summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format4
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml71
-rw-r--r--README.md1
-rw-r--r--SConstruct489
-rw-r--r--compat.py68
-rw-r--r--core/SCsub110
-rw-r--r--core/array.cpp4
-rw-r--r--core/bind/SCsub2
-rw-r--r--core/bind/core_bind.cpp609
-rw-r--r--core/bind/core_bind.h118
-rw-r--r--core/callable.cpp6
-rw-r--r--core/callable.h1
-rw-r--r--core/callable_method_pointer.h1
-rw-r--r--core/class_db.cpp92
-rw-r--r--core/class_db.h25
-rw-r--r--core/color.h2
-rw-r--r--core/command_queue_mt.cpp2
-rw-r--r--core/command_queue_mt.h10
-rw-r--r--core/compressed_translation.cpp6
-rw-r--r--core/core_builders.py197
-rw-r--r--core/core_string_names.cpp2
-rw-r--r--core/core_string_names.h4
-rw-r--r--core/cowdata.h74
-rw-r--r--core/crypto/SCsub8
-rw-r--r--core/crypto/crypto.cpp18
-rw-r--r--core/crypto/crypto.h2
-rw-r--r--core/crypto/hashing_context.cpp16
-rw-r--r--core/debugger/SCsub2
-rw-r--r--core/debugger/debugger_marshalls.cpp4
-rw-r--r--core/debugger/debugger_marshalls.h4
-rw-r--r--core/debugger/engine_debugger.cpp10
-rw-r--r--core/debugger/engine_debugger.h14
-rw-r--r--core/debugger/local_debugger.cpp6
-rw-r--r--core/debugger/local_debugger.h2
-rw-r--r--core/debugger/remote_debugger.cpp39
-rw-r--r--core/debugger/remote_debugger.h8
-rw-r--r--core/debugger/remote_debugger_peer.cpp4
-rw-r--r--core/debugger/remote_debugger_peer.h2
-rw-r--r--core/debugger/script_debugger.h8
-rw-r--r--core/dictionary.cpp14
-rw-r--r--core/dictionary.h2
-rw-r--r--core/engine.cpp8
-rw-r--r--core/engine.h4
-rw-r--r--core/error_list.h2
-rw-r--r--core/error_macros.cpp4
-rw-r--r--core/error_macros.h22
-rw-r--r--core/global_constants.cpp5
-rw-r--r--core/hash_map.h54
-rw-r--r--core/hashfuncs.h4
-rw-r--r--core/image.cpp56
-rw-r--r--core/image.h4
-rw-r--r--core/input/SCsub28
-rw-r--r--core/input/default_controller_mappings.h (renamed from main/default_controller_mappings.h)0
-rw-r--r--core/input/gamecontrollerdb.txt (renamed from main/gamecontrollerdb.txt)0
-rw-r--r--core/input/gamecontrollerdb_204.txt (renamed from main/gamecontrollerdb_204.txt)0
-rw-r--r--core/input/gamecontrollerdb_205.txt (renamed from main/gamecontrollerdb_205.txt)0
-rw-r--r--core/input/godotcontrollerdb.txt (renamed from main/godotcontrollerdb.txt)0
-rw-r--r--core/input/input_builders.py81
-rw-r--r--core/input/input_event.cpp1404
-rw-r--r--core/input/input_event.h641
-rw-r--r--core/input/input_filter.cpp1309
-rw-r--r--core/input/input_filter.h337
-rw-r--r--core/input/input_map.cpp338
-rw-r--r--core/input/input_map.h91
-rw-r--r--core/input_map.cpp338
-rw-r--r--core/input_map.h91
-rw-r--r--core/int_types.h7
-rw-r--r--core/io/SCsub2
-rw-r--r--core/io/config_file.cpp6
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/dtls_server.cpp2
-rw-r--r--core/io/file_access_compressed.cpp16
-rw-r--r--core/io/file_access_encrypted.cpp10
-rw-r--r--core/io/file_access_memory.cpp14
-rw-r--r--core/io/file_access_network.cpp8
-rw-r--r--core/io/file_access_pack.cpp6
-rw-r--r--core/io/file_access_pack.h4
-rw-r--r--core/io/file_access_zip.cpp26
-rw-r--r--core/io/http_client.cpp2
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/image_loader.h6
-rw-r--r--core/io/ip.cpp10
-rw-r--r--core/io/logger.cpp4
-rw-r--r--core/io/logger.h2
-rw-r--r--core/io/marshalls.cpp6
-rw-r--r--core/io/marshalls.h4
-rw-r--r--core/io/multiplayer_api.cpp31
-rw-r--r--core/io/multiplayer_api.h6
-rw-r--r--core/io/net_socket.cpp4
-rw-r--r--core/io/networked_multiplayer_peer.h2
-rw-r--r--core/io/packet_peer.cpp4
-rw-r--r--core/io/packet_peer_dtls.cpp2
-rw-r--r--core/io/pck_packer.cpp10
-rw-r--r--core/io/resource_format_binary.cpp6
-rw-r--r--core/io/resource_format_binary.h2
-rw-r--r--core/io/resource_importer.cpp10
-rw-r--r--core/io/resource_importer.h12
-rw-r--r--core/io/resource_loader.cpp20
-rw-r--r--core/io/resource_loader.h12
-rw-r--r--core/io/resource_saver.cpp6
-rw-r--r--core/io/resource_saver.h2
-rw-r--r--core/io/stream_peer.cpp4
-rw-r--r--core/io/stream_peer_ssl.cpp4
-rw-r--r--core/io/stream_peer_tcp.h2
-rw-r--r--core/io/translation_loader_po.cpp27
-rw-r--r--core/io/translation_loader_po.h4
-rw-r--r--core/io/xml_parser.cpp8
-rw-r--r--core/io/xml_parser.h2
-rw-r--r--core/io/zip_io.cpp4
-rw-r--r--core/list.h42
-rw-r--r--core/make_binders.py48
-rw-r--r--core/map.h46
-rw-r--r--core/math/SCsub2
-rw-r--r--core/math/a_star.cpp203
-rw-r--r--core/math/a_star.h16
-rw-r--r--core/math/aabb.h4
-rw-r--r--core/math/audio_frame.h6
-rw-r--r--core/math/basis.cpp4
-rw-r--r--core/math/camera_matrix.cpp2
-rw-r--r--core/math/camera_matrix.h2
-rw-r--r--core/math/disjoint_set.h2
-rw-r--r--core/math/expression.cpp80
-rw-r--r--core/math/expression.h4
-rw-r--r--core/math/geometry.cpp18
-rw-r--r--core/math/geometry.h32
-rw-r--r--core/math/octree.h54
-rw-r--r--core/math/quat.h2
-rw-r--r--core/math/quick_hull.cpp6
-rw-r--r--core/math/quick_hull.h8
-rw-r--r--core/math/random_pcg.h8
-rw-r--r--core/math/rect2.h2
-rw-r--r--core/math/triangulate.h2
-rw-r--r--core/message_queue.cpp14
-rw-r--r--core/method_bind.cpp2
-rw-r--r--core/method_bind.h4
-rw-r--r--core/method_ptrcall.h13
-rw-r--r--core/node_path.cpp12
-rw-r--r--core/node_path.h2
-rw-r--r--core/oa_hash_map.h14
-rw-r--r--core/object.cpp58
-rw-r--r--core/object.h36
-rw-r--r--core/ordered_hash_map.h26
-rw-r--r--core/os/SCsub2
-rw-r--r--core/os/copymem.h2
-rw-r--r--core/os/dir_access.cpp10
-rw-r--r--core/os/dir_access.h6
-rw-r--r--core/os/file_access.cpp12
-rw-r--r--core/os/file_access.h10
-rw-r--r--core/os/input.cpp157
-rw-r--r--core/os/input.h146
-rw-r--r--core/os/input_event.cpp1374
-rw-r--r--core/os/input_event.h625
-rw-r--r--core/os/keyboard.cpp2
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/main_loop.cpp38
-rw-r--r--core/os/main_loop.h31
-rw-r--r--core/os/memory.cpp12
-rw-r--r--core/os/memory.h2
-rw-r--r--core/os/midi_driver.cpp6
-rw-r--r--core/os/midi_driver.h2
-rw-r--r--core/os/mutex.cpp4
-rw-r--r--core/os/mutex.h6
-rw-r--r--core/os/os.cpp245
-rw-r--r--core/os/os.h251
-rw-r--r--core/os/rw_lock.cpp4
-rw-r--r--core/os/rw_lock.h6
-rw-r--r--core/os/semaphore.h2
-rw-r--r--core/os/thread.cpp10
-rw-r--r--core/os/thread.h2
-rw-r--r--core/os/thread_dummy.h2
-rw-r--r--core/os/thread_safe.h2
-rw-r--r--core/os/threaded_array_processor.h2
-rw-r--r--core/packed_data_container.cpp4
-rw-r--r--core/packed_data_container.h4
-rw-r--r--core/pool_allocator.cpp30
-rw-r--r--core/pool_allocator.h2
-rw-r--r--core/print_string.cpp6
-rw-r--r--core/print_string.h2
-rw-r--r--core/project_settings.cpp24
-rw-r--r--core/project_settings.h10
-rw-r--r--core/reference.h22
-rw-r--r--core/register_core_types.cpp27
-rw-r--r--core/register_core_types.h2
-rw-r--r--core/resource.cpp31
-rw-r--r--core/resource.h12
-rw-r--r--core/rid.h7
-rw-r--r--core/rid_owner.h21
-rw-r--r--core/ring_buffer.h6
-rw-r--r--core/safe_refcount.h2
-rw-r--r--core/script_language.cpp10
-rw-r--r--core/script_language.h27
-rw-r--r--core/self_list.h22
-rw-r--r--core/set.h42
-rw-r--r--core/simple_type.h2
-rw-r--r--core/string_buffer.h2
-rw-r--r--core/string_name.cpp24
-rw-r--r--core/string_name.h4
-rw-r--r--core/translation.cpp33
-rw-r--r--core/translation.h5
-rw-r--r--core/type_info.h13
-rw-r--r--core/typedefs.h175
-rw-r--r--core/ucaps.h3
-rw-r--r--core/undo_redo.cpp27
-rw-r--r--core/ustring.cpp31
-rw-r--r--core/ustring.h22
-rw-r--r--core/variant.cpp60
-rw-r--r--core/variant.h19
-rw-r--r--core/variant_call.cpp15
-rw-r--r--core/variant_op.cpp10
-rw-r--r--core/variant_parser.cpp2
-rw-r--r--core/variant_parser.h18
-rw-r--r--core/vector.h4
-rw-r--r--core/version.h6
-rw-r--r--doc/Makefile7
-rw-r--r--doc/classes/@GlobalScope.xml32
-rw-r--r--doc/classes/ARVRAnchor.xml66
-rw-r--r--doc/classes/ARVRCamera.xml17
-rw-r--r--doc/classes/ARVRController.xml106
-rw-r--r--doc/classes/ARVRInterface.xml127
-rw-r--r--doc/classes/ARVROrigin.xml25
-rw-r--r--doc/classes/ARVRPositionalTracker.xml111
-rw-r--r--doc/classes/ARVRServer.xml188
-rw-r--r--doc/classes/AStar2D.xml24
-rw-r--r--doc/classes/AcceptDialog.xml11
-rw-r--r--doc/classes/AnimatedSprite.xml85
-rw-r--r--doc/classes/AnimatedSprite2D.xml87
-rw-r--r--doc/classes/AnimatedTexture.xml4
-rw-r--r--doc/classes/Animation.xml29
-rw-r--r--doc/classes/AnimationNodeBlendTree.xml18
-rw-r--r--doc/classes/AnimationNodeOneShot.xml5
-rw-r--r--doc/classes/AnimationNodeOutput.xml1
-rw-r--r--doc/classes/AnimationNodeStateMachine.xml10
-rw-r--r--doc/classes/AnimationNodeTimeScale.xml2
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml2
-rw-r--r--doc/classes/AnimationNodeTransition.xml4
-rw-r--r--doc/classes/AnimationTree.xml9
-rw-r--r--doc/classes/Area.xml247
-rw-r--r--doc/classes/Area3D.xml247
-rw-r--r--doc/classes/Array.xml12
-rw-r--r--doc/classes/ArrayMesh.xml5
-rw-r--r--doc/classes/AudioEffectRecord.xml6
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml2
-rw-r--r--doc/classes/AudioStreamSample.xml12
-rw-r--r--doc/classes/BaseButton.xml1
-rw-r--r--doc/classes/BaseMaterial3D.xml21
-rw-r--r--doc/classes/BoneAttachment.xml20
-rw-r--r--doc/classes/BoneAttachment3D.xml20
-rw-r--r--doc/classes/BoxShape.xml20
-rw-r--r--doc/classes/BoxShape3D.xml20
-rw-r--r--doc/classes/CPUParticles.xml385
-rw-r--r--doc/classes/CPUParticles2D.xml4
-rw-r--r--doc/classes/CPUParticles3D.xml385
-rw-r--r--doc/classes/Callable.xml18
-rw-r--r--doc/classes/Camera.xml237
-rw-r--r--doc/classes/Camera2D.xml3
-rw-r--r--doc/classes/Camera3D.xml237
-rw-r--r--doc/classes/CameraFeed.xml2
-rw-r--r--doc/classes/CameraServer.xml13
-rw-r--r--doc/classes/CanvasItem.xml11
-rw-r--r--doc/classes/CanvasItemMaterial.xml6
-rw-r--r--doc/classes/CapsuleShape.xml23
-rw-r--r--doc/classes/CapsuleShape3D.xml23
-rw-r--r--doc/classes/ClippedCamera.xml110
-rw-r--r--doc/classes/ClippedCamera3D.xml110
-rw-r--r--doc/classes/CollisionObject.xml219
-rw-r--r--doc/classes/CollisionObject3D.xml219
-rw-r--r--doc/classes/CollisionPolygon.xml27
-rw-r--r--doc/classes/CollisionPolygon2D.xml1
-rw-r--r--doc/classes/CollisionPolygon3D.xml27
-rw-r--r--doc/classes/CollisionShape.xml40
-rw-r--r--doc/classes/CollisionShape2D.xml2
-rw-r--r--doc/classes/CollisionShape3D.xml40
-rw-r--r--doc/classes/Color.xml3
-rw-r--r--doc/classes/ColorPicker.xml8
-rw-r--r--doc/classes/ConcavePolygonShape.xml32
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml32
-rw-r--r--doc/classes/ConeTwistJoint.xml80
-rw-r--r--doc/classes/ConeTwistJoint3D.xml80
-rw-r--r--doc/classes/ConfigFile.xml2
-rw-r--r--doc/classes/ConfirmationDialog.xml5
-rw-r--r--doc/classes/Control.xml200
-rw-r--r--doc/classes/ConvexPolygonShape.xml20
-rw-r--r--doc/classes/ConvexPolygonShape3D.xml20
-rw-r--r--doc/classes/Curve3D.xml6
-rw-r--r--doc/classes/CylinderShape.xml23
-rw-r--r--doc/classes/CylinderShape3D.xml23
-rw-r--r--doc/classes/Dictionary.xml26
-rw-r--r--doc/classes/DirectionalLight.xml63
-rw-r--r--doc/classes/DirectionalLight3D.xml63
-rw-r--r--doc/classes/Directory.xml3
-rw-r--r--doc/classes/DisplayServer.xml1049
-rw-r--r--doc/classes/EditorExportPlugin.xml11
-rw-r--r--doc/classes/EditorFeatureProfile.xml21
-rw-r--r--doc/classes/EditorFileDialog.xml18
-rw-r--r--doc/classes/EditorFileSystem.xml1
-rw-r--r--doc/classes/EditorInterface.xml6
-rw-r--r--doc/classes/EditorNode3DGizmo.xml189
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml198
-rw-r--r--doc/classes/EditorPlugin.xml8
-rw-r--r--doc/classes/EditorSpatialGizmo.xml189
-rw-r--r--doc/classes/EditorSpatialGizmoPlugin.xml198
-rw-r--r--doc/classes/Environment.xml12
-rw-r--r--doc/classes/File.xml4
-rw-r--r--doc/classes/FileDialog.xml26
-rw-r--r--doc/classes/FileSystemDock.xml101
-rw-r--r--doc/classes/Font.xml1
-rw-r--r--doc/classes/GIProbe.xml4
-rw-r--r--doc/classes/GPUParticles2D.xml87
-rw-r--r--doc/classes/GPUParticles3D.xml122
-rw-r--r--doc/classes/Generic6DOFJoint.xml426
-rw-r--r--doc/classes/Generic6DOFJoint3D.xml426
-rw-r--r--doc/classes/GeometryInstance.xml103
-rw-r--r--doc/classes/GeometryInstance3D.xml103
-rw-r--r--doc/classes/GraphEdit.xml11
-rw-r--r--doc/classes/GraphNode.xml17
-rw-r--r--doc/classes/GridContainer.xml2
-rw-r--r--doc/classes/HSeparator.xml2
-rw-r--r--doc/classes/HSlider.xml6
-rw-r--r--doc/classes/HSplitContainer.xml3
-rw-r--r--doc/classes/HeightMapShape.xml26
-rw-r--r--doc/classes/HeightMapShape3D.xml26
-rw-r--r--doc/classes/HingeJoint.xml117
-rw-r--r--doc/classes/HingeJoint3D.xml121
-rw-r--r--doc/classes/Image.xml2
-rw-r--r--doc/classes/ImageTexture.xml1
-rw-r--r--doc/classes/ImmediateGeometry.xml110
-rw-r--r--doc/classes/ImmediateGeometry3D.xml110
-rw-r--r--doc/classes/Input.xml476
-rw-r--r--doc/classes/InputDefault.xml15
-rw-r--r--doc/classes/InputEventFromWindow.xml17
-rw-r--r--doc/classes/InputEventGesture.xml2
-rw-r--r--doc/classes/InputEventKey.xml2
-rw-r--r--doc/classes/InputEventMouseMotion.xml3
-rw-r--r--doc/classes/InputEventScreenDrag.xml2
-rw-r--r--doc/classes/InputEventScreenTouch.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml2
-rw-r--r--doc/classes/InputFilter.xml477
-rw-r--r--doc/classes/InterpolatedCamera.xml36
-rw-r--r--doc/classes/Joint.xml29
-rw-r--r--doc/classes/Joint3D.xml29
-rw-r--r--doc/classes/KinematicBody.xml181
-rw-r--r--doc/classes/KinematicBody3D.xml181
-rw-r--r--doc/classes/KinematicCollision.xml51
-rw-r--r--doc/classes/KinematicCollision3D.xml51
-rw-r--r--doc/classes/Light.xml138
-rw-r--r--doc/classes/Light3D.xml147
-rw-r--r--doc/classes/Listener.xml45
-rw-r--r--doc/classes/Listener3D.xml45
-rw-r--r--doc/classes/MainLoop.xml101
-rw-r--r--doc/classes/Material.xml2
-rw-r--r--doc/classes/MenuButton.xml4
-rw-r--r--doc/classes/Mesh.xml8
-rw-r--r--doc/classes/MeshInstance.xml74
-rw-r--r--doc/classes/MeshInstance2D.xml2
-rw-r--r--doc/classes/MeshInstance3D.xml83
-rw-r--r--doc/classes/MeshLibrary.xml4
-rw-r--r--doc/classes/MultiMesh.xml4
-rw-r--r--doc/classes/MultiMeshInstance.xml24
-rw-r--r--doc/classes/MultiMeshInstance2D.xml2
-rw-r--r--doc/classes/MultiMeshInstance3D.xml24
-rw-r--r--doc/classes/Navigation.xml83
-rw-r--r--doc/classes/Navigation2DServer.xml298
-rw-r--r--doc/classes/Navigation3D.xml83
-rw-r--r--doc/classes/NavigationAgent.xml165
-rw-r--r--doc/classes/NavigationAgent3D.xml165
-rw-r--r--doc/classes/NavigationObstacle.xml31
-rw-r--r--doc/classes/NavigationObstacle2D.xml2
-rw-r--r--doc/classes/NavigationObstacle3D.xml31
-rw-r--r--doc/classes/NavigationRegion.xml42
-rw-r--r--doc/classes/NavigationRegion3D.xml42
-rw-r--r--doc/classes/NavigationServer.xml375
-rw-r--r--doc/classes/NavigationServer2D.xml298
-rw-r--r--doc/classes/NavigationServer3D.xml375
-rw-r--r--doc/classes/Node.xml37
-rw-r--r--doc/classes/Node3D.xml350
-rw-r--r--doc/classes/Node3DGizmo.xml13
-rw-r--r--doc/classes/NodePath.xml34
-rw-r--r--doc/classes/OS.xml462
-rw-r--r--doc/classes/Object.xml11
-rw-r--r--doc/classes/OmniLight.xml33
-rw-r--r--doc/classes/OmniLight3D.xml33
-rw-r--r--doc/classes/OptionButton.xml4
-rw-r--r--doc/classes/PackedDataContainerRef.xml1
-rw-r--r--doc/classes/Panel.xml11
-rw-r--r--doc/classes/PanelContainer.xml1
-rw-r--r--doc/classes/PanoramaSky.xml22
-rw-r--r--doc/classes/PanoramaSkyMaterial.xml22
-rw-r--r--doc/classes/Particles.xml122
-rw-r--r--doc/classes/Particles2D.xml87
-rw-r--r--doc/classes/ParticlesMaterial.xml6
-rw-r--r--doc/classes/Path.xml28
-rw-r--r--doc/classes/Path3D.xml28
-rw-r--r--doc/classes/PathFollow.xml56
-rw-r--r--doc/classes/PathFollow3D.xml56
-rw-r--r--doc/classes/Performance.xml2
-rw-r--r--doc/classes/PhysicalBone.xml79
-rw-r--r--doc/classes/PhysicalBone3D.xml120
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml49
-rw-r--r--doc/classes/Physics2DDirectBodyState.xml218
-rw-r--r--doc/classes/Physics2DDirectBodyStateSW.xml15
-rw-r--r--doc/classes/Physics2DDirectSpaceState.xml145
-rw-r--r--doc/classes/Physics2DServer.xml1284
-rw-r--r--doc/classes/Physics2DServerSW.xml15
-rw-r--r--doc/classes/Physics2DShapeQueryParameters.xml50
-rw-r--r--doc/classes/Physics2DShapeQueryResult.xml58
-rw-r--r--doc/classes/Physics2DTestMotionResult.xml33
-rw-r--r--doc/classes/PhysicsBody.xml91
-rw-r--r--doc/classes/PhysicsBody3D.xml91
-rw-r--r--doc/classes/PhysicsDirectBodyState.xml223
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml218
-rw-r--r--doc/classes/PhysicsDirectBodyState2DSW.xml15
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml223
-rw-r--r--doc/classes/PhysicsDirectSpaceState.xml98
-rw-r--r--doc/classes/PhysicsDirectSpaceState2D.xml145
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml98
-rw-r--r--doc/classes/PhysicsMaterial.xml2
-rw-r--r--doc/classes/PhysicsServer.xml1639
-rw-r--r--doc/classes/PhysicsServer2D.xml1284
-rw-r--r--doc/classes/PhysicsServer2DSW.xml15
-rw-r--r--doc/classes/PhysicsServer3D.xml1639
-rw-r--r--doc/classes/PhysicsShapeQueryParameters.xml47
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml50
-rw-r--r--doc/classes/PhysicsShapeQueryParameters3D.xml47
-rw-r--r--doc/classes/PhysicsShapeQueryResult.xml58
-rw-r--r--doc/classes/PhysicsShapeQueryResult2D.xml58
-rw-r--r--doc/classes/PhysicsShapeQueryResult3D.xml58
-rw-r--r--doc/classes/PhysicsTestMotionResult2D.xml33
-rw-r--r--doc/classes/PinJoint.xml53
-rw-r--r--doc/classes/PinJoint2D.xml4
-rw-r--r--doc/classes/PinJoint3D.xml55
-rw-r--r--doc/classes/Polygon2D.xml8
-rw-r--r--doc/classes/Popup.xml76
-rw-r--r--doc/classes/PopupDialog.xml20
-rw-r--r--doc/classes/PopupMenu.xml17
-rw-r--r--doc/classes/PopupPanel.xml3
-rw-r--r--doc/classes/Position3D.xml4
-rw-r--r--doc/classes/ProceduralSky.xml84
-rw-r--r--doc/classes/ProceduralSkyMaterial.xml52
-rw-r--r--doc/classes/ProgressBar.xml5
-rw-r--r--doc/classes/ProjectSettings.xml74
-rw-r--r--doc/classes/ProximityGroup.xml47
-rw-r--r--doc/classes/ProximityGroup3D.xml47
-rw-r--r--doc/classes/RID.xml2
-rw-r--r--doc/classes/RayCast.xml150
-rw-r--r--doc/classes/RayCast3D.xml150
-rw-r--r--doc/classes/RayShape.xml23
-rw-r--r--doc/classes/RayShape3D.xml23
-rw-r--r--doc/classes/ReflectionProbe.xml4
-rw-r--r--doc/classes/RemoteTransform.xml40
-rw-r--r--doc/classes/RemoteTransform3D.xml40
-rw-r--r--doc/classes/RenderingServer.xml3726
-rw-r--r--doc/classes/ResourceLoader.xml9
-rw-r--r--doc/classes/RichTextLabel.xml17
-rw-r--r--doc/classes/RigidBody.xml253
-rw-r--r--doc/classes/RigidBody2D.xml6
-rw-r--r--doc/classes/RigidBody3D.xml254
-rw-r--r--doc/classes/RootMotionView.xml2
-rw-r--r--doc/classes/SceneTree.xml76
-rw-r--r--doc/classes/Script.xml5
-rw-r--r--doc/classes/ScriptCreateDialog.xml7
-rw-r--r--doc/classes/ScriptEditor.xml1
-rw-r--r--doc/classes/Shader.xml3
-rw-r--r--doc/classes/Shape.xml21
-rw-r--r--doc/classes/Shape3D.xml21
-rw-r--r--doc/classes/Signal.xml12
-rw-r--r--doc/classes/Skeleton.xml269
-rw-r--r--doc/classes/Skeleton3D.xml275
-rw-r--r--doc/classes/SkeletonIK.xml61
-rw-r--r--doc/classes/SkeletonIK3D.xml61
-rw-r--r--doc/classes/Sky.xml11
-rw-r--r--doc/classes/SliderJoint.xml173
-rw-r--r--doc/classes/SliderJoint3D.xml173
-rw-r--r--doc/classes/SoftBody.xml117
-rw-r--r--doc/classes/SoftBody3D.xml117
-rw-r--r--doc/classes/Spatial.xml350
-rw-r--r--doc/classes/SpatialGizmo.xml13
-rw-r--r--doc/classes/SpatialVelocityTracker.xml39
-rw-r--r--doc/classes/SphereShape.xml20
-rw-r--r--doc/classes/SphereShape3D.xml20
-rw-r--r--doc/classes/SpotLight.xml30
-rw-r--r--doc/classes/SpotLight3D.xml30
-rw-r--r--doc/classes/SpringArm.xml68
-rw-r--r--doc/classes/SpringArm3D.xml68
-rw-r--r--doc/classes/Sprite.xml97
-rw-r--r--doc/classes/Sprite2D.xml100
-rw-r--r--doc/classes/Sprite3D.xml2
-rw-r--r--doc/classes/SpriteBase3D.xml7
-rw-r--r--doc/classes/SpriteFrames.xml4
-rw-r--r--doc/classes/StaticBody.xml28
-rw-r--r--doc/classes/StaticBody3D.xml28
-rw-r--r--doc/classes/StreamPeerSSL.xml2
-rw-r--r--doc/classes/StreamTexture.xml1
-rw-r--r--doc/classes/StringName.xml3
-rw-r--r--doc/classes/SubViewport.xml57
-rw-r--r--doc/classes/SubViewportContainer.xml25
-rw-r--r--doc/classes/TabContainer.xml20
-rw-r--r--doc/classes/Tabs.xml15
-rw-r--r--doc/classes/TextEdit.xml6
-rw-r--r--doc/classes/Texture2D.xml20
-rw-r--r--doc/classes/Thread.xml2
-rw-r--r--doc/classes/TileMap.xml4
-rw-r--r--doc/classes/Transform.xml4
-rw-r--r--doc/classes/Transform2D.xml4
-rw-r--r--doc/classes/Tree.xml1
-rw-r--r--doc/classes/TreeItem.xml3
-rw-r--r--doc/classes/UndoRedo.xml2
-rw-r--r--doc/classes/VSeparator.xml2
-rw-r--r--doc/classes/VSlider.xml6
-rw-r--r--doc/classes/VSplitContainer.xml3
-rw-r--r--doc/classes/VehicleBody.xml31
-rw-r--r--doc/classes/VehicleBody3D.xml31
-rw-r--r--doc/classes/VehicleWheel.xml83
-rw-r--r--doc/classes/VehicleWheel3D.xml83
-rw-r--r--doc/classes/VelocityTracker3D.xml39
-rw-r--r--doc/classes/Viewport.xml117
-rw-r--r--doc/classes/ViewportContainer.xml25
-rw-r--r--doc/classes/VisibilityEnabler.xml52
-rw-r--r--doc/classes/VisibilityEnabler2D.xml9
-rw-r--r--doc/classes/VisibilityEnabler3D.xml53
-rw-r--r--doc/classes/VisibilityNotifier.xml54
-rw-r--r--doc/classes/VisibilityNotifier3D.xml54
-rw-r--r--doc/classes/VisualInstance.xml79
-rw-r--r--doc/classes/VisualInstance3D.xml79
-rw-r--r--doc/classes/VisualServer.xml3733
-rw-r--r--doc/classes/VisualShader.xml17
-rw-r--r--doc/classes/VisualShaderNode.xml1
-rw-r--r--doc/classes/Window.xml419
-rw-r--r--doc/classes/WindowDialog.xml50
-rw-r--r--doc/classes/World.xml35
-rw-r--r--doc/classes/World2D.xml6
-rw-r--r--doc/classes/World3D.xml35
-rw-r--r--doc/classes/WorldEnvironment.xml2
-rw-r--r--doc/classes/WorldMarginShape.xml20
-rw-r--r--doc/classes/WorldMarginShape3D.xml20
-rw-r--r--doc/classes/XRAnchor3D.xml66
-rw-r--r--doc/classes/XRCamera3D.xml17
-rw-r--r--doc/classes/XRController3D.xml106
-rw-r--r--doc/classes/XRInterface.xml127
-rw-r--r--doc/classes/XROrigin3D.xml25
-rw-r--r--doc/classes/XRPositionalTracker.xml111
-rw-r--r--doc/classes/XRServer.xml188
-rwxr-xr-xdoc/tools/doc_merge.py114
-rwxr-xr-xdoc/tools/doc_status.py351
-rwxr-xr-xdoc/tools/makerst.py319
-rw-r--r--doc/translations/Makefile23
-rw-r--r--doc/translations/classes.pot57448
-rw-r--r--doc/translations/extract.py286
-rw-r--r--doc/translations/fr.po57458
-rw-r--r--drivers/SCsub35
-rw-r--r--drivers/alsa/SCsub2
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp24
-rw-r--r--drivers/alsa/audio_driver_alsa.h10
-rw-r--r--drivers/alsamidi/SCsub2
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp12
-rw-r--r--drivers/coreaudio/SCsub2
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp40
-rw-r--r--drivers/coremidi/SCsub2
-rw-r--r--drivers/coremidi/midi_driver_coremidi.cpp6
-rw-r--r--drivers/dummy/SCsub2
-rw-r--r--drivers/dummy/rasterizer_dummy.h134
-rw-r--r--drivers/dummy/texture_loader_dummy.h2
-rw-r--r--drivers/gl_context/SCsub8
-rw-r--r--drivers/gles2/SCsub2
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp300
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.h4
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp26
-rw-r--r--drivers/gles2/rasterizer_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp402
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h36
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp614
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h150
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp356
-rw-r--r--drivers/gles2/shader_compiler_gles2.h12
-rw-r--r--drivers/gles2/shader_gles2.cpp32
-rw-r--r--drivers/gles2/shader_gles2.h6
-rw-r--r--drivers/gles2/shaders/SCsub40
-rw-r--r--drivers/gles2/shaders/blend_shape.glsl2
-rw-r--r--drivers/png/SCsub9
-rw-r--r--drivers/png/png_driver_common.cpp6
-rw-r--r--drivers/pulseaudio/SCsub2
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp66
-rw-r--r--drivers/spirv-reflect/SCsub6
-rw-r--r--drivers/unix/SCsub4
-rw-r--r--drivers/unix/dir_access_unix.cpp14
-rw-r--r--drivers/unix/file_access_unix.cpp12
-rw-r--r--drivers/unix/ip_unix.cpp18
-rw-r--r--drivers/unix/net_socket_posix.cpp16
-rw-r--r--drivers/unix/os_unix.cpp22
-rw-r--r--drivers/unix/os_unix.h2
-rw-r--r--drivers/unix/rw_lock_posix.cpp2
-rw-r--r--drivers/unix/syslog_logger.cpp2
-rw-r--r--drivers/unix/thread_posix.cpp4
-rw-r--r--drivers/vulkan/SCsub106
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp692
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h29
-rw-r--r--drivers/vulkan/vulkan_context.cpp214
-rw-r--r--drivers/vulkan/vulkan_context.h22
-rw-r--r--drivers/wasapi/SCsub2
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp60
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h6
-rw-r--r--drivers/windows/SCsub2
-rw-r--r--drivers/windows/dir_access_windows.cpp18
-rw-r--r--drivers/windows/file_access_windows.cpp12
-rw-r--r--drivers/windows/thread_windows.cpp4
-rw-r--r--drivers/winmidi/SCsub2
-rw-r--r--drivers/xaudio2/SCsub6
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp6
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.h2
-rw-r--r--editor/SCsub58
-rw-r--r--editor/animation_bezier_editor.cpp58
-rw-r--r--editor/animation_track_editor.cpp337
-rw-r--r--editor/animation_track_editor.h7
-rw-r--r--editor/animation_track_editor_plugins.cpp116
-rw-r--r--editor/array_property_edit.cpp6
-rw-r--r--editor/audio_stream_preview.cpp4
-rw-r--r--editor/code_editor.cpp112
-rw-r--r--editor/collada/SCsub5
-rw-r--r--editor/collada/collada.cpp2574
-rw-r--r--editor/collada/collada.h647
-rw-r--r--editor/connections_dialog.cpp64
-rw-r--r--editor/connections_dialog.h4
-rw-r--r--editor/create_dialog.cpp52
-rw-r--r--editor/debugger/SCsub2
-rw-r--r--editor/debugger/editor_debugger_inspector.cpp6
-rw-r--r--editor/debugger/editor_debugger_node.cpp27
-rw-r--r--editor/debugger/editor_debugger_node.h8
-rw-r--r--editor/debugger/editor_debugger_tree.cpp19
-rw-r--r--editor/debugger/editor_debugger_tree.h4
-rw-r--r--editor/debugger/editor_network_profiler.cpp26
-rw-r--r--editor/debugger/editor_profiler.cpp20
-rw-r--r--editor/debugger/editor_profiler.h2
-rw-r--r--editor/debugger/editor_visual_profiler.cpp22
-rw-r--r--editor/debugger/editor_visual_profiler.h2
-rw-r--r--editor/debugger/script_editor_debugger.cpp101
-rw-r--r--editor/debugger/script_editor_debugger.h6
-rw-r--r--editor/dependency_editor.cpp36
-rw-r--r--editor/dependency_editor.h2
-rw-r--r--editor/dictionary_property_edit.cpp2
-rw-r--r--editor/doc/SCsub5
-rw-r--r--editor/doc/doc_data.cpp1217
-rw-r--r--editor/doc/doc_dump.cpp308
-rw-r--r--editor/doc/doc_dump.h41
-rw-r--r--editor/doc_data.cpp1217
-rw-r--r--editor/doc_data.h (renamed from editor/doc/doc_data.h)0
-rw-r--r--editor/editor_about.cpp31
-rw-r--r--editor/editor_about.h2
-rw-r--r--editor/editor_asset_installer.cpp38
-rw-r--r--editor/editor_audio_buses.cpp96
-rw-r--r--editor/editor_audio_buses.h2
-rw-r--r--editor/editor_autoload_settings.cpp85
-rw-r--r--editor/editor_autoload_settings.h11
-rw-r--r--editor/editor_builders.py49
-rw-r--r--editor/editor_data.cpp26
-rw-r--r--editor/editor_data.h6
-rw-r--r--editor/editor_dir_dialog.cpp15
-rw-r--r--editor/editor_export.cpp33
-rw-r--r--editor/editor_export.h17
-rw-r--r--editor/editor_feature_profile.cpp24
-rw-r--r--editor/editor_feature_profile.h2
-rw-r--r--editor/editor_file_dialog.cpp253
-rw-r--r--editor/editor_file_dialog.h42
-rw-r--r--editor/editor_file_system.cpp70
-rw-r--r--editor/editor_file_system.h8
-rw-r--r--editor/editor_fonts.cpp2
-rw-r--r--editor/editor_help.cpp111
-rw-r--r--editor/editor_help.h14
-rw-r--r--editor/editor_help_search.cpp50
-rw-r--r--editor/editor_inspector.cpp229
-rw-r--r--editor/editor_inspector.h4
-rw-r--r--editor/editor_layouts_dialog.cpp16
-rw-r--r--editor/editor_log.cpp20
-rw-r--r--editor/editor_node.cpp725
-rw-r--r--editor/editor_node.h29
-rw-r--r--editor/editor_path.cpp2
-rw-r--r--editor/editor_plugin.cpp125
-rw-r--r--editor/editor_plugin.h19
-rw-r--r--editor/editor_plugin_settings.cpp28
-rw-r--r--editor/editor_properties.cpp146
-rw-r--r--editor/editor_properties_array_dict.cpp66
-rw-r--r--editor/editor_resource_preview.cpp18
-rw-r--r--editor/editor_resource_preview.h2
-rw-r--r--editor/editor_run.cpp19
-rw-r--r--editor/editor_run_script.cpp6
-rw-r--r--editor/editor_sectioned_inspector.cpp14
-rw-r--r--editor/editor_settings.cpp56
-rw-r--r--editor/editor_settings.h2
-rw-r--r--editor/editor_spin_slider.cpp78
-rw-r--r--editor/editor_spin_slider.h1
-rw-r--r--editor/editor_sub_scene.cpp18
-rw-r--r--editor/editor_themes.cpp34
-rw-r--r--editor/editor_themes.h4
-rw-r--r--editor/editor_vcs_interface.cpp2
-rw-r--r--editor/export_template_manager.cpp49
-rw-r--r--editor/file_type_cache.cpp104
-rw-r--r--editor/file_type_cache.h57
-rw-r--r--editor/fileserver/SCsub2
-rw-r--r--editor/filesystem_dock.cpp182
-rw-r--r--editor/filesystem_dock.h4
-rw-r--r--editor/find_in_files.cpp35
-rw-r--r--editor/find_in_files.h5
-rw-r--r--editor/groups_editor.cpp76
-rw-r--r--editor/groups_editor.h4
-rw-r--r--editor/icons/AcceptDialog.svg2
-rw-r--r--editor/icons/AnimatedSprite2D.svg (renamed from editor/icons/AnimatedSprite.svg)0
-rw-r--r--editor/icons/Area3D.svg (renamed from editor/icons/Area.svg)0
-rw-r--r--editor/icons/BoneAttachment3D.svg (renamed from editor/icons/BoneAttachment.svg)0
-rw-r--r--editor/icons/BoxShape3D.svg (renamed from editor/icons/BoxShape.svg)0
-rw-r--r--editor/icons/CPUParticles3D.svg (renamed from editor/icons/CPUParticles.svg)0
-rw-r--r--editor/icons/Camera3D.svg (renamed from editor/icons/Camera.svg)0
-rw-r--r--editor/icons/CapsuleShape3D.svg (renamed from editor/icons/CapsuleShape.svg)0
-rw-r--r--editor/icons/ClippedCamera3D.svg (renamed from editor/icons/ClippedCamera.svg)0
-rw-r--r--editor/icons/CollisionPolygon3D.svg (renamed from editor/icons/CollisionPolygon.svg)0
-rw-r--r--editor/icons/CollisionShape3D.svg (renamed from editor/icons/CollisionShape.svg)0
-rw-r--r--editor/icons/ConcavePolygonShape3D.svg (renamed from editor/icons/ConcavePolygonShape.svg)0
-rw-r--r--editor/icons/ConeTwistJoint3D.svg (renamed from editor/icons/ConeTwistJoint.svg)0
-rw-r--r--editor/icons/ConfirmationDialog.svg2
-rw-r--r--editor/icons/ConvexPolygonShape3D.svg (renamed from editor/icons/ConvexPolygonShape.svg)0
-rw-r--r--editor/icons/CylinderShape3D.svg (renamed from editor/icons/CylinderShape.svg)0
-rw-r--r--editor/icons/DirectionalLight3D.svg (renamed from editor/icons/DirectionalLight.svg)0
-rw-r--r--editor/icons/EditorFileDialog.svg1
-rw-r--r--editor/icons/FileDialog.svg2
-rw-r--r--editor/icons/GPUParticles2D.svg (renamed from editor/icons/Particles2D.svg)0
-rw-r--r--editor/icons/GPUParticles3D.svg (renamed from editor/icons/Particles.svg)0
-rw-r--r--editor/icons/Generic6DOFJoint3D.svg (renamed from editor/icons/Generic6DOFJoint.svg)0
-rw-r--r--editor/icons/Gizmo3DSamplePlayer.svg (renamed from editor/icons/GizmoSpatialSamplePlayer.svg)0
-rw-r--r--editor/icons/GizmoCPUParticles3D.svg (renamed from editor/icons/GizmoCPUParticles.svg)0
-rw-r--r--editor/icons/GizmoGPUParticles3D.svg (renamed from editor/icons/GizmoParticles.svg)0
-rw-r--r--editor/icons/HeightMapShape3D.svg (renamed from editor/icons/HeightMapShape.svg)0
-rw-r--r--editor/icons/HingeJoint3D.svg (renamed from editor/icons/HingeJoint.svg)0
-rw-r--r--editor/icons/ImmediateGeometry3D.svg (renamed from editor/icons/ImmediateGeometry.svg)0
-rw-r--r--editor/icons/KinematicBody3D.svg (renamed from editor/icons/KinematicBody.svg)0
-rw-r--r--editor/icons/Listener3D.svg (renamed from editor/icons/Listener.svg)0
-rw-r--r--editor/icons/MeshInstance3D.svg (renamed from editor/icons/MeshInstance.svg)0
-rw-r--r--editor/icons/MultiMeshInstance3D.svg (renamed from editor/icons/MultiMeshInstance.svg)0
-rw-r--r--editor/icons/Navigation3D.svg (renamed from editor/icons/Navigation.svg)0
-rw-r--r--editor/icons/NavigationAgent3D.svg (renamed from editor/icons/NavigationAgent.svg)0
-rw-r--r--editor/icons/NavigationObstacle3D.svg (renamed from editor/icons/NavigationObstacle.svg)0
-rw-r--r--editor/icons/NavigationRegion3D.svg (renamed from editor/icons/NavigationRegion.svg)0
-rw-r--r--editor/icons/Node3D.svg (renamed from editor/icons/Spatial.svg)0
-rw-r--r--editor/icons/OmniLight3D.svg (renamed from editor/icons/OmniLight.svg)0
-rw-r--r--editor/icons/Path3D.svg (renamed from editor/icons/Path.svg)0
-rw-r--r--editor/icons/PathFollow3D.svg (renamed from editor/icons/PathFollow.svg)0
-rw-r--r--editor/icons/PhysicalBone3D.svg (renamed from editor/icons/PhysicalBone.svg)0
-rw-r--r--editor/icons/PinJoint3D.svg (renamed from editor/icons/PinJoint.svg)0
-rw-r--r--editor/icons/Popup.svg2
-rw-r--r--editor/icons/PopupDialog.svg1
-rw-r--r--editor/icons/PopupMenu.svg2
-rw-r--r--editor/icons/PopupPanel.svg2
-rw-r--r--editor/icons/ProximityGroup3D.svg (renamed from editor/icons/ProximityGroup.svg)0
-rw-r--r--editor/icons/RayCast3D.svg (renamed from editor/icons/RayCast.svg)0
-rw-r--r--editor/icons/RayShape3D.svg (renamed from editor/icons/RayShape.svg)0
-rw-r--r--editor/icons/RemoteTransform3D.svg (renamed from editor/icons/RemoteTransform.svg)0
-rw-r--r--editor/icons/RigidBody3D.svg (renamed from editor/icons/RigidBody.svg)0
-rw-r--r--editor/icons/SCsub14
-rw-r--r--editor/icons/ScriptCreateDialog.svg2
-rw-r--r--editor/icons/Skeleton3D.svg (renamed from editor/icons/Skeleton.svg)0
-rw-r--r--editor/icons/SkeletonIK3D.svg (renamed from editor/icons/SkeletonIK.svg)0
-rw-r--r--editor/icons/Sky.svg1
-rw-r--r--editor/icons/SliderJoint3D.svg (renamed from editor/icons/SliderJoint.svg)0
-rw-r--r--editor/icons/SoftBody3D.svg (renamed from editor/icons/SoftBody.svg)0
-rw-r--r--editor/icons/SpatialMaterial.svg1
-rw-r--r--editor/icons/SphereShape3D.svg (renamed from editor/icons/SphereShape.svg)0
-rw-r--r--editor/icons/SpotLight3D.svg (renamed from editor/icons/SpotLight.svg)0
-rw-r--r--editor/icons/SpringArm3D.svg (renamed from editor/icons/SpringArm.svg)0
-rw-r--r--editor/icons/Sprite2D.svg (renamed from editor/icons/Sprite.svg)0
-rw-r--r--editor/icons/StaticBody3D.svg (renamed from editor/icons/StaticBody.svg)0
-rw-r--r--editor/icons/SubViewport.svg1
-rw-r--r--editor/icons/SubViewportContainer.svg (renamed from editor/icons/ViewportContainer.svg)0
-rw-r--r--editor/icons/VehicleBody3D.svg (renamed from editor/icons/VehicleBody.svg)0
-rw-r--r--editor/icons/VehicleWheel3D.svg (renamed from editor/icons/VehicleWheel.svg)0
-rw-r--r--editor/icons/VisibilityEnabler3D.svg (renamed from editor/icons/VisibilityEnabler.svg)0
-rw-r--r--editor/icons/VisibilityNotifier3D.svg (renamed from editor/icons/VisibilityNotifier.svg)0
-rw-r--r--editor/icons/Window.svg1
-rw-r--r--editor/icons/WindowDialog.svg1
-rw-r--r--editor/icons/World3D.svg (renamed from editor/icons/World.svg)0
-rw-r--r--editor/icons/WorldMarginShape.svg1
-rw-r--r--editor/icons/WorldMarginShape3D.svg (renamed from editor/icons/PlaneShape.svg)0
-rw-r--r--editor/icons/XRAnchor3D.svg (renamed from editor/icons/ARVRAnchor.svg)0
-rw-r--r--editor/icons/XRCamera3D.svg (renamed from editor/icons/ARVRCamera.svg)0
-rw-r--r--editor/icons/XRController3D.svg (renamed from editor/icons/ARVRController.svg)0
-rw-r--r--editor/icons/XROrigin3D.svg (renamed from editor/icons/ARVROrigin.svg)0
-rw-r--r--editor/icons/editor_icons_builders.py17
-rw-r--r--editor/import/SCsub2
-rw-r--r--editor/import/collada.cpp2582
-rw-r--r--editor/import/collada.h647
-rw-r--r--editor/import/editor_import_collada.cpp132
-rw-r--r--editor/import/editor_import_collada.h2
-rw-r--r--editor/import/editor_import_plugin.h2
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp96
-rw-r--r--editor/import/editor_scene_importer_gltf.h34
-rw-r--r--editor/import/resource_importer_bitmask.h2
-rw-r--r--editor/import/resource_importer_csv.h2
-rw-r--r--editor/import/resource_importer_csv_translation.cpp2
-rw-r--r--editor/import/resource_importer_csv_translation.h2
-rw-r--r--editor/import/resource_importer_image.h2
-rw-r--r--editor/import/resource_importer_layered_texture.cpp6
-rw-r--r--editor/import/resource_importer_layered_texture.h2
-rw-r--r--editor/import/resource_importer_obj.cpp26
-rw-r--r--editor/import/resource_importer_obj.h4
-rw-r--r--editor/import/resource_importer_scene.cpp172
-rw-r--r--editor/import/resource_importer_scene.h16
-rw-r--r--editor/import/resource_importer_texture.cpp10
-rw-r--r--editor/import/resource_importer_texture.h10
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp8
-rw-r--r--editor/import/resource_importer_texture_atlas.h6
-rw-r--r--editor/import/resource_importer_wav.h2
-rw-r--r--editor/import_dock.cpp34
-rw-r--r--editor/inspector_dock.cpp60
-rw-r--r--editor/node_3d_editor_gizmos.cpp4647
-rw-r--r--editor/node_3d_editor_gizmos.h452
-rw-r--r--editor/node_dock.cpp6
-rw-r--r--editor/pane_drag.cpp4
-rw-r--r--editor/plugin_config_dialog.cpp9
-rw-r--r--editor/plugins/SCsub2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp22
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp38
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp56
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp50
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp158
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp99
-rw-r--r--editor/plugins/animation_state_machine_editor.h1
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp6
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp116
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp28
-rw-r--r--editor/plugins/baked_lightmap_editor_plugin.cpp12
-rw-r--r--editor/plugins/camera_3d_editor_plugin.cpp124
-rw-r--r--editor/plugins/camera_3d_editor_plugin.h75
-rw-r--r--editor/plugins/camera_editor_plugin.cpp124
-rw-r--r--editor/plugins/camera_editor_plugin.h75
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp423
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h6
-rw-r--r--editor/plugins/collision_polygon_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp608
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.h119
-rw-r--r--editor/plugins/collision_polygon_editor_plugin.cpp608
-rw-r--r--editor/plugins/collision_polygon_editor_plugin.h119
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp31
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h2
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp16
-rw-r--r--editor/plugins/cpu_particles_3d_editor_plugin.cpp144
-rw-r--r--editor/plugins/cpu_particles_3d_editor_plugin.h85
-rw-r--r--editor/plugins/cpu_particles_editor_plugin.cpp145
-rw-r--r--editor/plugins/cpu_particles_editor_plugin.h85
-rw-r--r--editor/plugins/curve_editor_plugin.cpp28
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp1
-rw-r--r--editor/plugins/editor_preview_plugins.cpp194
-rw-r--r--editor/plugins/gi_probe_editor_plugin.cpp24
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp432
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.h100
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp490
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.h121
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp4
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp20
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp185
-rw-r--r--editor/plugins/material_editor_plugin.h49
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp24
-rw-r--r--editor/plugins/mesh_editor_plugin.h24
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp528
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.h104
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.cpp531
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.h104
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp38
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp46
-rw-r--r--editor/plugins/multimesh_editor_plugin.h8
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.cpp2
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.h2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp6817
-rw-r--r--editor/plugins/node_3d_editor_plugin.h892
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp435
-rw-r--r--editor/plugins/particles_2d_editor_plugin.h100
-rw-r--r--editor/plugins/particles_editor_plugin.cpp493
-rw-r--r--editor/plugins/particles_editor_plugin.h121
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp28
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp653
-rw-r--r--editor/plugins/path_3d_editor_plugin.h121
-rw-r--r--editor/plugins/path_editor_plugin.cpp653
-rw-r--r--editor/plugins/path_editor_plugin.h123
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.cpp113
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.h78
-rw-r--r--editor/plugins/physical_bone_plugin.cpp112
-rw-r--r--editor/plugins/physical_bone_plugin.h78
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp66
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp16
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp16
-rw-r--r--editor/plugins/script_editor_plugin.cpp157
-rw-r--r--editor/plugins/script_editor_plugin.h8
-rw-r--r--editor/plugins/script_text_editor.cpp142
-rw-r--r--editor/plugins/script_text_editor.h3
-rw-r--r--editor/plugins/shader_editor_plugin.cpp88
-rw-r--r--editor/plugins/shader_editor_plugin.h2
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp195
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h96
-rw-r--r--editor/plugins/skeleton_editor_plugin.cpp195
-rw-r--r--editor/plugins/skeleton_editor_plugin.h96
-rw-r--r--editor/plugins/skeleton_ik_3d_editor_plugin.cpp96
-rw-r--r--editor/plugins/skeleton_ik_3d_editor_plugin.h64
-rw-r--r--editor/plugins/skeleton_ik_editor_plugin.cpp99
-rw-r--r--editor/plugins/skeleton_ik_editor_plugin.h64
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp6761
-rw-r--r--editor/plugins/spatial_editor_plugin.h879
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp611
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.h117
-rw-r--r--editor/plugins/sprite_editor_plugin.cpp611
-rw-r--r--editor/plugins/sprite_editor_plugin.h117
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp59
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h2
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp4
-rw-r--r--editor/plugins/text_editor.cpp84
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--editor/plugins/texture_editor_plugin.cpp6
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp73
-rw-r--r--editor/plugins/texture_region_editor_plugin.h8
-rw-r--r--editor/plugins/theme_editor_plugin.cpp42
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp66
-rw-r--r--editor/plugins/tile_map_editor_plugin.h1
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp118
-rw-r--r--editor/plugins/tile_set_editor_plugin.h6
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp42
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp193
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h2
-rw-r--r--editor/progress_dialog.cpp19
-rw-r--r--editor/progress_dialog.h4
-rw-r--r--editor/project_export.cpp108
-rw-r--r--editor/project_export.h1
-rw-r--r--editor/project_manager.cpp229
-rw-r--r--editor/project_manager.h1
-rw-r--r--editor/project_settings_editor.cpp165
-rw-r--r--editor/project_settings_editor.h6
-rw-r--r--editor/property_editor.cpp128
-rw-r--r--editor/property_editor.h4
-rw-r--r--editor/property_selector.cpp92
-rw-r--r--editor/pvrtc_compress.cpp4
-rw-r--r--editor/quick_open.cpp31
-rw-r--r--editor/quick_open.h6
-rw-r--r--editor/rename_dialog.cpp76
-rw-r--r--editor/rename_dialog.h5
-rw-r--r--editor/reparent_dialog.cpp6
-rw-r--r--editor/scene_tree_dock.cpp266
-rw-r--r--editor/scene_tree_dock.h8
-rw-r--r--editor/scene_tree_editor.cpp115
-rw-r--r--editor/script_create_dialog.cpp97
-rw-r--r--editor/script_create_dialog.h5
-rw-r--r--editor/settings_config_dialog.cpp66
-rw-r--r--editor/spatial_editor_gizmos.cpp4510
-rw-r--r--editor/spatial_editor_gizmos.h434
-rw-r--r--editor/translations/ca.po13
-rw-r--r--editor/translations/cs.po5
-rw-r--r--editor/translations/de.po9
-rw-r--r--editor/translations/es.po6
-rw-r--r--editor/translations/es_AR.po6
-rwxr-xr-xeditor/translations/extract.py44
-rw-r--r--editor/translations/fi.po8
-rw-r--r--editor/translations/ja.po27
-rw-r--r--editor/translations/ko.po4
-rw-r--r--editor/translations/lv.po52
-rw-r--r--editor/translations/nl.po4
-rw-r--r--editor/translations/pl.po5
-rw-r--r--editor/translations/pt_PT.po7
-rw-r--r--editor/translations/ru.po8
-rw-r--r--editor/translations/tr.po28
-rw-r--r--gles_builders.py268
-rw-r--r--main/SCsub17
-rw-r--r--main/input_default.cpp1197
-rw-r--r--main/input_default.h280
-rw-r--r--main/main.cpp469
-rw-r--r--main/main_builders.py75
-rw-r--r--main/performance.cpp40
-rw-r--r--main/tests/SCsub2
-rw-r--r--main/tests/test_astar.cpp4
-rw-r--r--main/tests/test_gdscript.cpp20
-rw-r--r--main/tests/test_gui.cpp8
-rw-r--r--main/tests/test_main.cpp23
-rw-r--r--main/tests/test_main.h3
-rw-r--r--main/tests/test_math.cpp12
-rw-r--r--main/tests/test_oa_hash_map.cpp5
-rw-r--r--main/tests/test_oa_hash_map.h1
-rw-r--r--main/tests/test_ordered_hash_map.cpp10
-rw-r--r--main/tests/test_ordered_hash_map.h4
-rw-r--r--main/tests/test_physics.cpp438
-rw-r--r--main/tests/test_physics.h41
-rw-r--r--main/tests/test_physics_2d.cpp89
-rw-r--r--main/tests/test_physics_3d.cpp439
-rw-r--r--main/tests/test_physics_3d.h41
-rw-r--r--main/tests/test_render.cpp27
-rw-r--r--main/tests/test_shader_lang.cpp10
-rw-r--r--main/tests/test_string.cpp6
-rw-r--r--methods.py357
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj12
-rw-r--r--misc/dist/ios_xcode/godot_ios/dylibs/empty2
-rw-r--r--misc/hooks/README.md37
-rwxr-xr-xmisc/hooks/pre-commit2
-rwxr-xr-xmisc/hooks/pre-commit-black132
-rwxr-xr-xmisc/hooks/pre-commit-clang-format14
-rwxr-xr-xmisc/hooks/pre-commit-makerst9
-rwxr-xr-xmisc/scripts/fix_headers.py24
-rwxr-xr-xmisc/scripts/fix_style.sh20
-rwxr-xr-xmisc/travis/android-tools-linux.sh6
-rwxr-xr-xmisc/travis/black-format.sh48
-rwxr-xr-xmisc/travis/clang-format.sh8
-rw-r--r--modules/SCsub9
-rw-r--r--modules/arkit/SCsub6
-rw-r--r--modules/arkit/arkit_interface.h18
-rw-r--r--modules/arkit/arkit_interface.mm58
-rw-r--r--modules/arkit/arkit_session_delegate.mm2
-rw-r--r--modules/arkit/config.py3
-rw-r--r--modules/arkit/register_types.cpp2
-rw-r--r--modules/assimp/SCsub150
-rw-r--r--modules/assimp/config.py3
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp144
-rw-r--r--modules/assimp/editor_scene_importer_assimp.h20
-rw-r--r--modules/assimp/import_state.h34
-rw-r--r--modules/assimp/import_utils.h12
-rw-r--r--modules/assimp/register_types.h5
-rw-r--r--modules/basis_universal/SCsub42
-rw-r--r--modules/basis_universal/config.py1
-rw-r--r--modules/basis_universal/register_types.cpp37
-rw-r--r--modules/basis_universal/register_types.h5
-rw-r--r--modules/basis_universal/texture_basisu.cpp12
-rw-r--r--modules/bmp/SCsub4
-rw-r--r--modules/bmp/config.py1
-rw-r--r--modules/bmp/image_loader_bmp.cpp4
-rw-r--r--modules/bmp/register_types.cpp2
-rw-r--r--modules/bmp/register_types.h5
-rw-r--r--modules/bullet/SCsub357
-rw-r--r--modules/bullet/area_bullet.cpp48
-rw-r--r--modules/bullet/area_bullet.h16
-rw-r--r--modules/bullet/btRayShape.cpp1
-rw-r--r--modules/bullet/bullet_physics_server.cpp426
-rw-r--r--modules/bullet/bullet_physics_server.h20
-rw-r--r--modules/bullet/bullet_utilities.h2
-rw-r--r--modules/bullet/collision_object_bullet.cpp14
-rw-r--r--modules/bullet/collision_object_bullet.h8
-rw-r--r--modules/bullet/cone_twist_joint_bullet.cpp28
-rw-r--r--modules/bullet/cone_twist_joint_bullet.h6
-rw-r--r--modules/bullet/config.py7
-rw-r--r--modules/bullet/constraint_bullet.cpp4
-rw-r--r--modules/bullet/constraint_bullet.h2
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml13
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsDirectBodyState3D.xml13
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsServer.xml13
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsServer3D.xml13
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp104
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h12
-rw-r--r--modules/bullet/godot_collision_configuration.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.cpp8
-rw-r--r--modules/bullet/godot_result_callbacks.h14
-rw-r--r--modules/bullet/hinge_joint_bullet.cpp58
-rw-r--r--modules/bullet/hinge_joint_bullet.h10
-rw-r--r--modules/bullet/joint_bullet.h4
-rw-r--r--modules/bullet/pin_joint_bullet.cpp16
-rw-r--r--modules/bullet/pin_joint_bullet.h6
-rw-r--r--modules/bullet/register_types.cpp8
-rw-r--r--modules/bullet/rid_bullet.h8
-rw-r--r--modules/bullet/rigid_body_bullet.cpp214
-rw-r--r--modules/bullet/rigid_body_bullet.h44
-rw-r--r--modules/bullet/shape_bullet.cpp46
-rw-r--r--modules/bullet/shape_bullet.h22
-rw-r--r--modules/bullet/slider_joint_bullet.cpp94
-rw-r--r--modules/bullet/slider_joint_bullet.h6
-rw-r--r--modules/bullet/soft_body_bullet.cpp24
-rw-r--r--modules/bullet/soft_body_bullet.h6
-rw-r--r--modules/bullet/space_bullet.cpp146
-rw-r--r--modules/bullet/space_bullet.h32
-rw-r--r--modules/camera/SCsub7
-rw-r--r--modules/camera/camera_ios.h2
-rw-r--r--modules/camera/config.py3
-rw-r--r--modules/csg/SCsub4
-rw-r--r--modules/csg/config.py21
-rw-r--r--modules/csg/csg.cpp2
-rw-r--r--modules/csg/csg.h4
-rw-r--r--modules/csg/csg_gizmos.cpp146
-rw-r--r--modules/csg/csg_gizmos.h20
-rw-r--r--modules/csg/csg_shape.cpp602
-rw-r--r--modules/csg/csg_shape.h72
-rw-r--r--modules/csg/doc_classes/CSGBox.xml29
-rw-r--r--modules/csg/doc_classes/CSGBox3D.xml29
-rw-r--r--modules/csg/doc_classes/CSGCombiner.xml15
-rw-r--r--modules/csg/doc_classes/CSGCombiner3D.xml15
-rw-r--r--modules/csg/doc_classes/CSGCylinder.xml35
-rw-r--r--modules/csg/doc_classes/CSGCylinder3D.xml35
-rw-r--r--modules/csg/doc_classes/CSGMesh.xml23
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml23
-rw-r--r--modules/csg/doc_classes/CSGPolygon.xml74
-rw-r--r--modules/csg/doc_classes/CSGPolygon3D.xml74
-rw-r--r--modules/csg/doc_classes/CSGPrimitive.xml20
-rw-r--r--modules/csg/doc_classes/CSGPrimitive3D.xml20
-rw-r--r--modules/csg/doc_classes/CSGShape.xml100
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml100
-rw-r--r--modules/csg/doc_classes/CSGSphere.xml32
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml32
-rw-r--r--modules/csg/doc_classes/CSGTorus.xml35
-rw-r--r--modules/csg/doc_classes/CSGTorus3D.xml35
-rw-r--r--modules/csg/icons/CSGBox3D.svg (renamed from modules/csg/icons/CSGBox.svg)0
-rw-r--r--modules/csg/icons/CSGCapsule3D.svg (renamed from modules/csg/icons/CSGCapsule.svg)0
-rw-r--r--modules/csg/icons/CSGCombiner3D.svg (renamed from modules/csg/icons/CSGCombiner.svg)0
-rw-r--r--modules/csg/icons/CSGCylinder3D.svg (renamed from modules/csg/icons/CSGCylinder.svg)0
-rw-r--r--modules/csg/icons/CSGMesh3D.svg (renamed from modules/csg/icons/CSGMesh.svg)0
-rw-r--r--modules/csg/icons/CSGPolygon3D.svg (renamed from modules/csg/icons/CSGPolygon.svg)0
-rw-r--r--modules/csg/icons/CSGSphere3D.svg (renamed from modules/csg/icons/CSGSphere.svg)0
-rw-r--r--modules/csg/icons/CSGTorus3D.svg (renamed from modules/csg/icons/CSGTorus.svg)0
-rw-r--r--modules/csg/register_types.cpp18
-rw-r--r--modules/csg/register_types.h5
-rw-r--r--modules/cvtt/SCsub6
-rw-r--r--modules/cvtt/config.py3
-rw-r--r--modules/cvtt/register_types.h9
-rw-r--r--modules/dds/SCsub4
-rw-r--r--modules/dds/config.py1
-rw-r--r--modules/dds/register_types.h5
-rw-r--r--modules/dds/texture_loader_dds.h2
-rw-r--r--modules/enet/SCsub6
-rw-r--r--modules/enet/config.py3
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp28
-rw-r--r--modules/enet/register_types.h5
-rw-r--r--modules/etc/SCsub34
-rw-r--r--modules/etc/config.py3
-rw-r--r--modules/etc/image_etc.cpp2
-rw-r--r--modules/etc/register_types.h5
-rw-r--r--modules/etc/texture_loader_pkm.h2
-rw-r--r--modules/freetype/SCsub30
-rw-r--r--modules/freetype/config.py1
-rw-r--r--modules/freetype/register_types.h5
-rw-r--r--modules/gdnative/SCsub17
-rw-r--r--modules/gdnative/android/android_gdn.cpp8
-rw-r--r--modules/gdnative/arvr/SCsub6
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.cpp439
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.h91
-rw-r--r--modules/gdnative/arvr/config.py5
-rw-r--r--modules/gdnative/arvr/register_types.cpp39
-rw-r--r--modules/gdnative/arvr/register_types.h32
-rw-r--r--modules/gdnative/config.py5
-rw-r--r--modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml15
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml2
-rw-r--r--modules/gdnative/doc_classes/XRInterfaceGDNative.xml15
-rw-r--r--modules/gdnative/gdnative.cpp20
-rw-r--r--modules/gdnative/gdnative.h2
-rw-r--r--modules/gdnative/gdnative/gdnative.cpp8
-rw-r--r--modules/gdnative/gdnative_api.json28
-rw-r--r--modules/gdnative/gdnative_builders.py270
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp36
-rw-r--r--modules/gdnative/include/arvr/godot_arvr.h92
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h3
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h12
-rw-r--r--modules/gdnative/include/xr/godot_xr.h91
-rw-r--r--modules/gdnative/nativescript/SCsub8
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp20
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp14
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp64
-rw-r--r--modules/gdnative/nativescript/nativescript.h22
-rw-r--r--modules/gdnative/nativescript/register_types.h5
-rw-r--r--modules/gdnative/net/SCsub9
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.cpp30
-rw-r--r--modules/gdnative/net/packet_peer_gdnative.cpp10
-rw-r--r--modules/gdnative/net/register_types.h5
-rw-r--r--modules/gdnative/net/stream_peer_gdnative.cpp12
-rw-r--r--modules/gdnative/pluginscript/SCsub6
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h4
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.h2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp32
-rw-r--r--modules/gdnative/pluginscript/register_types.h5
-rw-r--r--modules/gdnative/register_types.cpp8
-rw-r--r--modules/gdnative/register_types.h5
-rw-r--r--modules/gdnative/videodecoder/SCsub8
-rw-r--r--modules/gdnative/videodecoder/register_types.h5
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.cpp48
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.h10
-rw-r--r--modules/gdnative/xr/SCsub6
-rw-r--r--modules/gdnative/xr/config.py6
-rw-r--r--modules/gdnative/xr/register_types.cpp40
-rw-r--r--modules/gdnative/xr/register_types.h37
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.cpp428
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.h91
-rw-r--r--modules/gdnavigation/SCsub34
-rw-r--r--modules/gdnavigation/config.py1
-rw-r--r--modules/gdnavigation/gd_navigation_server.cpp86
-rw-r--r--modules/gdnavigation/gd_navigation_server.h4
-rw-r--r--modules/gdnavigation/nav_map.cpp26
-rw-r--r--modules/gdnavigation/nav_region.cpp4
-rw-r--r--modules/gdnavigation/nav_region.h2
-rw-r--r--modules/gdnavigation/nav_utils.h6
-rw-r--r--modules/gdnavigation/navigation_mesh_editor_plugin.cpp22
-rw-r--r--modules/gdnavigation/navigation_mesh_editor_plugin.h6
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.cpp92
-rw-r--r--modules/gdnavigation/navigation_mesh_generator.h2
-rw-r--r--modules/gdnavigation/register_types.cpp8
-rw-r--r--modules/gdnavigation/register_types.h5
-rw-r--r--modules/gdnavigation/rvo_agent.cpp4
-rw-r--r--modules/gdscript/SCsub10
-rw-r--r--modules/gdscript/config.py3
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml8
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp10
-rw-r--r--modules/gdscript/gdscript.cpp204
-rw-r--r--modules/gdscript/gdscript.h19
-rw-r--r--modules/gdscript/gdscript_compiler.cpp30
-rw-r--r--modules/gdscript/gdscript_compiler.h4
-rw-r--r--modules/gdscript/gdscript_editor.cpp113
-rw-r--r--modules/gdscript/gdscript_function.cpp60
-rw-r--r--modules/gdscript/gdscript_function.h6
-rw-r--r--modules/gdscript/gdscript_functions.cpp6
-rw-r--r--modules/gdscript/gdscript_parser.cpp296
-rw-r--r--modules/gdscript/gdscript_parser.h24
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp10
-rw-r--r--modules/gdscript/gdscript_tokenizer.h11
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp16
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp16
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h2
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp8
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp10
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp20
-rw-r--r--modules/gdscript/language_server/lsp.hpp8
-rw-r--r--modules/gdscript/register_types.cpp2
-rw-r--r--modules/gdscript/register_types.h5
-rw-r--r--modules/glslang/SCsub12
-rw-r--r--modules/glslang/config.py1
-rw-r--r--modules/glslang/register_types.cpp2
-rw-r--r--modules/glslang/register_types.h6
-rw-r--r--modules/gridmap/SCsub4
-rw-r--r--modules/gridmap/config.py3
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml2
-rw-r--r--modules/gridmap/doc_classes/README.md2
-rw-r--r--modules/gridmap/grid_map.cpp176
-rw-r--r--modules/gridmap/grid_map.h14
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp171
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h10
-rw-r--r--modules/gridmap/register_types.h5
-rw-r--r--modules/hdr/SCsub4
-rw-r--r--modules/hdr/config.py1
-rw-r--r--modules/hdr/register_types.cpp2
-rw-r--r--modules/hdr/register_types.h5
-rw-r--r--modules/jpg/SCsub4
-rw-r--r--modules/jpg/config.py1
-rw-r--r--modules/jpg/register_types.cpp2
-rw-r--r--modules/jpg/register_types.h5
-rw-r--r--modules/jsonrpc/SCsub4
-rw-r--r--modules/jsonrpc/config.py5
-rw-r--r--modules/jsonrpc/jsonrpc.cpp2
-rw-r--r--modules/jsonrpc/register_types.h5
-rwxr-xr-xmodules/mbedtls/SCsub8
-rwxr-xr-xmodules/mbedtls/config.py1
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp28
-rw-r--r--modules/mbedtls/crypto_mbedtls.h4
-rw-r--r--modules/mbedtls/dtls_server_mbedtls.cpp2
-rwxr-xr-xmodules/mbedtls/packet_peer_mbed_dtls.cpp16
-rwxr-xr-xmodules/mbedtls/packet_peer_mbed_dtls.h2
-rwxr-xr-xmodules/mbedtls/register_types.h5
-rw-r--r--modules/mbedtls/ssl_context_mbedtls.cpp14
-rwxr-xr-xmodules/mbedtls/stream_peer_mbedtls.cpp14
-rw-r--r--modules/mobile_vr/SCsub6
-rw-r--r--modules/mobile_vr/config.py3
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml8
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp53
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h14
-rw-r--r--modules/mobile_vr/register_types.cpp2
-rw-r--r--modules/mobile_vr/register_types.h5
-rw-r--r--modules/modules_builders.py6
-rw-r--r--modules/mono/SCsub49
-rw-r--r--modules/mono/build_scripts/api_solution_build.py35
-rw-r--r--modules/mono/build_scripts/gen_cs_glue_version.py20
-rw-r--r--modules/mono/build_scripts/godot_tools_build.py23
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py20
-rw-r--r--modules/mono/build_scripts/mono_configure.py509
-rw-r--r--modules/mono/build_scripts/mono_reg_utils.py59
-rw-r--r--modules/mono/build_scripts/solution_builder.py132
-rw-r--r--modules/mono/build_scripts/tls_configure.py36
-rw-r--r--modules/mono/class_db_api_json.cpp10
-rw-r--r--modules/mono/config.py62
-rw-r--r--modules/mono/csharp_script.cpp719
-rw-r--r--modules/mono/csharp_script.h121
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeConnection/Properties/AssemblyInfo.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs37
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs78
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs64
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs192
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs26
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/BuildManager.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/BuildTab.cs12
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs12
-rwxr-xr-xmodules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs618
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs404
-rwxr-xr-xmodules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs93
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs109
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs44
-rw-r--r--modules/mono/editor/bindings_generator.cpp385
-rw-r--r--modules/mono/editor/bindings_generator.h67
-rw-r--r--modules/mono/editor/csharp_project.cpp4
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp18
-rw-r--r--modules/mono/editor/godotsharp_export.cpp13
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs31
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs395
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs37
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs59
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs29
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs262
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs82
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs26
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs380
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs402
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj7
-rw-r--r--modules/mono/glue/base_object_glue.cpp51
-rw-r--r--modules/mono/glue/base_object_glue.h8
-rw-r--r--modules/mono/glue/collections_glue.cpp26
-rw-r--r--modules/mono/glue/gd_glue.cpp28
-rw-r--r--modules/mono/glue/gd_glue.h2
-rw-r--r--modules/mono/glue/glue_header.h4
-rw-r--r--modules/mono/glue/string_name_glue.cpp61
-rw-r--r--modules/mono/glue/string_name_glue.h54
-rw-r--r--modules/mono/godotsharp_dirs.cpp12
-rw-r--r--modules/mono/managed_callable.cpp145
-rw-r--r--modules/mono/managed_callable.h77
-rw-r--r--modules/mono/mono_gc_handle.cpp57
-rw-r--r--modules/mono/mono_gc_handle.h87
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp198
-rw-r--r--modules/mono/mono_gd/gd_mono.h14
-rw-r--r--modules/mono/mono_gd/gd_mono_android.cpp686
-rw-r--r--modules/mono/mono_gd/gd_mono_android.h52
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp288
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h35
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp182
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h23
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp78
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp89
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h15
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp15
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp10
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h9
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp441
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h102
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp88
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h26
-rw-r--r--modules/mono/mono_gd/gd_mono_method_thunk.h52
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp32
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h20
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp160
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h23
-rw-r--r--modules/mono/mono_gd/managed_type.h2
-rwxr-xr-xmodules/mono/mono_gd/support/android_support.cpp690
-rwxr-xr-xmodules/mono/mono_gd/support/android_support.h55
-rwxr-xr-xmodules/mono/mono_gd/support/ios_support.h51
-rwxr-xr-xmodules/mono/mono_gd/support/ios_support.mm151
-rw-r--r--modules/mono/register_types.cpp4
-rw-r--r--modules/mono/signal_awaiter_utils.cpp215
-rw-r--r--modules/mono/signal_awaiter_utils.h68
-rw-r--r--modules/mono/utils/macros.h53
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp6
-rw-r--r--modules/mono/utils/osx_utils.cpp6
-rw-r--r--modules/mono/utils/path_utils.cpp10
-rw-r--r--modules/mono/utils/string_utils.cpp2
-rw-r--r--modules/mono/utils/thread_local.cpp107
-rw-r--r--modules/mono/utils/thread_local.h177
-rw-r--r--modules/ogg/SCsub9
-rw-r--r--modules/ogg/config.py1
-rw-r--r--modules/ogg/register_types.h5
-rw-r--r--modules/opensimplex/SCsub4
-rw-r--r--modules/opensimplex/config.py9
-rw-r--r--modules/opensimplex/noise_texture.cpp25
-rw-r--r--modules/opensimplex/register_types.h5
-rw-r--r--modules/opus/SCsub43
-rw-r--r--modules/opus/audio_stream_opus.cpp379
-rw-r--r--modules/opus/audio_stream_opus.h142
-rw-r--r--modules/opus/config.py9
-rw-r--r--modules/opus/register_types.cpp21
-rw-r--r--modules/opus/register_types.h5
-rw-r--r--modules/opus/stub/register_types.cpp37
-rw-r--r--modules/opus/stub/register_types.h32
-rw-r--r--modules/pvr/SCsub4
-rw-r--r--modules/pvr/config.py1
-rw-r--r--modules/pvr/register_types.h5
-rw-r--r--modules/pvr/texture_loader_pvr.cpp2
-rw-r--r--modules/pvr/texture_loader_pvr.h2
-rw-r--r--modules/regex/SCsub16
-rw-r--r--modules/regex/config.py3
-rw-r--r--modules/regex/regex.cpp26
-rw-r--r--modules/regex/register_types.h5
-rw-r--r--modules/squish/SCsub6
-rw-r--r--modules/squish/config.py1
-rw-r--r--modules/squish/register_types.h5
-rw-r--r--modules/stb_vorbis/SCsub4
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp23
-rw-r--r--modules/stb_vorbis/config.py3
-rw-r--r--modules/stb_vorbis/register_types.h5
-rw-r--r--modules/stb_vorbis/resource_importer_ogg_vorbis.h2
-rw-r--r--modules/svg/SCsub6
-rw-r--r--modules/svg/config.py1
-rw-r--r--modules/svg/image_loader_svg.cpp4
-rw-r--r--modules/svg/image_loader_svg.h2
-rw-r--r--modules/svg/register_types.cpp2
-rw-r--r--modules/svg/register_types.h5
-rw-r--r--modules/tga/SCsub4
-rw-r--r--modules/tga/config.py1
-rw-r--r--modules/tga/image_loader_tga.cpp2
-rw-r--r--modules/tga/register_types.cpp2
-rw-r--r--modules/tga/register_types.h5
-rw-r--r--modules/theora/SCsub60
-rw-r--r--modules/theora/config.py3
-rw-r--r--modules/theora/register_types.h5
-rw-r--r--modules/theora/video_stream_theora.cpp14
-rw-r--r--modules/theora/video_stream_theora.h2
-rw-r--r--modules/tinyexr/SCsub4
-rw-r--r--modules/tinyexr/config.py3
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp6
-rw-r--r--modules/tinyexr/register_types.cpp4
-rw-r--r--modules/tinyexr/register_types.h5
-rw-r--r--modules/upnp/SCsub6
-rw-r--r--modules/upnp/config.py5
-rw-r--r--modules/upnp/register_types.h5
-rw-r--r--modules/upnp/upnp.cpp29
-rw-r--r--modules/upnp/upnp.h2
-rw-r--r--modules/upnp/upnp_device.cpp30
-rw-r--r--modules/vhacd/SCsub6
-rw-r--r--modules/vhacd/config.py2
-rw-r--r--modules/vhacd/register_types.cpp6
-rw-r--r--modules/vhacd/register_types.h5
-rw-r--r--modules/visual_script/SCsub4
-rw-r--r--modules/visual_script/config.py3
-rw-r--r--modules/visual_script/register_types.cpp4
-rw-r--r--modules/visual_script/register_types.h5
-rw-r--r--modules/visual_script/visual_script.cpp70
-rw-r--r--modules/visual_script/visual_script.h8
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp10
-rw-r--r--modules/visual_script/visual_script_editor.cpp286
-rw-r--r--modules/visual_script/visual_script_editor.h10
-rw-r--r--modules/visual_script/visual_script_expression.cpp66
-rw-r--r--modules/visual_script/visual_script_expression.h2
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp56
-rw-r--r--modules/visual_script/visual_script_nodes.cpp23
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp104
-rw-r--r--modules/visual_script/visual_script_property_selector.h1
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp18
-rw-r--r--modules/vorbis/SCsub29
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp406
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h137
-rw-r--r--modules/vorbis/config.py1
-rw-r--r--modules/vorbis/register_types.cpp17
-rw-r--r--modules/vorbis/register_types.h5
-rw-r--r--modules/vorbis/stub/register_types.cpp37
-rw-r--r--modules/vorbis/stub/register_types.h32
-rw-r--r--modules/webm/SCsub12
-rw-r--r--modules/webm/config.py5
-rw-r--r--modules/webm/libvpx/SCsub175
-rw-r--r--modules/webm/register_types.h5
-rw-r--r--modules/webm/video_stream_webm.cpp34
-rw-r--r--modules/webm/video_stream_webm.h2
-rw-r--r--modules/webp/SCsub6
-rw-r--r--modules/webp/config.py1
-rw-r--r--modules/webp/image_loader_webp.cpp10
-rw-r--r--modules/webp/register_types.cpp2
-rw-r--r--modules/webp/register_types.h5
-rw-r--r--modules/webrtc/SCsub8
-rw-r--r--modules/webrtc/config.py5
-rw-r--r--modules/webrtc/register_types.h5
-rw-r--r--modules/webrtc/webrtc_data_channel_gdnative.cpp36
-rw-r--r--modules/webrtc/webrtc_data_channel_js.cpp4
-rw-r--r--modules/webrtc/webrtc_multiplayer.cpp27
-rw-r--r--modules/webrtc/webrtc_multiplayer.h4
-rw-r--r--modules/webrtc/webrtc_peer_connection.cpp4
-rw-r--r--modules/webrtc/webrtc_peer_connection_gdnative.cpp24
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.cpp2
-rw-r--r--modules/websocket/SCsub6
-rw-r--r--modules/websocket/config.py5
-rw-r--r--modules/websocket/emws_client.cpp2
-rw-r--r--modules/websocket/emws_server.cpp2
-rw-r--r--modules/websocket/packet_buffer.h4
-rw-r--r--modules/websocket/register_types.h5
-rw-r--r--modules/websocket/websocket_macros.h4
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp18
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h2
-rw-r--r--modules/websocket/wsl_client.cpp6
-rw-r--r--modules/websocket/wsl_peer.cpp20
-rw-r--r--modules/websocket/wsl_peer.h6
-rw-r--r--modules/websocket/wsl_server.cpp14
-rw-r--r--modules/websocket/wsl_server.h2
-rw-r--r--modules/xatlas_unwrap/SCsub6
-rw-r--r--modules/xatlas_unwrap/config.py3
-rw-r--r--modules/xatlas_unwrap/register_types.cpp4
-rw-r--r--modules/xatlas_unwrap/register_types.h5
-rw-r--r--platform/SCsub26
-rw-r--r--platform/android/SCsub79
-rw-r--r--platform/android/api/api.cpp9
-rw-r--r--platform/android/api/api.h5
-rw-r--r--platform/android/api/java_class_wrapper.h6
-rw-r--r--platform/android/api/jni_singleton.h242
-rw-r--r--platform/android/audio_driver_jandroid.cpp14
-rw-r--r--platform/android/audio_driver_opensl.cpp10
-rw-r--r--platform/android/detect.py246
-rw-r--r--platform/android/dir_access_jandroid.cpp12
-rw-r--r--platform/android/display_server_android.cpp655
-rw-r--r--platform/android/display_server_android.h174
-rw-r--r--platform/android/export/export.cpp77
-rw-r--r--platform/android/export/export.h5
-rw-r--r--platform/android/file_access_android.cpp8
-rw-r--r--platform/android/file_access_jandroid.cpp2
-rw-r--r--platform/android/java/app/build.gradle6
-rw-r--r--platform/android/java/app/config.gradle4
-rw-r--r--platform/android/java/app/settings.gradle2
-rw-r--r--platform/android/java/build.gradle6
-rw-r--r--platform/android/java/lib/AndroidManifest.xml2
-rw-r--r--platform/android/java/lib/build.gradle5
-rw-r--r--platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.pngbin1116 -> 0 bytes
-rw-r--r--platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.pngbin388 -> 0 bytes
-rw-r--r--platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.pngbin462 -> 0 bytes
-rw-r--r--platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.pngbin1556 -> 0 bytes
-rw-r--r--platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java94
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java225
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java40
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java7
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java47
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotView.java204
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java142
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java32
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java12
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java42
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java38
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java116
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/GodotPaymentInterface.java97
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java93
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java72
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java418
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java118
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java141
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java141
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java122
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java98
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java69
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java227
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/RequestParams.java85
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt43
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java1
-rw-r--r--platform/android/java/plugins/godotpayment/build.gradle1
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl (renamed from platform/android/java/lib/aidl/com/android/vending/billing/IInAppBillingService.aidl)0
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java116
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java59
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java93
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java71
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java405
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java118
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java141
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java141
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/CustomSSLSocketFactory.java70
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/HttpRequester.java228
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/RequestParams.java84
-rw-r--r--platform/android/java_class_wrapper.cpp20
-rw-r--r--platform/android/java_godot_io_wrapper.cpp41
-rw-r--r--platform/android/java_godot_io_wrapper.h10
-rw-r--r--platform/android/java_godot_lib_jni.cpp114
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/java_godot_wrapper.cpp24
-rw-r--r--platform/android/java_godot_wrapper.h12
-rw-r--r--platform/android/jni_utils.cpp8
-rw-r--r--platform/android/jni_utils.h188
-rw-r--r--platform/android/os_android.cpp529
-rw-r--r--platform/android/os_android.h116
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp48
-rw-r--r--platform/android/plugin/godot_plugin_jni.h2
-rw-r--r--platform/android/string_android.h4
-rw-r--r--platform/android/thread_jandroid.cpp16
-rw-r--r--platform/android/vulkan/vk_renderer_jni.cpp58
-rw-r--r--platform/android/vulkan/vk_renderer_jni.h46
-rw-r--r--platform/android/vulkan/vulkan_context_android.cpp60
-rw-r--r--platform/android/vulkan/vulkan_context_android.h49
-rw-r--r--platform/haiku/SCsub27
-rw-r--r--platform/haiku/audio_driver_media_kit.cpp8
-rw-r--r--platform/haiku/detect.py140
-rw-r--r--platform/haiku/haiku_direct_window.cpp12
-rw-r--r--platform/haiku/haiku_direct_window.h2
-rw-r--r--platform/haiku/os_haiku.cpp28
-rw-r--r--platform/haiku/os_haiku.h6
-rw-r--r--platform/iphone/SCsub38
-rw-r--r--platform/iphone/app_delegate.h8
-rw-r--r--platform/iphone/app_delegate.mm1
-rw-r--r--platform/iphone/detect.py257
-rw-r--r--platform/iphone/export/export.cpp43
-rw-r--r--platform/iphone/export/export.h5
-rw-r--r--platform/iphone/godot_iphone.cpp4
-rw-r--r--platform/iphone/os_iphone.cpp32
-rw-r--r--platform/iphone/os_iphone.h10
-rw-r--r--platform/iphone/platform_refcount.h48
-rw-r--r--platform/iphone/vulkan_context_iphone.h2
-rw-r--r--platform/iphone/vulkan_context_iphone.mm2
-rw-r--r--platform/javascript/SCsub68
-rw-r--r--platform/javascript/api/api.cpp4
-rw-r--r--platform/javascript/api/api.h5
-rw-r--r--platform/javascript/audio_driver_javascript.cpp6
-rw-r--r--platform/javascript/detect.py152
-rw-r--r--platform/javascript/emscripten_helpers.py25
-rw-r--r--platform/javascript/export/export.cpp4
-rw-r--r--platform/javascript/http_client_javascript.cpp4
-rw-r--r--platform/javascript/http_request.h2
-rw-r--r--platform/javascript/os_javascript.cpp48
-rw-r--r--platform/javascript/os_javascript.h8
-rw-r--r--platform/linuxbsd/SCsub22
-rw-r--r--platform/linuxbsd/context_gl_x11.cpp265
-rw-r--r--platform/linuxbsd/context_gl_x11.h (renamed from platform/x11/context_gl_x11.h)0
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp149
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.h48
-rw-r--r--platform/linuxbsd/detect.py377
-rw-r--r--platform/linuxbsd/detect_prime_x11.cpp238
-rw-r--r--platform/linuxbsd/detect_prime_x11.h37
-rw-r--r--platform/linuxbsd/display_server_x11.cpp3856
-rw-r--r--platform/linuxbsd/display_server_x11.h351
-rw-r--r--platform/linuxbsd/export/export.cpp169
-rw-r--r--platform/linuxbsd/export/export.h36
-rw-r--r--platform/linuxbsd/godot_linuxbsd.cpp67
-rw-r--r--platform/linuxbsd/joypad_linux.cpp554
-rw-r--r--platform/linuxbsd/joypad_linux.h102
-rw-r--r--platform/linuxbsd/key_mapping_x11.cpp (renamed from platform/x11/key_mapping_x11.cpp)0
-rw-r--r--platform/linuxbsd/key_mapping_x11.h (renamed from platform/x11/key_mapping_x11.h)0
-rw-r--r--platform/linuxbsd/logo.png (renamed from platform/x11/logo.png)bin1679 -> 1679 bytes
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp381
-rw-r--r--platform/linuxbsd/os_linuxbsd.h106
-rw-r--r--platform/linuxbsd/pck_embed.ld (renamed from platform/x11/pck_embed.ld)0
-rw-r--r--platform/linuxbsd/pck_embed.legacy.ld (renamed from platform/x11/pck_embed.legacy.ld)0
-rw-r--r--platform/linuxbsd/platform_config.h (renamed from platform/x11/platform_config.h)0
-rw-r--r--platform/linuxbsd/platform_linuxbsd_builders.py17
-rw-r--r--platform/linuxbsd/vulkan_context_x11.cpp57
-rw-r--r--platform/linuxbsd/vulkan_context_x11.h48
-rw-r--r--platform/osx/SCsub20
-rw-r--r--platform/osx/context_gl_osx.h2
-rw-r--r--platform/osx/detect.py208
-rw-r--r--platform/osx/display_server_osx.h308
-rw-r--r--platform/osx/display_server_osx.mm3595
-rw-r--r--platform/osx/export/export.cpp40
-rw-r--r--platform/osx/export/export.h5
-rw-r--r--platform/osx/joypad_osx.cpp58
-rw-r--r--platform/osx/joypad_osx.h6
-rw-r--r--platform/osx/os_osx.h244
-rw-r--r--platform/osx/os_osx.mm2880
-rw-r--r--platform/osx/platform_osx_builders.py10
-rw-r--r--platform/osx/vulkan_context_osx.h2
-rw-r--r--platform/osx/vulkan_context_osx.mm6
-rw-r--r--platform/server/SCsub12
-rw-r--r--platform/server/detect.py265
-rw-r--r--platform/server/os_server.cpp18
-rw-r--r--platform/server/os_server.h10
-rw-r--r--platform/uwp/SCsub20
-rw-r--r--platform/uwp/app.cpp12
-rw-r--r--platform/uwp/context_egl_uwp.cpp2
-rw-r--r--platform/uwp/detect.py172
-rw-r--r--platform/uwp/export/export.cpp36
-rw-r--r--platform/uwp/export/export.h5
-rw-r--r--platform/uwp/joypad_uwp.h2
-rw-r--r--platform/uwp/os_uwp.cpp30
-rw-r--r--platform/uwp/os_uwp.h11
-rw-r--r--platform/windows/SCsub11
-rw-r--r--platform/windows/context_gl_windows.cpp8
-rw-r--r--platform/windows/crash_handler_windows.cpp6
-rw-r--r--platform/windows/detect.py427
-rw-r--r--platform/windows/display_server_windows.cpp3007
-rw-r--r--platform/windows/display_server_windows.h418
-rw-r--r--platform/windows/export/export.cpp2
-rw-r--r--platform/windows/godot_windows.cpp14
-rw-r--r--platform/windows/joypad_windows.cpp44
-rw-r--r--platform/windows/joypad_windows.h10
-rw-r--r--platform/windows/os_windows.cpp2648
-rw-r--r--platform/windows/os_windows.h299
-rw-r--r--platform/windows/platform_windows_builders.py10
-rw-r--r--platform/windows/vulkan_context_win.cpp8
-rw-r--r--platform/windows/vulkan_context_win.h2
-rw-r--r--platform/windows/windows_terminal_logger.cpp2
-rw-r--r--platform/x11/SCsub21
-rw-r--r--platform/x11/context_gl_x11.cpp265
-rw-r--r--platform/x11/crash_handler_x11.cpp149
-rw-r--r--platform/x11/crash_handler_x11.h48
-rw-r--r--platform/x11/detect.py368
-rw-r--r--platform/x11/detect_prime.cpp236
-rw-r--r--platform/x11/detect_prime.h37
-rw-r--r--platform/x11/export/export.cpp169
-rw-r--r--platform/x11/export/export.h31
-rw-r--r--platform/x11/godot_x11.cpp67
-rw-r--r--platform/x11/joypad_linux.cpp551
-rw-r--r--platform/x11/joypad_linux.h102
-rw-r--r--platform/x11/os_x11.cpp3566
-rw-r--r--platform/x11/os_x11.h339
-rw-r--r--platform/x11/platform_x11_builders.py17
-rw-r--r--platform/x11/vulkan_context_x11.cpp57
-rw-r--r--platform/x11/vulkan_context_x11.h48
-rw-r--r--platform_methods.py42
-rw-r--r--scene/2d/SCsub2
-rw-r--r--scene/2d/animated_sprite.cpp772
-rw-r--r--scene/2d/animated_sprite.h231
-rw-r--r--scene/2d/animated_sprite_2d.cpp772
-rw-r--r--scene/2d/animated_sprite_2d.h231
-rw-r--r--scene/2d/area_2d.cpp40
-rw-r--r--scene/2d/audio_stream_player_2d.cpp8
-rw-r--r--scene/2d/back_buffer_copy.cpp6
-rw-r--r--scene/2d/camera_2d.cpp8
-rw-r--r--scene/2d/camera_2d.h2
-rw-r--r--scene/2d/canvas_item.cpp1439
-rw-r--r--scene/2d/canvas_item.h422
-rw-r--r--scene/2d/canvas_modulate.cpp10
-rw-r--r--scene/2d/collision_object_2d.cpp58
-rw-r--r--scene/2d/collision_object_2d.h2
-rw-r--r--scene/2d/collision_polygon_2d.cpp14
-rw-r--r--scene/2d/collision_polygon_2d.h2
-rw-r--r--scene/2d/collision_shape_2d.cpp6
-rw-r--r--scene/2d/cpu_particles_2d.cpp56
-rw-r--r--scene/2d/gpu_particles_2d.cpp432
-rw-r--r--scene/2d/gpu_particles_2d.h127
-rw-r--r--scene/2d/joints_2d.cpp38
-rw-r--r--scene/2d/light_2d.cpp56
-rw-r--r--scene/2d/light_occluder_2d.cpp32
-rw-r--r--scene/2d/line_2d.cpp2
-rw-r--r--scene/2d/line_builder.cpp8
-rw-r--r--scene/2d/navigation_2d.cpp20
-rw-r--r--scene/2d/navigation_2d.h2
-rw-r--r--scene/2d/navigation_agent_2d.cpp57
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp34
-rw-r--r--scene/2d/navigation_polygon.cpp582
-rw-r--r--scene/2d/navigation_polygon.h130
-rw-r--r--scene/2d/navigation_region_2d.cpp582
-rw-r--r--scene/2d/navigation_region_2d.h130
-rw-r--r--scene/2d/node_2d.cpp18
-rw-r--r--scene/2d/node_2d.h2
-rw-r--r--scene/2d/parallax_layer.cpp2
-rw-r--r--scene/2d/particles_2d.cpp432
-rw-r--r--scene/2d/particles_2d.h127
-rw-r--r--scene/2d/path_2d.cpp16
-rw-r--r--scene/2d/path_texture.cpp90
-rw-r--r--scene/2d/path_texture.h64
-rw-r--r--scene/2d/physics_body_2d.cpp160
-rw-r--r--scene/2d/physics_body_2d.h12
-rw-r--r--scene/2d/polygon_2d.cpp10
-rw-r--r--scene/2d/ray_cast_2d.cpp8
-rw-r--r--scene/2d/skeleton_2d.cpp24
-rw-r--r--scene/2d/sprite.cpp539
-rw-r--r--scene/2d/sprite.h143
-rw-r--r--scene/2d/sprite_2d.cpp539
-rw-r--r--scene/2d/sprite_2d.h143
-rw-r--r--scene/2d/tile_map.cpp112
-rw-r--r--scene/2d/touch_screen_button.cpp19
-rw-r--r--scene/2d/visibility_notifier_2d.cpp35
-rw-r--r--scene/2d/y_sort.cpp4
-rw-r--r--scene/3d/SCsub11
-rw-r--r--scene/3d/area.cpp759
-rw-r--r--scene/3d/area.h217
-rw-r--r--scene/3d/area_3d.cpp759
-rw-r--r--scene/3d/area_3d.h217
-rw-r--r--scene/3d/arvr_nodes.cpp621
-rw-r--r--scene/3d/arvr_nodes.h176
-rw-r--r--scene/3d/audio_stream_player_3d.cpp33
-rw-r--r--scene/3d/audio_stream_player_3d.h14
-rw-r--r--scene/3d/baked_lightmap.cpp36
-rw-r--r--scene/3d/bone_attachment.cpp127
-rw-r--r--scene/3d/bone_attachment.h59
-rw-r--r--scene/3d/bone_attachment_3d.cpp127
-rw-r--r--scene/3d/bone_attachment_3d.h59
-rw-r--r--scene/3d/camera.cpp954
-rw-r--r--scene/3d/camera.h246
-rw-r--r--scene/3d/camera_3d.cpp937
-rw-r--r--scene/3d/camera_3d.h246
-rw-r--r--scene/3d/collision_object.cpp396
-rw-r--r--scene/3d/collision_object.h119
-rw-r--r--scene/3d/collision_object_3d.cpp396
-rw-r--r--scene/3d/collision_object_3d.h119
-rw-r--r--scene/3d/collision_polygon.cpp207
-rw-r--r--scene/3d/collision_polygon.h79
-rw-r--r--scene/3d/collision_polygon_3d.cpp207
-rw-r--r--scene/3d/collision_polygon_3d.h79
-rw-r--r--scene/3d/collision_shape.cpp242
-rw-r--r--scene/3d/collision_shape.h78
-rw-r--r--scene/3d/collision_shape_3d.cpp244
-rw-r--r--scene/3d/collision_shape_3d.h78
-rw-r--r--scene/3d/cpu_particles.cpp1546
-rw-r--r--scene/3d/cpu_particles.h298
-rw-r--r--scene/3d/cpu_particles_3d.cpp1546
-rw-r--r--scene/3d/cpu_particles_3d.h298
-rw-r--r--scene/3d/decal.cpp235
-rw-r--r--scene/3d/decal.h114
-rw-r--r--scene/3d/gi_probe.cpp63
-rw-r--r--scene/3d/gi_probe.h12
-rw-r--r--scene/3d/gpu_particles_3d.cpp441
-rw-r--r--scene/3d/gpu_particles_3d.h133
-rw-r--r--scene/3d/immediate_geometry.cpp169
-rw-r--r--scene/3d/immediate_geometry.h73
-rw-r--r--scene/3d/immediate_geometry_3d.cpp169
-rw-r--r--scene/3d/immediate_geometry_3d.h73
-rw-r--r--scene/3d/interpolated_camera.cpp155
-rw-r--r--scene/3d/interpolated_camera.h63
-rw-r--r--scene/3d/light.cpp480
-rw-r--r--scene/3d/light.h216
-rw-r--r--scene/3d/light_3d.cpp528
-rw-r--r--scene/3d/light_3d.h224
-rw-r--r--scene/3d/listener.cpp178
-rw-r--r--scene/3d/listener.h78
-rw-r--r--scene/3d/listener_3d.cpp178
-rw-r--r--scene/3d/listener_3d.h78
-rw-r--r--scene/3d/mesh_instance.cpp421
-rw-r--r--scene/3d/mesh_instance.h103
-rw-r--r--scene/3d/mesh_instance_3d.cpp439
-rw-r--r--scene/3d/mesh_instance_3d.h104
-rw-r--r--scene/3d/multimesh_instance.cpp71
-rw-r--r--scene/3d/multimesh_instance.h58
-rw-r--r--scene/3d/multimesh_instance_3d.cpp71
-rw-r--r--scene/3d/multimesh_instance_3d.h58
-rw-r--r--scene/3d/navigation.cpp125
-rw-r--r--scene/3d/navigation.h79
-rw-r--r--scene/3d/navigation_3d.cpp125
-rw-r--r--scene/3d/navigation_3d.h79
-rw-r--r--scene/3d/navigation_agent.cpp361
-rw-r--r--scene/3d/navigation_agent.h162
-rw-r--r--scene/3d/navigation_agent_3d.cpp362
-rw-r--r--scene/3d/navigation_agent_3d.h162
-rw-r--r--scene/3d/navigation_obstacle.cpp163
-rw-r--r--scene/3d/navigation_obstacle.h71
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp163
-rw-r--r--scene/3d/navigation_obstacle_3d.h71
-rw-r--r--scene/3d/navigation_region.cpp258
-rw-r--r--scene/3d/navigation_region.h75
-rw-r--r--scene/3d/navigation_region_3d.cpp259
-rw-r--r--scene/3d/navigation_region_3d.h75
-rw-r--r--scene/3d/node_3d.cpp848
-rw-r--r--scene/3d/node_3d.h207
-rw-r--r--scene/3d/particles.cpp441
-rw-r--r--scene/3d/particles.h133
-rw-r--r--scene/3d/path.cpp416
-rw-r--r--scene/3d/path.h117
-rw-r--r--scene/3d/path_3d.cpp414
-rw-r--r--scene/3d/path_3d.h117
-rw-r--r--scene/3d/physics_body.cpp2596
-rw-r--r--scene/3d/physics_body.h646
-rw-r--r--scene/3d/physics_body_3d.cpp2680
-rw-r--r--scene/3d/physics_body_3d.h668
-rw-r--r--scene/3d/physics_joint.cpp1049
-rw-r--r--scene/3d/physics_joint.h343
-rw-r--r--scene/3d/physics_joint_3d.cpp1049
-rw-r--r--scene/3d/physics_joint_3d.h343
-rw-r--r--scene/3d/position_3d.h6
-rw-r--r--scene/3d/proximity_group.cpp214
-rw-r--r--scene/3d/proximity_group.h87
-rw-r--r--scene/3d/proximity_group_3d.cpp214
-rw-r--r--scene/3d/proximity_group_3d.h87
-rw-r--r--scene/3d/ray_cast.cpp405
-rw-r--r--scene/3d/ray_cast.h106
-rw-r--r--scene/3d/ray_cast_3d.cpp405
-rw-r--r--scene/3d/ray_cast_3d.h106
-rw-r--r--scene/3d/reflection_probe.cpp34
-rw-r--r--scene/3d/reflection_probe.h8
-rw-r--r--scene/3d/remote_transform.cpp223
-rw-r--r--scene/3d/remote_transform.h78
-rw-r--r--scene/3d/remote_transform_3d.cpp223
-rw-r--r--scene/3d/remote_transform_3d.h78
-rw-r--r--scene/3d/skeleton.cpp948
-rw-r--r--scene/3d/skeleton.h234
-rw-r--r--scene/3d/skeleton_3d.cpp956
-rw-r--r--scene/3d/skeleton_3d.h235
-rw-r--r--scene/3d/skeleton_ik_3d.cpp578
-rw-r--r--scene/3d/skeleton_ik_3d.h220
-rw-r--r--scene/3d/soft_body.cpp826
-rw-r--r--scene/3d/soft_body.h202
-rw-r--r--scene/3d/soft_body_3d.cpp827
-rw-r--r--scene/3d/soft_body_3d.h202
-rw-r--r--scene/3d/spatial.cpp848
-rw-r--r--scene/3d/spatial.h207
-rw-r--r--scene/3d/spatial_velocity_tracker.cpp136
-rw-r--r--scene/3d/spatial_velocity_tracker.h61
-rw-r--r--scene/3d/spring_arm.cpp173
-rw-r--r--scene/3d/spring_arm.h71
-rw-r--r--scene/3d/spring_arm_3d.cpp173
-rw-r--r--scene/3d/spring_arm_3d.h71
-rw-r--r--scene/3d/sprite_3d.cpp52
-rw-r--r--scene/3d/sprite_3d.h8
-rw-r--r--scene/3d/vehicle_body.cpp998
-rw-r--r--scene/3d/vehicle_body.h212
-rw-r--r--scene/3d/vehicle_body_3d.cpp998
-rw-r--r--scene/3d/vehicle_body_3d.h212
-rw-r--r--scene/3d/velocity_tracker_3d.cpp136
-rw-r--r--scene/3d/velocity_tracker_3d.h61
-rw-r--r--scene/3d/visibility_notifier.cpp276
-rw-r--r--scene/3d/visibility_notifier.h101
-rw-r--r--scene/3d/visibility_notifier_3d.cpp274
-rw-r--r--scene/3d/visibility_notifier_3d.h101
-rw-r--r--scene/3d/visual_instance.cpp335
-rw-r--r--scene/3d/visual_instance.h150
-rw-r--r--scene/3d/visual_instance_3d.cpp335
-rw-r--r--scene/3d/visual_instance_3d.h150
-rw-r--r--scene/3d/voxelizer.cpp2
-rw-r--r--scene/3d/voxelizer.h4
-rw-r--r--scene/3d/world_environment.cpp6
-rw-r--r--scene/3d/world_environment.h2
-rw-r--r--scene/3d/xr_nodes.cpp621
-rw-r--r--scene/3d/xr_nodes.h176
-rw-r--r--scene/SCsub26
-rw-r--r--scene/animation/SCsub2
-rw-r--r--scene/animation/animation_blend_tree.cpp2
-rw-r--r--scene/animation/animation_cache.cpp10
-rw-r--r--scene/animation/animation_cache.h14
-rw-r--r--scene/animation/animation_node_state_machine.cpp31
-rw-r--r--scene/animation/animation_node_state_machine.h1
-rw-r--r--scene/animation/animation_player.cpp37
-rw-r--r--scene/animation/animation_player.h26
-rw-r--r--scene/animation/animation_tree.cpp42
-rw-r--r--scene/animation/animation_tree.h20
-rw-r--r--scene/animation/root_motion_view.cpp28
-rw-r--r--scene/animation/root_motion_view.h6
-rw-r--r--scene/animation/skeleton_ik.cpp575
-rw-r--r--scene/animation/skeleton_ik.h220
-rw-r--r--scene/animation/tween.cpp56
-rw-r--r--scene/audio/SCsub2
-rw-r--r--scene/audio/audio_stream_player.cpp2
-rw-r--r--scene/debugger/SCsub2
-rw-r--r--scene/debugger/scene_debugger.cpp62
-rw-r--r--scene/debugger/scene_debugger.h4
-rw-r--r--scene/gui/SCsub2
-rw-r--r--scene/gui/base_button.cpp7
-rw-r--r--scene/gui/box_container.cpp6
-rw-r--r--scene/gui/button.cpp88
-rw-r--r--scene/gui/check_box.cpp22
-rw-r--r--scene/gui/check_button.cpp18
-rw-r--r--scene/gui/color_picker.cpp107
-rw-r--r--scene/gui/control.cpp959
-rw-r--r--scene/gui/control.h108
-rw-r--r--scene/gui/dialogs.cpp440
-rw-r--r--scene/gui/dialogs.h83
-rw-r--r--scene/gui/file_dialog.cpp201
-rw-r--r--scene/gui/file_dialog.h43
-rw-r--r--scene/gui/gradient_edit.cpp6
-rw-r--r--scene/gui/graph_edit.cpp87
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/graph_node.cpp58
-rw-r--r--scene/gui/grid_container.cpp8
-rw-r--r--scene/gui/item_list.cpp34
-rw-r--r--scene/gui/label.cpp46
-rw-r--r--scene/gui/line_edit.cpp192
-rw-r--r--scene/gui/link_button.cpp20
-rw-r--r--scene/gui/margin_container.cpp16
-rw-r--r--scene/gui/menu_button.cpp34
-rw-r--r--scene/gui/nine_patch_rect.cpp4
-rw-r--r--scene/gui/option_button.cpp43
-rw-r--r--scene/gui/panel.cpp21
-rw-r--r--scene/gui/panel.h17
-rw-r--r--scene/gui/panel_container.cpp20
-rw-r--r--scene/gui/popup.cpp280
-rw-r--r--scene/gui/popup.h39
-rw-r--r--scene/gui/popup_menu.cpp570
-rw-r--r--scene/gui/popup_menu.h13
-rw-r--r--scene/gui/progress_bar.cpp14
-rw-r--r--scene/gui/range.cpp2
-rw-r--r--scene/gui/rich_text_label.cpp181
-rw-r--r--scene/gui/rich_text_label.h18
-rw-r--r--scene/gui/scroll_bar.cpp62
-rw-r--r--scene/gui/scroll_container.cpp14
-rw-r--r--scene/gui/separator.cpp6
-rw-r--r--scene/gui/shortcut.h2
-rw-r--r--scene/gui/slider.cpp17
-rw-r--r--scene/gui/spin_box.cpp15
-rw-r--r--scene/gui/split_container.cpp28
-rw-r--r--scene/gui/subviewport_container.cpp215
-rw-r--r--scene/gui/subviewport_container.h61
-rw-r--r--scene/gui/tab_container.cpp106
-rw-r--r--scene/gui/tabs.cpp134
-rw-r--r--scene/gui/text_edit.cpp307
-rw-r--r--scene/gui/text_edit.h5
-rw-r--r--scene/gui/texture_progress.cpp2
-rw-r--r--scene/gui/texture_rect.cpp11
-rw-r--r--scene/gui/tree.cpp333
-rw-r--r--scene/gui/tree.h12
-rw-r--r--scene/gui/viewport_container.cpp215
-rw-r--r--scene/gui/viewport_container.h61
-rw-r--r--scene/main/SCsub2
-rw-r--r--scene/main/canvas_item.cpp1489
-rw-r--r--scene/main/canvas_item.h426
-rw-r--r--scene/main/canvas_layer.cpp36
-rw-r--r--scene/main/http_request.cpp8
-rw-r--r--scene/main/instance_placeholder.cpp10
-rw-r--r--scene/main/node.cpp141
-rw-r--r--scene/main/node.h23
-rw-r--r--scene/main/scene_tree.cpp443
-rw-r--r--scene/main/scene_tree.h64
-rw-r--r--[-rwxr-xr-x]scene/main/timer.cpp0
-rw-r--r--[-rwxr-xr-x]scene/main/timer.h0
-rw-r--r--scene/main/viewport.cpp2082
-rw-r--r--scene/main/viewport.h294
-rw-r--r--scene/main/window.cpp1406
-rw-r--r--scene/main/window.h265
-rw-r--r--scene/register_scene_types.cpp391
-rw-r--r--scene/resources/SCsub2
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/animation.h17
-rw-r--r--scene/resources/audio_stream_sample.cpp14
-rw-r--r--scene/resources/bit_map.cpp6
-rw-r--r--scene/resources/bit_map.h2
-rw-r--r--scene/resources/box_shape.cpp86
-rw-r--r--scene/resources/box_shape.h56
-rw-r--r--scene/resources/box_shape_3d.cpp86
-rw-r--r--scene/resources/box_shape_3d.h56
-rw-r--r--scene/resources/canvas.cpp46
-rw-r--r--scene/resources/canvas.h48
-rw-r--r--scene/resources/capsule_shape.cpp128
-rw-r--r--scene/resources/capsule_shape.h59
-rw-r--r--scene/resources/capsule_shape_2d.cpp10
-rw-r--r--scene/resources/capsule_shape_3d.cpp128
-rw-r--r--scene/resources/capsule_shape_3d.h59
-rw-r--r--scene/resources/circle_shape_2d.cpp10
-rw-r--r--scene/resources/concave_polygon_shape.cpp103
-rw-r--r--scene/resources/concave_polygon_shape.h75
-rw-r--r--scene/resources/concave_polygon_shape_2d.cpp12
-rw-r--r--scene/resources/concave_polygon_shape_3d.cpp103
-rw-r--r--scene/resources/concave_polygon_shape_3d.h75
-rw-r--r--scene/resources/convex_polygon_shape.cpp96
-rw-r--r--scene/resources/convex_polygon_shape.h56
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp10
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp96
-rw-r--r--scene/resources/convex_polygon_shape_3d.h56
-rw-r--r--scene/resources/curve.cpp4
-rw-r--r--scene/resources/cylinder_shape.cpp121
-rw-r--r--scene/resources/cylinder_shape.h58
-rw-r--r--scene/resources/cylinder_shape_3d.cpp121
-rw-r--r--scene/resources/cylinder_shape_3d.h58
-rw-r--r--scene/resources/default_theme/SCsub2
-rw-r--r--scene/resources/default_theme/default_theme.cpp35
-rwxr-xr-xscene/resources/default_theme/make_header.py18
-rw-r--r--scene/resources/dynamic_font.cpp33
-rw-r--r--scene/resources/dynamic_font.h16
-rw-r--r--scene/resources/environment.cpp199
-rw-r--r--scene/resources/environment.h10
-rw-r--r--scene/resources/font.cpp8
-rw-r--r--scene/resources/font.h4
-rw-r--r--scene/resources/height_map_shape.cpp209
-rw-r--r--scene/resources/height_map_shape.h63
-rw-r--r--scene/resources/height_map_shape_3d.cpp209
-rw-r--r--scene/resources/height_map_shape_3d.h63
-rw-r--r--scene/resources/line_shape_2d.cpp12
-rw-r--r--scene/resources/material.cpp296
-rw-r--r--scene/resources/material.h60
-rw-r--r--scene/resources/mesh.cpp108
-rw-r--r--scene/resources/mesh.h54
-rw-r--r--scene/resources/mesh_data_tool.cpp28
-rw-r--r--scene/resources/mesh_library.h6
-rw-r--r--scene/resources/multimesh.cpp36
-rw-r--r--scene/resources/multimesh.h6
-rw-r--r--scene/resources/packed_scene.cpp78
-rw-r--r--scene/resources/particles_material.cpp122
-rw-r--r--scene/resources/physics_material.h2
-rw-r--r--scene/resources/polygon_path_finder.cpp10
-rw-r--r--scene/resources/primitive_meshes.cpp104
-rw-r--r--scene/resources/ray_shape.cpp105
-rw-r--r--scene/resources/ray_shape.h57
-rw-r--r--scene/resources/ray_shape_3d.cpp105
-rw-r--r--scene/resources/ray_shape_3d.h57
-rw-r--r--scene/resources/rectangle_shape_2d.cpp10
-rw-r--r--scene/resources/resource_format_text.cpp10
-rw-r--r--scene/resources/resource_format_text.h2
-rw-r--r--scene/resources/segment_shape_2d.cpp18
-rw-r--r--scene/resources/shader.cpp23
-rw-r--r--scene/resources/shader.h9
-rw-r--r--scene/resources/shape.cpp127
-rw-r--r--scene/resources/shape.h73
-rw-r--r--scene/resources/shape_2d.cpp14
-rw-r--r--scene/resources/shape_3d.cpp127
-rw-r--r--scene/resources/shape_3d.h73
-rw-r--r--scene/resources/sky.cpp517
-rw-r--r--scene/resources/sky.h130
-rw-r--r--scene/resources/sky_material.cpp628
-rw-r--r--scene/resources/sky_material.h190
-rw-r--r--scene/resources/space_2d.cpp66
-rw-r--r--scene/resources/space_2d.h56
-rw-r--r--scene/resources/sphere_shape.cpp93
-rw-r--r--scene/resources/sphere_shape.h56
-rw-r--r--scene/resources/sphere_shape_3d.cpp93
-rw-r--r--scene/resources/sphere_shape_3d.h56
-rw-r--r--scene/resources/style_box.cpp9
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/surface_tool.cpp114
-rw-r--r--scene/resources/texture.cpp224
-rw-r--r--scene/resources/texture.h58
-rw-r--r--scene/resources/theme.cpp70
-rw-r--r--scene/resources/theme.h12
-rw-r--r--scene/resources/tile_set.cpp22
-rw-r--r--scene/resources/tile_set.h14
-rw-r--r--scene/resources/visual_shader.cpp97
-rw-r--r--scene/resources/visual_shader.h2
-rw-r--r--scene/resources/world.cpp382
-rw-r--r--scene/resources/world.h92
-rw-r--r--scene/resources/world_2d.cpp30
-rw-r--r--scene/resources/world_2d.h4
-rw-r--r--scene/resources/world_3d.cpp382
-rw-r--r--scene/resources/world_3d.h91
-rw-r--r--scene/resources/world_margin_shape.cpp95
-rw-r--r--scene/resources/world_margin_shape.h57
-rw-r--r--scene/resources/world_margin_shape_3d.cpp95
-rw-r--r--scene/resources/world_margin_shape_3d.h57
-rw-r--r--scene/scene_string_names.cpp8
-rw-r--r--scene/scene_string_names.h9
-rw-r--r--servers/SCsub14
-rw-r--r--servers/arvr/SCsub5
-rw-r--r--servers/arvr/arvr_interface.cpp145
-rw-r--r--servers/arvr/arvr_interface.h126
-rw-r--r--servers/arvr/arvr_positional_tracker.cpp237
-rw-r--r--servers/arvr/arvr_positional_tracker.h104
-rw-r--r--servers/arvr_server.cpp386
-rw-r--r--servers/arvr_server.h192
-rw-r--r--servers/audio/SCsub2
-rw-r--r--servers/audio/audio_driver_dummy.cpp6
-rw-r--r--servers/audio/audio_filter_sw.cpp2
-rw-r--r--servers/audio/audio_rb_resampler.cpp8
-rw-r--r--servers/audio/audio_rb_resampler.h2
-rw-r--r--servers/audio/effects/SCsub2
-rw-r--r--servers/audio/effects/audio_effect_pitch_shift.cpp3
-rw-r--r--servers/audio/effects/audio_effect_record.cpp8
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.h2
-rw-r--r--servers/audio/effects/audio_stream_generator.cpp2
-rw-r--r--servers/audio/effects/reverb.cpp6
-rw-r--r--servers/audio/reverb_sw.cpp538
-rw-r--r--servers/audio/reverb_sw.h88
-rw-r--r--servers/audio/voice_rb_sw.h141
-rw-r--r--servers/audio_server.cpp59
-rw-r--r--servers/audio_server.h18
-rw-r--r--servers/camera/SCsub4
-rw-r--r--servers/camera/camera_feed.cpp28
-rw-r--r--servers/camera/camera_feed.h4
-rw-r--r--servers/camera_server.cpp12
-rw-r--r--servers/camera_server.h2
-rw-r--r--servers/display_server.cpp593
-rw-r--r--servers/display_server.h389
-rw-r--r--servers/navigation_2d_server.cpp229
-rw-r--r--servers/navigation_2d_server.h163
-rw-r--r--servers/navigation_server.cpp107
-rw-r--r--servers/navigation_server.h199
-rw-r--r--servers/navigation_server_2d.cpp229
-rw-r--r--servers/navigation_server_2d.h163
-rw-r--r--servers/navigation_server_3d.cpp107
-rw-r--r--servers/navigation_server_3d.h199
-rw-r--r--servers/physics/SCsub7
-rw-r--r--servers/physics/area_pair_sw.cpp159
-rw-r--r--servers/physics/area_pair_sw.h70
-rw-r--r--servers/physics/area_sw.cpp264
-rw-r--r--servers/physics/area_sw.h203
-rw-r--r--servers/physics/body_pair_sw.cpp495
-rw-r--r--servers/physics/body_pair_sw.h97
-rw-r--r--servers/physics/body_sw.cpp814
-rw-r--r--servers/physics/body_sw.h475
-rw-r--r--servers/physics/broad_phase_basic.cpp225
-rw-r--r--servers/physics/broad_phase_basic.h108
-rw-r--r--servers/physics/broad_phase_octree.cpp129
-rw-r--r--servers/physics/broad_phase_octree.h73
-rw-r--r--servers/physics/broad_phase_sw.cpp36
-rw-r--r--servers/physics/broad_phase_sw.h73
-rw-r--r--servers/physics/collision_object_sw.cpp239
-rw-r--r--servers/physics/collision_object_sw.h164
-rw-r--r--servers/physics/collision_solver_sat.cpp1591
-rw-r--r--servers/physics/collision_solver_sat.h38
-rw-r--r--servers/physics/collision_solver_sw.cpp372
-rw-r--r--servers/physics/collision_solver_sw.h53
-rw-r--r--servers/physics/constraint_sw.h85
-rw-r--r--servers/physics/gjk_epa.cpp946
-rw-r--r--servers/physics/gjk_epa.h40
-rw-r--r--servers/physics/joints/SCsub5
-rw-r--r--servers/physics/joints/cone_twist_joint_sw.cpp366
-rw-r--r--servers/physics/joints/cone_twist_joint_sw.h142
-rw-r--r--servers/physics/joints/generic_6dof_joint_sw.cpp686
-rw-r--r--servers/physics/joints/generic_6dof_joint_sw.h401
-rw-r--r--servers/physics/joints/hinge_joint_sw.cpp450
-rw-r--r--servers/physics/joints/hinge_joint_sw.h117
-rw-r--r--servers/physics/joints/jacobian_entry_sw.h169
-rw-r--r--servers/physics/joints/pin_joint_sw.cpp167
-rw-r--r--servers/physics/joints/pin_joint_sw.h96
-rw-r--r--servers/physics/joints/slider_joint_sw.cpp443
-rw-r--r--servers/physics/joints/slider_joint_sw.h249
-rw-r--r--servers/physics/joints_sw.h46
-rw-r--r--servers/physics/physics_server_sw.cpp1589
-rw-r--r--servers/physics/physics_server_sw.h382
-rw-r--r--servers/physics/shape_sw.cpp1655
-rw-r--r--servers/physics/shape_sw.h470
-rw-r--r--servers/physics/space_sw.cpp1242
-rw-r--r--servers/physics/space_sw.h208
-rw-r--r--servers/physics/step_sw.cpp299
-rw-r--r--servers/physics/step_sw.h50
-rw-r--r--servers/physics_2d/SCsub2
-rw-r--r--servers/physics_2d/area_2d_sw.cpp48
-rw-r--r--servers/physics_2d/area_2d_sw.h14
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp12
-rw-r--r--servers/physics_2d/body_2d_sw.cpp166
-rw-r--r--servers/physics_2d/body_2d_sw.h44
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp12
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.cpp12
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.h4
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp4
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.h6
-rw-r--r--servers/physics_2d/broad_phase_2d_sw.cpp2
-rw-r--r--servers/physics_2d/broad_phase_2d_sw.h4
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp16
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp174
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.h2
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.cpp16
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.h6
-rw-r--r--servers/physics_2d/constraint_2d_sw.h2
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp24
-rw-r--r--servers/physics_2d/joints_2d_sw.h20
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp1464
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h296
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.cpp173
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h348
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp1465
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h296
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.cpp173
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h348
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp4
-rw-r--r--servers/physics_2d/shape_2d_sw.h26
-rw-r--r--servers/physics_2d/space_2d_sw.cpp156
-rw-r--r--servers/physics_2d/space_2d_sw.h20
-rw-r--r--servers/physics_2d/step_2d_sw.cpp20
-rw-r--r--servers/physics_2d_server.cpp840
-rw-r--r--servers/physics_2d_server.h699
-rw-r--r--servers/physics_3d/SCsub7
-rw-r--r--servers/physics_3d/area_3d_sw.cpp264
-rw-r--r--servers/physics_3d/area_3d_sw.h203
-rw-r--r--servers/physics_3d/area_pair_3d_sw.cpp159
-rw-r--r--servers/physics_3d/area_pair_3d_sw.h70
-rw-r--r--servers/physics_3d/body_3d_sw.cpp814
-rw-r--r--servers/physics_3d/body_3d_sw.h475
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp495
-rw-r--r--servers/physics_3d/body_pair_3d_sw.h97
-rw-r--r--servers/physics_3d/broad_phase_3d_basic.cpp225
-rw-r--r--servers/physics_3d/broad_phase_3d_basic.h108
-rw-r--r--servers/physics_3d/broad_phase_3d_sw.cpp36
-rw-r--r--servers/physics_3d/broad_phase_3d_sw.h73
-rw-r--r--servers/physics_3d/broad_phase_octree.cpp129
-rw-r--r--servers/physics_3d/broad_phase_octree.h73
-rw-r--r--servers/physics_3d/collision_object_3d_sw.cpp239
-rw-r--r--servers/physics_3d/collision_object_3d_sw.h164
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp1591
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.h38
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp372
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.h53
-rw-r--r--servers/physics_3d/constraint_3d_sw.h85
-rw-r--r--servers/physics_3d/gjk_epa.cpp946
-rw-r--r--servers/physics_3d/gjk_epa.h40
-rw-r--r--servers/physics_3d/joints/SCsub5
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp366
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.h142
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp686
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.h401
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.cpp450
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.h117
-rw-r--r--servers/physics_3d/joints/jacobian_entry_3d_sw.h169
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.cpp167
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.h96
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.cpp443
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.h249
-rw-r--r--servers/physics_3d/joints_3d_sw.h46
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp1589
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h382
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp1655
-rw-r--r--servers/physics_3d/shape_3d_sw.h470
-rw-r--r--servers/physics_3d/space_3d_sw.cpp1242
-rw-r--r--servers/physics_3d/space_3d_sw.h208
-rw-r--r--servers/physics_3d/step_3d_sw.cpp299
-rw-r--r--servers/physics_3d/step_3d_sw.h50
-rw-r--r--servers/physics_server.cpp800
-rw-r--r--servers/physics_server.h844
-rw-r--r--servers/physics_server_2d.cpp840
-rw-r--r--servers/physics_server_2d.h699
-rw-r--r--servers/physics_server_3d.cpp800
-rw-r--r--servers/physics_server_3d.h844
-rw-r--r--servers/register_server_types.cpp107
-rw-r--r--servers/rendering/SCsub7
-rw-r--r--servers/rendering/rasterizer.cpp77
-rw-r--r--servers/rendering/rasterizer.h1337
-rw-r--r--servers/rendering/rasterizer_rd/SCsub7
-rw-r--r--servers/rendering/rasterizer_rd/light_cluster_builder.cpp256
-rw-r--r--servers/rendering/rasterizer_rd/light_cluster_builder.h293
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp2558
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h501
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp1595
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.h634
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_rd.cpp177
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_rd.h95
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp3209
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h654
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp4308
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h1250
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp5193
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h1306
-rw-r--r--servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp97
-rw-r--r--servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h96
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.cpp1243
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.h123
-rw-r--r--servers/rendering/rasterizer_rd/shader_rd.cpp495
-rw-r--r--servers/rendering/rasterizer_rd/shader_rd.h (renamed from servers/visual/rasterizer_rd/shader_rd.h)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/SCsub30
-rw-r--r--servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl (renamed from servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas.glsl (renamed from servers/visual/rasterizer_rd/shaders/canvas.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl (renamed from servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl (renamed from servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/copy.glsl220
-rw-r--r--servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl104
-rw-r--r--servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl72
-rw-r--r--servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl188
-rw-r--r--servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl328
-rw-r--r--servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl147
-rw-r--r--servers/rendering/rasterizer_rd/shaders/giprobe.glsl (renamed from servers/visual/rasterizer_rd/shaders/giprobe.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl (renamed from servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl (renamed from servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl (renamed from servers/visual/rasterizer_rd/shaders/giprobe_write.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl (renamed from servers/visual/rasterizer_rd/shaders/luminance_reduce.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl (renamed from servers/visual/rasterizer_rd/shaders/roughness_limiter.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl2474
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl325
-rw-r--r--servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl262
-rw-r--r--servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl164
-rw-r--r--servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl96
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sky.glsl187
-rw-r--r--servers/rendering/rasterizer_rd/shaders/specular_merge.glsl59
-rw-r--r--servers/rendering/rasterizer_rd/shaders/ssao.glsl (renamed from servers/visual/rasterizer_rd/shaders/ssao.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl (renamed from servers/visual/rasterizer_rd/shaders/ssao_blur.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl (renamed from servers/visual/rasterizer_rd/shaders/ssao_minify.glsl)0
-rw-r--r--servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl198
-rw-r--r--servers/rendering/rasterizer_rd/shaders/tonemap.glsl359
-rw-r--r--servers/rendering/rendering_device.cpp64
-rw-r--r--servers/rendering/rendering_device.h1034
-rw-r--r--servers/rendering/rendering_server_canvas.cpp1479
-rw-r--r--servers/rendering/rendering_server_canvas.h270
-rw-r--r--servers/rendering/rendering_server_globals.cpp40
-rw-r--r--servers/rendering/rendering_server_globals.h54
-rw-r--r--servers/rendering/rendering_server_raster.cpp282
-rw-r--r--servers/rendering/rendering_server_raster.h788
-rw-r--r--servers/rendering/rendering_server_scene.cpp3021
-rw-r--r--servers/rendering/rendering_server_scene.h462
-rw-r--r--servers/rendering/rendering_server_viewport.cpp855
-rw-r--r--servers/rendering/rendering_server_viewport.h232
-rw-r--r--servers/rendering/rendering_server_wrap_mt.cpp197
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h709
-rw-r--r--servers/rendering/shader_language.cpp7011
-rw-r--r--servers/rendering/shader_language.h901
-rw-r--r--servers/rendering/shader_types.cpp334
-rw-r--r--servers/rendering/shader_types.h62
-rw-r--r--servers/rendering_server.cpp2378
-rw-r--r--servers/rendering_server.h1226
-rw-r--r--servers/visual/SCsub7
-rw-r--r--servers/visual/rasterizer.cpp77
-rw-r--r--servers/visual/rasterizer.h1307
-rw-r--r--servers/visual/rasterizer_rd/SCsub7
-rw-r--r--servers/visual/rasterizer_rd/cubemap_coeffs.h28
-rw-r--r--servers/visual/rasterizer_rd/light_cluster_builder.cpp255
-rw-r--r--servers/visual/rasterizer_rd/light_cluster_builder.h291
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp2558
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_canvas_rd.h501
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp1105
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_effects_rd.h478
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_rd.cpp177
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_rd.h95
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.cpp2722
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.h587
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp3229
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.h964
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp4820
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.h1134
-rw-r--r--servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp97
-rw-r--r--servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h96
-rw-r--r--servers/visual/rasterizer_rd/shader_compiler_rd.cpp1243
-rw-r--r--servers/visual/rasterizer_rd/shader_compiler_rd.h123
-rw-r--r--servers/visual/rasterizer_rd/shader_rd.cpp494
-rw-r--r--servers/visual/rasterizer_rd/shaders/SCsub24
-rw-r--r--servers/visual/rasterizer_rd/shaders/blur.glsl294
-rw-r--r--servers/visual/rasterizer_rd/shaders/blur_inc.glsl35
-rw-r--r--servers/visual/rasterizer_rd/shaders/copy.glsl86
-rw-r--r--servers/visual/rasterizer_rd/shaders/cubemap_downsampler.glsl220
-rw-r--r--servers/visual/rasterizer_rd/shaders/cubemap_filter.glsl289
-rw-r--r--servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl184
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_high_end.glsl1718
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_high_end_inc.glsl266
-rw-r--r--servers/visual/rasterizer_rd/shaders/sky.glsl79
-rw-r--r--servers/visual/rasterizer_rd/shaders/tonemap.glsl305
-rw-r--r--servers/visual/rendering_device.cpp64
-rw-r--r--servers/visual/rendering_device.h1031
-rw-r--r--servers/visual/shader_language.cpp6904
-rw-r--r--servers/visual/shader_language.h900
-rw-r--r--servers/visual/shader_types.cpp293
-rw-r--r--servers/visual/shader_types.h62
-rw-r--r--servers/visual/visual_server_canvas.cpp1479
-rw-r--r--servers/visual/visual_server_canvas.h270
-rw-r--r--servers/visual/visual_server_globals.cpp40
-rw-r--r--servers/visual/visual_server_globals.h54
-rw-r--r--servers/visual/visual_server_light_baker.cpp34
-rw-r--r--servers/visual/visual_server_light_baker.h52
-rw-r--r--servers/visual/visual_server_raster.cpp271
-rw-r--r--servers/visual/visual_server_raster.h762
-rw-r--r--servers/visual/visual_server_scene.cpp2839
-rw-r--r--servers/visual/visual_server_scene.h440
-rw-r--r--servers/visual/visual_server_viewport.cpp747
-rw-r--r--servers/visual/visual_server_viewport.h205
-rw-r--r--servers/visual/visual_server_wrap_mt.cpp196
-rw-r--r--servers/visual/visual_server_wrap_mt.h679
-rw-r--r--servers/visual_server.cpp2360
-rw-r--r--servers/visual_server.h1155
-rw-r--r--servers/xr/SCsub5
-rw-r--r--servers/xr/xr_interface.cpp145
-rw-r--r--servers/xr/xr_interface.h126
-rw-r--r--servers/xr/xr_positional_tracker.cpp237
-rw-r--r--servers/xr/xr_positional_tracker.h104
-rw-r--r--servers/xr_server.cpp386
-rw-r--r--servers/xr_server.h192
-rw-r--r--thirdparty/README.md6
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp24
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp24
-rw-r--r--thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch224
-rw-r--r--thirdparty/misc/cubemap_coeffs.h28
-rw-r--r--thirdparty/vulkan/android/vk_mem_alloc.cpp8
-rw-r--r--thirdparty/vulkan/vk_enum_string_helper.h2
2425 files changed, 319586 insertions, 189029 deletions
diff --git a/.clang-format b/.clang-format
index 237fd9ce30..eba6d586f0 100644
--- a/.clang-format
+++ b/.clang-format
@@ -112,11 +112,11 @@ UseTab: Always
---
### C++ specific config ###
Language: Cpp
-Standard: Cpp03
+Standard: Cpp11
---
### ObjC specific config ###
Language: ObjC
-Standard: Cpp03
+Standard: Cpp11
ObjCBlockIndentWidth: 4
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
diff --git a/.gitignore b/.gitignore
index cc5c822e69..19490b9878 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,8 +18,10 @@ local.properties
.idea
.gradletasknamecache
project.properties
+platform/android/java/lib/.cxx/
platform/android/java/libs/*
platform/android/java/app/libs/*
+platform/android/java/lib/.cxx/*
# General c++ generated files
*.lib
diff --git a/.travis.yml b/.travis.yml
index 25b7795e13..8cfd7a1a7f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,7 +31,7 @@ matrix:
- name: Linux editor (debug, GCC 9, with Mono)
stage: build
- env: PLATFORM=x11 TOOLS=yes TARGET=debug CACHE_NAME=${PLATFORM}-tools-mono-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="module_mono_enabled=yes mono_glue=no warnings=extra werror=yes"
+ env: PLATFORM=linuxbsd TOOLS=yes TARGET=debug CACHE_NAME=${PLATFORM}-tools-mono-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="module_mono_enabled=yes mono_glue=no warnings=extra werror=yes"
os: linux
compiler: gcc-9
addons:
@@ -47,7 +47,7 @@ matrix:
- name: Linux export template (release, Clang 7)
stage: build
- env: PLATFORM=x11 TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
+ env: PLATFORM=linuxbsd TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
os: linux
compiler: clang
addons:
@@ -55,17 +55,15 @@ matrix:
packages:
- *linux_deps
-# TODO: Android support
-
-# - name: Android export template (release_debug, Clang)
-# stage: build
-# env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
-# os: linux
-# compiler: clang
-# addons:
-# apt:
-# packages:
-# - openjdk-8-jdk
+ - name: Android export template (release_debug, Clang)
+ stage: build
+ env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes"
+ os: linux
+ compiler: clang
+ addons:
+ apt:
+ packages:
+ - openjdk-8-jdk
- name: macOS editor (debug, Clang)
stage: build
@@ -92,24 +90,9 @@ matrix:
# packages:
# - scons
-# TODO: Dummy/Offscreen rasterizer
-
-# - name: Linux headless editor (release_debug, GCC 9, testing project exporting and script running)
-# stage: build
-# env: PLATFORM=server TOOLS=yes TARGET=release_debug CACHE_NAME=${PLATFORM}-tools-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="warnings=extra werror=yes" TEST_PROJECT=yes
-# os: linux
-# compiler: gcc-9
-# addons:
-# apt:
-# sources:
-# - sourceline: "ppa:ubuntu-toolchain-r/test"
-# packages:
-# - *gcc9_deps
-# - *linux_deps
-
- name: Linux export template (release_debug, GCC 7, without 3D support)
stage: build
- env: PLATFORM=x11 TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-7 EXTRA_ARGS="disable_3d=yes"
+ env: PLATFORM=linuxbsd TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-7 EXTRA_ARGS="disable_3d=yes"
os: linux
compiler: gcc
addons:
@@ -117,21 +100,18 @@ matrix:
packages:
- *linux_deps
- - name: Javascript export template (release, emscripten latest)
- stage: build
- env: PLATFORM=javascript TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-emcc-latest EXTRA_ARGS="use_closure_compiler=yes"
- os: linux
- compiler: clang
- addons:
- apt:
- packages:
- - *linux_deps
+# - name: Javascript export template (release, emscripten latest)
+# stage: build
+# env: PLATFORM=javascript TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-emcc-latest EXTRA_ARGS="use_closure_compiler=yes"
+# os: linux
+# compiler: clang
+# addons:
+# apt:
+# packages:
+# - *linux_deps
before_install:
- eval "${MATRIX_EVAL}"
- - if [ "$STATIC_CHECKS" = "yes" ]; then
- unset SCONS_CACHE;
- fi
install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
@@ -150,6 +130,10 @@ install:
./emsdk/emsdk install latest;
./emsdk/emsdk activate latest;
fi
+ - if [ "$STATIC_CHECKS" = "yes" ]; then
+ unset SCONS_CACHE;
+ pip3 install --user black pygments;
+ fi
before_script:
- if [ "$PLATFORM" = "android" ]; then
@@ -160,12 +144,13 @@ before_script:
script:
- if [ "$STATIC_CHECKS" = "yes" ]; then
sh ./misc/travis/clang-format.sh &&
+ sh ./misc/travis/black-format.sh &&
doc/tools/makerst.py --dry-run doc/classes modules;
else
scons -j2 CC=$CC CXX=$CXX platform=$PLATFORM tools=$TOOLS target=$TARGET $OPTIONS $EXTRA_ARGS &&
if [ "$TEST_PROJECT" = "yes" ]; then
git clone --depth 1 "https://github.com/godotengine/godot-tests.git";
- sed -i "s:custom_template/release=\"\":custom_template/release=\"$(readlink -e bin/godot_server.x11.opt.tools.64)\":" godot-tests/tests/project_export/export_presets.cfg;
- godot-tests/tests/project_export/test_project.sh "bin/godot_server.x11.opt.tools.64";
+ sed -i "s:custom_template/release=\"\":custom_template/release=\"$(readlink -e bin/godot_server.linuxbsd.opt.tools.64)\":" godot-tests/tests/project_export/export_presets.cfg;
+ godot-tests/tests/project_export/test_project.sh "bin/godot_server.linuxbsd.opt.tools.64";
fi
fi
diff --git a/README.md b/README.md
index 1202dabc8c..f9855beaf6 100644
--- a/README.md
+++ b/README.md
@@ -71,3 +71,4 @@ for more info.
[![Code Triagers Badge](https://www.codetriage.com/godotengine/godot/badges/users.svg)](https://www.codetriage.com/godotengine/godot)
[![Translate on Weblate](https://hosted.weblate.org/widgets/godot-engine/-/godot/svg-badge.svg)](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget)
[![Total alerts on LGTM](https://img.shields.io/lgtm/alerts/g/godotengine/godot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/godotengine/godot/alerts)
+[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/godotengine/godot)](https://www.tickgit.com/browse?repo=github.com/godotengine/godot)
diff --git a/SConstruct b/SConstruct
index 4ebc33f593..8fc333a8fa 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,6 +1,7 @@
#!/usr/bin/env python
-EnsureSConsVersion(0, 98, 1)
+EnsureSConsVersion(3, 0, 0)
+EnsurePythonVersion(3, 5)
# System
import glob
@@ -13,7 +14,7 @@ import methods
import gles_builders
from platform_methods import run_in_subprocess
-# scan possible build platforms
+# Scan possible build platforms
platform_list = [] # list of platforms
platform_opts = {} # options for each platform
@@ -25,48 +26,48 @@ platform_exporters = []
platform_apis = []
for x in sorted(glob.glob("platform/*")):
- if (not os.path.isdir(x) or not os.path.exists(x + "/detect.py")):
+ if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
continue
tmppath = "./" + x
sys.path.insert(0, tmppath)
import detect
- if (os.path.exists(x + "/export/export.cpp")):
+ if os.path.exists(x + "/export/export.cpp"):
platform_exporters.append(x[9:])
- if (os.path.exists(x + "/api/api.cpp")):
+ if os.path.exists(x + "/api/api.cpp"):
platform_apis.append(x[9:])
- if (detect.is_active()):
+ if detect.is_active():
active_platforms.append(detect.get_name())
active_platform_ids.append(x)
- if (detect.can_build()):
+ if detect.can_build():
x = x.replace("platform/", "") # rest of world
x = x.replace("platform\\", "") # win32
platform_list += [x]
platform_opts[x] = detect.get_opts()
platform_flags[x] = detect.get_flags()
sys.path.remove(tmppath)
- sys.modules.pop('detect')
+ sys.modules.pop("detect")
module_list = methods.detect_modules()
methods.save_active_platforms(active_platforms, active_platform_ids)
-custom_tools = ['default']
+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)):
- custom_tools = ['mingw']
-elif platform_arg == 'javascript':
+ custom_tools = ["mingw"]
+elif platform_arg == "javascript":
# Use generic POSIX build toolchain for Emscripten.
- custom_tools = ['cc', 'c++', 'ar', 'link', 'textfile', 'zip']
+ custom_tools = ["cc", "c++", "ar", "link", "textfile", "zip"]
env_base = Environment(tools=custom_tools)
-if 'TERM' in os.environ:
- 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'))
+if "TERM" in os.environ:
+ 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.use_ptrcall = False
env_base.module_version_string = ""
@@ -93,7 +94,7 @@ env_base.SConsignFile(".sconsign{0}.dblite".format(pickle.HIGHEST_PROTOCOL))
# Build options
-customs = ['custom.py']
+customs = ["custom.py"]
profile = ARGUMENTS.get("profile", False)
if profile:
@@ -105,62 +106,62 @@ if profile:
opts = Variables(customs, ARGUMENTS)
# Target build options
-opts.Add('arch', "Platform-dependent architecture (arm/arm64/x86/x64/mips/...)", '')
-opts.Add(EnumVariable('bits', "Target platform bits", 'default', ('default', '32', '64')))
-opts.Add('p', "Platform (alias for 'platform')", '')
-opts.Add('platform', "Target platform (%s)" % ('|'.join(platform_list), ), '')
-opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'release_debug', 'release')))
-opts.Add(EnumVariable('optimize', "Optimization type", 'speed', ('speed', 'size')))
+opts.Add("arch", "Platform-dependent architecture (arm/arm64/x86/x64/mips/...)", "")
+opts.Add(EnumVariable("bits", "Target platform bits", "default", ("default", "32", "64")))
+opts.Add("p", "Platform (alias for 'platform')", "")
+opts.Add("platform", "Target platform (%s)" % ("|".join(platform_list),), "")
+opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release")))
+opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size")))
-opts.Add(BoolVariable('tools', "Build the tools (a.k.a. the Godot editor)", True))
-opts.Add(BoolVariable('use_lto', 'Use link-time optimization', False))
-opts.Add(BoolVariable('use_precise_math_checks', 'Math checks use very precise epsilon (useful to debug the engine)', False))
+opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True))
+opts.Add(BoolVariable("use_lto", "Use link-time optimization", False))
+opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
# Components
-opts.Add(BoolVariable('deprecated', "Enable deprecated features", True))
-opts.Add(BoolVariable('minizip', "Enable ZIP archive support using minizip", True))
-opts.Add(BoolVariable('xaudio2', "Enable the XAudio2 audio driver", False))
+opts.Add(BoolVariable("deprecated", "Enable deprecated features", True))
+opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True))
+opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
# Advanced options
-opts.Add(BoolVariable('verbose', "Enable verbose output for the compilation", False))
-opts.Add(BoolVariable('progress', "Show a progress indicator during compilation", True))
-opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'all', ('extra', 'all', 'moderate', 'no')))
-opts.Add(BoolVariable('werror', "Treat compiler warnings as errors. Depends on the level of warnings set with 'warnings'", False))
-opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=extra werror=yes", False))
-opts.Add('extra_suffix', "Custom extra suffix added to the base filename of all generated binary files", '')
-opts.Add(BoolVariable('vsproj', "Generate a Visual Studio solution", False))
-opts.Add(EnumVariable('macports_clang', "Build using Clang from MacPorts", 'no', ('no', '5.0', 'devel')))
-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('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("verbose", "Enable verbose output for the compilation", False))
+opts.Add(BoolVariable("progress", "Show a progress indicator during compilation", True))
+opts.Add(EnumVariable("warnings", "Level of compilation warnings", "all", ("extra", "all", "moderate", "no")))
+opts.Add(BoolVariable("werror", "Treat compiler warnings as errors", True))
+opts.Add(BoolVariable("dev", "If yes, alias for verbose=yes warnings=extra werror=yes", False))
+opts.Add("extra_suffix", "Custom extra suffix added to the base filename of all generated binary files", "")
+opts.Add(BoolVariable("vsproj", "Generate a Visual Studio solution", False))
+opts.Add(EnumVariable("macports_clang", "Build using Clang from MacPorts", "no", ("no", "5.0", "devel")))
+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("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)", "")
# Thirdparty libraries
-#opts.Add(BoolVariable('builtin_assimp', "Use the built-in Assimp library", True))
-opts.Add(BoolVariable('builtin_bullet', "Use the built-in Bullet library", True))
-opts.Add(BoolVariable('builtin_certs', "Bundle default SSL certificates to be used if you don't specify an override in the project settings", True))
-opts.Add(BoolVariable('builtin_enet', "Use the built-in ENet library", True))
-opts.Add(BoolVariable('builtin_freetype', "Use the built-in FreeType library", True))
-opts.Add(BoolVariable('builtin_glslang', "Use the built-in glslang library", True))
-opts.Add(BoolVariable('builtin_libogg', "Use the built-in libogg library", True))
-opts.Add(BoolVariable('builtin_libpng', "Use the built-in libpng library", True))
-opts.Add(BoolVariable('builtin_libtheora', "Use the built-in libtheora library", True))
-opts.Add(BoolVariable('builtin_libvorbis', "Use the built-in libvorbis library", True))
-opts.Add(BoolVariable('builtin_libvpx', "Use the built-in libvpx library", True))
-opts.Add(BoolVariable('builtin_libwebp', "Use the built-in libwebp library", True))
-opts.Add(BoolVariable('builtin_wslay', "Use the built-in wslay library", True))
-opts.Add(BoolVariable('builtin_mbedtls', "Use the built-in mbedTLS library", True))
-opts.Add(BoolVariable('builtin_miniupnpc', "Use the built-in miniupnpc library", True))
-opts.Add(BoolVariable('builtin_opus', "Use the built-in Opus library", True))
-opts.Add(BoolVariable('builtin_pcre2', "Use the built-in PCRE2 library", True))
-opts.Add(BoolVariable('builtin_pcre2_with_jit', "Use JIT compiler for the built-in PCRE2 library", True))
-opts.Add(BoolVariable('builtin_recast', "Use the built-in Recast library", True))
-opts.Add(BoolVariable('builtin_rvo2', "Use the built-in RVO2 library", True))
-opts.Add(BoolVariable('builtin_squish', "Use the built-in squish library", True))
-opts.Add(BoolVariable('builtin_vulkan', "Use the built-in Vulkan loader library and headers", True))
-opts.Add(BoolVariable('builtin_xatlas', "Use the built-in xatlas library", True))
-opts.Add(BoolVariable('builtin_zlib', "Use the built-in zlib library", True))
-opts.Add(BoolVariable('builtin_zstd', "Use the built-in Zstd library", True))
+# opts.Add(BoolVariable('builtin_assimp', "Use the built-in Assimp library", True))
+opts.Add(BoolVariable("builtin_bullet", "Use the built-in Bullet library", True))
+opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundles", True))
+opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
+opts.Add(BoolVariable("builtin_freetype", "Use the built-in FreeType library", True))
+opts.Add(BoolVariable("builtin_glslang", "Use the built-in glslang library", True))
+opts.Add(BoolVariable("builtin_libogg", "Use the built-in libogg library", True))
+opts.Add(BoolVariable("builtin_libpng", "Use the built-in libpng library", True))
+opts.Add(BoolVariable("builtin_libtheora", "Use the built-in libtheora library", True))
+opts.Add(BoolVariable("builtin_libvorbis", "Use the built-in libvorbis library", True))
+opts.Add(BoolVariable("builtin_libvpx", "Use the built-in libvpx library", True))
+opts.Add(BoolVariable("builtin_libwebp", "Use the built-in libwebp library", True))
+opts.Add(BoolVariable("builtin_wslay", "Use the built-in wslay library", True))
+opts.Add(BoolVariable("builtin_mbedtls", "Use the built-in mbedTLS library", True))
+opts.Add(BoolVariable("builtin_miniupnpc", "Use the built-in miniupnpc library", True))
+opts.Add(BoolVariable("builtin_opus", "Use the built-in Opus library", True))
+opts.Add(BoolVariable("builtin_pcre2", "Use the built-in PCRE2 library", True))
+opts.Add(BoolVariable("builtin_pcre2_with_jit", "Use JIT compiler for the built-in PCRE2 library", True))
+opts.Add(BoolVariable("builtin_recast", "Use the built-in Recast library", True))
+opts.Add(BoolVariable("builtin_rvo2", "Use the built-in RVO2 library", True))
+opts.Add(BoolVariable("builtin_squish", "Use the built-in squish library", True))
+opts.Add(BoolVariable("builtin_vulkan", "Use the built-in Vulkan loader library and headers", True))
+opts.Add(BoolVariable("builtin_xatlas", "Use the built-in xatlas library", True))
+opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib library", True))
+opts.Add(BoolVariable("builtin_zstd", "Use the built-in Zstd library", True))
# Compilation environment setup
opts.Add("CXX", "C++ compiler")
@@ -183,63 +184,64 @@ for x in module_list:
tmppath = "./modules/" + x
sys.path.insert(0, tmppath)
import config
+
enabled_attr = getattr(config, "is_enabled", None)
- if (callable(enabled_attr) and not config.is_enabled()):
+ if callable(enabled_attr) and not config.is_enabled():
module_enabled = False
sys.path.remove(tmppath)
- sys.modules.pop('config')
- opts.Add(BoolVariable('module_' + x + '_enabled', "Enable module '%s'" % (x, ), module_enabled))
+ sys.modules.pop("config")
+ opts.Add(BoolVariable("module_" + x + "_enabled", "Enable module '%s'" % (x,), module_enabled))
opts.Update(env_base) # update environment
Help(opts.GenerateHelpText(env_base)) # generate help
# add default include paths
-env_base.Prepend(CPPPATH=['#'])
+env_base.Prepend(CPPPATH=["#"])
# configure ENV for platform
env_base.platform_exporters = platform_exporters
env_base.platform_apis = platform_apis
-if (env_base["use_precise_math_checks"]):
- env_base.Append(CPPDEFINES=['PRECISE_MATH_CHECKS'])
+if env_base["use_precise_math_checks"]:
+ env_base.Append(CPPDEFINES=["PRECISE_MATH_CHECKS"])
-if (env_base['target'] == 'debug'):
- env_base.Append(CPPDEFINES=['DEBUG_MEMORY_ALLOC','DISABLE_FORCED_INLINE'])
+if env_base["target"] == "debug":
+ env_base.Append(CPPDEFINES=["DEBUG_MEMORY_ALLOC", "DISABLE_FORCED_INLINE"])
# The two options below speed up incremental builds, but reduce the certainty that all files
# will properly be rebuilt. As such, we only enable them for debug (dev) builds, not release.
# To decide whether to rebuild a file, use the MD5 sum only if the timestamp has changed.
# http://scons.org/doc/production/HTML/scons-user/ch06.html#idm139837621851792
- env_base.Decider('MD5-timestamp')
+ env_base.Decider("MD5-timestamp")
# Use cached implicit dependencies by default. Can be overridden by specifying `--implicit-deps-changed` in the command line.
# http://scons.org/doc/production/HTML/scons-user/ch06s04.html
- env_base.SetOption('implicit_cache', 1)
+ env_base.SetOption("implicit_cache", 1)
-if (env_base['no_editor_splash']):
- env_base.Append(CPPDEFINES=['NO_EDITOR_SPLASH'])
+if env_base["no_editor_splash"]:
+ env_base.Append(CPPDEFINES=["NO_EDITOR_SPLASH"])
-if not env_base['deprecated']:
- env_base.Append(CPPDEFINES=['DISABLE_DEPRECATED'])
+if not env_base["deprecated"]:
+ env_base.Append(CPPDEFINES=["DISABLE_DEPRECATED"])
env_base.platforms = {}
selected_platform = ""
-if env_base['platform'] != "":
- selected_platform = env_base['platform']
-elif env_base['p'] != "":
- selected_platform = env_base['p']
+if env_base["platform"] != "":
+ selected_platform = env_base["platform"]
+elif env_base["p"] != "":
+ selected_platform = env_base["p"]
env_base["platform"] = selected_platform
else:
# Missing `platform` argument, try to detect platform automatically
- if sys.platform.startswith('linux'):
- selected_platform = 'x11'
- elif sys.platform == 'darwin':
- selected_platform = 'osx'
- elif sys.platform == 'win32':
- selected_platform = 'windows'
+ if sys.platform.startswith("linux"):
+ selected_platform = "linuxbsd"
+ elif sys.platform == "darwin":
+ selected_platform = "osx"
+ elif sys.platform == "win32":
+ selected_platform = "windows"
else:
print("Could not detect platform automatically. Supported platforms:")
for x in platform_list:
@@ -250,21 +252,30 @@ else:
print("Automatically detected platform: " + selected_platform)
env_base["platform"] = selected_platform
+if selected_platform in ["linux", "bsd", "x11"]:
+ if selected_platform == "x11":
+ # Deprecated alias kept for compatibility.
+ print('Platform "x11" has been renamed to "linuxbsd" in Godot 4.0. Building for platform "linuxbsd".')
+ # Alias for convenience.
+ selected_platform = "linuxbsd"
+ env_base["platform"] = selected_platform
+
if selected_platform in platform_list:
tmppath = "./platform/" + selected_platform
sys.path.insert(0, tmppath)
import detect
+
if "create" in dir(detect):
env = detect.create(env_base)
else:
env = env_base.Clone()
- if env['dev']:
- env['verbose'] = True
- env['warnings'] = "extra"
- env['werror'] = True
+ if env["dev"]:
+ env["verbose"] = True
+ env["warnings"] = "extra"
+ env["werror"] = True
- if env['vsproj']:
+ if env["vsproj"]:
env.vs_incs = []
env.vs_srcs = []
@@ -277,7 +288,7 @@ if selected_platform in platform_list:
pieces = fname.split(".")
if len(pieces) > 0:
basename = pieces[0]
- basename = basename.replace('\\\\', '/')
+ basename = basename.replace("\\\\", "/")
if os.path.isfile(basename + ".h"):
env.vs_incs = env.vs_incs + [basename + ".h"]
elif os.path.isfile(basename + ".hpp"):
@@ -286,28 +297,29 @@ if selected_platform in platform_list:
env.vs_srcs = env.vs_srcs + [basename + ".c"]
elif os.path.isfile(basename + ".cpp"):
env.vs_srcs = env.vs_srcs + [basename + ".cpp"]
+
env.AddToVSProject = AddToVSProject
env.extra_suffix = ""
- if env["extra_suffix"] != '':
- env.extra_suffix += '.' + env["extra_suffix"]
+ if env["extra_suffix"] != "":
+ env.extra_suffix += "." + env["extra_suffix"]
# Environment flags
- CCFLAGS = env.get('CCFLAGS', '')
- env['CCFLAGS'] = ''
+ CCFLAGS = env.get("CCFLAGS", "")
+ env["CCFLAGS"] = ""
env.Append(CCFLAGS=str(CCFLAGS).split())
- CFLAGS = env.get('CFLAGS', '')
- env['CFLAGS'] = ''
+ CFLAGS = env.get("CFLAGS", "")
+ env["CFLAGS"] = ""
env.Append(CFLAGS=str(CFLAGS).split())
- CXXFLAGS = env.get('CXXFLAGS', '')
- env['CXXFLAGS'] = ''
+ CXXFLAGS = env.get("CXXFLAGS", "")
+ env["CXXFLAGS"] = ""
env.Append(CXXFLAGS=str(CXXFLAGS).split())
- LINKFLAGS = env.get('LINKFLAGS', '')
- env['LINKFLAGS'] = ''
+ LINKFLAGS = env.get("LINKFLAGS", "")
+ env["LINKFLAGS"] = ""
env.Append(LINKFLAGS=str(LINKFLAGS).split())
# Platform specific flags
@@ -326,12 +338,12 @@ if selected_platform in platform_list:
if not env.msvc:
# Specifying GNU extensions support explicitly, which are supported by
# both GCC and Clang. Both currently default to gnu11 and gnu++14.
- env.Prepend(CFLAGS=['-std=gnu11'])
- env.Prepend(CXXFLAGS=['-std=gnu++17'])
+ env.Prepend(CFLAGS=["-std=gnu11"])
+ env.Prepend(CXXFLAGS=["-std=gnu++17"])
else:
# MSVC doesn't have clear C standard support, /std only covers C++.
# We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
- env.Prepend(CCFLAGS=['/std:c++17'])
+ env.Prepend(CCFLAGS=["/std:c++17"])
# Enforce our minimal compiler version requirements
cc_version = methods.get_compiler_version(env) or [-1, -1]
@@ -342,16 +354,20 @@ if selected_platform in platform_list:
# GCC 8 before 8.4 has a regression in the support of guaranteed copy elision
# which causes a build failure: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86521
if cc_version_major == 8 and cc_version_minor < 4:
- print("Detected GCC 8 version < 8.4, which is not supported due to a "
- "regression in its C++17 guaranteed copy elision support. Use a "
- "newer GCC version, or Clang 6 or later by passing \"use_llvm=yes\" "
- "to the SCons command line.")
+ print(
+ "Detected GCC 8 version < 8.4, which is not supported due to a "
+ "regression in its C++17 guaranteed copy elision support. Use a "
+ 'newer GCC version, or Clang 6 or later by passing "use_llvm=yes" '
+ "to the SCons command line."
+ )
sys.exit(255)
elif cc_version_major < 7:
- print("Detected GCC version older than 7, which does not fully support "
- "C++17. Supported versions are GCC 7, 9 and later. Use a newer GCC "
- "version, or Clang 6 or later by passing \"use_llvm=yes\" to the "
- "SCons command line.")
+ print(
+ "Detected GCC version older than 7, which does not fully support "
+ "C++17. Supported versions are GCC 7, 9 and later. Use a newer GCC "
+ 'version, or Clang 6 or later by passing "use_llvm=yes" to the '
+ "SCons command line."
+ )
sys.exit(255)
elif methods.using_clang(env):
# Apple LLVM versions differ from upstream LLVM version \o/, compare
@@ -359,87 +375,100 @@ if selected_platform in platform_list:
if env["platform"] == "osx" or env["platform"] == "iphone":
vanilla = methods.is_vanilla_clang(env)
if vanilla and cc_version_major < 6:
- print("Detected Clang version older than 6, which does not fully support "
- "C++17. Supported versions are Clang 6 and later.")
+ print(
+ "Detected Clang version older than 6, which does not fully support "
+ "C++17. Supported versions are Clang 6 and later."
+ )
sys.exit(255)
elif not vanilla and cc_version_major < 10:
- print("Detected Apple Clang version older than 10, which does not fully "
- "support C++17. Supported versions are Apple Clang 10 and later.")
+ print(
+ "Detected Apple Clang version older than 10, which does not fully "
+ "support C++17. Supported versions are Apple Clang 10 and later."
+ )
sys.exit(255)
elif cc_version_major < 6:
- print("Detected Clang version older than 6, which does not fully support "
- "C++17. Supported versions are Clang 6 and later.")
+ print(
+ "Detected Clang version older than 6, which does not fully support "
+ "C++17. Supported versions are Clang 6 and later."
+ )
sys.exit(255)
# Configure compiler warnings
if env.msvc:
# Truncations, narrowing conversions, signed/unsigned comparisons...
- disable_nonessential_warnings = ['/wd4267', '/wd4244', '/wd4305', '/wd4018', '/wd4800']
- if (env["warnings"] == 'extra'):
- env.Append(CCFLAGS=['/Wall']) # Implies /W4
- elif (env["warnings"] == 'all'):
- env.Append(CCFLAGS=['/W3'] + disable_nonessential_warnings)
- elif (env["warnings"] == 'moderate'):
- env.Append(CCFLAGS=['/W2'] + disable_nonessential_warnings)
- else: # 'no'
- env.Append(CCFLAGS=['/w'])
+ disable_nonessential_warnings = ["/wd4267", "/wd4244", "/wd4305", "/wd4018", "/wd4800"]
+ if env["warnings"] == "extra":
+ env.Append(CCFLAGS=["/Wall"]) # Implies /W4
+ elif env["warnings"] == "all":
+ env.Append(CCFLAGS=["/W3"] + disable_nonessential_warnings)
+ elif env["warnings"] == "moderate":
+ env.Append(CCFLAGS=["/W2"] + disable_nonessential_warnings)
+ else: # 'no'
+ env.Append(CCFLAGS=["/w"])
# Set exception handling model to avoid warnings caused by Windows system headers.
- env.Append(CCFLAGS=['/EHsc'])
- if (env["werror"]):
- env.Append(CCFLAGS=['/WX'])
+ env.Append(CCFLAGS=["/EHsc"])
+ if env["werror"]:
+ env.Append(CCFLAGS=["/WX"])
# Force to use Unicode encoding
- env.Append(MSVC_FLAGS=['/utf8'])
- else: # Rest of the world
+ env.Append(MSVC_FLAGS=["/utf8"])
+ else: # Rest of the world
shadow_local_warning = []
- all_plus_warnings = ['-Wwrite-strings']
+ all_plus_warnings = ["-Wwrite-strings"]
if methods.using_gcc(env):
if cc_version_major >= 7:
- shadow_local_warning = ['-Wshadow-local']
+ shadow_local_warning = ["-Wshadow-local"]
- if (env["warnings"] == 'extra'):
- env.Append(CCFLAGS=['-Wall', '-Wextra', '-Wno-unused-parameter']
- + all_plus_warnings + shadow_local_warning)
- env.Append(CXXFLAGS=['-Wctor-dtor-privacy', '-Wnon-virtual-dtor'])
+ if env["warnings"] == "extra":
+ env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wno-unused-parameter"] + all_plus_warnings + shadow_local_warning)
+ env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"])
if methods.using_gcc(env):
- env.Append(CCFLAGS=['-Walloc-zero',
- '-Wduplicated-branches', '-Wduplicated-cond',
- '-Wstringop-overflow=4', '-Wlogical-op'])
+ env.Append(
+ CCFLAGS=[
+ "-Walloc-zero",
+ "-Wduplicated-branches",
+ "-Wduplicated-cond",
+ "-Wstringop-overflow=4",
+ "-Wlogical-op",
+ ]
+ )
# -Wnoexcept was removed temporarily due to GH-36325.
- env.Append(CXXFLAGS=['-Wplacement-new=1'])
+ env.Append(CXXFLAGS=["-Wplacement-new=1"])
if cc_version_major >= 9:
- env.Append(CCFLAGS=['-Wattribute-alias=2'])
+ env.Append(CCFLAGS=["-Wattribute-alias=2"])
if methods.using_clang(env):
- env.Append(CCFLAGS=['-Wimplicit-fallthrough'])
- elif (env["warnings"] == 'all'):
- env.Append(CCFLAGS=['-Wall'] + shadow_local_warning)
- elif (env["warnings"] == 'moderate'):
- env.Append(CCFLAGS=['-Wall', '-Wno-unused'] + shadow_local_warning)
- else: # 'no'
- env.Append(CCFLAGS=['-w'])
- if (env["werror"]):
- env.Append(CCFLAGS=['-Werror'])
+ env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
+ elif env["warnings"] == "all":
+ env.Append(CCFLAGS=["-Wall"] + shadow_local_warning)
+ elif env["warnings"] == "moderate":
+ env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + shadow_local_warning)
+ else: # 'no'
+ env.Append(CCFLAGS=["-w"])
+ if env["werror"]:
+ env.Append(CCFLAGS=["-Werror"])
# FIXME: Temporary workaround after the Vulkan merge, remove once warnings are fixed.
if methods.using_gcc(env):
- env.Append(CXXFLAGS=['-Wno-error=cpp'])
+ env.Append(CXXFLAGS=["-Wno-error=cpp"])
+ if cc_version_major == 7: # Bogus warning fixed in 8+.
+ env.Append(CCFLAGS=["-Wno-error=strict-overflow"])
else:
- env.Append(CXXFLAGS=['-Wno-error=#warnings'])
- else: # always enable those errors
- env.Append(CCFLAGS=['-Werror=return-type'])
+ env.Append(CXXFLAGS=["-Wno-error=#warnings"])
+ else: # always enable those errors
+ env.Append(CCFLAGS=["-Werror=return-type"])
- if (hasattr(detect, 'get_program_suffix')):
+ if hasattr(detect, "get_program_suffix"):
suffix = "." + detect.get_program_suffix()
else:
suffix = "." + selected_platform
- if (env["target"] == "release"):
+ if env["target"] == "release":
if env["tools"]:
print("Tools can only be built with targets 'debug' and 'release_debug'.")
sys.exit(255)
suffix += ".opt"
- env.Append(CPPDEFINES=['NDEBUG'])
+ env.Append(CPPDEFINES=["NDEBUG"])
- elif (env["target"] == "release_debug"):
+ elif env["target"] == "release_debug":
if env["tools"]:
suffix += ".opt.tools"
else:
@@ -452,27 +481,28 @@ if selected_platform in platform_list:
if env["arch"] != "":
suffix += "." + env["arch"]
- elif (env["bits"] == "32"):
+ elif env["bits"] == "32":
suffix += ".32"
- elif (env["bits"] == "64"):
+ elif env["bits"] == "64":
suffix += ".64"
suffix += env.extra_suffix
sys.path.remove(tmppath)
- sys.modules.pop('detect')
+ sys.modules.pop("detect")
env.module_list = []
env.module_icons_paths = []
env.doc_class_path = {}
for x in sorted(module_list):
- if not env['module_' + x + '_enabled']:
+ if not env["module_" + x + "_enabled"]:
continue
tmppath = "./modules/" + x
sys.path.insert(0, tmppath)
env.current_module = x
import config
+
if config.can_build(env, selected_platform):
config.configure(env)
env.module_list.append(x)
@@ -494,7 +524,7 @@ if selected_platform in platform_list:
env.module_icons_paths.append("modules/" + x + "/" + "icons")
sys.path.remove(tmppath)
- sys.modules.pop('config')
+ sys.modules.pop("config")
methods.update_version(env.module_version_string)
@@ -513,45 +543,66 @@ if selected_platform in platform_list:
env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
- if (env.use_ptrcall):
- env.Append(CPPDEFINES=['PTRCALL_ENABLED'])
- if env['tools']:
- env.Append(CPPDEFINES=['TOOLS_ENABLED'])
- if env['disable_3d']:
- if env['tools']:
- print("Build option 'disable_3d=yes' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template).")
+ if env.use_ptrcall:
+ env.Append(CPPDEFINES=["PTRCALL_ENABLED"])
+ if env["tools"]:
+ env.Append(CPPDEFINES=["TOOLS_ENABLED"])
+ if env["disable_3d"]:
+ if env["tools"]:
+ print(
+ "Build option 'disable_3d=yes' cannot be used with 'tools=yes' (editor), "
+ "only with 'tools=no' (export template)."
+ )
sys.exit(255)
else:
- env.Append(CPPDEFINES=['_3D_DISABLED'])
- if env['disable_advanced_gui']:
- if env['tools']:
- print("Build option 'disable_advanced_gui=yes' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template).")
+ env.Append(CPPDEFINES=["_3D_DISABLED"])
+ if env["disable_advanced_gui"]:
+ if env["tools"]:
+ print(
+ "Build option 'disable_advanced_gui=yes' cannot be used with 'tools=yes' (editor), "
+ "only with 'tools=no' (export template)."
+ )
sys.exit(255)
else:
- env.Append(CPPDEFINES=['ADVANCED_GUI_DISABLED'])
- if env['minizip']:
- env.Append(CPPDEFINES=['MINIZIP_ENABLED'])
+ env.Append(CPPDEFINES=["ADVANCED_GUI_DISABLED"])
+ if env["minizip"]:
+ env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
- editor_module_list = ['regex']
+ editor_module_list = ["regex"]
for x in editor_module_list:
- if not env['module_' + x + '_enabled']:
- if env['tools']:
- print("Build option 'module_" + x + "_enabled=no' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template).")
+ if not env["module_" + x + "_enabled"]:
+ if env["tools"]:
+ print(
+ "Build option 'module_" + x + "_enabled=no' cannot be used with 'tools=yes' (editor), "
+ "only with 'tools=no' (export template)."
+ )
sys.exit(255)
- if not env['verbose']:
+ if not env["verbose"]:
methods.no_verbose(sys, env)
- if (not env["platform"] == "server"):
- env.Append(BUILDERS = { 'GLES2_GLSL' : env.Builder(action=run_in_subprocess(gles_builders.build_gles2_headers), suffix='glsl.gen.h', src_suffix='.glsl')})
- env.Append(BUILDERS = { 'RD_GLSL' : env.Builder(action=run_in_subprocess(gles_builders.build_rd_headers), suffix='glsl.gen.h', src_suffix='.glsl')})
+ if not env["platform"] == "server":
+ env.Append(
+ BUILDERS={
+ "GLES2_GLSL": env.Builder(
+ action=run_in_subprocess(gles_builders.build_gles2_headers), suffix="glsl.gen.h", src_suffix=".glsl"
+ )
+ }
+ )
+ env.Append(
+ BUILDERS={
+ "RD_GLSL": env.Builder(
+ action=run_in_subprocess(gles_builders.build_rd_headers), suffix="glsl.gen.h", src_suffix=".glsl"
+ )
+ }
+ )
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path != None:
CacheDir(scons_cache_path)
print("Scons cache enabled... (path: '" + scons_cache_path + "')")
- Export('env')
+ Export("env")
# build subdirs, the build order is dependent on link order.
@@ -568,16 +619,16 @@ if selected_platform in platform_list:
SConscript("platform/" + selected_platform + "/SCsub") # build selected platform
# Microsoft Visual Studio Project Generation
- if env['vsproj']:
- env['CPPPATH'] = [Dir(path) for path in env['CPPPATH']]
+ if env["vsproj"]:
+ env["CPPPATH"] = [Dir(path) for path in env["CPPPATH"]]
methods.generate_vs_project(env, GetOption("num_jobs"))
methods.generate_cpp_hint_file("cpp.hint")
# Check for the existence of headers
conf = Configure(env)
- if ("check_c_headers" in env):
+ if "check_c_headers" in env:
for header in env["check_c_headers"]:
- if (conf.CheckCHeader(header[0])):
+ if conf.CheckCHeader(header[0]):
env.AppendUnique(CPPDEFINES=[header[1]])
elif selected_platform != "":
@@ -599,26 +650,30 @@ elif selected_platform != "":
sys.exit(255)
# The following only makes sense when the env is defined, and assumes it is
-if 'env' in locals():
+if "env" in locals():
screen = sys.stdout
# Progress reporting is not available in non-TTY environments since it
# messes with the output (for example, when writing to a file)
- show_progress = (env['progress'] and sys.stdout.isatty())
+ show_progress = env["progress"] and sys.stdout.isatty()
node_count = 0
node_count_max = 0
node_count_interval = 1
- node_count_fname = str(env.Dir('#')) + '/.scons_node_count'
+ node_count_fname = str(env.Dir("#")) + "/.scons_node_count"
import time, math
class cache_progress:
# The default is 1 GB cache and 12 hours half life
- def __init__(self, path = None, limit = 1073741824, half_life = 43200):
+ def __init__(self, path=None, limit=1073741824, half_life=43200):
self.path = path
self.limit = limit
self.exponent_scale = math.log(2) / half_life
- if env['verbose'] and path != None:
- screen.write('Current cache limit is ' + self.convert_size(limit) + ' (used: ' + self.convert_size(self.get_size(path)) + ')\n')
+ if env["verbose"] and path != None:
+ screen.write(
+ "Current cache limit is {} (used: {})\n".format(
+ self.convert_size(limit), self.convert_size(self.get_size(path))
+ )
+ )
self.delete(self.file_list())
def __call__(self, node, *args, **kw):
@@ -626,22 +681,22 @@ if 'env' in locals():
if show_progress:
# Print the progress percentage
node_count += node_count_interval
- if (node_count_max > 0 and node_count <= node_count_max):
- screen.write('\r[%3d%%] ' % (node_count * 100 / node_count_max))
+ if node_count_max > 0 and node_count <= node_count_max:
+ screen.write("\r[%3d%%] " % (node_count * 100 / node_count_max))
screen.flush()
- elif (node_count_max > 0 and node_count > node_count_max):
- screen.write('\r[100%] ')
+ elif node_count_max > 0 and node_count > node_count_max:
+ screen.write("\r[100%] ")
screen.flush()
else:
- screen.write('\r[Initial build] ')
+ screen.write("\r[Initial build] ")
screen.flush()
def delete(self, files):
if len(files) == 0:
return
- if env['verbose']:
+ if env["verbose"]:
# Utter something
- screen.write('\rPurging %d %s from cache...\n' % (len(files), len(files) > 1 and 'files' or 'file'))
+ screen.write("\rPurging %d %s from cache...\n" % (len(files), len(files) > 1 and "files" or "file"))
[os.remove(f) for f in files]
def file_list(self):
@@ -650,7 +705,7 @@ if 'env' in locals():
return []
# Gather a list of (filename, (size, atime)) within the
# cache directory
- file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, '*', '*'))]
+ file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, "*", "*"))]
if file_stat == []:
# Nothing to do
return []
@@ -665,7 +720,7 @@ if 'env' in locals():
# Search for the first entry where the storage limit is
# reached
sum, mark = 0, None
- for i,x in enumerate(file_stat):
+ for i, x in enumerate(file_stat):
sum += x[1]
if sum > self.limit:
mark = i
@@ -684,7 +739,7 @@ if 'env' in locals():
s = round(size_bytes / p, 2)
return "%s %s" % (int(s) if i == 0 else s, size_name[i])
- def get_size(self, start_path = '.'):
+ def get_size(self, start_path="."):
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
@@ -694,8 +749,8 @@ if 'env' in locals():
def progress_finish(target, source, env):
global node_count, progressor
- with open(node_count_fname, 'w') as f:
- f.write('%d\n' % node_count)
+ with open(node_count_fname, "w") as f:
+ f.write("%d\n" % node_count)
progressor.delete(progressor.file_list())
try:
@@ -709,7 +764,7 @@ if 'env' in locals():
# cache directory to a size not larger than cache_limit.
cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024
progressor = cache_progress(cache_directory, cache_limit)
- Progress(progressor, interval = node_count_interval)
+ Progress(progressor, interval=node_count_interval)
- progress_finish_command = Command('progress_finish', [], progress_finish)
+ progress_finish_command = Command("progress_finish", [], progress_finish)
AlwaysBuild(progress_finish_command)
diff --git a/compat.py b/compat.py
deleted file mode 100644
index de99eef9c2..0000000000
--- a/compat.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import sys
-
-if sys.version_info < (3,):
- def isbasestring(s):
- return isinstance(s, basestring)
- def open_utf8(filename, mode):
- return open(filename, mode)
- def byte_to_str(x):
- return str(ord(x))
- import cStringIO
- def StringIO():
- return cStringIO.StringIO()
- def encode_utf8(x):
- return x
- def decode_utf8(x):
- return x
- def iteritems(d):
- return d.iteritems()
- def itervalues(d):
- return d.itervalues()
- def escape_string(s):
- if isinstance(s, unicode):
- s = s.encode('ascii')
- result = ''
- for c in s:
- if not (32 <= ord(c) < 127) or c in ('\\', '"'):
- result += '\\%03o' % ord(c)
- else:
- result += c
- return result
-
-else:
- def isbasestring(s):
- return isinstance(s, (str, bytes))
- def open_utf8(filename, mode):
- return open(filename, mode, encoding="utf-8")
- def byte_to_str(x):
- return str(x)
- import io
- def StringIO():
- return io.StringIO()
- import codecs
- def encode_utf8(x):
- return codecs.utf_8_encode(x)[0]
- def decode_utf8(x):
- return codecs.utf_8_decode(x)[0]
- def iteritems(d):
- return iter(d.items())
- def itervalues(d):
- return iter(d.values())
- def charcode_to_c_escapes(c):
- rev_result = []
- while c >= 256:
- c, low = (c // 256, c % 256)
- rev_result.append('\\%03o' % low)
- rev_result.append('\\%03o' % c)
- return ''.join(reversed(rev_result))
- def escape_string(s):
- result = ''
- if isinstance(s, str):
- s = s.encode('utf-8')
- for c in s:
- if not(32 <= c < 127) or c in (ord('\\'), ord('"')):
- result += charcode_to_c_escapes(c)
- else:
- result += chr(c)
- return result
-
diff --git a/core/SCsub b/core/SCsub
index b4974196bd..0ab4f11d87 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
import core_builders
import make_binders
@@ -11,31 +11,32 @@ env.core_sources = []
# Generate AES256 script encryption key
import os
+
txt = "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"
-if ("SCRIPT_AES256_ENCRYPTION_KEY" in os.environ):
+if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
e = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
txt = ""
ec_valid = True
- if (len(e) != 64):
+ if len(e) != 64:
ec_valid = False
else:
for i in range(len(e) >> 1):
- if (i > 0):
+ if i > 0:
txt += ","
- txts = "0x" + e[i * 2:i * 2 + 2]
+ txts = "0x" + e[i * 2 : i * 2 + 2]
try:
int(txts, 16)
except:
ec_valid = False
txt += txts
- if (not ec_valid):
+ if not ec_valid:
txt = "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"
print("Invalid AES256 encryption key, not 64 bits hex: " + e)
# NOTE: It is safe to generate this file here, since this is still executed serially
with open("script_encryption_key.gen.cpp", "w") as f:
- f.write("#include \"core/project_settings.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n")
+ f.write('#include "core/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n")
# Add required thirdparty code.
@@ -49,7 +50,6 @@ thirdparty_misc_sources = [
# C sources
"fastlz.c",
"smaz.c",
-
# C++ sources
"hq2x.cpp",
"pcg.cpp",
@@ -60,30 +60,30 @@ thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_mis
env_thirdparty.add_source_files(env.core_sources, thirdparty_misc_sources)
# Zlib library, can be unbundled
-if env['builtin_zlib']:
- thirdparty_zlib_dir = "#thirdparty/zlib/"
- thirdparty_zlib_sources = [
- "adler32.c",
- "compress.c",
- "crc32.c",
- "deflate.c",
- "infback.c",
- "inffast.c",
- "inflate.c",
- "inftrees.c",
- "trees.c",
- "uncompr.c",
- "zutil.c",
- ]
- thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
-
- env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
- # Needs to be available in main env too
- env.Prepend(CPPPATH=[thirdparty_zlib_dir])
- if (env['target'] == 'debug'):
- env_thirdparty.Append(CPPDEFINES=['ZLIB_DEBUG'])
-
- env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources)
+if env["builtin_zlib"]:
+ thirdparty_zlib_dir = "#thirdparty/zlib/"
+ thirdparty_zlib_sources = [
+ "adler32.c",
+ "compress.c",
+ "crc32.c",
+ "deflate.c",
+ "infback.c",
+ "inffast.c",
+ "inflate.c",
+ "inftrees.c",
+ "trees.c",
+ "uncompr.c",
+ "zutil.c",
+ ]
+ thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+
+ env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
+ # Needs to be available in main env too
+ env.Prepend(CPPPATH=[thirdparty_zlib_dir])
+ if env["target"] == "debug":
+ env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
+
+ env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources)
# Minizip library, could be unbundled in theory
# However, our version has some custom modifications, so it won't compile with the system one
@@ -99,7 +99,7 @@ env_thirdparty.add_source_files(env.core_sources, thirdparty_minizip_sources)
# Zstd library, can be unbundled in theory
# though we currently use some private symbols
# https://github.com/godotengine/godot/issues/17374
-if env['builtin_zstd']:
+if env["builtin_zstd"]:
thirdparty_zstd_dir = "#thirdparty/zstd/"
thirdparty_zstd_sources = [
"common/debug.c",
@@ -142,31 +142,45 @@ if env['builtin_zstd']:
env.add_source_files(env.core_sources, "*.cpp")
# Certificates
-env.Depends("#core/io/certs_compressed.gen.h", ["#thirdparty/certs/ca-certificates.crt", env.Value(env['builtin_certs']), env.Value(env['system_certs_path'])])
-env.CommandNoCache("#core/io/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", run_in_subprocess(core_builders.make_certs_header))
+env.Depends(
+ "#core/io/certs_compressed.gen.h",
+ ["#thirdparty/certs/ca-certificates.crt", env.Value(env["builtin_certs"]), env.Value(env["system_certs_path"])],
+)
+env.CommandNoCache(
+ "#core/io/certs_compressed.gen.h",
+ "#thirdparty/certs/ca-certificates.crt",
+ run_in_subprocess(core_builders.make_certs_header),
+)
# Make binders
-env.CommandNoCache(['method_bind.gen.inc', 'method_bind_ext.gen.inc', 'method_bind_free_func.gen.inc'], 'make_binders.py', run_in_subprocess(make_binders.run))
+env.CommandNoCache(
+ ["method_bind.gen.inc", "method_bind_ext.gen.inc", "method_bind_free_func.gen.inc"],
+ "make_binders.py",
+ run_in_subprocess(make_binders.run),
+)
# Authors
-env.Depends('#core/authors.gen.h', "../AUTHORS.md")
-env.CommandNoCache('#core/authors.gen.h', "../AUTHORS.md", run_in_subprocess(core_builders.make_authors_header))
+env.Depends("#core/authors.gen.h", "../AUTHORS.md")
+env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", run_in_subprocess(core_builders.make_authors_header))
# Donors
-env.Depends('#core/donors.gen.h', "../DONORS.md")
-env.CommandNoCache('#core/donors.gen.h', "../DONORS.md", run_in_subprocess(core_builders.make_donors_header))
+env.Depends("#core/donors.gen.h", "../DONORS.md")
+env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", run_in_subprocess(core_builders.make_donors_header))
# License
-env.Depends('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"])
-env.CommandNoCache('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"], run_in_subprocess(core_builders.make_license_header))
+env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
+env.CommandNoCache(
+ "#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"], run_in_subprocess(core_builders.make_license_header)
+)
# Chain load SCsubs
-SConscript('os/SCsub')
-SConscript('math/SCsub')
-SConscript('crypto/SCsub')
-SConscript('io/SCsub')
-SConscript('debugger/SCsub')
-SConscript('bind/SCsub')
+SConscript("os/SCsub")
+SConscript("math/SCsub")
+SConscript("crypto/SCsub")
+SConscript("io/SCsub")
+SConscript("debugger/SCsub")
+SConscript("input/SCsub")
+SConscript("bind/SCsub")
# Build it all as a library
diff --git a/core/array.cpp b/core/array.cpp
index 7eb15ea934..d65bddae61 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -67,7 +67,7 @@ void Array::_unref() const {
if (_p->refcount.unref()) {
memdelete(_p);
}
- _p = NULL;
+ _p = nullptr;
}
Variant &Array::operator[](int p_idx) {
@@ -467,7 +467,7 @@ const void *Array::id() const {
Array::Array(const Array &p_from) {
- _p = NULL;
+ _p = nullptr;
_ref(p_from);
}
diff --git a/core/bind/SCsub b/core/bind/SCsub
index 1c5f954470..19a6549225 100644
--- a/core/bind/SCsub
+++ b/core/bind/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index bfe07d61c5..e8955c05df 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -62,7 +62,7 @@ static const unsigned int MONTH_DAYS_TABLE[2][12] = {
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
-_ResourceLoader *_ResourceLoader::singleton = NULL;
+_ResourceLoader *_ResourceLoader::singleton = nullptr;
Error _ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads) {
@@ -173,7 +173,7 @@ Vector<String> _ResourceSaver::get_recognized_extensions(const RES &p_resource)
return ret;
}
-_ResourceSaver *_ResourceSaver::singleton = NULL;
+_ResourceSaver *_ResourceSaver::singleton = nullptr;
void _ResourceSaver::_bind_methods() {
@@ -194,82 +194,6 @@ _ResourceSaver::_ResourceSaver() {
singleton = this;
}
-/////////////////OS
-
-void _OS::global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta) {
-
- OS::get_singleton()->global_menu_add_item(p_menu, p_label, p_signal, p_meta);
-}
-
-void _OS::global_menu_add_separator(const String &p_menu) {
-
- OS::get_singleton()->global_menu_add_separator(p_menu);
-}
-
-void _OS::global_menu_remove_item(const String &p_menu, int p_idx) {
-
- OS::get_singleton()->global_menu_remove_item(p_menu, p_idx);
-}
-
-void _OS::global_menu_clear(const String &p_menu) {
-
- OS::get_singleton()->global_menu_clear(p_menu);
-}
-
-Point2 _OS::get_mouse_position() const {
-
- return OS::get_singleton()->get_mouse_position();
-}
-
-void _OS::set_window_title(const String &p_title) {
-
- OS::get_singleton()->set_window_title(p_title);
-}
-
-int _OS::get_mouse_button_state() const {
-
- return OS::get_singleton()->get_mouse_button_state();
-}
-
-String _OS::get_unique_id() const {
- return OS::get_singleton()->get_unique_id();
-}
-
-bool _OS::has_touchscreen_ui_hint() const {
-
- return OS::get_singleton()->has_touchscreen_ui_hint();
-}
-
-void _OS::set_clipboard(const String &p_text) {
-
- OS::get_singleton()->set_clipboard(p_text);
-}
-
-String _OS::get_clipboard() const {
-
- return OS::get_singleton()->get_clipboard();
-}
-
-int _OS::get_video_driver_count() const {
- return OS::get_singleton()->get_video_driver_count();
-}
-
-String _OS::get_video_driver_name(VideoDriver p_driver) const {
- return OS::get_singleton()->get_video_driver_name((int)p_driver);
-}
-
-_OS::VideoDriver _OS::get_current_video_driver() const {
- return (VideoDriver)OS::get_singleton()->get_current_video_driver();
-}
-
-int _OS::get_audio_driver_count() const {
- return OS::get_singleton()->get_audio_driver_count();
-}
-
-String _OS::get_audio_driver_name(int p_driver) const {
- return OS::get_singleton()->get_audio_driver_name(p_driver);
-}
-
PackedStringArray _OS::get_connected_midi_inputs() {
return OS::get_singleton()->get_connected_midi_inputs();
}
@@ -282,198 +206,11 @@ void _OS::close_midi_inputs() {
OS::get_singleton()->close_midi_inputs();
}
-void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen) {
-
- OS::VideoMode vm;
- vm.width = p_size.width;
- vm.height = p_size.height;
- vm.fullscreen = p_fullscreen;
- vm.resizable = p_resizeable;
- OS::get_singleton()->set_video_mode(vm, p_screen);
-}
-
-Size2 _OS::get_video_mode(int p_screen) const {
-
- OS::VideoMode vm;
- vm = OS::get_singleton()->get_video_mode(p_screen);
- return Size2(vm.width, vm.height);
-}
-
-bool _OS::is_video_mode_fullscreen(int p_screen) const {
-
- OS::VideoMode vm;
- vm = OS::get_singleton()->get_video_mode(p_screen);
- return vm.fullscreen;
-}
-
-int _OS::get_screen_count() const {
- return OS::get_singleton()->get_screen_count();
-}
-
-int _OS::get_current_screen() const {
- return OS::get_singleton()->get_current_screen();
-}
-
-void _OS::set_current_screen(int p_screen) {
- OS::get_singleton()->set_current_screen(p_screen);
-}
-
-Point2 _OS::get_screen_position(int p_screen) const {
- return OS::get_singleton()->get_screen_position(p_screen);
-}
-
-Size2 _OS::get_screen_size(int p_screen) const {
- return OS::get_singleton()->get_screen_size(p_screen);
-}
-
-int _OS::get_screen_dpi(int p_screen) const {
-
- return OS::get_singleton()->get_screen_dpi(p_screen);
-}
-
-Point2 _OS::get_window_position() const {
- return OS::get_singleton()->get_window_position();
-}
-
-void _OS::set_window_position(const Point2 &p_position) {
- OS::get_singleton()->set_window_position(p_position);
-}
-
-Size2 _OS::get_max_window_size() const {
- return OS::get_singleton()->get_max_window_size();
-}
-
-Size2 _OS::get_min_window_size() const {
- return OS::get_singleton()->get_min_window_size();
-}
-
-Size2 _OS::get_window_size() const {
- return OS::get_singleton()->get_window_size();
-}
-
-Size2 _OS::get_real_window_size() const {
- return OS::get_singleton()->get_real_window_size();
-}
-
-void _OS::set_max_window_size(const Size2 &p_size) {
- OS::get_singleton()->set_max_window_size(p_size);
-}
-
-void _OS::set_min_window_size(const Size2 &p_size) {
- OS::get_singleton()->set_min_window_size(p_size);
-}
-
-void _OS::set_window_size(const Size2 &p_size) {
- OS::get_singleton()->set_window_size(p_size);
-}
-
-Rect2 _OS::get_window_safe_area() const {
- return OS::get_singleton()->get_window_safe_area();
-}
-
-void _OS::set_window_fullscreen(bool p_enabled) {
- OS::get_singleton()->set_window_fullscreen(p_enabled);
-}
-
-bool _OS::is_window_fullscreen() const {
- return OS::get_singleton()->is_window_fullscreen();
-}
-
-void _OS::set_window_resizable(bool p_enabled) {
- OS::get_singleton()->set_window_resizable(p_enabled);
-}
-
-bool _OS::is_window_resizable() const {
- return OS::get_singleton()->is_window_resizable();
-}
-
-void _OS::set_window_minimized(bool p_enabled) {
- OS::get_singleton()->set_window_minimized(p_enabled);
-}
-
-bool _OS::is_window_minimized() const {
- return OS::get_singleton()->is_window_minimized();
-}
-
-void _OS::set_window_maximized(bool p_enabled) {
- OS::get_singleton()->set_window_maximized(p_enabled);
-}
-
-bool _OS::is_window_maximized() const {
- return OS::get_singleton()->is_window_maximized();
-}
-
-void _OS::set_window_always_on_top(bool p_enabled) {
- OS::get_singleton()->set_window_always_on_top(p_enabled);
-}
-
-bool _OS::is_window_always_on_top() const {
- return OS::get_singleton()->is_window_always_on_top();
-}
-
-bool _OS::is_window_focused() const {
- return OS::get_singleton()->is_window_focused();
-}
-
-void _OS::set_borderless_window(bool p_borderless) {
- OS::get_singleton()->set_borderless_window(p_borderless);
-}
-
-bool _OS::get_window_per_pixel_transparency_enabled() const {
- return OS::get_singleton()->get_window_per_pixel_transparency_enabled();
-}
-
-void _OS::set_window_per_pixel_transparency_enabled(bool p_enabled) {
- OS::get_singleton()->set_window_per_pixel_transparency_enabled(p_enabled);
-}
-
-bool _OS::get_borderless_window() const {
- return OS::get_singleton()->get_borderless_window();
-}
-
-void _OS::set_ime_active(const bool p_active) {
-
- OS::get_singleton()->set_ime_active(p_active);
-}
-
-void _OS::set_ime_position(const Point2 &p_pos) {
-
- OS::get_singleton()->set_ime_position(p_pos);
-}
-
-Point2 _OS::get_ime_selection() const {
- return OS::get_singleton()->get_ime_selection();
-}
-
-String _OS::get_ime_text() const {
- return OS::get_singleton()->get_ime_text();
-}
-
void _OS::set_use_file_access_save_and_swap(bool p_enable) {
FileAccess::set_backup_save(p_enable);
}
-bool _OS::is_video_mode_resizable(int p_screen) const {
-
- OS::VideoMode vm;
- vm = OS::get_singleton()->get_video_mode(p_screen);
- return vm.resizable;
-}
-
-Array _OS::get_fullscreen_mode_list(int p_screen) const {
-
- List<OS::VideoMode> vmlist;
- OS::get_singleton()->get_fullscreen_mode_list(&vmlist, p_screen);
- Array vmarr;
- for (List<OS::VideoMode>::Element *E = vmlist.front(); E; E = E->next()) {
-
- vmarr.push_back(Size2(E->get().width, E->get().height));
- }
-
- return vmarr;
-}
-
void _OS::set_low_processor_usage_mode(bool p_enabled) {
OS::get_singleton()->set_low_processor_usage_mode(p_enabled);
@@ -562,52 +299,16 @@ String _OS::get_locale() const {
return OS::get_singleton()->get_locale();
}
-String _OS::get_latin_keyboard_variant() const {
- switch (OS::get_singleton()->get_latin_keyboard_variant()) {
- case OS::LATIN_KEYBOARD_QWERTY: return "QWERTY";
- case OS::LATIN_KEYBOARD_QWERTZ: return "QWERTZ";
- case OS::LATIN_KEYBOARD_AZERTY: return "AZERTY";
- case OS::LATIN_KEYBOARD_QZERTY: return "QZERTY";
- case OS::LATIN_KEYBOARD_DVORAK: return "DVORAK";
- case OS::LATIN_KEYBOARD_NEO: return "NEO";
- case OS::LATIN_KEYBOARD_COLEMAK: return "COLEMAK";
- default: return "ERROR";
- }
-}
-
String _OS::get_model_name() const {
return OS::get_singleton()->get_model_name();
}
-bool _OS::is_ok_left_and_cancel_right() const {
-
- return OS::get_singleton()->get_swap_ok_cancel();
-}
-
Error _OS::set_thread_name(const String &p_name) {
return Thread::set_name(p_name);
};
-void _OS::set_use_vsync(bool p_enable) {
- OS::get_singleton()->set_use_vsync(p_enable);
-}
-
-bool _OS::is_vsync_enabled() const {
-
- return OS::get_singleton()->is_vsync_enabled();
-}
-
-void _OS::set_vsync_via_compositor(bool p_enable) {
- OS::get_singleton()->set_vsync_via_compositor(p_enable);
-}
-
-bool _OS::is_vsync_via_compositor_enabled() const {
-
- return OS::get_singleton()->is_vsync_via_compositor_enabled();
-}
-
bool _OS::has_feature(const String &p_feature) const {
return OS::get_singleton()->has_feature(p_feature);
@@ -667,16 +368,6 @@ uint64_t _OS::get_static_memory_peak_usage() const {
return OS::get_singleton()->get_static_memory_peak_usage();
}
-void _OS::set_native_icon(const String &p_filename) {
-
- OS::get_singleton()->set_native_icon(p_filename);
-}
-
-void _OS::set_icon(const Ref<Image> &p_icon) {
-
- OS::get_singleton()->set_icon(p_icon);
-}
-
int _OS::get_exit_code() const {
return OS::get_singleton()->get_exit_code();
@@ -924,11 +615,6 @@ bool _OS::can_use_threads() const {
return OS::get_singleton()->can_use_threads();
}
-bool _OS::can_draw() const {
-
- return OS::get_singleton()->can_draw();
-}
-
bool _OS::is_userfs_persistent() const {
return OS::get_singleton()->is_userfs_persistent();
@@ -964,10 +650,10 @@ void _OS::print_all_textures_by_size() {
List<_OSCoreBindImg> imgs;
int total = 0;
{
- List<Ref<Resource> > rsrc;
+ List<Ref<Resource>> rsrc;
ResourceCache::get_cached_resources(&rsrc);
- for (List<Ref<Resource> >::Element *E = rsrc.front(); E; E = E->next()) {
+ for (List<Ref<Resource>>::Element *E = rsrc.front(); E; E = E->next()) {
if (!E->get()->is_class("ImageTexture"))
continue;
@@ -998,13 +684,13 @@ void _OS::print_resources_by_type(const Vector<String> &p_types) {
Map<String, int> type_count;
- List<Ref<Resource> > resources;
+ List<Ref<Resource>> resources;
ResourceCache::get_cached_resources(&resources);
- List<Ref<Resource> > rsrc;
+ List<Ref<Resource>> rsrc;
ResourceCache::get_cached_resources(&rsrc);
- for (List<Ref<Resource> >::Element *E = rsrc.front(); E; E = E->next()) {
+ for (List<Ref<Resource>>::Element *E = rsrc.front(); E; E = E->next()) {
Ref<Resource> r = E->get();
@@ -1025,22 +711,6 @@ void _OS::print_resources_by_type(const Vector<String> &p_types) {
}
};
-bool _OS::has_virtual_keyboard() const {
- return OS::get_singleton()->has_virtual_keyboard();
-}
-
-void _OS::show_virtual_keyboard(const String &p_existing_text) {
- OS::get_singleton()->show_virtual_keyboard(p_existing_text, Rect2());
-}
-
-void _OS::hide_virtual_keyboard() {
- OS::get_singleton()->hide_virtual_keyboard();
-}
-
-int _OS::get_virtual_keyboard_height() {
- return OS::get_singleton()->get_virtual_keyboard_height();
-}
-
void _OS::print_all_resources(const String &p_to_file) {
OS::get_singleton()->print_all_resources(p_to_file);
@@ -1061,45 +731,6 @@ String _OS::get_user_data_dir() const {
return OS::get_singleton()->get_user_data_dir();
};
-Error _OS::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
-
- return OS::get_singleton()->native_video_play(p_path, p_volume, p_audio_track, p_subtitle_track);
-};
-
-bool _OS::native_video_is_playing() {
-
- return OS::get_singleton()->native_video_is_playing();
-};
-
-void _OS::native_video_pause() {
-
- OS::get_singleton()->native_video_pause();
-};
-
-void _OS::native_video_unpause() {
- OS::get_singleton()->native_video_unpause();
-};
-
-void _OS::native_video_stop() {
-
- OS::get_singleton()->native_video_stop();
-};
-
-void _OS::request_attention() {
-
- OS::get_singleton()->request_attention();
-}
-
-void _OS::center_window() {
-
- OS::get_singleton()->center_window();
-}
-
-void _OS::move_window_to_foreground() {
-
- OS::get_singleton()->move_window_to_foreground();
-}
-
bool _OS::is_debug_build() const {
#ifdef DEBUG_ENABLED
@@ -1109,26 +740,6 @@ bool _OS::is_debug_build() const {
#endif
}
-void _OS::set_screen_orientation(ScreenOrientation p_orientation) {
-
- OS::get_singleton()->set_screen_orientation(OS::ScreenOrientation(p_orientation));
-}
-
-_OS::ScreenOrientation _OS::get_screen_orientation() const {
-
- return ScreenOrientation(OS::get_singleton()->get_screen_orientation());
-}
-
-void _OS::set_keep_screen_on(bool p_enabled) {
-
- OS::get_singleton()->set_keep_screen_on(p_enabled);
-}
-
-bool _OS::is_keep_screen_on() const {
-
- return OS::get_singleton()->is_keep_screen_on();
-}
-
String _OS::get_system_dir(SystemDir p_dir) const {
return OS::get_singleton()->get_system_dir(OS::SystemDir(p_dir));
@@ -1149,11 +760,6 @@ int _OS::find_keycode_from_string(const String &p_code) const {
return find_keycode(p_code);
}
-void _OS::alert(const String &p_alert, const String &p_title) {
-
- OS::get_singleton()->alert(p_alert, p_title);
-}
-
bool _OS::request_permission(const String &p_name) {
return OS::get_singleton()->request_permission(p_name);
@@ -1169,90 +775,17 @@ Vector<String> _OS::get_granted_permissions() const {
return OS::get_singleton()->get_granted_permissions();
}
-_OS *_OS::singleton = NULL;
+String _OS::get_unique_id() const {
+ return OS::get_singleton()->get_unique_id();
+}
+_OS *_OS::singleton = nullptr;
void _OS::_bind_methods() {
- //ClassDB::bind_method(D_METHOD("get_mouse_position"),&_OS::get_mouse_position);
- //ClassDB::bind_method(D_METHOD("is_mouse_grab_enabled"),&_OS::is_mouse_grab_enabled);
-
- ClassDB::bind_method(D_METHOD("set_clipboard", "clipboard"), &_OS::set_clipboard);
- ClassDB::bind_method(D_METHOD("get_clipboard"), &_OS::get_clipboard);
-
- //will not delete for now, just unexpose
- //ClassDB::bind_method(D_METHOD("set_video_mode","size","fullscreen","resizable","screen"),&_OS::set_video_mode,DEFVAL(0));
- //ClassDB::bind_method(D_METHOD("get_video_mode_size","screen"),&_OS::get_video_mode,DEFVAL(0));
- //ClassDB::bind_method(D_METHOD("is_video_mode_fullscreen","screen"),&_OS::is_video_mode_fullscreen,DEFVAL(0));
- //ClassDB::bind_method(D_METHOD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0));
- //ClassDB::bind_method(D_METHOD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0));
-
- ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu", "label", "id", "meta"), &_OS::global_menu_add_item);
- ClassDB::bind_method(D_METHOD("global_menu_add_separator", "menu"), &_OS::global_menu_add_separator);
- ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu", "idx"), &_OS::global_menu_remove_item);
- ClassDB::bind_method(D_METHOD("global_menu_clear", "menu"), &_OS::global_menu_clear);
-
- ClassDB::bind_method(D_METHOD("get_video_driver_count"), &_OS::get_video_driver_count);
- ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name);
- ClassDB::bind_method(D_METHOD("get_current_video_driver"), &_OS::get_current_video_driver);
-
- ClassDB::bind_method(D_METHOD("get_audio_driver_count"), &_OS::get_audio_driver_count);
- ClassDB::bind_method(D_METHOD("get_audio_driver_name", "driver"), &_OS::get_audio_driver_name);
ClassDB::bind_method(D_METHOD("get_connected_midi_inputs"), &_OS::get_connected_midi_inputs);
ClassDB::bind_method(D_METHOD("open_midi_inputs"), &_OS::open_midi_inputs);
ClassDB::bind_method(D_METHOD("close_midi_inputs"), &_OS::close_midi_inputs);
- ClassDB::bind_method(D_METHOD("get_screen_count"), &_OS::get_screen_count);
- ClassDB::bind_method(D_METHOD("get_current_screen"), &_OS::get_current_screen);
- ClassDB::bind_method(D_METHOD("set_current_screen", "screen"), &_OS::set_current_screen);
- ClassDB::bind_method(D_METHOD("get_screen_position", "screen"), &_OS::get_screen_position, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_screen_size", "screen"), &_OS::get_screen_size, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_screen_dpi", "screen"), &_OS::get_screen_dpi, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_window_position"), &_OS::get_window_position);
- ClassDB::bind_method(D_METHOD("set_window_position", "position"), &_OS::set_window_position);
- ClassDB::bind_method(D_METHOD("get_window_size"), &_OS::get_window_size);
- ClassDB::bind_method(D_METHOD("get_max_window_size"), &_OS::get_max_window_size);
- ClassDB::bind_method(D_METHOD("get_min_window_size"), &_OS::get_min_window_size);
- ClassDB::bind_method(D_METHOD("set_max_window_size", "size"), &_OS::set_max_window_size);
- ClassDB::bind_method(D_METHOD("set_min_window_size", "size"), &_OS::set_min_window_size);
- ClassDB::bind_method(D_METHOD("set_window_size", "size"), &_OS::set_window_size);
- ClassDB::bind_method(D_METHOD("get_window_safe_area"), &_OS::get_window_safe_area);
- ClassDB::bind_method(D_METHOD("set_window_fullscreen", "enabled"), &_OS::set_window_fullscreen);
- ClassDB::bind_method(D_METHOD("is_window_fullscreen"), &_OS::is_window_fullscreen);
- ClassDB::bind_method(D_METHOD("set_window_resizable", "enabled"), &_OS::set_window_resizable);
- ClassDB::bind_method(D_METHOD("is_window_resizable"), &_OS::is_window_resizable);
- ClassDB::bind_method(D_METHOD("set_window_minimized", "enabled"), &_OS::set_window_minimized);
- ClassDB::bind_method(D_METHOD("is_window_minimized"), &_OS::is_window_minimized);
- ClassDB::bind_method(D_METHOD("set_window_maximized", "enabled"), &_OS::set_window_maximized);
- ClassDB::bind_method(D_METHOD("is_window_maximized"), &_OS::is_window_maximized);
- ClassDB::bind_method(D_METHOD("set_window_always_on_top", "enabled"), &_OS::set_window_always_on_top);
- ClassDB::bind_method(D_METHOD("is_window_always_on_top"), &_OS::is_window_always_on_top);
- ClassDB::bind_method(D_METHOD("is_window_focused"), &_OS::is_window_focused);
- ClassDB::bind_method(D_METHOD("request_attention"), &_OS::request_attention);
- ClassDB::bind_method(D_METHOD("get_real_window_size"), &_OS::get_real_window_size);
- ClassDB::bind_method(D_METHOD("center_window"), &_OS::center_window);
- ClassDB::bind_method(D_METHOD("move_window_to_foreground"), &_OS::move_window_to_foreground);
-
- ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window);
- ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window);
-
- ClassDB::bind_method(D_METHOD("get_window_per_pixel_transparency_enabled"), &_OS::get_window_per_pixel_transparency_enabled);
- ClassDB::bind_method(D_METHOD("set_window_per_pixel_transparency_enabled", "enabled"), &_OS::set_window_per_pixel_transparency_enabled);
-
- ClassDB::bind_method(D_METHOD("set_ime_active", "active"), &_OS::set_ime_active);
- ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &_OS::set_ime_position);
- ClassDB::bind_method(D_METHOD("get_ime_selection"), &_OS::get_ime_selection);
- ClassDB::bind_method(D_METHOD("get_ime_text"), &_OS::get_ime_text);
-
- ClassDB::bind_method(D_METHOD("set_screen_orientation", "orientation"), &_OS::set_screen_orientation);
- ClassDB::bind_method(D_METHOD("get_screen_orientation"), &_OS::get_screen_orientation);
-
- ClassDB::bind_method(D_METHOD("set_keep_screen_on", "enabled"), &_OS::set_keep_screen_on);
- ClassDB::bind_method(D_METHOD("is_keep_screen_on"), &_OS::is_keep_screen_on);
-
- ClassDB::bind_method(D_METHOD("has_touchscreen_ui_hint"), &_OS::has_touchscreen_ui_hint);
-
- ClassDB::bind_method(D_METHOD("set_window_title", "title"), &_OS::set_window_title);
-
ClassDB::bind_method(D_METHOD("set_low_processor_usage_mode", "enable"), &_OS::set_low_processor_usage_mode);
ClassDB::bind_method(D_METHOD("is_in_low_processor_usage_mode"), &_OS::is_in_low_processor_usage_mode);
@@ -1283,9 +816,6 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_time_secs"), &_OS::get_system_time_secs);
ClassDB::bind_method(D_METHOD("get_system_time_msecs"), &_OS::get_system_time_msecs);
- ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &_OS::set_native_icon);
- ClassDB::bind_method(D_METHOD("set_icon", "icon"), &_OS::set_icon);
-
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);
@@ -1295,10 +825,8 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec);
ClassDB::bind_method(D_METHOD("get_splash_tick_msec"), &_OS::get_splash_tick_msec);
ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale);
- ClassDB::bind_method(D_METHOD("get_latin_keyboard_variant"), &_OS::get_latin_keyboard_variant);
ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name);
- ClassDB::bind_method(D_METHOD("can_draw"), &_OS::can_draw);
ClassDB::bind_method(D_METHOD("is_userfs_persistent"), &_OS::is_userfs_persistent);
ClassDB::bind_method(D_METHOD("is_stdout_verbose"), &_OS::is_stdout_verbose);
@@ -1310,10 +838,6 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("dump_memory_to_file", "file"), &_OS::dump_memory_to_file);
ClassDB::bind_method(D_METHOD("dump_resources_to_file", "file"), &_OS::dump_resources_to_file);
- ClassDB::bind_method(D_METHOD("has_virtual_keyboard"), &_OS::has_virtual_keyboard);
- ClassDB::bind_method(D_METHOD("show_virtual_keyboard", "existing_text"), &_OS::show_virtual_keyboard, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("hide_virtual_keyboard"), &_OS::hide_virtual_keyboard);
- ClassDB::bind_method(D_METHOD("get_virtual_keyboard_height"), &_OS::get_virtual_keyboard_height);
ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &_OS::print_resources_in_use, DEFVAL(false));
ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &_OS::print_all_resources, DEFVAL(""));
@@ -1324,81 +848,32 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_dir", "dir"), &_OS::get_system_dir);
ClassDB::bind_method(D_METHOD("get_unique_id"), &_OS::get_unique_id);
- ClassDB::bind_method(D_METHOD("is_ok_left_and_cancel_right"), &_OS::is_ok_left_and_cancel_right);
-
ClassDB::bind_method(D_METHOD("print_all_textures_by_size"), &_OS::print_all_textures_by_size);
ClassDB::bind_method(D_METHOD("print_resources_by_type", "types"), &_OS::print_resources_by_type);
- ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track"), &_OS::native_video_play);
- ClassDB::bind_method(D_METHOD("native_video_is_playing"), &_OS::native_video_is_playing);
- ClassDB::bind_method(D_METHOD("native_video_stop"), &_OS::native_video_stop);
- ClassDB::bind_method(D_METHOD("native_video_pause"), &_OS::native_video_pause);
- ClassDB::bind_method(D_METHOD("native_video_unpause"), &_OS::native_video_unpause);
-
ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &_OS::get_keycode_string);
ClassDB::bind_method(D_METHOD("is_keycode_unicode", "code"), &_OS::is_keycode_unicode);
ClassDB::bind_method(D_METHOD("find_keycode_from_string", "string"), &_OS::find_keycode_from_string);
ClassDB::bind_method(D_METHOD("set_use_file_access_save_and_swap", "enabled"), &_OS::set_use_file_access_save_and_swap);
- ClassDB::bind_method(D_METHOD("alert", "text", "title"), &_OS::alert, DEFVAL("Alert!"));
-
ClassDB::bind_method(D_METHOD("set_thread_name", "name"), &_OS::set_thread_name);
- ClassDB::bind_method(D_METHOD("set_use_vsync", "enable"), &_OS::set_use_vsync);
- ClassDB::bind_method(D_METHOD("is_vsync_enabled"), &_OS::is_vsync_enabled);
-
- ClassDB::bind_method(D_METHOD("set_vsync_via_compositor", "enable"), &_OS::set_vsync_via_compositor);
- ClassDB::bind_method(D_METHOD("is_vsync_via_compositor_enabled"), &_OS::is_vsync_via_compositor_enabled);
-
ClassDB::bind_method(D_METHOD("has_feature", "tag_name"), &_OS::has_feature);
ClassDB::bind_method(D_METHOD("request_permission", "name"), &_OS::request_permission);
ClassDB::bind_method(D_METHOD("request_permissions"), &_OS::request_permissions);
ClassDB::bind_method(D_METHOD("get_granted_permissions"), &_OS::get_granted_permissions);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "clipboard"), "set_clipboard", "get_clipboard");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen");
ADD_PROPERTY(PropertyInfo(Variant::INT, "exit_code"), "set_exit_code", "get_exit_code");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vsync_enabled"), "set_use_vsync", "is_vsync_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vsync_via_compositor"), "set_vsync_via_compositor", "is_vsync_via_compositor_enabled");
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::BOOL, "keep_screen_on"), "set_keep_screen_on", "is_keep_screen_on");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_window_size"), "set_min_window_size", "get_min_window_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_window_size"), "set_max_window_size", "get_max_window_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"), "set_screen_orientation", "get_screen_orientation");
- ADD_GROUP("Window", "window_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_borderless"), "set_borderless_window", "get_borderless_window");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_per_pixel_transparency_enabled"), "set_window_per_pixel_transparency_enabled", "get_window_per_pixel_transparency_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_fullscreen"), "set_window_fullscreen", "is_window_fullscreen");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_maximized"), "set_window_maximized", "is_window_maximized");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_minimized"), "set_window_minimized", "is_window_minimized");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_resizable"), "set_window_resizable", "is_window_resizable");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "window_position"), "set_window_position", "get_window_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "window_size"), "set_window_size", "get_window_size");
// 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("clipboard", "");
- ADD_PROPERTY_DEFAULT("current_screen", 0);
ADD_PROPERTY_DEFAULT("exit_code", 0);
- ADD_PROPERTY_DEFAULT("vsync_enabled", true);
- ADD_PROPERTY_DEFAULT("vsync_via_compositor", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
- ADD_PROPERTY_DEFAULT("keep_screen_on", true);
- ADD_PROPERTY_DEFAULT("min_window_size", Vector2());
- ADD_PROPERTY_DEFAULT("max_window_size", Vector2());
- ADD_PROPERTY_DEFAULT("screen_orientation", 0);
- ADD_PROPERTY_DEFAULT("window_borderless", false);
- ADD_PROPERTY_DEFAULT("window_per_pixel_transparency_enabled", false);
- ADD_PROPERTY_DEFAULT("window_fullscreen", false);
- ADD_PROPERTY_DEFAULT("window_maximized", false);
- ADD_PROPERTY_DEFAULT("window_minimized", false);
- ADD_PROPERTY_DEFAULT("window_resizable", true);
- ADD_PROPERTY_DEFAULT("window_position", Vector2());
- ADD_PROPERTY_DEFAULT("window_size", Vector2());
BIND_ENUM_CONSTANT(VIDEO_DRIVER_GLES2);
BIND_ENUM_CONSTANT(VIDEO_DRIVER_VULKAN);
@@ -1424,14 +899,6 @@ void _OS::_bind_methods() {
BIND_ENUM_CONSTANT(MONTH_NOVEMBER);
BIND_ENUM_CONSTANT(MONTH_DECEMBER);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_LANDSCAPE);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_PORTRAIT);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_REVERSE_PORTRAIT);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_SENSOR_PORTRAIT);
- BIND_ENUM_CONSTANT(SCREEN_ORIENTATION_SENSOR);
-
BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP);
BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM);
BIND_ENUM_CONSTANT(SYSTEM_DIR_DOCUMENTS);
@@ -1449,7 +916,7 @@ _OS::_OS() {
///////////////////// GEOMETRY
-_Geometry *_Geometry::singleton = NULL;
+_Geometry *_Geometry::singleton = nullptr;
_Geometry *_Geometry::get_singleton() {
@@ -1633,7 +1100,7 @@ Vector<Vector3> _Geometry::clip_polygon(const Vector<Vector3> &p_points, const P
Array _Geometry::merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
- Vector<Vector<Point2> > polys = Geometry::merge_polygons_2d(p_polygon_a, p_polygon_b);
+ Vector<Vector<Point2>> polys = Geometry::merge_polygons_2d(p_polygon_a, p_polygon_b);
Array ret;
@@ -1645,7 +1112,7 @@ Array _Geometry::merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vec
Array _Geometry::clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
- Vector<Vector<Point2> > polys = Geometry::clip_polygons_2d(p_polygon_a, p_polygon_b);
+ Vector<Vector<Point2>> polys = Geometry::clip_polygons_2d(p_polygon_a, p_polygon_b);
Array ret;
@@ -1657,7 +1124,7 @@ Array _Geometry::clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vect
Array _Geometry::intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
- Vector<Vector<Point2> > polys = Geometry::intersect_polygons_2d(p_polygon_a, p_polygon_b);
+ Vector<Vector<Point2>> polys = Geometry::intersect_polygons_2d(p_polygon_a, p_polygon_b);
Array ret;
@@ -1669,7 +1136,7 @@ Array _Geometry::intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const
Array _Geometry::exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
- Vector<Vector<Point2> > polys = Geometry::exclude_polygons_2d(p_polygon_a, p_polygon_b);
+ Vector<Vector<Point2>> polys = Geometry::exclude_polygons_2d(p_polygon_a, p_polygon_b);
Array ret;
@@ -1681,7 +1148,7 @@ Array _Geometry::exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const V
Array _Geometry::clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
- Vector<Vector<Point2> > polys = Geometry::clip_polyline_with_polygon_2d(p_polyline, p_polygon);
+ Vector<Vector<Point2>> polys = Geometry::clip_polyline_with_polygon_2d(p_polyline, p_polygon);
Array ret;
@@ -1693,7 +1160,7 @@ Array _Geometry::clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline
Array _Geometry::intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
- Vector<Vector<Point2> > polys = Geometry::intersect_polyline_with_polygon_2d(p_polyline, p_polygon);
+ Vector<Vector<Point2>> polys = Geometry::intersect_polyline_with_polygon_2d(p_polyline, p_polygon);
Array ret;
@@ -1705,7 +1172,7 @@ Array _Geometry::intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_pol
Array _Geometry::offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
- Vector<Vector<Point2> > polys = Geometry::offset_polygon_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type));
+ Vector<Vector<Point2>> polys = Geometry::offset_polygon_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type));
Array ret;
@@ -1717,7 +1184,7 @@ Array _Geometry::offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_de
Array _Geometry::offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
- Vector<Vector<Point2> > polys = Geometry::offset_polyline_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type), Geometry::PolyEndType(p_end_type));
+ Vector<Vector<Point2>> polys = Geometry::offset_polyline_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type), Geometry::PolyEndType(p_end_type));
Array ret;
@@ -1896,11 +1363,11 @@ void _File::close() {
if (f)
memdelete(f);
- f = NULL;
+ f = nullptr;
}
bool _File::is_open() const {
- return f != NULL;
+ return f != nullptr;
}
String _File::get_path() const {
@@ -2163,7 +1630,7 @@ void _File::store_var(const Variant &p_var, bool p_full_objects) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
int len;
- Error err = encode_variant(p_var, NULL, len, p_full_objects);
+ Error err = encode_variant(p_var, nullptr, len, p_full_objects);
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
Vector<uint8_t> buff;
@@ -2187,7 +1654,7 @@ Variant _File::get_var(bool p_allow_objects) const {
const uint8_t *r = buff.ptr();
Variant v;
- Error err = decode_variant(v, &r[0], len, NULL, p_allow_objects);
+ Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
return v;
@@ -2266,7 +1733,7 @@ void _File::_bind_methods() {
_File::_File() {
- f = NULL;
+ f = nullptr;
eswap = false;
}
@@ -2344,10 +1811,10 @@ Error _Directory::change_dir(String p_dir) {
ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
return d->change_dir(p_dir);
}
-String _Directory::get_current_dir(bool p_include_drive) {
+String _Directory::get_current_dir() {
ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use.");
- return d->get_current_dir(p_include_drive);
+ return d->get_current_dir();
}
Error _Directory::make_dir(String p_dir) {
@@ -2444,7 +1911,7 @@ void _Directory::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_drive", "idx"), &_Directory::get_drive);
ClassDB::bind_method(D_METHOD("get_current_drive"), &_Directory::get_current_drive);
ClassDB::bind_method(D_METHOD("change_dir", "todir"), &_Directory::change_dir);
- ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &_Directory::get_current_dir, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_current_dir"), &_Directory::get_current_dir);
ClassDB::bind_method(D_METHOD("make_dir", "path"), &_Directory::make_dir);
ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &_Directory::make_dir_recursive);
ClassDB::bind_method(D_METHOD("file_exists", "path"), &_Directory::file_exists);
@@ -2467,7 +1934,7 @@ _Directory::~_Directory() {
memdelete(d);
}
-_Marshalls *_Marshalls::singleton = NULL;
+_Marshalls *_Marshalls::singleton = nullptr;
_Marshalls *_Marshalls::get_singleton() {
return singleton;
@@ -2476,7 +1943,7 @@ _Marshalls *_Marshalls::get_singleton() {
String _Marshalls::variant_to_base64(const Variant &p_var, bool p_full_objects) {
int len;
- Error err = encode_variant(p_var, NULL, len, p_full_objects);
+ Error err = encode_variant(p_var, nullptr, len, p_full_objects);
ERR_FAIL_COND_V_MSG(err != OK, "", "Error when trying to encode Variant.");
Vector<uint8_t> buff;
@@ -2505,7 +1972,7 @@ Variant _Marshalls::base64_to_variant(const String &p_str, bool p_allow_objects)
ERR_FAIL_COND_V(CryptoCore::b64_decode(&w[0], buf.size(), &len, (unsigned char *)cstr.get_data(), strlen) != OK, Variant());
Variant v;
- Error err = decode_variant(v, &w[0], len, NULL, p_allow_objects);
+ Error err = decode_variant(v, &w[0], len, nullptr, p_allow_objects);
ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to decode Variant.");
return v;
@@ -2684,7 +2151,7 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia
if (!thread) {
active = false;
target_method = StringName();
- target_instance = NULL;
+ target_instance = nullptr;
userdata = Variant();
return ERR_CANT_CREATE;
}
@@ -2712,11 +2179,11 @@ Variant _Thread::wait_to_finish() {
Variant r = ret;
active = false;
target_method = StringName();
- target_instance = NULL;
+ target_instance = nullptr;
userdata = Variant();
if (thread)
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
return r;
}
@@ -2735,8 +2202,8 @@ void _Thread::_bind_methods() {
_Thread::_Thread() {
active = false;
- thread = NULL;
- target_instance = NULL;
+ thread = nullptr;
+ target_instance = nullptr;
}
_Thread::~_Thread() {
@@ -3114,7 +2581,7 @@ void _Engine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix");
}
-_Engine *_Engine::singleton = NULL;
+_Engine *_Engine::singleton = nullptr;
_Engine::_Engine() {
singleton = this;
@@ -3190,7 +2657,7 @@ Ref<JSONParseResult> _JSON::parse(const String &p_json) {
return result;
}
-_JSON *_JSON::singleton = NULL;
+_JSON *_JSON::singleton = nullptr;
_JSON::_JSON() {
singleton = this;
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index fc6419b7d8..d5f44cdc44 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -145,83 +145,10 @@ public:
MONTH_DECEMBER
};
- void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta);
- void global_menu_add_separator(const String &p_menu);
- void global_menu_remove_item(const String &p_menu, int p_idx);
- void global_menu_clear(const String &p_menu);
-
- Point2 get_mouse_position() const;
- void set_window_title(const String &p_title);
- int get_mouse_button_state() const;
-
- void set_clipboard(const String &p_text);
- String get_clipboard() const;
-
- void set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen = 0);
- Size2 get_video_mode(int p_screen = 0) const;
- bool is_video_mode_fullscreen(int p_screen = 0) const;
- bool is_video_mode_resizable(int p_screen = 0) const;
- Array get_fullscreen_mode_list(int p_screen = 0) const;
-
- virtual int get_video_driver_count() const;
- virtual String get_video_driver_name(VideoDriver p_driver) const;
- virtual VideoDriver get_current_video_driver() const;
-
- virtual int get_audio_driver_count() const;
- virtual String get_audio_driver_name(int p_driver) const;
-
virtual PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs();
virtual void close_midi_inputs();
- virtual int get_screen_count() const;
- virtual int get_current_screen() const;
- virtual void set_current_screen(int p_screen);
- virtual Point2 get_screen_position(int p_screen = -1) const;
- virtual Size2 get_screen_size(int p_screen = -1) const;
- virtual int get_screen_dpi(int p_screen = -1) const;
- virtual Point2 get_window_position() const;
- virtual void set_window_position(const Point2 &p_position);
- virtual Size2 get_max_window_size() const;
- virtual Size2 get_min_window_size() const;
- virtual Size2 get_window_size() const;
- virtual Size2 get_real_window_size() const;
- virtual Rect2 get_window_safe_area() const;
- virtual void set_max_window_size(const Size2 &p_size);
- virtual void set_min_window_size(const Size2 &p_size);
- virtual void set_window_size(const Size2 &p_size);
- virtual void set_window_fullscreen(bool p_enabled);
- virtual bool is_window_fullscreen() const;
- virtual void set_window_resizable(bool p_enabled);
- virtual bool is_window_resizable() const;
- virtual void set_window_minimized(bool p_enabled);
- virtual bool is_window_minimized() const;
- virtual void set_window_maximized(bool p_enabled);
- virtual bool is_window_maximized() const;
- virtual void set_window_always_on_top(bool p_enabled);
- virtual bool is_window_always_on_top() const;
- virtual bool is_window_focused() const;
- virtual void request_attention();
- virtual void center_window();
- virtual void move_window_to_foreground();
-
- virtual void set_borderless_window(bool p_borderless);
- virtual bool get_borderless_window() const;
-
- virtual bool get_window_per_pixel_transparency_enabled() const;
- virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
-
- virtual void set_ime_active(const bool p_active);
- virtual void set_ime_position(const Point2 &p_pos);
- virtual Point2 get_ime_selection() const;
- virtual String get_ime_text() const;
-
- Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
- bool native_video_is_playing();
- void native_video_pause();
- void native_video_unpause();
- void native_video_stop();
-
void set_low_processor_usage_mode(bool p_enabled);
bool is_in_low_processor_usage_mode() const;
@@ -243,25 +170,17 @@ public:
Vector<String> get_cmdline_args();
String get_locale() const;
- String get_latin_keyboard_variant() const;
String get_model_name() const;
void dump_memory_to_file(const String &p_file);
void dump_resources_to_file(const String &p_file);
- bool has_virtual_keyboard() const;
- void show_virtual_keyboard(const String &p_existing_text = "");
- void hide_virtual_keyboard();
- int get_virtual_keyboard_height();
-
void print_resources_in_use(bool p_short = false);
void print_all_resources(const String &p_to_file);
void print_all_textures_by_size();
void print_resources_by_type(const Vector<String> &p_types);
- bool has_touchscreen_ui_hint() const;
-
bool is_debug_build() const;
String get_unique_id() const;
@@ -272,9 +191,6 @@ public:
void set_use_file_access_save_and_swap(bool p_enable);
- void set_native_icon(const String &p_filename);
- void set_icon(const Ref<Image> &p_icon);
-
int get_exit_code() const;
void set_exit_code(int p_code);
Dictionary get_date(bool utc) const;
@@ -298,8 +214,6 @@ public:
bool can_use_threads() const;
- bool can_draw() const;
-
bool is_userfs_persistent() const;
bool is_stdout_verbose() const;
@@ -317,39 +231,12 @@ public:
SYSTEM_DIR_RINGTONES,
};
- enum ScreenOrientation {
-
- SCREEN_ORIENTATION_LANDSCAPE,
- SCREEN_ORIENTATION_PORTRAIT,
- SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
- SCREEN_ORIENTATION_REVERSE_PORTRAIT,
- SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
- SCREEN_ORIENTATION_SENSOR_PORTRAIT,
- SCREEN_ORIENTATION_SENSOR,
- };
-
String get_system_dir(SystemDir p_dir) const;
String get_user_data_dir() const;
- void alert(const String &p_alert, const String &p_title = "ALERT!");
-
- void set_screen_orientation(ScreenOrientation p_orientation);
- ScreenOrientation get_screen_orientation() const;
-
- void set_keep_screen_on(bool p_enabled);
- bool is_keep_screen_on() const;
-
- bool is_ok_left_and_cancel_right() const;
-
Error set_thread_name(const String &p_name);
- void set_use_vsync(bool p_enable);
- bool is_vsync_enabled() const;
-
- void set_vsync_via_compositor(bool p_enable);
- bool is_vsync_via_compositor_enabled() const;
-
bool has_feature(const String &p_feature) const;
bool request_permission(const String &p_name);
@@ -365,7 +252,6 @@ VARIANT_ENUM_CAST(_OS::VideoDriver);
VARIANT_ENUM_CAST(_OS::Weekday);
VARIANT_ENUM_CAST(_OS::Month);
VARIANT_ENUM_CAST(_OS::SystemDir);
-VARIANT_ENUM_CAST(_OS::ScreenOrientation);
class _Geometry : public Object {
@@ -572,7 +458,7 @@ public:
int get_current_drive();
Error change_dir(String p_dir); // Can be relative or absolute, return false on success.
- String get_current_dir(bool p_include_drive = true); // Return current dir location.
+ String get_current_dir(); // Return current dir location.
Error make_dir(String p_dir);
Error make_dir_recursive(String p_dir);
@@ -616,7 +502,7 @@ public:
String base64_to_utf8(const String &p_str);
_Marshalls() { singleton = this; }
- ~_Marshalls() { singleton = NULL; }
+ ~_Marshalls() { singleton = nullptr; }
};
class _Mutex : public Reference {
diff --git a/core/callable.cpp b/core/callable.cpp
index 4a5ae3a248..6a5dc151e5 100644
--- a/core/callable.cpp
+++ b/core/callable.cpp
@@ -78,6 +78,12 @@ StringName Callable::get_method() const {
return method;
}
+CallableCustom *Callable::get_custom() const {
+ ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
+ vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
+ return custom;
+}
+
uint32_t Callable::hash() const {
if (is_custom()) {
return custom->hash();
diff --git a/core/callable.h b/core/callable.h
index cecf2264a3..7fa024dccd 100644
--- a/core/callable.h
+++ b/core/callable.h
@@ -84,6 +84,7 @@ public:
Object *get_object() const;
ObjectID get_object_id() const;
StringName get_method() const;
+ CallableCustom *get_custom() const;
uint32_t hash() const;
diff --git a/core/callable_method_pointer.h b/core/callable_method_pointer.h
index a931a344e6..fb809c2b44 100644
--- a/core/callable_method_pointer.h
+++ b/core/callable_method_pointer.h
@@ -34,6 +34,7 @@
#include "core/callable.h"
#include "core/hashfuncs.h"
#include "core/object.h"
+#include "core/os/copymem.h"
#include "core/simple_type.h"
class CallableCustomMethodPointerBase : public CallableCustom {
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 35e216a58f..5e49688e9b 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -261,8 +261,9 @@ HashMap<StringName, StringName> ClassDB::compat_classes;
ClassDB::ClassInfo::ClassInfo() {
api = API_NONE;
- creation_func = NULL;
- inherits_ptr = NULL;
+ class_ptr = nullptr;
+ creation_func = nullptr;
+ inherits_ptr = nullptr;
disabled = false;
exposed = false;
}
@@ -289,7 +290,7 @@ void ClassDB::get_class_list(List<StringName> *p_classes) {
OBJTYPE_RLOCK;
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = classes.next(k))) {
@@ -303,7 +304,7 @@ void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringNa
OBJTYPE_RLOCK;
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = classes.next(k))) {
@@ -316,7 +317,7 @@ void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<S
OBJTYPE_RLOCK;
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = classes.next(k))) {
@@ -376,7 +377,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
List<StringName> names;
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = classes.next(k))) {
@@ -398,7 +399,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->method_map.next(k))) {
@@ -445,7 +446,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->constant_map.next(k))) {
@@ -465,7 +466,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->signal_map.next(k))) {
@@ -488,7 +489,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->property_setget.next(k))) {
@@ -548,14 +549,14 @@ Object *ClassDB::instance(const StringName &p_class) {
ti = classes.getptr(compat_classes[p_class]);
}
}
- ERR_FAIL_COND_V_MSG(!ti, NULL, "Cannot get class '" + String(p_class) + "'.");
- ERR_FAIL_COND_V_MSG(ti->disabled, NULL, "Class '" + String(p_class) + "' is disabled.");
- ERR_FAIL_COND_V(!ti->creation_func, NULL);
+ ERR_FAIL_COND_V_MSG(!ti, nullptr, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, "Class '" + String(p_class) + "' is disabled.");
+ ERR_FAIL_COND_V(!ti->creation_func, nullptr);
}
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
ERR_PRINT("Class '" + String(p_class) + "' can only be instantiated by editor.");
- return NULL;
+ return nullptr;
}
#endif
return ti->creation_func();
@@ -571,7 +572,7 @@ bool ClassDB::can_instance(const StringName &p_class) {
return false;
}
#endif
- return (!ti->disabled && ti->creation_func != NULL);
+ return (!ti->disabled && ti->creation_func != nullptr);
}
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
@@ -594,7 +595,7 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit
ti.inherits_ptr = &classes[ti.inherits];
} else {
- ti.inherits_ptr = NULL;
+ ti.inherits_ptr = nullptr;
}
}
@@ -652,7 +653,7 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b
#else
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = type->method_map.next(K))) {
@@ -684,7 +685,7 @@ MethodBind *ClassDB::get_method(StringName p_class, StringName p_name) {
return *method;
type = type->inherits_ptr;
}
- return NULL;
+ return nullptr;
}
void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant) {
@@ -736,7 +737,7 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List<String>
for (List<StringName>::Element *E = type->constant_order.front(); E; E = E->next())
p_constants->push_back(E->get());
#else
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = type->constant_map.next(K))) {
p_constants->push_back(*K);
@@ -783,7 +784,7 @@ StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const S
while (type) {
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = type->enum_map.next(k))) {
List<StringName> &constants_list = type->enum_map.get(*k);
@@ -809,7 +810,7 @@ void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums
while (type) {
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = type->enum_map.next(k))) {
p_enums->push_back(*k);
}
@@ -875,7 +876,7 @@ void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, b
while (check) {
- const StringName *S = NULL;
+ const StringName *S = nullptr;
while ((S = check->signal_map.next(S))) {
p_signals->push_back(check->signal_map[*S]);
@@ -929,6 +930,15 @@ void ClassDB::add_property_group(StringName p_class, const String &p_name, const
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
}
+void ClassDB::add_property_subgroup(StringName p_class, const String &p_name, const String &p_prefix) {
+
+ OBJTYPE_WLOCK;
+ ClassInfo *type = classes.getptr(p_class);
+ ERR_FAIL_COND(!type);
+
+ type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP));
+}
+
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
lock->read_lock();
@@ -937,7 +947,7 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons
ERR_FAIL_COND(!type);
- MethodBind *mb_set = NULL;
+ MethodBind *mb_set = nullptr;
if (p_setter) {
mb_set = get_method(p_class, p_setter);
#ifdef DEBUG_METHODS_ENABLED
@@ -949,7 +959,7 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons
#endif
}
- MethodBind *mb_get = NULL;
+ MethodBind *mb_get = nullptr;
if (p_getter) {
mb_get = get_method(p_class, p_getter);
@@ -1086,9 +1096,9 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia
Callable::CallError ce;
if (psg->_getptr) {
- r_value = psg->_getptr->call(p_object, NULL, 0, ce);
+ r_value = psg->_getptr->call(p_object, nullptr, 0, ce);
} else {
- r_value = p_object->call(psg->getter, NULL, 0, ce);
+ r_value = p_object->call(psg->getter, nullptr, 0, ce);
}
}
return true;
@@ -1245,33 +1255,33 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
#endif
OBJTYPE_WLOCK;
- ERR_FAIL_COND_V(!p_bind, NULL);
+ ERR_FAIL_COND_V(!p_bind, nullptr);
p_bind->set_name(mdname);
String instance_type = p_bind->get_instance_class();
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), NULL, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
+ ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), nullptr, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
#endif
ClassInfo *type = classes.getptr(instance_type);
if (!type) {
memdelete(p_bind);
- ERR_FAIL_V_MSG(NULL, "Couldn't bind method '" + mdname + "' for instance '" + instance_type + "'.");
+ ERR_FAIL_V_MSG(nullptr, "Couldn't bind method '" + mdname + "' for instance '" + instance_type + "'.");
}
if (type->method_map.has(mdname)) {
memdelete(p_bind);
// overloading not supported
- ERR_FAIL_V_MSG(NULL, "Method already bound '" + instance_type + "::" + mdname + "'.");
+ ERR_FAIL_V_MSG(nullptr, "Method already bound '" + instance_type + "::" + mdname + "'.");
}
#ifdef DEBUG_METHODS_ENABLED
if (method_name.args.size() > p_bind->get_argument_count()) {
memdelete(p_bind);
- ERR_FAIL_V_MSG(NULL, "Method definition provides more arguments than the method actually has '" + instance_type + "::" + mdname + "'.");
+ ERR_FAIL_V_MSG(nullptr, "Method definition provides more arguments than the method actually has '" + instance_type + "::" + mdname + "'.");
}
p_bind->set_argument_names(method_name.args);
@@ -1382,7 +1392,7 @@ void ClassDB::add_resource_base_extension(const StringName &p_extension, const S
void ClassDB::get_resource_base_extensions(List<String> *p_extensions) {
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = resource_base_extensions.next(K))) {
@@ -1392,7 +1402,7 @@ void ClassDB::get_resource_base_extensions(List<String> *p_extensions) {
void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p_extensions) {
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = resource_base_extensions.next(K))) {
StringName cmp = resource_base_extensions[*K];
@@ -1401,7 +1411,7 @@ void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p
}
}
-HashMap<StringName, HashMap<StringName, Variant> > ClassDB::default_values;
+HashMap<StringName, HashMap<StringName, Variant>> ClassDB::default_values;
Set<StringName> ClassDB::default_values_cached;
Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid) {
@@ -1412,7 +1422,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
default_values[p_class] = HashMap<StringName, Variant>();
}
- Object *c = NULL;
+ Object *c = nullptr;
bool cleanup_c = false;
if (Engine::get_singleton()->has_singleton(p_class)) {
@@ -1446,20 +1456,20 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
}
if (!default_values.has(p_class)) {
- if (r_valid != NULL) *r_valid = false;
+ if (r_valid != nullptr) *r_valid = false;
return Variant();
}
if (!default_values[p_class].has(p_property)) {
- if (r_valid != NULL) *r_valid = false;
+ if (r_valid != nullptr) *r_valid = false;
return Variant();
}
- if (r_valid != NULL) *r_valid = true;
+ if (r_valid != nullptr) *r_valid = true;
return default_values[p_class][p_property];
}
-RWLock *ClassDB::lock = NULL;
+RWLock *ClassDB::lock = nullptr;
void ClassDB::init() {
@@ -1476,13 +1486,13 @@ void ClassDB::cleanup() {
//OBJTYPE_LOCK; hah not here
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = classes.next(k))) {
ClassInfo &ti = classes[*k];
- const StringName *m = NULL;
+ const StringName *m = nullptr;
while ((m = ti.method_map.next(m))) {
memdelete(ti.method_map[*m]);
diff --git a/core/class_db.h b/core/class_db.h
index 398eca9132..f760aa1738 100644
--- a/core/class_db.h
+++ b/core/class_db.h
@@ -119,7 +119,7 @@ public:
void *class_ptr;
HashMap<StringName, MethodBind *> method_map;
HashMap<StringName, int> constant_map;
- HashMap<StringName, List<StringName> > enum_map;
+ HashMap<StringName, List<StringName>> enum_map;
HashMap<StringName, MethodInfo> signal_map;
List<PropertyInfo> property_list;
#ifdef DEBUG_METHODS_ENABLED
@@ -160,7 +160,7 @@ public:
static void _add_class2(const StringName &p_class, const StringName &p_inherits);
- static HashMap<StringName, HashMap<StringName, Variant> > default_values;
+ static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static Set<StringName> default_values_cached;
public:
@@ -234,7 +234,7 @@ public:
MethodBind *bind = create_method_bind(p_method);
- return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, NULL, 0); //use static function, much smaller binary usage
+ return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, nullptr, 0); //use static function, much smaller binary usage
}
template <class N, class M>
@@ -315,7 +315,7 @@ public:
GLOBAL_LOCK_FUNCTION;
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
- ERR_FAIL_COND_V(!bind, NULL);
+ ERR_FAIL_COND_V(!bind, nullptr);
bind->set_name(p_name);
bind->set_default_arguments(p_default_args);
@@ -325,13 +325,13 @@ public:
ClassInfo *type = classes.getptr(instance_type);
if (!type) {
memdelete(bind);
- ERR_FAIL_COND_V(!type, NULL);
+ ERR_FAIL_COND_V(!type, nullptr);
}
if (type->method_map.has(p_name)) {
memdelete(bind);
// overloading not supported
- ERR_FAIL_V_MSG(NULL, "Method already bound: " + instance_type + "::" + p_name + ".");
+ ERR_FAIL_V_MSG(nullptr, "Method already bound: " + instance_type + "::" + p_name + ".");
}
type->method_map[p_name] = bind;
#ifdef DEBUG_METHODS_ENABLED
@@ -349,14 +349,15 @@ public:
static void get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false);
static void add_property_group(StringName p_class, const String &p_name, const String &p_prefix = "");
+ static void add_property_subgroup(StringName p_class, const String &p_name, const String &p_prefix = "");
static void add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
static void set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default);
- static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = NULL);
- static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = NULL);
+ static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr);
static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value);
static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false);
- static int get_property_index(const StringName &p_class, const StringName &p_property, bool *r_is_valid = NULL);
- static Variant::Type get_property_type(const StringName &p_class, const StringName &p_property, bool *r_is_valid = NULL);
+ static int get_property_index(const StringName &p_class, const StringName &p_property, bool *r_is_valid = nullptr);
+ static Variant::Type get_property_type(const StringName &p_class, const StringName &p_property, bool *r_is_valid = nullptr);
static StringName get_property_setter(StringName p_class, const StringName &p_property);
static StringName get_property_getter(StringName p_class, const StringName &p_property);
@@ -371,13 +372,13 @@ public:
static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant);
static void get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance = false);
- static int get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = NULL);
+ static int get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = nullptr);
static StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false);
static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false);
- static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = NULL);
+ static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr);
static StringName get_category(const StringName &p_node);
diff --git a/core/color.h b/core/color.h
index a7ab94ab08..16dc721072 100644
--- a/core/color.h
+++ b/core/color.h
@@ -239,4 +239,4 @@ bool Color::operator<(const Color &p_color) const {
return r < p_color.r;
}
-#endif
+#endif // COLOR_H
diff --git a/core/command_queue_mt.cpp b/core/command_queue_mt.cpp
index 85e8a847a0..3ce769c72c 100644
--- a/core/command_queue_mt.cpp
+++ b/core/command_queue_mt.cpp
@@ -113,7 +113,7 @@ CommandQueueMT::CommandQueueMT(bool p_sync) {
if (p_sync)
sync = memnew(Semaphore);
else
- sync = NULL;
+ sync = nullptr;
}
CommandQueueMT::~CommandQueueMT() {
diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h
index 90231546ef..558453bdf5 100644
--- a/core/command_queue_mt.h
+++ b/core/command_queue_mt.h
@@ -360,7 +360,7 @@ class CommandQueueMT {
if (dealloc_one()) {
goto tryagain;
}
- return NULL;
+ return nullptr;
}
} else {
// ahead of dealloc_ptr, check that there is room
@@ -374,11 +374,11 @@ class CommandQueueMT {
if (dealloc_one()) {
goto tryagain;
}
- return NULL;
+ return nullptr;
}
// if this happens, it's a bug
- ERR_FAIL_COND_V((COMMAND_MEM_SIZE - write_ptr) < 8, NULL);
+ ERR_FAIL_COND_V((COMMAND_MEM_SIZE - write_ptr) < 8, nullptr);
// zero means, wrap to beginning
uint32_t *p = (uint32_t *)&command_mem[write_ptr];
@@ -406,7 +406,7 @@ class CommandQueueMT {
lock();
T *ret;
- while ((ret = allocate<T>()) == NULL) {
+ while ((ret = allocate<T>()) == nullptr) {
unlock();
// sleep a little until fetch happened and some room is made
@@ -508,4 +508,4 @@ public:
#undef CMD_SYNC_TYPE
#undef DECL_CMD_SYNC
-#endif
+#endif // COMMAND_QUEUE_MT_H
diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp
index ed307fd3ac..0225524bc8 100644
--- a/core/compressed_translation.cpp
+++ b/core/compressed_translation.cpp
@@ -50,8 +50,8 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
int size = Math::larger_prime(keys.size());
- Vector<Vector<Pair<int, CharString> > > buckets;
- Vector<Map<uint32_t, int> > table;
+ Vector<Vector<Pair<int, CharString>>> buckets;
+ Vector<Map<uint32_t, int>> table;
Vector<uint32_t> hfunc_table;
Vector<_PHashTranslationCmp> compressed;
@@ -109,7 +109,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
for (int i = 0; i < size; i++) {
- const Vector<Pair<int, CharString> > &b = buckets[i];
+ const Vector<Pair<int, CharString>> &b = buckets[i];
Map<uint32_t, int> &t = table.write[i];
if (b.size() == 0)
diff --git a/core/core_builders.py b/core/core_builders.py
index 7720183595..d03874608e 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -4,54 +4,83 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
"""
from platform_methods import subprocess_main
-from compat import iteritems, itervalues, open_utf8, escape_string, byte_to_str
-def make_certs_header(target, source, env):
+def escape_string(s):
+ def charcode_to_c_escapes(c):
+ rev_result = []
+ while c >= 256:
+ c, low = (c // 256, c % 256)
+ rev_result.append("\\%03o" % low)
+ rev_result.append("\\%03o" % c)
+ return "".join(reversed(rev_result))
+
+ result = ""
+ if isinstance(s, str):
+ s = s.encode("utf-8")
+ for c in s:
+ if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
+ result += charcode_to_c_escapes(c)
+ else:
+ result += chr(c)
+ return result
+
+def make_certs_header(target, source, env):
src = source[0]
dst = target[0]
f = open(src, "rb")
- g = open_utf8(dst, "w")
+ g = open(dst, "w", encoding="utf-8")
buf = f.read()
decomp_size = len(buf)
import zlib
+
buf = zlib.compress(buf)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- g.write("#ifndef _CERTS_RAW_H\n")
- g.write("#define _CERTS_RAW_H\n")
+ g.write("#ifndef CERTS_COMPRESSED_GEN_H\n")
+ g.write("#define CERTS_COMPRESSED_GEN_H\n")
# System certs path. Editor will use them if defined. (for package maintainers)
- path = env['system_certs_path']
- g.write("#define _SYSTEM_CERTS_PATH \"%s\"\n" % str(path))
- if env['builtin_certs']:
+ path = env["system_certs_path"]
+ g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path))
+ if env["builtin_certs"]:
# Defined here and not in env so changing it does not trigger a full rebuild.
g.write("#define BUILTIN_CERTS_ENABLED\n")
g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const unsigned char _certs_compressed[] = {\n")
for i in range(len(buf)):
- g.write("\t" + byte_to_str(buf[i]) + ",\n")
+ g.write("\t" + str(buf[i]) + ",\n")
g.write("};\n")
- g.write("#endif")
+ g.write("#endif // CERTS_COMPRESSED_GEN_H")
g.close()
f.close()
def make_authors_header(target, source, env):
- sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"]
- sections_id = ["AUTHORS_FOUNDERS", "AUTHORS_LEAD_DEVELOPERS", "AUTHORS_PROJECT_MANAGERS", "AUTHORS_DEVELOPERS"]
+ sections = [
+ "Project Founders",
+ "Lead Developer",
+ "Project Manager",
+ "Developers",
+ ]
+ sections_id = [
+ "AUTHORS_FOUNDERS",
+ "AUTHORS_LEAD_DEVELOPERS",
+ "AUTHORS_PROJECT_MANAGERS",
+ "AUTHORS_DEVELOPERS",
+ ]
src = source[0]
dst = target[0]
- f = open_utf8(src, "r")
- g = open_utf8(dst, "w")
+ f = open(src, "r", encoding="utf-8")
+ g = open(dst, "w", encoding="utf-8")
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- g.write("#ifndef _EDITOR_AUTHORS_H\n")
- g.write("#define _EDITOR_AUTHORS_H\n")
+ g.write("#ifndef AUTHORS_GEN_H\n")
+ g.write("#define AUTHORS_GEN_H\n")
reading = False
@@ -62,7 +91,7 @@ def make_authors_header(target, source, env):
for line in f:
if reading:
if line.startswith(" "):
- g.write("\t\"" + escape_string(line.strip()) + "\",\n")
+ g.write('\t"' + escape_string(line.strip()) + '",\n')
continue
if line.startswith("## "):
if reading:
@@ -78,26 +107,38 @@ def make_authors_header(target, source, env):
if reading:
close_section()
- g.write("#endif\n")
+ g.write("#endif // AUTHORS_GEN_H\n")
g.close()
f.close()
def make_donors_header(target, source, env):
- sections = ["Platinum sponsors", "Gold sponsors", "Mini sponsors",
- "Gold donors", "Silver donors", "Bronze donors"]
- sections_id = ["DONORS_SPONSOR_PLAT", "DONORS_SPONSOR_GOLD", "DONORS_SPONSOR_MINI",
- "DONORS_GOLD", "DONORS_SILVER", "DONORS_BRONZE"]
+ sections = [
+ "Platinum sponsors",
+ "Gold sponsors",
+ "Mini sponsors",
+ "Gold donors",
+ "Silver donors",
+ "Bronze donors",
+ ]
+ sections_id = [
+ "DONORS_SPONSOR_PLAT",
+ "DONORS_SPONSOR_GOLD",
+ "DONORS_SPONSOR_MINI",
+ "DONORS_GOLD",
+ "DONORS_SILVER",
+ "DONORS_BRONZE",
+ ]
src = source[0]
dst = target[0]
- f = open_utf8(src, "r")
- g = open_utf8(dst, "w")
+ f = open(src, "r", encoding="utf-8")
+ g = open(dst, "w", encoding="utf-8")
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- g.write("#ifndef _EDITOR_DONORS_H\n")
- g.write("#define _EDITOR_DONORS_H\n")
+ g.write("#ifndef DONORS_GEN_H\n")
+ g.write("#define DONORS_GEN_H\n")
reading = False
@@ -108,7 +149,7 @@ def make_donors_header(target, source, env):
for line in f:
if reading >= 0:
if line.startswith(" "):
- g.write("\t\"" + escape_string(line.strip()) + "\",\n")
+ g.write('\t"' + escape_string(line.strip()) + '",\n')
continue
if line.startswith("## "):
if reading:
@@ -124,7 +165,7 @@ def make_donors_header(target, source, env):
if reading:
close_section()
- g.write("#endif\n")
+ g.write("#endif // DONORS_GEN_H\n")
g.close()
f.close()
@@ -151,8 +192,8 @@ def make_license_header(target, source, env):
return line
def next_tag(self):
- if not ':' in self.current:
- return ('', [])
+ if not ":" in self.current:
+ return ("", [])
tag, line = self.current.split(":", 1)
lines = [line.strip()]
while self.next_line() and self.current.startswith(" "):
@@ -160,10 +201,11 @@ def make_license_header(target, source, env):
return (tag, lines)
from collections import OrderedDict
+
projects = OrderedDict()
license_list = []
- with open_utf8(src_copyright, "r") as copyright_file:
+ with open(src_copyright, "r", encoding="utf-8") as copyright_file:
reader = LicenseReader(copyright_file)
part = {}
while reader.current:
@@ -183,87 +225,108 @@ def make_license_header(target, source, env):
reader.next_line()
data_list = []
- for project in itervalues(projects):
+ for project in iter(projects.values()):
for part in project:
part["file_index"] = len(data_list)
data_list += part["Files"]
part["copyright_index"] = len(data_list)
data_list += part["Copyright"]
- with open_utf8(dst, "w") as f:
+ with open(dst, "w", encoding="utf-8") as f:
f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- f.write("#ifndef _EDITOR_LICENSE_H\n")
- f.write("#define _EDITOR_LICENSE_H\n")
+ f.write("#ifndef LICENSE_GEN_H\n")
+ f.write("#define LICENSE_GEN_H\n")
f.write("const char *const GODOT_LICENSE_TEXT =")
- with open_utf8(src_license, "r") as license_file:
+ with open(src_license, "r", encoding="utf-8") as license_file:
for line in license_file:
escaped_string = escape_string(line.strip())
- f.write("\n\t\t\"" + escaped_string + "\\n\"")
+ f.write('\n\t\t"' + escaped_string + '\\n"')
f.write(";\n\n")
- f.write("struct ComponentCopyrightPart {\n"
- "\tconst char *license;\n"
- "\tconst char *const *files;\n"
- "\tconst char *const *copyright_statements;\n"
- "\tint file_count;\n"
- "\tint copyright_count;\n"
- "};\n\n")
-
- f.write("struct ComponentCopyright {\n"
- "\tconst char *name;\n"
- "\tconst ComponentCopyrightPart *parts;\n"
- "\tint part_count;\n"
- "};\n\n")
+ f.write(
+ "struct ComponentCopyrightPart {\n"
+ "\tconst char *license;\n"
+ "\tconst char *const *files;\n"
+ "\tconst char *const *copyright_statements;\n"
+ "\tint file_count;\n"
+ "\tint copyright_count;\n"
+ "};\n\n"
+ )
+
+ f.write(
+ "struct ComponentCopyright {\n"
+ "\tconst char *name;\n"
+ "\tconst ComponentCopyrightPart *parts;\n"
+ "\tint part_count;\n"
+ "};\n\n"
+ )
f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n")
for line in data_list:
- f.write("\t\"" + escape_string(line) + "\",\n")
+ f.write('\t"' + escape_string(line) + '",\n')
f.write("};\n\n")
f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
part_index = 0
part_indexes = {}
- for project_name, project in iteritems(projects):
+ for project_name, project in iter(projects.items()):
part_indexes[project_name] = part_index
for part in project:
- f.write("\t{ \"" + escape_string(part["License"][0]) + "\", "
- + "&COPYRIGHT_INFO_DATA[" + str(part["file_index"]) + "], "
- + "&COPYRIGHT_INFO_DATA[" + str(part["copyright_index"]) + "], "
- + str(len(part["Files"])) + ", "
- + str(len(part["Copyright"])) + " },\n")
+ f.write(
+ '\t{ "'
+ + escape_string(part["License"][0])
+ + '", '
+ + "&COPYRIGHT_INFO_DATA["
+ + str(part["file_index"])
+ + "], "
+ + "&COPYRIGHT_INFO_DATA["
+ + str(part["copyright_index"])
+ + "], "
+ + str(len(part["Files"]))
+ + ", "
+ + str(len(part["Copyright"]))
+ + " },\n"
+ )
part_index += 1
f.write("};\n\n")
f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n")
f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n")
- for project_name, project in iteritems(projects):
- f.write("\t{ \"" + escape_string(project_name) + "\", "
- + "&COPYRIGHT_PROJECT_PARTS[" + str(part_indexes[project_name]) + "], "
- + str(len(project)) + " },\n")
+ for project_name, project in iter(projects.items()):
+ f.write(
+ '\t{ "'
+ + escape_string(project_name)
+ + '", '
+ + "&COPYRIGHT_PROJECT_PARTS["
+ + str(part_indexes[project_name])
+ + "], "
+ + str(len(project))
+ + " },\n"
+ )
f.write("};\n\n")
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
f.write("const char *const LICENSE_NAMES[] = {\n")
for l in license_list:
- f.write("\t\"" + escape_string(l[0]) + "\",\n")
+ f.write('\t"' + escape_string(l[0]) + '",\n')
f.write("};\n\n")
f.write("const char *const LICENSE_BODIES[] = {\n\n")
for l in license_list:
for line in l[1:]:
if line == ".":
- f.write("\t\"\\n\"\n")
+ f.write('\t"\\n"\n')
else:
- f.write("\t\"" + escape_string(line) + "\\n\"\n")
- f.write("\t\"\",\n\n")
+ f.write('\t"' + escape_string(line) + '\\n"\n')
+ f.write('\t"",\n\n')
f.write("};\n\n")
- f.write("#endif\n")
+ f.write("#endif // LICENSE_GEN_H\n")
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 253d5f1acb..1d3b333efc 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -30,7 +30,7 @@
#include "core_string_names.h"
-CoreStringNames *CoreStringNames::singleton = NULL;
+CoreStringNames *CoreStringNames::singleton = nullptr;
CoreStringNames::CoreStringNames() :
_free(StaticCString::create("free")),
diff --git a/core/core_string_names.h b/core/core_string_names.h
index 42416d3f75..2ade44f4e0 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -41,7 +41,7 @@ class CoreStringNames {
static void create() { singleton = memnew(CoreStringNames); }
static void free() {
memdelete(singleton);
- singleton = NULL;
+ singleton = nullptr;
}
CoreStringNames();
@@ -97,4 +97,4 @@ public:
StringName notification;
};
-#endif // SCENE_STRING_NAMES_H
+#endif // CORE_STRING_NAMES_H
diff --git a/core/cowdata.h b/core/cowdata.h
index 4fdcaf3cea..975a572906 100644
--- a/core/cowdata.h
+++ b/core/cowdata.h
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COWDATA_H_
-#define COWDATA_H_
-
-#include <string.h>
+#ifndef COWDATA_H
+#define COWDATA_H
#include "core/error_macros.h"
#include "core/os/memory.h"
#include "core/safe_refcount.h"
+#include <string.h>
+
template <class T>
class Vector;
class String;
@@ -61,7 +61,7 @@ private:
_FORCE_INLINE_ uint32_t *_get_refcount() const {
if (!_ptr)
- return NULL;
+ return nullptr;
return reinterpret_cast<uint32_t *>(_ptr) - 2;
}
@@ -69,7 +69,7 @@ private:
_FORCE_INLINE_ uint32_t *_get_size() const {
if (!_ptr)
- return NULL;
+ return nullptr;
return reinterpret_cast<uint32_t *>(_ptr) - 1;
}
@@ -77,29 +77,30 @@ private:
_FORCE_INLINE_ T *_get_data() const {
if (!_ptr)
- return NULL;
+ return nullptr;
return reinterpret_cast<T *>(_ptr);
}
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
- //return nearest_power_of_2_templated(p_elements*sizeof(T)+sizeof(SafeRefCount)+sizeof(int));
return next_power_of_2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
-#if defined(_add_overflow) && defined(_mul_overflow)
+#if defined(__GNUC__)
size_t o;
size_t p;
- if (_mul_overflow(p_elements, sizeof(T), &o)) {
+ if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
*out = 0;
return false;
}
*out = next_power_of_2(o);
- if (_add_overflow(o, static_cast<size_t>(32), &p)) return false; //no longer allocated here
+ if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
+ return false; // No longer allocated here.
+ }
return true;
#else
// Speed is more important than correctness here, do the operations unchecked
- // and hope the best
+ // and hope for the best.
*out = _get_alloc_size(p_elements);
return true;
#endif
@@ -252,37 +253,42 @@ Error CowData<T>::resize(int p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
- if (p_size == size())
+ int current_size = size();
+
+ if (p_size == current_size)
return OK;
if (p_size == 0) {
// wants to clean up
_unref(_ptr);
- _ptr = NULL;
+ _ptr = nullptr;
return OK;
}
// possibly changing size, copy on write
_copy_on_write();
+ size_t current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size;
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
- if (p_size > size()) {
+ if (p_size > current_size) {
- if (size() == 0) {
- // alloc from scratch
- uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
- ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
- *(ptr - 1) = 0; //size, currently none
- *(ptr - 2) = 1; //refcount
+ if (alloc_size != current_alloc_size) {
+ if (current_size == 0) {
+ // alloc from scratch
+ uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
+ ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
+ *(ptr - 1) = 0; //size, currently none
+ *(ptr - 2) = 1; //refcount
- _ptr = (T *)ptr;
+ _ptr = (T *)ptr;
- } else {
- void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
- ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
- _ptr = (T *)(_ptrnew);
+ } else {
+ void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+ ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ _ptr = (T *)(_ptrnew);
+ }
}
// construct the newly created elements
@@ -297,7 +303,7 @@ Error CowData<T>::resize(int p_size) {
*_get_size() = p_size;
- } else if (p_size < size()) {
+ } else if (p_size < current_size) {
if (!__has_trivial_destructor(T)) {
// deinitialize no longer needed elements
@@ -307,10 +313,12 @@ Error CowData<T>::resize(int p_size) {
}
}
- void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
- ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ if (alloc_size != current_alloc_size) {
+ void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+ ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
- _ptr = (T *)(_ptrnew);
+ _ptr = (T *)(_ptrnew);
+ }
*_get_size() = p_size;
}
@@ -348,7 +356,7 @@ void CowData<T>::_ref(const CowData &p_from) {
return; // self assign, do nothing.
_unref(_ptr);
- _ptr = NULL;
+ _ptr = nullptr;
if (!p_from._ptr)
return; //nothing to do
@@ -361,7 +369,7 @@ void CowData<T>::_ref(const CowData &p_from) {
template <class T>
CowData<T>::CowData() {
- _ptr = NULL;
+ _ptr = nullptr;
}
template <class T>
@@ -370,4 +378,4 @@ CowData<T>::~CowData() {
_unref(_ptr);
}
-#endif /* COW_H_ */
+#endif // COWDATA_H
diff --git a/core/crypto/SCsub b/core/crypto/SCsub
index 0a3f05d87a..da4a9c9381 100644
--- a/core/crypto/SCsub
+++ b/core/crypto/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env_crypto = env.Clone()
@@ -22,7 +22,9 @@ if not has_module:
env_thirdparty = env_crypto.Clone()
env_thirdparty.disable_warnings()
# Custom config file
- env_thirdparty.Append(CPPDEFINES=[('MBEDTLS_CONFIG_FILE', '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')])
+ env_thirdparty.Append(
+ CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_core_mbedtls_config.h\\"')]
+ )
thirdparty_mbedtls_dir = "#thirdparty/mbedtls/library/"
thirdparty_mbedtls_sources = [
"aes.c",
@@ -30,7 +32,7 @@ if not has_module:
"md5.c",
"sha1.c",
"sha256.c",
- "godot_core_mbedtls_platform.c"
+ "godot_core_mbedtls_platform.c",
]
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
env_thirdparty.add_source_files(env.core_sources, thirdparty_mbedtls_sources)
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 793bf719b7..ab8548e3ba 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -36,11 +36,11 @@
/// Resources
-CryptoKey *(*CryptoKey::_create)() = NULL;
+CryptoKey *(*CryptoKey::_create)() = nullptr;
CryptoKey *CryptoKey::create() {
if (_create)
return _create();
- return NULL;
+ return nullptr;
}
void CryptoKey::_bind_methods() {
@@ -48,11 +48,11 @@ void CryptoKey::_bind_methods() {
ClassDB::bind_method(D_METHOD("load", "path"), &CryptoKey::load);
}
-X509Certificate *(*X509Certificate::_create)() = NULL;
+X509Certificate *(*X509Certificate::_create)() = nullptr;
X509Certificate *X509Certificate::create() {
if (_create)
return _create();
- return NULL;
+ return nullptr;
}
void X509Certificate::_bind_methods() {
@@ -62,8 +62,8 @@ void X509Certificate::_bind_methods() {
/// Crypto
-void (*Crypto::_load_default_certificates)(String p_path) = NULL;
-Crypto *(*Crypto::_create)() = NULL;
+void (*Crypto::_load_default_certificates)(String p_path) = nullptr;
+Crypto *(*Crypto::_create)() = nullptr;
Crypto *Crypto::create() {
if (_create)
return _create();
@@ -87,11 +87,11 @@ PackedByteArray Crypto::generate_random_bytes(int p_bytes) {
}
Ref<CryptoKey> Crypto::generate_rsa(int p_bytes) {
- ERR_FAIL_V_MSG(NULL, "generate_rsa is not available when mbedtls module is disabled.");
+ ERR_FAIL_V_MSG(nullptr, "generate_rsa is not available when mbedtls module is disabled.");
}
Ref<X509Certificate> Crypto::generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after) {
- ERR_FAIL_V_MSG(NULL, "generate_self_signed_certificate is not available when mbedtls module is disabled.");
+ ERR_FAIL_V_MSG(nullptr, "generate_self_signed_certificate is not available when mbedtls module is disabled.");
}
Crypto::Crypto() {
@@ -113,7 +113,7 @@ RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_origi
key->load(p_path);
return key;
}
- return NULL;
+ return nullptr;
}
void ResourceFormatLoaderCrypto::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 3279c0620f..e515367de5 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -87,7 +87,7 @@ class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
GDCLASS(ResourceFormatLoaderCrypto, ResourceFormatLoader);
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/crypto/hashing_context.cpp b/core/crypto/hashing_context.cpp
index a4d8a93c8a..af43bc9bad 100644
--- a/core/crypto/hashing_context.cpp
+++ b/core/crypto/hashing_context.cpp
@@ -33,9 +33,9 @@
#include "core/crypto/crypto_core.h"
Error HashingContext::start(HashType p_type) {
- ERR_FAIL_COND_V(ctx != NULL, ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
_create_ctx(p_type);
- ERR_FAIL_COND_V(ctx == NULL, ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(ctx == nullptr, ERR_UNAVAILABLE);
switch (type) {
case HASH_MD5:
return ((CryptoCore::MD5Context *)ctx)->start();
@@ -48,7 +48,7 @@ Error HashingContext::start(HashType p_type) {
}
Error HashingContext::update(PackedByteArray p_chunk) {
- ERR_FAIL_COND_V(ctx == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(ctx == nullptr, ERR_UNCONFIGURED);
size_t len = p_chunk.size();
ERR_FAIL_COND_V(len == 0, FAILED);
const uint8_t *r = p_chunk.ptr();
@@ -64,7 +64,7 @@ Error HashingContext::update(PackedByteArray p_chunk) {
}
PackedByteArray HashingContext::finish() {
- ERR_FAIL_COND_V(ctx == NULL, PackedByteArray());
+ ERR_FAIL_COND_V(ctx == nullptr, PackedByteArray());
PackedByteArray out;
Error err = FAILED;
switch (type) {
@@ -99,7 +99,7 @@ void HashingContext::_create_ctx(HashType p_type) {
ctx = memnew(CryptoCore::SHA256Context);
break;
default:
- ctx = NULL;
+ ctx = nullptr;
}
}
@@ -116,7 +116,7 @@ void HashingContext::_delete_ctx() {
memdelete((CryptoCore::SHA256Context *)ctx);
break;
}
- ctx = NULL;
+ ctx = nullptr;
}
void HashingContext::_bind_methods() {
@@ -129,10 +129,10 @@ void HashingContext::_bind_methods() {
}
HashingContext::HashingContext() {
- ctx = NULL;
+ ctx = nullptr;
}
HashingContext::~HashingContext() {
- if (ctx != NULL)
+ if (ctx != nullptr)
_delete_ctx();
}
diff --git a/core/debugger/SCsub b/core/debugger/SCsub
index 1c5f954470..19a6549225 100644
--- a/core/debugger/SCsub
+++ b/core/debugger/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/debugger/debugger_marshalls.cpp b/core/debugger/debugger_marshalls.cpp
index eb3a19506a..410c55129d 100644
--- a/core/debugger/debugger_marshalls.cpp
+++ b/core/debugger/debugger_marshalls.cpp
@@ -227,7 +227,7 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
}
int len = 0;
- Error err = encode_variant(var, NULL, len, true);
+ Error err = encode_variant(var, nullptr, len, true);
if (err != OK)
ERR_PRINT("Failed to encode variant.");
@@ -317,7 +317,7 @@ bool DebuggerMarshalls::VisualProfilerFrame::deserialize(const Array &p_arr) {
CHECK_SIZE(p_arr, size, "VisualProfilerFrame");
int idx = 2;
areas.resize(size / 3);
- VS::FrameProfileArea *w = areas.ptrw();
+ RS::FrameProfileArea *w = areas.ptrw();
for (int i = 0; i < size / 3; i++) {
w[i].name = p_arr[idx];
w[i].cpu_msec = p_arr[idx + 1];
diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h
index 4c15adc555..04229c0afc 100644
--- a/core/debugger/debugger_marshalls.h
+++ b/core/debugger/debugger_marshalls.h
@@ -32,7 +32,7 @@
#define DEBUGGER_MARSHARLLS_H
#include "core/script_language.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
struct DebuggerMarshalls {
@@ -165,7 +165,7 @@ struct DebuggerMarshalls {
// Visual Profiler
struct VisualProfilerFrame {
uint64_t frame_number;
- Vector<VS::FrameProfileArea> areas;
+ Vector<RS::FrameProfileArea> areas;
Array serialize();
bool deserialize(const Array &p_arr);
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index c64d886800..bfe38d0f4a 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -35,8 +35,8 @@
#include "core/debugger/script_debugger.h"
#include "core/os/os.h"
-EngineDebugger *EngineDebugger::singleton = NULL;
-ScriptDebugger *EngineDebugger::script_debugger = NULL;
+EngineDebugger *EngineDebugger::singleton = nullptr;
+ScriptDebugger *EngineDebugger::script_debugger = nullptr;
Map<StringName, EngineDebugger::Profiler> EngineDebugger::profilers;
Map<StringName, EngineDebugger::Capture> EngineDebugger::captures;
@@ -173,7 +173,7 @@ void EngineDebugger::deinitialize() {
singleton->poll_events(false);
memdelete(singleton);
- singleton = NULL;
+ singleton = nullptr;
profilers.clear();
captures.clear();
}
@@ -181,6 +181,6 @@ void EngineDebugger::deinitialize() {
EngineDebugger::~EngineDebugger() {
if (script_debugger)
memdelete(script_debugger);
- script_debugger = NULL;
- singleton = NULL;
+ script_debugger = nullptr;
+ singleton = nullptr;
}
diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h
index 9e01aeba18..7b6b77ca9b 100644
--- a/core/debugger/engine_debugger.h
+++ b/core/debugger/engine_debugger.h
@@ -50,10 +50,10 @@ public:
class Profiler {
friend class EngineDebugger;
- ProfilingToggle toggle = NULL;
- ProfilingAdd add = NULL;
- ProfilingTick tick = NULL;
- void *data = NULL;
+ ProfilingToggle toggle = nullptr;
+ ProfilingAdd add = nullptr;
+ ProfilingTick tick = nullptr;
+ void *data = nullptr;
bool active = false;
public:
@@ -69,8 +69,8 @@ public:
class Capture {
friend class EngineDebugger;
- CaptureFunc capture = NULL;
- void *data = NULL;
+ CaptureFunc capture = nullptr;
+ void *data = nullptr;
public:
Capture() {}
@@ -97,7 +97,7 @@ protected:
public:
_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
- _FORCE_INLINE_ static bool is_active() { return singleton != NULL && script_debugger != NULL; }
+ _FORCE_INLINE_ static bool is_active() { return singleton != nullptr && script_debugger != nullptr; }
_FORCE_INLINE_ static ScriptDebugger *get_script_debugger() { return script_debugger; };
diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp
index 913d3fc031..6d88ceb2c1 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -262,14 +262,14 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
if (line.get_slice_count(" ") <= 1) {
- const Map<int, Set<StringName> > &breakpoints = script_debugger->get_breakpoints();
+ const Map<int, Set<StringName>> &breakpoints = script_debugger->get_breakpoints();
if (breakpoints.size() == 0) {
print_line("No Breakpoints.");
continue;
}
print_line("Breakpoint(s): " + itos(breakpoints.size()));
- for (Map<int, Set<StringName> >::Element *E = breakpoints.front(); E; E = E->next()) {
+ for (Map<int, Set<StringName>>::Element *E = breakpoints.front(); E; E = E->next()) {
print_line("\t" + String(E->value().front()->get()) + ":" + itos(E->key()));
}
@@ -402,7 +402,7 @@ LocalDebugger::LocalDebugger() {
[](void *p_user, bool p_enable, const Array &p_opts) {
((ScriptsProfiler *)p_user)->toggle(p_enable, p_opts);
},
- NULL,
+ nullptr,
[](void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) {
((ScriptsProfiler *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time);
});
diff --git a/core/debugger/local_debugger.h b/core/debugger/local_debugger.h
index e299df0546..2c4302f4da 100644
--- a/core/debugger/local_debugger.h
+++ b/core/debugger/local_debugger.h
@@ -40,7 +40,7 @@ class LocalDebugger : public EngineDebugger {
private:
struct ScriptsProfiler;
- ScriptsProfiler *scripts_profiler = NULL;
+ ScriptsProfiler *scripts_profiler = nullptr;
String target_function;
Map<String, String> options;
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 5f7ffb115c..e6bcc5f77e 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -33,11 +33,12 @@
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "core/script_language.h"
#include "scene/main/node.h"
+#include "servers/display_server.h"
template <typename T>
void RemoteDebugger::_bind_profiler(const String &p_name, T *p_prof) {
@@ -317,7 +318,7 @@ struct RemoteDebugger::ServersProfiler {
void _send_frame_data(bool p_final) {
DebuggerMarshalls::ServersProfilerFrame frame;
- frame.frame_number = Engine::get_singleton()->get_frames_drawn();
+ frame.frame_number = Engine::get_singleton()->get_idle_frames();
frame.frame_time = frame_time;
frame.idle_time = idle_time;
frame.physics_time = physics_time;
@@ -353,18 +354,18 @@ struct RemoteDebugger::VisualProfiler {
Map<StringName, ServerInfo> server_data;
void toggle(bool p_enable, const Array &p_opts) {
- VS::get_singleton()->set_frame_profiling_enabled(p_enable);
+ RS::get_singleton()->set_frame_profiling_enabled(p_enable);
}
void add(const Array &p_data) {}
void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) {
- Vector<VS::FrameProfileArea> profile_areas = VS::get_singleton()->get_frame_profile();
+ Vector<RS::FrameProfileArea> profile_areas = RS::get_singleton()->get_frame_profile();
DebuggerMarshalls::VisualProfilerFrame frame;
if (!profile_areas.size())
return;
- frame.frame_number = VS::get_singleton()->get_frame_profile_frame();
+ frame.frame_number = RS::get_singleton()->get_frame_profile_frame();
frame.areas.append_array(profile_areas);
EngineDebugger::get_singleton()->send_message("visual:profile_frame", frame.serialize());
}
@@ -372,7 +373,7 @@ struct RemoteDebugger::VisualProfiler {
struct RemoteDebugger::PerformanceProfiler {
- Object *performance = NULL;
+ Object *performance = nullptr;
int last_perf_time = 0;
void toggle(bool p_enable, const Array &p_opts) {}
@@ -403,10 +404,10 @@ void RemoteDebugger::_send_resource_usage() {
DebuggerMarshalls::ResourceUsage usage;
- List<VS::TextureInfo> tinfo;
- VS::get_singleton()->texture_debug_usage(&tinfo);
+ List<RS::TextureInfo> tinfo;
+ RS::get_singleton()->texture_debug_usage(&tinfo);
- for (List<VS::TextureInfo>::Element *E = tinfo.front(); E; E = E->next()) {
+ for (List<RS::TextureInfo>::Element *E = tinfo.front(); E; E = E->next()) {
DebuggerMarshalls::ResourceInfo info;
info.path = E->get().path;
@@ -658,9 +659,9 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
servers_profiler->skip_profile_frame = true; // Avoid frame time spike in debug.
- Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode();
- if (mouse_mode != Input::MOUSE_MODE_VISIBLE)
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ InputFilter::MouseMode mouse_mode = InputFilter::get_singleton()->get_mouse_mode();
+ if (mouse_mode != InputFilter::MOUSE_MODE_VISIBLE)
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE);
uint64_t loop_begin_usec = 0;
uint64_t loop_time_sec = 0;
@@ -694,7 +695,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else if (command == "continue") {
script_debugger->set_depth(-1);
script_debugger->set_lines_left(-1);
- OS::get_singleton()->move_window_to_foreground();
+ DisplayServer::get_singleton()->window_move_to_foreground();
break;
} else if (command == "break") {
@@ -770,16 +771,16 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
// This is for the camera override to stay live even when the game is paused from the editor
loop_time_sec = (OS::get_singleton()->get_ticks_usec() - loop_begin_usec) / 1000000.0f;
- VisualServer::get_singleton()->sync();
- if (VisualServer::get_singleton()->has_changed()) {
- VisualServer::get_singleton()->draw(true, loop_time_sec * Engine::get_singleton()->get_time_scale());
+ RenderingServer::get_singleton()->sync();
+ if (RenderingServer::get_singleton()->has_changed()) {
+ RenderingServer::get_singleton()->draw(true, loop_time_sec * Engine::get_singleton()->get_time_scale());
}
}
send_message("debug_exit", Array());
- if (mouse_mode != Input::MOUSE_MODE_VISIBLE)
- Input::get_singleton()->set_mouse_mode(mouse_mode);
+ if (mouse_mode != InputFilter::MOUSE_MODE_VISIBLE)
+ InputFilter::get_singleton()->set_mouse_mode(mouse_mode);
}
void RemoteDebugger::poll_events(bool p_is_idle) {
@@ -866,7 +867,7 @@ RemoteDebugger *RemoteDebugger::create_for_uri(const String &p_uri) {
Ref<RemoteDebuggerPeer> peer = RemoteDebuggerPeer::create_from_uri(p_uri);
if (peer.is_valid())
return memnew(RemoteDebugger(peer));
- return NULL;
+ return nullptr;
}
RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index 83789c67f9..f805eec631 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -50,10 +50,10 @@ private:
struct VisualProfiler;
struct PerformanceProfiler;
- NetworkProfiler *network_profiler = NULL;
- ServersProfiler *servers_profiler = NULL;
- VisualProfiler *visual_profiler = NULL;
- PerformanceProfiler *performance_profiler = NULL;
+ NetworkProfiler *network_profiler = nullptr;
+ ServersProfiler *servers_profiler = nullptr;
+ VisualProfiler *visual_profiler = nullptr;
+ PerformanceProfiler *performance_profiler = nullptr;
Ref<RemoteDebuggerPeer> peer;
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 42c2c8e309..ed04431177 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -68,7 +68,7 @@ void RemoteDebuggerPeerTCP::close() {
running = false;
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
tcp_client->disconnect_from_host();
out_buf.resize(0);
@@ -106,7 +106,7 @@ void RemoteDebuggerPeerTCP::_write_out() {
out_queue.pop_front();
mutex.unlock();
int size = 0;
- Error err = encode_variant(var, NULL, size);
+ Error err = encode_variant(var, nullptr, size);
ERR_CONTINUE(err != OK || size > out_buf.size() - 4); // 4 bytes separator.
encode_uint32(size, buf);
encode_variant(var, buf + 4, size);
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index 6fc3214a51..e4b838f145 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -58,7 +58,7 @@ class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer {
private:
Ref<StreamPeerTCP> tcp_client;
Mutex mutex;
- Thread *thread = NULL;
+ Thread *thread = nullptr;
List<Array> in_queue;
List<Array> out_queue;
int out_left = 0;
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index d8ddf353bf..e5066273d2 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -45,9 +45,9 @@ class ScriptDebugger {
int depth = -1;
bool skip_breakpoints = false;
- Map<int, Set<StringName> > breakpoints;
+ Map<int, Set<StringName>> breakpoints;
- ScriptLanguage *break_lang = NULL;
+ ScriptLanguage *break_lang = nullptr;
Vector<StackInfo> error_stack_info;
public:
@@ -67,7 +67,7 @@ public:
bool is_breakpoint(int p_line, const StringName &p_source) const;
bool is_breakpoint_line(int p_line) const;
void clear_breakpoints();
- const Map<int, Set<StringName> > &get_breakpoints() const { return breakpoints; }
+ const Map<int, Set<StringName>> &get_breakpoints() const { return breakpoints; }
void debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false);
ScriptLanguage *get_break_language() const;
@@ -77,4 +77,4 @@ public:
ScriptDebugger() {}
};
-#endif
+#endif // SCRIPT_DEBUGGER_H
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index cdb518228b..bc3b792bd5 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -90,7 +90,7 @@ const Variant *Dictionary::getptr(const Variant &p_key) const {
OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key);
if (!E)
- return NULL;
+ return nullptr;
return &E.get();
}
@@ -99,7 +99,7 @@ Variant *Dictionary::getptr(const Variant &p_key) {
OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(p_key);
if (!E)
- return NULL;
+ return nullptr;
return &E.get();
}
@@ -186,7 +186,7 @@ void Dictionary::_unref() const {
if (_p->refcount.unref()) {
memdelete(_p);
}
- _p = NULL;
+ _p = nullptr;
}
uint32_t Dictionary::hash() const {
@@ -236,17 +236,17 @@ Array Dictionary::values() const {
const Variant *Dictionary::next(const Variant *p_key) const {
- if (p_key == NULL) {
+ if (p_key == nullptr) {
// caller wants to get the first element
if (_p->variant_map.front())
return &_p->variant_map.front().key();
- return NULL;
+ return nullptr;
}
OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(*p_key);
if (E && E.next())
return &E.next().key();
- return NULL;
+ return nullptr;
}
Dictionary Dictionary::duplicate(bool p_deep) const {
@@ -270,7 +270,7 @@ const void *Dictionary::id() const {
}
Dictionary::Dictionary(const Dictionary &p_from) {
- _p = NULL;
+ _p = nullptr;
_ref(p_from);
}
diff --git a/core/dictionary.h b/core/dictionary.h
index 0ce817f3d4..c6cbacc144 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -75,7 +75,7 @@ public:
uint32_t hash() const;
void operator=(const Dictionary &p_dictionary);
- const Variant *next(const Variant *p_key = NULL) const;
+ const Variant *next(const Variant *p_key = nullptr) const;
Array keys() const;
Array values() const;
diff --git a/core/engine.cpp b/core/engine.cpp
index 85ad175f38..5361e09a8a 100644
--- a/core/engine.cpp
+++ b/core/engine.cpp
@@ -60,7 +60,7 @@ void Engine::set_target_fps(int p_fps) {
_target_fps = p_fps > 0 ? p_fps : 0;
}
-float Engine::get_target_fps() const {
+int Engine::get_target_fps() const {
return _target_fps;
}
@@ -114,7 +114,7 @@ Dictionary Engine::get_version_info() const {
static Array array_from_info(const char *const *info_list) {
Array arr;
- for (int i = 0; info_list[i] != NULL; i++) {
+ for (int i = 0; info_list[i] != nullptr; i++) {
arr.push_back(info_list[i]);
}
return arr;
@@ -193,7 +193,7 @@ void Engine::add_singleton(const Singleton &p_singleton) {
Object *Engine::get_singleton_object(const String &p_name) const {
const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name);
- ERR_FAIL_COND_V_MSG(!E, NULL, "Failed to retrieve non-existent singleton '" + p_name + "'.");
+ ERR_FAIL_COND_V_MSG(!E, nullptr, "Failed to retrieve non-existent singleton '" + p_name + "'.");
return E->get();
};
@@ -208,7 +208,7 @@ void Engine::get_singletons(List<Singleton> *p_singletons) {
p_singletons->push_back(E->get());
}
-Engine *Engine::singleton = NULL;
+Engine *Engine::singleton = nullptr;
Engine *Engine::get_singleton() {
return singleton;
diff --git a/core/engine.h b/core/engine.h
index cfe3a918fc..8512779d4c 100644
--- a/core/engine.h
+++ b/core/engine.h
@@ -42,7 +42,7 @@ public:
struct Singleton {
StringName name;
Object *ptr;
- Singleton(const StringName &p_name = StringName(), Object *p_ptr = NULL) :
+ Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr) :
name(p_name),
ptr(p_ptr) {
}
@@ -86,7 +86,7 @@ public:
float get_physics_jitter_fix() const;
virtual void set_target_fps(int p_fps);
- virtual float get_target_fps() const;
+ virtual int get_target_fps() const;
virtual float get_frames_per_second() const { return _fps; }
diff --git a/core/error_list.h b/core/error_list.h
index b464a93341..a0218cf045 100644
--- a/core/error_list.h
+++ b/core/error_list.h
@@ -90,4 +90,4 @@ enum Error {
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
};
-#endif
+#endif // ERROR_LIST_H
diff --git a/core/error_macros.cpp b/core/error_macros.cpp
index f6da990562..5de070844a 100644
--- a/core/error_macros.cpp
+++ b/core/error_macros.cpp
@@ -34,7 +34,7 @@
#include "core/ustring.h"
#include "os/os.h"
-static ErrorHandlerList *error_handler_list = NULL;
+static ErrorHandlerList *error_handler_list = nullptr;
void add_error_handler(ErrorHandlerList *p_handler) {
@@ -48,7 +48,7 @@ void remove_error_handler(ErrorHandlerList *p_handler) {
_global_lock();
- ErrorHandlerList *prev = NULL;
+ ErrorHandlerList *prev = nullptr;
ErrorHandlerList *l = error_handler_list;
while (l) {
diff --git a/core/error_macros.h b/core/error_macros.h
index e4d7609e04..18c46c9e7d 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -502,11 +502,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
*
* The current function returns `m_retval`.
*/
-#define ERR_FAIL_V(m_retval) \
- if (1) { \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_retval)); \
- return m_retval; \
- } else \
+#define ERR_FAIL_V(m_retval) \
+ if (1) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " _STR(m_retval)); \
+ return m_retval; \
+ } else \
((void)0)
/**
@@ -515,11 +515,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
*
* Prints `m_msg`, and the current function returns `m_retval`.
*/
-#define ERR_FAIL_V_MSG(m_retval, m_msg) \
- if (1) { \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_retval), DEBUG_STR(m_msg)); \
- return m_retval; \
- } else \
+#define ERR_FAIL_V_MSG(m_retval, m_msg) \
+ if (1) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " _STR(m_retval), DEBUG_STR(m_msg)); \
+ return m_retval; \
+ } else \
((void)0)
/**
@@ -623,4 +623,4 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
} else \
((void)0)
-#endif
+#endif // ERROR_MACROS_H
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 0945240c1f..6f6b8c1dd3 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -30,8 +30,8 @@
#include "global_constants.h"
+#include "core/input/input_event.h"
#include "core/object.h"
-#include "core/os/input_event.h"
#include "core/os/keyboard.h"
#include "core/variant.h"
@@ -568,9 +568,6 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
- //deprecated, replaced by ClassDB function to check default value
- //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO);
- //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
diff --git a/core/hash_map.h b/core/hash_map.h
index c9d3a690e7..f27a86cc02 100644
--- a/core/hash_map.h
+++ b/core/hash_map.h
@@ -197,14 +197,14 @@ private:
e = e->next;
}
- return NULL;
+ return nullptr;
}
Element *create_element(const TKey &p_key) {
/* if element doesn't exist, create it */
Element *e = memnew(Element);
- ERR_FAIL_COND_V_MSG(!e, NULL, "Out of memory.");
+ ERR_FAIL_COND_V_MSG(!e, nullptr, "Out of memory.");
uint32_t hash = Hasher::hash(p_key);
uint32_t index = hash & ((1 << hash_table_power) - 1);
e->next = hash_table[index];
@@ -234,7 +234,7 @@ private:
for (int i = 0; i < (1 << p_t.hash_table_power); i++) {
- hash_table[i] = NULL;
+ hash_table[i] = nullptr;
const Element *e = p_t.hash_table[i];
@@ -260,7 +260,7 @@ public:
Element *set(const Pair &p_pair) {
- Element *e = NULL;
+ Element *e = nullptr;
if (!hash_table)
make_hash_table(); // if no table, make one
else
@@ -272,7 +272,7 @@ public:
e = create_element(p_pair.key);
if (!e)
- return NULL;
+ return nullptr;
check_hash_table(); // perform mantenience routine
}
@@ -282,12 +282,12 @@ public:
bool has(const TKey &p_key) const {
- return getptr(p_key) != NULL;
+ return getptr(p_key) != nullptr;
}
/**
* Get a key from data, return a const reference.
- * WARNING: this doesn't check errors, use either getptr and check NULL, or check
+ * WARNING: this doesn't check errors, use either getptr and check nullptr, or check
* first with has(key)
*/
@@ -306,38 +306,38 @@ public:
}
/**
- * Same as get, except it can return NULL when item was not found.
+ * Same as get, except it can return nullptr when item was not found.
* This is mainly used for speed purposes.
*/
_FORCE_INLINE_ TData *getptr(const TKey &p_key) {
if (unlikely(!hash_table))
- return NULL;
+ return nullptr;
Element *e = const_cast<Element *>(get_element(p_key));
if (e)
return &e->pair.data;
- return NULL;
+ return nullptr;
}
_FORCE_INLINE_ const TData *getptr(const TKey &p_key) const {
if (unlikely(!hash_table))
- return NULL;
+ return nullptr;
const Element *e = const_cast<Element *>(get_element(p_key));
if (e)
return &e->pair.data;
- return NULL;
+ return nullptr;
}
/**
- * Same as get, except it can return NULL when item was not found.
+ * Same as get, except it can return nullptr when item was not found.
* This version is custom, will take a hash and a custom key (that should support operator==()
*/
@@ -345,7 +345,7 @@ public:
_FORCE_INLINE_ TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) {
if (unlikely(!hash_table))
- return NULL;
+ return nullptr;
uint32_t hash = p_custom_hash;
uint32_t index = hash & ((1 << hash_table_power) - 1);
@@ -364,14 +364,14 @@ public:
e = e->next;
}
- return NULL;
+ return nullptr;
}
template <class C>
_FORCE_INLINE_ const TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) const {
if (unlikely(!hash_table))
- return NULL;
+ return nullptr;
uint32_t hash = p_custom_hash;
uint32_t index = hash & ((1 << hash_table_power) - 1);
@@ -390,7 +390,7 @@ public:
e = e->next;
}
- return NULL;
+ return nullptr;
}
/**
@@ -406,7 +406,7 @@ public:
uint32_t index = hash & ((1 << hash_table_power) - 1);
Element *e = hash_table[index];
- Element *p = NULL;
+ Element *p = nullptr;
while (e) {
/* checking hash first avoids comparing key, which may take longer */
@@ -443,7 +443,7 @@ public:
}
inline TData &operator[](const TKey &p_key) { //assignment
- Element *e = NULL;
+ Element *e = nullptr;
if (!hash_table)
make_hash_table(); // if no table, make one
else
@@ -462,12 +462,12 @@ public:
/**
* Get the next key to p_key, and the first key if p_key is null.
- * Returns a pointer to the next key if found, NULL otherwise.
+ * Returns a pointer to the next key if found, nullptr otherwise.
* Adding/Removing elements while iterating will, of course, have unexpected results, don't do it.
*
* Example:
*
- * const TKey *k=NULL;
+ * const TKey *k=nullptr;
*
* while( (k=table.next(k)) ) {
*
@@ -478,7 +478,7 @@ public:
const TKey *next(const TKey *p_key) const {
if (unlikely(!hash_table))
- return NULL;
+ return nullptr;
if (!p_key) { /* get the first key */
@@ -492,7 +492,7 @@ public:
} else { /* get the next key */
const Element *e = get_element(*p_key);
- ERR_FAIL_COND_V_MSG(!e, NULL, "Invalid key supplied.");
+ ERR_FAIL_COND_V_MSG(!e, nullptr, "Invalid key supplied.");
if (e->next) {
/* if there is a "next" in the list, return that */
return &e->next->pair.key;
@@ -511,7 +511,7 @@ public:
/* nothing found, was at end */
}
- return NULL; /* nothing found */
+ return nullptr; /* nothing found */
}
inline unsigned int size() const {
@@ -552,7 +552,7 @@ public:
}
HashMap() {
- hash_table = NULL;
+ hash_table = nullptr;
elements = 0;
hash_table_power = 0;
}
@@ -586,7 +586,7 @@ public:
HashMap(const HashMap &p_table) {
- hash_table = NULL;
+ hash_table = nullptr;
elements = 0;
hash_table_power = 0;
@@ -599,4 +599,4 @@ public:
}
};
-#endif
+#endif // HASH_MAP_H
diff --git a/core/hashfuncs.h b/core/hashfuncs.h
index d6cf04e560..a41a034843 100644
--- a/core/hashfuncs.h
+++ b/core/hashfuncs.h
@@ -35,6 +35,7 @@
#include "core/math/math_funcs.h"
#include "core/node_path.h"
#include "core/object_id.h"
+#include "core/rid.h"
#include "core/string_name.h"
#include "core/typedefs.h"
#include "core/ustring.h"
@@ -149,6 +150,7 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
+ static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
@@ -171,4 +173,4 @@ struct HashMapComparatorDefault {
}
};
-#endif
+#endif // HASHFUNCS_H
diff --git a/core/image.cpp b/core/image.cpp
index 2c39c9b882..2097f27b01 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -84,10 +84,10 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
};
-SavePNGFunc Image::save_png_func = NULL;
-SaveEXRFunc Image::save_exr_func = NULL;
+SavePNGFunc Image::save_png_func = nullptr;
+SaveEXRFunc Image::save_exr_func = nullptr;
-SavePNGBufferFunc Image::save_png_buffer_func = NULL;
+SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) {
@@ -1680,7 +1680,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con
int pixel_ofs = y * w + x;
Color c = _get_color_at_ofs(ptr, pixel_ofs);
- float roughness;
+ float roughness = 0;
switch (p_roughness_channel) {
case ROUGHNESS_CHANNEL_R: {
@@ -2099,14 +2099,14 @@ Error Image::load(const String &p_path) {
Error Image::save_png(const String &p_path) const {
- if (save_png_func == NULL)
+ if (save_png_func == nullptr)
return ERR_UNAVAILABLE;
return save_png_func(p_path, Ref<Image>((Image *)this));
}
Vector<uint8_t> Image::save_png_to_buffer() const {
- if (save_png_buffer_func == NULL) {
+ if (save_png_buffer_func == nullptr) {
return Vector<uint8_t>();
}
@@ -2115,7 +2115,7 @@ Vector<uint8_t> Image::save_png_to_buffer() const {
Error Image::save_exr(const String &p_path, bool p_grayscale) const {
- if (save_exr_func == NULL)
+ if (save_exr_func == nullptr)
return ERR_UNAVAILABLE;
return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
@@ -2533,28 +2533,28 @@ void Image::fill(const Color &c) {
}
}
-ImageMemLoadFunc Image::_png_mem_loader_func = NULL;
-ImageMemLoadFunc Image::_jpg_mem_loader_func = NULL;
-ImageMemLoadFunc Image::_webp_mem_loader_func = NULL;
+ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
-void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = NULL;
-void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = NULL;
-void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL;
-void (*Image::_image_compress_pvrtc4_func)(Image *) = NULL;
-void (*Image::_image_compress_etc1_func)(Image *, float) = NULL;
-void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = NULL;
-void (*Image::_image_decompress_pvrtc)(Image *) = NULL;
-void (*Image::_image_decompress_bc)(Image *) = NULL;
-void (*Image::_image_decompress_bptc)(Image *) = NULL;
-void (*Image::_image_decompress_etc1)(Image *) = NULL;
-void (*Image::_image_decompress_etc2)(Image *) = NULL;
+void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nullptr;
+void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr;
+void (*Image::_image_compress_pvrtc2_func)(Image *) = nullptr;
+void (*Image::_image_compress_pvrtc4_func)(Image *) = nullptr;
+void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr;
+void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr;
+void (*Image::_image_decompress_pvrtc)(Image *) = nullptr;
+void (*Image::_image_decompress_bc)(Image *) = nullptr;
+void (*Image::_image_decompress_bptc)(Image *) = nullptr;
+void (*Image::_image_decompress_etc1)(Image *) = nullptr;
+void (*Image::_image_decompress_etc2)(Image *) = nullptr;
-Vector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = NULL;
-Ref<Image> (*Image::lossy_unpacker)(const Vector<uint8_t> &) = NULL;
-Vector<uint8_t> (*Image::lossless_packer)(const Ref<Image> &) = NULL;
-Ref<Image> (*Image::lossless_unpacker)(const Vector<uint8_t> &) = NULL;
-Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = NULL;
-Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = NULL;
+Vector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = nullptr;
+Ref<Image> (*Image::lossy_unpacker)(const Vector<uint8_t> &) = nullptr;
+Vector<uint8_t> (*Image::lossless_packer)(const Ref<Image> &) = nullptr;
+Ref<Image> (*Image::lossless_unpacker)(const Vector<uint8_t> &) = nullptr;
+Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr;
+Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr;
void Image::_set_data(const Dictionary &p_data) {
@@ -2945,7 +2945,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC));
ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7));
- ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality"), &Image::compress, DEFVAL(0.7));
+ ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality"), &Image::compress_from_channels, DEFVAL(0.7));
ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress);
ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed);
diff --git a/core/image.h b/core/image.h
index 4dc4bf1328..5bd73fa677 100644
--- a/core/image.h
+++ b/core/image.h
@@ -187,7 +187,7 @@ private:
_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data
- static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = NULL, int *r_mm_height = NULL);
+ static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
bool _can_modify(Format p_format) const;
_FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel);
@@ -396,4 +396,4 @@ VARIANT_ENUM_CAST(Image::UsedChannels)
VARIANT_ENUM_CAST(Image::AlphaMode)
VARIANT_ENUM_CAST(Image::RoughnessChannel)
-#endif
+#endif // IMAGE_H
diff --git a/core/input/SCsub b/core/input/SCsub
new file mode 100644
index 0000000000..d46e52a347
--- /dev/null
+++ b/core/input/SCsub
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+Import("env")
+
+from platform_methods import run_in_subprocess
+import input_builders
+
+
+# Order matters here. Higher index controller database files write on top of lower index database files.
+controller_databases = [
+ "#core/input/gamecontrollerdb_204.txt",
+ "#core/input/gamecontrollerdb_205.txt",
+ "#core/input/gamecontrollerdb.txt",
+ "#core/input/godotcontrollerdb.txt",
+]
+
+env.Depends("#core/input/default_controller_mappings.gen.cpp", controller_databases)
+env.CommandNoCache(
+ "#core/input/default_controller_mappings.gen.cpp",
+ controller_databases,
+ run_in_subprocess(input_builders.make_default_controller_mappings),
+)
+
+env.add_source_files(env.core_sources, "*.cpp")
+
+# Don't warn about duplicate entry here, we need it registered manually for first build,
+# even if later builds will pick it up twice due to above *.cpp globbing.
+env.add_source_files(env.core_sources, "#core/input/default_controller_mappings.gen.cpp", warn_duplicates=False)
diff --git a/main/default_controller_mappings.h b/core/input/default_controller_mappings.h
index 9e2a69acec..9e2a69acec 100644
--- a/main/default_controller_mappings.h
+++ b/core/input/default_controller_mappings.h
diff --git a/main/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 90d309c1c8..90d309c1c8 100644
--- a/main/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
diff --git a/main/gamecontrollerdb_204.txt b/core/input/gamecontrollerdb_204.txt
index 7fbe925b25..7fbe925b25 100644
--- a/main/gamecontrollerdb_204.txt
+++ b/core/input/gamecontrollerdb_204.txt
diff --git a/main/gamecontrollerdb_205.txt b/core/input/gamecontrollerdb_205.txt
index 55c45eb148..55c45eb148 100644
--- a/main/gamecontrollerdb_205.txt
+++ b/core/input/gamecontrollerdb_205.txt
diff --git a/main/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index 472b01947b..472b01947b 100644
--- a/main/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
new file mode 100644
index 0000000000..53b90f2073
--- /dev/null
+++ b/core/input/input_builders.py
@@ -0,0 +1,81 @@
+"""Functions used to generate source files during build time
+
+All such functions are invoked in a subprocess on Windows to prevent build flakiness.
+"""
+
+from platform_methods import subprocess_main
+from collections import OrderedDict
+
+
+def make_default_controller_mappings(target, source, env):
+ dst = target[0]
+ g = open(dst, "w")
+
+ g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ g.write('#include "core/typedefs.h"\n')
+ g.write('#include "core/input/default_controller_mappings.h"\n')
+
+ # ensure mappings have a consistent order
+ platform_mappings = OrderedDict()
+ for src_path in source:
+ with open(src_path, "r") as f:
+ # read mapping file and skip header
+ mapping_file_lines = f.readlines()[2:]
+
+ current_platform = None
+ for line in mapping_file_lines:
+ if not line:
+ continue
+ line = line.strip()
+ if len(line) == 0:
+ continue
+ if line[0] == "#":
+ current_platform = line[1:].strip()
+ if current_platform not in platform_mappings:
+ platform_mappings[current_platform] = {}
+ elif current_platform:
+ line_parts = line.split(",")
+ guid = line_parts[0]
+ if guid in platform_mappings[current_platform]:
+ g.write(
+ "// WARNING - DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(
+ src_path, current_platform, platform_mappings[current_platform][guid]
+ )
+ )
+ valid_mapping = True
+ for input_map in line_parts[2:]:
+ if "+" in input_map or "-" in input_map or "~" in input_map:
+ g.write(
+ "// WARNING - DISCARDED UNSUPPORTED MAPPING TYPE FROM DATABASE {}: {} {}\n".format(
+ src_path, current_platform, line
+ )
+ )
+ valid_mapping = False
+ break
+ if valid_mapping:
+ platform_mappings[current_platform][guid] = line
+
+ platform_variables = {
+ "Linux": "#if X11_ENABLED",
+ "Windows": "#ifdef WINDOWS_ENABLED",
+ "Mac OS X": "#ifdef OSX_ENABLED",
+ "Android": "#if defined(__ANDROID__)",
+ "iOS": "#ifdef IPHONE_ENABLED",
+ "Javascript": "#ifdef JAVASCRIPT_ENABLED",
+ "UWP": "#ifdef UWP_ENABLED",
+ }
+
+ g.write("const char* DefaultControllerMappings::mappings[] = {\n")
+ for platform, mappings in platform_mappings.items():
+ variable = platform_variables[platform]
+ g.write("{}\n".format(variable))
+ for mapping in mappings.values():
+ g.write('\t"{}",\n'.format(mapping))
+ g.write("#endif\n")
+
+ g.write("\tnullptr\n};\n")
+ g.close()
+
+
+if __name__ == "__main__":
+ subprocess_main(globals())
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
new file mode 100644
index 0000000000..80219331c0
--- /dev/null
+++ b/core/input/input_event.cpp
@@ -0,0 +1,1404 @@
+/*************************************************************************/
+/* input_event.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_event.h"
+
+#include "core/input/input_map.h"
+#include "core/os/keyboard.h"
+
+const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1;
+const int InputEvent::DEVICE_ID_INTERNAL = -2;
+
+void InputEvent::set_device(int p_device) {
+ device = p_device;
+}
+
+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_pressed(const StringName &p_action, bool p_allow_echo) const {
+
+ bool pressed;
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
+ return valid && pressed && (p_allow_echo || !is_echo());
+}
+
+bool InputEvent::is_action_released(const StringName &p_action) const {
+
+ bool pressed;
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
+ return valid && !pressed;
+}
+
+float InputEvent::get_action_strength(const StringName &p_action) const {
+
+ bool pressed;
+ float strength;
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed, &strength);
+ return valid ? strength : 0.0f;
+}
+
+bool InputEvent::is_pressed() const {
+
+ return false;
+}
+
+bool InputEvent::is_echo() const {
+
+ return false;
+}
+
+Ref<InputEvent> InputEvent::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ return Ref<InputEvent>((InputEvent *)this);
+}
+
+String InputEvent::as_text() const {
+
+ return String();
+}
+
+bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+
+ return false;
+}
+
+bool InputEvent::shortcut_match(const Ref<InputEvent> &p_event) const {
+
+ return false;
+}
+
+bool InputEvent::is_action_type() const {
+
+ return false;
+}
+
+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_pressed"), &InputEvent::is_pressed);
+ ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo);
+
+ ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text);
+
+ ClassDB::bind_method(D_METHOD("shortcut_match", "event"), &InputEvent::shortcut_match);
+
+ ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type);
+
+ ClassDB::bind_method(D_METHOD("accumulate", "with_event"), &InputEvent::accumulate);
+
+ ClassDB::bind_method(D_METHOD("xformed_by", "xform", "local_ofs"), &InputEvent::xformed_by, DEFVAL(Vector2()));
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device");
+}
+
+InputEvent::InputEvent() {
+
+ device = 0;
+}
+////////////////
+
+void InputEventFromWindow::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_window_id", "id"), &InputEventFromWindow::set_window_id);
+ ClassDB::bind_method(D_METHOD("get_window_id"), &InputEventFromWindow::get_window_id);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "window_id"), "set_window_id", "get_window_id");
+}
+
+void InputEventFromWindow::set_window_id(int64_t p_id) {
+ window_id = p_id;
+}
+int64_t InputEventFromWindow::get_window_id() const {
+ return window_id;
+}
+
+InputEventFromWindow::InputEventFromWindow() {
+ window_id = 0;
+}
+
+//////////////////
+
+void InputEventWithModifiers::set_shift(bool p_enabled) {
+
+ shift = p_enabled;
+}
+
+bool InputEventWithModifiers::get_shift() const {
+
+ return shift;
+}
+
+void InputEventWithModifiers::set_alt(bool p_enabled) {
+
+ alt = p_enabled;
+}
+bool InputEventWithModifiers::get_alt() const {
+
+ return alt;
+}
+
+void InputEventWithModifiers::set_control(bool p_enabled) {
+
+ control = p_enabled;
+}
+bool InputEventWithModifiers::get_control() const {
+
+ return control;
+}
+
+void InputEventWithModifiers::set_metakey(bool p_enabled) {
+
+ meta = p_enabled;
+}
+bool InputEventWithModifiers::get_metakey() const {
+
+ return meta;
+}
+
+void InputEventWithModifiers::set_command(bool p_enabled) {
+
+ command = p_enabled;
+}
+bool InputEventWithModifiers::get_command() const {
+
+ return command;
+}
+
+void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModifiers *event) {
+
+ set_alt(event->get_alt());
+ set_shift(event->get_shift());
+ set_control(event->get_control());
+ set_metakey(event->get_metakey());
+}
+
+void InputEventWithModifiers::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt);
+ ClassDB::bind_method(D_METHOD("get_alt"), &InputEventWithModifiers::get_alt);
+
+ ClassDB::bind_method(D_METHOD("set_shift", "enable"), &InputEventWithModifiers::set_shift);
+ ClassDB::bind_method(D_METHOD("get_shift"), &InputEventWithModifiers::get_shift);
+
+ ClassDB::bind_method(D_METHOD("set_control", "enable"), &InputEventWithModifiers::set_control);
+ ClassDB::bind_method(D_METHOD("get_control"), &InputEventWithModifiers::get_control);
+
+ ClassDB::bind_method(D_METHOD("set_metakey", "enable"), &InputEventWithModifiers::set_metakey);
+ ClassDB::bind_method(D_METHOD("get_metakey"), &InputEventWithModifiers::get_metakey);
+
+ ClassDB::bind_method(D_METHOD("set_command", "enable"), &InputEventWithModifiers::set_command);
+ ClassDB::bind_method(D_METHOD("get_command"), &InputEventWithModifiers::get_command);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt"), "set_alt", "get_alt");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift"), "set_shift", "get_shift");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "control"), "set_control", "get_control");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta"), "set_metakey", "get_metakey");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command"), "set_command", "get_command");
+}
+
+InputEventWithModifiers::InputEventWithModifiers() {
+
+ alt = false;
+ shift = false;
+ control = false;
+ meta = false;
+}
+
+//////////////////////////////////
+
+void InputEventKey::set_pressed(bool p_pressed) {
+
+ pressed = p_pressed;
+}
+
+bool InputEventKey::is_pressed() const {
+
+ return pressed;
+}
+
+void InputEventKey::set_keycode(uint32_t p_keycode) {
+
+ keycode = p_keycode;
+}
+
+uint32_t InputEventKey::get_keycode() const {
+
+ return keycode;
+}
+
+void InputEventKey::set_physical_keycode(uint32_t p_keycode) {
+
+ physical_keycode = p_keycode;
+}
+
+uint32_t InputEventKey::get_physical_keycode() const {
+
+ return physical_keycode;
+}
+
+void InputEventKey::set_unicode(uint32_t p_unicode) {
+
+ unicode = p_unicode;
+}
+
+uint32_t InputEventKey::get_unicode() const {
+
+ return unicode;
+}
+
+void InputEventKey::set_echo(bool p_enable) {
+
+ echo = p_enable;
+}
+
+bool InputEventKey::is_echo() const {
+
+ return echo;
+}
+
+uint32_t InputEventKey::get_keycode_with_modifiers() const {
+
+ uint32_t sc = keycode;
+ if (get_control())
+ sc |= KEY_MASK_CTRL;
+ if (get_alt())
+ sc |= KEY_MASK_ALT;
+ if (get_shift())
+ sc |= KEY_MASK_SHIFT;
+ if (get_metakey())
+ sc |= KEY_MASK_META;
+
+ return sc;
+}
+
+uint32_t InputEventKey::get_physical_keycode_with_modifiers() const {
+
+ uint32_t sc = physical_keycode;
+ if (get_control())
+ sc |= KEY_MASK_CTRL;
+ if (get_alt())
+ sc |= KEY_MASK_ALT;
+ if (get_shift())
+ sc |= KEY_MASK_SHIFT;
+ if (get_metakey())
+ sc |= KEY_MASK_META;
+
+ return sc;
+}
+
+String InputEventKey::as_text() const {
+
+ String kc = keycode_get_string(keycode);
+ if (kc == String())
+ return kc;
+
+ if (get_metakey()) {
+ kc = find_keycode_name(KEY_META) + ("+" + kc);
+ }
+ if (get_alt()) {
+ kc = find_keycode_name(KEY_ALT) + ("+" + kc);
+ }
+ if (get_shift()) {
+ kc = find_keycode_name(KEY_SHIFT) + ("+" + kc);
+ }
+ if (get_control()) {
+ kc = find_keycode_name(KEY_CONTROL) + ("+" + kc);
+ }
+ return kc;
+}
+
+bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+
+ Ref<InputEventKey> key = p_event;
+ if (key.is_null())
+ return false;
+
+ bool match = false;
+ if (get_keycode() == 0) {
+ uint32_t code = get_physical_keycode_with_modifiers();
+ uint32_t event_code = key->get_physical_keycode_with_modifiers();
+
+ match = get_physical_keycode() == key->get_physical_keycode() && (!key->is_pressed() || (code & event_code) == code);
+ } else {
+ uint32_t code = get_keycode_with_modifiers();
+ uint32_t event_code = key->get_keycode_with_modifiers();
+
+ match = get_keycode() == key->get_keycode() && (!key->is_pressed() || (code & event_code) == code);
+ }
+ if (match) {
+ if (p_pressed != nullptr)
+ *p_pressed = key->is_pressed();
+ if (p_strength != nullptr)
+ *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ }
+ return match;
+}
+
+bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const {
+
+ Ref<InputEventKey> key = p_event;
+ if (key.is_null())
+ return false;
+
+ uint32_t code = get_keycode_with_modifiers();
+ uint32_t event_code = key->get_keycode_with_modifiers();
+
+ return code == event_code;
+}
+
+void InputEventKey::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventKey::set_pressed);
+
+ ClassDB::bind_method(D_METHOD("set_keycode", "keycode"), &InputEventKey::set_keycode);
+ ClassDB::bind_method(D_METHOD("get_keycode"), &InputEventKey::get_keycode);
+
+ ClassDB::bind_method(D_METHOD("set_physical_keycode", "physical_keycode"), &InputEventKey::set_physical_keycode);
+ ClassDB::bind_method(D_METHOD("get_physical_keycode"), &InputEventKey::get_physical_keycode);
+
+ ClassDB::bind_method(D_METHOD("set_unicode", "unicode"), &InputEventKey::set_unicode);
+ ClassDB::bind_method(D_METHOD("get_unicode"), &InputEventKey::get_unicode);
+
+ ClassDB::bind_method(D_METHOD("set_echo", "echo"), &InputEventKey::set_echo);
+
+ ClassDB::bind_method(D_METHOD("get_keycode_with_modifiers"), &InputEventKey::get_keycode_with_modifiers);
+ ClassDB::bind_method(D_METHOD("get_physical_keycode_with_modifiers"), &InputEventKey::get_physical_keycode_with_modifiers);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "keycode"), "set_keycode", "get_keycode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_keycode"), "set_physical_keycode", "get_physical_keycode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "unicode"), "set_unicode", "get_unicode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "echo"), "set_echo", "is_echo");
+}
+
+InputEventKey::InputEventKey() {
+
+ pressed = false;
+ keycode = 0;
+ physical_keycode = 0;
+ unicode = 0; ///unicode
+ echo = false;
+}
+
+////////////////////////////////////////
+
+void InputEventMouse::set_button_mask(int p_mask) {
+
+ button_mask = p_mask;
+}
+int InputEventMouse::get_button_mask() const {
+
+ return button_mask;
+}
+
+void InputEventMouse::set_position(const Vector2 &p_pos) {
+
+ pos = p_pos;
+}
+Vector2 InputEventMouse::get_position() const {
+
+ return pos;
+}
+
+void InputEventMouse::set_global_position(const Vector2 &p_global_pos) {
+
+ global_pos = p_global_pos;
+}
+Vector2 InputEventMouse::get_global_position() const {
+
+ return global_pos;
+}
+
+void InputEventMouse::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_button_mask", "button_mask"), &InputEventMouse::set_button_mask);
+ ClassDB::bind_method(D_METHOD("get_button_mask"), &InputEventMouse::get_button_mask);
+
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventMouse::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &InputEventMouse::get_position);
+
+ ClassDB::bind_method(D_METHOD("set_global_position", "global_position"), &InputEventMouse::set_global_position);
+ ClassDB::bind_method(D_METHOD("get_global_position"), &InputEventMouse::get_global_position);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask"), "set_button_mask", "get_button_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position"), "set_global_position", "get_global_position");
+}
+
+InputEventMouse::InputEventMouse() {
+
+ button_mask = 0;
+}
+
+///////////////////////////////////////
+
+void InputEventMouseButton::set_factor(float p_factor) {
+
+ factor = p_factor;
+}
+
+float InputEventMouseButton::get_factor() {
+
+ return factor;
+}
+
+void InputEventMouseButton::set_button_index(int p_index) {
+
+ button_index = p_index;
+}
+int InputEventMouseButton::get_button_index() const {
+
+ return button_index;
+}
+
+void InputEventMouseButton::set_pressed(bool p_pressed) {
+
+ pressed = p_pressed;
+}
+bool InputEventMouseButton::is_pressed() const {
+
+ return pressed;
+}
+
+void InputEventMouseButton::set_doubleclick(bool p_doubleclick) {
+
+ doubleclick = p_doubleclick;
+}
+bool InputEventMouseButton::is_doubleclick() const {
+
+ return doubleclick;
+}
+
+Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ Vector2 g = get_global_position();
+ Vector2 l = p_xform.xform(get_position() + p_local_ofs);
+
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+
+ mb->set_device(get_device());
+ mb->set_window_id(get_window_id());
+ mb->set_modifiers_from_event(this);
+
+ mb->set_position(l);
+ mb->set_global_position(g);
+
+ mb->set_button_mask(get_button_mask());
+ mb->set_pressed(pressed);
+ mb->set_doubleclick(doubleclick);
+ mb->set_factor(factor);
+ mb->set_button_index(button_index);
+
+ return mb;
+}
+
+bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_null())
+ return false;
+
+ bool match = mb->button_index == button_index;
+ if (match) {
+ if (p_pressed != nullptr)
+ *p_pressed = mb->is_pressed();
+ if (p_strength != nullptr)
+ *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ }
+
+ return match;
+}
+
+String InputEventMouseButton::as_text() const {
+
+ String button_index_string = "";
+ switch (get_button_index()) {
+ case BUTTON_LEFT:
+ button_index_string = "BUTTON_LEFT";
+ break;
+ case BUTTON_RIGHT:
+ button_index_string = "BUTTON_RIGHT";
+ break;
+ case BUTTON_MIDDLE:
+ button_index_string = "BUTTON_MIDDLE";
+ break;
+ case BUTTON_WHEEL_UP:
+ button_index_string = "BUTTON_WHEEL_UP";
+ break;
+ case BUTTON_WHEEL_DOWN:
+ button_index_string = "BUTTON_WHEEL_DOWN";
+ break;
+ case BUTTON_WHEEL_LEFT:
+ button_index_string = "BUTTON_WHEEL_LEFT";
+ break;
+ case BUTTON_WHEEL_RIGHT:
+ button_index_string = "BUTTON_WHEEL_RIGHT";
+ break;
+ case BUTTON_XBUTTON1:
+ button_index_string = "BUTTON_XBUTTON1";
+ break;
+ case BUTTON_XBUTTON2:
+ button_index_string = "BUTTON_XBUTTON2";
+ break;
+ default:
+ button_index_string = itos(get_button_index());
+ break;
+ }
+ return "InputEventMouseButton : button_index=" + button_index_string + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + "), button_mask=" + itos(get_button_mask()) + ", doubleclick=" + (doubleclick ? "true" : "false");
+}
+
+void InputEventMouseButton::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_factor", "factor"), &InputEventMouseButton::set_factor);
+ ClassDB::bind_method(D_METHOD("get_factor"), &InputEventMouseButton::get_factor);
+
+ ClassDB::bind_method(D_METHOD("set_button_index", "button_index"), &InputEventMouseButton::set_button_index);
+ ClassDB::bind_method(D_METHOD("get_button_index"), &InputEventMouseButton::get_button_index);
+
+ ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventMouseButton::set_pressed);
+ // ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventMouseButton::is_pressed);
+
+ ClassDB::bind_method(D_METHOD("set_doubleclick", "doubleclick"), &InputEventMouseButton::set_doubleclick);
+ ClassDB::bind_method(D_METHOD("is_doubleclick"), &InputEventMouseButton::is_doubleclick);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "factor"), "set_factor", "get_factor");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "doubleclick"), "set_doubleclick", "is_doubleclick");
+}
+
+InputEventMouseButton::InputEventMouseButton() {
+
+ factor = 1;
+ button_index = 0;
+ pressed = false;
+ doubleclick = false;
+}
+
+////////////////////////////////////////////
+
+void InputEventMouseMotion::set_tilt(const Vector2 &p_tilt) {
+
+ tilt = p_tilt;
+}
+
+Vector2 InputEventMouseMotion::get_tilt() const {
+
+ return tilt;
+}
+
+void InputEventMouseMotion::set_pressure(float p_pressure) {
+
+ pressure = p_pressure;
+}
+
+float InputEventMouseMotion::get_pressure() const {
+
+ return pressure;
+}
+
+void InputEventMouseMotion::set_relative(const Vector2 &p_relative) {
+
+ relative = p_relative;
+}
+
+Vector2 InputEventMouseMotion::get_relative() const {
+
+ return relative;
+}
+
+void InputEventMouseMotion::set_speed(const Vector2 &p_speed) {
+
+ speed = p_speed;
+}
+
+Vector2 InputEventMouseMotion::get_speed() const {
+
+ return speed;
+}
+
+Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ Vector2 g = get_global_position();
+ Vector2 l = p_xform.xform(get_position() + p_local_ofs);
+ Vector2 r = p_xform.basis_xform(get_relative());
+ Vector2 s = p_xform.basis_xform(get_speed());
+
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+
+ mm->set_device(get_device());
+ mm->set_window_id(get_window_id());
+
+ mm->set_modifiers_from_event(this);
+
+ mm->set_position(l);
+ mm->set_pressure(get_pressure());
+ mm->set_tilt(get_tilt());
+ mm->set_global_position(g);
+
+ mm->set_button_mask(get_button_mask());
+ mm->set_relative(r);
+ mm->set_speed(s);
+
+ return mm;
+}
+
+String InputEventMouseMotion::as_text() const {
+
+ String button_mask_string = "";
+ switch (get_button_mask()) {
+ case BUTTON_MASK_LEFT:
+ button_mask_string = "BUTTON_MASK_LEFT";
+ break;
+ case BUTTON_MASK_MIDDLE:
+ button_mask_string = "BUTTON_MASK_MIDDLE";
+ break;
+ case BUTTON_MASK_RIGHT:
+ button_mask_string = "BUTTON_MASK_RIGHT";
+ break;
+ case BUTTON_MASK_XBUTTON1:
+ button_mask_string = "BUTTON_MASK_XBUTTON1";
+ break;
+ case BUTTON_MASK_XBUTTON2:
+ button_mask_string = "BUTTON_MASK_XBUTTON2";
+ break;
+ default:
+ button_mask_string = itos(get_button_mask());
+ break;
+ }
+ return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")";
+}
+
+bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
+
+ Ref<InputEventMouseMotion> motion = p_event;
+ if (motion.is_null())
+ return false;
+
+ if (get_window_id() != motion->get_window_id()) {
+ return false;
+ }
+
+ if (is_pressed() != motion->is_pressed()) {
+ return false;
+ }
+
+ if (get_button_mask() != motion->get_button_mask()) {
+ return false;
+ }
+
+ if (get_shift() != motion->get_shift()) {
+ return false;
+ }
+
+ if (get_control() != motion->get_control()) {
+ return false;
+ }
+
+ if (get_alt() != motion->get_alt()) {
+ return false;
+ }
+
+ if (get_metakey() != motion->get_metakey()) {
+ return false;
+ }
+
+ set_position(motion->get_position());
+ set_global_position(motion->get_global_position());
+ set_speed(motion->get_speed());
+ relative += motion->get_relative();
+
+ return true;
+}
+
+void InputEventMouseMotion::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_tilt", "tilt"), &InputEventMouseMotion::set_tilt);
+ ClassDB::bind_method(D_METHOD("get_tilt"), &InputEventMouseMotion::get_tilt);
+
+ ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMouseMotion::set_pressure);
+ ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMouseMotion::get_pressure);
+
+ ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventMouseMotion::set_relative);
+ ClassDB::bind_method(D_METHOD("get_relative"), &InputEventMouseMotion::get_relative);
+
+ ClassDB::bind_method(D_METHOD("set_speed", "speed"), &InputEventMouseMotion::set_speed);
+ ClassDB::bind_method(D_METHOD("get_speed"), &InputEventMouseMotion::get_speed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "speed"), "set_speed", "get_speed");
+}
+
+InputEventMouseMotion::InputEventMouseMotion() {
+
+ pressure = 0;
+}
+
+////////////////////////////////////////
+
+void InputEventJoypadMotion::set_axis(int p_axis) {
+
+ axis = p_axis;
+}
+
+int InputEventJoypadMotion::get_axis() const {
+
+ return axis;
+}
+
+void InputEventJoypadMotion::set_axis_value(float p_value) {
+
+ axis_value = p_value;
+}
+
+float InputEventJoypadMotion::get_axis_value() const {
+
+ return axis_value;
+}
+
+bool InputEventJoypadMotion::is_pressed() const {
+
+ return Math::abs(axis_value) >= 0.5f;
+}
+
+bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+
+ Ref<InputEventJoypadMotion> jm = p_event;
+ if (jm.is_null())
+ return false;
+
+ bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event.
+ if (match) {
+ bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0);
+ bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
+ if (p_pressed != nullptr)
+ *p_pressed = pressed;
+ if (p_strength != nullptr) {
+ if (pressed) {
+ if (p_deadzone == 1.0f) {
+ *p_strength = 1.0f;
+ } else {
+ *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
+ }
+ } else {
+ *p_strength = 0.0f;
+ }
+ }
+ }
+ return match;
+}
+
+String InputEventJoypadMotion::as_text() const {
+
+ return "InputEventJoypadMotion : axis=" + itos(axis) + ", axis_value=" + String(Variant(axis_value));
+}
+
+void InputEventJoypadMotion::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_axis", "axis"), &InputEventJoypadMotion::set_axis);
+ ClassDB::bind_method(D_METHOD("get_axis"), &InputEventJoypadMotion::get_axis);
+
+ ClassDB::bind_method(D_METHOD("set_axis_value", "axis_value"), &InputEventJoypadMotion::set_axis_value);
+ ClassDB::bind_method(D_METHOD("get_axis_value"), &InputEventJoypadMotion::get_axis_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "axis"), "set_axis", "get_axis");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "axis_value"), "set_axis_value", "get_axis_value");
+}
+
+InputEventJoypadMotion::InputEventJoypadMotion() {
+
+ axis = 0;
+ axis_value = 0;
+}
+/////////////////////////////////
+
+void InputEventJoypadButton::set_button_index(int p_index) {
+
+ button_index = p_index;
+}
+
+int InputEventJoypadButton::get_button_index() const {
+
+ return button_index;
+}
+
+void InputEventJoypadButton::set_pressed(bool p_pressed) {
+
+ pressed = p_pressed;
+}
+bool InputEventJoypadButton::is_pressed() const {
+
+ return pressed;
+}
+
+void InputEventJoypadButton::set_pressure(float p_pressure) {
+
+ pressure = p_pressure;
+}
+float InputEventJoypadButton::get_pressure() const {
+
+ return pressure;
+}
+
+bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+
+ Ref<InputEventJoypadButton> jb = p_event;
+ if (jb.is_null())
+ return false;
+
+ bool match = button_index == jb->button_index;
+ if (match) {
+ if (p_pressed != nullptr)
+ *p_pressed = jb->is_pressed();
+ if (p_strength != nullptr)
+ *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ }
+
+ return match;
+}
+
+bool InputEventJoypadButton::shortcut_match(const Ref<InputEvent> &p_event) const {
+
+ Ref<InputEventJoypadButton> button = p_event;
+ if (button.is_null())
+ return false;
+
+ return button_index == button->button_index;
+}
+
+String InputEventJoypadButton::as_text() const {
+
+ return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure));
+}
+
+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);
+
+ ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventJoypadButton::set_pressure);
+ ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventJoypadButton::get_pressure);
+
+ ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventJoypadButton::set_pressed);
+ // ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventJoypadButton::is_pressed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+}
+
+InputEventJoypadButton::InputEventJoypadButton() {
+
+ button_index = 0;
+ pressure = 0;
+ pressed = false;
+}
+
+//////////////////////////////////////////////
+
+void InputEventScreenTouch::set_index(int p_index) {
+
+ index = p_index;
+}
+int InputEventScreenTouch::get_index() const {
+
+ return index;
+}
+
+void InputEventScreenTouch::set_position(const Vector2 &p_pos) {
+
+ pos = p_pos;
+}
+Vector2 InputEventScreenTouch::get_position() const {
+
+ return pos;
+}
+
+void InputEventScreenTouch::set_pressed(bool p_pressed) {
+
+ pressed = p_pressed;
+}
+bool InputEventScreenTouch::is_pressed() const {
+
+ return pressed;
+}
+
+Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_device(get_device());
+ st->set_window_id(get_window_id());
+ st->set_index(index);
+ st->set_position(p_xform.xform(pos + p_local_ofs));
+ st->set_pressed(pressed);
+
+ return st;
+}
+
+String InputEventScreenTouch::as_text() const {
+
+ return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + ")";
+}
+
+void InputEventScreenTouch::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenTouch::set_index);
+ ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenTouch::get_index);
+
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenTouch::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenTouch::get_position);
+
+ ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed);
+ //ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+}
+
+InputEventScreenTouch::InputEventScreenTouch() {
+
+ index = 0;
+ pressed = false;
+}
+
+/////////////////////////////
+
+void InputEventScreenDrag::set_index(int p_index) {
+
+ index = p_index;
+}
+
+int InputEventScreenDrag::get_index() const {
+
+ return index;
+}
+
+void InputEventScreenDrag::set_position(const Vector2 &p_pos) {
+
+ pos = p_pos;
+}
+Vector2 InputEventScreenDrag::get_position() const {
+
+ return pos;
+}
+
+void InputEventScreenDrag::set_relative(const Vector2 &p_relative) {
+
+ relative = p_relative;
+}
+Vector2 InputEventScreenDrag::get_relative() const {
+
+ return relative;
+}
+
+void InputEventScreenDrag::set_speed(const Vector2 &p_speed) {
+
+ speed = p_speed;
+}
+Vector2 InputEventScreenDrag::get_speed() const {
+
+ return speed;
+}
+
+Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ Ref<InputEventScreenDrag> sd;
+
+ sd.instance();
+
+ sd->set_device(get_device());
+ sd->set_window_id(get_window_id());
+
+ sd->set_index(index);
+ sd->set_position(p_xform.xform(pos + p_local_ofs));
+ sd->set_relative(p_xform.basis_xform(relative));
+ sd->set_speed(p_xform.basis_xform(speed));
+
+ return sd;
+}
+
+String InputEventScreenDrag::as_text() const {
+
+ return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")";
+}
+
+void InputEventScreenDrag::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenDrag::set_index);
+ ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenDrag::get_index);
+
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenDrag::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenDrag::get_position);
+
+ ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventScreenDrag::set_relative);
+ ClassDB::bind_method(D_METHOD("get_relative"), &InputEventScreenDrag::get_relative);
+
+ ClassDB::bind_method(D_METHOD("set_speed", "speed"), &InputEventScreenDrag::set_speed);
+ ClassDB::bind_method(D_METHOD("get_speed"), &InputEventScreenDrag::get_speed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "speed"), "set_speed", "get_speed");
+}
+
+InputEventScreenDrag::InputEventScreenDrag() {
+
+ index = 0;
+}
+/////////////////////////////
+
+void InputEventAction::set_action(const StringName &p_action) {
+
+ action = p_action;
+}
+StringName InputEventAction::get_action() const {
+
+ return action;
+}
+
+void InputEventAction::set_pressed(bool p_pressed) {
+
+ pressed = p_pressed;
+}
+bool InputEventAction::is_pressed() const {
+
+ return pressed;
+}
+
+void InputEventAction::set_strength(float p_strength) {
+ strength = CLAMP(p_strength, 0.0f, 1.0f);
+}
+
+float InputEventAction::get_strength() const {
+ return strength;
+}
+
+bool InputEventAction::shortcut_match(const Ref<InputEvent> &p_event) const {
+ if (p_event.is_null())
+ return false;
+
+ return p_event->is_action(action);
+}
+
+bool InputEventAction::is_action(const StringName &p_action) const {
+
+ return action == p_action;
+}
+
+bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+
+ Ref<InputEventAction> act = p_event;
+ if (act.is_null())
+ return false;
+
+ bool match = action == act->action;
+ if (match) {
+ if (p_pressed != nullptr)
+ *p_pressed = act->pressed;
+ if (p_strength != nullptr)
+ *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ }
+ return match;
+}
+
+String InputEventAction::as_text() const {
+
+ return "InputEventAction : action=" + action + ", pressed=(" + (pressed ? "true" : "false");
+}
+
+void InputEventAction::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_action", "action"), &InputEventAction::set_action);
+ ClassDB::bind_method(D_METHOD("get_action"), &InputEventAction::get_action);
+
+ ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventAction::set_pressed);
+ //ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventAction::is_pressed);
+
+ ClassDB::bind_method(D_METHOD("set_strength", "strength"), &InputEventAction::set_strength);
+ ClassDB::bind_method(D_METHOD("get_strength"), &InputEventAction::get_strength);
+
+ // ClassDB::bind_method(D_METHOD("is_action", "name"), &InputEventAction::is_action);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action"), "set_action", "get_action");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_strength", "get_strength");
+}
+
+InputEventAction::InputEventAction() {
+ pressed = false;
+ strength = 1.0f;
+}
+/////////////////////////////
+
+void InputEventGesture::set_position(const Vector2 &p_pos) {
+
+ pos = p_pos;
+}
+
+void InputEventGesture::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventGesture::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &InputEventGesture::get_position);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
+}
+
+Vector2 InputEventGesture::get_position() const {
+
+ return pos;
+}
+/////////////////////////////
+
+void InputEventMagnifyGesture::set_factor(real_t p_factor) {
+
+ factor = p_factor;
+}
+
+real_t InputEventMagnifyGesture::get_factor() const {
+
+ return factor;
+}
+
+Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ Ref<InputEventMagnifyGesture> ev;
+ ev.instance();
+
+ ev->set_device(get_device());
+ ev->set_window_id(get_window_id());
+
+ ev->set_modifiers_from_event(this);
+
+ ev->set_position(p_xform.xform(get_position() + p_local_ofs));
+ ev->set_factor(get_factor());
+
+ return ev;
+}
+
+String InputEventMagnifyGesture::as_text() const {
+
+ return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")";
+}
+
+void InputEventMagnifyGesture::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_factor", "factor"), &InputEventMagnifyGesture::set_factor);
+ ClassDB::bind_method(D_METHOD("get_factor"), &InputEventMagnifyGesture::get_factor);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "factor"), "set_factor", "get_factor");
+}
+
+InputEventMagnifyGesture::InputEventMagnifyGesture() {
+
+ factor = 1.0;
+}
+/////////////////////////////
+
+void InputEventPanGesture::set_delta(const Vector2 &p_delta) {
+
+ delta = p_delta;
+}
+
+Vector2 InputEventPanGesture::get_delta() const {
+ return delta;
+}
+
+Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
+
+ Ref<InputEventPanGesture> ev;
+ ev.instance();
+
+ ev->set_device(get_device());
+ ev->set_window_id(get_window_id());
+
+ ev->set_modifiers_from_event(this);
+
+ ev->set_position(p_xform.xform(get_position() + p_local_ofs));
+ ev->set_delta(get_delta());
+
+ return ev;
+}
+
+String InputEventPanGesture::as_text() const {
+
+ return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")";
+}
+
+void InputEventPanGesture::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_delta", "delta"), &InputEventPanGesture::set_delta);
+ ClassDB::bind_method(D_METHOD("get_delta"), &InputEventPanGesture::get_delta);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "delta"), "set_delta", "get_delta");
+}
+
+InputEventPanGesture::InputEventPanGesture() {
+
+ delta = Vector2(0, 0);
+}
+/////////////////////////////
+
+void InputEventMIDI::set_channel(const int p_channel) {
+
+ channel = p_channel;
+}
+
+int InputEventMIDI::get_channel() const {
+ return channel;
+}
+
+void InputEventMIDI::set_message(const int p_message) {
+
+ message = p_message;
+}
+
+int InputEventMIDI::get_message() const {
+ return message;
+}
+
+void InputEventMIDI::set_pitch(const int p_pitch) {
+
+ pitch = p_pitch;
+}
+
+int InputEventMIDI::get_pitch() const {
+ return pitch;
+}
+
+void InputEventMIDI::set_velocity(const int p_velocity) {
+
+ velocity = p_velocity;
+}
+
+int InputEventMIDI::get_velocity() const {
+ return velocity;
+}
+
+void InputEventMIDI::set_instrument(const int p_instrument) {
+
+ instrument = p_instrument;
+}
+
+int InputEventMIDI::get_instrument() const {
+ return instrument;
+}
+
+void InputEventMIDI::set_pressure(const int p_pressure) {
+
+ pressure = p_pressure;
+}
+
+int InputEventMIDI::get_pressure() const {
+ return pressure;
+}
+
+void InputEventMIDI::set_controller_number(const int p_controller_number) {
+
+ controller_number = p_controller_number;
+}
+
+int InputEventMIDI::get_controller_number() const {
+ return controller_number;
+}
+
+void InputEventMIDI::set_controller_value(const int p_controller_value) {
+
+ controller_value = p_controller_value;
+}
+
+int InputEventMIDI::get_controller_value() const {
+ return controller_value;
+}
+
+String InputEventMIDI::as_text() const {
+
+ return "InputEventMIDI : channel=(" + itos(get_channel()) + "), message=(" + itos(get_message()) + ")";
+}
+
+void InputEventMIDI::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_channel", "channel"), &InputEventMIDI::set_channel);
+ ClassDB::bind_method(D_METHOD("get_channel"), &InputEventMIDI::get_channel);
+ ClassDB::bind_method(D_METHOD("set_message", "message"), &InputEventMIDI::set_message);
+ ClassDB::bind_method(D_METHOD("get_message"), &InputEventMIDI::get_message);
+ ClassDB::bind_method(D_METHOD("set_pitch", "pitch"), &InputEventMIDI::set_pitch);
+ ClassDB::bind_method(D_METHOD("get_pitch"), &InputEventMIDI::get_pitch);
+ ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &InputEventMIDI::set_velocity);
+ ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventMIDI::get_velocity);
+ ClassDB::bind_method(D_METHOD("set_instrument", "instrument"), &InputEventMIDI::set_instrument);
+ ClassDB::bind_method(D_METHOD("get_instrument"), &InputEventMIDI::get_instrument);
+ ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMIDI::set_pressure);
+ ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMIDI::get_pressure);
+ ClassDB::bind_method(D_METHOD("set_controller_number", "controller_number"), &InputEventMIDI::set_controller_number);
+ ClassDB::bind_method(D_METHOD("get_controller_number"), &InputEventMIDI::get_controller_number);
+ ClassDB::bind_method(D_METHOD("set_controller_value", "controller_value"), &InputEventMIDI::set_controller_value);
+ ClassDB::bind_method(D_METHOD("get_controller_value"), &InputEventMIDI::get_controller_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "channel"), "set_channel", "get_channel");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "message"), "set_message", "get_message");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pitch"), "set_pitch", "get_pitch");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "velocity"), "set_velocity", "get_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "instrument"), "set_instrument", "get_instrument");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pressure"), "set_pressure", "get_pressure");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_number"), "set_controller_number", "get_controller_number");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_value"), "set_controller_value", "get_controller_value");
+}
+
+InputEventMIDI::InputEventMIDI() {
+
+ channel = 0;
+ message = 0;
+ pitch = 0;
+ velocity = 0;
+ instrument = 0;
+ pressure = 0;
+ controller_number = 0;
+ controller_value = 0;
+}
diff --git a/core/input/input_event.h b/core/input/input_event.h
new file mode 100644
index 0000000000..2fdcdd0319
--- /dev/null
+++ b/core/input/input_event.h
@@ -0,0 +1,641 @@
+/*************************************************************************/
+/* input_event.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 INPUT_EVENT_H
+#define INPUT_EVENT_H
+
+#include "core/math/transform_2d.h"
+#include "core/os/copymem.h"
+#include "core/resource.h"
+#include "core/typedefs.h"
+#include "core/ustring.h"
+
+/**
+ * Input Event classes. These are used in the main loop.
+ * 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 JoystickList {
+
+ JOY_BUTTON_0 = 0,
+ JOY_BUTTON_1 = 1,
+ JOY_BUTTON_2 = 2,
+ JOY_BUTTON_3 = 3,
+ JOY_BUTTON_4 = 4,
+ JOY_BUTTON_5 = 5,
+ JOY_BUTTON_6 = 6,
+ JOY_BUTTON_7 = 7,
+ JOY_BUTTON_8 = 8,
+ JOY_BUTTON_9 = 9,
+ JOY_BUTTON_10 = 10,
+ JOY_BUTTON_11 = 11,
+ JOY_BUTTON_12 = 12,
+ JOY_BUTTON_13 = 13,
+ JOY_BUTTON_14 = 14,
+ JOY_BUTTON_15 = 15,
+ JOY_BUTTON_MAX = 16,
+
+ JOY_L = JOY_BUTTON_4,
+ JOY_R = JOY_BUTTON_5,
+ JOY_L2 = JOY_BUTTON_6,
+ JOY_R2 = JOY_BUTTON_7,
+ JOY_L3 = JOY_BUTTON_8,
+ JOY_R3 = JOY_BUTTON_9,
+ JOY_SELECT = JOY_BUTTON_10,
+ JOY_START = JOY_BUTTON_11,
+ JOY_DPAD_UP = JOY_BUTTON_12,
+ JOY_DPAD_DOWN = JOY_BUTTON_13,
+ JOY_DPAD_LEFT = JOY_BUTTON_14,
+ JOY_DPAD_RIGHT = JOY_BUTTON_15,
+
+ JOY_SONY_CIRCLE = JOY_BUTTON_1,
+ JOY_SONY_X = JOY_BUTTON_0,
+ JOY_SONY_SQUARE = JOY_BUTTON_2,
+ JOY_SONY_TRIANGLE = JOY_BUTTON_3,
+
+ JOY_XBOX_A = JOY_BUTTON_0,
+ JOY_XBOX_B = JOY_BUTTON_1,
+ JOY_XBOX_X = JOY_BUTTON_2,
+ JOY_XBOX_Y = JOY_BUTTON_3,
+
+ JOY_DS_A = JOY_BUTTON_1,
+ JOY_DS_B = JOY_BUTTON_0,
+ JOY_DS_X = JOY_BUTTON_3,
+ JOY_DS_Y = JOY_BUTTON_2,
+
+ JOY_WII_C = JOY_BUTTON_5,
+ JOY_WII_Z = JOY_BUTTON_6,
+
+ JOY_WII_MINUS = JOY_BUTTON_10,
+ JOY_WII_PLUS = JOY_BUTTON_11,
+
+ JOY_VR_GRIP = JOY_BUTTON_2,
+ JOY_VR_PAD = JOY_BUTTON_14,
+ JOY_VR_TRIGGER = JOY_BUTTON_15,
+
+ JOY_OCULUS_AX = JOY_BUTTON_7,
+ JOY_OCULUS_BY = JOY_BUTTON_1,
+ JOY_OCULUS_MENU = JOY_BUTTON_3,
+
+ JOY_OPENVR_MENU = JOY_BUTTON_1,
+
+ // end of history
+
+ JOY_AXIS_0 = 0,
+ JOY_AXIS_1 = 1,
+ JOY_AXIS_2 = 2,
+ JOY_AXIS_3 = 3,
+ JOY_AXIS_4 = 4,
+ JOY_AXIS_5 = 5,
+ JOY_AXIS_6 = 6,
+ JOY_AXIS_7 = 7,
+ JOY_AXIS_8 = 8,
+ JOY_AXIS_9 = 9,
+ JOY_AXIS_MAX = 10,
+
+ JOY_ANALOG_LX = JOY_AXIS_0,
+ JOY_ANALOG_LY = JOY_AXIS_1,
+
+ JOY_ANALOG_RX = JOY_AXIS_2,
+ JOY_ANALOG_RY = JOY_AXIS_3,
+
+ JOY_ANALOG_L2 = JOY_AXIS_6,
+ JOY_ANALOG_R2 = JOY_AXIS_7,
+
+ JOY_VR_ANALOG_TRIGGER = JOY_AXIS_2,
+ JOY_VR_ANALOG_GRIP = JOY_AXIS_4,
+
+ JOY_OPENVR_TOUCHPADX = JOY_AXIS_0,
+ JOY_OPENVR_TOUCHPADY = JOY_AXIS_1,
+};
+
+enum MidiMessageList {
+ MIDI_MESSAGE_NOTE_OFF = 0x8,
+ MIDI_MESSAGE_NOTE_ON = 0x9,
+ MIDI_MESSAGE_AFTERTOUCH = 0xA,
+ MIDI_MESSAGE_CONTROL_CHANGE = 0xB,
+ MIDI_MESSAGE_PROGRAM_CHANGE = 0xC,
+ MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD,
+ MIDI_MESSAGE_PITCH_BEND = 0xE,
+};
+
+/**
+ * Input Modifier Status
+ * for keyboard/mouse events.
+ */
+
+class InputEvent : public Resource {
+ GDCLASS(InputEvent, Resource);
+
+ int device;
+
+protected:
+ static void _bind_methods();
+
+public:
+ static const int DEVICE_ID_TOUCH_MOUSE;
+ static const int DEVICE_ID_INTERNAL;
+
+ 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;
+
+ // To be removed someday, since they do not make sense for all events
+ virtual bool is_pressed() const;
+ virtual bool is_echo() const;
+ // ...-.
+
+ virtual String as_text() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
+ virtual bool is_action_type() const;
+
+ virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; }
+ InputEvent();
+};
+
+class InputEventFromWindow : public InputEvent {
+
+ GDCLASS(InputEventFromWindow, InputEvent);
+
+ int64_t window_id;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_window_id(int64_t p_id);
+ int64_t get_window_id() const;
+
+ InputEventFromWindow();
+};
+
+class InputEventWithModifiers : public InputEventFromWindow {
+ GDCLASS(InputEventWithModifiers, InputEventFromWindow);
+
+ bool shift;
+ bool alt;
+#ifdef APPLE_STYLE_KEYS
+ union {
+ bool command;
+ bool meta; //< windows/mac key
+ };
+
+ bool control;
+#else
+ union {
+ bool command; //< windows/mac key
+ bool control;
+ };
+ bool meta; //< windows/mac key
+
+#endif
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_shift(bool p_enabled);
+ bool get_shift() const;
+
+ void set_alt(bool p_enabled);
+ bool get_alt() const;
+
+ void set_control(bool p_enabled);
+ bool get_control() const;
+
+ void set_metakey(bool p_enabled);
+ bool get_metakey() const;
+
+ void set_command(bool p_enabled);
+ bool get_command() const;
+
+ void set_modifiers_from_event(const InputEventWithModifiers *event);
+
+ InputEventWithModifiers();
+};
+
+class InputEventKey : public InputEventWithModifiers {
+
+ GDCLASS(InputEventKey, InputEventWithModifiers);
+
+ bool pressed; /// otherwise release
+
+ uint32_t keycode; ///< check keyboard.h , KeyCode enum, without modifier masks
+ uint32_t physical_keycode;
+ uint32_t unicode; ///unicode
+
+ bool echo; /// true if this is an echo key
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_pressed(bool p_pressed);
+ virtual bool is_pressed() const;
+
+ void set_keycode(uint32_t p_keycode);
+ uint32_t get_keycode() const;
+
+ void set_physical_keycode(uint32_t p_keycode);
+ uint32_t get_physical_keycode() const;
+
+ void set_unicode(uint32_t p_unicode);
+ uint32_t get_unicode() const;
+
+ void set_echo(bool p_enable);
+ virtual bool is_echo() const;
+
+ uint32_t get_keycode_with_modifiers() const;
+ uint32_t get_physical_keycode_with_modifiers() const;
+
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
+
+ virtual bool is_action_type() const { return true; }
+
+ virtual String as_text() const;
+
+ InputEventKey();
+};
+
+class InputEventMouse : public InputEventWithModifiers {
+
+ GDCLASS(InputEventMouse, InputEventWithModifiers);
+
+ int button_mask;
+
+ Vector2 pos;
+ Vector2 global_pos;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_button_mask(int p_mask);
+ int get_button_mask() const;
+
+ void set_position(const Vector2 &p_pos);
+ Vector2 get_position() const;
+
+ void set_global_position(const Vector2 &p_global_pos);
+ Vector2 get_global_position() const;
+
+ InputEventMouse();
+};
+
+class InputEventMouseButton : public InputEventMouse {
+
+ GDCLASS(InputEventMouseButton, InputEventMouse);
+
+ float factor;
+ int button_index;
+ bool pressed; //otherwise released
+ bool doubleclick; //last even less than doubleclick time
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_factor(float p_factor);
+ float get_factor();
+
+ void set_button_index(int p_index);
+ int get_button_index() const;
+
+ void set_pressed(bool p_pressed);
+ virtual bool is_pressed() const;
+
+ void set_doubleclick(bool p_doubleclick);
+ bool is_doubleclick() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+
+ virtual bool is_action_type() const { return true; }
+ virtual String as_text() const;
+
+ InputEventMouseButton();
+};
+
+class InputEventMouseMotion : public InputEventMouse {
+
+ GDCLASS(InputEventMouseMotion, InputEventMouse);
+
+ Vector2 tilt;
+ float pressure;
+ Vector2 relative;
+ Vector2 speed;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_tilt(const Vector2 &p_tilt);
+ Vector2 get_tilt() const;
+
+ void set_pressure(float p_pressure);
+ float get_pressure() const;
+
+ void set_relative(const Vector2 &p_relative);
+ Vector2 get_relative() const;
+
+ void set_speed(const Vector2 &p_speed);
+ Vector2 get_speed() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+ virtual String as_text() const;
+
+ virtual bool accumulate(const Ref<InputEvent> &p_event);
+
+ InputEventMouseMotion();
+};
+
+class InputEventJoypadMotion : public InputEvent {
+
+ GDCLASS(InputEventJoypadMotion, InputEvent);
+ int axis; ///< Joypad axis
+ float axis_value; ///< -1 to 1
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_axis(int p_axis);
+ int get_axis() const;
+
+ void set_axis_value(float p_value);
+ float get_axis_value() const;
+
+ virtual bool is_pressed() const;
+
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+
+ virtual bool is_action_type() const { return true; }
+ virtual String as_text() const;
+
+ InputEventJoypadMotion();
+};
+
+class InputEventJoypadButton : public InputEvent {
+ GDCLASS(InputEventJoypadButton, InputEvent);
+
+ int button_index;
+ bool pressed;
+ float pressure; //0 to 1
+protected:
+ static void _bind_methods();
+
+public:
+ void set_button_index(int p_index);
+ int get_button_index() const;
+
+ void set_pressed(bool p_pressed);
+ virtual bool is_pressed() const;
+
+ void set_pressure(float p_pressure);
+ float get_pressure() const;
+
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
+
+ virtual bool is_action_type() const { return true; }
+ virtual String as_text() const;
+
+ InputEventJoypadButton();
+};
+
+class InputEventScreenTouch : public InputEventFromWindow {
+ GDCLASS(InputEventScreenTouch, InputEventFromWindow);
+ int index;
+ Vector2 pos;
+ bool pressed;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_index(int p_index);
+ int get_index() const;
+
+ void set_position(const Vector2 &p_pos);
+ Vector2 get_position() const;
+
+ void set_pressed(bool p_pressed);
+ virtual bool is_pressed() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+ virtual String as_text() const;
+
+ InputEventScreenTouch();
+};
+
+class InputEventScreenDrag : public InputEventFromWindow {
+
+ GDCLASS(InputEventScreenDrag, InputEventFromWindow);
+ int index;
+ Vector2 pos;
+ Vector2 relative;
+ Vector2 speed;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_index(int p_index);
+ int get_index() const;
+
+ void set_position(const Vector2 &p_pos);
+ Vector2 get_position() const;
+
+ void set_relative(const Vector2 &p_relative);
+ Vector2 get_relative() const;
+
+ void set_speed(const Vector2 &p_speed);
+ Vector2 get_speed() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+ virtual String as_text() const;
+
+ InputEventScreenDrag();
+};
+
+class InputEventAction : public InputEvent {
+
+ GDCLASS(InputEventAction, InputEvent);
+
+ StringName action;
+ bool pressed;
+ float strength;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_action(const StringName &p_action);
+ StringName get_action() const;
+
+ void set_pressed(bool p_pressed);
+ virtual bool is_pressed() const;
+
+ void set_strength(float p_strength);
+ float get_strength() const;
+
+ virtual bool is_action(const StringName &p_action) const;
+
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
+ virtual bool is_action_type() const { return true; }
+ virtual String as_text() const;
+
+ InputEventAction();
+};
+
+class InputEventGesture : public InputEventWithModifiers {
+
+ GDCLASS(InputEventGesture, InputEventWithModifiers);
+
+ Vector2 pos;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_position(const Vector2 &p_pos);
+ Vector2 get_position() const;
+};
+
+class InputEventMagnifyGesture : public InputEventGesture {
+
+ GDCLASS(InputEventMagnifyGesture, InputEventGesture);
+ real_t factor;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_factor(real_t p_factor);
+ real_t get_factor() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+ virtual String as_text() const;
+
+ InputEventMagnifyGesture();
+};
+
+class InputEventPanGesture : public InputEventGesture {
+
+ GDCLASS(InputEventPanGesture, InputEventGesture);
+ Vector2 delta;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_delta(const Vector2 &p_delta);
+ Vector2 get_delta() const;
+
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
+ virtual String as_text() const;
+
+ InputEventPanGesture();
+};
+
+class InputEventMIDI : public InputEvent {
+ GDCLASS(InputEventMIDI, InputEvent);
+
+ int channel;
+ int message;
+ int pitch;
+ int velocity;
+ int instrument;
+ int pressure;
+ int controller_number;
+ int controller_value;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_channel(const int p_channel);
+ int get_channel() const;
+
+ void set_message(const int p_message);
+ int get_message() const;
+
+ void set_pitch(const int p_pitch);
+ int get_pitch() const;
+
+ void set_velocity(const int p_velocity);
+ int get_velocity() const;
+
+ void set_instrument(const int p_instrument);
+ int get_instrument() const;
+
+ void set_pressure(const int p_pressure);
+ int get_pressure() const;
+
+ void set_controller_number(const int p_controller_number);
+ int get_controller_number() const;
+
+ void set_controller_value(const int p_controller_value);
+ int get_controller_value() const;
+
+ virtual String as_text() const;
+
+ InputEventMIDI();
+};
+
+#endif // INPUT_EVENT_H
diff --git a/core/input/input_filter.cpp b/core/input/input_filter.cpp
new file mode 100644
index 0000000000..2e8442a905
--- /dev/null
+++ b/core/input/input_filter.cpp
@@ -0,0 +1,1309 @@
+/*************************************************************************/
+/* input_filter.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_filter.h"
+
+#include "core/input/default_controller_mappings.h"
+#include "core/input/input_map.h"
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
+InputFilter *InputFilter::singleton = nullptr;
+
+void (*InputFilter::set_mouse_mode_func)(InputFilter::MouseMode) = nullptr;
+InputFilter::MouseMode (*InputFilter::get_mouse_mode_func)() = nullptr;
+void (*InputFilter::warp_mouse_func)(const Vector2 &p_to_pos) = nullptr;
+InputFilter::CursorShape (*InputFilter::get_current_cursor_shape_func)() = nullptr;
+void (*InputFilter::set_custom_mouse_cursor_func)(const RES &, InputFilter::CursorShape, const Vector2 &) = nullptr;
+
+InputFilter *InputFilter::get_singleton() {
+
+ return singleton;
+}
+
+void InputFilter::set_mouse_mode(MouseMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 4);
+ set_mouse_mode_func(p_mode);
+}
+
+InputFilter::MouseMode InputFilter::get_mouse_mode() const {
+
+ return get_mouse_mode_func();
+}
+
+void InputFilter::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &InputFilter::is_key_pressed);
+ ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &InputFilter::is_mouse_button_pressed);
+ ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &InputFilter::is_joy_button_pressed);
+ ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &InputFilter::is_action_pressed);
+ ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &InputFilter::is_action_just_pressed);
+ ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &InputFilter::is_action_just_released);
+ ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputFilter::get_action_strength);
+ ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &InputFilter::add_joy_mapping, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &InputFilter::remove_joy_mapping);
+ ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &InputFilter::joy_connection_changed);
+ ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &InputFilter::is_joy_known);
+ ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &InputFilter::get_joy_axis);
+ ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &InputFilter::get_joy_name);
+ ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &InputFilter::get_joy_guid);
+ ClassDB::bind_method(D_METHOD("get_connected_joypads"), &InputFilter::get_connected_joypads);
+ ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &InputFilter::get_joy_vibration_strength);
+ ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &InputFilter::get_joy_vibration_duration);
+ ClassDB::bind_method(D_METHOD("get_joy_button_string", "button_index"), &InputFilter::get_joy_button_string);
+ ClassDB::bind_method(D_METHOD("get_joy_button_index_from_string", "button"), &InputFilter::get_joy_button_index_from_string);
+ ClassDB::bind_method(D_METHOD("get_joy_axis_string", "axis_index"), &InputFilter::get_joy_axis_string);
+ ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &InputFilter::get_joy_axis_index_from_string);
+ ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &InputFilter::start_joy_vibration, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &InputFilter::stop_joy_vibration);
+ ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &InputFilter::vibrate_handheld, DEFVAL(500));
+ ClassDB::bind_method(D_METHOD("get_gravity"), &InputFilter::get_gravity);
+ ClassDB::bind_method(D_METHOD("get_accelerometer"), &InputFilter::get_accelerometer);
+ ClassDB::bind_method(D_METHOD("get_magnetometer"), &InputFilter::get_magnetometer);
+ ClassDB::bind_method(D_METHOD("get_gyroscope"), &InputFilter::get_gyroscope);
+ ClassDB::bind_method(D_METHOD("get_last_mouse_speed"), &InputFilter::get_last_mouse_speed);
+ ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &InputFilter::get_mouse_button_mask);
+ ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &InputFilter::set_mouse_mode);
+ ClassDB::bind_method(D_METHOD("get_mouse_mode"), &InputFilter::get_mouse_mode);
+ ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &InputFilter::warp_mouse_position);
+ ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &InputFilter::action_press, DEFVAL(1.f));
+ ClassDB::bind_method(D_METHOD("action_release", "action"), &InputFilter::action_release);
+ ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &InputFilter::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
+ ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &InputFilter::get_current_cursor_shape);
+ ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &InputFilter::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
+ ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &InputFilter::parse_input_event);
+ ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &InputFilter::set_use_accumulated_input);
+
+ BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+
+ BIND_ENUM_CONSTANT(CURSOR_ARROW);
+ BIND_ENUM_CONSTANT(CURSOR_IBEAM);
+ BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
+ BIND_ENUM_CONSTANT(CURSOR_CROSS);
+ BIND_ENUM_CONSTANT(CURSOR_WAIT);
+ BIND_ENUM_CONSTANT(CURSOR_BUSY);
+ BIND_ENUM_CONSTANT(CURSOR_DRAG);
+ BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
+ BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
+ BIND_ENUM_CONSTANT(CURSOR_VSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_HSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_MOVE);
+ BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
+ BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
+ BIND_ENUM_CONSTANT(CURSOR_HELP);
+
+ ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
+}
+
+void InputFilter::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+#ifdef TOOLS_ENABLED
+
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+
+ String pf = p_function;
+ if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
+
+ List<PropertyInfo> pinfo;
+ ProjectSettings::get_singleton()->get_property_list(&pinfo);
+
+ for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
+ const PropertyInfo &pi = E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+ String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
+ r_options->push_back(quote_style + name + quote_style);
+ }
+ }
+#endif
+}
+
+void InputFilter::SpeedTrack::update(const Vector2 &p_delta_p) {
+
+ uint64_t tick = OS::get_singleton()->get_ticks_usec();
+ uint32_t tdiff = tick - last_tick;
+ float delta_t = tdiff / 1000000.0;
+ last_tick = tick;
+
+ accum += p_delta_p;
+ accum_t += delta_t;
+
+ if (accum_t > max_ref_frame * 10)
+ accum_t = max_ref_frame * 10;
+
+ while (accum_t >= min_ref_frame) {
+
+ float slice_t = min_ref_frame / accum_t;
+ Vector2 slice = accum * slice_t;
+ accum = accum - slice;
+ accum_t -= min_ref_frame;
+
+ speed = (slice / min_ref_frame).linear_interpolate(speed, min_ref_frame / max_ref_frame);
+ }
+}
+
+void InputFilter::SpeedTrack::reset() {
+ last_tick = OS::get_singleton()->get_ticks_usec();
+ speed = Vector2();
+ accum_t = 0;
+}
+
+InputFilter::SpeedTrack::SpeedTrack() {
+
+ min_ref_frame = 0.1;
+ max_ref_frame = 0.3;
+ reset();
+}
+
+bool InputFilter::is_key_pressed(int p_keycode) const {
+
+ _THREAD_SAFE_METHOD_
+ return keys_pressed.has(p_keycode);
+}
+
+bool InputFilter::is_mouse_button_pressed(int p_button) const {
+
+ _THREAD_SAFE_METHOD_
+ return (mouse_button_mask & (1 << (p_button - 1))) != 0;
+}
+
+static int _combine_device(int p_value, int p_device) {
+
+ return p_value | (p_device << 20);
+}
+
+bool InputFilter::is_joy_button_pressed(int p_device, int p_button) const {
+
+ _THREAD_SAFE_METHOD_
+ return joy_buttons_pressed.has(_combine_device(p_button, p_device));
+}
+
+bool InputFilter::is_action_pressed(const StringName &p_action) const {
+
+ return action_state.has(p_action) && action_state[p_action].pressed;
+}
+
+bool InputFilter::is_action_just_pressed(const StringName &p_action) const {
+
+ const Map<StringName, Action>::Element *E = action_state.find(p_action);
+ if (!E)
+ 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 {
+ return E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames();
+ }
+}
+
+bool InputFilter::is_action_just_released(const StringName &p_action) const {
+
+ const Map<StringName, Action>::Element *E = action_state.find(p_action);
+ if (!E)
+ 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 {
+ return !E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames();
+ }
+}
+
+float InputFilter::get_action_strength(const StringName &p_action) const {
+ const Map<StringName, Action>::Element *E = action_state.find(p_action);
+ if (!E)
+ return 0.0f;
+
+ return E->get().strength;
+}
+
+float InputFilter::get_joy_axis(int p_device, int p_axis) const {
+
+ _THREAD_SAFE_METHOD_
+ int c = _combine_device(p_axis, p_device);
+ if (_joy_axis.has(c)) {
+ return _joy_axis[c];
+ } else {
+ return 0;
+ }
+}
+
+String InputFilter::get_joy_name(int p_idx) {
+
+ _THREAD_SAFE_METHOD_
+ return joy_names[p_idx].name;
+};
+
+Vector2 InputFilter::get_joy_vibration_strength(int p_device) {
+ if (joy_vibration.has(p_device)) {
+ return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
+ } else {
+ return Vector2(0, 0);
+ }
+}
+
+uint64_t InputFilter::get_joy_vibration_timestamp(int p_device) {
+ if (joy_vibration.has(p_device)) {
+ return joy_vibration[p_device].timestamp;
+ } else {
+ return 0;
+ }
+}
+
+float InputFilter::get_joy_vibration_duration(int p_device) {
+ if (joy_vibration.has(p_device)) {
+ return joy_vibration[p_device].duration;
+ } else {
+ return 0.f;
+ }
+}
+
+static String _hex_str(uint8_t p_byte) {
+
+ static const char *dict = "0123456789abcdef";
+ char ret[3];
+ ret[2] = 0;
+
+ ret[0] = dict[p_byte >> 4];
+ ret[1] = dict[p_byte & 0xf];
+
+ return ret;
+};
+
+void InputFilter::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
+
+ _THREAD_SAFE_METHOD_
+ Joypad js;
+ js.name = p_connected ? p_name : "";
+ js.uid = p_connected ? p_guid : "";
+
+ if (p_connected) {
+
+ String uidname = p_guid;
+ if (p_guid == "") {
+ int uidlen = MIN(p_name.length(), 16);
+ for (int i = 0; i < uidlen; i++) {
+ uidname = uidname + _hex_str(p_name[i]);
+ };
+ };
+ js.uid = uidname;
+ js.connected = true;
+ int mapping = fallback_mapping;
+ for (int i = 0; i < map_db.size(); i++) {
+ if (js.uid == map_db[i].uid) {
+ mapping = i;
+ js.name = map_db[i].name;
+ };
+ };
+ js.mapping = mapping;
+ } else {
+ js.connected = false;
+ for (int i = 0; i < JOY_BUTTON_MAX; i++) {
+
+ if (i < JOY_AXIS_MAX)
+ set_joy_axis(p_idx, i, 0.0f);
+
+ int c = _combine_device(i, p_idx);
+ joy_buttons_pressed.erase(c);
+ };
+ };
+ joy_names[p_idx] = js;
+
+ emit_signal("joy_connection_changed", p_idx, p_connected);
+};
+
+Vector3 InputFilter::get_gravity() const {
+
+ _THREAD_SAFE_METHOD_
+ return gravity;
+}
+
+Vector3 InputFilter::get_accelerometer() const {
+
+ _THREAD_SAFE_METHOD_
+ return accelerometer;
+}
+
+Vector3 InputFilter::get_magnetometer() const {
+
+ _THREAD_SAFE_METHOD_
+ return magnetometer;
+}
+
+Vector3 InputFilter::get_gyroscope() const {
+
+ _THREAD_SAFE_METHOD_
+ return gyroscope;
+}
+
+void InputFilter::parse_input_event(const Ref<InputEvent> &p_event) {
+
+ _parse_input_event_impl(p_event, false);
+}
+
+void InputFilter::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
+
+ // Notes on mouse-touch emulation:
+ // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
+ // as true mouse events. The only difference is the situation is flagged as emulated so they are not
+ // emulated back to touch events in an endless loop.
+ // - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
+ // require additional handling by this class.
+
+ _THREAD_SAFE_METHOD_
+
+ Ref<InputEventKey> k = p_event;
+ if (k.is_valid() && !k->is_echo() && k->get_keycode() != 0) {
+ if (k->is_pressed())
+ keys_pressed.insert(k->get_keycode());
+ else
+ keys_pressed.erase(k->get_keycode());
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+
+ if (mb->is_pressed()) {
+ mouse_button_mask |= (1 << (mb->get_button_index() - 1));
+ } else {
+ mouse_button_mask &= ~(1 << (mb->get_button_index() - 1));
+ }
+
+ Point2 pos = mb->get_global_position();
+ if (mouse_pos != pos) {
+ set_mouse_position(pos);
+ }
+
+ if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) {
+ Ref<InputEventScreenTouch> touch_event;
+ touch_event.instance();
+ touch_event->set_pressed(mb->is_pressed());
+ touch_event->set_position(mb->get_position());
+ event_dispatch_function(touch_event);
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+
+ Point2 pos = mm->get_global_position();
+ if (mouse_pos != pos) {
+ set_mouse_position(pos);
+ }
+
+ if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) {
+ Ref<InputEventScreenDrag> drag_event;
+ drag_event.instance();
+
+ drag_event->set_position(mm->get_position());
+ drag_event->set_relative(mm->get_relative());
+ drag_event->set_speed(mm->get_speed());
+
+ event_dispatch_function(drag_event);
+ }
+ }
+
+ Ref<InputEventScreenTouch> st = p_event;
+
+ if (st.is_valid()) {
+
+ if (st->is_pressed()) {
+ SpeedTrack &track = touch_speed_track[st->get_index()];
+ track.reset();
+ } else {
+ // Since a pointer index may not occur again (OSs may or may not reuse them),
+ // imperatively remove it from the map to keep no fossil entries in it
+ touch_speed_track.erase(st->get_index());
+ }
+
+ if (emulate_mouse_from_touch) {
+
+ bool translate = false;
+ if (st->is_pressed()) {
+ if (mouse_from_touch_index == -1) {
+ translate = true;
+ mouse_from_touch_index = st->get_index();
+ }
+ } else {
+ if (st->get_index() == mouse_from_touch_index) {
+ translate = true;
+ mouse_from_touch_index = -1;
+ }
+ }
+
+ if (translate) {
+ Ref<InputEventMouseButton> button_event;
+ button_event.instance();
+
+ button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
+ 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);
+ if (st->is_pressed()) {
+ button_event->set_button_mask(mouse_button_mask | (1 << (BUTTON_LEFT - 1)));
+ } else {
+ button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1)));
+ }
+
+ _parse_input_event_impl(button_event, true);
+ }
+ }
+ }
+
+ Ref<InputEventScreenDrag> sd = p_event;
+
+ if (sd.is_valid()) {
+
+ SpeedTrack &track = touch_speed_track[sd->get_index()];
+ track.update(sd->get_relative());
+ sd->set_speed(track.speed);
+
+ if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) {
+
+ Ref<InputEventMouseMotion> motion_event;
+ motion_event.instance();
+
+ motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
+ motion_event->set_position(sd->get_position());
+ motion_event->set_global_position(sd->get_position());
+ motion_event->set_relative(sd->get_relative());
+ motion_event->set_speed(sd->get_speed());
+ motion_event->set_button_mask(mouse_button_mask);
+
+ _parse_input_event_impl(motion_event, true);
+ }
+ }
+
+ Ref<InputEventJoypadButton> jb = p_event;
+
+ if (jb.is_valid()) {
+
+ int c = _combine_device(jb->get_button_index(), jb->get_device());
+
+ if (jb->is_pressed())
+ joy_buttons_pressed.insert(c);
+ else
+ joy_buttons_pressed.erase(c);
+ }
+
+ Ref<InputEventJoypadMotion> jm = p_event;
+
+ if (jm.is_valid()) {
+ set_joy_axis(jm->get_device(), jm->get_axis(), jm->get_axis_value());
+ }
+
+ Ref<InputEventGesture> ge = p_event;
+
+ if (ge.is_valid()) {
+
+ if (event_dispatch_function) {
+ event_dispatch_function(ge);
+ }
+ }
+
+ 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())) {
+ Action action;
+ action.physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.idle_frame = Engine::get_singleton()->get_idle_frames();
+ action.pressed = p_event->is_action_pressed(E->key());
+ action.strength = 0.f;
+ action_state[E->key()] = action;
+ }
+ action_state[E->key()].strength = p_event->get_action_strength(E->key());
+ }
+ }
+
+ if (event_dispatch_function)
+ event_dispatch_function(p_event);
+}
+
+void InputFilter::set_joy_axis(int p_device, int p_axis, float p_value) {
+
+ _THREAD_SAFE_METHOD_
+ int c = _combine_device(p_axis, p_device);
+ _joy_axis[c] = p_value;
+}
+
+void InputFilter::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
+ _THREAD_SAFE_METHOD_
+ if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
+ return;
+ }
+ VibrationInfo vibration;
+ vibration.weak_magnitude = p_weak_magnitude;
+ vibration.strong_magnitude = p_strong_magnitude;
+ vibration.duration = p_duration;
+ vibration.timestamp = OS::get_singleton()->get_ticks_usec();
+ joy_vibration[p_device] = vibration;
+}
+
+void InputFilter::stop_joy_vibration(int p_device) {
+ _THREAD_SAFE_METHOD_
+ VibrationInfo vibration;
+ vibration.weak_magnitude = 0;
+ vibration.strong_magnitude = 0;
+ vibration.duration = 0;
+ vibration.timestamp = OS::get_singleton()->get_ticks_usec();
+ joy_vibration[p_device] = vibration;
+}
+
+void InputFilter::vibrate_handheld(int p_duration_ms) {
+ OS::get_singleton()->vibrate_handheld(p_duration_ms);
+}
+
+void InputFilter::set_gravity(const Vector3 &p_gravity) {
+
+ _THREAD_SAFE_METHOD_
+
+ gravity = p_gravity;
+}
+
+void InputFilter::set_accelerometer(const Vector3 &p_accel) {
+
+ _THREAD_SAFE_METHOD_
+
+ accelerometer = p_accel;
+}
+
+void InputFilter::set_magnetometer(const Vector3 &p_magnetometer) {
+
+ _THREAD_SAFE_METHOD_
+
+ magnetometer = p_magnetometer;
+}
+
+void InputFilter::set_gyroscope(const Vector3 &p_gyroscope) {
+
+ _THREAD_SAFE_METHOD_
+
+ gyroscope = p_gyroscope;
+}
+
+void InputFilter::set_mouse_position(const Point2 &p_posf) {
+
+ mouse_speed_track.update(p_posf - mouse_pos);
+ mouse_pos = p_posf;
+}
+
+Point2 InputFilter::get_mouse_position() const {
+
+ return mouse_pos;
+}
+Point2 InputFilter::get_last_mouse_speed() const {
+
+ return mouse_speed_track.speed;
+}
+
+int InputFilter::get_mouse_button_mask() const {
+
+ return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
+}
+
+void InputFilter::warp_mouse_position(const Vector2 &p_to) {
+ warp_mouse_func(p_to);
+}
+
+Point2i InputFilter::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()
+ // 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.
+ // And due to this mouse warping mechanism being stateless, we need to apply some heuristics to
+ // detect the warp: if the relative distance is greater than the half of the size of the relevant rect
+ // (checked per each axis), it will be considered as the consequence of a former pointer warp.
+
+ const Point2i rel_sgn(p_motion->get_relative().x >= 0.0f ? 1 : -1, p_motion->get_relative().y >= 0.0 ? 1 : -1);
+ const Size2i warp_margin = p_rect.size * 0.5f;
+ const Point2i rel_warped(
+ Math::fmod(p_motion->get_relative().x + rel_sgn.x * warp_margin.x, p_rect.size.x) - rel_sgn.x * warp_margin.x,
+ Math::fmod(p_motion->get_relative().y + rel_sgn.y * warp_margin.y, p_rect.size.y) - rel_sgn.y * warp_margin.y);
+
+ const Point2i pos_local = p_motion->get_global_position() - p_rect.position;
+ const Point2i pos_warped(Math::fposmod(pos_local.x, p_rect.size.x), Math::fposmod(pos_local.y, p_rect.size.y));
+ if (pos_warped != pos_local) {
+ warp_mouse_position(pos_warped + p_rect.position);
+ }
+
+ return rel_warped;
+}
+
+void InputFilter::iteration(float p_step) {
+}
+
+void InputFilter::action_press(const StringName &p_action, float p_strength) {
+
+ Action action;
+
+ action.physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.idle_frame = Engine::get_singleton()->get_idle_frames();
+ action.pressed = true;
+ action.strength = p_strength;
+
+ action_state[p_action] = action;
+}
+
+void InputFilter::action_release(const StringName &p_action) {
+
+ Action action;
+
+ action.physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.idle_frame = Engine::get_singleton()->get_idle_frames();
+ action.pressed = false;
+ action.strength = 0.f;
+
+ action_state[p_action] = action;
+}
+
+void InputFilter::set_emulate_touch_from_mouse(bool p_emulate) {
+
+ emulate_touch_from_mouse = p_emulate;
+}
+
+bool InputFilter::is_emulating_touch_from_mouse() const {
+
+ return emulate_touch_from_mouse;
+}
+
+// Calling this whenever the game window is focused helps unstucking the "touch mouse"
+// if the OS or its abstraction class hasn't properly reported that touch pointers raised
+void InputFilter::ensure_touch_mouse_raised() {
+
+ if (mouse_from_touch_index != -1) {
+ mouse_from_touch_index = -1;
+
+ Ref<InputEventMouseButton> button_event;
+ button_event.instance();
+
+ button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
+ 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)));
+
+ _parse_input_event_impl(button_event, true);
+ }
+}
+
+void InputFilter::set_emulate_mouse_from_touch(bool p_emulate) {
+
+ emulate_mouse_from_touch = p_emulate;
+}
+
+bool InputFilter::is_emulating_mouse_from_touch() const {
+
+ return emulate_mouse_from_touch;
+}
+
+InputFilter::CursorShape InputFilter::get_default_cursor_shape() const {
+
+ return default_shape;
+}
+
+void InputFilter::set_default_cursor_shape(CursorShape p_shape) {
+
+ if (default_shape == p_shape)
+ return;
+
+ default_shape = p_shape;
+ // The default shape is set in Viewport::_gui_input_event. To instantly
+ // see the shape in the viewport we need to trigger a mouse motion event.
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+ mm->set_position(mouse_pos);
+ mm->set_global_position(mouse_pos);
+ parse_input_event(mm);
+}
+
+InputFilter::CursorShape InputFilter::get_current_cursor_shape() const {
+
+ return get_current_cursor_shape_func();
+}
+
+void InputFilter::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
+ set_custom_mouse_cursor_func(p_cursor, p_shape, p_hotspot);
+}
+
+void InputFilter::accumulate_input_event(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ if (!use_accumulated_input) {
+ parse_input_event(p_event);
+ return;
+ }
+ if (!accumulated_events.empty() && accumulated_events.back()->get()->accumulate(p_event)) {
+ return; //event was accumulated, exit
+ }
+
+ accumulated_events.push_back(p_event);
+}
+void InputFilter::flush_accumulated_events() {
+
+ while (accumulated_events.front()) {
+ parse_input_event(accumulated_events.front()->get());
+ accumulated_events.pop_front();
+ }
+}
+
+void InputFilter::set_use_accumulated_input(bool p_enable) {
+
+ use_accumulated_input = p_enable;
+}
+
+void InputFilter::release_pressed_events() {
+
+ flush_accumulated_events(); // this is needed to release actions strengths
+
+ keys_pressed.clear();
+ joy_buttons_pressed.clear();
+ _joy_axis.clear();
+
+ for (Map<StringName, InputFilter::Action>::Element *E = action_state.front(); E; E = E->next()) {
+ if (E->get().pressed)
+ action_release(E->key());
+ }
+}
+
+void InputFilter::set_event_dispatch_function(EventDispatchFunc p_function) {
+ event_dispatch_function = p_function;
+}
+
+void InputFilter::joy_button(int p_device, int p_button, bool p_pressed) {
+
+ _THREAD_SAFE_METHOD_;
+ Joypad &joy = joy_names[p_device];
+ //printf("got button %i, mapping is %i\n", p_button, joy.mapping);
+ if (joy.last_buttons[p_button] == p_pressed) {
+ return;
+ }
+ joy.last_buttons[p_button] = p_pressed;
+ if (joy.mapping == -1) {
+ _button_event(p_device, p_button, p_pressed);
+ return;
+ }
+
+ const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].buttons.find(p_button);
+ if (!el) {
+ //don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis
+ //return _button_event(p_last_id, p_device, p_button, p_pressed);
+ return;
+ }
+
+ JoyEvent map = el->get();
+ if (map.type == TYPE_BUTTON) {
+ //fake additional axis event for triggers
+ if (map.index == JOY_L2 || map.index == JOY_R2) {
+ float value = p_pressed ? 1.0f : 0.0f;
+ int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
+ _axis_event(p_device, axis, value);
+ }
+ _button_event(p_device, map.index, p_pressed);
+ return;
+ }
+
+ if (map.type == TYPE_AXIS) {
+ _axis_event(p_device, map.index, p_pressed ? 1.0 : 0.0);
+ }
+ // no event?
+}
+
+void InputFilter::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
+
+ _THREAD_SAFE_METHOD_;
+
+ ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX);
+
+ Joypad &joy = joy_names[p_device];
+
+ if (joy.last_axis[p_axis] == p_value.value) {
+ return;
+ }
+
+ if (p_value.value > joy.last_axis[p_axis]) {
+
+ if (p_value.value < joy.last_axis[p_axis] + joy.filter) {
+
+ return;
+ }
+ } else if (p_value.value > joy.last_axis[p_axis] - joy.filter) {
+
+ return;
+ }
+
+ //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;
+ 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;
+ jx.min = p_value.min;
+ jx.value = p_value.value < 0 ? 0.1 : -0.1;
+ joy_axis(p_device, p_axis, jx);
+ }
+
+ joy.last_axis[p_axis] = p_value.value;
+ float val = p_value.min == 0 ? -1.0f + 2.0f * p_value.value : p_value.value;
+
+ if (joy.mapping == -1) {
+ _axis_event(p_device, p_axis, val);
+ return;
+ };
+
+ const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].axis.find(p_axis);
+ if (!el) {
+ //return _axis_event(p_last_id, p_device, p_axis, p_value);
+ return;
+ };
+
+ JoyEvent map = el->get();
+
+ if (map.type == TYPE_BUTTON) {
+ //send axis event for triggers
+ if (map.index == JOY_L2 || map.index == JOY_R2) {
+ float value = p_value.min == 0 ? p_value.value : 0.5f + p_value.value / 2.0f;
+ int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
+ _axis_event(p_device, axis, value);
+ }
+
+ if (map.index == JOY_DPAD_UP || map.index == JOY_DPAD_DOWN) {
+ bool pressed = p_value.value != 0.0f;
+ int button = p_value.value < 0 ? JOY_DPAD_UP : JOY_DPAD_DOWN;
+
+ if (!pressed) {
+ if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_UP, p_device))) {
+ _button_event(p_device, JOY_DPAD_UP, false);
+ }
+ if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_DOWN, p_device))) {
+ _button_event(p_device, JOY_DPAD_DOWN, false);
+ }
+ }
+ if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
+ return;
+ }
+ _button_event(p_device, button, true);
+ return;
+ }
+ if (map.index == JOY_DPAD_LEFT || map.index == JOY_DPAD_RIGHT) {
+ bool pressed = p_value.value != 0.0f;
+ int button = p_value.value < 0 ? JOY_DPAD_LEFT : JOY_DPAD_RIGHT;
+
+ if (!pressed) {
+ if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_LEFT, p_device))) {
+ _button_event(p_device, JOY_DPAD_LEFT, false);
+ }
+ if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_RIGHT, p_device))) {
+ _button_event(p_device, JOY_DPAD_RIGHT, false);
+ }
+ }
+ if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
+ return;
+ }
+ _button_event(p_device, button, true);
+ return;
+ }
+ float deadzone = p_value.min == 0 ? 0.5f : 0.0f;
+ bool pressed = p_value.value > deadzone;
+ if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) {
+ // button already pressed or released, this is an axis bounce value
+ return;
+ }
+ _button_event(p_device, map.index, pressed);
+ return;
+ }
+
+ if (map.type == TYPE_AXIS) {
+
+ _axis_event(p_device, map.index, val);
+ return;
+ }
+ //printf("invalid mapping\n");
+}
+
+void InputFilter::joy_hat(int p_device, int p_val) {
+
+ _THREAD_SAFE_METHOD_;
+ const Joypad &joy = joy_names[p_device];
+
+ const JoyEvent *map;
+
+ if (joy.mapping == -1) {
+ map = hat_map_default;
+ } else {
+ map = map_db[joy.mapping].hat;
+ };
+
+ int cur_val = joy_names[p_device].hat_current;
+
+ if ((p_val & HAT_MASK_UP) != (cur_val & HAT_MASK_UP)) {
+ _button_event(p_device, map[HAT_UP].index, p_val & HAT_MASK_UP);
+ }
+
+ if ((p_val & HAT_MASK_RIGHT) != (cur_val & HAT_MASK_RIGHT)) {
+ _button_event(p_device, map[HAT_RIGHT].index, p_val & HAT_MASK_RIGHT);
+ }
+ if ((p_val & HAT_MASK_DOWN) != (cur_val & HAT_MASK_DOWN)) {
+ _button_event(p_device, map[HAT_DOWN].index, p_val & HAT_MASK_DOWN);
+ }
+ if ((p_val & HAT_MASK_LEFT) != (cur_val & HAT_MASK_LEFT)) {
+ _button_event(p_device, map[HAT_LEFT].index, p_val & HAT_MASK_LEFT);
+ }
+
+ joy_names[p_device].hat_current = p_val;
+}
+
+void InputFilter::_button_event(int p_device, int p_index, bool p_pressed) {
+
+ Ref<InputEventJoypadButton> ievent;
+ ievent.instance();
+ ievent->set_device(p_device);
+ ievent->set_button_index(p_index);
+ ievent->set_pressed(p_pressed);
+
+ parse_input_event(ievent);
+}
+
+void InputFilter::_axis_event(int p_device, int p_axis, float p_value) {
+
+ Ref<InputEventJoypadMotion> ievent;
+ ievent.instance();
+ ievent->set_device(p_device);
+ ievent->set_axis(p_axis);
+ ievent->set_axis_value(p_value);
+
+ parse_input_event(ievent);
+};
+
+InputFilter::JoyEvent InputFilter::_find_to_event(String p_to) {
+
+ // string names of the SDL buttons in the same order as input_event.h godot buttons
+ static const char *buttons[] = { "a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", nullptr };
+
+ static const char *axis[] = { "leftx", "lefty", "rightx", "righty", nullptr };
+
+ JoyEvent ret;
+ ret.type = -1;
+ ret.index = 0;
+
+ int i = 0;
+ while (buttons[i]) {
+
+ if (p_to == buttons[i]) {
+ ret.type = TYPE_BUTTON;
+ ret.index = i;
+ ret.value = 0;
+ return ret;
+ };
+ ++i;
+ };
+
+ i = 0;
+ while (axis[i]) {
+
+ if (p_to == axis[i]) {
+ ret.type = TYPE_AXIS;
+ ret.index = i;
+ ret.value = 0;
+ return ret;
+ };
+ ++i;
+ };
+
+ return ret;
+};
+
+void InputFilter::parse_mapping(String p_mapping) {
+
+ _THREAD_SAFE_METHOD_;
+ JoyDeviceMapping mapping;
+ for (int i = 0; i < HAT_MAX; ++i)
+ mapping.hat[i].index = 1024 + i;
+
+ Vector<String> entry = p_mapping.split(",");
+ if (entry.size() < 2) {
+ return;
+ }
+
+ CharString uid;
+ uid.resize(17);
+
+ mapping.uid = entry[0];
+ mapping.name = entry[1];
+
+ int idx = 1;
+ while (++idx < entry.size()) {
+
+ if (entry[idx] == "")
+ continue;
+
+ String from = entry[idx].get_slice(":", 1).replace(" ", "");
+ String to = entry[idx].get_slice(":", 0).replace(" ", "");
+
+ JoyEvent to_event = _find_to_event(to);
+ if (to_event.type == -1)
+ continue;
+
+ String etype = from.substr(0, 1);
+ if (etype == "a") {
+
+ int aid = from.substr(1, from.length() - 1).to_int();
+ mapping.axis[aid] = to_event;
+
+ } else if (etype == "b") {
+
+ int bid = from.substr(1, from.length() - 1).to_int();
+ mapping.buttons[bid] = to_event;
+
+ } else if (etype == "h") {
+
+ int hat_value = from.get_slice(".", 1).to_int();
+ switch (hat_value) {
+ case 1:
+ mapping.hat[HAT_UP] = to_event;
+ break;
+ case 2:
+ mapping.hat[HAT_RIGHT] = to_event;
+ break;
+ case 4:
+ mapping.hat[HAT_DOWN] = to_event;
+ break;
+ case 8:
+ mapping.hat[HAT_LEFT] = to_event;
+ break;
+ };
+ };
+ };
+ map_db.push_back(mapping);
+ //printf("added mapping with uuid %ls\n", mapping.uid.c_str());
+};
+
+void InputFilter::add_joy_mapping(String p_mapping, bool p_update_existing) {
+ parse_mapping(p_mapping);
+ 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;
+ }
+ }
+ }
+}
+
+void InputFilter::remove_joy_mapping(String p_guid) {
+ for (int i = map_db.size() - 1; i >= 0; i--) {
+ if (p_guid == map_db[i].uid) {
+ 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;
+ }
+ }
+}
+
+void InputFilter::set_fallback_mapping(String p_guid) {
+
+ for (int i = 0; i < map_db.size(); i++) {
+ if (map_db[i].uid == p_guid) {
+ fallback_mapping = i;
+ return;
+ }
+ }
+}
+
+//platforms that use the remapping system can override and call to these ones
+bool InputFilter::is_joy_known(int p_device) {
+ int mapping = joy_names[p_device].mapping;
+ return mapping != -1 ? (mapping != fallback_mapping) : false;
+}
+
+String InputFilter::get_joy_guid(int p_device) const {
+ ERR_FAIL_COND_V(!joy_names.has(p_device), "");
+ return joy_names[p_device].uid;
+}
+
+Array InputFilter::get_connected_joypads() {
+ Array ret;
+ Map<int, Joypad>::Element *elem = joy_names.front();
+ while (elem) {
+ if (elem->get().connected) {
+ ret.push_back(elem->key());
+ }
+ elem = elem->next();
+ }
+ return ret;
+}
+
+static const char *_buttons[JOY_BUTTON_MAX] = {
+ "Face Button Bottom",
+ "Face Button Right",
+ "Face Button Left",
+ "Face Button Top",
+ "L",
+ "R",
+ "L2",
+ "R2",
+ "L3",
+ "R3",
+ "Select",
+ "Start",
+ "DPAD Up",
+ "DPAD Down",
+ "DPAD Left",
+ "DPAD Right"
+};
+
+static const char *_axes[JOY_AXIS_MAX] = {
+ "Left Stick X",
+ "Left Stick Y",
+ "Right Stick X",
+ "Right Stick Y",
+ "",
+ "",
+ "L2",
+ "R2",
+ "",
+ ""
+};
+
+String InputFilter::get_joy_button_string(int p_button) {
+ ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "");
+ return _buttons[p_button];
+}
+
+int InputFilter::get_joy_button_index_from_string(String p_button) {
+ for (int i = 0; i < JOY_BUTTON_MAX; i++) {
+ if (p_button == _buttons[i]) {
+ return i;
+ }
+ }
+ ERR_FAIL_V(-1);
+}
+
+int InputFilter::get_unused_joy_id() {
+ for (int i = 0; i < JOYPADS_MAX; i++) {
+ if (!joy_names.has(i) || !joy_names[i].connected) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+String InputFilter::get_joy_axis_string(int p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "");
+ return _axes[p_axis];
+}
+
+int InputFilter::get_joy_axis_index_from_string(String p_axis) {
+ for (int i = 0; i < JOY_AXIS_MAX; i++) {
+ if (p_axis == _axes[i]) {
+ return i;
+ }
+ }
+ ERR_FAIL_V(-1);
+}
+
+InputFilter::InputFilter() {
+
+ singleton = this;
+ use_accumulated_input = true;
+ mouse_button_mask = 0;
+ mouse_window = 0;
+ emulate_touch_from_mouse = false;
+ emulate_mouse_from_touch = false;
+ mouse_from_touch_index = -1;
+ event_dispatch_function = nullptr;
+ default_shape = CURSOR_ARROW;
+
+ hat_map_default[HAT_UP].type = TYPE_BUTTON;
+ hat_map_default[HAT_UP].index = JOY_DPAD_UP;
+ hat_map_default[HAT_UP].value = 0;
+
+ hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
+ hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
+ hat_map_default[HAT_RIGHT].value = 0;
+
+ hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
+ hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
+ hat_map_default[HAT_DOWN].value = 0;
+
+ hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
+ hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
+ hat_map_default[HAT_LEFT].value = 0;
+
+ fallback_mapping = -1;
+
+ // Parse default mappings.
+ {
+ int i = 0;
+ while (DefaultControllerMappings::mappings[i]) {
+ parse_mapping(DefaultControllerMappings::mappings[i++]);
+ }
+ }
+
+ // If defined, parse SDL_GAMECONTROLLERCONFIG for possible new mappings/overrides.
+ String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
+ if (env_mapping != "") {
+ Vector<String> entries = env_mapping.split("\n");
+ for (int i = 0; i < entries.size(); i++) {
+ if (entries[i] == "")
+ continue;
+ parse_mapping(entries[i]);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////
diff --git a/core/input/input_filter.h b/core/input/input_filter.h
new file mode 100644
index 0000000000..908a005228
--- /dev/null
+++ b/core/input/input_filter.h
@@ -0,0 +1,337 @@
+/*************************************************************************/
+/* input_filter.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 INPUT_H
+#define INPUT_H
+
+#include "core/input/input_event.h"
+#include "core/object.h"
+#include "core/os/thread_safe.h"
+
+class InputFilter : public Object {
+
+ GDCLASS(InputFilter, Object);
+ _THREAD_SAFE_CLASS_
+
+ static InputFilter *singleton;
+
+public:
+ enum MouseMode {
+ MOUSE_MODE_VISIBLE,
+ MOUSE_MODE_HIDDEN,
+ MOUSE_MODE_CAPTURED,
+ MOUSE_MODE_CONFINED
+ };
+
+#undef CursorShape
+ enum CursorShape {
+ CURSOR_ARROW,
+ CURSOR_IBEAM,
+ CURSOR_POINTING_HAND,
+ CURSOR_CROSS,
+ CURSOR_WAIT,
+ CURSOR_BUSY,
+ CURSOR_DRAG,
+ CURSOR_CAN_DROP,
+ CURSOR_FORBIDDEN,
+ CURSOR_VSIZE,
+ CURSOR_HSIZE,
+ CURSOR_BDIAGSIZE,
+ CURSOR_FDIAGSIZE,
+ CURSOR_MOVE,
+ CURSOR_VSPLIT,
+ CURSOR_HSPLIT,
+ CURSOR_HELP,
+ CURSOR_MAX
+ };
+
+ enum HatMask {
+ HAT_MASK_CENTER = 0,
+ HAT_MASK_UP = 1,
+ HAT_MASK_RIGHT = 2,
+ HAT_MASK_DOWN = 4,
+ HAT_MASK_LEFT = 8,
+ };
+
+ enum HatDir {
+ HAT_UP,
+ HAT_RIGHT,
+ HAT_DOWN,
+ HAT_LEFT,
+ HAT_MAX,
+ };
+
+ enum {
+ JOYPADS_MAX = 16,
+ };
+
+ struct JoyAxis {
+ int min;
+ float value;
+ };
+
+ typedef void (*EventDispatchFunc)(const Ref<InputEvent> &p_event);
+
+private:
+ int mouse_button_mask;
+
+ Set<int> keys_pressed;
+ Set<int> joy_buttons_pressed;
+ Map<int, float> _joy_axis;
+ //Map<StringName,int> custom_action_press;
+ Vector3 gravity;
+ Vector3 accelerometer;
+ Vector3 magnetometer;
+ Vector3 gyroscope;
+ Vector2 mouse_pos;
+ int64_t mouse_window;
+
+ struct Action {
+ uint64_t physics_frame;
+ uint64_t idle_frame;
+ bool pressed;
+ float strength;
+ };
+
+ Map<StringName, Action> action_state;
+
+ bool emulate_touch_from_mouse;
+ bool emulate_mouse_from_touch;
+
+ int mouse_from_touch_index;
+
+ struct VibrationInfo {
+ float weak_magnitude;
+ float strong_magnitude;
+ float duration; // Duration in seconds
+ uint64_t timestamp;
+ };
+
+ Map<int, VibrationInfo> joy_vibration;
+
+ struct SpeedTrack {
+
+ uint64_t last_tick;
+ Vector2 speed;
+ Vector2 accum;
+ float accum_t;
+ float min_ref_frame;
+ float max_ref_frame;
+
+ void update(const Vector2 &p_delta_p);
+ void reset();
+ SpeedTrack();
+ };
+
+ struct Joypad {
+ StringName name;
+ StringName uid;
+ bool connected;
+ bool last_buttons[JOY_BUTTON_MAX + 19]; //apparently SDL specifies 35 possible buttons on android
+ float last_axis[JOY_AXIS_MAX];
+ float filter;
+ int last_hat;
+ int mapping;
+ int hat_current;
+
+ Joypad() {
+ for (int i = 0; i < JOY_AXIS_MAX; i++) {
+
+ last_axis[i] = 0.0f;
+ }
+ for (int i = 0; i < JOY_BUTTON_MAX + 19; i++) {
+
+ last_buttons[i] = false;
+ }
+ connected = false;
+ last_hat = HAT_MASK_CENTER;
+ filter = 0.01f;
+ mapping = -1;
+ hat_current = 0;
+ }
+ };
+
+ SpeedTrack mouse_speed_track;
+ Map<int, SpeedTrack> touch_speed_track;
+ Map<int, Joypad> joy_names;
+ int fallback_mapping;
+
+ CursorShape default_shape;
+
+ enum JoyType {
+ TYPE_BUTTON,
+ TYPE_AXIS,
+ TYPE_HAT,
+ TYPE_MAX,
+ };
+
+ struct JoyEvent {
+ int type;
+ int index;
+ int value;
+ };
+
+ struct JoyDeviceMapping {
+
+ String uid;
+ String name;
+ Map<int, JoyEvent> buttons;
+ Map<int, JoyEvent> axis;
+ JoyEvent hat[HAT_MAX];
+ };
+
+ JoyEvent hat_map_default[HAT_MAX];
+
+ Vector<JoyDeviceMapping> map_db;
+
+ JoyEvent _find_to_event(String p_to);
+ void _button_event(int p_device, int p_index, bool p_pressed);
+ void _axis_event(int p_device, int p_axis, float p_value);
+ float _handle_deadzone(int p_device, int p_axis, float p_value);
+
+ void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
+
+ List<Ref<InputEvent>> accumulated_events;
+ bool use_accumulated_input;
+ friend class DisplayServer;
+
+ static void (*set_mouse_mode_func)(MouseMode);
+ static MouseMode (*get_mouse_mode_func)();
+ static void (*warp_mouse_func)(const Vector2 &p_to_pos);
+
+ static CursorShape (*get_current_cursor_shape_func)();
+ static void (*set_custom_mouse_cursor_func)(const RES &, CursorShape, const Vector2 &);
+
+ EventDispatchFunc event_dispatch_function;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_mouse_mode(MouseMode p_mode);
+ MouseMode get_mouse_mode() const;
+ void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
+
+ static InputFilter *get_singleton();
+
+ 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_joy_axis(int p_device, int p_axis) const;
+ String get_joy_name(int p_idx);
+ Array get_connected_joypads();
+ Vector2 get_joy_vibration_strength(int p_device);
+ float get_joy_vibration_duration(int p_device);
+ uint64_t get_joy_vibration_timestamp(int p_device);
+ void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
+ void parse_joypad_mapping(String p_mapping, bool p_update_existing);
+
+ Vector3 get_gravity() const;
+ Vector3 get_accelerometer() const;
+ Vector3 get_magnetometer() const;
+ Vector3 get_gyroscope() const;
+
+ Point2 get_mouse_position() const;
+ Point2 get_last_mouse_speed() const;
+ int get_mouse_button_mask() const;
+
+ void warp_mouse_position(const Vector2 &p_to);
+ Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
+
+ void parse_input_event(const Ref<InputEvent> &p_event);
+
+ void set_gravity(const Vector3 &p_gravity);
+ void set_accelerometer(const Vector3 &p_accel);
+ void set_magnetometer(const Vector3 &p_magnetometer);
+ void set_gyroscope(const Vector3 &p_gyroscope);
+ void set_joy_axis(int p_device, int p_axis, float p_value);
+
+ void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
+ void stop_joy_vibration(int p_device);
+ void vibrate_handheld(int p_duration_ms = 500);
+
+ void set_mouse_position(const Point2 &p_posf);
+
+ void action_press(const StringName &p_action, float p_strength = 1.f);
+ void action_release(const StringName &p_action);
+
+ void iteration(float p_step);
+
+ void set_emulate_touch_from_mouse(bool p_emulate);
+ bool is_emulating_touch_from_mouse() const;
+ void ensure_touch_mouse_raised();
+
+ void set_emulate_mouse_from_touch(bool p_emulate);
+ bool is_emulating_mouse_from_touch() const;
+
+ CursorShape get_default_cursor_shape() const;
+ void set_default_cursor_shape(CursorShape p_shape);
+ CursorShape get_current_cursor_shape() const;
+ void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = InputFilter::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+
+ 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_hat(int p_device, int p_val);
+
+ void add_joy_mapping(String p_mapping, bool p_update_existing = false);
+ void remove_joy_mapping(String p_guid);
+
+ String get_joy_button_string(int p_button);
+ String get_joy_axis_string(int p_axis);
+ int get_joy_axis_index_from_string(String p_axis);
+ int get_joy_button_index_from_string(String p_button);
+
+ int get_unused_joy_id();
+
+ bool is_joy_known(int p_device);
+ String get_joy_guid(int p_device) const;
+ void set_fallback_mapping(String p_guid);
+
+ void accumulate_input_event(const Ref<InputEvent> &p_event);
+ void flush_accumulated_events();
+ void set_use_accumulated_input(bool p_enable);
+
+ void release_pressed_events();
+
+ void set_event_dispatch_function(EventDispatchFunc p_function);
+
+ InputFilter();
+};
+
+VARIANT_ENUM_CAST(InputFilter::MouseMode);
+VARIANT_ENUM_CAST(InputFilter::CursorShape);
+
+#endif // INPUT_H
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
new file mode 100644
index 0000000000..6b6acf062d
--- /dev/null
+++ b/core/input/input_map.cpp
@@ -0,0 +1,338 @@
+/*************************************************************************/
+/* input_map.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.h"
+
+#include "core/os/keyboard.h"
+#include "core/project_settings.h"
+
+InputMap *InputMap::singleton = nullptr;
+
+int InputMap::ALL_DEVICES = -1;
+
+void InputMap::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
+ ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
+ ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f));
+ ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
+
+ ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
+ ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
+ ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
+ 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("get_action_list", "action"), &InputMap::_get_action_list);
+ ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action);
+ ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals);
+}
+
+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) + "'.");
+ input_map[p_action] = Action();
+ static int last_id = 1;
+ input_map[p_action].id = last_id;
+ input_map[p_action].deadzone = p_deadzone;
+ last_id++;
+}
+
+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) + "'.");
+ input_map.erase(p_action);
+}
+
+Array InputMap::_get_actions() {
+
+ Array ret;
+ List<StringName> actions = get_actions();
+ if (actions.empty())
+ return ret;
+
+ for (const List<StringName>::Element *E = actions.front(); E; E = E->next()) {
+
+ ret.push_back(E->get());
+ }
+
+ return ret;
+}
+
+List<StringName> InputMap::get_actions() const {
+
+ List<StringName> actions = List<StringName>();
+ if (input_map.empty()) {
+ return actions;
+ }
+
+ for (Map<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) const {
+
+ for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
+
+ const Ref<InputEvent> e = E->get();
+
+ //if (e.type != Ref<InputEvent>::KEY && e.device != p_event.device) -- unsure about the KEY comparison, why is this here?
+ // continue;
+
+ 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_action.deadzone)) {
+ return E;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+bool InputMap::has_action(const StringName &p_action) const {
+
+ return input_map.has(p_action);
+}
+
+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) + "'.");
+
+ 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))
+ return; //already gots
+
+ input_map[p_action].inputs.push_back(p_event);
+}
+
+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);
+}
+
+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) + "'.");
+
+ List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event);
+ if (E)
+ input_map[p_action].inputs.erase(E);
+}
+
+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) + "'.");
+
+ input_map[p_action].inputs.clear();
+}
+
+Array InputMap::_get_action_list(const StringName &p_action) {
+
+ Array ret;
+ const List<Ref<InputEvent>> *al = get_action_list(p_action);
+ if (al) {
+ for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) {
+
+ ret.push_back(E->get());
+ }
+ }
+
+ return ret;
+}
+
+const List<Ref<InputEvent>> *InputMap::get_action_list(const StringName &p_action) {
+
+ const Map<StringName, Action>::Element *E = input_map.find(p_action);
+ if (!E)
+ return nullptr;
+
+ 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_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_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) + "'.");
+
+ Ref<InputEventAction> input_event_action = p_event;
+ if (input_event_action.is_valid()) {
+ if (p_pressed != nullptr)
+ *p_pressed = input_event_action->is_pressed();
+ if (p_strength != nullptr)
+ *p_strength = (p_pressed != nullptr && *p_pressed) ? input_event_action->get_strength() : 0.0f;
+ return input_event_action->get_action() == p_action;
+ }
+
+ bool pressed;
+ float strength;
+ List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength);
+ if (event != nullptr) {
+ if (p_pressed != nullptr)
+ *p_pressed = pressed;
+ if (p_strength != nullptr)
+ *p_strength = strength;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+const Map<StringName, InputMap::Action> &InputMap::get_action_map() const {
+ return input_map;
+}
+
+void InputMap::load_from_globals() {
+
+ input_map.clear();
+
+ List<PropertyInfo> pinfo;
+ ProjectSettings::get_singleton()->get_property_list(&pinfo);
+
+ for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
+ const PropertyInfo &pi = E->get();
+
+ if (!pi.name.begins_with("input/"))
+ continue;
+
+ String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
+
+ Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
+ float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
+ Array events = action["events"];
+
+ add_action(name, deadzone);
+ for (int i = 0; i < events.size(); i++) {
+ Ref<InputEvent> event = events[i];
+ if (event.is_null())
+ continue;
+ action_add_event(name, event);
+ }
+ }
+}
+
+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");
+}
+
+InputMap::InputMap() {
+
+ ERR_FAIL_COND_MSG(singleton, "Singleton in InputMap already exist.");
+ singleton = this;
+}
diff --git a/core/input/input_map.h b/core/input/input_map.h
new file mode 100644
index 0000000000..e03bc5fd4f
--- /dev/null
+++ b/core/input/input_map.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* input_map.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 INPUT_MAP_H
+#define INPUT_MAP_H
+
+#include "core/input/input_event.h"
+#include "core/object.h"
+
+class InputMap : public Object {
+
+ GDCLASS(InputMap, Object);
+
+public:
+ /**
+ * A special value used to signify that a given Action can be triggered by any device
+ */
+ static int ALL_DEVICES;
+
+ struct Action {
+ int id;
+ float deadzone;
+ List<Ref<InputEvent>> inputs;
+ };
+
+private:
+ static InputMap *singleton;
+
+ mutable Map<StringName, Action> input_map;
+
+ List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr) const;
+
+ Array _get_action_list(const StringName &p_action);
+ Array _get_actions();
+
+protected:
+ static void _bind_methods();
+
+public:
+ static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
+
+ bool has_action(const StringName &p_action) const;
+ List<StringName> get_actions() const;
+ void add_action(const StringName &p_action, float p_deadzone = 0.5);
+ void erase_action(const StringName &p_action);
+
+ void action_set_deadzone(const StringName &p_action, float p_deadzone);
+ void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
+ bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
+ void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);
+ void action_erase_events(const StringName &p_action);
+
+ const List<Ref<InputEvent>> *get_action_list(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) const;
+
+ const Map<StringName, Action> &get_action_map() const;
+ void load_from_globals();
+ void load_default();
+
+ InputMap();
+};
+
+#endif // INPUT_MAP_H
diff --git a/core/input_map.cpp b/core/input_map.cpp
deleted file mode 100644
index b855e14e0d..0000000000
--- a/core/input_map.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-/*************************************************************************/
-/* input_map.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.h"
-
-#include "core/os/keyboard.h"
-#include "core/project_settings.h"
-
-InputMap *InputMap::singleton = NULL;
-
-int InputMap::ALL_DEVICES = -1;
-
-void InputMap::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
- ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
- ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f));
- ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
-
- ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
- ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event);
- ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event);
- 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("get_action_list", "action"), &InputMap::_get_action_list);
- ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action);
- ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals);
-}
-
-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) + "'.");
- input_map[p_action] = Action();
- static int last_id = 1;
- input_map[p_action].id = last_id;
- input_map[p_action].deadzone = p_deadzone;
- last_id++;
-}
-
-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) + "'.");
- input_map.erase(p_action);
-}
-
-Array InputMap::_get_actions() {
-
- Array ret;
- List<StringName> actions = get_actions();
- if (actions.empty())
- return ret;
-
- for (const List<StringName>::Element *E = actions.front(); E; E = E->next()) {
-
- ret.push_back(E->get());
- }
-
- return ret;
-}
-
-List<StringName> InputMap::get_actions() const {
-
- List<StringName> actions = List<StringName>();
- if (input_map.empty()) {
- return actions;
- }
-
- for (Map<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) const {
-
- for (List<Ref<InputEvent> >::Element *E = p_action.inputs.front(); E; E = E->next()) {
-
- const Ref<InputEvent> e = E->get();
-
- //if (e.type != Ref<InputEvent>::KEY && e.device != p_event.device) -- unsure about the KEY comparison, why is this here?
- // continue;
-
- 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_action.deadzone)) {
- return E;
- }
- }
- }
-
- return NULL;
-}
-
-bool InputMap::has_action(const StringName &p_action) const {
-
- return input_map.has(p_action);
-}
-
-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) + "'.");
-
- 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))
- return; //already gots
-
- input_map[p_action].inputs.push_back(p_event);
-}
-
-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) != NULL);
-}
-
-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) + "'.");
-
- List<Ref<InputEvent> >::Element *E = _find_event(input_map[p_action], p_event);
- if (E)
- input_map[p_action].inputs.erase(E);
-}
-
-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) + "'.");
-
- input_map[p_action].inputs.clear();
-}
-
-Array InputMap::_get_action_list(const StringName &p_action) {
-
- Array ret;
- const List<Ref<InputEvent> > *al = get_action_list(p_action);
- if (al) {
- for (const List<Ref<InputEvent> >::Element *E = al->front(); E; E = E->next()) {
-
- ret.push_back(E->get());
- }
- }
-
- return ret;
-}
-
-const List<Ref<InputEvent> > *InputMap::get_action_list(const StringName &p_action) {
-
- const Map<StringName, Action>::Element *E = input_map.find(p_action);
- if (!E)
- return NULL;
-
- 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_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_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) + "'.");
-
- Ref<InputEventAction> input_event_action = p_event;
- if (input_event_action.is_valid()) {
- if (p_pressed != NULL)
- *p_pressed = input_event_action->is_pressed();
- if (p_strength != NULL)
- *p_strength = (p_pressed != NULL && *p_pressed) ? input_event_action->get_strength() : 0.0f;
- return input_event_action->get_action() == p_action;
- }
-
- bool pressed;
- float strength;
- List<Ref<InputEvent> >::Element *event = _find_event(E->get(), p_event, &pressed, &strength);
- if (event != NULL) {
- if (p_pressed != NULL)
- *p_pressed = pressed;
- if (p_strength != NULL)
- *p_strength = strength;
- return true;
- } else {
- return false;
- }
-}
-
-const Map<StringName, InputMap::Action> &InputMap::get_action_map() const {
- return input_map;
-}
-
-void InputMap::load_from_globals() {
-
- input_map.clear();
-
- List<PropertyInfo> pinfo;
- ProjectSettings::get_singleton()->get_property_list(&pinfo);
-
- for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
- const PropertyInfo &pi = E->get();
-
- if (!pi.name.begins_with("input/"))
- continue;
-
- String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
-
- Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
- float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
- Array events = action["events"];
-
- add_action(name, deadzone);
- for (int i = 0; i < events.size(); i++) {
- Ref<InputEvent> event = events[i];
- if (event.is_null())
- continue;
- action_add_event(name, event);
- }
- }
-}
-
-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");
-}
-
-InputMap::InputMap() {
-
- ERR_FAIL_COND_MSG(singleton, "Singleton in InputMap already exist.");
- singleton = this;
-}
diff --git a/core/input_map.h b/core/input_map.h
deleted file mode 100644
index 19d550af77..0000000000
--- a/core/input_map.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*************************************************************************/
-/* input_map.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 INPUT_MAP_H
-#define INPUT_MAP_H
-
-#include "core/object.h"
-#include "core/os/input_event.h"
-
-class InputMap : public Object {
-
- GDCLASS(InputMap, Object);
-
-public:
- /**
- * A special value used to signify that a given Action can be triggered by any device
- */
- static int ALL_DEVICES;
-
- struct Action {
- int id;
- float deadzone;
- List<Ref<InputEvent> > inputs;
- };
-
-private:
- static InputMap *singleton;
-
- mutable Map<StringName, Action> input_map;
-
- List<Ref<InputEvent> >::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = NULL, float *p_strength = NULL) const;
-
- Array _get_action_list(const StringName &p_action);
- Array _get_actions();
-
-protected:
- static void _bind_methods();
-
-public:
- static _FORCE_INLINE_ InputMap *get_singleton() { return singleton; }
-
- bool has_action(const StringName &p_action) const;
- List<StringName> get_actions() const;
- void add_action(const StringName &p_action, float p_deadzone = 0.5);
- void erase_action(const StringName &p_action);
-
- void action_set_deadzone(const StringName &p_action, float p_deadzone);
- void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
- bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
- void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event);
- void action_erase_events(const StringName &p_action);
-
- const List<Ref<InputEvent> > *get_action_list(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 = NULL, float *p_strength = NULL) const;
-
- const Map<StringName, Action> &get_action_map() const;
- void load_from_globals();
- void load_default();
-
- InputMap();
-};
-
-#endif // INPUT_MAP_H
diff --git a/core/int_types.h b/core/int_types.h
index e7de053766..71caa2202d 100644
--- a/core/int_types.h
+++ b/core/int_types.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef INT_TYPES_H
+#define INT_TYPES_H
+
#ifdef _MSC_VER
typedef signed __int8 int8_t;
@@ -54,4 +57,6 @@ typedef unsigned long long uint64_t;
#include <stdint.h>
#endif
-#endif
+#endif // _MSC_VER
+
+#endif // INT_TYPES_H
diff --git a/core/io/SCsub b/core/io/SCsub
index 1c5f954470..19a6549225 100644
--- a/core/io/SCsub
+++ b/core/io/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 531467ecd6..73230e3a3c 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -107,7 +107,7 @@ bool ConfigFile::has_section_key(const String &p_section, const String &p_key) c
void ConfigFile::get_sections(List<String> *r_sections) const {
- for (OrderedHashMap<String, OrderedHashMap<String, Variant> >::ConstElement E = values.front(); E; E = E.next()) {
+ for (OrderedHashMap<String, OrderedHashMap<String, Variant>>::ConstElement E = values.front(); E; E = E.next()) {
r_sections->push_back(E.key());
}
}
@@ -187,7 +187,7 @@ Error ConfigFile::save_encrypted_pass(const String &p_path, const String &p_pass
Error ConfigFile::_internal_save(FileAccess *file) {
- for (OrderedHashMap<String, OrderedHashMap<String, Variant> >::Element E = values.front(); E; E = E.next()) {
+ for (OrderedHashMap<String, OrderedHashMap<String, Variant>>::Element E = values.front(); E; E = E.next()) {
if (E != values.front())
file->store_string("\n");
@@ -290,7 +290,7 @@ Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream)
next_tag.fields.clear();
next_tag.name = String();
- Error err = VariantParser::parse_tag_assign_eof(p_stream, lines, error_text, next_tag, assign, value, NULL, true);
+ Error err = VariantParser::parse_tag_assign_eof(p_stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
return OK;
} else if (err != OK) {
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 7efcb5a04c..39fc2ab412 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -40,7 +40,7 @@ class ConfigFile : public Reference {
GDCLASS(ConfigFile, Reference);
- OrderedHashMap<String, OrderedHashMap<String, Variant> > values;
+ OrderedHashMap<String, OrderedHashMap<String, Variant>> values;
PackedStringArray _get_sections() const;
PackedStringArray _get_section_keys(const String &p_section) const;
diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp
index 07e6abb1c9..5bda06e5b9 100644
--- a/core/io/dtls_server.cpp
+++ b/core/io/dtls_server.cpp
@@ -32,7 +32,7 @@
#include "core/os/file_access.h"
#include "core/project_settings.h"
-DTLSServer *(*DTLSServer::_create)() = NULL;
+DTLSServer *(*DTLSServer::_create)() = nullptr;
bool DTLSServer::available = false;
DTLSServer *DTLSServer::create() {
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 17cc6ce58f..c76142d22d 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -64,7 +64,7 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
cmode = (Compression::Mode)f->get_32();
block_size = f->get_32();
if (block_size == 0) {
- f = NULL; // Let the caller to handle the FileAccess object if failed to open as compressed file.
+ f = nullptr; // Let the caller to handle the FileAccess object if failed to open as compressed file.
ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted.");
}
read_total = f->get_32();
@@ -109,7 +109,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
if (err != OK) {
//not openable
- f = NULL;
+ f = nullptr;
return err;
}
@@ -131,7 +131,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
rmagic[4] = 0;
if (magic != rmagic || open_after_magic(f) != OK) {
memdelete(f);
- f = NULL;
+ f = nullptr;
return ERR_FILE_UNRECOGNIZED;
}
}
@@ -187,12 +187,12 @@ void FileAccessCompressed::close() {
}
memdelete(f);
- f = NULL;
+ f = nullptr;
}
bool FileAccessCompressed::is_open() const {
- return f != NULL;
+ return f != nullptr;
}
void FileAccessCompressed::seek(size_t p_position) {
@@ -392,20 +392,20 @@ Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t
FileAccessCompressed::FileAccessCompressed() :
cmode(Compression::MODE_ZSTD),
writing(false),
- write_ptr(0),
+ write_ptr(nullptr),
write_buffer_size(0),
write_max(0),
block_size(0),
read_eof(false),
at_end(false),
- read_ptr(NULL),
+ read_ptr(nullptr),
read_block(0),
read_block_count(0),
read_block_size(0),
read_pos(0),
read_total(0),
magic("GCMP"),
- f(NULL) {
+ f(nullptr) {
}
FileAccessCompressed::~FileAccessCompressed() {
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 20b6fc81dc..a5b3807789 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -41,7 +41,7 @@
Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode) {
- ERR_FAIL_COND_V_MSG(file != NULL, ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open.");
+ ERR_FAIL_COND_V_MSG(file != nullptr, ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open.");
ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
pos = 0;
@@ -159,7 +159,7 @@ void FileAccessEncrypted::close() {
file->store_buffer(compressed.ptr(), compressed.size());
file->close();
memdelete(file);
- file = NULL;
+ file = nullptr;
data.clear();
} else {
@@ -167,13 +167,13 @@ void FileAccessEncrypted::close() {
file->close();
memdelete(file);
data.clear();
- file = NULL;
+ file = nullptr;
}
}
bool FileAccessEncrypted::is_open() const {
- return file != NULL;
+ return file != nullptr;
}
String FileAccessEncrypted::get_path() const {
@@ -319,7 +319,7 @@ Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t
FileAccessEncrypted::FileAccessEncrypted() {
- file = NULL;
+ file = nullptr;
pos = 0;
eofed = false;
mode = MODE_MAX;
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index fc318b3dd2..a2379ce88f 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -35,12 +35,12 @@
#include "core/os/dir_access.h"
#include "core/project_settings.h"
-static Map<String, Vector<uint8_t> > *files = NULL;
+static Map<String, Vector<uint8_t>> *files = nullptr;
void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
if (!files) {
- files = memnew((Map<String, Vector<uint8_t> >));
+ files = memnew((Map<String, Vector<uint8_t>>));
}
String name;
@@ -71,7 +71,7 @@ bool FileAccessMemory::file_exists(const String &p_name) {
String name = fix_path(p_name);
//name = DirAccess::normalize_path(name);
- return files && (files->find(name) != NULL);
+ return files && (files->find(name) != nullptr);
}
Error FileAccessMemory::open_custom(const uint8_t *p_data, int p_len) {
@@ -89,7 +89,7 @@ Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
String name = fix_path(p_path);
//name = DirAccess::normalize_path(name);
- Map<String, Vector<uint8_t> >::Element *E = files->find(name);
+ Map<String, Vector<uint8_t>>::Element *E = files->find(name);
ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, "Can't find file '" + p_path + "'.");
data = E->get().ptrw();
@@ -101,12 +101,12 @@ Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
void FileAccessMemory::close() {
- data = NULL;
+ data = nullptr;
}
bool FileAccessMemory::is_open() const {
- return data != NULL;
+ return data != nullptr;
}
void FileAccessMemory::seek(size_t p_position) {
@@ -196,5 +196,5 @@ void FileAccessMemory::store_buffer(const uint8_t *p_src, int p_length) {
FileAccessMemory::FileAccessMemory() {
- data = NULL;
+ data = nullptr;
}
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 370dd8f982..a3f307393f 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -114,7 +114,7 @@ void FileAccessNetworkClient::_thread_func() {
int response = get_32();
DEBUG_PRINT("GET RESPONSE: " + itos(response));
- FileAccessNetwork *fa = NULL;
+ FileAccessNetwork *fa = nullptr;
if (response != FileAccessNetwork::RESPONSE_DATA) {
if (!accesses.has(id)) {
@@ -219,11 +219,11 @@ Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const S
return OK;
}
-FileAccessNetworkClient *FileAccessNetworkClient::singleton = NULL;
+FileAccessNetworkClient *FileAccessNetworkClient::singleton = nullptr;
FileAccessNetworkClient::FileAccessNetworkClient() {
- thread = NULL;
+ thread = nullptr;
quit = false;
singleton = this;
last_id = 0;
@@ -295,7 +295,7 @@ Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
pos = 0;
eof_flag = false;
last_page = -1;
- last_page_buff = NULL;
+ last_page_buff = nullptr;
//buffers.clear();
nc->unlock_mutex();
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 055ce816ad..0a7dee9444 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -98,18 +98,18 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o
void PackedData::add_pack_source(PackSource *p_source) {
- if (p_source != NULL) {
+ if (p_source != nullptr) {
sources.push_back(p_source);
}
};
-PackedData *PackedData::singleton = NULL;
+PackedData *PackedData::singleton = nullptr;
PackedData::PackedData() {
singleton = this;
root = memnew(PackedDir);
- root->parent = NULL;
+ root->parent = nullptr;
disabled = false;
add_pack_source(memnew(PackedSourcePCK));
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index e1f35aabdd..8df6826ac9 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -185,9 +185,9 @@ FileAccess *PackedData::try_open_path(const String &p_path) {
PathMD5 pmd5(p_path.md5_buffer());
Map<PathMD5, PackedFile>::Element *E = files.find(pmd5);
if (!E)
- return NULL; //not found
+ return nullptr; //not found
if (E->get().offset == 0)
- return NULL; //was erased
+ return nullptr; //was erased
return E->get().src->get_file(p_path, &E->get());
}
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 680450ba43..57de66afaf 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -35,20 +35,20 @@
#include "core/os/copymem.h"
#include "core/os/file_access.h"
-ZipArchive *ZipArchive::instance = NULL;
+ZipArchive *ZipArchive::instance = nullptr;
extern "C" {
static void *godot_open(void *data, const char *p_fname, int mode) {
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
- return NULL;
+ return nullptr;
}
FileAccess *f = (FileAccess *)data;
f->open(p_fname, FileAccess::READ);
- return f->is_open() ? data : NULL;
+ return f->is_open() ? data : nullptr;
}
static uLong godot_read(void *data, void *fdata, void *buf, uLong size) {
@@ -126,11 +126,11 @@ void ZipArchive::close_handle(unzFile p_file) const {
unzFile ZipArchive::get_file_handle(String p_file) const {
- ERR_FAIL_COND_V_MSG(!file_exists(p_file), NULL, "File '" + p_file + " doesn't exist.");
+ ERR_FAIL_COND_V_MSG(!file_exists(p_file), nullptr, "File '" + p_file + " doesn't exist.");
File file = files[p_file];
FileAccess *f = FileAccess::open(packages[file.package].filename, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, NULL, "Cannot open file '" + packages[file.package].filename + "'.");
+ ERR_FAIL_COND_V_MSG(!f, nullptr, "Cannot open file '" + packages[file.package].filename + "'.");
zlib_filefunc_def io;
zeromem(&io, sizeof(io));
@@ -149,12 +149,12 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
io.free_mem = godot_free;
unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
- ERR_FAIL_COND_V(!pkg, NULL);
+ ERR_FAIL_COND_V(!pkg, nullptr);
int unz_err = unzGoToFilePos(pkg, &file.file_pos);
if (unz_err != UNZ_OK || unzOpenCurrentFile(pkg) != UNZ_OK) {
unzClose(pkg);
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
return pkg;
@@ -199,7 +199,7 @@ bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files) {
char filename_inzip[256];
unz_file_info64 file_info;
- err = unzGetCurrentFileInfo64(zfile, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
+ err = unzGetCurrentFileInfo64(zfile, &file_info, filename_inzip, sizeof(filename_inzip), nullptr, 0, nullptr, 0);
ERR_CONTINUE(err != UNZ_OK);
File f;
@@ -233,7 +233,7 @@ FileAccess *ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p
ZipArchive *ZipArchive::get_singleton() {
- if (instance == NULL) {
+ if (instance == nullptr) {
instance = memnew(ZipArchive);
}
@@ -268,7 +268,7 @@ Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
zfile = arch->get_file_handle(p_path);
ERR_FAIL_COND_V(!zfile, FAILED);
- int err = unzGetCurrentFileInfo64(zfile, &file_info, NULL, 0, NULL, 0, NULL, 0);
+ int err = unzGetCurrentFileInfo64(zfile, &file_info, nullptr, 0, nullptr, 0, nullptr, 0);
ERR_FAIL_COND_V(err != UNZ_OK, FAILED);
return OK;
@@ -282,12 +282,12 @@ void FileAccessZip::close() {
ZipArchive *arch = ZipArchive::get_singleton();
ERR_FAIL_COND(!arch);
arch->close_handle(zfile);
- zfile = NULL;
+ zfile = nullptr;
}
bool FileAccessZip::is_open() const {
- return zfile != NULL;
+ return zfile != nullptr;
}
void FileAccessZip::seek(size_t p_position) {
@@ -370,7 +370,7 @@ bool FileAccessZip::file_exists(const String &p_name) {
}
FileAccessZip::FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file) :
- zfile(NULL) {
+ zfile(nullptr) {
_open(p_path, FileAccess::READ);
}
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index ce7025de35..56f8f1ff91 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -350,7 +350,7 @@ Error HTTPClient::poll() {
handshaking = true;
} else {
// We are already handshaking, which means we can use your already active SSL connection
- ssl = static_cast<Ref<StreamPeerSSL> >(connection);
+ ssl = static_cast<Ref<StreamPeerSSL>>(connection);
if (ssl.is_null()) {
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 99ac5bcdd9..2770adbd36 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -100,7 +100,7 @@ ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
return loader[i];
}
- return NULL;
+ return nullptr;
}
Vector<ImageFormatLoader *> ImageLoader::loader;
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index 3ba028b99c..18b4df98f7 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -59,7 +59,7 @@ class ImageLoader {
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = NULL, bool p_force_linear = false, float p_scale = 1.0);
+ static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = nullptr, bool p_force_linear = false, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
static ImageFormatLoader *recognize(const String &p_extension);
@@ -73,10 +73,10 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};
-#endif
+#endif // IMAGE_LOADER_H
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 2143b84d15..5de7fb7186 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -280,19 +280,19 @@ void IP::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_ANY);
}
-IP *IP::singleton = NULL;
+IP *IP::singleton = nullptr;
IP *IP::get_singleton() {
return singleton;
}
-IP *(*IP::_create)() = NULL;
+IP *(*IP::_create)() = nullptr;
IP *IP::create() {
- ERR_FAIL_COND_V_MSG(singleton, NULL, "IP singleton already exist.");
- ERR_FAIL_COND_V(!_create, NULL);
+ ERR_FAIL_COND_V_MSG(singleton, nullptr, "IP singleton already exist.");
+ ERR_FAIL_COND_V(!_create, nullptr);
return _create();
}
@@ -307,7 +307,7 @@ IP::IP() {
resolver->thread = Thread::create(_IP_ResolverPrivate::_thread_function, resolver);
#else
- resolver->thread = NULL;
+ resolver->thread = nullptr;
#endif
}
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 4d732332d5..48aebeda3d 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -108,7 +108,7 @@ Logger::~Logger() {}
void RotatedFileLogger::close_file() {
if (file) {
memdelete(file);
- file = NULL;
+ file = nullptr;
}
}
@@ -182,7 +182,7 @@ void RotatedFileLogger::rotate_file() {
RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) :
base_path(p_base_path.simplify_path()),
max_files(p_max_files > 0 ? p_max_files : 1),
- file(NULL) {
+ file(nullptr) {
rotate_file();
}
diff --git a/core/io/logger.h b/core/io/logger.h
index ab2f9d8bc7..7028551185 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -107,4 +107,4 @@ public:
virtual ~CompositeLogger();
};
-#endif
+#endif // LOGGER_H
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index fbcaa582b7..81bc45b2f7 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -439,7 +439,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += 8;
if (val.is_null()) {
- r_variant = (Object *)NULL;
+ r_variant = (Object *)nullptr;
} else {
Ref<EncodedObjectAsID> obj_as_id;
obj_as_id.instance();
@@ -457,7 +457,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
return err;
if (str == String()) {
- r_variant = (Object *)NULL;
+ r_variant = (Object *)nullptr;
} else {
Object *obj = ClassDB::instance(str);
@@ -917,7 +917,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
// Test for potential wrong values sent by the debugger when it breaks.
Object *obj = p_variant.get_validated_object();
if (!obj) {
- // Object is invalid, send a NULL instead.
+ // Object is invalid, send a nullptr instead.
if (buf) {
encode_uint32(Variant::NIL, buf);
}
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index 484f0755de..d029ed238c 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -199,7 +199,7 @@ public:
EncodedObjectAsID();
};
-Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = false);
+Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = nullptr, bool p_allow_objects = false);
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false);
-#endif
+#endif // MARSHALLS_H
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 4b864f0dd7..3bec52416e 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -207,7 +207,7 @@ int get_packet_len(uint32_t p_node_target, int p_packet_len) {
void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) {
- ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
+ ERR_FAIL_COND_MSG(root_node == nullptr, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small.");
#ifdef DEBUG_ENABLED
@@ -285,7 +285,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
}
Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len);
- ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found.");
+ ERR_FAIL_COND_MSG(node == nullptr, "Invalid packet received. Requested node was not found.");
uint16_t name_id = 0;
switch (name_id_compression) {
@@ -321,14 +321,14 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len) {
- Node *node = NULL;
+ Node *node = nullptr;
if (p_node_target & 0x80000000) {
// Use full path (not cached yet).
int ofs = p_node_target & 0x7FFFFFFF;
- ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, NULL, "Invalid packet received. Size smaller than declared.");
+ ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, nullptr, "Invalid packet received. Size smaller than declared.");
String paths;
paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs);
@@ -344,10 +344,10 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, uin
int id = p_node_target;
Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
- ERR_FAIL_COND_V_MSG(!E, NULL, "Invalid packet received. Requests invalid peer cache.");
+ ERR_FAIL_COND_V_MSG(!E, nullptr, "Invalid packet received. Requests invalid peer cache.");
Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id);
- ERR_FAIL_COND_V_MSG(!F, NULL, "Invalid packet received. Unabled to find requested cached node.");
+ ERR_FAIL_COND_V_MSG(!F, nullptr, "Invalid packet received. Unabled to find requested cached node.");
PathGetCache::NodeInfo *ni = &F->get();
// Do proper caching later.
@@ -456,7 +456,7 @@ void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_i
#endif
Variant value;
- Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL);
+ Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, nullptr);
ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value.");
@@ -491,7 +491,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
}
Node *node = root_node->get_node(path);
- ERR_FAIL_COND(node == NULL);
+ ERR_FAIL_COND(node == nullptr);
const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5;
if (valid_rpc_checksum == false) {
ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
@@ -504,7 +504,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet,
// Encode path to send ack.
CharString pname = String(path).utf8();
- int len = encode_cstring(pname.get_data(), NULL);
+ int len = encode_cstring(pname.get_data(), nullptr);
Vector<uint8_t> packet;
@@ -572,7 +572,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC
// Encode function name.
const CharString path = String(p_path).utf8();
- const int path_len = encode_cstring(path.get_data(), NULL);
+ const int path_len = encode_cstring(path.get_data(), nullptr);
// Extract MD5 from rpc methods list.
const String methods_md5 = p_node->get_rpc_md5();
@@ -862,7 +862,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
// Set argument.
int len(0);
- Error err = _encode_and_compress_variant(*p_arg[0], NULL, len);
+ Error err = _encode_and_compress_variant(*p_arg[0], nullptr, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
_encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len);
@@ -874,7 +874,8 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
if (method_id == UINT16_MAX && p_from->get_script_instance()) {
method_id = p_from->get_script_instance()->get_rpc_method_id(p_name);
}
- ERR_FAIL_COND_MSG(method_id == UINT16_MAX, "Unable to take the `method_id` for the function:" + p_name + ". this can happen only if this method is not marked as `remote`.");
+ ERR_FAIL_COND_MSG(method_id == UINT16_MAX,
+ vformat("Unable to take the `method_id` for the function \"%s\" at path: \"%s\". This happens when the method is not marked as `remote`.", p_name, p_from->get_path()));
if (method_id <= UINT8_MAX) {
// The ID fits in 1 byte
@@ -906,7 +907,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
int len(0);
- Error err = _encode_and_compress_variant(*p_arg[i], NULL, len);
+ Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len);
ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
MAKE_ROOM(ofs + len);
_encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
@@ -942,7 +943,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
// Append path at the end, since we will need it for some packets.
CharString pname = String(from_path).utf8();
- int path_len = encode_cstring(pname.get_data(), NULL);
+ int path_len = encode_cstring(pname.get_data(), nullptr);
MAKE_ROOM(ofs + path_len);
encode_cstring(pname.get_data(), &(packet_cache.write[ofs]));
@@ -1261,7 +1262,7 @@ void MultiplayerAPI::_bind_methods() {
MultiplayerAPI::MultiplayerAPI() :
allow_object_decoding(false) {
rpc_sender_id = 0;
- root_node = NULL;
+ root_node = nullptr;
clear();
}
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index 52f918aefa..4eb4a53e99 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef MULTIPLAYER_PROTOCOL_H
-#define MULTIPLAYER_PROTOCOL_H
+#ifndef MULTIPLAYER_API_H
+#define MULTIPLAYER_API_H
#include "core/io/networked_multiplayer_peer.h"
#include "core/reference.h"
@@ -148,4 +148,4 @@ public:
VARIANT_ENUM_CAST(MultiplayerAPI::RPCMode);
-#endif // MULTIPLAYER_PROTOCOL_H
+#endif // MULTIPLAYER_API_H
diff --git a/core/io/net_socket.cpp b/core/io/net_socket.cpp
index 23edbc7d64..838c674cec 100644
--- a/core/io/net_socket.cpp
+++ b/core/io/net_socket.cpp
@@ -30,7 +30,7 @@
#include "net_socket.h"
-NetSocket *(*NetSocket::_create)() = NULL;
+NetSocket *(*NetSocket::_create)() = nullptr;
NetSocket *NetSocket::create() {
@@ -38,5 +38,5 @@ NetSocket *NetSocket::create() {
return _create();
ERR_PRINT("Unable to create network socket, platform not supported");
- return NULL;
+ return nullptr;
}
diff --git a/core/io/networked_multiplayer_peer.h b/core/io/networked_multiplayer_peer.h
index bffd544589..c1f1924051 100644
--- a/core/io/networked_multiplayer_peer.h
+++ b/core/io/networked_multiplayer_peer.h
@@ -80,4 +80,4 @@ public:
VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::TransferMode)
VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::ConnectionStatus)
-#endif // NetworkedMultiplayerPeer_H
+#endif // NETWORKED_MULTIPLAYER_PEER_H
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 2f5c493c2c..38abb5c0d6 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -90,13 +90,13 @@ Error PacketPeer::get_var(Variant &r_variant, bool p_allow_objects) {
if (err)
return err;
- return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects);
+ return decode_variant(r_variant, buffer, buffer_size, nullptr, p_allow_objects);
}
Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) {
int len;
- Error err = encode_variant(p_packet, NULL, len, p_full_objects); // compute len first
+ Error err = encode_variant(p_packet, nullptr, len, p_full_objects); // compute len first
if (err)
return err;
diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp
index 01218a6881..6da115eed2 100644
--- a/core/io/packet_peer_dtls.cpp
+++ b/core/io/packet_peer_dtls.cpp
@@ -32,7 +32,7 @@
#include "core/os/file_access.h"
#include "core/project_settings.h"
-PacketPeerDTLS *(*PacketPeerDTLS::_create)() = NULL;
+PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr;
bool PacketPeerDTLS::available = false;
PacketPeerDTLS *PacketPeerDTLS::create() {
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index fb83f0ac90..5c4b3379ee 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -63,7 +63,7 @@ void PCKPacker::_bind_methods() {
Error PCKPacker::pck_start(const String &p_file, int p_alignment) {
- if (file != NULL) {
+ if (file != nullptr) {
memdelete(file);
}
@@ -163,7 +163,7 @@ Error PCKPacker::flush(bool p_verbose) {
src->close();
memdelete(src);
count += 1;
- if (p_verbose) {
+ if (p_verbose && files.size() > 0) {
if (count % 100 == 0) {
printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100);
fflush(stdout);
@@ -182,12 +182,12 @@ Error PCKPacker::flush(bool p_verbose) {
PCKPacker::PCKPacker() {
- file = NULL;
+ file = nullptr;
};
PCKPacker::~PCKPacker() {
- if (file != NULL) {
+ if (file != nullptr) {
memdelete(file);
};
- file = NULL;
+ file = nullptr;
};
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index efd452191a..a640565ecf 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1009,7 +1009,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) {
ResourceLoaderBinary::ResourceLoaderBinary() :
translation_remapped(false),
ver_format(0),
- f(NULL),
+ f(nullptr),
importmd_ofs(0),
error(OK) {
@@ -1107,7 +1107,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_path + "'.");
- FileAccess *fw = NULL; //=FileAccess::open(p_path+".depren");
+ FileAccess *fw = nullptr; //=FileAccess::open(p_path+".depren");
String local_path = p_path.get_base_dir();
@@ -2095,7 +2095,7 @@ void ResourceFormatSaverBinary::get_recognized_extensions(const RES &p_resource,
p_extensions->push_back("res");
}
-ResourceFormatSaverBinary *ResourceFormatSaverBinary::singleton = NULL;
+ResourceFormatSaverBinary *ResourceFormatSaverBinary::singleton = nullptr;
ResourceFormatSaverBinary::ResourceFormatSaverBinary() {
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 0ffa2c3626..da67e1e648 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -101,7 +101,7 @@ public:
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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 efaf958949..ceb73cab77 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -69,7 +69,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
memdelete(f);
return OK;
@@ -274,7 +274,7 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
memdelete(f);
return;
@@ -362,7 +362,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String
return Ref<ResourceImporter>();
}
-void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter> > *r_importers) {
+void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers) {
for (int i = 0; i < importers.size(); i++) {
List<String> local_exts;
@@ -423,7 +423,7 @@ bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) con
String ResourceFormatImporter::get_import_settings_hash() const {
- Vector<Ref<ResourceImporter> > sorted_importers = importers;
+ Vector<Ref<ResourceImporter>> sorted_importers = importers;
sorted_importers.sort_custom<SortImporterByName>();
@@ -434,7 +434,7 @@ String ResourceFormatImporter::get_import_settings_hash() const {
return hash.md5_text();
}
-ResourceFormatImporter *ResourceFormatImporter::singleton = NULL;
+ResourceFormatImporter *ResourceFormatImporter::singleton = nullptr;
ResourceFormatImporter::ResourceFormatImporter() {
singleton = this;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 65c148f2ac..dbac80599a 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -45,7 +45,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
Variant metadata;
};
- Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = NULL) const;
+ Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = nullptr) const;
static ResourceFormatImporter *singleton;
@@ -54,11 +54,11 @@ class ResourceFormatImporter : public ResourceFormatLoader {
bool operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const;
};
- Vector<Ref<ResourceImporter> > importers;
+ Vector<Ref<ResourceImporter>> importers;
public:
static ResourceFormatImporter *get_singleton() { return singleton; }
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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;
@@ -83,7 +83,7 @@ public:
void remove_importer(const Ref<ResourceImporter> &p_importer) { importers.erase(p_importer); }
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_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers);
bool are_import_settings_valid(const String &p_path) const;
String get_import_settings_hash() const;
@@ -123,9 +123,9 @@ public:
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const = 0;
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 = NULL, Variant *r_metadata = NULL) = 0;
+ 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 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 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; }
virtual String get_import_settings_string() const { return String(); }
};
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 5dca8b3b89..05a41013c2 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -936,7 +936,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
break;
} else if (err != OK) {
@@ -1048,7 +1048,7 @@ void ResourceLoader::set_load_callback(ResourceLoadedCallback p_callback) {
_loaded_callback = p_callback;
}
-ResourceLoadedCallback ResourceLoader::_loaded_callback = NULL;
+ResourceLoadedCallback ResourceLoader::_loaded_callback = nullptr;
Ref<ResourceFormatLoader> ResourceLoader::_find_custom_resource_format_loader(String path) {
for (int i = 0; i < loader_count; ++i) {
@@ -1075,7 +1075,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
Object *obj = ClassDB::instance(ibt);
- ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj);
crl->set_script(s);
@@ -1113,7 +1113,7 @@ void ResourceLoader::add_custom_loaders() {
void ResourceLoader::remove_custom_loaders() {
- Vector<Ref<ResourceFormatLoader> > custom_loaders;
+ Vector<Ref<ResourceFormatLoader>> custom_loaders;
for (int i = 0; i < loader_count; ++i) {
if (loader[i]->get_script_instance()) {
custom_loaders.push_back(loader[i]);
@@ -1140,11 +1140,11 @@ void ResourceLoader::finalize() {
memdelete(thread_load_semaphore);
}
-ResourceLoadErrorNotify ResourceLoader::err_notify = NULL;
-void *ResourceLoader::err_notify_ud = NULL;
+ResourceLoadErrorNotify ResourceLoader::err_notify = nullptr;
+void *ResourceLoader::err_notify_ud = nullptr;
-DependencyErrorNotify ResourceLoader::dep_err_notify = NULL;
-void *ResourceLoader::dep_err_notify_ud = NULL;
+DependencyErrorNotify ResourceLoader::dep_err_notify = nullptr;
+void *ResourceLoader::dep_err_notify_ud = nullptr;
bool ResourceLoader::abort_on_missing_resource = true;
bool ResourceLoader::timestamp_on_load = false;
@@ -1159,7 +1159,7 @@ int ResourceLoader::thread_suspended_count = 0;
int ResourceLoader::thread_load_max = 0;
SelfList<Resource>::List ResourceLoader::remapped_list;
-HashMap<String, Vector<String> > ResourceLoader::translation_remaps;
+HashMap<String, Vector<String>> ResourceLoader::translation_remaps;
HashMap<String, String> ResourceLoader::path_remaps;
-ResourceLoaderImport ResourceLoader::import = NULL;
+ResourceLoaderImport ResourceLoader::import = nullptr;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index ea89917a5f..be4adf9091 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -43,7 +43,7 @@ protected:
static void _bind_methods();
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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;
@@ -90,10 +90,10 @@ private:
static void *dep_err_notify_ud;
static DependencyErrorNotify dep_err_notify;
static bool abort_on_missing_resource;
- static HashMap<String, Vector<String> > translation_remaps;
+ static HashMap<String, Vector<String>> translation_remaps;
static HashMap<String, String> path_remaps;
- static String _path_remap(const String &p_path, bool *r_translation_remapped = NULL);
+ static String _path_remap(const String &p_path, bool *r_translation_remapped = nullptr);
friend class Resource;
static SelfList<Resource>::List remapped_list;
@@ -140,9 +140,9 @@ private:
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 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 = NULL);
+ 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 = NULL);
+ static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, 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);
@@ -200,4 +200,4 @@ public:
static void finalize();
};
-#endif
+#endif // RESOURCE_LOADER_H
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 740aaf5cfa..09128adb50 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -38,7 +38,7 @@ Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS];
int ResourceSaver::saver_count = 0;
bool ResourceSaver::timestamp_on_save = false;
-ResourceSavedCallback ResourceSaver::save_callback = 0;
+ResourceSavedCallback ResourceSaver::save_callback = nullptr;
Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
@@ -218,7 +218,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
Object *obj = ClassDB::instance(ibt);
- ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj);
crl->set_script(s);
@@ -256,7 +256,7 @@ void ResourceSaver::add_custom_savers() {
void ResourceSaver::remove_custom_savers() {
- Vector<Ref<ResourceFormatSaver> > custom_savers;
+ Vector<Ref<ResourceFormatSaver>> custom_savers;
for (int i = 0; i < saver_count; ++i) {
if (saver[i]->get_script_instance()) {
custom_savers.push_back(saver[i]);
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index e749f54cfa..2ddebf0581 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -90,4 +90,4 @@ public:
static void remove_custom_savers();
};
-#endif
+#endif // RESOURCE_SAVER_H
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 3c695c18fc..b28b17aa95 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -224,7 +224,7 @@ void StreamPeer::put_var(const Variant &p_variant, bool p_full_objects) {
int len = 0;
Vector<uint8_t> buf;
- encode_variant(p_variant, NULL, len, p_full_objects);
+ encode_variant(p_variant, nullptr, len, p_full_objects);
buf.resize(len);
put_32(len);
encode_variant(p_variant, buf.ptrw(), len, p_full_objects);
@@ -368,7 +368,7 @@ Variant StreamPeer::get_var(bool p_allow_objects) {
ERR_FAIL_COND_V(err != OK, Variant());
Variant ret;
- err = decode_variant(ret, var.ptr(), len, NULL, p_allow_objects);
+ err = decode_variant(ret, var.ptr(), len, nullptr, p_allow_objects);
ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to decode Variant.");
return ret;
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index 03ca726619..d98935f77c 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -32,13 +32,13 @@
#include "core/engine.h"
-StreamPeerSSL *(*StreamPeerSSL::_create)() = NULL;
+StreamPeerSSL *(*StreamPeerSSL::_create)() = nullptr;
StreamPeerSSL *StreamPeerSSL::create() {
if (_create)
return _create();
- return NULL;
+ return nullptr;
}
bool StreamPeerSSL::available = false;
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 327aa3cc3b..86df9ab8cf 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -93,4 +93,4 @@ public:
VARIANT_ENUM_CAST(StreamPeerTCP::Status);
-#endif
+#endif // STREAM_PEER_TCP_H
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 4051bf2947..5da236d029 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -33,7 +33,7 @@
#include "core/os/file_access.h"
#include "core/translation.h"
-RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const String &p_path) {
+RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
enum Status {
@@ -67,7 +67,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status == STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
+ ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
} else {
break;
}
@@ -78,7 +78,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status == STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: ");
+ ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: ");
}
if (msg_id != "") {
@@ -100,7 +100,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
if (status != STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
+ ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
}
l = l.substr(6, l.length()).strip_edges();
@@ -115,20 +115,29 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
continue; //nothing to read or comment
}
- ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), p_path + ":" + itos(line) + " Invalid line '" + l + "' while parsing: ");
+ ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), f->get_path() + ":" + itos(line) + " Invalid line '" + l + "' while parsing: ");
l = l.substr(1, l.length());
- //find final quote
+ // 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.
int end_pos = -1;
+ bool escape_next = false;
for (int i = 0; i < l.length(); i++) {
+ if (l[i] == '\\' && !escape_next) {
+ escape_next = true;
+ continue;
+ }
- if (l[i] == '"' && (i == 0 || l[i - 1] != '\\')) {
+ if (l[i] == '"' && !escape_next) {
end_pos = i;
break;
}
+
+ escape_next = false;
}
- ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), p_path + ":" + itos(line) + " Expected '\"' at end of message while parsing file: ");
+ ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), f->get_path() + ":" + itos(line) + ": Expected '\"' at end of message while parsing file.");
l = l.substr(0, end_pos);
l = l.c_unescape();
@@ -153,7 +162,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
config = msg_str;
}
- ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + f->get_path() + ".");
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index fe3a75e5eb..9d3117b630 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -37,8 +37,8 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
- static RES load_translation(FileAccess *f, Error *r_error, const String &p_path = String());
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
+ 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);
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/xml_parser.cpp b/core/io/xml_parser.cpp
index bd450dd84f..9613ad3f10 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -165,7 +165,7 @@ bool XMLParser::_parse_cdata() {
return true;
char *cDataBegin = P;
- char *cDataEnd = 0;
+ char *cDataEnd = nullptr;
// find end of CDATA
while (*P && !cDataEnd) {
@@ -529,9 +529,9 @@ void XMLParser::close() {
if (data)
memdelete_arr(data);
- data = NULL;
+ data = nullptr;
length = 0;
- P = NULL;
+ P = nullptr;
node_empty = false;
node_type = NODE_NONE;
node_offset = 0;
@@ -544,7 +544,7 @@ int XMLParser::get_current_line() const {
XMLParser::XMLParser() {
- data = NULL;
+ data = nullptr;
close();
special_characters.push_back("&amp;");
special_characters.push_back("<lt;");
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index 47e276da28..26c3e6802f 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -121,4 +121,4 @@ public:
~XMLParser();
};
-#endif
+#endif // XML_PARSER_H
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index 40e902d874..3a2a207d22 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -47,7 +47,7 @@ void *zipio_open(void *data, const char *p_fname, int mode) {
}
if (!f)
- return NULL;
+ return nullptr;
return data;
}
@@ -98,7 +98,7 @@ int zipio_close(voidpf opaque, voidpf stream) {
if (f) {
f->close();
memdelete(f);
- f = NULL;
+ f = nullptr;
}
return 0;
}
diff --git a/core/list.h b/core/list.h
index 6250cec598..be2dccd876 100644
--- a/core/list.h
+++ b/core/list.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GLOBALS_LIST_H
-#define GLOBALS_LIST_H
+#ifndef LIST_H
+#define LIST_H
#include "core/error_macros.h"
#include "core/os/memory.h"
@@ -142,7 +142,7 @@ public:
_FORCE_INLINE_ Element() {
next_ptr = 0;
prev_ptr = 0;
- data = NULL;
+ data = nullptr;
};
};
@@ -220,8 +220,8 @@ public:
if (!_data) {
_data = memnew_allocator(_Data, A);
- _data->first = NULL;
- _data->last = NULL;
+ _data->first = nullptr;
+ _data->last = nullptr;
_data->size_cache = 0;
}
@@ -261,8 +261,8 @@ public:
if (!_data) {
_data = memnew_allocator(_Data, A);
- _data->first = NULL;
- _data->last = NULL;
+ _data->first = nullptr;
+ _data->last = nullptr;
_data->size_cache = 0;
}
@@ -357,7 +357,7 @@ public:
it = it->next();
};
- return NULL;
+ return nullptr;
};
/**
@@ -370,7 +370,7 @@ public:
if (_data->size_cache == 0) {
memdelete_allocator<_Data, A>(_data);
- _data = NULL;
+ _data = nullptr;
}
return ret;
@@ -498,7 +498,7 @@ public:
_data->last->next_ptr = p_I;
p_I->prev_ptr = _data->last;
- p_I->next_ptr = NULL;
+ p_I->next_ptr = nullptr;
_data->last = p_I;
}
@@ -535,7 +535,7 @@ public:
_data->first->prev_ptr = p_I;
p_I->next_ptr = _data->first;
- p_I->prev_ptr = NULL;
+ p_I->prev_ptr = nullptr;
_data->first = p_I;
}
@@ -576,7 +576,7 @@ public:
void sort() {
- sort_custom<Comparator<T> >();
+ sort_custom<Comparator<T>>();
}
template <class C>
@@ -595,7 +595,7 @@ public:
if (from != current) {
- current->prev_ptr = NULL;
+ current->prev_ptr = nullptr;
current->next_ptr = from;
Element *find = from;
@@ -618,8 +618,8 @@ public:
to = current;
} else {
- current->prev_ptr = NULL;
- current->next_ptr = NULL;
+ current->prev_ptr = nullptr;
+ current->next_ptr = nullptr;
}
current = next;
@@ -657,16 +657,16 @@ public:
idx++;
}
- SortArray<Element *, AuxiliaryComparator<C> > sort;
+ SortArray<Element *, AuxiliaryComparator<C>> sort;
sort.sort(aux_buffer, s);
_data->first = aux_buffer[0];
- aux_buffer[0]->prev_ptr = NULL;
+ aux_buffer[0]->prev_ptr = nullptr;
aux_buffer[0]->next_ptr = aux_buffer[1];
_data->last = aux_buffer[s - 1];
aux_buffer[s - 1]->prev_ptr = aux_buffer[s - 2];
- aux_buffer[s - 1]->next_ptr = NULL;
+ aux_buffer[s - 1]->next_ptr = nullptr;
for (int i = 1; i < s - 1; i++) {
@@ -686,7 +686,7 @@ public:
*/
List(const List &p_list) {
- _data = NULL;
+ _data = nullptr;
const Element *it = p_list.front();
while (it) {
@@ -696,7 +696,7 @@ public:
}
List() {
- _data = NULL;
+ _data = nullptr;
};
~List() {
clear();
@@ -708,4 +708,4 @@ public:
};
};
-#endif
+#endif // LIST_H
diff --git a/core/make_binders.py b/core/make_binders.py
index c42b91fbe5..94bee95bfb 100644
--- a/core/make_binders.py
+++ b/core/make_binders.py
@@ -280,58 +280,57 @@ MethodBind* create_method_bind($ifret R$ $ifnoret void$ (*p_method)($ifconst con
"""
-
def make_version(template, nargs, argmax, const, ret):
intext = template
from_pos = 0
outtext = ""
- while(True):
+ while True:
to_pos = intext.find("$", from_pos)
- if (to_pos == -1):
+ if to_pos == -1:
outtext += intext[from_pos:]
break
else:
outtext += intext[from_pos:to_pos]
end = intext.find("$", to_pos + 1)
- if (end == -1):
+ if end == -1:
break # ignore
- macro = intext[to_pos + 1:end]
+ macro = intext[to_pos + 1 : end]
cmd = ""
data = ""
- if (macro.find(" ") != -1):
- cmd = macro[0:macro.find(" ")]
- data = macro[macro.find(" ") + 1:]
+ if macro.find(" ") != -1:
+ cmd = macro[0 : macro.find(" ")]
+ data = macro[macro.find(" ") + 1 :]
else:
cmd = macro
- if (cmd == "argc"):
+ if cmd == "argc":
outtext += str(nargs)
- if (cmd == "ifret" and ret):
+ if cmd == "ifret" and ret:
outtext += data
- if (cmd == "ifargs" and nargs):
+ if cmd == "ifargs" and nargs:
outtext += data
- if (cmd == "ifretargs" and nargs and ret):
+ if cmd == "ifretargs" and nargs and ret:
outtext += data
- if (cmd == "ifconst" and const):
+ if cmd == "ifconst" and const:
outtext += data
- elif (cmd == "ifnoconst" and not const):
+ elif cmd == "ifnoconst" and not const:
outtext += data
- elif (cmd == "ifnoret" and not ret):
+ elif cmd == "ifnoret" and not ret:
outtext += data
- elif (cmd == "iftempl" and (nargs > 0 or ret)):
+ elif cmd == "iftempl" and (nargs > 0 or ret):
outtext += data
- elif (cmd == "arg,"):
+ elif cmd == "arg,":
for i in range(1, nargs + 1):
- if (i > 1):
+ if i > 1:
outtext += ", "
outtext += data.replace("@", str(i))
- elif (cmd == "arg"):
+ elif cmd == "arg":
for i in range(1, nargs + 1):
outtext += data.replace("@", str(i))
- elif (cmd == "noarg"):
+ elif cmd == "noarg":
for i in range(nargs + 1, argmax + 1):
outtext += data.replace("@", str(i))
@@ -348,7 +347,9 @@ def run(target, source, env):
text_ext = ""
text_free_func = "#ifndef METHOD_BIND_FREE_FUNC_H\n#define METHOD_BIND_FREE_FUNC_H\n"
text_free_func += "\n//including this header file allows method binding to use free functions\n"
- text_free_func += "//note that the free function must have a pointer to an instance of the class as its first parameter\n"
+ text_free_func += (
+ "//note that the free function must have a pointer to an instance of the class as its first parameter\n"
+ )
for i in range(0, versions + 1):
@@ -361,7 +362,7 @@ def run(target, source, env):
t += make_version(template_typed, i, versions, True, False)
t += make_version(template, i, versions, True, True)
t += make_version(template_typed, i, versions, True, True)
- if (i >= versions_ext):
+ if i >= versions_ext:
text_ext += t
else:
text += t
@@ -383,6 +384,7 @@ def run(target, source, env):
f.write(text_free_func)
-if __name__ == '__main__':
+if __name__ == "__main__":
from platform_methods import subprocess_main
+
subprocess_main(globals())
diff --git a/core/map.h b/core/map.h
index b97f735f1b..6b9dff51de 100644
--- a/core/map.h
+++ b/core/map.h
@@ -95,11 +95,11 @@ public:
};
Element() {
color = RED;
- right = NULL;
- left = NULL;
- parent = NULL;
- _next = NULL;
- _prev = NULL;
+ right = nullptr;
+ left = nullptr;
+ parent = nullptr;
+ _next = nullptr;
+ _prev = nullptr;
};
};
@@ -118,7 +118,7 @@ private:
#else
_nil = (Element *)&_GlobalNilClass::_nil;
#endif
- _root = NULL;
+ _root = nullptr;
size_cache = 0;
}
@@ -133,7 +133,7 @@ private:
if (_root) {
memdelete_allocator<Element, A>(_root);
- _root = NULL;
+ _root = nullptr;
}
}
@@ -205,7 +205,7 @@ private:
}
if (node->parent == _data._root)
- return NULL; // No successor, as p_node = last node
+ return nullptr; // No successor, as p_node = last node
return node->parent;
}
}
@@ -227,7 +227,7 @@ private:
}
if (node == _data._root)
- return NULL; // No predecessor, as p_node = first node
+ return nullptr; // No predecessor, as p_node = first node
return node->parent;
}
}
@@ -246,13 +246,13 @@ private:
return node; // found
}
- return NULL;
+ return nullptr;
}
Element *_find_closest(const K &p_key) const {
Element *node = _data._root->left;
- Element *prev = NULL;
+ Element *prev = nullptr;
C less;
while (node != _data._nil) {
@@ -266,8 +266,8 @@ private:
return node; // found
}
- if (prev == NULL)
- return NULL; // tree empty
+ if (prev == nullptr)
+ return nullptr; // tree empty
if (less(p_key, prev->_key))
prev = prev->_prev;
@@ -519,7 +519,7 @@ public:
const Element *find(const K &p_key) const {
if (!_data._root)
- return NULL;
+ return nullptr;
const Element *res = _find(p_key);
return res;
@@ -528,7 +528,7 @@ public:
Element *find(const K &p_key) {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *res = _find(p_key);
return res;
@@ -537,7 +537,7 @@ public:
const Element *find_closest(const K &p_key) const {
if (!_data._root)
- return NULL;
+ return nullptr;
const Element *res = _find_closest(p_key);
return res;
@@ -546,7 +546,7 @@ public:
Element *find_closest(const K &p_key) {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *res = _find_closest(p_key);
return res;
@@ -554,7 +554,7 @@ public:
bool has(const K &p_key) const {
- return find(p_key) != NULL;
+ return find(p_key) != nullptr;
}
Element *insert(const K &p_key, const V &p_value) {
@@ -612,11 +612,11 @@ public:
Element *front() const {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *e = _data._root->left;
if (e == _data._nil)
- return NULL;
+ return nullptr;
while (e->left != _data._nil)
e = e->left;
@@ -627,11 +627,11 @@ public:
Element *back() const {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *e = _data._root->left;
if (e == _data._nil)
- return NULL;
+ return nullptr;
while (e->right != _data._nil)
e = e->right;
@@ -682,4 +682,4 @@ public:
}
};
-#endif
+#endif // MAP_H
diff --git a/core/math/SCsub b/core/math/SCsub
index be438fcfbe..c8fdac207e 100644
--- a/core/math/SCsub
+++ b/core/math/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env_math = env.Clone()
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 847d4d8681..3e3e6c50a7 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -66,7 +66,7 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
pt->id = p_id;
pt->pos = p_pos;
pt->weight_scale = p_weight_scale;
- pt->prev_point = NULL;
+ pt->prev_point = nullptr;
pt->open_pass = 0;
pt->closed_pass = 0;
pt->enabled = true;
@@ -167,7 +167,7 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) {
if (bidirectional) s.direction = Segment::BIDIRECTIONAL;
Set<Segment>::Element *element = segments.find(s);
- if (element != NULL) {
+ if (element != nullptr) {
s.direction |= element->get().direction;
if (s.direction == Segment::BIDIRECTIONAL) {
// Both are neighbours of each other now
@@ -194,7 +194,7 @@ void AStar::disconnect_points(int p_id, int p_with_id, bool bidirectional) {
int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : s.direction;
Set<Segment>::Element *element = segments.find(s);
- if (element != NULL) {
+ if (element != nullptr) {
// s is the new segment
// Erase the directions to be removed
s.direction = (element->get().direction & ~remove_direction);
@@ -255,7 +255,7 @@ bool AStar::are_points_connected(int p_id, int p_with_id, bool bidirectional) co
Segment s(p_id, p_with_id);
const Set<Segment>::Element *element = segments.find(s);
- return element != NULL &&
+ return element != nullptr &&
(bidirectional || (element->get().direction & s.direction) == s.direction);
}
@@ -399,7 +399,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
return found_route;
}
-float AStar::_estimate_cost(int p_from_id, int p_to_id) {
+real_t AStar::_estimate_cost(int p_from_id, int p_to_id) {
if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_estimate_cost))
return get_script_instance()->call(SceneStringNames::get_singleton()->_estimate_cost, p_from_id, p_to_id);
@@ -415,7 +415,7 @@ float AStar::_estimate_cost(int p_from_id, int p_to_id) {
return from_point->pos.distance_to(to_point->pos);
}
-float AStar::_compute_cost(int p_from_id, int p_to_id) {
+real_t AStar::_compute_cost(int p_from_id, int p_to_id) {
if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_compute_cost))
return get_script_instance()->call(SceneStringNames::get_singleton()->_compute_cost, p_from_id, p_to_id);
@@ -677,25 +677,195 @@ Vector2 AStar2D::get_closest_position_in_segment(const Vector2 &p_point) const {
return Vector2(p.x, p.y);
}
+real_t AStar2D::_estimate_cost(int p_from_id, int p_to_id) {
+
+ if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_estimate_cost))
+ return get_script_instance()->call(SceneStringNames::get_singleton()->_estimate_cost, p_from_id, p_to_id);
+
+ AStar::Point *from_point;
+ bool from_exists = astar.points.lookup(p_from_id, from_point);
+ ERR_FAIL_COND_V(!from_exists, 0);
+
+ AStar::Point *to_point;
+ bool to_exists = astar.points.lookup(p_to_id, to_point);
+ ERR_FAIL_COND_V(!to_exists, 0);
+
+ return from_point->pos.distance_to(to_point->pos);
+}
+
+real_t AStar2D::_compute_cost(int p_from_id, int p_to_id) {
+
+ if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_compute_cost))
+ return get_script_instance()->call(SceneStringNames::get_singleton()->_compute_cost, p_from_id, p_to_id);
+
+ AStar::Point *from_point;
+ bool from_exists = astar.points.lookup(p_from_id, from_point);
+ ERR_FAIL_COND_V(!from_exists, 0);
+
+ AStar::Point *to_point;
+ bool to_exists = astar.points.lookup(p_to_id, to_point);
+ ERR_FAIL_COND_V(!to_exists, 0);
+
+ return from_point->pos.distance_to(to_point->pos);
+}
+
Vector<Vector2> AStar2D::get_point_path(int p_from_id, int p_to_id) {
- PackedVector3Array pv = astar.get_point_path(p_from_id, p_to_id);
- int size = pv.size();
- PackedVector2Array path;
- path.resize(size);
+ AStar::Point *a;
+ bool from_exists = astar.points.lookup(p_from_id, a);
+ ERR_FAIL_COND_V(!from_exists, Vector<Vector2>());
+
+ AStar::Point *b;
+ bool to_exists = astar.points.lookup(p_to_id, b);
+ ERR_FAIL_COND_V(!to_exists, Vector<Vector2>());
+
+ if (a == b) {
+ Vector<Vector2> ret;
+ ret.push_back(Vector2(a->pos.x, a->pos.y));
+ return ret;
+ }
+
+ AStar::Point *begin_point = a;
+ AStar::Point *end_point = b;
+
+ bool found_route = _solve(begin_point, end_point);
+ if (!found_route) return Vector<Vector2>();
+
+ AStar::Point *p = end_point;
+ int pc = 1; // Begin point
+ while (p != begin_point) {
+ pc++;
+ p = p->prev_point;
+ }
+
+ Vector<Vector2> path;
+ path.resize(pc);
+
{
- const Vector3 *r = pv.ptr();
Vector2 *w = path.ptrw();
- for (int i = 0; i < size; i++) {
- Vector3 p = r[i];
- w[i] = Vector2(p.x, p.y);
+
+ AStar::Point *p2 = end_point;
+ int idx = pc - 1;
+ while (p2 != begin_point) {
+ w[idx--] = Vector2(p2->pos.x, p2->pos.y);
+ p2 = p2->prev_point;
}
+
+ w[0] = Vector2(p2->pos.x, p2->pos.y); // Assign first
}
+
return path;
}
Vector<int> AStar2D::get_id_path(int p_from_id, int p_to_id) {
- return astar.get_id_path(p_from_id, p_to_id);
+
+ AStar::Point *a;
+ bool from_exists = astar.points.lookup(p_from_id, a);
+ ERR_FAIL_COND_V(!from_exists, Vector<int>());
+
+ AStar::Point *b;
+ bool to_exists = astar.points.lookup(p_to_id, b);
+ ERR_FAIL_COND_V(!to_exists, Vector<int>());
+
+ if (a == b) {
+ Vector<int> ret;
+ ret.push_back(a->id);
+ return ret;
+ }
+
+ AStar::Point *begin_point = a;
+ AStar::Point *end_point = b;
+
+ bool found_route = _solve(begin_point, end_point);
+ if (!found_route) return Vector<int>();
+
+ AStar::Point *p = end_point;
+ int pc = 1; // Begin point
+ while (p != begin_point) {
+ pc++;
+ p = p->prev_point;
+ }
+
+ Vector<int> path;
+ path.resize(pc);
+
+ {
+ int *w = path.ptrw();
+
+ p = end_point;
+ int idx = pc - 1;
+ while (p != begin_point) {
+ w[idx--] = p->id;
+ p = p->prev_point;
+ }
+
+ w[0] = p->id; // Assign first
+ }
+
+ return path;
+}
+
+bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) {
+
+ astar.pass++;
+
+ if (!end_point->enabled) return false;
+
+ bool found_route = false;
+
+ Vector<AStar::Point *> open_list;
+ SortArray<AStar::Point *, AStar::SortPoints> sorter;
+
+ begin_point->g_score = 0;
+ begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
+ open_list.push_back(begin_point);
+
+ while (!open_list.empty()) {
+
+ AStar::Point *p = open_list[0]; // The currently processed point
+
+ if (p == end_point) {
+ found_route = true;
+ break;
+ }
+
+ sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
+ open_list.remove(open_list.size() - 1);
+ p->closed_pass = astar.pass; // Mark the point as closed
+
+ for (OAHashMap<int, AStar::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
+
+ AStar::Point *e = *(it.value); // The neighbour point
+
+ if (!e->enabled || e->closed_pass == astar.pass) {
+ continue;
+ }
+
+ real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale;
+
+ bool new_point = false;
+
+ if (e->open_pass != astar.pass) { // The point wasn't inside the open list.
+ e->open_pass = astar.pass;
+ open_list.push_back(e);
+ new_point = true;
+ } else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous.
+ continue;
+ }
+
+ e->prev_point = p;
+ e->g_score = tentative_g_score;
+ e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
+
+ if (new_point) { // The position of the new points is already known.
+ sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
+ } else {
+ sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
+ }
+ }
+ }
+
+ return found_route;
}
void AStar2D::_bind_methods() {
@@ -728,6 +898,9 @@ void AStar2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::get_point_path);
ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::get_id_path);
+
+ BIND_VMETHOD(MethodInfo(Variant::FLOAT, "_estimate_cost", PropertyInfo(Variant::INT, "from_id"), PropertyInfo(Variant::INT, "to_id")));
+ BIND_VMETHOD(MethodInfo(Variant::FLOAT, "_compute_cost", PropertyInfo(Variant::INT, "from_id"), PropertyInfo(Variant::INT, "to_id")));
}
AStar2D::AStar2D() {
diff --git a/core/math/a_star.h b/core/math/a_star.h
index bfcf0c09d3..8c10ace33c 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ASTAR_H
-#define ASTAR_H
+#ifndef A_STAR_H
+#define A_STAR_H
#include "core/oa_hash_map.h"
#include "core/reference.h"
@@ -43,6 +43,7 @@
class AStar : public Reference {
GDCLASS(AStar, Reference);
+ friend class AStar2D;
struct Point {
@@ -124,8 +125,8 @@ class AStar : public Reference {
protected:
static void _bind_methods();
- virtual float _estimate_cost(int p_from_id, int p_to_id);
- virtual float _compute_cost(int p_from_id, int p_to_id);
+ virtual real_t _estimate_cost(int p_from_id, int p_to_id);
+ virtual real_t _compute_cost(int p_from_id, int p_to_id);
public:
int get_available_point_id() const;
@@ -166,9 +167,14 @@ class AStar2D : public Reference {
GDCLASS(AStar2D, Reference);
AStar astar;
+ bool _solve(AStar::Point *begin_point, AStar::Point *end_point);
+
protected:
static void _bind_methods();
+ virtual real_t _estimate_cost(int p_from_id, int p_to_id);
+ virtual real_t _compute_cost(int p_from_id, int p_to_id);
+
public:
int get_available_point_id() const;
@@ -204,4 +210,4 @@ public:
~AStar2D();
};
-#endif // ASTAR_H
+#endif // A_STAR_H
diff --git a/core/math/aabb.h b/core/math/aabb.h
index d9d50c7139..eca74e6755 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -72,8 +72,8 @@ public:
AABB merge(const AABB &p_with) const;
void merge_with(const AABB &p_aabb); ///merge with another AABB
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
- bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = NULL, Vector3 *r_normal = NULL) const;
- bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = NULL, Vector3 *r_normal = NULL) const;
+ bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
+ bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count) const;
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index 6477d029d5..e1dbb385e4 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AUDIOFRAME_H
-#define AUDIOFRAME_H
+#ifndef AUDIO_FRAME_H
+#define AUDIO_FRAME_H
#include "core/math/vector2.h"
#include "core/typedefs.h"
@@ -140,4 +140,4 @@ struct AudioFrame {
_ALWAYS_INLINE_ AudioFrame() {}
};
-#endif
+#endif // AUDIO_FRAME_H
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 14079f811d..0f519a20d8 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -77,10 +77,6 @@ void Basis::invert() {
void Basis::orthonormalize() {
-#ifdef MATH_CHECKS
- ERR_FAIL_COND(determinant() == 0);
-#endif
-
// Gram-Schmidt Process
Vector3 x = get_axis(0);
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index c4981b954b..c36070e47f 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -145,7 +145,7 @@ void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_
f3 *= p_oversample;
// always apply KEEP_WIDTH aspect ratio
- f3 *= p_aspect;
+ f3 /= p_aspect;
switch (p_eye) {
case 1: { // left eye
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 60f7d15974..c10193bc84 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -124,4 +124,4 @@ Vector3 CameraMatrix::xform(const Vector3 &p_vec3) const {
return ret / w;
}
-#endif
+#endif // CAMERA_MATRIX_H
diff --git a/core/math/disjoint_set.h b/core/math/disjoint_set.h
index fb89941ce4..32b9875e4c 100644
--- a/core/math/disjoint_set.h
+++ b/core/math/disjoint_set.h
@@ -152,4 +152,4 @@ void DisjointSet<T, C, AL>::get_members(Vector<T> &out_members, T representative
}
}
-#endif
+#endif // DISJOINT_SET_H
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 04fda9d09a..859b9be8c5 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -760,7 +760,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
PackedByteArray barr;
bool full_objects = *p_inputs[1];
int len;
- Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
+ Error err = encode_variant(*p_inputs[0], nullptr, len, full_objects);
if (err) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -791,7 +791,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
Variant ret;
{
const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), NULL, allow_objects);
+ Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
@@ -1298,12 +1298,12 @@ Expression::ENode *Expression::_parse_expression() {
while (true) {
//keep appending stuff to expression
- ENode *expr = NULL;
+ ENode *expr = nullptr;
Token tk;
_get_token(tk);
if (error_set)
- return NULL;
+ return nullptr;
switch (tk.type) {
case TK_CURLY_BRACKET_OPEN: {
@@ -1321,18 +1321,18 @@ Expression::ENode *Expression::_parse_expression() {
//parse an expression
ENode *subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
dn->dict.push_back(subexpr);
_get_token(tk);
if (tk.type != TK_COLON) {
_set_error("Expected ':'");
- return NULL;
+ return nullptr;
}
subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
dn->dict.push_back(subexpr);
@@ -1365,7 +1365,7 @@ Expression::ENode *Expression::_parse_expression() {
//parse an expression
ENode *subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
an->array.push_back(subexpr);
cofs = str_ofs;
@@ -1385,11 +1385,11 @@ Expression::ENode *Expression::_parse_expression() {
//a suexpression
ENode *e = _parse_expression();
if (error_set)
- return NULL;
+ return nullptr;
_get_token(tk);
if (tk.type != TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')'");
- return NULL;
+ return nullptr;
}
expr = e;
@@ -1419,7 +1419,7 @@ Expression::ENode *Expression::_parse_expression() {
//parse an expression
ENode *subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
func_call->arguments.push_back(subexpr);
@@ -1484,7 +1484,7 @@ Expression::ENode *Expression::_parse_expression() {
_get_token(tk);
if (tk.type != TK_PARENTHESIS_OPEN) {
_set_error("Expected '('");
- return NULL;
+ return nullptr;
}
ConstructorNode *constructor = alloc_node<ConstructorNode>();
@@ -1501,7 +1501,7 @@ Expression::ENode *Expression::_parse_expression() {
//parse an expression
ENode *subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
constructor->arguments.push_back(subexpr);
@@ -1525,7 +1525,7 @@ Expression::ENode *Expression::_parse_expression() {
_get_token(tk);
if (tk.type != TK_PARENTHESIS_OPEN) {
_set_error("Expected '('");
- return NULL;
+ return nullptr;
}
BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
@@ -1542,7 +1542,7 @@ Expression::ENode *Expression::_parse_expression() {
//parse an expression
ENode *subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
bifunc->arguments.push_back(subexpr);
@@ -1584,7 +1584,7 @@ Expression::ENode *Expression::_parse_expression() {
default: {
_set_error("Expected expression.");
- return NULL;
+ return nullptr;
} break;
}
@@ -1594,7 +1594,7 @@ Expression::ENode *Expression::_parse_expression() {
int cofs2 = str_ofs;
_get_token(tk);
if (error_set)
- return NULL;
+ return nullptr;
bool done = false;
@@ -1607,14 +1607,14 @@ Expression::ENode *Expression::_parse_expression() {
ENode *what = _parse_expression();
if (!what)
- return NULL;
+ return nullptr;
index->index = what;
_get_token(tk);
if (tk.type != TK_BRACKET_CLOSE) {
_set_error("Expected ']' at end of index.");
- return NULL;
+ return nullptr;
}
expr = index;
@@ -1624,7 +1624,7 @@ Expression::ENode *Expression::_parse_expression() {
_get_token(tk);
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier after '.'");
- return NULL;
+ return nullptr;
}
StringName identifier = tk.value;
@@ -1648,7 +1648,7 @@ Expression::ENode *Expression::_parse_expression() {
//parse an expression
ENode *subexpr = _parse_expression();
if (!subexpr)
- return NULL;
+ return nullptr;
func_call->arguments.push_back(subexpr);
@@ -1698,7 +1698,7 @@ Expression::ENode *Expression::_parse_expression() {
int cofs = str_ofs;
_get_token(tk);
if (error_set)
- return NULL;
+ return nullptr;
Variant::Operator op = Variant::OP_MAX;
@@ -1805,7 +1805,7 @@ Expression::ENode *Expression::_parse_expression() {
default: {
_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
- return NULL;
+ return nullptr;
}
}
@@ -1822,7 +1822,7 @@ Expression::ENode *Expression::_parse_expression() {
if (next_op == -1) {
_set_error("Yet another parser bug....");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
// OK! create operator..
@@ -1835,7 +1835,7 @@ Expression::ENode *Expression::_parse_expression() {
if (expr_pos == expression.size()) {
//can happen..
_set_error("Unexpected end of expression...");
- return NULL;
+ return nullptr;
}
}
@@ -1845,7 +1845,7 @@ Expression::ENode *Expression::_parse_expression() {
OperatorNode *op = alloc_node<OperatorNode>();
op->op = expression[i].op;
op->nodes[0] = expression[i + 1].node;
- op->nodes[1] = NULL;
+ op->nodes[1] = nullptr;
expression.write[i].is_op = false;
expression.write[i].node = op;
expression.remove(i + 1);
@@ -1855,7 +1855,7 @@ Expression::ENode *Expression::_parse_expression() {
if (next_op < 1 || next_op >= (expression.size() - 1)) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
OperatorNode *op = alloc_node<OperatorNode>();
@@ -1864,7 +1864,7 @@ Expression::ENode *Expression::_parse_expression() {
if (expression[next_op - 1].is_op) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
if (expression[next_op + 1].is_op) {
@@ -1874,7 +1874,7 @@ Expression::ENode *Expression::_parse_expression() {
// due to how precedence works, unaries will always disappear first
_set_error("Unexpected two consecutive operators.");
- return NULL;
+ return nullptr;
}
op->nodes[0] = expression[next_op - 1].node; //expression goes as left
@@ -1897,8 +1897,8 @@ bool Expression::_compile_expression() {
if (nodes) {
memdelete(nodes);
- nodes = NULL;
- root = NULL;
+ nodes = nullptr;
+ root = nullptr;
}
error_str = String();
@@ -1908,11 +1908,11 @@ bool Expression::_compile_expression() {
root = _parse_expression();
if (error_set) {
- root = NULL;
+ root = nullptr;
if (nodes) {
memdelete(nodes);
}
- nodes = NULL;
+ nodes = nullptr;
return true;
}
@@ -2151,8 +2151,8 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
if (nodes) {
memdelete(nodes);
- nodes = NULL;
- root = NULL;
+ nodes = nullptr;
+ root = nullptr;
}
error_str = String();
@@ -2164,11 +2164,11 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
root = _parse_expression();
if (error_set) {
- root = NULL;
+ root = nullptr;
if (nodes) {
memdelete(nodes);
}
- nodes = NULL;
+ nodes = nullptr;
return ERR_INVALID_PARAMETER;
}
@@ -2212,9 +2212,11 @@ Expression::Expression() :
output_type(Variant::NIL),
sequenced(false),
error_set(true),
- root(NULL),
- nodes(NULL),
+ root(nullptr),
+ nodes(nullptr),
execution_error(false) {
+ str_ofs = 0;
+ expression_dirty = false;
}
Expression::~Expression() {
diff --git a/core/math/expression.h b/core/math/expression.h
index bbf946bb0a..78de225ebf 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -219,7 +219,7 @@ private:
Type type;
- ENode() { next = NULL; }
+ ENode() { next = nullptr; }
virtual ~ENode() {
if (next) {
memdelete(next);
@@ -352,7 +352,7 @@ protected:
public:
Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
- Variant execute(Array p_inputs, Object *p_base = NULL, bool p_show_error = true);
+ Variant execute(Array p_inputs, Object *p_base = nullptr, bool p_show_error = true);
bool has_execute_failed() const;
String get_error_text() const;
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index 69c7abfd30..3e07e9253e 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -214,9 +214,9 @@ static bool _group_face(_FaceClassify *p_faces, int len, int p_index, int p_grou
return true;
}
-Vector<Vector<Face3> > Geometry::separate_objects(Vector<Face3> p_array) {
+Vector<Vector<Face3>> Geometry::separate_objects(Vector<Face3> p_array) {
- Vector<Vector<Face3> > objects;
+ Vector<Vector<Face3>> objects;
int len = p_array.size();
@@ -235,7 +235,7 @@ Vector<Vector<Face3> > Geometry::separate_objects(Vector<Face3> p_array) {
bool error = _connect_faces(_fcptr, len, -1);
- ERR_FAIL_COND_V_MSG(error, Vector<Vector<Face3> >(), "Invalid geometry.");
+ ERR_FAIL_COND_V_MSG(error, Vector<Vector<Face3>>(), "Invalid geometry.");
// Group connected faces in separate objects.
@@ -679,8 +679,8 @@ Vector<Face3> Geometry::wrap_geometry(Vector<Face3> p_array, real_t *p_error) {
return wrapped_faces;
}
-Vector<Vector<Vector2> > Geometry::decompose_polygon_in_convex(Vector<Point2> polygon) {
- Vector<Vector<Vector2> > decomp;
+Vector<Vector<Vector2>> Geometry::decompose_polygon_in_convex(Vector<Point2> polygon) {
+ Vector<Vector<Vector2>> decomp;
List<TriangulatorPoly> in_poly, out_poly;
TriangulatorPoly inp;
@@ -1076,7 +1076,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu
r_size = Size2(results[best].max_w, results[best].max_h);
}
-Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) {
+Vector<Vector<Point2>> Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) {
using namespace ClipperLib;
@@ -1111,7 +1111,7 @@ Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p
clp.Execute(op, paths); // Works on closed polygons only.
}
// Have to scale points down now.
- Vector<Vector<Point2> > polypaths;
+ Vector<Vector<Point2>> polypaths;
for (Paths::size_type i = 0; i < paths.size(); ++i) {
Vector<Vector2> polypath;
@@ -1128,7 +1128,7 @@ Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p
return polypaths;
}
-Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+Vector<Vector<Point2>> Geometry::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
using namespace ClipperLib;
@@ -1162,7 +1162,7 @@ Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polyp
co.Execute(paths, p_delta * SCALE_FACTOR); // Inflate/deflate.
// Have to scale points down now.
- Vector<Vector<Point2> > polypaths;
+ Vector<Vector<Point2>> polypaths;
for (Paths::size_type i = 0; i < paths.size(); ++i) {
Vector<Vector2> polypath;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index a94d00bf77..e47d18b056 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -790,44 +790,44 @@ public:
END_ROUND
};
- static Vector<Vector<Point2> > merge_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+ static Vector<Vector<Point2>> merge_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
return _polypaths_do_operation(OPERATION_UNION, p_polygon_a, p_polygon_b);
}
- static Vector<Vector<Point2> > clip_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+ static Vector<Vector<Point2>> clip_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b);
}
- static Vector<Vector<Point2> > intersect_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+ static Vector<Vector<Point2>> intersect_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
return _polypaths_do_operation(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b);
}
- static Vector<Vector<Point2> > exclude_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+ static Vector<Vector<Point2>> exclude_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b);
}
- static Vector<Vector<Point2> > clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+ static Vector<Vector<Point2>> clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true);
}
- static Vector<Vector<Point2> > intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+ static Vector<Vector<Point2>> intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
return _polypaths_do_operation(OPERATION_INTERSECTION, p_polyline, p_polygon, true);
}
- static Vector<Vector<Point2> > offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
+ static Vector<Vector<Point2>> offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
return _polypath_offset(p_polygon, p_delta, p_join_type, END_POLYGON);
}
- static Vector<Vector<Point2> > offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+ static Vector<Vector<Point2>> offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
- ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector<Vector<Point2> >(), "Attempt to offset a polyline like a polygon (use offset_polygon_2d instead).");
+ ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector<Vector<Point2>>(), "Attempt to offset a polyline like a polygon (use offset_polygon_2d instead).");
return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type);
}
@@ -891,7 +891,7 @@ public:
for (int i = 0; i < c; i++) {
const Vector2 &v1 = p[i];
const Vector2 &v2 = p[(i + 1) % c];
- if (segment_intersects_segment_2d(v1, v2, p_point, further_away, NULL)) {
+ if (segment_intersects_segment_2d(v1, v2, p_point, further_away, nullptr)) {
intersections++;
}
}
@@ -899,10 +899,10 @@ public:
return (intersections & 1);
}
- static Vector<Vector<Face3> > separate_objects(Vector<Face3> p_array);
+ static Vector<Vector<Face3>> separate_objects(Vector<Face3> p_array);
// Create a "wrap" that encloses the given geometry.
- static Vector<Face3> wrap_geometry(Vector<Face3> p_array, real_t *p_error = NULL);
+ static Vector<Face3> wrap_geometry(Vector<Face3> p_array, real_t *p_error = nullptr);
struct MeshData {
@@ -1004,7 +1004,7 @@ public:
H.resize(k);
return H;
}
- static Vector<Vector<Vector2> > decompose_polygon_in_convex(Vector<Point2> polygon);
+ static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon);
static MeshData build_convex_mesh(const Vector<Plane> &p_planes);
static Vector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis = Vector3::AXIS_Z);
@@ -1015,8 +1015,8 @@ public:
static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
private:
- static Vector<Vector<Point2> > _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
- static Vector<Vector<Point2> > _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
+ static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
+ static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
};
-#endif
+#endif // GEOMETRY_H
diff --git a/core/math/octree.h b/core/math/octree.h
index 5478bdaf77..5225fbecb4 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -119,9 +119,9 @@ private:
children_count = 0;
parent_index = -1;
last_pass = 0;
- parent = NULL;
+ parent = nullptr;
for (int i = 0; i < 8; i++)
- children[i] = NULL;
+ children[i] = nullptr;
}
~Octant() {
@@ -171,7 +171,7 @@ private:
octree = 0;
pairable_mask = 0;
pairable_type = 0;
- common_parent = NULL;
+ common_parent = nullptr;
}
};
@@ -308,19 +308,19 @@ private:
while (root && root->children_count < 2 && !root->elements.size() && !(use_pairs && root->pairable_elements.size())) {
- Octant *new_root = NULL;
+ Octant *new_root = nullptr;
if (root->children_count == 1) {
for (int i = 0; i < 8; i++) {
if (root->children[i]) {
new_root = root->children[i];
- root->children[i] = NULL;
+ root->children[i] = nullptr;
break;
}
}
ERR_FAIL_COND(!new_root);
- new_root->parent = NULL;
+ new_root->parent = nullptr;
new_root->parent_index = -1;
}
@@ -332,7 +332,7 @@ private:
void _insert_element(Element *p_element, Octant *p_octant);
void _ensure_valid_root(const AABB &p_aabb);
- bool _remove_element_from_octant(Element *p_element, Octant *p_octant, Octant *p_limit = NULL);
+ bool _remove_element_from_octant(Element *p_element, Octant *p_octant, Octant *p_limit = nullptr);
void _remove_element(Element *p_element);
void _pair_element(Element *p_element, Octant *p_octant);
void _unpair_element(Element *p_element, Octant *p_octant);
@@ -377,10 +377,10 @@ public:
int get_subindex(OctreeElementID p_id) const;
int cull_convex(const Vector<Plane> &p_convex, T **p_result_array, int p_result_max, uint32_t p_mask = 0xFFFFFFFF);
- int cull_aabb(const AABB &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = NULL, uint32_t p_mask = 0xFFFFFFFF);
- int cull_segment(const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = NULL, uint32_t p_mask = 0xFFFFFFFF);
+ int cull_aabb(const AABB &p_aabb, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF);
+ int cull_segment(const Vector3 &p_from, const Vector3 &p_to, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF);
- int cull_point(const Vector3 &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = NULL, uint32_t p_mask = 0xFFFFFFFF);
+ int cull_point(const Vector3 &p_point, T **p_result_array, int p_result_max, int *p_subindex_array = nullptr, uint32_t p_mask = 0xFFFFFFFF);
void set_pair_callback(PairCallback p_callback, void *p_userdata);
void set_unpair_callback(UnpairCallback p_callback, void *p_userdata);
@@ -396,7 +396,7 @@ public:
template <class T, bool use_pairs, class AL>
T *Octree<T, use_pairs, AL>::get(OctreeElementID p_id) const {
const typename ElementMap::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, NULL);
+ ERR_FAIL_COND_V(!E, nullptr);
return E->get().userdata;
}
@@ -442,7 +442,7 @@ void Octree<T, use_pairs, AL>::_insert_element(Element *p_element, Octant *p_oct
p_element->octant_owners.push_back(owner);
- if (p_element->common_parent == NULL) {
+ if (p_element->common_parent == nullptr) {
p_element->common_parent = p_octant;
p_element->container_aabb = p_octant->aabb;
} else {
@@ -463,7 +463,7 @@ void Octree<T, use_pairs, AL>::_insert_element(Element *p_element, Octant *p_oct
} else {
/* not big enough, send it to subitems */
int splits = 0;
- bool candidate = p_element->common_parent == NULL;
+ bool candidate = p_element->common_parent == nullptr;
for (int i = 0; i < 8; i++) {
@@ -552,7 +552,7 @@ void Octree<T, use_pairs, AL>::_ensure_valid_root(const AABB &p_aabb) {
root = memnew_allocator(Octant, AL);
- root->parent = NULL;
+ root->parent = nullptr;
root->parent_index = -1;
root->aabb = base;
@@ -634,11 +634,11 @@ bool Octree<T, use_pairs, AL>::_remove_element_from_octant(Element *p_element, O
if (p_octant == root) { // won't have a parent, just erase
- root = NULL;
+ root = nullptr;
} else {
ERR_FAIL_INDEX_V(p_octant->parent_index, 8, octant_removed);
- parent->children[p_octant->parent_index] = NULL;
+ parent->children[p_octant->parent_index] = nullptr;
parent->children_count--;
}
@@ -852,12 +852,12 @@ void Octree<T, use_pairs, AL>::move(OctreeElementID p_id, const AABB &p_aabb) {
if (old_has_surf) {
_remove_element(&e); // removing
- e.common_parent = NULL;
+ e.common_parent = nullptr;
e.aabb = AABB();
_optimize();
} else {
_ensure_valid_root(p_aabb); // inserting
- e.common_parent = NULL;
+ e.common_parent = nullptr;
e.aabb = p_aabb;
_insert_element(&e, root);
if (use_pairs)
@@ -884,7 +884,7 @@ void Octree<T, use_pairs, AL>::move(OctreeElementID p_id, const AABB &p_aabb) {
combined.merge_with(p_aabb);
_ensure_valid_root(combined);
- ERR_FAIL_COND(e.octant_owners.front() == NULL);
+ ERR_FAIL_COND(e.octant_owners.front() == nullptr);
/* FIND COMMON PARENT */
@@ -902,7 +902,7 @@ void Octree<T, use_pairs, AL>::move(OctreeElementID p_id, const AABB &p_aabb) {
//prepare for reinsert
e.octant_owners.clear();
- e.common_parent = NULL;
+ e.common_parent = nullptr;
e.aabb = p_aabb;
_insert_element(&e, common_parent); // reinsert from this point
@@ -971,7 +971,7 @@ void Octree<T, use_pairs, AL>::set_pairable(OctreeElementID p_id, bool p_pairabl
e.pairable = p_pairable;
e.pairable_type = p_pairable_type;
e.pairable_mask = p_pairable_mask;
- e.common_parent = NULL;
+ e.common_parent = nullptr;
if (!e.aabb.has_no_surface()) {
_ensure_valid_root(e.aabb);
@@ -1364,15 +1364,15 @@ Octree<T, use_pairs, AL>::Octree(real_t p_unit_size) {
last_element_id = 1;
pass = 1;
unit_size = p_unit_size;
- root = NULL;
+ root = nullptr;
octant_count = 0;
pair_count = 0;
- pair_callback = NULL;
- unpair_callback = NULL;
- pair_callback_userdata = NULL;
- unpair_callback_userdata = NULL;
+ pair_callback = nullptr;
+ unpair_callback = nullptr;
+ pair_callback_userdata = nullptr;
+ unpair_callback_userdata = nullptr;
}
-#endif
+#endif // OCTREE_H
diff --git a/core/math/quat.h b/core/math/quat.h
index 11ae03dffb..b3135ad1ca 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -231,4 +231,4 @@ bool Quat::operator!=(const Quat &p_quat) const {
return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w;
}
-#endif
+#endif // QUAT_H
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 63dd18091f..7fbb26c377 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -399,7 +399,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
ERR_CONTINUE(!F);
List<Geometry::MeshData::Face>::Element *O = F->get().left == E ? F->get().right : F->get().left;
ERR_CONTINUE(O == E);
- ERR_CONTINUE(O == NULL);
+ ERR_CONTINUE(O == nullptr);
if (O->get().plane.is_equal_approx(f.plane)) {
//merge and delete edge and contiguous face, while repointing edges (uuugh!)
@@ -440,10 +440,10 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
// remove all edge connections to this face
for (Map<Edge, RetFaceConnect>::Element *G = ret_edges.front(); G; G = G->next()) {
if (G->get().left == O)
- G->get().left = NULL;
+ G->get().left = nullptr;
if (G->get().right == O)
- G->get().right = NULL;
+ G->get().right = nullptr;
}
ret_edges.erase(F); //remove the edge
diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h
index aea9ffad8b..173f919a73 100644
--- a/core/math/quick_hull.h
+++ b/core/math/quick_hull.h
@@ -77,15 +77,15 @@ private:
struct FaceConnect {
List<Face>::Element *left, *right;
FaceConnect() {
- left = NULL;
- right = NULL;
+ left = nullptr;
+ right = nullptr;
}
};
struct RetFaceConnect {
List<Geometry::MeshData::Face>::Element *left, *right;
RetFaceConnect() {
- left = NULL;
- right = NULL;
+ left = nullptr;
+ right = nullptr;
}
};
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index ac65ce3509..8fd5a056fa 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -37,10 +37,10 @@
#include "thirdparty/misc/pcg.h"
-#if defined(__GNUC__) || (_llvm_has_builtin(__builtin_clz))
+#if defined(__GNUC__)
#define CLZ32(x) __builtin_clz(x)
#elif defined(_MSC_VER)
-#include "intrin.h"
+#include <intrin.h>
static int __bsr_clz32(uint32_t x) {
unsigned long index;
_BitScanReverse(&index, x);
@@ -50,11 +50,11 @@ static int __bsr_clz32(uint32_t x) {
#else
#endif
-#if defined(__GNUC__) || (_llvm_has_builtin(__builtin_ldexp) && _llvm_has_builtin(__builtin_ldexpf))
+#if defined(__GNUC__)
#define LDEXP(s, e) __builtin_ldexp(s, e)
#define LDEXPF(s, e) __builtin_ldexpf(s, e)
#else
-#include "math.h"
+#include <math.h>
#define LDEXP(s, e) ldexp(s, e)
#define LDEXPF(s, e) ldexp(s, e)
#endif
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 3b9660e2f0..30dbfdbbe5 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -105,7 +105,7 @@ struct Rect2 {
bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const;
- bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = NULL, Point2 *r_normal = NULL) const;
+ bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = nullptr, Point2 *r_normal = nullptr) const;
inline bool encloses(const Rect2 &p_rect) const {
diff --git a/core/math/triangulate.h b/core/math/triangulate.h
index f9bcb37141..c453b77ecf 100644
--- a/core/math/triangulate.h
+++ b/core/math/triangulate.h
@@ -58,4 +58,4 @@ private:
static bool snip(const Vector<Vector2> &p_contour, int u, int v, int w, int n, const Vector<int> &V, bool relaxed);
};
-#endif
+#endif // TRIANGULATE_H
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index 37207483fe..652c424492 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -34,7 +34,7 @@
#include "core/project_settings.h"
#include "core/script_language.h"
-MessageQueue *MessageQueue::singleton = NULL;
+MessageQueue *MessageQueue::singleton = nullptr;
MessageQueue *MessageQueue::get_singleton() {
@@ -174,7 +174,7 @@ void MessageQueue::statistics() {
Object *target = message->callable.get_object();
- if (target != NULL) {
+ if (target != nullptr) {
switch (message->type & FLAG_MASK) {
@@ -240,7 +240,7 @@ int MessageQueue::get_max_buffer_usage() const {
void MessageQueue::_call_function(const Callable &p_callable, const Variant *p_args, int p_argcount, bool p_show_error) {
- const Variant **argptrs = NULL;
+ const Variant **argptrs = nullptr;
if (p_argcount) {
argptrs = (const Variant **)alloca(sizeof(Variant *) * p_argcount);
for (int i = 0; i < p_argcount; i++) {
@@ -291,7 +291,7 @@ void MessageQueue::flush() {
Object *target = message->callable.get_object();
- if (target != NULL) {
+ if (target != nullptr) {
switch (message->type & FLAG_MASK) {
case TYPE_CALL: {
@@ -343,14 +343,14 @@ bool MessageQueue::is_flushing() const {
MessageQueue::MessageQueue() {
- ERR_FAIL_COND_MSG(singleton != NULL, "MessageQueue singleton already exist.");
+ ERR_FAIL_COND_MSG(singleton != nullptr, "A MessageQueue singleton already exists.");
singleton = this;
flushing = false;
buffer_end = 0;
buffer_max_used = 0;
buffer_size = GLOBAL_DEF_RST("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB);
- ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "0,2048,1,or_greater"));
+ ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater"));
buffer_size *= 1024;
buffer = memnew_arr(uint8_t, buffer_size);
}
@@ -375,6 +375,6 @@ MessageQueue::~MessageQueue() {
read_pos += sizeof(Variant) * message->args;
}
- singleton = NULL;
+ singleton = nullptr;
memdelete_arr(buffer);
}
diff --git a/core/method_bind.cpp b/core/method_bind.cpp
index 2c9d0cee2f..c513de9ca0 100644
--- a/core/method_bind.cpp
+++ b/core/method_bind.cpp
@@ -108,7 +108,7 @@ MethodBind::MethodBind() {
argument_count = 0;
default_argument_count = 0;
#ifdef DEBUG_METHODS_ENABLED
- argument_types = NULL;
+ argument_types = nullptr;
#endif
_const = false;
_returns = false;
diff --git a/core/method_bind.h b/core/method_bind.h
index 726ce512f8..588b472b62 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -382,7 +382,7 @@ public:
virtual bool is_vararg() const { return true; }
MethodBindVarArg() {
- call_method = NULL;
+ call_method = nullptr;
_set_returns(true);
}
};
@@ -405,4 +405,4 @@ class __UnexistingClass;
#include "method_bind.gen.inc"
-#endif
+#endif // METHOD_BIND_H
diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h
index 3db186ca69..7ae0a788bd 100644
--- a/core/method_ptrcall.h
+++ b/core/method_ptrcall.h
@@ -118,6 +118,9 @@ MAKE_PTRARG(String);
MAKE_PTRARG(Vector2);
MAKE_PTRARG(Rect2);
MAKE_PTRARG_BY_REFERENCE(Vector3);
+MAKE_PTRARG(Vector2i);
+MAKE_PTRARG(Rect2i);
+MAKE_PTRARG_BY_REFERENCE(Vector3i);
MAKE_PTRARG(Transform2D);
MAKE_PTRARG_BY_REFERENCE(Plane);
MAKE_PTRARG(Quat);
@@ -192,7 +195,7 @@ struct PtrToArg<ObjectID> {
#define MAKE_VECARG(m_type) \
template <> \
- struct PtrToArg<Vector<m_type> > { \
+ struct PtrToArg<Vector<m_type>> { \
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
Vector<m_type> ret; \
@@ -237,7 +240,7 @@ struct PtrToArg<ObjectID> {
#define MAKE_VECARG_ALT(m_type, m_type_alt) \
template <> \
- struct PtrToArg<Vector<m_type_alt> > { \
+ struct PtrToArg<Vector<m_type_alt>> { \
_FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
const Vector<m_type> *dvs = reinterpret_cast<const Vector<m_type> *>(p_ptr); \
Vector<m_type_alt> ret; \
@@ -293,7 +296,7 @@ MAKE_VECARG_ALT(String, StringName);
//for stuff that gets converted to Array vectors
#define MAKE_VECARR(m_type) \
template <> \
- struct PtrToArg<Vector<m_type> > { \
+ struct PtrToArg<Vector<m_type>> { \
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
Vector<m_type> ret; \
@@ -333,7 +336,7 @@ MAKE_VECARR(Plane);
#define MAKE_DVECARR(m_type) \
template <> \
- struct PtrToArg<Vector<m_type> > { \
+ struct PtrToArg<Vector<m_type>> { \
_FORCE_INLINE_ static Vector<m_type> convert(const void *p_ptr) { \
const Array *arr = reinterpret_cast<const Array *>(p_ptr); \
Vector<m_type> ret; \
@@ -402,7 +405,7 @@ MAKE_VECARR(Plane);
MAKE_STRINGCONV_BY_REFERENCE(IP_Address);
template <>
-struct PtrToArg<Vector<Face3> > {
+struct PtrToArg<Vector<Face3>> {
_FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
const Vector<Vector3> *dvs = reinterpret_cast<const Vector<Vector3> *>(p_ptr);
Vector<Face3> ret;
diff --git a/core/node_path.cpp b/core/node_path.cpp
index e844cd7c27..83233622a0 100644
--- a/core/node_path.cpp
+++ b/core/node_path.cpp
@@ -99,7 +99,7 @@ void NodePath::unref() {
memdelete(data);
}
- data = NULL;
+ data = nullptr;
}
bool NodePath::operator==(const NodePath &p_path) const {
@@ -189,7 +189,7 @@ NodePath::operator String() const {
NodePath::NodePath(const NodePath &p_path) {
- data = NULL;
+ data = nullptr;
if (p_path.data && p_path.data->refcount.ref()) {
@@ -287,7 +287,7 @@ NodePath NodePath::get_as_property_path() const {
NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {
- data = NULL;
+ data = nullptr;
if (p_path.size() == 0)
return;
@@ -302,7 +302,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {
NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) {
- data = NULL;
+ data = nullptr;
if (p_path.size() == 0 && p_subpath.size() == 0)
return;
@@ -349,7 +349,7 @@ NodePath NodePath::simplified() const {
NodePath::NodePath(const String &p_path) {
- data = NULL;
+ data = nullptr;
if (p_path.length() == 0)
return;
@@ -442,7 +442,7 @@ bool NodePath::is_empty() const {
}
NodePath::NodePath() {
- data = NULL;
+ data = nullptr;
}
NodePath::~NodePath() {
diff --git a/core/node_path.h b/core/node_path.h
index 05b6d844ff..76de36cd9f 100644
--- a/core/node_path.h
+++ b/core/node_path.h
@@ -97,4 +97,4 @@ public:
~NodePath();
};
-#endif
+#endif // NODE_PATH_H
diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h
index 182ed8b116..71e3ba9068 100644
--- a/core/oa_hash_map.h
+++ b/core/oa_hash_map.h
@@ -48,7 +48,7 @@
*/
template <class TKey, class TValue,
class Hasher = HashMapHasherDefault,
- class Comparator = HashMapComparatorDefault<TKey> >
+ class Comparator = HashMapComparatorDefault<TKey>>
class OAHashMap {
private:
@@ -224,7 +224,7 @@ public:
/**
* returns true if the value was found, false otherwise.
*
- * if r_data is not NULL then the value will be written to the object
+ * if r_data is not nullptr then the value will be written to the object
* it points to.
*/
bool lookup(const TKey &p_key, TValue &r_data) const {
@@ -243,7 +243,7 @@ public:
/**
* returns true if the value was found, false otherwise.
*
- * if r_data is not NULL then the value will be written to the object
+ * if r_data is not nullptr then the value will be written to the object
* it points to.
*/
TValue *lookup_ptr(const TKey &p_key) const {
@@ -253,7 +253,7 @@ public:
if (exists) {
return &values[pos];
}
- return NULL;
+ return nullptr;
}
_FORCE_INLINE_ bool has(const TKey &p_key) const {
@@ -325,8 +325,8 @@ public:
Iterator it;
it.valid = false;
it.pos = p_iter.pos;
- it.key = NULL;
- it.value = NULL;
+ it.key = nullptr;
+ it.value = nullptr;
for (uint32_t i = it.pos; i < capacity; i++) {
it.pos = i + 1;
@@ -369,4 +369,4 @@ public:
}
};
-#endif
+#endif // OA_HASH_MAP_H
diff --git a/core/object.cpp b/core/object.cpp
index 140ee811fe..b0e6f2bdae 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -368,7 +368,7 @@ bool Object::_predelete() {
_predelete_ok = 1;
notification(NOTIFICATION_PREDELETE, true);
if (_predelete_ok) {
- _class_ptr = NULL; //must restore so destructors can access class ptr correctly
+ _class_ptr = nullptr; //must restore so destructors can access class ptr correctly
}
return _predelete_ok;
}
@@ -781,7 +781,7 @@ bool Object::has_method(const StringName &p_method) const {
MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
- return method != NULL;
+ return method != nullptr;
}
Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
@@ -797,7 +797,7 @@ void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid)
}
Variant Object::callv(const StringName &p_method, const Array &p_args) {
- const Variant **argptrs = NULL;
+ const Variant **argptrs = nullptr;
if (p_args.size() > 0) {
argptrs = (const Variant **)alloca(sizeof(Variant *) * p_args.size());
@@ -955,7 +955,7 @@ void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_
//this function is not meant to be used in any of these ways
ERR_FAIL_COND(p_script.is_null());
ERR_FAIL_COND(!p_instance);
- ERR_FAIL_COND(script_instance != NULL || !script.is_null());
+ ERR_FAIL_COND(script_instance != nullptr || !script.is_null());
script = p_script;
script_instance = p_instance;
@@ -968,7 +968,7 @@ void Object::set_script(const Variant &p_script) {
if (script_instance) {
memdelete(script_instance);
- script_instance = NULL;
+ script_instance = nullptr;
}
script = p_script;
@@ -1119,7 +1119,7 @@ Variant Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::C
StringName signal = *p_args[0];
- const Variant **args = NULL;
+ const Variant **args = nullptr;
int argc = p_argcount - 1;
if (argc) {
@@ -1324,6 +1324,25 @@ Array Object::_get_incoming_connections() const {
return ret;
}
+bool Object::has_signal(const StringName &p_name) const {
+ if (!script.is_null()) {
+ Ref<Script> scr = script;
+ if (scr.is_valid() && scr->has_script_signal(p_name)) {
+ return true;
+ }
+ }
+
+ if (ClassDB::has_signal(get_class_name(), p_name)) {
+ return true;
+ }
+
+ if (_has_user_signal(p_name)) {
+ return true;
+ }
+
+ return false;
+}
+
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
if (!script.is_null()) {
@@ -1335,7 +1354,7 @@ void Object::get_signal_list(List<MethodInfo> *p_signals) const {
ClassDB::get_signal_list(get_class_name(), p_signals);
//find maybe usersignals?
- const StringName *S = NULL;
+ const StringName *S = nullptr;
while ((S = signal_map.next(S))) {
@@ -1348,7 +1367,7 @@ void Object::get_signal_list(List<MethodInfo> *p_signals) const {
void Object::get_all_signal_connections(List<Connection> *p_connections) const {
- const StringName *S = NULL;
+ const StringName *S = nullptr;
while ((S = signal_map.next(S))) {
@@ -1374,7 +1393,7 @@ void Object::get_signal_connection_list(const StringName &p_signal, List<Connect
int Object::get_persistent_signal_connection_count() const {
int count = 0;
- const StringName *S = NULL;
+ const StringName *S = nullptr;
while ((S = signal_map.next(S))) {
@@ -1486,7 +1505,7 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
return s->slot_map.has(target);
//const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target);
- //return (E!=NULL);
+ //return (E!=nullptr );
}
void Object::disconnect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) {
@@ -1696,6 +1715,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method);
+ ClassDB::bind_method(D_METHOD("has_signal", "signal"), &Object::has_signal);
ClassDB::bind_method(D_METHOD("get_signal_list"), &Object::_get_signal_list);
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections);
@@ -1820,7 +1840,7 @@ Variant::Type Object::get_static_property_type_indexed(const Vector<StringName>
}
Callable::CallError ce;
- Variant check = Variant::construct(t, NULL, 0, ce);
+ Variant check = Variant::construct(t, nullptr, 0, ce);
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) {
@@ -1869,7 +1889,7 @@ uint32_t Object::get_edited_version() const {
void *Object::get_script_instance_binding(int p_script_language_index) {
#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, NULL);
+ 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
@@ -1890,19 +1910,19 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
bool Object::has_script_instance_binding(int p_script_language_index) {
- return _script_instance_bindings[p_script_language_index] != NULL;
+ return _script_instance_bindings[p_script_language_index] != nullptr;
}
void Object::set_script_instance_binding(int p_script_language_index, void *p_data) {
#ifdef DEBUG_ENABLED
- CRASH_COND(_script_instance_bindings[p_script_language_index] != NULL);
+ CRASH_COND(_script_instance_bindings[p_script_language_index] != nullptr);
#endif
_script_instance_bindings[p_script_language_index] = p_data;
}
void Object::_construct_object(bool p_reference) {
type_is_reference = p_reference;
- _class_ptr = NULL;
+ _class_ptr = nullptr;
_block_signals = false;
_predelete_ok = 0;
_instance_id = ObjectDB::add_instance(this);
@@ -1911,7 +1931,7 @@ void Object::_construct_object(bool p_reference) {
_emitting = false;
instance_binding_count = 0;
memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS);
- script_instance = NULL;
+ script_instance = nullptr;
#ifdef TOOLS_ENABLED
_edited = false;
@@ -1935,16 +1955,16 @@ Object::~Object() {
if (script_instance)
memdelete(script_instance);
- script_instance = NULL;
+ script_instance = nullptr;
- const StringName *S = NULL;
+ const StringName *S = nullptr;
if (_emitting) {
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
ERR_PRINT("Object " + to_string() + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes.");
}
- while ((S = signal_map.next(NULL))) {
+ while ((S = signal_map.next(nullptr))) {
SignalData *s = &signal_map[*S];
diff --git a/core/object.h b/core/object.h
index 59d3f06cfe..1eaab5034e 100644
--- a/core/object.h
+++ b/core/object.h
@@ -60,7 +60,6 @@ enum PropertyHint {
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
- PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat.
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
@@ -107,10 +106,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings
PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor
PROPERTY_USAGE_CATEGORY = 256,
- // FIXME: Drop in 4.0, possibly reorder other flags?
- // Those below are deprecated thanks to ClassDB's now class value cache
- //PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero
- //PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false
+ PROPERTY_USAGE_SUBGROUP = 512,
PROPERTY_USAGE_NO_INSTANCE_STATE = 2048,
PROPERTY_USAGE_RESTART_IF_CHANGED = 4096,
PROPERTY_USAGE_SCRIPT_VARIABLE = 8192,
@@ -138,6 +134,7 @@ enum PropertyUsageFlags {
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index)
#define ADD_PROPERTY_DEFAULT(m_property, m_default) ClassDB::set_property_default_value(get_class_static(), m_property, m_default)
#define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
+#define ADD_SUBGROUP(m_name, m_prefix) ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
struct PropertyInfo {
@@ -242,7 +239,7 @@ struct MethodInfo {
//if ( is_type(T::get_class_static()) )
//return static_cast<T*>(this);
////else
-//return NULL;
+//return nullptr;
/*
the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model.
@@ -591,11 +588,11 @@ public:
return dynamic_cast<T *>(p_object);
#else
if (!p_object)
- return NULL;
+ return nullptr;
if (p_object->is_class_ptr(T::get_class_ptr_static()))
return static_cast<T *>(p_object);
else
- return NULL;
+ return nullptr;
#endif
}
@@ -605,11 +602,11 @@ public:
return dynamic_cast<const T *>(p_object);
#else
if (!p_object)
- return NULL;
+ return nullptr;
if (p_object->is_class_ptr(T::get_class_ptr_static()))
return static_cast<const T *>(p_object);
else
- return NULL;
+ return nullptr;
#endif
}
@@ -644,10 +641,10 @@ public:
//void set(const String& p_name, const Variant& p_value);
//Variant get(const String& p_name) const;
- void set(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL);
- Variant get(const StringName &p_name, bool *r_valid = NULL) const;
- void set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid = NULL);
- Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = NULL) const;
+ void set(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr);
+ Variant get(const StringName &p_name, bool *r_valid = nullptr) const;
+ void set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid = nullptr);
+ Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = nullptr) const;
void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const;
@@ -664,8 +661,8 @@ public:
String to_string();
//used mainly by script, get and set all INCLUDING string
- virtual Variant getvar(const Variant &p_key, bool *r_valid = NULL) const;
- virtual void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = NULL);
+ virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
+ virtual void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = nullptr);
/* SCRIPT */
@@ -694,6 +691,7 @@ public:
void add_user_signal(const MethodInfo &p_signal);
Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST);
Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount);
+ bool has_signal(const StringName &p_name) const;
void get_signal_list(List<MethodInfo> *p_signals) const;
void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
void get_all_signal_connections(List<Connection> *p_connections) const;
@@ -714,8 +712,8 @@ public:
void set_block_signals(bool p_block);
bool is_blocking_signals() const;
- Variant::Type get_static_property_type(const StringName &p_property, bool *r_valid = NULL) const;
- Variant::Type get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid = NULL) const;
+ Variant::Type get_static_property_type(const StringName &p_property, bool *r_valid = nullptr) const;
+ Variant::Type get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid = nullptr) const;
virtual void get_translatable_strings(List<String> *p_strings) const;
@@ -816,4 +814,4 @@ public:
//needed by macros
#include "core/class_db.h"
-#endif
+#endif // OBJECT_H
diff --git a/core/ordered_hash_map.h b/core/ordered_hash_map.h
index a10cf06b75..05debd529f 100644
--- a/core/ordered_hash_map.h
+++ b/core/ordered_hash_map.h
@@ -45,7 +45,7 @@
*/
template <class K, class V, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<K>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
class OrderedHashMap {
- typedef List<Pair<const K *, V> > InternalList;
+ typedef List<Pair<const K *, V>> InternalList;
typedef HashMap<K, typename InternalList::Element *, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP> InternalMap;
InternalList list;
@@ -70,9 +70,9 @@ public:
public:
_FORCE_INLINE_ Element() :
- list_element(NULL),
- prev_element(NULL),
- next_element(NULL) {
+ list_element(nullptr),
+ prev_element(nullptr),
+ next_element(nullptr) {
}
Element next() const {
@@ -104,7 +104,7 @@ public:
}
operator bool() const {
- return (list_element != NULL);
+ return (list_element != nullptr);
}
const K &key() const {
@@ -144,7 +144,7 @@ public:
public:
_FORCE_INLINE_ ConstElement() :
- list_element(NULL) {
+ list_element(nullptr) {
}
ConstElement(const ConstElement &other) :
@@ -157,11 +157,11 @@ public:
}
ConstElement next() const {
- return ConstElement(list_element ? list_element->next() : NULL);
+ return ConstElement(list_element ? list_element->next() : nullptr);
}
ConstElement prev() const {
- return ConstElement(list_element ? list_element->prev() : NULL);
+ return ConstElement(list_element ? list_element->prev() : nullptr);
}
_FORCE_INLINE_ bool operator==(const ConstElement &p_other) const {
@@ -172,7 +172,7 @@ public:
}
operator bool() const {
- return (list_element != NULL);
+ return (list_element != nullptr);
}
const K &key() const {
@@ -196,7 +196,7 @@ public:
if (list_element) {
return ConstElement(*list_element);
}
- return ConstElement(NULL);
+ return ConstElement(nullptr);
}
Element find(const K &p_key) {
@@ -204,7 +204,7 @@ public:
if (list_element) {
return Element(*list_element);
}
- return Element(NULL);
+ return Element(nullptr);
}
Element insert(const K &p_key, const V &p_value) {
@@ -213,7 +213,7 @@ public:
(*list_element)->get().second = p_value;
return Element(*list_element);
}
- typename InternalList::Element *new_element = list.push_back(Pair<const K *, V>(NULL, p_value));
+ typename InternalList::Element *new_element = list.push_back(Pair<const K *, V>(nullptr, p_value));
typename InternalMap::Element *e = map.set(p_key, new_element);
new_element->get().first = &e->key();
@@ -223,7 +223,7 @@ public:
void erase(Element &p_element) {
map.erase(p_element.key());
list.erase(p_element.list_element);
- p_element.list_element = NULL;
+ p_element.list_element = nullptr;
}
bool erase(const K &p_key) {
diff --git a/core/os/SCsub b/core/os/SCsub
index 1c5f954470..19a6549225 100644
--- a/core/os/SCsub
+++ b/core/os/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/os/copymem.h b/core/os/copymem.h
index 1d6631ddb8..04ea3caeff 100644
--- a/core/os/copymem.h
+++ b/core/os/copymem.h
@@ -47,4 +47,4 @@
#endif
-#endif
+#endif // COPYMEM_H
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index 642c86be2f..94c8cd5d73 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -226,11 +226,11 @@ String DirAccess::fix_path(String p_path) const {
return p_path;
}
-DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { 0, 0, 0 };
+DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { nullptr, nullptr, nullptr };
DirAccess *DirAccess::create_for_path(const String &p_path) {
- DirAccess *da = NULL;
+ DirAccess *da = nullptr;
if (p_path.begins_with("res://")) {
da = create(ACCESS_RESOURCES);
@@ -249,13 +249,13 @@ DirAccess *DirAccess::open(const String &p_path, Error *r_error) {
DirAccess *da = create_for_path(p_path);
- ERR_FAIL_COND_V_MSG(!da, NULL, "Cannot create DirAccess for path '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(!da, nullptr, "Cannot create DirAccess for path '" + p_path + "'.");
Error err = da->change_dir(p_path);
if (r_error)
*r_error = err;
if (err != OK) {
memdelete(da);
- return NULL;
+ return nullptr;
}
return da;
@@ -263,7 +263,7 @@ DirAccess *DirAccess::open(const String &p_path, Error *r_error) {
DirAccess *DirAccess::create(AccessType p_access) {
- DirAccess *da = create_func[p_access] ? create_func[p_access]() : NULL;
+ DirAccess *da = create_func[p_access] ? create_func[p_access]() : nullptr;
if (da) {
da->_access_type = p_access;
}
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index aac6c67f0a..60eb553968 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -128,7 +128,7 @@ public:
create_func[p_access] = _create_builtin<T>;
}
- static DirAccess *open(const String &p_path, Error *r_error = NULL);
+ static DirAccess *open(const String &p_path, Error *r_error = nullptr);
DirAccess();
virtual ~DirAccess();
@@ -141,7 +141,7 @@ struct DirAccessRef {
return f;
}
- operator bool() const { return f != NULL; }
+ operator bool() const { return f != nullptr; }
DirAccess *f;
DirAccessRef(DirAccess *fa) { f = fa; }
~DirAccessRef() {
@@ -149,4 +149,4 @@ struct DirAccessRef {
}
};
-#endif
+#endif // DIR_ACCESS_H
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 30cfaa7617..3922f031b7 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -36,15 +36,15 @@
#include "core/os/os.h"
#include "core/project_settings.h"
-FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { 0, 0 };
+FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr };
-FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = NULL;
+FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr;
bool FileAccess::backup_save = false;
FileAccess *FileAccess::create(AccessType p_access) {
- ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, 0);
+ ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
FileAccess *ret = create_func[p_access]();
ret->_set_access_type(p_access);
@@ -70,7 +70,7 @@ void FileAccess::_set_access_type(AccessType p_access) {
FileAccess *FileAccess::create_for_path(const String &p_path) {
- FileAccess *ret = NULL;
+ FileAccess *ret = nullptr;
if (p_path.begins_with("res://")) {
ret = create(ACCESS_RESOURCES);
@@ -95,7 +95,7 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er
//try packed data first
- FileAccess *ret = NULL;
+ FileAccess *ret = nullptr;
if (!(p_mode_flags & WRITE) && PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled()) {
ret = PackedData::get_singleton()->try_open_path(p_path);
if (ret) {
@@ -113,7 +113,7 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er
if (err != OK) {
memdelete(ret);
- ret = NULL;
+ ret = nullptr;
}
return ret;
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 36a947c691..010cc74a87 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -153,7 +153,7 @@ public:
static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static FileAccess *create_for_path(const String &p_path);
- static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = NULL); /// Create a file access (for the current platform) this is the only portable way of accessing files.
+ static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
@@ -167,8 +167,8 @@ public:
static String get_sha256(const String &p_file);
static String get_multiple_md5(const Vector<String> &p_file);
- static Vector<uint8_t> get_file_as_array(const String &p_path, Error *r_error = NULL);
- static String get_file_as_string(const String &p_path, Error *r_error = NULL);
+ static Vector<uint8_t> get_file_as_array(const String &p_path, Error *r_error = nullptr);
+ static String get_file_as_string(const String &p_path, Error *r_error = nullptr);
template <class T>
static void make_default(AccessType p_access) {
@@ -187,7 +187,7 @@ struct FileAccessRef {
return f;
}
- operator bool() const { return f != NULL; }
+ operator bool() const { return f != nullptr; }
FileAccess *f;
operator FileAccess *() { return f; }
FileAccessRef(FileAccess *fa) { f = fa; }
@@ -196,4 +196,4 @@ struct FileAccessRef {
}
};
-#endif
+#endif // FILE_ACCESS_H
diff --git a/core/os/input.cpp b/core/os/input.cpp
deleted file mode 100644
index 1768b851df..0000000000
--- a/core/os/input.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*************************************************************************/
-/* input.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.h"
-
-#include "core/input_map.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
-
-Input *Input::singleton = NULL;
-
-Input *Input::get_singleton() {
-
- return singleton;
-}
-
-void Input::set_mouse_mode(MouseMode p_mode) {
- ERR_FAIL_INDEX((int)p_mode, 4);
- OS::get_singleton()->set_mouse_mode((OS::MouseMode)p_mode);
-}
-
-Input::MouseMode Input::get_mouse_mode() const {
-
- return (MouseMode)OS::get_singleton()->get_mouse_mode();
-}
-
-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("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
- ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed);
- ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known);
- ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
- ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
- ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
- ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
- ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
- ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
- ClassDB::bind_method(D_METHOD("get_joy_button_string", "button_index"), &Input::get_joy_button_string);
- ClassDB::bind_method(D_METHOD("get_joy_button_index_from_string", "button"), &Input::get_joy_button_index_from_string);
- ClassDB::bind_method(D_METHOD("get_joy_axis_string", "axis_index"), &Input::get_joy_axis_string);
- ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string);
- ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
- ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
- ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
- ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
- ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
- ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope);
- //ClassDB::bind_method(D_METHOD("get_mouse_position"),&Input::get_mouse_position); - this is not the function you want
- ClassDB::bind_method(D_METHOD("get_last_mouse_speed"), &Input::get_last_mouse_speed);
- ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask);
- ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
- ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
- ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
- ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
- ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
- ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
- ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
- ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
- ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
-
- BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
- BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
- BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
- BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
-
- BIND_ENUM_CONSTANT(CURSOR_ARROW);
- BIND_ENUM_CONSTANT(CURSOR_IBEAM);
- BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
- BIND_ENUM_CONSTANT(CURSOR_CROSS);
- BIND_ENUM_CONSTANT(CURSOR_WAIT);
- BIND_ENUM_CONSTANT(CURSOR_BUSY);
- BIND_ENUM_CONSTANT(CURSOR_DRAG);
- BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
- BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
- BIND_ENUM_CONSTANT(CURSOR_VSIZE);
- BIND_ENUM_CONSTANT(CURSOR_HSIZE);
- BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
- BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
- BIND_ENUM_CONSTANT(CURSOR_MOVE);
- BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
- BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
- BIND_ENUM_CONSTANT(CURSOR_HELP);
-
- ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
-}
-
-void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
-
- const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
-
- String pf = p_function;
- if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
-
- List<PropertyInfo> pinfo;
- ProjectSettings::get_singleton()->get_property_list(&pinfo);
-
- for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
- const PropertyInfo &pi = E->get();
-
- if (!pi.name.begins_with("input/"))
- continue;
-
- String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- r_options->push_back(quote_style + name + quote_style);
- }
- }
-#endif
-}
-
-Input::Input() {
-
- singleton = this;
-}
-
-//////////////////////////////////////////////////////////
diff --git a/core/os/input.h b/core/os/input.h
deleted file mode 100644
index 55e0511080..0000000000
--- a/core/os/input.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*************************************************************************/
-/* input.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 INPUT_H
-#define INPUT_H
-
-#include "core/object.h"
-#include "core/os/main_loop.h"
-#include "core/os/thread_safe.h"
-
-class Input : public Object {
-
- GDCLASS(Input, Object);
-
- static Input *singleton;
-
-protected:
- static void _bind_methods();
-
-public:
- enum MouseMode {
- MOUSE_MODE_VISIBLE,
- MOUSE_MODE_HIDDEN,
- MOUSE_MODE_CAPTURED,
- MOUSE_MODE_CONFINED
- };
-
-#undef CursorShape
- enum CursorShape {
- CURSOR_ARROW,
- CURSOR_IBEAM,
- CURSOR_POINTING_HAND,
- CURSOR_CROSS,
- CURSOR_WAIT,
- CURSOR_BUSY,
- CURSOR_DRAG,
- CURSOR_CAN_DROP,
- CURSOR_FORBIDDEN,
- CURSOR_VSIZE,
- CURSOR_HSIZE,
- CURSOR_BDIAGSIZE,
- CURSOR_FDIAGSIZE,
- CURSOR_MOVE,
- CURSOR_VSPLIT,
- CURSOR_HSPLIT,
- CURSOR_HELP,
- CURSOR_MAX
- };
-
- void set_mouse_mode(MouseMode p_mode);
- MouseMode get_mouse_mode() const;
-
- static Input *get_singleton();
-
- virtual bool is_key_pressed(int p_keycode) const = 0;
- virtual bool is_mouse_button_pressed(int p_button) const = 0;
- virtual bool is_joy_button_pressed(int p_device, int p_button) const = 0;
- virtual bool is_action_pressed(const StringName &p_action) const = 0;
- virtual bool is_action_just_pressed(const StringName &p_action) const = 0;
- virtual bool is_action_just_released(const StringName &p_action) const = 0;
- virtual float get_action_strength(const StringName &p_action) const = 0;
-
- virtual float get_joy_axis(int p_device, int p_axis) const = 0;
- virtual String get_joy_name(int p_idx) = 0;
- virtual Array get_connected_joypads() = 0;
- virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) = 0;
- virtual void add_joy_mapping(String p_mapping, bool p_update_existing = false) = 0;
- virtual void remove_joy_mapping(String p_guid) = 0;
- virtual bool is_joy_known(int p_device) = 0;
- virtual String get_joy_guid(int p_device) const = 0;
- virtual Vector2 get_joy_vibration_strength(int p_device) = 0;
- virtual float get_joy_vibration_duration(int p_device) = 0;
- virtual uint64_t get_joy_vibration_timestamp(int p_device) = 0;
- virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0) = 0;
- virtual void stop_joy_vibration(int p_device) = 0;
- virtual void vibrate_handheld(int p_duration_ms = 500) = 0;
-
- virtual Point2 get_mouse_position() const = 0;
- virtual Point2 get_last_mouse_speed() const = 0;
- virtual int get_mouse_button_mask() const = 0;
-
- virtual void warp_mouse_position(const Vector2 &p_to) = 0;
- virtual Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) = 0;
-
- virtual Vector3 get_gravity() const = 0;
- virtual Vector3 get_accelerometer() const = 0;
- virtual Vector3 get_magnetometer() const = 0;
- virtual Vector3 get_gyroscope() const = 0;
-
- virtual void action_press(const StringName &p_action, float p_strength = 1.f) = 0;
- virtual void action_release(const StringName &p_action) = 0;
-
- void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
-
- virtual bool is_emulating_touch_from_mouse() const = 0;
- virtual bool is_emulating_mouse_from_touch() const = 0;
-
- virtual CursorShape get_default_cursor_shape() const = 0;
- virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
- virtual CursorShape get_current_cursor_shape() const = 0;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
-
- virtual String get_joy_button_string(int p_button) = 0;
- virtual String get_joy_axis_string(int p_axis) = 0;
- virtual int get_joy_button_index_from_string(String p_button) = 0;
- virtual int get_joy_axis_index_from_string(String p_axis) = 0;
-
- virtual void parse_input_event(const Ref<InputEvent> &p_event) = 0;
- virtual void accumulate_input_event(const Ref<InputEvent> &p_event) = 0;
- virtual void flush_accumulated_events() = 0;
- virtual void set_use_accumulated_input(bool p_enable) = 0;
-
- Input();
-};
-
-VARIANT_ENUM_CAST(Input::MouseMode);
-VARIANT_ENUM_CAST(Input::CursorShape);
-
-#endif // INPUT_H
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
deleted file mode 100644
index 204a36bf56..0000000000
--- a/core/os/input_event.cpp
+++ /dev/null
@@ -1,1374 +0,0 @@
-/*************************************************************************/
-/* input_event.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_event.h"
-
-#include "core/input_map.h"
-#include "core/os/keyboard.h"
-
-const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1;
-const int InputEvent::DEVICE_ID_INTERNAL = -2;
-
-void InputEvent::set_device(int p_device) {
- device = p_device;
-}
-
-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_pressed(const StringName &p_action, bool p_allow_echo) const {
-
- bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
- return valid && pressed && (p_allow_echo || !is_echo());
-}
-
-bool InputEvent::is_action_released(const StringName &p_action) const {
-
- bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
- return valid && !pressed;
-}
-
-float InputEvent::get_action_strength(const StringName &p_action) const {
-
- bool pressed;
- float strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed, &strength);
- return valid ? strength : 0.0f;
-}
-
-bool InputEvent::is_pressed() const {
-
- return false;
-}
-
-bool InputEvent::is_echo() const {
-
- return false;
-}
-
-Ref<InputEvent> InputEvent::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- return Ref<InputEvent>((InputEvent *)this);
-}
-
-String InputEvent::as_text() const {
-
- return String();
-}
-
-bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
-
- return false;
-}
-
-bool InputEvent::shortcut_match(const Ref<InputEvent> &p_event) const {
-
- return false;
-}
-
-bool InputEvent::is_action_type() const {
-
- return false;
-}
-
-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_pressed"), &InputEvent::is_pressed);
- ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo);
-
- ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text);
-
- ClassDB::bind_method(D_METHOD("shortcut_match", "event"), &InputEvent::shortcut_match);
-
- ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type);
-
- ClassDB::bind_method(D_METHOD("accumulate", "with_event"), &InputEvent::accumulate);
-
- ClassDB::bind_method(D_METHOD("xformed_by", "xform", "local_ofs"), &InputEvent::xformed_by, DEFVAL(Vector2()));
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device");
-}
-
-InputEvent::InputEvent() {
-
- device = 0;
-}
-
-//////////////////
-
-void InputEventWithModifiers::set_shift(bool p_enabled) {
-
- shift = p_enabled;
-}
-
-bool InputEventWithModifiers::get_shift() const {
-
- return shift;
-}
-
-void InputEventWithModifiers::set_alt(bool p_enabled) {
-
- alt = p_enabled;
-}
-bool InputEventWithModifiers::get_alt() const {
-
- return alt;
-}
-
-void InputEventWithModifiers::set_control(bool p_enabled) {
-
- control = p_enabled;
-}
-bool InputEventWithModifiers::get_control() const {
-
- return control;
-}
-
-void InputEventWithModifiers::set_metakey(bool p_enabled) {
-
- meta = p_enabled;
-}
-bool InputEventWithModifiers::get_metakey() const {
-
- return meta;
-}
-
-void InputEventWithModifiers::set_command(bool p_enabled) {
-
- command = p_enabled;
-}
-bool InputEventWithModifiers::get_command() const {
-
- return command;
-}
-
-void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModifiers *event) {
-
- set_alt(event->get_alt());
- set_shift(event->get_shift());
- set_control(event->get_control());
- set_metakey(event->get_metakey());
-}
-
-void InputEventWithModifiers::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt);
- ClassDB::bind_method(D_METHOD("get_alt"), &InputEventWithModifiers::get_alt);
-
- ClassDB::bind_method(D_METHOD("set_shift", "enable"), &InputEventWithModifiers::set_shift);
- ClassDB::bind_method(D_METHOD("get_shift"), &InputEventWithModifiers::get_shift);
-
- ClassDB::bind_method(D_METHOD("set_control", "enable"), &InputEventWithModifiers::set_control);
- ClassDB::bind_method(D_METHOD("get_control"), &InputEventWithModifiers::get_control);
-
- ClassDB::bind_method(D_METHOD("set_metakey", "enable"), &InputEventWithModifiers::set_metakey);
- ClassDB::bind_method(D_METHOD("get_metakey"), &InputEventWithModifiers::get_metakey);
-
- ClassDB::bind_method(D_METHOD("set_command", "enable"), &InputEventWithModifiers::set_command);
- ClassDB::bind_method(D_METHOD("get_command"), &InputEventWithModifiers::get_command);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt"), "set_alt", "get_alt");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift"), "set_shift", "get_shift");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "control"), "set_control", "get_control");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta"), "set_metakey", "get_metakey");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command"), "set_command", "get_command");
-}
-
-InputEventWithModifiers::InputEventWithModifiers() {
-
- alt = false;
- shift = false;
- control = false;
- meta = false;
-}
-
-//////////////////////////////////
-
-void InputEventKey::set_pressed(bool p_pressed) {
-
- pressed = p_pressed;
-}
-
-bool InputEventKey::is_pressed() const {
-
- return pressed;
-}
-
-void InputEventKey::set_keycode(uint32_t p_keycode) {
-
- keycode = p_keycode;
-}
-
-uint32_t InputEventKey::get_keycode() const {
-
- return keycode;
-}
-
-void InputEventKey::set_physical_keycode(uint32_t p_keycode) {
-
- physical_keycode = p_keycode;
-}
-
-uint32_t InputEventKey::get_physical_keycode() const {
-
- return physical_keycode;
-}
-
-void InputEventKey::set_unicode(uint32_t p_unicode) {
-
- unicode = p_unicode;
-}
-
-uint32_t InputEventKey::get_unicode() const {
-
- return unicode;
-}
-
-void InputEventKey::set_echo(bool p_enable) {
-
- echo = p_enable;
-}
-
-bool InputEventKey::is_echo() const {
-
- return echo;
-}
-
-uint32_t InputEventKey::get_keycode_with_modifiers() const {
-
- uint32_t sc = keycode;
- if (get_control())
- sc |= KEY_MASK_CTRL;
- if (get_alt())
- sc |= KEY_MASK_ALT;
- if (get_shift())
- sc |= KEY_MASK_SHIFT;
- if (get_metakey())
- sc |= KEY_MASK_META;
-
- return sc;
-}
-
-uint32_t InputEventKey::get_physical_keycode_with_modifiers() const {
-
- uint32_t sc = physical_keycode;
- if (get_control())
- sc |= KEY_MASK_CTRL;
- if (get_alt())
- sc |= KEY_MASK_ALT;
- if (get_shift())
- sc |= KEY_MASK_SHIFT;
- if (get_metakey())
- sc |= KEY_MASK_META;
-
- return sc;
-}
-
-String InputEventKey::as_text() const {
-
- String kc = keycode_get_string(keycode);
- if (kc == String())
- return kc;
-
- if (get_metakey()) {
- kc = find_keycode_name(KEY_META) + ("+" + kc);
- }
- if (get_alt()) {
- kc = find_keycode_name(KEY_ALT) + ("+" + kc);
- }
- if (get_shift()) {
- kc = find_keycode_name(KEY_SHIFT) + ("+" + kc);
- }
- if (get_control()) {
- kc = find_keycode_name(KEY_CONTROL) + ("+" + kc);
- }
- return kc;
-}
-
-bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
-
- Ref<InputEventKey> key = p_event;
- if (key.is_null())
- return false;
-
- bool match = false;
- if (get_keycode() == 0) {
- uint32_t code = get_physical_keycode_with_modifiers();
- uint32_t event_code = key->get_physical_keycode_with_modifiers();
-
- match = get_physical_keycode() == key->get_physical_keycode() && (!key->is_pressed() || (code & event_code) == code);
- } else {
- uint32_t code = get_keycode_with_modifiers();
- uint32_t event_code = key->get_keycode_with_modifiers();
-
- match = get_keycode() == key->get_keycode() && (!key->is_pressed() || (code & event_code) == code);
- }
- if (match) {
- if (p_pressed != NULL)
- *p_pressed = key->is_pressed();
- if (p_strength != NULL)
- *p_strength = (p_pressed != NULL && *p_pressed) ? 1.0f : 0.0f;
- }
- return match;
-}
-
-bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const {
-
- Ref<InputEventKey> key = p_event;
- if (key.is_null())
- return false;
-
- uint32_t code = get_keycode_with_modifiers();
- uint32_t event_code = key->get_keycode_with_modifiers();
-
- return code == event_code;
-}
-
-void InputEventKey::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventKey::set_pressed);
-
- ClassDB::bind_method(D_METHOD("set_keycode", "keycode"), &InputEventKey::set_keycode);
- ClassDB::bind_method(D_METHOD("get_keycode"), &InputEventKey::get_keycode);
-
- ClassDB::bind_method(D_METHOD("set_physical_keycode", "physical_keycode"), &InputEventKey::set_physical_keycode);
- ClassDB::bind_method(D_METHOD("get_physical_keycode"), &InputEventKey::get_physical_keycode);
-
- ClassDB::bind_method(D_METHOD("set_unicode", "unicode"), &InputEventKey::set_unicode);
- ClassDB::bind_method(D_METHOD("get_unicode"), &InputEventKey::get_unicode);
-
- ClassDB::bind_method(D_METHOD("set_echo", "echo"), &InputEventKey::set_echo);
-
- ClassDB::bind_method(D_METHOD("get_keycode_with_modifiers"), &InputEventKey::get_keycode_with_modifiers);
- ClassDB::bind_method(D_METHOD("get_physical_keycode_with_modifiers"), &InputEventKey::get_physical_keycode_with_modifiers);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "keycode"), "set_keycode", "get_keycode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_keycode"), "set_physical_keycode", "get_physical_keycode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "unicode"), "set_unicode", "get_unicode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "echo"), "set_echo", "is_echo");
-}
-
-InputEventKey::InputEventKey() {
-
- pressed = false;
- keycode = 0;
- physical_keycode = 0;
- unicode = 0; ///unicode
- echo = false;
-}
-
-////////////////////////////////////////
-
-void InputEventMouse::set_button_mask(int p_mask) {
-
- button_mask = p_mask;
-}
-int InputEventMouse::get_button_mask() const {
-
- return button_mask;
-}
-
-void InputEventMouse::set_position(const Vector2 &p_pos) {
-
- pos = p_pos;
-}
-Vector2 InputEventMouse::get_position() const {
-
- return pos;
-}
-
-void InputEventMouse::set_global_position(const Vector2 &p_global_pos) {
-
- global_pos = p_global_pos;
-}
-Vector2 InputEventMouse::get_global_position() const {
-
- return global_pos;
-}
-
-void InputEventMouse::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_button_mask", "button_mask"), &InputEventMouse::set_button_mask);
- ClassDB::bind_method(D_METHOD("get_button_mask"), &InputEventMouse::get_button_mask);
-
- ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventMouse::set_position);
- ClassDB::bind_method(D_METHOD("get_position"), &InputEventMouse::get_position);
-
- ClassDB::bind_method(D_METHOD("set_global_position", "global_position"), &InputEventMouse::set_global_position);
- ClassDB::bind_method(D_METHOD("get_global_position"), &InputEventMouse::get_global_position);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask"), "set_button_mask", "get_button_mask");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position"), "set_global_position", "get_global_position");
-}
-
-InputEventMouse::InputEventMouse() {
-
- button_mask = 0;
-}
-
-///////////////////////////////////////
-
-void InputEventMouseButton::set_factor(float p_factor) {
-
- factor = p_factor;
-}
-
-float InputEventMouseButton::get_factor() {
-
- return factor;
-}
-
-void InputEventMouseButton::set_button_index(int p_index) {
-
- button_index = p_index;
-}
-int InputEventMouseButton::get_button_index() const {
-
- return button_index;
-}
-
-void InputEventMouseButton::set_pressed(bool p_pressed) {
-
- pressed = p_pressed;
-}
-bool InputEventMouseButton::is_pressed() const {
-
- return pressed;
-}
-
-void InputEventMouseButton::set_doubleclick(bool p_doubleclick) {
-
- doubleclick = p_doubleclick;
-}
-bool InputEventMouseButton::is_doubleclick() const {
-
- return doubleclick;
-}
-
-Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- Vector2 g = get_global_position();
- Vector2 l = p_xform.xform(get_position() + p_local_ofs);
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- mb->set_device(get_device());
-
- mb->set_modifiers_from_event(this);
-
- mb->set_position(l);
- mb->set_global_position(g);
-
- mb->set_button_mask(get_button_mask());
- mb->set_pressed(pressed);
- mb->set_doubleclick(doubleclick);
- mb->set_factor(factor);
- mb->set_button_index(button_index);
-
- return mb;
-}
-
-bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
-
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_null())
- return false;
-
- bool match = mb->button_index == button_index;
- if (match) {
- if (p_pressed != NULL)
- *p_pressed = mb->is_pressed();
- if (p_strength != NULL)
- *p_strength = (p_pressed != NULL && *p_pressed) ? 1.0f : 0.0f;
- }
-
- return match;
-}
-
-String InputEventMouseButton::as_text() const {
-
- String button_index_string = "";
- switch (get_button_index()) {
- case BUTTON_LEFT:
- button_index_string = "BUTTON_LEFT";
- break;
- case BUTTON_RIGHT:
- button_index_string = "BUTTON_RIGHT";
- break;
- case BUTTON_MIDDLE:
- button_index_string = "BUTTON_MIDDLE";
- break;
- case BUTTON_WHEEL_UP:
- button_index_string = "BUTTON_WHEEL_UP";
- break;
- case BUTTON_WHEEL_DOWN:
- button_index_string = "BUTTON_WHEEL_DOWN";
- break;
- case BUTTON_WHEEL_LEFT:
- button_index_string = "BUTTON_WHEEL_LEFT";
- break;
- case BUTTON_WHEEL_RIGHT:
- button_index_string = "BUTTON_WHEEL_RIGHT";
- break;
- case BUTTON_XBUTTON1:
- button_index_string = "BUTTON_XBUTTON1";
- break;
- case BUTTON_XBUTTON2:
- button_index_string = "BUTTON_XBUTTON2";
- break;
- default:
- button_index_string = itos(get_button_index());
- break;
- }
- return "InputEventMouseButton : button_index=" + button_index_string + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + "), button_mask=" + itos(get_button_mask()) + ", doubleclick=" + (doubleclick ? "true" : "false");
-}
-
-void InputEventMouseButton::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_factor", "factor"), &InputEventMouseButton::set_factor);
- ClassDB::bind_method(D_METHOD("get_factor"), &InputEventMouseButton::get_factor);
-
- ClassDB::bind_method(D_METHOD("set_button_index", "button_index"), &InputEventMouseButton::set_button_index);
- ClassDB::bind_method(D_METHOD("get_button_index"), &InputEventMouseButton::get_button_index);
-
- ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventMouseButton::set_pressed);
- // ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventMouseButton::is_pressed);
-
- ClassDB::bind_method(D_METHOD("set_doubleclick", "doubleclick"), &InputEventMouseButton::set_doubleclick);
- ClassDB::bind_method(D_METHOD("is_doubleclick"), &InputEventMouseButton::is_doubleclick);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "factor"), "set_factor", "get_factor");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "doubleclick"), "set_doubleclick", "is_doubleclick");
-}
-
-InputEventMouseButton::InputEventMouseButton() {
-
- factor = 1;
- button_index = 0;
- pressed = false;
- doubleclick = false;
-}
-
-////////////////////////////////////////////
-
-void InputEventMouseMotion::set_tilt(const Vector2 &p_tilt) {
-
- tilt = p_tilt;
-}
-
-Vector2 InputEventMouseMotion::get_tilt() const {
-
- return tilt;
-}
-
-void InputEventMouseMotion::set_pressure(float p_pressure) {
-
- pressure = p_pressure;
-}
-
-float InputEventMouseMotion::get_pressure() const {
-
- return pressure;
-}
-
-void InputEventMouseMotion::set_relative(const Vector2 &p_relative) {
-
- relative = p_relative;
-}
-
-Vector2 InputEventMouseMotion::get_relative() const {
-
- return relative;
-}
-
-void InputEventMouseMotion::set_speed(const Vector2 &p_speed) {
-
- speed = p_speed;
-}
-
-Vector2 InputEventMouseMotion::get_speed() const {
-
- return speed;
-}
-
-Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- Vector2 g = get_global_position();
- Vector2 l = p_xform.xform(get_position() + p_local_ofs);
- Vector2 r = p_xform.basis_xform(get_relative());
- Vector2 s = p_xform.basis_xform(get_speed());
-
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- mm->set_device(get_device());
-
- mm->set_modifiers_from_event(this);
-
- mm->set_position(l);
- mm->set_pressure(get_pressure());
- mm->set_tilt(get_tilt());
- mm->set_global_position(g);
-
- mm->set_button_mask(get_button_mask());
- mm->set_relative(r);
- mm->set_speed(s);
-
- return mm;
-}
-
-String InputEventMouseMotion::as_text() const {
-
- String button_mask_string = "";
- switch (get_button_mask()) {
- case BUTTON_MASK_LEFT:
- button_mask_string = "BUTTON_MASK_LEFT";
- break;
- case BUTTON_MASK_MIDDLE:
- button_mask_string = "BUTTON_MASK_MIDDLE";
- break;
- case BUTTON_MASK_RIGHT:
- button_mask_string = "BUTTON_MASK_RIGHT";
- break;
- case BUTTON_MASK_XBUTTON1:
- button_mask_string = "BUTTON_MASK_XBUTTON1";
- break;
- case BUTTON_MASK_XBUTTON2:
- button_mask_string = "BUTTON_MASK_XBUTTON2";
- break;
- default:
- button_mask_string = itos(get_button_mask());
- break;
- }
- return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")";
-}
-
-bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
-
- Ref<InputEventMouseMotion> motion = p_event;
- if (motion.is_null())
- return false;
-
- if (is_pressed() != motion->is_pressed()) {
- return false;
- }
-
- if (get_button_mask() != motion->get_button_mask()) {
- return false;
- }
-
- if (get_shift() != motion->get_shift()) {
- return false;
- }
-
- if (get_control() != motion->get_control()) {
- return false;
- }
-
- if (get_alt() != motion->get_alt()) {
- return false;
- }
-
- if (get_metakey() != motion->get_metakey()) {
- return false;
- }
-
- set_position(motion->get_position());
- set_global_position(motion->get_global_position());
- set_speed(motion->get_speed());
- relative += motion->get_relative();
-
- return true;
-}
-
-void InputEventMouseMotion::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_tilt", "tilt"), &InputEventMouseMotion::set_tilt);
- ClassDB::bind_method(D_METHOD("get_tilt"), &InputEventMouseMotion::get_tilt);
-
- ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMouseMotion::set_pressure);
- ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMouseMotion::get_pressure);
-
- ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventMouseMotion::set_relative);
- ClassDB::bind_method(D_METHOD("get_relative"), &InputEventMouseMotion::get_relative);
-
- ClassDB::bind_method(D_METHOD("set_speed", "speed"), &InputEventMouseMotion::set_speed);
- ClassDB::bind_method(D_METHOD("get_speed"), &InputEventMouseMotion::get_speed);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "speed"), "set_speed", "get_speed");
-}
-
-InputEventMouseMotion::InputEventMouseMotion() {
-
- pressure = 0;
-}
-
-////////////////////////////////////////
-
-void InputEventJoypadMotion::set_axis(int p_axis) {
-
- axis = p_axis;
-}
-
-int InputEventJoypadMotion::get_axis() const {
-
- return axis;
-}
-
-void InputEventJoypadMotion::set_axis_value(float p_value) {
-
- axis_value = p_value;
-}
-
-float InputEventJoypadMotion::get_axis_value() const {
-
- return axis_value;
-}
-
-bool InputEventJoypadMotion::is_pressed() const {
-
- return Math::abs(axis_value) >= 0.5f;
-}
-
-bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
-
- Ref<InputEventJoypadMotion> jm = p_event;
- if (jm.is_null())
- return false;
-
- bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event.
- if (match) {
- bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0);
- bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
- if (p_pressed != NULL)
- *p_pressed = pressed;
- if (p_strength != NULL) {
- if (pressed) {
- if (p_deadzone == 1.0f) {
- *p_strength = 1.0f;
- } else {
- *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
- }
- } else {
- *p_strength = 0.0f;
- }
- }
- }
- return match;
-}
-
-String InputEventJoypadMotion::as_text() const {
-
- return "InputEventJoypadMotion : axis=" + itos(axis) + ", axis_value=" + String(Variant(axis_value));
-}
-
-void InputEventJoypadMotion::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_axis", "axis"), &InputEventJoypadMotion::set_axis);
- ClassDB::bind_method(D_METHOD("get_axis"), &InputEventJoypadMotion::get_axis);
-
- ClassDB::bind_method(D_METHOD("set_axis_value", "axis_value"), &InputEventJoypadMotion::set_axis_value);
- ClassDB::bind_method(D_METHOD("get_axis_value"), &InputEventJoypadMotion::get_axis_value);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "axis"), "set_axis", "get_axis");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "axis_value"), "set_axis_value", "get_axis_value");
-}
-
-InputEventJoypadMotion::InputEventJoypadMotion() {
-
- axis = 0;
- axis_value = 0;
-}
-/////////////////////////////////
-
-void InputEventJoypadButton::set_button_index(int p_index) {
-
- button_index = p_index;
-}
-
-int InputEventJoypadButton::get_button_index() const {
-
- return button_index;
-}
-
-void InputEventJoypadButton::set_pressed(bool p_pressed) {
-
- pressed = p_pressed;
-}
-bool InputEventJoypadButton::is_pressed() const {
-
- return pressed;
-}
-
-void InputEventJoypadButton::set_pressure(float p_pressure) {
-
- pressure = p_pressure;
-}
-float InputEventJoypadButton::get_pressure() const {
-
- return pressure;
-}
-
-bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
-
- Ref<InputEventJoypadButton> jb = p_event;
- if (jb.is_null())
- return false;
-
- bool match = button_index == jb->button_index;
- if (match) {
- if (p_pressed != NULL)
- *p_pressed = jb->is_pressed();
- if (p_strength != NULL)
- *p_strength = (p_pressed != NULL && *p_pressed) ? 1.0f : 0.0f;
- }
-
- return match;
-}
-
-bool InputEventJoypadButton::shortcut_match(const Ref<InputEvent> &p_event) const {
-
- Ref<InputEventJoypadButton> button = p_event;
- if (button.is_null())
- return false;
-
- return button_index == button->button_index;
-}
-
-String InputEventJoypadButton::as_text() const {
-
- return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure));
-}
-
-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);
-
- ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventJoypadButton::set_pressure);
- ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventJoypadButton::get_pressure);
-
- ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventJoypadButton::set_pressed);
- // ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventJoypadButton::is_pressed);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure"), "set_pressure", "get_pressure");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
-}
-
-InputEventJoypadButton::InputEventJoypadButton() {
-
- button_index = 0;
- pressure = 0;
- pressed = false;
-}
-
-//////////////////////////////////////////////
-
-void InputEventScreenTouch::set_index(int p_index) {
-
- index = p_index;
-}
-int InputEventScreenTouch::get_index() const {
-
- return index;
-}
-
-void InputEventScreenTouch::set_position(const Vector2 &p_pos) {
-
- pos = p_pos;
-}
-Vector2 InputEventScreenTouch::get_position() const {
-
- return pos;
-}
-
-void InputEventScreenTouch::set_pressed(bool p_pressed) {
-
- pressed = p_pressed;
-}
-bool InputEventScreenTouch::is_pressed() const {
-
- return pressed;
-}
-
-Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- Ref<InputEventScreenTouch> st;
- st.instance();
- st->set_device(get_device());
- st->set_index(index);
- st->set_position(p_xform.xform(pos + p_local_ofs));
- st->set_pressed(pressed);
-
- return st;
-}
-
-String InputEventScreenTouch::as_text() const {
-
- return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + ")";
-}
-
-void InputEventScreenTouch::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenTouch::set_index);
- ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenTouch::get_index);
-
- ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenTouch::set_position);
- ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenTouch::get_position);
-
- ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed);
- //ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
-}
-
-InputEventScreenTouch::InputEventScreenTouch() {
-
- index = 0;
- pressed = false;
-}
-
-/////////////////////////////
-
-void InputEventScreenDrag::set_index(int p_index) {
-
- index = p_index;
-}
-
-int InputEventScreenDrag::get_index() const {
-
- return index;
-}
-
-void InputEventScreenDrag::set_position(const Vector2 &p_pos) {
-
- pos = p_pos;
-}
-Vector2 InputEventScreenDrag::get_position() const {
-
- return pos;
-}
-
-void InputEventScreenDrag::set_relative(const Vector2 &p_relative) {
-
- relative = p_relative;
-}
-Vector2 InputEventScreenDrag::get_relative() const {
-
- return relative;
-}
-
-void InputEventScreenDrag::set_speed(const Vector2 &p_speed) {
-
- speed = p_speed;
-}
-Vector2 InputEventScreenDrag::get_speed() const {
-
- return speed;
-}
-
-Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- Ref<InputEventScreenDrag> sd;
-
- sd.instance();
-
- sd->set_device(get_device());
-
- sd->set_index(index);
- sd->set_position(p_xform.xform(pos + p_local_ofs));
- sd->set_relative(p_xform.basis_xform(relative));
- sd->set_speed(p_xform.basis_xform(speed));
-
- return sd;
-}
-
-String InputEventScreenDrag::as_text() const {
-
- return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")";
-}
-
-void InputEventScreenDrag::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_index", "index"), &InputEventScreenDrag::set_index);
- ClassDB::bind_method(D_METHOD("get_index"), &InputEventScreenDrag::get_index);
-
- ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventScreenDrag::set_position);
- ClassDB::bind_method(D_METHOD("get_position"), &InputEventScreenDrag::get_position);
-
- ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventScreenDrag::set_relative);
- ClassDB::bind_method(D_METHOD("get_relative"), &InputEventScreenDrag::get_relative);
-
- ClassDB::bind_method(D_METHOD("set_speed", "speed"), &InputEventScreenDrag::set_speed);
- ClassDB::bind_method(D_METHOD("get_speed"), &InputEventScreenDrag::get_speed);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "speed"), "set_speed", "get_speed");
-}
-
-InputEventScreenDrag::InputEventScreenDrag() {
-
- index = 0;
-}
-/////////////////////////////
-
-void InputEventAction::set_action(const StringName &p_action) {
-
- action = p_action;
-}
-StringName InputEventAction::get_action() const {
-
- return action;
-}
-
-void InputEventAction::set_pressed(bool p_pressed) {
-
- pressed = p_pressed;
-}
-bool InputEventAction::is_pressed() const {
-
- return pressed;
-}
-
-void InputEventAction::set_strength(float p_strength) {
- strength = CLAMP(p_strength, 0.0f, 1.0f);
-}
-
-float InputEventAction::get_strength() const {
- return strength;
-}
-
-bool InputEventAction::shortcut_match(const Ref<InputEvent> &p_event) const {
- if (p_event.is_null())
- return false;
-
- return p_event->is_action(action);
-}
-
-bool InputEventAction::is_action(const StringName &p_action) const {
-
- return action == p_action;
-}
-
-bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
-
- Ref<InputEventAction> act = p_event;
- if (act.is_null())
- return false;
-
- bool match = action == act->action;
- if (match) {
- if (p_pressed != NULL)
- *p_pressed = act->pressed;
- if (p_strength != NULL)
- *p_strength = (p_pressed != NULL && *p_pressed) ? 1.0f : 0.0f;
- }
- return match;
-}
-
-String InputEventAction::as_text() const {
-
- return "InputEventAction : action=" + action + ", pressed=(" + (pressed ? "true" : "false");
-}
-
-void InputEventAction::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_action", "action"), &InputEventAction::set_action);
- ClassDB::bind_method(D_METHOD("get_action"), &InputEventAction::get_action);
-
- ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventAction::set_pressed);
- //ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventAction::is_pressed);
-
- ClassDB::bind_method(D_METHOD("set_strength", "strength"), &InputEventAction::set_strength);
- ClassDB::bind_method(D_METHOD("get_strength"), &InputEventAction::get_strength);
-
- // ClassDB::bind_method(D_METHOD("is_action", "name"), &InputEventAction::is_action);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "action"), "set_action", "get_action");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_strength", "get_strength");
-}
-
-InputEventAction::InputEventAction() {
- pressed = false;
- strength = 1.0f;
-}
-/////////////////////////////
-
-void InputEventGesture::set_position(const Vector2 &p_pos) {
-
- pos = p_pos;
-}
-
-void InputEventGesture::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_position", "position"), &InputEventGesture::set_position);
- ClassDB::bind_method(D_METHOD("get_position"), &InputEventGesture::get_position);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
-}
-
-Vector2 InputEventGesture::get_position() const {
-
- return pos;
-}
-/////////////////////////////
-
-void InputEventMagnifyGesture::set_factor(real_t p_factor) {
-
- factor = p_factor;
-}
-
-real_t InputEventMagnifyGesture::get_factor() const {
-
- return factor;
-}
-
-Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- Ref<InputEventMagnifyGesture> ev;
- ev.instance();
-
- ev->set_device(get_device());
- ev->set_modifiers_from_event(this);
-
- ev->set_position(p_xform.xform(get_position() + p_local_ofs));
- ev->set_factor(get_factor());
-
- return ev;
-}
-
-String InputEventMagnifyGesture::as_text() const {
-
- return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")";
-}
-
-void InputEventMagnifyGesture::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_factor", "factor"), &InputEventMagnifyGesture::set_factor);
- ClassDB::bind_method(D_METHOD("get_factor"), &InputEventMagnifyGesture::get_factor);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "factor"), "set_factor", "get_factor");
-}
-
-InputEventMagnifyGesture::InputEventMagnifyGesture() {
-
- factor = 1.0;
-}
-/////////////////////////////
-
-void InputEventPanGesture::set_delta(const Vector2 &p_delta) {
-
- delta = p_delta;
-}
-
-Vector2 InputEventPanGesture::get_delta() const {
- return delta;
-}
-
-Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
-
- Ref<InputEventPanGesture> ev;
- ev.instance();
-
- ev->set_device(get_device());
- ev->set_modifiers_from_event(this);
-
- ev->set_position(p_xform.xform(get_position() + p_local_ofs));
- ev->set_delta(get_delta());
-
- return ev;
-}
-
-String InputEventPanGesture::as_text() const {
-
- return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")";
-}
-
-void InputEventPanGesture::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_delta", "delta"), &InputEventPanGesture::set_delta);
- ClassDB::bind_method(D_METHOD("get_delta"), &InputEventPanGesture::get_delta);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "delta"), "set_delta", "get_delta");
-}
-
-InputEventPanGesture::InputEventPanGesture() {
-
- delta = Vector2(0, 0);
-}
-/////////////////////////////
-
-void InputEventMIDI::set_channel(const int p_channel) {
-
- channel = p_channel;
-}
-
-int InputEventMIDI::get_channel() const {
- return channel;
-}
-
-void InputEventMIDI::set_message(const int p_message) {
-
- message = p_message;
-}
-
-int InputEventMIDI::get_message() const {
- return message;
-}
-
-void InputEventMIDI::set_pitch(const int p_pitch) {
-
- pitch = p_pitch;
-}
-
-int InputEventMIDI::get_pitch() const {
- return pitch;
-}
-
-void InputEventMIDI::set_velocity(const int p_velocity) {
-
- velocity = p_velocity;
-}
-
-int InputEventMIDI::get_velocity() const {
- return velocity;
-}
-
-void InputEventMIDI::set_instrument(const int p_instrument) {
-
- instrument = p_instrument;
-}
-
-int InputEventMIDI::get_instrument() const {
- return instrument;
-}
-
-void InputEventMIDI::set_pressure(const int p_pressure) {
-
- pressure = p_pressure;
-}
-
-int InputEventMIDI::get_pressure() const {
- return pressure;
-}
-
-void InputEventMIDI::set_controller_number(const int p_controller_number) {
-
- controller_number = p_controller_number;
-}
-
-int InputEventMIDI::get_controller_number() const {
- return controller_number;
-}
-
-void InputEventMIDI::set_controller_value(const int p_controller_value) {
-
- controller_value = p_controller_value;
-}
-
-int InputEventMIDI::get_controller_value() const {
- return controller_value;
-}
-
-String InputEventMIDI::as_text() const {
-
- return "InputEventMIDI : channel=(" + itos(get_channel()) + "), message=(" + itos(get_message()) + ")";
-}
-
-void InputEventMIDI::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_channel", "channel"), &InputEventMIDI::set_channel);
- ClassDB::bind_method(D_METHOD("get_channel"), &InputEventMIDI::get_channel);
- ClassDB::bind_method(D_METHOD("set_message", "message"), &InputEventMIDI::set_message);
- ClassDB::bind_method(D_METHOD("get_message"), &InputEventMIDI::get_message);
- ClassDB::bind_method(D_METHOD("set_pitch", "pitch"), &InputEventMIDI::set_pitch);
- ClassDB::bind_method(D_METHOD("get_pitch"), &InputEventMIDI::get_pitch);
- ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &InputEventMIDI::set_velocity);
- ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventMIDI::get_velocity);
- ClassDB::bind_method(D_METHOD("set_instrument", "instrument"), &InputEventMIDI::set_instrument);
- ClassDB::bind_method(D_METHOD("get_instrument"), &InputEventMIDI::get_instrument);
- ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMIDI::set_pressure);
- ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMIDI::get_pressure);
- ClassDB::bind_method(D_METHOD("set_controller_number", "controller_number"), &InputEventMIDI::set_controller_number);
- ClassDB::bind_method(D_METHOD("get_controller_number"), &InputEventMIDI::get_controller_number);
- ClassDB::bind_method(D_METHOD("set_controller_value", "controller_value"), &InputEventMIDI::set_controller_value);
- ClassDB::bind_method(D_METHOD("get_controller_value"), &InputEventMIDI::get_controller_value);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "channel"), "set_channel", "get_channel");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "message"), "set_message", "get_message");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "pitch"), "set_pitch", "get_pitch");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "velocity"), "set_velocity", "get_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "instrument"), "set_instrument", "get_instrument");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "pressure"), "set_pressure", "get_pressure");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_number"), "set_controller_number", "get_controller_number");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_value"), "set_controller_value", "get_controller_value");
-}
-
-InputEventMIDI::InputEventMIDI() {
-
- channel = 0;
- message = 0;
- pitch = 0;
- velocity = 0;
- instrument = 0;
- pressure = 0;
- controller_number = 0;
- controller_value = 0;
-}
diff --git a/core/os/input_event.h b/core/os/input_event.h
deleted file mode 100644
index c105fcd1c1..0000000000
--- a/core/os/input_event.h
+++ /dev/null
@@ -1,625 +0,0 @@
-/*************************************************************************/
-/* input_event.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 INPUT_EVENT_H
-#define INPUT_EVENT_H
-
-#include "core/math/transform_2d.h"
-#include "core/os/copymem.h"
-#include "core/resource.h"
-#include "core/typedefs.h"
-#include "core/ustring.h"
-
-/**
- * Input Event classes. These are used in the main loop.
- * 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 JoystickList {
-
- JOY_BUTTON_0 = 0,
- JOY_BUTTON_1 = 1,
- JOY_BUTTON_2 = 2,
- JOY_BUTTON_3 = 3,
- JOY_BUTTON_4 = 4,
- JOY_BUTTON_5 = 5,
- JOY_BUTTON_6 = 6,
- JOY_BUTTON_7 = 7,
- JOY_BUTTON_8 = 8,
- JOY_BUTTON_9 = 9,
- JOY_BUTTON_10 = 10,
- JOY_BUTTON_11 = 11,
- JOY_BUTTON_12 = 12,
- JOY_BUTTON_13 = 13,
- JOY_BUTTON_14 = 14,
- JOY_BUTTON_15 = 15,
- JOY_BUTTON_MAX = 16,
-
- JOY_L = JOY_BUTTON_4,
- JOY_R = JOY_BUTTON_5,
- JOY_L2 = JOY_BUTTON_6,
- JOY_R2 = JOY_BUTTON_7,
- JOY_L3 = JOY_BUTTON_8,
- JOY_R3 = JOY_BUTTON_9,
- JOY_SELECT = JOY_BUTTON_10,
- JOY_START = JOY_BUTTON_11,
- JOY_DPAD_UP = JOY_BUTTON_12,
- JOY_DPAD_DOWN = JOY_BUTTON_13,
- JOY_DPAD_LEFT = JOY_BUTTON_14,
- JOY_DPAD_RIGHT = JOY_BUTTON_15,
-
- JOY_SONY_CIRCLE = JOY_BUTTON_1,
- JOY_SONY_X = JOY_BUTTON_0,
- JOY_SONY_SQUARE = JOY_BUTTON_2,
- JOY_SONY_TRIANGLE = JOY_BUTTON_3,
-
- JOY_XBOX_A = JOY_BUTTON_0,
- JOY_XBOX_B = JOY_BUTTON_1,
- JOY_XBOX_X = JOY_BUTTON_2,
- JOY_XBOX_Y = JOY_BUTTON_3,
-
- JOY_DS_A = JOY_BUTTON_1,
- JOY_DS_B = JOY_BUTTON_0,
- JOY_DS_X = JOY_BUTTON_3,
- JOY_DS_Y = JOY_BUTTON_2,
-
- JOY_WII_C = JOY_BUTTON_5,
- JOY_WII_Z = JOY_BUTTON_6,
-
- JOY_WII_MINUS = JOY_BUTTON_10,
- JOY_WII_PLUS = JOY_BUTTON_11,
-
- JOY_VR_GRIP = JOY_BUTTON_2,
- JOY_VR_PAD = JOY_BUTTON_14,
- JOY_VR_TRIGGER = JOY_BUTTON_15,
-
- JOY_OCULUS_AX = JOY_BUTTON_7,
- JOY_OCULUS_BY = JOY_BUTTON_1,
- JOY_OCULUS_MENU = JOY_BUTTON_3,
-
- JOY_OPENVR_MENU = JOY_BUTTON_1,
-
- // end of history
-
- JOY_AXIS_0 = 0,
- JOY_AXIS_1 = 1,
- JOY_AXIS_2 = 2,
- JOY_AXIS_3 = 3,
- JOY_AXIS_4 = 4,
- JOY_AXIS_5 = 5,
- JOY_AXIS_6 = 6,
- JOY_AXIS_7 = 7,
- JOY_AXIS_8 = 8,
- JOY_AXIS_9 = 9,
- JOY_AXIS_MAX = 10,
-
- JOY_ANALOG_LX = JOY_AXIS_0,
- JOY_ANALOG_LY = JOY_AXIS_1,
-
- JOY_ANALOG_RX = JOY_AXIS_2,
- JOY_ANALOG_RY = JOY_AXIS_3,
-
- JOY_ANALOG_L2 = JOY_AXIS_6,
- JOY_ANALOG_R2 = JOY_AXIS_7,
-
- JOY_VR_ANALOG_TRIGGER = JOY_AXIS_2,
- JOY_VR_ANALOG_GRIP = JOY_AXIS_4,
-
- JOY_OPENVR_TOUCHPADX = JOY_AXIS_0,
- JOY_OPENVR_TOUCHPADY = JOY_AXIS_1,
-};
-
-enum MidiMessageList {
- MIDI_MESSAGE_NOTE_OFF = 0x8,
- MIDI_MESSAGE_NOTE_ON = 0x9,
- MIDI_MESSAGE_AFTERTOUCH = 0xA,
- MIDI_MESSAGE_CONTROL_CHANGE = 0xB,
- MIDI_MESSAGE_PROGRAM_CHANGE = 0xC,
- MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD,
- MIDI_MESSAGE_PITCH_BEND = 0xE,
-};
-
-/**
- * Input Modifier Status
- * for keyboard/mouse events.
- */
-
-class InputEvent : public Resource {
- GDCLASS(InputEvent, Resource);
-
- int device;
-
-protected:
- static void _bind_methods();
-
-public:
- static const int DEVICE_ID_TOUCH_MOUSE;
- static const int DEVICE_ID_INTERNAL;
-
- 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;
-
- // To be removed someday, since they do not make sense for all events
- virtual bool is_pressed() const;
- virtual bool is_echo() const;
- // ...-.
-
- virtual String as_text() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
-
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
- virtual bool is_action_type() const;
-
- virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; }
- InputEvent();
-};
-
-class InputEventWithModifiers : public InputEvent {
- GDCLASS(InputEventWithModifiers, InputEvent);
-
- bool shift;
- bool alt;
-#ifdef APPLE_STYLE_KEYS
- union {
- bool command;
- bool meta; //< windows/mac key
- };
-
- bool control;
-#else
- union {
- bool command; //< windows/mac key
- bool control;
- };
- bool meta; //< windows/mac key
-
-#endif
-
-protected:
- static void _bind_methods();
-
-public:
- void set_shift(bool p_enabled);
- bool get_shift() const;
-
- void set_alt(bool p_enabled);
- bool get_alt() const;
-
- void set_control(bool p_enabled);
- bool get_control() const;
-
- void set_metakey(bool p_enabled);
- bool get_metakey() const;
-
- void set_command(bool p_enabled);
- bool get_command() const;
-
- void set_modifiers_from_event(const InputEventWithModifiers *event);
-
- InputEventWithModifiers();
-};
-
-class InputEventKey : public InputEventWithModifiers {
-
- GDCLASS(InputEventKey, InputEventWithModifiers);
-
- bool pressed; /// otherwise release
-
- uint32_t keycode; ///< check keyboard.h , KeyCode enum, without modifier masks
- uint32_t physical_keycode;
- uint32_t unicode; ///unicode
-
- bool echo; /// true if this is an echo key
-
-protected:
- static void _bind_methods();
-
-public:
- void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
-
- void set_keycode(uint32_t p_keycode);
- uint32_t get_keycode() const;
-
- void set_physical_keycode(uint32_t p_keycode);
- uint32_t get_physical_keycode() const;
-
- void set_unicode(uint32_t p_unicode);
- uint32_t get_unicode() const;
-
- void set_echo(bool p_enable);
- virtual bool is_echo() const;
-
- uint32_t get_keycode_with_modifiers() const;
- uint32_t get_physical_keycode_with_modifiers() const;
-
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
-
- virtual bool is_action_type() const { return true; }
-
- virtual String as_text() const;
-
- InputEventKey();
-};
-
-class InputEventMouse : public InputEventWithModifiers {
-
- GDCLASS(InputEventMouse, InputEventWithModifiers);
-
- int button_mask;
-
- Vector2 pos;
- Vector2 global_pos;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_button_mask(int p_mask);
- int get_button_mask() const;
-
- void set_position(const Vector2 &p_pos);
- Vector2 get_position() const;
-
- void set_global_position(const Vector2 &p_global_pos);
- Vector2 get_global_position() const;
-
- InputEventMouse();
-};
-
-class InputEventMouseButton : public InputEventMouse {
-
- GDCLASS(InputEventMouseButton, InputEventMouse);
-
- float factor;
- int button_index;
- bool pressed; //otherwise released
- bool doubleclick; //last even less than doubleclick time
-
-protected:
- static void _bind_methods();
-
-public:
- void set_factor(float p_factor);
- float get_factor();
-
- void set_button_index(int p_index);
- int get_button_index() const;
-
- void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
-
- void set_doubleclick(bool p_doubleclick);
- bool is_doubleclick() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
-
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
-
- InputEventMouseButton();
-};
-
-class InputEventMouseMotion : public InputEventMouse {
-
- GDCLASS(InputEventMouseMotion, InputEventMouse);
-
- Vector2 tilt;
- float pressure;
- Vector2 relative;
- Vector2 speed;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_tilt(const Vector2 &p_tilt);
- Vector2 get_tilt() const;
-
- void set_pressure(float p_pressure);
- float get_pressure() const;
-
- void set_relative(const Vector2 &p_relative);
- Vector2 get_relative() const;
-
- void set_speed(const Vector2 &p_speed);
- Vector2 get_speed() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
-
- virtual bool accumulate(const Ref<InputEvent> &p_event);
-
- InputEventMouseMotion();
-};
-
-class InputEventJoypadMotion : public InputEvent {
-
- GDCLASS(InputEventJoypadMotion, InputEvent);
- int axis; ///< Joypad axis
- float axis_value; ///< -1 to 1
-
-protected:
- static void _bind_methods();
-
-public:
- void set_axis(int p_axis);
- int get_axis() const;
-
- void set_axis_value(float p_value);
- float get_axis_value() const;
-
- virtual bool is_pressed() const;
-
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
-
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
-
- InputEventJoypadMotion();
-};
-
-class InputEventJoypadButton : public InputEvent {
- GDCLASS(InputEventJoypadButton, InputEvent);
-
- int button_index;
- bool pressed;
- float pressure; //0 to 1
-protected:
- static void _bind_methods();
-
-public:
- void set_button_index(int p_index);
- int get_button_index() const;
-
- void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
-
- void set_pressure(float p_pressure);
- float get_pressure() const;
-
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
-
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
-
- InputEventJoypadButton();
-};
-
-class InputEventScreenTouch : public InputEvent {
- GDCLASS(InputEventScreenTouch, InputEvent);
- int index;
- Vector2 pos;
- bool pressed;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_index(int p_index);
- int get_index() const;
-
- void set_position(const Vector2 &p_pos);
- Vector2 get_position() const;
-
- void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
-
- InputEventScreenTouch();
-};
-
-class InputEventScreenDrag : public InputEvent {
-
- GDCLASS(InputEventScreenDrag, InputEvent);
- int index;
- Vector2 pos;
- Vector2 relative;
- Vector2 speed;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_index(int p_index);
- int get_index() const;
-
- void set_position(const Vector2 &p_pos);
- Vector2 get_position() const;
-
- void set_relative(const Vector2 &p_relative);
- Vector2 get_relative() const;
-
- void set_speed(const Vector2 &p_speed);
- Vector2 get_speed() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
-
- InputEventScreenDrag();
-};
-
-class InputEventAction : public InputEvent {
-
- GDCLASS(InputEventAction, InputEvent);
-
- StringName action;
- bool pressed;
- float strength;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_action(const StringName &p_action);
- StringName get_action() const;
-
- void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
-
- void set_strength(float p_strength);
- float get_strength() const;
-
- virtual bool is_action(const StringName &p_action) const;
-
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
-
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
-
- InputEventAction();
-};
-
-class InputEventGesture : public InputEventWithModifiers {
-
- GDCLASS(InputEventGesture, InputEventWithModifiers);
-
- Vector2 pos;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_position(const Vector2 &p_pos);
- Vector2 get_position() const;
-};
-
-class InputEventMagnifyGesture : public InputEventGesture {
-
- GDCLASS(InputEventMagnifyGesture, InputEventGesture);
- real_t factor;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_factor(real_t p_factor);
- real_t get_factor() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
-
- InputEventMagnifyGesture();
-};
-
-class InputEventPanGesture : public InputEventGesture {
-
- GDCLASS(InputEventPanGesture, InputEventGesture);
- Vector2 delta;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_delta(const Vector2 &p_delta);
- Vector2 get_delta() const;
-
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
-
- InputEventPanGesture();
-};
-
-class InputEventMIDI : public InputEvent {
- GDCLASS(InputEventMIDI, InputEvent);
-
- int channel;
- int message;
- int pitch;
- int velocity;
- int instrument;
- int pressure;
- int controller_number;
- int controller_value;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_channel(const int p_channel);
- int get_channel() const;
-
- void set_message(const int p_message);
- int get_message() const;
-
- void set_pitch(const int p_pitch);
- int get_pitch() const;
-
- void set_velocity(const int p_velocity);
- int get_velocity() const;
-
- void set_instrument(const int p_instrument);
- int get_instrument() const;
-
- void set_pressure(const int p_pressure);
- int get_pressure() const;
-
- void set_controller_number(const int p_controller_number);
- int get_controller_number() const;
-
- void set_controller_value(const int p_controller_value);
- int get_controller_value() const;
-
- virtual String as_text() const;
-
- InputEventMIDI();
-};
-
-#endif
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 7141423c77..c65d3fefc2 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -288,7 +288,7 @@ static const _KeyCodeText _keycodes[] = {
{KEY_DIVISION ,"Division"},
{KEY_YDIAERESIS ,"Ydiaeresis"},
- {0 ,0}
+ {0 ,nullptr}
/* clang-format on */
};
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index bac32e01dd..5d11e6a378 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -325,4 +325,4 @@ int keycode_get_count();
int keycode_get_value_by_index(int p_index);
const char *keycode_get_name_by_index(int p_index);
-#endif
+#endif // KEYBOARD_H
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index ab43ce4af7..0d1a080682 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -34,30 +34,16 @@
void MainLoop::_bind_methods() {
- ClassDB::bind_method(D_METHOD("input_event", "event"), &MainLoop::input_event);
- ClassDB::bind_method(D_METHOD("input_text", "text"), &MainLoop::input_text);
ClassDB::bind_method(D_METHOD("init"), &MainLoop::init);
ClassDB::bind_method(D_METHOD("iteration", "delta"), &MainLoop::iteration);
ClassDB::bind_method(D_METHOD("idle", "delta"), &MainLoop::idle);
ClassDB::bind_method(D_METHOD("finish"), &MainLoop::finish);
- BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo("_input_text", PropertyInfo(Variant::STRING, "text")));
BIND_VMETHOD(MethodInfo("_initialize"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_iteration", PropertyInfo(Variant::FLOAT, "delta")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_idle", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_drop_files", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "from_screen")));
BIND_VMETHOD(MethodInfo("_finalize"));
- BIND_VMETHOD(MethodInfo("_global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
-
- BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
- BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
- BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
- BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
- BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
- BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST);
- BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST);
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
@@ -80,18 +66,6 @@ MainLoop::MainLoop() {
MainLoop::~MainLoop() {
}
-void MainLoop::input_text(const String &p_text) {
-
- if (get_script_instance())
- get_script_instance()->call("_input_text", p_text);
-}
-
-void MainLoop::input_event(const Ref<InputEvent> &p_event) {
-
- if (get_script_instance())
- get_script_instance()->call("_input_event", p_event);
-}
-
void MainLoop::init() {
if (init_script.is_valid())
@@ -115,18 +89,6 @@ bool MainLoop::idle(float p_time) {
return false;
}
-void MainLoop::drop_files(const Vector<String> &p_files, int p_from_screen) {
-
- if (get_script_instance())
- get_script_instance()->call("_drop_files", p_files, p_from_screen);
-}
-
-void MainLoop::global_menu_action(const Variant &p_id, const Variant &p_meta) {
-
- if (get_script_instance())
- get_script_instance()->call("_global_menu_action", p_id, p_meta);
-}
-
void MainLoop::finish() {
if (get_script_instance()) {
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index b1120aee8a..8f6c8c91b1 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -31,7 +31,7 @@
#ifndef MAIN_LOOP_H
#define MAIN_LOOP_H
-#include "core/os/input_event.h"
+#include "core/input/input_event.h"
#include "core/reference.h"
#include "core/script_language.h"
@@ -48,37 +48,24 @@ protected:
public:
enum {
//make sure these are replicated in Node
- NOTIFICATION_WM_MOUSE_ENTER = 1002,
- NOTIFICATION_WM_MOUSE_EXIT = 1003,
- NOTIFICATION_WM_FOCUS_IN = 1004,
- NOTIFICATION_WM_FOCUS_OUT = 1005,
- NOTIFICATION_WM_QUIT_REQUEST = 1006,
- NOTIFICATION_WM_GO_BACK_REQUEST = 1007,
- NOTIFICATION_WM_UNFOCUS_REQUEST = 1008,
- NOTIFICATION_OS_MEMORY_WARNING = 1009,
- NOTIFICATION_TRANSLATION_CHANGED = 1010,
- NOTIFICATION_WM_ABOUT = 1011,
- NOTIFICATION_CRASH = 1012,
- NOTIFICATION_OS_IME_UPDATE = 1013,
- NOTIFICATION_APP_RESUMED = 1014,
- NOTIFICATION_APP_PAUSED = 1015,
+ NOTIFICATION_OS_MEMORY_WARNING = 2009,
+ NOTIFICATION_TRANSLATION_CHANGED = 2010,
+ NOTIFICATION_WM_ABOUT = 2011,
+ NOTIFICATION_CRASH = 2012,
+ NOTIFICATION_OS_IME_UPDATE = 2013,
+ NOTIFICATION_APP_RESUMED = 2014,
+ NOTIFICATION_APP_PAUSED = 2015,
};
- virtual void input_event(const Ref<InputEvent> &p_event);
- virtual void input_text(const String &p_text);
-
virtual void init();
virtual bool iteration(float p_time);
virtual bool idle(float p_time);
virtual void finish();
- virtual void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
- virtual void global_menu_action(const Variant &p_id, const Variant &p_meta);
-
void set_init_script(const Ref<Script> &p_init_script);
MainLoop();
virtual ~MainLoop();
};
-#endif
+#endif // MAIN_LOOP_H
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 39d3fce910..d921c10ad4 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -81,7 +81,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
void *mem = malloc(p_bytes + (prepad ? PAD_ALIGN : 0));
- ERR_FAIL_COND_V(!mem, NULL);
+ ERR_FAIL_COND_V(!mem, nullptr);
atomic_increment(&alloc_count);
@@ -103,7 +103,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
- if (p_memory == NULL) {
+ if (p_memory == nullptr) {
return alloc_static(p_bytes, p_pad_align);
}
@@ -130,12 +130,12 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
if (p_bytes == 0) {
free(mem);
- return NULL;
+ return nullptr;
} else {
*s = p_bytes;
mem = (uint8_t *)realloc(mem, p_bytes + PAD_ALIGN);
- ERR_FAIL_COND_V(!mem, NULL);
+ ERR_FAIL_COND_V(!mem, nullptr);
s = (uint64_t *)mem;
@@ -147,7 +147,7 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
mem = (uint8_t *)realloc(mem, p_bytes);
- ERR_FAIL_COND_V(mem == NULL && p_bytes > 0, NULL);
+ ERR_FAIL_COND_V(mem == nullptr && p_bytes > 0, nullptr);
return mem;
}
@@ -155,7 +155,7 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
void Memory::free_static(void *p_ptr, bool p_pad_align) {
- ERR_FAIL_COND(p_ptr == NULL);
+ ERR_FAIL_COND(p_ptr == nullptr);
uint8_t *mem = (uint8_t *)p_ptr;
diff --git a/core/os/memory.h b/core/os/memory.h
index 207149b57e..dcaedd92ba 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -206,4 +206,4 @@ struct _GlobalNilClass {
static _GlobalNil _nil;
};
-#endif
+#endif // MEMORY_H
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index 6ebec50ff0..985f6f38e5 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -30,11 +30,11 @@
#include "midi_driver.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
-#include "main/input_default.h"
uint8_t MIDIDriver::last_received_message = 0x00;
-MIDIDriver *MIDIDriver::singleton = NULL;
+MIDIDriver *MIDIDriver::singleton = nullptr;
MIDIDriver *MIDIDriver::get_singleton() {
return singleton;
@@ -117,7 +117,7 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
break;
}
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ InputFilter *id = InputFilter::get_singleton();
id->parse_input_event(event);
}
diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h
index 4f53feb43e..b7377a8a40 100644
--- a/core/os/midi_driver.h
+++ b/core/os/midi_driver.h
@@ -58,4 +58,4 @@ public:
virtual ~MIDIDriver() {}
};
-#endif
+#endif // MIDI_DRIVER_H
diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp
index 97297dca28..31a0dc2bfa 100644
--- a/core/os/mutex.cpp
+++ b/core/os/mutex.cpp
@@ -44,7 +44,7 @@ void _global_unlock() {
template class MutexImpl<std::recursive_mutex>;
template class MutexImpl<std::mutex>;
-template class MutexLock<MutexImpl<std::recursive_mutex> >;
-template class MutexLock<MutexImpl<std::mutex> >;
+template class MutexLock<MutexImpl<std::recursive_mutex>>;
+template class MutexLock<MutexImpl<std::mutex>>;
#endif
diff --git a/core/os/mutex.h b/core/os/mutex.h
index 9033f0cb06..526549dd93 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -76,8 +76,8 @@ using BinaryMutex = MutexImpl<std::mutex>; // Non-recursive, handle with care
extern template class MutexImpl<std::recursive_mutex>;
extern template class MutexImpl<std::mutex>;
-extern template class MutexLock<MutexImpl<std::recursive_mutex> >;
-extern template class MutexLock<MutexImpl<std::mutex> >;
+extern template class MutexLock<MutexImpl<std::recursive_mutex>>;
+extern template class MutexLock<MutexImpl<std::mutex>>;
#else
@@ -105,4 +105,4 @@ using BinaryMutex = MutexImpl<FakeMutex>; // Non-recursive, handle with care
#endif // !NO_THREADS
-#endif
+#endif // MUTEX_H
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 9a65d537ac..0636810e4b 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -30,9 +30,9 @@
#include "os.h"
+#include "core/input/input_filter.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
-#include "core/os/input.h"
#include "core/os/midi_driver.h"
#include "core/project_settings.h"
#include "core/version_generated.gen.h"
@@ -40,7 +40,7 @@
#include <stdarg.h>
-OS *OS::singleton = NULL;
+OS *OS::singleton = nullptr;
OS *OS::get_singleton() {
@@ -139,14 +139,6 @@ void OS::printerr(const char *p_format, ...) {
va_end(argp);
};
-void OS::set_keep_screen_on(bool p_enabled) {
- _keep_screen_on = p_enabled;
-}
-
-bool OS::is_keep_screen_on() const {
- return _keep_screen_on;
-}
-
void OS::set_low_processor_usage_mode(bool p_enabled) {
low_processor_usage_mode = p_enabled;
@@ -167,15 +159,6 @@ int OS::get_low_processor_usage_mode_sleep_usec() const {
return low_processor_usage_mode_sleep_usec;
}
-void OS::set_clipboard(const String &p_text) {
-
- _local_clipboard = p_text;
-}
-String OS::get_clipboard() const {
-
- return _local_clipboard;
-}
-
String OS::get_executable_path() const {
return _execpath;
@@ -201,7 +184,7 @@ void OS::dump_memory_to_file(const char *p_file) {
//Memory::dump_static_mem_to_file(p_file);
}
-static FileAccess *_OSPRF = NULL;
+static FileAccess *_OSPRF = nullptr;
static void _OS_printres(Object *p_obj) {
@@ -216,31 +199,6 @@ static void _OS_printres(Object *p_obj) {
print_line(str);
}
-bool OS::has_virtual_keyboard() const {
-
- return false;
-}
-
-void OS::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) {
-}
-
-void OS::hide_virtual_keyboard() {
-}
-
-int OS::get_virtual_keyboard_height() const {
- return 0;
-}
-
-void OS::set_cursor_shape(CursorShape p_shape) {
-}
-
-OS::CursorShape OS::get_cursor_shape() const {
- return CURSOR_ARROW;
-}
-
-void OS::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-}
-
void OS::print_all_resources(String p_to_file) {
ERR_FAIL_COND(p_to_file != "" && _OSPRF);
@@ -249,7 +207,7 @@ void OS::print_all_resources(String p_to_file) {
Error err;
_OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err);
if (err != OK) {
- _OSPRF = NULL;
+ _OSPRF = nullptr;
ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + ".");
}
}
@@ -260,13 +218,13 @@ void OS::print_all_resources(String p_to_file) {
if (_OSPRF)
memdelete(_OSPRF);
- _OSPRF = NULL;
+ _OSPRF = nullptr;
}
}
void OS::print_resources_in_use(bool p_short) {
- ResourceCache::dump(NULL, p_short);
+ ResourceCache::dump(nullptr, p_short);
}
void OS::dump_resources_to_file(const char *p_file) {
@@ -372,45 +330,6 @@ Error OS::shell_open(String p_uri) {
};
// implement these with the canvas?
-Error OS::dialog_show(String p_title, String p_description, Vector<String> p_buttons, Object *p_obj, String p_callback) {
-
- while (true) {
-
- print("%ls\n--------\n%ls\n", p_title.c_str(), p_description.c_str());
- for (int i = 0; i < p_buttons.size(); i++) {
- if (i > 0) print(", ");
- print("%i=%ls", i + 1, p_buttons[i].c_str());
- };
- print("\n");
- String res = get_stdin_string().strip_edges();
- if (!res.is_numeric())
- continue;
- int n = res.to_int();
- if (n < 0 || n >= p_buttons.size())
- continue;
- if (p_obj && p_callback != "")
- p_obj->call_deferred(p_callback, n);
- break;
- };
- return OK;
-};
-
-Error OS::dialog_input_text(String p_title, String p_description, String p_partial, Object *p_obj, String p_callback) {
-
- ERR_FAIL_COND_V(!p_obj, FAILED);
- ERR_FAIL_COND_V(p_callback == "", FAILED);
- print("%ls\n---------\n%ls\n[%ls]:\n", p_title.c_str(), p_description.c_str(), p_partial.c_str());
-
- String res = get_stdin_string().strip_edges();
- bool success = true;
- if (res == "") {
- res = p_partial;
- };
-
- p_obj->call_deferred(p_callback, success, res);
-
- return OK;
-};
uint64_t OS::get_static_memory_usage() const {
@@ -427,12 +346,6 @@ Error OS::set_cwd(const String &p_cwd) {
return ERR_CANT_OPEN;
}
-bool OS::has_touchscreen_ui_hint() const {
-
- //return false;
- return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse();
-}
-
uint64_t OS::get_free_static_memory() const {
return Memory::get_mem_available();
@@ -441,17 +354,7 @@ uint64_t OS::get_free_static_memory() const {
void OS::yield() {
}
-void OS::set_screen_orientation(ScreenOrientation p_orientation) {
-
- _orientation = p_orientation;
-}
-
-OS::ScreenOrientation OS::get_screen_orientation() const {
-
- return (OS::ScreenOrientation)_orientation;
-}
-
-void OS::_ensure_user_data_dir() {
+void OS::ensure_user_data_dir() {
String dd = get_user_data_dir();
DirAccess *da = DirAccess::open(dd);
@@ -467,12 +370,6 @@ void OS::_ensure_user_data_dir() {
memdelete(da);
}
-void OS::set_native_icon(const String &p_filename) {
-}
-
-void OS::set_icon(const Ref<Image> &p_icon) {
-}
-
String OS::get_model_name() const {
return "GenericDevice";
@@ -484,15 +381,6 @@ void OS::set_cmdline(const char *p_execpath, const List<String> &p_args) {
_cmdline = p_args;
};
-void OS::release_rendering_thread() {
-}
-
-void OS::make_rendering_thread() {
-}
-
-void OS::swap_buffers() {
-}
-
String OS::get_unique_id() const {
ERR_FAIL_V("");
@@ -503,31 +391,6 @@ int OS::get_processor_count() const {
return 1;
}
-Error OS::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
-
- return FAILED;
-};
-
-bool OS::native_video_is_playing() const {
-
- return false;
-};
-
-void OS::native_video_pause(){
-
-};
-
-void OS::native_video_unpause(){
-
-};
-
-void OS::native_video_stop(){
-
-};
-
-void OS::set_mouse_mode(MouseMode p_mode) {
-}
-
bool OS::can_use_threads() const {
#ifdef NO_THREADS
@@ -537,51 +400,6 @@ bool OS::can_use_threads() const {
#endif
}
-OS::MouseMode OS::get_mouse_mode() const {
-
- return MOUSE_MODE_VISIBLE;
-}
-
-OS::LatinKeyboardVariant OS::get_latin_keyboard_variant() const {
-
- return LATIN_KEYBOARD_QWERTY;
-}
-
-bool OS::is_joy_known(int p_device) {
- return true;
-}
-
-String OS::get_joy_guid(int p_device) const {
- return "Default Joypad";
-}
-
-void OS::set_context(int p_context) {
-}
-
-OS::SwitchVSyncCallbackInThread OS::switch_vsync_function = NULL;
-
-void OS::set_use_vsync(bool p_enable) {
- _use_vsync = p_enable;
- if (switch_vsync_function) { //if a function was set, use function
- switch_vsync_function(p_enable);
- } else { //otherwise just call here
- _set_use_vsync(p_enable);
- }
-}
-
-bool OS::is_vsync_enabled() const {
-
- return _use_vsync;
-}
-
-void OS::set_vsync_via_compositor(bool p_enable) {
- _vsync_via_compositor = p_enable;
-}
-
-bool OS::is_vsync_via_compositor_enabled() const {
- return _vsync_via_compositor;
-}
-
void OS::set_has_server_feature_callback(HasServerFeatureCallback p_callback) {
has_server_feature_callback = p_callback;
@@ -653,48 +471,6 @@ bool OS::has_feature(const String &p_feature) {
return false;
}
-void OS::center_window() {
-
- if (is_window_fullscreen()) return;
-
- Point2 sp = get_screen_position(get_current_screen());
- Size2 scr = get_screen_size(get_current_screen());
- Size2 wnd = get_real_window_size();
-
- int x = sp.width + (scr.width - wnd.width) / 2;
- int y = sp.height + (scr.height - wnd.height) / 2;
-
- set_window_position(Vector2(x, y));
-}
-
-int OS::get_video_driver_count() const {
-
- return 2;
-}
-
-const char *OS::get_video_driver_name(int p_driver) const {
-
- switch (p_driver) {
- case VIDEO_DRIVER_GLES2:
- return "GLES2";
- case VIDEO_DRIVER_VULKAN:
- default:
- return "Vulkan";
- }
-}
-
-int OS::get_audio_driver_count() const {
-
- return AudioDriverManager::get_driver_count();
-}
-
-const char *OS::get_audio_driver_name(int p_driver) const {
-
- AudioDriver *driver = AudioDriverManager::get_driver(p_driver);
- ERR_FAIL_COND_V_MSG(!driver, "", "Cannot get audio driver at index '" + itos(p_driver) + "'.");
- return AudioDriverManager::get_driver(p_driver)->get_name();
-}
-
void OS::set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments) {
restart_on_exit = p_restart;
restart_commandline = p_restart_arguments;
@@ -740,7 +516,6 @@ OS::OS() {
_verbose_stdout = false;
_no_window = false;
_exit_code = 0;
- _orientation = SCREEN_LANDSCAPE;
_render_thread_mode = RENDER_THREAD_SAFE;
@@ -748,9 +523,9 @@ OS::OS() {
_allow_layered = false;
_stack_bottom = (void *)(&stack_bottom);
- _logger = NULL;
+ _logger = nullptr;
- has_server_feature_callback = NULL;
+ has_server_feature_callback = nullptr;
Vector<Logger *> loggers;
loggers.push_back(memnew(StdLogger));
@@ -759,5 +534,5 @@ OS::OS() {
OS::~OS() {
memdelete(_logger);
- singleton = NULL;
+ singleton = nullptr;
}
diff --git a/core/os/os.h b/core/os/os.h
index 1d3619b1e6..714a10bf76 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -82,31 +82,6 @@ public:
RENDER_THREAD_SAFE,
RENDER_SEPARATE_THREAD
};
- struct VideoMode {
-
- int width, height;
- bool fullscreen;
- bool resizable;
- bool borderless_window;
- bool maximized;
- bool always_on_top;
- bool use_vsync;
- bool vsync_via_compositor;
- bool layered;
- float get_aspect() const { return (float)width / (float)height; }
- VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false, bool p_always_on_top = false, bool p_use_vsync = false, bool p_vsync_via_compositor = false) {
- width = p_width;
- height = p_height;
- fullscreen = p_fullscreen;
- resizable = p_resizable;
- borderless_window = p_borderless_window;
- maximized = p_maximized;
- always_on_top = p_always_on_top;
- use_vsync = p_use_vsync;
- vsync_via_compositor = p_vsync_via_compositor;
- layered = false;
- }
- };
protected:
friend class Main;
@@ -117,8 +92,8 @@ protected:
// functions used by main to initialize/deinitialize the OS
void add_logger(Logger *p_logger);
- virtual void initialize_core() = 0;
- virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0;
+ virtual void initialize() = 0;
+ virtual void initialize_joypads() = 0;
virtual void set_main_loop(MainLoop *p_main_loop) = 0;
virtual void delete_main_loop() = 0;
@@ -128,7 +103,6 @@ protected:
virtual void set_cmdline(const char *p_execpath, const List<String> &p_args);
- void _ensure_user_data_dir();
virtual bool _check_internal_feature_support(const String &p_feature) = 0;
public:
@@ -136,128 +110,27 @@ public:
static OS *get_singleton();
- virtual void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta){};
- virtual void global_menu_add_separator(const String &p_menu){};
- virtual void global_menu_remove_item(const String &p_menu, int p_idx){};
- virtual void global_menu_clear(const String &p_menu){};
-
void 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 = Logger::ERR_ERROR);
void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
- virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0;
virtual String get_stdin_string(bool p_block = true) = 0;
- enum MouseMode {
- MOUSE_MODE_VISIBLE,
- MOUSE_MODE_HIDDEN,
- MOUSE_MODE_CAPTURED,
- MOUSE_MODE_CONFINED
- };
-
- virtual void set_mouse_mode(MouseMode p_mode);
- virtual MouseMode get_mouse_mode() const;
-
- virtual void warp_mouse_position(const Point2 &p_to) {}
- virtual Point2 get_mouse_position() const = 0;
- virtual int get_mouse_button_state() const = 0;
- virtual void set_window_title(const String &p_title) = 0;
-
- virtual void set_clipboard(const String &p_text);
- virtual String get_clipboard() const;
-
- virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0) = 0;
- virtual VideoMode get_video_mode(int p_screen = 0) const = 0;
- virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const = 0;
-
- enum VideoDriver {
- VIDEO_DRIVER_VULKAN,
- VIDEO_DRIVER_GLES2,
- VIDEO_DRIVER_MAX,
- };
-
- virtual int get_video_driver_count() const;
- virtual const char *get_video_driver_name(int p_driver) const;
- virtual int get_current_video_driver() const = 0;
-
- virtual int get_audio_driver_count() const;
- virtual const char *get_audio_driver_name(int p_driver) const;
-
virtual PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs();
virtual void close_midi_inputs();
- virtual int get_screen_count() const { return 1; }
- virtual int get_current_screen() const { return 0; }
- virtual void set_current_screen(int p_screen) {}
- virtual Point2 get_screen_position(int p_screen = -1) const { return Point2(); }
- virtual Size2 get_screen_size(int p_screen = -1) const { return get_window_size(); }
- virtual int get_screen_dpi(int p_screen = -1) const { return 72; }
- virtual Point2 get_window_position() const { return Vector2(); }
- virtual void set_window_position(const Point2 &p_position) {}
- virtual Size2 get_max_window_size() const { return Size2(); };
- virtual Size2 get_min_window_size() const { return Size2(); };
- virtual Size2 get_window_size() const = 0;
- virtual Size2 get_real_window_size() const { return get_window_size(); }
- virtual void set_min_window_size(const Size2 p_size) {}
- virtual void set_max_window_size(const Size2 p_size) {}
- virtual void set_window_size(const Size2 p_size) {}
- virtual void set_window_fullscreen(bool p_enabled) {}
- virtual bool is_window_fullscreen() const { return true; }
- virtual void set_window_resizable(bool p_enabled) {}
- virtual bool is_window_resizable() const { return false; }
- virtual void set_window_minimized(bool p_enabled) {}
- virtual bool is_window_minimized() const { return false; }
- virtual void set_window_maximized(bool p_enabled) {}
- virtual bool is_window_maximized() const { return true; }
- virtual void set_window_always_on_top(bool p_enabled) {}
- virtual bool is_window_always_on_top() const { return false; }
- virtual bool is_window_focused() const { return true; }
- virtual void set_console_visible(bool p_enabled) {}
- virtual bool is_console_visible() const { return false; }
- virtual void request_attention() {}
- virtual void center_window();
-
- // Returns window area free of hardware controls and other obstacles.
- // The application should use this to determine where to place UI elements.
- //
- // Keep in mind the area returned is in window coordinates rather than
- // viewport coordinates - you should perform the conversion on your own.
- //
- // The maximum size of the area is Rect2(0, 0, window_size.width, window_size.height).
- virtual Rect2 get_window_safe_area() const {
- Size2 window_size = get_window_size();
- return Rect2(0, 0, window_size.width, window_size.height);
- }
-
- virtual void set_borderless_window(bool p_borderless) {}
- virtual bool get_borderless_window() { return 0; }
-
- virtual bool get_window_per_pixel_transparency_enabled() const { return false; }
- virtual void set_window_per_pixel_transparency_enabled(bool p_enabled) {}
-
- virtual uint8_t *get_layered_buffer_data() { return NULL; }
- virtual Size2 get_layered_buffer_size() { return Size2(0, 0); }
- virtual void swap_layered_buffer() {}
-
- virtual void set_ime_active(const bool p_active) {}
- virtual void set_ime_position(const Point2 &p_pos) {}
- virtual Point2 get_ime_selection() const { return Point2(); }
- virtual String get_ime_text() const { return String(); }
-
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) { return ERR_UNAVAILABLE; }
virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; }
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; }
- virtual void set_keep_screen_on(bool p_enabled);
- virtual bool is_keep_screen_on() const;
virtual void set_low_processor_usage_mode(bool p_enabled);
virtual bool is_in_low_processor_usage_mode() const;
virtual void set_low_processor_usage_mode_sleep_usec(int p_usec);
virtual int get_low_processor_usage_mode_sleep_usec() const;
virtual String get_executable_path() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL) = 0;
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
virtual void vibrate_handheld(int p_duration_ms = 500);
@@ -273,6 +146,11 @@ public:
virtual List<String> get_cmdline_args() const { return _cmdline; }
virtual String get_model_name() const;
+ bool is_layered_allowed() const { return _allow_layered; }
+ bool is_hidpi_allowed() const { return _allow_hidpi; }
+
+ void ensure_user_data_dir();
+
virtual MainLoop *get_main_loop() const = 0;
virtual void yield();
@@ -338,8 +216,6 @@ public:
uint32_t get_ticks_msec() const;
uint64_t get_splash_tick_msec() const;
- virtual bool can_draw() const = 0;
-
virtual bool is_userfs_persistent() const { return true; }
bool is_stdout_verbose() const;
@@ -348,39 +224,6 @@ public:
virtual bool is_disable_crash_handler() const { return false; }
virtual void initialize_debugging() {}
- enum CursorShape {
- CURSOR_ARROW,
- CURSOR_IBEAM,
- CURSOR_POINTING_HAND,
- CURSOR_CROSS,
- CURSOR_WAIT,
- CURSOR_BUSY,
- CURSOR_DRAG,
- CURSOR_CAN_DROP,
- CURSOR_FORBIDDEN,
- CURSOR_VSIZE,
- CURSOR_HSIZE,
- CURSOR_BDIAGSIZE,
- CURSOR_FDIAGSIZE,
- CURSOR_MOVE,
- CURSOR_VSPLIT,
- CURSOR_HSPLIT,
- CURSOR_HELP,
- CURSOR_MAX
- };
-
- virtual bool has_virtual_keyboard() const;
- virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1);
- virtual void hide_virtual_keyboard();
-
- // returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
- virtual int get_virtual_keyboard_height() const;
-
- virtual void set_cursor_shape(CursorShape p_shape);
- virtual CursorShape get_cursor_shape() const;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
-
- virtual bool get_swap_ok_cancel() { return false; }
virtual void dump_memory_to_file(const char *p_file);
virtual void dump_resources_to_file(const char *p_file);
virtual void print_resources_in_use(bool p_short = false);
@@ -423,34 +266,8 @@ public:
virtual void set_no_window_mode(bool p_enable);
virtual bool is_no_window_mode_enabled() const;
- virtual bool has_touchscreen_ui_hint() const;
-
- enum ScreenOrientation {
-
- SCREEN_LANDSCAPE,
- SCREEN_PORTRAIT,
- SCREEN_REVERSE_LANDSCAPE,
- SCREEN_REVERSE_PORTRAIT,
- SCREEN_SENSOR_LANDSCAPE,
- SCREEN_SENSOR_PORTRAIT,
- SCREEN_SENSOR,
- };
-
- virtual void set_screen_orientation(ScreenOrientation p_orientation);
- ScreenOrientation get_screen_orientation() const;
-
- virtual void enable_for_stealing_focus(ProcessID pid) {}
- virtual void move_window_to_foreground() {}
-
virtual void debug_break();
- virtual void release_rendering_thread();
- virtual void make_rendering_thread();
- virtual void swap_buffers();
-
- virtual void set_native_icon(const String &p_filename);
- virtual void set_icon(const Ref<Image> &p_icon);
-
virtual int get_exit_code() const;
virtual void set_exit_code(int p_code);
@@ -458,62 +275,12 @@ public:
virtual String get_unique_id() const;
- virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
- virtual bool native_video_is_playing() const;
- virtual void native_video_pause();
- virtual void native_video_unpause();
- virtual void native_video_stop();
-
virtual bool can_use_threads() const;
- virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, Object *p_obj, String p_callback);
- virtual Error dialog_input_text(String p_title, String p_description, String p_partial, Object *p_obj, String p_callback);
-
- enum LatinKeyboardVariant {
- LATIN_KEYBOARD_QWERTY,
- LATIN_KEYBOARD_QWERTZ,
- LATIN_KEYBOARD_AZERTY,
- LATIN_KEYBOARD_QZERTY,
- LATIN_KEYBOARD_DVORAK,
- LATIN_KEYBOARD_NEO,
- LATIN_KEYBOARD_COLEMAK,
- };
-
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
-
- virtual bool is_joy_known(int p_device);
- virtual String get_joy_guid(int p_device) const;
-
- enum EngineContext {
- CONTEXT_EDITOR,
- CONTEXT_PROJECTMAN,
- CONTEXT_ENGINE,
- };
-
- virtual void set_context(int p_context);
-
- //amazing hack because OpenGL needs this to be set on a separate thread..
- //also core can't access servers, so a callback must be used
- typedef void (*SwitchVSyncCallbackInThread)(bool);
-
- static SwitchVSyncCallbackInThread switch_vsync_function;
- void set_use_vsync(bool p_enable);
- bool is_vsync_enabled() const;
-
- //real, actual overridable function to switch vsync, which needs to be called from graphics thread if needed
- virtual void _set_use_vsync(bool p_enable) {}
-
- void set_vsync_via_compositor(bool p_enable);
- bool is_vsync_via_compositor_enabled() const;
-
- virtual void force_process_input(){};
bool has_feature(const String &p_feature);
void set_has_server_feature_callback(HasServerFeatureCallback p_callback);
- bool is_layered_allowed() const { return _allow_layered; }
- bool is_hidpi_allowed() const { return _allow_hidpi; }
-
void set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments);
bool is_restart_on_exit_set() const;
List<String> get_restart_on_exit_arguments() const;
@@ -527,4 +294,4 @@ public:
virtual ~OS();
};
-#endif
+#endif // OS_H
diff --git a/core/os/rw_lock.cpp b/core/os/rw_lock.cpp
index 75683962af..1dd2c3bccb 100644
--- a/core/os/rw_lock.cpp
+++ b/core/os/rw_lock.cpp
@@ -34,11 +34,11 @@
#include <stddef.h>
-RWLock *(*RWLock::create_func)() = 0;
+RWLock *(*RWLock::create_func)() = nullptr;
RWLock *RWLock::create() {
- ERR_FAIL_COND_V(!create_func, 0);
+ ERR_FAIL_COND_V(!create_func, nullptr);
return create_func();
}
diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h
index 21648b6cbc..64dfbef20c 100644
--- a/core/os/rw_lock.h
+++ b/core/os/rw_lock.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RWLOCK_H
-#define RWLOCK_H
+#ifndef RW_LOCK_H
+#define RW_LOCK_H
#include "core/error_list.h"
@@ -79,4 +79,4 @@ public:
}
};
-#endif // RWLOCK_H
+#endif // RW_LOCK_H
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index 6f194d4887..3d9d1ab984 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -80,4 +80,4 @@ public:
#endif
-#endif
+#endif // SEMAPHORE_H
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index 7f6148057d..294b52f00c 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -30,10 +30,10 @@
#include "thread.h"
-Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = NULL;
-Thread::ID (*Thread::get_thread_id_func)() = NULL;
-void (*Thread::wait_to_finish_func)(Thread *) = NULL;
-Error (*Thread::set_name_func)(const String &) = NULL;
+Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = nullptr;
+Thread::ID (*Thread::get_thread_id_func)() = nullptr;
+void (*Thread::wait_to_finish_func)(Thread *) = nullptr;
+Error (*Thread::set_name_func)(const String &) = nullptr;
Thread::ID Thread::_main_thread_id = 0;
@@ -50,7 +50,7 @@ Thread *Thread::create(ThreadCreateCallback p_callback, void *p_user, const Sett
return create_func(p_callback, p_user, p_settings);
}
- return NULL;
+ return nullptr;
}
void Thread::wait_to_finish(Thread *p_thread) {
diff --git a/core/os/thread.h b/core/os/thread.h
index 0803fd1190..76d296bcf7 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -77,4 +77,4 @@ public:
virtual ~Thread();
};
-#endif
+#endif // THREAD_H
diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h
index da8188f983..066ee498ac 100644
--- a/core/os/thread_dummy.h
+++ b/core/os/thread_dummy.h
@@ -61,4 +61,4 @@ public:
static void make_default();
};
-#endif
+#endif // THREAD_DUMMY_H
diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h
index 0221edf491..670ee8b125 100644
--- a/core/os/thread_safe.h
+++ b/core/os/thread_safe.h
@@ -38,4 +38,4 @@
#define _THREAD_SAFE_LOCK_ _thread_safe_.lock();
#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
-#endif
+#endif // THREAD_SAFE_H
diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h
index 9dcd6ceece..00dc53286e 100644
--- a/core/os/threaded_array_processor.h
+++ b/core/os/threaded_array_processor.h
@@ -80,7 +80,7 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
threads.resize(OS::get_singleton()->get_processor_count());
for (int i = 0; i < threads.size(); i++) {
- threads.write[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U> >, &data);
+ threads.write[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U>>, &data);
}
for (int i = 0; i < threads.size(); i++) {
diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp
index b82a366ef2..04deba2c14 100644
--- a/core/packed_data_container.cpp
+++ b/core/packed_data_container.cpp
@@ -114,7 +114,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
} else {
Variant v;
- Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL, false);
+ Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, nullptr, false);
if (rerr != OK) {
@@ -254,7 +254,7 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
uint32_t pos = tmpdata.size();
int len;
- encode_variant(p_data, NULL, len, false);
+ encode_variant(p_data, nullptr, len, false);
tmpdata.resize(tmpdata.size() + len);
encode_variant(p_data, &tmpdata.write[pos], len, false);
return pos;
diff --git a/core/packed_data_container.h b/core/packed_data_container.h
index 852fdcd0d3..0f08a1cb7b 100644
--- a/core/packed_data_container.h
+++ b/core/packed_data_container.h
@@ -73,7 +73,7 @@ protected:
static void _bind_methods();
public:
- virtual Variant getvar(const Variant &p_key, bool *r_valid = NULL) const;
+ virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
Error pack(const Variant &p_data);
int size() const;
@@ -98,7 +98,7 @@ public:
bool _is_dictionary() const;
int size() const;
- virtual Variant getvar(const Variant &p_key, bool *r_valid = NULL) const;
+ virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
PackedDataContainerRef();
};
diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp
index 5a83c3eeb4..b74540395c 100644
--- a/core/pool_allocator.cpp
+++ b/core/pool_allocator.cpp
@@ -250,9 +250,9 @@ PoolAllocator::Entry *PoolAllocator::get_entry(ID p_mem) {
unsigned int check = p_mem & CHECK_MASK;
int entry = p_mem >> CHECK_BITS;
- ERR_FAIL_INDEX_V(entry, entry_max, NULL);
- ERR_FAIL_COND_V(entry_array[entry].check != check, NULL);
- ERR_FAIL_COND_V(entry_array[entry].len == 0, NULL);
+ ERR_FAIL_INDEX_V(entry, entry_max, nullptr);
+ ERR_FAIL_COND_V(entry_array[entry].check != check, nullptr);
+ ERR_FAIL_COND_V(entry_array[entry].len == 0, nullptr);
return &entry_array[entry];
}
@@ -261,9 +261,9 @@ const PoolAllocator::Entry *PoolAllocator::get_entry(ID p_mem) const {
unsigned int check = p_mem & CHECK_MASK;
int entry = p_mem >> CHECK_BITS;
- ERR_FAIL_INDEX_V(entry, entry_max, NULL);
- ERR_FAIL_COND_V(entry_array[entry].check != check, NULL);
- ERR_FAIL_COND_V(entry_array[entry].len == 0, NULL);
+ ERR_FAIL_INDEX_V(entry, entry_max, nullptr);
+ ERR_FAIL_COND_V(entry_array[entry].check != check, nullptr);
+ ERR_FAIL_COND_V(entry_array[entry].len == 0, nullptr);
return &entry_array[entry];
}
@@ -461,7 +461,7 @@ const void *PoolAllocator::get(ID p_mem) const {
if (!needs_locking) {
const Entry *e = get_entry(p_mem);
- ERR_FAIL_COND_V(!e, NULL);
+ ERR_FAIL_COND_V(!e, nullptr);
return &pool[e->pos];
}
@@ -471,20 +471,20 @@ const void *PoolAllocator::get(ID p_mem) const {
if (!e) {
mt_unlock();
- ERR_FAIL_COND_V(!e, NULL);
+ ERR_FAIL_COND_V(!e, nullptr);
}
if (e->lock == 0) {
mt_unlock();
ERR_PRINT("e->lock == 0");
- return NULL;
+ return nullptr;
}
if ((int)e->pos >= pool_size) {
mt_unlock();
ERR_PRINT("e->pos<0 || e->pos>=pool_size");
- return NULL;
+ return nullptr;
}
const void *ptr = &pool[e->pos];
@@ -498,7 +498,7 @@ void *PoolAllocator::get(ID p_mem) {
if (!needs_locking) {
Entry *e = get_entry(p_mem);
- ERR_FAIL_COND_V(!e, NULL);
+ ERR_FAIL_COND_V(!e, nullptr);
return &pool[e->pos];
}
@@ -508,21 +508,21 @@ void *PoolAllocator::get(ID p_mem) {
if (!e) {
mt_unlock();
- ERR_FAIL_COND_V(!e, NULL);
+ ERR_FAIL_COND_V(!e, nullptr);
}
if (e->lock == 0) {
//assert(0);
mt_unlock();
ERR_PRINT("e->lock == 0");
- return NULL;
+ return nullptr;
}
if ((int)e->pos >= pool_size) {
mt_unlock();
ERR_PRINT("e->pos<0 || e->pos>=pool_size");
- return NULL;
+ return nullptr;
}
void *ptr = &pool[e->pos];
@@ -606,7 +606,7 @@ PoolAllocator::PoolAllocator(void *p_mem, int p_size, int p_align, bool p_needs_
create_pool(p_mem, p_size, p_max_entries);
needs_locking = p_needs_locking;
align = p_align;
- mem_ptr = NULL;
+ mem_ptr = nullptr;
}
PoolAllocator::PoolAllocator(int p_align, int p_size, bool p_needs_locking, int p_max_entries) {
diff --git a/core/pool_allocator.h b/core/pool_allocator.h
index e34f5b1104..8c1710ebe0 100644
--- a/core/pool_allocator.h
+++ b/core/pool_allocator.h
@@ -148,4 +148,4 @@ public:
virtual ~PoolAllocator();
};
-#endif
+#endif // POOL_ALLOCATOR_H
diff --git a/core/print_string.cpp b/core/print_string.cpp
index 551b149334..8eb1d9e86a 100644
--- a/core/print_string.cpp
+++ b/core/print_string.cpp
@@ -34,7 +34,7 @@
#include <stdio.h>
-static PrintHandlerList *print_handler_list = NULL;
+static PrintHandlerList *print_handler_list = nullptr;
bool _print_line_enabled = true;
bool _print_error_enabled = true;
@@ -50,7 +50,7 @@ void remove_print_handler(PrintHandlerList *p_handler) {
_global_lock();
- PrintHandlerList *prev = NULL;
+ PrintHandlerList *prev = nullptr;
PrintHandlerList *l = print_handler_list;
while (l) {
@@ -69,7 +69,7 @@ void remove_print_handler(PrintHandlerList *p_handler) {
//OS::get_singleton()->print("print handler list is %p\n",print_handler_list);
_global_unlock();
- ERR_FAIL_COND(l == NULL);
+ ERR_FAIL_COND(l == nullptr);
}
void print_line(String p_string) {
diff --git a/core/print_string.h b/core/print_string.h
index c2cf1c293b..d83cc35dd6 100644
--- a/core/print_string.h
+++ b/core/print_string.h
@@ -60,4 +60,4 @@ extern void print_line(String p_string);
extern void print_error(String p_string);
extern void print_verbose(String p_string);
-#endif
+#endif // PRINT_STRING_H
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 3a21610331..63b52661b4 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -43,7 +43,7 @@
#include <zlib.h>
-ProjectSettings *ProjectSettings::singleton = NULL;
+ProjectSettings *ProjectSettings::singleton = nullptr;
ProjectSettings *ProjectSettings::get_singleton() {
@@ -532,7 +532,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) {
d.resize(vlen);
f->get_buffer(d.ptrw(), vlen);
Variant value;
- err = decode_variant(value, d.ptr(), d.size(), NULL, true);
+ err = decode_variant(value, d.ptr(), d.size(), nullptr, true);
ERR_CONTINUE_MSG(err != OK, "Error decoding property: " + key + ".");
set(key, value);
}
@@ -571,7 +571,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
memdelete(f);
// If we're loading a project.godot from source code, we can operate some
@@ -652,7 +652,7 @@ Error ProjectSettings::save() {
return save_custom(get_resource_path().plus_file("project.godot"));
}
-Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
@@ -663,7 +663,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
int count = 0;
- for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) {
+ for (Map<String, List<String>>::Element *E = props.front(); E; E = E->next()) {
for (List<String>::Element *F = E->get().front(); F; F = F->next()) {
@@ -679,7 +679,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key);
int len;
- err = encode_variant(p_custom_features, NULL, len, false);
+ err = encode_variant(p_custom_features, nullptr, len, false);
if (err != OK) {
memdelete(file);
ERR_FAIL_V(err);
@@ -700,7 +700,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_32(count); //store how many properties are saved
}
- for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) {
+ for (Map<String, List<String>>::Element *E = props.front(); E; E = E->next()) {
for (List<String>::Element *F = E->get().front(); F; F = F->next()) {
@@ -717,7 +717,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key);
int len;
- err = encode_variant(value, NULL, len, true);
+ err = encode_variant(value, nullptr, len, true);
if (err != OK)
memdelete(file);
ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant.");
@@ -740,7 +740,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
return OK;
}
-Error ProjectSettings::_save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_text(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
@@ -761,7 +761,7 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin
file->store_string("custom_features=\"" + p_custom_features + "\"\n");
file->store_string("\n");
- for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) {
+ for (Map<String, List<String>>::Element *E = props.front(); E; E = E->next()) {
if (E != props.front())
file->store_string("\n");
@@ -838,7 +838,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
vclist.insert(vc);
}
- Map<String, List<String> > props;
+ Map<String, List<String>> props;
for (Set<_VCSort>::Element *E = vclist.front(); E; E = E->next()) {
@@ -1220,5 +1220,5 @@ ProjectSettings::ProjectSettings() {
ProjectSettings::~ProjectSettings() {
- singleton = NULL;
+ singleton = nullptr;
}
diff --git a/core/project_settings.h b/core/project_settings.h
index ed153bdc20..7b3ca18c62 100644
--- a/core/project_settings.h
+++ b/core/project_settings.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GLOBAL_CONFIG_H
-#define GLOBAL_CONFIG_H
+#ifndef PROJECT_SETTINGS_H
+#define PROJECT_SETTINGS_H
#include "core/object.h"
#include "core/os/thread_safe.h"
@@ -97,8 +97,8 @@ protected:
Error _load_settings_binary(const String &p_path);
Error _load_settings_text_or_binary(const String &p_text_path, const String &p_bin_path);
- Error _save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
- Error _save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
+ Error _save_settings_text(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
+ Error _save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String());
Error _save_custom_bnd(const String &p_file);
@@ -166,4 +166,4 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
-#endif
+#endif // PROJECT_SETTINGS_H
diff --git a/core/reference.h b/core/reference.h
index fd42c4e537..30a93d82a6 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -152,7 +152,7 @@ public:
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
- r.reference = NULL;
+ r.reference = nullptr;
}
void operator=(const Variant &p_variant) {
@@ -190,14 +190,14 @@ public:
Ref(const Ref &p_from) {
- reference = NULL;
+ reference = nullptr;
ref(p_from);
}
template <class T_Other>
Ref(const Ref<T_Other> &p_from) {
- reference = NULL;
+ reference = nullptr;
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
if (!refb) {
unref();
@@ -206,12 +206,12 @@ public:
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
- r.reference = NULL;
+ r.reference = nullptr;
}
Ref(T *p_reference) {
- reference = NULL;
+ reference = nullptr;
if (p_reference)
ref_pointer(p_reference);
}
@@ -233,8 +233,8 @@ public:
}
}
- inline bool is_valid() const { return reference != NULL; }
- inline bool is_null() const { return reference == NULL; }
+ inline bool is_valid() const { return reference != nullptr; }
+ inline bool is_null() const { return reference == nullptr; }
void unref() {
//TODO this should be moved to mutexes, since this engine does not really
@@ -245,7 +245,7 @@ public:
memdelete(reference);
}
- reference = NULL;
+ reference = nullptr;
}
void instance() {
@@ -254,7 +254,7 @@ public:
Ref() {
- reference = NULL;
+ reference = nullptr;
}
~Ref() {
@@ -285,7 +285,7 @@ public:
#ifdef PTRCALL_ENABLED
template <class T>
-struct PtrToArg<Ref<T> > {
+struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
@@ -312,7 +312,7 @@ struct PtrToArg<const Ref<T> &> {
#ifdef DEBUG_METHODS_ENABLED
template <class T>
-struct GetTypeInfo<Ref<T> > {
+struct GetTypeInfo<Ref<T>> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index b0ba8ed194..905f43d61b 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -38,7 +38,8 @@
#include "core/crypto/hashing_context.h"
#include "core/engine.h"
#include "core/func_ref.h"
-#include "core/input_map.h"
+#include "core/input/input_filter.h"
+#include "core/input/input_map.h"
#include "core/io/config_file.h"
#include "core/io/dtls_server.h"
#include "core/io/http_client.h"
@@ -62,7 +63,6 @@
#include "core/math/geometry.h"
#include "core/math/random_number_generator.h"
#include "core/math/triangle_mesh.h"
-#include "core/os/input.h"
#include "core/os/main_loop.h"
#include "core/packed_data_container.h"
#include "core/path_remap.h"
@@ -78,17 +78,17 @@ static Ref<TranslationLoaderPO> resource_format_po;
static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto;
static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto;
-static _ResourceLoader *_resource_loader = NULL;
-static _ResourceSaver *_resource_saver = NULL;
-static _OS *_os = NULL;
-static _Engine *_engine = NULL;
-static _ClassDB *_classdb = NULL;
-static _Marshalls *_marshalls = NULL;
-static _JSON *_json = NULL;
+static _ResourceLoader *_resource_loader = nullptr;
+static _ResourceSaver *_resource_saver = nullptr;
+static _OS *_os = nullptr;
+static _Engine *_engine = nullptr;
+static _ClassDB *_classdb = nullptr;
+static _Marshalls *_marshalls = nullptr;
+static _JSON *_json = nullptr;
-static IP *ip = NULL;
+static IP *ip = nullptr;
-static _Geometry *_geometry = NULL;
+static _Geometry *_geometry = nullptr;
extern Mutex _global_mutex;
@@ -138,6 +138,7 @@ void register_core_types() {
ClassDB::register_virtual_class<InputEvent>();
ClassDB::register_virtual_class<InputEventWithModifiers>();
+ ClassDB::register_virtual_class<InputEventFromWindow>();
ClassDB::register_class<InputEventKey>();
ClassDB::register_virtual_class<InputEventMouse>();
ClassDB::register_class<InputEventMouseButton>();
@@ -248,7 +249,7 @@ void register_core_singletons() {
ClassDB::register_class<_ClassDB>();
ClassDB::register_class<_Marshalls>();
ClassDB::register_class<TranslationServer>();
- ClassDB::register_virtual_class<Input>();
+ ClassDB::register_virtual_class<InputFilter>();
ClassDB::register_class<InputMap>();
ClassDB::register_class<_JSON>();
ClassDB::register_class<Expression>();
@@ -263,7 +264,7 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("ClassDB", _classdb));
Engine::get_singleton()->add_singleton(Engine::Singleton("Marshalls", _Marshalls::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("TranslationServer", TranslationServer::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("Input", InputFilter::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton()));
}
diff --git a/core/register_core_types.h b/core/register_core_types.h
index 22c0025f0c..bdd335f33c 100644
--- a/core/register_core_types.h
+++ b/core/register_core_types.h
@@ -36,4 +36,4 @@ void register_core_settings();
void register_core_singletons();
void unregister_core_types();
-#endif
+#endif // REGISTER_CORE_TYPES_H
diff --git a/core/resource.cpp b/core/resource.cpp
index 2afc9e4042..8d5c441b21 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -149,7 +149,7 @@ void Resource::reload_from_file() {
}
}
-Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache) {
+Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache) {
List<PropertyInfo> plist;
get_property_list(&plist);
@@ -190,7 +190,7 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res
return res;
}
-void Resource::configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache) {
+void Resource::configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache) {
List<PropertyInfo> plist;
get_property_list(&plist);
@@ -328,7 +328,7 @@ Node *Resource::get_local_scene() const {
return _get_local_scene_func();
}
- return NULL;
+ return nullptr;
}
void Resource::setup_local_to_scene() {
@@ -337,7 +337,7 @@ void Resource::setup_local_to_scene() {
get_script_instance()->call("_setup_local_to_scene");
}
-Node *(*Resource::_get_local_scene_func)() = NULL;
+Node *(*Resource::_get_local_scene_func)() = nullptr;
void Resource::set_as_translation_remapped(bool p_remapped) {
@@ -438,7 +438,7 @@ Resource::Resource() :
subindex = 0;
local_to_scene = false;
- local_scene = NULL;
+ local_scene = nullptr;
}
Resource::~Resource() {
@@ -455,12 +455,12 @@ Resource::~Resource() {
HashMap<String, Resource *> ResourceCache::resources;
#ifdef TOOLS_ENABLED
-HashMap<String, HashMap<String, int> > ResourceCache::resource_path_cache;
+HashMap<String, HashMap<String, int>> ResourceCache::resource_path_cache;
#endif
-RWLock *ResourceCache::lock = NULL;
+RWLock *ResourceCache::lock = nullptr;
#ifdef TOOLS_ENABLED
-RWLock *ResourceCache::path_cache_lock = NULL;
+RWLock *ResourceCache::path_cache_lock = nullptr;
#endif
void ResourceCache::setup() {
@@ -477,12 +477,15 @@ void ResourceCache::clear() {
resources.clear();
memdelete(lock);
+#ifdef TOOLS_ENABLED
+ memdelete(path_cache_lock);
+#endif
}
void ResourceCache::reload_externals() {
/*
- const String *K=NULL;
+ const String *K=nullptr;
while ((K=resources.next(K))) {
resources[*K]->reload_external_data();
}
@@ -506,16 +509,16 @@ Resource *ResourceCache::get(const String &p_path) {
lock->read_unlock();
if (!res) {
- return NULL;
+ return nullptr;
}
return *res;
}
-void ResourceCache::get_cached_resources(List<Ref<Resource> > *p_resources) {
+void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) {
lock->read_lock();
- const String *K = NULL;
+ const String *K = nullptr;
while ((K = resources.next(K))) {
Resource *r = resources[*K];
@@ -539,13 +542,13 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
Map<String, int> type_count;
- FileAccess *f = NULL;
+ FileAccess *f = nullptr;
if (p_file) {
f = FileAccess::open(p_file, FileAccess::WRITE);
ERR_FAIL_COND_MSG(!f, "Cannot create file at path '" + String(p_file) + "'.");
}
- const String *K = NULL;
+ const String *K = nullptr;
while ((K = resources.next(K))) {
Resource *r = resources[*K];
diff --git a/core/resource.h b/core/resource.h
index b30788010b..3b7812c870 100644
--- a/core/resource.h
+++ b/core/resource.h
@@ -103,8 +103,8 @@ public:
int get_subindex() const;
virtual Ref<Resource> duplicate(bool p_subresources = false) const;
- Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache);
- void configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache);
+ Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache);
+ void configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache);
void set_local_to_scene(bool p_enable);
bool is_local_to_scene() const;
@@ -150,7 +150,7 @@ class ResourceCache {
static RWLock *lock;
static HashMap<String, Resource *> resources;
#ifdef TOOLS_ENABLED
- static HashMap<String, HashMap<String, int> > resource_path_cache; // each tscn has a set of resource paths and IDs
+ static HashMap<String, HashMap<String, int>> resource_path_cache; // each tscn has a set of resource paths and IDs
static RWLock *path_cache_lock;
#endif // TOOLS_ENABLED
friend void unregister_core_types();
@@ -162,9 +162,9 @@ public:
static void reload_externals();
static bool has(const String &p_path);
static Resource *get(const String &p_path);
- static void dump(const char *p_file = NULL, bool p_short = false);
- static void get_cached_resources(List<Ref<Resource> > *p_resources);
+ static void dump(const char *p_file = nullptr, bool p_short = false);
+ static void get_cached_resources(List<Ref<Resource>> *p_resources);
static int get_cached_resource_count();
};
-#endif
+#endif // RESOURCE_H
diff --git a/core/rid.h b/core/rid.h
index 0c4a96efed..a2f73423a3 100644
--- a/core/rid.h
+++ b/core/rid.h
@@ -31,11 +31,6 @@
#ifndef RID_H
#define RID_H
-#include "core/list.h"
-#include "core/oa_hash_map.h"
-#include "core/os/memory.h"
-#include "core/safe_refcount.h"
-#include "core/set.h"
#include "core/typedefs.h"
class RID_AllocBase;
@@ -75,4 +70,4 @@ public:
}
};
-#endif
+#endif // RID_H
diff --git a/core/rid_owner.h b/core/rid_owner.h
index 5c8c48a4cb..ad6996b9a7 100644
--- a/core/rid_owner.h
+++ b/core/rid_owner.h
@@ -31,8 +31,13 @@
#ifndef RID_OWNER_H
#define RID_OWNER_H
+#include "core/list.h"
+#include "core/oa_hash_map.h"
+#include "core/os/memory.h"
#include "core/print_string.h"
#include "core/rid.h"
+#include "core/safe_refcount.h"
+#include "core/set.h"
#include "core/spin_lock.h"
#include <stdio.h>
#include <typeinfo>
@@ -142,7 +147,7 @@ public:
if (THREAD_SAFE) {
spin_lock.unlock();
}
- return NULL;
+ return nullptr;
}
uint32_t idx_chunk = idx / elements_in_chunk;
@@ -153,7 +158,7 @@ public:
if (THREAD_SAFE) {
spin_lock.unlock();
}
- return NULL;
+ return nullptr;
}
T *ptr = &chunks[idx_chunk][idx_element];
@@ -236,7 +241,7 @@ public:
}
_FORCE_INLINE_ T *get_ptr_by_index(uint32_t p_index) {
- ERR_FAIL_INDEX_V(p_index, alloc_count, NULL);
+ ERR_FAIL_INDEX_V(p_index, alloc_count, nullptr);
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -283,14 +288,14 @@ public:
}
RID_Alloc(uint32_t p_target_chunk_byte_size = 4096) {
- chunks = NULL;
- free_list_chunks = NULL;
- validator_chunks = NULL;
+ chunks = nullptr;
+ free_list_chunks = nullptr;
+ validator_chunks = nullptr;
elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T));
max_alloc = 0;
alloc_count = 0;
- description = NULL;
+ description = nullptr;
}
~RID_Alloc() {
@@ -340,7 +345,7 @@ public:
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
T **ptr = alloc.getornull(p_rid);
if (unlikely(!ptr)) {
- return NULL;
+ return nullptr;
}
return *ptr;
}
diff --git a/core/ring_buffer.h b/core/ring_buffer.h
index f5f43607fe..620a3a3846 100644
--- a/core/ring_buffer.h
+++ b/core/ring_buffer.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RINGBUFFER_H
-#define RINGBUFFER_H
+#ifndef RING_BUFFER_H
+#define RING_BUFFER_H
#include "core/vector.h"
@@ -221,4 +221,4 @@ public:
~RingBuffer<T>(){};
};
-#endif
+#endif // RING_BUFFER_H
diff --git a/core/safe_refcount.h b/core/safe_refcount.h
index 887282f556..953a877397 100644
--- a/core/safe_refcount.h
+++ b/core/safe_refcount.h
@@ -208,4 +208,4 @@ public:
}
};
-#endif
+#endif // SAFE_REFCOUNT_H
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 428f363b17..82cac6bc9a 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -42,7 +42,7 @@ int ScriptServer::_language_count = 0;
bool ScriptServer::scripting_enabled = true;
bool ScriptServer::reload_scripts_on_save = false;
bool ScriptServer::languages_finished = false;
-ScriptEditRequestFunction ScriptServer::edit_request_func = NULL;
+ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr;
void Script::_notification(int p_what) {
@@ -136,7 +136,7 @@ bool ScriptServer::is_scripting_enabled() {
ScriptLanguage *ScriptServer::get_language(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, _language_count, NULL);
+ ERR_FAIL_INDEX_V(p_idx, _language_count, nullptr);
return _languages[p_idx];
}
@@ -256,7 +256,7 @@ StringName ScriptServer::get_global_class_native_base(const String &p_class) {
return base;
}
void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
- const StringName *K = NULL;
+ const StringName *K = nullptr;
List<StringName> classes;
while ((K = global_classes.next(K))) {
classes.push_back(*K);
@@ -284,7 +284,7 @@ void ScriptServer::save_global_classes() {
}
////////////////////
-void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) {
+void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) {
List<PropertyInfo> pinfo;
get_property_list(&pinfo);
@@ -350,7 +350,7 @@ void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DEC
ScriptInstance::~ScriptInstance() {
}
-ScriptCodeCompletionCache *ScriptCodeCompletionCache::singleton = NULL;
+ScriptCodeCompletionCache *ScriptCodeCompletionCache::singleton = nullptr;
ScriptCodeCompletionCache::ScriptCodeCompletionCache() {
singleton = this;
}
diff --git a/core/script_language.h b/core/script_language.h
index f1b809425b..2d86c5166d 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -137,7 +137,7 @@ public:
virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so
virtual ScriptInstance *instance_create(Object *p_this) = 0;
- virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) { return NULL; }
+ virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) { return nullptr; }
virtual bool instance_has(const Object *p_this) const = 0;
virtual bool has_source_code() const = 0;
@@ -189,10 +189,10 @@ public:
virtual bool set(const StringName &p_name, const Variant &p_value) = 0;
virtual bool get(const StringName &p_name, Variant &r_ret) const = 0;
virtual void get_property_list(List<PropertyInfo> *p_properties) const = 0;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const = 0;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const = 0;
- virtual Object *get_owner() { return NULL; }
- virtual void get_property_state(List<Pair<StringName, Variant> > &state);
+ virtual Object *get_owner() { return nullptr; }
+ virtual void get_property_state(List<Pair<StringName, Variant>> &state);
virtual void get_method_list(List<MethodInfo> *p_list) const = 0;
virtual bool has_method(const StringName &p_method) const = 0;
@@ -306,7 +306,7 @@ public:
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {}
virtual bool is_using_templates() { return false; }
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const = 0;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
virtual Script *create_script() const = 0;
virtual bool has_named_classes() const = 0;
@@ -363,7 +363,7 @@ public:
virtual String debug_get_stack_level_source(int p_level) const = 0;
virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
- virtual ScriptInstance *debug_get_stack_level_instance(int p_level) { return NULL; }
+ virtual ScriptInstance *debug_get_stack_level_instance(int p_level) { return nullptr; }
virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0;
virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) = 0;
@@ -375,7 +375,7 @@ public:
virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
virtual void get_public_functions(List<MethodInfo> *p_functions) const = 0;
- virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const = 0;
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const = 0;
struct ProfilingInfo {
StringName signature;
@@ -390,7 +390,7 @@ public:
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) = 0;
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) = 0;
- virtual void *alloc_instance_binding_data(Object *p_object) { return NULL; } //optional, not used by all languages
+ virtual void *alloc_instance_binding_data(Object *p_object) { return nullptr; } //optional, not used by all languages
virtual void free_instance_binding_data(void *p_data) {} //optional, not used by all languages
virtual void refcount_incremented_instance_binding(Object *p_object) {} //optional, not used by all languages
virtual bool refcount_decremented_instance_binding(Object *p_object) { return true; } //return true if it can die //optional, not used by all languages
@@ -398,7 +398,7 @@ public:
virtual void frame();
virtual bool handles_global_class_type(const String &p_type) const { return false; }
- virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const { return String(); }
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const { return String(); }
virtual ~ScriptLanguage() {}
};
@@ -418,7 +418,7 @@ public:
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
@@ -441,8 +441,8 @@ public:
virtual bool is_placeholder() const { return true; }
- virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL);
- virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = NULL);
+ virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr);
+ virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr);
virtual Vector<ScriptNetData> get_rpc_methods() const { return Vector<ScriptNetData>(); }
virtual uint16_t get_rpc_method_id(const StringName &p_method) const;
@@ -459,4 +459,5 @@ public:
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
~PlaceHolderScriptInstance();
};
-#endif
+
+#endif // SCRIPT_LANGUAGE_H
diff --git a/core/self_list.h b/core/self_list.h
index 1cd7bb44d8..19d2783208 100644
--- a/core/self_list.h
+++ b/core/self_list.h
@@ -49,7 +49,7 @@ public:
p_elem->_root = this;
p_elem->_next = _first;
- p_elem->_prev = NULL;
+ p_elem->_prev = nullptr;
if (_first) {
_first->_prev = p_elem;
@@ -66,7 +66,7 @@ public:
ERR_FAIL_COND(p_elem->_root);
p_elem->_root = this;
- p_elem->_next = NULL;
+ p_elem->_next = nullptr;
p_elem->_prev = _last;
if (_last) {
@@ -98,18 +98,18 @@ public:
_last = p_elem->_prev;
}
- p_elem->_next = NULL;
- p_elem->_prev = NULL;
- p_elem->_root = NULL;
+ p_elem->_next = nullptr;
+ p_elem->_prev = nullptr;
+ p_elem->_root = nullptr;
}
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
_FORCE_INLINE_ List() {
- _first = NULL;
- _last = NULL;
+ _first = nullptr;
+ _last = nullptr;
}
- _FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != NULL); }
+ _FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
};
private:
@@ -129,9 +129,9 @@ public:
_FORCE_INLINE_ SelfList(T *p_self) {
_self = p_self;
- _next = NULL;
- _prev = NULL;
- _root = NULL;
+ _next = nullptr;
+ _prev = nullptr;
+ _root = nullptr;
}
_FORCE_INLINE_ ~SelfList() {
diff --git a/core/set.h b/core/set.h
index aee3f4bc7a..c17ee15350 100644
--- a/core/set.h
+++ b/core/set.h
@@ -82,11 +82,11 @@ public:
};
Element() {
color = RED;
- right = NULL;
- left = NULL;
- parent = NULL;
- _next = NULL;
- _prev = NULL;
+ right = nullptr;
+ left = nullptr;
+ parent = nullptr;
+ _next = nullptr;
+ _prev = nullptr;
};
};
@@ -105,7 +105,7 @@ private:
#else
_nil = (Element *)&_GlobalNilClass::_nil;
#endif
- _root = NULL;
+ _root = nullptr;
size_cache = 0;
}
@@ -120,7 +120,7 @@ private:
if (_root) {
memdelete_allocator<Element, A>(_root);
- _root = NULL;
+ _root = nullptr;
}
}
@@ -192,7 +192,7 @@ private:
}
if (node->parent == _data._root)
- return NULL; // No successor, as p_node = last node
+ return nullptr; // No successor, as p_node = last node
return node->parent;
}
}
@@ -214,7 +214,7 @@ private:
}
if (node == _data._root)
- return NULL; // No predecessor, as p_node = first node.
+ return nullptr; // No predecessor, as p_node = first node.
return node->parent;
}
}
@@ -233,13 +233,13 @@ private:
return node; // found
}
- return NULL;
+ return nullptr;
}
Element *_lower_bound(const T &p_value) const {
Element *node = _data._root->left;
- Element *prev = NULL;
+ Element *prev = nullptr;
C less;
while (node != _data._nil) {
@@ -253,8 +253,8 @@ private:
return node; // found
}
- if (prev == NULL)
- return NULL; // tree empty
+ if (prev == nullptr)
+ return nullptr; // tree empty
if (less(prev->value, p_value))
prev = prev->_next;
@@ -504,7 +504,7 @@ public:
const Element *find(const T &p_value) const {
if (!_data._root)
- return NULL;
+ return nullptr;
const Element *res = _find(p_value);
return res;
@@ -513,7 +513,7 @@ public:
Element *find(const T &p_value) {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *res = _find(p_value);
return res;
@@ -526,7 +526,7 @@ public:
bool has(const T &p_value) const {
- return find(p_value) != NULL;
+ return find(p_value) != nullptr;
}
Element *insert(const T &p_value) {
@@ -564,11 +564,11 @@ public:
Element *front() const {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *e = _data._root->left;
if (e == _data._nil)
- return NULL;
+ return nullptr;
while (e->left != _data._nil)
e = e->left;
@@ -579,11 +579,11 @@ public:
Element *back() const {
if (!_data._root)
- return NULL;
+ return nullptr;
Element *e = _data._root->left;
if (e == _data._nil)
- return NULL;
+ return nullptr;
while (e->right != _data._nil)
e = e->right;
@@ -634,4 +634,4 @@ public:
}
};
-#endif
+#endif // SET_H
diff --git a/core/simple_type.h b/core/simple_type.h
index f637504db8..da031854c6 100644
--- a/core/simple_type.h
+++ b/core/simple_type.h
@@ -51,4 +51,4 @@ struct GetSimpleTypeT<T const> {
typedef T type_t;
};
-#endif
+#endif // SIMPLE_TYPE_H
diff --git a/core/string_buffer.h b/core/string_buffer.h
index d80a975c7f..a140f0abf7 100644
--- a/core/string_buffer.h
+++ b/core/string_buffer.h
@@ -163,4 +163,4 @@ int64_t StringBuffer<SHORT_BUFFER_SIZE>::as_int() {
return String::to_int(current_buffer_ptr());
}
-#endif
+#endif // STRING_BUFFER_H
diff --git a/core/string_name.cpp b/core/string_name.cpp
index 4ec9af008e..9cbac97a7c 100644
--- a/core/string_name.cpp
+++ b/core/string_name.cpp
@@ -54,7 +54,7 @@ void StringName::setup() {
ERR_FAIL_COND(configured);
for (int i = 0; i < STRING_TABLE_LEN; i++) {
- _table[i] = NULL;
+ _table[i] = nullptr;
}
configured = true;
}
@@ -110,7 +110,7 @@ void StringName::unref() {
memdelete(_data);
}
- _data = NULL;
+ _data = nullptr;
}
bool StringName::operator==(const String &p_name) const {
@@ -160,7 +160,7 @@ void StringName::operator=(const StringName &p_name) {
StringName::StringName(const StringName &p_name) {
- _data = NULL;
+ _data = nullptr;
ERR_FAIL_COND(!configured);
@@ -171,7 +171,7 @@ StringName::StringName(const StringName &p_name) {
StringName::StringName(const char *p_name) {
- _data = NULL;
+ _data = nullptr;
ERR_FAIL_COND(!configured);
@@ -206,9 +206,9 @@ StringName::StringName(const char *p_name) {
_data->refcount.init();
_data->hash = hash;
_data->idx = idx;
- _data->cname = NULL;
+ _data->cname = nullptr;
_data->next = _table[idx];
- _data->prev = NULL;
+ _data->prev = nullptr;
if (_table[idx])
_table[idx]->prev = _data;
_table[idx] = _data;
@@ -216,7 +216,7 @@ StringName::StringName(const char *p_name) {
StringName::StringName(const StaticCString &p_static_string) {
- _data = NULL;
+ _data = nullptr;
ERR_FAIL_COND(!configured);
@@ -252,7 +252,7 @@ StringName::StringName(const StaticCString &p_static_string) {
_data->idx = idx;
_data->cname = p_static_string.ptr;
_data->next = _table[idx];
- _data->prev = NULL;
+ _data->prev = nullptr;
if (_table[idx])
_table[idx]->prev = _data;
_table[idx] = _data;
@@ -260,7 +260,7 @@ StringName::StringName(const StaticCString &p_static_string) {
StringName::StringName(const String &p_name) {
- _data = NULL;
+ _data = nullptr;
ERR_FAIL_COND(!configured);
@@ -293,9 +293,9 @@ StringName::StringName(const String &p_name) {
_data->refcount.init();
_data->hash = hash;
_data->idx = idx;
- _data->cname = NULL;
+ _data->cname = nullptr;
_data->next = _table[idx];
- _data->prev = NULL;
+ _data->prev = nullptr;
if (_table[idx])
_table[idx]->prev = _data;
_table[idx] = _data;
@@ -390,7 +390,7 @@ StringName StringName::search(const String &p_name) {
StringName::StringName() {
- _data = NULL;
+ _data = nullptr;
}
StringName::~StringName() {
diff --git a/core/string_name.h b/core/string_name.h
index e68ab8bfa3..aec87b8e66 100644
--- a/core/string_name.h
+++ b/core/string_name.h
@@ -61,8 +61,8 @@ class StringName {
_Data *prev;
_Data *next;
_Data() {
- cname = NULL;
- next = prev = NULL;
+ cname = nullptr;
+ next = prev = nullptr;
idx = 0;
hash = 0;
}
diff --git a/core/translation.cpp b/core/translation.cpp
index 17c23b86cd..3f45bb17c9 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -407,7 +407,7 @@ static const char *locale_list[] = {
"zh_SG", // Chinese (Singapore)
"zh_TW", // Chinese (Taiwan)
"zu_ZA", // Zulu (South Africa)
- 0
+ nullptr
};
static const char *locale_names[] = {
@@ -775,7 +775,7 @@ static const char *locale_names[] = {
"Chinese (Singapore)",
"Chinese (Taiwan)",
"Zulu (South Africa)",
- 0
+ nullptr
};
// Windows has some weird locale identifiers which do not honor the ISO 639-1
@@ -789,7 +789,7 @@ static const char *locale_renames[][2] = {
{ "in", "id" }, // Indonesian
{ "iw", "he" }, // Hebrew
{ "no", "nb" }, // Norwegian Bokmål
- { NULL, NULL }
+ { nullptr, nullptr }
};
///////////////////////////////////////////////
@@ -929,7 +929,7 @@ String TranslationServer::standardize_locale(const String &p_locale) {
// Handles known non-ISO locale names used e.g. on Windows
int idx = 0;
- while (locale_renames[idx][0] != NULL) {
+ while (locale_renames[idx][0] != nullptr) {
if (locale_renames[idx][0] == univ_locale) {
univ_locale = locale_renames[idx][1];
break;
@@ -995,7 +995,7 @@ String TranslationServer::get_locale_name(const String &p_locale) const {
Array TranslationServer::get_loaded_locales() const {
Array locales;
- for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
+ for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
const Ref<Translation> &t = E->get();
ERR_FAIL_COND_V(t.is_null(), Array());
@@ -1072,7 +1072,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
String lang = get_language_code(locale);
bool near_match = false;
- for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
+ for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
const Ref<Translation> &t = E->get();
ERR_FAIL_COND_V(t.is_null(), p_message);
String l = t->get_locale();
@@ -1105,7 +1105,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
String fallback_lang = get_language_code(fallback);
near_match = false;
- for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
+ for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
const Ref<Translation> &t = E->get();
ERR_FAIL_COND_V(t.is_null(), p_message);
String l = t->get_locale();
@@ -1141,7 +1141,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
return res;
}
-TranslationServer *TranslationServer::singleton = NULL;
+TranslationServer *TranslationServer::singleton = nullptr;
bool TranslationServer::_load_translations(const String &p_from) {
@@ -1176,7 +1176,6 @@ void TranslationServer::setup() {
set_locale(OS::get_singleton()->get_locale());
fallback = GLOBAL_DEF("locale/fallback", "en");
#ifdef TOOLS_ENABLED
-
{
String options = "";
int idx = 0;
@@ -1189,7 +1188,6 @@ void TranslationServer::setup() {
ProjectSettings::get_singleton()->set_custom_property_info("locale/fallback", PropertyInfo(Variant::STRING, "locale/fallback", PROPERTY_HINT_ENUM, options));
}
#endif
- //load translations
}
void TranslationServer::set_tool_translation(const Ref<Translation> &p_translation) {
@@ -1197,15 +1195,26 @@ void TranslationServer::set_tool_translation(const Ref<Translation> &p_translati
}
StringName TranslationServer::tool_translate(const StringName &p_message) const {
-
if (tool_translation.is_valid()) {
StringName r = tool_translation->get_message(p_message);
-
if (r) {
return r;
}
}
+ return p_message;
+}
+void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) {
+ doc_translation = p_translation;
+}
+
+StringName TranslationServer::doc_translate(const StringName &p_message) const {
+ if (doc_translation.is_valid()) {
+ StringName r = doc_translation->get_message(p_message);
+ if (r) {
+ return r;
+ }
+ }
return p_message;
}
diff --git a/core/translation.h b/core/translation.h
index 0448ea56c5..29a068f450 100644
--- a/core/translation.h
+++ b/core/translation.h
@@ -71,8 +71,9 @@ class TranslationServer : public Object {
String locale;
String fallback;
- Set<Ref<Translation> > translations;
+ Set<Ref<Translation>> translations;
Ref<Translation> tool_translation;
+ Ref<Translation> doc_translation;
Map<String, String> locale_name_map;
@@ -109,6 +110,8 @@ public:
void set_tool_translation(const Ref<Translation> &p_translation);
StringName tool_translate(const StringName &p_message) const;
+ void set_doc_translation(const Ref<Translation> &p_translation);
+ StringName doc_translate(const StringName &p_message) const;
void setup();
diff --git a/core/type_info.h b/core/type_info.h
index 5dacf67de4..816d0d9381 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GET_TYPE_INFO_H
-#define GET_TYPE_INFO_H
+#ifndef TYPE_INFO_H
+#define TYPE_INFO_H
#ifdef DEBUG_METHODS_ENABLED
@@ -144,6 +144,9 @@ MAKE_TYPE_INFO(String, Variant::STRING)
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
MAKE_TYPE_INFO(Rect2, Variant::RECT2)
MAKE_TYPE_INFO(Vector3, Variant::VECTOR3)
+MAKE_TYPE_INFO(Vector2i, Variant::VECTOR2I)
+MAKE_TYPE_INFO(Rect2i, Variant::RECT2I)
+MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPE_INFO(Plane, Variant::PLANE)
MAKE_TYPE_INFO(Quat, Variant::QUAT)
@@ -174,7 +177,7 @@ MAKE_TYPE_INFO(IP_Address, Variant::STRING)
template <>
struct GetTypeInfo<ObjectID> {
static const Variant::Type VARIANT_TYPE = Variant::INT;
- static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_INT_IS_UINT64;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_OBJECTID);
}
@@ -201,7 +204,7 @@ struct GetTypeInfo<const Variant &> {
#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
template <> \
- struct GetTypeInfo<m_template<m_type> > { \
+ struct GetTypeInfo<m_template<m_type>> { \
static const Variant::Type VARIANT_TYPE = m_var_type; \
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
@@ -273,4 +276,4 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) {
#endif // DEBUG_METHODS_ENABLED
-#endif // GET_TYPE_INFO_H
+#endif // TYPE_INFO_H
diff --git a/core/typedefs.h b/core/typedefs.h
index 5376b0718a..bafbffcded 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -37,60 +37,41 @@
* Basic definitions and simple functions to be used everywhere.
*/
+// Include first in case the platform needs to pre-define/include some things.
#include "platform_config.h"
+// Should be available everywhere.
+#include "core/error_list.h"
+#include "core/int_types.h"
+
+// Turn argument to string constant:
+// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
#ifndef _STR
#define _STR(m_x) #m_x
#define _MKSTR(m_x) _STR(m_x)
#endif
-//should always inline no matter what
+// Should always inline no matter what.
#ifndef _ALWAYS_INLINE_
-
-#if defined(__GNUC__) && (__GNUC__ >= 4)
-#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
-#elif defined(__llvm__)
+#if defined(__GNUC__)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define _ALWAYS_INLINE_ __forceinline
#else
#define _ALWAYS_INLINE_ inline
#endif
-
#endif
-//should always inline, except in some cases because it makes debugging harder
+// Should always inline, except in debug builds because it makes debugging harder.
#ifndef _FORCE_INLINE_
-
#ifdef DISABLE_FORCED_INLINE
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
-
#endif
-//custom, gcc-safe offsetof, because gcc complains a lot.
-template <class T>
-T *_nullptr() {
- T *t = NULL;
- return t;
-}
-
-#define OFFSET_OF(st, m) \
- ((size_t)((char *)&(_nullptr<st>()->m) - (char *)0))
-/**
- * Some platforms (devices) don't define NULL
- */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/**
- * Windows badly defines a lot of stuff we'll never use. Undefine it.
- */
-
+// Windows badly defines a lot of stuff we'll never use. Undefine it.
#ifdef _WIN32
#undef min // override standard definition
#undef max // override standard definition
@@ -105,18 +86,11 @@ T *_nullptr() {
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
-#include "core/int_types.h"
-
-#include "core/error_list.h"
-
-/** Generic ABS function, for math uses please use Math::abs */
-
+// Generic ABS function, for math uses please use Math::abs.
#ifndef ABS
#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
#endif
-#define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
-
#ifndef SGN
#define SGN(m_v) (((m_v) < 0) ? (-1.0) : (+1.0))
#endif
@@ -133,49 +107,24 @@ T *_nullptr() {
#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
#endif
-/** Generic swap template */
+// Generic swap template.
#ifndef SWAP
-
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
-
T aux = x;
x = y;
y = aux;
}
+#endif // SWAP
-#endif //swap
-
-/* clang-format off */
-#define HEX2CHR(m_hex) \
- ((m_hex >= '0' && m_hex <= '9') ? (m_hex - '0') : \
- ((m_hex >= 'A' && m_hex <= 'F') ? (10 + m_hex - 'A') : \
- ((m_hex >= 'a' && m_hex <= 'f') ? (10 + m_hex - 'a') : 0)))
-/* clang-format on */
-
-// Macro to check whether we are compiled by clang
-// and we have a specific builtin
-#if defined(__llvm__) && defined(__has_builtin)
-#define _llvm_has_builtin(x) __has_builtin(x)
-#else
-#define _llvm_has_builtin(x) 0
-#endif
-
-#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_mul_overflow)
-#define _mul_overflow __builtin_mul_overflow
-#endif
-
-#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_add_overflow)
-#define _add_overflow __builtin_add_overflow
-#endif
-
-/** Function to find the next power of 2 to an integer */
+/* Functions to handle powers of 2 and shifting. */
+// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
-
- if (x == 0)
+ if (x == 0) {
return 0;
+ }
--x;
x |= x >> 1;
@@ -187,8 +136,8 @@ static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
return ++x;
}
+// Function to find the previous power of 2 to an integer.
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
-
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
@@ -197,40 +146,45 @@ static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
return x - (x >> 1);
}
+// Function to find the closest power of 2 to an integer.
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
-
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
-// We need this definition inside the function below.
-static inline int get_shift_from_power_of_2(unsigned int p_pixel);
+// Get a shift value from a power of 2.
+static inline int get_shift_from_power_of_2(unsigned int p_bits) {
+ for (unsigned int i = 0; i < 32; i++) {
+ if (p_bits == (unsigned int)(1 << i)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
-
--x;
// The number of operations on x is the base two logarithm
- // of the p_number of bits in the type. Add three to account
+ // of the number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
- // If the compiler is smart, it unrolls this loop
- // If its dumb, this is a bit slow.
- for (size_t i = 0; i < num; i++)
+ // If the compiler is smart, it unrolls this loop.
+ // If it's dumb, this is a bit slow.
+ for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
+ }
return ++x;
}
-/** Function to find the nearest (bigger) power of 2 to an integer */
-
+// Function to find the nearest (bigger) power of 2 to an integer.
static inline unsigned int nearest_shift(unsigned int p_number) {
-
for (int i = 30; i >= 0; i--) {
-
if (p_number & (1 << i))
return i + 1;
}
@@ -238,41 +192,20 @@ static inline unsigned int nearest_shift(unsigned int p_number) {
return 0;
}
-/** get a shift value from a power of 2 */
-static inline int get_shift_from_power_of_2(unsigned int p_pixel) {
- // return a GL_TEXTURE_SIZE_ENUM
-
- for (unsigned int i = 0; i < 32; i++) {
-
- if (p_pixel == (unsigned int)(1 << i))
- return i;
- }
-
- return -1;
-}
-
-/** Swap 16 bits value for endianness */
-#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap16)
+// Swap 16, 32 and 64 bits value for endianness.
+#if defined(__GNUC__)
#define BSWAP16(x) __builtin_bswap16(x)
+#define BSWAP32(x) __builtin_bswap32(x)
+#define BSWAP64(x) __builtin_bswap64(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
-#endif
-/** Swap 32 bits value for endianness */
-#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap32)
-#define BSWAP32(x) __builtin_bswap32(x)
-#else
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
-#endif
-/** Swap 64 bits value for endianness */
-#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap64)
-#define BSWAP64(x) __builtin_bswap64(x)
-#else
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
@@ -281,40 +214,24 @@ static inline uint64_t BSWAP64(uint64_t x) {
}
#endif
-/** When compiling with RTTI, we can add an "extra"
- * layer of safeness in many operations, so dynamic_cast
- * is used besides casting by enum.
- */
-
+// Generic comparator used in Map, List, etc.
template <class T>
struct Comparator {
-
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
+// Global lock macro, relies on the static Mutex::_global_mutex.
void _global_lock();
void _global_unlock();
struct _GlobalLock {
-
_GlobalLock() { _global_lock(); }
~_GlobalLock() { _global_unlock(); }
};
#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_;
-#ifdef NO_SAFE_CAST
-#define SAFE_CAST static_cast
-#else
-#define SAFE_CAST dynamic_cast
-#endif
-
-#define MT_SAFE
-
-#define __STRX(m_index) #m_index
-#define __STR(m_index) __STRX(m_index)
-
-#ifdef __GNUC__
+#if defined(__GNUC__)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
@@ -330,14 +247,12 @@ struct _GlobalLock {
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
#endif
-/** This is needed due to a strange OpenGL API that expects a pointer
- * type for an argument that is actually an offset.
- */
+// This is needed due to a strange OpenGL API that expects a pointer
+// type for an argument that is actually an offset.
#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
// Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple.
// https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion
-
template <size_t... Is>
struct IndexSequence {};
diff --git a/core/ucaps.h b/core/ucaps.h
index 013f264d2f..ad71731617 100644
--- a/core/ucaps.h
+++ b/core/ucaps.h
@@ -1413,4 +1413,5 @@ static int _find_lower(int ch) {
return ch;
}
-#endif
+
+#endif // UCAPS_H
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index 02f460c93d..62ad3e9f98 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -108,7 +108,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
@@ -128,7 +128,7 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA
void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
VARIANT_ARGPTRS
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -151,7 +151,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
}
void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
@@ -166,7 +166,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
}
void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -186,7 +186,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
}
void UndoRedo::add_do_reference(Object *p_object) {
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
@@ -199,7 +199,7 @@ void UndoRedo::add_do_reference(Object *p_object) {
}
void UndoRedo::add_undo_reference(Object *p_object) {
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -417,13 +417,13 @@ UndoRedo::UndoRedo() {
current_action = -1;
merge_mode = MERGE_DISABLE;
merging = false;
- callback = NULL;
- callback_ud = NULL;
+ callback = nullptr;
+ callback_ud = nullptr;
- method_callbck_ud = NULL;
- prop_callback_ud = NULL;
- method_callback = NULL;
- property_callback = NULL;
+ method_callbck_ud = nullptr;
+ prop_callback_ud = nullptr;
+ method_callback = nullptr;
+ property_callback = nullptr;
}
UndoRedo::~UndoRedo() {
@@ -511,8 +511,7 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action);
- // FIXME: Typo in "commiting", fix in 4.0 when breaking compat.
- ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_committing_action);
+ ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
{
MethodInfo mi;
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 1d4d9c2dfd..fbe3fcb1b2 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -205,7 +205,7 @@ void String::copy_from(const CharType *p_cstr, const int p_clip_to) {
}
// assumes the following have already been validated:
-// p_char != NULL
+// p_char != nullptr
// p_length > 0
// p_length <= p_char strlen
void String::copy_from_unchecked(const CharType *p_char, const int p_length) {
@@ -647,13 +647,13 @@ String String::camelcase_to_underscore(bool lowercase) const {
}
String String::get_with_code_lines() const {
- Vector<String> lines = split("\n");
+ const Vector<String> lines = split("\n");
String ret;
for (int i = 0; i < lines.size(); i++) {
if (i > 0) {
ret += "\n";
}
- ret += itos(i + 1) + " " + lines[i];
+ ret += vformat("%4d | %s", i + 1, lines[i]);
}
return ret;
}
@@ -1402,7 +1402,7 @@ String String::utf8(const char *p_utf8, int p_len) {
bool String::parse_utf8(const char *p_utf8, int p_len) {
-#define _UNICERROR(m_err) print_line("Unicode error: " + String(m_err));
+#define _UNICERROR(m_err) print_line("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?");
if (!p_utf8)
return true;
@@ -1640,7 +1640,7 @@ CharString String::utf8() const {
/*
String::String(CharType p_char) {
- shared=NULL;
+ shared=nullptr;
copy_from(p_char);
}
*/
@@ -1913,7 +1913,7 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
* necessary unless F is present. The "E" may
* actually be an "e". E and X may both be
* omitted (but not just one). */
- C **endPtr = NULL) /* If non-NULL, store terminating Cacter's
+ C **endPtr = nullptr) /* If non-nullptr, store terminating Cacter's
* address here. */
{
@@ -2101,7 +2101,7 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
done:
- if (endPtr != NULL) {
+ if (endPtr != nullptr) {
*endPtr = (C *)p;
}
@@ -2202,7 +2202,7 @@ double String::to_double() const {
return 0;
#ifndef NO_USE_STDLIB
return built_in_strtod<CharType>(c_str());
-//return wcstod(c_str(),NULL); DOES NOT WORK ON ANDROID :(
+//return wcstod(c_str(),nullptr ); DOES NOT WORK ON ANDROID :(
#else
return built_in_strtod<CharType>(c_str());
#endif
@@ -3449,7 +3449,7 @@ String String::http_unescape() const {
CharType ord2 = ord_at(i + 2);
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 };
- res += (char)strtol(bytes, NULL, 16);
+ res += (char)strtol(bytes, nullptr, 16);
i += 2;
}
} else {
@@ -3633,7 +3633,7 @@ String String::xml_unescape() const {
String str;
int l = length();
- int len = _xml_unescape(c_str(), l, NULL);
+ int len = _xml_unescape(c_str(), l, nullptr);
if (len == 0)
return String();
str.resize(len + 1);
@@ -4412,7 +4412,6 @@ String String::unquote() const {
#ifdef TOOLS_ENABLED
String TTR(const String &p_text) {
-
if (TranslationServer::get_singleton()) {
return TranslationServer::get_singleton()->tool_translate(p_text);
}
@@ -4420,10 +4419,18 @@ String TTR(const String &p_text) {
return p_text;
}
+String DTR(const String &p_text) {
+ if (TranslationServer::get_singleton()) {
+ // Comes straight from the XML, so remove indentation and any trailing whitespace.
+ const String text = p_text.dedent().strip_edges();
+ return TranslationServer::get_singleton()->doc_translate(text);
+ }
+
+ return p_text;
+}
#endif
String RTR(const String &p_text) {
-
if (TranslationServer::get_singleton()) {
String rtr = TranslationServer::get_singleton()->tool_translate(p_text);
if (rtr == String() || rtr == p_text) {
diff --git a/core/ustring.h b/core/ustring.h
index e70b2bfe27..ee7e3b1e16 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -117,7 +117,7 @@ struct StrRange {
const CharType *c_str;
int len;
- StrRange(const CharType *p_c_str = NULL, int p_len = 0) {
+ StrRange(const CharType *p_c_str = nullptr, int p_len = 0) {
c_str = p_c_str;
len = p_len;
}
@@ -206,7 +206,7 @@ public:
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
- int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = NULL) const; ///< return <0 if failed
+ int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = nullptr) const; ///< return <0 if failed
bool match(const String &p_wildcard) const;
bool matchn(const String &p_wildcard) const;
bool begins_with(const String &p_string) const;
@@ -253,7 +253,7 @@ public:
int64_t to_int64() const;
static int to_int(const char *p_str, int p_len = -1);
static double to_double(const char *p_str);
- static double to_double(const CharType *p_str, const CharType **r_end = NULL);
+ static double to_double(const CharType *p_str, const CharType **r_end = nullptr);
static int64_t to_int(const CharType *p_str, int p_len = -1);
String capitalize() const;
String camelcase_to_underscore(bool lowercase = true) const;
@@ -415,25 +415,25 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
/* end of namespace */
-//tool translate
+// Tool translate (TTR and variants) for the editor UI,
+// and doc translate for the class reference (DTR).
#ifdef TOOLS_ENABLED
-
-//gets parsed
+// Gets parsed.
String TTR(const String &);
-//use for C strings
+String DTR(const String &);
+// Use for C strings.
#define TTRC(m_value) (m_value)
-//use to avoid parsing (for use later with C strings)
+// Use to avoid parsing (for use later with C strings).
#define TTRGET(m_value) TTR(m_value)
#else
-
#define TTR(m_value) (String())
+#define DTR(m_value) (String())
#define TTRC(m_value) (m_value)
#define TTRGET(m_value) (m_value)
-
#endif
-//tool or regular translate
+// Runtime translate for the public node API.
String RTR(const String &);
bool is_symbol(CharType c);
diff --git a/core/variant.cpp b/core/variant.cpp
index b82602a5a4..b3611536b8 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -233,8 +233,8 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
return (p_type_to == OBJECT);
};
- const Type *valid_types = NULL;
- const Type *invalid_types = NULL;
+ const Type *valid_types = nullptr;
+ const Type *invalid_types = nullptr;
switch (p_type_to) {
case BOOL: {
@@ -570,7 +570,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
return (p_type_to == OBJECT);
};
- const Type *valid_types = NULL;
+ const Type *valid_types = nullptr;
switch (p_type_to) {
case BOOL: {
@@ -1020,7 +1020,7 @@ bool Variant::is_zero() const {
} break;
case OBJECT: {
- return _get_obj().obj == NULL;
+ return _get_obj().obj == nullptr;
} break;
case CALLABLE: {
@@ -1479,7 +1479,7 @@ void Variant::clear() {
memdelete(reference);
}
}
- _get_obj().obj = NULL;
+ _get_obj().obj = nullptr;
_get_obj().id = ObjectID();
} break;
case _RID: {
@@ -1864,7 +1864,7 @@ String Variant::stringify(List<const void *> &stack) const {
stack.push_back(d.id());
- //const String *K=NULL;
+ //const String *K=nullptr;
String str("{");
List<Variant> keys;
d.get_key_list(&keys);
@@ -2227,7 +2227,7 @@ Variant::operator RID() const {
};
#endif
Callable::CallError ce;
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, NULL, 0, ce);
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::_RID) {
return ret;
}
@@ -2242,7 +2242,7 @@ Variant::operator Object *() const {
if (type == OBJECT)
return _get_obj().obj;
else
- return NULL;
+ return nullptr;
}
Object *Variant::get_validated_object_with_check(bool &r_previously_freed) const {
@@ -2252,7 +2252,7 @@ Object *Variant::get_validated_object_with_check(bool &r_previously_freed) const
return instance;
} else {
r_previously_freed = false;
- return NULL;
+ return nullptr;
}
}
@@ -2260,7 +2260,7 @@ Object *Variant::get_validated_object() const {
if (type == OBJECT)
return ObjectDB::get_instance(_get_obj().id);
else
- return NULL;
+ return nullptr;
}
Variant::operator Node *() const {
@@ -2268,14 +2268,14 @@ Variant::operator Node *() const {
if (type == OBJECT)
return Object::cast_to<Node>(_get_obj().obj);
else
- return NULL;
+ return nullptr;
}
Variant::operator Control *() const {
if (type == OBJECT)
return Object::cast_to<Control>(_get_obj().obj);
else
- return NULL;
+ return nullptr;
}
Variant::operator Dictionary() const {
@@ -2325,31 +2325,31 @@ inline DA _convert_array_from_variant(const Variant &p_variant) {
return _convert_array<DA, Array>(p_variant.operator Array());
}
case Variant::PACKED_BYTE_ARRAY: {
- return _convert_array<DA, Vector<uint8_t> >(p_variant.operator Vector<uint8_t>());
+ return _convert_array<DA, Vector<uint8_t>>(p_variant.operator Vector<uint8_t>());
}
case Variant::PACKED_INT32_ARRAY: {
- return _convert_array<DA, Vector<int32_t> >(p_variant.operator Vector<int32_t>());
+ return _convert_array<DA, Vector<int32_t>>(p_variant.operator Vector<int32_t>());
}
case Variant::PACKED_INT64_ARRAY: {
- return _convert_array<DA, Vector<int64_t> >(p_variant.operator Vector<int64_t>());
+ return _convert_array<DA, Vector<int64_t>>(p_variant.operator Vector<int64_t>());
}
case Variant::PACKED_FLOAT32_ARRAY: {
- return _convert_array<DA, Vector<float> >(p_variant.operator Vector<float>());
+ return _convert_array<DA, Vector<float>>(p_variant.operator Vector<float>());
}
case Variant::PACKED_FLOAT64_ARRAY: {
- return _convert_array<DA, Vector<double> >(p_variant.operator Vector<double>());
+ return _convert_array<DA, Vector<double>>(p_variant.operator Vector<double>());
}
case Variant::PACKED_STRING_ARRAY: {
- return _convert_array<DA, Vector<String> >(p_variant.operator Vector<String>());
+ return _convert_array<DA, Vector<String>>(p_variant.operator Vector<String>());
}
case Variant::PACKED_VECTOR2_ARRAY: {
- return _convert_array<DA, Vector<Vector2> >(p_variant.operator Vector<Vector2>());
+ return _convert_array<DA, Vector<Vector2>>(p_variant.operator Vector<Vector2>());
}
case Variant::PACKED_VECTOR3_ARRAY: {
- return _convert_array<DA, Vector<Vector3> >(p_variant.operator Vector<Vector3>());
+ return _convert_array<DA, Vector<Vector3>>(p_variant.operator Vector<Vector3>());
}
case Variant::PACKED_COLOR_ARRAY: {
- return _convert_array<DA, Vector<Color> >(p_variant.operator Vector<Color>());
+ return _convert_array<DA, Vector<Color>>(p_variant.operator Vector<Color>());
}
default: {
return DA();
@@ -2370,21 +2370,21 @@ Variant::operator Vector<uint8_t>() const {
if (type == PACKED_BYTE_ARRAY)
return static_cast<PackedArrayRef<uint8_t> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<uint8_t> >(*this);
+ return _convert_array_from_variant<Vector<uint8_t>>(*this);
}
Variant::operator Vector<int32_t>() const {
if (type == PACKED_INT32_ARRAY)
return static_cast<PackedArrayRef<int32_t> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<int> >(*this);
+ return _convert_array_from_variant<Vector<int>>(*this);
}
Variant::operator Vector<int64_t>() const {
if (type == PACKED_INT64_ARRAY)
return static_cast<PackedArrayRef<int64_t> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<int64_t> >(*this);
+ return _convert_array_from_variant<Vector<int64_t>>(*this);
}
Variant::operator Vector<float>() const {
@@ -2392,7 +2392,7 @@ Variant::operator Vector<float>() const {
if (type == PACKED_FLOAT32_ARRAY)
return static_cast<PackedArrayRef<float> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<float> >(*this);
+ return _convert_array_from_variant<Vector<float>>(*this);
}
Variant::operator Vector<double>() const {
@@ -2400,7 +2400,7 @@ Variant::operator Vector<double>() const {
if (type == PACKED_FLOAT64_ARRAY)
return static_cast<PackedArrayRef<double> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<double> >(*this);
+ return _convert_array_from_variant<Vector<double>>(*this);
}
Variant::operator Vector<String>() const {
@@ -2408,21 +2408,21 @@ Variant::operator Vector<String>() const {
if (type == PACKED_STRING_ARRAY)
return static_cast<PackedArrayRef<String> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<String> >(*this);
+ return _convert_array_from_variant<Vector<String>>(*this);
}
Variant::operator Vector<Vector3>() const {
if (type == PACKED_VECTOR3_ARRAY)
return static_cast<PackedArrayRef<Vector3> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<Vector3> >(*this);
+ return _convert_array_from_variant<Vector<Vector3>>(*this);
}
Variant::operator Vector<Vector2>() const {
if (type == PACKED_VECTOR2_ARRAY)
return static_cast<PackedArrayRef<Vector2> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<Vector2> >(*this);
+ return _convert_array_from_variant<Vector<Vector2>>(*this);
}
Variant::operator Vector<Color>() const {
@@ -2430,7 +2430,7 @@ Variant::operator Vector<Color>() const {
if (type == PACKED_COLOR_ARRAY)
return static_cast<PackedArrayRef<Color> *>(_data.packed_array)->array;
else
- return _convert_array_from_variant<Vector<Color> >(*this);
+ return _convert_array_from_variant<Vector<Color>>(*this);
}
/* helpers */
diff --git a/core/variant.h b/core/variant.h
index 614d39e84a..a832f7ccf8 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -435,16 +435,16 @@ public:
bool has_method(const StringName &p_method) const;
static Vector<Variant::Type> get_method_argument_types(Variant::Type p_type, const StringName &p_method);
static Vector<Variant> get_method_default_arguments(Variant::Type p_type, const StringName &p_method);
- static Variant::Type get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return = NULL);
+ static Variant::Type get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return = nullptr);
static Vector<StringName> get_method_argument_names(Variant::Type p_type, const StringName &p_method);
static bool is_method_const(Variant::Type p_type, const StringName &p_method);
- void set_named(const StringName &p_index, const Variant &p_value, bool *r_valid = NULL);
- Variant get_named(const StringName &p_index, bool *r_valid = NULL) const;
+ void set_named(const StringName &p_index, const Variant &p_value, bool *r_valid = nullptr);
+ Variant get_named(const StringName &p_index, bool *r_valid = nullptr) const;
- void set(const Variant &p_index, const Variant &p_value, bool *r_valid = NULL);
- Variant get(const Variant &p_index, bool *r_valid = NULL) const;
- bool in(const Variant &p_index, bool *r_valid = NULL) const;
+ void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr);
+ Variant get(const Variant &p_index, bool *r_valid = nullptr) const;
+ bool in(const Variant &p_index, bool *r_valid = nullptr) const;
bool iter_init(Variant &r_iter, bool &r_valid) const;
bool iter_next(Variant &r_iter, bool &r_valid) const;
@@ -467,13 +467,13 @@ public:
static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);
static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
static bool has_constant(Variant::Type p_type, const StringName &p_value);
- static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = NULL);
+ static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr);
typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);
String get_construct_string() const;
- static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = NULL, void *p_construct_ud = NULL);
+ static void construct_from_string(const String &p_string, Variant &r_value, ObjectConstruct p_obj_construct = nullptr, void *p_construct_ud = nullptr);
void operator=(const Variant &p_variant); // only this is enough for all the other types
Variant(const Variant &p_variant);
@@ -516,4 +516,5 @@ const Variant::ObjData &Variant::_get_obj() const {
}
String vformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
-#endif
+
+#endif // VARIANT_H
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index f00aad33fc..391c293810 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -1191,9 +1191,9 @@ struct _VariantCall {
}
};
-_VariantCall::TypeFunc *_VariantCall::type_funcs = NULL;
-_VariantCall::ConstructFunc *_VariantCall::construct_funcs = NULL;
-_VariantCall::ConstantData *_VariantCall::constant_data = NULL;
+_VariantCall::TypeFunc *_VariantCall::type_funcs = nullptr;
+_VariantCall::ConstructFunc *_VariantCall::construct_funcs = nullptr;
+_VariantCall::ConstantData *_VariantCall::constant_data = nullptr;
Variant Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -1310,7 +1310,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i
case NODE_PATH:
return NodePath();
case _RID: return RID();
- case OBJECT: return (Object *)NULL;
+ case OBJECT: return (Object *)nullptr;
case CALLABLE: return Callable();
case SIGNAL: return Signal();
case DICTIONARY: return Dictionary();
@@ -1526,8 +1526,11 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const {
PropertyInfo ret;
#ifdef DEBUG_ENABLED
ret.type = fd.return_type;
- if (fd.returns)
+ if (fd.returns) {
ret.name = "ret";
+ if (fd.return_type == Variant::NIL)
+ ret.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
mi.return_val = ret;
#endif
@@ -1954,7 +1957,7 @@ void register_variant_methods() {
ADDFUNC0NC(DICTIONARY, NIL, Dictionary, clear, varray());
ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has, NIL, "key", varray());
ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has_all, ARRAY, "keys", varray());
- ADDFUNC1R(DICTIONARY, BOOL, Dictionary, erase, NIL, "key", varray());
+ ADDFUNC1RNC(DICTIONARY, BOOL, Dictionary, erase, NIL, "key", varray());
ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray());
ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray());
ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray());
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index 88f6ce19a2..f173c88054 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -438,7 +438,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
CASE_TYPE(math, OP_EQUAL, NIL) {
if (p_b.type == NIL) _RETURN(true);
if (p_b.type == OBJECT)
- _RETURN(p_b._get_obj().obj == NULL);
+ _RETURN(p_b._get_obj().obj == nullptr);
_RETURN(false);
}
@@ -457,7 +457,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
if (p_b.type == OBJECT)
_RETURN((p_a._get_obj().obj == p_b._get_obj().obj));
if (p_b.type == NIL)
- _RETURN(p_a._get_obj().obj == NULL);
+ _RETURN(p_a._get_obj().obj == nullptr);
_RETURN_FAIL;
}
@@ -534,7 +534,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
CASE_TYPE(math, OP_NOT_EQUAL, NIL) {
if (p_b.type == NIL) _RETURN(false);
if (p_b.type == OBJECT)
- _RETURN(p_b._get_obj().obj != NULL);
+ _RETURN(p_b._get_obj().obj != nullptr);
_RETURN(true);
}
@@ -554,7 +554,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a,
if (p_b.type == OBJECT)
_RETURN((p_a._get_obj().obj != p_b._get_obj().obj));
if (p_b.type == NIL)
- _RETURN(p_a._get_obj().obj != NULL);
+ _RETURN(p_a._get_obj().obj != nullptr);
_RETURN_FAIL;
}
@@ -3527,7 +3527,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
if (dic->empty())
return false;
- const Variant *next = dic->next(NULL);
+ const Variant *next = dic->next(nullptr);
r_iter = *next;
return true;
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
index d2ee0b71c9..0a578faf78 100644
--- a/core/variant_parser.cpp
+++ b/core/variant_parser.cpp
@@ -30,8 +30,8 @@
#include "variant_parser.h"
+#include "core/input/input_event.h"
#include "core/io/resource_loader.h"
-#include "core/os/input_event.h"
#include "core/os/keyboard.h"
#include "core/string_buffer.h"
diff --git a/core/variant_parser.h b/core/variant_parser.h
index d50842145c..63ed51bcc9 100644
--- a/core/variant_parser.h
+++ b/core/variant_parser.h
@@ -58,7 +58,7 @@ public:
virtual bool is_utf8() const;
virtual bool is_eof() const;
- StreamFile() { f = NULL; }
+ StreamFile() { f = nullptr; }
};
struct StreamString : public Stream {
@@ -130,17 +130,17 @@ private:
template <class T>
static Error _parse_construct(Stream *p_stream, Vector<T> &r_construct, int &line, String &r_err_str);
static Error _parse_enginecfg(Stream *p_stream, Vector<String> &strings, int &line, String &r_err_str);
- static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = NULL);
- static Error _parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = NULL);
- static Error _parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = NULL, bool p_simple_tag = false);
+ static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
+ static Error _parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
+ static Error _parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
public:
- static Error parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = NULL, bool p_simple_tag = false);
- static Error parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser = NULL, bool p_simple_tag = false);
+ static Error parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
+ static Error parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser = nullptr, bool p_simple_tag = false);
- static Error parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = NULL);
+ static Error parse_value(Token &token, Variant &value, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser = nullptr);
static Error get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str);
- static Error parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser = NULL);
+ static Error parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser = nullptr);
};
class VariantWriter {
@@ -149,7 +149,7 @@ public:
typedef String (*EncodeResourceFunc)(void *ud, const RES &p_resource);
static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud);
- static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = NULL, void *p_encode_res_ud = NULL);
+ static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr);
};
#endif // VARIANT_PARSER_H
diff --git a/core/vector.h b/core/vector.h
index d3476679ff..7277179621 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -103,7 +103,7 @@ public:
void sort() {
- sort_custom<_DefaultComparator<T> >();
+ sort_custom<_DefaultComparator<T>>();
}
void ordered_insert(const T &p_val) {
@@ -181,4 +181,4 @@ bool Vector<T>::push_back(T p_elem) {
return false;
}
-#endif
+#endif // VECTOR_H
diff --git a/core/version.h b/core/version.h
index 42c85c1b13..1198f62db4 100644
--- a/core/version.h
+++ b/core/version.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GODOT_VERSION_H
-#define GODOT_VERSION_H
+#ifndef VERSION_H
+#define VERSION_H
#include "core/version_generated.gen.h"
@@ -68,4 +68,4 @@
// Example: "Godot v3.1.4.stable.official.mono"
#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_FULL_BUILD
-#endif // GODOT_VERSION_H
+#endif // VERSION_H
diff --git a/doc/Makefile b/doc/Makefile
index 7f3f7ea939..9534da9bd5 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -13,13 +13,6 @@ doxygen:
mkdir -p $(OUTPUTDIR)/doxygen
doxygen Doxyfile
-markdown:
- rm -rf $(OUTPUTDIR)/markdown
- mkdir -p $(OUTPUTDIR)/markdown
- pushd $(OUTPUTDIR)/markdown
- python2 $(TOOLSDIR)/makemd.py $(CLASSES)
- popd
-
rst:
rm -rf $(OUTPUTDIR)/rst
mkdir -p $(OUTPUTDIR)/rst
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 74c364bad5..f462aa989d 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -12,8 +12,8 @@
<methods>
</methods>
<members>
- <member name="ARVRServer" type="ARVRServer" setter="" getter="">
- The [ARVRServer] singleton.
+ <member name="XRServer" type="XRServer" setter="" getter="">
+ The [XRServer] singleton.
</member>
<member name="AudioServer" type="AudioServer" setter="" getter="">
The [AudioServer] singleton.
@@ -36,8 +36,8 @@
<member name="IP" type="IP" setter="" getter="">
The [IP] singleton.
</member>
- <member name="Input" type="Input" setter="" getter="">
- The [Input] singleton.
+ <member name="Input" type="InputFilter" setter="" getter="">
+ The [InputFilter] singleton.
</member>
<member name="InputMap" type="InputMap" setter="" getter="">
The [InputMap] singleton.
@@ -56,14 +56,14 @@
<member name="Marshalls" type="Marshalls" setter="" getter="">
The [Marshalls] singleton.
</member>
- <member name="Navigation2DServer" type="Navigation2DServer" setter="" getter="">
- The [Navigation2DServer] singleton.
- </member>
<member name="NavigationMeshGenerator" type="NavigationMeshGenerator" setter="" getter="">
The [NavigationMeshGenerator] singleton.
</member>
- <member name="NavigationServer" type="NavigationServer" setter="" getter="">
- The [NavigationServer] singleton.
+ <member name="NavigationServer2D" type="NavigationServer2D" setter="" getter="">
+ The [NavigationServer2D] singleton.
+ </member>
+ <member name="NavigationServer3D" type="NavigationServer3D" setter="" getter="">
+ The [NavigationServer2D] singleton.
</member>
<member name="OS" type="OS" setter="" getter="">
The [OS] singleton.
@@ -71,15 +71,18 @@
<member name="Performance" type="Performance" setter="" getter="">
The [Performance] singleton.
</member>
- <member name="Physics2DServer" type="Physics2DServer" setter="" getter="">
- The [Physics2DServer] singleton.
+ <member name="PhysicsServer2D" type="PhysicsServer2D" setter="" getter="">
+ The [PhysicsServer2D] singleton.
</member>
- <member name="PhysicsServer" type="PhysicsServer" setter="" getter="">
- The [PhysicsServer] singleton.
+ <member name="PhysicsServer3D" type="PhysicsServer3D" setter="" getter="">
+ The [PhysicsServer3D] singleton.
</member>
<member name="ProjectSettings" type="ProjectSettings" setter="" getter="">
The [ProjectSettings] singleton.
</member>
+ <member name="RenderingServer" type="RenderingServer" setter="" getter="">
+ The [RenderingServer] singleton.
+ </member>
<member name="ResourceLoader" type="ResourceLoader" setter="" getter="">
The [ResourceLoader] singleton.
</member>
@@ -92,9 +95,6 @@
<member name="VisualScriptEditor" type="VisualScriptEditor" setter="" getter="">
The [VisualScriptEditor] singleton.
</member>
- <member name="VisualServer" type="VisualServer" setter="" getter="">
- The [VisualServer] singleton.
- </member>
</members>
<constants>
<constant name="MARGIN_LEFT" value="0" enum="Margin">
diff --git a/doc/classes/ARVRAnchor.xml b/doc/classes/ARVRAnchor.xml
deleted file mode 100644
index 87181f572d..0000000000
--- a/doc/classes/ARVRAnchor.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRAnchor" inherits="Spatial" version="4.0">
- <brief_description>
- An anchor point in AR space.
- </brief_description>
- <description>
- The [ARVRAnchor] point is a spatial node that maps a real world location identified by the AR platform to a position within the game world. For example, as long as plane detection in ARKit is on, ARKit will identify and update the position of planes (tables, floors, etc) and create anchors for them.
- This node is mapped to one of the anchors through its unique ID. When you receive a signal that a new anchor is available, you should add this node to your scene for that anchor. You can predefine nodes and set the ID; the nodes will simply remain on 0,0,0 until a plane is recognized.
- Keep in mind that, as long as plane detection is enabled, the size, placing and orientation of an anchor will be updated as the detection logic learns more about the real world out there especially if only part of the surface is in view.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_anchor_name" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the name given to this anchor.
- </description>
- </method>
- <method name="get_is_active" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the anchor is being tracked and [code]false[/code] if no anchor with this ID is currently known.
- </description>
- </method>
- <method name="get_mesh" qualifiers="const">
- <return type="Mesh">
- </return>
- <description>
- If provided by the [ARVRInterface], this returns a mesh object for the anchor. For an anchor, this can be a shape related to the object being tracked or it can be a mesh that provides topology related to the anchor and can be used to create shadows/reflections on surfaces or for generating collision shapes.
- </description>
- </method>
- <method name="get_plane" qualifiers="const">
- <return type="Plane">
- </return>
- <description>
- Returns a plane aligned with our anchor; handy for intersection testing.
- </description>
- </method>
- <method name="get_size" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- Returns the estimated size of the plane that was detected. Say when the anchor relates to a table in the real world, this is the estimated size of the surface of that table.
- </description>
- </method>
- </methods>
- <members>
- <member name="anchor_id" type="int" setter="set_anchor_id" getter="get_anchor_id" default="1">
- The anchor's ID. You can set this before the anchor itself exists. The first anchor gets an ID of [code]1[/code], the second an ID of [code]2[/code], etc. When anchors get removed, the engine can then assign the corresponding ID to new anchors. The most common situation where anchors "disappear" is when the AR server identifies that two anchors represent different parts of the same plane and merges them.
- </member>
- </members>
- <signals>
- <signal name="mesh_updated">
- <argument index="0" name="mesh" type="Mesh">
- </argument>
- <description>
- Emitted when the mesh associated with the anchor changes or when one becomes available. This is especially important for topology that is constantly being [code]mesh_updated[/code].
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ARVRCamera.xml b/doc/classes/ARVRCamera.xml
deleted file mode 100644
index a571d26c83..0000000000
--- a/doc/classes/ARVRCamera.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRCamera" inherits="Camera" version="4.0">
- <brief_description>
- A camera node with a few overrules for AR/VR applied, such as location tracking.
- </brief_description>
- <description>
- This is a helper spatial node for our camera; note that, if stereoscopic rendering is applicable (VR-HMD), most of the camera properties are ignored, as the HMD information overrides them. The only properties that can be trusted are the near and far planes.
- The position and orientation of this node is automatically updated by the ARVR Server to represent the location of the HMD if such tracking is available and can thus be used by game logic. Note that, in contrast to the ARVR Controller, the render thread has access to the most up-to-date tracking data of the HMD and the location of the ARVRCamera can lag a few milliseconds behind what is used for rendering as a result.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ARVRController.xml b/doc/classes/ARVRController.xml
deleted file mode 100644
index ebae25feb7..0000000000
--- a/doc/classes/ARVRController.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRController" inherits="Spatial" version="4.0">
- <brief_description>
- A spatial node representing a spatially-tracked controller.
- </brief_description>
- <description>
- This is a helper spatial node that is linked to the tracking of controllers. It also offers several handy passthroughs to the state of buttons and such on the controllers.
- Controllers are linked by their ID. You can create controller nodes before the controllers are available. If your game always uses two controllers (one for each hand), you can predefine the controllers with ID 1 and 2; they will become active as soon as the controllers are identified. If you expect additional controllers to be used, you should react to the signals and add ARVRController nodes to your scene.
- The position of the controller node is automatically updated by the [ARVRServer]. This makes this node ideal to add child nodes to visualize the controller.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
- </tutorials>
- <methods>
- <method name="get_controller_name" qualifiers="const">
- <return type="String">
- </return>
- <description>
- If active, returns the name of the associated controller if provided by the AR/VR SDK used.
- </description>
- </method>
- <method name="get_hand" qualifiers="const">
- <return type="int" enum="ARVRPositionalTracker.TrackerHand">
- </return>
- <description>
- Returns the hand holding this controller, if known. See [enum ARVRPositionalTracker.TrackerHand].
- </description>
- </method>
- <method name="get_is_active" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the bound controller is active. ARVR systems attempt to track active controllers.
- </description>
- </method>
- <method name="get_joystick_axis" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="axis" type="int">
- </argument>
- <description>
- Returns the value of the given axis for things like triggers, touchpads, etc. that are embedded into the controller.
- </description>
- </method>
- <method name="get_joystick_id" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the ID of the joystick object bound to this. Every controller tracked by the [ARVRServer] that has buttons and axis will also be registered as a joystick within Godot. This means that all the normal joystick tracking and input mapping will work for buttons and axis found on the AR/VR controllers. This ID is purely offered as information so you can link up the controller with its joystick entry.
- </description>
- </method>
- <method name="get_mesh" qualifiers="const">
- <return type="Mesh">
- </return>
- <description>
- If provided by the [ARVRInterface], this returns a mesh associated with the controller. This can be used to visualize the controller.
- </description>
- </method>
- <method name="is_button_pressed" qualifiers="const">
- <return type="bool">
- </return>
- <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 JoystickList], in particular the [code]JOY_VR_*[/code] constants.
- </description>
- </method>
- </methods>
- <members>
- <member name="controller_id" type="int" setter="set_controller_id" getter="get_controller_id" default="1">
- The controller's ID.
- A controller ID of 0 is unbound and will always result in an inactive node. Controller ID 1 is reserved for the first controller that identifies itself as the left-hand controller and ID 2 is reserved for the first controller that identifies itself as the right-hand controller.
- For any other controller that the [ARVRServer] detects, we continue with controller ID 3.
- When a controller is turned off, its slot is freed. This ensures controllers will keep the same ID even when controllers with lower IDs are turned off.
- </member>
- <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0">
- The degree to which the controller vibrates. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code]. If changed, updates [member ARVRPositionalTracker.rumble] accordingly.
- This is a useful property to animate if you want the controller to vibrate for a limited duration.
- </member>
- </members>
- <signals>
- <signal name="button_pressed">
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- Emitted when a button on this controller is pressed.
- </description>
- </signal>
- <signal name="button_release">
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- Emitted when a button on this controller is released.
- </description>
- </signal>
- <signal name="mesh_updated">
- <argument index="0" name="mesh" type="Mesh">
- </argument>
- <description>
- Emitted when the mesh associated with the controller changes or when one becomes available. Generally speaking this will be a static mesh after becoming available.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ARVRInterface.xml b/doc/classes/ARVRInterface.xml
deleted file mode 100644
index 0727bda668..0000000000
--- a/doc/classes/ARVRInterface.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRInterface" inherits="Reference" version="4.0">
- <brief_description>
- Base class for an AR/VR interface implementation.
- </brief_description>
- <description>
- This class needs to be implemented to make an AR or VR platform available to Godot and these should be implemented as C++ modules or GDNative modules (note that for GDNative the subclass ARVRScriptInterface should be used). Part of the interface is exposed to GDScript so you can detect, enable and configure an AR or VR platform.
- Interfaces should be written in such a way that simply enabling them will give us a working setup. You can query the available interfaces through [ARVRServer].
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
- </tutorials>
- <methods>
- <method name="get_camera_feed_id">
- <return type="int">
- </return>
- <description>
- If this is an AR interface that requires displaying a camera feed as the background, this method returns the feed ID in the [CameraServer] for this interface.
- </description>
- </method>
- <method name="get_capabilities" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns a combination of [enum Capabilities] flags providing information about the capabilities of this interface.
- </description>
- </method>
- <method name="get_name" qualifiers="const">
- <return type="StringName">
- </return>
- <description>
- Returns the name of this interface (OpenVR, OpenHMD, ARKit, etc).
- </description>
- </method>
- <method name="get_render_targetsize">
- <return type="Vector2">
- </return>
- <description>
- Returns the resolution at which we should render our intermediate results before things like lens distortion are applied by the VR platform.
- </description>
- </method>
- <method name="get_tracking_status" qualifiers="const">
- <return type="int" enum="ARVRInterface.Tracking_status">
- </return>
- <description>
- If supported, returns the status of our tracking. This will allow you to provide feedback to the user whether there are issues with positional tracking.
- </description>
- </method>
- <method name="initialize">
- <return type="bool">
- </return>
- <description>
- Call this to initialize this interface. The first interface that is initialized is identified as the primary interface and it will be used for rendering output.
- After initializing the interface you want to use you then need to enable the AR/VR mode of a viewport and rendering should commence.
- [b]Note:[/b] You must enable the AR/VR mode on the main viewport for any device that uses the main output of Godot, such as for mobile VR.
- If you do this for a platform that handles its own output (such as OpenVR) Godot will show just one eye without distortion on screen. Alternatively, you can add a separate viewport node to your scene and enable AR/VR on that viewport. It will be used to output to the HMD, leaving you free to do anything you like in the main window, such as using a separate camera as a spectator camera or rendering something completely different.
- While currently not used, you can activate additional interfaces. You may wish to do this if you want to track controllers from other platforms. However, at this point in time only one interface can render to an HMD.
- </description>
- </method>
- <method name="is_stereo">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the current output of this interface is in stereo.
- </description>
- </method>
- <method name="uninitialize">
- <return type="void">
- </return>
- <description>
- Turns the interface off.
- </description>
- </method>
- </methods>
- <members>
- <member name="ar_is_anchor_detection_enabled" type="bool" setter="set_anchor_detection_is_enabled" getter="get_anchor_detection_is_enabled" default="false">
- On an AR interface, [code]true[/code] if anchor detection is enabled.
- </member>
- <member name="interface_is_initialized" type="bool" setter="set_is_initialized" getter="is_initialized" default="false">
- [code]true[/code] if this interface been initialized.
- </member>
- <member name="interface_is_primary" type="bool" setter="set_is_primary" getter="is_primary" default="false">
- [code]true[/code] if this is the primary interface.
- </member>
- </members>
- <constants>
- <constant name="ARVR_NONE" value="0" enum="Capabilities">
- No ARVR capabilities.
- </constant>
- <constant name="ARVR_MONO" value="1" enum="Capabilities">
- This interface can work with normal rendering output (non-HMD based AR).
- </constant>
- <constant name="ARVR_STEREO" value="2" enum="Capabilities">
- This interface supports stereoscopic rendering.
- </constant>
- <constant name="ARVR_AR" value="4" enum="Capabilities">
- This interface supports AR (video background and real world tracking).
- </constant>
- <constant name="ARVR_EXTERNAL" value="8" enum="Capabilities">
- This interface outputs to an external device. If the main viewport is used, the on screen output is an unmodified buffer of either the left or right eye (stretched if the viewport size is not changed to the same aspect ratio of [method get_render_targetsize]). Using a separate viewport node frees up the main viewport for other purposes.
- </constant>
- <constant name="EYE_MONO" value="0" enum="Eyes">
- Mono output, this is mostly used internally when retrieving positioning information for our camera node or when stereo scopic rendering is not supported.
- </constant>
- <constant name="EYE_LEFT" value="1" enum="Eyes">
- Left eye output, this is mostly used internally when rendering the image for the left eye and obtaining positioning and projection information.
- </constant>
- <constant name="EYE_RIGHT" value="2" enum="Eyes">
- Right eye output, this is mostly used internally when rendering the image for the right eye and obtaining positioning and projection information.
- </constant>
- <constant name="ARVR_NORMAL_TRACKING" value="0" enum="Tracking_status">
- Tracking is behaving as expected.
- </constant>
- <constant name="ARVR_EXCESSIVE_MOTION" value="1" enum="Tracking_status">
- Tracking is hindered by excessive motion (the player is moving faster than tracking can keep up).
- </constant>
- <constant name="ARVR_INSUFFICIENT_FEATURES" value="2" enum="Tracking_status">
- Tracking is hindered by insufficient features, it's too dark (for camera-based tracking), player is blocked, etc.
- </constant>
- <constant name="ARVR_UNKNOWN_TRACKING" value="3" enum="Tracking_status">
- We don't know the status of the tracking or this interface does not provide feedback.
- </constant>
- <constant name="ARVR_NOT_TRACKING" value="4" enum="Tracking_status">
- Tracking is not functional (camera not plugged in or obscured, lighthouses turned off, etc.).
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ARVROrigin.xml b/doc/classes/ARVROrigin.xml
deleted file mode 100644
index 9a386fd154..0000000000
--- a/doc/classes/ARVROrigin.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVROrigin" inherits="Spatial" version="4.0">
- <brief_description>
- The origin point in AR/VR.
- </brief_description>
- <description>
- This is a special node within the AR/VR system that maps the physical location of the center of our tracking space to the virtual location within our game world.
- There should be only one of these nodes in your scene and you must have one. All the ARVRCamera, ARVRController and ARVRAnchor nodes should be direct children of this node for spatial tracking to work correctly.
- It is the position of this node that you update when your character needs to move through your game world while we're not moving in the real world. Movement in the real world is always in relation to this origin point.
- For example, if your character is driving a car, the ARVROrigin node should be a child node of this car. Or, if you're implementing a teleport system to move your character, you should change the position of this node.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
- Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
- [b]Note:[/b] This method is a passthrough to the [ARVRServer] itself.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ARVRPositionalTracker.xml b/doc/classes/ARVRPositionalTracker.xml
deleted file mode 100644
index 640b721d37..0000000000
--- a/doc/classes/ARVRPositionalTracker.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRPositionalTracker" inherits="Object" version="4.0">
- <brief_description>
- A tracked object.
- </brief_description>
- <description>
- An instance of this object represents a device that is tracked, such as a controller or anchor point. HMDs aren't represented here as they are handled internally.
- As controllers are turned on and the AR/VR interface detects them, instances of this object are automatically added to this list of active tracking objects accessible through the [ARVRServer].
- The [ARVRController] and [ARVRAnchor] both consume objects of this type and should be used in your project. The positional trackers are just under-the-hood objects that make this all work. These are mostly exposed so that GDNative-based interfaces can interact with them.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
- </tutorials>
- <methods>
- <method name="get_hand" qualifiers="const">
- <return type="int" enum="ARVRPositionalTracker.TrackerHand">
- </return>
- <description>
- Returns the hand holding this tracker, if known. See [enum TrackerHand] constants.
- </description>
- </method>
- <method name="get_joy_id" qualifiers="const">
- <return type="int">
- </return>
- <description>
- If this is a controller that is being tracked, the controller will also be represented by a joystick entry with this ID.
- </description>
- </method>
- <method name="get_mesh" qualifiers="const">
- <return type="Mesh">
- </return>
- <description>
- Returns the mesh related to a controller or anchor point if one is available.
- </description>
- </method>
- <method name="get_name" qualifiers="const">
- <return type="StringName">
- </return>
- <description>
- Returns the controller or anchor point's name if available.
- </description>
- </method>
- <method name="get_orientation" qualifiers="const">
- <return type="Basis">
- </return>
- <description>
- Returns the controller's orientation matrix.
- </description>
- </method>
- <method name="get_position" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- Returns the world-space controller position.
- </description>
- </method>
- <method name="get_tracker_id" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the internal tracker ID. This uniquely identifies the tracker per tracker type and matches the ID you need to specify for nodes such as the [ARVRController] and [ARVRAnchor] nodes.
- </description>
- </method>
- <method name="get_tracks_orientation" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if this device tracks orientation.
- </description>
- </method>
- <method name="get_tracks_position" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if this device tracks position.
- </description>
- </method>
- <method name="get_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="adjust_by_reference_frame" type="bool">
- </argument>
- <description>
- Returns the transform combining this device's orientation and position.
- </description>
- </method>
- <method name="get_type" qualifiers="const">
- <return type="int" enum="ARVRServer.TrackerType">
- </return>
- <description>
- Returns the tracker's type.
- </description>
- </method>
- </methods>
- <members>
- <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0">
- The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code].
- </member>
- </members>
- <constants>
- <constant name="TRACKER_HAND_UNKNOWN" value="0" enum="TrackerHand">
- The hand this tracker is held in is unknown or not applicable.
- </constant>
- <constant name="TRACKER_LEFT_HAND" value="1" enum="TrackerHand">
- This tracker is the left hand controller.
- </constant>
- <constant name="TRACKER_RIGHT_HAND" value="2" enum="TrackerHand">
- This tracker is the right hand controller.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ARVRServer.xml b/doc/classes/ARVRServer.xml
deleted file mode 100644
index 6db7121858..0000000000
--- a/doc/classes/ARVRServer.xml
+++ /dev/null
@@ -1,188 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRServer" inherits="Object" version="4.0">
- <brief_description>
- Server for AR and VR features.
- </brief_description>
- <description>
- The AR/VR server is the heart of our Advanced and Virtual Reality solution and handles all the processing.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
- </tutorials>
- <methods>
- <method name="center_on_hmd">
- <return type="void">
- </return>
- <argument index="0" name="rotation_mode" type="int" enum="ARVRServer.RotationMode">
- </argument>
- <argument index="1" name="keep_height" type="bool">
- </argument>
- <description>
- This is an important function to understand correctly. AR and VR platforms all handle positioning slightly differently.
- For platforms that do not offer spatial tracking, our origin point (0,0,0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
- For platforms that do offer spatial tracking, our origin point depends very much on the system. For OpenVR, our origin point is usually the center of the tracking space, on the ground. For other platforms, it's often the location of the tracking camera.
- This method allows you to center your tracker on the location of the HMD. It will take the current location of the HMD and use that to adjust all your tracking data; in essence, realigning the real world to your player's current position in the game world.
- For this method to produce usable results, tracking information must be available. This often takes a few frames after starting your game.
- 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="find_interface" qualifiers="const">
- <return type="ARVRInterface">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Finds an interface by its name. For instance, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
- </description>
- </method>
- <method name="get_hmd_transform">
- <return type="Transform">
- </return>
- <description>
- Returns the primary interface's transformation.
- </description>
- </method>
- <method name="get_interface" qualifiers="const">
- <return type="ARVRInterface">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the interface registered at a given index in our list of interfaces.
- </description>
- </method>
- <method name="get_interface_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of interfaces currently registered with the AR/VR server. If your project supports multiple AR/VR platforms, you can look through the available interface, and either present the user with a selection or simply try to initialize each interface and use the first one that returns [code]true[/code].
- </description>
- </method>
- <method name="get_interfaces" qualifiers="const">
- <return type="Array">
- </return>
- <description>
- Returns a list of available interfaces the ID and name of each interface.
- </description>
- </method>
- <method name="get_last_commit_usec">
- <return type="int">
- </return>
- <description>
- Returns the absolute timestamp (in μs) of the last [ARVRServer] commit of the AR/VR eyes to [VisualServer]. The value comes from an internal call to [method OS.get_ticks_usec].
- </description>
- </method>
- <method name="get_last_frame_usec">
- <return type="int">
- </return>
- <description>
- Returns the duration (in μs) of the last frame. This is computed as the difference between [method get_last_commit_usec] and [method get_last_process_usec] when committing.
- </description>
- </method>
- <method name="get_last_process_usec">
- <return type="int">
- </return>
- <description>
- Returns the absolute timestamp (in μs) of the last [ARVRServer] process callback. The value comes from an internal call to [method OS.get_ticks_usec].
- </description>
- </method>
- <method name="get_reference_frame" qualifiers="const">
- <return type="Transform">
- </return>
- <description>
- Returns the reference frame transform. Mostly used internally and exposed for GDNative build interfaces.
- </description>
- </method>
- <method name="get_tracker" qualifiers="const">
- <return type="ARVRPositionalTracker">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the positional tracker at the given ID.
- </description>
- </method>
- <method name="get_tracker_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of trackers currently registered.
- </description>
- </method>
- </methods>
- <members>
- <member name="primary_interface" type="ARVRInterface" setter="set_primary_interface" getter="get_primary_interface">
- The primary [ARVRInterface] currently bound to the [ARVRServer].
- </member>
- <member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
- Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
- </member>
- </members>
- <signals>
- <signal name="interface_added">
- <argument index="0" name="interface_name" type="StringName">
- </argument>
- <description>
- Emitted when a new interface has been added.
- </description>
- </signal>
- <signal name="interface_removed">
- <argument index="0" name="interface_name" type="StringName">
- </argument>
- <description>
- Emitted when an interface is removed.
- </description>
- </signal>
- <signal name="tracker_added">
- <argument index="0" name="tracker_name" type="StringName">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="id" type="int">
- </argument>
- <description>
- Emitted when a new tracker has been added. If you don't use a fixed number of controllers or if you're using [ARVRAnchor]s for an AR solution, it is important to react to this signal to add the appropriate [ARVRController] or [ARVRAnchor] nodes related to this new tracker.
- </description>
- </signal>
- <signal name="tracker_removed">
- <argument index="0" name="tracker_name" type="StringName">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="id" type="int">
- </argument>
- <description>
- Emitted when a tracker is removed. You should remove any [ARVRController] or [ARVRAnchor] points if applicable. This is not mandatory, the nodes simply become inactive and will be made active again when a new tracker becomes available (i.e. a new controller is switched on that takes the place of the previous one).
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="TRACKER_CONTROLLER" value="1" enum="TrackerType">
- The tracker tracks the location of a controller.
- </constant>
- <constant name="TRACKER_BASESTATION" value="2" enum="TrackerType">
- The tracker tracks the location of a base station.
- </constant>
- <constant name="TRACKER_ANCHOR" value="4" enum="TrackerType">
- The tracker tracks the location and size of an AR anchor.
- </constant>
- <constant name="TRACKER_ANY_KNOWN" value="127" enum="TrackerType">
- Used internally to filter trackers of any known type.
- </constant>
- <constant name="TRACKER_UNKNOWN" value="128" enum="TrackerType">
- Used internally if we haven't set the tracker type yet.
- </constant>
- <constant name="TRACKER_ANY" value="255" enum="TrackerType">
- Used internally to select all trackers.
- </constant>
- <constant name="RESET_FULL_ROTATION" value="0" enum="RotationMode">
- Fully reset the orientation of the HMD. Regardless of what direction the user is looking to in the real world. The user will look dead ahead in the virtual world.
- </constant>
- <constant name="RESET_BUT_KEEP_TILT" value="1" enum="RotationMode">
- Resets the orientation but keeps the tilt of the device. So if we're looking down, we keep looking down but heading will be reset.
- </constant>
- <constant name="DONT_RESET_ROTATION" value="2" enum="RotationMode">
- Does not reset the orientation of the HMD, only the position of the player gets centered.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 2639f62552..16fa05041e 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -9,6 +9,30 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_compute_cost" qualifiers="virtual">
+ <return type="float">
+ </return>
+ <argument index="0" name="from_id" type="int">
+ </argument>
+ <argument index="1" name="to_id" type="int">
+ </argument>
+ <description>
+ Called when computing the cost between two connected points.
+ Note that this function is hidden in the default [code]AStar2D[/code] class.
+ </description>
+ </method>
+ <method name="_estimate_cost" qualifiers="virtual">
+ <return type="float">
+ </return>
+ <argument index="0" name="from_id" type="int">
+ </argument>
+ <argument index="1" name="to_id" type="int">
+ </argument>
+ <description>
+ Called when estimating the cost between a point and the path's ending point.
+ Note that this function is hidden in the default [code]AStar2D[/code] class.
+ </description>
+ </method>
<method name="add_point">
<return type="void">
</return>
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index 01540383dc..99b566e74f 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AcceptDialog" inherits="WindowDialog" version="4.0">
+<class name="AcceptDialog" inherits="Window" version="4.0">
<brief_description>
Base dialog for user notification.
</brief_description>
@@ -67,9 +67,16 @@
<member name="dialog_text" type="String" setter="set_text" getter="get_text" default="&quot;&quot;">
The text displayed by the dialog.
</member>
- <member name="window_title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Alert!&quot;" />
+ <member name="title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Alert!&quot;" />
+ <member name="transient" type="bool" setter="set_transient" getter="is_transient" override="true" default="true" />
+ <member name="visible" type="bool" setter="set_visible" getter="is_visible" override="true" default="false" />
+ <member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" override="true" default="true" />
</members>
<signals>
+ <signal name="cancelled">
+ <description>
+ </description>
+ </signal>
<signal name="confirmed">
<description>
Emitted when the dialog is accepted, i.e. the OK button is pressed.
diff --git a/doc/classes/AnimatedSprite.xml b/doc/classes/AnimatedSprite.xml
deleted file mode 100644
index 03c23b6fdd..0000000000
--- a/doc/classes/AnimatedSprite.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AnimatedSprite" inherits="Node2D" version="4.0">
- <brief_description>
- Sprite node that can use multiple textures for animation.
- </brief_description>
- <description>
- Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="is_playing" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if an animation is currently being played.
- </description>
- </method>
- <method name="play">
- <return type="void">
- </return>
- <argument index="0" name="anim" type="StringName" default="@&quot;&quot;">
- </argument>
- <argument index="1" name="backwards" type="bool" default="false">
- </argument>
- <description>
- Plays the animation named [code]anim[/code]. If no [code]anim[/code] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse.
- </description>
- </method>
- <method name="stop">
- <return type="void">
- </return>
- <description>
- Stops the current animation (does not reset the frame counter).
- </description>
- </method>
- </methods>
- <members>
- <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@&quot;default&quot;">
- The current animation from the [code]frames[/code] resource. If this value changes, the [code]frame[/code] counter is reset.
- </member>
- <member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true">
- If [code]true[/code], texture will be centered.
- </member>
- <member name="flip_h" type="bool" setter="set_flip_h" getter="is_flipped_h" default="false">
- If [code]true[/code], texture is flipped horizontally.
- </member>
- <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v" default="false">
- If [code]true[/code], texture is flipped vertically.
- </member>
- <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
- The displayed animation frame's index.
- </member>
- <member name="frames" type="SpriteFrames" setter="set_sprite_frames" getter="get_sprite_frames">
- The [SpriteFrames] resource containing the animation(s).
- </member>
- <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
- The texture's drawing offset.
- </member>
- <member name="playing" type="bool" setter="_set_playing" getter="_is_playing" default="false">
- If [code]true[/code], the [member animation] is currently playing.
- </member>
- <member name="shininess" type="float" setter="set_shininess" getter="get_shininess" default="1.0">
- </member>
- <member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color( 1, 1, 1, 1 )">
- </member>
- <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The animation speed is multiplied by this value.
- </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.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
new file mode 100644
index 0000000000..8d0534ccd2
--- /dev/null
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AnimatedSprite2D" inherits="Node2D" version="4.0">
+ <brief_description>
+ Sprite node that can use multiple textures for animation.
+ </brief_description>
+ <description>
+ Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="is_playing" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if an animation is currently being played.
+ </description>
+ </method>
+ <method name="play">
+ <return type="void">
+ </return>
+ <argument index="0" name="anim" type="StringName" default="@&quot;&quot;">
+ </argument>
+ <argument index="1" name="backwards" type="bool" default="false">
+ </argument>
+ <description>
+ Plays the animation named [code]anim[/code]. If no [code]anim[/code] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse.
+ </description>
+ </method>
+ <method name="stop">
+ <return type="void">
+ </return>
+ <description>
+ Stops the current animation (does not reset the frame counter).
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@&quot;default&quot;">
+ The current animation from the [code]frames[/code] resource. If this value changes, the [code]frame[/code] counter is reset.
+ </member>
+ <member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true">
+ If [code]true[/code], texture will be centered.
+ </member>
+ <member name="flip_h" type="bool" setter="set_flip_h" getter="is_flipped_h" default="false">
+ If [code]true[/code], texture is flipped horizontally.
+ </member>
+ <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v" default="false">
+ If [code]true[/code], texture is flipped vertically.
+ </member>
+ <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
+ The displayed animation frame's index.
+ </member>
+ <member name="frames" type="SpriteFrames" setter="set_sprite_frames" getter="get_sprite_frames">
+ The [SpriteFrames] resource containing the animation(s).
+ </member>
+ <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
+ The texture's drawing offset.
+ </member>
+ <member name="playing" type="bool" setter="_set_playing" getter="_is_playing" default="false">
+ If [code]true[/code], the [member animation] is currently playing.
+ </member>
+ <member name="shininess" type="float" setter="set_shininess" getter="get_shininess" default="1.0">
+ Strength of the specular light effect of this [AnimatedSprite2D].
+ </member>
+ <member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color( 1, 1, 1, 1 )">
+ The color of the specular light effect.
+ </member>
+ <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
+ The animation speed is multiplied by this value.
+ </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.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/AnimatedTexture.xml b/doc/classes/AnimatedTexture.xml
index b851c76e59..80b910aaa7 100644
--- a/doc/classes/AnimatedTexture.xml
+++ b/doc/classes/AnimatedTexture.xml
@@ -4,7 +4,7 @@
Proxy texture for simple frame-based animations.
</brief_description>
<description>
- [AnimatedTexture] is a resource format for frame-based animations, where multiple textures can be chained automatically with a predefined delay for each frame. Unlike [AnimationPlayer] or [AnimatedSprite], it isn't a [Node], but has the advantage of being usable anywhere a [Texture2D] resource can be used, e.g. in a [TileSet].
+ [AnimatedTexture] is a resource format for frame-based animations, where multiple textures can be chained automatically with a predefined delay for each frame. Unlike [AnimationPlayer] or [AnimatedSprite2D], it isn't a [Node], but has the advantage of being usable anywhere a [Texture2D] resource can be used, e.g. in a [TileSet].
The playback of the animation is controlled by the [member fps] property as well as each frame's optional delay (see [method set_frame_delay]). The animation loops, i.e. it will restart at frame 0 automatically after playing the last frame.
[AnimatedTexture] currently requires all frame textures to have the same size, otherwise the bigger ones will be cropped to match the smallest one. Also, it doesn't support [AtlasTexture]. Each frame needs to be separate image.
</description>
@@ -71,7 +71,7 @@
</members>
<constants>
<constant name="MAX_FRAMES" value="256">
- The maximum number of frames supported by [AnimatedTexture]. If you need more frames in your animation, use [AnimationPlayer] or [AnimatedSprite].
+ The maximum number of frames supported by [AnimatedTexture]. If you need more frames in your animation, use [AnimationPlayer] or [AnimatedSprite2D].
</constant>
</constants>
</class>
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 0926ef9855..09811d5617 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -14,7 +14,7 @@
animation.track_insert_key(track_index, 0.0, 0)
animation.track_insert_key(track_index, 0.5, 100)
[/codeblock]
- Animations are just data containers, and must be added to nodes such as an [AnimationPlayer] to be played back.
+ Animations are just data containers, and must be added to nodes such as an [AnimationPlayer] to be played back. Animation tracks have different types, each with its own set of dedicated methods. Check [enum TrackType] to see available types.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
@@ -39,6 +39,7 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the animation name at the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Animation Track.
</description>
</method>
<method name="animation_track_insert_key">
@@ -51,6 +52,7 @@
<argument index="2" name="animation" type="StringName">
</argument>
<description>
+ Inserts a key with value [code]animation[/code] at the given [code]time[/code] (in seconds). The [code]track_idx[/code] must be the index of an Animation Track.
</description>
</method>
<method name="animation_track_set_key_animation">
@@ -63,6 +65,7 @@
<argument index="2" name="animation" type="StringName">
</argument>
<description>
+ Sets the key identified by [code]key_idx[/code] to value [code]animation[/code]. The [code]track_idx[/code] must be the index of an Animation Track.
</description>
</method>
<method name="audio_track_get_key_end_offset" qualifiers="const">
@@ -73,6 +76,8 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the end offset of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ End offset is the number of seconds cut off at the ending of the audio stream.
</description>
</method>
<method name="audio_track_get_key_start_offset" qualifiers="const">
@@ -83,6 +88,8 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the start offset of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Start offset is the number of seconds cut off at the beginning of the audio stream.
</description>
</method>
<method name="audio_track_get_key_stream" qualifiers="const">
@@ -93,6 +100,7 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the audio stream of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
</description>
</method>
<method name="audio_track_insert_key">
@@ -109,6 +117,8 @@
<argument index="4" name="end_offset" type="float" default="0">
</argument>
<description>
+ Inserts an Audio Track key at the given [code]time[/code] in seconds. The [code]track_idx[/code] must be the index of an Audio Track.
+ [code]stream[/code] is the [AudioStream] resource to play. [code]start_offset[/code] is the number of seconds cut off at the beginning of the audio stream, while [code]end_offset[/code] is at the ending.
</description>
</method>
<method name="audio_track_set_key_end_offset">
@@ -121,6 +131,7 @@
<argument index="2" name="offset" type="float">
</argument>
<description>
+ Sets the end offset of the key identified by [code]key_idx[/code] to value [code]offset[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
</description>
</method>
<method name="audio_track_set_key_start_offset">
@@ -133,6 +144,7 @@
<argument index="2" name="offset" type="float">
</argument>
<description>
+ Sets the start offset of the key identified by [code]key_idx[/code] to value [code]offset[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
</description>
</method>
<method name="audio_track_set_key_stream">
@@ -145,6 +157,7 @@
<argument index="2" name="stream" type="Resource">
</argument>
<description>
+ Sets the stream of the key identified by [code]key_idx[/code] to value [code]offset[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
</description>
</method>
<method name="bezier_track_get_key_in_handle" qualifiers="const">
@@ -155,6 +168,7 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the in handle of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_get_key_out_handle" qualifiers="const">
@@ -165,6 +179,7 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the out handle of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_get_key_value" qualifiers="const">
@@ -175,6 +190,7 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
+ Returns the value of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_insert_key">
@@ -191,6 +207,8 @@
<argument index="4" name="out_handle" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
+ Inserts a Bezier Track key at the given [code]time[/code] in seconds. The [code]track_idx[/code] must be the index of a Bezier Track.
+ [code]in_handle[/code] is the left-side weight of the added Bezier curve point, [code]out_handle[/code] is the right-side one, while [code]value[/code] is the actual value at this point.
</description>
</method>
<method name="bezier_track_interpolate" qualifiers="const">
@@ -201,6 +219,7 @@
<argument index="1" name="time" type="float">
</argument>
<description>
+ Returns the interpolated value at the given [code]time[/code] (in seconds). The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_in_handle">
@@ -213,6 +232,7 @@
<argument index="2" name="in_handle" type="Vector2">
</argument>
<description>
+ Sets the in handle of the key identified by [code]key_idx[/code] to value [code]in_handle[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_out_handle">
@@ -225,6 +245,7 @@
<argument index="2" name="out_handle" type="Vector2">
</argument>
<description>
+ Sets the out handle of the key identified by [code]key_idx[/code] to value [code]out_handle[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_value">
@@ -237,6 +258,7 @@
<argument index="2" name="value" type="float">
</argument>
<description>
+ Sets the value of the key identified by [code]key_idx[/code] to the given value. The [code]track_idx[/code] must be the index of a Bezier Track.
</description>
</method>
<method name="clear">
@@ -675,6 +697,7 @@
<signals>
<signal name="tracks_changed">
<description>
+ Emitted when there's a change in the list of tracks, e.g. tracks are added, moved or have changed paths.
</description>
</signal>
</signals>
@@ -689,10 +712,13 @@
Method tracks call functions with given arguments per key.
</constant>
<constant name="TYPE_BEZIER" value="3" enum="TrackType">
+ Bezier tracks are used to interpolate a value using custom curves. They can also be used to animate sub-properties of vectors and colors (e.g. alpha value of a [Color]).
</constant>
<constant name="TYPE_AUDIO" value="4" enum="TrackType">
+ Audio tracks are used to play an audio stream with either type of [AudioStreamPlayer]. The stream can be trimmed and previewed in the animation.
</constant>
<constant name="TYPE_ANIMATION" value="5" enum="TrackType">
+ Animation tracks play animations in other [AnimationPlayer] nodes.
</constant>
<constant name="INTERPOLATION_NEAREST" value="0" enum="InterpolationType">
No interpolation (nearest value).
@@ -713,6 +739,7 @@
Update at the keyframes.
</constant>
<constant name="UPDATE_CAPTURE" value="3" enum="UpdateMode">
+ Same as linear interpolation, but also interpolates from the current value (i.e. dynamically at runtime) if the first key isn't at 0 seconds.
</constant>
</constants>
</class>
diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml
index 0befb79577..4a34d75ff9 100644
--- a/doc/classes/AnimationNodeBlendTree.xml
+++ b/doc/classes/AnimationNodeBlendTree.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeBlendTree" inherits="AnimationRootNode" version="4.0">
<brief_description>
+ [AnimationTree] node resource that contains many blend type nodes.
</brief_description>
<description>
+ This node may contain a sub-tree of any other blend type nodes, such as mix, blend2, blend3, one shot, etc. This is one of the most commonly used roots.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
@@ -18,6 +20,7 @@
<argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
+ Adds an [AnimationNode] at the given [code]position[/code]. The [code]name[/code] is used to identify the created sub-node later.
</description>
</method>
<method name="connect_node">
@@ -30,6 +33,7 @@
<argument index="2" name="output_node" type="StringName">
</argument>
<description>
+ Connects the output of an [AnimationNode] as input for another [AnimationNode], at the input port specified by [code]input_index[/code].
</description>
</method>
<method name="disconnect_node">
@@ -40,6 +44,7 @@
<argument index="1" name="input_index" type="int">
</argument>
<description>
+ Disconnects the node connected to the specified input.
</description>
</method>
<method name="get_node" qualifiers="const">
@@ -48,6 +53,7 @@
<argument index="0" name="name" type="StringName">
</argument>
<description>
+ Returns the sub-node with the specified [code]name[/code].
</description>
</method>
<method name="get_node_position" qualifiers="const">
@@ -56,6 +62,7 @@
<argument index="0" name="name" type="StringName">
</argument>
<description>
+ Returns the position of the sub-node with the specified [code]name[/code].
</description>
</method>
<method name="has_node" qualifiers="const">
@@ -64,6 +71,7 @@
<argument index="0" name="name" type="StringName">
</argument>
<description>
+ Returns [code]true[/code] if a sub-node with specified [code]name[/code] exists.
</description>
</method>
<method name="remove_node">
@@ -72,6 +80,7 @@
<argument index="0" name="name" type="StringName">
</argument>
<description>
+ Removes a sub-node.
</description>
</method>
<method name="rename_node">
@@ -82,6 +91,7 @@
<argument index="1" name="new_name" type="StringName">
</argument>
<description>
+ Changes the name of a sub-node.
</description>
</method>
<method name="set_node_position">
@@ -92,25 +102,33 @@
<argument index="1" name="position" type="Vector2">
</argument>
<description>
+ Modifies the position of a sub-node.
</description>
</method>
</methods>
<members>
<member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2( 0, 0 )">
+ The global offset of all sub-nodes.
</member>
</members>
<constants>
<constant name="CONNECTION_OK" value="0">
+ The connection was successful.
</constant>
<constant name="CONNECTION_ERROR_NO_INPUT" value="1">
+ The input node is [code]null[/code].
</constant>
<constant name="CONNECTION_ERROR_NO_INPUT_INDEX" value="2">
+ The specified input port is out of range.
</constant>
<constant name="CONNECTION_ERROR_NO_OUTPUT" value="3">
+ The output node is [code]null[/code].
</constant>
<constant name="CONNECTION_ERROR_SAME_NODE" value="4">
+ Input and output nodes are the same.
</constant>
<constant name="CONNECTION_ERROR_CONNECTION_EXISTS" value="5">
+ The specified connection already exists.
</constant>
</constants>
</class>
diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml
index b6e4ed9c98..4ba0b82df6 100644
--- a/doc/classes/AnimationNodeOneShot.xml
+++ b/doc/classes/AnimationNodeOneShot.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeOneShot" inherits="AnimationNode" version="4.0">
<brief_description>
+ Plays an animation once in [AnimationNodeBlendTree].
</brief_description>
<description>
+ A resource to add to an [AnimationNodeBlendTree]. This node will execute a sub-animation and return once it finishes. Blend times for fading in and out can be customized, as well as filters.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
@@ -25,10 +27,13 @@
</methods>
<members>
<member name="autorestart" type="bool" setter="set_autorestart" getter="has_autorestart" default="false">
+ If [code]true[/code], the sub-animation will restart automatically after finishing.
</member>
<member name="autorestart_delay" type="float" setter="set_autorestart_delay" getter="get_autorestart_delay" default="1.0">
+ The delay after which the automatic restart is triggered, in seconds.
</member>
<member name="autorestart_random_delay" type="float" setter="set_autorestart_random_delay" getter="get_autorestart_random_delay" default="0.0">
+ If [member autorestart] is [code]true[/code], a random additional delay (in seconds) between 0 and this value will be added to [member autorestart_delay].
</member>
<member name="fadein_time" type="float" setter="set_fadein_time" getter="get_fadein_time" default="0.1">
</member>
diff --git a/doc/classes/AnimationNodeOutput.xml b/doc/classes/AnimationNodeOutput.xml
index f4bded2cd1..38b05eb650 100644
--- a/doc/classes/AnimationNodeOutput.xml
+++ b/doc/classes/AnimationNodeOutput.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeOutput" inherits="AnimationNode" version="4.0">
<brief_description>
+ Generic output node to be added to [AnimationNodeBlendTree].
</brief_description>
<description>
</description>
diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml
index b647ff70b8..3b351a3345 100644
--- a/doc/classes/AnimationNodeStateMachine.xml
+++ b/doc/classes/AnimationNodeStateMachine.xml
@@ -183,6 +183,16 @@
Renames the given node.
</description>
</method>
+ <method name="replace_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="node" type="AnimationNode">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_end_node">
<return type="void">
</return>
diff --git a/doc/classes/AnimationNodeTimeScale.xml b/doc/classes/AnimationNodeTimeScale.xml
index 229f9bbba2..5c2e6cb692 100644
--- a/doc/classes/AnimationNodeTimeScale.xml
+++ b/doc/classes/AnimationNodeTimeScale.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeTimeScale" inherits="AnimationNode" version="4.0">
<brief_description>
+ A time-scaling animation node to be used with [AnimationTree].
</brief_description>
<description>
+ Allows scaling the speed of the animation (or reversing it) in any children nodes. Setting it to 0 will pause the animation.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index 5a9cbe4861..0fef106da5 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeTimeSeek" inherits="AnimationNode" version="4.0">
<brief_description>
+ 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.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index bf94fe0466..11250c5b17 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeTransition" inherits="AnimationNode" version="4.0">
<brief_description>
+ A generic animation transition node for [AnimationTree].
</brief_description>
<description>
+ Simple state machine for cases which don't require a more advanced [AnimationNodeStateMachine]. Animations can be connected to the inputs and transition times can be specified.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
@@ -47,8 +49,10 @@
</methods>
<members>
<member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
+ The number of available input ports for this node.
</member>
<member name="xfade_time" type="float" setter="set_cross_fade_time" getter="get_cross_fade_time" default="0.0">
+ Cross-fading time (in seconds) between each animation connected to the inputs.
</member>
</members>
<constants>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 2a7db37eea..9642dd1c70 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationTree" inherits="Node" version="4.0">
<brief_description>
+ A node to be used for advanced animation transitions in an [AnimationPlayer].
</brief_description>
<description>
</description>
@@ -15,6 +16,7 @@
<argument index="0" name="delta" type="float">
</argument>
<description>
+ Manually advance the animations by the specified time (in seconds).
</description>
</method>
<method name="get_root_motion_transform" qualifiers="const">
@@ -36,22 +38,29 @@
</methods>
<members>
<member name="active" type="bool" setter="set_active" getter="is_active" default="false">
+ If [code]true[/code], the [AnimationTree] will be processing.
</member>
<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>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
</member>
<member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
+ The root animation node of this [AnimationTree]. See [AnimationNode].
</member>
</members>
<constants>
<constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessMode">
+ The animations will progress during the physics frame (i.e. [method Node._physics_process]).
</constant>
<constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode">
+ The animations will progress during the idle frame (i.e. [method Node._process]).
</constant>
<constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode">
+ The animations will only progress manually (see [method advance]).
</constant>
</constants>
</class>
diff --git a/doc/classes/Area.xml b/doc/classes/Area.xml
deleted file mode 100644
index b273a7a9d9..0000000000
--- a/doc/classes/Area.xml
+++ /dev/null
@@ -1,247 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Area" inherits="CollisionObject" version="4.0">
- <brief_description>
- General-purpose area node for detection and 3D physics influence.
- </brief_description>
- <description>
- 3D area that detects [CollisionObject] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
- </description>
- <tutorials>
- </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="Array">
- </return>
- <description>
- Returns a list of intersecting [Area]s. For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.
- </description>
- </method>
- <method name="get_overlapping_bodies" qualifiers="const">
- <return type="Array">
- </return>
- <description>
- Returns a list of intersecting [PhysicsBody]s. For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.
- </description>
- </method>
- <method name="overlaps_area" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="area" type="Node">
- </argument>
- <description>
- If [code]true[/code], the given area overlaps the Area.
- [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
- </description>
- </method>
- <method name="overlaps_body" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- If [code]true[/code], the given physics body overlaps the Area.
- [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
- The [code]body[/code] argument can either be a [PhysicsBody] 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 [Area]'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 [Area] layers this [Area] scans.
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="0.1">
- The rate at which objects stop spinning in this area. Represents the angular velocity lost per second. Values range from [code]0[/code] (no damping) to [code]1[/code] (full damping).
- </member>
- <member name="audio_bus_name" type="StringName" setter="set_audio_bus" getter="get_audio_bus" default="@&quot;Master&quot;">
- The name of the area's audio bus.
- </member>
- <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].
- </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.
- </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>
- <member name="gravity_distance_scale" type="float" setter="set_gravity_distance_scale" getter="get_gravity_distance_scale" default="0.0">
- The falloff factor for point gravity. The greater the value, the faster gravity decreases with distance.
- </member>
- <member name="gravity_point" type="bool" setter="set_gravity_is_point" getter="is_gravity_a_point" default="false">
- If [code]true[/code], gravity is calculated from a point (set via [member gravity_vec]). See also [member space_override].
- </member>
- <member name="gravity_vec" type="Vector3" setter="set_gravity_vector" getter="get_gravity_vector" default="Vector3( 0, -1, 0 )">
- The area's gravity vector (not normalized). If gravity is a point (see [member gravity_point]), this will be the point of attraction.
- </member>
- <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.1">
- The rate at which objects stop moving in this area. Represents the linear velocity lost per second. Values range from [code]0[/code] (no damping) to [code]1[/code] (full damping).
- </member>
- <member name="monitorable" type="bool" setter="set_monitorable" getter="is_monitorable" default="true">
- If [code]true[/code], other monitoring areas can detect this area.
- </member>
- <member name="monitoring" type="bool" setter="set_monitoring" getter="is_monitoring" default="true">
- If [code]true[/code], the area detects bodies or areas entering and exiting it.
- </member>
- <member name="priority" type="float" setter="set_priority" getter="get_priority" default="0.0">
- The area's priority. Higher priority areas are processed first.
- </member>
- <member name="reverb_bus_amount" type="float" setter="set_reverb_amount" getter="get_reverb_amount" default="0.0">
- The degree to which this area applies reverb to its associated audio. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision.
- </member>
- <member name="reverb_bus_enable" type="bool" setter="set_use_reverb_bus" getter="is_using_reverb_bus" default="false">
- If [code]true[/code], the area applies reverb to its associated audio.
- </member>
- <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus" getter="get_reverb_bus" default="@&quot;Master&quot;">
- The reverb bus name to use for this area's associated audio.
- </member>
- <member name="reverb_bus_uniformity" type="float" setter="set_reverb_uniformity" getter="get_reverb_uniformity" default="0.0">
- The degree to which this area's reverb is a uniform effect. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision.
- </member>
- <member name="space_override" type="int" setter="set_space_override_mode" getter="get_space_override_mode" enum="Area.SpaceOverride" default="0">
- Override mode for gravity and damping calculations within this area. See [enum SpaceOverride] for possible values.
- </member>
- </members>
- <signals>
- <signal name="area_entered">
- <argument index="0" name="area" type="Area">
- </argument>
- <description>
- Emitted when another area enters.
- </description>
- </signal>
- <signal name="area_exited">
- <argument index="0" name="area" type="Area">
- </argument>
- <description>
- Emitted when another area exits.
- </description>
- </signal>
- <signal name="area_shape_entered">
- <argument index="0" name="area_id" type="int">
- </argument>
- <argument index="1" name="area" type="Area">
- </argument>
- <argument index="2" name="area_shape" type="int">
- </argument>
- <argument index="3" name="self_shape" type="int">
- </argument>
- <description>
- Emitted when another area enters, reporting which areas overlapped. [code]shape_owner_get_owner(shape_find_owner(shape))[/code] returns the parent object of the owner of the [code]shape[/code].
- </description>
- </signal>
- <signal name="area_shape_exited">
- <argument index="0" name="area_id" type="int">
- </argument>
- <argument index="1" name="area" type="Area">
- </argument>
- <argument index="2" name="area_shape" type="int">
- </argument>
- <argument index="3" name="self_shape" type="int">
- </argument>
- <description>
- Emitted when another area exits, reporting which areas were overlapping.
- </description>
- </signal>
- <signal name="body_entered">
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- Emitted when a physics body enters.
- The [code]body[/code] argument can either be a [PhysicsBody] or a [GridMap] instance (while GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
- </description>
- </signal>
- <signal name="body_exited">
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- Emitted when a physics body exits.
- The [code]body[/code] argument can either be a [PhysicsBody] or a [GridMap] instance (while GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
- </description>
- </signal>
- <signal name="body_shape_entered">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Node">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="area_shape" type="int">
- </argument>
- <description>
- Emitted when a physics body enters, reporting which shapes overlapped.
- The [code]body[/code] argument can either be a [PhysicsBody] or a [GridMap] instance (while GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
- </description>
- </signal>
- <signal name="body_shape_exited">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Node">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="area_shape" type="int">
- </argument>
- <description>
- Emitted when a physics body exits, reporting which shapes were overlapping.
- The [code]body[/code] argument can either be a [PhysicsBody] or a [GridMap] instance (while GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="SPACE_OVERRIDE_DISABLED" value="0" enum="SpaceOverride">
- This area does not affect gravity/damping.
- </constant>
- <constant name="SPACE_OVERRIDE_COMBINE" value="1" enum="SpaceOverride">
- This area adds its gravity/damping values to whatever has been calculated so far (in [member priority] order).
- </constant>
- <constant name="SPACE_OVERRIDE_COMBINE_REPLACE" value="2" enum="SpaceOverride">
- This area adds its gravity/damping values to whatever has been calculated so far (in [member priority] order), ignoring any lower priority areas.
- </constant>
- <constant name="SPACE_OVERRIDE_REPLACE" value="3" enum="SpaceOverride">
- This area replaces any gravity/damping, even the defaults, ignoring any lower priority areas.
- </constant>
- <constant name="SPACE_OVERRIDE_REPLACE_COMBINE" value="4" enum="SpaceOverride">
- This area replaces any gravity/damping calculated so far (in [member priority] order), but keeps calculating the rest of the areas.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
new file mode 100644
index 0000000000..1adfc878e2
--- /dev/null
+++ b/doc/classes/Area3D.xml
@@ -0,0 +1,247 @@
+<?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.
+ </brief_description>
+ <description>
+ 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
+ </description>
+ <tutorials>
+ </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="Array">
+ </return>
+ <description>
+ Returns a list of intersecting [Area3D]s. For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.
+ </description>
+ </method>
+ <method name="get_overlapping_bodies" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Returns a list of intersecting [PhysicsBody3D]s. For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.
+ </description>
+ </method>
+ <method name="overlaps_area" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="area" type="Node">
+ </argument>
+ <description>
+ If [code]true[/code], the given area overlaps the Area3D.
+ [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
+ </description>
+ </method>
+ <method name="overlaps_body" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ If [code]true[/code], the given physics body overlaps the Area3D.
+ [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
+ 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">
+ The rate at which objects stop spinning in this area. Represents the angular velocity lost per second. Values range from [code]0[/code] (no damping) to [code]1[/code] (full damping).
+ </member>
+ <member name="audio_bus_name" type="StringName" setter="set_audio_bus" getter="get_audio_bus" default="@&quot;Master&quot;">
+ The name of the area's audio bus.
+ </member>
+ <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].
+ </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.
+ </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>
+ <member name="gravity_distance_scale" type="float" setter="set_gravity_distance_scale" getter="get_gravity_distance_scale" default="0.0">
+ The falloff factor for point gravity. The greater the value, the faster gravity decreases with distance.
+ </member>
+ <member name="gravity_point" type="bool" setter="set_gravity_is_point" getter="is_gravity_a_point" default="false">
+ If [code]true[/code], gravity is calculated from a point (set via [member gravity_vec]). See also [member space_override].
+ </member>
+ <member name="gravity_vec" type="Vector3" setter="set_gravity_vector" getter="get_gravity_vector" default="Vector3( 0, -1, 0 )">
+ The area's gravity vector (not normalized). If gravity is a point (see [member gravity_point]), this will be the point of attraction.
+ </member>
+ <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.1">
+ The rate at which objects stop moving in this area. Represents the linear velocity lost per second. Values range from [code]0[/code] (no damping) to [code]1[/code] (full damping).
+ </member>
+ <member name="monitorable" type="bool" setter="set_monitorable" getter="is_monitorable" default="true">
+ If [code]true[/code], other monitoring areas can detect this area.
+ </member>
+ <member name="monitoring" type="bool" setter="set_monitoring" getter="is_monitoring" default="true">
+ If [code]true[/code], the area detects bodies or areas entering and exiting it.
+ </member>
+ <member name="priority" type="float" setter="set_priority" getter="get_priority" default="0.0">
+ The area's priority. Higher priority areas are processed first.
+ </member>
+ <member name="reverb_bus_amount" type="float" setter="set_reverb_amount" getter="get_reverb_amount" default="0.0">
+ The degree to which this area applies reverb to its associated audio. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision.
+ </member>
+ <member name="reverb_bus_enable" type="bool" setter="set_use_reverb_bus" getter="is_using_reverb_bus" default="false">
+ If [code]true[/code], the area applies reverb to its associated audio.
+ </member>
+ <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus" getter="get_reverb_bus" default="@&quot;Master&quot;">
+ The reverb bus name to use for this area's associated audio.
+ </member>
+ <member name="reverb_bus_uniformity" type="float" setter="set_reverb_uniformity" getter="get_reverb_uniformity" default="0.0">
+ The degree to which this area's reverb is a uniform effect. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision.
+ </member>
+ <member name="space_override" type="int" setter="set_space_override_mode" getter="get_space_override_mode" enum="Area3D.SpaceOverride" default="0">
+ Override mode for gravity and damping calculations within this area. See [enum SpaceOverride] for possible values.
+ </member>
+ </members>
+ <signals>
+ <signal name="area_entered">
+ <argument index="0" name="area" type="Area3D">
+ </argument>
+ <description>
+ Emitted when another area enters.
+ </description>
+ </signal>
+ <signal name="area_exited">
+ <argument index="0" name="area" type="Area3D">
+ </argument>
+ <description>
+ Emitted when another area exits.
+ </description>
+ </signal>
+ <signal name="area_shape_entered">
+ <argument index="0" name="area_id" type="int">
+ </argument>
+ <argument index="1" name="area" type="Area3D">
+ </argument>
+ <argument index="2" name="area_shape" type="int">
+ </argument>
+ <argument index="3" name="self_shape" type="int">
+ </argument>
+ <description>
+ Emitted when another area enters, reporting which areas overlapped. [code]shape_owner_get_owner(shape_find_owner(shape))[/code] returns the parent object of the owner of the [code]shape[/code].
+ </description>
+ </signal>
+ <signal name="area_shape_exited">
+ <argument index="0" name="area_id" type="int">
+ </argument>
+ <argument index="1" name="area" type="Area3D">
+ </argument>
+ <argument index="2" name="area_shape" type="int">
+ </argument>
+ <argument index="3" name="self_shape" type="int">
+ </argument>
+ <description>
+ Emitted when another area exits, reporting which areas were overlapping.
+ </description>
+ </signal>
+ <signal name="body_entered">
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ Emitted when a physics body enters.
+ 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>
+ </signal>
+ <signal name="body_exited">
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ Emitted when a physics body exits.
+ 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>
+ </signal>
+ <signal name="body_shape_entered">
+ <argument index="0" name="body_id" type="int">
+ </argument>
+ <argument index="1" name="body" type="Node">
+ </argument>
+ <argument index="2" name="body_shape" type="int">
+ </argument>
+ <argument index="3" name="area_shape" type="int">
+ </argument>
+ <description>
+ Emitted when a physics body enters, reporting which shapes overlapped.
+ 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>
+ </signal>
+ <signal name="body_shape_exited">
+ <argument index="0" name="body_id" type="int">
+ </argument>
+ <argument index="1" name="body" type="Node">
+ </argument>
+ <argument index="2" name="body_shape" type="int">
+ </argument>
+ <argument index="3" name="area_shape" type="int">
+ </argument>
+ <description>
+ Emitted when a physics body exits, reporting which shapes were overlapping.
+ 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>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="SPACE_OVERRIDE_DISABLED" value="0" enum="SpaceOverride">
+ This area does not affect gravity/damping.
+ </constant>
+ <constant name="SPACE_OVERRIDE_COMBINE" value="1" enum="SpaceOverride">
+ This area adds its gravity/damping values to whatever has been calculated so far (in [member priority] order).
+ </constant>
+ <constant name="SPACE_OVERRIDE_COMBINE_REPLACE" value="2" enum="SpaceOverride">
+ This area adds its gravity/damping values to whatever has been calculated so far (in [member priority] order), ignoring any lower priority areas.
+ </constant>
+ <constant name="SPACE_OVERRIDE_REPLACE" value="3" enum="SpaceOverride">
+ This area replaces any gravity/damping, even the defaults, ignoring any lower priority areas.
+ </constant>
+ <constant name="SPACE_OVERRIDE_REPLACE_COMBINE" value="4" enum="SpaceOverride">
+ This area replaces any gravity/damping calculated so far (in [member priority] order), but keeps calculating the rest of the areas.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 6401feb95c..20296bbf45 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -116,7 +116,7 @@
</description>
</method>
<method name="back">
- <return type="void">
+ <return type="Variant">
</return>
<description>
Returns the last element of the array, or [code]null[/code] if the array is empty.
@@ -213,7 +213,7 @@
</description>
</method>
<method name="front">
- <return type="void">
+ <return type="Variant">
</return>
<description>
Returns the first element of the array, or [code]null[/code] if the array is empty.
@@ -260,28 +260,28 @@
</description>
</method>
<method name="max">
- <return type="void">
+ <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">
- <return type="void">
+ <return type="Variant">
</return>
<description>
Returns the minimum 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="pop_back">
- <return type="void">
+ <return type="Variant">
</return>
<description>
Removes and returns the last element of the array. Returns [code]null[/code] if the array is empty.
</description>
</method>
<method name="pop_front">
- <return type="void">
+ <return type="Variant">
</return>
<description>
Removes and returns the first element of the array. Returns [code]null[/code] if the array is empty.
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index 33b62054df..9e742ea581 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -18,10 +18,10 @@
arrays[ArrayMesh.ARRAY_VERTEX] = vertices
# Create the Mesh.
arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
- var m = MeshInstance.new()
+ var m = MeshInstance3D.new()
m.mesh = arr_mesh
[/codeblock]
- The [MeshInstance] is ready to be added to the [SceneTree] to be shown.
+ The [MeshInstance3D] is ready to be added to the [SceneTree] to be shown.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/content/procedural_geometry/arraymesh.html</link>
@@ -70,6 +70,7 @@
<return type="void">
</return>
<description>
+ Removes all surfaces from this [ArrayMesh].
</description>
</method>
<method name="get_blend_shape_count" qualifiers="const">
diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml
index 189e3c7059..4dac81322f 100644
--- a/doc/classes/AudioEffectRecord.xml
+++ b/doc/classes/AudioEffectRecord.xml
@@ -1,22 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioEffectRecord" inherits="AudioEffect" version="4.0">
<brief_description>
+ Audio effect used for recording sound from a microphone.
</brief_description>
<description>
</description>
<tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/audio/recording_with_microphone.html</link>
</tutorials>
<methods>
<method name="get_recording" qualifiers="const">
<return type="AudioStreamSample">
</return>
<description>
+ Returns the recorded sample.
</description>
</method>
<method name="is_recording_active" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether the recording is active or not.
</description>
</method>
<method name="set_recording_active">
@@ -25,11 +29,13 @@
<argument index="0" name="record" type="bool">
</argument>
<description>
+ If [code]true[/code], the sound will be recorded. Note that restarting the recording will remove the previously recorded sample.
</description>
</method>
</methods>
<members>
<member name="format" type="int" setter="set_format" getter="get_format" enum="AudioStreamSample.Format" default="1">
+ Specifies the format in which the sample will be recorded. See [enum AudioStreamSample.Format] for available formats.
</member>
</members>
<constants>
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index 4ec8dba2c6..3eeb524e9c 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamPlayer3D" inherits="Spatial" version="4.0">
+<class name="AudioStreamPlayer3D" inherits="Node3D" version="4.0">
<brief_description>
Plays 3D sound in 3D space.
</brief_description>
diff --git a/doc/classes/AudioStreamSample.xml b/doc/classes/AudioStreamSample.xml
index 6d99433c90..c12e1bd05c 100644
--- a/doc/classes/AudioStreamSample.xml
+++ b/doc/classes/AudioStreamSample.xml
@@ -30,13 +30,13 @@
Audio format. See [enum Format] constants for values.
</member>
<member name="loop_begin" type="int" setter="set_loop_begin" getter="get_loop_begin" default="0">
- Loop start in bytes.
+ The loop start point (in number of samples, relative to the beginning of the sample). This information will be imported automatically from the WAV file if present.
</member>
<member name="loop_end" type="int" setter="set_loop_end" getter="get_loop_end" default="0">
- Loop end in bytes.
+ The loop end point (in number of samples, relative to the beginning of the sample). This information will be imported automatically from the WAV file if present.
</member>
<member name="loop_mode" type="int" setter="set_loop_mode" getter="get_loop_mode" enum="AudioStreamSample.LoopMode" default="0">
- Loop mode. See [enum LoopMode] constants for values.
+ The loop mode. This information will be imported automatically from the WAV file if present. See [enum LoopMode] constants for values.
</member>
<member name="mix_rate" type="int" setter="set_mix_rate" getter="get_mix_rate" default="44100">
The sample rate for mixing this audio.
@@ -59,13 +59,13 @@
Audio does not loop.
</constant>
<constant name="LOOP_FORWARD" value="1" enum="LoopMode">
- Audio loops the data between [member loop_begin] and [member loop_end] playing forward only.
+ Audio loops the data between [member loop_begin] and [member loop_end], playing forward only.
</constant>
<constant name="LOOP_PING_PONG" value="2" enum="LoopMode">
- Audio loops the data between [member loop_begin] and [member loop_end] playing back and forth.
+ Audio loops the data between [member loop_begin] and [member loop_end], playing back and forth.
</constant>
<constant name="LOOP_BACKWARD" value="3" enum="LoopMode">
- Audio loops the data between [member loop_begin] and [member loop_end] playing backward only.
+ Audio loops the data between [member loop_begin] and [member loop_end], playing backward only.
</constant>
</constants>
</class>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index 2147b2b4b0..5e908b0e53 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -60,6 +60,7 @@
</member>
<member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside" default="false">
If [code]true[/code], the button stays pressed when moving the cursor outside the button while pressing it.
+ [b]Note:[/b] This property only affects the button's visual appearance. Signals will be emitted at the same moment regardless of this property's value.
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
If [code]true[/code], the button's state is pressed. Means the button is pressed down or toggled (if [member toggle_mode] is active).
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index 2e4ca9677d..5bb94d2858 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -67,6 +67,7 @@
<argument index="1" name="texture" type="Texture2D">
</argument>
<description>
+ Sets the texture for the slot specified by [code]param[/code]. See [enum TextureParam] for available slots.
</description>
</method>
</methods>
@@ -305,6 +306,8 @@
<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>
<member name="subsurf_scatter_strength" type="float" setter="set_subsurface_scattering_strength" getter="get_subsurface_scattering_strength">
The strength of the subsurface scattering effect.
</member>
@@ -425,8 +428,10 @@
Represents the size of the [enum TextureParam] enum.
</constant>
<constant name="TEXTURE_FILTER_NEAREST" value="0" enum="TextureFilter">
+ The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering, but the texture will look pixelized.
</constant>
<constant name="TEXTURE_FILTER_LINEAR" value="1" enum="TextureFilter">
+ The texture filter blends between the nearest four pixels. Use this for most cases where you want to avoid a pixelated style.
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="2" enum="TextureFilter">
</constant>
@@ -437,6 +442,7 @@
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
</constant>
<constant name="TEXTURE_FILTER_MAX" value="6" enum="TextureFilter">
+ Represents the size of the [enum TextureFilter] enum.
</constant>
<constant name="DETAIL_UV_1" value="0" enum="DetailUV">
Use [code]UV[/code] with the detail texture.
@@ -445,22 +451,29 @@
Use [code]UV2[/code] with the detail texture.
</constant>
<constant name="TRANSPARENCY_DISABLED" value="0" enum="Transparency">
+ The material will not use transparency.
</constant>
<constant name="TRANSPARENCY_ALPHA" value="1" enum="Transparency">
+ The material will use the texture's alpha values for transparency.
</constant>
<constant name="TRANSPARENCY_ALPHA_SCISSOR" value="2" enum="Transparency">
</constant>
<constant name="TRANSPARENCY_ALPHA_DEPTH_PRE_PASS" value="3" enum="Transparency">
</constant>
<constant name="TRANSPARENCY_MAX" value="4" enum="Transparency">
+ Represents the size of the [enum Transparency] enum.
</constant>
<constant name="SHADING_MODE_UNSHADED" value="0" enum="ShadingMode">
+ The object will not receive shadows.
</constant>
<constant name="SHADING_MODE_PER_PIXEL" value="1" enum="ShadingMode">
+ The object will be shaded per pixel. Useful for realistic shading effect.
</constant>
<constant name="SHADING_MODE_PER_VERTEX" value="2" enum="ShadingMode">
+ The object will be shaded per vertex. Useful when you want cheaper shaders and do not care about visual quality.
</constant>
<constant name="SHADING_MODE_MAX" value="3" enum="ShadingMode">
+ Represents the size of the [enum ShadingMode] enum.
</constant>
<constant name="FEATURE_EMISSION" value="0" enum="Feature">
Constant for setting [member emission_enabled].
@@ -580,7 +593,9 @@
<constant name="FLAG_INVERT_HEIGHTMAP" value="17" enum="Flags">
Invert values read from a depth texture to convert them to height values (heightmap).
</constant>
- <constant name="FLAG_MAX" value="18" enum="Flags">
+ <constant name="FLAG_SUBSURFACE_MODE_SKIN" value="18" enum="Flags">
+ </constant>
+ <constant name="FLAG_MAX" value="19" enum="Flags">
Represents the size of the [enum Flags] enum.
</constant>
<constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode">
@@ -623,8 +638,8 @@
The object's X axis will always face the camera.
</constant>
<constant name="BILLBOARD_PARTICLES" value="3" enum="BillboardMode">
- Used for particle systems when assigned to [Particles] and [CPUParticles] nodes. Enables [code]particles_anim_*[/code] properties.
- The [member ParticlesMaterial.anim_speed] or [member CPUParticles.anim_speed] should also be set to a positive value for the animation to play.
+ Used for particle systems when assigned to [GPUParticles3D] and [CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties.
+ The [member ParticlesMaterial.anim_speed] or [member CPUParticles3D.anim_speed] should also be set to a positive value for the animation to play.
</constant>
<constant name="TEXTURE_CHANNEL_RED" value="0" enum="TextureChannel">
Used to read from the red channel of a texture.
diff --git a/doc/classes/BoneAttachment.xml b/doc/classes/BoneAttachment.xml
deleted file mode 100644
index d15322254b..0000000000
--- a/doc/classes/BoneAttachment.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoneAttachment" inherits="Spatial" version="4.0">
- <brief_description>
- A node that will attach to a bone.
- </brief_description>
- <description>
- This node must be the child of a [Skeleton] node. You can then select a bone for this node to attach to. The BoneAttachment node will copy the transform of the selected bone.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
- The name of the attached bone.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
new file mode 100644
index 0000000000..ab1e5b17d9
--- /dev/null
+++ b/doc/classes/BoneAttachment3D.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="BoneAttachment3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ A node that will attach to a bone.
+ </brief_description>
+ <description>
+ This node must be the child of a [Skeleton3D] node. You can then select a bone for this node to attach to. The BoneAttachment3D node will copy the transform of the selected bone.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
+ The name of the attached bone.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/BoxShape.xml b/doc/classes/BoxShape.xml
deleted file mode 100644
index 3a5f05ef79..0000000000
--- a/doc/classes/BoxShape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BoxShape" inherits="Shape" version="4.0">
- <brief_description>
- Box shape resource.
- </brief_description>
- <description>
- 3D box shape that can be a child of a [PhysicsBody] or [Area].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )">
- The box's half extents. The width, height and depth of this shape is twice the half extents.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/BoxShape3D.xml b/doc/classes/BoxShape3D.xml
new file mode 100644
index 0000000000..fd08da148d
--- /dev/null
+++ b/doc/classes/BoxShape3D.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="BoxShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Box shape resource.
+ </brief_description>
+ <description>
+ 3D box shape that can be a child of a [PhysicsBody3D] or [Area3D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )">
+ The box's half extents. The width, height and depth of this shape is twice the half extents.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CPUParticles.xml b/doc/classes/CPUParticles.xml
deleted file mode 100644
index 6a6525e99a..0000000000
--- a/doc/classes/CPUParticles.xml
+++ /dev/null
@@ -1,385 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CPUParticles" inherits="GeometryInstance" version="4.0">
- <brief_description>
- CPU-based 3D particle emitter.
- </brief_description>
- <description>
- CPU-based 3D particle node used to create a variety of particle systems and effects.
- See also [Particles], which provides the same functionality with hardware acceleration, but may not run on older devices.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="convert_from_particles">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="Node">
- </argument>
- <description>
- Sets this node's properties to match a given [Particles] node with an assigned [ParticlesMaterial].
- </description>
- </method>
- <method name="get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="CPUParticles.Parameter">
- </argument>
- <description>
- Returns the base value of the parameter specified by [enum Parameter].
- </description>
- </method>
- <method name="get_param_curve" qualifiers="const">
- <return type="Curve">
- </return>
- <argument index="0" name="param" type="int" enum="CPUParticles.Parameter">
- </argument>
- <description>
- Returns the [Curve] of the parameter specified by [enum Parameter].
- </description>
- </method>
- <method name="get_param_randomness" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="CPUParticles.Parameter">
- </argument>
- <description>
- Returns the randomness factor of the parameter specified by [enum Parameter].
- </description>
- </method>
- <method name="get_particle_flag" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int" enum="CPUParticles.Flags">
- </argument>
- <description>
- Returns the enabled state of the given flag (see [enum Flags] for options).
- </description>
- </method>
- <method name="restart">
- <return type="void">
- </return>
- <description>
- Restarts the particle emitter.
- </description>
- </method>
- <method name="set_param">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="CPUParticles.Parameter">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- Sets the base value of the parameter specified by [enum Parameter].
- </description>
- </method>
- <method name="set_param_curve">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="CPUParticles.Parameter">
- </argument>
- <argument index="1" name="curve" type="Curve">
- </argument>
- <description>
- Sets the [Curve] of the parameter specified by [enum Parameter].
- </description>
- </method>
- <method name="set_param_randomness">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="CPUParticles.Parameter">
- </argument>
- <argument index="1" name="randomness" type="float">
- </argument>
- <description>
- Sets the randomness factor of the parameter specified by [enum Parameter].
- </description>
- </method>
- <method name="set_particle_flag">
- <return type="void">
- </return>
- <argument index="0" name="flag" type="int" enum="CPUParticles.Flags">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Enables or disables the given flag (see [enum Flags] for options).
- </description>
- </method>
- </methods>
- <members>
- <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
- Number of particles emitted in one emission cycle.
- </member>
- <member name="angle" type="float" setter="set_param" getter="get_param" default="0.0">
- Initial rotation applied to each particle, in degrees.
- </member>
- <member name="angle_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's rotation will be animated along this [Curve].
- </member>
- <member name="angle_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Rotation randomness ratio.
- </member>
- <member name="angular_velocity" type="float" setter="set_param" getter="get_param" default="0.0">
- Initial angular velocity applied to each particle. Sets the speed of rotation of the particle.
- </member>
- <member name="angular_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's angular velocity will vary along this [Curve].
- </member>
- <member name="angular_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Angular velocity randomness ratio.
- </member>
- <member name="anim_offset" type="float" setter="set_param" getter="get_param" default="0.0">
- Particle animation offset.
- </member>
- <member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's animation offset will vary along this [Curve].
- </member>
- <member name="anim_offset_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Animation offset randomness ratio.
- </member>
- <member name="anim_speed" type="float" setter="set_param" getter="get_param" default="0.0">
- Particle animation speed.
- </member>
- <member name="anim_speed_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's animation speed will vary along this [Curve].
- </member>
- <member name="anim_speed_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Animation speed randomness ratio.
- </member>
- <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )">
- Unused for 3D particles.
- </member>
- <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
- Unused for 3D particles.
- </member>
- <member name="damping" type="float" setter="set_param" getter="get_param" default="0.0">
- The rate at which particles lose velocity.
- </member>
- <member name="damping_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Damping will vary along this [Curve].
- </member>
- <member name="damping_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Damping randomness ratio.
- </member>
- <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3( 1, 0, 0 )">
- Unit vector specifying the particles' emission direction.
- </member>
- <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="CPUParticles.DrawOrder" default="0">
- Particle draw order. Uses [enum DrawOrder] values.
- </member>
- <member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents">
- The rectangle's extents if [member emission_shape] is set to [constant EMISSION_SHAPE_BOX].
- </member>
- <member name="emission_colors" type="PackedColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PackedColorArray( )">
- Sets the [Color]s to modulate particles by when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
- </member>
- <member name="emission_normals" type="PackedVector3Array" setter="set_emission_normals" getter="get_emission_normals">
- Sets the direction the particles will be emitted in when using [constant EMISSION_SHAPE_DIRECTED_POINTS].
- </member>
- <member name="emission_points" type="PackedVector3Array" setter="set_emission_points" getter="get_emission_points" default="PackedVector3Array( )">
- Sets the initial positions to spawn particles when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
- </member>
- <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="CPUParticles.EmissionShape" default="0">
- Particles will be emitted inside this region. See [enum EmissionShape] for possible values.
- </member>
- <member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius">
- The sphere's radius if [enum EmissionShape] is set to [constant EMISSION_SHAPE_SPHERE].
- </member>
- <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
- If [code]true[/code], particles are being emitted.
- </member>
- <member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
- How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
- </member>
- <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
- 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 particle system itself.
- </member>
- <member name="flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
- Align Y axis of particle with the direction of its velocity.
- </member>
- <member name="flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
- If [code]true[/code], particles will not move on the z axis.
- </member>
- <member name="flag_rotate_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
- If [code]true[/code], particles rotate around Y axis by [member angle].
- </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.
- </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="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )">
- Gravity applied to every particle.
- </member>
- <member name="hue_variation" type="float" setter="set_param" getter="get_param" default="0.0">
- Initial hue variation applied to each particle.
- </member>
- <member name="hue_variation_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's hue will vary along this [Curve].
- </member>
- <member name="hue_variation_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Hue variation randomness ratio.
- </member>
- <member name="initial_velocity" type="float" setter="set_param" getter="get_param" default="0.0">
- Initial velocity magnitude for each particle. Direction comes from [member spread] and the node's orientation.
- </member>
- <member name="initial_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Initial velocity randomness ratio.
- </member>
- <member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
- Amount of time each particle will exist.
- </member>
- <member name="lifetime_randomness" type="float" setter="set_lifetime_randomness" getter="get_lifetime_randomness" default="0.0">
- Particle lifetime randomness ratio.
- </member>
- <member name="linear_accel" type="float" setter="set_param" getter="get_param" default="0.0">
- Linear acceleration applied to each particle in the direction of motion.
- </member>
- <member name="linear_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's linear acceleration will vary along this [Curve].
- </member>
- <member name="linear_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Linear acceleration randomness ratio.
- </member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
- </member>
- <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
- The [Mesh] used for each particle. If [code]null[/code], particles will be spheres.
- </member>
- <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
- If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
- </member>
- <member name="orbit_velocity" type="float" setter="set_param" getter="get_param">
- Orbital velocity applied to each particle. Makes the particles circle around origin in the local XY plane. Specified in number of full rotations around origin per second.
- This property is only available when [member flag_disable_z] is [code]true[/code].
- </member>
- <member name="orbit_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's orbital velocity will vary along this [Curve].
- </member>
- <member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness">
- Orbital velocity randomness ratio.
- </member>
- <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
- Particle system starts as if it had already run for this many seconds.
- </member>
- <member name="radial_accel" type="float" setter="set_param" getter="get_param" default="0.0">
- Radial acceleration applied to each particle. Makes particle accelerate away from origin.
- </member>
- <member name="radial_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's radial acceleration will vary along this [Curve].
- </member>
- <member name="radial_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Radial acceleration randomness ratio.
- </member>
- <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
- Emission lifetime randomness ratio.
- </member>
- <member name="scale_amount" type="float" setter="set_param" getter="get_param" default="1.0">
- Initial scale applied to each particle.
- </member>
- <member name="scale_amount_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's scale will vary along this [Curve].
- </member>
- <member name="scale_amount_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Scale randomness ratio.
- </member>
- <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
- </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.
- </member>
- <member name="tangential_accel" type="float" setter="set_param" getter="get_param" default="0.0">
- Tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion.
- </member>
- <member name="tangential_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
- Each particle's tangential acceleration will vary along this [Curve].
- </member>
- <member name="tangential_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
- Tangential acceleration randomness ratio.
- </member>
- </members>
- <constants>
- <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
- Particles are drawn in the order emitted.
- </constant>
- <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
- Particles are drawn in order of remaining lifetime.
- </constant>
- <constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
- Particles are drawn in order of depth.
- </constant>
- <constant name="PARAM_INITIAL_LINEAR_VELOCITY" value="0" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set initial velocity properties.
- </constant>
- <constant name="PARAM_ANGULAR_VELOCITY" value="1" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set angular velocity properties.
- </constant>
- <constant name="PARAM_ORBIT_VELOCITY" value="2" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set orbital velocity properties.
- </constant>
- <constant name="PARAM_LINEAR_ACCEL" value="3" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set linear acceleration properties.
- </constant>
- <constant name="PARAM_RADIAL_ACCEL" value="4" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set radial acceleration properties.
- </constant>
- <constant name="PARAM_TANGENTIAL_ACCEL" value="5" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set tangential acceleration properties.
- </constant>
- <constant name="PARAM_DAMPING" value="6" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set damping properties.
- </constant>
- <constant name="PARAM_ANGLE" value="7" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set angle properties.
- </constant>
- <constant name="PARAM_SCALE" value="8" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set scale properties.
- </constant>
- <constant name="PARAM_HUE_VARIATION" value="9" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set hue variation properties.
- </constant>
- <constant name="PARAM_ANIM_SPEED" value="10" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set animation speed properties.
- </constant>
- <constant name="PARAM_ANIM_OFFSET" value="11" enum="Parameter">
- Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set animation offset properties.
- </constant>
- <constant name="PARAM_MAX" value="12" enum="Parameter">
- Represents the size of the [enum Parameter] enum.
- </constant>
- <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags">
- Use with [method set_particle_flag] to set [member flag_align_y].
- </constant>
- <constant name="FLAG_ROTATE_Y" value="1" enum="Flags">
- Use with [method set_particle_flag] to set [member flag_rotate_y].
- </constant>
- <constant name="FLAG_DISABLE_Z" value="2" enum="Flags">
- Use with [method set_particle_flag] to set [member flag_disable_z].
- </constant>
- <constant name="FLAG_MAX" value="3" enum="Flags">
- Represents the size of the [enum Flags] enum.
- </constant>
- <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">
- All particles will be emitted from a single point.
- </constant>
- <constant name="EMISSION_SHAPE_SPHERE" value="1" enum="EmissionShape">
- Particles will be emitted in the volume of a sphere.
- </constant>
- <constant name="EMISSION_SHAPE_BOX" value="2" enum="EmissionShape">
- Particles will be emitted in the volume of a box.
- </constant>
- <constant name="EMISSION_SHAPE_POINTS" value="3" enum="EmissionShape">
- Particles will be emitted at a position chosen randomly among [member emission_points]. Particle color will be modulated by [member emission_colors].
- </constant>
- <constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape">
- Particles will be emitted at a position chosen randomly among [member emission_points]. Particle velocity and rotation will be set based on [member emission_normals]. Particle color will be modulated by [member emission_colors].
- </constant>
- <constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape">
- Represents the size of the [enum EmissionShape] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 799ba32075..c2b821699d 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
CPU-based 2D particle node used to create a variety of particle systems and effects.
- See also [Particles2D], which provides the same functionality with hardware acceleration, but may not run on older devices.
+ See also [GPUParticles2D], which provides the same functionality with hardware acceleration, but may not run on older devices.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
@@ -17,7 +17,7 @@
<argument index="0" name="particles" type="Node">
</argument>
<description>
- Sets this node's properties to match a given [Particles2D] node with an assigned [ParticlesMaterial].
+ Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticlesMaterial].
</description>
</method>
<method name="get_param" qualifiers="const">
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
new file mode 100644
index 0000000000..07da066bd9
--- /dev/null
+++ b/doc/classes/CPUParticles3D.xml
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CPUParticles3D" inherits="GeometryInstance3D" version="4.0">
+ <brief_description>
+ CPU-based 3D particle emitter.
+ </brief_description>
+ <description>
+ CPU-based 3D particle node used to create a variety of particle systems and effects.
+ See also [GPUParticles3D], which provides the same functionality with hardware acceleration, but may not run on older devices.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="convert_from_particles">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="Node">
+ </argument>
+ <description>
+ Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticlesMaterial].
+ </description>
+ </method>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter">
+ </argument>
+ <description>
+ Returns the base value of the parameter specified by [enum Parameter].
+ </description>
+ </method>
+ <method name="get_param_curve" qualifiers="const">
+ <return type="Curve">
+ </return>
+ <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter">
+ </argument>
+ <description>
+ Returns the [Curve] of the parameter specified by [enum Parameter].
+ </description>
+ </method>
+ <method name="get_param_randomness" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter">
+ </argument>
+ <description>
+ Returns the randomness factor of the parameter specified by [enum Parameter].
+ </description>
+ </method>
+ <method name="get_particle_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="CPUParticles3D.Flags">
+ </argument>
+ <description>
+ Returns the enabled state of the given flag (see [enum Flags] for options).
+ </description>
+ </method>
+ <method name="restart">
+ <return type="void">
+ </return>
+ <description>
+ Restarts the particle emitter.
+ </description>
+ </method>
+ <method name="set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ Sets the base value of the parameter specified by [enum Parameter].
+ </description>
+ </method>
+ <method name="set_param_curve">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter">
+ </argument>
+ <argument index="1" name="curve" type="Curve">
+ </argument>
+ <description>
+ Sets the [Curve] of the parameter specified by [enum Parameter].
+ </description>
+ </method>
+ <method name="set_param_randomness">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter">
+ </argument>
+ <argument index="1" name="randomness" type="float">
+ </argument>
+ <description>
+ Sets the randomness factor of the parameter specified by [enum Parameter].
+ </description>
+ </method>
+ <method name="set_particle_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="CPUParticles3D.Flags">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ Enables or disables the given flag (see [enum Flags] for options).
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
+ Number of particles emitted in one emission cycle.
+ </member>
+ <member name="angle" type="float" setter="set_param" getter="get_param" default="0.0">
+ Initial rotation applied to each particle, in degrees.
+ </member>
+ <member name="angle_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's rotation will be animated along this [Curve].
+ </member>
+ <member name="angle_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Rotation randomness ratio.
+ </member>
+ <member name="angular_velocity" type="float" setter="set_param" getter="get_param" default="0.0">
+ Initial angular velocity applied to each particle. Sets the speed of rotation of the particle.
+ </member>
+ <member name="angular_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's angular velocity will vary along this [Curve].
+ </member>
+ <member name="angular_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Angular velocity randomness ratio.
+ </member>
+ <member name="anim_offset" type="float" setter="set_param" getter="get_param" default="0.0">
+ Particle animation offset.
+ </member>
+ <member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's animation offset will vary along this [Curve].
+ </member>
+ <member name="anim_offset_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Animation offset randomness ratio.
+ </member>
+ <member name="anim_speed" type="float" setter="set_param" getter="get_param" default="0.0">
+ Particle animation speed.
+ </member>
+ <member name="anim_speed_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's animation speed will vary along this [Curve].
+ </member>
+ <member name="anim_speed_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Animation speed randomness ratio.
+ </member>
+ <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )">
+ Unused for 3D particles.
+ </member>
+ <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
+ Unused for 3D particles.
+ </member>
+ <member name="damping" type="float" setter="set_param" getter="get_param" default="0.0">
+ The rate at which particles lose velocity.
+ </member>
+ <member name="damping_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Damping will vary along this [Curve].
+ </member>
+ <member name="damping_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Damping randomness ratio.
+ </member>
+ <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3( 1, 0, 0 )">
+ Unit vector specifying the particles' emission direction.
+ </member>
+ <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="CPUParticles3D.DrawOrder" default="0">
+ Particle draw order. Uses [enum DrawOrder] values.
+ </member>
+ <member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents">
+ The rectangle's extents if [member emission_shape] is set to [constant EMISSION_SHAPE_BOX].
+ </member>
+ <member name="emission_colors" type="PackedColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PackedColorArray( )">
+ Sets the [Color]s to modulate particles by when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
+ </member>
+ <member name="emission_normals" type="PackedVector3Array" setter="set_emission_normals" getter="get_emission_normals">
+ Sets the direction the particles will be emitted in when using [constant EMISSION_SHAPE_DIRECTED_POINTS].
+ </member>
+ <member name="emission_points" type="PackedVector3Array" setter="set_emission_points" getter="get_emission_points" default="PackedVector3Array( )">
+ Sets the initial positions to spawn particles when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
+ </member>
+ <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="CPUParticles3D.EmissionShape" default="0">
+ Particles will be emitted inside this region. See [enum EmissionShape] for possible values.
+ </member>
+ <member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius">
+ The sphere's radius if [enum EmissionShape] is set to [constant EMISSION_SHAPE_SPHERE].
+ </member>
+ <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
+ If [code]true[/code], particles are being emitted.
+ </member>
+ <member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
+ How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
+ </member>
+ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
+ 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 particle system itself.
+ </member>
+ <member name="flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
+ Align Y axis of particle with the direction of its velocity.
+ </member>
+ <member name="flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
+ If [code]true[/code], particles will not move on the z axis.
+ </member>
+ <member name="flag_rotate_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
+ If [code]true[/code], particles rotate around Y axis by [member angle].
+ </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.
+ </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="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )">
+ Gravity applied to every particle.
+ </member>
+ <member name="hue_variation" type="float" setter="set_param" getter="get_param" default="0.0">
+ Initial hue variation applied to each particle.
+ </member>
+ <member name="hue_variation_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's hue will vary along this [Curve].
+ </member>
+ <member name="hue_variation_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Hue variation randomness ratio.
+ </member>
+ <member name="initial_velocity" type="float" setter="set_param" getter="get_param" default="0.0">
+ Initial velocity magnitude for each particle. Direction comes from [member spread] and the node's orientation.
+ </member>
+ <member name="initial_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Initial velocity randomness ratio.
+ </member>
+ <member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
+ Amount of time each particle will exist.
+ </member>
+ <member name="lifetime_randomness" type="float" setter="set_lifetime_randomness" getter="get_lifetime_randomness" default="0.0">
+ Particle lifetime randomness ratio.
+ </member>
+ <member name="linear_accel" type="float" setter="set_param" getter="get_param" default="0.0">
+ Linear acceleration applied to each particle in the direction of motion.
+ </member>
+ <member name="linear_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's linear acceleration will vary along this [Curve].
+ </member>
+ <member name="linear_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Linear acceleration randomness ratio.
+ </member>
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
+ If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ </member>
+ <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
+ The [Mesh] used for each particle. If [code]null[/code], particles will be spheres.
+ </member>
+ <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
+ If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
+ </member>
+ <member name="orbit_velocity" type="float" setter="set_param" getter="get_param">
+ Orbital velocity applied to each particle. Makes the particles circle around origin in the local XY plane. Specified in number of full rotations around origin per second.
+ This property is only available when [member flag_disable_z] is [code]true[/code].
+ </member>
+ <member name="orbit_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's orbital velocity will vary along this [Curve].
+ </member>
+ <member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness">
+ Orbital velocity randomness ratio.
+ </member>
+ <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
+ Particle system starts as if it had already run for this many seconds.
+ </member>
+ <member name="radial_accel" type="float" setter="set_param" getter="get_param" default="0.0">
+ Radial acceleration applied to each particle. Makes particle accelerate away from origin.
+ </member>
+ <member name="radial_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's radial acceleration will vary along this [Curve].
+ </member>
+ <member name="radial_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Radial acceleration randomness ratio.
+ </member>
+ <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
+ Emission lifetime randomness ratio.
+ </member>
+ <member name="scale_amount" type="float" setter="set_param" getter="get_param" default="1.0">
+ Initial scale applied to each particle.
+ </member>
+ <member name="scale_amount_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's scale will vary along this [Curve].
+ </member>
+ <member name="scale_amount_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Scale randomness ratio.
+ </member>
+ <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
+ Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
+ </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.
+ </member>
+ <member name="tangential_accel" type="float" setter="set_param" getter="get_param" default="0.0">
+ Tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion.
+ </member>
+ <member name="tangential_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
+ Each particle's tangential acceleration will vary along this [Curve].
+ </member>
+ <member name="tangential_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
+ Tangential acceleration randomness ratio.
+ </member>
+ </members>
+ <constants>
+ <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
+ Particles are drawn in the order emitted.
+ </constant>
+ <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
+ Particles are drawn in order of remaining lifetime.
+ </constant>
+ <constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
+ Particles are drawn in order of depth.
+ </constant>
+ <constant name="PARAM_INITIAL_LINEAR_VELOCITY" value="0" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set initial velocity properties.
+ </constant>
+ <constant name="PARAM_ANGULAR_VELOCITY" value="1" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set angular velocity properties.
+ </constant>
+ <constant name="PARAM_ORBIT_VELOCITY" value="2" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set orbital velocity properties.
+ </constant>
+ <constant name="PARAM_LINEAR_ACCEL" value="3" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set linear acceleration properties.
+ </constant>
+ <constant name="PARAM_RADIAL_ACCEL" value="4" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set radial acceleration properties.
+ </constant>
+ <constant name="PARAM_TANGENTIAL_ACCEL" value="5" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set tangential acceleration properties.
+ </constant>
+ <constant name="PARAM_DAMPING" value="6" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set damping properties.
+ </constant>
+ <constant name="PARAM_ANGLE" value="7" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set angle properties.
+ </constant>
+ <constant name="PARAM_SCALE" value="8" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set scale properties.
+ </constant>
+ <constant name="PARAM_HUE_VARIATION" value="9" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set hue variation properties.
+ </constant>
+ <constant name="PARAM_ANIM_SPEED" value="10" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set animation speed properties.
+ </constant>
+ <constant name="PARAM_ANIM_OFFSET" value="11" enum="Parameter">
+ Use with [method set_param], [method set_param_randomness], and [method set_param_curve] to set animation offset properties.
+ </constant>
+ <constant name="PARAM_MAX" value="12" enum="Parameter">
+ Represents the size of the [enum Parameter] enum.
+ </constant>
+ <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags">
+ Use with [method set_particle_flag] to set [member flag_align_y].
+ </constant>
+ <constant name="FLAG_ROTATE_Y" value="1" enum="Flags">
+ Use with [method set_particle_flag] to set [member flag_rotate_y].
+ </constant>
+ <constant name="FLAG_DISABLE_Z" value="2" enum="Flags">
+ Use with [method set_particle_flag] to set [member flag_disable_z].
+ </constant>
+ <constant name="FLAG_MAX" value="3" enum="Flags">
+ Represents the size of the [enum Flags] enum.
+ </constant>
+ <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape">
+ All particles will be emitted from a single point.
+ </constant>
+ <constant name="EMISSION_SHAPE_SPHERE" value="1" enum="EmissionShape">
+ Particles will be emitted in the volume of a sphere.
+ </constant>
+ <constant name="EMISSION_SHAPE_BOX" value="2" enum="EmissionShape">
+ Particles will be emitted in the volume of a box.
+ </constant>
+ <constant name="EMISSION_SHAPE_POINTS" value="3" enum="EmissionShape">
+ Particles will be emitted at a position chosen randomly among [member emission_points]. Particle color will be modulated by [member emission_colors].
+ </constant>
+ <constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape">
+ Particles will be emitted at a position chosen randomly among [member emission_points]. Particle velocity and rotation will be set based on [member emission_normals]. Particle color will be modulated by [member emission_colors].
+ </constant>
+ <constant name="EMISSION_SHAPE_MAX" value="5" enum="EmissionShape">
+ Represents the size of the [enum EmissionShape] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index ec38128c1e..3cc74beb58 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -1,8 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Callable" version="4.0">
<brief_description>
+ An object representing a method in a certain object that can be called.
</brief_description>
<description>
+ [Callable] is a first class object which can be held in variables and passed to functions. It represents a given method in an [Object], and is typically used for signal callbacks.
+ [b]Example:[/b]
+ [codeblock]
+ 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".
+ 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.
+ [/codeblock]
</description>
<tutorials>
</tutorials>
@@ -15,36 +27,42 @@
<argument index="1" name="method_name" type="StringName">
</argument>
<description>
+ Creates a new [Callable] for the method called [code]method_name[/code] in the specified [code]object[/code].
</description>
</method>
<method name="call" qualifiers="vararg">
<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">
<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">
<return type="StringName">
</return>
<description>
+ Returns the name of the method represented by this [Callable].
</description>
</method>
<method name="get_object">
<return type="Object">
</return>
<description>
+ Returns the object on which this [Callable] is called.
</description>
</method>
<method name="get_object_id">
<return type="int">
</return>
<description>
+ Returns the ID of this [Callable]'s object (see [method Object.get_instance_id]).
</description>
</method>
<method name="hash">
diff --git a/doc/classes/Camera.xml b/doc/classes/Camera.xml
deleted file mode 100644
index 6097721cbd..0000000000
--- a/doc/classes/Camera.xml
+++ /dev/null
@@ -1,237 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Camera" inherits="Spatial" version="4.0">
- <brief_description>
- Camera node, displays from a point of view.
- </brief_description>
- <description>
- Camera is a special node that displays what is visible from its current location. Cameras register themselves in the nearest [Viewport] node (when ascending the tree). Only one camera can be active per viewport. If no viewport is available ascending the tree, the camera will register in the global viewport. In other words, a camera just provides 3D display capabilities to a [Viewport], and, without one, a scene registered in that [Viewport] (or higher viewports) can't be displayed.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="clear_current">
- <return type="void">
- </return>
- <argument index="0" name="enable_next" type="bool" default="true">
- </argument>
- <description>
- If this is the current camera, remove it from being current. If [code]enable_next[/code] is [code]true[/code], request to make the next camera current, if any.
- </description>
- </method>
- <method name="get_camera_rid" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Returns the camera's RID from the [VisualServer].
- </description>
- </method>
- <method name="get_camera_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <description>
- Gets the camera transform. Subclassed cameras such as [InterpolatedCamera] may provide different transforms than the [Node] transform.
- </description>
- </method>
- <method name="get_cull_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="layer" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the given [code]layer[/code] in the [member cull_mask] is enabled, [code]false[/code] otherwise.
- </description>
- </method>
- <method name="get_frustum" qualifiers="const">
- <return type="Array">
- </return>
- <description>
- Returns the camera's frustum planes in world-space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset].
- </description>
- </method>
- <method name="is_position_behind" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="world_point" type="Vector3">
- </argument>
- <description>
- Returns [code]true[/code] if the given position is behind the camera.
- [b]Note:[/b] A position which returns [code]false[/code] may still be outside the camera's field of view.
- </description>
- </method>
- <method name="make_current">
- <return type="void">
- </return>
- <description>
- Makes this camera the current camera for the [Viewport] (see class description). If the camera node is outside the scene tree, it will attempt to become current once it's added.
- </description>
- </method>
- <method name="project_local_ray_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- Returns a normal vector from the screen point location directed along the camera. Orthogonal cameras are normalized. Perspective cameras account for perspective, screen width/height, etc.
- </description>
- </method>
- <method name="project_position" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <argument index="1" name="z_depth" type="float">
- </argument>
- <description>
- Returns the 3D point in worldspace that maps to the given 2D coordinate in the [Viewport] rectangle on a plane that is the given [code]z_depth[/code] distance into the scene away from the camera.
- </description>
- </method>
- <method name="project_ray_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- Returns a normal vector in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
- </description>
- </method>
- <method name="project_ray_origin" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- Returns a 3D position in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
- </description>
- </method>
- <method name="set_cull_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="layer" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Enables or disables the given [code]layer[/code] in the [member cull_mask].
- </description>
- </method>
- <method name="set_frustum">
- <return type="void">
- </return>
- <argument index="0" name="size" type="float">
- </argument>
- <argument index="1" name="offset" type="Vector2">
- </argument>
- <argument index="2" name="z_near" type="float">
- </argument>
- <argument index="3" name="z_far" type="float">
- </argument>
- <description>
- Sets the camera projection to frustum mode (see [constant PROJECTION_FRUSTUM]), by specifying a [code]size[/code], an [code]offset[/code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in world-space units.
- </description>
- </method>
- <method name="set_orthogonal">
- <return type="void">
- </return>
- <argument index="0" name="size" type="float">
- </argument>
- <argument index="1" name="z_near" type="float">
- </argument>
- <argument index="2" name="z_far" type="float">
- </argument>
- <description>
- Sets the camera projection to orthogonal mode (see [constant PROJECTION_ORTHOGONAL]), by specifying a [code]size[/code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in world-space units. (As a hint, 2D games often use this projection, with values specified in pixels.)
- </description>
- </method>
- <method name="set_perspective">
- <return type="void">
- </return>
- <argument index="0" name="fov" type="float">
- </argument>
- <argument index="1" name="z_near" type="float">
- </argument>
- <argument index="2" name="z_far" type="float">
- </argument>
- <description>
- Sets the camera projection to perspective mode (see [constant PROJECTION_PERSPECTIVE]), by specifying a [code]fov[/code] (field of view) angle in degrees, and the [code]z_near[/code] and [code]z_far[/code] clip planes in world-space units.
- </description>
- </method>
- <method name="unproject_position" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="world_point" type="Vector3">
- </argument>
- <description>
- Returns the 2D coordinate in the [Viewport] rectangle that maps to the given 3D point in worldspace.
- </description>
- </method>
- </methods>
- <members>
- <member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
- The culling mask that describes which 3D render layers are rendered by this camera.
- </member>
- <member name="current" type="bool" setter="set_current" getter="is_current" default="false">
- If [code]true[/code], the ancestor [Viewport] is currently using this camera.
- </member>
- <member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="Camera.DopplerTracking" default="0">
- If not [constant DOPPLER_TRACKING_DISABLED], this camera will simulate the [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] for objects changed in particular [code]_process[/code] methods. See [enum DopplerTracking] for possible values.
- </member>
- <member name="effects" type="CameraEffects" setter="set_effects" getter="get_effects">
- </member>
- <member name="environment" type="Environment" setter="set_environment" getter="get_environment">
- The [Environment] to use for this camera.
- </member>
- <member name="far" type="float" setter="set_zfar" getter="get_zfar" default="100.0">
- The distance to the far culling boundary for this camera relative to its local Z axis.
- </member>
- <member name="fov" type="float" setter="set_fov" getter="get_fov" default="70.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.
- </member>
- <member name="frustum_offset" type="Vector2" setter="set_frustum_offset" getter="get_frustum_offset" default="Vector2( 0, 0 )">
- The camera's frustum offset. This can be changed from the default to create "tilted frustum" effects such as [url=https://zdoom.org/wiki/Y-shearing]Y-shearing[/url].
- </member>
- <member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0">
- The horizontal (X) offset of the camera viewport.
- </member>
- <member name="keep_aspect" type="int" setter="set_keep_aspect_mode" getter="get_keep_aspect_mode" enum="Camera.KeepAspect" default="1">
- The axis to lock during [member fov]/[member size] adjustments. Can be either [constant KEEP_WIDTH] or [constant KEEP_HEIGHT].
- </member>
- <member name="near" type="float" setter="set_znear" getter="get_znear" default="0.05">
- The distance to the near culling boundary for this camera relative to its local Z axis.
- </member>
- <member name="projection" type="int" setter="set_projection" getter="get_projection" enum="Camera.Projection" default="0">
- The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, objects' Z distance from the camera's local space scales their perceived size.
- </member>
- <member name="size" type="float" setter="set_size" getter="get_size" default="1.0">
- The camera's size measured as 1/2 the width or height. Only applicable in orthogonal mode. Since [member keep_aspect] locks on axis, [code]size[/code] sets the other axis' size length.
- </member>
- <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
- The vertical (Y) offset of the camera viewport.
- </member>
- </members>
- <constants>
- <constant name="PROJECTION_PERSPECTIVE" value="0" enum="Projection">
- Perspective projection. Objects on the screen becomes smaller when they are far away.
- </constant>
- <constant name="PROJECTION_ORTHOGONAL" value="1" enum="Projection">
- Orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are.
- </constant>
- <constant name="PROJECTION_FRUSTUM" value="2" enum="Projection">
- Frustum projection. This mode allows adjusting [member frustum_offset] to create "tilted frustum" effects.
- </constant>
- <constant name="KEEP_WIDTH" value="0" enum="KeepAspect">
- Preserves the horizontal aspect ratio; also known as Vert- scaling. This is usually the best option for projects running in portrait mode, as taller aspect ratios will benefit from a wider vertical FOV.
- </constant>
- <constant name="KEEP_HEIGHT" value="1" enum="KeepAspect">
- Preserves the vertical aspect ratio; also known as Hor+ scaling. This is usually the best option for projects running in landscape mode, as wider aspect ratios will automatically benefit from a wider horizontal FOV.
- </constant>
- <constant name="DOPPLER_TRACKING_DISABLED" value="0" enum="DopplerTracking">
- Disables [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] simulation (default).
- </constant>
- <constant name="DOPPLER_TRACKING_IDLE_STEP" value="1" enum="DopplerTracking">
- Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] by tracking positions of objects that are changed in [code]_process[/code]. Changes in the relative velocity of this camera compared to those objects affect how Audio is perceived (changing the Audio's [code]pitch shift[/code]).
- </constant>
- <constant name="DOPPLER_TRACKING_PHYSICS_STEP" value="2" enum="DopplerTracking">
- Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] by tracking positions of objects that are changed in [code]_physics_process[/code]. Changes in the relative velocity of this camera compared to those objects affect how Audio is perceived (changing the Audio's [code]pitch shift[/code]).
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index 73892481e6..ad49216b34 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -5,7 +5,8 @@
</brief_description>
<description>
Camera node for 2D scenes. It forces the screen (current layer) to scroll following this node. This makes it easier (and faster) to program scrollable scenes than manually changing the position of [CanvasItem]-based nodes.
- This node is intended to be a simple helper to get things going quickly and it may happen that more functionality is desired to change how the camera works. To make your own custom camera node, simply inherit from [Node2D] and change the transform of the canvas by calling get_viewport().set_canvas_transform(m) in [Viewport].
+ This node is intended to be a simple helper to get things going quickly and it may happen that more functionality is desired to change how the camera works. To make your own custom camera node, inherit from [Node2D] and change the transform of the canvas by setting [member Viewport.canvas_transform] in [Viewport] (you can obtain the current [Viewport] by using [method Node.get_viewport]).
+ Note that the [Camera2D] node's [code]position[/code] doesn't represent the actual position of the screen, which may differ due to applied smoothing or limits. You can use [method get_camera_screen_center] to get the real position.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
new file mode 100644
index 0000000000..bfba23c7ee
--- /dev/null
+++ b/doc/classes/Camera3D.xml
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Camera3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Camera node, displays from a point of view.
+ </brief_description>
+ <description>
+ [Camera3D] is a special node that displays what is visible from its current location. Cameras register themselves in the nearest [Viewport] node (when ascending the tree). Only one camera can be active per viewport. If no viewport is available ascending the tree, the camera will register in the global viewport. In other words, a camera just provides 3D display capabilities to a [Viewport], and, without one, a scene registered in that [Viewport] (or higher viewports) can't be displayed.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="clear_current">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable_next" type="bool" default="true">
+ </argument>
+ <description>
+ If this is the current camera, remove it from being current. If [code]enable_next[/code] is [code]true[/code], request to make the next camera current, if any.
+ </description>
+ </method>
+ <method name="get_camera_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the camera's RID from the [RenderingServer].
+ </description>
+ </method>
+ <method name="get_camera_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <description>
+ Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may provide different transforms than the [Node] transform.
+ </description>
+ </method>
+ <method name="get_cull_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the given [code]layer[/code] in the [member cull_mask] is enabled, [code]false[/code] otherwise.
+ </description>
+ </method>
+ <method name="get_frustum" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Returns the camera's frustum planes in world-space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset].
+ </description>
+ </method>
+ <method name="is_position_behind" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="world_point" type="Vector3">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the given position is behind the camera.
+ [b]Note:[/b] A position which returns [code]false[/code] may still be outside the camera's field of view.
+ </description>
+ </method>
+ <method name="make_current">
+ <return type="void">
+ </return>
+ <description>
+ Makes this camera the current camera for the [Viewport] (see class description). If the camera node is outside the scene tree, it will attempt to become current once it's added.
+ </description>
+ </method>
+ <method name="project_local_ray_normal" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="screen_point" type="Vector2">
+ </argument>
+ <description>
+ Returns a normal vector from the screen point location directed along the camera. Orthogonal cameras are normalized. Perspective cameras account for perspective, screen width/height, etc.
+ </description>
+ </method>
+ <method name="project_position" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="screen_point" type="Vector2">
+ </argument>
+ <argument index="1" name="z_depth" type="float">
+ </argument>
+ <description>
+ Returns the 3D point in worldspace that maps to the given 2D coordinate in the [Viewport] rectangle on a plane that is the given [code]z_depth[/code] distance into the scene away from the camera.
+ </description>
+ </method>
+ <method name="project_ray_normal" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="screen_point" type="Vector2">
+ </argument>
+ <description>
+ Returns a normal vector in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
+ </description>
+ </method>
+ <method name="project_ray_origin" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="screen_point" type="Vector2">
+ </argument>
+ <description>
+ Returns a 3D position in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
+ </description>
+ </method>
+ <method name="set_cull_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ Enables or disables the given [code]layer[/code] in the [member cull_mask].
+ </description>
+ </method>
+ <method name="set_frustum">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="float">
+ </argument>
+ <argument index="1" name="offset" type="Vector2">
+ </argument>
+ <argument index="2" name="z_near" type="float">
+ </argument>
+ <argument index="3" name="z_far" type="float">
+ </argument>
+ <description>
+ Sets the camera projection to frustum mode (see [constant PROJECTION_FRUSTUM]), by specifying a [code]size[/code], an [code]offset[/code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in world-space units.
+ </description>
+ </method>
+ <method name="set_orthogonal">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="float">
+ </argument>
+ <argument index="1" name="z_near" type="float">
+ </argument>
+ <argument index="2" name="z_far" type="float">
+ </argument>
+ <description>
+ Sets the camera projection to orthogonal mode (see [constant PROJECTION_ORTHOGONAL]), by specifying a [code]size[/code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in world-space units. (As a hint, 2D games often use this projection, with values specified in pixels.)
+ </description>
+ </method>
+ <method name="set_perspective">
+ <return type="void">
+ </return>
+ <argument index="0" name="fov" type="float">
+ </argument>
+ <argument index="1" name="z_near" type="float">
+ </argument>
+ <argument index="2" name="z_far" type="float">
+ </argument>
+ <description>
+ Sets the camera projection to perspective mode (see [constant PROJECTION_PERSPECTIVE]), by specifying a [code]fov[/code] (field of view) angle in degrees, and the [code]z_near[/code] and [code]z_far[/code] clip planes in world-space units.
+ </description>
+ </method>
+ <method name="unproject_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="world_point" type="Vector3">
+ </argument>
+ <description>
+ Returns the 2D coordinate in the [Viewport] rectangle that maps to the given 3D point in worldspace.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
+ The culling mask that describes which 3D render layers are rendered by this camera.
+ </member>
+ <member name="current" type="bool" setter="set_current" getter="is_current" default="false">
+ If [code]true[/code], the ancestor [Viewport] is currently using this camera.
+ </member>
+ <member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="Camera3D.DopplerTracking" default="0">
+ If not [constant DOPPLER_TRACKING_DISABLED], this camera will simulate the [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] for objects changed in particular [code]_process[/code] methods. See [enum DopplerTracking] for possible values.
+ </member>
+ <member name="effects" type="CameraEffects" setter="set_effects" getter="get_effects">
+ </member>
+ <member name="environment" type="Environment" setter="set_environment" getter="get_environment">
+ The [Environment] to use for this camera.
+ </member>
+ <member name="far" type="float" setter="set_zfar" getter="get_zfar" default="100.0">
+ The distance to the far culling boundary for this camera relative to its local Z axis.
+ </member>
+ <member name="fov" type="float" setter="set_fov" getter="get_fov" default="70.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.
+ </member>
+ <member name="frustum_offset" type="Vector2" setter="set_frustum_offset" getter="get_frustum_offset" default="Vector2( 0, 0 )">
+ The camera's frustum offset. This can be changed from the default to create "tilted frustum" effects such as [url=https://zdoom.org/wiki/Y-shearing]Y-shearing[/url].
+ </member>
+ <member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0">
+ The horizontal (X) offset of the camera viewport.
+ </member>
+ <member name="keep_aspect" type="int" setter="set_keep_aspect_mode" getter="get_keep_aspect_mode" enum="Camera3D.KeepAspect" default="1">
+ The axis to lock during [member fov]/[member size] adjustments. Can be either [constant KEEP_WIDTH] or [constant KEEP_HEIGHT].
+ </member>
+ <member name="near" type="float" setter="set_znear" getter="get_znear" default="0.05">
+ The distance to the near culling boundary for this camera relative to its local Z axis.
+ </member>
+ <member name="projection" type="int" setter="set_projection" getter="get_projection" enum="Camera3D.Projection" default="0">
+ The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, objects' Z distance from the camera's local space scales their perceived size.
+ </member>
+ <member name="size" type="float" setter="set_size" getter="get_size" default="1.0">
+ The camera's size measured as 1/2 the width or height. Only applicable in orthogonal mode. Since [member keep_aspect] locks on axis, [code]size[/code] sets the other axis' size length.
+ </member>
+ <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
+ The vertical (Y) offset of the camera viewport.
+ </member>
+ </members>
+ <constants>
+ <constant name="PROJECTION_PERSPECTIVE" value="0" enum="Projection">
+ Perspective projection. Objects on the screen becomes smaller when they are far away.
+ </constant>
+ <constant name="PROJECTION_ORTHOGONAL" value="1" enum="Projection">
+ Orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are.
+ </constant>
+ <constant name="PROJECTION_FRUSTUM" value="2" enum="Projection">
+ Frustum projection. This mode allows adjusting [member frustum_offset] to create "tilted frustum" effects.
+ </constant>
+ <constant name="KEEP_WIDTH" value="0" enum="KeepAspect">
+ Preserves the horizontal aspect ratio; also known as Vert- scaling. This is usually the best option for projects running in portrait mode, as taller aspect ratios will benefit from a wider vertical FOV.
+ </constant>
+ <constant name="KEEP_HEIGHT" value="1" enum="KeepAspect">
+ Preserves the vertical aspect ratio; also known as Hor+ scaling. This is usually the best option for projects running in landscape mode, as wider aspect ratios will automatically benefit from a wider horizontal FOV.
+ </constant>
+ <constant name="DOPPLER_TRACKING_DISABLED" value="0" enum="DopplerTracking">
+ Disables [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] simulation (default).
+ </constant>
+ <constant name="DOPPLER_TRACKING_IDLE_STEP" value="1" enum="DopplerTracking">
+ Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] by tracking positions of objects that are changed in [code]_process[/code]. Changes in the relative velocity of this camera compared to those objects affect how Audio is perceived (changing the Audio's [code]pitch shift[/code]).
+ </constant>
+ <constant name="DOPPLER_TRACKING_PHYSICS_STEP" value="2" enum="DopplerTracking">
+ Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] by tracking positions of objects that are changed in [code]_physics_process[/code]. Changes in the relative velocity of this camera compared to those objects affect how Audio is perceived (changing the Audio's [code]pitch shift[/code]).
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml
index 3232f5970c..4fc124592f 100644
--- a/doc/classes/CameraFeed.xml
+++ b/doc/classes/CameraFeed.xml
@@ -4,7 +4,7 @@
A camera feed gives you access to a single physical camera attached to your device.
</brief_description>
<description>
- A camera feed gives you access to a single physical camera attached to your device. When enabled, Godot will start capturing frames from the camera which can then be used.
+ A camera feed gives you access to a single physical camera attached to your device. When enabled, Godot will start capturing frames from the camera which can then be used. See also [CameraServer].
[b]Note:[/b] Many cameras will return YCbCr images which are split into two textures and need to be combined in a shader. Godot does this automatically for you if you set the environment to show the camera image in the background.
</description>
<tutorials>
diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml
index 82d1faf716..e00dc031dc 100644
--- a/doc/classes/CameraServer.xml
+++ b/doc/classes/CameraServer.xml
@@ -6,6 +6,7 @@
<description>
The [CameraServer] keeps track of different cameras accessible in Godot. These are external cameras such as webcams or the cameras on your phone.
It is notably used to provide AR modules with a video feed from the camera.
+ [b]Note:[/b] This class is currently only implemented on macOS and iOS. On other platforms, no [CameraFeed]s will be available.
</description>
<tutorials>
</tutorials>
@@ -16,7 +17,7 @@
<argument index="0" name="feed" type="CameraFeed">
</argument>
<description>
- Adds a camera feed to the camera server.
+ Adds the camera [code]feed[/code] to the camera server.
</description>
</method>
<method name="feeds">
@@ -32,7 +33,7 @@
<argument index="0" name="index" type="int">
</argument>
<description>
- Returns the [CameraFeed] with this id.
+ Returns the [CameraFeed] corresponding to the camera with the given [code]index[/code].
</description>
</method>
<method name="get_feed_count">
@@ -48,7 +49,7 @@
<argument index="0" name="feed" type="CameraFeed">
</argument>
<description>
- Removes a [CameraFeed].
+ Removes the specified camera [code]feed[/code].
</description>
</method>
</methods>
@@ -57,14 +58,14 @@
<argument index="0" name="id" type="int">
</argument>
<description>
- Emitted when a [CameraFeed] is added (e.g. webcam is plugged in).
+ Emitted when a [CameraFeed] is added (e.g. a webcam is plugged in).
</description>
</signal>
<signal name="camera_feed_removed">
<argument index="0" name="id" type="int">
</argument>
<description>
- Emitted when a [CameraFeed] is removed (e.g. webcam is unplugged).
+ Emitted when a [CameraFeed] is removed (e.g. a webcam is unplugged).
</description>
</signal>
</signals>
@@ -73,7 +74,7 @@
The RGBA camera image.
</constant>
<constant name="FEED_YCBCR_IMAGE" value="0" enum="FeedImage">
- The YCbCr camera image.
+ The [url=https://en.wikipedia.org/wiki/YCbCr]YCbCr[/url] camera image.
</constant>
<constant name="FEED_Y_IMAGE" value="0" enum="FeedImage">
The Y component camera image.
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index dec7c907a4..f2ce2a6fb9 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -426,7 +426,7 @@
<return type="RID">
</return>
<description>
- Returns the canvas item RID used by [VisualServer] for this item.
+ Returns the canvas item RID used by [RenderingServer] for this item.
</description>
</method>
<method name="get_canvas_transform" qualifiers="const">
@@ -656,10 +656,13 @@
The [CanvasItem] has exited the canvas.
</constant>
<constant name="TEXTURE_FILTER_PARENT_NODE" value="0" enum="TextureFilter">
+ The [CanvasItem] will inherit the filter from its parent.
</constant>
<constant name="TEXTURE_FILTER_NEAREST" value="1" enum="TextureFilter">
+ The texture filter reads from the nearest pixel only. The simplest and fastest method of filtering. Useful for pixel art.
</constant>
<constant name="TEXTURE_FILTER_LINEAR" value="2" enum="TextureFilter">
+ The texture filter blends between the nearest four pixels. Use this for most cases where you want to avoid a pixelated style.
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="TextureFilter">
</constant>
@@ -670,16 +673,22 @@
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="TextureFilter">
</constant>
<constant name="TEXTURE_FILTER_MAX" value="7" enum="TextureFilter">
+ Represents the size of the [enum TextureFilter] enum.
</constant>
<constant name="TEXTURE_REPEAT_PARENT_NODE" value="0" enum="TextureRepeat">
+ The [CanvasItem] will inherit the filter from its parent.
</constant>
<constant name="TEXTURE_REPEAT_DISABLED" value="1" enum="TextureRepeat">
+ Texture will not repeat.
</constant>
<constant name="TEXTURE_REPEAT_ENABLED" value="2" enum="TextureRepeat">
+ Texture will repeat normally.
</constant>
<constant name="TEXTURE_REPEAT_MIRROR" value="3" enum="TextureRepeat">
+ Texture will repeat in a 2x2 tiled mode, where elements at even positions are mirrored.
</constant>
<constant name="TEXTURE_REPEAT_MAX" value="4" enum="TextureRepeat">
+ Represents the size of the [enum TextureRepeat] enum.
</constant>
</constants>
</class>
diff --git a/doc/classes/CanvasItemMaterial.xml b/doc/classes/CanvasItemMaterial.xml
index ffe2272260..c2d44c1d17 100644
--- a/doc/classes/CanvasItemMaterial.xml
+++ b/doc/classes/CanvasItemMaterial.xml
@@ -18,7 +18,7 @@
The manner in which material reacts to lighting.
</member>
<member name="particles_anim_h_frames" type="int" setter="set_particles_anim_h_frames" getter="get_particles_anim_h_frames">
- The number of columns in the spritesheet assigned as [Texture2D] for a [Particles2D] or [CPUParticles2D].
+ The number of columns in the spritesheet assigned as [Texture2D] for a [GPUParticles2D] or [CPUParticles2D].
[b]Note:[/b] This property is only used and visible in the editor if [member particles_animation] is [code]true[/code].
</member>
<member name="particles_anim_loop" type="bool" setter="set_particles_anim_loop" getter="get_particles_anim_loop">
@@ -26,11 +26,11 @@
[b]Note:[/b] This property is only used and visible in the editor if [member particles_animation] is [code]true[/code].
</member>
<member name="particles_anim_v_frames" type="int" setter="set_particles_anim_v_frames" getter="get_particles_anim_v_frames">
- The number of rows in the spritesheet assigned as [Texture2D] for a [Particles2D] or [CPUParticles2D].
+ The number of rows in the spritesheet assigned as [Texture2D] for a [GPUParticles2D] or [CPUParticles2D].
[b]Note:[/b] This property is only used and visible in the editor if [member particles_animation] is [code]true[/code].
</member>
<member name="particles_animation" type="bool" setter="set_particles_animation" getter="get_particles_animation" default="false">
- If [code]true[/code], enable spritesheet-based animation features when assigned to [Particles2D] and [CPUParticles2D] nodes. The [member ParticlesMaterial.anim_speed] or [member CPUParticles2D.anim_speed] should also be set to a positive value for the animation to play.
+ If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticlesMaterial.anim_speed] or [member CPUParticles2D.anim_speed] should also be set to a positive value for the animation to play.
This property (and other [code]particles_anim_*[/code] properties that depend on it) has no effect on other types of nodes.
</member>
</members>
diff --git a/doc/classes/CapsuleShape.xml b/doc/classes/CapsuleShape.xml
deleted file mode 100644
index c83e832281..0000000000
--- a/doc/classes/CapsuleShape.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CapsuleShape" inherits="Shape" version="4.0">
- <brief_description>
- Capsule shape for collisions.
- </brief_description>
- <description>
- Capsule shape for collisions.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
- The capsule's height.
- </member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- The capsule's radius.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/CapsuleShape3D.xml b/doc/classes/CapsuleShape3D.xml
new file mode 100644
index 0000000000..f56d94dc63
--- /dev/null
+++ b/doc/classes/CapsuleShape3D.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CapsuleShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Capsule shape for collisions.
+ </brief_description>
+ <description>
+ Capsule shape for collisions.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
+ The capsule's height.
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ The capsule's radius.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/ClippedCamera.xml b/doc/classes/ClippedCamera.xml
deleted file mode 100644
index 4cdc098c2f..0000000000
--- a/doc/classes/ClippedCamera.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ClippedCamera" inherits="Camera" version="4.0">
- <brief_description>
- A [Camera] that includes collision.
- </brief_description>
- <description>
- This node extends [Camera] to add collisions with [Area] and/or [PhysicsBody] nodes. The camera cannot move through colliding objects.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_exception">
- <return type="void">
- </return>
- <argument index="0" name="node" type="Object">
- </argument>
- <description>
- Adds a collision exception so the camera does not collide with the specified node.
- </description>
- </method>
- <method name="add_exception_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Adds a collision exception so the camera does not collide with the specified [RID].
- </description>
- </method>
- <method name="clear_exceptions">
- <return type="void">
- </return>
- <description>
- Removes all collision exceptions.
- </description>
- </method>
- <method name="get_clip_offset" qualifiers="const">
- <return type="float">
- </return>
- <description>
- Returns the distance the camera has been offset due to a collision.
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the specified bit index is on.
- [b]Note:[/b] Bit indices range from 0-19.
- </description>
- </method>
- <method name="remove_exception">
- <return type="void">
- </return>
- <argument index="0" name="node" type="Object">
- </argument>
- <description>
- Removes a collision exception with the specified node.
- </description>
- </method>
- <method name="remove_exception_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Removes a collision exception with the specified [RID].
- </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 the specified bit index to the [code]value[/code].
- [b]Note:[/b] Bit indices range from 0-19.
- </description>
- </method>
- </methods>
- <members>
- <member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false">
- If [code]true[/code], the camera stops on contact with [Area]s.
- </member>
- <member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true">
- If [code]true[/code], the camera stops on contact with [PhysicsBody]s.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected.
- </member>
- <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="ClippedCamera.ProcessMode" default="0">
- The camera's process callback. See [enum ProcessMode].
- </member>
- </members>
- <constants>
- <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ProcessMode">
- The camera updates with the [code]_physics_process[/code] callback.
- </constant>
- <constant name="CLIP_PROCESS_IDLE" value="1" enum="ProcessMode">
- The camera updates with the [code]_process[/code] callback.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ClippedCamera3D.xml b/doc/classes/ClippedCamera3D.xml
new file mode 100644
index 0000000000..58ecec828d
--- /dev/null
+++ b/doc/classes/ClippedCamera3D.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ClippedCamera3D" inherits="Camera3D" version="4.0">
+ <brief_description>
+ A [Camera3D] that includes collision.
+ </brief_description>
+ <description>
+ This node extends [Camera3D] to add collisions with [Area3D] and/or [PhysicsBody3D] nodes. The camera cannot move through colliding objects.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Object">
+ </argument>
+ <description>
+ Adds a collision exception so the camera does not collide with the specified node.
+ </description>
+ </method>
+ <method name="add_exception_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ Adds a collision exception so the camera does not collide with the specified [RID].
+ </description>
+ </method>
+ <method name="clear_exceptions">
+ <return type="void">
+ </return>
+ <description>
+ Removes all collision exceptions.
+ </description>
+ </method>
+ <method name="get_clip_offset" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the distance the camera has been offset due to a collision.
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the specified bit index is on.
+ [b]Note:[/b] Bit indices range from 0-19.
+ </description>
+ </method>
+ <method name="remove_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Object">
+ </argument>
+ <description>
+ Removes a collision exception with the specified node.
+ </description>
+ </method>
+ <method name="remove_exception_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ Removes a collision exception with the specified [RID].
+ </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 the specified bit index to the [code]value[/code].
+ [b]Note:[/b] Bit indices range from 0-19.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false">
+ If [code]true[/code], the camera stops on contact with [Area3D]s.
+ </member>
+ <member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true">
+ If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s.
+ </member>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected.
+ </member>
+ <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>
+ </members>
+ <constants>
+ <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ProcessMode">
+ The camera updates with the [code]_physics_process[/code] callback.
+ </constant>
+ <constant name="CLIP_PROCESS_IDLE" value="1" enum="ProcessMode">
+ The camera updates with the [code]_process[/code] callback.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/CollisionObject.xml b/doc/classes/CollisionObject.xml
deleted file mode 100644
index 34758d71b2..0000000000
--- a/doc/classes/CollisionObject.xml
+++ /dev/null
@@ -1,219 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionObject" inherits="Spatial" version="4.0">
- <brief_description>
- Base node for collision objects.
- </brief_description>
- <description>
- CollisionObject is the base class for physics objects. It can hold any number of collision [Shape]s. Each shape must be assigned to a [i]shape owner[/i]. The CollisionObject can have any number of shape owners. Shape owners are not nodes and do not appear in the editor, but are accessible through code using the [code]shape_owner_*[/code] methods.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="_input_event" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="Object">
- </argument>
- <argument index="1" name="event" type="InputEvent">
- </argument>
- <argument index="2" name="click_position" type="Vector3">
- </argument>
- <argument index="3" name="click_normal" type="Vector3">
- </argument>
- <argument index="4" name="shape_idx" type="int">
- </argument>
- <description>
- Accepts unhandled [InputEvent]s. [code]click_position[/code] is the clicked location in world space and [code]click_normal[/code] is the normal vector extending from the clicked surface of the [Shape] at [code]shape_idx[/code]. Connect to the [code]input_event[/code] signal to easily pick up these events.
- </description>
- </method>
- <method name="create_shape_owner">
- <return type="int">
- </return>
- <argument index="0" name="owner" type="Object">
- </argument>
- <description>
- 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_rid" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Returns the object's [RID].
- </description>
- </method>
- <method name="get_shape_owners">
- <return type="Array">
- </return>
- <description>
- Returns an [Array] of [code]owner_id[/code] identifiers. You can use these ids in other methods that take [code]owner_id[/code] as an argument.
- </description>
- </method>
- <method name="is_shape_owner_disabled" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <description>
- If [code]true[/code], the shape owner and its shapes are disabled.
- </description>
- </method>
- <method name="remove_shape_owner">
- <return type="void">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <description>
- Removes the given shape owner.
- </description>
- </method>
- <method name="shape_find_owner" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="shape_index" type="int">
- </argument>
- <description>
- Returns the [code]owner_id[/code] of the given shape.
- </description>
- </method>
- <method name="shape_owner_add_shape">
- <return type="void">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <argument index="1" name="shape" type="Shape">
- </argument>
- <description>
- Adds a [Shape] to the shape owner.
- </description>
- </method>
- <method name="shape_owner_clear_shapes">
- <return type="void">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <description>
- Removes all shapes from the shape owner.
- </description>
- </method>
- <method name="shape_owner_get_owner" qualifiers="const">
- <return type="Object">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <description>
- Returns the parent object of the given shape owner.
- </description>
- </method>
- <method name="shape_owner_get_shape" qualifiers="const">
- <return type="Shape">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <description>
- Returns the [Shape] with the given id from the given shape owner.
- </description>
- </method>
- <method name="shape_owner_get_shape_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <description>
- Returns the number of shapes the given shape owner contains.
- </description>
- </method>
- <method name="shape_owner_get_shape_index" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <description>
- Returns the child index of the [Shape] with the given id from the given shape owner.
- </description>
- </method>
- <method name="shape_owner_get_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <description>
- Returns the shape owner's [Transform].
- </description>
- </method>
- <method name="shape_owner_remove_shape">
- <return type="void">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <argument index="1" name="shape_id" type="int">
- </argument>
- <description>
- Removes a shape from the given shape owner.
- </description>
- </method>
- <method name="shape_owner_set_disabled">
- <return type="void">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <argument index="1" name="disabled" type="bool">
- </argument>
- <description>
- If [code]true[/code], disables the given shape owner.
- </description>
- </method>
- <method name="shape_owner_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="owner_id" type="int">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- Sets the [Transform] of the given shape owner.
- </description>
- </method>
- </methods>
- <members>
- <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 [CollisionObject] will continue to receive input events as the mouse is dragged across its shapes.
- </member>
- <member name="input_ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
- If [code]true[/code], the [CollisionObject]'s shapes will respond to [RayCast]s.
- </member>
- </members>
- <signals>
- <signal name="input_event">
- <argument index="0" name="camera" type="Node">
- </argument>
- <argument index="1" name="event" type="InputEvent">
- </argument>
- <argument index="2" name="click_position" type="Vector3">
- </argument>
- <argument index="3" name="click_normal" type="Vector3">
- </argument>
- <argument index="4" name="shape_idx" type="int">
- </argument>
- <description>
- Emitted when [method _input_event] receives an event. See its description for details.
- </description>
- </signal>
- <signal name="mouse_entered">
- <description>
- Emitted when the mouse pointer enters any of this object's shapes.
- </description>
- </signal>
- <signal name="mouse_exited">
- <description>
- Emitted when the mouse pointer exits all this object's shapes.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
new file mode 100644
index 0000000000..f8e897653d
--- /dev/null
+++ b/doc/classes/CollisionObject3D.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CollisionObject3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Base node for collision objects.
+ </brief_description>
+ <description>
+ CollisionObject3D is the base class for physics objects. It can hold any number of collision [Shape3D]s. Each shape must be assigned to a [i]shape owner[/i]. The CollisionObject3D can have any number of shape owners. Shape owners are not nodes and do not appear in the editor, but are accessible through code using the [code]shape_owner_*[/code] methods.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_input_event" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="Object">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <argument index="2" name="click_position" type="Vector3">
+ </argument>
+ <argument index="3" name="click_normal" type="Vector3">
+ </argument>
+ <argument index="4" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Accepts unhandled [InputEvent]s. [code]click_position[/code] is the clicked location in world space and [code]click_normal[/code] is the normal vector extending from the clicked surface of the [Shape3D] at [code]shape_idx[/code]. Connect to the [code]input_event[/code] signal to easily pick up these events.
+ </description>
+ </method>
+ <method name="create_shape_owner">
+ <return type="int">
+ </return>
+ <argument index="0" name="owner" type="Object">
+ </argument>
+ <description>
+ 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_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the object's [RID].
+ </description>
+ </method>
+ <method name="get_shape_owners">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an [Array] of [code]owner_id[/code] identifiers. You can use these ids in other methods that take [code]owner_id[/code] as an argument.
+ </description>
+ </method>
+ <method name="is_shape_owner_disabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <description>
+ If [code]true[/code], the shape owner and its shapes are disabled.
+ </description>
+ </method>
+ <method name="remove_shape_owner">
+ <return type="void">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <description>
+ Removes the given shape owner.
+ </description>
+ </method>
+ <method name="shape_find_owner" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shape_index" type="int">
+ </argument>
+ <description>
+ Returns the [code]owner_id[/code] of the given shape.
+ </description>
+ </method>
+ <method name="shape_owner_add_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <argument index="1" name="shape" type="Shape3D">
+ </argument>
+ <description>
+ Adds a [Shape3D] to the shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_clear_shapes">
+ <return type="void">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <description>
+ Removes all shapes from the shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_get_owner" qualifiers="const">
+ <return type="Object">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <description>
+ Returns the parent object of the given shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_get_shape" qualifiers="const">
+ <return type="Shape3D">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <argument index="1" name="shape_id" type="int">
+ </argument>
+ <description>
+ Returns the [Shape3D] with the given id from the given shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_get_shape_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <description>
+ Returns the number of shapes the given shape owner contains.
+ </description>
+ </method>
+ <method name="shape_owner_get_shape_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <argument index="1" name="shape_id" type="int">
+ </argument>
+ <description>
+ Returns the child index of the [Shape3D] with the given id from the given shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_get_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <description>
+ Returns the shape owner's [Transform].
+ </description>
+ </method>
+ <method name="shape_owner_remove_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <argument index="1" name="shape_id" type="int">
+ </argument>
+ <description>
+ Removes a shape from the given shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_set_disabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <argument index="1" name="disabled" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], disables the given shape owner.
+ </description>
+ </method>
+ <method name="shape_owner_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="owner_id" type="int">
+ </argument>
+ <argument index="1" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the [Transform] of the given shape owner.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <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>
+ <member name="input_ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
+ If [code]true[/code], the [CollisionObject3D]'s shapes will respond to [RayCast3D]s.
+ </member>
+ </members>
+ <signals>
+ <signal name="input_event">
+ <argument index="0" name="camera" type="Node">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <argument index="2" name="click_position" type="Vector3">
+ </argument>
+ <argument index="3" name="click_normal" type="Vector3">
+ </argument>
+ <argument index="4" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Emitted when [method _input_event] receives an event. See its description for details.
+ </description>
+ </signal>
+ <signal name="mouse_entered">
+ <description>
+ Emitted when the mouse pointer enters any of this object's shapes.
+ </description>
+ </signal>
+ <signal name="mouse_exited">
+ <description>
+ Emitted when the mouse pointer exits all this object's shapes.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CollisionPolygon.xml b/doc/classes/CollisionPolygon.xml
deleted file mode 100644
index 8aceec17a8..0000000000
--- a/doc/classes/CollisionPolygon.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionPolygon" inherits="Spatial" version="4.0">
- <brief_description>
- Editor-only class for defining a collision polygon in 3D space.
- </brief_description>
- <description>
- Allows editing a collision polygon's vertices on a selected plane. Can also set a depth perpendicular to that plane. This class is only available in the editor. It will not appear in the scene tree at run-time. Creates a [Shape] for gameplay. Properties modified during gameplay will have no effect.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
- Length that the resulting collision extends in either direction perpendicular to its polygon.
- </member>
- <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="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.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml
index e3135a4d0f..242cdb8c80 100644
--- a/doc/classes/CollisionPolygon2D.xml
+++ b/doc/classes/CollisionPolygon2D.xml
@@ -21,6 +21,7 @@
If [code]true[/code], only edges that face up, relative to [CollisionPolygon2D]'s rotation, will collide with other objects.
</member>
<member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0">
+ The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the polygon at a high velocity.
</member>
<member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( )">
The polygon's list of vertices. The final point will be connected to the first. The returned value is a clone of the [PackedVector2Array], not a reference.
diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml
new file mode 100644
index 0000000000..dd3c57d1d0
--- /dev/null
+++ b/doc/classes/CollisionPolygon3D.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CollisionPolygon3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Editor-only class for defining a collision polygon in 3D space.
+ </brief_description>
+ <description>
+ Allows editing a collision polygon's vertices on a selected plane. Can also set a depth perpendicular to that plane. This class is only available in the editor. It will not appear in the scene tree at run-time. Creates a [Shape3D] for gameplay. Properties modified during gameplay will have no effect.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
+ Length that the resulting collision extends in either direction perpendicular to its polygon.
+ </member>
+ <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="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.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CollisionShape.xml b/doc/classes/CollisionShape.xml
deleted file mode 100644
index 7787bf957d..0000000000
--- a/doc/classes/CollisionShape.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CollisionShape" inherits="Spatial" version="4.0">
- <brief_description>
- Node that represents collision shape data in 3D space.
- </brief_description>
- <description>
- Editor facility for creating and editing collision shapes in 3D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area] to give it a detection shape, or add it to a [PhysicsBody] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject.shape_owner_get_shape] to get the actual shape.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
- </tutorials>
- <methods>
- <method name="make_convex_from_brothers">
- <return type="void">
- </return>
- <description>
- Sets the collision shape's shape to the addition of all its convexed [MeshInstance] siblings geometry.
- </description>
- </method>
- <method name="resource_changed">
- <return type="void">
- </return>
- <argument index="0" name="resource" type="Resource">
- </argument>
- <description>
- If this method exists within a script it will be called whenever the shape resource has been modified.
- </description>
- </method>
- </methods>
- <members>
- <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
- A disabled collision shape has no effect in the world.
- </member>
- <member name="shape" type="Shape" setter="set_shape" getter="get_shape">
- The actual shape owned by this collision shape.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index 4903f0d3a5..e32ce9c9f9 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -19,7 +19,7 @@
Sets whether this collision shape should only detect collision on one side (top or bottom).
</member>
<member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0">
- The margin used for one-way collision (in pixels).
+ The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the shape at a high velocity.
</member>
<member name="shape" type="Shape2D" setter="set_shape" getter="get_shape">
The actual shape owned by this collision shape.
diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml
new file mode 100644
index 0000000000..76515a65a7
--- /dev/null
+++ b/doc/classes/CollisionShape3D.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CollisionShape3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Node that represents collision shape data in 3D space.
+ </brief_description>
+ <description>
+ Editor facility for creating and editing collision shapes in 3D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area3D] to give it a detection shape, or add it to a [PhysicsBody3D] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ </tutorials>
+ <methods>
+ <method name="make_convex_from_brothers">
+ <return type="void">
+ </return>
+ <description>
+ Sets the collision shape's shape to the addition of all its convexed [MeshInstance3D] siblings geometry.
+ </description>
+ </method>
+ <method name="resource_changed">
+ <return type="void">
+ </return>
+ <argument index="0" name="resource" type="Resource">
+ </argument>
+ <description>
+ If this method exists within a script it will be called whenever the shape resource has been modified.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
+ A disabled collision shape has no effect in the world.
+ </member>
+ <member name="shape" type="Shape3D" setter="set_shape" getter="get_shape">
+ The actual shape owned by this collision shape.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 8587acade3..d495be2ffd 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -5,7 +5,8 @@
</brief_description>
<description>
A color is represented by red, green, and blue [code](r, g, b)[/code] components. Additionally, [code]a[/code] represents the alpha component, often used for transparency. Values are in floating-point and usually range from 0 to 1. Some properties (such as [member CanvasItem.modulate]) may accept values greater than 1.
- You can also create a color from standardized color names by using [method @GDScript.ColorN] or directly using the color constants defined here. The standardized color set is based on the [url=https://en.wikipedia.org/wiki/X11_color_names]X11 color names[/url].
+ You can also create a color from standardized color names by using [method @GDScript.ColorN] or directly using the color constants defined here. The standardized color set is based on the [url=https://en.wikipedia.org/wiki/X11_color_names]X11 color names[/url].
+ If you want to supply values in a range of 0 to 255, you should use [method @GDScript.Color8].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 5ab929d911..d8b4a8f76c 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -88,26 +88,34 @@
</constants>
<theme_items>
<theme_item name="add_preset" type="Texture2D">
+ The icon for the "Add Preset" button.
</theme_item>
<theme_item name="color_hue" type="Texture2D">
+ Custom texture for the hue selection slider on the right.
</theme_item>
<theme_item name="color_sample" type="Texture2D">
</theme_item>
<theme_item name="h_width" type="int" default="30">
+ The width of the hue selection slider.
</theme_item>
<theme_item name="label_width" type="int" default="10">
</theme_item>
<theme_item name="margin" type="int" default="4">
+ The margin around the [ColorPicker].
</theme_item>
<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="preset_bg" type="Texture2D">
</theme_item>
<theme_item name="screen_picker" type="Texture2D">
+ The icon for the screen color picker button.
</theme_item>
<theme_item name="sv_height" type="int" default="256">
+ The height of the saturation-value selection box.
</theme_item>
<theme_item name="sv_width" type="int" default="256">
+ The width of the saturation-value selection box.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/ConcavePolygonShape.xml b/doc/classes/ConcavePolygonShape.xml
deleted file mode 100644
index 47f2276c63..0000000000
--- a/doc/classes/ConcavePolygonShape.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConcavePolygonShape" inherits="Shape" version="4.0">
- <brief_description>
- Concave polygon shape.
- </brief_description>
- <description>
- Concave polygon shape resource, which can be set into a [PhysicsBody] or area. This shape is created by feeding a list of triangles.
- Note: when used for collision, [ConcavePolygonShape] is intended to work with static [PhysicsBody] nodes like [StaticBody] and will not work with [KinematicBody] or [RigidBody] with a mode other than Static.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_faces" qualifiers="const">
- <return type="PackedVector3Array">
- </return>
- <description>
- Returns the faces (an array of triangles).
- </description>
- </method>
- <method name="set_faces">
- <return type="void">
- </return>
- <argument index="0" name="faces" type="PackedVector3Array">
- </argument>
- <description>
- Sets the faces (an array of triangles).
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
new file mode 100644
index 0000000000..20402d350a
--- /dev/null
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ConcavePolygonShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Concave polygon shape.
+ </brief_description>
+ <description>
+ Concave polygon shape resource, which can be set into a [PhysicsBody3D] or area. This shape is created by feeding a list of triangles.
+ Note: when used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [KinematicBody3D] or [RigidBody3D] with a mode other than Static.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_faces" qualifiers="const">
+ <return type="PackedVector3Array">
+ </return>
+ <description>
+ Returns the faces (an array of triangles).
+ </description>
+ </method>
+ <method name="set_faces">
+ <return type="void">
+ </return>
+ <argument index="0" name="faces" type="PackedVector3Array">
+ </argument>
+ <description>
+ Sets the faces (an array of triangles).
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/ConeTwistJoint.xml b/doc/classes/ConeTwistJoint.xml
deleted file mode 100644
index 8682391a73..0000000000
--- a/doc/classes/ConeTwistJoint.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConeTwistJoint" inherits="Joint" version="4.0">
- <brief_description>
- A twist joint between two 3D bodies.
- </brief_description>
- <description>
- The joint can rotate the bodies across an axis defined by the local x-axes of the [Joint].
- The twist axis is initiated as the X axis of the [Joint].
- Once the Bodies swing, the twist axis is calculated as the middle of the x-axes of the Joint in the local space of the two Bodies.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="ConeTwistJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="ConeTwistJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="bias" type="float" setter="set_param" getter="get_param" default="0.3">
- The speed with which the swing or twist will take place.
- The higher, the faster.
- </member>
- <member name="relaxation" type="float" setter="set_param" getter="get_param" default="1.0">
- Defines, how fast the swing- and twist-speed-difference on both sides gets synced.
- </member>
- <member name="softness" type="float" setter="set_param" getter="get_param" default="0.8">
- The ease with which the joint starts to twist. If it's too low, it takes more force to start twisting the joint.
- </member>
- <member name="swing_span" type="float" setter="_set_swing_span" getter="_get_swing_span" default="45.0">
- Swing is rotation from side to side, around the axis perpendicular to the twist axis.
- The swing span defines, how much rotation will not get corrected along the swing axis.
- Could be defined as looseness in the [ConeTwistJoint].
- If below 0.05, this behavior is locked.
- </member>
- <member name="twist_span" type="float" setter="_set_twist_span" getter="_get_twist_span" default="180.0">
- Twist is the rotation around the twist axis, this value defined how far the joint can twist.
- Twist is locked if below 0.05.
- </member>
- </members>
- <constants>
- <constant name="PARAM_SWING_SPAN" value="0" enum="Param">
- Swing is rotation from side to side, around the axis perpendicular to the twist axis.
- The swing span defines, how much rotation will not get corrected along the swing axis.
- Could be defined as looseness in the [ConeTwistJoint].
- If below 0.05, this behavior is locked.
- </constant>
- <constant name="PARAM_TWIST_SPAN" value="1" enum="Param">
- Twist is the rotation around the twist axis, this value defined how far the joint can twist.
- Twist is locked if below 0.05.
- </constant>
- <constant name="PARAM_BIAS" value="2" enum="Param">
- The speed with which the swing or twist will take place.
- The higher, the faster.
- </constant>
- <constant name="PARAM_SOFTNESS" value="3" enum="Param">
- The ease with which the joint starts to twist. If it's too low, it takes more force to start twisting the joint.
- </constant>
- <constant name="PARAM_RELAXATION" value="4" enum="Param">
- Defines, how fast the swing- and twist-speed-difference on both sides gets synced.
- </constant>
- <constant name="PARAM_MAX" value="5" enum="Param">
- Represents the size of the [enum Param] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ConeTwistJoint3D.xml b/doc/classes/ConeTwistJoint3D.xml
new file mode 100644
index 0000000000..e86e95bec3
--- /dev/null
+++ b/doc/classes/ConeTwistJoint3D.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ConeTwistJoint3D" inherits="Joint3D" version="4.0">
+ <brief_description>
+ A twist joint between two 3D bodies.
+ </brief_description>
+ <description>
+ The joint can rotate the bodies across an axis defined by the local x-axes of the [Joint3D].
+ The twist axis is initiated as the X axis of the [Joint3D].
+ Once the Bodies swing, the twist axis is calculated as the middle of the x-axes of the Joint3D in the local space of the two Bodies.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="ConeTwistJoint3D.Param">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="ConeTwistJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bias" type="float" setter="set_param" getter="get_param" default="0.3">
+ The speed with which the swing or twist will take place.
+ The higher, the faster.
+ </member>
+ <member name="relaxation" type="float" setter="set_param" getter="get_param" default="1.0">
+ Defines, how fast the swing- and twist-speed-difference on both sides gets synced.
+ </member>
+ <member name="softness" type="float" setter="set_param" getter="get_param" default="0.8">
+ The ease with which the joint starts to twist. If it's too low, it takes more force to start twisting the joint.
+ </member>
+ <member name="swing_span" type="float" setter="_set_swing_span" getter="_get_swing_span" default="45.0">
+ Swing is rotation from side to side, around the axis perpendicular to the twist axis.
+ The swing span defines, how much rotation will not get corrected along the swing axis.
+ Could be defined as looseness in the [ConeTwistJoint3D].
+ If below 0.05, this behavior is locked.
+ </member>
+ <member name="twist_span" type="float" setter="_set_twist_span" getter="_get_twist_span" default="180.0">
+ Twist is the rotation around the twist axis, this value defined how far the joint can twist.
+ Twist is locked if below 0.05.
+ </member>
+ </members>
+ <constants>
+ <constant name="PARAM_SWING_SPAN" value="0" enum="Param">
+ Swing is rotation from side to side, around the axis perpendicular to the twist axis.
+ The swing span defines, how much rotation will not get corrected along the swing axis.
+ Could be defined as looseness in the [ConeTwistJoint3D].
+ If below 0.05, this behavior is locked.
+ </constant>
+ <constant name="PARAM_TWIST_SPAN" value="1" enum="Param">
+ Twist is the rotation around the twist axis, this value defined how far the joint can twist.
+ Twist is locked if below 0.05.
+ </constant>
+ <constant name="PARAM_BIAS" value="2" enum="Param">
+ The speed with which the swing or twist will take place.
+ The higher, the faster.
+ </constant>
+ <constant name="PARAM_SOFTNESS" value="3" enum="Param">
+ The ease with which the joint starts to twist. If it's too low, it takes more force to start twisting the joint.
+ </constant>
+ <constant name="PARAM_RELAXATION" value="4" enum="Param">
+ Defines, how fast the swing- and twist-speed-difference on both sides gets synced.
+ </constant>
+ <constant name="PARAM_MAX" value="5" enum="Param">
+ Represents the size of the [enum Param] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml
index a16326d55a..522d484131 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -8,7 +8,7 @@
[codeblock]
[section]
some_key=42
- string_example="Hello World!"
+ string_example="Hello World3D!"
a_vector=Vector3( 1, 0, 2 )
[/codeblock]
The stored data can be saved to or parsed from a file, though ConfigFile objects can also be used directly without accessing the filesystem.
diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml
index 801d9508dd..6d5871508b 100644
--- a/doc/classes/ConfirmationDialog.xml
+++ b/doc/classes/ConfirmationDialog.xml
@@ -22,8 +22,9 @@
</method>
</methods>
<members>
- <member name="rect_min_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" override="true" default="Vector2( 200, 70 )" />
- <member name="window_title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Please Confirm...&quot;" />
+ <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" override="true" default="Vector2i( 200, 70 )" />
+ <member name="size" type="Vector2i" setter="set_size" getter="get_size" override="true" default="Vector2i( 200, 100 )" />
+ <member name="title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Please Confirm...&quot;" />
</members>
<constants>
</constants>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 89db5baf8a..0c8d42021a 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -7,10 +7,12 @@
Base class for all UI-related nodes. [Control] features a bounding rectangle that defines its extents, an anchor position relative to its parent control or the current viewport, and margins that represent an offset to the anchor. The margins update automatically when the node, any of its parents, or the screen size change.
For more information on Godot's UI system, anchors, margins, and containers, see the related tutorials in the manual. To build flexible UIs, you'll need a mix of UI elements that inherit from [Control] and [Container] nodes.
[b]User Interface nodes and input[/b]
- Godot sends input events to the scene's root node first, by calling [method Node._input]. [method Node._input] forwards the event down the node tree to the nodes under the mouse cursor, or on keyboard focus. To do so, it calls [method MainLoop._input_event]. Call [method accept_event] so no other node receives the event. Once you accepted an input, it becomes handled so [method Node._unhandled_input] will not process it.
+ Godot sends input events to the scene's root node first, by calling [method Node._input]. [method Node._input] forwards the event down the node tree to the nodes under the mouse cursor, or on keyboard focus. To do so, it calls [code]MainLoop._input_event[/code].
+ [b]FIXME:[/b] No longer valid after DisplayServer split and Input refactoring.
+ Call [method accept_event] so no other node receives the event. Once you accepted an input, it becomes handled so [method Node._unhandled_input] will not process it.
Only one [Control] node can be in keyboard focus. Only the node in focus will receive keyboard events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus.
Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a [Control] node to ignore mouse or touch events. You'll need it if you place an icon on top of a button.
- [Theme] resources change the Control's appearance. If you change the [Theme] on a [Control] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_*_override[/code] methods, like [method add_font_override]. You can override the theme with the inspector.
+ [Theme] resources change the Control's appearance. If you change the [Theme] on a [Control] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can override the theme with the inspector.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/gui/index.html</link>
@@ -87,7 +89,7 @@
Marks an input event as handled. Once you accept an input event, it stops propagating, even to nodes listening to [method Node._unhandled_input] or [method Node._unhandled_key_input].
</description>
</method>
- <method name="add_color_override">
+ <method name="add_theme_color_override">
<return type="void">
</return>
<argument index="0" name="name" type="StringName">
@@ -98,7 +100,7 @@
Overrides the [Color] with given [code]name[/code] in the [member theme] resource the control uses. If the [code]color[/code] is empty or invalid, the override is cleared and the color from assigned [Theme] is used.
</description>
</method>
- <method name="add_constant_override">
+ <method name="add_theme_constant_override">
<return type="void">
</return>
<argument index="0" name="name" type="StringName">
@@ -109,7 +111,7 @@
Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses. If the [code]constant[/code] is empty or invalid, the override is cleared and the constant from assigned [Theme] is used.
</description>
</method>
- <method name="add_font_override">
+ <method name="add_theme_font_override">
<return type="void">
</return>
<argument index="0" name="name" type="StringName">
@@ -120,7 +122,7 @@
Overrides the font with given [code]name[/code] in the [member theme] resource the control uses. If [code]font[/code] is empty or invalid, the override is cleared and the font from assigned [Theme] is used.
</description>
</method>
- <method name="add_icon_override">
+ <method name="add_theme_icon_override">
<return type="void">
</return>
<argument index="0" name="name" type="StringName">
@@ -131,7 +133,7 @@
Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses. If [code]icon[/code] is empty or invalid, the override is cleared and the icon from assigned [Theme] is used.
</description>
</method>
- <method name="add_shader_override">
+ <method name="add_theme_shader_override">
<return type="void">
</return>
<argument index="0" name="name" type="StringName">
@@ -142,7 +144,7 @@
Overrides the [Shader] with given [code]name[/code] in the [member theme] resource the control uses. If [code]shader[/code] is empty or invalid, the override is cleared and the shader from assigned [Theme] is used.
</description>
</method>
- <method name="add_stylebox_override">
+ <method name="add_theme_stylebox_override">
<return type="void">
</return>
<argument index="0" name="name" type="StringName">
@@ -217,21 +219,6 @@
Returns [member margin_left] and [member margin_top]. See also [member rect_position].
</description>
</method>
- <method name="get_color" qualifiers="const">
- <return type="Color">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
- </argument>
- <description>
- Returns a color from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
- [codeblock]
- func _ready():
- modulate = get_color("font_color", "Button") #get the color defined for button fonts
- [/codeblock]
- </description>
- </method>
<method name="get_combined_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
@@ -239,17 +226,6 @@
Returns combined minimum size from [member rect_min_size] and [method get_minimum_size].
</description>
</method>
- <method name="get_constant" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
- </argument>
- <description>
- Returns a constant from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
- </description>
- </method>
<method name="get_cursor_shape" qualifiers="const">
<return type="int" enum="Control.CursorShape">
</return>
@@ -298,17 +274,6 @@
Returns the control that has the keyboard focus or [code]null[/code] if none.
</description>
</method>
- <method name="get_font" qualifiers="const">
- <return type="Font">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
- </argument>
- <description>
- Returns a font from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
- </description>
- </method>
<method name="get_global_rect" qualifiers="const">
<return type="Rect2">
</return>
@@ -316,17 +281,6 @@
Returns the position and size of the control relative to the top-left corner of the screen. See [member rect_position] and [member rect_size].
</description>
</method>
- <method name="get_icon" qualifiers="const">
- <return type="Texture2D">
- </return>
- <argument index="0" name="name" type="StringName">
- </argument>
- <argument index="1" name="type" type="StringName" default="&quot;&quot;">
- </argument>
- <description>
- Returns an icon from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
- </description>
- </method>
<method name="get_margin" qualifiers="const">
<return type="float">
</return>
@@ -371,7 +325,55 @@
Returns the rotation (in radians).
</description>
</method>
- <method name="get_stylebox" qualifiers="const">
+ <method name="get_theme_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ Returns a color from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
+ [codeblock]
+ func _ready():
+ modulate = get_theme_color("font_color", "Button") #get the color defined for button fonts
+ [/codeblock]
+ </description>
+ </method>
+ <method name="get_theme_constant" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ Returns a constant from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
+ </description>
+ </method>
+ <method name="get_theme_font" qualifiers="const">
+ <return type="Font">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ Returns a font from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
+ </description>
+ </method>
+ <method name="get_theme_icon" qualifiers="const">
+ <return type="Texture2D">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ Returns an icon from assigned [Theme] with given [code]name[/code] and associated with [Control] of given [code]type[/code].
+ </description>
+ </method>
+ <method name="get_theme_stylebox" qualifiers="const">
<return type="StyleBox">
</return>
<argument index="0" name="name" type="StringName">
@@ -409,7 +411,25 @@
Steal the focus from another control and become the focused control (see [member focus_mode]).
</description>
</method>
- <method name="has_color" qualifiers="const">
+ <method name="has_focus" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if this is the current focused control. See [member focus_mode].
+ </description>
+ </method>
+ <method name="has_point" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <description>
+ Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control.
+ If not overridden, default behavior is checking if the point is within control's Rect.
+ [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code].
+ </description>
+ </method>
+ <method name="has_theme_color" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -420,7 +440,7 @@
Returns [code]true[/code] if [Color] with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme].
</description>
</method>
- <method name="has_color_override" qualifiers="const">
+ <method name="has_theme_color_override" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -429,7 +449,7 @@
Returns [code]true[/code] if [Color] with given [code]name[/code] has a valid override in this [Control] node.
</description>
</method>
- <method name="has_constant" qualifiers="const">
+ <method name="has_theme_constant" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -440,7 +460,7 @@
Returns [code]true[/code] if constant with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme].
</description>
</method>
- <method name="has_constant_override" qualifiers="const">
+ <method name="has_theme_constant_override" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -449,14 +469,7 @@
Returns [code]true[/code] if constant with given [code]name[/code] has a valid override in this [Control] node.
</description>
</method>
- <method name="has_focus" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if this is the current focused control. See [member focus_mode].
- </description>
- </method>
- <method name="has_font" qualifiers="const">
+ <method name="has_theme_font" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -467,7 +480,7 @@
Returns [code]true[/code] if font with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme].
</description>
</method>
- <method name="has_font_override" qualifiers="const">
+ <method name="has_theme_font_override" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -476,7 +489,7 @@
Returns [code]true[/code] if font with given [code]name[/code] has a valid override in this [Control] node.
</description>
</method>
- <method name="has_icon" qualifiers="const">
+ <method name="has_theme_icon" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -487,7 +500,7 @@
Returns [code]true[/code] if icon with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme].
</description>
</method>
- <method name="has_icon_override" qualifiers="const">
+ <method name="has_theme_icon_override" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -496,18 +509,7 @@
Returns [code]true[/code] if icon with given [code]name[/code] has a valid override in this [Control] node.
</description>
</method>
- <method name="has_point" qualifiers="virtual">
- <return type="bool">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <description>
- Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control.
- If not overridden, default behavior is checking if the point is within control's Rect.
- [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code].
- </description>
- </method>
- <method name="has_shader_override" qualifiers="const">
+ <method name="has_theme_shader_override" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -516,7 +518,7 @@
Returns [code]true[/code] if [Shader] with given [code]name[/code] has a valid override in this [Control] node.
</description>
</method>
- <method name="has_stylebox" qualifiers="const">
+ <method name="has_theme_stylebox" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -527,7 +529,7 @@
Returns [code]true[/code] if [StyleBox] with given [code]name[/code] and associated with [Control] of given [code]type[/code] exists in assigned [Theme].
</description>
</method>
- <method name="has_stylebox_override" qualifiers="const">
+ <method name="has_theme_stylebox_override" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="StringName">
@@ -757,16 +759,6 @@
If [code]keep_margins[/code] is [code]true[/code], control's anchors will be updated instead of margins.
</description>
</method>
- <method name="show_modal">
- <return type="void">
- </return>
- <argument index="0" name="exclusive" type="bool" default="false">
- </argument>
- <description>
- Displays a control as modal. Control must be a subwindow. Modal controls capture the input signals until closed or the area outside them is accessed. When a modal control loses focus, or the ESC key is pressed, they automatically hide. Modal controls are used extensively for popup dialogs and menus.
- If [code]exclusive[/code] is [code]true[/code], other controls will not receive input and clicking outside this control will not close it.
- </description>
- </method>
<method name="warp_mouse">
<return type="void">
</return>
@@ -846,7 +838,7 @@
Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Also controls whether the control can receive the [signal mouse_entered], and [signal mouse_exited] signals. See the constants to learn what each does.
</member>
<member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false">
- Enables whether rendering of children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered.
+ Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered.
</member>
<member name="rect_global_position" type="Vector2" setter="_set_global_position" getter="get_global_position">
The node's global position, relative to the world (usually to the top-left corner of the window).
@@ -905,11 +897,6 @@
Emitted when the node's minimum size changes.
</description>
</signal>
- <signal name="modal_closed">
- <description>
- Emitted when a modal [Control] is closed. See [method show_modal].
- </description>
- </signal>
<signal name="mouse_entered">
<description>
Emitted when the mouse enters the control's [code]Rect[/code] area, provided its [member mouse_filter] lets the event reach it.
@@ -930,6 +917,10 @@
Emitted when one of the size flags changes. See [member size_flags_horizontal] and [member size_flags_vertical].
</description>
</signal>
+ <signal name="theme_changed">
+ <description>
+ </description>
+ </signal>
</signals>
<constants>
<constant name="FOCUS_NONE" value="0" enum="FocusMode">
@@ -957,10 +948,7 @@
Sent when the node loses focus.
</constant>
<constant name="NOTIFICATION_THEME_CHANGED" value="45">
- Sent when the node's [member theme] changes, right before Godot redraws the control. Happens when you call one of the [code]add_*_override[/code] methods.
- </constant>
- <constant name="NOTIFICATION_MODAL_CLOSE" value="46">
- Sent when an open modal dialog closes. See [method show_modal].
+ Sent when the node's [member theme] changes, right before Godot redraws the control. Happens when you call one of the [code]add_theme_*_override[/code] methods.
</constant>
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47">
Sent when this node is inside a [ScrollContainer] which has begun being scrolled.
diff --git a/doc/classes/ConvexPolygonShape.xml b/doc/classes/ConvexPolygonShape.xml
deleted file mode 100644
index 077bb57a03..0000000000
--- a/doc/classes/ConvexPolygonShape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ConvexPolygonShape" inherits="Shape" version="4.0">
- <brief_description>
- Convex polygon shape for 3D physics.
- </brief_description>
- <description>
- Convex polygon shape resource, which can be added to a [PhysicsBody] or area.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="points" type="PackedVector3Array" setter="set_points" getter="get_points" default="PackedVector3Array( )">
- The list of 3D points forming the convex polygon shape.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ConvexPolygonShape3D.xml b/doc/classes/ConvexPolygonShape3D.xml
new file mode 100644
index 0000000000..c036f80e2d
--- /dev/null
+++ b/doc/classes/ConvexPolygonShape3D.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ConvexPolygonShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Convex polygon shape for 3D physics.
+ </brief_description>
+ <description>
+ Convex polygon shape resource, which can be added to a [PhysicsBody3D] or area.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="points" type="PackedVector3Array" setter="set_points" getter="get_points" default="PackedVector3Array( )">
+ The list of 3D points forming the convex polygon shape.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index 5024cdefbd..fe454d90cc 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -4,7 +4,7 @@
Describes a Bézier curve in 3D space.
</brief_description>
<description>
- This class describes a Bézier curve in 3D space. It is mainly used to give a shape to a [Path], but can be manually sampled for other purposes.
+ This class describes a Bézier curve in 3D space. It is mainly used to give a shape to a [Path3D], but can be manually sampled for other purposes.
It keeps a cache of precalculated points along the curve, to speed up further calculations.
</description>
<tutorials>
@@ -223,7 +223,7 @@
</argument>
<description>
Sets the tilt angle in radians for the point [code]idx[/code]. If the index is out of bounds, the function sends an error to the console.
- The tilt controls the rotation along the look-at axis an object traveling the path would have. In the case of a curve controlling a [PathFollow], this tilt is an offset over the natural tilt the [PathFollow] calculates.
+ The tilt controls the rotation along the look-at axis an object traveling the path would have. In the case of a curve controlling a [PathFollow3D], this tilt is an offset over the natural tilt the [PathFollow3D] calculates.
</description>
</method>
<method name="tessellate" qualifiers="const">
@@ -246,7 +246,7 @@
The distance in meters between two adjacent cached points. Changing it forces the cache to be recomputed the next time the [method get_baked_points] or [method get_baked_length] function is called. The smaller the distance, the more points in the cache and the more memory it will consume, so use with care.
</member>
<member name="up_vector_enabled" type="bool" setter="set_up_vector_enabled" getter="is_up_vector_enabled" default="true">
- If [code]true[/code], the curve will bake up vectors used for orientation. This is used when [member PathFollow.rotation_mode] is set to [constant PathFollow.ROTATION_ORIENTED]. Changing it forces the cache to be recomputed.
+ If [code]true[/code], the curve will bake up vectors used for orientation. This is used when [member PathFollow3D.rotation_mode] is set to [constant PathFollow3D.ROTATION_ORIENTED]. Changing it forces the cache to be recomputed.
</member>
</members>
<constants>
diff --git a/doc/classes/CylinderShape.xml b/doc/classes/CylinderShape.xml
deleted file mode 100644
index 54adbd3b04..0000000000
--- a/doc/classes/CylinderShape.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CylinderShape" inherits="Shape" version="4.0">
- <brief_description>
- Cylinder shape for collisions.
- </brief_description>
- <description>
- Cylinder shape for collisions.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
- The cylinder's height.
- </member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- The cylinder's radius.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/CylinderShape3D.xml b/doc/classes/CylinderShape3D.xml
new file mode 100644
index 0000000000..eb12568e71
--- /dev/null
+++ b/doc/classes/CylinderShape3D.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CylinderShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Cylinder shape for collisions.
+ </brief_description>
+ <description>
+ Cylinder shape for collisions.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
+ The cylinder's height.
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ The cylinder's radius.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 062e72388f..7bd01d6781 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -4,8 +4,9 @@
Dictionary type.
</brief_description>
<description>
- Dictionary type. Associative container which contains values referenced by unique keys. Dictionary are composed of pairs of keys (which must be unique) and values. 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].
+ 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.
+ 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.
Creating a dictionary:
[codeblock]
var my_dir = {} # Creates an empty dictionary.
@@ -16,15 +17,16 @@
key3: value3,
}
[/codeblock]
- You can access values of a dictionary by referencing appropriate key in above example [code]points_dir["White"][/code] would return value of 50.
+ You can access a dictionary's values by referencing the appropriate key. In the above example, [code]points_dir["White"][/code] will return [code]50[/code]. You can also write [code]points_dir.White[/code], which is equivalent. However, you'll have to use the bracket syntax if the key you're accessing the dictionary with isn't a fixed string (such as a number or variable).
[codeblock]
export(String, "White", "Yellow", "Orange") var my_color
var points_dir = {"White": 50, "Yellow": 75, "Orange": 100}
func _ready():
+ # We can't use dot syntax here as `my_color` is a variable.
var points = points_dir[my_color]
[/codeblock]
- In the above code [code]points[/code] will be assigned the value that is paired with the appropriate color selected in [code]my_color[/code].
+ In the above code, [code]points[/code] will be assigned the value that is paired with the appropriate color selected in [code]my_color[/code].
Dictionaries can contain more complex data:
[codeblock]
my_dir = {"First Array": [1, 2, 3, 4]} # Assigns an Array to a String key.
@@ -36,9 +38,17 @@
[/codeblock]
Finally, dictionaries can contain different types of keys and values in the same dictionary:
[codeblock]
- var my_dir = {"String Key": 5, 4: [1, 2, 3], 7: "Hello"} # This is a valid dictionary.
+ # This is a valid dictionary.
+ # To access the string "Nested value" below, use `my_dir.sub_dir.sub_key` or `my_dir["sub_dir"]["sub_key"]`.
+ # Indexing styles can be mixed and matched depending on your needs.
+ var my_dir = {
+ "String Key": 5,
+ 4: [1, 2, 3],
+ 7: "Hello",
+ "sub_dir": {"sub_key": "Nested value"},
+ }
[/codeblock]
- [b]Note:[/b] Unlike [Array]s you can't compare dictionaries directly:
+ [b]Note:[/b] Unlike [Array]s, you can't compare dictionaries directly:
[codeblock]
array1 = [1, 2, 3]
array2 = [1, 2, 3]
@@ -78,7 +88,7 @@
<argument index="0" name="deep" type="bool" default="false">
</argument>
<description>
- Creates a copy of the dictionary, and returns it.
+ Creates a copy of the dictionary, and returns it. The [code]deep[/code] parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects.
</description>
</method>
<method name="empty">
@@ -98,7 +108,7 @@
</description>
</method>
<method name="get">
- <return type="void">
+ <return type="Variant">
</return>
<argument index="0" name="key" type="Variant">
</argument>
diff --git a/doc/classes/DirectionalLight.xml b/doc/classes/DirectionalLight.xml
deleted file mode 100644
index a3ef830d5d..0000000000
--- a/doc/classes/DirectionalLight.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="DirectionalLight" inherits="Light" version="4.0">
- <brief_description>
- Directional light from a distance, as from the Sun.
- </brief_description>
- <description>
- A directional light is a type of [Light] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight transform (origin) is ignored. Only the basis is used to determine light direction.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="directional_shadow_bias_split_scale" type="float" setter="set_param" getter="get_param" default="0.25">
- Amount of extra bias for shadow splits that are far away. If self-shadowing occurs only on the splits far away, increasing this value can fix them.
- </member>
- <member name="directional_shadow_blend_splits" type="bool" setter="set_blend_splits" getter="is_blend_splits_enabled" default="false">
- If [code]true[/code], shadow detail is sacrificed in exchange for smoother transitions between splits.
- </member>
- <member name="directional_shadow_depth_range" type="int" setter="set_shadow_depth_range" getter="get_shadow_depth_range" enum="DirectionalLight.ShadowDepthRange" default="0">
- Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange].
- </member>
- <member name="directional_shadow_fade_start" type="float" setter="set_param" getter="get_param" default="0.8">
- </member>
- <member name="directional_shadow_max_distance" type="float" setter="set_param" getter="get_param" default="100.0">
- The maximum distance for shadow splits.
- </member>
- <member name="directional_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="DirectionalLight.ShadowMode" default="2">
- The light's shadow rendering algorithm. See [enum ShadowMode].
- </member>
- <member name="directional_shadow_normal_bias" type="float" setter="set_param" getter="get_param" default="0.8">
- Can be used to fix special cases of self shadowing when objects are perpendicular to the light.
- </member>
- <member name="directional_shadow_split_1" type="float" setter="set_param" getter="get_param" default="0.1">
- The distance from camera to shadow split 1. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or [code]SHADOW_PARALLEL_4_SPLITS[/code].
- </member>
- <member name="directional_shadow_split_2" type="float" setter="set_param" getter="get_param" default="0.2">
- The distance from shadow split 1 to split 2. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or [code]SHADOW_PARALLEL_4_SPLITS[/code].
- </member>
- <member name="directional_shadow_split_3" type="float" setter="set_param" getter="get_param" default="0.5">
- The distance from shadow split 2 to split 3. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [code]SHADOW_PARALLEL_4_SPLITS[/code].
- </member>
- <member name="shadow_bias" type="float" setter="set_param" getter="get_param" override="true" default="0.1" />
- </members>
- <constants>
- <constant name="SHADOW_ORTHOGONAL" value="0" enum="ShadowMode">
- Renders the entire scene's shadow map from an orthogonal point of view. May result in blockier shadows on close objects.
- </constant>
- <constant name="SHADOW_PARALLEL_2_SPLITS" value="1" enum="ShadowMode">
- Splits the view frustum in 2 areas, each with its own shadow map.
- </constant>
- <constant name="SHADOW_PARALLEL_4_SPLITS" value="2" enum="ShadowMode">
- Splits the view frustum in 4 areas, each with its own shadow map.
- </constant>
- <constant name="SHADOW_DEPTH_RANGE_STABLE" value="0" enum="ShadowDepthRange">
- Keeps the shadow stable when the camera moves, at the cost of lower effective shadow resolution.
- </constant>
- <constant name="SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="ShadowDepthRange">
- Tries to achieve maximum shadow resolution. May result in saw effect on shadow edges.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml
new file mode 100644
index 0000000000..a5d476f5c8
--- /dev/null
+++ b/doc/classes/DirectionalLight3D.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="DirectionalLight3D" inherits="Light3D" version="4.0">
+ <brief_description>
+ Directional light from a distance, as from the Sun.
+ </brief_description>
+ <description>
+ A directional light is a type of [Light3D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight3D transform (origin) is ignored. Only the basis is used to determine light direction.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="directional_shadow_bias_split_scale" type="float" setter="set_param" getter="get_param" default="0.25">
+ Amount of extra bias for shadow splits that are far away. If self-shadowing occurs only on the splits far away, increasing this value can fix them.
+ </member>
+ <member name="directional_shadow_blend_splits" type="bool" setter="set_blend_splits" getter="is_blend_splits_enabled" default="false">
+ If [code]true[/code], shadow detail is sacrificed in exchange for smoother transitions between splits.
+ </member>
+ <member name="directional_shadow_depth_range" type="int" setter="set_shadow_depth_range" getter="get_shadow_depth_range" enum="DirectionalLight3D.ShadowDepthRange" default="0">
+ Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange].
+ </member>
+ <member name="directional_shadow_fade_start" type="float" setter="set_param" getter="get_param" default="0.8">
+ </member>
+ <member name="directional_shadow_max_distance" type="float" setter="set_param" getter="get_param" default="100.0">
+ The maximum distance for shadow splits.
+ </member>
+ <member name="directional_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="DirectionalLight3D.ShadowMode" default="2">
+ The light's shadow rendering algorithm. See [enum ShadowMode].
+ </member>
+ <member name="directional_shadow_normal_bias" type="float" setter="set_param" getter="get_param" default="0.8">
+ Can be used to fix special cases of self shadowing when objects are perpendicular to the light.
+ </member>
+ <member name="directional_shadow_split_1" type="float" setter="set_param" getter="get_param" default="0.1">
+ The distance from camera to shadow split 1. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or [code]SHADOW_PARALLEL_4_SPLITS[/code].
+ </member>
+ <member name="directional_shadow_split_2" type="float" setter="set_param" getter="get_param" default="0.2">
+ The distance from shadow split 1 to split 2. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or [code]SHADOW_PARALLEL_4_SPLITS[/code].
+ </member>
+ <member name="directional_shadow_split_3" type="float" setter="set_param" getter="get_param" default="0.5">
+ The distance from shadow split 2 to split 3. Relative to [member directional_shadow_max_distance]. Only used when [member directional_shadow_mode] is [code]SHADOW_PARALLEL_4_SPLITS[/code].
+ </member>
+ <member name="shadow_bias" type="float" setter="set_param" getter="get_param" override="true" default="0.1" />
+ </members>
+ <constants>
+ <constant name="SHADOW_ORTHOGONAL" value="0" enum="ShadowMode">
+ Renders the entire scene's shadow map from an orthogonal point of view. May result in blockier shadows on close objects.
+ </constant>
+ <constant name="SHADOW_PARALLEL_2_SPLITS" value="1" enum="ShadowMode">
+ Splits the view frustum in 2 areas, each with its own shadow map.
+ </constant>
+ <constant name="SHADOW_PARALLEL_4_SPLITS" value="2" enum="ShadowMode">
+ Splits the view frustum in 4 areas, each with its own shadow map.
+ </constant>
+ <constant name="SHADOW_DEPTH_RANGE_STABLE" value="0" enum="ShadowDepthRange">
+ Keeps the shadow stable when the camera moves, at the cost of lower effective shadow resolution.
+ </constant>
+ <constant name="SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="ShadowDepthRange">
+ Tries to achieve maximum shadow resolution. May result in saw effect on shadow edges.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index cb59a69876..ed4257a809 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -77,11 +77,8 @@
<method name="get_current_dir">
<return type="String">
</return>
- <argument index="0" name="include_drive" type="bool" default="true">
- </argument>
<description>
Returns the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]).
- On Windows, if [code]include_drive[/code] is [code]false[/code], the leading drive specificator is omitted from the returned value (e.g. [code]\tmp\folder[/code]).
</description>
</method>
<method name="get_current_drive">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
new file mode 100644
index 0000000000..90828089f9
--- /dev/null
+++ b/doc/classes/DisplayServer.xml
@@ -0,0 +1,1049 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="DisplayServer" inherits="Object" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="alert">
+ <return type="void">
+ </return>
+ <argument index="0" name="text" type="String">
+ </argument>
+ <argument index="1" name="title" type="String" default="&quot;Alert!&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clipboard_get" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clipboard_set">
+ <return type="void">
+ </return>
+ <argument index="0" name="clipboard" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="console_set_visible">
+ <return type="void">
+ </return>
+ <argument index="0" name="console_visible" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="create_sub_window">
+ <return type="int">
+ </return>
+ <argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode">
+ </argument>
+ <argument index="1" name="rect" type="int">
+ </argument>
+ <argument index="2" name="arg2" type="Rect2i" default="Rect2i( 0, 0, 0, 0 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="cursor_get_shape" qualifiers="const">
+ <return type="int" enum="DisplayServer.CursorShape">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="cursor_set_custom_image">
+ <return type="void">
+ </return>
+ <argument index="0" name="cursor" type="Resource">
+ </argument>
+ <argument index="1" name="shape" type="int" enum="DisplayServer.CursorShape" default="0">
+ </argument>
+ <argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="cursor_set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="shape" type="int" enum="DisplayServer.CursorShape">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="delete_sub_window">
+ <return type="void">
+ </return>
+ <argument index="0" name="window_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="dialog_input_text">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="title" type="String">
+ </argument>
+ <argument index="1" name="description" type="String">
+ </argument>
+ <argument index="2" name="existing_text" type="String">
+ </argument>
+ <argument index="3" name="callback" type="Callable">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="dialog_show">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="title" type="String">
+ </argument>
+ <argument index="1" name="description" type="String">
+ </argument>
+ <argument index="2" name="buttons" type="PackedStringArray">
+ </argument>
+ <argument index="3" name="callback" type="Callable">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="enable_for_stealing_focus">
+ <return type="void">
+ </return>
+ <argument index="0" name="process_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="force_process_and_drop_events">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_latin_keyboard_variant" qualifiers="const">
+ <return type="int" enum="DisplayServer.LatinKeyboardVariant">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_screen_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_swap_ok_cancel">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_window_at_screen_position" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="position" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_window_list" qualifiers="const">
+ <return type="PackedInt32Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_add_check_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="label" type="String">
+ </argument>
+ <argument index="2" name="callback" type="Callable">
+ </argument>
+ <argument index="3" name="tag" type="Variant" default="null">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_add_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="label" type="String">
+ </argument>
+ <argument index="2" name="callback" type="Callable">
+ </argument>
+ <argument index="3" name="tag" type="Variant" default="null">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_add_separator">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_add_submenu_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="label" type="String">
+ </argument>
+ <argument index="2" name="submenu" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_clear">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_get_item_callback">
+ <return type="Callable">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_get_item_submenu">
+ <return type="String">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_get_item_tag">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_get_item_text">
+ <return type="String">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_is_item_checkable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_is_item_checked" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_remove_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_set_item_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <argument index="2" name="callback" type="Callable">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_set_item_checkable">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <argument index="2" name="checkable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_set_item_checked">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <argument index="2" name="checked" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_set_item_submenu">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <argument index="2" name="submenu" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_set_item_tag">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <argument index="2" name="tag" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_menu_set_item_text">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu_root" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <argument index="2" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_feature" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="feature" type="int" enum="DisplayServer.Feature">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="ime_get_selection" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="ime_get_text" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_console_visible" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="mouse_get_absolute_position" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="mouse_get_button_state" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="mouse_get_mode" qualifiers="const">
+ <return type="int" enum="DisplayServer.MouseMode">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="mouse_get_position" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="mouse_set_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="mouse_mode" type="int" enum="DisplayServer.MouseMode">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="mouse_warp_to_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_is_playing" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_pause">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_play">
+ <return type="int" enum="Error">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <argument index="1" name="volume" type="float">
+ </argument>
+ <argument index="2" name="audio_track" type="String">
+ </argument>
+ <argument index="3" name="subtitle_track" type="String">
+ </argument>
+ <argument index="4" name="arg4" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_stop">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="native_video_unpause">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="process_events">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="screen_get_dpi" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_get_orientation" qualifiers="const">
+ <return type="int" enum="DisplayServer.ScreenOrientation">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_get_position" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_get_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_get_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_get_usable_rect" qualifiers="const">
+ <return type="Rect2i">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_is_kept_on" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="screen_is_touchscreen" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_set_keep_on">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="screen_set_orientation">
+ <return type="void">
+ </return>
+ <argument index="0" name="orientation" type="int" enum="DisplayServer.ScreenOrientation">
+ </argument>
+ <argument index="1" name="screen" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_icon">
+ <return type="void">
+ </return>
+ <argument index="0" name="image" type="Image">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_native_icon">
+ <return type="void">
+ </return>
+ <argument index="0" name="filename" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="virtual_keyboard_get_height" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="virtual_keyboard_hide">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="virtual_keyboard_show">
+ <return type="void">
+ </return>
+ <argument index="0" name="existing_text" type="String">
+ </argument>
+ <argument index="1" name="position" type="Rect2" default="Rect2i( 0, 0, 0, 0 )">
+ </argument>
+ <argument index="2" name="max_length" type="int" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vsync_is_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="vsync_is_using_via_compositor" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="vsync_set_enabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vsync_set_use_via_compositor">
+ <return type="void">
+ </return>
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_attach_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance_id" type="int">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_can_draw" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_attached_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_current_screen" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="DisplayServer.WindowFlags">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_max_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_min_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_mode" qualifiers="const">
+ <return type="int" enum="DisplayServer.WindowMode">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_position" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_real_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_get_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_move_to_foreground">
+ <return type="void">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_request_attention">
+ <return type="void">
+ </return>
+ <argument index="0" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_current_screen">
+ <return type="void">
+ </return>
+ <argument index="0" name="screen" type="int">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_drop_files_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callback" type="Callable">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="DisplayServer.WindowFlags">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <argument index="2" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_ime_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="active" type="bool">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_ime_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector2i">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_input_event_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callback" type="Callable">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_input_text_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callback" type="Callable">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_max_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="max_size" type="Vector2i">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_min_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="min_size" type="Vector2i">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector2i">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_rect_changed_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callback" type="Callable">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="Vector2i">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_title">
+ <return type="void">
+ </return>
+ <argument index="0" name="title" type="String">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_transient">
+ <return type="void">
+ </return>
+ <argument index="0" name="window_id" type="int">
+ </argument>
+ <argument index="1" name="parent_window_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="window_set_window_event_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callback" type="Callable">
+ </argument>
+ <argument index="1" name="window_id" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="FEATURE_GLOBAL_MENU" value="0" enum="Feature">
+ </constant>
+ <constant name="FEATURE_SUBWINDOWS" value="1" enum="Feature">
+ </constant>
+ <constant name="FEATURE_TOUCHSCREEN" value="2" enum="Feature">
+ </constant>
+ <constant name="FEATURE_MOUSE" value="3" enum="Feature">
+ </constant>
+ <constant name="FEATURE_MOUSE_WARP" value="4" enum="Feature">
+ </constant>
+ <constant name="FEATURE_CLIPBOARD" value="5" enum="Feature">
+ </constant>
+ <constant name="FEATURE_VIRTUAL_KEYBOARD" value="6" enum="Feature">
+ </constant>
+ <constant name="FEATURE_CURSOR_SHAPE" value="7" enum="Feature">
+ </constant>
+ <constant name="FEATURE_CUSTOM_CURSOR_SHAPE" value="8" enum="Feature">
+ </constant>
+ <constant name="FEATURE_NATIVE_VIDEO" value="9" enum="Feature">
+ </constant>
+ <constant name="FEATURE_NATIVE_DIALOG" value="10" enum="Feature">
+ </constant>
+ <constant name="FEATURE_CONSOLE_WINDOW" value="11" enum="Feature">
+ </constant>
+ <constant name="FEATURE_IME" value="12" enum="Feature">
+ </constant>
+ <constant name="FEATURE_WINDOW_TRANSPARENCY" value="13" enum="Feature">
+ </constant>
+ <constant name="FEATURE_HIDPI" value="14" enum="Feature">
+ </constant>
+ <constant name="FEATURE_ICON" value="15" enum="Feature">
+ </constant>
+ <constant name="FEATURE_NATIVE_ICON" value="16" enum="Feature">
+ </constant>
+ <constant name="FEATURE_ORIENTATION" value="17" enum="Feature">
+ </constant>
+ <constant name="FEATURE_SWAP_BUFFERS" value="18" enum="Feature">
+ </constant>
+ <constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
+ </constant>
+ <constant name="MOUSE_MODE_HIDDEN" value="1" enum="MouseMode">
+ </constant>
+ <constant name="MOUSE_MODE_CAPTURED" value="2" enum="MouseMode">
+ </constant>
+ <constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
+ </constant>
+ <constant name="SCREEN_OF_MAIN_WINDOW" value="-1">
+ </constant>
+ <constant name="MAIN_WINDOW_ID" value="0">
+ </constant>
+ <constant name="INVALID_WINDOW_ID" value="-1">
+ </constant>
+ <constant name="SCREEN_LANDSCAPE" value="0" enum="ScreenOrientation">
+ </constant>
+ <constant name="SCREEN_PORTRAIT" value="1" enum="ScreenOrientation">
+ </constant>
+ <constant name="SCREEN_REVERSE_LANDSCAPE" value="2" enum="ScreenOrientation">
+ </constant>
+ <constant name="SCREEN_REVERSE_PORTRAIT" value="3" enum="ScreenOrientation">
+ </constant>
+ <constant name="SCREEN_SENSOR_LANDSCAPE" value="4" enum="ScreenOrientation">
+ </constant>
+ <constant name="SCREEN_SENSOR_PORTRAIT" value="5" enum="ScreenOrientation">
+ </constant>
+ <constant name="SCREEN_SENSOR" value="6" enum="ScreenOrientation">
+ </constant>
+ <constant name="CURSOR_ARROW" value="0" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_IBEAM" value="1" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_CROSS" value="3" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_WAIT" value="4" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_BUSY" value="5" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_DRAG" value="6" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_VSIZE" value="9" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_HSIZE" value="10" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_MOVE" value="13" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_VSPLIT" value="14" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_HSPLIT" value="15" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_HELP" value="16" enum="CursorShape">
+ </constant>
+ <constant name="CURSOR_MAX" value="17" enum="CursorShape">
+ </constant>
+ <constant name="WINDOW_MODE_WINDOWED" value="0" enum="WindowMode">
+ </constant>
+ <constant name="WINDOW_MODE_MINIMIZED" value="1" enum="WindowMode">
+ </constant>
+ <constant name="WINDOW_MODE_MAXIMIZED" value="2" enum="WindowMode">
+ </constant>
+ <constant name="WINDOW_MODE_FULLSCREEN" value="3" enum="WindowMode">
+ </constant>
+ <constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags">
+ </constant>
+ <constant name="WINDOW_FLAG_BORDERLESS" value="1" enum="WindowFlags">
+ </constant>
+ <constant name="WINDOW_FLAG_ALWAYS_ON_TOP" value="2" enum="WindowFlags">
+ </constant>
+ <constant name="WINDOW_FLAG_TRANSPARENT" value="3" enum="WindowFlags">
+ </constant>
+ <constant name="WINDOW_FLAG_NO_FOCUS" value="4" enum="WindowFlags">
+ </constant>
+ <constant name="WINDOW_FLAG_MAX" value="5" enum="WindowFlags">
+ </constant>
+ <constant name="LATIN_KEYBOARD_QWERTY" value="0" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="LATIN_KEYBOARD_QWERTZ" value="1" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="LATIN_KEYBOARD_AZERTY" value="2" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="LATIN_KEYBOARD_QZERTY" value="3" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="LATIN_KEYBOARD_DVORAK" value="4" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="LATIN_KEYBOARD_NEO" value="5" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="LATIN_KEYBOARD_COLEMAK" value="6" enum="LatinKeyboardVariant">
+ </constant>
+ <constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
+ </constant>
+ <constant name="WINDOW_EVENT_MOUSE_EXIT" value="1" enum="WindowEvent">
+ </constant>
+ <constant name="WINDOW_EVENT_FOCUS_IN" value="2" enum="WindowEvent">
+ </constant>
+ <constant name="WINDOW_EVENT_FOCUS_OUT" value="3" enum="WindowEvent">
+ </constant>
+ <constant name="WINDOW_EVENT_CLOSE_REQUEST" value="4" enum="WindowEvent">
+ </constant>
+ <constant name="WINDOW_EVENT_GO_BACK_REQUEST" value="5" enum="WindowEvent">
+ </constant>
+ <constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml
index da3840384e..8cfd3b63d6 100644
--- a/doc/classes/EditorExportPlugin.xml
+++ b/doc/classes/EditorExportPlugin.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlugin" inherits="Reference" version="4.0">
<brief_description>
+ A script that is executed when exporting projects.
</brief_description>
<description>
</description>
@@ -19,12 +20,14 @@
<argument index="3" name="flags" type="int">
</argument>
<description>
+ Virtual method to be overridden by the user. It is called when the export starts and provides all information about the export.
</description>
</method>
<method name="_export_end" qualifiers="virtual">
<return type="void">
</return>
<description>
+ Virtual method to be overridden by the user. Called when the export is finished.
</description>
</method>
<method name="_export_file" qualifiers="virtual">
@@ -91,6 +94,14 @@
<description>
</description>
</method>
+ <method name="add_ios_project_static_lib">
+ <return type="void">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="add_shared_object">
<return type="void">
</return>
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index 387962cf6a..53db8dd293 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorFeatureProfile" inherits="Reference" version="4.0">
<brief_description>
+ An editor feature profile which can be used to disable specific features.
</brief_description>
<description>
+ An editor feature profile can be used to disable specific features of the Godot editor. When disabled, the features won't appear in the editor, which makes the editor less cluttered. This is useful in education settings to reduce confusion or when working in a team. For example, artists and level designers could use a feature profile that disables the script editor to avoid accidentally making changes to files they aren't supposed to edit.
+ To manage editor feature profiles visually, use [b]Editor &gt; Manage Feature Profiles...[/b] at the top of the editor window.
</description>
<tutorials>
</tutorials>
@@ -13,6 +16,7 @@
<argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature">
</argument>
<description>
+ Returns the specified [code]feature[/code]'s human-readable name.
</description>
</method>
<method name="is_class_disabled" qualifiers="const">
@@ -21,6 +25,7 @@
<argument index="0" name="class_name" type="StringName">
</argument>
<description>
+ Returns [code]true[/code] if the class specified by [code]class_name[/code] is disabled. When disabled, the class won't appear in the Create New Node dialog.
</description>
</method>
<method name="is_class_editor_disabled" qualifiers="const">
@@ -29,6 +34,7 @@
<argument index="0" name="class_name" type="StringName">
</argument>
<description>
+ Returns [code]true[/code] if editing for the class specified by [code]class_name[/code] is disabled. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
</description>
</method>
<method name="is_class_property_disabled" qualifiers="const">
@@ -39,6 +45,7 @@
<argument index="1" name="property" type="StringName">
</argument>
<description>
+ Returns [code]true[/code] if [code]property[/code] is disabled in the class specified by [code]class_name[/code]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [code]class_name[/code].
</description>
</method>
<method name="is_feature_disabled" qualifiers="const">
@@ -47,6 +54,7 @@
<argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature">
</argument>
<description>
+ Returns [code]true[/code] if the [code]feature[/code] is disabled. When a feature is disabled, it will disappear from the editor entirely.
</description>
</method>
<method name="load_from_file">
@@ -55,6 +63,7 @@
<argument index="0" name="path" type="String">
</argument>
<description>
+ Loads an editor feature profile from a file. The file must follow the JSON format obtained by using the feature profile manager's [b]Export[/b] button or the [method save_to_file] method.
</description>
</method>
<method name="save_to_file">
@@ -63,6 +72,7 @@
<argument index="0" name="path" type="String">
</argument>
<description>
+ Saves the editor feature profile to a file in JSON format. It can then be imported using the feature profile manager's [b]Import[/b] button or the [method load_from_file] button.
</description>
</method>
<method name="set_disable_class">
@@ -73,6 +83,7 @@
<argument index="1" name="disable" type="bool">
</argument>
<description>
+ If [code]disable[/code] is [code]true[/code], disables the class specified by [code]class_name[/code]. When disabled, the class won't appear in the Create New Node dialog.
</description>
</method>
<method name="set_disable_class_editor">
@@ -83,6 +94,7 @@
<argument index="1" name="disable" type="bool">
</argument>
<description>
+ If [code]disable[/code] is [code]true[/code], disables editing for the class specified by [code]class_name[/code]. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
</description>
</method>
<method name="set_disable_class_property">
@@ -95,6 +107,7 @@
<argument index="2" name="disable" type="bool">
</argument>
<description>
+ If [code]disable[/code] is [code]true[/code], disables editing for [code]property[/code] in the class specified by [code]class_name[/code]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [code]class_name[/code].
</description>
</method>
<method name="set_disable_feature">
@@ -105,23 +118,31 @@
<argument index="1" name="disable" type="bool">
</argument>
<description>
+ If [code]disable[/code] is [code]true[/code], disables the editor feature specified in [code]feature[/code]. When a feature is disabled, it will disappear from the editor entirely.
</description>
</method>
</methods>
<constants>
<constant name="FEATURE_3D" value="0" enum="Feature">
+ The 3D editor. If this feature is disabled, the 3D editor won't display but 3D nodes will still display in the Create New Node dialog.
</constant>
<constant name="FEATURE_SCRIPT" value="1" enum="Feature">
+ The Script tab, which contains the script editor and class reference browser. If this feature is disabled, the Script tab won't display.
</constant>
<constant name="FEATURE_ASSET_LIB" value="2" enum="Feature">
+ The AssetLib tab. If this feature is disabled, the AssetLib tab won't display.
</constant>
<constant name="FEATURE_SCENE_TREE" value="3" enum="Feature">
+ Scene tree editing. If this feature is disabled, the Scene tree dock will still be visible but will be read-only.
</constant>
<constant name="FEATURE_IMPORT_DOCK" value="4" enum="Feature">
+ The Import dock. If this feature is disabled, the Import dock won't be visible.
</constant>
<constant name="FEATURE_NODE_DOCK" value="5" enum="Feature">
+ The Node dock. If this feature is disabled, signals and groups won't be visible and modifiable from the editor.
</constant>
<constant name="FEATURE_FILESYSTEM_DOCK" value="6" enum="Feature">
+ The FileSystem dock. If this feature is disabled, the FileSystem dock won't be visible.
</constant>
<constant name="FEATURE_MAX" value="7" enum="Feature">
Represents the size of the [enum Feature] enum.
diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml
index 2afdfde064..084459e518 100644
--- a/doc/classes/EditorFileDialog.xml
+++ b/doc/classes/EditorFileDialog.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorFileDialog" inherits="ConfirmationDialog" version="4.0">
<brief_description>
+ A modified version of [FileDialog] used by the editor.
</brief_description>
<description>
</description>
@@ -59,14 +60,13 @@
<member name="display_mode" type="int" setter="set_display_mode" getter="get_display_mode" enum="EditorFileDialog.DisplayMode" default="0">
The view format in which the [EditorFileDialog] displays resources to the user.
</member>
- <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="EditorFileDialog.Mode" default="4">
- The purpose of the [EditorFileDialog], which defines the allowed behaviors.
+ <member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="EditorFileDialog.FileMode" default="4">
+ The dialog's open or save mode, which affects the selection behavior. See [enum FileMode]
</member>
- <member name="resizable" type="bool" setter="set_resizable" getter="get_resizable" override="true" default="true" />
<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog].
</member>
- <member name="window_title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Save a File&quot;" />
+ <member name="title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Save a File&quot;" />
</members>
<signals>
<signal name="dir_selected">
@@ -92,19 +92,19 @@
</signal>
</signals>
<constants>
- <constant name="MODE_OPEN_FILE" value="0" enum="Mode">
+ <constant name="FILE_MODE_OPEN_FILE" value="0" enum="FileMode">
The [EditorFileDialog] can select only one file. Accepting the window will open the file.
</constant>
- <constant name="MODE_OPEN_FILES" value="1" enum="Mode">
+ <constant name="FILE_MODE_OPEN_FILES" value="1" enum="FileMode">
The [EditorFileDialog] can select multiple files. Accepting the window will open all files.
</constant>
- <constant name="MODE_OPEN_DIR" value="2" enum="Mode">
+ <constant name="FILE_MODE_OPEN_DIR" value="2" enum="FileMode">
The [EditorFileDialog] can select only one directory. Accepting the window will open the directory.
</constant>
- <constant name="MODE_OPEN_ANY" value="3" enum="Mode">
+ <constant name="FILE_MODE_OPEN_ANY" value="3" enum="FileMode">
The [EditorFileDialog] can select a file or directory. Accepting the window will open it.
</constant>
- <constant name="MODE_SAVE_FILE" value="4" enum="Mode">
+ <constant name="FILE_MODE_SAVE_FILE" value="4" enum="FileMode">
The [EditorFileDialog] can select only one file. Accepting the window will save the file.
</constant>
<constant name="ACCESS_RESOURCES" value="0" enum="Access">
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index a79c57e90f..30e1de1f5e 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -75,6 +75,7 @@
<return type="void">
</return>
<description>
+ Scans the script files and updates the list of custom class names.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 771b7d59d4..5e76f90fc4 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -52,6 +52,12 @@
Returns the editor [Viewport].
</description>
</method>
+ <method name="get_file_system_dock">
+ <return type="FileSystemDock">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_inspector" qualifiers="const">
<return type="EditorInspector">
</return>
diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml
new file mode 100644
index 0000000000..6d695ddeea
--- /dev/null
+++ b/doc/classes/EditorNode3DGizmo.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorNode3DGizmo" inherits="Node3DGizmo" version="4.0">
+ <brief_description>
+ Custom gizmo for editing Node3D objects.
+ </brief_description>
+ <description>
+ Custom gizmo that is used for providing custom visualization and editing (handles) for Node3D objects. See [EditorNode3DGizmoPlugin] for more information.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_collision_segments">
+ <return type="void">
+ </return>
+ <argument index="0" name="segments" type="PackedVector3Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_collision_triangles">
+ <return type="void">
+ </return>
+ <argument index="0" name="triangles" type="TriangleMesh">
+ </argument>
+ <description>
+ Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be generated from a regular [Mesh] too. Call this function during [method redraw].
+ </description>
+ </method>
+ <method name="add_handles">
+ <return type="void">
+ </return>
+ <argument index="0" name="handles" type="PackedVector3Array">
+ </argument>
+ <argument index="1" name="material" type="Material">
+ </argument>
+ <argument index="2" name="billboard" type="bool" default="false">
+ </argument>
+ <argument index="3" name="secondary" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a list of handles (points) which can be used to deform the object being edited.
+ There are virtual functions which will be called upon editing of these handles. Call this function during [method redraw].
+ </description>
+ </method>
+ <method name="add_lines">
+ <return type="void">
+ </return>
+ <argument index="0" name="lines" type="PackedVector3Array">
+ </argument>
+ <argument index="1" name="material" type="Material">
+ </argument>
+ <argument index="2" name="billboard" type="bool" default="false">
+ </argument>
+ <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )">
+ </argument>
+ <description>
+ Adds lines to the gizmo (as sets of 2 points), with a given material. The lines are used for visualizing the gizmo. Call this function during [method redraw].
+ </description>
+ </method>
+ <method name="add_mesh">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="ArrayMesh">
+ </argument>
+ <argument index="1" name="billboard" type="bool" default="false">
+ </argument>
+ <argument index="2" name="skeleton" type="SkinReference" default="null">
+ </argument>
+ <argument index="3" name="material" type="Material" default="null">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_unscaled_billboard">
+ <return type="void">
+ </return>
+ <argument index="0" name="material" type="Material">
+ </argument>
+ <argument index="1" name="default_scale" type="float" default="1">
+ </argument>
+ <argument index="2" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )">
+ </argument>
+ <description>
+ Adds an unscaled billboard for visualization. Call this function during [method redraw].
+ </description>
+ </method>
+ <method name="clear">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="commit_handle" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <argument index="1" name="restore" type="Variant">
+ </argument>
+ <argument index="2" name="cancel" type="bool" default="false">
+ </argument>
+ <description>
+ Commit a handle being edited (handles must have been previously added by [method add_handles]).
+ If the [code]cancel[/code] parameter is [code]true[/code], an option to restore the edited value to the original is provided.
+ </description>
+ </method>
+ <method name="get_handle_name" qualifiers="virtual">
+ <return type="String">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ Gets the name of an edited handle (handles must have been previously added by [method add_handles]).
+ Handles can be named for reference to the user when editing.
+ </description>
+ </method>
+ <method name="get_handle_value" qualifiers="virtual">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ Gets actual value of a handle. This value can be anything and used for eventually undoing the motion when calling [method commit_handle].
+ </description>
+ </method>
+ <method name="get_plugin" qualifiers="const">
+ <return type="EditorNode3DGizmoPlugin">
+ </return>
+ <description>
+ Returns the [EditorNode3DGizmoPlugin] that owns this gizmo. It's useful to retrieve materials using [method EditorNode3DGizmoPlugin.get_material].
+ </description>
+ </method>
+ <method name="get_spatial_node" qualifiers="const">
+ <return type="Node3D">
+ </return>
+ <description>
+ Returns the Node3D node associated with this gizmo.
+ </description>
+ </method>
+ <method name="is_handle_highlighted" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ Gets whether a handle is highlighted or not.
+ </description>
+ </method>
+ <method name="redraw" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <description>
+ This function is called when the Node3D this gizmo refers to changes (the [method Node3D.update_gizmo] is called).
+ </description>
+ </method>
+ <method name="set_handle" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <argument index="1" name="camera" type="Camera3D">
+ </argument>
+ <argument index="2" name="point" type="Vector2">
+ </argument>
+ <description>
+ This function is used when the user drags a gizmo handle (previously added with [method add_handles]) in screen coordinates.
+ The [Camera3D] is also provided so screen coordinates can be converted to raycasts.
+ </description>
+ </method>
+ <method name="set_hidden">
+ <return type="void">
+ </return>
+ <argument index="0" name="hidden" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_spatial_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Node">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
new file mode 100644
index 0000000000..ca75b47fbf
--- /dev/null
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorNode3DGizmoPlugin" inherits="Resource" version="4.0">
+ <brief_description>
+ Used by the editor to define Node3D gizmo types.
+ </brief_description>
+ <description>
+ EditorNode3DGizmoPlugin allows you to define a new type of Gizmo. There are two main ways to do so: extending [EditorNode3DGizmoPlugin] for the simpler gizmos, or creating a new [EditorNode3DGizmo] type. See the tutorial in the documentation for more info.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/spatial_gizmos.html</link>
+ </tutorials>
+ <methods>
+ <method name="add_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="material" type="StandardMaterial3D">
+ </argument>
+ <description>
+ Adds a new material to the internal material list for the plugin. It can then be accessed with [method get_material]. Should not be overridden.
+ </description>
+ </method>
+ <method name="can_be_hidden" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <description>
+ Override this method to define whether the gizmo can be hidden or not. Returns [code]true[/code] if not overridden.
+ </description>
+ </method>
+ <method name="commit_handle" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <argument index="2" name="restore" type="Variant">
+ </argument>
+ <argument index="3" name="cancel" type="bool" default="false">
+ </argument>
+ <description>
+ Override this method to commit gizmo handles. Called for this plugin's active gizmos.
+ </description>
+ </method>
+ <method name="create_gizmo" qualifiers="virtual">
+ <return type="EditorNode3DGizmo">
+ </return>
+ <argument index="0" name="spatial" type="Node3D">
+ </argument>
+ <description>
+ Override this method to return a custom [EditorNode3DGizmo] for the spatial nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method has_gizmo].
+ </description>
+ </method>
+ <method name="create_handle_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="billboard" type="bool" default="false">
+ </argument>
+ <description>
+ Creates a handle 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_handles]. Should not be overridden.
+ </description>
+ </method>
+ <method name="create_icon_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="texture" type="Texture2D">
+ </argument>
+ <argument index="2" name="on_top" type="bool" default="false">
+ </argument>
+ <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
+ </argument>
+ <description>
+ Creates an icon 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_unscaled_billboard]. Should not be overridden.
+ </description>
+ </method>
+ <method name="create_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <argument index="2" name="billboard" type="bool" default="false">
+ </argument>
+ <argument index="3" name="on_top" type="bool" default="false">
+ </argument>
+ <argument index="4" name="use_vertex_color" type="bool" default="false">
+ </argument>
+ <description>
+ 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_handle_name" qualifiers="virtual">
+ <return type="String">
+ </return>
+ <argument index="0" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Override this method to provide gizmo's handle names. Called for this plugin's active gizmos.
+ </description>
+ </method>
+ <method name="get_handle_value" qualifiers="virtual">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Gets actual value of a handle from gizmo. Called for this plugin's active gizmos.
+ </description>
+ </method>
+ <method name="get_material">
+ <return type="StandardMaterial3D">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <description>
+ 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="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="has_gizmo" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <argument index="0" name="spatial" type="Node3D">
+ </argument>
+ <description>
+ Override this method to define which Node3D nodes have a gizmo from this plugin. Whenever a [Node3D] node is added to a scene this method is called, if it returns [code]true[/code] the node gets a generic [EditorNode3DGizmo] assigned and is added to this plugin's list of active gizmos.
+ </description>
+ </method>
+ <method name="is_handle_highlighted" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <argument index="0" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Gets whether a handle is highlighted or not. Called for this plugin's active gizmos.
+ </description>
+ </method>
+ <method name="is_selectable_when_hidden" qualifiers="virtual">
+ <return type="bool">
+ </return>
+ <description>
+ Override this method to define whether Node3D with this gizmo should be selecteble even when the gizmo is hidden.
+ </description>
+ </method>
+ <method name="redraw" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <description>
+ Callback to redraw the provided gizmo. Called for this plugin's active gizmos.
+ </description>
+ </method>
+ <method name="set_handle" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="gizmo" type="EditorNode3DGizmo">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <argument index="2" name="camera" type="Camera3D">
+ </argument>
+ <argument index="3" name="point" type="Vector2">
+ </argument>
+ <description>
+ Update the value of a handle after it has been updated. Called for this plugin's active gizmos.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 587fd51f1e..19583fca28 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -71,7 +71,7 @@
</argument>
<description>
Adds a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed.
- When given node or resource is selected, the base type will be instanced (e.g. "Spatial", "Control", "Resource"), then the script will be loaded and set to this object.
+ When given node or resource is selected, the base type will be instanced (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object.
You can use the virtual method [method handles] to check if your custom object is being edited by checking the script or using the [code]is[/code] keyword.
During run-time, this will be a simple object with a script so this function does not need to be called then.
</description>
@@ -111,7 +111,7 @@
<method name="add_spatial_gizmo_plugin">
<return type="void">
</return>
- <argument index="0" name="plugin" type="EditorSpatialGizmoPlugin">
+ <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin">
</argument>
<description>
</description>
@@ -229,7 +229,7 @@
<method name="forward_spatial_gui_input" qualifiers="virtual">
<return type="bool">
</return>
- <argument index="0" name="camera" type="Camera">
+ <argument index="0" name="camera" type="Camera3D">
</argument>
<argument index="1" name="event" type="InputEvent">
</argument>
@@ -450,7 +450,7 @@
<method name="remove_spatial_gizmo_plugin">
<return type="void">
</return>
- <argument index="0" name="plugin" type="EditorSpatialGizmoPlugin">
+ <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin">
</argument>
<description>
</description>
diff --git a/doc/classes/EditorSpatialGizmo.xml b/doc/classes/EditorSpatialGizmo.xml
deleted file mode 100644
index b8c4daab07..0000000000
--- a/doc/classes/EditorSpatialGizmo.xml
+++ /dev/null
@@ -1,189 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSpatialGizmo" inherits="SpatialGizmo" version="4.0">
- <brief_description>
- Custom gizmo for editing Spatial objects.
- </brief_description>
- <description>
- Custom gizmo that is used for providing custom visualization and editing (handles) for 3D Spatial objects. See [EditorSpatialGizmoPlugin] for more information.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_collision_segments">
- <return type="void">
- </return>
- <argument index="0" name="segments" type="PackedVector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_collision_triangles">
- <return type="void">
- </return>
- <argument index="0" name="triangles" type="TriangleMesh">
- </argument>
- <description>
- Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be generated from a regular [Mesh] too. Call this function during [method redraw].
- </description>
- </method>
- <method name="add_handles">
- <return type="void">
- </return>
- <argument index="0" name="handles" type="PackedVector3Array">
- </argument>
- <argument index="1" name="material" type="Material">
- </argument>
- <argument index="2" name="billboard" type="bool" default="false">
- </argument>
- <argument index="3" name="secondary" type="bool" default="false">
- </argument>
- <description>
- Adds a list of handles (points) which can be used to deform the object being edited.
- There are virtual functions which will be called upon editing of these handles. Call this function during [method redraw].
- </description>
- </method>
- <method name="add_lines">
- <return type="void">
- </return>
- <argument index="0" name="lines" type="PackedVector3Array">
- </argument>
- <argument index="1" name="material" type="Material">
- </argument>
- <argument index="2" name="billboard" type="bool" default="false">
- </argument>
- <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )">
- </argument>
- <description>
- Adds lines to the gizmo (as sets of 2 points), with a given material. The lines are used for visualizing the gizmo. Call this function during [method redraw].
- </description>
- </method>
- <method name="add_mesh">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="ArrayMesh">
- </argument>
- <argument index="1" name="billboard" type="bool" default="false">
- </argument>
- <argument index="2" name="skeleton" type="SkinReference" default="null">
- </argument>
- <argument index="3" name="material" type="Material" default="null">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_unscaled_billboard">
- <return type="void">
- </return>
- <argument index="0" name="material" type="Material">
- </argument>
- <argument index="1" name="default_scale" type="float" default="1">
- </argument>
- <argument index="2" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )">
- </argument>
- <description>
- Adds an unscaled billboard for visualization. Call this function during [method redraw].
- </description>
- </method>
- <method name="clear">
- <return type="void">
- </return>
- <description>
- </description>
- </method>
- <method name="commit_handle" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <argument index="1" name="restore" type="Variant">
- </argument>
- <argument index="2" name="cancel" type="bool" default="false">
- </argument>
- <description>
- Commit a handle being edited (handles must have been previously added by [method add_handles]).
- If the [code]cancel[/code] parameter is [code]true[/code], an option to restore the edited value to the original is provided.
- </description>
- </method>
- <method name="get_handle_name" qualifiers="virtual">
- <return type="String">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <description>
- Gets the name of an edited handle (handles must have been previously added by [method add_handles]).
- Handles can be named for reference to the user when editing.
- </description>
- </method>
- <method name="get_handle_value" qualifiers="virtual">
- <return type="Variant">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <description>
- Gets actual value of a handle. This value can be anything and used for eventually undoing the motion when calling [method commit_handle].
- </description>
- </method>
- <method name="get_plugin" qualifiers="const">
- <return type="EditorSpatialGizmoPlugin">
- </return>
- <description>
- Returns the [EditorSpatialGizmoPlugin] that owns this gizmo. It's useful to retrieve materials using [method EditorSpatialGizmoPlugin.get_material].
- </description>
- </method>
- <method name="get_spatial_node" qualifiers="const">
- <return type="Spatial">
- </return>
- <description>
- Returns the Spatial node associated with this gizmo.
- </description>
- </method>
- <method name="is_handle_highlighted" qualifiers="virtual">
- <return type="bool">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <description>
- Gets whether a handle is highlighted or not.
- </description>
- </method>
- <method name="redraw" qualifiers="virtual">
- <return type="void">
- </return>
- <description>
- This function is called when the Spatial this gizmo refers to changes (the [method Spatial.update_gizmo] is called).
- </description>
- </method>
- <method name="set_handle" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <argument index="1" name="camera" type="Camera">
- </argument>
- <argument index="2" name="point" type="Vector2">
- </argument>
- <description>
- This function is used when the user drags a gizmo handle (previously added with [method add_handles]) in screen coordinates.
- The [Camera] is also provided so screen coordinates can be converted to raycasts.
- </description>
- </method>
- <method name="set_hidden">
- <return type="void">
- </return>
- <argument index="0" name="hidden" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_spatial_node">
- <return type="void">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/EditorSpatialGizmoPlugin.xml b/doc/classes/EditorSpatialGizmoPlugin.xml
deleted file mode 100644
index b1a4a25a5f..0000000000
--- a/doc/classes/EditorSpatialGizmoPlugin.xml
+++ /dev/null
@@ -1,198 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSpatialGizmoPlugin" inherits="Resource" version="4.0">
- <brief_description>
- Used by the editor to define Spatial gizmo types.
- </brief_description>
- <description>
- EditorSpatialGizmoPlugin allows you to define a new type of Gizmo. There are two main ways to do so: extending [EditorSpatialGizmoPlugin] for the simpler gizmos, or creating a new [EditorSpatialGizmo] type. See the tutorial in the documentation for more info.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/spatial_gizmos.html</link>
- </tutorials>
- <methods>
- <method name="add_material">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="material" type="StandardMaterial3D">
- </argument>
- <description>
- Adds a new material to the internal material list for the plugin. It can then be accessed with [method get_material]. Should not be overridden.
- </description>
- </method>
- <method name="can_be_hidden" qualifiers="virtual">
- <return type="bool">
- </return>
- <description>
- Override this method to define whether the gizmo can be hidden or not. Returns [code]true[/code] if not overridden.
- </description>
- </method>
- <method name="commit_handle" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <argument index="2" name="restore" type="Variant">
- </argument>
- <argument index="3" name="cancel" type="bool" default="false">
- </argument>
- <description>
- Override this method to commit gizmo handles. Called for this plugin's active gizmos.
- </description>
- </method>
- <method name="create_gizmo" qualifiers="virtual">
- <return type="EditorSpatialGizmo">
- </return>
- <argument index="0" name="spatial" type="Spatial">
- </argument>
- <description>
- Override this method to return a custom [EditorSpatialGizmo] for the spatial nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method has_gizmo].
- </description>
- </method>
- <method name="create_handle_material">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="billboard" type="bool" default="false">
- </argument>
- <description>
- Creates a handle 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 EditorSpatialGizmo.add_handles]. Should not be overridden.
- </description>
- </method>
- <method name="create_icon_material">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="texture" type="Texture2D">
- </argument>
- <argument index="2" name="on_top" type="bool" default="false">
- </argument>
- <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )">
- </argument>
- <description>
- Creates an icon 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 EditorSpatialGizmo.add_unscaled_billboard]. Should not be overridden.
- </description>
- </method>
- <method name="create_material">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <argument index="2" name="billboard" type="bool" default="false">
- </argument>
- <argument index="3" name="on_top" type="bool" default="false">
- </argument>
- <argument index="4" name="use_vertex_color" type="bool" default="false">
- </argument>
- <description>
- 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 EditorSpatialGizmo.add_mesh] and [method EditorSpatialGizmo.add_lines]. Should not be overridden.
- </description>
- </method>
- <method name="get_handle_name" qualifiers="virtual">
- <return type="String">
- </return>
- <argument index="0" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Override this method to provide gizmo's handle names. Called for this plugin's active gizmos.
- </description>
- </method>
- <method name="get_handle_value" qualifiers="virtual">
- <return type="Variant">
- </return>
- <argument index="0" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Gets actual value of a handle from gizmo. Called for this plugin's active gizmos.
- </description>
- </method>
- <method name="get_material">
- <return type="StandardMaterial3D">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <description>
- Gets material from the internal list of materials. If an [EditorSpatialGizmo] 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="String">
- </return>
- <description>
- </description>
- </method>
- <method name="has_gizmo" qualifiers="virtual">
- <return type="bool">
- </return>
- <argument index="0" name="spatial" type="Spatial">
- </argument>
- <description>
- Override this method to define which Spatial nodes have a gizmo from this plugin. Whenever a [Spatial] node is added to a scene this method is called, if it returns [code]true[/code] the node gets a generic [EditorSpatialGizmo] assigned and is added to this plugin's list of active gizmos.
- </description>
- </method>
- <method name="is_handle_highlighted" qualifiers="virtual">
- <return type="bool">
- </return>
- <argument index="0" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Gets whether a handle is highlighted or not. Called for this plugin's active gizmos.
- </description>
- </method>
- <method name="is_selectable_when_hidden" qualifiers="virtual">
- <return type="bool">
- </return>
- <description>
- Override this method to define whether Spatial with this gizmo should be selecteble even when the gizmo is hidden.
- </description>
- </method>
- <method name="redraw" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <description>
- Callback to redraw the provided gizmo. Called for this plugin's active gizmos.
- </description>
- </method>
- <method name="set_handle" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="gizmo" type="EditorSpatialGizmo">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <argument index="2" name="camera" type="Camera">
- </argument>
- <argument index="3" name="point" type="Vector2">
- </argument>
- <description>
- Update the value of a handle after it has been updated. Called for this plugin's active gizmos.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 3dad948629..6f55bfc229 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -108,7 +108,7 @@
If [code]true[/code], the depth fog effect is enabled. When enabled, fog will appear in the distance (relative to the camera).
</member>
<member name="fog_depth_end" type="float" setter="set_fog_depth_end" getter="get_fog_depth_end" default="100.0">
- The fog's depth end distance from the camera. If this value is set to 0, it will be equal to the current camera's [member Camera.far] value.
+ The fog's depth end distance from the camera. If this value is set to 0, it will be equal to the current camera's [member Camera3D.far] value.
</member>
<member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false">
If [code]true[/code], fog effects are enabled. [member fog_height_enabled] and/or [member fog_depth_enabled] must be set to [code]true[/code] to actually display fog.
@@ -126,7 +126,7 @@
The Y coordinate where the height fog will be the least intense. If this value is greater than [member fog_height_max], fog will be displayed from top to bottom. Otherwise, it will be displayed from bottom to top.
</member>
<member name="fog_sun_amount" type="float" setter="set_fog_sun_amount" getter="get_fog_sun_amount" default="0.0">
- The intensity of the depth fog color transition when looking towards the sun. The sun's direction is determined automatically using the DirectionalLight node in the scene.
+ The intensity of the depth fog color transition when looking towards the sun. The sun's direction is determined automatically using the DirectionalLight3D node in the scene.
</member>
<member name="fog_sun_color" type="Color" setter="set_fog_sun_color" getter="get_fog_sun_color" default="Color( 1, 0.9, 0.7, 1 )">
The depth fog's [Color] when looking towards the sun.
@@ -137,10 +137,6 @@
<member name="fog_transmit_enabled" type="bool" setter="set_fog_transmit_enabled" getter="is_fog_transmit_enabled" default="false">
Enables fog's light transmission effect. If [code]true[/code], light will be more visible in the fog to simulate light scattering as in real life.
</member>
- <member name="glow_bicubic_upscale" type="bool" setter="set_glow_bicubic_upscale" getter="is_glow_bicubic_upscale_enabled" default="false">
- Smooths out the blockiness created by sampling higher levels, at the cost of performance.
- [b]Note:[/b] When using the GLES2 renderer, this is only available if the GPU supports the [code]GL_EXT_gpu_shader4[/code] extension.
- </member>
<member name="glow_blend_mode" type="int" setter="set_glow_blend_mode" getter="get_glow_blend_mode" enum="Environment.GlowBlendMode" default="2">
The glow blending mode.
</member>
@@ -191,6 +187,7 @@
<member name="reflected_light_source" type="int" setter="set_reflection_source" getter="get_reflection_source" enum="Environment.ReflectionSource" default="0">
</member>
<member name="sky" type="Sky" setter="set_sky" getter="get_sky">
+ The [Sky] resource used for this [Environment].
</member>
<member name="sky_custom_fov" type="float" setter="set_sky_custom_fov" getter="get_sky_custom_fov" default="0.0">
</member>
@@ -211,9 +208,6 @@
<member name="ss_reflections_max_steps" type="int" setter="set_ssr_max_steps" getter="get_ssr_max_steps" default="64">
The maximum number of steps for screen-space reflections. Higher values are slower.
</member>
- <member name="ss_reflections_roughness" type="bool" setter="set_ssr_rough" getter="is_ssr_rough" default="true">
- If [code]true[/code], screen-space reflections will take the material roughness into account.
- </member>
<member name="ssao_ao_channel_affect" type="float" setter="set_ssao_ao_channel_affect" getter="get_ssao_ao_channel_affect" default="0.0">
The screen-space ambient occlusion intensity on materials that have an AO texture defined. Values higher than [code]0[/code] will make the SSAO effect visible in areas darkened by AO textures.
</member>
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index e9477517cf..17c65731ff 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -297,6 +297,7 @@
</argument>
<description>
Stores an integer as 16 bits in the file.
+ [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^16 - 1][/code].
</description>
</method>
<method name="store_32">
@@ -306,6 +307,7 @@
</argument>
<description>
Stores an integer as 32 bits in the file.
+ [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^32 - 1][/code].
</description>
</method>
<method name="store_64">
@@ -315,6 +317,7 @@
</argument>
<description>
Stores an integer as 64 bits in the file.
+ [b]Note:[/b] The [code]value[/code] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value).
</description>
</method>
<method name="store_8">
@@ -324,6 +327,7 @@
</argument>
<description>
Stores an integer as 8 bits in the file.
+ [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 255][/code].
</description>
</method>
<method name="store_buffer">
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index f2c65a8610..99563ee367 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -68,19 +68,19 @@
The currently selected file path of the file dialog.
</member>
<member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok" override="true" default="false" />
+ <member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="FileDialog.FileMode" default="4">
+ The dialog's open or save mode, which affects the selection behavior. See [enum FileMode].
+ </member>
<member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray( )">
The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code].
</member>
- <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="FileDialog.Mode" default="4">
- The dialog's open or save mode, which affects the selection behavior. See enum [code]Mode[/code] constants.
- </member>
<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
- If [code]true[/code], changing the [code]Mode[/code] property will set the window title accordingly (e.g. setting mode to [constant MODE_OPEN_FILE] will change the window title to "Open a File").
+ If [code]true[/code], changing the [code]Mode[/code] property will set the window title accordingly (e.g. setting mode to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
</member>
<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
If [code]true[/code], the dialog will show hidden files.
</member>
- <member name="window_title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Save a File&quot;" />
+ <member name="title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Save a File&quot;" />
</members>
<signals>
<signal name="dir_selected">
@@ -106,19 +106,19 @@
</signal>
</signals>
<constants>
- <constant name="MODE_OPEN_FILE" value="0" enum="Mode">
+ <constant name="FILE_MODE_OPEN_FILE" value="0" enum="FileMode">
The dialog allows selecting one, and only one file.
</constant>
- <constant name="MODE_OPEN_FILES" value="1" enum="Mode">
+ <constant name="FILE_MODE_OPEN_FILES" value="1" enum="FileMode">
The dialog allows selecting multiple files.
</constant>
- <constant name="MODE_OPEN_DIR" value="2" enum="Mode">
+ <constant name="FILE_MODE_OPEN_DIR" value="2" enum="FileMode">
The dialog only allows selecting a directory, disallowing the selection of any file.
</constant>
- <constant name="MODE_OPEN_ANY" value="3" enum="Mode">
+ <constant name="FILE_MODE_OPEN_ANY" value="3" enum="FileMode">
The dialog allows selecting one file or directory.
</constant>
- <constant name="MODE_SAVE_FILE" value="4" enum="Mode">
+ <constant name="FILE_MODE_SAVE_FILE" value="4" enum="FileMode">
The dialog will warn when a file exists.
</constant>
<constant name="ACCESS_RESOURCES" value="0" enum="Access">
@@ -133,16 +133,22 @@
</constants>
<theme_items>
<theme_item name="files_disabled" type="Color" default="Color( 0, 0, 0, 0.7 )">
+ The color tint for disabled files (when the [FileDialog] is used in open folder mode).
</theme_item>
<theme_item name="folder" type="Texture2D">
+ Custom icon for folders.
</theme_item>
<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="parent_folder" type="Texture2D">
+ Custom icon for the parent folder arrow.
</theme_item>
<theme_item name="reload" type="Texture2D">
+ Custom icon for the reload button.
</theme_item>
<theme_item name="toggle_hidden" type="Texture2D">
+ Custom icon for the toggle hidden button.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml
new file mode 100644
index 0000000000..fdf29f89b2
--- /dev/null
+++ b/doc/classes/FileSystemDock.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="FileSystemDock" inherits="VBoxContainer" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="can_drop_data_fw" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="arg0" type="Vector2">
+ </argument>
+ <argument index="1" name="arg1" type="Variant">
+ </argument>
+ <argument index="2" name="arg2" type="Control">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="drop_data_fw">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="Vector2">
+ </argument>
+ <argument index="1" name="arg1" type="Variant">
+ </argument>
+ <argument index="2" name="arg2" type="Control">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_drag_data_fw">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="arg0" type="Vector2">
+ </argument>
+ <argument index="1" name="arg1" type="Control">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="navigate_to_path">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="display_mode_changed">
+ <description>
+ </description>
+ </signal>
+ <signal name="file_removed">
+ <argument index="0" name="file" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="files_moved">
+ <argument index="0" name="old_file" type="String">
+ </argument>
+ <argument index="1" name="new_file" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="folder_moved">
+ <argument index="0" name="old_folder" type="String">
+ </argument>
+ <argument index="1" name="new_file" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="folder_removed">
+ <argument index="0" name="folder" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="inherit">
+ <argument index="0" name="file" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="instance">
+ <argument index="0" name="files" type="PackedStringArray">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index 6543a3ecf1..882f819e37 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -85,6 +85,7 @@
<argument index="1" name="width" type="float">
</argument>
<description>
+ Returns the size that the string would have with word wrapping enabled with a fixed [code]width[/code].
</description>
</method>
<method name="has_outline" qualifiers="const">
diff --git a/doc/classes/GIProbe.xml b/doc/classes/GIProbe.xml
index 322143ea9e..df50244c77 100644
--- a/doc/classes/GIProbe.xml
+++ b/doc/classes/GIProbe.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GIProbe" inherits="VisualInstance" version="4.0">
+<class name="GIProbe" inherits="VisualInstance3D" version="4.0">
<brief_description>
Real-time global illumination (GI) probe.
</brief_description>
@@ -19,7 +19,7 @@
<argument index="1" name="create_visual_debug" type="bool" default="false">
</argument>
<description>
- Bakes the effect from all [GeometryInstance]s marked with [member GeometryInstance.use_in_baked_light] and [Light]s marked with either [constant Light.BAKE_INDIRECT] or [constant Light.BAKE_ALL]. If [code]create_visual_debug[/code] is [code]true[/code], after baking the light, this will generate a [MultiMesh] that has a cube representing each solid cell with each cube colored to the cell's albedo color. This can be used to visualize the [GIProbe]'s data and debug any issues that may be occurring.
+ Bakes the effect from all [GeometryInstance3D]s marked with [member GeometryInstance3D.use_in_baked_light] and [Light3D]s marked with either [constant Light3D.BAKE_INDIRECT] or [constant Light3D.BAKE_ALL]. If [code]create_visual_debug[/code] is [code]true[/code], after baking the light, this will generate a [MultiMesh] that has a cube representing each solid cell with each cube colored to the cell's albedo color. This can be used to visualize the [GIProbe]'s data and debug any issues that may be occurring.
</description>
</method>
<method name="debug_bake">
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
new file mode 100644
index 0000000000..64a2522f2f
--- /dev/null
+++ b/doc/classes/GPUParticles2D.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GPUParticles2D" inherits="Node2D" version="4.0">
+ <brief_description>
+ 2D particle emitter.
+ </brief_description>
+ <description>
+ 2D particle node used to create a variety of particle systems and effects. [GPUParticles2D] features an emitter that generates some number of particles at a given rate.
+ Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
+ </tutorials>
+ <methods>
+ <method name="capture_rect" qualifiers="const">
+ <return type="Rect2">
+ </return>
+ <description>
+ Returns a rectangle containing the positions of all existing particles.
+ </description>
+ </method>
+ <method name="restart">
+ <return type="void">
+ </return>
+ <description>
+ Restarts all the existing particles.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
+ Number of particles emitted in one emission cycle.
+ </member>
+ <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles2D.DrawOrder" default="0">
+ Particle draw order. Uses [enum DrawOrder] values.
+ </member>
+ <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="false">
+ 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">
+ How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
+ </member>
+ <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
+ 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="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
+ Amount of time each particle will exist.
+ </member>
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
+ If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ </member>
+ <member name="normal_map" type="Texture2D" setter="set_normal_map" getter="get_normal_map">
+ Normal map to be used for the [member texture] property.
+ </member>
+ <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
+ If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
+ </member>
+ <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
+ Particle system starts as if it had already run for this many seconds.
+ </member>
+ <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
+ [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
+ </member>
+ <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
+ Emission lifetime randomness ratio.
+ </member>
+ <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
+ Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
+ </member>
+ <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ Particle texture. If [code]null[/code], particles will be squares.
+ </member>
+ <member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2( -100, -100, 200, 200 )">
+ Editor visibility helper.
+ </member>
+ </members>
+ <constants>
+ <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
+ Particles are drawn in the order emitted.
+ </constant>
+ <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
+ Particles are drawn in order of remaining lifetime.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
new file mode 100644
index 0000000000..add8f28bf8
--- /dev/null
+++ b/doc/classes/GPUParticles3D.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GPUParticles3D" inherits="GeometryInstance3D" version="4.0">
+ <brief_description>
+ 3D particle emitter.
+ </brief_description>
+ <description>
+ 3D particle node used to create a variety of particle systems and effects. [GPUParticles3D] features an emitter that generates some number of particles at a given rate.
+ Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/controlling_thousands_of_fish.html</link>
+ </tutorials>
+ <methods>
+ <method name="capture_aabb" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <description>
+ Returns the axis-aligned bounding box that contains all the particles that are active in the current frame.
+ </description>
+ </method>
+ <method name="get_draw_pass_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <argument index="0" name="pass" type="int">
+ </argument>
+ <description>
+ Returns the [Mesh] that is drawn at index [code]pass[/code].
+ </description>
+ </method>
+ <method name="restart">
+ <return type="void">
+ </return>
+ <description>
+ Restarts the particle emission, clearing existing particles.
+ </description>
+ </method>
+ <method name="set_draw_pass_mesh">
+ <return type="void">
+ </return>
+ <argument index="0" name="pass" type="int">
+ </argument>
+ <argument index="1" name="mesh" type="Mesh">
+ </argument>
+ <description>
+ Sets the [Mesh] that is drawn at index [code]pass[/code].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
+ Number of particles to emit.
+ </member>
+ <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles3D.DrawOrder" default="0">
+ Particle draw order. Uses [enum DrawOrder] values.
+ </member>
+ <member name="draw_pass_1" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
+ [Mesh] that is drawn for the first draw pass.
+ </member>
+ <member name="draw_pass_2" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
+ [Mesh] that is drawn for the second draw pass.
+ </member>
+ <member name="draw_pass_3" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
+ [Mesh] that is drawn for the third draw pass.
+ </member>
+ <member name="draw_pass_4" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
+ [Mesh] that is drawn for the fourth draw pass.
+ </member>
+ <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="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="false">
+ 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">
+ 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="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
+ Amount of time each particle will exist.
+ </member>
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
+ If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ </member>
+ <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
+ If [code]true[/code], only [code]amount[/code] particles will be emitted.
+ </member>
+ <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
+ Amount of time to preprocess the particles before animation starts. Lets you start the animation some time after particles have started emitting.
+ </member>
+ <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
+ [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
+ </member>
+ <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
+ Emission randomness ratio.
+ </member>
+ <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
+ Speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
+ </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 area of the world part of which needs to be visible on screen for the particle system to be active.
+ </member>
+ </members>
+ <constants>
+ <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
+ Particles are drawn in the order emitted.
+ </constant>
+ <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
+ Particles are drawn in order of remaining lifetime.
+ </constant>
+ <constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
+ Particles are drawn in order of depth.
+ </constant>
+ <constant name="MAX_DRAW_PASSES" value="4">
+ Maximum number of draw passes supported.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Generic6DOFJoint.xml b/doc/classes/Generic6DOFJoint.xml
deleted file mode 100644
index 29ebf9f5d6..0000000000
--- a/doc/classes/Generic6DOFJoint.xml
+++ /dev/null
@@ -1,426 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Generic6DOFJoint" inherits="Joint" version="4.0">
- <brief_description>
- The generic 6-degrees-of-freedom joint can implement a variety of joint types by locking certain axes' rotation or translation.
- </brief_description>
- <description>
- The first 3 DOF axes are linear axes, which represent translation of Bodies, and the latter 3 DOF axes represent the angular motion. Each axis can be either locked, or limited.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_flag_x" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint.Flag">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_flag_y" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint.Flag">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_flag_z" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint.Flag">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param_x" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param_y" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param_z" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_flag_x">
- <return type="void">
- </return>
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint.Flag">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_flag_y">
- <return type="void">
- </return>
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint.Flag">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_flag_z">
- <return type="void">
- </return>
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint.Flag">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param_x">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param_y">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param_z">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_limit_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="1.0">
- The amount of rotational damping across the X axis.
- The lower, the longer an impulse from one side takes to travel to the other side.
- </member>
- <member name="angular_limit_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="true">
- If [code]true[/code], rotation across the X axis is limited.
- </member>
- <member name="angular_limit_x/erp" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
- When rotating across the X axis, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
- </member>
- <member name="angular_limit_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- The maximum amount of force that can occur, when rotating around the X axis.
- </member>
- <member name="angular_limit_x/lower_angle" type="float" setter="_set_angular_lo_limit_x" getter="_get_angular_lo_limit_x" default="0.0">
- The minimum rotation in negative direction to break loose and rotate around the X axis.
- </member>
- <member name="angular_limit_x/restitution" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- The amount of rotational restitution across the X axis. The lower, the more restitution occurs.
- </member>
- <member name="angular_limit_x/softness" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
- The speed of all rotations across the X axis.
- </member>
- <member name="angular_limit_x/upper_angle" type="float" setter="_set_angular_hi_limit_x" getter="_get_angular_hi_limit_x" default="0.0">
- The minimum rotation in positive direction to break loose and rotate around the X axis.
- </member>
- <member name="angular_limit_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="1.0">
- The amount of rotational damping across the Y axis. The lower, the more dampening occurs.
- </member>
- <member name="angular_limit_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="true">
- If [code]true[/code], rotation across the Y axis is limited.
- </member>
- <member name="angular_limit_y/erp" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
- When rotating across the Y axis, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
- </member>
- <member name="angular_limit_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- The maximum amount of force that can occur, when rotating around the Y axis.
- </member>
- <member name="angular_limit_y/lower_angle" type="float" setter="_set_angular_lo_limit_y" getter="_get_angular_lo_limit_y" default="0.0">
- The minimum rotation in negative direction to break loose and rotate around the Y axis.
- </member>
- <member name="angular_limit_y/restitution" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- The amount of rotational restitution across the Y axis. The lower, the more restitution occurs.
- </member>
- <member name="angular_limit_y/softness" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
- The speed of all rotations across the Y axis.
- </member>
- <member name="angular_limit_y/upper_angle" type="float" setter="_set_angular_hi_limit_y" getter="_get_angular_hi_limit_y" default="0.0">
- The minimum rotation in positive direction to break loose and rotate around the Y axis.
- </member>
- <member name="angular_limit_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="1.0">
- The amount of rotational damping across the Z axis. The lower, the more dampening occurs.
- </member>
- <member name="angular_limit_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="true">
- If [code]true[/code], rotation across the Z axis is limited.
- </member>
- <member name="angular_limit_z/erp" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
- When rotating across the Z axis, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
- </member>
- <member name="angular_limit_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- The maximum amount of force that can occur, when rotating around the Z axis.
- </member>
- <member name="angular_limit_z/lower_angle" type="float" setter="_set_angular_lo_limit_z" getter="_get_angular_lo_limit_z" default="0.0">
- The minimum rotation in negative direction to break loose and rotate around the Z axis.
- </member>
- <member name="angular_limit_z/restitution" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- The amount of rotational restitution across the Z axis. The lower, the more restitution occurs.
- </member>
- <member name="angular_limit_z/softness" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
- The speed of all rotations across the Z axis.
- </member>
- <member name="angular_limit_z/upper_angle" type="float" setter="_set_angular_hi_limit_z" getter="_get_angular_hi_limit_z" default="0.0">
- The minimum rotation in positive direction to break loose and rotate around the Z axis.
- </member>
- <member name="angular_motor_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
- If [code]true[/code], a rotating motor at the X axis is enabled.
- </member>
- <member name="angular_motor_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="300.0">
- Maximum acceleration for the motor at the X axis.
- </member>
- <member name="angular_motor_x/target_velocity" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- Target speed for the motor at the X axis.
- </member>
- <member name="angular_motor_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
- If [code]true[/code], a rotating motor at the Y axis is enabled.
- </member>
- <member name="angular_motor_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="300.0">
- Maximum acceleration for the motor at the Y axis.
- </member>
- <member name="angular_motor_y/target_velocity" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- Target speed for the motor at the Y axis.
- </member>
- <member name="angular_motor_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
- If [code]true[/code], a rotating motor at the Z axis is enabled.
- </member>
- <member name="angular_motor_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="300.0">
- Maximum acceleration for the motor at the Z axis.
- </member>
- <member name="angular_motor_z/target_velocity" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- Target speed for the motor at the Z axis.
- </member>
- <member name="angular_spring_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- </member>
- <member name="angular_spring_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
- </member>
- <member name="angular_spring_x/equilibrium_point" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- </member>
- <member name="angular_spring_x/stiffness" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- </member>
- <member name="angular_spring_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- </member>
- <member name="angular_spring_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
- </member>
- <member name="angular_spring_y/equilibrium_point" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- </member>
- <member name="angular_spring_y/stiffness" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- </member>
- <member name="angular_spring_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- </member>
- <member name="angular_spring_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
- </member>
- <member name="angular_spring_z/equilibrium_point" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- </member>
- <member name="angular_spring_z/stiffness" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- </member>
- <member name="linear_limit_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="1.0">
- The amount of damping that happens at the X motion.
- </member>
- <member name="linear_limit_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="true">
- If [code]true[/code], the linear motion across the X axis is limited.
- </member>
- <member name="linear_limit_x/lower_distance" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- The minimum difference between the pivot points' X axis.
- </member>
- <member name="linear_limit_x/restitution" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
- The amount of restitution on the X axis movement. The lower, the more momentum gets lost.
- </member>
- <member name="linear_limit_x/softness" type="float" setter="set_param_x" getter="get_param_x" default="0.7">
- A factor applied to the movement across the X axis. The lower, the slower the movement.
- </member>
- <member name="linear_limit_x/upper_distance" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- The maximum difference between the pivot points' X axis.
- </member>
- <member name="linear_limit_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="1.0">
- The amount of damping that happens at the Y motion.
- </member>
- <member name="linear_limit_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="true">
- If [code]true[/code], the linear motion across the Y axis is limited.
- </member>
- <member name="linear_limit_y/lower_distance" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- The minimum difference between the pivot points' Y axis.
- </member>
- <member name="linear_limit_y/restitution" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
- The amount of restitution on the Y axis movement. The lower, the more momentum gets lost.
- </member>
- <member name="linear_limit_y/softness" type="float" setter="set_param_y" getter="get_param_y" default="0.7">
- A factor applied to the movement across the Y axis. The lower, the slower the movement.
- </member>
- <member name="linear_limit_y/upper_distance" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- The maximum difference between the pivot points' Y axis.
- </member>
- <member name="linear_limit_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="1.0">
- The amount of damping that happens at the Z motion.
- </member>
- <member name="linear_limit_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="true">
- If [code]true[/code], the linear motion across the Z axis is limited.
- </member>
- <member name="linear_limit_z/lower_distance" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- The minimum difference between the pivot points' Z axis.
- </member>
- <member name="linear_limit_z/restitution" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
- The amount of restitution on the Z axis movement. The lower, the more momentum gets lost.
- </member>
- <member name="linear_limit_z/softness" type="float" setter="set_param_z" getter="get_param_z" default="0.7">
- A factor applied to the movement across the Z axis. The lower, the slower the movement.
- </member>
- <member name="linear_limit_z/upper_distance" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- The maximum difference between the pivot points' Z axis.
- </member>
- <member name="linear_motor_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
- If [code]true[/code], then there is a linear motor on the X axis. It will attempt to reach the target velocity while staying within the force limits.
- </member>
- <member name="linear_motor_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- The maximum force the linear motor can apply on the X axis while trying to reach the target velocity.
- </member>
- <member name="linear_motor_x/target_velocity" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- The speed that the linear motor will attempt to reach on the X axis.
- </member>
- <member name="linear_motor_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
- If [code]true[/code], then there is a linear motor on the Y axis. It will attempt to reach the target velocity while staying within the force limits.
- </member>
- <member name="linear_motor_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- The maximum force the linear motor can apply on the Y axis while trying to reach the target velocity.
- </member>
- <member name="linear_motor_y/target_velocity" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- The speed that the linear motor will attempt to reach on the Y axis.
- </member>
- <member name="linear_motor_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
- If [code]true[/code], then there is a linear motor on the Z axis. It will attempt to reach the target velocity while staying within the force limits.
- </member>
- <member name="linear_motor_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- The maximum force the linear motor can apply on the Z axis while trying to reach the target velocity.
- </member>
- <member name="linear_motor_z/target_velocity" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- The speed that the linear motor will attempt to reach on the Z axis.
- </member>
- <member name="linear_spring_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="0.01">
- </member>
- <member name="linear_spring_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
- </member>
- <member name="linear_spring_x/equilibrium_point" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
- </member>
- <member name="linear_spring_x/stiffness" type="float" setter="set_param_x" getter="get_param_x" default="0.01">
- </member>
- <member name="linear_spring_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="0.01">
- </member>
- <member name="linear_spring_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
- </member>
- <member name="linear_spring_y/equilibrium_point" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
- </member>
- <member name="linear_spring_y/stiffness" type="float" setter="set_param_y" getter="get_param_y" default="0.01">
- </member>
- <member name="linear_spring_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="0.01">
- </member>
- <member name="linear_spring_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
- </member>
- <member name="linear_spring_z/equilibrium_point" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
- </member>
- <member name="linear_spring_z/stiffness" type="float" setter="set_param_z" getter="get_param_z" default="0.01">
- </member>
- <member name="precision" type="int" setter="set_precision" getter="get_precision" default="1">
- </member>
- </members>
- <constants>
- <constant name="PARAM_LINEAR_LOWER_LIMIT" value="0" enum="Param">
- The minimum difference between the pivot points' axes.
- </constant>
- <constant name="PARAM_LINEAR_UPPER_LIMIT" value="1" enum="Param">
- The maximum difference between the pivot points' axes.
- </constant>
- <constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2" enum="Param">
- A factor applied to the movement across the axes. The lower, the slower the movement.
- </constant>
- <constant name="PARAM_LINEAR_RESTITUTION" value="3" enum="Param">
- The amount of restitution on the axes' movement. The lower, the more momentum gets lost.
- </constant>
- <constant name="PARAM_LINEAR_DAMPING" value="4" enum="Param">
- The amount of damping that happens at the linear motion across the axes.
- </constant>
- <constant name="PARAM_LINEAR_MOTOR_TARGET_VELOCITY" value="5" enum="Param">
- The velocity the linear motor will try to reach.
- </constant>
- <constant name="PARAM_LINEAR_MOTOR_FORCE_LIMIT" value="6" enum="Param">
- The maximum force the linear motor will apply while trying to reach the velocity target.
- </constant>
- <constant name="PARAM_ANGULAR_LOWER_LIMIT" value="10" enum="Param">
- The minimum rotation in negative direction to break loose and rotate around the axes.
- </constant>
- <constant name="PARAM_ANGULAR_UPPER_LIMIT" value="11" enum="Param">
- The minimum rotation in positive direction to break loose and rotate around the axes.
- </constant>
- <constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="12" enum="Param">
- The speed of all rotations across the axes.
- </constant>
- <constant name="PARAM_ANGULAR_DAMPING" value="13" enum="Param">
- The amount of rotational damping across the axes. The lower, the more dampening occurs.
- </constant>
- <constant name="PARAM_ANGULAR_RESTITUTION" value="14" enum="Param">
- The amount of rotational restitution across the axes. The lower, the more restitution occurs.
- </constant>
- <constant name="PARAM_ANGULAR_FORCE_LIMIT" value="15" enum="Param">
- The maximum amount of force that can occur, when rotating around the axes.
- </constant>
- <constant name="PARAM_ANGULAR_ERP" value="16" enum="Param">
- When rotating across the axes, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
- </constant>
- <constant name="PARAM_ANGULAR_MOTOR_TARGET_VELOCITY" value="17" enum="Param">
- Target speed for the motor at the axes.
- </constant>
- <constant name="PARAM_ANGULAR_MOTOR_FORCE_LIMIT" value="18" enum="Param">
- Maximum acceleration for the motor at the axes.
- </constant>
- <constant name="PARAM_MAX" value="22" enum="Param">
- Represents the size of the [enum Param] enum.
- </constant>
- <constant name="FLAG_ENABLE_LINEAR_LIMIT" value="0" enum="Flag">
- If enabled, linear motion is possible within the given limits.
- </constant>
- <constant name="FLAG_ENABLE_ANGULAR_LIMIT" value="1" enum="Flag">
- If enabled, rotational motion is possible within the given limits.
- </constant>
- <constant name="FLAG_ENABLE_LINEAR_SPRING" value="3" enum="Flag">
- </constant>
- <constant name="FLAG_ENABLE_ANGULAR_SPRING" value="2" enum="Flag">
- </constant>
- <constant name="FLAG_ENABLE_MOTOR" value="4" enum="Flag">
- If enabled, there is a rotational motor across these axes.
- </constant>
- <constant name="FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="Flag">
- If enabled, there is a linear motor across these axes.
- </constant>
- <constant name="FLAG_MAX" value="6" enum="Flag">
- Represents the size of the [enum Flag] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Generic6DOFJoint3D.xml b/doc/classes/Generic6DOFJoint3D.xml
new file mode 100644
index 0000000000..fae567dc58
--- /dev/null
+++ b/doc/classes/Generic6DOFJoint3D.xml
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Generic6DOFJoint3D" inherits="Joint3D" version="4.0">
+ <brief_description>
+ The generic 6-degrees-of-freedom joint can implement a variety of joint types by locking certain axes' rotation or translation.
+ </brief_description>
+ <description>
+ The first 3 DOF axes are linear axes, which represent translation of Bodies, and the latter 3 DOF axes represent the angular motion. Each axis can be either locked, or limited.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_flag_x" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_flag_y" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_flag_z" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param_x" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param_y" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_param_z" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag_x">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag_y">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag_z">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param_x">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param_y">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param_z">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_limit_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="1.0">
+ The amount of rotational damping across the X axis.
+ The lower, the longer an impulse from one side takes to travel to the other side.
+ </member>
+ <member name="angular_limit_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="true">
+ If [code]true[/code], rotation across the X axis is limited.
+ </member>
+ <member name="angular_limit_x/erp" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
+ When rotating across the X axis, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
+ </member>
+ <member name="angular_limit_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ The maximum amount of force that can occur, when rotating around the X axis.
+ </member>
+ <member name="angular_limit_x/lower_angle" type="float" setter="_set_angular_lo_limit_x" getter="_get_angular_lo_limit_x" default="0.0">
+ The minimum rotation in negative direction to break loose and rotate around the X axis.
+ </member>
+ <member name="angular_limit_x/restitution" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ The amount of rotational restitution across the X axis. The lower, the more restitution occurs.
+ </member>
+ <member name="angular_limit_x/softness" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
+ The speed of all rotations across the X axis.
+ </member>
+ <member name="angular_limit_x/upper_angle" type="float" setter="_set_angular_hi_limit_x" getter="_get_angular_hi_limit_x" default="0.0">
+ The minimum rotation in positive direction to break loose and rotate around the X axis.
+ </member>
+ <member name="angular_limit_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="1.0">
+ The amount of rotational damping across the Y axis. The lower, the more dampening occurs.
+ </member>
+ <member name="angular_limit_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="true">
+ If [code]true[/code], rotation across the Y axis is limited.
+ </member>
+ <member name="angular_limit_y/erp" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
+ When rotating across the Y axis, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
+ </member>
+ <member name="angular_limit_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ The maximum amount of force that can occur, when rotating around the Y axis.
+ </member>
+ <member name="angular_limit_y/lower_angle" type="float" setter="_set_angular_lo_limit_y" getter="_get_angular_lo_limit_y" default="0.0">
+ The minimum rotation in negative direction to break loose and rotate around the Y axis.
+ </member>
+ <member name="angular_limit_y/restitution" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ The amount of rotational restitution across the Y axis. The lower, the more restitution occurs.
+ </member>
+ <member name="angular_limit_y/softness" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
+ The speed of all rotations across the Y axis.
+ </member>
+ <member name="angular_limit_y/upper_angle" type="float" setter="_set_angular_hi_limit_y" getter="_get_angular_hi_limit_y" default="0.0">
+ The minimum rotation in positive direction to break loose and rotate around the Y axis.
+ </member>
+ <member name="angular_limit_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="1.0">
+ The amount of rotational damping across the Z axis. The lower, the more dampening occurs.
+ </member>
+ <member name="angular_limit_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="true">
+ If [code]true[/code], rotation across the Z axis is limited.
+ </member>
+ <member name="angular_limit_z/erp" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
+ When rotating across the Z axis, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
+ </member>
+ <member name="angular_limit_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ The maximum amount of force that can occur, when rotating around the Z axis.
+ </member>
+ <member name="angular_limit_z/lower_angle" type="float" setter="_set_angular_lo_limit_z" getter="_get_angular_lo_limit_z" default="0.0">
+ The minimum rotation in negative direction to break loose and rotate around the Z axis.
+ </member>
+ <member name="angular_limit_z/restitution" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ The amount of rotational restitution across the Z axis. The lower, the more restitution occurs.
+ </member>
+ <member name="angular_limit_z/softness" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
+ The speed of all rotations across the Z axis.
+ </member>
+ <member name="angular_limit_z/upper_angle" type="float" setter="_set_angular_hi_limit_z" getter="_get_angular_hi_limit_z" default="0.0">
+ The minimum rotation in positive direction to break loose and rotate around the Z axis.
+ </member>
+ <member name="angular_motor_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
+ If [code]true[/code], a rotating motor at the X axis is enabled.
+ </member>
+ <member name="angular_motor_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="300.0">
+ Maximum acceleration for the motor at the X axis.
+ </member>
+ <member name="angular_motor_x/target_velocity" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ Target speed for the motor at the X axis.
+ </member>
+ <member name="angular_motor_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
+ If [code]true[/code], a rotating motor at the Y axis is enabled.
+ </member>
+ <member name="angular_motor_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="300.0">
+ Maximum acceleration for the motor at the Y axis.
+ </member>
+ <member name="angular_motor_y/target_velocity" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ Target speed for the motor at the Y axis.
+ </member>
+ <member name="angular_motor_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
+ If [code]true[/code], a rotating motor at the Z axis is enabled.
+ </member>
+ <member name="angular_motor_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="300.0">
+ Maximum acceleration for the motor at the Z axis.
+ </member>
+ <member name="angular_motor_z/target_velocity" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ Target speed for the motor at the Z axis.
+ </member>
+ <member name="angular_spring_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ </member>
+ <member name="angular_spring_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
+ </member>
+ <member name="angular_spring_x/equilibrium_point" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ </member>
+ <member name="angular_spring_x/stiffness" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ </member>
+ <member name="angular_spring_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ </member>
+ <member name="angular_spring_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
+ </member>
+ <member name="angular_spring_y/equilibrium_point" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ </member>
+ <member name="angular_spring_y/stiffness" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ </member>
+ <member name="angular_spring_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ </member>
+ <member name="angular_spring_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
+ </member>
+ <member name="angular_spring_z/equilibrium_point" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ </member>
+ <member name="angular_spring_z/stiffness" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ </member>
+ <member name="linear_limit_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="1.0">
+ The amount of damping that happens at the X motion.
+ </member>
+ <member name="linear_limit_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="true">
+ If [code]true[/code], the linear motion across the X axis is limited.
+ </member>
+ <member name="linear_limit_x/lower_distance" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ The minimum difference between the pivot points' X axis.
+ </member>
+ <member name="linear_limit_x/restitution" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
+ The amount of restitution on the X axis movement. The lower, the more momentum gets lost.
+ </member>
+ <member name="linear_limit_x/softness" type="float" setter="set_param_x" getter="get_param_x" default="0.7">
+ A factor applied to the movement across the X axis. The lower, the slower the movement.
+ </member>
+ <member name="linear_limit_x/upper_distance" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ The maximum difference between the pivot points' X axis.
+ </member>
+ <member name="linear_limit_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="1.0">
+ The amount of damping that happens at the Y motion.
+ </member>
+ <member name="linear_limit_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="true">
+ If [code]true[/code], the linear motion across the Y axis is limited.
+ </member>
+ <member name="linear_limit_y/lower_distance" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ The minimum difference between the pivot points' Y axis.
+ </member>
+ <member name="linear_limit_y/restitution" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
+ The amount of restitution on the Y axis movement. The lower, the more momentum gets lost.
+ </member>
+ <member name="linear_limit_y/softness" type="float" setter="set_param_y" getter="get_param_y" default="0.7">
+ A factor applied to the movement across the Y axis. The lower, the slower the movement.
+ </member>
+ <member name="linear_limit_y/upper_distance" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ The maximum difference between the pivot points' Y axis.
+ </member>
+ <member name="linear_limit_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="1.0">
+ The amount of damping that happens at the Z motion.
+ </member>
+ <member name="linear_limit_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="true">
+ If [code]true[/code], the linear motion across the Z axis is limited.
+ </member>
+ <member name="linear_limit_z/lower_distance" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ The minimum difference between the pivot points' Z axis.
+ </member>
+ <member name="linear_limit_z/restitution" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
+ The amount of restitution on the Z axis movement. The lower, the more momentum gets lost.
+ </member>
+ <member name="linear_limit_z/softness" type="float" setter="set_param_z" getter="get_param_z" default="0.7">
+ A factor applied to the movement across the Z axis. The lower, the slower the movement.
+ </member>
+ <member name="linear_limit_z/upper_distance" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ The maximum difference between the pivot points' Z axis.
+ </member>
+ <member name="linear_motor_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
+ If [code]true[/code], then there is a linear motor on the X axis. It will attempt to reach the target velocity while staying within the force limits.
+ </member>
+ <member name="linear_motor_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ The maximum force the linear motor can apply on the X axis while trying to reach the target velocity.
+ </member>
+ <member name="linear_motor_x/target_velocity" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ The speed that the linear motor will attempt to reach on the X axis.
+ </member>
+ <member name="linear_motor_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
+ If [code]true[/code], then there is a linear motor on the Y axis. It will attempt to reach the target velocity while staying within the force limits.
+ </member>
+ <member name="linear_motor_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ The maximum force the linear motor can apply on the Y axis while trying to reach the target velocity.
+ </member>
+ <member name="linear_motor_y/target_velocity" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ The speed that the linear motor will attempt to reach on the Y axis.
+ </member>
+ <member name="linear_motor_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
+ If [code]true[/code], then there is a linear motor on the Z axis. It will attempt to reach the target velocity while staying within the force limits.
+ </member>
+ <member name="linear_motor_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ The maximum force the linear motor can apply on the Z axis while trying to reach the target velocity.
+ </member>
+ <member name="linear_motor_z/target_velocity" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ The speed that the linear motor will attempt to reach on the Z axis.
+ </member>
+ <member name="linear_spring_x/damping" type="float" setter="set_param_x" getter="get_param_x" default="0.01">
+ </member>
+ <member name="linear_spring_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
+ </member>
+ <member name="linear_spring_x/equilibrium_point" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
+ </member>
+ <member name="linear_spring_x/stiffness" type="float" setter="set_param_x" getter="get_param_x" default="0.01">
+ </member>
+ <member name="linear_spring_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="0.01">
+ </member>
+ <member name="linear_spring_y/enabled" type="bool" setter="set_flag_y" getter="get_flag_y" default="false">
+ </member>
+ <member name="linear_spring_y/equilibrium_point" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
+ </member>
+ <member name="linear_spring_y/stiffness" type="float" setter="set_param_y" getter="get_param_y" default="0.01">
+ </member>
+ <member name="linear_spring_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="0.01">
+ </member>
+ <member name="linear_spring_z/enabled" type="bool" setter="set_flag_z" getter="get_flag_z" default="false">
+ </member>
+ <member name="linear_spring_z/equilibrium_point" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
+ </member>
+ <member name="linear_spring_z/stiffness" type="float" setter="set_param_z" getter="get_param_z" default="0.01">
+ </member>
+ <member name="precision" type="int" setter="set_precision" getter="get_precision" default="1">
+ </member>
+ </members>
+ <constants>
+ <constant name="PARAM_LINEAR_LOWER_LIMIT" value="0" enum="Param">
+ The minimum difference between the pivot points' axes.
+ </constant>
+ <constant name="PARAM_LINEAR_UPPER_LIMIT" value="1" enum="Param">
+ The maximum difference between the pivot points' axes.
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2" enum="Param">
+ A factor applied to the movement across the axes. The lower, the slower the movement.
+ </constant>
+ <constant name="PARAM_LINEAR_RESTITUTION" value="3" enum="Param">
+ The amount of restitution on the axes' movement. The lower, the more momentum gets lost.
+ </constant>
+ <constant name="PARAM_LINEAR_DAMPING" value="4" enum="Param">
+ The amount of damping that happens at the linear motion across the axes.
+ </constant>
+ <constant name="PARAM_LINEAR_MOTOR_TARGET_VELOCITY" value="5" enum="Param">
+ The velocity the linear motor will try to reach.
+ </constant>
+ <constant name="PARAM_LINEAR_MOTOR_FORCE_LIMIT" value="6" enum="Param">
+ The maximum force the linear motor will apply while trying to reach the velocity target.
+ </constant>
+ <constant name="PARAM_ANGULAR_LOWER_LIMIT" value="10" enum="Param">
+ The minimum rotation in negative direction to break loose and rotate around the axes.
+ </constant>
+ <constant name="PARAM_ANGULAR_UPPER_LIMIT" value="11" enum="Param">
+ The minimum rotation in positive direction to break loose and rotate around the axes.
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="12" enum="Param">
+ The speed of all rotations across the axes.
+ </constant>
+ <constant name="PARAM_ANGULAR_DAMPING" value="13" enum="Param">
+ The amount of rotational damping across the axes. The lower, the more dampening occurs.
+ </constant>
+ <constant name="PARAM_ANGULAR_RESTITUTION" value="14" enum="Param">
+ The amount of rotational restitution across the axes. The lower, the more restitution occurs.
+ </constant>
+ <constant name="PARAM_ANGULAR_FORCE_LIMIT" value="15" enum="Param">
+ The maximum amount of force that can occur, when rotating around the axes.
+ </constant>
+ <constant name="PARAM_ANGULAR_ERP" value="16" enum="Param">
+ When rotating across the axes, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTOR_TARGET_VELOCITY" value="17" enum="Param">
+ Target speed for the motor at the axes.
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTOR_FORCE_LIMIT" value="18" enum="Param">
+ Maximum acceleration for the motor at the axes.
+ </constant>
+ <constant name="PARAM_MAX" value="22" enum="Param">
+ Represents the size of the [enum Param] enum.
+ </constant>
+ <constant name="FLAG_ENABLE_LINEAR_LIMIT" value="0" enum="Flag">
+ If enabled, linear motion is possible within the given limits.
+ </constant>
+ <constant name="FLAG_ENABLE_ANGULAR_LIMIT" value="1" enum="Flag">
+ If enabled, rotational motion is possible within the given limits.
+ </constant>
+ <constant name="FLAG_ENABLE_LINEAR_SPRING" value="3" enum="Flag">
+ </constant>
+ <constant name="FLAG_ENABLE_ANGULAR_SPRING" value="2" enum="Flag">
+ </constant>
+ <constant name="FLAG_ENABLE_MOTOR" value="4" enum="Flag">
+ If enabled, there is a rotational motor across these axes.
+ </constant>
+ <constant name="FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="Flag">
+ If enabled, there is a linear motor across these axes.
+ </constant>
+ <constant name="FLAG_MAX" value="6" enum="Flag">
+ Represents the size of the [enum Flag] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/GeometryInstance.xml b/doc/classes/GeometryInstance.xml
deleted file mode 100644
index 8259462531..0000000000
--- a/doc/classes/GeometryInstance.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GeometryInstance" inherits="VisualInstance" version="4.0">
- <brief_description>
- Base node for geometry-based visual instances.
- </brief_description>
- <description>
- Base node for geometry-based visual instances. Shares some common functionality like visibility and custom materials.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_flag" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int" enum="GeometryInstance.Flags">
- </argument>
- <description>
- Returns the [enum GeometryInstance.Flags] that have been set for this object.
- </description>
- </method>
- <method name="set_custom_aabb">
- <return type="void">
- </return>
- <argument index="0" name="aabb" type="AABB">
- </argument>
- <description>
- Overrides the bounding box of this node with a custom one. To remove it, set an [AABB] with all fields set to zero.
- </description>
- </method>
- <method name="set_flag">
- <return type="void">
- </return>
- <argument index="0" name="flag" type="int" enum="GeometryInstance.Flags">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets the [enum GeometryInstance.Flags] specified. See [enum GeometryInstance.Flags] for options.
- </description>
- </method>
- </methods>
- <members>
- <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance.ShadowCastingSetting" default="1">
- The selected shadow casting flag. See [enum ShadowCastingSetting] for possible values.
- </member>
- <member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin" default="0.0">
- The extra distance added to the GeometryInstance's bounding box ([AABB]) to increase its cull box.
- </member>
- <member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0">
- The GeometryInstance's max LOD distance.
- [b]Note:[/b] This property currently has no effect.
- </member>
- <member name="lod_max_hysteresis" type="float" setter="set_lod_max_hysteresis" getter="get_lod_max_hysteresis" default="0.0">
- The GeometryInstance's max LOD margin.
- [b]Note:[/b] This property currently has no effect.
- </member>
- <member name="lod_min_distance" type="float" setter="set_lod_min_distance" getter="get_lod_min_distance" default="0.0">
- The GeometryInstance's min LOD distance.
- [b]Note:[/b] This property currently has no effect.
- </member>
- <member name="lod_min_hysteresis" type="float" setter="set_lod_min_hysteresis" getter="get_lod_min_hysteresis" default="0.0">
- The GeometryInstance's min LOD margin.
- [b]Note:[/b] This property currently has no effect.
- </member>
- <member name="material_override" type="Material" setter="set_material_override" getter="get_material_override">
- The material override for the whole geometry.
- If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh.
- </member>
- <member name="use_dynamic_gi" type="bool" setter="set_flag" getter="get_flag" default="false">
- </member>
- <member name="use_in_baked_light" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], this GeometryInstance will be used when baking lights using a [GIProbe].
- </member>
- </members>
- <constants>
- <constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
- Will not cast any shadows.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_ON" value="1" enum="ShadowCastingSetting">
- Will cast shadows from all visible faces in the GeometryInstance.
- Will take culling into account, so faces not being rendered will not be taken into account when shadow casting.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_DOUBLE_SIDED" value="2" enum="ShadowCastingSetting">
- Will cast shadows from all visible faces in the GeometryInstance.
- Will not take culling into account, so all faces will be taken into account when shadow casting.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_SHADOWS_ONLY" value="3" enum="ShadowCastingSetting">
- Will only show the shadows casted from this object.
- In other words, the actual mesh will not be visible, only the shadows casted from the mesh will be.
- </constant>
- <constant name="FLAG_USE_BAKED_LIGHT" value="0" enum="Flags">
- Will allow the GeometryInstance to be used when baking lights using a [GIProbe].
- </constant>
- <constant name="FLAG_USE_DYNAMIC_GI" value="1" enum="Flags">
- </constant>
- <constant name="FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="2" enum="Flags">
- Unused in this class, exposed for consistency with [enum VisualServer.InstanceFlags].
- </constant>
- <constant name="FLAG_MAX" value="3" enum="Flags">
- Represents the size of the [enum Flags] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
new file mode 100644
index 0000000000..7df5f0ea50
--- /dev/null
+++ b/doc/classes/GeometryInstance3D.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GeometryInstance3D" inherits="VisualInstance3D" version="4.0">
+ <brief_description>
+ Base node for geometry-based visual instances.
+ </brief_description>
+ <description>
+ Base node for geometry-based visual instances. Shares some common functionality like visibility and custom materials.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="GeometryInstance3D.Flags">
+ </argument>
+ <description>
+ Returns the [enum GeometryInstance3D.Flags] that have been set for this object.
+ </description>
+ </method>
+ <method name="set_custom_aabb">
+ <return type="void">
+ </return>
+ <argument index="0" name="aabb" type="AABB">
+ </argument>
+ <description>
+ Overrides the bounding box of this node with a custom one. To remove it, set an [AABB] with all fields set to zero.
+ </description>
+ </method>
+ <method name="set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="GeometryInstance3D.Flags">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ Sets the [enum GeometryInstance3D.Flags] specified. See [enum GeometryInstance3D.Flags] for options.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance3D.ShadowCastingSetting" default="1">
+ The selected shadow casting flag. See [enum ShadowCastingSetting] for possible values.
+ </member>
+ <member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin" default="0.0">
+ The extra distance added to the GeometryInstance3D's bounding box ([AABB]) to increase its cull box.
+ </member>
+ <member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0">
+ The GeometryInstance3D's max LOD distance.
+ [b]Note:[/b] This property currently has no effect.
+ </member>
+ <member name="lod_max_hysteresis" type="float" setter="set_lod_max_hysteresis" getter="get_lod_max_hysteresis" default="0.0">
+ The GeometryInstance3D's max LOD margin.
+ [b]Note:[/b] This property currently has no effect.
+ </member>
+ <member name="lod_min_distance" type="float" setter="set_lod_min_distance" getter="get_lod_min_distance" default="0.0">
+ The GeometryInstance3D's min LOD distance.
+ [b]Note:[/b] This property currently has no effect.
+ </member>
+ <member name="lod_min_hysteresis" type="float" setter="set_lod_min_hysteresis" getter="get_lod_min_hysteresis" default="0.0">
+ The GeometryInstance3D's min LOD margin.
+ [b]Note:[/b] This property currently has no effect.
+ </member>
+ <member name="material_override" type="Material" setter="set_material_override" getter="get_material_override">
+ The material override for the whole geometry.
+ If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh.
+ </member>
+ <member name="use_dynamic_gi" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
+ <member name="use_in_baked_light" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], this GeometryInstance3D will be used when baking lights using a [GIProbe].
+ </member>
+ </members>
+ <constants>
+ <constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
+ Will not cast any shadows.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_ON" value="1" enum="ShadowCastingSetting">
+ Will cast shadows from all visible faces in the GeometryInstance3D.
+ Will take culling into account, so faces not being rendered will not be taken into account when shadow casting.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_DOUBLE_SIDED" value="2" enum="ShadowCastingSetting">
+ Will cast shadows from all visible faces in the GeometryInstance3D.
+ Will not take culling into account, so all faces will be taken into account when shadow casting.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_SHADOWS_ONLY" value="3" enum="ShadowCastingSetting">
+ Will only show the shadows casted from this object.
+ In other words, the actual mesh will not be visible, only the shadows casted from the mesh will be.
+ </constant>
+ <constant name="FLAG_USE_BAKED_LIGHT" value="0" enum="Flags">
+ Will allow the GeometryInstance3D to be used when baking lights using a [GIProbe].
+ </constant>
+ <constant name="FLAG_USE_DYNAMIC_GI" value="1" enum="Flags">
+ </constant>
+ <constant name="FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="2" enum="Flags">
+ Unused in this class, exposed for consistency with [enum RenderingServer.InstanceFlags].
+ </constant>
+ <constant name="FLAG_MAX" value="3" enum="Flags">
+ Represents the size of the [enum Flags] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 543afb01ee..c41ffd4bff 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -303,26 +303,37 @@
<theme_item name="bezier_len_pos" type="int" default="80">
</theme_item>
<theme_item name="bg" type="StyleBox">
+ The background drawn under the grid.
</theme_item>
<theme_item name="grid_major" type="Color" default="Color( 1, 1, 1, 0.2 )">
+ Color of major grid lines.
</theme_item>
<theme_item name="grid_minor" type="Color" default="Color( 1, 1, 1, 0.05 )">
+ Color of minor grid lines.
</theme_item>
<theme_item name="minus" type="Texture2D">
+ The icon for the zoom out button.
</theme_item>
<theme_item name="more" type="Texture2D">
+ The icon for the zoom in button.
</theme_item>
<theme_item name="port_grab_distance_horizontal" type="int" default="48">
+ The horizontal range within which a port can be grabbed (on both sides).
</theme_item>
<theme_item name="port_grab_distance_vertical" type="int" default="6">
+ The vertical range within which a port can be grabbed (on both sides).
</theme_item>
<theme_item name="reset" type="Texture2D">
+ The icon for the zoom reset button.
</theme_item>
<theme_item name="selection_fill" type="Color" default="Color( 1, 1, 1, 0.3 )">
+ The fill color of the selection rectangle.
</theme_item>
<theme_item name="selection_stroke" type="Color" default="Color( 1, 1, 1, 0.8 )">
+ The outline color of the selection rectangle.
</theme_item>
<theme_item name="snap" type="Texture2D">
+ The icon for the snap toggle button.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index a9f1b15443..33074536da 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -253,42 +253,59 @@
</constants>
<theme_items>
<theme_item name="breakpoint" type="StyleBox">
+ The background used when [member overlay] is set to [constant OVERLAY_BREAKPOINT].
</theme_item>
<theme_item name="close" type="Texture2D">
+ The icon for the close button, visible when [member show_close] is enabled.
</theme_item>
<theme_item name="close_color" type="Color" default="Color( 0, 0, 0, 1 )">
+ The color modulation applied to the close button icon.
</theme_item>
<theme_item name="close_offset" type="int" default="18">
+ The vertical offset of the close button.
</theme_item>
<theme_item name="comment" type="StyleBox">
+ The [StyleBox] used when [member comment] is enabled.
</theme_item>
<theme_item name="commentfocus" type="StyleBox">
+ The [StyleBox] used when [member comment] is enabled and the [GraphNode] is focused.
</theme_item>
<theme_item name="defaultfocus" type="StyleBox">
</theme_item>
<theme_item name="defaultframe" type="StyleBox">
</theme_item>
<theme_item name="frame" type="StyleBox">
+ The default background for [GraphNode].
</theme_item>
<theme_item name="port" type="Texture2D">
+ The icon used for representing ports.
</theme_item>
<theme_item name="port_offset" type="int" default="3">
+ Horizontal offset for the ports.
</theme_item>
<theme_item name="position" type="StyleBox">
+ The background used when [member overlay] is set to [constant OVERLAY_POSITION].
</theme_item>
<theme_item name="resizer" type="Texture2D">
+ The icon used for resizer, visible when [member resizable] is enabled.
</theme_item>
<theme_item name="resizer_color" type="Color" default="Color( 0, 0, 0, 1 )">
+ The color modulation applied to the resizer icon.
</theme_item>
<theme_item name="selectedframe" type="StyleBox">
+ The background used when the [GraphNode] is selected.
</theme_item>
<theme_item name="separation" type="int" default="1">
+ The vertical distance between ports.
</theme_item>
<theme_item name="title_color" type="Color" default="Color( 0, 0, 0, 1 )">
+ Color of the title text.
</theme_item>
<theme_item name="title_font" type="Font">
+ Font used for the title text.
</theme_item>
<theme_item name="title_offset" type="int" default="20">
+ Vertical offset of the title text.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/GridContainer.xml b/doc/classes/GridContainer.xml
index 4493ee8dc1..e13dc43104 100644
--- a/doc/classes/GridContainer.xml
+++ b/doc/classes/GridContainer.xml
@@ -20,8 +20,10 @@
</constants>
<theme_items>
<theme_item name="hseparation" type="int" default="4">
+ The horizontal separation of children nodes.
</theme_item>
<theme_item name="vseparation" type="int" default="4">
+ The vertical separation of children nodes.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/HSeparator.xml b/doc/classes/HSeparator.xml
index aa83b67934..5b418d6428 100644
--- a/doc/classes/HSeparator.xml
+++ b/doc/classes/HSeparator.xml
@@ -14,8 +14,10 @@
</constants>
<theme_items>
<theme_item name="separation" type="int" default="4">
+ The height of the area covered by the separator. Effectively works like a minimum height.
</theme_item>
<theme_item name="separator" type="StyleBox">
+ The style for the separator line. Works best with [StyleBoxLine].
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/HSlider.xml b/doc/classes/HSlider.xml
index be3c94e495..2738958058 100644
--- a/doc/classes/HSlider.xml
+++ b/doc/classes/HSlider.xml
@@ -14,16 +14,22 @@
</constants>
<theme_items>
<theme_item name="grabber" type="Texture2D">
+ The texture for the grabber (the draggable element).
</theme_item>
<theme_item name="grabber_area" type="StyleBox">
+ The background of the area to the left of the grabber.
</theme_item>
<theme_item name="grabber_disabled" type="Texture2D">
+ The texture for the grabber when it's disabled.
</theme_item>
<theme_item name="grabber_highlight" type="Texture2D">
+ The texture for the grabber when it's focused.
</theme_item>
<theme_item name="slider" type="StyleBox">
+ The background for the whole slider. Determines the height of the [code]grabber_area[/code].
</theme_item>
<theme_item name="tick" type="Texture2D">
+ The texture for the ticks, visible when [member Slider.tick_count] is greater than 0.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/HSplitContainer.xml b/doc/classes/HSplitContainer.xml
index 0dd1f96602..f6e9f33c20 100644
--- a/doc/classes/HSplitContainer.xml
+++ b/doc/classes/HSplitContainer.xml
@@ -14,12 +14,15 @@
</constants>
<theme_items>
<theme_item name="autohide" type="int" default="1">
+ Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible.
</theme_item>
<theme_item name="bg" type="StyleBox">
</theme_item>
<theme_item name="grabber" type="Texture2D">
+ The icon used for the grabber drawn in the middle area.
</theme_item>
<theme_item name="separation" type="int" default="12">
+ The space between sides of the container.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/HeightMapShape.xml b/doc/classes/HeightMapShape.xml
deleted file mode 100644
index 029f3642d2..0000000000
--- a/doc/classes/HeightMapShape.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HeightMapShape" inherits="Shape" version="4.0">
- <brief_description>
- Height map shape for 3D physics (Bullet only).
- </brief_description>
- <description>
- Height map shape resource, which can be added to a [PhysicsBody] or [Area].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="map_data" type="PackedFloat32Array" setter="set_map_data" getter="get_map_data" default="PackedFloat32Array( 0, 0, 0, 0 )">
- Height map data, pool array must be of [member map_width] * [member map_depth] size.
- </member>
- <member name="map_depth" type="int" setter="set_map_depth" getter="get_map_depth" default="2">
- Depth of the height map data. Changing this will resize the [member map_data].
- </member>
- <member name="map_width" type="int" setter="set_map_width" getter="get_map_width" default="2">
- Width of the height map data. Changing this will resize the [member map_data].
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml
new file mode 100644
index 0000000000..6d230bdab8
--- /dev/null
+++ b/doc/classes/HeightMapShape3D.xml
@@ -0,0 +1,26 @@
+<?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).
+ </brief_description>
+ <description>
+ Height map shape resource, which can be added to a [PhysicsBody3D] or [Area3D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="map_data" type="PackedFloat32Array" setter="set_map_data" getter="get_map_data" default="PackedFloat32Array( 0, 0, 0, 0 )">
+ Height map data, pool array must be of [member map_width] * [member map_depth] size.
+ </member>
+ <member name="map_depth" type="int" setter="set_map_depth" getter="get_map_depth" default="2">
+ Depth of the height map data. Changing this will resize the [member map_data].
+ </member>
+ <member name="map_width" type="int" setter="set_map_width" getter="get_map_width" default="2">
+ Width of the height map data. Changing this will resize the [member map_data].
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/HingeJoint.xml b/doc/classes/HingeJoint.xml
deleted file mode 100644
index 53fa74cace..0000000000
--- a/doc/classes/HingeJoint.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="HingeJoint" inherits="Joint" version="4.0">
- <brief_description>
- A hinge between two 3D bodies.
- </brief_description>
- <description>
- A HingeJoint normally uses the Z axis of body A as the hinge axis, another axis can be specified when adding it manually though.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_flag" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int" enum="HingeJoint.Flag">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="HingeJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_flag">
- <return type="void">
- </return>
- <argument index="0" name="flag" type="int" enum="HingeJoint.Flag">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="HingeJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_limit/bias" type="float" setter="set_param" getter="get_param" default="0.3">
- The speed with which the rotation across the axis perpendicular to the hinge gets corrected.
- </member>
- <member name="angular_limit/enable" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], the hinges maximum and minimum rotation, defined by [member angular_limit/lower] and [member angular_limit/upper] has effects.
- </member>
- <member name="angular_limit/lower" type="float" setter="_set_lower_limit" getter="_get_lower_limit" default="-90.0">
- The minimum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
- </member>
- <member name="angular_limit/relaxation" type="float" setter="set_param" getter="get_param" default="1.0">
- The lower this value, the more the rotation gets slowed down.
- </member>
- <member name="angular_limit/softness" type="float" setter="set_param" getter="get_param" default="0.9">
- </member>
- <member name="angular_limit/upper" type="float" setter="_set_upper_limit" getter="_get_upper_limit" default="90.0">
- The maximum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
- </member>
- <member name="motor/enable" type="bool" setter="set_flag" getter="get_flag" default="false">
- When activated, a motor turns the hinge.
- </member>
- <member name="motor/max_impulse" type="float" setter="set_param" getter="get_param" default="1.0">
- Maximum acceleration for the motor.
- </member>
- <member name="motor/target_velocity" type="float" setter="set_param" getter="get_param" default="1.0">
- Target speed for the motor.
- </member>
- <member name="params/bias" type="float" setter="set_param" getter="get_param" default="0.3">
- The speed with which the two bodies get pulled together when they move in different directions.
- </member>
- </members>
- <constants>
- <constant name="PARAM_BIAS" value="0" enum="Param">
- The speed with which the two bodies get pulled together when they move in different directions.
- </constant>
- <constant name="PARAM_LIMIT_UPPER" value="1" enum="Param">
- The maximum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
- </constant>
- <constant name="PARAM_LIMIT_LOWER" value="2" enum="Param">
- The minimum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
- </constant>
- <constant name="PARAM_LIMIT_BIAS" value="3" enum="Param">
- The speed with which the rotation across the axis perpendicular to the hinge gets corrected.
- </constant>
- <constant name="PARAM_LIMIT_SOFTNESS" value="4" enum="Param">
- </constant>
- <constant name="PARAM_LIMIT_RELAXATION" value="5" enum="Param">
- The lower this value, the more the rotation gets slowed down.
- </constant>
- <constant name="PARAM_MOTOR_TARGET_VELOCITY" value="6" enum="Param">
- Target speed for the motor.
- </constant>
- <constant name="PARAM_MOTOR_MAX_IMPULSE" value="7" enum="Param">
- Maximum acceleration for the motor.
- </constant>
- <constant name="PARAM_MAX" value="8" enum="Param">
- Represents the size of the [enum Param] enum.
- </constant>
- <constant name="FLAG_USE_LIMIT" value="0" enum="Flag">
- If [code]true[/code], the hinges maximum and minimum rotation, defined by [member angular_limit/lower] and [member angular_limit/upper] has effects.
- </constant>
- <constant name="FLAG_ENABLE_MOTOR" value="1" enum="Flag">
- When activated, a motor turns the hinge.
- </constant>
- <constant name="FLAG_MAX" value="2" enum="Flag">
- Represents the size of the [enum Flag] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/HingeJoint3D.xml b/doc/classes/HingeJoint3D.xml
new file mode 100644
index 0000000000..2d4480cb20
--- /dev/null
+++ b/doc/classes/HingeJoint3D.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="HingeJoint3D" inherits="Joint3D" version="4.0">
+ <brief_description>
+ A hinge between two 3D bodies.
+ </brief_description>
+ <description>
+ A HingeJoint3D normally uses the Z axis of body A as the hinge axis, another axis can be specified when adding it manually though.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="HingeJoint3D.Flag">
+ </argument>
+ <description>
+ Returns the value of the specified flag.
+ </description>
+ </method>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="HingeJoint3D.Param">
+ </argument>
+ <description>
+ Returns the value of the specified parameter.
+ </description>
+ </method>
+ <method name="set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="HingeJoint3D.Flag">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], enables the specified flag.
+ </description>
+ </method>
+ <method name="set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="HingeJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ Sets the value of the specified parameter.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_limit/bias" type="float" setter="set_param" getter="get_param" default="0.3">
+ The speed with which the rotation across the axis perpendicular to the hinge gets corrected.
+ </member>
+ <member name="angular_limit/enable" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the hinges maximum and minimum rotation, defined by [member angular_limit/lower] and [member angular_limit/upper] has effects.
+ </member>
+ <member name="angular_limit/lower" type="float" setter="_set_lower_limit" getter="_get_lower_limit" default="-90.0">
+ The minimum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
+ </member>
+ <member name="angular_limit/relaxation" type="float" setter="set_param" getter="get_param" default="1.0">
+ The lower this value, the more the rotation gets slowed down.
+ </member>
+ <member name="angular_limit/softness" type="float" setter="set_param" getter="get_param" default="0.9">
+ </member>
+ <member name="angular_limit/upper" type="float" setter="_set_upper_limit" getter="_get_upper_limit" default="90.0">
+ The maximum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
+ </member>
+ <member name="motor/enable" type="bool" setter="set_flag" getter="get_flag" default="false">
+ When activated, a motor turns the hinge.
+ </member>
+ <member name="motor/max_impulse" type="float" setter="set_param" getter="get_param" default="1.0">
+ Maximum acceleration for the motor.
+ </member>
+ <member name="motor/target_velocity" type="float" setter="set_param" getter="get_param" default="1.0">
+ Target speed for the motor.
+ </member>
+ <member name="params/bias" type="float" setter="set_param" getter="get_param" default="0.3">
+ The speed with which the two bodies get pulled together when they move in different directions.
+ </member>
+ </members>
+ <constants>
+ <constant name="PARAM_BIAS" value="0" enum="Param">
+ The speed with which the two bodies get pulled together when they move in different directions.
+ </constant>
+ <constant name="PARAM_LIMIT_UPPER" value="1" enum="Param">
+ The maximum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
+ </constant>
+ <constant name="PARAM_LIMIT_LOWER" value="2" enum="Param">
+ The minimum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
+ </constant>
+ <constant name="PARAM_LIMIT_BIAS" value="3" enum="Param">
+ The speed with which the rotation across the axis perpendicular to the hinge gets corrected.
+ </constant>
+ <constant name="PARAM_LIMIT_SOFTNESS" value="4" enum="Param">
+ </constant>
+ <constant name="PARAM_LIMIT_RELAXATION" value="5" enum="Param">
+ The lower this value, the more the rotation gets slowed down.
+ </constant>
+ <constant name="PARAM_MOTOR_TARGET_VELOCITY" value="6" enum="Param">
+ Target speed for the motor.
+ </constant>
+ <constant name="PARAM_MOTOR_MAX_IMPULSE" value="7" enum="Param">
+ Maximum acceleration for the motor.
+ </constant>
+ <constant name="PARAM_MAX" value="8" enum="Param">
+ Represents the size of the [enum Param] enum.
+ </constant>
+ <constant name="FLAG_USE_LIMIT" value="0" enum="Flag">
+ If [code]true[/code], the hinges maximum and minimum rotation, defined by [member angular_limit/lower] and [member angular_limit/upper] has effects.
+ </constant>
+ <constant name="FLAG_ENABLE_MOTOR" value="1" enum="Flag">
+ When activated, a motor turns the hinge.
+ </constant>
+ <constant name="FLAG_MAX" value="2" enum="Flag">
+ Represents the size of the [enum Flag] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 8bd2213194..f541b0ae66 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -99,7 +99,7 @@
</return>
<argument index="0" name="mode" type="int" enum="Image.CompressMode">
</argument>
- <argument index="1" name="channels" type="int" enum="Image.CompressSource">
+ <argument index="1" name="channels" type="int" enum="Image.UsedChannels">
</argument>
<argument index="2" name="lossy_quality" type="float" default="0.7">
</argument>
diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml
index 98eb42831b..1578783b8b 100644
--- a/doc/classes/ImageTexture.xml
+++ b/doc/classes/ImageTexture.xml
@@ -42,6 +42,7 @@
<argument index="1" name="immediate" type="bool" default="false">
</argument>
<description>
+ Replaces the texture's data with a new [code]image[/code]. If [code]immediate[/code] is [code]true[/code], it will take effect immediately after the call.
</description>
</method>
</methods>
diff --git a/doc/classes/ImmediateGeometry.xml b/doc/classes/ImmediateGeometry.xml
deleted file mode 100644
index 710e929d1a..0000000000
--- a/doc/classes/ImmediateGeometry.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ImmediateGeometry" inherits="GeometryInstance" version="4.0">
- <brief_description>
- Draws simple geometry from code.
- </brief_description>
- <description>
- Draws simple geometry from code. Uses a drawing mode similar to OpenGL 1.x.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_sphere">
- <return type="void">
- </return>
- <argument index="0" name="lats" type="int">
- </argument>
- <argument index="1" name="lons" type="int">
- </argument>
- <argument index="2" name="radius" type="float">
- </argument>
- <argument index="3" name="add_uv" type="bool" default="true">
- </argument>
- <description>
- Simple helper to draw an UV sphere with given latitude, longitude and radius.
- </description>
- </method>
- <method name="add_vertex">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <description>
- Adds a vertex in local coordinate space with the currently set color/uv/etc.
- </description>
- </method>
- <method name="begin">
- <return type="void">
- </return>
- <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType">
- </argument>
- <argument index="1" name="texture" type="Texture2D" default="null">
- </argument>
- <description>
- Begin drawing (and optionally pass a texture override). When done call [method end]. For more information on how this works, search for [code]glBegin()[/code] and [code]glEnd()[/code] references.
- For the type of primitive, see the [enum Mesh.PrimitiveType] enum.
- </description>
- </method>
- <method name="clear">
- <return type="void">
- </return>
- <description>
- Clears everything that was drawn using begin/end.
- </description>
- </method>
- <method name="end">
- <return type="void">
- </return>
- <description>
- Ends a drawing context and displays the results.
- </description>
- </method>
- <method name="set_color">
- <return type="void">
- </return>
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- The current drawing color.
- </description>
- </method>
- <method name="set_normal">
- <return type="void">
- </return>
- <argument index="0" name="normal" type="Vector3">
- </argument>
- <description>
- The next vertex's normal.
- </description>
- </method>
- <method name="set_tangent">
- <return type="void">
- </return>
- <argument index="0" name="tangent" type="Plane">
- </argument>
- <description>
- The next vertex's tangent (and binormal facing).
- </description>
- </method>
- <method name="set_uv">
- <return type="void">
- </return>
- <argument index="0" name="uv" type="Vector2">
- </argument>
- <description>
- The next vertex's UV.
- </description>
- </method>
- <method name="set_uv2">
- <return type="void">
- </return>
- <argument index="0" name="uv" type="Vector2">
- </argument>
- <description>
- The next vertex's second layer UV.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/ImmediateGeometry3D.xml b/doc/classes/ImmediateGeometry3D.xml
new file mode 100644
index 0000000000..1c0831c922
--- /dev/null
+++ b/doc/classes/ImmediateGeometry3D.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ImmediateGeometry3D" inherits="GeometryInstance3D" version="4.0">
+ <brief_description>
+ Draws simple geometry from code.
+ </brief_description>
+ <description>
+ Draws simple geometry from code. Uses a drawing mode similar to OpenGL 1.x.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_sphere">
+ <return type="void">
+ </return>
+ <argument index="0" name="lats" type="int">
+ </argument>
+ <argument index="1" name="lons" type="int">
+ </argument>
+ <argument index="2" name="radius" type="float">
+ </argument>
+ <argument index="3" name="add_uv" type="bool" default="true">
+ </argument>
+ <description>
+ Simple helper to draw an UV sphere with given latitude, longitude and radius.
+ </description>
+ </method>
+ <method name="add_vertex">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <description>
+ Adds a vertex in local coordinate space with the currently set color/uv/etc.
+ </description>
+ </method>
+ <method name="begin">
+ <return type="void">
+ </return>
+ <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType">
+ </argument>
+ <argument index="1" name="texture" type="Texture2D" default="null">
+ </argument>
+ <description>
+ Begin drawing (and optionally pass a texture override). When done call [method end]. For more information on how this works, search for [code]glBegin()[/code] and [code]glEnd()[/code] references.
+ For the type of primitive, see the [enum Mesh.PrimitiveType] enum.
+ </description>
+ </method>
+ <method name="clear">
+ <return type="void">
+ </return>
+ <description>
+ Clears everything that was drawn using begin/end.
+ </description>
+ </method>
+ <method name="end">
+ <return type="void">
+ </return>
+ <description>
+ Ends a drawing context and displays the results.
+ </description>
+ </method>
+ <method name="set_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ The current drawing color.
+ </description>
+ </method>
+ <method name="set_normal">
+ <return type="void">
+ </return>
+ <argument index="0" name="normal" type="Vector3">
+ </argument>
+ <description>
+ The next vertex's normal.
+ </description>
+ </method>
+ <method name="set_tangent">
+ <return type="void">
+ </return>
+ <argument index="0" name="tangent" type="Plane">
+ </argument>
+ <description>
+ The next vertex's tangent (and binormal facing).
+ </description>
+ </method>
+ <method name="set_uv">
+ <return type="void">
+ </return>
+ <argument index="0" name="uv" type="Vector2">
+ </argument>
+ <description>
+ The next vertex's UV.
+ </description>
+ </method>
+ <method name="set_uv2">
+ <return type="void">
+ </return>
+ <argument index="0" name="uv" type="Vector2">
+ </argument>
+ <description>
+ The next vertex's second layer UV.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
deleted file mode 100644
index 557a63b1cc..0000000000
--- a/doc/classes/Input.xml
+++ /dev/null
@@ -1,476 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Input" inherits="Object" version="4.0">
- <brief_description>
- A singleton that deals with inputs.
- </brief_description>
- <description>
- A singleton that deals with inputs. This includes key presses, mouse buttons and movement, joypads, and input actions. Actions and their events can be set in the [b]Input Map[/b] tab in the [b]Project &gt; Project Settings[/b], or with the [InputMap] class.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/index.html</link>
- </tutorials>
- <methods>
- <method name="action_press">
- <return type="void">
- </return>
- <argument index="0" name="action" type="StringName">
- </argument>
- <argument index="1" name="strength" type="float" default="1.0">
- </argument>
- <description>
- This will simulate pressing the specified action.
- The strength can be used for non-boolean actions, it's ranged between 0 and 1 representing the intensity of the given action.
- [b]Note:[/b] This method will not cause any [method Node._input] calls. It is intended to be used with [method is_action_pressed] and [method is_action_just_pressed]. If you want to simulate [code]_input[/code], use [method parse_input_event] instead.
- </description>
- </method>
- <method name="action_release">
- <return type="void">
- </return>
- <argument index="0" name="action" type="StringName">
- </argument>
- <description>
- If the specified action is already pressed, this will release it.
- </description>
- </method>
- <method name="add_joy_mapping">
- <return type="void">
- </return>
- <argument index="0" name="mapping" type="String">
- </argument>
- <argument index="1" name="update_existing" type="bool" default="false">
- </argument>
- <description>
- Adds a new mapping entry (in SDL2 format) to the mapping database. Optionally update already connected devices.
- </description>
- </method>
- <method name="get_accelerometer" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- If the device has an accelerometer, this will return the acceleration. Otherwise, it returns an empty [Vector3].
- 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.
- </description>
- </method>
- <method name="get_action_strength" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="action" type="StringName">
- </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>
- </method>
- <method name="get_connected_joypads">
- <return type="Array">
- </return>
- <description>
- Returns an [Array] containing the device IDs of all currently connected joypads.
- </description>
- </method>
- <method name="get_current_cursor_shape" qualifiers="const">
- <return type="int" enum="Input.CursorShape">
- </return>
- <description>
- Returns the currently assigned cursor shape (see [enum CursorShape]).
- </description>
- </method>
- <method name="get_gravity" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- If the device has an accelerometer, this will return the gravity. Otherwise, it returns an empty [Vector3].
- </description>
- </method>
- <method name="get_gyroscope" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- If the device has a gyroscope, this will return the rate of rotation in rad/s around a device's X, Y, and Z axes. Otherwise, it returns an empty [Vector3].
- </description>
- </method>
- <method name="get_joy_axis" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <argument index="1" name="axis" type="int">
- </argument>
- <description>
- Returns the current value of the joypad axis at given index (see [enum JoystickList]).
- </description>
- </method>
- <method name="get_joy_axis_index_from_string">
- <return type="int">
- </return>
- <argument index="0" name="axis" type="String">
- </argument>
- <description>
- Returns the index of the provided axis name.
- </description>
- </method>
- <method name="get_joy_axis_string">
- <return type="String">
- </return>
- <argument index="0" name="axis_index" type="int">
- </argument>
- <description>
- Receives a [enum JoystickList] axis and returns its equivalent name as a string.
- </description>
- </method>
- <method name="get_joy_button_index_from_string">
- <return type="int">
- </return>
- <argument index="0" name="button" type="String">
- </argument>
- <description>
- Returns the index of the provided button name.
- </description>
- </method>
- <method name="get_joy_button_string">
- <return type="String">
- </return>
- <argument index="0" name="button_index" type="int">
- </argument>
- <description>
- Receives a gamepad button from [enum JoystickList] and returns its equivalent name as a string.
- </description>
- </method>
- <method name="get_joy_guid" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <description>
- Returns a SDL2-compatible device GUID on platforms that use gamepad remapping. Returns [code]"Default Gamepad"[/code] otherwise.
- </description>
- </method>
- <method name="get_joy_name">
- <return type="String">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <description>
- Returns the name of the joypad at the specified device index.
- </description>
- </method>
- <method name="get_joy_vibration_duration">
- <return type="float">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <description>
- Returns the duration of the current vibration effect in seconds.
- </description>
- </method>
- <method name="get_joy_vibration_strength">
- <return type="Vector2">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <description>
- Returns the strength of the joypad vibration: x is the strength of the weak motor, and y is the strength of the strong motor.
- </description>
- </method>
- <method name="get_last_mouse_speed" qualifiers="const">
- <return type="Vector2">
- </return>
- <description>
- Returns the mouse speed for the last time the cursor was moved, and this until the next frame where the mouse moves. This means that even if the mouse is not moving, this function will still return the value of the last motion.
- </description>
- </method>
- <method name="get_magnetometer" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- If the device has a magnetometer, this will return the magnetic field strength in micro-Tesla for all axes.
- </description>
- </method>
- <method name="get_mouse_button_mask" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together.
- </description>
- </method>
- <method name="get_mouse_mode" qualifiers="const">
- <return type="int" enum="Input.MouseMode">
- </return>
- <description>
- Returns the mouse mode. See the constants for more information.
- </description>
- </method>
- <method name="is_action_just_pressed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="action" type="StringName">
- </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.
- </description>
- </method>
- <method name="is_action_just_released" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="action" type="StringName">
- </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>
- </method>
- <method name="is_action_pressed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="action" type="StringName">
- </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>
- </method>
- <method name="is_joy_button_pressed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <argument index="1" name="button" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if you are pressing the joypad button (see [enum JoystickList]).
- </description>
- </method>
- <method name="is_joy_known">
- <return type="bool">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the system knows the specified device. This means that it sets all button and axis indices exactly as defined in [enum JoystickList]. Unknown joypads are not expected to match these constants, but you can still retrieve events from them.
- </description>
- </method>
- <method name="is_key_pressed" qualifiers="const">
- <return type="bool">
- </return>
- <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.
- </description>
- </method>
- <method name="is_mouse_button_pressed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if you are pressing the mouse button specified with [enum ButtonList].
- </description>
- </method>
- <method name="joy_connection_changed">
- <return type="void">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <argument index="1" name="connected" type="bool">
- </argument>
- <argument index="2" name="name" type="String">
- </argument>
- <argument index="3" name="guid" type="String">
- </argument>
- <description>
- Notifies the [Input] singleton that a connection has changed, to update the state for the [code]device[/code] index.
- This is used internally and should not have to be called from user scripts. See [signal joy_connection_changed] for the signal emitted when this is triggered internally.
- </description>
- </method>
- <method name="parse_input_event">
- <return type="void">
- </return>
- <argument index="0" name="event" type="InputEvent">
- </argument>
- <description>
- Feeds an [InputEvent] to the game. Can be used to artificially trigger input events from code. Also generates [method Node._input] calls.
- Example:
- [codeblock]
- var a = InputEventAction.new()
- a.action = "ui_cancel"
- a.pressed = true
- Input.parse_input_event(a)
- [/codeblock]
- </description>
- </method>
- <method name="remove_joy_mapping">
- <return type="void">
- </return>
- <argument index="0" name="guid" type="String">
- </argument>
- <description>
- Removes all mappings from the internal database that match the given GUID.
- </description>
- </method>
- <method name="set_custom_mouse_cursor">
- <return type="void">
- </return>
- <argument index="0" name="image" type="Resource">
- </argument>
- <argument index="1" name="shape" type="int" enum="Input.CursorShape" default="0">
- </argument>
- <argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <description>
- Sets a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. Passing [code]null[/code] to the image parameter resets to the system cursor. See [enum CursorShape] for the list of shapes.
- [code]image[/code]'s size must be lower than 256×256.
- [code]hotspot[/code] must be within [code]image[/code]'s size.
- [b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If using an [AnimatedTexture], only the first frame will be displayed.
- [b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or [b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] compression mode can't be used for custom cursors.
- </description>
- </method>
- <method name="set_default_cursor_shape">
- <return type="void">
- </return>
- <argument index="0" name="shape" type="int" enum="Input.CursorShape" default="0">
- </argument>
- <description>
- Sets the default cursor shape to be used in the viewport instead of [constant CURSOR_ARROW].
- [b]Note:[/b] If you want to change the default cursor shape for [Control]'s nodes, use [member Control.mouse_default_cursor_shape] instead.
- [b]Note:[/b] This method generates an [InputEventMouseMotion] to update cursor immediately.
- </description>
- </method>
- <method name="set_mouse_mode">
- <return type="void">
- </return>
- <argument index="0" name="mode" type="int" enum="Input.MouseMode">
- </argument>
- <description>
- Sets the mouse mode. See the constants for more information.
- </description>
- </method>
- <method name="set_use_accumulated_input">
- <return type="void">
- </return>
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Whether to accumulate similar input events sent by the operating system. Enabled by default.
- </description>
- </method>
- <method name="start_joy_vibration">
- <return type="void">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <argument index="1" name="weak_magnitude" type="float">
- </argument>
- <argument index="2" name="strong_magnitude" type="float">
- </argument>
- <argument index="3" name="duration" type="float" default="0">
- </argument>
- <description>
- Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [code]weak_magnitude[/code] is the strength of the weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the strength of the strong motor (between 0 and 1). [code]duration[/code] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely).
- [b]Note:[/b] Not every hardware is compatible with long effect durations; it is recommended to restart an effect if it has to be played for more than a few seconds.
- </description>
- </method>
- <method name="stop_joy_vibration">
- <return type="void">
- </return>
- <argument index="0" name="device" type="int">
- </argument>
- <description>
- Stops the vibration of the joypad.
- </description>
- </method>
- <method name="vibrate_handheld">
- <return type="void">
- </return>
- <argument index="0" name="duration_ms" type="int" default="500">
- </argument>
- <description>
- Vibrate Android and iOS devices.
- [b]Note:[/b] It needs VIBRATE permission for Android at export settings. iOS does not support duration.
- </description>
- </method>
- <method name="warp_mouse_position">
- <return type="void">
- </return>
- <argument index="0" name="to" type="Vector2">
- </argument>
- <description>
- Sets the mouse position to the specified vector.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="joy_connection_changed">
- <argument index="0" name="device" type="int">
- </argument>
- <argument index="1" name="connected" type="bool">
- </argument>
- <description>
- Emitted when a joypad device has been connected or disconnected.
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
- Makes the mouse cursor visible if it is hidden.
- </constant>
- <constant name="MOUSE_MODE_HIDDEN" value="1" enum="MouseMode">
- Makes the mouse cursor hidden if it is visible.
- </constant>
- <constant name="MOUSE_MODE_CAPTURED" value="2" enum="MouseMode">
- Captures the mouse. The mouse will be hidden and unable to leave the game window, but it will still register movement and mouse button presses. On Windows and Linux, the mouse will use raw input mode, which means the reported movement will be unaffected by the OS' mouse acceleration settings.
- </constant>
- <constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
- Makes the mouse cursor visible but confines it to the game window.
- </constant>
- <constant name="CURSOR_ARROW" value="0" enum="CursorShape">
- Arrow cursor. Standard, default pointing cursor.
- </constant>
- <constant name="CURSOR_IBEAM" value="1" enum="CursorShape">
- I-beam cursor. Usually used to show where the text cursor will appear when the mouse is clicked.
- </constant>
- <constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape">
- Pointing hand cursor. Usually used to indicate the pointer is over a link or other interactable item.
- </constant>
- <constant name="CURSOR_CROSS" value="3" enum="CursorShape">
- Cross cursor. Typically appears over regions in which a drawing operation can be performed or for selections.
- </constant>
- <constant name="CURSOR_WAIT" value="4" enum="CursorShape">
- Wait cursor. Indicates that the application is busy performing an operation. This cursor shape denotes that the application is still usable during the operation.
- </constant>
- <constant name="CURSOR_BUSY" value="5" enum="CursorShape">
- Busy cursor. Indicates that the application is busy performing an operation. This cursor shape denotes that the application isn't usable during the operation (e.g. something is blocking its main thread).
- </constant>
- <constant name="CURSOR_DRAG" value="6" enum="CursorShape">
- Drag cursor. Usually displayed when dragging something.
- </constant>
- <constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape">
- Can drop cursor. Usually displayed when dragging something to indicate that it can be dropped at the current position.
- </constant>
- <constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape">
- Forbidden cursor. Indicates that the current action is forbidden (for example, when dragging something) or that the control at a position is disabled.
- </constant>
- <constant name="CURSOR_VSIZE" value="9" enum="CursorShape">
- Vertical resize mouse cursor. A double-headed vertical arrow. It tells the user they can resize the window or the panel vertically.
- </constant>
- <constant name="CURSOR_HSIZE" value="10" enum="CursorShape">
- Horizontal resize mouse cursor. A double-headed horizontal arrow. It tells the user they can resize the window or the panel horizontally.
- </constant>
- <constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape">
- Window resize mouse cursor. The cursor is a double-headed arrow that goes from the bottom left to the top right. It tells the user they can resize the window or the panel both horizontally and vertically.
- </constant>
- <constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape">
- Window resize mouse cursor. The cursor is a double-headed arrow that goes from the top left to the bottom right, the opposite of [constant CURSOR_BDIAGSIZE]. It tells the user they can resize the window or the panel both horizontally and vertically.
- </constant>
- <constant name="CURSOR_MOVE" value="13" enum="CursorShape">
- Move cursor. Indicates that something can be moved.
- </constant>
- <constant name="CURSOR_VSPLIT" value="14" enum="CursorShape">
- Vertical split mouse cursor. On Windows, it's the same as [constant CURSOR_VSIZE].
- </constant>
- <constant name="CURSOR_HSPLIT" value="15" enum="CursorShape">
- Horizontal split mouse cursor. On Windows, it's the same as [constant CURSOR_HSIZE].
- </constant>
- <constant name="CURSOR_HELP" value="16" enum="CursorShape">
- Help cursor. Usually a question mark.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/InputDefault.xml b/doc/classes/InputDefault.xml
deleted file mode 100644
index ea4d08c628..0000000000
--- a/doc/classes/InputDefault.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputDefault" inherits="Input" version="4.0">
- <brief_description>
- Default implementation of the [Input] class.
- </brief_description>
- <description>
- Default implementation of the [Input] class, used internally by the editor and games for default input management.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/InputEventFromWindow.xml b/doc/classes/InputEventFromWindow.xml
new file mode 100644
index 0000000000..7cd5b7d179
--- /dev/null
+++ b/doc/classes/InputEventFromWindow.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="InputEventFromWindow" inherits="InputEvent" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="window_id" type="int" setter="set_window_id" getter="get_window_id" default="0">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/InputEventGesture.xml b/doc/classes/InputEventGesture.xml
index 9cacd3e6fd..861ec026cd 100644
--- a/doc/classes/InputEventGesture.xml
+++ b/doc/classes/InputEventGesture.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="InputEventGesture" inherits="InputEventWithModifiers" version="4.0">
<brief_description>
+ Base class for touch control gestures.
</brief_description>
<description>
</description>
@@ -10,6 +11,7 @@
</methods>
<members>
<member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2( 0, 0 )">
+ The local gesture position relative to the [Viewport]. If used in [method Control._gui_input], the position is relative to the current [Control] that received this gesture.
</member>
</members>
<constants>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index c8d0769b90..34afa90553 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -43,7 +43,7 @@
If [code]true[/code], the key's state is pressed. If [code]false[/code], the key's state is released.
</member>
<member name="unicode" type="int" setter="set_unicode" getter="get_unicode" default="0">
- The key Unicode identifier (when relevant). Unicode identifiers for the composite characters and complex scripts may not be available unless IME input mode is active. See [method OS.set_ime_active] for more information.
+ The key Unicode identifier (when relevant). Unicode identifiers for the composite characters and complex scripts may not be available unless IME input mode is active. See [method Window.set_ime_active] for more information.
</member>
</members>
<constants>
diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml
index 1549353d45..97b9d5247a 100644
--- a/doc/classes/InputEventMouseMotion.xml
+++ b/doc/classes/InputEventMouseMotion.xml
@@ -16,7 +16,8 @@
Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code].
</member>
<member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2( 0, 0 )">
- The mouse position relative to the previous position (position at the last frame).
+ The mouse position relative to the previous position (position at the last frame).
+ [b]Note:[/b] Since [InputEventMouseMotion] is only emitted when the mouse moves, the last event won't have a relative position of [code]Vector2(0, 0)[/code] when the user stops moving the mouse.
</member>
<member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2( 0, 0 )">
The mouse speed in pixels per second.
diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml
index d7e0c2454c..a315e4ddfb 100644
--- a/doc/classes/InputEventScreenDrag.xml
+++ b/doc/classes/InputEventScreenDrag.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventScreenDrag" inherits="InputEvent" version="4.0">
+<class name="InputEventScreenDrag" inherits="InputEventFromWindow" version="4.0">
<brief_description>
Input event type for screen drag events. Only available on mobile devices.
</brief_description>
diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml
index 4a5cd36423..16a3cf8353 100644
--- a/doc/classes/InputEventScreenTouch.xml
+++ b/doc/classes/InputEventScreenTouch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventScreenTouch" inherits="InputEvent" version="4.0">
+<class name="InputEventScreenTouch" inherits="InputEventFromWindow" version="4.0">
<brief_description>
Input event type for screen touch events.
(only available on mobile devices)
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index 63465ad28c..34faf18e24 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InputEventWithModifiers" inherits="InputEvent" version="4.0">
+<class name="InputEventWithModifiers" inherits="InputEventFromWindow" version="4.0">
<brief_description>
Base class for keys events with modifiers.
</brief_description>
diff --git a/doc/classes/InputFilter.xml b/doc/classes/InputFilter.xml
new file mode 100644
index 0000000000..54184ae8a3
--- /dev/null
+++ b/doc/classes/InputFilter.xml
@@ -0,0 +1,477 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="InputFilter" inherits="Object" version="4.0">
+ <brief_description>
+ A singleton that deals with inputs.
+ </brief_description>
+ <description>
+ A singleton that deals with inputs. This includes key presses, mouse buttons and movement, joypads, and input actions. Actions and their events can be set in the [b]Input Map[/b] tab in the [b]Project &gt; Project Settings[/b], or with the [InputMap] class.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/inputs/index.html</link>
+ </tutorials>
+ <methods>
+ <method name="action_press">
+ <return type="void">
+ </return>
+ <argument index="0" name="action" type="StringName">
+ </argument>
+ <argument index="1" name="strength" type="float" default="1.0">
+ </argument>
+ <description>
+ This will simulate pressing the specified action.
+ The strength can be used for non-boolean actions, it's ranged between 0 and 1 representing the intensity of the given action.
+ [b]Note:[/b] This method will not cause any [method Node._input] calls. It is intended to be used with [method is_action_pressed] and [method is_action_just_pressed]. If you want to simulate [code]_input[/code], use [method parse_input_event] instead.
+ </description>
+ </method>
+ <method name="action_release">
+ <return type="void">
+ </return>
+ <argument index="0" name="action" type="StringName">
+ </argument>
+ <description>
+ If the specified action is already pressed, this will release it.
+ </description>
+ </method>
+ <method name="add_joy_mapping">
+ <return type="void">
+ </return>
+ <argument index="0" name="mapping" type="String">
+ </argument>
+ <argument index="1" name="update_existing" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a new mapping entry (in SDL2 format) to the mapping database. Optionally update already connected devices.
+ </description>
+ </method>
+ <method name="get_accelerometer" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ If the device has an accelerometer, this will return the acceleration. Otherwise, it returns an empty [Vector3].
+ 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.
+ </description>
+ </method>
+ <method name="get_action_strength" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="action" type="StringName">
+ </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>
+ </method>
+ <method name="get_connected_joypads">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an [Array] containing the device IDs of all currently connected joypads.
+ </description>
+ </method>
+ <method name="get_current_cursor_shape" qualifiers="const">
+ <return type="int" enum="InputFilter.CursorShape">
+ </return>
+ <description>
+ Returns the currently assigned cursor shape (see [enum CursorShape]).
+ </description>
+ </method>
+ <method name="get_gravity" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ If the device has an accelerometer, this will return the gravity. Otherwise, it returns an empty [Vector3].
+ </description>
+ </method>
+ <method name="get_gyroscope" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ If the device has a gyroscope, this will return the rate of rotation in rad/s around a device's X, Y, and Z axes. Otherwise, it returns an empty [Vector3].
+ </description>
+ </method>
+ <method name="get_joy_axis" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <argument index="1" name="axis" type="int">
+ </argument>
+ <description>
+ Returns the current value of the joypad axis at given index (see [enum JoystickList]).
+ </description>
+ </method>
+ <method name="get_joy_axis_index_from_string">
+ <return type="int">
+ </return>
+ <argument index="0" name="axis" type="String">
+ </argument>
+ <description>
+ Returns the index of the provided axis name.
+ </description>
+ </method>
+ <method name="get_joy_axis_string">
+ <return type="String">
+ </return>
+ <argument index="0" name="axis_index" type="int">
+ </argument>
+ <description>
+ Receives a [enum JoystickList] axis and returns its equivalent name as a string.
+ </description>
+ </method>
+ <method name="get_joy_button_index_from_string">
+ <return type="int">
+ </return>
+ <argument index="0" name="button" type="String">
+ </argument>
+ <description>
+ Returns the index of the provided button name.
+ </description>
+ </method>
+ <method name="get_joy_button_string">
+ <return type="String">
+ </return>
+ <argument index="0" name="button_index" type="int">
+ </argument>
+ <description>
+ Receives a gamepad button from [enum JoystickList] and returns its equivalent name as a string.
+ </description>
+ </method>
+ <method name="get_joy_guid" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Returns a SDL2-compatible device GUID on platforms that use gamepad remapping. Returns [code]"Default Gamepad"[/code] otherwise.
+ </description>
+ </method>
+ <method name="get_joy_name">
+ <return type="String">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Returns the name of the joypad at the specified device index.
+ </description>
+ </method>
+ <method name="get_joy_vibration_duration">
+ <return type="float">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Returns the duration of the current vibration effect in seconds.
+ </description>
+ </method>
+ <method name="get_joy_vibration_strength">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Returns the strength of the joypad vibration: x is the strength of the weak motor, and y is the strength of the strong motor.
+ </description>
+ </method>
+ <method name="get_last_mouse_speed" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ Returns the mouse speed for the last time the cursor was moved, and this until the next frame where the mouse moves. This means that even if the mouse is not moving, this function will still return the value of the last motion.
+ </description>
+ </method>
+ <method name="get_magnetometer" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ If the device has a magnetometer, this will return the magnetic field strength in micro-Tesla for all axes.
+ </description>
+ </method>
+ <method name="get_mouse_button_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together.
+ </description>
+ </method>
+ <method name="get_mouse_mode" qualifiers="const">
+ <return type="int" enum="InputFilter.MouseMode">
+ </return>
+ <description>
+ Returns the mouse mode. See the constants for more information.
+ </description>
+ </method>
+ <method name="is_action_just_pressed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="action" type="StringName">
+ </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.
+ </description>
+ </method>
+ <method name="is_action_just_released" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="action" type="StringName">
+ </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>
+ </method>
+ <method name="is_action_pressed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="action" type="StringName">
+ </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>
+ </method>
+ <method name="is_joy_button_pressed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <argument index="1" name="button" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if you are pressing the joypad button (see [enum JoystickList]).
+ </description>
+ </method>
+ <method name="is_joy_known">
+ <return type="bool">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the system knows the specified device. This means that it sets all button and axis indices exactly as defined in [enum JoystickList]. Unknown joypads are not expected to match these constants, but you can still retrieve events from them.
+ </description>
+ </method>
+ <method name="is_key_pressed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <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.
+ </description>
+ </method>
+ <method name="is_mouse_button_pressed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="button" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if you are pressing the mouse button specified with [enum ButtonList].
+ </description>
+ </method>
+ <method name="joy_connection_changed">
+ <return type="void">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <argument index="1" name="connected" type="bool">
+ </argument>
+ <argument index="2" name="name" type="String">
+ </argument>
+ <argument index="3" name="guid" type="String">
+ </argument>
+ <description>
+ Notifies the [InputFilter] singleton that a connection has changed, to update the state for the [code]device[/code] index.
+ This is used internally and should not have to be called from user scripts. See [signal joy_connection_changed] for the signal emitted when this is triggered internally.
+ </description>
+ </method>
+ <method name="parse_input_event">
+ <return type="void">
+ </return>
+ <argument index="0" name="event" type="InputEvent">
+ </argument>
+ <description>
+ Feeds an [InputEvent] to the game. Can be used to artificially trigger input events from code. Also generates [method Node._input] calls.
+ Example:
+ [codeblock]
+ var a = InputEventAction.new()
+ a.action = "ui_cancel"
+ a.pressed = true
+ InputFilter.parse_input_event(a)
+ [/codeblock]
+ </description>
+ </method>
+ <method name="remove_joy_mapping">
+ <return type="void">
+ </return>
+ <argument index="0" name="guid" type="String">
+ </argument>
+ <description>
+ Removes all mappings from the internal database that match the given GUID.
+ </description>
+ </method>
+ <method name="set_custom_mouse_cursor">
+ <return type="void">
+ </return>
+ <argument index="0" name="image" type="Resource">
+ </argument>
+ <argument index="1" name="shape" type="int" enum="InputFilter.CursorShape" default="0">
+ </argument>
+ <argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
+ </argument>
+ <description>
+ Sets a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. Passing [code]null[/code] to the image parameter resets to the system cursor. See [enum CursorShape] for the list of shapes.
+ [code]image[/code]'s size must be lower than 256×256.
+ [code]hotspot[/code] must be within [code]image[/code]'s size.
+ [b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If using an [AnimatedTexture], only the first frame will be displayed.
+ [b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or [b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] compression mode can't be used for custom cursors.
+ </description>
+ </method>
+ <method name="set_default_cursor_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="shape" type="int" enum="InputFilter.CursorShape" default="0">
+ </argument>
+ <description>
+ Sets the default cursor shape to be used in the viewport instead of [constant CURSOR_ARROW].
+ [b]Note:[/b] If you want to change the default cursor shape for [Control]'s nodes, use [member Control.mouse_default_cursor_shape] instead.
+ [b]Note:[/b] This method generates an [InputEventMouseMotion] to update cursor immediately.
+ </description>
+ </method>
+ <method name="set_mouse_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="mode" type="int" enum="InputFilter.MouseMode">
+ </argument>
+ <description>
+ Sets the mouse mode. See the constants for more information.
+ </description>
+ </method>
+ <method name="set_use_accumulated_input">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Enables or disables the accumulation of similar input events sent by the operating system. When input accumulation is enabled, all input events generated during a frame will be merged and emitted when the frame is done rendering. Therefore, this limits the number of input method calls per second to the rendering FPS.
+ Input accumulation is enabled by default. It can be disabled to get slightly more precise/reactive input at the cost of increased CPU usage. In applications where drawing freehand lines is required, input accumulation should generally be disabled while the user is drawing the line to get results that closely follow the actual input.
+ </description>
+ </method>
+ <method name="start_joy_vibration">
+ <return type="void">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <argument index="1" name="weak_magnitude" type="float">
+ </argument>
+ <argument index="2" name="strong_magnitude" type="float">
+ </argument>
+ <argument index="3" name="duration" type="float" default="0">
+ </argument>
+ <description>
+ Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [code]weak_magnitude[/code] is the strength of the weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the strength of the strong motor (between 0 and 1). [code]duration[/code] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely).
+ [b]Note:[/b] Not every hardware is compatible with long effect durations; it is recommended to restart an effect if it has to be played for more than a few seconds.
+ </description>
+ </method>
+ <method name="stop_joy_vibration">
+ <return type="void">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Stops the vibration of the joypad.
+ </description>
+ </method>
+ <method name="vibrate_handheld">
+ <return type="void">
+ </return>
+ <argument index="0" name="duration_ms" type="int" default="500">
+ </argument>
+ <description>
+ Vibrate Android and iOS devices.
+ [b]Note:[/b] It needs VIBRATE permission for Android at export settings. iOS does not support duration.
+ </description>
+ </method>
+ <method name="warp_mouse_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="to" type="Vector2">
+ </argument>
+ <description>
+ Sets the mouse position to the specified vector.
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="joy_connection_changed">
+ <argument index="0" name="device" type="int">
+ </argument>
+ <argument index="1" name="connected" type="bool">
+ </argument>
+ <description>
+ Emitted when a joypad device has been connected or disconnected.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
+ Makes the mouse cursor visible if it is hidden.
+ </constant>
+ <constant name="MOUSE_MODE_HIDDEN" value="1" enum="MouseMode">
+ Makes the mouse cursor hidden if it is visible.
+ </constant>
+ <constant name="MOUSE_MODE_CAPTURED" value="2" enum="MouseMode">
+ Captures the mouse. The mouse will be hidden and unable to leave the game window, but it will still register movement and mouse button presses. On Windows and Linux, the mouse will use raw input mode, which means the reported movement will be unaffected by the OS' mouse acceleration settings.
+ </constant>
+ <constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
+ Makes the mouse cursor visible but confines it to the game window.
+ </constant>
+ <constant name="CURSOR_ARROW" value="0" enum="CursorShape">
+ Arrow cursor. Standard, default pointing cursor.
+ </constant>
+ <constant name="CURSOR_IBEAM" value="1" enum="CursorShape">
+ I-beam cursor. Usually used to show where the text cursor will appear when the mouse is clicked.
+ </constant>
+ <constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape">
+ Pointing hand cursor. Usually used to indicate the pointer is over a link or other interactable item.
+ </constant>
+ <constant name="CURSOR_CROSS" value="3" enum="CursorShape">
+ Cross cursor. Typically appears over regions in which a drawing operation can be performed or for selections.
+ </constant>
+ <constant name="CURSOR_WAIT" value="4" enum="CursorShape">
+ Wait cursor. Indicates that the application is busy performing an operation. This cursor shape denotes that the application is still usable during the operation.
+ </constant>
+ <constant name="CURSOR_BUSY" value="5" enum="CursorShape">
+ Busy cursor. Indicates that the application is busy performing an operation. This cursor shape denotes that the application isn't usable during the operation (e.g. something is blocking its main thread).
+ </constant>
+ <constant name="CURSOR_DRAG" value="6" enum="CursorShape">
+ Drag cursor. Usually displayed when dragging something.
+ </constant>
+ <constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape">
+ Can drop cursor. Usually displayed when dragging something to indicate that it can be dropped at the current position.
+ </constant>
+ <constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape">
+ Forbidden cursor. Indicates that the current action is forbidden (for example, when dragging something) or that the control at a position is disabled.
+ </constant>
+ <constant name="CURSOR_VSIZE" value="9" enum="CursorShape">
+ Vertical resize mouse cursor. A double-headed vertical arrow. It tells the user they can resize the window or the panel vertically.
+ </constant>
+ <constant name="CURSOR_HSIZE" value="10" enum="CursorShape">
+ Horizontal resize mouse cursor. A double-headed horizontal arrow. It tells the user they can resize the window or the panel horizontally.
+ </constant>
+ <constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape">
+ Window resize mouse cursor. The cursor is a double-headed arrow that goes from the bottom left to the top right. It tells the user they can resize the window or the panel both horizontally and vertically.
+ </constant>
+ <constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape">
+ Window resize mouse cursor. The cursor is a double-headed arrow that goes from the top left to the bottom right, the opposite of [constant CURSOR_BDIAGSIZE]. It tells the user they can resize the window or the panel both horizontally and vertically.
+ </constant>
+ <constant name="CURSOR_MOVE" value="13" enum="CursorShape">
+ Move cursor. Indicates that something can be moved.
+ </constant>
+ <constant name="CURSOR_VSPLIT" value="14" enum="CursorShape">
+ Vertical split mouse cursor. On Windows, it's the same as [constant CURSOR_VSIZE].
+ </constant>
+ <constant name="CURSOR_HSPLIT" value="15" enum="CursorShape">
+ Horizontal split mouse cursor. On Windows, it's the same as [constant CURSOR_HSIZE].
+ </constant>
+ <constant name="CURSOR_HELP" value="16" enum="CursorShape">
+ Help cursor. Usually a question mark.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/InterpolatedCamera.xml b/doc/classes/InterpolatedCamera.xml
deleted file mode 100644
index 66df7e9531..0000000000
--- a/doc/classes/InterpolatedCamera.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="InterpolatedCamera" inherits="Camera" version="4.0">
- <brief_description>
- Camera which moves toward another node.
- </brief_description>
- <description>
- InterpolatedCamera is a [Camera] which smoothly moves to match a target node's position and rotation.
- If it is not [member enabled] or does not have a valid target set, InterpolatedCamera acts like a normal Camera.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="set_target">
- <return type="void">
- </return>
- <argument index="0" name="target" type="Object">
- </argument>
- <description>
- Sets the node to move toward and orient with.
- </description>
- </method>
- </methods>
- <members>
- <member name="enabled" type="bool" setter="set_interpolation_enabled" getter="is_interpolation_enabled" default="false">
- If [code]true[/code], and a target is set, the camera will move automatically.
- </member>
- <member name="speed" type="float" setter="set_speed" getter="get_speed" default="1.0">
- How quickly the camera moves toward its target. Higher values will result in tighter camera motion.
- </member>
- <member name="target" type="NodePath" setter="set_target_path" getter="get_target_path" default="NodePath(&quot;&quot;)">
- The target's [NodePath].
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Joint.xml b/doc/classes/Joint.xml
deleted file mode 100644
index 34da997292..0000000000
--- a/doc/classes/Joint.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Joint" inherits="Spatial" version="4.0">
- <brief_description>
- Base class for all 3D joints.
- </brief_description>
- <description>
- Joints are used to bind together two physics bodies. They have a solver priority and can define if the bodies of the two attached nodes should be able to collide with each other.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="collision/exclude_nodes" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
- If [code]true[/code], the two bodies of the nodes are not able to collide with each other.
- </member>
- <member name="nodes/node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath(&quot;&quot;)">
- The node attached to the first side (A) of the joint.
- </member>
- <member name="nodes/node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath(&quot;&quot;)">
- The node attached to the second side (B) of the joint.
- </member>
- <member name="solver/priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1">
- The priority used to define which solver is executed first for multiple joints. The lower the value, the higher the priority.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml
new file mode 100644
index 0000000000..15bef960f6
--- /dev/null
+++ b/doc/classes/Joint3D.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Joint3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Base class for all 3D joints.
+ </brief_description>
+ <description>
+ Joints are used to bind together two physics bodies. They have a solver priority and can define if the bodies of the two attached nodes should be able to collide with each other.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="collision/exclude_nodes" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
+ If [code]true[/code], the two bodies of the nodes are not able to collide with each other.
+ </member>
+ <member name="nodes/node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath(&quot;&quot;)">
+ The node attached to the first side (A) of the joint.
+ </member>
+ <member name="nodes/node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath(&quot;&quot;)">
+ The node attached to the second side (B) of the joint.
+ </member>
+ <member name="solver/priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1">
+ The priority used to define which solver is executed first for multiple joints. The lower the value, the higher the priority.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml
deleted file mode 100644
index 4ccbc679bf..0000000000
--- a/doc/classes/KinematicBody.xml
+++ /dev/null
@@ -1,181 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicBody" inherits="PhysicsBody" version="4.0">
- <brief_description>
- Kinematic body 3D node.
- </brief_description>
- <description>
- Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses:
- [b]Simulated motion:[/b] When these bodies are moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc).
- [b]Kinematic characters:[/b] KinematicBody also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
- </tutorials>
- <methods>
- <method name="get_axis_lock" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="axis" type="int" enum="PhysicsServer.BodyAxis">
- </argument>
- <description>
- Returns [code]true[/code] if the specified [code]axis[/code] is locked. See also [member move_lock_x], [member move_lock_y] and [member move_lock_z].
- </description>
- </method>
- <method name="get_floor_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code].
- </description>
- </method>
- <method name="get_floor_velocity" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code].
- </description>
- </method>
- <method name="get_slide_collision">
- <return type="KinematicCollision">
- </return>
- <argument index="0" name="slide_idx" type="int">
- </argument>
- <description>
- Returns a [KinematicCollision], which contains information about a collision that occurred during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1).
- </description>
- </method>
- <method name="get_slide_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of times the body collided and changed direction during the last call to [method move_and_slide].
- </description>
- </method>
- <method name="is_on_ceiling" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body is on the ceiling. Only updates when calling [method move_and_slide].
- </description>
- </method>
- <method name="is_on_floor" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body is on the floor. Only updates when calling [method move_and_slide].
- </description>
- </method>
- <method name="is_on_wall" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the body is on a wall. Only updates when calling [method move_and_slide].
- </description>
- </method>
- <method name="move_and_collide">
- <return type="KinematicCollision">
- </return>
- <argument index="0" name="rel_vec" type="Vector3">
- </argument>
- <argument index="1" name="infinite_inertia" type="bool" default="true">
- </argument>
- <argument index="2" name="exclude_raycast_shapes" type="bool" default="true">
- </argument>
- <argument index="3" name="test_only" type="bool" default="false">
- </argument>
- <description>
- Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision], which contains information about the collision.
- If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
- </description>
- </method>
- <method name="move_and_slide">
- <return type="Vector3">
- </return>
- <argument index="0" name="linear_velocity" type="Vector3">
- </argument>
- <argument index="1" name="up_direction" type="Vector3" default="Vector3( 0, 0, 0 )">
- </argument>
- <argument index="2" name="stop_on_slope" type="bool" default="false">
- </argument>
- <argument index="3" name="max_slides" type="int" default="4">
- </argument>
- <argument index="4" name="floor_max_angle" type="float" default="0.785398">
- </argument>
- <argument index="5" name="infinite_inertia" type="bool" default="true">
- </argument>
- <description>
- Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody] or [RigidBody], it will also be affected by the motion of the other body. You can use this to make moving or rotating platforms, or to make nodes push other nodes.
- This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
- [code]linear_velocity[/code] is the velocity vector (typically meters per second). Unlike in [method move_and_collide], you should [i]not[/i] multiply it by [code]delta[/code] — the physics engine handles applying the velocity.
- [code]up_direction[/code] is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of [code]Vector3(0, 0, 0)[/code], everything is considered a wall.
- If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on slopes if you include gravity in [code]linear_velocity[/code].
- If the body collides, it will change direction a maximum of [code]max_slides[/code] times before it stops.
- [code]floor_max_angle[/code] is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees.
- If [code]infinite_inertia[/code] is [code]true[/code], body will be able to push [RigidBody] nodes, but it won't also detect any collisions with them. If [code]false[/code], it will interact with [RigidBody] nodes like with [StaticBody].
- Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
- </description>
- </method>
- <method name="move_and_slide_with_snap">
- <return type="Vector3">
- </return>
- <argument index="0" name="linear_velocity" type="Vector3">
- </argument>
- <argument index="1" name="snap" type="Vector3">
- </argument>
- <argument index="2" name="up_direction" type="Vector3" default="Vector3( 0, 0, 0 )">
- </argument>
- <argument index="3" name="stop_on_slope" type="bool" default="false">
- </argument>
- <argument index="4" name="max_slides" type="int" default="4">
- </argument>
- <argument index="5" name="floor_max_angle" type="float" default="0.785398">
- </argument>
- <argument index="6" name="infinite_inertia" type="bool" default="true">
- </argument>
- <description>
- Moves the body while keeping it attached to slopes. Similar to [method move_and_slide].
- As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code](0, 0, 0)[/code] or by using [method move_and_slide] instead.
- </description>
- </method>
- <method name="set_axis_lock">
- <return type="void">
- </return>
- <argument index="0" name="axis" type="int" enum="PhysicsServer.BodyAxis">
- </argument>
- <argument index="1" name="lock" type="bool">
- </argument>
- <description>
- Locks or unlocks the specified [code]axis[/code] depending on the value of [code]lock[/code]. See also [member move_lock_x], [member move_lock_y] and [member move_lock_z].
- </description>
- </method>
- <method name="test_move">
- <return type="bool">
- </return>
- <argument index="0" name="from" type="Transform">
- </argument>
- <argument index="1" name="rel_vec" type="Vector3">
- </argument>
- <argument index="2" name="infinite_inertia" type="bool" default="true">
- </argument>
- <description>
- Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
- </description>
- </method>
- </methods>
- <members>
- <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.
- </member>
- <member name="move_lock_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's X axis movement.
- </member>
- <member name="move_lock_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's Y axis movement.
- </member>
- <member name="move_lock_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's Z axis movement.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml
new file mode 100644
index 0000000000..5f9b36f97d
--- /dev/null
+++ b/doc/classes/KinematicBody3D.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="KinematicBody3D" inherits="PhysicsBody3D" version="4.0">
+ <brief_description>
+ Kinematic body 3D node.
+ </brief_description>
+ <description>
+ Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses:
+ [b]Simulated motion:[/b] When these bodies are moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc).
+ [b]Kinematic characters:[/b] KinematicBody3D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
+ </tutorials>
+ <methods>
+ <method name="get_axis_lock" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the specified [code]axis[/code] is locked. See also [member move_lock_x], [member move_lock_y] and [member move_lock_z].
+ </description>
+ </method>
+ <method name="get_floor_normal" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code].
+ </description>
+ </method>
+ <method name="get_floor_velocity" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code].
+ </description>
+ </method>
+ <method name="get_slide_collision">
+ <return type="KinematicCollision3D">
+ </return>
+ <argument index="0" name="slide_idx" type="int">
+ </argument>
+ <description>
+ Returns a [KinematicCollision3D], which contains information about a collision that occurred during the last [method move_and_slide] call. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1).
+ </description>
+ </method>
+ <method name="get_slide_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of times the body collided and changed direction during the last call to [method move_and_slide].
+ </description>
+ </method>
+ <method name="is_on_ceiling" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body is on the ceiling. Only updates when calling [method move_and_slide].
+ </description>
+ </method>
+ <method name="is_on_floor" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body is on the floor. Only updates when calling [method move_and_slide].
+ </description>
+ </method>
+ <method name="is_on_wall" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the body is on a wall. Only updates when calling [method move_and_slide].
+ </description>
+ </method>
+ <method name="move_and_collide">
+ <return type="KinematicCollision3D">
+ </return>
+ <argument index="0" name="rel_vec" type="Vector3">
+ </argument>
+ <argument index="1" name="infinite_inertia" type="bool" default="true">
+ </argument>
+ <argument index="2" name="exclude_raycast_shapes" type="bool" default="true">
+ </argument>
+ <argument index="3" name="test_only" type="bool" default="false">
+ </argument>
+ <description>
+ Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision.
+ If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
+ </description>
+ </method>
+ <method name="move_and_slide">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="linear_velocity" type="Vector3">
+ </argument>
+ <argument index="1" name="up_direction" type="Vector3" default="Vector3( 0, 0, 0 )">
+ </argument>
+ <argument index="2" name="stop_on_slope" type="bool" default="false">
+ </argument>
+ <argument index="3" name="max_slides" type="int" default="4">
+ </argument>
+ <argument index="4" name="floor_max_angle" type="float" default="0.785398">
+ </argument>
+ <argument index="5" name="infinite_inertia" type="bool" default="true">
+ </argument>
+ <description>
+ Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving or rotating platforms, or to make nodes push other nodes.
+ This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
+ [code]linear_velocity[/code] is the velocity vector (typically meters per second). Unlike in [method move_and_collide], you should [i]not[/i] multiply it by [code]delta[/code] — the physics engine handles applying the velocity.
+ [code]up_direction[/code] is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of [code]Vector3(0, 0, 0)[/code], everything is considered a wall.
+ If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on slopes if you include gravity in [code]linear_velocity[/code].
+ If the body collides, it will change direction a maximum of [code]max_slides[/code] times before it stops.
+ [code]floor_max_angle[/code] is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees.
+ If [code]infinite_inertia[/code] is [code]true[/code], body will be able to push [RigidBody3D] nodes, but it won't also detect any collisions with them. If [code]false[/code], it will interact with [RigidBody3D] nodes like with [StaticBody3D].
+ Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
+ </description>
+ </method>
+ <method name="move_and_slide_with_snap">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="linear_velocity" type="Vector3">
+ </argument>
+ <argument index="1" name="snap" type="Vector3">
+ </argument>
+ <argument index="2" name="up_direction" type="Vector3" default="Vector3( 0, 0, 0 )">
+ </argument>
+ <argument index="3" name="stop_on_slope" type="bool" default="false">
+ </argument>
+ <argument index="4" name="max_slides" type="int" default="4">
+ </argument>
+ <argument index="5" name="floor_max_angle" type="float" default="0.785398">
+ </argument>
+ <argument index="6" name="infinite_inertia" type="bool" default="true">
+ </argument>
+ <description>
+ Moves the body while keeping it attached to slopes. Similar to [method move_and_slide].
+ As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code](0, 0, 0)[/code] or by using [method move_and_slide] instead.
+ </description>
+ </method>
+ <method name="set_axis_lock">
+ <return type="void">
+ </return>
+ <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis">
+ </argument>
+ <argument index="1" name="lock" type="bool">
+ </argument>
+ <description>
+ Locks or unlocks the specified [code]axis[/code] depending on the value of [code]lock[/code]. See also [member move_lock_x], [member move_lock_y] and [member move_lock_z].
+ </description>
+ </method>
+ <method name="test_move">
+ <return type="bool">
+ </return>
+ <argument index="0" name="from" type="Transform">
+ </argument>
+ <argument index="1" name="rel_vec" type="Vector3">
+ </argument>
+ <argument index="2" name="infinite_inertia" type="bool" default="true">
+ </argument>
+ <description>
+ Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <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.
+ </member>
+ <member name="move_lock_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's X axis movement.
+ </member>
+ <member name="move_lock_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's Y axis movement.
+ </member>
+ <member name="move_lock_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's Z axis movement.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/KinematicCollision.xml b/doc/classes/KinematicCollision.xml
deleted file mode 100644
index 858a1e69c0..0000000000
--- a/doc/classes/KinematicCollision.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="KinematicCollision" inherits="Reference" version="4.0">
- <brief_description>
- Collision data for [KinematicBody] collisions.
- </brief_description>
- <description>
- Contains collision data for [KinematicBody] collisions. When a [KinematicBody] is moved using [method KinematicBody.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a KinematicCollision object is returned.
- This object contains information about the collision, including the colliding object, the remaining motion, and the collision position. This information can be used to calculate a collision response.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="collider" type="Object" setter="" getter="get_collider">
- The colliding body.
- </member>
- <member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
- The colliding body's unique instance ID. See [method Object.get_instance_id].
- </member>
- <member name="collider_metadata" type="Variant" setter="" getter="get_collider_metadata">
- The colliding body's metadata. See [Object].
- </member>
- <member name="collider_shape" type="Object" setter="" getter="get_collider_shape">
- The colliding body's shape.
- </member>
- <member name="collider_shape_index" type="int" setter="" getter="get_collider_shape_index" default="0">
- The colliding shape's index. See [CollisionObject].
- </member>
- <member name="collider_velocity" type="Vector3" setter="" getter="get_collider_velocity" default="Vector3( 0, 0, 0 )">
- The colliding object's velocity.
- </member>
- <member name="local_shape" type="Object" setter="" getter="get_local_shape">
- The moving object's colliding shape.
- </member>
- <member name="normal" type="Vector3" setter="" getter="get_normal" default="Vector3( 0, 0, 0 )">
- The colliding body's shape's normal at the point of collision.
- </member>
- <member name="position" type="Vector3" setter="" getter="get_position" default="Vector3( 0, 0, 0 )">
- The point of collision, in global coordinates.
- </member>
- <member name="remainder" type="Vector3" setter="" getter="get_remainder" default="Vector3( 0, 0, 0 )">
- The moving object's remaining movement vector.
- </member>
- <member name="travel" type="Vector3" setter="" getter="get_travel" default="Vector3( 0, 0, 0 )">
- The distance the moving object traveled before collision.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/KinematicCollision3D.xml b/doc/classes/KinematicCollision3D.xml
new file mode 100644
index 0000000000..f3248a9ca1
--- /dev/null
+++ b/doc/classes/KinematicCollision3D.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="KinematicCollision3D" inherits="Reference" version="4.0">
+ <brief_description>
+ Collision data for [KinematicBody3D] collisions.
+ </brief_description>
+ <description>
+ Contains collision data for [KinematicBody3D] collisions. When a [KinematicBody3D] is moved using [method KinematicBody3D.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a KinematicCollision3D object is returned.
+ This object contains information about the collision, including the colliding object, the remaining motion, and the collision position. This information can be used to calculate a collision response.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="collider" type="Object" setter="" getter="get_collider">
+ The colliding body.
+ </member>
+ <member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
+ The colliding body's unique instance ID. See [method Object.get_instance_id].
+ </member>
+ <member name="collider_metadata" type="Variant" setter="" getter="get_collider_metadata">
+ The colliding body's metadata. See [Object].
+ </member>
+ <member name="collider_shape" type="Object" setter="" getter="get_collider_shape">
+ The colliding body's shape.
+ </member>
+ <member name="collider_shape_index" type="int" setter="" getter="get_collider_shape_index" default="0">
+ The colliding shape's index. See [CollisionObject3D].
+ </member>
+ <member name="collider_velocity" type="Vector3" setter="" getter="get_collider_velocity" default="Vector3( 0, 0, 0 )">
+ The colliding object's velocity.
+ </member>
+ <member name="local_shape" type="Object" setter="" getter="get_local_shape">
+ The moving object's colliding shape.
+ </member>
+ <member name="normal" type="Vector3" setter="" getter="get_normal" default="Vector3( 0, 0, 0 )">
+ The colliding body's shape's normal at the point of collision.
+ </member>
+ <member name="position" type="Vector3" setter="" getter="get_position" default="Vector3( 0, 0, 0 )">
+ The point of collision, in global coordinates.
+ </member>
+ <member name="remainder" type="Vector3" setter="" getter="get_remainder" default="Vector3( 0, 0, 0 )">
+ The moving object's remaining movement vector.
+ </member>
+ <member name="travel" type="Vector3" setter="" getter="get_travel" default="Vector3( 0, 0, 0 )">
+ The distance the moving object traveled before collision.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Light.xml b/doc/classes/Light.xml
deleted file mode 100644
index a2867a50d2..0000000000
--- a/doc/classes/Light.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Light" inherits="VisualInstance" version="4.0">
- <brief_description>
- Provides a base class for different kinds of light nodes.
- </brief_description>
- <description>
- Light is the abstract base class for light nodes, so it shouldn't be used directly (it can't be instanced). Other types of light nodes inherit from it. Light contains the common variables and parameters used for lighting.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
- </tutorials>
- <methods>
- <method name="get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="Light.Param">
- </argument>
- <description>
- Returns the value of the specified [enum Light.Param] parameter.
- </description>
- </method>
- <method name="set_param">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="Light.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- Sets the value of the specified [enum Light.Param] parameter.
- </description>
- </method>
- </methods>
- <members>
- <member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false">
- If [code]true[/code], the light only appears in the editor and will not be visible at runtime.
- </member>
- <member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light.BakeMode" default="1">
- The light's bake mode. See [enum BakeMode].
- </member>
- <member name="light_color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )">
- The light's color.
- </member>
- <member name="light_cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
- The light will affect objects in the selected layers.
- </member>
- <member name="light_energy" type="float" setter="set_param" getter="get_param" default="1.0">
- The light's strength multiplier.
- </member>
- <member name="light_indirect_energy" type="float" setter="set_param" getter="get_param" default="1.0">
- Secondary multiplier used with indirect light (light bounces). Used with [GIProbe].
- </member>
- <member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false">
- If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
- </member>
- <member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
- The intensity of the specular blob in objects affected by the light. At [code]0[/code] the light becomes a pure diffuse light.
- </member>
- <member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.15">
- Used to adjust shadow appearance. Too small a value results in self-shadowing, while too large a value causes shadows to separate from casters. Adjust as needed.
- </member>
- <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 1 )">
- The color of shadows cast by this light.
- </member>
- <member name="shadow_contact" type="float" setter="set_param" getter="get_param" default="0.0">
- Attempts to reduce [member shadow_bias] gap.
- </member>
- <member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false">
- If [code]true[/code], the light will cast shadows.
- </member>
- <member name="shadow_reverse_cull_face" type="bool" setter="set_shadow_reverse_cull_face" getter="get_shadow_reverse_cull_face" default="false">
- 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 [constant GeometryInstance.SHADOW_CASTING_SETTING_DOUBLE_SIDED].
- </member>
- </members>
- <constants>
- <constant name="PARAM_ENERGY" value="0" enum="Param">
- Constant for accessing [member light_energy].
- </constant>
- <constant name="PARAM_INDIRECT_ENERGY" value="1" enum="Param">
- Constant for accessing [member light_indirect_energy].
- </constant>
- <constant name="PARAM_SPECULAR" value="2" enum="Param">
- Constant for accessing [member light_specular].
- </constant>
- <constant name="PARAM_RANGE" value="3" enum="Param">
- Constant for accessing [member OmniLight.omni_range] or [member SpotLight.spot_range].
- </constant>
- <constant name="PARAM_ATTENUATION" value="4" enum="Param">
- Constant for accessing [member OmniLight.omni_attenuation] or [member SpotLight.spot_attenuation].
- </constant>
- <constant name="PARAM_SPOT_ANGLE" value="5" enum="Param">
- Constant for accessing [member SpotLight.spot_angle].
- </constant>
- <constant name="PARAM_SPOT_ATTENUATION" value="6" enum="Param">
- Constant for accessing [member SpotLight.spot_angle_attenuation].
- </constant>
- <constant name="PARAM_CONTACT_SHADOW_SIZE" value="7" enum="Param">
- Constant for accessing [member shadow_contact].
- </constant>
- <constant name="PARAM_SHADOW_MAX_DISTANCE" value="8" enum="Param">
- Constant for accessing [member DirectionalLight.directional_shadow_max_distance].
- </constant>
- <constant name="PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="Param">
- Constant for accessing [member DirectionalLight.directional_shadow_split_1].
- </constant>
- <constant name="PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="Param">
- Constant for accessing [member DirectionalLight.directional_shadow_split_2].
- </constant>
- <constant name="PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="Param">
- Constant for accessing [member DirectionalLight.directional_shadow_split_3].
- </constant>
- <constant name="PARAM_SHADOW_FADE_START" value="12" enum="Param">
- </constant>
- <constant name="PARAM_SHADOW_NORMAL_BIAS" value="13" enum="Param">
- Constant for accessing [member DirectionalLight.directional_shadow_normal_bias].
- </constant>
- <constant name="PARAM_SHADOW_BIAS" value="14" enum="Param">
- Constant for accessing [member shadow_bias].
- </constant>
- <constant name="PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="Param">
- Constant for accessing [member DirectionalLight.directional_shadow_bias_split_scale].
- </constant>
- <constant name="PARAM_MAX" value="16" enum="Param">
- Represents the size of the [enum Param] enum.
- </constant>
- <constant name="BAKE_DISABLED" value="0" enum="BakeMode">
- Light is ignored when baking.
- [b]Note:[/b] Hiding a light does [i]not[/i] affect baking.
- </constant>
- <constant name="BAKE_INDIRECT" value="1" enum="BakeMode">
- Only indirect lighting will be baked (default).
- </constant>
- <constant name="BAKE_ALL" value="2" enum="BakeMode">
- Both direct and indirect light will be baked.
- [b]Note:[/b] You should hide the light if you don't want it to appear twice (dynamic and baked).
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
new file mode 100644
index 0000000000..623b2a2bb0
--- /dev/null
+++ b/doc/classes/Light3D.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Light3D" inherits="VisualInstance3D" version="4.0">
+ <brief_description>
+ Provides a base class for different kinds of light nodes.
+ </brief_description>
+ <description>
+ Light3D is the abstract base class for light nodes, so it shouldn't be used directly (it can't be instanced). Other types of light nodes inherit from it. Light3D contains the common variables and parameters used for lighting.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ </tutorials>
+ <methods>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="Light3D.Param">
+ </argument>
+ <description>
+ Returns the value of the specified [enum Light3D.Param] parameter.
+ </description>
+ </method>
+ <method name="set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="Light3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ Sets the value of the specified [enum Light3D.Param] parameter.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false">
+ If [code]true[/code], the light only appears in the editor and will not be visible at runtime.
+ </member>
+ <member name="light_angular_distance" type="float" setter="set_param" getter="get_param" default="0.0">
+ Angular size of the light in degrees. Only available for [DirectionalLight3D]s. For reference, the sun from earth is approximately [code]0.5[/code].
+ </member>
+ <member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="1">
+ The light's bake mode. See [enum BakeMode].
+ </member>
+ <member name="light_color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )">
+ The light's color.
+ </member>
+ <member name="light_cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
+ The light will affect objects in the selected layers.
+ </member>
+ <member name="light_energy" type="float" setter="set_param" getter="get_param" default="1.0">
+ The light's strength multiplier.
+ </member>
+ <member name="light_indirect_energy" type="float" setter="set_param" getter="get_param" default="1.0">
+ Secondary multiplier used with indirect light (light bounces). Used with [GIProbe].
+ </member>
+ <member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false">
+ If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
+ </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.
+ </member>
+ <member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
+ The intensity of the specular blob in objects affected by the light. At [code]0[/code] the light becomes a pure diffuse light.
+ </member>
+ <member name="shadow_bias" type="float" setter="set_param" getter="get_param" default="0.15">
+ Used to adjust shadow appearance. Too small a value results in self-shadowing, while too large a value causes shadows to separate from casters. Adjust as needed.
+ </member>
+ <member name="shadow_blur" type="float" setter="set_param" getter="get_param" default="1.0">
+ Blurs the edges of the shadow. Can be used to hide pixel artifacts in low resolution shadow maps. A high value can make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible.
+ </member>
+ <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 1 )">
+ The color of shadows cast by this light.
+ </member>
+ <member name="shadow_contact" type="float" setter="set_param" getter="get_param" default="0.0">
+ Attempts to reduce [member shadow_bias] gap.
+ </member>
+ <member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false">
+ If [code]true[/code], the light will cast shadows.
+ </member>
+ <member name="shadow_reverse_cull_face" type="bool" setter="set_shadow_reverse_cull_face" getter="get_shadow_reverse_cull_face" default="false">
+ 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 [constant GeometryInstance3D.SHADOW_CASTING_SETTING_DOUBLE_SIDED].
+ </member>
+ </members>
+ <constants>
+ <constant name="PARAM_ENERGY" value="0" enum="Param">
+ Constant for accessing [member light_energy].
+ </constant>
+ <constant name="PARAM_INDIRECT_ENERGY" value="1" enum="Param">
+ Constant for accessing [member light_indirect_energy].
+ </constant>
+ <constant name="PARAM_SPECULAR" value="2" enum="Param">
+ Constant for accessing [member light_specular].
+ </constant>
+ <constant name="PARAM_RANGE" value="3" enum="Param">
+ Constant for accessing [member OmniLight3D.omni_range] or [member SpotLight3D.spot_range].
+ </constant>
+ <constant name="PARAM_ATTENUATION" value="4" enum="Param">
+ Constant for accessing [member OmniLight3D.omni_attenuation] or [member SpotLight3D.spot_attenuation].
+ </constant>
+ <constant name="PARAM_SPOT_ANGLE" value="5" enum="Param">
+ Constant for accessing [member SpotLight3D.spot_angle].
+ </constant>
+ <constant name="PARAM_SPOT_ATTENUATION" value="6" enum="Param">
+ Constant for accessing [member SpotLight3D.spot_angle_attenuation].
+ </constant>
+ <constant name="PARAM_CONTACT_SHADOW_SIZE" value="7" enum="Param">
+ Constant for accessing [member shadow_contact].
+ </constant>
+ <constant name="PARAM_SHADOW_MAX_DISTANCE" value="8" enum="Param">
+ Constant for accessing [member DirectionalLight3D.directional_shadow_max_distance].
+ </constant>
+ <constant name="PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="Param">
+ Constant for accessing [member DirectionalLight3D.directional_shadow_split_1].
+ </constant>
+ <constant name="PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="Param">
+ Constant for accessing [member DirectionalLight3D.directional_shadow_split_2].
+ </constant>
+ <constant name="PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="Param">
+ Constant for accessing [member DirectionalLight3D.directional_shadow_split_3].
+ </constant>
+ <constant name="PARAM_SHADOW_FADE_START" value="12" enum="Param">
+ </constant>
+ <constant name="PARAM_SHADOW_NORMAL_BIAS" value="13" enum="Param">
+ Constant for accessing [member DirectionalLight3D.directional_shadow_normal_bias].
+ </constant>
+ <constant name="PARAM_SHADOW_BIAS" value="14" enum="Param">
+ Constant for accessing [member shadow_bias].
+ </constant>
+ <constant name="PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="Param">
+ Constant for accessing [member DirectionalLight3D.directional_shadow_bias_split_scale].
+ </constant>
+ <constant name="PARAM_MAX" value="16" enum="Param">
+ Represents the size of the [enum Param] enum.
+ </constant>
+ <constant name="BAKE_DISABLED" value="0" enum="BakeMode">
+ Light is ignored when baking.
+ [b]Note:[/b] Hiding a light does [i]not[/i] affect baking.
+ </constant>
+ <constant name="BAKE_INDIRECT" value="1" enum="BakeMode">
+ Only indirect lighting will be baked (default).
+ </constant>
+ <constant name="BAKE_ALL" value="2" enum="BakeMode">
+ Both direct and indirect light will be baked.
+ [b]Note:[/b] You should hide the light if you don't want it to appear twice (dynamic and baked).
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Listener.xml b/doc/classes/Listener.xml
deleted file mode 100644
index 72bbfa29d4..0000000000
--- a/doc/classes/Listener.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Listener" inherits="Spatial" version="4.0">
- <brief_description>
- Overrides the location sounds are heard from.
- </brief_description>
- <description>
- Once added to the scene tree and enabled using [method make_current], this node will override the location sounds are heard from. This can be used to listen from a location different from the [Camera].
- [b]Note:[/b] There is no 2D equivalent for this node yet.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="clear_current">
- <return type="void">
- </return>
- <description>
- Disables the listener to use the current camera's listener instead.
- </description>
- </method>
- <method name="get_listener_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <description>
- Returns the listener's global orthonormalized [Transform].
- </description>
- </method>
- <method name="is_current" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the listener was made current using [method make_current], [code]false[/code] otherwise.
- [b]Note:[/b] There may be more than one Listener marked as "current" in the scene tree, but only the one that was made current last will be used.
- </description>
- </method>
- <method name="make_current">
- <return type="void">
- </return>
- <description>
- Enables the listener. This will override the current camera's listener.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Listener3D.xml b/doc/classes/Listener3D.xml
new file mode 100644
index 0000000000..998ea757ff
--- /dev/null
+++ b/doc/classes/Listener3D.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Listener3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Overrides the location sounds are heard from.
+ </brief_description>
+ <description>
+ Once added to the scene tree and enabled using [method make_current], this node will override the location sounds are heard from. This can be used to listen from a location different from the [Camera3D].
+ [b]Note:[/b] There is no 2D equivalent for this node yet.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="clear_current">
+ <return type="void">
+ </return>
+ <description>
+ Disables the listener to use the current camera's listener instead.
+ </description>
+ </method>
+ <method name="get_listener_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <description>
+ Returns the listener's global orthonormalized [Transform].
+ </description>
+ </method>
+ <method name="is_current" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the listener was made current using [method make_current], [code]false[/code] otherwise.
+ [b]Note:[/b] There may be more than one Listener3D marked as "current" in the scene tree, but only the one that was made current last will be used.
+ </description>
+ </method>
+ <method name="make_current">
+ <return type="void">
+ </return>
+ <description>
+ Enables the listener. This will override the current camera's listener.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml
index af71c30936..7bb478fce2 100644
--- a/doc/classes/MainLoop.xml
+++ b/doc/classes/MainLoop.xml
@@ -7,6 +7,7 @@
[MainLoop] is the abstract base class for a Godot project's game loop. It is inherited by [SceneTree], which is the default game loop implementation used in Godot projects, though it is also possible to write and use one's own [MainLoop] subclass instead of the scene tree.
Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a main [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code], which should then be a [MainLoop] implementation.
Here is an example script implementing a simple [MainLoop]:
+ [b]FIXME:[/b] No longer valid after DisplayServer split and Input refactoring.
[codeblock]
extends MainLoop
@@ -43,17 +44,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="_drop_files" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="files" type="PackedStringArray">
- </argument>
- <argument index="1" name="from_screen" type="int">
- </argument>
- <description>
- Called when files are dragged from the OS file manager and dropped in the game window. The arguments are a list of file paths and the identifier of the screen where the drag originated.
- </description>
- </method>
<method name="_finalize" qualifiers="virtual">
<return type="void">
</return>
@@ -61,17 +51,6 @@
Called before the program exits.
</description>
</method>
- <method name="_global_menu_action" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="id" type="Variant">
- </argument>
- <argument index="1" name="meta" type="Variant">
- </argument>
- <description>
- Called when the user performs an action in the system global menu (e.g. the Mac OS menu bar).
- </description>
- </method>
<method name="_idle" qualifiers="virtual">
<return type="bool">
</return>
@@ -89,24 +68,6 @@
Called once during initialization.
</description>
</method>
- <method name="_input_event" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="event" type="InputEvent">
- </argument>
- <description>
- Called whenever an [InputEvent] is received by the main loop.
- </description>
- </method>
- <method name="_input_text" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Deprecated callback, does not do anything. Use [method _input_event] to parse text input. Will be removed in Godot 4.0.
- </description>
- </method>
<method name="_iteration" qualifiers="virtual">
<return type="bool">
</return>
@@ -140,24 +101,6 @@
Should not be called manually, override [method _initialize] instead. Will be removed in Godot 4.0.
</description>
</method>
- <method name="input_event">
- <return type="void">
- </return>
- <argument index="0" name="event" type="InputEvent">
- </argument>
- <description>
- Should not be called manually, override [method _input_event] instead. Will be removed in Godot 4.0.
- </description>
- </method>
- <method name="input_text">
- <return type="void">
- </return>
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Should not be called manually, override [method _input_text] instead. Will be removed in Godot 4.0.
- </description>
- </method>
<method name="iteration">
<return type="bool">
</return>
@@ -180,58 +123,30 @@
</signal>
</signals>
<constants>
- <constant name="NOTIFICATION_WM_MOUSE_ENTER" value="1002">
- Notification received from the OS when the mouse enters the game window.
- Implemented on desktop and web platforms.
- </constant>
- <constant name="NOTIFICATION_WM_MOUSE_EXIT" value="1003">
- Notification received from the OS when the mouse leaves the game window.
- Implemented on desktop and web platforms.
- </constant>
- <constant name="NOTIFICATION_WM_FOCUS_IN" value="1004">
- Notification received from the OS when the game window is focused.
- Implemented on all platforms.
- </constant>
- <constant name="NOTIFICATION_WM_FOCUS_OUT" value="1005">
- Notification received from the OS when the game window is unfocused.
- Implemented on all platforms.
- </constant>
- <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="1006">
- Notification received from the OS when a quit request is sent (e.g. closing the window with a "Close" button or Alt+F4).
- Implemented on desktop platforms.
- </constant>
- <constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007">
- Notification received from the OS when a go back request is sent (e.g. pressing the "Back" button on Android).
- Specific to the Android platform.
- </constant>
- <constant name="NOTIFICATION_WM_UNFOCUS_REQUEST" value="1008">
- Notification received from the OS when an unfocus request is sent (e.g. another OS window wants to take the focus).
- No supported platforms currently send this notification.
- </constant>
- <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="1009">
+ <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="2009">
Notification received from the OS when the application is exceeding its allocated memory.
Specific to the iOS platform.
</constant>
- <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="1010">
+ <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="2010">
Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr].
</constant>
- <constant name="NOTIFICATION_WM_ABOUT" value="1011">
+ <constant name="NOTIFICATION_WM_ABOUT" value="2011">
Notification received from the OS when a request for "About" information is sent.
Specific to the macOS platform.
</constant>
- <constant name="NOTIFICATION_CRASH" value="1012">
+ <constant name="NOTIFICATION_CRASH" value="2012">
Notification received from Godot's crash handler when the engine is about to crash.
Implemented on desktop platforms if the crash handler is enabled.
</constant>
- <constant name="NOTIFICATION_OS_IME_UPDATE" value="1013">
+ <constant name="NOTIFICATION_OS_IME_UPDATE" value="2013">
Notification received from the OS when an update of the Input Method Engine occurs (e.g. change of IME cursor position or composition string).
Specific to the macOS platform.
</constant>
- <constant name="NOTIFICATION_APP_RESUMED" value="1014">
+ <constant name="NOTIFICATION_APP_RESUMED" value="2014">
Notification received from the OS when the app is resumed.
Specific to the Android platform.
</constant>
- <constant name="NOTIFICATION_APP_PAUSED" value="1015">
+ <constant name="NOTIFICATION_APP_PAUSED" value="2015">
Notification received from the OS when the app is paused.
Specific to the Android platform.
</constant>
diff --git a/doc/classes/Material.xml b/doc/classes/Material.xml
index a0c1979646..a37c8127f0 100644
--- a/doc/classes/Material.xml
+++ b/doc/classes/Material.xml
@@ -4,7 +4,7 @@
Abstract base [Resource] for coloring and shading geometry.
</brief_description>
<description>
- Material is a base [Resource] used for coloring and shading geometry. All materials inherit from it and almost all [VisualInstance] derived nodes carry a Material. A few flags and parameters are shared between all material types and are configured here.
+ Material is a base [Resource] used for coloring and shading geometry. All materials inherit from it and almost all [VisualInstance3D] derived nodes carry a Material. A few flags and parameters are shared between all material types and are configured here.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index 6ec9d60df4..316315f777 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -38,9 +38,9 @@
<member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode" override="true" default="true" />
</members>
<signals>
- <signal name="about_to_show">
+ <signal name="about_to_popup">
<description>
- Emitted when [PopupMenu] of this MenuButton is about to show.
+ Emitted when the [PopupMenu] of this MenuButton is about to show.
</description>
</signal>
</signals>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index dc7ffc8934..6958c815a6 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -10,10 +10,10 @@
</tutorials>
<methods>
<method name="create_convex_shape" qualifiers="const">
- <return type="Shape">
+ <return type="Shape3D">
</return>
<description>
- Calculate a [ConvexPolygonShape] from the mesh.
+ Calculate a [ConvexPolygonShape3D] from the mesh.
</description>
</method>
<method name="create_outline" qualifiers="const">
@@ -27,10 +27,10 @@
</description>
</method>
<method name="create_trimesh_shape" qualifiers="const">
- <return type="Shape">
+ <return type="Shape3D">
</return>
<description>
- Calculate a [ConcavePolygonShape] from the mesh.
+ Calculate a [ConcavePolygonShape3D] from the mesh.
</description>
</method>
<method name="generate_triangle_mesh" qualifiers="const">
diff --git a/doc/classes/MeshInstance.xml b/doc/classes/MeshInstance.xml
deleted file mode 100644
index 6123dfa37a..0000000000
--- a/doc/classes/MeshInstance.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MeshInstance" inherits="GeometryInstance" version="4.0">
- <brief_description>
- Node that instances meshes into a scenario.
- </brief_description>
- <description>
- MeshInstance is a node that takes a [Mesh] resource and adds it to the current scenario by creating an instance of it. This is the class most often used to get 3D geometry rendered and can be used to instance a single [Mesh] in many places. This allows to reuse geometry and save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance] instead.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="create_convex_collision">
- <return type="void">
- </return>
- <description>
- This helper creates a [StaticBody] child node with a [ConvexPolygonShape] collision shape calculated from the mesh geometry. It's mainly used for testing.
- </description>
- </method>
- <method name="create_debug_tangents">
- <return type="void">
- </return>
- <description>
- This helper creates a [MeshInstance] child node with gizmos at every vertex calculated from the mesh geometry. It's mainly used for testing.
- </description>
- </method>
- <method name="create_trimesh_collision">
- <return type="void">
- </return>
- <description>
- This helper creates a [StaticBody] child node with a [ConcavePolygonShape] collision shape calculated from the mesh geometry. It's mainly used for testing.
- </description>
- </method>
- <method name="get_surface_material" qualifiers="const">
- <return type="Material">
- </return>
- <argument index="0" name="surface" type="int">
- </argument>
- <description>
- Returns the [Material] for a surface of the [Mesh] resource.
- </description>
- </method>
- <method name="get_surface_material_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of surface materials.
- </description>
- </method>
- <method name="set_surface_material">
- <return type="void">
- </return>
- <argument index="0" name="surface" type="int">
- </argument>
- <argument index="1" name="material" type="Material">
- </argument>
- <description>
- Sets the [Material] for a surface of the [Mesh] resource.
- </description>
- </method>
- </methods>
- <members>
- <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
- The [Mesh] resource for the instance.
- </member>
- <member name="skeleton" type="NodePath" setter="set_skeleton_path" getter="get_skeleton_path" default="NodePath(&quot;..&quot;)">
- [NodePath] to the [Skeleton] associated with the instance.
- </member>
- <member name="skin" type="Skin" setter="set_skin" getter="get_skin">
- Sets the skin to be used by this instance.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/MeshInstance2D.xml b/doc/classes/MeshInstance2D.xml
index 2781dd4626..0cfc8deb0a 100644
--- a/doc/classes/MeshInstance2D.xml
+++ b/doc/classes/MeshInstance2D.xml
@@ -4,7 +4,7 @@
Node used for displaying a [Mesh] in 2D.
</brief_description>
<description>
- Node used for displaying a [Mesh] in 2D. Can be constructed from an existing [Sprite] via a tool in the editor toolbar. Select "Sprite" then "Convert to Mesh2D", select settings in popup and press "Create Mesh2D".
+ Node used for displaying a [Mesh] in 2D. Can be constructed from an existing [Sprite2D] via a tool in the editor toolbar. Select "Sprite2D" then "Convert to Mesh2D", select settings in popup and press "Create Mesh2D".
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_meshes.html</link>
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
new file mode 100644
index 0000000000..c569da2df1
--- /dev/null
+++ b/doc/classes/MeshInstance3D.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="MeshInstance3D" inherits="GeometryInstance3D" version="4.0">
+ <brief_description>
+ Node that instances meshes into a scenario.
+ </brief_description>
+ <description>
+ MeshInstance3D is a node that takes a [Mesh] resource and adds it to the current scenario by creating an instance of it. This is the class most often used render 3D geometry and can be used to instance a single [Mesh] in many places. This allows reuse of geometry which can save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance3D] instead.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="create_convex_collision">
+ <return type="void">
+ </return>
+ <description>
+ This helper creates a [StaticBody3D] child node with a [ConvexPolygonShape3D] collision shape calculated from the mesh geometry. It's mainly used for testing.
+ </description>
+ </method>
+ <method name="create_debug_tangents">
+ <return type="void">
+ </return>
+ <description>
+ 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_trimesh_collision">
+ <return type="void">
+ </return>
+ <description>
+ This helper creates a [StaticBody3D] child node with a [ConcavePolygonShape3D] collision shape calculated from the mesh geometry. It's mainly used for testing.
+ </description>
+ </method>
+ <method name="get_active_material" qualifiers="const">
+ <return type="Material">
+ </return>
+ <argument index="0" name="surface" type="int">
+ </argument>
+ <description>
+ 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">
+ <return type="Material">
+ </return>
+ <argument index="0" name="surface" type="int">
+ </argument>
+ <description>
+ Returns the override [Material] for the specified surface of the [Mesh] resource.
+ </description>
+ </method>
+ <method name="get_surface_material_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of surface materials.
+ </description>
+ </method>
+ <method name="set_surface_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="surface" type="int">
+ </argument>
+ <argument index="1" name="material" type="Material">
+ </argument>
+ <description>
+ Sets the override [Material] for the specified surface of the [Mesh] resource. This material is associated with this [MeshInstance3D] rather than with the [Mesh] resource.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
+ The [Mesh] resource for the instance.
+ </member>
+ <member name="skeleton" type="NodePath" setter="set_skeleton_path" getter="get_skeleton_path" default="NodePath(&quot;..&quot;)">
+ [NodePath] to the [Skeleton3D] associated with the instance.
+ </member>
+ <member name="skin" type="Skin" setter="set_skin" getter="get_skin">
+ Sets the skin to be used by this instance.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml
index a96f6d7231..ccf6172017 100644
--- a/doc/classes/MeshLibrary.xml
+++ b/doc/classes/MeshLibrary.xml
@@ -94,7 +94,7 @@
</argument>
<description>
Returns an item's collision shapes.
- The array consists of each [Shape] followed by its [Transform].
+ The array consists of each [Shape3D] followed by its [Transform].
</description>
</method>
<method name="get_last_unused_item_id" qualifiers="const">
@@ -178,7 +178,7 @@
</argument>
<description>
Sets an item's collision shapes.
- The array should consist of [Shape] objects, each followed by a [Transform] that will be applied to it. For shapes that should not have a transform, use [constant Transform.IDENTITY].
+ The array should consist of [Shape3D] objects, each followed by a [Transform] that will be applied to it. For shapes that should not have a transform, use [constant Transform.IDENTITY].
</description>
</method>
</methods>
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 24b87f8e28..0f56ab4b95 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -4,7 +4,7 @@
Provides high-performance mesh instancing.
</brief_description>
<description>
- MultiMesh provides low-level mesh instancing. Drawing thousands of [MeshInstance] nodes can be slow, since each object is submitted to the GPU then drawn individually.
+ 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).
Since instances may have any behavior, the AABB used for visibility must be provided by the user.
@@ -125,8 +125,10 @@
Format of transform used to transform mesh, either 2D or 3D.
</member>
<member name="use_colors" type="bool" setter="set_use_colors" getter="is_using_colors" default="false">
+ If [code]true[/code], the [MultiMesh] will use color data (see [member color_array]).
</member>
<member name="use_custom_data" type="bool" setter="set_use_custom_data" getter="is_using_custom_data" default="false">
+ If [code]true[/code], the [MultiMesh] will use custom data (see [member custom_data_array]).
</member>
<member name="visible_instance_count" type="int" setter="set_visible_instance_count" getter="get_visible_instance_count" default="-1">
Limits the number of instances drawn, -1 draws all instances. Changing this does not change the sizes of the buffers.
diff --git a/doc/classes/MultiMeshInstance.xml b/doc/classes/MultiMeshInstance.xml
deleted file mode 100644
index 6cbc0a8e04..0000000000
--- a/doc/classes/MultiMeshInstance.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiMeshInstance" inherits="GeometryInstance" version="4.0">
- <brief_description>
- Node that instances a [MultiMesh].
- </brief_description>
- <description>
- [MultiMeshInstance] is a specialized node to instance [GeometryInstance]s based on a [MultiMesh] resource.
- This is useful to optimize the rendering of a high amount of instances of a given mesh (for example trees in a forest or grass strands).
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/animating_thousands_of_fish.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_multi_mesh_instance.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_multimesh.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="multimesh" type="MultiMesh" setter="set_multimesh" getter="get_multimesh">
- The [MultiMesh] resource that will be used and shared among all instances of the [MultiMeshInstance].
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/MultiMeshInstance2D.xml b/doc/classes/MultiMeshInstance2D.xml
index 2fe5447a27..07f21514ef 100644
--- a/doc/classes/MultiMeshInstance2D.xml
+++ b/doc/classes/MultiMeshInstance2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
[MultiMeshInstance2D] is a specialized node to instance a [MultiMesh] resource in 2D.
- Usage is the same as [MultiMeshInstance].
+ Usage is the same as [MultiMeshInstance3D].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/MultiMeshInstance3D.xml b/doc/classes/MultiMeshInstance3D.xml
new file mode 100644
index 0000000000..cab17c952e
--- /dev/null
+++ b/doc/classes/MultiMeshInstance3D.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="MultiMeshInstance3D" inherits="GeometryInstance3D" version="4.0">
+ <brief_description>
+ Node that instances a [MultiMesh].
+ </brief_description>
+ <description>
+ [MultiMeshInstance3D] is a specialized node to instance [GeometryInstance3D]s based on a [MultiMesh] resource.
+ This is useful to optimize the rendering of a high amount of instances of a given mesh (for example trees in a forest or grass strands).
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/animating_thousands_of_fish.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_multi_mesh_instance.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_multimesh.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="multimesh" type="MultiMesh" setter="set_multimesh" getter="get_multimesh">
+ The [MultiMesh] resource that will be used and shared among all instances of the [MultiMeshInstance3D].
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Navigation.xml b/doc/classes/Navigation.xml
deleted file mode 100644
index 93170bca4a..0000000000
--- a/doc/classes/Navigation.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Navigation" inherits="Spatial" 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 [NavigationRegion] nodes. In addition to basic pathfinding, this class also assists with aligning navigation agents with the meshes they are navigating on.
- </description>
- <tutorials>
- </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/Navigation2DServer.xml b/doc/classes/Navigation2DServer.xml
deleted file mode 100644
index 110844c492..0000000000
--- a/doc/classes/Navigation2DServer.xml
+++ /dev/null
@@ -1,298 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Navigation2DServer" inherits="Object" version="4.0">
- <brief_description>
- Server interface for low-level 2D navigation access
- </brief_description>
- <description>
- Navigation2DServer 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.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="agent_create" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Creates the agent.
- </description>
- </method>
- <method name="agent_is_map_changed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <description>
- Returns true if the map got changed the previous frame.
- </description>
- </method>
- <method name="agent_set_callback" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
- </argument>
- <argument index="3" name="userdata" type="Variant" default="null">
- </argument>
- <description>
- Callback called at the end of the RVO process.
- </description>
- </method>
- <method name="agent_set_map" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="map" type="RID">
- </argument>
- <description>
- Puts the agent in the map.
- </description>
- </method>
- <method name="agent_set_max_neighbors" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="count" type="int">
- </argument>
- <description>
- Sets the maximum number of other agents the agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
- </description>
- </method>
- <method name="agent_set_max_speed" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="max_speed" type="float">
- </argument>
- <description>
- Sets the maximum speed of the agent. Must be positive.
- </description>
- </method>
- <method name="agent_set_neighbor_dist" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="dist" type="float">
- </argument>
- <description>
- Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
- </description>
- </method>
- <method name="agent_set_position" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="position" type="Vector2">
- </argument>
- <description>
- Sets the position of the agent in world space.
- </description>
- </method>
- <method name="agent_set_radius" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="radius" type="float">
- </argument>
- <description>
- Sets the radius of the agent.
- </description>
- </method>
- <method name="agent_set_target_velocity" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="target_velocity" type="Vector2">
- </argument>
- <description>
- Sets the new target velocity.
- </description>
- </method>
- <method name="agent_set_time_horizon" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="time" type="float">
- </argument>
- <description>
- The minimal amount of time for which the agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
- </description>
- </method>
- <method name="agent_set_velocity" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="velocity" type="Vector2">
- </argument>
- <description>
- Sets the current velocity of the agent.
- </description>
- </method>
- <method name="free" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="object" type="RID">
- </argument>
- <description>
- Destroy the RID
- </description>
- </method>
- <method name="map_create" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Create a new map.
- </description>
- </method>
- <method name="map_get_cell_size" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <description>
- Returns the map cell size.
- </description>
- </method>
- <method name="map_get_closest_point" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" 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="map_get_closest_point_owner" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="to_point" type="Vector2">
- </argument>
- <description>
- Returns the owner region RID for the point returned by [method map_get_closest_point].
- </description>
- </method>
- <method name="map_get_edge_connection_margin" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <description>
- Returns the edge connection margin of the map. The edge connection margin is a distance used to connect two regions.
- </description>
- </method>
- <method name="map_get_path" qualifiers="const">
- <return type="PackedVector2Array">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="origin" type="Vector2">
- </argument>
- <argument index="2" name="destination" type="Vector2">
- </argument>
- <argument index="3" name="optimize" type="bool">
- </argument>
- <description>
- Returns the navigation path to reach the destination from the origin, while avoiding static obstacles.
- </description>
- </method>
- <method name="map_is_active" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="nap" type="RID">
- </argument>
- <description>
- Returns true if the map is active.
- </description>
- </method>
- <method name="map_set_active" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="active" type="bool">
- </argument>
- <description>
- Sets the map active.
- </description>
- </method>
- <method name="map_set_cell_size" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="cell_size" type="float">
- </argument>
- <description>
- Set the map cell size used to weld the navigation mesh polygons.
- </description>
- </method>
- <method name="map_set_edge_connection_margin" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="margin" type="float">
- </argument>
- <description>
- Set the map edge connection margin used to weld the compatible region edges.
- </description>
- </method>
- <method name="region_create" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Creates a new region.
- </description>
- </method>
- <method name="region_set_map" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="region" type="RID">
- </argument>
- <argument index="1" name="map" type="RID">
- </argument>
- <description>
- Sets the map for the region.
- </description>
- </method>
- <method name="region_set_navpoly" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="region" type="RID">
- </argument>
- <argument index="1" name="nav_poly" type="NavigationPolygon">
- </argument>
- <description>
- Sets the navigation mesh for the region.
- </description>
- </method>
- <method name="region_set_transform" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="region" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the global transformation for the region.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Navigation3D.xml b/doc/classes/Navigation3D.xml
new file mode 100644
index 0000000000..807f0ad309
--- /dev/null
+++ b/doc/classes/Navigation3D.xml
@@ -0,0 +1,83 @@
+<?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>
+ </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/NavigationAgent.xml b/doc/classes/NavigationAgent.xml
deleted file mode 100644
index c6c9abec13..0000000000
--- a/doc/classes/NavigationAgent.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationAgent" inherits="Node" version="4.0">
- <brief_description>
- 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 [Navigation] node, or using [method set_navigation]. [NavigationAgent] is physics safe.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="distance_to_target" qualifiers="const">
- <return type="float">
- </return>
- <description>
- Returns the distance to the target location, using the agent's global position. The user must set the target location with [method set_target_location] in order for this to be accurate.
- </description>
- </method>
- <method name="get_final_location">
- <return type="Vector3">
- </return>
- <description>
- Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
- </description>
- </method>
- <method name="get_nav_path" qualifiers="const">
- <return type="PackedVector3Array">
- </return>
- <description>
- Returns the path from start to finish in global coordinates.
- </description>
- </method>
- <method name="get_nav_path_index" qualifiers="const">
- <return type="int">
- </return>
- <description>
- 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">
- </return>
- <description>
- Returns the [Navigation] node that the agent is using for its navigation system.
- </description>
- </method>
- <method name="get_next_location">
- <return type="Vector3">
- </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">
- <return type="Vector3">
- </return>
- <description>
- Returns the user defined [Vector3] after setting the target location.
- </description>
- </method>
- <method name="is_navigation_finished">
- <return type="bool">
- </return>
- <description>
- Returns true if the navigation path's final location has been reached.
- </description>
- </method>
- <method name="is_target_reachable">
- <return type="bool">
- </return>
- <description>
- Returns true if the target location is reachable. The target location is set using [method set_target_location].
- </description>
- </method>
- <method name="is_target_reached" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- 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 [Navigation] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation] node.
- </description>
- </method>
- <method name="set_target_location">
- <return type="void">
- </return>
- <argument index="0" name="location" type="Vector3">
- </argument>
- <description>
- Sets the user desired final location. This will clear the current navigation path.
- </description>
- </method>
- <method name="set_velocity">
- <return type="void">
- </return>
- <argument index="0" name="velocity" type="Vector3">
- </argument>
- <description>
- Sends the passed in velocity to the collision avoidance algorithm. It will adjust the velocity to avoid collisions. Once the adjustment to the velocity is complete, it will emit the [signal velocity_computed] signal.
- </description>
- </method>
- </methods>
- <members>
- <member name="agent_height_offset" type="float" setter="set_agent_height_offset" getter="get_agent_height_offset" default="0.0">
- The agent height offset to match the navigation mesh height.
- </member>
- <member name="ignore_y" type="bool" setter="set_ignore_y" getter="get_ignore_y" default="true">
- Ignores collisions on the Y axis. Must be true to move on a horizontal plane.
- </member>
- <member name="max_neighbors" type="int" setter="set_max_neighbors" getter="get_max_neighbors" default="10">
- The maximum number of neighbors for the agent to consider.
- </member>
- <member name="max_speed" type="float" setter="set_max_speed" getter="get_max_speed" default="10.0">
- The maximum speed that an agent can move.
- </member>
- <member name="neighbor_dist" type="float" setter="set_neighbor_dist" getter="get_neighbor_dist" default="50.0">
- The distance to search for other agents.
- </member>
- <member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="3.0">
- The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
- </member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- The radius of the agent.
- </member>
- <member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0">
- 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.
- </member>
- </members>
- <signals>
- <signal name="navigation_finished">
- <description>
- Notifies when the final location is reached.
- </description>
- </signal>
- <signal name="path_changed">
- <description>
- Notifies when the navigation path changes.
- </description>
- </signal>
- <signal name="target_reached">
- <description>
- Notifies when the player defined target, set with [method set_target_location], is reached.
- </description>
- </signal>
- <signal name="velocity_computed">
- <argument index="0" name="safe_velocity" type="Vector3">
- </argument>
- <description>
- Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity].
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
new file mode 100644
index 0000000000..f9df1d390b
--- /dev/null
+++ b/doc/classes/NavigationAgent3D.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationAgent3D" inherits="Node" version="4.0">
+ <brief_description>
+ 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.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="distance_to_target" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the distance to the target location, using the agent's global position. The user must set the target location with [method set_target_location] in order for this to be accurate.
+ </description>
+ </method>
+ <method name="get_final_location">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame.
+ </description>
+ </method>
+ <method name="get_nav_path" qualifiers="const">
+ <return type="PackedVector3Array">
+ </return>
+ <description>
+ Returns the path from start to finish in global coordinates.
+ </description>
+ </method>
+ <method name="get_nav_path_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ 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">
+ </return>
+ <description>
+ Returns the [Navigation3D] node that the agent is using for its navigation system.
+ </description>
+ </method>
+ <method name="get_next_location">
+ <return type="Vector3">
+ </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">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the user defined [Vector3] after setting the target location.
+ </description>
+ </method>
+ <method name="is_navigation_finished">
+ <return type="bool">
+ </return>
+ <description>
+ Returns true if the navigation path's final location has been reached.
+ </description>
+ </method>
+ <method name="is_target_reachable">
+ <return type="bool">
+ </return>
+ <description>
+ Returns true if the target location is reachable. The target location is set using [method set_target_location].
+ </description>
+ </method>
+ <method name="is_target_reached" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ 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>
+ <argument index="0" name="location" type="Vector3">
+ </argument>
+ <description>
+ Sets the user desired final location. This will clear the current navigation path.
+ </description>
+ </method>
+ <method name="set_velocity">
+ <return type="void">
+ </return>
+ <argument index="0" name="velocity" type="Vector3">
+ </argument>
+ <description>
+ Sends the passed in velocity to the collision avoidance algorithm. It will adjust the velocity to avoid collisions. Once the adjustment to the velocity is complete, it will emit the [signal velocity_computed] signal.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="agent_height_offset" type="float" setter="set_agent_height_offset" getter="get_agent_height_offset" default="0.0">
+ The agent height offset to match the navigation mesh height.
+ </member>
+ <member name="ignore_y" type="bool" setter="set_ignore_y" getter="get_ignore_y" default="true">
+ Ignores collisions on the Y axis. Must be true to move on a horizontal plane.
+ </member>
+ <member name="max_neighbors" type="int" setter="set_max_neighbors" getter="get_max_neighbors" default="10">
+ The maximum number of neighbors for the agent to consider.
+ </member>
+ <member name="max_speed" type="float" setter="set_max_speed" getter="get_max_speed" default="10.0">
+ The maximum speed that an agent can move.
+ </member>
+ <member name="neighbor_dist" type="float" setter="set_neighbor_dist" getter="get_neighbor_dist" default="50.0">
+ The distance to search for other agents.
+ </member>
+ <member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="3.0">
+ The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ The radius of the agent.
+ </member>
+ <member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0">
+ 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.
+ </member>
+ </members>
+ <signals>
+ <signal name="navigation_finished">
+ <description>
+ Notifies when the final location is reached.
+ </description>
+ </signal>
+ <signal name="path_changed">
+ <description>
+ Notifies when the navigation path changes.
+ </description>
+ </signal>
+ <signal name="target_reached">
+ <description>
+ Notifies when the player defined target, set with [method set_target_location], is reached.
+ </description>
+ </signal>
+ <signal name="velocity_computed">
+ <argument index="0" name="safe_velocity" type="Vector3">
+ </argument>
+ <description>
+ Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity].
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/NavigationObstacle.xml b/doc/classes/NavigationObstacle.xml
deleted file mode 100644
index 31cf01793a..0000000000
--- a/doc/classes/NavigationObstacle.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationObstacle" inherits="Node" version="4.0">
- <brief_description>
- 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 [Navigation] node, or using [method set_navigation]. [NavigationObstacle] is physics safe.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_navigation" qualifiers="const">
- <return type="Node">
- </return>
- <description>
- Returns the [Navigation] 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 [Navigation] node used by the obstacle. Useful when you don't want to make the obstacle a child of a [Navigation] node.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml
index 4d12b985e0..ddd96975f1 100644
--- a/doc/classes/NavigationObstacle2D.xml
+++ b/doc/classes/NavigationObstacle2D.xml
@@ -4,7 +4,7 @@
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]. [NavigationObstacle] is physics safe.
+ 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.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml
new file mode 100644
index 0000000000..e01a40ed73
--- /dev/null
+++ b/doc/classes/NavigationObstacle3D.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationObstacle3D" inherits="Node" version="4.0">
+ <brief_description>
+ 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.
+ </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>
+</class>
diff --git a/doc/classes/NavigationRegion.xml b/doc/classes/NavigationRegion.xml
deleted file mode 100644
index a32ded2878..0000000000
--- a/doc/classes/NavigationRegion.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationRegion" inherits="Spatial" version="4.0">
- <brief_description>
- A region of the navigation map.
- </brief_description>
- <description>
- A region of the navigation map. It tells the [Navigation] node what can be navigated and what cannot, based on the [NavigationMesh] resource. This should be a child of a [Navigation] node (even not a direct child).
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="bake_navigation_mesh">
- <return type="void">
- </return>
- <description>
- Bakes the [NavigationMesh]. The baking is done in a separate thread because navigation baking is not a cheap operation. This can be done at runtime. When it is completed, it automatically sets the new [NavigationMesh].
- </description>
- </method>
- </methods>
- <members>
- <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
- Determines if the [NavigationRegion] is enabled or disabled.
- </member>
- <member name="navmesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh">
- The [NavigationMesh] resource to use.
- </member>
- </members>
- <signals>
- <signal name="bake_finished">
- <description>
- Notifies when the navigation mesh bake operation is completed.
- </description>
- </signal>
- <signal name="navigation_mesh_changed">
- <description>
- Notifies when the [NavigationMesh] has changed.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
new file mode 100644
index 0000000000..b70bfb6596
--- /dev/null
+++ b/doc/classes/NavigationRegion3D.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationRegion3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ 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).
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="bake_navigation_mesh">
+ <return type="void">
+ </return>
+ <description>
+ Bakes the [NavigationMesh]. The baking is done in a separate thread because navigation baking is not a cheap operation. This can be done at runtime. When it is completed, it automatically sets the new [NavigationMesh].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
+ Determines if the [NavigationRegion3D] is enabled or disabled.
+ </member>
+ <member name="navmesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh">
+ The [NavigationMesh] resource to use.
+ </member>
+ </members>
+ <signals>
+ <signal name="bake_finished">
+ <description>
+ Notifies when the navigation mesh bake operation is completed.
+ </description>
+ </signal>
+ <signal name="navigation_mesh_changed">
+ <description>
+ Notifies when the [NavigationMesh] has changed.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/NavigationServer.xml b/doc/classes/NavigationServer.xml
deleted file mode 100644
index 1b534b8458..0000000000
--- a/doc/classes/NavigationServer.xml
+++ /dev/null
@@ -1,375 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NavigationServer" inherits="Object" version="4.0">
- <brief_description>
- Server interface for low-level 3D navigation access
- </brief_description>
- <description>
- NavigationServer 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.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="agent_create" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Creates the agent.
- </description>
- </method>
- <method name="agent_is_map_changed" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <description>
- Returns true if the map got changed the previous frame.
- </description>
- </method>
- <method name="agent_set_callback" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
- </argument>
- <argument index="3" name="userdata" type="Variant" default="null">
- </argument>
- <description>
- Callback called at the end of the RVO process.
- </description>
- </method>
- <method name="agent_set_map" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="map" type="RID">
- </argument>
- <description>
- Puts the agent in the map.
- </description>
- </method>
- <method name="agent_set_max_neighbors" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="count" type="int">
- </argument>
- <description>
- Sets the maximum number of other agents the agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
- </description>
- </method>
- <method name="agent_set_max_speed" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="max_speed" type="float">
- </argument>
- <description>
- Sets the maximum speed of the agent. Must be positive.
- </description>
- </method>
- <method name="agent_set_neighbor_dist" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="dist" type="float">
- </argument>
- <description>
- Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
- </description>
- </method>
- <method name="agent_set_position" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="position" type="Vector3">
- </argument>
- <description>
- Sets the position of the agent in world space.
- </description>
- </method>
- <method name="agent_set_radius" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="radius" type="float">
- </argument>
- <description>
- Sets the radius of the agent.
- </description>
- </method>
- <method name="agent_set_target_velocity" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="target_velocity" type="Vector3">
- </argument>
- <description>
- Sets the new target velocity.
- </description>
- </method>
- <method name="agent_set_time_horizon" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="time" type="float">
- </argument>
- <description>
- The minimal amount of time for which the agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
- </description>
- </method>
- <method name="agent_set_velocity" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="agent" type="RID">
- </argument>
- <argument index="1" name="velocity" type="Vector3">
- </argument>
- <description>
- Sets the current velocity of the agent.
- </description>
- </method>
- <method name="free" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="object" type="RID">
- </argument>
- <description>
- Destroy the RID
- </description>
- </method>
- <method name="map_create" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Create a new map.
- </description>
- </method>
- <method name="map_get_cell_size" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <description>
- Returns the map cell size.
- </description>
- </method>
- <method name="map_get_closest_point" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="to_point" type="Vector3">
- </argument>
- <description>
- Returns the point closest to the provided [code]point[/code] on the navigation mesh surface.
- </description>
- </method>
- <method name="map_get_closest_point_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="to_point" type="Vector3">
- </argument>
- <description>
- Returns the normal for the point returned by [method map_get_closest_point].
- </description>
- </method>
- <method name="map_get_closest_point_owner" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="to_point" type="Vector3">
- </argument>
- <description>
- Returns the owner region RID for the point returned by [method map_get_closest_point].
- </description>
- </method>
- <method name="map_get_closest_point_to_segment" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="start" type="Vector3">
- </argument>
- <argument index="2" name="end" type="Vector3">
- </argument>
- <argument index="3" name="use_collision" type="bool" default="false">
- </argument>
- <description>
- Returns the closest point between the navigation surface and the segment.
- </description>
- </method>
- <method name="map_get_edge_connection_margin" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <description>
- Returns the edge connection margin of the map.
- </description>
- </method>
- <method name="map_get_path" qualifiers="const">
- <return type="PackedVector3Array">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="origin" type="Vector3">
- </argument>
- <argument index="2" name="destination" type="Vector3">
- </argument>
- <argument index="3" name="optimize" type="bool">
- </argument>
- <description>
- Returns the navigation path to reach the destination from the origin.
- </description>
- </method>
- <method name="map_get_up" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <description>
- Returns the map's up direction.
- </description>
- </method>
- <method name="map_is_active" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="nap" type="RID">
- </argument>
- <description>
- Returns true if the map is active.
- </description>
- </method>
- <method name="map_set_active" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="active" type="bool">
- </argument>
- <description>
- Sets the map active.
- </description>
- </method>
- <method name="map_set_cell_size" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="cell_size" type="float">
- </argument>
- <description>
- Set the map cell size used to weld the navigation mesh polygons.
- </description>
- </method>
- <method name="map_set_edge_connection_margin" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="margin" type="float">
- </argument>
- <description>
- Set the map edge connection margein used to weld the compatible region edges.
- </description>
- </method>
- <method name="map_set_up" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="map" type="RID">
- </argument>
- <argument index="1" name="up" type="Vector3">
- </argument>
- <description>
- Sets the map up direction.
- </description>
- </method>
- <method name="process">
- <return type="void">
- </return>
- <argument index="0" name="delta_time" type="float">
- </argument>
- <description>
- Process the collision avoidance agents.
- The result of this process is needed by the physics server, so this must be called in the main thread.
- Note: This function is not thread safe.
- </description>
- </method>
- <method name="region_bake_navmesh" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="NavigationMesh">
- </argument>
- <argument index="1" name="node" type="Node">
- </argument>
- <description>
- Bakes the navigation mesh.
- </description>
- </method>
- <method name="region_create" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Creates a new region.
- </description>
- </method>
- <method name="region_set_map" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="region" type="RID">
- </argument>
- <argument index="1" name="map" type="RID">
- </argument>
- <description>
- Sets the map for the region.
- </description>
- </method>
- <method name="region_set_navmesh" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="region" type="RID">
- </argument>
- <argument index="1" name="nav_mesh" type="NavigationMesh">
- </argument>
- <description>
- Sets the navigation mesh for the region.
- </description>
- </method>
- <method name="region_set_transform" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="region" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- Sets the global transformation for the region.
- </description>
- </method>
- <method name="set_active" qualifiers="const">
- <return type="void">
- </return>
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- Control activation of this server.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
new file mode 100644
index 0000000000..1b9099336c
--- /dev/null
+++ b/doc/classes/NavigationServer2D.xml
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationServer2D" inherits="Object" version="4.0">
+ <brief_description>
+ 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.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="agent_create" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Creates the agent.
+ </description>
+ </method>
+ <method name="agent_is_map_changed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <description>
+ Returns true if the map got changed the previous frame.
+ </description>
+ </method>
+ <method name="agent_set_callback" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="receiver" type="Object">
+ </argument>
+ <argument index="2" name="method" type="StringName">
+ </argument>
+ <argument index="3" name="userdata" type="Variant" default="null">
+ </argument>
+ <description>
+ Callback called at the end of the RVO process.
+ </description>
+ </method>
+ <method name="agent_set_map" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="map" type="RID">
+ </argument>
+ <description>
+ Puts the agent in the map.
+ </description>
+ </method>
+ <method name="agent_set_max_neighbors" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="count" type="int">
+ </argument>
+ <description>
+ Sets the maximum number of other agents the agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ </description>
+ </method>
+ <method name="agent_set_max_speed" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="max_speed" type="float">
+ </argument>
+ <description>
+ Sets the maximum speed of the agent. Must be positive.
+ </description>
+ </method>
+ <method name="agent_set_neighbor_dist" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="dist" type="float">
+ </argument>
+ <description>
+ Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ </description>
+ </method>
+ <method name="agent_set_position" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="position" type="Vector2">
+ </argument>
+ <description>
+ Sets the position of the agent in world space.
+ </description>
+ </method>
+ <method name="agent_set_radius" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="radius" type="float">
+ </argument>
+ <description>
+ Sets the radius of the agent.
+ </description>
+ </method>
+ <method name="agent_set_target_velocity" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="target_velocity" type="Vector2">
+ </argument>
+ <description>
+ Sets the new target velocity.
+ </description>
+ </method>
+ <method name="agent_set_time_horizon" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="time" type="float">
+ </argument>
+ <description>
+ The minimal amount of time for which the agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
+ </description>
+ </method>
+ <method name="agent_set_velocity" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="velocity" type="Vector2">
+ </argument>
+ <description>
+ Sets the current velocity of the agent.
+ </description>
+ </method>
+ <method name="free" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="object" type="RID">
+ </argument>
+ <description>
+ Destroy the RID
+ </description>
+ </method>
+ <method name="map_create" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Create a new map.
+ </description>
+ </method>
+ <method name="map_get_cell_size" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Returns the map cell size.
+ </description>
+ </method>
+ <method name="map_get_closest_point" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" 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="map_get_closest_point_owner" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="to_point" type="Vector2">
+ </argument>
+ <description>
+ Returns the owner region RID for the point returned by [method map_get_closest_point].
+ </description>
+ </method>
+ <method name="map_get_edge_connection_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Returns the edge connection margin of the map. The edge connection margin is a distance used to connect two regions.
+ </description>
+ </method>
+ <method name="map_get_path" qualifiers="const">
+ <return type="PackedVector2Array">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="origin" type="Vector2">
+ </argument>
+ <argument index="2" name="destination" type="Vector2">
+ </argument>
+ <argument index="3" name="optimize" type="bool">
+ </argument>
+ <description>
+ Returns the navigation path to reach the destination from the origin, while avoiding static obstacles.
+ </description>
+ </method>
+ <method name="map_is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="nap" type="RID">
+ </argument>
+ <description>
+ Returns true if the map is active.
+ </description>
+ </method>
+ <method name="map_set_active" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="active" type="bool">
+ </argument>
+ <description>
+ Sets the map active.
+ </description>
+ </method>
+ <method name="map_set_cell_size" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="cell_size" type="float">
+ </argument>
+ <description>
+ Set the map cell size used to weld the navigation mesh polygons.
+ </description>
+ </method>
+ <method name="map_set_edge_connection_margin" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="margin" type="float">
+ </argument>
+ <description>
+ Set the map edge connection margin used to weld the compatible region edges.
+ </description>
+ </method>
+ <method name="region_create" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a new region.
+ </description>
+ </method>
+ <method name="region_set_map" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="map" type="RID">
+ </argument>
+ <description>
+ Sets the map for the region.
+ </description>
+ </method>
+ <method name="region_set_navpoly" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="nav_poly" type="NavigationPolygon">
+ </argument>
+ <description>
+ Sets the navigation mesh for the region.
+ </description>
+ </method>
+ <method name="region_set_transform" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the global transformation for the region.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
new file mode 100644
index 0000000000..1f621c3c81
--- /dev/null
+++ b/doc/classes/NavigationServer3D.xml
@@ -0,0 +1,375 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NavigationServer3D" inherits="Object" version="4.0">
+ <brief_description>
+ 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.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="agent_create" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Creates the agent.
+ </description>
+ </method>
+ <method name="agent_is_map_changed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <description>
+ Returns true if the map got changed the previous frame.
+ </description>
+ </method>
+ <method name="agent_set_callback" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="receiver" type="Object">
+ </argument>
+ <argument index="2" name="method" type="StringName">
+ </argument>
+ <argument index="3" name="userdata" type="Variant" default="null">
+ </argument>
+ <description>
+ Callback called at the end of the RVO process.
+ </description>
+ </method>
+ <method name="agent_set_map" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="map" type="RID">
+ </argument>
+ <description>
+ Puts the agent in the map.
+ </description>
+ </method>
+ <method name="agent_set_max_neighbors" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="count" type="int">
+ </argument>
+ <description>
+ Sets the maximum number of other agents the agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ </description>
+ </method>
+ <method name="agent_set_max_speed" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="max_speed" type="float">
+ </argument>
+ <description>
+ Sets the maximum speed of the agent. Must be positive.
+ </description>
+ </method>
+ <method name="agent_set_neighbor_dist" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="dist" type="float">
+ </argument>
+ <description>
+ Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
+ </description>
+ </method>
+ <method name="agent_set_position" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="position" type="Vector3">
+ </argument>
+ <description>
+ Sets the position of the agent in world space.
+ </description>
+ </method>
+ <method name="agent_set_radius" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="radius" type="float">
+ </argument>
+ <description>
+ Sets the radius of the agent.
+ </description>
+ </method>
+ <method name="agent_set_target_velocity" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="target_velocity" type="Vector3">
+ </argument>
+ <description>
+ Sets the new target velocity.
+ </description>
+ </method>
+ <method name="agent_set_time_horizon" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="time" type="float">
+ </argument>
+ <description>
+ The minimal amount of time for which the agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
+ </description>
+ </method>
+ <method name="agent_set_velocity" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="agent" type="RID">
+ </argument>
+ <argument index="1" name="velocity" type="Vector3">
+ </argument>
+ <description>
+ Sets the current velocity of the agent.
+ </description>
+ </method>
+ <method name="free" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="object" type="RID">
+ </argument>
+ <description>
+ Destroy the RID
+ </description>
+ </method>
+ <method name="map_create" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Create a new map.
+ </description>
+ </method>
+ <method name="map_get_cell_size" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Returns the map cell size.
+ </description>
+ </method>
+ <method name="map_get_closest_point" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="to_point" type="Vector3">
+ </argument>
+ <description>
+ Returns the point closest to the provided [code]point[/code] on the navigation mesh surface.
+ </description>
+ </method>
+ <method name="map_get_closest_point_normal" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="to_point" type="Vector3">
+ </argument>
+ <description>
+ Returns the normal for the point returned by [method map_get_closest_point].
+ </description>
+ </method>
+ <method name="map_get_closest_point_owner" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="to_point" type="Vector3">
+ </argument>
+ <description>
+ Returns the owner region RID for the point returned by [method map_get_closest_point].
+ </description>
+ </method>
+ <method name="map_get_closest_point_to_segment" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="start" type="Vector3">
+ </argument>
+ <argument index="2" name="end" type="Vector3">
+ </argument>
+ <argument index="3" name="use_collision" type="bool" default="false">
+ </argument>
+ <description>
+ Returns the closest point between the navigation surface and the segment.
+ </description>
+ </method>
+ <method name="map_get_edge_connection_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Returns the edge connection margin of the map.
+ </description>
+ </method>
+ <method name="map_get_path" qualifiers="const">
+ <return type="PackedVector3Array">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="origin" type="Vector3">
+ </argument>
+ <argument index="2" name="destination" type="Vector3">
+ </argument>
+ <argument index="3" name="optimize" type="bool">
+ </argument>
+ <description>
+ Returns the navigation path to reach the destination from the origin.
+ </description>
+ </method>
+ <method name="map_get_up" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <description>
+ Returns the map's up direction.
+ </description>
+ </method>
+ <method name="map_is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="nap" type="RID">
+ </argument>
+ <description>
+ Returns true if the map is active.
+ </description>
+ </method>
+ <method name="map_set_active" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="active" type="bool">
+ </argument>
+ <description>
+ Sets the map active.
+ </description>
+ </method>
+ <method name="map_set_cell_size" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="cell_size" type="float">
+ </argument>
+ <description>
+ Set the map cell size used to weld the navigation mesh polygons.
+ </description>
+ </method>
+ <method name="map_set_edge_connection_margin" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="margin" type="float">
+ </argument>
+ <description>
+ Set the map edge connection margein used to weld the compatible region edges.
+ </description>
+ </method>
+ <method name="map_set_up" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="map" type="RID">
+ </argument>
+ <argument index="1" name="up" type="Vector3">
+ </argument>
+ <description>
+ Sets the map up direction.
+ </description>
+ </method>
+ <method name="process">
+ <return type="void">
+ </return>
+ <argument index="0" name="delta_time" type="float">
+ </argument>
+ <description>
+ Process the collision avoidance agents.
+ The result of this process is needed by the physics server, so this must be called in the main thread.
+ Note: This function is not thread safe.
+ </description>
+ </method>
+ <method name="region_bake_navmesh" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="NavigationMesh">
+ </argument>
+ <argument index="1" name="node" type="Node">
+ </argument>
+ <description>
+ Bakes the navigation mesh.
+ </description>
+ </method>
+ <method name="region_create" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a new region.
+ </description>
+ </method>
+ <method name="region_set_map" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="map" type="RID">
+ </argument>
+ <description>
+ Sets the map for the region.
+ </description>
+ </method>
+ <method name="region_set_navmesh" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="nav_mesh" type="NavigationMesh">
+ </argument>
+ <description>
+ Sets the navigation mesh for the region.
+ </description>
+ </method>
+ <method name="region_set_transform" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="region" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the global transformation for the region.
+ </description>
+ </method>
+ <method name="set_active" qualifiers="const">
+ <return type="void">
+ </return>
+ <argument index="0" name="active" type="bool">
+ </argument>
+ <description>
+ Control activation of this server.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 717130728d..8c588f0373 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -53,7 +53,7 @@
<description>
Called when there is an input event. The input event propagates up through the node tree until a node consumes it.
It is only called if input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_input].
- To consume the input event and stop it propagating further to other nodes, [method SceneTree.set_input_as_handled] can be called.
+ To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
For gameplay input, [method _unhandled_input] and [method _unhandled_key_input] are usually a better fit as they allow the GUI to intercept the events first.
</description>
</method>
@@ -97,7 +97,7 @@
<description>
Called when an [InputEvent] hasn't been consumed by [method _input] or any GUI. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_input].
- To consume the input event and stop it propagating further to other nodes, [method SceneTree.set_input_as_handled] can be called.
+ To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
For gameplay input, this and [method _unhandled_key_input] are usually a better fit than [method _input] as they allow the GUI to intercept the events first.
</description>
</method>
@@ -109,7 +109,7 @@
<description>
Called when an [InputEventKey] hasn't been consumed by [method _input] or any GUI. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled key input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_key_input].
- To consume the input event and stop it propagating further to other nodes, [method SceneTree.set_input_as_handled] can be called.
+ To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
For gameplay input, this and [method _unhandled_input] are usually a better fit than [method _input] as they allow the GUI to intercept the events first.
</description>
</method>
@@ -238,7 +238,7 @@
<return type="int">
</return>
<description>
- Returns the node's index, i.e. its position among the siblings of its parent.
+ Returns the node's order in the scene tree branch. For example, if called on the first child node the position is [code]0[/code].
</description>
</method>
<method name="get_network_master" qualifiers="const">
@@ -331,13 +331,6 @@
Returns the time elapsed since the last physics-bound frame (see [method _physics_process]). This is always a constant value in physics processing unless the frames per second is changed via [member Engine.iterations_per_second].
</description>
</method>
- <method name="get_position_in_parent" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the node's order in the scene tree branch. For example, if called on the first child node the position is [code]0[/code].
- </description>
- </method>
<method name="get_process_delta_time" qualifiers="const">
<return type="float">
</return>
@@ -938,42 +931,40 @@
Notification received from the OS when the game window is unfocused.
Implemented on all platforms.
</constant>
- <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="1006">
- Notification received from the OS when a quit request is sent (e.g. closing the window with a "Close" button or Alt+F4).
+ <constant name="NOTIFICATION_WM_CLOSE_REQUEST" value="1006">
+ Notification received from the OS when a close request is sent (e.g. closing the window with a "Close" button or Alt+F4).
Implemented on desktop platforms.
</constant>
<constant name="NOTIFICATION_WM_GO_BACK_REQUEST" value="1007">
Notification received from the OS when a go back request is sent (e.g. pressing the "Back" button on Android).
Specific to the Android platform.
</constant>
- <constant name="NOTIFICATION_WM_UNFOCUS_REQUEST" value="1008">
- Notification received from the OS when an unfocus request is sent (e.g. another OS window wants to take the focus).
- No supported platforms currently send this notification.
+ <constant name="NOTIFICATION_WM_SIZE_CHANGED" value="1008">
</constant>
- <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="1009">
+ <constant name="NOTIFICATION_OS_MEMORY_WARNING" value="2009">
Notification received from the OS when the application is exceeding its allocated memory.
Specific to the iOS platform.
</constant>
- <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="1010">
+ <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="2010">
Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr].
</constant>
- <constant name="NOTIFICATION_WM_ABOUT" value="1011">
+ <constant name="NOTIFICATION_WM_ABOUT" value="2011">
Notification received from the OS when a request for "About" information is sent.
Specific to the macOS platform.
</constant>
- <constant name="NOTIFICATION_CRASH" value="1012">
+ <constant name="NOTIFICATION_CRASH" value="2012">
Notification received from Godot's crash handler when the engine is about to crash.
Implemented on desktop platforms if the crash handler is enabled.
</constant>
- <constant name="NOTIFICATION_OS_IME_UPDATE" value="1013">
+ <constant name="NOTIFICATION_OS_IME_UPDATE" value="2013">
Notification received from the OS when an update of the Input Method Engine occurs (e.g. change of IME cursor position or composition string).
Specific to the macOS platform.
</constant>
- <constant name="NOTIFICATION_APP_RESUMED" value="1014">
+ <constant name="NOTIFICATION_APP_RESUMED" value="2014">
Notification received from the OS when the app is resumed.
Specific to the Android platform.
</constant>
- <constant name="NOTIFICATION_APP_PAUSED" value="1015">
+ <constant name="NOTIFICATION_APP_PAUSED" value="2015">
Notification received from the OS when the app is paused.
Specific to the Android platform.
</constant>
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
new file mode 100644
index 0000000000..ef24f638fb
--- /dev/null
+++ b/doc/classes/Node3D.xml
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Node3D" inherits="Node" version="4.0">
+ <brief_description>
+ Most basic 3D game object, parent of all 3D-related nodes.
+ </brief_description>
+ <description>
+ Most basic 3D game object, with a 3D [Transform] and visibility settings. All other 3D game objects inherit from Node3D. Use [Node3D] as a parent node to move, scale, rotate and show/hide children in a 3D project.
+ Affine operations (rotate, scale, translate) happen in parent's local coordinate system, unless the [Node3D] object is set as top-level. Affine operations in this coordinate system correspond to direct affine operations on the [Node3D]'s transform. The word local below refers to this coordinate system. The coordinate system that is attached to the [Node3D] object itself is referred to as object-local coordinate system.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html</link>
+ </tutorials>
+ <methods>
+ <method name="force_update_transform">
+ <return type="void">
+ </return>
+ <description>
+ Forces the transform to update. Transform changes in physics are not instant for performance reasons. Transforms are accumulated and then set. Use this if you need an up-to-date transform when doing physics operations.
+ </description>
+ </method>
+ <method name="get_parent_spatial" qualifiers="const">
+ <return type="Node3D">
+ </return>
+ <description>
+ Returns the parent [Node3D], or an empty [Object] if no parent exists or parent is not of type [Node3D].
+ </description>
+ </method>
+ <method name="get_world" qualifiers="const">
+ <return type="World3D">
+ </return>
+ <description>
+ Returns the current [World3D] resource this [Node3D] node is registered to.
+ </description>
+ </method>
+ <method name="global_rotate">
+ <return type="void">
+ </return>
+ <argument index="0" name="axis" type="Vector3">
+ </argument>
+ <argument index="1" name="angle" type="float">
+ </argument>
+ <description>
+ Rotates the global (world) transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in global coordinate system.
+ </description>
+ </method>
+ <method name="global_scale">
+ <return type="void">
+ </return>
+ <argument index="0" name="scale" type="Vector3">
+ </argument>
+ <description>
+ Scales the global (world) transformation by the given [Vector3] scale factors.
+ </description>
+ </method>
+ <method name="global_translate">
+ <return type="void">
+ </return>
+ <argument index="0" name="offset" type="Vector3">
+ </argument>
+ <description>
+ Moves the global (world) transformation by [Vector3] offset. The offset is in global coordinate system.
+ </description>
+ </method>
+ <method name="hide">
+ <return type="void">
+ </return>
+ <description>
+ Disables rendering of this node. Changes [member visible] to [code]false[/code].
+ </description>
+ </method>
+ <method name="is_local_transform_notification_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether node notifies about its local transformation changes. [Node3D] will not propagate this by default.
+ </description>
+ </method>
+ <method name="is_scale_disabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this node uses a scale of [code](1, 1, 1)[/code] or its local transformation scale.
+ </description>
+ </method>
+ <method name="is_set_as_toplevel" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this node is set as Toplevel, that is whether it ignores its parent nodes transformations.
+ </description>
+ </method>
+ <method name="is_transform_notification_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether the node notifies about its global and local transformation changes. [Node3D] will not propagate this by default.
+ </description>
+ </method>
+ <method name="is_visible_in_tree" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether the node is visible, taking into consideration that its parents visibility.
+ </description>
+ </method>
+ <method name="look_at">
+ <return type="void">
+ </return>
+ <argument index="0" name="target" type="Vector3">
+ </argument>
+ <argument index="1" name="up" type="Vector3">
+ </argument>
+ <description>
+ Rotates itself so that the local -Z axis points towards the [code]target[/code] position.
+ The transform will first be rotated around the given [code]up[/code] vector, and then fully aligned to the target by a further rotation around an axis perpendicular to both the [code]target[/code] and [code]up[/code] vectors.
+ Operations take place in global space.
+ </description>
+ </method>
+ <method name="look_at_from_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <argument index="1" name="target" type="Vector3">
+ </argument>
+ <argument index="2" name="up" type="Vector3">
+ </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.
+ </description>
+ </method>
+ <method name="orthonormalize">
+ <return type="void">
+ </return>
+ <description>
+ Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform].
+ </description>
+ </method>
+ <method name="rotate">
+ <return type="void">
+ </return>
+ <argument index="0" name="axis" type="Vector3">
+ </argument>
+ <argument index="1" name="angle" type="float">
+ </argument>
+ <description>
+ Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians.
+ </description>
+ </method>
+ <method name="rotate_object_local">
+ <return type="void">
+ </return>
+ <argument index="0" name="axis" type="Vector3">
+ </argument>
+ <argument index="1" name="angle" type="float">
+ </argument>
+ <description>
+ Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in object-local coordinate system.
+ </description>
+ </method>
+ <method name="rotate_x">
+ <return type="void">
+ </return>
+ <argument index="0" name="angle" type="float">
+ </argument>
+ <description>
+ Rotates the local transformation around the X axis by angle in radians.
+ </description>
+ </method>
+ <method name="rotate_y">
+ <return type="void">
+ </return>
+ <argument index="0" name="angle" type="float">
+ </argument>
+ <description>
+ Rotates the local transformation around the Y axis by angle in radians.
+ </description>
+ </method>
+ <method name="rotate_z">
+ <return type="void">
+ </return>
+ <argument index="0" name="angle" type="float">
+ </argument>
+ <description>
+ Rotates the local transformation around the Z axis by angle in radians.
+ </description>
+ </method>
+ <method name="scale_object_local">
+ <return type="void">
+ </return>
+ <argument index="0" name="scale" type="Vector3">
+ </argument>
+ <description>
+ Scales the local transformation by given 3D scale factors in object-local coordinate system.
+ </description>
+ </method>
+ <method name="set_as_toplevel">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Makes the node ignore its parents transformations. Node transformations are only in global space.
+ </description>
+ </method>
+ <method name="set_disable_scale">
+ <return type="void">
+ </return>
+ <argument index="0" name="disable" type="bool">
+ </argument>
+ <description>
+ Sets whether the node uses a scale of [code](1, 1, 1)[/code] or its local transformation scale. Changes to the local transformation scale are preserved.
+ </description>
+ </method>
+ <method name="set_identity">
+ <return type="void">
+ </return>
+ <description>
+ Reset all transformations for this node (sets its [Transform] to the identity matrix).
+ </description>
+ </method>
+ <method name="set_ignore_transform_notification">
+ <return type="void">
+ </return>
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets whether the node ignores notification that its transformation (global or local) changed.
+ </description>
+ </method>
+ <method name="set_notify_local_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets whether the node notifies about its local transformation changes. [Node3D] will not propagate this by default.
+ </description>
+ </method>
+ <method name="set_notify_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets whether the node notifies about its global and local transformation changes. [Node3D] will not propagate this by default.
+ </description>
+ </method>
+ <method name="show">
+ <return type="void">
+ </return>
+ <description>
+ Enables rendering of this node. Changes [member visible] to [code]true[/code].
+ </description>
+ </method>
+ <method name="to_global" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="local_point" type="Vector3">
+ </argument>
+ <description>
+ Transforms [code]local_point[/code] from this node's local space to world space.
+ </description>
+ </method>
+ <method name="to_local" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="global_point" type="Vector3">
+ </argument>
+ <description>
+ Transforms [code]global_point[/code] from world space to this node's local space.
+ </description>
+ </method>
+ <method name="translate">
+ <return type="void">
+ </return>
+ <argument index="0" name="offset" type="Vector3">
+ </argument>
+ <description>
+ Changes the node's position by the given offset [Vector3].
+ Note that the translation [code]offset[/code] is affected by the node's scale, so if scaled by e.g. [code](10, 1, 1)[/code], a translation by an offset of [code](2, 0, 0)[/code] would actually add 20 ([code]2 * 10[/code]) to the X coordinate.
+ </description>
+ </method>
+ <method name="translate_object_local">
+ <return type="void">
+ </return>
+ <argument index="0" name="offset" type="Vector3">
+ </argument>
+ <description>
+ Changes the node's position by the given offset [Vector3] in local space.
+ </description>
+ </method>
+ <method name="update_gizmo">
+ <return type="void">
+ </return>
+ <description>
+ Updates the [Node3DGizmo] of this node.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="gizmo" type="Node3DGizmo" setter="set_gizmo" getter="get_gizmo">
+ The [Node3DGizmo] for this node. Used for example in [EditorNode3DGizmo] as custom visualization and editing handles in Editor.
+ </member>
+ <member name="global_transform" type="Transform" setter="set_global_transform" getter="get_global_transform">
+ World3D space (global) [Transform] of this node.
+ </member>
+ <member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation">
+ Rotation part of the local transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle).
+ [b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful.
+ </member>
+ <member name="rotation_degrees" type="Vector3" setter="set_rotation_degrees" getter="get_rotation_degrees" default="Vector3( 0, 0, 0 )">
+ Rotation part of the local transformation in degrees, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle).
+ </member>
+ <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3( 1, 1, 1 )">
+ Scale part of the local transformation.
+ </member>
+ <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ Local space [Transform] of this node, with respect to the parent node.
+ </member>
+ <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3( 0, 0, 0 )">
+ Local translation of this node.
+ </member>
+ <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
+ If [code]true[/code], this node is drawn.
+ </member>
+ </members>
+ <signals>
+ <signal name="visibility_changed">
+ <description>
+ Emitted when node visibility changes.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="2000">
+ Node3D nodes receives this notification when their global transform changes. This means that either the current or a parent node changed its transform.
+ In order for [constant NOTIFICATION_TRANSFORM_CHANGED] to work, users first need to ask for it, with [method set_notify_transform].
+ </constant>
+ <constant name="NOTIFICATION_ENTER_WORLD" value="41">
+ Node3D nodes receives this notification when they are registered to new [World3D] resource.
+ </constant>
+ <constant name="NOTIFICATION_EXIT_WORLD" value="42">
+ Node3D nodes receives this notification when they are unregistered from current [World3D] resource.
+ </constant>
+ <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="43">
+ Node3D nodes receives this notification when their visibility changes.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Node3DGizmo.xml b/doc/classes/Node3DGizmo.xml
new file mode 100644
index 0000000000..55080614fc
--- /dev/null
+++ b/doc/classes/Node3DGizmo.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Node3DGizmo" inherits="Reference" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index e8ab3e536e..dc7fd1be3f 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -4,7 +4,7 @@
Pre-parsed scene tree path.
</brief_description>
<description>
- A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite"[/code] which is a child of the other named nodes in the path.
+ A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite2D"[/code] which is a child of the other named nodes in the path.
You will usually just pass a string to [method Node.get_node] and it will be automatically converted, but you may occasionally want to parse a path ahead of time with [NodePath] or the literal syntax [code]@"path"[/code]. Exporting a [NodePath] variable will give you a node selection widget in the properties panel of the editor, which can often be useful.
A [NodePath] is composed of a list of slash-separated node names (like a filesystem path) and an optional colon-separated list of "subnames" which can be resources or properties.
Some examples of NodePaths include the following:
@@ -30,20 +30,20 @@
<argument index="0" name="from" type="String">
</argument>
<description>
- Creates a NodePath from a string, e.g. [code]"Path2D/PathFollow2D/Sprite:texture:size"[/code]. A path is absolute if it starts with a slash. Absolute paths are only valid in the global scene tree, not within individual scenes. In a relative path, [code]"."[/code] and [code]".."[/code] indicate the current node and its parent.
+ Creates a NodePath from a string, e.g. [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code]. A path is absolute if it starts with a slash. Absolute paths are only valid in the global scene tree, not within individual scenes. In a relative path, [code]"."[/code] and [code]".."[/code] indicate the current node and its parent.
The "subnames" optionally included after the path to the target node can point to resources or properties, and can also be nested.
Examples of valid NodePaths (assuming that those nodes exist and have the referenced resources or properties):
[codeblock]
- # Points to the Sprite node
- "Path2D/PathFollow2D/Sprite"
- # Points to the Sprite node and its "texture" resource.
- # get_node() would retrieve "Sprite", while get_node_and_resource()
- # would retrieve both the Sprite node and the "texture" resource.
- "Path2D/PathFollow2D/Sprite:texture"
- # Points to the Sprite node and its "position" property.
- "Path2D/PathFollow2D/Sprite:position"
- # Points to the Sprite node and the "x" component of its "position" property.
- "Path2D/PathFollow2D/Sprite:position:x"
+ # Points to the Sprite2D node
+ "Path2D/PathFollow2D/Sprite2D"
+ # Points to the Sprite2D node and its "texture" resource.
+ # get_node() would retrieve "Sprite2D", while get_node_and_resource()
+ # would retrieve both the Sprite2D node and the "texture" resource.
+ "Path2D/PathFollow2D/Sprite2D:texture"
+ # Points to the Sprite2D node and its "position" property.
+ "Path2D/PathFollow2D/Sprite2D:position"
+ # Points to the Sprite2D node and the "x" component of its "position" property.
+ "Path2D/PathFollow2D/Sprite2D:position:x"
# Absolute path (from "root")
"/root/Level/Path2D"
[/codeblock]
@@ -69,7 +69,7 @@
<description>
Returns all subnames concatenated with a colon character ([code]:[/code]) as separator, i.e. the right side of the first colon in a node path.
[codeblock]
- var nodepath = NodePath("Path2D/PathFollow2D/Sprite:texture:load_path")
+ var nodepath = NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path")
print(nodepath.get_concatenated_subnames()) # texture:load_path
[/codeblock]
</description>
@@ -82,7 +82,7 @@
<description>
Gets the node name indicated by [code]idx[/code] (0 to [method get_name_count]).
[codeblock]
- var node_path = NodePath("Path2D/PathFollow2D/Sprite")
+ var node_path = NodePath("Path2D/PathFollow2D/Sprite2D")
print(node_path.get_name(0)) # Path2D
print(node_path.get_name(1)) # PathFollow2D
print(node_path.get_name(2)) # Sprite
@@ -94,7 +94,7 @@
</return>
<description>
Gets the number of node names which make up the path. Subnames (see [method get_subname_count]) are not included.
- For example, [code]"Path2D/PathFollow2D/Sprite"[/code] has 3 names.
+ For example, [code]"Path2D/PathFollow2D/Sprite2D"[/code] has 3 names.
</description>
</method>
<method name="get_subname">
@@ -105,7 +105,7 @@
<description>
Gets the resource or property name indicated by [code]idx[/code] (0 to [method get_subname_count]).
[codeblock]
- var node_path = NodePath("Path2D/PathFollow2D/Sprite:texture:load_path")
+ var node_path = NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path")
print(node_path.get_subname(0)) # texture
print(node_path.get_subname(1)) # load_path
[/codeblock]
@@ -116,7 +116,7 @@
</return>
<description>
Gets the number of resource or property names ("subnames") in the path. Each subname is listed after a colon character ([code]:[/code]) in the node path.
- For example, [code]"Path2D/PathFollow2D/Sprite:texture:load_path"[/code] has 2 subnames.
+ For example, [code]"Path2D/PathFollow2D/Sprite2D:texture:load_path"[/code] has 2 subnames.
</description>
</method>
<method name="is_absolute">
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index d43c395433..db79ee7765 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -9,24 +9,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="alert">
- <return type="void">
- </return>
- <argument index="0" name="text" type="String">
- </argument>
- <argument index="1" name="title" type="String" default="&quot;Alert!&quot;">
- </argument>
- <description>
- Displays a modal dialog box using the host OS' facilities. Execution is blocked until the dialog is closed.
- </description>
- </method>
- <method name="can_draw" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the host OS allows drawing.
- </description>
- </method>
<method name="can_use_threads" qualifiers="const">
<return type="bool">
</return>
@@ -34,13 +16,6 @@
Returns [code]true[/code] if the current host platform is using multiple threads.
</description>
</method>
- <method name="center_window">
- <return type="void">
- </return>
- <description>
- Centers the window on the screen if in windowed mode.
- </description>
- </method>
<method name="close_midi_inputs">
<return type="void">
</return>
@@ -133,22 +108,6 @@
Returns the keycode of the given string (e.g. "Escape").
</description>
</method>
- <method name="get_audio_driver_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the total number of available audio drivers.
- </description>
- </method>
- <method name="get_audio_driver_name" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="driver" type="int">
- </argument>
- <description>
- Returns the audio driver name for the given index.
- </description>
- </method>
<method name="get_cmdline_args">
<return type="PackedStringArray">
</return>
@@ -165,13 +124,6 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
- <method name="get_current_video_driver" qualifiers="const">
- <return type="int" enum="OS.VideoDriver">
- </return>
- <description>
- Returns the currently used video driver, using one of the values from [enum VideoDriver].
- </description>
- </method>
<method name="get_date" qualifiers="const">
<return type="Dictionary">
</return>
@@ -224,24 +176,6 @@
[b]Note:[/b] This method is implemented on Android.
</description>
</method>
- <method name="get_ime_selection" qualifiers="const">
- <return type="Vector2">
- </return>
- <description>
- Returns the IME cursor position (the currently-edited portion of the string) relative to the characters in the composition string.
- [constant MainLoop.NOTIFICATION_OS_IME_UPDATE] is sent to the application to notify it of changes to the IME cursor position.
- [b]Note:[/b] This method is implemented on macOS.
- </description>
- </method>
- <method name="get_ime_text" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the IME intermediate composition string.
- [constant MainLoop.NOTIFICATION_OS_IME_UPDATE] is sent to the application to notify it of changes to the IME composition string.
- [b]Note:[/b] This method is implemented on macOS.
- </description>
- </method>
<method name="get_keycode_string" qualifiers="const">
<return type="String">
</return>
@@ -252,15 +186,6 @@
See also [member InputEventKey.keycode] and [method InputEventKey.get_keycode_with_modifiers].
</description>
</method>
- <method name="get_latin_keyboard_variant" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the current latin keyboard variant as a String.
- Possible return values are: [code]"QWERTY"[/code], [code]"AZERTY"[/code], [code]"QZERTY"[/code], [code]"DVORAK"[/code], [code]"NEO"[/code], [code]"COLEMAK"[/code] or [code]"ERROR"[/code].
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows. Returns [code]"QWERTY"[/code] on unsupported platforms.
- </description>
- </method>
<method name="get_locale" qualifiers="const">
<return type="String">
</return>
@@ -298,57 +223,6 @@
Returns the number of threads available on the host machine.
</description>
</method>
- <method name="get_real_window_size" qualifiers="const">
- <return type="Vector2">
- </return>
- <description>
- Returns the window size including decorations like window borders.
- </description>
- </method>
- <method name="get_screen_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of displays attached to the host machine.
- </description>
- </method>
- <method name="get_screen_dpi" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="screen" type="int" default="-1">
- </argument>
- <description>
- Returns the dots per inch density of the specified screen. If [code]screen[/code] is [/code]-1[/code] (the default value), the current screen will be used.
- On Android devices, the actual screen densities are grouped into six generalized densities:
- [codeblock]
- ldpi - 120 dpi
- mdpi - 160 dpi
- hdpi - 240 dpi
- xhdpi - 320 dpi
- xxhdpi - 480 dpi
- xxxhdpi - 640 dpi
- [/codeblock]
- [b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows. Returns [code]72[/code] on unsupported platforms.
- </description>
- </method>
- <method name="get_screen_position" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="screen" type="int" default="-1">
- </argument>
- <description>
- Returns the position of the specified screen by index. If [code]screen[/code] is [/code]-1[/code] (the default value), the current screen will be used.
- </description>
- </method>
- <method name="get_screen_size" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="screen" type="int" default="-1">
- </argument>
- <description>
- Returns the dimensions in pixels of the specified screen. If [code]screen[/code] is [/code]-1[/code] (the default value), the current screen will be used.
- </description>
- </method>
<method name="get_splash_tick_msec" qualifiers="const">
<return type="int">
</return>
@@ -461,84 +335,6 @@
If the project name is empty, [code]user://[/code] falls back to [code]res://[/code].
</description>
</method>
- <method name="get_video_driver_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of video drivers supported on the current platform.
- </description>
- </method>
- <method name="get_video_driver_name" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="driver" type="int" enum="OS.VideoDriver">
- </argument>
- <description>
- Returns the name of the video driver matching the given [code]driver[/code] index. This index is a value from [enum VideoDriver], and you can use [method get_current_video_driver] to get the current backend's index.
- </description>
- </method>
- <method name="get_virtual_keyboard_height">
- <return type="int">
- </return>
- <description>
- Returns the on-screen keyboard's height in pixels. Returns 0 if there is no keyboard or if it is currently hidden.
- </description>
- </method>
- <method name="get_window_safe_area" qualifiers="const">
- <return type="Rect2">
- </return>
- <description>
- Returns unobscured area of the window where interactive controls should be rendered.
- </description>
- </method>
- <method name="global_menu_add_item">
- <return type="void">
- </return>
- <argument index="0" name="menu" type="String">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="Variant">
- </argument>
- <argument index="3" name="meta" type="Variant">
- </argument>
- <description>
- Add a new item with text "label" to global menu. Use "_dock" menu to add item to the macOS dock icon menu.
- [b]Note:[/b] This method is implemented on macOS.
- </description>
- </method>
- <method name="global_menu_add_separator">
- <return type="void">
- </return>
- <argument index="0" name="menu" type="String">
- </argument>
- <description>
- Add a separator between items. Separators also occupy an index.
- [b]Note:[/b] This method is implemented on macOS.
- </description>
- </method>
- <method name="global_menu_clear">
- <return type="void">
- </return>
- <argument index="0" name="menu" type="String">
- </argument>
- <description>
- Clear the global menu, in effect removing all items.
- [b]Note:[/b] This method is implemented on macOS.
- </description>
- </method>
- <method name="global_menu_remove_item">
- <return type="void">
- </return>
- <argument index="0" name="menu" type="String">
- </argument>
- <argument index="1" name="idx" type="int">
- </argument>
- <description>
- Removes the item at index "idx" from the global menu. Note that the indexes of items after the removed item are going to be shifted by one.
- [b]Note:[/b] This method is implemented on macOS.
- </description>
- </method>
<method name="has_environment" qualifiers="const">
<return type="bool">
</return>
@@ -558,27 +354,6 @@
[b]Note:[/b] Tag names are case-sensitive.
</description>
</method>
- <method name="has_touchscreen_ui_hint" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the device has a touchscreen or emulates one.
- </description>
- </method>
- <method name="has_virtual_keyboard" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the platform has a virtual keyboard, [code]false[/code] otherwise.
- </description>
- </method>
- <method name="hide_virtual_keyboard">
- <return type="void">
- </return>
- <description>
- Hides the virtual keyboard if it is shown, does nothing otherwise.
- </description>
- </method>
<method name="is_debug_build" qualifiers="const">
<return type="bool">
</return>
@@ -597,13 +372,6 @@
Returns [code]true[/code] if the input keycode corresponds to a Unicode character.
</description>
</method>
- <method name="is_ok_left_and_cancel_right" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the [b]OK[/b] button should appear on the left and [b]Cancel[/b] on the right.
- </description>
- </method>
<method name="is_stdout_verbose" qualifiers="const">
<return type="bool">
</return>
@@ -618,21 +386,6 @@
If [code]true[/code], the [code]user://[/code] file system is persistent, so that its state is the same after a player quits and starts the game again. Relevant to the HTML5 platform, where this persistence may be unavailable.
</description>
</method>
- <method name="is_window_always_on_top" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the window should always be on top of other windows.
- </description>
- </method>
- <method name="is_window_focused" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the window is currently focused.
- [b]Note:[/b] Only implemented on desktop platforms. On other platforms, it will always return [code]true[/code].
- </description>
- </method>
<method name="kill">
<return type="int" enum="Error">
</return>
@@ -644,62 +397,6 @@
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
</description>
</method>
- <method name="move_window_to_foreground">
- <return type="void">
- </return>
- <description>
- Moves the window to the front.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
- </description>
- </method>
- <method name="native_video_is_playing">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if native video is playing.
- [b]Note:[/b] This method is implemented on Android and iOS.
- </description>
- </method>
- <method name="native_video_pause">
- <return type="void">
- </return>
- <description>
- Pauses native video playback.
- [b]Note:[/b] This method is implemented on Android and iOS.
- </description>
- </method>
- <method name="native_video_play">
- <return type="int" enum="Error">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="volume" type="float">
- </argument>
- <argument index="2" name="audio_track" type="String">
- </argument>
- <argument index="3" name="subtitle_track" type="String">
- </argument>
- <description>
- Plays native video from the specified path, at the given volume and with audio and subtitle tracks.
- [b]Note:[/b] This method is implemented on Android and iOS, and the current Android implementation does not support the [code]volume[/code], [code]audio_track[/code] and [code]subtitle_track[/code] options.
- </description>
- </method>
- <method name="native_video_stop">
- <return type="void">
- </return>
- <description>
- Stops native video playback.
- [b]Note:[/b] This method is implemented on Android and iOS.
- </description>
- </method>
- <method name="native_video_unpause">
- <return type="void">
- </return>
- <description>
- Resumes native video playback.
- [b]Note:[/b] This method is implemented on Android and iOS.
- </description>
- </method>
<method name="open_midi_inputs">
<return type="void">
</return>
@@ -742,14 +439,6 @@
Shows all resources currently used by the game.
</description>
</method>
- <method name="request_attention">
- <return type="void">
- </return>
- <description>
- Request the user attention to the window. It'll flash the taskbar button on Windows or bounce the dock icon on OSX.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
- </description>
- </method>
<method name="request_permission">
<return type="bool">
</return>
@@ -767,51 +456,6 @@
[b]Note:[/b] This method is implemented on Android.
</description>
</method>
- <method name="set_icon">
- <return type="void">
- </return>
- <argument index="0" name="icon" type="Image">
- </argument>
- <description>
- Sets the game's icon using an [Image] resource.
- The same image is used for window caption, taskbar/dock and window selection dialog. Image is scaled as needed.
- [b]Note:[/b] This method is implemented on HTML5, Linux, macOS and Windows.
- </description>
- </method>
- <method name="set_ime_active">
- <return type="void">
- </return>
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- Sets whether IME input mode should be enabled.
- If active IME handles key events before the application and creates an composition string and suggestion list.
- Application can retrieve the composition status by using [method get_ime_selection] and [method get_ime_text] functions.
- Completed composition string is committed when input is finished.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
- </description>
- </method>
- <method name="set_ime_position">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <description>
- Sets position of IME suggestion list popup (in window coordinates).
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
- </description>
- </method>
- <method name="set_native_icon">
- <return type="void">
- </return>
- <argument index="0" name="filename" type="String">
- </argument>
- <description>
- Sets the game's icon using a multi-size platform-specific icon file ([code]*.ico[/code] on Windows and [code]*.icns[/code] on macOS).
- Appropriate size sub-icons are used for window caption, taskbar/dock and window selection dialog.
- [b]Note:[/b] This method is implemented on macOS and Windows.
- </description>
- </method>
<method name="set_thread_name">
<return type="int" enum="Error">
</return>
@@ -830,27 +474,6 @@
Enables backup saves if [code]enabled[/code] is [code]true[/code].
</description>
</method>
- <method name="set_window_always_on_top">
- <return type="void">
- </return>
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Sets whether the window should always be on top.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
- </description>
- </method>
- <method name="set_window_title">
- <return type="void">
- </return>
- <argument index="0" name="title" type="String">
- </argument>
- <description>
- Sets the window title to the specified string.
- [b]Note:[/b] This should be used sporadically. Don't set this every frame, as that will negatively affect performance on some window managers.
- [b]Note:[/b] This method is implemented on HTML5, Linux, macOS and Windows.
- </description>
- </method>
<method name="shell_open">
<return type="int" enum="Error">
</return>
@@ -864,82 +487,18 @@
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS and Windows.
</description>
</method>
- <method name="show_virtual_keyboard">
- <return type="void">
- </return>
- <argument index="0" name="existing_text" type="String" default="&quot;&quot;">
- </argument>
- <description>
- Shows the virtual keyboard if the platform has one. The [code]existing_text[/code] parameter is useful for implementing your own LineEdit, as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions).
- [b]Note:[/b] This method is implemented on Android, iOS and UWP.
- </description>
- </method>
</methods>
<members>
- <member name="clipboard" type="String" setter="set_clipboard" getter="get_clipboard" default="&quot;&quot;">
- The clipboard from the host OS. Might be unavailable on some platforms.
- </member>
- <member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen" default="0">
- The current screen index (starting from 0).
- </member>
<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="keep_screen_on" type="bool" setter="set_keep_screen_on" getter="is_keep_screen_on" default="true">
- If [code]true[/code], the engine tries to keep the screen on while the game is running. Useful on mobile.
- </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="max_window_size" type="Vector2" setter="set_max_window_size" getter="get_max_window_size" default="Vector2( 0, 0 )">
- The maximum size of the window (without counting window manager decorations). Does not affect fullscreen mode. Set to [code](0, 0)[/code] to reset to the system default value.
- </member>
- <member name="min_window_size" type="Vector2" setter="set_min_window_size" getter="get_min_window_size" default="Vector2( 0, 0 )">
- The minimum size of the window (without counting window manager decorations). Does not affect fullscreen mode. Set to [code](0, 0)[/code] to reset to the system default value.
- </member>
- <member name="screen_orientation" type="int" setter="set_screen_orientation" getter="get_screen_orientation" enum="_OS.ScreenOrientation" default="0">
- The current screen orientation.
- </member>
- <member name="vsync_enabled" type="bool" setter="set_use_vsync" getter="is_vsync_enabled" default="true">
- If [code]true[/code], vertical synchronization (Vsync) is enabled.
- </member>
- <member name="vsync_via_compositor" type="bool" setter="set_vsync_via_compositor" getter="is_vsync_via_compositor_enabled" default="false">
- If [code]true[/code] and [code]vsync_enabled[/code] is true, the operating system's window compositor will be used for vsync when the compositor is enabled and the game is in windowed mode.
- [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.
- [b]Note:[/b] This property is only implemented on Windows.
- </member>
- <member name="window_borderless" type="bool" setter="set_borderless_window" getter="get_borderless_window" default="false">
- If [code]true[/code], removes the window frame.
- [b]Note:[/b] Setting [code]window_borderless[/code] to [code]false[/code] disables per-pixel transparency.
- </member>
- <member name="window_fullscreen" type="bool" setter="set_window_fullscreen" getter="is_window_fullscreen" default="false">
- If [code]true[/code], the window is fullscreen.
- </member>
- <member name="window_maximized" type="bool" setter="set_window_maximized" getter="is_window_maximized" default="false">
- If [code]true[/code], the window is maximized.
- </member>
- <member name="window_minimized" type="bool" setter="set_window_minimized" getter="is_window_minimized" default="false">
- If [code]true[/code], the window is minimized.
- </member>
- <member name="window_per_pixel_transparency_enabled" type="bool" setter="set_window_per_pixel_transparency_enabled" getter="get_window_per_pixel_transparency_enabled" default="false">
- If [code]true[/code], the window background is transparent and window frame is removed.
- Use [code]get_tree().get_root().set_transparent_background(true)[/code] to disable main viewport background rendering.
- [b]Note:[/b] This property has no effect if [b]Project &gt; Project Settings &gt; Display &gt; Window &gt; Per-pixel transparency &gt; Allowed[/b] setting is disabled.
- [b]Note:[/b] This property is implemented on HTML5, Linux, macOS and Windows.
- </member>
- <member name="window_position" type="Vector2" setter="set_window_position" getter="get_window_position" default="Vector2( 0, 0 )">
- The window position relative to the screen, the origin is the top left corner, +Y axis goes to the bottom and +X axis goes to the right.
- </member>
- <member name="window_resizable" type="bool" setter="set_window_resizable" getter="is_window_resizable" default="true">
- If [code]true[/code], the window is resizable by the user.
- </member>
- <member name="window_size" type="Vector2" setter="set_window_size" getter="get_window_size" default="Vector2( 0, 0 )">
- The size of the window (without counting window manager decorations).
- </member>
</members>
<constants>
<constant name="VIDEO_DRIVER_GLES2" value="0" enum="VideoDriver">
@@ -1005,27 +564,6 @@
<constant name="MONTH_DECEMBER" value="12" enum="Month">
December.
</constant>
- <constant name="SCREEN_ORIENTATION_LANDSCAPE" value="0" enum="ScreenOrientation">
- Landscape screen orientation.
- </constant>
- <constant name="SCREEN_ORIENTATION_PORTRAIT" value="1" enum="ScreenOrientation">
- Portrait screen orientation.
- </constant>
- <constant name="SCREEN_ORIENTATION_REVERSE_LANDSCAPE" value="2" enum="ScreenOrientation">
- Reverse landscape screen orientation.
- </constant>
- <constant name="SCREEN_ORIENTATION_REVERSE_PORTRAIT" value="3" enum="ScreenOrientation">
- Reverse portrait screen orientation.
- </constant>
- <constant name="SCREEN_ORIENTATION_SENSOR_LANDSCAPE" value="4" enum="ScreenOrientation">
- Uses landscape or reverse landscape based on the hardware sensor.
- </constant>
- <constant name="SCREEN_ORIENTATION_SENSOR_PORTRAIT" value="5" enum="ScreenOrientation">
- Uses portrait or reverse portrait based on the hardware sensor.
- </constant>
- <constant name="SCREEN_ORIENTATION_SENSOR" value="6" enum="ScreenOrientation">
- Uses most suitable orientation based on the hardware sensor.
- </constant>
<constant name="SYSTEM_DIR_DESKTOP" value="0" enum="SystemDir">
Desktop directory path.
</constant>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index a3faccae1a..35e87d1a2a 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -311,13 +311,22 @@
Returns [code]true[/code] if the object contains the given [code]method[/code].
</description>
</method>
+ <method name="has_signal" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="signal" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the given [code]signal[/code] exists.
+ </description>
+ </method>
<method name="has_user_signal" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="signal" type="StringName">
</argument>
<description>
- Returns [code]true[/code] if the given user-defined [code]signal[/code] exists.
+ Returns [code]true[/code] if the given user-defined [code]signal[/code] exists. Only signals added using [method add_user_signal] are taken into account.
</description>
</method>
<method name="is_blocking_signals" qualifiers="const">
diff --git a/doc/classes/OmniLight.xml b/doc/classes/OmniLight.xml
deleted file mode 100644
index dc57efd3f9..0000000000
--- a/doc/classes/OmniLight.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OmniLight" inherits="Light" version="4.0">
- <brief_description>
- Omnidirectional light, such as a light bulb or a candle.
- </brief_description>
- <description>
- An Omnidirectional light is a type of [Light] that emits light in all directions. The light is attenuated by distance and this attenuation can be configured by changing its energy, radius, and attenuation parameters.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="omni_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
- The light's attenuation (drop-off) curve. A number of presets are available in the [b]Inspector[/b] by right-clicking the curve.
- </member>
- <member name="omni_range" type="float" setter="set_param" getter="get_param" default="5.0">
- The light's radius.
- </member>
- <member name="omni_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="OmniLight.ShadowMode" default="1">
- See [enum ShadowMode].
- </member>
- </members>
- <constants>
- <constant name="SHADOW_DUAL_PARABOLOID" value="0" enum="ShadowMode">
- Shadows are rendered to a dual-paraboloid texture. Faster than [constant SHADOW_CUBE], but lower-quality.
- </constant>
- <constant name="SHADOW_CUBE" value="1" enum="ShadowMode">
- Shadows are rendered to a cubemap. Slower than [constant SHADOW_DUAL_PARABOLOID], but higher-quality.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/OmniLight3D.xml b/doc/classes/OmniLight3D.xml
new file mode 100644
index 0000000000..0bbc987156
--- /dev/null
+++ b/doc/classes/OmniLight3D.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="OmniLight3D" inherits="Light3D" version="4.0">
+ <brief_description>
+ Omnidirectional light, such as a light bulb or a candle.
+ </brief_description>
+ <description>
+ An Omnidirectional light is a type of [Light3D] that emits light in all directions. The light is attenuated by distance and this attenuation can be configured by changing its energy, radius, and attenuation parameters.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="omni_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
+ The light's attenuation (drop-off) curve. A number of presets are available in the [b]Inspector[/b] by right-clicking the curve.
+ </member>
+ <member name="omni_range" type="float" setter="set_param" getter="get_param" default="5.0">
+ The light's radius.
+ </member>
+ <member name="omni_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="OmniLight3D.ShadowMode" default="1">
+ See [enum ShadowMode].
+ </member>
+ </members>
+ <constants>
+ <constant name="SHADOW_DUAL_PARABOLOID" value="0" enum="ShadowMode">
+ Shadows are rendered to a dual-paraboloid texture. Faster than [constant SHADOW_CUBE], but lower-quality.
+ </constant>
+ <constant name="SHADOW_CUBE" value="1" enum="ShadowMode">
+ Shadows are rendered to a cubemap. Slower than [constant SHADOW_DUAL_PARABOLOID], but higher-quality.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 5cb2aaf314..39d974ec47 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -214,14 +214,14 @@
</members>
<signals>
<signal name="item_focused">
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
Emitted the when user navigates to an item using the [code]ui_up[/code] or [code]ui_down[/code] actions. The index of the item selected is passed as argument.
</description>
</signal>
<signal name="item_selected">
- <argument index="0" name="id" type="int">
+ <argument index="0" name="index" type="int">
</argument>
<description>
Emitted when the current item has been changed by the user. The index of the item selected is passed as argument.
diff --git a/doc/classes/PackedDataContainerRef.xml b/doc/classes/PackedDataContainerRef.xml
index 9e7ed59054..f0f59675de 100644
--- a/doc/classes/PackedDataContainerRef.xml
+++ b/doc/classes/PackedDataContainerRef.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PackedDataContainerRef" inherits="Reference" version="4.0">
<brief_description>
+ Reference version of [PackedDataContainer].
</brief_description>
<description>
</description>
diff --git a/doc/classes/Panel.xml b/doc/classes/Panel.xml
index a96871ba28..7285bc9e2e 100644
--- a/doc/classes/Panel.xml
+++ b/doc/classes/Panel.xml
@@ -10,10 +10,21 @@
</tutorials>
<methods>
</methods>
+ <members>
+ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="Panel.Mode" default="0">
+ </member>
+ </members>
<constants>
+ <constant name="MODE_BACKGROUND" value="0" enum="Mode">
+ </constant>
+ <constant name="MODE_FOREGROUND" value="1" enum="Mode">
+ </constant>
</constants>
<theme_items>
<theme_item name="panel" type="StyleBox">
+ The style of this [Panel].
+ </theme_item>
+ <theme_item name="panel_fg" type="StyleBox">
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/PanelContainer.xml b/doc/classes/PanelContainer.xml
index 9803a8dc51..d39122c395 100644
--- a/doc/classes/PanelContainer.xml
+++ b/doc/classes/PanelContainer.xml
@@ -17,6 +17,7 @@
</constants>
<theme_items>
<theme_item name="panel" type="StyleBox">
+ The style of [PanelContainer]'s background.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/PanoramaSky.xml b/doc/classes/PanoramaSky.xml
deleted file mode 100644
index 0ddf1cb054..0000000000
--- a/doc/classes/PanoramaSky.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PanoramaSky" inherits="Sky" version="4.0">
- <brief_description>
- A type of [Sky] used to draw a background texture.
- </brief_description>
- <description>
- A resource referenced in an [Environment] that is used to draw a background. The Panorama sky functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cube map.
- Using an HDR panorama is strongly recommended for accurate, high-quality reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) image formats for this purpose.
- You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="panorama" type="Texture2D" setter="set_panorama" getter="get_panorama">
- [Texture2D] to be applied to the PanoramaSky.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PanoramaSkyMaterial.xml b/doc/classes/PanoramaSkyMaterial.xml
new file mode 100644
index 0000000000..905a2dd506
--- /dev/null
+++ b/doc/classes/PanoramaSkyMaterial.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PanoramaSkyMaterial" inherits="Material" version="4.0">
+ <brief_description>
+ A [Material] used with [Sky] to draw a background texture.
+ </brief_description>
+ <description>
+ A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cube map.
+ Using an HDR panorama is strongly recommended for accurate, high-quality reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) image formats for this purpose.
+ You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="panorama" type="Texture2D" setter="set_panorama" getter="get_panorama">
+ [Texture2D] to be applied to the [PanoramaSkyMaterial].
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Particles.xml b/doc/classes/Particles.xml
deleted file mode 100644
index 74651ddd2f..0000000000
--- a/doc/classes/Particles.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Particles" inherits="GeometryInstance" version="4.0">
- <brief_description>
- 3D particle emitter.
- </brief_description>
- <description>
- 3D particle node used to create a variety of particle systems and effects. [Particles] features an emitter that generates some number of particles at a given rate.
- Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/controlling_thousands_of_fish.html</link>
- </tutorials>
- <methods>
- <method name="capture_aabb" qualifiers="const">
- <return type="AABB">
- </return>
- <description>
- Returns the axis-aligned bounding box that contains all the particles that are active in the current frame.
- </description>
- </method>
- <method name="get_draw_pass_mesh" qualifiers="const">
- <return type="Mesh">
- </return>
- <argument index="0" name="pass" type="int">
- </argument>
- <description>
- Returns the [Mesh] that is drawn at index [code]pass[/code].
- </description>
- </method>
- <method name="restart">
- <return type="void">
- </return>
- <description>
- Restarts the particle emission, clearing existing particles.
- </description>
- </method>
- <method name="set_draw_pass_mesh">
- <return type="void">
- </return>
- <argument index="0" name="pass" type="int">
- </argument>
- <argument index="1" name="mesh" type="Mesh">
- </argument>
- <description>
- Sets the [Mesh] that is drawn at index [code]pass[/code].
- </description>
- </method>
- </methods>
- <members>
- <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
- Number of particles to emit.
- </member>
- <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="Particles.DrawOrder" default="0">
- Particle draw order. Uses [enum DrawOrder] values.
- </member>
- <member name="draw_pass_1" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
- [Mesh] that is drawn for the first draw pass.
- </member>
- <member name="draw_pass_2" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
- [Mesh] that is drawn for the second draw pass.
- </member>
- <member name="draw_pass_3" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
- [Mesh] that is drawn for the third draw pass.
- </member>
- <member name="draw_pass_4" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
- [Mesh] that is drawn for the fourth draw pass.
- </member>
- <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="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="false">
- 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">
- 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="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
- Amount of time each particle will exist.
- </member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
- </member>
- <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
- If [code]true[/code], only [code]amount[/code] particles will be emitted.
- </member>
- <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
- Amount of time to preprocess the particles before animation starts. Lets you start the animation some time after particles have started emitting.
- </member>
- <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
- [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
- </member>
- <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
- Emission randomness ratio.
- </member>
- <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- Speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
- </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 area of the world part of which needs to be visible on screen for the particle system to be active.
- </member>
- </members>
- <constants>
- <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
- Particles are drawn in the order emitted.
- </constant>
- <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
- Particles are drawn in order of remaining lifetime.
- </constant>
- <constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
- Particles are drawn in order of depth.
- </constant>
- <constant name="MAX_DRAW_PASSES" value="4">
- Maximum number of draw passes supported.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Particles2D.xml b/doc/classes/Particles2D.xml
deleted file mode 100644
index 50fc3680bc..0000000000
--- a/doc/classes/Particles2D.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Particles2D" inherits="Node2D" version="4.0">
- <brief_description>
- 2D particle emitter.
- </brief_description>
- <description>
- 2D particle node used to create a variety of particle systems and effects. [Particles2D] features an emitter that generates some number of particles at a given rate.
- Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
- </tutorials>
- <methods>
- <method name="capture_rect" qualifiers="const">
- <return type="Rect2">
- </return>
- <description>
- Returns a rectangle containing the positions of all existing particles.
- </description>
- </method>
- <method name="restart">
- <return type="void">
- </return>
- <description>
- Restarts all the existing particles.
- </description>
- </method>
- </methods>
- <members>
- <member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
- Number of particles emitted in one emission cycle.
- </member>
- <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="Particles2D.DrawOrder" default="0">
- Particle draw order. Uses [enum DrawOrder] values.
- </member>
- <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="false">
- 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">
- How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
- </member>
- <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
- 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="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
- Amount of time each particle will exist.
- </member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
- </member>
- <member name="normal_map" type="Texture2D" setter="set_normal_map" getter="get_normal_map">
- Normal map to be used for the [member texture] property.
- </member>
- <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
- If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
- </member>
- <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
- Particle system starts as if it had already run for this many seconds.
- </member>
- <member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
- [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
- </member>
- <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
- Emission lifetime randomness ratio.
- </member>
- <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
- </member>
- <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
- Particle texture. If [code]null[/code], particles will be squares.
- </member>
- <member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2( -100, -100, 200, 200 )">
- Editor visibility helper.
- </member>
- </members>
- <constants>
- <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
- Particles are drawn in the order emitted.
- </constant>
- <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
- Particles are drawn in order of remaining lifetime.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml
index 1e90214e47..d04ac5bdce 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticlesMaterial.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ParticlesMaterial" inherits="Material" version="4.0">
<brief_description>
- Particle properties for [Particles] and [Particles2D] nodes.
+ Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes.
</brief_description>
<description>
- ParticlesMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [Particles] and [Particles2D] emitter nodes.
+ ParticlesMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes.
Some of this material's properties are applied to each particle when emitted, while others can have a [CurveTexture] applied to vary values over the lifetime of the particle.
When a randomness ratio is applied to a property it is used to scale that property by a random amount. The random ratio is used to interpolate between [code]1.0[/code] and a random number less than one, the result is multiplied by the property to obtain the randomized property. For example a random ratio of [code]0.4[/code] would scale the original property between [code]0.4-1.0[/code] of its original value.
</description>
@@ -132,7 +132,7 @@
Animation speed randomness ratio.
</member>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )">
- Each particle's initial color. If the [Particles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code].
+ Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code].
</member>
<member name="color_ramp" type="Texture2D" setter="set_color_ramp" getter="get_color_ramp">
Each particle's color will vary along this [GradientTexture].
diff --git a/doc/classes/Path.xml b/doc/classes/Path.xml
deleted file mode 100644
index 801e86ff9e..0000000000
--- a/doc/classes/Path.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Path" inherits="Spatial" version="4.0">
- <brief_description>
- Contains a [Curve3D] path for [PathFollow] nodes to follow.
- </brief_description>
- <description>
- Can have [PathFollow] child nodes moving along the [Curve3D]. See [PathFollow] for more information on the usage.
- Note that the path is considered as relative to the moved nodes (children of [PathFollow]). As such, the curve should usually start with a zero vector [code](0, 0, 0)[/code].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="curve" type="Curve3D" setter="set_curve" getter="get_curve">
- A [Curve3D] describing the path.
- </member>
- </members>
- <signals>
- <signal name="curve_changed">
- <description>
- Emitted when the [member curve] changes.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Path3D.xml b/doc/classes/Path3D.xml
new file mode 100644
index 0000000000..b97e7efd5d
--- /dev/null
+++ b/doc/classes/Path3D.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Path3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Contains a [Curve3D] path for [PathFollow3D] nodes to follow.
+ </brief_description>
+ <description>
+ Can have [PathFollow3D] child nodes moving along the [Curve3D]. See [PathFollow3D] for more information on the usage.
+ Note that the path is considered as relative to the moved nodes (children of [PathFollow3D]). As such, the curve should usually start with a zero vector [code](0, 0, 0)[/code].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="curve" type="Curve3D" setter="set_curve" getter="get_curve">
+ A [Curve3D] describing the path.
+ </member>
+ </members>
+ <signals>
+ <signal name="curve_changed">
+ <description>
+ Emitted when the [member curve] changes.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PathFollow.xml b/doc/classes/PathFollow.xml
deleted file mode 100644
index 85ca5b787f..0000000000
--- a/doc/classes/PathFollow.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PathFollow" inherits="Spatial" version="4.0">
- <brief_description>
- Point sampler for a [Path].
- </brief_description>
- <description>
- This node takes its parent [Path], and returns the coordinates of a point within it, given a distance from the first vertex.
- It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting an offset in this node.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="cubic_interp" type="bool" setter="set_cubic_interpolation" getter="get_cubic_interpolation" default="true">
- If [code]true[/code], the position between two cached points is interpolated cubically, and linearly otherwise.
- The points along the [Curve3D] of the [Path] are precomputed before use, for faster calculations. The point at the requested offset is then calculated interpolating between two adjacent cached points. This may present a problem if the curve makes sharp turns, as the cached points may not follow the curve closely enough.
- There are two answers to this problem: either increase the number of cached points and increase memory consumption, or make a cubic interpolation between two points at the cost of (slightly) slower calculations.
- </member>
- <member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0">
- The node's offset along the curve.
- </member>
- <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true">
- If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
- </member>
- <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0">
- The distance from the first vertex, measured in 3D units along the path. This sets this node's position to a point within the path.
- </member>
- <member name="rotation_mode" type="int" setter="set_rotation_mode" getter="get_rotation_mode" enum="PathFollow.RotationMode" default="3">
- Allows or forbids rotation on one or more axes, depending on the [enum RotationMode] constants being used.
- </member>
- <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0">
- The distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length.
- </member>
- <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
- The node's offset perpendicular to the curve.
- </member>
- </members>
- <constants>
- <constant name="ROTATION_NONE" value="0" enum="RotationMode">
- Forbids the PathFollow to rotate.
- </constant>
- <constant name="ROTATION_Y" value="1" enum="RotationMode">
- Allows the PathFollow to rotate in the Y axis only.
- </constant>
- <constant name="ROTATION_XY" value="2" enum="RotationMode">
- Allows the PathFollow to rotate in both the X, and Y axes.
- </constant>
- <constant name="ROTATION_XYZ" value="3" enum="RotationMode">
- Allows the PathFollow to rotate in any axis.
- </constant>
- <constant name="ROTATION_ORIENTED" value="4" enum="RotationMode">
- Uses the up vector information in a [Curve3D] to enforce orientation. This rotation mode requires the [Path]'s [member Curve3D.up_vector_enabled] property to be set to [code]true[/code].
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml
new file mode 100644
index 0000000000..f405bdedfc
--- /dev/null
+++ b/doc/classes/PathFollow3D.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PathFollow3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Point sampler for a [Path3D].
+ </brief_description>
+ <description>
+ This node takes its parent [Path3D], and returns the coordinates of a point within it, given a distance from the first vertex.
+ It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting an offset in this node.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="cubic_interp" type="bool" setter="set_cubic_interpolation" getter="get_cubic_interpolation" default="true">
+ If [code]true[/code], the position between two cached points is interpolated cubically, and linearly otherwise.
+ The points along the [Curve3D] of the [Path3D] are precomputed before use, for faster calculations. The point at the requested offset is then calculated interpolating between two adjacent cached points. This may present a problem if the curve makes sharp turns, as the cached points may not follow the curve closely enough.
+ There are two answers to this problem: either increase the number of cached points and increase memory consumption, or make a cubic interpolation between two points at the cost of (slightly) slower calculations.
+ </member>
+ <member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0">
+ The node's offset along the curve.
+ </member>
+ <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true">
+ If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
+ </member>
+ <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0">
+ The distance from the first vertex, measured in 3D units along the path. This sets this node's position to a point within the path.
+ </member>
+ <member name="rotation_mode" type="int" setter="set_rotation_mode" getter="get_rotation_mode" enum="PathFollow3D.RotationMode" default="3">
+ Allows or forbids rotation on one or more axes, depending on the [enum RotationMode] constants being used.
+ </member>
+ <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0">
+ The distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length.
+ </member>
+ <member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
+ The node's offset perpendicular to the curve.
+ </member>
+ </members>
+ <constants>
+ <constant name="ROTATION_NONE" value="0" enum="RotationMode">
+ Forbids the PathFollow3D to rotate.
+ </constant>
+ <constant name="ROTATION_Y" value="1" enum="RotationMode">
+ Allows the PathFollow3D to rotate in the Y axis only.
+ </constant>
+ <constant name="ROTATION_XY" value="2" enum="RotationMode">
+ Allows the PathFollow3D to rotate in both the X, and Y axes.
+ </constant>
+ <constant name="ROTATION_XYZ" value="3" enum="RotationMode">
+ Allows the PathFollow3D to rotate in any axis.
+ </constant>
+ <constant name="ROTATION_ORIENTED" value="4" enum="RotationMode">
+ Uses the up vector information in a [Curve3D] to enforce orientation. This rotation mode requires the [Path3D]'s [member Curve3D.up_vector_enabled] property to be set to [code]true[/code].
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml
index 378b165644..2a0c153267 100644
--- a/doc/classes/Performance.xml
+++ b/doc/classes/Performance.xml
@@ -95,7 +95,7 @@
Number of islands in the 2D physics engine.
</constant>
<constant name="PHYSICS_3D_ACTIVE_OBJECTS" value="23" enum="Monitor">
- Number of active [RigidBody] and [VehicleBody] nodes in the game.
+ Number of active [RigidBody3D] and [VehicleBody3D] nodes in the game.
</constant>
<constant name="PHYSICS_3D_COLLISION_PAIRS" value="24" enum="Monitor">
Number of collision pairs in the 3D physics engine.
diff --git a/doc/classes/PhysicalBone.xml b/doc/classes/PhysicalBone.xml
deleted file mode 100644
index bb31f03c18..0000000000
--- a/doc/classes/PhysicalBone.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicalBone" inherits="PhysicsBody" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="apply_central_impulse">
- <return type="void">
- </return>
- <argument index="0" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="apply_impulse">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <argument index="1" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_id" qualifiers="const">
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_simulate_physics">
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_simulating_physics">
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="body_offset" type="Transform" setter="set_body_offset" getter="get_body_offset" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- </member>
- <member name="bounce" type="float" setter="set_bounce" getter="get_bounce" default="0.0">
- </member>
- <member name="friction" type="float" setter="set_friction" getter="get_friction" default="1.0">
- </member>
- <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
- </member>
- <member name="joint_offset" type="Transform" setter="set_joint_offset" getter="get_joint_offset" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- </member>
- <member name="joint_type" type="int" setter="set_joint_type" getter="get_joint_type" enum="PhysicalBone.JointType" default="0">
- </member>
- <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0">
- </member>
- <member name="weight" type="float" setter="set_weight" getter="get_weight" default="9.8">
- </member>
- </members>
- <constants>
- <constant name="JOINT_TYPE_NONE" value="0" enum="JointType">
- </constant>
- <constant name="JOINT_TYPE_PIN" value="1" enum="JointType">
- </constant>
- <constant name="JOINT_TYPE_CONE" value="2" enum="JointType">
- </constant>
- <constant name="JOINT_TYPE_HINGE" value="3" enum="JointType">
- </constant>
- <constant name="JOINT_TYPE_SLIDER" value="4" enum="JointType">
- </constant>
- <constant name="JOINT_TYPE_6DOF" value="5" enum="JointType">
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
new file mode 100644
index 0000000000..75f1f3eab4
--- /dev/null
+++ b/doc/classes/PhysicalBone3D.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicalBone3D" inherits="PhysicsBody3D" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="apply_central_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="apply_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <argument index="1" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bone_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_simulate_physics">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_simulating_physics">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="-1.0">
+ Damps the body's rotation if greater than [code]0[/code].
+ </member>
+ <member name="axis_lock_angular_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's rotation in the X axis.
+ </member>
+ <member name="axis_lock_angular_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's rotation in the Y axis.
+ </member>
+ <member name="axis_lock_angular_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's rotation in the Z axis.
+ </member>
+ <member name="axis_lock_linear_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's movement in the X axis.
+ </member>
+ <member name="axis_lock_linear_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's movement in the Y axis.
+ </member>
+ <member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's movement in the Z axis.
+ </member>
+ <member name="body_offset" type="Transform" setter="set_body_offset" getter="get_body_offset" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ Sets the body's transform.
+ </member>
+ <member name="bounce" type="float" setter="set_bounce" getter="get_bounce" default="0.0">
+ 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.
+ </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).
+ </member>
+ <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
+ This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce the body's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
+ </member>
+ <member name="joint_offset" type="Transform" setter="set_joint_offset" getter="get_joint_offset" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ Sets the joint's transform.
+ </member>
+ <member name="joint_rotation" type="Vector3" setter="set_joint_rotation" getter="get_joint_rotation" default="Vector3( 0, 0, 0 )">
+ Sets the joint's rotation in radians.
+ </member>
+ <member name="joint_rotation_degrees" type="Vector3" setter="set_joint_rotation_degrees" getter="get_joint_rotation_degrees" default="Vector3( 0, 0, 0 )">
+ Sets the joint's rotation in degrees.
+ </member>
+ <member name="joint_type" type="int" setter="set_joint_type" getter="get_joint_type" enum="PhysicalBone3D.JointType" default="0">
+ Sets the joint type. See [enum JointType] for possible values.
+ </member>
+ <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="-1.0">
+ Damps the body's movement if greater than [code]0[/code].
+ </member>
+ <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0">
+ The body's mass.
+ </member>
+ <member name="weight" type="float" setter="set_weight" getter="get_weight" default="9.8">
+ The body's weight based on its mass and the global 3D gravity. Global values are set in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b].
+ </member>
+ </members>
+ <constants>
+ <constant name="JOINT_TYPE_NONE" value="0" enum="JointType">
+ </constant>
+ <constant name="JOINT_TYPE_PIN" value="1" enum="JointType">
+ </constant>
+ <constant name="JOINT_TYPE_CONE" value="2" enum="JointType">
+ </constant>
+ <constant name="JOINT_TYPE_HINGE" value="3" enum="JointType">
+ </constant>
+ <constant name="JOINT_TYPE_SLIDER" value="4" enum="JointType">
+ </constant>
+ <constant name="JOINT_TYPE_6DOF" value="5" enum="JointType">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml
new file mode 100644
index 0000000000..89b43158dc
--- /dev/null
+++ b/doc/classes/PhysicalSkyMaterial.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicalSkyMaterial" inherits="Material" version="4.0">
+ <brief_description>
+ [Sky] [Material] used for a physically based sky.
+ </brief_description>
+ <description>
+ The [PhysicalSkyMaterial] uses the Preetham analytic daylight model to draw a sky based on physical properties. This results in a substantially more realistic sky than the [ProceduralSkyMaterial], but it is slightly slower and less flexible.
+ The [PhysicalSkyMaterial] only supports one sun. The color, energy, and direction of the sun are taken from the first [DirectionalLight3D] in the scene tree.
+ As it is based on a daylight model, the sky fades to black as the sunset ends. If you want a full day/night cycle, you will have to add a night sky by converting this to a [ShaderMaterial] and adding a night sky directly into the resulting shader.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="dither_strength" type="float" setter="set_dither_strength" getter="get_dither_strength" default="1.0">
+ Sets the amount of dithering to use. Dithering helps reduce banding that appears from the smooth changes in color in the sky. Use the lowest value possible, higher amounts may add fuzziness to the sky.
+ </member>
+ <member name="exposure" type="float" setter="set_exposure" getter="get_exposure" default="0.1">
+ Sets the exposure of the sky. Higher exposure values make the entire sky brighter.
+ </member>
+ <member name="ground_color" type="Color" setter="set_ground_color" getter="get_ground_color" default="Color( 1, 1, 1, 1 )">
+ 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.
+ </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.
+ </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.
+ </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.
+ </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.
+ </member>
+ <member name="turbidity" type="float" setter="set_turbidity" getter="get_turbidity" default="10.0">
+ Sets the thickness of the atmosphere. High turbidity creates a foggy looking atmosphere, while a low turbidity results in a clearer atmosphere.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Physics2DDirectBodyState.xml b/doc/classes/Physics2DDirectBodyState.xml
deleted file mode 100644
index d9d402ac9a..0000000000
--- a/doc/classes/Physics2DDirectBodyState.xml
+++ /dev/null
@@ -1,218 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DDirectBodyState" inherits="Object" version="4.0">
- <brief_description>
- Direct access object to a physics body in the [Physics2DServer].
- </brief_description>
- <description>
- Provides direct access to a physics body in the [Physics2DServer], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces].
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
- </tutorials>
- <methods>
- <method name="add_central_force">
- <return type="void">
- </return>
- <argument index="0" name="force" type="Vector2">
- </argument>
- <description>
- Adds a constant directional force without affecting rotation.
- </description>
- </method>
- <method name="add_force">
- <return type="void">
- </return>
- <argument index="0" name="offset" type="Vector2">
- </argument>
- <argument index="1" name="force" type="Vector2">
- </argument>
- <description>
- Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates.
- </description>
- </method>
- <method name="add_torque">
- <return type="void">
- </return>
- <argument index="0" name="torque" type="float">
- </argument>
- <description>
- Adds a constant rotational force.
- </description>
- </method>
- <method name="apply_central_impulse">
- <return type="void">
- </return>
- <argument index="0" name="impulse" type="Vector2">
- </argument>
- <description>
- Applies a directional impulse without affecting rotation.
- </description>
- </method>
- <method name="apply_impulse">
- <return type="void">
- </return>
- <argument index="0" name="offset" type="Vector2">
- </argument>
- <argument index="1" name="impulse" type="Vector2">
- </argument>
- <description>
- Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise). The offset uses the rotation of the global coordinate system, but is centered at the object's origin.
- </description>
- </method>
- <method name="apply_torque_impulse">
- <return type="void">
- </return>
- <argument index="0" name="impulse" type="float">
- </argument>
- <description>
- Applies a rotational impulse to the body.
- </description>
- </method>
- <method name="get_contact_collider" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider's [RID].
- </description>
- </method>
- <method name="get_contact_collider_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider's object id.
- </description>
- </method>
- <method name="get_contact_collider_object" qualifiers="const">
- <return type="Object">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider object. This depends on how it was created (will return a scene node if such was used to create it).
- </description>
- </method>
- <method name="get_contact_collider_position" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the contact position in the collider.
- </description>
- </method>
- <method name="get_contact_collider_shape" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider's shape index.
- </description>
- </method>
- <method name="get_contact_collider_shape_metadata" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collided shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- </description>
- </method>
- <method name="get_contact_collider_velocity_at_position" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the linear velocity vector at the collider's contact point.
- </description>
- </method>
- <method name="get_contact_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of contacts this body has with other bodies.
- [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody2D.contact_monitor].
- </description>
- </method>
- <method name="get_contact_local_normal" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the local normal at the contact point.
- </description>
- </method>
- <method name="get_contact_local_position" qualifiers="const">
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the local position of the contact point.
- </description>
- </method>
- <method name="get_contact_local_shape" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the local shape index of the collision.
- </description>
- </method>
- <method name="get_space_state">
- <return type="Physics2DDirectSpaceState">
- </return>
- <description>
- Returns the current state of the space, useful for queries.
- </description>
- </method>
- <method name="integrate_forces">
- <return type="void">
- </return>
- <description>
- Calls the built-in force integration code.
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity">
- The body's rotational velocity.
- </member>
- <member name="inverse_inertia" type="float" setter="" getter="get_inverse_inertia">
- The inverse of the inertia of the body.
- </member>
- <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass">
- The inverse of the mass of the body.
- </member>
- <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity">
- The body's linear velocity.
- </member>
- <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping">
- If [code]true[/code], this body is currently sleeping (not active).
- </member>
- <member name="step" type="float" setter="" getter="get_step">
- The timestep (delta) used for the simulation.
- </member>
- <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp">
- The rate at which the body stops rotating, if there are not any other forces moving it.
- </member>
- <member name="total_gravity" type="Vector2" setter="" getter="get_total_gravity">
- The total gravity vector being currently applied to this body.
- </member>
- <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp">
- The rate at which the body stops moving, if there are not any other forces moving it.
- </member>
- <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform">
- The body's transformation matrix.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DDirectBodyStateSW.xml b/doc/classes/Physics2DDirectBodyStateSW.xml
deleted file mode 100644
index 11f1140ca8..0000000000
--- a/doc/classes/Physics2DDirectBodyStateSW.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DDirectBodyStateSW" inherits="Physics2DDirectBodyState" version="4.0">
- <brief_description>
- Software implementation of [Physics2DDirectBodyState].
- </brief_description>
- <description>
- Software implementation of [Physics2DDirectBodyState]. This object exposes no new methods or properties and should not be used, as [Physics2DDirectBodyState] selects the best implementation available.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DDirectSpaceState.xml b/doc/classes/Physics2DDirectSpaceState.xml
deleted file mode 100644
index 662a823d84..0000000000
--- a/doc/classes/Physics2DDirectSpaceState.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DDirectSpaceState" inherits="Object" version="4.0">
- <brief_description>
- Direct access object to a space in the [Physics2DServer].
- </brief_description>
- <description>
- Direct access object to a space in the [Physics2DServer]. It's used mainly to do queries against objects and areas residing in a given space.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
- </tutorials>
- <methods>
- <method name="cast_motion">
- <return type="Array">
- </return>
- <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
- </argument>
- <description>
- Checks how far the shape can travel toward a point. If the shape can not move, the array will be empty.
- [b]Note:[/b] Both the shape and the motion are supplied through a [Physics2DShapeQueryParameters] object. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code].
- </description>
- </method>
- <method name="collide_shape">
- <return type="Array">
- </return>
- <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
- </argument>
- <argument index="1" name="max_results" type="int" default="32">
- </argument>
- <description>
- Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
- </description>
- </method>
- <method name="get_rest_info">
- <return type="Dictionary">
- </return>
- <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
- </argument>
- <description>
- Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space. If it collides with more than one shape, the nearest one is selected. If the shape did not intersect anything, then an empty dictionary is returned instead.
- [b]Note:[/b] This method does not take into account the [code]motion[/code] property of the object. The returned object is a dictionary containing the following fields:
- [code]collider_id[/code]: The colliding object's ID.
- [code]linear_velocity[/code]: The colliding object's velocity [Vector2]. If the object is an [Area2D], the result is [code](0, 0)[/code].
- [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- [code]normal[/code]: The object's surface normal at the intersection point.
- [code]point[/code]: The intersection point.
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- </description>
- </method>
- <method name="intersect_point">
- <return type="Array">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="max_results" type="int" default="32">
- </argument>
- <argument index="2" name="exclude" type="Array" default="[ ]">
- </argument>
- <argument index="3" name="collision_layer" type="int" default="2147483647">
- </argument>
- <argument index="4" name="collide_with_bodies" type="bool" default="true">
- </argument>
- <argument index="5" name="collide_with_areas" type="bool" default="false">
- </argument>
- <description>
- Checks whether a point is inside any shape. The shapes the point is inside of are returned in an array containing dictionaries with the following fields:
- [code]collider[/code]: The colliding object.
- [code]collider_id[/code]: The colliding object's ID.
- [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody]s or [Area]s, respectively.
- </description>
- </method>
- <method name="intersect_point_on_canvas">
- <return type="Array">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="canvas_instance_id" type="int">
- </argument>
- <argument index="2" name="max_results" type="int" default="32">
- </argument>
- <argument index="3" name="exclude" type="Array" default="[ ]">
- </argument>
- <argument index="4" name="collision_layer" type="int" default="2147483647">
- </argument>
- <argument index="5" name="collide_with_bodies" type="bool" default="true">
- </argument>
- <argument index="6" name="collide_with_areas" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="intersect_ray">
- <return type="Dictionary">
- </return>
- <argument index="0" name="from" type="Vector2">
- </argument>
- <argument index="1" name="to" type="Vector2">
- </argument>
- <argument index="2" name="exclude" type="Array" default="[ ]">
- </argument>
- <argument index="3" name="collision_layer" type="int" default="2147483647">
- </argument>
- <argument index="4" name="collide_with_bodies" type="bool" default="true">
- </argument>
- <argument index="5" name="collide_with_areas" type="bool" default="false">
- </argument>
- <description>
- Intersects a ray in a given space. The returned object is a dictionary with the following fields:
- [code]collider[/code]: The colliding object.
- [code]collider_id[/code]: The colliding object's ID.
- [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- [code]normal[/code]: The object's surface normal at the intersection point.
- [code]position[/code]: The intersection point.
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- If the ray did not intersect anything, then an empty dictionary is returned instead.
- Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody]s or [Area]s, respectively.
- </description>
- </method>
- <method name="intersect_shape">
- <return type="Array">
- </return>
- <argument index="0" name="shape" type="Physics2DShapeQueryParameters">
- </argument>
- <argument index="1" name="max_results" type="int" default="32">
- </argument>
- <description>
- Checks the intersections of a shape, given through a [Physics2DShapeQueryParameters] object, against the space.
- [b]Note:[/b] This method does not take into account the [code]motion[/code] property of the object. The intersected shapes are returned in an array containing dictionaries with the following fields:
- [code]collider[/code]: The colliding object.
- [code]collider_id[/code]: The colliding object's ID.
- [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method Physics2DServer.shape_set_data].
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml
deleted file mode 100644
index 45215253be..0000000000
--- a/doc/classes/Physics2DServer.xml
+++ /dev/null
@@ -1,1284 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DServer" inherits="Object" version="4.0">
- <brief_description>
- Server interface for low-level 2D physics access.
- </brief_description>
- <description>
- Physics2DServer is the server responsible for all 2D physics. It can create many kinds of physics objects, but does not insert them on the node tree.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="area_add_shape">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
- </argument>
- <argument index="3" name="disabled" type="bool" default="false">
- </argument>
- <description>
- Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
- </description>
- </method>
- <method name="area_attach_canvas_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_attach_object_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Assigns the area to a descendant of [Object], so it can exist in the node tree.
- </description>
- </method>
- <method name="area_clear_shapes">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Removes all shapes from an area. It does not delete the shapes, so they can be reassigned later.
- </description>
- </method>
- <method name="area_create">
- <return type="RID">
- </return>
- <description>
- Creates an [Area2D].
- </description>
- </method>
- <method name="area_get_canvas_instance_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_object_instance_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Gets the instance ID of the object the area is assigned to.
- </description>
- </method>
- <method name="area_get_param" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.AreaParameter">
- </argument>
- <description>
- Returns an area parameter value. See [enum AreaParameter] for a list of available parameters.
- </description>
- </method>
- <method name="area_get_shape" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the [RID] of the nth shape of an area.
- </description>
- </method>
- <method name="area_get_shape_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the number of shapes assigned to an area.
- </description>
- </method>
- <method name="area_get_shape_transform" qualifiers="const">
- <return type="Transform2D">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the transform matrix of a shape within an area.
- </description>
- </method>
- <method name="area_get_space" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the space assigned to the area.
- </description>
- </method>
- <method name="area_get_space_override_mode" qualifiers="const">
- <return type="int" enum="Physics2DServer.AreaSpaceOverrideMode">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the space override mode for the area.
- </description>
- </method>
- <method name="area_get_transform" qualifiers="const">
- <return type="Transform2D">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the transform matrix for an area.
- </description>
- </method>
- <method name="area_remove_shape">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Removes a shape from an area. It does not delete the shape, so it can be reassigned later.
- </description>
- </method>
- <method name="area_set_area_monitor_callback">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_collision_layer">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="layer" type="int">
- </argument>
- <description>
- Assigns the area to one or many physics layers.
- </description>
- </method>
- <method name="area_set_collision_mask">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- Sets which physics layers the area will monitor.
- </description>
- </method>
- <method name="area_set_monitor_callback">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
- </argument>
- <description>
- Sets the function to call when any body/area enters or exits the area. This callback will be called for any object interacting with the area, and takes five parameters:
- 1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on whether the object entered or exited the area.
- 2: [RID] of the object that entered/exited the area.
- 3: Instance ID of the object that entered/exited the area.
- 4: The shape index of the object that entered/exited the area.
- 5: The shape index of the area where the object entered/exited.
- </description>
- </method>
- <method name="area_set_monitorable">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="monitorable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_param">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.AreaParameter">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- Sets the value for an area parameter. See [enum AreaParameter] for a list of available parameters.
- </description>
- </method>
- <method name="area_set_shape">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- Substitutes a given area shape by another. The old shape is selected by its index, the new one by its [RID].
- </description>
- </method>
- <method name="area_set_shape_disabled">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="disabled" type="bool">
- </argument>
- <description>
- Disables a given shape in an area.
- </description>
- </method>
- <method name="area_set_shape_transform">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the transform matrix for an area shape.
- </description>
- </method>
- <method name="area_set_space">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <description>
- Assigns a space to the area.
- </description>
- </method>
- <method name="area_set_space_override_mode">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="Physics2DServer.AreaSpaceOverrideMode">
- </argument>
- <description>
- Sets the space override mode for the area. See [enum AreaSpaceOverrideMode] for a list of available modes.
- </description>
- </method>
- <method name="area_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the transform matrix for an area.
- </description>
- </method>
- <method name="body_add_central_force">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="force" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_collision_exception">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="excepted_body" type="RID">
- </argument>
- <description>
- Adds a body to the list of bodies exempt from collisions.
- </description>
- </method>
- <method name="body_add_force">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="offset" type="Vector2">
- </argument>
- <argument index="2" name="force" type="Vector2">
- </argument>
- <description>
- Adds a positioned force to the applied force and torque. As with [method body_apply_impulse], both the force and the offset from the body origin are in global coordinates. A force differs from an impulse in that, while the two are forces, the impulse clears itself after being applied.
- </description>
- </method>
- <method name="body_add_shape">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
- </argument>
- <argument index="3" name="disabled" type="bool" default="false">
- </argument>
- <description>
- Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
- </description>
- </method>
- <method name="body_add_torque">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="torque" type="float">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_central_impulse">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="impulse" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_impulse">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="position" type="Vector2">
- </argument>
- <argument index="2" name="impulse" type="Vector2">
- </argument>
- <description>
- Adds a positioned impulse to the applied force and torque. Both the force and the offset from the body origin are in global coordinates.
- </description>
- </method>
- <method name="body_apply_torque_impulse">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="impulse" type="float">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_attach_canvas_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_attach_object_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Assigns the area to a descendant of [Object], so it can exist in the node tree.
- </description>
- </method>
- <method name="body_clear_shapes">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Removes all shapes from a body.
- </description>
- </method>
- <method name="body_create">
- <return type="RID">
- </return>
- <description>
- Creates a physics body.
- </description>
- </method>
- <method name="body_get_canvas_instance_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_collision_layer" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the physics layer or layers a body belongs to.
- </description>
- </method>
- <method name="body_get_collision_mask" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the physics layer or layers a body can collide with.
- </description>
- </method>
- <method name="body_get_continuous_collision_detection_mode" qualifiers="const">
- <return type="int" enum="Physics2DServer.CCDMode">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the continuous collision detection mode.
- </description>
- </method>
- <method name="body_get_direct_state">
- <return type="Physics2DDirectBodyState">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the [Physics2DDirectBodyState] of the body.
- </description>
- </method>
- <method name="body_get_max_contacts_reported" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the maximum contacts that can be reported. See [method body_set_max_contacts_reported].
- </description>
- </method>
- <method name="body_get_mode" qualifiers="const">
- <return type="int" enum="Physics2DServer.BodyMode">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the body mode.
- </description>
- </method>
- <method name="body_get_object_instance_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Gets the instance ID of the object the area is assigned to.
- </description>
- </method>
- <method name="body_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.BodyParameter">
- </argument>
- <description>
- Returns the value of a body parameter. See [enum BodyParameter] for a list of available parameters.
- </description>
- </method>
- <method name="body_get_shape" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the [RID] of the nth shape of a body.
- </description>
- </method>
- <method name="body_get_shape_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the number of shapes assigned to a body.
- </description>
- </method>
- <method name="body_get_shape_metadata" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the metadata of a shape of a body.
- </description>
- </method>
- <method name="body_get_shape_transform" qualifiers="const">
- <return type="Transform2D">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the transform matrix of a body shape.
- </description>
- </method>
- <method name="body_get_space" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the [RID] of the space assigned to a body.
- </description>
- </method>
- <method name="body_get_state" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int" enum="Physics2DServer.BodyState">
- </argument>
- <description>
- Returns a body state.
- </description>
- </method>
- <method name="body_is_omitting_force_integration" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- 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_remove_collision_exception">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="excepted_body" type="RID">
- </argument>
- <description>
- Removes a body from the list of bodies exempt from collisions.
- </description>
- </method>
- <method name="body_remove_shape">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Removes a shape from a body. The shape is not deleted, so it can be reused afterwards.
- </description>
- </method>
- <method name="body_set_axis_velocity">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis_velocity" type="Vector2">
- </argument>
- <description>
- Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
- </description>
- </method>
- <method name="body_set_collision_layer">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="layer" type="int">
- </argument>
- <description>
- Sets the physics layer or layers a body belongs to.
- </description>
- </method>
- <method name="body_set_collision_mask">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- Sets the physics layer or layers a body can collide with.
- </description>
- </method>
- <method name="body_set_continuous_collision_detection_mode">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="Physics2DServer.CCDMode">
- </argument>
- <description>
- Sets the continuous collision detection mode using one of the [enum CCDMode] constants.
- Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
- </description>
- </method>
- <method name="body_set_force_integration_callback">
- <return type="void">
- </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>
- <argument index="3" 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]).
- </description>
- </method>
- <method name="body_set_max_contacts_reported">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="amount" type="int">
- </argument>
- <description>
- Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
- </description>
- </method>
- <method name="body_set_mode">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="Physics2DServer.BodyMode">
- </argument>
- <description>
- Sets the body mode using one of the [enum BodyMode] constants.
- </description>
- </method>
- <method name="body_set_omit_force_integration">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
- </description>
- </method>
- <method name="body_set_param">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.BodyParameter">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets a body parameter. See [enum BodyParameter] for a list of available parameters.
- </description>
- </method>
- <method name="body_set_shape">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- Substitutes a given body shape by another. The old shape is selected by its index, the new one by its [RID].
- </description>
- </method>
- <method name="body_set_shape_as_one_way_collision">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="enable" type="bool">
- </argument>
- <argument index="3" name="margin" type="float">
- </argument>
- <description>
- Enables one way collision on body if [code]enable[/code] is [code]true[/code].
- </description>
- </method>
- <method name="body_set_shape_disabled">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="disabled" type="bool">
- </argument>
- <description>
- Disables shape in body if [code]disable[/code] is [code]true[/code].
- </description>
- </method>
- <method name="body_set_shape_metadata">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="metadata" type="Variant">
- </argument>
- <description>
- Sets metadata of a shape within a body. This metadata is different from [method Object.set_meta], and can be retrieved on shape queries.
- </description>
- </method>
- <method name="body_set_shape_transform">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the transform matrix for a body shape.
- </description>
- </method>
- <method name="body_set_space">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <description>
- Assigns a space to the body (see [method space_create]).
- </description>
- </method>
- <method name="body_set_state">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int" enum="Physics2DServer.BodyState">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- Sets a body state using one of the [enum BodyState] constants.
- </description>
- </method>
- <method name="body_test_motion">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="from" type="Transform2D">
- </argument>
- <argument index="2" name="motion" type="Vector2">
- </argument>
- <argument index="3" name="infinite_inertia" type="bool">
- </argument>
- <argument index="4" name="margin" type="float" default="0.08">
- </argument>
- <argument index="5" name="result" type="Physics2DTestMotionResult" default="null">
- </argument>
- <description>
- Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [Physics2DTestMotionResult] can be passed to return additional information in.
- </description>
- </method>
- <method name="capsule_shape_create">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="circle_shape_create">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="concave_polygon_shape_create">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="convex_polygon_shape_create">
- <return type="RID">
- </return>
- <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_string_joint_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.DampedStringParam">
- </argument>
- <description>
- Returns the value of a damped spring joint parameter.
- </description>
- </method>
- <method name="damped_string_joint_set_param">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.DampedStringParam">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets a damped spring joint parameter. See [enum DampedStringParam] for a list of available parameters.
- </description>
- </method>
- <method name="free_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Destroys any of the objects created by Physics2DServer. If the [RID] passed is not one of the objects that can be created by Physics2DServer, an error will be sent to the console.
- </description>
- </method>
- <method name="get_process_info">
- <return type="int">
- </return>
- <argument index="0" name="process_info" type="int" enum="Physics2DServer.ProcessInfo">
- </argument>
- <description>
- 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">
- </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>
- <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_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.JointParam">
- </argument>
- <description>
- Returns the value of a joint parameter.
- </description>
- </method>
- <method name="joint_get_type" qualifiers="const">
- <return type="int" enum="Physics2DServer.JointType">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <description>
- Returns a joint's type (see [enum JointType]).
- </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="Physics2DServer.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="pin_joint_create">
- <return type="RID">
- </return>
- <argument index="0" name="anchor" type="Vector2">
- </argument>
- <argument index="1" name="body_a" type="RID">
- </argument>
- <argument index="2" 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="ray_shape_create">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="rectangle_shape_create">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="segment_shape_create">
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="set_active">
- <return type="void">
- </return>
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- Activates or deactivates the 2D physics engine.
- </description>
- </method>
- <method name="shape_get_data" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- Returns the shape data.
- </description>
- </method>
- <method name="shape_get_type" qualifiers="const">
- <return type="int" enum="Physics2DServer.ShapeType">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- Returns a shape's type (see [enum ShapeType]).
- </description>
- </method>
- <method name="shape_set_data">
- <return type="void">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <description>
- Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type].
- </description>
- </method>
- <method name="space_create">
- <return type="RID">
- </return>
- <description>
- Creates a space. A space is a collection of parameters for the physics engine that can be assigned to an area or a body. It can be assigned to an area with [method area_set_space], or to a body with [method body_set_space].
- </description>
- </method>
- <method name="space_get_direct_state">
- <return type="Physics2DDirectSpaceState">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <description>
- Returns the state of a space, a [Physics2DDirectSpaceState]. This object can be used to make collision/intersection queries.
- </description>
- </method>
- <method name="space_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.SpaceParameter">
- </argument>
- <description>
- Returns the value of a space parameter.
- </description>
- </method>
- <method name="space_is_active" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <description>
- Returns whether the space is active.
- </description>
- </method>
- <method name="space_set_active">
- <return type="void">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="active" type="bool">
- </argument>
- <description>
- Marks a space as active. It will not have an effect, unless it is assigned to an area or body.
- </description>
- </method>
- <method name="space_set_param">
- <return type="void">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="Physics2DServer.SpaceParameter">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets the value for a space parameter. See [enum SpaceParameter] for a list of available parameters.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="SPACE_PARAM_CONTACT_RECYCLE_RADIUS" value="0" enum="SpaceParameter">
- Constant to set/get the maximum distance a pair of bodies has to move before their collision status has to be recalculated.
- </constant>
- <constant name="SPACE_PARAM_CONTACT_MAX_SEPARATION" value="1" enum="SpaceParameter">
- Constant to set/get the maximum distance a shape can be from another before they are considered separated.
- </constant>
- <constant name="SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION" value="2" enum="SpaceParameter">
- Constant to set/get the maximum distance a shape can penetrate another shape before it is considered a collision.
- </constant>
- <constant name="SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD" value="3" enum="SpaceParameter">
- Constant to set/get the threshold linear velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
- </constant>
- <constant name="SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD" value="4" enum="SpaceParameter">
- Constant to set/get the threshold angular velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
- </constant>
- <constant name="SPACE_PARAM_BODY_TIME_TO_SLEEP" value="5" enum="SpaceParameter">
- Constant to set/get the maximum time of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after this time.
- </constant>
- <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="6" enum="SpaceParameter">
- Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
- </constant>
- <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="7" enum="SpaceParameter">
- </constant>
- <constant name="SHAPE_LINE" value="0" enum="ShapeType">
- This is the constant for creating line shapes. A line shape is an infinite line with an origin point, and a normal. Thus, it can be used for front/behind checks.
- </constant>
- <constant name="SHAPE_RAY" value="1" enum="ShapeType">
- </constant>
- <constant name="SHAPE_SEGMENT" value="2" enum="ShapeType">
- This is the constant for creating segment shapes. A segment shape is a line from a point A to a point B. It can be checked for intersections.
- </constant>
- <constant name="SHAPE_CIRCLE" value="3" enum="ShapeType">
- This is the constant for creating circle shapes. A circle shape only has a radius. It can be used for intersections and inside/outside checks.
- </constant>
- <constant name="SHAPE_RECTANGLE" value="4" enum="ShapeType">
- This is the constant for creating rectangle shapes. A rectangle shape is defined by a width and a height. It can be used for intersections and inside/outside checks.
- </constant>
- <constant name="SHAPE_CAPSULE" value="5" enum="ShapeType">
- This is the constant for creating capsule shapes. A capsule shape is defined by a radius and a length. It can be used for intersections and inside/outside checks.
- </constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
- This is the constant for creating convex polygon shapes. A polygon is defined by a list of points. It can be used for intersections and inside/outside checks. Unlike the [member CollisionPolygon2D.polygon] property, polygons modified with [method shape_set_data] do not verify that the points supplied form is a convex polygon.
- </constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
- This is the constant for creating concave polygon shapes. A polygon is defined by a list of points. It can be used for intersections checks, but not for inside/outside checks.
- </constant>
- <constant name="SHAPE_CUSTOM" value="8" 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">
- Constant to set/get gravity strength in an area.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_VECTOR" value="1" enum="AreaParameter">
- Constant to set/get gravity vector/center in an area.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="2" enum="AreaParameter">
- Constant to set/get whether the gravity vector of an area is a direction, or a center point.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_DISTANCE_SCALE" value="3" enum="AreaParameter">
- Constant to set/get the falloff factor for point gravity of an area. The greater this value is, the faster the strength of gravity decreases with the square of distance.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4" enum="AreaParameter">
- This constant was used to set/get the falloff factor for point gravity. It has been superseded by [constant AREA_PARAM_GRAVITY_DISTANCE_SCALE].
- </constant>
- <constant name="AREA_PARAM_LINEAR_DAMP" value="5" enum="AreaParameter">
- Constant to set/get the linear dampening factor of an area.
- </constant>
- <constant name="AREA_PARAM_ANGULAR_DAMP" value="6" enum="AreaParameter">
- Constant to set/get the angular dampening factor of an area.
- </constant>
- <constant name="AREA_PARAM_PRIORITY" value="7" enum="AreaParameter">
- Constant to set/get the priority (order of processing) of an area.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_DISABLED" value="0" enum="AreaSpaceOverrideMode">
- This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1" enum="AreaSpaceOverrideMode">
- This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_COMBINE_REPLACE" value="2" enum="AreaSpaceOverrideMode">
- This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="3" enum="AreaSpaceOverrideMode">
- This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_REPLACE_COMBINE" value="4" enum="AreaSpaceOverrideMode">
- This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
- </constant>
- <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode">
- Constant for static bodies.
- </constant>
- <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
- Constant for kinematic bodies.
- </constant>
- <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
- Constant for rigid bodies.
- </constant>
- <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode">
- Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics.
- </constant>
- <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
- Constant to set/get a body's bounce factor.
- </constant>
- <constant name="BODY_PARAM_FRICTION" value="1" enum="BodyParameter">
- Constant to set/get a body's friction.
- </constant>
- <constant name="BODY_PARAM_MASS" value="2" enum="BodyParameter">
- Constant to set/get a body's mass.
- </constant>
- <constant name="BODY_PARAM_INERTIA" value="3" enum="BodyParameter">
- Constant to set/get a body's inertia.
- </constant>
- <constant name="BODY_PARAM_GRAVITY_SCALE" value="4" enum="BodyParameter">
- Constant to set/get a body's gravity multiplier.
- </constant>
- <constant name="BODY_PARAM_LINEAR_DAMP" value="5" enum="BodyParameter">
- Constant to set/get a body's linear dampening factor.
- </constant>
- <constant name="BODY_PARAM_ANGULAR_DAMP" value="6" enum="BodyParameter">
- Constant to set/get a body's angular dampening factor.
- </constant>
- <constant name="BODY_PARAM_MAX" value="7" enum="BodyParameter">
- Represents the size of the [enum BodyParameter] enum.
- </constant>
- <constant name="BODY_STATE_TRANSFORM" value="0" enum="BodyState">
- Constant to set/get the current transform matrix of the body.
- </constant>
- <constant name="BODY_STATE_LINEAR_VELOCITY" value="1" enum="BodyState">
- Constant to set/get the current linear velocity of the body.
- </constant>
- <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2" enum="BodyState">
- Constant to set/get the current angular velocity of the body.
- </constant>
- <constant name="BODY_STATE_SLEEPING" value="3" enum="BodyState">
- Constant to sleep/wake up a body, or to get whether it is sleeping.
- </constant>
- <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 to create pin joints.
- </constant>
- <constant name="JOINT_GROOVE" value="1" enum="JointType">
- Constant to create groove joints.
- </constant>
- <constant name="JOINT_DAMPED_SPRING" value="2" enum="JointType">
- Constant to create damped spring joints.
- </constant>
- <constant name="JOINT_PARAM_BIAS" value="0" enum="JointParam">
- </constant>
- <constant name="JOINT_PARAM_MAX_BIAS" value="1" enum="JointParam">
- </constant>
- <constant name="JOINT_PARAM_MAX_FORCE" value="2" enum="JointParam">
- </constant>
- <constant name="DAMPED_STRING_REST_LENGTH" value="0" enum="DampedStringParam">
- Sets the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
- </constant>
- <constant name="DAMPED_STRING_STIFFNESS" value="1" enum="DampedStringParam">
- Sets the stiffness of the spring joint. The joint applies a force equal to the stiffness times the distance from its resting length.
- </constant>
- <constant name="DAMPED_STRING_DAMPING" value="2" enum="DampedStringParam">
- Sets the damping ratio of the spring joint. A value of 0 indicates an undamped spring, while 1 causes the system to reach equilibrium as fast as possible (critical damping).
- </constant>
- <constant name="CCD_MODE_DISABLED" value="0" enum="CCDMode">
- Disables continuous collision detection. This is the fastest way to detect body collisions, but can miss small, fast-moving objects.
- </constant>
- <constant name="CCD_MODE_CAST_RAY" value="1" enum="CCDMode">
- Enables continuous collision detection by raycasting. It is faster than shapecasting, but less precise.
- </constant>
- <constant name="CCD_MODE_CAST_SHAPE" value="2" enum="CCDMode">
- Enables continuous collision detection by shapecasting. It is the slowest CCD method, and the most precise.
- </constant>
- <constant name="AREA_BODY_ADDED" value="0" enum="AreaBodyStatus">
- The value of the first parameter and area callback function receives, when an object enters one of its shapes.
- </constant>
- <constant name="AREA_BODY_REMOVED" value="1" enum="AreaBodyStatus">
- The value of the first parameter and area callback function receives, when an object exits one of its shapes.
- </constant>
- <constant name="INFO_ACTIVE_OBJECTS" value="0" enum="ProcessInfo">
- Constant to get the number of objects that are not sleeping.
- </constant>
- <constant name="INFO_COLLISION_PAIRS" value="1" enum="ProcessInfo">
- Constant to get the number of possible collisions.
- </constant>
- <constant name="INFO_ISLAND_COUNT" value="2" enum="ProcessInfo">
- Constant to get the number of space regions where a collision could occur.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DServerSW.xml b/doc/classes/Physics2DServerSW.xml
deleted file mode 100644
index 1e4531ed66..0000000000
--- a/doc/classes/Physics2DServerSW.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DServerSW" inherits="Physics2DServer" version="4.0">
- <brief_description>
- Software implementation of [Physics2DServer].
- </brief_description>
- <description>
- This class exposes no new methods or properties and should not be used, as [Physics2DServer] automatically selects the best implementation available.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DShapeQueryParameters.xml b/doc/classes/Physics2DShapeQueryParameters.xml
deleted file mode 100644
index 392ccbd10a..0000000000
--- a/doc/classes/Physics2DShapeQueryParameters.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DShapeQueryParameters" inherits="Reference" version="4.0">
- <brief_description>
- Parameters to be sent to a 2D shape physics query.
- </brief_description>
- <description>
- This class contains the shape and other parameters for 2D intersection/collision queries. See also [Physics2DShapeQueryResult].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="set_shape">
- <return type="void">
- </return>
- <argument index="0" name="shape" type="Resource">
- </argument>
- <description>
- Sets the [Shape2D] that will be used for collision/intersection queries.
- </description>
- </method>
- </methods>
- <members>
- <member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
- If [code]true[/code], the query will take [Area2D]s into account.
- </member>
- <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
- If [code]true[/code], the query will take [PhysicsBody2D]s into account.
- </member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="2147483647">
- The physics layer(s) the query will take into account (as a bitmask).
- </member>
- <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]">
- The list of objects or object [RID]s that will be excluded from collisions.
- </member>
- <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
- The collision margin for the shape.
- </member>
- <member name="motion" type="Vector2" setter="set_motion" getter="get_motion" default="Vector2( 0, 0 )">
- The motion of the shape being queried for.
- </member>
- <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid">
- The queried shape's [RID]. See also [method set_shape].
- </member>
- <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
- The queried shape's transform matrix.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DShapeQueryResult.xml b/doc/classes/Physics2DShapeQueryResult.xml
deleted file mode 100644
index 359a716bee..0000000000
--- a/doc/classes/Physics2DShapeQueryResult.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DShapeQueryResult" inherits="Reference" version="4.0">
- <brief_description>
- Result of a 2D shape query in [Physics2DServer].
- </brief_description>
- <description>
- The result of a 2D shape query in [Physics2DServer]. See also [Physics2DShapeQueryParameters].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_result_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of objects that intersected with the shape.
- </description>
- </method>
- <method name="get_result_object" qualifiers="const">
- <return type="Object">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the [Object] that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- <method name="get_result_object_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the instance ID of the [Object] that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- <method name="get_result_object_shape" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the child index of the object's [Shape] that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- <method name="get_result_rid" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the [RID] of the object that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Physics2DTestMotionResult.xml b/doc/classes/Physics2DTestMotionResult.xml
deleted file mode 100644
index 9e8c03580f..0000000000
--- a/doc/classes/Physics2DTestMotionResult.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Physics2DTestMotionResult" inherits="Reference" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="collider" type="Object" setter="" getter="get_collider">
- </member>
- <member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
- </member>
- <member name="collider_rid" type="RID" setter="" getter="get_collider_rid">
- </member>
- <member name="collider_shape" type="int" setter="" getter="get_collider_shape" default="0">
- </member>
- <member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2( 0, 0 )">
- </member>
- <member name="collision_normal" type="Vector2" setter="" getter="get_collision_normal" default="Vector2( 0, 0 )">
- </member>
- <member name="collision_point" type="Vector2" setter="" getter="get_collision_point" default="Vector2( 0, 0 )">
- </member>
- <member name="motion" type="Vector2" setter="" getter="get_motion" default="Vector2( 0, 0 )">
- </member>
- <member name="motion_remainder" type="Vector2" setter="" getter="get_motion_remainder" default="Vector2( 0, 0 )">
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsBody.xml b/doc/classes/PhysicsBody.xml
deleted file mode 100644
index c0927a5b53..0000000000
--- a/doc/classes/PhysicsBody.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsBody" inherits="CollisionObject" version="4.0">
- <brief_description>
- Base class for all objects affected by physics in 3D space.
- </brief_description>
- <description>
- PhysicsBody is an abstract base class for implementing a physics body. All *Body types inherit from it.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
- </tutorials>
- <methods>
- <method name="add_collision_exception_with">
- <return type="void">
- </return>
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- Adds a body to the list of bodies that this body can't collide with.
- </description>
- </method>
- <method name="get_collision_exceptions">
- <return type="Array">
- </return>
- <description>
- 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>
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- 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.
- </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.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
new file mode 100644
index 0000000000..f0ba2a7f5f
--- /dev/null
+++ b/doc/classes/PhysicsBody3D.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsBody3D" inherits="CollisionObject3D" version="4.0">
+ <brief_description>
+ Base class for all objects affected by physics in 3D space.
+ </brief_description>
+ <description>
+ PhysicsBody3D is an abstract base class for implementing a physics body. All *Body types inherit from it.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ </tutorials>
+ <methods>
+ <method name="add_collision_exception_with">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ Adds a body to the list of bodies that this body can't collide with.
+ </description>
+ </method>
+ <method name="get_collision_exceptions">
+ <return type="Array">
+ </return>
+ <description>
+ 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>
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ 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.
+ </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.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsDirectBodyState.xml b/doc/classes/PhysicsDirectBodyState.xml
deleted file mode 100644
index 24cf4961be..0000000000
--- a/doc/classes/PhysicsDirectBodyState.xml
+++ /dev/null
@@ -1,223 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectBodyState" inherits="Object" version="4.0">
- <brief_description>
- Direct access object to a physics body in the [PhysicsServer].
- </brief_description>
- <description>
- Provides direct access to a physics body in the [PhysicsServer], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody._integrate_forces].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_central_force">
- <return type="void">
- </return>
- <argument index="0" name="force" type="Vector3">
- </argument>
- <description>
- Adds a constant directional force without affecting rotation.
- This is equivalent to [code]add_force(force, Vector3(0,0,0))[/code].
- </description>
- </method>
- <method name="add_force">
- <return type="void">
- </return>
- <argument index="0" name="force" type="Vector3">
- </argument>
- <argument index="1" name="position" type="Vector3">
- </argument>
- <description>
- Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates.
- </description>
- </method>
- <method name="add_torque">
- <return type="void">
- </return>
- <argument index="0" name="torque" type="Vector3">
- </argument>
- <description>
- Adds a constant rotational force without affecting position.
- </description>
- </method>
- <method name="apply_central_impulse">
- <return type="void">
- </return>
- <argument index="0" name="j" type="Vector3">
- </argument>
- <description>
- Applies a single directional impulse without affecting rotation.
- This is equivalent to [code]apply_impulse(Vector3(0, 0, 0), impulse)[/code].
- </description>
- </method>
- <method name="apply_impulse">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <argument index="1" name="j" type="Vector3">
- </argument>
- <description>
- Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts. The position uses the rotation of the global coordinate system, but is centered at the object's origin.
- </description>
- </method>
- <method name="apply_torque_impulse">
- <return type="void">
- </return>
- <argument index="0" name="j" type="Vector3">
- </argument>
- <description>
- Apply a torque impulse (which will be affected by the body mass and shape). This will rotate the body around the vector [code]j[/code] passed as parameter.
- </description>
- </method>
- <method name="get_contact_collider" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider's [RID].
- </description>
- </method>
- <method name="get_contact_collider_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider's object id.
- </description>
- </method>
- <method name="get_contact_collider_object" qualifiers="const">
- <return type="Object">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider object.
- </description>
- </method>
- <method name="get_contact_collider_position" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the contact position in the collider.
- </description>
- </method>
- <method name="get_contact_collider_shape" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the collider's shape index.
- </description>
- </method>
- <method name="get_contact_collider_velocity_at_position" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the linear velocity vector at the collider's contact point.
- </description>
- </method>
- <method name="get_contact_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of contacts this body has with other bodies.
- [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody.contact_monitor].
- </description>
- </method>
- <method name="get_contact_impulse" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Impulse created by the contact. Only implemented for Bullet physics.
- </description>
- </method>
- <method name="get_contact_local_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the local normal at the contact point.
- </description>
- </method>
- <method name="get_contact_local_position" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the local position of the contact point.
- </description>
- </method>
- <method name="get_contact_local_shape" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- Returns the local shape index of the collision.
- </description>
- </method>
- <method name="get_space_state">
- <return type="PhysicsDirectSpaceState">
- </return>
- <description>
- Returns the current state of the space, useful for queries.
- </description>
- </method>
- <method name="integrate_forces">
- <return type="void">
- </return>
- <description>
- Calls the built-in force integration code.
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity">
- The body's rotational velocity.
- </member>
- <member name="center_of_mass" type="Vector3" setter="" getter="get_center_of_mass">
- </member>
- <member name="inverse_inertia" type="Vector3" setter="" getter="get_inverse_inertia">
- The inverse of the inertia of the body.
- </member>
- <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass">
- The inverse of the mass of the body.
- </member>
- <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity">
- The body's linear velocity.
- </member>
- <member name="principal_inertia_axes" type="Basis" setter="" getter="get_principal_inertia_axes">
- </member>
- <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping">
- If [code]true[/code], this body is currently sleeping (not active).
- </member>
- <member name="step" type="float" setter="" getter="get_step">
- The timestep (delta) used for the simulation.
- </member>
- <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp">
- The rate at which the body stops rotating, if there are not any other forces moving it.
- </member>
- <member name="total_gravity" type="Vector3" setter="" getter="get_total_gravity">
- The total gravity vector being currently applied to this body.
- </member>
- <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp">
- The rate at which the body stops moving, if there are not any other forces moving it.
- </member>
- <member name="transform" type="Transform" setter="set_transform" getter="get_transform">
- The body's transformation matrix.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
new file mode 100644
index 0000000000..46205fecd1
--- /dev/null
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectBodyState2D" inherits="Object" version="4.0">
+ <brief_description>
+ Direct access object to a physics body in the [PhysicsServer2D].
+ </brief_description>
+ <description>
+ Provides direct access to a physics body in the [PhysicsServer2D], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces].
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ </tutorials>
+ <methods>
+ <method name="add_central_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="Vector2">
+ </argument>
+ <description>
+ Adds a constant directional force without affecting rotation.
+ </description>
+ </method>
+ <method name="add_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="offset" type="Vector2">
+ </argument>
+ <argument index="1" name="force" type="Vector2">
+ </argument>
+ <description>
+ Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates.
+ </description>
+ </method>
+ <method name="add_torque">
+ <return type="void">
+ </return>
+ <argument index="0" name="torque" type="float">
+ </argument>
+ <description>
+ Adds a constant rotational force.
+ </description>
+ </method>
+ <method name="apply_central_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="impulse" type="Vector2">
+ </argument>
+ <description>
+ Applies a directional impulse without affecting rotation.
+ </description>
+ </method>
+ <method name="apply_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="offset" type="Vector2">
+ </argument>
+ <argument index="1" name="impulse" type="Vector2">
+ </argument>
+ <description>
+ Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise). The offset uses the rotation of the global coordinate system, but is centered at the object's origin.
+ </description>
+ </method>
+ <method name="apply_torque_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="impulse" type="float">
+ </argument>
+ <description>
+ Applies a rotational impulse to the body.
+ </description>
+ </method>
+ <method name="get_contact_collider" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider's [RID].
+ </description>
+ </method>
+ <method name="get_contact_collider_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider's object id.
+ </description>
+ </method>
+ <method name="get_contact_collider_object" qualifiers="const">
+ <return type="Object">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider object. This depends on how it was created (will return a scene node if such was used to create it).
+ </description>
+ </method>
+ <method name="get_contact_collider_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the contact position in the collider.
+ </description>
+ </method>
+ <method name="get_contact_collider_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider's shape index.
+ </description>
+ </method>
+ <method name="get_contact_collider_shape_metadata" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collided shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data].
+ </description>
+ </method>
+ <method name="get_contact_collider_velocity_at_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the linear velocity vector at the collider's contact point.
+ </description>
+ </method>
+ <method name="get_contact_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of contacts this body has with other bodies.
+ [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody2D.contact_monitor].
+ </description>
+ </method>
+ <method name="get_contact_local_normal" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the local normal at the contact point.
+ </description>
+ </method>
+ <method name="get_contact_local_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the local position of the contact point.
+ </description>
+ </method>
+ <method name="get_contact_local_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the local shape index of the collision.
+ </description>
+ </method>
+ <method name="get_space_state">
+ <return type="PhysicsDirectSpaceState2D">
+ </return>
+ <description>
+ Returns the current state of the space, useful for queries.
+ </description>
+ </method>
+ <method name="integrate_forces">
+ <return type="void">
+ </return>
+ <description>
+ Calls the built-in force integration code.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity">
+ The body's rotational velocity.
+ </member>
+ <member name="inverse_inertia" type="float" setter="" getter="get_inverse_inertia">
+ The inverse of the inertia of the body.
+ </member>
+ <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass">
+ The inverse of the mass of the body.
+ </member>
+ <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity">
+ The body's linear velocity.
+ </member>
+ <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping">
+ If [code]true[/code], this body is currently sleeping (not active).
+ </member>
+ <member name="step" type="float" setter="" getter="get_step">
+ The timestep (delta) used for the simulation.
+ </member>
+ <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp">
+ The rate at which the body stops rotating, if there are not any other forces moving it.
+ </member>
+ <member name="total_gravity" type="Vector2" setter="" getter="get_total_gravity">
+ The total gravity vector being currently applied to this body.
+ </member>
+ <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp">
+ The rate at which the body stops moving, if there are not any other forces moving it.
+ </member>
+ <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform">
+ The body's transformation matrix.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsDirectBodyState2DSW.xml b/doc/classes/PhysicsDirectBodyState2DSW.xml
new file mode 100644
index 0000000000..94fc4213b7
--- /dev/null
+++ b/doc/classes/PhysicsDirectBodyState2DSW.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectBodyState2DSW" inherits="PhysicsDirectBodyState2D" version="4.0">
+ <brief_description>
+ Software implementation of [PhysicsDirectBodyState2D].
+ </brief_description>
+ <description>
+ Software implementation of [PhysicsDirectBodyState2D]. This object exposes no new methods or properties and should not be used, as [PhysicsDirectBodyState2D] selects the best implementation available.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
new file mode 100644
index 0000000000..1ee520fe5f
--- /dev/null
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectBodyState3D" inherits="Object" version="4.0">
+ <brief_description>
+ Direct access object to a physics body in the [PhysicsServer3D].
+ </brief_description>
+ <description>
+ Provides direct access to a physics body in the [PhysicsServer3D], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody3D._integrate_forces].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_central_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="Vector3">
+ </argument>
+ <description>
+ Adds a constant directional force without affecting rotation.
+ This is equivalent to [code]add_force(force, Vector3(0,0,0))[/code].
+ </description>
+ </method>
+ <method name="add_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="Vector3">
+ </argument>
+ <argument index="1" name="position" type="Vector3">
+ </argument>
+ <description>
+ Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates.
+ </description>
+ </method>
+ <method name="add_torque">
+ <return type="void">
+ </return>
+ <argument index="0" name="torque" type="Vector3">
+ </argument>
+ <description>
+ Adds a constant rotational force without affecting position.
+ </description>
+ </method>
+ <method name="apply_central_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="j" type="Vector3">
+ </argument>
+ <description>
+ Applies a single directional impulse without affecting rotation.
+ This is equivalent to [code]apply_impulse(Vector3(0, 0, 0), impulse)[/code].
+ </description>
+ </method>
+ <method name="apply_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <argument index="1" name="j" type="Vector3">
+ </argument>
+ <description>
+ Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts. The position uses the rotation of the global coordinate system, but is centered at the object's origin.
+ </description>
+ </method>
+ <method name="apply_torque_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="j" type="Vector3">
+ </argument>
+ <description>
+ Apply a torque impulse (which will be affected by the body mass and shape). This will rotate the body around the vector [code]j[/code] passed as parameter.
+ </description>
+ </method>
+ <method name="get_contact_collider" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider's [RID].
+ </description>
+ </method>
+ <method name="get_contact_collider_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider's object id.
+ </description>
+ </method>
+ <method name="get_contact_collider_object" qualifiers="const">
+ <return type="Object">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider object.
+ </description>
+ </method>
+ <method name="get_contact_collider_position" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the contact position in the collider.
+ </description>
+ </method>
+ <method name="get_contact_collider_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the collider's shape index.
+ </description>
+ </method>
+ <method name="get_contact_collider_velocity_at_position" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the linear velocity vector at the collider's contact point.
+ </description>
+ </method>
+ <method name="get_contact_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of contacts this body has with other bodies.
+ [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody3D.contact_monitor].
+ </description>
+ </method>
+ <method name="get_contact_impulse" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Impulse created by the contact. Only implemented for Bullet physics.
+ </description>
+ </method>
+ <method name="get_contact_local_normal" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the local normal at the contact point.
+ </description>
+ </method>
+ <method name="get_contact_local_position" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the local position of the contact point.
+ </description>
+ </method>
+ <method name="get_contact_local_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="contact_idx" type="int">
+ </argument>
+ <description>
+ Returns the local shape index of the collision.
+ </description>
+ </method>
+ <method name="get_space_state">
+ <return type="PhysicsDirectSpaceState3D">
+ </return>
+ <description>
+ Returns the current state of the space, useful for queries.
+ </description>
+ </method>
+ <method name="integrate_forces">
+ <return type="void">
+ </return>
+ <description>
+ Calls the built-in force integration code.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity">
+ The body's rotational velocity.
+ </member>
+ <member name="center_of_mass" type="Vector3" setter="" getter="get_center_of_mass">
+ </member>
+ <member name="inverse_inertia" type="Vector3" setter="" getter="get_inverse_inertia">
+ The inverse of the inertia of the body.
+ </member>
+ <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass">
+ The inverse of the mass of the body.
+ </member>
+ <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity">
+ The body's linear velocity.
+ </member>
+ <member name="principal_inertia_axes" type="Basis" setter="" getter="get_principal_inertia_axes">
+ </member>
+ <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping">
+ If [code]true[/code], this body is currently sleeping (not active).
+ </member>
+ <member name="step" type="float" setter="" getter="get_step">
+ The timestep (delta) used for the simulation.
+ </member>
+ <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp">
+ The rate at which the body stops rotating, if there are not any other forces moving it.
+ </member>
+ <member name="total_gravity" type="Vector3" setter="" getter="get_total_gravity">
+ The total gravity vector being currently applied to this body.
+ </member>
+ <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp">
+ The rate at which the body stops moving, if there are not any other forces moving it.
+ </member>
+ <member name="transform" type="Transform" setter="set_transform" getter="get_transform">
+ The body's transformation matrix.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsDirectSpaceState.xml b/doc/classes/PhysicsDirectSpaceState.xml
deleted file mode 100644
index a6172805e9..0000000000
--- a/doc/classes/PhysicsDirectSpaceState.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectSpaceState" inherits="Object" version="4.0">
- <brief_description>
- Direct access object to a space in the [PhysicsServer].
- </brief_description>
- <description>
- Direct access object to a space in the [PhysicsServer]. It's used mainly to do queries against objects and areas residing in a given space.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
- </tutorials>
- <methods>
- <method name="cast_motion">
- <return type="Array">
- </return>
- <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
- </argument>
- <argument index="1" name="motion" type="Vector3">
- </argument>
- <description>
- Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code].
- If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics.
- </description>
- </method>
- <method name="collide_shape">
- <return type="Array">
- </return>
- <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
- </argument>
- <argument index="1" name="max_results" type="int" default="32">
- </argument>
- <description>
- Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
- </description>
- </method>
- <method name="get_rest_info">
- <return type="Dictionary">
- </return>
- <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
- </argument>
- <description>
- Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. If it collides with more than one shape, the nearest one is selected. The returned object is a dictionary containing the following fields:
- [code]collider_id[/code]: The colliding object's ID.
- [code]linear_velocity[/code]: The colliding object's velocity [Vector3]. If the object is an [Area], the result is [code](0, 0, 0)[/code].
- [code]normal[/code]: The object's surface normal at the intersection point.
- [code]point[/code]: The intersection point.
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- If the shape did not intersect anything, then an empty dictionary is returned instead.
- </description>
- </method>
- <method name="intersect_ray">
- <return type="Dictionary">
- </return>
- <argument index="0" name="from" type="Vector3">
- </argument>
- <argument index="1" name="to" type="Vector3">
- </argument>
- <argument index="2" name="exclude" type="Array" default="[ ]">
- </argument>
- <argument index="3" name="collision_mask" type="int" default="2147483647">
- </argument>
- <argument index="4" name="collide_with_bodies" type="bool" default="true">
- </argument>
- <argument index="5" name="collide_with_areas" type="bool" default="false">
- </argument>
- <description>
- Intersects a ray in a given space. The returned object is a dictionary with the following fields:
- [code]collider[/code]: The colliding object.
- [code]collider_id[/code]: The colliding object's ID.
- [code]normal[/code]: The object's surface normal at the intersection point.
- [code]position[/code]: The intersection point.
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- If the ray did not intersect anything, then an empty dictionary is returned instead.
- Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody]s or [Area]s, respectively.
- </description>
- </method>
- <method name="intersect_shape">
- <return type="Array">
- </return>
- <argument index="0" name="shape" type="PhysicsShapeQueryParameters">
- </argument>
- <argument index="1" name="max_results" type="int" default="32">
- </argument>
- <description>
- Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields:
- [code]collider[/code]: The colliding object.
- [code]collider_id[/code]: The colliding object's ID.
- [code]rid[/code]: The intersecting object's [RID].
- [code]shape[/code]: The shape index of the colliding shape.
- The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml
new file mode 100644
index 0000000000..d85d7794dd
--- /dev/null
+++ b/doc/classes/PhysicsDirectSpaceState2D.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectSpaceState2D" inherits="Object" version="4.0">
+ <brief_description>
+ Direct access object to a space in the [PhysicsServer2D].
+ </brief_description>
+ <description>
+ Direct access object to a space in the [PhysicsServer2D]. It's used mainly to do queries against objects and areas residing in a given space.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ </tutorials>
+ <methods>
+ <method name="cast_motion">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters2D">
+ </argument>
+ <description>
+ Checks how far the shape can travel toward a point. If the shape can not move, the array will be empty.
+ [b]Note:[/b] Both the shape and the motion are supplied through a [PhysicsShapeQueryParameters2D] object. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code].
+ </description>
+ </method>
+ <method name="collide_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters2D">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters2D] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
+ </description>
+ </method>
+ <method name="get_rest_info">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters2D">
+ </argument>
+ <description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters2D] object, against the space. If it collides with more than one shape, the nearest one is selected. If the shape did not intersect anything, then an empty dictionary is returned instead.
+ [b]Note:[/b] This method does not take into account the [code]motion[/code] property of the object. The returned object is a dictionary containing the following fields:
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]linear_velocity[/code]: The colliding object's velocity [Vector2]. If the object is an [Area2D], the result is [code](0, 0)[/code].
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data].
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]point[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ </description>
+ </method>
+ <method name="intersect_point">
+ <return type="Array">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <argument index="2" name="exclude" type="Array" default="[ ]">
+ </argument>
+ <argument index="3" name="collision_layer" type="int" default="2147483647">
+ </argument>
+ <argument index="4" name="collide_with_bodies" type="bool" default="true">
+ </argument>
+ <argument index="5" name="collide_with_areas" type="bool" default="false">
+ </argument>
+ <description>
+ Checks whether a point is inside any shape. The shapes the point is inside of are returned in an array containing dictionaries with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data].
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively.
+ </description>
+ </method>
+ <method name="intersect_point_on_canvas">
+ <return type="Array">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <argument index="1" name="canvas_instance_id" type="int">
+ </argument>
+ <argument index="2" name="max_results" type="int" default="32">
+ </argument>
+ <argument index="3" name="exclude" type="Array" default="[ ]">
+ </argument>
+ <argument index="4" name="collision_layer" type="int" default="2147483647">
+ </argument>
+ <argument index="5" name="collide_with_bodies" type="bool" default="true">
+ </argument>
+ <argument index="6" name="collide_with_areas" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="intersect_ray">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="from" type="Vector2">
+ </argument>
+ <argument index="1" name="to" type="Vector2">
+ </argument>
+ <argument index="2" name="exclude" type="Array" default="[ ]">
+ </argument>
+ <argument index="3" name="collision_layer" type="int" default="2147483647">
+ </argument>
+ <argument index="4" name="collide_with_bodies" type="bool" default="true">
+ </argument>
+ <argument index="5" name="collide_with_areas" type="bool" default="false">
+ </argument>
+ <description>
+ Intersects a ray in a given space. The returned object is a dictionary with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data].
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]position[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the ray did not intersect anything, then an empty dictionary is returned instead.
+ Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively.
+ </description>
+ </method>
+ <method name="intersect_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters2D">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters2D] object, against the space.
+ [b]Note:[/b] This method does not take into account the [code]motion[/code] property of the object. The intersected shapes are returned in an array containing dictionaries with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data].
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
new file mode 100644
index 0000000000..ea094dcd90
--- /dev/null
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsDirectSpaceState3D" inherits="Object" version="4.0">
+ <brief_description>
+ Direct access object to a space in the [PhysicsServer3D].
+ </brief_description>
+ <description>
+ Direct access object to a space in the [PhysicsServer3D]. It's used mainly to do queries against objects and areas residing in a given space.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ </tutorials>
+ <methods>
+ <method name="cast_motion">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters3D">
+ </argument>
+ <argument index="1" name="motion" type="Vector3">
+ </argument>
+ <description>
+ Checks whether the shape can travel to a point. The method will return an array with two floats between 0 and 1, both representing a fraction of [code]motion[/code]. The first is how far the shape can move without triggering a collision, and the second is the point at which a collision will occur. If no collision is detected, the returned array will be [code][1, 1][/code].
+ If the shape can not move, the returned array will be [code][0, 0][/code] under Bullet, and empty under GodotPhysics3D.
+ </description>
+ </method>
+ <method name="collide_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters3D">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters3D] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
+ </description>
+ </method>
+ <method name="get_rest_info">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters3D">
+ </argument>
+ <description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters3D] object, against the space. If it collides with more than one shape, the nearest one is selected. The returned object is a dictionary containing the following fields:
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]linear_velocity[/code]: The colliding object's velocity [Vector3]. If the object is an [Area3D], the result is [code](0, 0, 0)[/code].
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]point[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the shape did not intersect anything, then an empty dictionary is returned instead.
+ </description>
+ </method>
+ <method name="intersect_ray">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="from" type="Vector3">
+ </argument>
+ <argument index="1" name="to" type="Vector3">
+ </argument>
+ <argument index="2" name="exclude" type="Array" default="[ ]">
+ </argument>
+ <argument index="3" name="collision_mask" type="int" default="2147483647">
+ </argument>
+ <argument index="4" name="collide_with_bodies" type="bool" default="true">
+ </argument>
+ <argument index="5" name="collide_with_areas" type="bool" default="false">
+ </argument>
+ <description>
+ Intersects a ray in a given space. The returned object is a dictionary with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]normal[/code]: The object's surface normal at the intersection point.
+ [code]position[/code]: The intersection point.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ If the ray did not intersect anything, then an empty dictionary is returned instead.
+ Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to check in, or booleans to determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, respectively.
+ </description>
+ </method>
+ <method name="intersect_shape">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shape" type="PhysicsShapeQueryParameters3D">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <description>
+ Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters3D] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields:
+ [code]collider[/code]: The colliding object.
+ [code]collider_id[/code]: The colliding object's ID.
+ [code]rid[/code]: The intersecting object's [RID].
+ [code]shape[/code]: The shape index of the colliding shape.
+ The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsMaterial.xml b/doc/classes/PhysicsMaterial.xml
index 84e7f2b275..6410626496 100644
--- a/doc/classes/PhysicsMaterial.xml
+++ b/doc/classes/PhysicsMaterial.xml
@@ -4,7 +4,7 @@
A material for physics properties.
</brief_description>
<description>
- Provides a means of modifying the collision properties of a [PhysicsBody].
+ Provides a means of modifying the collision properties of a [PhysicsBody3D].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml
deleted file mode 100644
index 1b9ce80a1b..0000000000
--- a/doc/classes/PhysicsServer.xml
+++ /dev/null
@@ -1,1639 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServer" inherits="Object" version="4.0">
- <brief_description>
- Server interface for low-level physics access.
- </brief_description>
- <description>
- PhysicsServer is the server responsible for all 3D physics. It can create many kinds of physics objects, but does not insert them on the node tree.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="area_add_shape">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- </argument>
- <argument index="3" name="disabled" type="bool" default="false">
- </argument>
- <description>
- Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
- </description>
- </method>
- <method name="area_attach_object_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Assigns the area to a descendant of [Object], so it can exist in the node tree.
- </description>
- </method>
- <method name="area_clear_shapes">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Removes all shapes from an area. It does not delete the shapes, so they can be reassigned later.
- </description>
- </method>
- <method name="area_create">
- <return type="RID">
- </return>
- <description>
- Creates an [Area].
- </description>
- </method>
- <method name="area_get_object_instance_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Gets the instance ID of the object the area is assigned to.
- </description>
- </method>
- <method name="area_get_param" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.AreaParameter">
- </argument>
- <description>
- Returns an area parameter value. A list of available parameters is on the [enum AreaParameter] constants.
- </description>
- </method>
- <method name="area_get_shape" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the [RID] of the nth shape of an area.
- </description>
- </method>
- <method name="area_get_shape_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the number of shapes assigned to an area.
- </description>
- </method>
- <method name="area_get_shape_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the transform matrix of a shape within an area.
- </description>
- </method>
- <method name="area_get_space" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the space assigned to the area.
- </description>
- </method>
- <method name="area_get_space_override_mode" qualifiers="const">
- <return type="int" enum="PhysicsServer.AreaSpaceOverrideMode">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- Returns the space override mode for the area.
- </description>
- </method>
- <method name="area_get_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- 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>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Removes a shape from an area. It does not delete the shape, so it can be reassigned later.
- </description>
- </method>
- <method name="area_set_area_monitor_callback">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_collision_layer">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="layer" type="int">
- </argument>
- <description>
- Assigns the area to one or many physics layers.
- </description>
- </method>
- <method name="area_set_collision_mask">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- Sets which physics layers the area will monitor.
- </description>
- </method>
- <method name="area_set_monitor_callback">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
- </argument>
- <description>
- Sets the function to call when any body/area enters or exits the area. This callback will be called for any object interacting with the area, and takes five parameters:
- 1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on whether the object entered or exited the area.
- 2: [RID] of the object that entered/exited the area.
- 3: Instance ID of the object that entered/exited the area.
- 4: The shape index of the object that entered/exited the area.
- 5: The shape index of the area where the object entered/exited.
- </description>
- </method>
- <method name="area_set_monitorable">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="monitorable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_param">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.AreaParameter">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- Sets the value for an area parameter. A list of available parameters is on the [enum AreaParameter] constants.
- </description>
- </method>
- <method name="area_set_ray_pickable">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Sets object pickable with rays.
- </description>
- </method>
- <method name="area_set_shape">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- Substitutes a given area shape by another. The old shape is selected by its index, the new one by its [RID].
- </description>
- </method>
- <method name="area_set_shape_disabled">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="disabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_shape_transform">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform">
- </argument>
- <description>
- Sets the transform matrix for an area shape.
- </description>
- </method>
- <method name="area_set_space">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <description>
- Assigns a space to the area.
- </description>
- </method>
- <method name="area_set_space_override_mode">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="PhysicsServer.AreaSpaceOverrideMode">
- </argument>
- <description>
- Sets the space override mode for the area. The modes are described in the [enum AreaSpaceOverrideMode] constants.
- </description>
- </method>
- <method name="area_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- Sets the transform matrix for an area.
- </description>
- </method>
- <method name="body_add_central_force">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="force" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_collision_exception">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="excepted_body" type="RID">
- </argument>
- <description>
- Adds a body to the list of bodies exempt from collisions.
- </description>
- </method>
- <method name="body_add_force">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="force" type="Vector3">
- </argument>
- <argument index="2" name="position" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_shape">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- </argument>
- <argument index="3" name="disabled" type="bool" default="false">
- </argument>
- <description>
- Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
- </description>
- </method>
- <method name="body_add_torque">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="torque" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_central_impulse">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_impulse">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="position" type="Vector3">
- </argument>
- <argument index="2" name="impulse" type="Vector3">
- </argument>
- <description>
- Gives the body a push at a [code]position[/code] in the direction of the [code]impulse[/code].
- </description>
- </method>
- <method name="body_apply_torque_impulse">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="impulse" type="Vector3">
- </argument>
- <description>
- Gives the body a push to rotate it.
- </description>
- </method>
- <method name="body_attach_object_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Assigns the area to a descendant of [Object], so it can exist in the node tree.
- </description>
- </method>
- <method name="body_clear_shapes">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Removes all shapes from a body.
- </description>
- </method>
- <method name="body_create">
- <return type="RID">
- </return>
- <argument index="0" name="mode" type="int" enum="PhysicsServer.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">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the physics layer or layers a body belongs to.
- </description>
- </method>
- <method name="body_get_collision_mask" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the physics layer or layers a body can collide with.
--
- </description>
- </method>
- <method name="body_get_direct_state">
- <return type="PhysicsDirectBodyState">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the [PhysicsDirectBodyState] of the body.
- </description>
- </method>
- <method name="body_get_kinematic_safe_margin" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_max_contacts_reported" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the maximum contacts that can be reported. See [method body_set_max_contacts_reported].
- </description>
- </method>
- <method name="body_get_mode" qualifiers="const">
- <return type="int" enum="PhysicsServer.BodyMode">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the body mode.
- </description>
- </method>
- <method name="body_get_object_instance_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Gets the instance ID of the object the area is assigned to.
- </description>
- </method>
- <method name="body_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.BodyParameter">
- </argument>
- <description>
- Returns the value of a body parameter. A list of available parameters is on the [enum BodyParameter] constants.
- </description>
- </method>
- <method name="body_get_shape" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the [RID] of the nth shape of a body.
- </description>
- </method>
- <method name="body_get_shape_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the number of shapes assigned to a body.
- </description>
- </method>
- <method name="body_get_shape_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Returns the transform matrix of a body shape.
- </description>
- </method>
- <method name="body_get_space" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- Returns the [RID] of the space assigned to a body.
- </description>
- </method>
- <method name="body_get_state" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int" enum="PhysicsServer.BodyState">
- </argument>
- <description>
- Returns a body state.
- </description>
- </method>
- <method name="body_is_axis_locked" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis" type="int" enum="PhysicsServer.BodyAxis">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_is_continuous_collision_detection_enabled" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- If [code]true[/code], the continuous collision detection mode is enabled.
- </description>
- </method>
- <method name="body_is_omitting_force_integration" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- 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>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="excepted_body" type="RID">
- </argument>
- <description>
- Removes a body from the list of bodies exempt from collisions.
- Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
- </description>
- </method>
- <method name="body_remove_shape">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- Removes a shape from a body. The shape is not deleted, so it can be reused afterwards.
- </description>
- </method>
- <method name="body_set_axis_lock">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis" type="int" enum="PhysicsServer.BodyAxis">
- </argument>
- <argument index="2" name="lock" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_axis_velocity">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis_velocity" type="Vector3">
- </argument>
- <description>
- Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
- </description>
- </method>
- <method name="body_set_collision_layer">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="layer" type="int">
- </argument>
- <description>
- Sets the physics layer or layers a body belongs to.
- </description>
- </method>
- <method name="body_set_collision_mask">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- Sets the physics layer or layers a body can collide with.
- </description>
- </method>
- <method name="body_set_enable_continuous_collision_detection">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], the continuous collision detection mode is enabled.
- Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
- </description>
- </method>
- <method name="body_set_force_integration_callback">
- <return type="void">
- </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>
- <argument index="3" 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]).
- </description>
- </method>
- <method name="body_set_kinematic_safe_margin">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="margin" type="float">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_max_contacts_reported">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="amount" type="int">
- </argument>
- <description>
- Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
- </description>
- </method>
- <method name="body_set_mode">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="PhysicsServer.BodyMode">
- </argument>
- <description>
- Sets the body mode, from one of the [enum BodyMode] constants.
- </description>
- </method>
- <method name="body_set_omit_force_integration">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
- </description>
- </method>
- <method name="body_set_param">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.BodyParameter">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets a body parameter. A list of available parameters is on the [enum BodyParameter] constants.
- </description>
- </method>
- <method name="body_set_ray_pickable">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Sets the body pickable with rays if [code]enabled[/code] is set.
- </description>
- </method>
- <method name="body_set_shape">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- Substitutes a given body shape by another. The old shape is selected by its index, the new one by its [RID].
- </description>
- </method>
- <method name="body_set_shape_disabled">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="disabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape_transform">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform">
- </argument>
- <description>
- Sets the transform matrix for a body shape.
- </description>
- </method>
- <method name="body_set_space">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <description>
- Assigns a space to the body (see [method space_create]).
- </description>
- </method>
- <method name="body_set_state">
- <return type="void">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int" enum="PhysicsServer.BodyState">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- Sets a body state (see [enum BodyState] constants).
- </description>
- </method>
- <method name="cone_twist_joint_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.ConeTwistJointParam">
- </argument>
- <description>
- Gets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
- </description>
- </method>
- <method name="cone_twist_joint_set_param">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.ConeTwistJointParam">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
- </description>
- </method>
- <method name="free_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Destroys any of the objects created by PhysicsServer. If the [RID] passed is not one of the objects that can be created by PhysicsServer, an error will be sent to the console.
- </description>
- </method>
- <method name="generic_6dof_joint_get_flag">
- <return type="bool">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="axis" type="int" enum="Vector3.Axis">
- </argument>
- <argument index="2" name="flag" type="int" enum="PhysicsServer.G6DOFJointAxisFlag">
- </argument>
- <description>
- Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
- </description>
- </method>
- <method name="generic_6dof_joint_get_param">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="axis" type="int" enum="Vector3.Axis">
- </argument>
- <argument index="2" name="param" type="int" enum="PhysicsServer.G6DOFJointAxisParam">
- </argument>
- <description>
- Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
- </description>
- </method>
- <method name="generic_6dof_joint_set_flag">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="axis" type="int" enum="Vector3.Axis">
- </argument>
- <argument index="2" name="flag" type="int" enum="PhysicsServer.G6DOFJointAxisFlag">
- </argument>
- <argument index="3" name="enable" type="bool">
- </argument>
- <description>
- Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
- </description>
- </method>
- <method name="generic_6dof_joint_set_param">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="axis" type="int" enum="Vector3.Axis">
- </argument>
- <argument index="2" name="param" type="int" enum="PhysicsServer.G6DOFJointAxisParam">
- </argument>
- <argument index="3" name="value" type="float">
- </argument>
- <description>
- Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
- </description>
- </method>
- <method name="get_process_info">
- <return type="int">
- </return>
- <argument index="0" name="process_info" type="int" enum="PhysicsServer.ProcessInfo">
- </argument>
- <description>
- Returns an Info defined by the [enum ProcessInfo] input given.
- </description>
- </method>
- <method name="hinge_joint_get_flag" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="flag" type="int" enum="PhysicsServer.HingeJointFlag">
- </argument>
- <description>
- Gets a hinge_joint flag (see [enum HingeJointFlag] constants).
- </description>
- </method>
- <method name="hinge_joint_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.HingeJointParam">
- </argument>
- <description>
- Gets a hinge_joint parameter (see [enum HingeJointParam]).
- </description>
- </method>
- <method name="hinge_joint_set_flag">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="flag" type="int" enum="PhysicsServer.HingeJointFlag">
- </argument>
- <argument index="2" name="enabled" type="bool">
- </argument>
- <description>
- Sets a hinge_joint flag (see [enum HingeJointFlag] constants).
- </description>
- </method>
- <method name="hinge_joint_set_param">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.HingeJointParam">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets a hinge_joint parameter (see [enum HingeJointParam] constants).
- </description>
- </method>
- <method name="joint_create_cone_twist">
- <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">
- </argument>
- <argument index="3" name="local_ref_B" type="Transform">
- </argument>
- <description>
- Creates a [ConeTwistJoint].
- </description>
- </method>
- <method name="joint_create_generic_6dof">
- <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">
- </argument>
- <argument index="3" name="local_ref_B" type="Transform">
- </argument>
- <description>
- Creates a [Generic6DOFJoint].
- </description>
- </method>
- <method name="joint_create_hinge">
- <return type="RID">
- </return>
- <argument index="0" name="body_A" type="RID">
- </argument>
- <argument index="1" name="hinge_A" type="Transform">
- </argument>
- <argument index="2" name="body_B" type="RID">
- </argument>
- <argument index="3" name="hinge_B" type="Transform">
- </argument>
- <description>
- Creates a [HingeJoint].
- </description>
- </method>
- <method name="joint_create_pin">
- <return type="RID">
- </return>
- <argument index="0" name="body_A" type="RID">
- </argument>
- <argument index="1" name="local_A" type="Vector3">
- </argument>
- <argument index="2" name="body_B" type="RID">
- </argument>
- <argument index="3" name="local_B" type="Vector3">
- </argument>
- <description>
- Creates a [PinJoint].
- </description>
- </method>
- <method name="joint_create_slider">
- <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">
- </argument>
- <argument index="3" name="local_ref_B" type="Transform">
- </argument>
- <description>
- Creates a [SliderJoint].
- </description>
- </method>
- <method name="joint_get_solver_priority" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <description>
- Gets the priority value of the Joint.
- </description>
- </method>
- <method name="joint_get_type" qualifiers="const">
- <return type="int" enum="PhysicsServer.JointType">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <description>
- Returns the type of the Joint.
- </description>
- </method>
- <method name="joint_set_solver_priority">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="priority" type="int">
- </argument>
- <description>
- Sets the priority value of the Joint.
- </description>
- </method>
- <method name="pin_joint_get_local_a" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <description>
- Returns position of the joint in the local space of body a of the joint.
- </description>
- </method>
- <method name="pin_joint_get_local_b" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <description>
- Returns position of the joint in the local space of body b of the joint.
- </description>
- </method>
- <method name="pin_joint_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.PinJointParam">
- </argument>
- <description>
- Gets a pin_joint parameter (see [enum PinJointParam] constants).
- </description>
- </method>
- <method name="pin_joint_set_local_a">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="local_A" type="Vector3">
- </argument>
- <description>
- Sets position of the joint in the local space of body a of the joint.
- </description>
- </method>
- <method name="pin_joint_set_local_b">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="local_B" type="Vector3">
- </argument>
- <description>
- Sets position of the joint in the local space of body b of the joint.
- </description>
- </method>
- <method name="pin_joint_set_param">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.PinJointParam">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets a pin_joint parameter (see [enum PinJointParam] constants).
- </description>
- </method>
- <method name="set_active">
- <return type="void">
- </return>
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- Activates or deactivates the 3D physics engine.
- </description>
- </method>
- <method name="shape_create">
- <return type="RID">
- </return>
- <argument index="0" name="type" type="int" enum="PhysicsServer.ShapeType">
- </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].
- </description>
- </method>
- <method name="shape_get_data" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- Returns the shape data.
- </description>
- </method>
- <method name="shape_get_type" qualifiers="const">
- <return type="int" enum="PhysicsServer.ShapeType">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- Returns the type of shape (see [enum ShapeType] constants).
- </description>
- </method>
- <method name="shape_set_data">
- <return type="void">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <argument index="1" name="data" type="Variant">
- </argument>
- <description>
- Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type].
- </description>
- </method>
- <method name="slider_joint_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.SliderJointParam">
- </argument>
- <description>
- Gets a slider_joint parameter (see [enum SliderJointParam] constants).
- </description>
- </method>
- <method name="slider_joint_set_param">
- <return type="void">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.SliderJointParam">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Gets a slider_joint parameter (see [enum SliderJointParam] constants).
- </description>
- </method>
- <method name="space_create">
- <return type="RID">
- </return>
- <description>
- Creates a space. A space is a collection of parameters for the physics engine that can be assigned to an area or a body. It can be assigned to an area with [method area_set_space], or to a body with [method body_set_space].
- </description>
- </method>
- <method name="space_get_direct_state">
- <return type="PhysicsDirectSpaceState">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <description>
- Returns the state of a space, a [PhysicsDirectSpaceState]. This object can be used to make collision/intersection queries.
- </description>
- </method>
- <method name="space_get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.SpaceParameter">
- </argument>
- <description>
- Returns the value of a space parameter.
- </description>
- </method>
- <method name="space_is_active" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <description>
- Returns whether the space is active.
- </description>
- </method>
- <method name="space_set_active">
- <return type="void">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="active" type="bool">
- </argument>
- <description>
- Marks a space as active. It will not have an effect, unless it is assigned to an area or body.
- </description>
- </method>
- <method name="space_set_param">
- <return type="void">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="PhysicsServer.SpaceParameter">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets the value for a space parameter. A list of available parameters is on the [enum SpaceParameter] constants.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="JOINT_PIN" value="0" enum="JointType">
- The [Joint] is a [PinJoint].
- </constant>
- <constant name="JOINT_HINGE" value="1" enum="JointType">
- The [Joint] is a [HingeJoint].
- </constant>
- <constant name="JOINT_SLIDER" value="2" enum="JointType">
- The [Joint] is a [SliderJoint].
- </constant>
- <constant name="JOINT_CONE_TWIST" value="3" enum="JointType">
- The [Joint] is a [ConeTwistJoint].
- </constant>
- <constant name="JOINT_6DOF" value="4" enum="JointType">
- The [Joint] is a [Generic6DOFJoint].
- </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.
- </constant>
- <constant name="PIN_JOINT_DAMPING" value="1" enum="PinJointParam">
- The strength with which the pinned objects try to stay in velocity relation to each other.
- The higher, the stronger.
- </constant>
- <constant name="PIN_JOINT_IMPULSE_CLAMP" value="2" enum="PinJointParam">
- If above 0, this value is the maximum value for an impulse that this Joint puts on its ends.
- </constant>
- <constant name="HINGE_JOINT_BIAS" value="0" enum="HingeJointParam">
- The speed with which the two bodies get pulled together when they move in different directions.
- </constant>
- <constant name="HINGE_JOINT_LIMIT_UPPER" value="1" enum="HingeJointParam">
- The maximum rotation across the Hinge.
- </constant>
- <constant name="HINGE_JOINT_LIMIT_LOWER" value="2" enum="HingeJointParam">
- The minimum rotation across the Hinge.
- </constant>
- <constant name="HINGE_JOINT_LIMIT_BIAS" value="3" enum="HingeJointParam">
- The speed with which the rotation across the axis perpendicular to the hinge gets corrected.
- </constant>
- <constant name="HINGE_JOINT_LIMIT_SOFTNESS" value="4" enum="HingeJointParam">
- </constant>
- <constant name="HINGE_JOINT_LIMIT_RELAXATION" value="5" enum="HingeJointParam">
- The lower this value, the more the rotation gets slowed down.
- </constant>
- <constant name="HINGE_JOINT_MOTOR_TARGET_VELOCITY" value="6" enum="HingeJointParam">
- Target speed for the motor.
- </constant>
- <constant name="HINGE_JOINT_MOTOR_MAX_IMPULSE" value="7" enum="HingeJointParam">
- Maximum acceleration for the motor.
- </constant>
- <constant name="HINGE_JOINT_FLAG_USE_LIMIT" value="0" enum="HingeJointFlag">
- If [code]true[/code], the Hinge has a maximum and a minimum rotation.
- </constant>
- <constant name="HINGE_JOINT_FLAG_ENABLE_MOTOR" value="1" enum="HingeJointFlag">
- If [code]true[/code], a motor turns the Hinge.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_LIMIT_UPPER" value="0" enum="SliderJointParam">
- The maximum difference between the pivot points on their X axis before damping happens.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_LIMIT_LOWER" value="1" enum="SliderJointParam">
- The minimum difference between the pivot points on their X axis before damping happens.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS" value="2" enum="SliderJointParam">
- A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION" value="3" enum="SliderJointParam">
- The amount of restitution once the limits are surpassed. The lower, the more velocityenergy gets lost.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_LIMIT_DAMPING" value="4" enum="SliderJointParam">
- The amount of damping once the slider limits are surpassed.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_MOTION_SOFTNESS" value="5" enum="SliderJointParam">
- A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_MOTION_RESTITUTION" value="6" enum="SliderJointParam">
- The amount of restitution inside the slider limits.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_MOTION_DAMPING" value="7" enum="SliderJointParam">
- The amount of damping inside the slider limits.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS" value="8" enum="SliderJointParam">
- A factor applied to the movement across axes orthogonal to the slider.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION" value="9" enum="SliderJointParam">
- The amount of restitution when movement is across axes orthogonal to the slider.
- </constant>
- <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING" value="10" enum="SliderJointParam">
- The amount of damping when movement is across axes orthogonal to the slider.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_LIMIT_UPPER" value="11" enum="SliderJointParam">
- The upper limit of rotation in the slider.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_LIMIT_LOWER" value="12" enum="SliderJointParam">
- The lower limit of rotation in the slider.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS" value="13" enum="SliderJointParam">
- A factor applied to the all rotation once the limit is surpassed.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION" value="14" enum="SliderJointParam">
- The amount of restitution of the rotation when the limit is surpassed.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_LIMIT_DAMPING" value="15" enum="SliderJointParam">
- The amount of damping of the rotation when the limit is surpassed.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS" value="16" enum="SliderJointParam">
- A factor that gets applied to the all rotation in the limits.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION" value="17" enum="SliderJointParam">
- The amount of restitution of the rotation in the limits.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_MOTION_DAMPING" value="18" enum="SliderJointParam">
- The amount of damping of the rotation in the limits.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS" value="19" enum="SliderJointParam">
- A factor that gets applied to the all rotation across axes orthogonal to the slider.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION" value="20" enum="SliderJointParam">
- The amount of restitution of the rotation across axes orthogonal to the slider.
- </constant>
- <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING" value="21" enum="SliderJointParam">
- The amount of damping of the rotation across axes orthogonal to the slider.
- </constant>
- <constant name="SLIDER_JOINT_MAX" value="22" enum="SliderJointParam">
- Represents the size of the [enum SliderJointParam] enum.
- </constant>
- <constant name="CONE_TWIST_JOINT_SWING_SPAN" value="0" enum="ConeTwistJointParam">
- Swing is rotation from side to side, around the axis perpendicular to the twist axis.
- The swing span defines, how much rotation will not get corrected along the swing axis.
- Could be defined as looseness in the [ConeTwistJoint].
- If below 0.05, this behavior is locked.
- </constant>
- <constant name="CONE_TWIST_JOINT_TWIST_SPAN" value="1" enum="ConeTwistJointParam">
- Twist is the rotation around the twist axis, this value defined how far the joint can twist.
- Twist is locked if below 0.05.
- </constant>
- <constant name="CONE_TWIST_JOINT_BIAS" value="2" enum="ConeTwistJointParam">
- The speed with which the swing or twist will take place.
- The higher, the faster.
- </constant>
- <constant name="CONE_TWIST_JOINT_SOFTNESS" value="3" enum="ConeTwistJointParam">
- The ease with which the Joint twists, if it's too low, it takes more force to twist the joint.
- </constant>
- <constant name="CONE_TWIST_JOINT_RELAXATION" value="4" enum="ConeTwistJointParam">
- Defines, how fast the swing- and twist-speed-difference on both sides gets synced.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_LOWER_LIMIT" value="0" enum="G6DOFJointAxisParam">
- The minimum difference between the pivot points' axes.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_UPPER_LIMIT" value="1" enum="G6DOFJointAxisParam">
- The maximum difference between the pivot points' axes.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS" value="2" enum="G6DOFJointAxisParam">
- A factor that gets applied to the movement across the axes. The lower, the slower the movement.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_RESTITUTION" value="3" enum="G6DOFJointAxisParam">
- The amount of restitution on the axes movement. The lower, the more velocity-energy gets lost.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_DAMPING" value="4" enum="G6DOFJointAxisParam">
- The amount of damping that happens at the linear motion across the axes.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY" value="5" enum="G6DOFJointAxisParam">
- The velocity that the joint's linear motor will attempt to reach.
- </constant>
- <constant name="G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT" value="6" enum="G6DOFJointAxisParam">
- The maximum force that the linear motor can apply while trying to reach the target velocity.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_LOWER_LIMIT" value="10" enum="G6DOFJointAxisParam">
- The minimum rotation in negative direction to break loose and rotate around the axes.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_UPPER_LIMIT" value="11" enum="G6DOFJointAxisParam">
- The minimum rotation in positive direction to break loose and rotate around the axes.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS" value="12" enum="G6DOFJointAxisParam">
- A factor that gets multiplied onto all rotations across the axes.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_DAMPING" value="13" enum="G6DOFJointAxisParam">
- The amount of rotational damping across the axes. The lower, the more dampening occurs.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_RESTITUTION" value="14" enum="G6DOFJointAxisParam">
- The amount of rotational restitution across the axes. The lower, the more restitution occurs.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_FORCE_LIMIT" value="15" enum="G6DOFJointAxisParam">
- The maximum amount of force that can occur, when rotating around the axes.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_ERP" value="16" enum="G6DOFJointAxisParam">
- When correcting the crossing of limits in rotation across the axes, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY" value="17" enum="G6DOFJointAxisParam">
- Target speed for the motor at the axes.
- </constant>
- <constant name="G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT" value="18" enum="G6DOFJointAxisParam">
- Maximum acceleration for the motor at the axes.
- </constant>
- <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT" value="0" enum="G6DOFJointAxisFlag">
- If [code]set[/code] there is linear motion possible within the given limits.
- </constant>
- <constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT" value="1" enum="G6DOFJointAxisFlag">
- If [code]set[/code] there is rotational motion possible.
- </constant>
- <constant name="G6DOF_JOINT_FLAG_ENABLE_MOTOR" value="4" enum="G6DOFJointAxisFlag">
- If [code]set[/code] there is a rotational motor across these axes.
- </constant>
- <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="G6DOFJointAxisFlag">
- If [code]set[/code] there is a linear motor on this axis that targets a specific velocity.
- </constant>
- <constant name="SHAPE_PLANE" value="0" enum="ShapeType">
- The [Shape] is a [WorldMarginShape].
- </constant>
- <constant name="SHAPE_RAY" value="1" enum="ShapeType">
- The [Shape] is a [RayShape].
- </constant>
- <constant name="SHAPE_SPHERE" value="2" enum="ShapeType">
- The [Shape] is a [SphereShape].
- </constant>
- <constant name="SHAPE_BOX" value="3" enum="ShapeType">
- The [Shape] is a [BoxShape].
- </constant>
- <constant name="SHAPE_CAPSULE" value="4" enum="ShapeType">
- The [Shape] is a [CapsuleShape].
- </constant>
- <constant name="SHAPE_CYLINDER" value="5" enum="ShapeType">
- The [Shape] is a [CylinderShape].
- </constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
- The [Shape] is a [ConvexPolygonShape].
- </constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
- The [Shape] is a [ConcavePolygonShape].
- </constant>
- <constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType">
- The [Shape] is a [HeightMapShape].
- </constant>
- <constant name="SHAPE_CUSTOM" value="9" 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">
- Constant to set/get gravity strength in an area.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_VECTOR" value="1" enum="AreaParameter">
- Constant to set/get gravity vector/center in an area.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="2" enum="AreaParameter">
- Constant to set/get whether the gravity vector of an area is a direction, or a center point.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_DISTANCE_SCALE" value="3" enum="AreaParameter">
- Constant to set/get the falloff factor for point gravity of an area. The greater this value is, the faster the strength of gravity decreases with the square of distance.
- </constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4" enum="AreaParameter">
- This constant was used to set/get the falloff factor for point gravity. It has been superseded by [constant AREA_PARAM_GRAVITY_DISTANCE_SCALE].
- </constant>
- <constant name="AREA_PARAM_LINEAR_DAMP" value="5" enum="AreaParameter">
- Constant to set/get the linear dampening factor of an area.
- </constant>
- <constant name="AREA_PARAM_ANGULAR_DAMP" value="6" enum="AreaParameter">
- Constant to set/get the angular dampening factor of an area.
- </constant>
- <constant name="AREA_PARAM_PRIORITY" value="7" enum="AreaParameter">
- Constant to set/get the priority (order of processing) of an area.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_DISABLED" value="0" enum="AreaSpaceOverrideMode">
- This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1" enum="AreaSpaceOverrideMode">
- This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_COMBINE_REPLACE" value="2" enum="AreaSpaceOverrideMode">
- This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="3" enum="AreaSpaceOverrideMode">
- This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
- </constant>
- <constant name="AREA_SPACE_OVERRIDE_REPLACE_COMBINE" value="4" enum="AreaSpaceOverrideMode">
- This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
- </constant>
- <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode">
- Constant for static bodies.
- </constant>
- <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
- Constant for kinematic bodies.
- </constant>
- <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
- Constant for rigid bodies.
- </constant>
- <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode">
- Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics.
- </constant>
- <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
- Constant to set/get a body's bounce factor.
- </constant>
- <constant name="BODY_PARAM_FRICTION" value="1" enum="BodyParameter">
- Constant to set/get a body's friction.
- </constant>
- <constant name="BODY_PARAM_MASS" value="2" enum="BodyParameter">
- Constant to set/get a body's mass.
- </constant>
- <constant name="BODY_PARAM_GRAVITY_SCALE" value="3" enum="BodyParameter">
- Constant to set/get a body's gravity multiplier.
- </constant>
- <constant name="BODY_PARAM_LINEAR_DAMP" value="4" enum="BodyParameter">
- Constant to set/get a body's linear dampening factor.
- </constant>
- <constant name="BODY_PARAM_ANGULAR_DAMP" value="5" enum="BodyParameter">
- Constant to set/get a body's angular dampening factor.
- </constant>
- <constant name="BODY_PARAM_MAX" value="6" enum="BodyParameter">
- Represents the size of the [enum BodyParameter] enum.
- </constant>
- <constant name="BODY_STATE_TRANSFORM" value="0" enum="BodyState">
- Constant to set/get the current transform matrix of the body.
- </constant>
- <constant name="BODY_STATE_LINEAR_VELOCITY" value="1" enum="BodyState">
- Constant to set/get the current linear velocity of the body.
- </constant>
- <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2" enum="BodyState">
- Constant to set/get the current angular velocity of the body.
- </constant>
- <constant name="BODY_STATE_SLEEPING" value="3" enum="BodyState">
- Constant to sleep/wake up a body, or to get whether it is sleeping.
- </constant>
- <constant name="BODY_STATE_CAN_SLEEP" value="4" enum="BodyState">
- Constant to set/get whether the body can sleep.
- </constant>
- <constant name="AREA_BODY_ADDED" value="0" enum="AreaBodyStatus">
- The value of the first parameter and area callback function receives, when an object enters one of its shapes.
- </constant>
- <constant name="AREA_BODY_REMOVED" value="1" enum="AreaBodyStatus">
- The value of the first parameter and area callback function receives, when an object exits one of its shapes.
- </constant>
- <constant name="INFO_ACTIVE_OBJECTS" value="0" enum="ProcessInfo">
- Constant to get the number of objects that are not sleeping.
- </constant>
- <constant name="INFO_COLLISION_PAIRS" value="1" enum="ProcessInfo">
- Constant to get the number of possible collisions.
- </constant>
- <constant name="INFO_ISLAND_COUNT" value="2" enum="ProcessInfo">
- Constant to get the number of space regions where a collision could occur.
- </constant>
- <constant name="SPACE_PARAM_CONTACT_RECYCLE_RADIUS" value="0" enum="SpaceParameter">
- Constant to set/get the maximum distance a pair of bodies has to move before their collision status has to be recalculated.
- </constant>
- <constant name="SPACE_PARAM_CONTACT_MAX_SEPARATION" value="1" enum="SpaceParameter">
- Constant to set/get the maximum distance a shape can be from another before they are considered separated.
- </constant>
- <constant name="SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION" value="2" enum="SpaceParameter">
- Constant to set/get the maximum distance a shape can penetrate another shape before it is considered a collision.
- </constant>
- <constant name="SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD" value="3" enum="SpaceParameter">
- Constant to set/get the threshold linear velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
- </constant>
- <constant name="SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD" value="4" enum="SpaceParameter">
- Constant to set/get the threshold angular velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
- </constant>
- <constant name="SPACE_PARAM_BODY_TIME_TO_SLEEP" value="5" enum="SpaceParameter">
- Constant to set/get the maximum time of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after this time.
- </constant>
- <constant name="SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO" value="6" enum="SpaceParameter">
- </constant>
- <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="7" enum="SpaceParameter">
- Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
- </constant>
- <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="8" enum="SpaceParameter">
- </constant>
- <constant name="BODY_AXIS_LINEAR_X" value="1" enum="BodyAxis">
- </constant>
- <constant name="BODY_AXIS_LINEAR_Y" value="2" enum="BodyAxis">
- </constant>
- <constant name="BODY_AXIS_LINEAR_Z" value="4" enum="BodyAxis">
- </constant>
- <constant name="BODY_AXIS_ANGULAR_X" value="8" enum="BodyAxis">
- </constant>
- <constant name="BODY_AXIS_ANGULAR_Y" value="16" enum="BodyAxis">
- </constant>
- <constant name="BODY_AXIS_ANGULAR_Z" value="32" enum="BodyAxis">
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
new file mode 100644
index 0000000000..9da739e57a
--- /dev/null
+++ b/doc/classes/PhysicsServer2D.xml
@@ -0,0 +1,1284 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer2D" inherits="Object" version="4.0">
+ <brief_description>
+ Server interface for low-level 2D physics access.
+ </brief_description>
+ <description>
+ PhysicsServer2D is the server responsible for all 2D physics. It can create many kinds of physics objects, but does not insert them on the node tree.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="area_add_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="RID">
+ </argument>
+ <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
+ </argument>
+ <argument index="3" name="disabled" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
+ </description>
+ </method>
+ <method name="area_attach_canvas_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_attach_object_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ Assigns the area to a descendant of [Object], so it can exist in the node tree.
+ </description>
+ </method>
+ <method name="area_clear_shapes">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Removes all shapes from an area. It does not delete the shapes, so they can be reassigned later.
+ </description>
+ </method>
+ <method name="area_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an [Area2D].
+ </description>
+ </method>
+ <method name="area_get_canvas_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_get_object_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Gets the instance ID of the object the area is assigned to.
+ </description>
+ </method>
+ <method name="area_get_param" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter">
+ </argument>
+ <description>
+ Returns an area parameter value. See [enum AreaParameter] for a list of available parameters.
+ </description>
+ </method>
+ <method name="area_get_shape" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the [RID] of the nth shape of an area.
+ </description>
+ </method>
+ <method name="area_get_shape_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the number of shapes assigned to an area.
+ </description>
+ </method>
+ <method name="area_get_shape_transform" qualifiers="const">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the transform matrix of a shape within an area.
+ </description>
+ </method>
+ <method name="area_get_space" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the space assigned to the area.
+ </description>
+ </method>
+ <method name="area_get_space_override_mode" qualifiers="const">
+ <return type="int" enum="PhysicsServer2D.AreaSpaceOverrideMode">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the space override mode for the area.
+ </description>
+ </method>
+ <method name="area_get_transform" qualifiers="const">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the transform matrix for an area.
+ </description>
+ </method>
+ <method name="area_remove_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Removes a shape from an area. It does not delete the shape, so it can be reassigned later.
+ </description>
+ </method>
+ <method name="area_set_area_monitor_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="receiver" type="Object">
+ </argument>
+ <argument index="2" name="method" type="StringName">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_collision_layer">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="layer" type="int">
+ </argument>
+ <description>
+ Assigns the area to one or many physics layers.
+ </description>
+ </method>
+ <method name="area_set_collision_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ Sets which physics layers the area will monitor.
+ </description>
+ </method>
+ <method name="area_set_monitor_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="receiver" type="Object">
+ </argument>
+ <argument index="2" name="method" type="StringName">
+ </argument>
+ <description>
+ Sets the function to call when any body/area enters or exits the area. This callback will be called for any object interacting with the area, and takes five parameters:
+ 1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on whether the object entered or exited the area.
+ 2: [RID] of the object that entered/exited the area.
+ 3: Instance ID of the object that entered/exited the area.
+ 4: The shape index of the object that entered/exited the area.
+ 5: The shape index of the area where the object entered/exited.
+ </description>
+ </method>
+ <method name="area_set_monitorable">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="monitorable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter">
+ </argument>
+ <argument index="2" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets the value for an area parameter. See [enum AreaParameter] for a list of available parameters.
+ </description>
+ </method>
+ <method name="area_set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="shape" type="RID">
+ </argument>
+ <description>
+ Substitutes a given area shape by another. The old shape is selected by its index, the new one by its [RID].
+ </description>
+ </method>
+ <method name="area_set_shape_disabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="disabled" type="bool">
+ </argument>
+ <description>
+ Disables a given shape in an area.
+ </description>
+ </method>
+ <method name="area_set_shape_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the transform matrix for an area shape.
+ </description>
+ </method>
+ <method name="area_set_space">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="space" type="RID">
+ </argument>
+ <description>
+ Assigns a space to the area.
+ </description>
+ </method>
+ <method name="area_set_space_override_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="PhysicsServer2D.AreaSpaceOverrideMode">
+ </argument>
+ <description>
+ Sets the space override mode for the area. See [enum AreaSpaceOverrideMode] for a list of available modes.
+ </description>
+ </method>
+ <method name="area_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the transform matrix for an area.
+ </description>
+ </method>
+ <method name="body_add_central_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="force" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_add_collision_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="excepted_body" type="RID">
+ </argument>
+ <description>
+ Adds a body to the list of bodies exempt from collisions.
+ </description>
+ </method>
+ <method name="body_add_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="offset" type="Vector2">
+ </argument>
+ <argument index="2" name="force" type="Vector2">
+ </argument>
+ <description>
+ Adds a positioned force to the applied force and torque. As with [method body_apply_impulse], both the force and the offset from the body origin are in global coordinates. A force differs from an impulse in that, while the two are forces, the impulse clears itself after being applied.
+ </description>
+ </method>
+ <method name="body_add_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="RID">
+ </argument>
+ <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
+ </argument>
+ <argument index="3" name="disabled" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
+ </description>
+ </method>
+ <method name="body_add_torque">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="torque" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_apply_central_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="impulse" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_apply_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="position" type="Vector2">
+ </argument>
+ <argument index="2" name="impulse" type="Vector2">
+ </argument>
+ <description>
+ Adds a positioned impulse to the applied force and torque. Both the force and the offset from the body origin are in global coordinates.
+ </description>
+ </method>
+ <method name="body_apply_torque_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="impulse" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_attach_canvas_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_attach_object_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ Assigns the area to a descendant of [Object], so it can exist in the node tree.
+ </description>
+ </method>
+ <method name="body_clear_shapes">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Removes all shapes from a body.
+ </description>
+ </method>
+ <method name="body_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a physics body.
+ </description>
+ </method>
+ <method name="body_get_canvas_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_collision_layer" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the physics layer or layers a body belongs to.
+ </description>
+ </method>
+ <method name="body_get_collision_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the physics layer or layers a body can collide with.
+ </description>
+ </method>
+ <method name="body_get_continuous_collision_detection_mode" qualifiers="const">
+ <return type="int" enum="PhysicsServer2D.CCDMode">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the continuous collision detection mode.
+ </description>
+ </method>
+ <method name="body_get_direct_state">
+ <return type="PhysicsDirectBodyState2D">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the [PhysicsDirectBodyState2D] of the body.
+ </description>
+ </method>
+ <method name="body_get_max_contacts_reported" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the maximum contacts that can be reported. See [method body_set_max_contacts_reported].
+ </description>
+ </method>
+ <method name="body_get_mode" qualifiers="const">
+ <return type="int" enum="PhysicsServer2D.BodyMode">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the body mode.
+ </description>
+ </method>
+ <method name="body_get_object_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Gets the instance ID of the object the area is assigned to.
+ </description>
+ </method>
+ <method name="body_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter">
+ </argument>
+ <description>
+ Returns the value of a body parameter. See [enum BodyParameter] for a list of available parameters.
+ </description>
+ </method>
+ <method name="body_get_shape" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the [RID] of the nth shape of a body.
+ </description>
+ </method>
+ <method name="body_get_shape_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the number of shapes assigned to a body.
+ </description>
+ </method>
+ <method name="body_get_shape_metadata" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the metadata of a shape of a body.
+ </description>
+ </method>
+ <method name="body_get_shape_transform" qualifiers="const">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the transform matrix of a body shape.
+ </description>
+ </method>
+ <method name="body_get_space" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the [RID] of the space assigned to a body.
+ </description>
+ </method>
+ <method name="body_get_state" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="state" type="int" enum="PhysicsServer2D.BodyState">
+ </argument>
+ <description>
+ Returns a body state.
+ </description>
+ </method>
+ <method name="body_is_omitting_force_integration" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ 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_remove_collision_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="excepted_body" type="RID">
+ </argument>
+ <description>
+ Removes a body from the list of bodies exempt from collisions.
+ </description>
+ </method>
+ <method name="body_remove_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Removes a shape from a body. The shape is not deleted, so it can be reused afterwards.
+ </description>
+ </method>
+ <method name="body_set_axis_velocity">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="axis_velocity" type="Vector2">
+ </argument>
+ <description>
+ Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
+ </description>
+ </method>
+ <method name="body_set_collision_layer">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="layer" type="int">
+ </argument>
+ <description>
+ Sets the physics layer or layers a body belongs to.
+ </description>
+ </method>
+ <method name="body_set_collision_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ Sets the physics layer or layers a body can collide with.
+ </description>
+ </method>
+ <method name="body_set_continuous_collision_detection_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="PhysicsServer2D.CCDMode">
+ </argument>
+ <description>
+ Sets the continuous collision detection mode using one of the [enum CCDMode] constants.
+ Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
+ </description>
+ </method>
+ <method name="body_set_force_integration_callback">
+ <return type="void">
+ </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>
+ <argument index="3" 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]).
+ </description>
+ </method>
+ <method name="body_set_max_contacts_reported">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="amount" type="int">
+ </argument>
+ <description>
+ Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
+ </description>
+ </method>
+ <method name="body_set_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="PhysicsServer2D.BodyMode">
+ </argument>
+ <description>
+ Sets the body mode using one of the [enum BodyMode] constants.
+ </description>
+ </method>
+ <method name="body_set_omit_force_integration">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
+ </description>
+ </method>
+ <method name="body_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a body parameter. See [enum BodyParameter] for a list of available parameters.
+ </description>
+ </method>
+ <method name="body_set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="shape" type="RID">
+ </argument>
+ <description>
+ Substitutes a given body shape by another. The old shape is selected by its index, the new one by its [RID].
+ </description>
+ </method>
+ <method name="body_set_shape_as_one_way_collision">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="enable" type="bool">
+ </argument>
+ <argument index="3" name="margin" type="float">
+ </argument>
+ <description>
+ Enables one way collision on body if [code]enable[/code] is [code]true[/code].
+ </description>
+ </method>
+ <method name="body_set_shape_disabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="disabled" type="bool">
+ </argument>
+ <description>
+ Disables shape in body if [code]disable[/code] is [code]true[/code].
+ </description>
+ </method>
+ <method name="body_set_shape_metadata">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="metadata" type="Variant">
+ </argument>
+ <description>
+ Sets metadata of a shape within a body. This metadata is different from [method Object.set_meta], and can be retrieved on shape queries.
+ </description>
+ </method>
+ <method name="body_set_shape_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the transform matrix for a body shape.
+ </description>
+ </method>
+ <method name="body_set_space">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="space" type="RID">
+ </argument>
+ <description>
+ Assigns a space to the body (see [method space_create]).
+ </description>
+ </method>
+ <method name="body_set_state">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="state" type="int" enum="PhysicsServer2D.BodyState">
+ </argument>
+ <argument index="2" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets a body state using one of the [enum BodyState] constants.
+ </description>
+ </method>
+ <method name="body_test_motion">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="from" type="Transform2D">
+ </argument>
+ <argument index="2" name="motion" type="Vector2">
+ </argument>
+ <argument index="3" name="infinite_inertia" type="bool">
+ </argument>
+ <argument index="4" name="margin" type="float" default="0.08">
+ </argument>
+ <argument index="5" name="result" type="PhysicsTestMotionResult2D" default="null">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult2D] can be passed to return additional information in.
+ </description>
+ </method>
+ <method name="capsule_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="circle_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="concave_polygon_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="convex_polygon_shape_create">
+ <return type="RID">
+ </return>
+ <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_string_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.DampedStringParam">
+ </argument>
+ <description>
+ Returns the value of a damped spring joint parameter.
+ </description>
+ </method>
+ <method name="damped_string_joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.DampedStringParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a damped spring joint parameter. See [enum DampedStringParam] for a list of available parameters.
+ </description>
+ </method>
+ <method name="free_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ Destroys any of the objects created by PhysicsServer2D. If the [RID] passed is not one of the objects that can be created by PhysicsServer2D, an error will be sent to the console.
+ </description>
+ </method>
+ <method name="get_process_info">
+ <return type="int">
+ </return>
+ <argument index="0" name="process_info" type="int" enum="PhysicsServer2D.ProcessInfo">
+ </argument>
+ <description>
+ 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">
+ </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>
+ <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_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.JointParam">
+ </argument>
+ <description>
+ Returns the value of a joint parameter.
+ </description>
+ </method>
+ <method name="joint_get_type" qualifiers="const">
+ <return type="int" enum="PhysicsServer2D.JointType">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <description>
+ Returns a joint's type (see [enum JointType]).
+ </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="pin_joint_create">
+ <return type="RID">
+ </return>
+ <argument index="0" name="anchor" type="Vector2">
+ </argument>
+ <argument index="1" name="body_a" type="RID">
+ </argument>
+ <argument index="2" 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="ray_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="rectangle_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="segment_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="active" type="bool">
+ </argument>
+ <description>
+ Activates or deactivates the 2D physics engine.
+ </description>
+ </method>
+ <method name="shape_get_data" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <description>
+ Returns the shape data.
+ </description>
+ </method>
+ <method name="shape_get_type" qualifiers="const">
+ <return type="int" enum="PhysicsServer2D.ShapeType">
+ </return>
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <description>
+ Returns a shape's type (see [enum ShapeType]).
+ </description>
+ </method>
+ <method name="shape_set_data">
+ <return type="void">
+ </return>
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <argument index="1" name="data" type="Variant">
+ </argument>
+ <description>
+ Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type].
+ </description>
+ </method>
+ <method name="space_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a space. A space is a collection of parameters for the physics engine that can be assigned to an area or a body. It can be assigned to an area with [method area_set_space], or to a body with [method body_set_space].
+ </description>
+ </method>
+ <method name="space_get_direct_state">
+ <return type="PhysicsDirectSpaceState2D">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <description>
+ Returns the state of a space, a [PhysicsDirectSpaceState2D]. This object can be used to make collision/intersection queries.
+ </description>
+ </method>
+ <method name="space_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter">
+ </argument>
+ <description>
+ Returns the value of a space parameter.
+ </description>
+ </method>
+ <method name="space_is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <description>
+ Returns whether the space is active.
+ </description>
+ </method>
+ <method name="space_set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <argument index="1" name="active" type="bool">
+ </argument>
+ <description>
+ Marks a space as active. It will not have an effect, unless it is assigned to an area or body.
+ </description>
+ </method>
+ <method name="space_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets the value for a space parameter. See [enum SpaceParameter] for a list of available parameters.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="SPACE_PARAM_CONTACT_RECYCLE_RADIUS" value="0" enum="SpaceParameter">
+ Constant to set/get the maximum distance a pair of bodies has to move before their collision status has to be recalculated.
+ </constant>
+ <constant name="SPACE_PARAM_CONTACT_MAX_SEPARATION" value="1" enum="SpaceParameter">
+ Constant to set/get the maximum distance a shape can be from another before they are considered separated.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION" value="2" enum="SpaceParameter">
+ Constant to set/get the maximum distance a shape can penetrate another shape before it is considered a collision.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD" value="3" enum="SpaceParameter">
+ Constant to set/get the threshold linear velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD" value="4" enum="SpaceParameter">
+ Constant to set/get the threshold angular velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_TIME_TO_SLEEP" value="5" enum="SpaceParameter">
+ Constant to set/get the maximum time of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after this time.
+ </constant>
+ <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="6" enum="SpaceParameter">
+ Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
+ </constant>
+ <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="7" enum="SpaceParameter">
+ </constant>
+ <constant name="SHAPE_LINE" value="0" enum="ShapeType">
+ This is the constant for creating line shapes. A line shape is an infinite line with an origin point, and a normal. Thus, it can be used for front/behind checks.
+ </constant>
+ <constant name="SHAPE_RAY" value="1" enum="ShapeType">
+ </constant>
+ <constant name="SHAPE_SEGMENT" value="2" enum="ShapeType">
+ This is the constant for creating segment shapes. A segment shape is a line from a point A to a point B. It can be checked for intersections.
+ </constant>
+ <constant name="SHAPE_CIRCLE" value="3" enum="ShapeType">
+ This is the constant for creating circle shapes. A circle shape only has a radius. It can be used for intersections and inside/outside checks.
+ </constant>
+ <constant name="SHAPE_RECTANGLE" value="4" enum="ShapeType">
+ This is the constant for creating rectangle shapes. A rectangle shape is defined by a width and a height. It can be used for intersections and inside/outside checks.
+ </constant>
+ <constant name="SHAPE_CAPSULE" value="5" enum="ShapeType">
+ This is the constant for creating capsule shapes. A capsule shape is defined by a radius and a length. It can be used for intersections and inside/outside checks.
+ </constant>
+ <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
+ This is the constant for creating convex polygon shapes. A polygon is defined by a list of points. It can be used for intersections and inside/outside checks. Unlike the [member CollisionPolygon2D.polygon] property, polygons modified with [method shape_set_data] do not verify that the points supplied form is a convex polygon.
+ </constant>
+ <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
+ This is the constant for creating concave polygon shapes. A polygon is defined by a list of points. It can be used for intersections checks, but not for inside/outside checks.
+ </constant>
+ <constant name="SHAPE_CUSTOM" value="8" 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">
+ Constant to set/get gravity strength in an area.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_VECTOR" value="1" enum="AreaParameter">
+ Constant to set/get gravity vector/center in an area.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="2" enum="AreaParameter">
+ Constant to set/get whether the gravity vector of an area is a direction, or a center point.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_DISTANCE_SCALE" value="3" enum="AreaParameter">
+ Constant to set/get the falloff factor for point gravity of an area. The greater this value is, the faster the strength of gravity decreases with the square of distance.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4" enum="AreaParameter">
+ This constant was used to set/get the falloff factor for point gravity. It has been superseded by [constant AREA_PARAM_GRAVITY_DISTANCE_SCALE].
+ </constant>
+ <constant name="AREA_PARAM_LINEAR_DAMP" value="5" enum="AreaParameter">
+ Constant to set/get the linear dampening factor of an area.
+ </constant>
+ <constant name="AREA_PARAM_ANGULAR_DAMP" value="6" enum="AreaParameter">
+ Constant to set/get the angular dampening factor of an area.
+ </constant>
+ <constant name="AREA_PARAM_PRIORITY" value="7" enum="AreaParameter">
+ Constant to set/get the priority (order of processing) of an area.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_DISABLED" value="0" enum="AreaSpaceOverrideMode">
+ This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1" enum="AreaSpaceOverrideMode">
+ This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE_REPLACE" value="2" enum="AreaSpaceOverrideMode">
+ This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="3" enum="AreaSpaceOverrideMode">
+ This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE_COMBINE" value="4" enum="AreaSpaceOverrideMode">
+ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
+ </constant>
+ <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode">
+ Constant for static bodies.
+ </constant>
+ <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
+ Constant for kinematic bodies.
+ </constant>
+ <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
+ Constant for rigid bodies.
+ </constant>
+ <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode">
+ Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics.
+ </constant>
+ <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
+ Constant to set/get a body's bounce factor.
+ </constant>
+ <constant name="BODY_PARAM_FRICTION" value="1" enum="BodyParameter">
+ Constant to set/get a body's friction.
+ </constant>
+ <constant name="BODY_PARAM_MASS" value="2" enum="BodyParameter">
+ Constant to set/get a body's mass.
+ </constant>
+ <constant name="BODY_PARAM_INERTIA" value="3" enum="BodyParameter">
+ Constant to set/get a body's inertia.
+ </constant>
+ <constant name="BODY_PARAM_GRAVITY_SCALE" value="4" enum="BodyParameter">
+ Constant to set/get a body's gravity multiplier.
+ </constant>
+ <constant name="BODY_PARAM_LINEAR_DAMP" value="5" enum="BodyParameter">
+ Constant to set/get a body's linear dampening factor.
+ </constant>
+ <constant name="BODY_PARAM_ANGULAR_DAMP" value="6" enum="BodyParameter">
+ Constant to set/get a body's angular dampening factor.
+ </constant>
+ <constant name="BODY_PARAM_MAX" value="7" enum="BodyParameter">
+ Represents the size of the [enum BodyParameter] enum.
+ </constant>
+ <constant name="BODY_STATE_TRANSFORM" value="0" enum="BodyState">
+ Constant to set/get the current transform matrix of the body.
+ </constant>
+ <constant name="BODY_STATE_LINEAR_VELOCITY" value="1" enum="BodyState">
+ Constant to set/get the current linear velocity of the body.
+ </constant>
+ <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2" enum="BodyState">
+ Constant to set/get the current angular velocity of the body.
+ </constant>
+ <constant name="BODY_STATE_SLEEPING" value="3" enum="BodyState">
+ Constant to sleep/wake up a body, or to get whether it is sleeping.
+ </constant>
+ <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 to create pin joints.
+ </constant>
+ <constant name="JOINT_GROOVE" value="1" enum="JointType">
+ Constant to create groove joints.
+ </constant>
+ <constant name="JOINT_DAMPED_SPRING" value="2" enum="JointType">
+ Constant to create damped spring joints.
+ </constant>
+ <constant name="JOINT_PARAM_BIAS" value="0" enum="JointParam">
+ </constant>
+ <constant name="JOINT_PARAM_MAX_BIAS" value="1" enum="JointParam">
+ </constant>
+ <constant name="JOINT_PARAM_MAX_FORCE" value="2" enum="JointParam">
+ </constant>
+ <constant name="DAMPED_STRING_REST_LENGTH" value="0" enum="DampedStringParam">
+ Sets the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
+ </constant>
+ <constant name="DAMPED_STRING_STIFFNESS" value="1" enum="DampedStringParam">
+ Sets the stiffness of the spring joint. The joint applies a force equal to the stiffness times the distance from its resting length.
+ </constant>
+ <constant name="DAMPED_STRING_DAMPING" value="2" enum="DampedStringParam">
+ Sets the damping ratio of the spring joint. A value of 0 indicates an undamped spring, while 1 causes the system to reach equilibrium as fast as possible (critical damping).
+ </constant>
+ <constant name="CCD_MODE_DISABLED" value="0" enum="CCDMode">
+ Disables continuous collision detection. This is the fastest way to detect body collisions, but can miss small, fast-moving objects.
+ </constant>
+ <constant name="CCD_MODE_CAST_RAY" value="1" enum="CCDMode">
+ Enables continuous collision detection by raycasting. It is faster than shapecasting, but less precise.
+ </constant>
+ <constant name="CCD_MODE_CAST_SHAPE" value="2" enum="CCDMode">
+ Enables continuous collision detection by shapecasting. It is the slowest CCD method, and the most precise.
+ </constant>
+ <constant name="AREA_BODY_ADDED" value="0" enum="AreaBodyStatus">
+ The value of the first parameter and area callback function receives, when an object enters one of its shapes.
+ </constant>
+ <constant name="AREA_BODY_REMOVED" value="1" enum="AreaBodyStatus">
+ The value of the first parameter and area callback function receives, when an object exits one of its shapes.
+ </constant>
+ <constant name="INFO_ACTIVE_OBJECTS" value="0" enum="ProcessInfo">
+ Constant to get the number of objects that are not sleeping.
+ </constant>
+ <constant name="INFO_COLLISION_PAIRS" value="1" enum="ProcessInfo">
+ Constant to get the number of possible collisions.
+ </constant>
+ <constant name="INFO_ISLAND_COUNT" value="2" enum="ProcessInfo">
+ Constant to get the number of space regions where a collision could occur.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsServer2DSW.xml b/doc/classes/PhysicsServer2DSW.xml
new file mode 100644
index 0000000000..dac5e360f0
--- /dev/null
+++ b/doc/classes/PhysicsServer2DSW.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer2DSW" inherits="PhysicsServer2D" version="4.0">
+ <brief_description>
+ Software implementation of [PhysicsServer2D].
+ </brief_description>
+ <description>
+ This class exposes no new methods or properties and should not be used, as [PhysicsServer2D] automatically selects the best implementation available.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
new file mode 100644
index 0000000000..e9e1552c92
--- /dev/null
+++ b/doc/classes/PhysicsServer3D.xml
@@ -0,0 +1,1639 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsServer3D" inherits="Object" version="4.0">
+ <brief_description>
+ Server interface for low-level physics access.
+ </brief_description>
+ <description>
+ PhysicsServer3D is the server responsible for all 3D physics. It can create many kinds of physics objects, but does not insert them on the node tree.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="area_add_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="RID">
+ </argument>
+ <argument index="2" name="transform" type="Transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ </argument>
+ <argument index="3" name="disabled" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
+ </description>
+ </method>
+ <method name="area_attach_object_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ Assigns the area to a descendant of [Object], so it can exist in the node tree.
+ </description>
+ </method>
+ <method name="area_clear_shapes">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Removes all shapes from an area. It does not delete the shapes, so they can be reassigned later.
+ </description>
+ </method>
+ <method name="area_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an [Area3D].
+ </description>
+ </method>
+ <method name="area_get_object_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Gets the instance ID of the object the area is assigned to.
+ </description>
+ </method>
+ <method name="area_get_param" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter">
+ </argument>
+ <description>
+ Returns an area parameter value. A list of available parameters is on the [enum AreaParameter] constants.
+ </description>
+ </method>
+ <method name="area_get_shape" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the [RID] of the nth shape of an area.
+ </description>
+ </method>
+ <method name="area_get_shape_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the number of shapes assigned to an area.
+ </description>
+ </method>
+ <method name="area_get_shape_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the transform matrix of a shape within an area.
+ </description>
+ </method>
+ <method name="area_get_space" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the space assigned to the area.
+ </description>
+ </method>
+ <method name="area_get_space_override_mode" qualifiers="const">
+ <return type="int" enum="PhysicsServer3D.AreaSpaceOverrideMode">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ Returns the space override mode for the area.
+ </description>
+ </method>
+ <method name="area_get_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <description>
+ 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>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Removes a shape from an area. It does not delete the shape, so it can be reassigned later.
+ </description>
+ </method>
+ <method name="area_set_area_monitor_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="receiver" type="Object">
+ </argument>
+ <argument index="2" name="method" type="StringName">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_collision_layer">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="layer" type="int">
+ </argument>
+ <description>
+ Assigns the area to one or many physics layers.
+ </description>
+ </method>
+ <method name="area_set_collision_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ Sets which physics layers the area will monitor.
+ </description>
+ </method>
+ <method name="area_set_monitor_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="receiver" type="Object">
+ </argument>
+ <argument index="2" name="method" type="StringName">
+ </argument>
+ <description>
+ Sets the function to call when any body/area enters or exits the area. This callback will be called for any object interacting with the area, and takes five parameters:
+ 1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on whether the object entered or exited the area.
+ 2: [RID] of the object that entered/exited the area.
+ 3: Instance ID of the object that entered/exited the area.
+ 4: The shape index of the object that entered/exited the area.
+ 5: The shape index of the area where the object entered/exited.
+ </description>
+ </method>
+ <method name="area_set_monitorable">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="monitorable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter">
+ </argument>
+ <argument index="2" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets the value for an area parameter. A list of available parameters is on the [enum AreaParameter] constants.
+ </description>
+ </method>
+ <method name="area_set_ray_pickable">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets object pickable with rays.
+ </description>
+ </method>
+ <method name="area_set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="shape" type="RID">
+ </argument>
+ <description>
+ Substitutes a given area shape by another. The old shape is selected by its index, the new one by its [RID].
+ </description>
+ </method>
+ <method name="area_set_shape_disabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="disabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_shape_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the transform matrix for an area shape.
+ </description>
+ </method>
+ <method name="area_set_space">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="space" type="RID">
+ </argument>
+ <description>
+ Assigns a space to the area.
+ </description>
+ </method>
+ <method name="area_set_space_override_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="PhysicsServer3D.AreaSpaceOverrideMode">
+ </argument>
+ <description>
+ Sets the space override mode for the area. The modes are described in the [enum AreaSpaceOverrideMode] constants.
+ </description>
+ </method>
+ <method name="area_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the transform matrix for an area.
+ </description>
+ </method>
+ <method name="body_add_central_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="force" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_add_collision_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="excepted_body" type="RID">
+ </argument>
+ <description>
+ Adds a body to the list of bodies exempt from collisions.
+ </description>
+ </method>
+ <method name="body_add_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="force" type="Vector3">
+ </argument>
+ <argument index="2" name="position" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_add_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="RID">
+ </argument>
+ <argument index="2" name="transform" type="Transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ </argument>
+ <argument index="3" name="disabled" type="bool" default="false">
+ </argument>
+ <description>
+ Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
+ </description>
+ </method>
+ <method name="body_add_torque">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="torque" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_apply_central_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_apply_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="position" type="Vector3">
+ </argument>
+ <argument index="2" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ Gives the body a push at a [code]position[/code] in the direction of the [code]impulse[/code].
+ </description>
+ </method>
+ <method name="body_apply_torque_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ Gives the body a push to rotate it.
+ </description>
+ </method>
+ <method name="body_attach_object_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ Assigns the area to a descendant of [Object], so it can exist in the node tree.
+ </description>
+ </method>
+ <method name="body_clear_shapes">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Removes all shapes from a body.
+ </description>
+ </method>
+ <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">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the physics layer or layers a body belongs to.
+ </description>
+ </method>
+ <method name="body_get_collision_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the physics layer or layers a body can collide with.
+-
+ </description>
+ </method>
+ <method name="body_get_direct_state">
+ <return type="PhysicsDirectBodyState3D">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the [PhysicsDirectBodyState3D] of the body.
+ </description>
+ </method>
+ <method name="body_get_kinematic_safe_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_max_contacts_reported" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the maximum contacts that can be reported. See [method body_set_max_contacts_reported].
+ </description>
+ </method>
+ <method name="body_get_mode" qualifiers="const">
+ <return type="int" enum="PhysicsServer3D.BodyMode">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the body mode.
+ </description>
+ </method>
+ <method name="body_get_object_instance_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Gets the instance ID of the object the area is assigned to.
+ </description>
+ </method>
+ <method name="body_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter">
+ </argument>
+ <description>
+ Returns the value of a body parameter. A list of available parameters is on the [enum BodyParameter] constants.
+ </description>
+ </method>
+ <method name="body_get_shape" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the [RID] of the nth shape of a body.
+ </description>
+ </method>
+ <method name="body_get_shape_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the number of shapes assigned to a body.
+ </description>
+ </method>
+ <method name="body_get_shape_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Returns the transform matrix of a body shape.
+ </description>
+ </method>
+ <method name="body_get_space" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ Returns the [RID] of the space assigned to a body.
+ </description>
+ </method>
+ <method name="body_get_state" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="state" type="int" enum="PhysicsServer3D.BodyState">
+ </argument>
+ <description>
+ Returns a body state.
+ </description>
+ </method>
+ <method name="body_is_axis_locked" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_is_continuous_collision_detection_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ If [code]true[/code], the continuous collision detection mode is enabled.
+ </description>
+ </method>
+ <method name="body_is_omitting_force_integration" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ 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>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="excepted_body" type="RID">
+ </argument>
+ <description>
+ Removes a body from the list of bodies exempt from collisions.
+ Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
+ </description>
+ </method>
+ <method name="body_remove_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <description>
+ Removes a shape from a body. The shape is not deleted, so it can be reused afterwards.
+ </description>
+ </method>
+ <method name="body_set_axis_lock">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis">
+ </argument>
+ <argument index="2" name="lock" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_axis_velocity">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="axis_velocity" type="Vector3">
+ </argument>
+ <description>
+ Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
+ </description>
+ </method>
+ <method name="body_set_collision_layer">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="layer" type="int">
+ </argument>
+ <description>
+ Sets the physics layer or layers a body belongs to.
+ </description>
+ </method>
+ <method name="body_set_collision_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ Sets the physics layer or layers a body can collide with.
+ </description>
+ </method>
+ <method name="body_set_enable_continuous_collision_detection">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], the continuous collision detection mode is enabled.
+ Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
+ </description>
+ </method>
+ <method name="body_set_force_integration_callback">
+ <return type="void">
+ </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>
+ <argument index="3" 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]).
+ </description>
+ </method>
+ <method name="body_set_kinematic_safe_margin">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="margin" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_max_contacts_reported">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="amount" type="int">
+ </argument>
+ <description>
+ Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
+ </description>
+ </method>
+ <method name="body_set_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="PhysicsServer3D.BodyMode">
+ </argument>
+ <description>
+ Sets the body mode, from one of the [enum BodyMode] constants.
+ </description>
+ </method>
+ <method name="body_set_omit_force_integration">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
+ </description>
+ </method>
+ <method name="body_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a body parameter. A list of available parameters is on the [enum BodyParameter] constants.
+ </description>
+ </method>
+ <method name="body_set_ray_pickable">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets the body pickable with rays if [code]enabled[/code] is set.
+ </description>
+ </method>
+ <method name="body_set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="shape" type="RID">
+ </argument>
+ <description>
+ Substitutes a given body shape by another. The old shape is selected by its index, the new one by its [RID].
+ </description>
+ </method>
+ <method name="body_set_shape_disabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="disabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_shape_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="shape_idx" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the transform matrix for a body shape.
+ </description>
+ </method>
+ <method name="body_set_space">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="space" type="RID">
+ </argument>
+ <description>
+ Assigns a space to the body (see [method space_create]).
+ </description>
+ </method>
+ <method name="body_set_state">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="state" type="int" enum="PhysicsServer3D.BodyState">
+ </argument>
+ <argument index="2" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets a body state (see [enum BodyState] constants).
+ </description>
+ </method>
+ <method name="cone_twist_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam">
+ </argument>
+ <description>
+ Gets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
+ </description>
+ </method>
+ <method name="cone_twist_joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
+ </description>
+ </method>
+ <method name="free_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ 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">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int" enum="Vector3.Axis">
+ </argument>
+ <argument index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag">
+ </argument>
+ <description>
+ Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
+ </description>
+ </method>
+ <method name="generic_6dof_joint_get_param">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int" enum="Vector3.Axis">
+ </argument>
+ <argument index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam">
+ </argument>
+ <description>
+ Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
+ </description>
+ </method>
+ <method name="generic_6dof_joint_set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int" enum="Vector3.Axis">
+ </argument>
+ <argument index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag">
+ </argument>
+ <argument index="3" name="enable" type="bool">
+ </argument>
+ <description>
+ Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
+ </description>
+ </method>
+ <method name="generic_6dof_joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="axis" type="int" enum="Vector3.Axis">
+ </argument>
+ <argument index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam">
+ </argument>
+ <argument index="3" name="value" type="float">
+ </argument>
+ <description>
+ Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
+ </description>
+ </method>
+ <method name="get_process_info">
+ <return type="int">
+ </return>
+ <argument index="0" name="process_info" type="int" enum="PhysicsServer3D.ProcessInfo">
+ </argument>
+ <description>
+ Returns an Info defined by the [enum ProcessInfo] input given.
+ </description>
+ </method>
+ <method name="hinge_joint_get_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag">
+ </argument>
+ <description>
+ Gets a hinge_joint flag (see [enum HingeJointFlag] constants).
+ </description>
+ </method>
+ <method name="hinge_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam">
+ </argument>
+ <description>
+ Gets a hinge_joint parameter (see [enum HingeJointParam]).
+ </description>
+ </method>
+ <method name="hinge_joint_set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag">
+ </argument>
+ <argument index="2" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets a hinge_joint flag (see [enum HingeJointFlag] constants).
+ </description>
+ </method>
+ <method name="hinge_joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a hinge_joint parameter (see [enum HingeJointParam] constants).
+ </description>
+ </method>
+ <method name="joint_create_cone_twist">
+ <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">
+ </argument>
+ <argument index="3" name="local_ref_B" type="Transform">
+ </argument>
+ <description>
+ Creates a [ConeTwistJoint3D].
+ </description>
+ </method>
+ <method name="joint_create_generic_6dof">
+ <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">
+ </argument>
+ <argument index="3" name="local_ref_B" type="Transform">
+ </argument>
+ <description>
+ Creates a [Generic6DOFJoint3D].
+ </description>
+ </method>
+ <method name="joint_create_hinge">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="hinge_A" type="Transform">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="hinge_B" type="Transform">
+ </argument>
+ <description>
+ Creates a [HingeJoint3D].
+ </description>
+ </method>
+ <method name="joint_create_pin">
+ <return type="RID">
+ </return>
+ <argument index="0" name="body_A" type="RID">
+ </argument>
+ <argument index="1" name="local_A" type="Vector3">
+ </argument>
+ <argument index="2" name="body_B" type="RID">
+ </argument>
+ <argument index="3" name="local_B" type="Vector3">
+ </argument>
+ <description>
+ Creates a [PinJoint3D].
+ </description>
+ </method>
+ <method name="joint_create_slider">
+ <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">
+ </argument>
+ <argument index="3" name="local_ref_B" type="Transform">
+ </argument>
+ <description>
+ Creates a [SliderJoint3D].
+ </description>
+ </method>
+ <method name="joint_get_solver_priority" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <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>
+ Returns the type of the Joint3D.
+ </description>
+ </method>
+ <method name="joint_set_solver_priority">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="priority" type="int">
+ </argument>
+ <description>
+ Sets the priority value of the Joint3D.
+ </description>
+ </method>
+ <method name="pin_joint_get_local_a" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <description>
+ Returns position of the joint in the local space of body a of the joint.
+ </description>
+ </method>
+ <method name="pin_joint_get_local_b" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <description>
+ Returns position of the joint in the local space of body b of the joint.
+ </description>
+ </method>
+ <method name="pin_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam">
+ </argument>
+ <description>
+ Gets a pin_joint parameter (see [enum PinJointParam] constants).
+ </description>
+ </method>
+ <method name="pin_joint_set_local_a">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="local_A" type="Vector3">
+ </argument>
+ <description>
+ Sets position of the joint in the local space of body a of the joint.
+ </description>
+ </method>
+ <method name="pin_joint_set_local_b">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="local_B" type="Vector3">
+ </argument>
+ <description>
+ Sets position of the joint in the local space of body b of the joint.
+ </description>
+ </method>
+ <method name="pin_joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets a pin_joint parameter (see [enum PinJointParam] constants).
+ </description>
+ </method>
+ <method name="set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="active" type="bool">
+ </argument>
+ <description>
+ Activates or deactivates the 3D physics engine.
+ </description>
+ </method>
+ <method name="shape_create">
+ <return type="RID">
+ </return>
+ <argument index="0" name="type" type="int" enum="PhysicsServer3D.ShapeType">
+ </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].
+ </description>
+ </method>
+ <method name="shape_get_data" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <description>
+ Returns the shape data.
+ </description>
+ </method>
+ <method name="shape_get_type" qualifiers="const">
+ <return type="int" enum="PhysicsServer3D.ShapeType">
+ </return>
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <description>
+ Returns the type of shape (see [enum ShapeType] constants).
+ </description>
+ </method>
+ <method name="shape_set_data">
+ <return type="void">
+ </return>
+ <argument index="0" name="shape" type="RID">
+ </argument>
+ <argument index="1" name="data" type="Variant">
+ </argument>
+ <description>
+ Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type].
+ </description>
+ </method>
+ <method name="slider_joint_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam">
+ </argument>
+ <description>
+ Gets a slider_joint parameter (see [enum SliderJointParam] constants).
+ </description>
+ </method>
+ <method name="slider_joint_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="joint" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Gets a slider_joint parameter (see [enum SliderJointParam] constants).
+ </description>
+ </method>
+ <method name="space_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a space. A space is a collection of parameters for the physics engine that can be assigned to an area or a body. It can be assigned to an area with [method area_set_space], or to a body with [method body_set_space].
+ </description>
+ </method>
+ <method name="space_get_direct_state">
+ <return type="PhysicsDirectSpaceState3D">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <description>
+ Returns the state of a space, a [PhysicsDirectSpaceState3D]. This object can be used to make collision/intersection queries.
+ </description>
+ </method>
+ <method name="space_get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter">
+ </argument>
+ <description>
+ Returns the value of a space parameter.
+ </description>
+ </method>
+ <method name="space_is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <description>
+ Returns whether the space is active.
+ </description>
+ </method>
+ <method name="space_set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <argument index="1" name="active" type="bool">
+ </argument>
+ <description>
+ Marks a space as active. It will not have an effect, unless it is assigned to an area or body.
+ </description>
+ </method>
+ <method name="space_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="space" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets the value for a space parameter. A list of available parameters is on the [enum SpaceParameter] constants.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="JOINT_PIN" value="0" enum="JointType">
+ The [Joint3D] is a [PinJoint3D].
+ </constant>
+ <constant name="JOINT_HINGE" value="1" enum="JointType">
+ The [Joint3D] is a [HingeJoint3D].
+ </constant>
+ <constant name="JOINT_SLIDER" value="2" enum="JointType">
+ The [Joint3D] is a [SliderJoint3D].
+ </constant>
+ <constant name="JOINT_CONE_TWIST" value="3" enum="JointType">
+ The [Joint3D] is a [ConeTwistJoint3D].
+ </constant>
+ <constant name="JOINT_6DOF" value="4" enum="JointType">
+ The [Joint3D] is a [Generic6DOFJoint3D].
+ </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.
+ </constant>
+ <constant name="PIN_JOINT_DAMPING" value="1" enum="PinJointParam">
+ The strength with which the pinned objects try to stay in velocity relation to each other.
+ The higher, the stronger.
+ </constant>
+ <constant name="PIN_JOINT_IMPULSE_CLAMP" value="2" enum="PinJointParam">
+ If above 0, this value is the maximum value for an impulse that this Joint3D puts on its ends.
+ </constant>
+ <constant name="HINGE_JOINT_BIAS" value="0" enum="HingeJointParam">
+ The speed with which the two bodies get pulled together when they move in different directions.
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_UPPER" value="1" enum="HingeJointParam">
+ The maximum rotation across the Hinge.
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_LOWER" value="2" enum="HingeJointParam">
+ The minimum rotation across the Hinge.
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_BIAS" value="3" enum="HingeJointParam">
+ The speed with which the rotation across the axis perpendicular to the hinge gets corrected.
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_SOFTNESS" value="4" enum="HingeJointParam">
+ </constant>
+ <constant name="HINGE_JOINT_LIMIT_RELAXATION" value="5" enum="HingeJointParam">
+ The lower this value, the more the rotation gets slowed down.
+ </constant>
+ <constant name="HINGE_JOINT_MOTOR_TARGET_VELOCITY" value="6" enum="HingeJointParam">
+ Target speed for the motor.
+ </constant>
+ <constant name="HINGE_JOINT_MOTOR_MAX_IMPULSE" value="7" enum="HingeJointParam">
+ Maximum acceleration for the motor.
+ </constant>
+ <constant name="HINGE_JOINT_FLAG_USE_LIMIT" value="0" enum="HingeJointFlag">
+ If [code]true[/code], the Hinge has a maximum and a minimum rotation.
+ </constant>
+ <constant name="HINGE_JOINT_FLAG_ENABLE_MOTOR" value="1" enum="HingeJointFlag">
+ If [code]true[/code], a motor turns the Hinge.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_UPPER" value="0" enum="SliderJointParam">
+ The maximum difference between the pivot points on their X axis before damping happens.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_LOWER" value="1" enum="SliderJointParam">
+ The minimum difference between the pivot points on their X axis before damping happens.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS" value="2" enum="SliderJointParam">
+ A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION" value="3" enum="SliderJointParam">
+ The amount of restitution once the limits are surpassed. The lower, the more velocityenergy gets lost.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_LIMIT_DAMPING" value="4" enum="SliderJointParam">
+ The amount of damping once the slider limits are surpassed.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_MOTION_SOFTNESS" value="5" enum="SliderJointParam">
+ A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_MOTION_RESTITUTION" value="6" enum="SliderJointParam">
+ The amount of restitution inside the slider limits.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_MOTION_DAMPING" value="7" enum="SliderJointParam">
+ The amount of damping inside the slider limits.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS" value="8" enum="SliderJointParam">
+ A factor applied to the movement across axes orthogonal to the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION" value="9" enum="SliderJointParam">
+ The amount of restitution when movement is across axes orthogonal to the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING" value="10" enum="SliderJointParam">
+ The amount of damping when movement is across axes orthogonal to the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_UPPER" value="11" enum="SliderJointParam">
+ The upper limit of rotation in the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_LOWER" value="12" enum="SliderJointParam">
+ The lower limit of rotation in the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS" value="13" enum="SliderJointParam">
+ A factor applied to the all rotation once the limit is surpassed.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION" value="14" enum="SliderJointParam">
+ The amount of restitution of the rotation when the limit is surpassed.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_LIMIT_DAMPING" value="15" enum="SliderJointParam">
+ The amount of damping of the rotation when the limit is surpassed.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS" value="16" enum="SliderJointParam">
+ A factor that gets applied to the all rotation in the limits.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION" value="17" enum="SliderJointParam">
+ The amount of restitution of the rotation in the limits.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_MOTION_DAMPING" value="18" enum="SliderJointParam">
+ The amount of damping of the rotation in the limits.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS" value="19" enum="SliderJointParam">
+ A factor that gets applied to the all rotation across axes orthogonal to the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION" value="20" enum="SliderJointParam">
+ The amount of restitution of the rotation across axes orthogonal to the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING" value="21" enum="SliderJointParam">
+ The amount of damping of the rotation across axes orthogonal to the slider.
+ </constant>
+ <constant name="SLIDER_JOINT_MAX" value="22" enum="SliderJointParam">
+ Represents the size of the [enum SliderJointParam] enum.
+ </constant>
+ <constant name="CONE_TWIST_JOINT_SWING_SPAN" value="0" enum="ConeTwistJointParam">
+ Swing is rotation from side to side, around the axis perpendicular to the twist axis.
+ The swing span defines, how much rotation will not get corrected along the swing axis.
+ Could be defined as looseness in the [ConeTwistJoint3D].
+ If below 0.05, this behavior is locked.
+ </constant>
+ <constant name="CONE_TWIST_JOINT_TWIST_SPAN" value="1" enum="ConeTwistJointParam">
+ Twist is the rotation around the twist axis, this value defined how far the joint can twist.
+ Twist is locked if below 0.05.
+ </constant>
+ <constant name="CONE_TWIST_JOINT_BIAS" value="2" enum="ConeTwistJointParam">
+ The speed with which the swing or twist will take place.
+ The higher, the faster.
+ </constant>
+ <constant name="CONE_TWIST_JOINT_SOFTNESS" value="3" enum="ConeTwistJointParam">
+ The ease with which the Joint3D twists, if it's too low, it takes more force to twist the joint.
+ </constant>
+ <constant name="CONE_TWIST_JOINT_RELAXATION" value="4" enum="ConeTwistJointParam">
+ Defines, how fast the swing- and twist-speed-difference on both sides gets synced.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_LOWER_LIMIT" value="0" enum="G6DOFJointAxisParam">
+ The minimum difference between the pivot points' axes.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_UPPER_LIMIT" value="1" enum="G6DOFJointAxisParam">
+ The maximum difference between the pivot points' axes.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS" value="2" enum="G6DOFJointAxisParam">
+ A factor that gets applied to the movement across the axes. The lower, the slower the movement.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_RESTITUTION" value="3" enum="G6DOFJointAxisParam">
+ The amount of restitution on the axes movement. The lower, the more velocity-energy gets lost.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_DAMPING" value="4" enum="G6DOFJointAxisParam">
+ The amount of damping that happens at the linear motion across the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY" value="5" enum="G6DOFJointAxisParam">
+ The velocity that the joint's linear motor will attempt to reach.
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT" value="6" enum="G6DOFJointAxisParam">
+ The maximum force that the linear motor can apply while trying to reach the target velocity.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_LOWER_LIMIT" value="10" enum="G6DOFJointAxisParam">
+ The minimum rotation in negative direction to break loose and rotate around the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_UPPER_LIMIT" value="11" enum="G6DOFJointAxisParam">
+ The minimum rotation in positive direction to break loose and rotate around the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS" value="12" enum="G6DOFJointAxisParam">
+ A factor that gets multiplied onto all rotations across the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_DAMPING" value="13" enum="G6DOFJointAxisParam">
+ The amount of rotational damping across the axes. The lower, the more dampening occurs.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_RESTITUTION" value="14" enum="G6DOFJointAxisParam">
+ The amount of rotational restitution across the axes. The lower, the more restitution occurs.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_FORCE_LIMIT" value="15" enum="G6DOFJointAxisParam">
+ The maximum amount of force that can occur, when rotating around the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_ERP" value="16" enum="G6DOFJointAxisParam">
+ When correcting the crossing of limits in rotation across the axes, this error tolerance factor defines how much the correction gets slowed down. The lower, the slower.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY" value="17" enum="G6DOFJointAxisParam">
+ Target speed for the motor at the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT" value="18" enum="G6DOFJointAxisParam">
+ Maximum acceleration for the motor at the axes.
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT" value="0" enum="G6DOFJointAxisFlag">
+ If [code]set[/code] there is linear motion possible within the given limits.
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT" value="1" enum="G6DOFJointAxisFlag">
+ If [code]set[/code] there is rotational motion possible.
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_MOTOR" value="4" enum="G6DOFJointAxisFlag">
+ If [code]set[/code] there is a rotational motor across these axes.
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="G6DOFJointAxisFlag">
+ If [code]set[/code] there is a linear motor on this axis that targets a specific velocity.
+ </constant>
+ <constant name="SHAPE_PLANE" value="0" enum="ShapeType">
+ The [Shape3D] is a [WorldMarginShape3D].
+ </constant>
+ <constant name="SHAPE_RAY" value="1" enum="ShapeType">
+ The [Shape3D] is a [RayShape3D].
+ </constant>
+ <constant name="SHAPE_SPHERE" value="2" enum="ShapeType">
+ The [Shape3D] is a [SphereShape3D].
+ </constant>
+ <constant name="SHAPE_BOX" value="3" enum="ShapeType">
+ The [Shape3D] is a [BoxShape3D].
+ </constant>
+ <constant name="SHAPE_CAPSULE" value="4" enum="ShapeType">
+ The [Shape3D] is a [CapsuleShape3D].
+ </constant>
+ <constant name="SHAPE_CYLINDER" value="5" enum="ShapeType">
+ The [Shape3D] is a [CylinderShape3D].
+ </constant>
+ <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
+ The [Shape3D] is a [ConvexPolygonShape3D].
+ </constant>
+ <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
+ The [Shape3D] is a [ConcavePolygonShape3D].
+ </constant>
+ <constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType">
+ The [Shape3D] is a [HeightMapShape3D].
+ </constant>
+ <constant name="SHAPE_CUSTOM" value="9" 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">
+ Constant to set/get gravity strength in an area.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_VECTOR" value="1" enum="AreaParameter">
+ Constant to set/get gravity vector/center in an area.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="2" enum="AreaParameter">
+ Constant to set/get whether the gravity vector of an area is a direction, or a center point.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_DISTANCE_SCALE" value="3" enum="AreaParameter">
+ Constant to set/get the falloff factor for point gravity of an area. The greater this value is, the faster the strength of gravity decreases with the square of distance.
+ </constant>
+ <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4" enum="AreaParameter">
+ This constant was used to set/get the falloff factor for point gravity. It has been superseded by [constant AREA_PARAM_GRAVITY_DISTANCE_SCALE].
+ </constant>
+ <constant name="AREA_PARAM_LINEAR_DAMP" value="5" enum="AreaParameter">
+ Constant to set/get the linear dampening factor of an area.
+ </constant>
+ <constant name="AREA_PARAM_ANGULAR_DAMP" value="6" enum="AreaParameter">
+ Constant to set/get the angular dampening factor of an area.
+ </constant>
+ <constant name="AREA_PARAM_PRIORITY" value="7" enum="AreaParameter">
+ Constant to set/get the priority (order of processing) of an area.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_DISABLED" value="0" enum="AreaSpaceOverrideMode">
+ This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1" enum="AreaSpaceOverrideMode">
+ This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE_REPLACE" value="2" enum="AreaSpaceOverrideMode">
+ This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="3" enum="AreaSpaceOverrideMode">
+ This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE_COMBINE" value="4" enum="AreaSpaceOverrideMode">
+ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
+ </constant>
+ <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode">
+ Constant for static bodies.
+ </constant>
+ <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
+ Constant for kinematic bodies.
+ </constant>
+ <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
+ Constant for rigid bodies.
+ </constant>
+ <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode">
+ Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics.
+ </constant>
+ <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
+ Constant to set/get a body's bounce factor.
+ </constant>
+ <constant name="BODY_PARAM_FRICTION" value="1" enum="BodyParameter">
+ Constant to set/get a body's friction.
+ </constant>
+ <constant name="BODY_PARAM_MASS" value="2" enum="BodyParameter">
+ Constant to set/get a body's mass.
+ </constant>
+ <constant name="BODY_PARAM_GRAVITY_SCALE" value="3" enum="BodyParameter">
+ Constant to set/get a body's gravity multiplier.
+ </constant>
+ <constant name="BODY_PARAM_LINEAR_DAMP" value="4" enum="BodyParameter">
+ Constant to set/get a body's linear dampening factor.
+ </constant>
+ <constant name="BODY_PARAM_ANGULAR_DAMP" value="5" enum="BodyParameter">
+ Constant to set/get a body's angular dampening factor.
+ </constant>
+ <constant name="BODY_PARAM_MAX" value="6" enum="BodyParameter">
+ Represents the size of the [enum BodyParameter] enum.
+ </constant>
+ <constant name="BODY_STATE_TRANSFORM" value="0" enum="BodyState">
+ Constant to set/get the current transform matrix of the body.
+ </constant>
+ <constant name="BODY_STATE_LINEAR_VELOCITY" value="1" enum="BodyState">
+ Constant to set/get the current linear velocity of the body.
+ </constant>
+ <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2" enum="BodyState">
+ Constant to set/get the current angular velocity of the body.
+ </constant>
+ <constant name="BODY_STATE_SLEEPING" value="3" enum="BodyState">
+ Constant to sleep/wake up a body, or to get whether it is sleeping.
+ </constant>
+ <constant name="BODY_STATE_CAN_SLEEP" value="4" enum="BodyState">
+ Constant to set/get whether the body can sleep.
+ </constant>
+ <constant name="AREA_BODY_ADDED" value="0" enum="AreaBodyStatus">
+ The value of the first parameter and area callback function receives, when an object enters one of its shapes.
+ </constant>
+ <constant name="AREA_BODY_REMOVED" value="1" enum="AreaBodyStatus">
+ The value of the first parameter and area callback function receives, when an object exits one of its shapes.
+ </constant>
+ <constant name="INFO_ACTIVE_OBJECTS" value="0" enum="ProcessInfo">
+ Constant to get the number of objects that are not sleeping.
+ </constant>
+ <constant name="INFO_COLLISION_PAIRS" value="1" enum="ProcessInfo">
+ Constant to get the number of possible collisions.
+ </constant>
+ <constant name="INFO_ISLAND_COUNT" value="2" enum="ProcessInfo">
+ Constant to get the number of space regions where a collision could occur.
+ </constant>
+ <constant name="SPACE_PARAM_CONTACT_RECYCLE_RADIUS" value="0" enum="SpaceParameter">
+ Constant to set/get the maximum distance a pair of bodies has to move before their collision status has to be recalculated.
+ </constant>
+ <constant name="SPACE_PARAM_CONTACT_MAX_SEPARATION" value="1" enum="SpaceParameter">
+ Constant to set/get the maximum distance a shape can be from another before they are considered separated.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION" value="2" enum="SpaceParameter">
+ Constant to set/get the maximum distance a shape can penetrate another shape before it is considered a collision.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD" value="3" enum="SpaceParameter">
+ Constant to set/get the threshold linear velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD" value="4" enum="SpaceParameter">
+ Constant to set/get the threshold angular velocity of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after the time given.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_TIME_TO_SLEEP" value="5" enum="SpaceParameter">
+ Constant to set/get the maximum time of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after this time.
+ </constant>
+ <constant name="SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO" value="6" enum="SpaceParameter">
+ </constant>
+ <constant name="SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS" value="7" enum="SpaceParameter">
+ Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
+ </constant>
+ <constant name="SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH" value="8" enum="SpaceParameter">
+ </constant>
+ <constant name="BODY_AXIS_LINEAR_X" value="1" enum="BodyAxis">
+ </constant>
+ <constant name="BODY_AXIS_LINEAR_Y" value="2" enum="BodyAxis">
+ </constant>
+ <constant name="BODY_AXIS_LINEAR_Z" value="4" enum="BodyAxis">
+ </constant>
+ <constant name="BODY_AXIS_ANGULAR_X" value="8" enum="BodyAxis">
+ </constant>
+ <constant name="BODY_AXIS_ANGULAR_Y" value="16" enum="BodyAxis">
+ </constant>
+ <constant name="BODY_AXIS_ANGULAR_Z" value="32" enum="BodyAxis">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsShapeQueryParameters.xml b/doc/classes/PhysicsShapeQueryParameters.xml
deleted file mode 100644
index 829a1d1bf0..0000000000
--- a/doc/classes/PhysicsShapeQueryParameters.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryParameters" inherits="Reference" version="4.0">
- <brief_description>
- Parameters to be sent to a 3D shape physics query.
- </brief_description>
- <description>
- This class contains the shape and other parameters for 3D intersection/collision queries. See also [PhysicsShapeQueryResult].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="set_shape">
- <return type="void">
- </return>
- <argument index="0" name="shape" type="Resource">
- </argument>
- <description>
- Sets the [Shape] that will be used for collision/intersection queries.
- </description>
- </method>
- </methods>
- <members>
- <member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
- If [code]true[/code], the query will take [Area]s into account.
- </member>
- <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
- If [code]true[/code], the query will take [PhysicsBody]s into account.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647">
- The physics layer(s) the query will take into account (as a bitmask).
- </member>
- <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]">
- The list of objects or object [RID]s that will be excluded from collisions.
- </member>
- <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
- The collision margin for the shape.
- </member>
- <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid">
- The queried shape's [RID]. See also [method set_shape].
- </member>
- <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- The queried shape's transform matrix.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml
new file mode 100644
index 0000000000..9a162dabbb
--- /dev/null
+++ b/doc/classes/PhysicsShapeQueryParameters2D.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsShapeQueryParameters2D" inherits="Reference" version="4.0">
+ <brief_description>
+ Parameters to be sent to a 2D shape physics query.
+ </brief_description>
+ <description>
+ This class contains the shape and other parameters for 2D intersection/collision queries. See also [PhysicsShapeQueryResult2D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="shape" type="Resource">
+ </argument>
+ <description>
+ Sets the [Shape2D] that will be used for collision/intersection queries.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
+ If [code]true[/code], the query will take [Area2D]s into account.
+ </member>
+ <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
+ If [code]true[/code], the query will take [PhysicsBody2D]s into account.
+ </member>
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="2147483647">
+ The physics layer(s) the query will take into account (as a bitmask).
+ </member>
+ <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]">
+ The list of objects or object [RID]s that will be excluded from collisions.
+ </member>
+ <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
+ The collision margin for the shape.
+ </member>
+ <member name="motion" type="Vector2" setter="set_motion" getter="get_motion" default="Vector2( 0, 0 )">
+ The motion of the shape being queried for.
+ </member>
+ <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid">
+ The queried shape's [RID]. See also [method set_shape].
+ </member>
+ <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, 1, 0, 0 )">
+ The queried shape's transform matrix.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml
new file mode 100644
index 0000000000..6606cfbc59
--- /dev/null
+++ b/doc/classes/PhysicsShapeQueryParameters3D.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsShapeQueryParameters3D" inherits="Reference" version="4.0">
+ <brief_description>
+ Parameters to be sent to a 3D shape physics query.
+ </brief_description>
+ <description>
+ This class contains the shape and other parameters for 3D intersection/collision queries. See also [PhysicsShapeQueryResult3D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="shape" type="Resource">
+ </argument>
+ <description>
+ Sets the [Shape3D] that will be used for collision/intersection queries.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
+ If [code]true[/code], the query will take [Area3D]s into account.
+ </member>
+ <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
+ If [code]true[/code], the query will take [PhysicsBody3D]s into account.
+ </member>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647">
+ The physics layer(s) the query will take into account (as a bitmask).
+ </member>
+ <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]">
+ The list of objects or object [RID]s that will be excluded from collisions.
+ </member>
+ <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
+ The collision margin for the shape.
+ </member>
+ <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid">
+ The queried shape's [RID]. See also [method set_shape].
+ </member>
+ <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ The queried shape's transform matrix.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsShapeQueryResult.xml b/doc/classes/PhysicsShapeQueryResult.xml
deleted file mode 100644
index ea6dc2c39e..0000000000
--- a/doc/classes/PhysicsShapeQueryResult.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsShapeQueryResult" inherits="Reference" version="4.0">
- <brief_description>
- Result of a 3D shape query in [PhysicsServer].
- </brief_description>
- <description>
- The result of a 3D shape query in [PhysicsServer]. See also [PhysicsShapeQueryParameters].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_result_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the number of objects that intersected with the shape.
- </description>
- </method>
- <method name="get_result_object" qualifiers="const">
- <return type="Object">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the [Object] that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- <method name="get_result_object_id" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the instance ID of the [Object] that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- <method name="get_result_object_shape" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the child index of the object's [Shape] that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- <method name="get_result_rid" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Returns the [RID] of the object that intersected with the shape at index [code]idx[/code].
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/PhysicsShapeQueryResult2D.xml b/doc/classes/PhysicsShapeQueryResult2D.xml
new file mode 100644
index 0000000000..227683cc33
--- /dev/null
+++ b/doc/classes/PhysicsShapeQueryResult2D.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsShapeQueryResult2D" inherits="Reference" version="4.0">
+ <brief_description>
+ Result of a 2D shape query in [PhysicsServer2D].
+ </brief_description>
+ <description>
+ The result of a 2D shape query in [PhysicsServer2D]. See also [PhysicsShapeQueryParameters2D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_result_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of objects that intersected with the shape.
+ </description>
+ </method>
+ <method name="get_result_object" qualifiers="const">
+ <return type="Object">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the [Object] that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ <method name="get_result_object_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the instance ID of the [Object] that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ <method name="get_result_object_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the child index of the object's [Shape2D] that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ <method name="get_result_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the [RID] of the object that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsShapeQueryResult3D.xml b/doc/classes/PhysicsShapeQueryResult3D.xml
new file mode 100644
index 0000000000..4555c4e242
--- /dev/null
+++ b/doc/classes/PhysicsShapeQueryResult3D.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsShapeQueryResult3D" inherits="Reference" version="4.0">
+ <brief_description>
+ Result of a 3D shape query in [PhysicsServer3D].
+ </brief_description>
+ <description>
+ The result of a 3D shape query in [PhysicsServer3D]. See also [PhysicsShapeQueryParameters3D].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_result_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of objects that intersected with the shape.
+ </description>
+ </method>
+ <method name="get_result_object" qualifiers="const">
+ <return type="Object">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the [Object] that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ <method name="get_result_object_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the instance ID of the [Object] that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ <method name="get_result_object_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the child index of the object's [Shape3D] that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ <method name="get_result_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the [RID] of the object that intersected with the shape at index [code]idx[/code].
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsTestMotionResult2D.xml b/doc/classes/PhysicsTestMotionResult2D.xml
new file mode 100644
index 0000000000..301cff2885
--- /dev/null
+++ b/doc/classes/PhysicsTestMotionResult2D.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PhysicsTestMotionResult2D" inherits="Reference" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="collider" type="Object" setter="" getter="get_collider">
+ </member>
+ <member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
+ </member>
+ <member name="collider_rid" type="RID" setter="" getter="get_collider_rid">
+ </member>
+ <member name="collider_shape" type="int" setter="" getter="get_collider_shape" default="0">
+ </member>
+ <member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2( 0, 0 )">
+ </member>
+ <member name="collision_normal" type="Vector2" setter="" getter="get_collision_normal" default="Vector2( 0, 0 )">
+ </member>
+ <member name="collision_point" type="Vector2" setter="" getter="get_collision_point" default="Vector2( 0, 0 )">
+ </member>
+ <member name="motion" type="Vector2" setter="" getter="get_motion" default="Vector2( 0, 0 )">
+ </member>
+ <member name="motion_remainder" type="Vector2" setter="" getter="get_motion_remainder" default="Vector2( 0, 0 )">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PinJoint.xml b/doc/classes/PinJoint.xml
deleted file mode 100644
index de4cb9d98a..0000000000
--- a/doc/classes/PinJoint.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PinJoint" inherits="Joint" version="4.0">
- <brief_description>
- Pin joint for 3D shapes.
- </brief_description>
- <description>
- Pin joint for 3D rigid bodies. It pins 2 bodies (rigid or static) together.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="PinJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="PinJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="params/bias" type="float" setter="set_param" getter="get_param" default="0.3">
- The force with which the pinned objects stay in positional relation to each other. The higher, the stronger.
- </member>
- <member name="params/damping" type="float" setter="set_param" getter="get_param" default="1.0">
- The force with which the pinned objects stay in velocity relation to each other. The higher, the stronger.
- </member>
- <member name="params/impulse_clamp" type="float" setter="set_param" getter="get_param" default="0.0">
- If above 0, this value is the maximum value for an impulse that this Joint produces.
- </member>
- </members>
- <constants>
- <constant name="PARAM_BIAS" value="0" enum="Param">
- The force with which the pinned objects stay in positional relation to each other. The higher, the stronger.
- </constant>
- <constant name="PARAM_DAMPING" value="1" enum="Param">
- The force with which the pinned objects stay in velocity relation to each other. The higher, the stronger.
- </constant>
- <constant name="PARAM_IMPULSE_CLAMP" value="2" enum="Param">
- If above 0, this value is the maximum value for an impulse that this Joint produces.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/PinJoint2D.xml b/doc/classes/PinJoint2D.xml
index 020babdf40..42155a7f25 100644
--- a/doc/classes/PinJoint2D.xml
+++ b/doc/classes/PinJoint2D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PinJoint2D" inherits="Joint2D" version="4.0">
<brief_description>
- Pin Joint for 2D shapes.
+ Pin joint for 2D shapes.
</brief_description>
<description>
- Pin Joint for 2D rigid bodies. It pins two bodies (rigid or static) together.
+ Pin joint for 2D rigid bodies. It pins two bodies (rigid or static) together.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PinJoint3D.xml b/doc/classes/PinJoint3D.xml
new file mode 100644
index 0000000000..0af1e60839
--- /dev/null
+++ b/doc/classes/PinJoint3D.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="PinJoint3D" inherits="Joint3D" version="4.0">
+ <brief_description>
+ Pin joint for 3D shapes.
+ </brief_description>
+ <description>
+ Pin joint for 3D rigid bodies. It pins 2 bodies (rigid or static) together.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="PinJoint3D.Param">
+ </argument>
+ <description>
+ Returns the value of the specified parameter.
+ </description>
+ </method>
+ <method name="set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="PinJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ Sets the value of the specified parameter.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="params/bias" type="float" setter="set_param" getter="get_param" default="0.3">
+ The force with which the pinned objects stay in positional relation to each other. The higher, the stronger.
+ </member>
+ <member name="params/damping" type="float" setter="set_param" getter="get_param" default="1.0">
+ The force with which the pinned objects stay in velocity relation to each other. The higher, the stronger.
+ </member>
+ <member name="params/impulse_clamp" type="float" setter="set_param" getter="get_param" default="0.0">
+ If above 0, this value is the maximum value for an impulse that this Joint3D produces.
+ </member>
+ </members>
+ <constants>
+ <constant name="PARAM_BIAS" value="0" enum="Param">
+ The force with which the pinned objects stay in positional relation to each other. The higher, the stronger.
+ </constant>
+ <constant name="PARAM_DAMPING" value="1" enum="Param">
+ The force with which the pinned objects stay in velocity relation to each other. The higher, the stronger.
+ </constant>
+ <constant name="PARAM_IMPULSE_CLAMP" value="2" enum="Param">
+ If above 0, this value is the maximum value for an impulse that this Joint3D produces.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml
index f777545733..13332ca4f0 100644
--- a/doc/classes/Polygon2D.xml
+++ b/doc/classes/Polygon2D.xml
@@ -17,12 +17,14 @@
<argument index="1" name="weights" type="PackedFloat32Array">
</argument>
<description>
+ Adds a bone with the specified [code]path[/code] and [code]weights[/code].
</description>
</method>
<method name="clear_bones">
<return type="void">
</return>
<description>
+ Removes all bones from this [Polygon2D].
</description>
</method>
<method name="erase_bone">
@@ -31,12 +33,14 @@
<argument index="0" name="index" type="int">
</argument>
<description>
+ Removes the specified bone from this [Polygon2D].
</description>
</method>
<method name="get_bone_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of bones in this [Polygon2D].
</description>
</method>
<method name="get_bone_path" qualifiers="const">
@@ -45,6 +49,7 @@
<argument index="0" name="index" type="int">
</argument>
<description>
+ Returns the path to the node associated with the specified bone.
</description>
</method>
<method name="get_bone_weights" qualifiers="const">
@@ -53,6 +58,7 @@
<argument index="0" name="index" type="int">
</argument>
<description>
+ Returns the height values of the specified bone.
</description>
</method>
<method name="set_bone_path">
@@ -63,6 +69,7 @@
<argument index="1" name="path" type="NodePath">
</argument>
<description>
+ Sets the path to the node associated with the specified bone.
</description>
</method>
<method name="set_bone_weights">
@@ -73,6 +80,7 @@
<argument index="1" name="weights" type="PackedFloat32Array">
</argument>
<description>
+ Sets the weight values for the specified bone.
</description>
</method>
</methods>
diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml
index 483e262f60..6f77f3371d 100644
--- a/doc/classes/Popup.xml
+++ b/doc/classes/Popup.xml
@@ -1,81 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Popup" inherits="Control" version="4.0">
+<class name="Popup" inherits="Window" version="4.0">
<brief_description>
Base container control for popups and dialogs.
</brief_description>
<description>
- Popup is a base [Control] used to show dialogs and popups. It's a subwindow and modal by default (see [Control]) and has helpers for custom popup behavior. All popup methods ensure correct placement within the viewport.
+ Popup is a base [Control] used to show dialogs and popups. It's a subwindow and modal by default (see [Control]) and has helpers for custom popup behavior.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="popup">
- <return type="void">
- </return>
- <argument index="0" name="bounds" type="Rect2" default="Rect2( 0, 0, 0, 0 )">
- </argument>
- <description>
- Popup (show the control in modal form).
- </description>
- </method>
- <method name="popup_centered">
- <return type="void">
- </return>
- <argument index="0" name="size" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <description>
- Popup (show the control in modal form) in the center of the screen relative to its current canvas transform, at the current size, or at a size determined by [code]size[/code].
- </description>
- </method>
- <method name="popup_centered_clamped">
- <return type="void">
- </return>
- <argument index="0" name="size" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <argument index="1" name="fallback_ratio" type="float" default="0.75">
- </argument>
- <description>
- Popup (show the control in modal form) in the center of the screen relative to the current canvas transform, clamping the size to [code]size[/code], then ensuring the popup is no larger than the viewport size multiplied by [code]fallback_ratio[/code].
- </description>
- </method>
- <method name="popup_centered_minsize">
- <return type="void">
- </return>
- <argument index="0" name="minsize" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <description>
- Popup (show the control in modal form) in the center of the screen relative to the current canvas transform, ensuring the size is never smaller than [code]minsize[/code].
- </description>
- </method>
- <method name="popup_centered_ratio">
- <return type="void">
- </return>
- <argument index="0" name="ratio" type="float" default="0.75">
- </argument>
- <description>
- Popup (show the control in modal form) in the center of the screen relative to the current canvas transform, scaled at a ratio of size of the screen.
- </description>
- </method>
- <method name="set_as_minsize">
- <return type="void">
- </return>
- <description>
- Shrink popup to keep to the minimum size of content.
- </description>
- </method>
</methods>
<members>
- <member name="popup_exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false">
- If [code]true[/code], the popup will not be hidden when a click event occurs outside of it, or when it receives the [code]ui_cancel[/code] action event.
- </member>
+ <member name="borderless" type="bool" setter="set_flag" getter="get_flag" override="true" default="true" />
+ <member name="transient" type="bool" setter="set_transient" getter="is_transient" override="true" default="true" />
+ <member name="unresizable" type="bool" setter="set_flag" getter="get_flag" override="true" default="true" />
<member name="visible" type="bool" setter="set_visible" getter="is_visible" override="true" default="false" />
+ <member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" override="true" default="true" />
</members>
<signals>
- <signal name="about_to_show">
- <description>
- Emitted when a popup is about to be shown. This is often used in [PopupMenu] to clear the list of options then create a new one according to the current context.
- </description>
- </signal>
<signal name="popup_hide">
<description>
Emitted when a popup is hidden.
@@ -83,11 +25,5 @@
</signal>
</signals>
<constants>
- <constant name="NOTIFICATION_POST_POPUP" value="80">
- Notification sent right after the popup is shown.
- </constant>
- <constant name="NOTIFICATION_POPUP_HIDE" value="81">
- Notification sent right after the popup is hidden.
- </constant>
</constants>
</class>
diff --git a/doc/classes/PopupDialog.xml b/doc/classes/PopupDialog.xml
deleted file mode 100644
index a8fd9c1b7d..0000000000
--- a/doc/classes/PopupDialog.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PopupDialog" inherits="Popup" version="4.0">
- <brief_description>
- Base class for popup dialogs.
- </brief_description>
- <description>
- PopupDialog is a base class for popup dialogs, along with [WindowDialog].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
- <theme_items>
- <theme_item name="panel" type="StyleBox">
- Sets a custom [StyleBox] for the panel of the [PopupDialog].
- </theme_item>
- </theme_items>
-</class>
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 8dda33f624..569da5c58b 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -330,13 +330,6 @@
Returns the tooltip associated with the specified index index [code]idx[/code].
</description>
</method>
- <method name="is_hide_on_window_lose_focus" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the popup will be hidden when the window loses focus or not.
- </description>
- </method>
<method name="is_item_checkable" qualifiers="const">
<return type="bool">
</return>
@@ -404,15 +397,6 @@
[b]Note:[/b] The indices of items after the removed item will be shifted by one.
</description>
</method>
- <method name="set_hide_on_window_lose_focus">
- <return type="void">
- </return>
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Hides the [PopupMenu] when the window loses focus.
- </description>
- </method>
<method name="set_item_accelerator">
<return type="void">
</return>
@@ -604,7 +588,6 @@
<member name="allow_search" type="bool" setter="set_allow_search" getter="get_allow_search" default="false">
If [code]true[/code], allows to navigate [PopupMenu] with letter keys.
</member>
- <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" />
<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.
</member>
diff --git a/doc/classes/PopupPanel.xml b/doc/classes/PopupPanel.xml
index a3dd722f81..72045c5559 100644
--- a/doc/classes/PopupPanel.xml
+++ b/doc/classes/PopupPanel.xml
@@ -4,7 +4,7 @@
Class for displaying popups with a panel background.
</brief_description>
<description>
- Class for displaying popups with a panel background. In some cases it might be simpler to use than [Popup], since it provides a configurable background. If you are making windows, better check [WindowDialog].
+ Class for displaying popups with a panel background. In some cases it might be simpler to use than [Popup], since it provides a configurable background. If you are making windows, better check [Window].
</description>
<tutorials>
</tutorials>
@@ -14,6 +14,7 @@
</constants>
<theme_items>
<theme_item name="panel" type="StyleBox">
+ The background panel style of this [PopupPanel].
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/Position3D.xml b/doc/classes/Position3D.xml
index 6dce8a91c6..ca61a57483 100644
--- a/doc/classes/Position3D.xml
+++ b/doc/classes/Position3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Position3D" inherits="Spatial" version="4.0">
+<class name="Position3D" inherits="Node3D" version="4.0">
<brief_description>
Generic 3D position hint for editing.
</brief_description>
<description>
- Generic 3D position hint for editing. It's just like a plain [Spatial], but it displays as a cross in the 3D editor at all times.
+ Generic 3D position hint for editing. It's just like a plain [Node3D], but it displays as a cross in the 3D editor at all times.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ProceduralSky.xml b/doc/classes/ProceduralSky.xml
deleted file mode 100644
index 9a61fac63a..0000000000
--- a/doc/classes/ProceduralSky.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ProceduralSky" inherits="Sky" version="4.0">
- <brief_description>
- Type of [Sky] that is generated procedurally based on user input parameters.
- </brief_description>
- <description>
- ProceduralSky provides a way to create an effective background quickly by defining procedural parameters for the sun, the sky and the ground. The sky and ground are very similar, they are defined by a color at the horizon, another color, and finally an easing curve to interpolate between these two colors. Similarly, the sun is described by a position in the sky, a color, and an easing curve. However, the sun also defines a minimum and maximum angle, these two values define at what distance the easing curve begins and ends from the sun, and thus end up defining the size of the sun in the sky.
- The ProceduralSky is updated on the CPU after the parameters change. It is stored in a texture and then displayed as a background in the scene. This makes it relatively unsuitable for real-time updates during gameplay. However, with a small enough texture size, it can still be updated relatively frequently, as it is updated on a background thread when multi-threading is available.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color" default="Color( 0.156863, 0.184314, 0.211765, 1 )">
- Color of the ground at the bottom.
- </member>
- <member name="ground_curve" type="float" setter="set_ground_curve" getter="get_ground_curve" default="0.02">
- How quickly the [member ground_horizon_color] fades into the [member ground_bottom_color].
- </member>
- <member name="ground_energy" type="float" setter="set_ground_energy" getter="get_ground_energy" default="1.0">
- Amount of energy contribution from the ground.
- </member>
- <member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color" default="Color( 0.423529, 0.396078, 0.372549, 1 )">
- Color of the ground at the horizon.
- </member>
- <member name="sky_curve" type="float" setter="set_sky_curve" getter="get_sky_curve" default="0.09">
- How quickly the [member sky_horizon_color] fades into the [member sky_top_color].
- </member>
- <member name="sky_energy" type="float" setter="set_sky_energy" getter="get_sky_energy" default="1.0">
- Amount of energy contribution from the sky.
- </member>
- <member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color" default="Color( 0.839216, 0.917647, 0.980392, 1 )">
- Color of the sky at the horizon.
- </member>
- <member name="sky_top_color" type="Color" setter="set_sky_top_color" getter="get_sky_top_color" default="Color( 0.647059, 0.839216, 0.945098, 1 )">
- Color of the sky at the top.
- </member>
- <member name="sun_angle_max" type="float" setter="set_sun_angle_max" getter="get_sun_angle_max" default="100.0">
- Distance from center of sun where it fades out completely.
- </member>
- <member name="sun_angle_min" type="float" setter="set_sun_angle_min" getter="get_sun_angle_min" default="1.0">
- Distance from sun where it goes from solid to starting to fade.
- </member>
- <member name="sun_color" type="Color" setter="set_sun_color" getter="get_sun_color" default="Color( 1, 1, 1, 1 )">
- The sun's color.
- </member>
- <member name="sun_curve" type="float" setter="set_sun_curve" getter="get_sun_curve" default="0.05">
- How quickly the sun fades away between [member sun_angle_min] and [member sun_angle_max].
- </member>
- <member name="sun_energy" type="float" setter="set_sun_energy" getter="get_sun_energy" default="1.0">
- Amount of energy contribution from the sun.
- </member>
- <member name="sun_latitude" type="float" setter="set_sun_latitude" getter="get_sun_latitude" default="35.0">
- The sun's height using polar coordinates.
- </member>
- <member name="sun_longitude" type="float" setter="set_sun_longitude" getter="get_sun_longitude" default="0.0">
- The direction of the sun using polar coordinates.
- </member>
- <member name="texture_size" type="int" setter="set_texture_size" getter="get_texture_size" enum="ProceduralSky.TextureSize" default="2">
- Size of [Texture2D] that the ProceduralSky will generate. The size is set using [enum TextureSize].
- </member>
- </members>
- <constants>
- <constant name="TEXTURE_SIZE_256" value="0" enum="TextureSize">
- Sky texture will be 256x128.
- </constant>
- <constant name="TEXTURE_SIZE_512" value="1" enum="TextureSize">
- Sky texture will be 512x256.
- </constant>
- <constant name="TEXTURE_SIZE_1024" value="2" enum="TextureSize">
- Sky texture will be 1024x512. This is the default size.
- </constant>
- <constant name="TEXTURE_SIZE_2048" value="3" enum="TextureSize">
- Sky texture will be 2048x1024.
- </constant>
- <constant name="TEXTURE_SIZE_4096" value="4" enum="TextureSize">
- Sky texture will be 4096x2048.
- </constant>
- <constant name="TEXTURE_SIZE_MAX" value="5" enum="TextureSize">
- Represents the size of the [enum TextureSize] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ProceduralSkyMaterial.xml b/doc/classes/ProceduralSkyMaterial.xml
new file mode 100644
index 0000000000..70e82d248c
--- /dev/null
+++ b/doc/classes/ProceduralSkyMaterial.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ProceduralSkyMaterial" inherits="Material" version="4.0">
+ <brief_description>
+ A [Material] used with [Sky] to generate a background based on user input parameters.
+ </brief_description>
+ <description>
+ ProceduralSkyMaterial provides a way to create an effective background quickly by defining procedural parameters for the sun, the sky and the ground. The sky and ground are very similar, they are defined by a color at the horizon, another color, and finally an easing curve to interpolate between these two colors. Similarly, the sun is described by a position in the sky, a color, and an easing curve. However, the sun also defines a minimum and maximum angle, these two values define at what distance the easing curve begins and ends from the sun, and thus end up defining the size of the sun in the sky.
+ The [ProceduralSkyMaterial] uses a lightweight shader to draw the sky and is thus suited for real time updates. When you do not need a quick sky that is not realistic, this is a good option.
+ The [ProceduralSkyMaterial] supports up to 4 suns. Each sun takes its color, energy, and direction from the corresponding [DirectionalLight3D] in the scene.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color" default="Color( 0.12, 0.12, 0.13, 1 )">
+ Color of the ground at the bottom. Blends with [member ground_horizon_color].
+ </member>
+ <member name="ground_curve" type="float" setter="set_ground_curve" getter="get_ground_curve" default="0.02">
+ How quickly the [member ground_horizon_color] fades into the [member ground_bottom_color].
+ </member>
+ <member name="ground_energy" type="float" setter="set_ground_energy" getter="get_ground_energy" default="1.0">
+ Amount of energy contribution from the ground.
+ </member>
+ <member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color" default="Color( 0.37, 0.33, 0.31, 1 )">
+ Color of the ground at the horizon. Blends with [member ground_bottom_color].
+ </member>
+ <member name="sky_curve" type="float" setter="set_sky_curve" getter="get_sky_curve" default="0.09">
+ How quickly the [member sky_horizon_color] fades into the [member sky_top_color].
+ </member>
+ <member name="sky_energy" type="float" setter="set_sky_energy" getter="get_sky_energy" default="1.0">
+ Amount of energy contribution from the sky.
+ </member>
+ <member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color" default="Color( 0.55, 0.69, 0.81, 1 )">
+ Color of the sky at the horizon. Blends with [member sky_top_color].
+ </member>
+ <member name="sky_top_color" type="Color" setter="set_sky_top_color" getter="get_sky_top_color" default="Color( 0.35, 0.46, 0.71, 1 )">
+ Color of the sky at the top. Blends with [member sky_horizon_color].
+ </member>
+ <member name="sun_angle_max" type="float" setter="set_sun_angle_max" getter="get_sun_angle_max" default="100.0">
+ Distance from center of sun where it fades out completely.
+ </member>
+ <member name="sun_angle_min" type="float" setter="set_sun_angle_min" getter="get_sun_angle_min" default="1.0">
+ Distance from sun where it goes from solid to starting to fade.
+ </member>
+ <member name="sun_curve" type="float" setter="set_sun_curve" getter="get_sun_curve" default="0.05">
+ How quickly the sun fades away between [member sun_angle_min] and [member sun_angle_max].
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml
index e94299a5b8..c957d6f182 100644
--- a/doc/classes/ProgressBar.xml
+++ b/doc/classes/ProgressBar.xml
@@ -21,14 +21,19 @@
</constants>
<theme_items>
<theme_item name="bg" type="StyleBox">
+ The style of the background.
</theme_item>
<theme_item name="fg" type="StyleBox">
+ The style of the progress (i.e. the part that fills the bar).
</theme_item>
<theme_item name="font" type="Font">
+ Font used to draw the fill percentage if [member percent_visible] is [code]true[/code].
</theme_item>
<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_color_shadow" type="Color" default="Color( 0, 0, 0, 1 )">
+ The color of the text's shadow.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index af594c36d1..67a033daca 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -202,7 +202,7 @@
Icon used for the project, set when project loads. Exporters will also use this icon when possible.
</member>
<member name="application/config/macos_native_icon" type="String" setter="" getter="" default="&quot;&quot;">
- Icon set in [code].icns[/code] format used on macOS to set the game's icon. This is done automatically on start by calling [method OS.set_native_icon].
+ Icon set in [code].icns[/code] format used on macOS to set the game's icon. This is done automatically on start by calling [method DisplayServer.set_native_icon].
</member>
<member name="application/config/name" type="String" setter="" getter="" default="&quot;&quot;">
The project's name. It is used both by the Project Manager and by exporters. The project name can be translated by translating its value in localization files.
@@ -215,7 +215,7 @@
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].
</member>
<member name="application/config/windows_native_icon" type="String" setter="" getter="" default="&quot;&quot;">
- Icon set in [code].ico[/code] format used on Windows to set the game's icon. This is done automatically on start by calling [method OS.set_native_icon].
+ Icon set in [code].ico[/code] format used on Windows to set the game's icon. This is done automatically on start by calling [method DisplayServer.set_native_icon].
</member>
<member name="application/run/disable_stderr" type="bool" setter="" getter="" default="false">
If [code]true[/code], disables printing to standard error in an exported build.
@@ -426,12 +426,6 @@
<member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true">
If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button.
</member>
- <member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
- If [code]true[/code], allows per-pixel transparency in a desktop window. This affects performance, so leave it on [code]false[/code] unless you need it.
- </member>
- <member name="display/window/per_pixel_transparency/enabled" type="bool" setter="" getter="" default="false">
- Sets the window background to transparent when it starts.
- </member>
<member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false">
Force the window to be always on top.
</member>
@@ -824,16 +818,16 @@
</member>
<member name="mono/unhandled_exception_policy" type="int" setter="" getter="" default="0">
</member>
- <member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="2048">
+ <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>
- <member name="network/limits/debugger/max_errors_per_second" type="int" setter="" getter="" default="100">
+ <member name="network/limits/debugger/max_errors_per_second" type="int" setter="" getter="" default="400">
Maximum number of errors allowed to be sent from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
</member>
- <member name="network/limits/debugger/max_queued_messages" type="int" setter="" getter="" default="10">
+ <member name="network/limits/debugger/max_queued_messages" type="int" setter="" getter="" default="2048">
Maximum amount of messages in the debugger queue. Over this value, content is dropped. This helps to limit the debugger memory usage.
</member>
- <member name="network/limits/debugger/max_warnings_per_second" type="int" setter="" getter="" default="100">
+ <member name="network/limits/debugger/max_warnings_per_second" type="int" setter="" getter="" default="400">
Maximum number of warnings allowed to be sent from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
</member>
<member name="network/limits/packet_peer_stream/max_buffer_po2" type="int" setter="" getter="" default="16">
@@ -898,7 +892,7 @@
[b]Note:[/b] This property is only read when the project starts. To change the default gravity at runtime, use the following code sample:
[codeblock]
# Set the default gravity strength to 98.
- Physics2DServer.area_set_param(get_viewport().find_world_2d().get_space(), Physics2DServer.AREA_PARAM_GRAVITY, 98)
+ PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), PhysicsServer2D.AREA_PARAM_GRAVITY, 98)
[/codeblock]
</member>
<member name="physics/2d/default_gravity_vector" type="Vector2" setter="" getter="" default="Vector2( 0, 1 )">
@@ -906,7 +900,7 @@
[b]Note:[/b] This property is only read when the project starts. To change the default gravity vector at runtime, use the following code sample:
[codeblock]
# Set the default gravity direction to `Vector2(0, 1)`.
- Physics2DServer.area_set_param(get_viewport().find_world_2d().get_space(), Physics2DServer.AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1))
+ PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), PhysicsServer2D.AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1))
[/codeblock]
</member>
<member name="physics/2d/default_linear_damp" type="float" setter="" getter="" default="0.1">
@@ -917,23 +911,23 @@
</member>
<member name="physics/2d/physics_engine" type="String" setter="" getter="" default="&quot;DEFAULT&quot;">
Sets which physics engine to use for 2D physics.
- "DEFAULT" and "GodotPhysics" are the same, as there is currently no alternative 2D physics server implemented.
+ "DEFAULT" and "GodotPhysics2D" are the same, as there is currently no alternative 2D physics server implemented.
</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 Physics2DServer.SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD].
+ 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 Physics2DServer.SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD].
+ 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 Physics2DServer.SPACE_PARAM_BODY_TIME_TO_SLEEP].
+ 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 [SoftBody] physics. Only applies to the Bullet physics engine.
+ 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.
@@ -943,7 +937,7 @@
[b]Note:[/b] This property is only read when the project starts. To change the default gravity at runtime, use the following code sample:
[codeblock]
# Set the default gravity strength to 9.8.
- PhysicsServer.area_set_param(get_viewport().find_world().get_space(), PhysicsServer.AREA_PARAM_GRAVITY, 9.8)
+ PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8)
[/codeblock]
</member>
<member name="physics/3d/default_gravity_vector" type="Vector3" setter="" getter="" default="Vector3( 0, -1, 0 )">
@@ -951,7 +945,7 @@
[b]Note:[/b] This property is only read when the project starts. To change the default gravity vector at runtime, use the following code sample:
[codeblock]
# Set the default gravity direction to `Vector3(0, -1, 0)`.
- PhysicsServer.area_set_param(get_viewport().find_world().get_space(), PhysicsServer.AREA_PARAM_GRAVITY_VECTOR, Vector3(0, -1, 0))
+ PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3(0, -1, 0))
[/codeblock]
</member>
<member name="physics/3d/default_linear_damp" type="float" setter="" getter="" default="0.1">
@@ -959,7 +953,7 @@
</member>
<member name="physics/3d/physics_engine" type="String" setter="" getter="" default="&quot;DEFAULT&quot;">
Sets which physics engine to use for 3D physics.
- "DEFAULT" is currently the [url=https://bulletphysics.org]Bullet[/url] physics engine. The "GodotPhysics" engine is still supported as an alternative.
+ "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/common/enable_object_picking" type="bool" setter="" getter="" default="true">
Enables [member Viewport.physics_object_picking] on the root viewport.
@@ -973,7 +967,7 @@
[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/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 VisualServer.set_default_clear_color].
+ 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/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.
@@ -1000,9 +994,17 @@
<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>
+ <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>
+ <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>
<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]--video-driver[/code] command line argument. In such cases, this property is not updated, so use [method OS.get_current_video_driver] to query it at run-time.
+ [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/filters/depth_of_field_bokeh_quality" type="int" setter="" getter="" default="2">
</member>
@@ -1027,6 +1029,10 @@
</member>
<member name="rendering/quality/gi_probes/quality" type="int" setter="" getter="" default="1">
</member>
+ <member name="rendering/quality/glow/upscale_mode" type="int" setter="" getter="" default="1">
+ </member>
+ <member name="rendering/quality/glow/upscale_mode.mobile" type="int" setter="" getter="" default="0">
+ </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>
@@ -1036,7 +1042,7 @@
<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>
- <member name="rendering/quality/reflection_atlas/reflection_size" type="int" setter="" getter="" default="128">
+ <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>
<member name="rendering/quality/reflection_atlas/reflection_size.mobile" type="int" setter="" getter="" default="128">
@@ -1051,7 +1057,7 @@
<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>
- <member name="rendering/quality/reflections/roughness_layers" type="int" setter="" getter="" default="6">
+ <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>
<member name="rendering/quality/reflections/texture_array_reflections" type="bool" setter="" getter="" default="true">
@@ -1060,6 +1066,8 @@
<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>
+ <member name="rendering/quality/screen_space_reflection/roughness_quality" type="int" setter="" getter="" default="1">
+ </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>
@@ -1096,16 +1104,22 @@
<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>
- <member name="rendering/quality/shadows/filter_mode" type="int" setter="" getter="" default="1">
- Shadow filter mode. Higher-quality settings result in smoother shadows that flicker less when moving. "Disabled" is the fastest option, but also has the lowest quality. "PCF5" is smoother but is also slower. "PCF13" is the smoothest option, but is also the slowest.
+ <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>
- <member name="rendering/quality/shadows/filter_mode.mobile" type="int" setter="" getter="" default="0">
- Lower-end override for [member rendering/quality/shadows/filter_mode] on mobile devices, due to performance concerns or driver support.
+ <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>
<member name="rendering/quality/ssao/half_size" type="bool" setter="" getter="" default="false">
</member>
<member name="rendering/quality/ssao/quality" type="int" setter="" getter="" default="1">
</member>
+ <member name="rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale" type="float" setter="" getter="" default="0.01">
+ </member>
+ <member name="rendering/quality/subsurface_scattering/subsurface_scattering_quality" type="int" setter="" getter="" default="1">
+ </member>
+ <member name="rendering/quality/subsurface_scattering/subsurface_scattering_scale" type="float" setter="" getter="" default="0.05">
+ </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>
diff --git a/doc/classes/ProximityGroup.xml b/doc/classes/ProximityGroup.xml
deleted file mode 100644
index dee1a3daf0..0000000000
--- a/doc/classes/ProximityGroup.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ProximityGroup" inherits="Spatial" version="4.0">
- <brief_description>
- General-purpose proximity detection node.
- </brief_description>
- <description>
- General-purpose proximity detection node.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="broadcast">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="parameters" type="Variant">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="dispatch_mode" type="int" setter="set_dispatch_mode" getter="get_dispatch_mode" enum="ProximityGroup.DispatchMode" default="0">
- </member>
- <member name="grid_radius" type="Vector3" setter="set_grid_radius" getter="get_grid_radius" default="Vector3( 1, 1, 1 )">
- </member>
- <member name="group_name" type="String" setter="set_group_name" getter="get_group_name" default="&quot;&quot;">
- </member>
- </members>
- <signals>
- <signal name="broadcast">
- <argument index="0" name="group_name" type="String">
- </argument>
- <argument index="1" name="parameters" type="Array">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="MODE_PROXY" value="0" enum="DispatchMode">
- </constant>
- <constant name="MODE_SIGNAL" value="1" enum="DispatchMode">
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/ProximityGroup3D.xml b/doc/classes/ProximityGroup3D.xml
new file mode 100644
index 0000000000..1714c1ec8d
--- /dev/null
+++ b/doc/classes/ProximityGroup3D.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ProximityGroup3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ General-purpose proximity detection node.
+ </brief_description>
+ <description>
+ General-purpose proximity detection node.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="broadcast">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="parameters" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="dispatch_mode" type="int" setter="set_dispatch_mode" getter="get_dispatch_mode" enum="ProximityGroup3D.DispatchMode" default="0">
+ </member>
+ <member name="grid_radius" type="Vector3" setter="set_grid_radius" getter="get_grid_radius" default="Vector3( 1, 1, 1 )">
+ </member>
+ <member name="group_name" type="String" setter="set_group_name" getter="get_group_name" default="&quot;&quot;">
+ </member>
+ </members>
+ <signals>
+ <signal name="broadcast">
+ <argument index="0" name="group_name" type="String">
+ </argument>
+ <argument index="1" name="parameters" type="Array">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="MODE_PROXY" value="0" enum="DispatchMode">
+ </constant>
+ <constant name="MODE_SIGNAL" value="1" enum="DispatchMode">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/RID.xml b/doc/classes/RID.xml
index 77c608fccb..644c427120 100644
--- a/doc/classes/RID.xml
+++ b/doc/classes/RID.xml
@@ -4,7 +4,7 @@
Handle for a [Resource]'s unique ID.
</brief_description>
<description>
- The RID type is used to access the unique integer ID of a resource. They are opaque, which means they do not grant access to the associated resource by themselves. They are used by and with the low-level Server classes such as [VisualServer].
+ The RID type is used to access the unique integer ID of a resource. They are opaque, which means they do not grant access to the associated resource by themselves. They are used by and with the low-level Server classes such as [RenderingServer].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/RayCast.xml b/doc/classes/RayCast.xml
deleted file mode 100644
index 65f632ba74..0000000000
--- a/doc/classes/RayCast.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RayCast" inherits="Spatial" version="4.0">
- <brief_description>
- Query the closest object intersecting a ray.
- </brief_description>
- <description>
- A RayCast represents a line from its origin to its destination position, [code]cast_to[/code]. It is used to query the 3D space in order to find the closest object along the path of the ray.
- RayCast can ignore some objects by adding them to the exception list via [code]add_exception[/code] or by setting proper filtering with collision layers and masks.
- RayCast can be configured to report collisions with [Area]s ([member collide_with_areas]) and/or [PhysicsBody]s ([member collide_with_bodies]).
- Only enabled raycasts will be able to query the space and report collisions.
- RayCast calculates intersection every physics frame (see [Node]), and the result is cached so it can be used later until the next frame. If multiple queries are required between physics frames (or during the same frame), use [method force_raycast_update] after adjusting the raycast.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
- </tutorials>
- <methods>
- <method name="add_exception">
- <return type="void">
- </return>
- <argument index="0" name="node" type="Object">
- </argument>
- <description>
- Adds a collision exception so the ray does not report collisions with the specified node.
- </description>
- </method>
- <method name="add_exception_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Adds a collision exception so the ray does not report collisions with the specified [RID].
- </description>
- </method>
- <method name="clear_exceptions">
- <return type="void">
- </return>
- <description>
- Removes all collision exceptions for this ray.
- </description>
- </method>
- <method name="force_raycast_update">
- <return type="void">
- </return>
- <description>
- Updates the collision information for the ray.
- Use this method to update the collision information immediately instead of waiting for the next [code]_physics_process[/code] call, for example if the ray or its parent has changed state.
- [b]Note:[/b] [code]enabled == true[/code] is not required for this to work.
- </description>
- </method>
- <method name="get_collider" qualifiers="const">
- <return type="Object">
- </return>
- <description>
- Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
- </description>
- </method>
- <method name="get_collider_shape" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns [code]true[/code] if the bit index passed is turned on.
- [b]Note:[/b] Bit indices range from 0-19.
- </description>
- </method>
- <method name="get_collision_normal" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- Returns the normal of the intersecting object's shape at the collision point.
- </description>
- </method>
- <method name="get_collision_point" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- Returns the collision point at which the ray intersects the closest object.
- [b]Note:[/b] This point is in the [b]global[/b] coordinate system.
- </description>
- </method>
- <method name="is_colliding" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns whether any object is intersecting with the ray's vector (considering the vector length).
- </description>
- </method>
- <method name="remove_exception">
- <return type="void">
- </return>
- <argument index="0" name="node" type="Object">
- </argument>
- <description>
- Removes a collision exception so the ray does report collisions with the specified node.
- </description>
- </method>
- <method name="remove_exception_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Removes a collision exception so the ray does report collisions with the specified [RID].
- </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 the bit index passed to the [code]value[/code] passed.
- [b]Note:[/b] Bit indexes range from 0-19.
- </description>
- </method>
- </methods>
- <members>
- <member name="cast_to" type="Vector3" setter="set_cast_to" getter="get_cast_to" default="Vector3( 0, -1, 0 )">
- The ray's destination point, relative to the RayCast's [code]position[/code].
- </member>
- <member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
- If [code]true[/code], collision with [Area]s will be reported.
- </member>
- <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
- If [code]true[/code], collision with [PhysicsBody]s will be reported.
- </member>
- <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.
- </member>
- <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="false">
- If [code]true[/code], collisions will be reported.
- </member>
- <member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
- If [code]true[/code], collisions will be ignored for this RayCast's immediate parent.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
new file mode 100644
index 0000000000..08c6d6f40c
--- /dev/null
+++ b/doc/classes/RayCast3D.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RayCast3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Query the closest object intersecting a ray.
+ </brief_description>
+ <description>
+ A RayCast represents a line from its origin to its destination position, [code]cast_to[/code]. It is used to query the 3D space in order to find the closest object along the path of the ray.
+ RayCast3D can ignore some objects by adding them to the exception list via [code]add_exception[/code] or by setting proper filtering with collision layers and masks.
+ RayCast3D can be configured to report collisions with [Area3D]s ([member collide_with_areas]) and/or [PhysicsBody3D]s ([member collide_with_bodies]).
+ Only enabled raycasts will be able to query the space and report collisions.
+ RayCast3D calculates intersection every physics frame (see [Node]), and the result is cached so it can be used later until the next frame. If multiple queries are required between physics frames (or during the same frame), use [method force_raycast_update] after adjusting the raycast.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ </tutorials>
+ <methods>
+ <method name="add_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Object">
+ </argument>
+ <description>
+ Adds a collision exception so the ray does not report collisions with the specified node.
+ </description>
+ </method>
+ <method name="add_exception_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ Adds a collision exception so the ray does not report collisions with the specified [RID].
+ </description>
+ </method>
+ <method name="clear_exceptions">
+ <return type="void">
+ </return>
+ <description>
+ Removes all collision exceptions for this ray.
+ </description>
+ </method>
+ <method name="force_raycast_update">
+ <return type="void">
+ </return>
+ <description>
+ Updates the collision information for the ray.
+ Use this method to update the collision information immediately instead of waiting for the next [code]_physics_process[/code] call, for example if the ray or its parent has changed state.
+ [b]Note:[/b] [code]enabled == true[/code] is not required for this to work.
+ </description>
+ </method>
+ <method name="get_collider" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
+ </description>
+ </method>
+ <method name="get_collider_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the shape ID of the first object that the ray intersects, or [code]0[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the bit index passed is turned on.
+ [b]Note:[/b] Bit indices range from 0-19.
+ </description>
+ </method>
+ <method name="get_collision_normal" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the normal of the intersecting object's shape at the collision point.
+ </description>
+ </method>
+ <method name="get_collision_point" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the collision point at which the ray intersects the closest object.
+ [b]Note:[/b] This point is in the [b]global[/b] coordinate system.
+ </description>
+ </method>
+ <method name="is_colliding" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether any object is intersecting with the ray's vector (considering the vector length).
+ </description>
+ </method>
+ <method name="remove_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Object">
+ </argument>
+ <description>
+ Removes a collision exception so the ray does report collisions with the specified node.
+ </description>
+ </method>
+ <method name="remove_exception_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ Removes a collision exception so the ray does report collisions with the specified [RID].
+ </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 the bit index passed to the [code]value[/code] passed.
+ [b]Note:[/b] Bit indexes range from 0-19.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="cast_to" type="Vector3" setter="set_cast_to" getter="get_cast_to" default="Vector3( 0, -1, 0 )">
+ The ray's destination point, relative to the RayCast's [code]position[/code].
+ </member>
+ <member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
+ If [code]true[/code], collision with [Area3D]s will be reported.
+ </member>
+ <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true">
+ If [code]true[/code], collision with [PhysicsBody3D]s will be reported.
+ </member>
+ <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.
+ </member>
+ <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="false">
+ If [code]true[/code], collisions will be reported.
+ </member>
+ <member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true">
+ If [code]true[/code], collisions will be ignored for this RayCast3D's immediate parent.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/RayShape.xml b/doc/classes/RayShape.xml
deleted file mode 100644
index 87a642f779..0000000000
--- a/doc/classes/RayShape.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RayShape" inherits="Shape" version="4.0">
- <brief_description>
- Ray shape for 3D collisions.
- </brief_description>
- <description>
- Ray shape for 3D collisions, which can be set into a [PhysicsBody] or [Area]. A ray is not really a collision body; instead, it tries to separate itself from whatever is touching its far endpoint. It's often useful for characters.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="length" type="float" setter="set_length" getter="get_length" default="1.0">
- The ray's length.
- </member>
- <member name="slips_on_slope" type="bool" setter="set_slips_on_slope" getter="get_slips_on_slope" default="false">
- If [code]true[/code], allow the shape to return the correct normal.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/RayShape3D.xml b/doc/classes/RayShape3D.xml
new file mode 100644
index 0000000000..9839044c30
--- /dev/null
+++ b/doc/classes/RayShape3D.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RayShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Ray shape for 3D collisions.
+ </brief_description>
+ <description>
+ Ray shape for 3D collisions, which can be set into a [PhysicsBody3D] or [Area3D]. A ray is not really a collision body; instead, it tries to separate itself from whatever is touching its far endpoint. It's often useful for characters.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="length" type="float" setter="set_length" getter="get_length" default="1.0">
+ The ray's length.
+ </member>
+ <member name="slips_on_slope" type="bool" setter="set_slips_on_slope" getter="get_slips_on_slope" default="false">
+ If [code]true[/code], allow the shape to return the correct normal.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index e138af6841..84f87c3e71 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ReflectionProbe" inherits="VisualInstance" version="4.0">
+<class name="ReflectionProbe" inherits="VisualInstance3D" version="4.0">
<brief_description>
Captures its surroundings to create reflections.
</brief_description>
@@ -17,7 +17,7 @@
If [code]true[/code], enables box projection. This makes reflections look more correct in rectangle-shaped rooms by offsetting the reflection center depending on the camera's location.
</member>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
- Sets the cull mask which determines what objects are drawn by this probe. Every [VisualInstance] with a layer included in this cull mask will be rendered by the probe. It is best to only include large objects which are likely to take up a lot of space in the reflection in order to save on rendering cost.
+ Sets the cull mask which determines what objects are drawn by this probe. Every [VisualInstance3D] with a layer included in this cull mask will be rendered by the probe. It is best to only include large objects which are likely to take up a lot of space in the reflection in order to save on rendering cost.
</member>
<member name="enable_shadows" type="bool" setter="set_enable_shadows" getter="are_shadows_enabled" default="false">
If [code]true[/code], computes shadows in the reflection probe. This makes the reflection probe slower to render; you may want to disable this if using the [constant UPDATE_ALWAYS] [member update_mode].
diff --git a/doc/classes/RemoteTransform.xml b/doc/classes/RemoteTransform.xml
deleted file mode 100644
index feb6ac1841..0000000000
--- a/doc/classes/RemoteTransform.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RemoteTransform" inherits="Spatial" version="4.0">
- <brief_description>
- RemoteTransform pushes its own [Transform] to another [Spatial] derived Node in the scene.
- </brief_description>
- <description>
- RemoteTransform pushes its own [Transform] to another [Spatial] derived Node (called the remote node) in the scene.
- It can be set to update another Node's position, rotation and/or scale. It can use either global or local coordinates.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="force_update_cache">
- <return type="void">
- </return>
- <description>
- [RemoteTransform] caches the remote node. It may not notice if the remote node disappears; [method force_update_cache] forces it to update the cache again.
- </description>
- </method>
- </methods>
- <members>
- <member name="remote_path" type="NodePath" setter="set_remote_node" getter="get_remote_node" default="NodePath(&quot;&quot;)">
- The [NodePath] to the remote node, relative to the RemoteTransform's position in the scene.
- </member>
- <member name="update_position" type="bool" setter="set_update_position" getter="get_update_position" default="true">
- If [code]true[/code], the remote node's position is updated.
- </member>
- <member name="update_rotation" type="bool" setter="set_update_rotation" getter="get_update_rotation" default="true">
- If [code]true[/code], the remote node's rotation is updated.
- </member>
- <member name="update_scale" type="bool" setter="set_update_scale" getter="get_update_scale" default="true">
- If [code]true[/code], the remote node's scale is updated.
- </member>
- <member name="use_global_coordinates" type="bool" setter="set_use_global_coordinates" getter="get_use_global_coordinates" default="true">
- If [code]true[/code], global coordinates are used. If [code]false[/code], local coordinates are used.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/RemoteTransform3D.xml b/doc/classes/RemoteTransform3D.xml
new file mode 100644
index 0000000000..bd3da2aea9
--- /dev/null
+++ b/doc/classes/RemoteTransform3D.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RemoteTransform3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ RemoteTransform3D pushes its own [Transform] to another [Node3D] derived Node in the scene.
+ </brief_description>
+ <description>
+ RemoteTransform3D pushes its own [Transform] to another [Node3D] derived Node (called the remote node) in the scene.
+ It can be set to update another Node's position, rotation and/or scale. It can use either global or local coordinates.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="force_update_cache">
+ <return type="void">
+ </return>
+ <description>
+ [RemoteTransform3D] caches the remote node. It may not notice if the remote node disappears; [method force_update_cache] forces it to update the cache again.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="remote_path" type="NodePath" setter="set_remote_node" getter="get_remote_node" default="NodePath(&quot;&quot;)">
+ The [NodePath] to the remote node, relative to the RemoteTransform3D's position in the scene.
+ </member>
+ <member name="update_position" type="bool" setter="set_update_position" getter="get_update_position" default="true">
+ If [code]true[/code], the remote node's position is updated.
+ </member>
+ <member name="update_rotation" type="bool" setter="set_update_rotation" getter="get_update_rotation" default="true">
+ If [code]true[/code], the remote node's rotation is updated.
+ </member>
+ <member name="update_scale" type="bool" setter="set_update_scale" getter="get_update_scale" default="true">
+ If [code]true[/code], the remote node's scale is updated.
+ </member>
+ <member name="use_global_coordinates" type="bool" setter="set_use_global_coordinates" getter="get_use_global_coordinates" default="true">
+ If [code]true[/code], global coordinates are used. If [code]false[/code], local coordinates are used.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
new file mode 100644
index 0000000000..bfdcf1bb79
--- /dev/null
+++ b/doc/classes/RenderingServer.xml
@@ -0,0 +1,3726 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RenderingServer" inherits="Object" version="4.0">
+ <brief_description>
+ Server for anything visible.
+ </brief_description>
+ <description>
+ Server for anything visible. The visual server is the API backend for everything visible. The whole scene system mounts on it to display.
+ The visual server is completely opaque, the internals are entirely implementation specific and cannot be accessed.
+ The visual server can be used to bypass the scene system entirely.
+ 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 visual server from a running game, the scenario can be accessed from the scene tree from any [Node3D] node with [method Node3D.get_world]. Otherwise, a scenario can be created with [method scenario_create].
+ 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>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers.html</link>
+ </tutorials>
+ <methods>
+ <method name="black_bars_set_images">
+ <return type="void">
+ </return>
+ <argument index="0" name="left" type="RID">
+ </argument>
+ <argument index="1" name="top" type="RID">
+ </argument>
+ <argument index="2" name="right" type="RID">
+ </argument>
+ <argument index="3" name="bottom" type="RID">
+ </argument>
+ <description>
+ Sets images to be rendered in the window margin.
+ </description>
+ </method>
+ <method name="black_bars_set_margins">
+ <return type="void">
+ </return>
+ <argument index="0" name="left" type="int">
+ </argument>
+ <argument index="1" name="top" type="int">
+ </argument>
+ <argument index="2" name="right" type="int">
+ </argument>
+ <argument index="3" name="bottom" type="int">
+ </argument>
+ <description>
+ Sets margin size, where black bars (or images, if [method black_bars_set_images] was used) are rendered.
+ </description>
+ </method>
+ <method name="camera_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a camera and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="camera_set_cull_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="layers" type="int">
+ </argument>
+ <description>
+ Sets the cull mask associated with this camera. The cull mask describes which 3D layers are rendered by this camera. Equivalent to [member Camera3D.cull_mask].
+ </description>
+ </method>
+ <method name="camera_set_environment">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="env" type="RID">
+ </argument>
+ <description>
+ Sets the environment used by this camera. Equivalent to [member Camera3D.environment].
+ </description>
+ </method>
+ <method name="camera_set_frustum">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="size" type="float">
+ </argument>
+ <argument index="2" name="offset" type="Vector2">
+ </argument>
+ <argument index="3" name="z_near" type="float">
+ </argument>
+ <argument index="4" name="z_far" type="float">
+ </argument>
+ <description>
+ Sets camera to use frustum projection. This mode allows adjusting the [code]offset[/code] argument to create "tilted frustum" effects.
+ </description>
+ </method>
+ <method name="camera_set_orthogonal">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="size" type="float">
+ </argument>
+ <argument index="2" name="z_near" type="float">
+ </argument>
+ <argument index="3" name="z_far" type="float">
+ </argument>
+ <description>
+ Sets camera to use orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are.
+ </description>
+ </method>
+ <method name="camera_set_perspective">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="fovy_degrees" type="float">
+ </argument>
+ <argument index="2" name="z_near" type="float">
+ </argument>
+ <argument index="3" name="z_far" type="float">
+ </argument>
+ <description>
+ Sets camera to use perspective projection. Objects on the screen becomes smaller when they are far away.
+ </description>
+ </method>
+ <method name="camera_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets [Transform] of camera.
+ </description>
+ </method>
+ <method name="camera_set_use_vertical_aspect">
+ <return type="void">
+ </return>
+ <argument index="0" name="camera" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], preserves the horizontal aspect ratio which is equivalent to [constant Camera3D.KEEP_WIDTH]. If [code]false[/code], preserves the vertical aspect ratio which is equivalent to [constant Camera3D.KEEP_HEIGHT].
+ </description>
+ </method>
+ <method name="canvas_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a canvas and returns the assigned [RID]. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="canvas_item_clear">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <description>
+ Clears the [CanvasItem] and removes all commands in it.
+ </description>
+ </method>
+ <method name="canvas_item_set_copy_to_backbuffer">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <argument index="2" name="rect" type="Rect2">
+ </argument>
+ <description>
+ Sets the [CanvasItem] to copy a rect to the backbuffer.
+ </description>
+ </method>
+ <method name="canvas_item_set_draw_index">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Sets the index for the [CanvasItem].
+ </description>
+ </method>
+ <method name="canvas_item_set_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <argument index="1" name="material" type="RID">
+ </argument>
+ <description>
+ Sets a new material to the [CanvasItem].
+ </description>
+ </method>
+ <method name="canvas_item_set_use_parent_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets if the [CanvasItem] uses its parent's material.
+ </description>
+ </method>
+ <method name="canvas_item_set_z_as_relative_to_parent">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ If this is enabled, the Z index of the parent will be added to the children's Z index.
+ </description>
+ </method>
+ <method name="canvas_item_set_z_index">
+ <return type="void">
+ </return>
+ <argument index="0" name="item" type="RID">
+ </argument>
+ <argument index="1" name="z_index" type="int">
+ </argument>
+ <description>
+ Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are drawn first).
+ </description>
+ </method>
+ <method name="canvas_light_attach_to_canvas">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="canvas" type="RID">
+ </argument>
+ <description>
+ Attaches the canvas light to the canvas. Removes it from its previous canvas.
+ </description>
+ </method>
+ <method name="canvas_light_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a canvas light and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_light_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="canvas_light_occluder_attach_to_canvas">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder" type="RID">
+ </argument>
+ <argument index="1" name="canvas" type="RID">
+ </argument>
+ <description>
+ Attaches a light occluder to the canvas. Removes it from its previous canvas.
+ </description>
+ </method>
+ <method name="canvas_light_occluder_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a light occluder and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_light_ocluder_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="canvas_light_occluder_set_enabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Enables or disables light occluder.
+ </description>
+ </method>
+ <method name="canvas_light_occluder_set_light_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ The light mask. See [LightOccluder2D] for more information on light masks.
+ </description>
+ </method>
+ <method name="canvas_light_occluder_set_polygon">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder" type="RID">
+ </argument>
+ <argument index="1" name="polygon" type="RID">
+ </argument>
+ <description>
+ Sets a light occluder's polygon.
+ </description>
+ </method>
+ <method name="canvas_light_occluder_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets a light occluder's [Transform2D].
+ </description>
+ </method>
+ <method name="canvas_light_set_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the color for a light.
+ </description>
+ </method>
+ <method name="canvas_light_set_enabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Enables or disables a canvas light.
+ </description>
+ </method>
+ <method name="canvas_light_set_energy">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="energy" type="float">
+ </argument>
+ <description>
+ Sets a canvas light's energy.
+ </description>
+ </method>
+ <method name="canvas_light_set_height">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="height" type="float">
+ </argument>
+ <description>
+ Sets a canvas light's height.
+ </description>
+ </method>
+ <method name="canvas_light_set_item_cull_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ The light mask. See [LightOccluder2D] for more information on light masks.
+ </description>
+ </method>
+ <method name="canvas_light_set_item_shadow_cull_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ The binary mask used to determine which layers this canvas light's shadows affects. See [LightOccluder2D] for more information on light masks.
+ </description>
+ </method>
+ <method name="canvas_light_set_layer_range">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="min_layer" type="int">
+ </argument>
+ <argument index="2" name="max_layer" type="int">
+ </argument>
+ <description>
+ The layer range that gets rendered with this light.
+ </description>
+ </method>
+ <method name="canvas_light_set_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="RenderingServer.CanvasLightMode">
+ </argument>
+ <description>
+ The mode of the light, see [enum CanvasLightMode] constants.
+ </description>
+ </method>
+ <method name="canvas_light_set_scale">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="scale" type="float">
+ </argument>
+ <description>
+ Sets the texture's scale factor of the light. Equivalent to [member Light2D.texture_scale].
+ </description>
+ </method>
+ <method name="canvas_light_set_shadow_buffer_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="size" type="int">
+ </argument>
+ <description>
+ Sets the width of the shadow buffer, size gets scaled to the next power of two for this.
+ </description>
+ </method>
+ <method name="canvas_light_set_shadow_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the color of the canvas light's shadow.
+ </description>
+ </method>
+ <method name="canvas_light_set_shadow_enabled">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Enables or disables the canvas light's shadow.
+ </description>
+ </method>
+ <method name="canvas_light_set_shadow_filter">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasLightShadowFilter">
+ </argument>
+ <description>
+ Sets the canvas light's shadow's filter, see [enum CanvasLightShadowFilter] constants.
+ </description>
+ </method>
+ <method name="canvas_light_set_shadow_smooth">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="smooth" type="float">
+ </argument>
+ <description>
+ Smoothens the shadow. The lower, the smoother.
+ </description>
+ </method>
+ <method name="canvas_light_set_texture">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="texture" type="RID">
+ </argument>
+ <description>
+ Sets texture to be used by light. Equivalent to [member Light2D.texture].
+ </description>
+ </method>
+ <method name="canvas_light_set_texture_offset">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="offset" type="Vector2">
+ </argument>
+ <description>
+ Sets the offset of the light's texture. Equivalent to [member Light2D.offset].
+ </description>
+ </method>
+ <method name="canvas_light_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the canvas light's [Transform2D].
+ </description>
+ </method>
+ <method name="canvas_light_set_z_range">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="min_z" type="int">
+ </argument>
+ <argument index="2" name="max_z" type="int">
+ </argument>
+ <description>
+ Sets the Z range of objects that will be affected by this light. Equivalent to [member Light2D.range_z_min] and [member Light2D.range_z_max].
+ </description>
+ </method>
+ <method name="canvas_occluder_polygon_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a new light occluder polygon and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_occluder_polygon_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="canvas_occluder_polygon_set_cull_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder_polygon" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="RenderingServer.CanvasOccluderPolygonCullMode">
+ </argument>
+ <description>
+ Sets an occluder polygons cull mode. See [enum CanvasOccluderPolygonCullMode] constants.
+ </description>
+ </method>
+ <method name="canvas_occluder_polygon_set_shape">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder_polygon" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="PackedVector2Array">
+ </argument>
+ <argument index="2" name="closed" type="bool">
+ </argument>
+ <description>
+ Sets the shape of the occluder polygon.
+ </description>
+ </method>
+ <method name="canvas_occluder_polygon_set_shape_as_lines">
+ <return type="void">
+ </return>
+ <argument index="0" name="occluder_polygon" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="PackedVector2Array">
+ </argument>
+ <description>
+ Sets the shape of the occluder polygon as lines.
+ </description>
+ </method>
+ <method name="canvas_set_item_mirroring">
+ <return type="void">
+ </return>
+ <argument index="0" name="canvas" type="RID">
+ </argument>
+ <argument index="1" name="item" type="RID">
+ </argument>
+ <argument index="2" name="mirroring" type="Vector2">
+ </argument>
+ <description>
+ A copy of the canvas item will be drawn with a local offset of the mirroring [Vector2].
+ </description>
+ </method>
+ <method name="canvas_set_modulate">
+ <return type="void">
+ </return>
+ <argument index="0" name="canvas" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Modulates all colors in the given canvas.
+ </description>
+ </method>
+ <method name="directional_light_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a directional light and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID can be used in most [code]light_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this directional light to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="environment_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an environment and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]environment_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="environment_set_adjustment">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="brightness" type="float">
+ </argument>
+ <argument index="3" name="contrast" type="float">
+ </argument>
+ <argument index="4" name="saturation" type="float">
+ </argument>
+ <argument index="5" name="ramp" type="RID">
+ </argument>
+ <description>
+ Sets the values to be used with the "Adjustment" post-process effect. See [Environment] for more details.
+ </description>
+ </method>
+ <method name="environment_set_ambient_light">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <argument index="2" name="ambient" type="int" enum="RenderingServer.EnvironmentAmbientSource" default="0">
+ </argument>
+ <argument index="3" name="energy" type="float" default="1.0">
+ </argument>
+ <argument index="4" name="sky_contibution" type="float" default="0.0">
+ </argument>
+ <argument index="5" name="reflection_source" type="int" enum="RenderingServer.EnvironmentReflectionSource" default="0">
+ </argument>
+ <argument index="6" name="ao_color" type="Color" default="Color( 0, 0, 0, 1 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="environment_set_background">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="bg" type="int" enum="RenderingServer.EnvironmentBG">
+ </argument>
+ <description>
+ Sets the [i]BGMode[/i] of the environment. Equivalent to [member Environment.background_mode].
+ </description>
+ </method>
+ <method name="environment_set_bg_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Color displayed for clear areas of the scene (if using Custom color or Color+Sky background modes).
+ </description>
+ </method>
+ <method name="environment_set_bg_energy">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="energy" type="float">
+ </argument>
+ <description>
+ Sets the intensity of the background color.
+ </description>
+ </method>
+ <method name="environment_set_canvas_max_layer">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="max_layer" type="int">
+ </argument>
+ <description>
+ Sets the maximum layer to use if using Canvas background mode.
+ </description>
+ </method>
+ <method name="environment_set_fog">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="color" type="Color">
+ </argument>
+ <argument index="3" name="sun_color" type="Color">
+ </argument>
+ <argument index="4" name="sun_amount" type="float">
+ </argument>
+ <description>
+ Sets the variables to be used with the scene fog. See [Environment] for more details.
+ </description>
+ </method>
+ <method name="environment_set_fog_depth">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="depth_begin" type="float">
+ </argument>
+ <argument index="3" name="depth_end" type="float">
+ </argument>
+ <argument index="4" name="depth_curve" type="float">
+ </argument>
+ <argument index="5" name="transmit" type="bool">
+ </argument>
+ <argument index="6" name="transmit_curve" type="float">
+ </argument>
+ <description>
+ Sets the variables to be used with the fog depth effect. See [Environment] for more details.
+ </description>
+ </method>
+ <method name="environment_set_fog_height">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="min_height" type="float">
+ </argument>
+ <argument index="3" name="max_height" type="float">
+ </argument>
+ <argument index="4" name="height_curve" type="float">
+ </argument>
+ <description>
+ Sets the variables to be used with the fog height effect. See [Environment] for more details.
+ </description>
+ </method>
+ <method name="environment_set_glow">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="level_flags" type="int">
+ </argument>
+ <argument index="3" name="intensity" type="float">
+ </argument>
+ <argument index="4" name="strength" type="float">
+ </argument>
+ <argument index="5" name="mix" type="float">
+ </argument>
+ <argument index="6" name="bloom_threshold" type="float">
+ </argument>
+ <argument index="7" name="blend_mode" type="int" enum="RenderingServer.EnvironmentGlowBlendMode">
+ </argument>
+ <argument index="8" name="hdr_bleed_threshold" type="float">
+ </argument>
+ <argument index="9" name="hdr_bleed_scale" type="float">
+ </argument>
+ <argument index="10" name="hdr_luminance_cap" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="environment_set_sky">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="sky" type="RID">
+ </argument>
+ <description>
+ Sets the [Sky] to be used as the environment's background when using [i]BGMode[/i] sky. Equivalent to [member Environment.sky].
+ </description>
+ </method>
+ <method name="environment_set_sky_custom_fov">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="scale" type="float">
+ </argument>
+ <description>
+ Sets a custom field of view for the background [Sky]. Equivalent to [member Environment.sky_custom_fov].
+ </description>
+ </method>
+ <method name="environment_set_sky_orientation">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="orientation" type="Basis">
+ </argument>
+ <description>
+ Sets the rotation of the background [Sky] expressed as a [Basis]. Equivalent to [member Environment.sky_rotation], where the rotation vector is used to construct the [Basis].
+ </description>
+ </method>
+ <method name="environment_set_ssao">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="radius" type="float">
+ </argument>
+ <argument index="3" name="intensity" type="float">
+ </argument>
+ <argument index="4" name="bias" type="float">
+ </argument>
+ <argument index="5" name="light_affect" type="float">
+ </argument>
+ <argument index="6" name="ao_channel_affect" type="float">
+ </argument>
+ <argument index="7" name="blur" type="int" enum="RenderingServer.EnvironmentSSAOBlur">
+ </argument>
+ <argument index="8" name="bilateral_sharpness" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="environment_set_ssr">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="max_steps" type="int">
+ </argument>
+ <argument index="3" name="fade_in" type="float">
+ </argument>
+ <argument index="4" name="fade_out" type="float">
+ </argument>
+ <argument index="5" name="depth_tolerance" type="float">
+ </argument>
+ <description>
+ Sets the variables to be used with the "screen space reflections" post-process effect. See [Environment] for more details.
+ </description>
+ </method>
+ <method name="environment_set_tonemap">
+ <return type="void">
+ </return>
+ <argument index="0" name="env" type="RID">
+ </argument>
+ <argument index="1" name="tone_mapper" type="int" enum="RenderingServer.EnvironmentToneMapper">
+ </argument>
+ <argument index="2" name="exposure" type="float">
+ </argument>
+ <argument index="3" name="white" type="float">
+ </argument>
+ <argument index="4" name="auto_exposure" type="bool">
+ </argument>
+ <argument index="5" name="min_luminance" type="float">
+ </argument>
+ <argument index="6" name="max_luminance" type="float">
+ </argument>
+ <argument index="7" name="auto_exp_speed" type="float">
+ </argument>
+ <argument index="8" name="auto_exp_grey" type="float">
+ </argument>
+ <description>
+ Sets the variables to be used with the "tonemap" post-process effect. See [Environment] for more details.
+ </description>
+ </method>
+ <method name="finish">
+ <return type="void">
+ </return>
+ <description>
+ Removes buffers and clears testcubes.
+ </description>
+ </method>
+ <method name="force_draw">
+ <return type="void">
+ </return>
+ <argument index="0" name="swap_buffers" type="bool" default="true">
+ </argument>
+ <argument index="1" name="frame_step" type="float" default="0.0">
+ </argument>
+ <description>
+ Forces a frame to be drawn when the function is called. Drawing a frame updates all [Viewport]s that are set to update. Use with extreme caution.
+ </description>
+ </method>
+ <method name="force_sync">
+ <return type="void">
+ </return>
+ <description>
+ Synchronizes threads.
+ </description>
+ </method>
+ <method name="free_rid">
+ <return type="void">
+ </return>
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ Tries to free an object in the RenderingServer.
+ </description>
+ </method>
+ <method name="get_render_info">
+ <return type="int">
+ </return>
+ <argument index="0" name="info" type="int" enum="RenderingServer.RenderInfo">
+ </argument>
+ <description>
+ Returns a certain information, see [enum RenderInfo] for options.
+ </description>
+ </method>
+ <method name="get_test_cube">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the id of the test cube. Creates one if none exists.
+ </description>
+ </method>
+ <method name="get_test_texture">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the id of the test texture. Creates one if none exists.
+ </description>
+ </method>
+ <method name="get_video_adapter_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the name of the video adapter (e.g. "GeForce GTX 1080/PCIe/SSE2").
+ [b]Note:[/b] When running a headless or server binary, this function returns an empty string.
+ </description>
+ </method>
+ <method name="get_video_adapter_vendor" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the vendor of the video adapter (e.g. "NVIDIA Corporation").
+ [b]Note:[/b] When running a headless or server binary, this function returns an empty string.
+ </description>
+ </method>
+ <method name="get_white_texture">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the id of a white texture. Creates one if none exists.
+ </description>
+ </method>
+ <method name="has_changed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if changes have been made to the RenderingServer's data. [method force_draw] is usually called if this happens.
+ </description>
+ </method>
+ <method name="has_feature" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="feature" type="int" enum="RenderingServer.Features">
+ </argument>
+ <description>
+ Not yet implemented. Always returns [code]false[/code].
+ </description>
+ </method>
+ <method name="has_os_feature" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="feature" type="String">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the OS supports a certain feature. Features might be [code]s3tc[/code], [code]etc[/code], [code]etc2[/code] and [code]pvrtc[/code].
+ </description>
+ </method>
+ <method name="immediate_begin">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="primitive" type="int" enum="RenderingServer.PrimitiveType">
+ </argument>
+ <argument index="2" name="texture" type="RID">
+ </argument>
+ <description>
+ Sets up [ImmediateGeometry3D] internals to prepare for drawing. Equivalent to [method ImmediateGeometry3D.begin].
+ </description>
+ </method>
+ <method name="immediate_clear">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <description>
+ Clears everything that was set up between [method immediate_begin] and [method immediate_end]. Equivalent to [method ImmediateGeometry3D.clear].
+ </description>
+ </method>
+ <method name="immediate_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the color to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_color].
+ </description>
+ </method>
+ <method name="immediate_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an immediate geometry and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]immediate_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this immediate geometry to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="immediate_end">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <description>
+ Ends drawing the [ImmediateGeometry3D] and displays it. Equivalent to [method ImmediateGeometry3D.end].
+ </description>
+ </method>
+ <method name="immediate_get_material" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <description>
+ Returns the material assigned to the [ImmediateGeometry3D].
+ </description>
+ </method>
+ <method name="immediate_normal">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="normal" type="Vector3">
+ </argument>
+ <description>
+ Sets the normal to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_normal].
+ </description>
+ </method>
+ <method name="immediate_set_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="material" type="RID">
+ </argument>
+ <description>
+ Sets the material to be used to draw the [ImmediateGeometry3D].
+ </description>
+ </method>
+ <method name="immediate_tangent">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="tangent" type="Plane">
+ </argument>
+ <description>
+ Sets the tangent to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_tangent].
+ </description>
+ </method>
+ <method name="immediate_uv">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="tex_uv" type="Vector2">
+ </argument>
+ <description>
+ Sets the UV to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_uv].
+ </description>
+ </method>
+ <method name="immediate_uv2">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="tex_uv" type="Vector2">
+ </argument>
+ <description>
+ Sets the UV2 to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_uv2].
+ </description>
+ </method>
+ <method name="immediate_vertex">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="vertex" type="Vector3">
+ </argument>
+ <description>
+ Adds the next vertex using the information provided in advance. Equivalent to [method ImmediateGeometry3D.add_vertex].
+ </description>
+ </method>
+ <method name="immediate_vertex_2d">
+ <return type="void">
+ </return>
+ <argument index="0" name="immediate" type="RID">
+ </argument>
+ <argument index="1" name="vertex" type="Vector2">
+ </argument>
+ <description>
+ Adds the next vertex using the information provided in advance. This is a helper class that calls [method immediate_vertex] under the hood. Equivalent to [method ImmediateGeometry3D.add_vertex].
+ </description>
+ </method>
+ <method name="init">
+ <return type="void">
+ </return>
+ <description>
+ Initializes the visual server. This function is called internally by platform-dependent code during engine initialization. If called from a running game, it will not do anything.
+ </description>
+ </method>
+ <method name="instance_attach_object_instance_id">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ Attaches a unique Object ID to instance. Object ID must be attached to instance for proper culling with [method instances_cull_aabb], [method instances_cull_convex], and [method instances_cull_ray].
+ </description>
+ </method>
+ <method name="instance_attach_skeleton">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="skeleton" type="RID">
+ </argument>
+ <description>
+ Attaches a skeleton to an instance. Removes the previous skeleton from the instance.
+ </description>
+ </method>
+ <method name="instance_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a visual instance and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ An instance is a way of placing a 3D object in the scenario. Objects like particles, meshes, and reflection probes need to be associated with an instance to be visible in the scenario using [method instance_set_base].
+ </description>
+ </method>
+ <method name="instance_create2">
+ <return type="RID">
+ </return>
+ <argument index="0" name="base" type="RID">
+ </argument>
+ <argument index="1" name="scenario" type="RID">
+ </argument>
+ <description>
+ Creates a visual instance, adds it to the RenderingServer, and sets both base and scenario. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="instance_geometry_set_as_instance_lod">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="as_lod_of_instance" type="RID">
+ </argument>
+ <description>
+ Not implemented in Godot 3.x.
+ </description>
+ </method>
+ <method name="instance_geometry_set_cast_shadows_setting">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="shadow_casting_setting" type="int" enum="RenderingServer.ShadowCastingSetting">
+ </argument>
+ <description>
+ Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance3D.cast_shadow].
+ </description>
+ </method>
+ <method name="instance_geometry_set_draw_range">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="min" type="float">
+ </argument>
+ <argument index="2" name="max" type="float">
+ </argument>
+ <argument index="3" name="min_margin" type="float">
+ </argument>
+ <argument index="4" name="max_margin" type="float">
+ </argument>
+ <description>
+ Not implemented in Godot 3.x.
+ </description>
+ </method>
+ <method name="instance_geometry_set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="flag" type="int" enum="RenderingServer.InstanceFlags">
+ </argument>
+ <argument index="2" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details.
+ </description>
+ </method>
+ <method name="instance_geometry_set_material_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="material" type="RID">
+ </argument>
+ <description>
+ Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_override].
+ </description>
+ </method>
+ <method name="instance_set_base">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="base" type="RID">
+ </argument>
+ <description>
+ Sets the base of the instance. A base can be any of the 3D objects that are created in the RenderingServer that can be displayed. For example, any of the light types, mesh, multimesh, immediate geometry, particle system, reflection probe, lightmap capture, and the GI probe are all types that can be set as the base of an instance in order to be displayed in the scenario.
+ </description>
+ </method>
+ <method name="instance_set_blend_shape_weight">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="shape" type="int">
+ </argument>
+ <argument index="2" name="weight" type="float">
+ </argument>
+ <description>
+ Sets the weight for a given blend shape associated with this instance.
+ </description>
+ </method>
+ <method name="instance_set_custom_aabb">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="aabb" type="AABB">
+ </argument>
+ <description>
+ Sets a custom AABB to use when culling objects from the view frustum. Equivalent to [method GeometryInstance3D.set_custom_aabb].
+ </description>
+ </method>
+ <method name="instance_set_exterior">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Function not implemented in Godot 3.x.
+ </description>
+ </method>
+ <method name="instance_set_extra_visibility_margin">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <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].
+ </description>
+ </method>
+ <method name="instance_set_layer_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ Sets the render layers that this instance will be drawn to. Equivalent to [member VisualInstance3D.layers].
+ </description>
+ </method>
+ <method name="instance_set_scenario">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="scenario" type="RID">
+ </argument>
+ <description>
+ 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">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <argument index="2" name="material" type="RID">
+ </argument>
+ <description>
+ Sets the material of a specific surface. Equivalent to [method MeshInstance3D.set_surface_material].
+ </description>
+ </method>
+ <method name="instance_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the world space transform of the instance. Equivalent to [member Node3D.transform].
+ </description>
+ </method>
+ <method name="instance_set_use_lightmap">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="lightmap_instance" type="RID">
+ </argument>
+ <argument index="2" name="lightmap" type="RID">
+ </argument>
+ <description>
+ Sets the lightmap to use with this instance.
+ </description>
+ </method>
+ <method name="instance_set_visible">
+ <return type="void">
+ </return>
+ <argument index="0" name="instance" type="RID">
+ </argument>
+ <argument index="1" name="visible" type="bool">
+ </argument>
+ <description>
+ Sets whether an instance is drawn or not. Equivalent to [member Node3D.visible].
+ </description>
+ </method>
+ <method name="instances_cull_aabb" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="aabb" type="AABB">
+ </argument>
+ <argument index="1" name="scenario" type="RID">
+ </argument>
+ <description>
+ Returns an array of object IDs intersecting with the provided AABB. Only visual 3D nodes are considered, such as [MeshInstance3D] or [DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World3D] you want to query. This forces an update for all resources queued to update.
+ [b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
+ </description>
+ </method>
+ <method name="instances_cull_convex" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="convex" type="Array">
+ </argument>
+ <argument index="1" name="scenario" type="RID">
+ </argument>
+ <description>
+ Returns an array of object IDs intersecting with the provided convex shape. Only visual 3D nodes are considered, such as [MeshInstance3D] or [DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World3D] you want to query. This forces an update for all resources queued to update.
+ [b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
+ </description>
+ </method>
+ <method name="instances_cull_ray" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="from" type="Vector3">
+ </argument>
+ <argument index="1" name="to" type="Vector3">
+ </argument>
+ <argument index="2" name="scenario" type="RID">
+ </argument>
+ <description>
+ Returns an array of object IDs intersecting with the provided 3D ray. Only visual 3D nodes are considered, such as [MeshInstance3D] or [DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World3D] you want to query. This forces an update for all resources queued to update.
+ [b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
+ </description>
+ </method>
+ <method name="light_directional_set_blend_splits">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], this directional light will blend between shadow map splits resulting in a smoother transition between them. Equivalent to [member DirectionalLight3D.directional_shadow_blend_splits].
+ </description>
+ </method>
+ <method name="light_directional_set_shadow_depth_range_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="range_mode" type="int" enum="RenderingServer.LightDirectionalShadowDepthRangeMode">
+ </argument>
+ <description>
+ Sets the shadow depth range mode for this directional light. Equivalent to [member DirectionalLight3D.directional_shadow_depth_range]. See [enum LightDirectionalShadowDepthRangeMode] for options.
+ </description>
+ </method>
+ <method name="light_directional_set_shadow_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="RenderingServer.LightDirectionalShadowMode">
+ </argument>
+ <description>
+ Sets the shadow mode for this directional light. Equivalent to [member DirectionalLight3D.directional_shadow_mode]. See [enum LightDirectionalShadowMode] for options.
+ </description>
+ </method>
+ <method name="light_omni_set_shadow_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="RenderingServer.LightOmniShadowMode">
+ </argument>
+ <description>
+ Sets whether to use a dual paraboloid or a cubemap for the shadow map. Dual paraboloid is faster but may suffer from artifacts. Equivalent to [member OmniLight3D.omni_shadow_mode].
+ </description>
+ </method>
+ <method name="light_set_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the color of the light. Equivalent to [member Light3D.light_color].
+ </description>
+ </method>
+ <method name="light_set_cull_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ Sets the cull mask for this Light3D. Lights only affect objects in the selected layers. Equivalent to [member Light3D.light_cull_mask].
+ </description>
+ </method>
+ <method name="light_set_negative">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], light will subtract light instead of adding light. Equivalent to [member Light3D.light_negative].
+ </description>
+ </method>
+ <method name="light_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="param" type="int" enum="RenderingServer.LightParam">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ Sets the specified light parameter. See [enum LightParam] for options. Equivalent to [method Light3D.set_param].
+ </description>
+ </method>
+ <method name="light_set_projector">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="texture" type="RID">
+ </argument>
+ <description>
+ Not implemented in Godot 3.x.
+ </description>
+ </method>
+ <method name="light_set_reverse_cull_face_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <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].
+ </description>
+ </method>
+ <method name="light_set_shadow">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], light will cast shadows. Equivalent to [member Light3D.shadow_enabled].
+ </description>
+ </method>
+ <method name="light_set_shadow_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the color of the shadow cast by the light. Equivalent to [member Light3D.shadow_color].
+ </description>
+ </method>
+ <method name="light_set_use_gi">
+ <return type="void">
+ </return>
+ <argument index="0" name="light" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets whether GI probes capture light information from this light.
+ </description>
+ </method>
+ <method name="lightmap_capture_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a lightmap capture and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]lightmap_capture_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this lightmap capture to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="lightmap_capture_get_bounds" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <description>
+ Returns the size of the lightmap capture area.
+ </description>
+ </method>
+ <method name="lightmap_capture_get_energy" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <description>
+ Returns the energy multiplier used by the lightmap capture.
+ </description>
+ </method>
+ <method name="lightmap_capture_get_octree" qualifiers="const">
+ <return type="PackedByteArray">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <description>
+ Returns the octree used by the lightmap capture.
+ </description>
+ </method>
+ <method name="lightmap_capture_get_octree_cell_subdiv" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <description>
+ Returns the cell subdivision amount used by this lightmap capture's octree.
+ </description>
+ </method>
+ <method name="lightmap_capture_get_octree_cell_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <description>
+ Returns the cell transform for this lightmap capture's octree.
+ </description>
+ </method>
+ <method name="lightmap_capture_set_bounds">
+ <return type="void">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <argument index="1" name="bounds" type="AABB">
+ </argument>
+ <description>
+ Sets the size of the area covered by the lightmap capture.
+ </description>
+ </method>
+ <method name="lightmap_capture_set_energy">
+ <return type="void">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <argument index="1" name="energy" type="float">
+ </argument>
+ <description>
+ Sets the energy multiplier for this lightmap capture.
+ </description>
+ </method>
+ <method name="lightmap_capture_set_octree">
+ <return type="void">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <argument index="1" name="octree" type="PackedByteArray">
+ </argument>
+ <description>
+ Sets the octree to be used by this lightmap capture.
+ </description>
+ </method>
+ <method name="lightmap_capture_set_octree_cell_subdiv">
+ <return type="void">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <argument index="1" name="subdiv" type="int">
+ </argument>
+ <description>
+ Sets the subdivision level of this lightmap capture's octree.
+ </description>
+ </method>
+ <method name="lightmap_capture_set_octree_cell_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="capture" type="RID">
+ </argument>
+ <argument index="1" name="xform" type="Transform">
+ </argument>
+ <description>
+ Sets the octree cell transform for this lightmap capture's octree.
+ </description>
+ </method>
+ <method name="make_sphere_mesh">
+ <return type="RID">
+ </return>
+ <argument index="0" name="latitudes" type="int">
+ </argument>
+ <argument index="1" name="longitudes" type="int">
+ </argument>
+ <argument index="2" name="radius" type="float">
+ </argument>
+ <description>
+ Returns a mesh of a sphere with the given amount of horizontal and vertical subdivisions.
+ </description>
+ </method>
+ <method name="material_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an empty material and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]material_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="material_get_param" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="material" type="RID">
+ </argument>
+ <argument index="1" name="parameter" type="StringName">
+ </argument>
+ <description>
+ Returns the value of a certain material's parameter.
+ </description>
+ </method>
+ <method name="material_set_next_pass">
+ <return type="void">
+ </return>
+ <argument index="0" name="material" type="RID">
+ </argument>
+ <argument index="1" name="next_material" type="RID">
+ </argument>
+ <description>
+ Sets an object's next material.
+ </description>
+ </method>
+ <method name="material_set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="material" type="RID">
+ </argument>
+ <argument index="1" name="parameter" type="StringName">
+ </argument>
+ <argument index="2" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets a material's parameter.
+ </description>
+ </method>
+ <method name="material_set_render_priority">
+ <return type="void">
+ </return>
+ <argument index="0" name="material" type="RID">
+ </argument>
+ <argument index="1" name="priority" type="int">
+ </argument>
+ <description>
+ Sets a material's render priority.
+ </description>
+ </method>
+ <method name="material_set_shader">
+ <return type="void">
+ </return>
+ <argument index="0" name="shader_material" type="RID">
+ </argument>
+ <argument index="1" name="shader" type="RID">
+ </argument>
+ <description>
+ Sets a shader material's shader.
+ </description>
+ </method>
+ <method name="mesh_add_surface_from_arrays">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="primitive" type="int" enum="RenderingServer.PrimitiveType">
+ </argument>
+ <argument index="2" name="arrays" type="Array">
+ </argument>
+ <argument index="3" name="blend_shapes" type="Array" default="[ ]">
+ </argument>
+ <argument index="4" name="lods" type="Dictionary" default="{
+
+}">
+ </argument>
+ <argument index="5" name="compress_format" type="int" default="31744">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="mesh_clear">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <description>
+ Removes all surfaces from a mesh.
+ </description>
+ </method>
+ <method name="mesh_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a new mesh and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]mesh_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this mesh to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="mesh_get_blend_shape_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <description>
+ Returns a mesh's blend shape count.
+ </description>
+ </method>
+ <method name="mesh_get_blend_shape_mode" qualifiers="const">
+ <return type="int" enum="RenderingServer.BlendShapeMode">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <description>
+ Returns a mesh's blend shape mode.
+ </description>
+ </method>
+ <method name="mesh_get_custom_aabb" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <description>
+ Returns a mesh's custom aabb.
+ </description>
+ </method>
+ <method name="mesh_get_surface_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <description>
+ Returns a mesh's number of surfaces.
+ </description>
+ </method>
+ <method name="mesh_set_blend_shape_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="RenderingServer.BlendShapeMode">
+ </argument>
+ <description>
+ Sets a mesh's blend shape mode.
+ </description>
+ </method>
+ <method name="mesh_set_custom_aabb">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="aabb" type="AABB">
+ </argument>
+ <description>
+ Sets a mesh's custom aabb.
+ </description>
+ </method>
+ <method name="mesh_surface_get_arrays" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <description>
+ Returns a mesh's surface's buffer arrays.
+ </description>
+ </method>
+ <method name="mesh_surface_get_blend_shape_arrays" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <description>
+ Returns a mesh's surface's arrays for blend shapes.
+ </description>
+ </method>
+ <method name="mesh_surface_get_format_offset" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="format" type="int">
+ </argument>
+ <argument index="1" name="vertex_len" type="int">
+ </argument>
+ <argument index="2" name="index_len" type="int">
+ </argument>
+ <argument index="3" name="array_index" type="int">
+ </argument>
+ <description>
+ Function is unused in Godot 3.x.
+ </description>
+ </method>
+ <method name="mesh_surface_get_format_stride" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="format" type="int">
+ </argument>
+ <argument index="1" name="vertex_len" type="int">
+ </argument>
+ <argument index="2" name="index_len" type="int">
+ </argument>
+ <description>
+ Function is unused in Godot 3.x.
+ </description>
+ </method>
+ <method name="mesh_surface_get_material" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <description>
+ Returns a mesh's surface's material.
+ </description>
+ </method>
+ <method name="mesh_surface_set_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <argument index="2" name="material" type="RID">
+ </argument>
+ <description>
+ Sets a mesh's surface's material.
+ </description>
+ </method>
+ <method name="mesh_surface_update_region">
+ <return type="void">
+ </return>
+ <argument index="0" name="mesh" type="RID">
+ </argument>
+ <argument index="1" name="surface" type="int">
+ </argument>
+ <argument index="2" name="offset" type="int">
+ </argument>
+ <argument index="3" name="data" type="PackedByteArray">
+ </argument>
+ <description>
+ 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">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="instances" type="int">
+ </argument>
+ <argument index="2" name="transform_format" type="int" enum="RenderingServer.MultimeshTransformFormat">
+ </argument>
+ <argument index="3" name="color_format" type="bool" default="false">
+ </argument>
+ <argument index="4" name="custom_data_format" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="multimesh_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a new multimesh on the RenderingServer and returns an [RID] handle. This RID will be used in all [code]multimesh_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this multimesh to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="multimesh_get_aabb" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <description>
+ Calculates and returns the axis-aligned bounding box that encloses all instances within the multimesh.
+ </description>
+ </method>
+ <method name="multimesh_get_buffer" qualifiers="const">
+ <return type="PackedFloat32Array">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="multimesh_get_instance_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <description>
+ Returns the number of instances allocated for this multimesh.
+ </description>
+ </method>
+ <method name="multimesh_get_mesh" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <description>
+ Returns the RID of the mesh that will be used in drawing this multimesh.
+ </description>
+ </method>
+ <method name="multimesh_get_visible_instances" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <description>
+ Returns the number of visible instances for this multimesh.
+ </description>
+ </method>
+ <method name="multimesh_instance_get_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Returns the color by which the specified instance will be modulated.
+ </description>
+ </method>
+ <method name="multimesh_instance_get_custom_data" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Returns the custom data associated with the specified instance.
+ </description>
+ </method>
+ <method name="multimesh_instance_get_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Returns the [Transform] of the specified instance.
+ </description>
+ </method>
+ <method name="multimesh_instance_get_transform_2d" qualifiers="const">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ Returns the [Transform2D] of the specified instance. For use when the multimesh is set to use 2D transforms.
+ </description>
+ </method>
+ <method name="multimesh_instance_set_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <argument index="2" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the color by which this instance will be modulated. Equivalent to [method MultiMesh.set_instance_color].
+ </description>
+ </method>
+ <method name="multimesh_instance_set_custom_data">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <argument index="2" name="custom_data" type="Color">
+ </argument>
+ <description>
+ Sets the custom data for this instance. Custom data is passed as a [Color], but is interpreted as a [code]vec4[/code] in the shader. Equivalent to [method MultiMesh.set_instance_custom_data].
+ </description>
+ </method>
+ <method name="multimesh_instance_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the [Transform] for this instance. Equivalent to [method MultiMesh.set_instance_transform].
+ </description>
+ </method>
+ <method name="multimesh_instance_set_transform_2d">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the [Transform2D] for this instance. For use when multimesh is used in 2D. Equivalent to [method MultiMesh.set_instance_transform_2d].
+ </description>
+ </method>
+ <method name="multimesh_set_buffer">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="buffer" type="PackedFloat32Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="multimesh_set_mesh">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="mesh" type="RID">
+ </argument>
+ <description>
+ Sets the mesh to be drawn by the multimesh. Equivalent to [member MultiMesh.mesh].
+ </description>
+ </method>
+ <method name="multimesh_set_visible_instances">
+ <return type="void">
+ </return>
+ <argument index="0" name="multimesh" type="RID">
+ </argument>
+ <argument index="1" name="visible" type="int">
+ </argument>
+ <description>
+ 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="omni_light_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a new omni light and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID can be used in most [code]light_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this omni light to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="particles_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a particle system and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]particles_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach these particles to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="particles_get_current_aabb">
+ <return type="AABB">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <description>
+ Calculates and returns the axis-aligned bounding box that contains all the particles. Equivalent to [method GPUParticles3D.capture_aabb].
+ </description>
+ </method>
+ <method name="particles_get_emitting">
+ <return type="bool">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <description>
+ Returns [code]true[/code] if particles are currently set to emitting.
+ </description>
+ </method>
+ <method name="particles_is_inactive">
+ <return type="bool">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <description>
+ Returns [code]true[/code] if particles are not emitting and particles are set to inactive.
+ </description>
+ </method>
+ <method name="particles_request_process">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <description>
+ Add particle system to list of particle systems that need to be updated. Update will take place on the next frame, or on the next call to [method instances_cull_aabb], [method instances_cull_convex], or [method instances_cull_ray].
+ </description>
+ </method>
+ <method name="particles_restart">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <description>
+ Reset the particles on the next update. Equivalent to [method GPUParticles3D.restart].
+ </description>
+ </method>
+ <method name="particles_set_amount">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="amount" type="int">
+ </argument>
+ <description>
+ Sets the number of particles to be drawn and allocates the memory for them. Equivalent to [member GPUParticles3D.amount].
+ </description>
+ </method>
+ <method name="particles_set_custom_aabb">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="aabb" type="AABB">
+ </argument>
+ <description>
+ Sets a custom axis-aligned bounding box for the particle system. Equivalent to [member GPUParticles3D.visibility_aabb].
+ </description>
+ </method>
+ <method name="particles_set_draw_order">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="order" type="int" enum="RenderingServer.ParticlesDrawOrder">
+ </argument>
+ <description>
+ Sets the draw order of the particles to one of the named enums from [enum ParticlesDrawOrder]. See [enum ParticlesDrawOrder] for options. Equivalent to [member GPUParticles3D.draw_order].
+ </description>
+ </method>
+ <method name="particles_set_draw_pass_mesh">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="pass" type="int">
+ </argument>
+ <argument index="2" name="mesh" type="RID">
+ </argument>
+ <description>
+ Sets the mesh to be used for the specified draw pass. Equivalent to [member GPUParticles3D.draw_pass_1], [member GPUParticles3D.draw_pass_2], [member GPUParticles3D.draw_pass_3], and [member GPUParticles3D.draw_pass_4].
+ </description>
+ </method>
+ <method name="particles_set_draw_passes">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="count" type="int">
+ </argument>
+ <description>
+ Sets the number of draw passes to use. Equivalent to [member GPUParticles3D.draw_passes].
+ </description>
+ </method>
+ <method name="particles_set_emission_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the [Transform] that will be used by the particles when they first emit.
+ </description>
+ </method>
+ <method name="particles_set_emitting">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="emitting" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], particles will emit over time. Setting to false does not reset the particles, but only stops their emission. Equivalent to [member GPUParticles3D.emitting].
+ </description>
+ </method>
+ <method name="particles_set_explosiveness_ratio">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="ratio" type="float">
+ </argument>
+ <description>
+ Sets the explosiveness ratio. Equivalent to [member GPUParticles3D.explosiveness].
+ </description>
+ </method>
+ <method name="particles_set_fixed_fps">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="fps" type="int">
+ </argument>
+ <description>
+ Sets the frame rate that the particle system rendering will be fixed to. Equivalent to [member GPUParticles3D.fixed_fps].
+ </description>
+ </method>
+ <method name="particles_set_fractional_delta">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], uses fractional delta which smooths the movement of the particles. Equivalent to [member GPUParticles3D.fract_delta].
+ </description>
+ </method>
+ <method name="particles_set_lifetime">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="lifetime" type="float">
+ </argument>
+ <description>
+ Sets the lifetime of each particle in the system. Equivalent to [member GPUParticles3D.lifetime].
+ </description>
+ </method>
+ <method name="particles_set_one_shot">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="one_shot" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], particles will emit once and then stop. Equivalent to [member GPUParticles3D.one_shot].
+ </description>
+ </method>
+ <method name="particles_set_pre_process_time">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <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].
+ </description>
+ </method>
+ <method name="particles_set_process_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="material" type="RID">
+ </argument>
+ <description>
+ Sets the material for processing the particles. Note: this is not the material used to draw the materials. Equivalent to [member GPUParticles3D.process_material].
+ </description>
+ </method>
+ <method name="particles_set_randomness_ratio">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="ratio" type="float">
+ </argument>
+ <description>
+ Sets the emission randomness ratio. This randomizes the emission of particles within their phase. Equivalent to [member GPUParticles3D.randomness].
+ </description>
+ </method>
+ <method name="particles_set_speed_scale">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="scale" type="float">
+ </argument>
+ <description>
+ Sets the speed scale of the particle system. Equivalent to [member GPUParticles3D.speed_scale].
+ </description>
+ </method>
+ <method name="particles_set_use_local_coordinates">
+ <return type="void">
+ </return>
+ <argument index="0" name="particles" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], particles use local coordinates. If [code]false[/code] they use global coordinates. Equivalent to [member GPUParticles3D.local_coords].
+ </description>
+ </method>
+ <method name="reflection_probe_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a reflection probe and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]reflection_probe_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this reflection probe to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="reflection_probe_set_as_interior">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], reflections will ignore sky contribution. Equivalent to [member ReflectionProbe.interior_enable].
+ </description>
+ </method>
+ <method name="reflection_probe_set_cull_mask">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="layers" type="int">
+ </argument>
+ <description>
+ Sets the render cull mask for this reflection probe. Only instances with a matching cull mask will be rendered by this probe. Equivalent to [member ReflectionProbe.cull_mask].
+ </description>
+ </method>
+ <method name="reflection_probe_set_enable_box_projection">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], uses box projection. This can make reflections look more correct in certain situations. Equivalent to [member ReflectionProbe.box_projection].
+ </description>
+ </method>
+ <method name="reflection_probe_set_enable_shadows">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], computes shadows in the reflection probe. This makes the reflection much slower to compute. Equivalent to [member ReflectionProbe.enable_shadows].
+ </description>
+ </method>
+ <method name="reflection_probe_set_extents">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="extents" type="Vector3">
+ </argument>
+ <description>
+ Sets the size of the area that the reflection probe will capture. Equivalent to [member ReflectionProbe.extents].
+ </description>
+ </method>
+ <method name="reflection_probe_set_intensity">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="intensity" type="float">
+ </argument>
+ <description>
+ Sets the intensity of the reflection probe. Intensity modulates the strength of the reflection. Equivalent to [member ReflectionProbe.intensity].
+ </description>
+ </method>
+ <method name="reflection_probe_set_interior_ambient">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the ambient light color for this reflection probe when set to interior mode. Equivalent to [member ReflectionProbe.interior_ambient_color].
+ </description>
+ </method>
+ <method name="reflection_probe_set_interior_ambient_energy">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="energy" type="float">
+ </argument>
+ <description>
+ Sets the energy multiplier for this reflection probes ambient light contribution when set to interior mode. Equivalent to [member ReflectionProbe.interior_ambient_energy].
+ </description>
+ </method>
+ <method name="reflection_probe_set_interior_ambient_probe_contribution">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="contrib" type="float">
+ </argument>
+ <description>
+ Sets the contribution value for how much the reflection affects the ambient light for this reflection probe when set to interior mode. Useful so that ambient light matches the color of the room. Equivalent to [member ReflectionProbe.interior_ambient_contrib].
+ </description>
+ </method>
+ <method name="reflection_probe_set_max_distance">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="distance" type="float">
+ </argument>
+ <description>
+ Sets the max distance away from the probe an object can be before it is culled. Equivalent to [member ReflectionProbe.max_distance].
+ </description>
+ </method>
+ <method name="reflection_probe_set_origin_offset">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="offset" type="Vector3">
+ </argument>
+ <description>
+ Sets the origin offset to be used when this reflection probe is in box project mode. Equivalent to [member ReflectionProbe.origin_offset].
+ </description>
+ </method>
+ <method name="reflection_probe_set_update_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="probe" type="RID">
+ </argument>
+ <argument index="1" name="mode" type="int" enum="RenderingServer.ReflectionProbeUpdateMode">
+ </argument>
+ <description>
+ Sets how often the reflection probe updates. Can either be once or every frame. See [enum ReflectionProbeUpdateMode] for options.
+ </description>
+ </method>
+ <method name="request_frame_drawn_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="where" type="Object">
+ </argument>
+ <argument index="1" name="method" type="StringName">
+ </argument>
+ <argument index="2" name="userdata" type="Variant">
+ </argument>
+ <description>
+ Schedules a callback to the corresponding named [code]method[/code] on [code]where[/code] after a frame has been drawn.
+ The callback method must use only 1 argument which will be called with [code]userdata[/code].
+ </description>
+ </method>
+ <method name="scenario_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a scenario and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]scenario_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ The scenario is the 3D world that all the visual instances exist in.
+ </description>
+ </method>
+ <method name="scenario_set_debug">
+ <return type="void">
+ </return>
+ <argument index="0" name="scenario" type="RID">
+ </argument>
+ <argument index="1" name="debug_mode" type="int" enum="RenderingServer.ScenarioDebugMode">
+ </argument>
+ <description>
+ Sets the [enum ScenarioDebugMode] for this scenario. See [enum ScenarioDebugMode] for options.
+ </description>
+ </method>
+ <method name="scenario_set_environment">
+ <return type="void">
+ </return>
+ <argument index="0" name="scenario" type="RID">
+ </argument>
+ <argument index="1" name="environment" type="RID">
+ </argument>
+ <description>
+ Sets the environment that will be used with this scenario.
+ </description>
+ </method>
+ <method name="scenario_set_fallback_environment">
+ <return type="void">
+ </return>
+ <argument index="0" name="scenario" type="RID">
+ </argument>
+ <argument index="1" name="environment" type="RID">
+ </argument>
+ <description>
+ Sets the fallback environment to be used by this scenario. The fallback environment is used if no environment is set. Internally, this is used by the editor to provide a default environment.
+ </description>
+ </method>
+ <method name="set_boot_image">
+ <return type="void">
+ </return>
+ <argument index="0" name="image" type="Image">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <argument index="2" name="scale" type="bool">
+ </argument>
+ <argument index="3" name="use_filter" type="bool" default="true">
+ </argument>
+ <description>
+ Sets a boot image. The color defines the background color. If [code]scale[/code] is [code]true[/code], the image will be scaled to fit the screen size. If [code]use_filter[/code] is [code]true[/code], the image will be scaled with linear interpolation. If [code]use_filter[/code] is [code]false[/code], the image will be scaled with nearest-neighbor interpolation.
+ </description>
+ </method>
+ <method name="set_debug_generate_wireframes">
+ <return type="void">
+ </return>
+ <argument index="0" name="generate" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], the engine will generate wireframes for use with the wireframe debug mode.
+ </description>
+ </method>
+ <method name="set_default_clear_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ Sets the default clear color which is used when a specific clear color has not been selected.
+ </description>
+ </method>
+ <method name="shader_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an empty shader and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]shader_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="shader_get_code" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="shader" type="RID">
+ </argument>
+ <description>
+ Returns a shader's code.
+ </description>
+ </method>
+ <method name="shader_get_default_texture_param" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="shader" type="RID">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <description>
+ Returns a default texture from a shader searched by name.
+ </description>
+ </method>
+ <method name="shader_get_param_default" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="material" type="RID">
+ </argument>
+ <argument index="1" name="parameter" type="StringName">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="shader_get_param_list" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shader" type="RID">
+ </argument>
+ <description>
+ Returns the parameters of a shader.
+ </description>
+ </method>
+ <method name="shader_set_code">
+ <return type="void">
+ </return>
+ <argument index="0" name="shader" type="RID">
+ </argument>
+ <argument index="1" name="code" type="String">
+ </argument>
+ <description>
+ Sets a shader's code.
+ </description>
+ </method>
+ <method name="shader_set_default_texture_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="shader" type="RID">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="texture" type="RID">
+ </argument>
+ <description>
+ Sets a shader's default texture. Overwrites the texture given by name.
+ </description>
+ </method>
+ <method name="skeleton_allocate">
+ <return type="void">
+ </return>
+ <argument index="0" name="skeleton" type="RID">
+ </argument>
+ <argument index="1" name="bones" type="int">
+ </argument>
+ <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">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="skeleton" type="RID">
+ </argument>
+ <argument index="1" name="bone" type="int">
+ </argument>
+ <description>
+ Returns the [Transform] set for a specific bone of this skeleton.
+ </description>
+ </method>
+ <method name="skeleton_bone_get_transform_2d" qualifiers="const">
+ <return type="Transform2D">
+ </return>
+ <argument index="0" name="skeleton" type="RID">
+ </argument>
+ <argument index="1" name="bone" type="int">
+ </argument>
+ <description>
+ Returns the [Transform2D] set for a specific bone of this skeleton.
+ </description>
+ </method>
+ <method name="skeleton_bone_set_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="skeleton" type="RID">
+ </argument>
+ <argument index="1" name="bone" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform">
+ </argument>
+ <description>
+ Sets the [Transform] for a specific bone of this skeleton.
+ </description>
+ </method>
+ <method name="skeleton_bone_set_transform_2d">
+ <return type="void">
+ </return>
+ <argument index="0" name="skeleton" type="RID">
+ </argument>
+ <argument index="1" name="bone" type="int">
+ </argument>
+ <argument index="2" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the [Transform2D] for a specific bone of this skeleton.
+ </description>
+ </method>
+ <method name="skeleton_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a skeleton and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]skeleton_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="skeleton_get_bone_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="skeleton" type="RID">
+ </argument>
+ <description>
+ Returns the number of bones allocated for this skeleton.
+ </description>
+ </method>
+ <method name="sky_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an empty sky and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]sky_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="sky_set_material">
+ <return type="void">
+ </return>
+ <argument index="0" name="sky" type="RID">
+ </argument>
+ <argument index="1" name="material" type="RID">
+ </argument>
+ <description>
+ Sets the material that the sky uses to render the background and reflection maps.
+ </description>
+ </method>
+ <method name="spot_light_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates a spot light and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID can be used in most [code]light_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ To place in a scene, attach this spot light to an instance using [method instance_set_base] using the returned RID.
+ </description>
+ </method>
+ <method name="texture_2d_create">
+ <return type="RID">
+ </return>
+ <argument index="0" name="image" type="Image">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_2d_get" qualifiers="const">
+ <return type="Image">
+ </return>
+ <argument index="0" name="texture" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="viewport_attach_camera">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="camera" type="RID">
+ </argument>
+ <description>
+ Sets a viewport's camera.
+ </description>
+ </method>
+ <method name="viewport_attach_canvas">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="canvas" type="RID">
+ </argument>
+ <description>
+ Sets a viewport's canvas.
+ </description>
+ </method>
+ <method name="viewport_attach_to_screen">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="rect" type="Rect2" default="Rect2( 0, 0, 0, 0 )">
+ </argument>
+ <argument index="2" name="screen" type="int" default="0">
+ </argument>
+ <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]
+ func _ready():
+ get_viewport().set_attach_to_screen_rect(Rect2())
+ $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))
+ [/codeblock]
+ 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>
+ <method name="viewport_create">
+ <return type="RID">
+ </return>
+ <description>
+ Creates an empty viewport and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]viewport_*[/code] RenderingServer functions.
+ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
+ </description>
+ </method>
+ <method name="viewport_get_render_info">
+ <return type="int">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="info" type="int" enum="RenderingServer.ViewportRenderInfo">
+ </argument>
+ <description>
+ Returns a viewport's render information. For options, see the [enum ViewportRenderInfo] constants.
+ </description>
+ </method>
+ <method name="viewport_get_texture" qualifiers="const">
+ <return type="RID">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <description>
+ Returns the viewport's last rendered frame.
+ </description>
+ </method>
+ <method name="viewport_remove_canvas">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="canvas" type="RID">
+ </argument>
+ <description>
+ Detaches a viewport from a canvas and vice versa.
+ </description>
+ </method>
+ <method name="viewport_set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="active" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], sets the viewport active, else sets it inactive.
+ </description>
+ </method>
+ <method name="viewport_set_canvas_stacking">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="canvas" type="RID">
+ </argument>
+ <argument index="2" name="layer" type="int">
+ </argument>
+ <argument index="3" name="sublayer" type="int">
+ </argument>
+ <description>
+ Sets the stacking order for a viewport's canvas.
+ [code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] specifies the stacking order of the canvas among those in the same layer.
+ </description>
+ </method>
+ <method name="viewport_set_canvas_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="canvas" type="RID">
+ </argument>
+ <argument index="2" name="offset" type="Transform2D">
+ </argument>
+ <description>
+ Sets the transformation of a viewport's canvas.
+ </description>
+ </method>
+ <method name="viewport_set_clear_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="clear_mode" type="int" enum="RenderingServer.ViewportClearMode">
+ </argument>
+ <description>
+ Sets the clear mode of a viewport. See [enum ViewportClearMode] for options.
+ </description>
+ </method>
+ <method name="viewport_set_debug_draw">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="draw" type="int" enum="RenderingServer.ViewportDebugDraw">
+ </argument>
+ <description>
+ Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for options.
+ </description>
+ </method>
+ <method name="viewport_set_disable_environment">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="disabled" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], rendering of a viewport's environment is disabled.
+ </description>
+ </method>
+ <method name="viewport_set_global_canvas_transform">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="transform" type="Transform2D">
+ </argument>
+ <description>
+ Sets the viewport's global transformation matrix.
+ </description>
+ </method>
+ <method name="viewport_set_hide_canvas">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="hidden" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], the viewport's canvas is not rendered.
+ </description>
+ </method>
+ <method name="viewport_set_hide_scenario">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="hidden" type="bool">
+ </argument>
+ <description>
+ Currently unimplemented in Godot 3.x.
+ </description>
+ </method>
+ <method name="viewport_set_msaa">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="msaa" type="int" enum="RenderingServer.ViewportMSAA">
+ </argument>
+ <description>
+ Sets the anti-aliasing mode. See [enum ViewportMSAA] for options.
+ </description>
+ </method>
+ <method name="viewport_set_parent_viewport">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="parent_viewport" type="RID">
+ </argument>
+ <description>
+ Sets the viewport's parent to another viewport.
+ </description>
+ </method>
+ <method name="viewport_set_render_direct_to_screen">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
+ </description>
+ </method>
+ <method name="viewport_set_scenario">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="scenario" type="RID">
+ </argument>
+ <description>
+ Sets a viewport's scenario.
+ The scenario contains information about the [enum ScenarioDebugMode], environment information, reflection atlas etc.
+ </description>
+ </method>
+ <method name="viewport_set_shadow_atlas_quadrant_subdivision">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="quadrant" type="int">
+ </argument>
+ <argument index="2" name="subdivision" type="int">
+ </argument>
+ <description>
+ Sets the shadow atlas quadrant's subdivision.
+ </description>
+ </method>
+ <method name="viewport_set_shadow_atlas_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="size" type="int">
+ </argument>
+ <description>
+ Sets the size of the shadow atlas's images (used for omni and spot lights). The value will be rounded up to the nearest power of 2.
+ </description>
+ </method>
+ <method name="viewport_set_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="width" type="int">
+ </argument>
+ <argument index="2" name="height" type="int">
+ </argument>
+ <description>
+ Sets the viewport's width and height.
+ </description>
+ </method>
+ <method name="viewport_set_transparent_background">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], the viewport renders its background as transparent.
+ </description>
+ </method>
+ <method name="viewport_set_update_mode">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="update_mode" type="int" enum="RenderingServer.ViewportUpdateMode">
+ </argument>
+ <description>
+ Sets when the viewport should be updated. See [enum ViewportUpdateMode] constants for options.
+ </description>
+ </method>
+ <method name="viewport_set_use_xr">
+ <return type="void">
+ </return>
+ <argument index="0" name="viewport" type="RID">
+ </argument>
+ <argument index="1" name="use_xr" type="bool">
+ </argument>
+ <description>
+ If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [XRInterface].
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="frame_post_draw">
+ <description>
+ Emitted at the end of the frame, after the RenderingServer has finished updating all the Viewports.
+ </description>
+ </signal>
+ <signal name="frame_pre_draw">
+ <description>
+ Emitted at the beginning of the frame, before the RenderingServer updates all the Viewports.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="NO_INDEX_ARRAY" value="-1">
+ Marks an error that shows that the index array is empty.
+ </constant>
+ <constant name="ARRAY_WEIGHTS_SIZE" value="4">
+ Number of weights/bones per vertex.
+ </constant>
+ <constant name="CANVAS_ITEM_Z_MIN" value="-4096">
+ The minimum Z-layer for canvas items.
+ </constant>
+ <constant name="CANVAS_ITEM_Z_MAX" value="4096">
+ The maximum Z-layer for canvas items.
+ </constant>
+ <constant name="MAX_GLOW_LEVELS" value="7">
+ Max number of glow levels that can be used with glow post-process effect.
+ </constant>
+ <constant name="MAX_CURSORS" value="8">
+ Unused enum in Godot 3.x.
+ </constant>
+ <constant name="MATERIAL_RENDER_PRIORITY_MIN" value="-128">
+ The minimum renderpriority of all materials.
+ </constant>
+ <constant name="MATERIAL_RENDER_PRIORITY_MAX" value="127">
+ The maximum renderpriority of all materials.
+ </constant>
+ <constant name="TEXTURE_LAYERED_2D_ARRAY" value="0" enum="TextureLayeredType">
+ </constant>
+ <constant name="TEXTURE_LAYERED_CUBEMAP" value="1" enum="TextureLayeredType">
+ </constant>
+ <constant name="TEXTURE_LAYERED_CUBEMAP_ARRAY" value="2" enum="TextureLayeredType">
+ </constant>
+ <constant name="CUBEMAP_LAYER_LEFT" value="0" enum="CubeMapLayer">
+ </constant>
+ <constant name="CUBEMAP_LAYER_RIGHT" value="1" enum="CubeMapLayer">
+ </constant>
+ <constant name="CUBEMAP_LAYER_BOTTOM" value="2" enum="CubeMapLayer">
+ </constant>
+ <constant name="CUBEMAP_LAYER_TOP" value="3" enum="CubeMapLayer">
+ </constant>
+ <constant name="CUBEMAP_LAYER_FRONT" value="4" enum="CubeMapLayer">
+ </constant>
+ <constant name="CUBEMAP_LAYER_BACK" value="5" enum="CubeMapLayer">
+ </constant>
+ <constant name="SHADER_SPATIAL" value="0" enum="ShaderMode">
+ Shader is a 3D shader.
+ </constant>
+ <constant name="SHADER_CANVAS_ITEM" value="1" enum="ShaderMode">
+ Shader is a 2D shader.
+ </constant>
+ <constant name="SHADER_PARTICLES" value="2" enum="ShaderMode">
+ Shader is a particle shader.
+ </constant>
+ <constant name="SHADER_SKY" value="3" enum="ShaderMode">
+ Shader is a sky shader.
+ </constant>
+ <constant name="SHADER_MAX" value="4" enum="ShaderMode">
+ Represents the size of the [enum ShaderMode] enum.
+ </constant>
+ <constant name="ARRAY_VERTEX" value="0" enum="ArrayType">
+ Array is a vertex array.
+ </constant>
+ <constant name="ARRAY_NORMAL" value="1" enum="ArrayType">
+ Array is a normal array.
+ </constant>
+ <constant name="ARRAY_TANGENT" value="2" enum="ArrayType">
+ Array is a tangent array.
+ </constant>
+ <constant name="ARRAY_COLOR" value="3" enum="ArrayType">
+ Array is a color array.
+ </constant>
+ <constant name="ARRAY_TEX_UV" value="4" enum="ArrayType">
+ Array is an UV coordinates array.
+ </constant>
+ <constant name="ARRAY_TEX_UV2" value="5" enum="ArrayType">
+ Array is an UV coordinates array for the second UV coordinates.
+ </constant>
+ <constant name="ARRAY_BONES" value="6" enum="ArrayType">
+ Array contains bone information.
+ </constant>
+ <constant name="ARRAY_WEIGHTS" value="7" enum="ArrayType">
+ Array is weight information.
+ </constant>
+ <constant name="ARRAY_INDEX" value="8" enum="ArrayType">
+ Array is index array.
+ </constant>
+ <constant name="ARRAY_MAX" value="9" enum="ArrayType">
+ Represents the size of the [enum ArrayType] enum.
+ </constant>
+ <constant name="ARRAY_FORMAT_VERTEX" value="1" enum="ArrayFormat">
+ Flag used to mark a vertex array.
+ </constant>
+ <constant name="ARRAY_FORMAT_NORMAL" value="2" enum="ArrayFormat">
+ Flag used to mark a normal array.
+ </constant>
+ <constant name="ARRAY_FORMAT_TANGENT" value="4" enum="ArrayFormat">
+ Flag used to mark a tangent array.
+ </constant>
+ <constant name="ARRAY_FORMAT_COLOR" value="8" enum="ArrayFormat">
+ Flag used to mark a color array.
+ </constant>
+ <constant name="ARRAY_FORMAT_TEX_UV" value="16" enum="ArrayFormat">
+ Flag used to mark an UV coordinates array.
+ </constant>
+ <constant name="ARRAY_FORMAT_TEX_UV2" value="32" enum="ArrayFormat">
+ Flag used to mark an UV coordinates array for the second UV coordinates.
+ </constant>
+ <constant name="ARRAY_FORMAT_BONES" value="64" enum="ArrayFormat">
+ Flag used to mark a bone information array.
+ </constant>
+ <constant name="ARRAY_FORMAT_WEIGHTS" value="128" enum="ArrayFormat">
+ Flag used to mark a weights array.
+ </constant>
+ <constant name="ARRAY_FORMAT_INDEX" value="256" enum="ArrayFormat">
+ Flag used to mark an index array.
+ </constant>
+ <constant name="ARRAY_COMPRESS_NORMAL" value="1024" enum="ArrayFormat">
+ Flag used to mark a compressed (half float) normal array.
+ </constant>
+ <constant name="ARRAY_COMPRESS_TANGENT" value="2048" enum="ArrayFormat">
+ Flag used to mark a compressed (half float) tangent array.
+ </constant>
+ <constant name="ARRAY_COMPRESS_COLOR" value="4096" enum="ArrayFormat">
+ Flag used to mark a compressed (half float) color array.
+ </constant>
+ <constant name="ARRAY_COMPRESS_TEX_UV" value="8192" enum="ArrayFormat">
+ Flag used to mark a compressed (half float) UV coordinates array.
+ </constant>
+ <constant name="ARRAY_COMPRESS_TEX_UV2" value="16384" enum="ArrayFormat">
+ Flag used to mark a compressed (half float) UV coordinates array for the second UV coordinates.
+ </constant>
+ <constant name="ARRAY_COMPRESS_INDEX" value="131072" enum="ArrayFormat">
+ Flag used to mark a compressed index array.
+ </constant>
+ <constant name="ARRAY_FLAG_USE_2D_VERTICES" value="262144" enum="ArrayFormat">
+ Flag used to mark that the array contains 2D vertices.
+ </constant>
+ <constant name="ARRAY_FLAG_USE_DYNAMIC_UPDATE" value="1048576" enum="ArrayFormat">
+ </constant>
+ <constant name="ARRAY_COMPRESS_DEFAULT" value="31744" enum="ArrayFormat">
+ Used to set flags [constant ARRAY_COMPRESS_NORMAL], [constant ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant ARRAY_COMPRESS_TEX_UV] and [constant ARRAY_COMPRESS_TEX_UV2] quickly.
+ </constant>
+ <constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType">
+ Primitive to draw consists of points.
+ </constant>
+ <constant name="PRIMITIVE_LINES" value="1" enum="PrimitiveType">
+ Primitive to draw consists of lines.
+ </constant>
+ <constant name="PRIMITIVE_LINE_STRIP" value="2" enum="PrimitiveType">
+ Primitive to draw consists of a line strip from start to end.
+ </constant>
+ <constant name="PRIMITIVE_TRIANGLES" value="3" enum="PrimitiveType">
+ Primitive to draw consists of triangles.
+ </constant>
+ <constant name="PRIMITIVE_TRIANGLE_STRIP" value="4" enum="PrimitiveType">
+ Primitive to draw consists of a triangle strip (the last 3 vertices are always combined to make a triangle).
+ </constant>
+ <constant name="PRIMITIVE_MAX" value="5" enum="PrimitiveType">
+ Represents the size of the [enum PrimitiveType] enum.
+ </constant>
+ <constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode">
+ Blend shapes are normalized.
+ </constant>
+ <constant name="BLEND_SHAPE_MODE_RELATIVE" value="1" enum="BlendShapeMode">
+ Blend shapes are relative to base weight.
+ </constant>
+ <constant name="MULTIMESH_TRANSFORM_2D" value="0" enum="MultimeshTransformFormat">
+ Use [Transform2D] to store MultiMesh transform.
+ </constant>
+ <constant name="MULTIMESH_TRANSFORM_3D" value="1" enum="MultimeshTransformFormat">
+ Use [Transform] to store MultiMesh transform.
+ </constant>
+ <constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType">
+ Is a directional (sun) light.
+ </constant>
+ <constant name="LIGHT_OMNI" value="1" enum="LightType">
+ Is an omni light.
+ </constant>
+ <constant name="LIGHT_SPOT" value="2" enum="LightType">
+ Is a spot light.
+ </constant>
+ <constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam">
+ The light's energy.
+ </constant>
+ <constant name="LIGHT_PARAM_INDIRECT_ENERGY" value="1" enum="LightParam">
+ </constant>
+ <constant name="LIGHT_PARAM_SPECULAR" value="2" enum="LightParam">
+ The light's influence on specularity.
+ </constant>
+ <constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam">
+ The light's range.
+ </constant>
+ <constant name="LIGHT_PARAM_SIZE" value="4" enum="LightParam">
+ The size of the light when using spot light or omni light. The angular size of the light when using directional light.
+ </constant>
+ <constant name="LIGHT_PARAM_ATTENUATION" value="5" enum="LightParam">
+ The light's attenuation.
+ </constant>
+ <constant name="LIGHT_PARAM_SPOT_ANGLE" value="6" enum="LightParam">
+ The spotlight's angle.
+ </constant>
+ <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="7" enum="LightParam">
+ The spotlight's attenuation.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam">
+ Max distance that shadows will be rendered.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="LightParam">
+ Proportion of shadow atlas occupied by the first split.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="LightParam">
+ Proportion of shadow atlas occupied by the second split.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="LightParam">
+ Proportion of shadow atlas occupied by the third split. The fourth split occupies the rest.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_FADE_START" value="12" enum="LightParam">
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_NORMAL_BIAS" value="13" enum="LightParam">
+ Normal bias used to offset shadow lookup by object normal. Can be used to fix self-shadowing artifacts.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_BIAS" value="14" enum="LightParam">
+ Bias the shadow lookup to fix self-shadowing artifacts.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="LightParam">
+ Increases bias on further splits to fix self-shadowing that only occurs far away from the camera.
+ </constant>
+ <constant name="LIGHT_PARAM_MAX" value="16" enum="LightParam">
+ Represents the size of the [enum LightParam] enum.
+ </constant>
+ <constant name="LIGHT_OMNI_SHADOW_DUAL_PARABOLOID" value="0" enum="LightOmniShadowMode">
+ Use a dual paraboloid shadow map for omni lights.
+ </constant>
+ <constant name="LIGHT_OMNI_SHADOW_CUBE" value="1" enum="LightOmniShadowMode">
+ Use a cubemap shadow map for omni lights. Slower but better quality than dual paraboloid.
+ </constant>
+ <constant name="LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL" value="0" enum="LightDirectionalShadowMode">
+ Use orthogonal shadow projection for directional light.
+ </constant>
+ <constant name="LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS" value="1" enum="LightDirectionalShadowMode">
+ Use 2 splits for shadow projection when using directional light.
+ </constant>
+ <constant name="LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS" value="2" enum="LightDirectionalShadowMode">
+ Use 4 splits for shadow projection when using directional light.
+ </constant>
+ <constant name="LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE" value="0" enum="LightDirectionalShadowDepthRangeMode">
+ Keeps shadows stable as camera moves but has lower effective resolution.
+ </constant>
+ <constant name="LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="LightDirectionalShadowDepthRangeMode">
+ Optimize use of shadow maps, increasing the effective resolution. But may result in shadows moving or flickering slightly.
+ </constant>
+ <constant name="REFLECTION_PROBE_UPDATE_ONCE" value="0" enum="ReflectionProbeUpdateMode">
+ Reflection probe will update reflections once and then stop.
+ </constant>
+ <constant name="REFLECTION_PROBE_UPDATE_ALWAYS" value="1" enum="ReflectionProbeUpdateMode">
+ Reflection probe will update each frame. This mode is necessary to capture moving objects.
+ </constant>
+ <constant name="PARTICLES_DRAW_ORDER_INDEX" value="0" enum="ParticlesDrawOrder">
+ Draw particles in the order that they appear in the particles array.
+ </constant>
+ <constant name="PARTICLES_DRAW_ORDER_LIFETIME" value="1" enum="ParticlesDrawOrder">
+ Sort particles based on their lifetime.
+ </constant>
+ <constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="2" enum="ParticlesDrawOrder">
+ Sort particles based on their distance to the camera.
+ </constant>
+ <constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">
+ Do not update the viewport.
+ </constant>
+ <constant name="VIEWPORT_UPDATE_ONCE" value="1" enum="ViewportUpdateMode">
+ Update the viewport once then set to disabled.
+ </constant>
+ <constant name="VIEWPORT_UPDATE_WHEN_VISIBLE" value="2" enum="ViewportUpdateMode">
+ Update the viewport whenever it is visible.
+ </constant>
+ <constant name="VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE" value="3" enum="ViewportUpdateMode">
+ </constant>
+ <constant name="VIEWPORT_UPDATE_ALWAYS" value="4" enum="ViewportUpdateMode">
+ Always update the viewport.
+ </constant>
+ <constant name="VIEWPORT_CLEAR_ALWAYS" value="0" enum="ViewportClearMode">
+ The viewport is always cleared before drawing.
+ </constant>
+ <constant name="VIEWPORT_CLEAR_NEVER" value="1" enum="ViewportClearMode">
+ The viewport is never cleared before drawing.
+ </constant>
+ <constant name="VIEWPORT_CLEAR_ONLY_NEXT_FRAME" value="2" enum="ViewportClearMode">
+ The viewport is cleared once, then the clear mode is set to [constant VIEWPORT_CLEAR_NEVER].
+ </constant>
+ <constant name="VIEWPORT_MSAA_DISABLED" value="0" enum="ViewportMSAA">
+ Multisample antialiasing is disabled.
+ </constant>
+ <constant name="VIEWPORT_MSAA_2X" value="1" enum="ViewportMSAA">
+ Multisample antialiasing is set to 2×.
+ </constant>
+ <constant name="VIEWPORT_MSAA_4X" value="2" enum="ViewportMSAA">
+ Multisample antialiasing is set to 4×.
+ </constant>
+ <constant name="VIEWPORT_MSAA_8X" value="3" enum="ViewportMSAA">
+ Multisample antialiasing is set to 8×.
+ </constant>
+ <constant name="VIEWPORT_MSAA_16X" value="4" enum="ViewportMSAA">
+ Multisample antialiasing is set to 16×.
+ </constant>
+ <constant name="VIEWPORT_MSAA_EXT_2X" value="5" enum="ViewportMSAA">
+ Multisample antialiasing is set to 2× on external texture. Special mode for GLES2 Android VR (Oculus Quest and Go).
+ </constant>
+ <constant name="VIEWPORT_MSAA_EXT_4X" value="6" enum="ViewportMSAA">
+ Multisample antialiasing is set to 4× on external texture. Special mode for GLES2 Android VR (Oculus Quest and Go).
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME" value="0" enum="ViewportRenderInfo">
+ Number of objects drawn in a single frame.
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME" value="1" enum="ViewportRenderInfo">
+ Number of vertices drawn in a single frame.
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="ViewportRenderInfo">
+ Number of material changes during this frame.
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="ViewportRenderInfo">
+ Number of shader changes during this frame.
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="ViewportRenderInfo">
+ Number of surface changes during this frame.
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="5" enum="ViewportRenderInfo">
+ Number of draw calls during this frame.
+ </constant>
+ <constant name="VIEWPORT_RENDER_INFO_MAX" value="6" enum="ViewportRenderInfo">
+ Represents the size of the [enum ViewportRenderInfo] enum.
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_DISABLED" value="0" enum="ViewportDebugDraw">
+ Debug draw is disabled. Default setting.
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_UNSHADED" value="1" enum="ViewportDebugDraw">
+ Debug draw sets objects to unshaded.
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_LIGHTING" value="2" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_OVERDRAW" value="3" enum="ViewportDebugDraw">
+ Overwrites clear color to [code](0,0,0,0)[/code].
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_WIREFRAME" value="4" enum="ViewportDebugDraw">
+ Debug draw draws objects in wireframe.
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO" value="6" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING" value="7" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION" value="8" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS" value="9" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS" value="10" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE" value="11" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_SSAO" value="12" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER" value="13" enum="ViewportDebugDraw">
+ </constant>
+ <constant name="SKY_MODE_QUALITY" value="0" enum="SkyMode">
+ </constant>
+ <constant name="SKY_MODE_REALTIME" value="1" enum="SkyMode">
+ </constant>
+ <constant name="ENV_BG_CLEAR_COLOR" value="0" enum="EnvironmentBG">
+ Use the clear color as background.
+ </constant>
+ <constant name="ENV_BG_COLOR" value="1" enum="EnvironmentBG">
+ Use a specified color as the background.
+ </constant>
+ <constant name="ENV_BG_SKY" value="2" enum="EnvironmentBG">
+ Use a sky resource for the background.
+ </constant>
+ <constant name="ENV_BG_CANVAS" value="3" enum="EnvironmentBG">
+ Use a specified canvas layer as the background. This can be useful for instantiating a 2D scene in a 3D world.
+ </constant>
+ <constant name="ENV_BG_KEEP" value="4" enum="EnvironmentBG">
+ Do not clear the background, use whatever was rendered last frame as the background.
+ </constant>
+ <constant name="ENV_BG_CAMERA_FEED" value="5" enum="EnvironmentBG">
+ Displays a camera feed in the background.
+ </constant>
+ <constant name="ENV_BG_MAX" value="6" enum="EnvironmentBG">
+ Represents the size of the [enum EnvironmentBG] enum.
+ </constant>
+ <constant name="ENV_AMBIENT_SOURCE_BG" value="0" enum="EnvironmentAmbientSource">
+ </constant>
+ <constant name="ENV_AMBIENT_SOURCE_DISABLED" value="1" enum="EnvironmentAmbientSource">
+ </constant>
+ <constant name="ENV_AMBIENT_SOURCE_COLOR" value="2" enum="EnvironmentAmbientSource">
+ </constant>
+ <constant name="ENV_AMBIENT_SOURCE_SKY" value="3" enum="EnvironmentAmbientSource">
+ </constant>
+ <constant name="ENV_REFLECTION_SOURCE_BG" value="0" enum="EnvironmentReflectionSource">
+ </constant>
+ <constant name="ENV_REFLECTION_SOURCE_DISABLED" value="1" enum="EnvironmentReflectionSource">
+ </constant>
+ <constant name="ENV_REFLECTION_SOURCE_SKY" value="2" enum="EnvironmentReflectionSource">
+ </constant>
+ <constant name="ENV_GLOW_BLEND_MODE_ADDITIVE" value="0" enum="EnvironmentGlowBlendMode">
+ </constant>
+ <constant name="ENV_GLOW_BLEND_MODE_SCREEN" value="1" enum="EnvironmentGlowBlendMode">
+ </constant>
+ <constant name="ENV_GLOW_BLEND_MODE_SOFTLIGHT" value="2" enum="EnvironmentGlowBlendMode">
+ </constant>
+ <constant name="ENV_GLOW_BLEND_MODE_REPLACE" value="3" enum="EnvironmentGlowBlendMode">
+ </constant>
+ <constant name="ENV_GLOW_BLEND_MODE_MIX" value="4" enum="EnvironmentGlowBlendMode">
+ </constant>
+ <constant name="ENV_TONE_MAPPER_LINEAR" value="0" enum="EnvironmentToneMapper">
+ Output color as they came in.
+ </constant>
+ <constant name="ENV_TONE_MAPPER_REINHARD" value="1" enum="EnvironmentToneMapper">
+ Use the Reinhard tonemapper.
+ </constant>
+ <constant name="ENV_TONE_MAPPER_FILMIC" value="2" enum="EnvironmentToneMapper">
+ Use the filmic tonemapper.
+ </constant>
+ <constant name="ENV_TONE_MAPPER_ACES" value="3" enum="EnvironmentToneMapper">
+ Use the ACES tonemapper.
+ </constant>
+ <constant name="ENV_SSAO_BLUR_DISABLED" value="0" enum="EnvironmentSSAOBlur">
+ Disables the blur set for SSAO. Will make SSAO look noisier.
+ </constant>
+ <constant name="ENV_SSAO_BLUR_1x1" value="1" enum="EnvironmentSSAOBlur">
+ Perform a 1x1 blur on the SSAO output.
+ </constant>
+ <constant name="ENV_SSAO_BLUR_2x2" value="2" enum="EnvironmentSSAOBlur">
+ Performs a 2x2 blur on the SSAO output.
+ </constant>
+ <constant name="ENV_SSAO_BLUR_3x3" value="3" enum="EnvironmentSSAOBlur">
+ Performs a 3x3 blur on the SSAO output. Use this for smoothest SSAO.
+ </constant>
+ <constant name="ENV_SSAO_QUALITY_LOW" value="0" enum="EnvironmentSSAOQuality">
+ Lowest quality of screen space ambient occlusion.
+ </constant>
+ <constant name="ENV_SSAO_QUALITY_MEDIUM" value="1" enum="EnvironmentSSAOQuality">
+ Medium quality screen space ambient occlusion.
+ </constant>
+ <constant name="ENV_SSAO_QUALITY_HIGH" value="2" enum="EnvironmentSSAOQuality">
+ Highest quality screen space ambient occlusion.
+ </constant>
+ <constant name="ENV_SSAO_QUALITY_ULTRA" value="3" enum="EnvironmentSSAOQuality">
+ </constant>
+ <constant name="DOF_BLUR_QUALITY_VERY_LOW" value="0" enum="DOFBlurQuality">
+ </constant>
+ <constant name="DOF_BLUR_QUALITY_LOW" value="1" enum="DOFBlurQuality">
+ </constant>
+ <constant name="DOF_BLUR_QUALITY_MEDIUM" value="2" enum="DOFBlurQuality">
+ </constant>
+ <constant name="DOF_BLUR_QUALITY_HIGH" value="3" enum="DOFBlurQuality">
+ </constant>
+ <constant name="DOF_BOKEH_BOX" value="0" enum="DOFBokehShape">
+ </constant>
+ <constant name="DOF_BOKEH_HEXAGON" value="1" enum="DOFBokehShape">
+ </constant>
+ <constant name="DOF_BOKEH_CIRCLE" value="2" enum="DOFBokehShape">
+ </constant>
+ <constant name="SCENARIO_DEBUG_DISABLED" value="0" enum="ScenarioDebugMode">
+ Do not use a debug mode.
+ </constant>
+ <constant name="SCENARIO_DEBUG_WIREFRAME" value="1" enum="ScenarioDebugMode">
+ Draw all objects as wireframe models.
+ </constant>
+ <constant name="SCENARIO_DEBUG_OVERDRAW" value="2" enum="ScenarioDebugMode">
+ Draw all objects in a way that displays how much overdraw is occurring. Overdraw occurs when a section of pixels is drawn and shaded and then another object covers it up. To optimize a scene, you should reduce overdraw.
+ </constant>
+ <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="INSTANCE_NONE" value="0" enum="InstanceType">
+ The instance does not have a type.
+ </constant>
+ <constant name="INSTANCE_MESH" value="1" enum="InstanceType">
+ The instance is a mesh.
+ </constant>
+ <constant name="INSTANCE_MULTIMESH" value="2" enum="InstanceType">
+ The instance is a multimesh.
+ </constant>
+ <constant name="INSTANCE_IMMEDIATE" value="3" enum="InstanceType">
+ The instance is an immediate geometry.
+ </constant>
+ <constant name="INSTANCE_PARTICLES" value="4" enum="InstanceType">
+ The instance is a particle emitter.
+ </constant>
+ <constant name="INSTANCE_LIGHT" value="5" enum="InstanceType">
+ The instance is a light.
+ </constant>
+ <constant name="INSTANCE_REFLECTION_PROBE" value="6" enum="InstanceType">
+ The instance is a reflection probe.
+ </constant>
+ <constant name="INSTANCE_GI_PROBE" value="7" enum="InstanceType">
+ The instance is a GI probe.
+ </constant>
+ <constant name="INSTANCE_LIGHTMAP_CAPTURE" value="8" enum="InstanceType">
+ The instance is a lightmap capture.
+ </constant>
+ <constant name="INSTANCE_MAX" value="9" enum="InstanceType">
+ Represents the size of the [enum InstanceType] enum.
+ </constant>
+ <constant name="INSTANCE_GEOMETRY_MASK" value="30" enum="InstanceType">
+ A combination of the flags of geometry instances (mesh, multimesh, immediate and particles).
+ </constant>
+ <constant name="INSTANCE_FLAG_USE_BAKED_LIGHT" value="0" enum="InstanceFlags">
+ Allows the instance to be used in baked lighting.
+ </constant>
+ <constant name="INSTANCE_FLAG_USE_DYNAMIC_GI" value="1" enum="InstanceFlags">
+ </constant>
+ <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">
+ Represents the size of the [enum InstanceFlags] enum.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
+ Disable shadows from this instance.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_ON" value="1" enum="ShadowCastingSetting">
+ Cast shadows from this instance.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_DOUBLE_SIDED" value="2" enum="ShadowCastingSetting">
+ Disable backface culling when rendering the shadow of the object. This is slightly slower but may result in more correct shadows.
+ </constant>
+ <constant name="SHADOW_CASTING_SETTING_SHADOWS_ONLY" value="3" enum="ShadowCastingSetting">
+ Only render the shadows from the object. The object itself will not be drawn.
+ </constant>
+ <constant name="NINE_PATCH_STRETCH" value="0" enum="NinePatchAxisMode">
+ The nine patch gets stretched where needed.
+ </constant>
+ <constant name="NINE_PATCH_TILE" value="1" enum="NinePatchAxisMode">
+ The nine patch gets filled with tiles where needed.
+ </constant>
+ <constant name="NINE_PATCH_TILE_FIT" value="2" enum="NinePatchAxisMode">
+ The nine patch gets filled with tiles where needed and stretches them a bit if needed.
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_DEFAULT" value="0" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="1" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="2" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="4" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_FILTER_MAX" value="7" enum="CanvasItemTextureFilter">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT" value="0" enum="CanvasItemTextureRepeat">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_REPEAT_DISABLED" value="1" enum="CanvasItemTextureRepeat">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_REPEAT_ENABLED" value="2" enum="CanvasItemTextureRepeat">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_REPEAT_MIRROR" value="3" enum="CanvasItemTextureRepeat">
+ </constant>
+ <constant name="CANVAS_ITEM_TEXTURE_REPEAT_MAX" value="4" enum="CanvasItemTextureRepeat">
+ </constant>
+ <constant name="CANVAS_LIGHT_MODE_ADD" value="0" enum="CanvasLightMode">
+ Adds light color additive to the canvas.
+ </constant>
+ <constant name="CANVAS_LIGHT_MODE_SUB" value="1" enum="CanvasLightMode">
+ Adds light color subtractive to the canvas.
+ </constant>
+ <constant name="CANVAS_LIGHT_MODE_MIX" value="2" enum="CanvasLightMode">
+ The light adds color depending on transparency.
+ </constant>
+ <constant name="CANVAS_LIGHT_MODE_MASK" value="3" enum="CanvasLightMode">
+ The light adds color depending on mask.
+ </constant>
+ <constant name="CANVAS_LIGHT_FILTER_NONE" value="0" enum="CanvasLightShadowFilter">
+ Do not apply a filter to canvas light shadows.
+ </constant>
+ <constant name="CANVAS_LIGHT_FILTER_PCF5" value="1" enum="CanvasLightShadowFilter">
+ Use PCF5 filtering to filter canvas light shadows.
+ </constant>
+ <constant name="CANVAS_LIGHT_FILTER_PCF13" value="2" enum="CanvasLightShadowFilter">
+ Use PCF13 filtering to filter canvas light shadows.
+ </constant>
+ <constant name="CANVAS_LIGHT_FILTER_MAX" value="3" enum="CanvasLightShadowFilter">
+ </constant>
+ <constant name="CANVAS_OCCLUDER_POLYGON_CULL_DISABLED" value="0" enum="CanvasOccluderPolygonCullMode">
+ Culling of the canvas occluder is disabled.
+ </constant>
+ <constant name="CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE" value="1" enum="CanvasOccluderPolygonCullMode">
+ Culling of the canvas occluder is clockwise.
+ </constant>
+ <constant name="CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE" value="2" enum="CanvasOccluderPolygonCullMode">
+ Culling of the canvas occluder is counterclockwise.
+ </constant>
+ <constant name="INFO_OBJECTS_IN_FRAME" value="0" enum="RenderInfo">
+ The amount of objects in the frame.
+ </constant>
+ <constant name="INFO_VERTICES_IN_FRAME" value="1" enum="RenderInfo">
+ The amount of vertices in the frame.
+ </constant>
+ <constant name="INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="RenderInfo">
+ The amount of modified materials in the frame.
+ </constant>
+ <constant name="INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="RenderInfo">
+ The amount of shader rebinds in the frame.
+ </constant>
+ <constant name="INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="RenderInfo">
+ The amount of surface changes in the frame.
+ </constant>
+ <constant name="INFO_DRAW_CALLS_IN_FRAME" value="5" enum="RenderInfo">
+ The amount of draw calls in frame.
+ </constant>
+ <constant name="INFO_USAGE_VIDEO_MEM_TOTAL" value="6" enum="RenderInfo">
+ Unimplemented in the GLES2 rendering backend, always returns 0.
+ </constant>
+ <constant name="INFO_VIDEO_MEM_USED" value="7" enum="RenderInfo">
+ The amount of video memory used, i.e. texture and vertex memory combined.
+ </constant>
+ <constant name="INFO_TEXTURE_MEM_USED" value="8" enum="RenderInfo">
+ The amount of texture memory used.
+ </constant>
+ <constant name="INFO_VERTEX_MEM_USED" value="9" enum="RenderInfo">
+ The amount of vertex memory used.
+ </constant>
+ <constant name="FEATURE_SHADERS" value="0" enum="Features">
+ Hardware supports shaders. This enum is currently unused in Godot 3.x.
+ </constant>
+ <constant name="FEATURE_MULTITHREADED" value="1" enum="Features">
+ Hardware supports multithreading. This enum is currently unused in Godot 3.x.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml
index 533bc9ec28..1cf775f389 100644
--- a/doc/classes/ResourceLoader.xml
+++ b/doc/classes/ResourceLoader.xml
@@ -74,6 +74,8 @@
<argument index="0" name="path" type="String">
</argument>
<description>
+ Returns the resource loaded by [method load_threaded_request].
+ If this is called before the loading thread is done (i.e. [method load_threaded_get_status] is not [constant THREAD_LOAD_LOADED]), the calling thread will be blocked until the resource has finished loading.
</description>
</method>
<method name="load_threaded_get_status">
@@ -84,6 +86,8 @@
<argument index="1" name="progress" type="Array" default="[ ]">
</argument>
<description>
+ Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [code]path[/code]. See [enum ThreadLoadStatus] for possible return values.
+ An array variable can optionally be passed via [code]progress[/code], and will return a one-element array containing the percentage of completion of the threaded loading.
</description>
</method>
<method name="load_threaded_request">
@@ -96,6 +100,7 @@
<argument index="2" name="use_sub_threads" type="bool" default="false">
</argument>
<description>
+ Loads the resource using threads. If [code]use_sub_threads[/code] is [code]true[/code], multiple threads will be used to load the resource, which makes loading faster, but may affect the main thread (and thus cause game slowdowns).
</description>
</method>
<method name="set_abort_on_missing_resources">
@@ -110,12 +115,16 @@
</methods>
<constants>
<constant name="THREAD_LOAD_INVALID_RESOURCE" value="0" enum="ThreadLoadStatus">
+ The resource is invalid, or has not been loaded with [method load_threaded_request].
</constant>
<constant name="THREAD_LOAD_IN_PROGRESS" value="1" enum="ThreadLoadStatus">
+ The resource is still being loaded.
</constant>
<constant name="THREAD_LOAD_FAILED" value="2" enum="ThreadLoadStatus">
+ Some error occurred during loading and it failed.
</constant>
<constant name="THREAD_LOAD_LOADED" value="3" enum="ThreadLoadStatus">
+ The resource was loaded successfully and can be accessed via [method load_threaded_get].
</constant>
</constants>
</class>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 5f07133a27..efc0c9d600 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -409,38 +409,55 @@
</constants>
<theme_items>
<theme_item name="bold_font" type="Font">
+ The font used for bold text.
</theme_item>
<theme_item name="bold_italics_font" type="Font">
+ The font used for bold italics text.
</theme_item>
<theme_item name="default_color" type="Color" default="Color( 1, 1, 1, 1 )">
+ The default text color.
</theme_item>
<theme_item name="focus" type="StyleBox">
+ The background The background used when the [RichTextLabel] is focused.
</theme_item>
<theme_item name="font_color_selected" type="Color" default="Color( 0.49, 0.49, 0.49, 1 )">
+ The color of selected text, used when [member selection_enabled] is [code]true[/code].
</theme_item>
<theme_item name="font_color_shadow" type="Color" default="Color( 0, 0, 0, 0 )">
+ The color of the font's shadow.
</theme_item>
<theme_item name="italics_font" type="Font">
+ The font used for italics text.
</theme_item>
<theme_item name="line_separation" type="int" default="1">
+ The vertical space between lines.
</theme_item>
<theme_item name="mono_font" type="Font">
+ The font used for monospace text.
</theme_item>
<theme_item name="normal" type="StyleBox">
+ The normal background for the [RichTextLabel].
</theme_item>
<theme_item name="normal_font" type="Font">
+ The default text font.
</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>
<theme_item name="shadow_as_outline" type="int" default="0">
+ Boolean value. If 1 ([code]true[/code]), the shadow will be displayed around the whole text as an outline.
</theme_item>
<theme_item name="shadow_offset_x" type="int" default="1">
+ The horizontal offset of the font's shadow.
</theme_item>
<theme_item name="shadow_offset_y" type="int" default="1">
+ The vertical offset of the font's shadow.
</theme_item>
<theme_item name="table_hseparation" type="int" default="3">
+ The horizontal separation of elements in a table.
</theme_item>
<theme_item name="table_vseparation" type="int" default="3">
+ The vertical separation of elements in a table.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml
deleted file mode 100644
index e2b7813361..0000000000
--- a/doc/classes/RigidBody.xml
+++ /dev/null
@@ -1,253 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RigidBody" inherits="PhysicsBody" version="4.0">
- <brief_description>
- Physics Body whose position is determined through physics simulation in 3D space.
- </brief_description>
- <description>
- This is the node that implements full 3D physics. This means that you do not control a RigidBody directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc.
- A RigidBody has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic.
- [b]Note:[/b] Don't change a RigidBody's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
- If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator].
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
- </tutorials>
- <methods>
- <method name="_integrate_forces" qualifiers="virtual">
- <return type="void">
- </return>
- <argument index="0" name="state" type="PhysicsDirectBodyState">
- </argument>
- <description>
- Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it works in addition to the usual physics behavior, but the [member custom_integrator] property allows you to disable the default behavior and do fully custom force integration for a body.
- </description>
- </method>
- <method name="add_central_force">
- <return type="void">
- </return>
- <argument index="0" name="force" type="Vector3">
- </argument>
- <description>
- Adds a constant directional force without affecting rotation.
- This is equivalent to [code]add_force(force, Vector3(0,0,0))[/code].
- </description>
- </method>
- <method name="add_force">
- <return type="void">
- </return>
- <argument index="0" name="force" type="Vector3">
- </argument>
- <argument index="1" name="position" type="Vector3">
- </argument>
- <description>
- Adds a constant force (i.e. acceleration).
- </description>
- </method>
- <method name="add_torque">
- <return type="void">
- </return>
- <argument index="0" name="torque" type="Vector3">
- </argument>
- <description>
- Adds a constant rotational force (i.e. a motor) without affecting position.
- </description>
- </method>
- <method name="apply_central_impulse">
- <return type="void">
- </return>
- <argument index="0" name="impulse" type="Vector3">
- </argument>
- <description>
- Applies a directional impulse without affecting rotation.
- This is equivalent to [code]apply_impulse(Vector3(0,0,0), impulse)[/code].
- </description>
- </method>
- <method name="apply_impulse">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <argument index="1" name="impulse" type="Vector3">
- </argument>
- <description>
- Applies a positioned impulse to the body. An impulse is time independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts. The position uses the rotation of the global coordinate system, but is centered at the object's origin.
- </description>
- </method>
- <method name="apply_torque_impulse">
- <return type="void">
- </return>
- <argument index="0" name="impulse" type="Vector3">
- </argument>
- <description>
- Applies a torque impulse which will be affected by the body mass and shape. This will rotate the body around the [code]impulse[/code] vector passed.
- </description>
- </method>
- <method name="get_axis_lock" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="axis" type="int" enum="PhysicsServer.BodyAxis">
- </argument>
- <description>
- Returns [code]true[/code] if the specified linear or rotational axis is locked.
- </description>
- </method>
- <method name="get_colliding_bodies" qualifiers="const">
- <return type="Array">
- </return>
- <description>
- Returns a list of the bodies colliding with this one. By default, number of max contacts reported is at 0, see the [member contacts_reported] property to increase it.
- [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead.
- </description>
- </method>
- <method name="set_axis_lock">
- <return type="void">
- </return>
- <argument index="0" name="axis" type="int" enum="PhysicsServer.BodyAxis">
- </argument>
- <argument index="1" name="lock" type="bool">
- </argument>
- <description>
- Locks the specified linear or rotational axis.
- </description>
- </method>
- <method name="set_axis_velocity">
- <return type="void">
- </return>
- <argument index="0" name="axis_velocity" type="Vector3">
- </argument>
- <description>
- Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="-1.0">
- Damps RigidBody's rotational forces.
- </member>
- <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity" default="Vector3( 0, 0, 0 )">
- RigidBody's rotational velocity.
- </member>
- <member name="axis_lock_angular_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's rotation in the X axis.
- </member>
- <member name="axis_lock_angular_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's rotation in the Y axis.
- </member>
- <member name="axis_lock_angular_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's rotation in the Z axis.
- </member>
- <member name="axis_lock_linear_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's movement in the X axis.
- </member>
- <member name="axis_lock_linear_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's movement in the Y axis.
- </member>
- <member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
- Lock the body's movement in the Z axis.
- </member>
- <member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true">
- If [code]true[/code], the RigidBody will not calculate forces and will act as a static body while there is no movement. It will wake up when forces are applied through other collisions or when the [code]apply_impulse[/code] method is used.
- </member>
- <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
- If [code]true[/code], the RigidBody will emit signals when it collides with another RigidBody.
- </member>
- <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0">
- The maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
- </member>
- <member name="continuous_cd" type="bool" setter="set_use_continuous_collision_detection" getter="is_using_continuous_collision_detection" default="false">
- If [code]true[/code], continuous collision detection is used.
- Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided. Continuous collision detection is more precise, and misses fewer impacts by small, fast-moving objects. Not using continuous collision detection is faster to compute, but can miss small, fast-moving objects.
- </member>
- <member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false">
- If [code]true[/code], internal force integration will be disabled (like gravity or air friction) for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] function, if defined.
- </member>
- <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
- This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce RigidBody's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
- </member>
- <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="-1.0">
- The body's linear damp. Cannot be less than -1.0. If this value is different from -1.0, any linear damp derived from the world or areas will be overridden.
- </member>
- <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3( 0, 0, 0 )">
- The body's linear velocity. Can be used sporadically, but [b]don't set this every frame[/b], because physics may run in another thread and runs at a different granularity. Use [method _integrate_forces] as your process loop for precise control of the body state.
- </member>
- <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0">
- The body's mass.
- </member>
- <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidBody.Mode" default="0">
- The body mode. See [enum Mode] for possible values.
- </member>
- <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
- The physics material override for the body.
- If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
- </member>
- <member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping" default="false">
- If [code]true[/code], the body is sleeping and will not calculate forces until woken up by a collision or the [code]apply_impulse[/code] method.
- </member>
- <member name="weight" type="float" setter="set_weight" getter="get_weight" default="9.8">
- The body's weight based on its mass and the global 3D gravity. Global values are set in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b].
- </member>
- </members>
- <signals>
- <signal name="body_entered">
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
- </description>
- </signal>
- <signal name="body_exited">
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work.
- </description>
- </signal>
- <signal name="body_shape_entered">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Node">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="local_shape" type="int">
- </argument>
- <description>
- Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
- This signal not only receives the body that collided with this one, but also its [RID] ([code]body_id[/code]), the shape index from the colliding body ([code]body_shape[/code]), and the shape index from this body ([code]local_shape[/code]) the other body collided with.
- </description>
- </signal>
- <signal name="body_shape_exited">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Node">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="local_shape" type="int">
- </argument>
- <description>
- Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work.
- This signal not only receives the body that stopped colliding with this one, but also its [RID] ([code]body_id[/code]), the shape index from the colliding body ([code]body_shape[/code]), and the shape index from this body ([code]local_shape[/code]) the other body stopped colliding with.
- </description>
- </signal>
- <signal name="sleeping_state_changed">
- <description>
- Emitted when the body changes its sleeping state. Either by sleeping or waking up.
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="MODE_RIGID" value="0" enum="Mode">
- Rigid body mode. This is the "natural" state of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code.
- </constant>
- <constant name="MODE_STATIC" value="1" enum="Mode">
- Static mode. The body behaves like a [StaticBody], and can only move by user code.
- </constant>
- <constant name="MODE_CHARACTER" value="2" enum="Mode">
- Character body mode. This behaves like a rigid body, but can not rotate.
- </constant>
- <constant name="MODE_KINEMATIC" value="3" enum="Mode">
- Kinematic body mode. The body behaves like a [KinematicBody], and can only move by user code.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 79c4205f59..e746d7fc96 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -16,7 +16,7 @@
<method name="_integrate_forces" qualifiers="virtual">
<return type="void">
</return>
- <argument index="0" name="state" type="Physics2DDirectBodyState">
+ <argument index="0" name="state" type="PhysicsDirectBodyState2D">
</argument>
<description>
Allows you to read and safely modify the simulation state for the object. Use this instead of [method Node._physics_process] if you need to directly change the body's [code]position[/code] or other physics properties. By default, it works in addition to the usual physics behavior, but [member custom_integrator] allows you to disable the default behavior and write custom force integration for a body.
@@ -106,10 +106,10 @@
</argument>
<argument index="2" name="margin" type="float" default="0.08">
</argument>
- <argument index="3" name="result" type="Physics2DTestMotionResult" default="null">
+ <argument index="3" name="result" type="PhysicsTestMotionResult2D" default="null">
</argument>
<description>
- Returns [code]true[/code] if a collision would result from moving in the given vector. [code]margin[/code] increases the size of the shapes involved in the collision detection, and [code]result[/code] is an object of type [Physics2DTestMotionResult], which contains additional information about the collision (should there be one).
+ Returns [code]true[/code] if a collision would result from moving in the given vector. [code]margin[/code] increases the size of the shapes involved in the collision detection, and [code]result[/code] is an object of type [PhysicsTestMotionResult2D], which contains additional information about the collision (should there be one).
</description>
</method>
</methods>
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
new file mode 100644
index 0000000000..1db818d6af
--- /dev/null
+++ b/doc/classes/RigidBody3D.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RigidBody3D" inherits="PhysicsBody3D" version="4.0">
+ <brief_description>
+ Physics Body whose position is determined through physics simulation in 3D space.
+ </brief_description>
+ <description>
+ This is the node that implements full 3D physics. This means that you do not control a RigidBody3D directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc.
+ A RigidBody3D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic.
+ [b]Note:[/b] Don't change a RigidBody3D's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
+ If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator].
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ </tutorials>
+ <methods>
+ <method name="_integrate_forces" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="state" type="PhysicsDirectBodyState3D">
+ </argument>
+ <description>
+ Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it works in addition to the usual physics behavior, but the [member custom_integrator] property allows you to disable the default behavior and do fully custom force integration for a body.
+ </description>
+ </method>
+ <method name="add_central_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="Vector3">
+ </argument>
+ <description>
+ Adds a constant directional force (i.e. acceleration) without affecting rotation.
+ This is equivalent to [code]add_force(force, Vector3(0,0,0))[/code].
+ </description>
+ </method>
+ <method name="add_force">
+ <return type="void">
+ </return>
+ <argument index="0" name="force" type="Vector3">
+ </argument>
+ <argument index="1" name="position" type="Vector3">
+ </argument>
+ <description>
+ Adds a constant directional force (i.e. acceleration).
+ The position uses the rotation of the global coordinate system, but is centered at the object's origin.
+ </description>
+ </method>
+ <method name="add_torque">
+ <return type="void">
+ </return>
+ <argument index="0" name="torque" type="Vector3">
+ </argument>
+ <description>
+ Adds a constant rotational force (i.e. a motor) without affecting position.
+ </description>
+ </method>
+ <method name="apply_central_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ Applies a directional impulse without affecting rotation.
+ This is equivalent to [code]apply_impulse(Vector3(0,0,0), impulse)[/code].
+ </description>
+ </method>
+ <method name="apply_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <argument index="1" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ Applies a positioned impulse to the body. An impulse is time independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts. The position uses the rotation of the global coordinate system, but is centered at the object's origin.
+ </description>
+ </method>
+ <method name="apply_torque_impulse">
+ <return type="void">
+ </return>
+ <argument index="0" name="impulse" type="Vector3">
+ </argument>
+ <description>
+ Applies a torque impulse which will be affected by the body mass and shape. This will rotate the body around the [code]impulse[/code] vector passed.
+ </description>
+ </method>
+ <method name="get_axis_lock" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis">
+ </argument>
+ <description>
+ Returns [code]true[/code] if the specified linear or rotational axis is locked.
+ </description>
+ </method>
+ <method name="get_colliding_bodies" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Returns a list of the bodies colliding with this one. By default, number of max contacts reported is at 0, see the [member contacts_reported] property to increase it.
+ [b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead.
+ </description>
+ </method>
+ <method name="set_axis_lock">
+ <return type="void">
+ </return>
+ <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis">
+ </argument>
+ <argument index="1" name="lock" type="bool">
+ </argument>
+ <description>
+ Locks the specified linear or rotational axis.
+ </description>
+ </method>
+ <method name="set_axis_velocity">
+ <return type="void">
+ </return>
+ <argument index="0" name="axis_velocity" type="Vector3">
+ </argument>
+ <description>
+ Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="-1.0">
+ Damps RigidBody3D's rotational forces.
+ </member>
+ <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity" default="Vector3( 0, 0, 0 )">
+ RigidBody3D's rotational velocity.
+ </member>
+ <member name="axis_lock_angular_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's rotation in the X axis.
+ </member>
+ <member name="axis_lock_angular_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's rotation in the Y axis.
+ </member>
+ <member name="axis_lock_angular_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's rotation in the Z axis.
+ </member>
+ <member name="axis_lock_linear_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's movement in the X axis.
+ </member>
+ <member name="axis_lock_linear_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's movement in the Y axis.
+ </member>
+ <member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false">
+ Lock the body's movement in the Z axis.
+ </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.
+ </member>
+ <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
+ If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D.
+ </member>
+ <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0">
+ The maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
+ </member>
+ <member name="continuous_cd" type="bool" setter="set_use_continuous_collision_detection" getter="is_using_continuous_collision_detection" default="false">
+ If [code]true[/code], continuous collision detection is used.
+ Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided. Continuous collision detection is more precise, and misses fewer impacts by small, fast-moving objects. Not using continuous collision detection is faster to compute, but can miss small, fast-moving objects.
+ </member>
+ <member name="custom_integrator" type="bool" setter="set_use_custom_integrator" getter="is_using_custom_integrator" default="false">
+ If [code]true[/code], internal force integration will be disabled (like gravity or air friction) for this body. Other than collision response, the body will only move as determined by the [method _integrate_forces] function, if defined.
+ </member>
+ <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
+ This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce RigidBody3D's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
+ </member>
+ <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="-1.0">
+ The body's linear damp. Cannot be less than -1.0. If this value is different from -1.0, any linear damp derived from the world or areas will be overridden.
+ </member>
+ <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3( 0, 0, 0 )">
+ The body's linear velocity. Can be used sporadically, but [b]don't set this every frame[/b], because physics may run in another thread and runs at a different granularity. Use [method _integrate_forces] as your process loop for precise control of the body state.
+ </member>
+ <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0">
+ The body's mass.
+ </member>
+ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidBody3D.Mode" default="0">
+ The body mode. See [enum Mode] for possible values.
+ </member>
+ <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
+ The physics material override for the body.
+ If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
+ </member>
+ <member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping" default="false">
+ If [code]true[/code], the body is sleeping and will not calculate forces until woken up by a collision or the [code]apply_impulse[/code] method.
+ </member>
+ <member name="weight" type="float" setter="set_weight" getter="get_weight" default="9.8">
+ The body's weight based on its mass and the global 3D gravity. Global values are set in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b].
+ </member>
+ </members>
+ <signals>
+ <signal name="body_entered">
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ </description>
+ </signal>
+ <signal name="body_exited">
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ </description>
+ </signal>
+ <signal name="body_shape_entered">
+ <argument index="0" name="body_id" type="int">
+ </argument>
+ <argument index="1" name="body" type="Node">
+ </argument>
+ <argument index="2" name="body_shape" type="int">
+ </argument>
+ <argument index="3" name="local_shape" type="int">
+ </argument>
+ <description>
+ Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ This signal not only receives the body that collided with this one, but also its [RID] ([code]body_id[/code]), the shape index from the colliding body ([code]body_shape[/code]), and the shape index from this body ([code]local_shape[/code]) the other body collided with.
+ </description>
+ </signal>
+ <signal name="body_shape_exited">
+ <argument index="0" name="body_id" type="int">
+ </argument>
+ <argument index="1" name="body" type="Node">
+ </argument>
+ <argument index="2" name="body_shape" type="int">
+ </argument>
+ <argument index="3" name="local_shape" type="int">
+ </argument>
+ <description>
+ Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ This signal not only receives the body that stopped colliding with this one, but also its [RID] ([code]body_id[/code]), the shape index from the colliding body ([code]body_shape[/code]), and the shape index from this body ([code]local_shape[/code]) the other body stopped colliding with.
+ </description>
+ </signal>
+ <signal name="sleeping_state_changed">
+ <description>
+ Emitted when the body changes its sleeping state. Either by sleeping or waking up.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="MODE_RIGID" value="0" enum="Mode">
+ Rigid body mode. This is the "natural" state of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code.
+ </constant>
+ <constant name="MODE_STATIC" value="1" enum="Mode">
+ Static mode. The body behaves like a [StaticBody3D], and can only move by user code.
+ </constant>
+ <constant name="MODE_CHARACTER" value="2" enum="Mode">
+ Character body mode. This behaves like a rigid body, but can not rotate.
+ </constant>
+ <constant name="MODE_KINEMATIC" value="3" enum="Mode">
+ Kinematic body mode. The body behaves like a [KinematicBody3D], and can only move by user code.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/RootMotionView.xml b/doc/classes/RootMotionView.xml
index 654e42a3c6..be8d8d0078 100644
--- a/doc/classes/RootMotionView.xml
+++ b/doc/classes/RootMotionView.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RootMotionView" inherits="VisualInstance" version="4.0">
+<class name="RootMotionView" inherits="VisualInstance3D" version="4.0">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index e6778013cf..00ca5c6e9f 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -135,13 +135,6 @@
Returns [code]true[/code] if there is a [member network_peer] set.
</description>
</method>
- <method name="is_input_handled">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if the most recent [InputEvent] was marked as handled with [method set_input_as_handled].
- </description>
- </method>
<method name="is_network_server" qualifiers="const">
<return type="bool">
</return>
@@ -237,13 +230,6 @@
Sets the given [code]property[/code] to [code]value[/code] on all members of the given group, respecting the given [enum GroupCallFlags].
</description>
</method>
- <method name="set_input_as_handled">
- <return type="void">
- </return>
- <description>
- Marks the most recent [InputEvent] as handled.
- </description>
- </method>
<method name="set_quit_on_go_back">
<return type="void">
</return>
@@ -251,22 +237,7 @@
</argument>
<description>
If [code]true[/code], the application quits automatically on going back (e.g. on Android). Enabled by default.
- To handle 'Go Back' button when this option is disabled, use [constant MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST].
- </description>
- </method>
- <method name="set_screen_stretch">
- <return type="void">
- </return>
- <argument index="0" name="mode" type="int" enum="SceneTree.StretchMode">
- </argument>
- <argument index="1" name="aspect" type="int" enum="SceneTree.StretchAspect">
- </argument>
- <argument index="2" name="minsize" type="Vector2">
- </argument>
- <argument index="3" name="shrink" type="float" default="1">
- </argument>
- <description>
- Configures screen stretching to the given [enum StretchMode], [enum StretchAspect], minimum size and [code]shrink[/code] ratio.
+ To handle 'Go Back' button when this option is disabled, use [constant DisplayServer.WINDOW_EVENT_GO_BACK_REQUEST].
</description>
</method>
</methods>
@@ -301,11 +272,8 @@
<member name="refuse_new_network_connections" type="bool" setter="set_refuse_new_network_connections" getter="is_refusing_new_network_connections" default="false">
If [code]true[/code], the [SceneTree]'s [member network_peer] refuses new incoming connections.
</member>
- <member name="root" type="Viewport" setter="" getter="get_root">
- The [SceneTree]'s root [Viewport].
- </member>
- <member name="use_font_oversampling" type="bool" setter="set_use_font_oversampling" getter="is_using_font_oversampling" default="false">
- If [code]true[/code], font oversampling is used.
+ <member name="root" type="Window" setter="" getter="get_root">
+ The [SceneTree]'s root [Window].
</member>
</members>
<signals>
@@ -328,15 +296,6 @@
Emitted when files are dragged from the OS file manager and dropped in the game window. The arguments are a list of file paths and the identifier of the screen where the drag originated.
</description>
</signal>
- <signal name="global_menu_action">
- <argument index="0" name="id" type="Variant">
- </argument>
- <argument index="1" name="meta" type="Variant">
- </argument>
- <description>
- Emitted whenever global menu item is clicked.
- </description>
- </signal>
<signal name="idle_frame">
<description>
Emitted immediately before [method Node._process] is called on every node in the [SceneTree].
@@ -389,11 +348,6 @@
Emitted immediately before [method Node._physics_process] is called on every node in the [SceneTree].
</description>
</signal>
- <signal name="screen_resized">
- <description>
- Emitted when the screen resolution (fullscreen) or window size (windowed) changes.
- </description>
- </signal>
<signal name="server_disconnected">
<description>
Emitted whenever this [SceneTree]'s [member network_peer] disconnected from server. Only emitted on clients.
@@ -418,29 +372,5 @@
<constant name="GROUP_CALL_UNIQUE" value="4" enum="GroupCallFlags">
Call a group only once even if the call is executed many times.
</constant>
- <constant name="STRETCH_MODE_DISABLED" value="0" enum="StretchMode">
- No stretching.
- </constant>
- <constant name="STRETCH_MODE_2D" value="1" enum="StretchMode">
- Render stretching in higher resolution (interpolated).
- </constant>
- <constant name="STRETCH_MODE_VIEWPORT" value="2" enum="StretchMode">
- Keep the specified display resolution. No interpolation. Content may appear pixelated.
- </constant>
- <constant name="STRETCH_ASPECT_IGNORE" value="0" enum="StretchAspect">
- Fill the window with the content stretched to cover excessive space. Content may appear stretched.
- </constant>
- <constant name="STRETCH_ASPECT_KEEP" value="1" enum="StretchAspect">
- Retain the same aspect ratio by padding with black bars on either axis. This prevents distortion.
- </constant>
- <constant name="STRETCH_ASPECT_KEEP_WIDTH" value="2" enum="StretchAspect">
- Expand vertically. Left/right black bars may appear if the window is too wide.
- </constant>
- <constant name="STRETCH_ASPECT_KEEP_HEIGHT" value="3" enum="StretchAspect">
- Expand horizontally. Top/bottom black bars may appear if the window is too tall.
- </constant>
- <constant name="STRETCH_ASPECT_EXPAND" value="4" enum="StretchAspect">
- Expand in both directions, retaining the same aspect ratio. This prevents distortion while avoiding black bars.
- </constant>
</constants>
</class>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index f671315620..0d94453e52 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -38,30 +38,35 @@
<argument index="0" name="property" type="StringName">
</argument>
<description>
+ Returns the default value of the specified property.
</description>
</method>
<method name="get_script_constant_map">
<return type="Dictionary">
</return>
<description>
+ Returns a dictionary containing constant names and their values.
</description>
</method>
<method name="get_script_method_list">
<return type="Array">
</return>
<description>
+ Returns the list of methods in this [Script].
</description>
</method>
<method name="get_script_property_list">
<return type="Array">
</return>
<description>
+ Returns the list of properties in this [Script].
</description>
</method>
<method name="get_script_signal_list">
<return type="Array">
</return>
<description>
+ Returns the list of user signals defined in this [Script].
</description>
</method>
<method name="has_script_signal" qualifiers="const">
diff --git a/doc/classes/ScriptCreateDialog.xml b/doc/classes/ScriptCreateDialog.xml
index 9f16a6ed46..aa60ecb12b 100644
--- a/doc/classes/ScriptCreateDialog.xml
+++ b/doc/classes/ScriptCreateDialog.xml
@@ -4,7 +4,7 @@
The Editor's popup dialog for creating new [Script] files.
</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 Popup.popup] methods.
+ 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]
func _ready():
dialog.config("Node", "res://new_node.gd") # For in-engine types
@@ -33,10 +33,7 @@
</methods>
<members>
<member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok" override="true" default="false" />
- <member name="margin_bottom" type="float" setter="set_margin" getter="get_margin" override="true" default="232.0" />
- <member name="margin_right" type="float" setter="set_margin" getter="get_margin" override="true" default="361.0" />
- <member name="rect_size" type="Vector2" setter="_set_size" getter="get_size" override="true" default="Vector2( 361, 232 )" />
- <member name="window_title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Attach Node Script&quot;" />
+ <member name="title" type="String" setter="set_title" getter="get_title" override="true" default="&quot;Attach Node Script&quot;" />
</members>
<signals>
<signal name="script_created">
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index ed401d6853..10d6e5f578 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ScriptEditor" inherits="PanelContainer" version="4.0">
<brief_description>
+ Godot editor's script editor.
</brief_description>
<description>
</description>
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index 14c5d7a03c..109c500a63 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -66,5 +66,8 @@
<constant name="MODE_PARTICLES" value="2" enum="Mode">
Mode used to calculate particle information on a per-particle basis. Not used for drawing.
</constant>
+ <constant name="MODE_SKY" value="3" enum="Mode">
+ Mode used for drawing skies. Only works with shaders attached to [Sky] objects.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Shape.xml b/doc/classes/Shape.xml
deleted file mode 100644
index d70d2c09b3..0000000000
--- a/doc/classes/Shape.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Shape" inherits="Resource" version="4.0">
- <brief_description>
- Base class for all 3D shape resources.
- </brief_description>
- <description>
- Base class for all 3D shape resources. Nodes that inherit from this can be used as shapes for a [PhysicsBody] or [Area] objects.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
- The collision margin for the shape.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
new file mode 100644
index 0000000000..1af6550dc5
--- /dev/null
+++ b/doc/classes/Shape3D.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Shape3D" inherits="Resource" version="4.0">
+ <brief_description>
+ Base class for all 3D shape resources.
+ </brief_description>
+ <description>
+ Base class for all 3D shape resources. Nodes that inherit from this can be used as shapes for a [PhysicsBody3D] or [Area3D] objects.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
+ The collision margin for the shape.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml
index 350ab40c0e..1a05c02b60 100644
--- a/doc/classes/Signal.xml
+++ b/doc/classes/Signal.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Signal" version="4.0">
<brief_description>
+ Class representing a signal defined in an object.
</brief_description>
<description>
</description>
@@ -15,6 +16,7 @@
<argument index="1" name="signal_name" type="StringName">
</argument>
<description>
+ Creates a new signal named [code]signal_name[/code] in the given object.
</description>
</method>
<method name="connect">
@@ -27,44 +29,51 @@
<argument index="2" name="flags" type="int" default="0">
</argument>
<description>
+ Connects this signal to the specified [Callable], optionally providing binds and connection flags.
</description>
</method>
<method name="disconnect">
- <return type="void">
+ <return type="Variant">
</return>
<argument index="0" name="callable" type="Callable">
</argument>
<description>
+ Disconnects this signal from the specified [Callable].
</description>
</method>
<method name="emit" qualifiers="vararg">
<return type="void">
</return>
<description>
+ Emits this signal to all connected objects.
</description>
</method>
<method name="get_connections">
<return type="Array">
</return>
<description>
+ Returns the list of [Callable]s connected to this signal.
</description>
</method>
<method name="get_name">
<return type="StringName">
</return>
<description>
+ Returns the name of this signal.
</description>
</method>
<method name="get_object">
<return type="Object">
</return>
<description>
+ Returns the object emitting this signal.
</description>
</method>
<method name="get_object_id">
<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">
@@ -73,6 +82,7 @@
<argument index="0" name="callable" type="Callable">
</argument>
<description>
+ Returns [code]true[/code] if the specified [Callable] is connected to this signal.
</description>
</method>
<method name="is_null">
diff --git a/doc/classes/Skeleton.xml b/doc/classes/Skeleton.xml
deleted file mode 100644
index eaab4063b8..0000000000
--- a/doc/classes/Skeleton.xml
+++ /dev/null
@@ -1,269 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Skeleton" inherits="Spatial" version="4.0">
- <brief_description>
- Skeleton for characters and animated objects.
- </brief_description>
- <description>
- Skeleton provides a hierarchical interface for managing bones, including pose, rest and animation (see [Animation]). It can also use ragdoll physics.
- The overall transform of a bone with respect to the skeleton is determined by the following hierarchical order: rest pose, custom pose and pose.
- Note that "global pose" below refers to the overall transform of the bone with respect to skeleton, so it not the actual global/world transform of the bone.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_bone">
- <return type="void">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Adds a bone, with name [code]name[/code]. [method get_bone_count] will become the bone index.
- </description>
- </method>
- <method name="bind_child_node_to_bone">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="node" type="Node">
- </argument>
- <description>
- [i]Deprecated soon.[/i]
- </description>
- </method>
- <method name="clear_bones">
- <return type="void">
- </return>
- <description>
- Clear all the bones in this skeleton.
- </description>
- </method>
- <method name="find_bone" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Returns the bone index that matches [code]name[/code] as its name.
- </description>
- </method>
- <method name="get_bone_count" qualifiers="const">
- <return type="int">
- </return>
- <description>
- Returns the amount of bones in the skeleton.
- </description>
- </method>
- <method name="get_bone_custom_pose" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Returns the custom pose of the specified bone. Custom pose is applied on top of the rest pose.
- </description>
- </method>
- <method name="get_bone_global_pose" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Returns the overall transform of the specified bone, with respect to the skeleton. Being relative to the skeleton frame, this is not the actual "global" transform of the bone.
- </description>
- </method>
- <method name="get_bone_name" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Returns the name of the bone at index [code]index[/code].
- </description>
- </method>
- <method name="get_bone_parent" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Returns the bone index which is the parent of the bone at [code]bone_idx[/code]. If -1, then bone has no parent.
- [b]Note:[/b] The parent bone returned will always be less than [code]bone_idx[/code].
- </description>
- </method>
- <method name="get_bone_pose" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Returns the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose.
- </description>
- </method>
- <method name="get_bone_rest" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Returns the rest transform for a bone [code]bone_idx[/code].
- </description>
- </method>
- <method name="get_bound_child_nodes_to_bone" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- [i]Deprecated soon.[/i]
- </description>
- </method>
- <method name="is_bone_rest_disabled" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="localize_rests">
- <return type="void">
- </return>
- <description>
- </description>
- </method>
- <method name="physical_bones_add_collision_exception">
- <return type="void">
- </return>
- <argument index="0" name="exception" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="physical_bones_remove_collision_exception">
- <return type="void">
- </return>
- <argument index="0" name="exception" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="physical_bones_start_simulation">
- <return type="void">
- </return>
- <argument index="0" name="bones" type="Array" default="[ ]">
- </argument>
- <description>
- </description>
- </method>
- <method name="physical_bones_stop_simulation">
- <return type="void">
- </return>
- <description>
- </description>
- </method>
- <method name="register_skin">
- <return type="SkinReference">
- </return>
- <argument index="0" name="skin" type="Skin">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_custom_pose">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="custom_pose" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_disable_rest">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="disable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_global_pose_override">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="pose" type="Transform">
- </argument>
- <argument index="2" name="amount" type="float">
- </argument>
- <argument index="3" name="persistent" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_parent">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="parent_idx" type="int">
- </argument>
- <description>
- Sets the bone index [code]parent_idx[/code] as the parent of the bone at [code]bone_idx[/code]. If -1, then bone has no parent.
- [b]Note:[/b] [code]parent_idx[/code] must be less than [code]bone_idx[/code].
- </description>
- </method>
- <method name="set_bone_pose">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="pose" type="Transform">
- </argument>
- <description>
- Returns the pose transform for bone [code]bone_idx[/code].
- </description>
- </method>
- <method name="set_bone_rest">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="rest" type="Transform">
- </argument>
- <description>
- Sets the rest transform for bone [code]bone_idx[/code].
- </description>
- </method>
- <method name="unbind_child_node_from_bone">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="node" type="Node">
- </argument>
- <description>
- [i]Deprecated soon.[/i]
- </description>
- </method>
- <method name="unparent_bone_and_rest">
- <return type="void">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true">
- </member>
- </members>
- <constants>
- <constant name="NOTIFICATION_UPDATE_SKELETON" value="50">
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
new file mode 100644
index 0000000000..08404fb467
--- /dev/null
+++ b/doc/classes/Skeleton3D.xml
@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Skeleton3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Skeleton for characters and animated objects.
+ </brief_description>
+ <description>
+ Skeleton3D provides a hierarchical interface for managing bones, including pose, rest and animation (see [Animation]). It can also use ragdoll physics.
+ The overall transform of a bone with respect to the skeleton is determined by the following hierarchical order: rest pose, custom pose and pose.
+ Note that "global pose" below refers to the overall transform of the bone with respect to skeleton, so it not the actual global/world transform of the bone.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_bone">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ Adds a bone, with name [code]name[/code]. [method get_bone_count] will become the bone index.
+ </description>
+ </method>
+ <method name="bind_child_node_to_bone">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="node" type="Node">
+ </argument>
+ <description>
+ [i]Deprecated soon.[/i]
+ </description>
+ </method>
+ <method name="clear_bones">
+ <return type="void">
+ </return>
+ <description>
+ Clear all the bones in this skeleton.
+ </description>
+ </method>
+ <method name="clear_bones_global_pose_override">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="find_bone" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ Returns the bone index that matches [code]name[/code] as its name.
+ </description>
+ </method>
+ <method name="get_bone_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the amount of bones in the skeleton.
+ </description>
+ </method>
+ <method name="get_bone_custom_pose" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the custom pose of the specified bone. Custom pose is applied on top of the rest pose.
+ </description>
+ </method>
+ <method name="get_bone_global_pose" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the overall transform of the specified bone, with respect to the skeleton. Being relative to the skeleton frame, this is not the actual "global" transform of the bone.
+ </description>
+ </method>
+ <method name="get_bone_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the name of the bone at index [code]index[/code].
+ </description>
+ </method>
+ <method name="get_bone_parent" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the bone index which is the parent of the bone at [code]bone_idx[/code]. If -1, then bone has no parent.
+ [b]Note:[/b] The parent bone returned will always be less than [code]bone_idx[/code].
+ </description>
+ </method>
+ <method name="get_bone_pose" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose.
+ </description>
+ </method>
+ <method name="get_bone_rest" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ Returns the rest transform for a bone [code]bone_idx[/code].
+ </description>
+ </method>
+ <method name="get_bound_child_nodes_to_bone" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ [i]Deprecated soon.[/i]
+ </description>
+ </method>
+ <method name="is_bone_rest_disabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="localize_rests">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="physical_bones_add_collision_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="exception" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="physical_bones_remove_collision_exception">
+ <return type="void">
+ </return>
+ <argument index="0" name="exception" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="physical_bones_start_simulation">
+ <return type="void">
+ </return>
+ <argument index="0" name="bones" type="Array" default="[ ]">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="physical_bones_stop_simulation">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="register_skin">
+ <return type="SkinReference">
+ </return>
+ <argument index="0" name="skin" type="Skin">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_bone_custom_pose">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="custom_pose" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_bone_disable_rest">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="disable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_bone_global_pose_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="pose" type="Transform">
+ </argument>
+ <argument index="2" name="amount" type="float">
+ </argument>
+ <argument index="3" name="persistent" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_bone_parent">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="parent_idx" type="int">
+ </argument>
+ <description>
+ Sets the bone index [code]parent_idx[/code] as the parent of the bone at [code]bone_idx[/code]. If -1, then bone has no parent.
+ [b]Note:[/b] [code]parent_idx[/code] must be less than [code]bone_idx[/code].
+ </description>
+ </method>
+ <method name="set_bone_pose">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="pose" type="Transform">
+ </argument>
+ <description>
+ Returns the pose transform for bone [code]bone_idx[/code].
+ </description>
+ </method>
+ <method name="set_bone_rest">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="rest" type="Transform">
+ </argument>
+ <description>
+ Sets the rest transform for bone [code]bone_idx[/code].
+ </description>
+ </method>
+ <method name="unbind_child_node_from_bone">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="node" type="Node">
+ </argument>
+ <description>
+ [i]Deprecated soon.[/i]
+ </description>
+ </method>
+ <method name="unparent_bone_and_rest">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true">
+ </member>
+ </members>
+ <constants>
+ <constant name="NOTIFICATION_UPDATE_SKELETON" value="50">
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/SkeletonIK.xml b/doc/classes/SkeletonIK.xml
deleted file mode 100644
index 1db78314d2..0000000000
--- a/doc/classes/SkeletonIK.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonIK" inherits="Node" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_parent_skeleton" qualifiers="const">
- <return type="Skeleton">
- </return>
- <description>
- </description>
- </method>
- <method name="is_running">
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="start">
- <return type="void">
- </return>
- <argument index="0" name="one_time" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop">
- <return type="void">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="interpolation" type="float" setter="set_interpolation" getter="get_interpolation" default="1.0">
- </member>
- <member name="magnet" type="Vector3" setter="set_magnet_position" getter="get_magnet_position" default="Vector3( 0, 0, 0 )">
- </member>
- <member name="max_iterations" type="int" setter="set_max_iterations" getter="get_max_iterations" default="10">
- </member>
- <member name="min_distance" type="float" setter="set_min_distance" getter="get_min_distance" default="0.01">
- </member>
- <member name="override_tip_basis" type="bool" setter="set_override_tip_basis" getter="is_override_tip_basis" default="true">
- </member>
- <member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="@&quot;&quot;">
- </member>
- <member name="target" type="Transform" setter="set_target_transform" getter="get_target_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- </member>
- <member name="target_node" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- </member>
- <member name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="@&quot;&quot;">
- </member>
- <member name="use_magnet" type="bool" setter="set_use_magnet" getter="is_using_magnet" default="false">
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml
new file mode 100644
index 0000000000..de83847403
--- /dev/null
+++ b/doc/classes/SkeletonIK3D.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SkeletonIK3D" inherits="Node" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_parent_skeleton" qualifiers="const">
+ <return type="Skeleton3D">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_running">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="start">
+ <return type="void">
+ </return>
+ <argument index="0" name="one_time" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="stop">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="interpolation" type="float" setter="set_interpolation" getter="get_interpolation" default="1.0">
+ </member>
+ <member name="magnet" type="Vector3" setter="set_magnet_position" getter="get_magnet_position" default="Vector3( 0, 0, 0 )">
+ </member>
+ <member name="max_iterations" type="int" setter="set_max_iterations" getter="get_max_iterations" default="10">
+ </member>
+ <member name="min_distance" type="float" setter="set_min_distance" getter="get_min_distance" default="0.01">
+ </member>
+ <member name="override_tip_basis" type="bool" setter="set_override_tip_basis" getter="is_override_tip_basis" default="true">
+ </member>
+ <member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="@&quot;&quot;">
+ </member>
+ <member name="target" type="Transform" setter="set_target_transform" getter="get_target_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
+ </member>
+ <member name="target_node" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ </member>
+ <member name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="@&quot;&quot;">
+ </member>
+ <member name="use_magnet" type="bool" setter="set_use_magnet" getter="is_using_magnet" default="false">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Sky.xml b/doc/classes/Sky.xml
index ba9c5ee661..f574f42431 100644
--- a/doc/classes/Sky.xml
+++ b/doc/classes/Sky.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Sky" inherits="Resource" version="4.0">
<brief_description>
- The base class for [PanoramaSky] and [ProceduralSky].
+ Background that uses a [Material] to draw a sky.
</brief_description>
<description>
- The base class for [PanoramaSky] and [ProceduralSky].
+ The [Sky] class uses a [Material] to draw the background and update the reflection/radiance cubemaps.
</description>
<tutorials>
</tutorials>
@@ -14,11 +14,14 @@
<member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Sky.ProcessMode" default="0">
Sets the method for generating the radiance map from the sky. The radiance map is a cubemap with increasingly blurry versions of the sky corresponding to different levels of roughness. Radiance maps can be expensive to calculate. See [enum ProcessMode] for options.
</member>
- <member name="radiance_size" type="int" setter="set_radiance_size" getter="get_radiance_size" enum="Sky.RadianceSize" default="2">
+ <member name="radiance_size" type="int" setter="set_radiance_size" getter="get_radiance_size" enum="Sky.RadianceSize" default="3">
The [Sky]'s radiance map size. The higher the radiance map size, the more detailed the lighting from the [Sky] will be.
See [enum RadianceSize] constants for values.
[b]Note:[/b] Some hardware will have trouble with higher radiance sizes, especially [constant RADIANCE_SIZE_512] and above. Only use such high values on high-end hardware.
</member>
+ <member name="sky_material" type="Material" setter="set_material" getter="get_material">
+ [Material] used to draw the background. Can be [PanoramaSkyMaterial], [ProceduralSkyMaterial], [PhysicalSkyMaterial], or even a [ShaderMaterial] if you want to use your own custom shader.
+ </member>
</members>
<constants>
<constant name="RADIANCE_SIZE_32" value="0" enum="RadianceSize">
@@ -50,7 +53,7 @@
</constant>
<constant name="PROCESS_MODE_REALTIME" value="1" enum="ProcessMode">
Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times.
- [b]Note:[/b] The fast filtering algorithm is limited to 128x128 cubemaps, so [member radiance_size] must be set to [constant RADIANCE_SIZE_128].
+ [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>
</class>
diff --git a/doc/classes/SliderJoint.xml b/doc/classes/SliderJoint.xml
deleted file mode 100644
index dc0cf96eb4..0000000000
--- a/doc/classes/SliderJoint.xml
+++ /dev/null
@@ -1,173 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SliderJoint" inherits="Joint" version="4.0">
- <brief_description>
- Piston kind of slider between two bodies in 3D.
- </brief_description>
- <description>
- Slides across the X axis of the pivot object.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_param" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="param" type="int" enum="SliderJoint.Param">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_param">
- <return type="void">
- </return>
- <argument index="0" name="param" type="int" enum="SliderJoint.Param">
- </argument>
- <argument index="1" name="value" type="float">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="angular_limit/damping" type="float" setter="set_param" getter="get_param" default="0.0">
- The amount of damping of the rotation when the limit is surpassed.
- A lower damping value allows a rotation initiated by body A to travel to body B slower.
- </member>
- <member name="angular_limit/lower_angle" type="float" setter="_set_lower_limit_angular" getter="_get_lower_limit_angular" default="0.0">
- The lower limit of rotation in the slider.
- </member>
- <member name="angular_limit/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
- The amount of restitution of the rotation when the limit is surpassed.
- Does not affect damping.
- </member>
- <member name="angular_limit/softness" type="float" setter="set_param" getter="get_param" default="1.0">
- A factor applied to the all rotation once the limit is surpassed.
- Makes all rotation slower when between 0 and 1.
- </member>
- <member name="angular_limit/upper_angle" type="float" setter="_set_upper_limit_angular" getter="_get_upper_limit_angular" default="0.0">
- The upper limit of rotation in the slider.
- </member>
- <member name="angular_motion/damping" type="float" setter="set_param" getter="get_param" default="1.0">
- The amount of damping of the rotation in the limits.
- </member>
- <member name="angular_motion/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
- The amount of restitution of the rotation in the limits.
- </member>
- <member name="angular_motion/softness" type="float" setter="set_param" getter="get_param" default="1.0">
- A factor applied to the all rotation in the limits.
- </member>
- <member name="angular_ortho/damping" type="float" setter="set_param" getter="get_param" default="1.0">
- The amount of damping of the rotation across axes orthogonal to the slider.
- </member>
- <member name="angular_ortho/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
- The amount of restitution of the rotation across axes orthogonal to the slider.
- </member>
- <member name="angular_ortho/softness" type="float" setter="set_param" getter="get_param" default="1.0">
- A factor applied to the all rotation across axes orthogonal to the slider.
- </member>
- <member name="linear_limit/damping" type="float" setter="set_param" getter="get_param" default="1.0">
- The amount of damping that happens once the limit defined by [member linear_limit/lower_distance] and [member linear_limit/upper_distance] is surpassed.
- </member>
- <member name="linear_limit/lower_distance" type="float" setter="set_param" getter="get_param" default="-1.0">
- The minimum difference between the pivot points on their X axis before damping happens.
- </member>
- <member name="linear_limit/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
- The amount of restitution once the limits are surpassed. The lower, the more velocity-energy gets lost.
- </member>
- <member name="linear_limit/softness" type="float" setter="set_param" getter="get_param" default="1.0">
- A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
- </member>
- <member name="linear_limit/upper_distance" type="float" setter="set_param" getter="get_param" default="1.0">
- The maximum difference between the pivot points on their X axis before damping happens.
- </member>
- <member name="linear_motion/damping" type="float" setter="set_param" getter="get_param" default="0.0">
- The amount of damping inside the slider limits.
- </member>
- <member name="linear_motion/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
- The amount of restitution inside the slider limits.
- </member>
- <member name="linear_motion/softness" type="float" setter="set_param" getter="get_param" default="1.0">
- A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
- </member>
- <member name="linear_ortho/damping" type="float" setter="set_param" getter="get_param" default="1.0">
- The amount of damping when movement is across axes orthogonal to the slider.
- </member>
- <member name="linear_ortho/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
- The amount of restitution when movement is across axes orthogonal to the slider.
- </member>
- <member name="linear_ortho/softness" type="float" setter="set_param" getter="get_param" default="1.0">
- A factor applied to the movement across axes orthogonal to the slider.
- </member>
- </members>
- <constants>
- <constant name="PARAM_LINEAR_LIMIT_UPPER" value="0" enum="Param">
- The maximum difference between the pivot points on their X axis before damping happens.
- </constant>
- <constant name="PARAM_LINEAR_LIMIT_LOWER" value="1" enum="Param">
- The minimum difference between the pivot points on their X axis before damping happens.
- </constant>
- <constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2" enum="Param">
- A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
- </constant>
- <constant name="PARAM_LINEAR_LIMIT_RESTITUTION" value="3" enum="Param">
- The amount of restitution once the limits are surpassed. The lower, the more velocityenergy gets lost.
- </constant>
- <constant name="PARAM_LINEAR_LIMIT_DAMPING" value="4" enum="Param">
- The amount of damping once the slider limits are surpassed.
- </constant>
- <constant name="PARAM_LINEAR_MOTION_SOFTNESS" value="5" enum="Param">
- A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
- </constant>
- <constant name="PARAM_LINEAR_MOTION_RESTITUTION" value="6" enum="Param">
- The amount of restitution inside the slider limits.
- </constant>
- <constant name="PARAM_LINEAR_MOTION_DAMPING" value="7" enum="Param">
- The amount of damping inside the slider limits.
- </constant>
- <constant name="PARAM_LINEAR_ORTHOGONAL_SOFTNESS" value="8" enum="Param">
- A factor applied to the movement across axes orthogonal to the slider.
- </constant>
- <constant name="PARAM_LINEAR_ORTHOGONAL_RESTITUTION" value="9" enum="Param">
- The amount of restitution when movement is across axes orthogonal to the slider.
- </constant>
- <constant name="PARAM_LINEAR_ORTHOGONAL_DAMPING" value="10" enum="Param">
- The amount of damping when movement is across axes orthogonal to the slider.
- </constant>
- <constant name="PARAM_ANGULAR_LIMIT_UPPER" value="11" enum="Param">
- The upper limit of rotation in the slider.
- </constant>
- <constant name="PARAM_ANGULAR_LIMIT_LOWER" value="12" enum="Param">
- The lower limit of rotation in the slider.
- </constant>
- <constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="13" enum="Param">
- A factor applied to the all rotation once the limit is surpassed.
- </constant>
- <constant name="PARAM_ANGULAR_LIMIT_RESTITUTION" value="14" enum="Param">
- The amount of restitution of the rotation when the limit is surpassed.
- </constant>
- <constant name="PARAM_ANGULAR_LIMIT_DAMPING" value="15" enum="Param">
- The amount of damping of the rotation when the limit is surpassed.
- </constant>
- <constant name="PARAM_ANGULAR_MOTION_SOFTNESS" value="16" enum="Param">
- A factor applied to the all rotation in the limits.
- </constant>
- <constant name="PARAM_ANGULAR_MOTION_RESTITUTION" value="17" enum="Param">
- The amount of restitution of the rotation in the limits.
- </constant>
- <constant name="PARAM_ANGULAR_MOTION_DAMPING" value="18" enum="Param">
- The amount of damping of the rotation in the limits.
- </constant>
- <constant name="PARAM_ANGULAR_ORTHOGONAL_SOFTNESS" value="19" enum="Param">
- A factor applied to the all rotation across axes orthogonal to the slider.
- </constant>
- <constant name="PARAM_ANGULAR_ORTHOGONAL_RESTITUTION" value="20" enum="Param">
- The amount of restitution of the rotation across axes orthogonal to the slider.
- </constant>
- <constant name="PARAM_ANGULAR_ORTHOGONAL_DAMPING" value="21" enum="Param">
- The amount of damping of the rotation across axes orthogonal to the slider.
- </constant>
- <constant name="PARAM_MAX" value="22" enum="Param">
- Represents the size of the [enum Param] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/SliderJoint3D.xml b/doc/classes/SliderJoint3D.xml
new file mode 100644
index 0000000000..efd6353e3c
--- /dev/null
+++ b/doc/classes/SliderJoint3D.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SliderJoint3D" inherits="Joint3D" version="4.0">
+ <brief_description>
+ Piston kind of slider between two bodies in 3D.
+ </brief_description>
+ <description>
+ Slides across the X axis of the pivot object.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_param" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="param" type="int" enum="SliderJoint3D.Param">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_param">
+ <return type="void">
+ </return>
+ <argument index="0" name="param" type="int" enum="SliderJoint3D.Param">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="angular_limit/damping" type="float" setter="set_param" getter="get_param" default="0.0">
+ The amount of damping of the rotation when the limit is surpassed.
+ A lower damping value allows a rotation initiated by body A to travel to body B slower.
+ </member>
+ <member name="angular_limit/lower_angle" type="float" setter="_set_lower_limit_angular" getter="_get_lower_limit_angular" default="0.0">
+ The lower limit of rotation in the slider.
+ </member>
+ <member name="angular_limit/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
+ The amount of restitution of the rotation when the limit is surpassed.
+ Does not affect damping.
+ </member>
+ <member name="angular_limit/softness" type="float" setter="set_param" getter="get_param" default="1.0">
+ A factor applied to the all rotation once the limit is surpassed.
+ Makes all rotation slower when between 0 and 1.
+ </member>
+ <member name="angular_limit/upper_angle" type="float" setter="_set_upper_limit_angular" getter="_get_upper_limit_angular" default="0.0">
+ The upper limit of rotation in the slider.
+ </member>
+ <member name="angular_motion/damping" type="float" setter="set_param" getter="get_param" default="1.0">
+ The amount of damping of the rotation in the limits.
+ </member>
+ <member name="angular_motion/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
+ The amount of restitution of the rotation in the limits.
+ </member>
+ <member name="angular_motion/softness" type="float" setter="set_param" getter="get_param" default="1.0">
+ A factor applied to the all rotation in the limits.
+ </member>
+ <member name="angular_ortho/damping" type="float" setter="set_param" getter="get_param" default="1.0">
+ The amount of damping of the rotation across axes orthogonal to the slider.
+ </member>
+ <member name="angular_ortho/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
+ The amount of restitution of the rotation across axes orthogonal to the slider.
+ </member>
+ <member name="angular_ortho/softness" type="float" setter="set_param" getter="get_param" default="1.0">
+ A factor applied to the all rotation across axes orthogonal to the slider.
+ </member>
+ <member name="linear_limit/damping" type="float" setter="set_param" getter="get_param" default="1.0">
+ The amount of damping that happens once the limit defined by [member linear_limit/lower_distance] and [member linear_limit/upper_distance] is surpassed.
+ </member>
+ <member name="linear_limit/lower_distance" type="float" setter="set_param" getter="get_param" default="-1.0">
+ The minimum difference between the pivot points on their X axis before damping happens.
+ </member>
+ <member name="linear_limit/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
+ The amount of restitution once the limits are surpassed. The lower, the more velocity-energy gets lost.
+ </member>
+ <member name="linear_limit/softness" type="float" setter="set_param" getter="get_param" default="1.0">
+ A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
+ </member>
+ <member name="linear_limit/upper_distance" type="float" setter="set_param" getter="get_param" default="1.0">
+ The maximum difference between the pivot points on their X axis before damping happens.
+ </member>
+ <member name="linear_motion/damping" type="float" setter="set_param" getter="get_param" default="0.0">
+ The amount of damping inside the slider limits.
+ </member>
+ <member name="linear_motion/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
+ The amount of restitution inside the slider limits.
+ </member>
+ <member name="linear_motion/softness" type="float" setter="set_param" getter="get_param" default="1.0">
+ A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
+ </member>
+ <member name="linear_ortho/damping" type="float" setter="set_param" getter="get_param" default="1.0">
+ The amount of damping when movement is across axes orthogonal to the slider.
+ </member>
+ <member name="linear_ortho/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
+ The amount of restitution when movement is across axes orthogonal to the slider.
+ </member>
+ <member name="linear_ortho/softness" type="float" setter="set_param" getter="get_param" default="1.0">
+ A factor applied to the movement across axes orthogonal to the slider.
+ </member>
+ </members>
+ <constants>
+ <constant name="PARAM_LINEAR_LIMIT_UPPER" value="0" enum="Param">
+ The maximum difference between the pivot points on their X axis before damping happens.
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_LOWER" value="1" enum="Param">
+ The minimum difference between the pivot points on their X axis before damping happens.
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_SOFTNESS" value="2" enum="Param">
+ A factor applied to the movement across the slider axis once the limits get surpassed. The lower, the slower the movement.
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_RESTITUTION" value="3" enum="Param">
+ The amount of restitution once the limits are surpassed. The lower, the more velocityenergy gets lost.
+ </constant>
+ <constant name="PARAM_LINEAR_LIMIT_DAMPING" value="4" enum="Param">
+ The amount of damping once the slider limits are surpassed.
+ </constant>
+ <constant name="PARAM_LINEAR_MOTION_SOFTNESS" value="5" enum="Param">
+ A factor applied to the movement across the slider axis as long as the slider is in the limits. The lower, the slower the movement.
+ </constant>
+ <constant name="PARAM_LINEAR_MOTION_RESTITUTION" value="6" enum="Param">
+ The amount of restitution inside the slider limits.
+ </constant>
+ <constant name="PARAM_LINEAR_MOTION_DAMPING" value="7" enum="Param">
+ The amount of damping inside the slider limits.
+ </constant>
+ <constant name="PARAM_LINEAR_ORTHOGONAL_SOFTNESS" value="8" enum="Param">
+ A factor applied to the movement across axes orthogonal to the slider.
+ </constant>
+ <constant name="PARAM_LINEAR_ORTHOGONAL_RESTITUTION" value="9" enum="Param">
+ The amount of restitution when movement is across axes orthogonal to the slider.
+ </constant>
+ <constant name="PARAM_LINEAR_ORTHOGONAL_DAMPING" value="10" enum="Param">
+ The amount of damping when movement is across axes orthogonal to the slider.
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_UPPER" value="11" enum="Param">
+ The upper limit of rotation in the slider.
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_LOWER" value="12" enum="Param">
+ The lower limit of rotation in the slider.
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_SOFTNESS" value="13" enum="Param">
+ A factor applied to the all rotation once the limit is surpassed.
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_RESTITUTION" value="14" enum="Param">
+ The amount of restitution of the rotation when the limit is surpassed.
+ </constant>
+ <constant name="PARAM_ANGULAR_LIMIT_DAMPING" value="15" enum="Param">
+ The amount of damping of the rotation when the limit is surpassed.
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTION_SOFTNESS" value="16" enum="Param">
+ A factor applied to the all rotation in the limits.
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTION_RESTITUTION" value="17" enum="Param">
+ The amount of restitution of the rotation in the limits.
+ </constant>
+ <constant name="PARAM_ANGULAR_MOTION_DAMPING" value="18" enum="Param">
+ The amount of damping of the rotation in the limits.
+ </constant>
+ <constant name="PARAM_ANGULAR_ORTHOGONAL_SOFTNESS" value="19" enum="Param">
+ A factor applied to the all rotation across axes orthogonal to the slider.
+ </constant>
+ <constant name="PARAM_ANGULAR_ORTHOGONAL_RESTITUTION" value="20" enum="Param">
+ The amount of restitution of the rotation across axes orthogonal to the slider.
+ </constant>
+ <constant name="PARAM_ANGULAR_ORTHOGONAL_DAMPING" value="21" enum="Param">
+ The amount of damping of the rotation across axes orthogonal to the slider.
+ </constant>
+ <constant name="PARAM_MAX" value="22" enum="Param">
+ Represents the size of the [enum Param] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/SoftBody.xml b/doc/classes/SoftBody.xml
deleted file mode 100644
index 46a00fbd67..0000000000
--- a/doc/classes/SoftBody.xml
+++ /dev/null
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SoftBody" inherits="MeshInstance" version="4.0">
- <brief_description>
- A soft mesh physics body.
- </brief_description>
- <description>
- A deformable physics body. Used to create elastic or deformable objects such as cloth, rubber, or other flexible materials.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html</link>
- </tutorials>
- <methods>
- <method name="add_collision_exception_with">
- <return type="void">
- </return>
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- Adds a body to the list of bodies that this body can't collide with.
- </description>
- </method>
- <method name="get_collision_exceptions">
- <return type="Array">
- </return>
- <description>
- 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 collision 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="remove_collision_exception_with">
- <return type="void">
- </return>
- <argument index="0" name="body" type="Node">
- </argument>
- <description>
- 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 layer mask. 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 collision mask. Use this if you only need to change one layer's value.
- </description>
- </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 SoftBody 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.
- 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.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this SoftBody scans for collisions.
- </member>
- <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01">
- </member>
- <member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0">
- </member>
- <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5">
- </member>
- <member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore" default="NodePath(&quot;&quot;)">
- [NodePath] to a [CollisionObject] this SoftBody should avoid clipping.
- </member>
- <member name="pose_matching_coefficient" type="float" setter="set_pose_matching_coefficient" getter="get_pose_matching_coefficient" default="0.0">
- </member>
- <member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient" default="0.0">
- </member>
- <member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
- If [code]true[/code], the [SoftBody] will respond to [RayCast]s.
- </member>
- <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="5">
- Increasing this value will improve the resulting simulation, but can affect performance. Use with care.
- </member>
- <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="1.0">
- The SoftBody's mass.
- </member>
- <member name="volume_stiffness" type="float" setter="set_volume_stiffness" getter="get_volume_stiffness" default="0.5">
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
new file mode 100644
index 0000000000..24d6609900
--- /dev/null
+++ b/doc/classes/SoftBody3D.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SoftBody3D" inherits="MeshInstance3D" version="4.0">
+ <brief_description>
+ A soft mesh physics body.
+ </brief_description>
+ <description>
+ A deformable physics body. Used to create elastic or deformable objects such as cloth, rubber, or other flexible materials.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html</link>
+ </tutorials>
+ <methods>
+ <method name="add_collision_exception_with">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ Adds a body to the list of bodies that this body can't collide with.
+ </description>
+ </method>
+ <method name="get_collision_exceptions">
+ <return type="Array">
+ </return>
+ <description>
+ 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 collision 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="remove_collision_exception_with">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="Node">
+ </argument>
+ <description>
+ 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 layer mask. 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 collision mask. Use this if you only need to change one layer's value.
+ </description>
+ </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.
+ 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.
+ </member>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The physics layers this SoftBody3D scans for collisions.
+ </member>
+ <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01">
+ </member>
+ <member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0">
+ </member>
+ <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5">
+ </member>
+ <member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore" default="NodePath(&quot;&quot;)">
+ [NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping.
+ </member>
+ <member name="pose_matching_coefficient" type="float" setter="set_pose_matching_coefficient" getter="get_pose_matching_coefficient" default="0.0">
+ </member>
+ <member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient" default="0.0">
+ </member>
+ <member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
+ If [code]true[/code], the [SoftBody3D] will respond to [RayCast3D]s.
+ </member>
+ <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="5">
+ Increasing this value will improve the resulting simulation, but can affect performance. Use with care.
+ </member>
+ <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="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>
+</class>
diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml
deleted file mode 100644
index d057db8519..0000000000
--- a/doc/classes/Spatial.xml
+++ /dev/null
@@ -1,350 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Spatial" inherits="Node" version="4.0">
- <brief_description>
- Most basic 3D game object, parent of all 3D-related nodes.
- </brief_description>
- <description>
- Most basic 3D game object, with a 3D [Transform] and visibility settings. All other 3D game objects inherit from Spatial. Use [Spatial] as a parent node to move, scale, rotate and show/hide children in a 3D project.
- Affine operations (rotate, scale, translate) happen in parent's local coordinate system, unless the [Spatial] object is set as top-level. Affine operations in this coordinate system correspond to direct affine operations on the [Spatial]'s transform. The word local below refers to this coordinate system. The coordinate system that is attached to the [Spatial] object itself is referred to as object-local coordinate system.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html</link>
- </tutorials>
- <methods>
- <method name="force_update_transform">
- <return type="void">
- </return>
- <description>
- Forces the transform to update. Transform changes in physics are not instant for performance reasons. Transforms are accumulated and then set. Use this if you need an up-to-date transform when doing physics operations.
- </description>
- </method>
- <method name="get_parent_spatial" qualifiers="const">
- <return type="Spatial">
- </return>
- <description>
- Returns the parent [Spatial], or an empty [Object] if no parent exists or parent is not of type [Spatial].
- </description>
- </method>
- <method name="get_world" qualifiers="const">
- <return type="World">
- </return>
- <description>
- Returns the current [World] resource this [Spatial] node is registered to.
- </description>
- </method>
- <method name="global_rotate">
- <return type="void">
- </return>
- <argument index="0" name="axis" type="Vector3">
- </argument>
- <argument index="1" name="angle" type="float">
- </argument>
- <description>
- Rotates the global (world) transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in global coordinate system.
- </description>
- </method>
- <method name="global_scale">
- <return type="void">
- </return>
- <argument index="0" name="scale" type="Vector3">
- </argument>
- <description>
- Scales the global (world) transformation by the given [Vector3] scale factors.
- </description>
- </method>
- <method name="global_translate">
- <return type="void">
- </return>
- <argument index="0" name="offset" type="Vector3">
- </argument>
- <description>
- Moves the global (world) transformation by [Vector3] offset. The offset is in global coordinate system.
- </description>
- </method>
- <method name="hide">
- <return type="void">
- </return>
- <description>
- Disables rendering of this node. Changes [member visible] to [code]false[/code].
- </description>
- </method>
- <method name="is_local_transform_notification_enabled" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns whether node notifies about its local transformation changes. [Spatial] will not propagate this by default.
- </description>
- </method>
- <method name="is_scale_disabled" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns whether this node uses a scale of [code](1, 1, 1)[/code] or its local transformation scale.
- </description>
- </method>
- <method name="is_set_as_toplevel" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns whether this node is set as Toplevel, that is whether it ignores its parent nodes transformations.
- </description>
- </method>
- <method name="is_transform_notification_enabled" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns whether the node notifies about its global and local transformation changes. [Spatial] will not propagate this by default.
- </description>
- </method>
- <method name="is_visible_in_tree" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns whether the node is visible, taking into consideration that its parents visibility.
- </description>
- </method>
- <method name="look_at">
- <return type="void">
- </return>
- <argument index="0" name="target" type="Vector3">
- </argument>
- <argument index="1" name="up" type="Vector3">
- </argument>
- <description>
- Rotates itself so that the local -Z axis points towards the [code]target[/code] position.
- The transform will first be rotated around the given [code]up[/code] vector, and then fully aligned to the target by a further rotation around an axis perpendicular to both the [code]target[/code] and [code]up[/code] vectors.
- Operations take place in global space.
- </description>
- </method>
- <method name="look_at_from_position">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <argument index="1" name="target" type="Vector3">
- </argument>
- <argument index="2" name="up" type="Vector3">
- </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.
- </description>
- </method>
- <method name="orthonormalize">
- <return type="void">
- </return>
- <description>
- Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform].
- </description>
- </method>
- <method name="rotate">
- <return type="void">
- </return>
- <argument index="0" name="axis" type="Vector3">
- </argument>
- <argument index="1" name="angle" type="float">
- </argument>
- <description>
- Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians.
- </description>
- </method>
- <method name="rotate_object_local">
- <return type="void">
- </return>
- <argument index="0" name="axis" type="Vector3">
- </argument>
- <argument index="1" name="angle" type="float">
- </argument>
- <description>
- Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in object-local coordinate system.
- </description>
- </method>
- <method name="rotate_x">
- <return type="void">
- </return>
- <argument index="0" name="angle" type="float">
- </argument>
- <description>
- Rotates the local transformation around the X axis by angle in radians.
- </description>
- </method>
- <method name="rotate_y">
- <return type="void">
- </return>
- <argument index="0" name="angle" type="float">
- </argument>
- <description>
- Rotates the local transformation around the Y axis by angle in radians.
- </description>
- </method>
- <method name="rotate_z">
- <return type="void">
- </return>
- <argument index="0" name="angle" type="float">
- </argument>
- <description>
- Rotates the local transformation around the Z axis by angle in radians.
- </description>
- </method>
- <method name="scale_object_local">
- <return type="void">
- </return>
- <argument index="0" name="scale" type="Vector3">
- </argument>
- <description>
- Scales the local transformation by given 3D scale factors in object-local coordinate system.
- </description>
- </method>
- <method name="set_as_toplevel">
- <return type="void">
- </return>
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Makes the node ignore its parents transformations. Node transformations are only in global space.
- </description>
- </method>
- <method name="set_disable_scale">
- <return type="void">
- </return>
- <argument index="0" name="disable" type="bool">
- </argument>
- <description>
- Sets whether the node uses a scale of [code](1, 1, 1)[/code] or its local transformation scale. Changes to the local transformation scale are preserved.
- </description>
- </method>
- <method name="set_identity">
- <return type="void">
- </return>
- <description>
- Reset all transformations for this node (sets its [Transform] to the identity matrix).
- </description>
- </method>
- <method name="set_ignore_transform_notification">
- <return type="void">
- </return>
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Sets whether the node ignores notification that its transformation (global or local) changed.
- </description>
- </method>
- <method name="set_notify_local_transform">
- <return type="void">
- </return>
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Sets whether the node notifies about its local transformation changes. [Spatial] will not propagate this by default.
- </description>
- </method>
- <method name="set_notify_transform">
- <return type="void">
- </return>
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Sets whether the node notifies about its global and local transformation changes. [Spatial] will not propagate this by default.
- </description>
- </method>
- <method name="show">
- <return type="void">
- </return>
- <description>
- Enables rendering of this node. Changes [member visible] to [code]true[/code].
- </description>
- </method>
- <method name="to_global" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="local_point" type="Vector3">
- </argument>
- <description>
- Transforms [code]local_point[/code] from this node's local space to world space.
- </description>
- </method>
- <method name="to_local" qualifiers="const">
- <return type="Vector3">
- </return>
- <argument index="0" name="global_point" type="Vector3">
- </argument>
- <description>
- Transforms [code]global_point[/code] from world space to this node's local space.
- </description>
- </method>
- <method name="translate">
- <return type="void">
- </return>
- <argument index="0" name="offset" type="Vector3">
- </argument>
- <description>
- Changes the node's position by the given offset [Vector3].
- Note that the translation [code]offset[/code] is affected by the node's scale, so if scaled by e.g. [code](10, 1, 1)[/code], a translation by an offset of [code](2, 0, 0)[/code] would actually add 20 ([code]2 * 10[/code]) to the X coordinate.
- </description>
- </method>
- <method name="translate_object_local">
- <return type="void">
- </return>
- <argument index="0" name="offset" type="Vector3">
- </argument>
- <description>
- Changes the node's position by the given offset [Vector3] in local space.
- </description>
- </method>
- <method name="update_gizmo">
- <return type="void">
- </return>
- <description>
- Updates the [SpatialGizmo] of this node.
- </description>
- </method>
- </methods>
- <members>
- <member name="gizmo" type="SpatialGizmo" setter="set_gizmo" getter="get_gizmo">
- The [SpatialGizmo] for this node. Used for example in [EditorSpatialGizmo] as custom visualization and editing handles in Editor.
- </member>
- <member name="global_transform" type="Transform" setter="set_global_transform" getter="get_global_transform">
- World space (global) [Transform] of this node.
- </member>
- <member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation">
- Rotation part of the local transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle).
- [b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful.
- </member>
- <member name="rotation_degrees" type="Vector3" setter="set_rotation_degrees" getter="get_rotation_degrees" default="Vector3( 0, 0, 0 )">
- Rotation part of the local transformation in degrees, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle).
- </member>
- <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3( 1, 1, 1 )">
- Scale part of the local transformation.
- </member>
- <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
- Local space [Transform] of this node, with respect to the parent node.
- </member>
- <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3( 0, 0, 0 )">
- Local translation of this node.
- </member>
- <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
- If [code]true[/code], this node is drawn.
- </member>
- </members>
- <signals>
- <signal name="visibility_changed">
- <description>
- Emitted when node visibility changes.
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="2000">
- Spatial nodes receives this notification when their global transform changes. This means that either the current or a parent node changed its transform.
- In order for [constant NOTIFICATION_TRANSFORM_CHANGED] to work, users first need to ask for it, with [method set_notify_transform].
- </constant>
- <constant name="NOTIFICATION_ENTER_WORLD" value="41">
- Spatial nodes receives this notification when they are registered to new [World] resource.
- </constant>
- <constant name="NOTIFICATION_EXIT_WORLD" value="42">
- Spatial nodes receives this notification when they are unregistered from current [World] resource.
- </constant>
- <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="43">
- Spatial nodes receives this notification when their visibility changes.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/SpatialGizmo.xml b/doc/classes/SpatialGizmo.xml
deleted file mode 100644
index 5260eaa8a3..0000000000
--- a/doc/classes/SpatialGizmo.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpatialGizmo" inherits="Reference" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SpatialVelocityTracker.xml b/doc/classes/SpatialVelocityTracker.xml
deleted file mode 100644
index 7a4e0c054a..0000000000
--- a/doc/classes/SpatialVelocityTracker.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpatialVelocityTracker" inherits="Reference" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_tracked_linear_velocity" qualifiers="const">
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="reset">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="update_position">
- <return type="void">
- </return>
- <argument index="0" name="position" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="track_physics_step" type="bool" setter="set_track_physics_step" getter="is_tracking_physics_step" default="false">
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SphereShape.xml b/doc/classes/SphereShape.xml
deleted file mode 100644
index 75dab58c38..0000000000
--- a/doc/classes/SphereShape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SphereShape" inherits="Shape" version="4.0">
- <brief_description>
- Sphere shape for 3D collisions.
- </brief_description>
- <description>
- Sphere shape for 3D collisions, which can be set into a [PhysicsBody] or [Area]. This shape is useful for modeling sphere-like 3D objects.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- The sphere's radius. The shape's diameter is double the radius.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SphereShape3D.xml b/doc/classes/SphereShape3D.xml
new file mode 100644
index 0000000000..1eaf890639
--- /dev/null
+++ b/doc/classes/SphereShape3D.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SphereShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Sphere shape for 3D collisions.
+ </brief_description>
+ <description>
+ Sphere shape for 3D collisions, which can be set into a [PhysicsBody3D] or [Area3D]. This shape is useful for modeling sphere-like 3D objects.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ The sphere's radius. The shape's diameter is double the radius.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SpotLight.xml b/doc/classes/SpotLight.xml
deleted file mode 100644
index 351d4f8aff..0000000000
--- a/doc/classes/SpotLight.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpotLight" inherits="Light" version="4.0">
- <brief_description>
- A spotlight, such as a reflector spotlight or a lantern.
- </brief_description>
- <description>
- A Spotlight is a type of [Light] node that emits lights in a specific direction, in the shape of a cone. The light is attenuated through the distance. This attenuation can be configured by changing the energy, radius and attenuation parameters of [Light].
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="spot_angle" type="float" setter="set_param" getter="get_param" default="45.0">
- The spotlight's angle in degrees.
- </member>
- <member name="spot_angle_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
- The spotlight's angular attenuation curve.
- </member>
- <member name="spot_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
- The spotlight's light energy attenuation curve.
- </member>
- <member name="spot_range" type="float" setter="set_param" getter="get_param" default="5.0">
- The maximal range that can be reached by the spotlight.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SpotLight3D.xml b/doc/classes/SpotLight3D.xml
new file mode 100644
index 0000000000..f094818c21
--- /dev/null
+++ b/doc/classes/SpotLight3D.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SpotLight3D" inherits="Light3D" version="4.0">
+ <brief_description>
+ A spotlight, such as a reflector spotlight or a lantern.
+ </brief_description>
+ <description>
+ A Spotlight is a type of [Light3D] node that emits lights in a specific direction, in the shape of a cone. The light is attenuated through the distance. This attenuation can be configured by changing the energy, radius and attenuation parameters of [Light3D].
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="spot_angle" type="float" setter="set_param" getter="get_param" default="45.0">
+ The spotlight's angle in degrees.
+ </member>
+ <member name="spot_angle_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
+ The spotlight's angular attenuation curve.
+ </member>
+ <member name="spot_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
+ The spotlight's light energy attenuation curve.
+ </member>
+ <member name="spot_range" type="float" setter="set_param" getter="get_param" default="5.0">
+ The maximal range that can be reached by the spotlight.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/SpringArm.xml b/doc/classes/SpringArm.xml
deleted file mode 100644
index 780ed5077d..0000000000
--- a/doc/classes/SpringArm.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpringArm" inherits="Spatial" version="4.0">
- <brief_description>
- A helper node, mostly used in 3rd person cameras.
- </brief_description>
- <description>
- The SpringArm node is a node that casts a ray (or collision shape) along its z axis and moves all its direct children to the collision point, minus a margin.
- The most common use case for this is to make a 3rd person camera that reacts to collisions in the environment.
- The SpringArm will either cast a ray, or if a shape is given, it will cast the shape in the direction of its z axis.
- If you use the SpringArm as a camera controller for your player, you might need to exclude the player's collider from the SpringArm's collision check.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_excluded_object">
- <return type="void">
- </return>
- <argument index="0" name="RID" type="RID">
- </argument>
- <description>
- Adds the [PhysicsBody] object with the given [RID] to the list of [PhysicsBody] objects excluded from the collision check.
- </description>
- </method>
- <method name="clear_excluded_objects">
- <return type="void">
- </return>
- <description>
- Clears the list of [PhysicsBody] objects excluded from the collision check.
- </description>
- </method>
- <method name="get_hit_length">
- <return type="float">
- </return>
- <description>
- Returns the proportion between the current arm length (after checking for collisions) and the [member spring_length]. Ranges from 0 to 1.
- </description>
- </method>
- <method name="remove_excluded_object">
- <return type="bool">
- </return>
- <argument index="0" name="RID" type="RID">
- </argument>
- <description>
- Removes the given [RID] from the list of [PhysicsBody] objects excluded from the collision check.
- </description>
- </method>
- </methods>
- <members>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The layers against which the collision check shall be done.
- </member>
- <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.01">
- When the collision check is made, a candidate length for the SpringArm is given.
- The margin is then subtracted to this length and the translation is applied to the child objects of the SpringArm.
- This margin is useful for when the SpringArm has a [Camera] as a child node: without the margin, the [Camera] would be placed on the exact point of collision, while with the margin the [Camera] would be placed close to the point of collision.
- </member>
- <member name="shape" type="Shape" setter="set_shape" getter="get_shape">
- The [Shape] to use for the SpringArm.
- When the shape is set, the SpringArm will cast the [Shape] on its z axis instead of performing a ray cast.
- </member>
- <member name="spring_length" type="float" setter="set_length" getter="get_length" default="1.0">
- The maximum extent of the SpringArm. This is used as a length for both the ray and the shape cast used internally to calculate the desired position of the SpringArm's child nodes.
- To know more about how to perform a shape cast or a ray cast, please consult the [PhysicsDirectSpaceState] documentation.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/SpringArm3D.xml b/doc/classes/SpringArm3D.xml
new file mode 100644
index 0000000000..8305494c2b
--- /dev/null
+++ b/doc/classes/SpringArm3D.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SpringArm3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ A helper node, mostly used in 3rd person cameras.
+ </brief_description>
+ <description>
+ The SpringArm3D node is a node that casts a ray (or collision shape) along its z axis and moves all its direct children to the collision point, minus a margin.
+ The most common use case for this is to make a 3rd person camera that reacts to collisions in the environment.
+ The SpringArm3D will either cast a ray, or if a shape is given, it will cast the shape in the direction of its z axis.
+ If you use the SpringArm3D as a camera controller for your player, you might need to exclude the player's collider from the SpringArm3D's collision check.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_excluded_object">
+ <return type="void">
+ </return>
+ <argument index="0" name="RID" type="RID">
+ </argument>
+ <description>
+ Adds the [PhysicsBody3D] object with the given [RID] to the list of [PhysicsBody3D] objects excluded from the collision check.
+ </description>
+ </method>
+ <method name="clear_excluded_objects">
+ <return type="void">
+ </return>
+ <description>
+ Clears the list of [PhysicsBody3D] objects excluded from the collision check.
+ </description>
+ </method>
+ <method name="get_hit_length">
+ <return type="float">
+ </return>
+ <description>
+ Returns the proportion between the current arm length (after checking for collisions) and the [member spring_length]. Ranges from 0 to 1.
+ </description>
+ </method>
+ <method name="remove_excluded_object">
+ <return type="bool">
+ </return>
+ <argument index="0" name="RID" type="RID">
+ </argument>
+ <description>
+ Removes the given [RID] from the list of [PhysicsBody3D] objects excluded from the collision check.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The layers against which the collision check shall be done.
+ </member>
+ <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.01">
+ When the collision check is made, a candidate length for the SpringArm3D is given.
+ The margin is then subtracted to this length and the translation is applied to the child objects of the SpringArm3D.
+ This margin is useful for when the SpringArm3D has a [Camera3D] as a child node: without the margin, the [Camera3D] would be placed on the exact point of collision, while with the margin the [Camera3D] would be placed close to the point of collision.
+ </member>
+ <member name="shape" type="Shape3D" setter="set_shape" getter="get_shape">
+ The [Shape3D] to use for the SpringArm3D.
+ When the shape is set, the SpringArm3D will cast the [Shape3D] on its z axis instead of performing a ray cast.
+ </member>
+ <member name="spring_length" type="float" setter="set_length" getter="get_length" default="1.0">
+ The maximum extent of the SpringArm3D. This is used as a length for both the ray and the shape cast used internally to calculate the desired position of the SpringArm3D's child nodes.
+ To know more about how to perform a shape cast or a ray cast, please consult the [PhysicsDirectSpaceState3D] documentation.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Sprite.xml b/doc/classes/Sprite.xml
deleted file mode 100644
index 89cdae1dff..0000000000
--- a/doc/classes/Sprite.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Sprite" inherits="Node2D" version="4.0">
- <brief_description>
- General-purpose sprite node.
- </brief_description>
- <description>
- A node that displays a 2D texture. The texture displayed can be a region from a larger atlas texture, or a frame from a sprite sheet animation.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_rect" qualifiers="const">
- <return type="Rect2">
- </return>
- <description>
- Returns a [Rect2] representing the Sprite's boundary in local coordinates. Can be used to detect if the Sprite was clicked. Example:
- [codeblock]
- func _input(event):
- if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
- if get_rect().has_point(to_local(event.position)):
- print("A click!")
- [/codeblock]
- </description>
- </method>
- <method name="is_pixel_opaque" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- Returns [code]true[/code], if the pixel at the given position is opaque and [code]false[/code] in other case.
- [b]Note:[/b] It also returns [code]false[/code], if the sprite's texture is [code]null[/code] or if the given position is invalid.
- </description>
- </method>
- </methods>
- <members>
- <member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true">
- If [code]true[/code], texture is centered.
- </member>
- <member name="flip_h" type="bool" setter="set_flip_h" getter="is_flipped_h" default="false">
- If [code]true[/code], texture is flipped horizontally.
- </member>
- <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v" default="false">
- If [code]true[/code], texture is flipped vertically.
- </member>
- <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
- Current frame to display from sprite sheet. [member vframes] or [member hframes] must be greater than 1.
- </member>
- <member name="frame_coords" type="Vector2" setter="set_frame_coords" getter="get_frame_coords" default="Vector2( 0, 0 )">
- Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member vframes] or [member hframes] must be greater than 1.
- </member>
- <member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
- The number of columns in the sprite sheet.
- </member>
- <member name="normal_map" type="Texture2D" setter="set_normal_map" getter="get_normal_map">
- The normal map gives depth to the Sprite.
- </member>
- <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">
- 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>
- <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].
- </member>
- <member name="shininess" type="float" setter="set_shininess" getter="get_shininess" default="1.0">
- </member>
- <member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color( 1, 1, 1, 1 )">
- </member>
- <member name="specular_map" type="Texture2D" setter="set_specular_map" getter="get_specular_map">
- </member>
- <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
- [Texture2D] object to draw.
- </member>
- <member name="vframes" type="int" setter="set_vframes" getter="get_vframes" default="1">
- The number of rows in the sprite sheet.
- </member>
- </members>
- <signals>
- <signal name="frame_changed">
- <description>
- Emitted when the [member frame] changes.
- </description>
- </signal>
- <signal name="texture_changed">
- <description>
- Emitted when the [member texture] changes.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
new file mode 100644
index 0000000000..950fda4e20
--- /dev/null
+++ b/doc/classes/Sprite2D.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Sprite2D" inherits="Node2D" version="4.0">
+ <brief_description>
+ General-purpose sprite node.
+ </brief_description>
+ <description>
+ A node that displays a 2D texture. The texture displayed can be a region from a larger atlas texture, or a frame from a sprite sheet animation.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_rect" qualifiers="const">
+ <return type="Rect2">
+ </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]
+ func _input(event):
+ if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
+ if get_rect().has_point(to_local(event.position)):
+ print("A click!")
+ [/codeblock]
+ </description>
+ </method>
+ <method name="is_pixel_opaque" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="pos" type="Vector2">
+ </argument>
+ <description>
+ Returns [code]true[/code], if the pixel at the given position is opaque and [code]false[/code] in other case.
+ [b]Note:[/b] It also returns [code]false[/code], if the sprite's texture is [code]null[/code] or if the given position is invalid.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true">
+ If [code]true[/code], texture is centered.
+ </member>
+ <member name="flip_h" type="bool" setter="set_flip_h" getter="is_flipped_h" default="false">
+ If [code]true[/code], texture is flipped horizontally.
+ </member>
+ <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v" default="false">
+ If [code]true[/code], texture is flipped vertically.
+ </member>
+ <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
+ Current frame to display from sprite sheet. [member vframes] or [member hframes] must be greater than 1.
+ </member>
+ <member name="frame_coords" type="Vector2" setter="set_frame_coords" getter="get_frame_coords" default="Vector2( 0, 0 )">
+ Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member vframes] or [member hframes] must be greater than 1.
+ </member>
+ <member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
+ The number of columns in the sprite sheet.
+ </member>
+ <member name="normal_map" type="Texture2D" setter="set_normal_map" getter="get_normal_map">
+ The normal map gives depth to the Sprite2D.
+ </member>
+ <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">
+ 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>
+ <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].
+ </member>
+ <member name="shininess" type="float" setter="set_shininess" getter="get_shininess" default="1.0">
+ Strength of the specular light effect of this [Sprite2D].
+ </member>
+ <member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color( 1, 1, 1, 1 )">
+ The color of the specular light effect.
+ </member>
+ <member name="specular_map" type="Texture2D" setter="set_specular_map" getter="get_specular_map">
+ The specular map is used for more control on the shininess effect.
+ </member>
+ <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ [Texture2D] object to draw.
+ </member>
+ <member name="vframes" type="int" setter="set_vframes" getter="get_vframes" default="1">
+ The number of rows in the sprite sheet.
+ </member>
+ </members>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ Emitted when the [member frame] changes.
+ </description>
+ </signal>
+ <signal name="texture_changed">
+ <description>
+ Emitted when the [member texture] changes.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index 63958eeb7b..f59d5130c9 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
A node that displays a 2D texture in a 3D environment. The texture displayed can be a region from a larger atlas texture, or a frame from a sprite sheet animation.
- [b]Note:[/b] There are [url=https://github.com/godotengine/godot/issues/20855]known performance issues[/url] when using [Sprite3D]. Consider using a [MeshInstance] with a [QuadMesh] as the mesh instead. You can still have billboarding by enabling billboard properties in the QuadMesh's [StandardMaterial3D].
+ [b]Note:[/b] There are [url=https://github.com/godotengine/godot/issues/20855]known performance issues[/url] when using [Sprite3D]. Consider using a [MeshInstance3D] with a [QuadMesh] as the mesh instead. You can still have billboarding by enabling billboard properties in the QuadMesh's [StandardMaterial3D].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml
index aaea4178fb..479dc5f94c 100644
--- a/doc/classes/SpriteBase3D.xml
+++ b/doc/classes/SpriteBase3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SpriteBase3D" inherits="GeometryInstance" version="4.0">
+<class name="SpriteBase3D" inherits="GeometryInstance3D" version="4.0">
<brief_description>
2D sprite node in 3D environment.
</brief_description>
@@ -21,12 +21,14 @@
<argument index="0" name="flag" type="int" enum="SpriteBase3D.DrawFlags">
</argument>
<description>
+ Returns the value of the specified flag.
</description>
</method>
<method name="get_item_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
+ Returns the rectangle representing this sprite.
</description>
</method>
<method name="set_draw_flag">
@@ -37,6 +39,7 @@
<argument index="1" name="enabled" type="bool">
</argument>
<description>
+ If [code]true[/code], the specified flag will be enabled.
</description>
</method>
</methods>
@@ -73,7 +76,7 @@
The size of one pixel's width on the sprite to scale it in 3D.
</member>
<member name="shaded" type="bool" setter="set_draw_flag" getter="get_draw_flag" default="false">
- If [code]true[/code], the [Light] in the [Environment] has effects on the sprite.
+ If [code]true[/code], the [Light3D] in the [Environment] has effects on the sprite.
</member>
<member name="transparent" type="bool" setter="set_draw_flag" getter="get_draw_flag" default="true">
If [code]true[/code], the texture's transparency and the opacity are used to make those parts of the sprite invisible.
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 9facdde681..6e1e1688f4 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpriteFrames" inherits="Resource" version="4.0">
<brief_description>
- Sprite frame library for AnimatedSprite.
+ Sprite frame library for AnimatedSprite2D.
</brief_description>
<description>
- Sprite frame library for [AnimatedSprite]. Contains frames and animation data for playback.
+ Sprite frame library for [AnimatedSprite2D]. Contains frames and animation data for playback.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/StaticBody.xml b/doc/classes/StaticBody.xml
deleted file mode 100644
index 280b95d182..0000000000
--- a/doc/classes/StaticBody.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StaticBody" inherits="PhysicsBody" version="4.0">
- <brief_description>
- Static body for 3D physics.
- </brief_description>
- <description>
- Static body for 3D physics. A static body is a simple body that is not intended to move. In contrast to [RigidBody], they don't consume any CPU resources as long as they don't move.
- Additionally, a constant linear or angular velocity can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels).
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="constant_angular_velocity" type="Vector3" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="Vector3( 0, 0, 0 )">
- The body's constant angular velocity. This does not rotate the body, but affects other bodies that touch it, as if it was in a state of rotation.
- </member>
- <member name="constant_linear_velocity" type="Vector3" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector3( 0, 0, 0 )">
- The body's constant linear velocity. This does not move the body, but affects other bodies that touch it, as if it was in a state of movement.
- </member>
- <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
- The physics material override for the body.
- If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml
new file mode 100644
index 0000000000..c896efc314
--- /dev/null
+++ b/doc/classes/StaticBody3D.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="StaticBody3D" inherits="PhysicsBody3D" version="4.0">
+ <brief_description>
+ Static body for 3D physics.
+ </brief_description>
+ <description>
+ Static body for 3D physics. A static body is a simple body that is not intended to move. In contrast to [RigidBody3D], they don't consume any CPU resources as long as they don't move.
+ Additionally, a constant linear or angular velocity can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels).
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="constant_angular_velocity" type="Vector3" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="Vector3( 0, 0, 0 )">
+ The body's constant angular velocity. This does not rotate the body, but affects other bodies that touch it, as if it was in a state of rotation.
+ </member>
+ <member name="constant_linear_velocity" type="Vector3" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector3( 0, 0, 0 )">
+ The body's constant linear velocity. This does not move the body, but affects other bodies that touch it, as if it was in a state of movement.
+ </member>
+ <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
+ The physics material override for the body.
+ If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml
index 738d623d02..69e8f67a5e 100644
--- a/doc/classes/StreamPeerSSL.xml
+++ b/doc/classes/StreamPeerSSL.xml
@@ -72,11 +72,13 @@
A status representing a [StreamPeerSSL] that is disconnected.
</constant>
<constant name="STATUS_HANDSHAKING" value="1" enum="Status">
+ A status representing a [StreamPeerSSL] during handshaking.
</constant>
<constant name="STATUS_CONNECTED" value="2" enum="Status">
A status representing a [StreamPeerSSL] that is connected to a host.
</constant>
<constant name="STATUS_ERROR" value="3" enum="Status">
+ A status representing a [StreamPeerSSL] in error state.
</constant>
<constant name="STATUS_ERROR_HOSTNAME_MISMATCH" value="4" enum="Status">
An error status that shows a mismatch in the SSL certificate domain presented by the host and the domain requested for validation.
diff --git a/doc/classes/StreamTexture.xml b/doc/classes/StreamTexture.xml
index a2d26d3d14..03afcb5b0d 100644
--- a/doc/classes/StreamTexture.xml
+++ b/doc/classes/StreamTexture.xml
@@ -15,6 +15,7 @@
<argument index="0" name="path" type="String">
</argument>
<description>
+ Loads the texture from the given path.
</description>
</method>
</methods>
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index f323a4bb6a..5d8ac6fdcc 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="StringName" version="4.0">
<brief_description>
+ 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.
</description>
<tutorials>
</tutorials>
@@ -13,6 +15,7 @@
<argument index="0" name="from" type="String">
</argument>
<description>
+ Creates a new [StringName] from the given [String].
</description>
</method>
</methods>
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
new file mode 100644
index 0000000000..e877050bf8
--- /dev/null
+++ b/doc/classes/SubViewport.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SubViewport" inherits="Viewport" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <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>
+ <member name="render_target_clear_mode" type="int" setter="set_clear_mode" getter="get_clear_mode" enum="SubViewport.ClearMode" default="0">
+ The clear mode when the sub-viewport is used as a render target.
+ </member>
+ <member name="render_target_update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="SubViewport.UpdateMode" default="2">
+ The update mode when the sub-viewport is used as a render target.
+ </member>
+ <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i( 0, 0 )">
+ The width and height of the sub-viewport.
+ </member>
+ <member name="size_2d_override" type="Vector2i" setter="set_size_2d_override" getter="get_size_2d_override" default="Vector2i( 0, 0 )">
+ The 2D size override of the sub-viewport. If either the width or height is [code]0[/code], the override is disabled.
+ </member>
+ <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>
+ </members>
+ <constants>
+ <constant name="UPDATE_DISABLED" value="0" enum="UpdateMode">
+ Do not update the render target.
+ </constant>
+ <constant name="UPDATE_ONCE" value="1" enum="UpdateMode">
+ Update the render target once, then switch to [constant UPDATE_DISABLED].
+ </constant>
+ <constant name="UPDATE_WHEN_VISIBLE" value="2" enum="UpdateMode">
+ Update the render target only when it is visible. This is the default value.
+ </constant>
+ <constant name="UPDATE_WHEN_PARENT_VISIBLE" value="3" enum="UpdateMode">
+ Update the render target only when the its parent is visible.
+ </constant>
+ <constant name="UPDATE_ALWAYS" value="4" enum="UpdateMode">
+ Always update the render target.
+ </constant>
+ <constant name="CLEAR_MODE_ALWAYS" value="0" enum="ClearMode">
+ Always clear the render target before drawing.
+ </constant>
+ <constant name="CLEAR_MODE_NEVER" value="1" enum="ClearMode">
+ Never clear the render target.
+ </constant>
+ <constant name="CLEAR_MODE_ONLY_NEXT_FRAME" value="2" enum="ClearMode">
+ Clear the render target next frame, then switch to [constant CLEAR_MODE_NEVER].
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml
new file mode 100644
index 0000000000..e6a0bd4866
--- /dev/null
+++ b/doc/classes/SubViewportContainer.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="SubViewportContainer" inherits="Container" version="4.0">
+ <brief_description>
+ Control for holding [SubViewport]s.
+ </brief_description>
+ <description>
+ A [Container] node that holds a [SubViewport], automatically setting its size.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled" default="false">
+ If [code]true[/code], the sub-viewport will be scaled to the control's size.
+ </member>
+ <member name="stretch_shrink" type="int" setter="set_stretch_shrink" getter="get_stretch_shrink" default="1">
+ Divides the sub-viewport's effective resolution by this value while preserving its scale. This can be used to speed up rendering.
+ For example, a 1280×720 sub-viewport with [member stretch_shrink] set to [code]2[/code] will be rendered at 640×360 while occupying the same size in the container.
+ [b]Note:[/b] [member stretch] must be [code]true[/code] for this property to work.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index 3c4fd4c41a..22e92ae5d9 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -36,10 +36,10 @@
<method name="get_tab_control" qualifiers="const">
<return type="Control">
</return>
- <argument index="0" name="idx" type="int">
+ <argument index="0" name="tab_idx" type="int">
</argument>
<description>
- Returns the currently visible tab's [Control] node.
+ Returns the [Control] node from the tab at index [code]tab_idx[/code].
</description>
</method>
<method name="get_tab_count" qualifiers="const">
@@ -187,36 +187,52 @@
</constants>
<theme_items>
<theme_item name="decrement" type="Texture2D">
+ Icon for the left arrow button that appears when there are too many tabs to fit in the container width. When the button is disabled (i.e. the first tab is visible), it appears semi-transparent.
</theme_item>
<theme_item name="decrement_highlight" type="Texture2D">
+ Icon for the left 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="font" type="Font">
+ The font used to draw tab names.
</theme_item>
<theme_item name="font_color_bg" type="Color" default="Color( 0.69, 0.69, 0.69, 1 )">
+ Font color of inactive tabs.
</theme_item>
<theme_item name="font_color_disabled" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )">
+ Font color of disabled tabs.
</theme_item>
<theme_item name="font_color_fg" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
+ Font color of the currently selected tab.
</theme_item>
<theme_item name="hseparation" type="int" default="4">
+ Horizontal separation between tabs.
</theme_item>
<theme_item name="increment" type="Texture2D">
+ Icon for the right arrow button that appears when there are too many tabs to fit in the container width. When the button is disabled (i.e. the last tab is visible) it appears semi-transparent.
</theme_item>
<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="menu" type="Texture2D">
+ The icon for the menu button (see [method set_popup]).
</theme_item>
<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="panel" type="StyleBox">
+ The style for the background fill.
</theme_item>
<theme_item name="side_margin" type="int" default="8">
+ The space at the left and right edges of the tab bar.
</theme_item>
<theme_item name="tab_bg" type="StyleBox">
+ The style of inactive tabs.
</theme_item>
<theme_item name="tab_disabled" type="StyleBox">
+ The style of disabled tabs.
</theme_item>
<theme_item name="tab_fg" type="StyleBox">
+ The style of the currently selected tab.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml
index 8f31b24131..3fc1db9dc6 100644
--- a/doc/classes/Tabs.xml
+++ b/doc/classes/Tabs.xml
@@ -262,36 +262,51 @@
</constants>
<theme_items>
<theme_item name="button" type="StyleBox">
+ Background of the close button when it's being hovered with the cursor.
</theme_item>
<theme_item name="button_pressed" type="StyleBox">
+ Background of the close button when it's being pressed.
</theme_item>
<theme_item name="close" type="Texture2D">
+ The icon for the close button (see [member tab_close_display_policy]).
</theme_item>
<theme_item name="decrement" type="Texture2D">
+ Icon for the left arrow button that appears when there are too many tabs to fit in the container width. When the button is disabled (i.e. the first tab is visible), it appears semi-transparent.
</theme_item>
<theme_item name="decrement_highlight" type="Texture2D">
+ Icon for the left 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="font" type="Font">
+ The font used to draw tab names.
</theme_item>
<theme_item name="font_color_bg" type="Color" default="Color( 0.69, 0.69, 0.69, 1 )">
+ Font color of inactive tabs.
</theme_item>
<theme_item name="font_color_disabled" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )">
+ Font color of disabled tabs.
</theme_item>
<theme_item name="font_color_fg" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
+ Font color of the currently selected tab.
</theme_item>
<theme_item name="hseparation" type="int" default="4">
+ The horizontal separation between the tabs.
</theme_item>
<theme_item name="increment" type="Texture2D">
+ Icon for the right arrow button that appears when there are too many tabs to fit in the container width. When the button is disabled (i.e. the last tab is visible) it appears semi-transparent.
</theme_item>
<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>
<theme_item name="tab_bg" type="StyleBox">
+ The style of an inactive tab.
</theme_item>
<theme_item name="tab_disabled" type="StyleBox">
+ The style of a disabled tab
</theme_item>
<theme_item name="tab_fg" type="StyleBox">
+ The style of the currently selected tab.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index d4eeb574eb..b515b27b31 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -502,6 +502,12 @@
<description>
</description>
</signal>
+ <signal name="symbol_validate">
+ <argument index="0" name="symbol" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="text_changed">
<description>
Emitted when the text changes.
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 63cdb0d90a..ffe806cef7 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -4,7 +4,7 @@
Texture for 2D and 3D.
</brief_description>
<description>
- A texture works by registering an image in the video hardware, which then can be used in 3D models or 2D [Sprite] or GUI [Control].
+ A texture works by registering an image in the video hardware, which then can be used in 3D models or 2D [Sprite2D] or GUI [Control].
Textures are often created by loading them from a file. See [method @GDScript.load].
[Texture2D] is a base for other resources. It cannot be used directly.
</description>
@@ -28,12 +28,12 @@
</argument>
<argument index="6" name="specular_color_shininess" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
- <argument index="7" name="texture_filter" type="int" enum="VisualServer.CanvasItemTextureFilter" default="0">
+ <argument index="7" name="texture_filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" default="0">
</argument>
- <argument index="8" name="texture_repeat" type="int" enum="VisualServer.CanvasItemTextureRepeat" default="0">
+ <argument index="8" name="texture_repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" default="0">
</argument>
<description>
- Draws the texture using a [CanvasItem] with the [VisualServer] API at the specified [code]position[/code].
+ Draws the texture using a [CanvasItem] with the [RenderingServer] API at the specified [code]position[/code].
</description>
</method>
<method name="draw_rect" qualifiers="const">
@@ -55,12 +55,12 @@
</argument>
<argument index="7" name="specular_color_shininess" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
- <argument index="8" name="texture_filter" type="int" enum="VisualServer.CanvasItemTextureFilter" default="0">
+ <argument index="8" name="texture_filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" default="0">
</argument>
- <argument index="9" name="texture_repeat" type="int" enum="VisualServer.CanvasItemTextureRepeat" default="0">
+ <argument index="9" name="texture_repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" default="0">
</argument>
<description>
- Draws the texture using a [CanvasItem] with the [VisualServer] API.
+ Draws the texture using a [CanvasItem] with the [RenderingServer] API.
</description>
</method>
<method name="draw_rect_region" qualifiers="const">
@@ -82,14 +82,14 @@
</argument>
<argument index="7" name="specular_color_shininess" type="Color" default="Color( 1, 1, 1, 1 )">
</argument>
- <argument index="8" name="texture_filter" type="int" enum="VisualServer.CanvasItemTextureFilter" default="0">
+ <argument index="8" name="texture_filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" default="0">
</argument>
- <argument index="9" name="texture_repeat" type="int" enum="VisualServer.CanvasItemTextureRepeat" default="0">
+ <argument index="9" name="texture_repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" default="0">
</argument>
<argument index="10" name="clip_uv" type="bool" default="true">
</argument>
<description>
- Draws a part of the texture using a [CanvasItem] with the [VisualServer] API.
+ Draws a part of the texture using a [CanvasItem] with the [RenderingServer] API.
</description>
</method>
<method name="get_data" qualifiers="const">
diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml
index 3bb5797df5..4d6e89fa6f 100644
--- a/doc/classes/Thread.xml
+++ b/doc/classes/Thread.xml
@@ -36,7 +36,7 @@
<argument index="3" name="priority" type="int" enum="Thread.Priority" default="1">
</argument>
<description>
- Starts a new [Thread] that runs [code]method[/code] on object [code]instance[/code] with [code]userdata[/code] passed as an argument. The [code]priority[/code] of the [Thread] can be changed by passing a value from the [enum Priority] enum.
+ Starts a new [Thread] that runs [code]method[/code] on object [code]instance[/code] with [code]userdata[/code] passed as an argument. Even if no userdata is passed, [code]method[/code] must accept one argument and it will be null. The [code]priority[/code] of the [Thread] can be changed by passing a value from the [enum Priority] enum.
Returns [constant OK] on success, or [constant ERR_CANT_CREATE] on failure.
</description>
</method>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 1db1142aa0..5b7694b775 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -43,7 +43,7 @@
<argument index="1" name="y" type="int">
</argument>
<description>
- Returns the coordinate of the autotile variation in the tileset. Returns a zero vector if the cell doesn't have autotiling.
+ Returns the coordinate (subtile column and row) of the autotile variation in the tileset. Returns a zero vector if the cell doesn't have autotiling.
</description>
</method>
<method name="get_cellv" qualifiers="const">
@@ -161,7 +161,7 @@
<description>
Sets the tile index for the cell given by a Vector2.
An index of [code]-1[/code] clears the cell.
- Optionally, the tile can also be flipped, transposed, or given autotile coordinates.
+ Optionally, the tile can also be flipped, transposed, or given autotile coordinates. The autotile coordinate refers to the column and row of the subtile.
[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:
diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml
index 72f9c5493a..e4d367c344 100644
--- a/doc/classes/Transform.xml
+++ b/doc/classes/Transform.xml
@@ -149,7 +149,7 @@
</description>
</method>
<method name="xform">
- <return type="void">
+ <return type="Variant">
</return>
<argument index="0" name="v" type="Variant">
</argument>
@@ -158,7 +158,7 @@
</description>
</method>
<method name="xform_inv">
- <return type="void">
+ <return type="Variant">
</return>
<argument index="0" name="v" type="Variant">
</argument>
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 164efd4e5e..af93d4c654 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -151,7 +151,7 @@
</description>
</method>
<method name="xform">
- <return type="void">
+ <return type="Variant">
</return>
<argument index="0" name="v" type="Variant">
</argument>
@@ -160,7 +160,7 @@
</description>
</method>
<method name="xform_inv">
- <return type="void">
+ <return type="Variant">
</return>
<argument index="0" name="v" type="Variant">
</argument>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index 5fa24100ae..b01ba3850f 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -313,6 +313,7 @@
</signal>
<signal name="item_custom_button_pressed">
<description>
+ Emitted when a custom button is pressed (i.e. in a [constant TreeItem.CELL_MODE_CUSTOM] mode cell).
</description>
</signal>
<signal name="item_double_clicked">
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index f498919f9e..84aa3a3686 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -23,8 +23,7 @@
<argument index="4" name="tooltip" type="String" default="&quot;&quot;">
</argument>
<description>
- Adds a button with [Texture2D] [code]button[/code] at column [code]column[/code]. The [code]button_idx[/code] index is used to identify the button when calling other methods. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately after this method. Optionally, the button can be [code]disabled[/code] and have a [code]tooltip
- [/code].
+ Adds a button with [Texture2D] [code]button[/code] at column [code]column[/code]. The [code]button_idx[/code] index is used to identify the button when calling other methods. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately after this method. Optionally, the button can be [code]disabled[/code] and have a [code]tooltip[/code].
</description>
</method>
<method name="call_recursive" qualifiers="vararg">
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 766ebf7e32..2cc3e974e2 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -155,7 +155,7 @@
Returns [code]true[/code] if an "undo" action is available.
</description>
</method>
- <method name="is_commiting_action" qualifiers="const">
+ <method name="is_committing_action" qualifiers="const">
<return type="bool">
</return>
<description>
diff --git a/doc/classes/VSeparator.xml b/doc/classes/VSeparator.xml
index 19e995b9bc..52f31b1da7 100644
--- a/doc/classes/VSeparator.xml
+++ b/doc/classes/VSeparator.xml
@@ -14,8 +14,10 @@
</constants>
<theme_items>
<theme_item name="separation" type="int" default="4">
+ The width of the area covered by the separator. Effectively works like a minimum width.
</theme_item>
<theme_item name="separator" type="StyleBox">
+ The style for the separator line. Works best with [StyleBoxLine] (remember to enable [member StyleBoxLine.vertical]).
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/VSlider.xml b/doc/classes/VSlider.xml
index cbc4ac1a13..3faafdfe80 100644
--- a/doc/classes/VSlider.xml
+++ b/doc/classes/VSlider.xml
@@ -18,16 +18,22 @@
</constants>
<theme_items>
<theme_item name="grabber" type="Texture2D">
+ The texture for the grabber (the draggable element).
</theme_item>
<theme_item name="grabber_area" type="StyleBox">
+ The background of the area below the grabber.
</theme_item>
<theme_item name="grabber_disabled" type="Texture2D">
+ The texture for the grabber when it's disabled.
</theme_item>
<theme_item name="grabber_highlight" type="Texture2D">
+ The texture for the grabber when it's focused.
</theme_item>
<theme_item name="slider" type="StyleBox">
+ The background for the whole slider. Determines the width of the [code]grabber_area[/code].
</theme_item>
<theme_item name="tick" type="Texture2D">
+ The texture for the ticks, visible when [member Slider.tick_count] is greater than 0.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/VSplitContainer.xml b/doc/classes/VSplitContainer.xml
index 0e659408d7..18b515e7ce 100644
--- a/doc/classes/VSplitContainer.xml
+++ b/doc/classes/VSplitContainer.xml
@@ -14,12 +14,15 @@
</constants>
<theme_items>
<theme_item name="autohide" type="int" default="1">
+ Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible.
</theme_item>
<theme_item name="bg" type="StyleBox">
</theme_item>
<theme_item name="grabber" type="Texture2D">
+ The icon used for the grabber drawn in the middle area.
</theme_item>
<theme_item name="separation" type="int" default="12">
+ The space between sides of the container.
</theme_item>
</theme_items>
</class>
diff --git a/doc/classes/VehicleBody.xml b/doc/classes/VehicleBody.xml
deleted file mode 100644
index 74879419a1..0000000000
--- a/doc/classes/VehicleBody.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VehicleBody" inherits="RigidBody" version="4.0">
- <brief_description>
- Physics body that simulates the behavior of a car.
- </brief_description>
- <description>
- This node implements all the physics logic needed to simulate a car. It is based on the raycast vehicle system commonly found in physics engines. You will need to add a [CollisionShape] for the main body of your vehicle and add [VehicleWheel] nodes for the wheels. You should also add a [MeshInstance] to this node for the 3D model of your car but this model should not include meshes for the wheels. You should control the vehicle by using the [member brake], [member engine_force], and [member steering] properties and not change the position or orientation of this node directly.
- [b]Note:[/b] The origin point of your VehicleBody will determine the center of gravity of your vehicle so it is better to keep this low and move the [CollisionShape] and [MeshInstance] upwards.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="brake" type="float" setter="set_brake" getter="get_brake" default="0.0">
- Slows down the vehicle by applying a braking force. The vehicle is only slowed down if the wheels are in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidBody.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
- </member>
- <member name="engine_force" type="float" setter="set_engine_force" getter="get_engine_force" default="0.0">
- Accelerates the vehicle by applying an engine force. The vehicle is only speed up if the wheels that have [member VehicleWheel.use_as_traction] set to [code]true[/code] and are in contact with a surface. The [member RigidBody.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
- [b]Note:[/b] The simulation does not take the effect of gears into account, you will need to add logic for this if you wish to simulate gears.
- A negative value will result in the vehicle reversing.
- </member>
- <member name="mass" type="float" setter="set_mass" getter="get_mass" override="true" default="40.0" />
- <member name="steering" type="float" setter="set_steering" getter="get_steering" default="0.0">
- The steering angle for the vehicle. Setting this to a non-zero value will result in the vehicle turning when it's moving. Wheels that have [member VehicleWheel.use_as_steering] set to [code]true[/code] will automatically be rotated.
- </member>
- <member name="weight" type="float" setter="set_weight" getter="get_weight" override="true" default="392.0" />
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/VehicleBody3D.xml b/doc/classes/VehicleBody3D.xml
new file mode 100644
index 0000000000..b8b85ff605
--- /dev/null
+++ b/doc/classes/VehicleBody3D.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VehicleBody3D" inherits="RigidBody3D" version="4.0">
+ <brief_description>
+ Physics body that simulates the behavior of a car.
+ </brief_description>
+ <description>
+ This node implements all the physics logic needed to simulate a car. It is based on the raycast vehicle system commonly found in physics engines. You will need to add a [CollisionShape3D] for the main body of your vehicle and add [VehicleWheel3D] nodes for the wheels. You should also add a [MeshInstance3D] to this node for the 3D model of your car but this model should not include meshes for the wheels. You should control the vehicle by using the [member brake], [member engine_force], and [member steering] properties and not change the position or orientation of this node directly.
+ [b]Note:[/b] The origin point of your VehicleBody3D will determine the center of gravity of your vehicle so it is better to keep this low and move the [CollisionShape3D] and [MeshInstance3D] upwards.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="brake" type="float" setter="set_brake" getter="get_brake" default="0.0">
+ Slows down the vehicle by applying a braking force. The vehicle is only slowed down if the wheels are in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
+ </member>
+ <member name="engine_force" type="float" setter="set_engine_force" getter="get_engine_force" default="0.0">
+ Accelerates the vehicle by applying an engine force. The vehicle is only speed up if the wheels that have [member VehicleWheel3D.use_as_traction] set to [code]true[/code] and are in contact with a surface. The [member RigidBody3D.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
+ [b]Note:[/b] The simulation does not take the effect of gears into account, you will need to add logic for this if you wish to simulate gears.
+ A negative value will result in the vehicle reversing.
+ </member>
+ <member name="mass" type="float" setter="set_mass" getter="get_mass" override="true" default="40.0" />
+ <member name="steering" type="float" setter="set_steering" getter="get_steering" default="0.0">
+ The steering angle for the vehicle. Setting this to a non-zero value will result in the vehicle turning when it's moving. Wheels that have [member VehicleWheel3D.use_as_steering] set to [code]true[/code] will automatically be rotated.
+ </member>
+ <member name="weight" type="float" setter="set_weight" getter="get_weight" override="true" default="392.0" />
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VehicleWheel.xml b/doc/classes/VehicleWheel.xml
deleted file mode 100644
index 1a6a226fd1..0000000000
--- a/doc/classes/VehicleWheel.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VehicleWheel" inherits="Spatial" version="4.0">
- <brief_description>
- Physics object that simulates the behavior of a wheel.
- </brief_description>
- <description>
- This node needs to be used as a child node of [VehicleBody] and simulates the behavior of one of its wheels. This node also acts as a collider to detect if the wheel is touching a surface.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_rpm" qualifiers="const">
- <return type="float">
- </return>
- <description>
- Returns the rotational speed of the wheel in revolutions per minute.
- </description>
- </method>
- <method name="get_skidinfo" qualifiers="const">
- <return type="float">
- </return>
- <description>
- Returns a value between 0.0 and 1.0 that indicates whether this wheel is skidding. 0.0 is skidding (the wheel has lost grip, e.g. icy terrain), 1.0 means not skidding (the wheel has full grip, e.g. dry asphalt road).
- </description>
- </method>
- <method name="is_in_contact" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if this wheel is in contact with a surface.
- </description>
- </method>
- </methods>
- <members>
- <member name="brake" type="float" setter="set_brake" getter="get_brake" default="0.0">
- Slows down the wheel by applying a braking force. The wheel is only slowed down if it is in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidBody.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
- </member>
- <member name="damping_compression" type="float" setter="set_damping_compression" getter="get_damping_compression" default="0.83">
- The damping applied to the spring when the spring is being compressed. This value should be between 0.0 (no damping) and 1.0. A value of 0.0 means the car will keep bouncing as the spring keeps its energy. A good value for this is around 0.3 for a normal car, 0.5 for a race car.
- </member>
- <member name="damping_relaxation" type="float" setter="set_damping_relaxation" getter="get_damping_relaxation" default="0.88">
- The damping applied to the spring when relaxing. This value should be between 0.0 (no damping) and 1.0. This value should always be slightly higher than the [member damping_compression] property. For a [member damping_compression] value of 0.3, try a relaxation value of 0.5.
- </member>
- <member name="engine_force" type="float" setter="set_engine_force" getter="get_engine_force" default="0.0">
- Accelerates the wheel by applying an engine force. The wheel is only speed up if it is in contact with a surface. The [member RigidBody.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
- [b]Note:[/b] The simulation does not take the effect of gears into account, you will need to add logic for this if you wish to simulate gears.
- A negative value will result in the wheel reversing.
- </member>
- <member name="steering" type="float" setter="set_steering" getter="get_steering" default="0.0">
- The steering angle for the wheel. Setting this to a non-zero value will result in the vehicle turning when it's moving.
- </member>
- <member name="suspension_max_force" type="float" setter="set_suspension_max_force" getter="get_suspension_max_force" default="6000.0">
- The maximum force the spring can resist. This value should be higher than a quarter of the [member RigidBody.mass] of the [VehicleBody] or the spring will not carry the weight of the vehicle. Good results are often obtained by a value that is about 3× to 4× this number.
- </member>
- <member name="suspension_stiffness" type="float" setter="set_suspension_stiffness" getter="get_suspension_stiffness" default="5.88">
- This value defines the stiffness of the suspension. Use a value lower than 50 for an off-road car, a value between 50 and 100 for a race car and try something around 200 for something like a Formula 1 car.
- </member>
- <member name="suspension_travel" type="float" setter="set_suspension_travel" getter="get_suspension_travel" default="5.0">
- This is the distance the suspension can travel. As Godot units are equivalent to meters, keep this setting relatively low. Try a value between 0.1 and 0.3 depending on the type of car.
- </member>
- <member name="use_as_steering" type="bool" setter="set_use_as_steering" getter="is_used_as_steering" default="false">
- If [code]true[/code], this wheel will be turned when the car steers. This value is used in conjunction with [member VehicleBody.steering] and ignored if you are using the per-wheel [member steering] value instead.
- </member>
- <member name="use_as_traction" type="bool" setter="set_use_as_traction" getter="is_used_as_traction" default="false">
- If [code]true[/code], this wheel transfers engine force to the ground to propel the vehicle forward. This value is used in conjunction with [member VehicleBody.engine_force] and ignored if you are using the per-wheel [member engine_force] value instead.
- </member>
- <member name="wheel_friction_slip" type="float" setter="set_friction_slip" getter="get_friction_slip" default="10.5">
- This determines how much grip this wheel has. It is combined with the friction setting of the surface the wheel is in contact with. 0.0 means no grip, 1.0 is normal grip. For a drift car setup, try setting the grip of the rear wheels slightly lower than the front wheels, or use a lower value to simulate tire wear.
- It's best to set this to 1.0 when starting out.
- </member>
- <member name="wheel_radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
- The radius of the wheel in meters.
- </member>
- <member name="wheel_rest_length" type="float" setter="set_suspension_rest_length" getter="get_suspension_rest_length" default="0.15">
- This is the distance in meters the wheel is lowered from its origin point. Don't set this to 0.0 and move the wheel into position, instead move the origin point of your wheel (the gizmo in Godot) to the position the wheel will take when bottoming out, then use the rest length to move the wheel down to the position it should be in when the car is in rest.
- </member>
- <member name="wheel_roll_influence" type="float" setter="set_roll_influence" getter="get_roll_influence" default="0.1">
- This value affects the roll of your vehicle. If set to 1.0 for all wheels, your vehicle will be prone to rolling over, while a value of 0.0 will resist body roll.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/VehicleWheel3D.xml b/doc/classes/VehicleWheel3D.xml
new file mode 100644
index 0000000000..c71d797eff
--- /dev/null
+++ b/doc/classes/VehicleWheel3D.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VehicleWheel3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Physics object that simulates the behavior of a wheel.
+ </brief_description>
+ <description>
+ This node needs to be used as a child node of [VehicleBody3D] and simulates the behavior of one of its wheels. This node also acts as a collider to detect if the wheel is touching a surface.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_rpm" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the rotational speed of the wheel in revolutions per minute.
+ </description>
+ </method>
+ <method name="get_skidinfo" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns a value between 0.0 and 1.0 that indicates whether this wheel is skidding. 0.0 is skidding (the wheel has lost grip, e.g. icy terrain), 1.0 means not skidding (the wheel has full grip, e.g. dry asphalt road).
+ </description>
+ </method>
+ <method name="is_in_contact" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if this wheel is in contact with a surface.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="brake" type="float" setter="set_brake" getter="get_brake" default="0.0">
+ Slows down the wheel by applying a braking force. The wheel is only slowed down if it is in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
+ </member>
+ <member name="damping_compression" type="float" setter="set_damping_compression" getter="get_damping_compression" default="0.83">
+ The damping applied to the spring when the spring is being compressed. This value should be between 0.0 (no damping) and 1.0. A value of 0.0 means the car will keep bouncing as the spring keeps its energy. A good value for this is around 0.3 for a normal car, 0.5 for a race car.
+ </member>
+ <member name="damping_relaxation" type="float" setter="set_damping_relaxation" getter="get_damping_relaxation" default="0.88">
+ The damping applied to the spring when relaxing. This value should be between 0.0 (no damping) and 1.0. This value should always be slightly higher than the [member damping_compression] property. For a [member damping_compression] value of 0.3, try a relaxation value of 0.5.
+ </member>
+ <member name="engine_force" type="float" setter="set_engine_force" getter="get_engine_force" default="0.0">
+ Accelerates the wheel by applying an engine force. The wheel is only speed up if it is in contact with a surface. The [member RigidBody3D.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
+ [b]Note:[/b] The simulation does not take the effect of gears into account, you will need to add logic for this if you wish to simulate gears.
+ A negative value will result in the wheel reversing.
+ </member>
+ <member name="steering" type="float" setter="set_steering" getter="get_steering" default="0.0">
+ The steering angle for the wheel. Setting this to a non-zero value will result in the vehicle turning when it's moving.
+ </member>
+ <member name="suspension_max_force" type="float" setter="set_suspension_max_force" getter="get_suspension_max_force" default="6000.0">
+ The maximum force the spring can resist. This value should be higher than a quarter of the [member RigidBody3D.mass] of the [VehicleBody3D] or the spring will not carry the weight of the vehicle. Good results are often obtained by a value that is about 3× to 4× this number.
+ </member>
+ <member name="suspension_stiffness" type="float" setter="set_suspension_stiffness" getter="get_suspension_stiffness" default="5.88">
+ This value defines the stiffness of the suspension. Use a value lower than 50 for an off-road car, a value between 50 and 100 for a race car and try something around 200 for something like a Formula 1 car.
+ </member>
+ <member name="suspension_travel" type="float" setter="set_suspension_travel" getter="get_suspension_travel" default="5.0">
+ This is the distance the suspension can travel. As Godot units are equivalent to meters, keep this setting relatively low. Try a value between 0.1 and 0.3 depending on the type of car.
+ </member>
+ <member name="use_as_steering" type="bool" setter="set_use_as_steering" getter="is_used_as_steering" default="false">
+ If [code]true[/code], this wheel will be turned when the car steers. This value is used in conjunction with [member VehicleBody3D.steering] and ignored if you are using the per-wheel [member steering] value instead.
+ </member>
+ <member name="use_as_traction" type="bool" setter="set_use_as_traction" getter="is_used_as_traction" default="false">
+ If [code]true[/code], this wheel transfers engine force to the ground to propel the vehicle forward. This value is used in conjunction with [member VehicleBody3D.engine_force] and ignored if you are using the per-wheel [member engine_force] value instead.
+ </member>
+ <member name="wheel_friction_slip" type="float" setter="set_friction_slip" getter="get_friction_slip" default="10.5">
+ This determines how much grip this wheel has. It is combined with the friction setting of the surface the wheel is in contact with. 0.0 means no grip, 1.0 is normal grip. For a drift car setup, try setting the grip of the rear wheels slightly lower than the front wheels, or use a lower value to simulate tire wear.
+ It's best to set this to 1.0 when starting out.
+ </member>
+ <member name="wheel_radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
+ The radius of the wheel in meters.
+ </member>
+ <member name="wheel_rest_length" type="float" setter="set_suspension_rest_length" getter="get_suspension_rest_length" default="0.15">
+ This is the distance in meters the wheel is lowered from its origin point. Don't set this to 0.0 and move the wheel into position, instead move the origin point of your wheel (the gizmo in Godot) to the position the wheel will take when bottoming out, then use the rest length to move the wheel down to the position it should be in when the car is in rest.
+ </member>
+ <member name="wheel_roll_influence" type="float" setter="set_roll_influence" getter="get_roll_influence" default="0.1">
+ This value affects the roll of your vehicle. If set to 1.0 for all wheels, your vehicle will be prone to rolling over, while a value of 0.0 will resist body roll.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VelocityTracker3D.xml b/doc/classes/VelocityTracker3D.xml
new file mode 100644
index 0000000000..98f7533c76
--- /dev/null
+++ b/doc/classes/VelocityTracker3D.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VelocityTracker3D" inherits="Reference" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_tracked_linear_velocity" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="reset">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="update_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="position" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="track_physics_step" type="bool" setter="set_track_physics_step" getter="is_tracking_physics_step" default="false">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 0632be28e1..5826822c6e 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -4,9 +4,9 @@
Creates a sub-view into the screen.
</brief_description>
<description>
- A Viewport creates a different view into the screen, or a sub-view inside another viewport. Children 2D Nodes will display on it, and children Camera 3D nodes will render on it too.
+ A Viewport creates a different view into the screen, or a sub-view inside another viewport. Children 2D Nodes will display on it, and children Camera3D 3D nodes will render on it too.
Optionally, a viewport can have its own 2D or 3D world, so they don't share what they draw with other viewports.
- If a viewport is a child of a [ViewportContainer], it will automatically take up its size, otherwise it must be set manually.
+ If a viewport is a child of a [SubViewportContainer], it will automatically take up its size, otherwise it must be set manually.
Viewports can also choose to be audio listeners, so they generate positional audio depending on a 2D or 3D camera child of it.
Also, viewports can be assigned to different screens in case the devices have multiple screens.
Finally, viewports can also behave as render targets, in which case they will not be visible unless the associated texture is used to draw.
@@ -17,7 +17,7 @@
</tutorials>
<methods>
<method name="find_world" qualifiers="const">
- <return type="World">
+ <return type="World3D">
</return>
<description>
Returns the 3D world of the viewport, or if none the world of the parent viewport.
@@ -31,7 +31,7 @@
</description>
</method>
<method name="get_camera" qualifiers="const">
- <return type="Camera">
+ <return type="Camera3D">
</return>
<description>
Returns the active 3D camera.
@@ -44,13 +44,6 @@
Returns the total transform of the viewport.
</description>
</method>
- <method name="get_modal_stack_top" qualifiers="const">
- <return type="Control">
- </return>
- <description>
- Returns the topmost modal in the stack.
- </description>
- </method>
<method name="get_mouse_position" qualifiers="const">
<return type="Vector2">
</return>
@@ -76,13 +69,6 @@
Returns the [enum ShadowAtlasQuadrantSubdiv] of the specified quadrant.
</description>
</method>
- <method name="get_size_override" qualifiers="const">
- <return type="Vector2">
- </return>
- <description>
- Returns the size override set with [method set_size_override].
- </description>
- </method>
<method name="get_texture" qualifiers="const">
<return type="ViewportTexture">
</return>
@@ -99,7 +85,7 @@
<return type="RID">
</return>
<description>
- Returns the viewport's RID from the [VisualServer].
+ Returns the viewport's RID from the [RenderingServer].
</description>
</method>
<method name="get_visible_rect" qualifiers="const">
@@ -116,13 +102,6 @@
Returns the drag data from the GUI, that was previously returned by [method Control.get_drag_data].
</description>
</method>
- <method name="gui_has_modal_stack" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if there are visible modals on-screen.
- </description>
- </method>
<method name="gui_is_dragging" qualifiers="const">
<return type="bool">
</return>
@@ -133,31 +112,31 @@
<method name="input">
<return type="void">
</return>
- <argument index="0" name="local_event" type="InputEvent">
+ <argument index="0" name="event" type="InputEvent">
+ </argument>
+ <argument index="1" name="in_local_coords" type="bool" default="false">
</argument>
<description>
</description>
</method>
- <method name="is_input_handled" qualifiers="const">
- <return type="bool">
+ <method name="input_text">
+ <return type="void">
</return>
+ <argument index="0" name="text" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="is_size_override_enabled" qualifiers="const">
+ <method name="is_embedding_subwindows" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns [code]true[/code] if the size override is enabled. See [method set_size_override].
</description>
</method>
- <method name="set_attach_to_screen_rect">
- <return type="void">
+ <method name="is_input_handled" qualifiers="const">
+ <return type="bool">
</return>
- <argument index="0" name="rect" type="Rect2">
- </argument>
<description>
- Attaches this [Viewport] to the root [Viewport] with the specified rectangle. This bypasses the need for another node to display this [Viewport] but makes you responsible for updating the position of this [Viewport] manually.
</description>
</method>
<method name="set_input_as_handled">
@@ -178,23 +157,12 @@
Sets the number of subdivisions to use in the specified quadrant. A higher number of subdivisions allows you to have more shadows in the scene at once, but reduces the quality of the shadows. A good practice is to have quadrants with a varying number of subdivisions and to have as few subdivisions as possible.
</description>
</method>
- <method name="set_size_override">
- <return type="void">
- </return>
- <argument index="0" name="enable" type="bool">
- </argument>
- <argument index="1" name="size" type="Vector2" default="Vector2( -1, -1 )">
- </argument>
- <argument index="2" name="margin" type="Vector2" default="Vector2( 0, 0 )">
- </argument>
- <description>
- Sets the size override of the viewport. If the [code]enable[/code] parameter is [code]true[/code] the override is used, otherwise it uses the default size. If the size parameter is [code](-1, -1)[/code], it won't update the size.
- </description>
- </method>
<method name="unhandled_input">
<return type="void">
</return>
- <argument index="0" name="local_event" type="InputEvent">
+ <argument index="0" name="event" type="InputEvent">
+ </argument>
+ <argument index="1" name="in_local_coords" type="bool" default="false">
</argument>
<description>
</description>
@@ -217,9 +185,6 @@
</method>
</methods>
<members>
- <member name="arvr" type="bool" setter="set_use_arvr" getter="use_arvr" default="false">
- If [code]true[/code], the viewport will be used in AR/VR process.
- </member>
<member name="audio_listener_enable_2d" type="bool" setter="set_as_audio_listener_2d" getter="is_audio_listener_2d" default="false">
If [code]true[/code], the viewport will process 2D audio streams.
</member>
@@ -242,6 +207,8 @@
<member name="gui_disable_input" type="bool" setter="set_disable_input" getter="is_input_disabled" default="false">
If [code]true[/code], the viewport will not receive input event.
</member>
+ <member name="gui_embed_subwindows" type="bool" setter="set_embed_subwindows_hint" getter="get_embed_subwindows_hint" default="false">
+ </member>
<member name="gui_snap_controls_to_pixels" type="bool" setter="set_snap_controls_to_pixels" getter="is_snap_controls_to_pixels_enabled" default="true">
If [code]true[/code], the GUI controls on the viewport will lay pixel perfectly.
</member>
@@ -251,20 +218,11 @@
The multisample anti-aliasing mode. A higher number results in smoother edges at the cost of significantly worse performance. A value of 4 is best unless targeting very high-end systems.
</member>
<member name="own_world" type="bool" setter="set_use_own_world" getter="is_using_own_world" default="false">
- If [code]true[/code], the viewport will use [World] defined in [code]world[/code] property.
+ If [code]true[/code], the viewport will use [World3D] defined in [code]world[/code] property.
</member>
<member name="physics_object_picking" type="bool" setter="set_physics_object_picking" getter="get_physics_object_picking" default="false">
If [code]true[/code], the objects rendered by viewport become subjects of mouse picking process.
</member>
- <member name="render_direct_to_screen" type="bool" setter="set_use_render_direct_to_screen" getter="is_using_render_direct_to_screen" default="false">
- If [code]true[/code], renders the Viewport directly to the screen instead of to the root viewport. Only available in GLES2. This is a low-level optimization and should not be used in most cases. If used, reading from the Viewport or from [code]SCREEN_TEXTURE[/code] becomes unavailable. For more information see [method VisualServer.viewport_set_render_direct_to_screen].
- </member>
- <member name="render_target_clear_mode" type="int" setter="set_clear_mode" getter="get_clear_mode" enum="Viewport.ClearMode" default="0">
- The clear mode when viewport used as a render target.
- </member>
- <member name="render_target_update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="Viewport.UpdateMode" default="2">
- The update mode when viewport used as a render target.
- </member>
<member name="shadow_atlas_quad_0" type="int" setter="set_shadow_atlas_quadrant_subdiv" getter="get_shadow_atlas_quadrant_subdiv" enum="Viewport.ShadowAtlasQuadrantSubdiv" default="2">
The subdivision amount of the first quadrant on the shadow atlas.
</member>
@@ -281,17 +239,11 @@
The shadow atlas' resolution (used for omni and spot lights). The value will be rounded up to the nearest power of 2.
[b]Note:[/b] If this is set to 0, shadows won't be visible. Since user-created viewports default to a value of 0, this value must be set above 0 manually.
</member>
- <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 0, 0 )">
- The width and height of viewport.
- </member>
- <member name="size_override_stretch" type="bool" setter="set_size_override_stretch" getter="is_size_override_stretch_enabled" default="false">
- If [code]true[/code], the size override affects stretch as well.
- </member>
<member name="transparent_bg" type="bool" setter="set_transparent_background" getter="has_transparent_background" default="false">
If [code]true[/code], the viewport should render its background as transparent.
</member>
- <member name="world" type="World" setter="set_world" getter="get_world">
- The custom [World] which can be used as 3D environment source.
+ <member name="world" type="World3D" setter="set_world" getter="get_world">
+ The custom [World3D] which can be used as 3D environment source.
</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.
@@ -307,23 +259,11 @@
</signal>
<signal name="size_changed">
<description>
- Emitted when the size of the viewport is changed, whether by [method set_size_override], resize of window, or some other means.
+ Emitted when the size of the viewport is changed, whether by resizing of window, or some other means.
</description>
</signal>
</signals>
<constants>
- <constant name="UPDATE_DISABLED" value="0" enum="UpdateMode">
- Do not update the render target.
- </constant>
- <constant name="UPDATE_ONCE" value="1" enum="UpdateMode">
- Update the render target once, then switch to [constant UPDATE_DISABLED].
- </constant>
- <constant name="UPDATE_WHEN_VISIBLE" value="2" enum="UpdateMode">
- Update the render target only when it is visible. This is the default value.
- </constant>
- <constant name="UPDATE_ALWAYS" value="3" enum="UpdateMode">
- Always update the render target.
- </constant>
<constant name="SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED" value="0" enum="ShadowAtlasQuadrantSubdiv">
This quadrant will not be used.
</constant>
@@ -410,15 +350,6 @@
<constant name="MSAA_16X" value="4" enum="MSAA">
Use 16x Multisample Antialiasing. Likely unsupported on medium and low-end hardware.
</constant>
- <constant name="CLEAR_MODE_ALWAYS" value="0" enum="ClearMode">
- Always clear the render target before drawing.
- </constant>
- <constant name="CLEAR_MODE_NEVER" value="1" enum="ClearMode">
- Never clear the render target.
- </constant>
- <constant name="CLEAR_MODE_ONLY_NEXT_FRAME" value="2" enum="ClearMode">
- Clear the render target next frame, then switch to [constant CLEAR_MODE_NEVER].
- </constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="0" enum="DefaultCanvasItemTextureFilter">
</constant>
<constant name="DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="1" enum="DefaultCanvasItemTextureFilter">
diff --git a/doc/classes/ViewportContainer.xml b/doc/classes/ViewportContainer.xml
deleted file mode 100644
index d2fbb85305..0000000000
--- a/doc/classes/ViewportContainer.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ViewportContainer" inherits="Container" version="4.0">
- <brief_description>
- Control for holding [Viewport]s.
- </brief_description>
- <description>
- A [Container] node that holds a [Viewport], automatically setting its size.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled" default="false">
- If [code]true[/code], the viewport will be scaled to the control's size.
- </member>
- <member name="stretch_shrink" type="int" setter="set_stretch_shrink" getter="get_stretch_shrink" default="1">
- Divides the viewport's effective resolution by this value while preserving its scale. This can be used to speed up rendering.
- For example, a 1280×720 viewport with [member stretch_shrink] set to [code]2[/code] will be rendered at 640×360 while occupying the same size in the container.
- [b]Note:[/b] [member stretch] must be [code]true[/code] for this property to work.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/VisibilityEnabler.xml b/doc/classes/VisibilityEnabler.xml
deleted file mode 100644
index 82b952fda6..0000000000
--- a/doc/classes/VisibilityEnabler.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibilityEnabler" inherits="VisibilityNotifier" version="4.0">
- <brief_description>
- Enables certain nodes only when visible.
- </brief_description>
- <description>
- The VisibilityEnabler will disable [RigidBody] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibilityEnabler itself.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="is_enabler_enabled" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="enabler" type="int" enum="VisibilityEnabler.Enabler">
- </argument>
- <description>
- Returns whether the enabler identified by given [enum Enabler] constant is active.
- </description>
- </method>
- <method name="set_enabler">
- <return type="void">
- </return>
- <argument index="0" name="enabler" type="int" enum="VisibilityEnabler.Enabler">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Sets active state of the enabler identified by given [enum Enabler] constant.
- </description>
- </method>
- </methods>
- <members>
- <member name="freeze_bodies" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
- If [code]true[/code], [RigidBody] nodes will be paused.
- </member>
- <member name="pause_animations" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
- If [code]true[/code], [AnimationPlayer] nodes will be paused.
- </member>
- </members>
- <constants>
- <constant name="ENABLER_PAUSE_ANIMATIONS" value="0" enum="Enabler">
- This enabler will pause [AnimationPlayer] nodes.
- </constant>
- <constant name="ENABLER_FREEZE_BODIES" value="1" enum="Enabler">
- This enabler will freeze [RigidBody] nodes.
- </constant>
- <constant name="ENABLER_MAX" value="2" enum="Enabler">
- Represents the size of the [enum Enabler] enum.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/VisibilityEnabler2D.xml b/doc/classes/VisibilityEnabler2D.xml
index 98c3e5d78d..0bdecafbfa 100644
--- a/doc/classes/VisibilityEnabler2D.xml
+++ b/doc/classes/VisibilityEnabler2D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and other nodes when they are not visible. It will only affect nodes with the same root node as the VisibilityEnabler2D, and the root node itself.
+ Note that VisibilityEnabler2D will not affect nodes added after scene initialization.
</description>
<tutorials>
</tutorials>
@@ -35,13 +36,13 @@
If [code]true[/code], [RigidBody2D] nodes will be paused.
</member>
<member name="pause_animated_sprites" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
- If [code]true[/code], [AnimatedSprite] nodes will be paused.
+ If [code]true[/code], [AnimatedSprite2D] nodes will be paused.
</member>
<member name="pause_animations" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
If [code]true[/code], [AnimationPlayer] nodes will be paused.
</member>
<member name="pause_particles" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
- If [code]true[/code], [Particles2D] nodes will be paused.
+ If [code]true[/code], [GPUParticles2D] nodes will be paused.
</member>
<member name="physics_process_parent" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="false">
If [code]true[/code], the parent's [method Node._physics_process] will be stopped.
@@ -58,7 +59,7 @@
This enabler will freeze [RigidBody2D] nodes.
</constant>
<constant name="ENABLER_PAUSE_PARTICLES" value="2" enum="Enabler">
- This enabler will stop [Particles2D] nodes.
+ This enabler will stop [GPUParticles2D] nodes.
</constant>
<constant name="ENABLER_PARENT_PROCESS" value="3" enum="Enabler">
This enabler will stop the parent's _process function.
@@ -67,7 +68,7 @@
This enabler will stop the parent's _physics_process function.
</constant>
<constant name="ENABLER_PAUSE_ANIMATED_SPRITES" value="5" enum="Enabler">
- This enabler will stop [AnimatedSprite] nodes animations.
+ This enabler will stop [AnimatedSprite2D] nodes animations.
</constant>
<constant name="ENABLER_MAX" value="6" enum="Enabler">
Represents the size of the [enum Enabler] enum.
diff --git a/doc/classes/VisibilityEnabler3D.xml b/doc/classes/VisibilityEnabler3D.xml
new file mode 100644
index 0000000000..9c25c6c7c8
--- /dev/null
+++ b/doc/classes/VisibilityEnabler3D.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisibilityEnabler3D" inherits="VisibilityNotifier3D" version="4.0">
+ <brief_description>
+ Enables certain nodes only when visible.
+ </brief_description>
+ <description>
+ The VisibilityEnabler3D will disable [RigidBody3D] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibilityEnabler3D itself.
+ Note that VisibilityEnabler3D will not affect nodes added after scene initialization.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="is_enabler_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="enabler" type="int" enum="VisibilityEnabler3D.Enabler">
+ </argument>
+ <description>
+ Returns whether the enabler identified by given [enum Enabler] constant is active.
+ </description>
+ </method>
+ <method name="set_enabler">
+ <return type="void">
+ </return>
+ <argument index="0" name="enabler" type="int" enum="VisibilityEnabler3D.Enabler">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Sets active state of the enabler identified by given [enum Enabler] constant.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="freeze_bodies" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
+ If [code]true[/code], [RigidBody3D] nodes will be paused.
+ </member>
+ <member name="pause_animations" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true">
+ If [code]true[/code], [AnimationPlayer] nodes will be paused.
+ </member>
+ </members>
+ <constants>
+ <constant name="ENABLER_PAUSE_ANIMATIONS" value="0" enum="Enabler">
+ This enabler will pause [AnimationPlayer] nodes.
+ </constant>
+ <constant name="ENABLER_FREEZE_BODIES" value="1" enum="Enabler">
+ This enabler will freeze [RigidBody3D] nodes.
+ </constant>
+ <constant name="ENABLER_MAX" value="2" enum="Enabler">
+ Represents the size of the [enum Enabler] enum.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/VisibilityNotifier.xml b/doc/classes/VisibilityNotifier.xml
deleted file mode 100644
index 6161017884..0000000000
--- a/doc/classes/VisibilityNotifier.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisibilityNotifier" inherits="Spatial" version="4.0">
- <brief_description>
- Detects when the node is visible on screen.
- </brief_description>
- <description>
- The VisibilityNotifier detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a [Camera]'s view.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="is_on_screen" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- If [code]true[/code], the bounding box is on the screen.
- [b]Note:[/b] It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass.
- </description>
- </method>
- </methods>
- <members>
- <member name="aabb" type="AABB" setter="set_aabb" getter="get_aabb" default="AABB( -1, -1, -1, 2, 2, 2 )">
- The VisibilityNotifier's bounding box.
- </member>
- </members>
- <signals>
- <signal name="camera_entered">
- <argument index="0" name="camera" type="Camera">
- </argument>
- <description>
- Emitted when the VisibilityNotifier enters a [Camera]'s view.
- </description>
- </signal>
- <signal name="camera_exited">
- <argument index="0" name="camera" type="Camera">
- </argument>
- <description>
- Emitted when the VisibilityNotifier exits a [Camera]'s view.
- </description>
- </signal>
- <signal name="screen_entered">
- <description>
- Emitted when the VisibilityNotifier enters the screen.
- </description>
- </signal>
- <signal name="screen_exited">
- <description>
- Emitted when the VisibilityNotifier exits the screen.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/VisibilityNotifier3D.xml b/doc/classes/VisibilityNotifier3D.xml
new file mode 100644
index 0000000000..d8a605c69c
--- /dev/null
+++ b/doc/classes/VisibilityNotifier3D.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisibilityNotifier3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Detects when the node is visible on screen.
+ </brief_description>
+ <description>
+ The VisibilityNotifier3D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a [Camera3D]'s view.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="is_on_screen" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ If [code]true[/code], the bounding box is on the screen.
+ [b]Note:[/b] It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="aabb" type="AABB" setter="set_aabb" getter="get_aabb" default="AABB( -1, -1, -1, 2, 2, 2 )">
+ The VisibilityNotifier3D's bounding box.
+ </member>
+ </members>
+ <signals>
+ <signal name="camera_entered">
+ <argument index="0" name="camera" type="Camera3D">
+ </argument>
+ <description>
+ Emitted when the VisibilityNotifier3D enters a [Camera3D]'s view.
+ </description>
+ </signal>
+ <signal name="camera_exited">
+ <argument index="0" name="camera" type="Camera3D">
+ </argument>
+ <description>
+ Emitted when the VisibilityNotifier3D exits a [Camera3D]'s view.
+ </description>
+ </signal>
+ <signal name="screen_entered">
+ <description>
+ Emitted when the VisibilityNotifier3D enters the screen.
+ </description>
+ </signal>
+ <signal name="screen_exited">
+ <description>
+ Emitted when the VisibilityNotifier3D exits the screen.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualInstance.xml b/doc/classes/VisualInstance.xml
deleted file mode 100644
index 1bbd5cb64d..0000000000
--- a/doc/classes/VisualInstance.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualInstance" inherits="Spatial" version="4.0">
- <brief_description>
- Parent of all visual 3D nodes.
- </brief_description>
- <description>
- The [VisualInstance] is used to connect a resource to a visual representation. All visual 3D nodes inherit from the [VisualInstance]. In general, you should not access the [VisualInstance] properties directly as they are accessed and managed by the nodes that inherit from [VisualInstance]. [VisualInstance] is the node representation of the [VisualServer] instance.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_aabb" qualifiers="const">
- <return type="AABB">
- </return>
- <description>
- Returns the [AABB] (also known as the bounding box) for this [VisualInstance].
- </description>
- </method>
- <method name="get_base" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Returns the RID of the resource associated with this [VisualInstance]. For example, if the Node is a [MeshInstance], this will return the RID of the associated [Mesh].
- </description>
- </method>
- <method name="get_instance" qualifiers="const">
- <return type="RID">
- </return>
- <description>
- Returns the RID of this instance. This RID is the same as the RID returned by [method VisualServer.instance_create]. This RID is needed if you want to call [VisualServer] functions directly on this [VisualInstance].
- </description>
- </method>
- <method name="get_layer_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="layer" type="int">
- </argument>
- <description>
- Returns [code]true[/code] when the specified layer is enabled in [member layers] and [code]false[/code] otherwise.
- </description>
- </method>
- <method name="get_transformed_aabb" qualifiers="const">
- <return type="AABB">
- </return>
- <description>
- Returns the transformed [AABB] (also known as the bounding box) for this [VisualInstance].
- Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Spatial]'s [Transform].
- </description>
- </method>
- <method name="set_base">
- <return type="void">
- </return>
- <argument index="0" name="base" type="RID">
- </argument>
- <description>
- Sets the resource that is instantiated by this [VisualInstance], which changes how the engine handles the [VisualInstance] under the hood. Equivalent to [method VisualServer.instance_set_base].
- </description>
- </method>
- <method name="set_layer_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="layer" type="int">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Enables a particular layer in [member layers].
- </description>
- </method>
- </methods>
- <members>
- <member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask" default="1">
- The render layer(s) this [VisualInstance] is drawn on.
- This object will only be visible for [Camera]s whose cull mask includes the render object this [VisualInstance] is set to.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
new file mode 100644
index 0000000000..6451b3f330
--- /dev/null
+++ b/doc/classes/VisualInstance3D.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualInstance3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ Parent of all visual 3D nodes.
+ </brief_description>
+ <description>
+ The [VisualInstance3D] is used to connect a resource to a visual representation. All visual 3D nodes inherit from the [VisualInstance3D]. In general, you should not access the [VisualInstance3D] properties directly as they are accessed and managed by the nodes that inherit from [VisualInstance3D]. [VisualInstance3D] is the node representation of the [RenderingServer] instance.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_aabb" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <description>
+ Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D].
+ </description>
+ </method>
+ <method name="get_base" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the RID of the resource associated with this [VisualInstance3D]. For example, if the Node is a [MeshInstance3D], this will return the RID of the associated [Mesh].
+ </description>
+ </method>
+ <method name="get_instance" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ Returns the RID of this instance. This RID is the same as the RID returned by [method RenderingServer.instance_create]. This RID is needed if you want to call [RenderingServer] functions directly on this [VisualInstance3D].
+ </description>
+ </method>
+ <method name="get_layer_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <description>
+ Returns [code]true[/code] when the specified layer is enabled in [member layers] and [code]false[/code] otherwise.
+ </description>
+ </method>
+ <method name="get_transformed_aabb" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <description>
+ Returns the transformed [AABB] (also known as the bounding box) for this [VisualInstance3D].
+ Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform].
+ </description>
+ </method>
+ <method name="set_base">
+ <return type="void">
+ </return>
+ <argument index="0" name="base" type="RID">
+ </argument>
+ <description>
+ Sets the resource that is instantiated by this [VisualInstance3D], which changes how the engine handles the [VisualInstance3D] under the hood. Equivalent to [method RenderingServer.instance_set_base].
+ </description>
+ </method>
+ <method name="set_layer_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ Enables a particular layer in [member layers].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask" default="1">
+ The render layer(s) this [VisualInstance3D] is drawn on.
+ This object will only be visible for [Camera3D]s whose cull mask includes the render object this [VisualInstance3D] is set to.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml
deleted file mode 100644
index ca2058ddbb..0000000000
--- a/doc/classes/VisualServer.xml
+++ /dev/null
@@ -1,3733 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualServer" inherits="Object" version="4.0">
- <brief_description>
- Server for anything visible.
- </brief_description>
- <description>
- Server for anything visible. The visual server is the API backend for everything visible. The whole scene system mounts on it to display.
- The visual server is completely opaque, the internals are entirely implementation specific and cannot be accessed.
- The visual server can be used to bypass the scene system entirely.
- 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 visual server from a running game, the scenario can be accessed from the scene tree from any [Spatial] node with [method Spatial.get_world]. Otherwise, a scenario can be created with [method scenario_create].
- 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>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers.html</link>
- </tutorials>
- <methods>
- <method name="black_bars_set_images">
- <return type="void">
- </return>
- <argument index="0" name="left" type="RID">
- </argument>
- <argument index="1" name="top" type="RID">
- </argument>
- <argument index="2" name="right" type="RID">
- </argument>
- <argument index="3" name="bottom" type="RID">
- </argument>
- <description>
- Sets images to be rendered in the window margin.
- </description>
- </method>
- <method name="black_bars_set_margins">
- <return type="void">
- </return>
- <argument index="0" name="left" type="int">
- </argument>
- <argument index="1" name="top" type="int">
- </argument>
- <argument index="2" name="right" type="int">
- </argument>
- <argument index="3" name="bottom" type="int">
- </argument>
- <description>
- Sets margin size, where black bars (or images, if [method black_bars_set_images] was used) are rendered.
- </description>
- </method>
- <method name="camera_create">
- <return type="RID">
- </return>
- <description>
- Creates a camera and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="camera_set_cull_mask">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="layers" type="int">
- </argument>
- <description>
- Sets the cull mask associated with this camera. The cull mask describes which 3D layers are rendered by this camera. Equivalent to [member Camera.cull_mask].
- </description>
- </method>
- <method name="camera_set_environment">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="env" type="RID">
- </argument>
- <description>
- Sets the environment used by this camera. Equivalent to [member Camera.environment].
- </description>
- </method>
- <method name="camera_set_frustum">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="size" type="float">
- </argument>
- <argument index="2" name="offset" type="Vector2">
- </argument>
- <argument index="3" name="z_near" type="float">
- </argument>
- <argument index="4" name="z_far" type="float">
- </argument>
- <description>
- Sets camera to use frustum projection. This mode allows adjusting the [code]offset[/code] argument to create "tilted frustum" effects.
- </description>
- </method>
- <method name="camera_set_orthogonal">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="size" type="float">
- </argument>
- <argument index="2" name="z_near" type="float">
- </argument>
- <argument index="3" name="z_far" type="float">
- </argument>
- <description>
- Sets camera to use orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are.
- </description>
- </method>
- <method name="camera_set_perspective">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="fovy_degrees" type="float">
- </argument>
- <argument index="2" name="z_near" type="float">
- </argument>
- <argument index="3" name="z_far" type="float">
- </argument>
- <description>
- Sets camera to use perspective projection. Objects on the screen becomes smaller when they are far away.
- </description>
- </method>
- <method name="camera_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- Sets [Transform] of camera.
- </description>
- </method>
- <method name="camera_set_use_vertical_aspect">
- <return type="void">
- </return>
- <argument index="0" name="camera" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], preserves the horizontal aspect ratio which is equivalent to [constant Camera.KEEP_WIDTH]. If [code]false[/code], preserves the vertical aspect ratio which is equivalent to [constant Camera.KEEP_HEIGHT].
- </description>
- </method>
- <method name="canvas_create">
- <return type="RID">
- </return>
- <description>
- Creates a canvas and returns the assigned [RID]. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="canvas_item_clear">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <description>
- Clears the [CanvasItem] and removes all commands in it.
- </description>
- </method>
- <method name="canvas_item_set_copy_to_backbuffer">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <argument index="2" name="rect" type="Rect2">
- </argument>
- <description>
- Sets the [CanvasItem] to copy a rect to the backbuffer.
- </description>
- </method>
- <method name="canvas_item_set_draw_index">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Sets the index for the [CanvasItem].
- </description>
- </method>
- <method name="canvas_item_set_material">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <argument index="1" name="material" type="RID">
- </argument>
- <description>
- Sets a new material to the [CanvasItem].
- </description>
- </method>
- <method name="canvas_item_set_use_parent_material">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Sets if the [CanvasItem] uses its parent's material.
- </description>
- </method>
- <method name="canvas_item_set_z_as_relative_to_parent">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- If this is enabled, the Z index of the parent will be added to the children's Z index.
- </description>
- </method>
- <method name="canvas_item_set_z_index">
- <return type="void">
- </return>
- <argument index="0" name="item" type="RID">
- </argument>
- <argument index="1" name="z_index" type="int">
- </argument>
- <description>
- Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are drawn first).
- </description>
- </method>
- <method name="canvas_light_attach_to_canvas">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="canvas" type="RID">
- </argument>
- <description>
- Attaches the canvas light to the canvas. Removes it from its previous canvas.
- </description>
- </method>
- <method name="canvas_light_create">
- <return type="RID">
- </return>
- <description>
- Creates a canvas light and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_light_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="canvas_light_occluder_attach_to_canvas">
- <return type="void">
- </return>
- <argument index="0" name="occluder" type="RID">
- </argument>
- <argument index="1" name="canvas" type="RID">
- </argument>
- <description>
- Attaches a light occluder to the canvas. Removes it from its previous canvas.
- </description>
- </method>
- <method name="canvas_light_occluder_create">
- <return type="RID">
- </return>
- <description>
- Creates a light occluder and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_light_ocluder_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="canvas_light_occluder_set_enabled">
- <return type="void">
- </return>
- <argument index="0" name="occluder" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Enables or disables light occluder.
- </description>
- </method>
- <method name="canvas_light_occluder_set_light_mask">
- <return type="void">
- </return>
- <argument index="0" name="occluder" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- The light mask. See [LightOccluder2D] for more information on light masks.
- </description>
- </method>
- <method name="canvas_light_occluder_set_polygon">
- <return type="void">
- </return>
- <argument index="0" name="occluder" type="RID">
- </argument>
- <argument index="1" name="polygon" type="RID">
- </argument>
- <description>
- Sets a light occluder's polygon.
- </description>
- </method>
- <method name="canvas_light_occluder_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="occluder" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets a light occluder's [Transform2D].
- </description>
- </method>
- <method name="canvas_light_set_color">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the color for a light.
- </description>
- </method>
- <method name="canvas_light_set_enabled">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Enables or disables a canvas light.
- </description>
- </method>
- <method name="canvas_light_set_energy">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="energy" type="float">
- </argument>
- <description>
- Sets a canvas light's energy.
- </description>
- </method>
- <method name="canvas_light_set_height">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="height" type="float">
- </argument>
- <description>
- Sets a canvas light's height.
- </description>
- </method>
- <method name="canvas_light_set_item_cull_mask">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- The light mask. See [LightOccluder2D] for more information on light masks.
- </description>
- </method>
- <method name="canvas_light_set_item_shadow_cull_mask">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- The binary mask used to determine which layers this canvas light's shadows affects. See [LightOccluder2D] for more information on light masks.
- </description>
- </method>
- <method name="canvas_light_set_layer_range">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="min_layer" type="int">
- </argument>
- <argument index="2" name="max_layer" type="int">
- </argument>
- <description>
- The layer range that gets rendered with this light.
- </description>
- </method>
- <method name="canvas_light_set_mode">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="VisualServer.CanvasLightMode">
- </argument>
- <description>
- The mode of the light, see [enum CanvasLightMode] constants.
- </description>
- </method>
- <method name="canvas_light_set_scale">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="scale" type="float">
- </argument>
- <description>
- Sets the texture's scale factor of the light. Equivalent to [member Light2D.texture_scale].
- </description>
- </method>
- <method name="canvas_light_set_shadow_buffer_size">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="size" type="int">
- </argument>
- <description>
- Sets the width of the shadow buffer, size gets scaled to the next power of two for this.
- </description>
- </method>
- <method name="canvas_light_set_shadow_color">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the color of the canvas light's shadow.
- </description>
- </method>
- <method name="canvas_light_set_shadow_enabled">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Enables or disables the canvas light's shadow.
- </description>
- </method>
- <method name="canvas_light_set_shadow_filter">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="filter" type="int" enum="VisualServer.CanvasLightShadowFilter">
- </argument>
- <description>
- Sets the canvas light's shadow's filter, see [enum CanvasLightShadowFilter] constants.
- </description>
- </method>
- <method name="canvas_light_set_shadow_smooth">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="smooth" type="float">
- </argument>
- <description>
- Smoothens the shadow. The lower, the smoother.
- </description>
- </method>
- <method name="canvas_light_set_texture">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="texture" type="RID">
- </argument>
- <description>
- Sets texture to be used by light. Equivalent to [member Light2D.texture].
- </description>
- </method>
- <method name="canvas_light_set_texture_offset">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="offset" type="Vector2">
- </argument>
- <description>
- Sets the offset of the light's texture. Equivalent to [member Light2D.offset].
- </description>
- </method>
- <method name="canvas_light_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the canvas light's [Transform2D].
- </description>
- </method>
- <method name="canvas_light_set_z_range">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="min_z" type="int">
- </argument>
- <argument index="2" name="max_z" type="int">
- </argument>
- <description>
- Sets the Z range of objects that will be affected by this light. Equivalent to [member Light2D.range_z_min] and [member Light2D.range_z_max].
- </description>
- </method>
- <method name="canvas_occluder_polygon_create">
- <return type="RID">
- </return>
- <description>
- Creates a new light occluder polygon and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]canvas_occluder_polygon_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="canvas_occluder_polygon_set_cull_mode">
- <return type="void">
- </return>
- <argument index="0" name="occluder_polygon" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="VisualServer.CanvasOccluderPolygonCullMode">
- </argument>
- <description>
- Sets an occluder polygons cull mode. See [enum CanvasOccluderPolygonCullMode] constants.
- </description>
- </method>
- <method name="canvas_occluder_polygon_set_shape">
- <return type="void">
- </return>
- <argument index="0" name="occluder_polygon" type="RID">
- </argument>
- <argument index="1" name="shape" type="PackedVector2Array">
- </argument>
- <argument index="2" name="closed" type="bool">
- </argument>
- <description>
- Sets the shape of the occluder polygon.
- </description>
- </method>
- <method name="canvas_occluder_polygon_set_shape_as_lines">
- <return type="void">
- </return>
- <argument index="0" name="occluder_polygon" type="RID">
- </argument>
- <argument index="1" name="shape" type="PackedVector2Array">
- </argument>
- <description>
- Sets the shape of the occluder polygon as lines.
- </description>
- </method>
- <method name="canvas_set_item_mirroring">
- <return type="void">
- </return>
- <argument index="0" name="canvas" type="RID">
- </argument>
- <argument index="1" name="item" type="RID">
- </argument>
- <argument index="2" name="mirroring" type="Vector2">
- </argument>
- <description>
- A copy of the canvas item will be drawn with a local offset of the mirroring [Vector2].
- </description>
- </method>
- <method name="canvas_set_modulate">
- <return type="void">
- </return>
- <argument index="0" name="canvas" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Modulates all colors in the given canvas.
- </description>
- </method>
- <method name="directional_light_create">
- <return type="RID">
- </return>
- <description>
- Creates a directional light and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID can be used in most [code]light_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this directional light to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="environment_create">
- <return type="RID">
- </return>
- <description>
- Creates an environment and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]environment_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="environment_set_adjustment">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="brightness" type="float">
- </argument>
- <argument index="3" name="contrast" type="float">
- </argument>
- <argument index="4" name="saturation" type="float">
- </argument>
- <argument index="5" name="ramp" type="RID">
- </argument>
- <description>
- Sets the values to be used with the "Adjustment" post-process effect. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_ambient_light">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <argument index="2" name="ambient" type="int" enum="VisualServer.EnvironmentAmbientSource" default="0">
- </argument>
- <argument index="3" name="energy" type="float" default="1.0">
- </argument>
- <argument index="4" name="sky_contibution" type="float" default="0.0">
- </argument>
- <argument index="5" name="reflection_source" type="int" enum="VisualServer.EnvironmentReflectionSource" default="0">
- </argument>
- <argument index="6" name="ao_color" type="Color" default="Color( 0, 0, 0, 1 )">
- </argument>
- <description>
- </description>
- </method>
- <method name="environment_set_background">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="bg" type="int" enum="VisualServer.EnvironmentBG">
- </argument>
- <description>
- Sets the [i]BGMode[/i] of the environment. Equivalent to [member Environment.background_mode].
- </description>
- </method>
- <method name="environment_set_bg_color">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Color displayed for clear areas of the scene (if using Custom color or Color+Sky background modes).
- </description>
- </method>
- <method name="environment_set_bg_energy">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="energy" type="float">
- </argument>
- <description>
- Sets the intensity of the background color.
- </description>
- </method>
- <method name="environment_set_canvas_max_layer">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="max_layer" type="int">
- </argument>
- <description>
- Sets the maximum layer to use if using Canvas background mode.
- </description>
- </method>
- <method name="environment_set_fog">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <argument index="3" name="sun_color" type="Color">
- </argument>
- <argument index="4" name="sun_amount" type="float">
- </argument>
- <description>
- Sets the variables to be used with the scene fog. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_fog_depth">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="depth_begin" type="float">
- </argument>
- <argument index="3" name="depth_end" type="float">
- </argument>
- <argument index="4" name="depth_curve" type="float">
- </argument>
- <argument index="5" name="transmit" type="bool">
- </argument>
- <argument index="6" name="transmit_curve" type="float">
- </argument>
- <description>
- Sets the variables to be used with the fog depth effect. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_fog_height">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="min_height" type="float">
- </argument>
- <argument index="3" name="max_height" type="float">
- </argument>
- <argument index="4" name="height_curve" type="float">
- </argument>
- <description>
- Sets the variables to be used with the fog height effect. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_glow">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="level_flags" type="int">
- </argument>
- <argument index="3" name="intensity" type="float">
- </argument>
- <argument index="4" name="strength" type="float">
- </argument>
- <argument index="5" name="mix" type="float">
- </argument>
- <argument index="6" name="bloom_threshold" type="float">
- </argument>
- <argument index="7" name="blend_mode" type="int" enum="VisualServer.EnvironmentGlowBlendMode">
- </argument>
- <argument index="8" name="hdr_bleed_threshold" type="float">
- </argument>
- <argument index="9" name="hdr_bleed_scale" type="float">
- </argument>
- <argument index="10" name="hdr_luminance_cap" type="float">
- </argument>
- <argument index="11" name="bicubic_upscale" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="environment_set_sky">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="sky" type="RID">
- </argument>
- <description>
- Sets the [Sky] to be used as the environment's background when using [i]BGMode[/i] sky. Equivalent to [member Environment.sky].
- </description>
- </method>
- <method name="environment_set_sky_custom_fov">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="scale" type="float">
- </argument>
- <description>
- Sets a custom field of view for the background [Sky]. Equivalent to [member Environment.sky_custom_fov].
- </description>
- </method>
- <method name="environment_set_sky_orientation">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="orientation" type="Basis">
- </argument>
- <description>
- Sets the rotation of the background [Sky] expressed as a [Basis]. Equivalent to [member Environment.sky_rotation], where the rotation vector is used to construct the [Basis].
- </description>
- </method>
- <method name="environment_set_ssao">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="radius" type="float">
- </argument>
- <argument index="3" name="intensity" type="float">
- </argument>
- <argument index="4" name="bias" type="float">
- </argument>
- <argument index="5" name="light_affect" type="float">
- </argument>
- <argument index="6" name="ao_channel_affect" type="float">
- </argument>
- <argument index="7" name="blur" type="int" enum="VisualServer.EnvironmentSSAOBlur">
- </argument>
- <argument index="8" name="bilateral_sharpness" type="float">
- </argument>
- <description>
- </description>
- </method>
- <method name="environment_set_ssr">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <argument index="2" name="max_steps" type="int">
- </argument>
- <argument index="3" name="fade_in" type="float">
- </argument>
- <argument index="4" name="fade_out" type="float">
- </argument>
- <argument index="5" name="depth_tolerance" type="float">
- </argument>
- <argument index="6" name="roughness" type="bool">
- </argument>
- <description>
- Sets the variables to be used with the "screen space reflections" post-process effect. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_tonemap">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="tone_mapper" type="int" enum="VisualServer.EnvironmentToneMapper">
- </argument>
- <argument index="2" name="exposure" type="float">
- </argument>
- <argument index="3" name="white" type="float">
- </argument>
- <argument index="4" name="auto_exposure" type="bool">
- </argument>
- <argument index="5" name="min_luminance" type="float">
- </argument>
- <argument index="6" name="max_luminance" type="float">
- </argument>
- <argument index="7" name="auto_exp_speed" type="float">
- </argument>
- <argument index="8" name="auto_exp_grey" type="float">
- </argument>
- <description>
- Sets the variables to be used with the "tonemap" post-process effect. See [Environment] for more details.
- </description>
- </method>
- <method name="finish">
- <return type="void">
- </return>
- <description>
- Removes buffers and clears testcubes.
- </description>
- </method>
- <method name="force_draw">
- <return type="void">
- </return>
- <argument index="0" name="swap_buffers" type="bool" default="true">
- </argument>
- <argument index="1" name="frame_step" type="float" default="0.0">
- </argument>
- <description>
- Forces a frame to be drawn when the function is called. Drawing a frame updates all [Viewport]s that are set to update. Use with extreme caution.
- </description>
- </method>
- <method name="force_sync">
- <return type="void">
- </return>
- <description>
- Synchronizes threads.
- </description>
- </method>
- <method name="free_rid">
- <return type="void">
- </return>
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- Tries to free an object in the VisualServer.
- </description>
- </method>
- <method name="get_render_info">
- <return type="int">
- </return>
- <argument index="0" name="info" type="int" enum="VisualServer.RenderInfo">
- </argument>
- <description>
- Returns a certain information, see [enum RenderInfo] for options.
- </description>
- </method>
- <method name="get_test_cube">
- <return type="RID">
- </return>
- <description>
- Returns the id of the test cube. Creates one if none exists.
- </description>
- </method>
- <method name="get_test_texture">
- <return type="RID">
- </return>
- <description>
- Returns the id of the test texture. Creates one if none exists.
- </description>
- </method>
- <method name="get_video_adapter_name" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the name of the video adapter (e.g. "GeForce GTX 1080/PCIe/SSE2").
- [b]Note:[/b] When running a headless or server binary, this function returns an empty string.
- </description>
- </method>
- <method name="get_video_adapter_vendor" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the vendor of the video adapter (e.g. "NVIDIA Corporation").
- [b]Note:[/b] When running a headless or server binary, this function returns an empty string.
- </description>
- </method>
- <method name="get_white_texture">
- <return type="RID">
- </return>
- <description>
- Returns the id of a white texture. Creates one if none exists.
- </description>
- </method>
- <method name="has_changed" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if changes have been made to the VisualServer's data. [method force_draw] is usually called if this happens.
- </description>
- </method>
- <method name="has_feature" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="feature" type="int" enum="VisualServer.Features">
- </argument>
- <description>
- Not yet implemented. Always returns [code]false[/code].
- </description>
- </method>
- <method name="has_os_feature" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="feature" type="String">
- </argument>
- <description>
- Returns [code]true[/code] if the OS supports a certain feature. Features might be [code]s3tc[/code], [code]etc[/code], [code]etc2[/code] and [code]pvrtc[/code].
- </description>
- </method>
- <method name="immediate_begin">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="primitive" type="int" enum="VisualServer.PrimitiveType">
- </argument>
- <argument index="2" name="texture" type="RID">
- </argument>
- <description>
- Sets up [ImmediateGeometry] internals to prepare for drawing. Equivalent to [method ImmediateGeometry.begin].
- </description>
- </method>
- <method name="immediate_clear">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <description>
- Clears everything that was set up between [method immediate_begin] and [method immediate_end]. Equivalent to [method ImmediateGeometry.clear].
- </description>
- </method>
- <method name="immediate_color">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the color to be used with next vertex. Equivalent to [method ImmediateGeometry.set_color].
- </description>
- </method>
- <method name="immediate_create">
- <return type="RID">
- </return>
- <description>
- Creates an immediate geometry and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]immediate_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this immediate geometry to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="immediate_end">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <description>
- Ends drawing the [ImmediateGeometry] and displays it. Equivalent to [method ImmediateGeometry.end].
- </description>
- </method>
- <method name="immediate_get_material" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <description>
- Returns the material assigned to the [ImmediateGeometry].
- </description>
- </method>
- <method name="immediate_normal">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="normal" type="Vector3">
- </argument>
- <description>
- Sets the normal to be used with next vertex. Equivalent to [method ImmediateGeometry.set_normal].
- </description>
- </method>
- <method name="immediate_set_material">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="material" type="RID">
- </argument>
- <description>
- Sets the material to be used to draw the [ImmediateGeometry].
- </description>
- </method>
- <method name="immediate_tangent">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="tangent" type="Plane">
- </argument>
- <description>
- Sets the tangent to be used with next vertex. Equivalent to [method ImmediateGeometry.set_tangent].
- </description>
- </method>
- <method name="immediate_uv">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="tex_uv" type="Vector2">
- </argument>
- <description>
- Sets the UV to be used with next vertex. Equivalent to [method ImmediateGeometry.set_uv].
- </description>
- </method>
- <method name="immediate_uv2">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="tex_uv" type="Vector2">
- </argument>
- <description>
- Sets the UV2 to be used with next vertex. Equivalent to [method ImmediateGeometry.set_uv2].
- </description>
- </method>
- <method name="immediate_vertex">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="vertex" type="Vector3">
- </argument>
- <description>
- Adds the next vertex using the information provided in advance. Equivalent to [method ImmediateGeometry.add_vertex].
- </description>
- </method>
- <method name="immediate_vertex_2d">
- <return type="void">
- </return>
- <argument index="0" name="immediate" type="RID">
- </argument>
- <argument index="1" name="vertex" type="Vector2">
- </argument>
- <description>
- Adds the next vertex using the information provided in advance. This is a helper class that calls [method immediate_vertex] under the hood. Equivalent to [method ImmediateGeometry.add_vertex].
- </description>
- </method>
- <method name="init">
- <return type="void">
- </return>
- <description>
- Initializes the visual server. This function is called internally by platform-dependent code during engine initialization. If called from a running game, it will not do anything.
- </description>
- </method>
- <method name="instance_attach_object_instance_id">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Attaches a unique Object ID to instance. Object ID must be attached to instance for proper culling with [method instances_cull_aabb], [method instances_cull_convex], and [method instances_cull_ray].
- </description>
- </method>
- <method name="instance_attach_skeleton">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="skeleton" type="RID">
- </argument>
- <description>
- Attaches a skeleton to an instance. Removes the previous skeleton from the instance.
- </description>
- </method>
- <method name="instance_create">
- <return type="RID">
- </return>
- <description>
- Creates a visual instance and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- An instance is a way of placing a 3D object in the scenario. Objects like particles, meshes, and reflection probes need to be associated with an instance to be visible in the scenario using [method instance_set_base].
- </description>
- </method>
- <method name="instance_create2">
- <return type="RID">
- </return>
- <argument index="0" name="base" type="RID">
- </argument>
- <argument index="1" name="scenario" type="RID">
- </argument>
- <description>
- Creates a visual instance, adds it to the VisualServer, and sets both base and scenario. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="instance_geometry_set_as_instance_lod">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="as_lod_of_instance" type="RID">
- </argument>
- <description>
- Not implemented in Godot 3.x.
- </description>
- </method>
- <method name="instance_geometry_set_cast_shadows_setting">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="shadow_casting_setting" type="int" enum="VisualServer.ShadowCastingSetting">
- </argument>
- <description>
- Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance.cast_shadow].
- </description>
- </method>
- <method name="instance_geometry_set_draw_range">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="min" type="float">
- </argument>
- <argument index="2" name="max" type="float">
- </argument>
- <argument index="3" name="min_margin" type="float">
- </argument>
- <argument index="4" name="max_margin" type="float">
- </argument>
- <description>
- Not implemented in Godot 3.x.
- </description>
- </method>
- <method name="instance_geometry_set_flag">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="flag" type="int" enum="VisualServer.InstanceFlags">
- </argument>
- <argument index="2" name="enabled" type="bool">
- </argument>
- <description>
- Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details.
- </description>
- </method>
- <method name="instance_geometry_set_material_override">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="material" type="RID">
- </argument>
- <description>
- Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance.material_override].
- </description>
- </method>
- <method name="instance_set_base">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="base" type="RID">
- </argument>
- <description>
- Sets the base of the instance. A base can be any of the 3D objects that are created in the VisualServer that can be displayed. For example, any of the light types, mesh, multimesh, immediate geometry, particle system, reflection probe, lightmap capture, and the GI probe are all types that can be set as the base of an instance in order to be displayed in the scenario.
- </description>
- </method>
- <method name="instance_set_blend_shape_weight">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="shape" type="int">
- </argument>
- <argument index="2" name="weight" type="float">
- </argument>
- <description>
- Sets the weight for a given blend shape associated with this instance.
- </description>
- </method>
- <method name="instance_set_custom_aabb">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="aabb" type="AABB">
- </argument>
- <description>
- Sets a custom AABB to use when culling objects from the view frustum. Equivalent to [method GeometryInstance.set_custom_aabb].
- </description>
- </method>
- <method name="instance_set_exterior">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Function not implemented in Godot 3.x.
- </description>
- </method>
- <method name="instance_set_extra_visibility_margin">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <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 GeometryInstance.extra_cull_margin].
- </description>
- </method>
- <method name="instance_set_layer_mask">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- Sets the render layers that this instance will be drawn to. Equivalent to [member VisualInstance.layers].
- </description>
- </method>
- <method name="instance_set_scenario">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="scenario" type="RID">
- </argument>
- <description>
- 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">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="surface" type="int">
- </argument>
- <argument index="2" name="material" type="RID">
- </argument>
- <description>
- Sets the material of a specific surface. Equivalent to [method MeshInstance.set_surface_material].
- </description>
- </method>
- <method name="instance_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- Sets the world space transform of the instance. Equivalent to [member Spatial.transform].
- </description>
- </method>
- <method name="instance_set_use_lightmap">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="lightmap_instance" type="RID">
- </argument>
- <argument index="2" name="lightmap" type="RID">
- </argument>
- <description>
- Sets the lightmap to use with this instance.
- </description>
- </method>
- <method name="instance_set_visible">
- <return type="void">
- </return>
- <argument index="0" name="instance" type="RID">
- </argument>
- <argument index="1" name="visible" type="bool">
- </argument>
- <description>
- Sets whether an instance is drawn or not. Equivalent to [member Spatial.visible].
- </description>
- </method>
- <method name="instances_cull_aabb" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="aabb" type="AABB">
- </argument>
- <argument index="1" name="scenario" type="RID">
- </argument>
- <description>
- Returns an array of object IDs intersecting with the provided AABB. Only visual 3D nodes are considered, such as [MeshInstance] or [DirectionalLight]. Use [method @GDScript.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World] you want to query. This forces an update for all resources queued to update.
- [b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
- </description>
- </method>
- <method name="instances_cull_convex" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="convex" type="Array">
- </argument>
- <argument index="1" name="scenario" type="RID">
- </argument>
- <description>
- Returns an array of object IDs intersecting with the provided convex shape. Only visual 3D nodes are considered, such as [MeshInstance] or [DirectionalLight]. Use [method @GDScript.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World] you want to query. This forces an update for all resources queued to update.
- [b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
- </description>
- </method>
- <method name="instances_cull_ray" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="from" type="Vector3">
- </argument>
- <argument index="1" name="to" type="Vector3">
- </argument>
- <argument index="2" name="scenario" type="RID">
- </argument>
- <description>
- Returns an array of object IDs intersecting with the provided 3D ray. Only visual 3D nodes are considered, such as [MeshInstance] or [DirectionalLight]. Use [method @GDScript.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World] you want to query. This forces an update for all resources queued to update.
- [b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
- </description>
- </method>
- <method name="light_directional_set_blend_splits">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], this directional light will blend between shadow map splits resulting in a smoother transition between them. Equivalent to [member DirectionalLight.directional_shadow_blend_splits].
- </description>
- </method>
- <method name="light_directional_set_shadow_depth_range_mode">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="range_mode" type="int" enum="VisualServer.LightDirectionalShadowDepthRangeMode">
- </argument>
- <description>
- Sets the shadow depth range mode for this directional light. Equivalent to [member DirectionalLight.directional_shadow_depth_range]. See [enum LightDirectionalShadowDepthRangeMode] for options.
- </description>
- </method>
- <method name="light_directional_set_shadow_mode">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="VisualServer.LightDirectionalShadowMode">
- </argument>
- <description>
- Sets the shadow mode for this directional light. Equivalent to [member DirectionalLight.directional_shadow_mode]. See [enum LightDirectionalShadowMode] for options.
- </description>
- </method>
- <method name="light_omni_set_shadow_mode">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="VisualServer.LightOmniShadowMode">
- </argument>
- <description>
- Sets whether to use a dual paraboloid or a cubemap for the shadow map. Dual paraboloid is faster but may suffer from artifacts. Equivalent to [member OmniLight.omni_shadow_mode].
- </description>
- </method>
- <method name="light_set_color">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the color of the light. Equivalent to [member Light.light_color].
- </description>
- </method>
- <method name="light_set_cull_mask">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="mask" type="int">
- </argument>
- <description>
- Sets the cull mask for this Light. Lights only affect objects in the selected layers. Equivalent to [member Light.light_cull_mask].
- </description>
- </method>
- <method name="light_set_negative">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], light will subtract light instead of adding light. Equivalent to [member Light.light_negative].
- </description>
- </method>
- <method name="light_set_param">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="param" type="int" enum="VisualServer.LightParam">
- </argument>
- <argument index="2" name="value" type="float">
- </argument>
- <description>
- Sets the specified light parameter. See [enum LightParam] for options. Equivalent to [method Light.set_param].
- </description>
- </method>
- <method name="light_set_projector">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="texture" type="RID">
- </argument>
- <description>
- Not implemented in Godot 3.x.
- </description>
- </method>
- <method name="light_set_reverse_cull_face_mode">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <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 Light.shadow_reverse_cull_face].
- </description>
- </method>
- <method name="light_set_shadow">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- If [code]true[/code], light will cast shadows. Equivalent to [member Light.shadow_enabled].
- </description>
- </method>
- <method name="light_set_shadow_color">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the color of the shadow cast by the light. Equivalent to [member Light.shadow_color].
- </description>
- </method>
- <method name="light_set_use_gi">
- <return type="void">
- </return>
- <argument index="0" name="light" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- Sets whether GI probes capture light information from this light.
- </description>
- </method>
- <method name="lightmap_capture_create">
- <return type="RID">
- </return>
- <description>
- Creates a lightmap capture and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]lightmap_capture_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this lightmap capture to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="lightmap_capture_get_bounds" qualifiers="const">
- <return type="AABB">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <description>
- Returns the size of the lightmap capture area.
- </description>
- </method>
- <method name="lightmap_capture_get_energy" qualifiers="const">
- <return type="float">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <description>
- Returns the energy multiplier used by the lightmap capture.
- </description>
- </method>
- <method name="lightmap_capture_get_octree" qualifiers="const">
- <return type="PackedByteArray">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <description>
- Returns the octree used by the lightmap capture.
- </description>
- </method>
- <method name="lightmap_capture_get_octree_cell_subdiv" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <description>
- Returns the cell subdivision amount used by this lightmap capture's octree.
- </description>
- </method>
- <method name="lightmap_capture_get_octree_cell_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <description>
- Returns the cell transform for this lightmap capture's octree.
- </description>
- </method>
- <method name="lightmap_capture_set_bounds">
- <return type="void">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <argument index="1" name="bounds" type="AABB">
- </argument>
- <description>
- Sets the size of the area covered by the lightmap capture.
- </description>
- </method>
- <method name="lightmap_capture_set_energy">
- <return type="void">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <argument index="1" name="energy" type="float">
- </argument>
- <description>
- Sets the energy multiplier for this lightmap capture.
- </description>
- </method>
- <method name="lightmap_capture_set_octree">
- <return type="void">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <argument index="1" name="octree" type="PackedByteArray">
- </argument>
- <description>
- Sets the octree to be used by this lightmap capture.
- </description>
- </method>
- <method name="lightmap_capture_set_octree_cell_subdiv">
- <return type="void">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <argument index="1" name="subdiv" type="int">
- </argument>
- <description>
- Sets the subdivision level of this lightmap capture's octree.
- </description>
- </method>
- <method name="lightmap_capture_set_octree_cell_transform">
- <return type="void">
- </return>
- <argument index="0" name="capture" type="RID">
- </argument>
- <argument index="1" name="xform" type="Transform">
- </argument>
- <description>
- Sets the octree cell transform for this lightmap capture's octree.
- </description>
- </method>
- <method name="make_sphere_mesh">
- <return type="RID">
- </return>
- <argument index="0" name="latitudes" type="int">
- </argument>
- <argument index="1" name="longitudes" type="int">
- </argument>
- <argument index="2" name="radius" type="float">
- </argument>
- <description>
- Returns a mesh of a sphere with the given amount of horizontal and vertical subdivisions.
- </description>
- </method>
- <method name="material_create">
- <return type="RID">
- </return>
- <description>
- Creates an empty material and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]material_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="material_get_param" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="material" type="RID">
- </argument>
- <argument index="1" name="parameter" type="StringName">
- </argument>
- <description>
- Returns the value of a certain material's parameter.
- </description>
- </method>
- <method name="material_set_next_pass">
- <return type="void">
- </return>
- <argument index="0" name="material" type="RID">
- </argument>
- <argument index="1" name="next_material" type="RID">
- </argument>
- <description>
- Sets an object's next material.
- </description>
- </method>
- <method name="material_set_param">
- <return type="void">
- </return>
- <argument index="0" name="material" type="RID">
- </argument>
- <argument index="1" name="parameter" type="StringName">
- </argument>
- <argument index="2" name="value" type="Variant">
- </argument>
- <description>
- Sets a material's parameter.
- </description>
- </method>
- <method name="material_set_render_priority">
- <return type="void">
- </return>
- <argument index="0" name="material" type="RID">
- </argument>
- <argument index="1" name="priority" type="int">
- </argument>
- <description>
- Sets a material's render priority.
- </description>
- </method>
- <method name="material_set_shader">
- <return type="void">
- </return>
- <argument index="0" name="shader_material" type="RID">
- </argument>
- <argument index="1" name="shader" type="RID">
- </argument>
- <description>
- Sets a shader material's shader.
- </description>
- </method>
- <method name="mesh_add_surface_from_arrays">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="primitive" type="int" enum="VisualServer.PrimitiveType">
- </argument>
- <argument index="2" name="arrays" type="Array">
- </argument>
- <argument index="3" name="blend_shapes" type="Array" default="[ ]">
- </argument>
- <argument index="4" name="lods" type="Dictionary" default="{
-
-}">
- </argument>
- <argument index="5" name="compress_format" type="int" default="31744">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_clear">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <description>
- Removes all surfaces from a mesh.
- </description>
- </method>
- <method name="mesh_create">
- <return type="RID">
- </return>
- <description>
- Creates a new mesh and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]mesh_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this mesh to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="mesh_get_blend_shape_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <description>
- Returns a mesh's blend shape count.
- </description>
- </method>
- <method name="mesh_get_blend_shape_mode" qualifiers="const">
- <return type="int" enum="VisualServer.BlendShapeMode">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <description>
- Returns a mesh's blend shape mode.
- </description>
- </method>
- <method name="mesh_get_custom_aabb" qualifiers="const">
- <return type="AABB">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <description>
- Returns a mesh's custom aabb.
- </description>
- </method>
- <method name="mesh_get_surface_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <description>
- Returns a mesh's number of surfaces.
- </description>
- </method>
- <method name="mesh_set_blend_shape_mode">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="VisualServer.BlendShapeMode">
- </argument>
- <description>
- Sets a mesh's blend shape mode.
- </description>
- </method>
- <method name="mesh_set_custom_aabb">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="aabb" type="AABB">
- </argument>
- <description>
- Sets a mesh's custom aabb.
- </description>
- </method>
- <method name="mesh_surface_get_arrays" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="surface" type="int">
- </argument>
- <description>
- Returns a mesh's surface's buffer arrays.
- </description>
- </method>
- <method name="mesh_surface_get_blend_shape_arrays" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="surface" type="int">
- </argument>
- <description>
- Returns a mesh's surface's arrays for blend shapes.
- </description>
- </method>
- <method name="mesh_surface_get_format_offset" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="format" type="int">
- </argument>
- <argument index="1" name="vertex_len" type="int">
- </argument>
- <argument index="2" name="index_len" type="int">
- </argument>
- <argument index="3" name="array_index" type="int">
- </argument>
- <description>
- Function is unused in Godot 3.x.
- </description>
- </method>
- <method name="mesh_surface_get_format_stride" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="format" type="int">
- </argument>
- <argument index="1" name="vertex_len" type="int">
- </argument>
- <argument index="2" name="index_len" type="int">
- </argument>
- <description>
- Function is unused in Godot 3.x.
- </description>
- </method>
- <method name="mesh_surface_get_material" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="surface" type="int">
- </argument>
- <description>
- Returns a mesh's surface's material.
- </description>
- </method>
- <method name="mesh_surface_set_material">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="surface" type="int">
- </argument>
- <argument index="2" name="material" type="RID">
- </argument>
- <description>
- Sets a mesh's surface's material.
- </description>
- </method>
- <method name="mesh_surface_update_region">
- <return type="void">
- </return>
- <argument index="0" name="mesh" type="RID">
- </argument>
- <argument index="1" name="surface" type="int">
- </argument>
- <argument index="2" name="offset" type="int">
- </argument>
- <argument index="3" name="data" type="PackedByteArray">
- </argument>
- <description>
- 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">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="instances" type="int">
- </argument>
- <argument index="2" name="transform_format" type="int" enum="VisualServer.MultimeshTransformFormat">
- </argument>
- <argument index="3" name="color_format" type="bool" default="false">
- </argument>
- <argument index="4" name="custom_data_format" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_create">
- <return type="RID">
- </return>
- <description>
- Creates a new multimesh on the VisualServer and returns an [RID] handle. This RID will be used in all [code]multimesh_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this multimesh to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="multimesh_get_aabb" qualifiers="const">
- <return type="AABB">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <description>
- Calculates and returns the axis-aligned bounding box that encloses all instances within the multimesh.
- </description>
- </method>
- <method name="multimesh_get_buffer" qualifiers="const">
- <return type="PackedFloat32Array">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_get_instance_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <description>
- Returns the number of instances allocated for this multimesh.
- </description>
- </method>
- <method name="multimesh_get_mesh" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <description>
- Returns the RID of the mesh that will be used in drawing this multimesh.
- </description>
- </method>
- <method name="multimesh_get_visible_instances" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <description>
- Returns the number of visible instances for this multimesh.
- </description>
- </method>
- <method name="multimesh_instance_get_color" qualifiers="const">
- <return type="Color">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Returns the color by which the specified instance will be modulated.
- </description>
- </method>
- <method name="multimesh_instance_get_custom_data" qualifiers="const">
- <return type="Color">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Returns the custom data associated with the specified instance.
- </description>
- </method>
- <method name="multimesh_instance_get_transform" qualifiers="const">
- <return type="Transform">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Returns the [Transform] of the specified instance.
- </description>
- </method>
- <method name="multimesh_instance_get_transform_2d" qualifiers="const">
- <return type="Transform2D">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <description>
- Returns the [Transform2D] of the specified instance. For use when the multimesh is set to use 2D transforms.
- </description>
- </method>
- <method name="multimesh_instance_set_color">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <description>
- Sets the color by which this instance will be modulated. Equivalent to [method MultiMesh.set_instance_color].
- </description>
- </method>
- <method name="multimesh_instance_set_custom_data">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <argument index="2" name="custom_data" type="Color">
- </argument>
- <description>
- Sets the custom data for this instance. Custom data is passed as a [Color], but is interpreted as a [code]vec4[/code] in the shader. Equivalent to [method MultiMesh.set_instance_custom_data].
- </description>
- </method>
- <method name="multimesh_instance_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform">
- </argument>
- <description>
- Sets the [Transform] for this instance. Equivalent to [method MultiMesh.set_instance_transform].
- </description>
- </method>
- <method name="multimesh_instance_set_transform_2d">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="index" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the [Transform2D] for this instance. For use when multimesh is used in 2D. Equivalent to [method MultiMesh.set_instance_transform_2d].
- </description>
- </method>
- <method name="multimesh_set_buffer">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="buffer" type="PackedFloat32Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_set_mesh">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="mesh" type="RID">
- </argument>
- <description>
- Sets the mesh to be drawn by the multimesh. Equivalent to [member MultiMesh.mesh].
- </description>
- </method>
- <method name="multimesh_set_visible_instances">
- <return type="void">
- </return>
- <argument index="0" name="multimesh" type="RID">
- </argument>
- <argument index="1" name="visible" type="int">
- </argument>
- <description>
- 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="omni_light_create">
- <return type="RID">
- </return>
- <description>
- Creates a new omni light and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID can be used in most [code]light_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this omni light to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="particles_create">
- <return type="RID">
- </return>
- <description>
- Creates a particle system and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]particles_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach these particles to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="particles_get_current_aabb">
- <return type="AABB">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <description>
- Calculates and returns the axis-aligned bounding box that contains all the particles. Equivalent to [method Particles.capture_aabb].
- </description>
- </method>
- <method name="particles_get_emitting">
- <return type="bool">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <description>
- Returns [code]true[/code] if particles are currently set to emitting.
- </description>
- </method>
- <method name="particles_is_inactive">
- <return type="bool">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <description>
- Returns [code]true[/code] if particles are not emitting and particles are set to inactive.
- </description>
- </method>
- <method name="particles_request_process">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <description>
- Add particle system to list of particle systems that need to be updated. Update will take place on the next frame, or on the next call to [method instances_cull_aabb], [method instances_cull_convex], or [method instances_cull_ray].
- </description>
- </method>
- <method name="particles_restart">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <description>
- Reset the particles on the next update. Equivalent to [method Particles.restart].
- </description>
- </method>
- <method name="particles_set_amount">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="amount" type="int">
- </argument>
- <description>
- Sets the number of particles to be drawn and allocates the memory for them. Equivalent to [member Particles.amount].
- </description>
- </method>
- <method name="particles_set_custom_aabb">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="aabb" type="AABB">
- </argument>
- <description>
- Sets a custom axis-aligned bounding box for the particle system. Equivalent to [member Particles.visibility_aabb].
- </description>
- </method>
- <method name="particles_set_draw_order">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="order" type="int" enum="VisualServer.ParticlesDrawOrder">
- </argument>
- <description>
- Sets the draw order of the particles to one of the named enums from [enum ParticlesDrawOrder]. See [enum ParticlesDrawOrder] for options. Equivalent to [member Particles.draw_order].
- </description>
- </method>
- <method name="particles_set_draw_pass_mesh">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="pass" type="int">
- </argument>
- <argument index="2" name="mesh" type="RID">
- </argument>
- <description>
- Sets the mesh to be used for the specified draw pass. Equivalent to [member Particles.draw_pass_1], [member Particles.draw_pass_2], [member Particles.draw_pass_3], and [member Particles.draw_pass_4].
- </description>
- </method>
- <method name="particles_set_draw_passes">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="count" type="int">
- </argument>
- <description>
- Sets the number of draw passes to use. Equivalent to [member Particles.draw_passes].
- </description>
- </method>
- <method name="particles_set_emission_transform">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- Sets the [Transform] that will be used by the particles when they first emit.
- </description>
- </method>
- <method name="particles_set_emitting">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="emitting" type="bool">
- </argument>
- <description>
- If [code]true[/code], particles will emit over time. Setting to false does not reset the particles, but only stops their emission. Equivalent to [member Particles.emitting].
- </description>
- </method>
- <method name="particles_set_explosiveness_ratio">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="ratio" type="float">
- </argument>
- <description>
- Sets the explosiveness ratio. Equivalent to [member Particles.explosiveness].
- </description>
- </method>
- <method name="particles_set_fixed_fps">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="fps" type="int">
- </argument>
- <description>
- Sets the frame rate that the particle system rendering will be fixed to. Equivalent to [member Particles.fixed_fps].
- </description>
- </method>
- <method name="particles_set_fractional_delta">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], uses fractional delta which smooths the movement of the particles. Equivalent to [member Particles.fract_delta].
- </description>
- </method>
- <method name="particles_set_lifetime">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="lifetime" type="float">
- </argument>
- <description>
- Sets the lifetime of each particle in the system. Equivalent to [member Particles.lifetime].
- </description>
- </method>
- <method name="particles_set_one_shot">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="one_shot" type="bool">
- </argument>
- <description>
- If [code]true[/code], particles will emit once and then stop. Equivalent to [member Particles.one_shot].
- </description>
- </method>
- <method name="particles_set_pre_process_time">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <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 Particles.preprocess].
- </description>
- </method>
- <method name="particles_set_process_material">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="material" type="RID">
- </argument>
- <description>
- Sets the material for processing the particles. Note: this is not the material used to draw the materials. Equivalent to [member Particles.process_material].
- </description>
- </method>
- <method name="particles_set_randomness_ratio">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="ratio" type="float">
- </argument>
- <description>
- Sets the emission randomness ratio. This randomizes the emission of particles within their phase. Equivalent to [member Particles.randomness].
- </description>
- </method>
- <method name="particles_set_speed_scale">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="scale" type="float">
- </argument>
- <description>
- Sets the speed scale of the particle system. Equivalent to [member Particles.speed_scale].
- </description>
- </method>
- <method name="particles_set_use_local_coordinates">
- <return type="void">
- </return>
- <argument index="0" name="particles" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], particles use local coordinates. If [code]false[/code] they use global coordinates. Equivalent to [member Particles.local_coords].
- </description>
- </method>
- <method name="reflection_probe_create">
- <return type="RID">
- </return>
- <description>
- Creates a reflection probe and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]reflection_probe_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this reflection probe to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="reflection_probe_set_as_interior">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], reflections will ignore sky contribution. Equivalent to [member ReflectionProbe.interior_enable].
- </description>
- </method>
- <method name="reflection_probe_set_cull_mask">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="layers" type="int">
- </argument>
- <description>
- Sets the render cull mask for this reflection probe. Only instances with a matching cull mask will be rendered by this probe. Equivalent to [member ReflectionProbe.cull_mask].
- </description>
- </method>
- <method name="reflection_probe_set_enable_box_projection">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], uses box projection. This can make reflections look more correct in certain situations. Equivalent to [member ReflectionProbe.box_projection].
- </description>
- </method>
- <method name="reflection_probe_set_enable_shadows">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- If [code]true[/code], computes shadows in the reflection probe. This makes the reflection much slower to compute. Equivalent to [member ReflectionProbe.enable_shadows].
- </description>
- </method>
- <method name="reflection_probe_set_extents">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="extents" type="Vector3">
- </argument>
- <description>
- Sets the size of the area that the reflection probe will capture. Equivalent to [member ReflectionProbe.extents].
- </description>
- </method>
- <method name="reflection_probe_set_intensity">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="intensity" type="float">
- </argument>
- <description>
- Sets the intensity of the reflection probe. Intensity modulates the strength of the reflection. Equivalent to [member ReflectionProbe.intensity].
- </description>
- </method>
- <method name="reflection_probe_set_interior_ambient">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Sets the ambient light color for this reflection probe when set to interior mode. Equivalent to [member ReflectionProbe.interior_ambient_color].
- </description>
- </method>
- <method name="reflection_probe_set_interior_ambient_energy">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="energy" type="float">
- </argument>
- <description>
- Sets the energy multiplier for this reflection probes ambient light contribution when set to interior mode. Equivalent to [member ReflectionProbe.interior_ambient_energy].
- </description>
- </method>
- <method name="reflection_probe_set_interior_ambient_probe_contribution">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="contrib" type="float">
- </argument>
- <description>
- Sets the contribution value for how much the reflection affects the ambient light for this reflection probe when set to interior mode. Useful so that ambient light matches the color of the room. Equivalent to [member ReflectionProbe.interior_ambient_contrib].
- </description>
- </method>
- <method name="reflection_probe_set_max_distance">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="distance" type="float">
- </argument>
- <description>
- Sets the max distance away from the probe an object can be before it is culled. Equivalent to [member ReflectionProbe.max_distance].
- </description>
- </method>
- <method name="reflection_probe_set_origin_offset">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="offset" type="Vector3">
- </argument>
- <description>
- Sets the origin offset to be used when this reflection probe is in box project mode. Equivalent to [member ReflectionProbe.origin_offset].
- </description>
- </method>
- <method name="reflection_probe_set_update_mode">
- <return type="void">
- </return>
- <argument index="0" name="probe" type="RID">
- </argument>
- <argument index="1" name="mode" type="int" enum="VisualServer.ReflectionProbeUpdateMode">
- </argument>
- <description>
- Sets how often the reflection probe updates. Can either be once or every frame. See [enum ReflectionProbeUpdateMode] for options.
- </description>
- </method>
- <method name="request_frame_drawn_callback">
- <return type="void">
- </return>
- <argument index="0" name="where" type="Object">
- </argument>
- <argument index="1" name="method" type="StringName">
- </argument>
- <argument index="2" name="userdata" type="Variant">
- </argument>
- <description>
- Schedules a callback to the corresponding named [code]method[/code] on [code]where[/code] after a frame has been drawn.
- The callback method must use only 1 argument which will be called with [code]userdata[/code].
- </description>
- </method>
- <method name="scenario_create">
- <return type="RID">
- </return>
- <description>
- Creates a scenario and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]scenario_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- The scenario is the 3D world that all the visual instances exist in.
- </description>
- </method>
- <method name="scenario_set_debug">
- <return type="void">
- </return>
- <argument index="0" name="scenario" type="RID">
- </argument>
- <argument index="1" name="debug_mode" type="int" enum="VisualServer.ScenarioDebugMode">
- </argument>
- <description>
- Sets the [enum ScenarioDebugMode] for this scenario. See [enum ScenarioDebugMode] for options.
- </description>
- </method>
- <method name="scenario_set_environment">
- <return type="void">
- </return>
- <argument index="0" name="scenario" type="RID">
- </argument>
- <argument index="1" name="environment" type="RID">
- </argument>
- <description>
- Sets the environment that will be used with this scenario.
- </description>
- </method>
- <method name="scenario_set_fallback_environment">
- <return type="void">
- </return>
- <argument index="0" name="scenario" type="RID">
- </argument>
- <argument index="1" name="environment" type="RID">
- </argument>
- <description>
- Sets the fallback environment to be used by this scenario. The fallback environment is used if no environment is set. Internally, this is used by the editor to provide a default environment.
- </description>
- </method>
- <method name="set_boot_image">
- <return type="void">
- </return>
- <argument index="0" name="image" type="Image">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <argument index="2" name="scale" type="bool">
- </argument>
- <argument index="3" name="use_filter" type="bool" default="true">
- </argument>
- <description>
- Sets a boot image. The color defines the background color. If [code]scale[/code] is [code]true[/code], the image will be scaled to fit the screen size. If [code]use_filter[/code] is [code]true[/code], the image will be scaled with linear interpolation. If [code]use_filter[/code] is [code]false[/code], the image will be scaled with nearest-neighbor interpolation.
- </description>
- </method>
- <method name="set_debug_generate_wireframes">
- <return type="void">
- </return>
- <argument index="0" name="generate" type="bool">
- </argument>
- <description>
- If [code]true[/code], the engine will generate wireframes for use with the wireframe debug mode.
- </description>
- </method>
- <method name="set_default_clear_color">
- <return type="void">
- </return>
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- Sets the default clear color which is used when a specific clear color has not been selected.
- </description>
- </method>
- <method name="shader_create">
- <return type="RID">
- </return>
- <description>
- Creates an empty shader and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]shader_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="shader_get_code" qualifiers="const">
- <return type="String">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- Returns a shader's code.
- </description>
- </method>
- <method name="shader_get_default_texture_param" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="name" type="StringName">
- </argument>
- <description>
- Returns a default texture from a shader searched by name.
- </description>
- </method>
- <method name="shader_get_param_default" qualifiers="const">
- <return type="Variant">
- </return>
- <argument index="0" name="material" type="RID">
- </argument>
- <argument index="1" name="parameter" type="StringName">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_param_list" qualifiers="const">
- <return type="Array">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- Returns the parameters of a shader.
- </description>
- </method>
- <method name="shader_set_code">
- <return type="void">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="code" type="String">
- </argument>
- <description>
- Sets a shader's code.
- </description>
- </method>
- <method name="shader_set_default_texture_param">
- <return type="void">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="name" type="StringName">
- </argument>
- <argument index="2" name="texture" type="RID">
- </argument>
- <description>
- Sets a shader's default texture. Overwrites the texture given by name.
- </description>
- </method>
- <method name="skeleton_allocate">
- <return type="void">
- </return>
- <argument index="0" name="skeleton" type="RID">
- </argument>
- <argument index="1" name="bones" type="int">
- </argument>
- <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">
- <return type="Transform">
- </return>
- <argument index="0" name="skeleton" type="RID">
- </argument>
- <argument index="1" name="bone" type="int">
- </argument>
- <description>
- Returns the [Transform] set for a specific bone of this skeleton.
- </description>
- </method>
- <method name="skeleton_bone_get_transform_2d" qualifiers="const">
- <return type="Transform2D">
- </return>
- <argument index="0" name="skeleton" type="RID">
- </argument>
- <argument index="1" name="bone" type="int">
- </argument>
- <description>
- Returns the [Transform2D] set for a specific bone of this skeleton.
- </description>
- </method>
- <method name="skeleton_bone_set_transform">
- <return type="void">
- </return>
- <argument index="0" name="skeleton" type="RID">
- </argument>
- <argument index="1" name="bone" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform">
- </argument>
- <description>
- Sets the [Transform] for a specific bone of this skeleton.
- </description>
- </method>
- <method name="skeleton_bone_set_transform_2d">
- <return type="void">
- </return>
- <argument index="0" name="skeleton" type="RID">
- </argument>
- <argument index="1" name="bone" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the [Transform2D] for a specific bone of this skeleton.
- </description>
- </method>
- <method name="skeleton_create">
- <return type="RID">
- </return>
- <description>
- Creates a skeleton and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]skeleton_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="skeleton_get_bone_count" qualifiers="const">
- <return type="int">
- </return>
- <argument index="0" name="skeleton" type="RID">
- </argument>
- <description>
- Returns the number of bones allocated for this skeleton.
- </description>
- </method>
- <method name="sky_create">
- <return type="RID">
- </return>
- <description>
- Creates an empty sky and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]sky_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="sky_set_texture">
- <return type="void">
- </return>
- <argument index="0" name="sky" type="RID">
- </argument>
- <argument index="1" name="panorama" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="spot_light_create">
- <return type="RID">
- </return>
- <description>
- Creates a spot light and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID can be used in most [code]light_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- To place in a scene, attach this spot light to an instance using [method instance_set_base] using the returned RID.
- </description>
- </method>
- <method name="texture_2d_create">
- <return type="RID">
- </return>
- <argument index="0" name="image" type="Image">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_2d_get" qualifiers="const">
- <return type="Image">
- </return>
- <argument index="0" name="texture" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_attach_camera">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="camera" type="RID">
- </argument>
- <description>
- Sets a viewport's camera.
- </description>
- </method>
- <method name="viewport_attach_canvas">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="canvas" type="RID">
- </argument>
- <description>
- Sets a viewport's canvas.
- </description>
- </method>
- <method name="viewport_attach_to_screen">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="rect" type="Rect2" default="Rect2( 0, 0, 0, 0 )">
- </argument>
- <argument index="2" name="screen" type="int" default="0">
- </argument>
- <description>
- Copies viewport to a region of the screen specified by [code]rect[/code]. If [member Viewport.render_direct_to_screen] is [code]true[/code], then 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]
- func _ready():
- get_viewport().set_attach_to_screen_rect(Rect2())
- $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))
- [/codeblock]
- 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>
- <method name="viewport_create">
- <return type="RID">
- </return>
- <description>
- Creates an empty viewport and adds it to the VisualServer. It can be accessed with the RID that is returned. This RID will be used in all [code]viewport_*[/code] VisualServer functions.
- Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
- </description>
- </method>
- <method name="viewport_detach">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <description>
- Detaches the viewport from the screen.
- </description>
- </method>
- <method name="viewport_get_render_info">
- <return type="int">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="info" type="int" enum="VisualServer.ViewportRenderInfo">
- </argument>
- <description>
- Returns a viewport's render information. For options, see the [enum ViewportRenderInfo] constants.
- </description>
- </method>
- <method name="viewport_get_texture" qualifiers="const">
- <return type="RID">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <description>
- Returns the viewport's last rendered frame.
- </description>
- </method>
- <method name="viewport_remove_canvas">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="canvas" type="RID">
- </argument>
- <description>
- Detaches a viewport from a canvas and vice versa.
- </description>
- </method>
- <method name="viewport_set_active">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="active" type="bool">
- </argument>
- <description>
- If [code]true[/code], sets the viewport active, else sets it inactive.
- </description>
- </method>
- <method name="viewport_set_canvas_stacking">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="canvas" type="RID">
- </argument>
- <argument index="2" name="layer" type="int">
- </argument>
- <argument index="3" name="sublayer" type="int">
- </argument>
- <description>
- Sets the stacking order for a viewport's canvas.
- [code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] specifies the stacking order of the canvas among those in the same layer.
- </description>
- </method>
- <method name="viewport_set_canvas_transform">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="canvas" type="RID">
- </argument>
- <argument index="2" name="offset" type="Transform2D">
- </argument>
- <description>
- Sets the transformation of a viewport's canvas.
- </description>
- </method>
- <method name="viewport_set_clear_mode">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="clear_mode" type="int" enum="VisualServer.ViewportClearMode">
- </argument>
- <description>
- Sets the clear mode of a viewport. See [enum ViewportClearMode] for options.
- </description>
- </method>
- <method name="viewport_set_debug_draw">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="draw" type="int" enum="VisualServer.ViewportDebugDraw">
- </argument>
- <description>
- Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for options.
- </description>
- </method>
- <method name="viewport_set_disable_environment">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="disabled" type="bool">
- </argument>
- <description>
- If [code]true[/code], rendering of a viewport's environment is disabled.
- </description>
- </method>
- <method name="viewport_set_global_canvas_transform">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform2D">
- </argument>
- <description>
- Sets the viewport's global transformation matrix.
- </description>
- </method>
- <method name="viewport_set_hide_canvas">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="hidden" type="bool">
- </argument>
- <description>
- If [code]true[/code], the viewport's canvas is not rendered.
- </description>
- </method>
- <method name="viewport_set_hide_scenario">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="hidden" type="bool">
- </argument>
- <description>
- Currently unimplemented in Godot 3.x.
- </description>
- </method>
- <method name="viewport_set_msaa">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="msaa" type="int" enum="VisualServer.ViewportMSAA">
- </argument>
- <description>
- Sets the anti-aliasing mode. See [enum ViewportMSAA] for options.
- </description>
- </method>
- <method name="viewport_set_parent_viewport">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="parent_viewport" type="RID">
- </argument>
- <description>
- Sets the viewport's parent to another viewport.
- </description>
- </method>
- <method name="viewport_set_render_direct_to_screen">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
- </description>
- </method>
- <method name="viewport_set_scenario">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="scenario" type="RID">
- </argument>
- <description>
- Sets a viewport's scenario.
- The scenario contains information about the [enum ScenarioDebugMode], environment information, reflection atlas etc.
- </description>
- </method>
- <method name="viewport_set_shadow_atlas_quadrant_subdivision">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="quadrant" type="int">
- </argument>
- <argument index="2" name="subdivision" type="int">
- </argument>
- <description>
- Sets the shadow atlas quadrant's subdivision.
- </description>
- </method>
- <method name="viewport_set_shadow_atlas_size">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="size" type="int">
- </argument>
- <description>
- Sets the size of the shadow atlas's images (used for omni and spot lights). The value will be rounded up to the nearest power of 2.
- </description>
- </method>
- <method name="viewport_set_size">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="width" type="int">
- </argument>
- <argument index="2" name="height" type="int">
- </argument>
- <description>
- Sets the viewport's width and height.
- </description>
- </method>
- <method name="viewport_set_transparent_background">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- If [code]true[/code], the viewport renders its background as transparent.
- </description>
- </method>
- <method name="viewport_set_update_mode">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="update_mode" type="int" enum="VisualServer.ViewportUpdateMode">
- </argument>
- <description>
- Sets when the viewport should be updated. See [enum ViewportUpdateMode] constants for options.
- </description>
- </method>
- <method name="viewport_set_use_arvr">
- <return type="void">
- </return>
- <argument index="0" name="viewport" type="RID">
- </argument>
- <argument index="1" name="use_arvr" type="bool">
- </argument>
- <description>
- If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [ARVRInterface].
- </description>
- </method>
- </methods>
- <signals>
- <signal name="frame_post_draw">
- <description>
- Emitted at the end of the frame, after the VisualServer has finished updating all the Viewports.
- </description>
- </signal>
- <signal name="frame_pre_draw">
- <description>
- Emitted at the beginning of the frame, before the VisualServer updates all the Viewports.
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NO_INDEX_ARRAY" value="-1">
- Marks an error that shows that the index array is empty.
- </constant>
- <constant name="ARRAY_WEIGHTS_SIZE" value="4">
- Number of weights/bones per vertex.
- </constant>
- <constant name="CANVAS_ITEM_Z_MIN" value="-4096">
- The minimum Z-layer for canvas items.
- </constant>
- <constant name="CANVAS_ITEM_Z_MAX" value="4096">
- The maximum Z-layer for canvas items.
- </constant>
- <constant name="MAX_GLOW_LEVELS" value="7">
- Max number of glow levels that can be used with glow post-process effect.
- </constant>
- <constant name="MAX_CURSORS" value="8">
- Unused enum in Godot 3.x.
- </constant>
- <constant name="MATERIAL_RENDER_PRIORITY_MIN" value="-128">
- The minimum renderpriority of all materials.
- </constant>
- <constant name="MATERIAL_RENDER_PRIORITY_MAX" value="127">
- The maximum renderpriority of all materials.
- </constant>
- <constant name="TEXTURE_LAYERED_2D_ARRAY" value="0" enum="TextureLayeredType">
- </constant>
- <constant name="TEXTURE_LAYERED_CUBEMAP" value="1" enum="TextureLayeredType">
- </constant>
- <constant name="TEXTURE_LAYERED_CUBEMAP_ARRAY" value="2" enum="TextureLayeredType">
- </constant>
- <constant name="CUBEMAP_LAYER_LEFT" value="0" enum="CubeMapLayer">
- </constant>
- <constant name="CUBEMAP_LAYER_RIGHT" value="1" enum="CubeMapLayer">
- </constant>
- <constant name="CUBEMAP_LAYER_BOTTOM" value="2" enum="CubeMapLayer">
- </constant>
- <constant name="CUBEMAP_LAYER_TOP" value="3" enum="CubeMapLayer">
- </constant>
- <constant name="CUBEMAP_LAYER_FRONT" value="4" enum="CubeMapLayer">
- </constant>
- <constant name="CUBEMAP_LAYER_BACK" value="5" enum="CubeMapLayer">
- </constant>
- <constant name="SHADER_SPATIAL" value="0" enum="ShaderMode">
- Shader is a 3D shader.
- </constant>
- <constant name="SHADER_CANVAS_ITEM" value="1" enum="ShaderMode">
- Shader is a 2D shader.
- </constant>
- <constant name="SHADER_PARTICLES" value="2" enum="ShaderMode">
- Shader is a particle shader.
- </constant>
- <constant name="SHADER_MAX" value="3" enum="ShaderMode">
- Represents the size of the [enum ShaderMode] enum.
- </constant>
- <constant name="ARRAY_VERTEX" value="0" enum="ArrayType">
- Array is a vertex array.
- </constant>
- <constant name="ARRAY_NORMAL" value="1" enum="ArrayType">
- Array is a normal array.
- </constant>
- <constant name="ARRAY_TANGENT" value="2" enum="ArrayType">
- Array is a tangent array.
- </constant>
- <constant name="ARRAY_COLOR" value="3" enum="ArrayType">
- Array is a color array.
- </constant>
- <constant name="ARRAY_TEX_UV" value="4" enum="ArrayType">
- Array is an UV coordinates array.
- </constant>
- <constant name="ARRAY_TEX_UV2" value="5" enum="ArrayType">
- Array is an UV coordinates array for the second UV coordinates.
- </constant>
- <constant name="ARRAY_BONES" value="6" enum="ArrayType">
- Array contains bone information.
- </constant>
- <constant name="ARRAY_WEIGHTS" value="7" enum="ArrayType">
- Array is weight information.
- </constant>
- <constant name="ARRAY_INDEX" value="8" enum="ArrayType">
- Array is index array.
- </constant>
- <constant name="ARRAY_MAX" value="9" enum="ArrayType">
- Represents the size of the [enum ArrayType] enum.
- </constant>
- <constant name="ARRAY_FORMAT_VERTEX" value="1" enum="ArrayFormat">
- Flag used to mark a vertex array.
- </constant>
- <constant name="ARRAY_FORMAT_NORMAL" value="2" enum="ArrayFormat">
- Flag used to mark a normal array.
- </constant>
- <constant name="ARRAY_FORMAT_TANGENT" value="4" enum="ArrayFormat">
- Flag used to mark a tangent array.
- </constant>
- <constant name="ARRAY_FORMAT_COLOR" value="8" enum="ArrayFormat">
- Flag used to mark a color array.
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV" value="16" enum="ArrayFormat">
- Flag used to mark an UV coordinates array.
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV2" value="32" enum="ArrayFormat">
- Flag used to mark an UV coordinates array for the second UV coordinates.
- </constant>
- <constant name="ARRAY_FORMAT_BONES" value="64" enum="ArrayFormat">
- Flag used to mark a bone information array.
- </constant>
- <constant name="ARRAY_FORMAT_WEIGHTS" value="128" enum="ArrayFormat">
- Flag used to mark a weights array.
- </constant>
- <constant name="ARRAY_FORMAT_INDEX" value="256" enum="ArrayFormat">
- Flag used to mark an index array.
- </constant>
- <constant name="ARRAY_COMPRESS_NORMAL" value="1024" enum="ArrayFormat">
- Flag used to mark a compressed (half float) normal array.
- </constant>
- <constant name="ARRAY_COMPRESS_TANGENT" value="2048" enum="ArrayFormat">
- Flag used to mark a compressed (half float) tangent array.
- </constant>
- <constant name="ARRAY_COMPRESS_COLOR" value="4096" enum="ArrayFormat">
- Flag used to mark a compressed (half float) color array.
- </constant>
- <constant name="ARRAY_COMPRESS_TEX_UV" value="8192" enum="ArrayFormat">
- Flag used to mark a compressed (half float) UV coordinates array.
- </constant>
- <constant name="ARRAY_COMPRESS_TEX_UV2" value="16384" enum="ArrayFormat">
- Flag used to mark a compressed (half float) UV coordinates array for the second UV coordinates.
- </constant>
- <constant name="ARRAY_COMPRESS_INDEX" value="131072" enum="ArrayFormat">
- Flag used to mark a compressed index array.
- </constant>
- <constant name="ARRAY_FLAG_USE_2D_VERTICES" value="262144" enum="ArrayFormat">
- Flag used to mark that the array contains 2D vertices.
- </constant>
- <constant name="ARRAY_FLAG_USE_DYNAMIC_UPDATE" value="1048576" enum="ArrayFormat">
- </constant>
- <constant name="ARRAY_COMPRESS_DEFAULT" value="31744" enum="ArrayFormat">
- Used to set flags [constant ARRAY_COMPRESS_NORMAL], [constant ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant ARRAY_COMPRESS_TEX_UV] and [constant ARRAY_COMPRESS_TEX_UV2] quickly.
- </constant>
- <constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType">
- Primitive to draw consists of points.
- </constant>
- <constant name="PRIMITIVE_LINES" value="1" enum="PrimitiveType">
- Primitive to draw consists of lines.
- </constant>
- <constant name="PRIMITIVE_LINE_STRIP" value="2" enum="PrimitiveType">
- Primitive to draw consists of a line strip from start to end.
- </constant>
- <constant name="PRIMITIVE_TRIANGLES" value="3" enum="PrimitiveType">
- Primitive to draw consists of triangles.
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_STRIP" value="4" enum="PrimitiveType">
- Primitive to draw consists of a triangle strip (the last 3 vertices are always combined to make a triangle).
- </constant>
- <constant name="PRIMITIVE_MAX" value="5" enum="PrimitiveType">
- Represents the size of the [enum PrimitiveType] enum.
- </constant>
- <constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode">
- Blend shapes are normalized.
- </constant>
- <constant name="BLEND_SHAPE_MODE_RELATIVE" value="1" enum="BlendShapeMode">
- Blend shapes are relative to base weight.
- </constant>
- <constant name="MULTIMESH_TRANSFORM_2D" value="0" enum="MultimeshTransformFormat">
- Use [Transform2D] to store MultiMesh transform.
- </constant>
- <constant name="MULTIMESH_TRANSFORM_3D" value="1" enum="MultimeshTransformFormat">
- Use [Transform] to store MultiMesh transform.
- </constant>
- <constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType">
- Is a directional (sun) light.
- </constant>
- <constant name="LIGHT_OMNI" value="1" enum="LightType">
- Is an omni light.
- </constant>
- <constant name="LIGHT_SPOT" value="2" enum="LightType">
- Is a spot light.
- </constant>
- <constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam">
- The light's energy.
- </constant>
- <constant name="LIGHT_PARAM_INDIRECT_ENERGY" value="1" enum="LightParam">
- </constant>
- <constant name="LIGHT_PARAM_SPECULAR" value="2" enum="LightParam">
- The light's influence on specularity.
- </constant>
- <constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam">
- The light's range.
- </constant>
- <constant name="LIGHT_PARAM_ATTENUATION" value="4" enum="LightParam">
- The light's attenuation.
- </constant>
- <constant name="LIGHT_PARAM_SPOT_ANGLE" value="5" enum="LightParam">
- The spotlight's angle.
- </constant>
- <constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="6" enum="LightParam">
- The spotlight's attenuation.
- </constant>
- <constant name="LIGHT_PARAM_CONTACT_SHADOW_SIZE" value="7" enum="LightParam">
- Scales the shadow color.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam">
- Max distance that shadows will be rendered.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="LightParam">
- Proportion of shadow atlas occupied by the first split.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="LightParam">
- Proportion of shadow atlas occupied by the second split.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="LightParam">
- Proportion of shadow atlas occupied by the third split. The fourth split occupies the rest.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_FADE_START" value="12" enum="LightParam">
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_NORMAL_BIAS" value="13" enum="LightParam">
- Normal bias used to offset shadow lookup by object normal. Can be used to fix self-shadowing artifacts.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_BIAS" value="14" enum="LightParam">
- Bias the shadow lookup to fix self-shadowing artifacts.
- </constant>
- <constant name="LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="LightParam">
- Increases bias on further splits to fix self-shadowing that only occurs far away from the camera.
- </constant>
- <constant name="LIGHT_PARAM_MAX" value="16" enum="LightParam">
- Represents the size of the [enum LightParam] enum.
- </constant>
- <constant name="LIGHT_OMNI_SHADOW_DUAL_PARABOLOID" value="0" enum="LightOmniShadowMode">
- Use a dual paraboloid shadow map for omni lights.
- </constant>
- <constant name="LIGHT_OMNI_SHADOW_CUBE" value="1" enum="LightOmniShadowMode">
- Use a cubemap shadow map for omni lights. Slower but better quality than dual paraboloid.
- </constant>
- <constant name="LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL" value="0" enum="LightDirectionalShadowMode">
- Use orthogonal shadow projection for directional light.
- </constant>
- <constant name="LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS" value="1" enum="LightDirectionalShadowMode">
- Use 2 splits for shadow projection when using directional light.
- </constant>
- <constant name="LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS" value="2" enum="LightDirectionalShadowMode">
- Use 4 splits for shadow projection when using directional light.
- </constant>
- <constant name="LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE" value="0" enum="LightDirectionalShadowDepthRangeMode">
- Keeps shadows stable as camera moves but has lower effective resolution.
- </constant>
- <constant name="LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="LightDirectionalShadowDepthRangeMode">
- Optimize use of shadow maps, increasing the effective resolution. But may result in shadows moving or flickering slightly.
- </constant>
- <constant name="REFLECTION_PROBE_UPDATE_ONCE" value="0" enum="ReflectionProbeUpdateMode">
- Reflection probe will update reflections once and then stop.
- </constant>
- <constant name="REFLECTION_PROBE_UPDATE_ALWAYS" value="1" enum="ReflectionProbeUpdateMode">
- Reflection probe will update each frame. This mode is necessary to capture moving objects.
- </constant>
- <constant name="PARTICLES_DRAW_ORDER_INDEX" value="0" enum="ParticlesDrawOrder">
- Draw particles in the order that they appear in the particles array.
- </constant>
- <constant name="PARTICLES_DRAW_ORDER_LIFETIME" value="1" enum="ParticlesDrawOrder">
- Sort particles based on their lifetime.
- </constant>
- <constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="2" enum="ParticlesDrawOrder">
- Sort particles based on their distance to the camera.
- </constant>
- <constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">
- Do not update the viewport.
- </constant>
- <constant name="VIEWPORT_UPDATE_ONCE" value="1" enum="ViewportUpdateMode">
- Update the viewport once then set to disabled.
- </constant>
- <constant name="VIEWPORT_UPDATE_WHEN_VISIBLE" value="2" enum="ViewportUpdateMode">
- Update the viewport whenever it is visible.
- </constant>
- <constant name="VIEWPORT_UPDATE_ALWAYS" value="3" enum="ViewportUpdateMode">
- Always update the viewport.
- </constant>
- <constant name="VIEWPORT_CLEAR_ALWAYS" value="0" enum="ViewportClearMode">
- The viewport is always cleared before drawing.
- </constant>
- <constant name="VIEWPORT_CLEAR_NEVER" value="1" enum="ViewportClearMode">
- The viewport is never cleared before drawing.
- </constant>
- <constant name="VIEWPORT_CLEAR_ONLY_NEXT_FRAME" value="2" enum="ViewportClearMode">
- The viewport is cleared once, then the clear mode is set to [constant VIEWPORT_CLEAR_NEVER].
- </constant>
- <constant name="VIEWPORT_MSAA_DISABLED" value="0" enum="ViewportMSAA">
- Multisample antialiasing is disabled.
- </constant>
- <constant name="VIEWPORT_MSAA_2X" value="1" enum="ViewportMSAA">
- Multisample antialiasing is set to 2×.
- </constant>
- <constant name="VIEWPORT_MSAA_4X" value="2" enum="ViewportMSAA">
- Multisample antialiasing is set to 4×.
- </constant>
- <constant name="VIEWPORT_MSAA_8X" value="3" enum="ViewportMSAA">
- Multisample antialiasing is set to 8×.
- </constant>
- <constant name="VIEWPORT_MSAA_16X" value="4" enum="ViewportMSAA">
- Multisample antialiasing is set to 16×.
- </constant>
- <constant name="VIEWPORT_MSAA_EXT_2X" value="5" enum="ViewportMSAA">
- Multisample antialiasing is set to 2× on external texture. Special mode for GLES2 Android VR (Oculus Quest and Go).
- </constant>
- <constant name="VIEWPORT_MSAA_EXT_4X" value="6" enum="ViewportMSAA">
- Multisample antialiasing is set to 4× on external texture. Special mode for GLES2 Android VR (Oculus Quest and Go).
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME" value="0" enum="ViewportRenderInfo">
- Number of objects drawn in a single frame.
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME" value="1" enum="ViewportRenderInfo">
- Number of vertices drawn in a single frame.
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="ViewportRenderInfo">
- Number of material changes during this frame.
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="ViewportRenderInfo">
- Number of shader changes during this frame.
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="ViewportRenderInfo">
- Number of surface changes during this frame.
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="5" enum="ViewportRenderInfo">
- Number of draw calls during this frame.
- </constant>
- <constant name="VIEWPORT_RENDER_INFO_MAX" value="6" enum="ViewportRenderInfo">
- Represents the size of the [enum ViewportRenderInfo] enum.
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_DISABLED" value="0" enum="ViewportDebugDraw">
- Debug draw is disabled. Default setting.
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_UNSHADED" value="1" enum="ViewportDebugDraw">
- Debug draw sets objects to unshaded.
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_LIGHTING" value="2" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_OVERDRAW" value="3" enum="ViewportDebugDraw">
- Overwrites clear color to [code](0,0,0,0)[/code].
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_WIREFRAME" value="4" enum="ViewportDebugDraw">
- Debug draw draws objects in wireframe.
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO" value="6" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING" value="7" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION" value="8" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS" value="9" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS" value="10" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE" value="11" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_SSAO" value="12" enum="ViewportDebugDraw">
- </constant>
- <constant name="VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER" value="13" enum="ViewportDebugDraw">
- </constant>
- <constant name="SKY_MODE_QUALITY" value="0" enum="SkyMode">
- </constant>
- <constant name="SKY_MODE_REALTIME" value="1" enum="SkyMode">
- </constant>
- <constant name="ENV_BG_CLEAR_COLOR" value="0" enum="EnvironmentBG">
- Use the clear color as background.
- </constant>
- <constant name="ENV_BG_COLOR" value="1" enum="EnvironmentBG">
- Use a specified color as the background.
- </constant>
- <constant name="ENV_BG_SKY" value="2" enum="EnvironmentBG">
- Use a sky resource for the background.
- </constant>
- <constant name="ENV_BG_CANVAS" value="3" enum="EnvironmentBG">
- Use a specified canvas layer as the background. This can be useful for instantiating a 2D scene in a 3D world.
- </constant>
- <constant name="ENV_BG_KEEP" value="4" enum="EnvironmentBG">
- Do not clear the background, use whatever was rendered last frame as the background.
- </constant>
- <constant name="ENV_BG_CAMERA_FEED" value="5" enum="EnvironmentBG">
- Displays a camera feed in the background.
- </constant>
- <constant name="ENV_BG_MAX" value="6" enum="EnvironmentBG">
- Represents the size of the [enum EnvironmentBG] enum.
- </constant>
- <constant name="ENV_AMBIENT_SOURCE_BG" value="0" enum="EnvironmentAmbientSource">
- </constant>
- <constant name="ENV_AMBIENT_SOURCE_DISABLED" value="1" enum="EnvironmentAmbientSource">
- </constant>
- <constant name="ENV_AMBIENT_SOURCE_COLOR" value="2" enum="EnvironmentAmbientSource">
- </constant>
- <constant name="ENV_AMBIENT_SOURCE_SKY" value="3" enum="EnvironmentAmbientSource">
- </constant>
- <constant name="ENV_REFLECTION_SOURCE_BG" value="0" enum="EnvironmentReflectionSource">
- </constant>
- <constant name="ENV_REFLECTION_SOURCE_DISABLED" value="1" enum="EnvironmentReflectionSource">
- </constant>
- <constant name="ENV_REFLECTION_SOURCE_SKY" value="2" enum="EnvironmentReflectionSource">
- </constant>
- <constant name="ENV_GLOW_BLEND_MODE_ADDITIVE" value="0" enum="EnvironmentGlowBlendMode">
- </constant>
- <constant name="ENV_GLOW_BLEND_MODE_SCREEN" value="1" enum="EnvironmentGlowBlendMode">
- </constant>
- <constant name="ENV_GLOW_BLEND_MODE_SOFTLIGHT" value="2" enum="EnvironmentGlowBlendMode">
- </constant>
- <constant name="ENV_GLOW_BLEND_MODE_REPLACE" value="3" enum="EnvironmentGlowBlendMode">
- </constant>
- <constant name="ENV_GLOW_BLEND_MODE_MIX" value="4" enum="EnvironmentGlowBlendMode">
- </constant>
- <constant name="ENV_TONE_MAPPER_LINEAR" value="0" enum="EnvironmentToneMapper">
- Output color as they came in.
- </constant>
- <constant name="ENV_TONE_MAPPER_REINHARD" value="1" enum="EnvironmentToneMapper">
- Use the Reinhard tonemapper.
- </constant>
- <constant name="ENV_TONE_MAPPER_FILMIC" value="2" enum="EnvironmentToneMapper">
- Use the filmic tonemapper.
- </constant>
- <constant name="ENV_TONE_MAPPER_ACES" value="3" enum="EnvironmentToneMapper">
- Use the ACES tonemapper.
- </constant>
- <constant name="ENV_SSAO_BLUR_DISABLED" value="0" enum="EnvironmentSSAOBlur">
- Disables the blur set for SSAO. Will make SSAO look noisier.
- </constant>
- <constant name="ENV_SSAO_BLUR_1x1" value="1" enum="EnvironmentSSAOBlur">
- Perform a 1x1 blur on the SSAO output.
- </constant>
- <constant name="ENV_SSAO_BLUR_2x2" value="2" enum="EnvironmentSSAOBlur">
- Performs a 2x2 blur on the SSAO output.
- </constant>
- <constant name="ENV_SSAO_BLUR_3x3" value="3" enum="EnvironmentSSAOBlur">
- Performs a 3x3 blur on the SSAO output. Use this for smoothest SSAO.
- </constant>
- <constant name="ENV_SSAO_QUALITY_LOW" value="0" enum="EnvironmentSSAOQuality">
- Lowest quality of screen space ambient occlusion.
- </constant>
- <constant name="ENV_SSAO_QUALITY_MEDIUM" value="1" enum="EnvironmentSSAOQuality">
- Medium quality screen space ambient occlusion.
- </constant>
- <constant name="ENV_SSAO_QUALITY_HIGH" value="2" enum="EnvironmentSSAOQuality">
- Highest quality screen space ambient occlusion.
- </constant>
- <constant name="ENV_SSAO_QUALITY_ULTRA" value="3" enum="EnvironmentSSAOQuality">
- </constant>
- <constant name="DOF_BLUR_QUALITY_VERY_LOW" value="0" enum="DOFBlurQuality">
- </constant>
- <constant name="DOF_BLUR_QUALITY_LOW" value="1" enum="DOFBlurQuality">
- </constant>
- <constant name="DOF_BLUR_QUALITY_MEDIUM" value="2" enum="DOFBlurQuality">
- </constant>
- <constant name="DOF_BLUR_QUALITY_HIGH" value="3" enum="DOFBlurQuality">
- </constant>
- <constant name="DOF_BOKEH_BOX" value="0" enum="DOFBokehShape">
- </constant>
- <constant name="DOF_BOKEH_HEXAGON" value="1" enum="DOFBokehShape">
- </constant>
- <constant name="DOF_BOKEH_CIRCLE" value="2" enum="DOFBokehShape">
- </constant>
- <constant name="SCENARIO_DEBUG_DISABLED" value="0" enum="ScenarioDebugMode">
- Do not use a debug mode.
- </constant>
- <constant name="SCENARIO_DEBUG_WIREFRAME" value="1" enum="ScenarioDebugMode">
- Draw all objects as wireframe models.
- </constant>
- <constant name="SCENARIO_DEBUG_OVERDRAW" value="2" enum="ScenarioDebugMode">
- Draw all objects in a way that displays how much overdraw is occurring. Overdraw occurs when a section of pixels is drawn and shaded and then another object covers it up. To optimize a scene, you should reduce overdraw.
- </constant>
- <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="INSTANCE_NONE" value="0" enum="InstanceType">
- The instance does not have a type.
- </constant>
- <constant name="INSTANCE_MESH" value="1" enum="InstanceType">
- The instance is a mesh.
- </constant>
- <constant name="INSTANCE_MULTIMESH" value="2" enum="InstanceType">
- The instance is a multimesh.
- </constant>
- <constant name="INSTANCE_IMMEDIATE" value="3" enum="InstanceType">
- The instance is an immediate geometry.
- </constant>
- <constant name="INSTANCE_PARTICLES" value="4" enum="InstanceType">
- The instance is a particle emitter.
- </constant>
- <constant name="INSTANCE_LIGHT" value="5" enum="InstanceType">
- The instance is a light.
- </constant>
- <constant name="INSTANCE_REFLECTION_PROBE" value="6" enum="InstanceType">
- The instance is a reflection probe.
- </constant>
- <constant name="INSTANCE_GI_PROBE" value="7" enum="InstanceType">
- The instance is a GI probe.
- </constant>
- <constant name="INSTANCE_LIGHTMAP_CAPTURE" value="8" enum="InstanceType">
- The instance is a lightmap capture.
- </constant>
- <constant name="INSTANCE_MAX" value="9" enum="InstanceType">
- Represents the size of the [enum InstanceType] enum.
- </constant>
- <constant name="INSTANCE_GEOMETRY_MASK" value="30" enum="InstanceType">
- A combination of the flags of geometry instances (mesh, multimesh, immediate and particles).
- </constant>
- <constant name="INSTANCE_FLAG_USE_BAKED_LIGHT" value="0" enum="InstanceFlags">
- Allows the instance to be used in baked lighting.
- </constant>
- <constant name="INSTANCE_FLAG_USE_DYNAMIC_GI" value="1" enum="InstanceFlags">
- </constant>
- <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">
- Represents the size of the [enum InstanceFlags] enum.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
- Disable shadows from this instance.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_ON" value="1" enum="ShadowCastingSetting">
- Cast shadows from this instance.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_DOUBLE_SIDED" value="2" enum="ShadowCastingSetting">
- Disable backface culling when rendering the shadow of the object. This is slightly slower but may result in more correct shadows.
- </constant>
- <constant name="SHADOW_CASTING_SETTING_SHADOWS_ONLY" value="3" enum="ShadowCastingSetting">
- Only render the shadows from the object. The object itself will not be drawn.
- </constant>
- <constant name="NINE_PATCH_STRETCH" value="0" enum="NinePatchAxisMode">
- The nine patch gets stretched where needed.
- </constant>
- <constant name="NINE_PATCH_TILE" value="1" enum="NinePatchAxisMode">
- The nine patch gets filled with tiles where needed.
- </constant>
- <constant name="NINE_PATCH_TILE_FIT" value="2" enum="NinePatchAxisMode">
- The nine patch gets filled with tiles where needed and stretches them a bit if needed.
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_DEFAULT" value="0" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST" value="1" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR" value="2" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS" value="3" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS" value="4" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_FILTER_MAX" value="7" enum="CanvasItemTextureFilter">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT" value="0" enum="CanvasItemTextureRepeat">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_REPEAT_DISABLED" value="1" enum="CanvasItemTextureRepeat">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_REPEAT_ENABLED" value="2" enum="CanvasItemTextureRepeat">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_REPEAT_MIRROR" value="3" enum="CanvasItemTextureRepeat">
- </constant>
- <constant name="CANVAS_ITEM_TEXTURE_REPEAT_MAX" value="4" enum="CanvasItemTextureRepeat">
- </constant>
- <constant name="CANVAS_LIGHT_MODE_ADD" value="0" enum="CanvasLightMode">
- Adds light color additive to the canvas.
- </constant>
- <constant name="CANVAS_LIGHT_MODE_SUB" value="1" enum="CanvasLightMode">
- Adds light color subtractive to the canvas.
- </constant>
- <constant name="CANVAS_LIGHT_MODE_MIX" value="2" enum="CanvasLightMode">
- The light adds color depending on transparency.
- </constant>
- <constant name="CANVAS_LIGHT_MODE_MASK" value="3" enum="CanvasLightMode">
- The light adds color depending on mask.
- </constant>
- <constant name="CANVAS_LIGHT_FILTER_NONE" value="0" enum="CanvasLightShadowFilter">
- Do not apply a filter to canvas light shadows.
- </constant>
- <constant name="CANVAS_LIGHT_FILTER_PCF5" value="1" enum="CanvasLightShadowFilter">
- Use PCF5 filtering to filter canvas light shadows.
- </constant>
- <constant name="CANVAS_LIGHT_FILTER_PCF13" value="2" enum="CanvasLightShadowFilter">
- Use PCF13 filtering to filter canvas light shadows.
- </constant>
- <constant name="CANVAS_LIGHT_FILTER_MAX" value="3" enum="CanvasLightShadowFilter">
- </constant>
- <constant name="CANVAS_OCCLUDER_POLYGON_CULL_DISABLED" value="0" enum="CanvasOccluderPolygonCullMode">
- Culling of the canvas occluder is disabled.
- </constant>
- <constant name="CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE" value="1" enum="CanvasOccluderPolygonCullMode">
- Culling of the canvas occluder is clockwise.
- </constant>
- <constant name="CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE" value="2" enum="CanvasOccluderPolygonCullMode">
- Culling of the canvas occluder is counterclockwise.
- </constant>
- <constant name="INFO_OBJECTS_IN_FRAME" value="0" enum="RenderInfo">
- The amount of objects in the frame.
- </constant>
- <constant name="INFO_VERTICES_IN_FRAME" value="1" enum="RenderInfo">
- The amount of vertices in the frame.
- </constant>
- <constant name="INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="RenderInfo">
- The amount of modified materials in the frame.
- </constant>
- <constant name="INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="RenderInfo">
- The amount of shader rebinds in the frame.
- </constant>
- <constant name="INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="RenderInfo">
- The amount of surface changes in the frame.
- </constant>
- <constant name="INFO_DRAW_CALLS_IN_FRAME" value="5" enum="RenderInfo">
- The amount of draw calls in frame.
- </constant>
- <constant name="INFO_USAGE_VIDEO_MEM_TOTAL" value="6" enum="RenderInfo">
- Unimplemented in the GLES2 rendering backend, always returns 0.
- </constant>
- <constant name="INFO_VIDEO_MEM_USED" value="7" enum="RenderInfo">
- The amount of video memory used, i.e. texture and vertex memory combined.
- </constant>
- <constant name="INFO_TEXTURE_MEM_USED" value="8" enum="RenderInfo">
- The amount of texture memory used.
- </constant>
- <constant name="INFO_VERTEX_MEM_USED" value="9" enum="RenderInfo">
- The amount of vertex memory used.
- </constant>
- <constant name="FEATURE_SHADERS" value="0" enum="Features">
- Hardware supports shaders. This enum is currently unused in Godot 3.x.
- </constant>
- <constant name="FEATURE_MULTITHREADED" value="1" enum="Features">
- Hardware supports multithreading. This enum is currently unused in Godot 3.x.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index 0dd8ec0064..40b0f52469 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -22,6 +22,7 @@
<argument index="3" name="id" type="int">
</argument>
<description>
+ Adds the specified node to the shader.
</description>
</method>
<method name="can_connect_nodes" qualifiers="const">
@@ -38,6 +39,7 @@
<argument index="4" name="to_port" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the specified nodes and ports can be connected together.
</description>
</method>
<method name="connect_nodes">
@@ -54,6 +56,7 @@
<argument index="4" name="to_port" type="int">
</argument>
<description>
+ Connects the specified nodes and ports.
</description>
</method>
<method name="connect_nodes_forced">
@@ -70,6 +73,7 @@
<argument index="4" name="to_port" type="int">
</argument>
<description>
+ Connects the specified nodes and ports, even if they can't be connected. Such connection is invalid and will not function properly.
</description>
</method>
<method name="disconnect_nodes">
@@ -86,6 +90,7 @@
<argument index="4" name="to_port" type="int">
</argument>
<description>
+ Connects the specified nodes and ports.
</description>
</method>
<method name="get_node" qualifiers="const">
@@ -96,6 +101,7 @@
<argument index="1" name="id" type="int">
</argument>
<description>
+ Returns the shader node instance with specified [code]type[/code] and [code]id[/code].
</description>
</method>
<method name="get_node_connections" qualifiers="const">
@@ -104,6 +110,7 @@
<argument index="0" name="type" type="int" enum="VisualShader.Type">
</argument>
<description>
+ Returns the list of connected nodes with the specified type.
</description>
</method>
<method name="get_node_list" qualifiers="const">
@@ -112,6 +119,7 @@
<argument index="0" name="type" type="int" enum="VisualShader.Type">
</argument>
<description>
+ Returns the list of all nodes in the shader with the specified type.
</description>
</method>
<method name="get_node_position" qualifiers="const">
@@ -122,6 +130,7 @@
<argument index="1" name="id" type="int">
</argument>
<description>
+ Returns the position of the specified node within the shader graph.
</description>
</method>
<method name="get_valid_node_id" qualifiers="const">
@@ -146,6 +155,7 @@
<argument index="4" name="to_port" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the specified node and port connection exist.
</description>
</method>
<method name="remove_node">
@@ -156,6 +166,7 @@
<argument index="1" name="id" type="int">
</argument>
<description>
+ Removes the specified node from the shader.
</description>
</method>
<method name="set_mode">
@@ -164,6 +175,7 @@
<argument index="0" name="mode" type="int" enum="Shader.Mode">
</argument>
<description>
+ Sets the mode of this shader.
</description>
</method>
<method name="set_node_position">
@@ -176,22 +188,27 @@
<argument index="2" name="position" type="Vector2">
</argument>
<description>
+ Sets the position of the specified node.
</description>
</method>
</methods>
<members>
<member name="code" type="String" setter="set_code" getter="get_code" override="true" default="&quot;shader_type spatial;void vertex() {// Output:0}void fragment() {// Output:0}void light() {// Output:0}&quot;" />
<member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2( 0, 0 )">
+ The offset vector of the whole graph.
</member>
<member name="version" type="String" setter="set_version" getter="get_version" default="&quot;&quot;">
</member>
</members>
<constants>
<constant name="TYPE_VERTEX" value="0" enum="Type">
+ A vertex shader, operating on vertices.
</constant>
<constant name="TYPE_FRAGMENT" value="1" enum="Type">
+ A fragment shader, operating on fragments (pixels).
</constant>
<constant name="TYPE_LIGHT" value="2" enum="Type">
+ A shader for light calculations.
</constant>
<constant name="TYPE_MAX" value="3" enum="Type">
Represents the size of the [enum Type] enum.
diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml
index 72ce743656..28d13a7d32 100644
--- a/doc/classes/VisualShaderNode.xml
+++ b/doc/classes/VisualShaderNode.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNode" inherits="Resource" version="4.0">
<brief_description>
+ Base class for nodes in a visual shader graph.
</brief_description>
<description>
</description>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
new file mode 100644
index 0000000000..e1a0f1f22a
--- /dev/null
+++ b/doc/classes/Window.xml
@@ -0,0 +1,419 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Window" inherits="Viewport" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="can_draw" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="child_controls_changed">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_flag" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Window.Flags">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_real_size" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_constant" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_font" qualifiers="const">
+ <return type="Font">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_icon" qualifiers="const">
+ <return type="Texture2D">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_stylebox" qualifiers="const">
+ <return type="StyleBox">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="grab_focus">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="has_focus" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="has_theme_color" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_theme_constant" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_theme_font" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_theme_icon" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_theme_stylebox" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="StringName" default="&quot;&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="hide">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_embedded" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_maximize_allowed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_using_font_oversampling" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="move_to_foreground">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="popup">
+ <return type="void">
+ </return>
+ <argument index="0" name="rect" type="Rect2i" default="Rect2i( 0, 0, 0, 0 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="popup_centered">
+ <return type="void">
+ </return>
+ <argument index="0" name="minsize" type="Vector2i" default="Vector2i( 0, 0 )">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="popup_centered_clamped">
+ <return type="void">
+ </return>
+ <argument index="0" name="minsize" type="Vector2i" default="Vector2i( 0, 0 )">
+ </argument>
+ <argument index="1" name="fallback_ratio" type="float" default="0.75">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="popup_centered_ratio">
+ <return type="void">
+ </return>
+ <argument index="0" name="ratio" type="float" default="0.8">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="popup_on_parent">
+ <return type="void">
+ </return>
+ <argument index="0" name="parent_rect" type="Rect2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="request_attention">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_flag">
+ <return type="void">
+ </return>
+ <argument index="0" name="flag" type="int" enum="Window.Flags">
+ </argument>
+ <argument index="1" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_ime_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_ime_position">
+ <return type="void">
+ </return>
+ <argument index="0" name="arg0" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_use_font_oversampling">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="show">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="always_on_top" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
+ <member name="borderless" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
+ <member name="content_scale_aspect" type="int" setter="set_content_scale_aspect" getter="get_content_scale_aspect" enum="Window.ContentScaleAspect" default="0">
+ </member>
+ <member name="content_scale_mode" type="int" setter="set_content_scale_mode" getter="get_content_scale_mode" enum="Window.ContentScaleMode" default="0">
+ </member>
+ <member name="content_scale_size" type="Vector2i" setter="set_content_scale_size" getter="get_content_scale_size" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen" default="0">
+ </member>
+ <member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false">
+ </member>
+ <member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="Window.Mode" default="0">
+ </member>
+ <member name="position" type="Vector2i" setter="set_position" getter="get_position" default="Vector2i( 0, 0 )">
+ </member>
+ <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i( 100, 100 )">
+ </member>
+ <member name="theme" type="Theme" setter="set_theme" getter="get_theme">
+ </member>
+ <member name="title" type="String" setter="set_title" getter="get_title" default="&quot;&quot;">
+ </member>
+ <member name="transient" type="bool" setter="set_transient" getter="is_transient" default="false">
+ </member>
+ <member name="transparent" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
+ <member name="unfocusable" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
+ <member name="unresizable" type="bool" setter="set_flag" getter="get_flag" default="false">
+ </member>
+ <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
+ </member>
+ <member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" default="false">
+ </member>
+ </members>
+ <signals>
+ <signal name="about_to_popup">
+ <description>
+ </description>
+ </signal>
+ <signal name="close_requested">
+ <description>
+ </description>
+ </signal>
+ <signal name="files_dropped">
+ <argument index="0" name="files" type="PackedStringArray">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="focus_entered">
+ <description>
+ </description>
+ </signal>
+ <signal name="focus_exited">
+ <description>
+ </description>
+ </signal>
+ <signal name="go_back_requested">
+ <description>
+ </description>
+ </signal>
+ <signal name="mouse_entered">
+ <description>
+ </description>
+ </signal>
+ <signal name="mouse_exited">
+ <description>
+ </description>
+ </signal>
+ <signal name="visibility_changed">
+ <description>
+ </description>
+ </signal>
+ <signal name="window_input">
+ <argument index="0" name="event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="30">
+ </constant>
+ <constant name="MODE_WINDOWED" value="0" enum="Mode">
+ </constant>
+ <constant name="MODE_MINIMIZED" value="1" enum="Mode">
+ </constant>
+ <constant name="MODE_MAXIMIZED" value="2" enum="Mode">
+ </constant>
+ <constant name="MODE_FULLSCREEN" value="3" enum="Mode">
+ </constant>
+ <constant name="FLAG_RESIZE_DISABLED" value="0" enum="Flags">
+ </constant>
+ <constant name="FLAG_BORDERLESS" value="1" enum="Flags">
+ </constant>
+ <constant name="FLAG_ALWAYS_ON_TOP" value="2" enum="Flags">
+ </constant>
+ <constant name="FLAG_TRANSPARENT" value="3" enum="Flags">
+ </constant>
+ <constant name="FLAG_NO_FOCUS" value="4" enum="Flags">
+ </constant>
+ <constant name="FLAG_MAX" value="5" enum="Flags">
+ </constant>
+ <constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
+ </constant>
+ <constant name="CONTENT_SCALE_MODE_OBJECTS" value="1" enum="ContentScaleMode">
+ </constant>
+ <constant name="CONTENT_SCALE_MODE_PIXELS" value="2" enum="ContentScaleMode">
+ </constant>
+ <constant name="CONTENT_SCALE_ASPECT_IGNORE" value="0" enum="ContentScaleAspect">
+ </constant>
+ <constant name="CONTENT_SCALE_ASPECT_KEEP" value="1" enum="ContentScaleAspect">
+ </constant>
+ <constant name="CONTENT_SCALE_ASPECT_KEEP_WIDTH" value="2" enum="ContentScaleAspect">
+ </constant>
+ <constant name="CONTENT_SCALE_ASPECT_KEEP_HEIGHT" value="3" enum="ContentScaleAspect">
+ </constant>
+ <constant name="CONTENT_SCALE_ASPECT_EXPAND" value="4" enum="ContentScaleAspect">
+ </constant>
+ </constants>
+ <theme_items>
+ <theme_item name="close" type="Texture2D">
+ </theme_item>
+ <theme_item name="close_h_ofs" type="int" default="18">
+ </theme_item>
+ <theme_item name="close_highlight" type="Texture2D">
+ </theme_item>
+ <theme_item name="close_v_ofs" type="int" default="18">
+ </theme_item>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ <theme_item name="resize_margin" type="int" default="4">
+ </theme_item>
+ <theme_item name="scaleborder_size" type="int" default="4">
+ </theme_item>
+ <theme_item name="title_color" type="Color" default="Color( 0, 0, 0, 1 )">
+ </theme_item>
+ <theme_item name="title_font" type="Font">
+ </theme_item>
+ <theme_item name="title_height" type="int" default="20">
+ </theme_item>
+ <theme_item name="window_panel" type="StyleBox">
+ </theme_item>
+ </theme_items>
+</class>
diff --git a/doc/classes/WindowDialog.xml b/doc/classes/WindowDialog.xml
deleted file mode 100644
index 16b8085df3..0000000000
--- a/doc/classes/WindowDialog.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WindowDialog" inherits="Popup" version="4.0">
- <brief_description>
- Base class for window dialogs.
- </brief_description>
- <description>
- Windowdialog is the base class for all window-based dialogs. It's a by-default toplevel [Control] that draws a window decoration and allows motion and resizing.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_close_button">
- <return type="TextureButton">
- </return>
- <description>
- Returns the close [TextureButton].
- </description>
- </method>
- </methods>
- <members>
- <member name="resizable" type="bool" setter="set_resizable" getter="get_resizable" default="false">
- If [code]true[/code], the user can resize the window.
- </member>
- <member name="window_title" type="String" setter="set_title" getter="get_title" default="&quot;&quot;">
- The text displayed in the window's title bar.
- </member>
- </members>
- <constants>
- </constants>
- <theme_items>
- <theme_item name="close" type="Texture2D">
- </theme_item>
- <theme_item name="close_h_ofs" type="int" default="18">
- </theme_item>
- <theme_item name="close_highlight" type="Texture2D">
- </theme_item>
- <theme_item name="close_v_ofs" type="int" default="18">
- </theme_item>
- <theme_item name="panel" type="StyleBox">
- </theme_item>
- <theme_item name="scaleborder_size" type="int" default="4">
- </theme_item>
- <theme_item name="title_color" type="Color" default="Color( 0, 0, 0, 1 )">
- </theme_item>
- <theme_item name="title_font" type="Font">
- </theme_item>
- <theme_item name="title_height" type="int" default="20">
- </theme_item>
- </theme_items>
-</class>
diff --git a/doc/classes/World.xml b/doc/classes/World.xml
deleted file mode 100644
index 48596c87d0..0000000000
--- a/doc/classes/World.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="World" inherits="Resource" version="4.0">
- <brief_description>
- Class that has everything pertaining to a world.
- </brief_description>
- <description>
- Class that has everything pertaining to a world. A physics space, a visual scenario and a sound space. Spatial nodes register their resources into the current world.
- </description>
- <tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="camera_effects" type="CameraEffects" setter="set_camera_effects" getter="get_camera_effects">
- </member>
- <member name="direct_space_state" type="PhysicsDirectSpaceState" setter="" getter="get_direct_space_state">
- The World's physics direct space state, used for making various queries. Might be used only during [code]_physics_process[/code].
- </member>
- <member name="environment" type="Environment" setter="set_environment" getter="get_environment">
- The World's [Environment].
- </member>
- <member name="fallback_environment" type="Environment" setter="set_fallback_environment" getter="get_fallback_environment">
- The World's fallback_environment will be used if the World's [Environment] fails or is missing.
- </member>
- <member name="scenario" type="RID" setter="" getter="get_scenario">
- The World's visual scenario.
- </member>
- <member name="space" type="RID" setter="" getter="get_space">
- The World's physics space.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/World2D.xml b/doc/classes/World2D.xml
index 9e2d4cfde3..2d8382b7e3 100644
--- a/doc/classes/World2D.xml
+++ b/doc/classes/World2D.xml
@@ -13,13 +13,13 @@
</methods>
<members>
<member name="canvas" type="RID" setter="" getter="get_canvas">
- The [RID] of this world's canvas resource. Used by the [VisualServer] for 2D drawing.
+ The [RID] of this world's canvas resource. Used by the [RenderingServer] for 2D drawing.
</member>
- <member name="direct_space_state" type="Physics2DDirectSpaceState" setter="" getter="get_direct_space_state">
+ <member name="direct_space_state" type="PhysicsDirectSpaceState2D" setter="" getter="get_direct_space_state">
The state of this world's physics space. This allows arbitrary querying for collision.
</member>
<member name="space" type="RID" setter="" getter="get_space">
- The [RID] of this world's physics space resource. Used by the [Physics2DServer] for 2D physics, treating it as both a space and an area.
+ 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>
</members>
<constants>
diff --git a/doc/classes/World3D.xml b/doc/classes/World3D.xml
new file mode 100644
index 0000000000..4224a2a2c3
--- /dev/null
+++ b/doc/classes/World3D.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="World3D" inherits="Resource" version="4.0">
+ <brief_description>
+ Class that has everything pertaining to a world.
+ </brief_description>
+ <description>
+ Class that has everything pertaining to a world. A physics space, a visual scenario and a sound space. Node3D nodes register their resources into the current world.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="camera_effects" type="CameraEffects" setter="set_camera_effects" getter="get_camera_effects">
+ </member>
+ <member name="direct_space_state" type="PhysicsDirectSpaceState3D" setter="" getter="get_direct_space_state">
+ The World3D's physics direct space state, used for making various queries. Might be used only during [code]_physics_process[/code].
+ </member>
+ <member name="environment" type="Environment" setter="set_environment" getter="get_environment">
+ The World3D's [Environment].
+ </member>
+ <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="scenario" type="RID" setter="" getter="get_scenario">
+ The World3D's visual scenario.
+ </member>
+ <member name="space" type="RID" setter="" getter="get_space">
+ The World3D's physics space.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml
index 73500868a8..92b75621c2 100644
--- a/doc/classes/WorldEnvironment.xml
+++ b/doc/classes/WorldEnvironment.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
The [WorldEnvironment] node is used to configure the default [Environment] for the scene.
- The parameters defined in the [WorldEnvironment] can be overridden by an [Environment] node set on the current [Camera]. Additionally, only one [WorldEnvironment] may be instanced in a given scene at a time.
+ The parameters defined in the [WorldEnvironment] can be overridden by an [Environment] node set on the current [Camera3D]. Additionally, only one [WorldEnvironment] may be instanced in a given scene at a time.
The [WorldEnvironment] allows the user to specify default lighting parameters (e.g. ambient lighting), various post-processing effects (e.g. SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, skybox). Usually, these are added in order to improve the realism/color balance of the scene.
</description>
<tutorials>
diff --git a/doc/classes/WorldMarginShape.xml b/doc/classes/WorldMarginShape.xml
deleted file mode 100644
index 54f76a066b..0000000000
--- a/doc/classes/WorldMarginShape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WorldMarginShape" inherits="Shape" version="4.0">
- <brief_description>
- Infinite plane shape for 3D collisions.
- </brief_description>
- <description>
- An infinite plane shape for 3D collisions. Note that the [Plane]'s normal matters; anything "below" the plane will collide with it. If the [WorldMarginShape] is used in a [PhysicsBody], it will cause colliding objects placed "below" it to teleport "above" the plane.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="plane" type="Plane" setter="set_plane" getter="get_plane" default="Plane( 0, 1, 0, 0 )">
- The [Plane] used by the [WorldMarginShape] for collision.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/WorldMarginShape3D.xml b/doc/classes/WorldMarginShape3D.xml
new file mode 100644
index 0000000000..a91447056b
--- /dev/null
+++ b/doc/classes/WorldMarginShape3D.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="WorldMarginShape3D" inherits="Shape3D" version="4.0">
+ <brief_description>
+ Infinite plane shape for 3D collisions.
+ </brief_description>
+ <description>
+ An infinite plane shape for 3D collisions. Note that the [Plane]'s normal matters; anything "below" the plane will collide with it. If the [WorldMarginShape3D] is used in a [PhysicsBody3D], it will cause colliding objects placed "below" it to teleport "above" the plane.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="plane" type="Plane" setter="set_plane" getter="get_plane" default="Plane( 0, 1, 0, 0 )">
+ The [Plane] used by the [WorldMarginShape3D] for collision.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/XRAnchor3D.xml b/doc/classes/XRAnchor3D.xml
new file mode 100644
index 0000000000..a409c79230
--- /dev/null
+++ b/doc/classes/XRAnchor3D.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRAnchor3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ An anchor point in AR space.
+ </brief_description>
+ <description>
+ The [XRAnchor3D] point is a spatial node that maps a real world location identified by the AR platform to a position within the game world. For example, as long as plane detection in ARKit is on, ARKit will identify and update the position of planes (tables, floors, etc) and create anchors for them.
+ This node is mapped to one of the anchors through its unique ID. When you receive a signal that a new anchor is available, you should add this node to your scene for that anchor. You can predefine nodes and set the ID; the nodes will simply remain on 0,0,0 until a plane is recognized.
+ Keep in mind that, as long as plane detection is enabled, the size, placing and orientation of an anchor will be updated as the detection logic learns more about the real world out there especially if only part of the surface is in view.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_anchor_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Returns the name given to this anchor.
+ </description>
+ </method>
+ <method name="get_is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the anchor is being tracked and [code]false[/code] if no anchor with this ID is currently known.
+ </description>
+ </method>
+ <method name="get_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <description>
+ If provided by the [XRInterface], this returns a mesh object for the anchor. For an anchor, this can be a shape related to the object being tracked or it can be a mesh that provides topology related to the anchor and can be used to create shadows/reflections on surfaces or for generating collision shapes.
+ </description>
+ </method>
+ <method name="get_plane" qualifiers="const">
+ <return type="Plane">
+ </return>
+ <description>
+ Returns a plane aligned with our anchor; handy for intersection testing.
+ </description>
+ </method>
+ <method name="get_size" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the estimated size of the plane that was detected. Say when the anchor relates to a table in the real world, this is the estimated size of the surface of that table.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="anchor_id" type="int" setter="set_anchor_id" getter="get_anchor_id" default="1">
+ The anchor's ID. You can set this before the anchor itself exists. The first anchor gets an ID of [code]1[/code], the second an ID of [code]2[/code], etc. When anchors get removed, the engine can then assign the corresponding ID to new anchors. The most common situation where anchors "disappear" is when the AR server identifies that two anchors represent different parts of the same plane and merges them.
+ </member>
+ </members>
+ <signals>
+ <signal name="mesh_updated">
+ <argument index="0" name="mesh" type="Mesh">
+ </argument>
+ <description>
+ Emitted when the mesh associated with the anchor changes or when one becomes available. This is especially important for topology that is constantly being [code]mesh_updated[/code].
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/XRCamera3D.xml b/doc/classes/XRCamera3D.xml
new file mode 100644
index 0000000000..4d86e24daa
--- /dev/null
+++ b/doc/classes/XRCamera3D.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRCamera3D" inherits="Camera3D" version="4.0">
+ <brief_description>
+ A camera node with a few overrules for AR/VR applied, such as location tracking.
+ </brief_description>
+ <description>
+ This is a helper spatial node for our camera; note that, if stereoscopic rendering is applicable (VR-HMD), most of the camera properties are ignored, as the HMD information overrides them. The only properties that can be trusted are the near and far planes.
+ The position and orientation of this node is automatically updated by the XR Server to represent the location of the HMD if such tracking is available and can thus be used by game logic. Note that, in contrast to the XR Controller, the render thread has access to the most up-to-date tracking data of the HMD and the location of the XRCamera3D can lag a few milliseconds behind what is used for rendering as a result.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml
new file mode 100644
index 0000000000..e4a06a80db
--- /dev/null
+++ b/doc/classes/XRController3D.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRController3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ A spatial node representing a spatially-tracked controller.
+ </brief_description>
+ <description>
+ This is a helper spatial node that is linked to the tracking of controllers. It also offers several handy passthroughs to the state of buttons and such on the controllers.
+ Controllers are linked by their ID. You can create controller nodes before the controllers are available. If your game always uses two controllers (one for each hand), you can predefine the controllers with ID 1 and 2; they will become active as soon as the controllers are identified. If you expect additional controllers to be used, you should react to the signals and add XRController3D nodes to your scene.
+ The position of the controller node is automatically updated by the [XRServer]. This makes this node ideal to add child nodes to visualize the controller.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ </tutorials>
+ <methods>
+ <method name="get_controller_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ If active, returns the name of the associated controller if provided by the AR/VR SDK used.
+ </description>
+ </method>
+ <method name="get_hand" qualifiers="const">
+ <return type="int" enum="XRPositionalTracker.TrackerHand">
+ </return>
+ <description>
+ Returns the hand holding this controller, if known. See [enum XRPositionalTracker.TrackerHand].
+ </description>
+ </method>
+ <method name="get_is_active" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the bound controller is active. XR systems attempt to track active controllers.
+ </description>
+ </method>
+ <method name="get_joystick_axis" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="axis" type="int">
+ </argument>
+ <description>
+ Returns the value of the given axis for things like triggers, touchpads, etc. that are embedded into the controller.
+ </description>
+ </method>
+ <method name="get_joystick_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the ID of the joystick object bound to this. Every controller tracked by the [XRServer] that has buttons and axis will also be registered as a joystick within Godot. This means that all the normal joystick tracking and input mapping will work for buttons and axis found on the AR/VR controllers. This ID is purely offered as information so you can link up the controller with its joystick entry.
+ </description>
+ </method>
+ <method name="get_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <description>
+ If provided by the [XRInterface], this returns a mesh associated with the controller. This can be used to visualize the controller.
+ </description>
+ </method>
+ <method name="is_button_pressed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <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 JoystickList], in particular the [code]JOY_VR_*[/code] constants.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="controller_id" type="int" setter="set_controller_id" getter="get_controller_id" default="1">
+ The controller's ID.
+ A controller ID of 0 is unbound and will always result in an inactive node. Controller ID 1 is reserved for the first controller that identifies itself as the left-hand controller and ID 2 is reserved for the first controller that identifies itself as the right-hand controller.
+ For any other controller that the [XRServer] detects, we continue with controller ID 3.
+ When a controller is turned off, its slot is freed. This ensures controllers will keep the same ID even when controllers with lower IDs are turned off.
+ </member>
+ <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0">
+ The degree to which the controller vibrates. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code]. If changed, updates [member XRPositionalTracker.rumble] accordingly.
+ This is a useful property to animate if you want the controller to vibrate for a limited duration.
+ </member>
+ </members>
+ <signals>
+ <signal name="button_pressed">
+ <argument index="0" name="button" type="int">
+ </argument>
+ <description>
+ Emitted when a button on this controller is pressed.
+ </description>
+ </signal>
+ <signal name="button_release">
+ <argument index="0" name="button" type="int">
+ </argument>
+ <description>
+ Emitted when a button on this controller is released.
+ </description>
+ </signal>
+ <signal name="mesh_updated">
+ <argument index="0" name="mesh" type="Mesh">
+ </argument>
+ <description>
+ Emitted when the mesh associated with the controller changes or when one becomes available. Generally speaking this will be a static mesh after becoming available.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
new file mode 100644
index 0000000000..1985010223
--- /dev/null
+++ b/doc/classes/XRInterface.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRInterface" inherits="Reference" version="4.0">
+ <brief_description>
+ Base class for an AR/VR interface implementation.
+ </brief_description>
+ <description>
+ This class needs to be implemented to make an AR or VR platform available to Godot and these should be implemented as C++ modules or GDNative modules (note that for GDNative the subclass XRScriptInterface should be used). Part of the interface is exposed to GDScript so you can detect, enable and configure an AR or VR platform.
+ Interfaces should be written in such a way that simply enabling them will give us a working setup. You can query the available interfaces through [XRServer].
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ </tutorials>
+ <methods>
+ <method name="get_camera_feed_id">
+ <return type="int">
+ </return>
+ <description>
+ If this is an AR interface that requires displaying a camera feed as the background, this method returns the feed ID in the [CameraServer] for this interface.
+ </description>
+ </method>
+ <method name="get_capabilities" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns a combination of [enum Capabilities] flags providing information about the capabilities of this interface.
+ </description>
+ </method>
+ <method name="get_name" qualifiers="const">
+ <return type="StringName">
+ </return>
+ <description>
+ Returns the name of this interface (OpenVR, OpenHMD, ARKit, etc).
+ </description>
+ </method>
+ <method name="get_render_targetsize">
+ <return type="Vector2">
+ </return>
+ <description>
+ Returns the resolution at which we should render our intermediate results before things like lens distortion are applied by the VR platform.
+ </description>
+ </method>
+ <method name="get_tracking_status" qualifiers="const">
+ <return type="int" enum="XRInterface.Tracking_status">
+ </return>
+ <description>
+ If supported, returns the status of our tracking. This will allow you to provide feedback to the user whether there are issues with positional tracking.
+ </description>
+ </method>
+ <method name="initialize">
+ <return type="bool">
+ </return>
+ <description>
+ Call this to initialize this interface. The first interface that is initialized is identified as the primary interface and it will be used for rendering output.
+ After initializing the interface you want to use you then need to enable the AR/VR mode of a viewport and rendering should commence.
+ [b]Note:[/b] You must enable the AR/VR mode on the main viewport for any device that uses the main output of Godot, such as for mobile VR.
+ If you do this for a platform that handles its own output (such as OpenVR) Godot will show just one eye without distortion on screen. Alternatively, you can add a separate viewport node to your scene and enable AR/VR on that viewport. It will be used to output to the HMD, leaving you free to do anything you like in the main window, such as using a separate camera as a spectator camera or rendering something completely different.
+ While currently not used, you can activate additional interfaces. You may wish to do this if you want to track controllers from other platforms. However, at this point in time only one interface can render to an HMD.
+ </description>
+ </method>
+ <method name="is_stereo">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the current output of this interface is in stereo.
+ </description>
+ </method>
+ <method name="uninitialize">
+ <return type="void">
+ </return>
+ <description>
+ Turns the interface off.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="ar_is_anchor_detection_enabled" type="bool" setter="set_anchor_detection_is_enabled" getter="get_anchor_detection_is_enabled" default="false">
+ On an AR interface, [code]true[/code] if anchor detection is enabled.
+ </member>
+ <member name="interface_is_initialized" type="bool" setter="set_is_initialized" getter="is_initialized" default="false">
+ [code]true[/code] if this interface been initialized.
+ </member>
+ <member name="interface_is_primary" type="bool" setter="set_is_primary" getter="is_primary" default="false">
+ [code]true[/code] if this is the primary interface.
+ </member>
+ </members>
+ <constants>
+ <constant name="XR_NONE" value="0" enum="Capabilities">
+ No XR capabilities.
+ </constant>
+ <constant name="XR_MONO" value="1" enum="Capabilities">
+ This interface can work with normal rendering output (non-HMD based AR).
+ </constant>
+ <constant name="XR_STEREO" value="2" enum="Capabilities">
+ This interface supports stereoscopic rendering.
+ </constant>
+ <constant name="XR_AR" value="4" enum="Capabilities">
+ This interface supports AR (video background and real world tracking).
+ </constant>
+ <constant name="XR_EXTERNAL" value="8" enum="Capabilities">
+ This interface outputs to an external device. If the main viewport is used, the on screen output is an unmodified buffer of either the left or right eye (stretched if the viewport size is not changed to the same aspect ratio of [method get_render_targetsize]). Using a separate viewport node frees up the main viewport for other purposes.
+ </constant>
+ <constant name="EYE_MONO" value="0" enum="Eyes">
+ Mono output, this is mostly used internally when retrieving positioning information for our camera node or when stereo scopic rendering is not supported.
+ </constant>
+ <constant name="EYE_LEFT" value="1" enum="Eyes">
+ Left eye output, this is mostly used internally when rendering the image for the left eye and obtaining positioning and projection information.
+ </constant>
+ <constant name="EYE_RIGHT" value="2" enum="Eyes">
+ Right eye output, this is mostly used internally when rendering the image for the right eye and obtaining positioning and projection information.
+ </constant>
+ <constant name="XR_NORMAL_TRACKING" value="0" enum="Tracking_status">
+ Tracking is behaving as expected.
+ </constant>
+ <constant name="XR_EXCESSIVE_MOTION" value="1" enum="Tracking_status">
+ Tracking is hindered by excessive motion (the player is moving faster than tracking can keep up).
+ </constant>
+ <constant name="XR_INSUFFICIENT_FEATURES" value="2" enum="Tracking_status">
+ Tracking is hindered by insufficient features, it's too dark (for camera-based tracking), player is blocked, etc.
+ </constant>
+ <constant name="XR_UNKNOWN_TRACKING" value="3" enum="Tracking_status">
+ We don't know the status of the tracking or this interface does not provide feedback.
+ </constant>
+ <constant name="XR_NOT_TRACKING" value="4" enum="Tracking_status">
+ Tracking is not functional (camera not plugged in or obscured, lighthouses turned off, etc.).
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/XROrigin3D.xml b/doc/classes/XROrigin3D.xml
new file mode 100644
index 0000000000..57cf673d30
--- /dev/null
+++ b/doc/classes/XROrigin3D.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XROrigin3D" inherits="Node3D" version="4.0">
+ <brief_description>
+ The origin point in AR/VR.
+ </brief_description>
+ <description>
+ This is a special node within the AR/VR system that maps the physical location of the center of our tracking space to the virtual location within our game world.
+ There should be only one of these nodes in your scene and you must have one. All the XRCamera3D, XRController3D and XRAnchor3D nodes should be direct children of this node for spatial tracking to work correctly.
+ It is the position of this node that you update when your character needs to move through your game world while we're not moving in the real world. Movement in the real world is always in relation to this origin point.
+ For example, if your character is driving a car, the XROrigin3D node should be a child node of this car. Or, if you're implementing a teleport system to move your character, you should change the position of this node.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
+ Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
+ [b]Note:[/b] This method is a passthrough to the [XRServer] itself.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
new file mode 100644
index 0000000000..2f7cc21703
--- /dev/null
+++ b/doc/classes/XRPositionalTracker.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRPositionalTracker" inherits="Object" version="4.0">
+ <brief_description>
+ A tracked object.
+ </brief_description>
+ <description>
+ An instance of this object represents a device that is tracked, such as a controller or anchor point. HMDs aren't represented here as they are handled internally.
+ As controllers are turned on and the AR/VR interface detects them, instances of this object are automatically added to this list of active tracking objects accessible through the [XRServer].
+ The [XRController3D] and [XRAnchor3D] both consume objects of this type and should be used in your project. The positional trackers are just under-the-hood objects that make this all work. These are mostly exposed so that GDNative-based interfaces can interact with them.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ </tutorials>
+ <methods>
+ <method name="get_hand" qualifiers="const">
+ <return type="int" enum="XRPositionalTracker.TrackerHand">
+ </return>
+ <description>
+ Returns the hand holding this tracker, if known. See [enum TrackerHand] constants.
+ </description>
+ </method>
+ <method name="get_joy_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ If this is a controller that is being tracked, the controller will also be represented by a joystick entry with this ID.
+ </description>
+ </method>
+ <method name="get_mesh" qualifiers="const">
+ <return type="Mesh">
+ </return>
+ <description>
+ Returns the mesh related to a controller or anchor point if one is available.
+ </description>
+ </method>
+ <method name="get_name" qualifiers="const">
+ <return type="StringName">
+ </return>
+ <description>
+ Returns the controller or anchor point's name if available.
+ </description>
+ </method>
+ <method name="get_orientation" qualifiers="const">
+ <return type="Basis">
+ </return>
+ <description>
+ Returns the controller's orientation matrix.
+ </description>
+ </method>
+ <method name="get_position" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns the world-space controller position.
+ </description>
+ </method>
+ <method name="get_tracker_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the internal tracker ID. This uniquely identifies the tracker per tracker type and matches the ID you need to specify for nodes such as the [XRController3D] and [XRAnchor3D] nodes.
+ </description>
+ </method>
+ <method name="get_tracks_orientation" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if this device tracks orientation.
+ </description>
+ </method>
+ <method name="get_tracks_position" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if this device tracks position.
+ </description>
+ </method>
+ <method name="get_transform" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="adjust_by_reference_frame" type="bool">
+ </argument>
+ <description>
+ Returns the transform combining this device's orientation and position.
+ </description>
+ </method>
+ <method name="get_type" qualifiers="const">
+ <return type="int" enum="XRServer.TrackerType">
+ </return>
+ <description>
+ Returns the tracker's type.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0">
+ The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code].
+ </member>
+ </members>
+ <constants>
+ <constant name="TRACKER_HAND_UNKNOWN" value="0" enum="TrackerHand">
+ The hand this tracker is held in is unknown or not applicable.
+ </constant>
+ <constant name="TRACKER_LEFT_HAND" value="1" enum="TrackerHand">
+ This tracker is the left hand controller.
+ </constant>
+ <constant name="TRACKER_RIGHT_HAND" value="2" enum="TrackerHand">
+ This tracker is the right hand controller.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
new file mode 100644
index 0000000000..5e6002aee3
--- /dev/null
+++ b/doc/classes/XRServer.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRServer" inherits="Object" version="4.0">
+ <brief_description>
+ Server for AR and VR features.
+ </brief_description>
+ <description>
+ The AR/VR server is the heart of our Advanced and Virtual Reality solution and handles all the processing.
+ </description>
+ <tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ </tutorials>
+ <methods>
+ <method name="center_on_hmd">
+ <return type="void">
+ </return>
+ <argument index="0" name="rotation_mode" type="int" enum="XRServer.RotationMode">
+ </argument>
+ <argument index="1" name="keep_height" type="bool">
+ </argument>
+ <description>
+ This is an important function to understand correctly. AR and VR platforms all handle positioning slightly differently.
+ For platforms that do not offer spatial tracking, our origin point (0,0,0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
+ For platforms that do offer spatial tracking, our origin point depends very much on the system. For OpenVR, our origin point is usually the center of the tracking space, on the ground. For other platforms, it's often the location of the tracking camera.
+ This method allows you to center your tracker on the location of the HMD. It will take the current location of the HMD and use that to adjust all your tracking data; in essence, realigning the real world to your player's current position in the game world.
+ For this method to produce usable results, tracking information must be available. This often takes a few frames after starting your game.
+ 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="find_interface" qualifiers="const">
+ <return type="XRInterface">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ Finds an interface by its name. For instance, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
+ </description>
+ </method>
+ <method name="get_hmd_transform">
+ <return type="Transform">
+ </return>
+ <description>
+ Returns the primary interface's transformation.
+ </description>
+ </method>
+ <method name="get_interface" qualifiers="const">
+ <return type="XRInterface">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the interface registered at a given index in our list of interfaces.
+ </description>
+ </method>
+ <method name="get_interface_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of interfaces currently registered with the AR/VR server. If your project supports multiple AR/VR platforms, you can look through the available interface, and either present the user with a selection or simply try to initialize each interface and use the first one that returns [code]true[/code].
+ </description>
+ </method>
+ <method name="get_interfaces" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Returns a list of available interfaces the ID and name of each interface.
+ </description>
+ </method>
+ <method name="get_last_commit_usec">
+ <return type="int">
+ </return>
+ <description>
+ Returns the absolute timestamp (in μs) of the last [XRServer] commit of the AR/VR eyes to [RenderingServer]. The value comes from an internal call to [method OS.get_ticks_usec].
+ </description>
+ </method>
+ <method name="get_last_frame_usec">
+ <return type="int">
+ </return>
+ <description>
+ Returns the duration (in μs) of the last frame. This is computed as the difference between [method get_last_commit_usec] and [method get_last_process_usec] when committing.
+ </description>
+ </method>
+ <method name="get_last_process_usec">
+ <return type="int">
+ </return>
+ <description>
+ Returns the absolute timestamp (in μs) of the last [XRServer] process callback. The value comes from an internal call to [method OS.get_ticks_usec].
+ </description>
+ </method>
+ <method name="get_reference_frame" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <description>
+ Returns the reference frame transform. Mostly used internally and exposed for GDNative build interfaces.
+ </description>
+ </method>
+ <method name="get_tracker" qualifiers="const">
+ <return type="XRPositionalTracker">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Returns the positional tracker at the given ID.
+ </description>
+ </method>
+ <method name="get_tracker_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of trackers currently registered.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="primary_interface" type="XRInterface" setter="set_primary_interface" getter="get_primary_interface">
+ The primary [XRInterface] currently bound to the [XRServer].
+ </member>
+ <member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
+ Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
+ </member>
+ </members>
+ <signals>
+ <signal name="interface_added">
+ <argument index="0" name="interface_name" type="StringName">
+ </argument>
+ <description>
+ Emitted when a new interface has been added.
+ </description>
+ </signal>
+ <signal name="interface_removed">
+ <argument index="0" name="interface_name" type="StringName">
+ </argument>
+ <description>
+ Emitted when an interface is removed.
+ </description>
+ </signal>
+ <signal name="tracker_added">
+ <argument index="0" name="tracker_name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="int">
+ </argument>
+ <argument index="2" name="id" type="int">
+ </argument>
+ <description>
+ Emitted when a new tracker has been added. If you don't use a fixed number of controllers or if you're using [XRAnchor3D]s for an AR solution, it is important to react to this signal to add the appropriate [XRController3D] or [XRAnchor3D] nodes related to this new tracker.
+ </description>
+ </signal>
+ <signal name="tracker_removed">
+ <argument index="0" name="tracker_name" type="StringName">
+ </argument>
+ <argument index="1" name="type" type="int">
+ </argument>
+ <argument index="2" name="id" type="int">
+ </argument>
+ <description>
+ Emitted when a tracker is removed. You should remove any [XRController3D] or [XRAnchor3D] points if applicable. This is not mandatory, the nodes simply become inactive and will be made active again when a new tracker becomes available (i.e. a new controller is switched on that takes the place of the previous one).
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="TRACKER_CONTROLLER" value="1" enum="TrackerType">
+ The tracker tracks the location of a controller.
+ </constant>
+ <constant name="TRACKER_BASESTATION" value="2" enum="TrackerType">
+ The tracker tracks the location of a base station.
+ </constant>
+ <constant name="TRACKER_ANCHOR" value="4" enum="TrackerType">
+ The tracker tracks the location and size of an AR anchor.
+ </constant>
+ <constant name="TRACKER_ANY_KNOWN" value="127" enum="TrackerType">
+ Used internally to filter trackers of any known type.
+ </constant>
+ <constant name="TRACKER_UNKNOWN" value="128" enum="TrackerType">
+ Used internally if we haven't set the tracker type yet.
+ </constant>
+ <constant name="TRACKER_ANY" value="255" enum="TrackerType">
+ Used internally to select all trackers.
+ </constant>
+ <constant name="RESET_FULL_ROTATION" value="0" enum="RotationMode">
+ Fully reset the orientation of the HMD. Regardless of what direction the user is looking to in the real world. The user will look dead ahead in the virtual world.
+ </constant>
+ <constant name="RESET_BUT_KEEP_TILT" value="1" enum="RotationMode">
+ Resets the orientation but keeps the tilt of the device. So if we're looking down, we keep looking down but heading will be reset.
+ </constant>
+ <constant name="DONT_RESET_ROTATION" value="2" enum="RotationMode">
+ Does not reset the orientation of the HMD, only the position of the player gets centered.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/tools/doc_merge.py b/doc/tools/doc_merge.py
index 496d5dcb74..f6f52f5d66 100755
--- a/doc/tools/doc_merge.py
+++ b/doc/tools/doc_merge.py
@@ -21,7 +21,7 @@ def write_string(_f, text, newline=True):
for t in range(tab):
_f.write("\t")
_f.write(text)
- if (newline):
+ if newline:
_f.write("\n")
@@ -30,7 +30,7 @@ def escape(ret):
ret = ret.replace("<", "&gt;")
ret = ret.replace(">", "&lt;")
ret = ret.replace("'", "&apos;")
- ret = ret.replace("\"", "&quot;")
+ ret = ret.replace('"', "&quot;")
return ret
@@ -43,25 +43,26 @@ def dec_tab():
global tab
tab -= 1
+
write_string(f, '<?xml version="1.0" encoding="UTF-8" ?>')
write_string(f, '<doc version="' + new_doc.attrib["version"] + '">')
def get_tag(node, name):
tag = ""
- if (name in node.attrib):
- tag = ' ' + name + '="' + escape(node.attrib[name]) + '" '
+ if name in node.attrib:
+ tag = " " + name + '="' + escape(node.attrib[name]) + '" '
return tag
def find_method_descr(old_class, name):
methods = old_class.find("methods")
- if(methods != None and len(list(methods)) > 0):
+ if methods != None and len(list(methods)) > 0:
for m in list(methods):
- if (m.attrib["name"] == name):
+ if m.attrib["name"] == name:
description = m.find("description")
- if (description != None and description.text.strip() != ""):
+ if description != None and description.text.strip() != "":
return description.text
return None
@@ -70,11 +71,11 @@ def find_method_descr(old_class, name):
def find_signal_descr(old_class, name):
signals = old_class.find("signals")
- if(signals != None and len(list(signals)) > 0):
+ if signals != None and len(list(signals)) > 0:
for m in list(signals):
- if (m.attrib["name"] == name):
+ if m.attrib["name"] == name:
description = m.find("description")
- if (description != None and description.text.strip() != ""):
+ if description != None and description.text.strip() != "":
return description.text
return None
@@ -82,13 +83,13 @@ def find_signal_descr(old_class, name):
def find_constant_descr(old_class, name):
- if (old_class is None):
+ if old_class is None:
return None
constants = old_class.find("constants")
- if(constants != None and len(list(constants)) > 0):
+ if constants != None and len(list(constants)) > 0:
for m in list(constants):
- if (m.attrib["name"] == name):
- if (m.text.strip() != ""):
+ if m.attrib["name"] == name:
+ if m.text.strip() != "":
return m.text
return None
@@ -96,35 +97,35 @@ def find_constant_descr(old_class, name):
def write_class(c):
class_name = c.attrib["name"]
print("Parsing Class: " + class_name)
- if (class_name in old_classes):
+ if class_name in old_classes:
old_class = old_classes[class_name]
else:
old_class = None
category = get_tag(c, "category")
inherits = get_tag(c, "inherits")
- write_string(f, '<class name="' + class_name + '" ' + category + inherits + '>')
+ write_string(f, '<class name="' + class_name + '" ' + category + inherits + ">")
inc_tab()
write_string(f, "<brief_description>")
- if (old_class != None):
+ if old_class != None:
old_brief_descr = old_class.find("brief_description")
- if (old_brief_descr != None):
+ if old_brief_descr != None:
write_string(f, escape(old_brief_descr.text.strip()))
write_string(f, "</brief_description>")
write_string(f, "<description>")
- if (old_class != None):
+ if old_class != None:
old_descr = old_class.find("description")
- if (old_descr != None):
+ if old_descr != None:
write_string(f, escape(old_descr.text.strip()))
write_string(f, "</description>")
methods = c.find("methods")
- if(methods != None and len(list(methods)) > 0):
+ if methods != None and len(list(methods)) > 0:
write_string(f, "<methods>")
inc_tab()
@@ -132,35 +133,46 @@ def write_class(c):
for m in list(methods):
qualifiers = get_tag(m, "qualifiers")
- write_string(f, '<method name="' + escape(m.attrib["name"]) + '" ' + qualifiers + '>')
+ write_string(f, '<method name="' + escape(m.attrib["name"]) + '" ' + qualifiers + ">")
inc_tab()
for a in list(m):
- if (a.tag == "return"):
+ if a.tag == "return":
typ = get_tag(a, "type")
- write_string(f, '<return' + typ + '>')
- write_string(f, '</return>')
- elif (a.tag == "argument"):
+ write_string(f, "<return" + typ + ">")
+ write_string(f, "</return>")
+ elif a.tag == "argument":
default = get_tag(a, "default")
- write_string(f, '<argument index="' + a.attrib["index"] + '" name="' + escape(a.attrib["name"]) + '" type="' + a.attrib["type"] + '"' + default + '>')
- write_string(f, '</argument>')
-
- write_string(f, '<description>')
- if (old_class != None):
+ write_string(
+ f,
+ '<argument index="'
+ + a.attrib["index"]
+ + '" name="'
+ + escape(a.attrib["name"])
+ + '" type="'
+ + a.attrib["type"]
+ + '"'
+ + default
+ + ">",
+ )
+ write_string(f, "</argument>")
+
+ write_string(f, "<description>")
+ if old_class != None:
old_method_descr = find_method_descr(old_class, m.attrib["name"])
- if (old_method_descr):
+ if old_method_descr:
write_string(f, escape(escape(old_method_descr.strip())))
- write_string(f, '</description>')
+ write_string(f, "</description>")
dec_tab()
write_string(f, "</method>")
dec_tab()
write_string(f, "</methods>")
signals = c.find("signals")
- if(signals != None and len(list(signals)) > 0):
+ if signals != None and len(list(signals)) > 0:
write_string(f, "<signals>")
inc_tab()
@@ -171,24 +183,33 @@ def write_class(c):
inc_tab()
for a in list(m):
- if (a.tag == "argument"):
-
- write_string(f, '<argument index="' + a.attrib["index"] + '" name="' + escape(a.attrib["name"]) + '" type="' + a.attrib["type"] + '">')
- write_string(f, '</argument>')
-
- write_string(f, '<description>')
- if (old_class != None):
+ if a.tag == "argument":
+
+ write_string(
+ f,
+ '<argument index="'
+ + a.attrib["index"]
+ + '" name="'
+ + escape(a.attrib["name"])
+ + '" type="'
+ + a.attrib["type"]
+ + '">',
+ )
+ write_string(f, "</argument>")
+
+ write_string(f, "<description>")
+ if old_class != None:
old_signal_descr = find_signal_descr(old_class, m.attrib["name"])
- if (old_signal_descr):
+ if old_signal_descr:
write_string(f, escape(old_signal_descr.strip()))
- write_string(f, '</description>')
+ write_string(f, "</description>")
dec_tab()
write_string(f, "</signal>")
dec_tab()
write_string(f, "</signals>")
constants = c.find("constants")
- if(constants != None and len(list(constants)) > 0):
+ if constants != None and len(list(constants)) > 0:
write_string(f, "<constants>")
inc_tab()
@@ -197,7 +218,7 @@ def write_class(c):
write_string(f, '<constant name="' + escape(m.attrib["name"]) + '" value="' + m.attrib["value"] + '">')
old_constant_descr = find_constant_descr(old_class, m.attrib["name"])
- if (old_constant_descr):
+ if old_constant_descr:
write_string(f, escape(old_constant_descr.strip()))
write_string(f, "</constant>")
@@ -207,9 +228,10 @@ def write_class(c):
dec_tab()
write_string(f, "</class>")
+
for c in list(old_doc):
old_classes[c.attrib["name"]] = c
for c in list(new_doc):
write_class(c)
-write_string(f, '</doc>\n')
+write_string(f, "</doc>\n")
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py
index e6e6d5f606..629b5a032b 100755
--- a/doc/tools/doc_status.py
+++ b/doc/tools/doc_status.py
@@ -13,75 +13,74 @@ import xml.etree.ElementTree as ET
################################################################################
flags = {
- 'c': platform.platform() != 'Windows', # Disable by default on windows, since we use ANSI escape codes
- 'b': False,
- 'g': False,
- 's': False,
- 'u': False,
- 'h': False,
- 'p': False,
- 'o': True,
- 'i': False,
- 'a': True,
- 'e': False,
+ "c": platform.platform() != "Windows", # Disable by default on windows, since we use ANSI escape codes
+ "b": False,
+ "g": False,
+ "s": False,
+ "u": False,
+ "h": False,
+ "p": False,
+ "o": True,
+ "i": False,
+ "a": True,
+ "e": False,
}
flag_descriptions = {
- 'c': 'Toggle colors when outputting.',
- 'b': 'Toggle showing only not fully described classes.',
- 'g': 'Toggle showing only completed classes.',
- 's': 'Toggle showing comments about the status.',
- 'u': 'Toggle URLs to docs.',
- 'h': 'Show help and exit.',
- 'p': 'Toggle showing percentage as well as counts.',
- 'o': 'Toggle overall column.',
- 'i': 'Toggle collapse of class items columns.',
- 'a': 'Toggle showing all items.',
- 'e': 'Toggle hiding empty items.',
+ "c": "Toggle colors when outputting.",
+ "b": "Toggle showing only not fully described classes.",
+ "g": "Toggle showing only completed classes.",
+ "s": "Toggle showing comments about the status.",
+ "u": "Toggle URLs to docs.",
+ "h": "Show help and exit.",
+ "p": "Toggle showing percentage as well as counts.",
+ "o": "Toggle overall column.",
+ "i": "Toggle collapse of class items columns.",
+ "a": "Toggle showing all items.",
+ "e": "Toggle hiding empty items.",
}
long_flags = {
- 'colors': 'c',
- 'use-colors': 'c',
-
- 'bad': 'b',
- 'only-bad': 'b',
-
- 'good': 'g',
- 'only-good': 'g',
-
- 'comments': 's',
- 'status': 's',
-
- 'urls': 'u',
- 'gen-url': 'u',
-
- 'help': 'h',
-
- 'percent': 'p',
- 'use-percentages': 'p',
-
- 'overall': 'o',
- 'use-overall': 'o',
-
- 'items': 'i',
- 'collapse': 'i',
-
- 'all': 'a',
-
- 'empty': 'e',
+ "colors": "c",
+ "use-colors": "c",
+ "bad": "b",
+ "only-bad": "b",
+ "good": "g",
+ "only-good": "g",
+ "comments": "s",
+ "status": "s",
+ "urls": "u",
+ "gen-url": "u",
+ "help": "h",
+ "percent": "p",
+ "use-percentages": "p",
+ "overall": "o",
+ "use-overall": "o",
+ "items": "i",
+ "collapse": "i",
+ "all": "a",
+ "empty": "e",
}
-table_columns = ['name', 'brief_description', 'description', 'methods', 'constants', 'members', 'signals', 'theme_items']
-table_column_names = ['Name', 'Brief Desc.', 'Desc.', 'Methods', 'Constants', 'Members', 'Signals', 'Theme Items']
+table_columns = [
+ "name",
+ "brief_description",
+ "description",
+ "methods",
+ "constants",
+ "members",
+ "signals",
+ "theme_items",
+]
+table_column_names = ["Name", "Brief Desc.", "Desc.", "Methods", "Constants", "Members", "Signals", "Theme Items"]
colors = {
- 'name': [36], # cyan
- 'part_big_problem': [4, 31], # underline, red
- 'part_problem': [31], # red
- 'part_mostly_good': [33], # yellow
- 'part_good': [32], # green
- 'url': [4, 34], # underline, blue
- 'section': [1, 4], # bold, underline
- 'state_off': [36], # cyan
- 'state_on': [1, 35], # bold, magenta/plum
- 'bold': [1], # bold
+ "name": [36], # cyan
+ "part_big_problem": [4, 31], # underline, red
+ "part_problem": [31], # red
+ "part_mostly_good": [33], # yellow
+ "part_good": [32], # green
+ "url": [4, 34], # underline, blue
+ "section": [1, 4], # bold, underline
+ "state_off": [36], # cyan
+ "state_on": [1, 35], # bold, magenta/plum
+ "bold": [1], # bold
}
overall_progress_description_weigth = 10
@@ -90,6 +89,7 @@ overall_progress_description_weigth = 10
# Utils #
################################################################################
+
def validate_tag(elem, tag):
if elem.tag != tag:
print('Tag mismatch, expected "' + tag + '", got ' + elem.tag)
@@ -97,36 +97,38 @@ def validate_tag(elem, tag):
def color(color, string):
- if flags['c'] and terminal_supports_color():
- color_format = ''
+ if flags["c"] and terminal_supports_color():
+ color_format = ""
for code in colors[color]:
- color_format += '\033[' + str(code) + 'm'
- return color_format + string + '\033[0m'
+ color_format += "\033[" + str(code) + "m"
+ return color_format + string + "\033[0m"
else:
return string
-ansi_escape = re.compile(r'\x1b[^m]*m')
+
+ansi_escape = re.compile(r"\x1b[^m]*m")
def nonescape_len(s):
- return len(ansi_escape.sub('', s))
+ return len(ansi_escape.sub("", s))
+
def terminal_supports_color():
p = sys.platform
- supported_platform = p != 'Pocket PC' and (p != 'win32' or
- 'ANSICON' in os.environ)
+ supported_platform = p != "Pocket PC" and (p != "win32" or "ANSICON" in os.environ)
- is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
+ is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
if not supported_platform or not is_a_tty:
return False
return True
+
################################################################################
# Classes #
################################################################################
-class ClassStatusProgress:
+class ClassStatusProgress:
def __init__(self, described=0, total=0):
self.described = described
self.total = total
@@ -143,42 +145,41 @@ class ClassStatusProgress:
return self.described >= self.total
def to_configured_colored_string(self):
- if flags['p']:
- return self.to_colored_string('{percent}% ({has}/{total})', '{pad_percent}{pad_described}{s}{pad_total}')
+ if flags["p"]:
+ return self.to_colored_string("{percent}% ({has}/{total})", "{pad_percent}{pad_described}{s}{pad_total}")
else:
return self.to_colored_string()
- def to_colored_string(self, format='{has}/{total}', pad_format='{pad_described}{s}{pad_total}'):
+ def to_colored_string(self, format="{has}/{total}", pad_format="{pad_described}{s}{pad_total}"):
ratio = float(self.described) / float(self.total) if self.total != 0 else 1
percent = int(round(100 * ratio))
s = format.format(has=str(self.described), total=str(self.total), percent=str(percent))
if self.described >= self.total:
- s = color('part_good', s)
+ s = color("part_good", s)
elif self.described >= self.total / 4 * 3:
- s = color('part_mostly_good', s)
+ s = color("part_mostly_good", s)
elif self.described > 0:
- s = color('part_problem', s)
+ s = color("part_problem", s)
else:
- s = color('part_big_problem', s)
+ s = color("part_big_problem", s)
pad_size = max(len(str(self.described)), len(str(self.total)))
- pad_described = ''.ljust(pad_size - len(str(self.described)))
- pad_percent = ''.ljust(3 - len(str(percent)))
- pad_total = ''.ljust(pad_size - len(str(self.total)))
+ pad_described = "".ljust(pad_size - len(str(self.described)))
+ pad_percent = "".ljust(3 - len(str(percent)))
+ pad_total = "".ljust(pad_size - len(str(self.total)))
return pad_format.format(pad_described=pad_described, pad_total=pad_total, pad_percent=pad_percent, s=s)
class ClassStatus:
-
- def __init__(self, name=''):
+ def __init__(self, name=""):
self.name = name
self.has_brief_description = True
self.has_description = True
self.progresses = {
- 'methods': ClassStatusProgress(),
- 'constants': ClassStatusProgress(),
- 'members': ClassStatusProgress(),
- 'theme_items': ClassStatusProgress(),
- 'signals': ClassStatusProgress()
+ "methods": ClassStatusProgress(),
+ "constants": ClassStatusProgress(),
+ "members": ClassStatusProgress(),
+ "theme_items": ClassStatusProgress(),
+ "signals": ClassStatusProgress(),
}
def __add__(self, other):
@@ -208,66 +209,70 @@ class ClassStatus:
def make_output(self):
output = {}
- output['name'] = color('name', self.name)
+ output["name"] = color("name", self.name)
- ok_string = color('part_good', 'OK')
- missing_string = color('part_big_problem', 'MISSING')
+ ok_string = color("part_good", "OK")
+ missing_string = color("part_big_problem", "MISSING")
- output['brief_description'] = ok_string if self.has_brief_description else missing_string
- output['description'] = ok_string if self.has_description else missing_string
+ output["brief_description"] = ok_string if self.has_brief_description else missing_string
+ output["description"] = ok_string if self.has_description else missing_string
description_progress = ClassStatusProgress(
(self.has_brief_description + self.has_description) * overall_progress_description_weigth,
- 2 * overall_progress_description_weigth
+ 2 * overall_progress_description_weigth,
)
items_progress = ClassStatusProgress()
- for k in ['methods', 'constants', 'members', 'signals', 'theme_items']:
+ for k in ["methods", "constants", "members", "signals", "theme_items"]:
items_progress += self.progresses[k]
output[k] = self.progresses[k].to_configured_colored_string()
- output['items'] = items_progress.to_configured_colored_string()
+ output["items"] = items_progress.to_configured_colored_string()
- output['overall'] = (description_progress + items_progress).to_colored_string(color('bold', '{percent}%'), '{pad_percent}{s}')
+ output["overall"] = (description_progress + items_progress).to_colored_string(
+ color("bold", "{percent}%"), "{pad_percent}{s}"
+ )
- if self.name.startswith('Total'):
- output['url'] = color('url', 'https://docs.godotengine.org/en/latest/classes/')
- if flags['s']:
- output['comment'] = color('part_good', 'ALL OK')
+ if self.name.startswith("Total"):
+ output["url"] = color("url", "https://docs.godotengine.org/en/latest/classes/")
+ if flags["s"]:
+ output["comment"] = color("part_good", "ALL OK")
else:
- output['url'] = color('url', 'https://docs.godotengine.org/en/latest/classes/class_{name}.html'.format(name=self.name.lower()))
+ output["url"] = color(
+ "url", "https://docs.godotengine.org/en/latest/classes/class_{name}.html".format(name=self.name.lower())
+ )
- if flags['s'] and not flags['g'] and self.is_ok():
- output['comment'] = color('part_good', 'ALL OK')
+ if flags["s"] and not flags["g"] and self.is_ok():
+ output["comment"] = color("part_good", "ALL OK")
return output
@staticmethod
def generate_for_class(c):
status = ClassStatus()
- status.name = c.attrib['name']
+ status.name = c.attrib["name"]
for tag in list(c):
- if tag.tag == 'brief_description':
+ if tag.tag == "brief_description":
status.has_brief_description = len(tag.text.strip()) > 0
- elif tag.tag == 'description':
+ elif tag.tag == "description":
status.has_description = len(tag.text.strip()) > 0
- elif tag.tag in ['methods', 'signals']:
+ elif tag.tag in ["methods", "signals"]:
for sub_tag in list(tag):
- descr = sub_tag.find('description')
+ descr = sub_tag.find("description")
status.progresses[tag.tag].increment(len(descr.text.strip()) > 0)
- elif tag.tag in ['constants', 'members', 'theme_items']:
+ elif tag.tag in ["constants", "members", "theme_items"]:
for sub_tag in list(tag):
if not sub_tag.text is None:
status.progresses[tag.tag].increment(len(sub_tag.text.strip()) > 0)
- elif tag.tag in ['tutorials']:
+ elif tag.tag in ["tutorials"]:
pass # Ignore those tags for now
- elif tag.tag in ['theme_items']:
+ elif tag.tag in ["theme_items"]:
pass # Ignore those tags, since they seem to lack description at all
else:
@@ -286,63 +291,69 @@ merged_file = ""
for arg in sys.argv[1:]:
try:
- if arg.startswith('--'):
+ if arg.startswith("--"):
flags[long_flags[arg[2:]]] = not flags[long_flags[arg[2:]]]
- elif arg.startswith('-'):
+ elif arg.startswith("-"):
for f in arg[1:]:
flags[f] = not flags[f]
elif os.path.isdir(arg):
for f in os.listdir(arg):
- if f.endswith('.xml'):
- input_file_list.append(os.path.join(arg, f));
+ if f.endswith(".xml"):
+ input_file_list.append(os.path.join(arg, f))
else:
input_class_list.append(arg)
except KeyError:
print("Unknown command line flag: " + arg)
sys.exit(1)
-if flags['i']:
- for r in ['methods', 'constants', 'members', 'signals', 'theme_items']:
+if flags["i"]:
+ for r in ["methods", "constants", "members", "signals", "theme_items"]:
index = table_columns.index(r)
del table_column_names[index]
del table_columns[index]
- table_column_names.append('Items')
- table_columns.append('items')
+ table_column_names.append("Items")
+ table_columns.append("items")
-if flags['o'] == (not flags['i']):
- table_column_names.append(color('bold', 'Overall'))
- table_columns.append('overall')
+if flags["o"] == (not flags["i"]):
+ table_column_names.append(color("bold", "Overall"))
+ table_columns.append("overall")
-if flags['u']:
- table_column_names.append('Docs URL')
- table_columns.append('url')
+if flags["u"]:
+ table_column_names.append("Docs URL")
+ table_columns.append("url")
################################################################################
# Help #
################################################################################
-if len(input_file_list) < 1 or flags['h']:
- if not flags['h']:
- print(color('section', 'Invalid usage') + ': Please specify a classes directory')
- print(color('section', 'Usage') + ': doc_status.py [flags] <classes_dir> [class names]')
- print('\t< and > signify required parameters, while [ and ] signify optional parameters.')
- print(color('section', 'Available flags') + ':')
+if len(input_file_list) < 1 or flags["h"]:
+ if not flags["h"]:
+ print(color("section", "Invalid usage") + ": Please specify a classes directory")
+ print(color("section", "Usage") + ": doc_status.py [flags] <classes_dir> [class names]")
+ print("\t< and > signify required parameters, while [ and ] signify optional parameters.")
+ print(color("section", "Available flags") + ":")
possible_synonym_list = list(long_flags)
possible_synonym_list.sort()
flag_list = list(flags)
flag_list.sort()
for flag in flag_list:
- synonyms = [color('name', '-' + flag)]
+ synonyms = [color("name", "-" + flag)]
for synonym in possible_synonym_list:
if long_flags[synonym] == flag:
- synonyms.append(color('name', '--' + synonym))
-
- print(('{synonyms} (Currently ' + color('state_' + ('on' if flags[flag] else 'off'), '{value}') + ')\n\t{description}').format(
- synonyms=', '.join(synonyms),
- value=('on' if flags[flag] else 'off'),
- description=flag_descriptions[flag]
- ))
+ synonyms.append(color("name", "--" + synonym))
+
+ print(
+ (
+ "{synonyms} (Currently "
+ + color("state_" + ("on" if flags[flag] else "off"), "{value}")
+ + ")\n\t{description}"
+ ).format(
+ synonyms=", ".join(synonyms),
+ value=("on" if flags[flag] else "off"),
+ description=flag_descriptions[flag],
+ )
+ )
sys.exit(0)
@@ -357,21 +368,21 @@ for file in input_file_list:
tree = ET.parse(file)
doc = tree.getroot()
- if 'version' not in doc.attrib:
+ if "version" not in doc.attrib:
print('Version missing from "doc"')
sys.exit(255)
- version = doc.attrib['version']
+ version = doc.attrib["version"]
- if doc.attrib['name'] in class_names:
+ if doc.attrib["name"] in class_names:
continue
- class_names.append(doc.attrib['name'])
- classes[doc.attrib['name']] = doc
+ class_names.append(doc.attrib["name"])
+ classes[doc.attrib["name"]] = doc
class_names.sort()
if len(input_class_list) < 1:
- input_class_list = ['*']
+ input_class_list = ["*"]
filtered_classes = set()
for pattern in input_class_list:
@@ -384,23 +395,23 @@ filtered_classes.sort()
################################################################################
table = [table_column_names]
-table_row_chars = '| - '
-table_column_chars = '|'
+table_row_chars = "| - "
+table_column_chars = "|"
-total_status = ClassStatus('Total')
+total_status = ClassStatus("Total")
for cn in filtered_classes:
c = classes[cn]
- validate_tag(c, 'class')
+ validate_tag(c, "class")
status = ClassStatus.generate_for_class(c)
total_status = total_status + status
- if (flags['b'] and status.is_ok()) or (flags['g'] and not status.is_ok()) or (not flags['a']):
+ if (flags["b"] and status.is_ok()) or (flags["g"] and not status.is_ok()) or (not flags["a"]):
continue
- if flags['e'] and status.is_empty():
+ if flags["e"] and status.is_empty():
continue
out = status.make_output()
@@ -409,10 +420,10 @@ for cn in filtered_classes:
if column in out:
row.append(out[column])
else:
- row.append('')
+ row.append("")
- if 'comment' in out and out['comment'] != '':
- row.append(out['comment'])
+ if "comment" in out and out["comment"] != "":
+ row.append(out["comment"])
table.append(row)
@@ -421,22 +432,22 @@ for cn in filtered_classes:
# Print output table #
################################################################################
-if len(table) == 1 and flags['a']:
- print(color('part_big_problem', 'No classes suitable for printing!'))
+if len(table) == 1 and flags["a"]:
+ print(color("part_big_problem", "No classes suitable for printing!"))
sys.exit(0)
-if len(table) > 2 or not flags['a']:
- total_status.name = 'Total = {0}'.format(len(table) - 1)
+if len(table) > 2 or not flags["a"]:
+ total_status.name = "Total = {0}".format(len(table) - 1)
out = total_status.make_output()
row = []
for column in table_columns:
if column in out:
row.append(out[column])
else:
- row.append('')
+ row.append("")
table.append(row)
-if flags['a']:
+if flags["a"]:
# Duplicate the headers at the bottom of the table so they can be viewed
# without having to scroll back to the top.
table.append(table_column_names)
@@ -451,7 +462,9 @@ for row in table:
divider_string = table_row_chars[0]
for cell_i in range(len(table[0])):
- divider_string += table_row_chars[1] + table_row_chars[2] * (table_column_sizes[cell_i]) + table_row_chars[1] + table_row_chars[0]
+ divider_string += (
+ table_row_chars[1] + table_row_chars[2] * (table_column_sizes[cell_i]) + table_row_chars[1] + table_row_chars[0]
+ )
print(divider_string)
for row_i, row in enumerate(table):
@@ -461,7 +474,11 @@ for row_i, row in enumerate(table):
if cell_i == 0:
row_string += table_row_chars[3] + cell + table_row_chars[3] * (padding_needed - 1)
else:
- row_string += table_row_chars[3] * int(math.floor(float(padding_needed) / 2)) + cell + table_row_chars[3] * int(math.ceil(float(padding_needed) / 2))
+ row_string += (
+ table_row_chars[3] * int(math.floor(float(padding_needed) / 2))
+ + cell
+ + table_row_chars[3] * int(math.ceil(float(padding_needed) / 2))
+ )
row_string += table_column_chars
print(row_string)
@@ -474,5 +491,5 @@ for row_i, row in enumerate(table):
print(divider_string)
-if total_status.is_ok() and not flags['g']:
- print('All listed classes are ' + color('part_good', 'OK') + '!')
+if total_status.is_ok() and not flags["g"]:
+ print("All listed classes are " + color("part_good", "OK") + "!")
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index 9012de03b3..c6c6cae6c0 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -7,10 +7,12 @@ import xml.etree.ElementTree as ET
from collections import OrderedDict
# Uncomment to do type checks. I have it commented out so it works below Python 3.5
-#from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union
+# from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union
# http(s)://docs.godotengine.org/<langcode>/<tag>/path/to/page.html(#fragment-tag)
-GODOT_DOCS_PATTERN = re.compile(r'^http(?:s)?://docs\.godotengine\.org/(?:[a-zA-Z0-9.\-_]*)/(?:[a-zA-Z0-9.\-_]*)/(.*)\.html(#.*)?$')
+GODOT_DOCS_PATTERN = re.compile(
+ r"^http(?:s)?://docs\.godotengine\.org/(?:[a-zA-Z0-9.\-_]*)/(?:[a-zA-Z0-9.\-_]*)/(.*)\.html(#.*)?$"
+)
def print_error(error, state): # type: (str, State) -> None
@@ -37,7 +39,9 @@ class TypeName:
class PropertyDef:
- def __init__(self, name, type_name, setter, getter, text, default_value, overridden): # type: (str, TypeName, Optional[str], Optional[str], Optional[str], Optional[str], Optional[bool]) -> None
+ def __init__(
+ self, name, type_name, setter, getter, text, default_value, overridden
+ ): # type: (str, TypeName, Optional[str], Optional[str], Optional[str], Optional[str], Optional[bool]) -> None
self.name = name
self.type_name = type_name
self.setter = setter
@@ -46,6 +50,7 @@ class PropertyDef:
self.default_value = default_value
self.overridden = overridden
+
class ParameterDef:
def __init__(self, name, type_name, default_value): # type: (str, TypeName, Optional[str]) -> None
self.name = name
@@ -61,7 +66,9 @@ class SignalDef:
class MethodDef:
- def __init__(self, name, return_type, parameters, description, qualifiers): # type: (str, TypeName, List[ParameterDef], Optional[str], Optional[str]) -> None
+ def __init__(
+ self, name, return_type, parameters, description, qualifiers
+ ): # type: (str, TypeName, List[ParameterDef], Optional[str], Optional[str]) -> None
self.name = name
self.return_type = return_type
self.parameters = parameters
@@ -144,10 +151,12 @@ class State:
getter = property.get("getter") or None
default_value = property.get("default") or None
if default_value is not None:
- default_value = '``{}``'.format(default_value)
+ default_value = "``{}``".format(default_value)
overridden = property.get("override") or False
- property_def = PropertyDef(property_name, type_name, setter, getter, property.text, default_value, overridden)
+ property_def = PropertyDef(
+ property_name, type_name, setter, getter, property.text, default_value, overridden
+ )
class_def.properties[property_name] = property_def
methods = class_root.find("methods")
@@ -246,8 +255,6 @@ class State:
if link.text is not None:
class_def.tutorials.append(link.text)
-
-
def sort_classes(self): # type: () -> None
self.classes = OrderedDict(sorted(self.classes.items(), key=lambda t: t[0]))
@@ -273,7 +280,11 @@ def main(): # type: () -> None
parser.add_argument("path", nargs="+", help="A path to an XML file or a directory containing XML files to parse.")
group = parser.add_mutually_exclusive_group()
group.add_argument("--output", "-o", default=".", help="The directory to save output .rst files in.")
- group.add_argument("--dry-run", action="store_true", help="If passed, no output will be generated and XML files are only checked for errors.")
+ group.add_argument(
+ "--dry-run",
+ action="store_true",
+ help="If passed, no output will be generated and XML files are only checked for errors.",
+ )
args = parser.parse_args()
file_list = [] # type: List[str]
@@ -283,15 +294,15 @@ def main(): # type: () -> None
if path.endswith(os.sep):
path = path[:-1]
- if os.path.basename(path) == 'modules':
+ if os.path.basename(path) == "modules":
for subdir, dirs, _ in os.walk(path):
- if 'doc_classes' in dirs:
- doc_dir = os.path.join(subdir, 'doc_classes')
- class_file_names = (f for f in os.listdir(doc_dir) if f.endswith('.xml'))
+ if "doc_classes" in dirs:
+ doc_dir = os.path.join(subdir, "doc_classes")
+ class_file_names = (f for f in os.listdir(doc_dir) if f.endswith(".xml"))
file_list += (os.path.join(doc_dir, f) for f in class_file_names)
elif os.path.isdir(path):
- file_list += (os.path.join(path, f) for f in os.listdir(path) if f.endswith('.xml'))
+ file_list += (os.path.join(path, f) for f in os.listdir(path) if f.endswith(".xml"))
elif os.path.isfile(path):
if not path.endswith(".xml"):
@@ -311,7 +322,7 @@ def main(): # type: () -> None
continue
doc = tree.getroot()
- if 'version' not in doc.attrib:
+ if "version" not in doc.attrib:
print_error("Version missing from 'doc', file: {}".format(cur_file), state)
continue
@@ -337,13 +348,14 @@ def main(): # type: () -> None
if state.errored:
exit(1)
+
def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, State, bool, str) -> None
class_name = class_def.name
if dry_run:
- f = open(os.devnull, "w")
+ f = open(os.devnull, "w", encoding="utf-8")
else:
- f = open(os.path.join(output_dir, "class_" + class_name.lower() + '.rst'), 'w', encoding='utf-8')
+ f = open(os.path.join(output_dir, "class_" + class_name.lower() + ".rst"), "w", encoding="utf-8")
# Warn contributors not to edit this file directly
f.write(":github_url: hide\n\n")
@@ -352,13 +364,13 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write(".. The source is found in doc/classes or modules/<name>/doc_classes.\n\n")
f.write(".. _class_" + class_name + ":\n\n")
- f.write(make_heading(class_name, '='))
+ f.write(make_heading(class_name, "="))
# Inheritance tree
# Ascendants
if class_def.inherits:
inh = class_def.inherits.strip()
- f.write('**Inherits:** ')
+ f.write("**Inherits:** ")
first = True
while inh in state.classes:
if not first:
@@ -381,7 +393,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
inherited.append(c.name)
if len(inherited):
- f.write('**Inherited By:** ')
+ f.write("**Inherited By:** ")
for i, child in enumerate(inherited):
if i > 0:
f.write(", ")
@@ -393,26 +405,26 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write(rstize_text(class_def.brief_description.strip(), state) + "\n\n")
# Class description
- if class_def.description is not None and class_def.description.strip() != '':
- f.write(make_heading('Description', '-'))
+ if class_def.description is not None and class_def.description.strip() != "":
+ f.write(make_heading("Description", "-"))
f.write(rstize_text(class_def.description.strip(), state) + "\n\n")
# Online tutorials
if len(class_def.tutorials) > 0:
- f.write(make_heading('Tutorials', '-'))
+ f.write(make_heading("Tutorials", "-"))
for t in class_def.tutorials:
link = t.strip()
f.write("- " + make_url(link) + "\n\n")
# Properties overview
if len(class_def.properties) > 0:
- f.write(make_heading('Properties', '-'))
+ f.write(make_heading("Properties", "-"))
ml = [] # type: List[Tuple[str, str, str]]
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:
- ml.append((type_rst, property_def.name, "**O:** " + default))
+ ml.append((type_rst, property_def.name, default + " *(parent override)*"))
else:
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
ml.append((type_rst, ref, default))
@@ -420,7 +432,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Methods overview
if len(class_def.methods) > 0:
- f.write(make_heading('Methods', '-'))
+ f.write(make_heading("Methods", "-"))
ml = []
for method_list in class_def.methods.values():
for m in method_list:
@@ -429,7 +441,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Theme properties
if class_def.theme_items is not None and len(class_def.theme_items) > 0:
- f.write(make_heading('Theme Properties', '-'))
+ f.write(make_heading("Theme Properties", "-"))
pl = []
for theme_item_list in class_def.theme_items.values():
for theme_item in theme_item_list:
@@ -438,30 +450,30 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Signals
if len(class_def.signals) > 0:
- f.write(make_heading('Signals', '-'))
+ f.write(make_heading("Signals", "-"))
index = 0
for signal in class_def.signals.values():
if index != 0:
- f.write('----\n\n')
+ f.write("----\n\n")
f.write(".. _class_{}_signal_{}:\n\n".format(class_name, signal.name))
_, signature = make_method_signature(class_def, signal, False, state)
f.write("- {}\n\n".format(signature))
- if signal.description is not None and signal.description.strip() != '':
- f.write(rstize_text(signal.description.strip(), state) + '\n\n')
+ if signal.description is not None and signal.description.strip() != "":
+ f.write(rstize_text(signal.description.strip(), state) + "\n\n")
index += 1
# Enums
if len(class_def.enums) > 0:
- f.write(make_heading('Enumerations', '-'))
+ f.write(make_heading("Enumerations", "-"))
index = 0
for e in class_def.enums.values():
if index != 0:
- f.write('----\n\n')
+ f.write("----\n\n")
f.write(".. _enum_{}_{}:\n\n".format(class_name, e.name))
# Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it.
@@ -474,16 +486,16 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("enum **{}**:\n\n".format(e.name))
for value in e.values.values():
f.write("- **{}** = **{}**".format(value.name, value.value))
- if value.text is not None and value.text.strip() != '':
- f.write(' --- ' + rstize_text(value.text.strip(), state))
+ if value.text is not None and value.text.strip() != "":
+ f.write(" --- " + rstize_text(value.text.strip(), state))
- f.write('\n\n')
+ f.write("\n\n")
index += 1
# Constants
if len(class_def.constants) > 0:
- f.write(make_heading('Constants', '-'))
+ f.write(make_heading("Constants", "-"))
# Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it.
# As such I'll put them all above the list. Won't be perfect but better than making the list visually broken.
for constant in class_def.constants.values():
@@ -491,14 +503,14 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for constant in class_def.constants.values():
f.write("- **{}** = **{}**".format(constant.name, constant.value))
- if constant.text is not None and constant.text.strip() != '':
- f.write(' --- ' + rstize_text(constant.text.strip(), state))
+ if constant.text is not None and constant.text.strip() != "":
+ f.write(" --- " + rstize_text(constant.text.strip(), state))
- f.write('\n\n')
+ f.write("\n\n")
# Property descriptions
if any(not p.overridden for p in class_def.properties.values()) > 0:
- f.write(make_heading('Property Descriptions', '-'))
+ f.write(make_heading("Property Descriptions", "-"))
index = 0
for property_def in class_def.properties.values():
@@ -506,36 +518,36 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
continue
if index != 0:
- f.write('----\n\n')
+ f.write("----\n\n")
f.write(".. _class_{}_property_{}:\n\n".format(class_name, property_def.name))
- f.write('- {} **{}**\n\n'.format(property_def.type_name.to_rst(state), property_def.name))
+ f.write("- {} **{}**\n\n".format(property_def.type_name.to_rst(state), property_def.name))
info = []
if property_def.default_value is not None:
info.append(("*Default*", property_def.default_value))
if property_def.setter is not None and not property_def.setter.startswith("_"):
- info.append(("*Setter*", property_def.setter + '(value)'))
+ info.append(("*Setter*", property_def.setter + "(value)"))
if property_def.getter is not None and not property_def.getter.startswith("_"):
- info.append(('*Getter*', property_def.getter + '()'))
+ info.append(("*Getter*", property_def.getter + "()"))
if len(info) > 0:
format_table(f, info)
- if property_def.text is not None and property_def.text.strip() != '':
- f.write(rstize_text(property_def.text.strip(), state) + '\n\n')
+ if property_def.text is not None and property_def.text.strip() != "":
+ f.write(rstize_text(property_def.text.strip(), state) + "\n\n")
index += 1
# Method descriptions
if len(class_def.methods) > 0:
- f.write(make_heading('Method Descriptions', '-'))
+ f.write(make_heading("Method Descriptions", "-"))
index = 0
for method_list in class_def.methods.values():
for i, m in enumerate(method_list):
if index != 0:
- f.write('----\n\n')
+ f.write("----\n\n")
if i == 0:
f.write(".. _class_{}_method_{}:\n\n".format(class_name, m.name))
@@ -543,24 +555,24 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
ret_type, signature = make_method_signature(class_def, m, False, state)
f.write("- {} {}\n\n".format(ret_type, signature))
- if m.description is not None and m.description.strip() != '':
- f.write(rstize_text(m.description.strip(), state) + '\n\n')
+ if m.description is not None and m.description.strip() != "":
+ f.write(rstize_text(m.description.strip(), state) + "\n\n")
index += 1
def make_class_list(class_list, columns): # type: (List[str], int) -> None
# This function is no longer used.
- f = open('class_list.rst', 'w', encoding='utf-8')
+ f = open("class_list.rst", "w", encoding="utf-8")
col_max = len(class_list) // columns + 1
- print(('col max is ', col_max))
+ print(("col max is ", col_max))
fit_columns = [] # type: List[List[str]]
for _ in range(0, columns):
fit_columns.append([])
indexers = [] # type List[str]
- last_initial = ''
+ last_initial = ""
for idx, name in enumerate(class_list):
col = idx // col_max
@@ -590,7 +602,7 @@ def make_class_list(class_list, columns): # type: (List[str], int) -> None
f.write("\n")
for r in range(0, row_max):
- s = '+ '
+ s = "+ "
for c in range(0, columns):
if r >= len(fit_columns[c]):
continue
@@ -598,13 +610,13 @@ def make_class_list(class_list, columns): # type: (List[str], int) -> None
classname = fit_columns[c][r]
initial = classname[0]
if classname in indexers:
- s += '**' + initial + '** | '
+ s += "**" + initial + "** | "
else:
- s += ' | '
+ s += " | "
- s += '[' + classname + '](class_' + classname.lower() + ') | '
+ s += "[" + classname + "](class_" + classname.lower() + ") | "
- s += '\n'
+ s += "\n"
f.write(s)
for n in range(0, columns):
@@ -618,29 +630,29 @@ def escape_rst(text, until_pos=-1): # type: (str) -> str
# Escape \ character, otherwise it ends up as an escape character in rst
pos = 0
while True:
- pos = text.find('\\', pos, until_pos)
+ pos = text.find("\\", pos, until_pos)
if pos == -1:
break
- text = text[:pos] + "\\\\" + text[pos + 1:]
+ text = text[:pos] + "\\\\" + text[pos + 1 :]
pos += 2
# Escape * character to avoid interpreting it as emphasis
pos = 0
while True:
- pos = text.find('*', pos, until_pos)
+ pos = text.find("*", pos, until_pos)
if pos == -1:
break
- text = text[:pos] + "\*" + text[pos + 1:]
+ text = text[:pos] + "\*" + text[pos + 1 :]
pos += 2
# Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink
pos = 0
while True:
- pos = text.find('_', pos, until_pos)
+ pos = text.find("_", pos, until_pos)
if pos == -1:
break
if not text[pos + 1].isalnum(): # don't escape within a snake_case word
- text = text[:pos] + "\_" + text[pos + 1:]
+ text = text[:pos] + "\_" + text[pos + 1 :]
pos += 2
else:
pos += 1
@@ -652,16 +664,16 @@ def rstize_text(text, state): # type: (str, State) -> str
# Linebreak + tabs in the XML should become two line breaks unless in a "codeblock"
pos = 0
while True:
- pos = text.find('\n', pos)
+ pos = text.find("\n", pos)
if pos == -1:
break
pre_text = text[:pos]
indent_level = 0
- while text[pos + 1] == '\t':
+ while text[pos + 1] == "\t":
pos += 1
indent_level += 1
- post_text = text[pos + 1:]
+ post_text = text[pos + 1 :]
# Handle codeblocks
if post_text.startswith("[codeblock]"):
@@ -670,28 +682,33 @@ def rstize_text(text, state): # type: (str, State) -> str
print_error("[codeblock] without a closing tag, file: {}".format(state.current_class), state)
return ""
- code_text = post_text[len("[codeblock]"):end_pos]
+ code_text = post_text[len("[codeblock]") : end_pos]
post_text = post_text[end_pos:]
# Remove extraneous tabs
code_pos = 0
while True:
- code_pos = code_text.find('\n', code_pos)
+ code_pos = code_text.find("\n", code_pos)
if code_pos == -1:
break
to_skip = 0
- while code_pos + to_skip + 1 < len(code_text) and code_text[code_pos + to_skip + 1] == '\t':
+ while code_pos + to_skip + 1 < len(code_text) and code_text[code_pos + to_skip + 1] == "\t":
to_skip += 1
if to_skip > indent_level:
- print_error("Four spaces should be used for indentation within [codeblock], file: {}".format(state.current_class), state)
-
- if len(code_text[code_pos + to_skip + 1:]) == 0:
+ print_error(
+ "Four spaces should be used for indentation within [codeblock], file: {}".format(
+ state.current_class
+ ),
+ state,
+ )
+
+ if len(code_text[code_pos + to_skip + 1 :]) == 0:
code_text = code_text[:code_pos] + "\n"
code_pos += 1
else:
- code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1:]
+ code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :]
code_pos += 5 - to_skip
text = pre_text + "\n[codeblock]" + code_text + post_text
@@ -702,7 +719,7 @@ def rstize_text(text, state): # type: (str, State) -> str
text = pre_text + "\n\n" + post_text
pos += 2
- next_brac_pos = text.find('[')
+ next_brac_pos = text.find("[")
text = escape_rst(text, next_brac_pos)
# Handle [tags]
@@ -714,54 +731,59 @@ def rstize_text(text, state): # type: (str, State) -> str
tag_depth = 0
previous_pos = 0
while True:
- pos = text.find('[', pos)
+ pos = text.find("[", pos)
if inside_url and (pos > previous_pos):
url_has_name = True
if pos == -1:
break
- endq_pos = text.find(']', pos + 1)
+ endq_pos = text.find("]", pos + 1)
if endq_pos == -1:
break
pre_text = text[:pos]
- post_text = text[endq_pos + 1:]
- tag_text = text[pos + 1:endq_pos]
+ post_text = text[endq_pos + 1 :]
+ tag_text = text[pos + 1 : endq_pos]
escape_post = False
if tag_text in state.classes:
if tag_text == state.current_class:
# We don't want references to the same class
- tag_text = '``{}``'.format(tag_text)
+ tag_text = "``{}``".format(tag_text)
else:
tag_text = make_type(tag_text, state)
escape_post = True
else: # command
cmd = tag_text
- space_pos = tag_text.find(' ')
- if cmd == '/codeblock':
- tag_text = ''
+ space_pos = tag_text.find(" ")
+ if cmd == "/codeblock":
+ tag_text = ""
tag_depth -= 1
inside_code = False
# Strip newline if the tag was alone on one
- if pre_text[-1] == '\n':
+ if pre_text[-1] == "\n":
pre_text = pre_text[:-1]
- elif cmd == '/code':
- tag_text = '``'
+ elif cmd == "/code":
+ tag_text = "``"
tag_depth -= 1
inside_code = False
escape_post = True
elif inside_code:
- tag_text = '[' + tag_text + ']'
- elif cmd.find('html') == 0:
- param = tag_text[space_pos + 1:]
+ tag_text = "[" + tag_text + "]"
+ elif cmd.find("html") == 0:
+ param = tag_text[space_pos + 1 :]
tag_text = param
- elif cmd.startswith('method') or cmd.startswith('member') or cmd.startswith('signal') or cmd.startswith('constant'):
- param = tag_text[space_pos + 1:]
-
- if param.find('.') != -1:
- ss = param.split('.')
+ elif (
+ cmd.startswith("method")
+ or cmd.startswith("member")
+ or cmd.startswith("signal")
+ or cmd.startswith("constant")
+ ):
+ param = tag_text[space_pos + 1 :]
+
+ if param.find(".") != -1:
+ ss = param.split(".")
if len(ss) > 2:
print_error("Bad reference: '{}', file: {}".format(param, state.current_class), state)
class_param, method_param = ss
@@ -794,7 +816,7 @@ def rstize_text(text, state): # type: (str, State) -> str
# Search in the current class
search_class_defs = [class_def]
- if param.find('.') == -1:
+ if param.find(".") == -1:
# Also search in @GlobalScope as a last resort if no class was specified
search_class_defs.append(state.classes["@GlobalScope"])
@@ -815,66 +837,71 @@ def rstize_text(text, state): # type: (str, State) -> str
ref_type = "_constant"
else:
- print_error("Unresolved type reference '{}' in method reference '{}', file: {}".format(class_param, param, state.current_class), state)
+ print_error(
+ "Unresolved type reference '{}' in method reference '{}', file: {}".format(
+ class_param, param, state.current_class
+ ),
+ state,
+ )
repl_text = method_param
if class_param != state.current_class:
repl_text = "{}.{}".format(class_param, method_param)
- tag_text = ':ref:`{}<class_{}{}_{}>`'.format(repl_text, class_param, ref_type, method_param)
+ tag_text = ":ref:`{}<class_{}{}_{}>`".format(repl_text, class_param, ref_type, method_param)
escape_post = True
- elif cmd.find('image=') == 0:
+ elif cmd.find("image=") == 0:
tag_text = "" # '![](' + cmd[6:] + ')'
- elif cmd.find('url=') == 0:
+ elif cmd.find("url=") == 0:
url_link = cmd[4:]
- tag_text = '`'
+ tag_text = "`"
tag_depth += 1
inside_url = True
url_has_name = False
- elif cmd == '/url':
- tag_text = ('' if url_has_name else url_link) + " <" + url_link + ">`_"
+ elif cmd == "/url":
+ tag_text = ("" if url_has_name else url_link) + " <" + url_link + ">`_"
tag_depth -= 1
escape_post = True
inside_url = False
url_has_name = False
- elif cmd == 'center':
+ elif cmd == "center":
tag_depth += 1
- tag_text = ''
- elif cmd == '/center':
+ tag_text = ""
+ elif cmd == "/center":
tag_depth -= 1
- tag_text = ''
- elif cmd == 'codeblock':
+ tag_text = ""
+ elif cmd == "codeblock":
tag_depth += 1
- tag_text = '\n::\n'
+ tag_text = "\n::\n"
inside_code = True
- elif cmd == 'br':
+ elif cmd == "br":
# Make a new paragraph instead of a linebreak, rst is not so linebreak friendly
- tag_text = '\n\n'
+ tag_text = "\n\n"
# Strip potential leading spaces
- while post_text[0] == ' ':
+ while post_text[0] == " ":
post_text = post_text[1:]
- elif cmd == 'i' or cmd == '/i':
+ elif cmd == "i" or cmd == "/i":
if cmd == "/i":
tag_depth -= 1
else:
tag_depth += 1
- tag_text = '*'
- elif cmd == 'b' or cmd == '/b':
+ tag_text = "*"
+ elif cmd == "b" or cmd == "/b":
if cmd == "/b":
tag_depth -= 1
else:
tag_depth += 1
- tag_text = '**'
- elif cmd == 'u' or cmd == '/u':
+ tag_text = "**"
+ elif cmd == "u" or cmd == "/u":
if cmd == "/u":
tag_depth -= 1
else:
tag_depth += 1
- tag_text = ''
- elif cmd == 'code':
- tag_text = '``'
+ tag_text = ""
+ elif cmd == "code":
+ tag_text = "``"
tag_depth += 1
inside_code = True
- elif cmd.startswith('enum '):
+ elif cmd.startswith("enum "):
tag_text = make_enum(cmd[5:], state)
escape_post = True
else:
@@ -883,24 +910,24 @@ def rstize_text(text, state): # type: (str, State) -> str
# Properly escape things like `[Node]s`
if escape_post and post_text and (post_text[0].isalnum() or post_text[0] == "("): # not punctuation, escape
- post_text = '\ ' + post_text
+ post_text = "\ " + post_text
- next_brac_pos = post_text.find('[', 0)
+ next_brac_pos = post_text.find("[", 0)
iter_pos = 0
while not inside_code:
- iter_pos = post_text.find('*', iter_pos, next_brac_pos)
+ iter_pos = post_text.find("*", iter_pos, next_brac_pos)
if iter_pos == -1:
break
- post_text = post_text[:iter_pos] + "\*" + post_text[iter_pos + 1:]
+ post_text = post_text[:iter_pos] + "\*" + post_text[iter_pos + 1 :]
iter_pos += 2
iter_pos = 0
while not inside_code:
- iter_pos = post_text.find('_', iter_pos, next_brac_pos)
+ iter_pos = post_text.find("_", iter_pos, next_brac_pos)
if iter_pos == -1:
break
if not post_text[iter_pos + 1].isalnum(): # don't escape within a snake_case word
- post_text = post_text[:iter_pos] + "\_" + post_text[iter_pos + 1:]
+ post_text = post_text[:iter_pos] + "\_" + post_text[iter_pos + 1 :]
iter_pos += 2
else:
iter_pos += 1
@@ -922,7 +949,7 @@ def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterabl
column_sizes = [0] * len(data[0])
for row in data:
for i, text in enumerate(row):
- text_length = len(text or '')
+ text_length = len(text or "")
if text_length > column_sizes[i]:
column_sizes[i] = text_length
@@ -939,16 +966,16 @@ def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterabl
for i, text in enumerate(row):
if column_sizes[i] == 0 and remove_empty_columns:
continue
- row_text += " " + (text or '').ljust(column_sizes[i]) + " |"
+ row_text += " " + (text or "").ljust(column_sizes[i]) + " |"
row_text += "\n"
f.write(row_text)
f.write(sep)
- f.write('\n')
+ f.write("\n")
def make_type(t, state): # type: (str, State) -> str
if t in state.classes:
- return ':ref:`{0}<class_{0}>`'.format(t)
+ return ":ref:`{0}<class_{0}>`".format(t)
print_error("Unresolved type '{}', file: {}".format(t, state.current_class), state)
return t
@@ -957,7 +984,7 @@ def make_enum(t, state): # type: (str, State) -> str
p = t.find(".")
if p >= 0:
c = t[0:p]
- e = t[p + 1:]
+ e = t[p + 1 :]
# Variant enums live in GlobalScope but still use periods.
if c == "Variant":
c = "@GlobalScope"
@@ -969,7 +996,7 @@ def make_enum(t, state): # type: (str, State) -> str
c = "@GlobalScope"
if not c in state.classes and c.startswith("_"):
- c = c[1:] # Remove the underscore prefix
+ c = c[1:] # Remove the underscore prefix
if c in state.classes and e in state.classes[c].enums:
return ":ref:`{0}<enum_{1}_{0}>`".format(e, c)
@@ -981,7 +1008,9 @@ def make_enum(t, state): # type: (str, State) -> str
return t
-def make_method_signature(class_def, method_def, make_ref, state): # type: (ClassDef, Union[MethodDef, SignalDef], bool, State) -> Tuple[str, str]
+def make_method_signature(
+ class_def, method_def, make_ref, state
+): # type: (ClassDef, Union[MethodDef, SignalDef], bool, State) -> Tuple[str, str]
ret_type = " "
ref_type = "signal"
@@ -996,34 +1025,34 @@ def make_method_signature(class_def, method_def, make_ref, state): # type: (Cla
else:
out += "**{}** ".format(method_def.name)
- out += '**(**'
+ out += "**(**"
for i, arg in enumerate(method_def.parameters):
if i > 0:
- out += ', '
+ out += ", "
else:
- out += ' '
+ out += " "
out += "{} {}".format(arg.type_name.to_rst(state), arg.name)
if arg.default_value is not None:
- out += '=' + arg.default_value
+ out += "=" + arg.default_value
- if isinstance(method_def, MethodDef) and method_def.qualifiers is not None and 'vararg' in method_def.qualifiers:
+ if isinstance(method_def, MethodDef) and method_def.qualifiers is not None and "vararg" in method_def.qualifiers:
if len(method_def.parameters) > 0:
- out += ', ...'
+ out += ", ..."
else:
- out += ' ...'
+ out += " ..."
- out += ' **)**'
+ out += " **)**"
if isinstance(method_def, MethodDef) and method_def.qualifiers is not None:
- out += ' ' + method_def.qualifiers
+ out += " " + method_def.qualifiers
return ret_type, out
def make_heading(title, underline): # type: (str, str) -> str
- return title + '\n' + (underline * len(title)) + "\n\n"
+ return title + "\n" + (underline * len(title)) + "\n\n"
def make_url(link): # type: (str) -> str
@@ -1047,5 +1076,5 @@ def make_url(link): # type: (str) -> str
return "`" + link + " <" + link + ">`_"
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/doc/translations/Makefile b/doc/translations/Makefile
new file mode 100644
index 0000000000..ceee79ec95
--- /dev/null
+++ b/doc/translations/Makefile
@@ -0,0 +1,23 @@
+# Makefile providing various facilities to manage translations
+
+TEMPLATE = classes.pot
+POFILES = $(wildcard *.po)
+LANGS = $(POFILES:%.po=%)
+
+all: update merge
+
+update:
+ @cd ../..; \
+ python3 doc/translations/extract.py \
+ --path doc/classes modules/*/doc_classes \
+ --output doc/translations/$(TEMPLATE)
+
+merge:
+ @for po in $(POFILES); do \
+ echo -e "\nMerging $$po..."; \
+ msgmerge -w 79 -C $$po $$po $(TEMPLATE) > "$$po".new; \
+ mv -f "$$po".new $$po; \
+ done
+
+check:
+ @for po in $(POFILES); do msgfmt -c $$po -o /dev/null; done
diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot
new file mode 100644
index 0000000000..641d80c5ca
--- /dev/null
+++ b/doc/translations/classes.pot
@@ -0,0 +1,57448 @@
+# LANGUAGE translation of the Godot Engine class reference.
+# Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine class reference\n"
+"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+#: doc/tools/makerst.py
+msgid "Description"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Tutorials"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Properties"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Methods"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Theme Properties"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Signals"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Enumerations"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Constants"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Property Descriptions"
+msgstr ""
+
+#: doc/tools/makerst.py
+msgid "Method Descriptions"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:4
+msgid "Built-in GDScript functions."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:7
+msgid ""
+"List of core built-in GDScript functions. Math functions and other "
+"utilities. Everything else is provided by objects. (Keywords: builtin, built "
+"in, global functions.)"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:24
+msgid ""
+"Returns a color constructed from integer red, green, blue, and alpha "
+"channels. Each channel should have 8 bits of information ranging from 0 to "
+"255.\n"
+"[code]r8[/code] red channel\n"
+"[code]g8[/code] green channel\n"
+"[code]b8[/code] blue channel\n"
+"[code]a8[/code] alpha channel\n"
+"[codeblock]\n"
+"red = Color8(255, 0, 0)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:42
+msgid ""
+"Returns a color according to the standardized [code]name[/code] with "
+"[code]alpha[/code] ranging from 0 to 1.\n"
+"[codeblock]\n"
+"red = ColorN(\"red\", 1)\n"
+"[/codeblock]\n"
+"Supported color names are the same as the constants defined in [Color]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:55
+msgid ""
+"Returns the absolute value of parameter [code]s[/code] (i.e. unsigned value, "
+"works for integer and float).\n"
+"[codeblock]\n"
+"# a is 1\n"
+"a = abs(-1)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:68
+msgid ""
+"Returns the arc cosine of [code]s[/code] in radians. Use to get the angle of "
+"cosine [code]s[/code].\n"
+"[codeblock]\n"
+"# c is 0.523599 or 30 degrees if converted with rad2deg(s)\n"
+"c = acos(0.866025)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:81
+msgid ""
+"Returns the arc sine of [code]s[/code] in radians. Use to get the angle of "
+"sine [code]s[/code].\n"
+"[codeblock]\n"
+"# s is 0.523599 or 30 degrees if converted with rad2deg(s)\n"
+"s = asin(0.5)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:96
+msgid ""
+"Asserts that the [code]condition[/code] is [code]true[/code]. If the "
+"[code]condition[/code] is [code]false[/code], an error is generated and the "
+"program is halted until you resume it. Only executes in debug builds, or "
+"when running the game from the editor. Use it for debugging purposes, to "
+"make sure a statement is [code]true[/code] during development.\n"
+"The optional [code]message[/code] argument, if given, is shown in addition "
+"to the generic \"Assertion failed\" message. You can use this to provide "
+"additional details about why the assertion failed.\n"
+"[codeblock]\n"
+"# Imagine we always want speed to be between 0 and 20\n"
+"speed = -10\n"
+"assert(speed < 20) # True, the program will continue\n"
+"assert(speed >= 0) # False, the program will stop\n"
+"assert(speed >= 0 && speed < 20) # You can also combine the two conditional "
+"statements in one check\n"
+"assert(speed < 20, \"speed = %f, but the speed limit is 20\" % speed) # Show "
+"a message with clarifying details\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:114
+msgid ""
+"Returns the arc tangent of [code]s[/code] in radians. Use it to get the "
+"angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == "
+"angle[/code].\n"
+"The method cannot know in which quadrant the angle should fall. See [method "
+"atan2] if you always want an exact angle.\n"
+"[codeblock]\n"
+"a = atan(0.5) # a is 0.463648\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:129
+msgid ""
+"Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle "
+"of tangent [code]y/x[/code]. To compute the value, the method takes into "
+"account the sign of both arguments in order to determine the quadrant.\n"
+"[codeblock]\n"
+"a = atan2(0, -1) # a is 3.141593\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:143
+msgid ""
+"Decodes a byte array back to a value. When [code]allow_objects[/code] is "
+"[code]true[/code] decoding objects is allowed.\n"
+"[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do "
+"not use this option if the serialized object comes from untrusted sources to "
+"avoid potential security threats (remote code execution)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:155
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:145
+msgid ""
+"Converts a 2D point expressed in the cartesian coordinate system (X and Y "
+"axis) to the polar coordinate system (a distance from the origin and an "
+"angle)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:164
+msgid ""
+"Rounds [code]s[/code] upward, returning the smallest integral value that is "
+"not less than [code]s[/code].\n"
+"[codeblock]\n"
+"i = ceil(1.45) # i is 2\n"
+"i = ceil(1.001) # i is 2\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:177
+msgid ""
+"Returns a character as a String of the given Unicode code point (which is "
+"compatible with ASCII code).\n"
+"[codeblock]\n"
+"a = char(65) # a is \"A\"\n"
+"a = char(65 + 32) # a is \"a\"\n"
+"a = char(8364) # a is \"€\"\n"
+"[/codeblock]\n"
+"This is the inverse of [method ord]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:196
+msgid ""
+"Clamps [code]value[/code] and returns a value not less than [code]min[/code] "
+"and not more than [code]max[/code].\n"
+"[codeblock]\n"
+"speed = 1000\n"
+"# a is 20\n"
+"a = clamp(speed, 1, 20)\n"
+"\n"
+"speed = -10\n"
+"# a is 1\n"
+"a = clamp(speed, 1, 20)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:216
+msgid ""
+"Converts from a type to another in the best way possible. The [code]type[/"
+"code] parameter uses the [enum Variant.Type] values.\n"
+"[codeblock]\n"
+"a = Vector2(1, 0)\n"
+"# Prints 1\n"
+"print(a.length())\n"
+"a = convert(a, TYPE_STRING)\n"
+"# Prints 6 as \"(1, 0)\" is 6 characters\n"
+"print(a.length())\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:233
+msgid ""
+"Returns the cosine of angle [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"# Prints 1 then -1\n"
+"print(cos(PI * 2))\n"
+"print(cos(PI))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:247
+msgid ""
+"Returns the hyperbolic cosine of [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"# Prints 1.543081\n"
+"print(cosh(1))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:260
+msgid "Converts from decibels to linear energy (audio)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:273
+msgid ""
+"Returns the result of [code]value[/code] decreased by [code]step[/code] * "
+"[code]amount[/code].\n"
+"[codeblock]\n"
+"# a = 59\n"
+"a = dectime(60, 10, 0.1))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:286
+msgid ""
+"Returns degrees converted to radians.\n"
+"[codeblock]\n"
+"# r is 3.141593\n"
+"r = deg2rad(180)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:299
+msgid ""
+"Converts a previously converted instance to a dictionary, back into an "
+"instance. Useful for deserializing."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:310
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:90
+msgid ""
+"Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is "
+"ease-in, 1+ is ease out. Negative values are in-out/out in."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:319
+msgid ""
+"The natural exponential function. It raises the mathematical constant [b]e[/"
+"b] to the power of [code]s[/code] and returns it.\n"
+"[b]e[/b] has an approximate value of 2.71828.\n"
+"For exponents to other bases use the method [method pow].\n"
+"[codeblock]\n"
+"a = exp(2) # Approximately 7.39\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:333
+msgid ""
+"Rounds [code]s[/code] to the closest smaller integer and returns it.\n"
+"[codeblock]\n"
+"# a is 2.0\n"
+"a = floor(2.99)\n"
+"# a is -3.0\n"
+"a = floor(-2.99)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] This method returns a float. If you need an integer, you can "
+"use [code]int(s)[/code] directly."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:351
+msgid ""
+"Returns the floating-point remainder of [code]a/b[/code], keeping the sign "
+"of [code]a[/code].\n"
+"[codeblock]\n"
+"# Remainder is 1.5\n"
+"var remainder = fmod(7, 5.5)\n"
+"[/codeblock]\n"
+"For the integer remainder operation, use the % operator."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:367
+msgid ""
+"Returns the floating-point modulus of [code]a/b[/code] that wraps equally in "
+"positive and negative.\n"
+"[codeblock]\n"
+"var i = -6\n"
+"while i < 5:\n"
+" prints(i, fposmod(i, 3))\n"
+" i += 1\n"
+"[/codeblock]\n"
+"Produces:\n"
+"[codeblock]\n"
+"-6 0\n"
+"-5 1\n"
+"-4 2\n"
+"-3 0\n"
+"-2 1\n"
+"-1 2\n"
+"0 0\n"
+"1 1\n"
+"2 2\n"
+"3 0\n"
+"4 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:398
+msgid ""
+"Returns a reference to the specified function [code]funcname[/code] in the "
+"[code]instance[/code] node. As functions aren't first-class objects in "
+"GDscript, use [code]funcref[/code] to store a [FuncRef] in a variable and "
+"call it later.\n"
+"[codeblock]\n"
+"func foo():\n"
+" return(\"bar\")\n"
+"\n"
+"a = funcref(self, \"foo\")\n"
+"print(a.call_func()) # Prints bar\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:412
+msgid ""
+"Returns an array of dictionaries representing the current call stack.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" foo()\n"
+"\n"
+"func foo():\n"
+" bar()\n"
+"\n"
+"func bar():\n"
+" print(get_stack())\n"
+"[/codeblock]\n"
+"would print\n"
+"[codeblock]\n"
+"[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, "
+"source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:435
+msgid ""
+"Returns the integer hash of the variable passed.\n"
+"[codeblock]\n"
+"print(hash(\"a\")) # Prints 177670\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:447
+msgid ""
+"Returns the passed instance converted to a dictionary (useful for "
+"serializing).\n"
+"[codeblock]\n"
+"var foo = \"bar\"\n"
+"func _ready():\n"
+" var d = inst2dict(self)\n"
+" print(d.keys())\n"
+" print(d.values())\n"
+"[/codeblock]\n"
+"Prints out:\n"
+"[codeblock]\n"
+"[@subpath, @path, foo]\n"
+"[, res://test.gd, bar]\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:468
+msgid ""
+"Returns the Object that corresponds to [code]instance_id[/code]. All Objects "
+"have a unique instance ID.\n"
+"[codeblock]\n"
+"var foo = \"bar\"\n"
+"func _ready():\n"
+" var id = get_instance_id()\n"
+" var inst = instance_from_id(id)\n"
+" print(inst.foo) # Prints bar\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:488
+msgid ""
+"Returns a normalized value considering the given range. This is the opposite "
+"of [method lerp].\n"
+"[codeblock]\n"
+"var middle = lerp(20, 30, 0.75)\n"
+"# `middle` is now 27.5.\n"
+"# Now, we pretend to have forgotten the original ratio and want to get it "
+"back.\n"
+"var ratio = inverse_lerp(20, 30, 27.5)\n"
+"# `ratio` is now 0.75.\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:506
+msgid ""
+"Returns [code]true[/code] if [code]a[/code] and [code]b[/code] are "
+"approximately equal to each other."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:515
+msgid ""
+"Returns whether [code]s[/code] is an infinity value (either positive "
+"infinity or negative infinity)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:524
+msgid ""
+"Returns whether [code]instance[/code] is a valid object (e.g. has not been "
+"deleted from memory)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:533
+msgid "Returns whether [code]s[/code] is a NaN (Not-A-Number) value."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:542
+msgid "Returns [code]true[/code] if [code]s[/code] is zero or almost zero."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:551
+msgid ""
+"Returns length of Variant [code]var[/code]. Length is the character count of "
+"String, element count of Array, size of Dictionary, etc.\n"
+"[b]Note:[/b] Generates a fatal error if Variant can not provide a length.\n"
+"[codeblock]\n"
+"a = [1, 2, 3, 4]\n"
+"len(a) # Returns 4\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:569
+msgid ""
+"Linearly interpolates between two values by a normalized value. This is the "
+"opposite of [method inverse_lerp].\n"
+"If the [code]from[/code] and [code]to[/code] arguments are of type [int] or "
+"[float], the return value is a [float].\n"
+"If both are of the same vector type ([Vector2], [Vector3] or [Color]), the "
+"return value will be of the same type ([code]lerp[/code] then calls the "
+"vector type's [code]linear_interpolate[/code] method).\n"
+"[codeblock]\n"
+"lerp(0, 4, 0.75) # Returns 3.0\n"
+"lerp(Vector2(1, 5), Vector2(3, 2), 0.5) # Returns Vector2(2, 3.5)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:588
+msgid ""
+"Linearly interpolates between two angles (in radians) by a normalized "
+"value.\n"
+"Similar to [method lerp], but interpolates correctly when the angles wrap "
+"around [constant @GDScript.TAU].\n"
+"[codeblock]\n"
+"extends Sprite\n"
+"var elapsed = 0.0\n"
+"func _process(delta):\n"
+" var min_angle = deg2rad(0.0)\n"
+" var max_angle = deg2rad(90.0)\n"
+" rotation = lerp_angle(min_angle, max_angle, elapsed)\n"
+" elapsed += delta\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:607
+msgid ""
+"Converts from linear energy to decibels (audio). This can be used to "
+"implement volume sliders that behave as expected (since volume isn't "
+"linear). Example:\n"
+"[codeblock]\n"
+"# \"Slider\" refers to a node that inherits Range such as HSlider or "
+"VSlider.\n"
+"# Its range must be configured to go from 0 to 1.\n"
+"# Change the bus name if you'd like to change the volume of a specific bus "
+"only.\n"
+"AudioServer.set_bus_volume_db(AudioServer.get_bus_index(\"Master\"), "
+"linear2db($Slider.value))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:622
+msgid ""
+"Loads a resource from the filesystem located at [code]path[/code].\n"
+"[b]Note:[/b] Resource paths can be obtained by right-clicking on a resource "
+"in the FileSystem dock and choosing [b]Copy Path[/b].\n"
+"[codeblock]\n"
+"# Load a scene called main located in the root of the project directory.\n"
+"var main = load(\"res://main.tscn\")\n"
+"[/codeblock]\n"
+"[b]Important:[/b] The path must be absolute, a local path will just return "
+"[code]null[/code]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:637
+msgid ""
+"Natural logarithm. The amount of time needed to reach a certain level of "
+"continuous growth.\n"
+"[b]Note:[/b] This is not the same as the \"log\" function on most "
+"calculators, which uses a base 10 logarithm.\n"
+"[codeblock]\n"
+"log(10) # Returns 2.302585\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:652
+msgid ""
+"Returns the maximum of two values.\n"
+"[codeblock]\n"
+"max(1, 2) # Returns 2\n"
+"max(-3.99, -4) # Returns -3.99\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:667
+msgid ""
+"Returns the minimum of two values.\n"
+"[codeblock]\n"
+"min(1, 2) # Returns 1\n"
+"min(-3.99, -4) # Returns -4\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:684
+msgid ""
+"Moves [code]from[/code] toward [code]to[/code] by the [code]delta[/code] "
+"value.\n"
+"Use a negative [code]delta[/code] value to move away.\n"
+"[codeblock]\n"
+"move_toward(10, 5, 4) # Returns 6\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:697
+msgid ""
+"Returns the nearest larger power of 2 for integer [code]value[/code].\n"
+"[codeblock]\n"
+"nearest_po2(3) # Returns 4\n"
+"nearest_po2(4) # Returns 4\n"
+"nearest_po2(5) # Returns 8\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:711
+msgid ""
+"Returns an integer representing the Unicode code point of the given Unicode "
+"character [code]char[/code].\n"
+"[codeblock]\n"
+"a = ord(\"A\") # a is 65\n"
+"a = ord(\"a\") # a is 97\n"
+"a = ord(\"€\") # a is 8364\n"
+"[/codeblock]\n"
+"This is the inverse of [method char]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:726
+msgid ""
+"Parse JSON text to a Variant (use [method typeof] to check if it is what you "
+"expect).\n"
+"Be aware that the JSON specification does not define integer or float types, "
+"but only a number type. Therefore, parsing a JSON text will convert all "
+"numerical values to [float] types.\n"
+"Note that JSON objects do not preserve key order like Godot dictionaries, "
+"thus you should not rely on keys being in a certain order if a dictionary is "
+"constructed from JSON. In contrast, JSON arrays retain the order of their "
+"elements:\n"
+"[codeblock]\n"
+"p = parse_json('[\"a\", \"b\", \"c\"]')\n"
+"if typeof(p) == TYPE_ARRAY:\n"
+" print(p[0]) # Prints a\n"
+"else:\n"
+" print(\"unexpected results\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:746
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:142
+msgid ""
+"Converts a 2D point expressed in the polar coordinate system (a distance "
+"from the origin [code]r[/code] and an angle [code]th[/code]) to the "
+"cartesian coordinate system (X and Y axis)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:757
+msgid ""
+"Returns the integer modulus of [code]a/b[/code] that wraps equally in "
+"positive and negative.\n"
+"[codeblock]\n"
+"var i = -6\n"
+"while i < 5:\n"
+" prints(i, posmod(i, 3))\n"
+" i += 1\n"
+"[/codeblock]\n"
+"Produces:\n"
+"[codeblock]\n"
+"-6 0\n"
+"-5 1\n"
+"-4 2\n"
+"-3 0\n"
+"-2 1\n"
+"-1 2\n"
+"0 0\n"
+"1 1\n"
+"2 2\n"
+"3 0\n"
+"4 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:788
+msgid ""
+"Returns the result of [code]x[/code] raised to the power of [code]y[/code].\n"
+"[codeblock]\n"
+"pow(2, 5) # Returns 32\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:800
+msgid ""
+"Returns a resource from the filesystem that is loaded during script "
+"parsing.\n"
+"[b]Note:[/b] Resource paths can be obtained by right clicking on a resource "
+"in the Assets Panel and choosing \"Copy Path\".\n"
+"[codeblock]\n"
+"# Load a scene called main located in the root of the project directory.\n"
+"var main = preload(\"res://main.tscn\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:812
+msgid ""
+"Converts one or more arguments to strings in the best way possible and "
+"prints them to the console.\n"
+"[codeblock]\n"
+"a = [1, 2, 3]\n"
+"print(\"a\", \"b\", a) # Prints ab[1, 2, 3]\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:823
+msgid "Like [method print], but prints only when used in debug mode."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:830
+msgid ""
+"Prints a stack track at code location, only works when running with debugger "
+"turned on.\n"
+"Output in the console would look something like this:\n"
+"[codeblock]\n"
+"Frame 0 - res://test.gd:16 in function '_process'\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:841
+msgid ""
+"Prints one or more arguments to strings in the best way possible to standard "
+"error line.\n"
+"[codeblock]\n"
+"printerr(\"prints to stderr\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:851
+msgid ""
+"Prints one or more arguments to strings in the best way possible to console. "
+"No newline is added at the end.\n"
+"[codeblock]\n"
+"printraw(\"A\")\n"
+"printraw(\"B\")\n"
+"# Prints AB\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Due to limitations with Godot's built-in console, this only "
+"prints to the terminal. If you need to print in the editor, use another "
+"method, such as [method print]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:864
+msgid ""
+"Prints one or more arguments to the console with a space between each "
+"argument.\n"
+"[codeblock]\n"
+"prints(\"A\", \"B\", \"C\") # Prints A B C\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:874
+msgid ""
+"Prints one or more arguments to the console with a tab between each "
+"argument.\n"
+"[codeblock]\n"
+"printt(\"A\", \"B\", \"C\") # Prints A B C\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:886
+msgid ""
+"Pushes an error message to Godot's built-in debugger and to the OS "
+"terminal.\n"
+"[codeblock]\n"
+"push_error(\"test error\") # Prints \"test error\" to debugger and terminal "
+"as error call\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:898
+msgid ""
+"Pushes a warning message to Godot's built-in debugger and to the OS "
+"terminal.\n"
+"[codeblock]\n"
+"push_warning(\"test warning\") # Prints \"test warning\" to debugger and "
+"terminal as warning call\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:910
+msgid ""
+"Converts from radians to degrees.\n"
+"[codeblock]\n"
+"rad2deg(0.523599) # Returns 30\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:924
+msgid ""
+"Random range, any floating point value between [code]from[/code] and "
+"[code]to[/code].\n"
+"[codeblock]\n"
+"prints(rand_range(0, 1), rand_range(0, 1)) # Prints e.g. 0.135591 0.405263\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:936
+msgid ""
+"Random from seed: pass a [code]seed[/code], and an array with both number "
+"and new seed is returned. \"Seed\" here refers to the internal state of the "
+"pseudo random number generator. The internal state of the current "
+"implementation is 64 bits."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:943
+msgid ""
+"Returns a random floating point value on the interval [code][0, 1][/code].\n"
+"[codeblock]\n"
+"randf() # Returns e.g. 0.375671\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:953
+msgid ""
+"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).\n"
+"[codeblock]\n"
+"randi() # Returns random integer between 0 and 2^32 - 1\n"
+"randi() % 20 # Returns random integer between 0 and 19\n"
+"randi() % 100 # Returns random integer between 0 and 99\n"
+"randi() % 100 + 1 # Returns random integer between 1 and 100\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:966
+msgid ""
+"Randomizes the seed (or the internal state) of the random number generator. "
+"Current implementation reseeds using a number based on time.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" randomize()\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:977
+msgid ""
+"Returns an array with the given range. Range can be 1 argument N (0 to N-1), "
+"two arguments (initial, final-1) or three arguments (initial, final-1, "
+"increment).\n"
+"[codeblock]\n"
+"for i in range(4):\n"
+" print(i)\n"
+"for i in range(2, 5):\n"
+" print(i)\n"
+"for i in range(0, 6, 2):\n"
+" print(i)\n"
+"[/codeblock]\n"
+"Output:\n"
+"[codeblock]\n"
+"0\n"
+"1\n"
+"2\n"
+"3\n"
+"\n"
+"2\n"
+"3\n"
+"4\n"
+"\n"
+"0\n"
+"2\n"
+"4\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1017
+msgid ""
+"Maps a [code]value[/code] from range [code][istart, istop][/code] to [code]"
+"[ostart, ostop][/code].\n"
+"[codeblock]\n"
+"range_lerp(75, 0, 100, -1, 1) # Returns 0.5\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1029
+msgid ""
+"Returns the integral value that is nearest to [code]s[/code], with halfway "
+"cases rounded away from zero.\n"
+"[codeblock]\n"
+"round(2.6) # Returns 3\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1041
+msgid ""
+"Sets seed for the random number generator.\n"
+"[codeblock]\n"
+"my_seed = \"Godot Rocks\"\n"
+"seed(my_seed.hash())\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1054
+msgid ""
+"Returns the sign of [code]s[/code]: -1 or 1. Returns 0 if [code]s[/code] is "
+"0.\n"
+"[codeblock]\n"
+"sign(-6) # Returns -1\n"
+"sign(0) # Returns 0\n"
+"sign(6) # Returns 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1068
+msgid ""
+"Returns the sine of angle [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"sin(0.523599) # Returns 0.5\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1080
+msgid ""
+"Returns the hyperbolic sine of [code]s[/code].\n"
+"[codeblock]\n"
+"a = log(2.0) # Returns 0.693147\n"
+"sinh(a) # Returns 0.75\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1097
+msgid ""
+"Returns a number smoothly interpolated between the [code]from[/code] and "
+"[code]to[/code], based on the [code]weight[/code]. Similar to [method lerp], "
+"but interpolates faster at the beginning and slower at the end.\n"
+"[codeblock]\n"
+"smoothstep(0, 2, 0.5) # Returns 0.15\n"
+"smoothstep(0, 2, 1.0) # Returns 0.5\n"
+"smoothstep(0, 2, 2.0) # Returns 1.0\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1111
+msgid ""
+"Returns the square root of [code]s[/code].\n"
+"[codeblock]\n"
+"sqrt(9) # Returns 3\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1123
+msgid ""
+"Returns the position of the first non-zero digit, after the decimal point. "
+"Note that the maximum return value is 10, which is a design decision in the "
+"implementation.\n"
+"[codeblock]\n"
+"# n is 0\n"
+"n = step_decimals(5)\n"
+"# n is 4\n"
+"n = step_decimals(1.0005)\n"
+"# n is 9\n"
+"n = step_decimals(0.000000005)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1142
+msgid ""
+"Snaps float value [code]s[/code] to a given [code]step[/code]. This can also "
+"be used to round a floating point number to an arbitrary number of "
+"decimals.\n"
+"[codeblock]\n"
+"stepify(100, 32) # Returns 96\n"
+"stepify(3.14159, 0.01) # Returns 3.14\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1153
+msgid ""
+"Converts one or more arguments to string in the best way possible.\n"
+"[codeblock]\n"
+"var a = [10, 20, 30]\n"
+"var b = str(a);\n"
+"len(a) # Returns 3\n"
+"len(b) # Returns 12\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1168
+msgid ""
+"Converts a formatted string that was returned by [method var2str] to the "
+"original value.\n"
+"[codeblock]\n"
+"a = '{ \"a\": 1, \"b\": 2 }'\n"
+"b = str2var(a)\n"
+"print(b[\"a\"]) # Prints 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1182
+msgid ""
+"Returns the tangent of angle [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"tan(deg2rad(45)) # Returns 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1194
+msgid ""
+"Returns the hyperbolic tangent of [code]s[/code].\n"
+"[codeblock]\n"
+"a = log(2.0) # Returns 0.693147\n"
+"tanh(a) # Returns 0.6\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1207
+msgid ""
+"Converts a Variant [code]var[/code] to JSON text and return the result. "
+"Useful for serializing data to store or send over the network.\n"
+"[codeblock]\n"
+"a = { \"a\": 1, \"b\": 2 }\n"
+"b = to_json(a)\n"
+"print(b) # {\"a\":1, \"b\":2}\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1221
+msgid ""
+"Returns whether the given class exists in [ClassDB].\n"
+"[codeblock]\n"
+"type_exists(\"Sprite2D\") # Returns true\n"
+"type_exists(\"Variant\") # Returns false\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1234
+msgid ""
+"Returns the internal type of the given Variant object, using the [enum "
+"Variant.Type] values.\n"
+"[codeblock]\n"
+"p = parse_json('[\"a\", \"b\", \"c\"]')\n"
+"if typeof(p) == TYPE_ARRAY:\n"
+" print(p[0]) # Prints a\n"
+"else:\n"
+" print(\"unexpected results\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1250
+msgid ""
+"Checks that [code]json[/code] is valid JSON data. Returns an empty string if "
+"valid, or an error message otherwise.\n"
+"[codeblock]\n"
+"j = to_json([1, 2, 3])\n"
+"v = validate_json(j)\n"
+"if not v:\n"
+" print(\"valid\")\n"
+"else:\n"
+" prints(\"invalid\", v)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1269
+msgid ""
+"Encodes a variable value to a byte array. When [code]full_objects[/code] is "
+"[code]true[/code] encoding objects is allowed (and can potentially include "
+"code)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1278
+msgid ""
+"Converts a Variant [code]var[/code] to a formatted string that can later be "
+"parsed using [method str2var].\n"
+"[codeblock]\n"
+"a = { \"a\": 1, \"b\": 2 }\n"
+"print(var2str(a))\n"
+"[/codeblock]\n"
+"prints\n"
+"[codeblock]\n"
+"{\n"
+"\"a\": 1,\n"
+"\"b\": 2\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1298
+msgid ""
+"Returns a weak reference to an object.\n"
+"A weak reference to an object is not enough to keep the object alive: when "
+"the only remaining references to a referent are weak references, garbage "
+"collection is free to destroy the referent and reuse its memory for "
+"something else. However, until the object is actually destroyed the weak "
+"reference may return the object even if there are no strong references to it."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1312
+msgid ""
+"Wraps float [code]value[/code] between [code]min[/code] and [code]max[/"
+"code].\n"
+"Usable for creating loop-alike behavior or infinite surfaces.\n"
+"[codeblock]\n"
+"# a is 0.5\n"
+"a = wrapf(10.5, 0.0, 10.0)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# a is 9.5\n"
+"a = wrapf(-0.5, 0.0, 10.0)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# Infinite loop between 0.0 and 0.99\n"
+"f = wrapf(f + 0.1, 0.0, 1.0)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# Infinite rotation (in radians)\n"
+"angle = wrapf(angle + 0.1, 0.0, TAU)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] If you just want to wrap between 0.0 and [code]n[/code] (where "
+"[code]n[/code] is a positive floating-point value), it is better for "
+"performance to use the [method fmod] method like [code]fmod(number, n)[/"
+"code].\n"
+"[code]wrapf[/code] is more flexible than using the [method fmod] approach by "
+"giving the user a simple control over the minimum value. It also fully "
+"supports negative numbers, e.g.\n"
+"[codeblock]\n"
+"# Infinite rotation (in radians)\n"
+"angle = wrapf(angle + 0.1, -PI, PI)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1348
+msgid ""
+"Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/"
+"code].\n"
+"Usable for creating loop-alike behavior or infinite surfaces.\n"
+"[codeblock]\n"
+"# a is 0\n"
+"a = wrapi(10, 0, 10)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# a is 9\n"
+"a = wrapi(-1, 0, 10)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# Infinite loop between 0 and 9\n"
+"frame = wrapi(frame + 1, 0, 10)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] If you just want to wrap between 0 and [code]n[/code] (where "
+"[code]n[/code] is a positive integer value), it is better for performance to "
+"use the modulo operator like [code]number % n[/code].\n"
+"[code]wrapi[/code] is more flexible than using the modulo approach by giving "
+"the user a simple control over the minimum value. It also fully supports "
+"negative numbers, e.g.\n"
+"[codeblock]\n"
+"# result is -2\n"
+"var result = wrapi(-6, -5, -1)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1378
+msgid ""
+"Stops the function execution and returns the current suspended state to the "
+"calling function.\n"
+"From the caller, call [method GDScriptFunctionState.resume] on the state to "
+"resume execution. This invalidates the state. Within the resumed function, "
+"[code]yield()[/code] returns whatever was passed to the [code]resume()[/"
+"code] function call.\n"
+"If passed an object and a signal, the execution is resumed when the object "
+"emits the given signal. In this case, [code]yield()[/code] returns the "
+"argument passed to [code]emit_signal()[/code] if the signal takes only one "
+"argument, or an array containing all the arguments passed to "
+"[code]emit_signal()[/code] if the signal takes multiple arguments.\n"
+"You can also use [code]yield[/code] to wait for a function to finish:\n"
+"[codeblock]\n"
+"func _ready():\n"
+" yield(countdown(), \"completed\") # waiting for the countdown() function "
+"to complete\n"
+" print('Ready')\n"
+"\n"
+"func countdown():\n"
+" yield(get_tree(), \"idle_frame\") # returns a GDScriptFunctionState "
+"object to _ready()\n"
+" print(3)\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(2)\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(1)\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+"\n"
+"# prints:\n"
+"# 3\n"
+"# 2\n"
+"# 1\n"
+"# Ready\n"
+"[/codeblock]\n"
+"When yielding on a function, the [code]completed[/code] signal will be "
+"emitted automatically when the function returns. It can, therefore, be used "
+"as the [code]signal[/code] parameter of the [code]yield[/code] method to "
+"resume.\n"
+"In order to yield on a function, the resulting function should also return a "
+"[code]GDScriptFunctionState[/code]. Notice [code]yield(get_tree(), "
+"\"idle_frame\")[/code] from the above example."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1409
+msgid ""
+"Constant that represents how many times the diameter of a circle fits around "
+"its perimeter."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1412
+msgid "The circle constant, the circumference of the unit circle."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1415
+msgid "A positive infinity. (For negative infinity, use -INF)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1418
+msgid ""
+"Macro constant that expands to an expression of type float that represents a "
+"NaN.\n"
+"The NaN values are used to identify undefined or non-representable values "
+"for floating-point elements, such as the square root of negative numbers or "
+"the result of 0/0."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:4
+msgid "Global scope constants and variables."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:7
+msgid ""
+"Global scope constants and variables. This is all that resides in the "
+"globals, constants regarding error codes, keycodes, property hints, etc.\n"
+"Singletons are also documented here, since they can be accessed from "
+"anywhere."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:16
+msgid "The [ARVRServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:19
+msgid "The [AudioServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:22
+msgid "The [CameraServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:25
+msgid "The [ClassDB] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:28
+msgid "The [Engine] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:31
+msgid "The [Geometry] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:34
+msgid ""
+"The [GodotSharp] singleton. Only available when using Godot's Mono build."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:37
+msgid "The [IP] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:40
+msgid "The [InputFilter] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:43
+msgid "The [InputMap] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:46
+msgid "The [JSON] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:49
+msgid ""
+"The [JavaClassWrapper] singleton.\n"
+"[b]Note:[/b] Only implemented on Android."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:53
+msgid ""
+"The [JavaScript] singleton.\n"
+"[b]Note:[/b] Only implemented on HTML5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:57
+msgid "The [Marshalls] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:60
+msgid "The [NavigationMeshGenerator] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:63 doc/classes/@GlobalScope.xml:66
+msgid "The [NavigationServer2D] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:69
+msgid "The [OS] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:72
+msgid "The [Performance] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:75
+msgid "The [PhysicsServer2D] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:78
+msgid "The [PhysicsServer3D] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:81
+msgid "The [ProjectSettings] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:84
+msgid "The [RenderingServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:87
+msgid "The [ResourceLoader] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:90
+msgid "The [ResourceSaver] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:93
+msgid "The [TranslationServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:96
+msgid "The [VisualScriptEditor] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:101
+msgid "Left margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:104
+msgid "Top margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:107
+msgid "Right margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:110
+msgid ""
+"Bottom margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:113
+msgid "Top-left corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:116
+msgid "Top-right corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:119
+msgid "Bottom-right corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:122
+msgid "Bottom-left corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:125
+msgid ""
+"General vertical alignment, usually used for [Separator], [ScrollBar], "
+"[Slider], etc."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:128
+msgid ""
+"General horizontal alignment, usually used for [Separator], [ScrollBar], "
+"[Slider], etc."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:131
+msgid "Horizontal left alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:134
+msgid "Horizontal center alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:137
+msgid "Horizontal right alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:140
+msgid "Vertical top alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:143
+msgid "Vertical center alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:146
+msgid "Vertical bottom alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:149
+msgid "Keycodes with this bit applied are non-printable."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:152
+msgid "Escape key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:155
+msgid "Tab key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:158
+msgid "Shift+Tab key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:161
+msgid "Backspace key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:164
+msgid "Return key (on the main keyboard)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:167
+msgid "Enter key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:170
+msgid "Insert key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:173
+msgid "Delete key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:176
+msgid "Pause key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:179
+msgid "Print Screen key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:182
+msgid "System Request key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:185
+msgid "Clear key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:188
+msgid "Home key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:191
+msgid "End key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:194
+msgid "Left arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:197
+msgid "Up arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:200
+msgid "Right arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:203
+msgid "Down arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:206
+msgid "Page Up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:209
+msgid "Page Down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:212
+msgid "Shift key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:215
+msgid "Control key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:218
+msgid "Meta key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:221
+msgid "Alt key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:224
+msgid "Caps Lock key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:227
+msgid "Num Lock key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:230
+msgid "Scroll Lock key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:233
+msgid "F1 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:236
+msgid "F2 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:239
+msgid "F3 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:242
+msgid "F4 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:245
+msgid "F5 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:248
+msgid "F6 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:251
+msgid "F7 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:254
+msgid "F8 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:257
+msgid "F9 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:260
+msgid "F10 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:263
+msgid "F11 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:266
+msgid "F12 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:269
+msgid "F13 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:272
+msgid "F14 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:275
+msgid "F15 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:278
+msgid "F16 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:281
+msgid "Multiply (*) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:284
+msgid "Divide (/) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:287
+msgid "Subtract (-) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:290
+msgid "Period (.) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:293
+msgid "Add (+) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:296
+msgid "Number 0 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:299
+msgid "Number 1 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:302
+msgid "Number 2 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:305
+msgid "Number 3 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:308
+msgid "Number 4 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:311
+msgid "Number 5 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:314
+msgid "Number 6 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:317
+msgid "Number 7 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:320
+msgid "Number 8 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:323
+msgid "Number 9 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:326
+msgid "Left Super key (Windows key)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:329
+msgid "Right Super key (Windows key)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:332
+msgid "Context menu key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:335
+msgid "Left Hyper key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:338
+msgid "Right Hyper key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:341
+msgid "Help key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:344
+msgid "Left Direction key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:347
+msgid "Right Direction key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:350
+msgid "Back key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:353
+msgid "Forward key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:356
+msgid "Stop key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:359
+msgid "Refresh key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:362
+msgid "Volume down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:365
+msgid "Mute volume key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:368
+msgid "Volume up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:371
+msgid "Bass Boost key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:374
+msgid "Bass up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:377
+msgid "Bass down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:380
+msgid "Treble up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:383
+msgid "Treble down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:386
+msgid "Media play key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:389
+msgid "Media stop key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:392
+msgid "Previous song key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:395
+msgid "Next song key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:398
+msgid "Media record key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:401
+msgid "Home page key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:404
+msgid "Favorites key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:407
+msgid "Search key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:410
+msgid "Standby key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:413
+msgid "Open URL / Launch Browser key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:416
+msgid "Launch Mail key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:419
+msgid "Launch Media key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:422
+msgid "Launch Shortcut 0 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:425
+msgid "Launch Shortcut 1 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:428
+msgid "Launch Shortcut 2 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:431
+msgid "Launch Shortcut 3 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:434
+msgid "Launch Shortcut 4 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:437
+msgid "Launch Shortcut 5 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:440
+msgid "Launch Shortcut 6 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:443
+msgid "Launch Shortcut 7 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:446
+msgid "Launch Shortcut 8 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:449
+msgid "Launch Shortcut 9 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:452
+msgid "Launch Shortcut A key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:455
+msgid "Launch Shortcut B key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:458
+msgid "Launch Shortcut C key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:461
+msgid "Launch Shortcut D key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:464
+msgid "Launch Shortcut E key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:467
+msgid "Launch Shortcut F key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:470
+msgid "Unknown key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:473
+msgid "Space key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:476
+msgid "! key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:479
+msgid "\" key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:482
+msgid "# key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:485
+msgid "$ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:488
+msgid "% key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:491
+msgid "& key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:494
+msgid "' key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:497
+msgid "( key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:500
+msgid ") key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:503
+msgid "* key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:506
+msgid "+ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:509
+msgid ", key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:512
+msgid "- key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:515
+msgid ". key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:518
+msgid "/ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:521
+msgid "Number 0."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:524
+msgid "Number 1."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:527
+msgid "Number 2."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:530
+msgid "Number 3."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:533
+msgid "Number 4."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:536
+msgid "Number 5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:539
+msgid "Number 6."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:542
+msgid "Number 7."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:545
+msgid "Number 8."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:548
+msgid "Number 9."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:551
+msgid ": key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:554
+msgid "; key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:557
+msgid "< key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:560
+msgid "= key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:563
+msgid "> key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:566
+msgid "? key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:569
+msgid "@ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:572
+msgid "A key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:575
+msgid "B key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:578
+msgid "C key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:581
+msgid "D key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:584
+msgid "E key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:587
+msgid "F key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:590
+msgid "G key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:593
+msgid "H key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:596
+msgid "I key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:599
+msgid "J key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:602
+msgid "K key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:605
+msgid "L key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:608
+msgid "M key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:611
+msgid "N key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:614
+msgid "O key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:617
+msgid "P key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:620
+msgid "Q key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:623
+msgid "R key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:626
+msgid "S key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:629
+msgid "T key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:632
+msgid "U key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:635
+msgid "V key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:638
+msgid "W key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:641
+msgid "X key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:644
+msgid "Y key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:647
+msgid "Z key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:650
+msgid "[ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:653
+msgid "\\ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:656
+msgid "] key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:659
+msgid "^ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:662
+msgid "_ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:665
+msgid "` key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:668
+msgid "{ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:671
+msgid "| key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:674
+msgid "} key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:677
+msgid "~ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:680
+msgid "Non-breakable space key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:683
+msgid "¡ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:686
+msgid "¢ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:689
+msgid "£ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:692
+msgid "¤ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:695
+msgid "¥ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:698
+msgid "¦ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:701
+msgid "§ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:704
+msgid "¨ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:707
+msgid "© key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:710
+msgid "ª key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:713
+msgid "« key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:716
+msgid "¬ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:719
+msgid "Soft hyphen key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:722
+msgid "® key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:725
+msgid "¯ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:728
+msgid "° key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:731
+msgid "± key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:734
+msgid "² key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:737
+msgid "³ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:740
+msgid "´ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:743
+msgid "µ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:746
+msgid "¶ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:749
+msgid "· key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:752
+msgid "¸ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:755
+msgid "¹ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:758
+msgid "º key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:761
+msgid "» key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:764
+msgid "¼ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:767
+msgid "½ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:770
+msgid "¾ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:773
+msgid "¿ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:776
+msgid "À key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:779
+msgid "Á key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:782
+msgid "Â key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:785
+msgid "Ã key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:788
+msgid "Ä key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:791
+msgid "Å key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:794
+msgid "Æ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:797
+msgid "Ç key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:800
+msgid "È key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:803
+msgid "É key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:806
+msgid "Ê key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:809
+msgid "Ë key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:812
+msgid "Ì key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:815
+msgid "Í key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:818
+msgid "Î key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:821
+msgid "Ï key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:824
+msgid "Ð key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:827
+msgid "Ñ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:830
+msgid "Ò key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:833
+msgid "Ó key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:836
+msgid "Ô key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:839
+msgid "Õ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:842
+msgid "Ö key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:845
+msgid "× key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:848
+msgid "Ø key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:851
+msgid "Ù key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:854
+msgid "Ú key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:857
+msgid "Û key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:860
+msgid "Ü key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:863
+msgid "Ý key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:866
+msgid "Þ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:869
+msgid "ß key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:872
+msgid "÷ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:875
+msgid "ÿ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:878
+msgid "Key Code mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:881
+msgid "Modifier key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:884
+msgid "Shift key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:887
+msgid "Alt key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:890
+msgid "Meta key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:893
+msgid "Ctrl key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:896
+msgid ""
+"Command key mask. On macOS, this is equivalent to [constant KEY_MASK_META]. "
+"On other platforms, this is equivalent to [constant KEY_MASK_CTRL]. This "
+"mask should be preferred to [constant KEY_MASK_META] or [constant "
+"KEY_MASK_CTRL] for system shortcuts as it handles all platforms correctly."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:899
+msgid "Keypad key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:902
+msgid "Group Switch key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:905
+msgid "Left mouse button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:908
+msgid "Right mouse button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:911
+msgid "Middle mouse button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:914
+msgid "Extra mouse button 1 (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:917
+msgid "Extra mouse button 2 (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:920
+msgid "Mouse wheel up."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:923
+msgid "Mouse wheel down."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:926
+msgid "Mouse wheel left button (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:929
+msgid "Mouse wheel right button (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:932
+msgid "Left mouse button mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:935
+msgid "Right mouse button mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:938
+msgid "Middle mouse button mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:941
+msgid "Extra mouse button 1 mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:944
+msgid "Extra mouse button 2 mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:947
+msgid "Gamepad button 0."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:950
+msgid "Gamepad button 1."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:953
+msgid "Gamepad button 2."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:956
+msgid "Gamepad button 3."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:959
+msgid "Gamepad button 4."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:962
+msgid "Gamepad button 5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:965
+msgid "Gamepad button 6."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:968
+msgid "Gamepad button 7."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:971
+msgid "Gamepad button 8."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:974
+msgid "Gamepad button 9."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:977
+msgid "Gamepad button 10."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:980
+msgid "Gamepad button 11."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:983
+msgid "Gamepad button 12."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:986
+msgid "Gamepad button 13."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:989
+msgid "Gamepad button 14."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:992
+msgid "Gamepad button 15."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:995
+msgid "Represents the maximum number of joystick buttons supported."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:998
+msgid "DualShock circle button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1001
+msgid "DualShock X button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1004
+msgid "DualShock square button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1007
+msgid "DualShock triangle button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1010
+msgid "Xbox controller B button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1013
+msgid "Xbox controller A button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1016
+msgid "Xbox controller X button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1019
+msgid "Xbox controller Y button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1022
+msgid "Nintendo controller A button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1025
+msgid "Nintendo controller B button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1028
+msgid "Nintendo controller X button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1031
+msgid "Nintendo controller Y button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1034
+msgid "Grip (side) buttons on a VR controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1037
+msgid "Push down on the touchpad or main joystick on a VR controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1040
+msgid "Trigger on a VR controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1043
+msgid ""
+"A button on the right Oculus Touch controller, X button on the left "
+"controller (also when used in OpenVR)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1046
+msgid ""
+"B button on the right Oculus Touch controller, Y button on the left "
+"controller (also when used in OpenVR)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1049
+msgid "Menu button on either Oculus Touch controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1052
+msgid "Menu button in OpenVR (Except when Oculus Touch controllers are used)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1055
+msgid "Gamepad button Select."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1058
+msgid "Gamepad button Start."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1061
+msgid "Gamepad DPad up."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1064
+msgid "Gamepad DPad down."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1067
+msgid "Gamepad DPad left."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1070
+msgid "Gamepad DPad right."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1073
+msgid "Gamepad left Shoulder button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1076
+msgid "Gamepad left trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1079
+msgid "Gamepad left stick click."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1082
+msgid "Gamepad right Shoulder button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1085
+msgid "Gamepad right trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1088
+msgid "Gamepad right stick click."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1091 doc/classes/@GlobalScope.xml:1124
+msgid "Gamepad left stick horizontal axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1094 doc/classes/@GlobalScope.xml:1127
+msgid "Gamepad left stick vertical axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1097 doc/classes/@GlobalScope.xml:1130
+msgid "Gamepad right stick horizontal axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1100 doc/classes/@GlobalScope.xml:1133
+msgid "Gamepad right stick vertical axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1103
+msgid "Generic gamepad axis 4."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1106
+msgid "Generic gamepad axis 5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1109
+msgid "Gamepad left trigger analog axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1112
+msgid "Gamepad right trigger analog axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1115
+msgid "Generic gamepad axis 8."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1118
+msgid "Generic gamepad axis 9."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1121
+msgid "Represents the maximum number of joystick axes supported."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1136
+msgid "Gamepad left analog trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1139
+msgid "Gamepad right analog trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1142
+msgid "VR Controller analog trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1145
+msgid "VR Controller analog grip (side buttons)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1148
+msgid ""
+"OpenVR touchpad X axis (Joystick axis on Oculus Touch and Windows MR "
+"controllers)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1151
+msgid ""
+"OpenVR touchpad Y axis (Joystick axis on Oculus Touch and Windows MR "
+"controllers)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1154
+msgid "MIDI note OFF message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1157
+msgid "MIDI note ON message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1160
+msgid "MIDI aftertouch message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1163
+msgid "MIDI control change message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1166
+msgid "MIDI program change message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1169
+msgid "MIDI channel pressure message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1172
+msgid "MIDI pitch bend message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1175
+msgid ""
+"Methods that return [enum Error] return [constant OK] when no error "
+"occurred. Note that many functions don't return an error code but will print "
+"error messages to standard output.\n"
+"Since [constant OK] has value 0, and all other failure codes are positive "
+"integers, it can also be used in boolean checks, e.g.:\n"
+"[codeblock]\n"
+"var err = method_that_returns_error()\n"
+"if err != OK:\n"
+" print(\"Failure!)\n"
+"# Or, equivalent:\n"
+"if err:\n"
+" print(\"Still failing!)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1187
+msgid "Generic error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1190
+msgid "Unavailable error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1193
+msgid "Unconfigured error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1196
+msgid "Unauthorized error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1199
+msgid "Parameter range error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1202
+msgid "Out of memory (OOM) error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1205
+msgid "File: Not found error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1208
+msgid "File: Bad drive error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1211
+msgid "File: Bad path error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1214
+msgid "File: No permission error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1217
+msgid "File: Already in use error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1220
+msgid "File: Can't open error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1223
+msgid "File: Can't write error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1226
+msgid "File: Can't read error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1229
+msgid "File: Unrecognized error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1232
+msgid "File: Corrupt error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1235
+msgid "File: Missing dependencies error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1238
+msgid "File: End of file (EOF) error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1241
+msgid "Can't open error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1244
+msgid "Can't create error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1247
+msgid "Query failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1250
+msgid "Already in use error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1253
+msgid "Locked error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1256
+msgid "Timeout error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1259
+msgid "Can't connect error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1262
+msgid "Can't resolve error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1265
+msgid "Connection error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1268
+msgid "Can't acquire resource error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1271
+msgid "Can't fork process error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1274
+msgid "Invalid data error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1277
+msgid "Invalid parameter error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1280
+msgid "Already exists error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1283
+msgid "Does not exist error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1286
+msgid "Database: Read error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1289
+msgid "Database: Write error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1292
+msgid "Compilation failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1295
+msgid "Method not found error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1298
+msgid "Linking failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1301
+msgid "Script failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1304
+msgid "Cycling link (import cycle) error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1307
+msgid "Invalid declaration error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1310
+msgid "Duplicate symbol error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1313
+msgid "Parse error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1316
+msgid "Busy error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1319
+msgid "Skip error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1322
+msgid "Help error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1325
+msgid "Bug error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1328
+msgid ""
+"Printer on fire error. (This is an easter egg, no engine methods return this "
+"error code.)"
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1331
+msgid "No hint for the edited property."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1334
+msgid ""
+"Hints that an integer or float property should be within a range specified "
+"via the hint string [code]\"min,max\"[/code] or [code]\"min,max,step\"[/"
+"code]. The hint string can optionally include [code]\"or_greater\"[/code] "
+"and/or [code]\"or_lesser\"[/code] to allow manual input going respectively "
+"above the max or below the min values. Example: [code]\"-360,360,1,"
+"or_greater,or_lesser\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1337
+msgid ""
+"Hints that an integer or float property should be within an exponential "
+"range specified via the hint string [code]\"min,max\"[/code] or [code]\"min,"
+"max,step\"[/code]. The hint string can optionally include [code]\"or_greater"
+"\"[/code] and/or [code]\"or_lesser\"[/code] to allow manual input going "
+"respectively above the max or below the min values. Example: "
+"[code]\"0.01,100,0.01,or_greater\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1340
+msgid ""
+"Hints that an integer, float or string property is an enumerated value to "
+"pick in a list specified via a hint string such as [code]\"Hello,Something,"
+"Else\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1343
+msgid ""
+"Hints that a float property should be edited via an exponential easing "
+"function. The hint string can include [code]\"attenuation\"[/code] to flip "
+"the curve horizontally and/or [code]\"inout\"[/code] to also include in/out "
+"easing."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1346 doc/classes/@GlobalScope.xml:1349
+msgid "Deprecated hint, unused."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1352
+msgid ""
+"Hints that an integer property is a bitmask with named bit flags. For "
+"example, to allow toggling bits 0, 1, 2 and 4, the hint could be something "
+"like [code]\"Bit0,Bit1,Bit2,,Bit4\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1355
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 2D "
+"render layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1358
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 2D "
+"physics layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1361
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 3D "
+"render layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1364
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 3D "
+"physics layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1367
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1370
+msgid ""
+"Hints that a string property is a path to a directory. Editing it will show "
+"a file dialog for picking the path."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1373
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1376
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1379
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1382
+msgid ""
+"Hints that a string property is text with line breaks. Editing it will show "
+"a text input field where line breaks can be typed."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1385
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1388
+msgid ""
+"Hints that a color property should be edited without changing its alpha "
+"component, i.e. only R, G and B channels are edited."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1391
+msgid "Hints that an image is compressed using lossy compression."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1394
+msgid "Hints that an image is compressed using lossless compression."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1397
+msgid "The property is serialized and saved in the scene file (default)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1400
+msgid "The property is shown in the editor inspector (default)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1403 doc/classes/@GlobalScope.xml:1406
+msgid "Deprecated usage flag, unused."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1409
+msgid "The property can be checked in the editor inspector."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1412
+msgid "The property is checked in the editor inspector."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1415
+msgid "The property is a translatable string."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1418
+msgid "Used to group properties together in the editor."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1421
+msgid "Used to categorize properties together in the editor."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1424
+msgid "The property does not save its state in [PackedScene]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1427
+msgid "Editing the property prompts the user for restarting the editor."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1430
+msgid ""
+"The property is a script variable which should be serialized and saved in "
+"the scene file."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1433
+msgid "Default usage (storage, editor and network)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1436
+msgid ""
+"Default usage for translatable strings (storage, editor, network and "
+"internationalized)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1439
+msgid ""
+"Default usage but without showing the property in the editor (storage, "
+"network)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1442
+msgid "Flag for a normal method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1445
+msgid "Flag for an editor method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1448 doc/classes/@GlobalScope.xml:1454
+#: doc/classes/@GlobalScope.xml:1460
+msgid "Deprecated method flag, unused."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1451
+msgid "Flag for a constant method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1457
+msgid "Flag for a virtual method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1463
+msgid "Default method flags."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1466
+msgid "Variable is [code]null[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1469
+msgid "Variable is of type [bool]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1472
+msgid "Variable is of type [int]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1475
+msgid "Variable is of type [float] (real)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1478
+msgid "Variable is of type [String]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1481
+msgid "Variable is of type [Vector2]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1484
+msgid "Variable is of type [Vector2i]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1487
+msgid "Variable is of type [Rect2]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1490
+msgid "Variable is of type [Rect2i]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1493
+msgid "Variable is of type [Vector3]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1496
+msgid "Variable is of type [Vector3i]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1499
+msgid "Variable is of type [Transform2D]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1502
+msgid "Variable is of type [Plane]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1505
+msgid "Variable is of type [Quat]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1508
+msgid "Variable is of type [AABB]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1511
+msgid "Variable is of type [Basis]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1514
+msgid "Variable is of type [Transform]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1517
+msgid "Variable is of type [Color]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1520
+msgid "Variable is of type [StringName]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1523
+msgid "Variable is of type [NodePath]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1526
+msgid "Variable is of type [RID]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1529
+msgid "Variable is of type [Object]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1532
+msgid "Variable is of type [Callable]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1535
+msgid "Variable is of type [Signal]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1538
+msgid "Variable is of type [Dictionary]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1541
+msgid "Variable is of type [Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1544
+msgid "Variable is of type [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1547
+msgid "Variable is of type [PackedInt32Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1550
+msgid "Variable is of type [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1553
+msgid "Variable is of type [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1556
+msgid "Variable is of type [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1559
+msgid "Variable is of type [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1562
+msgid "Variable is of type [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1565
+msgid "Variable is of type [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1568
+msgid "Variable is of type [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1571
+msgid "Represents the size of the [enum Variant.Type] enum."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1574
+msgid "Equality operator ([code]==[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1577
+msgid "Inequality operator ([code]!=[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1580
+msgid "Less than operator ([code]<[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1583
+msgid "Less than or equal operator ([code]<=[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1586
+msgid "Greater than operator ([code]>[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1589
+msgid "Greater than or equal operator ([code]>=[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1592
+msgid "Addition operator ([code]+[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1595
+msgid "Subtraction operator ([code]-[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1598
+msgid "Multiplication operator ([code]*[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1601
+msgid "Division operator ([code]/[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1604
+msgid "Unary negation operator ([code]-[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1607
+msgid "Unary plus operator ([code]+[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1610
+msgid "Remainder/modulo operator ([code]%[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1613
+msgid "String concatenation operator ([code]+[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1616
+msgid "Left shift operator ([code]<<[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1619
+msgid "Right shift operator ([code]>>[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1622
+msgid "Bitwise AND operator ([code]&[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1625
+msgid "Bitwise OR operator ([code]|[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1628
+msgid "Bitwise XOR operator ([code]^[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1631
+msgid "Bitwise NOT operator ([code]~[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1634
+msgid "Logical AND operator ([code]and[/code] or [code]&&[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1637
+msgid "Logical OR operator ([code]or[/code] or [code]||[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1640
+msgid "Logical XOR operator (not implemented in GDScript)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1643
+msgid "Logical NOT operator ([code]not[/code] or [code]![/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1646
+msgid "Logical IN operator ([code]in[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1649
+msgid "Represents the size of the [enum Variant.Operator] enum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/@VisualScript.xml:4
+msgid "Built-in visual script functions."
+msgstr ""
+
+#: modules/visual_script/doc_classes/@VisualScript.xml:7
+msgid ""
+"A list of built-in visual script functions, see [VisualScriptBuiltinFunc] "
+"and [VisualScript]."
+msgstr ""
+
+#: doc/classes/AABB.xml:4
+msgid "Axis-Aligned Bounding Box."
+msgstr ""
+
+#: doc/classes/AABB.xml:7
+msgid ""
+"AABB consists of a position, a size, and several utility functions. It is "
+"typically used for fast overlap tests."
+msgstr ""
+
+#: doc/classes/AABB.xml:10 doc/classes/Plane.xml:10 doc/classes/Rect2.xml:11
+#: doc/classes/Rect2i.xml:11 doc/classes/Transform.xml:10
+#: doc/classes/Vector2.xml:11 doc/classes/Vector2i.xml:11
+#: doc/classes/Vector3.xml:11 doc/classes/Vector3i.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/math/index.html"
+msgstr ""
+
+#: doc/classes/AABB.xml:21
+msgid "Optional constructor, accepts position and size."
+msgstr ""
+
+#: doc/classes/AABB.xml:30
+msgid ""
+"Returns [code]true[/code] if this [AABB] completely encloses another one."
+msgstr ""
+
+#: doc/classes/AABB.xml:39
+msgid "Returns this [AABB] expanded to include a given point."
+msgstr ""
+
+#: doc/classes/AABB.xml:46
+msgid "Returns the volume of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:55
+msgid "Gets the position of the 8 endpoints of the [AABB] in space."
+msgstr ""
+
+#: doc/classes/AABB.xml:62
+msgid "Returns the normalized longest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:69
+msgid ""
+"Returns the index of the longest axis of the [AABB] (according to "
+"[Vector3]'s [code]AXIS_*[/code] constants)."
+msgstr ""
+
+#: doc/classes/AABB.xml:76
+msgid "Returns the scalar length of the longest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:83
+msgid "Returns the normalized shortest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:90
+msgid ""
+"Returns the index of the shortest axis of the [AABB] (according to "
+"[Vector3]::AXIS* enum)."
+msgstr ""
+
+#: doc/classes/AABB.xml:97
+msgid "Returns the scalar length of the shortest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:106
+msgid ""
+"Returns the support point in a given direction. This is useful for collision "
+"detection algorithms."
+msgstr ""
+
+#: doc/classes/AABB.xml:115
+msgid ""
+"Returns a copy of the [AABB] grown a given amount of units towards all the "
+"sides."
+msgstr ""
+
+#: doc/classes/AABB.xml:122
+msgid "Returns [code]true[/code] if the [AABB] is flat or empty."
+msgstr ""
+
+#: doc/classes/AABB.xml:129
+msgid "Returns [code]true[/code] if the [AABB] is empty."
+msgstr ""
+
+#: doc/classes/AABB.xml:138
+msgid "Returns [code]true[/code] if the [AABB] contains a point."
+msgstr ""
+
+#: doc/classes/AABB.xml:147
+msgid ""
+"Returns the intersection between two [AABB]. An empty AABB (size 0,0,0) is "
+"returned on failure."
+msgstr ""
+
+#: doc/classes/AABB.xml:156
+msgid "Returns [code]true[/code] if the [AABB] overlaps with another."
+msgstr ""
+
+#: doc/classes/AABB.xml:165
+msgid "Returns [code]true[/code] if the [AABB] is on both sides of a plane."
+msgstr ""
+
+#: doc/classes/AABB.xml:176
+msgid ""
+"Returns [code]true[/code] if the [AABB] intersects the line segment between "
+"[code]from[/code] and [code]to[/code]."
+msgstr ""
+
+#: doc/classes/AABB.xml:185
+msgid ""
+"Returns [code]true[/code] if this [AABB] and [code]aabb[/code] are "
+"approximately equal, by calling [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/AABB.xml:194
+msgid ""
+"Returns a larger [AABB] that contains both this [AABB] and [code]with[/code]."
+msgstr ""
+
+#: doc/classes/AABB.xml:200
+msgid ""
+"Ending corner. This is calculated as [code]position + size[/code]. Changing "
+"this property changes [member size] accordingly."
+msgstr ""
+
+#: doc/classes/AABB.xml:203
+msgid "Beginning corner."
+msgstr ""
+
+#: doc/classes/AABB.xml:206 doc/classes/Rect2.xml:180
+msgid "Size from position to end."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:4
+msgid "Base dialog for user notification."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:7
+msgid ""
+"This dialog is useful for small notifications to the user about an event. It "
+"can only be accepted or closed, with the same result."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:22
+msgid ""
+"Adds a button with label [code]text[/code] and a custom [code]action[/code] "
+"to the dialog and returns the created button. [code]action[/code] will be "
+"passed to the [signal custom_action] signal when pressed.\n"
+"If [code]true[/code], [code]right[/code] will place the button to the right "
+"of any sibling buttons."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:32
+msgid ""
+"Adds a button with label [code]name[/code] and a cancel action to the dialog "
+"and returns the created button."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:39
+msgid "Returns the label used for built-in text."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:46
+msgid "Returns the OK [Button] instance."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:55
+msgid ""
+"Registers a [LineEdit] in the dialog. When the enter key is pressed, the "
+"dialog will be accepted."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:61
+msgid "Sets autowrapping for the text in the dialog."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:64
+msgid ""
+"If [code]true[/code], the dialog is hidden when the OK button is pressed. "
+"You can set it to [code]false[/code] if you want to do e.g. input validation "
+"when receiving the [signal confirmed] signal, and handle hiding the dialog "
+"in your own logic.\n"
+"[b]Note:[/b] Some nodes derived from this class can have a different default "
+"value, and potentially their own built-in logic overriding this setting. For "
+"example [FileDialog] defaults to [code]false[/code], and has its own input "
+"validation code that is called when you press OK, which eventually hides the "
+"dialog if the input is valid. As such, this property can't be used in "
+"[FileDialog] to disable hiding the dialog when pressing OK."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:68
+msgid "The text displayed by the dialog."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:82
+msgid "Emitted when the dialog is accepted, i.e. the OK button is pressed."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:89
+msgid "Emitted when a custom button is pressed. See [method add_button]."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:4
+msgid "Sprite node that can use multiple textures for animation."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:7 doc/classes/AnimatedSprite3D.xml:7
+msgid ""
+"Animations are created using a [SpriteFrames] resource, which can be "
+"configured in the editor via the SpriteFrames panel."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:16 doc/classes/AnimatedSprite3D.xml:16
+msgid "Returns [code]true[/code] if an animation is currently being played."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:27
+msgid ""
+"Plays the animation named [code]anim[/code]. If no [code]anim[/code] is "
+"provided, the current animation is played. If [code]backwards[/code] is "
+"[code]true[/code], the animation will be played in reverse."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:34 doc/classes/AnimatedSprite3D.xml:32
+msgid "Stops the current animation (does not reset the frame counter)."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:40 doc/classes/AnimatedSprite3D.xml:38
+msgid ""
+"The current animation from the [code]frames[/code] resource. If this value "
+"changes, the [code]frame[/code] counter is reset."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:43 doc/classes/SpriteBase3D.xml:55
+msgid "If [code]true[/code], texture will be centered."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:46 doc/classes/Sprite2D.xml:41
+#: doc/classes/SpriteBase3D.xml:61 doc/classes/TextureRect.xml:18
+msgid "If [code]true[/code], texture is flipped horizontally."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:49 doc/classes/Sprite2D.xml:44
+#: doc/classes/SpriteBase3D.xml:64 doc/classes/TextureRect.xml:21
+msgid "If [code]true[/code], texture is flipped vertically."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:52 doc/classes/AnimatedSprite3D.xml:41
+msgid "The displayed animation frame's index."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:55 doc/classes/AnimatedSprite3D.xml:44
+msgid "The [SpriteFrames] resource containing the animation(s)."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:58 doc/classes/Sprite2D.xml:59
+#: doc/classes/SpriteBase3D.xml:70
+msgid "The texture's drawing offset."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:61 doc/classes/AnimatedSprite3D.xml:47
+msgid "If [code]true[/code], the [member animation] is currently playing."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:64
+msgid "Strength of the specular light effect of this [AnimatedSprite2D]."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:67 doc/classes/Sprite2D.xml:74
+msgid "The color of the specular light effect."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:70
+msgid "The animation speed is multiplied by this value."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:76
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:81 doc/classes/AnimatedSprite3D.xml:53
+msgid "Emitted when [member frame] changed."
+msgstr ""
+
+#: doc/classes/AnimatedSprite3D.xml:4
+msgid ""
+"2D sprite node in 3D world, that can use multiple 2D textures for animation."
+msgstr ""
+
+#: doc/classes/AnimatedSprite3D.xml:25
+msgid ""
+"Plays the animation named [code]anim[/code]. If no [code]anim[/code] is "
+"provided, the current animation is played."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:4
+msgid "Proxy texture for simple frame-based animations."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:7
+msgid ""
+"[AnimatedTexture] is a resource format for frame-based animations, where "
+"multiple textures can be chained automatically with a predefined delay for "
+"each frame. Unlike [AnimationPlayer] or [AnimatedSprite2D], it isn't a "
+"[Node], but has the advantage of being usable anywhere a [Texture2D] "
+"resource can be used, e.g. in a [TileSet].\n"
+"The playback of the animation is controlled by the [member fps] property as "
+"well as each frame's optional delay (see [method set_frame_delay]). The "
+"animation loops, i.e. it will restart at frame 0 automatically after playing "
+"the last frame.\n"
+"[AnimatedTexture] currently requires all frame textures to have the same "
+"size, otherwise the bigger ones will be cropped to match the smallest one. "
+"Also, it doesn't support [AtlasTexture]. Each frame needs to be separate "
+"image."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:20
+msgid "Returns the given frame's delay value."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:29
+msgid "Returns the given frame's [Texture2D]."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:40
+msgid ""
+"Sets an additional delay (in seconds) between this frame and the next one, "
+"that will be added to the time interval defined by [member fps]. By default, "
+"frames have no delay defined. If a delay value is defined, the final time "
+"interval between this frame and the next will be [code]1.0 / fps + delay[/"
+"code].\n"
+"For example, for an animation with 3 frames, 2 FPS and a frame delay on the "
+"second frame of 1.2, the resulting playback will be:\n"
+"[codeblock]\n"
+"Frame 0: 0.5 s (1 / fps)\n"
+"Frame 1: 1.7 s (1 / fps + 1.2)\n"
+"Frame 2: 0.5 s (1 / fps)\n"
+"Total duration: 2.7 s\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:58
+msgid ""
+"Assigns a [Texture2D] to the given frame. Frame IDs start at 0, so the first "
+"frame has ID 0, and the last frame of the animation has ID [member frames] - "
+"1.\n"
+"You can define any number of textures up to [constant MAX_FRAMES], but keep "
+"in mind that only frames from 0 to [member frames] - 1 will be part of the "
+"animation."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:65
+msgid ""
+"Animation speed in frames per second. This value defines the default time "
+"interval between two frames of the animation, and thus the overall duration "
+"of the animation loop based on the [member frames] property. A value of 0 "
+"means no predefined number of frames per second, the animation will play "
+"according to each frame's frame delay (see [method set_frame_delay]).\n"
+"For example, an animation with 8 frames, no frame delay and a [code]fps[/"
+"code] value of 2 will run for 4 seconds, with each frame lasting 0.5 seconds."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:69
+msgid ""
+"Number of frames to use in the animation. While you can create the frames "
+"independently with [method set_frame_texture], you need to set this value "
+"for the animation to take new frames into account. The maximum number of "
+"frames is [constant MAX_FRAMES]."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:74
+msgid ""
+"The maximum number of frames supported by [AnimatedTexture]. If you need "
+"more frames in your animation, use [AnimationPlayer] or [AnimatedSprite2D]."
+msgstr ""
+
+#: doc/classes/Animation.xml:4
+msgid "Contains data used to animate everything in the engine."
+msgstr ""
+
+#: doc/classes/Animation.xml:7
+msgid ""
+"An Animation resource contains data used to animate everything in the "
+"engine. Animations are divided into tracks, and each track must be linked to "
+"a node. The state of that node can be changed through time, by adding timed "
+"keys (events) to the track.\n"
+"[codeblock]\n"
+"# This creates an animation that makes the node \"Enemy\" move to the right "
+"by\n"
+"# 100 pixels in 1 second.\n"
+"var animation = Animation.new()\n"
+"var track_index = animation.add_track(Animation.TYPE_VALUE)\n"
+"animation.track_set_path(track_index, \"Enemy:position.x\")\n"
+"animation.track_insert_key(track_index, 0.0, 0)\n"
+"animation.track_insert_key(track_index, 0.5, 100)\n"
+"[/codeblock]\n"
+"Animations are just data containers, and must be added to nodes such as an "
+"[AnimationPlayer] to be played back. Animation tracks have different types, "
+"each with its own set of dedicated methods. Check [enum TrackType] to see "
+"available types."
+msgstr ""
+
+#: doc/classes/Animation.xml:20 doc/classes/AnimationPlayer.xml:13
+msgid "https://docs.godotengine.org/en/latest/tutorials/animation/index.html"
+msgstr ""
+
+#: doc/classes/Animation.xml:31
+msgid "Adds a track to the Animation."
+msgstr ""
+
+#: doc/classes/Animation.xml:42
+msgid ""
+"Returns the animation name at the key identified by [code]key_idx[/code]. "
+"The [code]track_idx[/code] must be the index of an Animation Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:55
+msgid ""
+"Inserts a key with value [code]animation[/code] at the given [code]time[/"
+"code] (in seconds). The [code]track_idx[/code] must be the index of an "
+"Animation Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:68
+msgid ""
+"Sets the key identified by [code]key_idx[/code] to value [code]animation[/"
+"code]. The [code]track_idx[/code] must be the index of an Animation Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:79
+msgid ""
+"Returns the end offset of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of an Audio Track.\n"
+"End offset is the number of seconds cut off at the ending of the audio "
+"stream."
+msgstr ""
+
+#: doc/classes/Animation.xml:91
+msgid ""
+"Returns the start offset of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of an Audio Track.\n"
+"Start offset is the number of seconds cut off at the beginning of the audio "
+"stream."
+msgstr ""
+
+#: doc/classes/Animation.xml:103
+msgid ""
+"Returns the audio stream of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of an Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:120
+msgid ""
+"Inserts an Audio Track key at the given [code]time[/code] in seconds. The "
+"[code]track_idx[/code] must be the index of an Audio Track.\n"
+"[code]stream[/code] is the [AudioStream] resource to play. "
+"[code]start_offset[/code] is the number of seconds cut off at the beginning "
+"of the audio stream, while [code]end_offset[/code] is at the ending."
+msgstr ""
+
+#: doc/classes/Animation.xml:134
+msgid ""
+"Sets the end offset of the key identified by [code]key_idx[/code] to value "
+"[code]offset[/code]. The [code]track_idx[/code] must be the index of an "
+"Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:147
+msgid ""
+"Sets the start offset of the key identified by [code]key_idx[/code] to value "
+"[code]offset[/code]. The [code]track_idx[/code] must be the index of an "
+"Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:160
+msgid ""
+"Sets the stream of the key identified by [code]key_idx[/code] to value "
+"[code]offset[/code]. The [code]track_idx[/code] must be the index of an "
+"Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:171
+msgid ""
+"Returns the in handle of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:182
+msgid ""
+"Returns the out handle of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:193
+msgid ""
+"Returns the value of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:210
+msgid ""
+"Inserts a Bezier Track key at the given [code]time[/code] in seconds. The "
+"[code]track_idx[/code] must be the index of a Bezier Track.\n"
+"[code]in_handle[/code] is the left-side weight of the added Bezier curve "
+"point, [code]out_handle[/code] is the right-side one, while [code]value[/"
+"code] is the actual value at this point."
+msgstr ""
+
+#: doc/classes/Animation.xml:222
+msgid ""
+"Returns the interpolated value at the given [code]time[/code] (in seconds). "
+"The [code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:235
+msgid ""
+"Sets the in handle of the key identified by [code]key_idx[/code] to value "
+"[code]in_handle[/code]. The [code]track_idx[/code] must be the index of a "
+"Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:248
+msgid ""
+"Sets the out handle of the key identified by [code]key_idx[/code] to value "
+"[code]out_handle[/code]. The [code]track_idx[/code] must be the index of a "
+"Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:261
+msgid ""
+"Sets the value of the key identified by [code]key_idx[/code] to the given "
+"value. The [code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:268
+msgid "Clear the animation (clear all tracks and reset all)."
+msgstr ""
+
+#: doc/classes/Animation.xml:279
+msgid ""
+"Adds a new track that is a copy of the given track from [code]to_animation[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:288
+msgid ""
+"Returns the index of the specified track. If the track is not found, return "
+"-1."
+msgstr ""
+
+#: doc/classes/Animation.xml:295
+msgid "Returns the amount of tracks in the animation."
+msgstr ""
+
+#: doc/classes/Animation.xml:308
+msgid ""
+"Returns all the key indices of a method track, given a position and delta "
+"time."
+msgstr ""
+
+#: doc/classes/Animation.xml:319
+msgid "Returns the method name of a method track."
+msgstr ""
+
+#: doc/classes/Animation.xml:330
+msgid ""
+"Returns the arguments values to be called on a method track for a given key "
+"in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:339
+msgid "Removes a track by specifying the track index."
+msgstr ""
+
+#: doc/classes/Animation.xml:352
+msgid ""
+"Finds the key index by time in a given track. Optionally, only find it if "
+"the exact time is given."
+msgstr ""
+
+#: doc/classes/Animation.xml:361
+msgid ""
+"Returns [code]true[/code] if the track at [code]idx[/code] wraps the "
+"interpolation loop. New tracks wrap the interpolation loop by default."
+msgstr ""
+
+#: doc/classes/Animation.xml:370
+msgid "Returns the interpolation type of a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:379
+msgid "Returns the amount of keys in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:390
+msgid "Returns the time at which the key is located."
+msgstr ""
+
+#: doc/classes/Animation.xml:401
+msgid ""
+"Returns the transition curve (easing) for a specific key (see the built-in "
+"math function [method @GDScript.ease])."
+msgstr ""
+
+#: doc/classes/Animation.xml:412
+msgid "Returns the value of a given key in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:421
+msgid ""
+"Gets the path of a track. For more information on the path format, see "
+"[method track_set_path]."
+msgstr ""
+
+#: doc/classes/Animation.xml:430
+msgid "Gets the type of a track."
+msgstr ""
+
+#: doc/classes/Animation.xml:445
+msgid "Insert a generic key in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:454
+msgid ""
+"Returns [code]true[/code] if the track at index [code]idx[/code] is enabled."
+msgstr ""
+
+#: doc/classes/Animation.xml:463
+msgid ""
+"Returns [code]true[/code] if the given track is imported. Else, return "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:472
+msgid "Moves a track down."
+msgstr ""
+
+#: doc/classes/Animation.xml:483
+msgid ""
+"Changes the index position of track [code]idx[/code] to the one defined in "
+"[code]to_idx[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:492
+msgid "Moves a track up."
+msgstr ""
+
+#: doc/classes/Animation.xml:503
+msgid "Removes a key by index in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:514
+msgid "Removes a key by position (seconds) in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:525
+msgid "Enables/disables the given track. Tracks are enabled by default."
+msgstr ""
+
+#: doc/classes/Animation.xml:536
+msgid "Sets the given track as imported or not."
+msgstr ""
+
+#: doc/classes/Animation.xml:547
+msgid ""
+"If [code]true[/code], the track at [code]idx[/code] wraps the interpolation "
+"loop."
+msgstr ""
+
+#: doc/classes/Animation.xml:558
+msgid "Sets the interpolation type of a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:571
+msgid "Sets the time of an existing key."
+msgstr ""
+
+#: doc/classes/Animation.xml:584
+msgid ""
+"Sets the transition curve (easing) for a specific key (see the built-in math "
+"function [method @GDScript.ease])."
+msgstr ""
+
+#: doc/classes/Animation.xml:597
+msgid "Sets the value of an existing key."
+msgstr ""
+
+#: doc/classes/Animation.xml:608
+msgid ""
+"Sets the path of a track. 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. Tracks that control properties or bones must append "
+"their name after the path, separated by [code]\":\"[/code].\n"
+"For example, [code]\"character/skeleton:ankle\"[/code] or [code]\"character/"
+"mesh:transform/local\"[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:620
+msgid ""
+"Swaps the track [code]idx[/code]'s index position with the track "
+"[code]with_idx[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:637
+msgid "Insert a transform key for a transform track."
+msgstr ""
+
+#: doc/classes/Animation.xml:648
+msgid ""
+"Returns the interpolated value of a transform track at a given time (in "
+"seconds). An array consisting of 3 elements: position ([Vector3]), rotation "
+"([Quat]) and scale ([Vector3])."
+msgstr ""
+
+#: doc/classes/Animation.xml:661
+msgid ""
+"Returns all the key indices of a value track, given a position and delta "
+"time."
+msgstr ""
+
+#: doc/classes/Animation.xml:670
+msgid "Returns the update mode of a value track."
+msgstr ""
+
+#: doc/classes/Animation.xml:681
+msgid "Sets the update mode (see [enum UpdateMode]) of a value track."
+msgstr ""
+
+#: doc/classes/Animation.xml:687
+msgid ""
+"The total length of the animation (in seconds).\n"
+"[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."
+msgstr ""
+
+#: doc/classes/Animation.xml:691
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Animation.xml:694
+msgid "The animation step value."
+msgstr ""
+
+#: doc/classes/Animation.xml:700
+msgid ""
+"Emitted when there's a change in the list of tracks, e.g. tracks are added, "
+"moved or have changed paths."
+msgstr ""
+
+#: doc/classes/Animation.xml:706
+msgid ""
+"Value tracks set values in node properties, but only those which can be "
+"Interpolated."
+msgstr ""
+
+#: doc/classes/Animation.xml:709
+msgid ""
+"Transform tracks are used to change node local transforms or skeleton pose "
+"bones. Transitions are interpolated."
+msgstr ""
+
+#: doc/classes/Animation.xml:712
+msgid "Method tracks call functions with given arguments per key."
+msgstr ""
+
+#: doc/classes/Animation.xml:715
+msgid ""
+"Bezier tracks are used to interpolate a value using custom curves. They can "
+"also be used to animate sub-properties of vectors and colors (e.g. alpha "
+"value of a [Color])."
+msgstr ""
+
+#: doc/classes/Animation.xml:718
+msgid ""
+"Audio tracks are used to play an audio stream with either type of "
+"[AudioStreamPlayer]. The stream can be trimmed and previewed in the "
+"animation."
+msgstr ""
+
+#: doc/classes/Animation.xml:721
+msgid "Animation tracks play animations in other [AnimationPlayer] nodes."
+msgstr ""
+
+#: doc/classes/Animation.xml:724
+msgid "No interpolation (nearest value)."
+msgstr ""
+
+#: doc/classes/Animation.xml:727
+msgid "Linear interpolation."
+msgstr ""
+
+#: doc/classes/Animation.xml:730
+msgid "Cubic interpolation."
+msgstr ""
+
+#: doc/classes/Animation.xml:733
+msgid "Update between keyframes."
+msgstr ""
+
+#: doc/classes/Animation.xml:736
+msgid "Update at the keyframes and hold the value."
+msgstr ""
+
+#: doc/classes/Animation.xml:739
+msgid "Update at the keyframes."
+msgstr ""
+
+#: doc/classes/Animation.xml:742
+msgid ""
+"Same as linear interpolation, but also interpolates from the current value "
+"(i.e. dynamically at runtime) if the first key isn't at 0 seconds."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:4
+msgid "Base resource for [AnimationTree] nodes."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:7
+msgid ""
+"Base resource for [AnimationTree] nodes. In general, it's not used directly, "
+"but you can create custom ones with custom blending formulas.\n"
+"Inherit this when creating nodes mainly for use in [AnimationNodeBlendTree], "
+"otherwise [AnimationRootNode] should be used instead."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:11 doc/classes/AnimationNodeAdd2.xml:10
+#: doc/classes/AnimationNodeAdd3.xml:14
+#: doc/classes/AnimationNodeAnimation.xml:10
+#: doc/classes/AnimationNodeBlend2.xml:10
+#: doc/classes/AnimationNodeBlend3.xml:14
+#: doc/classes/AnimationNodeBlendSpace1D.xml:13
+#: doc/classes/AnimationNodeBlendSpace2D.xml:12
+#: doc/classes/AnimationNodeBlendTree.xml:10
+#: doc/classes/AnimationNodeOneShot.xml:10
+#: doc/classes/AnimationNodeOutput.xml:9
+#: doc/classes/AnimationNodeStateMachine.xml:15
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:15
+#: doc/classes/AnimationNodeStateMachineTransition.xml:8
+#: doc/classes/AnimationNodeTimeScale.xml:10
+#: doc/classes/AnimationNodeTimeSeek.xml:10
+#: doc/classes/AnimationNodeTransition.xml:10 doc/classes/AnimationTree.xml:9
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree."
+"html"
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:20
+msgid ""
+"Adds an input to the node. This is only useful for nodes created for use in "
+"an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:37
+msgid ""
+"Blend an animation by [code]blend[/code] amount (name must be valid in the "
+"linked [AnimationPlayer]). A [code]time[/code] and [code]delta[/code] may be "
+"passed, as well as whether [code]seek[/code] happened."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:56
+msgid ""
+"Blend an input. This is only useful for nodes created for an "
+"[AnimationNodeBlendTree]. The [code]time[/code] parameter is a relative "
+"delta, unless [code]seek[/code] is [code]true[/code], in which case it is "
+"absolute. A filter mode may be optionally passed (see [enum FilterAction] "
+"for options)."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:77
+msgid ""
+"Blend another animation node (in case this node contains children animation "
+"nodes). This function is only useful if you inherit from [AnimationRootNode] "
+"instead, else editors will not display your node for addition."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:84
+msgid "Gets the text caption for this node (used by some editors)."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:93
+msgid ""
+"Gets a child node by index (used by editors inheriting from "
+"[AnimationRootNode])."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:100
+msgid ""
+"Gets all children nodes in order as a [code]name: node[/code] dictionary. "
+"Only useful when inheriting [AnimationRootNode]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:107
+msgid ""
+"Amount of inputs in this node, only useful for nodes that go into "
+"[AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:116
+msgid "Gets the name of an input by index."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:125
+msgid ""
+"Gets the value of a parameter. Parameters are custom local memory used for "
+"your nodes, given a resource can be reused in multiple trees."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:134
+msgid ""
+"Gets the default value of a parameter. Parameters are custom local memory "
+"used for your nodes, given a resource can be reused in multiple trees."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:141
+msgid ""
+"Gets the property information for parameter. Parameters are custom local "
+"memory used for your nodes, given a resource can be reused in multiple "
+"trees. Format is similar to [method Object.get_property_list]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:148
+msgid ""
+"Returns [code]true[/code] whether you want the blend tree editor to display "
+"filter editing on this node."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:157
+msgid "Returns [code]true[/code] whether a given path is filtered."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:168
+msgid ""
+"User-defined callback called when a custom node is processed. The "
+"[code]time[/code] parameter is a relative delta, unless [code]seek[/code] is "
+"[code]true[/code], in which case it is absolute.\n"
+"Here, call the [method blend_input], [method blend_node] or [method "
+"blend_animation] functions. You can also use [method get_parameter] and "
+"[method set_parameter] to modify local memory.\n"
+"This function should return the time left for the current animation to "
+"finish (if unsure, pass the value from the main blend being called)."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:179
+msgid "Removes an input, call this only when inactive."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:190
+msgid "Adds or removes a path for the filter."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:201
+msgid ""
+"Sets a custom parameter. These are used as local storage, because resources "
+"can be reused across the tree or scenes."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:207
+msgid "If [code]true[/code], filtering is enabled."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:213
+msgid "Called when the node was removed from the graph."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:218
+msgid ""
+"Emitted by nodes that inherit from this class and that have an internal tree "
+"when one of their nodes changes. The nodes that emit this signal are "
+"[AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], "
+"[AnimationNodeStateMachine], and [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:224
+msgid "Do not use filtering."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:227
+msgid "Paths matching the filter will be allowed to pass."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:230
+msgid "Paths matching the filter will be discarded."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:233
+msgid "Paths matching the filter will be blended (by the blend value)."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd2.xml:4
+msgid "Blends two animations additively inside of an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd2.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"additively based on an amount value in the [code][0.0, 1.0][/code] range."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd2.xml:16 doc/classes/AnimationNodeAdd3.xml:20
+#: doc/classes/AnimationNodeBlend2.xml:16
+#: doc/classes/AnimationNodeBlend3.xml:20
+msgid ""
+"If [code]true[/code], sets the [code]optimization[/code] to [code]false[/"
+"code] when calling [method AnimationNode.blend_input], forcing the blended "
+"animations to update every frame."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd3.xml:4
+msgid ""
+"Blends two of three animations additively inside of an "
+"[AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd3.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"together additively out of three based on a value in the [code][-1.0, 1.0][/"
+"code] range.\n"
+"This node has three inputs:\n"
+"- The base animation to add to\n"
+"- A -add animation to blend with when the blend amount is in the [code]"
+"[-1.0, 0.0][/code] range.\n"
+"- A +add animation to blend with when the blend amount is in the [code][0.0, "
+"1.0][/code] range"
+msgstr ""
+
+#: doc/classes/AnimationNodeAnimation.xml:4
+msgid "Input animation to use in an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeAnimation.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Only features one output "
+"set using the [member animation] property. Use it as an input for "
+"[AnimationNode] that blend animations together."
+msgstr ""
+
+#: doc/classes/AnimationNodeAnimation.xml:16
+msgid ""
+"Animation to use as an output. It is one of the animations provided by "
+"[member AnimationTree.anim_player]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend2.xml:4
+msgid "Blends two animations linearly inside of an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend2.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"linearly based on an amount value in the [code][0.0, 1.0][/code] range."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend3.xml:4
+msgid ""
+"Blends two of three animations linearly inside of an "
+"[AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend3.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"together linearly out of three based on a value in the [code][-1.0, 1.0][/"
+"code] range.\n"
+"This node has three inputs:\n"
+"- The base animation\n"
+"- A -blend animation to blend with when the blend amount is in the [code]"
+"[-1.0, 0.0][/code] range.\n"
+"- A +blend animation to blend with when the blend amount is in the [code]"
+"[0.0, 1.0][/code] range"
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:4
+msgid ""
+"Blends linearly between two of any number of [AnimationNode] of any type "
+"placed on a virtual axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree].\n"
+"This is a virtual axis on which you can add any type of [AnimationNode] "
+"using [method add_blend_point].\n"
+"Outputs the linear blend of the two [AnimationNode]s closest to the node's "
+"current value.\n"
+"You can set the extents of the axis using the [member min_space] and [member "
+"max_space]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:26
+msgid ""
+"Adds a new point that represents a [code]node[/code] on the virtual axis at "
+"a given position set by [code]pos[/code]. You can insert it at a specific "
+"index using the [code]at_index[/code] argument. If you use the default value "
+"for [code]at_index[/code], the point is inserted at the end of the blend "
+"points array."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:33
+msgid "Returns the number of points on the blend axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:42
+msgid ""
+"Returns the [AnimationNode] referenced by the point at index [code]point[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:51
+#: doc/classes/AnimationNodeBlendSpace2D.xml:65
+msgid "Returns the position of the point at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:60
+msgid "Removes the point at index [code]point[/code] from the blend axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:71
+#: doc/classes/AnimationNodeBlendSpace2D.xml:112
+msgid ""
+"Changes the [AnimationNode] referenced by the point at index [code]point[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:82
+#: doc/classes/AnimationNodeBlendSpace2D.xml:123
+msgid ""
+"Updates the position of the point at index [code]point[/code] on the blend "
+"axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:88
+msgid ""
+"The blend space's axis's upper limit for the points' position. See [method "
+"add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:91
+msgid ""
+"The blend space's axis's lower limit for the points' position. See [method "
+"add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:94
+msgid "Position increment to snap to when moving a point on the axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:97
+msgid "Label of the virtual axis of the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:4
+msgid ""
+"Blends linearly between three [AnimationNode] of any type placed in a 2D "
+"space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree].\n"
+"This node allows you to blend linearly between three animations using a "
+"[Vector2] weight.\n"
+"You can add vertices to the blend space with [method add_blend_point] and "
+"automatically triangulate it by setting [member auto_triangles] to "
+"[code]true[/code]. Otherwise, use [method add_triangle] and [method "
+"remove_triangle] to create up the blend space by hand."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:25
+msgid ""
+"Adds a new point that represents a [code]node[/code] at the position set by "
+"[code]pos[/code]. You can insert it at a specific index using the "
+"[code]at_index[/code] argument. If you use the default value for "
+"[code]at_index[/code], the point is inserted at the end of the blend points "
+"array."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:40
+msgid ""
+"Creates a new triangle using three points [code]x[/code], [code]y[/code], "
+"and [code]z[/code]. Triangles can overlap. You can insert the triangle at a "
+"specific index using the [code]at_index[/code] argument. If you use the "
+"default value for [code]at_index[/code], the point is inserted at the end of "
+"the blend points array."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:47
+msgid "Returns the number of points in the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:56
+msgid ""
+"Returns the [AnimationRootNode] referenced by the point at index "
+"[code]point[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:72
+msgid "Returns the number of triangles in the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:83
+msgid ""
+"Returns the position of the point at index [code]point[/code] in the "
+"triangle of index [code]triangle[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:92
+msgid "Removes the point at index [code]point[/code] from the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:101
+msgid ""
+"Removes the triangle at index [code]triangle[/code] from the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:129
+msgid ""
+"If [code]true[/code], the blend space is triangulated automatically. The "
+"mesh updates every time you add or remove points with [method "
+"add_blend_point] and [method remove_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:132
+msgid ""
+"Controls the interpolation between animations. See [enum BlendMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:135
+msgid ""
+"The blend space's X and Y axes' upper limit for the points' position. See "
+"[method add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:138
+msgid ""
+"The blend space's X and Y axes' lower limit for the points' position. See "
+"[method add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:141
+msgid "Position increment to snap to when moving a point."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:144
+msgid "Name of the blend space's X axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:147
+msgid "Name of the blend space's Y axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:153
+msgid ""
+"Emitted every time the blend space's triangles are created, removed, or when "
+"one of their vertices changes position."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:159
+msgid "The interpolation between animations is linear."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:162
+msgid ""
+"The blend space plays the animation of the node the blending position is "
+"closest to. Useful for frame-by-frame 2D animations."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:165
+msgid ""
+"Similar to [constant BLEND_MODE_DISCRETE], but starts the new animation at "
+"the last animation's playback position."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:4
+msgid "[AnimationTree] node resource that contains many blend type nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:7
+msgid ""
+"This node may contain a sub-tree of any other blend type nodes, such as mix, "
+"blend2, blend3, one shot, etc. This is one of the most commonly used roots."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:23
+msgid ""
+"Adds an [AnimationNode] at the given [code]position[/code]. The [code]name[/"
+"code] is used to identify the created sub-node later."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:36
+msgid ""
+"Connects the output of an [AnimationNode] as input for another "
+"[AnimationNode], at the input port specified by [code]input_index[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:47
+msgid "Disconnects the node connected to the specified input."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:56
+msgid "Returns the sub-node with the specified [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:65
+msgid ""
+"Returns the position of the sub-node with the specified [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:74
+msgid ""
+"Returns [code]true[/code] if a sub-node with specified [code]name[/code] "
+"exists."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:83
+msgid "Removes a sub-node."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:94
+msgid "Changes the name of a sub-node."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:105
+msgid "Modifies the position of a sub-node."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:111
+msgid "The global offset of all sub-nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:116
+msgid "The connection was successful."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:119
+msgid "The input node is [code]null[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:122
+msgid "The specified input port is out of range."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:125
+msgid "The output node is [code]null[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:128
+msgid "Input and output nodes are the same."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:131
+msgid "The specified connection already exists."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:4
+msgid "Plays an animation once in [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. This node will execute a "
+"sub-animation and return once it finishes. Blend times for fading in and out "
+"can be customized, as well as filters."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:30
+msgid ""
+"If [code]true[/code], the sub-animation will restart automatically after "
+"finishing."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:33
+msgid "The delay after which the automatic restart is triggered, in seconds."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:36
+msgid ""
+"If [member autorestart] is [code]true[/code], a random additional delay (in "
+"seconds) between 0 and this value will be added to [member "
+"autorestart_delay]."
+msgstr ""
+
+#: doc/classes/AnimationNodeOutput.xml:4
+msgid "Generic output node to be added to [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:4
+msgid "State machine for control of animations."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:7
+msgid ""
+"Contains multiple nodes representing animation states, connected in a graph. "
+"Node transitions can be configured to happen automatically or via code, "
+"using a shortest-path algorithm. Retrieve the "
+"[AnimationNodeStateMachinePlayback] object from the [AnimationTree] node to "
+"control it programmatically.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var state_machine = $AnimationTree.get(\"parameters/playback\")\n"
+"state_machine.travel(\"some_state\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:28
+msgid ""
+"Adds a new node to the graph. The [code]position[/code] is used for display "
+"in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:41
+msgid "Adds a transition between the given nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:48
+#: doc/classes/AnimationNodeStateMachine.xml:89
+msgid "Returns the graph's end node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:55
+msgid "Returns the draw offset of the graph. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:64
+msgid "Returns the animation node with the given name."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:73
+msgid "Returns the given animation node's name."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:82
+msgid "Returns the given node's coordinates. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:98
+msgid "Returns the given transition."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:105
+msgid "Returns the number of connections in the graph."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:114
+msgid "Returns the given transition's start node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:123
+msgid "Returns the given transition's end node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:132
+msgid "Returns [code]true[/code] if the graph contains the given node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:143
+msgid ""
+"Returns [code]true[/code] if there is a transition between the given nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:152
+msgid "Deletes the given node from the graph."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:163
+msgid "Deletes the transition between the two specified nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:172
+msgid "Deletes the given transition by index."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:183
+msgid "Renames the given node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:202
+msgid "Sets the given node as the graph end point."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:211
+msgid "Sets the draw offset of the graph. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:222
+msgid "Sets the node's coordinates. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:231
+msgid "Sets the given node as the graph start point."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:4
+msgid "Playback control for [AnimationNodeStateMachine]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:7
+msgid ""
+"Allows control of [AnimationTree] state machines created with "
+"[AnimationNodeStateMachine]. Retrieve with [code]$AnimationTree."
+"get(\"parameters/playback\")[/code].\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var state_machine = $AnimationTree.get(\"parameters/playback\")\n"
+"state_machine.travel(\"some_state\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:22
+msgid "Returns the currently playing animation state."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:29
+msgid ""
+"Returns the current travel path as computed internally by the A* algorithm."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:36
+msgid "Returns [code]true[/code] if an animation is playing."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:45
+msgid "Starts playing the given animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:52
+msgid "Stops the currently playing animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:61
+msgid ""
+"Transitions from the current state to another one, following the shortest "
+"path."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:14
+msgid ""
+"Turn on auto advance when this condition is set. The provided name will "
+"become a boolean parameter on the [AnimationTree] that can be controlled "
+"from code (see [url=https://docs.godotengine.org/en/latest/tutorials/"
+"animation/animation_tree.html#controlling-from-code][/url]). For example, if "
+"[member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and "
+"[member advance_condition] is set to [code]\"idle\"[/code]:\n"
+"[codeblock]\n"
+"$animation_tree[\"parameters/conditions/idle\"] = is_on_floor and "
+"(linear_velocity.x == 0)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:20
+msgid ""
+"Turn on the transition automatically when this state is reached. This works "
+"best with [constant SWITCH_MODE_AT_END]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:23
+msgid ""
+"Don't use this transition during [method AnimationNodeStateMachinePlayback."
+"travel] or [member auto_advance]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:26
+msgid ""
+"Lower priority transitions are preferred when travelling through the tree "
+"via [method AnimationNodeStateMachinePlayback.travel] or [member "
+"auto_advance]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:29
+msgid "The transition type."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:32
+msgid "The time to cross-fade between this state and the next."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:38
+msgid "Emitted when [member advance_condition] is changed."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:44
+msgid ""
+"Switch to the next state immediately. The current state will end and blend "
+"into the beginning of the new one."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:47
+msgid ""
+"Switch to the next state immediately, but will seek the new state to the "
+"playback position of the old state."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:50
+msgid ""
+"Wait for the current state playback to end, then switch to the beginning of "
+"the next state animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeScale.xml:4
+msgid "A time-scaling animation node to be used with [AnimationTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeScale.xml:7
+msgid ""
+"Allows scaling the speed of the animation (or reversing it) in any children "
+"nodes. Setting it to 0 will pause the animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeSeek.xml:4
+msgid "A time-seeking animation node to be used with [AnimationTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeSeek.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:4
+msgid "A generic animation transition node for [AnimationTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:7
+msgid ""
+"Simple state machine for cases which don't require a more advanced "
+"[AnimationNodeStateMachine]. Animations can be connected to the inputs and "
+"transition times can be specified."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:52
+msgid "The number of available input ports for this node."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:55
+msgid ""
+"Cross-fading time (in seconds) between each animation connected to the "
+"inputs."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:4
+msgid "Container and player of [Animation] resources."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:7
+msgid ""
+"An animation player is used for general-purpose playback of [Animation] "
+"resources. It contains a dictionary of animations (referenced by name) and "
+"custom blend times between their transitions. Additionally, animations can "
+"be played and blended in different channels.\n"
+"[AnimationPlayer] is more suited than [Tween] for animations where you know "
+"the final values in advance. For example, fading a screen in and out is more "
+"easily done with an [AnimationPlayer] node thanks to the animation tools "
+"provided by the editor. That particular example can also be implemented with "
+"a [Tween] node, but it requires doing everything by code.\n"
+"Updating the target properties of animations occurs at process time."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"animations.html"
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:24
+msgid ""
+"Adds [code]animation[/code] to the player accessible with the key "
+"[code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:33
+msgid ""
+"Shifts position in the animation timeline and immediately updates the "
+"animation. [code]delta[/code] is the time in seconds to shift. Events "
+"between the current frame and [code]delta[/code] are handled."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:42
+msgid "Returns the name of the next animation in the queue."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:53
+msgid ""
+"Triggers the [code]anim_to[/code] animation when the [code]anim_from[/code] "
+"animation completes."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:60
+msgid ""
+"[AnimationPlayer] caches animated nodes. It may not notice if a node "
+"disappears; [method clear_caches] forces it to update the cache again."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:67
+msgid "Clears all queued, unplayed animations."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:76
+msgid ""
+"Returns the name of [code]animation[/code] or an empty string if not found."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:85
+msgid ""
+"Returns the [Animation] with key [code]name[/code] or [code]null[/code] if "
+"not found."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:92
+msgid "Returns the list of stored animation names."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:103
+msgid ""
+"Gets the blend time (in seconds) between two animations, referenced by their "
+"names."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:110
+msgid ""
+"Gets the actual playing speed of current animation or 0 if not playing. This "
+"speed is the [member playback_speed] property multiplied by "
+"[code]custom_speed[/code] argument specified when calling the [method play] "
+"method."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:117
+msgid ""
+"Returns a list of the animation names that are currently queued to play."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:126
+msgid ""
+"Returns [code]true[/code] if the [AnimationPlayer] stores an [Animation] "
+"with key [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:133
+msgid "Returns [code]true[/code] if playing an animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:148
+msgid ""
+"Plays the animation with key [code]name[/code]. Custom blend times and speed "
+"can be set. If [code]custom_speed[/code] is negative and [code]from_end[/"
+"code] is [code]true[/code], the animation will play backwards (which is "
+"equivalent to calling [method play_backwards]).\n"
+"The [AnimationPlayer] keeps track of its current or last played animation "
+"with [member assigned_animation]. If this method is called with that same "
+"animation [code]name[/code], or with no [code]name[/code] parameter, the "
+"assigned animation will resume playing if it was paused, or restart if it "
+"was stopped (see [method stop] for both pause and stop). If the animation "
+"was already playing, it will keep playing.\n"
+"[b]Note:[/b] The animation will be updated the next time the "
+"[AnimationPlayer] is processed. If other variables are updated at the same "
+"time this is called, they may be updated too early. To perform the update "
+"immediately, call [code]advance(0)[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:161
+msgid ""
+"Plays the animation with key [code]name[/code] in reverse.\n"
+"This method is a shorthand for [method play] with [code]custom_speed = -1.0[/"
+"code] and [code]from_end = true[/code], so see its description for more "
+"information."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:171
+msgid ""
+"Queues an animation for playback once the current one is done.\n"
+"[b]Note:[/b] If a looped animation is currently playing, the queued "
+"animation will never play unless the looped animation is stopped somehow."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:181
+msgid "Removes the animation with key [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:192
+msgid ""
+"Renames an existing animation with key [code]name[/code] to [code]newname[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:203
+msgid ""
+"Seeks the animation to the [code]seconds[/code] point in time (in seconds). "
+"If [code]update[/code] is [code]true[/code], the animation updates too, "
+"otherwise it updates at process time. Events between the current frame and "
+"[code]seconds[/code] are skipped."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:216
+msgid ""
+"Specifies a blend time (in seconds) between two animations, referenced by "
+"their names."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:225
+msgid ""
+"Stops or pauses the currently playing animation. If [code]reset[/code] is "
+"[code]true[/code], the animation position is reset to [code]0[/code] and the "
+"playback speed is reset to [code]1.0[/code].\n"
+"If [code]reset[/code] is [code]false[/code], the [member "
+"current_animation_position] will be kept and calling [method play] or "
+"[method play_backwards] without arguments or with the same animation name as "
+"[member assigned_animation] will resume the animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:232
+msgid ""
+"If playing, the current animation; otherwise, the animation last played. "
+"When set, would change the animation, but would not play it unless currently "
+"playing. See also [member current_animation]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:235
+msgid "The name of the animation to play when the scene loads."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:238
+msgid ""
+"The name of the current animation, \"\" if not playing anything. When being "
+"set, does not restart the animation. See also [method play]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:241
+msgid "The length (in seconds) of the currently being played animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:244
+msgid "The position (in seconds) of the currently playing animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:247
+msgid "The call mode to use for Call Method tracks."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:250
+msgid ""
+"If [code]true[/code], updates animations in response to process-related "
+"notifications."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:253
+msgid ""
+"The default time in which to blend animations. Ranges from 0 to 4096 with "
+"0.01 precision."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:256
+msgid "The process notification in which to update animations."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:259
+msgid ""
+"The speed scaling ratio. For instance, if this value is 1, then the "
+"animation plays at normal speed. If it's 0.5, then it plays at half speed. "
+"If it's 2, then it plays at double speed."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:262
+msgid "The node from which node path references will travel."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:272
+msgid ""
+"If the currently being played animation changes, this signal will notify of "
+"such change."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:279
+msgid "Notifies when an animation finished playing."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:286
+msgid "Notifies when an animation starts playing."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:291
+msgid ""
+"Notifies when the caches have been cleared, either automatically, or "
+"manually via [method clear_caches]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:297
+msgid ""
+"Process animation during the physics process. This is especially useful when "
+"animating physics bodies."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:300
+msgid "Process animation during the idle process."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:303
+msgid ""
+"Do not process animation. Use [method advance] to process the animation "
+"manually."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:306
+msgid ""
+"Batch method calls during the animation process, then do the calls after "
+"events are processed. This avoids bugs involving deleting nodes or modifying "
+"the AnimationPlayer while playing."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:309
+msgid "Make method calls immediately when reached in the animation."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:4
+msgid ""
+"A node to be used for advanced animation transitions in an [AnimationPlayer]."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:10
+msgid "https://github.com/godotengine/tps-demo"
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:19
+msgid "Manually advance the animations by the specified time (in seconds)."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:41
+msgid "If [code]true[/code], the [AnimationTree] will be processing."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:44
+msgid "The path to the [AnimationPlayer] used for animating."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:47
+msgid ""
+"The process mode of this [AnimationTree]. See [enum AnimationProcessMode] "
+"for available modes."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:52
+msgid "The root animation node of this [AnimationTree]. See [AnimationNode]."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:57
+msgid ""
+"The animations will progress during the physics frame (i.e. [method Node."
+"_physics_process])."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:60
+msgid ""
+"The animations will progress during the idle frame (i.e. [method Node."
+"_process])."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:63
+msgid "The animations will only progress manually (see [method advance])."
+msgstr ""
+
+#: doc/classes/Area2D.xml:4
+msgid "2D area for detection and 2D physics influence."
+msgstr ""
+
+#: doc/classes/Area2D.xml:7
+msgid ""
+"2D area that detects [CollisionObject2D] nodes overlapping, entering, or "
+"exiting. Can also alter or override local physics parameters (gravity, "
+"damping)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/using_area_2d.html"
+msgstr ""
+
+#: doc/classes/Area2D.xml:19
+msgid ""
+"Returns an individual bit on the layer mask. Describes whether other areas "
+"will collide with this one on the given layer."
+msgstr ""
+
+#: doc/classes/Area2D.xml:28
+msgid ""
+"Returns an individual bit on the collision mask. Describes whether this area "
+"will collide with others on the given layer."
+msgstr ""
+
+#: doc/classes/Area2D.xml:35
+msgid ""
+"Returns a list of intersecting [Area2D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area2D.xml:42
+msgid ""
+"Returns a list of intersecting [PhysicsBody2D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area2D.xml:51
+msgid ""
+"If [code]true[/code], the given area overlaps the Area2D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/Area2D.xml:61
+msgid ""
+"If [code]true[/code], the given physics body overlaps the Area2D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:74
+msgid ""
+"Set/clear individual bits on the layer mask. This makes getting an area in/"
+"out of only one layer easier."
+msgstr ""
+
+#: doc/classes/Area2D.xml:85
+msgid ""
+"Set/clear individual bits on the collision mask. This makes selecting the "
+"areas scanned easier."
+msgstr ""
+
+#: doc/classes/Area2D.xml:91 doc/classes/Area3D.xml:90
+msgid ""
+"The rate at which objects stop spinning in this area. Represents the angular "
+"velocity lost per second. Values range from [code]0[/code] (no damping) to "
+"[code]1[/code] (full damping)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:94 doc/classes/Area3D.xml:93
+msgid "The name of the area's audio bus."
+msgstr ""
+
+#: doc/classes/Area2D.xml:97 doc/classes/Area3D.xml:96
+msgid ""
+"If [code]true[/code], the area's audio bus overrides the default audio bus."
+msgstr ""
+
+#: doc/classes/Area2D.xml:100 doc/classes/Area3D.xml:99
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/Area2D.xml:103 doc/classes/Area3D.xml:102
+msgid "The physics layers this area scans to determine collision detection."
+msgstr ""
+
+#: doc/classes/Area2D.xml:106 doc/classes/Area3D.xml:105
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Area2D.xml:109 doc/classes/Area3D.xml:108
+msgid ""
+"The falloff factor for point gravity. The greater the value, the faster "
+"gravity decreases with distance."
+msgstr ""
+
+#: doc/classes/Area2D.xml:112 doc/classes/Area3D.xml:111
+msgid ""
+"If [code]true[/code], gravity is calculated from a point (set via [member "
+"gravity_vec]). See also [member space_override]."
+msgstr ""
+
+#: doc/classes/Area2D.xml:115 doc/classes/Area3D.xml:114
+msgid ""
+"The area's gravity vector (not normalized). If gravity is a point (see "
+"[member gravity_point]), this will be the point of attraction."
+msgstr ""
+
+#: doc/classes/Area2D.xml:118 doc/classes/Area3D.xml:117
+msgid ""
+"The rate at which objects stop moving in this area. Represents the linear "
+"velocity lost per second. Values range from [code]0[/code] (no damping) to "
+"[code]1[/code] (full damping)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:121 doc/classes/Area3D.xml:120
+msgid "If [code]true[/code], other monitoring areas can detect this area."
+msgstr ""
+
+#: doc/classes/Area2D.xml:124 doc/classes/Area3D.xml:123
+msgid ""
+"If [code]true[/code], the area detects bodies or areas entering and exiting "
+"it."
+msgstr ""
+
+#: doc/classes/Area2D.xml:127 doc/classes/Area3D.xml:126
+msgid "The area's priority. Higher priority areas are processed first."
+msgstr ""
+
+#: doc/classes/Area2D.xml:130 doc/classes/Area3D.xml:141
+msgid ""
+"Override mode for gravity and damping calculations within this area. See "
+"[enum SpaceOverride] for possible values."
+msgstr ""
+
+#: doc/classes/Area2D.xml:138 doc/classes/Area3D.xml:149
+msgid "Emitted when another area enters."
+msgstr ""
+
+#: doc/classes/Area2D.xml:145 doc/classes/Area3D.xml:156
+msgid "Emitted when another area exits."
+msgstr ""
+
+#: doc/classes/Area2D.xml:158
+msgid ""
+"Emitted when another area enters, reporting which shapes overlapped. "
+"[code]shape_owner_get_owner(shape_find_owner(shape))[/code] returns the "
+"parent object of the owner of the [code]shape[/code]."
+msgstr ""
+
+#: doc/classes/Area2D.xml:171
+msgid ""
+"Emitted when another area exits, reporting which shapes were overlapping."
+msgstr ""
+
+#: doc/classes/Area2D.xml:178
+msgid ""
+"Emitted when a physics body enters.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:186
+msgid ""
+"Emitted when a physics body exits.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:200
+msgid ""
+"Emitted when a physics body enters, reporting which shapes overlapped.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:214
+msgid ""
+"Emitted when a physics body exits, reporting which shapes were overlapping.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:221 doc/classes/Area3D.xml:232
+msgid "This area does not affect gravity/damping."
+msgstr ""
+
+#: doc/classes/Area2D.xml:224 doc/classes/Area3D.xml:235
+msgid ""
+"This area adds its gravity/damping values to whatever has been calculated so "
+"far (in [member priority] order)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:227 doc/classes/Area3D.xml:238
+msgid ""
+"This area adds its gravity/damping values to whatever has been calculated so "
+"far (in [member priority] order), ignoring any lower priority areas."
+msgstr ""
+
+#: doc/classes/Area2D.xml:230 doc/classes/Area3D.xml:241
+msgid ""
+"This area replaces any gravity/damping, even the defaults, ignoring any "
+"lower priority areas."
+msgstr ""
+
+#: doc/classes/Area2D.xml:233 doc/classes/Area3D.xml:244
+msgid ""
+"This area replaces any gravity/damping calculated so far (in [member "
+"priority] order), but keeps calculating the rest of the areas."
+msgstr ""
+
+#: doc/classes/Area3D.xml:4
+msgid "General-purpose area node for detection and 3D physics influence."
+msgstr ""
+
+#: doc/classes/Area3D.xml:7
+msgid ""
+"3D area that detects [CollisionObject3D] nodes overlapping, entering, or "
+"exiting. Can also alter or override local physics parameters (gravity, "
+"damping)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:18
+msgid "Returns an individual bit on the layer mask."
+msgstr ""
+
+#: doc/classes/Area3D.xml:27 modules/csg/doc_classes/CSGShape3D.xml:18
+#: modules/csg/doc_classes/CSGShape3D.xml:27 doc/classes/RayCast2D.xml:70
+#: doc/classes/SoftBody3D.xml:35 doc/classes/SoftBody3D.xml:44
+msgid "Returns an individual bit on the collision mask."
+msgstr ""
+
+#: doc/classes/Area3D.xml:34
+msgid ""
+"Returns a list of intersecting [Area3D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area3D.xml:41
+msgid ""
+"Returns a list of intersecting [PhysicsBody3D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area3D.xml:50
+msgid ""
+"If [code]true[/code], the given area overlaps the Area3D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/Area3D.xml:60
+msgid ""
+"If [code]true[/code], the given physics body overlaps the Area3D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:73
+msgid ""
+"Set/clear individual bits on the layer mask. This simplifies editing this "
+"[Area3D]'s layers."
+msgstr ""
+
+#: doc/classes/Area3D.xml:84
+msgid ""
+"Set/clear individual bits on the collision mask. This simplifies editing "
+"which [Area3D] layers this [Area3D] scans."
+msgstr ""
+
+#: doc/classes/Area3D.xml:129
+msgid ""
+"The degree to which this area applies reverb to its associated audio. Ranges "
+"from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision."
+msgstr ""
+
+#: doc/classes/Area3D.xml:132
+msgid "If [code]true[/code], the area applies reverb to its associated audio."
+msgstr ""
+
+#: doc/classes/Area3D.xml:135
+msgid "The reverb bus name to use for this area's associated audio."
+msgstr ""
+
+#: doc/classes/Area3D.xml:138
+msgid ""
+"The degree to which this area's reverb is a uniform effect. Ranges from "
+"[code]0[/code] to [code]1[/code] with [code]0.1[/code] precision."
+msgstr ""
+
+#: doc/classes/Area3D.xml:169
+msgid ""
+"Emitted when another area enters, reporting which areas overlapped. "
+"[code]shape_owner_get_owner(shape_find_owner(shape))[/code] returns the "
+"parent object of the owner of the [code]shape[/code]."
+msgstr ""
+
+#: doc/classes/Area3D.xml:182
+msgid ""
+"Emitted when another area exits, reporting which areas were overlapping."
+msgstr ""
+
+#: doc/classes/Area3D.xml:189
+msgid ""
+"Emitted when a physics body enters.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:197
+msgid ""
+"Emitted when a physics body exits.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:211
+msgid ""
+"Emitted when a physics body enters, reporting which shapes overlapped.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:225
+msgid ""
+"Emitted when a physics body exits, reporting which shapes were overlapping.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Array.xml:4
+msgid "Generic array datatype."
+msgstr ""
+
+#: doc/classes/Array.xml:7
+msgid ""
+"Generic array which can contain several elements of any type, accessible by "
+"a numerical index starting at 0. Negative indices can be used to count from "
+"the back, like in Python (-1 is the last element, -2 the second to last, "
+"etc.).\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var array = [\"One\", 2, 3, \"Four\"]\n"
+"print(array[0]) # One.\n"
+"print(array[2]) # 3.\n"
+"print(array[-1]) # Four.\n"
+"array[2] = \"Three\"\n"
+"print(array[-2]) # Three.\n"
+"[/codeblock]\n"
+"Arrays can be concatenated using the [code]+[/code] operator:\n"
+"[codeblock]\n"
+"var array1 = [\"One\", 2]\n"
+"var array2 = [3, \"Four\"]\n"
+"print(array1 + array2) # [\"One\", 2, 3, \"Four\"]\n"
+"[/codeblock]\n"
+"Arrays are always passed by reference."
+msgstr ""
+
+#: doc/classes/Array.xml:34
+msgid "Constructs an array from a [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/Array.xml:43
+msgid "Constructs an array from a [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:52
+msgid "Constructs an array from a [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:61
+msgid "Constructs an array from a [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/Array.xml:70
+msgid "Constructs an array from a [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:79
+msgid "Constructs an array from a [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:88
+msgid "Constructs an array from a [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:97
+msgid "Constructs an array from a [PackedInt32Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:106
+msgid "Constructs an array from a [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/Array.xml:115 doc/classes/PackedByteArray.xml:28
+#: doc/classes/PackedColorArray.xml:28 doc/classes/PackedFloat32Array.xml:29
+#: doc/classes/PackedFloat64Array.xml:29 doc/classes/PackedInt32Array.xml:29
+#: doc/classes/PackedInt64Array.xml:29 doc/classes/PackedStringArray.xml:28
+#: doc/classes/PackedVector2Array.xml:28 doc/classes/PackedVector3Array.xml:28
+msgid ""
+"Appends an element at the end of the array (alias of [method push_back])."
+msgstr ""
+
+#: doc/classes/Array.xml:122
+msgid ""
+"Returns the last element of the array, or [code]null[/code] if the array is "
+"empty."
+msgstr ""
+
+#: doc/classes/Array.xml:133
+msgid ""
+"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. 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.\n"
+"[b]Note:[/b] Calling [method bsearch] on an unsorted array results in "
+"unexpected behavior."
+msgstr ""
+
+#: doc/classes/Array.xml:149
+msgid ""
+"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.\n"
+"[b]Note:[/b] Calling [method bsearch] on an unsorted array results in "
+"unexpected behavior."
+msgstr ""
+
+#: doc/classes/Array.xml:157
+msgid ""
+"Clears the array. This is equivalent to using [method resize] with a size of "
+"[code]0[/code]."
+msgstr ""
+
+#: doc/classes/Array.xml:166
+msgid "Returns the number of times an element is in the array."
+msgstr ""
+
+#: doc/classes/Array.xml:175
+msgid ""
+"Returns a copy of the array.\n"
+"If [code]deep[/code] is [code]true[/code], a deep copy is performed: all "
+"nested arrays and dictionaries are duplicated and will not be shared with "
+"the original array. If [code]false[/code], a shallow copy is made and "
+"references to the original nested arrays and dictionaries are kept, so that "
+"modifying a sub-array or dictionary in the copy will also impact those "
+"referenced in the source array."
+msgstr ""
+
+#: doc/classes/Array.xml:183 doc/classes/PackedByteArray.xml:64
+#: doc/classes/PackedColorArray.xml:44 doc/classes/PackedFloat32Array.xml:45
+#: doc/classes/PackedFloat64Array.xml:45 doc/classes/PackedInt32Array.xml:45
+#: doc/classes/PackedInt64Array.xml:45 doc/classes/PackedStringArray.xml:44
+#: doc/classes/PackedVector2Array.xml:44 doc/classes/PackedVector3Array.xml:44
+msgid "Returns [code]true[/code] if the array is empty."
+msgstr ""
+
+#: doc/classes/Array.xml:192
+msgid "Removes the first occurrence of a value from the array."
+msgstr ""
+
+#: doc/classes/Array.xml:203
+msgid ""
+"Searches the array for a value and returns its index or -1 if not found. "
+"Optionally, the initial search index can be passed."
+msgstr ""
+
+#: doc/classes/Array.xml:212
+msgid ""
+"Searches the array in reverse order for a value and returns its index or -1 "
+"if not found."
+msgstr ""
+
+#: doc/classes/Array.xml:219
+msgid ""
+"Returns the first element of the array, or [code]null[/code] if the array is "
+"empty."
+msgstr ""
+
+#: doc/classes/Array.xml:228
+msgid ""
+"Returns [code]true[/code] if the array contains the given value.\n"
+"[codeblock]\n"
+"[\"inside\", 7].has(\"inside\") == true\n"
+"[\"inside\", 7].has(\"outside\") == false\n"
+"[\"inside\", 7].has(7) == true\n"
+"[\"inside\", 7].has(\"7\") == false\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Array.xml:241
+msgid "Returns a hashed integer value representing the array contents."
+msgstr ""
+
+#: doc/classes/Array.xml:252
+msgid ""
+"Inserts a new element at a given position in the array. The position must be "
+"valid, or at the end of the array ([code]pos == size()[/code])."
+msgstr ""
+
+#: doc/classes/Array.xml:259 doc/classes/PackedByteArray.xml:107
+#: doc/classes/PackedColorArray.xml:62 doc/classes/PackedFloat32Array.xml:63
+#: doc/classes/PackedFloat64Array.xml:63 doc/classes/PackedInt32Array.xml:63
+#: doc/classes/PackedInt64Array.xml:63 doc/classes/PackedStringArray.xml:62
+#: doc/classes/PackedVector2Array.xml:62 doc/classes/PackedVector3Array.xml:62
+msgid "Reverses the order of the elements in the array."
+msgstr ""
+
+#: doc/classes/Array.xml:266
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Array.xml:273
+msgid ""
+"Returns the minimum value contained in the array if all elements are of "
+"comparable types. If the elements can't be compared, [code]null[/code] is "
+"returned."
+msgstr ""
+
+#: doc/classes/Array.xml:280
+msgid ""
+"Removes and returns the last element of the array. Returns [code]null[/code] "
+"if the array is empty."
+msgstr ""
+
+#: doc/classes/Array.xml:287
+msgid ""
+"Removes and returns the first element of the array. Returns [code]null[/"
+"code] if the array is empty."
+msgstr ""
+
+#: doc/classes/Array.xml:296 doc/classes/PackedByteArray.xml:116
+#: doc/classes/PackedFloat32Array.xml:72 doc/classes/PackedFloat64Array.xml:72
+msgid "Appends an element at the end of the array."
+msgstr ""
+
+#: doc/classes/Array.xml:305
+msgid "Adds an element at the beginning of the array."
+msgstr ""
+
+#: doc/classes/Array.xml:314 doc/classes/PackedByteArray.xml:125
+#: doc/classes/PackedColorArray.xml:80 doc/classes/PackedFloat32Array.xml:81
+#: doc/classes/PackedFloat64Array.xml:81 doc/classes/PackedInt32Array.xml:81
+#: doc/classes/PackedInt64Array.xml:81 doc/classes/PackedStringArray.xml:80
+#: doc/classes/PackedVector2Array.xml:80 doc/classes/PackedVector3Array.xml:80
+msgid "Removes an element from the array by index."
+msgstr ""
+
+#: doc/classes/Array.xml:323
+msgid ""
+"Resizes the array to contain a different number of elements. If the array "
+"size is smaller, elements are cleared, if bigger, new elements are "
+"[code]null[/code]."
+msgstr ""
+
+#: doc/classes/Array.xml:334
+msgid ""
+"Searches the array in reverse order. Optionally, a start search index can be "
+"passed. If negative, the start index is considered relative to the end of "
+"the array."
+msgstr ""
+
+#: doc/classes/Array.xml:341
+msgid ""
+"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 "
+"@GDScript.randi]. Call [method @GDScript.randomize] to ensure that a new "
+"seed will be used each time if you want non-reproducible shuffling."
+msgstr ""
+
+#: doc/classes/Array.xml:348
+msgid "Returns the number of elements in the array."
+msgstr ""
+
+#: doc/classes/Array.xml:363
+msgid ""
+"Duplicates the subset described in the function and returns it in an array, "
+"deeply copying the array if [code]deep[/code] is [code]true[/code]. Lower "
+"and upper index are inclusive, with the [code]step[/code] describing the "
+"change between indices while slicing."
+msgstr ""
+
+#: doc/classes/Array.xml:370
+msgid ""
+"Sorts the array.\n"
+"[b]Note:[/b] Strings are sorted in alphabetical order (as opposed to natural "
+"order). This may lead to unexpected behavior when sorting an array of "
+"strings ending with a sequence of numbers. Consider the following example:\n"
+"[codeblock]\n"
+"var strings = [\"string1\", \"string2\", \"string10\", \"string11\"]\n"
+"strings.sort()\n"
+"print(strings) # Prints [string1, string10, string11, string2]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Array.xml:387
+msgid ""
+"Sorts the array using a custom method. The arguments are an object that "
+"holds the method and the name of such method. The custom method receives two "
+"arguments (a pair of elements from the array) and must return either "
+"[code]true[/code] or [code]false[/code].\n"
+"[b]Note:[/b] you cannot randomize the return value as the heapsort algorithm "
+"expects a deterministic result. Doing so will result in unexpected "
+"behavior.\n"
+"[codeblock]\n"
+"class MyCustomSorter:\n"
+" static func sort_ascending(a, b):\n"
+" if a[0] < b[0]:\n"
+" return true\n"
+" return false\n"
+"\n"
+"var my_items = [[5, \"Potato\"], [9, \"Rice\"], [4, \"Tomato\"]]\n"
+"my_items.sort_custom(MyCustomSorter, \"sort_ascending\")\n"
+"print(my_items) # Prints [[4, Tomato], [5, Potato], [9, Rice]].\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:4
+msgid ""
+"[Mesh] type that provides utility for constructing a surface from arrays."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:7
+msgid ""
+"The [ArrayMesh] is used to construct a [Mesh] by specifying the attributes "
+"as arrays.\n"
+"The most basic example is the creation of a single triangle:\n"
+"[codeblock]\n"
+"var vertices = PackedVector3Array()\n"
+"vertices.push_back(Vector3(0, 1, 0))\n"
+"vertices.push_back(Vector3(1, 0, 0))\n"
+"vertices.push_back(Vector3(0, 0, 1))\n"
+"# Initialize the ArrayMesh.\n"
+"var arr_mesh = ArrayMesh.new()\n"
+"var arrays = []\n"
+"arrays.resize(ArrayMesh.ARRAY_MAX)\n"
+"arrays[ArrayMesh.ARRAY_VERTEX] = vertices\n"
+"# Create the Mesh.\n"
+"arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)\n"
+"var m = MeshInstance3D.new()\n"
+"m.mesh = arr_mesh\n"
+"[/codeblock]\n"
+"The [MeshInstance3D] is ready to be added to the [SceneTree] to be shown."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:27
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/content/procedural_geometry/"
+"arraymesh.html"
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:36
+msgid ""
+"Adds name for a blend shape that will be added with [method "
+"add_surface_from_arrays]. Must be called before surface is added."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:55
+msgid ""
+"Creates a new surface.\n"
+"Surfaces are created to be rendered using a [code]primitive[/code], which "
+"may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, "
+"when using indices, it is recommended to only use points, lines or "
+"triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/"
+"code] for this new surface.\n"
+"The [code]arrays[/code] argument is an array of arrays. See [enum ArrayType] "
+"for the values used in this array. For example, [code]arrays[0][/code] is "
+"the array of vertices. That first vertex sub-array is always required; the "
+"others are optional. Adding an index array puts this function into \"index "
+"mode\" where the vertex and other arrays become the sources of data and the "
+"index array defines the vertex order. All sub-arrays must have the same "
+"length as the vertex array or be empty, except for [constant ARRAY_INDEX] if "
+"it is used.\n"
+"Adding an index array puts this function into \"index mode\" where the "
+"vertex and other arrays become the sources of data, and the index array "
+"defines the order of the vertices.\n"
+"Godot uses clockwise winding order for front faces of triangle primitive "
+"modes."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:66
+msgid "Removes all blend shapes from this [ArrayMesh]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:73
+msgid "Removes all surfaces from this [ArrayMesh]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:80
+msgid "Returns the number of blend shapes that the [ArrayMesh] holds."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:89
+msgid "Returns the name of the blend shape at this index."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:100
+msgid ""
+"Will perform a UV unwrap on the [ArrayMesh] to prepare the mesh for "
+"lightmapping."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:107
+msgid "Will regenerate normal maps for the [ArrayMesh]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:116
+msgid ""
+"Returns the index of the first surface with this name held within this "
+"[ArrayMesh]. If none are found, -1 is returned."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:125
+msgid ""
+"Returns the length in indices of the index array in the requested surface "
+"(see [method add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:134
+msgid ""
+"Returns the length in vertices of the vertex array in the requested surface "
+"(see [method add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:143
+msgid ""
+"Returns the format mask of the requested surface (see [method "
+"add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:152
+msgid "Gets the name assigned to this surface."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:161
+msgid ""
+"Returns the primitive type of the requested surface (see [method "
+"add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:172
+msgid "Sets a name for a given surface."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:185
+msgid ""
+"Updates a specified region of mesh arrays on the GPU.\n"
+"[b]Warning:[/b] Only use if you know what you are doing. You can easily "
+"cause crashes by calling this function with improper arguments."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:192
+msgid "Sets the blend shape mode to one of [enum Mesh.BlendShapeMode]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:195
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:200
+msgid "Default value used for index_array_len when no indices are present."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:203
+msgid "Amount of weights/bone indices per vertex (always 4)."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:206
+msgid ""
+"[PackedVector3Array], [PackedVector2Array], or [Array] of vertex positions."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:209
+msgid "[PackedVector3Array] of vertex normals."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:212
+msgid ""
+"[PackedFloat32Array] of vertex tangents. Each element in groups of 4 floats, "
+"first 3 floats determine the tangent, and the last the binormal direction as "
+"-1 or 1."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:215
+msgid "[PackedColorArray] of vertex colors."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:218
+msgid "[PackedVector2Array] for UV coordinates."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:221
+msgid "[PackedVector2Array] for second UV coordinates."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:224
+msgid ""
+"[PackedFloat32Array] or [PackedInt32Array] of bone indices. Each element in "
+"groups of 4 floats."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:227
+msgid ""
+"[PackedFloat32Array] of bone weights. Each element in groups of 4 floats."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:230
+msgid ""
+"[PackedInt32Array] of integers used as indices referencing vertices, colors, "
+"normals, tangents, and textures. All of those arrays must have the same "
+"number of elements as the vertex array. No index can be beyond the vertex "
+"array size. When this index array is present, it puts the function into "
+"\"index mode,\" where the index selects the *i*'th vertex, normal, tangent, "
+"color, UV, etc. This means if you want to have different normals or colors "
+"along an edge, you have to duplicate the vertices.\n"
+"For triangles, the index array is interpreted as triples, referring to the "
+"vertices of each triangle. For lines, the index array is in pairs indicating "
+"the start and end of each line."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:234 doc/classes/Mesh.xml:210
+#: doc/classes/RenderingServer.xml:3180
+msgid "Represents the size of the [enum ArrayType] enum."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:237
+msgid "Array format will include vertices (mandatory)."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:240
+msgid "Array format will include normals."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:243
+msgid "Array format will include tangents."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:246
+msgid "Array format will include a color array."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:249
+msgid "Array format will include UVs."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:252
+msgid "Array format will include another set of UVs."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:255
+msgid "Array format will include bone indices."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:258
+msgid "Array format will include bone weights."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:261
+msgid "Index array will be used."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:4
+msgid "An anchor point in AR space."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:7
+msgid ""
+"The [ARVRAnchor] point is a spatial node that maps a real world location "
+"identified by the AR platform to a position within the game world. For "
+"example, as long as plane detection in ARKit is on, ARKit will identify and "
+"update the position of planes (tables, floors, etc) and create anchors for "
+"them.\n"
+"This node is mapped to one of the anchors through its unique ID. When you "
+"receive a signal that a new anchor is available, you should add this node to "
+"your scene for that anchor. You can predefine nodes and set the ID; the "
+"nodes will simply remain on 0,0,0 until a plane is recognized.\n"
+"Keep in mind that, as long as plane detection is enabled, the size, placing "
+"and orientation of an anchor will be updated as the detection logic learns "
+"more about the real world out there especially if only part of the surface "
+"is in view."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:18
+msgid "Returns the name given to this anchor."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:25
+msgid ""
+"Returns [code]true[/code] if the anchor is being tracked and [code]false[/"
+"code] if no anchor with this ID is currently known."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:32
+msgid ""
+"If provided by the [ARVRInterface], this returns a mesh object for the "
+"anchor. For an anchor, this can be a shape related to the object being "
+"tracked or it can be a mesh that provides topology related to the anchor and "
+"can be used to create shadows/reflections on surfaces or for generating "
+"collision shapes."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:39
+msgid ""
+"Returns a plane aligned with our anchor; handy for intersection testing."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:46
+msgid ""
+"Returns the estimated size of the plane that was detected. Say when the "
+"anchor relates to a table in the real world, this is the estimated size of "
+"the surface of that table."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:52
+msgid ""
+"The anchor's ID. You can set this before the anchor itself exists. The first "
+"anchor gets an ID of [code]1[/code], the second an ID of [code]2[/code], "
+"etc. When anchors get removed, the engine can then assign the corresponding "
+"ID to new anchors. The most common situation where anchors \"disappear\" is "
+"when the AR server identifies that two anchors represent different parts of "
+"the same plane and merges them."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:60
+msgid ""
+"Emitted when the mesh associated with the anchor changes or when one becomes "
+"available. This is especially important for topology that is constantly "
+"being [code]mesh_updated[/code]."
+msgstr ""
+
+#: doc/classes/ARVRCamera.xml:4
+msgid ""
+"A camera node with a few overrules for AR/VR applied, such as location "
+"tracking."
+msgstr ""
+
+#: doc/classes/ARVRCamera.xml:7
+msgid ""
+"This is a helper spatial node for our camera; note that, if stereoscopic "
+"rendering is applicable (VR-HMD), most of the camera properties are ignored, "
+"as the HMD information overrides them. The only properties that can be "
+"trusted are the near and far planes.\n"
+"The position and orientation of this node is automatically updated by the "
+"ARVR Server to represent the location of the HMD if such tracking is "
+"available and can thus be used by game logic. Note that, in contrast to the "
+"ARVR Controller, the render thread has access to the most up-to-date "
+"tracking data of the HMD and the location of the ARVRCamera can lag a few "
+"milliseconds behind what is used for rendering as a result."
+msgstr ""
+
+#: doc/classes/ARVRCamera.xml:11 doc/classes/ARVRController.xml:12
+#: doc/classes/ARVRInterface.xml:11 doc/classes/ARVROrigin.xml:13
+#: doc/classes/ARVRPositionalTracker.xml:12 doc/classes/ARVRServer.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/vr/index.html"
+msgstr ""
+
+#: doc/classes/ARVRController.xml:4
+msgid "A spatial node representing a spatially-tracked controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:7
+msgid ""
+"This is a helper spatial node that is linked to the tracking of controllers. "
+"It also offers several handy passthroughs to the state of buttons and such "
+"on the controllers.\n"
+"Controllers are linked by their ID. You can create controller nodes before "
+"the controllers are available. If your game always uses two controllers (one "
+"for each hand), you can predefine the controllers with ID 1 and 2; they will "
+"become active as soon as the controllers are identified. If you expect "
+"additional controllers to be used, you should react to the signals and add "
+"ARVRController nodes to your scene.\n"
+"The position of the controller node is automatically updated by the "
+"[ARVRServer]. This makes this node ideal to add child nodes to visualize the "
+"controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:19
+msgid ""
+"If active, returns the name of the associated controller if provided by the "
+"AR/VR SDK used."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:26
+msgid ""
+"Returns the hand holding this controller, if known. See [enum "
+"ARVRPositionalTracker.TrackerHand]."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:33
+msgid ""
+"Returns [code]true[/code] if the bound controller is active. ARVR systems "
+"attempt to track active controllers."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:42
+msgid ""
+"Returns the value of the given axis for things like triggers, touchpads, "
+"etc. that are embedded into the controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:49
+msgid ""
+"Returns the ID of the joystick object bound to this. Every controller "
+"tracked by the [ARVRServer] that has buttons and axis will also be "
+"registered as a joystick within Godot. This means that all the normal "
+"joystick tracking and input mapping will work for buttons and axis found on "
+"the AR/VR controllers. This ID is purely offered as information so you can "
+"link up the controller with its joystick entry."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:56
+msgid ""
+"If provided by the [ARVRInterface], this returns a mesh associated with the "
+"controller. This can be used to visualize the controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:65
+msgid ""
+"Returns [code]true[/code] if the button at index [code]button[/code] is "
+"pressed. See [enum JoystickList], in particular the [code]JOY_VR_*[/code] "
+"constants."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:71
+msgid ""
+"The controller's ID.\n"
+"A controller ID of 0 is unbound and will always result in an inactive node. "
+"Controller ID 1 is reserved for the first controller that identifies itself "
+"as the left-hand controller and ID 2 is reserved for the first controller "
+"that identifies itself as the right-hand controller.\n"
+"For any other controller that the [ARVRServer] detects, we continue with "
+"controller ID 3.\n"
+"When a controller is turned off, its slot is freed. This ensures controllers "
+"will keep the same ID even when controllers with lower IDs are turned off."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:77
+msgid ""
+"The degree to which the controller vibrates. Ranges from [code]0.0[/code] to "
+"[code]1.0[/code] with precision [code].01[/code]. If changed, updates "
+"[member ARVRPositionalTracker.rumble] accordingly.\n"
+"This is a useful property to animate if you want the controller to vibrate "
+"for a limited duration."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:86
+msgid "Emitted when a button on this controller is pressed."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:93
+msgid "Emitted when a button on this controller is released."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:100
+msgid ""
+"Emitted when the mesh associated with the controller changes or when one "
+"becomes available. Generally speaking this will be a static mesh after "
+"becoming available."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:4
+msgid "Base class for an AR/VR interface implementation."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:7
+msgid ""
+"This class needs to be implemented to make an AR or VR platform available to "
+"Godot and these should be implemented as C++ modules or GDNative modules "
+"(note that for GDNative the subclass ARVRScriptInterface should be used). "
+"Part of the interface is exposed to GDScript so you can detect, enable and "
+"configure an AR or VR platform.\n"
+"Interfaces should be written in such a way that simply enabling them will "
+"give us a working setup. You can query the available interfaces through "
+"[ARVRServer]."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:18
+msgid ""
+"If this is an AR interface that requires displaying a camera feed as the "
+"background, this method returns the feed ID in the [CameraServer] for this "
+"interface."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:25
+msgid ""
+"Returns a combination of [enum Capabilities] flags providing information "
+"about the capabilities of this interface."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:32
+msgid "Returns the name of this interface (OpenVR, OpenHMD, ARKit, etc)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:39
+msgid ""
+"Returns the resolution at which we should render our intermediate results "
+"before things like lens distortion are applied by the VR platform."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:46
+msgid ""
+"If supported, returns the status of our tracking. This will allow you to "
+"provide feedback to the user whether there are issues with positional "
+"tracking."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:53
+msgid ""
+"Call this to initialize this interface. The first interface that is "
+"initialized is identified as the primary interface and it will be used for "
+"rendering output.\n"
+"After initializing the interface you want to use you then need to enable the "
+"AR/VR mode of a viewport and rendering should commence.\n"
+"[b]Note:[/b] You must enable the AR/VR mode on the main viewport for any "
+"device that uses the main output of Godot, such as for mobile VR.\n"
+"If you do this for a platform that handles its own output (such as OpenVR) "
+"Godot will show just one eye without distortion on screen. Alternatively, "
+"you can add a separate viewport node to your scene and enable AR/VR on that "
+"viewport. It will be used to output to the HMD, leaving you free to do "
+"anything you like in the main window, such as using a separate camera as a "
+"spectator camera or rendering something completely different.\n"
+"While currently not used, you can activate additional interfaces. You may "
+"wish to do this if you want to track controllers from other platforms. "
+"However, at this point in time only one interface can render to an HMD."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:64
+msgid ""
+"Returns [code]true[/code] if the current output of this interface is in "
+"stereo."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:71
+msgid "Turns the interface off."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:77
+msgid "On an AR interface, [code]true[/code] if anchor detection is enabled."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:80
+msgid "[code]true[/code] if this interface been initialized."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:83
+msgid "[code]true[/code] if this is the primary interface."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:88
+msgid "No ARVR capabilities."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:91
+msgid ""
+"This interface can work with normal rendering output (non-HMD based AR)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:94
+msgid "This interface supports stereoscopic rendering."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:97
+msgid "This interface supports AR (video background and real world tracking)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:100
+msgid ""
+"This interface outputs to an external device. If the main viewport is used, "
+"the on screen output is an unmodified buffer of either the left or right eye "
+"(stretched if the viewport size is not changed to the same aspect ratio of "
+"[method get_render_targetsize]). Using a separate viewport node frees up the "
+"main viewport for other purposes."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:103
+msgid ""
+"Mono output, this is mostly used internally when retrieving positioning "
+"information for our camera node or when stereo scopic rendering is not "
+"supported."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:106
+msgid ""
+"Left eye output, this is mostly used internally when rendering the image for "
+"the left eye and obtaining positioning and projection information."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:109
+msgid ""
+"Right eye output, this is mostly used internally when rendering the image "
+"for the right eye and obtaining positioning and projection information."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:112
+msgid "Tracking is behaving as expected."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:115
+msgid ""
+"Tracking is hindered by excessive motion (the player is moving faster than "
+"tracking can keep up)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:118
+msgid ""
+"Tracking is hindered by insufficient features, it's too dark (for camera-"
+"based tracking), player is blocked, etc."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:121
+msgid ""
+"We don't know the status of the tracking or this interface does not provide "
+"feedback."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:124
+msgid ""
+"Tracking is not functional (camera not plugged in or obscured, lighthouses "
+"turned off, etc.)."
+msgstr ""
+
+#: modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml:4
+msgid "GDNative wrapper for an ARVR interface."
+msgstr ""
+
+#: modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml:7
+msgid ""
+"This is a wrapper class for GDNative implementations of the ARVR interface. "
+"To use a GDNative ARVR interface, simply instantiate this object and set "
+"your GDNative library containing the ARVR interface implementation."
+msgstr ""
+
+#: doc/classes/ARVROrigin.xml:4
+msgid "The origin point in AR/VR."
+msgstr ""
+
+#: doc/classes/ARVROrigin.xml:7
+msgid ""
+"This is a special node within the AR/VR system that maps the physical "
+"location of the center of our tracking space to the virtual location within "
+"our game world.\n"
+"There should be only one of these nodes in your scene and you must have one. "
+"All the ARVRCamera, ARVRController and ARVRAnchor nodes should be direct "
+"children of this node for spatial tracking to work correctly.\n"
+"It is the position of this node that you update when your character needs to "
+"move through your game world while we're not moving in the real world. "
+"Movement in the real world is always in relation to this origin point.\n"
+"For example, if your character is driving a car, the ARVROrigin node should "
+"be a child node of this car. Or, if you're implementing a teleport system to "
+"move your character, you should change the position of this node."
+msgstr ""
+
+#: doc/classes/ARVROrigin.xml:19
+msgid ""
+"Allows you to adjust the scale to your game's units. Most AR/VR platforms "
+"assume a scale of 1 game world unit = 1 real world meter.\n"
+"[b]Note:[/b] This method is a passthrough to the [ARVRServer] itself."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:4
+msgid "A tracked object."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:7
+msgid ""
+"An instance of this object represents a device that is tracked, such as a "
+"controller or anchor point. HMDs aren't represented here as they are handled "
+"internally.\n"
+"As controllers are turned on and the AR/VR interface detects them, instances "
+"of this object are automatically added to this list of active tracking "
+"objects accessible through the [ARVRServer].\n"
+"The [ARVRController] and [ARVRAnchor] both consume objects of this type and "
+"should be used in your project. The positional trackers are just under-the-"
+"hood objects that make this all work. These are mostly exposed so that "
+"GDNative-based interfaces can interact with them."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:19
+msgid ""
+"Returns the hand holding this tracker, if known. See [enum TrackerHand] "
+"constants."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:26
+msgid ""
+"If this is a controller that is being tracked, the controller will also be "
+"represented by a joystick entry with this ID."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:33
+msgid ""
+"Returns the mesh related to a controller or anchor point if one is available."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:40
+msgid "Returns the controller or anchor point's name if available."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:47
+msgid "Returns the controller's orientation matrix."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:54
+msgid "Returns the world-space controller position."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:61
+msgid ""
+"Returns the internal tracker ID. This uniquely identifies the tracker per "
+"tracker type and matches the ID you need to specify for nodes such as the "
+"[ARVRController] and [ARVRAnchor] nodes."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:68
+msgid "Returns [code]true[/code] if this device tracks orientation."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:75
+msgid "Returns [code]true[/code] if this device tracks position."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:84
+msgid "Returns the transform combining this device's orientation and position."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:91
+msgid "Returns the tracker's type."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:97
+msgid ""
+"The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to "
+"[code]1.0[/code] with precision [code].01[/code]."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:102
+msgid "The hand this tracker is held in is unknown or not applicable."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:105
+msgid "This tracker is the left hand controller."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:108
+msgid "This tracker is the right hand controller."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:4
+msgid "Server for AR and VR features."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:7
+msgid ""
+"The AR/VR server is the heart of our Advanced and Virtual Reality solution "
+"and handles all the processing."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:21
+msgid ""
+"This is an important function to understand correctly. AR and VR platforms "
+"all handle positioning slightly differently.\n"
+"For platforms that do not offer spatial tracking, our origin point (0,0,0) "
+"is the location of our HMD, but you have little control over the direction "
+"the player is facing in the real world.\n"
+"For platforms that do offer spatial tracking, our origin point depends very "
+"much on the system. For OpenVR, our origin point is usually the center of "
+"the tracking space, on the ground. For other platforms, it's often the "
+"location of the tracking camera.\n"
+"This method allows you to center your tracker on the location of the HMD. It "
+"will take the current location of the HMD and use that to adjust all your "
+"tracking data; in essence, realigning the real world to your player's "
+"current position in the game world.\n"
+"For this method to produce usable results, tracking information must be "
+"available. This often takes a few frames after starting your game.\n"
+"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."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:35
+msgid ""
+"Finds an interface by its name. For instance, if your project uses "
+"capabilities of an AR/VR platform, you can find the interface for that "
+"platform by name and initialize it."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:42
+msgid "Returns the primary interface's transformation."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:51
+msgid ""
+"Returns the interface registered at a given index in our list of interfaces."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:58
+msgid ""
+"Returns the number of interfaces currently registered with the AR/VR server. "
+"If your project supports multiple AR/VR platforms, you can look through the "
+"available interface, and either present the user with a selection or simply "
+"try to initialize each interface and use the first one that returns "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:65
+msgid ""
+"Returns a list of available interfaces the ID and name of each interface."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:72
+msgid ""
+"Returns the absolute timestamp (in μs) of the last [ARVRServer] commit of "
+"the AR/VR eyes to [RenderingServer]. The value comes from an internal call "
+"to [method OS.get_ticks_usec]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:79
+msgid ""
+"Returns the duration (in μs) of the last frame. This is computed as the "
+"difference between [method get_last_commit_usec] and [method "
+"get_last_process_usec] when committing."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:86
+msgid ""
+"Returns the absolute timestamp (in μs) of the last [ARVRServer] process "
+"callback. The value comes from an internal call to [method OS."
+"get_ticks_usec]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:93
+msgid ""
+"Returns the reference frame transform. Mostly used internally and exposed "
+"for GDNative build interfaces."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:102
+msgid "Returns the positional tracker at the given ID."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:109
+msgid "Returns the number of trackers currently registered."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:115
+msgid "The primary [ARVRInterface] currently bound to the [ARVRServer]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:118
+msgid ""
+"Allows you to adjust the scale to your game's units. Most AR/VR platforms "
+"assume a scale of 1 game world unit = 1 real world meter."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:126
+msgid "Emitted when a new interface has been added."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:133
+msgid "Emitted when an interface is removed."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:144
+msgid ""
+"Emitted when a new tracker has been added. If you don't use a fixed number "
+"of controllers or if you're using [ARVRAnchor]s for an AR solution, it is "
+"important to react to this signal to add the appropriate [ARVRController] or "
+"[ARVRAnchor] nodes related to this new tracker."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:155
+msgid ""
+"Emitted when a tracker is removed. You should remove any [ARVRController] or "
+"[ARVRAnchor] points if applicable. This is not mandatory, the nodes simply "
+"become inactive and will be made active again when a new tracker becomes "
+"available (i.e. a new controller is switched on that takes the place of the "
+"previous one)."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:161
+msgid "The tracker tracks the location of a controller."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:164
+msgid "The tracker tracks the location of a base station."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:167
+msgid "The tracker tracks the location and size of an AR anchor."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:170
+msgid "Used internally to filter trackers of any known type."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:173
+msgid "Used internally if we haven't set the tracker type yet."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:176
+msgid "Used internally to select all trackers."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:179
+msgid ""
+"Fully reset the orientation of the HMD. Regardless of what direction the "
+"user is looking to in the real world. The user will look dead ahead in the "
+"virtual world."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:182
+msgid ""
+"Resets the orientation but keeps the tilt of the device. So if we're looking "
+"down, we keep looking down but heading will be reset."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:185
+msgid ""
+"Does not reset the orientation of the HMD, only the position of the player "
+"gets centered."
+msgstr ""
+
+#: doc/classes/AStar.xml:4
+msgid ""
+"An implementation of A* to find shortest paths among connected points in "
+"space."
+msgstr ""
+
+#: doc/classes/AStar.xml:7
+msgid ""
+"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.\n"
+"You must add points manually with [method add_point] and create segments "
+"manually with [method connect_points]. Then you can test if there is a path "
+"between two points with the [method are_points_connected] function, get a "
+"path containing indices by [method get_id_path], or one containing actual "
+"coordinates with [method get_point_path].\n"
+"It is also possible to use non-Euclidean distances. To do so, create a class "
+"that extends [code]AStar[/code] and override methods [method _compute_cost] "
+"and [method _estimate_cost]. Both take two indices and return a length, as "
+"is shown in the following example.\n"
+"[codeblock]\n"
+"class MyAStar:\n"
+" extends AStar\n"
+"\n"
+" func _compute_cost(u, v):\n"
+" return abs(u - v)\n"
+"\n"
+" func _estimate_cost(u, v):\n"
+" return min(0, abs(u - v) - 1)\n"
+"[/codeblock]\n"
+"[method _estimate_cost] should return a lower bound of the distance, i.e. "
+"[code]_estimate_cost(u, v) <= _compute_cost(u, v)[/code]. This serves as a "
+"hint to the algorithm because the custom [code]_compute_cost[/code] might be "
+"computation-heavy. If this is not the case, make [method _estimate_cost] "
+"return the same value as [method _compute_cost] to provide the algorithm "
+"with the most accurate information."
+msgstr ""
+
+#: doc/classes/AStar.xml:33
+msgid ""
+"Called when computing the cost between two connected points.\n"
+"Note that this function is hidden in the default [code]AStar[/code] class."
+msgstr ""
+
+#: doc/classes/AStar.xml:45
+msgid ""
+"Called when estimating the cost between a point and the path's ending "
+"point.\n"
+"Note that this function is hidden in the default [code]AStar[/code] class."
+msgstr ""
+
+#: doc/classes/AStar.xml:59
+msgid ""
+"Adds a new point at the given position with the given identifier. The "
+"algorithm prefers points with lower [code]weight_scale[/code] to form a "
+"path. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/"
+"code] must be 1 or larger.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(1, 0, 0), 4) # Adds the point (1, 0, 0) with "
+"weight_scale 4 and id 1\n"
+"[/codeblock]\n"
+"If there already exists a point for the given [code]id[/code], its position "
+"and weight scale are updated to the given values."
+msgstr ""
+
+#: doc/classes/AStar.xml:77
+msgid ""
+"Returns whether the two given points are directly connected by a segment. If "
+"[code]bidirectional[/code] is [code]false[/code], returns whether movement "
+"from [code]id[/code] to [code]to_id[/code] is possible through this segment."
+msgstr ""
+
+#: doc/classes/AStar.xml:84 doc/classes/AStar2D.xml:69
+msgid "Clears all the points and segments."
+msgstr ""
+
+#: doc/classes/AStar.xml:97
+msgid ""
+"Creates a segment between the given points. If [code]bidirectional[/code] is "
+"[code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] "
+"is allowed, not the reverse direction.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(1, 1, 0))\n"
+"astar.add_point(2, Vector3(0, 5, 0))\n"
+"astar.connect_points(1, 2, false)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar.xml:116
+msgid ""
+"Deletes the segment between the given points. If [code]bidirectional[/code] "
+"is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/"
+"code] is prevented, and a unidirectional segment possibly remains."
+msgstr ""
+
+#: doc/classes/AStar.xml:123 doc/classes/AStar2D.xml:106
+msgid "Returns the next available point ID with no point associated to it."
+msgstr ""
+
+#: doc/classes/AStar.xml:134 doc/classes/AStar2D.xml:117
+msgid ""
+"Returns the ID of the closest point to [code]to_position[/code], optionally "
+"taking disabled points into account. Returns -1 if there are no points in "
+"the points pool."
+msgstr ""
+
+#: doc/classes/AStar.xml:143
+msgid ""
+"Returns the closest position to [code]to_position[/code] that resides inside "
+"a segment between two connected points.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(0, 0, 0))\n"
+"astar.add_point(2, Vector3(0, 5, 0))\n"
+"astar.connect_points(1, 2)\n"
+"var res = astar.get_closest_position_in_segment(Vector3(3, 3, 0)) # Returns "
+"(0, 3, 0)\n"
+"[/codeblock]\n"
+"The result is in the segment that goes from [code]y = 0[/code] to [code]y = "
+"5[/code]. It's the closest position in the segment to the given point."
+msgstr ""
+
+#: doc/classes/AStar.xml:162
+msgid ""
+"Returns an array with the IDs of the points that form the path found by "
+"AStar between the given points. The array is ordered from the starting point "
+"to the ending point of the path.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(0, 0, 0))\n"
+"astar.add_point(2, Vector3(0, 1, 0), 1) # Default weight is 1\n"
+"astar.add_point(3, Vector3(1, 1, 0))\n"
+"astar.add_point(4, Vector3(2, 0, 0))\n"
+"\n"
+"astar.connect_points(1, 2, false)\n"
+"astar.connect_points(2, 3, false)\n"
+"astar.connect_points(4, 3, false)\n"
+"astar.connect_points(1, 4, false)\n"
+"\n"
+"var res = astar.get_id_path(1, 3) # Returns [1, 2, 3]\n"
+"[/codeblock]\n"
+"If you change the 2nd point's weight to 3, then the result will be [code][1, "
+"4, 3][/code] instead, because now even though the distance is longer, it's "
+"\"easier\" to get through point 4 than through point 2."
+msgstr ""
+
+#: doc/classes/AStar.xml:184 doc/classes/AStar2D.xml:167
+msgid ""
+"Returns the capacity of the structure backing the points, useful in "
+"conjunction with [code]reserve_space[/code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:193
+msgid ""
+"Returns an array with the IDs of the points that form the connection with "
+"the given point.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(0, 0, 0))\n"
+"astar.add_point(2, Vector3(0, 1, 0))\n"
+"astar.add_point(3, Vector3(1, 1, 0))\n"
+"astar.add_point(4, Vector3(2, 0, 0))\n"
+"\n"
+"astar.connect_points(1, 2, true)\n"
+"astar.connect_points(1, 3, true)\n"
+"\n"
+"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar.xml:212 doc/classes/AStar2D.xml:195
+msgid "Returns the number of points currently in the points pool."
+msgstr ""
+
+#: doc/classes/AStar.xml:223
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AStar.xml:232 doc/classes/AStar2D.xml:215
+msgid ""
+"Returns the position of the point associated with the given [code]id[/code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:241 doc/classes/AStar2D.xml:224
+msgid ""
+"Returns the weight scale of the point associated with the given [code]id[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:248 doc/classes/AStar2D.xml:231
+msgid "Returns an array of all points."
+msgstr ""
+
+#: doc/classes/AStar.xml:257 doc/classes/AStar2D.xml:240
+msgid ""
+"Returns whether a point associated with the given [code]id[/code] exists."
+msgstr ""
+
+#: doc/classes/AStar.xml:266 doc/classes/AStar2D.xml:249
+msgid ""
+"Returns whether a point is disabled or not for pathfinding. By default, all "
+"points are enabled."
+msgstr ""
+
+#: doc/classes/AStar.xml:275 doc/classes/AStar2D.xml:258
+msgid ""
+"Removes the point associated with the given [code]id[/code] from the points "
+"pool."
+msgstr ""
+
+#: doc/classes/AStar.xml:284 doc/classes/AStar2D.xml:267
+msgid ""
+"Reserves space internally for [code]num_nodes[/code] points, useful if "
+"you're adding a known large number of points at once, for a grid for "
+"instance. New capacity must be greater or equals to old capacity."
+msgstr ""
+
+#: doc/classes/AStar.xml:295 doc/classes/AStar2D.xml:278
+msgid ""
+"Disables or enables the specified point for pathfinding. Useful for making a "
+"temporary obstacle."
+msgstr ""
+
+#: doc/classes/AStar.xml:306 doc/classes/AStar2D.xml:289
+msgid ""
+"Sets the [code]position[/code] for the point with the given [code]id[/code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:317 doc/classes/AStar2D.xml:300
+msgid ""
+"Sets the [code]weight_scale[/code] for the point with the given [code]id[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:4
+msgid "AStar class representation that uses 2D vectors as edges."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:7
+msgid ""
+"This is a wrapper for the [AStar] class which uses 2D vectors instead of 3D "
+"vectors."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:20
+msgid ""
+"Called when computing the cost between two connected points.\n"
+"Note that this function is hidden in the default [code]AStar2D[/code] class."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:32
+msgid ""
+"Called when estimating the cost between a point and the path's ending "
+"point.\n"
+"Note that this function is hidden in the default [code]AStar2D[/code] class."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:46
+msgid ""
+"Adds a new point at the given position with the given identifier. The "
+"algorithm prefers points with lower [code]weight_scale[/code] to form a "
+"path. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/"
+"code] must be 1 or larger.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(1, 0), 4) # Adds the point (1, 0) with "
+"weight_scale 4 and id 1\n"
+"[/codeblock]\n"
+"If there already exists a point for the given [code]id[/code], its position "
+"and weight scale are updated to the given values."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:62
+msgid "Returns whether there is a connection/segment between the given points."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:82
+msgid ""
+"Creates a segment between the given points. If [code]bidirectional[/code] is "
+"[code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] "
+"is allowed, not the reverse direction.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(1, 1))\n"
+"astar.add_point(2, Vector2(0, 5))\n"
+"astar.connect_points(1, 2, false)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar2D.xml:99
+msgid "Deletes the segment between the given points."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:126
+msgid ""
+"Returns the closest position to [code]to_position[/code] that resides inside "
+"a segment between two connected points.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(0, 0))\n"
+"astar.add_point(2, Vector2(0, 5))\n"
+"astar.connect_points(1, 2)\n"
+"var res = astar.get_closest_position_in_segment(Vector2(3, 3)) # Returns (0, "
+"3)\n"
+"[/codeblock]\n"
+"The result is in the segment that goes from [code]y = 0[/code] to [code]y = "
+"5[/code]. It's the closest position in the segment to the given point."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:145
+msgid ""
+"Returns an array with the IDs of the points that form the path found by "
+"AStar2D between the given points. The array is ordered from the starting "
+"point to the ending point of the path.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(0, 0))\n"
+"astar.add_point(2, Vector2(0, 1), 1) # Default weight is 1\n"
+"astar.add_point(3, Vector2(1, 1))\n"
+"astar.add_point(4, Vector2(2, 0))\n"
+"\n"
+"astar.connect_points(1, 2, false)\n"
+"astar.connect_points(2, 3, false)\n"
+"astar.connect_points(4, 3, false)\n"
+"astar.connect_points(1, 4, false)\n"
+"\n"
+"var res = astar.get_id_path(1, 3) # Returns [1, 2, 3]\n"
+"[/codeblock]\n"
+"If you change the 2nd point's weight to 3, then the result will be [code][1, "
+"4, 3][/code] instead, because now even though the distance is longer, it's "
+"\"easier\" to get through point 4 than through point 2."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:176
+msgid ""
+"Returns an array with the IDs of the points that form the connection with "
+"the given point.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(0, 0))\n"
+"astar.add_point(2, Vector2(0, 1))\n"
+"astar.add_point(3, Vector2(1, 1))\n"
+"astar.add_point(4, Vector2(2, 0))\n"
+"\n"
+"astar.connect_points(1, 2, true)\n"
+"astar.connect_points(1, 3, true)\n"
+"\n"
+"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar2D.xml:206
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:4
+msgid ""
+"Packs multiple small textures in a single, bigger one. Helps to optimize "
+"video memory costs and render calls."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:7
+msgid ""
+"[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."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:15
+msgid "The texture that contains the atlas. Can be any [Texture2D] subtype."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:18
+msgid ""
+"If [code]true[/code], clips the area outside of the region to avoid bleeding "
+"of the surrounding texture pixels."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:21
+msgid ""
+"The margin around the region. The [Rect2]'s [member Rect2.size] parameter "
+"(\"w\" and \"h\" in the editor) resizes the texture so it fits within the "
+"margin."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:24
+msgid "The AtlasTexture's used region."
+msgstr ""
+
+#: doc/classes/AudioBusLayout.xml:4
+msgid "Stores information about the audio buses."
+msgstr ""
+
+#: doc/classes/AudioBusLayout.xml:7
+msgid ""
+"Stores position, muting, solo, bypass, effects, effect position, volume, and "
+"the connections between buses. See [AudioServer] for usage."
+msgstr ""
+
+#: doc/classes/AudioEffect.xml:4
+msgid "Audio effect for audio."
+msgstr ""
+
+#: doc/classes/AudioEffect.xml:7
+msgid ""
+"Base resource for audio bus. Applies an audio effect on the bus that the "
+"resource is applied on."
+msgstr ""
+
+#: doc/classes/AudioEffectAmplify.xml:4
+msgid ""
+"Adds an amplifying audio effect to an audio bus.\n"
+"Increases or decreases the volume of the selected audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectAmplify.xml:8
+msgid "Increases or decreases the volume being routed through the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectAmplify.xml:16
+msgid ""
+"Amount of amplification in decibels. Positive values make the sound louder, "
+"negative values make it quieter. Value can range from -80 to 24."
+msgstr ""
+
+#: doc/classes/AudioEffectBandLimitFilter.xml:4
+msgid "Adds a band limit filter to the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectBandLimitFilter.xml:7
+msgid ""
+"Limits the frequencies in a range around the [member AudioEffectFilter."
+"cutoff_hz] and allows frequencies outside of this range to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectBandPassFilter.xml:4
+msgid "Adds a band pass filter to the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectBandPassFilter.xml:7
+msgid ""
+"Attenuates the frequencies inside of a range around the [member "
+"AudioEffectFilter.cutoff_hz] and cuts frequencies outside of this band."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:4
+msgid "Adds a chorus audio effect."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:7
+msgid ""
+"Adds a chorus audio effect. The effect applies a filter with voices to "
+"duplicate the audio source and manipulate it through the filter."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:123
+msgid "The effect's raw signal."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:126 doc/classes/AudioEffectChorus.xml:144
+#: doc/classes/AudioEffectChorus.xml:162 doc/classes/AudioEffectChorus.xml:180
+msgid "The voice's cutoff frequency."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:129 doc/classes/AudioEffectChorus.xml:147
+#: doc/classes/AudioEffectChorus.xml:165 doc/classes/AudioEffectChorus.xml:183
+msgid "The voice's signal delay."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:132 doc/classes/AudioEffectChorus.xml:150
+#: doc/classes/AudioEffectChorus.xml:168 doc/classes/AudioEffectChorus.xml:186
+msgid "The voice filter's depth."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:135 doc/classes/AudioEffectChorus.xml:153
+#: doc/classes/AudioEffectChorus.xml:171 doc/classes/AudioEffectChorus.xml:189
+msgid "The voice's volume."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:138 doc/classes/AudioEffectChorus.xml:156
+#: doc/classes/AudioEffectChorus.xml:174 doc/classes/AudioEffectChorus.xml:192
+msgid "The voice's pan level."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:141 doc/classes/AudioEffectChorus.xml:159
+#: doc/classes/AudioEffectChorus.xml:177 doc/classes/AudioEffectChorus.xml:195
+msgid "The voice's filter rate."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:198
+msgid "The amount of voices in the effect."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:201
+msgid "The effect's processed signal."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:4
+msgid ""
+"Adds a compressor audio effect to an audio bus.\n"
+"Reduces sounds that exceed a certain threshold level, smooths out the "
+"dynamics and increases the overall volume."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:8
+msgid ""
+"Dynamic range compressor reduces the level of the sound when the amplitude "
+"goes over a certain threshold in Decibels. One of the main uses of a "
+"compressor is to increase the dynamic range by clipping as little as "
+"possible (when sound goes over 0dB).\n"
+"Compressor has many uses in the mix:\n"
+"- In the Master bus to compress the whole output (although an "
+"[AudioEffectLimiter] is probably better).\n"
+"- In voice channels to ensure they sound as balanced as possible.\n"
+"- Sidechained. This can reduce the sound level sidechained with another "
+"audio bus for threshold detection. This technique is common in video game "
+"mixing to the level of music and SFX while voices are being heard.\n"
+"- Accentuates transients by using a wider attack, making effects sound more "
+"punchy."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:21
+msgid ""
+"Compressor's reaction time when the signal exceeds the threshold, in "
+"microseconds. Value can range from 20 to 2000."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:24
+msgid "Gain applied to the output signal."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:27
+msgid ""
+"Balance between original signal and effect signal. Value can range from 0 "
+"(totally dry) to 1 (totally wet)."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:30
+msgid ""
+"Amount of compression applied to the audio once it passes the threshold "
+"level. The higher the ratio, the more the loud parts of the audio will be "
+"compressed. Value can range from 1 to 48."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:33
+msgid ""
+"Compressor's delay time to stop reducing the signal after the signal level "
+"falls below the threshold, in milliseconds. Value can range from 20 to 2000."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:36
+msgid "Reduce the sound level using another audio bus for threshold detection."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:39
+msgid ""
+"The level above which compression is applied to the audio. Value can range "
+"from -60 to 0."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:4
+msgid ""
+"Adds a delay audio effect to an audio bus. Plays input signal back after a "
+"period of time.\n"
+"Two tap delay and feedback options."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:8
+msgid ""
+"Plays input signal back after a period of time. The delayed signal may be "
+"played back multiple times to create the sound of a repeating, decaying "
+"echo. Delay effects range from a subtle echo effect to a pronounced blending "
+"of previous sounds with new sounds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:16
+msgid ""
+"Output percent of original sound. At 0, only delayed sounds are output. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:19
+msgid "If [code]true[/code], feedback is enabled."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:22
+msgid "Feedback delay time in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:25 doc/classes/AudioEffectDelay.xml:37
+msgid "Sound level for [code]tap1[/code]."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:28
+msgid ""
+"Low-pass filter for feedback, in Hz. Frequencies below this value are "
+"filtered out of the source signal."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:31
+msgid "If [code]true[/code], [code]tap1[/code] will be enabled."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:34
+msgid "[code]tap1[/code] delay time in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:40
+msgid ""
+"Pan position for [code]tap1[/code]. Value can range from -1 (fully left) to "
+"1 (fully right)."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:43
+msgid "If [code]true[/code], [code]tap2[/code] will be enabled."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:46
+msgid "[b]Tap2[/b] delay time in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:49
+msgid "Sound level for [code]tap2[/code]."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:52
+msgid ""
+"Pan position for [code]tap2[/code]. Value can range from -1 (fully left) to "
+"1 (fully right)."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:4
+msgid ""
+"Adds a distortion audio effect to an Audio bus.\n"
+"Modify the sound to make it dirty."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:8
+msgid ""
+"Modify the sound and make it dirty. Different types are available: clip, "
+"tan, lo-fi (bit crushing), overdrive, or waveshape.\n"
+"By distorting the waveform the frequency content change, which will often "
+"make the sound \"crunchy\" or \"abrasive\". For games, it can simulate sound "
+"coming from some saturated device or speaker very efficiently."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:17
+msgid "Distortion power. Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:20
+msgid ""
+"High-pass filter, in Hz. Frequencies higher than this value will not be "
+"affected by the distortion. Value can range from 1 to 20000."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:23
+msgid "Distortion type."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:26
+msgid ""
+"Increases or decreases the volume after the effect. Value can range from -80 "
+"to 24."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:29
+msgid ""
+"Increases or decreases the volume before the effect. Value can range from "
+"-60 to 60."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:34
+msgid ""
+"Digital distortion effect which cuts off peaks at the top and bottom of the "
+"waveform."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:39
+msgid ""
+"Low-resolution digital distortion effect. You can use it to emulate the "
+"sound of early digital audio devices."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:42
+msgid ""
+"Emulates the warm distortion produced by a field effect transistor, which is "
+"commonly used in solid-state musical instrument amplifiers."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:45
+msgid ""
+"Waveshaper distortions are used mainly by electronic musicians to achieve an "
+"extra-abrasive sound."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:4
+msgid ""
+"Base class for audio equalizers. Gives you control over frequencies.\n"
+"Use it to create a custom equalizer if [AudioEffectEQ6], [AudioEffectEQ10] "
+"or [AudioEffectEQ21] don't fit your needs."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:8
+msgid ""
+"AudioEffectEQ gives you control over frequencies. Use it to compensate for "
+"existing deficiencies in audio. AudioEffectEQs are useful on the Master bus "
+"to completely master a mix and give it more character. They are also useful "
+"when a game is run on a mobile device, to adjust the mix to that kind of "
+"speakers (it can be added but disabled when headphones are plugged)."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:17
+msgid "Returns the number of bands of the equalizer."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:26
+msgid "Returns the band's gain at the specified index, in dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:37
+msgid "Sets band's gain at the specified index, in dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ10.xml:4
+msgid ""
+"Adds a 10-band equalizer audio effect to an Audio bus. Gives you control "
+"over frequencies from 31 Hz to 16000 Hz.\n"
+"Each frequency can be modulated between -60/+24 dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ10.xml:8
+msgid ""
+"Frequency bands:\n"
+"Band 1: 31 Hz\n"
+"Band 2: 62 Hz\n"
+"Band 3: 125 Hz\n"
+"Band 4: 250 Hz\n"
+"Band 5: 500 Hz\n"
+"Band 6: 1000 Hz\n"
+"Band 7: 2000 Hz\n"
+"Band 8: 4000 Hz\n"
+"Band 9: 8000 Hz\n"
+"Band 10: 16000 Hz\n"
+"See also [AudioEffectEQ], [AudioEffectEQ6], [AudioEffectEQ21]."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ21.xml:4
+msgid ""
+"Adds a 21-band equalizer audio effect to an Audio bus. Gives you control "
+"over frequencies from 22 Hz to 22000 Hz.\n"
+"Each frequency can be modulated between -60/+24 dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ21.xml:8
+msgid ""
+"Frequency bands:\n"
+"Band 1: 22 Hz\n"
+"Band 2: 32 Hz\n"
+"Band 3: 44 Hz\n"
+"Band 4: 63 Hz\n"
+"Band 5: 90 Hz\n"
+"Band 6: 125 Hz\n"
+"Band 7: 175 Hz\n"
+"Band 8: 250 Hz\n"
+"Band 9: 350 Hz\n"
+"Band 10: 500 Hz\n"
+"Band 11: 700 Hz\n"
+"Band 12: 1000 Hz\n"
+"Band 13: 1400 Hz\n"
+"Band 14: 2000 Hz\n"
+"Band 15: 2800 Hz\n"
+"Band 16: 4000 Hz\n"
+"Band 17: 5600 Hz\n"
+"Band 18: 8000 Hz\n"
+"Band 19: 11000 Hz\n"
+"Band 20: 16000 Hz\n"
+"Band 21: 22000 Hz\n"
+"See also [AudioEffectEQ], [AudioEffectEQ6], [AudioEffectEQ10]."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ6.xml:4
+msgid ""
+"Adds a 6-band equalizer audio effect to an Audio bus. Gives you control over "
+"frequencies from 32 Hz to 10000 Hz.\n"
+"Each frequency can be modulated between -60/+24 dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ6.xml:8
+msgid ""
+"Frequency bands:\n"
+"Band 1: 32 Hz\n"
+"Band 2: 100 Hz\n"
+"Band 3: 320 Hz\n"
+"Band 4: 1000 Hz\n"
+"Band 5: 3200 Hz\n"
+"Band 6: 10000 Hz\n"
+"See also [AudioEffectEQ], [AudioEffectEQ10], [AudioEffectEQ21]."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:4
+msgid "Adds a filter to the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:7
+msgid "Allows frequencies other than the [member cutoff_hz] to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:15
+msgid "Threshold frequency for the filter, in Hz."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:20
+msgid "Gain amount of the frequencies after the filter."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:23
+msgid "Amount of boost in the overtones near the cutoff frequency."
+msgstr ""
+
+#: doc/classes/AudioEffectHighPassFilter.xml:4
+msgid "Adds a high-pass filter to the Audio Bus."
+msgstr ""
+
+#: doc/classes/AudioEffectHighPassFilter.xml:7
+msgid ""
+"Cuts frequencies lower than the [member AudioEffectFilter.cutoff_hz] and "
+"allows higher frequencies to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:4
+msgid "Adds a soft-clip limiter audio effect to an Audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:7
+msgid ""
+"A limiter is similar to a compressor, but it's less flexible and designed to "
+"disallow sound going over a given dB threshold. Adding one in the Master bus "
+"is always recommended to reduce the effects of clipping.\n"
+"Soft clipping starts to reduce the peaks a little below the threshold level "
+"and progressively increases its effect as the input level increases such "
+"that the threshold is never exceeded."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:16
+msgid ""
+"The waveform's maximum allowed value, in decibels. Value can range from -20 "
+"to -0.1."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:19
+msgid ""
+"Applies a gain to the limited waves, in decibels. Value can range from 0 to "
+"6."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:24
+msgid ""
+"Threshold from which the limiter begins to be active, in decibels. Value can "
+"range from -30 to 0."
+msgstr ""
+
+#: doc/classes/AudioEffectLowPassFilter.xml:4
+msgid "Adds a low-pass filter to the Audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectLowPassFilter.xml:7
+msgid ""
+"Cuts frequencies higher than the [member AudioEffectFilter.cutoff_hz] and "
+"allows lower frequencies to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectNotchFilter.xml:4
+msgid "Adds a notch filter to the Audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectNotchFilter.xml:7
+msgid ""
+"Attenuates frequencies in a narrow band around the [member AudioEffectFilter."
+"cutoff_hz] and cuts frequencies outside of this range."
+msgstr ""
+
+#: doc/classes/AudioEffectPanner.xml:4
+msgid "Adds a panner audio effect to an Audio bus. Pans sound left or right."
+msgstr ""
+
+#: doc/classes/AudioEffectPanner.xml:7
+msgid ""
+"Determines how much of an audio signal is sent to the left and right buses."
+msgstr ""
+
+#: doc/classes/AudioEffectPanner.xml:15
+msgid "Pan position. Value can range from -1 (fully left) to 1 (fully right)."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:4
+msgid ""
+"Adds a phaser audio effect to an Audio bus.\n"
+"Combines the original signal with a copy that is slightly out of phase with "
+"the original."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:8
+msgid ""
+"Combines phase-shifted signals with the original signal. The movement of the "
+"phase-shifted signals is controlled using a low-frequency oscillator."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:16
+msgid ""
+"Governs how high the filter frequencies sweep. Low value will primarily "
+"affect bass frequencies. High value can sweep high into the treble. Value "
+"can range from 0.1 to 4."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:19
+msgid "Output percent of modified sound. Value can range from 0.1 to 0.9."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:22
+msgid ""
+"Determines the maximum frequency affected by the LFO modulations, in Hz. "
+"Value can range from 10 to 10000."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:25
+msgid ""
+"Determines the minimum frequency affected by the LFO modulations, in Hz. "
+"Value can range from 10 to 10000."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:28
+msgid ""
+"Adjusts the rate in Hz at which the effect sweeps up and down across the "
+"frequency range."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:4
+msgid ""
+"Adds a pitch-shifting audio effect to an Audio bus.\n"
+"Raises or lowers the pitch of original sound."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:8
+msgid ""
+"Allows modulation of pitch independently of tempo. All frequencies can be "
+"increased/decreased with minimal effect on transients."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:20
+msgid "Pitch value. Can range from 0 (-1 octave) to 16 (+16 octaves)."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:35
+#: doc/classes/AudioEffectSpectrumAnalyzer.xml:31
+msgid "Represents the size of the [enum FFT_Size] enum."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:4
+msgid "Audio effect used for recording sound from a microphone."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:9
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/audio/"
+"recording_with_microphone.html"
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:16
+msgid "Returns the recorded sample."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:23
+msgid "Returns whether the recording is active or not."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:32
+msgid ""
+"If [code]true[/code], the sound will be recorded. Note that restarting the "
+"recording will remove the previously recorded sample."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:38
+msgid ""
+"Specifies the format in which the sample will be recorded. See [enum "
+"AudioStreamSample.Format] for available formats."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:4
+msgid ""
+"Adds a reverberation audio effect to an Audio bus.\n"
+"Simulates the sound of acoustic environments such as rooms, concert halls, "
+"caverns, or an open spaces."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:8
+msgid ""
+"Simulates rooms of different sizes. Its parameters can be adjusted to "
+"simulate the sound of a specific room."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:16
+msgid ""
+"Defines how reflective the imaginary room's walls are. Value can range from "
+"0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:19
+msgid ""
+"Output percent of original sound. At 0, only modified sound is outputted. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:22
+msgid ""
+"High-pass filter passes signals with a frequency higher than a certain "
+"cutoff frequency and attenuates signals with frequencies lower than the "
+"cutoff frequency. Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:25
+msgid "Output percent of predelay. Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:28
+msgid ""
+"Time between the original signal and the early reflections of the reverb "
+"signal, in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:31
+msgid ""
+"Dimensions of simulated room. Bigger means more echoes. Value can range from "
+"0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:34
+msgid ""
+"Widens or narrows the stereo image of the reverb tail. 1 means fully widens. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:37
+msgid ""
+"Output percent of modified sound. At 0, only original sound is outputted. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectSpectrumAnalyzerInstance.xml:25
+msgid "Use the average value as magnitude."
+msgstr ""
+
+#: doc/classes/AudioEffectSpectrumAnalyzerInstance.xml:28
+msgid "Use the maximum value as magnitude."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:4
+msgid "Server interface for low-level audio access."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:7
+msgid ""
+"[AudioServer] is a low-level server interface for audio access. It is in "
+"charge of creating sample data (playable audio) as well as its playback via "
+"a voice interface."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html"
+msgstr ""
+
+#: doc/classes/AudioServer.xml:19
+msgid "Adds a bus at [code]at_position[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:32
+msgid ""
+"Adds an [AudioEffect] effect to the bus [code]bus_idx[/code] at "
+"[code]at_position[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:39
+msgid ""
+"Name of the current device for audio input (see [method "
+"capture_get_device_list])."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:46
+msgid "Returns the names of all audio input devices detected on the system."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:55
+msgid "Sets which audio input device is used for audio capture."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:62
+msgid "Generates an [AudioBusLayout] using the available buses and effects."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:71
+msgid ""
+"Returns the amount of channels of the bus at index [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:82
+msgid ""
+"Returns the [AudioEffect] at position [code]effect_idx[/code] in bus "
+"[code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:91
+msgid "Returns the number of effects on the bus at [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:104
+msgid ""
+"Returns the [AudioEffectInstance] assigned to the given bus and effect "
+"indices (and optionally channel)."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:113
+msgid "Returns the index of the bus with the name [code]bus_name[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:122
+msgid "Returns the name of the bus with the index [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:133
+msgid ""
+"Returns the peak volume of the left speaker at bus index [code]bus_idx[/"
+"code] and channel index [code]channel[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:144
+msgid ""
+"Returns the peak volume of the right speaker at bus index [code]bus_idx[/"
+"code] and channel index [code]channel[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:153
+msgid ""
+"Returns the name of the bus that the bus at index [code]bus_idx[/code] sends "
+"to."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:162
+msgid "Returns the volume of the bus at index [code]bus_idx[/code] in dB."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:169
+msgid "Returns the names of all audio devices detected on the system."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:176
+msgid "Returns the sample rate at the output of the [AudioServer]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:183
+msgid "Returns the audio driver's output latency."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:190
+msgid "Returns the speaker configuration."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:197
+msgid "Returns the relative time since the last mix occurred."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:204
+msgid "Returns the relative time until the next mix occurs."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:213 doc/classes/AudioServer.xml:292
+msgid ""
+"If [code]true[/code], the bus at index [code]bus_idx[/code] is bypassing "
+"effects."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:224 doc/classes/AudioServer.xml:305
+msgid ""
+"If [code]true[/code], the effect at index [code]effect_idx[/code] on the bus "
+"at index [code]bus_idx[/code] is enabled."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:233 doc/classes/AudioServer.xml:325
+msgid "If [code]true[/code], the bus at index [code]bus_idx[/code] is muted."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:242 doc/classes/AudioServer.xml:358
+msgid ""
+"If [code]true[/code], the bus at index [code]bus_idx[/code] is in solo mode."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:249
+msgid ""
+"Locks the audio driver's main loop.\n"
+"[b]Note:[/b] Remember to unlock it afterwards."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:261
+msgid ""
+"Moves the bus from index [code]index[/code] to index [code]to_index[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:270
+msgid "Removes the bus at index [code]index[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:281
+msgid ""
+"Removes the effect at index [code]effect_idx[/code] from the bus at index "
+"[code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:314
+msgid "Overwrites the currently used [AudioBusLayout]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:336
+msgid ""
+"Sets the name of the bus at index [code]bus_idx[/code] to [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:347
+msgid ""
+"Connects the output of the bus at [code]bus_idx[/code] to the bus named "
+"[code]send[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:369
+msgid ""
+"Sets the volume of the bus at index [code]bus_idx[/code] to [code]volume_db[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:382
+msgid "Swaps the position of two effects in bus [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:389
+msgid ""
+"Unlocks the audio driver's main loop. (After locking it, you should always "
+"unlock it.)"
+msgstr ""
+
+#: doc/classes/AudioServer.xml:395
+msgid "Number of available audio buses."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:398
+msgid ""
+"Name of the current device for audio output (see [method get_device_list])."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:401
+msgid ""
+"Scales the rate at which audio is played (i.e. setting it to [code]0.5[/"
+"code] will make the audio be played twice as fast)."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:407
+msgid "Emitted when the [AudioBusLayout] changes."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:413
+msgid "Two or fewer speakers were detected."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:416
+msgid "A 3.1 channel surround setup was detected."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:419
+msgid "A 5.1 channel surround setup was detected."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:422
+msgid "A 7.1 channel surround setup was detected."
+msgstr ""
+
+#: doc/classes/AudioStream.xml:4
+msgid "Base class for audio streams."
+msgstr ""
+
+#: doc/classes/AudioStream.xml:7
+msgid ""
+"Base class for audio streams. Audio streams are used for sound effects and "
+"music playback, and support WAV (via [AudioStreamSample]) and OGG (via "
+"[AudioStreamOGGVorbis]) file formats."
+msgstr ""
+
+#: doc/classes/AudioStream.xml:10 doc/classes/AudioStreamPlayer.xml:10
+#: doc/classes/AudioStreamPlayer2D.xml:10
+#: doc/classes/AudioStreamPlayer3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html"
+msgstr ""
+
+#: doc/classes/AudioStream.xml:17
+msgid "Returns the length of the audio stream in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamGenerator.xml:8
+#: doc/classes/AudioStreamGeneratorPlayback.xml:8
+msgid ""
+"https://github.com/godotengine/godot-demo-projects/tree/master/audio/"
+"generator"
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:4
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:7
+msgid "OGG Vorbis audio stream driver."
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:15
+msgid "Contains the audio data in bytes."
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:18
+msgid ""
+"If [code]true[/code], the stream will automatically loop when it reaches the "
+"end."
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:21
+msgid "Time in seconds at which the stream starts after being looped."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayback.xml:4
+msgid "Meta class for playing back audio."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayback.xml:7
+msgid ""
+"Can play, loop, pause a scroll through audio. See [AudioStream] and "
+"[AudioStreamOGGVorbis] for usage."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:4
+msgid "Plays back audio non-positionally."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:7
+msgid "Plays an audio stream non-positionally."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:17
+msgid "Returns the position in the [AudioStream] in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:24
+msgid ""
+"Returns the [AudioStreamPlayback] object associated with this "
+"[AudioStreamPlayer]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:33
+msgid "Plays the audio from the given [code]from_position[/code], in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:42 doc/classes/AudioStreamPlayer2D.xml:42
+#: doc/classes/AudioStreamPlayer3D.xml:42
+msgid "Sets the position from which audio will be played, in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:49 doc/classes/AudioStreamPlayer2D.xml:49
+#: doc/classes/AudioStreamPlayer3D.xml:49
+msgid "Stops the audio."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:55 doc/classes/AudioStreamPlayer2D.xml:61
+#: doc/classes/AudioStreamPlayer3D.xml:67
+msgid "If [code]true[/code], audio plays when added to scene tree."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:58 doc/classes/AudioStreamPlayer2D.xml:64
+#: doc/classes/AudioStreamPlayer3D.xml:70
+msgid "Bus on which this audio is playing."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:61
+msgid ""
+"If the audio configuration has more than two speakers, this sets the target "
+"channels. See [enum MixTarget] constants."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:64 doc/classes/AudioStreamPlayer2D.xml:70
+#: doc/classes/AudioStreamPlayer3D.xml:94
+msgid "Changes the pitch and the tempo of the audio."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:67 doc/classes/AudioStreamPlayer2D.xml:73
+#: doc/classes/AudioStreamPlayer3D.xml:97
+msgid "If [code]true[/code], audio is playing."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:70 doc/classes/AudioStreamPlayer2D.xml:76
+#: doc/classes/AudioStreamPlayer3D.xml:100
+msgid "The [AudioStream] object to be played."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:73 doc/classes/AudioStreamPlayer2D.xml:79
+#: doc/classes/AudioStreamPlayer3D.xml:103
+msgid ""
+"If [code]true[/code], the playback is paused. You can resume it by setting "
+"[code]stream_paused[/code] to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:76
+msgid "Volume of sound, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:82 doc/classes/AudioStreamPlayer2D.xml:88
+#: doc/classes/AudioStreamPlayer3D.xml:115
+msgid "Emitted when the audio stops playing."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:88
+msgid "The audio will be played only on the first channel."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:91
+msgid "The audio will be played on all surround channels."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:94
+msgid ""
+"The audio will be played on the second channel, which is usually the center."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:4
+msgid "Plays audio in 2D."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:7
+msgid "Plays audio that dampens with distance from screen center."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:17
+#: doc/classes/AudioStreamPlayer3D.xml:17
+msgid "Returns the position in the [AudioStream]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:24
+msgid ""
+"Returns the [AudioStreamPlayback] object associated with this "
+"[AudioStreamPlayer2D]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:33
+#: doc/classes/AudioStreamPlayer3D.xml:33
+msgid ""
+"Plays the audio from the given position [code]from_position[/code], in "
+"seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:55
+#: doc/classes/AudioStreamPlayer3D.xml:55
+msgid "Areas in which this sound plays."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:58
+msgid "Dampens audio over distance with this as an exponent."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:67
+msgid "Maximum distance from which audio is still hearable."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:82
+msgid "Base volume without dampening."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:4
+msgid "Plays 3D sound in 3D space."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:7
+msgid ""
+"Plays a sound effect with directed sound effects, dampens with distance if "
+"needed, generates effect of hearable position in space."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:24
+msgid ""
+"Returns the [AudioStreamPlayback] object associated with this "
+"[AudioStreamPlayer3D]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:58
+msgid "Dampens audio above this frequency, in Hz."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:61
+msgid "Amount how much the filter affects the loudness, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:64
+msgid ""
+"Decides if audio should get quieter with distance linearly, quadratically, "
+"logarithmically, or not be affected by distance, effectively disabling "
+"attenuation."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:73
+msgid "Decides in which step the Doppler effect should be calculated."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:76
+msgid "The angle in which the audio reaches cameras undampened."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:79
+msgid ""
+"If [code]true[/code], the audio should be dampened according to the "
+"direction of the sound."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:82
+msgid ""
+"Dampens audio if camera is outside of [member emission_angle_degrees] and "
+"[member emission_angle_enabled] is set by this factor, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:85
+msgid "Sets the absolute maximum of the soundlevel, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:88
+msgid ""
+"Sets the distance from which the [member out_of_range_mode] takes effect. "
+"Has no effect if set to 0."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:91
+msgid ""
+"Decides if audio should pause when source is outside of [member "
+"max_distance] range."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:106
+msgid "Base sound level unaffected by dampening, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:109
+msgid "Factor for the attenuation effect."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:121
+msgid "Linear dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:124
+msgid "Squared dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:127
+msgid "Logarithmic dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:130
+msgid "No dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:133
+msgid "Mix this audio in, even when it's out of range."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:136
+msgid "Pause this audio when it gets out of range."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:139
+msgid "Disables doppler tracking."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:142
+msgid "Executes doppler tracking in idle step."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:145
+msgid "Executes doppler tracking in physics step."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:4
+msgid "Plays audio with random pitch shifting."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:7
+msgid "Randomly varies pitch on each start."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:15
+msgid "The current [AudioStream]."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:18
+msgid "The intensity of random pitch variation."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:4
+msgid "Stores audio data loaded from WAV files."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:7
+msgid ""
+"AudioStreamSample stores sound samples loaded from WAV files. To play the "
+"stored sound, use an [AudioStreamPlayer] (for non-positional audio) or "
+"[AudioStreamPlayer2D]/[AudioStreamPlayer3D] (for positional audio). The "
+"sound can be looped.\n"
+"This class can also be used to store dynamically-generated PCM audio data."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:19
+msgid ""
+"Saves the AudioStreamSample as a WAV file to [code]path[/code]. Samples with "
+"IMA ADPCM format can't be saved.\n"
+"[b]Note:[/b] A [code].wav[/code] extension is automatically appended to "
+"[code]path[/code] if it is missing."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:26
+msgid ""
+"Contains the audio data in bytes.\n"
+"[b]Note:[/b] This property expects signed PCM8 data. To convert unsigned "
+"PCM8 to signed PCM8, subtract 128 from each byte."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:30
+msgid "Audio format. See [enum Format] constants for values."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:33
+msgid "Loop start in bytes."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:36
+msgid "Loop end in bytes."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:39
+msgid "Loop mode. See [enum LoopMode] constants for values."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:42
+msgid "The sample rate for mixing this audio."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:45
+msgid "If [code]true[/code], audio is stereo."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:50
+msgid "8-bit audio codec."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:53
+msgid "16-bit audio codec."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:56
+msgid "Audio is compressed using IMA ADPCM."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:59
+msgid "Audio does not loop."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:62
+msgid ""
+"Audio loops the data between [member loop_begin] and [member loop_end] "
+"playing forward only."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:65
+msgid ""
+"Audio loops the data between [member loop_begin] and [member loop_end] "
+"playing back and forth."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:68
+msgid ""
+"Audio loops the data between [member loop_begin] and [member loop_end] "
+"playing backward only."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:4
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:15
+msgid "Buffer mode. See [enum CopyMode] constants."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:18
+msgid ""
+"The area covered by the BackBufferCopy. Only used if [member copy_mode] is "
+"[constant COPY_MODE_RECT]."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:23
+msgid ""
+"Disables the buffering mode. This means the BackBufferCopy node will "
+"directly use the portion of screen it covers."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:26
+msgid "BackBufferCopy buffers a rectangular region."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:29
+msgid "BackBufferCopy buffers the entire screen."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:4
+msgid "Base class for different kinds of buttons."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:7
+msgid ""
+"BaseButton is the abstract base class for buttons, so it shouldn't be used "
+"directly (it doesn't display anything). Other types of buttons inherit from "
+"it."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:16
+msgid "Called when the button is pressed."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:25
+msgid ""
+"Called when the button is toggled (only if [member toggle_mode] is active)."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:32
+msgid ""
+"Returns the visual state used to draw the button. This is useful mainly when "
+"implementing your own draw code by either overriding _draw() or connecting "
+"to \"draw\" signal. The visual state of the button is defined by the [enum "
+"DrawMode] enum."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:39
+msgid ""
+"Returns [code]true[/code] if the mouse has entered the button and has not "
+"left it yet."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:45
+msgid ""
+"Determines when the button is considered clicked, one of the [enum "
+"ActionMode] constants."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:48
+msgid ""
+"Binary mask to choose which mouse buttons this button will respond to.\n"
+"To allow both left-click and right-click, use [code]BUTTON_MASK_LEFT | "
+"BUTTON_MASK_RIGHT[/code]."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:52
+msgid ""
+"If [code]true[/code], the button is in disabled state and can't be clicked "
+"or toggled."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:55
+msgid ""
+"Focus access mode to use when switching between enabled/disabled (see "
+"[member Control.focus_mode] and [member disabled])."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:59
+msgid "[ButtonGroup] associated to the button."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:62
+msgid ""
+"If [code]true[/code], the button stays pressed when moving the cursor "
+"outside the button while pressing it."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:65
+msgid ""
+"If [code]true[/code], the button's state is pressed. Means the button is "
+"pressed down or toggled (if [member toggle_mode] is active)."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:68
+msgid "[ShortCut] associated to the button."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:71
+msgid ""
+"If [code]true[/code], the button will add information about its shortcut in "
+"the tooltip."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:74
+msgid ""
+"If [code]true[/code], the button is in toggle mode. Makes the button flip "
+"state between pressed and unpressed each time its area is clicked."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:80
+msgid "Emitted when the button starts being held down."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:85
+msgid "Emitted when the button stops being held down."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:90
+msgid ""
+"Emitted when the button is toggled or pressed. This is on [signal "
+"button_down] if [member action_mode] is [constant ACTION_MODE_BUTTON_PRESS] "
+"and on [signal button_up] otherwise."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:97
+msgid ""
+"Emitted when the button was just toggled between pressed and normal states "
+"(only if [member toggle_mode] is active). The new state is contained in the "
+"[code]button_pressed[/code] argument."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:103
+msgid ""
+"The normal state (i.e. not pressed, not hovered, not toggled and enabled) of "
+"buttons."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:106
+msgid "The state of buttons are pressed."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:109
+msgid "The state of buttons are hovered."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:112
+msgid "The state of buttons are disabled."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:115
+msgid "The state of buttons are both hovered and pressed."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:118
+msgid "Require just a press to consider the button clicked."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:121
+msgid ""
+"Require a press and a subsequent release before considering the button "
+"clicked."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:4
+msgid "Default 3D rendering material."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:7
+msgid ""
+"This provides a default material with a wide variety of rendering features "
+"and properties without the need to write shader code. See the tutorial below "
+"for details."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/spatial_material.html"
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:19
+msgid "Returns [code]true[/code], if the specified [enum Feature] is enabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:28
+msgid ""
+"Returns [code]true[/code], if the specified flag is enabled. See [enum "
+"Flags] enumerator for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:37
+msgid ""
+"Returns the [Texture] associated with the specified [enum TextureParam]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:48
+msgid ""
+"If [code]true[/code], enables the specified [enum Feature]. Many features "
+"that are available in [BaseMaterial3D]s need to be enabled before use. This "
+"way the cost for using the feature is only incurred when specified. Features "
+"can also be enabled by setting the corresponding member to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:59
+msgid ""
+"If [code]true[/code], enables the specified flag. Flags are optional "
+"behavior that can be turned on and off. Only one flag can be enabled at a "
+"time with this function, the flag enumerators cannot be bit-masked together "
+"to enable or disable multiple flags at once. Flags can also be enabled by "
+"setting the corresponding member to [code]true[/code]. See [enum Flags] "
+"enumerator for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:70
+msgid ""
+"Sets the texture for the slot specified by [code]param[/code]. See [enum "
+"TextureParam] for available slots."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:76
+msgid "The material's base color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:79
+msgid ""
+"Forces a conversion of the [member albedo_texture] from sRGB space to linear "
+"space."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:82
+msgid ""
+"Texture to multiply by [member albedo_color]. Used for basic texturing of "
+"objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:85
+msgid "Threshold at which the alpha scissor will discard values."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:88
+msgid "The strength of the anisotropy effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:91
+msgid ""
+"If [code]true[/code], anisotropy is enabled. Changes the shape of the "
+"specular blob and aligns it to tangent space. Mesh tangents are needed for "
+"this to work. If the mesh does not contain tangents the anisotropy effect "
+"will appear broken."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:94
+msgid "Texture that offsets the tangent map for anisotropy calculations."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:97
+msgid ""
+"If [code]true[/code], ambient occlusion is enabled. Ambient occlusion "
+"darkens areas based on the [member ao_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:100
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:103
+msgid ""
+"If [code]true[/code], use [code]UV2[/code] coordinates to look up from the "
+"[member ao_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:106
+msgid ""
+"Texture that defines the amount of ambient occlusion for a given point on "
+"the object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:109 doc/classes/BaseMaterial3D.xml:275
+#: doc/classes/BaseMaterial3D.xml:296
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:112
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:115
+msgid "Controls how the object faces the camera. See [enum BillboardMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:118
+msgid ""
+"The material's blend mode.\n"
+"[b]Note:[/b] Values other than [code]Mix[/code] force the object into the "
+"transparent pipeline. See [enum BlendMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:122
+msgid ""
+"Sets the strength of the clearcoat effect. Setting to [code]0[/code] looks "
+"the same as disabling the clearcoat effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:125
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:128
+msgid ""
+"Sets the roughness of the clearcoat pass. A higher value results in a "
+"smoother clearcoat while a lower value results in a rougher clearcoat."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:131
+msgid ""
+"Texture that defines the strength of the clearcoat effect and the glossiness "
+"of the clearcoat. Strength is specified in the red channel while glossiness "
+"is specified in the green channel."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:134
+msgid ""
+"Which side of the object is not drawn when backfaces are rendered. See [enum "
+"CullMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:137
+msgid ""
+"Determines when depth rendering takes place. See [enum DepthDrawMode]. See "
+"also [member transparency]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:140
+msgid "Texture that specifies the color of the detail overlay."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:143
+msgid ""
+"Specifies how the [member detail_albedo] should blend with the current "
+"[code]ALBEDO[/code]. See [enum BlendMode] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:146
+msgid ""
+"If [code]true[/code], enables the detail overlay. Detail is a second texture "
+"that gets mixed over the surface of the object based on [member "
+"detail_mask]. This can be used to add variation to objects, or to blend "
+"between two different albedo/normal textures."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:149
+msgid ""
+"Texture used to specify how the detail textures get blended with the base "
+"textures."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:152
+msgid "Texture that specifies the per-pixel normal of the detail overlay."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:155
+msgid ""
+"Specifies whether to use [code]UV[/code] or [code]UV2[/code] for the detail "
+"layer. See [enum DetailUV] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:158
+msgid ""
+"The algorithm used for diffuse light scattering. See [enum DiffuseMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:161
+msgid "If [code]true[/code], the object receives no ambient light."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:164
+msgid ""
+"If [code]true[/code], the object receives no shadow that would otherwise be "
+"cast onto it."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:167
+msgid "Distance at which the object fades fully and is no longer visible."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:170
+msgid ""
+"Distance at which the object starts to fade. If the object is less than this "
+"distance away it will appear normal."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:173
+msgid ""
+"Specifies which type of fade to use. Can be any of the [enum "
+"DistanceFadeMode]s."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:176
+msgid "The emitted light's color. See [member emission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:179
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:182
+msgid "The emitted light's strength. See [member emission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:185
+msgid "Use [code]UV2[/code] to read from the [member emission_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:188
+msgid ""
+"Sets how [member emission] interacts with [member emission_texture]. Can "
+"either add or multiply. See [enum EmissionOperator] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:191
+msgid "Texture that specifies how much surface emits light at a given point."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:194
+msgid ""
+"If [code]true[/code], the object is rendered at the same size regardless of "
+"distance."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:197
+msgid ""
+"If [code]true[/code], enables the vertex grow setting. See [member "
+"grow_amount]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:200
+msgid "Grows object vertices in the direction of their normals."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:221
+msgid ""
+"A high value makes the material appear more like a metal. Non-metals use "
+"their albedo as the diffuse color and add diffuse to the specular "
+"reflection. With non-metals, the reflection appears on top of the albedo "
+"color. Metals use their albedo as a multiplier to the specular reflection "
+"and set the diffuse color to black resulting in a tinted reflection. "
+"Materials work better when fully metal or fully non-metal, values between "
+"[code]0[/code] and [code]1[/code] should only be used for blending between "
+"metal and non-metal sections. To alter the amount of reflection use [member "
+"roughness]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:224
+msgid ""
+"Sets the size of the specular lobe. The specular lobe is the bright spot "
+"that is reflected from light sources.\n"
+"[b]Note:[/b] unlike [member metallic], this is not energy-conserving, so it "
+"should be left at [code]0.5[/code] in most cases. See also [member "
+"roughness]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:228
+msgid ""
+"Texture used to specify metallic for an object. This is multiplied by "
+"[member metallic]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:231
+msgid ""
+"Specifies the channel of the [member metallic_texture] in which the metallic "
+"information is stored. This is useful when you store the information for "
+"multiple effects in a single texture. For example if you stored metallic in "
+"the red channel, roughness in the blue, and ambient occlusion in the green "
+"you could reduce the number of textures you use."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:234
+msgid ""
+"If [code]true[/code], depth testing is disabled and the object will be drawn "
+"in render order."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:237
+msgid "If [code]true[/code], normal mapping is enabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:240
+msgid "The strength of the normal map's effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:243
+msgid ""
+"Texture used to specify the normal at a given pixel. The "
+"[code]normal_texture[/code] only uses the red and green channels. The normal "
+"read from [code]normal_texture[/code] is oriented around the surface normal "
+"provided by the [Mesh]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:248
+msgid ""
+"The number of horizontal frames in the particle sprite sheet. Only enabled "
+"when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:251
+msgid ""
+"If [code]true[/code], particle animations are looped. Only enabled when "
+"using [constant BILLBOARD_PARTICLES]. See [member billboard_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:254
+msgid ""
+"The number of vertical frames in the particle sprite sheet. Only enabled "
+"when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:257
+msgid "The point size in pixels. See [member use_point_size]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:260
+msgid ""
+"Distance over which the fade effect takes place. The larger the distance the "
+"longer it takes for an object to fade."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:263
+msgid ""
+"If [code]true[/code], the proximity fade effect is enabled. The proximity "
+"fade effect fades out each pixel based on its distance to another object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:266
+msgid ""
+"If [code]true[/code], the refraction effect is enabled. Distorts "
+"transparency based on light from behind the object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:269
+msgid "The strength of the refraction effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:272
+msgid ""
+"Texture that controls the strength of the refraction per-pixel. Multiplied "
+"by [member refraction_scale]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:278
+msgid "Sets the strength of the rim lighting effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:281
+msgid ""
+"If [code]true[/code], rim effect is enabled. Rim lighting increases the "
+"brightness at glancing angles on an object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:284
+msgid ""
+"Texture used to set the strength of the rim lighting effect per-pixel. "
+"Multiplied by [member rim]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:287
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:290
+msgid ""
+"Surface reflection. A value of [code]0[/code] represents a perfect mirror "
+"while a value of [code]1[/code] completely blurs the reflection. See also "
+"[member metallic]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:293
+msgid ""
+"Texture used to control the roughness per-pixel. Multiplied by [member "
+"roughness]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:301
+msgid ""
+"If [code]true[/code], enables the \"shadow to opacity\" render mode where "
+"lighting modifies the alpha so shadowed areas are opaque and non-shadowed "
+"areas are transparent. Useful for overlaying shadows onto a camera feed in "
+"AR."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:304
+msgid "The method for rendering the specular blob. See [enum SpecularMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:307
+msgid ""
+"If [code]true[/code], subsurface scattering is enabled. Emulates light that "
+"penetrates an object's surface, is scattered, and then emerges."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:312
+msgid "The strength of the subsurface scattering effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:315
+msgid ""
+"Texture used to control the subsurface scattering strength. Stored in the "
+"red texture channel. Multiplied by [member subsurf_scatter_strength]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:318
+msgid "Filter flags for the texture. See [enum TextureFilter] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:321
+msgid "Repeat flags for the texture. See [enum TextureFilter] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:324
+msgid ""
+"The color used by the transmission effect. Represents the light passing "
+"through an object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:327
+msgid "If [code]true[/code], the transmission effect is enabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:330
+msgid ""
+"Texture used to control the transmission effect per-pixel. Added to [member "
+"transmission]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:333
+msgid ""
+"If [code]true[/code], transparency is enabled on the body. See also [member "
+"blend_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:336
+msgid ""
+"If [code]true[/code], render point size can be changed.\n"
+"[b]Note:[/b] this is only effective for objects whose geometry is point-"
+"based rather than triangle-based. See also [member point_size]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:340
+msgid ""
+"How much to offset the [code]UV[/code] coordinates. This amount will be "
+"added to [code]UV[/code] in the vertex function. This can be used to offset "
+"a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:343
+msgid ""
+"How much to scale the [code]UV[/code] coordinates. This is multiplied by "
+"[code]UV[/code] in the vertex function."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:346
+msgid ""
+"If [code]true[/code], instead of using [code]UV[/code] textures will use a "
+"triplanar texture lookup to determine how to apply textures. Triplanar uses "
+"the orientation of the object's surface to blend between texture "
+"coordinates. It reads from the source texture 3 times, once for each axis "
+"and then blends between the results based on how closely the pixel aligns "
+"with each axis. This is often used for natural features to get a realistic "
+"blend of materials. Because triplanar texturing requires many more texture "
+"reads per-pixel it is much slower than normal UV texturing. Additionally, "
+"because it is blending the texture between the three axes, it is unsuitable "
+"when you are trying to achieve crisp texturing."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:349 doc/classes/BaseMaterial3D.xml:364
+msgid ""
+"A lower number blends the texture more softly while a higher number blends "
+"the texture more sharply."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:352
+msgid ""
+"If [code]true[/code], triplanar mapping for [code]UV[/code] is calculated in "
+"world space rather than object local space. See also [member uv1_triplanar]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:355
+msgid ""
+"How much to offset the [code]UV2[/code] coordinates. This amount will be "
+"added to [code]UV2[/code] in the vertex function. This can be used to offset "
+"a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:358
+msgid ""
+"How much to scale the [code]UV2[/code] coordinates. This is multiplied by "
+"[code]UV2[/code] in the vertex function."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:361
+msgid ""
+"If [code]true[/code], instead of using [code]UV2[/code] textures will use a "
+"triplanar texture lookup to determine how to apply textures. Triplanar uses "
+"the orientation of the object's surface to blend between texture "
+"coordinates. It reads from the source texture 3 times, once for each axis "
+"and then blends between the results based on how closely the pixel aligns "
+"with each axis. This is often used for natural features to get a realistic "
+"blend of materials. Because triplanar texturing requires many more texture "
+"reads per-pixel it is much slower than normal UV texturing. Additionally, "
+"because it is blending the texture between the three axes, it is unsuitable "
+"when you are trying to achieve crisp texturing."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:367
+msgid ""
+"If [code]true[/code], triplanar mapping for [code]UV2[/code] is calculated "
+"in world space rather than object local space. See also [member "
+"uv2_triplanar]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:370
+msgid ""
+"If [code]true[/code], the model's vertex colors are processed as sRGB mode."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:373
+msgid "If [code]true[/code], the vertex color is used as albedo color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:378
+msgid "Texture specifying per-pixel color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:381
+msgid "Texture specifying per-pixel metallic value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:384
+msgid "Texture specifying per-pixel roughness value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:387
+msgid "Texture specifying per-pixel emission color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:390
+msgid "Texture specifying per-pixel normal vector."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:393
+msgid "Texture specifying per-pixel rim value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:396
+msgid "Texture specifying per-pixel clearcoat value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:399
+msgid ""
+"Texture specifying per-pixel flowmap direction for use with [member "
+"anisotropy]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:402
+msgid "Texture specifying per-pixel ambient occlusion value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:405
+msgid "Texture specifying per-pixel height."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:408
+msgid "Texture specifying per-pixel subsurface scattering."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:411
+msgid "Texture specifying per-pixel transmission color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:414
+msgid "Texture specifying per-pixel refraction strength."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:417
+msgid "Texture specifying per-pixel detail mask blending value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:420
+msgid "Texture specifying per-pixel detail color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:423
+msgid "Texture specifying per-pixel detail normal."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:428
+msgid "Represents the size of the [enum TextureParam] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:431
+msgid ""
+"The texture filter reads from the nearest pixel only. The simplest and "
+"fastest method of filtering, but the texture will look pixelized."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:434 doc/classes/CanvasItem.xml:665
+msgid ""
+"The texture filter blends between the nearest four pixels. Use this for most "
+"cases where you want to avoid a pixelated style."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:445 doc/classes/CanvasItem.xml:676
+msgid "Represents the size of the [enum TextureFilter] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:448
+msgid "Use [code]UV[/code] with the detail texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:451
+msgid "Use [code]UV2[/code] with the detail texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:454
+msgid "The material will not use transparency."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:457
+msgid "The material will use the texture's alpha values for transparency."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:464
+msgid "Represents the size of the [enum Transparency] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:467
+msgid "The object will not receive shadows."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:470
+msgid ""
+"The object will be shaded per pixel. Useful for realistic shading effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:473
+msgid ""
+"The object will be shaded per vertex. Useful when you want cheaper shaders "
+"and do not care about visual quality."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:476
+msgid "Represents the size of the [enum ShadingMode] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:479
+msgid "Constant for setting [member emission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:482
+msgid "Constant for setting [member normal_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:485
+msgid "Constant for setting [member rim_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:488
+msgid "Constant for setting [member clearcoat_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:491
+msgid "Constant for setting [member anisotropy_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:494
+msgid "Constant for setting [member ao_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:499
+msgid "Constant for setting [member subsurf_scatter_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:502
+msgid "Constant for setting [member transmission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:505
+msgid "Constant for setting [member refraction_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:508
+msgid "Constant for setting [member detail_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:511 doc/classes/EditorFeatureProfile.xml:148
+msgid "Represents the size of the [enum Feature] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:514
+msgid ""
+"Default blend mode. The color of the object is blended over the background "
+"based on the object's alpha value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:517
+msgid "The color of the object is added to the background."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:520
+msgid "The color of the object is subtracted from the background."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:523
+msgid "The color of the object is multiplied by the background."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:526
+msgid "Default depth draw mode. Depth is drawn only for opaque objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:529
+msgid "Depth draw is calculated for both opaque and transparent objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:532
+msgid "No depth draw."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:535
+msgid "Default cull mode. The back of the object is culled when not visible."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:538
+msgid "The front of the object is culled when not visible."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:541
+msgid "No culling is performed."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:544
+msgid ""
+"Disables the depth test, so this object is drawn on top of all others. "
+"However, objects drawn after it in the draw order may cover it."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:547
+msgid "Set [code]ALBEDO[/code] to the per-vertex color specified in the mesh."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:550
+msgid ""
+"Vertex color is in sRGB space and needs to be converted to linear. Only "
+"applies in the Vulkan renderer."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:553
+msgid ""
+"Uses point size to alter the size of primitive points. Also changes the "
+"albedo texture lookup to use [code]POINT_COORD[/code] instead of [code]UV[/"
+"code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:556
+msgid ""
+"Object is scaled by depth so that it always appears the same size on screen."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:559
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:562 doc/classes/BaseMaterial3D.xml:568
+msgid ""
+"Use triplanar texture lookup for all texture lookups that would normally use "
+"[code]UV[/code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:565 doc/classes/BaseMaterial3D.xml:571
+msgid ""
+"Use triplanar texture lookup for all texture lookups that would normally use "
+"[code]UV2[/code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:574
+msgid ""
+"Use [code]UV2[/code] coordinates to look up from the [member ao_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:577
+msgid ""
+"Use [code]UV2[/code] coordinates to look up from the [member "
+"emission_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:580
+msgid "Forces the shader to convert albedo from sRGB space to linear space."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:583
+msgid "Disables receiving shadows from other objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:586
+msgid "Disables receiving ambient light."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:589
+msgid "Enables the shadow to opacity feature."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:594
+msgid ""
+"Invert values read from a depth texture to convert them to height values "
+"(heightmap)."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:599 doc/classes/CPUParticles2D.xml:355
+#: doc/classes/CPUParticles3D.xml:364 doc/classes/GeometryInstance3D.xml:100
+#: doc/classes/ParticlesMaterial.xml:315
+msgid "Represents the size of the [enum Flags] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:602
+msgid "Default diffuse scattering algorithm."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:605
+msgid "Diffuse scattering ignores roughness."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:608
+msgid "Extends Lambert to cover more than 90 degrees when roughness increases."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:611
+msgid "Attempts to use roughness to emulate microsurfacing."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:614
+msgid "Uses a hard cut for lighting, with smoothing affected by roughness."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:617
+msgid "Default specular blob."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:620 doc/classes/BaseMaterial3D.xml:623
+msgid "Older specular algorithm, included for compatibility."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:626
+msgid "Toon blob which changes size based on roughness."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:629
+msgid "No specular blob."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:632
+msgid "Billboard mode is disabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:635
+msgid "The object's Z axis will always face the camera."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:638
+msgid "The object's X axis will always face the camera."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:641
+msgid ""
+"Used for particle systems when assigned to [GPUParticles3D] and "
+"[CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties.\n"
+"The [member ParticlesMaterial.anim_speed] or [member CPUParticles3D."
+"anim_speed] should also be set to a positive value for the animation to play."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:645
+msgid "Used to read from the red channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:648
+msgid "Used to read from the green channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:651
+msgid "Used to read from the blue channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:654
+msgid "Used to read from the alpha channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:657
+msgid "Currently unused."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:660
+msgid "Adds the emission color to the color from the emission texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:663
+msgid "Multiplies the emission color by the color from the emission texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:666
+msgid "Do not use distance fade."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:669
+msgid ""
+"Smoothly fades the object out based on each pixel's distance from the camera "
+"using the alpha channel."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:672
+msgid ""
+"Smoothly fades the object out based on each pixel's distance from the camera "
+"using a dither approach. Dithering discards pixels based on a set pattern to "
+"smoothly fade without enabling transparency. On certain hardware this can be "
+"faster than [constant DISTANCE_FADE_PIXEL_ALPHA]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:675
+msgid ""
+"Smoothly fades the object out based on the object's distance from the camera "
+"using a dither approach. Dithering discards pixels based on a set pattern to "
+"smoothly fade without enabling transparency. On certain hardware this can be "
+"faster than [constant DISTANCE_FADE_PIXEL_ALPHA]."
+msgstr ""
+
+#: doc/classes/Basis.xml:4
+msgid "3×3 matrix datatype."
+msgstr ""
+
+#: doc/classes/Basis.xml:7
+msgid ""
+"3×3 matrix used for 3D rotation and scale. Contains 3 vector fields X, Y and "
+"Z as its columns, which can be interpreted as the local basis vectors of a "
+"transformation. Can also be accessed as array of 3D vectors. These vectors "
+"are orthogonal to each other, but are not necessarily normalized (due to "
+"scaling). Almost always used as an orthogonal basis for a [Transform].\n"
+"For such use, it is composed of a scaling and a rotation matrix, in that "
+"order (M = R.S)."
+msgstr ""
+
+#: doc/classes/Basis.xml:11 doc/classes/Transform.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html"
+msgstr ""
+
+#: doc/classes/Basis.xml:20
+msgid "Create a rotation matrix from the given quaternion."
+msgstr ""
+
+#: doc/classes/Basis.xml:29
+msgid ""
+"Create a rotation matrix (in the YXZ convention: first Z, then X, and Y "
+"last) from the specified Euler angles, given in the vector format as (X "
+"angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Basis.xml:40
+msgid ""
+"Create a rotation matrix which rotates around the given axis by the "
+"specified angle, in radians. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:53
+msgid "Create a matrix from 3 axis vectors."
+msgstr ""
+
+#: doc/classes/Basis.xml:60
+msgid "Returns the determinant of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:67
+msgid ""
+"Returns the basis's rotation in the form of Euler angles (in the YXZ "
+"convention: first Z, then X, and Y last). The returned vector contains the "
+"rotation angles in the format (X angle, Y angle, Z angle). See [method "
+"get_rotation_quat] if you need a quaternion instead."
+msgstr ""
+
+#: doc/classes/Basis.xml:74
+msgid ""
+"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 grid map editor. For "
+"further details, refer to the Godot source code."
+msgstr ""
+
+#: doc/classes/Basis.xml:81
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Basis.xml:88
+msgid ""
+"Assuming that the matrix is the combination of a rotation and scaling, "
+"return the absolute value of scaling factors along each axis."
+msgstr ""
+
+#: doc/classes/Basis.xml:95 doc/classes/Transform2D.xml:49
+msgid "Returns the inverse of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:106
+msgid ""
+"Returns [code]true[/code] if this basis and [code]b[/code] are approximately "
+"equal, by calling [code]is_equal_approx[/code] on each component."
+msgstr ""
+
+#: doc/classes/Basis.xml:113
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Basis.xml:124
+msgid ""
+"Introduce an additional rotation around the given axis by phi (radians). The "
+"axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:133
+msgid ""
+"Introduce an additional scaling specified by the given 3D scaling factor."
+msgstr ""
+
+#: doc/classes/Basis.xml:144
+msgid ""
+"Assuming that the matrix is a proper rotation matrix, slerp performs a "
+"spherical-linear interpolation with another rotation matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:153
+msgid "Transposed dot product with the X axis of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:162
+msgid "Transposed dot product with the Y axis of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:171
+msgid "Transposed dot product with the Z axis of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:178
+msgid "Returns the transposed version of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:187
+msgid "Returns a vector transformed (multiplied) by the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:196
+msgid ""
+"Returns a vector transformed (multiplied) by the transposed matrix.\n"
+"[b]Note:[/b] This results in a multiplication by the inverse of the matrix "
+"only if it represents a rotation-reflection."
+msgstr ""
+
+#: doc/classes/Basis.xml:203
+msgid "The basis matrix's X vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:206
+msgid "The basis matrix's Y vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:209
+msgid "The basis matrix's Z vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:214
+msgid ""
+"The identity basis. This is identical to calling [code]Basis()[/code] "
+"without any parameters. This constant can be used to make your code clearer."
+msgstr ""
+
+#: doc/classes/Basis.xml:217
+msgid ""
+"The basis that will flip something along the X axis when used in a "
+"transformation."
+msgstr ""
+
+#: doc/classes/Basis.xml:220
+msgid ""
+"The basis that will flip something along the Y axis when used in a "
+"transformation."
+msgstr ""
+
+#: doc/classes/Basis.xml:223
+msgid ""
+"The basis that will flip something along the Z axis when used in a "
+"transformation."
+msgstr ""
+
+#: doc/classes/BitMap.xml:4
+msgid "Boolean matrix."
+msgstr ""
+
+#: doc/classes/BitMap.xml:7
+msgid ""
+"A two-dimensional array of boolean values, can be used to efficiently store "
+"a binary matrix (every matrix element takes only one bit) and query the "
+"values using natural cartesian coordinates."
+msgstr ""
+
+#: doc/classes/BitMap.xml:18
+msgid ""
+"Creates a bitmap with the specified size, filled with [code]false[/code]."
+msgstr ""
+
+#: doc/classes/BitMap.xml:29
+msgid ""
+"Creates a bitmap that matches the given image dimensions, every element of "
+"the bitmap is set to [code]false[/code] if the alpha value of the image at "
+"that position is equal to [code]threshold[/code] or less, and [code]true[/"
+"code] in other case."
+msgstr ""
+
+#: doc/classes/BitMap.xml:38
+msgid "Returns bitmap's value at the specified position."
+msgstr ""
+
+#: doc/classes/BitMap.xml:45
+msgid "Returns bitmap's dimensions."
+msgstr ""
+
+#: doc/classes/BitMap.xml:52
+msgid ""
+"Returns the amount of bitmap elements that are set to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/BitMap.xml:83
+msgid ""
+"Sets the bitmap's element at the specified position, to the specified value."
+msgstr ""
+
+#: doc/classes/BitMap.xml:94
+msgid "Sets a rectangular portion of the bitmap to the specified value."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:4
+msgid ""
+"Renders text using fonts under the [url=https://www.angelcode.com/products/"
+"bmfont/]BMFont[/url] format.\n"
+"Handles files with the [code].fnt[/code] extension."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:8
+msgid ""
+"Renders text using [code]*.fnt[/code] fonts containing texture atlases. "
+"Supports distance fields. For using vector font files like TTF directly, see "
+"[DynamicFont]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:27
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:40
+msgid ""
+"Adds a kerning pair to the [BitmapFont] as a difference. Kerning pairs are "
+"special cases where a typeface advance is determined by the next character."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:49
+msgid "Adds a texture to the [BitmapFont]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:56
+msgid "Clears all the font data and settings."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:65
+msgid ""
+"Creates a BitmapFont from the [code]*.fnt[/code] file at [code]path[/code]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:76
+msgid ""
+"Returns the size of a character, optionally taking kerning into account if "
+"the next character is provided."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:87
+msgid "Returns a kerning pair as a difference."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:96
+msgid "Returns the font atlas texture at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:103
+msgid "Returns the number of textures in the BitmapFont atlas."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:109
+msgid "Ascent (number of pixels above the baseline)."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:112
+msgid "If [code]true[/code], distance field hint is enabled."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:115
+msgid "The fallback font."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:118
+msgid "Total font height (ascent plus descent) in pixels."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:4
+msgid "Joint used with [Skeleton2D] to control and animate other nodes."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:7
+msgid ""
+"Use a hierarchy of [code]Bone2D[/code] bound to a [Skeleton2D] to control, "
+"and animate other [Node2D] nodes.\n"
+"You can use [code]Bone2D[/code] and [code]Skeleton2D[/code] nodes to animate "
+"2D meshes created with the Polygon 2D UV editor.\n"
+"Each bone has a [member rest] transform that you can reset to with [method "
+"apply_rest]. These rest poses are relative to the bone's parent.\n"
+"If in the editor, you can set the rest pose of an entire skeleton using a "
+"menu option, from the code, you need to iterate over the bones to set their "
+"individual rest poses."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:19
+msgid "Stores the node's current transforms in [member rest]."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:26
+msgid ""
+"Returns the node's index as part of the entire skeleton. See [Skeleton2D]."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:33
+msgid ""
+"Returns the node's [member rest] [code]Transform2D[/code] if it doesn't have "
+"a parent, or its rest pose relative to its parent."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:39
+msgid ""
+"Length of the bone's representation drawn in the editor's viewport in pixels."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:42
+msgid ""
+"Rest transform of the bone. You can reset the node's transforms to this "
+"value using [method apply_rest]."
+msgstr ""
+
+#: doc/classes/BoneAttachment3D.xml:4
+msgid "A node that will attach to a bone."
+msgstr ""
+
+#: doc/classes/BoneAttachment3D.xml:7
+msgid ""
+"This node must be the child of a [Skeleton3D] node. You can then select a "
+"bone for this node to attach to. The BoneAttachment3D node will copy the "
+"transform of the selected bone."
+msgstr ""
+
+#: doc/classes/BoneAttachment3D.xml:15
+msgid "The name of the attached bone."
+msgstr ""
+
+#: doc/classes/bool.xml:4
+msgid "Boolean built-in type."
+msgstr ""
+
+#: doc/classes/bool.xml:7
+msgid ""
+"Boolean is a built-in type. It can represent any data type that is either a "
+"true or false value. You can think of it as an switch with on or off (1 or "
+"0) setting. It's often used as part of programming logic in condition "
+"statements like [code]if[/code] statements.\n"
+"[b]Note:[/b] In a code below [code]if can_shoot[/code] is equivalent of "
+"[code]if can_shoot == true[/code]. It is good practice to follow the natural "
+"spoken language structure when possible. Use [code]if can_shoot[/code] "
+"rather than [code]if can_shoot == true[/code] and use [code]if not "
+"can_shoot[/code] rather than [code]if can_shoot == false[/code].\n"
+"[codeblock]\n"
+"var can_shoot = true\n"
+"\n"
+"func shoot():\n"
+" if can_shoot:\n"
+" # Perform shooting actions here.\n"
+"[/codeblock]\n"
+"The following code will only create a bullet if both conditions are met: "
+"action \"shoot\" is pressed and if [code]can_shoot[/code] is [code]true[/"
+"code].\n"
+"[b]Note:[/b] [code]Input.is_action_pressed(\"shoot\")[/code] is also a "
+"boolean that is [code]true[/code] when \"shoot\" is pressed and [code]false[/"
+"code] when \"shoot\" isn't pressed.\n"
+"[codeblock]\n"
+"var can_shoot = true\n"
+"\n"
+"func shoot():\n"
+" if can_shoot and Input.is_action_pressed(\"shoot\"):\n"
+" create_bullet()\n"
+"[/codeblock]\n"
+"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.\n"
+"[codeblock]\n"
+"var can_shoot = true\n"
+"onready var cool_down = $CoolDownTimer\n"
+"\n"
+"func shoot():\n"
+" if can_shoot and Input.is_action_pressed(\"shoot\"):\n"
+" create_bullet()\n"
+" can_shoot = false\n"
+" cool_down.start()\n"
+"\n"
+"func _on_CoolDownTimer_timeout():\n"
+" can_shoot = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/bool.xml:49
+msgid ""
+"Cast an [int] value to a boolean value, this method will return [code]true[/"
+"code] if called with an integer value different to 0 and [code]false[/code] "
+"in other case."
+msgstr ""
+
+#: doc/classes/bool.xml:58
+msgid ""
+"Cast a [float] value to a boolean value, this method will return [code]true[/"
+"code] if called with a floating-point value different to 0 and [code]false[/"
+"code] in other case."
+msgstr ""
+
+#: doc/classes/bool.xml:67
+msgid ""
+"Cast a [String] value to a boolean value, this method will return "
+"[code]true[/code] if called with a non-empty string and [code]false[/code] "
+"in other case. Examples: [code]bool(\"False\")[/code] returns [code]true[/"
+"code], [code]bool(\"\")[/code] returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:4
+msgid "Base class for box containers."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:7
+msgid ""
+"Arranges child [Control] nodes vertically or horizontally, and rearranges "
+"them automatically when their minimum size changes."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:18
+msgid ""
+"Adds a [Control] node to the box as a spacer. If [code]begin[/code] is "
+"[code]true[/code], it will insert the [Control] node in front of all other "
+"children."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:24
+msgid ""
+"The alignment of the container's children (must be one of [constant "
+"ALIGN_BEGIN], [constant ALIGN_CENTER], or [constant ALIGN_END])."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:29
+msgid "Aligns children with the beginning of the container."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:32
+msgid "Aligns children with the center of the container."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:35
+msgid "Aligns children with the end of the container."
+msgstr ""
+
+#: doc/classes/BoxShape3D.xml:4
+msgid "Box shape resource."
+msgstr ""
+
+#: doc/classes/BoxShape3D.xml:7
+msgid "3D box shape that can be a child of a [PhysicsBody3D] or [Area3D]."
+msgstr ""
+
+#: doc/classes/BoxShape3D.xml:15
+msgid ""
+"The box's half extents. The width, height and depth of this shape is twice "
+"the half extents."
+msgstr ""
+
+#: doc/classes/Button.xml:4
+msgid "Standard themed Button."
+msgstr ""
+
+#: doc/classes/Button.xml:7
+msgid ""
+"Button is the standard themed button. It can contain text and an icon, and "
+"will display them according to the current [Theme]."
+msgstr ""
+
+#: doc/classes/Button.xml:15
+msgid ""
+"Text alignment policy for the button's text, use one of the [enum TextAlign] "
+"constants."
+msgstr ""
+
+#: doc/classes/Button.xml:18
+msgid ""
+"When this property is enabled, text that is too large to fit the button is "
+"clipped, when disabled the Button will always be wide enough to hold the "
+"text."
+msgstr ""
+
+#: doc/classes/Button.xml:21
+msgid ""
+"When enabled, the button's icon will expand/shrink to fit the button's size "
+"while keeping its aspect."
+msgstr ""
+
+#: doc/classes/Button.xml:24
+msgid "Flat buttons don't display decoration."
+msgstr ""
+
+#: doc/classes/Button.xml:27
+msgid ""
+"Button's icon, if text is present the icon will be placed before the text."
+msgstr ""
+
+#: doc/classes/Button.xml:30 doc/classes/LinkButton.xml:18
+msgid "The button's text that will be displayed inside the button's area."
+msgstr ""
+
+#: doc/classes/Button.xml:35
+msgid "Align the text to the left."
+msgstr ""
+
+#: doc/classes/Button.xml:38
+msgid "Align the text to the center."
+msgstr ""
+
+#: doc/classes/Button.xml:41
+msgid "Align the text to the right."
+msgstr ""
+
+#: doc/classes/Button.xml:46
+msgid "[StyleBox] used when the [Button] is disabled."
+msgstr ""
+
+#: doc/classes/Button.xml:49
+msgid ""
+"[StyleBox] used when the [Button] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/Button.xml:52
+msgid "[Font] of the [Button]'s text."
+msgstr ""
+
+#: doc/classes/Button.xml:55
+msgid "Default text [Color] of the [Button]."
+msgstr ""
+
+#: doc/classes/Button.xml:58
+msgid "Text [Color] used when the [Button] is disabled."
+msgstr ""
+
+#: doc/classes/Button.xml:61
+msgid "Text [Color] used when the [Button] is being hovered."
+msgstr ""
+
+#: doc/classes/Button.xml:64
+msgid "Text [Color] used when the [Button] is being pressed."
+msgstr ""
+
+#: doc/classes/Button.xml:67
+msgid "[StyleBox] used when the [Button] is being hovered."
+msgstr ""
+
+#: doc/classes/Button.xml:70
+msgid "The horizontal space between [Button]'s icon and text."
+msgstr ""
+
+#: doc/classes/Button.xml:73
+msgid "Default [StyleBox] for the [Button]."
+msgstr ""
+
+#: doc/classes/Button.xml:76
+msgid "[StyleBox] used when the [Button] is being pressed."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:4
+msgid "Group of Buttons."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:7
+msgid ""
+"Group of [Button]. All direct and indirect children buttons become radios. "
+"Only one allows being pressed.\n"
+"[member BaseButton.toggle_mode] should be [code]true[/code]."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:17
+msgid ""
+"Returns an [Array] of [Button]s who have this as their [ButtonGroup] (see "
+"[member BaseButton.group])."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:24
+msgid "Returns the current pressed button."
+msgstr ""
+
+#: doc/classes/Callable.xml:4
+msgid "An object representing a method in a certain object that can be called."
+msgstr ""
+
+#: doc/classes/Callable.xml:7
+msgid ""
+"[Callable] is a first class object which can be held in variables and passed "
+"to functions. It represents a given method in an [Object], and is typically "
+"used for signal callbacks.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var callable = Callable(self, \"print_args\")\n"
+"func print_args(arg1, arg2, arg3 = \"\"):\n"
+" prints(arg1, arg2, arg3)\n"
+"func test():\n"
+" callable.call(\"hello\", \"world\") # Prints \"hello world\".\n"
+" callable.call(Vector2.UP, 42, callable) # Prints \"(0, -1) 42 Node(Node."
+"gd)::print_args\".\n"
+" callable.call(\"invalid\") # Invalid call, should have at least 2 "
+"arguments.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Callable.xml:30
+msgid ""
+"Creates a new [Callable] for the method called [code]method_name[/code] in "
+"the specified [code]object[/code]."
+msgstr ""
+
+#: doc/classes/Callable.xml:37
+msgid ""
+"Calls the method represented by this [Callable]. Arguments can be passed and "
+"should match the method's signature."
+msgstr ""
+
+#: doc/classes/Callable.xml:44
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Callable.xml:51
+msgid "Returns the name of the method represented by this [Callable]."
+msgstr ""
+
+#: doc/classes/Callable.xml:58
+msgid "Returns the object on which this [Callable] is called."
+msgstr ""
+
+#: doc/classes/Callable.xml:65
+msgid ""
+"Returns the ID of this [Callable]'s object (see [method Object."
+"get_instance_id])."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:4
+msgid "Camera node for 2D scenes."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:7
+msgid ""
+"Camera node for 2D scenes. It forces the screen (current layer) to scroll "
+"following this node. This makes it easier (and faster) to program scrollable "
+"scenes than manually changing the position of [CanvasItem]-based nodes.\n"
+"This node is intended to be a simple helper to get things going quickly and "
+"it may happen that more functionality is desired to change how the camera "
+"works. To make your own custom camera node, simply inherit from [Node2D] and "
+"change the transform of the canvas by calling get_viewport()."
+"set_canvas_transform(m) in [Viewport]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:17
+msgid "Aligns the camera to the tracked node."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:24
+msgid ""
+"Removes any [Camera2D] from the ancestor [Viewport]'s internal currently-"
+"assigned camera."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:31
+msgid "Forces the camera to update scroll immediately."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:38
+msgid "Returns the camera position."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:45
+msgid ""
+"Returns the location of the [Camera2D]'s screen-center, relative to the "
+"origin."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:54
+msgid ""
+"Returns the specified margin. See also [member drag_margin_bottom], [member "
+"drag_margin_top], [member drag_margin_left], and [member drag_margin_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:63
+msgid ""
+"Returns the specified camera limit. See also [member limit_bottom], [member "
+"limit_top], [member limit_left], and [member limit_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:70
+msgid ""
+"Make this the current 2D camera for the scene (viewport and layer), in case "
+"there are many cameras in the scene."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:77
+msgid ""
+"Sets the camera's position immediately to its current smoothing "
+"destination.\n"
+"This has no effect if smoothing is disabled."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:89
+msgid ""
+"Sets the specified margin. See also [member drag_margin_bottom], [member "
+"drag_margin_top], [member drag_margin_left], and [member drag_margin_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:100
+msgid ""
+"Sets the specified camera limit. See also [member limit_bottom], [member "
+"limit_top], [member limit_left], and [member limit_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:106
+msgid "The Camera2D's anchor point. See [enum AnchorMode] constants."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:109
+msgid ""
+"If [code]true[/code], the camera is the active camera for the current scene. "
+"Only one camera can be current, so setting a different camera [code]current[/"
+"code] will disable this one."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:112
+msgid ""
+"The custom [Viewport] node attached to the [Camera2D]. If [code]null[/code] "
+"or not a [Viewport], uses the default viewport instead."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:115
+msgid ""
+"Bottom margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:118
+msgid ""
+"If [code]true[/code], the camera only moves when reaching the horizontal "
+"drag margins. If [code]false[/code], the camera moves horizontally "
+"regardless of margins."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:121
+msgid ""
+"Left margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:124
+msgid ""
+"Right margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:127
+msgid ""
+"Top margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:130
+msgid ""
+"If [code]true[/code], the camera only moves when reaching the vertical drag "
+"margins. If [code]false[/code], the camera moves vertically regardless of "
+"margins."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:133
+msgid ""
+"If [code]true[/code], draws the camera's drag margin rectangle in the editor."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:136
+msgid ""
+"If [code]true[/code], draws the camera's limits rectangle in the editor."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:139
+msgid ""
+"If [code]true[/code], draws the camera's screen rectangle in the editor."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:142
+msgid ""
+"Bottom scroll limit in pixels. The camera stops moving when reaching this "
+"value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:145
+msgid ""
+"Left scroll limit in pixels. The camera stops moving when reaching this "
+"value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:148
+msgid ""
+"Right scroll limit in pixels. The camera stops moving when reaching this "
+"value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:151
+msgid ""
+"If [code]true[/code], the camera smoothly stops when reaches its limits."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:154
+msgid ""
+"Top scroll limit in pixels. The camera stops moving when reaching this value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:157
+msgid ""
+"The camera's offset, useful for looking around or camera shake animations."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:160
+msgid ""
+"The horizontal offset of the camera, relative to the drag margins.\n"
+"[b]Note:[/b] Offset H is used only to force offset relative to margins. It's "
+"not updated in any way if drag margins are enabled and can be used to set "
+"initial offset."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:164
+msgid ""
+"The vertical offset of the camera, relative to the drag margins.\n"
+"[b]Note:[/b] Used the same as [member offset_h]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:168
+msgid "The camera's process callback. See [enum Camera2DProcessMode]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:171
+msgid "If [code]true[/code], the camera rotates with the target."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:174
+msgid ""
+"If [code]true[/code], the camera smoothly moves towards the target at "
+"[member smoothing_speed]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:177
+msgid ""
+"Speed in pixels per second of the camera's smoothing effect when [member "
+"smoothing_enabled] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:180
+msgid ""
+"The camera's zoom relative to the viewport. Values larger than "
+"[code]Vector2(1, 1)[/code] zoom out and smaller values zoom in. For an "
+"example, use [code]Vector2(0.5, 0.5)[/code] for a 2× zoom-in, and "
+"[code]Vector2(4, 4)[/code] for a 4× zoom-out."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:185
+msgid ""
+"The camera's position is fixed so that the top-left corner is always at the "
+"origin."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:188
+msgid ""
+"The camera's position takes into account vertical/horizontal offsets and the "
+"screen size."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:191 doc/classes/ClippedCamera3D.xml:104
+msgid "The camera updates with the [code]_physics_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:194 doc/classes/ClippedCamera3D.xml:107
+msgid "The camera updates with the [code]_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:4
+msgid "Camera node, displays from a point of view."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:7
+msgid ""
+"[Camera3D] is a special node that displays what is visible from its current "
+"location. Cameras register themselves in the nearest [Viewport] node (when "
+"ascending the tree). Only one camera can be active per viewport. If no "
+"viewport is available ascending the tree, the camera will register in the "
+"global viewport. In other words, a camera just provides 3D display "
+"capabilities to a [Viewport], and, without one, a scene registered in that "
+"[Viewport] (or higher viewports) can't be displayed."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:18
+msgid ""
+"If this is the current camera, remove it from being current. If "
+"[code]enable_next[/code] is [code]true[/code], request to make the next "
+"camera current, if any."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:25
+msgid "Returns the camera's RID from the [RenderingServer]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:32
+msgid ""
+"Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may "
+"provide different transforms than the [Node] transform."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:41
+msgid ""
+"Returns [code]true[/code] if the given [code]layer[/code] in the [member "
+"cull_mask] is enabled, [code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:48
+msgid ""
+"Returns the camera's frustum planes in world-space units as an array of "
+"[Plane]s in the following order: near, far, left, top, right, bottom. Not to "
+"be confused with [member frustum_offset]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:57
+msgid ""
+"Returns [code]true[/code] if the given position is behind the camera.\n"
+"[b]Note:[/b] A position which returns [code]false[/code] may still be "
+"outside the camera's field of view."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:65
+msgid ""
+"Makes this camera the current camera for the [Viewport] (see class "
+"description). If the camera node is outside the scene tree, it will attempt "
+"to become current once it's added."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:74
+msgid ""
+"Returns a normal vector from the screen point location directed along the "
+"camera. Orthogonal cameras are normalized. Perspective cameras account for "
+"perspective, screen width/height, etc."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:85
+msgid ""
+"Returns the 3D point in worldspace that maps to the given 2D coordinate in "
+"the [Viewport] rectangle on a plane that is the given [code]z_depth[/code] "
+"distance into the scene away from the camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:94
+msgid ""
+"Returns a normal vector in worldspace, that is the result of projecting a "
+"point on the [Viewport] rectangle by the camera projection. This is useful "
+"for casting rays in the form of (origin, normal) for object intersection or "
+"picking."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:103
+msgid ""
+"Returns a 3D position in worldspace, that is the result of projecting a "
+"point on the [Viewport] rectangle by the camera projection. This is useful "
+"for casting rays in the form of (origin, normal) for object intersection or "
+"picking."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:114
+msgid ""
+"Enables or disables the given [code]layer[/code] in the [member cull_mask]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:129
+msgid ""
+"Sets the camera projection to frustum mode (see [constant "
+"PROJECTION_FRUSTUM]), by specifying a [code]size[/code], an [code]offset[/"
+"code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in "
+"world-space units."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:142
+msgid ""
+"Sets the camera projection to orthogonal mode (see [constant "
+"PROJECTION_ORTHOGONAL]), by specifying a [code]size[/code], and the "
+"[code]z_near[/code] and [code]z_far[/code] clip planes in world-space units. "
+"(As a hint, 2D games often use this projection, with values specified in "
+"pixels.)"
+msgstr ""
+
+#: doc/classes/Camera3D.xml:155
+msgid ""
+"Sets the camera projection to perspective mode (see [constant "
+"PROJECTION_PERSPECTIVE]), by specifying a [code]fov[/code] (field of view) "
+"angle in degrees, and the [code]z_near[/code] and [code]z_far[/code] clip "
+"planes in world-space units."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:164
+msgid ""
+"Returns the 2D coordinate in the [Viewport] rectangle that maps to the given "
+"3D point in worldspace."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:170
+msgid ""
+"The culling mask that describes which 3D render layers are rendered by this "
+"camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:173
+msgid ""
+"If [code]true[/code], the ancestor [Viewport] is currently using this camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:176
+msgid ""
+"If not [constant DOPPLER_TRACKING_DISABLED], this camera will simulate the "
+"[url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] for "
+"objects changed in particular [code]_process[/code] methods. See [enum "
+"DopplerTracking] for possible values."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:181
+msgid "The [Environment] to use for this camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:184
+msgid ""
+"The distance to the far culling boundary for this camera relative to its "
+"local Z axis."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:187
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:190
+msgid ""
+"The camera's frustum offset. This can be changed from the default to create "
+"\"tilted frustum\" effects such as [url=https://zdoom.org/wiki/Y-shearing]Y-"
+"shearing[/url]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:193
+msgid "The horizontal (X) offset of the camera viewport."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:196
+msgid ""
+"The axis to lock during [member fov]/[member size] adjustments. Can be "
+"either [constant KEEP_WIDTH] or [constant KEEP_HEIGHT]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:199
+msgid ""
+"The distance to the near culling boundary for this camera relative to its "
+"local Z axis."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:202
+msgid ""
+"The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, "
+"objects' Z distance from the camera's local space scales their perceived "
+"size."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:205
+msgid ""
+"The camera's size measured as 1/2 the width or height. Only applicable in "
+"orthogonal mode. Since [member keep_aspect] locks on axis, [code]size[/code] "
+"sets the other axis' size length."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:208
+msgid "The vertical (Y) offset of the camera viewport."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:213
+msgid ""
+"Perspective projection. Objects on the screen becomes smaller when they are "
+"far away."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:216
+msgid ""
+"Orthogonal projection, also known as orthographic projection. Objects remain "
+"the same size on the screen no matter how far away they are."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:219
+msgid ""
+"Frustum projection. This mode allows adjusting [member frustum_offset] to "
+"create \"tilted frustum\" effects."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:222
+msgid ""
+"Preserves the horizontal aspect ratio; also known as Vert- scaling. This is "
+"usually the best option for projects running in portrait mode, as taller "
+"aspect ratios will benefit from a wider vertical FOV."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:225
+msgid ""
+"Preserves the vertical aspect ratio; also known as Hor+ scaling. This is "
+"usually the best option for projects running in landscape mode, as wider "
+"aspect ratios will automatically benefit from a wider horizontal FOV."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:228
+msgid ""
+"Disables [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/"
+"url] simulation (default)."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:231
+msgid ""
+"Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/"
+"url] by tracking positions of objects that are changed in [code]_process[/"
+"code]. Changes in the relative velocity of this camera compared to those "
+"objects affect how Audio is perceived (changing the Audio's [code]pitch "
+"shift[/code])."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:234
+msgid ""
+"Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/"
+"url] by tracking positions of objects that are changed in "
+"[code]_physics_process[/code]. Changes in the relative velocity of this "
+"camera compared to those objects affect how Audio is perceived (changing the "
+"Audio's [code]pitch shift[/code])."
+msgstr ""
+
+#: doc/classes/CameraFeed.xml:4
+msgid ""
+"A camera feed gives you access to a single physical camera attached to your "
+"device."
+msgstr ""
+
+#: doc/classes/CameraFeed.xml:7
+msgid ""
+"A camera feed gives you access to a single physical camera attached to your "
+"device. When enabled, Godot will start capturing frames from the camera "
+"which can then be used.\n"
+"[b]Note:[/b] Many cameras will return YCbCr images which are split into two "
+"textures and need to be combined in a shader. Godot does this automatically "
+"for you if you set the environment to show the camera image in the "
+"background."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:4
+msgid "Server keeping track of different cameras accessible in Godot."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:7
+msgid ""
+"The [CameraServer] keeps track of different cameras accessible in Godot. "
+"These are external cameras such as webcams or the cameras on your phone.\n"
+"It is notably used to provide AR modules with a video feed from the camera."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:19
+msgid "Adds a camera feed to the camera server."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:26
+msgid "Returns an array of [CameraFeed]s."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:35
+msgid "Returns the [CameraFeed] with this id."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:42
+msgid "Returns the number of [CameraFeed]s registered."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:51
+msgid "Removes a [CameraFeed]."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:60
+msgid "Emitted when a [CameraFeed] is added (e.g. webcam is plugged in)."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:67
+msgid "Emitted when a [CameraFeed] is removed (e.g. webcam is unplugged)."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:73
+msgid "The RGBA camera image."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:76
+msgid "The YCbCr camera image."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:79
+msgid "The Y component camera image."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:82
+msgid "The CbCr component camera image."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:4
+msgid "Texture provided by a [CameraFeed]."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:7
+msgid ""
+"This texture gives access to the camera texture provided by a [CameraFeed].\n"
+"[b]Note:[/b] Many cameras supply YCbCr images which need to be converted in "
+"a shader."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:16
+msgid "The ID of the [CameraFeed] for which we want to display the image."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:19
+msgid ""
+"Convenience property that gives access to the active property of the "
+"[CameraFeed]."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:22
+msgid ""
+"Which image within the [CameraFeed] we want access to, important if the "
+"camera image is split in a Y and CbCr component."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:4
+msgid "Base class of anything 2D."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:7
+msgid ""
+"Base class of anything 2D. Canvas items are laid out in a tree; children "
+"inherit and extend their parent's transform. [CanvasItem] is extended by "
+"[Control] for anything GUI-related, and by [Node2D] for anything related to "
+"the 2D engine.\n"
+"Any [CanvasItem] can draw. For this, [method update] must be called, then "
+"[constant NOTIFICATION_DRAW] will be received on idle time to request "
+"redraw. Because of this, canvas items don't need to be redrawn on every "
+"frame, improving the performance significantly. Several functions for "
+"drawing on the [CanvasItem] are provided (see [code]draw_*[/code] "
+"functions). However, they can only be used inside the [method Object."
+"_notification], signal or [method _draw] virtual functions.\n"
+"Canvas items are drawn in tree order. By default, children are on top of "
+"their parents so a root [CanvasItem] will be drawn behind everything. This "
+"behavior can be changed on a per-item basis.\n"
+"A [CanvasItem] can also be hidden, which will also hide its children. It "
+"provides many ways to change parameters such as modulation (for itself and "
+"its children) and self modulation (only for itself), as well as its blend "
+"mode.\n"
+"Ultimately, a transform notification can be requested, which will notify the "
+"node that its global position changed in case the parent tree changed."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:14 doc/classes/CanvasLayer.xml:10
+#: doc/classes/InputEvent.xml:11 doc/classes/Viewport.xml:15
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html"
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:15 doc/classes/Control.xml:19
+#: doc/classes/Node2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html"
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:22
+msgid ""
+"Overridable function called by the engine (if defined) to draw the canvas "
+"item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:43
+msgid ""
+"Draws an arc between the given angles. The larger the value of "
+"[code]point_count[/code], the smoother the curve."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:60
+msgid ""
+"Draws a string character using a custom font. Returns the advance, depending "
+"on the character width and kerning with an optional next character."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:73
+msgid "Draws a colored circle."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:98
+msgid "Draws a colored polygon of any amount of points, convex or concave."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:113
+msgid "Draws a line from a 2D point to another, with a given color and width."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:138
+msgid ""
+"Draws a [Mesh] in 2D, using the provided texture. See [MeshInstance2D] for "
+"related documentation."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:151
+msgid "Draws multiple, parallel lines with a uniform [code]color[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:164
+msgid ""
+"Draws multiple, parallel lines with a uniform [code]width[/code] and segment-"
+"by-segment coloring. Colors assigned to line segments match by index between "
+"[code]points[/code] and [code]colors[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:185
+msgid ""
+"Draws a [MultiMesh] in 2D with the provided texture. See "
+"[MultiMeshInstance2D] for related documentation."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:210
+msgid "Draws a polygon of any amount of points, convex or concave."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:223
+msgid ""
+"Draws interconnected line segments with a uniform [code]color[/code] and "
+"[code]width[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:236
+msgid ""
+"Draws interconnected line segments with a uniform [code]width[/code] and "
+"segment-by-segment coloring. Colors assigned to line segments match by index "
+"between [code]points[/code] and [code]colors[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:263
+msgid ""
+"Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points "
+"for a triangle, and 4 points for a quad."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:278
+msgid ""
+"Draws a rectangle. If [code]filled[/code] is [code]true[/code], the "
+"rectangle will be filled with the [code]color[/code] specified. If "
+"[code]filled[/code] is [code]false[/code], the rectangle will be drawn as a "
+"stroke with the [code]color[/code] and [code]width[/code] specified.\n"
+"[b]Note:[/b] [code]width[/code] is only effective if [code]filled[/code] is "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:292
+msgid ""
+"Sets a custom transform for drawing via components. Anything drawn "
+"afterwards will be transformed by this."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:301
+msgid ""
+"Sets a custom transform for drawing via matrix. Anything drawn afterwards "
+"will be transformed by this."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:318
+msgid "Draws a string using a custom font."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:329
+msgid "Draws a styled rectangle."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:352
+msgid "Draws a texture at a given position."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:379
+msgid ""
+"Draws a textured rectangle at a given position, optionally modulated by a "
+"color. If [code]transpose[/code] is [code]true[/code], the texture will have "
+"its X and Y coordinates swapped."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:408
+msgid ""
+"Draws a textured rectangle region at a given position, optionally modulated "
+"by a color. If [code]transpose[/code] is [code]true[/code], the texture will "
+"have its X and Y coordinates swapped."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:415 doc/classes/Node3D.xml:18
+msgid ""
+"Forces the transform to update. Transform changes in physics are not instant "
+"for performance reasons. Transforms are accumulated and then set. Use this "
+"if you need an up-to-date transform when doing physics operations."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:422
+msgid "Returns the [RID] of the [World2D] canvas where this item is in."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:429
+msgid "Returns the canvas item RID used by [RenderingServer] for this item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:436
+msgid "Returns the transform matrix of this item's canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:443
+msgid "Returns the global position of the mouse."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:450
+msgid "Returns the global transform matrix of this item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:457
+msgid ""
+"Returns the global transform matrix of this item in relation to the canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:464
+msgid "Returns the mouse position relative to this item's position."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:471
+msgid "Returns the transform matrix of this item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:478
+msgid "Returns the viewport's boundaries as a [Rect2]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:485
+msgid "Returns this item's transform in relation to the viewport."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:492
+msgid "Returns the [World2D] where this item is in."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:499
+msgid "Hide the [CanvasItem] if it's currently visible."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:506
+msgid ""
+"Returns [code]true[/code] if local transform notifications are communicated "
+"to children."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:513
+msgid ""
+"Returns [code]true[/code] if the node is set as top-level. See [method "
+"set_as_toplevel]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:520
+msgid ""
+"Returns [code]true[/code] if global transform notifications are communicated "
+"to children."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:527
+msgid ""
+"Returns [code]true[/code] if the node is present in the [SceneTree], its "
+"[member visible] property is [code]true[/code] and its inherited visibility "
+"is also [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:536
+msgid "Assigns [code]screen_point[/code] as this node's new local transform."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:545
+msgid ""
+"Transformations issued by [code]event[/code]'s inputs are applied in local "
+"space instead of global space."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:554
+msgid ""
+"If [code]enable[/code] is [code]true[/code], the node won't inherit its "
+"transform from parent canvas items."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:563
+msgid ""
+"If [code]enable[/code] is [code]true[/code], children will be updated with "
+"local transform data."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:572
+msgid ""
+"If [code]enable[/code] is [code]true[/code], children will be updated with "
+"global transform data."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:579
+msgid ""
+"Show the [CanvasItem] if it's currently hidden. For controls that inherit "
+"[Popup], the correct way to make them visible is to call one of the multiple "
+"[code]popup*()[/code] functions instead."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:586
+msgid ""
+"Queue the [CanvasItem] for update. [constant NOTIFICATION_DRAW] will be "
+"called on idle time to request redraw."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:592
+msgid ""
+"The rendering layers in which this [CanvasItem] responds to [Light2D] nodes."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:595
+msgid "The material applied to textures on this [CanvasItem]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:598
+msgid "The color applied to textures on this [CanvasItem]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:601
+msgid ""
+"The color applied to textures on this [CanvasItem]. This is not inherited by "
+"children [CanvasItem]s."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:604
+msgid "If [code]true[/code], the object draws behind its parent."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:607
+msgid "If [code]true[/code], the object draws on top of its parent."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:614
+msgid ""
+"If [code]true[/code], the parent [CanvasItem]'s [member material] property "
+"is used as this one's material."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:617
+msgid ""
+"If [code]true[/code], this [CanvasItem] is drawn. For controls that inherit "
+"[Popup], the correct way to make them visible is to call one of the multiple "
+"[code]popup*()[/code] functions instead."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:623
+msgid ""
+"Emitted when the [CanvasItem] must redraw. This can only be connected "
+"realtime, as deferred will not allow drawing."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:628
+msgid "Emitted when becoming hidden."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:633
+msgid "Emitted when the item rect has changed."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:638
+msgid "Emitted when the visibility (hidden/visible) changes."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:644
+msgid ""
+"The [CanvasItem]'s transform has changed. This notification is only received "
+"if enabled by [method set_notify_transform] or [method "
+"set_notify_local_transform]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:647
+msgid "The [CanvasItem] is requested to draw."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:650
+msgid "The [CanvasItem]'s visibility has changed."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:653
+msgid "The [CanvasItem] has entered the canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:656
+msgid "The [CanvasItem] has exited the canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:659 doc/classes/CanvasItem.xml:679
+msgid "The [CanvasItem] will inherit the filter from its parent."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:662
+msgid ""
+"The texture filter reads from the nearest pixel only. The simplest and "
+"fastest method of filtering. Useful for pixel art."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:682
+msgid "Texture will not repeat."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:685
+msgid "Texture will repeat normally."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:688
+msgid ""
+"Texture will repeat in a 2x2 tiled mode, where elements at even positions "
+"are mirrored."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:691
+msgid "Represents the size of the [enum TextureRepeat] enum."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:4
+msgid "A material for [CanvasItem]s."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:7
+msgid ""
+"[CanvasItemMaterial]s provide a means of modifying the textures associated "
+"with a CanvasItem. They specialize in describing blend and lighting "
+"behaviors for textures. Use a [ShaderMaterial] to more fully customize a "
+"material's interactions with a [CanvasItem]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:15
+msgid ""
+"The manner in which a material's rendering is applied to underlying textures."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:18
+msgid "The manner in which material reacts to lighting."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:21
+msgid ""
+"The number of columns in the spritesheet assigned as [Texture2D] for a "
+"[GPUParticles2D] or [CPUParticles2D].\n"
+"[b]Note:[/b] This property is only used and visible in the editor if [member "
+"particles_animation] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:25
+msgid ""
+"If [code]true[/code], the particles animation will loop.\n"
+"[b]Note:[/b] This property is only used and visible in the editor if [member "
+"particles_animation] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:29
+msgid ""
+"The number of rows in the spritesheet assigned as [Texture2D] for a "
+"[GPUParticles2D] or [CPUParticles2D].\n"
+"[b]Note:[/b] This property is only used and visible in the editor if [member "
+"particles_animation] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:33
+msgid ""
+"If [code]true[/code], enable spritesheet-based animation features when "
+"assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member "
+"ParticlesMaterial.anim_speed] or [member CPUParticles2D.anim_speed] should "
+"also be set to a positive value for the animation to play.\n"
+"This property (and other [code]particles_anim_*[/code] properties that "
+"depend on it) has no effect on other types of nodes."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:39
+msgid ""
+"Mix blending mode. Colors are assumed to be independent of the alpha "
+"(opacity) value."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:42
+msgid "Additive blending mode."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:45
+msgid "Subtractive blending mode."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:48
+msgid "Multiplicative blending mode."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:51
+msgid ""
+"Mix blending mode. Colors are assumed to be premultiplied by the alpha "
+"(opacity) value."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:54
+msgid ""
+"Render the material using both light and non-light sensitive material "
+"properties."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:57
+msgid "Render the material as if there were no light."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:60
+msgid "Render the material as if there were only light."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:4
+msgid "Canvas drawing layer."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:7
+msgid ""
+"Canvas drawing layer. [CanvasItem] nodes that are direct or indirect "
+"children of a [CanvasLayer] will be drawn in that layer. The layer is a "
+"numeric index that defines the draw order. The default 2D scene renders with "
+"index 0, so a [CanvasLayer] with index -1 will be drawn below, and one with "
+"index 1 will be drawn above. This is very useful for HUDs (in layer 1+ or "
+"above), or backgrounds (in layer -1 or below)."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/canvas_layers.html"
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:18
+msgid "Returns the RID of the canvas used by this layer."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:24
+msgid ""
+"The custom [Viewport] node assigned to the [CanvasLayer]. If [code]null[/"
+"code], uses the default viewport instead."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:27
+msgid ""
+"Sets the layer to follow the viewport in order to simulate a pseudo 3D "
+"effect."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:30
+msgid ""
+"Scales the layer when using [member follow_viewport_enable]. Layers moving "
+"into the foreground should have increasing scales, while layers moving into "
+"the background should have decreasing scales."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:33
+msgid "Layer index for draw order. Lower values are drawn first."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:36
+msgid "The layer's base offset."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:39
+msgid "The layer's rotation in radians."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:42
+msgid "The layer's rotation in degrees."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:45
+msgid "The layer's scale."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:48
+msgid "The layer's transform."
+msgstr ""
+
+#: doc/classes/CanvasModulate.xml:4
+msgid "Tint the entire canvas."
+msgstr ""
+
+#: doc/classes/CanvasModulate.xml:7
+msgid ""
+"[CanvasModulate] tints the canvas elements using its assigned [member color]."
+msgstr ""
+
+#: doc/classes/CanvasModulate.xml:15
+msgid "The tint color to apply."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:4 doc/classes/CapsuleMesh.xml:7
+msgid "Class representing a capsule-shaped [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:15
+msgid "Height of the capsule mesh from the center point."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:18
+msgid "Number of radial segments on the capsule mesh."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:21
+msgid "Radius of the capsule mesh."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:24
+msgid "Number of rings along the height of the capsule."
+msgstr ""
+
+#: doc/classes/CapsuleShape2D.xml:4 doc/classes/CapsuleShape2D.xml:7
+msgid "Capsule shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/CapsuleShape2D.xml:15 doc/classes/CapsuleShape3D.xml:15
+msgid "The capsule's height."
+msgstr ""
+
+#: doc/classes/CapsuleShape2D.xml:18 doc/classes/CapsuleShape3D.xml:18
+msgid "The capsule's radius."
+msgstr ""
+
+#: doc/classes/CapsuleShape3D.xml:4 doc/classes/CapsuleShape3D.xml:7
+msgid "Capsule shape for collisions."
+msgstr ""
+
+#: doc/classes/CenterContainer.xml:4
+msgid "Keeps children controls centered."
+msgstr ""
+
+#: doc/classes/CenterContainer.xml:7
+msgid ""
+"CenterContainer keeps children controls centered. This container keeps all "
+"children to their minimum size, in the center."
+msgstr ""
+
+#: doc/classes/CenterContainer.xml:15
+msgid ""
+"If [code]true[/code], centers children relative to the [CenterContainer]'s "
+"top left corner."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:4
+msgid ""
+"Controls how an individual character will be displayed in a [RichTextEffect]."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:7
+msgid ""
+"By setting various properties on this object, you can control how individual "
+"characters will be displayed in a [RichTextEffect]."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:10 doc/classes/RichTextEffect.xml:16
+#: doc/classes/RichTextLabel.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel."
+"html"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:11 doc/classes/RichTextEffect.xml:17
+msgid ""
+"https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:17 doc/classes/CharFXTransform.xml:45
+msgid ""
+"The index of the current character (starting from 0). Setting this property "
+"won't affect drawing."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:20
+msgid ""
+"The Unicode codepoint the character will use. This only affects non-"
+"whitespace characters. [method @GDScript.ord] can be useful here. For "
+"example, the following will replace all characters with asterisks:\n"
+"[codeblock]\n"
+"# `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`.\n"
+"# See the RichTextEffect documentation for details.\n"
+"char_fx.character = ord(\"*\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:28
+msgid "The color the character will be drawn with."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:31
+msgid ""
+"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].\n"
+"[b]Note:[/b] Time still passes while the [RichTextLabel] is hidden."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:35
+msgid ""
+"Contains the arguments passed in the opening BBCode tag. By default, "
+"arguments are strings; if their contents match a type such as [bool], [int] "
+"or [float], they will be converted automatically. Color codes in the form "
+"[code]#rrggbb[/code] or [code]#rgb[/code] will be converted to an opaque "
+"[Color]. String arguments may not contain spaces, even if they're quoted. If "
+"present, quotes will also be present in the final string.\n"
+"For example, the opening BBCode tag [code][example foo=hello bar=true baz=42 "
+"color=#ffffff][/code] will map to the following [Dictionary]:\n"
+"[codeblock]\n"
+"{\"foo\": \"hello\", \"bar\": true, \"baz\": 42, \"color\": Color(1, 1, 1, "
+"1)}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:42
+msgid "The position offset the character will be drawn with (in pixels)."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:48
+msgid ""
+"If [code]true[/code], the character will be drawn. If [code]false[/code], "
+"the character will be hidden. Characters around hidden characters will "
+"reflow to take the space of hidden characters. If this is not desired, set "
+"their [member color] to [code]Color(1, 1, 1, 0)[/code] instead."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:4
+msgid "Binary choice user interface widget. See also [CheckButton]."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:7
+msgid ""
+"A checkbox allows the user to make a binary choice (choosing only one of two "
+"possible options). It's similar to [CheckButton] in functionality, but it "
+"has a different appearance. To follow established UX patterns, it's "
+"recommended to use CheckBox when toggling it has [b]no[/b] immediate effect "
+"on something. For instance, it should be used when toggling it will only do "
+"something once a confirmation button is pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:21
+msgid "The vertical offset used when rendering the check icons (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:24
+msgid "The check icon to display when the [CheckBox] is checked."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:27
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is disabled."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:30
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is focused."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:33
+msgid "The [Font] to use for the [CheckBox] text."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:36
+msgid "The [CheckBox] text's font color."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:39
+msgid "The [CheckBox] text's font color when it's disabled."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:42
+msgid "The [CheckBox] text's font color when it's hovered."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:45
+msgid "The [CheckBox] text's font color when it's hovered and pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:48
+msgid "The [CheckBox] text's font color when it's pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:51
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is hovered."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:54
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is hovered and "
+"pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:57
+msgid "The separation between the check icon and the text (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:60 doc/classes/CheckButton.xml:57
+msgid "The [StyleBox] to display as a background."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:63
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:66
+msgid ""
+"If the [CheckBox] is configured as a radio button, the icon to display when "
+"the [CheckBox] is checked."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:69
+msgid ""
+"If the [CheckBox] is configured as a radio button, the icon to display when "
+"the [CheckBox] is unchecked."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:72
+msgid "The check icon to display when the [CheckBox] is unchecked."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:4
+msgid "Checkable button. See also [CheckBox]."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:7
+msgid ""
+"CheckButton is a toggle button displayed as a check field. It's similar to "
+"[CheckBox] in functionality, but it has a different appearance. To follow "
+"established UX patterns, it's recommended to use CheckButton when toggling "
+"it has an [b]immediate[/b] effect on something. For instance, it should be "
+"used if toggling it enables/disables a setting without requiring the user to "
+"press a confirmation button."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:21
+msgid "The vertical offset used when rendering the toggle icons (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:24
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:27
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is focused."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:30
+msgid "The [Font] to use for the [CheckButton] text."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:33
+msgid "The [CheckButton] text's font color."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:36
+msgid "The [CheckButton] text's font color when it's disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:39
+msgid "The [CheckButton] text's font color when it's hovered."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:42
+msgid "The [CheckButton] text's font color when it's hovered and pressed."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:45
+msgid "The [CheckButton] text's font color when it's pressed."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:48
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is hovered."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:51
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is hovered "
+"and pressed."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:54
+msgid "The separation between the toggle icon and the text (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:60
+msgid "The icon to display when the [CheckButton] is unchecked."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:63
+msgid "The icon to display when the [CheckButton] is unchecked and disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:66
+msgid "The icon to display when the [CheckButton] is checked."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:69
+msgid "The icon to display when the [CheckButton] is checked and disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:72
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is pressed."
+msgstr ""
+
+#: doc/classes/CircleShape2D.xml:4
+msgid "Circular shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/CircleShape2D.xml:7
+msgid ""
+"Circular shape for 2D collisions. This shape is useful for modeling balls or "
+"small characters and its collision detection with everything else is very "
+"fast."
+msgstr ""
+
+#: doc/classes/CircleShape2D.xml:15
+msgid "The circle's radius."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:4
+msgid "Class information repository."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:7
+msgid "Provides access to metadata stored for every available class."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:18
+msgid ""
+"Returns [code]true[/code] if you can instance objects from the specified "
+"[code]class[/code], [code]false[/code] in other case."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:27
+msgid "Returns whether the specified [code]class[/code] is available or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:36
+msgid ""
+"Returns a category associated with the class for use in documentation and "
+"the Asset Library. Debug mode required."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:47
+msgid ""
+"Returns the value of the integer constant [code]name[/code] of [code]class[/"
+"code] or its ancestry. Always returns 0 when the constant could not be found."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:58
+msgid ""
+"Returns an array with the names all the integer constants of [code]class[/"
+"code] or its ancestry."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:69
+msgid ""
+"Returns an array with all the methods of [code]class[/code] or its ancestry "
+"if [code]no_inheritance[/code] is [code]false[/code]. Every element of the "
+"array is a [Dictionary] with the following keys: [code]args[/code], "
+"[code]default_args[/code], [code]flags[/code], [code]id[/code], [code]name[/"
+"code], [code]return: (class_name, hint, hint_string, name, type, usage)[/"
+"code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:80
+msgid ""
+"Returns the value of [code]property[/code] of [code]class[/code] or its "
+"ancestry."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:91
+msgid ""
+"Returns an array with all the properties of [code]class[/code] or its "
+"ancestry if [code]no_inheritance[/code] is [code]false[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:102
+msgid ""
+"Returns the [code]signal[/code] data of [code]class[/code] or its ancestry. "
+"The returned value is a [Dictionary] with the following keys: [code]args[/"
+"code], [code]default_args[/code], [code]flags[/code], [code]id[/code], "
+"[code]name[/code], [code]return: (class_name, hint, hint_string, name, type, "
+"usage)[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:113
+msgid ""
+"Returns an array with all the signals of [code]class[/code] or its ancestry "
+"if [code]no_inheritance[/code] is [code]false[/code]. Every element of the "
+"array is a [Dictionary] as described in [method class_get_signal]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:124
+msgid ""
+"Returns whether [code]class[/code] or its ancestry has an integer constant "
+"called [code]name[/code] or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:137
+msgid ""
+"Returns whether [code]class[/code] (or its ancestry if [code]no_inheritance[/"
+"code] is [code]false[/code]) has a method called [code]method[/code] or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:148
+msgid ""
+"Returns whether [code]class[/code] or its ancestry has a signal called "
+"[code]signal[/code] or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:161
+msgid ""
+"Sets [code]property[/code] value of [code]class[/code] to [code]value[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:168
+msgid "Returns the names of all the classes available."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:177
+msgid ""
+"Returns the names of all the classes that directly or indirectly inherit "
+"from [code]class[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:186
+msgid "Returns the parent class of [code]class[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:195
+msgid "Creates an instance of [code]class[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:204
+msgid "Returns whether this [code]class[/code] is enabled or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:215
+msgid ""
+"Returns whether [code]inherits[/code] is an ancestor of [code]class[/code] "
+"or not."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:4
+msgid "A [Camera3D] that includes collision."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:7
+msgid ""
+"This node extends [Camera3D] to add collisions with [Area3D] and/or "
+"[PhysicsBody3D] nodes. The camera cannot move through colliding objects."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:18
+msgid ""
+"Adds a collision exception so the camera does not collide with the specified "
+"node."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:27
+msgid ""
+"Adds a collision exception so the camera does not collide with the specified "
+"[RID]."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:34
+msgid "Removes all collision exceptions."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:41
+msgid "Returns the distance the camera has been offset due to a collision."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:50
+msgid ""
+"Returns [code]true[/code] if the specified bit index is on.\n"
+"[b]Note:[/b] Bit indices range from 0-19."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:60
+msgid "Removes a collision exception with the specified node."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:69
+msgid "Removes a collision exception with the specified [RID]."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:80
+msgid ""
+"Sets the specified bit index to the [code]value[/code].\n"
+"[b]Note:[/b] Bit indices range from 0-19."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:87
+msgid "If [code]true[/code], the camera stops on contact with [Area3D]s."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:90
+msgid ""
+"If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:93
+msgid ""
+"The camera's collision mask. Only objects in at least one collision layer "
+"matching the mask will be detected."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:96
+msgid ""
+"The camera's collision margin. The camera can't get closer than this "
+"distance to a colliding object."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:99
+msgid "The camera's process callback. See [enum ProcessMode]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:4
+msgid "Base node for 2D collision objects."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:7
+msgid ""
+"CollisionObject2D is the base class for 2D physics objects. It can hold any "
+"number of 2D collision [Shape2D]s. Each shape must be assigned to a [i]shape "
+"owner[/i]. The CollisionObject2D can have any number of shape owners. Shape "
+"owners are not nodes and do not appear in the editor, but are accessible "
+"through code using the [code]shape_owner_*[/code] methods."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:22
+msgid ""
+"Accepts unhandled [InputEvent]s. Requires [member input_pickable] to be "
+"[code]true[/code]. [code]shape_idx[/code] is the child index of the clicked "
+"[Shape2D]. Connect to the [code]input_event[/code] signal to easily pick up "
+"these events."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:31 doc/classes/CollisionObject3D.xml:35
+msgid ""
+"Creates a new shape owner for the given object. Returns [code]owner_id[/"
+"code] of the new owner for future reference."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:38 doc/classes/CollisionObject3D.xml:42
+msgid "Returns the object's [RID]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:47
+msgid ""
+"Returns the [code]one_way_collision_margin[/code] of the shape owner "
+"identified by given [code]owner_id[/code]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:54 doc/classes/CollisionObject3D.xml:49
+msgid ""
+"Returns an [Array] of [code]owner_id[/code] identifiers. You can use these "
+"ids in other methods that take [code]owner_id[/code] as an argument."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:63 doc/classes/CollisionObject3D.xml:58
+msgid "If [code]true[/code], the shape owner and its shapes are disabled."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:72
+msgid ""
+"Returns [code]true[/code] if collisions for the shape owner originating from "
+"this [CollisionObject2D] will not be reported to collided with "
+"[CollisionObject2D]s."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:81 doc/classes/CollisionObject3D.xml:67
+msgid "Removes the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:90 doc/classes/CollisionObject3D.xml:76
+msgid "Returns the [code]owner_id[/code] of the given shape."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:101
+msgid "Adds a [Shape2D] to the shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:110 doc/classes/CollisionObject3D.xml:96
+msgid "Removes all shapes from the shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:119 doc/classes/CollisionObject3D.xml:105
+msgid "Returns the parent object of the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:130
+msgid "Returns the [Shape2D] with the given id from the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:139 doc/classes/CollisionObject3D.xml:125
+msgid "Returns the number of shapes the given shape owner contains."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:150
+msgid ""
+"Returns the child index of the [Shape2D] with the given id from the given "
+"shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:159
+msgid "Returns the shape owner's [Transform2D]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:170 doc/classes/CollisionObject3D.xml:156
+msgid "Removes a shape from the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:181 doc/classes/CollisionObject3D.xml:167
+msgid "If [code]true[/code], disables the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:192
+msgid ""
+"If [code]enable[/code] is [code]true[/code], collisions for the shape owner "
+"originating from this [CollisionObject2D] will not be reported to collided "
+"with [CollisionObject2D]s."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:203
+msgid ""
+"Sets the [code]one_way_collision_margin[/code] of the shape owner identified "
+"by given [code]owner_id[/code] to [code]margin[/code] pixels."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:214
+msgid "Sets the [Transform2D] of the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:220
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:232
+msgid ""
+"Emitted when an input event occurs. Requires [member input_pickable] to be "
+"[code]true[/code] and at least one [code]collision_layer[/code] bit to be "
+"set. See [method _input_event] for details."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:237
+msgid ""
+"Emitted when the mouse pointer enters any of this object's shapes. Requires "
+"[member input_pickable] to be [code]true[/code] and at least one "
+"[code]collision_layer[/code] bit to be set."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:242
+msgid ""
+"Emitted when the mouse pointer exits all this object's shapes. Requires "
+"[member input_pickable] to be [code]true[/code] and at least one "
+"[code]collision_layer[/code] bit to be set."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:4
+msgid "Base node for collision objects."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:7
+msgid ""
+"CollisionObject3D is the base class for physics objects. It can hold any "
+"number of collision [Shape3D]s. Each shape must be assigned to a [i]shape "
+"owner[/i]. The CollisionObject3D can have any number of shape owners. Shape "
+"owners are not nodes and do not appear in the editor, but are accessible "
+"through code using the [code]shape_owner_*[/code] methods."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:26
+msgid ""
+"Accepts unhandled [InputEvent]s. [code]click_position[/code] is the clicked "
+"location in world space and [code]click_normal[/code] is the normal vector "
+"extending from the clicked surface of the [Shape3D] at [code]shape_idx[/"
+"code]. Connect to the [code]input_event[/code] signal to easily pick up "
+"these events."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:87
+msgid "Adds a [Shape3D] to the shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:116
+msgid "Returns the [Shape3D] with the given id from the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:136
+msgid ""
+"Returns the child index of the [Shape3D] with the given id from the given "
+"shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:145
+msgid "Returns the shape owner's [Transform]."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:178
+msgid "Sets the [Transform] of the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:184
+msgid ""
+"If [code]true[/code], the [CollisionObject3D] will continue to receive input "
+"events as the mouse is dragged across its shapes."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:187
+msgid ""
+"If [code]true[/code], the [CollisionObject3D]'s shapes will respond to "
+"[RayCast3D]s."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:203
+msgid ""
+"Emitted when [method _input_event] receives an event. See its description "
+"for details."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:208
+msgid "Emitted when the mouse pointer enters any of this object's shapes."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:213
+msgid "Emitted when the mouse pointer exits all this object's shapes."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:4
+msgid "Defines a 2D collision polygon."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:7
+msgid ""
+"Provides a 2D collision polygon to a [CollisionObject2D] parent. Polygons "
+"can be drawn in the editor or specified by a list of vertices."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:15
+msgid "Collision build mode. Use one of the [enum BuildMode] constants."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:18
+msgid "If [code]true[/code], no collisions will be detected."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:21
+msgid ""
+"If [code]true[/code], only edges that face up, relative to "
+"[CollisionPolygon2D]'s rotation, will collide with other objects."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:24
+msgid ""
+"The margin used for one-way collision (in pixels). Higher values will make "
+"the shape thicker, and work better for colliders that enter the polygon at a "
+"high velocity."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:27
+msgid ""
+"The polygon's list of vertices. The final point will be connected to the "
+"first. The returned value is a clone of the [PackedVector2Array], not a "
+"reference."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:32
+msgid "Collisions will include the polygon and its contained area."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:35
+msgid "Collisions will only include the polygon edges."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:4
+msgid "Editor-only class for defining a collision polygon in 3D space."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:7
+msgid ""
+"Allows editing a collision polygon's vertices on a selected plane. Can also "
+"set a depth perpendicular to that plane. This class is only available in the "
+"editor. It will not appear in the scene tree at run-time. Creates a "
+"[Shape3D] for gameplay. Properties modified during gameplay will have no "
+"effect."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:15
+msgid ""
+"Length that the resulting collision extends in either direction "
+"perpendicular to its polygon."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:18
+msgid "If [code]true[/code], no collision will be produced."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:21
+msgid ""
+"Array of vertices which define the polygon.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:4
+msgid "Node that represents collision shape data in 2D space."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:7
+msgid ""
+"Editor facility for creating and editing collision shapes in 2D space. You "
+"can use this node to represent all sorts of collision shapes, for example, "
+"add this to an [Area2D] to give it a detection shape, or add it to a "
+"[PhysicsBody2D] to create a solid object. [b]IMPORTANT[/b]: this is an "
+"Editor-only helper to create shapes, use [method CollisionObject2D."
+"shape_owner_get_shape] to get the actual shape."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:10 doc/classes/CollisionShape3D.xml:10
+#: doc/classes/PhysicsBody2D.xml:10 doc/classes/PhysicsBody3D.xml:10
+#: doc/classes/RigidBody3D.xml:13 doc/classes/Shape2D.xml:10
+#: doc/classes/Shape3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/"
+"physics_introduction.html"
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:16 doc/classes/CollisionShape3D.xml:32
+msgid "A disabled collision shape has no effect in the world."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:19
+msgid ""
+"Sets whether this collision shape should only detect collision on one side "
+"(top or bottom)."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:22
+msgid ""
+"The margin used for one-way collision (in pixels). Higher values will make "
+"the shape thicker, and work better for colliders that enter the shape at a "
+"high velocity."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:25 doc/classes/CollisionShape3D.xml:35
+msgid "The actual shape owned by this collision shape."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:4
+msgid "Node that represents collision shape data in 3D space."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:7
+msgid ""
+"Editor facility for creating and editing collision shapes in 3D space. You "
+"can use this node to represent all sorts of collision shapes, for example, "
+"add this to an [Area3D] to give it a detection shape, or add it to a "
+"[PhysicsBody3D] to create a solid object. [b]IMPORTANT[/b]: this is an "
+"Editor-only helper to create shapes, use [method CollisionObject3D."
+"shape_owner_get_shape] to get the actual shape."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:17
+msgid ""
+"Sets the collision shape's shape to the addition of all its convexed "
+"[MeshInstance3D] siblings geometry."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:26
+msgid ""
+"If this method exists within a script it will be called whenever the shape "
+"resource has been modified."
+msgstr ""
+
+#: doc/classes/Color.xml:4
+msgid "Color in RGBA format with some support for ARGB format."
+msgstr ""
+
+#: doc/classes/Color.xml:7
+msgid ""
+"A color is represented by red, green, and blue [code](r, g, b)[/code] "
+"components. Additionally, [code]a[/code] represents the alpha component, "
+"often used for transparency. Values are in floating-point and usually range "
+"from 0 to 1. Some properties (such as [member CanvasItem.modulate]) may "
+"accept values greater than 1.\n"
+"You can also create a color from standardized color names by using [method "
+"@GDScript.ColorN] or directly using the color constants defined here. The "
+"standardized color set is based on the [url=https://en.wikipedia.org/wiki/"
+"X11_color_names]X11 color names[/url]. \n"
+"If you want to supply values in a range of 0 to 255, you should use [method "
+"@GDScript.Color8]."
+msgstr ""
+
+#: doc/classes/Color.xml:20
+msgid ""
+"Constructs a color from an HTML hexadecimal color string in ARGB or RGB "
+"format. See also [method @GDScript.ColorN].\n"
+"[codeblock]\n"
+"# Each of the following creates the same color RGBA(178, 217, 10, 255).\n"
+"var c1 = Color(\"#ffb2d90a\") # ARGB format with \"#\".\n"
+"var c2 = Color(\"ffb2d90a\") # ARGB format.\n"
+"var c3 = Color(\"#b2d90a\") # RGB format with \"#\".\n"
+"var c4 = Color(\"b2d90a\") # RGB format.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:36
+msgid ""
+"Constructs a color from a 32-bit integer (each byte represents a component "
+"of the RGBA profile).\n"
+"[codeblock]\n"
+"var c = Color(274) # Equivalent to RGBA(0, 0, 1, 18)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:52
+msgid ""
+"Constructs a color from an RGB profile using values between 0 and 1. Alpha "
+"will always be 1.\n"
+"[codeblock]\n"
+"var c = Color(0.2, 1.0, 0.7) # Equivalent to RGBA(51, 255, 178, 255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:70
+msgid ""
+"Constructs a color from an RGBA profile using values between 0 and 1.\n"
+"[codeblock]\n"
+"var c = Color(0.2, 1.0, 0.7, 0.8) # Equivalent to RGBA(51, 255, 178, 204)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:82
+msgid ""
+"Returns a new color resulting from blending this color over another. If the "
+"color is opaque, the result is also opaque. The second color may have a "
+"range of alpha values.\n"
+"[codeblock]\n"
+"var bg = Color(0.0, 1.0, 0.0, 0.5) # Green with alpha of 50%\n"
+"var fg = Color(1.0, 0.0, 0.0, 0.5) # Red with alpha of 50%\n"
+"var blended_color = bg.blend(fg) # Brown with alpha of 75%\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:94
+msgid ""
+"Returns the most contrasting color.\n"
+"[codeblock]\n"
+"var c = Color(0.3, 0.4, 0.9)\n"
+"var contrasted_color = c.contrasted() # Equivalent to RGBA(204, 229, 102, "
+"255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:107
+msgid ""
+"Returns a new color resulting from making this color darker by the specified "
+"percentage (ratio from 0 to 1).\n"
+"[codeblock]\n"
+"var green = Color(0.0, 1.0, 0.0)\n"
+"var darkgreen = green.darkened(0.2) # 20% darker than regular green\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:126
+msgid ""
+"Constructs a color from an HSV profile. [code]h[/code], [code]s[/code], and "
+"[code]v[/code] are values between 0 and 1.\n"
+"[codeblock]\n"
+"var c = Color.from_hsv(0.58, 0.5, 0.79, 0.8) # Equivalent to HSV(210, 50, "
+"79, 0.8) or Color8(100, 151, 201, 0.8)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:136
+msgid ""
+"Returns the inverted color [code](1 - r, 1 - g, 1 - b, a)[/code].\n"
+"[codeblock]\n"
+"var c = Color(0.3, 0.4, 0.9)\n"
+"var inverted_color = c.inverted() # A color of an RGBA(178, 153, 26, 255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:149
+msgid ""
+"Returns [code]true[/code] if this color and [code]color[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Color.xml:158
+msgid ""
+"Returns a new color resulting from making this color lighter by the "
+"specified percentage (ratio from 0 to 1).\n"
+"[codeblock]\n"
+"var green = Color(0.0, 1.0, 0.0)\n"
+"var lightgreen = green.lightened(0.2) # 20% lighter than regular green\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:173
+msgid ""
+"Returns the linear interpolation with another color. The interpolation "
+"factor [code]t[/code] is between 0 and 1.\n"
+"[codeblock]\n"
+"var c1 = Color(1.0, 0.0, 0.0)\n"
+"var c2 = Color(0.0, 1.0, 0.0)\n"
+"var li_c = c1.linear_interpolate(c2, 0.5) # A color of an RGBA(128, 128, 0, "
+"255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:185
+msgid ""
+"Returns the color's 32-bit integer in ABGR format (each byte represents a "
+"component of the ABGR profile). ABGR is the reversed version of the default "
+"format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_abgr32()) # Prints 4281565439\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:196
+msgid ""
+"Returns the color's 64-bit integer in ABGR format (each word represents a "
+"component of the ABGR profile). ABGR is the reversed version of the default "
+"format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_abgr64()) # Prints -225178692812801\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:207
+msgid ""
+"Returns the color's 32-bit integer in ARGB format (each byte represents a "
+"component of the ARGB profile). ARGB is more compatible with DirectX.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_argb32()) # Prints 4294934323\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:218
+msgid ""
+"Returns the color's 64-bit integer in ARGB format (each word represents a "
+"component of the ARGB profile). ARGB is more compatible with DirectX.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_argb64()) # Prints -2147470541\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:231
+msgid ""
+"Returns the color's HTML hexadecimal color string in ARGB format (ex: "
+"[code]ff34f822[/code]).\n"
+"Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from "
+"the hexadecimal string.\n"
+"[codeblock]\n"
+"var c = Color(1, 1, 1, 0.5)\n"
+"var s1 = c.to_html() # Returns \"7fffffff\"\n"
+"var s2 = c.to_html(false) # Returns \"ffffff\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:244
+msgid ""
+"Returns the color's 32-bit integer in RGBA format (each byte represents a "
+"component of the RGBA profile). RGBA is Godot's default format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_rgba32()) # Prints 4286526463\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:255
+msgid ""
+"Returns the color's 64-bit integer in RGBA format (each word represents a "
+"component of the RGBA profile). RGBA is Godot's default format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_rgba64()) # Prints -140736629309441\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:265
+msgid "Alpha value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:268
+msgid "Alpha value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:271
+msgid "Blue value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:274
+msgid "Blue value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:277
+msgid "Green value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:280
+msgid "Green value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:283
+msgid "HSV hue value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:286
+msgid "Red value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:289
+msgid "Red value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:292
+msgid "HSV saturation value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:295
+msgid "HSV value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:300
+msgid "Alice blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:303
+msgid "Antique white color."
+msgstr ""
+
+#: doc/classes/Color.xml:306
+msgid "Aqua color."
+msgstr ""
+
+#: doc/classes/Color.xml:309
+msgid "Aquamarine color."
+msgstr ""
+
+#: doc/classes/Color.xml:312
+msgid "Azure color."
+msgstr ""
+
+#: doc/classes/Color.xml:315
+msgid "Beige color."
+msgstr ""
+
+#: doc/classes/Color.xml:318
+msgid "Bisque color."
+msgstr ""
+
+#: doc/classes/Color.xml:321
+msgid "Black color."
+msgstr ""
+
+#: doc/classes/Color.xml:324
+msgid "Blanche almond color."
+msgstr ""
+
+#: doc/classes/Color.xml:327
+msgid "Blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:330
+msgid "Blue violet color."
+msgstr ""
+
+#: doc/classes/Color.xml:333
+msgid "Brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:336
+msgid "Burly wood color."
+msgstr ""
+
+#: doc/classes/Color.xml:339
+msgid "Cadet blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:342
+msgid "Chartreuse color."
+msgstr ""
+
+#: doc/classes/Color.xml:345
+msgid "Chocolate color."
+msgstr ""
+
+#: doc/classes/Color.xml:348
+msgid "Coral color."
+msgstr ""
+
+#: doc/classes/Color.xml:351
+msgid "Cornflower color."
+msgstr ""
+
+#: doc/classes/Color.xml:354
+msgid "Corn silk color."
+msgstr ""
+
+#: doc/classes/Color.xml:357
+msgid "Crimson color."
+msgstr ""
+
+#: doc/classes/Color.xml:360
+msgid "Cyan color."
+msgstr ""
+
+#: doc/classes/Color.xml:363
+msgid "Dark blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:366
+msgid "Dark cyan color."
+msgstr ""
+
+#: doc/classes/Color.xml:369
+msgid "Dark goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:372
+msgid "Dark gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:375
+msgid "Dark green color."
+msgstr ""
+
+#: doc/classes/Color.xml:378
+msgid "Dark khaki color."
+msgstr ""
+
+#: doc/classes/Color.xml:381
+msgid "Dark magenta color."
+msgstr ""
+
+#: doc/classes/Color.xml:384
+msgid "Dark olive green color."
+msgstr ""
+
+#: doc/classes/Color.xml:387
+msgid "Dark orange color."
+msgstr ""
+
+#: doc/classes/Color.xml:390
+msgid "Dark orchid color."
+msgstr ""
+
+#: doc/classes/Color.xml:393
+msgid "Dark red color."
+msgstr ""
+
+#: doc/classes/Color.xml:396
+msgid "Dark salmon color."
+msgstr ""
+
+#: doc/classes/Color.xml:399
+msgid "Dark sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:402
+msgid "Dark slate blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:405
+msgid "Dark slate gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:408
+msgid "Dark turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:411
+msgid "Dark violet color."
+msgstr ""
+
+#: doc/classes/Color.xml:414
+msgid "Deep pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:417
+msgid "Deep sky blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:420
+msgid "Dim gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:423
+msgid "Dodger blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:426
+msgid "Firebrick color."
+msgstr ""
+
+#: doc/classes/Color.xml:429
+msgid "Floral white color."
+msgstr ""
+
+#: doc/classes/Color.xml:432
+msgid "Forest green color."
+msgstr ""
+
+#: doc/classes/Color.xml:435
+msgid "Fuchsia color."
+msgstr ""
+
+#: doc/classes/Color.xml:438
+msgid "Gainsboro color."
+msgstr ""
+
+#: doc/classes/Color.xml:441
+msgid "Ghost white color."
+msgstr ""
+
+#: doc/classes/Color.xml:444
+msgid "Gold color."
+msgstr ""
+
+#: doc/classes/Color.xml:447
+msgid "Goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:450
+msgid "Gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:453
+msgid "Green color."
+msgstr ""
+
+#: doc/classes/Color.xml:456
+msgid "Green yellow color."
+msgstr ""
+
+#: doc/classes/Color.xml:459
+msgid "Honeydew color."
+msgstr ""
+
+#: doc/classes/Color.xml:462
+msgid "Hot pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:465
+msgid "Indian red color."
+msgstr ""
+
+#: doc/classes/Color.xml:468
+msgid "Indigo color."
+msgstr ""
+
+#: doc/classes/Color.xml:471
+msgid "Ivory color."
+msgstr ""
+
+#: doc/classes/Color.xml:474
+msgid "Khaki color."
+msgstr ""
+
+#: doc/classes/Color.xml:477
+msgid "Lavender color."
+msgstr ""
+
+#: doc/classes/Color.xml:480
+msgid "Lavender blush color."
+msgstr ""
+
+#: doc/classes/Color.xml:483
+msgid "Lawn green color."
+msgstr ""
+
+#: doc/classes/Color.xml:486
+msgid "Lemon chiffon color."
+msgstr ""
+
+#: doc/classes/Color.xml:489
+msgid "Light blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:492
+msgid "Light coral color."
+msgstr ""
+
+#: doc/classes/Color.xml:495
+msgid "Light cyan color."
+msgstr ""
+
+#: doc/classes/Color.xml:498
+msgid "Light goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:501
+msgid "Light gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:504
+msgid "Light green color."
+msgstr ""
+
+#: doc/classes/Color.xml:507
+msgid "Light pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:510
+msgid "Light salmon color."
+msgstr ""
+
+#: doc/classes/Color.xml:513
+msgid "Light sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:516
+msgid "Light sky blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:519
+msgid "Light slate gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:522
+msgid "Light steel blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:525
+msgid "Light yellow color."
+msgstr ""
+
+#: doc/classes/Color.xml:528
+msgid "Lime color."
+msgstr ""
+
+#: doc/classes/Color.xml:531
+msgid "Lime green color."
+msgstr ""
+
+#: doc/classes/Color.xml:534
+msgid "Linen color."
+msgstr ""
+
+#: doc/classes/Color.xml:537
+msgid "Magenta color."
+msgstr ""
+
+#: doc/classes/Color.xml:540
+msgid "Maroon color."
+msgstr ""
+
+#: doc/classes/Color.xml:543
+msgid "Medium aquamarine color."
+msgstr ""
+
+#: doc/classes/Color.xml:546
+msgid "Medium blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:549
+msgid "Medium orchid color."
+msgstr ""
+
+#: doc/classes/Color.xml:552
+msgid "Medium purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:555
+msgid "Medium sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:558
+msgid "Medium slate blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:561
+msgid "Medium spring green color."
+msgstr ""
+
+#: doc/classes/Color.xml:564
+msgid "Medium turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:567
+msgid "Medium violet red color."
+msgstr ""
+
+#: doc/classes/Color.xml:570
+msgid "Midnight blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:573
+msgid "Mint cream color."
+msgstr ""
+
+#: doc/classes/Color.xml:576
+msgid "Misty rose color."
+msgstr ""
+
+#: doc/classes/Color.xml:579
+msgid "Moccasin color."
+msgstr ""
+
+#: doc/classes/Color.xml:582
+msgid "Navajo white color."
+msgstr ""
+
+#: doc/classes/Color.xml:585
+msgid "Navy blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:588
+msgid "Old lace color."
+msgstr ""
+
+#: doc/classes/Color.xml:591
+msgid "Olive color."
+msgstr ""
+
+#: doc/classes/Color.xml:594
+msgid "Olive drab color."
+msgstr ""
+
+#: doc/classes/Color.xml:597
+msgid "Orange color."
+msgstr ""
+
+#: doc/classes/Color.xml:600
+msgid "Orange red color."
+msgstr ""
+
+#: doc/classes/Color.xml:603
+msgid "Orchid color."
+msgstr ""
+
+#: doc/classes/Color.xml:606
+msgid "Pale goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:609
+msgid "Pale green color."
+msgstr ""
+
+#: doc/classes/Color.xml:612
+msgid "Pale turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:615
+msgid "Pale violet red color."
+msgstr ""
+
+#: doc/classes/Color.xml:618
+msgid "Papaya whip color."
+msgstr ""
+
+#: doc/classes/Color.xml:621
+msgid "Peach puff color."
+msgstr ""
+
+#: doc/classes/Color.xml:624
+msgid "Peru color."
+msgstr ""
+
+#: doc/classes/Color.xml:627
+msgid "Pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:630
+msgid "Plum color."
+msgstr ""
+
+#: doc/classes/Color.xml:633
+msgid "Powder blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:636
+msgid "Purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:639
+msgid "Rebecca purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:642
+msgid "Red color."
+msgstr ""
+
+#: doc/classes/Color.xml:645
+msgid "Rosy brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:648
+msgid "Royal blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:651
+msgid "Saddle brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:654
+msgid "Salmon color."
+msgstr ""
+
+#: doc/classes/Color.xml:657
+msgid "Sandy brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:660
+msgid "Sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:663
+msgid "Seashell color."
+msgstr ""
+
+#: doc/classes/Color.xml:666
+msgid "Sienna color."
+msgstr ""
+
+#: doc/classes/Color.xml:669
+msgid "Silver color."
+msgstr ""
+
+#: doc/classes/Color.xml:672
+msgid "Sky blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:675
+msgid "Slate blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:678
+msgid "Slate gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:681
+msgid "Snow color."
+msgstr ""
+
+#: doc/classes/Color.xml:684
+msgid "Spring green color."
+msgstr ""
+
+#: doc/classes/Color.xml:687
+msgid "Steel blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:690
+msgid "Tan color."
+msgstr ""
+
+#: doc/classes/Color.xml:693
+msgid "Teal color."
+msgstr ""
+
+#: doc/classes/Color.xml:696
+msgid "Thistle color."
+msgstr ""
+
+#: doc/classes/Color.xml:699
+msgid "Tomato color."
+msgstr ""
+
+#: doc/classes/Color.xml:702
+msgid "Transparent color (white with no alpha)."
+msgstr ""
+
+#: doc/classes/Color.xml:705
+msgid "Turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:708
+msgid "Violet color."
+msgstr ""
+
+#: doc/classes/Color.xml:711
+msgid "Web gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:714
+msgid "Web green color."
+msgstr ""
+
+#: doc/classes/Color.xml:717
+msgid "Web maroon color."
+msgstr ""
+
+#: doc/classes/Color.xml:720
+msgid "Web purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:723
+msgid "Wheat color."
+msgstr ""
+
+#: doc/classes/Color.xml:726
+msgid "White color."
+msgstr ""
+
+#: doc/classes/Color.xml:729
+msgid "White smoke color."
+msgstr ""
+
+#: doc/classes/Color.xml:732
+msgid "Yellow color."
+msgstr ""
+
+#: doc/classes/Color.xml:735
+msgid "Yellow green color."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:4
+msgid "Color picker control."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:7
+msgid ""
+"Displays a color picker widget. Useful for selecting a color from an RGB/"
+"RGBA colorspace."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:18
+msgid ""
+"Adds the given color to a list of color presets. The presets are displayed "
+"in the color picker and the user will be able to select them.\n"
+"[b]Note:[/b] the presets list is only for [i]this[/i] color picker."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:28
+msgid ""
+"Removes the given color from the list of color presets of this color picker."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:35
+msgid "Returns the list of colors in the presets of the color picker."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:41 doc/classes/ColorPickerButton.xml:29
+msgid "The currently selected color."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:44
+msgid ""
+"If [code]true[/code], the color will apply only after the user releases the "
+"mouse button, otherwise it will apply immediately even in mouse motion event "
+"(which can cause performance issues)."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:47
+msgid "If [code]true[/code], shows an alpha channel slider (transparency)."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:50
+msgid ""
+"If [code]true[/code], allows editing the color with Hue/Saturation/Value "
+"sliders.\n"
+"[b]Note:[/b] Cannot be enabled if raw mode is on."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:54
+msgid "If [code]true[/code], the \"add preset\" button is enabled."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:57
+msgid "If [code]true[/code], saved color presets are visible."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:60
+msgid ""
+"If [code]true[/code], allows the color R, G, B component values to go beyond "
+"1.0, which can be used for certain special operations that require it (like "
+"tinting without darkening or rendering sprites in HDR).\n"
+"[b]Note:[/b] Cannot be enabled if HSV mode is on."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:69
+msgid "Emitted when the color is changed."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:76
+msgid "Emitted when a preset is added."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:83
+msgid "Emitted when a preset is removed."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:91
+msgid "The icon for the \"Add Preset\" button."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:94
+msgid "Custom texture for the hue selection slider on the right."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:99
+msgid "The width of the hue selection slider."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:104
+msgid "The margin around the [ColorPicker]."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:107
+msgid ""
+"The indicator used to signalize that the color value is outside the 0-1 "
+"range."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:112
+msgid "The icon for the screen color picker button."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:115
+msgid "The height of the saturation-value selection box."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:118
+msgid "The width of the saturation-value selection box."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:4
+msgid "Button that pops out a [ColorPicker]."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:7
+msgid ""
+"Encapsulates a [ColorPicker] making it accessible by pressing a button. "
+"Pressing the button will toggle the [ColorPicker] visibility."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:16
+msgid "Returns the [ColorPicker] that this node toggles."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:23
+msgid ""
+"Returns the control's [PopupPanel] which allows you to connect to popup "
+"signals. This allows you to handle events when the ColorPicker is shown or "
+"hidden."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:32
+msgid ""
+"If [code]true[/code], the alpha channel in the displayed [ColorPicker] will "
+"be visible."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:41
+msgid "Emitted when the color changes."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:46
+msgid ""
+"Emitted when the [ColorPicker] is created (the button is pressed for the "
+"first time)."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:51
+msgid "Emitted when the [ColorPicker] is closed."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:59
+msgid "The background of the color preview rect on the button."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:62
+msgid "[StyleBox] used when the [ColorPickerButton] is disabled."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:65
+msgid ""
+"[StyleBox] used when the [ColorPickerButton] is focused. It is displayed "
+"over the current [StyleBox], so using [StyleBoxEmpty] will just disable the "
+"focus visual effect."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:68
+msgid "[Font] of the [ColorPickerButton]'s text."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:71
+msgid "Default text [Color] of the [ColorPickerButton]."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:74
+msgid "Text [Color] used when the [ColorPickerButton] is disabled."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:77
+msgid "Text [Color] used when the [ColorPickerButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:80
+msgid "Text [Color] used when the [ColorPickerButton] is being pressed."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:83
+msgid "[StyleBox] used when the [ColorPickerButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:86
+msgid "The horizontal space between [ColorPickerButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:89
+msgid "Default [StyleBox] for the [ColorPickerButton]."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:92
+msgid "[StyleBox] used when the [ColorPickerButton] is being pressed."
+msgstr ""
+
+#: doc/classes/ColorRect.xml:4
+msgid "Colored rectangle."
+msgstr ""
+
+#: doc/classes/ColorRect.xml:7
+msgid "Displays a colored rectangle."
+msgstr ""
+
+#: doc/classes/ColorRect.xml:15
+msgid ""
+"The fill color.\n"
+"[codeblock]\n"
+"$ColorRect.color = Color(1, 0, 0, 1) # Set ColorRect's color to red.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape2D.xml:4
+msgid "Concave polygon 2D shape resource for physics."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape2D.xml:7
+msgid ""
+"Concave polygon 2D shape resource for physics. It is made out of segments "
+"and is optimal for complex polygonal concave collisions. However, it is not "
+"advised to use for [RigidBody2D] nodes. A CollisionPolygon2D in convex "
+"decomposition mode (solids) or several convex objects are advised for that "
+"instead. Otherwise, a concave polygon 2D shape is better for static "
+"collisions.\n"
+"The main difference between a [ConvexPolygonShape2D] and a "
+"[ConcavePolygonShape2D] is that a concave polygon assumes it is concave and "
+"uses a more complex method of collision detection, and a convex one forces "
+"itself to be convex in order to speed up collision detection."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape2D.xml:16
+msgid ""
+"The array of points that make up the [ConcavePolygonShape2D]'s line segments."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:4
+msgid "Concave polygon shape."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:7
+msgid ""
+"Concave polygon shape resource, which can be set into a [PhysicsBody3D] or "
+"area. This shape is created by feeding a list of triangles.\n"
+"Note: when used for collision, [ConcavePolygonShape3D] is intended to work "
+"with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with "
+"[KinematicBody3D] or [RigidBody3D] with a mode other than Static."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:17
+msgid "Returns the faces (an array of triangles)."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:26
+msgid "Sets the faces (an array of triangles)."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:4
+msgid "A twist joint between two 3D bodies."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:7
+msgid ""
+"The joint can rotate the bodies across an axis defined by the local x-axes "
+"of the [Joint3D].\n"
+"The twist axis is initiated as the X axis of the [Joint3D].\n"
+"Once the Bodies swing, the twist axis is calculated as the middle of the x-"
+"axes of the Joint3D in the local space of the two Bodies."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:35 doc/classes/ConeTwistJoint3D.xml:67
+#: doc/classes/PhysicsServer3D.xml:1400
+msgid ""
+"The speed with which the swing or twist will take place.\n"
+"The higher, the faster."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:39 doc/classes/ConeTwistJoint3D.xml:74
+#: doc/classes/PhysicsServer3D.xml:1407
+msgid ""
+"Defines, how fast the swing- and twist-speed-difference on both sides gets "
+"synced."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:42 doc/classes/ConeTwistJoint3D.xml:71
+msgid ""
+"The ease with which the joint starts to twist. If it's too low, it takes "
+"more force to start twisting the joint."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:45 doc/classes/ConeTwistJoint3D.xml:57
+#: doc/classes/PhysicsServer3D.xml:1390
+msgid ""
+"Swing is rotation from side to side, around the axis perpendicular to the "
+"twist axis.\n"
+"The swing span defines, how much rotation will not get corrected along the "
+"swing axis.\n"
+"Could be defined as looseness in the [ConeTwistJoint3D].\n"
+"If below 0.05, this behavior is locked."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:51 doc/classes/ConeTwistJoint3D.xml:63
+#: doc/classes/PhysicsServer3D.xml:1396
+msgid ""
+"Twist is the rotation around the twist axis, this value defined how far the "
+"joint can twist.\n"
+"Twist is locked if below 0.05."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:77 doc/classes/Generic6DOFJoint3D.xml:404
+#: doc/classes/HingeJoint3D.xml:109 doc/classes/Light3D.xml:124
+#: doc/classes/SliderJoint3D.xml:170
+msgid "Represents the size of the [enum Param] enum."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:4
+msgid "Helper class to handle INI-style files."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:7
+msgid ""
+"This helper class can be used to store [Variant] values on the filesystem "
+"using INI-style formatting. The stored values are identified by a section "
+"and a key:\n"
+"[codeblock]\n"
+"[section]\n"
+"some_key=42\n"
+"string_example=\"Hello World3D!\"\n"
+"a_vector=Vector3( 1, 0, 2 )\n"
+"[/codeblock]\n"
+"The stored data can be saved to or parsed from a file, though ConfigFile "
+"objects can also be used directly without accessing the filesystem.\n"
+"The following example shows how to parse an INI-style file from the system, "
+"read its contents and store new values in it:\n"
+"[codeblock]\n"
+"var config = ConfigFile.new()\n"
+"var err = config.load(\"user://settings.cfg\")\n"
+"if err == OK: # If not, something went wrong with the file loading\n"
+" # Look for the display/width pair, and default to 1024 if missing\n"
+" var screen_width = config.get_value(\"display\", \"width\", 1024)\n"
+" # Store a variable if and only if it hasn't been defined yet\n"
+" if not config.has_section_key(\"audio\", \"mute\"):\n"
+" config.set_value(\"audio\", \"mute\", false)\n"
+" # Save the changes by overwriting the previous file\n"
+" config.save(\"user://settings.cfg\")\n"
+"[/codeblock]\n"
+"Keep in mind that section and property names can't contain spaces. Anything "
+"after a space will be ignored on save and on load.\n"
+"ConfigFiles can also contain manually written comment lines starting with a "
+"semicolon ([code];[/code]). Those lines will be ignored when parsing the "
+"file. Note that comments will be lost when saving the ConfigFile. This can "
+"still be useful for dedicated server configuration files, which are "
+"typically never overwritten without explicit user action."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:40
+msgid ""
+"Deletes the specified section along with all the key-value pairs inside. "
+"Raises an error if the section does not exist."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:51
+msgid ""
+"Deletes the specified key in a section. Raises an error if either the "
+"section or the key do not exist."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:60
+msgid ""
+"Returns an array of all defined key identifiers in the specified section. "
+"Raises an error and returns an empty array if the section does not exist."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:67
+msgid "Returns an array of all defined section identifiers."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:80
+msgid ""
+"Returns the current value for the specified section and key. If either the "
+"section or the key do not exist, the method returns the fallback "
+"[code]default[/code] value. If [code]default[/code] is not specified or set "
+"to [code]null[/code], an error is also raised."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:89
+msgid "Returns [code]true[/code] if the specified section exists."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:100
+msgid "Returns [code]true[/code] if the specified section-key pair exists."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:109
+msgid ""
+"Loads the config file specified as a parameter. The file's contents are "
+"parsed and loaded in the [ConfigFile] object which the method was called "
+"on.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:121
+msgid ""
+"Loads the encrypted config file specified as a parameter, using the provided "
+"[code]key[/code] to decrypt it. The file's contents are parsed and loaded in "
+"the [ConfigFile] object which the method was called on.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:133
+msgid ""
+"Loads the encrypted config file specified as a parameter, using the provided "
+"[code]password[/code] to decrypt it. The file's contents are parsed and "
+"loaded in the [ConfigFile] object which the method was called on.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:143
+msgid ""
+"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.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:153
+msgid ""
+"Saves the contents of the [ConfigFile] object to the file specified as a "
+"parameter. The output file uses an INI-style structure.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:165
+msgid ""
+"Saves the contents of the [ConfigFile] object to the AES-256 encrypted file "
+"specified as a parameter, using the provided [code]key[/code] to encrypt it. "
+"The output file uses an INI-style structure.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:177
+msgid ""
+"Saves the contents of the [ConfigFile] object to the AES-256 encrypted file "
+"specified as a parameter, using the provided [code]password[/code] to "
+"encrypt it. The output file uses an INI-style structure.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:191
+msgid ""
+"Assigns a value to the specified key of the specified section. If either the "
+"section or the key do not exist, they are created. Passing a [code]null[/"
+"code] value deletes the specified key if it exists, and deletes the section "
+"if it ends up empty once the key has been removed."
+msgstr ""
+
+#: doc/classes/ConfirmationDialog.xml:4
+msgid "Dialog for confirmation of actions."
+msgstr ""
+
+#: doc/classes/ConfirmationDialog.xml:7
+msgid ""
+"Dialog for confirmation of actions. This dialog inherits from "
+"[AcceptDialog], but has by default an OK and Cancel button (in host OS "
+"order).\n"
+"To get cancel action, you can use:\n"
+"[codeblock]\n"
+"get_cancel().connect(\"pressed\", self, \"cancelled\")\n"
+"[/codeblock]."
+msgstr ""
+
+#: doc/classes/ConfirmationDialog.xml:20
+msgid "Returns the cancel button."
+msgstr ""
+
+#: doc/classes/Container.xml:4
+msgid "Base node for containers."
+msgstr ""
+
+#: doc/classes/Container.xml:7
+msgid ""
+"Base node for containers. A [Container] contains other controls and "
+"automatically arranges them in a certain way.\n"
+"A Control can inherit this to create custom container classes."
+msgstr ""
+
+#: doc/classes/Container.xml:21
+msgid ""
+"Fit a child control in a given rect. This is mainly a helper for creating "
+"custom container classes."
+msgstr ""
+
+#: doc/classes/Container.xml:28
+msgid ""
+"Queue resort of the contained children. This is called automatically anyway, "
+"but can be called upon request."
+msgstr ""
+
+#: doc/classes/Container.xml:38
+msgid "Emitted when sorting the children is needed."
+msgstr ""
+
+#: doc/classes/Container.xml:44
+msgid ""
+"Notification for when sorting the children, it must be obeyed immediately."
+msgstr ""
+
+#: doc/classes/Control.xml:4
+msgid ""
+"All user interface nodes inherit from Control. A control's anchors and "
+"margins adapt its position and size relative to its parent."
+msgstr ""
+
+#: doc/classes/Control.xml:7
+msgid ""
+"Base class for all UI-related nodes. [Control] features a bounding rectangle "
+"that defines its extents, an anchor position relative to its parent control "
+"or the current viewport, and margins that represent an offset to the anchor. "
+"The margins update automatically when the node, any of its parents, or the "
+"screen size change.\n"
+"For more information on Godot's UI system, anchors, margins, and containers, "
+"see the related tutorials in the manual. To build flexible UIs, you'll need "
+"a mix of UI elements that inherit from [Control] and [Container] nodes.\n"
+"[b]User Interface nodes and input[/b]\n"
+"Godot sends input events to the scene's root node first, by calling [method "
+"Node._input]. [method Node._input] forwards the event down the node tree to "
+"the nodes under the mouse cursor, or on keyboard focus. To do so, it calls "
+"[code]MainLoop._input_event[/code].\n"
+"[b]FIXME:[/b] No longer valid after DisplayServer split and Input "
+"refactoring.\n"
+"Call [method accept_event] so no other node receives the event. Once you "
+"accepted an input, it becomes handled so [method Node._unhandled_input] will "
+"not process it.\n"
+"Only one [Control] node can be in keyboard focus. Only the node in focus "
+"will receive keyboard events. To get the focus, call [method grab_focus]. "
+"[Control] nodes lose focus when another node grabs it, or if you hide the "
+"node in focus.\n"
+"Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a "
+"[Control] node to ignore mouse or touch events. You'll need it if you place "
+"an icon on top of a button.\n"
+"[Theme] resources change the Control's appearance. If you change the [Theme] "
+"on a [Control] node, it affects all of its children. To override some of the "
+"theme's parameters, call one of the [code]add_theme_*_override[/code] "
+"methods, like [method add_theme_font_override]. You can override the theme "
+"with the inspector."
+msgstr ""
+
+#: doc/classes/Control.xml:18
+msgid "https://docs.godotengine.org/en/latest/tutorials/gui/index.html"
+msgstr ""
+
+#: doc/classes/Control.xml:26
+msgid ""
+"Virtual method to be implemented by the user. Returns whether [method "
+"_gui_input] should not be called for children controls outside this "
+"control's rectangle. Input will be clipped to the Rect of this [Control]. "
+"Similar to [member rect_clip_content], but doesn't affect visibility.\n"
+"If not overridden, defaults to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:34
+msgid ""
+"Virtual method to be implemented by the user. Returns the minimum size for "
+"this control. Alternative to [member rect_min_size] for controlling minimum "
+"size via code. The actual minimum size will be the max value of these two "
+"(in each axis separately).\n"
+"If not overridden, defaults to [constant Vector2.ZERO]."
+msgstr ""
+
+#: doc/classes/Control.xml:44
+msgid ""
+"Virtual method to be implemented by the user. Use this method to process and "
+"accept inputs on UI elements. See [method accept_event].\n"
+"Example: clicking a control.\n"
+"[codeblock]\n"
+"func _gui_input(event):\n"
+" if event is InputEventMouseButton:\n"
+" if event.button_index == BUTTON_LEFT and event.pressed:\n"
+" print(\"I've been clicked D:\")\n"
+"[/codeblock]\n"
+"The event won't trigger if:\n"
+"* clicking outside the control (see [method has_point]);\n"
+"* control has [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];\n"
+"* control is obstructed by another [Control] on top of it, which doesn't "
+"have [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];\n"
+"* control's parent has [member mouse_filter] set to [constant "
+"MOUSE_FILTER_STOP] or has accepted the event;\n"
+"* it happens outside parent's rectangle and the parent has either [member "
+"rect_clip_content] or [method _clips_input] enabled."
+msgstr ""
+
+#: doc/classes/Control.xml:66
+msgid ""
+"Virtual method to be implemented by the user. Returns a [Control] node that "
+"should be used as a tooltip instead of the default one. Use [code]for_text[/"
+"code] parameter to determine what text the tooltip should contain (likely "
+"the contents of [member hint_tooltip]).\n"
+"The returned node must be of type [Control] or Control-derieved. It can have "
+"child nodes of any type. It is freed when the tooltip disappears, so make "
+"sure you always provide a new instance, not e.g. a node from scene. When "
+"[code]null[/code] or non-Control node is returned, the default tooltip will "
+"be used instead.\n"
+"[b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure "
+"it's fully visible, you might want to set its [member rect_min_size] to some "
+"non-zero value.\n"
+"Example of usage with custom-constructed node:\n"
+"[codeblock]\n"
+"func _make_custom_tooltip(for_text):\n"
+" var label = Label.new()\n"
+" label.text = for_text\n"
+" return label\n"
+"[/codeblock]\n"
+"Example of usage with custom scene instance:\n"
+"[codeblock]\n"
+"func _make_custom_tooltip(for_text):\n"
+" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n"
+" tooltip.get_node(\"Label\").text = for_text\n"
+" return tooltip\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:89
+msgid ""
+"Marks an input event as handled. Once you accept an input event, it stops "
+"propagating, even to nodes listening to [method Node._unhandled_input] or "
+"[method Node._unhandled_key_input]."
+msgstr ""
+
+#: doc/classes/Control.xml:100
+msgid ""
+"Overrides the [Color] with given [code]name[/code] in the [member theme] "
+"resource the control uses. If the [code]color[/code] is empty or invalid, "
+"the override is cleared and the color from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:111
+msgid ""
+"Overrides an integer constant with given [code]name[/code] in the [member "
+"theme] resource the control uses. If the [code]constant[/code] is empty or "
+"invalid, the override is cleared and the constant from assigned [Theme] is "
+"used."
+msgstr ""
+
+#: doc/classes/Control.xml:122
+msgid ""
+"Overrides the font with given [code]name[/code] in the [member theme] "
+"resource the control uses. If [code]font[/code] is empty or invalid, the "
+"override is cleared and the font from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:133
+msgid ""
+"Overrides the icon with given [code]name[/code] in the [member theme] "
+"resource the control uses. If [code]icon[/code] is empty or invalid, the "
+"override is cleared and the icon from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:144
+msgid ""
+"Overrides the [Shader] with given [code]name[/code] in the [member theme] "
+"resource the control uses. If [code]shader[/code] is empty or invalid, the "
+"override is cleared and the shader from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:155
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Control.xml:166
+msgid ""
+"Godot calls this method to test if [code]data[/code] from a control's "
+"[method get_drag_data] can be dropped at [code]position[/code]. "
+"[code]position[/code] is local to this control.\n"
+"This method should only be used to test the data. Process the data in "
+"[method drop_data].\n"
+"[codeblock]\n"
+"func can_drop_data(position, data):\n"
+" # Check position if it is relevant to you\n"
+" # Otherwise, just check data\n"
+" return typeof(data) == TYPE_DICTIONARY and data.has(\"expected\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:184
+msgid ""
+"Godot calls this method to pass you the [code]data[/code] from a control's "
+"[method get_drag_data] result. Godot first calls [method can_drop_data] to "
+"test if [code]data[/code] is allowed to drop at [code]position[/code] where "
+"[code]position[/code] is local to this control.\n"
+"[codeblock]\n"
+"func can_drop_data(position, data):\n"
+" return typeof(data) == TYPE_DICTIONARY and data.has(\"color\")\n"
+"\n"
+"func drop_data(position, data):\n"
+" color = data[\"color\"]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:202
+msgid ""
+"Forces drag and bypasses [method get_drag_data] and [method "
+"set_drag_preview] by passing [code]data[/code] and [code]preview[/code]. "
+"Drag will start even if the mouse is neither over nor pressed on this "
+"control.\n"
+"The methods [method can_drop_data] and [method drop_data] must be "
+"implemented on controls that want to receive drop data."
+msgstr ""
+
+#: doc/classes/Control.xml:212
+msgid ""
+"Returns the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum. A getter method for [member anchor_bottom], [member "
+"anchor_left], [member anchor_right] and [member anchor_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:219
+msgid ""
+"Returns [member margin_left] and [member margin_top]. See also [member "
+"rect_position]."
+msgstr ""
+
+#: doc/classes/Control.xml:226
+msgid ""
+"Returns combined minimum size from [member rect_min_size] and [method "
+"get_minimum_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:235
+msgid ""
+"Returns the mouse cursor shape the control displays on mouse hover. See "
+"[enum CursorShape]."
+msgstr ""
+
+#: doc/classes/Control.xml:244
+msgid ""
+"Godot calls this method to get data that can be dragged and dropped onto "
+"controls that expect drop data. Returns [code]null[/code] if there is no "
+"data to drag. Controls that want to receive drop data should implement "
+"[method can_drop_data] and [method drop_data]. [code]position[/code] is "
+"local to this control. Drag may be forced with [method force_drag].\n"
+"A preview that will follow the mouse that should represent the data can be "
+"set with [method set_drag_preview]. A good time to set the preview is in "
+"this method.\n"
+"[codeblock]\n"
+"func get_drag_data(position):\n"
+" var mydata = make_data()\n"
+" set_drag_preview(make_preview(mydata))\n"
+" return mydata\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:258
+msgid "Returns [member margin_right] and [member margin_bottom]."
+msgstr ""
+
+#: doc/classes/Control.xml:267
+msgid ""
+"Returns the focus neighbour identified by [code]margin[/code] constant from "
+"[enum Margin] enum. A getter method for [member focus_neighbour_bottom], "
+"[member focus_neighbour_left], [member focus_neighbour_right] and [member "
+"focus_neighbour_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:274
+msgid ""
+"Returns the control that has the keyboard focus or [code]null[/code] if none."
+msgstr ""
+
+#: doc/classes/Control.xml:281
+msgid ""
+"Returns the position and size of the control relative to the top-left corner "
+"of the screen. See [member rect_position] and [member rect_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:290
+msgid ""
+"Returns the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum. A getter method for [member margin_bottom], [member "
+"margin_left], [member margin_right] and [member margin_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:297
+msgid "Returns the minimum size for this control. See [member rect_min_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:304
+msgid "Returns the width/height occupied in the parent control."
+msgstr ""
+
+#: doc/classes/Control.xml:311
+msgid "Returns the parent control node."
+msgstr ""
+
+#: doc/classes/Control.xml:318
+msgid ""
+"Returns the position and size of the control relative to the top-left corner "
+"of the parent Control. See [member rect_position] and [member rect_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:325
+msgid "Returns the rotation (in radians)."
+msgstr ""
+
+#: doc/classes/Control.xml:336
+msgid ""
+"Returns a color from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code].\n"
+"[codeblock]\n"
+"func _ready():\n"
+" modulate = get_theme_color(\"font_color\", \"Button\") #get the color "
+"defined for button fonts\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:351
+msgid ""
+"Returns a constant from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:362
+msgid ""
+"Returns a font from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:373
+msgid ""
+"Returns an icon from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:384
+msgid ""
+"Returns a [StyleBox] from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:393
+msgid ""
+"Returns the tooltip, which will appear when the cursor is resting over this "
+"control. See [member hint_tooltip]."
+msgstr ""
+
+#: doc/classes/Control.xml:400
+msgid ""
+"Creates an [InputEventMouseButton] that attempts to click the control. If "
+"the event is received, the control acquires focus.\n"
+"[codeblock]\n"
+"func _process(delta):\n"
+" grab_click_focus() #when clicking another Control node, this node will "
+"be clicked instead\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:411
+msgid ""
+"Steal the focus from another control and become the focused control (see "
+"[member focus_mode])."
+msgstr ""
+
+#: doc/classes/Control.xml:418
+msgid ""
+"Returns [code]true[/code] if this is the current focused control. See "
+"[member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:427
+msgid ""
+"Virtual method to be implemented by the user. Returns whether the given "
+"[code]point[/code] is inside this control.\n"
+"If not overridden, default behavior is checking if the point is within "
+"control's Rect.\n"
+"[b]Note:[/b] If you want to check if a point is inside the control, you can "
+"use [code]get_rect().has_point(point)[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:440
+msgid ""
+"Returns [code]true[/code] if [Color] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:449
+msgid ""
+"Returns [code]true[/code] if [Color] with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:460
+msgid ""
+"Returns [code]true[/code] if constant with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:469
+msgid ""
+"Returns [code]true[/code] if constant with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:480
+msgid ""
+"Returns [code]true[/code] if font with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:489
+msgid ""
+"Returns [code]true[/code] if font with given [code]name[/code] has a valid "
+"override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:500
+msgid ""
+"Returns [code]true[/code] if icon with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:509
+msgid ""
+"Returns [code]true[/code] if icon with given [code]name[/code] has a valid "
+"override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:518
+msgid ""
+"Returns [code]true[/code] if [Shader] with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:529
+msgid ""
+"Returns [code]true[/code] if [StyleBox] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:538
+msgid ""
+"Returns [code]true[/code] if [StyleBox] with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:545
+msgid ""
+"Invalidates the size cache in this node and in parent nodes up to toplevel. "
+"Intended to be used with [method get_minimum_size] when the return value is "
+"changed. Setting [member rect_min_size] directly calls this method "
+"automatically."
+msgstr ""
+
+#: doc/classes/Control.xml:552
+msgid ""
+"Give up the focus. No other control will be able to receive keyboard input."
+msgstr ""
+
+#: doc/classes/Control.xml:567
+msgid ""
+"Sets the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum to value [code]anchor[/code]. A setter method for [member "
+"anchor_bottom], [member anchor_left], [member anchor_right] and [member "
+"anchor_top].\n"
+"If [code]keep_margin[/code] is [code]true[/code], margins aren't updated "
+"after this operation.\n"
+"If [code]push_opposite_anchor[/code] is [code]true[/code] and the opposite "
+"anchor overlaps this anchor, the opposite one will have its value "
+"overridden. For example, when setting left anchor to 1 and the right anchor "
+"has value of 0.5, the right anchor will also get value of 1. If "
+"[code]push_opposite_anchor[/code] was [code]false[/code], the left anchor "
+"would get value 0.5."
+msgstr ""
+
+#: doc/classes/Control.xml:584
+msgid ""
+"Works the same as [method set_anchor], but instead of [code]keep_margin[/"
+"code] argument and automatic update of margin, it allows to set the margin "
+"offset yourself (see [method set_margin])."
+msgstr ""
+
+#: doc/classes/Control.xml:597
+msgid ""
+"Sets both anchor preset and margin preset. See [method set_anchors_preset] "
+"and [method set_margins_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:608
+msgid ""
+"Sets the anchors to a [code]preset[/code] from [enum Control.LayoutPreset] "
+"enum. This is code equivalent of using the Layout menu in 2D editor.\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's position will "
+"also be updated."
+msgstr ""
+
+#: doc/classes/Control.xml:618
+msgid ""
+"Sets [member margin_left] and [member margin_top] at the same time. "
+"Equivalent of changing [member rect_position]."
+msgstr ""
+
+#: doc/classes/Control.xml:627
+msgid ""
+"Forwards the handling of this control's drag and drop to [code]target[/code] "
+"control.\n"
+"Forwarding can be implemented in the target control similar to the methods "
+"[method get_drag_data], [method can_drop_data], and [method drop_data] but "
+"with two differences:\n"
+"1. The function name must be suffixed with [b]_fw[/b]\n"
+"2. The function must take an extra argument that is the control doing the "
+"forwarding\n"
+"[codeblock]\n"
+"# ThisControl.gd\n"
+"extends Control\n"
+"func _ready():\n"
+" set_drag_forwarding(target_control)\n"
+"\n"
+"# TargetControl.gd\n"
+"extends Control\n"
+"func can_drop_data_fw(position, data, from_control):\n"
+" return true\n"
+"\n"
+"func drop_data_fw(position, data, from_control):\n"
+" my_handle_data(data)\n"
+"\n"
+"func get_drag_data_fw(position, from_control):\n"
+" set_drag_preview(my_preview)\n"
+" return my_data()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:657
+msgid ""
+"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.\n"
+"[codeblock]\n"
+"export (Color, RGBA) var color = Color(1, 0, 0, 1)\n"
+"\n"
+"func get_drag_data(position):\n"
+" # Use a control that is not in the tree\n"
+" var cpb = ColorPickerButton.new()\n"
+" cpb.color = color\n"
+" cpb.rect_size = Vector2(50, 50)\n"
+" set_drag_preview(cpb)\n"
+" return color\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:677
+msgid "Sets [member margin_right] and [member margin_bottom] at the same time."
+msgstr ""
+
+#: doc/classes/Control.xml:688
+msgid ""
+"Sets the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum to [Control] at [code]neighbor[/code] node path. A setter "
+"method for [member focus_neighbour_bottom], [member focus_neighbour_left], "
+"[member focus_neighbour_right] and [member focus_neighbour_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:699
+msgid ""
+"Sets the [member rect_global_position] to given [code]position[/code].\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's anchors will be "
+"updated instead of margins."
+msgstr ""
+
+#: doc/classes/Control.xml:711
+msgid ""
+"Sets the margin identified by [code]margin[/code] constant from [enum "
+"Margin] enum to given [code]offset[/code]. A setter method for [member "
+"margin_bottom], [member margin_left], [member margin_right] and [member "
+"margin_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:724
+msgid ""
+"Sets the margins to a [code]preset[/code] from [enum Control.LayoutPreset] "
+"enum. This is code equivalent of using the Layout menu in 2D editor.\n"
+"Use parameter [code]resize_mode[/code] with constants from [enum Control."
+"LayoutPresetMode] to better determine the resulting size of the [Control]. "
+"Constant size will be ignored if used with presets that change size, e.g. "
+"[code]PRESET_LEFT_WIDE[/code].\n"
+"Use parameter [code]margin[/code] to determine the gap between the [Control] "
+"and the edges."
+msgstr ""
+
+#: doc/classes/Control.xml:737
+msgid ""
+"Sets the [member rect_position] to given [code]position[/code].\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's anchors will be "
+"updated instead of margins."
+msgstr ""
+
+#: doc/classes/Control.xml:747
+msgid "Sets the rotation (in radians)."
+msgstr ""
+
+#: doc/classes/Control.xml:758
+msgid ""
+"Sets the size (see [member rect_size]).\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's anchors will be "
+"updated instead of margins."
+msgstr ""
+
+#: doc/classes/Control.xml:768
+msgid ""
+"Moves the mouse cursor to [code]to_position[/code], relative to [member "
+"rect_position] of this [Control]."
+msgstr ""
+
+#: doc/classes/Control.xml:774
+msgid ""
+"Anchors the bottom edge of the node to the origin, the center, or the end of "
+"its parent control. It changes how the bottom margin updates when the node "
+"moves or changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:777
+msgid ""
+"Anchors the left edge of the node to the origin, the center or the end of "
+"its parent control. It changes how the left margin updates when the node "
+"moves or changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:780
+msgid ""
+"Anchors the right edge of the node to the origin, the center or the end of "
+"its parent control. It changes how the right margin updates when the node "
+"moves or changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:783
+msgid ""
+"Anchors the top edge of the node to the origin, the center or the end of its "
+"parent control. It changes how the top margin updates when the node moves or "
+"changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:786
+msgid ""
+"The focus access mode for the control (None, Click or All). Only one Control "
+"can be focused at the same time, and it will receive keyboard signals."
+msgstr ""
+
+#: doc/classes/Control.xml:789
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the down arrow on the keyboard or down on a gamepad by default. You can "
+"change the key by editing the [code]ui_down[/code] input action. The node "
+"must be a [Control]. If this property is not set, Godot will give focus to "
+"the closest [Control] to the bottom of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:792
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the left arrow on the keyboard or left on a gamepad by default. You can "
+"change the key by editing the [code]ui_left[/code] input action. The node "
+"must be a [Control]. If this property is not set, Godot will give focus to "
+"the closest [Control] to the left of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:795
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the right arrow on the keyboard or right on a gamepad by default. You can "
+"change the key by editing the [code]ui_right[/code] input action. The node "
+"must be a [Control]. If this property is not set, Godot will give focus to "
+"the closest [Control] to the bottom of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:798
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the top arrow on the keyboard or top on a gamepad by default. You can change "
+"the key by editing the [code]ui_top[/code] input action. The node must be a "
+"[Control]. If this property is not set, Godot will give focus to the closest "
+"[Control] to the bottom of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:801
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"Tab on a keyboard by default. You can change the key by editing the "
+"[code]ui_focus_next[/code] input action.\n"
+"If this property is not set, Godot will select a \"best guess\" based on "
+"surrounding nodes in the scene tree."
+msgstr ""
+
+#: doc/classes/Control.xml:805
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"Shift+Tab on a keyboard by default. You can change the key by editing the "
+"[code]ui_focus_prev[/code] input action.\n"
+"If this property is not set, Godot will select a \"best guess\" based on "
+"surrounding nodes in the scene tree."
+msgstr ""
+
+#: doc/classes/Control.xml:809
+msgid ""
+"Controls the direction on the horizontal axis in which the control should "
+"grow if its horizontal minimum size is changed to be greater than its "
+"current size, as the control always has to be at least the minimum size."
+msgstr ""
+
+#: doc/classes/Control.xml:812
+msgid ""
+"Controls the direction on the vertical axis in which the control should grow "
+"if its vertical minimum size is changed to be greater than its current size, "
+"as the control always has to be at least the minimum size."
+msgstr ""
+
+#: doc/classes/Control.xml:815
+msgid ""
+"Changes the tooltip text. The tooltip appears when the user's mouse cursor "
+"stays idle over this control for a few moments, provided that the [member "
+"mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. You can change "
+"the time required for the tooltip to appear with [code]gui/timers/"
+"tooltip_delay_sec[/code] option in Project Settings."
+msgstr ""
+
+#: doc/classes/Control.xml:818
+msgid ""
+"Distance between the node's bottom edge and its parent control, based on "
+"[member anchor_bottom].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:822
+msgid ""
+"Distance between the node's left edge and its parent control, based on "
+"[member anchor_left].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:826
+msgid ""
+"Distance between the node's right edge and its parent control, based on "
+"[member anchor_right].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:830
+msgid ""
+"Distance between the node's top edge and its parent control, based on "
+"[member anchor_top].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:834
+msgid ""
+"The default cursor shape for this control. Useful for Godot plugins and "
+"applications or games that use the system's mouse cursors.\n"
+"[b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the "
+"system."
+msgstr ""
+
+#: doc/classes/Control.xml:838
+msgid ""
+"Controls whether the control will be able to receive mouse button input "
+"events through [method _gui_input] and how these events should be handled. "
+"Also controls whether the control can receive the [signal mouse_entered], "
+"and [signal mouse_exited] signals. See the constants to learn what each does."
+msgstr ""
+
+#: doc/classes/Control.xml:841
+msgid ""
+"Enables whether rendering of children should be clipped to this control's "
+"rectangle. If [code]true[/code], parts of a child which would be visibly "
+"outside of this control's rectangle will not be rendered."
+msgstr ""
+
+#: doc/classes/Control.xml:844
+msgid ""
+"The node's global position, relative to the world (usually to the top-left "
+"corner of the window)."
+msgstr ""
+
+#: doc/classes/Control.xml:847
+msgid ""
+"The minimum size of the node's bounding rectangle. If you set it to a value "
+"greater than (0, 0), the node's bounding rectangle will always have at least "
+"this size, even if its content is smaller. If it's set to (0, 0), the node "
+"sizes automatically to fit its content, be it a texture or child nodes."
+msgstr ""
+
+#: doc/classes/Control.xml:850
+msgid ""
+"By default, the node's pivot is its top-left corner. When you change its "
+"[member rect_scale], it will scale around this pivot. Set this property to "
+"[member rect_size] / 2 to center the pivot in the node's rectangle."
+msgstr ""
+
+#: doc/classes/Control.xml:853
+msgid ""
+"The node's position, relative to its parent. It corresponds to the "
+"rectangle's top-left corner. The property is not affected by [member "
+"rect_pivot_offset]."
+msgstr ""
+
+#: doc/classes/Control.xml:856
+msgid ""
+"The node's rotation around its pivot, in degrees. See [member "
+"rect_pivot_offset] to change the pivot's position."
+msgstr ""
+
+#: doc/classes/Control.xml:859
+msgid ""
+"The node's scale, relative to its [member rect_size]. Change this property "
+"to scale the node around its [member rect_pivot_offset]."
+msgstr ""
+
+#: doc/classes/Control.xml:862
+msgid ""
+"The size of the node's bounding rectangle, in pixels. [Container] nodes "
+"update this property automatically."
+msgstr ""
+
+#: doc/classes/Control.xml:865
+msgid ""
+"Tells the parent [Container] nodes how they should resize and place the node "
+"on the X axis. Use one of the [enum SizeFlags] constants to change the "
+"flags. See the constants to learn what each does."
+msgstr ""
+
+#: doc/classes/Control.xml:868
+msgid ""
+"If the node and at least one of its neighbours uses the [constant "
+"SIZE_EXPAND] size flag, the parent [Container] will let it take more or less "
+"space depending on this property. If this node has a stretch ratio of 2 and "
+"its neighbour a ratio of 1, this node will take two thirds of the available "
+"space."
+msgstr ""
+
+#: doc/classes/Control.xml:871
+msgid ""
+"Tells the parent [Container] nodes how they should resize and place the node "
+"on the Y axis. Use one of the [enum SizeFlags] constants to change the "
+"flags. See the constants to learn what each does."
+msgstr ""
+
+#: doc/classes/Control.xml:874
+msgid ""
+"Changing this property replaces the current [Theme] resource this node and "
+"all its [Control] children use."
+msgstr ""
+
+#: doc/classes/Control.xml:880
+msgid "Emitted when the node gains keyboard focus."
+msgstr ""
+
+#: doc/classes/Control.xml:885
+msgid "Emitted when the node loses keyboard focus."
+msgstr ""
+
+#: doc/classes/Control.xml:892
+msgid "Emitted when the node receives an [InputEvent]."
+msgstr ""
+
+#: doc/classes/Control.xml:897
+msgid "Emitted when the node's minimum size changes."
+msgstr ""
+
+#: doc/classes/Control.xml:902
+msgid ""
+"Emitted when the mouse enters the control's [code]Rect[/code] area, provided "
+"its [member mouse_filter] lets the event reach it."
+msgstr ""
+
+#: doc/classes/Control.xml:907
+msgid ""
+"Emitted when the mouse leaves the control's [code]Rect[/code] area, provided "
+"its [member mouse_filter] lets the event reach it."
+msgstr ""
+
+#: doc/classes/Control.xml:912
+msgid "Emitted when the control changes size."
+msgstr ""
+
+#: doc/classes/Control.xml:917
+msgid ""
+"Emitted when one of the size flags changes. See [member "
+"size_flags_horizontal] and [member size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:927
+msgid "The node cannot grab focus. Use with [member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:930
+msgid ""
+"The node can only grab focus on mouse clicks. Use with [member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:933
+msgid ""
+"The node can grab focus on mouse click or using the arrows and the Tab keys "
+"on the keyboard. Use with [member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:936
+msgid ""
+"Sent when the node changes size. Use [member rect_size] to get the new size."
+msgstr ""
+
+#: doc/classes/Control.xml:939
+msgid "Sent when the mouse pointer enters the node."
+msgstr ""
+
+#: doc/classes/Control.xml:942
+msgid "Sent when the mouse pointer exits the node."
+msgstr ""
+
+#: doc/classes/Control.xml:945
+msgid "Sent when the node grabs focus."
+msgstr ""
+
+#: doc/classes/Control.xml:948
+msgid "Sent when the node loses focus."
+msgstr ""
+
+#: doc/classes/Control.xml:951
+msgid ""
+"Sent when the node's [member theme] changes, right before Godot redraws the "
+"control. Happens when you call one of the [code]add_theme_*_override[/code] "
+"methods."
+msgstr ""
+
+#: doc/classes/Control.xml:954
+msgid ""
+"Sent when this node is inside a [ScrollContainer] which has begun being "
+"scrolled."
+msgstr ""
+
+#: doc/classes/Control.xml:957
+msgid ""
+"Sent when this node is inside a [ScrollContainer] which has stopped being "
+"scrolled."
+msgstr ""
+
+#: doc/classes/Control.xml:960
+msgid ""
+"Show the system's arrow mouse cursor when the user hovers the node. Use with "
+"[member mouse_default_cursor_shape]."
+msgstr ""
+
+#: doc/classes/Control.xml:963
+msgid ""
+"Show the system's I-beam mouse cursor when the user hovers the node. The I-"
+"beam pointer has a shape similar to \"I\". It tells the user they can "
+"highlight or insert text."
+msgstr ""
+
+#: doc/classes/Control.xml:966
+msgid ""
+"Show the system's pointing hand mouse cursor when the user hovers the node."
+msgstr ""
+
+#: doc/classes/Control.xml:969
+msgid "Show the system's cross mouse cursor when the user hovers the node."
+msgstr ""
+
+#: doc/classes/Control.xml:972
+msgid ""
+"Show the system's wait mouse cursor, often an hourglass, when the user "
+"hovers the node."
+msgstr ""
+
+#: doc/classes/Control.xml:975
+msgid ""
+"Show the system's busy mouse cursor when the user hovers the node. Often an "
+"hourglass."
+msgstr ""
+
+#: doc/classes/Control.xml:978
+msgid ""
+"Show the system's drag mouse cursor, often a closed fist or a cross symbol, "
+"when the user hovers the node. It tells the user they're currently dragging "
+"an item, like a node in the Scene dock."
+msgstr ""
+
+#: doc/classes/Control.xml:981
+msgid ""
+"Show the system's drop mouse cursor when the user hovers the node. It can be "
+"an open hand. It tells the user they can drop an item they're currently "
+"grabbing, like a node in the Scene dock."
+msgstr ""
+
+#: doc/classes/Control.xml:984
+msgid ""
+"Show the system's forbidden mouse cursor when the user hovers the node. "
+"Often a crossed circle."
+msgstr ""
+
+#: doc/classes/Control.xml:987
+msgid ""
+"Show the system's vertical resize mouse cursor when the user hovers the "
+"node. A double-headed vertical arrow. It tells the user they can resize the "
+"window or the panel vertically."
+msgstr ""
+
+#: doc/classes/Control.xml:990
+msgid ""
+"Show the system's horizontal resize mouse cursor when the user hovers the "
+"node. A double-headed horizontal arrow. It tells the user they can resize "
+"the window or the panel horizontally."
+msgstr ""
+
+#: doc/classes/Control.xml:993
+msgid ""
+"Show the system's window resize mouse cursor when the user hovers the node. "
+"The cursor is a double-headed arrow that goes from the bottom left to the "
+"top right. It tells the user they can resize the window or the panel both "
+"horizontally and vertically."
+msgstr ""
+
+#: doc/classes/Control.xml:996
+msgid ""
+"Show the system's window resize mouse cursor when the user hovers the node. "
+"The cursor is a double-headed arrow that goes from the top left to the "
+"bottom right, the opposite of [constant CURSOR_BDIAGSIZE]. It tells the user "
+"they can resize the window or the panel both horizontally and vertically."
+msgstr ""
+
+#: doc/classes/Control.xml:999
+msgid ""
+"Show the system's move mouse cursor when the user hovers the node. It shows "
+"2 double-headed arrows at a 90 degree angle. It tells the user they can move "
+"a UI element freely."
+msgstr ""
+
+#: doc/classes/Control.xml:1002
+msgid ""
+"Show the system's vertical split mouse cursor when the user hovers the node. "
+"On Windows, it's the same as [constant CURSOR_VSIZE]."
+msgstr ""
+
+#: doc/classes/Control.xml:1005
+msgid ""
+"Show the system's horizontal split mouse cursor when the user hovers the "
+"node. On Windows, it's the same as [constant CURSOR_HSIZE]."
+msgstr ""
+
+#: doc/classes/Control.xml:1008
+msgid ""
+"Show the system's help mouse cursor when the user hovers the node, a "
+"question mark."
+msgstr ""
+
+#: doc/classes/Control.xml:1011
+msgid ""
+"Snap all 4 anchors to the top-left of the parent control's bounds. Use with "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1014
+msgid ""
+"Snap all 4 anchors to the top-right of the parent control's bounds. Use with "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1017
+msgid ""
+"Snap all 4 anchors to the bottom-left of the parent control's bounds. Use "
+"with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1020
+msgid ""
+"Snap all 4 anchors to the bottom-right of the parent control's bounds. Use "
+"with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1023
+msgid ""
+"Snap all 4 anchors to the center of the left edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1026
+msgid ""
+"Snap all 4 anchors to the center of the top edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1029
+msgid ""
+"Snap all 4 anchors to the center of the right edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1032
+msgid ""
+"Snap all 4 anchors to the center of the bottom edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1035
+msgid ""
+"Snap all 4 anchors to the center of the parent control's bounds. Use with "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1038
+msgid ""
+"Snap all 4 anchors to the left edge of the parent control. The left margin "
+"becomes relative to the left edge and the top margin relative to the top "
+"left corner of the node's parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1041
+msgid ""
+"Snap all 4 anchors to the top edge of the parent control. The left margin "
+"becomes relative to the top left corner, the top margin relative to the top "
+"edge, and the right margin relative to the top right corner of the node's "
+"parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1044
+msgid ""
+"Snap all 4 anchors to the right edge of the parent control. The right margin "
+"becomes relative to the right edge and the top margin relative to the top "
+"right corner of the node's parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1047
+msgid ""
+"Snap all 4 anchors to the bottom edge of the parent control. The left margin "
+"becomes relative to the bottom left corner, the bottom margin relative to "
+"the bottom edge, and the right margin relative to the bottom right corner of "
+"the node's parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1050
+msgid ""
+"Snap all 4 anchors to a vertical line that cuts the parent control in half. "
+"Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1053
+msgid ""
+"Snap all 4 anchors to a horizontal line that cuts the parent control in "
+"half. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1056
+msgid ""
+"Snap all 4 anchors to the respective corners of the parent control. Set all "
+"4 margins to 0 after you applied this preset and the [Control] will fit its "
+"parent control. This is equivalent to the \"Full Rect\" layout option in the "
+"editor. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1059
+msgid "The control will be resized to its minimum size."
+msgstr ""
+
+#: doc/classes/Control.xml:1062
+msgid "The control's width will not change."
+msgstr ""
+
+#: doc/classes/Control.xml:1065
+msgid "The control's height will not change."
+msgstr ""
+
+#: doc/classes/Control.xml:1068
+msgid "The control's size will not change."
+msgstr ""
+
+#: doc/classes/Control.xml:1071
+msgid ""
+"Tells the parent [Container] to expand the bounds of this node to fill all "
+"the available space without pushing any other node. Use with [member "
+"size_flags_horizontal] and [member size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1074
+msgid ""
+"Tells the parent [Container] to let this node take all the available space "
+"on the axis you flag. If multiple neighboring nodes are set to expand, "
+"they'll share the space based on their stretch ratio. See [member "
+"size_flags_stretch_ratio]. Use with [member size_flags_horizontal] and "
+"[member size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1077
+msgid ""
+"Sets the node's size flags to both fill and expand. See the 2 constants "
+"above for more information."
+msgstr ""
+
+#: doc/classes/Control.xml:1080
+msgid ""
+"Tells the parent [Container] to center the node in itself. It centers the "
+"control based on its bounding box, so it doesn't work with the fill or "
+"expand size flags. Use with [member size_flags_horizontal] and [member "
+"size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1083
+msgid ""
+"Tells the parent [Container] to align the node with its end, either the "
+"bottom or the right edge. It doesn't work with the fill or expand size "
+"flags. Use with [member size_flags_horizontal] and [member "
+"size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1086
+msgid ""
+"The control will receive mouse button input events through [method "
+"_gui_input] if clicked on. And the control will receive the [signal "
+"mouse_entered] and [signal mouse_exited] signals. These events are "
+"automatically marked as handled, and they will not propagate further to "
+"other controls. This also results in blocking signals in other controls."
+msgstr ""
+
+#: doc/classes/Control.xml:1089
+msgid ""
+"The control will receive mouse button input events through [method "
+"_gui_input] if clicked on. And the control will receive the [signal "
+"mouse_entered] and [signal mouse_exited] signals. If this control does not "
+"handle the event, the parent control (if any) will be considered, and so on "
+"until there is no more parent control to potentially handle it. This also "
+"allows signals to fire in other controls. Even if no control handled it at "
+"all, the event will still be handled automatically, so unhandled input will "
+"not be fired."
+msgstr ""
+
+#: doc/classes/Control.xml:1092
+msgid ""
+"The control will not receive mouse button input events through [method "
+"_gui_input]. The control will also not receive the [signal mouse_entered] "
+"nor [signal mouse_exited] signals. This will not block other controls from "
+"receiving these events or firing the signals. Ignored events will not be "
+"handled automatically."
+msgstr ""
+
+#: doc/classes/Control.xml:1095
+msgid ""
+"The control will grow to the left or top to make up if its minimum size is "
+"changed to be greater than its current size on the respective axis."
+msgstr ""
+
+#: doc/classes/Control.xml:1098
+msgid ""
+"The control will grow to the right or bottom to make up if its minimum size "
+"is changed to be greater than its current size on the respective axis."
+msgstr ""
+
+#: doc/classes/Control.xml:1101
+msgid ""
+"The control will grow in both directions equally to make up if its minimum "
+"size is changed to be greater than its current size."
+msgstr ""
+
+#: doc/classes/Control.xml:1104
+msgid ""
+"Snaps one of the 4 anchor's sides to the origin of the node's [code]Rect[/"
+"code], in the top left. Use it with one of the [code]anchor_*[/code] member "
+"variables, like [member anchor_left]. To change all 4 anchors at once, use "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1107
+msgid ""
+"Snaps one of the 4 anchor's sides to the end of the node's [code]Rect[/"
+"code], in the bottom right. Use it with one of the [code]anchor_*[/code] "
+"member variables, like [member anchor_left]. To change all 4 anchors at "
+"once, use [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:4
+msgid "Convex polygon shape for 2D physics."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:7
+msgid ""
+"Convex polygon shape for 2D physics. A convex polygon, whatever its shape, "
+"is internally decomposed into as many convex polygons as needed to ensure "
+"all collision checks against it are always done on convex polygons (which "
+"are faster to check).\n"
+"The main difference between a [ConvexPolygonShape2D] and a "
+"[ConcavePolygonShape2D] is that a concave polygon assumes it is concave and "
+"uses a more complex method of collision detection, and a convex one forces "
+"itself to be convex in order to speed up collision detection."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:19
+msgid ""
+"Based on the set of points provided, this creates and assigns the [member "
+"points] property using the convex hull algorithm. Removing all unneeded "
+"points. See [method Geometry.convex_hull_2d] for details."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:25
+msgid ""
+"The polygon's list of vertices. Can be in either clockwise or "
+"counterclockwise order."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape3D.xml:4
+msgid "Convex polygon shape for 3D physics."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape3D.xml:7
+msgid ""
+"Convex polygon shape resource, which can be added to a [PhysicsBody3D] or "
+"area."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape3D.xml:15
+msgid "The list of 3D points forming the convex polygon shape."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:4
+msgid "CPU-based 2D particle emitter."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:7
+msgid ""
+"CPU-based 2D particle node used to create a variety of particle systems and "
+"effects.\n"
+"See also [GPUParticles2D], which provides the same functionality with "
+"hardware acceleration, but may not run on older devices."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:11 doc/classes/GPUParticles2D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html"
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:20
+msgid ""
+"Sets this node's properties to match a given [GPUParticles2D] node with an "
+"assigned [ParticlesMaterial]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:29 doc/classes/CPUParticles3D.xml:28
+msgid "Returns the base value of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:38 doc/classes/CPUParticles3D.xml:37
+msgid "Returns the [Curve] of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:47 doc/classes/CPUParticles3D.xml:46
+msgid ""
+"Returns the randomness factor of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:56 doc/classes/CPUParticles3D.xml:55
+msgid ""
+"Returns the enabled state of the given flag (see [enum Flags] for options)."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:63 doc/classes/CPUParticles3D.xml:62
+msgid "Restarts the particle emitter."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:74 doc/classes/CPUParticles3D.xml:73
+msgid "Sets the base value of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:85 doc/classes/CPUParticles3D.xml:84
+msgid "Sets the [Curve] of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:96 doc/classes/CPUParticles3D.xml:95
+msgid ""
+"Sets the randomness factor of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:107 doc/classes/CPUParticles3D.xml:106
+msgid "Enables or disables the given flag (see [enum Flags] for options)."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:113 doc/classes/CPUParticles3D.xml:112
+#: doc/classes/GPUParticles2D.xml:31
+msgid "Number of particles emitted in one emission cycle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:116 doc/classes/CPUParticles3D.xml:115
+msgid "Initial rotation applied to each particle, in degrees."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:119 doc/classes/CPUParticles3D.xml:118
+msgid "Each particle's rotation will be animated along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:122 doc/classes/CPUParticles3D.xml:121
+#: doc/classes/ParticlesMaterial.xml:104
+msgid "Rotation randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:125 doc/classes/CPUParticles3D.xml:124
+msgid ""
+"Initial angular velocity applied to each particle. Sets the speed of "
+"rotation of the particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:128 doc/classes/CPUParticles3D.xml:127
+msgid "Each particle's angular velocity will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:131 doc/classes/CPUParticles3D.xml:130
+#: doc/classes/ParticlesMaterial.xml:114
+msgid "Angular velocity randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:134 doc/classes/CPUParticles3D.xml:133
+#: doc/classes/ParticlesMaterial.xml:117
+msgid "Particle animation offset."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:137 doc/classes/CPUParticles3D.xml:136
+msgid "Each particle's animation offset will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:140 doc/classes/CPUParticles3D.xml:139
+#: doc/classes/ParticlesMaterial.xml:123
+msgid "Animation offset randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:143 doc/classes/CPUParticles3D.xml:142
+#: doc/classes/ParticlesMaterial.xml:126
+msgid "Particle animation speed."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:146 doc/classes/CPUParticles3D.xml:145
+msgid "Each particle's animation speed will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:149 doc/classes/CPUParticles3D.xml:148
+#: doc/classes/ParticlesMaterial.xml:132
+msgid "Animation speed randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:152
+msgid ""
+"Each particle's initial color. If [member texture] is defined, it will be "
+"multiplied by this color."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:155
+msgid "Each particle's color will vary along this [Gradient]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:158 doc/classes/CPUParticles3D.xml:157
+#: doc/classes/ParticlesMaterial.xml:141
+msgid "The rate at which particles lose velocity."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:161 doc/classes/CPUParticles3D.xml:160
+msgid "Damping will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:164 doc/classes/CPUParticles3D.xml:163
+#: doc/classes/ParticlesMaterial.xml:147
+msgid "Damping randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:167 doc/classes/CPUParticles3D.xml:166
+#: doc/classes/ParticlesMaterial.xml:150
+msgid "Unit vector specifying the particles' emission direction."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:170 doc/classes/CPUParticles3D.xml:169
+#: doc/classes/GPUParticles2D.xml:34 doc/classes/GPUParticles3D.xml:54
+msgid "Particle draw order. Uses [enum DrawOrder] values."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:173 doc/classes/CPUParticles3D.xml:175
+msgid ""
+"Sets the [Color]s to modulate particles by when using [constant "
+"EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:176 doc/classes/CPUParticles3D.xml:178
+msgid ""
+"Sets the direction the particles will be emitted in when using [constant "
+"EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:179 doc/classes/CPUParticles3D.xml:181
+msgid ""
+"Sets the initial positions to spawn particles when using [constant "
+"EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:182
+msgid ""
+"The rectangle's extents if [member emission_shape] is set to [constant "
+"EMISSION_SHAPE_RECTANGLE]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:185 doc/classes/CPUParticles3D.xml:184
+msgid ""
+"Particles will be emitted inside this region. See [enum EmissionShape] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:188
+msgid ""
+"The sphere's radius if [member emission_shape] is set to [constant "
+"EMISSION_SHAPE_SPHERE]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:191 doc/classes/CPUParticles3D.xml:190
+#: doc/classes/GPUParticles2D.xml:37 doc/classes/GPUParticles3D.xml:72
+msgid "If [code]true[/code], particles are being emitted."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:194 doc/classes/CPUParticles3D.xml:193
+#: doc/classes/GPUParticles2D.xml:40
+msgid ""
+"How rapidly particles in an emission cycle are emitted. If greater than "
+"[code]0[/code], there will be a gap in emissions before the next cycle "
+"begins."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:197 doc/classes/GPUParticles2D.xml:43
+#: doc/classes/GPUParticles3D.xml:78
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:200 doc/classes/CPUParticles3D.xml:199
+#: doc/classes/ParticlesMaterial.xml:174
+msgid "Align Y axis of particle with the direction of its velocity."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:203 doc/classes/CPUParticles3D.xml:211
+#: doc/classes/GPUParticles2D.xml:46 doc/classes/GPUParticles3D.xml:81
+msgid ""
+"If [code]true[/code], results in fractional delta calculation which has a "
+"smoother particles display effect."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:206 doc/classes/CPUParticles3D.xml:214
+#: doc/classes/ParticlesMaterial.xml:186
+msgid "Gravity applied to every particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:209 doc/classes/CPUParticles3D.xml:217
+#: doc/classes/ParticlesMaterial.xml:189
+msgid "Initial hue variation applied to each particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:212 doc/classes/CPUParticles3D.xml:220
+msgid "Each particle's hue will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:215 doc/classes/CPUParticles3D.xml:223
+#: doc/classes/ParticlesMaterial.xml:195
+msgid "Hue variation randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:218 doc/classes/CPUParticles3D.xml:226
+#: doc/classes/ParticlesMaterial.xml:198
+msgid ""
+"Initial velocity magnitude for each particle. Direction comes from [member "
+"spread] and the node's orientation."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:221 doc/classes/CPUParticles3D.xml:229
+#: doc/classes/ParticlesMaterial.xml:201
+msgid "Initial velocity randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:224 doc/classes/CPUParticles3D.xml:232
+#: doc/classes/GPUParticles2D.xml:49 doc/classes/GPUParticles3D.xml:84
+msgid "Amount of time each particle will exist."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:227 doc/classes/CPUParticles3D.xml:235
+#: doc/classes/ParticlesMaterial.xml:204
+msgid "Particle lifetime randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:230 doc/classes/CPUParticles3D.xml:238
+#: doc/classes/ParticlesMaterial.xml:207
+msgid ""
+"Linear acceleration applied to each particle in the direction of motion."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:233 doc/classes/CPUParticles3D.xml:241
+msgid "Each particle's linear acceleration will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:236 doc/classes/CPUParticles3D.xml:244
+#: doc/classes/ParticlesMaterial.xml:213
+msgid "Linear acceleration randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:239 doc/classes/CPUParticles3D.xml:247
+#: doc/classes/GPUParticles2D.xml:52 doc/classes/GPUParticles3D.xml:87
+msgid ""
+"If [code]true[/code], particles use the parent node's coordinate space. If "
+"[code]false[/code], they use global coordinates."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:242 doc/classes/GPUParticles2D.xml:55
+msgid "Normal map to be used for the [member texture] property."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:245 doc/classes/CPUParticles3D.xml:253
+#: doc/classes/GPUParticles2D.xml:58
+msgid ""
+"If [code]true[/code], only one emission cycle occurs. If set [code]true[/"
+"code] during a cycle, emission will stop at the cycle's end."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:248
+msgid ""
+"Orbital velocity applied to each particle. Makes the particles circle around "
+"origin. Specified in number of full rotations around origin per second."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:251 doc/classes/CPUParticles3D.xml:260
+msgid "Each particle's orbital velocity will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:254 doc/classes/CPUParticles3D.xml:263
+#: doc/classes/ParticlesMaterial.xml:223
+msgid "Orbital velocity randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:257 doc/classes/CPUParticles3D.xml:266
+#: doc/classes/GPUParticles2D.xml:61
+msgid "Particle system starts as if it had already run for this many seconds."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:260 doc/classes/CPUParticles3D.xml:269
+#: doc/classes/ParticlesMaterial.xml:226
+msgid ""
+"Radial acceleration applied to each particle. Makes particle accelerate away "
+"from origin."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:263 doc/classes/CPUParticles3D.xml:272
+msgid "Each particle's radial acceleration will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:266 doc/classes/CPUParticles3D.xml:275
+#: doc/classes/ParticlesMaterial.xml:232
+msgid "Radial acceleration randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:269 doc/classes/CPUParticles3D.xml:278
+#: doc/classes/GPUParticles2D.xml:67
+msgid "Emission lifetime randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:272 doc/classes/CPUParticles3D.xml:281
+#: doc/classes/ParticlesMaterial.xml:235
+msgid "Initial scale applied to each particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:275 doc/classes/CPUParticles3D.xml:284
+msgid "Each particle's scale will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:278 doc/classes/CPUParticles3D.xml:287
+#: doc/classes/ParticlesMaterial.xml:241
+msgid "Scale randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:281 doc/classes/CPUParticles3D.xml:290
+#: doc/classes/GPUParticles2D.xml:70
+msgid ""
+"Particle system's running speed scaling ratio. A value of [code]0[/code] can "
+"be used to pause the particles."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:284
+msgid ""
+"Each particle's initial direction range from [code]+spread[/code] to [code]-"
+"spread[/code] degrees."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:287 doc/classes/CPUParticles3D.xml:296
+#: doc/classes/ParticlesMaterial.xml:247
+msgid ""
+"Tangential acceleration applied to each particle. Tangential acceleration is "
+"perpendicular to the particle's velocity giving the particles a swirling "
+"motion."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:290 doc/classes/CPUParticles3D.xml:299
+msgid "Each particle's tangential acceleration will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:293 doc/classes/CPUParticles3D.xml:302
+#: doc/classes/ParticlesMaterial.xml:253
+msgid "Tangential acceleration randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:296 doc/classes/GPUParticles2D.xml:73
+msgid "Particle texture. If [code]null[/code], particles will be squares."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:301 doc/classes/CPUParticles3D.xml:307
+#: doc/classes/GPUParticles2D.xml:81 doc/classes/GPUParticles3D.xml:110
+msgid "Particles are drawn in the order emitted."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:304 doc/classes/CPUParticles3D.xml:310
+#: doc/classes/GPUParticles2D.xml:84 doc/classes/GPUParticles3D.xml:113
+msgid "Particles are drawn in order of remaining lifetime."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:307 doc/classes/CPUParticles3D.xml:316
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set initial velocity properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:310 doc/classes/CPUParticles3D.xml:319
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set angular velocity properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:313 doc/classes/CPUParticles3D.xml:322
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set orbital velocity properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:316 doc/classes/CPUParticles3D.xml:325
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set linear acceleration properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:319 doc/classes/CPUParticles3D.xml:328
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set radial acceleration properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:322 doc/classes/CPUParticles3D.xml:331
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set tangential acceleration properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:325 doc/classes/CPUParticles3D.xml:334
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set damping properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:328 doc/classes/CPUParticles3D.xml:337
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set angle properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:331 doc/classes/CPUParticles3D.xml:340
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set scale properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:334 doc/classes/CPUParticles3D.xml:343
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set hue variation properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:337 doc/classes/CPUParticles3D.xml:346
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set animation speed properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:340 doc/classes/CPUParticles3D.xml:349
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set animation offset properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:343 doc/classes/CPUParticles3D.xml:352
+#: doc/classes/ParticlesMaterial.xml:303
+msgid "Represents the size of the [enum Parameter] enum."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:346 doc/classes/CPUParticles3D.xml:355
+msgid "Use with [method set_particle_flag] to set [member flag_align_y]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:349 doc/classes/CPUParticles2D.xml:352
+msgid "Present for consistency with 3D particle nodes, not used in 2D."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:358 doc/classes/CPUParticles3D.xml:367
+#: doc/classes/ParticlesMaterial.xml:318
+msgid "All particles will be emitted from a single point."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:361
+msgid ""
+"Particles will be emitted on the surface of a sphere flattened to two "
+"dimensions."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:364
+msgid "Particles will be emitted in the area of a rectangle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:367 doc/classes/CPUParticles3D.xml:376
+msgid ""
+"Particles will be emitted at a position chosen randomly among [member "
+"emission_points]. Particle color will be modulated by [member "
+"emission_colors]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:370 doc/classes/CPUParticles3D.xml:379
+msgid ""
+"Particles will be emitted at a position chosen randomly among [member "
+"emission_points]. Particle velocity and rotation will be set based on "
+"[member emission_normals]. Particle color will be modulated by [member "
+"emission_colors]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:373 doc/classes/CPUParticles3D.xml:382
+#: doc/classes/ParticlesMaterial.xml:333
+msgid "Represents the size of the [enum EmissionShape] enum."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:4
+msgid "CPU-based 3D particle emitter."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:7
+msgid ""
+"CPU-based 3D particle node used to create a variety of particle systems and "
+"effects.\n"
+"See also [GPUParticles3D], which provides the same functionality with "
+"hardware acceleration, but may not run on older devices."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:19
+msgid ""
+"Sets this node's properties to match a given [GPUParticles3D] node with an "
+"assigned [ParticlesMaterial]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:151 doc/classes/CPUParticles3D.xml:154
+msgid "Unused for 3D particles."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:172
+msgid ""
+"The rectangle's extents if [member emission_shape] is set to [constant "
+"EMISSION_SHAPE_BOX]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:187
+msgid ""
+"The sphere's radius if [enum EmissionShape] is set to [constant "
+"EMISSION_SHAPE_SPHERE]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:196
+msgid ""
+"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 particle system itself."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:202 doc/classes/ParticlesMaterial.xml:177
+msgid "If [code]true[/code], particles will not move on the z axis."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:205 doc/classes/ParticlesMaterial.xml:180
+msgid "If [code]true[/code], particles rotate around Y axis by [member angle]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:208 doc/classes/ParticlesMaterial.xml:183
+msgid ""
+"Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts "
+"particles to X/Z plane."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:250
+msgid ""
+"The [Mesh] used for each particle. If [code]null[/code], particles will be "
+"spheres."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:256
+msgid ""
+"Orbital velocity applied to each particle. Makes the particles circle around "
+"origin in the local XY plane. Specified in number of full rotations around "
+"origin per second.\n"
+"This property is only available when [member flag_disable_z] is [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:293 doc/classes/ParticlesMaterial.xml:244
+msgid ""
+"Each particle's initial direction range from [code]+spread[/code] to [code]-"
+"spread[/code] degrees. Applied to X/Z plane and Y/Z planes."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:313 doc/classes/GPUParticles3D.xml:116
+msgid "Particles are drawn in order of depth."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:358
+msgid "Use with [method set_particle_flag] to set [member flag_rotate_y]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:361
+msgid "Use with [method set_particle_flag] to set [member flag_disable_z]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:370 doc/classes/ParticlesMaterial.xml:321
+msgid "Particles will be emitted in the volume of a sphere."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:373 doc/classes/ParticlesMaterial.xml:324
+msgid "Particles will be emitted in the volume of a box."
+msgstr ""
+
+#: doc/classes/Crypto.xml:4
+msgid "Access to advanced cryptographic functionalities."
+msgstr ""
+
+#: doc/classes/Crypto.xml:7
+msgid ""
+"The Crypto class allows you to access some more advanced cryptographic "
+"functionalities in Godot.\n"
+"For now, this includes generating cryptographically secure random bytes, and "
+"RSA keys and self-signed X509 certificates generation. More functionalities "
+"are planned for future releases.\n"
+"[codeblock]\n"
+"extends Node\n"
+"\n"
+"var crypto = Crypto.new()\n"
+"var key = CryptoKey.new()\n"
+"var cert = X509Certificate.new()\n"
+"\n"
+"func _ready():\n"
+" # Generate new RSA key.\n"
+" key = crypto.generate_rsa(4096)\n"
+" # Generate new self-signed certificate with the given key.\n"
+" cert = crypto.generate_self_signed_certificate(key, \"CN=mydomain.com,"
+"O=My Game Company,C=IT\")\n"
+" # Save key and certificate in the user folder.\n"
+" key.save(\"user://generated.key\")\n"
+" cert.save(\"user://generated.crt\")\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/Crypto.xml:36
+msgid ""
+"Generates a [PackedByteArray] of cryptographically secure random bytes with "
+"given [code]size[/code]."
+msgstr ""
+
+#: doc/classes/Crypto.xml:45
+msgid ""
+"Generates an RSA [CryptoKey] that can be used for creating self-signed "
+"certificates and passed to [method StreamPeerSSL.accept_stream]."
+msgstr ""
+
+#: doc/classes/Crypto.xml:60
+msgid ""
+"Generates a self-signed [X509Certificate] from the given [CryptoKey] and "
+"[code]issuer_name[/code]. The certificate validity will be defined by "
+"[code]not_before[/code] and [code]not_after[/code] (first valid date and "
+"last valid date). The [code]issuer_name[/code] must contain at least \"CN="
+"\" (common name, i.e. the domain name), \"O=\" (organization, i.e. your "
+"company name), \"C=\" (country, i.e. 2 lettered ISO-3166 code of the country "
+"the organization is based in).\n"
+"A small example to generate an RSA key and a X509 self-signed certificate.\n"
+"[codeblock]\n"
+"var crypto = Crypto.new()\n"
+"# Generate 4096 bits RSA key.\n"
+"var key = crypto.generate_rsa(4096)\n"
+"# Generate self-signed certificate using the given key.\n"
+"var cert = crypto.generate_self_signed_certificate(key, \"CN=example.com,O=A "
+"Game Company,C=IT\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:4
+msgid "A cryptographic key (RSA)."
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:7
+msgid ""
+"The CryptoKey class represents a cryptographic key. Keys can be loaded and "
+"saved like any other [Resource].\n"
+"They can be used to generate a self-signed [X509Certificate] via [method "
+"Crypto.generate_self_signed_certificate] and as private key in [method "
+"StreamPeerSSL.accept_stream] along with the appropriate certificate.\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:20
+msgid "Loads a key from [code]path[/code] (\"*.key\" file)."
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:29
+msgid ""
+"Saves a key to the given [code]path[/code] (should be a \"*.key\" file)."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:4
+msgid "A CSG Box shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:7
+msgid "This node allows you to create a box for use with the CSG system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:15
+msgid "Depth of the box measured from the center of the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:18
+msgid "Height of the box measured from the center of the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:21
+msgid "The material used to render the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:24
+msgid "Width of the box measured from the center of the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCombiner3D.xml:4
+msgid "A CSG node that allows you to combine other CSG modifiers."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCombiner3D.xml:7
+msgid ""
+"For complex arrangements of shapes, it is sometimes needed to add structure "
+"to your CSG nodes. The CSGCombiner3D node allows you to create this "
+"structure. The node encapsulates the result of the CSG operations of its "
+"children. In this way, it is possible to do operations on one set of shapes "
+"that are children of one CSGCombiner3D node, and a set of separate "
+"operations on a second set of shapes that are children of a second "
+"CSGCombiner3D node, and then do an operation that takes the two end results "
+"as its input to create the final shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:4
+msgid "A CSG Cylinder shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:7
+msgid ""
+"This node allows you to create a cylinder (or cone) for use with the CSG "
+"system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:15
+msgid ""
+"If [code]true[/code] a cone is created, the [member radius] will only apply "
+"to one side."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:18
+msgid "The height of the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:21
+msgid "The material used to render the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:24
+msgid "The radius of the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:27
+msgid ""
+"The number of sides of the cylinder, the higher this number the more detail "
+"there will be in the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:30
+msgid ""
+"If [code]true[/code] the normals of the cylinder are set to give a smooth "
+"effect making the cylinder seem rounded. If [code]false[/code] the cylinder "
+"will have a flat shaded look."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:4
+msgid "A CSG Mesh shape that uses a mesh resource."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:15
+msgid "The [Material] used in drawing the CSG shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:18
+msgid "The [Mesh] resource to use as a CSG shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:4
+msgid "Extrudes a 2D polygon shape to create a 3D mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:7
+msgid "This node takes a 2D polygon shape and extrudes it to create a 3D mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:15
+msgid "Extrusion depth when [member mode] is [constant MODE_DEPTH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:18
+msgid "Material to use for the resulting mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:21
+msgid "Extrusion mode."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:24
+msgid ""
+"If [code]true[/code] the u component of our uv will continuously increase in "
+"unison with the distance traveled along our path when [member mode] is "
+"[constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:27
+msgid ""
+"Interval at which a new extrusion slice is added along the path when [member "
+"mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:30
+msgid ""
+"If [code]true[/code] the start and end of our path are joined together "
+"ensuring there is no seam when [member mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:33
+msgid ""
+"If [code]false[/code] we extrude centered on our path, if [code]true[/code] "
+"we extrude in relation to the position of our CSGPolygon3D when [member "
+"mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:36
+msgid ""
+"The [Shape3D] object containing the path along which we extrude when [member "
+"mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:39
+msgid ""
+"The method by which each slice is rotated along the path when [member mode] "
+"is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:42
+msgid "Point array that defines the shape that we'll extrude."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:45
+msgid "Generates smooth normals so smooth shading is applied to our mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:48
+msgid ""
+"Degrees to rotate our extrusion for each slice when [member mode] is "
+"[constant MODE_SPIN]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:51
+msgid "Number of extrusion when [member mode] is [constant MODE_SPIN]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:56
+msgid "Shape3D is extruded to [member depth]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:59
+msgid "Shape3D is extruded by rotating it around an axis."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:62
+msgid ""
+"Shape3D is extruded along a path set by a [Shape3D] set in [member "
+"path_node]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:65
+msgid "Slice is not rotated."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:68
+msgid "Slice is rotated around the up vector of the path."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:71
+msgid "Slice is rotate to match the path exactly."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPrimitive3D.xml:4
+msgid "Base class for CSG primitives."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPrimitive3D.xml:7
+msgid ""
+"Parent class for various CSG primitives. It contains code and functionality "
+"that is common between them. It cannot be used directly. Instead use one of "
+"the various classes that inherit from it."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPrimitive3D.xml:15
+msgid "Invert the faces of the mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:4
+msgid "The CSG base class."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:7
+msgid ""
+"This is the CSG base class that provides CSG operation support to the "
+"various CSG nodes in Godot."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:34
+msgid ""
+"Returns an [Array] with two elements, the first is the [Transform] of this "
+"node and the second is the root [Mesh] of this node. Only works when this "
+"node is the root shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:41
+msgid ""
+"Returns [code]true[/code] if this is a root shape and is thus the object "
+"that is rendered."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:52 doc/classes/SoftBody3D.xml:64
+msgid ""
+"Sets individual bits on the layer mask. Use this if you only need to change "
+"one layer's value."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:63 doc/classes/SoftBody3D.xml:75
+msgid ""
+"Sets individual bits on the collision mask. Use this if you only need to "
+"change one layer's value."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:69
+msgid ""
+"Calculate tangents for the CSG shape which allows the use of normal maps. "
+"This is only applied on the root shape, this setting is ignored on any child."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:72
+msgid ""
+"The physics layers this area is in.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:77
+msgid "The physics layers this CSG shape scans for collisions."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:80
+msgid ""
+"The operation that is performed on this shape. This is ignored for the first "
+"CSG child node as the operation is between this node and the previous child "
+"of this nodes parent."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:83
+msgid ""
+"Snap makes the mesh snap to a given distance so that the faces of two meshes "
+"can be perfectly aligned. A lower value results in greater precision but may "
+"be harder to adjust."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:86
+msgid ""
+"Adds a collision shape to the physics engine for our CSG shape. This will "
+"always act like a static body. Note that the collision shape is still active "
+"even if the CSG shape itself is hidden."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:91
+msgid ""
+"Geometry of both primitives is merged, intersecting geometry is removed."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:94
+msgid "Only intersecting geometry remains, the rest is removed."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:97
+msgid ""
+"The second shape is subtracted from the first, leaving a dent with its shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:4
+msgid "A CSG Sphere shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:7
+msgid "This node allows you to create a sphere for use with the CSG system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:15
+msgid "The material used to render the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:18
+msgid "Number of vertical slices for the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:21
+msgid "Radius of the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:24
+msgid "Number of horizontal slices for the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:27
+msgid ""
+"If [code]true[/code] the normals of the sphere are set to give a smooth "
+"effect making the sphere seem rounded. If [code]false[/code] the sphere will "
+"have a flat shaded look."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:4
+msgid "A CSG Torus shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:7
+msgid "This node allows you to create a torus for use with the CSG system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:15
+msgid "The inner radius of the torus."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:18
+msgid "The material used to render the torus."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:21
+msgid "The outer radius of the torus."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:24
+msgid "The number of edges each ring of the torus is constructed of."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:27
+msgid "The number of slices the torus is constructed of."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:30
+msgid ""
+"If [code]true[/code] the normals of the torus are set to give a smooth "
+"effect making the torus seem rounded. If [code]false[/code] the torus will "
+"have a flat shaded look."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:4
+msgid "Generate an axis-aligned cuboid [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:7
+msgid ""
+"Generate an axis-aligned cuboid [PrimitiveMesh].\n"
+"The cube's UV layout is arranged in a 3×2 layout that allows texturing each "
+"face individually. To apply the same texture on all faces, change the "
+"material's UV property to [code]Vector3(3, 2, 1)[/code]."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:16
+msgid "Size of the cuboid mesh."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:19
+msgid "Number of extra edge loops inserted along the Z axis."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:22
+msgid "Number of extra edge loops inserted along the Y axis."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:25
+msgid "Number of extra edge loops inserted along the X axis."
+msgstr ""
+
+#: doc/classes/Curve.xml:4
+msgid "A mathematic curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:7
+msgid ""
+"A curve that can be saved and re-used for other objects. By default, it "
+"ranges between [code]0[/code] and [code]1[/code] on the Y axis and positions "
+"points relative to the [code]0.5[/code] Y position."
+msgstr ""
+
+#: doc/classes/Curve.xml:26
+msgid ""
+"Adds a point to the curve. For each side, if the [code]*_mode[/code] is "
+"[constant TANGENT_LINEAR], the [code]*_tangent[/code] angle (in degrees) "
+"uses the slope of the curve halfway to the adjacent point. Allows custom "
+"assignments to the [code]*_tangent[/code] angle if [code]*_mode[/code] is "
+"set to [constant TANGENT_FREE]."
+msgstr ""
+
+#: doc/classes/Curve.xml:33
+msgid "Recomputes the baked cache of points for the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:40
+msgid ""
+"Removes points that are closer than [code]CMP_EPSILON[/code] (0.00001) units "
+"to their neighbor on the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:47 doc/classes/Curve2D.xml:33
+#: doc/classes/Curve3D.xml:33
+msgid "Removes all points from the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:54 doc/classes/Curve2D.xml:74
+#: doc/classes/Curve3D.xml:89
+msgid "Returns the number of points describing the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:63
+msgid ""
+"Returns the left [enum TangentMode] for the point at [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:72
+msgid ""
+"Returns the left tangent angle (in degrees) for the point at [code]index[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:81
+msgid "Returns the curve coordinates for the point at [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:90
+msgid ""
+"Returns the right [enum TangentMode] for the point at [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:99
+msgid ""
+"Returns the right tangent angle (in degrees) for the point at [code]index[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:108
+msgid ""
+"Returns the Y value for the point that would exist at the X position "
+"[code]offset[/code] along the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:117
+msgid ""
+"Returns the Y value for the point that would exist at the X position "
+"[code]offset[/code] along the curve using the baked cache. Bakes the curve's "
+"points if not already baked."
+msgstr ""
+
+#: doc/classes/Curve.xml:126
+msgid "Removes the point at [code]index[/code] from the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:137
+msgid ""
+"Sets the left [enum TangentMode] for the point at [code]index[/code] to "
+"[code]mode[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:148
+msgid ""
+"Sets the left tangent angle for the point at [code]index[/code] to "
+"[code]tangent[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:159
+msgid "Sets the offset from [code]0.5[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:170
+msgid ""
+"Sets the right [enum TangentMode] for the point at [code]index[/code] to "
+"[code]mode[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:181
+msgid ""
+"Sets the right tangent angle for the point at [code]index[/code] to "
+"[code]tangent[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:192
+msgid ""
+"Assigns the vertical position [code]y[/code] to the point at [code]index[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:198
+msgid "The number of points to include in the baked (i.e. cached) curve data."
+msgstr ""
+
+#: doc/classes/Curve.xml:201
+msgid "The maximum value the curve can reach."
+msgstr ""
+
+#: doc/classes/Curve.xml:204
+msgid "The minimum value the curve can reach."
+msgstr ""
+
+#: doc/classes/Curve.xml:210
+msgid "Emitted when [member max_value] or [member min_value] is changed."
+msgstr ""
+
+#: doc/classes/Curve.xml:216
+msgid "The tangent on this side of the point is user-defined."
+msgstr ""
+
+#: doc/classes/Curve.xml:219
+msgid ""
+"The curve calculates the tangent on this side of the point as the slope "
+"halfway towards the adjacent point."
+msgstr ""
+
+#: doc/classes/Curve.xml:222
+msgid "The total number of available tangent modes."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:4
+msgid "Describes a Bézier curve in 2D space."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:7
+msgid ""
+"This class describes a Bézier curve in 2D space. It is mainly used to give a "
+"shape to a [Path2D], but can be manually sampled for other purposes.\n"
+"It keeps a cache of precalculated points along the curve, to speed up "
+"further calculations."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:25 doc/classes/Curve3D.xml:25
+msgid ""
+"Adds a point to a curve at [code]position[/code], with control points "
+"[code]in[/code] and [code]out[/code].\n"
+"If [code]at_position[/code] is given, the point is inserted before the point "
+"number [code]at_position[/code], moving that point (and every point after) "
+"after the inserted point. If [code]at_position[/code] is not given, or is an "
+"illegal value ([code]at_position <0[/code] or [code]at_position >= [method "
+"get_point_count][/code]), the point will be appended at the end of the point "
+"list."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:40 doc/classes/Curve3D.xml:40
+msgid ""
+"Returns the total length of the curve, based on the cached points. Given "
+"enough density (see [member bake_interval]), it should be approximate enough."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:47
+msgid "Returns the cache of points as a [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:56
+msgid ""
+"Returns the closest offset to [code]to_point[/code]. This offset is meant to "
+"be used in [method interpolate_baked].\n"
+"[code]to_point[/code] must be in this curve's local space."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:66 doc/classes/Curve3D.xml:81
+msgid ""
+"Returns the closest point (in curve's local space) to [code]to_point[/"
+"code].\n"
+"[code]to_point[/code] must be in this curve's local space."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:83
+msgid ""
+"Returns the position of the control point leading to the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console, and returns [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:92
+msgid ""
+"Returns the position of the control point leading out of the vertex "
+"[code]idx[/code]. If the index is out of bounds, the function sends an error "
+"to the console, and returns [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:101
+msgid ""
+"Returns the position of the vertex [code]idx[/code]. If the index is out of "
+"bounds, the function sends an error to the console, and returns [code](0, 0)"
+"[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:112
+msgid ""
+"Returns the position between the vertex [code]idx[/code] and the vertex "
+"[code]idx + 1[/code], where [code]t[/code] controls if the point is the "
+"first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), "
+"or in between. Values of [code]t[/code] outside the range ([code]0.0 >= t "
+"<=1[/code]) give strange, but predictable results.\n"
+"If [code]idx[/code] is out of bounds it is truncated to the first or last "
+"vertex, and [code]t[/code] is ignored. If the curve has no points, the "
+"function sends an error to the console, and returns [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:124 doc/classes/Curve3D.xml:148
+msgid ""
+"Returns a point within the curve at position [code]offset[/code], where "
+"[code]offset[/code] is measured as a pixel distance along the curve.\n"
+"To do that, it finds the two cached points where the [code]offset[/code] "
+"lies between, then interpolates the values. This interpolation is cubic if "
+"[code]cubic[/code] is set to [code]true[/code], or linear if set to "
+"[code]false[/code].\n"
+"Cubic interpolation tends to follow the curves better, but linear is faster "
+"(and often, precise enough)."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:135 doc/classes/Curve3D.xml:172
+msgid ""
+"Returns the position at the vertex [code]fofs[/code]. It calls [method "
+"interpolate] using the integer part of [code]fofs[/code] as [code]idx[/"
+"code], and its fractional part as [code]t[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:144 doc/classes/Curve3D.xml:181
+msgid ""
+"Deletes the point [code]idx[/code] from the curve. Sends an error to the "
+"console if [code]idx[/code] is out of bounds."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:155 doc/classes/Curve3D.xml:192
+msgid ""
+"Sets the position of the control point leading to the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:166 doc/classes/Curve3D.xml:203
+msgid ""
+"Sets the position of the control point leading out of the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:177 doc/classes/Curve3D.xml:214
+msgid ""
+"Sets the position for the vertex [code]idx[/code]. If the index is out of "
+"bounds, the function sends an error to the console."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:188 doc/classes/Curve3D.xml:237
+msgid ""
+"Returns a list of points along the curve, with a curvature controlled point "
+"density. That is, the curvier parts will have more points than the "
+"straighter parts.\n"
+"This approximation makes straight segments between each point, then "
+"subdivides those segments until the resulting shape is similar enough.\n"
+"[code]max_stages[/code] controls how many subdivisions a curve segment may "
+"face before it is considered approximate enough. Each subdivision splits the "
+"segment in half, so the default 5 stages may mean up to 32 subdivisions per "
+"curve segment. Increase with care!\n"
+"[code]tolerance_degrees[/code] controls how many degrees the midpoint of a "
+"segment may deviate from the real curve, before the segment has to be "
+"subdivided."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:197
+msgid ""
+"The distance in pixels between two adjacent cached points. Changing it "
+"forces the cache to be recomputed the next time the [method "
+"get_baked_points] or [method get_baked_length] function is called. The "
+"smaller the distance, the more points in the cache and the more memory it "
+"will consume, so use with care."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:4
+msgid "Describes a Bézier curve in 3D space."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:7
+msgid ""
+"This class describes a Bézier curve in 3D space. It is mainly used to give a "
+"shape to a [Path3D], but can be manually sampled for other purposes.\n"
+"It keeps a cache of precalculated points along the curve, to speed up "
+"further calculations."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:47
+msgid "Returns the cache of points as a [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:54
+msgid "Returns the cache of tilts as a [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:61
+msgid ""
+"Returns the cache of up vectors as a [PackedVector3Array].\n"
+"If [member up_vector_enabled] is [code]false[/code], the cache will be empty."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:71
+msgid ""
+"Returns the closest offset to [code]to_point[/code]. This offset is meant to "
+"be used in [method interpolate_baked] or [method "
+"interpolate_baked_up_vector].\n"
+"[code]to_point[/code] must be in this curve's local space."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:98
+msgid ""
+"Returns the position of the control point leading to the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console, and returns [code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:107
+msgid ""
+"Returns the position of the control point leading out of the vertex "
+"[code]idx[/code]. If the index is out of bounds, the function sends an error "
+"to the console, and returns [code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:116
+msgid ""
+"Returns the position of the vertex [code]idx[/code]. If the index is out of "
+"bounds, the function sends an error to the console, and returns [code](0, 0, "
+"0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:125
+msgid ""
+"Returns the tilt angle in radians for the point [code]idx[/code]. If the "
+"index is out of bounds, the function sends an error to the console, and "
+"returns [code]0[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:136
+msgid ""
+"Returns the position between the vertex [code]idx[/code] and the vertex "
+"[code]idx + 1[/code], where [code]t[/code] controls if the point is the "
+"first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), "
+"or in between. Values of [code]t[/code] outside the range ([code]0.0 >= t "
+"<=1[/code]) give strange, but predictable results.\n"
+"If [code]idx[/code] is out of bounds it is truncated to the first or last "
+"vertex, and [code]t[/code] is ignored. If the curve has no points, the "
+"function sends an error to the console, and returns [code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:161
+msgid ""
+"Returns an up vector within the curve at position [code]offset[/code], where "
+"[code]offset[/code] is measured as a distance in 3D units along the curve.\n"
+"To do that, it finds the two cached up vectors where the [code]offset[/code] "
+"lies between, then interpolates the values. If [code]apply_tilt[/code] is "
+"[code]true[/code], an interpolated tilt is applied to the interpolated up "
+"vector.\n"
+"If the curve has no up vectors, the function sends an error to the console, "
+"and returns [code](0, 1, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:225
+msgid ""
+"Sets the tilt angle in radians for the point [code]idx[/code]. If the index "
+"is out of bounds, the function sends an error to the console.\n"
+"The tilt controls the rotation along the look-at axis an object traveling "
+"the path would have. In the case of a curve controlling a [PathFollow3D], "
+"this tilt is an offset over the natural tilt the [PathFollow3D] calculates."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:246
+msgid ""
+"The distance in meters between two adjacent cached points. Changing it "
+"forces the cache to be recomputed the next time the [method "
+"get_baked_points] or [method get_baked_length] function is called. The "
+"smaller the distance, the more points in the cache and the more memory it "
+"will consume, so use with care."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:249
+msgid ""
+"If [code]true[/code], the curve will bake up vectors used for orientation. "
+"This is used when [member PathFollow3D.rotation_mode] is set to [constant "
+"PathFollow3D.ROTATION_ORIENTED]. Changing it forces the cache to be "
+"recomputed."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:4
+msgid "A texture that shows a curve."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:7
+msgid ""
+"Renders a given [Curve] provided to it. Simplifies the task of drawing "
+"curves and/or saving them as image files."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:15
+msgid "The [code]curve[/code] rendered onto the texture."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:18
+msgid "The width of the texture."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:4
+msgid "Class representing a cylindrical [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:7
+msgid ""
+"Class representing a cylindrical [PrimitiveMesh]. This class can be used to "
+"create cones by setting either the [member top_radius] or [member "
+"bottom_radius] properties to 0.0."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:15
+msgid "Bottom radius of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:18
+msgid "Full height of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:21
+msgid "Number of radial segments on the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:24
+msgid "Number of edge rings along the height of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:27
+msgid "Top radius of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderShape3D.xml:4 doc/classes/CylinderShape3D.xml:7
+msgid "Cylinder shape for collisions."
+msgstr ""
+
+#: doc/classes/CylinderShape3D.xml:15
+msgid "The cylinder's height."
+msgstr ""
+
+#: doc/classes/CylinderShape3D.xml:18
+msgid "The cylinder's radius."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:4
+msgid "Damped spring constraint for 2D physics."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:7
+msgid ""
+"Damped spring constraint for 2D physics. This resembles a spring joint that "
+"always wants to go back to a given length."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:15
+msgid ""
+"The spring joint's damping ratio. A value between [code]0[/code] and "
+"[code]1[/code]. When the two bodies move into different directions the "
+"system tries to align them to the spring axis again. A high [code]damping[/"
+"code] value forces the attached bodies to align faster."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:18
+msgid ""
+"The spring joint's maximum length. The two attached bodies cannot stretch it "
+"past this value."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:21
+msgid ""
+"When the bodies attached to the spring joint move they stretch or squash it. "
+"The joint always tries to resize towards this length."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:24
+msgid ""
+"The higher the value, the less the bodies attached to the joint will deform "
+"it. The joint applies an opposing force to the bodies, the product of the "
+"stiffness multiplied by the size difference from its resting length."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:4
+msgid "Dictionary type."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:7
+msgid ""
+"Dictionary type. Associative container which contains values referenced by "
+"unique keys. Dictionary are composed of pairs of keys (which must be unique) "
+"and values. You can define a dictionary by placing a comma separated list of "
+"[code]key: value[/code] pairs in curly braces [code]{}[/code].\n"
+"Erasing elements while iterating over them [b]is not supported[/b].\n"
+"Creating a dictionary:\n"
+"[codeblock]\n"
+"var my_dir = {} # Creates an empty dictionary.\n"
+"var points_dir = {\"White\": 50, \"Yellow\": 75, \"Orange\": 100}\n"
+"var my_dir = {\n"
+" key1: value1,\n"
+" key2: value2,\n"
+" key3: value3,\n"
+"}\n"
+"[/codeblock]\n"
+"You can access values of a dictionary by referencing appropriate key in "
+"above example [code]points_dir[\"White\"][/code] would return value of 50.\n"
+"[codeblock]\n"
+"export(String, \"White\", \"Yellow\", \"Orange\") var my_color\n"
+"var points_dir = {\"White\": 50, \"Yellow\": 75, \"Orange\": 100}\n"
+"\n"
+"func _ready():\n"
+" var points = points_dir[my_color]\n"
+"[/codeblock]\n"
+"In the above code [code]points[/code] will be assigned the value that is "
+"paired with the appropriate color selected in [code]my_color[/code].\n"
+"Dictionaries can contain more complex data:\n"
+"[codeblock]\n"
+"my_dir = {\"First Array\": [1, 2, 3, 4]} # Assigns an Array to a String "
+"key.\n"
+"[/codeblock]\n"
+"To add a key to an existing dictionary, access it like an existing key and "
+"assign to it:\n"
+"[codeblock]\n"
+"var points_dir = {\"White\": 50, \"Yellow\": 75, \"Orange\": 100}\n"
+"var points_dir[\"Blue\"] = 150 # Add \"Blue\" as a key and assign 150 as its "
+"value.\n"
+"[/codeblock]\n"
+"Finally, dictionaries can contain different types of keys and values in the "
+"same dictionary:\n"
+"[codeblock]\n"
+"var my_dir = {\"String Key\": 5, 4: [1, 2, 3], 7: \"Hello\"} # This is a "
+"valid dictionary.\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Unlike [Array]s you can't compare dictionaries directly:\n"
+"[codeblock]\n"
+"array1 = [1, 2, 3]\n"
+"array2 = [1, 2, 3]\n"
+"\n"
+"func compare_arrays():\n"
+" print(array1 == array2) # Will print true.\n"
+"\n"
+"dir1 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"dir2 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"\n"
+"func compare_dictionaries():\n"
+" print(dir1 == dir2) # Will NOT print true.\n"
+"[/codeblock]\n"
+"You need to first calculate the dictionary's hash with [method hash] before "
+"you can compare them:\n"
+"[codeblock]\n"
+"dir1 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"dir2 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"\n"
+"func compare_dictionaries():\n"
+" print(dir1.hash() == dir2.hash()) # Will print true.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Dictionary.xml:65
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/"
+"gdscript_basics.html#dictionary"
+msgstr ""
+
+#: doc/classes/Dictionary.xml:72
+msgid "Clear the dictionary, removing all key/value pairs."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:81
+msgid "Creates a copy of the dictionary, and returns it."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:88
+msgid "Returns [code]true[/code] if the dictionary is empty."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:97
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:108
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:117
+msgid "Returns [code]true[/code] if the dictionary has a given key."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:126
+msgid ""
+"Returns [code]true[/code] if the dictionary has all of the keys in the given "
+"array."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:133
+msgid ""
+"Returns a hashed integer value representing the dictionary contents. This "
+"can be used to compare dictionaries by value:\n"
+"[codeblock]\n"
+"var dict1 = {0: 10}\n"
+"var dict2 = {0: 10}\n"
+"# The line below prints `true`, whereas it would have printed `false` if "
+"both variables were compared directly.\n"
+"print(dict1.hash() == dict2.hash())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Dictionary.xml:146
+msgid "Returns the list of keys in the [Dictionary]."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:153
+msgid "Returns the size of the dictionary (in pairs)."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:160
+msgid "Returns the list of values in the [Dictionary]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:4
+msgid "Directional light from a distance, as from the Sun."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:7
+msgid ""
+"A directional light is a type of [Light3D] node that models an infinite "
+"number of parallel rays covering the entire scene. It is used for lights "
+"with strong intensity that are located far away from the scene to model "
+"sunlight or moonlight. The worldspace location of the DirectionalLight3D "
+"transform (origin) is ignored. Only the basis is used to determine light "
+"direction."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:10 doc/classes/Light3D.xml:10
+#: doc/classes/OmniLight3D.xml:10 doc/classes/SpotLight3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html"
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:16
+msgid ""
+"Amount of extra bias for shadow splits that are far away. If self-shadowing "
+"occurs only on the splits far away, increasing this value can fix them."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:19
+msgid ""
+"If [code]true[/code], shadow detail is sacrificed in exchange for smoother "
+"transitions between splits."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:22
+msgid ""
+"Optimizes shadow rendering for detail versus movement. See [enum "
+"ShadowDepthRange]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:27
+msgid "The maximum distance for shadow splits."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:30
+msgid "The light's shadow rendering algorithm. See [enum ShadowMode]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:33
+msgid ""
+"Can be used to fix special cases of self shadowing when objects are "
+"perpendicular to the light."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:36
+msgid ""
+"The distance from camera to shadow split 1. Relative to [member "
+"directional_shadow_max_distance]. Only used when [member "
+"directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or "
+"[code]SHADOW_PARALLEL_4_SPLITS[/code]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:39
+msgid ""
+"The distance from shadow split 1 to split 2. Relative to [member "
+"directional_shadow_max_distance]. Only used when [member "
+"directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or "
+"[code]SHADOW_PARALLEL_4_SPLITS[/code]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:42
+msgid ""
+"The distance from shadow split 2 to split 3. Relative to [member "
+"directional_shadow_max_distance]. Only used when [member "
+"directional_shadow_mode] is [code]SHADOW_PARALLEL_4_SPLITS[/code]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:48
+msgid ""
+"Renders the entire scene's shadow map from an orthogonal point of view. May "
+"result in blockier shadows on close objects."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:51
+msgid "Splits the view frustum in 2 areas, each with its own shadow map."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:54
+msgid "Splits the view frustum in 4 areas, each with its own shadow map."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:57
+msgid ""
+"Keeps the shadow stable when the camera moves, at the cost of lower "
+"effective shadow resolution."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:60
+msgid ""
+"Tries to achieve maximum shadow resolution. May result in saw effect on "
+"shadow edges."
+msgstr ""
+
+#: doc/classes/Directory.xml:4
+msgid "Type used to handle the filesystem."
+msgstr ""
+
+#: doc/classes/Directory.xml:7
+msgid ""
+"Directory type. It is used to manage directories and their content (not "
+"restricted to the project folder).\n"
+"When creating a new [Directory], its default opened directory will be "
+"[code]res://[/code]. This may change in the future, so it is advised to "
+"always use [method open] to initialize your [Directory] where you want to "
+"operate, with explicit error checking.\n"
+"Here is an example on how to iterate through the files of a directory:\n"
+"[codeblock]\n"
+"func dir_contents(path):\n"
+" var dir = Directory.new()\n"
+" if dir.open(path) == OK:\n"
+" dir.list_dir_begin()\n"
+" var file_name = dir.get_next()\n"
+" while file_name != \"\":\n"
+" if dir.current_is_dir():\n"
+" print(\"Found directory: \" + file_name)\n"
+" else:\n"
+" print(\"Found file: \" + file_name)\n"
+" file_name = dir.get_next()\n"
+" else:\n"
+" print(\"An error occurred when trying to access the path.\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Directory.xml:27 doc/classes/File.xml:25
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"filesystem.html"
+msgstr ""
+
+#: doc/classes/Directory.xml:36
+msgid ""
+"Changes the currently opened directory to the one passed as an argument. The "
+"argument can be relative to the current directory (e.g. [code]newdir[/code] "
+"or [code]../newdir[/code]), or an absolute path (e.g. [code]/tmp/newdir[/"
+"code] or [code]res://somedir/newdir[/code]).\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:48
+msgid ""
+"Copies the [code]from[/code] file to the [code]to[/code] destination. Both "
+"arguments should be paths to files, either relative or absolute. If the "
+"destination file exists and is not access-protected, it will be "
+"overwritten.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:56
+msgid ""
+"Returns whether the current item processed with the last [method get_next] "
+"call is a directory ([code].[/code] and [code]..[/code] are considered "
+"directories)."
+msgstr ""
+
+#: doc/classes/Directory.xml:65
+msgid ""
+"Returns whether the target directory exists. The argument can be relative to "
+"the current directory, or an absolute path."
+msgstr ""
+
+#: doc/classes/Directory.xml:74
+msgid ""
+"Returns whether the target file exists. The argument can be relative to the "
+"current directory, or an absolute path."
+msgstr ""
+
+#: doc/classes/Directory.xml:81
+msgid ""
+"Returns the absolute path to the currently opened directory (e.g. "
+"[code]res://folder[/code] or [code]C:\\tmp\\folder[/code])."
+msgstr ""
+
+#: doc/classes/Directory.xml:88
+msgid ""
+"Returns the currently opened directory's drive index. See [method get_drive] "
+"to convert returned index to the name of the drive."
+msgstr ""
+
+#: doc/classes/Directory.xml:97
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Directory.xml:104
+msgid ""
+"On Windows, returns the number of drives (partitions) mounted on the current "
+"filesystem. On other platforms, the method returns 0."
+msgstr ""
+
+#: doc/classes/Directory.xml:111
+msgid ""
+"Returns the next element (file or directory) in the current directory "
+"(including [code].[/code] and [code]..[/code], unless "
+"[code]skip_navigational[/code] was given to [method list_dir_begin]).\n"
+"The name of the file or directory is returned (and not its full path). Once "
+"the stream has been fully processed, the method returns an empty String and "
+"closes the stream automatically (i.e. [method list_dir_end] would not be "
+"mandatory in such a case)."
+msgstr ""
+
+#: doc/classes/Directory.xml:119
+msgid ""
+"On UNIX desktop systems, returns the available space on the current "
+"directory's disk. On other platforms, this information is not available and "
+"the method returns 0 or -1."
+msgstr ""
+
+#: doc/classes/Directory.xml:130
+msgid ""
+"Initializes the stream used to list all files and directories using the "
+"[method get_next] function, closing the current opened stream if needed. "
+"Once the stream has been processed, it should typically be closed with "
+"[method list_dir_end].\n"
+"If [code]skip_navigational[/code] is [code]true[/code], [code].[/code] and "
+"[code]..[/code] are filtered out.\n"
+"If [code]skip_hidden[/code] is [code]true[/code], hidden files are filtered "
+"out."
+msgstr ""
+
+#: doc/classes/Directory.xml:139
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/Directory.xml:148
+msgid ""
+"Creates a directory. The argument can be relative to the current directory, "
+"or an absolute path. The target directory should be placed in an already "
+"existing directory (to create the full path recursively, see [method "
+"make_dir_recursive]).\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:158
+msgid ""
+"Creates a target directory and all necessary intermediate directories in its "
+"path, by calling [method make_dir] recursively. The argument can be relative "
+"to the current directory, or an absolute path.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:168
+msgid ""
+"Opens an existing directory of the filesystem. The [code]path[/code] "
+"argument can be within the project tree ([code]res://folder[/code]), the "
+"user directory ([code]user://folder[/code]) or an absolute path of the user "
+"filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\\tmp\\folder[/code]).\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:178
+msgid ""
+"Deletes the target file or an empty directory. The argument can be relative "
+"to the current directory, or an absolute path. If the target directory is "
+"not empty, the operation will fail.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:190
+msgid ""
+"Renames (move) the [code]from[/code] file to the [code]to[/code] "
+"destination. Both arguments should be paths to files, either relative or "
+"absolute. If the destination file exists and is not access-protected, it "
+"will be overwritten.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:4
+msgid "Helper class to implement a DTLS server."
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:7
+msgid ""
+"This class is used to store the state of a DTLS server. Upon [method setup] "
+"it converts connected [PacketPeerUDP] to [PacketPeerDTLS] accepting them via "
+"[method take_connection] as DTLS clients. Under the hood, this class is used "
+"to store the DTLS state and cookies of the server. The reason of why the "
+"state and cookies are needed is outside of the scope of this documentation.\n"
+"Below a small example of how to use it:\n"
+"[codeblock]\n"
+"# server.gd\n"
+"extends Node\n"
+"\n"
+"var dtls := DTLSServer.new()\n"
+"var server := UDPServer.new()\n"
+"var peers = []\n"
+"\n"
+"func _ready():\n"
+" server.listen(4242)\n"
+" var key = load(\"key.key\") # Your private key.\n"
+" var cert = load(\"cert.crt\") # Your X509 certificate.\n"
+" dtls.setup(key, cert)\n"
+"\n"
+"func _process(delta):\n"
+" while server.is_connection_available():\n"
+" var peer : PacketPeerUDP = server.take_connection()\n"
+" var dtls_peer : PacketPeerDTLS = dtls.take_connection(peer)\n"
+" if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:\n"
+" continue # It is normal that 50% of the connections fails due to "
+"cookie exchange.\n"
+" print(\"Peer connected!\")\n"
+" peers.append(dtls_peer)\n"
+" for p in peers:\n"
+" p.poll() # Must poll to update the state.\n"
+" if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:\n"
+" while p.get_available_packet_count() > 0:\n"
+" print(\"Received message from client: %s\" % p.get_packet()."
+"get_string_from_utf8())\n"
+" p.put_packet(\"Hello DTLS client\".to_utf8())\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# client.gd\n"
+"extends Node\n"
+"\n"
+"var dtls := PacketPeerDTLS.new()\n"
+"var udp := PacketPeerUDP.new()\n"
+"var connected = false\n"
+"\n"
+"func _ready():\n"
+" udp.connect_to_host(\"127.0.0.1\", 4242)\n"
+" dtls.connect_to_peer(udp, false) # Use true in production for "
+"certificate validation!\n"
+"\n"
+"func _process(delta):\n"
+" dtls.poll()\n"
+" if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:\n"
+" if !connected:\n"
+" # Try to contact server\n"
+" dtls.put_packet(\"The answer is... 42!\".to_utf8())\n"
+" while dtls.get_available_packet_count() > 0:\n"
+" print(\"Connected: %s\" % dtls.get_packet()."
+"get_string_from_utf8())\n"
+" connected = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:74
+msgid ""
+"Setup the DTLS server to use the given [code]private_key[/code] and provide "
+"the given [code]certificate[/code] to clients. You can pass the optional "
+"[code]chain[/code] parameter to provide additional CA chain information "
+"along with the certificate."
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:83
+msgid ""
+"Try to initiate the DTLS handshake with the given [code]udp_peer[/code] "
+"which must be already connected (see [method PacketPeerUDP."
+"connect_to_host]).\n"
+"[b]Note[/b]: You must check that the state of the return PacketPeerUDP is "
+"[constant PacketPeerDTLS.STATUS_HANDSHAKING], as it is normal that 50% of "
+"the new connections will be invalid due to cookie exchange."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:4
+msgid "DynamicFont renders vector font files at runtime."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:7
+msgid ""
+"DynamicFont renders vector font files (such as TTF or OTF) dynamically at "
+"runtime instead of using a prerendered texture atlas like [BitmapFont]. This "
+"trades the faster loading time of [BitmapFont]s for the ability to change "
+"font parameters like size and spacing during runtime. [DynamicFontData] is "
+"used for referencing the font file paths. DynamicFont also supports defining "
+"one or more fallbacks fonts, which will be used when displaying a character "
+"not supported by the main font.\n"
+"DynamicFont uses the [url=https://www.freetype.org/]FreeType[/url] library "
+"for rasterization.\n"
+"[codeblock]\n"
+"var dynamic_font = DynamicFont.new()\n"
+"dynamic_font.font_data = load(\"res://BarlowCondensed-Bold.ttf\")\n"
+"dynamic_font.size = 64\n"
+"$\"Label\".set(\"custom_fonts/font\", dynamic_font)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:25
+msgid "Adds a fallback font."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:34
+msgid "Returns the fallback font at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:41
+msgid "Returns the number of fallback fonts."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:50
+msgid ""
+"Returns the spacing for the given [code]type[/code] (see [enum SpacingType])."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:59
+msgid "Removes the fallback font at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:70
+msgid "Sets the fallback font at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:81
+msgid ""
+"Sets the spacing for [code]type[/code] (see [enum SpacingType]) to "
+"[code]value[/code] in pixels (not relative to the font size)."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:87
+msgid "Extra spacing at the bottom in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:90
+msgid "Extra character spacing in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:93
+msgid "Extra space spacing in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:96
+msgid "Extra spacing at the top in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:99
+msgid "The font data."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:102
+msgid ""
+"The font outline's color.\n"
+"[b]Note:[/b] It's recommended to leave this at the default value so that you "
+"can adjust it in individual controls. For example, if the outline is made "
+"black here, it won't be possible to change its color using a Label's font "
+"outline modulate theme item."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:106
+msgid "The font outline's thickness in pixels (not relative to the font size)."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:109
+msgid "The font size in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:114
+msgid "Spacing at the top."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:117
+msgid "Spacing at the bottom."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:120
+msgid "Character spacing."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:123
+msgid "Space spacing."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:4
+msgid "Used with [DynamicFont] to describe the location of a font file."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:7
+msgid ""
+"Used with [DynamicFont] to describe the location of a vector font file for "
+"dynamic rendering at runtime."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:15
+msgid "If [code]true[/code], the font is rendered with anti-aliasing."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:18
+msgid "The path to the vector font file."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:21
+msgid "The font hinting mode used by FreeType. See [enum Hinting] for options."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:26
+msgid "Disables font hinting (smoother but less crisp)."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:29
+msgid "Use the light font hinting mode."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:32
+msgid "Use the default font hinting mode (crisper but less smooth)."
+msgstr ""
+
+#: doc/classes/EditorExportPlugin.xml:4
+msgid "A script that is executed when exporting projects."
+msgstr ""
+
+#: doc/classes/EditorExportPlugin.xml:23
+msgid ""
+"Virtual method to be overridden by the user. It is called when the export "
+"starts and provides all information about the export."
+msgstr ""
+
+#: doc/classes/EditorExportPlugin.xml:30
+msgid ""
+"Virtual method to be overridden by the user. Called when the export is "
+"finished."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:4
+msgid ""
+"An editor feature profile which can be used to disable specific features."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:7
+msgid ""
+"An editor feature profile can be used to disable specific features of the "
+"Godot editor. When disabled, the features won't appear in the editor, which "
+"makes the editor less cluttered. This is useful in education settings to "
+"reduce confusion or when working in a team. For example, artists and level "
+"designers could use a feature profile that disables the script editor to "
+"avoid accidentally making changes to files they aren't supposed to edit.\n"
+"To manage editor feature profiles visually, use [b]Editor > Manage Feature "
+"Profiles...[/b] at the top of the editor window."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:19
+msgid "Returns the specified [code]feature[/code]'s human-readable name."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:28
+msgid ""
+"Returns [code]true[/code] if the class specified by [code]class_name[/code] "
+"is disabled. When disabled, the class won't appear in the Create New Node "
+"dialog."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:37
+msgid ""
+"Returns [code]true[/code] if editing for the class specified by "
+"[code]class_name[/code] is disabled. When disabled, the class will still "
+"appear in the Create New Node dialog but the inspector will be read-only "
+"when selecting a node that extends the class."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:48
+msgid ""
+"Returns [code]true[/code] if [code]property[/code] is disabled in the class "
+"specified by [code]class_name[/code]. When a property is disabled, it won't "
+"appear in the inspector when selecting a node that extends the class "
+"specified by [code]class_name[/code]."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:57
+msgid ""
+"Returns [code]true[/code] if the [code]feature[/code] is disabled. When a "
+"feature is disabled, it will disappear from the editor entirely."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:66
+msgid ""
+"Loads an editor feature profile from a file. The file must follow the JSON "
+"format obtained by using the feature profile manager's [b]Export[/b] button "
+"or the [method save_to_file] method."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:75
+msgid ""
+"Saves the editor feature profile to a file in JSON format. It can then be "
+"imported using the feature profile manager's [b]Import[/b] button or the "
+"[method load_from_file] button."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:86
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables the class specified "
+"by [code]class_name[/code]. When disabled, the class won't appear in the "
+"Create New Node dialog."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:97
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables editing for the class "
+"specified by [code]class_name[/code]. When disabled, the class will still "
+"appear in the Create New Node dialog but the inspector will be read-only "
+"when selecting a node that extends the class."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:110
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables editing for "
+"[code]property[/code] in the class specified by [code]class_name[/code]. "
+"When a property is disabled, it won't appear in the inspector when selecting "
+"a node that extends the class specified by [code]class_name[/code]."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:121
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables the editor feature "
+"specified in [code]feature[/code]. When a feature is disabled, it will "
+"disappear from the editor entirely."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:127
+msgid ""
+"The 3D editor. If this feature is disabled, the 3D editor won't display but "
+"3D nodes will still display in the Create New Node dialog."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:130
+msgid ""
+"The Script tab, which contains the script editor and class reference "
+"browser. If this feature is disabled, the Script tab won't display."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:133
+msgid ""
+"The AssetLib tab. If this feature is disabled, the AssetLib tab won't "
+"display."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:136
+msgid ""
+"Scene tree editing. If this feature is disabled, the Scene tree dock will "
+"still be visible but will be read-only."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:139
+msgid ""
+"The Import dock. If this feature is disabled, the Import dock won't be "
+"visible."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:142
+msgid ""
+"The Node dock. If this feature is disabled, signals and groups won't be "
+"visible and modifiable from the editor."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:145
+msgid ""
+"The FileSystem dock. If this feature is disabled, the FileSystem dock won't "
+"be visible."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:4
+msgid "A modified version of [FileDialog] used by the editor."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:17
+msgid ""
+"Adds a comma-delimited file extension filter option to the "
+"[EditorFileDialog] with an optional semi-colon-delimited label.\n"
+"For example, [code]\"*.tscn, *.scn; Scenes\"[/code] results in filter text "
+"\"Scenes (*.tscn, *.scn)\"."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:25
+msgid "Removes all filters except for \"All Files (*)\"."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:32
+msgid "Returns the [code]VBoxContainer[/code] used to display the file system."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:39
+msgid ""
+"Notify the [EditorFileDialog] that its view of the data is no longer "
+"accurate. Updates the view contents on next view update."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:45
+msgid ""
+"The location from which the user may select a file, including [code]res://[/"
+"code], [code]user://[/code], and the local file system."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:48
+msgid "The currently occupied directory."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:51
+msgid "The currently selected file."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:54
+msgid "The file system path in the address bar."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:58
+msgid ""
+"If [code]true[/code], the [EditorFileDialog] will not warn the user before "
+"overwriting files."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:61
+msgid ""
+"The view format in which the [EditorFileDialog] displays resources to the "
+"user."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:64
+msgid ""
+"The dialog's open or save mode, which affects the selection behavior. See "
+"[enum FileMode]"
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:67
+msgid ""
+"If [code]true[/code], hidden files and directories will be visible in the "
+"[EditorFileDialog]."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:76
+msgid "Emitted when a directory is selected."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:83
+msgid "Emitted when a file is selected."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:90
+msgid "Emitted when multiple files are selected."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:96
+msgid ""
+"The [EditorFileDialog] can select only one file. Accepting the window will "
+"open the file."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:99
+msgid ""
+"The [EditorFileDialog] can select multiple files. Accepting the window will "
+"open all files."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:102
+msgid ""
+"The [EditorFileDialog] can select only one directory. Accepting the window "
+"will open the directory."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:105
+msgid ""
+"The [EditorFileDialog] can select a file or directory. Accepting the window "
+"will open it."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:108
+msgid ""
+"The [EditorFileDialog] can select only one file. Accepting the window will "
+"save the file."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:111
+msgid ""
+"The [EditorFileDialog] can only view [code]res://[/code] directory contents."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:114
+msgid ""
+"The [EditorFileDialog] can only view [code]user://[/code] directory contents."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:117
+msgid "The [EditorFileDialog] can view the entire local file system."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:120
+msgid "The [EditorFileDialog] displays resources as thumbnails."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:123
+msgid "The [EditorFileDialog] displays resources as a list of filenames."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:4
+msgid "Resource filesystem, as the editor sees it."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:7
+msgid ""
+"This object holds information of all resources in the filesystem, their "
+"types, etc."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:18
+msgid "Gets the type of the file, given the full path."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:25
+msgid "Gets the root directory object."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:34
+msgid "Returns a view into the filesystem at [code]path[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:41
+msgid "Returns the scan progress for 0 to 1 if the FS is being scanned."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:48
+msgid "Returns [code]true[/code] of the filesystem is being scanned."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:55
+msgid "Scan the filesystem for changes."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:62
+msgid "Check if the source of any imported resource changed."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:71
+msgid ""
+"Update a file information. Call this if an external program (not Godot) "
+"modified the file."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:78
+msgid "Scans the script files and updates the list of custom class names."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:85
+msgid "Emitted if the filesystem changed."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:92
+msgid "Remitted if a resource is reimported."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:105
+msgid "Emitted if the source of any imported file changed."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:4
+msgid "A directory for the resource filesystem."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:7
+msgid "A more generalized, low-level variation of the directory concept."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:18
+msgid ""
+"Returns the index of the directory with name [code]name[/code] or [code]-1[/"
+"code] if not found."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:27
+msgid ""
+"Returns the index of the file with name [code]name[/code] or [code]-1[/code] "
+"if not found."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:36
+msgid "Returns the name of the file at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:43
+msgid "Returns the number of files in this directory."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:52
+msgid ""
+"Returns [code]true[/code] if the file at index [code]idx[/code] imported "
+"properly."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:61
+msgid "Returns the path to the file at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:86
+msgid "Returns the file extension of the file at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:93
+msgid "Returns the name of this directory."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:100
+msgid ""
+"Returns the parent directory for this directory or [code]null[/code] if "
+"called on a directory at [code]res://[/code] or [code]user://[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:107
+msgid "Returns the path to this directory."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:116
+msgid "Returns the subdirectory at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:123
+msgid "Returns the number of subdirectories in this directory."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:4
+msgid ""
+"Registers a custom resource importer in the editor. Use the class to parse "
+"any file and import it as a new resource type."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:7
+msgid ""
+"EditorImportPlugins provide a way to extend the editor's resource import "
+"functionality. Use them to import resources from custom files or to provide "
+"alternatives to the editor's existing importers. Register your "
+"[EditorPlugin] with [method EditorPlugin.add_import_plugin].\n"
+"EditorImportPlugins work by associating with specific file extensions and a "
+"resource type. See [method get_recognized_extensions] and [method "
+"get_resource_type]. They may optionally specify some import presets that "
+"affect the import process. EditorImportPlugins are responsible for creating "
+"the resources and saving them in the [code].import[/code] directory.\n"
+"Below is an example EditorImportPlugin that imports a [Mesh] from a file "
+"with the extension \".special\" or \".spec\":\n"
+"[codeblock]\n"
+"tool\n"
+"extends EditorImportPlugin\n"
+"\n"
+"func get_importer_name():\n"
+" return \"my.special.plugin\"\n"
+"\n"
+"func get_visible_name():\n"
+" return \"Special Mesh Importer\"\n"
+"\n"
+"func get_recognized_extensions():\n"
+" return [\"special\", \"spec\"]\n"
+"\n"
+"func get_save_extension():\n"
+" return \"mesh\"\n"
+"\n"
+"func get_resource_type():\n"
+" return \"Mesh\"\n"
+"\n"
+"func get_preset_count():\n"
+" return 1\n"
+"\n"
+"func get_preset_name(i):\n"
+" return \"Default\"\n"
+"\n"
+"func get_import_options(i):\n"
+" return [{\"name\": \"my_option\", \"default_value\": false}]\n"
+"\n"
+"func import(source_file, save_path, options, platform_variants, gen_files):\n"
+" var file = File.new()\n"
+" if file.open(source_file, File.READ) != OK:\n"
+" return FAILED\n"
+"\n"
+" var mesh = Mesh.new()\n"
+" # Fill the Mesh with data read in \"file\", left as an exercise to the "
+"reader\n"
+"\n"
+" var filename = save_path + \".\" + get_save_extension()\n"
+" ResourceSaver.save(filename, mesh)\n"
+" return OK\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:52
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/"
+"import_plugins.html"
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:61
+msgid ""
+"Gets the options and default values for the preset at this index. Returns an "
+"Array of Dictionaries with the following keys: [code]name[/code], "
+"[code]default_value[/code], [code]property_hint[/code] (optional), "
+"[code]hint_string[/code] (optional), [code]usage[/code] (optional)."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:68
+msgid ""
+"Gets the order of this importer to be run when importing resources. Higher "
+"values will be called later. Use this to ensure the importer runs after the "
+"dependencies are already imported."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:75
+msgid "Gets the unique name of the importer."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:92
+msgid ""
+"Gets the number of initial presets defined by the plugin. Use [method "
+"get_import_options] to get the default options for the preset and [method "
+"get_preset_name] to get the name of the preset."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:101
+msgid "Gets the name of the options preset at this index."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:108
+msgid ""
+"Gets the priority of this plugin for the recognized extension. Higher "
+"priority plugins will be preferred. The default priority is [code]1.0[/code]."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:115
+msgid ""
+"Gets the list of file extensions to associate with this loader (case-"
+"insensitive). e.g. [code][\"obj\"][/code]."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:122
+msgid ""
+"Gets the Godot resource type associated with this loader. e.g. [code]\"Mesh"
+"\"[/code] or [code]\"Animation\"[/code]."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:129
+msgid ""
+"Gets the extension used to save this resource in the [code].import[/code] "
+"directory."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:136
+msgid "Gets the name to display in the import window."
+msgstr ""
+
+#: doc/classes/EditorInspector.xml:4
+msgid "A tab used to edit properties of the selected node."
+msgstr ""
+
+#: doc/classes/EditorInspector.xml:7
+msgid ""
+"The editor inspector is by default located on the right-hand side of the "
+"editor. It's used to edit the properties of the selected node. For example, "
+"you can select a node such as the Sprite2D then edit its transform through "
+"the inspector tool. The editor inspector is an essential tool in the game "
+"development workflow."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:4
+msgid "Plugin for adding custom property editors on inspector."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:7
+msgid ""
+"This plugins allows adding custom property editors to [EditorInspector].\n"
+"Plugins are registered via [method EditorPlugin.add_inspector_plugin].\n"
+"When an object is edited, the [method can_handle] function is called and "
+"must return [code]true[/code] if the object type is supported.\n"
+"If supported, the function [method parse_begin] will be called, allowing to "
+"place custom controls at the beginning of the class.\n"
+"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.\n"
+"Finally [method parse_end] will be called.\n"
+"On each of these calls, the \"add\" functions can be called."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:24
+msgid "Adds a custom control, not necessarily a property editor."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:35
+msgid "Adds a property editor, this must inherit [EditorProperty]."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:48
+msgid ""
+"Adds an editor that allows modifying multiple properties, this must inherit "
+"[EditorProperty]."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:57
+msgid "Returns [code]true[/code] if this object can be handled by this plugin."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:66
+msgid "Called to allow adding controls at the beginning of the list."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:77
+msgid "Called to allow adding controls at the beginning of the category."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:84
+msgid "Called to allow adding controls at the end of the list."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:103
+msgid ""
+"Called to allow adding property specific editors to the inspector. Usually "
+"these inherit [EditorProperty]. Returning [code]true[/code] removes the "
+"built-in editor for this property, otherwise allows to insert a custom "
+"editor before the built-in one."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:4
+msgid "Godot editor's interface."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:7
+msgid ""
+"EditorInterface gives you control over Godot editor's window. It allows "
+"customizing the window, saving and (re-)loading scenes, rendering mesh "
+"previews, inspecting and editing resources and objects, and provides access "
+"to [EditorSettings], [EditorFileSystem], [EditorResourcePreview], "
+"[ScriptEditor], the editor viewport, and information about scenes."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:18
+msgid "Edits the given [Resource]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:25
+msgid ""
+"Returns the main container of Godot editor's window. You can use it, for "
+"example, to retrieve the size of the container and place your controls "
+"accordingly."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:38
+msgid "Returns the edited (current) scene's root [Node]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:45
+msgid "Returns the [EditorSettings]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:52
+msgid "Returns the editor [Viewport]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:71
+msgid "Returns an [Array] with the file paths of the currently opened scenes."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:78
+msgid "Returns the [EditorFileSystem]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:85
+msgid "Returns the [EditorResourcePreview]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:92
+msgid "Returns the [ScriptEditor]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:105
+msgid "Returns the [EditorSelection]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:116
+msgid ""
+"Shows the given property on the given [code]object[/code] in the Editor's "
+"Inspector dock."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:125
+msgid ""
+"Returns the enabled status of a plugin. The plugin name is the same as its "
+"directory name."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:136
+msgid ""
+"Returns mesh previews rendered at the given size as an [Array] of "
+"[Texture2D]s."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:145
+msgid "Opens the scene at the given path."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:154
+msgid "Reloads the scene at the given path."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:161
+msgid ""
+"Saves the scene. Returns either [code]OK[/code] or [code]ERR_CANT_CREATE[/"
+"code] (see [@GlobalScope] constants)."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:172
+msgid "Saves the scene as a file at [code]path[/code]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:181
+msgid ""
+"Selects the file, with the path provided by [code]file[/code], in the "
+"FileSystem dock."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:208
+msgid ""
+"Sets the enabled status of a plugin. The plugin name is the same as its "
+"directory name."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:4
+msgid "Custom gizmo for editing Node3D objects."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:7
+msgid ""
+"Custom gizmo that is used for providing custom visualization and editing "
+"(handles) for Node3D objects. See [EditorNode3DGizmoPlugin] for more "
+"information."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:26
+msgid ""
+"Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be "
+"generated from a regular [Mesh] too. Call this function during [method "
+"redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:41
+msgid ""
+"Adds a list of handles (points) which can be used to deform the object being "
+"edited.\n"
+"There are virtual functions which will be called upon editing of these "
+"handles. Call this function during [method redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:57
+msgid ""
+"Adds lines to the gizmo (as sets of 2 points), with a given material. The "
+"lines are used for visualizing the gizmo. Call this function during [method "
+"redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:84
+msgid ""
+"Adds an unscaled billboard for visualization. Call this function during "
+"[method redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:103
+msgid ""
+"Commit a handle being edited (handles must have been previously added by "
+"[method add_handles]).\n"
+"If the [code]cancel[/code] parameter is [code]true[/code], an option to "
+"restore the edited value to the original is provided."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:113
+msgid ""
+"Gets the name of an edited handle (handles must have been previously added "
+"by [method add_handles]).\n"
+"Handles can be named for reference to the user when editing."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:123
+msgid ""
+"Gets actual value of a handle. This value can be anything and used for "
+"eventually undoing the motion when calling [method commit_handle]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:130
+msgid ""
+"Returns the [EditorNode3DGizmoPlugin] that owns this gizmo. It's useful to "
+"retrieve materials using [method EditorNode3DGizmoPlugin.get_material]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:137
+msgid "Returns the Node3D node associated with this gizmo."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:146
+msgid "Gets whether a handle is highlighted or not."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:153
+msgid ""
+"This function is called when the Node3D this gizmo refers to changes (the "
+"[method Node3D.update_gizmo] is called)."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:166
+msgid ""
+"This function is used when the user drags a gizmo handle (previously added "
+"with [method add_handles]) in screen coordinates.\n"
+"The [Camera3D] is also provided so screen coordinates can be converted to "
+"raycasts."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:4
+msgid "Used by the editor to define Node3D gizmo types."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:7
+msgid ""
+"EditorNode3DGizmoPlugin allows you to define a new type of Gizmo. There are "
+"two main ways to do so: extending [EditorNode3DGizmoPlugin] for the simpler "
+"gizmos, or creating a new [EditorNode3DGizmo] type. See the tutorial in the "
+"documentation for more info."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/"
+"spatial_gizmos.html"
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:21
+msgid ""
+"Adds a new material to the internal material list for the plugin. It can "
+"then be accessed with [method get_material]. Should not be overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:28
+msgid ""
+"Override this method to define whether the gizmo can be hidden or not. "
+"Returns [code]true[/code] if not overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:43
+msgid ""
+"Override this method to commit gizmo handles. Called for this plugin's "
+"active gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:52
+msgid ""
+"Override this method to return a custom [EditorNode3DGizmo] for the spatial "
+"nodes of your choice, return [code]null[/code] for the rest of nodes. See "
+"also [method has_gizmo]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:63
+msgid ""
+"Creates a handle 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_handles]. "
+"Should not be overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:78
+msgid ""
+"Creates an icon 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_unscaled_billboard]. Should not be overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:95
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:106
+msgid ""
+"Override this method to provide gizmo's handle names. Called for this "
+"plugin's active gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:117
+msgid ""
+"Gets actual value of a handle from gizmo. Called for this plugin's active "
+"gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:128
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:135
+msgid ""
+"Override this method to provide the name that will appear in the gizmo "
+"visibility menu."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:150
+msgid ""
+"Override this method to define which Node3D nodes have a gizmo from this "
+"plugin. Whenever a [Node3D] node is added to a scene this method is called, "
+"if it returns [code]true[/code] the node gets a generic [EditorNode3DGizmo] "
+"assigned and is added to this plugin's list of active gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:161
+msgid ""
+"Gets whether a handle is highlighted or not. Called for this plugin's active "
+"gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:168
+msgid ""
+"Override this method to define whether Node3D with this gizmo should be "
+"selecteble even when the gizmo is hidden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:177
+msgid ""
+"Callback to redraw the provided gizmo. Called for this plugin's active "
+"gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:192
+msgid ""
+"Update the value of a handle after it has been updated. Called for this "
+"plugin's active gizmos."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:4
+msgid "Used by the editor to extend its functionality."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:7
+msgid ""
+"Plugins are used by the editor to extend functionality. The most common "
+"types of plugins are those which edit a given node or resource type, import "
+"plugins and export plugins. See also [EditorScript] to add functions to the "
+"editor."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/index.html"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:21
+msgid ""
+"Adds a script at [code]path[/code] to the Autoload list as [code]name[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:32
+msgid ""
+"Adds a control to the bottom panel (together with Output, Debug, Animation, "
+"etc). Returns a reference to the button added. It's up to you to hide/show "
+"the button when needed. When your plugin is deactivated, make sure to remove "
+"your custom control with [method remove_control_from_bottom_panel] and free "
+"it with [method Node.queue_free]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:43
+msgid ""
+"Adds a custom control to a container (see [enum CustomControlContainer]). "
+"There are many locations where custom controls can be added in the editor "
+"UI.\n"
+"Please remember that you have to manage the visibility of your custom "
+"controls yourself (and likely hide it after adding it).\n"
+"When your plugin is deactivated, make sure to remove your custom control "
+"with [method remove_control_from_container] and free it with [method Node."
+"queue_free]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:56
+msgid ""
+"Adds the control to a specific dock slot (see [enum DockSlot] for options).\n"
+"If the dock is repositioned and as long as the plugin is active, the editor "
+"will save the dock position on further sessions.\n"
+"When your plugin is deactivated, make sure to remove your custom control "
+"with [method remove_control_from_docks] and free it with [method Node."
+"queue_free]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:73
+msgid ""
+"Adds a custom type, which will appear in the list of nodes or resources. An "
+"icon can be optionally passed.\n"
+"When given node or resource is selected, the base type will be instanced (e."
+"g. \"Node3D\", \"Control\", \"Resource\"), then the script will be loaded "
+"and set to this object.\n"
+"You can use the virtual method [method handles] to check if your custom "
+"object is being edited by checking the script or using the [code]is[/code] "
+"keyword.\n"
+"During run-time, this will be a simple object with a script so this function "
+"does not need to be called then."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:131
+msgid ""
+"Adds a custom menu item to [b]Project > Tools[/b] as [code]name[/code] that "
+"calls [code]callback[/code] on an instance of [code]handler[/code] with a "
+"parameter [code]ud[/code] when user activates it."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:142
+msgid ""
+"Adds a custom submenu under [b]Project > Tools >[/b] [code]name[/code]. "
+"[code]submenu[/code] should be an object of class [PopupMenu]. This submenu "
+"should be cleaned up using [code]remove_tool_menu_item(name)[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:149
+msgid ""
+"This method is called when the editor is about to save the project, switch "
+"to another tab, etc. It asks the plugin to apply any pending state changes "
+"to ensure consistency.\n"
+"This is used, for example, in shader editors to let the plugin know that it "
+"must apply the shader code being written by the user to the object."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:163
+msgid ""
+"Clear all the state and reset the object being edited to zero. This ensures "
+"your plugin does not keep editing a currently existing node, or a node from "
+"the wrong scene."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:170
+msgid ""
+"Called by the engine when the user disables the [EditorPlugin] in the Plugin "
+"tab of the project settings window."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:179
+msgid ""
+"This function is used for plugins that edit specific object types (nodes or "
+"resources). It requests the editor to edit the given object."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:186
+msgid ""
+"Called by the engine when the user enables the [EditorPlugin] in the Plugin "
+"tab of the project settings window."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:211
+msgid ""
+"Called when there is a root node in the current edited scene, [method "
+"handles] is implemented and an [InputEvent] happens in the 2D viewport. "
+"Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] "
+"consumes the [code]event[/code], otherwise forwards [code]event[/code] to "
+"other Editor classes. Example:\n"
+"[codeblock]\n"
+"# Prevents the InputEvent to reach other Editor classes\n"
+"func forward_canvas_gui_input(event):\n"
+" var forward = true\n"
+" return forward\n"
+"[/codeblock]\n"
+"Must [code]return false[/code] in order to forward the [InputEvent] to other "
+"Editor classes. Example:\n"
+"[codeblock]\n"
+"# Consumes InputEventMouseMotion and forwards other InputEvent types\n"
+"func forward_canvas_gui_input(event):\n"
+" var forward = false\n"
+" if event is InputEventMouseMotion:\n"
+" forward = true\n"
+" return forward\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:237
+msgid ""
+"Called when there is a root node in the current edited scene, [method "
+"handles] is implemented and an [InputEvent] happens in the 3D viewport. "
+"Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] "
+"consumes the [code]event[/code], otherwise forwards [code]event[/code] to "
+"other Editor classes. Example:\n"
+"[codeblock]\n"
+"# Prevents the InputEvent to reach other Editor classes\n"
+"func forward_spatial_gui_input(camera, event):\n"
+" var forward = true\n"
+" return forward\n"
+"[/codeblock]\n"
+"Must [code]return false[/code] in order to forward the [InputEvent] to other "
+"Editor classes. Example:\n"
+"[codeblock]\n"
+"# Consumes InputEventMouseMotion and forwards other InputEvent types\n"
+"func forward_spatial_gui_input(camera, event):\n"
+" var forward = false\n"
+" if event is InputEventMouseMotion:\n"
+" forward = true\n"
+" return forward\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:259
+msgid ""
+"This is for editors that edit script-based objects. You can return a list of "
+"breakpoints in the format ([code]script:line[/code]), for example: "
+"[code]res://path_to_script.gd:25[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:266
+msgid ""
+"Returns the [EditorInterface] object that gives you control over Godot "
+"editor's window and its functionalities."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:273
+msgid ""
+"Override this method in your plugin to return a [Texture2D] in order to give "
+"it an icon.\n"
+"For main screen plugins, this appears at the top of the screen, to the right "
+"of the \"2D\", \"3D\", \"Script\", and \"AssetLib\" buttons.\n"
+"Ideally, the plugin icon should be white with a transparent background and "
+"16x16 pixels in size.\n"
+"[codeblock]\n"
+"func get_plugin_icon():\n"
+" # You can use a custom icon:\n"
+" return preload(\"res://addons/my_plugin/my_plugin_icon.svg\")\n"
+" # Or use a built-in icon:\n"
+" return get_editor_interface().get_base_control().get_icon(\"Node\", "
+"\"EditorIcons\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:289
+msgid ""
+"Override this method in your plugin to provide the name of the plugin when "
+"displayed in the Godot editor.\n"
+"For main screen plugins, this appears at the top of the screen, to the right "
+"of the \"2D\", \"3D\", \"Script\", and \"AssetLib\" buttons."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:297
+msgid ""
+"Gets the Editor's dialogue used for making scripts.\n"
+"[b]Note:[/b] Users can configure it before use."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:305
+msgid ""
+"Gets the state of your plugin editor. This is used when saving the scene (so "
+"state is kept when opening it again) and for switching tabs (so state can be "
+"restored when the tab returns)."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:312
+msgid ""
+"Gets the undo/redo object. Most actions in the editor can be undoable, so "
+"use this object to make sure this happens when it's worth it."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:321
+msgid ""
+"Gets the GUI layout of the plugin. This is used to save the project's editor "
+"layout when [method queue_save_layout] is called or the editor layout was "
+"changed(For example changing the position of a dock)."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:330
+msgid ""
+"Implement this function if your plugin edits a specific type of object "
+"(Resource or Node). If you return [code]true[/code], then you will get the "
+"functions [method edit] and [method make_visible] called when the editor "
+"requests them. If you have declared the methods [method "
+"forward_canvas_gui_input] and [method forward_spatial_gui_input] these will "
+"be called too."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:337
+msgid ""
+"Returns [code]true[/code] if this is a main screen editor plugin (it goes in "
+"the workspace selector together with [b]2D[/b], [b]3D[/b], [b]Script[/b] and "
+"[b]AssetLib[/b])."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:360
+msgid ""
+"This function will be called when the editor is requested to become visible. "
+"It is used for plugins that edit a specific object type.\n"
+"Remember that you have to manage the visibility of all your editor controls "
+"manually."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:368
+msgid "Queue save the project's editor layout."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:377
+msgid "Removes an Autoload [code]name[/code] from the list."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:386
+msgid ""
+"Removes the control from the bottom panel. You have to manually [method Node."
+"queue_free] the control."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:397
+msgid ""
+"Removes the control from the specified container. You have to manually "
+"[method Node.queue_free] the control."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:406
+msgid ""
+"Removes the control from the dock. You have to manually [method Node."
+"queue_free] the control."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:415
+msgid "Removes a custom type added by [method add_custom_type]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:464
+msgid "Removes a menu [code]name[/code] from [b]Project > Tools[/b]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:471
+msgid ""
+"This method is called after the editor saves the project or when it's "
+"closed. It asks the plugin to save edited external scenes/resources."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:484
+msgid ""
+"Use this method if you always want to receive inputs from 3D view screen "
+"inside [method forward_spatial_gui_input]. It might be especially usable if "
+"your plugin will want to use raycast in the scene."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:493
+msgid "Restore the state saved by [method get_state]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:502
+msgid "Restore the plugin GUI layout saved by [method get_window_layout]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:509
+msgid "Updates the overlays of the editor (2D/3D) viewport."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:518
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:531
+msgid ""
+"Emitted when the scene is changed in the editor. The argument will return "
+"the root node of the scene that has just become active. If this scene is new "
+"and empty, the argument will be [code]null[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:538
+msgid ""
+"Emitted when user closes a scene. The argument is file path to a closed "
+"scene."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:584
+msgid "Represents the size of the [enum DockSlot] enum."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:4
+msgid "Custom control to edit properties for adding into the inspector."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:7
+msgid ""
+"This control allows property editing for one or multiple properties into "
+"[EditorInspector]. It is added via [EditorInspectorPlugin]."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:18
+msgid ""
+"If any of the controls added can gain keyboard focus, add it here. This "
+"ensures that focus will be restored if the inspector is refreshed."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:33
+msgid ""
+"If one or several properties have changed, this must be called. [code]field[/"
+"code] is used in case your editor can modify fields separately (as an "
+"example, Vector3.x). The [code]changing[/code] argument avoids the editor "
+"requesting this property to be refreshed (leave as [code]false[/code] if "
+"unsure)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:40
+msgid "Gets the edited object."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:47
+msgid ""
+"Gets the edited property. If your editor is for a single property (added via "
+"[method EditorInspectorPlugin.parse_property]), then this will return the "
+"property."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:54
+msgid "Override if you want to allow a custom tooltip over your property."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:63
+msgid ""
+"Adds controls with this function if you want them on the bottom (below the "
+"label)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:70
+msgid "When this virtual function is called, you must update your editor."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:76
+msgid "Used by the inspector, set when property is checkable."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:79
+msgid "Used by the inspector, when the property is checked."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:82
+msgid "Used by the inspector, when the property must draw with error color."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:85
+msgid "Used by the inspector, when the property can add keys for animation."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:88
+msgid "Sets this property to change the label (if you want to show one)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:91
+msgid "Used by the inspector, when the property is read-only."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:101
+msgid ""
+"Emit it if you want multiple properties modified at the same time. Do not "
+"use if added via [method EditorInspectorPlugin.parse_property]."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:110
+msgid "Used by sub-inspectors. Emit it if what was selected was an Object ID."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:119
+msgid ""
+"Do not emit this manually, use the [method emit_changed] method instead."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:128
+msgid "Emitted when a property was checked. Used internally."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:135
+msgid ""
+"Emit it if you want to add this value as an animation key (check for keying "
+"being enabled first)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:144
+msgid "Emit it if you want to key a property with a single value."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:153
+msgid ""
+"If you want a sub-resource to be edited, emit this signal with the resource."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:162
+msgid "Emitted when selected. Used internally."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:4
+msgid "Helper to generate previews of resources or files."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:7
+msgid "This object is used to generate previews for resources of files."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:18
+msgid "Create an own, custom preview generator."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:27
+msgid ""
+"Check if the resource changed, if so, it will be invalidated and the "
+"corresponding signal emitted."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:42
+msgid ""
+"Queue a resource being edited for preview (using an instance). Once the "
+"preview is ready, your receiver.receiver_func will be called either "
+"containing the preview texture or an empty texture (if no preview was "
+"possible). Callback must have the format: (path,texture,userdata). Userdata "
+"can be anything."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:57
+msgid ""
+"Queue a resource file for preview (using a path). Once the preview is ready, "
+"your receiver.receiver_func will be called either containing the preview "
+"texture or an empty texture (if no preview was possible). Callback must have "
+"the format: (path,texture,userdata). Userdata can be anything."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:66
+msgid "Removes a custom preview generator."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:75
+msgid ""
+"Emitted if a preview was invalidated (changed). [code]path[/code] "
+"corresponds to the path of the preview."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:4
+msgid "Custom generator of previews."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:7
+msgid ""
+"Custom code to generate previews. Please check [code]file_dialog/"
+"thumbnail_size[/code] in [EditorSettings] to find out the right size to do "
+"previews at."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:16
+msgid ""
+"If this function returns [code]true[/code], the generator will call [method "
+"generate] or [method generate_from_path] for small previews as well.\n"
+"By default, it returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:28
+msgid ""
+"Generate a preview from a given resource with the specified size. This must "
+"always be implemented.\n"
+"Returning an empty texture is an OK way to fail and let another generator "
+"take care.\n"
+"Care must be taken because this function is always called from a thread (not "
+"the main thread)."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:41
+msgid ""
+"Generate a preview directly from a path with the specified size. "
+"Implementing this is optional, as default code will load and call [method "
+"generate].\n"
+"Returning an empty texture is an OK way to fail and let another generator "
+"take care.\n"
+"Care must be taken because this function is always called from a thread (not "
+"the main thread)."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:50
+msgid ""
+"If this function returns [code]true[/code], the generator will automatically "
+"generate the small previews from the normal preview texture generated by the "
+"methods [method generate] or [method generate_from_path].\n"
+"By default, it returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:60
+msgid ""
+"Returns [code]true[/code] if your generator supports the resource of type "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/EditorSceneImporter.xml:4
+msgid "Imports scenes from third-parties' 3D files."
+msgstr ""
+
+#: doc/classes/EditorSceneImporterAssimp.xml:4
+msgid "FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/url]."
+msgstr ""
+
+#: doc/classes/EditorSceneImporterAssimp.xml:7
+msgid ""
+"This is an FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/"
+"url]. It currently has many known limitations and works best with static "
+"meshes. Most animated meshes won't import correctly.\n"
+"If exporting a FBX scene from Autodesk Maya, use these FBX export settings:\n"
+"[codeblock]\n"
+"- Smoothing Groups\n"
+"- Smooth Mesh\n"
+"- Triangluate (for meshes with blend shapes)\n"
+"- Bake Animation\n"
+"- Resample All\n"
+"- Deformed Models\n"
+"- Skins\n"
+"- Blend Shapes\n"
+"- Curve Filters\n"
+"- Constant Key Reducer\n"
+"- Auto Tangents Only\n"
+"- *Do not check* Constraints (as it will break the file)\n"
+"- Can check Embed Media (embeds textures into the exported FBX file)\n"
+" - Note that when importing embedded media, the texture and mesh will be a "
+"single immutable file.\n"
+" - You will have to re-export then re-import the FBX if the texture has "
+"changed.\n"
+"- Units: Centimeters\n"
+"- Up Axis: Y\n"
+"- Binary format in FBX 2017\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:4
+msgid "Post-processes scenes after import."
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:7
+msgid ""
+"Imported scenes can be automatically modified right after import by setting "
+"their [b]Custom Script[/b] Import property to a [code]tool[/code] script "
+"that inherits from this class.\n"
+"The [method post_import] callback receives the imported scene's root node "
+"and returns the modified version of the scene. Usage example:\n"
+"[codeblock]\n"
+"tool # Needed so it runs in editor\n"
+"extends EditorScenePostImport\n"
+"\n"
+"# This sample changes all node names\n"
+"\n"
+"# Called right after the scene is imported and gets the root node\n"
+"func post_import(scene):\n"
+" # Change all node names to \"modified_[oldnodename]\"\n"
+" iterate(scene)\n"
+" return scene # Remember to return the imported scene\n"
+"\n"
+"func iterate(node):\n"
+" if node != null:\n"
+" node.name = \"modified_\" + node.name\n"
+" for child in node.get_children():\n"
+" iterate(child)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:29
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/workflow/assets/"
+"importing_scenes.html#custom-script"
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:36
+msgid ""
+"Returns the source file path which got imported (e.g. [code]res://scene.dae[/"
+"code])."
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:43
+msgid "Returns the resource folder the imported scene file is located in."
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:52
+msgid ""
+"Called after the scene was imported. This method must return the modified "
+"version of the scene."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:4
+msgid "Base script that can be used to add extension functions to the editor."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:7
+msgid ""
+"Scripts extending this class and implementing its [method _run] method can "
+"be executed from the Script Editor's [b]File > Run[/b] menu option (or by "
+"pressing [code]Ctrl+Shift+X[/code]) while the editor is running. This is "
+"useful for adding custom in-editor functionality to Godot. For more complex "
+"additions, consider using [EditorPlugin]s instead.\n"
+"[b]Note:[/b] Extending scripts need to have [code]tool[/code] mode enabled.\n"
+"[b]Example script:[/b]\n"
+"[codeblock]\n"
+"tool\n"
+"extends EditorScript\n"
+"\n"
+"func _run():\n"
+" print(\"Hello from the Godot Editor!\")\n"
+"[/codeblock]\n"
+"[b]Note:[/b] The script is run in the Editor context, which means the output "
+"is visible in the console window started with the Editor (stdout) instead of "
+"the usual Godot [b]Output[/b] dock."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:26
+msgid "This method is executed by the Editor when [b]File > Run[/b] is used."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:35
+msgid ""
+"Adds [code]node[/code] as a child of the root node in the editor context.\n"
+"[b]Warning:[/b] The implementation of this method is currently disabled."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:43
+msgid "Returns the [EditorInterface] singleton instance."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:50
+msgid "Returns the Editor's currently active scene."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:4
+msgid "Manages the SceneTree selection in the editor."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:7
+msgid "This object manages the SceneTree selection in the editor."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:18
+msgid "Adds a node to the selection."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:25
+msgid "Clear the selection."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:32
+msgid "Gets the list of selected nodes."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:39
+msgid ""
+"Gets the list of selected nodes, optimized for transform operations (i.e. "
+"moving them, rotating, etc). This list avoids situations where a node is "
+"selected and also child/grandchild."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:48
+msgid "Removes a node from the selection."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:55
+msgid "Emitted when the selection changes."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:4
+msgid "Object that holds the project-independent editor settings."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:7
+msgid ""
+"Object that holds the project-independent editor settings. These settings "
+"are generally visible in the [b]Editor > Editor Settings[/b] menu.\n"
+"Accessing the settings is done by using the regular [Object] API, such as:\n"
+"[codeblock]\n"
+"settings.set(prop,value)\n"
+"settings.get(prop)\n"
+"list_of_settings = settings.get_property_list()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:24
+msgid ""
+"Adds a custom property info to a property. The dictionary must contain:\n"
+"- [code]name[/code]: [String] (the name of the property)\n"
+"- [code]type[/code]: [int] (see [enum Variant.Type])\n"
+"- optionally [code]hint[/code]: [int] (see [enum PropertyHint]) and "
+"[code]hint_string[/code]: [String]\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"editor_settings.set(\"category/property_name\", 0)\n"
+"\n"
+"var property_info = {\n"
+" \"name\": \"category/property_name\",\n"
+" \"type\": TYPE_INT,\n"
+" \"hint\": PROPERTY_HINT_ENUM,\n"
+" \"hint_string\": \"one,two,three\"\n"
+"}\n"
+"\n"
+"editor_settings.add_property_info(property_info)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:49
+msgid "Erase a given setting (pass full property path)."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:56
+msgid "Gets the list of favorite files and directories for this project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:75
+msgid ""
+"Gets the specific project settings path. Projects all have a unique sub-"
+"directory inside the settings path where project specific settings are saved."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:82
+msgid ""
+"Gets the list of recently visited folders in the file dialog for this "
+"project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:97
+msgid ""
+"Gets the global settings path for the engine. Inside this path, you can find "
+"some standard paths such as:\n"
+"[code]settings/tmp[/code] - Used for temporary storage of files\n"
+"[code]settings/templates[/code] - Where export templates are located"
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:132
+msgid "Sets the list of favorite files and directories for this project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:165
+msgid ""
+"Sets the list of recently visited folders in the file dialog for this "
+"project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:182
+msgid "Emitted when editor settings change."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:188
+msgid ""
+"Emitted when editor settings change. It used by various editor plugins to "
+"update their visuals on theme changes or logic on configuration changes."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:4
+msgid ""
+"Version Control System (VCS) interface which reads and writes to the local "
+"VCS in use."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:7
+msgid ""
+"Used by the editor to display VCS extracted information in the editor. The "
+"implementation of this API is included in VCS addons, which are essentially "
+"GDNative plugins that need to be put into the project folder. These VCS "
+"addons are scripts which are attached (on demand) to the object instance of "
+"[code]EditorVCSInterface[/code]. All the functions listed below, instead of "
+"performing the task themselves, they call the internally defined functions "
+"in the VCS addons to provide a plug-n-play experience."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:18
+msgid ""
+"Creates a version commit if the addon is initialized, else returns without "
+"doing anything. Uses the files which have been staged previously, with the "
+"commit message set to a value as provided as in the argument."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:27
+msgid ""
+"Returns an [Array] of [Dictionary] objects containing the diff output from "
+"the VCS in use, if a VCS addon is initialized, else returns an empty [Array] "
+"object. The diff contents also consist of some contextual lines which "
+"provide context to the observed line change in the file.\n"
+"Each [Dictionary] object has the line diff contents under the keys:\n"
+"- [code]\"content\"[/code] to store a [String] containing the line contents\n"
+"- [code]\"status\"[/code] to store a [String] which contains [code]\"+\"[/"
+"code] in case the content is a line addition but it stores a [code]\"-\"[/"
+"code] in case of deletion and an empty string in the case the line content "
+"is neither an addition nor a deletion.\n"
+"- [code]\"new_line_number\"[/code] to store an integer containing the new "
+"line number of the line content.\n"
+"- [code]\"line_count\"[/code] to store an integer containing the number of "
+"lines in the line content.\n"
+"- [code]\"old_line_number\"[/code] to store an integer containing the old "
+"line number of the line content.\n"
+"- [code]\"offset\"[/code] to store the offset of the line change since the "
+"first contextual line content."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:41
+msgid ""
+"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.\n"
+"The following integer values are being used to signify that the detected "
+"file is:\n"
+"- [code]0[/code]: New to the VCS working directory\n"
+"- [code]1[/code]: Modified\n"
+"- [code]2[/code]: Renamed\n"
+"- [code]3[/code]: Deleted\n"
+"- [code]4[/code]: Typechanged"
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:54
+msgid "Returns the project name of the VCS working directory."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:61
+msgid ""
+"Returns the name of the VCS if the VCS has been initialized, else return an "
+"empty string."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:70
+msgid ""
+"Initializes the VCS addon if not already. Uses the argument value as the "
+"path to the working directory of the project. Creates the initial commit if "
+"required. Returns [code]true[/code] if no failure occurs, else returns "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:77
+msgid ""
+"Returns [code]true[/code] if the addon is ready to respond to function "
+"calls, else returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:84
+msgid ""
+"Returns [code]true[/code] if the VCS addon has been initialized, else "
+"returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:91
+msgid ""
+"Shuts down the VCS addon to allow cleanup code to run on call. Returns "
+"[code]true[/code] is no failure occurs, else returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:100
+msgid ""
+"Stages the file which should be committed when [method EditorVCSInterface."
+"commit] is called. Argument should contain the absolute path."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:109
+msgid ""
+"Unstages the file which was staged previously to be committed, so that it is "
+"no longer committed when [method EditorVCSInterface.commit] is called. "
+"Argument should contain the absolute path."
+msgstr ""
+
+#: doc/classes/EncodedObjectAsID.xml:4
+msgid "Holds a reference to an [Object]'s instance ID."
+msgstr ""
+
+#: doc/classes/EncodedObjectAsID.xml:7
+msgid ""
+"Utility class which holds a reference to the internal identifier of an "
+"[Object] instance, as given by [method Object.get_instance_id]. This ID can "
+"then be used to retrieve the object instance with [method @GDScript."
+"instance_from_id].\n"
+"This class is used internally by the editor inspector and script debugger, "
+"but can also be used in plugins to pass and display objects as their IDs."
+msgstr ""
+
+#: doc/classes/EncodedObjectAsID.xml:16
+msgid ""
+"The [Object] identifier stored in this [EncodedObjectAsID] instance. The "
+"object instance can be retrieved with [method @GDScript.instance_from_id]."
+msgstr ""
+
+#: doc/classes/Engine.xml:4
+msgid "Access to basic engine properties."
+msgstr ""
+
+#: doc/classes/Engine.xml:7
+msgid ""
+"The [Engine] class allows you to query and modify the project's run-time "
+"parameters, such as frames per second, time scale, and others."
+msgstr ""
+
+#: doc/classes/Engine.xml:16
+msgid ""
+"Returns engine author information in a Dictionary.\n"
+"[code]lead_developers[/code] - Array of Strings, lead developer names\n"
+"[code]founders[/code] - Array of Strings, founder names\n"
+"[code]project_managers[/code] - Array of Strings, project manager names\n"
+"[code]developers[/code] - Array of Strings, developer names"
+msgstr ""
+
+#: doc/classes/Engine.xml:27
+msgid ""
+"Returns an Array of copyright information Dictionaries.\n"
+"[code]name[/code] - String, component name\n"
+"[code]parts[/code] - Array of Dictionaries {[code]files[/code], "
+"[code]copyright[/code], [code]license[/code]} describing subsections of the "
+"component"
+msgstr ""
+
+#: doc/classes/Engine.xml:36
+msgid ""
+"Returns a Dictionary of Arrays of donor names.\n"
+"{[code]platinum_sponsors[/code], [code]gold_sponsors[/code], "
+"[code]mini_sponsors[/code], [code]gold_donors[/code], [code]silver_donors[/"
+"code], [code]bronze_donors[/code]}"
+msgstr ""
+
+#: doc/classes/Engine.xml:44
+msgid ""
+"Returns the total number of frames drawn. If the render loop is disabled "
+"with [code]--disable-render-loop[/code] via command line, this returns "
+"[code]0[/code]. See also [method get_idle_frames]."
+msgstr ""
+
+#: doc/classes/Engine.xml:51
+msgid "Returns the frames per second of the running game."
+msgstr ""
+
+#: doc/classes/Engine.xml:58
+msgid ""
+"Returns the total number of frames passed since engine initialization which "
+"is advanced on each [b]idle frame[/b], regardless of whether the render loop "
+"is enabled. See also [method get_frames_drawn]."
+msgstr ""
+
+#: doc/classes/Engine.xml:65
+msgid ""
+"Returns Dictionary of licenses used by Godot and included third party "
+"components."
+msgstr ""
+
+#: doc/classes/Engine.xml:72
+msgid "Returns Godot license text."
+msgstr ""
+
+#: doc/classes/Engine.xml:79
+msgid "Returns the main loop object (see [MainLoop] and [SceneTree])."
+msgstr ""
+
+#: doc/classes/Engine.xml:86
+msgid ""
+"Returns the total number of frames passed since engine initialization which "
+"is advanced on each [b]physics frame[/b]."
+msgstr ""
+
+#: doc/classes/Engine.xml:93
+msgid ""
+"Returns the fraction through the current physics tick we are at the time of "
+"rendering the frame. This can be used to implement fixed timestep "
+"interpolation."
+msgstr ""
+
+#: doc/classes/Engine.xml:102
+msgid ""
+"Returns a global singleton with given [code]name[/code]. Often used for "
+"plugins, e.g. GodotPayments."
+msgstr ""
+
+#: doc/classes/Engine.xml:109
+msgid ""
+"Returns the current engine version information in a Dictionary.\n"
+"[code]major[/code] - Holds the major version number as an int\n"
+"[code]minor[/code] - Holds the minor version number as an int\n"
+"[code]patch[/code] - Holds the patch version number as an int\n"
+"[code]hex[/code] - Holds the full version number encoded as a "
+"hexadecimal int with one byte (2 places) per number (see example below)\n"
+"[code]status[/code] - Holds the status (e.g. \"beta\", \"rc1\", "
+"\"rc2\", ... \"stable\") as a String\n"
+"[code]build[/code] - Holds the build name (e.g. \"custom_build\") as a "
+"String\n"
+"[code]hash[/code] - Holds the full Git commit hash as a String\n"
+"[code]year[/code] - Holds the year the version was released in as an "
+"int\n"
+"[code]string[/code] - [code]major[/code] + [code]minor[/code] + "
+"[code]patch[/code] + [code]status[/code] + [code]build[/code] in a single "
+"String\n"
+"The [code]hex[/code] value is encoded as follows, from left to right: one "
+"byte for the major, one byte for the minor, one byte for the patch version. "
+"For example, \"3.1.12\" would be [code]0x03010C[/code]. [b]Note:[/b] It's "
+"still an int internally, and printing it will give you its decimal "
+"representation, which is not particularly meaningful. Use hexadecimal "
+"literals for easy version comparisons from code:\n"
+"[codeblock]\n"
+"if Engine.get_version_info().hex >= 0x030200:\n"
+" # Do things specific to version 3.2 or later\n"
+"else:\n"
+" # Do things specific to versions before 3.2\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Engine.xml:134
+msgid ""
+"Returns [code]true[/code] if a singleton with given [code]name[/code] exists "
+"in global scope."
+msgstr ""
+
+#: doc/classes/Engine.xml:141
+msgid ""
+"Returns [code]true[/code] if the game is inside the fixed process and "
+"physics phase of the game loop."
+msgstr ""
+
+#: doc/classes/Engine.xml:147
+msgid ""
+"If [code]true[/code], it is running inside the editor. Useful for tool "
+"scripts."
+msgstr ""
+
+#: doc/classes/Engine.xml:150
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Engine.xml:153
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Engine.xml:156
+msgid ""
+"The desired frames per second. If the hardware cannot keep up, this setting "
+"may not be respected. A value of 0 means no limit."
+msgstr ""
+
+#: doc/classes/Engine.xml:159
+msgid ""
+"Controls how fast or slow the in-game clock ticks versus the real life one. "
+"It defaults to 1.0. A value of 2.0 means the game moves twice as fast as "
+"real life, whilst a value of 0.5 means the game moves at half the regular "
+"speed."
+msgstr ""
+
+#: doc/classes/Environment.xml:4
+msgid ""
+"Resource for environment nodes (like [WorldEnvironment]) that define "
+"multiple rendering options."
+msgstr ""
+
+#: doc/classes/Environment.xml:7
+msgid ""
+"Resource for environment nodes (like [WorldEnvironment]) that define "
+"multiple environment operations (such as background [Sky] or [Color], "
+"ambient light, fog, depth-of-field...). These parameters affect the final "
+"render of the scene. The order of these operations is:\n"
+"- Depth of Field Blur\n"
+"- Glow\n"
+"- Tonemap (Auto Exposure)\n"
+"- Adjustments"
+msgstr ""
+
+#: doc/classes/Environment.xml:14 doc/classes/WorldEnvironment.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/"
+"environment_and_post_processing.html"
+msgstr ""
+
+#: doc/classes/Environment.xml:15
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/high_dynamic_range.html"
+msgstr ""
+
+#: doc/classes/Environment.xml:24
+msgid ""
+"Returns [code]true[/code] if the glow level [code]idx[/code] is specified, "
+"[code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/Environment.xml:35
+msgid ""
+"Enables or disables the glow level at index [code]idx[/code]. Each level "
+"relies on the previous level. This means that enabling higher glow levels "
+"will slow down the glow effect rendering, even if previous levels aren't "
+"enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:41
+msgid ""
+"The global brightness value of the rendered scene. Effective only if "
+"[code]adjustment_enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:44
+msgid ""
+"Applies the provided [Texture2D] resource to affect the global color aspect "
+"of the rendered scene. Effective only if [code]adjustment_enabled[/code] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:47
+msgid ""
+"The global contrast value of the rendered scene (default value is 1). "
+"Effective only if [code]adjustment_enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:50
+msgid ""
+"If [code]true[/code], enables the [code]adjustment_*[/code] properties "
+"provided by this resource. If [code]false[/code], modifications to the "
+"[code]adjustment_*[/code] properties will have no effect on the rendered "
+"scene."
+msgstr ""
+
+#: doc/classes/Environment.xml:53
+msgid ""
+"The global color saturation value of the rendered scene (default value is "
+"1). Effective only if [code]adjustment_enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:56
+msgid "The ambient light's [Color]."
+msgstr ""
+
+#: doc/classes/Environment.xml:59
+msgid ""
+"The ambient light's energy. The higher the value, the stronger the light."
+msgstr ""
+
+#: doc/classes/Environment.xml:64
+msgid ""
+"Defines the amount of light that the sky brings on the scene. A value of 0 "
+"means that the sky's light emission has no effect on the scene illumination, "
+"thus all ambient illumination is provided by the ambient light. On the "
+"contrary, a value of 1 means that all the light that affects the scene is "
+"provided by the sky, thus the ambient light parameter has no effect on the "
+"scene."
+msgstr ""
+
+#: doc/classes/Environment.xml:69
+msgid ""
+"If [code]true[/code], enables the tonemapping auto exposure mode of the "
+"scene renderer. If [code]true[/code], the renderer will automatically "
+"determine the exposure setting to adapt to the scene's illumination and the "
+"observed light."
+msgstr ""
+
+#: doc/classes/Environment.xml:72
+msgid "The maximum luminance value for the auto exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:75
+msgid "The minimum luminance value for the auto exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:78
+msgid ""
+"The scale of the auto exposure effect. Affects the intensity of auto "
+"exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:81
+msgid ""
+"The speed of the auto exposure effect. Affects the time needed for the "
+"camera to perform auto exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:84
+msgid "The ID of the camera feed to show in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:87
+msgid ""
+"The maximum layer ID to display. Only effective when using the [constant "
+"BG_CANVAS] background mode."
+msgstr ""
+
+#: doc/classes/Environment.xml:90
+msgid ""
+"The [Color] displayed for clear areas of the scene. Only effective when "
+"using the [constant BG_COLOR] background mode."
+msgstr ""
+
+#: doc/classes/Environment.xml:93
+msgid "The power of the light emitted by the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:96
+msgid "The background mode. See [enum BGMode] for possible values."
+msgstr ""
+
+#: doc/classes/Environment.xml:99
+msgid "The fog's [Color]."
+msgstr ""
+
+#: doc/classes/Environment.xml:102
+msgid "The fog's depth starting distance from the camera."
+msgstr ""
+
+#: doc/classes/Environment.xml:105
+msgid ""
+"The fog depth's intensity curve. A number of presets are available in the "
+"[b]Inspector[/b] by right-clicking the curve."
+msgstr ""
+
+#: doc/classes/Environment.xml:108
+msgid ""
+"If [code]true[/code], the depth fog effect is enabled. When enabled, fog "
+"will appear in the distance (relative to the camera)."
+msgstr ""
+
+#: doc/classes/Environment.xml:111
+msgid ""
+"The fog's depth end distance from the camera. If this value is set to 0, it "
+"will be equal to the current camera's [member Camera3D.far] value."
+msgstr ""
+
+#: doc/classes/Environment.xml:114
+msgid ""
+"If [code]true[/code], fog effects are enabled. [member fog_height_enabled] "
+"and/or [member fog_depth_enabled] must be set to [code]true[/code] to "
+"actually display fog."
+msgstr ""
+
+#: doc/classes/Environment.xml:117
+msgid ""
+"The height fog's intensity. A number of presets are available in the "
+"[b]Inspector[/b] by right-clicking the curve."
+msgstr ""
+
+#: doc/classes/Environment.xml:120
+msgid ""
+"If [code]true[/code], the height fog effect is enabled. When enabled, fog "
+"will appear in a defined height range, regardless of the distance from the "
+"camera. This can be used to simulate \"deep water\" effects with a lower "
+"performance cost compared to a dedicated shader."
+msgstr ""
+
+#: doc/classes/Environment.xml:123
+msgid ""
+"The Y coordinate where the height fog will be the most intense. If this "
+"value is greater than [member fog_height_min], fog will be displayed from "
+"bottom to top. Otherwise, it will be displayed from top to bottom."
+msgstr ""
+
+#: doc/classes/Environment.xml:126
+msgid ""
+"The Y coordinate where the height fog will be the least intense. If this "
+"value is greater than [member fog_height_max], fog will be displayed from "
+"top to bottom. Otherwise, it will be displayed from bottom to top."
+msgstr ""
+
+#: doc/classes/Environment.xml:129
+msgid ""
+"The intensity of the depth fog color transition when looking towards the "
+"sun. The sun's direction is determined automatically using the "
+"DirectionalLight3D node in the scene."
+msgstr ""
+
+#: doc/classes/Environment.xml:132
+msgid "The depth fog's [Color] when looking towards the sun."
+msgstr ""
+
+#: doc/classes/Environment.xml:135
+msgid ""
+"The intensity of the fog light transmittance effect. Amount of light that "
+"the fog transmits."
+msgstr ""
+
+#: doc/classes/Environment.xml:138
+msgid ""
+"Enables fog's light transmission effect. If [code]true[/code], light will be "
+"more visible in the fog to simulate light scattering as in real life."
+msgstr ""
+
+#: doc/classes/Environment.xml:141
+msgid "The glow blending mode."
+msgstr ""
+
+#: doc/classes/Environment.xml:144
+msgid ""
+"The bloom's intensity. If set to a value higher than [code]0[/code], this "
+"will make glow visible in areas darker than the [member glow_hdr_threshold]."
+msgstr ""
+
+#: doc/classes/Environment.xml:147
+msgid "If [code]true[/code], the glow effect is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:150
+msgid ""
+"The higher threshold of the HDR glow. Areas brighter than this threshold "
+"will be clamped for the purposes of the glow effect."
+msgstr ""
+
+#: doc/classes/Environment.xml:153
+msgid "The bleed scale of the HDR glow."
+msgstr ""
+
+#: doc/classes/Environment.xml:156
+msgid ""
+"The lower threshold of the HDR glow. When using the GLES2 renderer (which "
+"doesn't support HDR), this needs to be below [code]1.0[/code] for glow to be "
+"visible. A value of [code]0.9[/code] works well in this case."
+msgstr ""
+
+#: doc/classes/Environment.xml:159
+msgid ""
+"The glow intensity. When using the GLES2 renderer, this should be increased "
+"to 1.5 to compensate for the lack of HDR rendering."
+msgstr ""
+
+#: doc/classes/Environment.xml:162
+msgid ""
+"If [code]true[/code], the 1st level of glow is enabled. This is the most "
+"\"local\" level (least blurry)."
+msgstr ""
+
+#: doc/classes/Environment.xml:165
+msgid "If [code]true[/code], the 2th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:168
+msgid "If [code]true[/code], the 3th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:171
+msgid "If [code]true[/code], the 4th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:174
+msgid "If [code]true[/code], the 5th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:177
+msgid "If [code]true[/code], the 6th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:180
+msgid ""
+"If [code]true[/code], the 7th level of glow is enabled. This is the most "
+"\"global\" level (blurriest)."
+msgstr ""
+
+#: doc/classes/Environment.xml:185
+msgid ""
+"The glow strength. When using the GLES2 renderer, this should be increased "
+"to 1.3 to compensate for the lack of HDR rendering."
+msgstr ""
+
+#: doc/classes/Environment.xml:190
+msgid "The [Sky] resource used for this [Environment]."
+msgstr ""
+
+#: doc/classes/Environment.xml:197
+msgid "The depth tolerance for screen-space reflections."
+msgstr ""
+
+#: doc/classes/Environment.xml:200
+msgid ""
+"If [code]true[/code], screen-space reflections are enabled. Screen-space "
+"reflections are more accurate than reflections from [GIProbe]s or "
+"[ReflectionProbe]s, but are slower and can't reflect surfaces occluded by "
+"others."
+msgstr ""
+
+#: doc/classes/Environment.xml:203
+msgid ""
+"The fade-in distance for screen-space reflections. Affects the area from the "
+"reflected material to the screen-space reflection)."
+msgstr ""
+
+#: doc/classes/Environment.xml:206
+msgid ""
+"The fade-out distance for screen-space reflections. Affects the area from "
+"the screen-space reflection to the \"global\" reflection."
+msgstr ""
+
+#: doc/classes/Environment.xml:209
+msgid ""
+"The maximum number of steps for screen-space reflections. Higher values are "
+"slower."
+msgstr ""
+
+#: doc/classes/Environment.xml:212
+msgid ""
+"The screen-space ambient occlusion intensity on materials that have an AO "
+"texture defined. Values higher than [code]0[/code] will make the SSAO effect "
+"visible in areas darkened by AO textures."
+msgstr ""
+
+#: doc/classes/Environment.xml:215
+msgid ""
+"The screen-space ambient occlusion bias. This should be kept high enough to "
+"prevent \"smooth\" curves from being affected by ambient occlusion."
+msgstr ""
+
+#: doc/classes/Environment.xml:218
+msgid ""
+"The screen-space ambient occlusion blur quality. See [enum SSAOBlur] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/Environment.xml:221
+msgid "The screen-space ambient occlusion edge sharpness."
+msgstr ""
+
+#: doc/classes/Environment.xml:224
+msgid ""
+"If [code]true[/code], the screen-space ambient occlusion effect is enabled. "
+"This darkens objects' corners and cavities to simulate ambient light not "
+"reaching the entire object as in real life. This works well for small, "
+"dynamic objects, but baked lighting or ambient occlusion textures will do a "
+"better job at displaying ambient occlusion on large static objects. This is "
+"a costly effect and should be disabled first when running into performance "
+"issues."
+msgstr ""
+
+#: doc/classes/Environment.xml:227
+msgid ""
+"The primary screen-space ambient occlusion intensity. See also [member "
+"ssao_radius]."
+msgstr ""
+
+#: doc/classes/Environment.xml:230
+msgid ""
+"The screen-space ambient occlusion intensity in direct light. In real life, "
+"ambient occlusion only applies to indirect light, which means its effects "
+"can't be seen in direct light. Values higher than [code]0[/code] will make "
+"the SSAO effect visible in direct light."
+msgstr ""
+
+#: doc/classes/Environment.xml:233
+msgid "The primary screen-space ambient occlusion radius."
+msgstr ""
+
+#: doc/classes/Environment.xml:236
+msgid "The default exposure used for tonemapping."
+msgstr ""
+
+#: doc/classes/Environment.xml:239
+msgid ""
+"The tonemapping mode to use. Tonemapping is the process that \"converts\" "
+"HDR values to be suitable for rendering on a LDR display. (Godot doesn't "
+"support rendering on HDR displays yet.)"
+msgstr ""
+
+#: doc/classes/Environment.xml:242
+msgid ""
+"The white reference value for tonemapping. Only effective if the [member "
+"tonemap_mode] isn't set to [constant TONE_MAPPER_LINEAR]."
+msgstr ""
+
+#: doc/classes/Environment.xml:247
+msgid ""
+"Clears the background using the clear color defined in [member "
+"ProjectSettings.rendering/environment/default_clear_color]."
+msgstr ""
+
+#: doc/classes/Environment.xml:250
+msgid "Clears the background using a custom clear color."
+msgstr ""
+
+#: doc/classes/Environment.xml:253
+msgid "Displays a user-defined sky in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:256
+msgid "Displays a [CanvasLayer] in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:259
+msgid ""
+"Keeps on screen every pixel drawn in the background. This is the fastest "
+"background mode, but it can only be safely used in fully-interior scenes (no "
+"visible sky or sky reflections). If enabled in a scene where the background "
+"is visible, \"ghost trail\" artifacts will be visible when moving the camera."
+msgstr ""
+
+#: doc/classes/Environment.xml:262 doc/classes/RenderingServer.xml:3476
+msgid "Displays a camera feed in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:265
+msgid "Represents the size of the [enum BGMode] enum."
+msgstr ""
+
+#: doc/classes/Environment.xml:282
+msgid ""
+"Additive glow blending mode. Mostly used for particles, glows (bloom), lens "
+"flare, bright sources."
+msgstr ""
+
+#: doc/classes/Environment.xml:285
+msgid ""
+"Screen glow blending mode. Increases brightness, used frequently with bloom."
+msgstr ""
+
+#: doc/classes/Environment.xml:288
+msgid ""
+"Soft light glow blending mode. Modifies contrast, exposes shadows and "
+"highlights (vivid bloom)."
+msgstr ""
+
+#: doc/classes/Environment.xml:291
+msgid ""
+"Replace glow blending mode. Replaces all pixels' color by the glow value. "
+"This can be used to simulate a full-screen blur effect by tweaking the glow "
+"parameters to match the original image's brightness."
+msgstr ""
+
+#: doc/classes/Environment.xml:296
+msgid ""
+"Linear tonemapper operator. Reads the linear data and passes it on "
+"unmodified."
+msgstr ""
+
+#: doc/classes/Environment.xml:299
+msgid ""
+"Reinhardt tonemapper operator. Performs a variation on rendered pixels' "
+"colors by this formula: [code]color = color / (1 + color)[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:302
+msgid "Filmic tonemapper operator."
+msgstr ""
+
+#: doc/classes/Environment.xml:305
+msgid "Academy Color Encoding System tonemapper operator."
+msgstr ""
+
+#: doc/classes/Environment.xml:308
+msgid "No blur for the screen-space ambient occlusion effect (fastest)."
+msgstr ""
+
+#: doc/classes/Environment.xml:311
+msgid "1×1 blur for the screen-space ambient occlusion effect."
+msgstr ""
+
+#: doc/classes/Environment.xml:314
+msgid "2×2 blur for the screen-space ambient occlusion effect."
+msgstr ""
+
+#: doc/classes/Environment.xml:317
+msgid "3×3 blur for the screen-space ambient occlusion effect (slowest)."
+msgstr ""
+
+#: doc/classes/Expression.xml:4
+msgid "A class that stores an expression you can execute."
+msgstr ""
+
+#: doc/classes/Expression.xml:7
+msgid ""
+"An expression can be made of any arithmetic operation, built-in math "
+"function call, method call of a passed instance, or built-in type "
+"construction call.\n"
+"An example expression text using the built-in math functions could be "
+"[code]sqrt(pow(3,2) + pow(4,2))[/code].\n"
+"In the following example we use a [LineEdit] node to write our expression "
+"and show the result.\n"
+"[codeblock]\n"
+"onready var expression = Expression.new()\n"
+"\n"
+"func _ready():\n"
+" $LineEdit.connect(\"text_entered\", self, \"_on_text_entered\")\n"
+"\n"
+"func _on_text_entered(command):\n"
+" var error = expression.parse(command, [])\n"
+" if error != OK:\n"
+" print(expression.get_error_text())\n"
+" return\n"
+" var result = expression.execute([], null, true)\n"
+" if not expression.has_execute_failed():\n"
+" $LineEdit.text = str(result)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Expression.xml:39
+msgid ""
+"Executes the expression that was previously parsed by [method parse] and "
+"returns the result. Before you use the returned object, you should check if "
+"the method failed by calling [method has_execute_failed].\n"
+"If you defined input variables in [method parse], you can specify their "
+"values in the inputs array, in the same order."
+msgstr ""
+
+#: doc/classes/Expression.xml:47
+msgid "Returns the error text if [method parse] has failed."
+msgstr ""
+
+#: doc/classes/Expression.xml:54
+msgid "Returns [code]true[/code] if [method execute] has failed."
+msgstr ""
+
+#: doc/classes/Expression.xml:65
+msgid ""
+"Parses the expression and returns an [enum Error] code.\n"
+"You can optionally specify names of variables that may appear in the "
+"expression with [code]input_names[/code], so that you can bind them when it "
+"gets executed."
+msgstr ""
+
+#: doc/classes/File.xml:4
+msgid "Type to handle file reading and writing operations."
+msgstr ""
+
+#: doc/classes/File.xml:7
+msgid ""
+"File type. This is used to permanently store data into the user device's "
+"file system and to read from it. This can be used to store game save data or "
+"player configuration files, for example.\n"
+"Here's a sample on how to write and read from a file:\n"
+"[codeblock]\n"
+"func save(content):\n"
+" var file = File.new()\n"
+" file.open(\"user://save_game.dat\", File.WRITE)\n"
+" file.store_string(content)\n"
+" file.close()\n"
+"\n"
+"func load():\n"
+" var file = File.new()\n"
+" file.open(\"user://save_game.dat\", File.READ)\n"
+" var content = file.get_as_text()\n"
+" file.close()\n"
+" return content\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/File.xml:32
+msgid "Closes the currently opened file."
+msgstr ""
+
+#: doc/classes/File.xml:39
+msgid ""
+"Returns [code]true[/code] if the file cursor has read past the end of the "
+"file.\n"
+"[b]Note:[/b] This function will still return [code]false[/code] while at the "
+"end of the file and only activates when reading past it. This can be "
+"confusing but it conforms to how low-level file access works in all "
+"operating systems. There is always [method get_len] and [method "
+"get_position] to implement a custom logic."
+msgstr ""
+
+#: doc/classes/File.xml:49
+msgid ""
+"Returns [code]true[/code] if the file exists in the given path.\n"
+"[b]Note:[/b] Many resources types are imported (e.g. textures or sound "
+"files), and that their source asset will not be included in the exported "
+"game, as only the imported version is used (in the [code]res://.import[/"
+"code] folder). To check for the existence of such resources while taking "
+"into account the remapping to their imported location, use [method "
+"ResourceLoader.exists]. Typically, using [code]File.file_exists[/code] on an "
+"imported resource would work while you are developing in the editor (the "
+"source asset is present in [code]res://[/code], but fail when exported)."
+msgstr ""
+
+#: doc/classes/File.xml:57
+msgid "Returns the next 16 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:64
+msgid "Returns the next 32 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:71
+msgid "Returns the next 64 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:78
+msgid "Returns the next 8 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:85
+msgid ""
+"Returns the whole file as a [String].\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:95
+msgid "Returns next [code]len[/code] bytes of the file as a [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/File.xml:104
+msgid ""
+"Returns the next value of the file in CSV (Comma-Separated Values) format. "
+"You can pass a different delimiter [code]delim[/code] to use other than the "
+"default [code]\",\"[/code] (comma). This delimiter must be one-character "
+"long.\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:112
+msgid "Returns the next 64 bits from the file as a floating-point number."
+msgstr ""
+
+#: doc/classes/File.xml:119
+msgid ""
+"Returns the last error that happened when trying to perform operations. "
+"Compare with the [code]ERR_FILE_*[/code] constants from [enum Error]."
+msgstr ""
+
+#: doc/classes/File.xml:126
+msgid "Returns the next 32 bits from the file as a floating-point number."
+msgstr ""
+
+#: doc/classes/File.xml:133
+msgid "Returns the size of the file in bytes."
+msgstr ""
+
+#: doc/classes/File.xml:140
+msgid ""
+"Returns the next line of the file as a [String].\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:150
+msgid ""
+"Returns an MD5 String representing the file at the given path or an empty "
+"[String] on failure."
+msgstr ""
+
+#: doc/classes/File.xml:159
+msgid ""
+"Returns the last time the [code]file[/code] was modified in unix timestamp "
+"format or returns a [String] \"ERROR IN [code]file[/code]\". This unix "
+"timestamp can be converted to datetime by using [method OS."
+"get_datetime_from_unix_time]."
+msgstr ""
+
+#: doc/classes/File.xml:166
+msgid ""
+"Returns a [String] saved in Pascal format from the file.\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:174
+msgid "Returns the path as a [String] for the current open file."
+msgstr ""
+
+#: doc/classes/File.xml:181
+msgid "Returns the absolute path as a [String] for the current open file."
+msgstr ""
+
+#: doc/classes/File.xml:188
+msgid "Returns the file cursor's position."
+msgstr ""
+
+#: doc/classes/File.xml:195
+msgid "Returns the next bits from the file as a floating-point number."
+msgstr ""
+
+#: doc/classes/File.xml:204
+msgid ""
+"Returns a SHA-256 [String] representing the file at the given path or an "
+"empty [String] on failure."
+msgstr ""
+
+#: doc/classes/File.xml:213
+msgid ""
+"Returns the next [Variant] value from the file. If [code]allow_objects[/"
+"code] is [code]true[/code], decoding objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/File.xml:221
+msgid "Returns [code]true[/code] if the file is currently opened."
+msgstr ""
+
+#: doc/classes/File.xml:232
+msgid "Opens the file for writing or reading, depending on the flags."
+msgstr ""
+
+#: doc/classes/File.xml:245
+msgid "Opens a compressed file for reading or writing."
+msgstr ""
+
+#: doc/classes/File.xml:258
+msgid ""
+"Opens an encrypted file in write or read mode. You need to pass a binary key "
+"to encrypt/decrypt it."
+msgstr ""
+
+#: doc/classes/File.xml:271
+msgid ""
+"Opens an encrypted file in write or read mode. You need to pass a password "
+"to encrypt/decrypt it."
+msgstr ""
+
+#: doc/classes/File.xml:280
+msgid ""
+"Changes the file reading/writing cursor to the specified position (in bytes "
+"from the beginning of the file)."
+msgstr ""
+
+#: doc/classes/File.xml:289
+msgid ""
+"Changes the file reading/writing cursor to the specified position (in bytes "
+"from the end of the file).\n"
+"[b]Note:[/b] This is an offset, so you should use negative numbers or the "
+"cursor will be at the end of the file."
+msgstr ""
+
+#: doc/classes/File.xml:299
+msgid "Stores an integer as 16 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:308
+msgid "Stores an integer as 32 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:317
+msgid "Stores an integer as 64 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:326
+msgid "Stores an integer as 8 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:335
+msgid "Stores the given array of bytes in the file."
+msgstr ""
+
+#: doc/classes/File.xml:346
+msgid ""
+"Store the given [PackedStringArray] in the file as a line formatted in the "
+"CSV (Comma-Separated Values) format. You can pass a different delimiter "
+"[code]delim[/code] to use other than the default [code]\",\"[/code] (comma). "
+"This delimiter must be one-character long.\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:356
+msgid "Stores a floating-point number as 64 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:365
+msgid "Stores a floating-point number as 32 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:374
+msgid ""
+"Stores the given [String] as a line in the file.\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:384
+msgid ""
+"Stores the given [String] as a line in the file in Pascal format (i.e. also "
+"store the length of the string).\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:394
+msgid "Stores a floating-point number in the file."
+msgstr ""
+
+#: doc/classes/File.xml:403
+msgid ""
+"Stores the given [String] in the file.\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:415
+msgid ""
+"Stores any Variant value in the file. If [code]full_objects[/code] is "
+"[code]true[/code], encoding objects is allowed (and can potentially include "
+"code)."
+msgstr ""
+
+#: doc/classes/File.xml:421
+msgid ""
+"If [code]true[/code], the file's endianness is swapped. Use this if you're "
+"dealing with files written on big-endian machines.\n"
+"[b]Note:[/b] This is about the file format, not CPU type. This is always "
+"reset to [code]false[/code] whenever you open the file."
+msgstr ""
+
+#: doc/classes/File.xml:427
+msgid "Opens the file for read operations."
+msgstr ""
+
+#: doc/classes/File.xml:430
+msgid ""
+"Opens the file for write operations. Create it if the file does not exist "
+"and truncate if it exists."
+msgstr ""
+
+#: doc/classes/File.xml:433
+msgid ""
+"Opens the file for read and write operations. Does not truncate the file."
+msgstr ""
+
+#: doc/classes/File.xml:436
+msgid ""
+"Opens the file for read and write operations. Create it if the file does not "
+"exist and truncate if it exists."
+msgstr ""
+
+#: doc/classes/File.xml:439
+msgid "Uses the [url=http://fastlz.org/]FastLZ[/url] compression method."
+msgstr ""
+
+#: doc/classes/File.xml:442
+msgid ""
+"Uses the [url=https://en.wikipedia.org/wiki/DEFLATE]DEFLATE[/url] "
+"compression method."
+msgstr ""
+
+#: doc/classes/File.xml:445
+msgid ""
+"Uses the [url=https://facebook.github.io/zstd/]Zstandard[/url] compression "
+"method."
+msgstr ""
+
+#: doc/classes/File.xml:448
+msgid "Uses the [url=https://www.gzip.org/]gzip[/url] compression method."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:4
+msgid "Dialog for selecting files or directories in the filesystem."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:7
+msgid ""
+"FileDialog is a preset dialog used to choose files and directories in the "
+"filesystem. It supports filter masks."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:18
+msgid ""
+"Adds [code]filter[/code] as a custom filter; [code]filter[/code] should be "
+"of the form [code]\"filename.extension ; Description\"[/code]. For example, "
+"[code]\"*.png ; PNG Images\"[/code]."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:25
+msgid "Clear all the added filters in the dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:32
+msgid "Clear currently selected items in the dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:39
+msgid "Returns the LineEdit for the selected file."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:46
+msgid ""
+"Returns the vertical box container of the dialog, custom controls can be "
+"added to it."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:53
+msgid "Invalidate and update the current dialog content list."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:59
+msgid "The file system access scope. See enum [code]Access[/code] constants."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:62
+msgid "The current working directory of the file dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:65
+msgid "The currently selected file of the file dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:68
+msgid "The currently selected file path of the file dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:72
+msgid ""
+"The dialog's open or save mode, which affects the selection behavior. See "
+"[enum FileMode]."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:75
+msgid ""
+"The available file type filters. For example, this shows only [code].png[/"
+"code] and [code].gd[/code] files: [code]set_filters(PackedStringArray([\"*."
+"png ; PNG Images\",\"*.gd ; GDScript Files\"]))[/code]."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:78
+msgid ""
+"If [code]true[/code], changing the [code]Mode[/code] property will set the "
+"window title accordingly (e.g. setting mode to [constant "
+"FILE_MODE_OPEN_FILE] will change the window title to \"Open a File\")."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:81
+msgid "If [code]true[/code], the dialog will show hidden files."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:90
+msgid "Emitted when the user selects a directory."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:97
+msgid ""
+"Emitted when the user selects a file by double-clicking it or pressing the "
+"[b]OK[/b] button."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:104
+msgid "Emitted when the user selects multiple files."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:110
+msgid "The dialog allows selecting one, and only one file."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:113
+msgid "The dialog allows selecting multiple files."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:116
+msgid ""
+"The dialog only allows selecting a directory, disallowing the selection of "
+"any file."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:119
+msgid "The dialog allows selecting one file or directory."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:122
+msgid "The dialog will warn when a file exists."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:125
+msgid ""
+"The dialog only allows accessing files under the [Resource] path "
+"([code]res://[/code])."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:128
+msgid ""
+"The dialog only allows accessing files under user data path ([code]user://[/"
+"code])."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:131
+msgid "The dialog allows accessing files on the whole file system."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:136
+msgid ""
+"The color tint for disabled files (when the [FileDialog] is used in open "
+"folder mode)."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:139
+msgid "Custom icon for folders."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:142
+msgid "The color modulation applied to the folder icon."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:145
+msgid "Custom icon for the parent folder arrow."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:148
+msgid "Custom icon for the reload button."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:151
+msgid "Custom icon for the toggle hidden button."
+msgstr ""
+
+#: doc/classes/float.xml:4 doc/classes/float.xml:7
+msgid "Float built-in type."
+msgstr ""
+
+#: doc/classes/float.xml:18
+msgid ""
+"Cast a [bool] value to a floating-point value, [code]float(true)[/code] will "
+"be equal to 1.0 and [code]float(false)[/code] will be equal to 0.0."
+msgstr ""
+
+#: doc/classes/float.xml:27
+msgid ""
+"Cast an [int] value to a floating-point value, [code]float(1)[/code] will be "
+"equal to 1.0."
+msgstr ""
+
+#: doc/classes/float.xml:36
+msgid ""
+"Cast a [String] value to a floating-point value. This method accepts float "
+"value strings like [code]\"1.23\"[/code] and exponential notation strings "
+"for its parameter so calling [code]float(\"1e3\")[/code] will return 1000.0 "
+"and calling [code]float(\"1e-3\")[/code] will return 0.001. Calling this "
+"method with an invalid float string will return 0. This method stops parsing "
+"at the first invalid character and will return the parsed result so far, so "
+"calling [code]float(\"1a3\")[/code] will return 1 while calling "
+"[code]float(\"1e3a2\")[/code] will return 1000.0."
+msgstr ""
+
+#: doc/classes/Font.xml:4
+msgid "Internationalized font and text drawing support."
+msgstr ""
+
+#: doc/classes/Font.xml:7
+msgid ""
+"Font contains a Unicode-compatible character set, as well as the ability to "
+"draw it with variable width, ascent, descent and kerning. For creating fonts "
+"from TTF files (or other font formats), see the editor support for fonts."
+msgstr ""
+
+#: doc/classes/Font.xml:28
+msgid ""
+"Draw [code]string[/code] into a canvas item using the font at a given "
+"position, with [code]modulate[/code] color, and optionally clipping the "
+"width. [code]position[/code] specifies the baseline, not the top. To draw "
+"from the top, [i]ascent[/i] must be added to the Y axis."
+msgstr ""
+
+#: doc/classes/Font.xml:47
+msgid ""
+"Draw character [code]char[/code] into a canvas item using the font at a "
+"given position, with [code]modulate[/code] color, and optionally kerning if "
+"[code]next[/code] is passed. clipping the width. [code]position[/code] "
+"specifies the baseline, not the top. To draw from the top, [i]ascent[/i] "
+"must be added to the Y axis. The width used by the character is returned, "
+"making this function useful for drawing strings character by character."
+msgstr ""
+
+#: doc/classes/Font.xml:54
+msgid "Returns the font ascent (number of pixels above the baseline)."
+msgstr ""
+
+#: doc/classes/Font.xml:61
+msgid "Returns the font descent (number of pixels below the baseline)."
+msgstr ""
+
+#: doc/classes/Font.xml:68
+msgid "Returns the total font height (ascent plus descent) in pixels."
+msgstr ""
+
+#: doc/classes/Font.xml:77
+msgid "Returns the size of a string, taking kerning and advance into account."
+msgstr ""
+
+#: doc/classes/Font.xml:88
+msgid ""
+"Returns the size that the string would have with word wrapping enabled with "
+"a fixed [code]width[/code]."
+msgstr ""
+
+#: doc/classes/Font.xml:95
+msgid "Returns [code]true[/code] if the font has an outline."
+msgstr ""
+
+#: doc/classes/Font.xml:108
+msgid ""
+"After editing a font (changing size, ascent, char rects, etc.). Call this "
+"function to propagate changes to controls that might use it."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:4
+msgid "Reference to a function in an object."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:7
+msgid ""
+"In GDScript, functions are not [i]first-class objects[/i]. This means it is "
+"impossible to store them directly as variables, return them from another "
+"function, or pass them as arguments.\n"
+"However, by creating a [FuncRef] using the [method @GDScript.funcref] "
+"function, a reference to a function in a given object can be created, passed "
+"around and called."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:17
+msgid ""
+"Calls the referenced function previously set by [method set_function] or "
+"[method @GDScript.funcref]."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:26
+msgid ""
+"Calls the referenced function previously set by [method set_function] or "
+"[method @GDScript.funcref]. Contrarily to [method call_func], this method "
+"does not support a variable number of arguments but expects all parameters "
+"to be passed via a single [Array]."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:33
+msgid "Returns whether the object still exists and has the function assigned."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:42
+msgid ""
+"The name of the referenced function to call on the object, without "
+"parentheses or any parameters."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:51
+msgid ""
+"The object containing the referenced function. This object must be of a type "
+"actually inheriting from [Object], not a built-in type such as [int], "
+"[Vector2] or [Dictionary]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:4
+msgid ""
+"An external library containing functions or script classes to use in Godot."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:7
+msgid ""
+"A GDNative library can implement [NativeScript]s, global functions to call "
+"with the [GDNative] class, or low-level engine extensions through interfaces "
+"such as [ARVRInterfaceGDNative]. The library must be compiled for each "
+"platform and architecture that the project will run on."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-"
+"example.html"
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-"
+"cpp-example.html"
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:18
+msgid ""
+"Returns paths to all dependency libraries for the current platform and "
+"architecture."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:25
+msgid ""
+"Returns the path to the dynamic library file for the current platform and "
+"architecture."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:31
+msgid ""
+"This resource in INI-style [ConfigFile] format, as in [code].gdnlib[/code] "
+"files."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:34
+msgid ""
+"If [code]true[/code], Godot loads only one copy of the library and each "
+"script that references the library will share static data like static or "
+"global variables.\n"
+"If [code]false[/code], Godot loads a separate copy of the library into "
+"memory for each script that references it."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:38
+msgid ""
+"If [code]true[/code], the editor will temporarily unload the library "
+"whenever the user switches away from the editor window, allowing the user to "
+"recompile the library without restarting Godot.\n"
+"[b]Note:[/b] If the library defines tool scripts that run inside the editor, "
+"[code]reloadable[/code] must be [code]false[/code]. Otherwise, the editor "
+"will attempt to unload the tool scripts while they're in use and crash."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:42
+msgid ""
+"If [code]true[/code], Godot loads the library at startup rather than the "
+"first time a script uses the library, calling [code]{prefix}"
+"gdnative_singleton[/code] after initializing the library (where [code]"
+"{prefix}[/code] is the value of [member symbol_prefix]). The library remains "
+"loaded as long as Godot is running.\n"
+"[b]Note:[/b] A singleton library cannot be [member reloadable]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:46
+msgid ""
+"The prefix this library's entry point functions begin with. For example, a "
+"GDNativeLibrary would declare its [code]gdnative_init[/code] function as "
+"[code]godot_gdnative_init[/code] by default.\n"
+"On platforms that require statically linking libraries (currently only iOS), "
+"each library must have a different [code]symbol_prefix[/code]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:4
+msgid "A script implemented in the GDScript programming language."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:7
+msgid ""
+"A script implemented in the GDScript programming language. The script "
+"extends the functionality of all objects that instance it.\n"
+"[method new] creates a new instance of the script. [method Object."
+"set_script] extends an existing object, if that object's class matches one "
+"of the script's base classes."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/"
+"index.html"
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:18
+msgid "Returns byte code for the script source code."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:25
+msgid ""
+"Returns a new instance of the script.\n"
+"For example:\n"
+"[codeblock]\n"
+"var MyClass = load(\"myclass.gd\")\n"
+"var instance = MyClass.new()\n"
+"assert(instance.get_script() == MyClass)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:4
+msgid "State of a function call after yielding."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:7
+msgid ""
+"Calling [method @GDScript.yield] within a function will cause that function "
+"to yield and return its current state as an object of this type. The yielded "
+"function call can then be resumed later by calling [method resume] on this "
+"state object."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:18
+msgid ""
+"Check whether the function call may be resumed. This is not the case if the "
+"function state was already resumed.\n"
+"If [code]extended_check[/code] is enabled, it also checks if the associated "
+"script and object still exist. The extended check is done in debug mode as "
+"part of [method GDScriptFunctionState.resume], but you can use this if you "
+"know you may be trying to resume without knowing for sure the object and/or "
+"script have survived up to that point."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:28
+msgid ""
+"Resume execution of the yielded function call.\n"
+"If handed an argument, return the argument from the [method @GDScript.yield] "
+"call in the yielded function call. You can pass e.g. an [Array] to hand "
+"multiple arguments.\n"
+"This function returns what the resumed function call returns, possibly "
+"another function state if yielded again."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:4
+msgid ""
+"The generic 6-degrees-of-freedom joint can implement a variety of joint "
+"types by locking certain axes' rotation or translation."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:7
+msgid ""
+"The first 3 DOF axes are linear axes, which represent translation of Bodies, "
+"and the latter 3 DOF axes represent the angular motion. Each axis can be "
+"either locked, or limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:123
+msgid ""
+"The amount of rotational damping across the X axis.\n"
+"The lower, the longer an impulse from one side takes to travel to the other "
+"side."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:127
+msgid "If [code]true[/code], rotation across the X axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:130
+msgid ""
+"When rotating across the X axis, this error tolerance factor defines how "
+"much the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:133
+msgid ""
+"The maximum amount of force that can occur, when rotating around the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:136
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:139
+msgid ""
+"The amount of rotational restitution across the X axis. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:142
+msgid "The speed of all rotations across the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:145
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:148
+msgid ""
+"The amount of rotational damping across the Y axis. The lower, the more "
+"dampening occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:151
+msgid "If [code]true[/code], rotation across the Y axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:154
+msgid ""
+"When rotating across the Y axis, this error tolerance factor defines how "
+"much the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:157
+msgid ""
+"The maximum amount of force that can occur, when rotating around the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:160
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:163
+msgid ""
+"The amount of rotational restitution across the Y axis. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:166
+msgid "The speed of all rotations across the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:169
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:172
+msgid ""
+"The amount of rotational damping across the Z axis. The lower, the more "
+"dampening occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:175
+msgid "If [code]true[/code], rotation across the Z axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:178
+msgid ""
+"When rotating across the Z axis, this error tolerance factor defines how "
+"much the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:181
+msgid ""
+"The maximum amount of force that can occur, when rotating around the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:184
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:187
+msgid ""
+"The amount of rotational restitution across the Z axis. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:190
+msgid "The speed of all rotations across the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:193
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:196
+msgid "If [code]true[/code], a rotating motor at the X axis is enabled."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:199
+msgid "Maximum acceleration for the motor at the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:202
+msgid "Target speed for the motor at the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:205
+msgid "If [code]true[/code], a rotating motor at the Y axis is enabled."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:208
+msgid "Maximum acceleration for the motor at the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:211
+msgid "Target speed for the motor at the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:214
+msgid "If [code]true[/code], a rotating motor at the Z axis is enabled."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:217
+msgid "Maximum acceleration for the motor at the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:220
+msgid "Target speed for the motor at the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:247
+msgid "The amount of damping that happens at the X motion."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:250
+msgid "If [code]true[/code], the linear motion across the X axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:253
+msgid "The minimum difference between the pivot points' X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:256
+msgid ""
+"The amount of restitution on the X axis movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:259
+msgid ""
+"A factor applied to the movement across the X axis. The lower, the slower "
+"the movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:262
+msgid "The maximum difference between the pivot points' X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:265
+msgid "The amount of damping that happens at the Y motion."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:268
+msgid "If [code]true[/code], the linear motion across the Y axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:271
+msgid "The minimum difference between the pivot points' Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:274
+msgid ""
+"The amount of restitution on the Y axis movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:277
+msgid ""
+"A factor applied to the movement across the Y axis. The lower, the slower "
+"the movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:280
+msgid "The maximum difference between the pivot points' Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:283
+msgid "The amount of damping that happens at the Z motion."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:286
+msgid "If [code]true[/code], the linear motion across the Z axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:289
+msgid "The minimum difference between the pivot points' Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:292
+msgid ""
+"The amount of restitution on the Z axis movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:295
+msgid ""
+"A factor applied to the movement across the Z axis. The lower, the slower "
+"the movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:298
+msgid "The maximum difference between the pivot points' Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:301
+msgid ""
+"If [code]true[/code], then there is a linear motor on the X axis. It will "
+"attempt to reach the target velocity while staying within the force limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:304
+msgid ""
+"The maximum force the linear motor can apply on the X axis while trying to "
+"reach the target velocity."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:307
+msgid "The speed that the linear motor will attempt to reach on the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:310
+msgid ""
+"If [code]true[/code], then there is a linear motor on the Y axis. It will "
+"attempt to reach the target velocity while staying within the force limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:313
+msgid ""
+"The maximum force the linear motor can apply on the Y axis while trying to "
+"reach the target velocity."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:316
+msgid "The speed that the linear motor will attempt to reach on the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:319
+msgid ""
+"If [code]true[/code], then there is a linear motor on the Z axis. It will "
+"attempt to reach the target velocity while staying within the force limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:322
+msgid ""
+"The maximum force the linear motor can apply on the Z axis while trying to "
+"reach the target velocity."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:325
+msgid "The speed that the linear motor will attempt to reach on the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:356 doc/classes/PhysicsServer3D.xml:1410
+msgid "The minimum difference between the pivot points' axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:359 doc/classes/PhysicsServer3D.xml:1413
+msgid "The maximum difference between the pivot points' axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:362
+msgid ""
+"A factor applied to the movement across the axes. The lower, the slower the "
+"movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:365
+msgid ""
+"The amount of restitution on the axes' movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:368 doc/classes/PhysicsServer3D.xml:1422
+msgid ""
+"The amount of damping that happens at the linear motion across the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:371
+msgid "The velocity the linear motor will try to reach."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:374
+msgid ""
+"The maximum force the linear motor will apply while trying to reach the "
+"velocity target."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:377 doc/classes/PhysicsServer3D.xml:1431
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:380 doc/classes/PhysicsServer3D.xml:1434
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:383
+msgid "The speed of all rotations across the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:386 doc/classes/PhysicsServer3D.xml:1440
+msgid ""
+"The amount of rotational damping across the axes. The lower, the more "
+"dampening occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:389 doc/classes/PhysicsServer3D.xml:1443
+msgid ""
+"The amount of rotational restitution across the axes. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:392 doc/classes/PhysicsServer3D.xml:1446
+msgid ""
+"The maximum amount of force that can occur, when rotating around the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:395
+msgid ""
+"When rotating across the axes, this error tolerance factor defines how much "
+"the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:398 doc/classes/PhysicsServer3D.xml:1452
+msgid "Target speed for the motor at the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:401 doc/classes/PhysicsServer3D.xml:1455
+msgid "Maximum acceleration for the motor at the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:407
+msgid "If enabled, linear motion is possible within the given limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:410
+msgid "If enabled, rotational motion is possible within the given limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:417
+msgid "If enabled, there is a rotational motor across these axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:420
+msgid "If enabled, there is a linear motor across these axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:423 doc/classes/HingeJoint3D.xml:118
+msgid "Represents the size of the [enum Flag] enum."
+msgstr ""
+
+#: doc/classes/Geometry.xml:4
+msgid "Helper node to calculate generic geometry operations."
+msgstr ""
+
+#: doc/classes/Geometry.xml:7
+msgid ""
+"Geometry provides users with a set of helper functions to create geometric "
+"shapes, compute intersections between shapes, and process various other "
+"geometric operations."
+msgstr ""
+
+#: doc/classes/Geometry.xml:18
+msgid ""
+"Returns an array with 6 [Plane]s that describe the sides of a box centered "
+"at the origin. The box size is defined by [code]extents[/code], which "
+"represents one (positive) corner of the box (i.e. half its actual size)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:35
+msgid ""
+"Returns an array of [Plane]s closely bounding a faceted capsule centered at "
+"the origin with radius [code]radius[/code] and height [code]height[/code]. "
+"The parameter [code]sides[/code] defines how many planes will be generated "
+"for the side part of the capsule, whereas [code]lats[/code] gives the number "
+"of latitudinal steps at the bottom and top of the capsule. The parameter "
+"[code]axis[/code] describes the axis along which the capsule is oriented (0 "
+"for X, 1 for Y, 2 for Z)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:50
+msgid ""
+"Returns an array of [Plane]s closely bounding a faceted cylinder centered at "
+"the origin with radius [code]radius[/code] and height [code]height[/code]. "
+"The parameter [code]sides[/code] defines how many planes will be generated "
+"for the round part of the cylinder. The parameter [code]axis[/code] "
+"describes the axis along which the cylinder is oriented (0 for X, 1 for Y, 2 "
+"for Z)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:61
+msgid ""
+"Clips the polygon defined by the points in [code]points[/code] against the "
+"[code]plane[/code] and returns the points of the clipped polygon."
+msgstr ""
+
+#: doc/classes/Geometry.xml:72
+msgid ""
+"Clips [code]polygon_a[/code] against [code]polygon_b[/code] and returns an "
+"array of clipped polygons. This performs [constant OPERATION_DIFFERENCE] "
+"between polygons. Returns an empty array if [code]polygon_b[/code] "
+"completely overlaps [code]polygon_a[/code].\n"
+"If [code]polygon_b[/code] is enclosed by [code]polygon_a[/code], returns an "
+"outer polygon (boundary) and inner polygon (hole) which could be "
+"distinguished by calling [method is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:84
+msgid ""
+"Clips [code]polyline[/code] against [code]polygon[/code] and returns an "
+"array of clipped polylines. This performs [constant OPERATION_DIFFERENCE] "
+"between the polyline and the polygon. This operation can be thought of as "
+"cutting a line with a closed shape."
+msgstr ""
+
+#: doc/classes/Geometry.xml:93
+msgid ""
+"Given an array of [Vector2]s, returns the convex hull as a list of points in "
+"counterclockwise order. The last point is the same as the first one."
+msgstr ""
+
+#: doc/classes/Geometry.xml:104
+msgid ""
+"Mutually excludes common area defined by intersection of [code]polygon_a[/"
+"code] and [code]polygon_b[/code] (see [method intersect_polygons_2d]) and "
+"returns an array of excluded polygons. This performs [constant "
+"OPERATION_XOR] between polygons. In other words, returns all but common area "
+"between polygons.\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:118
+msgid ""
+"Returns the 3D point on the 3D segment ([code]s1[/code], [code]s2[/code]) "
+"that is closest to [code]point[/code]. The returned point will always be "
+"inside the specified segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:131
+msgid ""
+"Returns the 2D point on the 2D segment ([code]s1[/code], [code]s2[/code]) "
+"that is closest to [code]point[/code]. The returned point will always be "
+"inside the specified segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:144
+msgid ""
+"Returns the 3D point on the 3D line defined by ([code]s1[/code], [code]s2[/"
+"code]) that is closest to [code]point[/code]. The returned point can be "
+"inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. "
+"somewhere on the line extending from the segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:157
+msgid ""
+"Returns the 2D point on the 2D line defined by ([code]s1[/code], [code]s2[/"
+"code]) that is closest to [code]point[/code]. The returned point can be "
+"inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. "
+"somewhere on the line extending from the segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:172
+msgid ""
+"Given the two 3D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/"
+"code], [code]q2[/code]), finds those two points on the two segments that are "
+"closest to each other. Returns a [PackedVector3Array] that contains this "
+"point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point "
+"on ([code]q1[/code], [code]q2[/code])."
+msgstr ""
+
+#: doc/classes/Geometry.xml:187
+msgid ""
+"Given the two 2D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/"
+"code], [code]q2[/code]), finds those two points on the two segments that are "
+"closest to each other. Returns a [PackedVector2Array] that contains this "
+"point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point "
+"on ([code]q1[/code], [code]q2[/code])."
+msgstr ""
+
+#: doc/classes/Geometry.xml:196
+msgid "Used internally by the engine."
+msgstr ""
+
+#: doc/classes/Geometry.xml:207
+msgid ""
+"Intersects [code]polygon_a[/code] with [code]polygon_b[/code] and returns an "
+"array of intersected polygons. This performs [constant "
+"OPERATION_INTERSECTION] between polygons. In other words, returns common "
+"area shared by polygons. Returns an empty array if no intersection occurs.\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:219
+msgid ""
+"Intersects [code]polyline[/code] with [code]polygon[/code] and returns an "
+"array of intersected polylines. This performs [constant "
+"OPERATION_INTERSECTION] between the polyline and the polygon. This operation "
+"can be thought of as chopping a line with a closed shape."
+msgstr ""
+
+#: doc/classes/Geometry.xml:232
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is inside the circle or if "
+"it's located exactly [i]on[/i] the circle's boundary, otherwise returns "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:243
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is inside [code]polygon[/"
+"code] or if it's located exactly [i]on[/i] polygon's boundary, otherwise "
+"returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:252
+msgid ""
+"Returns [code]true[/code] if [code]polygon[/code]'s vertices are ordered in "
+"clockwise order, otherwise returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:267
+msgid ""
+"Checks if the two lines ([code]from_a[/code], [code]dir_a[/code]) and "
+"([code]from_b[/code], [code]dir_b[/code]) intersect. If yes, return the "
+"point of intersection as [Vector2]. If no intersection takes place, returns "
+"an empty [Variant].\n"
+"[b]Note:[/b] The lines are specified using direction vectors, not end points."
+msgstr ""
+
+#: doc/classes/Geometry.xml:277
+msgid ""
+"Given an array of [Vector2]s representing tiles, builds an atlas. The "
+"returned dictionary has two keys: [code]points[/code] is a vector of "
+"[Vector2] that specifies the positions of each tile, [code]size[/code] "
+"contains the overall size of the whole atlas as [Vector2]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:288
+msgid ""
+"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.\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:302
+msgid ""
+"Inflates or deflates [code]polygon[/code] by [code]delta[/code] units "
+"(pixels). If [code]delta[/code] is positive, makes the polygon grow outward. "
+"If [code]delta[/code] is negative, shrinks the polygon inward. Returns an "
+"array of polygons because inflating/deflating may result in multiple "
+"discrete polygons. Returns an empty array if [code]delta[/code] is negative "
+"and the absolute value of it approximately exceeds the minimum bounding "
+"rectangle dimensions of the polygon.\n"
+"Each polygon's vertices will be rounded as determined by [code]join_type[/"
+"code], see [enum PolyJoinType].\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:319
+msgid ""
+"Inflates or deflates [code]polyline[/code] by [code]delta[/code] units "
+"(pixels), producing polygons. If [code]delta[/code] is positive, makes the "
+"polyline grow outward. Returns an array of polygons because inflating/"
+"deflating may result in multiple discrete polygons. If [code]delta[/code] is "
+"negative, returns an empty array.\n"
+"Each polygon's vertices will be rounded as determined by [code]join_type[/"
+"code], see [enum PolyJoinType].\n"
+"Each polygon's endpoints will be rounded as determined by [code]end_type[/"
+"code], see [enum PolyEndType].\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:337
+msgid ""
+"Returns if [code]point[/code] is inside the triangle specified by [code]a[/"
+"code], [code]b[/code] and [code]c[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:354
+msgid ""
+"Tests if the 3D ray starting at [code]from[/code] with the direction of "
+"[code]dir[/code] intersects the triangle specified by [code]a[/code], "
+"[code]b[/code] and [code]c[/code]. If yes, returns the point of intersection "
+"as [Vector3]. If no intersection takes place, an empty [Variant] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:369
+msgid ""
+"Given the 2D segment ([code]segment_from[/code], [code]segment_to[/code]), "
+"returns the position on the segment (as a number between 0 and 1) at which "
+"the segment hits the circle that is located at position "
+"[code]circle_position[/code] and has radius [code]circle_radius[/code]. If "
+"the segment does not intersect the circle, -1 is returned (this is also the "
+"case if the line extending the segment would intersect the circle, but the "
+"segment does not)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:382
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Geometry.xml:397
+msgid ""
+"Checks if the segment ([code]from[/code], [code]to[/code]) intersects the "
+"cylinder with height [code]height[/code] that is centered at the origin and "
+"has radius [code]radius[/code]. If no, returns an empty "
+"[PackedVector3Array]. If an intersection takes place, the returned array "
+"contains the point of intersection and the cylinder's normal at the point of "
+"intersection."
+msgstr ""
+
+#: doc/classes/Geometry.xml:412
+msgid ""
+"Checks if the two segments ([code]from_a[/code], [code]to_a[/code]) and "
+"([code]from_b[/code], [code]to_b[/code]) intersect. If yes, return the point "
+"of intersection as [Vector2]. If no intersection takes place, returns an "
+"empty [Variant]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:427
+msgid ""
+"Checks if the segment ([code]from[/code], [code]to[/code]) intersects the "
+"sphere that is located at [code]sphere_position[/code] and has radius "
+"[code]sphere_radius[/code]. If no, returns an empty [PackedVector3Array]. If "
+"yes, returns a [PackedVector3Array] containing the point of intersection and "
+"the sphere's normal at the point of intersection."
+msgstr ""
+
+#: doc/classes/Geometry.xml:444
+msgid ""
+"Tests if the segment ([code]from[/code], [code]to[/code]) intersects the "
+"triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the "
+"point of intersection as [Vector3]. If no intersection takes place, an empty "
+"[Variant] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:453
+msgid ""
+"Triangulates the area specified by discrete set of [code]points[/code] such "
+"that no point is inside the circumcircle of any resulting triangle. Returns "
+"a [PackedInt32Array] where each triangle consists of three consecutive point "
+"indices into [code]points[/code] (i.e. the returned array will have [code]n "
+"* 3[/code] elements, with [code]n[/code] being the number of found "
+"triangles). If the triangulation did not succeed, an empty "
+"[PackedInt32Array] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:462
+msgid ""
+"Triangulates the polygon specified by the points in [code]polygon[/code]. "
+"Returns a [PackedInt32Array] where each triangle consists of three "
+"consecutive point indices into [code]polygon[/code] (i.e. the returned array "
+"will have [code]n * 3[/code] elements, with [code]n[/code] being the number "
+"of found triangles). If the triangulation did not succeed, an empty "
+"[PackedInt32Array] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:468
+msgid ""
+"Create regions where either subject or clip polygons (or both) are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:471
+msgid ""
+"Create regions where subject polygons are filled except where clip polygons "
+"are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:474
+msgid "Create regions where both subject and clip polygons are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:477
+msgid ""
+"Create regions where either subject or clip polygons are filled but not "
+"where both are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:480
+msgid ""
+"Squaring is applied uniformally at all convex edge joins at [code]1 * delta[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:483
+msgid ""
+"While flattened paths can never perfectly trace an arc, they are "
+"approximated by a series of arc chords."
+msgstr ""
+
+#: doc/classes/Geometry.xml:486
+msgid ""
+"There's a necessary limit to mitered joins since offsetting edges that join "
+"at very acute angles will produce excessively long and narrow \"spikes\". "
+"For any given edge join, when miter offsetting would exceed that maximum "
+"distance, \"square\" joining is applied."
+msgstr ""
+
+#: doc/classes/Geometry.xml:489
+msgid ""
+"Endpoints are joined using the [enum PolyJoinType] value and the path filled "
+"as a polygon."
+msgstr ""
+
+#: doc/classes/Geometry.xml:492
+msgid ""
+"Endpoints are joined using the [enum PolyJoinType] value and the path filled "
+"as a polyline."
+msgstr ""
+
+#: doc/classes/Geometry.xml:495
+msgid "Endpoints are squared off with no extension."
+msgstr ""
+
+#: doc/classes/Geometry.xml:498
+msgid "Endpoints are squared off and extended by [code]delta[/code] units."
+msgstr ""
+
+#: doc/classes/Geometry.xml:501
+msgid "Endpoints are rounded off and extended by [code]delta[/code] units."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:4
+msgid "Base node for geometry-based visual instances."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:7
+msgid ""
+"Base node for geometry-based visual instances. Shares some common "
+"functionality like visibility and custom materials."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:18
+msgid ""
+"Returns the [enum GeometryInstance3D.Flags] that have been set for this "
+"object."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:27
+msgid ""
+"Overrides the bounding box of this node with a custom one. To remove it, set "
+"an [AABB] with all fields set to zero."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:38
+msgid ""
+"Sets the [enum GeometryInstance3D.Flags] specified. See [enum "
+"GeometryInstance3D.Flags] for options."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:44
+msgid ""
+"The selected shadow casting flag. See [enum ShadowCastingSetting] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:47
+msgid ""
+"The extra distance added to the GeometryInstance3D's bounding box ([AABB]) "
+"to increase its cull box."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:50
+msgid ""
+"The GeometryInstance3D's max LOD distance.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:54
+msgid ""
+"The GeometryInstance3D's max LOD margin.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:58
+msgid ""
+"The GeometryInstance3D's min LOD distance.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:62
+msgid ""
+"The GeometryInstance3D's min LOD margin.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:66
+msgid ""
+"The material override for the whole geometry.\n"
+"If a material is assigned to this property, it will be used instead of any "
+"material set in any material slot of the mesh."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:72
+msgid ""
+"If [code]true[/code], this GeometryInstance3D will be used when baking "
+"lights using a [GIProbe]."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:77
+msgid "Will not cast any shadows."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:80
+msgid ""
+"Will cast shadows from all visible faces in the GeometryInstance3D.\n"
+"Will take culling into account, so faces not being rendered will not be "
+"taken into account when shadow casting."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:84
+msgid ""
+"Will cast shadows from all visible faces in the GeometryInstance3D.\n"
+"Will not take culling into account, so all faces will be taken into account "
+"when shadow casting."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:88
+msgid ""
+"Will only show the shadows casted from this object.\n"
+"In other words, the actual mesh will not be visible, only the shadows casted "
+"from the mesh will be."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:92
+msgid ""
+"Will allow the GeometryInstance3D to be used when baking lights using a "
+"[GIProbe]."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:97
+msgid ""
+"Unused in this class, exposed for consistency with [enum RenderingServer."
+"InstanceFlags]."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:4
+msgid "Real-time global illumination (GI) probe."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:7
+msgid ""
+"[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.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html"
+msgstr ""
+
+#: doc/classes/GIProbe.xml:22
+msgid ""
+"Bakes the effect from all [GeometryInstance3D]s marked with [member "
+"GeometryInstance3D.use_in_baked_light] and [Light3D]s marked with either "
+"[constant Light3D.BAKE_INDIRECT] or [constant Light3D.BAKE_ALL]. If "
+"[code]create_visual_debug[/code] is [code]true[/code], after baking the "
+"light, this will generate a [MultiMesh] that has a cube representing each "
+"solid cell with each cube colored to the cell's albedo color. This can be "
+"used to visualize the [GIProbe]'s data and debug any issues that may be "
+"occurring."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:29
+msgid "Calls [method bake] with [code]create_visual_debug[/code] enabled."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:35
+msgid "The [GIProbeData] resource that holds the data for this [GIProbe]."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:38
+msgid ""
+"The size of the area covered by the [GIProbe]. If you make the extents "
+"larger without increasing the subdivisions with [member subdiv], the size of "
+"each cell will increase and result in lower detailed lighting."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:41
+msgid ""
+"Number of times to subdivide the grid that the [GIProbe] operates on. A "
+"higher number results in finer detail and thus higher visual quality, while "
+"lower numbers result in better performance."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:46
+msgid ""
+"Use 64 subdivisions. This is the lowest quality setting, but the fastest. "
+"Use it if you can, but especially use it on lower-end hardware."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:49
+msgid "Use 128 subdivisions. This is the default quality setting."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:52
+msgid "Use 256 subdivisions."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:55
+msgid ""
+"Use 512 subdivisions. This is the highest quality setting, but the slowest. "
+"On lower-end hardware this could cause the GPU to stall."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:58
+msgid "Represents the size of the [enum Subdiv] enum."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:14
+msgid "Attaches the current thread to the mono runtime."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:21
+msgid "Detaches the current thread from the mono runtime."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:42
+msgid "Returns whether the domain is being finalized."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:61
+msgid "Returns whether the scripts domain is loaded."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:4
+msgid "2D particle emitter."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:7
+msgid ""
+"2D particle node used to create a variety of particle systems and effects. "
+"[GPUParticles2D] features an emitter that generates some number of particles "
+"at a given rate.\n"
+"Use the [code]process_material[/code] property to add a [ParticlesMaterial] "
+"to configure particle appearance and behavior. Alternatively, you can add a "
+"[ShaderMaterial] which will be applied to all particles."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:18
+msgid "Returns a rectangle containing the positions of all existing particles."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:25
+msgid "Restarts all the existing particles."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:64 doc/classes/GPUParticles3D.xml:96
+msgid ""
+"[Material] for processing particles. Can be a [ParticlesMaterial] or a "
+"[ShaderMaterial]."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:76
+msgid "Editor visibility helper."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:4
+msgid "3D particle emitter."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:7
+msgid ""
+"3D particle node used to create a variety of particle systems and effects. "
+"[GPUParticles3D] features an emitter that generates some number of particles "
+"at a given rate.\n"
+"Use the [code]process_material[/code] property to add a [ParticlesMaterial] "
+"to configure particle appearance and behavior. Alternatively, you can add a "
+"[ShaderMaterial] which will be applied to all particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/"
+"controlling_thousands_of_fish.html"
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:18
+msgid ""
+"Returns the axis-aligned bounding box that contains all the particles that "
+"are active in the current frame."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:27
+msgid "Returns the [Mesh] that is drawn at index [code]pass[/code]."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:34
+msgid "Restarts the particle emission, clearing existing particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:45
+msgid "Sets the [Mesh] that is drawn at index [code]pass[/code]."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:51
+msgid "Number of particles to emit."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:57
+msgid "[Mesh] that is drawn for the first draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:60
+msgid "[Mesh] that is drawn for the second draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:63
+msgid "[Mesh] that is drawn for the third draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:66
+msgid "[Mesh] that is drawn for the fourth draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:69
+msgid "The number of draw passes when rendering particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:75
+msgid ""
+"Time ratio between each emission. If [code]0[/code], particles are emitted "
+"continuously. If [code]1[/code], all particles are emitted simultaneously."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:90
+msgid ""
+"If [code]true[/code], only [code]amount[/code] particles will be emitted."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:93
+msgid ""
+"Amount of time to preprocess the particles before animation starts. Lets you "
+"start the animation some time after particles have started emitting."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:99
+msgid "Emission randomness ratio."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:102
+msgid ""
+"Speed scaling ratio. A value of [code]0[/code] can be used to pause the "
+"particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:105
+msgid ""
+"The [AABB] that determines the area of the world part of which needs to be "
+"visible on screen for the particle system to be active."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:119
+msgid "Maximum number of draw passes supported."
+msgstr ""
+
+#: doc/classes/Gradient.xml:4
+msgid ""
+"A color interpolator resource which can be used to generate colors between "
+"user-defined color points."
+msgstr ""
+
+#: doc/classes/Gradient.xml:7
+msgid ""
+"Given a set of colors, this resource will interpolate them in order. This "
+"means that if you have color 1, color 2 and color 3, the ramp will "
+"interpolate from color 1 to color 2 and from color 2 to color 3. The ramp "
+"will initially have 2 colors (black and white), one (black) at ramp lower "
+"offset 0 and the other (white) at the ramp higher offset 1."
+msgstr ""
+
+#: doc/classes/Gradient.xml:20
+msgid ""
+"Adds the specified color to the end of the ramp, with the specified offset."
+msgstr ""
+
+#: doc/classes/Gradient.xml:29
+msgid "Returns the color of the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:38
+msgid "Returns the offset of the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:45
+msgid "Returns the number of colors in the ramp."
+msgstr ""
+
+#: doc/classes/Gradient.xml:54
+msgid "Returns the interpolated color specified by [code]offset[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:63
+msgid "Removes the color at the index [code]offset[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:74
+msgid "Sets the color of the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:85
+msgid "Sets the offset for the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:91
+msgid "Gradient's colors returned as a [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:94
+msgid "Gradient's offsets returned as a [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:4
+msgid "Gradient-filled texture."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:7
+msgid ""
+"GradientTexture uses a [Gradient] to fill the texture data. The gradient "
+"will be filled from left to right using colors obtained from the gradient. "
+"This means the texture does not necessarily represent an exact copy of the "
+"gradient, but instead an interpolation of samples obtained from the gradient "
+"at fixed steps (see [member width])."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:15
+msgid "The [Gradient] that will be used to fill the texture."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:18
+msgid "The number of color samples that will be obtained from the [Gradient]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:4
+msgid ""
+"GraphEdit is an area capable of showing various GraphNodes. It manages "
+"connection events between them."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:7
+msgid ""
+"GraphEdit manages the showing of GraphNodes it contains, as well as "
+"connections and disconnections between them. Signals are sent for each of "
+"these two events. Disconnection between GraphNode slots is disabled by "
+"default.\n"
+"It is greatly advised to enable low-processor usage mode (see [member OS."
+"low_processor_usage_mode]) when using GraphEdits."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:21
+msgid ""
+"Makes possible the connection between two different slot types. The type is "
+"defined with the [method GraphNode.set_slot] method."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:30
+msgid ""
+"Makes possible to disconnect nodes when dragging from the slot at the left "
+"if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:39
+msgid ""
+"Makes possible to disconnect nodes when dragging from the slot at the right "
+"if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:46
+msgid "Removes all connections between nodes."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:61
+msgid ""
+"Create a connection between the [code]from_port[/code] slot of the "
+"[code]from[/code] GraphNode and the [code]to_port[/code] slot of the "
+"[code]to[/code] GraphNode. If the connection already exists, no connection "
+"is created."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:76
+msgid ""
+"Removes the connection between the [code]from_port[/code] slot of the "
+"[code]from[/code] GraphNode and the [code]to_port[/code] slot of the "
+"[code]to[/code] GraphNode. If the connection does not exist, no connection "
+"is removed."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:83
+msgid ""
+"Returns an Array containing the list of connections. A connection consists "
+"in a structure of the form [code]{ from_port: 0, from: \"GraphNode name 0\", "
+"to_port: 1, to: \"GraphNode name 1\" }[/code]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:90
+msgid ""
+"Gets the [HBoxContainer] that contains the zooming and grid snap controls in "
+"the top left of the graph.\n"
+"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."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:106
+msgid ""
+"Returns [code]true[/code] if the [code]from_port[/code] slot of the "
+"[code]from[/code] GraphNode is connected to the [code]to_port[/code] slot of "
+"the [code]to[/code] GraphNode."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:117
+msgid "Returns whether it's possible to connect slots of the specified types."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:128
+msgid ""
+"Makes it not possible to connect between two different slot types. The type "
+"is defined with the [method GraphNode.set_slot] method."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:137
+msgid ""
+"Removes the possibility to disconnect nodes when dragging from the slot at "
+"the left if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:146
+msgid ""
+"Removes the possibility to disconnect nodes when dragging from the slot at "
+"the right if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:163
+msgid ""
+"Sets the coloration of the connection between [code]from[/code]'s "
+"[code]from_port[/code] and [code]to[/code]'s [code]to_port[/code] with the "
+"color provided in the [code]activity[/code] theme property."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:172
+msgid "Sets the specified [code]node[/code] as the one selected."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:180
+msgid ""
+"If [code]true[/code], enables disconnection of existing connections in the "
+"GraphEdit by dragging the right end."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:183
+msgid "The scroll offset."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:186
+msgid "The snapping distance in pixels."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:189
+msgid "If [code]true[/code], enables snapping."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:192
+msgid "The current zoom value."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:198
+msgid "Emitted at the beginning of a GraphNode movement."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:203
+msgid "Emitted at the end of a GraphNode movement."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:214
+msgid ""
+"Emitted when user dragging connection from input port into empty space of "
+"the graph."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:227
+msgid ""
+"Emitted to the GraphEdit when the connection between the [code]from_slot[/"
+"code] slot of the [code]from[/code] GraphNode and the [code]to_slot[/code] "
+"slot of the [code]to[/code] GraphNode is attempted to be created."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:238
+msgid ""
+"Emitted when user dragging connection from output port into empty space of "
+"the graph."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:243
+msgid "Emitted when the user presses [code]Ctrl + C[/code]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:248
+msgid "Emitted when a GraphNode is attempted to be removed from the GraphEdit."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:261
+msgid ""
+"Emitted to the GraphEdit when the connection between [code]from_slot[/code] "
+"slot of [code]from[/code] GraphNode and [code]to_slot[/code] slot of "
+"[code]to[/code] GraphNode is attempted to be removed."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:266
+msgid ""
+"Emitted when a GraphNode is attempted to be duplicated in the GraphEdit."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:273
+msgid "Emitted when a GraphNode is selected."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:278
+msgid "Emitted when the user presses [code]Ctrl + V[/code]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:285
+msgid ""
+"Emitted when a popup is requested. Happens on right-clicking in the "
+"GraphEdit. [code]position[/code] is the position of the mouse pointer when "
+"the signal is sent."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:292
+msgid ""
+"Emitted when the scroll offset is changed by the user. It will not be "
+"emitted when changed in code."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:306
+msgid "The background drawn under the grid."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:309
+msgid "Color of major grid lines."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:312
+msgid "Color of minor grid lines."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:315
+msgid "The icon for the zoom out button."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:318
+msgid "The icon for the zoom in button."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:321
+msgid ""
+"The horizontal range within which a port can be grabbed (on both sides)."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:324
+msgid "The vertical range within which a port can be grabbed (on both sides)."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:327
+msgid "The icon for the zoom reset button."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:330
+msgid "The fill color of the selection rectangle."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:333
+msgid "The outline color of the selection rectangle."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:336
+msgid "The icon for the snap toggle button."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:4
+msgid ""
+"A GraphNode is a container with potentially several input and output slots "
+"allowing connections between GraphNodes. Slots can have different, "
+"incompatible types."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:18
+msgid "Disables all input and output slots of the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:27
+msgid "Disables input and output slot whose index is [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:36
+msgid "Returns the color of the input connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:43
+msgid ""
+"Returns the number of enabled input slots (connections) to the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:52
+msgid "Returns the position of the input connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:61
+msgid "Returns the type of the input connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:70
+msgid "Returns the color of the output connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:77
+msgid ""
+"Returns the number of enabled output slots (connections) of the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:86
+msgid "Returns the position of the output connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:95
+msgid "Returns the type of the output connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:104
+msgid "Returns the color set to [code]idx[/code] left (input) slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:113
+msgid "Returns the color set to [code]idx[/code] right (output) slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:122
+msgid "Returns the (integer) type of left (input) [code]idx[/code] slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:131
+msgid "Returns the (integer) type of right (output) [code]idx[/code] slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:140
+msgid ""
+"Returns [code]true[/code] if left (input) slot [code]idx[/code] is enabled, "
+"[code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:149
+msgid ""
+"Returns [code]true[/code] if right (output) slot [code]idx[/code] is "
+"enabled, [code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:174
+msgid ""
+"Sets properties of the slot with ID [code]idx[/code].\n"
+"If [code]enable_left[/code]/[code]right[/code], a port will appear and the "
+"slot will be able to be connected from this side.\n"
+"[code]type_left[/code]/[code]right[/code] is an arbitrary type of the port. "
+"Only ports with the same type values can be connected.\n"
+"[code]color_left[/code]/[code]right[/code] is the tint of the port's icon on "
+"this side.\n"
+"[code]custom_left[/code]/[code]right[/code] is a custom texture for this "
+"side's port.\n"
+"[b]Note:[/b] This method only sets properties of the slot. To create the "
+"slot, add a [Control]-derived child to the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:185
+msgid "If [code]true[/code], the GraphNode is a comment node."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:189
+msgid ""
+"The offset of the GraphNode, relative to the scroll offset of the "
+"[GraphEdit].\n"
+"[b]Note:[/b] You cannot use position directly, as [GraphEdit] is a "
+"[Container]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:193
+msgid "Sets the overlay shown above the GraphNode. See [enum Overlay]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:196
+msgid ""
+"If [code]true[/code], the user can resize the GraphNode.\n"
+"[b]Note:[/b] Dragging the handle will only emit the [signal resize_request] "
+"signal, the GraphNode needs to be resized manually."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:200
+msgid "If [code]true[/code], the GraphNode is selected."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:203
+msgid ""
+"If [code]true[/code], the close button will be visible.\n"
+"[b]Note:[/b] Pressing it will only emit the [signal close_request] signal, "
+"the GraphNode needs to be removed manually."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:207
+msgid "The text displayed in the GraphNode's title bar."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:213
+msgid ""
+"Emitted when the GraphNode is requested to be closed. Happens on clicking "
+"the close button (see [member show_close])."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:222
+msgid "Emitted when the GraphNode is dragged."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:227
+msgid "Emitted when the GraphNode is moved."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:232
+msgid ""
+"Emitted when the GraphNode is requested to be displayed over other ones. "
+"Happens on focusing (clicking into) the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:239
+msgid ""
+"Emitted when the GraphNode is requested to be resized. Happens on dragging "
+"the resizer handle (see [member resizable])."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:245
+msgid "No overlay is shown."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:248
+msgid "Show overlay set in the [code]breakpoint[/code] theme property."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:251
+msgid "Show overlay set in the [code]position[/code] theme property."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:256
+msgid ""
+"The background used when [member overlay] is set to [constant "
+"OVERLAY_BREAKPOINT]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:259
+msgid ""
+"The icon for the close button, visible when [member show_close] is enabled."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:262
+msgid "The color modulation applied to the close button icon."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:265
+msgid "The vertical offset of the close button."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:268
+msgid "The [StyleBox] used when [member comment] is enabled."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:271
+msgid ""
+"The [StyleBox] used when [member comment] is enabled and the [GraphNode] is "
+"focused."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:278
+msgid "The default background for [GraphNode]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:281
+msgid "The icon used for representing ports."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:284
+msgid "Horizontal offset for the ports."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:287
+msgid ""
+"The background used when [member overlay] is set to [constant "
+"OVERLAY_POSITION]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:290
+msgid "The icon used for resizer, visible when [member resizable] is enabled."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:293
+msgid "The color modulation applied to the resizer icon."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:296
+msgid "The background used when the [GraphNode] is selected."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:299
+msgid "The vertical distance between ports."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:302
+msgid "Color of the title text."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:305
+msgid "Font used for the title text."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:308
+msgid "Vertical offset of the title text."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:4
+msgid "Grid container used to arrange elements in a grid like layout."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:7
+msgid ""
+"Grid container will arrange its children in a grid like structure, the grid "
+"columns are specified using the [member columns] property and the number of "
+"rows will be equal to the number of children in the container divided by the "
+"number of columns. For example, if the container has 5 children, and 2 "
+"columns, there will be 3 rows in the container.\n"
+"Notice that grid layout will preserve the columns and rows for every size of "
+"the container, and that empty columns will be expanded automatically."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:16
+msgid ""
+"The number of columns in the [GridContainer]. If modified, [GridContainer] "
+"reorders its children to accommodate the new layout."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:23
+msgid "The horizontal separation of children nodes."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:26
+msgid "The vertical separation of children nodes."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:4
+msgid "Node for 3D tile-based maps."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:7
+msgid ""
+"GridMap lets you place meshes on a grid interactively. It works both from "
+"the editor and from scripts, which can help you create in-game level "
+"editors.\n"
+"GridMaps use a [MeshLibrary] which contains a list of tiles. Each tile is a "
+"mesh with materials plus optional collision and navigation shapes.\n"
+"A GridMap contains a collection of cells. Each grid cell refers to a tile in "
+"the [MeshLibrary]. All cells in the map have the same dimensions.\n"
+"Internally, a GridMap is split into a sparse collection of octants for "
+"efficient rendering and physics processing. Every octant has the same "
+"dimensions and can contain several cells."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:13
+msgid "https://docs.godotengine.org/en/latest/tutorials/3d/using_gridmaps.html"
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:20
+msgid "Clear all cells."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:53
+msgid ""
+"The [MeshLibrary] item index located at the grid-based X, Y and Z "
+"coordinates. If the cell is empty, [constant INVALID_CELL_ITEM] will be "
+"returned."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:66
+msgid ""
+"The orientation of the cell at the grid-based X, Y and Z coordinates. -1 is "
+"returned if the cell is empty."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:75 doc/classes/PhysicsBody2D.xml:35
+#: doc/classes/PhysicsBody3D.xml:35
+msgid "Returns an individual bit on the [member collision_layer]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:84 doc/classes/PhysicsBody2D.xml:44
+#: doc/classes/PhysicsBody3D.xml:44
+msgid "Returns an individual bit on the [member collision_mask]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:91
+msgid ""
+"Returns an array of [Transform] and [Mesh] references corresponding to the "
+"non-empty cells in the grid. The transforms are specified in world space."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:98
+msgid ""
+"Returns an array of [Vector3] with the non-empty cell coordinates in the "
+"grid map."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:121
+msgid ""
+"Returns the position of a grid cell in the GridMap's local coordinate space."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:146
+msgid ""
+"Sets the mesh index for the cell referenced by its grid-based X, Y and Z "
+"coordinates.\n"
+"A negative item index such as [constant INVALID_CELL_ITEM] will clear the "
+"cell.\n"
+"Optionally, the item's orientation can be passed. For valid orientation "
+"values, see [method Basis.get_orthogonal_index]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:173
+msgid "Sets an individual bit on the [member collision_layer]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:184
+msgid "Sets an individual bit on the [member collision_mask]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:193
+msgid ""
+"Returns the coordinates of the grid cell containing the given point.\n"
+"[code]pos[/code] should be in the GridMap's local coordinate space."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:200
+msgid "If [code]true[/code], grid items are centered on the X axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:203
+msgid "If [code]true[/code], grid items are centered on the Y axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:206
+msgid "If [code]true[/code], grid items are centered on the Z axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:209
+msgid ""
+"The size of each octant measured in number of cells. This applies to all "
+"three axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:212
+msgid ""
+"The scale of the cell items.\n"
+"This does not affect the size of the grid cells themselves, only the items "
+"in them. This can be used to make cell items overlap their neighbors."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:216
+msgid ""
+"The dimensions of the grid's cells.\n"
+"This does not affect the size of the meshes. See [member cell_scale]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:220
+msgid ""
+"The physics layers this GridMap is in.\n"
+"GridMaps act as static bodies, meaning they aren't affected by gravity or "
+"other forces. They only affect other physics bodies that collide with them."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:224
+msgid "The physics layers this GridMap detects collisions in."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:227
+msgid "The assigned [MeshLibrary]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:235
+msgid "Emitted when [member cell_size] changes."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:241
+msgid ""
+"Invalid cell item that can be used in [method set_cell_item] to clear cells "
+"(or represent an empty cell in [method get_cell_item])."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:4
+msgid "Groove constraint for 2D physics."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:7
+msgid ""
+"Groove constraint for 2D physics. This is useful for making a body \"slide\" "
+"through a segment placed in another."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:15
+msgid ""
+"The body B's initial anchor position defined by the joint's origin and a "
+"local offset [member initial_offset] along the joint's Y axis (along the "
+"groove)."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:18
+msgid ""
+"The groove's length. The groove is from the joint's origin towards [member "
+"length] along the joint's local Y axis."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:4
+msgid "Context to compute cryptographic hashes over multiple iterations."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:7
+msgid ""
+"The HashingContext class provides an interface for computing cryptographic "
+"hashes over multiple iterations. This is useful for example when computing "
+"hashes of big files (so you don't have to load them all in memory), network "
+"streams, and data streams in general (so you don't have to hold buffers).\n"
+"The [enum HashType] enum shows the supported hashing algorithms.\n"
+"[codeblock]\n"
+"const CHUNK_SIZE = 1024\n"
+"\n"
+"func hash_file(path):\n"
+" var ctx = HashingContext.new()\n"
+" var file = File.new()\n"
+" # Start a SHA-256 context.\n"
+" ctx.start(HashingContext.HASH_SHA256)\n"
+" # Check that file exists.\n"
+" if not file.file_exists(path):\n"
+" return\n"
+" # Open the file to hash.\n"
+" file.open(path, File.READ)\n"
+" # Update the context after reading each chunk.\n"
+" while not file.eof_reached():\n"
+" ctx.update(file.get_buffer(CHUNK_SIZE))\n"
+" # Get the computed hash.\n"
+" var res = ctx.finish()\n"
+" # Print the result as hex string and array.\n"
+" printt(res.hex_encode(), Array(res))\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:39
+msgid "Closes the current context, and return the computed hash."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:48
+msgid ""
+"Starts a new hash computation of the given [code]type[/code] (e.g. [constant "
+"HASH_SHA256] to start computation of a SHA-256)."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:57
+msgid "Updates the computation with the given [code]chunk[/code] of data."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:63
+msgid "Hashing algorithm: MD5."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:66
+msgid "Hashing algorithm: SHA-1."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:69
+msgid "Hashing algorithm: SHA-256."
+msgstr ""
+
+#: doc/classes/HBoxContainer.xml:4
+msgid "Horizontal box container."
+msgstr ""
+
+#: doc/classes/HBoxContainer.xml:7
+msgid "Horizontal box container. See [BoxContainer]."
+msgstr ""
+
+#: doc/classes/HBoxContainer.xml:17
+msgid "The horizontal space between the [HBoxContainer]'s elements."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:4
+msgid "Height map shape for 3D physics (Bullet only)."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:7
+msgid ""
+"Height map shape resource, which can be added to a [PhysicsBody3D] or "
+"[Area3D]."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:15
+msgid ""
+"Height map data, pool array must be of [member map_width] * [member "
+"map_depth] size."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:18
+msgid ""
+"Depth of the height map data. Changing this will resize the [member "
+"map_data]."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:21
+msgid ""
+"Width of the height map data. Changing this will resize the [member "
+"map_data]."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:4
+msgid "A hinge between two 3D bodies."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:7
+msgid ""
+"A HingeJoint3D normally uses the Z axis of body A as the hinge axis, another "
+"axis can be specified when adding it manually though."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:18 doc/classes/SpriteBase3D.xml:24
+msgid "Returns the value of the specified flag."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:27 doc/classes/ParticlesMaterial.xml:29
+#: doc/classes/PinJoint3D.xml:18
+msgid "Returns the value of the specified parameter."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:38
+msgid "If [code]true[/code], enables the specified flag."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:49 doc/classes/PinJoint3D.xml:29
+msgid "Sets the value of the specified parameter."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:55 doc/classes/HingeJoint3D.xml:95
+#: doc/classes/PhysicsServer3D.xml:1301
+msgid ""
+"The speed with which the rotation across the axis perpendicular to the hinge "
+"gets corrected."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:58 doc/classes/HingeJoint3D.xml:112
+msgid ""
+"If [code]true[/code], the hinges maximum and minimum rotation, defined by "
+"[member angular_limit/lower] and [member angular_limit/upper] has effects."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:61 doc/classes/HingeJoint3D.xml:92
+msgid ""
+"The minimum rotation. Only active if [member angular_limit/enable] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:64 doc/classes/HingeJoint3D.xml:100
+#: doc/classes/PhysicsServer3D.xml:1306
+msgid "The lower this value, the more the rotation gets slowed down."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:69 doc/classes/HingeJoint3D.xml:89
+msgid ""
+"The maximum rotation. Only active if [member angular_limit/enable] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:72 doc/classes/HingeJoint3D.xml:115
+msgid "When activated, a motor turns the hinge."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:75 doc/classes/HingeJoint3D.xml:106
+#: doc/classes/PhysicsServer3D.xml:1312
+msgid "Maximum acceleration for the motor."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:78 doc/classes/HingeJoint3D.xml:103
+#: doc/classes/PhysicsServer3D.xml:1309
+msgid "Target speed for the motor."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:81 doc/classes/HingeJoint3D.xml:86
+#: doc/classes/PhysicsServer3D.xml:1292
+msgid ""
+"The speed with which the two bodies get pulled together when they move in "
+"different directions."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:4
+msgid "Horizontal scroll bar."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:7
+msgid ""
+"Horizontal version of [ScrollBar], which goes from left (min) to right (max)."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:17
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] left. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:20 doc/classes/VScrollBar.xml:24
+msgid "Displayed when the mouse cursor hovers over the decrement button."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:23 doc/classes/VScrollBar.xml:27
+msgid ""
+"Used as texture for the grabber, the draggable element representing current "
+"scroll."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:26 doc/classes/VScrollBar.xml:30
+msgid "Used when the mouse hovers over the grabber."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:29 doc/classes/VScrollBar.xml:33
+msgid "Used when the grabber is being dragged."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:32
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] right. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:35 doc/classes/VScrollBar.xml:39
+msgid "Displayed when the mouse cursor hovers over the increment button."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:38 doc/classes/VScrollBar.xml:42
+msgid "Used as background of this [ScrollBar]."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:41 doc/classes/VScrollBar.xml:45
+msgid "Used as background when the [ScrollBar] has the GUI focus."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:4
+msgid "Horizontal separator."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:7
+msgid ""
+"Horizontal separator. See [Separator]. Even though it looks horizontal, it "
+"is used to separate objects vertically."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:17
+msgid ""
+"The height of the area covered by the separator. Effectively works like a "
+"minimum height."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:20
+msgid "The style for the separator line. Works best with [StyleBoxLine]."
+msgstr ""
+
+#: doc/classes/HSlider.xml:4
+msgid "Horizontal slider."
+msgstr ""
+
+#: doc/classes/HSlider.xml:7
+msgid ""
+"Horizontal slider. See [Slider]. This one goes from left (min) to right "
+"(max)."
+msgstr ""
+
+#: doc/classes/HSlider.xml:17 doc/classes/VSlider.xml:21
+msgid "The texture for the grabber (the draggable element)."
+msgstr ""
+
+#: doc/classes/HSlider.xml:20
+msgid "The background of the area to the left of the grabber."
+msgstr ""
+
+#: doc/classes/HSlider.xml:23 doc/classes/VSlider.xml:27
+msgid "The texture for the grabber when it's disabled."
+msgstr ""
+
+#: doc/classes/HSlider.xml:26 doc/classes/VSlider.xml:30
+msgid "The texture for the grabber when it's focused."
+msgstr ""
+
+#: doc/classes/HSlider.xml:29
+msgid ""
+"The background for the whole slider. Determines the height of the "
+"[code]grabber_area[/code]."
+msgstr ""
+
+#: doc/classes/HSlider.xml:32 doc/classes/VSlider.xml:36
+msgid ""
+"The texture for the ticks, visible when [member Slider.tick_count] is "
+"greater than 0."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:4
+msgid "Horizontal split container."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:7
+msgid ""
+"Horizontal split container. See [SplitContainer]. This goes from left to "
+"right."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:17 doc/classes/VSplitContainer.xml:17
+msgid ""
+"Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically "
+"when it isn't under the cursor. If 0 ([code]false[/code]), it's always "
+"visible."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:22 doc/classes/VSplitContainer.xml:22
+msgid "The icon used for the grabber drawn in the middle area."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:25 doc/classes/VSplitContainer.xml:25
+msgid "The space between sides of the container."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:4
+msgid "Hyper-text transfer protocol client."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:7
+msgid ""
+"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. See "
+"[HTTPRequest] for an higher-level alternative.\n"
+"[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.\n"
+"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.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/"
+"http_client_class.html"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:14 doc/classes/HTTPRequest.xml:62
+#: doc/classes/StreamPeerSSL.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates."
+"html"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:21
+msgid "Closes the current connection, allowing reuse of this [HTTPClient]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:36
+msgid ""
+"Connects to a host. This needs to be done before any requests are sent.\n"
+"The host should not have http:// prepended but will strip the protocol "
+"identifier if provided.\n"
+"If no [code]port[/code] is specified (or [code]-1[/code] is used), it is "
+"automatically set to 80 for HTTP and 443 for HTTPS (if [code]use_ssl[/code] "
+"is enabled).\n"
+"[code]verify_host[/code] will check the SSL identity of the host if set to "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:46
+msgid ""
+"Returns the response's body length.\n"
+"[b]Note:[/b] Some Web servers may not send a body length. In this case, the "
+"value returned will be [code]-1[/code]. If using chunked transfer encoding, "
+"the body length will also be [code]-1[/code]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:54
+msgid "Returns the response's HTTP status code."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:61
+msgid "Returns the response headers."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:68
+msgid ""
+"Returns all response headers as a Dictionary of structure [code]{ \"key\": "
+"\"value1; value2\" }[/code] where the case-sensitivity of the keys and "
+"values is kept like the server delivers it. A value is a simple String, this "
+"string can have more than one value where \"; \" is used as separator.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"{\n"
+" \"content-length\": 12,\n"
+" \"Content-Type\": \"application/json; charset=UTF-8\",\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:82
+msgid ""
+"Returns a [enum Status] constant. Need to call [method poll] in order to get "
+"status updates."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:89
+msgid "If [code]true[/code], this [HTTPClient] has a response available."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:96
+msgid "If [code]true[/code], this [HTTPClient] has a response that is chunked."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:103
+msgid ""
+"This needs to be called in order to have any request processed. Check "
+"results with [method get_status]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:112
+msgid ""
+"Generates a GET/POST application/x-www-form-urlencoded style query string "
+"from a provided dictionary, e.g.:\n"
+"[codeblock]\n"
+"var fields = {\"username\": \"user\", \"password\": \"pass\"}\n"
+"var query_string = http_client.query_string_from_dict(fields)\n"
+"# Returns \"username=user&password=pass\"\n"
+"[/codeblock]\n"
+"Furthermore, if a key has a [code]null[/code] value, only the key itself is "
+"added, without equal sign and value. If the value is an array, for each "
+"value in it a pair with the same key is added.\n"
+"[codeblock]\n"
+"var fields = {\"single\": 123, \"not_valued\": null, \"multiple\": [22, 33, "
+"44]}\n"
+"var query_string = http_client.query_string_from_dict(fields)\n"
+"# Returns \"single=123&not_valued&multiple=22&multiple=33&multiple=44\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:130
+msgid "Reads one chunk from the response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:145
+msgid ""
+"Sends a request to the connected host. The URL parameter is just the part "
+"after the host, so for [code]http://somehost.com/index.php[/code], it is "
+"[code]index.php[/code].\n"
+"Headers are HTTP request headers. For available HTTP methods, see [enum "
+"Method].\n"
+"To create a POST request with query strings to push to the server, do:\n"
+"[codeblock]\n"
+"var fields = {\"username\" : \"user\", \"password\" : \"pass\"}\n"
+"var query_string = http_client.query_string_from_dict(fields)\n"
+"var headers = [\"Content-Type: application/x-www-form-urlencoded\", "
+"\"Content-Length: \" + str(query_string.length())]\n"
+"var result = http_client.request(http_client.METHOD_POST, \"index.php\", "
+"headers, query_string)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:168
+msgid ""
+"Sends a raw request to the connected host. The URL parameter is just the "
+"part after the host, so for [code]http://somehost.com/index.php[/code], it "
+"is [code]index.php[/code].\n"
+"Headers are HTTP request headers. For available HTTP methods, see [enum "
+"Method].\n"
+"Sends the body data raw, as a byte array and does not encode it in any way."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:176
+msgid ""
+"If [code]true[/code], execution will block until all data is read from the "
+"response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:179
+msgid "The connection to use for this client."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:182
+msgid ""
+"The size of the buffer used and maximum bytes to read per iteration. See "
+"[method read_response_body_chunk]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:187
+msgid ""
+"HTTP GET method. The GET method requests a representation of the specified "
+"resource. Requests using GET should only retrieve data."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:190
+msgid ""
+"HTTP HEAD method. The HEAD method asks for a response identical to that of a "
+"GET request, but without the response body. This is useful to request "
+"metadata like HTTP headers or to check if a resource exists."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:193
+msgid ""
+"HTTP POST method. The POST method is used to submit an entity to the "
+"specified resource, often causing a change in state or side effects on the "
+"server. This is often used for forms and submitting data or uploading files."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:196
+msgid ""
+"HTTP PUT method. The PUT method asks to replace all current representations "
+"of the target resource with the request payload. (You can think of POST as "
+"\"create or update\" and PUT as \"update\", although many services tend to "
+"not make a clear distinction or change their meaning)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:199
+msgid ""
+"HTTP DELETE method. The DELETE method requests to delete the specified "
+"resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:202
+msgid ""
+"HTTP OPTIONS method. The OPTIONS method asks for a description of the "
+"communication options for the target resource. Rarely used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:205
+msgid ""
+"HTTP TRACE method. The TRACE method performs a message loop-back test along "
+"the path to the target resource. Returns the entire HTTP request received in "
+"the response body. Rarely used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:208
+msgid ""
+"HTTP CONNECT method. The CONNECT method establishes a tunnel to the server "
+"identified by the target resource. Rarely used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:211
+msgid ""
+"HTTP PATCH method. The PATCH method is used to apply partial modifications "
+"to a resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:214
+msgid "Represents the size of the [enum Method] enum."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:217
+msgid "Status: Disconnected from the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:220
+msgid "Status: Currently resolving the hostname for the given URL into an IP."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:223
+msgid "Status: DNS failure: Can't resolve the hostname for the given URL."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:226
+msgid "Status: Currently connecting to server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:229
+msgid "Status: Can't connect to the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:232
+msgid "Status: Connection established."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:235
+msgid "Status: Currently sending request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:238
+msgid "Status: HTTP body received."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:241
+msgid "Status: Error in HTTP connection."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:244
+msgid "Status: Error in SSL handshake."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:247
+msgid ""
+"HTTP status code [code]100 Continue[/code]. Interim response that indicates "
+"everything so far is OK and that the client should continue with the request "
+"(or ignore this status if already finished)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:250
+msgid ""
+"HTTP status code [code]101 Switching Protocol[/code]. Sent in response to an "
+"[code]Upgrade[/code] request header by the client. Indicates the protocol "
+"the server is switching to."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:253
+msgid ""
+"HTTP status code [code]102 Processing[/code] (WebDAV). Indicates that the "
+"server has received and is processing the request, but no response is "
+"available yet."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:256
+msgid ""
+"HTTP status code [code]200 OK[/code]. The request has succeeded. Default "
+"response for successful requests. Meaning varies depending on the request. "
+"GET: The resource has been fetched and is transmitted in the message body. "
+"HEAD: The entity headers are in the message body. POST: The resource "
+"describing the result of the action is transmitted in the message body. "
+"TRACE: The message body contains the request message as received by the "
+"server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:259
+msgid ""
+"HTTP status code [code]201 Created[/code]. The request has succeeded and a "
+"new resource has been created as a result of it. This is typically the "
+"response sent after a PUT request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:262
+msgid ""
+"HTTP status code [code]202 Accepted[/code]. The request has been received "
+"but not yet acted upon. It is non-committal, meaning that there is no way in "
+"HTTP to later send an asynchronous response indicating the outcome of "
+"processing the request. It is intended for cases where another process or "
+"server handles the request, or for batch processing."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:265
+msgid ""
+"HTTP status code [code]203 Non-Authoritative Information[/code]. This "
+"response code means returned meta-information set is not exact set as "
+"available from the origin server, but collected from a local or a third "
+"party copy. Except this condition, 200 OK response should be preferred "
+"instead of this response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:268
+msgid ""
+"HTTP status code [code]204 No Content[/code]. There is no content to send "
+"for this request, but the headers may be useful. The user-agent may update "
+"its cached headers for this resource with the new ones."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:271
+msgid ""
+"HTTP status code [code]205 Reset Content[/code]. The server has fulfilled "
+"the request and desires that the client resets the \"document view\" that "
+"caused the request to be sent to its original state as received from the "
+"origin server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:274
+msgid ""
+"HTTP status code [code]206 Partial Content[/code]. This response code is "
+"used because of a range header sent by the client to separate download into "
+"multiple streams."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:277
+msgid ""
+"HTTP status code [code]207 Multi-Status[/code] (WebDAV). A Multi-Status "
+"response conveys information about multiple resources in situations where "
+"multiple status codes might be appropriate."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:280
+msgid ""
+"HTTP status code [code]208 Already Reported[/code] (WebDAV). Used inside a "
+"DAV: propstat response element to avoid enumerating the internal members of "
+"multiple bindings to the same collection repeatedly."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:283
+msgid ""
+"HTTP status code [code]226 IM Used[/code] (WebDAV). The server has fulfilled "
+"a GET request for the resource, and the response is a representation of the "
+"result of one or more instance-manipulations applied to the current instance."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:286
+msgid ""
+"HTTP status code [code]300 Multiple Choice[/code]. The request has more than "
+"one possible responses and there is no standardized way to choose one of the "
+"responses. User-agent or user should choose one of them."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:289
+msgid ""
+"HTTP status code [code]301 Moved Permanently[/code]. Redirection. This "
+"response code means the URI of requested resource has been changed. The new "
+"URI is usually included in the response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:292
+msgid ""
+"HTTP status code [code]302 Found[/code]. Temporary redirection. This "
+"response code means the URI of requested resource has been changed "
+"temporarily. New changes in the URI might be made in the future. Therefore, "
+"this same URI should be used by the client in future requests."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:295
+msgid ""
+"HTTP status code [code]303 See Other[/code]. The server is redirecting the "
+"user agent to a different resource, as indicated by a URI in the Location "
+"header field, which is intended to provide an indirect response to the "
+"original request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:298
+msgid ""
+"HTTP status code [code]304 Not Modified[/code]. A conditional GET or HEAD "
+"request has been received and would have resulted in a 200 OK response if it "
+"were not for the fact that the condition evaluated to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:301
+msgid ""
+"HTTP status code [code]305 Use Proxy[/code]. [i]Deprecated. Do not use.[/i]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:304
+msgid ""
+"HTTP status code [code]306 Switch Proxy[/code]. [i]Deprecated. Do not use.[/"
+"i]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:307
+msgid ""
+"HTTP status code [code]307 Temporary Redirect[/code]. The target resource "
+"resides temporarily under a different URI and the user agent MUST NOT change "
+"the request method if it performs an automatic redirection to that URI."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:310
+msgid ""
+"HTTP status code [code]308 Permanent Redirect[/code]. The target resource "
+"has been assigned a new permanent URI and any future references to this "
+"resource ought to use one of the enclosed URIs."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:313
+msgid ""
+"HTTP status code [code]400 Bad Request[/code]. The request was invalid. The "
+"server cannot or will not process the request due to something that is "
+"perceived to be a client error (e.g., malformed request syntax, invalid "
+"request message framing, invalid request contents, or deceptive request "
+"routing)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:316
+msgid ""
+"HTTP status code [code]401 Unauthorized[/code]. Credentials required. The "
+"request has not been applied because it lacks valid authentication "
+"credentials for the target resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:319
+msgid ""
+"HTTP status code [code]402 Payment Required[/code]. This response code is "
+"reserved for future use. Initial aim for creating this code was using it for "
+"digital payment systems, however this is not currently used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:322
+msgid ""
+"HTTP status code [code]403 Forbidden[/code]. The client does not have access "
+"rights to the content, i.e. they are unauthorized, so server is rejecting to "
+"give proper response. Unlike [code]401[/code], the client's identity is "
+"known to the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:325
+msgid ""
+"HTTP status code [code]404 Not Found[/code]. The server can not find "
+"requested resource. Either the URL is not recognized or the endpoint is "
+"valid but the resource itself does not exist. May also be sent instead of "
+"403 to hide existence of a resource if the client is not authorized."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:328
+msgid ""
+"HTTP status code [code]405 Method Not Allowed[/code]. The request's HTTP "
+"method is known by the server but has been disabled and cannot be used. For "
+"example, an API may forbid DELETE-ing a resource. The two mandatory methods, "
+"GET and HEAD, must never be disabled and should not return this error code."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:331
+msgid ""
+"HTTP status code [code]406 Not Acceptable[/code]. The target resource does "
+"not have a current representation that would be acceptable to the user "
+"agent, according to the proactive negotiation header fields received in the "
+"request. Used when negotiation content."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:334
+msgid ""
+"HTTP status code [code]407 Proxy Authentication Required[/code]. Similar to "
+"401 Unauthorized, but it indicates that the client needs to authenticate "
+"itself in order to use a proxy."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:337
+msgid ""
+"HTTP status code [code]408 Request Timeout[/code]. The server did not "
+"receive a complete request message within the time that it was prepared to "
+"wait."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:340
+msgid ""
+"HTTP status code [code]409 Conflict[/code]. The request could not be "
+"completed due to a conflict with the current state of the target resource. "
+"This code is used in situations where the user might be able to resolve the "
+"conflict and resubmit the request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:343
+msgid ""
+"HTTP status code [code]410 Gone[/code]. The target resource is no longer "
+"available at the origin server and this condition is likely permanent."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:346
+msgid ""
+"HTTP status code [code]411 Length Required[/code]. The server refuses to "
+"accept the request without a defined Content-Length header."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:349
+msgid ""
+"HTTP status code [code]412 Precondition Failed[/code]. One or more "
+"conditions given in the request header fields evaluated to [code]false[/"
+"code] when tested on the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:352
+msgid ""
+"HTTP status code [code]413 Entity Too Large[/code]. The server is refusing "
+"to process a request because the request payload is larger than the server "
+"is willing or able to process."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:355
+msgid ""
+"HTTP status code [code]414 Request-URI Too Long[/code]. The server is "
+"refusing to service the request because the request-target is longer than "
+"the server is willing to interpret."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:358
+msgid ""
+"HTTP status code [code]415 Unsupported Media Type[/code]. The origin server "
+"is refusing to service the request because the payload is in a format not "
+"supported by this method on the target resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:361
+msgid ""
+"HTTP status code [code]416 Requested Range Not Satisfiable[/code]. None of "
+"the ranges in the request's Range header field overlap the current extent of "
+"the selected resource or the set of ranges requested has been rejected due "
+"to invalid ranges or an excessive request of small or overlapping ranges."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:364
+msgid ""
+"HTTP status code [code]417 Expectation Failed[/code]. The expectation given "
+"in the request's Expect header field could not be met by at least one of the "
+"inbound servers."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:367
+msgid ""
+"HTTP status code [code]418 I'm A Teapot[/code]. Any attempt to brew coffee "
+"with a teapot should result in the error code \"418 I'm a teapot\". The "
+"resulting entity body MAY be short and stout."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:370
+msgid ""
+"HTTP status code [code]421 Misdirected Request[/code]. The request was "
+"directed at a server that is not able to produce a response. This can be "
+"sent by a server that is not configured to produce responses for the "
+"combination of scheme and authority that are included in the request URI."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:373
+msgid ""
+"HTTP status code [code]422 Unprocessable Entity[/code] (WebDAV). The server "
+"understands the content type of the request entity (hence a 415 Unsupported "
+"Media Type status code is inappropriate), and the syntax of the request "
+"entity is correct (thus a 400 Bad Request status code is inappropriate) but "
+"was unable to process the contained instructions."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:376
+msgid ""
+"HTTP status code [code]423 Locked[/code] (WebDAV). The source or destination "
+"resource of a method is locked."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:379
+msgid ""
+"HTTP status code [code]424 Failed Dependency[/code] (WebDAV). The method "
+"could not be performed on the resource because the requested action depended "
+"on another action and that action failed."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:382
+msgid ""
+"HTTP status code [code]426 Upgrade Required[/code]. The server refuses to "
+"perform the request using the current protocol but might be willing to do so "
+"after the client upgrades to a different protocol."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:385
+msgid ""
+"HTTP status code [code]428 Precondition Required[/code]. The origin server "
+"requires the request to be conditional."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:388
+msgid ""
+"HTTP status code [code]429 Too Many Requests[/code]. The user has sent too "
+"many requests in a given amount of time (see \"rate limiting\"). Back off "
+"and increase time between requests or try again later."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:391
+msgid ""
+"HTTP status code [code]431 Request Header Fields Too Large[/code]. The "
+"server is unwilling to process the request because its header fields are too "
+"large. The request MAY be resubmitted after reducing the size of the request "
+"header fields."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:394
+msgid ""
+"HTTP status code [code]451 Response Unavailable For Legal Reasons[/code]. "
+"The server is denying access to the resource as a consequence of a legal "
+"demand."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:397
+msgid ""
+"HTTP status code [code]500 Internal Server Error[/code]. The server "
+"encountered an unexpected condition that prevented it from fulfilling the "
+"request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:400
+msgid ""
+"HTTP status code [code]501 Not Implemented[/code]. The server does not "
+"support the functionality required to fulfill the request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:403
+msgid ""
+"HTTP status code [code]502 Bad Gateway[/code]. The server, while acting as a "
+"gateway or proxy, received an invalid response from an inbound server it "
+"accessed while attempting to fulfill the request. Usually returned by load "
+"balancers or proxies."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:406
+msgid ""
+"HTTP status code [code]503 Service Unavailable[/code]. The server is "
+"currently unable to handle the request due to a temporary overload or "
+"scheduled maintenance, which will likely be alleviated after some delay. Try "
+"again later."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:409
+msgid ""
+"HTTP status code [code]504 Gateway Timeout[/code]. The server, while acting "
+"as a gateway or proxy, did not receive a timely response from an upstream "
+"server it needed to access in order to complete the request. Usually "
+"returned by load balancers or proxies."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:412
+msgid ""
+"HTTP status code [code]505 HTTP Version Not Supported[/code]. The server "
+"does not support, or refuses to support, the major version of HTTP that was "
+"used in the request message."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:415
+msgid ""
+"HTTP status code [code]506 Variant Also Negotiates[/code]. The server has an "
+"internal configuration error: the chosen variant resource is configured to "
+"engage in transparent content negotiation itself, and is therefore not a "
+"proper end point in the negotiation process."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:418
+msgid ""
+"HTTP status code [code]507 Insufficient Storage[/code]. The method could not "
+"be performed on the resource because the server is unable to store the "
+"representation needed to successfully complete the request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:421
+msgid ""
+"HTTP status code [code]508 Loop Detected[/code]. The server terminated an "
+"operation because it encountered an infinite loop while processing a request "
+"with \"Depth: infinity\". This status indicates that the entire operation "
+"failed."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:424
+msgid ""
+"HTTP status code [code]510 Not Extended[/code]. The policy for accessing the "
+"resource has not been met in the request. The server should send back all "
+"the information necessary for the client to issue an extended request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:427
+msgid ""
+"HTTP status code [code]511 Network Authentication Required[/code]. The "
+"client needs to authenticate to gain network access."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:4
+msgid "A node with the ability to send HTTP(S) requests."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:7
+msgid ""
+"A node with the ability to send HTTP requests. Uses [HTTPClient] "
+"internally.\n"
+"Can be used to make HTTP requests, i.e. download or upload files or web "
+"content via HTTP.\n"
+"[b]Example of contacting a REST API and printing one of its returned fields:"
+"[/b]\n"
+"[codeblock]\n"
+"func _ready():\n"
+" # Create an HTTP request node and connect its completion signal.\n"
+" var http_request = HTTPRequest.new()\n"
+" add_child(http_request)\n"
+" http_request.connect(\"request_completed\", self, "
+"\"_http_request_completed\")\n"
+"\n"
+" # Perform the HTTP request. The URL below returns some JSON as of "
+"writing.\n"
+" var error = http_request.request(\"https://httpbin.org/get\")\n"
+" if error != OK:\n"
+" push_error(\"An error occurred in the HTTP request.\")\n"
+"\n"
+"\n"
+"# Called when the HTTP request is completed.\n"
+"func _http_request_completed(result, response_code, headers, body):\n"
+" var response = parse_json(body.get_string_from_utf8())\n"
+"\n"
+" # Will print the user agent string used by the HTTPRequest node (as "
+"recognized by httpbin.org).\n"
+" print(response.headers[\"User-Agent\"])\n"
+"[/codeblock]\n"
+"[b]Example of loading and displaying an image using HTTPRequest:[/b]\n"
+"[codeblock]\n"
+"func _ready():\n"
+" # Create an HTTP request node and connect its completion signal.\n"
+" var http_request = HTTPRequest.new()\n"
+" add_child(http_request)\n"
+" http_request.connect(\"request_completed\", self, "
+"\"_http_request_completed\")\n"
+"\n"
+" # Perform the HTTP request. The URL below returns a PNG image as of "
+"writing.\n"
+" var error = http_request.request(\"https://via.placeholder.com/512\")\n"
+" if error != OK:\n"
+" push_error(\"An error occurred in the HTTP request.\")\n"
+"\n"
+"\n"
+"# Called when the HTTP request is completed.\n"
+"func _http_request_completed(result, response_code, headers, body):\n"
+" var image = Image.new()\n"
+" var error = image.load_png_from_buffer(body)\n"
+" if error != OK:\n"
+" push_error(\"Couldn't load the image.\")\n"
+"\n"
+" var texture = ImageTexture.new()\n"
+" texture.create_from_image(image)\n"
+"\n"
+" # Display the image in a TextureRect node.\n"
+" var texture_rect = TextureRect.new()\n"
+" add_child(texture_rect)\n"
+" texture_rect.texture = texture\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:61
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/"
+"http_request_class.html"
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:69
+msgid "Cancels the current request."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:76
+msgid ""
+"Returns the response body length.\n"
+"[b]Note:[/b] Some Web servers may not send a body length. In this case, the "
+"value returned will be [code]-1[/code]. If using chunked transfer encoding, "
+"the body length will also be [code]-1[/code]."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:84
+msgid "Returns the amount of bytes this HTTPRequest downloaded."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:91
+msgid ""
+"Returns the current status of the underlying [HTTPClient]. See [enum "
+"HTTPClient.Status]."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:108
+msgid ""
+"Creates request on the underlying [HTTPClient]. If there is no configuration "
+"errors, it tries to connect using [method HTTPClient.connect_to_host] and "
+"passes parameters onto [method HTTPClient.request].\n"
+"Returns [constant OK] if request is successfully created. (Does not imply "
+"that the server has responded), [constant ERR_UNCONFIGURED] if not in the "
+"tree, [constant ERR_BUSY] if still processing previous request, [constant "
+"ERR_INVALID_PARAMETER] if given string is not a valid URL format, or "
+"[constant ERR_CANT_CONNECT] if not using thread and the [HTTPClient] cannot "
+"connect to host."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:115
+msgid "Maximum allowed size for response bodies."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:118
+msgid ""
+"The size of the buffer used and maximum bytes to read per iteration. See "
+"[member HTTPClient.read_chunk_size].\n"
+"Set this to a higher value (e.g. 65536 for 64 KiB) when downloading large "
+"files to achieve better speeds at the cost of memory."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:122
+msgid "The file to download into. Will output any received file into it."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:125
+msgid "Maximum number of allowed redirects."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:130
+msgid "If [code]true[/code], multithreading is used to improve performance."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:144
+msgid "Emitted when a request is completed."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:150
+msgid "Request successful."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:155
+msgid "Request failed while connecting."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:158
+msgid "Request failed while resolving."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:161
+msgid "Request failed due to connection (read/write) error."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:164
+msgid "Request failed on SSL handshake."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:167
+msgid "Request does not have a response (yet)."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:170
+msgid "Request exceeded its maximum size limit, see [member body_size_limit]."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:173
+msgid "Request failed (currently unused)."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:176
+msgid "HTTPRequest couldn't open the download file."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:179
+msgid "HTTPRequest couldn't write to the download file."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:182
+msgid "Request reached its maximum redirect limit, see [member max_redirects]."
+msgstr ""
+
+#: doc/classes/Image.xml:4
+msgid "Image datatype."
+msgstr ""
+
+#: doc/classes/Image.xml:7
+msgid ""
+"Native image datatype. Contains image data, which can be converted to a "
+"[Texture2D], and several functions to interact with it. The maximum width "
+"and height for an [Image] are [constant MAX_WIDTH] and [constant MAX_HEIGHT]."
+msgstr ""
+
+#: doc/classes/Image.xml:22
+msgid ""
+"Alpha-blends [code]src_rect[/code] from [code]src[/code] image to this image "
+"at coordinates [code]dest[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:37
+msgid ""
+"Alpha-blends [code]src_rect[/code] from [code]src[/code] image to this image "
+"using [code]mask[/code] image at coordinates [code]dst[/code]. Alpha "
+"channels are required for both [code]src[/code] and [code]mask[/code]. "
+"[code]dst[/code] pixels and [code]src[/code] pixels will blend if the "
+"corresponding mask pixel's alpha value is not 0. [code]src[/code] image and "
+"[code]mask[/code] image [b]must[/b] have the same size (width and height) "
+"but they can have different formats."
+msgstr ""
+
+#: doc/classes/Image.xml:50
+msgid ""
+"Copies [code]src_rect[/code] from [code]src[/code] image to this image at "
+"coordinates [code]dst[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:65
+msgid ""
+"Blits [code]src_rect[/code] area from [code]src[/code] image to this image "
+"at the coordinates given by [code]dst[/code]. [code]src[/code] pixel is "
+"copied onto [code]dst[/code] if the corresponding [code]mask[/code] pixel's "
+"alpha value is not 0. [code]src[/code] image and [code]mask[/code] image "
+"[b]must[/b] have the same size (width and height) but they can have "
+"different formats."
+msgstr ""
+
+#: doc/classes/Image.xml:74
+msgid ""
+"Converts a bumpmap to a normalmap. A bumpmap provides a height offset per-"
+"pixel, while a normalmap provides a normal direction per pixel."
+msgstr ""
+
+#: doc/classes/Image.xml:81
+msgid "Removes the image's mipmaps."
+msgstr ""
+
+#: doc/classes/Image.xml:94
+msgid ""
+"Compresses the image to use less memory. Can not directly access pixel data "
+"while the image is compressed. Returns error if the chosen compression mode "
+"is not available. See [enum CompressMode] and [enum CompressSource] "
+"constants."
+msgstr ""
+
+#: doc/classes/Image.xml:115
+msgid "Converts the image's format. See [enum Format] constants."
+msgstr ""
+
+#: doc/classes/Image.xml:124
+msgid "Copies [code]src[/code] image to this image."
+msgstr ""
+
+#: doc/classes/Image.xml:139
+msgid ""
+"Creates an empty image of given size and format. See [enum Format] "
+"constants. If [code]use_mipmaps[/code] is [code]true[/code] then generate "
+"mipmaps for this image. See the [method generate_mipmaps]."
+msgstr ""
+
+#: doc/classes/Image.xml:156
+msgid ""
+"Creates a new image of given size and format. See [enum Format] constants. "
+"Fills the image with the given raw data. If [code]use_mipmaps[/code] is "
+"[code]true[/code] then generate mipmaps for this image. See the [method "
+"generate_mipmaps]."
+msgstr ""
+
+#: doc/classes/Image.xml:167
+msgid ""
+"Crops the image to the given [code]width[/code] and [code]height[/code]. If "
+"the specified size is larger than the current size, the extra area is filled "
+"with black pixels."
+msgstr ""
+
+#: doc/classes/Image.xml:174
+msgid ""
+"Decompresses the image if it is compressed. Returns an error if decompress "
+"function is not available."
+msgstr ""
+
+#: doc/classes/Image.xml:181
+msgid ""
+"Returns [constant ALPHA_BLEND] if the image has data for alpha values. "
+"Returns [constant ALPHA_BIT] if all the alpha values are stored in a single "
+"bit. Returns [constant ALPHA_NONE] if no data for alpha values is found."
+msgstr ""
+
+#: doc/classes/Image.xml:196
+msgid ""
+"Stretches the image and enlarges it by a factor of 2. No interpolation is "
+"done."
+msgstr ""
+
+#: doc/classes/Image.xml:205
+msgid "Fills the image with a given [Color]."
+msgstr ""
+
+#: doc/classes/Image.xml:212
+msgid "Blends low-alpha pixels with nearby pixels."
+msgstr ""
+
+#: doc/classes/Image.xml:219
+msgid "Flips the image horizontally."
+msgstr ""
+
+#: doc/classes/Image.xml:226
+msgid "Flips the image vertically."
+msgstr ""
+
+#: doc/classes/Image.xml:235
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Image.xml:242
+msgid "Returns the image's raw data."
+msgstr ""
+
+#: doc/classes/Image.xml:249
+msgid "Returns the image's format. See [enum Format] constants."
+msgstr ""
+
+#: doc/classes/Image.xml:256
+msgid "Returns the image's height."
+msgstr ""
+
+#: doc/classes/Image.xml:265
+msgid ""
+"Returns the offset where the image's mipmap with index [code]mipmap[/code] "
+"is stored in the [code]data[/code] dictionary."
+msgstr ""
+
+#: doc/classes/Image.xml:276
+msgid ""
+"Returns the color of the pixel at [code](x, y)[/code]. This is the same as "
+"[method get_pixelv], but with two integer arguments instead of a [Vector2] "
+"argument."
+msgstr ""
+
+#: doc/classes/Image.xml:285
+msgid ""
+"Returns the color of the pixel at [code]src[/code]. This is the same as "
+"[method get_pixel], but with a [Vector2] argument instead of two integer "
+"arguments."
+msgstr ""
+
+#: doc/classes/Image.xml:294
+msgid ""
+"Returns a new image that is a copy of the image's area specified with "
+"[code]rect[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:301
+msgid "Returns the image's size (width and height)."
+msgstr ""
+
+#: doc/classes/Image.xml:308
+msgid ""
+"Returns a [Rect2] enclosing the visible portion of the image, considering "
+"each pixel with a non-zero alpha channel as visible."
+msgstr ""
+
+#: doc/classes/Image.xml:315
+msgid "Returns the image's width."
+msgstr ""
+
+#: doc/classes/Image.xml:322
+msgid "Returns [code]true[/code] if the image has generated mipmaps."
+msgstr ""
+
+#: doc/classes/Image.xml:329
+msgid "Returns [code]true[/code] if the image is compressed."
+msgstr ""
+
+#: doc/classes/Image.xml:336
+msgid "Returns [code]true[/code] if the image has no data."
+msgstr ""
+
+#: doc/classes/Image.xml:343
+msgid ""
+"Returns [code]true[/code] if all the image's pixels have an alpha value of "
+"0. Returns [code]false[/code] if any pixel has an alpha value higher than 0."
+msgstr ""
+
+#: doc/classes/Image.xml:352
+msgid "Loads an image from file [code]path[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:361
+msgid "Loads an image from the binary contents of a JPEG file."
+msgstr ""
+
+#: doc/classes/Image.xml:370
+msgid "Loads an image from the binary contents of a PNG file."
+msgstr ""
+
+#: doc/classes/Image.xml:379
+msgid "Loads an image from the binary contents of a WebP file."
+msgstr ""
+
+#: doc/classes/Image.xml:386
+msgid ""
+"Converts the image's data to represent coordinates on a 3D plane. This is "
+"used when the image represents a normalmap. A normalmap can add lots of "
+"detail to a 3D surface without increasing the polygon count."
+msgstr ""
+
+#: doc/classes/Image.xml:393
+msgid ""
+"Multiplies color values with alpha values. Resulting color values for a "
+"pixel are [code](color * alpha)/256[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:406
+msgid ""
+"Resizes the image to the given [code]width[/code] and [code]height[/code]. "
+"New pixels are calculated using [code]interpolation[/code]. See "
+"[code]interpolation[/code] constants."
+msgstr ""
+
+#: doc/classes/Image.xml:415
+msgid ""
+"Resizes the image to the nearest power of 2 for the width and height. If "
+"[code]square[/code] is [code]true[/code] then set width and height to be the "
+"same."
+msgstr ""
+
+#: doc/classes/Image.xml:422
+msgid ""
+"Converts a standard RGBE (Red Green Blue Exponent) image to an sRGB image."
+msgstr ""
+
+#: doc/classes/Image.xml:433
+msgid ""
+"Saves the image as an EXR file to [code]path[/code]. If [code]grayscale[/"
+"code] is [code]true[/code] and the image has only one channel, it will be "
+"saved explicitly as monochrome rather than one red channel. This function "
+"will return [constant ERR_UNAVAILABLE] if Godot was compiled without the "
+"TinyEXR module."
+msgstr ""
+
+#: doc/classes/Image.xml:442
+msgid "Saves the image as a PNG file to [code]path[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:455
+msgid ""
+"Sets the [Color] of the pixel at [code](x, y)[/code]. Example:\n"
+"[codeblock]\n"
+"var img = Image.new()\n"
+"img.create(img_width, img_height, false, Image.FORMAT_RGBA8)\n"
+"img.set_pixel(x, y, color)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Image.xml:471
+msgid ""
+"Sets the [Color] of the pixel at [code](dst.x, dst.y)[/code]. Note that the "
+"[code]dst[/code] values must be integers. Example:\n"
+"[codeblock]\n"
+"var img = Image.new()\n"
+"img.create(img_width, img_height, false, Image.FORMAT_RGBA8)\n"
+"img.set_pixelv(Vector2(x, y), color)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Image.xml:483
+msgid "Shrinks the image by a factor of 2."
+msgstr ""
+
+#: doc/classes/Image.xml:490
+msgid "Converts the raw data from the sRGB colorspace to a linear scale."
+msgstr ""
+
+#: doc/classes/Image.xml:496
+msgid ""
+"Holds all of the image's color data in a given format. See [enum Format] "
+"constants."
+msgstr ""
+
+#: doc/classes/Image.xml:501
+msgid "The maximal width allowed for [Image] resources."
+msgstr ""
+
+#: doc/classes/Image.xml:504
+msgid "The maximal height allowed for [Image] resources."
+msgstr ""
+
+#: doc/classes/Image.xml:507
+msgid "Texture format with a single 8-bit depth representing luminance."
+msgstr ""
+
+#: doc/classes/Image.xml:510
+msgid ""
+"OpenGL texture format with two values, luminance and alpha each stored with "
+"8 bits."
+msgstr ""
+
+#: doc/classes/Image.xml:513
+msgid ""
+"OpenGL texture format [code]RED[/code] with a single component and a "
+"bitdepth of 8."
+msgstr ""
+
+#: doc/classes/Image.xml:516
+msgid ""
+"OpenGL texture format [code]RG[/code] with two components and a bitdepth of "
+"8 for each."
+msgstr ""
+
+#: doc/classes/Image.xml:519
+msgid ""
+"OpenGL texture format [code]RGB[/code] with three components, each with a "
+"bitdepth of 8.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:523
+msgid ""
+"OpenGL texture format [code]RGBA[/code] with four components, each with a "
+"bitdepth of 8.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:527
+msgid ""
+"OpenGL texture format [code]RGBA[/code] with four components, each with a "
+"bitdepth of 4."
+msgstr ""
+
+#: doc/classes/Image.xml:532
+msgid ""
+"OpenGL texture format [code]GL_R32F[/code] where there's one component, a 32-"
+"bit floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:535
+msgid ""
+"OpenGL texture format [code]GL_RG32F[/code] where there are two components, "
+"each a 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/Image.xml:538
+msgid ""
+"OpenGL texture format [code]GL_RGB32F[/code] where there are three "
+"components, each a 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/Image.xml:541
+msgid ""
+"OpenGL texture format [code]GL_RGBA32F[/code] where there are four "
+"components, each a 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/Image.xml:544
+msgid ""
+"OpenGL texture format [code]GL_R32F[/code] where there's one component, a 16-"
+"bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:547
+msgid ""
+"OpenGL texture format [code]GL_RG32F[/code] where there are two components, "
+"each a 16-bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:550
+msgid ""
+"OpenGL texture format [code]GL_RGB32F[/code] where there are three "
+"components, each a 16-bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:553
+msgid ""
+"OpenGL texture format [code]GL_RGBA32F[/code] where there are four "
+"components, each a 16-bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:556
+msgid ""
+"A special OpenGL texture format where the three color components have 9 bits "
+"of precision and all three share a single 5-bit exponent."
+msgstr ""
+
+#: doc/classes/Image.xml:559
+msgid ""
+"The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] "
+"texture format that uses Block Compression 1, and is the smallest variation "
+"of S3TC, only providing 1 bit of alpha and color data being premultiplied "
+"with alpha.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:563
+msgid ""
+"The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] "
+"texture format that uses Block Compression 2, and color data is interpreted "
+"as not having been premultiplied by alpha. Well suited for images with sharp "
+"alpha transitions between translucent and opaque areas.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:567
+msgid ""
+"The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] "
+"texture format also known as Block Compression 3 or BC3 that contains 64 "
+"bits of alpha channel data followed by 64 bits of DXT1-encoded color data. "
+"Color data is not premultiplied by alpha, same as DXT3. DXT5 generally "
+"produces superior results for transparent gradients compared to DXT3.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:571
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"Red_Green_Texture_Compression]Red Green Texture Compression[/url], "
+"normalizing the red channel data using the same compression algorithm that "
+"DXT5 uses for the alpha channel."
+msgstr ""
+
+#: doc/classes/Image.xml:574
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"Red_Green_Texture_Compression]Red Green Texture Compression[/url], "
+"normalizing the red and green channel data using the same compression "
+"algorithm that DXT5 uses for the alpha channel."
+msgstr ""
+
+#: doc/classes/Image.xml:577
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"BPTC_Texture_Compression]BPTC[/url] compression with unsigned normalized "
+"RGBA components.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:581
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"BPTC_Texture_Compression]BPTC[/url] compression with signed floating-point "
+"RGB components."
+msgstr ""
+
+#: doc/classes/Image.xml:584
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"BPTC_Texture_Compression]BPTC[/url] compression with unsigned floating-point "
+"RGB components."
+msgstr ""
+
+#: doc/classes/Image.xml:587
+msgid ""
+"Texture format used on PowerVR-supported mobile platforms, uses 2-bit color "
+"depth with no alpha. More information can be found [url=https://en.wikipedia."
+"org/wiki/PVRTC]here[/url].\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:591
+msgid ""
+"Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with an "
+"alpha component."
+msgstr ""
+
+#: doc/classes/Image.xml:594
+msgid ""
+"Similar to [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with 4-"
+"bit color depth and no alpha."
+msgstr ""
+
+#: doc/classes/Image.xml:597
+msgid ""
+"Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC4[/url], but with an "
+"alpha component."
+msgstr ""
+
+#: doc/classes/Image.xml:600
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC1]Ericsson Texture Compression format 1[/"
+"url], also referred to as \"ETC1\", and is part of the OpenGL ES graphics "
+"standard. This format cannot store an alpha channel."
+msgstr ""
+
+#: doc/classes/Image.xml:603
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]R11_EAC[/code] variant), which provides one channel of "
+"unsigned data."
+msgstr ""
+
+#: doc/classes/Image.xml:606
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]SIGNED_R11_EAC[/code] variant), which provides one "
+"channel of signed data."
+msgstr ""
+
+#: doc/classes/Image.xml:609
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RG11_EAC[/code] variant), which provides two channels "
+"of unsigned data."
+msgstr ""
+
+#: doc/classes/Image.xml:612
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]SIGNED_RG11_EAC[/code] variant), which provides two "
+"channels of signed data."
+msgstr ""
+
+#: doc/classes/Image.xml:615
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RGB8[/code] variant), which is a follow-up of ETC1 and "
+"compresses RGB888 data.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:619
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RGBA8[/code]variant), which compresses RGBA8888 data "
+"with full alpha support.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:623
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RGB8_PUNCHTHROUGH_ALPHA1[/code] variant), which "
+"compresses RGBA data to make alpha either fully transparent or fully "
+"opaque.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:631
+msgid "Represents the size of the [enum Format] enum."
+msgstr ""
+
+#: doc/classes/Image.xml:634
+msgid ""
+"Performs nearest-neighbor interpolation. If the image is resized, it will be "
+"pixelated."
+msgstr ""
+
+#: doc/classes/Image.xml:637
+msgid ""
+"Performs bilinear interpolation. If the image is resized, it will be blurry. "
+"This mode is faster than [constant INTERPOLATE_CUBIC], but it results in "
+"lower quality."
+msgstr ""
+
+#: doc/classes/Image.xml:640
+msgid ""
+"Performs cubic interpolation. If the image is resized, it will be blurry. "
+"This mode often gives better results compared to [constant "
+"INTERPOLATE_BILINEAR], at the cost of being slower."
+msgstr ""
+
+#: doc/classes/Image.xml:643
+msgid ""
+"Performs bilinear separately on the two most-suited mipmap levels, then "
+"linearly interpolates between them.\n"
+"It's slower than [constant INTERPOLATE_BILINEAR], but produces higher-"
+"quality results with much less aliasing artifacts.\n"
+"If the image does not have mipmaps, they will be generated and used "
+"internally, but no mipmaps will be generated on the resulting image.\n"
+"[b]Note:[/b] If you intend to scale multiple copies of the original image, "
+"it's better to call [method generate_mipmaps]] on it in advance, to avoid "
+"wasting processing power in generating them again and again.\n"
+"On the other hand, if the image already has mipmaps, they will be used, and "
+"a new set will be generated for the resulting image."
+msgstr ""
+
+#: doc/classes/Image.xml:650
+msgid ""
+"Performs Lanczos interpolation. This is the slowest image resizing mode, but "
+"it typically gives the best results, especially when downscalng images."
+msgstr ""
+
+#: doc/classes/Image.xml:653
+msgid "Image does not have alpha."
+msgstr ""
+
+#: doc/classes/Image.xml:656
+msgid "Image stores alpha in a single bit."
+msgstr ""
+
+#: doc/classes/Image.xml:659
+msgid "Image uses alpha."
+msgstr ""
+
+#: doc/classes/Image.xml:662
+msgid "Use S3TC compression."
+msgstr ""
+
+#: doc/classes/Image.xml:665
+msgid "Use PVRTC2 compression."
+msgstr ""
+
+#: doc/classes/Image.xml:668
+msgid "Use PVRTC4 compression."
+msgstr ""
+
+#: doc/classes/Image.xml:671
+msgid "Use ETC compression."
+msgstr ""
+
+#: doc/classes/Image.xml:674
+msgid "Use ETC2 compression."
+msgstr ""
+
+#: doc/classes/Image.xml:689
+msgid ""
+"Source texture (before compression) is a regular texture. Default for all "
+"textures."
+msgstr ""
+
+#: doc/classes/Image.xml:692
+msgid "Source texture (before compression) is in sRGB space."
+msgstr ""
+
+#: doc/classes/Image.xml:695
+msgid ""
+"Source texture (before compression) is a normal texture (e.g. it can be "
+"compressed into two channels)."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:4
+msgid "A [Texture2D] based on an [Image]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:7
+msgid ""
+"A [Texture2D] based on an [Image]. Can be created from an [Image] with "
+"[method create_from_image]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:18
+msgid "Create a new [ImageTexture] from an [Image]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:25
+msgid "Returns the format of the [ImageTexture], one of [enum Image.Format]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:34
+msgid "Resizes the [ImageTexture] to the specified dimensions."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:45
+msgid ""
+"Replaces the texture's data with a new [code]image[/code]. If "
+"[code]immediate[/code] is [code]true[/code], it will take effect immediately "
+"after the call."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:4
+msgid "Draws simple geometry from code."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:7
+msgid ""
+"Draws simple geometry from code. Uses a drawing mode similar to OpenGL 1.x."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:24
+msgid ""
+"Simple helper to draw an UV sphere with given latitude, longitude and radius."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:33
+msgid ""
+"Adds a vertex in local coordinate space with the currently set color/uv/etc."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:44
+msgid ""
+"Begin drawing (and optionally pass a texture override). When done call "
+"[method end]. For more information on how this works, search for "
+"[code]glBegin()[/code] and [code]glEnd()[/code] references.\n"
+"For the type of primitive, see the [enum Mesh.PrimitiveType] enum."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:52
+msgid "Clears everything that was drawn using begin/end."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:59
+msgid "Ends a drawing context and displays the results."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:68
+msgid "The current drawing color."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:77
+msgid "The next vertex's normal."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:86
+msgid "The next vertex's tangent (and binormal facing)."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:95
+msgid "The next vertex's UV."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:104
+msgid "The next vertex's second layer UV."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:4
+msgid "Generic input event."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:7
+msgid "Base class of all sort of input event. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:10 doc/classes/InputEventJoypadButton.xml:10
+#: doc/classes/InputEventJoypadMotion.xml:10 doc/classes/InputEventKey.xml:10
+#: doc/classes/InputEventMouse.xml:10 doc/classes/InputEventScreenDrag.xml:10
+#: doc/classes/InputEventScreenTouch.xml:11
+#: doc/classes/InputEventWithModifiers.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html"
+msgstr ""
+
+#: doc/classes/InputEvent.xml:20
+msgid ""
+"Returns [code]true[/code] if the given input event and this input event can "
+"be added together (only for events of type [InputEventMouseMotion]).\n"
+"The given input event's position, global position and speed will be copied. "
+"The resulting [code]relative[/code] is a sum of both events. Both events' "
+"modifiers have to be identical."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:28
+msgid "Returns a [String] representation of the event."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:37
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:46
+msgid ""
+"Returns [code]true[/code] if this input event matches a pre-defined action "
+"of any type."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:57
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:66
+msgid ""
+"Returns [code]true[/code] if the given action is released (i.e. not "
+"pressed). Not relevant for events of type [InputEventMouseMotion] or "
+"[InputEventScreenDrag]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:73
+msgid ""
+"Returns [code]true[/code] if this input event's type is one that can be "
+"assigned to an input action."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:80
+msgid ""
+"Returns [code]true[/code] if this input event is an echo event (only for "
+"events of type [InputEventKey])."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:87
+msgid ""
+"Returns [code]true[/code] if this input event is pressed. Not relevant for "
+"events of type [InputEventMouseMotion] or [InputEventScreenDrag]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:96
+msgid ""
+"Returns [code]true[/code] if the given input event is checking for the same "
+"key ([InputEventKey]), button ([InputEventJoypadButton]) or action "
+"([InputEventAction])."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:107
+msgid ""
+"Returns a copy of the given input event which has been offset by "
+"[code]local_ofs[/code] and transformed by [code]xform[/code]. Relevant for "
+"events of type [InputEventMouseButton], [InputEventMouseMotion], "
+"[InputEventScreenTouch], [InputEventScreenDrag], [InputEventMagnifyGesture] "
+"and [InputEventPanGesture]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:113
+msgid ""
+"The event's device ID.\n"
+"[b]Note:[/b] This device ID will always be [code]-1[/code] for emulated "
+"mouse input from a touchscreen. This can be used to distinguish emulated "
+"mouse input from physical mouse input."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:4
+msgid "Input event type for actions."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:7
+msgid ""
+"Contains a generic action which can be targeted from several types of "
+"inputs. Actions can be created from the [b]Input Map[/b] tab in the "
+"[b]Project > Project Settings[/b] menu. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent."
+"html#actions"
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:16
+msgid "The action's name. Actions are accessed via this [String]."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:19
+msgid ""
+"If [code]true[/code], the action's state is pressed. If [code]false[/code], "
+"the action's state is released."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:22
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputEventGesture.xml:4
+msgid "Base class for touch control gestures."
+msgstr ""
+
+#: doc/classes/InputEventGesture.xml:14
+msgid ""
+"The local gesture position relative to the [Viewport]. If used in [method "
+"Control._gui_input], the position is relative to the current [Control] that "
+"received this gesture."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:4
+msgid "Input event for gamepad buttons."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:7
+msgid ""
+"Input event type for gamepad buttons. For gamepad analog sticks and "
+"joysticks, see [InputEventJoypadMotion]."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:16
+msgid "Button identifier. One of the [enum JoystickList] button constants."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:19
+msgid ""
+"If [code]true[/code], the button's state is pressed. If [code]false[/code], "
+"the button's state is released."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:22
+msgid ""
+"Represents the pressure the user puts on the button with his finger, if the "
+"controller supports it. Ranges from [code]0[/code] to [code]1[/code]."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:4
+msgid ""
+"Input event type for gamepad joysticks and other motions. For buttons, see "
+"[code]InputEventJoypadButton[/code]."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:7
+msgid ""
+"Stores information about joystick motions. One [InputEventJoypadMotion] "
+"represents one axis at a time."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:16
+msgid "Axis identifier. Use one of the [enum JoystickList] axis constants."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:19
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:4
+msgid "Input event type for keyboard events."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:7
+msgid ""
+"Stores key presses on the keyboard. Supports key presses, key releases and "
+"[member echo] events."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:17
+msgid ""
+"Returns the keycode combined with modifier keys such as [code]Shift[/code] "
+"or [code]Alt[/code]. See also [InputEventWithModifiers].\n"
+"To get a human-readable representation of the [InputEventKey] with "
+"modifiers, use [code]OS.get_keycode_string(event."
+"get_keycode_with_modifiers())[/code] where [code]event[/code] is the "
+"[InputEventKey]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:25
+msgid ""
+"Returns the physical keycode combined with modifier keys such as "
+"[code]Shift[/code] or [code]Alt[/code]. See also [InputEventWithModifiers].\n"
+"To get a human-readable representation of the [InputEventKey] with "
+"modifiers, use [code]OS.get_keycode_string(event."
+"get_physical_keycode_with_modifiers())[/code] where [code]event[/code] is "
+"the [InputEventKey]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:32
+msgid ""
+"If [code]true[/code], the key was already pressed before this event. It "
+"means the user is holding the key down."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:35
+msgid ""
+"The key keycode, which corresponds to one of the [enum KeyList] constants. "
+"Represent key in the current keyboard layout.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:39
+msgid ""
+"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.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:43
+msgid ""
+"If [code]true[/code], the key's state is pressed. If [code]false[/code], the "
+"key's state is released."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:46
+msgid ""
+"The key Unicode identifier (when relevant). Unicode identifiers for the "
+"composite characters and complex scripts may not be available unless IME "
+"input mode is active. See [method Window.set_ime_active] for more "
+"information."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:4
+msgid "Base input event type for mouse events."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:7
+msgid "Stores general mouse events information."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:16
+msgid ""
+"The mouse button mask identifier, one of or a bitwise combination of the "
+"[enum ButtonList] button masks."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:19
+msgid ""
+"The global mouse position relative to the current [Viewport] when used in "
+"[method Control._gui_input], otherwise is at 0,0."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:22
+msgid ""
+"The local mouse position relative to the [Viewport]. If used in [method "
+"Control._gui_input], the position is relative to the current [Control] which "
+"is under the mouse."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:4
+msgid "Input event type for mouse button events."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:7
+msgid "Contains mouse click information. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:10
+#: doc/classes/InputEventMouseMotion.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/inputs/"
+"mouse_and_input_coordinates.html"
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:16
+msgid ""
+"The mouse button identifier, one of the [enum ButtonList] button or button "
+"wheel constants."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:19
+msgid "If [code]true[/code], the mouse button's state is a double-click."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:22
+msgid ""
+"The amount (or delta) of the event. When used for high-precision scroll "
+"events, this indicates the scroll amount (vertical or horizontal). This is "
+"only supported on some platforms; the reported sensitivity varies depending "
+"on the platform. May be [code]0[/code] if not supported."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:25
+msgid ""
+"If [code]true[/code], the mouse button's state is pressed. If [code]false[/"
+"code], the mouse button's state is released."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:4
+msgid "Input event type for mouse motion events."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:7
+msgid ""
+"Contains mouse and pen motion information. Supports relative, absolute "
+"positions and speed. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:16
+msgid ""
+"Represents the pressure the user puts on the pen. Ranges from [code]0.0[/"
+"code] to [code]1.0[/code]."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:19
+msgid ""
+"The mouse position relative to the previous position (position at the last "
+"frame). \n"
+"[b]Note:[/b] Since [InputEventMouseMotion] is only emitted when the mouse "
+"moves, the last event won't have a relative position of [code]Vector2(0, 0)[/"
+"code] when the user stops moving the mouse."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:23
+msgid "The mouse speed in pixels per second."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:26
+msgid ""
+"Represents the angles of tilt of the pen. Positive X-coordinate value "
+"indicates a tilt to the right. Positive Y-coordinate value indicates a tilt "
+"toward the user. Ranges from [code]-1.0[/code] to [code]1.0[/code] for both "
+"axes."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:4
+msgid ""
+"Input event type for screen drag events. Only available on mobile devices."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:7
+msgid "Contains screen drag information. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:16
+msgid "The drag event index in the case of a multi-drag event."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:19
+msgid "The drag position."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:22
+msgid "The drag position relative to its start position."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:25
+msgid "The drag speed."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:4
+msgid ""
+"Input event type for screen touch events.\n"
+"(only available on mobile devices)"
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:8
+msgid ""
+"Stores multi-touch press/release information. Supports touch press, touch "
+"release and [member index] for multi-touch count and order."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:17
+msgid ""
+"The touch index in the case of a multi-touch event. One index = one finger."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:20
+msgid "The touch position."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:23
+msgid ""
+"If [code]true[/code], the touch's state is pressed. If [code]false[/code], "
+"the touch's state is released."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:4
+msgid "Base class for keys events with modifiers."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:7
+msgid ""
+"Contains keys events information with modifiers support like [code]Shift[/"
+"code] or [code]Alt[/code]. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:16
+msgid "State of the [code]Alt[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:19
+msgid "State of the [code]Command[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:22
+msgid "State of the [code]Ctrl[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:25
+msgid "State of the [code]Meta[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:28
+msgid "State of the [code]Shift[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:4
+msgid "A singleton that deals with inputs."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:7
+msgid ""
+"A singleton that deals with inputs. This includes key presses, mouse buttons "
+"and movement, joypads, and input actions. Actions and their events can be "
+"set in the [b]Input Map[/b] tab in the [b]Project > Project Settings[/b], or "
+"with the [InputMap] class."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/inputs/index.html"
+msgstr ""
+
+#: doc/classes/InputFilter.xml:21
+msgid ""
+"This will simulate pressing the specified action.\n"
+"The strength can be used for non-boolean actions, it's ranged between 0 and "
+"1 representing the intensity of the given action.\n"
+"[b]Note:[/b] This method will not cause any [method Node._input] calls. It "
+"is intended to be used with [method is_action_pressed] and [method "
+"is_action_just_pressed]. If you want to simulate [code]_input[/code], use "
+"[method parse_input_event] instead."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:32
+msgid "If the specified action is already pressed, this will release it."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:43
+msgid ""
+"Adds a new mapping entry (in SDL2 format) to the mapping database. "
+"Optionally update already connected devices."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:50
+msgid ""
+"If the device has an accelerometer, this will return the acceleration. "
+"Otherwise, it returns an empty [Vector3].\n"
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:60
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:67
+msgid ""
+"Returns an [Array] containing the device IDs of all currently connected "
+"joypads."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:74
+msgid "Returns the currently assigned cursor shape (see [enum CursorShape])."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:81
+msgid ""
+"If the device has an accelerometer, this will return the gravity. Otherwise, "
+"it returns an empty [Vector3]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:88
+msgid ""
+"If the device has a gyroscope, this will return the rate of rotation in rad/"
+"s around a device's X, Y, and Z axes. Otherwise, it returns an empty "
+"[Vector3]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:99
+msgid ""
+"Returns the current value of the joypad axis at given index (see [enum "
+"JoystickList])."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:108
+msgid "Returns the index of the provided axis name."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:117
+msgid ""
+"Receives a [enum JoystickList] axis and returns its equivalent name as a "
+"string."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:126
+msgid "Returns the index of the provided button name."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:135
+msgid ""
+"Receives a gamepad button from [enum JoystickList] and returns its "
+"equivalent name as a string."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:144
+msgid ""
+"Returns a SDL2-compatible device GUID on platforms that use gamepad "
+"remapping. Returns [code]\"Default Gamepad\"[/code] otherwise."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:153
+msgid "Returns the name of the joypad at the specified device index."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:162
+msgid "Returns the duration of the current vibration effect in seconds."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:171
+msgid ""
+"Returns the strength of the joypad vibration: x is the strength of the weak "
+"motor, and y is the strength of the strong motor."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:178
+msgid ""
+"Returns the mouse speed for the last time the cursor was moved, and this "
+"until the next frame where the mouse moves. This means that even if the "
+"mouse is not moving, this function will still return the value of the last "
+"motion."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:185
+msgid ""
+"If the device has a magnetometer, this will return the magnetic field "
+"strength in micro-Tesla for all axes."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:192
+msgid ""
+"Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at "
+"the same time, the bits are added together."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:199
+msgid "Returns the mouse mode. See the constants for more information."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:208
+msgid ""
+"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.\n"
+"This is useful for code that needs to run only once when an action is "
+"pressed, instead of every frame while it's pressed."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:218
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:227
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:238
+msgid ""
+"Returns [code]true[/code] if you are pressing the joypad button (see [enum "
+"JoystickList])."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:247
+msgid ""
+"Returns [code]true[/code] if the system knows the specified device. This "
+"means that it sets all button and axis indices exactly as defined in [enum "
+"JoystickList]. Unknown joypads are not expected to match these constants, "
+"but you can still retrieve events from them."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:256
+msgid ""
+"Returns [code]true[/code] if you are pressing the key in the current "
+"keyboard layout. You can pass a [enum KeyList] constant."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:265
+msgid ""
+"Returns [code]true[/code] if you are pressing the mouse button specified "
+"with [enum ButtonList]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:280
+msgid ""
+"Notifies the [InputFilter] singleton that a connection has changed, to "
+"update the state for the [code]device[/code] index.\n"
+"This is used internally and should not have to be called from user scripts. "
+"See [signal joy_connection_changed] for the signal emitted when this is "
+"triggered internally."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:290
+msgid ""
+"Feeds an [InputEvent] to the game. Can be used to artificially trigger input "
+"events from code. Also generates [method Node._input] calls.\n"
+"Example:\n"
+"[codeblock]\n"
+"var a = InputEventAction.new()\n"
+"a.action = \"ui_cancel\"\n"
+"a.pressed = true\n"
+"InputFilter.parse_input_event(a)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/InputFilter.xml:306
+msgid ""
+"Removes all mappings from the internal database that match the given GUID."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:319
+msgid ""
+"Sets a custom mouse cursor image, which is only visible inside the game "
+"window. The hotspot can also be specified. Passing [code]null[/code] to the "
+"image parameter resets to the system cursor. See [enum CursorShape] for the "
+"list of shapes.\n"
+"[code]image[/code]'s size must be lower than 256×256.\n"
+"[code]hotspot[/code] must be within [code]image[/code]'s size.\n"
+"[b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If "
+"using an [AnimatedTexture], only the first frame will be displayed.\n"
+"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
+"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
+"compression mode can't be used for custom cursors."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:332
+msgid ""
+"Sets the default cursor shape to be used in the viewport instead of "
+"[constant CURSOR_ARROW].\n"
+"[b]Note:[/b] If you want to change the default cursor shape for [Control]'s "
+"nodes, use [member Control.mouse_default_cursor_shape] instead.\n"
+"[b]Note:[/b] This method generates an [InputEventMouseMotion] to update "
+"cursor immediately."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:343
+msgid "Sets the mouse mode. See the constants for more information."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:352
+msgid ""
+"Enables or disables the accumulation of similar input events sent by the "
+"operating system. When input accumulation is enabled, all input events "
+"generated during a frame will be merged and emitted when the frame is done "
+"rendering. Therefore, this limits the number of input method calls per "
+"second to the rendering FPS.\n"
+"Input accumulation is enabled by default. It can be disabled to get slightly "
+"more precise/reactive input at the cost of increased CPU usage. In "
+"applications where drawing freehand lines is required, input accumulation "
+"should generally be disabled while the user is drawing the line to get "
+"results that closely follow the actual input."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:368
+msgid ""
+"Starts to vibrate the joypad. Joypads usually come with two rumble motors, a "
+"strong and a weak one. [code]weak_magnitude[/code] is the strength of the "
+"weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the "
+"strength of the strong motor (between 0 and 1). [code]duration[/code] is the "
+"duration of the effect in seconds (a duration of 0 will try to play the "
+"vibration indefinitely).\n"
+"[b]Note:[/b] Not every hardware is compatible with long effect durations; it "
+"is recommended to restart an effect if it has to be played for more than a "
+"few seconds."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:378
+msgid "Stops the vibration of the joypad."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:387
+msgid ""
+"Vibrate Android and iOS devices.\n"
+"[b]Note:[/b] It needs VIBRATE permission for Android at export settings. iOS "
+"does not support duration."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:397
+msgid "Sets the mouse position to the specified vector."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:408
+msgid "Emitted when a joypad device has been connected or disconnected."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:414
+msgid "Makes the mouse cursor visible if it is hidden."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:417
+msgid "Makes the mouse cursor hidden if it is visible."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:420
+msgid ""
+"Captures the mouse. The mouse will be hidden and unable to leave the game "
+"window, but it will still register movement and mouse button presses. On "
+"Windows and Linux, the mouse will use raw input mode, which means the "
+"reported movement will be unaffected by the OS' mouse acceleration settings."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:423
+msgid "Makes the mouse cursor visible but confines it to the game window."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:426
+msgid "Arrow cursor. Standard, default pointing cursor."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:429
+msgid ""
+"I-beam cursor. Usually used to show where the text cursor will appear when "
+"the mouse is clicked."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:432
+msgid ""
+"Pointing hand cursor. Usually used to indicate the pointer is over a link or "
+"other interactable item."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:435
+msgid ""
+"Cross cursor. Typically appears over regions in which a drawing operation "
+"can be performed or for selections."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:438
+msgid ""
+"Wait cursor. Indicates that the application is busy performing an operation. "
+"This cursor shape denotes that the application is still usable during the "
+"operation."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:441
+msgid ""
+"Busy cursor. Indicates that the application is busy performing an operation. "
+"This cursor shape denotes that the application isn't usable during the "
+"operation (e.g. something is blocking its main thread)."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:444
+msgid "Drag cursor. Usually displayed when dragging something."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:447
+msgid ""
+"Can drop cursor. Usually displayed when dragging something to indicate that "
+"it can be dropped at the current position."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:450
+msgid ""
+"Forbidden cursor. Indicates that the current action is forbidden (for "
+"example, when dragging something) or that the control at a position is "
+"disabled."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:453
+msgid ""
+"Vertical resize mouse cursor. A double-headed vertical arrow. It tells the "
+"user they can resize the window or the panel vertically."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:456
+msgid ""
+"Horizontal resize mouse cursor. A double-headed horizontal arrow. It tells "
+"the user they can resize the window or the panel horizontally."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:459
+msgid ""
+"Window resize mouse cursor. The cursor is a double-headed arrow that goes "
+"from the bottom left to the top right. It tells the user they can resize the "
+"window or the panel both horizontally and vertically."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:462
+msgid ""
+"Window resize mouse cursor. The cursor is a double-headed arrow that goes "
+"from the top left to the bottom right, the opposite of [constant "
+"CURSOR_BDIAGSIZE]. It tells the user they can resize the window or the panel "
+"both horizontally and vertically."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:465
+msgid "Move cursor. Indicates that something can be moved."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:468
+msgid ""
+"Vertical split mouse cursor. On Windows, it's the same as [constant "
+"CURSOR_VSIZE]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:471
+msgid ""
+"Horizontal split mouse cursor. On Windows, it's the same as [constant "
+"CURSOR_HSIZE]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:474
+msgid "Help cursor. Usually a question mark."
+msgstr ""
+
+#: doc/classes/InputMap.xml:4
+msgid "Singleton that manages [InputEventAction]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:7
+msgid ""
+"Manages all [InputEventAction] which can be created/modified from the "
+"project settings menu [b]Project > Project Settings > Input Map[/b] or in "
+"code with [method add_action] and [method action_add_event]. See [method "
+"Node._input]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent."
+"html#inputmap"
+msgstr ""
+
+#: doc/classes/InputMap.xml:21
+msgid ""
+"Adds an [InputEvent] to an action. This [InputEvent] will trigger the action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:32
+msgid "Removes an [InputEvent] from an action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:41
+msgid "Removes all events from an action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:52
+msgid ""
+"Returns [code]true[/code] if the action has the given [InputEvent] "
+"associated with it."
+msgstr ""
+
+#: doc/classes/InputMap.xml:63
+msgid "Sets a deadzone value for the action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:74
+msgid ""
+"Adds an empty action to the [InputMap] with a configurable [code]deadzone[/"
+"code].\n"
+"An [InputEvent] can then be added to this action with [method "
+"action_add_event]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:84
+msgid "Removes an action from the [InputMap]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:95
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputMap.xml:104
+msgid "Returns an array of [InputEvent]s associated with a given action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:111
+msgid "Returns an array of all actions in the [InputMap]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:120
+msgid ""
+"Returns [code]true[/code] if the [InputMap] has a registered action with the "
+"given name."
+msgstr ""
+
+#: doc/classes/InputMap.xml:127
+msgid ""
+"Clears all [InputEventAction] in the [InputMap] and load it anew from "
+"[ProjectSettings]."
+msgstr ""
+
+#: doc/classes/InstancePlaceholder.xml:4
+msgid "Placeholder for the root [Node] of a [PackedScene]."
+msgstr ""
+
+#: doc/classes/InstancePlaceholder.xml:7
+msgid ""
+"Turning on the option [b]Load As Placeholder[/b] for an instanced scene in "
+"the editor causes it to be replaced by an [InstancePlaceholder] when running "
+"the game. This makes it possible to delay actually loading the scene until "
+"calling [method create_instance]. This is useful to avoid loading large "
+"scenes all at once by loading parts of it selectively.\n"
+"The [InstancePlaceholder] does not have a transform. This causes any child "
+"nodes to be positioned relatively to the [Viewport] from point (0,0), rather "
+"than their parent as displayed in the editor. Replacing the placeholder with "
+"a scene with a transform will transform children relatively to their parent "
+"again."
+msgstr ""
+
+#: doc/classes/InstancePlaceholder.xml:27
+msgid ""
+"Gets the path to the [PackedScene] resource file that is loaded by default "
+"when calling [method create_instance]."
+msgstr ""
+
+#: doc/classes/int.xml:4
+msgid "Integer built-in type."
+msgstr ""
+
+#: doc/classes/int.xml:7
+msgid ""
+"Signed 64-bit integer type.\n"
+"It can take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. "
+"[code][-9223372036854775808, 9223372036854775807][/code]. Exceeding those "
+"bounds will wrap around.\n"
+"[int] is a [Variant] type, and will thus be used when assigning an integer "
+"value to a [Variant]. It can also be enforced with the [code]: int[/code] "
+"type hint.\n"
+"[codeblock]\n"
+"var my_variant = 0 # int, value 0.\n"
+"my_variant += 4.2 # float, value 4.2.\n"
+"var my_int: int = 1 # int, value 1.\n"
+"my_int = 4.2 # int, value 4, the right value is implicitly cast to int.\n"
+"my_int = int(\"6.7\") # int, value 6, the String is explicitly cast with "
+"int.\n"
+"\n"
+"var max_int = 9223372036854775807\n"
+"print(max_int) # 9223372036854775807, OK.\n"
+"max_int += 1\n"
+"print(max_int) # -9223372036854775808, we overflowed and wrapped around.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/int.xml:32
+msgid ""
+"Cast a [bool] value to an integer value, [code]int(true)[/code] will be "
+"equals to 1 and [code]int(false)[/code] will be equals to 0."
+msgstr ""
+
+#: doc/classes/int.xml:41
+msgid ""
+"Cast a float value to an integer value, this method simply removes the "
+"number fractions, so for example [code]int(2.7)[/code] will be equals to 2, "
+"[code]int(.1)[/code] will be equals to 0 and [code]int(-2.7)[/code] will be "
+"equals to -2."
+msgstr ""
+
+#: doc/classes/int.xml:50
+msgid ""
+"Cast a [String] value to an integer value, this method is an integer parser "
+"from a string, so calling this method with an invalid integer string will "
+"return 0, a valid string will be something like [code]'1.7'[/code]. This "
+"method will ignore all non-number characters, so calling [code]int('1e3')[/"
+"code] will return 13."
+msgstr ""
+
+#: doc/classes/IP.xml:4
+msgid "Internet protocol (IP) support functions such as DNS resolution."
+msgstr ""
+
+#: doc/classes/IP.xml:7
+msgid ""
+"IP contains support functions for the Internet Protocol (IP). TCP/IP support "
+"is in different classes (see [StreamPeerTCP] and [TCP_Server]). IP provides "
+"DNS hostname resolution support, both blocking and threaded."
+msgstr ""
+
+#: doc/classes/IP.xml:18
+msgid ""
+"Removes all of a [code]hostname[/code]'s cached references. If no "
+"[code]hostname[/code] is given, all cached IP addresses are removed."
+msgstr ""
+
+#: doc/classes/IP.xml:27
+msgid ""
+"Removes a given item [code]id[/code] from the queue. This should be used to "
+"free a queue after it has completed to enable more queries to happen."
+msgstr ""
+
+#: doc/classes/IP.xml:34
+msgid "Returns all of the user's current IPv4 and IPv6 addresses as an array."
+msgstr ""
+
+#: doc/classes/IP.xml:41
+msgid ""
+"Returns all network adapters as an array.\n"
+"Each adapter is a dictionary of the form:\n"
+"[codeblock]\n"
+"{\n"
+" \"index\": \"1\", # Interface index.\n"
+" \"name\": \"eth0\", # Interface name.\n"
+" \"friendly\": \"Ethernet One\", # A friendly name (might be empty).\n"
+" \"addresses\": [\"192.168.1.101\"], # An array of IP addresses "
+"associated to this interface.\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/IP.xml:59
+msgid ""
+"Returns a queued hostname's IP address, given its queue [code]id[/code]. "
+"Returns an empty string on error or if resolution hasn't happened yet (see "
+"[method get_resolve_item_status])."
+msgstr ""
+
+#: doc/classes/IP.xml:68
+msgid ""
+"Returns a queued hostname's status as a [enum ResolverStatus] constant, "
+"given its queue [code]id[/code]."
+msgstr ""
+
+#: doc/classes/IP.xml:79
+msgid ""
+"Returns a given hostname's IPv4 or IPv6 address when resolved (blocking-type "
+"method). The address type returned depends on the [enum Type] constant given "
+"as [code]ip_type[/code]."
+msgstr ""
+
+#: doc/classes/IP.xml:90
+msgid ""
+"Creates a queue item to resolve a hostname to an IPv4 or IPv6 address "
+"depending on the [enum Type] constant given as [code]ip_type[/code]. Returns "
+"the queue ID if successful, or [constant RESOLVER_INVALID_ID] on error."
+msgstr ""
+
+#: doc/classes/IP.xml:96
+msgid "DNS hostname resolver status: No status."
+msgstr ""
+
+#: doc/classes/IP.xml:99
+msgid "DNS hostname resolver status: Waiting."
+msgstr ""
+
+#: doc/classes/IP.xml:102
+msgid "DNS hostname resolver status: Done."
+msgstr ""
+
+#: doc/classes/IP.xml:105
+msgid "DNS hostname resolver status: Error."
+msgstr ""
+
+#: doc/classes/IP.xml:108
+msgid ""
+"Maximum number of concurrent DNS resolver queries allowed, [constant "
+"RESOLVER_INVALID_ID] is returned if exceeded."
+msgstr ""
+
+#: doc/classes/IP.xml:111
+msgid ""
+"Invalid ID constant. Returned if [constant RESOLVER_MAX_QUERIES] is exceeded."
+msgstr ""
+
+#: doc/classes/IP.xml:114
+msgid "Address type: None."
+msgstr ""
+
+#: doc/classes/IP.xml:117
+msgid "Address type: Internet protocol version 4 (IPv4)."
+msgstr ""
+
+#: doc/classes/IP.xml:120
+msgid "Address type: Internet protocol version 6 (IPv6)."
+msgstr ""
+
+#: doc/classes/IP.xml:123
+msgid "Address type: Any."
+msgstr ""
+
+#: doc/classes/IP_Unix.xml:4
+msgid "UNIX IP support. See [IP]."
+msgstr ""
+
+#: doc/classes/IP_Unix.xml:7
+msgid "UNIX-specific implementation of IP support functions. See [IP]."
+msgstr ""
+
+#: doc/classes/ItemList.xml:4
+msgid ""
+"Control that provides a list of selectable items (and/or icons) in a single "
+"column, or optionally in multiple columns."
+msgstr ""
+
+#: doc/classes/ItemList.xml:7
+msgid ""
+"This control provides a selectable list of items that may be in a single (or "
+"multiple columns) with option of text, icons, or both text and icon. "
+"Tooltips are supported and may be different for every item in the list.\n"
+"Selectable items in the list may be selected or deselected and multiple "
+"selection may be enabled. Selection with right mouse button may also be "
+"enabled to allow use of popup context menus. Items may also be \"activated\" "
+"by double-clicking them or by pressing Enter.\n"
+"Item text only supports single-line strings, newline characters (e.g. "
+"[code]\\n[/code]) in the string won't produce a newline. Text wrapping is "
+"enabled in [constant ICON_MODE_TOP] mode, but column's width is adjusted to "
+"fully fit its content by default. You need to set [member "
+"fixed_column_width] greater than zero to wrap the text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:22
+msgid "Adds an item to the item list with no text, only an icon."
+msgstr ""
+
+#: doc/classes/ItemList.xml:35
+msgid ""
+"Adds an item to the item list with specified text. Specify an [code]icon[/"
+"code], or use [code]null[/code] as the [code]icon[/code] for a list item "
+"with no icon.\n"
+"If selectable is [code]true[/code], the list item will be selectable."
+msgstr ""
+
+#: doc/classes/ItemList.xml:43
+msgid "Removes all items from the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:50
+msgid ""
+"Ensure current selection is visible, adjusting the scroll position as "
+"necessary."
+msgstr ""
+
+#: doc/classes/ItemList.xml:61
+msgid ""
+"Returns the item index at the given [code]position[/code].\n"
+"When there is no item at that point, -1 will be returned if [code]exact[/"
+"code] is [code]true[/code], and the closest item index will be returned "
+"otherwise."
+msgstr ""
+
+#: doc/classes/ItemList.xml:69
+msgid "Returns the number of items currently in the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:78
+msgid ""
+"Returns the custom background color of the item specified by [code]idx[/"
+"code] index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:87
+msgid ""
+"Returns the custom foreground color of the item specified by [code]idx[/"
+"code] index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:96
+msgid "Returns the icon associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:105
+msgid "Returns a [Color] modulating item's icon at the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:114
+msgid ""
+"Returns the region of item's icon used. The whole icon will be used if the "
+"region has no area."
+msgstr ""
+
+#: doc/classes/ItemList.xml:123
+msgid "Returns the metadata value of the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:132
+msgid "Returns the text associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:141
+msgid "Returns the tooltip hint associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:148
+msgid "Returns an array with the indexes of the selected items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:155
+msgid "Returns the [Object] ID associated with the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:162
+msgid "Returns [code]true[/code] if one or more items are selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:171
+msgid ""
+"Returns [code]true[/code] if the item at the specified index is disabled."
+msgstr ""
+
+#: doc/classes/ItemList.xml:180
+msgid ""
+"Returns [code]true[/code] if the item icon will be drawn transposed, i.e. "
+"the X and Y axes are swapped."
+msgstr ""
+
+#: doc/classes/ItemList.xml:189
+msgid ""
+"Returns [code]true[/code] if the item at the specified index is selectable."
+msgstr ""
+
+#: doc/classes/ItemList.xml:198
+msgid ""
+"Returns [code]true[/code] if the tooltip is enabled for specified item index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:207
+msgid ""
+"Returns [code]true[/code] if the item at the specified index is currently "
+"selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:218
+msgid "Moves item from index [code]from_idx[/code] to [code]to_idx[/code]."
+msgstr ""
+
+#: doc/classes/ItemList.xml:227
+msgid "Removes the item specified by [code]idx[/code] index from the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:238
+msgid ""
+"Select the item at the specified index.\n"
+"[b]Note:[/b] This method does not trigger the item selection signal."
+msgstr ""
+
+#: doc/classes/ItemList.xml:250
+msgid ""
+"Sets the background color of the item specified by [code]idx[/code] index to "
+"the specified [Color].\n"
+"[codeblock]\n"
+"var some_string = \"Some text\"\n"
+"some_string.set_item_custom_bg_color(0,Color(1, 0, 0, 1) # This will set the "
+"background color of the first item of the control to red.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ItemList.xml:265
+msgid ""
+"Sets the foreground color of the item specified by [code]idx[/code] index to "
+"the specified [Color].\n"
+"[codeblock]\n"
+"var some_string = \"Some text\"\n"
+"some_string.set_item_custom_fg_color(0,Color(1, 0, 0, 1) # This will set the "
+"foreground color of the first item of the control to red.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ItemList.xml:280
+msgid ""
+"Disables (or enables) the item at the specified index.\n"
+"Disabled items cannot be selected and do not trigger activation signals "
+"(when double-clicking or pressing Enter)."
+msgstr ""
+
+#: doc/classes/ItemList.xml:292
+msgid ""
+"Sets (or replaces) the icon's [Texture2D] associated with the specified "
+"index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:303
+msgid ""
+"Sets a modulating [Color] of the item associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:314
+msgid ""
+"Sets the region of item's icon used. The whole icon will be used if the "
+"region has no area."
+msgstr ""
+
+#: doc/classes/ItemList.xml:325
+msgid "Sets whether the item icon will be drawn transposed."
+msgstr ""
+
+#: doc/classes/ItemList.xml:336
+msgid ""
+"Sets a value (of any type) to be stored with the item associated with the "
+"specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:347
+msgid ""
+"Allows or disallows selection of the item associated with the specified "
+"index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:358
+msgid "Sets text of the item associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:369
+msgid "Sets the tooltip hint for the item associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:380
+msgid "Sets whether the tooltip hint is enabled for specified item index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:387
+msgid "Sorts items in the list by their text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:396
+msgid "Ensures the item associated with the specified index is not selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:403
+msgid "Ensures there are no items selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:409
+msgid ""
+"If [code]true[/code], the currently selected item can be selected again."
+msgstr ""
+
+#: doc/classes/ItemList.xml:412
+msgid "If [code]true[/code], right mouse button click can select items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:415
+msgid ""
+"If [code]true[/code], the control will automatically resize the height to "
+"fit its content."
+msgstr ""
+
+#: doc/classes/ItemList.xml:418
+msgid ""
+"The width all columns will be adjusted to.\n"
+"A value of zero disables the adjustment, each item will have a width equal "
+"to the width of its content and the columns will have an uneven width."
+msgstr ""
+
+#: doc/classes/ItemList.xml:422
+msgid ""
+"The size all icons will be adjusted to.\n"
+"If either X or Y component is not greater than zero, icon size won't be "
+"affected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:427
+msgid ""
+"The icon position, whether above or to the left of the text. See the [enum "
+"IconMode] constants."
+msgstr ""
+
+#: doc/classes/ItemList.xml:430
+msgid ""
+"The scale of icon applied after [member fixed_icon_size] and transposing "
+"takes effect."
+msgstr ""
+
+#: doc/classes/ItemList.xml:433
+msgid ""
+"Maximum columns the list will have.\n"
+"If greater than zero, the content will be split among the specified "
+"columns.\n"
+"A value of zero means unlimited columns, i.e. all items will be put in the "
+"same row."
+msgstr ""
+
+#: doc/classes/ItemList.xml:438
+msgid ""
+"Maximum lines of text allowed in each item. Space will be reserved even when "
+"there is not enough lines of text to display.\n"
+"[b]Note:[/b] This property takes effect only when [member icon_mode] is "
+"[constant ICON_MODE_TOP]. To make the text wrap, [member fixed_column_width] "
+"should be greater than zero."
+msgstr ""
+
+#: doc/classes/ItemList.xml:443
+msgid ""
+"Whether all columns will have the same width.\n"
+"If [code]true[/code], the width is equal to the largest column width of all "
+"columns."
+msgstr ""
+
+#: doc/classes/ItemList.xml:447
+msgid ""
+"Allows single or multiple item selection. See the [enum SelectMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/ItemList.xml:455
+msgid ""
+"Triggered when specified list item is activated via double-clicking or by "
+"pressing Enter."
+msgstr ""
+
+#: doc/classes/ItemList.xml:464
+msgid ""
+"Triggered when specified list item has been selected via right mouse "
+"clicking.\n"
+"The click position is also provided to allow appropriate popup of context "
+"menus at the correct location.\n"
+"[member allow_rmb_select] must be enabled."
+msgstr ""
+
+#: doc/classes/ItemList.xml:473
+msgid ""
+"Triggered when specified item has been selected.\n"
+"[member allow_reselect] must be enabled to reselect an item."
+msgstr ""
+
+#: doc/classes/ItemList.xml:483
+msgid ""
+"Triggered when a multiple selection is altered on a list allowing multiple "
+"selection."
+msgstr ""
+
+#: doc/classes/ItemList.xml:488
+msgid ""
+"Triggered when a left mouse click is issued within the rect of the list but "
+"on empty space."
+msgstr ""
+
+#: doc/classes/ItemList.xml:495
+msgid ""
+"Triggered when a right mouse click is issued within the rect of the list but "
+"on empty space.\n"
+"[member allow_rmb_select] must be enabled."
+msgstr ""
+
+#: doc/classes/ItemList.xml:502
+msgid "Icon is drawn above the text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:505
+msgid "Icon is drawn to the left of the text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:508
+msgid "Only allow selecting a single item."
+msgstr ""
+
+#: doc/classes/ItemList.xml:511
+msgid "Allows selecting multiple items by holding Ctrl or Shift."
+msgstr ""
+
+#: doc/classes/ItemList.xml:516
+msgid ""
+"Default [StyleBox] for the [ItemList], i.e. used when the control is not "
+"being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:519
+msgid "[StyleBox] used when the [ItemList] is being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:522
+msgid "[StyleBox] used for the cursor, when the [ItemList] is being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:525
+msgid ""
+"[StyleBox] used for the cursor, when the [ItemList] is not being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:528 doc/classes/Tree.xml:439
+msgid "[Font] of the item's text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:531 doc/classes/Tree.xml:442
+msgid "Default text [Color] of the item."
+msgstr ""
+
+#: doc/classes/ItemList.xml:534 doc/classes/Tree.xml:445
+msgid "Text [Color] used when the item is selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:537
+msgid ""
+"[Color] of the guideline. The guideline is a line drawn between each row of "
+"items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:540
+msgid "The horizontal spacing between items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:543
+msgid "The spacing between item's icon and text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:546
+msgid "The vertical spacing between each line of text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:549
+msgid ""
+"[StyleBox] for the selected items, used when the [ItemList] is not being "
+"focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:552
+msgid ""
+"[StyleBox] for the selected items, used when the [ItemList] is being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:555
+msgid "The vertical spacing between items."
+msgstr ""
+
+#: doc/classes/JavaScript.xml:4
+msgid ""
+"Singleton that connects the engine with the browser's JavaScript context in "
+"HTML5 export."
+msgstr ""
+
+#: doc/classes/JavaScript.xml:7
+msgid ""
+"The JavaScript singleton is implemented only in the HTML5 export. It's used "
+"to access the browser's JavaScript context. This allows interaction with "
+"embedding pages or calling third-party JavaScript APIs."
+msgstr ""
+
+#: doc/classes/JavaScript.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/workflow/export/"
+"exporting_for_web.html#calling-javascript-from-script"
+msgstr ""
+
+#: doc/classes/JavaScript.xml:21
+msgid ""
+"Execute the string [code]code[/code] as JavaScript code within the browser "
+"window. This is a call to the actual global JavaScript function [code]eval()"
+"[/code].\n"
+"If [code]use_global_execution_context[/code] is [code]true[/code], the code "
+"will be evaluated in the global execution context. Otherwise, it is "
+"evaluated in the execution context of a function within the engine's runtime "
+"environment."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:4
+msgid "Base node for all joint constraints in 2D physics."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:7
+msgid ""
+"Base node for all joint constraints in 2D physics. Joints take 2 bodies and "
+"apply a custom constraint."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:15
+msgid ""
+"When [member node_a] and [member node_b] move in different directions the "
+"[code]bias[/code] controls how fast the joint pulls them back to their "
+"original position. The lower the [code]bias[/code] the more the two bodies "
+"can pull on the joint."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:18
+msgid "If [code]true[/code], [member node_a] and [member node_b] can collide."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:21
+msgid "The first body attached to the joint. Must derive from [PhysicsBody2D]."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:24
+msgid ""
+"The second body attached to the joint. Must derive from [PhysicsBody2D]."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:4
+msgid "Base class for all 3D joints."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:7
+msgid ""
+"Joints are used to bind together two physics bodies. They have a solver "
+"priority and can define if the bodies of the two attached nodes should be "
+"able to collide with each other."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:15
+msgid ""
+"If [code]true[/code], the two bodies of the nodes are not able to collide "
+"with each other."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:18
+msgid "The node attached to the first side (A) of the joint."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:21
+msgid "The node attached to the second side (B) of the joint."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:24
+msgid ""
+"The priority used to define which solver is executed first for multiple "
+"joints. The lower the value, the higher the priority."
+msgstr ""
+
+#: doc/classes/JSON.xml:4
+msgid "Helper class for parsing JSON data."
+msgstr ""
+
+#: doc/classes/JSON.xml:7
+msgid ""
+"Helper class for parsing JSON data. For usage example and other important "
+"hints, see [JSONParseResult]."
+msgstr ""
+
+#: doc/classes/JSON.xml:18
+msgid ""
+"Parses a JSON encoded string and returns a [JSONParseResult] containing the "
+"result."
+msgstr ""
+
+#: doc/classes/JSON.xml:31
+msgid ""
+"Converts a [Variant] var to JSON text and returns the result. Useful for "
+"serializing data to store or send over the network."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:4
+msgid "Data class wrapper for decoded JSON."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:7
+msgid ""
+"Returned by [method JSON.parse], [JSONParseResult] contains the decoded JSON "
+"or error information if the JSON source wasn't successfully parsed. You can "
+"check if the JSON source was successfully parsed with [code]if json_result."
+"error == OK[/code]."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:15
+msgid ""
+"The error type if the JSON source was not successfully parsed. See the [enum "
+"Error] constants."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:18
+msgid ""
+"The line number where the error occurred if JSON source was not successfully "
+"parsed."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:21
+msgid ""
+"The error message if JSON source was not successfully parsed. See the [enum "
+"Error] constants."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:24
+msgid ""
+"A [Variant] containing the parsed JSON. Use [method @GDScript.typeof] or the "
+"[code]is[/code] keyword to check if it is what you expect. For example, if "
+"the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] "
+"will be returned. If the JSON source starts with braces ([code][][/code]), "
+"an [Array] will be returned.\n"
+"[b]Note:[/b] The JSON specification does not define integer or float types, "
+"but only a number type. Therefore, parsing a JSON text will convert all "
+"numerical values to float types.\n"
+"[b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, "
+"thus, you should not rely on keys being in a certain order if a dictionary "
+"is constructed from JSON. In contrast, JSON arrays retain the order of their "
+"elements:\n"
+"[codeblock]\n"
+"var p = JSON.parse('[\"hello\", \"world\", \"!\"]')\n"
+"if typeof(p.result) == TYPE_ARRAY:\n"
+" print(p.result[0]) # Prints \"hello\"\n"
+"else:\n"
+" print(\"unexpected results\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:4
+msgid "Kinematic body 2D node."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:7
+msgid ""
+"Kinematic bodies are special types of bodies that are meant to be user-"
+"controlled. They are not affected by physics at all; to other types of "
+"bodies, such as a character or a rigid body, these are the same as a static "
+"body. However, they have two main uses:\n"
+"[b]Simulated motion:[/b] When these bodies are moved manually, either from "
+"code or from an [AnimationPlayer] (with [member AnimationPlayer."
+"playback_process_mode] set to \"physics\"), the physics will automatically "
+"compute an estimate of their linear and angular velocity. This makes them "
+"very useful for moving platforms or other AnimationPlayer-controlled objects "
+"(like a door, a bridge that opens, etc).\n"
+"[b]Kinematic characters:[/b] KinematicBody2D also has an API for moving "
+"objects (the [method move_and_collide] and [method move_and_slide] methods) "
+"while performing collision tests. This makes them really useful to implement "
+"characters that collide against a world, but that don't require advanced "
+"physics."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:12 doc/classes/KinematicBody3D.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/"
+"kinematic_character_2d.html"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/"
+"using_kinematic_body_2d.html"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:20 doc/classes/KinematicBody3D.xml:28
+msgid ""
+"Returns the surface normal of the floor at the last collision point. Only "
+"valid after calling [method move_and_slide] or [method "
+"move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:27 doc/classes/KinematicBody3D.xml:35
+msgid ""
+"Returns the linear velocity of the floor at the last collision point. Only "
+"valid after calling [method move_and_slide] or [method "
+"move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:36
+msgid ""
+"Returns a [KinematicCollision2D], which contains information about a "
+"collision that occurred during the last [method move_and_slide] call. Since "
+"the body can collide several times in a single call to [method "
+"move_and_slide], you must specify the index of the collision in the range 0 "
+"to ([method get_slide_count] - 1).\n"
+"[b]Example usage:[/b]\n"
+"[codeblock]\n"
+"for i in get_slide_count():\n"
+" var collision = get_slide_collision(i)\n"
+" print(\"Collided with: \", collision.collider.name)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:49 doc/classes/KinematicBody3D.xml:51
+msgid ""
+"Returns the number of times the body collided and changed direction during "
+"the last call to [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:56 doc/classes/KinematicBody3D.xml:58
+msgid ""
+"Returns [code]true[/code] if the body is on the ceiling. Only updates when "
+"calling [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:63 doc/classes/KinematicBody3D.xml:65
+msgid ""
+"Returns [code]true[/code] if the body is on the floor. Only updates when "
+"calling [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:70 doc/classes/KinematicBody3D.xml:72
+msgid ""
+"Returns [code]true[/code] if the body is on a wall. Only updates when "
+"calling [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:85
+msgid ""
+"Moves the body along the vector [code]rel_vec[/code]. The body will stop if "
+"it collides. Returns a [KinematicCollision2D], which contains information "
+"about the collision.\n"
+"If [code]test_only[/code] is [code]true[/code], the body does not move but "
+"the would-be collision information is given."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:105
+msgid ""
+"Moves the body along a vector. If the body collides with another, it will "
+"slide along the other body rather than stop immediately. If the other body "
+"is a [KinematicBody2D] or [RigidBody2D], it will also be affected by the "
+"motion of the other body. You can use this to make moving or rotating "
+"platforms, or to make nodes push other nodes.\n"
+"This method should be used in [method Node._physics_process] (or in a method "
+"called by [method Node._physics_process]), as it uses the physics step's "
+"[code]delta[/code] value automatically in calculations. Otherwise, the "
+"simulation will run at an incorrect speed.\n"
+"[code]linear_velocity[/code] is the velocity vector in pixels per second. "
+"Unlike in [method move_and_collide], you should [i]not[/i] multiply it by "
+"[code]delta[/code] — the physics engine handles applying the velocity. \n"
+"[code]up_direction[/code] is the up direction, used to determine what is a "
+"wall and what is a floor or a ceiling. If set to the default value of "
+"[code]Vector2(0, 0)[/code], everything is considered a wall. This is useful "
+"for topdown games.\n"
+"If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on "
+"slopes when you include gravity in [code]linear_velocity[/code] and the body "
+"is standing still.\n"
+"If the body collides, it will change direction a maximum of "
+"[code]max_slides[/code] times before it stops.\n"
+"[code]floor_max_angle[/code] is the maximum angle (in radians) where a slope "
+"is still considered a floor (or a ceiling), rather than a wall. The default "
+"value equals 45 degrees.\n"
+"If [code]infinite_inertia[/code] is [code]true[/code], body will be able to "
+"push [RigidBody2D] nodes, but it won't also detect any collisions with them. "
+"If [code]false[/code], it will interact with [RigidBody2D] nodes like with "
+"[StaticBody2D].\n"
+"Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a "
+"slide collision occurred. To get detailed information about collisions that "
+"occurred, use [method get_slide_collision]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:134
+msgid ""
+"Moves the body while keeping it attached to slopes. Similar to [method "
+"move_and_slide].\n"
+"As long as the [code]snap[/code] vector is in contact with the ground, the "
+"body will remain attached to the surface. This means you must disable snap "
+"in order to jump, for example. You can do this by setting [code]snap[/code] "
+"to [code](0, 0)[/code] or by using [method move_and_slide] instead."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:148
+msgid ""
+"Checks for collisions without moving the body. Virtually sets the node's "
+"position, scale and rotation to that of the given [Transform2D], then tries "
+"to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/"
+"code] if a collision would occur."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:154 doc/classes/KinematicBody3D.xml:167
+msgid ""
+"If the body is at least this close to another body, this body will consider "
+"them to be colliding."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:157
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:4
+msgid "Kinematic body 3D node."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:7
+msgid ""
+"Kinematic bodies are special types of bodies that are meant to be user-"
+"controlled. They are not affected by physics at all; to other types of "
+"bodies, such as a character or a rigid body, these are the same as a static "
+"body. However, they have two main uses:\n"
+"[b]Simulated motion:[/b] When these bodies are moved manually, either from "
+"code or from an [AnimationPlayer] (with [member AnimationPlayer."
+"playback_process_mode] set to \"physics\"), the physics will automatically "
+"compute an estimate of their linear and angular velocity. This makes them "
+"very useful for moving platforms or other AnimationPlayer-controlled objects "
+"(like a door, a bridge that opens, etc).\n"
+"[b]Kinematic characters:[/b] KinematicBody3D also has an API for moving "
+"objects (the [method move_and_collide] and [method move_and_slide] methods) "
+"while performing collision tests. This makes them really useful to implement "
+"characters that collide against a world, but that don't require advanced "
+"physics."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:21
+msgid ""
+"Returns [code]true[/code] if the specified [code]axis[/code] is locked. See "
+"also [member move_lock_x], [member move_lock_y] and [member move_lock_z]."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:44
+msgid ""
+"Returns a [KinematicCollision3D], which contains information about a "
+"collision that occurred during the last [method move_and_slide] call. Since "
+"the body can collide several times in a single call to [method "
+"move_and_slide], you must specify the index of the collision in the range 0 "
+"to ([method get_slide_count] - 1)."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:87
+msgid ""
+"Moves the body along the vector [code]rel_vec[/code]. The body will stop if "
+"it collides. Returns a [KinematicCollision3D], which contains information "
+"about the collision.\n"
+"If [code]test_only[/code] is [code]true[/code], the body does not move but "
+"the would-be collision information is given."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:107
+msgid ""
+"Moves the body along a vector. If the body collides with another, it will "
+"slide along the other body rather than stop immediately. If the other body "
+"is a [KinematicBody3D] or [RigidBody3D], it will also be affected by the "
+"motion of the other body. You can use this to make moving or rotating "
+"platforms, or to make nodes push other nodes.\n"
+"This method should be used in [method Node._physics_process] (or in a method "
+"called by [method Node._physics_process]), as it uses the physics step's "
+"[code]delta[/code] value automatically in calculations. Otherwise, the "
+"simulation will run at an incorrect speed.\n"
+"[code]linear_velocity[/code] is the velocity vector (typically meters per "
+"second). Unlike in [method move_and_collide], you should [i]not[/i] multiply "
+"it by [code]delta[/code] — the physics engine handles applying the "
+"velocity. \n"
+"[code]up_direction[/code] is the up direction, used to determine what is a "
+"wall and what is a floor or a ceiling. If set to the default value of "
+"[code]Vector3(0, 0, 0)[/code], everything is considered a wall.\n"
+"If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on "
+"slopes if you include gravity in [code]linear_velocity[/code].\n"
+"If the body collides, it will change direction a maximum of "
+"[code]max_slides[/code] times before it stops.\n"
+"[code]floor_max_angle[/code] is the maximum angle (in radians) where a slope "
+"is still considered a floor (or a ceiling), rather than a wall. The default "
+"value equals 45 degrees.\n"
+"If [code]infinite_inertia[/code] is [code]true[/code], body will be able to "
+"push [RigidBody3D] nodes, but it won't also detect any collisions with them. "
+"If [code]false[/code], it will interact with [RigidBody3D] nodes like with "
+"[StaticBody3D].\n"
+"Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a "
+"slide collision occurred. To get detailed information about collisions that "
+"occurred, use [method get_slide_collision]."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:136
+msgid ""
+"Moves the body while keeping it attached to slopes. Similar to [method "
+"move_and_slide].\n"
+"As long as the [code]snap[/code] vector is in contact with the ground, the "
+"body will remain attached to the surface. This means you must disable snap "
+"in order to jump, for example. You can do this by setting [code]snap[/code] "
+"to [code](0, 0, 0)[/code] or by using [method move_and_slide] instead."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:148
+msgid ""
+"Locks or unlocks the specified [code]axis[/code] depending on the value of "
+"[code]lock[/code]. See also [member move_lock_x], [member move_lock_y] and "
+"[member move_lock_z]."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:161
+msgid ""
+"Checks for collisions without moving the body. Virtually sets the node's "
+"position, scale and rotation to that of the given [Transform], then tries to "
+"move the body along the vector [code]rel_vec[/code]. Returns [code]true[/"
+"code] if a collision would occur."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:170
+msgid "Lock the body's X axis movement."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:173
+msgid "Lock the body's Y axis movement."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:176
+msgid "Lock the body's Z axis movement."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:4
+msgid "Collision data for [KinematicBody2D] collisions."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:7
+msgid ""
+"Contains collision data for [KinematicBody2D] collisions. When a "
+"[KinematicBody2D] is moved using [method KinematicBody2D.move_and_collide], "
+"it stops if it detects a collision with another body. If a collision is "
+"detected, a KinematicCollision2D object is returned.\n"
+"This object contains information about the collision, including the "
+"colliding object, the remaining motion, and the collision position. This "
+"information can be used to calculate a collision response."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:16
+#: doc/classes/KinematicCollision3D.xml:16
+msgid "The colliding body."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:19
+#: doc/classes/KinematicCollision3D.xml:19
+msgid ""
+"The colliding body's unique instance ID. See [method Object.get_instance_id]."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:22
+#: doc/classes/KinematicCollision3D.xml:22
+msgid "The colliding body's metadata. See [Object]."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:25
+#: doc/classes/KinematicCollision3D.xml:25
+msgid "The colliding body's shape."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:28
+msgid "The colliding shape's index. See [CollisionObject2D]."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:31
+#: doc/classes/KinematicCollision3D.xml:31
+msgid "The colliding object's velocity."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:34
+#: doc/classes/KinematicCollision3D.xml:34
+msgid "The moving object's colliding shape."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:37
+#: doc/classes/KinematicCollision3D.xml:37
+msgid "The colliding body's shape's normal at the point of collision."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:40
+#: doc/classes/KinematicCollision3D.xml:40
+msgid "The point of collision, in global coordinates."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:43
+#: doc/classes/KinematicCollision3D.xml:43
+msgid "The moving object's remaining movement vector."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:46
+#: doc/classes/KinematicCollision3D.xml:46
+msgid "The distance the moving object traveled before collision."
+msgstr ""
+
+#: doc/classes/KinematicCollision3D.xml:4
+msgid "Collision data for [KinematicBody3D] collisions."
+msgstr ""
+
+#: doc/classes/KinematicCollision3D.xml:7
+msgid ""
+"Contains collision data for [KinematicBody3D] collisions. When a "
+"[KinematicBody3D] is moved using [method KinematicBody3D.move_and_collide], "
+"it stops if it detects a collision with another body. If a collision is "
+"detected, a KinematicCollision3D object is returned.\n"
+"This object contains information about the collision, including the "
+"colliding object, the remaining motion, and the collision position. This "
+"information can be used to calculate a collision response."
+msgstr ""
+
+#: doc/classes/KinematicCollision3D.xml:28
+msgid "The colliding shape's index. See [CollisionObject3D]."
+msgstr ""
+
+#: doc/classes/Label.xml:4
+msgid ""
+"Displays plain text in a line or wrapped inside a rectangle. For formatted "
+"text, use [RichTextLabel]."
+msgstr ""
+
+#: doc/classes/Label.xml:7
+msgid ""
+"Label displays plain text on the screen. It gives you control over the "
+"horizontal and vertical alignment, and can wrap the text inside the node's "
+"bounding rectangle. It doesn't support bold, italics or other formatting. "
+"For that, use [RichTextLabel] instead.\n"
+"[b]Note:[/b] Contrarily to most other [Control]s, Label's [member Control."
+"mouse_filter] defaults to [constant Control.MOUSE_FILTER_IGNORE] (i.e. it "
+"doesn't react to mouse input events). This implies that a label won't "
+"display any configured [member Control.hint_tooltip], unless you change its "
+"mouse filter."
+msgstr ""
+
+#: doc/classes/Label.xml:17
+msgid "Returns the amount of lines of text the Label has."
+msgstr ""
+
+#: doc/classes/Label.xml:24
+msgid "Returns the font size in pixels."
+msgstr ""
+
+#: doc/classes/Label.xml:31
+msgid ""
+"Returns the total number of printable characters in the text (excluding "
+"spaces and newlines)."
+msgstr ""
+
+#: doc/classes/Label.xml:38
+msgid ""
+"Returns the number of lines shown. Useful if the [Label]'s height cannot "
+"currently display all lines."
+msgstr ""
+
+#: doc/classes/Label.xml:44
+msgid ""
+"Controls the text's horizontal align. Supports left, center, right, and "
+"fill, or justify. Set it to one of the [enum Align] constants."
+msgstr ""
+
+#: doc/classes/Label.xml:47
+msgid ""
+"If [code]true[/code], wraps the text inside the node's bounding rectangle. "
+"If you resize the node, it will change its height automatically to show all "
+"the text."
+msgstr ""
+
+#: doc/classes/Label.xml:50
+msgid ""
+"If [code]true[/code], the Label only shows the text that fits inside its "
+"bounding rectangle. It also lets you scale the node down freely."
+msgstr ""
+
+#: doc/classes/Label.xml:53
+msgid ""
+"The node ignores the first [code]lines_skipped[/code] lines before it starts "
+"to display text."
+msgstr ""
+
+#: doc/classes/Label.xml:56
+msgid "Limits the lines of text the node shows on screen."
+msgstr ""
+
+#: doc/classes/Label.xml:60
+msgid ""
+"Limits the count of visible characters. If you set [code]percent_visible[/"
+"code] to 50, only up to half of the text's characters will display on "
+"screen. Useful to animate the text in a dialog box."
+msgstr ""
+
+#: doc/classes/Label.xml:64
+msgid "The text to display on screen."
+msgstr ""
+
+#: doc/classes/Label.xml:67
+msgid "If [code]true[/code], all the text displays as UPPERCASE."
+msgstr ""
+
+#: doc/classes/Label.xml:70
+msgid ""
+"Controls the text's vertical align. Supports top, center, bottom, and fill. "
+"Set it to one of the [enum VAlign] constants."
+msgstr ""
+
+#: doc/classes/Label.xml:73
+msgid "Restricts the number of characters to display. Set to -1 to disable."
+msgstr ""
+
+#: doc/classes/Label.xml:78
+msgid "Align rows to the left (default)."
+msgstr ""
+
+#: doc/classes/Label.xml:81
+msgid "Align rows centered."
+msgstr ""
+
+#: doc/classes/Label.xml:84
+msgid "Align rows to the right."
+msgstr ""
+
+#: doc/classes/Label.xml:87
+msgid "Expand row whitespaces to fit the width."
+msgstr ""
+
+#: doc/classes/Label.xml:90
+msgid "Align the whole text to the top."
+msgstr ""
+
+#: doc/classes/Label.xml:93
+msgid "Align the whole text to the center."
+msgstr ""
+
+#: doc/classes/Label.xml:96
+msgid "Align the whole text to the bottom."
+msgstr ""
+
+#: doc/classes/Label.xml:99
+msgid "Align the whole text by spreading the rows."
+msgstr ""
+
+#: doc/classes/Label.xml:104
+msgid "[Font] used for the [Label]'s text."
+msgstr ""
+
+#: doc/classes/Label.xml:107
+msgid "Default text [Color] of the [Label]."
+msgstr ""
+
+#: doc/classes/Label.xml:110
+msgid "[Color] of the text's shadow effect."
+msgstr ""
+
+#: doc/classes/Label.xml:113
+msgid "The tint of [Font]'s outline. See [member DynamicFont.outline_color]."
+msgstr ""
+
+#: doc/classes/Label.xml:116
+msgid "Vertical space between lines in multiline [Label]."
+msgstr ""
+
+#: doc/classes/Label.xml:119
+msgid "Background [StyleBox] for the [Label]."
+msgstr ""
+
+#: doc/classes/Label.xml:122
+msgid ""
+"Boolean value. If set to 1 ([code]true[/code]), the shadow will be displayed "
+"around the whole text as an outline."
+msgstr ""
+
+#: doc/classes/Label.xml:125
+msgid "The horizontal offset of the text's shadow."
+msgstr ""
+
+#: doc/classes/Label.xml:128
+msgid "The vertical offset of the text's shadow."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:4
+msgid "A [Texture2D] capable of storing many smaller textures with offsets."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:7
+msgid ""
+"A [Texture2D] capable of storing many smaller textures with offsets.\n"
+"You can dynamically add pieces ([Texture2D]s) to this [LargeTexture] using "
+"different offsets."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:21
+msgid ""
+"Adds [code]texture[/code] to this [LargeTexture], starting on offset "
+"[code]ofs[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:28
+msgid "Clears the [LargeTexture]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:35
+msgid "Returns the number of pieces currently in this [LargeTexture]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:44
+msgid "Returns the offset of the piece with the index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:53
+msgid "Returns the [Texture2D] of the piece with the index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:64
+msgid ""
+"Sets the offset of the piece with the index [code]idx[/code] to [code]ofs[/"
+"code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:75
+msgid ""
+"Sets the [Texture2D] of the piece with index [code]idx[/code] to "
+"[code]texture[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:84
+msgid "Sets the size of this [LargeTexture]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:4
+msgid "Casts light in a 2D environment."
+msgstr ""
+
+#: doc/classes/Light2D.xml:7
+msgid ""
+"Casts light in a 2D environment. Light is defined by a (usually grayscale) "
+"texture, a color, an energy value, a mode (see constants), and various other "
+"parameters (range and shadows-related).\n"
+"[b]Note:[/b] Light2D can also be used as a mask."
+msgstr ""
+
+#: doc/classes/Light2D.xml:11 doc/classes/LightOccluder2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/2d/2d_lights_and_shadows."
+"html"
+msgstr ""
+
+#: doc/classes/Light2D.xml:17
+msgid "The Light2D's [Color]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:20
+msgid "If [code]true[/code], Light2D will only appear when editing the scene."
+msgstr ""
+
+#: doc/classes/Light2D.xml:23
+msgid "If [code]true[/code], Light2D will emit light."
+msgstr ""
+
+#: doc/classes/Light2D.xml:26
+msgid ""
+"The Light2D's energy value. The larger the value, the stronger the light."
+msgstr ""
+
+#: doc/classes/Light2D.xml:29
+msgid "The Light2D's mode. See [enum Mode] constants for values."
+msgstr ""
+
+#: doc/classes/Light2D.xml:32
+msgid "The offset of the Light2D's [code]texture[/code]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:35
+msgid "The height of the Light2D. Used with 2D normal mapping."
+msgstr ""
+
+#: doc/classes/Light2D.xml:38
+msgid ""
+"The layer mask. Only objects with a matching mask will be affected by the "
+"Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:41
+msgid "Maximum layer value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:44
+msgid "Minimum layer value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:47
+msgid ""
+"Maximum [code]z[/code] value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:50
+msgid ""
+"Minimum [code]z[/code] value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:53
+msgid "Shadow buffer size."
+msgstr ""
+
+#: doc/classes/Light2D.xml:56
+msgid "[Color] of shadows cast by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:59
+msgid "If [code]true[/code], the Light2D will cast shadows."
+msgstr ""
+
+#: doc/classes/Light2D.xml:62
+msgid "Shadow filter type. See [enum ShadowFilter] for possible values."
+msgstr ""
+
+#: doc/classes/Light2D.xml:65
+msgid "Smoothing value for shadows."
+msgstr ""
+
+#: doc/classes/Light2D.xml:68
+msgid ""
+"The shadow mask. Used with [LightOccluder2D] to cast shadows. Only occluders "
+"with a matching light mask will cast shadows."
+msgstr ""
+
+#: doc/classes/Light2D.xml:71
+msgid "[Texture2D] used for the Light2D's appearance."
+msgstr ""
+
+#: doc/classes/Light2D.xml:74
+msgid "The [code]texture[/code]'s scale factor."
+msgstr ""
+
+#: doc/classes/Light2D.xml:79
+msgid ""
+"Adds the value of pixels corresponding to the Light2D to the values of "
+"pixels under it. This is the common behavior of a light."
+msgstr ""
+
+#: doc/classes/Light2D.xml:82
+msgid ""
+"Subtracts the value of pixels corresponding to the Light2D to the values of "
+"pixels under it, resulting in inversed light effect."
+msgstr ""
+
+#: doc/classes/Light2D.xml:85
+msgid ""
+"Mix the value of pixels corresponding to the Light2D to the values of pixels "
+"under it by linear interpolation."
+msgstr ""
+
+#: doc/classes/Light2D.xml:88
+msgid ""
+"The light texture of the Light2D is used as a mask, hiding or revealing "
+"parts of the screen underneath depending on the value of each pixel of the "
+"light (mask) texture."
+msgstr ""
+
+#: doc/classes/Light2D.xml:91
+msgid "No filter applies to the shadow map. See [member shadow_filter]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:94
+msgid ""
+"Percentage closer filtering (5 samples) applies to the shadow map. See "
+"[member shadow_filter]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:97
+msgid ""
+"Percentage closer filtering (13 samples) applies to the shadow map. See "
+"[member shadow_filter]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:4
+msgid "Provides a base class for different kinds of light nodes."
+msgstr ""
+
+#: doc/classes/Light3D.xml:7
+msgid ""
+"Light3D is the abstract base class for light nodes, so it shouldn't be used "
+"directly (it can't be instanced). Other types of light nodes inherit from "
+"it. Light3D contains the common variables and parameters used for lighting."
+msgstr ""
+
+#: doc/classes/Light3D.xml:19
+msgid "Returns the value of the specified [enum Light3D.Param] parameter."
+msgstr ""
+
+#: doc/classes/Light3D.xml:30
+msgid "Sets the value of the specified [enum Light3D.Param] parameter."
+msgstr ""
+
+#: doc/classes/Light3D.xml:36
+msgid ""
+"If [code]true[/code], the light only appears in the editor and will not be "
+"visible at runtime."
+msgstr ""
+
+#: doc/classes/Light3D.xml:39
+msgid "The light's bake mode. See [enum BakeMode]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:42
+msgid "The light's color."
+msgstr ""
+
+#: doc/classes/Light3D.xml:45
+msgid "The light will affect objects in the selected layers."
+msgstr ""
+
+#: doc/classes/Light3D.xml:48
+msgid "The light's strength multiplier."
+msgstr ""
+
+#: doc/classes/Light3D.xml:51
+msgid ""
+"Secondary multiplier used with indirect light (light bounces). Used with "
+"[GIProbe]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:54
+msgid ""
+"If [code]true[/code], the light's effect is reversed, darkening areas and "
+"casting bright shadows."
+msgstr ""
+
+#: doc/classes/Light3D.xml:57
+msgid ""
+"The intensity of the specular blob in objects affected by the light. At "
+"[code]0[/code] the light becomes a pure diffuse light."
+msgstr ""
+
+#: doc/classes/Light3D.xml:60
+msgid ""
+"Used to adjust shadow appearance. Too small a value results in self-"
+"shadowing, while too large a value causes shadows to separate from casters. "
+"Adjust as needed."
+msgstr ""
+
+#: doc/classes/Light3D.xml:63
+msgid "The color of shadows cast by this light."
+msgstr ""
+
+#: doc/classes/Light3D.xml:66
+msgid "Attempts to reduce [member shadow_bias] gap."
+msgstr ""
+
+#: doc/classes/Light3D.xml:69
+msgid "If [code]true[/code], the light will cast shadows."
+msgstr ""
+
+#: doc/classes/Light3D.xml:72
+msgid ""
+"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 [constant GeometryInstance3D."
+"SHADOW_CASTING_SETTING_DOUBLE_SIDED]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:77
+msgid "Constant for accessing [member light_energy]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:80
+msgid "Constant for accessing [member light_indirect_energy]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:83
+msgid "Constant for accessing [member light_specular]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:86
+msgid ""
+"Constant for accessing [member OmniLight3D.omni_range] or [member "
+"SpotLight3D.spot_range]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:89
+msgid ""
+"Constant for accessing [member OmniLight3D.omni_attenuation] or [member "
+"SpotLight3D.spot_attenuation]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:92
+msgid "Constant for accessing [member SpotLight3D.spot_angle]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:95
+msgid "Constant for accessing [member SpotLight3D.spot_angle_attenuation]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:98
+msgid "Constant for accessing [member shadow_contact]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:101
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_max_distance]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:104
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_split_1]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:107
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_split_2]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:110
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_split_3]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:115
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_normal_bias]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:118
+msgid "Constant for accessing [member shadow_bias]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:121
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_bias_split_scale]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:127
+msgid ""
+"Light is ignored when baking.\n"
+"[b]Note:[/b] Hiding a light does [i]not[/i] affect baking."
+msgstr ""
+
+#: doc/classes/Light3D.xml:131
+msgid "Only indirect lighting will be baked (default)."
+msgstr ""
+
+#: doc/classes/Light3D.xml:134
+msgid ""
+"Both direct and indirect light will be baked.\n"
+"[b]Note:[/b] You should hide the light if you don't want it to appear twice "
+"(dynamic and baked)."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:4
+msgid "Occludes light cast by a Light2D, casting shadows."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:7
+msgid ""
+"Occludes light cast by a Light2D, casting shadows. The LightOccluder2D must "
+"be provided with an [OccluderPolygon2D] in order for the shadow to be "
+"computed."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:16
+msgid ""
+"The LightOccluder2D's light mask. The LightOccluder2D will cast shadows only "
+"from Light2D(s) that have the same light mask(s)."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:19
+msgid "The [OccluderPolygon2D] used to compute the shadow."
+msgstr ""
+
+#: doc/classes/Line2D.xml:4
+msgid "A 2D line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:7
+msgid "A line through several points in 2D space."
+msgstr ""
+
+#: doc/classes/Line2D.xml:20
+msgid ""
+"Adds a point at the [code]position[/code]. Appends the point at the end of "
+"the line.\n"
+"If [code]at_position[/code] is given, the point is inserted before the point "
+"number [code]at_position[/code], moving that point (and every point after) "
+"after the inserted point. If [code]at_position[/code] is not given, or is an "
+"illegal value ([code]at_position < 0[/code] or [code]at_position >= [method "
+"get_point_count][/code]), the point will be appended at the end of the point "
+"list."
+msgstr ""
+
+#: doc/classes/Line2D.xml:28
+msgid "Removes all points from the line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:35
+msgid "Returns the Line2D's amount of points."
+msgstr ""
+
+#: doc/classes/Line2D.xml:44
+msgid "Returns point [code]i[/code]'s position."
+msgstr ""
+
+#: doc/classes/Line2D.xml:53
+msgid "Removes the point at index [code]i[/code] from the line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:64
+msgid ""
+"Overwrites the position in point [code]i[/code] with the supplied "
+"[code]position[/code]."
+msgstr ""
+
+#: doc/classes/Line2D.xml:70
+msgid "If [code]true[/code], the line's border will be anti-aliased."
+msgstr ""
+
+#: doc/classes/Line2D.xml:73
+msgid ""
+"Controls the style of the line's first point. Use [enum LineCapMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/Line2D.xml:76
+msgid "The line's color. Will not be used if a gradient is set."
+msgstr ""
+
+#: doc/classes/Line2D.xml:79
+msgid ""
+"Controls the style of the line's last point. Use [enum LineCapMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/Line2D.xml:82
+msgid ""
+"The gradient is drawn through the whole line from start to finish. The "
+"default color will not be used if a gradient is set."
+msgstr ""
+
+#: doc/classes/Line2D.xml:85
+msgid "The style for the points between the start and the end."
+msgstr ""
+
+#: doc/classes/Line2D.xml:88
+msgid ""
+"The points that form the lines. The line is drawn between every point set in "
+"this array."
+msgstr ""
+
+#: doc/classes/Line2D.xml:91
+msgid ""
+"The smoothness of the rounded joints and caps. This is only used if a cap or "
+"joint is set as round."
+msgstr ""
+
+#: doc/classes/Line2D.xml:94
+msgid ""
+"The direction difference in radians between vector points. This value is "
+"only used if [code]joint mode[/code] is set to [constant LINE_JOINT_SHARP]."
+msgstr ""
+
+#: doc/classes/Line2D.xml:97
+msgid ""
+"The texture used for the line's texture. Uses [code]texture_mode[/code] for "
+"drawing style."
+msgstr ""
+
+#: doc/classes/Line2D.xml:100
+msgid ""
+"The style to render the [code]texture[/code] on the line. Use [enum "
+"LineTextureMode] constants."
+msgstr ""
+
+#: doc/classes/Line2D.xml:103
+msgid "The line's width."
+msgstr ""
+
+#: doc/classes/Line2D.xml:106
+msgid ""
+"The line's width varies with the curve. The original width is simply "
+"multiply by the value of the Curve."
+msgstr ""
+
+#: doc/classes/Line2D.xml:111
+msgid ""
+"The line's joints will be pointy. If [code]sharp_limit[/code] is greater "
+"than the rotation of a joint, it becomes a bevel joint instead."
+msgstr ""
+
+#: doc/classes/Line2D.xml:114
+msgid "The line's joints will be bevelled/chamfered."
+msgstr ""
+
+#: doc/classes/Line2D.xml:117
+msgid "The line's joints will be rounded."
+msgstr ""
+
+#: doc/classes/Line2D.xml:120
+msgid "Don't draw a line cap."
+msgstr ""
+
+#: doc/classes/Line2D.xml:123
+msgid "Draws the line cap as a box."
+msgstr ""
+
+#: doc/classes/Line2D.xml:126
+msgid "Draws the line cap as a circle."
+msgstr ""
+
+#: doc/classes/Line2D.xml:129
+msgid ""
+"Takes the left pixels of the texture and renders it over the whole line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:132
+msgid ""
+"Tiles the texture over the line. The texture must be imported with "
+"[b]Repeat[/b] enabled for it to work properly."
+msgstr ""
+
+#: doc/classes/Line2D.xml:135
+msgid ""
+"Stretches the texture across the line. Import the texture with [b]Repeat[/b] "
+"disabled for best results."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:4
+msgid "Control that provides single-line string editing."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:7
+msgid ""
+"LineEdit provides a single-line string editor, used for text fields.\n"
+"It features many built-in shortcuts which will always be available "
+"([code]Ctrl[/code] here maps to [code]Command[/code] on macOS):\n"
+"- Ctrl + C: Copy\n"
+"- Ctrl + X: Cut\n"
+"- Ctrl + V or Ctrl + Y: Paste/\"yank\"\n"
+"- Ctrl + Z: Undo\n"
+"- Ctrl + Shift + Z: Redo\n"
+"- Ctrl + U: Delete text from the cursor position to the beginning of the "
+"line\n"
+"- Ctrl + K: Delete text from the cursor position to the end of the line\n"
+"- Ctrl + A: Select all text\n"
+"- Up/Down arrow: Move the cursor to the beginning/end of the line\n"
+"On macOS, some extra keyboard shortcuts are available:\n"
+"- Ctrl + F: Like the right arrow key, move the cursor one character right\n"
+"- Ctrl + B: Like the left arrow key, move the cursor one character left\n"
+"- Ctrl + P: Like the up arrow key, move the cursor to the previous line\n"
+"- Ctrl + N: Like the down arrow key, move the cursor to the next line\n"
+"- Ctrl + D: Like the Delete key, delete the character on the right side of "
+"cursor\n"
+"- Ctrl + H: Like the Backspace key, delete the character on the left side of "
+"the cursor\n"
+"- Ctrl + A: Like the Home key, move the cursor to the beginning of the line\n"
+"- Ctrl + E: Like the End key, move the cursor to the end of the line\n"
+"- Command + Left arrow: Like the Home key, move the cursor to the beginning "
+"of the line\n"
+"- Command + Right arrow: Like the End key, move the cursor to the end of the "
+"line"
+msgstr ""
+
+#: doc/classes/LineEdit.xml:39
+msgid ""
+"Adds [code]text[/code] after the cursor. If the resulting value is longer "
+"than [member max_length], nothing happens."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:46
+msgid "Erases the [LineEdit] text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:53
+msgid "Clears the current selection."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:60
+msgid ""
+"Returns the [PopupMenu] of this [LineEdit]. By default, this menu is "
+"displayed when right-clicking on the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:69
+msgid "Executes a given action as defined in the [enum MenuItems] enum."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:80
+msgid ""
+"Selects characters inside [LineEdit] between [code]from[/code] and [code]to[/"
+"code]. By default, [code]from[/code] is at the beginning and [code]to[/code] "
+"at the end.\n"
+"[codeblock]\n"
+"text = \"Welcome\"\n"
+"select() # Will select \"Welcome\".\n"
+"select(4) # Will select \"ome\".\n"
+"select(2, 5) # Will select \"lco\".\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/LineEdit.xml:93
+msgid "Selects the whole [String]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:99
+msgid "Text alignment as defined in the [enum Align] enum."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:102 doc/classes/TextEdit.xml:395
+msgid "If [code]true[/code], the caret (visual cursor) blinks."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:105 doc/classes/TextEdit.xml:398
+msgid "Duration (in seconds) of a caret's blinking cycle."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:108
+msgid ""
+"The cursor's position inside the [LineEdit]. When set, the text may scroll "
+"to accommodate it."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:111
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:114
+msgid "If [code]true[/code], the context menu will appear when right-clicked."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:117
+msgid ""
+"If [code]false[/code], existing text cannot be modified and new text cannot "
+"be added."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:120
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:124
+msgid ""
+"Maximum amount of characters that can be entered inside the [LineEdit]. If "
+"[code]0[/code], there is no limit."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:128
+msgid ""
+"Opacity of the [member placeholder_text]. From [code]0[/code] to [code]1[/"
+"code]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:131
+msgid ""
+"Text shown when the [LineEdit] is empty. It is [b]not[/b] the [LineEdit]'s "
+"default value (see [member text])."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:134
+msgid ""
+"Sets the icon that will appear in the right end of the [LineEdit] if there's "
+"no [member text], or always, if [member clear_button_enabled] is set to "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:137
+msgid ""
+"If [code]true[/code], every character is replaced with the secret character "
+"(see [member secret_character])."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:140
+msgid ""
+"The character to use to mask secret input (defaults to \"*\"). Only a single "
+"character can be used as the secret character."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:143
+msgid ""
+"If [code]false[/code], it's impossible to select the text using mouse nor "
+"keyboard."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:146
+msgid "If [code]false[/code], using shortcuts will be disabled."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:149
+msgid ""
+"String value of the [LineEdit].\n"
+"[b]Note:[/b] Changing text using this property won't emit the [signal "
+"text_changed] signal."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:156
+msgid ""
+"Emitted when trying to append text that would overflow the [member "
+"max_length]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:163 doc/classes/TextEdit.xml:513
+msgid "Emitted when the text changes."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:170
+msgid "Emitted when the user presses [constant KEY_ENTER] on the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:176
+msgid "Aligns the text on the left-hand side of the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:179
+msgid "Centers the text in the middle of the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:182
+msgid "Aligns the text on the right-hand side of the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:185
+msgid "Stretches whitespaces to fit the [LineEdit]'s width."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:188 doc/classes/TextEdit.xml:534
+msgid "Cuts (copies and clears) the selected text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:191 doc/classes/TextEdit.xml:537
+msgid "Copies the selected text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:194
+msgid ""
+"Pastes the clipboard text over the selected text (or at the cursor's "
+"position).\n"
+"Non-printable escape characters are automatically stripped from the OS "
+"clipboard via [method String.strip_escapes]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:198
+msgid "Erases the whole [LineEdit] text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:201
+msgid "Selects the whole [LineEdit] text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:204 doc/classes/TextEdit.xml:549
+msgid "Undoes the previous action."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:207
+msgid "Reverse the last undo action."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:210 doc/classes/TextEdit.xml:555
+msgid "Represents the size of the [enum MenuItems] enum."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:215
+msgid "Texture for the clear button. See [member clear_button_enabled]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:218
+msgid "Color used as default tint for the clear button."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:221
+msgid "Color used for the clear button when it's pressed."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:224
+msgid "Color of the [LineEdit]'s visual cursor (caret)."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:227
+msgid "Background used when [LineEdit] has GUI focus."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:230
+msgid "Font used for the text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:233
+msgid "Default font color."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:236
+msgid "Font color for selected text (inside the selection rectangle)."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:239
+msgid "Font color when editing is disabled."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:242
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:245
+msgid "Default background for the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:248
+msgid ""
+"Background used when [LineEdit] is in read-only mode ([member editable] is "
+"set to [code]false[/code])."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:251
+msgid "Color of the selection rectangle."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:4
+msgid "Line shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:7
+msgid ""
+"Line shape for 2D collisions. It works like a 2D plane and will not allow "
+"any physics body to go to the negative side. Not recommended for rigid "
+"bodies, and usually not recommended for static bodies either because it "
+"forces checks against it on every frame."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:15
+msgid "The line's distance from the origin."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:18
+msgid "The line's normal."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:4
+msgid "Simple button used to represent a link to some resource."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:7
+msgid ""
+"This kind of button is primarily used when the interaction with the button "
+"causes a context change (like linking to a web page)."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:21
+msgid ""
+"Determines when to show the underline. See [enum UnderlineMode] for options."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:26
+msgid "The LinkButton will always show an underline at the bottom of its text."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:29
+msgid ""
+"The LinkButton will show an underline at the bottom of its text when the "
+"mouse cursor is over it."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:32
+msgid "The LinkButton will never show an underline at the bottom of its text."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:37
+msgid ""
+"[StyleBox] used when the [LinkButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:40
+msgid "[Font] of the [LinkButton]'s text."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:43
+msgid "Default text [Color] of the [LinkButton]."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:46
+msgid "Text [Color] used when the [LinkButton] is being hovered."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:49
+msgid "Text [Color] used when the [LinkButton] is being pressed."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:52
+msgid "The vertical space between the baseline of text and the underline."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:4
+msgid "Overrides the location sounds are heard from."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:7
+msgid ""
+"Once added to the scene tree and enabled using [method make_current], this "
+"node will override the location sounds are heard from. This can be used to "
+"listen from a location different from the [Camera3D].\n"
+"[b]Note:[/b] There is no 2D equivalent for this node yet."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:17
+msgid "Disables the listener to use the current camera's listener instead."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:24
+msgid "Returns the listener's global orthonormalized [Transform]."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:31
+msgid ""
+"Returns [code]true[/code] if the listener was made current using [method "
+"make_current], [code]false[/code] otherwise.\n"
+"[b]Note:[/b] There may be more than one Listener3D marked as \"current\" in "
+"the scene tree, but only the one that was made current last will be used."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:39
+msgid "Enables the listener. This will override the current camera's listener."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:4
+msgid "Abstract base class for the game's main loop."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:7
+msgid ""
+"[MainLoop] is the abstract base class for a Godot project's game loop. It is "
+"inherited by [SceneTree], which is the default game loop implementation used "
+"in Godot projects, though it is also possible to write and use one's own "
+"[MainLoop] subclass instead of the scene tree.\n"
+"Upon the application start, a [MainLoop] implementation must be provided to "
+"the OS; otherwise, the application will exit. This happens automatically "
+"(and a [SceneTree] is created) unless a main [Script] is provided from the "
+"command line (with e.g. [code]godot -s my_loop.gd[/code], which should then "
+"be a [MainLoop] implementation.\n"
+"Here is an example script implementing a simple [MainLoop]:\n"
+"[b]FIXME:[/b] No longer valid after DisplayServer split and Input "
+"refactoring.\n"
+"[codeblock]\n"
+"extends MainLoop\n"
+"\n"
+"var time_elapsed = 0\n"
+"var keys_typed = []\n"
+"var quit = false\n"
+"\n"
+"func _initialize():\n"
+" print(\"Initialized:\")\n"
+" print(\" Starting time: %s\" % str(time_elapsed))\n"
+"\n"
+"func _idle(delta):\n"
+" time_elapsed += delta\n"
+" # Return true to end the main loop.\n"
+" return quit\n"
+"\n"
+"func _input_event(event):\n"
+" # Record keys.\n"
+" if event is InputEventKey and event.pressed and !event.echo:\n"
+" keys_typed.append(OS.get_keycode_string(event.keycode))\n"
+" # Quit on Escape press.\n"
+" if event.keycode == KEY_ESCAPE:\n"
+" quit = true\n"
+" # Quit on any mouse click.\n"
+" if event is InputEventMouseButton:\n"
+" quit = true\n"
+"\n"
+"func _finalize():\n"
+" print(\"Finalized:\")\n"
+" print(\" End time: %s\" % str(time_elapsed))\n"
+" print(\" Keys typed: %s\" % var2str(keys_typed))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/MainLoop.xml:51
+msgid "Called before the program exits."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:60
+msgid ""
+"Called each idle frame with the time since the last idle frame as argument "
+"(in seconds). Equivalent to [method Node._process].\n"
+"If implemented, the method must return a boolean value. [code]true[/code] "
+"ends the main loop, while [code]false[/code] lets it proceed to the next "
+"frame."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:68
+msgid "Called once during initialization."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:77
+msgid ""
+"Called each physics frame with the time since the last physics frame as "
+"argument (in seconds). Equivalent to [method Node._physics_process].\n"
+"If implemented, the method must return a boolean value. [code]true[/code] "
+"ends the main loop, while [code]false[/code] lets it proceed to the next "
+"frame."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:85
+msgid ""
+"Should not be called manually, override [method _finalize] instead. Will be "
+"removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:94
+msgid ""
+"Should not be called manually, override [method _idle] instead. Will be "
+"removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:101
+msgid ""
+"Should not be called manually, override [method _initialize] instead. Will "
+"be removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:110
+msgid ""
+"Should not be called manually, override [method _iteration] instead. Will be "
+"removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:121
+msgid "Emitted when a user responds to a permission request."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:127 doc/classes/Node.xml:945
+msgid ""
+"Notification received from the OS when the application is exceeding its "
+"allocated memory.\n"
+"Specific to the iOS platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:131 doc/classes/Node.xml:949
+msgid ""
+"Notification received when translations may have changed. Can be triggered "
+"by the user changing the locale. Can be used to respond to language changes, "
+"for example to change the UI strings on the fly. Useful when working with "
+"the built-in translation support, like [method Object.tr]."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:134 doc/classes/Node.xml:952
+msgid ""
+"Notification received from the OS when a request for \"About\" information "
+"is sent.\n"
+"Specific to the macOS platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:138 doc/classes/Node.xml:956
+msgid ""
+"Notification received from Godot's crash handler when the engine is about to "
+"crash.\n"
+"Implemented on desktop platforms if the crash handler is enabled."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:142 doc/classes/Node.xml:960
+msgid ""
+"Notification received from the OS when an update of the Input Method Engine "
+"occurs (e.g. change of IME cursor position or composition string).\n"
+"Specific to the macOS platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:146 doc/classes/Node.xml:964
+msgid ""
+"Notification received from the OS when the app is resumed.\n"
+"Specific to the Android platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:150 doc/classes/Node.xml:968
+msgid ""
+"Notification received from the OS when the app is paused.\n"
+"Specific to the Android platform."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:4
+msgid "Simple margin container."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:7
+msgid ""
+"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.\n"
+"[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:\n"
+"[codeblock]\n"
+"var margin_value = 100\n"
+"set(\"custom_constants/margin_top\", margin_value)\n"
+"set(\"custom_constants/margin_left\", margin_value)\n"
+"set(\"custom_constants/margin_bottom\", margin_value)\n"
+"set(\"custom_constants/margin_right\", margin_value)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:25
+msgid ""
+"All direct children of [MarginContainer] will have a bottom margin of "
+"[code]margin_bottom[/code] pixels."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:28
+msgid ""
+"All direct children of [MarginContainer] will have a left margin of "
+"[code]margin_left[/code] pixels."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:31
+msgid ""
+"All direct children of [MarginContainer] will have a right margin of "
+"[code]margin_right[/code] pixels."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:34
+msgid ""
+"All direct children of [MarginContainer] will have a top margin of "
+"[code]margin_top[/code] pixels."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:4
+msgid "Data transformation (marshalling) and encoding helpers."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:7
+msgid "Provides data transformation and encoding utility functions."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:18
+msgid ""
+"Returns a decoded [PackedByteArray] corresponding to the Base64-encoded "
+"string [code]base64_str[/code]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:27
+msgid ""
+"Returns a decoded string corresponding to the Base64-encoded string "
+"[code]base64_str[/code]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:38
+msgid ""
+"Returns a decoded [Variant] corresponding to the Base64-encoded string "
+"[code]base64_str[/code]. If [code]allow_objects[/code] is [code]true[/code], "
+"decoding objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:48
+msgid "Returns a Base64-encoded string of a given [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:57
+msgid ""
+"Returns a Base64-encoded string of the UTF-8 string [code]utf8_str[/code]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:68
+msgid ""
+"Returns a Base64-encoded string of the [Variant] [code]variant[/code]. If "
+"[code]full_objects[/code] is [code]true[/code], encoding objects is allowed "
+"(and can potentially include code)."
+msgstr ""
+
+#: doc/classes/Material.xml:4
+msgid "Abstract base [Resource] for coloring and shading geometry."
+msgstr ""
+
+#: doc/classes/Material.xml:7
+msgid ""
+"Material is a base [Resource] used for coloring and shading geometry. All "
+"materials inherit from it and almost all [VisualInstance3D] derived nodes "
+"carry a Material. A few flags and parameters are shared between all material "
+"types and are configured here."
+msgstr ""
+
+#: doc/classes/Material.xml:15
+msgid ""
+"Sets the [Material] to be used for the next pass. This renders the object "
+"again using a different material.\n"
+"[b]Note:[/b] only applies to [StandardMaterial3D]s and [ShaderMaterial]s "
+"with type \"Spatial\"."
+msgstr ""
+
+#: doc/classes/Material.xml:19
+msgid ""
+"Sets the render priority for transparent objects in 3D scenes. Higher "
+"priority objects will be sorted in front of lower priority objects.\n"
+"[b]Note:[/b] this only applies to sorting of transparent objects. This will "
+"not impact how transparent objects are sorted relative to opaque objects. "
+"This is because opaque objects are sorted based on depth, while transparent "
+"objects are sorted from back to front (subject to priority)."
+msgstr ""
+
+#: doc/classes/Material.xml:25
+msgid "Maximum value for the [member render_priority] parameter."
+msgstr ""
+
+#: doc/classes/Material.xml:28
+msgid "Minimum value for the [member render_priority] parameter."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:4
+msgid "Special button that brings up a [PopupMenu] when clicked."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:7
+msgid ""
+"Special button that brings up a [PopupMenu] when clicked.\n"
+"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."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:17 doc/classes/OptionButton.xml:106
+msgid "Returns the [PopupMenu] contained in this button."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:26
+msgid ""
+"If [code]true[/code], shortcuts are disabled and cannot be used to trigger "
+"the button."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:36
+msgid ""
+"If [code]true[/code], when the cursor hovers above another [MenuButton] "
+"within the same parent which also has [code]switch_on_hover[/code] enabled, "
+"it will close the current [MenuButton] and open the other one."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:43
+msgid "Emitted when the [PopupMenu] of this MenuButton is about to show."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:51
+msgid "[StyleBox] used when the [MenuButton] is disabled."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:54
+msgid ""
+"[StyleBox] used when the [MenuButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:57
+msgid "[Font] of the [MenuButton]'s text."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:60
+msgid "Default text [Color] of the [MenuButton]."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:63
+msgid "Text [Color] used when the [MenuButton] is disabled."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:66
+msgid "Text [Color] used when the [MenuButton] is being hovered."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:69
+msgid "Text [Color] used when the [MenuButton] is being pressed."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:72
+msgid "[StyleBox] used when the [MenuButton] is being hovered."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:75
+msgid "The horizontal space between [MenuButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:78
+msgid "Default [StyleBox] for the [MenuButton]."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:81
+msgid "[StyleBox] used when the [MenuButton] is being pressed."
+msgstr ""
+
+#: doc/classes/Mesh.xml:4
+msgid "A [Resource] that contains vertex array-based geometry."
+msgstr ""
+
+#: doc/classes/Mesh.xml:7
+msgid ""
+"Mesh is a type of [Resource] that contains vertex array-based geometry, "
+"divided in [i]surfaces[/i]. Each surface contains a completely separate "
+"array and a material used to draw it. Design wise, a mesh with multiple "
+"surfaces is preferred to a single surface, because objects created in 3D "
+"editing software commonly contain multiple materials."
+msgstr ""
+
+#: doc/classes/Mesh.xml:16
+msgid "Calculate a [ConvexPolygonShape3D] from the mesh."
+msgstr ""
+
+#: doc/classes/Mesh.xml:25
+msgid ""
+"Calculate an outline mesh at a defined offset (margin) from the original "
+"mesh.\n"
+"[b]Note:[/b] This method typically returns the vertices in reverse order (e."
+"g. clockwise to counterclockwise)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:33
+msgid "Calculate a [ConcavePolygonShape3D] from the mesh."
+msgstr ""
+
+#: doc/classes/Mesh.xml:40
+msgid "Generate a [TriangleMesh] from the mesh."
+msgstr ""
+
+#: doc/classes/Mesh.xml:47
+msgid ""
+"Returns the smallest [AABB] enclosing this mesh. Not affected by "
+"[code]custom_aabb[/code].\n"
+"[b]Note:[/b] This is only implemented for [ArrayMesh] and [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/Mesh.xml:55
+msgid ""
+"Returns all the vertices that make up the faces of the mesh. Each three "
+"vertices represent one triangle."
+msgstr ""
+
+#: doc/classes/Mesh.xml:62
+msgid "Returns the amount of surfaces that the [Mesh] holds."
+msgstr ""
+
+#: doc/classes/Mesh.xml:71
+msgid ""
+"Returns the arrays for the vertices, normals, uvs, etc. that make up the "
+"requested surface (see [method ArrayMesh.add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/Mesh.xml:80
+msgid "Returns the blend shape arrays for the requested surface."
+msgstr ""
+
+#: doc/classes/Mesh.xml:89
+msgid ""
+"Returns a [Material] in a given surface. Surface is rendered using this "
+"material."
+msgstr ""
+
+#: doc/classes/Mesh.xml:100
+msgid ""
+"Sets a [Material] for a given surface. Surface will be rendered using this "
+"material."
+msgstr ""
+
+#: doc/classes/Mesh.xml:106
+msgid "Sets a hint to be used for lightmap resolution."
+msgstr ""
+
+#: doc/classes/Mesh.xml:111
+msgid "Render array as points (one vertex equals one point)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:114
+msgid "Render array as lines (every two vertices a line is created)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:117
+msgid "Render array as line strip."
+msgstr ""
+
+#: doc/classes/Mesh.xml:120
+msgid "Render array as triangles (every three vertices a triangle is created)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:123
+msgid "Render array as triangle strips."
+msgstr ""
+
+#: doc/classes/Mesh.xml:126 doc/classes/RenderingServer.xml:3254
+msgid "Blend shapes are normalized."
+msgstr ""
+
+#: doc/classes/Mesh.xml:129 doc/classes/RenderingServer.xml:3257
+msgid "Blend shapes are relative to base weight."
+msgstr ""
+
+#: doc/classes/Mesh.xml:132
+msgid ""
+"Mesh array contains vertices. All meshes require a vertex array so this "
+"should always be present."
+msgstr ""
+
+#: doc/classes/Mesh.xml:135
+msgid "Mesh array contains normals."
+msgstr ""
+
+#: doc/classes/Mesh.xml:138
+msgid "Mesh array contains tangents."
+msgstr ""
+
+#: doc/classes/Mesh.xml:141
+msgid "Mesh array contains colors."
+msgstr ""
+
+#: doc/classes/Mesh.xml:144
+msgid "Mesh array contains UVs."
+msgstr ""
+
+#: doc/classes/Mesh.xml:147
+msgid "Mesh array contains second UV."
+msgstr ""
+
+#: doc/classes/Mesh.xml:150
+msgid "Mesh array contains bones."
+msgstr ""
+
+#: doc/classes/Mesh.xml:153
+msgid "Mesh array contains bone weights."
+msgstr ""
+
+#: doc/classes/Mesh.xml:156
+msgid "Mesh array uses indices."
+msgstr ""
+
+#: doc/classes/Mesh.xml:159 doc/classes/RenderingServer.xml:3210
+msgid "Flag used to mark a compressed (half float) normal array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:162 doc/classes/RenderingServer.xml:3213
+msgid "Flag used to mark a compressed (half float) tangent array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:165 doc/classes/RenderingServer.xml:3216
+msgid "Flag used to mark a compressed (half float) color array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:168 doc/classes/RenderingServer.xml:3219
+msgid "Flag used to mark a compressed (half float) UV coordinates array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:171 doc/classes/RenderingServer.xml:3222
+msgid ""
+"Flag used to mark a compressed (half float) UV coordinates array for the "
+"second UV coordinates."
+msgstr ""
+
+#: doc/classes/Mesh.xml:174 doc/classes/RenderingServer.xml:3225
+msgid "Flag used to mark a compressed index array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:177 doc/classes/RenderingServer.xml:3228
+msgid "Flag used to mark that the array contains 2D vertices."
+msgstr ""
+
+#: doc/classes/Mesh.xml:180 doc/classes/RenderingServer.xml:3233
+msgid ""
+"Used to set flags [constant ARRAY_COMPRESS_NORMAL], [constant "
+"ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant "
+"ARRAY_COMPRESS_TEX_UV] and [constant ARRAY_COMPRESS_TEX_UV2] quickly."
+msgstr ""
+
+#: doc/classes/Mesh.xml:183
+msgid "Array of vertices."
+msgstr ""
+
+#: doc/classes/Mesh.xml:186
+msgid "Array of normals."
+msgstr ""
+
+#: doc/classes/Mesh.xml:189
+msgid "Array of tangents as an array of floats, 4 floats per tangent."
+msgstr ""
+
+#: doc/classes/Mesh.xml:192
+msgid "Array of colors."
+msgstr ""
+
+#: doc/classes/Mesh.xml:195
+msgid "Array of UV coordinates."
+msgstr ""
+
+#: doc/classes/Mesh.xml:198
+msgid "Array of second set of UV coordinates."
+msgstr ""
+
+#: doc/classes/Mesh.xml:201
+msgid "Array of bone data."
+msgstr ""
+
+#: doc/classes/Mesh.xml:204
+msgid "Array of weights."
+msgstr ""
+
+#: doc/classes/Mesh.xml:207
+msgid "Array of indices."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:4
+msgid "Helper tool to access and edit [Mesh] data."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:7
+msgid ""
+"MeshDataTool provides access to individual vertices in a [Mesh]. It allows "
+"users to read and edit vertex data of meshes. It also creates an array of "
+"faces and edges.\n"
+"To use MeshDataTool, load a mesh with [method create_from_surface]. When you "
+"are finished editing the data commit the data to a mesh with [method "
+"commit_to_surface].\n"
+"Below is an example of how MeshDataTool may be used.\n"
+"[codeblock]\n"
+"var mdt = MeshDataTool.new()\n"
+"mdt.create_from_surface(mesh, 0)\n"
+"for i in range(mdt.get_vertex_count()):\n"
+" var vertex = mdt.get_vertex(i)\n"
+" ...\n"
+" mdt.set_vertex(i, vertex)\n"
+"mesh.surface_remove(0)\n"
+"mdt.commit_to_surface(mesh)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:28
+msgid "Clears all data currently in MeshDataTool."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:37
+msgid "Adds a new surface to specified [Mesh] with edited data."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:48
+msgid ""
+"Uses specified surface of given [Mesh] to populate data for MeshDataTool.\n"
+"Requires [Mesh] with primitive type [constant Mesh.PRIMITIVE_TRIANGLES]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:56
+msgid "Returns the number of edges in this [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:65
+msgid "Returns array of faces that touch given edge."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:74
+msgid "Returns meta information assigned to given edge."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:85
+msgid ""
+"Returns index of specified vertex connected to given edge.\n"
+"Vertex argument can only be 0 or 1 because edges are comprised of two "
+"vertices."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:93
+msgid "Returns the number of faces in this [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:104
+msgid ""
+"Returns specified edge associated with given face.\n"
+"Edge argument must 2 or less because a face only has three edges."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:114
+msgid "Returns the metadata associated with the given face."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:123
+msgid "Calculates and returns the face normal of the given face."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:134
+msgid ""
+"Returns the specified vertex of the given face.\n"
+"Vertex argument must be 2 or less because faces contain three vertices."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:142
+msgid ""
+"Returns the [Mesh]'s format. Format is an integer made up of [Mesh] format "
+"flags combined together. For example, a mesh containing both vertices and "
+"normals would return a format of [code]3[/code] because [constant ArrayMesh."
+"ARRAY_FORMAT_VERTEX] is [code]1[/code] and [constant ArrayMesh."
+"ARRAY_FORMAT_NORMAL] is [code]2[/code].\n"
+"See [enum ArrayMesh.ArrayFormat] for a list of format flags."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:150
+msgid "Returns the material assigned to the [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:159
+msgid "Returns the vertex at given index."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:168
+msgid "Returns the bones of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:177
+msgid "Returns the color of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:184
+msgid "Returns the total number of vertices in [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:193
+msgid "Returns an array of edges that share the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:202
+msgid "Returns an array of faces that share the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:211
+msgid "Returns the metadata associated with the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:220
+msgid "Returns the normal of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:229
+msgid "Returns the tangent of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:238
+msgid "Returns the UV of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:247
+msgid "Returns the UV2 of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:256
+msgid "Returns bone weights of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:267
+msgid "Sets the metadata of the given edge."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:278
+msgid "Sets the metadata of the given face."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:287
+msgid "Sets the material to be used by newly-constructed [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:298
+msgid "Sets the position of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:309
+msgid "Sets the bones of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:320
+msgid "Sets the color of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:331
+msgid "Sets the metadata associated with the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:342
+msgid "Sets the normal of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:353
+msgid "Sets the tangent of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:364
+msgid "Sets the UV of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:375
+msgid "Sets the UV2 of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:386
+msgid "Sets the bone weights of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:4
+msgid "Node used for displaying a [Mesh] in 2D."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:7
+msgid ""
+"Node used for displaying a [Mesh] in 2D. Can be constructed from an existing "
+"[Sprite2D] via a tool in the editor toolbar. Select \"Sprite2D\" then "
+"\"Convert to Mesh2D\", select settings in popup and press \"Create Mesh2D\"."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/2d_meshes.html"
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:16
+msgid "The [Mesh] that will be drawn by the [MeshInstance2D]."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:19 doc/classes/MultiMeshInstance2D.xml:19
+msgid ""
+"The normal map that will be used if using the default [CanvasItemMaterial]."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:22 doc/classes/MultiMeshInstance2D.xml:22
+msgid ""
+"The [Texture2D] that will be used if using the default [CanvasItemMaterial]. "
+"Can be accessed as [code]TEXTURE[/code] in CanvasItem shader."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:28 doc/classes/MultiMeshInstance2D.xml:28
+msgid "Emitted when the [member texture] is changed."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:4
+msgid "Node that instances meshes into a scenario."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:7
+msgid ""
+"MeshInstance3D is a node that takes a [Mesh] resource and adds it to the "
+"current scenario by creating an instance of it. This is the class most often "
+"used render 3D geometry and can be used to instance a single [Mesh] in many "
+"places. This allows reuse of geometry which can save on resources. When a "
+"[Mesh] has to be instanced more than thousands of times at close proximity, "
+"consider using a [MultiMesh] in a [MultiMeshInstance3D] instead."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:16
+msgid ""
+"This helper creates a [StaticBody3D] child node with a "
+"[ConvexPolygonShape3D] collision shape calculated from the mesh geometry. "
+"It's mainly used for testing."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:23
+msgid ""
+"This helper creates a [MeshInstance3D] child node with gizmos at every "
+"vertex calculated from the mesh geometry. It's mainly used for testing."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:30
+msgid ""
+"This helper creates a [StaticBody3D] child node with a "
+"[ConcavePolygonShape3D] collision shape calculated from the mesh geometry. "
+"It's mainly used for testing."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:39
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:48
+msgid ""
+"Returns the override [Material] for the specified surface of the [Mesh] "
+"resource."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:55
+msgid "Returns the number of surface materials."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:66
+msgid ""
+"Sets the override [Material] for the specified surface of the [Mesh] "
+"resource. This material is associated with this [MeshInstance3D] rather than "
+"with the [Mesh] resource."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:72
+msgid "The [Mesh] resource for the instance."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:75
+msgid "[NodePath] to the [Skeleton3D] associated with the instance."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:78
+msgid "Sets the skin to be used by this instance."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:4
+msgid "Library of meshes."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:7
+msgid ""
+"A library of meshes. Contains a list of [Mesh] resources, each with a name "
+"and ID. Each item can also include collision and navigation shapes. This "
+"resource is used in [GridMap]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:16
+msgid "Clears the library."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:25
+msgid ""
+"Creates a new item in the library with the given ID.\n"
+"You can get an unused ID from [method get_last_unused_item_id]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:35
+msgid "Returns the first item with the given name."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:42
+msgid "Returns the list of item IDs in use."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:51
+msgid "Returns the item's mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:60
+msgid "Returns the item's name."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:69
+msgid "Returns the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:78
+msgid "Returns the transform applied to the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:87
+msgid ""
+"When running in the editor, returns a generated item preview (a 3D rendering "
+"in isometric perspective). When used in a running project, returns the "
+"manually-defined item preview which can be set using [method "
+"set_item_preview]. Returns an empty [Texture2D] if no preview was manually "
+"set in a running project."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:96
+msgid ""
+"Returns an item's collision shapes.\n"
+"The array consists of each [Shape3D] followed by its [Transform]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:104
+msgid "Gets an unused ID for a new item."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:113
+msgid "Removes the item."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:124
+msgid "Sets the item's mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:135
+msgid ""
+"Sets the item's name.\n"
+"This name is shown in the editor. It can also be used to look up the item "
+"later using [method find_item_by_name]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:147
+msgid "Sets the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:158
+msgid "Sets the transform to apply to the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:169
+msgid "Sets a texture to use as the item's preview icon in the editor."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:180
+msgid ""
+"Sets an item's collision shapes.\n"
+"The array should consist of [Shape3D] objects, each followed by a "
+"[Transform] that will be applied to it. For shapes that should not have a "
+"transform, use [constant Transform.IDENTITY]."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:4
+msgid "Simple texture that uses a mesh to draw itself."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:7
+msgid ""
+"Simple texture that uses a mesh to draw itself. It's limited because flags "
+"can't be changed and region drawing is not supported."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:15
+msgid "Sets the base texture that the Mesh will use to draw."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:18
+msgid "Sets the size of the image, needed for reference."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:21
+msgid "Sets the mesh used to draw. It must be a mesh using 2D vertices."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:4
+msgid "Generic mobile VR implementation."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:7
+msgid ""
+"This is a generic mobile VR implementation where you need to provide details "
+"about the phone and HMD used. It does not rely on any existing framework. "
+"This is the most basic interface we have. For the best effect, you need a "
+"mobile phone with a gyroscope and accelerometer.\n"
+"Note that even though there is no positional tracking, the camera will "
+"assume the headset is at a height of 1.85 meters. You can change this by "
+"setting [member eye_height].\n"
+"You can initialise this interface as follows:\n"
+"[codeblock]\n"
+"var interface = ARVRServer.find_interface(\"Native mobile\")\n"
+"if interface and interface.initialize():\n"
+" get_viewport().arvr = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:22
+msgid ""
+"The distance between the display and the lenses inside of the device in "
+"centimeters."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:25
+msgid "The width of the display in centimeters."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:28
+msgid ""
+"The height at which the camera is placed in relation to the ground (i.e. "
+"[ARVROrigin] node)."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:31
+msgid ""
+"The interocular distance, also known as the interpupillary distance. The "
+"distance between the pupils of the left and right eye."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:34
+msgid ""
+"The k1 lens factor is one of the two constants that define the strength of "
+"the lens used and directly influences the lens distortion effect."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:37
+msgid "The k2 lens factor, see k1."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:40
+msgid ""
+"The oversample setting. Because of the lens distortion we have to render our "
+"buffers at a higher resolution then the screen can natively handle. A value "
+"between 1.5 and 2.0 often provides good results but at the cost of "
+"performance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:4
+msgid "Provides high-performance mesh instancing."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:7
+msgid ""
+"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.\n"
+"MultiMesh is much faster as it can draw thousands of instances with a single "
+"draw call, resulting in less API overhead.\n"
+"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).\n"
+"Since instances may have any behavior, the AABB used for visibility must be "
+"provided by the user."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:13 doc/classes/MultiMeshInstance3D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/"
+"animating_thousands_of_fish.html"
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:14 doc/classes/MultiMeshInstance3D.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/optimization/"
+"using_multimesh.html"
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:21
+msgid "Returns the visibility axis-aligned bounding box."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:30
+msgid "Gets a specific instance's color."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:39
+msgid "Returns the custom data that has been set for a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:48
+msgid "Returns the [Transform] of a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:57
+msgid "Returns the [Transform2D] of a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:68
+msgid ""
+"Sets the color of a specific instance.\n"
+"For the color to take effect, ensure that [member use_colors] is [code]true[/"
+"code] on the [MultiMesh] and [member BaseMaterial3D."
+"vertex_color_use_as_albedo] is [code]true[/code] on the material."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:80
+msgid ""
+"Sets custom data for a specific instance. Although [Color] is used, it is "
+"just a container for 4 floating point numbers.\n"
+"For the custom data to be used, ensure that [member use_custom_data] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:92
+msgid "Sets the [Transform] for a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:103
+msgid "Sets the [Transform2D] for a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:115
+msgid ""
+"Number of instances that will get drawn. This clears and (re)sizes the "
+"buffers. By default, all instances are drawn but you can limit this with "
+"[member visible_instance_count]."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:118
+msgid "Mesh to be drawn."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:125
+msgid "Format of transform used to transform mesh, either 2D or 3D."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:128
+msgid ""
+"If [code]true[/code], the [MultiMesh] will use color data (see [member "
+"color_array])."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:131
+msgid ""
+"If [code]true[/code], the [MultiMesh] will use custom data (see [member "
+"custom_data_array])."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:134
+msgid ""
+"Limits the number of instances drawn, -1 draws all instances. Changing this "
+"does not change the sizes of the buffers."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:139
+msgid "Use this when using 2D transforms."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:142
+msgid "Use this when using 3D transforms."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance2D.xml:4
+msgid "Node that instances a [MultiMesh] in 2D."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance2D.xml:7
+msgid ""
+"[MultiMeshInstance2D] is a specialized node to instance a [MultiMesh] "
+"resource in 2D.\n"
+"Usage is the same as [MultiMeshInstance3D]."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance2D.xml:16
+msgid "The [MultiMesh] that will be drawn by the [MultiMeshInstance2D]."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:4
+msgid "Node that instances a [MultiMesh]."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:7
+msgid ""
+"[MultiMeshInstance3D] is a specialized node to instance "
+"[GeometryInstance3D]s based on a [MultiMesh] resource.\n"
+"This is useful to optimize the rendering of a high amount of instances of a "
+"given mesh (for example trees in a forest or grass strands)."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/"
+"using_multi_mesh_instance.html"
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:19
+msgid ""
+"The [MultiMesh] resource that will be used and shared among all instances of "
+"the [MultiMeshInstance3D]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:4
+msgid "High-level multiplayer API."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:7
+msgid ""
+"This class implements most of the logic behind the high-level multiplayer "
+"API.\n"
+"By default, [SceneTree] has a reference to this class that is used to "
+"provide multiplayer capabilities (i.e. RPC/RSET) across the whole scene.\n"
+"It is possible to override the MultiplayerAPI instance used by specific "
+"Nodes by setting the [member Node.custom_multiplayer] property, effectively "
+"allowing to run both client and server in the same scene."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:18
+msgid ""
+"Clears the current MultiplayerAPI network state (you shouldn't call this "
+"unless you know what you are doing)."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:25
+msgid ""
+"Returns the peer IDs of all connected peers of this MultiplayerAPI's [member "
+"network_peer]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:32
+msgid ""
+"Returns the unique peer ID of this MultiplayerAPI's [member network_peer]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:39
+msgid ""
+"Returns the sender's peer ID for the RPC currently being executed.\n"
+"[b]Note:[/b] If not inside an RPC this method will return 0."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:47 doc/classes/SceneTree.xml:135
+msgid "Returns [code]true[/code] if there is a [member network_peer] set."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:54
+msgid ""
+"Returns [code]true[/code] if this MultiplayerAPI's [member network_peer] is "
+"in server mode (listening for connections)."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:61
+msgid ""
+"Method used for polling the MultiplayerAPI. You only need to worry about "
+"this if you are using [member Node.custom_multiplayer] override or you set "
+"[member SceneTree.multiplayer_poll] to [code]false[/code]. By default, "
+"[SceneTree] will poll its MultiplayerAPI for you.\n"
+"[b]Note:[/b] This method results in RPCs and RSETs being called, so they "
+"will be executed in the same context of this function (e.g. [code]_process[/"
+"code], [code]physics[/code], [Thread])."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:75
+msgid ""
+"Sends the given raw [code]bytes[/code] to a specific peer identified by "
+"[code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). "
+"Default ID is [code]0[/code], i.e. broadcast to all peers."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:84
+msgid ""
+"Sets the base root node to use for RPCs. Instead of an absolute path, a "
+"relative path will be used to find the node upon which the RPC should be "
+"executed.\n"
+"This effectively allows to have different branches of the scene tree to be "
+"managed by different MultiplayerAPI, allowing for example to run both client "
+"and server in the same scene."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:91
+msgid ""
+"If [code]true[/code], the MultiplayerAPI will allow encoding and decoding of "
+"object during RPCs/RSETs.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:95
+msgid ""
+"The peer object to handle the RPC system (effectively enabling networking "
+"when set). Depending on the peer itself, the MultiplayerAPI will become a "
+"network server (check with [method is_network_server]) and will set root "
+"node's network mode to master, or it will become a regular peer with root "
+"node set to puppet. All child nodes are set to inherit the network mode by "
+"default. Handling of networking-related events (connection, disconnection, "
+"new clients) is done by connecting to MultiplayerAPI's signals."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:98
+msgid ""
+"If [code]true[/code], the MultiplayerAPI's [member network_peer] refuses new "
+"incoming connections."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:104
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] successfully "
+"connected to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:109
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] fails to establish "
+"a connection to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:116
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] connects with a new "
+"peer. ID is the peer ID of the new peer. Clients get notified when other "
+"clients connect to the same server. Upon connecting to a server, a client "
+"also receives this signal for the server (with ID being 1)."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:123
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] disconnects from a "
+"peer. Clients get notified when other clients disconnect from the same "
+"server."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:132
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] receive a "
+"[code]packet[/code] with custom data (see [method send_bytes]). ID is the "
+"peer ID of the peer that sent the packet."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:137
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] disconnects from "
+"server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:143
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to disable a "
+"method or property for all RPC calls, making it unavailable. Default for all "
+"methods."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:146
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to set a "
+"method to be called or a property to be changed only on the remote end, not "
+"locally. Analogous to the [code]remote[/code] keyword. Calls and property "
+"changes are accepted from all remote peers, no matter if they are node's "
+"master or puppets."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:149
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to set a "
+"method to be called or a property to be changed only on the network master "
+"for this node. Analogous to the [code]master[/code] keyword. Only accepts "
+"calls or property changes from the node's network puppets, see [method Node."
+"set_network_master]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:152
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to set a "
+"method to be called or a property to be changed only on puppets for this "
+"node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or "
+"property changes from the node's network master, see [method Node."
+"set_network_master]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:155
+msgid ""
+"Behave like [constant RPC_MODE_REMOTE] but also make the call or property "
+"change locally. Analogous to the [code]remotesync[/code] keyword."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:158
+msgid ""
+"Behave like [constant RPC_MODE_MASTER] but also make the call or property "
+"change locally. Analogous to the [code]mastersync[/code] keyword."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:161
+msgid ""
+"Behave like [constant RPC_MODE_PUPPET] but also make the call or property "
+"change locally. Analogous to the [code]puppetsync[/code] keyword."
+msgstr ""
+
+#: doc/classes/Mutex.xml:4
+msgid "A synchronization mutex (mutual exclusion)."
+msgstr ""
+
+#: doc/classes/Mutex.xml:7
+msgid ""
+"A synchronization mutex (mutual exclusion). This is used to synchronize "
+"multiple [Thread]s, and is equivalent to a binary [Semaphore]. It guarantees "
+"that only one thread can ever acquire the lock at a time. A mutex can be "
+"used to protect a critical section; however, be careful to avoid deadlocks."
+msgstr ""
+
+#: doc/classes/Mutex.xml:10 doc/classes/Semaphore.xml:10
+#: doc/classes/Thread.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/threads/"
+"using_multiple_threads.html"
+msgstr ""
+
+#: doc/classes/Mutex.xml:17
+msgid "Locks this [Mutex], blocks until it is unlocked by the current owner."
+msgstr ""
+
+#: doc/classes/Mutex.xml:24
+msgid ""
+"Tries locking this [Mutex], but does not block. Returns [constant OK] on "
+"success, [constant ERR_BUSY] otherwise."
+msgstr ""
+
+#: doc/classes/Mutex.xml:31
+msgid "Unlocks this [Mutex], leaving it to other threads."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:14
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_class_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:23
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_method_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:32
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_property_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:41
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_signal_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:48
+msgid ""
+"Constructs a new object of the base type with a script of this type already "
+"attached.\n"
+"[i]Note[/i]: Any arguments passed to this function will be ignored and not "
+"passed to the native constructor function. This will change with in a future "
+"API extension."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:4
+msgid "2D navigation and pathfinding node."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:7
+msgid ""
+"Navigation2D provides navigation and pathfinding within a 2D area, specified "
+"as a collection of [NavigationPolygon] resources. These are automatically "
+"collected from child [NavigationRegion2D] nodes."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:18 doc/classes/Navigation3D.xml:18
+#: doc/classes/NavigationServer2D.xml:175
+msgid ""
+"Returns the point closest to the provided [code]to_point[/code] on the "
+"navigation mesh surface."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:27 doc/classes/Navigation3D.xml:36
+msgid ""
+"Returns the owner region RID for the point returned by [method "
+"get_closest_point]."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:46
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:4
+msgid "Mesh-based navigation and pathfinding node."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:27
+msgid ""
+"Returns the normal for the point returned by [method get_closest_point]."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:49 doc/classes/NavigationServer3D.xml:212
+msgid ""
+"Returns the closest point between the navigation surface and the segment."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:68
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:78
+msgid ""
+"Defines which direction is up. By default, this is [code](0, 1, 0)[/code], "
+"which is the world's \"up\" direction."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:4
+msgid "2D Agent used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:7
+msgid ""
+"2D Agent that is used in navigation to reach a location while avoiding "
+"static and dynamic obstacles. The dynamic obstacles are avoided using RVO "
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:16 doc/classes/NavigationAgent3D.xml:16
+msgid ""
+"Returns the distance to the target location, using the agent's global "
+"position. The user must set the target location with [method "
+"set_target_location] in order for this to be accurate."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:23
+msgid ""
+"Returns the reachable final location in global coordinates. This can change "
+"if the navigation path is altered in any way."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:30 doc/classes/NavigationAgent3D.xml:30
+msgid "Returns the path from start to finish in global coordinates."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:37
+msgid ""
+"Returns which index the agent is currently on in the navigation path's "
+"[PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:44
+msgid ""
+"Returns the [Navigation2D] node that the agent is using for its navigation "
+"system."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:51
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:58
+msgid "Returns the user defined [Vector2] after setting the target location."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:65 doc/classes/NavigationAgent3D.xml:65
+msgid "Returns true if the navigation path's final location has been reached."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:72 doc/classes/NavigationAgent3D.xml:72
+msgid ""
+"Returns true if the target location is reachable. The target location is set "
+"using [method set_target_location]."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:79 doc/classes/NavigationAgent3D.xml:79
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:88
+msgid ""
+"Sets the [Navigation2D] node used by the agent. Useful when you don't want "
+"to make the agent a child of a [Navigation2D] node."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:97 doc/classes/NavigationAgent3D.xml:97
+msgid ""
+"Sets the user desired final location. This will clear the current navigation "
+"path."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:106 doc/classes/NavigationAgent3D.xml:106
+msgid ""
+"Sends the passed in velocity to the collision avoidance algorithm. It will "
+"adjust the velocity to avoid collisions. Once the adjustment to the velocity "
+"is complete, it will emit the [signal velocity_computed] signal."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:112 doc/classes/NavigationAgent3D.xml:118
+msgid "The maximum number of neighbors for the agent to consider."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:115 doc/classes/NavigationAgent3D.xml:121
+msgid "The maximum speed that an agent can move."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:118 doc/classes/NavigationAgent3D.xml:124
+msgid "The distance to search for other agents."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:121 doc/classes/NavigationAgent3D.xml:127
+msgid ""
+"The maximum distance the agent is allowed away from the ideal path to the "
+"final location. This can happen due to trying to avoid collisions. When the "
+"maximum distance is exceeded, it recalculates the ideal path."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:124 doc/classes/NavigationAgent3D.xml:130
+msgid "The radius of the agent."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:127 doc/classes/NavigationAgent3D.xml:133
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:130 doc/classes/NavigationAgent3D.xml:136
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:136 doc/classes/NavigationAgent3D.xml:142
+msgid "Notifies when the final location is reached."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:141 doc/classes/NavigationAgent3D.xml:147
+msgid "Notifies when the navigation path changes."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:146 doc/classes/NavigationAgent3D.xml:152
+msgid ""
+"Notifies when the player defined target, set with [method "
+"set_target_location], is reached."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:153 doc/classes/NavigationAgent3D.xml:159
+msgid ""
+"Notifies when the collision avoidance velocity is calculated. Emitted by "
+"[method set_velocity]."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:4
+msgid "3D Agent used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:7
+msgid ""
+"3D Agent that is used in navigation to reach a location while avoiding "
+"static and dynamic obstacles. The dynamic obstacles are avoided using RVO "
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:23
+msgid ""
+"Returns the reachable final location in global coordinates. This can change "
+"if the navigation path is altered in any way. Because of this, it would be "
+"best to check this each frame."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:37
+msgid ""
+"Returns which index the agent is currently on in the navigation path's "
+"[PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:44
+msgid ""
+"Returns the [Navigation3D] node that the agent is using for its navigation "
+"system."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:51
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:58
+msgid "Returns the user defined [Vector3] after setting the target location."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:88
+msgid ""
+"Sets the [Navigation3D] node used by the agent. Useful when you don't want "
+"to make the agent a child of a [Navigation3D] node."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:112
+msgid "The agent height offset to match the navigation mesh height."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:115
+msgid ""
+"Ignores collisions on the Y axis. Must be true to move on a horizontal plane."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:4
+msgid "2D Obstacle used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:16
+msgid ""
+"Returns the [Navigation2D] node that the obstacle is using for its "
+"navigation system."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:25
+msgid ""
+"Sets the [Navigation2D] node used by the obstacle. Useful when you don't "
+"want to make the obstacle a child of a [Navigation2D] node."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:4
+msgid "3D Obstacle used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:16
+msgid ""
+"Returns the [Navigation3D] node that the obstacle is using for its "
+"navigation system."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:25
+msgid ""
+"Sets the [Navigation3D] node used by the obstacle. Useful when you don't "
+"want to make the obstacle a child of a [Navigation3D] node."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:4
+msgid ""
+"A node that has methods to draw outlines or use indices of vertices to "
+"create navigation polygons."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:7
+msgid ""
+"There are two ways to create polygons. Either by using the [method "
+"add_outline] method, or using the [method add_polygon] method.\n"
+"Using [method add_outline]:\n"
+"[codeblock]\n"
+"var polygon = NavigationPolygon.new()\n"
+"var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, "
+"50), Vector2(50, 0)])\n"
+"polygon.add_outline(outline)\n"
+"polygon.make_polygons_from_outlines()\n"
+"$NavigationRegion2D.navpoly = polygon\n"
+"[/codeblock]\n"
+"Using [method add_polygon] and indices of the vertices array.\n"
+"[codeblock]\n"
+"var polygon = NavigationPolygon.new()\n"
+"var vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), "
+"Vector2(50, 50), Vector2(50, 0)])\n"
+"polygon.set_vertices(vertices)\n"
+"var indices = PackedInt32Array(0, 3, 1)\n"
+"polygon.add_polygon(indices)\n"
+"$NavigationRegion2D.navpoly = polygon\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:35
+msgid ""
+"Appends a [PackedVector2Array] that contains the vertices of an outline to "
+"the internal array that contains all the outlines. You have to call [method "
+"make_polygons_from_outlines] in order for this array to be converted to "
+"polygons that the engine will use."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:46
+msgid ""
+"Adds a [PackedVector2Array] that contains the vertices of an outline to the "
+"internal array that contains all the outlines at a fixed position. You have "
+"to call [method make_polygons_from_outlines] in order for this array to be "
+"converted to polygons that the engine will use."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:55
+msgid ""
+"Adds a polygon using the indices of the vertices you get when calling "
+"[method get_vertices]."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:62
+msgid ""
+"Clears the array of the outlines, but it doesn't clear the vertices and the "
+"polygons that were created by them."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:69
+msgid ""
+"Clears the array of polygons, but it doesn't clear the array of outlines and "
+"vertices."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:78
+msgid ""
+"Returns a [PackedVector2Array] containing the vertices of an outline that "
+"was created in the editor or by script."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:85
+msgid ""
+"Returns the number of outlines that were created in the editor or by script."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:94
+msgid ""
+"Returns a [PackedInt32Array] containing the indices of the vertices of a "
+"created polygon."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:101
+msgid "Returns the count of all polygons."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:108
+msgid ""
+"Returns a [PackedVector2Array] containing all the vertices being used to "
+"create the polygons."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:115
+msgid "Creates polygons from the outlines added in the editor or by script."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:124
+msgid ""
+"Removes an outline created in the editor or by script. You have to call "
+"[method make_polygons_from_outlines] for the polygons to update."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:135
+msgid ""
+"Changes an outline created in the editor or by script. You have to call "
+"[method make_polygons_from_outlines] for the polygons to update."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:144
+msgid ""
+"Sets the vertices that can be then indexed to create polygons with the "
+"[method add_polygon] method."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:4
+msgid "A region of the navigation map."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:7
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:16
+msgid ""
+"Bakes the [NavigationMesh]. The baking is done in a separate thread because "
+"navigation baking is not a cheap operation. This can be done at runtime. "
+"When it is completed, it automatically sets the new [NavigationMesh]."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:22
+msgid "Determines if the [NavigationRegion3D] is enabled or disabled."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:25
+msgid "The [NavigationMesh] resource to use."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:31
+msgid "Notifies when the navigation mesh bake operation is completed."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:36
+msgid "Notifies when the [NavigationMesh] has changed."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:4
+msgid "Server interface for low-level 2D navigation access"
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:16 doc/classes/NavigationServer3D.xml:16
+msgid "Creates the agent."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:25 doc/classes/NavigationServer3D.xml:25
+msgid "Returns true if the map got changed the previous frame."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:40 doc/classes/NavigationServer3D.xml:40
+msgid "Callback called at the end of the RVO process."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:51 doc/classes/NavigationServer3D.xml:51
+msgid "Puts the agent in the map."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:62 doc/classes/NavigationServer3D.xml:62
+msgid ""
+"Sets the maximum number of other agents the agent takes into account in the "
+"navigation. The larger this number, the longer the running time of the "
+"simulation. If the number is too low, the simulation will not be safe."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:73 doc/classes/NavigationServer3D.xml:73
+msgid "Sets the maximum speed of the agent. Must be positive."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:84 doc/classes/NavigationServer3D.xml:84
+msgid ""
+"Sets the maximum distance to other agents this agent takes into account in "
+"the navigation. The larger this number, the longer the running time of the "
+"simulation. If the number is too low, the simulation will not be safe."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:95 doc/classes/NavigationServer3D.xml:95
+msgid "Sets the position of the agent in world space."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:106
+#: doc/classes/NavigationServer3D.xml:106
+msgid "Sets the radius of the agent."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:117
+#: doc/classes/NavigationServer3D.xml:117
+msgid "Sets the new target velocity."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:128
+#: doc/classes/NavigationServer3D.xml:128
+msgid ""
+"The minimal amount of time for which the agent's velocities that are "
+"computed by the simulation are safe with respect to other agents. The larger "
+"this number, the sooner this agent will respond to the presence of other "
+"agents, but the less freedom this agent has in choosing its velocities. Must "
+"be positive."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:139
+#: doc/classes/NavigationServer3D.xml:139
+msgid "Sets the current velocity of the agent."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:148
+#: doc/classes/NavigationServer3D.xml:148
+msgid "Destroy the RID"
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:155
+#: doc/classes/NavigationServer3D.xml:155
+msgid "Create a new map."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:164
+#: doc/classes/NavigationServer3D.xml:164
+msgid "Returns the map cell size."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:186
+#: doc/classes/NavigationServer3D.xml:197
+msgid ""
+"Returns the owner region RID for the point returned by [method "
+"map_get_closest_point]."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:195
+msgid ""
+"Returns the edge connection margin of the map. The edge connection margin is "
+"a distance used to connect two regions."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:210
+msgid ""
+"Returns the navigation path to reach the destination from the origin, while "
+"avoiding static obstacles."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:219
+#: doc/classes/NavigationServer3D.xml:254
+msgid "Returns true if the map is active."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:230
+#: doc/classes/NavigationServer3D.xml:265
+msgid "Sets the map active."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:241
+#: doc/classes/NavigationServer3D.xml:276
+msgid "Set the map cell size used to weld the navigation mesh polygons."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:252
+msgid ""
+"Set the map edge connection margin used to weld the compatible region edges."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:259
+#: doc/classes/NavigationServer3D.xml:327
+msgid "Creates a new region."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:270
+#: doc/classes/NavigationServer3D.xml:338
+msgid "Sets the map for the region."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:281
+#: doc/classes/NavigationServer3D.xml:349
+msgid "Sets the navigation mesh for the region."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:292
+#: doc/classes/NavigationServer3D.xml:360
+msgid "Sets the global transformation for the region."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:4
+msgid "Server interface for low-level 3D navigation access"
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:175
+msgid ""
+"Returns the point closest to the provided [code]point[/code] on the "
+"navigation mesh surface."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:186
+msgid ""
+"Returns the normal for the point returned by [method map_get_closest_point]."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:221
+msgid "Returns the edge connection margin of the map."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:236
+msgid "Returns the navigation path to reach the destination from the origin."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:245
+msgid "Returns the map's up direction."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:287
+msgid ""
+"Set the map edge connection margein used to weld the compatible region edges."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:298
+msgid "Sets the map up direction."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:307
+msgid ""
+"Process the collision avoidance agents.\n"
+"The result of this process is needed by the physics server, so this must be "
+"called in the main thread.\n"
+"Note: This function is not thread safe."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:320
+msgid "Bakes the navigation mesh."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:369
+msgid "Control activation of this server."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:4
+msgid ""
+"PacketPeer implementation using the [url=http://enet.bespin.org/index."
+"html]ENet[/url] library."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:7
+msgid ""
+"A PacketPeer implementation that should be passed to [member SceneTree."
+"network_peer] after being initialized as either a client or server. Events "
+"can then be handled by connecting to [SceneTree] signals."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:10
+#: doc/classes/NetworkedMultiplayerPeer.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/"
+"high_level_multiplayer.html"
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:11
+msgid "http://enet.bespin.org/usergroup0.html"
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:20
+msgid ""
+"Closes the connection. Ignored if no connection is currently established. If "
+"this is a server it tries to notify all clients before forcibly "
+"disconnecting them. If this is a client it simply closes the connection to "
+"the server."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:37
+msgid ""
+"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."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:52
+msgid ""
+"Create server that listens to connections via [code]port[/code]. The port "
+"needs to be an available, unused port between 0 and 65535. Note that ports "
+"below 1024 are privileged and may require elevated permissions depending on "
+"the platform. To change the interface the server listens on, use [method "
+"set_bind_ip]. The default IP is the wildcard [code]\"*\"[/code], which "
+"listens on all available interfaces. [code]max_clients[/code] is the maximum "
+"number of clients that are allowed at once, any number up to 4095 may be "
+"used, although the achievable number of simultaneous clients may be far "
+"lower and depends on the application. For additional details on the "
+"bandwidth parameters, see [method create_client]. Returns [constant OK] if a "
+"server 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 server could not be created."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:63
+msgid ""
+"Disconnect the given peer. If \"now\" is set to [code]true[/code], the "
+"connection will be closed immediately without flushing queued messages."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:70
+msgid ""
+"Returns the channel of the last packet fetched via [method PacketPeer."
+"get_packet]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:77
+msgid ""
+"Returns the channel of the next packet that will be retrieved via [method "
+"PacketPeer.get_packet]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:86
+#: modules/websocket/doc_classes/WebSocketServer.xml:33
+msgid "Returns the IP address of the given peer."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:95
+#: modules/websocket/doc_classes/WebSocketServer.xml:42
+msgid "Returns the remote port of the given peer."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:104
+msgid ""
+"The IP used when creating a server. This is set to the wildcard [code]\"*\"[/"
+"code] by default, which binds to all available interfaces. The given IP "
+"needs to be in IPv4 or IPv6 address format, for example: "
+"[code]\"192.168.1.1\"[/code]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:113
+msgid ""
+"Configure the [X509Certificate] to use when [member use_dtls] is [code]true[/"
+"code]. For servers, you must also setup the [CryptoKey] via [method "
+"set_dtls_key]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:122
+msgid ""
+"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]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:128
+msgid ""
+"Enforce ordered packets when using [constant NetworkedMultiplayerPeer."
+"TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant "
+"NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the "
+"only way to use ordering with the RPC system."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:131
+msgid ""
+"The number of channels to be used by ENet. Channels are used to separate "
+"different kinds of data. In reliable or ordered mode, for example, the "
+"packet delivery order is ensured on a per channel basis."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:134
+msgid ""
+"The compression method used for network packets. These have different "
+"tradeoffs of compression speed versus bandwidth, you may need to test which "
+"one works best for your use case if you use compression at all."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:137
+msgid ""
+"Enable or disable certificate verification when [member use_dtls] "
+"[code]true[/code]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:141
+msgid ""
+"Enable or disable the server feature that notifies clients of other peers' "
+"connection/disconnection, and relays messages between them. When this option "
+"is [code]false[/code], clients won't be automatically notified of other "
+"peers and won't be able to send them packets through the server."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:144
+msgid ""
+"Set the default channel to be used to transfer data. By default, this value "
+"is [code]-1[/code] which means that ENet will only use 2 channels, one for "
+"reliable and one for unreliable packets. Channel [code]0[/code] is reserved, "
+"and cannot be used. Setting this member to any value between [code]0[/code] "
+"and [member channel_count] (excluded) will force ENet to use that channel "
+"for sending data."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:148
+msgid ""
+"When enabled, the client or server created by this peer, will use "
+"[PacketPeerDTLS] instead of raw UDP sockets for communicating with the "
+"remote peer. This will make the communication encrypted with DTLS at the "
+"cost of higher resource usage and potentially larger packet size.\n"
+"Note: When creating a DTLS server, make sure you setup the key/certificate "
+"pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS "
+"clients, have a look at the [member dtls_verify] option, and configure the "
+"certificate accordingly via [method set_dtls_certificate]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:154
+msgid ""
+"No compression. This uses the most bandwidth, but has the upside of "
+"requiring the fewest CPU resources."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:157
+msgid "ENet's built-in range encoding."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:160
+msgid ""
+"[url=http://fastlz.org/]FastLZ[/url] compression. This option uses less CPU "
+"resources compared to [constant COMPRESS_ZLIB], at the expense of using more "
+"bandwidth."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:163
+msgid ""
+"[url=https://www.zlib.net/]Zlib[/url] compression. This option uses less "
+"bandwidth compared to [constant COMPRESS_FASTLZ], at the expense of using "
+"more CPU resources."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:166
+msgid "[url=https://facebook.github.io/zstd/]Zstandard[/url] compression."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:4
+msgid "A high-level network interface to simplify multiplayer interactions."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:7
+msgid ""
+"Manages the connection to network peers. Assigns unique IDs to each client "
+"connected to the server."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:17
+msgid ""
+"Returns the current state of the connection. See [enum ConnectionStatus]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:24
+msgid ""
+"Returns the ID of the [NetworkedMultiplayerPeer] who sent the most recent "
+"packet."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:31
+msgid "Returns the ID of this [NetworkedMultiplayerPeer]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:38
+msgid "Waits up to 1 second to receive a new network event."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:47
+msgid ""
+"Sets the peer to which packets will be sent.\n"
+"The [code]id[/code] can be one of: [constant TARGET_PEER_BROADCAST] to send "
+"to all connected peers, [constant TARGET_PEER_SERVER] to send to the peer "
+"acting as server, a valid peer ID to send to that specific peer, a negative "
+"peer ID to send to all peers except that one. By default, the target peer is "
+"[constant TARGET_PEER_BROADCAST]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:54
+msgid ""
+"If [code]true[/code], this [NetworkedMultiplayerPeer] refuses new "
+"connections."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:57
+msgid ""
+"The manner in which to send packets to the [code]target_peer[/code]. See "
+"[enum TransferMode]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:63
+msgid "Emitted when a connection attempt fails."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:68
+msgid "Emitted when a connection attempt succeeds."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:75
+msgid "Emitted by the server when a client connects."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:82
+msgid "Emitted by the server when a client disconnects."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:87
+msgid "Emitted by clients when the server disconnects."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:93
+msgid ""
+"Packets are not acknowledged, no resend attempts are made for lost packets. "
+"Packets may arrive in any order. Potentially faster than [constant "
+"TRANSFER_MODE_UNRELIABLE_ORDERED]. Use for non-critical data, and always "
+"consider whether the order matters."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:96
+msgid ""
+"Packets are not acknowledged, no resend attempts are made for lost packets. "
+"Packets are received in the order they were sent in. Potentially faster than "
+"[constant TRANSFER_MODE_RELIABLE]. Use for non-critical data or data that "
+"would be outdated if received late due to resend attempt(s) anyway, for "
+"example movement and positional data."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:99
+msgid ""
+"Packets must be received and resend attempts should be made until the "
+"packets are acknowledged. Packets must be received in the order they were "
+"sent in. Most reliable transfer mode, but potentially the slowest due to the "
+"overhead. Use for critical data that must be transmitted and arrive in "
+"order, for example an ability being triggered or a chat message. Consider "
+"carefully if the information really is critical, and use sparingly."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:102
+msgid "The ongoing connection disconnected."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:105
+msgid "A connection attempt is ongoing."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:108
+msgid "The connection attempt succeeded."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:111
+msgid "Packets are sent to the server and then redistributed to other peers."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:114
+msgid "Packets are sent to the server alone."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:4
+msgid ""
+"Scalable texture-based frame that tiles the texture's centers and sides, but "
+"keeps the corners' original size. Perfect for panels and dialog boxes."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:7
+msgid ""
+"Also known as 9-slice panels, NinePatchRect produces clean panels of any "
+"size, based on a small texture. To do so, it splits the texture in a 3×3 "
+"grid. When you scale the node, it tiles the texture's sides horizontally or "
+"vertically, the center on both axes but it doesn't scale or tile the corners."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:18
+msgid ""
+"Returns the size of the margin identified by the given [enum Margin] "
+"constant."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:29
+msgid ""
+"Sets the size of the margin identified by the given [enum Margin] constant "
+"to [code]value[/code] in pixels."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:35 doc/classes/NinePatchRect.xml:38
+#: doc/classes/NinePatchRect.xml:72 doc/classes/NinePatchRect.xml:75
+#: doc/classes/NinePatchRect.xml:78
+msgid "Doesn't do anything at the time of writing."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:41
+msgid ""
+"If [code]true[/code], draw the panel's center. Else, only draw the 9-slice's "
+"borders."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:45
+msgid ""
+"The height of the 9-slice's bottom row. A margin of 16 means the 9-slice's "
+"bottom corners and side will have a height of 16 pixels. You can set all 4 "
+"margin values individually to create panels with non-uniform borders."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:48
+msgid "The height of the 9-slice's left column."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:51
+msgid "The height of the 9-slice's right column."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:54
+msgid "The height of the 9-slice's top row."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:57
+msgid ""
+"Rectangular region of the texture to sample from. If you're working with an "
+"atlas, use this property to define the area the 9-slice should use. All "
+"other properties are relative to this one. If the rect is empty, "
+"NinePatchRect will use the whole texture."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:60
+msgid "The node's texture resource."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:66
+msgid "Emitted when the node's texture changes."
+msgstr ""
+
+#: doc/classes/Node.xml:4
+msgid "Base class for all [i]scene[/i] objects."
+msgstr ""
+
+#: doc/classes/Node.xml:7
+msgid ""
+"Nodes are Godot's building blocks. They can be assigned as the child of "
+"another node, resulting in a tree arrangement. A given node can contain any "
+"number of nodes as children with the requirement that all siblings (direct "
+"children of a node) should have unique names.\n"
+"A tree of nodes is called a [i]scene[/i]. Scenes can be saved to the disk "
+"and then instanced into other scenes. This allows for very high flexibility "
+"in the architecture and data model of Godot projects.\n"
+"[b]Scene tree:[/b] The [SceneTree] contains the active tree of nodes. When a "
+"node is added to the scene tree, it receives the [constant "
+"NOTIFICATION_ENTER_TREE] notification and its [method _enter_tree] callback "
+"is triggered. Child nodes are always added [i]after[/i] their parent node, i."
+"e. the [method _enter_tree] callback of a parent node will be triggered "
+"before its child's.\n"
+"Once all nodes have been added in the scene tree, they receive the [constant "
+"NOTIFICATION_READY] notification and their respective [method _ready] "
+"callbacks are triggered. For groups of nodes, the [method _ready] callback "
+"is called in reverse order, starting with the children and moving up to the "
+"parent nodes.\n"
+"This means that when adding a node to the scene tree, the following order "
+"will be used for the callbacks: [method _enter_tree] of the parent, [method "
+"_enter_tree] of the children, [method _ready] of the children and finally "
+"[method _ready] of the parent (recursively for the entire scene tree).\n"
+"[b]Processing:[/b] Nodes can override the \"process\" state, so that they "
+"receive a callback on each frame requesting them to process (do something). "
+"Normal processing (callback [method _process], toggled with [method "
+"set_process]) happens as fast as possible and is dependent on the frame "
+"rate, so the processing time [i]delta[/i] is passed as an argument. Physics "
+"processing (callback [method _physics_process], toggled with [method "
+"set_physics_process]) happens a fixed number of times per second (60 by "
+"default) and is useful for code related to the physics engine.\n"
+"Nodes can also process input events. When present, the [method _input] "
+"function will be called for each input that the program receives. In many "
+"cases, this can be overkill (unless used for simple projects), and the "
+"[method _unhandled_input] function might be preferred; it is called when the "
+"input event was not handled by anyone else (typically, GUI [Control] nodes), "
+"ensuring that the node only receives the events that were meant for it.\n"
+"To keep track of the scene hierarchy (especially when instancing scenes into "
+"other scenes), an \"owner\" can be set for the node with the [member owner] "
+"property. This keeps track of who instanced what. This is mostly useful when "
+"writing editors and tools, though.\n"
+"Finally, when a node is freed with [method Object.free] or [method "
+"queue_free], it will also free all its children.\n"
+"[b]Groups:[/b] Nodes can be added to as many groups as you want to be easy "
+"to manage, you could create groups like \"enemies\" or \"collectables\" for "
+"example, depending on your game. See [method add_to_group], [method "
+"is_in_group] and [method remove_from_group]. You can then retrieve all nodes "
+"in these groups, iterate them and even call methods on groups via the "
+"methods on [SceneTree].\n"
+"[b]Networking with nodes:[/b] After connecting to a server (or making one, "
+"see [NetworkedMultiplayerENet]), it is possible to use the built-in RPC "
+"(remote procedure call) system to communicate over the network. By calling "
+"[method rpc] with a method name, it will be called locally and in all "
+"connected peers (peers = clients and the server that accepts connections). "
+"To identify which node receives the RPC call, Godot will use its [NodePath] "
+"(make sure node names are the same on all peers). Also, take a look at the "
+"high-level networking tutorial and corresponding demos."
+msgstr ""
+
+#: doc/classes/Node.xml:20
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"scenes_and_nodes.html"
+msgstr ""
+
+#: doc/classes/Node.xml:27
+msgid ""
+"Called when the node enters the [SceneTree] (e.g. upon instancing, scene "
+"changing, or after calling [method add_child] in a script). If the node has "
+"children, its [method _enter_tree] callback will be called first, and then "
+"that of the children.\n"
+"Corresponds to the [constant NOTIFICATION_ENTER_TREE] notification in "
+"[method Object._notification]."
+msgstr ""
+
+#: doc/classes/Node.xml:35
+msgid ""
+"Called when the node is about to leave the [SceneTree] (e.g. upon freeing, "
+"scene changing, or after calling [method remove_child] in a script). If the "
+"node has children, its [method _exit_tree] callback will be called last, "
+"after all its children have left the tree.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/Node.xml:43
+msgid ""
+"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.\n"
+"Returning an empty string produces no warning.\n"
+"Call [method update_configuration_warning] when the warning needs to be "
+"updated for this node."
+msgstr ""
+
+#: doc/classes/Node.xml:54
+msgid ""
+"Called when there is an input event. The input event propagates up through "
+"the node tree until a node consumes it.\n"
+"It is only called if input processing is enabled, which is done "
+"automatically if this method is overridden, and can be toggled with [method "
+"set_process_input].\n"
+"To consume the input event and stop it propagating further to other nodes, "
+"[method Viewport.set_input_as_handled] can be called.\n"
+"For gameplay input, [method _unhandled_input] and [method "
+"_unhandled_key_input] are usually a better fit as they allow the GUI to "
+"intercept the events first."
+msgstr ""
+
+#: doc/classes/Node.xml:66
+msgid ""
+"Called during the physics processing step of the main loop. Physics "
+"processing means that the frame rate is synced to the physics, i.e. the "
+"[code]delta[/code] variable should be constant.\n"
+"It is only called if physics processing is enabled, which is done "
+"automatically if this method is overridden, and can be toggled with [method "
+"set_physics_process].\n"
+"Corresponds to the [constant NOTIFICATION_PHYSICS_PROCESS] notification in "
+"[method Object._notification]."
+msgstr ""
+
+#: doc/classes/Node.xml:77
+msgid ""
+"Called during the processing step of the main loop. Processing happens at "
+"every frame and as fast as possible, so the [code]delta[/code] time since "
+"the previous frame is not constant.\n"
+"It is only called if processing is enabled, which is done automatically if "
+"this method is overridden, and can be toggled with [method set_process].\n"
+"Corresponds to the [constant NOTIFICATION_PROCESS] notification in [method "
+"Object._notification]."
+msgstr ""
+
+#: doc/classes/Node.xml:86
+msgid ""
+"Called when the node is \"ready\", i.e. when both the node and its children "
+"have entered the scene tree. If the node has children, their [method _ready] "
+"callbacks get triggered first, and the parent node will receive the ready "
+"notification afterwards.\n"
+"Corresponds to the [constant NOTIFICATION_READY] notification in [method "
+"Object._notification]. See also the [code]onready[/code] keyword for "
+"variables.\n"
+"Usually used for initialization. For even earlier initialization, [method "
+"Object._init] may be used. See also [method _enter_tree].\n"
+"[b]Note:[/b] [method _ready] may be called only once for each node. After "
+"removing a node from the scene tree and adding again, [code]_ready[/code] "
+"will not be called for the second time. This can be bypassed with requesting "
+"another call with [method request_ready], which may be called anywhere "
+"before adding the node again."
+msgstr ""
+
+#: doc/classes/Node.xml:98
+msgid ""
+"Called when an [InputEvent] hasn't been consumed by [method _input] or any "
+"GUI. The input event propagates up through the node tree until a node "
+"consumes it.\n"
+"It is only called if unhandled input processing is enabled, which is done "
+"automatically if this method is overridden, and can be toggled with [method "
+"set_process_unhandled_input].\n"
+"To consume the input event and stop it propagating further to other nodes, "
+"[method Viewport.set_input_as_handled] can be called.\n"
+"For gameplay input, this and [method _unhandled_key_input] are usually a "
+"better fit than [method _input] as they allow the GUI to intercept the "
+"events first."
+msgstr ""
+
+#: doc/classes/Node.xml:110
+msgid ""
+"Called when an [InputEventKey] hasn't been consumed by [method _input] or "
+"any GUI. The input event propagates up through the node tree until a node "
+"consumes it.\n"
+"It is only called if unhandled key input processing is enabled, which is "
+"done automatically if this method is overridden, and can be toggled with "
+"[method set_process_unhandled_key_input].\n"
+"To consume the input event and stop it propagating further to other nodes, "
+"[method Viewport.set_input_as_handled] can be called.\n"
+"For gameplay input, this and [method _unhandled_input] are usually a better "
+"fit than [method _input] as they allow the GUI to intercept the events first."
+msgstr ""
+
+#: doc/classes/Node.xml:124
+msgid ""
+"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.\n"
+"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.\n"
+"[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:\n"
+"[codeblock]\n"
+"if child_node.get_parent():\n"
+" child_node.get_parent().remove_child(child_node)\n"
+"add_child(child_node)\n"
+"[/codeblock]\n"
+"If you need the child node to be added below a specific node in the list of "
+"children, use [method add_child_below_node] instead of this method.\n"
+"[b]Note:[/b] If you want a child to be persisted to a [PackedScene], you "
+"must set [member owner] in addition to calling [method add_child]. This is "
+"typically relevant for [url=https://godot.readthedocs.io/en/latest/tutorials/"
+"misc/running_code_in_the_editor.html]tool scripts[/url] and [url=https://"
+"godot.readthedocs.io/en/latest/tutorials/plugins/editor/index.html]editor "
+"plugins[/url]. If [method add_child] is called without setting [member "
+"owner], the newly added [Node] will not be visible in the scene tree, though "
+"it will be visible in the 2D/3D view."
+msgstr ""
+
+#: doc/classes/Node.xml:146
+msgid ""
+"Adds a child node below the [code]preceding_node[/code].\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:159
+msgid ""
+"Adds the node to a group. Groups are helpers to name and organize a subset "
+"of nodes, for example \"enemies\" or \"collectables\". A node can be in any "
+"number of groups. Nodes can be assigned a group at any time, but will not be "
+"added until they are inside the scene tree (see [method is_inside_tree]). "
+"See notes in the description, and the group methods in [SceneTree].\n"
+"The [code]persistent[/code] option is used when packing node to "
+"[PackedScene] and saving to file. Non-persistent groups aren't stored."
+msgstr ""
+
+#: doc/classes/Node.xml:167
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:176
+msgid ""
+"Duplicates the node, returning a new node.\n"
+"You can fine-tune the behavior using the [code]flags[/code] (see [enum "
+"DuplicateFlags]).\n"
+"[b]Note:[/b] It will not work properly if the node contains a script with "
+"constructor arguments (i.e. needs to supply arguments to [method Object."
+"_init] method). In that case, the node will be duplicated without a script."
+msgstr ""
+
+#: doc/classes/Node.xml:191
+msgid ""
+"Finds a descendant of this node whose name matches [code]mask[/code] as in "
+"[method String.match] (i.e. case-sensitive, but [code]\"*\"[/code] matches "
+"zero or more characters and [code]\"?\"[/code] matches any single character "
+"except [code]\".\"[/code]).\n"
+"[b]Note:[/b] It does not match against the full path, just against "
+"individual node names.\n"
+"If [code]owned[/code] is [code]true[/code], this method only finds nodes "
+"whose owner is this node. This is especially important for scenes "
+"instantiated through a script, because those scenes don't have an owner."
+msgstr ""
+
+#: doc/classes/Node.xml:202
+msgid ""
+"Finds the first parent of the current node whose name matches [code]mask[/"
+"code] as in [method String.match] (i.e. case-sensitive, but [code]\"*\"[/"
+"code] matches zero or more characters and [code]\"?\"[/code] matches any "
+"single character except [code]\".\"[/code]).\n"
+"[b]Note:[/b] It does not match against the full path, just against "
+"individual node names."
+msgstr ""
+
+#: doc/classes/Node.xml:212
+msgid ""
+"Returns a child node by its index (see [method get_child_count]). This "
+"method is often used for iterating all children of a node.\n"
+"To access a child node via its name, use [method get_node]."
+msgstr ""
+
+#: doc/classes/Node.xml:220
+msgid "Returns the number of child nodes."
+msgstr ""
+
+#: doc/classes/Node.xml:227
+msgid "Returns an array of references to node's children."
+msgstr ""
+
+#: doc/classes/Node.xml:234
+msgid "Returns an array listing the groups that the node is a member of."
+msgstr ""
+
+#: doc/classes/Node.xml:241
+msgid ""
+"Returns the node's order in the scene tree branch. For example, if called on "
+"the first child node the position is [code]0[/code]."
+msgstr ""
+
+#: doc/classes/Node.xml:248
+msgid ""
+"Returns the peer ID of the network master for this node. See [method "
+"set_network_master]."
+msgstr ""
+
+#: doc/classes/Node.xml:257
+msgid ""
+"Fetches a node. The [NodePath] can be either a relative path (from the "
+"current node) or an absolute path (in the scene tree) to a node. If the path "
+"does not exist, a [code]null instance[/code] is returned and an error is "
+"logged. Attempts to access methods on the return value will result in an "
+"\"Attempt to call <method> on a null instance.\" error.\n"
+"[b]Note:[/b] Fetching absolute paths only works when the node is inside the "
+"scene tree (see [method is_inside_tree]).\n"
+"[b]Example:[/b] Assume your current node is Character and the following "
+"tree:\n"
+"[codeblock]\n"
+"/root\n"
+"/root/Character\n"
+"/root/Character/Sword\n"
+"/root/Character/Backpack/Dagger\n"
+"/root/MyGame\n"
+"/root/Swamp/Alligator\n"
+"/root/Swamp/Mosquito\n"
+"/root/Swamp/Goblin\n"
+"[/codeblock]\n"
+"Possible paths are:\n"
+"[codeblock]\n"
+"get_node(\"Sword\")\n"
+"get_node(\"Backpack/Dagger\")\n"
+"get_node(\"../Swamp/Alligator\")\n"
+"get_node(\"/root/MyGame\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:285
+msgid ""
+"Fetches a node and one of its resources as specified by the [NodePath]'s "
+"subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested "
+"resources are specified in the [NodePath], the last one will be fetched.\n"
+"The return value is an array of size 3: the first index points to the [Node] "
+"(or [code]null[/code] if not found), the second index points to the "
+"[Resource] (or [code]null[/code] if not found), and the third index is the "
+"remaining [NodePath], if any.\n"
+"For example, assuming that [code]Area2D/CollisionShape2D[/code] is a valid "
+"node and that its [code]shape[/code] property has been assigned a "
+"[RectangleShape2D] resource, one could have this kind of output:\n"
+"[codeblock]\n"
+"print(get_node_and_resource(\"Area2D/CollisionShape2D\")) # "
+"[[CollisionShape2D:1161], Null, ]\n"
+"print(get_node_and_resource(\"Area2D/CollisionShape2D:shape\")) # "
+"[[CollisionShape2D:1161], [RectangleShape2D:1156], ]\n"
+"print(get_node_and_resource(\"Area2D/CollisionShape2D:shape:extents\")) # "
+"[[CollisionShape2D:1161], [RectangleShape2D:1156], :extents]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:301
+msgid ""
+"Similar to [method get_node], but does not log an error if [code]path[/code] "
+"does not point to a valid [Node]."
+msgstr ""
+
+#: doc/classes/Node.xml:308
+msgid ""
+"Returns the parent node of the current node, or an empty [Node] if the node "
+"lacks a parent."
+msgstr ""
+
+#: doc/classes/Node.xml:315
+msgid ""
+"Returns the absolute path of the current node. This only works if the "
+"current node is inside the scene tree (see [method is_inside_tree])."
+msgstr ""
+
+#: doc/classes/Node.xml:324
+msgid ""
+"Returns the relative [NodePath] from this node to the specified [code]node[/"
+"code]. Both nodes must be in the same scene or the function will fail."
+msgstr ""
+
+#: doc/classes/Node.xml:331
+msgid ""
+"Returns the time elapsed since the last physics-bound frame (see [method "
+"_physics_process]). This is always a constant value in physics processing "
+"unless the frames per second is changed via [member Engine."
+"iterations_per_second]."
+msgstr ""
+
+#: doc/classes/Node.xml:338
+msgid ""
+"Returns the time elapsed (in seconds) since the last process callback. This "
+"value may vary from frame to frame."
+msgstr ""
+
+#: doc/classes/Node.xml:345
+msgid ""
+"Returns [code]true[/code] if this is an instance load placeholder. See "
+"[InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/Node.xml:352
+msgid "Returns the [SceneTree] that contains this node."
+msgstr ""
+
+#: doc/classes/Node.xml:359
+msgid "Returns the node's [Viewport]."
+msgstr ""
+
+#: doc/classes/Node.xml:368
+msgid ""
+"Returns [code]true[/code] if the node that the [NodePath] points to exists."
+msgstr ""
+
+#: doc/classes/Node.xml:377
+msgid ""
+"Returns [code]true[/code] if the [NodePath] points to a valid node and its "
+"subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:"
+"shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive "
+"math types) are not considered resources."
+msgstr ""
+
+#: doc/classes/Node.xml:386
+msgid ""
+"Returns [code]true[/code] if the given node is a direct or indirect child of "
+"the current node."
+msgstr ""
+
+#: doc/classes/Node.xml:393
+msgid ""
+"Returns [code]true[/code] if the node is folded (collapsed) in the Scene "
+"dock."
+msgstr ""
+
+#: doc/classes/Node.xml:402
+msgid ""
+"Returns [code]true[/code] if the given node occurs later in the scene "
+"hierarchy than the current node."
+msgstr ""
+
+#: doc/classes/Node.xml:411
+msgid ""
+"Returns [code]true[/code] if this node is in the specified group. See notes "
+"in the description, and the group methods in [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:418
+msgid ""
+"Returns [code]true[/code] if this node is currently inside a [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:425
+msgid ""
+"Returns [code]true[/code] if the local system is the master of this node."
+msgstr ""
+
+#: doc/classes/Node.xml:432
+msgid ""
+"Returns [code]true[/code] if physics processing is enabled (see [method "
+"set_physics_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:439
+msgid ""
+"Returns [code]true[/code] if internal physics processing is enabled (see "
+"[method set_physics_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:446
+msgid ""
+"Returns [code]true[/code] if processing is enabled (see [method "
+"set_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:453
+msgid ""
+"Returns [code]true[/code] if the node is processing input (see [method "
+"set_process_input])."
+msgstr ""
+
+#: doc/classes/Node.xml:460
+msgid ""
+"Returns [code]true[/code] if internal processing is enabled (see [method "
+"set_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:467
+msgid ""
+"Returns [code]true[/code] if the node is processing unhandled input (see "
+"[method set_process_unhandled_input])."
+msgstr ""
+
+#: doc/classes/Node.xml:474
+msgid ""
+"Returns [code]true[/code] if the node is processing unhandled key input (see "
+"[method set_process_unhandled_key_input])."
+msgstr ""
+
+#: doc/classes/Node.xml:485
+msgid ""
+"Moves a child node to a different position (order) among the other children. "
+"Since calls, signals, etc are performed by tree order, changing the order of "
+"children nodes may be useful."
+msgstr ""
+
+#: doc/classes/Node.xml:492
+msgid ""
+"Prints all stray nodes (nodes outside the [SceneTree]). Used for debugging. "
+"Works only in debug builds."
+msgstr ""
+
+#: doc/classes/Node.xml:499
+msgid ""
+"Prints the tree to stdout. Used mainly for debugging purposes. This version "
+"displays the path relative to the current node, and is good for copy/pasting "
+"into the [method get_node] function.\n"
+"[b]Example output:[/b]\n"
+"[codeblock]\n"
+"TheGame\n"
+"TheGame/Menu\n"
+"TheGame/Menu/Label\n"
+"TheGame/Menu/Camera2D\n"
+"TheGame/SplashScreen\n"
+"TheGame/SplashScreen/Camera2D\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:515
+msgid ""
+"Similar to [method print_tree], this prints the tree to stdout. This version "
+"displays a more graphical representation similar to what is displayed in the "
+"scene inspector. It is useful for inspecting larger trees.\n"
+"[b]Example output:[/b]\n"
+"[codeblock]\n"
+" ┖╴TheGame\n"
+" ┠╴Menu\n"
+" ┃ ┠╴Label\n"
+" ┃ ┖╴Camera2D\n"
+" ┖-SplashScreen\n"
+" ┖╴Camera2D\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:537
+msgid ""
+"Calls the given method (if present) with the arguments given in [code]args[/"
+"code] on this node and recursively on all its children. If the "
+"[code]parent_first[/code] argument is [code]true[/code], the method will be "
+"called on the current node first, then on all its children. If "
+"[code]parent_first[/code] is [code]false[/code], the children will be called "
+"first."
+msgstr ""
+
+#: doc/classes/Node.xml:546
+msgid ""
+"Notifies the current node and all its children recursively by calling "
+"[method Object.notification] on all of them."
+msgstr ""
+
+#: doc/classes/Node.xml:553
+msgid ""
+"Queues a node for deletion at the end of the current frame. When deleted, "
+"all of its child nodes will be deleted as well. This method ensures it's "
+"safe to delete the node, contrary to [method Object.free]. Use [method "
+"Object.is_queued_for_deletion] to check whether a node will be deleted at "
+"the end of the frame."
+msgstr ""
+
+#: doc/classes/Node.xml:560
+msgid ""
+"Moves this node to the bottom of parent node's children hierarchy. This is "
+"often useful in GUIs ([Control] nodes), because their order of drawing "
+"depends on their order in the tree, i.e. the further they are on the node "
+"list, the higher they are drawn. After using [code]raise[/code], a Control "
+"will be drawn on top of their siblings."
+msgstr ""
+
+#: doc/classes/Node.xml:567
+msgid ""
+"Removes a node and sets all its children as children of the parent node (if "
+"it exists). All event subscriptions that pass by the removed node will be "
+"unsubscribed."
+msgstr ""
+
+#: doc/classes/Node.xml:576
+msgid ""
+"Removes a child node. The node is NOT deleted and must be deleted manually."
+msgstr ""
+
+#: doc/classes/Node.xml:585
+msgid ""
+"Removes a node from a group. See notes in the description, and the group "
+"methods in [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:596
+msgid ""
+"Replaces a node in a scene by the given one. Subscriptions that pass through "
+"this node will be lost."
+msgstr ""
+
+#: doc/classes/Node.xml:603
+msgid ""
+"Requests that [code]_ready[/code] be called again. Note that the method "
+"won't be called immediately, but is scheduled for when the node is added to "
+"the scene tree again (see [method _ready]). [code]_ready[/code] is called "
+"only for the node which requested it, which means that you need to request "
+"ready for each child if you want them to call [code]_ready[/code] too (in "
+"which case, [code]_ready[/code] will be called in the same order as it would "
+"normally)."
+msgstr ""
+
+#: doc/classes/Node.xml:612
+msgid ""
+"Sends a remote procedure call request for the given [code]method[/code] to "
+"peers on the network (and locally), optionally sending all additional "
+"arguments as arguments to the method called by the RPC. The call request "
+"will only be received by nodes with the same [NodePath], including the exact "
+"same node name. Behaviour depends on the RPC configuration for the given "
+"method, see [method rpc_config]. Methods are not exposed to RPCs by default. "
+"See also [method rset] and [method rset_config] for properties. Returns an "
+"empty [Variant].\n"
+"[b]Note:[/b] You can only safely use RPCs on clients after you received the "
+"[code]connected_to_server[/code] signal from the [SceneTree]. You also need "
+"to keep track of the connection state, either by the [SceneTree] signals "
+"like [code]server_disconnected[/code] or by checking [code]SceneTree."
+"network_peer.get_connection_status() == CONNECTION_CONNECTED[/code]."
+msgstr ""
+
+#: doc/classes/Node.xml:624
+msgid ""
+"Changes the RPC mode for the given [code]method[/code] to the given "
+"[code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is "
+"annotating methods and properties with the corresponding keywords "
+"([code]remote[/code], [code]master[/code], [code]puppet[/code], "
+"[code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). "
+"By default, methods are not exposed to networking (and RPCs). See also "
+"[method rset] and [method rset_config] for properties."
+msgstr ""
+
+#: doc/classes/Node.xml:635
+msgid ""
+"Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] "
+"(see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty "
+"[Variant]."
+msgstr ""
+
+#: doc/classes/Node.xml:644
+msgid ""
+"Sends a [method rpc] using an unreliable protocol. Returns an empty "
+"[Variant]."
+msgstr ""
+
+#: doc/classes/Node.xml:655
+msgid ""
+"Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] "
+"using an unreliable protocol (see [method NetworkedMultiplayerPeer."
+"set_target_peer]). Returns an empty [Variant]."
+msgstr ""
+
+#: doc/classes/Node.xml:666
+msgid ""
+"Remotely changes a property's value on other peers (and locally). Behaviour "
+"depends on the RPC configuration for the given property, see [method "
+"rset_config]. See also [method rpc] for RPCs for methods, most information "
+"applies to this method as well."
+msgstr ""
+
+#: doc/classes/Node.xml:677
+msgid ""
+"Changes the RPC mode for the given [code]property[/code] to the given "
+"[code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is "
+"annotating methods and properties with the corresponding keywords "
+"([code]remote[/code], [code]master[/code], [code]puppet[/code], "
+"[code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). "
+"By default, properties are not exposed to networking (and RPCs). See also "
+"[method rpc] and [method rpc_config] for methods."
+msgstr ""
+
+#: doc/classes/Node.xml:690
+msgid ""
+"Remotely changes the property's value on a specific peer identified by "
+"[code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer])."
+msgstr ""
+
+#: doc/classes/Node.xml:701
+msgid ""
+"Remotely changes the property's value on other peers (and locally) using an "
+"unreliable protocol."
+msgstr ""
+
+#: doc/classes/Node.xml:714
+msgid ""
+"Remotely changes property's value on a specific peer identified by "
+"[code]peer_id[/code] using an unreliable protocol (see [method "
+"NetworkedMultiplayerPeer.set_target_peer])."
+msgstr ""
+
+#: doc/classes/Node.xml:723
+msgid "Sets the folded state of the node in the Scene dock."
+msgstr ""
+
+#: doc/classes/Node.xml:734
+msgid ""
+"Sets the node's network master to the peer with the given peer ID. The "
+"network master is the peer that has authority over the node on the network. "
+"Useful in conjunction with the [code]master[/code] and [code]puppet[/code] "
+"keywords. Inherited from the parent node by default, which ultimately "
+"defaults to peer ID 1 (the server). If [code]recursive[/code], the given "
+"peer is recursively set as the master for all children of this node."
+msgstr ""
+
+#: doc/classes/Node.xml:743
+msgid ""
+"Enables or disables physics (i.e. fixed framerate) processing. When a node "
+"is being processed, it will receive a [constant "
+"NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine."
+"iterations_per_second] to change) interval (and the [method "
+"_physics_process] callback will be called if exists). Enabled automatically "
+"if [method _physics_process] is overridden. Any calls to this before [method "
+"_ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:752
+msgid ""
+"Enables or disables internal physics for this node. Internal physics "
+"processing happens in isolation from the normal [method _physics_process] "
+"calls and is used by some nodes internally to guarantee proper functioning "
+"even if the node is paused or physics processing is disabled for scripting "
+"([method set_physics_process]). Only useful for advanced uses to manipulate "
+"built-in nodes' behaviour."
+msgstr ""
+
+#: doc/classes/Node.xml:761
+msgid ""
+"Enables or disables processing. When a node is being processed, it will "
+"receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the "
+"[method _process] callback will be called if exists). Enabled automatically "
+"if [method _process] is overridden. Any calls to this before [method _ready] "
+"will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:770
+msgid ""
+"Enables or disables input processing. This is not required for GUI controls! "
+"Enabled automatically if [method _input] is overridden. Any calls to this "
+"before [method _ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:779
+msgid ""
+"Enables or disabled internal processing for this node. Internal processing "
+"happens in isolation from the normal [method _process] calls and is used by "
+"some nodes internally to guarantee proper functioning even if the node is "
+"paused or processing is disabled for scripting ([method set_process]). Only "
+"useful for advanced uses to manipulate built-in nodes' behaviour."
+msgstr ""
+
+#: doc/classes/Node.xml:788
+msgid ""
+"Enables unhandled input processing. This is not required for GUI controls! "
+"It enables the node to receive all input that was not previously handled "
+"(usually by a [Control]). Enabled automatically if [method _unhandled_input] "
+"is overridden. Any calls to this before [method _ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:797
+msgid ""
+"Enables unhandled key input processing. Enabled automatically if [method "
+"_unhandled_key_input] is overridden. Any calls to this before [method "
+"_ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:806
+msgid ""
+"Sets whether this is an instance load placeholder. See [InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/Node.xml:813
+msgid ""
+"Updates the warning displayed for this node in the Scene Dock.\n"
+"Use [method _get_configuration_warning] to setup the warning message to "
+"display."
+msgstr ""
+
+#: doc/classes/Node.xml:820
+msgid ""
+"The override to the default [MultiplayerAPI]. Set to [code]null[/code] to "
+"use the default [SceneTree] one."
+msgstr ""
+
+#: doc/classes/Node.xml:823
+msgid ""
+"When a scene is instanced from a file, its topmost node contains the "
+"filename from which it was loaded."
+msgstr ""
+
+#: doc/classes/Node.xml:826
+msgid ""
+"The [MultiplayerAPI] instance associated with this node. Either the [member "
+"custom_multiplayer], or the default SceneTree one (if inside tree)."
+msgstr ""
+
+#: doc/classes/Node.xml:829
+msgid ""
+"The name of the node. This name is unique among the siblings (other child "
+"nodes from the same parent). When set to an existing name, the node will be "
+"automatically renamed."
+msgstr ""
+
+#: doc/classes/Node.xml:832
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:835
+msgid "Pause mode. How the node will behave if the [SceneTree] is paused."
+msgstr ""
+
+#: doc/classes/Node.xml:838
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:844
+msgid "Emitted when the node is ready."
+msgstr ""
+
+#: doc/classes/Node.xml:849
+msgid "Emitted when the node is renamed."
+msgstr ""
+
+#: doc/classes/Node.xml:854
+msgid "Emitted when the node enters the tree."
+msgstr ""
+
+#: doc/classes/Node.xml:859
+msgid "Emitted after the node exits the tree and is no longer active."
+msgstr ""
+
+#: doc/classes/Node.xml:864
+msgid ""
+"Emitted when the node is still active but about to exit the tree. This is "
+"the right place for de-initialization (or a \"destructor\", if you will)."
+msgstr ""
+
+#: doc/classes/Node.xml:870
+msgid "Notification received when the node enters a [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:873
+msgid "Notification received when the node is about to exit a [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:876
+msgid "Notification received when the node is moved in the parent."
+msgstr ""
+
+#: doc/classes/Node.xml:879
+msgid "Notification received when the node is ready. See [method _ready]."
+msgstr ""
+
+#: doc/classes/Node.xml:882
+msgid "Notification received when the node is paused."
+msgstr ""
+
+#: doc/classes/Node.xml:885
+msgid "Notification received when the node is unpaused."
+msgstr ""
+
+#: doc/classes/Node.xml:888
+msgid ""
+"Notification received every frame when the physics process flag is set (see "
+"[method set_physics_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:891
+msgid ""
+"Notification received every frame when the process flag is set (see [method "
+"set_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:894
+msgid ""
+"Notification received when a node is set as a child of another node.\n"
+"[b]Note:[/b] This doesn't mean that a node entered the [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:898
+msgid ""
+"Notification received when a node is unparented (parent removed it from the "
+"list of children)."
+msgstr ""
+
+#: doc/classes/Node.xml:901
+msgid "Notification received when the node is instanced."
+msgstr ""
+
+#: doc/classes/Node.xml:904
+msgid "Notification received when a drag begins."
+msgstr ""
+
+#: doc/classes/Node.xml:907
+msgid "Notification received when a drag ends."
+msgstr ""
+
+#: doc/classes/Node.xml:910
+msgid "Notification received when the node's [NodePath] changed."
+msgstr ""
+
+#: doc/classes/Node.xml:913
+msgid ""
+"Notification received every frame when the internal process flag is set (see "
+"[method set_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:916
+msgid ""
+"Notification received every frame when the internal physics process flag is "
+"set (see [method set_physics_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:919
+msgid ""
+"Notification received from the OS when the mouse enters the game window.\n"
+"Implemented on desktop and web platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:923
+msgid ""
+"Notification received from the OS when the mouse leaves the game window.\n"
+"Implemented on desktop and web platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:927
+msgid ""
+"Notification received from the OS when the game window is focused.\n"
+"Implemented on all platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:931
+msgid ""
+"Notification received from the OS when the game window is unfocused.\n"
+"Implemented on all platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:935
+msgid ""
+"Notification received from the OS when a close request is sent (e.g. closing "
+"the window with a \"Close\" button or Alt+F4).\n"
+"Implemented on desktop platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:939
+msgid ""
+"Notification received from the OS when a go back request is sent (e.g. "
+"pressing the \"Back\" button on Android).\n"
+"Specific to the Android platform."
+msgstr ""
+
+#: doc/classes/Node.xml:972
+msgid ""
+"Inherits pause mode from the node's parent. For the root node, it is "
+"equivalent to [constant PAUSE_MODE_STOP]. Default."
+msgstr ""
+
+#: doc/classes/Node.xml:975
+msgid "Stops processing when the [SceneTree] is paused."
+msgstr ""
+
+#: doc/classes/Node.xml:978
+msgid "Continue to process regardless of the [SceneTree] pause state."
+msgstr ""
+
+#: doc/classes/Node.xml:981
+msgid "Duplicate the node's signals."
+msgstr ""
+
+#: doc/classes/Node.xml:984
+msgid "Duplicate the node's groups."
+msgstr ""
+
+#: doc/classes/Node.xml:987
+msgid "Duplicate the node's scripts."
+msgstr ""
+
+#: doc/classes/Node.xml:990
+msgid ""
+"Duplicate using instancing.\n"
+"An instance stays linked to the original so when the original changes, the "
+"instance changes too."
+msgstr ""
+
+#: doc/classes/Node2D.xml:4
+msgid ""
+"A 2D game object, inherited by all 2D-related nodes. Has a position, "
+"rotation, scale, and Z index."
+msgstr ""
+
+#: doc/classes/Node2D.xml:7
+msgid ""
+"A 2D game object, with a transform (position, rotation, and scale). All 2D "
+"nodes, including physics objects and sprites, inherit from Node2D. Use "
+"Node2D as a parent node to move, scale and rotate children in a 2D project. "
+"Also gives control of the node's render order."
+msgstr ""
+
+#: doc/classes/Node2D.xml:19
+msgid "Multiplies the current scale by the [code]ratio[/code] vector."
+msgstr ""
+
+#: doc/classes/Node2D.xml:28
+msgid ""
+"Returns the angle between the node and the [code]point[/code] in radians."
+msgstr ""
+
+#: doc/classes/Node2D.xml:37
+msgid "Returns the [Transform2D] relative to this node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:46
+msgid "Adds the [code]offset[/code] vector to the node's global position."
+msgstr ""
+
+#: doc/classes/Node2D.xml:55
+msgid ""
+"Rotates the node so it points towards the [code]point[/code], which is "
+"expected to use global coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:66
+msgid ""
+"Applies a local translation on the node's X axis based on the [method Node."
+"_process]'s [code]delta[/code]. If [code]scaled[/code] is [code]false[/"
+"code], normalizes the movement."
+msgstr ""
+
+#: doc/classes/Node2D.xml:77
+msgid ""
+"Applies a local translation on the node's Y axis based on the [method Node."
+"_process]'s [code]delta[/code]. If [code]scaled[/code] is [code]false[/"
+"code], normalizes the movement."
+msgstr ""
+
+#: doc/classes/Node2D.xml:86
+msgid ""
+"Applies a rotation to the node, in radians, starting from its current "
+"rotation."
+msgstr ""
+
+#: doc/classes/Node2D.xml:95
+msgid "Converts a local point's coordinates to global coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:104
+msgid "Converts a global point's coordinates to local coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:113
+msgid ""
+"Translates the node by the given [code]offset[/code] in local coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:119
+msgid "Global position."
+msgstr ""
+
+#: doc/classes/Node2D.xml:122
+msgid "Global rotation in radians."
+msgstr ""
+
+#: doc/classes/Node2D.xml:125
+msgid "Global rotation in degrees."
+msgstr ""
+
+#: doc/classes/Node2D.xml:128
+msgid "Global scale."
+msgstr ""
+
+#: doc/classes/Node2D.xml:131
+msgid "Global [Transform2D]."
+msgstr ""
+
+#: doc/classes/Node2D.xml:134
+msgid "Position, relative to the node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:137
+msgid "Rotation in radians, relative to the node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:140
+msgid "Rotation in degrees, relative to the node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:143
+msgid "The node's scale. Unscaled value: [code](1, 1)[/code]."
+msgstr ""
+
+#: doc/classes/Node2D.xml:146
+msgid "Local [Transform2D]."
+msgstr ""
+
+#: doc/classes/Node2D.xml:149
+msgid ""
+"If [code]true[/code], the node's Z index is relative to its parent's Z "
+"index. If this node's Z index is 2 and its parent's effective Z index is 3, "
+"then this node's effective Z index will be 2 + 3 = 5."
+msgstr ""
+
+#: doc/classes/Node2D.xml:152
+msgid ""
+"Z index. Controls the order in which the nodes render. A node with a higher "
+"Z index will display in front of others."
+msgstr ""
+
+#: doc/classes/Node3D.xml:4
+msgid "Most basic 3D game object, parent of all 3D-related nodes."
+msgstr ""
+
+#: doc/classes/Node3D.xml:7
+msgid ""
+"Most basic 3D game object, with a 3D [Transform] and visibility settings. "
+"All other 3D game objects inherit from Node3D. Use [Node3D] as a parent node "
+"to move, scale, rotate and show/hide children in a 3D project.\n"
+"Affine operations (rotate, scale, translate) happen in parent's local "
+"coordinate system, unless the [Node3D] object is set as top-level. Affine "
+"operations in this coordinate system correspond to direct affine operations "
+"on the [Node3D]'s transform. The word local below refers to this coordinate "
+"system. The coordinate system that is attached to the [Node3D] object itself "
+"is referred to as object-local coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html"
+msgstr ""
+
+#: doc/classes/Node3D.xml:25
+msgid ""
+"Returns the parent [Node3D], or an empty [Object] if no parent exists or "
+"parent is not of type [Node3D]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:32
+msgid ""
+"Returns the current [World3D] resource this [Node3D] node is registered to."
+msgstr ""
+
+#: doc/classes/Node3D.xml:43
+msgid ""
+"Rotates the global (world) transformation around axis, a unit [Vector3], by "
+"specified angle in radians. The rotation axis is in global coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:52
+msgid ""
+"Scales the global (world) transformation by the given [Vector3] scale "
+"factors."
+msgstr ""
+
+#: doc/classes/Node3D.xml:61
+msgid ""
+"Moves the global (world) transformation by [Vector3] offset. The offset is "
+"in global coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:68
+msgid ""
+"Disables rendering of this node. Changes [member visible] to [code]false[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:75
+msgid ""
+"Returns whether node notifies about its local transformation changes. "
+"[Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:82
+msgid ""
+"Returns whether this node uses a scale of [code](1, 1, 1)[/code] or its "
+"local transformation scale."
+msgstr ""
+
+#: doc/classes/Node3D.xml:89
+msgid ""
+"Returns whether this node is set as Toplevel, that is whether it ignores its "
+"parent nodes transformations."
+msgstr ""
+
+#: doc/classes/Node3D.xml:96
+msgid ""
+"Returns whether the node notifies about its global and local transformation "
+"changes. [Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:103
+msgid ""
+"Returns whether the node is visible, taking into consideration that its "
+"parents visibility."
+msgstr ""
+
+#: doc/classes/Node3D.xml:114
+msgid ""
+"Rotates itself so that the local -Z axis points towards the [code]target[/"
+"code] position.\n"
+"The transform will first be rotated around the given [code]up[/code] vector, "
+"and then fully aligned to the target by a further rotation around an axis "
+"perpendicular to both the [code]target[/code] and [code]up[/code] vectors.\n"
+"Operations take place in global space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:129
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node3D.xml:136
+msgid ""
+"Resets this node's transformations (like scale, skew and taper) preserving "
+"its rotation and translation by performing Gram-Schmidt orthonormalization "
+"on this node's [Transform]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:147
+msgid ""
+"Rotates the local transformation around axis, a unit [Vector3], by specified "
+"angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:158
+msgid ""
+"Rotates the local transformation around axis, a unit [Vector3], by specified "
+"angle in radians. The rotation axis is in object-local coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:167
+msgid "Rotates the local transformation around the X axis by angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:176
+msgid "Rotates the local transformation around the Y axis by angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:185
+msgid "Rotates the local transformation around the Z axis by angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:194
+msgid ""
+"Scales the local transformation by given 3D scale factors in object-local "
+"coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:203
+msgid ""
+"Makes the node ignore its parents transformations. Node transformations are "
+"only in global space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:212
+msgid ""
+"Sets whether the node uses a scale of [code](1, 1, 1)[/code] or its local "
+"transformation scale. Changes to the local transformation scale are "
+"preserved."
+msgstr ""
+
+#: doc/classes/Node3D.xml:219
+msgid ""
+"Reset all transformations for this node (sets its [Transform] to the "
+"identity matrix)."
+msgstr ""
+
+#: doc/classes/Node3D.xml:228
+msgid ""
+"Sets whether the node ignores notification that its transformation (global "
+"or local) changed."
+msgstr ""
+
+#: doc/classes/Node3D.xml:237
+msgid ""
+"Sets whether the node notifies about its local transformation changes. "
+"[Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:246
+msgid ""
+"Sets whether the node notifies about its global and local transformation "
+"changes. [Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:253
+msgid ""
+"Enables rendering of this node. Changes [member visible] to [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:262
+msgid ""
+"Transforms [code]local_point[/code] from this node's local space to world "
+"space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:271
+msgid ""
+"Transforms [code]global_point[/code] from world space to this node's local "
+"space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:280
+msgid ""
+"Changes the node's position by the given offset [Vector3].\n"
+"Note that the translation [code]offset[/code] is affected by the node's "
+"scale, so if scaled by e.g. [code](10, 1, 1)[/code], a translation by an "
+"offset of [code](2, 0, 0)[/code] would actually add 20 ([code]2 * 10[/code]) "
+"to the X coordinate."
+msgstr ""
+
+#: doc/classes/Node3D.xml:290
+msgid ""
+"Changes the node's position by the given offset [Vector3] in local space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:297
+msgid "Updates the [Node3DGizmo] of this node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:303
+msgid ""
+"The [Node3DGizmo] for this node. Used for example in [EditorNode3DGizmo] as "
+"custom visualization and editing handles in Editor."
+msgstr ""
+
+#: doc/classes/Node3D.xml:306
+msgid "World3D space (global) [Transform] of this node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:309
+msgid ""
+"Rotation part of the local transformation in radians, specified in terms of "
+"YXZ-Euler angles in the format (X angle, Y angle, Z angle).\n"
+"[b]Note:[/b] In the mathematical sense, rotation is a matrix and not a "
+"vector. The three Euler angles, which are the three independent parameters "
+"of the Euler-angle parametrization of the rotation matrix, are stored in a "
+"[Vector3] data structure not because the rotation is a vector, but only "
+"because [Vector3] exists as a convenient data-structure to store 3 floating-"
+"point numbers. Therefore, applying affine operations on the rotation \"vector"
+"\" is not meaningful."
+msgstr ""
+
+#: doc/classes/Node3D.xml:313
+msgid ""
+"Rotation part of the local transformation in degrees, specified in terms of "
+"YXZ-Euler angles in the format (X angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Node3D.xml:316
+msgid "Scale part of the local transformation."
+msgstr ""
+
+#: doc/classes/Node3D.xml:319
+msgid "Local space [Transform] of this node, with respect to the parent node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:322
+msgid "Local translation of this node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:325
+msgid "If [code]true[/code], this node is drawn."
+msgstr ""
+
+#: doc/classes/Node3D.xml:331
+msgid "Emitted when node visibility changes."
+msgstr ""
+
+#: doc/classes/Node3D.xml:337
+msgid ""
+"Node3D nodes receives this notification when their global transform changes. "
+"This means that either the current or a parent node changed its transform.\n"
+"In order for [constant NOTIFICATION_TRANSFORM_CHANGED] to work, users first "
+"need to ask for it, with [method set_notify_transform]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:341
+msgid ""
+"Node3D nodes receives this notification when they are registered to new "
+"[World3D] resource."
+msgstr ""
+
+#: doc/classes/Node3D.xml:344
+msgid ""
+"Node3D nodes receives this notification when they are unregistered from "
+"current [World3D] resource."
+msgstr ""
+
+#: doc/classes/Node3D.xml:347
+msgid "Node3D nodes receives this notification when their visibility changes."
+msgstr ""
+
+#: doc/classes/NodePath.xml:4
+msgid "Pre-parsed scene tree path."
+msgstr ""
+
+#: doc/classes/NodePath.xml:7
+msgid ""
+"A pre-parsed relative or absolute path in a scene tree, for use with [method "
+"Node.get_node] and similar functions. It can reference a node, a resource "
+"within a node, or a property of a node or resource. For instance, "
+"[code]\"Path2D/PathFollow2D/Sprite2D:texture:size\"[/code] would refer to "
+"the [code]size[/code] property of the [code]texture[/code] resource on the "
+"node named [code]\"Sprite2D\"[/code] which is a child of the other named "
+"nodes in the path.\n"
+"You will usually just pass a string to [method Node.get_node] and it will be "
+"automatically converted, but you may occasionally want to parse a path ahead "
+"of time with [NodePath] or the literal syntax [code]@\"path\"[/code]. "
+"Exporting a [NodePath] variable will give you a node selection widget in the "
+"properties panel of the editor, which can often be useful.\n"
+"A [NodePath] is composed of a list of slash-separated node names (like a "
+"filesystem path) and an optional colon-separated list of \"subnames\" which "
+"can be resources or properties.\n"
+"Some examples of NodePaths include the following:\n"
+"[codeblock]\n"
+"# No leading slash means it is relative to the current node.\n"
+"@\"A\" # Immediate child A\n"
+"@\"A/B\" # A's child B\n"
+"@\".\" # The current node.\n"
+"@\"..\" # The parent node.\n"
+"@\"../C\" # A sibling node C.\n"
+"# A leading slash means it is absolute from the SceneTree.\n"
+"@\"/root\" # Equivalent to get_tree().get_root().\n"
+"@\"/root/Main\" # If your main scene's root node were named \"Main\".\n"
+"@\"/root/MyAutoload\" # If you have an autoloaded node or scene.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:33
+msgid ""
+"Creates a NodePath from a string, e.g. [code]\"Path2D/PathFollow2D/Sprite2D:"
+"texture:size\"[/code]. A path is absolute if it starts with a slash. "
+"Absolute paths are only valid in the global scene tree, not within "
+"individual scenes. In a relative path, [code]\".\"[/code] and [code]\"..\"[/"
+"code] indicate the current node and its parent.\n"
+"The \"subnames\" optionally included after the path to the target node can "
+"point to resources or properties, and can also be nested.\n"
+"Examples of valid NodePaths (assuming that those nodes exist and have the "
+"referenced resources or properties):\n"
+"[codeblock]\n"
+"# Points to the Sprite2D node\n"
+"\"Path2D/PathFollow2D/Sprite2D\"\n"
+"# Points to the Sprite2D node and its \"texture\" resource.\n"
+"# get_node() would retrieve \"Sprite2D\", while get_node_and_resource()\n"
+"# would retrieve both the Sprite2D node and the \"texture\" resource.\n"
+"\"Path2D/PathFollow2D/Sprite2D:texture\"\n"
+"# Points to the Sprite2D node and its \"position\" property.\n"
+"\"Path2D/PathFollow2D/Sprite2D:position\"\n"
+"# Points to the Sprite2D node and the \"x\" component of its \"position\" "
+"property.\n"
+"\"Path2D/PathFollow2D/Sprite2D:position:x\"\n"
+"# Absolute path (from \"root\")\n"
+"\"/root/Level/Path2D\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:56
+msgid ""
+"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).\n"
+"[codeblock]\n"
+"# This will be parsed as a node path to the \"x\" property in the \"position"
+"\" node\n"
+"var node_path = NodePath(\"position:x\")\n"
+"# This will be parsed as a node path to the \"x\" component of the \"position"
+"\" property in the current node\n"
+"var property_path = node_path.get_as_property_path()\n"
+"print(property_path) # :position:x\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:70
+msgid ""
+"Returns all subnames concatenated with a colon character ([code]:[/code]) as "
+"separator, i.e. the right side of the first colon in a node path.\n"
+"[codeblock]\n"
+"var nodepath = NodePath(\"Path2D/PathFollow2D/Sprite2D:texture:load_path\")\n"
+"print(nodepath.get_concatenated_subnames()) # texture:load_path\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:83
+msgid ""
+"Gets the node name indicated by [code]idx[/code] (0 to [method "
+"get_name_count]).\n"
+"[codeblock]\n"
+"var node_path = NodePath(\"Path2D/PathFollow2D/Sprite2D\")\n"
+"print(node_path.get_name(0)) # Path2D\n"
+"print(node_path.get_name(1)) # PathFollow2D\n"
+"print(node_path.get_name(2)) # Sprite\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:96
+msgid ""
+"Gets the number of node names which make up the path. Subnames (see [method "
+"get_subname_count]) are not included.\n"
+"For example, [code]\"Path2D/PathFollow2D/Sprite2D\"[/code] has 3 names."
+msgstr ""
+
+#: doc/classes/NodePath.xml:106
+msgid ""
+"Gets the resource or property name indicated by [code]idx[/code] (0 to "
+"[method get_subname_count]).\n"
+"[codeblock]\n"
+"var node_path = NodePath(\"Path2D/PathFollow2D/Sprite2D:texture:load_path"
+"\")\n"
+"print(node_path.get_subname(0)) # texture\n"
+"print(node_path.get_subname(1)) # load_path\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:118
+msgid ""
+"Gets the number of resource or property names (\"subnames\") in the path. "
+"Each subname is listed after a colon character ([code]:[/code]) in the node "
+"path.\n"
+"For example, [code]\"Path2D/PathFollow2D/Sprite2D:texture:load_path\"[/code] "
+"has 2 subnames."
+msgstr ""
+
+#: doc/classes/NodePath.xml:126
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/NodePath.xml:133
+msgid "Returns [code]true[/code] if the node path is empty."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:4
+msgid "[OpenSimplexNoise] filled texture."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:7
+msgid ""
+"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.\n"
+"NoiseTexture can also generate normalmap textures.\n"
+"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:\n"
+"[codeblock]\n"
+"var texture = preload(\"res://noise.tres\")\n"
+"yield(texture, \"changed\")\n"
+"var image = texture.get_data()\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:22
+msgid ""
+"If [code]true[/code], the resulting texture contains a normal map created "
+"from the original noise interpreted as a bump map."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:25
+msgid ""
+"Strength of the bump maps used in this texture. A higher value will make the "
+"bump maps appear larger while a lower value will make them appear softer."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:28
+msgid "Height of the generated texture."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:31
+msgid "The [OpenSimplexNoise] instance used to generate the noise."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:34
+msgid ""
+"Whether the texture can be tiled without visible seams or not. Seamless "
+"textures take longer to generate."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:37
+msgid "Width of the generated texture."
+msgstr ""
+
+#: doc/classes/Object.xml:4
+msgid "Base class for all non built-in types."
+msgstr ""
+
+#: doc/classes/Object.xml:7
+msgid ""
+"Every class which is not a built-in type inherits from this class.\n"
+"You can construct Objects from scripting languages, using [code]Object.new()"
+"[/code] in GDScript, [code]new Object[/code] in C#, or the \"Construct Object"
+"\" node in VisualScript.\n"
+"Objects do not manage memory. If a class inherits from Object, you will have "
+"to delete instances of it manually. To do so, call the [method free] method "
+"from your script or delete the instance from C++.\n"
+"Some classes that extend Object add memory management. This is the case of "
+"[Reference], which counts references and deletes itself automatically when "
+"no longer referenced. [Node], another fundamental type, deletes all its "
+"children when freed from memory.\n"
+"Objects export properties, which are mainly useful for storage and editing, "
+"but not really so much in programming. Properties are exported in [method "
+"_get_property_list] and handled in [method _get] and [method _set]. However, "
+"scripting languages and C++ have simpler means to export them.\n"
+"Property membership can be tested directly in GDScript using [code]in[/"
+"code]:\n"
+"[codeblock]\n"
+"var n = Node2D.new()\n"
+"print(\"position\" in n) # Prints \"True\".\n"
+"print(\"other_property\" in n) # Prints \"False\".\n"
+"[/codeblock]\n"
+"Objects also receive notifications. Notifications are a simple way to notify "
+"the object about different events, so they can all be handled together. See "
+"[method _notification]."
+msgstr ""
+
+#: doc/classes/Object.xml:29
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method get].\n"
+"Returns the given property. Returns [code]null[/code] if the [code]property[/"
+"code] does not exist."
+msgstr ""
+
+#: doc/classes/Object.xml:37
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method get_property_list].\n"
+"Returns the object's property list as an [Array] of dictionaries.\n"
+"Each property's [Dictionary] must contain at least [code]name: String[/code] "
+"and [code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it "
+"can also include [code]hint: int[/code] (see [enum PropertyHint]), "
+"[code]hint_string: String[/code], and [code]usage: int[/code] (see [enum "
+"PropertyUsageFlags])."
+msgstr ""
+
+#: doc/classes/Object.xml:46
+msgid "Called when the object is initialized."
+msgstr ""
+
+#: doc/classes/Object.xml:55
+msgid ""
+"Called whenever the object receives a notification, which is identified in "
+"[code]what[/code] by a constant. The base [Object] has two constants "
+"[constant NOTIFICATION_POSTINITIALIZE] and [constant "
+"NOTIFICATION_PREDELETE], but subclasses such as [Node] define a lot more "
+"notifications which are also received by this method."
+msgstr ""
+
+#: doc/classes/Object.xml:66
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method set].\n"
+"Sets a property. Returns [code]true[/code] if the [code]property[/code] "
+"exists."
+msgstr ""
+
+#: doc/classes/Object.xml:74
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method to_string], and thus the object's representation where it is "
+"converted to a string, e.g. with [code]print(obj)[/code].\n"
+"Returns a [String] representing the object. If not overridden, defaults to "
+"[code]\"[ClassName:RID]\"[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:86
+msgid ""
+"Adds a user-defined [code]signal[/code]. Arguments are optional, but can be "
+"added as an [Array] of dictionaries, each containing [code]name: String[/"
+"code] and [code]type: int[/code] (see [enum Variant.Type]) entries."
+msgstr ""
+
+#: doc/classes/Object.xml:95
+msgid ""
+"Calls the [code]method[/code] on the object and returns the result. This "
+"method supports a variable number of arguments, so parameters are passed as "
+"a comma separated list. Example:\n"
+"[codeblock]\n"
+"call(\"set\", \"position\", Vector2(42.0, 0.0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:107
+msgid ""
+"Calls the [code]method[/code] on the object during idle time. This method "
+"supports a variable number of arguments, so parameters are passed as a comma "
+"separated list. Example:\n"
+"[codeblock]\n"
+"call_deferred(\"set\", \"position\", Vector2(42.0, 0.0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:121
+msgid ""
+"Calls the [code]method[/code] on the object and returns the result. "
+"Contrarily to [method call], this method does not support a variable number "
+"of arguments but expects all parameters to be via a single [Array].\n"
+"[codeblock]\n"
+"callv(\"set\", [ \"position\", Vector2(42.0, 0.0) ])\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:131
+msgid ""
+"Returns [code]true[/code] if the object can translate strings. See [method "
+"set_message_translation] and [method tr]."
+msgstr ""
+
+#: doc/classes/Object.xml:146
+msgid ""
+"[b]FIXME:[/b] The syntax changed with the addition of [Callable], this "
+"should be updated.\n"
+"Connects a [code]signal[/code] to a [code]method[/code] on a [code]target[/"
+"code] object. Pass optional [code]binds[/code] to the call as an [Array] of "
+"parameters. These parameters will be passed to the 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.\n"
+"A [code]signal[/code] can only be connected once to a [code]method[/code]. "
+"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.\n"
+"If the [code]target[/code] is destroyed in the game's lifecycle, the "
+"connection will be lost.\n"
+"Examples:\n"
+"[codeblock]\n"
+"connect(\"pressed\", self, \"_on_Button_pressed\") # BaseButton signal\n"
+"connect(\"text_entered\", self, \"_on_LineEdit_text_entered\") # LineEdit "
+"signal\n"
+"connect(\"hit\", self, \"_on_Player_hit\", [ weapon_type, damage ]) # User-"
+"defined signal\n"
+"[/codeblock]\n"
+"An example of the relationship between [code]binds[/code] passed to [method "
+"connect] and parameters used when calling [method emit_signal]:\n"
+"[codeblock]\n"
+"connect(\"hit\", self, \"_on_Player_hit\", [ weapon_type, damage ]) # "
+"weapon_type and damage are passed last\n"
+"emit_signal(\"hit\", \"Dark lord\", 5) # \"Dark lord\" and 5 are passed "
+"first\n"
+"func _on_Player_hit(hit_by, level, weapon_type, damage):\n"
+" print(\"Hit by %s (lvl %d) with weapon %s for %d damage\" % [hit_by, "
+"level, weapon_type, damage])\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:173
+msgid ""
+"[b]FIXME:[/b] The syntax changed with the addition of [Callable], this "
+"should be updated.\n"
+"Disconnects a [code]signal[/code] from a [code]method[/code] on the given "
+"[code]target[/code].\n"
+"If you try to disconnect a connection that does not exist, the method will "
+"throw an error. Use [method is_connected] to ensure that the connection "
+"exists."
+msgstr ""
+
+#: doc/classes/Object.xml:184
+msgid ""
+"Emits the given [code]signal[/code]. The signal must exist, so it should be "
+"a built-in signal of this class or one of its parent classes, or a user-"
+"defined signal. This method supports a variable number of arguments, so "
+"parameters are passed as a comma separated list. Example:\n"
+"[codeblock]\n"
+"emit_signal(\"hit\", weapon_type, damage)\n"
+"emit_signal(\"game_over\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:195
+msgid ""
+"Deletes the object from memory. Any pre-existing reference to the freed "
+"object will now return [code]null[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:204
+msgid ""
+"Returns the [Variant] value of the given [code]property[/code]. If the "
+"[code]property[/code] doesn't exist, this will return [code]null[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:211
+msgid "Returns the object's class as a [String]."
+msgstr ""
+
+#: doc/classes/Object.xml:218
+msgid ""
+"Returns an [Array] of dictionaries with information about signals that are "
+"connected to the object.\n"
+"Each [Dictionary] contains three String entries:\n"
+"- [code]source[/code] is a reference to the signal emitter.\n"
+"- [code]signal_name[/code] is the name of the connected signal.\n"
+"- [code]method_name[/code] is the name of the method to which the signal is "
+"connected."
+msgstr ""
+
+#: doc/classes/Object.xml:231
+msgid ""
+"Gets the object's property indexed by the given [NodePath]. The node path "
+"should be relative to the current object and can use the colon character "
+"([code]:[/code]) to access nested properties. Examples: [code]\"position:x"
+"\"[/code] or [code]\"material:next_pass:blend_mode\"[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:238
+msgid ""
+"Returns the object's unique instance ID.\n"
+"This ID can be saved in [EncodedObjectAsID], and can be used to retrieve the "
+"object instance with [method @GDScript.instance_from_id]."
+msgstr ""
+
+#: doc/classes/Object.xml:248
+msgid "Returns the object's metadata entry for the given [code]name[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:255
+msgid "Returns the object's metadata as a [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/Object.xml:262
+msgid "Returns the object's methods and their signatures as an [Array]."
+msgstr ""
+
+#: doc/classes/Object.xml:269
+msgid ""
+"Returns the object's property list as an [Array] of dictionaries.\n"
+"Each property's [Dictionary] contain at least [code]name: String[/code] and "
+"[code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it can "
+"also include [code]hint: int[/code] (see [enum PropertyHint]), "
+"[code]hint_string: String[/code], and [code]usage: int[/code] (see [enum "
+"PropertyUsageFlags])."
+msgstr ""
+
+#: doc/classes/Object.xml:277
+msgid ""
+"Returns the object's [Script] instance, or [code]null[/code] if none is "
+"assigned."
+msgstr ""
+
+#: doc/classes/Object.xml:286
+msgid "Returns an [Array] of connections for the given [code]signal[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:293
+msgid "Returns the list of signals as an [Array] of dictionaries."
+msgstr ""
+
+#: doc/classes/Object.xml:302
+msgid ""
+"Returns [code]true[/code] if a metadata entry is found with the given "
+"[code]name[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:311
+msgid ""
+"Returns [code]true[/code] if the object contains the given [code]method[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Object.xml:320
+msgid "Returns [code]true[/code] if the given [code]signal[/code] exists."
+msgstr ""
+
+#: doc/classes/Object.xml:329
+msgid ""
+"Returns [code]true[/code] if the given user-defined [code]signal[/code] "
+"exists. Only signals added using [method add_user_signal] are taken into "
+"account."
+msgstr ""
+
+#: doc/classes/Object.xml:336
+msgid "Returns [code]true[/code] if signal emission blocking is enabled."
+msgstr ""
+
+#: doc/classes/Object.xml:345
+msgid ""
+"Returns [code]true[/code] if the object inherits from the given [code]class[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Object.xml:356
+msgid ""
+"[b]FIXME:[/b] The syntax changed with the addition of [Callable], this "
+"should be updated.\n"
+"Returns [code]true[/code] if a connection exists for a given [code]signal[/"
+"code], [code]target[/code], and [code]method[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:364
+msgid ""
+"Returns [code]true[/code] if the [method Node.queue_free] method was called "
+"for the object."
+msgstr ""
+
+#: doc/classes/Object.xml:375
+msgid ""
+"Send a given notification to the object, which will also trigger a call to "
+"the [method _notification] method of all classes that the object inherits "
+"from.\n"
+"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."
+msgstr ""
+
+#: doc/classes/Object.xml:383
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Object.xml:392
+msgid "Removes a given entry from the object's metadata."
+msgstr ""
+
+#: doc/classes/Object.xml:403
+msgid ""
+"Assigns a new value to the given property. If the [code]property[/code] does "
+"not exist, nothing will happen."
+msgstr ""
+
+#: doc/classes/Object.xml:412
+msgid "If set to [code]true[/code], signal emission is blocked."
+msgstr ""
+
+#: doc/classes/Object.xml:423
+msgid ""
+"Assigns a new value to the given property, after the current frame's physics "
+"step. This is equivalent to calling [method set] via [method call_deferred], "
+"i.e. [code]call_deferred(\"set\", property, value)[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:434
+msgid ""
+"Assigns a new value to the property identified by the [NodePath]. The node "
+"path should be relative to the current object and can use the colon "
+"character ([code]:[/code]) to access nested properties. Example:\n"
+"[codeblock]\n"
+"set_indexed(\"position\", Vector2(42, 0))\n"
+"set_indexed(\"position:y\", -10)\n"
+"print(position) # (42, -10)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:448
+msgid ""
+"Defines whether the object can translate strings (with calls to [method "
+"tr]). Enabled by default."
+msgstr ""
+
+#: doc/classes/Object.xml:459
+msgid ""
+"Adds or changes a given entry in the object's metadata. Metadata are "
+"serialized, and can take any [Variant] value."
+msgstr ""
+
+#: doc/classes/Object.xml:468
+msgid ""
+"Assigns a script to the object. Each object can have a single script "
+"assigned to it, which are used to extend its functionality.\n"
+"If the object already had a script, the previous script instance will be "
+"freed and its variables and state will be lost. The new script's [method "
+"_init] method will be called."
+msgstr ""
+
+#: doc/classes/Object.xml:476
+msgid ""
+"Returns a [String] representing the object. If not overridden, defaults to "
+"[code]\"[ClassName:RID]\"[/code].\n"
+"Override the method [method _to_string] to customize the [String] "
+"representation."
+msgstr ""
+
+#: doc/classes/Object.xml:486
+msgid ""
+"Translates a message using translation catalogs configured in the Project "
+"Settings.\n"
+"Only works if message translation is enabled (which it is by default), "
+"otherwise it returns the [code]message[/code] unchanged. See [method "
+"set_message_translation]."
+msgstr ""
+
+#: doc/classes/Object.xml:494
+msgid "Emitted whenever the object's script is changed."
+msgstr ""
+
+#: doc/classes/Object.xml:500
+msgid "Called right when the object is initialized. Not available in script."
+msgstr ""
+
+#: doc/classes/Object.xml:503
+msgid "Called before the object is about to be deleted."
+msgstr ""
+
+#: doc/classes/Object.xml:506
+msgid ""
+"Connects a signal in deferred mode. This way, signal emissions are stored in "
+"a queue, then set on idle time."
+msgstr ""
+
+#: doc/classes/Object.xml:509
+msgid "Persisting connections are saved when the object is serialized to file."
+msgstr ""
+
+#: doc/classes/Object.xml:512
+msgid "One-shot connections disconnect themselves after emission."
+msgstr ""
+
+#: doc/classes/Object.xml:515
+msgid ""
+"Connect a signal as reference counted. This means that a given signal can be "
+"connected several times to the same target, and will only be fully "
+"disconnected once no references are left."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:4
+msgid "Defines a 2D polygon for LightOccluder2D."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:7
+msgid ""
+"Editor facility that helps you draw a 2D polygon used as resource for "
+"[LightOccluder2D]."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:15
+msgid ""
+"If [code]true[/code], closes the polygon. A closed OccluderPolygon2D "
+"occludes the light coming from any direction. An opened OccluderPolygon2D "
+"occludes the light only at its outline's direction."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:18
+msgid "The culling mode to use."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:21
+msgid ""
+"A [Vector2] array with the index for polygon's vertices positions.\n"
+"[b]Note:[/b] The returned value is a copy of the underlying array, rather "
+"than a reference."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:27
+msgid "Culling is disabled. See [member cull_mode]."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:30
+msgid ""
+"Culling is performed in the clockwise direction. See [member cull_mode]."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:33
+msgid ""
+"Culling is performed in the counterclockwise direction. See [member "
+"cull_mode]."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:4
+msgid "Omnidirectional light, such as a light bulb or a candle."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:7
+msgid ""
+"An Omnidirectional light is a type of [Light3D] that emits light in all "
+"directions. The light is attenuated by distance and this attenuation can be "
+"configured by changing its energy, radius, and attenuation parameters."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:16
+msgid ""
+"The light's attenuation (drop-off) curve. A number of presets are available "
+"in the [b]Inspector[/b] by right-clicking the curve."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:19
+msgid "The light's radius."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:22
+msgid "See [enum ShadowMode]."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:27
+msgid ""
+"Shadows are rendered to a dual-paraboloid texture. Faster than [constant "
+"SHADOW_CUBE], but lower-quality."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:30
+msgid ""
+"Shadows are rendered to a cubemap. Slower than [constant "
+"SHADOW_DUAL_PARABOLOID], but higher-quality."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:4
+msgid "Noise generator based on Open Simplex."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:7
+msgid ""
+"This resource allows you to configure and sample a fractal noise space. Here "
+"is a brief usage example that configures an OpenSimplexNoise and gets "
+"samples at various positions and dimensions:\n"
+"[codeblock]\n"
+"var noise = OpenSimplexNoise.new()\n"
+"\n"
+"# Configure\n"
+"noise.seed = randi()\n"
+"noise.octaves = 4\n"
+"noise.period = 20.0\n"
+"noise.persistence = 0.8\n"
+"\n"
+"# Sample\n"
+"print(\"Values:\")\n"
+"print(noise.get_noise_2d(1.0, 1.0))\n"
+"print(noise.get_noise_3d(0.5, 3.0, 15.0))\n"
+"print(noise.get_noise_4d(0.5, 1.9, 4.7, 0.0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:35
+msgid ""
+"Generate a noise image with the requested [code]width[/code] and "
+"[code]height[/code], based on the current noise parameters."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:44
+msgid ""
+"Returns the 1D noise value [code][-1,1][/code] at the given x-coordinate.\n"
+"[b]Note:[/b] This method actually returns the 2D noise value [code][-1,1][/"
+"code] with fixed y-coordinate value 0.0."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:56
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:65
+msgid "Returns the 2D noise value [code][-1,1][/code] at the given position."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:78
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:87
+msgid "Returns the 3D noise value [code][-1,1][/code] at the given position."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:102
+msgid "Returns the 4D noise value [code][-1,1][/code] at the given position."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:111
+msgid ""
+"Generate a tileable noise image, based on the current noise parameters. "
+"Generated seamless images are always square ([code]size[/code] × [code]size[/"
+"code])."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:117
+msgid "Difference in period between [member octaves]."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:120
+msgid ""
+"Number of OpenSimplex noise layers that are sampled to get the fractal "
+"noise. Higher values result in more detailed noise but take more time to "
+"generate.\n"
+"[b]Note:[/b] The maximum allowed value is 9."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:124
+msgid ""
+"Period of the base octave. A lower period results in a higher-frequency "
+"noise (more value changes across the same distance)."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:127
+msgid ""
+"Contribution factor of the different octaves. A [code]persistence[/code] "
+"value of 1 means all the octaves have the same contribution, a value of 0.5 "
+"means each octave contributes half as much as the previous one."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:130
+msgid ""
+"Seed used to generate random values, different seeds will generate different "
+"noise maps."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:4
+msgid "Button control that provides selectable options when pressed."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:7
+msgid ""
+"OptionButton is a type button that provides a selectable list of items when "
+"pressed. The item selected becomes the \"current\" item and is displayed as "
+"the button text."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:22
+msgid ""
+"Adds an item, with a [code]texture[/code] icon, text [code]label[/code] and "
+"(optionally) [code]id[/code]. If no [code]id[/code] is passed, the item "
+"index will be used as the item's ID. New items are appended at the end."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:33
+msgid ""
+"Adds an item, with text [code]label[/code] and (optionally) [code]id[/code]. "
+"If no [code]id[/code] is passed, the item index will be used as the item's "
+"ID. New items are appended at the end."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:40
+msgid ""
+"Adds a separator to the list of items. Separators help to group items. "
+"Separator also takes up an index and is appended at the end."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:47
+msgid "Clears all the items in the [OptionButton]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:54
+msgid "Returns the amount of items in the OptionButton, including separators."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:63 doc/classes/PopupMenu.xml:267
+msgid "Returns the icon of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:72
+msgid "Returns the ID of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:81
+msgid "Returns the index of the item with the given [code]id[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:90
+msgid ""
+"Retrieves the metadata of an item. Metadata may be any type and can be used "
+"to store extra information about an item, such as an external string ID."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:99 doc/classes/PopupMenu.xml:321
+msgid "Returns the text of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:113
+msgid ""
+"Returns the ID of the selected item, or [code]0[/code] if no item is "
+"selected."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:120
+msgid ""
+"Gets the metadata of the selected item. Metadata for items can be set using "
+"[method set_item_metadata]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:129
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:138
+msgid "Removes the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:147
+msgid ""
+"Selects an item by index and makes it the current item. This will work even "
+"if the item is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:158
+msgid ""
+"Sets whether the item at index [code]idx[/code] is disabled.\n"
+"Disabled items are drawn differently in the dropdown and are not selectable "
+"by the user. If the current selected item is set as disabled, it will remain "
+"selected."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:170
+msgid "Sets the icon of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:181
+msgid "Sets the ID of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:192
+msgid ""
+"Sets the metadata of an item. Metadata may be of any type and can be used to "
+"store extra information about an item, such as an external string ID."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:203 doc/classes/PopupMenu.xml:554
+msgid "Sets the text of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:211
+msgid ""
+"The index of the currently selected item, or [code]-1[/code] if no item is "
+"selected."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:220
+msgid ""
+"Emitted the when user navigates to an item using the [code]ui_up[/code] or "
+"[code]ui_down[/code] actions. The index of the item selected is passed as "
+"argument."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:227
+msgid ""
+"Emitted when the current item has been changed by the user. The index of the "
+"item selected is passed as argument."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:235
+msgid "The arrow icon to be drawn on the right end of the button."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:238
+msgid ""
+"The horizontal space between the arrow icon and the right edge of the button."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:241
+msgid "[StyleBox] used when the [OptionButton] is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:244
+msgid ""
+"[StyleBox] used when the [OptionButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:247
+msgid "[Font] of the [OptionButton]'s text."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:250
+msgid "Default text [Color] of the [OptionButton]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:253
+msgid "Text [Color] used when the [OptionButton] is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:256
+msgid "Text [Color] used when the [OptionButton] is being hovered."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:259
+msgid "Text [Color] used when the [OptionButton] is being pressed."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:262
+msgid "[StyleBox] used when the [OptionButton] is being hovered."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:265
+msgid "The horizontal space between [OptionButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:268
+msgid "Default [StyleBox] for the [OptionButton]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:271
+msgid "[StyleBox] used when the [OptionButton] is being pressed."
+msgstr ""
+
+#: doc/classes/OS.xml:4
+msgid "Operating System functions."
+msgstr ""
+
+#: doc/classes/OS.xml:7
+msgid ""
+"Operating System functions. OS wraps the most common functionality to "
+"communicate with the host operating system, such as the clipboard, video "
+"driver, date and time, timers, environment variables, execution of binaries, "
+"command line, etc."
+msgstr ""
+
+#: doc/classes/OS.xml:16
+msgid ""
+"Returns [code]true[/code] if the current host platform is using multiple "
+"threads."
+msgstr ""
+
+#: doc/classes/OS.xml:23
+msgid ""
+"Shuts down system MIDI driver.\n"
+"[b]Note:[/b] This method is implemented on Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:33
+msgid ""
+"Delay execution of the current thread by [code]msec[/code] milliseconds."
+msgstr ""
+
+#: doc/classes/OS.xml:42
+msgid ""
+"Delay execution of the current thread by [code]usec[/code] microseconds."
+msgstr ""
+
+#: doc/classes/OS.xml:51
+msgid ""
+"Dumps the memory allocation ringlist to a file (only works in debug).\n"
+"Entry format per line: \"Address - Size - Description\"."
+msgstr ""
+
+#: doc/classes/OS.xml:61
+msgid ""
+"Dumps all used resources to file (only works in debug).\n"
+"Entry format per line: \"Resource Type : Resource Location\".\n"
+"At the end of the file is a statistic of all used Resource Types."
+msgstr ""
+
+#: doc/classes/OS.xml:80
+msgid ""
+"Execute the file at the given path with the arguments passed as an array of "
+"strings. Platform path resolution will take place. The resolved file must "
+"exist and be executable.\n"
+"The arguments are used in the given order and separated by a space, so "
+"[code]OS.execute(\"ping\", [\"-w\", \"3\", \"godotengine.org\"], false)[/"
+"code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's "
+"shell.\n"
+"This method has slightly different behavior based on whether the "
+"[code]blocking[/code] mode is enabled.\n"
+"If [code]blocking[/code] is [code]true[/code], the Godot thread will pause "
+"its execution while waiting for the process to terminate. The shell output "
+"of the process will be written to the [code]output[/code] array as a single "
+"string. When the process terminates, the Godot thread will resume "
+"execution.\n"
+"If [code]blocking[/code] is [code]false[/code], the Godot thread will "
+"continue while the new process runs. It is not possible to retrieve the "
+"shell output in non-blocking mode, so [code]output[/code] will be empty.\n"
+"The return value also depends on the blocking mode. When blocking, the "
+"method will return an exit code of the process. When non-blocking, the "
+"method returns a process ID, which you can use to monitor the process (and "
+"potentially terminate it with [method kill]). If the process forking (non-"
+"blocking) or opening (blocking) fails, the method will return [code]-1[/"
+"code] or another exit code.\n"
+"Example of blocking mode and retrieving the shell output:\n"
+"[codeblock]\n"
+"var output = []\n"
+"var exit_code = OS.execute(\"ls\", [\"-l\", \"/tmp\"], true, output)\n"
+"[/codeblock]\n"
+"Example of non-blocking mode, running another instance of the project and "
+"storing its process ID:\n"
+"[codeblock]\n"
+"var pid = OS.execute(OS.get_executable_path(), [], false)\n"
+"[/codeblock]\n"
+"If you wish to access a shell built-in or perform a composite command, a "
+"platform-specific shell can be invoked. For example:\n"
+"[codeblock]\n"
+"OS.execute(\"CMD.exe\", [\"/C\", \"cd %TEMP% && dir\"], true, output)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and "
+"Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:108
+msgid "Returns the keycode of the given string (e.g. \"Escape\")."
+msgstr ""
+
+#: doc/classes/OS.xml:115
+msgid "Returns the command line arguments passed to the engine."
+msgstr ""
+
+#: doc/classes/OS.xml:122
+msgid ""
+"Returns an array of MIDI device names.\n"
+"The returned array will be empty if the system MIDI driver has not "
+"previously been initialised with [method open_midi_inputs].\n"
+"[b]Note:[/b] This method is implemented on Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:133
+msgid ""
+"Returns current date as a dictionary of keys: [code]year[/code], "
+"[code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] "
+"(Daylight Savings Time)."
+msgstr ""
+
+#: doc/classes/OS.xml:142
+msgid ""
+"Returns current datetime as a dictionary of keys: [code]year[/code], "
+"[code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] "
+"(Daylight Savings Time), [code]hour[/code], [code]minute[/code], "
+"[code]second[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:151
+msgid ""
+"Gets a dictionary of time values corresponding to the given UNIX epoch time "
+"(in seconds).\n"
+"The returned Dictionary's values will be the same as [method get_datetime], "
+"with the exception of Daylight Savings Time as it cannot be determined from "
+"the epoch."
+msgstr ""
+
+#: doc/classes/OS.xml:161
+msgid "Returns an environment variable."
+msgstr ""
+
+#: doc/classes/OS.xml:168
+msgid "Returns the path to the current engine executable."
+msgstr ""
+
+#: doc/classes/OS.xml:175
+msgid ""
+"With this function you can get the list of dangerous permissions that have "
+"been granted to the Android application.\n"
+"[b]Note:[/b] This method is implemented on Android."
+msgstr ""
+
+#: doc/classes/OS.xml:185
+msgid ""
+"Returns the given keycode as a string (e.g. Return values: [code]\"Escape\"[/"
+"code], [code]\"Shift+Escape\"[/code]).\n"
+"See also [member InputEventKey.keycode] and [method InputEventKey."
+"get_keycode_with_modifiers]."
+msgstr ""
+
+#: doc/classes/OS.xml:193
+msgid "Returns the host OS locale."
+msgstr ""
+
+#: doc/classes/OS.xml:200
+msgid ""
+"Returns the model name of the current device.\n"
+"[b]Note:[/b] This method is implemented on Android and iOS. Returns "
+"[code]\"GenericDevice\"[/code] on unsupported platforms."
+msgstr ""
+
+#: doc/classes/OS.xml:208
+msgid ""
+"Returns the name of the host OS. Possible values are: [code]\"Android\"[/"
+"code], [code]\"Haiku\"[/code], [code]\"iOS\"[/code], [code]\"HTML5\"[/code], "
+"[code]\"OSX\"[/code], [code]\"Server\"[/code], [code]\"Windows\"[/code], "
+"[code]\"UWP\"[/code], [code]\"X11\"[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:215
+msgid ""
+"Returns the project's process ID.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and "
+"Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:223
+msgid "Returns the number of threads available on the host machine."
+msgstr ""
+
+#: doc/classes/OS.xml:230
+msgid ""
+"Returns the amount of time in milliseconds it took for the boot logo to "
+"appear."
+msgstr ""
+
+#: doc/classes/OS.xml:237
+msgid "Returns the maximum amount of static memory used (only works in debug)."
+msgstr ""
+
+#: doc/classes/OS.xml:244
+msgid "Returns the amount of static memory being used by the program in bytes."
+msgstr ""
+
+#: doc/classes/OS.xml:253
+msgid ""
+"Returns the actual path to commonly used folders across different platforms. "
+"Available locations are specified in [enum SystemDir].\n"
+"[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:261
+msgid "Returns the epoch time of the operating system in milliseconds."
+msgstr ""
+
+#: doc/classes/OS.xml:268
+msgid "Returns the epoch time of the operating system in seconds."
+msgstr ""
+
+#: doc/classes/OS.xml:275
+msgid ""
+"Returns the amount of time passed in milliseconds since the engine started."
+msgstr ""
+
+#: doc/classes/OS.xml:282
+msgid ""
+"Returns the amount of time passed in microseconds since the engine started."
+msgstr ""
+
+#: doc/classes/OS.xml:291
+msgid "Returns current time as a dictionary of keys: hour, minute, second."
+msgstr ""
+
+#: doc/classes/OS.xml:298
+msgid ""
+"Returns the current time zone as a dictionary with the keys: bias and name."
+msgstr ""
+
+#: doc/classes/OS.xml:305
+msgid ""
+"Returns a string that is unique to the device.\n"
+"[b]Note:[/b] Returns an empty string on HTML5 and UWP, as this method isn't "
+"implemented on those platforms yet."
+msgstr ""
+
+#: doc/classes/OS.xml:313
+msgid "Returns the current UNIX epoch timestamp."
+msgstr ""
+
+#: doc/classes/OS.xml:322
+msgid ""
+"Gets an epoch time value from a dictionary of time values.\n"
+"[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].\n"
+"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."
+msgstr ""
+
+#: doc/classes/OS.xml:331
+msgid ""
+"Returns the absolute directory path where user data is written ([code]user://"
+"[/code]).\n"
+"On Linux, this is [code]~/.local/share/godot/app_userdata/[project_name][/"
+"code], or [code]~/.local/share/[custom_name][/code] if "
+"[code]use_custom_user_dir[/code] is set.\n"
+"On macOS, this is [code]~/Library/Application Support/Godot/app_userdata/"
+"[project_name][/code], or [code]~/Library/Application Support/[custom_name][/"
+"code] if [code]use_custom_user_dir[/code] is set.\n"
+"On Windows, this is [code]%APPDATA%\\Godot\\app_userdata\\[project_name][/"
+"code], or [code]%APPDATA%\\[custom_name][/code] if "
+"[code]use_custom_user_dir[/code] is set. [code]%APPDATA%[/code] expands to "
+"[code]%USERPROFILE%\\AppData\\Roaming[/code].\n"
+"If the project name is empty, [code]user://[/code] falls back to [code]res://"
+"[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:344
+msgid "Returns [code]true[/code] if an environment variable exists."
+msgstr ""
+
+#: doc/classes/OS.xml:353
+msgid ""
+"Returns [code]true[/code] if the feature for the given feature tag is "
+"supported in the currently running instance, depending on platform, build "
+"etc. Can be used to check whether you're currently running a debug build, on "
+"a certain platform or arch, etc. Refer to the [url=https://docs.godotengine."
+"org/en/latest/getting_started/workflow/export/feature_tags.html]Feature "
+"Tags[/url] documentation for more details.\n"
+"[b]Note:[/b] Tag names are case-sensitive."
+msgstr ""
+
+#: doc/classes/OS.xml:361
+msgid ""
+"Returns [code]true[/code] if the Godot binary used to run the project is a "
+"[i]debug[/i] export template, or when running in the editor.\n"
+"Returns [code]false[/code] if the Godot binary used to run the project is a "
+"[i]release[/i] export template.\n"
+"To check whether the Godot binary used to run the project is an export "
+"template (debug or release), use [code]OS.has_feature(\"standalone\")[/code] "
+"instead."
+msgstr ""
+
+#: doc/classes/OS.xml:372
+msgid ""
+"Returns [code]true[/code] if the input keycode corresponds to a Unicode "
+"character."
+msgstr ""
+
+#: doc/classes/OS.xml:379
+msgid ""
+"Returns [code]true[/code] if the engine was executed with [code]-v[/code] "
+"(verbose stdout)."
+msgstr ""
+
+#: doc/classes/OS.xml:386
+msgid ""
+"If [code]true[/code], the [code]user://[/code] file system is persistent, so "
+"that its state is the same after a player quits and starts the game again. "
+"Relevant to the HTML5 platform, where this persistence may be unavailable."
+msgstr ""
+
+#: doc/classes/OS.xml:395
+msgid ""
+"Kill (terminate) the process identified by the given process ID ([code]pid[/"
+"code]), e.g. the one returned by [method execute] in non-blocking mode.\n"
+"[b]Note:[/b] This method can also be used to kill processes that were not "
+"spawned by the game.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and "
+"Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:404
+msgid ""
+"Initialises the singleton for the system MIDI driver.\n"
+"[b]Note:[/b] This method is implemented on Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:414
+msgid ""
+"Shows all resources in the game. Optionally, the list can be written to a "
+"file by specifying a file path in [code]tofile[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:421
+msgid "Shows the list of loaded textures sorted by size in memory."
+msgstr ""
+
+#: doc/classes/OS.xml:430
+msgid "Shows the number of resources loaded by the game of the given types."
+msgstr ""
+
+#: doc/classes/OS.xml:439
+msgid "Shows all resources currently used by the game."
+msgstr ""
+
+#: doc/classes/OS.xml:448
+msgid ""
+"At the moment this function is only used by [code]AudioDriverOpenSL[/code] "
+"to request permission for [code]RECORD_AUDIO[/code] on Android."
+msgstr ""
+
+#: doc/classes/OS.xml:455
+msgid ""
+"With this function you can request dangerous permissions since normal "
+"permissions are automatically granted at install time in Android "
+"application.\n"
+"[b]Note:[/b] This method is implemented on Android."
+msgstr ""
+
+#: doc/classes/OS.xml:465
+msgid "Sets the name of the current thread."
+msgstr ""
+
+#: doc/classes/OS.xml:474
+msgid "Enables backup saves if [code]enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:483
+msgid ""
+"Requests the OS to open a resource with the most appropriate program. For "
+"example:\n"
+"- [code]OS.shell_open(\"C:\\\\Users\\name\\Downloads\")[/code] on Windows "
+"opens the file explorer at the user's Downloads folder.\n"
+"- [code]OS.shell_open(\"https://godotengine.org\")[/code] opens the default "
+"web browser on the official Godot website.\n"
+"- [code]OS.shell_open(\"mailto:example@example.com\")[/code] opens the "
+"default email client with the \"To\" field set to [code]example@example.com[/"
+"code]. See [url=https://blog.escapecreative.com/customizing-mailto-"
+"links/]Customizing [code]mailto:[/code] Links[/url] for a list of fields "
+"that can be added.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS "
+"and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:493
+msgid ""
+"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).\n"
+"[b]Note:[/b] This value will be ignored if using [method SceneTree.quit] "
+"with an [code]exit_code[/code] argument passed."
+msgstr ""
+
+#: doc/classes/OS.xml:497
+msgid ""
+"If [code]true[/code], the engine optimizes for low processor usage by only "
+"refreshing the screen if needed. Can improve battery consumption on mobile."
+msgstr ""
+
+#: doc/classes/OS.xml:500
+msgid ""
+"The amount of sleeping between frames when the low-processor usage mode is "
+"enabled (in microseconds). Higher values will result in lower CPU usage."
+msgstr ""
+
+#: doc/classes/OS.xml:505
+msgid ""
+"The GLES2 rendering backend. It uses OpenGL ES 2.0 on mobile devices, OpenGL "
+"2.1 on desktop platforms and WebGL 1.0 on the web."
+msgstr ""
+
+#: doc/classes/OS.xml:508
+msgid "The Vulkan rendering backend."
+msgstr ""
+
+#: doc/classes/OS.xml:511
+msgid "Sunday."
+msgstr ""
+
+#: doc/classes/OS.xml:514
+msgid "Monday."
+msgstr ""
+
+#: doc/classes/OS.xml:517
+msgid "Tuesday."
+msgstr ""
+
+#: doc/classes/OS.xml:520
+msgid "Wednesday."
+msgstr ""
+
+#: doc/classes/OS.xml:523
+msgid "Thursday."
+msgstr ""
+
+#: doc/classes/OS.xml:526
+msgid "Friday."
+msgstr ""
+
+#: doc/classes/OS.xml:529
+msgid "Saturday."
+msgstr ""
+
+#: doc/classes/OS.xml:532
+msgid "January."
+msgstr ""
+
+#: doc/classes/OS.xml:535
+msgid "February."
+msgstr ""
+
+#: doc/classes/OS.xml:538
+msgid "March."
+msgstr ""
+
+#: doc/classes/OS.xml:541
+msgid "April."
+msgstr ""
+
+#: doc/classes/OS.xml:544
+msgid "May."
+msgstr ""
+
+#: doc/classes/OS.xml:547
+msgid "June."
+msgstr ""
+
+#: doc/classes/OS.xml:550
+msgid "July."
+msgstr ""
+
+#: doc/classes/OS.xml:553
+msgid "August."
+msgstr ""
+
+#: doc/classes/OS.xml:556
+msgid "September."
+msgstr ""
+
+#: doc/classes/OS.xml:559
+msgid "October."
+msgstr ""
+
+#: doc/classes/OS.xml:562
+msgid "November."
+msgstr ""
+
+#: doc/classes/OS.xml:565
+msgid "December."
+msgstr ""
+
+#: doc/classes/OS.xml:568
+msgid "Desktop directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:571
+msgid "DCIM (Digital Camera Images) directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:574
+msgid "Documents directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:577
+msgid "Downloads directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:580
+msgid "Movies directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:583
+msgid "Music directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:586
+msgid "Pictures directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:589
+msgid "Ringtones directory path."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:4
+msgid "A packed [Array] of bytes."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:7
+msgid ""
+"An [Array] specifically designed to hold bytes. Packs data tightly, so it "
+"saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:19
+msgid ""
+"Constructs a new [PackedByteArray]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:37
+msgid "Appends a [PackedByteArray] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:46
+msgid ""
+"Returns a new [PackedByteArray] with the data compressed. Set the "
+"compression mode using one of [enum File.CompressionMode]'s constants."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:57
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:71
+msgid ""
+"Returns a copy of the array's contents as [String]. Fast alternative to "
+"[method get_string_from_utf8] if the content is ASCII-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]."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:78
+msgid ""
+"Returns a copy of the array's contents as [String]. Slower than [method "
+"get_string_from_ascii] but supports UTF-8 encoded data. Use this function if "
+"you are unsure about the source of the data. For user input this function "
+"should always be preferred."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:85
+msgid ""
+"Returns a hexadecimal representation of this array as a [String].\n"
+"[codeblock]\n"
+"var array = PackedByteArray([11, 46, 255])\n"
+"print(array.hex_encode()) # Prints: 0b2eff\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:100 doc/classes/PackedColorArray.xml:55
+#: doc/classes/PackedFloat32Array.xml:56 doc/classes/PackedFloat64Array.xml:56
+#: doc/classes/PackedStringArray.xml:55 doc/classes/PackedVector2Array.xml:55
+#: doc/classes/PackedVector3Array.xml:55
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:134 doc/classes/PackedColorArray.xml:89
+#: doc/classes/PackedFloat32Array.xml:90 doc/classes/PackedFloat64Array.xml:90
+#: doc/classes/PackedInt32Array.xml:90 doc/classes/PackedInt64Array.xml:90
+#: doc/classes/PackedStringArray.xml:89 doc/classes/PackedVector2Array.xml:89
+#: doc/classes/PackedVector3Array.xml:89
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:145
+msgid "Changes the byte at the given index."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:152 doc/classes/PackedColorArray.xml:107
+#: doc/classes/PackedFloat32Array.xml:108
+#: doc/classes/PackedFloat64Array.xml:108 doc/classes/PackedStringArray.xml:107
+#: doc/classes/PackedVector2Array.xml:107
+#: doc/classes/PackedVector3Array.xml:107
+msgid "Returns the size of the array."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:163
+msgid ""
+"Returns the slice of the [PackedByteArray] between indices (inclusive) as a "
+"new [PackedByteArray]. Any negative index is considered to be from the end "
+"of the array."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:4
+msgid "A packed [Array] of [Color]s."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:7
+msgid ""
+"An [Array] specifically designed to hold [Color]. Packs data tightly, so it "
+"saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:19
+msgid ""
+"Constructs a new [PackedColorArray]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:37
+msgid "Appends a [PackedColorArray] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:71 doc/classes/PackedInt32Array.xml:72
+#: doc/classes/PackedInt64Array.xml:72
+msgid "Appends a value to the array."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:100
+msgid "Changes the [Color] at the given index."
+msgstr ""
+
+#: doc/classes/PackedDataContainerRef.xml:4
+msgid "Reference version of [PackedDataContainer]."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:4
+msgid "A packed [Array] of 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 32-bit floating-point values. Packs "
+"data tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"If you need to pack 64-bit floats tightly, see [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:20
+msgid ""
+"Constructs a new [PackedFloat32Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:38
+msgid "Appends a [PackedFloat32Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:101
+#: doc/classes/PackedFloat64Array.xml:101
+msgid "Changes the float at the given index."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:4
+msgid "A packed [Array] of 64-bit floating-point values."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 64-bit floating-point values. Packs "
+"data tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"If you only need to pack 32-bit floats tightly, see [PackedFloat32Array] for "
+"a more memory-friendly alternative."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:20
+msgid ""
+"Constructs a new [PackedFloat64Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:38
+msgid "Appends a [PackedFloat64Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:4
+msgid "A packed [Array] of 32-bit integers."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 32-bit integer values. Packs data "
+"tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"[b]Note:[/b] This type stores signed 32-bit integers, which means it can "
+"take values in the interval [code][-2^31, 2^31 - 1][/code], i.e. [code]"
+"[-2147483648, 2147483647][/code]. Exceeding those bounds will wrap around. "
+"In comparison, [int] uses signed 64-bit integers which can hold much larger "
+"values. If you need to pack 64-bit integers tightly, see [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:20
+msgid ""
+"Constructs a new [PackedInt32Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:38
+msgid "Appends a [PackedInt32Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:56 doc/classes/PackedInt64Array.xml:56
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:101 doc/classes/PackedInt64Array.xml:101
+msgid "Changes the integer at the given index."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:108 doc/classes/PackedInt64Array.xml:108
+msgid "Returns the array size."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:4
+msgid "A packed [Array] of 64-bit integers."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 64-bit integer values. Packs data "
+"tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"[b]Note:[/b] This type stores signed 64-bit integers, which means it can "
+"take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. [code]"
+"[-9223372036854775808, 9223372036854775807][/code]. Exceeding those bounds "
+"will wrap around. If you only need to pack 32-bit integers tightly, see "
+"[PackedInt32Array] for a more memory-friendly alternative."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:20
+msgid ""
+"Constructs a new [PackedInt64Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:38
+msgid "Appends a [PackedInt64Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:4
+msgid "An abstraction of a serialized scene."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:7
+msgid ""
+"A simplified interface to a scene file. Provides access to operations and "
+"checks that can be performed on the scene resource itself.\n"
+"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]).\n"
+"[b]Note:[/b] The node doesn't need to own itself.\n"
+"[b]Example of saving a node with different owners:[/b] The following example "
+"creates 3 objects: [code]Node2D[/code] ([code]node[/code]), "
+"[code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/"
+"code] ([code]collision[/code]). [code]collision[/code] is a child of "
+"[code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/"
+"code] is owned by [code]node[/code] and [code]pack[/code] will therefore "
+"only save those two nodes, but not [code]collision[/code].\n"
+"[codeblock]\n"
+"# Create the objects\n"
+"var node = Node2D.new()\n"
+"var rigid = RigidBody2D.new()\n"
+"var collision = CollisionShape2D.new()\n"
+"\n"
+"# Create the object hierarchy\n"
+"rigid.add_child(collision)\n"
+"node.add_child(rigid)\n"
+"\n"
+"# Change owner of rigid, but not of collision\n"
+"rigid.owner = node\n"
+"\n"
+"var scene = PackedScene.new()\n"
+"# Only node and rigid are now packed\n"
+"var result = scene.pack(node)\n"
+"if result == OK:\n"
+" ResourceSaver.save(\"res://path/name.scn\", scene) # Or \"user://...\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/PackedScene.xml:38
+msgid "Returns [code]true[/code] if the scene file has nodes."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:45
+msgid ""
+"Returns the [code]SceneState[/code] representing the scene file contents."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:54
+msgid ""
+"Instantiates the scene's node hierarchy. Triggers child scene "
+"instantiation(s). Triggers a [constant Node.NOTIFICATION_INSTANCED] "
+"notification on the root node."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:63
+msgid ""
+"Pack will ignore any sub-nodes not owned by given node. See [member Node."
+"owner]."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:69
+msgid ""
+"A dictionary representation of the scene contents.\n"
+"Available keys include \"rnames\" and \"variants\" for resources, "
+"\"node_count\", \"nodes\", \"node_paths\" for nodes, \"editable_instances\" "
+"for base scene children overrides, \"conn_count\" and \"conns\" for signal "
+"connections, and \"version\" for the format style of the PackedScene."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:75
+msgid "If passed to [method instance], blocks edits to the scene state."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:78
+msgid ""
+"If passed to [method instance], provides local scene resources to the local "
+"scene.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:82
+msgid ""
+"If passed to [method instance], provides local scene resources to the local "
+"scene. Only the main scene should receive the main edit state.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:4
+msgid "A packed [Array] of [String]s."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:7
+msgid ""
+"An [Array] specifically designed to hold [String]s. Packs data tightly, so "
+"it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:19
+msgid ""
+"Constructs a new [PackedStringArray]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:37
+msgid "Appends a [PackedStringArray] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:71
+msgid "Appends a string element at end of the array."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:100
+msgid "Changes the [String] at the given index."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:4
+msgid "A packed [Array] of [Vector2]s."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold [Vector2]. Packs data tightly, so "
+"it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:19
+msgid ""
+"Constructs a new [PackedVector2Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:37
+msgid "Appends a [PackedVector2Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:71
+msgid "Inserts a [Vector2] at the end."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:100
+msgid "Changes the [Vector2] at the given index."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:4
+msgid "A packed [Array] of [Vector3]s."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold [Vector3]. Packs data tightly, so "
+"it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:19
+msgid ""
+"Constructs a new [PackedVector3Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:37
+msgid "Appends a [PackedVector3Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:71
+msgid "Inserts a [Vector3] at the end."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:100
+msgid "Changes the [Vector3] at the given index."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:4
+msgid "Abstraction and base class for packet-based protocols."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:7
+msgid ""
+"PacketPeer is an abstraction and base class for packet-based protocols (such "
+"as UDP). It provides an API for sending and receiving packets both as raw "
+"data or variables. This makes it easy to transfer data over a protocol, "
+"without having to encode data as low-level bytes or having to worry about "
+"network ordering."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:16
+msgid "Returns the number of packets currently available in the ring-buffer."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:23
+msgid "Gets a raw packet."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:30
+msgid ""
+"Returns the error state of the last packet received (via [method get_packet] "
+"and [method get_var])."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:39
+msgid ""
+"Gets a Variant. If [code]allow_objects[/code] is [code]true[/code], decoding "
+"objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:49
+msgid "Sends a raw packet."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:60
+msgid ""
+"Sends a [Variant] as a packet. If [code]full_objects[/code] is [code]true[/"
+"code], encoding objects is allowed (and can potentially include code)."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:66
+msgid ""
+"Maximum buffer size allowed when encoding [Variant]s. Raise this value to "
+"support heavier memory allocations.\n"
+"The [method put_var] method allocates memory on the stack, and the buffer "
+"used will grow automatically to the closest power of two to match the size "
+"of the [Variant]. If the [Variant] is bigger than "
+"[code]encode_buffer_max_size[/code], the method will error out with "
+"[constant ERR_OUT_OF_MEMORY]."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:4
+msgid "DTLS packet peer."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:7
+msgid ""
+"This class represents a DTLS peer connection. It can be used to connect to a "
+"DTLS server, and is returned by [method DTLSServer.take_connection]."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:24
+msgid ""
+"Connects a [code]peer[/code] beginning the DTLS handshake using the "
+"underlying [PacketPeerUDP] which must be connected (see [method "
+"PacketPeerUDP.connect_to_host]). If [code]validate_certs[/code] is "
+"[code]true[/code], [PacketPeerDTLS] will validate that the certificate "
+"presented by the remote peer and match it with the [code]for_hostname[/code] "
+"argument. You can specify a custom [X509Certificate] to use for validation "
+"via the [code]valid_certificate[/code] argument."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:31
+msgid "Disconnects this peer, terminating the DTLS session."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:38 doc/classes/StreamPeerSSL.xml:55
+msgid "Returns the status of the connection. See [enum Status] for values."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:45
+msgid ""
+"Poll the connection to check for incoming packets. Call this frequently to "
+"update the status and keep the connection working."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:51
+msgid "A status representing a [PacketPeerDTLS] that is disconnected."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:54
+msgid ""
+"A status representing a [PacketPeerDTLS] that is currently performing the "
+"handshake with a remote peer."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:57
+msgid ""
+"A status representing a [PacketPeerDTLS] that is connected to a remote peer."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:60
+msgid "A status representing a [PacketPeerDTLS] in a generic error state."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:63
+msgid ""
+"An error status that shows a mismatch in the DTLS certificate domain "
+"presented by the host and the domain requested for validation."
+msgstr ""
+
+#: doc/classes/PacketPeerStream.xml:4
+msgid "Wrapper to use a PacketPeer over a StreamPeer."
+msgstr ""
+
+#: doc/classes/PacketPeerStream.xml:7
+msgid ""
+"PacketStreamPeer provides a wrapper for working using packets over a stream. "
+"This allows for using packet based code with StreamPeers. PacketPeerStream "
+"implements a custom protocol over the StreamPeer, so the user should not "
+"read or write to the wrapped StreamPeer directly."
+msgstr ""
+
+#: doc/classes/PacketPeerStream.xml:19
+msgid "The wrapped [StreamPeer] object."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:4
+msgid "UDP packet peer."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:7
+msgid ""
+"UDP packet peer. Can be used to send raw UDP packets as well as [Variant]s."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:16
+msgid "Closes the UDP socket the [PacketPeerUDP] is currently listening on."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:27
+msgid ""
+"Calling this method connects this UDP peer to the given [code]host[/code]/"
+"[code]port[/code] pair. UDP is in reality connectionless, so this option "
+"only means that incoming packets from different addresses are automatically "
+"discarded, and that outgoing packets are always sent to the connected "
+"address (future calls to [method set_dest_address] are not allowed). This "
+"method does not send any data to the remote peer, to do that, use [method "
+"PacketPeer.put_var] or [method PacketPeer.put_packet] as usual. See also "
+"[UDPServer].\n"
+"Note: 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."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:35
+msgid ""
+"Returns the IP of the remote peer that sent the last packet(that was "
+"received with [method PacketPeer.get_packet] or [method PacketPeer.get_var])."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:42
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:49
+msgid ""
+"Returns [code]true[/code] if the UDP socket is open and has been connected "
+"to a remote address. See [method connect_to_host]."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:56
+msgid "Returns whether this [PacketPeerUDP] is listening."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:67
+msgid ""
+"Joins the multicast group specified by [code]multicast_address[/code] using "
+"the interface identified by [code]interface_name[/code].\n"
+"You can join the same multicast group with multiple interfaces. Use [method "
+"IP.get_local_interfaces] to know which are available.\n"
+"Note: Some Android devices might require the "
+"[code]CHANGE_WIFI_MULTICAST_STATE[/code] permission for multicast to work."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:80
+msgid ""
+"Removes the interface identified by [code]interface_name[/code] from the "
+"multicast group specified by [code]multicast_address[/code]."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:93
+msgid ""
+"Makes this [PacketPeerUDP] listen on the [code]port[/code] binding to "
+"[code]bind_address[/code] with a buffer size [code]recv_buf_size[/code].\n"
+"If [code]bind_address[/code] is set to [code]\"*\"[/code] (default), the "
+"peer will listen on all available addresses (both IPv4 and IPv6).\n"
+"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.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:105
+msgid ""
+"Enable or disable sending of broadcast packets (e.g. "
+"[code]set_dest_address(\"255.255.255.255\", 4343)[/code]. This option is "
+"disabled by default.\n"
+"Note: Some Android devices might require the "
+"[code]CHANGE_WIFI_MULTICAST_STATE[/code] permission and this option to be "
+"enabled to receive broadcast packets too."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:117
+msgid ""
+"Sets the destination address and port for sending packets and variables. A "
+"hostname will be resolved using DNS if needed.\n"
+"Note: [method set_broadcast_enabled] must be enabled before sending packets "
+"to a broadcast address (e.g. [code]255.255.255.255[/code])."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:125
+msgid ""
+"Waits for a packet to arrive on the listening port. See [method listen]."
+msgstr ""
+
+#: doc/classes/Panel.xml:4
+msgid "Provides an opaque background for [Control] children."
+msgstr ""
+
+#: doc/classes/Panel.xml:7
+msgid ""
+"Panel is a [Control] that displays an opaque background. It's commonly used "
+"as a parent and container for other types of [Control] nodes."
+msgstr ""
+
+#: doc/classes/Panel.xml:25
+msgid "The style of this [Panel]."
+msgstr ""
+
+#: doc/classes/PanelContainer.xml:4
+msgid "Panel container type."
+msgstr ""
+
+#: doc/classes/PanelContainer.xml:7
+msgid ""
+"Panel container type. This container fits controls inside of the delimited "
+"area of a stylebox. It's useful for giving controls an outline."
+msgstr ""
+
+#: doc/classes/PanelContainer.xml:20
+msgid "The style of [PanelContainer]'s background."
+msgstr ""
+
+#: doc/classes/PanoramaSkyMaterial.xml:4
+msgid "A [Material] used with [Sky] to draw a background texture."
+msgstr ""
+
+#: doc/classes/PanoramaSkyMaterial.xml:7
+msgid ""
+"A resource referenced in a [Sky] that is used to draw a background. The "
+"Panorama sky material functions similar to skyboxes in other engines, except "
+"it uses an equirectangular sky map instead of a cube map.\n"
+"Using an HDR panorama is strongly recommended for accurate, high-quality "
+"reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR "
+"([code].exr[/code]) image formats for this purpose.\n"
+"You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/"
+"cubemap_to_panorama.html]this tool[/url] to convert a cube map to an "
+"equirectangular sky map."
+msgstr ""
+
+#: doc/classes/PanoramaSkyMaterial.xml:17
+msgid "[Texture2D] to be applied to the [PanoramaSkyMaterial]."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:4
+msgid "A node used to create a parallax scrolling background."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:7
+msgid ""
+"A ParallaxBackground uses one or more [ParallaxLayer] child nodes to create "
+"a parallax effect. Each [ParallaxLayer] can move at a different speed using "
+"[member ParallaxLayer.motion_offset]. This creates an illusion of depth in a "
+"2D game. If not used with a [Camera2D], you must manually calculate the "
+"[member scroll_offset]."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:16
+msgid "The base position offset for all [ParallaxLayer] children."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:19
+msgid "The base motion scale for all [ParallaxLayer] children."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:22
+msgid ""
+"If [code]true[/code], elements in [ParallaxLayer] child aren't affected by "
+"the zoom level of the camera."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:25
+msgid ""
+"Top-left limits for scrolling to begin. If the camera is outside of this "
+"limit, the background will stop scrolling. Must be lower than [member "
+"scroll_limit_end] to work."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:28
+msgid ""
+"Bottom-right limits for scrolling to end. If the camera is outside of this "
+"limit, the background will stop scrolling. Must be higher than [member "
+"scroll_limit_begin] to work."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:31
+msgid ""
+"The ParallaxBackground's scroll value. Calculated automatically when using a "
+"[Camera2D], but can be used to manually manage scrolling when no camera is "
+"present."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:4
+msgid "A parallax scrolling layer to be used with [ParallaxBackground]."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:7
+msgid ""
+"A ParallaxLayer must be the child of a [ParallaxBackground] node. Each "
+"ParallaxLayer can be set to move at different speeds relative to the camera "
+"movement or the [member ParallaxBackground.scroll_offset] value.\n"
+"This node's children will be affected by its scroll offset.\n"
+"[b]Note:[/b] Any changes to this node's position and scale made after it "
+"enters the scene will be ignored."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:17
+msgid ""
+"The ParallaxLayer's [Texture2D] mirroring. Useful for creating an infinite "
+"scrolling background. If an axis is set to [code]0[/code], the [Texture2D] "
+"will not be mirrored."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:20
+msgid ""
+"The ParallaxLayer's offset relative to the parent ParallaxBackground's "
+"[member ParallaxBackground.scroll_offset]."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:23
+msgid ""
+"Multiplies the ParallaxLayer's motion. If an axis is set to [code]0[/code], "
+"it will not scroll."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:4
+msgid "Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:7
+msgid ""
+"ParticlesMaterial defines particle properties and behavior. It is used in "
+"the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] "
+"emitter nodes.\n"
+"Some of this material's properties are applied to each particle when "
+"emitted, while others can have a [CurveTexture] applied to vary values over "
+"the lifetime of the particle.\n"
+"When a randomness ratio is applied to a property it is used to scale that "
+"property by a random amount. The random ratio is used to interpolate between "
+"[code]1.0[/code] and a random number less than one, the result is multiplied "
+"by the property to obtain the randomized property. For example a random "
+"ratio of [code]0.4[/code] would scale the original property between "
+"[code]0.4-1.0[/code] of its original value."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:20
+msgid "Returns [code]true[/code] if the specified flag is enabled."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:38
+msgid "Returns the randomness ratio associated with the specified parameter."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:47
+msgid "Returns the [Texture2D] used by the specified parameter."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:58
+msgid ""
+"If [code]true[/code], enables the specified flag. See [enum Flags] for "
+"options."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:69
+msgid "Sets the specified [enum Parameter]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:80
+msgid "Sets the randomness ratio for the specified [enum Parameter]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:91
+msgid "Sets the [Texture2D] for the specified [enum Parameter]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:97
+msgid ""
+"Initial rotation applied to each particle, in degrees.\n"
+"Only applied when [member flag_disable_z] or [member flag_rotate_y] are "
+"[code]true[/code] or the [BaseMaterial3D] being used to draw the particle is "
+"using [constant BaseMaterial3D.BILLBOARD_PARTICLES]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:101
+msgid "Each particle's rotation will be animated along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:107
+msgid ""
+"Initial angular velocity applied to each particle. Sets the speed of "
+"rotation of the particle.\n"
+"Only applied when [member flag_disable_z] or [member flag_rotate_y] are "
+"[code]true[/code] or the [BaseMaterial3D] being used to draw the particle is "
+"using [constant BaseMaterial3D.BILLBOARD_PARTICLES]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:111
+msgid "Each particle's angular velocity will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:120
+msgid "Each particle's animation offset will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:129
+msgid "Each particle's animation speed will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:135
+msgid ""
+"Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/"
+"code] is defined, it will be multiplied by this color. To have particle "
+"display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D."
+"vertex_color_use_as_albedo] to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:138
+msgid "Each particle's color will vary along this [GradientTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:144
+msgid "Damping will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:153
+msgid ""
+"The box's extents if [code]emission_shape[/code] is set to [constant "
+"EMISSION_SHAPE_BOX]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:156
+msgid ""
+"Particle color will be modulated by color determined by sampling this "
+"texture at the same point as the [member emission_point_texture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:159
+msgid ""
+"Particle velocity and rotation will be set by sampling this texture at the "
+"same point as the [member emission_point_texture]. Used only in [constant "
+"EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from mesh or "
+"node by selecting \"Create Emission Points from Mesh/Node\" under the "
+"\"Particles\" tool in the toolbar."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:162
+msgid ""
+"The number of emission points if [code]emission_shape[/code] is set to "
+"[constant EMISSION_SHAPE_POINTS] or [constant "
+"EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:165
+msgid ""
+"Particles will be emitted at positions determined by sampling this texture "
+"at a random position. Used with [constant EMISSION_SHAPE_POINTS] and "
+"[constant EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from "
+"mesh or node by selecting \"Create Emission Points from Mesh/Node\" under "
+"the \"Particles\" tool in the toolbar."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:168
+msgid ""
+"Particles will be emitted inside this region. Use [enum EmissionShape] "
+"constants for values."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:171
+msgid ""
+"The sphere's radius if [code]emission_shape[/code] is set to [constant "
+"EMISSION_SHAPE_SPHERE]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:192
+msgid "Each particle's hue will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:210
+msgid ""
+"Each particle's linear acceleration will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:216
+msgid ""
+"Orbital velocity applied to each particle. Makes the particles circle around "
+"origin. Specified in number of full rotations around origin per second.\n"
+"Only available when [member flag_disable_z] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:220
+msgid "Each particle's orbital velocity will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:229
+msgid ""
+"Each particle's radial acceleration will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:238
+msgid "Each particle's scale will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:250
+msgid ""
+"Each particle's tangential acceleration will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:256
+msgid "Trail particles' color will vary along this [GradientTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:259
+msgid ""
+"Emitter will emit [code]amount[/code] divided by [code]trail_divisor[/code] "
+"particles. The remaining particles will be used as trail(s)."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:262
+msgid "Trail particles' size will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:267
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set initial velocity properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:270
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set angular velocity properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:273
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set orbital velocity properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:276
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set linear acceleration properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:279
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set radial acceleration properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:282
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set tangential acceleration properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:285
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set damping properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:288
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set angle properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:291
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set scale properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:294
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set hue variation properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:297
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set animation speed properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:300
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set animation offset properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:306
+msgid "Use with [method set_flag] to set [member flag_align_y]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:309
+msgid "Use with [method set_flag] to set [member flag_rotate_y]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:312
+msgid "Use with [method set_flag] to set [member flag_disable_z]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:327
+msgid ""
+"Particles will be emitted at a position determined by sampling a random "
+"point on the [member emission_point_texture]. Particle color will be "
+"modulated by [member emission_color_texture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:330
+msgid ""
+"Particles will be emitted at a position determined by sampling a random "
+"point on the [member emission_point_texture]. Particle velocity and rotation "
+"will be set based on [member emission_normal_texture]. Particle color will "
+"be modulated by [member emission_color_texture]."
+msgstr ""
+
+#: doc/classes/Path2D.xml:4
+msgid "Contains a [Curve2D] path for [PathFollow2D] nodes to follow."
+msgstr ""
+
+#: doc/classes/Path2D.xml:7
+msgid ""
+"Can have [PathFollow2D] child nodes moving along the [Curve2D]. See "
+"[PathFollow2D] for more information on usage.\n"
+"[b]Note:[/b] The path is considered as relative to the moved nodes (children "
+"of [PathFollow2D]). As such, the curve should usually start with a zero "
+"vector ([code](0, 0)[/code])."
+msgstr ""
+
+#: doc/classes/Path2D.xml:16
+msgid "A [Curve2D] describing the path."
+msgstr ""
+
+#: doc/classes/Path3D.xml:4
+msgid "Contains a [Curve3D] path for [PathFollow3D] nodes to follow."
+msgstr ""
+
+#: doc/classes/Path3D.xml:7
+msgid ""
+"Can have [PathFollow3D] child nodes moving along the [Curve3D]. See "
+"[PathFollow3D] for more information on the usage.\n"
+"Note that the path is considered as relative to the moved nodes (children of "
+"[PathFollow3D]). As such, the curve should usually start with a zero vector "
+"[code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Path3D.xml:16
+msgid "A [Curve3D] describing the path."
+msgstr ""
+
+#: doc/classes/Path3D.xml:22
+msgid "Emitted when the [member curve] changes."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:4
+msgid "Point sampler for a [Path2D]."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:7
+msgid ""
+"This node takes its parent [Path2D], and returns the coordinates of a point "
+"within it, given a distance from the first vertex.\n"
+"It is useful for making other nodes follow a path, without coding the "
+"movement pattern. For that, the nodes must be children of this node. The "
+"descendant nodes will then move accordingly when setting an offset in this "
+"node."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:16
+msgid ""
+"If [code]true[/code], the position between two cached points is interpolated "
+"cubically, and linearly otherwise.\n"
+"The points along the [Curve2D] of the [Path2D] are precomputed before use, "
+"for faster calculations. The point at the requested offset is then "
+"calculated interpolating between two adjacent cached points. This may "
+"present a problem if the curve makes sharp turns, as the cached points may "
+"not follow the curve closely enough.\n"
+"There are two answers to this problem: either increase the number of cached "
+"points and increase memory consumption, or make a cubic interpolation "
+"between two points at the cost of (slightly) slower calculations."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:21 doc/classes/PathFollow3D.xml:21
+msgid "The node's offset along the curve."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:24
+msgid ""
+"How far to look ahead of the curve to calculate the tangent if the node is "
+"rotating. E.g. shorter lookaheads will lead to faster rotations."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:27 doc/classes/PathFollow3D.xml:24
+msgid ""
+"If [code]true[/code], any offset outside the path's length will wrap around, "
+"instead of stopping at the ends. Use it for cyclic paths."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:30
+msgid "The distance along the path in pixels."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:33
+msgid ""
+"If [code]true[/code], this node rotates to follow the path, making its "
+"descendants rotate."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:36
+msgid ""
+"The distance along the path as a number in the range 0.0 (for the first "
+"vertex) to 1.0 (for the last). This is just another way of expressing the "
+"offset within the path, as the offset supplied is multiplied internally by "
+"the path's length."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:39 doc/classes/PathFollow3D.xml:36
+msgid "The node's offset perpendicular to the curve."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:4
+msgid "Point sampler for a [Path3D]."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:7
+msgid ""
+"This node takes its parent [Path3D], and returns the coordinates of a point "
+"within it, given a distance from the first vertex.\n"
+"It is useful for making other nodes follow a path, without coding the "
+"movement pattern. For that, the nodes must be children of this node. The "
+"descendant nodes will then move accordingly when setting an offset in this "
+"node."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:16
+msgid ""
+"If [code]true[/code], the position between two cached points is interpolated "
+"cubically, and linearly otherwise.\n"
+"The points along the [Curve3D] of the [Path3D] are precomputed before use, "
+"for faster calculations. The point at the requested offset is then "
+"calculated interpolating between two adjacent cached points. This may "
+"present a problem if the curve makes sharp turns, as the cached points may "
+"not follow the curve closely enough.\n"
+"There are two answers to this problem: either increase the number of cached "
+"points and increase memory consumption, or make a cubic interpolation "
+"between two points at the cost of (slightly) slower calculations."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:27
+msgid ""
+"The distance from the first vertex, measured in 3D units along the path. "
+"This sets this node's position to a point within the path."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:30
+msgid ""
+"Allows or forbids rotation on one or more axes, depending on the [enum "
+"RotationMode] constants being used."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:33
+msgid ""
+"The distance from the first vertex, considering 0.0 as the first vertex and "
+"1.0 as the last. This is just another way of expressing the offset within "
+"the path, as the offset supplied is multiplied internally by the path's "
+"length."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:41
+msgid "Forbids the PathFollow3D to rotate."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:44
+msgid "Allows the PathFollow3D to rotate in the Y axis only."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:47
+msgid "Allows the PathFollow3D to rotate in both the X, and Y axes."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:50
+msgid "Allows the PathFollow3D to rotate in any axis."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:53
+msgid ""
+"Uses the up vector information in a [Curve3D] to enforce orientation. This "
+"rotation mode requires the [Path3D]'s [member Curve3D.up_vector_enabled] "
+"property to be set to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:4
+msgid "Creates packages that can be loaded into a running project."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:7
+msgid ""
+"The [PCKPacker] is used to create packages that can be loaded into a running "
+"project using [method ProjectSettings.load_resource_pack].\n"
+"[codeblock]\n"
+"var packer = PCKPacker.new()\n"
+"packer.pck_start(\"test.pck\")\n"
+"packer.add_file(\"res://text.txt\", \"text.txt\")\n"
+"packer.flush()\n"
+"[/codeblock]\n"
+"The above [PCKPacker] creates package [code]test.pck[/code], then adds a "
+"file named [code]text.txt[/code] at the root of the package."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:27
+msgid ""
+"Adds the [code]source_path[/code] file to the current PCK package at the "
+"[code]pck_path[/code] internal path (should start with [code]res://[/code])."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:36
+msgid ""
+"Writes the files specified using all [method add_file] calls since the last "
+"flush. If [code]verbose[/code] is [code]true[/code], a list of files added "
+"will be printed to the console for easier debugging."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:47
+msgid ""
+"Creates a new PCK file with the name [code]pck_name[/code]. The [code].pck[/"
+"code] file extension isn't added automatically, so it should be part of "
+"[code]pck_name[/code] (even though it's not required)."
+msgstr ""
+
+#: doc/classes/Performance.xml:4
+msgid "Exposes performance-related data."
+msgstr ""
+
+#: doc/classes/Performance.xml:7
+msgid ""
+"This class provides access to a number of different monitors related to "
+"performance, such as memory usage, draw calls, and FPS. These are the same "
+"as the values displayed in the [b]Monitor[/b] tab in the editor's "
+"[b]Debugger[/b] panel. By using the [method get_monitor] method of this "
+"class, you can access this data from your code.\n"
+"[b]Note:[/b] A few of these monitors are only available in debug mode and "
+"will always return 0 when used in a release build.\n"
+"[b]Note:[/b] Many of these monitors are not updated in real-time, so there "
+"may be a short delay between changes."
+msgstr ""
+
+#: doc/classes/Performance.xml:20
+msgid ""
+"Returns the value of one of the available monitors. You should provide one "
+"of the [enum Monitor] constants as the argument, like this:\n"
+"[codeblock]\n"
+"print(Performance.get_monitor(Performance.TIME_FPS)) # Prints the FPS to the "
+"console\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Performance.xml:29
+msgid "Number of frames per second."
+msgstr ""
+
+#: doc/classes/Performance.xml:32
+msgid "Time it took to complete one frame, in seconds."
+msgstr ""
+
+#: doc/classes/Performance.xml:35
+msgid "Time it took to complete one physics frame, in seconds."
+msgstr ""
+
+#: doc/classes/Performance.xml:38
+msgid ""
+"Static memory currently used, in bytes. Not available in release builds."
+msgstr ""
+
+#: doc/classes/Performance.xml:41
+msgid "Available static memory. Not available in release builds."
+msgstr ""
+
+#: doc/classes/Performance.xml:44
+msgid ""
+"Largest amount of memory the message queue buffer has used, in bytes. The "
+"message queue is used for deferred functions calls and notifications."
+msgstr ""
+
+#: doc/classes/Performance.xml:47
+msgid "Number of objects currently instanced (including nodes)."
+msgstr ""
+
+#: doc/classes/Performance.xml:50
+msgid "Number of resources currently used."
+msgstr ""
+
+#: doc/classes/Performance.xml:53
+msgid ""
+"Number of nodes currently instanced in the scene tree. This also includes "
+"the root node."
+msgstr ""
+
+#: doc/classes/Performance.xml:56
+msgid ""
+"Number of orphan nodes, i.e. nodes which are not parented to a node of the "
+"scene tree."
+msgstr ""
+
+#: doc/classes/Performance.xml:59
+msgid "3D objects drawn per frame."
+msgstr ""
+
+#: doc/classes/Performance.xml:62
+msgid "Vertices drawn per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:65
+msgid "Material changes per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:68
+msgid "Shader changes per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:71
+msgid "Render surface changes per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:74
+msgid "Draw calls per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:77 doc/classes/RenderingServer.xml:3711
+msgid ""
+"The amount of video memory used, i.e. texture and vertex memory combined."
+msgstr ""
+
+#: doc/classes/Performance.xml:80 doc/classes/RenderingServer.xml:3714
+msgid "The amount of texture memory used."
+msgstr ""
+
+#: doc/classes/Performance.xml:83 doc/classes/RenderingServer.xml:3717
+msgid "The amount of vertex memory used."
+msgstr ""
+
+#: doc/classes/Performance.xml:86 doc/classes/RenderingServer.xml:3708
+msgid "Unimplemented in the GLES2 rendering backend, always returns 0."
+msgstr ""
+
+#: doc/classes/Performance.xml:89
+msgid "Number of active [RigidBody2D] nodes in the game."
+msgstr ""
+
+#: doc/classes/Performance.xml:92
+msgid "Number of collision pairs in the 2D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:95
+msgid "Number of islands in the 2D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:98
+msgid "Number of active [RigidBody3D] and [VehicleBody3D] nodes in the game."
+msgstr ""
+
+#: doc/classes/Performance.xml:101
+msgid "Number of collision pairs in the 3D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:104
+msgid "Number of islands in the 3D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:107
+msgid "Output latency of the [AudioServer]."
+msgstr ""
+
+#: doc/classes/Performance.xml:110
+msgid "Represents the size of the [enum Monitor] enum."
+msgstr ""
+
+#: doc/classes/PHashTranslation.xml:4
+msgid "Optimized translation."
+msgstr ""
+
+#: doc/classes/PHashTranslation.xml:7
+msgid ""
+"Optimized translation. Uses real-time compressed translations, which results "
+"in very small dictionaries."
+msgstr ""
+
+#: doc/classes/PHashTranslation.xml:18
+msgid ""
+"Generates and sets an optimized translation from the given [Translation] "
+"resource."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:4
+msgid "[Sky] [Material] used for a physically based sky."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:7
+msgid ""
+"The [PhysicalSkyMaterial] uses the Preetham analytic daylight model to draw "
+"a sky based on physical properties. This results in a substantially more "
+"realistic sky than the [ProceduralSkyMaterial], but it is slightly slower "
+"and less flexible.\n"
+"The [PhysicalSkyMaterial] only supports one sun. The color, energy, and "
+"direction of the sun are taken from the first [DirectionalLight3D] in the "
+"scene tree.\n"
+"As it is based on a daylight model, the sky fades to black as the sunset "
+"ends. If you want a full day/night cycle, you will have to add a night sky "
+"by converting this to a [ShaderMaterial] and adding a night sky directly "
+"into the resulting shader."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:17
+msgid ""
+"Sets the amount of dithering to use. Dithering helps reduce banding that "
+"appears from the smooth changes in color in the sky. Use the lowest value "
+"possible, higher amounts may add fuzziness to the sky."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:20
+msgid ""
+"Sets the exposure of the sky. Higher exposure values make the entire sky "
+"brighter."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:23
+msgid ""
+"Modulates the [Color] on the bottom half of the sky to represent the ground."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:26
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:29
+msgid ""
+"Controls the [Color] of the mie scattering effect. While not physically "
+"accurate, this allows for the creation of alien looking planets."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:32
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:35
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:38
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:41
+msgid ""
+"Sets the size of the sun disk. Default value is based on Sol's perceived "
+"size from Earth."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:44
+msgid ""
+"Sets the thickness of the atmosphere. High turbidity creates a foggy looking "
+"atmosphere, while a low turbidity results in a clearer atmosphere."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:4
+msgid "Base class for all objects affected by physics in 2D space."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:7
+msgid ""
+"PhysicsBody2D is an abstract base class for implementing a physics body. All "
+"*Body2D types inherit from it."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:19 doc/classes/PhysicsBody3D.xml:19
+#: doc/classes/SoftBody3D.xml:19
+msgid "Adds a body to the list of bodies that this body can't collide with."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:26 doc/classes/PhysicsBody3D.xml:26
+#: doc/classes/SoftBody3D.xml:26
+msgid ""
+"Returns an array of nodes that were added as collision exceptions for this "
+"body."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:53 doc/classes/PhysicsBody3D.xml:53
+#: doc/classes/SoftBody3D.xml:53
+msgid ""
+"Removes a body from the list of bodies that this body can't collide with."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:64 doc/classes/PhysicsBody3D.xml:64
+msgid ""
+"Sets individual bits on the [member collision_layer] bitmask. Use this if "
+"you only need to change one layer's value."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:75 doc/classes/PhysicsBody3D.xml:75
+msgid ""
+"Sets individual bits on the [member collision_mask] bitmask. Use this if you "
+"only need to change one layer's value."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:81 doc/classes/PhysicsBody3D.xml:81
+msgid ""
+"The physics layers this area is in.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:86 doc/classes/PhysicsBody3D.xml:86
+msgid "The physics layers this area scans for collisions."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:90
+msgid ""
+"Both [member collision_layer] and [member collision_mask]. Returns [member "
+"collision_layer] when accessed. Updates [member collision_layer] and [member "
+"collision_mask] when modified."
+msgstr ""
+
+#: doc/classes/PhysicsBody3D.xml:4
+msgid "Base class for all objects affected by physics in 3D space."
+msgstr ""
+
+#: doc/classes/PhysicsBody3D.xml:7
+msgid ""
+"PhysicsBody3D is an abstract base class for implementing a physics body. All "
+"*Body types inherit from it."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:4
+msgid "Direct access object to a physics body in the [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:7
+msgid ""
+"Provides direct access to a physics body in the [PhysicsServer2D], allowing "
+"safe changes to physics properties. This object is passed via the direct "
+"state callback of rigid/character bodies, and is intended for changing the "
+"direct state of that body. See [method RigidBody2D._integrate_forces]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:10
+#: doc/classes/PhysicsDirectSpaceState2D.xml:10
+#: doc/classes/PhysicsDirectSpaceState3D.xml:10 doc/classes/RayCast2D.xml:14
+#: doc/classes/RayCast3D.xml:14 doc/classes/World2D.xml:10
+#: doc/classes/World3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html"
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:19 doc/classes/RigidBody2D.xml:31
+msgid "Adds a constant directional force without affecting rotation."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:30
+#: doc/classes/PhysicsDirectBodyState3D.xml:30 doc/classes/RigidBody2D.xml:42
+msgid ""
+"Adds a positioned force to the body. Both the force and the offset from the "
+"body origin are in global coordinates."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:39 doc/classes/RigidBody2D.xml:51
+msgid "Adds a constant rotational force."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:48 doc/classes/RigidBody2D.xml:60
+msgid "Applies a directional impulse without affecting rotation."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:59
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time-independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason, it should only be used when simulating one-time impacts "
+"(use the \"_force\" functions otherwise). The offset uses the rotation of "
+"the global coordinate system, but is centered at the object's origin."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:68 doc/classes/RigidBody2D.xml:80
+msgid "Applies a rotational impulse to the body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:77
+#: doc/classes/PhysicsDirectBodyState3D.xml:78
+msgid "Returns the collider's [RID]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:86
+#: doc/classes/PhysicsDirectBodyState3D.xml:87
+msgid "Returns the collider's object id."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:95
+msgid ""
+"Returns the collider object. This depends on how it was created (will return "
+"a scene node if such was used to create it)."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:104
+#: doc/classes/PhysicsDirectBodyState3D.xml:105
+msgid "Returns the contact position in the collider."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:113
+#: doc/classes/PhysicsDirectBodyState3D.xml:114
+msgid "Returns the collider's shape index."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:122
+msgid ""
+"Returns the collided shape's metadata. This metadata is different from "
+"[method Object.get_meta], and is set with [method PhysicsServer2D."
+"shape_set_data]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:131
+#: doc/classes/PhysicsDirectBodyState3D.xml:123
+msgid "Returns the linear velocity vector at the collider's contact point."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:138
+msgid ""
+"Returns the number of contacts this body has with other bodies.\n"
+"[b]Note:[/b] By default, this returns 0 unless bodies are configured to "
+"monitor contacts. See [member RigidBody2D.contact_monitor]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:148
+#: doc/classes/PhysicsDirectBodyState3D.xml:149
+msgid "Returns the local normal at the contact point."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:157
+#: doc/classes/PhysicsDirectBodyState3D.xml:158
+msgid "Returns the local position of the contact point."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:166
+#: doc/classes/PhysicsDirectBodyState3D.xml:167
+msgid "Returns the local shape index of the collision."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:173
+#: doc/classes/PhysicsDirectBodyState3D.xml:174
+msgid "Returns the current state of the space, useful for queries."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:180
+#: doc/classes/PhysicsDirectBodyState3D.xml:181
+msgid "Calls the built-in force integration code."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:186
+#: doc/classes/PhysicsDirectBodyState3D.xml:187 doc/classes/RigidBody2D.xml:121
+msgid "The body's rotational velocity."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:189
+#: doc/classes/PhysicsDirectBodyState3D.xml:192
+msgid "The inverse of the inertia of the body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:192
+#: doc/classes/PhysicsDirectBodyState3D.xml:195
+msgid "The inverse of the mass of the body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:195
+#: doc/classes/PhysicsDirectBodyState3D.xml:198 doc/classes/RigidBody2D.xml:155
+msgid "The body's linear velocity."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:198
+#: doc/classes/PhysicsDirectBodyState3D.xml:203
+msgid "If [code]true[/code], this body is currently sleeping (not active)."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:201
+#: doc/classes/PhysicsDirectBodyState3D.xml:206
+msgid "The timestep (delta) used for the simulation."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:204
+#: doc/classes/PhysicsDirectBodyState3D.xml:209
+msgid ""
+"The rate at which the body stops rotating, if there are not any other forces "
+"moving it."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:207
+#: doc/classes/PhysicsDirectBodyState3D.xml:212
+msgid "The total gravity vector being currently applied to this body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:210
+#: doc/classes/PhysicsDirectBodyState3D.xml:215
+msgid ""
+"The rate at which the body stops moving, if there are not any other forces "
+"moving it."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:213
+#: doc/classes/PhysicsDirectBodyState3D.xml:218
+msgid "The body's transformation matrix."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2DSW.xml:4
+msgid "Software implementation of [PhysicsDirectBodyState2D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2DSW.xml:7
+msgid ""
+"Software implementation of [PhysicsDirectBodyState2D]. This object exposes "
+"no new methods or properties and should not be used, as "
+"[PhysicsDirectBodyState2D] selects the best implementation available."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:4
+msgid "Direct access object to a physics body in the [PhysicsServer3D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:7
+msgid ""
+"Provides direct access to a physics body in the [PhysicsServer3D], allowing "
+"safe changes to physics properties. This object is passed via the direct "
+"state callback of rigid/character bodies, and is intended for changing the "
+"direct state of that body. See [method RigidBody3D._integrate_forces]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:18 doc/classes/RigidBody3D.xml:31
+msgid ""
+"Adds a constant directional force without affecting rotation.\n"
+"This is equivalent to [code]add_force(force, Vector3(0,0,0))[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:39
+msgid "Adds a constant rotational force without affecting position."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:48
+msgid ""
+"Applies a single directional impulse without affecting rotation.\n"
+"This is equivalent to [code]apply_impulse(Vector3(0, 0, 0), impulse)[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:60
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time-independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason it should only be used when simulating one-time impacts. The "
+"position uses the rotation of the global coordinate system, but is centered "
+"at the object's origin."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:69
+msgid ""
+"Apply a torque impulse (which will be affected by the body mass and shape). "
+"This will rotate the body around the vector [code]j[/code] passed as "
+"parameter."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:96
+msgid "Returns the collider object."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:130
+msgid ""
+"Returns the number of contacts this body has with other bodies.\n"
+"[b]Note:[/b] By default, this returns 0 unless bodies are configured to "
+"monitor contacts. See [member RigidBody3D.contact_monitor]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:140
+msgid "Impulse created by the contact. Only implemented for Bullet physics."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:4
+msgid "Direct access object to a space in the [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:7
+msgid ""
+"Direct access object to a space in the [PhysicsServer2D]. It's used mainly "
+"to do queries against objects and areas residing in a given space."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:19
+msgid ""
+"Checks how far the shape can travel toward a point. If the shape can not "
+"move, the array will be empty.\n"
+"[b]Note:[/b] Both the shape and the motion are supplied through a "
+"[PhysicsShapeQueryParameters2D] object. The method will return an array with "
+"two floats between 0 and 1, both representing a fraction of [code]motion[/"
+"code]. The first is how far the shape can move without triggering a "
+"collision, and the second is the point at which a collision will occur. If "
+"no collision is detected, the returned array will be [code][1, 1][/code]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:31
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters2D] object, against the space. The resulting "
+"array contains a list of points where the shape intersects another. Like "
+"with [method intersect_shape], the number of returned results can be limited "
+"to save processing time."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:40
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters2D] object, against the space. If it collides "
+"with more than one shape, the nearest one is selected. If the shape did not "
+"intersect anything, then an empty dictionary is returned instead.\n"
+"[b]Note:[/b] This method does not take into account the [code]motion[/code] "
+"property of the object. The returned object is a dictionary containing the "
+"following fields:\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]linear_velocity[/code]: The colliding object's velocity [Vector2]. If "
+"the object is an [Area2D], the result is [code](0, 0)[/code].\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]point[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:67
+msgid ""
+"Checks whether a point is inside any shape. The shapes the point is inside "
+"of are returned in an array containing dictionaries with the following "
+"fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"Additionally, the method can take an [code]exclude[/code] array of objects "
+"or [RID]s that are to be excluded from collisions, a [code]collision_mask[/"
+"code] bitmask representing the physics layers to check in, or booleans to "
+"determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, "
+"respectively."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:112
+msgid ""
+"Intersects a ray in a given space. The returned object is a dictionary with "
+"the following fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]position[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"If the ray did not intersect anything, then an empty dictionary is returned "
+"instead.\n"
+"Additionally, the method can take an [code]exclude[/code] array of objects "
+"or [RID]s that are to be excluded from collisions, a [code]collision_mask[/"
+"code] bitmask representing the physics layers to check in, or booleans to "
+"determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, "
+"respectively."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:132
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters2D] object, against the space.\n"
+"[b]Note:[/b] This method does not take into account the [code]motion[/code] "
+"property of the object. The intersected shapes are returned in an array "
+"containing dictionaries with the following fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"The number of intersections can be limited with the [code]max_results[/code] "
+"parameter, to reduce the processing time."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:4
+msgid "Direct access object to a space in the [PhysicsServer3D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:7
+msgid ""
+"Direct access object to a space in the [PhysicsServer3D]. It's used mainly "
+"to do queries against objects and areas residing in a given space."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:21
+msgid ""
+"Checks whether the shape can travel to a point. The method will return an "
+"array with two floats between 0 and 1, both representing a fraction of "
+"[code]motion[/code]. The first is how far the shape can move without "
+"triggering a collision, and the second is the point at which a collision "
+"will occur. If no collision is detected, the returned array will be [code]"
+"[1, 1][/code].\n"
+"If the shape can not move, the returned array will be [code][0, 0][/code] "
+"under Bullet, and empty under GodotPhysics."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:33
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters3D] object, against the space. The resulting "
+"array contains a list of points where the shape intersects another. Like "
+"with [method intersect_shape], the number of returned results can be limited "
+"to save processing time."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:42
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters3D] object, against the space. If it collides "
+"with more than one shape, the nearest one is selected. The returned object "
+"is a dictionary containing the following fields:\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]linear_velocity[/code]: The colliding object's velocity [Vector3]. If "
+"the object is an [Area3D], the result is [code](0, 0, 0)[/code].\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]point[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"If the shape did not intersect anything, then an empty dictionary is "
+"returned instead."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:68
+msgid ""
+"Intersects a ray in a given space. The returned object is a dictionary with "
+"the following fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]position[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"If the ray did not intersect anything, then an empty dictionary is returned "
+"instead.\n"
+"Additionally, the method can take an [code]exclude[/code] array of objects "
+"or [RID]s that are to be excluded from collisions, a [code]collision_mask[/"
+"code] bitmask representing the physics layers to check in, or booleans to "
+"determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, "
+"respectively."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:87
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters3D] object, against the space. The intersected "
+"shapes are returned in an array containing dictionaries with the following "
+"fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"The number of intersections can be limited with the [code]max_results[/code] "
+"parameter, to reduce the processing time."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:4
+msgid "A material for physics properties."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:7
+msgid ""
+"Provides a means of modifying the collision properties of a [PhysicsBody3D]."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:17
+msgid ""
+"The body's bounciness. Values range from [code]0[/code] (no bounce) to "
+"[code]1[/code] (full bounciness)."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:20
+msgid ""
+"The body's friction. Values range from [code]0[/code] (frictionless) to "
+"[code]1[/code] (maximum friction)."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:4
+msgid "Server interface for low-level 2D physics access."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:7
+msgid ""
+"PhysicsServer2D is the server responsible for all 2D physics. It can create "
+"many kinds of physics objects, but does not insert them on the node tree."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:24 doc/classes/PhysicsServer3D.xml:24
+msgid ""
+"Adds a shape to the area, along with a transform matrix. Shapes are usually "
+"referenced by their index, so you should track which shape has a given index."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:45 doc/classes/PhysicsServer2D.xml:418
+#: doc/classes/PhysicsServer3D.xml:35 doc/classes/PhysicsServer3D.xml:409
+msgid ""
+"Assigns the area to a descendant of [Object], so it can exist in the node "
+"tree."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:54 doc/classes/PhysicsServer3D.xml:44
+msgid ""
+"Removes all shapes from an area. It does not delete the shapes, so they can "
+"be reassigned later."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:61
+msgid "Creates an [Area2D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:78 doc/classes/PhysicsServer2D.xml:505
+#: doc/classes/PhysicsServer3D.xml:60 doc/classes/PhysicsServer3D.xml:492
+msgid "Gets the instance ID of the object the area is assigned to."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:89
+msgid ""
+"Returns an area parameter value. See [enum AreaParameter] for a list of "
+"available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:100 doc/classes/PhysicsServer3D.xml:82
+msgid "Returns the [RID] of the nth shape of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:109 doc/classes/PhysicsServer3D.xml:91
+msgid "Returns the number of shapes assigned to an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:120 doc/classes/PhysicsServer3D.xml:102
+msgid "Returns the transform matrix of a shape within an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:129 doc/classes/PhysicsServer3D.xml:111
+msgid "Returns the space assigned to the area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:138 doc/classes/PhysicsServer3D.xml:120
+msgid "Returns the space override mode for the area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:147 doc/classes/PhysicsServer3D.xml:129
+msgid "Returns the transform matrix for an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:158 doc/classes/PhysicsServer3D.xml:149
+msgid ""
+"Removes a shape from an area. It does not delete the shape, so it can be "
+"reassigned later."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:181 doc/classes/PhysicsServer3D.xml:172
+msgid "Assigns the area to one or many physics layers."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:192 doc/classes/PhysicsServer3D.xml:183
+msgid "Sets which physics layers the area will monitor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:205 doc/classes/PhysicsServer3D.xml:196
+msgid ""
+"Sets the function to call when any body/area enters or exits the area. This "
+"callback will be called for any object interacting with the area, and takes "
+"five parameters:\n"
+"1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on "
+"whether the object entered or exited the area.\n"
+"2: [RID] of the object that entered/exited the area.\n"
+"3: Instance ID of the object that entered/exited the area.\n"
+"4: The shape index of the object that entered/exited the area.\n"
+"5: The shape index of the area where the object entered/exited."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:233
+msgid ""
+"Sets the value for an area parameter. See [enum AreaParameter] for a list of "
+"available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:246 doc/classes/PhysicsServer3D.xml:248
+msgid ""
+"Substitutes a given area shape by another. The old shape is selected by its "
+"index, the new one by its [RID]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:259
+msgid "Disables a given shape in an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:272 doc/classes/PhysicsServer3D.xml:273
+msgid "Sets the transform matrix for an area shape."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:283 doc/classes/PhysicsServer3D.xml:284
+msgid "Assigns a space to the area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:294
+msgid ""
+"Sets the space override mode for the area. See [enum AreaSpaceOverrideMode] "
+"for a list of available modes."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:305 doc/classes/PhysicsServer3D.xml:306
+msgid "Sets the transform matrix for an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:326 doc/classes/PhysicsServer3D.xml:327
+msgid "Adds a body to the list of bodies exempt from collisions."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:339
+msgid ""
+"Adds a positioned force to the applied force and torque. As with [method "
+"body_apply_impulse], both the force and the offset from the body origin are "
+"in global coordinates. A force differs from an impulse in that, while the "
+"two are forces, the impulse clears itself after being applied."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:354 doc/classes/PhysicsServer3D.xml:354
+msgid ""
+"Adds a shape to the body, along with a transform matrix. Shapes are usually "
+"referenced by their index, so you should track which shape has a given index."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:387
+msgid ""
+"Adds a positioned impulse to the applied force and torque. Both the force "
+"and the offset from the body origin are in global coordinates."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:427 doc/classes/PhysicsServer3D.xml:418
+msgid "Removes all shapes from a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:434
+msgid "Creates a physics body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:451 doc/classes/PhysicsServer3D.xml:438
+msgid "Returns the physics layer or layers a body belongs to."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:460
+msgid "Returns the physics layer or layers a body can collide with."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:469
+msgid "Returns the continuous collision detection mode."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:478
+msgid "Returns the [PhysicsDirectBodyState2D] of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:487 doc/classes/PhysicsServer3D.xml:474
+msgid ""
+"Returns the maximum contacts that can be reported. See [method "
+"body_set_max_contacts_reported]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:496 doc/classes/PhysicsServer3D.xml:483
+msgid "Returns the body mode."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:516
+msgid ""
+"Returns the value of a body parameter. See [enum BodyParameter] for a list "
+"of available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:527 doc/classes/PhysicsServer3D.xml:514
+msgid "Returns the [RID] of the nth shape of a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:536 doc/classes/PhysicsServer3D.xml:523
+msgid "Returns the number of shapes assigned to a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:547
+msgid "Returns the metadata of a shape of a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:558 doc/classes/PhysicsServer3D.xml:534
+msgid "Returns the transform matrix of a body shape."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:567 doc/classes/PhysicsServer3D.xml:543
+msgid "Returns the [RID] of the space assigned to a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:578 doc/classes/PhysicsServer3D.xml:554
+msgid "Returns a body state."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:587 doc/classes/PhysicsServer3D.xml:582
+msgid ""
+"Returns whether a body uses a callback function to calculate its own physics "
+"(see [method body_set_force_integration_callback])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:598
+msgid "Removes a body from the list of bodies exempt from collisions."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:609 doc/classes/PhysicsServer3D.xml:614
+msgid ""
+"Removes a shape from a body. The shape is not deleted, so it can be reused "
+"afterwards."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:620 doc/classes/PhysicsServer3D.xml:637
+#: doc/classes/RigidBody3D.xml:119
+msgid ""
+"Sets an axis velocity. The velocity in the given vector axis will be set as "
+"the given vector length. This is useful for jumping behavior."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:631 doc/classes/PhysicsServer3D.xml:648
+msgid "Sets the physics layer or layers a body belongs to."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:642 doc/classes/PhysicsServer3D.xml:659
+msgid "Sets the physics layer or layers a body can collide with."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:653
+msgid ""
+"Sets the continuous collision detection mode using one of the [enum CCDMode] "
+"constants.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:669 doc/classes/PhysicsServer3D.xml:686
+msgid ""
+"Sets the function used to calculate physics for an object, if that object "
+"allows it (see [method body_set_omit_force_integration])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:680 doc/classes/PhysicsServer3D.xml:707
+msgid ""
+"Sets the maximum contacts to report. Bodies can keep a log of the contacts "
+"with other bodies, this is enabled by setting the maximum amount of contacts "
+"reported to a number greater than 0."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:691
+msgid "Sets the body mode using one of the [enum BodyMode] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:702 doc/classes/PhysicsServer3D.xml:729
+msgid ""
+"Sets whether a body uses a callback function to calculate its own physics "
+"(see [method body_set_force_integration_callback])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:715
+msgid ""
+"Sets a body parameter. See [enum BodyParameter] for a list of available "
+"parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:728 doc/classes/PhysicsServer3D.xml:766
+msgid ""
+"Substitutes a given body shape by another. The old shape is selected by its "
+"index, the new one by its [RID]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:743
+msgid ""
+"Enables one way collision on body if [code]enable[/code] is [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:756
+msgid "Disables shape in body if [code]disable[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:769
+msgid ""
+"Sets metadata of a shape within a body. This metadata is different from "
+"[method Object.set_meta], and can be retrieved on shape queries."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:782 doc/classes/PhysicsServer3D.xml:791
+msgid "Sets the transform matrix for a body shape."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:793 doc/classes/PhysicsServer3D.xml:802
+msgid "Assigns a space to the body (see [method space_create])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:806
+msgid "Sets a body state using one of the [enum BodyState] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:825
+msgid ""
+"Returns [code]true[/code] if a collision would result from moving in the "
+"given direction from a given point in space. Margin increases the size of "
+"the shapes involved in the collision detection. [PhysicsTestMotionResult2D] "
+"can be passed to return additional information in."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:864
+msgid ""
+"Creates a damped spring joint between two bodies. If not specified, the "
+"second body is assumed to be the joint itself."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:875
+msgid "Returns the value of a damped spring joint parameter."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:888
+msgid ""
+"Sets a damped spring joint parameter. See [enum DampedStringParam] for a "
+"list of available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:897
+msgid ""
+"Destroys any of the objects created by PhysicsServer2D. If the [RID] passed "
+"is not one of the objects that can be created by PhysicsServer2D, an error "
+"will be sent to the console."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:906
+msgid ""
+"Returns information about the current state of the 2D physics engine. See "
+"[enum ProcessInfo] for a list of available states."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:923
+msgid ""
+"Creates a groove joint between two bodies. If not specified, the bodies are "
+"assumed to be the joint itself."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:934
+msgid "Returns the value of a joint parameter."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:943
+msgid "Returns a joint's type (see [enum JointType])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:956
+msgid ""
+"Sets a joint parameter. See [enum JointParam] for a list of available "
+"parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:975
+msgid ""
+"Creates a pin joint between two bodies. If not specified, the second body is "
+"assumed to be the joint itself."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1002
+msgid "Activates or deactivates the 2D physics engine."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1011 doc/classes/PhysicsServer3D.xml:1156
+msgid "Returns the shape data."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1020
+msgid "Returns a shape's type (see [enum ShapeType])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1031 doc/classes/PhysicsServer3D.xml:1176
+msgid ""
+"Sets the shape data that defines its shape and size. The data to be passed "
+"depends on the kind of shape created [method shape_get_type]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1038 doc/classes/PhysicsServer3D.xml:1207
+msgid ""
+"Creates a space. A space is a collection of parameters for the physics "
+"engine that can be assigned to an area or a body. It can be assigned to an "
+"area with [method area_set_space], or to a body with [method body_set_space]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1047
+msgid ""
+"Returns the state of a space, a [PhysicsDirectSpaceState2D]. This object can "
+"be used to make collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1058 doc/classes/PhysicsServer3D.xml:1227
+msgid "Returns the value of a space parameter."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1067 doc/classes/PhysicsServer3D.xml:1236
+msgid "Returns whether the space is active."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1078 doc/classes/PhysicsServer3D.xml:1247
+msgid ""
+"Marks a space as active. It will not have an effect, unless it is assigned "
+"to an area or body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1091
+msgid ""
+"Sets the value for a space parameter. See [enum SpaceParameter] for a list "
+"of available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1097 doc/classes/PhysicsServer3D.xml:1602
+msgid ""
+"Constant to set/get the maximum distance a pair of bodies has to move before "
+"their collision status has to be recalculated."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1100 doc/classes/PhysicsServer3D.xml:1605
+msgid ""
+"Constant to set/get the maximum distance a shape can be from another before "
+"they are considered separated."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1103 doc/classes/PhysicsServer3D.xml:1608
+msgid ""
+"Constant to set/get the maximum distance a shape can penetrate another shape "
+"before it is considered a collision."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1106 doc/classes/PhysicsServer3D.xml:1611
+msgid ""
+"Constant to set/get the threshold linear velocity of activity. A body marked "
+"as potentially inactive for both linear and angular velocity will be put to "
+"sleep after the time given."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1109 doc/classes/PhysicsServer3D.xml:1614
+msgid ""
+"Constant to set/get the threshold angular velocity of activity. A body "
+"marked as potentially inactive for both linear and angular velocity will be "
+"put to sleep after the time given."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1112 doc/classes/PhysicsServer3D.xml:1617
+msgid ""
+"Constant to set/get the maximum time of activity. A body marked as "
+"potentially inactive for both linear and angular velocity will be put to "
+"sleep after this time."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1115 doc/classes/PhysicsServer3D.xml:1622
+msgid ""
+"Constant to set/get the default solver bias for all physics constraints. A "
+"solver bias is a factor controlling how much two objects \"rebound\", after "
+"violating a constraint, to avoid leaving them in that state because of "
+"numerical imprecision."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1120
+msgid ""
+"This is the constant for creating line shapes. A line shape is an infinite "
+"line with an origin point, and a normal. Thus, it can be used for front/"
+"behind checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1125
+msgid ""
+"This is the constant for creating segment shapes. A segment shape is a line "
+"from a point A to a point B. It can be checked for intersections."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1128
+msgid ""
+"This is the constant for creating circle shapes. A circle shape only has a "
+"radius. It can be used for intersections and inside/outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1131
+msgid ""
+"This is the constant for creating rectangle shapes. A rectangle shape is "
+"defined by a width and a height. It can be used for intersections and inside/"
+"outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1134
+msgid ""
+"This is the constant for creating capsule shapes. A capsule shape is defined "
+"by a radius and a length. It can be used for intersections and inside/"
+"outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1137
+msgid ""
+"This is the constant for creating convex polygon shapes. A polygon is "
+"defined by a list of points. It can be used for intersections and inside/"
+"outside checks. Unlike the [member CollisionPolygon2D.polygon] property, "
+"polygons modified with [method shape_set_data] do not verify that the points "
+"supplied form is a convex polygon."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1140
+msgid ""
+"This is the constant for creating concave polygon shapes. A polygon is "
+"defined by a list of points. It can be used for intersections checks, but "
+"not for inside/outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1143 doc/classes/PhysicsServer3D.xml:1497
+msgid ""
+"This constant is used internally by the engine. Any attempt to create this "
+"kind of shape results in an error."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1146 doc/classes/PhysicsServer3D.xml:1500
+msgid "Constant to set/get gravity strength in an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1149 doc/classes/PhysicsServer3D.xml:1503
+msgid "Constant to set/get gravity vector/center in an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1152 doc/classes/PhysicsServer3D.xml:1506
+msgid ""
+"Constant to set/get whether the gravity vector of an area is a direction, or "
+"a center point."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1155 doc/classes/PhysicsServer3D.xml:1509
+msgid ""
+"Constant to set/get the falloff factor for point gravity of an area. The "
+"greater this value is, the faster the strength of gravity decreases with the "
+"square of distance."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1158 doc/classes/PhysicsServer3D.xml:1512
+msgid ""
+"This constant was used to set/get the falloff factor for point gravity. It "
+"has been superseded by [constant AREA_PARAM_GRAVITY_DISTANCE_SCALE]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1161 doc/classes/PhysicsServer3D.xml:1515
+msgid "Constant to set/get the linear dampening factor of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1164 doc/classes/PhysicsServer3D.xml:1518
+msgid "Constant to set/get the angular dampening factor of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1167 doc/classes/PhysicsServer3D.xml:1521
+msgid "Constant to set/get the priority (order of processing) of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1170 doc/classes/PhysicsServer3D.xml:1524
+msgid ""
+"This area does not affect gravity/damp. These are generally areas that exist "
+"only to detect collisions, and objects entering or exiting them."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1173 doc/classes/PhysicsServer3D.xml:1527
+msgid ""
+"This area adds its gravity/damp values to whatever has been calculated so "
+"far. This way, many overlapping areas can combine their physics to make "
+"interesting effects."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1176 doc/classes/PhysicsServer3D.xml:1530
+msgid ""
+"This area adds its gravity/damp values to whatever has been calculated so "
+"far. Then stops taking into account the rest of the areas, even the default "
+"one."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1179 doc/classes/PhysicsServer3D.xml:1533
+msgid ""
+"This area replaces any gravity/damp, even the default one, and stops taking "
+"into account the rest of the areas."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1182 doc/classes/PhysicsServer3D.xml:1536
+msgid ""
+"This area replaces any gravity/damp calculated so far, but keeps calculating "
+"the rest of the areas, down to the default one."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1185 doc/classes/PhysicsServer3D.xml:1539
+msgid "Constant for static bodies."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1188 doc/classes/PhysicsServer3D.xml:1542
+msgid "Constant for kinematic bodies."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1191 doc/classes/PhysicsServer3D.xml:1545
+msgid "Constant for rigid bodies."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1194 doc/classes/PhysicsServer3D.xml:1548
+msgid ""
+"Constant for rigid bodies in character mode. In this mode, a body can not "
+"rotate, and only its linear velocity is affected by physics."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1197 doc/classes/PhysicsServer3D.xml:1551
+msgid "Constant to set/get a body's bounce factor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1200 doc/classes/PhysicsServer3D.xml:1554
+msgid "Constant to set/get a body's friction."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1203 doc/classes/PhysicsServer3D.xml:1557
+msgid "Constant to set/get a body's mass."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1206
+msgid "Constant to set/get a body's inertia."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1209 doc/classes/PhysicsServer3D.xml:1560
+msgid "Constant to set/get a body's gravity multiplier."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1212 doc/classes/PhysicsServer3D.xml:1563
+msgid "Constant to set/get a body's linear dampening factor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1215 doc/classes/PhysicsServer3D.xml:1566
+msgid "Constant to set/get a body's angular dampening factor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1218 doc/classes/PhysicsServer3D.xml:1569
+msgid "Represents the size of the [enum BodyParameter] enum."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1221 doc/classes/PhysicsServer3D.xml:1572
+msgid "Constant to set/get the current transform matrix of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1224 doc/classes/PhysicsServer3D.xml:1575
+msgid "Constant to set/get the current linear velocity of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1227 doc/classes/PhysicsServer3D.xml:1578
+msgid "Constant to set/get the current angular velocity of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1230 doc/classes/PhysicsServer3D.xml:1581
+msgid "Constant to sleep/wake up a body, or to get whether it is sleeping."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1233 doc/classes/PhysicsServer3D.xml:1584
+msgid "Constant to set/get whether the body can sleep."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1236
+msgid "Constant to create pin joints."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1239
+msgid "Constant to create groove joints."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1242
+msgid "Constant to create damped spring joints."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1251
+msgid ""
+"Sets the resting length of the spring joint. The joint will always try to go "
+"to back this length when pulled apart."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1254
+msgid ""
+"Sets the stiffness of the spring joint. The joint applies a force equal to "
+"the stiffness times the distance from its resting length."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1257
+msgid ""
+"Sets the damping ratio of the spring joint. A value of 0 indicates an "
+"undamped spring, while 1 causes the system to reach equilibrium as fast as "
+"possible (critical damping)."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1260
+msgid ""
+"Disables continuous collision detection. This is the fastest way to detect "
+"body collisions, but can miss small, fast-moving objects."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1263
+msgid ""
+"Enables continuous collision detection by raycasting. It is faster than "
+"shapecasting, but less precise."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1266
+msgid ""
+"Enables continuous collision detection by shapecasting. It is the slowest "
+"CCD method, and the most precise."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1269 doc/classes/PhysicsServer3D.xml:1587
+msgid ""
+"The value of the first parameter and area callback function receives, when "
+"an object enters one of its shapes."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1272 doc/classes/PhysicsServer3D.xml:1590
+msgid ""
+"The value of the first parameter and area callback function receives, when "
+"an object exits one of its shapes."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1275 doc/classes/PhysicsServer3D.xml:1593
+msgid "Constant to get the number of objects that are not sleeping."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1278 doc/classes/PhysicsServer3D.xml:1596
+msgid "Constant to get the number of possible collisions."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1281 doc/classes/PhysicsServer3D.xml:1599
+msgid ""
+"Constant to get the number of space regions where a collision could occur."
+msgstr ""
+
+#: doc/classes/PhysicsServer2DSW.xml:4
+msgid "Software implementation of [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2DSW.xml:7
+msgid ""
+"This class exposes no new methods or properties and should not be used, as "
+"[PhysicsServer2D] automatically selects the best implementation available."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:4
+msgid "Server interface for low-level physics access."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:7
+msgid ""
+"PhysicsServer3D is the server responsible for all 3D physics. It can create "
+"many kinds of physics objects, but does not insert them on the node tree."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:51
+msgid "Creates an [Area3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:71
+msgid ""
+"Returns an area parameter value. A list of available parameters is on the "
+"[enum AreaParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:138
+msgid "If [code]true[/code], area collides with rays."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:224
+msgid ""
+"Sets the value for an area parameter. A list of available parameters is on "
+"the [enum AreaParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:235
+msgid "Sets object pickable with rays."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:295
+msgid ""
+"Sets the space override mode for the area. The modes are described in the "
+"[enum AreaSpaceOverrideMode] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:387
+msgid ""
+"Gives the body a push at a [code]position[/code] in the direction of the "
+"[code]impulse[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:398
+msgid "Gives the body a push to rotate it."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:429
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:447
+msgid ""
+"Returns the physics layer or layers a body can collide with.\n"
+"-"
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:457
+msgid "Returns the [PhysicsDirectBodyState3D] of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:503
+msgid ""
+"Returns the value of a body parameter. A list of available parameters is on "
+"the [enum BodyParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:573
+msgid ""
+"If [code]true[/code], the continuous collision detection mode is enabled."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:591
+msgid "If [code]true[/code], the body can be detected by rays."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:602
+msgid ""
+"Removes a body from the list of bodies exempt from collisions.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:670
+msgid ""
+"If [code]true[/code], the continuous collision detection mode is enabled.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:718
+msgid "Sets the body mode, from one of the [enum BodyMode] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:742
+msgid ""
+"Sets a body parameter. A list of available parameters is on the [enum "
+"BodyParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:753
+msgid "Sets the body pickable with rays if [code]enabled[/code] is set."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:815
+msgid "Sets a body state (see [enum BodyState] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:826
+msgid ""
+"Gets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:839
+msgid ""
+"Sets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:848
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:861
+msgid ""
+"Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:874
+msgid ""
+"Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] "
+"constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:889
+msgid ""
+"Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:904
+msgid ""
+"Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] "
+"constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:913
+msgid "Returns an Info defined by the [enum ProcessInfo] input given."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:924
+msgid "Gets a hinge_joint flag (see [enum HingeJointFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:935
+msgid "Gets a hinge_joint parameter (see [enum HingeJointParam])."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:948
+msgid "Sets a hinge_joint flag (see [enum HingeJointFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:961
+msgid "Sets a hinge_joint parameter (see [enum HingeJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:976
+msgid "Creates a [ConeTwistJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:991
+msgid "Creates a [Generic6DOFJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1006
+msgid "Creates a [HingeJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1021
+msgid "Creates a [PinJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1036
+msgid "Creates a [SliderJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1045
+msgid "Gets the priority value of the Joint3D."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1054
+msgid "Returns the type of the Joint3D."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1065
+msgid "Sets the priority value of the Joint3D."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1074
+msgid ""
+"Returns position of the joint in the local space of body a of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1083
+msgid ""
+"Returns position of the joint in the local space of body b of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1094
+msgid "Gets a pin_joint parameter (see [enum PinJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1105
+msgid "Sets position of the joint in the local space of body a of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1116
+msgid "Sets position of the joint in the local space of body b of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1129
+msgid "Sets a pin_joint parameter (see [enum PinJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1138
+msgid "Activates or deactivates the 3D physics engine."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1147
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1165
+msgid "Returns the type of shape (see [enum ShapeType] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1187 doc/classes/PhysicsServer3D.xml:1200
+msgid "Gets a slider_joint parameter (see [enum SliderJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1216
+msgid ""
+"Returns the state of a space, a [PhysicsDirectSpaceState3D]. This object can "
+"be used to make collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1260
+msgid ""
+"Sets the value for a space parameter. A list of available parameters is on "
+"the [enum SpaceParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1266
+msgid "The [Joint3D] is a [PinJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1269
+msgid "The [Joint3D] is a [HingeJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1272
+msgid "The [Joint3D] is a [SliderJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1275
+msgid "The [Joint3D] is a [ConeTwistJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1278
+msgid "The [Joint3D] is a [Generic6DOFJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1281
+msgid ""
+"The strength with which the pinned objects try to stay in positional "
+"relation to each other.\n"
+"The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1285
+msgid ""
+"The strength with which the pinned objects try to stay in velocity relation "
+"to each other.\n"
+"The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1289
+msgid ""
+"If above 0, this value is the maximum value for an impulse that this Joint3D "
+"puts on its ends."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1295
+msgid "The maximum rotation across the Hinge."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1298
+msgid "The minimum rotation across the Hinge."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1315
+msgid "If [code]true[/code], the Hinge has a maximum and a minimum rotation."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1318
+msgid "If [code]true[/code], a motor turns the Hinge."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1321 doc/classes/SliderJoint3D.xml:81
+#: doc/classes/SliderJoint3D.xml:104
+msgid ""
+"The maximum difference between the pivot points on their X axis before "
+"damping happens."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1324 doc/classes/SliderJoint3D.xml:72
+#: doc/classes/SliderJoint3D.xml:107
+msgid ""
+"The minimum difference between the pivot points on their X axis before "
+"damping happens."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1327 doc/classes/SliderJoint3D.xml:78
+#: doc/classes/SliderJoint3D.xml:110
+msgid ""
+"A factor applied to the movement across the slider axis once the limits get "
+"surpassed. The lower, the slower the movement."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1330 doc/classes/SliderJoint3D.xml:113
+msgid ""
+"The amount of restitution once the limits are surpassed. The lower, the more "
+"velocityenergy gets lost."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1333 doc/classes/SliderJoint3D.xml:116
+msgid "The amount of damping once the slider limits are surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1336 doc/classes/SliderJoint3D.xml:90
+#: doc/classes/SliderJoint3D.xml:119
+msgid ""
+"A factor applied to the movement across the slider axis as long as the "
+"slider is in the limits. The lower, the slower the movement."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1339 doc/classes/SliderJoint3D.xml:87
+#: doc/classes/SliderJoint3D.xml:122
+msgid "The amount of restitution inside the slider limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1342 doc/classes/SliderJoint3D.xml:84
+#: doc/classes/SliderJoint3D.xml:125
+msgid "The amount of damping inside the slider limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1345 doc/classes/SliderJoint3D.xml:99
+#: doc/classes/SliderJoint3D.xml:128
+msgid "A factor applied to the movement across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1348 doc/classes/SliderJoint3D.xml:96
+#: doc/classes/SliderJoint3D.xml:131
+msgid ""
+"The amount of restitution when movement is across axes orthogonal to the "
+"slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1351 doc/classes/SliderJoint3D.xml:93
+#: doc/classes/SliderJoint3D.xml:134
+msgid ""
+"The amount of damping when movement is across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1354 doc/classes/SliderJoint3D.xml:48
+#: doc/classes/SliderJoint3D.xml:137
+msgid "The upper limit of rotation in the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1357 doc/classes/SliderJoint3D.xml:37
+#: doc/classes/SliderJoint3D.xml:140
+msgid "The lower limit of rotation in the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1360 doc/classes/SliderJoint3D.xml:143
+msgid "A factor applied to the all rotation once the limit is surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1363 doc/classes/SliderJoint3D.xml:146
+msgid "The amount of restitution of the rotation when the limit is surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1366 doc/classes/SliderJoint3D.xml:149
+msgid "The amount of damping of the rotation when the limit is surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1369
+msgid "A factor that gets applied to the all rotation in the limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1372 doc/classes/SliderJoint3D.xml:54
+#: doc/classes/SliderJoint3D.xml:155
+msgid "The amount of restitution of the rotation in the limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1375 doc/classes/SliderJoint3D.xml:51
+#: doc/classes/SliderJoint3D.xml:158
+msgid "The amount of damping of the rotation in the limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1378
+msgid ""
+"A factor that gets applied to the all rotation across axes orthogonal to the "
+"slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1381 doc/classes/SliderJoint3D.xml:63
+#: doc/classes/SliderJoint3D.xml:164
+msgid ""
+"The amount of restitution of the rotation across axes orthogonal to the "
+"slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1384 doc/classes/SliderJoint3D.xml:60
+#: doc/classes/SliderJoint3D.xml:167
+msgid ""
+"The amount of damping of the rotation across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1387
+msgid "Represents the size of the [enum SliderJointParam] enum."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1404
+msgid ""
+"The ease with which the Joint3D twists, if it's too low, it takes more force "
+"to twist the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1416
+msgid ""
+"A factor that gets applied to the movement across the axes. The lower, the "
+"slower the movement."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1419
+msgid ""
+"The amount of restitution on the axes movement. The lower, the more velocity-"
+"energy gets lost."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1425
+msgid "The velocity that the joint's linear motor will attempt to reach."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1428
+msgid ""
+"The maximum force that the linear motor can apply while trying to reach the "
+"target velocity."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1437
+msgid "A factor that gets multiplied onto all rotations across the axes."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1449
+msgid ""
+"When correcting the crossing of limits in rotation across the axes, this "
+"error tolerance factor defines how much the correction gets slowed down. The "
+"lower, the slower."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1458
+msgid ""
+"If [code]set[/code] there is linear motion possible within the given limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1461
+msgid "If [code]set[/code] there is rotational motion possible."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1464
+msgid "If [code]set[/code] there is a rotational motor across these axes."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1467
+msgid ""
+"If [code]set[/code] there is a linear motor on this axis that targets a "
+"specific velocity."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1470
+msgid "The [Shape3D] is a [WorldMarginShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1473
+msgid "The [Shape3D] is a [RayShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1476
+msgid "The [Shape3D] is a [SphereShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1479
+msgid "The [Shape3D] is a [BoxShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1482
+msgid "The [Shape3D] is a [CapsuleShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1485
+msgid "The [Shape3D] is a [CylinderShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1488
+msgid "The [Shape3D] is a [ConvexPolygonShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1491
+msgid "The [Shape3D] is a [ConcavePolygonShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1494
+msgid "The [Shape3D] is a [HeightMapShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:4
+msgid "Parameters to be sent to a 2D shape physics query."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:7
+msgid ""
+"This class contains the shape and other parameters for 2D intersection/"
+"collision queries. See also [PhysicsShapeQueryResult2D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:18
+msgid ""
+"Sets the [Shape2D] that will be used for collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:24
+msgid "If [code]true[/code], the query will take [Area2D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:27
+msgid ""
+"If [code]true[/code], the query will take [PhysicsBody2D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:30
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:30
+msgid "The physics layer(s) the query will take into account (as a bitmask)."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:33
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:33
+msgid ""
+"The list of objects or object [RID]s that will be excluded from collisions."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:36
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:36 doc/classes/Shape3D.xml:16
+msgid "The collision margin for the shape."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:39
+msgid "The motion of the shape being queried for."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:42
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:39
+msgid "The queried shape's [RID]. See also [method set_shape]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:45
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:42
+msgid "The queried shape's transform matrix."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:4
+msgid "Parameters to be sent to a 3D shape physics query."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:7
+msgid ""
+"This class contains the shape and other parameters for 3D intersection/"
+"collision queries. See also [PhysicsShapeQueryResult3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:18
+msgid ""
+"Sets the [Shape3D] that will be used for collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:24
+msgid "If [code]true[/code], the query will take [Area3D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:27
+msgid ""
+"If [code]true[/code], the query will take [PhysicsBody3D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:4
+msgid "Result of a 2D shape query in [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:7
+msgid ""
+"The result of a 2D shape query in [PhysicsServer2D]. See also "
+"[PhysicsShapeQueryParameters2D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:16
+#: doc/classes/PhysicsShapeQueryResult3D.xml:16
+msgid "Returns the number of objects that intersected with the shape."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:25
+#: doc/classes/PhysicsShapeQueryResult3D.xml:25
+msgid ""
+"Returns the [Object] that intersected with the shape at index [code]idx[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:34
+#: doc/classes/PhysicsShapeQueryResult3D.xml:34
+msgid ""
+"Returns the instance ID of the [Object] that intersected with the shape at "
+"index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:43
+msgid ""
+"Returns the child index of the object's [Shape2D] that intersected with the "
+"shape at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:52
+#: doc/classes/PhysicsShapeQueryResult3D.xml:52
+msgid ""
+"Returns the [RID] of the object that intersected with the shape at index "
+"[code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult3D.xml:4
+msgid "Result of a 3D shape query in [PhysicsServer3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult3D.xml:7
+msgid ""
+"The result of a 3D shape query in [PhysicsServer3D]. See also "
+"[PhysicsShapeQueryParameters3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult3D.xml:43
+msgid ""
+"Returns the child index of the object's [Shape3D] that intersected with the "
+"shape at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PinJoint2D.xml:4
+msgid "Pin joint for 2D shapes."
+msgstr ""
+
+#: doc/classes/PinJoint2D.xml:7
+msgid ""
+"Pin joint for 2D rigid bodies. It pins two bodies (rigid or static) together."
+msgstr ""
+
+#: doc/classes/PinJoint2D.xml:15
+msgid ""
+"The higher this value, the more the bond to the pinned partner can flex."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:4
+msgid "Pin joint for 3D shapes."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:7
+msgid ""
+"Pin joint for 3D rigid bodies. It pins 2 bodies (rigid or static) together."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:35 doc/classes/PinJoint3D.xml:46
+msgid ""
+"The force with which the pinned objects stay in positional relation to each "
+"other. The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:38 doc/classes/PinJoint3D.xml:49
+msgid ""
+"The force with which the pinned objects stay in velocity relation to each "
+"other. The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:41 doc/classes/PinJoint3D.xml:52
+msgid ""
+"If above 0, this value is the maximum value for an impulse that this Joint3D "
+"produces."
+msgstr ""
+
+#: doc/classes/Plane.xml:4
+msgid "Plane in hessian form."
+msgstr ""
+
+#: doc/classes/Plane.xml:7
+msgid ""
+"Plane represents a normalized plane equation. Basically, \"normal\" is the "
+"normal of the plane (a,b,c normalized), and \"d\" is the distance from the "
+"origin to the plane (in the direction of \"normal\"). \"Over\" or \"Above\" "
+"the plane is considered the side of the plane towards where the normal is "
+"pointing."
+msgstr ""
+
+#: doc/classes/Plane.xml:25
+msgid ""
+"Creates a plane from the four parameters. The three components of the "
+"resulting plane's [member normal] are [code]a[/code], [code]b[/code] and "
+"[code]c[/code], and the plane has a distance of [code]d[/code] from the "
+"origin."
+msgstr ""
+
+#: doc/classes/Plane.xml:38
+msgid "Creates a plane from the three points, given in clockwise order."
+msgstr ""
+
+#: doc/classes/Plane.xml:49
+msgid "Creates a plane from the normal and the plane's distance to the origin."
+msgstr ""
+
+#: doc/classes/Plane.xml:56
+msgid "Returns the center of the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:65
+msgid ""
+"Returns the shortest distance from the plane to the position [code]point[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Plane.xml:72
+msgid "Returns a point on the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:83
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is inside the plane (by a "
+"very minimum [code]epsilon[/code] threshold)."
+msgstr ""
+
+#: doc/classes/Plane.xml:94
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Plane.xml:105
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Plane.xml:116
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Plane.xml:125
+msgid ""
+"Returns [code]true[/code] if this plane and [code]plane[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Plane.xml:134
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is located above the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:141
+msgid "Returns a copy of the plane, normalized."
+msgstr ""
+
+#: doc/classes/Plane.xml:150
+msgid ""
+"Returns the orthogonal projection of point [code]p[/code] into a point in "
+"the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:156
+msgid ""
+"Distance from the origin to the plane, in the direction of [member normal]."
+msgstr ""
+
+#: doc/classes/Plane.xml:159
+msgid ""
+"The normal of the plane. \"Over\" or \"Above\" the plane is considered the "
+"side of the plane towards where the normal is pointing."
+msgstr ""
+
+#: doc/classes/Plane.xml:162
+msgid "The [member normal]'s X component."
+msgstr ""
+
+#: doc/classes/Plane.xml:165
+msgid "The [member normal]'s Y component."
+msgstr ""
+
+#: doc/classes/Plane.xml:168
+msgid "The [member normal]'s Z component."
+msgstr ""
+
+#: doc/classes/Plane.xml:173
+msgid "A plane that extends in the Y and Z axes."
+msgstr ""
+
+#: doc/classes/Plane.xml:176
+msgid "A plane that extends in the X and Z axes."
+msgstr ""
+
+#: doc/classes/Plane.xml:179
+msgid "A plane that extends in the X and Y axes."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:4
+msgid "Class representing a planar [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:7
+msgid ""
+"Class representing a planar [PrimitiveMesh]. This flat mesh does not have a "
+"thickness. By default, this mesh is aligned on the X and Z axes; this "
+"default rotation isn't suited for use with billboarded materials. For "
+"billboarded materials, use [QuadMesh] instead."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:15
+msgid "Size of the generated plane."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:18
+msgid "Number of subdivision along the Z axis."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:21
+msgid "Number of subdivision along the X axis."
+msgstr ""
+
+#: modules/gdnative/doc_classes/PluginScript.xml:14
+msgid "Returns a new instance of the script."
+msgstr ""
+
+#: doc/classes/PointMesh.xml:4
+msgid "Mesh with a single Point primitive."
+msgstr ""
+
+#: doc/classes/PointMesh.xml:7
+msgid ""
+"The PointMesh is made from a single point. Instead of relying on triangles, "
+"points are rendered as a single rectangle on the screen with a constant "
+"size. They are intended to be used with Particle systems, but can be used as "
+"a cheap way to render constant size billboarded sprites (for example in a "
+"point cloud).\n"
+"PointMeshes, must be used with a material that has a point size. Point size "
+"can be accessed in a shader with [code]POINT_SIZE[/code], or in a "
+"[BaseMaterial3D] by setting [member BaseMaterial3D.use_point_size] and the "
+"variable [member BaseMaterial3D.point_size].\n"
+"When using PointMeshes, properties that normally alter vertices will be "
+"ignored, including billboard mode, grow, and cull face."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:4
+msgid "A 2D polygon."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:7
+msgid ""
+"A Polygon2D is defined by a set of points. Each point is connected to the "
+"next, with the final point being connected to the first, resulting in a "
+"closed polygon. Polygon2Ds can be filled with color (solid or gradient) or "
+"filled with a given texture."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:20
+msgid ""
+"Adds a bone with the specified [code]path[/code] and [code]weights[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:27
+msgid "Removes all bones from this [Polygon2D]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:36
+msgid "Removes the specified bone from this [Polygon2D]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:43
+msgid "Returns the number of bones in this [Polygon2D]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:52
+msgid "Returns the path to the node associated with the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:61
+msgid "Returns the height values of the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:72
+msgid "Sets the path to the node associated with the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:83
+msgid "Sets the weight values for the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:89
+msgid "If [code]true[/code], polygon edges will be anti-aliased."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:94
+msgid ""
+"The polygon's fill color. If [code]texture[/code] is defined, it will be "
+"multiplied by this color. It will also be the default color for vertices not "
+"set in [code]vertex_colors[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:99
+msgid ""
+"Added padding applied to the bounding box when using [code]invert[/code]. "
+"Setting this value too small may result in a \"Bad Polygon\" error."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:102
+msgid ""
+"If [code]true[/code], polygon will be inverted, containing the area outside "
+"the defined points and extending to the [code]invert_border[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:107
+msgid "The offset applied to each vertex."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:110
+msgid ""
+"The polygon's list of vertices. The final point will be connected to the "
+"first.\n"
+"[b]Note:[/b] This returns a copy of the [PackedVector2Array] rather than a "
+"reference."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:124
+msgid ""
+"The polygon's fill texture. Use [code]uv[/code] to set texture coordinates."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:127
+msgid ""
+"Amount to offset the polygon's [code]texture[/code]. If [code](0, 0)[/code] "
+"the texture's origin (its top-left corner) will be placed at the polygon's "
+"[code]position[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:130
+msgid "The texture's rotation in radians."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:133
+msgid "The texture's rotation in degrees."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:136
+msgid ""
+"Amount to multiply the [code]uv[/code] coordinates when using a "
+"[code]texture[/code]. Larger values make the texture smaller, and vice versa."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:139
+msgid ""
+"Texture coordinates for each vertex of the polygon. There should be one "
+"[code]uv[/code] per polygon vertex. If there are fewer, undefined vertices "
+"will use [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:142
+msgid ""
+"Color for each vertex. Colors are interpolated between vertices, resulting "
+"in smooth gradients. There should be one per polygon vertex. If there are "
+"fewer, undefined vertices will use [code]color[/code]."
+msgstr ""
+
+#: doc/classes/Popup.xml:4
+msgid "Base container control for popups and dialogs."
+msgstr ""
+
+#: doc/classes/Popup.xml:7
+msgid ""
+"Popup is a base [Control] used to show dialogs and popups. It's a subwindow "
+"and modal by default (see [Control]) and has helpers for custom popup "
+"behavior."
+msgstr ""
+
+#: doc/classes/Popup.xml:23
+msgid "Emitted when a popup is hidden."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:4
+msgid "PopupMenu displays a list of options."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:7
+msgid ""
+"[PopupMenu] is a [Control] that displays a list of options. They are popular "
+"in toolbars or context menus."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:22
+msgid ""
+"Adds a new checkable item with text [code]label[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:37
+msgid ""
+"Adds a new checkable item and assigns the specified [ShortCut] to it. Sets "
+"the label of the checkbox to the [ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:54
+msgid ""
+"Adds a new checkable item with text [code]label[/code] and icon "
+"[code]texture[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:71
+msgid ""
+"Adds a new checkable item and assigns the specified [ShortCut] and icon "
+"[code]texture[/code] to it. Sets the label of the checkbox to the "
+"[ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:88
+msgid ""
+"Adds a new item with text [code]label[/code] and icon [code]texture[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:104
+msgid "Same as [method add_icon_check_item], but uses a radio check button."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:119
+msgid ""
+"Same as [method add_icon_check_shortcut], but uses a radio check button."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:134
+msgid ""
+"Adds a new item and assigns the specified [ShortCut] and icon [code]texture[/"
+"code] to it. Sets the label of the checkbox to the [ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:148
+msgid ""
+"Adds a new item with text [code]label[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:166
+msgid ""
+"Adds a new multistate item with text [code]label[/code].\n"
+"Contrarily to normal binary items, multistate items can have more than two "
+"states, as defined by [code]max_states[/code]. Each press or activate of the "
+"item will increase the state by one. The default value is defined by "
+"[code]default_state[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:181
+msgid ""
+"Adds a new radio check button with text [code]label[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:196
+msgid ""
+"Adds a new radio check button and assigns a [ShortCut] to it. Sets the label "
+"of the checkbox to the [ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:207
+msgid "Adds a separator between items. Separators also occupy an index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:220
+msgid ""
+"Adds a [ShortCut].\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:234
+msgid ""
+"Adds an item that will act as a submenu of the parent [PopupMenu] node when "
+"clicked. The [code]submenu[/code] argument is the name of the child "
+"[PopupMenu] node that will be shown when the item is clicked.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:242
+msgid "Removes all items from the [PopupMenu]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:251
+msgid ""
+"Returns the accelerator of the item at index [code]idx[/code]. Accelerators "
+"are special combinations of keys that activate the item, no matter which "
+"control is focused."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:258
+msgid "Returns the number of items in the [PopupMenu]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:276
+msgid ""
+"Returns the id of the item at index [code]idx[/code]. [code]id[/code] can be "
+"manually assigned, while index can not."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:285
+msgid ""
+"Returns the index of the item containing the specified [code]id[/code]. "
+"Index is automatically assigned to each item by the engine. Index can not be "
+"set manually."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:294
+msgid ""
+"Returns the metadata of the specified item, which might be of any type. You "
+"can set it with [method set_item_metadata], which provides a simple way of "
+"assigning context data to items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:303
+msgid ""
+"Returns the [ShortCut] associated with the specified [code]idx[/code] item."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:312
+msgid ""
+"Returns the submenu name of the item at index [code]idx[/code]. See [method "
+"add_submenu_item] for more info on how to add a submenu."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:330
+msgid ""
+"Returns the tooltip associated with the specified index index [code]idx[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:339
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is checkable "
+"in some way, i.e. if it has a checkbox or radio button.\n"
+"[b]Note:[/b] Checkable items just display a checkmark or radio button, but "
+"don't have any built-in checking behavior and must be checked/unchecked "
+"manually."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:349
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is checked."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:358
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is disabled. "
+"When it is disabled it can't be selected, or its action invoked.\n"
+"See [method set_item_disabled] for more info on how to disable an item."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:368
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] has radio "
+"button-style checkability.\n"
+"[b]Note:[/b] This is purely cosmetic; you must add the logic for checking/"
+"unchecking items in radio groups."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:378
+msgid ""
+"Returns [code]true[/code] if the item is a separator. If it is, it will be "
+"displayed as a line. See [method add_separator] for more info on how to add "
+"a separator."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:387
+msgid "Returns [code]true[/code] if the specified item's shortcut is disabled."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:396
+msgid ""
+"Removes the item at index [code]idx[/code] from the menu.\n"
+"[b]Note:[/b] The indices of items after the removed item will be shifted by "
+"one."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:408
+msgid ""
+"Sets the accelerator of the item at index [code]idx[/code]. Accelerators are "
+"special combinations of keys that activate the item, no matter which control "
+"is focused."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:419
+msgid ""
+"Sets whether the item at index [code]idx[/code] has a checkbox. If "
+"[code]false[/code], sets the type of the item to plain text.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:431
+msgid ""
+"Sets the type of the item at the specified index [code]idx[/code] to radio "
+"button. If [code]false[/code], sets the type of the item to plain text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:442
+msgid ""
+"Mark the item at index [code]idx[/code] as a separator, which means that it "
+"would be displayed as a line. If [code]false[/code], sets the type of the "
+"item to plain text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:453
+msgid "Sets the checkstate status of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:464
+msgid ""
+"Enables/disables the item at index [code]idx[/code]. When it is disabled, it "
+"can't be selected and its action can't be invoked."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:475
+msgid "Replaces the [Texture2D] icon of the specified [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:486
+msgid "Sets the [code]id[/code] of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:497
+msgid ""
+"Sets the metadata of an item, which may be of any type. You can later get it "
+"with [method get_item_metadata], which provides a simple way of assigning "
+"context data to items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:508
+msgid ""
+"Sets the state of an multistate item. See [method add_multistate_item] for "
+"details."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:521
+msgid "Sets a [ShortCut] for the specified item [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:532
+msgid "Disables the [ShortCut] of the specified index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:543
+msgid ""
+"Sets the submenu of the item at index [code]idx[/code]. The submenu is the "
+"name of a child [PopupMenu] node that would be shown when the item is "
+"clicked."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:565
+msgid ""
+"Sets the [String] tooltip of the item at the specified index [code]idx[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:574
+msgid ""
+"Toggles the check state of the item of the specified index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:583
+msgid ""
+"Cycle to the next state of an multistate item. See [method "
+"add_multistate_item] for details."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:589
+msgid "If [code]true[/code], allows to navigate [PopupMenu] with letter keys."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:592
+msgid ""
+"If [code]true[/code], hides the [PopupMenu] when a checkbox or radio button "
+"is selected."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:595
+msgid "If [code]true[/code], hides the [PopupMenu] when an item is selected."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:598
+msgid ""
+"If [code]true[/code], hides the [PopupMenu] when a state item is selected."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:601
+msgid ""
+"Sets the delay time in seconds for the submenu item to popup on mouse "
+"hovering. If the popup menu is added as a child of another (acting as a "
+"submenu), it will inherit the delay time of the parent menu item."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:609
+msgid ""
+"Emitted when user navigated to an item of some [code]id[/code] using "
+"[code]ui_up[/code] or [code]ui_down[/code] action."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:616
+msgid ""
+"Emitted when an item of some [code]id[/code] is pressed or its accelerator "
+"is activated."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:623
+msgid ""
+"Emitted when an item of some [code]index[/code] is pressed or its "
+"accelerator is activated."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:631
+msgid "[Texture2D] icon for the checked checkbox items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:634
+msgid "[Font] used for the menu items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:637
+msgid "The default text [Color] for menu items' names."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:640
+msgid ""
+"The text [Color] used for shortcuts and accelerators that show next to the "
+"menu item name when defined. See [method get_item_accelerator] for more info "
+"on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:643
+msgid "[Color] used for disabled menu items' text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:646
+msgid "[Color] used for the hovered text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:649
+msgid "[StyleBox] displayed when the [PopupMenu] item is hovered."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:652
+msgid ""
+"The horizontal space between the item's name and the shortcut text/submenu "
+"arrow."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:655
+msgid ""
+"[StyleBox] for the left side of labeled separator. See [method "
+"add_separator]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:658
+msgid ""
+"[StyleBox] for the right side of labeled separator. See [method "
+"add_separator]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:661
+msgid "Default [StyleBox] of the [PopupMenu] items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:664
+msgid "[StyleBox] used when the [PopupMenu] item is disabled."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:667
+msgid "[Texture2D] icon for the checked radio button items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:670
+msgid "[Texture2D] icon for the unchecked radio button items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:673
+msgid "[StyleBox] used for the separators. See [method add_separator]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:676
+msgid "[Texture2D] icon for the submenu arrow."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:679
+msgid "[Texture2D] icon for the unchecked checkbox items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:682
+msgid "The vertical space between each menu item."
+msgstr ""
+
+#: doc/classes/PopupPanel.xml:4
+msgid "Class for displaying popups with a panel background."
+msgstr ""
+
+#: doc/classes/PopupPanel.xml:7
+msgid ""
+"Class for displaying popups with a panel background. In some cases it might "
+"be simpler to use than [Popup], since it provides a configurable background. "
+"If you are making windows, better check [Window]."
+msgstr ""
+
+#: doc/classes/PopupPanel.xml:17
+msgid "The background panel style of this [PopupPanel]."
+msgstr ""
+
+#: doc/classes/Position2D.xml:4
+msgid "Generic 2D position hint for editing."
+msgstr ""
+
+#: doc/classes/Position2D.xml:7
+msgid ""
+"Generic 2D position hint for editing. It's just like a plain [Node2D], but "
+"it displays as a cross in the 2D editor at all times. You can set cross' "
+"visual size by using the gizmo in the 2D editor while the node is selected."
+msgstr ""
+
+#: doc/classes/Position3D.xml:4
+msgid "Generic 3D position hint for editing."
+msgstr ""
+
+#: doc/classes/Position3D.xml:7
+msgid ""
+"Generic 3D position hint for editing. It's just like a plain [Node3D], but "
+"it displays as a cross in the 3D editor at all times."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:4
+msgid ""
+"Base class for all primitive meshes. Handles applying a [Material] to a "
+"primitive mesh."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:7
+msgid ""
+"Base class for all primitive meshes. Handles applying a [Material] to a "
+"primitive mesh. Examples include [CapsuleMesh], [CubeMesh], [CylinderMesh], "
+"[PlaneMesh], [PrismMesh], [QuadMesh], and [SphereMesh]."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:16
+msgid ""
+"Returns mesh arrays used to constitute surface of [Mesh]. Mesh arrays can be "
+"used with [ArrayMesh] to create new surfaces."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:22
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:25
+msgid ""
+"If set, the order of the vertices in each triangle are reversed resulting in "
+"the backside of the mesh being drawn.\n"
+"This gives the same result as using [constant BaseMaterial3D.CULL_BACK] in "
+"[member BaseMaterial3D.cull_mode]."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:29
+msgid "The current [Material] of the primitive mesh."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:4 doc/classes/PrismMesh.xml:7
+msgid "Class representing a prism-shaped [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:15
+msgid ""
+"Displacement of the upper edge along the X axis. 0.0 positions edge straight "
+"above the bottom-left edge."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:18
+msgid "Size of the prism."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:21
+msgid "Number of added edge loops along the Z axis."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:24
+msgid "Number of added edge loops along the Y axis."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:27
+msgid "Number of added edge loops along the X axis."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:4
+msgid ""
+"A [Material] used with [Sky] to generate a background based on user input "
+"parameters."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:7
+msgid ""
+"ProceduralSkyMaterial provides a way to create an effective background "
+"quickly by defining procedural parameters for the sun, the sky and the "
+"ground. The sky and ground are very similar, they are defined by a color at "
+"the horizon, another color, and finally an easing curve to interpolate "
+"between these two colors. Similarly, the sun is described by a position in "
+"the sky, a color, and an easing curve. However, the sun also defines a "
+"minimum and maximum angle, these two values define at what distance the "
+"easing curve begins and ends from the sun, and thus end up defining the size "
+"of the sun in the sky.\n"
+"The [ProceduralSkyMaterial] uses a lightweight shader to draw the sky and is "
+"thus suited for real time updates. When you do not need a quick sky that is "
+"not realistic, this is a good option.\n"
+"The [ProceduralSkyMaterial] supports up to 4 suns. Each sun takes its color, "
+"energy, and direction from the corresponding [DirectionalLight3D] in the "
+"scene."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:17
+msgid ""
+"Color of the ground at the bottom. Blends with [member ground_horizon_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:20
+msgid ""
+"How quickly the [member ground_horizon_color] fades into the [member "
+"ground_bottom_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:23
+msgid "Amount of energy contribution from the ground."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:26
+msgid ""
+"Color of the ground at the horizon. Blends with [member ground_bottom_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:29
+msgid ""
+"How quickly the [member sky_horizon_color] fades into the [member "
+"sky_top_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:32
+msgid "Amount of energy contribution from the sky."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:35
+msgid "Color of the sky at the horizon. Blends with [member sky_top_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:38
+msgid "Color of the sky at the top. Blends with [member sky_horizon_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:41
+msgid "Distance from center of sun where it fades out completely."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:44
+msgid "Distance from sun where it goes from solid to starting to fade."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:47
+msgid ""
+"How quickly the sun fades away between [member sun_angle_min] and [member "
+"sun_angle_max]."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:4
+msgid "General-purpose progress bar."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:7
+msgid "General-purpose progress bar. Shows fill percentage from right to left."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:15
+msgid "If [code]true[/code], the fill percentage is displayed on the bar."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:24
+msgid "The style of the background."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:27
+msgid "The style of the progress (i.e. the part that fills the bar)."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:30
+msgid ""
+"Font used to draw the fill percentage if [member percent_visible] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:33
+msgid "The color of the text."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:36
+msgid "The color of the text's shadow."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:4
+msgid "Contains global variables accessible from everywhere."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:20
+msgid ""
+"Adds a custom property info to a property. The dictionary must contain:\n"
+"- [code]name[/code]: [String] (the property's name)\n"
+"- [code]type[/code]: [int] (see [enum Variant.Type])\n"
+"- optionally [code]hint[/code]: [int] (see [enum PropertyHint]) and "
+"[code]hint_string[/code]: [String]\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"ProjectSettings.set(\"category/property_name\", 0)\n"
+"\n"
+"var property_info = {\n"
+" \"name\": \"category/property_name\",\n"
+" \"type\": TYPE_INT,\n"
+" \"hint\": PROPERTY_HINT_ENUM,\n"
+" \"hint_string\": \"one,two,three\"\n"
+"}\n"
+"\n"
+"ProjectSettings.add_property_info(property_info)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:45
+msgid "Clears the whole configuration (not recommended, may break things)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:54
+msgid ""
+"Returns the order of a configuration value (influences when saved to the "
+"config file)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:63
+msgid ""
+"Returns the value of a setting.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"print(ProjectSettings.get_setting(\"application/config/name\"))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:76
+msgid ""
+"Converts a localized path ([code]res://[/code]) to a full native OS path."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:85
+msgid "Returns [code]true[/code] if a configuration value is present."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:96
+msgid ""
+"Loads the contents of the .pck or .zip file specified by [code]pack[/code] "
+"into the resource filesystem ([code]res://[/code]). Returns [code]true[/"
+"code] on success.\n"
+"[b]Note:[/b] If a file from [code]pack[/code] shares the same path as a file "
+"already in the resource filesystem, any attempts to load that file will use "
+"the file from [code]pack[/code] unless [code]replace_files[/code] is set to "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:106
+msgid "Convert a path to a localized path ([code]res://[/code] path)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:115
+msgid ""
+"Returns [code]true[/code] if the specified property exists and its initial "
+"value differs from the current value."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:124
+msgid ""
+"Returns the specified property's initial value. Returns [code]null[/code] if "
+"the property does not exist."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:131
+msgid "Saves the configuration to the [code]project.godot[/code] file."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:140
+msgid "Saves the configuration to a custom file."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:151
+msgid ""
+"Sets the specified property's initial value. This is the value the property "
+"reverts to."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:162
+msgid ""
+"Sets the order of a configuration value (influences when saved to the config "
+"file)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:173
+msgid ""
+"Sets the value of a setting.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"ProjectSettings.set_setting(\"application/config/name\", \"Example\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:183
+msgid "Background color for the boot splash."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:186
+msgid ""
+"If [code]true[/code], scale the boot splash image to the full window length "
+"when engine starts. If [code]false[/code], the engine will leave it at the "
+"default pixel size."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:189
+msgid "Path to an image used as the boot splash."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:192
+msgid ""
+"If [code]true[/code], applies linear filtering when scaling the image "
+"(recommended for high resolution artwork). If [code]false[/code], uses "
+"nearest-neighbor interpolation (recommended for pixel art)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:195
+msgid ""
+"This user directory is used for storing persistent data ([code]user://[/"
+"code] filesystem). If left empty, [code]user://[/code] resolves to a project-"
+"specific folder in Godot's own configuration folder (see [method OS."
+"get_user_data_dir]). If a custom directory name is defined, this name will "
+"be used instead and appended to the system-specific user data directory "
+"(same parent folder as the Godot configuration folder documented in [method "
+"OS.get_user_data_dir]).\n"
+"The [member application/config/use_custom_user_dir] setting must be enabled "
+"for this to take effect."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:199
+msgid ""
+"The project's description, displayed as a tooltip in the Project Manager "
+"when hovering the project."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:202
+msgid ""
+"Icon used for the project, set when project loads. Exporters will also use "
+"this icon when possible."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:205
+msgid ""
+"Icon set in [code].icns[/code] format used on macOS to set the game's icon. "
+"This is done automatically on start by calling [method DisplayServer."
+"set_native_icon]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:208
+msgid ""
+"The project's name. It is used both by the Project Manager and by exporters. "
+"The project name can be translated by translating its value in localization "
+"files."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:211
+msgid ""
+"Specifies a file to override project settings. For example: [code]user://"
+"custom_settings.cfg[/code].\n"
+"[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)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:215
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:218
+msgid ""
+"Icon set in [code].ico[/code] format used on Windows to set the game's icon. "
+"This is done automatically on start by calling [method DisplayServer."
+"set_native_icon]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:221
+msgid ""
+"If [code]true[/code], disables printing to standard error in an exported "
+"build."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:224
+msgid ""
+"If [code]true[/code], disables printing to standard output in an exported "
+"build."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:227
+msgid ""
+"Forces a delay between frames in the main loop (in milliseconds). This may "
+"be useful if you plan to disable vertical synchronization."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:230
+msgid ""
+"If [code]true[/code], enables low-processor usage mode. This setting only "
+"works on desktop platforms. The screen is not redrawn if nothing changes "
+"visually. This is meant for writing applications and editors, but is pretty "
+"useless (and can hurt performance) in most games."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:233
+msgid ""
+"Amount of sleeping between frames when the low-processor usage mode is "
+"enabled (in microseconds). Higher values will result in lower CPU usage."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:236
+msgid "Path to the main scene file that will be loaded when the project runs."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:239 doc/classes/ProjectSettings.xml:242
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:245
+msgid ""
+"Default [AudioBusLayout] resource file to use in the project, unless "
+"overridden by the scene."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:248
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:251
+msgid ""
+"If [code]true[/code], microphone input will be allowed. This requires "
+"appropriate permissions to be set when exporting to Android or iOS."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:254
+msgid ""
+"Mixing rate used for audio. In general, it's better to not touch this and "
+"leave it to the host operating system."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:257
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:260
+msgid ""
+"Setting to hardcode audio delay when playing video. Best to leave this "
+"untouched unless you know what you are doing."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:263
+msgid ""
+"Default compression level for gzip. Affects compressed scenes and resources."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:266
+msgid ""
+"Default compression level for Zlib. Affects compressed scenes and resources."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:269
+msgid ""
+"Default compression level for Zstandard. Affects compressed scenes and "
+"resources."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:272
+msgid "Enables long-distance matching in Zstandard."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:275
+msgid ""
+"Largest size limit (in power of 2) allowed when compressing using long-"
+"distance matching with Zstandard."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:278
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:281
+msgid ""
+"If [code]true[/code], enables warnings when a constant is used as a function."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:284
+msgid ""
+"If [code]true[/code], enables warnings when deprecated keywords are used."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:287
+msgid ""
+"If [code]true[/code], enables specific GDScript warnings (see [code]debug/"
+"gdscript/warnings/*[/code] settings). If [code]false[/code], disables all "
+"GDScript warnings."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:290
+msgid ""
+"If [code]true[/code], scripts in the [code]res://addons[/code] folder will "
+"not generate warnings."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:293
+msgid ""
+"If [code]true[/code], enables warnings when a function is declared with the "
+"same name as a constant."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:296
+msgid ""
+"If [code]true[/code], enables warnings when a function is declared with the "
+"same name as a variable. This will turn into an error in a future version "
+"when first-class functions become supported in GDScript."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:299
+msgid ""
+"If [code]true[/code], enables warnings when a function assigned to a "
+"variable may yield and return a function state instead of a value."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:302
+msgid ""
+"If [code]true[/code], enables warnings when using a function as if it was a "
+"property."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:305
+msgid ""
+"If [code]true[/code], enables warnings when a ternary operator may emit "
+"values with incompatible types."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:308
+msgid ""
+"If [code]true[/code], enables warnings when dividing an integer by another "
+"integer (the decimal part will be discarded)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:311
+msgid ""
+"If [code]true[/code], enables warnings when passing a floating-point value "
+"to a function that expects an integer (it will be converted and lose "
+"precision)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:314
+msgid ""
+"If [code]true[/code], enables warnings when using a property as if it was a "
+"function."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:317
+msgid ""
+"If [code]true[/code], enables warnings when calling a function without using "
+"its return value (by assigning it to a variable or using it as a function "
+"argument). Such return values are sometimes used to denote possible errors "
+"using the [enum Error] enum."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:320
+msgid ""
+"If [code]true[/code], enables warnings when defining a local or subclass "
+"member variable that would shadow a variable at an upper level (such as a "
+"member variable)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:323
+msgid ""
+"If [code]true[/code], enables warnings when calling an expression that has "
+"no effect on the surrounding code, such as writing [code]2 + 2[/code] as a "
+"statement."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:326
+msgid ""
+"If [code]true[/code], enables warnings when calling a ternary expression "
+"that has no effect on the surrounding code, such as writing [code]42 if "
+"active else 0[/code] as a statement."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:329
+msgid ""
+"If [code]true[/code], all warnings will be reported as if they were errors."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:332
+msgid ""
+"If [code]true[/code], enables warnings when using a variable that wasn't "
+"previously assigned."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:335
+msgid ""
+"If [code]true[/code], enables warnings when assigning a variable using an "
+"assignment operator like [code]+=[/code] if the variable wasn't previously "
+"assigned."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:338
+msgid ""
+"If [code]true[/code], enables warnings when unreachable code is detected "
+"(such as after a [code]return[/code] statement that will always be executed)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:341
+msgid ""
+"If [code]true[/code], enables warnings when using an expression whose type "
+"may not be compatible with the function parameter expected."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:344
+msgid "If [code]true[/code], enables warnings when performing an unsafe cast."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:347
+msgid ""
+"If [code]true[/code], enables warnings when calling a method whose presence "
+"is not guaranteed at compile-time in the class."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:350
+msgid ""
+"If [code]true[/code], enables warnings when accessing a property whose "
+"presence is not guaranteed at compile-time in the class."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:353
+msgid ""
+"If [code]true[/code], enables warnings when a function parameter is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:356
+msgid ""
+"If [code]true[/code], enables warnings when a member variable is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:359
+msgid "If [code]true[/code], enables warnings when a signal is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:362
+msgid "If [code]true[/code], enables warnings when a local variable is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:365
+msgid ""
+"If [code]true[/code], enables warnings when a variable is declared with the "
+"same name as a function. This will turn into an error in a future version "
+"when first-class functions become supported in GDScript."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:368
+msgid ""
+"If [code]true[/code], enables warnings when assigning the result of a "
+"function that returns [code]void[/code] to a variable."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:371
+msgid "Message to be displayed before the backtrace when the engine crashes."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:374
+msgid ""
+"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.\n"
+"If [member display/window/vsync/use_vsync] is enabled, it takes precedence "
+"and the forced FPS number cannot exceed the monitor's refresh rate.\n"
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:379
+msgid "Maximum call stack allowed for debugging GDScript."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:382
+msgid "Maximum amount of functions per frame allowed when profiling."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:385
+msgid "Print frames per second to standard output every second."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:388
+msgid ""
+"Print more information to standard output when running. It displays "
+"information such as memory leaks, which scenes and resources are being "
+"loaded, etc."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:391
+msgid "Maximum call stack in visual scripting, to avoid infinite recursion."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:394
+msgid ""
+"Color of the contact points between collision shapes, visible when \"Visible "
+"Collision Shapes\" is enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:397
+msgid ""
+"Maximum number of contact points between collision shapes to display when "
+"\"Visible Collision Shapes\" is enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:400
+msgid ""
+"Color of the collision shapes, visible when \"Visible Collision Shapes\" is "
+"enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:403
+msgid ""
+"Color of the disabled navigation geometry, visible when \"Visible Navigation"
+"\" is enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:406
+msgid ""
+"Color of the navigation geometry, visible when \"Visible Navigation\" is "
+"enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:409
+msgid "Custom image for the mouse cursor (limited to 256×256)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:412
+msgid "Hotspot for the custom mouse cursor image."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:415
+msgid "Position offset for tooltips, relative to the mouse cursor's hotspot."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:418
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:421
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:424
+msgid "Default orientation on mobile devices."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:427
+msgid ""
+"If [code]true[/code], the home indicator is hidden automatically. This only "
+"affects iOS devices without a physical home button."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:430
+msgid "Force the window to be always on top."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:433
+msgid "Force the window to be borderless."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:436
+msgid "Sets the window to full screen when it starts."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:439
+msgid ""
+"Sets the game's main viewport height. On desktop platforms, this is the "
+"default window size. Stretch mode settings also use this as a reference when "
+"enabled."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:442
+msgid "Allows the window to be resizable by default."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:445
+msgid ""
+"If greater than zero, overrides the window height when running the game. "
+"Useful for testing stretch modes."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:448
+msgid ""
+"If greater than zero, overrides the window width when running the game. "
+"Useful for testing stretch modes."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:451
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:454
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:457
+msgid ""
+"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.)\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:461
+msgid ""
+"Search path for project-specific script templates. Script templates will be "
+"search both in the editor-specific path and in this project-specific path."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:464
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:467
+msgid ""
+"Default value for [member ScrollContainer.scroll_deadzone], which will be "
+"used for all [ScrollContainer]s unless overridden."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:470
+msgid ""
+"If [code]true[/code], swaps OK and Cancel buttons in dialogs on Windows and "
+"UWP to follow interface conventions."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:473
+msgid ""
+"Path to a custom [Theme] resource file to use for the project ([code]theme[/"
+"code] or generic [code]tres[/code]/[code]res[/code] extension)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:476
+msgid ""
+"Path to a custom [Font] resource to use as default for all GUI elements of "
+"the project."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:479
+msgid "If [code]true[/code], makes sure the theme used works with HiDPI."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:482
+msgid ""
+"Timer setting for incremental search in [Tree], [ItemList], etc. controls "
+"(in milliseconds)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:485
+msgid "Timer for detecting idle in [TextEdit] (in seconds)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:488
+msgid "Default delay for tooltips (in seconds)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:491
+msgid ""
+"Default [InputEventAction] to confirm a focused button, menu or list item, "
+"or validate input.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:495
+msgid ""
+"Default [InputEventAction] to discard a modal or pending input.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:499
+msgid ""
+"Default [InputEventAction] to move down in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:503
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:507
+msgid ""
+"Default [InputEventAction] to focus the next [Control] in the scene. The "
+"focus behavior can be configured via [member Control.focus_next].\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:511
+msgid ""
+"Default [InputEventAction] to focus the previous [Control] in the scene. The "
+"focus behavior can be configured via [member Control.focus_previous].\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:515
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:519
+msgid ""
+"Default [InputEventAction] to move left in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:523
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:527
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:531
+msgid ""
+"Default [InputEventAction] to move right in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:535
+msgid ""
+"Default [InputEventAction] to select an item in a [Control] (e.g. in an "
+"[ItemList] or a [Tree]).\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:539
+msgid ""
+"Default [InputEventAction] to move up in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:543
+msgid ""
+"If [code]true[/code], sends mouse input events when tapping or swiping on "
+"the touchscreen."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:546
+msgid ""
+"If [code]true[/code], sends touch input events when clicking or dragging the "
+"mouse."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:549
+msgid "Optional name for the 2D physics layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:552
+msgid "Optional name for the 2D physics layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:555
+msgid "Optional name for the 2D physics layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:558
+msgid "Optional name for the 2D physics layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:561
+msgid "Optional name for the 2D physics layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:564
+msgid "Optional name for the 2D physics layer 14."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:567
+msgid "Optional name for the 2D physics layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:570
+msgid "Optional name for the 2D physics layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:573
+msgid "Optional name for the 2D physics layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:576
+msgid "Optional name for the 2D physics layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:579
+msgid "Optional name for the 2D physics layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:582
+msgid "Optional name for the 2D physics layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:585
+msgid "Optional name for the 2D physics layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:588
+msgid "Optional name for the 2D physics layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:591
+msgid "Optional name for the 2D physics layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:594
+msgid "Optional name for the 2D physics layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:597
+msgid "Optional name for the 2D physics layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:600
+msgid "Optional name for the 2D physics layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:603
+msgid "Optional name for the 2D physics layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:606
+msgid "Optional name for the 2D physics layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:609
+msgid "Optional name for the 2D render layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:612
+msgid "Optional name for the 2D render layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:615
+msgid "Optional name for the 2D render layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:618
+msgid "Optional name for the 2D render layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:621
+msgid "Optional name for the 2D render layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:624
+msgid "Optional name for the 2D render layer 14."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:627
+msgid "Optional name for the 2D render layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:630
+msgid "Optional name for the 2D render layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:633
+msgid "Optional name for the 2D render layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:636
+msgid "Optional name for the 2D render layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:639
+msgid "Optional name for the 2D render layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:642
+msgid "Optional name for the 2D render layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:645
+msgid "Optional name for the 2D render layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:648
+msgid "Optional name for the 2D render layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:651
+msgid "Optional name for the 2D render layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:654
+msgid "Optional name for the 2D render layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:657
+msgid "Optional name for the 2D render layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:660
+msgid "Optional name for the 2D render layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:663
+msgid "Optional name for the 2D render layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:666
+msgid "Optional name for the 2D render layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:669
+msgid "Optional name for the 3D physics layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:672
+msgid "Optional name for the 3D physics layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:675
+msgid "Optional name for the 3D physics layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:678
+msgid "Optional name for the 3D physics layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:681
+msgid "Optional name for the 3D physics layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:684
+msgid "Optional name for the 3D physics layer 14."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:687
+msgid "Optional name for the 3D physics layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:690
+msgid "Optional name for the 3D physics layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:693
+msgid "Optional name for the 3D physics layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:696
+msgid "Optional name for the 3D physics layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:699
+msgid "Optional name for the 3D physics layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:702
+msgid "Optional name for the 3D physics layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:705
+msgid "Optional name for the 3D physics layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:708
+msgid "Optional name for the 3D physics layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:711
+msgid "Optional name for the 3D physics layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:714
+msgid "Optional name for the 3D physics layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:717
+msgid "Optional name for the 3D physics layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:720
+msgid "Optional name for the 3D physics layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:723
+msgid "Optional name for the 3D physics layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:726
+msgid "Optional name for the 3D physics layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:729
+msgid "Optional name for the 3D render layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:732
+msgid "Optional name for the 3D render layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:735
+msgid "Optional name for the 3D render layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:738
+msgid "Optional name for the 3D render layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:741
+msgid "Optional name for the 3D render layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:744
+msgid "Optional name for the 3D render layer 14"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:747
+msgid "Optional name for the 3D render layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:750
+msgid "Optional name for the 3D render layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:753
+msgid "Optional name for the 3D render layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:756
+msgid "Optional name for the 3D render layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:759
+msgid "Optional name for the 3D render layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:762
+msgid "Optional name for the 3D render layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:765
+msgid "Optional name for the 3D render layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:768
+msgid "Optional name for the 3D render layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:771
+msgid "Optional name for the 3D render layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:774
+msgid "Optional name for the 3D render layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:777
+msgid "Optional name for the 3D render layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:780
+msgid "Optional name for the 3D render layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:783
+msgid "Optional name for the 3D render layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:786
+msgid "Optional name for the 3D render layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:789
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:792
+msgid ""
+"If non-empty, this locale will be used when running the project from the "
+"editor."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:795
+msgid "If [code]true[/code], logs all output to files."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:798
+msgid ""
+"Path to logs within the project. Using an [code]user://[/code] path is "
+"recommended."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:801
+msgid "Specifies the maximum amount of log files allowed (used for rotation)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:804
+msgid ""
+"Godot uses a message queue to defer some function calls. If you run out of "
+"space on it (you will see an error), you can increase the size here."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:807
+msgid ""
+"This is used by servers when used in multi-threading mode (servers and "
+"visual). RIDs are preallocated to avoid stalling the server requesting them "
+"on threads. If servers get stalled too often when loading resources in a "
+"thread, increase this number."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:822
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:825
+msgid ""
+"Maximum number of errors allowed to be sent from the debugger. Over this "
+"value, content is dropped. This helps not to stall the debugger connection."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:828
+msgid ""
+"Maximum amount of messages in the debugger queue. Over this value, content "
+"is dropped. This helps to limit the debugger memory usage."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:831
+msgid ""
+"Maximum number of warnings allowed to be sent from the debugger. Over this "
+"value, content is dropped. This helps not to stall the debugger connection."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:834
+msgid ""
+"Default size of packet peer stream for deserializing Godot data. Over this "
+"size, data is dropped."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:837
+msgid "Timeout (in seconds) for connection attempts using TCP."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:840
+msgid "Maximum size (in kiB) for the [WebRTCDataChannel] input buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:843
+msgid "Maximum size (in kiB) for the [WebSocketClient] input buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:846
+msgid "Maximum number of concurrent input packets for [WebSocketClient]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:849
+msgid "Maximum size (in kiB) for the [WebSocketClient] output buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:852
+msgid "Maximum number of concurrent output packets for [WebSocketClient]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:855
+msgid "Maximum size (in kiB) for the [WebSocketServer] input buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:858
+msgid "Maximum number of concurrent input packets for [WebSocketServer]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:861
+msgid "Maximum size (in kiB) for the [WebSocketServer] output buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:864
+msgid "Maximum number of concurrent output packets for [WebSocketServer]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:867
+msgid ""
+"Amount of read ahead used by remote filesystem. Higher values decrease the "
+"effects of latency at the cost of higher bandwidth usage."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:870
+msgid "Page size used by remote filesystem (in bytes)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:873
+msgid ""
+"CA certificates bundle to use for SSL connections. If not defined, Godot's "
+"internal CA certificates are used."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:876
+msgid ""
+"When creating node names automatically, set the type of casing in this "
+"project. This is mostly an editor setting."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:879
+msgid ""
+"What to use to separate node name from number. This is mostly an editor "
+"setting."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:882
+msgid "Size of the hash table used for the broad-phase 2D hash grid algorithm."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:885
+msgid "Cell size used for the broad-phase 2D hash grid algorithm."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:888
+msgid "The default angular damp in 2D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:891
+msgid ""
+"The default gravity strength in 2D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity strength to 98.\n"
+"PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), "
+"PhysicsServer2D.AREA_PARAM_GRAVITY, 98)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:899
+msgid ""
+"The default gravity direction in 2D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity vector at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity direction to `Vector2(0, 1)`.\n"
+"PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), "
+"PhysicsServer2D.AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:907
+msgid "The default linear damp in 2D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:910
+msgid ""
+"Threshold defining the surface size that constitutes a large object with "
+"regard to cells in the broad-phase 2D hash grid algorithm."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:913
+msgid ""
+"Sets which physics engine to use for 2D physics.\n"
+"\"DEFAULT\" and \"GodotPhysics\" are the same, as there is currently no "
+"alternative 2D physics server implemented."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:917
+msgid ""
+"Threshold angular velocity under which a 2D physics body will be considered "
+"inactive. See [constant PhysicsServer2D."
+"SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:920
+msgid ""
+"Threshold linear velocity under which a 2D physics body will be considered "
+"inactive. See [constant PhysicsServer2D."
+"SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:923
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:927
+msgid ""
+"Time (in seconds) of inactivity before which a 2D physics body will put to "
+"sleep. See [constant PhysicsServer2D.SPACE_PARAM_BODY_TIME_TO_SLEEP]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:930
+msgid ""
+"Sets whether the 3D physics world will be created with support for "
+"[SoftBody3D] physics. Only applies to the Bullet physics engine."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:933
+msgid "The default angular damp in 3D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:936
+msgid ""
+"The default gravity strength in 3D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity strength to 9.8.\n"
+"PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), "
+"PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:944
+msgid ""
+"The default gravity direction in 3D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity vector at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity direction to `Vector3(0, -1, 0)`.\n"
+"PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), "
+"PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3(0, -1, 0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:952
+msgid "The default linear damp in 3D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:955
+msgid ""
+"Sets which physics engine to use for 3D physics.\n"
+"\"DEFAULT\" is currently the [url=https://bulletphysics.org]Bullet[/url] "
+"physics engine. The \"GodotPhysics\" engine is still supported as an "
+"alternative."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:959
+msgid "Enables [member Viewport.physics_object_picking] on the root viewport."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:962
+msgid ""
+"The number of fixed iterations per second. This controls how often physics "
+"simulation and [method Node._physics_process] methods are run.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the physics FPS at runtime, set [member Engine.iterations_per_second] "
+"instead."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:966
+msgid ""
+"Fix to improve physics jitter, specially on monitors where refresh rate is "
+"different than the physics FPS.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:970
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:973
+msgid ""
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:976
+msgid ""
+"Max amount of elements renderable in a frame. If more than this are visible "
+"per frame, they will be dropped. Keep in mind elements refer to mesh "
+"surfaces and not meshes themselves."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:979
+msgid ""
+"Some NVIDIA GPU drivers have a bug which produces flickering issues for the "
+"[code]draw_rect[/code] method, especially as used in [TileMap]. Refer to "
+"[url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/"
+"url] for details.\n"
+"If [code]true[/code], this option enables a \"safe\" code path for such "
+"NVIDIA GPUs at the cost of performance. This option only impacts the GLES2 "
+"rendering backend, and only desktop platforms. It is not necessary when "
+"using the Vulkan backend."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:983
+msgid ""
+"If [code]true[/code], forces snapping of polygons to pixels in 2D rendering. "
+"May help in some pixel art styles."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:986
+msgid ""
+"Disables depth pre-pass for some GPU vendors (usually mobile), as their "
+"architecture already does this."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:989
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:992
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:995
+msgid ""
+"Lower-end override for [member rendering/quality/directional_shadow/size] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:998
+msgid ""
+"The video driver to use (\"GLES2\" or \"Vulkan\").\n"
+"[b]Note:[/b] The backend in use can be overridden at runtime via the [code]--"
+"rendering-driver[/code] command line argument.\n"
+"[b]FIXME:[/b] No longer valid after DisplayServer split:\n"
+"In such cases, this property is not updated, so use [code]OS."
+"get_current_video_driver[/code] to query it at run-time."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1012
+msgid ""
+"Sets the number of MSAA samples to use. 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.\n"
+"[b]Note:[/b] MSAA is not available on HTML5 export using the GLES2 backend."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1020
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1031
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1034
+msgid ""
+"Lower-end override for [member rendering/quality/intended_usage/"
+"framebuffer_allocation] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1037
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1040
+msgid ""
+"Size of cubemap faces for [ReflectionProbe]s. A higher number requires more "
+"VRAM and may make reflection probe updating slower."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1043
+msgid ""
+"Lower-end override for [member rendering/quality/reflection_atlas/"
+"reflection_size] on mobile devices, due to performance concerns or driver "
+"support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1046
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1049
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1052
+msgid ""
+"Lower-end override for [member rendering/quality/reflections/ggx_samples] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1055
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1058
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1061
+msgid ""
+"Lower-end override for [member rendering/quality/reflections/"
+"texture_array_reflections] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1066
+msgid ""
+"If [code]true[/code], uses faster but lower-quality Blinn model to generate "
+"blurred reflections instead of the GGX model."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1069
+msgid ""
+"Lower-end override for [member rendering/quality/shading/"
+"force_blinn_over_ggx] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1072
+msgid ""
+"If [code]true[/code], uses faster but lower-quality Lambert material "
+"lighting model instead of Burley."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1075
+msgid ""
+"Lower-end override for [member rendering/quality/shading/"
+"force_lambert_over_burley] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1078
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1081
+msgid ""
+"Lower-end override for [member rendering/quality/shading/"
+"force_vertex_shading] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1084 doc/classes/ProjectSettings.xml:1087
+#: doc/classes/ProjectSettings.xml:1090 doc/classes/ProjectSettings.xml:1093
+msgid ""
+"Subdivision quadrant size for shadow mapping. See shadow mapping "
+"documentation."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1096
+msgid ""
+"Size for shadow atlas (used for OmniLights and SpotLights). See "
+"documentation."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1099
+msgid ""
+"Lower-end override for [member rendering/quality/shadow_atlas/size] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1102
+msgid ""
+"Shadow filter mode. Higher-quality settings result in smoother shadows that "
+"flicker less when moving. \"Disabled\" is the fastest option, but also has "
+"the lowest quality. \"PCF5\" is smoother but is also slower. \"PCF13\" is "
+"the smoothest option, but is also the slowest."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1105
+msgid ""
+"Lower-end override for [member rendering/quality/shadows/filter_mode] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1118
+msgid ""
+"Thread model for rendering. Rendering on a thread can vastly improve "
+"performance, but synchronizing to the main thread can cause a bit more "
+"jitter."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1121
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1124
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1127
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1130
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1133
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProximityGroup3D.xml:4 doc/classes/ProximityGroup3D.xml:7
+msgid "General-purpose proximity detection node."
+msgstr ""
+
+#: doc/classes/QuadMesh.xml:4
+msgid "Class representing a square mesh."
+msgstr ""
+
+#: doc/classes/QuadMesh.xml:7
+msgid ""
+"Class representing a square [PrimitiveMesh]. This flat mesh does not have a "
+"thickness. By default, this mesh is aligned on the X and Y axes; this "
+"default rotation is more suited for use with billboarded materials. Unlike "
+"[PlaneMesh], this mesh doesn't provide subdivision options."
+msgstr ""
+
+#: doc/classes/QuadMesh.xml:15
+msgid "Size on the X and Y axes."
+msgstr ""
+
+#: doc/classes/Quat.xml:4
+msgid "Quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:7
+msgid ""
+"A unit quaternion used for representing 3D rotations.\n"
+"It is similar to [Basis], which implements matrix representation of "
+"rotations, and can be parametrized using both an axis-angle pair or Euler "
+"angles. But due to its compactness and the way it is stored in memory, "
+"certain operations (obtaining axis-angle and performing SLERP, in "
+"particular) are more efficient and robust against floating-point errors.\n"
+"Quaternions need to be (re)normalized."
+msgstr ""
+
+#: doc/classes/Quat.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms."
+"html#interpolating-with-quaternions"
+msgstr ""
+
+#: doc/classes/Quat.xml:21
+msgid "Returns the rotation matrix corresponding to the given quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:30
+msgid ""
+"Returns a quaternion that will perform a rotation specified by Euler angles "
+"(in the YXZ convention: first Z, then X, and Y last), given in the vector "
+"format as (X angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Quat.xml:41
+msgid ""
+"Returns a quaternion that will rotate around the given axis by the specified "
+"angle. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Quat.xml:56
+msgid "Returns a quaternion defined by these values."
+msgstr ""
+
+#: doc/classes/Quat.xml:71
+msgid ""
+"Performs a cubic spherical-linear interpolation with another quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:80
+msgid "Returns the dot product of two quaternions."
+msgstr ""
+
+#: doc/classes/Quat.xml:87
+msgid ""
+"Returns Euler angles (in the YXZ convention: 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)."
+msgstr ""
+
+#: doc/classes/Quat.xml:94
+msgid "Returns the inverse of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:103
+msgid ""
+"Returns [code]true[/code] if this quaterion and [code]quat[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Quat.xml:110
+msgid "Returns whether the quaternion is normalized or not."
+msgstr ""
+
+#: doc/classes/Quat.xml:117
+msgid "Returns the length of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:124
+msgid "Returns the length of the quaternion, squared."
+msgstr ""
+
+#: doc/classes/Quat.xml:131
+msgid "Returns a copy of the quaternion, normalized to unit length."
+msgstr ""
+
+#: doc/classes/Quat.xml:142
+msgid ""
+"Sets the quaternion to a rotation which rotates around axis by the specified "
+"angle, in radians. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Quat.xml:151
+msgid ""
+"Sets the quaternion to a rotation specified by Euler angles (in the YXZ "
+"convention: first Z, then X, and Y last), given in the vector format as (X "
+"angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Quat.xml:162
+msgid "Performs a spherical-linear interpolation with another quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:173
+msgid ""
+"Performs a spherical-linear interpolation with another quaterion without "
+"checking if the rotation path is not bigger than 90°."
+msgstr ""
+
+#: doc/classes/Quat.xml:182
+msgid "Transforms the vector [code]v[/code] by this quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:188
+msgid "W component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:191
+msgid "X component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:194
+msgid "Y component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:197
+msgid "Z component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:202
+msgid ""
+"The identity rotation. Equivalent to an identity matrix. If a vector is "
+"transformed by an identity quaternion, it will not change."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:4
+msgid "A class for generating pseudo-random numbers."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:7
+msgid ""
+"RandomNumberGenerator is a class for generating pseudo-random numbers. It "
+"currently uses [url=http://www.pcg-random.org/]PCG32[/url].\n"
+"[b]Note:[/b] The underlying algorithm is an implementation detail. As a "
+"result, it should not be depended upon for reproducible random streams "
+"across Godot versions.\n"
+"To generate a random float number (within a given range) based on a time-"
+"dependant seed:\n"
+"[codeblock]\n"
+"var rng = RandomNumberGenerator.new()\n"
+"func _ready():\n"
+" rng.randomize()\n"
+" var my_random_number = rng.randf_range(-10.0, 10.0)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:24
+msgid ""
+"Generates a pseudo-random float between [code]0.0[/code] and [code]1.0[/"
+"code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:35
+msgid ""
+"Generates a pseudo-random float between [code]from[/code] and [code]to[/"
+"code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:46
+msgid ""
+"Generates a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-"
+"distributed[/url] pseudo-random number, using Box-Muller transform with the "
+"specified [code]mean[/code] and a standard [code]deviation[/code]. This is "
+"also called Gaussian distribution."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:53
+msgid ""
+"Generates a pseudo-random 32-bit unsigned integer between [code]0[/code] and "
+"[code]4294967295[/code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:64
+msgid ""
+"Generates a pseudo-random 32-bit signed integer between [code]from[/code] "
+"and [code]to[/code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:71
+msgid "Setups a time-based seed to generator."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:77
+msgid ""
+"The seed used by the random number generator. A given seed will give a "
+"reproducible sequence of pseudo-random numbers.\n"
+"[b]Note:[/b] The RNG does not have an avalanche effect, and can output "
+"similar random streams given similar seeds. Consider using a hash function "
+"to improve your seed quality if they're sourced externally."
+msgstr ""
+
+#: doc/classes/Range.xml:4
+msgid "Abstract base class for range-based controls."
+msgstr ""
+
+#: doc/classes/Range.xml:7
+msgid ""
+"Range is a base class for [Control] nodes that change a floating-point "
+"[i]value[/i] between a [i]minimum[/i] and a [i]maximum[/i], using [i]step[/"
+"i] and [i]page[/i], for example a [ScrollBar]."
+msgstr ""
+
+#: doc/classes/Range.xml:18
+msgid ""
+"Binds two ranges together along with any ranges previously grouped with "
+"either of them. When any of range's member variables change, it will share "
+"the new value with all other ranges in its group."
+msgstr ""
+
+#: doc/classes/Range.xml:25
+msgid "Stops range from sharing its member variables with any other."
+msgstr ""
+
+#: doc/classes/Range.xml:31
+msgid ""
+"If [code]true[/code], [member value] may be greater than [member max_value]."
+msgstr ""
+
+#: doc/classes/Range.xml:34
+msgid ""
+"If [code]true[/code], [member value] may be less than [member min_value]."
+msgstr ""
+
+#: doc/classes/Range.xml:37
+msgid ""
+"If [code]true[/code], and [code]min_value[/code] is greater than 0, "
+"[code]value[/code] will be represented exponentially rather than linearly."
+msgstr ""
+
+#: doc/classes/Range.xml:40
+msgid ""
+"Maximum value. Range is clamped if [code]value[/code] is greater than "
+"[code]max_value[/code]."
+msgstr ""
+
+#: doc/classes/Range.xml:43
+msgid ""
+"Minimum value. Range is clamped if [code]value[/code] is less than "
+"[code]min_value[/code]."
+msgstr ""
+
+#: doc/classes/Range.xml:46
+msgid ""
+"Page size. Used mainly for [ScrollBar]. ScrollBar's length is its size "
+"multiplied by [code]page[/code] over the difference between [code]min_value[/"
+"code] and [code]max_value[/code]."
+msgstr ""
+
+#: doc/classes/Range.xml:49
+msgid "The value mapped between 0 and 1."
+msgstr ""
+
+#: doc/classes/Range.xml:52
+msgid ""
+"If [code]true[/code], [code]value[/code] will always be rounded to the "
+"nearest integer."
+msgstr ""
+
+#: doc/classes/Range.xml:55
+msgid ""
+"If greater than 0, [code]value[/code] will always be rounded to a multiple "
+"of [code]step[/code]. If [code]rounded[/code] is also [code]true[/code], "
+"[code]value[/code] will first be rounded to a multiple of [code]step[/code] "
+"then rounded to the nearest integer."
+msgstr ""
+
+#: doc/classes/Range.xml:58
+msgid "Range's current value."
+msgstr ""
+
+#: doc/classes/Range.xml:64
+msgid ""
+"Emitted when [member min_value], [member max_value], [member page], or "
+"[member step] change."
+msgstr ""
+
+#: doc/classes/Range.xml:71
+msgid "Emitted when [member value] changes."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:4 doc/classes/RayCast3D.xml:4
+msgid "Query the closest object intersecting a ray."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:7
+msgid ""
+"A RayCast represents a line from its origin to its destination position, "
+"[code]cast_to[/code]. It is used to query the 2D space in order to find the "
+"closest object along the path of the ray.\n"
+"RayCast2D can ignore some objects by adding them to the exception list via "
+"[code]add_exception[/code], by setting proper filtering with collision "
+"layers, or by filtering object types with type masks.\n"
+"RayCast2D can be configured to report collisions with [Area2D]s ([member "
+"collide_with_areas]) and/or [PhysicsBody2D]s ([member "
+"collide_with_bodies]).\n"
+"Only enabled raycasts will be able to query the space and report "
+"collisions.\n"
+"RayCast2D calculates intersection every physics frame (see [Node]), and the "
+"result is cached so it can be used later until the next frame. If multiple "
+"queries are required between physics frames (or during the same frame) use "
+"[method force_raycast_update] after adjusting the raycast."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:23 doc/classes/RayCast3D.xml:23
+msgid ""
+"Adds a collision exception so the ray does not report collisions with the "
+"specified node."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:32 doc/classes/RayCast3D.xml:32
+msgid ""
+"Adds a collision exception so the ray does not report collisions with the "
+"specified [RID]."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:39 doc/classes/RayCast3D.xml:39
+msgid "Removes all collision exceptions for this ray."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:46
+msgid ""
+"Updates the collision information for the ray. Use this method to update the "
+"collision information immediately instead of waiting for the next "
+"[code]_physics_process[/code] call, for example if the ray or its parent has "
+"changed state.\n"
+"[b]Note:[/b] [code]enabled == true[/code] is not required for this to work."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:54 doc/classes/RayCast3D.xml:55
+msgid ""
+"Returns the first object that the ray intersects, or [code]null[/code] if no "
+"object is intersecting the ray (i.e. [method is_colliding] returns "
+"[code]false[/code])."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:61 doc/classes/RayCast3D.xml:62
+msgid ""
+"Returns the shape ID of the first object that the ray intersects, or "
+"[code]0[/code] if no object is intersecting the ray (i.e. [method "
+"is_colliding] returns [code]false[/code])."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:77 doc/classes/RayCast3D.xml:79
+msgid ""
+"Returns the normal of the intersecting object's shape at the collision point."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:84
+msgid ""
+"Returns the collision point at which the ray intersects the closest object.\n"
+"[b]Note:[/b] this point is in the [b]global[/b] coordinate system."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:92 doc/classes/RayCast3D.xml:94
+msgid ""
+"Returns whether any object is intersecting with the ray's vector "
+"(considering the vector length)."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:101 doc/classes/RayCast3D.xml:103
+msgid ""
+"Removes a collision exception so the ray does report collisions with the "
+"specified node."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:110 doc/classes/RayCast3D.xml:112
+msgid ""
+"Removes a collision exception so the ray does report collisions with the "
+"specified [RID]."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:121
+msgid ""
+"Sets or clears individual bits on the collision mask. This makes selecting "
+"the areas scanned easier."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:127 doc/classes/RayCast3D.xml:130
+msgid ""
+"The ray's destination point, relative to the RayCast's [code]position[/code]."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:130
+msgid "If [code]true[/code], collision with [Area2D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:133
+msgid "If [code]true[/code], collision with [PhysicsBody2D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:136 doc/classes/RayCast3D.xml:139
+msgid ""
+"The ray's collision mask. Only objects in at least one collision layer "
+"enabled in the mask will be detected."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:139 doc/classes/RayCast3D.xml:142
+msgid "If [code]true[/code], collisions will be reported."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:142
+msgid ""
+"If [code]true[/code], the parent node will be excluded from collision "
+"detection."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:7
+msgid ""
+"A RayCast represents a line from its origin to its destination position, "
+"[code]cast_to[/code]. It is used to query the 3D space in order to find the "
+"closest object along the path of the ray.\n"
+"RayCast3D can ignore some objects by adding them to the exception list via "
+"[code]add_exception[/code] or by setting proper filtering with collision "
+"layers and masks.\n"
+"RayCast3D can be configured to report collisions with [Area3D]s ([member "
+"collide_with_areas]) and/or [PhysicsBody3D]s ([member "
+"collide_with_bodies]).\n"
+"Only enabled raycasts will be able to query the space and report "
+"collisions.\n"
+"RayCast3D calculates intersection every physics frame (see [Node]), and the "
+"result is cached so it can be used later until the next frame. If multiple "
+"queries are required between physics frames (or during the same frame), use "
+"[method force_raycast_update] after adjusting the raycast."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:46
+msgid ""
+"Updates the collision information for the ray.\n"
+"Use this method to update the collision information immediately instead of "
+"waiting for the next [code]_physics_process[/code] call, for example if the "
+"ray or its parent has changed state.\n"
+"[b]Note:[/b] [code]enabled == true[/code] is not required for this to work."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:71
+msgid ""
+"Returns [code]true[/code] if the bit index passed is turned on.\n"
+"[b]Note:[/b] Bit indices range from 0-19."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:86
+msgid ""
+"Returns the collision point at which the ray intersects the closest object.\n"
+"[b]Note:[/b] This point is in the [b]global[/b] coordinate system."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:123
+msgid ""
+"Sets the bit index passed to the [code]value[/code] passed.\n"
+"[b]Note:[/b] Bit indexes range from 0-19."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:133
+msgid "If [code]true[/code], collision with [Area3D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:136
+msgid "If [code]true[/code], collision with [PhysicsBody3D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:145
+msgid ""
+"If [code]true[/code], collisions will be ignored for this RayCast3D's "
+"immediate parent."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:4
+msgid "Ray shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:7
+msgid ""
+"Ray shape for 2D collisions. A ray is not really a collision body; instead, "
+"it tries to separate itself from whatever is touching its far endpoint. It's "
+"often useful for characters."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:15 doc/classes/RayShape3D.xml:15
+msgid "The ray's length."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:18 doc/classes/RayShape3D.xml:18
+msgid "If [code]true[/code], allow the shape to return the correct normal."
+msgstr ""
+
+#: doc/classes/RayShape3D.xml:4
+msgid "Ray shape for 3D collisions."
+msgstr ""
+
+#: doc/classes/RayShape3D.xml:7
+msgid ""
+"Ray shape for 3D collisions, which can be set into a [PhysicsBody3D] or "
+"[Area3D]. A ray is not really a collision body; instead, it tries to "
+"separate itself from whatever is touching its far endpoint. It's often "
+"useful for characters."
+msgstr ""
+
+#: doc/classes/Rect2.xml:4
+msgid "2D axis-aligned bounding box using floating point coordinates."
+msgstr ""
+
+#: doc/classes/Rect2.xml:7
+msgid ""
+"[Rect2] consists of a position, a size, and several utility functions. It is "
+"typically used for fast overlap tests.\n"
+"It uses floating point coordinates."
+msgstr ""
+
+#: doc/classes/Rect2.xml:22
+msgid "Constructs a [Rect2] by position and size."
+msgstr ""
+
+#: doc/classes/Rect2.xml:37
+msgid "Constructs a [Rect2] by x, y, width, and height."
+msgstr ""
+
+#: doc/classes/Rect2.xml:46
+msgid "Constructs a [Rect2] from a [Rect2i]."
+msgstr ""
+
+#: doc/classes/Rect2.xml:53
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Rect2.xml:62
+msgid "Returns the intersection of this [Rect2] and b."
+msgstr ""
+
+#: doc/classes/Rect2.xml:71
+msgid ""
+"Returns [code]true[/code] if this [Rect2] completely encloses another one."
+msgstr ""
+
+#: doc/classes/Rect2.xml:80
+msgid "Returns this [Rect2] expanded to include a given point."
+msgstr ""
+
+#: doc/classes/Rect2.xml:87
+msgid "Returns the area of the [Rect2]."
+msgstr ""
+
+#: doc/classes/Rect2.xml:96
+msgid ""
+"Returns a copy of the [Rect2] grown a given amount of units towards all the "
+"sides."
+msgstr ""
+
+#: doc/classes/Rect2.xml:111
+msgid ""
+"Returns a copy of the [Rect2] grown a given amount of units towards each "
+"direction individually."
+msgstr ""
+
+#: doc/classes/Rect2.xml:122
+msgid ""
+"Returns a copy of the [Rect2] grown a given amount of units towards the "
+"[enum Margin] direction."
+msgstr ""
+
+#: doc/classes/Rect2.xml:129
+msgid "Returns [code]true[/code] if the [Rect2] is flat or empty."
+msgstr ""
+
+#: doc/classes/Rect2.xml:138
+msgid "Returns [code]true[/code] if the [Rect2] contains a point."
+msgstr ""
+
+#: doc/classes/Rect2.xml:149
+msgid ""
+"Returns [code]true[/code] if the [Rect2] overlaps with [code]b[/code] (i.e. "
+"they have at least one point in common).\n"
+"If [code]include_borders[/code] is [code]true[/code], they will also be "
+"considered overlapping if their borders touch, even without intersection."
+msgstr ""
+
+#: doc/classes/Rect2.xml:159
+msgid ""
+"Returns [code]true[/code] if this [Rect2] and [code]rect[/code] are "
+"approximately equal, by calling [code]is_equal_approx[/code] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Rect2.xml:168
+msgid "Returns a larger [Rect2] that contains this [Rect2] and [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Rect2.xml:174
+msgid "Ending corner."
+msgstr ""
+
+#: doc/classes/Rect2.xml:177
+msgid "Position (starting corner)."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:4
+msgid "2D axis-aligned bounding box using integer coordinates."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:7
+msgid ""
+"[Rect2i] consists of a position, a size, and several utility functions. It "
+"is typically used for fast overlap tests.\n"
+"It uses integer coordinates."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:22
+msgid "Constructs a [Rect2i] by position and size."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:37
+msgid "Constructs a [Rect2i] by x, y, width, and height."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:46
+msgid ""
+"Constructs a new [Rect2i] from [Rect2]. The floating point coordinates will "
+"be truncated."
+msgstr ""
+
+#: doc/classes/RectangleShape2D.xml:4
+msgid "Rectangle shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/RectangleShape2D.xml:7
+msgid ""
+"Rectangle shape for 2D collisions. This shape is useful for modeling box-"
+"like 2D objects."
+msgstr ""
+
+#: doc/classes/RectangleShape2D.xml:15
+msgid ""
+"The rectangle's half extents. The width and height of this shape is twice "
+"the half extents."
+msgstr ""
+
+#: doc/classes/Reference.xml:4
+msgid "Base class for reference-counted objects."
+msgstr ""
+
+#: doc/classes/Reference.xml:7
+msgid ""
+"Base class for any object that keeps a reference count. [Resource] and many "
+"other helper objects inherit this class.\n"
+"References keep an internal reference counter so that they are automatically "
+"released when no longer in use, and only then. References therefore do not "
+"need to be freed manually with [method Object.free].\n"
+"In the vast majority of use cases, instantiating and using [Reference]-"
+"derived types is all you need to do. The methods provided in this class are "
+"only for advanced users, and can cause issues if misused."
+msgstr ""
+
+#: doc/classes/Reference.xml:18
+msgid ""
+"Initializes the internal reference counter. Use this only if you really know "
+"what you are doing.\n"
+"Returns whether the initialization was successful."
+msgstr ""
+
+#: doc/classes/Reference.xml:26
+msgid ""
+"Increments the internal reference counter. Use this only if you really know "
+"what you are doing.\n"
+"Returns [code]true[/code] if the increment was successful, [code]false[/"
+"code] otherwise."
+msgstr ""
+
+#: doc/classes/Reference.xml:34
+msgid ""
+"Decrements the internal reference counter. Use this only if you really know "
+"what you are doing.\n"
+"Returns [code]true[/code] if the decrement was successful, [code]false[/"
+"code] otherwise."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:4
+msgid "Reference frame for GUI."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:7
+msgid ""
+"A rectangle box that displays only a [member border_color] border color "
+"around its rectangle. [ReferenceRect] has no fill [Color]."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:15
+msgid "Sets the border [Color] of the [ReferenceRect]."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:18
+msgid ""
+"If set to [code]true[/code], the [ReferenceRect] will only be visible while "
+"in editor. Otherwise, [ReferenceRect] will be visible in game."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:4
+msgid "Captures its surroundings to create reflections."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:7
+msgid ""
+"Captures its surroundings as a cubemap, and stores versions of it with "
+"increasing levels of blur to simulate different material roughnesses.\n"
+"The [ReflectionProbe] is used to create high-quality reflections at the cost "
+"of performance. It can be combined with [GIProbe]s and Screen Space "
+"Reflections to achieve high quality reflections. [ReflectionProbe]s render "
+"all objects within their [member cull_mask], so updating them can be quite "
+"expensive. It is best to update them once with the important static objects "
+"and then leave them."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html"
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:17
+msgid ""
+"If [code]true[/code], enables box projection. This makes reflections look "
+"more correct in rectangle-shaped rooms by offsetting the reflection center "
+"depending on the camera's location."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:20
+msgid ""
+"Sets the cull mask which determines what objects are drawn by this probe. "
+"Every [VisualInstance3D] with a layer included in this cull mask will be "
+"rendered by the probe. It is best to only include large objects which are "
+"likely to take up a lot of space in the reflection in order to save on "
+"rendering cost."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:23
+msgid ""
+"If [code]true[/code], computes shadows in the reflection probe. This makes "
+"the reflection probe slower to render; you may want to disable this if using "
+"the [constant UPDATE_ALWAYS] [member update_mode]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:26
+msgid ""
+"The size of the reflection probe. The larger the extents the more space "
+"covered by the probe which will lower the perceived resolution. It is best "
+"to keep the extents only as large as you need them."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:29
+msgid ""
+"Defines the reflection intensity. Intensity modulates the strength of the "
+"reflection."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:32
+msgid ""
+"Sets the ambient light color to be used when this probe is set to [member "
+"interior_enable]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:35
+msgid ""
+"Sets the contribution value for how much the reflection affects the ambient "
+"light for this reflection probe when set to [member interior_enable]. Useful "
+"so that ambient light matches the color of the room."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:38
+msgid ""
+"Sets the energy multiplier for this reflection probe's ambient light "
+"contribution when set to [member interior_enable]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:41
+msgid ""
+"If [code]true[/code], reflections will ignore sky contribution. Ambient "
+"lighting is then controlled by the [code]interior_ambient_*[/code] "
+"properties."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:44
+msgid ""
+"Sets the max distance away from the probe an object can be before it is "
+"culled."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:47
+msgid ""
+"Sets the origin offset to be used when this reflection probe is in box "
+"project mode."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:50
+msgid ""
+"Sets how frequently the probe is updated. Can be [constant UPDATE_ONCE] or "
+"[constant UPDATE_ALWAYS]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:55
+msgid ""
+"Update the probe once on the next frame. The corresponding radiance map will "
+"be generated over the following six frames. This is slower to update than "
+"[constant UPDATE_ALWAYS] but can result in higher quality reflections."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:58
+msgid ""
+"Update the probe every frame. This is needed when you want to capture "
+"dynamic objects. However, it results in an increased render time. Use "
+"[constant UPDATE_ONCE] whenever possible."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:4
+msgid "Class for searching text for patterns using regular expressions."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:7
+msgid ""
+"A regular expression (or regex) is a compact language that can be used to "
+"recognise strings that follow a specific pattern, such as URLs, email "
+"addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/"
+"code] would find any string that is [code]ab[/code] followed by any number "
+"from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can "
+"easily find various tutorials and detailed explanations on the Internet.\n"
+"To begin, the RegEx object needs to be compiled with the search pattern "
+"using [method compile] before it can be used.\n"
+"[codeblock]\n"
+"var regex = RegEx.new()\n"
+"regex.compile(\"\\\\w-(\\\\d+)\")\n"
+"[/codeblock]\n"
+"The search pattern must be escaped first for GDScript before it is escaped "
+"for the expression. For example, [code]compile(\"\\\\d+\")[/code] would be "
+"read by RegEx as [code]\\d+[/code]. Similarly, [code]compile(\"\\\"(?:\\\\\\"
+"\\.|[^\\\"])*\\\"\")[/code] would be read as [code]\"(?:\\\\.|[^\"])*\"[/"
+"code].\n"
+"Using [method search] you can find the pattern within the given text. If a "
+"pattern is found, [RegExMatch] is returned and you can retrieve details of "
+"the results using functions such as [method RegExMatch.get_string] and "
+"[method RegExMatch.get_start].\n"
+"[codeblock]\n"
+"var regex = RegEx.new()\n"
+"regex.compile(\"\\\\w-(\\\\d+)\")\n"
+"var result = regex.search(\"abc n-0123\")\n"
+"if result:\n"
+" print(result.get_string()) # Would print n-0123\n"
+"[/codeblock]\n"
+"The results of capturing groups [code]()[/code] can be retrieved by passing "
+"the group number to the various functions in [RegExMatch]. Group 0 is the "
+"default and will always refer to the entire pattern. In the above example, "
+"calling [code]result.get_string(1)[/code] would give you [code]0123[/code].\n"
+"This version of RegEx also supports named capturing groups, and the names "
+"can be used to retrieve the results. If two or more groups have the same "
+"name, the name would only refer to the first one with a match.\n"
+"[codeblock]\n"
+"var regex = RegEx.new()\n"
+"regex.compile(\"d(?<digit>[0-9]+)|x(?<digit>[0-9a-f]+)\")\n"
+"var result = regex.search(\"the number is x2f\")\n"
+"if result:\n"
+" print(result.get_string(\"digit\")) # Would print 2f\n"
+"[/codeblock]\n"
+"If you need to process multiple results, [method search_all] generates a "
+"list of all non-overlapping results. This can be combined with a [code]for[/"
+"code] loop for convenience.\n"
+"[codeblock]\n"
+"for result in regex.search_all(\"d01, d03, d0c, x3f and x42\"):\n"
+" print(result.get_string(\"digit\"))\n"
+"# Would print 01 03 3f 42\n"
+"# Note that d0c would not match\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Godot's regex implementation is based on the [url=https://www."
+"pcre.org/]PCRE2[/url] library. You can view the full pattern reference "
+"[url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url].\n"
+"[b]Tip:[/b] You can use [url=https://regexr.com/]Regexr[/url] to test "
+"regular expressions online."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:48
+msgid ""
+"This method resets the state of the object, as if it was freshly created. "
+"Namely, it unassigns the regular expression of this object."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:57
+msgid ""
+"Compiles and assign the search pattern to use. Returns [constant OK] if the "
+"compilation is successful. If an error is encountered, details are printed "
+"to standard output and an error is returned."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:64
+msgid "Returns the number of capturing groups in compiled pattern."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:71
+msgid ""
+"Returns an array of names of named capturing groups in the compiled pattern. "
+"They are ordered by appearance."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:78
+msgid "Returns the original search pattern that was compiled."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:85
+msgid "Returns whether this object has a valid search pattern assigned."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:98
+msgid ""
+"Searches the text for the compiled pattern. Returns a [RegExMatch] container "
+"of the first matching result if found, otherwise [code]null[/code]. The "
+"region to search within can be specified without modifying where the start "
+"and end anchor would be."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:111
+msgid ""
+"Searches the text for the compiled pattern. Returns an array of [RegExMatch] "
+"containers for each non-overlapping result. If no results were found, an "
+"empty array is returned instead. The region to search within can be "
+"specified without modifying where the start and end anchor would be."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:128
+msgid ""
+"Searches the text for the compiled pattern and replaces it with the "
+"specified string. Escapes and backreferences such as [code]$1[/code] and "
+"[code]$name[/code] are expanded and resolved. By default, only the first "
+"instance is replaced, but it can be changed for all instances (global "
+"replacement). The region to search within can be specified without modifying "
+"where the start and end anchor would be."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:4
+msgid "Contains the results of a [RegEx] search."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:7
+msgid ""
+"Contains the results of a single [RegEx] match returned by [method RegEx."
+"search] and [method RegEx.search_all]. It can be used to find the position "
+"and range of the match and its capturing groups, and it can extract its "
+"substring for you."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:18
+msgid ""
+"Returns the end position of the match within the source string. The end "
+"position of capturing groups can be retrieved by providing its group number "
+"as an integer or its string name (if it's a named group). The default value "
+"of 0 refers to the whole pattern.\n"
+"Returns -1 if the group did not match or doesn't exist."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:26
+msgid "Returns the number of capturing groups."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:35
+msgid ""
+"Returns the starting position of the match within the source string. The "
+"starting position of capturing groups can be retrieved by providing its "
+"group number as an integer or its string name (if it's a named group). The "
+"default value of 0 refers to the whole pattern.\n"
+"Returns -1 if the group did not match or doesn't exist."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:45
+msgid ""
+"Returns the substring of the match from the source string. Capturing groups "
+"can be retrieved by providing its group number as an integer or its string "
+"name (if it's a named group). The default value of 0 refers to the whole "
+"pattern.\n"
+"Returns an empty string if the group did not match or doesn't exist."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:52
+msgid ""
+"A dictionary of named groups and its corresponding group number. Only groups "
+"with that were matched are included. If multiple groups have the same name, "
+"that name would refer to the first matching one."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:55
+msgid "An [Array] of the match and its capturing groups."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:58
+msgid ""
+"The source string used with the search pattern to find this matching result."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:4
+msgid ""
+"RemoteTransform2D pushes its own [Transform2D] to another [CanvasItem] "
+"derived Node in the scene."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:7
+msgid ""
+"RemoteTransform2D pushes its own [Transform2D] to another [CanvasItem] "
+"derived Node (called the remote node) in the scene.\n"
+"It can be set to update another Node's position, rotation and/or scale. It "
+"can use either global or local coordinates."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:17
+msgid ""
+"[RemoteTransform2D] caches the remote node. It may not notice if the remote "
+"node disappears; [method force_update_cache] forces it to update the cache "
+"again."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:23
+msgid ""
+"The [NodePath] to the remote node, relative to the RemoteTransform2D's "
+"position in the scene."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:26 doc/classes/RemoteTransform3D.xml:26
+msgid "If [code]true[/code], the remote node's position is updated."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:29 doc/classes/RemoteTransform3D.xml:29
+msgid "If [code]true[/code], the remote node's rotation is updated."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:32 doc/classes/RemoteTransform3D.xml:32
+msgid "If [code]true[/code], the remote node's scale is updated."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:35 doc/classes/RemoteTransform3D.xml:35
+msgid ""
+"If [code]true[/code], global coordinates are used. If [code]false[/code], "
+"local coordinates are used."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:4
+msgid ""
+"RemoteTransform3D pushes its own [Transform] to another [Node3D] derived "
+"Node in the scene."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:7
+msgid ""
+"RemoteTransform3D pushes its own [Transform] to another [Node3D] derived "
+"Node (called the remote node) in the scene.\n"
+"It can be set to update another Node's position, rotation and/or scale. It "
+"can use either global or local coordinates."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:17
+msgid ""
+"[RemoteTransform3D] caches the remote node. It may not notice if the remote "
+"node disappears; [method force_update_cache] forces it to update the cache "
+"again."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:23
+msgid ""
+"The [NodePath] to the remote node, relative to the RemoteTransform3D's "
+"position in the scene."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:4
+msgid "Server for anything visible."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:7
+msgid ""
+"Server for anything visible. The visual server is the API backend for "
+"everything visible. The whole scene system mounts on it to display.\n"
+"The visual server is completely opaque, the internals are entirely "
+"implementation specific and cannot be accessed.\n"
+"The visual server can be used to bypass the scene system entirely.\n"
+"Resources are created using the [code]*_create[/code] functions.\n"
+"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].\n"
+"In 3D, all visual objects must be associated with a scenario. The scenario "
+"is a visual representation of the world. If accessing the visual server from "
+"a running game, the scenario can be accessed from the scene tree from any "
+"[Node3D] node with [method Node3D.get_world]. Otherwise, a scenario can be "
+"created with [method scenario_create].\n"
+"Similarly in 2D, a canvas is needed to draw all canvas items.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:18
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers."
+"html"
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:33
+msgid "Sets images to be rendered in the window margin."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:48
+msgid ""
+"Sets margin size, where black bars (or images, if [method "
+"black_bars_set_images] was used) are rendered."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:55
+msgid ""
+"Creates a camera and adds it to the RenderingServer. It can be accessed with "
+"the RID that is returned. This RID will be used in all [code]camera_*[/code] "
+"RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:67
+msgid ""
+"Sets the cull mask associated with this camera. The cull mask describes "
+"which 3D layers are rendered by this camera. Equivalent to [member Camera3D."
+"cull_mask]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:78
+msgid ""
+"Sets the environment used by this camera. Equivalent to [member Camera3D."
+"environment]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:95
+msgid ""
+"Sets camera to use frustum projection. This mode allows adjusting the "
+"[code]offset[/code] argument to create \"tilted frustum\" effects."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:110
+msgid ""
+"Sets camera to use orthogonal projection, also known as orthographic "
+"projection. Objects remain the same size on the screen no matter how far "
+"away they are."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:125
+msgid ""
+"Sets camera to use perspective projection. Objects on the screen becomes "
+"smaller when they are far away."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:136
+msgid "Sets [Transform] of camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:147
+msgid ""
+"If [code]true[/code], preserves the horizontal aspect ratio which is "
+"equivalent to [constant Camera3D.KEEP_WIDTH]. If [code]false[/code], "
+"preserves the vertical aspect ratio which is equivalent to [constant "
+"Camera3D.KEEP_HEIGHT]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:154
+msgid ""
+"Creates a canvas and returns the assigned [RID]. It can be accessed with the "
+"RID that is returned. This RID will be used in all [code]canvas_*[/code] "
+"RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:164
+msgid "Clears the [CanvasItem] and removes all commands in it."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:177
+msgid "Sets the [CanvasItem] to copy a rect to the backbuffer."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:188
+msgid "Sets the index for the [CanvasItem]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:199
+msgid "Sets a new material to the [CanvasItem]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:210
+msgid "Sets if the [CanvasItem] uses its parent's material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:221
+msgid ""
+"If this is enabled, the Z index of the parent will be added to the "
+"children's Z index."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:232
+msgid ""
+"Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are "
+"drawn first)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:243
+msgid ""
+"Attaches the canvas light to the canvas. Removes it from its previous canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:250
+msgid ""
+"Creates a canvas light and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]canvas_light_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:262
+msgid ""
+"Attaches a light occluder to the canvas. Removes it from its previous canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:269
+msgid ""
+"Creates a light occluder and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]canvas_light_ocluder_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:281
+msgid "Enables or disables light occluder."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:292 doc/classes/RenderingServer.xml:369
+msgid ""
+"The light mask. See [LightOccluder2D] for more information on light masks."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:303
+msgid "Sets a light occluder's polygon."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:314
+msgid "Sets a light occluder's [Transform2D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:325
+msgid "Sets the color for a light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:336
+msgid "Enables or disables a canvas light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:347
+msgid "Sets a canvas light's energy."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:358
+msgid "Sets a canvas light's height."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:380
+msgid ""
+"The binary mask used to determine which layers this canvas light's shadows "
+"affects. See [LightOccluder2D] for more information on light masks."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:393
+msgid "The layer range that gets rendered with this light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:404
+msgid "The mode of the light, see [enum CanvasLightMode] constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:415
+msgid ""
+"Sets the texture's scale factor of the light. Equivalent to [member Light2D."
+"texture_scale]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:426
+msgid ""
+"Sets the width of the shadow buffer, size gets scaled to the next power of "
+"two for this."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:437
+msgid "Sets the color of the canvas light's shadow."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:448
+msgid "Enables or disables the canvas light's shadow."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:459
+msgid ""
+"Sets the canvas light's shadow's filter, see [enum CanvasLightShadowFilter] "
+"constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:470
+msgid "Smoothens the shadow. The lower, the smoother."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:481
+msgid ""
+"Sets texture to be used by light. Equivalent to [member Light2D.texture]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:492
+msgid ""
+"Sets the offset of the light's texture. Equivalent to [member Light2D."
+"offset]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:503
+msgid "Sets the canvas light's [Transform2D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:516
+msgid ""
+"Sets the Z range of objects that will be affected by this light. Equivalent "
+"to [member Light2D.range_z_min] and [member Light2D.range_z_max]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:523
+msgid ""
+"Creates a new light occluder polygon and adds it to the RenderingServer. It "
+"can be accessed with the RID that is returned. This RID will be used in all "
+"[code]canvas_occluder_polygon_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:535
+msgid ""
+"Sets an occluder polygons cull mode. See [enum "
+"CanvasOccluderPolygonCullMode] constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:548
+msgid "Sets the shape of the occluder polygon."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:559
+msgid "Sets the shape of the occluder polygon as lines."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:572
+msgid ""
+"A copy of the canvas item will be drawn with a local offset of the mirroring "
+"[Vector2]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:583
+msgid "Modulates all colors in the given canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:590
+msgid ""
+"Creates a directional light and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID can be used in most "
+"[code]light_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this directional light to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:599
+msgid ""
+"Creates an environment and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]environment_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:619
+msgid ""
+"Sets the values to be used with the \"Adjustment\" post-process effect. See "
+"[Environment] for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:650
+msgid ""
+"Sets the [i]BGMode[/i] of the environment. Equivalent to [member Environment."
+"background_mode]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:661
+msgid ""
+"Color displayed for clear areas of the scene (if using Custom color or Color"
+"+Sky background modes)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:672
+msgid "Sets the intensity of the background color."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:683
+msgid "Sets the maximum layer to use if using Canvas background mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:700
+msgid ""
+"Sets the variables to be used with the scene fog. See [Environment] for more "
+"details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:721
+msgid ""
+"Sets the variables to be used with the fog depth effect. See [Environment] "
+"for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:738
+msgid ""
+"Sets the variables to be used with the fog height effect. See [Environment] "
+"for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:777
+msgid ""
+"Sets the [Sky] to be used as the environment's background when using "
+"[i]BGMode[/i] sky. Equivalent to [member Environment.sky]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:788
+msgid ""
+"Sets a custom field of view for the background [Sky]. Equivalent to [member "
+"Environment.sky_custom_fov]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:799
+msgid ""
+"Sets the rotation of the background [Sky] expressed as a [Basis]. Equivalent "
+"to [member Environment.sky_rotation], where the rotation vector is used to "
+"construct the [Basis]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:842
+msgid ""
+"Sets the variables to be used with the \"screen space reflections\" post-"
+"process effect. See [Environment] for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:867
+msgid ""
+"Sets the variables to be used with the \"tonemap\" post-process effect. See "
+"[Environment] for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:874
+msgid "Removes buffers and clears testcubes."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:885
+msgid ""
+"Forces a frame to be drawn when the function is called. Drawing a frame "
+"updates all [Viewport]s that are set to update. Use with extreme caution."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:892
+msgid "Synchronizes threads."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:901
+msgid "Tries to free an object in the RenderingServer."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:910
+msgid "Returns a certain information, see [enum RenderInfo] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:917
+msgid "Returns the id of the test cube. Creates one if none exists."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:924
+msgid "Returns the id of the test texture. Creates one if none exists."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:931
+msgid ""
+"Returns the name of the video adapter (e.g. \"GeForce GTX 1080/PCIe/"
+"SSE2\").\n"
+"[b]Note:[/b] When running a headless or server binary, this function returns "
+"an empty string."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:939
+msgid ""
+"Returns the vendor of the video adapter (e.g. \"NVIDIA Corporation\").\n"
+"[b]Note:[/b] When running a headless or server binary, this function returns "
+"an empty string."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:947
+msgid "Returns the id of a white texture. Creates one if none exists."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:954
+msgid ""
+"Returns [code]true[/code] if changes have been made to the RenderingServer's "
+"data. [method force_draw] is usually called if this happens."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:963
+msgid "Not yet implemented. Always returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:972
+msgid ""
+"Returns [code]true[/code] if the OS supports a certain feature. Features "
+"might be [code]s3tc[/code], [code]etc[/code], [code]etc2[/code] and "
+"[code]pvrtc[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:985
+msgid ""
+"Sets up [ImmediateGeometry3D] internals to prepare for drawing. Equivalent "
+"to [method ImmediateGeometry3D.begin]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:994
+msgid ""
+"Clears everything that was set up between [method immediate_begin] and "
+"[method immediate_end]. Equivalent to [method ImmediateGeometry3D.clear]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1005
+msgid ""
+"Sets the color to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1012
+msgid ""
+"Creates an immediate geometry and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]immediate_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this immediate geometry to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1023
+msgid ""
+"Ends drawing the [ImmediateGeometry3D] and displays it. Equivalent to "
+"[method ImmediateGeometry3D.end]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1032
+msgid "Returns the material assigned to the [ImmediateGeometry3D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1043
+msgid ""
+"Sets the normal to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_normal]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1054
+msgid "Sets the material to be used to draw the [ImmediateGeometry3D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1065
+msgid ""
+"Sets the tangent to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_tangent]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1076
+msgid ""
+"Sets the UV to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_uv]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1087
+msgid ""
+"Sets the UV2 to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_uv2]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1098
+msgid ""
+"Adds the next vertex using the information provided in advance. Equivalent "
+"to [method ImmediateGeometry3D.add_vertex]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1109
+msgid ""
+"Adds the next vertex using the information provided in advance. This is a "
+"helper class that calls [method immediate_vertex] under the hood. Equivalent "
+"to [method ImmediateGeometry3D.add_vertex]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1116
+msgid ""
+"Initializes the visual server. This function is called internally by "
+"platform-dependent code during engine initialization. If called from a "
+"running game, it will not do anything."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1127
+msgid ""
+"Attaches a unique Object ID to instance. Object ID must be attached to "
+"instance for proper culling with [method instances_cull_aabb], [method "
+"instances_cull_convex], and [method instances_cull_ray]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1138
+msgid ""
+"Attaches a skeleton to an instance. Removes the previous skeleton from the "
+"instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1145
+msgid ""
+"Creates a visual instance and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]instance_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"An instance is a way of placing a 3D object in the scenario. Objects like "
+"particles, meshes, and reflection probes need to be associated with an "
+"instance to be visible in the scenario using [method instance_set_base]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1158
+msgid ""
+"Creates a visual instance, adds it to the RenderingServer, and sets both "
+"base and scenario. It can be accessed with the RID that is returned. This "
+"RID will be used in all [code]instance_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1170 doc/classes/RenderingServer.xml:1198
+#: doc/classes/RenderingServer.xml:1488
+msgid "Not implemented in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1181
+msgid ""
+"Sets the shadow casting setting to one of [enum ShadowCastingSetting]. "
+"Equivalent to [member GeometryInstance3D.cast_shadow]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1211
+msgid ""
+"Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for "
+"more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1222
+msgid ""
+"Sets a material that will override the material for all surfaces on the mesh "
+"associated with this instance. Equivalent to [member GeometryInstance3D."
+"material_override]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1233
+msgid ""
+"Sets the base of the instance. A base can be any of the 3D objects that are "
+"created in the RenderingServer that can be displayed. For example, any of "
+"the light types, mesh, multimesh, immediate geometry, particle system, "
+"reflection probe, lightmap capture, and the GI probe are all types that can "
+"be set as the base of an instance in order to be displayed in the scenario."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1246
+msgid "Sets the weight for a given blend shape associated with this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1257
+msgid ""
+"Sets a custom AABB to use when culling objects from the view frustum. "
+"Equivalent to [method GeometryInstance3D.set_custom_aabb]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1268
+msgid "Function not implemented in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1279
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1290
+msgid ""
+"Sets the render layers that this instance will be drawn to. Equivalent to "
+"[member VisualInstance3D.layers]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1301
+msgid ""
+"Sets the scenario that the instance is in. The scenario is the 3D world that "
+"the objects will be displayed in."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1314
+msgid ""
+"Sets the material of a specific surface. Equivalent to [method "
+"MeshInstance3D.set_surface_material]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1325
+msgid ""
+"Sets the world space transform of the instance. Equivalent to [member Node3D."
+"transform]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1338
+msgid "Sets the lightmap to use with this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1349
+msgid ""
+"Sets whether an instance is drawn or not. Equivalent to [member Node3D."
+"visible]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1360
+msgid ""
+"Returns an array of object IDs intersecting with the provided AABB. Only "
+"visual 3D nodes are considered, such as [MeshInstance3D] or "
+"[DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the "
+"actual nodes. A scenario RID must be provided, which is available in the "
+"[World3D] you want to query. This forces an update for all resources queued "
+"to update.\n"
+"[b]Warning:[/b] This function is primarily intended for editor usage. For in-"
+"game use cases, prefer physics collision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1372
+msgid ""
+"Returns an array of object IDs intersecting with the provided convex shape. "
+"Only visual 3D nodes are considered, such as [MeshInstance3D] or "
+"[DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the "
+"actual nodes. A scenario RID must be provided, which is available in the "
+"[World3D] you want to query. This forces an update for all resources queued "
+"to update.\n"
+"[b]Warning:[/b] This function is primarily intended for editor usage. For in-"
+"game use cases, prefer physics collision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1386
+msgid ""
+"Returns an array of object IDs intersecting with the provided 3D ray. Only "
+"visual 3D nodes are considered, such as [MeshInstance3D] or "
+"[DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the "
+"actual nodes. A scenario RID must be provided, which is available in the "
+"[World3D] you want to query. This forces an update for all resources queued "
+"to update.\n"
+"[b]Warning:[/b] This function is primarily intended for editor usage. For in-"
+"game use cases, prefer physics collision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1398
+msgid ""
+"If [code]true[/code], this directional light will blend between shadow map "
+"splits resulting in a smoother transition between them. Equivalent to "
+"[member DirectionalLight3D.directional_shadow_blend_splits]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1409
+msgid ""
+"Sets the shadow depth range mode for this directional light. Equivalent to "
+"[member DirectionalLight3D.directional_shadow_depth_range]. See [enum "
+"LightDirectionalShadowDepthRangeMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1420
+msgid ""
+"Sets the shadow mode for this directional light. Equivalent to [member "
+"DirectionalLight3D.directional_shadow_mode]. See [enum "
+"LightDirectionalShadowMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1431
+msgid ""
+"Sets whether to use a dual paraboloid or a cubemap for the shadow map. Dual "
+"paraboloid is faster but may suffer from artifacts. Equivalent to [member "
+"OmniLight3D.omni_shadow_mode]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1442
+msgid ""
+"Sets the color of the light. Equivalent to [member Light3D.light_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1453
+msgid ""
+"Sets the cull mask for this Light3D. Lights only affect objects in the "
+"selected layers. Equivalent to [member Light3D.light_cull_mask]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1464
+msgid ""
+"If [code]true[/code], light will subtract light instead of adding light. "
+"Equivalent to [member Light3D.light_negative]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1477
+msgid ""
+"Sets the specified light parameter. See [enum LightParam] for options. "
+"Equivalent to [method Light3D.set_param]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1499
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1510
+msgid ""
+"If [code]true[/code], light will cast shadows. Equivalent to [member Light3D."
+"shadow_enabled]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1521
+msgid ""
+"Sets the color of the shadow cast by the light. Equivalent to [member "
+"Light3D.shadow_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1532
+msgid "Sets whether GI probes capture light information from this light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1539
+msgid ""
+"Creates a lightmap capture and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]lightmap_capture_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this lightmap capture to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1550
+msgid "Returns the size of the lightmap capture area."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1559
+msgid "Returns the energy multiplier used by the lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1568
+msgid "Returns the octree used by the lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1577
+msgid ""
+"Returns the cell subdivision amount used by this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1586
+msgid "Returns the cell transform for this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1597
+msgid "Sets the size of the area covered by the lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1608
+msgid "Sets the energy multiplier for this lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1619
+msgid "Sets the octree to be used by this lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1630
+msgid "Sets the subdivision level of this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1641
+msgid "Sets the octree cell transform for this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1654
+msgid ""
+"Returns a mesh of a sphere with the given amount of horizontal and vertical "
+"subdivisions."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1661
+msgid ""
+"Creates an empty material and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]material_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1673
+msgid "Returns the value of a certain material's parameter."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1684
+msgid "Sets an object's next material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1697
+msgid "Sets a material's parameter."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1708
+msgid "Sets a material's render priority."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1719
+msgid "Sets a shader material's shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1748
+msgid "Removes all surfaces from a mesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1755
+msgid ""
+"Creates a new mesh and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all [code]mesh_*[/"
+"code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this mesh to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1766
+msgid "Returns a mesh's blend shape count."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1775
+msgid "Returns a mesh's blend shape mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1784
+msgid "Returns a mesh's custom aabb."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1793
+msgid "Returns a mesh's number of surfaces."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1804
+msgid "Sets a mesh's blend shape mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1815
+msgid "Sets a mesh's custom aabb."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1826
+msgid "Returns a mesh's surface's buffer arrays."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1837
+msgid "Returns a mesh's surface's arrays for blend shapes."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1852 doc/classes/RenderingServer.xml:1865
+msgid "Function is unused in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1876
+msgid "Returns a mesh's surface's material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1889
+msgid "Sets a mesh's surface's material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1904
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1927
+msgid ""
+"Creates a new multimesh on the RenderingServer and returns an [RID] handle. "
+"This RID will be used in all [code]multimesh_*[/code] RenderingServer "
+"functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this multimesh to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1938
+msgid ""
+"Calculates and returns the axis-aligned bounding box that encloses all "
+"instances within the multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1955
+msgid "Returns the number of instances allocated for this multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1964
+msgid ""
+"Returns the RID of the mesh that will be used in drawing this multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1973
+msgid "Returns the number of visible instances for this multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1984
+msgid "Returns the color by which the specified instance will be modulated."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1995
+msgid "Returns the custom data associated with the specified instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2006
+msgid "Returns the [Transform] of the specified instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2017
+msgid ""
+"Returns the [Transform2D] of the specified instance. For use when the "
+"multimesh is set to use 2D transforms."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2030
+msgid ""
+"Sets the color by which this instance will be modulated. Equivalent to "
+"[method MultiMesh.set_instance_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2043
+msgid ""
+"Sets the custom data for this instance. Custom data is passed as a [Color], "
+"but is interpreted as a [code]vec4[/code] in the shader. Equivalent to "
+"[method MultiMesh.set_instance_custom_data]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2056
+msgid ""
+"Sets the [Transform] for this instance. Equivalent to [method MultiMesh."
+"set_instance_transform]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2069
+msgid ""
+"Sets the [Transform2D] for this instance. For use when multimesh is used in "
+"2D. Equivalent to [method MultiMesh.set_instance_transform_2d]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2090
+msgid ""
+"Sets the mesh to be drawn by the multimesh. Equivalent to [member MultiMesh."
+"mesh]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2101
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2108
+msgid ""
+"Creates a new omni light and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID can be used in most "
+"[code]light_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this omni light to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2117
+msgid ""
+"Creates a particle system and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]particles_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach these particles to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2128
+msgid ""
+"Calculates and returns the axis-aligned bounding box that contains all the "
+"particles. Equivalent to [method GPUParticles3D.capture_aabb]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2137
+msgid "Returns [code]true[/code] if particles are currently set to emitting."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2146
+msgid ""
+"Returns [code]true[/code] if particles are not emitting and particles are "
+"set to inactive."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2155
+msgid ""
+"Add particle system to list of particle systems that need to be updated. "
+"Update will take place on the next frame, or on the next call to [method "
+"instances_cull_aabb], [method instances_cull_convex], or [method "
+"instances_cull_ray]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2164
+msgid ""
+"Reset the particles on the next update. Equivalent to [method GPUParticles3D."
+"restart]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2175
+msgid ""
+"Sets the number of particles to be drawn and allocates the memory for them. "
+"Equivalent to [member GPUParticles3D.amount]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2186
+msgid ""
+"Sets a custom axis-aligned bounding box for the particle system. Equivalent "
+"to [member GPUParticles3D.visibility_aabb]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2197
+msgid ""
+"Sets the draw order of the particles to one of the named enums from [enum "
+"ParticlesDrawOrder]. See [enum ParticlesDrawOrder] for options. Equivalent "
+"to [member GPUParticles3D.draw_order]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2210
+msgid ""
+"Sets the mesh to be used for the specified draw pass. Equivalent to [member "
+"GPUParticles3D.draw_pass_1], [member GPUParticles3D.draw_pass_2], [member "
+"GPUParticles3D.draw_pass_3], and [member GPUParticles3D.draw_pass_4]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2221
+msgid ""
+"Sets the number of draw passes to use. Equivalent to [member GPUParticles3D."
+"draw_passes]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2232
+msgid ""
+"Sets the [Transform] that will be used by the particles when they first emit."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2243
+msgid ""
+"If [code]true[/code], particles will emit over time. Setting to false does "
+"not reset the particles, but only stops their emission. Equivalent to "
+"[member GPUParticles3D.emitting]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2254
+msgid ""
+"Sets the explosiveness ratio. Equivalent to [member GPUParticles3D."
+"explosiveness]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2265
+msgid ""
+"Sets the frame rate that the particle system rendering will be fixed to. "
+"Equivalent to [member GPUParticles3D.fixed_fps]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2276
+msgid ""
+"If [code]true[/code], uses fractional delta which smooths the movement of "
+"the particles. Equivalent to [member GPUParticles3D.fract_delta]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2287
+msgid ""
+"Sets the lifetime of each particle in the system. Equivalent to [member "
+"GPUParticles3D.lifetime]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2298
+msgid ""
+"If [code]true[/code], particles will emit once and then stop. Equivalent to "
+"[member GPUParticles3D.one_shot]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2309
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2320
+msgid ""
+"Sets the material for processing the particles. Note: this is not the "
+"material used to draw the materials. Equivalent to [member GPUParticles3D."
+"process_material]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2331
+msgid ""
+"Sets the emission randomness ratio. This randomizes the emission of "
+"particles within their phase. Equivalent to [member GPUParticles3D."
+"randomness]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2342
+msgid ""
+"Sets the speed scale of the particle system. Equivalent to [member "
+"GPUParticles3D.speed_scale]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2353
+msgid ""
+"If [code]true[/code], particles use local coordinates. If [code]false[/code] "
+"they use global coordinates. Equivalent to [member GPUParticles3D."
+"local_coords]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2360
+msgid ""
+"Creates a reflection probe and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]reflection_probe_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this reflection probe to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2373
+msgid ""
+"If [code]true[/code], reflections will ignore sky contribution. Equivalent "
+"to [member ReflectionProbe.interior_enable]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2384
+msgid ""
+"Sets the render cull mask for this reflection probe. Only instances with a "
+"matching cull mask will be rendered by this probe. Equivalent to [member "
+"ReflectionProbe.cull_mask]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2395
+msgid ""
+"If [code]true[/code], uses box projection. This can make reflections look "
+"more correct in certain situations. Equivalent to [member ReflectionProbe."
+"box_projection]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2406
+msgid ""
+"If [code]true[/code], computes shadows in the reflection probe. This makes "
+"the reflection much slower to compute. Equivalent to [member ReflectionProbe."
+"enable_shadows]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2417
+msgid ""
+"Sets the size of the area that the reflection probe will capture. Equivalent "
+"to [member ReflectionProbe.extents]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2428
+msgid ""
+"Sets the intensity of the reflection probe. Intensity modulates the strength "
+"of the reflection. Equivalent to [member ReflectionProbe.intensity]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2439
+msgid ""
+"Sets the ambient light color for this reflection probe when set to interior "
+"mode. Equivalent to [member ReflectionProbe.interior_ambient_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2450
+msgid ""
+"Sets the energy multiplier for this reflection probes ambient light "
+"contribution when set to interior mode. Equivalent to [member "
+"ReflectionProbe.interior_ambient_energy]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2461
+msgid ""
+"Sets the contribution value for how much the reflection affects the ambient "
+"light for this reflection probe when set to interior mode. Useful so that "
+"ambient light matches the color of the room. Equivalent to [member "
+"ReflectionProbe.interior_ambient_contrib]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2472
+msgid ""
+"Sets the max distance away from the probe an object can be before it is "
+"culled. Equivalent to [member ReflectionProbe.max_distance]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2483
+msgid ""
+"Sets the origin offset to be used when this reflection probe is in box "
+"project mode. Equivalent to [member ReflectionProbe.origin_offset]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2494
+msgid ""
+"Sets how often the reflection probe updates. Can either be once or every "
+"frame. See [enum ReflectionProbeUpdateMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2507
+msgid ""
+"Schedules a callback to the corresponding named [code]method[/code] on "
+"[code]where[/code] after a frame has been drawn.\n"
+"The callback method must use only 1 argument which will be called with "
+"[code]userdata[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2515
+msgid ""
+"Creates a scenario and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all "
+"[code]scenario_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"The scenario is the 3D world that all the visual instances exist in."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2528
+msgid ""
+"Sets the [enum ScenarioDebugMode] for this scenario. See [enum "
+"ScenarioDebugMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2539
+msgid "Sets the environment that will be used with this scenario."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2550
+msgid ""
+"Sets the fallback environment to be used by this scenario. The fallback "
+"environment is used if no environment is set. Internally, this is used by "
+"the editor to provide a default environment."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2565
+msgid ""
+"Sets a boot image. The color defines the background color. If [code]scale[/"
+"code] is [code]true[/code], the image will be scaled to fit the screen size. "
+"If [code]use_filter[/code] is [code]true[/code], the image will be scaled "
+"with linear interpolation. If [code]use_filter[/code] is [code]false[/code], "
+"the image will be scaled with nearest-neighbor interpolation."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2574
+msgid ""
+"If [code]true[/code], the engine will generate wireframes for use with the "
+"wireframe debug mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2583
+msgid ""
+"Sets the default clear color which is used when a specific clear color has "
+"not been selected."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2590
+msgid ""
+"Creates an empty shader and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]shader_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2600
+msgid "Returns a shader's code."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2611
+msgid "Returns a default texture from a shader searched by name."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2630
+msgid "Returns the parameters of a shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2641
+msgid "Sets a shader's code."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2654
+msgid "Sets a shader's default texture. Overwrites the texture given by name."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2667
+msgid "Allocates the GPU buffers for this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2678
+msgid "Returns the [Transform] set for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2689
+msgid "Returns the [Transform2D] set for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2702
+msgid "Sets the [Transform] for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2715
+msgid "Sets the [Transform2D] for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2722
+msgid ""
+"Creates a skeleton and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all "
+"[code]skeleton_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2732
+msgid "Returns the number of bones allocated for this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2739
+msgid ""
+"Creates an empty sky and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all [code]sky_*[/"
+"code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2751
+msgid ""
+"Sets the material that the sky uses to render the background and reflection "
+"maps."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2758
+msgid ""
+"Creates a spot light and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID can be used in most [code]light_*[/"
+"code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this spot light to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2787
+msgid "Sets a viewport's camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2798
+msgid "Sets a viewport's canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2811
+msgid ""
+"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.\n"
+"For example, you can set the root viewport to not render at all with the "
+"following code:\n"
+"[codeblock]\n"
+"func _ready():\n"
+" get_viewport().set_attach_to_screen_rect(Rect2())\n"
+" $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n"
+"[/codeblock]\n"
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2825
+msgid ""
+"Creates an empty viewport and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]viewport_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2837
+msgid ""
+"Returns a viewport's render information. For options, see the [enum "
+"ViewportRenderInfo] constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2846
+msgid "Returns the viewport's last rendered frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2857
+msgid "Detaches a viewport from a canvas and vice versa."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2868
+msgid "If [code]true[/code], sets the viewport active, else sets it inactive."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2883
+msgid ""
+"Sets the stacking order for a viewport's canvas.\n"
+"[code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] "
+"specifies the stacking order of the canvas among those in the same layer."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2897
+msgid "Sets the transformation of a viewport's canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2908
+msgid ""
+"Sets the clear mode of a viewport. See [enum ViewportClearMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2919
+msgid ""
+"Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for "
+"options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2930
+msgid ""
+"If [code]true[/code], rendering of a viewport's environment is disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2941
+msgid "Sets the viewport's global transformation matrix."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2952
+msgid "If [code]true[/code], the viewport's canvas is not rendered."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2963
+msgid "Currently unimplemented in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2974
+msgid "Sets the anti-aliasing mode. See [enum ViewportMSAA] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2985
+msgid "Sets the viewport's parent to another viewport."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2996
+msgid ""
+"If [code]true[/code], render the contents of the viewport directly to "
+"screen. This allows a low-level optimization where you can skip drawing a "
+"viewport to the root viewport. While this optimization can result in a "
+"significant increase in speed (especially on older devices), it comes at a "
+"cost of usability. When this is enabled, you cannot read from the viewport "
+"or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of "
+"certain window settings, such as the various stretch modes. Another "
+"consequence to be aware of is that in 2D the rendering happens in window "
+"coordinates, so if you have a viewport that is double the size of the "
+"window, and you set this, then only the portion that fits within the window "
+"will be drawn, no automatic scaling is possible, even if your game scene is "
+"significantly larger than the window size."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3007
+msgid ""
+"Sets a viewport's scenario.\n"
+"The scenario contains information about the [enum ScenarioDebugMode], "
+"environment information, reflection atlas etc."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3021
+msgid "Sets the shadow atlas quadrant's subdivision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3032
+msgid ""
+"Sets the size of the shadow atlas's images (used for omni and spot lights). "
+"The value will be rounded up to the nearest power of 2."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3045
+msgid "Sets the viewport's width and height."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3056
+msgid ""
+"If [code]true[/code], the viewport renders its background as transparent."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3067
+msgid ""
+"Sets when the viewport should be updated. See [enum ViewportUpdateMode] "
+"constants for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3078
+msgid ""
+"If [code]true[/code], the viewport uses augmented or virtual reality "
+"technologies. See [ARVRInterface]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3085
+msgid ""
+"Emitted at the end of the frame, after the RenderingServer has finished "
+"updating all the Viewports."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3090
+msgid ""
+"Emitted at the beginning of the frame, before the RenderingServer updates "
+"all the Viewports."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3096
+msgid "Marks an error that shows that the index array is empty."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3099
+msgid "Number of weights/bones per vertex."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3102
+msgid "The minimum Z-layer for canvas items."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3105
+msgid "The maximum Z-layer for canvas items."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3108
+msgid ""
+"Max number of glow levels that can be used with glow post-process effect."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3111
+msgid "Unused enum in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3114
+msgid "The minimum renderpriority of all materials."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3117
+msgid "The maximum renderpriority of all materials."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3138
+msgid "Shader is a 3D shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3141
+msgid "Shader is a 2D shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3144
+msgid "Shader is a particle shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3147
+msgid "Shader is a sky shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3150
+msgid "Represents the size of the [enum ShaderMode] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3153
+msgid "Array is a vertex array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3156
+msgid "Array is a normal array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3159
+msgid "Array is a tangent array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3162
+msgid "Array is a color array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3165
+msgid "Array is an UV coordinates array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3168
+msgid "Array is an UV coordinates array for the second UV coordinates."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3171
+msgid "Array contains bone information."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3174
+msgid "Array is weight information."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3177
+msgid "Array is index array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3183
+msgid "Flag used to mark a vertex array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3186
+msgid "Flag used to mark a normal array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3189
+msgid "Flag used to mark a tangent array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3192
+msgid "Flag used to mark a color array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3195
+msgid "Flag used to mark an UV coordinates array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3198
+msgid ""
+"Flag used to mark an UV coordinates array for the second UV coordinates."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3201
+msgid "Flag used to mark a bone information array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3204
+msgid "Flag used to mark a weights array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3207
+msgid "Flag used to mark an index array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3236
+msgid "Primitive to draw consists of points."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3239
+msgid "Primitive to draw consists of lines."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3242
+msgid "Primitive to draw consists of a line strip from start to end."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3245
+msgid "Primitive to draw consists of triangles."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3248
+msgid ""
+"Primitive to draw consists of a triangle strip (the last 3 vertices are "
+"always combined to make a triangle)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3251
+msgid "Represents the size of the [enum PrimitiveType] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3260
+msgid "Use [Transform2D] to store MultiMesh transform."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3263
+msgid "Use [Transform] to store MultiMesh transform."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3266
+msgid "Is a directional (sun) light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3269
+msgid "Is an omni light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3272
+msgid "Is a spot light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3275
+msgid "The light's energy."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3280
+msgid "The light's influence on specularity."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3283
+msgid "The light's range."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3286
+msgid "The light's attenuation."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3289
+msgid "The spotlight's angle."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3292
+msgid "The spotlight's attenuation."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3295
+msgid "Scales the shadow color."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3298
+msgid "Max distance that shadows will be rendered."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3301
+msgid "Proportion of shadow atlas occupied by the first split."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3304
+msgid "Proportion of shadow atlas occupied by the second split."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3307
+msgid ""
+"Proportion of shadow atlas occupied by the third split. The fourth split "
+"occupies the rest."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3312
+msgid ""
+"Normal bias used to offset shadow lookup by object normal. Can be used to "
+"fix self-shadowing artifacts."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3315
+msgid "Bias the shadow lookup to fix self-shadowing artifacts."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3318
+msgid ""
+"Increases bias on further splits to fix self-shadowing that only occurs far "
+"away from the camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3321
+msgid "Represents the size of the [enum LightParam] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3324
+msgid "Use a dual paraboloid shadow map for omni lights."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3327
+msgid ""
+"Use a cubemap shadow map for omni lights. Slower but better quality than "
+"dual paraboloid."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3330
+msgid "Use orthogonal shadow projection for directional light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3333
+msgid "Use 2 splits for shadow projection when using directional light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3336
+msgid "Use 4 splits for shadow projection when using directional light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3339
+msgid ""
+"Keeps shadows stable as camera moves but has lower effective resolution."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3342
+msgid ""
+"Optimize use of shadow maps, increasing the effective resolution. But may "
+"result in shadows moving or flickering slightly."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3345
+msgid "Reflection probe will update reflections once and then stop."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3348
+msgid ""
+"Reflection probe will update each frame. This mode is necessary to capture "
+"moving objects."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3351
+msgid "Draw particles in the order that they appear in the particles array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3354
+msgid "Sort particles based on their lifetime."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3357
+msgid "Sort particles based on their distance to the camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3360
+msgid "Do not update the viewport."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3363
+msgid "Update the viewport once then set to disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3366
+msgid "Update the viewport whenever it is visible."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3371
+msgid "Always update the viewport."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3374
+msgid "The viewport is always cleared before drawing."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3377
+msgid "The viewport is never cleared before drawing."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3380
+msgid ""
+"The viewport is cleared once, then the clear mode is set to [constant "
+"VIEWPORT_CLEAR_NEVER]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3383
+msgid "Multisample antialiasing is disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3386
+msgid "Multisample antialiasing is set to 2×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3389
+msgid "Multisample antialiasing is set to 4×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3392
+msgid "Multisample antialiasing is set to 8×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3395
+msgid "Multisample antialiasing is set to 16×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3398
+msgid ""
+"Multisample antialiasing is set to 2× on external texture. Special mode for "
+"GLES2 Android VR (Oculus Quest and Go)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3401
+msgid ""
+"Multisample antialiasing is set to 4× on external texture. Special mode for "
+"GLES2 Android VR (Oculus Quest and Go)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3404
+msgid "Number of objects drawn in a single frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3407
+msgid "Number of vertices drawn in a single frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3410
+msgid "Number of material changes during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3413
+msgid "Number of shader changes during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3416
+msgid "Number of surface changes during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3419
+msgid "Number of draw calls during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3422
+msgid "Represents the size of the [enum ViewportRenderInfo] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3425
+msgid "Debug draw is disabled. Default setting."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3428
+msgid "Debug draw sets objects to unshaded."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3433
+msgid "Overwrites clear color to [code](0,0,0,0)[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3436
+msgid "Debug draw draws objects in wireframe."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3461
+msgid "Use the clear color as background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3464
+msgid "Use a specified color as the background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3467
+msgid "Use a sky resource for the background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3470
+msgid ""
+"Use a specified canvas layer as the background. This can be useful for "
+"instantiating a 2D scene in a 3D world."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3473
+msgid ""
+"Do not clear the background, use whatever was rendered last frame as the "
+"background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3479
+msgid "Represents the size of the [enum EnvironmentBG] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3506
+msgid "Output color as they came in."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3509
+msgid "Use the Reinhard tonemapper."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3512
+msgid "Use the filmic tonemapper."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3515
+msgid "Use the ACES tonemapper."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3518
+msgid "Disables the blur set for SSAO. Will make SSAO look noisier."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3521
+msgid "Perform a 1x1 blur on the SSAO output."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3524
+msgid "Performs a 2x2 blur on the SSAO output."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3527
+msgid "Performs a 3x3 blur on the SSAO output. Use this for smoothest SSAO."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3530
+msgid "Lowest quality of screen space ambient occlusion."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3533
+msgid "Medium quality screen space ambient occlusion."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3536
+msgid "Highest quality screen space ambient occlusion."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3555
+msgid "Do not use a debug mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3558
+msgid "Draw all objects as wireframe models."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3561
+msgid ""
+"Draw all objects in a way that displays how much overdraw is occurring. "
+"Overdraw occurs when a section of pixels is drawn and shaded and then "
+"another object covers it up. To optimize a scene, you should reduce overdraw."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3564
+msgid ""
+"Draw all objects without shading. Equivalent to setting all objects shaders "
+"to [code]unshaded[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3567
+msgid "The instance does not have a type."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3570
+msgid "The instance is a mesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3573
+msgid "The instance is a multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3576
+msgid "The instance is an immediate geometry."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3579
+msgid "The instance is a particle emitter."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3582
+msgid "The instance is a light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3585
+msgid "The instance is a reflection probe."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3588
+msgid "The instance is a GI probe."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3591
+msgid "The instance is a lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3594
+msgid "Represents the size of the [enum InstanceType] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3597
+msgid ""
+"A combination of the flags of geometry instances (mesh, multimesh, immediate "
+"and particles)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3600
+msgid "Allows the instance to be used in baked lighting."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3605
+msgid "When set, manually requests to draw geometry on next frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3608
+msgid "Represents the size of the [enum InstanceFlags] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3611
+msgid "Disable shadows from this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3614
+msgid "Cast shadows from this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3617
+msgid ""
+"Disable backface culling when rendering the shadow of the object. This is "
+"slightly slower but may result in more correct shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3620
+msgid ""
+"Only render the shadows from the object. The object itself will not be drawn."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3623
+msgid "The nine patch gets stretched where needed."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3626
+msgid "The nine patch gets filled with tiles where needed."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3629
+msgid ""
+"The nine patch gets filled with tiles where needed and stretches them a bit "
+"if needed."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3658
+msgid "Adds light color additive to the canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3661
+msgid "Adds light color subtractive to the canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3664
+msgid "The light adds color depending on transparency."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3667
+msgid "The light adds color depending on mask."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3670
+msgid "Do not apply a filter to canvas light shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3673
+msgid "Use PCF5 filtering to filter canvas light shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3676
+msgid "Use PCF13 filtering to filter canvas light shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3681
+msgid "Culling of the canvas occluder is disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3684
+msgid "Culling of the canvas occluder is clockwise."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3687
+msgid "Culling of the canvas occluder is counterclockwise."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3690
+msgid "The amount of objects in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3693
+msgid "The amount of vertices in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3696
+msgid "The amount of modified materials in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3699
+msgid "The amount of shader rebinds in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3702
+msgid "The amount of surface changes in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3705
+msgid "The amount of draw calls in frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3720
+msgid "Hardware supports shaders. This enum is currently unused in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3723
+msgid ""
+"Hardware supports multithreading. This enum is currently unused in Godot 3.x."
+msgstr ""
+
+#: doc/classes/Resource.xml:4
+msgid "Base class for all resources."
+msgstr ""
+
+#: doc/classes/Resource.xml:7
+msgid ""
+"Resource is the base class for all Godot-specific resource types, serving "
+"primarily as data containers. They are reference counted and freed when no "
+"longer in use. They are also cached once loaded from disk, so that any "
+"further attempts to load a resource from a given path will return the same "
+"reference (all this in contrast to a [Node], which is not reference counted "
+"and can be instanced from disk as many times as desired). Resources can be "
+"saved externally on disk or bundled into another object, such as a [Node] or "
+"another resource."
+msgstr ""
+
+#: doc/classes/Resource.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"resources.html"
+msgstr ""
+
+#: doc/classes/Resource.xml:17
+msgid ""
+"Virtual function which can be overridden to customize the behavior value of "
+"[method setup_local_to_scene]."
+msgstr ""
+
+#: doc/classes/Resource.xml:26
+msgid ""
+"Duplicates the resource, returning a new resource. By default, sub-resources "
+"are shared between resource copies for efficiency, this can be changed by "
+"passing [code]true[/code] to the [code]subresources[/code] argument."
+msgstr ""
+
+#: doc/classes/Resource.xml:33
+msgid ""
+"If [member resource_local_to_scene] is enabled and the resource was loaded "
+"from a [PackedScene] instantiation, returns the local scene where this "
+"resource's unique copy is in use. Otherwise, returns [code]null[/code]."
+msgstr ""
+
+#: doc/classes/Resource.xml:40
+msgid ""
+"Returns the RID of the resource (or an empty RID). Many resources (such as "
+"[Texture2D], [Mesh], etc) are high-level abstractions of resources stored in "
+"a server, so this function will return the original RID."
+msgstr ""
+
+#: doc/classes/Resource.xml:47
+msgid ""
+"This method is called when a resource with [member resource_local_to_scene] "
+"enabled is loaded from a [PackedScene] instantiation. Its behavior can be "
+"customized by overriding [method _setup_local_to_scene] from script.\n"
+"For most resources, this method performs no base logic. [ViewportTexture] "
+"performs custom logic to properly set the proxy texture and flags in the "
+"local viewport."
+msgstr ""
+
+#: doc/classes/Resource.xml:57
+msgid ""
+"Sets the path of the resource, potentially overriding an existing cache "
+"entry for this path. This differs from setting [member resource_path], as "
+"the latter would error out if another resource was already cached for the "
+"given path."
+msgstr ""
+
+#: doc/classes/Resource.xml:63
+msgid ""
+"If [code]true[/code], the resource will be made unique in each instance of "
+"its local scene. It can thus be modified in a scene instance without "
+"impacting other instances of that same scene."
+msgstr ""
+
+#: doc/classes/Resource.xml:66
+msgid "The name of the resource. This is an optional identifier."
+msgstr ""
+
+#: doc/classes/Resource.xml:69
+msgid ""
+"The path to the resource. In case it has its own file, it will return its "
+"filepath. If it's tied to the scene, it will return the scene's path, "
+"followed by the resource's index."
+msgstr ""
+
+#: doc/classes/Resource.xml:75
+msgid "Emitted whenever the resource changes."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:4
+msgid "Loads a specific resource type from a file."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:7
+msgid ""
+"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.\n"
+"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].\n"
+"[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] ([StreamTexture]) first, so they can be loaded with "
+"better efficiency on the graphics card."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:22
+msgid ""
+"If implemented, gets the dependencies of a given resource. If "
+"[code]add_types[/code] is [code]true[/code], paths should be appended "
+"[code]::TypeName[/code], where [code]TypeName[/code] is the class name of "
+"the dependency.\n"
+"[b]Note:[/b] Custom resource types defined by scripts aren't known by the "
+"[ClassDB], so you might just return [code]\"Resource\"[/code] for them."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:30
+msgid "Gets the list of extensions for files this loader is able to read."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:39
+msgid ""
+"Gets the class name of the resource associated with the given path. If the "
+"loader cannot handle it, it should return [code]\"\"[/code].\n"
+"[b]Note:[/b] Custom resource types defined by scripts aren't known by the "
+"[ClassDB], so you might just return [code]\"Resource\"[/code] for them."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:49
+msgid ""
+"Tells which resource class this loader can load.\n"
+"[b]Note:[/b] Custom resource types defined by scripts aren't known by the "
+"[ClassDB], so you might just handle [code]\"Resource\"[/code] for them."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:61
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:72
+msgid ""
+"If implemented, renames dependencies within the given resource and saves it. "
+"[code]renames[/code] is a dictionary [code]{ String => String }[/code] "
+"mapping old dependency paths to new paths.\n"
+"Returns [constant OK] on success, or an [enum Error] constant in case of "
+"failure."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:4
+msgid "Saves a specific resource type to a file."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:7
+msgid ""
+"The engine can save resources when you do it from the editor, or when you "
+"use the [ResourceSaver] singleton. This is accomplished thanks to multiple "
+"[ResourceFormatSaver]s, each handling its own format and called "
+"automatically by the engine.\n"
+"By default, Godot saves resources as [code].tres[/code] (text-based), [code]."
+"res[/code] (binary) or another built-in format, but you can choose to create "
+"your own format by extending this class. 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 "
+"ResourceFormatSavers, it will be called automatically when saving resources "
+"of its recognized type(s). You may also implement a [ResourceFormatLoader]."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:19
+msgid ""
+"Returns the list of extensions available for saving the resource object, "
+"provided it is recognized (see [method recognize])."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:28
+msgid "Returns whether the given resource object can be saved by this saver."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:41
+msgid ""
+"Saves the given resource object to a file at the target [code]path[/code]. "
+"[code]flags[/code] is a bitmask composed with [enum ResourceSaver."
+"SaverFlags] constants.\n"
+"Returns [constant OK] on success, or an [enum Error] constant in case of "
+"failure."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:4
+msgid "Singleton used to load resource files."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:7
+msgid ""
+"Singleton used to load resource files from the filesystem.\n"
+"It uses the many [ResourceFormatLoader] classes registered in the engine "
+"(either built-in or from a plugin) to load files into memory and convert "
+"them to a format that can be used by the engine.\n"
+"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."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:22
+msgid ""
+"Returns whether a recognized resource exists for the given [code]path[/"
+"code].\n"
+"An optional [code]type_hint[/code] can be used to further specify the "
+"[Resource] type that should be handled by the [ResourceFormatLoader]."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:32
+msgid ""
+"Returns the dependencies for the resource at the given [code]path[/code]."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:41
+msgid "Returns the list of recognized extensions for a resource type."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:50
+msgid ""
+"Returns whether a cached resource is available for the given [code]path[/"
+"code].\n"
+"Once a resource has been loaded by the engine, it is cached in memory for "
+"faster access, and future calls to the [method load] method will use the "
+"cached version. The cached resource can be overridden by using [method "
+"Resource.take_over_path] on a new resource for that same path."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:64
+msgid ""
+"Loads a resource at the given [code]path[/code], caching the result for "
+"further access.\n"
+"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.\n"
+"An optional [code]type_hint[/code] can be used to further specify the "
+"[Resource] type that should be handled by the [ResourceFormatLoader].\n"
+"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.\n"
+"Returns an empty resource if no ResourceFormatLoader could handle the file."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:77
+msgid ""
+"Returns the resource loaded by [method load_threaded_request].\n"
+"If this is called before the loading thread is done (i.e. [method "
+"load_threaded_get_status] is not [constant THREAD_LOAD_LOADED]), the calling "
+"thread will be blocked until the resource has finished loading."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:89
+msgid ""
+"Returns the status of a threaded loading operation started with [method "
+"load_threaded_request] for the resource at [code]path[/code]. See [enum "
+"ThreadLoadStatus] for possible return values.\n"
+"An array variable can optionally be passed via [code]progress[/code], and "
+"will return a one-element array containing the percentage of completion of "
+"the threaded loading."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:103
+msgid ""
+"Loads the resource using threads. If [code]use_sub_threads[/code] is "
+"[code]true[/code], multiple threads will be used to load the resource, which "
+"makes loading faster, but may affect the main thread (and thus cause game "
+"slowdowns)."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:112
+msgid ""
+"Changes the behavior on missing sub-resources. The default behavior is to "
+"abort loading."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:118
+msgid ""
+"The resource is invalid, or has not been loaded with [method "
+"load_threaded_request]."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:121
+msgid "The resource is still being loaded."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:124
+msgid "Some error occurred during loading and it failed."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:127
+msgid ""
+"The resource was loaded successfully and can be accessed via [method "
+"load_threaded_get]."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:4
+msgid "Resource Preloader Node."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:7
+msgid ""
+"This node is used to preload sub-resources inside a scene, so when the scene "
+"is loaded, all the resources are ready to use and can be retrieved from the "
+"preloader.\n"
+"GDScript has a simplified [method @GDScript.preload] built-in method which "
+"can be used in most situations, leaving the use of [ResourcePreloader] for "
+"more advanced scenarios."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:21
+msgid ""
+"Adds a resource to the preloader with the given [code]name[/code]. If a "
+"resource with the given [code]name[/code] already exists, the new resource "
+"will be renamed to \"[code]name[/code] N\" where N is an incrementing number "
+"starting from 2."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:30
+msgid "Returns the resource associated to [code]name[/code]."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:37
+msgid "Returns the list of resources inside the preloader."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:46
+msgid ""
+"Returns [code]true[/code] if the preloader contains a resource associated to "
+"[code]name[/code]."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:55
+msgid ""
+"Removes the resource associated to [code]name[/code] from the preloader."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:66
+msgid ""
+"Renames a resource inside the preloader from [code]name[/code] to "
+"[code]newname[/code]."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:4
+msgid "Singleton for saving Godot-specific resource types."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:7
+msgid ""
+"Singleton for saving Godot-specific resource types to the filesystem.\n"
+"It uses the many [ResourceFormatSaver] classes registered in the engine "
+"(either built-in or from a plugin) to save engine-specific resource data to "
+"text-based (e.g. [code].tres[/code] or [code].tscn[/code]) or binary files "
+"(e.g. [code].res[/code] or [code].scn[/code])."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:19
+msgid ""
+"Returns the list of extensions available for saving a resource of a given "
+"type."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:32
+msgid ""
+"Saves a resource to disk to the given path, using a [ResourceFormatSaver] "
+"that recognizes the resource object.\n"
+"The [code]flags[/code] bitmask can be specified to customize the save "
+"behavior.\n"
+"Returns [constant OK] on success."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:40
+msgid "Save the resource with a path relative to the scene which uses it."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:43
+msgid "Bundles external resources."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:46
+msgid ""
+"Changes the [member Resource.resource_path] of the saved resource to match "
+"its new location."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:49
+msgid ""
+"Do not save editor-specific metadata (identified by their [code]__editor[/"
+"code] prefix)."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:52
+msgid "Save as big endian (see [member File.endian_swap])."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:55
+msgid ""
+"Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only "
+"available for binary resource types."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:58
+msgid ""
+"Take over the paths of the saved subresources (see [method Resource."
+"take_over_path])."
+msgstr ""
+
+#: doc/classes/RichTextEffect.xml:4
+msgid "A custom effect for use with [RichTextLabel]."
+msgstr ""
+
+#: doc/classes/RichTextEffect.xml:7
+msgid ""
+"A custom effect for use with [RichTextLabel].\n"
+"[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.\n"
+"[codeblock]\n"
+"# The RichTextEffect will be usable like this: `[example]Some text[/"
+"example]`\n"
+"var bbcode = \"example\"\n"
+"[/codeblock]\n"
+"[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."
+msgstr ""
+
+#: doc/classes/RichTextEffect.xml:26
+msgid ""
+"Override this method to modify properties in [code]char_fx[/code]. The "
+"method must return [code]true[/code] if the character could be transformed "
+"successfully. If the method returns [code]false[/code], it will skip "
+"transformation to avoid displaying broken text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:4
+msgid "Label that displays rich text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:7
+msgid ""
+"Rich text can contain custom text, fonts, images and some basic formatting. "
+"The label manages these as an internal tag stack. It also adapts itself to "
+"given width/heights.\n"
+"[b]Note:[/b] Assignments to [member bbcode_text] clear the tag stack and "
+"reconstruct it from the property's contents. Any edits made to [member "
+"bbcode_text] will erase previous edits made from other manual sources such "
+"as [method append_bbcode] and the [code]push_*[/code] / [method pop] methods."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:24
+msgid ""
+"Adds an image's opening and closing tags to the tag stack, optionally "
+"providing a [code]width[/code] and [code]height[/code] to resize the image.\n"
+"If [code]width[/code] or [code]height[/code] is set to 0, the image size "
+"will be adjusted in order to keep the original aspect ratio."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:34
+msgid "Adds raw non-BBCode-parsed text to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:43
+msgid ""
+"Parses [code]bbcode[/code] and adds tags to the tag stack as needed. Returns "
+"the result of the parsing, [constant OK] if successful."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:50
+msgid "Clears the tag stack and sets [member bbcode_text] to an empty string."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:57
+msgid "Returns the height of the content."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:64
+msgid ""
+"Returns the total number of newlines in the tag stack's text tags. Considers "
+"wrapped text as one line."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:71
+msgid ""
+"Returns the total number of characters from text tags. Does not include "
+"BBCodes."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:78
+msgid "Returns the vertical scrollbar."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:85
+msgid "Returns the number of visible lines."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:94
+msgid ""
+"Installs a custom effect. [code]effect[/code] should be a valid "
+"[RichTextEffect]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:101
+msgid "Adds a newline tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:110
+msgid ""
+"The assignment version of [method append_bbcode]. Clears the tag stack and "
+"inserts the new content. Returns [constant OK] if parses [code]bbcode[/code] "
+"successfully."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:119
+msgid "Parses BBCode parameter [code]expressions[/code] into a dictionary."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:126
+msgid ""
+"Terminates the current tag. Use after [code]push_*[/code] methods to close "
+"BBCodes manually. Does not need to follow [code]add_*[/code] methods."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:135
+msgid ""
+"Adds an [code][align][/code] tag based on the given [code]align[/code] "
+"value. See [enum Align] for possible values."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:142
+msgid ""
+"Adds a [code][font][/code] tag with a bold font to the tag stack. This is "
+"the same as adding a [code][b][/code] tag if not currently in a [code][i][/"
+"code] tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:149
+msgid ""
+"Adds a [code][font][/code] tag with a bold italics font to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:156
+msgid ""
+"Adds a [code][cell][/code] tag to the tag stack. Must be inside a [code]"
+"[table][/code] tag. See [method push_table] for details."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:165
+msgid "Adds a [code][color][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:174
+msgid ""
+"Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for "
+"its duration."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:183
+msgid ""
+"Adds an [code][indent][/code] tag to the tag stack. Multiplies [code]level[/"
+"code] by current [member tab_size] to determine new margin length."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:190
+msgid ""
+"Adds a [code][font][/code] tag with a italics font to the tag stack. This is "
+"the same as adding a [code][i][/code] tag if not currently in a [code][b][/"
+"code] tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:199
+msgid ""
+"Adds a [code][list][/code] tag to the tag stack. Similar to the BBCodes "
+"[code][ol][/code] or [code][ul][/code], but supports more list types. Not "
+"fully implemented!"
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:208
+msgid ""
+"Adds a [code][meta][/code] tag to the tag stack. Similar to the BBCode [code]"
+"[url=something]{text}[/url][/code], but supports non-[String] metadata types."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:215
+msgid "Adds a [code][font][/code] tag with a monospace font to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:222
+msgid "Adds a [code][font][/code] tag with a normal font to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:229
+msgid "Adds a [code][s][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:238
+msgid "Adds a [code][table=columns][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:245
+msgid "Adds a [code][u][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:254
+msgid ""
+"Removes a line of content from the label. Returns [code]true[/code] if the "
+"line exists.\n"
+"The [code]line[/code] argument is the index of the line to remove, it can "
+"take values in the interval [code][0, get_line_count() - 1][/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:264
+msgid "Scrolls the window's top line to match [code]line[/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:277
+msgid ""
+"Edits the selected column's expansion options. If [code]expand[/code] is "
+"[code]true[/code], the column expands in proportion to its expansion ratio "
+"versus the other columns' ratios.\n"
+"For example, 2 columns with ratios 3 and 4 plus 70 pixels in available width "
+"would expand 30 and 40 pixels, respectively.\n"
+"If [code]expand[/code] is [code]false[/code], the column will not contribute "
+"to the total ratio."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:285
+msgid "If [code]true[/code], the label uses BBCode formatting."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:288
+msgid ""
+"The label's text in BBCode format. Is not representative of manual "
+"modifications to the internal tag stack. Erases changes made by other "
+"methods when edited.\n"
+"[b]Note:[/b] It is unadvised to use [code]+=[/code] operator with "
+"[code]bbcode_text[/code] (e.g. [code]bbcode_text += \"some string\"[/code]) "
+"as it replaces the whole text and can cause slowdowns. Use [method "
+"append_bbcode] for adding text instead."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:292
+msgid ""
+"The currently installed custom effects. This is an array of "
+"[RichTextEffect]s.\n"
+"To add a custom effect, it's more convenient to use [method install_effect]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:296
+msgid ""
+"If [code]true[/code], the label underlines meta tags such as [code][url]"
+"{text}[/url][/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:299
+msgid "If [code]true[/code], the label uses the custom font color."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:302
+msgid ""
+"The range of characters to display, as a [float] between 0.0 and 1.0. When "
+"assigned an out of range value, it's the same as assigning 1.0.\n"
+"[b]Note:[/b] Setting this property updates [member visible_characters] based "
+"on current [method get_total_character_count]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:307
+msgid ""
+"If [code]true[/code], the scrollbar is visible. Setting this to [code]false[/"
+"code] does not block scrolling completely. See [method scroll_to_line]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:310
+msgid ""
+"If [code]true[/code], the window scrolls down to display new content "
+"automatically."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:313
+msgid "If [code]true[/code], the label allows text selection."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:316
+msgid ""
+"The number of spaces associated with a single tab length. Does not affect "
+"[code]\\t[/code] in text tags, only indent tags."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:319
+msgid ""
+"The raw text of the label.\n"
+"When set, clears the tag stack and adds a raw text tag to the top of it. "
+"Does not parse BBCodes. Does not modify [member bbcode_text]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:323
+msgid ""
+"The restricted number of characters to display in the label. If [code]-1[/"
+"code], all characters will be displayed."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:331
+msgid ""
+"Triggered when the user clicks on content between meta tags. If the meta is "
+"defined in text, e.g. [code][url={\"data\"=\"hi\"}]hi[/url][/code], then the "
+"parameter for this signal will be a [String] type. If a particular type or "
+"an object is desired, the [method push_meta] method must be used to manually "
+"insert the data into the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:338
+msgid "Triggers when the mouse exits a meta tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:345
+msgid "Triggers when the mouse enters a meta tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:351
+msgid "Makes text left aligned."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:354
+msgid "Makes text centered."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:357
+msgid "Makes text right aligned."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:360
+msgid "Makes text fill width."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:363
+msgid "Each list item has a number marker."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:366
+msgid "Each list item has a letter marker."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:369
+msgid "Each list item has a filled circle marker."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:412
+msgid "The font used for bold text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:415
+msgid "The font used for bold italics text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:418
+msgid "The default text color."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:421
+msgid "The background The background used when the [RichTextLabel] is focused."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:424
+msgid ""
+"The color of selected text, used when [member selection_enabled] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:427
+msgid "The color of the font's shadow."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:430
+msgid "The font used for italics text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:433
+msgid "The vertical space between lines."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:436
+msgid "The font used for monospace text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:439
+msgid "The normal background for the [RichTextLabel]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:442
+msgid "The default text font."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:445
+msgid "The color of the selection box."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:448
+msgid ""
+"Boolean value. If 1 ([code]true[/code]), the shadow will be displayed around "
+"the whole text as an outline."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:451
+msgid "The horizontal offset of the font's shadow."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:454
+msgid "The vertical offset of the font's shadow."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:457
+msgid "The horizontal separation of elements in a table."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:460
+msgid "The vertical separation of elements in a table."
+msgstr ""
+
+#: doc/classes/RID.xml:4
+msgid "Handle for a [Resource]'s unique ID."
+msgstr ""
+
+#: doc/classes/RID.xml:7
+msgid ""
+"The RID type is used to access the unique integer ID of a resource. They are "
+"opaque, which means they do not grant access to the associated resource by "
+"themselves. They are used by and with the low-level Server classes such as "
+"[RenderingServer]."
+msgstr ""
+
+#: doc/classes/RID.xml:18
+msgid ""
+"Creates a new RID instance with the ID of a given resource. When not handed "
+"a valid resource, silently stores the unused ID 0."
+msgstr ""
+
+#: doc/classes/RID.xml:25
+msgid "Returns the ID of the referenced resource."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:4
+msgid "A body that is controlled by the 2D physics engine."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:7
+msgid ""
+"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.\n"
+"A RigidBody2D has 4 behavior [member mode]s: Rigid, Static, Character, and "
+"Kinematic.\n"
+"[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.\n"
+"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.\n"
+"If you need to override the default physics behavior or add a transformation "
+"at runtime, you can write a custom force integration. See [member "
+"custom_integrator]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:22
+msgid ""
+"Allows you to read and safely modify the simulation state for the object. "
+"Use this instead of [method Node._physics_process] if you need to directly "
+"change the body's [code]position[/code] or other physics properties. By "
+"default, it works in addition to the usual physics behavior, but [member "
+"custom_integrator] allows you to disable the default behavior and write "
+"custom force integration for a body."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:71
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time-independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason it should only be used when simulating one-time impacts (use "
+"the \"_force\" functions otherwise). The position uses the rotation of the "
+"global coordinate system, but is centered at the object's origin."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:87
+msgid ""
+"Returns a list of the bodies colliding with this one. Use [member "
+"contacts_reported] to set the maximum number reported. You must also set "
+"[member contact_monitor] to [code]true[/code].\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of collisions is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:97
+msgid ""
+"Sets the body's velocity on the given axis. The velocity in the given vector "
+"axis will be set as the given vector length. This is useful for jumping "
+"behavior."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:112
+msgid ""
+"Returns [code]true[/code] if a collision would result from moving in the "
+"given vector. [code]margin[/code] increases the size of the shapes involved "
+"in the collision detection, and [code]result[/code] is an object of type "
+"[PhysicsTestMotionResult2D], which contains additional information about the "
+"collision (should there be one)."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:118
+msgid ""
+"Damps the body's [member angular_velocity]. If [code]-1[/code], the body "
+"will use the [b]Default Angular Damp[/b] defined in [b]Project > Project "
+"Settings > Physics > 2d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:124
+msgid "The body's total applied force."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:127
+msgid "The body's total applied torque."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:130
+msgid ""
+"If [code]true[/code], the body will not calculate forces and will act as a "
+"static body if there is no movement. The body will wake up when other forces "
+"are applied via collisions or by using [method apply_impulse] or [method "
+"add_force]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:133
+msgid ""
+"If [code]true[/code], the body will emit signals when it collides with "
+"another RigidBody2D. See also [member contacts_reported]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:136
+msgid "The maximum number of contacts to report."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:139
+msgid ""
+"Continuous collision detection mode.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide instead of moving it and correcting its movement after collision. "
+"Continuous collision detection is slower, but more precise and misses fewer "
+"collisions with small, fast-moving objects. Raycasting and shapecasting "
+"methods are available. See [enum CCDMode] for details."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:143
+msgid ""
+"If [code]true[/code], internal force integration is disabled for this body. "
+"Aside from collision response, the body will only move as determined by the "
+"[method _integrate_forces] function."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:146
+msgid ""
+"Multiplies the gravity applied to the body. The body's gravity is calculated "
+"from the [b]Default Gravity[/b] value in [b]Project > Project Settings > "
+"Physics > 2d[/b] and/or any additional gravity vector applied by [Area2D]s."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:149
+msgid ""
+"The body's moment of inertia. This is like mass, but for rotation: it "
+"determines how much torque it takes to rotate the body. The moment of "
+"inertia is usually computed automatically from the mass and the shapes, but "
+"this function allows you to set a custom value. Set 0 inertia to return to "
+"automatically computing it."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:152
+msgid ""
+"Damps the body's [member linear_velocity]. If [code]-1[/code], the body will "
+"use the [b]Default Linear Damp[/b] in [b]Project > Project Settings > "
+"Physics > 2d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:158 doc/classes/RigidBody3D.xml:174
+msgid "The body's mass."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:161
+msgid "The body's mode. See [enum Mode] for possible values."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:164 doc/classes/RigidBody3D.xml:180
+#: doc/classes/StaticBody2D.xml:22 doc/classes/StaticBody3D.xml:22
+msgid ""
+"The physics material override for the body.\n"
+"If a material is assigned to this property, it will be used instead of any "
+"other physics material, such as an inherited one."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:168
+msgid ""
+"If [code]true[/code], the body is sleeping and will not calculate forces "
+"until woken up by a collision or by using [method apply_impulse] or [method "
+"add_force]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:171
+msgid ""
+"The body's weight based on its mass and the [b]Default Gravity[/b] value in "
+"[b]Project > Project Settings > Physics > 2d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:179
+msgid ""
+"Emitted when a body enters into contact with this one. [member "
+"contact_monitor] must be [code]true[/code] and [member contacts_reported] "
+"greater than [code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:186
+msgid ""
+"Emitted when a body exits contact with this one. [member contact_monitor] "
+"must be [code]true[/code] and [member contacts_reported] greater than "
+"[code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:199
+msgid ""
+"Emitted when a body enters into contact with this one. Reports colliding "
+"shape information. See [CollisionObject2D] for shape index information. "
+"[member contact_monitor] must be [code]true[/code] and [member "
+"contacts_reported] greater than [code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:212
+msgid ""
+"Emitted when a body shape exits contact with this one. Reports colliding "
+"shape information. See [CollisionObject2D] for shape index information. "
+"[member contact_monitor] must be [code]true[/code] and [member "
+"contacts_reported] greater than [code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:217
+msgid "Emitted when [member sleeping] changes."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:223
+msgid ""
+"Rigid mode. The body behaves as a physical object. It collides with other "
+"bodies and responds to forces applied to it. This is the default mode."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:226
+msgid "Static mode. The body behaves like a [StaticBody2D] and does not move."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:229
+msgid ""
+"Character mode. Similar to [constant MODE_RIGID], but the body can not "
+"rotate."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:232
+msgid ""
+"Kinematic mode. The body behaves like a [KinematicBody2D], and must be moved "
+"by code."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:235
+msgid ""
+"Continuous collision detection disabled. This is the fastest way to detect "
+"body collisions, but can miss small, fast-moving objects."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:238
+msgid ""
+"Continuous collision detection enabled using raycasting. This is faster than "
+"shapecasting but less precise."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:241
+msgid ""
+"Continuous collision detection enabled using shapecasting. This is the "
+"slowest CCD method and the most precise."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:4
+msgid ""
+"Physics Body whose position is determined through physics simulation in 3D "
+"space."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:7
+msgid ""
+"This is the node that implements full 3D physics. This means that you do not "
+"control a RigidBody3D directly. Instead, you can apply forces to it "
+"(gravity, impulses, etc.), and the physics simulation will calculate the "
+"resulting movement, collision, bouncing, rotating, etc.\n"
+"A RigidBody3D has 4 behavior [member mode]s: Rigid, Static, Character, and "
+"Kinematic.\n"
+"[b]Note:[/b] Don't change a RigidBody3D's position every frame or very "
+"often. Sporadic changes work fine, but physics runs at a different "
+"granularity (fixed Hz) than usual rendering (process callback) and maybe "
+"even in a separate thread, so changing this from a process loop may result "
+"in strange behavior. If you need to directly affect the body's state, use "
+"[method _integrate_forces], which allows you to directly access the physics "
+"state.\n"
+"If you need to override the default physics behavior, you can write a custom "
+"force integration function. See [member custom_integrator]."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:22
+msgid ""
+"Called during physics processing, allowing you to read and safely modify the "
+"simulation state for the object. By default, it works in addition to the "
+"usual physics behavior, but the [member custom_integrator] property allows "
+"you to disable the default behavior and do fully custom force integration "
+"for a body."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:43
+msgid "Adds a constant force (i.e. acceleration)."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:52
+msgid ""
+"Adds a constant rotational force (i.e. a motor) without affecting position."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:61
+msgid ""
+"Applies a directional impulse without affecting rotation.\n"
+"This is equivalent to [code]apply_impulse(Vector3(0,0,0), impulse)[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:73
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason it should only be used when simulating one-time impacts. The "
+"position uses the rotation of the global coordinate system, but is centered "
+"at the object's origin."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:82
+msgid ""
+"Applies a torque impulse which will be affected by the body mass and shape. "
+"This will rotate the body around the [code]impulse[/code] vector passed."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:91
+msgid ""
+"Returns [code]true[/code] if the specified linear or rotational axis is "
+"locked."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:98
+msgid ""
+"Returns a list of the bodies colliding with this one. By default, number of "
+"max contacts reported is at 0, see the [member contacts_reported] property "
+"to increase it.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of collisions is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:110
+msgid "Locks the specified linear or rotational axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:125
+msgid "Damps RigidBody3D's rotational forces."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:128
+msgid "RigidBody3D's rotational velocity."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:131
+msgid "Lock the body's rotation in the X axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:134
+msgid "Lock the body's rotation in the Y axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:137
+msgid "Lock the body's rotation in the Z axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:140
+msgid "Lock the body's movement in the X axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:143
+msgid "Lock the body's movement in the Y axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:146
+msgid "Lock the body's movement in the Z axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:149
+msgid ""
+"If [code]true[/code], the RigidBody3D will not calculate forces and will act "
+"as a static body while there is no movement. It will wake up when forces are "
+"applied through other collisions or when the [code]apply_impulse[/code] "
+"method is used."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:152
+msgid ""
+"If [code]true[/code], the RigidBody3D will emit signals when it collides "
+"with another RigidBody3D."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:155
+msgid ""
+"The maximum contacts to report. Bodies can keep a log of the contacts with "
+"other bodies, this is enabled by setting the maximum amount of contacts "
+"reported to a number greater than 0."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:158
+msgid ""
+"If [code]true[/code], continuous collision detection is used.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided. "
+"Continuous collision detection is more precise, and misses fewer impacts by "
+"small, fast-moving objects. Not using continuous collision detection is "
+"faster to compute, but can miss small, fast-moving objects."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:162
+msgid ""
+"If [code]true[/code], internal force integration will be disabled (like "
+"gravity or air friction) for this body. Other than collision response, the "
+"body will only move as determined by the [method _integrate_forces] "
+"function, if defined."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:165
+msgid ""
+"This is multiplied by the global 3D gravity setting found in [b]Project > "
+"Project Settings > Physics > 3d[/b] to produce RigidBody3D's gravity. For "
+"example, a value of 1 will be normal gravity, 2 will apply double gravity, "
+"and 0.5 will apply half gravity to this object."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:168
+msgid ""
+"The body's linear damp. Cannot be less than -1.0. If this value is different "
+"from -1.0, any linear damp derived from the world or areas will be "
+"overridden."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:171
+msgid ""
+"The body's linear velocity. Can be used sporadically, but [b]don't set this "
+"every frame[/b], because physics may run in another thread and runs at a "
+"different granularity. Use [method _integrate_forces] as your process loop "
+"for precise control of the body state."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:177
+msgid "The body mode. See [enum Mode] for possible values."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:184
+msgid ""
+"If [code]true[/code], the body is sleeping and will not calculate forces "
+"until woken up by a collision or the [code]apply_impulse[/code] method."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:187
+msgid ""
+"The body's weight based on its mass and the global 3D gravity. Global values "
+"are set in [b]Project > Project Settings > Physics > 3d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:195
+msgid ""
+"Emitted when a body enters into contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:202
+msgid ""
+"Emitted when a body shape exits contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:215
+msgid ""
+"Emitted when a body enters into contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work.\n"
+"This signal not only receives the body that collided with this one, but also "
+"its [RID] ([code]body_id[/code]), the shape index from the colliding body "
+"([code]body_shape[/code]), and the shape index from this body "
+"([code]local_shape[/code]) the other body collided with."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:229
+msgid ""
+"Emitted when a body shape exits contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work.\n"
+"This signal not only receives the body that stopped colliding with this one, "
+"but also its [RID] ([code]body_id[/code]), the shape index from the "
+"colliding body ([code]body_shape[/code]), and the shape index from this body "
+"([code]local_shape[/code]) the other body stopped colliding with."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:235
+msgid ""
+"Emitted when the body changes its sleeping state. Either by sleeping or "
+"waking up."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:241
+msgid ""
+"Rigid body mode. This is the \"natural\" state of a rigid body. It is "
+"affected by forces, and can move, rotate, and be affected by user code."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:244
+msgid ""
+"Static mode. The body behaves like a [StaticBody3D], and can only move by "
+"user code."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:247
+msgid ""
+"Character body mode. This behaves like a rigid body, but can not rotate."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:250
+msgid ""
+"Kinematic body mode. The body behaves like a [KinematicBody3D], and can only "
+"move by user code."
+msgstr ""
+
+#: doc/classes/SceneState.xml:4
+msgid "A script interface to a scene file's data."
+msgstr ""
+
+#: doc/classes/SceneState.xml:7
+msgid ""
+"Maintains a list of resources, nodes, exported, and overridden properties, "
+"and built-in scripts associated with a scene.\n"
+"This class cannot be instantiated directly, it is retrieved for a given "
+"scene as the result of [method PackedScene.get_state]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:19
+msgid ""
+"Returns the list of bound parameters for the signal at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:26
+msgid ""
+"Returns the number of signal connections in the scene.\n"
+"The [code]idx[/code] argument used to query connection metadata in other "
+"[code]get_connection_*[/code] methods in the interval [code][0, "
+"get_connection_count() - 1][/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:36
+msgid ""
+"Returns the connection flags for the signal at [code]idx[/code]. See [enum "
+"Object.ConnectFlags] constants."
+msgstr ""
+
+#: doc/classes/SceneState.xml:45
+msgid "Returns the method connected to the signal at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:54
+msgid "Returns the name of the signal at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:63
+msgid ""
+"Returns the path to the node that owns the signal at [code]idx[/code], "
+"relative to the root node."
+msgstr ""
+
+#: doc/classes/SceneState.xml:72
+msgid ""
+"Returns the path to the node that owns the method connected to the signal at "
+"[code]idx[/code], relative to the root node."
+msgstr ""
+
+#: doc/classes/SceneState.xml:79
+msgid ""
+"Returns the number of nodes in the scene.\n"
+"The [code]idx[/code] argument used to query node data in other "
+"[code]get_node_*[/code] methods in the interval [code][0, get_node_count() - "
+"1][/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:89
+msgid ""
+"Returns the list of group names associated with the node at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:98
+msgid ""
+"Returns the node's index, which is its position relative to its siblings. "
+"This is only relevant and saved in scenes for cases where new nodes are "
+"added to an instanced or inherited scene among siblings from the base scene. "
+"Despite the name, this index is not related to the [code]idx[/code] argument "
+"used here and in other methods."
+msgstr ""
+
+#: doc/classes/SceneState.xml:107
+msgid ""
+"Returns a [PackedScene] for the node at [code]idx[/code] (i.e. the whole "
+"branch starting at this node, with its child nodes and resources), or "
+"[code]null[/code] if the node is not an instance."
+msgstr ""
+
+#: doc/classes/SceneState.xml:116
+msgid ""
+"Returns the path to the represented scene file if the node at [code]idx[/"
+"code] is an [InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:125
+msgid "Returns the name of the node at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:134
+msgid ""
+"Returns the path to the owner of the node at [code]idx[/code], relative to "
+"the root node."
+msgstr ""
+
+#: doc/classes/SceneState.xml:145
+msgid ""
+"Returns the path to the node at [code]idx[/code].\n"
+"If [code]for_parent[/code] is [code]true[/code], returns the path of the "
+"[code]idx[/code] node's parent instead."
+msgstr ""
+
+#: doc/classes/SceneState.xml:155
+msgid ""
+"Returns the number of exported or overridden properties for the node at "
+"[code]idx[/code].\n"
+"The [code]prop_idx[/code] argument used to query node property data in other "
+"[code]get_node_property_*[/code] methods in the interval [code][0, "
+"get_node_property_count() - 1][/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:167
+msgid ""
+"Returns the name of the property at [code]prop_idx[/code] for the node at "
+"[code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:178
+msgid ""
+"Returns the value of the property at [code]prop_idx[/code] for the node at "
+"[code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:187
+msgid "Returns the type of the node at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:196
+msgid ""
+"Returns [code]true[/code] if the node at [code]idx[/code] is an "
+"[InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:202
+msgid ""
+"If passed to [method PackedScene.instance], blocks edits to the scene state."
+msgstr ""
+
+#: doc/classes/SceneState.xml:205
+msgid ""
+"If passed to [method PackedScene.instance], provides inherited scene "
+"resources to the local scene.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/SceneState.xml:209
+msgid ""
+"If passed to [method PackedScene.instance], provides local scene resources "
+"to the local scene. Only the main scene should receive the main edit state.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:4
+msgid "Manages the game loop via a hierarchy of nodes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"[SceneTree] is the default [MainLoop] implementation used by scenes, and is "
+"thus in charge of the game loop."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"scene_tree.html"
+msgstr ""
+
+#: doc/classes/SceneTree.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/viewports/"
+"multiple_resolutions.html"
+msgstr ""
+
+#: doc/classes/SceneTree.xml:24
+msgid "Calls [code]method[/code] on each member of the given group."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:37
+msgid ""
+"Calls [code]method[/code] on each member of the given group, respecting the "
+"given [enum GroupCallFlags]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:46
+msgid ""
+"Changes the running scene to the one at the given [code]path[/code], after "
+"loading it into a [PackedScene] and creating a new instance.\n"
+"Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the "
+"[code]path[/code] cannot be loaded into a [PackedScene], or [constant "
+"ERR_CANT_CREATE] if that scene cannot be instantiated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:56
+msgid ""
+"Changes the running scene to a new instance of the given [PackedScene].\n"
+"Returns [constant OK] on success or [constant ERR_CANT_CREATE] if the scene "
+"cannot be instantiated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:68
+msgid ""
+"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.\n"
+"Commonly used to create a one-shot delay timer as in the following example:\n"
+"[codeblock]\n"
+"func some_function():\n"
+" print(\"start\")\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(\"end\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/SceneTree.xml:82
+msgid ""
+"Returns the current frame number, i.e. the total frame count since the "
+"application started."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:89
+msgid ""
+"Returns the peer IDs of all connected peers of this [SceneTree]'s [member "
+"network_peer]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:96
+msgid "Returns the unique peer ID of this [SceneTree]'s [member network_peer]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:103
+msgid "Returns the number of nodes in this [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:112
+msgid "Returns a list of all nodes assigned to the given group."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:119
+msgid "Returns the sender's peer ID for the most recently received RPC call."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:128
+msgid "Returns [code]true[/code] if the given group exists."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:142
+msgid ""
+"Returns [code]true[/code] if this [SceneTree]'s [member network_peer] is in "
+"server mode (listening for connections)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:153
+msgid "Sends the given notification to all members of the [code]group[/code]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:166
+msgid ""
+"Sends the given notification to all members of the [code]group[/code], "
+"respecting the given [enum GroupCallFlags]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:175
+msgid ""
+"Queues the given object for deletion, delaying the call to [method Object."
+"free] to after the current frame."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:184
+msgid ""
+"Quits the application. 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."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:191
+msgid ""
+"Reloads the currently active scene.\n"
+"Returns [constant OK] on success, [constant ERR_UNCONFIGURED] if no [member "
+"current_scene] was defined yet, [constant ERR_CANT_OPEN] if [member "
+"current_scene] cannot be loaded into a [PackedScene], or [constant "
+"ERR_CANT_CREATE] if the scene cannot be instantiated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:201
+msgid ""
+"If [code]true[/code], the application automatically accepts quitting. "
+"Enabled by default.\n"
+"For mobile platforms, see [method set_quit_on_go_back]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:215
+msgid ""
+"Sets the given [code]property[/code] to [code]value[/code] on all members of "
+"the given group."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:230
+msgid ""
+"Sets the given [code]property[/code] to [code]value[/code] on all members of "
+"the given group, respecting the given [enum GroupCallFlags]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:239
+msgid ""
+"If [code]true[/code], the application quits automatically on going back (e."
+"g. on Android). Enabled by default.\n"
+"To handle 'Go Back' button when this option is disabled, use [constant "
+"DisplayServer.WINDOW_EVENT_GO_BACK_REQUEST]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:246
+msgid "The current scene."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:249
+msgid ""
+"If [code]true[/code], collision shapes will be visible when running the game "
+"from the editor for debugging purposes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:252
+msgid ""
+"If [code]true[/code], navigation polygons will be visible when running the "
+"game from the editor for debugging purposes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:255
+msgid "The root of the edited scene."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:258
+msgid "The default [MultiplayerAPI] instance for this [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:261
+msgid ""
+"If [code]true[/code] (default value), enables automatic polling of the "
+"[MultiplayerAPI] for this SceneTree during [signal idle_frame].\n"
+"If [code]false[/code], you need to manually call [method MultiplayerAPI."
+"poll] to process network packets and deliver RPCs/RSETs. This allows running "
+"RPCs/RSETs in a different loop (e.g. physics, thread, specific time step) "
+"and for manual [Mutex] protection when accessing the [MultiplayerAPI] from "
+"threads."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:265
+msgid ""
+"The peer object to handle the RPC system (effectively enabling networking "
+"when set). Depending on the peer itself, the [SceneTree] will become a "
+"network server (check with [method is_network_server]) and will set the root "
+"node's network mode to master, or it will become a regular peer with the "
+"root node set to puppet. All child nodes are set to inherit the network mode "
+"by default. Handling of networking-related events (connection, "
+"disconnection, new clients) is done by connecting to [SceneTree]'s signals."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:268
+msgid ""
+"If [code]true[/code], the [SceneTree] is paused. Doing so will have the "
+"following behavior:\n"
+"- 2D and 3D physics will be stopped.\n"
+"- [method Node._process], [method Node._physics_process] and [method Node."
+"_input] will not be called anymore in nodes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:273
+msgid ""
+"If [code]true[/code], the [SceneTree]'s [member network_peer] refuses new "
+"incoming connections."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:276
+msgid "The [SceneTree]'s root [Window]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:282
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] successfully "
+"connected to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:287
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] fails to establish "
+"a connection to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:296
+msgid ""
+"Emitted when files are dragged from the OS file manager and dropped in the "
+"game window. The arguments are a list of file paths and the identifier of "
+"the screen where the drag originated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:301
+msgid ""
+"Emitted immediately before [method Node._process] is called on every node in "
+"the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:308
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] connects with a "
+"new peer. ID is the peer ID of the new peer. Clients get notified when other "
+"clients connect to the same server. Upon connecting to a server, a client "
+"also receives this signal for the server (with ID being 1)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:315
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] disconnects from a "
+"peer. Clients get notified when other clients disconnect from the same "
+"server."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:322
+msgid "Emitted whenever a node is added to the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:329
+msgid ""
+"Emitted when a node's configuration changed. Only emitted in [code]tool[/"
+"code] mode."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:336
+msgid "Emitted whenever a node is removed from the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:343
+msgid "Emitted whenever a node is renamed."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:348
+msgid ""
+"Emitted immediately before [method Node._physics_process] is called on every "
+"node in the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:353
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] disconnected from "
+"server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:358
+msgid ""
+"Emitted whenever the [SceneTree] hierarchy changed (children being moved or "
+"renamed, etc.)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:364
+msgid "Call a group with no flags (default)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:367
+msgid "Call a group in reverse scene order."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:370
+msgid "Call a group immediately (calls are normally made on idle)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:373
+msgid "Call a group only once even if the call is executed many times."
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:4
+msgid "One-shot timer."
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:7
+msgid ""
+"A one-shot timer managed by the scene tree, which emits [signal timeout] on "
+"completion. See also [method SceneTree.create_timer].\n"
+"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:\n"
+"[codeblock]\n"
+"func some_function():\n"
+" print(\"Timer started.\")\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(\"Timer ended.\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:22
+msgid "The time remaining."
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:28 doc/classes/Timer.xml:62
+msgid "Emitted when the timer reaches 0."
+msgstr ""
+
+#: doc/classes/Script.xml:4
+msgid "A class stored as a resource."
+msgstr ""
+
+#: doc/classes/Script.xml:7
+msgid ""
+"A class stored as a resource. A script extends the functionality of all "
+"objects that instance it.\n"
+"The [code]new[/code] method of a script subclass creates a new instance. "
+"[method Object.set_script] extends an existing object, if that object's "
+"class matches one of the script's base classes."
+msgstr ""
+
+#: doc/classes/Script.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"scripting.html"
+msgstr ""
+
+#: doc/classes/Script.xml:18
+msgid "Returns [code]true[/code] if the script can be instanced."
+msgstr ""
+
+#: doc/classes/Script.xml:25
+msgid "Returns the script directly inherited by this script."
+msgstr ""
+
+#: doc/classes/Script.xml:32
+msgid "Returns the script's base type."
+msgstr ""
+
+#: doc/classes/Script.xml:41
+msgid "Returns the default value of the specified property."
+msgstr ""
+
+#: doc/classes/Script.xml:48
+msgid "Returns a dictionary containing constant names and their values."
+msgstr ""
+
+#: doc/classes/Script.xml:55
+msgid "Returns the list of methods in this [Script]."
+msgstr ""
+
+#: doc/classes/Script.xml:62
+msgid "Returns the list of properties in this [Script]."
+msgstr ""
+
+#: doc/classes/Script.xml:69
+msgid "Returns the list of user signals defined in this [Script]."
+msgstr ""
+
+#: doc/classes/Script.xml:78
+msgid ""
+"Returns [code]true[/code] if the script, or a base class, defines a signal "
+"with the given name."
+msgstr ""
+
+#: doc/classes/Script.xml:85
+msgid "Returns [code]true[/code] if the script contains non-empty source code."
+msgstr ""
+
+#: doc/classes/Script.xml:94
+msgid ""
+"Returns [code]true[/code] if [code]base_object[/code] is an instance of this "
+"script."
+msgstr ""
+
+#: doc/classes/Script.xml:101
+msgid ""
+"Returns [code]true[/code] if the script is a tool script. A tool script can "
+"run in the editor."
+msgstr ""
+
+#: doc/classes/Script.xml:110
+msgid "Reloads the script's class implementation. Returns an error code."
+msgstr ""
+
+#: doc/classes/Script.xml:116
+msgid ""
+"The script source code or an empty string if source code is not available. "
+"When set, does not reload the class implementation automatically."
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:4
+msgid "The Editor's popup dialog for creating new [Script] files."
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:7
+msgid ""
+"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.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" dialog.config(\"Node\", \"res://new_node.gd\") # For in-engine types\n"
+" dialog.config(\"\\\"res://base_node.gd\\\"\", \"res://derived_node.gd\") "
+"# For script types\n"
+" dialog.popup_centered()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:30
+msgid "Prefills required fields to configure the ScriptCreateDialog for use."
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:43
+msgid "Emitted when the user clicks the OK button."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:4
+msgid "Godot editor's script editor."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:39
+msgid "Returns a [Script] that is currently active in editor."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:56
+msgid ""
+"Returns an array with all [Script] objects which are currently open in "
+"editor."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:65
+msgid "Goes to the specified line in the current script."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:84
+msgid ""
+"Emitted when user changed active script. Argument is a freshly activated "
+"[Script]."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:91
+msgid ""
+"Emitted when editor is about to close the active script. Argument is a "
+"[Script] that is going to be closed."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:4
+msgid "Base class for scroll bars."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:7
+msgid ""
+"Scrollbars are a [Range]-based [Control], that display a draggable area (the "
+"size of the page). Horizontal ([HScrollBar]) and Vertical ([VScrollBar]) "
+"versions are available."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:15
+msgid ""
+"Overrides the step used when clicking increment and decrement buttons or "
+"when using arrow keys when the [ScrollBar] is focused."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:23
+msgid "Emitted when the scrollbar is being scrolled."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:4
+msgid "A helper node for displaying scrollable elements such as lists."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:7
+msgid ""
+"A ScrollContainer node meant to contain a [Control] child.\n"
+"ScrollContainers will automatically create a scrollbar child ([HScrollBar], "
+"[VScrollBar], or both) when needed and will only draw the Control within the "
+"ScrollContainer area. Scrollbars will automatically be drawn at the right "
+"(for vertical) or bottom (for horizontal) and will enable dragging to move "
+"the viewable Control (and its children) within the ScrollContainer. "
+"Scrollbars will also automatically resize the grabber based on the [member "
+"Control.rect_min_size] of the Control relative to the ScrollContainer.\n"
+"Works great with a [Panel] control. You can set [code]EXPAND[/code] on the "
+"children's size flags, so they will upscale to the ScrollContainer's size if "
+"it's larger (scroll is invisible for the chosen dimension)."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:18
+msgid ""
+"Returns the horizontal scrollbar [HScrollBar] of this [ScrollContainer]."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:25
+msgid "Returns the vertical scrollbar [VScrollBar] of this [ScrollContainer]."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:31
+msgid ""
+"If [code]true[/code], the ScrollContainer will automatically scroll to "
+"focused children (including indirect children) to make sure they are fully "
+"visible."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:37 doc/classes/TextEdit.xml:441
+msgid "The current horizontal scroll value."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:40
+msgid "If [code]true[/code], enables horizontal scrolling."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:43 doc/classes/TextEdit.xml:444
+msgid "The current vertical scroll value."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:46
+msgid "If [code]true[/code], enables vertical scrolling."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:52
+msgid "Emitted when scrolling stops."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:57
+msgid "Emitted when scrolling is started."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:65
+msgid "The background [StyleBox] of the [ScrollContainer]."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:4
+msgid "Segment shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:7
+msgid ""
+"Segment shape for 2D collisions. Consists of two points, [code]a[/code] and "
+"[code]b[/code]."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:15
+msgid "The segment's first point position."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:18
+msgid "The segment's second point position."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:4
+msgid "A synchronization semaphore."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:7
+msgid ""
+"A synchronization semaphore which can be used to synchronize multiple "
+"[Thread]s. Initialized to zero on creation. Be careful to avoid deadlocks. "
+"For a binary version, see [Mutex]."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:17
+msgid "Lowers the [Semaphore], allowing one more thread in."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:24
+msgid ""
+"Like [method wait], but won't block, so if the value is zero, fails "
+"immediately and returns [constant ERR_BUSY]. If non-zero, it returns "
+"[constant OK] to report success."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:31
+msgid "Waits for the [Semaphore], if its value is zero, blocks until non-zero."
+msgstr ""
+
+#: doc/classes/Separator.xml:4
+msgid "Base class for separators."
+msgstr ""
+
+#: doc/classes/Separator.xml:7
+msgid ""
+"Separator is a [Control] used for separating other controls. It's purely a "
+"visual decoration. Horizontal ([HSeparator]) and Vertical ([VSeparator]) "
+"versions are available."
+msgstr ""
+
+#: doc/classes/Shader.xml:4
+msgid "A custom shader program."
+msgstr ""
+
+#: doc/classes/Shader.xml:7
+msgid ""
+"This class allows you to define a custom shader program that can be used by "
+"a [ShaderMaterial]. Shaders allow you to write your own custom behavior for "
+"rendering objects or updating particle information. For a detailed "
+"explanation and usage, please see the tutorials linked below."
+msgstr ""
+
+#: doc/classes/Shader.xml:10 doc/classes/ShaderMaterial.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/shading/index.html"
+msgstr ""
+
+#: doc/classes/Shader.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/shading/your_first_shader/"
+"what_are_shaders.html"
+msgstr ""
+
+#: doc/classes/Shader.xml:20
+msgid ""
+"Returns the texture that is set as default for the specified parameter.\n"
+"[b]Note:[/b] [code]param[/code] must match the name of the uniform in the "
+"code exactly."
+msgstr ""
+
+#: doc/classes/Shader.xml:28
+msgid ""
+"Returns the shader mode for the shader, either [constant MODE_CANVAS_ITEM], "
+"[constant MODE_SPATIAL] or [constant MODE_PARTICLES]."
+msgstr ""
+
+#: doc/classes/Shader.xml:37
+msgid ""
+"Returns [code]true[/code] if the shader has this param defined as a uniform "
+"in its code.\n"
+"[b]Note:[/b] [code]param[/code] must match the name of the uniform in the "
+"code exactly."
+msgstr ""
+
+#: doc/classes/Shader.xml:49
+msgid ""
+"Sets the default texture to be used with a texture uniform. The default is "
+"used if a texture is not set in the [ShaderMaterial].\n"
+"[b]Note:[/b] [code]param[/code] must match the name of the uniform in the "
+"code exactly."
+msgstr ""
+
+#: doc/classes/Shader.xml:56
+msgid ""
+"Returns the shader's code as the user has written it, not the full generated "
+"code used internally."
+msgstr ""
+
+#: doc/classes/Shader.xml:61
+msgid "Mode used to draw all 3D objects."
+msgstr ""
+
+#: doc/classes/Shader.xml:64
+msgid "Mode used to draw all 2D objects."
+msgstr ""
+
+#: doc/classes/Shader.xml:67
+msgid ""
+"Mode used to calculate particle information on a per-particle basis. Not "
+"used for drawing."
+msgstr ""
+
+#: doc/classes/Shader.xml:70
+msgid ""
+"Mode used for drawing skies. Only works with shaders attached to [Sky] "
+"objects."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:4
+msgid "A material that uses a custom [Shader] program."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:7
+msgid ""
+"A material that uses a custom [Shader] program to render either items to "
+"screen or process particles. You can create multiple materials for the same "
+"shader but configure different values for the uniforms defined in the shader."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:19
+msgid ""
+"Returns the current value set for this material of a uniform in the shader."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:28
+msgid ""
+"Returns [code]true[/code] if the property identified by [code]name[/code] "
+"can be reverted to a default value."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:37
+msgid ""
+"Returns the default value of the material property with given [code]name[/"
+"code]."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:48
+msgid ""
+"Changes the value set for this material of a uniform in the shader. [b]Note:"
+"[/b] [code]param[/code] must match the name of the uniform in the code "
+"exactly."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:54
+msgid "The [Shader] program used to render this material."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:4
+msgid "Base class for all 2D shapes."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:7
+msgid "Base class for all 2D shapes. All 2D shape types inherit from this."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:23
+msgid ""
+"Returns [code]true[/code] if this shape is colliding with another.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), and the transformation matrix of that shape "
+"([code]shape_xform[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:37
+msgid ""
+"Returns a list of the points where this shape touches another. If there are "
+"no collisions the list is empty.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), and the transformation matrix of that shape "
+"([code]shape_xform[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:55
+msgid ""
+"Returns whether this shape would collide with another, if a given movement "
+"was applied.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the movement to test on this shape "
+"([code]local_motion[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), the transformation matrix of that shape "
+"([code]shape_xform[/code]), and the movement to test onto the other object "
+"([code]shape_motion[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:73
+msgid ""
+"Returns a list of the points where this shape would touch another, if a "
+"given movement was applied. If there are no collisions the list is empty.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the movement to test on this shape "
+"([code]local_motion[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), the transformation matrix of that shape "
+"([code]shape_xform[/code]), and the movement to test onto the other object "
+"([code]shape_motion[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:80
+msgid "The shape's custom solver bias."
+msgstr ""
+
+#: doc/classes/Shape3D.xml:4
+msgid "Base class for all 3D shape resources."
+msgstr ""
+
+#: doc/classes/Shape3D.xml:7
+msgid ""
+"Base class for all 3D shape resources. Nodes that inherit from this can be "
+"used as shapes for a [PhysicsBody3D] or [Area3D] objects."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:4
+msgid "A shortcut for binding input."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:7
+msgid ""
+"A shortcut for binding input.\n"
+"Shortcuts are commonly used for interacting with a [Control] element from a "
+"[InputEvent]."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:17
+msgid "Returns the shortcut's [InputEvent] as a [String]."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:26
+msgid ""
+"Returns [code]true[/code] if the shortcut's [InputEvent] equals [code]event[/"
+"code]."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:33
+msgid "If [code]true[/code], this shortcut is valid."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:39
+msgid ""
+"The shortcut's [InputEvent].\n"
+"Generally the [InputEvent] is a keyboard key, though it can be any "
+"[InputEvent]."
+msgstr ""
+
+#: doc/classes/Signal.xml:4
+msgid "Class representing a signal defined in an object."
+msgstr ""
+
+#: doc/classes/Signal.xml:19
+msgid ""
+"Creates a new signal named [code]signal_name[/code] in the given object."
+msgstr ""
+
+#: doc/classes/Signal.xml:32
+msgid ""
+"Connects this signal to the specified [Callable], optionally providing binds "
+"and connection flags."
+msgstr ""
+
+#: doc/classes/Signal.xml:41
+msgid "Disconnects this signal from the specified [Callable]."
+msgstr ""
+
+#: doc/classes/Signal.xml:48
+msgid "Emits this signal to all connected objects."
+msgstr ""
+
+#: doc/classes/Signal.xml:55
+msgid "Returns the list of [Callable]s connected to this signal."
+msgstr ""
+
+#: doc/classes/Signal.xml:62
+msgid "Returns the name of this signal."
+msgstr ""
+
+#: doc/classes/Signal.xml:69
+msgid "Returns the object emitting this signal."
+msgstr ""
+
+#: doc/classes/Signal.xml:76
+msgid ""
+"Returns the ID of the object emitting this signal (see [method Object."
+"get_instance_id])."
+msgstr ""
+
+#: doc/classes/Signal.xml:85
+msgid ""
+"Returns [code]true[/code] if the specified [Callable] is connected to this "
+"signal."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:4
+msgid "Skeleton for 2D characters and animated objects."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:7
+msgid ""
+"Skeleton2D parents a hierarchy of [Bone2D] objects. It is a requirement of "
+"[Bone2D]. Skeleton2D holds a reference to the rest pose of its children and "
+"acts as a single point of access to its bones."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html"
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:19
+msgid ""
+"Returns a [Bone2D] from the node hierarchy parented by Skeleton2D. The "
+"object to return is identified by the parameter [code]idx[/code]. Bones are "
+"indexed by descending the node hierarchy from top to bottom, adding the "
+"children of each branch before moving to the next sibling."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:26
+msgid ""
+"Returns the number of [Bone2D] nodes in the node hierarchy parented by "
+"Skeleton2D."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:33
+msgid "Returns the [RID] of a Skeleton2D instance."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:4
+msgid "Skeleton for characters and animated objects."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:7
+msgid ""
+"Skeleton3D provides a hierarchical interface for managing bones, including "
+"pose, rest and animation (see [Animation]). It can also use ragdoll "
+"physics.\n"
+"The overall transform of a bone with respect to the skeleton is determined "
+"by the following hierarchical order: rest pose, custom pose and pose.\n"
+"Note that \"global pose\" below refers to the overall transform of the bone "
+"with respect to skeleton, so it not the actual global/world transform of the "
+"bone."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:20
+msgid ""
+"Adds a bone, with name [code]name[/code]. [method get_bone_count] will "
+"become the bone index."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:31 doc/classes/Skeleton3D.xml:124
+#: doc/classes/Skeleton3D.xml:255
+msgid "[i]Deprecated soon.[/i]"
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:38
+msgid "Clear all the bones in this skeleton."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:53
+msgid "Returns the bone index that matches [code]name[/code] as its name."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:60
+msgid "Returns the amount of bones in the skeleton."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:69
+msgid ""
+"Returns the custom pose of the specified bone. Custom pose is applied on top "
+"of the rest pose."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:78
+msgid ""
+"Returns the overall transform of the specified bone, with respect to the "
+"skeleton. Being relative to the skeleton frame, this is not the actual "
+"\"global\" transform of the bone."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:87
+msgid "Returns the name of the bone at index [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:96
+msgid ""
+"Returns the bone index which is the parent of the bone at [code]bone_idx[/"
+"code]. If -1, then bone has no parent.\n"
+"[b]Note:[/b] The parent bone returned will always be less than "
+"[code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:106
+msgid ""
+"Returns the pose transform of the specified bone. Pose is applied on top of "
+"the custom pose, which is applied on top the rest pose."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:115
+msgid "Returns the rest transform for a bone [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:221
+msgid ""
+"Sets the bone index [code]parent_idx[/code] as the parent of the bone at "
+"[code]bone_idx[/code]. If -1, then bone has no parent.\n"
+"[b]Note:[/b] [code]parent_idx[/code] must be less than [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:233
+msgid "Returns the pose transform for bone [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:244
+msgid "Sets the rest transform for bone [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Sky.xml:4
+msgid "Background that uses a [Material] to draw a sky."
+msgstr ""
+
+#: doc/classes/Sky.xml:7
+msgid ""
+"The [Sky] class uses a [Material] to draw the background and update the "
+"reflection/radiance cubemaps."
+msgstr ""
+
+#: doc/classes/Sky.xml:15
+msgid ""
+"Sets the method for generating the radiance map from the sky. The radiance "
+"map is a cubemap with increasingly blurry versions of the sky corresponding "
+"to different levels of roughness. Radiance maps can be expensive to "
+"calculate. See [enum ProcessMode] for options."
+msgstr ""
+
+#: doc/classes/Sky.xml:18
+msgid ""
+"The [Sky]'s radiance map size. The higher the radiance map size, the more "
+"detailed the lighting from the [Sky] will be.\n"
+"See [enum RadianceSize] constants for values.\n"
+"[b]Note:[/b] Some hardware will have trouble with higher radiance sizes, "
+"especially [constant RADIANCE_SIZE_512] and above. Only use such high values "
+"on high-end hardware."
+msgstr ""
+
+#: doc/classes/Sky.xml:23
+msgid ""
+"[Material] used to draw the background. Can be [PanoramaSkyMaterial], "
+"[ProceduralSkyMaterial], [PhysicalSkyMaterial], or even a [ShaderMaterial] "
+"if you want to use your own custom shader."
+msgstr ""
+
+#: doc/classes/Sky.xml:28
+msgid "Radiance texture size is 32×32 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:31
+msgid "Radiance texture size is 64×64 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:34
+msgid "Radiance texture size is 128×128 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:37
+msgid "Radiance texture size is 256×256 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:40
+msgid "Radiance texture size is 512×512 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:43
+msgid "Radiance texture size is 1024×1024 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:46
+msgid "Radiance texture size is 2048×2048 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:49
+msgid "Represents the size of the [enum RadianceSize] enum."
+msgstr ""
+
+#: doc/classes/Sky.xml:52
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Sky.xml:55
+msgid ""
+"Uses the fast filtering algorithm to process the radiance map. In general "
+"this results in lower quality, but substantially faster run times.\n"
+"[b]Note:[/b] The fast filtering algorithm is limited to 256x256 cubemaps, so "
+"[member radiance_size] must be set to [constant RADIANCE_SIZE_256]."
+msgstr ""
+
+#: doc/classes/Slider.xml:4 doc/classes/Slider.xml:7
+msgid "Base class for GUI sliders."
+msgstr ""
+
+#: doc/classes/Slider.xml:15
+msgid ""
+"If [code]true[/code], the slider can be interacted with. If [code]false[/"
+"code], the value can be changed only by code."
+msgstr ""
+
+#: doc/classes/Slider.xml:19
+msgid "If [code]true[/code], the value can be changed using the mouse wheel."
+msgstr ""
+
+#: doc/classes/Slider.xml:23
+msgid ""
+"Number of ticks displayed on the slider, including border ticks. Ticks are "
+"uniformly-distributed value markers."
+msgstr ""
+
+#: doc/classes/Slider.xml:26
+msgid ""
+"If [code]true[/code], the slider will display ticks for minimum and maximum "
+"values."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:4
+msgid "Piston kind of slider between two bodies in 3D."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:7
+msgid "Slides across the X axis of the pivot object."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:33
+msgid ""
+"The amount of damping of the rotation when the limit is surpassed.\n"
+"A lower damping value allows a rotation initiated by body A to travel to "
+"body B slower."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:40
+msgid ""
+"The amount of restitution of the rotation when the limit is surpassed.\n"
+"Does not affect damping."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:44
+msgid ""
+"A factor applied to the all rotation once the limit is surpassed.\n"
+"Makes all rotation slower when between 0 and 1."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:57 doc/classes/SliderJoint3D.xml:152
+msgid "A factor applied to the all rotation in the limits."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:66 doc/classes/SliderJoint3D.xml:161
+msgid ""
+"A factor applied to the all rotation across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:69
+msgid ""
+"The amount of damping that happens once the limit defined by [member "
+"linear_limit/lower_distance] and [member linear_limit/upper_distance] is "
+"surpassed."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:75
+msgid ""
+"The amount of restitution once the limits are surpassed. The lower, the more "
+"velocity-energy gets lost."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:4
+msgid "A soft mesh physics body."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:7
+msgid ""
+"A deformable physics body. Used to create elastic or deformable objects such "
+"as cloth, rubber, or other flexible materials."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html"
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:83
+msgid ""
+"The physics layers this SoftBody3D is in.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:88
+msgid "The physics layers this SoftBody3D scans for collisions."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:97
+msgid ""
+"[NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:104
+msgid "If [code]true[/code], the [SoftBody3D] will respond to [RayCast3D]s."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:107
+msgid ""
+"Increasing this value will improve the resulting simulation, but can affect "
+"performance. Use with care."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:110
+msgid "The SoftBody3D's mass."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:4 doc/classes/SphereMesh.xml:7
+msgid "Class representing a spherical [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:15
+msgid "Full height of the sphere."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:18
+msgid ""
+"If [code]true[/code], a hemisphere is created rather than a full sphere.\n"
+"[b]Note:[/b] To get a regular hemisphere, the height and radius of the "
+"sphere must be equal."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:22
+msgid "Number of radial segments on the sphere."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:25
+msgid "Radius of sphere."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:28
+msgid "Number of segments along the height of the sphere."
+msgstr ""
+
+#: doc/classes/SphereShape3D.xml:4
+msgid "Sphere shape for 3D collisions."
+msgstr ""
+
+#: doc/classes/SphereShape3D.xml:7
+msgid ""
+"Sphere shape for 3D collisions, which can be set into a [PhysicsBody3D] or "
+"[Area3D]. This shape is useful for modeling sphere-like 3D objects."
+msgstr ""
+
+#: doc/classes/SphereShape3D.xml:15
+msgid "The sphere's radius. The shape's diameter is double the radius."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:4
+msgid "Numerical input text field."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:7
+msgid ""
+"SpinBox is a numerical input text field. It allows entering integers and "
+"floats.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var spin_box = SpinBox.new()\n"
+"add_child(spin_box)\n"
+"var line_edit = spin_box.get_line_edit()\n"
+"line_edit.context_menu_enabled = false\n"
+"spin_box.align = LineEdit.ALIGN_RIGHT\n"
+"[/codeblock]\n"
+"The above code will create a [SpinBox], disable context menu on it and set "
+"the text alignment to right.\n"
+"See [Range] class for more options over the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:26
+msgid "Applies the current value of this [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:33
+msgid ""
+"Returns the [LineEdit] instance from this [SpinBox]. You can use it to "
+"access properties and methods of [LineEdit]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:39
+msgid "Sets the text alignment of the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:42
+msgid ""
+"If [code]true[/code], the [SpinBox] will be editable. Otherwise, it will be "
+"read only."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:45
+msgid ""
+"Adds the specified [code]prefix[/code] string before the numerical value of "
+"the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:48
+msgid ""
+"Adds the specified [code]prefix[/code] string after the numerical value of "
+"the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:55
+msgid "Sets a custom [Texture2D] for up and down arrows of the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:4
+msgid "Container for splitting and adjusting."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:7
+msgid ""
+"Container for splitting two [Control]s vertically or horizontally, with a "
+"grabber that allows adjusting the split offset or ratio."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:16
+msgid ""
+"Clamps the [member split_offset] value to not go outside the currently "
+"possible minimal and maximum values."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:22
+msgid ""
+"If [code]true[/code], the area of the first [Control] will be collapsed and "
+"the dragger will be disabled."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:25
+msgid ""
+"Determines the dragger's visibility. See [enum DraggerVisibility] for "
+"details."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:28
+msgid ""
+"The initial offset of the splitting between the two [Control]s, with "
+"[code]0[/code] being at the end of the first [Control]."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:36
+msgid "Emitted when the dragger is dragged by user."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:42
+msgid "The split dragger is visible when the cursor hovers it."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:45
+msgid "The split dragger is never visible."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:48
+msgid "The split dragger is never visible and its space collapsed."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:4
+msgid "A spotlight, such as a reflector spotlight or a lantern."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:7
+msgid ""
+"A Spotlight is a type of [Light3D] node that emits lights in a specific "
+"direction, in the shape of a cone. The light is attenuated through the "
+"distance. This attenuation can be configured by changing the energy, radius "
+"and attenuation parameters of [Light3D]."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:16
+msgid "The spotlight's angle in degrees."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:19
+msgid "The spotlight's angular attenuation curve."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:22
+msgid "The spotlight's light energy attenuation curve."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:25
+msgid "The maximal range that can be reached by the spotlight."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:4
+msgid "A helper node, mostly used in 3rd person cameras."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:7
+msgid ""
+"The SpringArm3D node is a node that casts a ray (or collision shape) along "
+"its z axis and moves all its direct children to the collision point, minus a "
+"margin.\n"
+"The most common use case for this is to make a 3rd person camera that reacts "
+"to collisions in the environment.\n"
+"The SpringArm3D will either cast a ray, or if a shape is given, it will cast "
+"the shape in the direction of its z axis.\n"
+"If you use the SpringArm3D as a camera controller for your player, you might "
+"need to exclude the player's collider from the SpringArm3D's collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:21
+msgid ""
+"Adds the [PhysicsBody3D] object with the given [RID] to the list of "
+"[PhysicsBody3D] objects excluded from the collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:28
+msgid ""
+"Clears the list of [PhysicsBody3D] objects excluded from the collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:35
+msgid ""
+"Returns the proportion between the current arm length (after checking for "
+"collisions) and the [member spring_length]. Ranges from 0 to 1."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:44
+msgid ""
+"Removes the given [RID] from the list of [PhysicsBody3D] objects excluded "
+"from the collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:50
+msgid "The layers against which the collision check shall be done."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:53
+msgid ""
+"When the collision check is made, a candidate length for the SpringArm3D is "
+"given.\n"
+"The margin is then subtracted to this length and the translation is applied "
+"to the child objects of the SpringArm3D.\n"
+"This margin is useful for when the SpringArm3D has a [Camera3D] as a child "
+"node: without the margin, the [Camera3D] would be placed on the exact point "
+"of collision, while with the margin the [Camera3D] would be placed close to "
+"the point of collision."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:58
+msgid ""
+"The [Shape3D] to use for the SpringArm3D.\n"
+"When the shape is set, the SpringArm3D will cast the [Shape3D] on its z axis "
+"instead of performing a ray cast."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:62
+msgid ""
+"The maximum extent of the SpringArm3D. This is used as a length for both the "
+"ray and the shape cast used internally to calculate the desired position of "
+"the SpringArm3D's child nodes.\n"
+"To know more about how to perform a shape cast or a ray cast, please consult "
+"the [PhysicsDirectSpaceState3D] documentation."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:4
+msgid "General-purpose sprite node."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:7
+msgid ""
+"A node that displays a 2D texture. The texture displayed can be a region "
+"from a larger atlas texture, or a frame from a sprite sheet animation."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:16
+msgid ""
+"Returns a [Rect2] representing the Sprite2D's boundary in local coordinates. "
+"Can be used to detect if the Sprite2D was clicked. Example:\n"
+"[codeblock]\n"
+"func _input(event):\n"
+" if event is InputEventMouseButton and event.pressed and event."
+"button_index == BUTTON_LEFT:\n"
+" if get_rect().has_point(to_local(event.position)):\n"
+" print(\"A click!\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:31
+msgid ""
+"Returns [code]true[/code], if the pixel at the given position is opaque and "
+"[code]false[/code] in other case.\n"
+"[b]Note:[/b] It also returns [code]false[/code], if the sprite's texture is "
+"[code]null[/code] or if the given position is invalid."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:38
+msgid "If [code]true[/code], texture is centered."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:47 doc/classes/Sprite3D.xml:16
+msgid ""
+"Current frame to display from sprite sheet. [member vframes] or [member "
+"hframes] must be greater than 1."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:50 doc/classes/Sprite3D.xml:19
+msgid ""
+"Coordinates of the frame to display from sprite sheet. This is as an alias "
+"for the [member frame] property. [member vframes] or [member hframes] must "
+"be greater than 1."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:53 doc/classes/Sprite3D.xml:22
+msgid "The number of columns in the sprite sheet."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:56
+msgid "The normal map gives depth to the Sprite2D."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:62
+msgid ""
+"If [code]true[/code], texture is cut from a larger atlas texture. See "
+"[member region_rect]."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:65
+msgid "If [code]true[/code], the outermost pixels get blurred out."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:68 doc/classes/Sprite3D.xml:28
+msgid ""
+"The region of the atlas texture to display. [member region_enabled] must be "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:71
+msgid "Strength of the specular light effect of this [Sprite2D]."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:77
+msgid "The specular map is used for more control on the shininess effect."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:80 doc/classes/Sprite3D.xml:31
+msgid "[Texture2D] object to draw."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:83 doc/classes/Sprite3D.xml:34
+msgid "The number of rows in the sprite sheet."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:89 doc/classes/Sprite3D.xml:40
+msgid "Emitted when the [member frame] changes."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:94
+msgid "Emitted when the [member texture] changes."
+msgstr ""
+
+#: doc/classes/Sprite3D.xml:4
+msgid "2D sprite node in a 3D world."
+msgstr ""
+
+#: doc/classes/Sprite3D.xml:7
+msgid ""
+"A node that displays a 2D texture in a 3D environment. The texture displayed "
+"can be a region from a larger atlas texture, or a frame from a sprite sheet "
+"animation.\n"
+"[b]Note:[/b] There are [url=https://github.com/godotengine/godot/"
+"issues/20855]known performance issues[/url] when using [Sprite3D]. Consider "
+"using a [MeshInstance3D] with a [QuadMesh] as the mesh instead. You can "
+"still have billboarding by enabling billboard properties in the QuadMesh's "
+"[StandardMaterial3D]."
+msgstr ""
+
+#: doc/classes/Sprite3D.xml:25
+msgid ""
+"If [code]true[/code], texture will be cut from a larger atlas texture. See "
+"[member region_rect]."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:4
+msgid "2D sprite node in 3D environment."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:7
+msgid "A node that displays 2D texture information in a 3D environment."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:31
+msgid "Returns the rectangle representing this sprite."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:42
+msgid "If [code]true[/code], the specified flag will be enabled."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:50
+msgid "The direction in which the front of the texture faces."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:58
+msgid ""
+"If [code]true[/code], texture can be seen from the back as well, if "
+"[code]false[/code], it is invisible when looking at it from behind."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:67
+msgid ""
+"A color value that gets multiplied on, could be used for mood-coloring or to "
+"simulate the color of light."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:73
+msgid ""
+"The objects visibility on a scale from [code]0[/code] fully invisible to "
+"[code]1[/code] fully visible."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:76
+msgid "The size of one pixel's width on the sprite to scale it in 3D."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:79
+msgid ""
+"If [code]true[/code], the [Light3D] in the [Environment] has effects on the "
+"sprite."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:82
+msgid ""
+"If [code]true[/code], the texture's transparency and the opacity are used to "
+"make those parts of the sprite invisible."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:87
+msgid ""
+"If set, the texture's transparency and the opacity are used to make those "
+"parts of the sprite invisible."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:90
+msgid "If set, lights in the environment affect the sprite."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:93
+msgid ""
+"If set, texture can be seen from the back as well, if not, it is invisible "
+"when looking at it from behind."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:96
+msgid "Represents the size of the [enum DrawFlags] enum."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:4
+msgid "Sprite frame library for AnimatedSprite2D."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:7
+msgid ""
+"Sprite frame library for [AnimatedSprite2D]. Contains frames and animation "
+"data for playback."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:18
+msgid "Adds a new animation to the library."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:31
+msgid "Adds a frame to the given animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:40
+msgid "Removes all frames from the given animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:47
+msgid "Removes all animations. A \"default\" animation will be created."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:56
+msgid "If [code]true[/code], the given animation will loop."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:63
+msgid ""
+"Returns an array containing the names associated to each animation. Values "
+"are placed in alphabetical order."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:72 doc/classes/SpriteFrames.xml:154
+msgid "The animation's speed in frames per second."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:83
+msgid "Returns the animation's selected frame."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:92
+msgid "Returns the number of frames in the animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:101
+msgid "If [code]true[/code], the named animation exists."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:110
+msgid "Removes the given animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:121
+msgid "Removes the animation's selected frame."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:132
+msgid "Changes the animation's name to [code]newname[/code]."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:143
+msgid "If [code]true[/code], the animation will loop."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:167
+msgid "Sets the texture of the given frame."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:173
+msgid "Compatibility property, always equals to an empty array."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:4
+msgid "Static body for 2D physics."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:7
+msgid ""
+"Static body for 2D physics. A StaticBody2D is a body that is not intended to "
+"move. It is ideal for implementing objects in the environment, such as walls "
+"or platforms.\n"
+"Additionally, a constant linear or angular velocity can be set for the "
+"static body, which will affect colliding bodies as if it were moving (for "
+"example, a conveyor belt)."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:16
+msgid ""
+"The body's constant angular velocity. This does not rotate the body, but "
+"affects colliding bodies, as if it were rotating."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:19
+msgid ""
+"The body's constant linear velocity. This does not move the body, but "
+"affects colliding bodies, as if it were moving."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:4
+msgid "Static body for 3D physics."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:7
+msgid ""
+"Static body for 3D physics. A static body is a simple body that is not "
+"intended to move. In contrast to [RigidBody3D], they don't consume any CPU "
+"resources as long as they don't move.\n"
+"Additionally, a constant linear or angular velocity can be set for the "
+"static body, so even if it doesn't move, it affects other bodies as if it "
+"was moving (this is useful for simulating conveyor belts or conveyor wheels)."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:16
+msgid ""
+"The body's constant angular velocity. This does not rotate the body, but "
+"affects other bodies that touch it, as if it was in a state of rotation."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:19
+msgid ""
+"The body's constant linear velocity. This does not move the body, but "
+"affects other bodies that touch it, as if it was in a state of movement."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:4
+msgid "Abstraction and base class for stream-based protocols."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:7
+msgid ""
+"StreamPeer is an abstraction and base class for stream-based protocols (such "
+"as TCP or UNIX sockets). It provides an API for sending and receiving data "
+"through streams as raw data or strings."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:16
+msgid "Gets a signed 16-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:23
+msgid "Gets a signed 32-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:30
+msgid "Gets a signed 64-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:37
+msgid "Gets a signed byte from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:44
+msgid "Returns the amount of bytes this [StreamPeer] has available."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:53
+msgid ""
+"Returns a chunk data with the received bytes. The amount of bytes to be "
+"received can be requested in the [code]bytes[/code] argument. If not enough "
+"bytes are available, the function will block until the desired amount is "
+"received. This function returns two values, an [enum @GlobalScope.Error] "
+"code and a data array."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:60
+msgid "Gets a double-precision float from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:67
+msgid "Gets a single-precision float from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:76
+msgid ""
+"Returns a chunk data with the received bytes. The amount of bytes to be "
+"received can be requested in the \"bytes\" argument. If not enough bytes are "
+"available, the function will return how many were actually received. This "
+"function returns two values, an [enum @GlobalScope.Error] code, and a data "
+"array."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:85
+msgid ""
+"Gets a string with byte-length [code]bytes[/code] from the stream. If "
+"[code]bytes[/code] is negative (default) the length will be read from the "
+"stream using the reverse process of [method put_string]."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:92
+msgid "Gets an unsigned 16-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:99
+msgid "Gets an unsigned 32-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:106
+msgid "Gets an unsigned 64-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:113
+msgid "Gets an unsigned byte from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:122
+msgid ""
+"Gets an UTF-8 string with byte-length [code]bytes[/code] from the stream "
+"(this decodes the string sent as UTF-8). If [code]bytes[/code] is negative "
+"(default) the length will be read from the stream using the reverse process "
+"of [method put_utf8_string]."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:131
+msgid ""
+"Gets a Variant from the stream. If [code]allow_objects[/code] is [code]true[/"
+"code], decoding objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:141
+msgid "Puts a signed 16-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:150
+msgid "Puts a signed 32-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:159
+msgid "Puts a signed 64-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:168
+msgid "Puts a signed byte into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:177
+msgid ""
+"Sends a chunk of data through the connection, blocking if necessary until "
+"the data is done sending. This function returns an [enum @GlobalScope.Error] "
+"code."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:186
+msgid "Puts a double-precision float into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:195
+msgid "Puts a single-precision float into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:204
+msgid ""
+"Sends a chunk of data through the connection. If all the data could not be "
+"sent at once, only part of it will. This function returns two values, an "
+"[enum @GlobalScope.Error] code and an integer, describing how much data was "
+"actually sent."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:213
+msgid ""
+"Puts a zero-terminated ASCII string into the stream prepended by a 32-bit "
+"unsigned integer representing its size.\n"
+"Note: To put an ASCII string without prepending its size, you can use "
+"[method put_data]:\n"
+"[codeblock]\n"
+"put_data(\"Hello world\".to_ascii())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:226
+msgid "Puts an unsigned 16-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:235
+msgid "Puts an unsigned 32-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:244
+msgid "Puts an unsigned 64-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:253
+msgid "Puts an unsigned byte into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:262
+msgid ""
+"Puts a zero-terminated UTF-8 string into the stream prepended by a 32 bits "
+"unsigned integer representing its size.\n"
+"Note: To put an UTF-8 string without prepending its size, you can use "
+"[method put_data]:\n"
+"[codeblock]\n"
+"put_data(\"Hello world\".to_utf8())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:277
+msgid ""
+"Puts a Variant into the stream. If [code]full_objects[/code] is [code]true[/"
+"code] encoding objects is allowed (and can potentially include code)."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:283
+msgid ""
+"If [code]true[/code], this [StreamPeer] will using big-endian format for "
+"encoding and decoding."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:4
+msgid "SSL stream peer."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:7
+msgid ""
+"SSL stream peer. This object can be used to connect to an SSL server or "
+"accept a single SSL client connection."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:25
+msgid ""
+"Accepts a peer connection as a server using the given [code]private_key[/"
+"code] and providing the given [code]certificate[/code] to the client. You "
+"can pass the optional [code]chain[/code] parameter to provide additional CA "
+"chain information along with the certificate."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:40
+msgid ""
+"Connects to a peer using an underlying [StreamPeer] [code]stream[/code]. If "
+"[code]validate_certs[/code] is [code]true[/code], [StreamPeerSSL] will "
+"validate that the certificate presented by the peer matches the "
+"[code]for_hostname[/code].\n"
+"[b]Note:[/b] Specifying a custom [code]valid_certificate[/code] is not "
+"supported in HTML5 exports due to browsers restrictions."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:48 doc/classes/StreamPeerTCP.xml:27
+msgid "Disconnects from host."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:62
+msgid ""
+"Poll the connection to check for incoming bytes. Call this right before "
+"[method StreamPeer.get_available_bytes] for it to work properly."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:72
+msgid "A status representing a [StreamPeerSSL] that is disconnected."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:75
+msgid "A status representing a [StreamPeerSSL] during handshaking."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:78
+msgid "A status representing a [StreamPeerSSL] that is connected to a host."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:81
+msgid "A status representing a [StreamPeerSSL] in error state."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:84
+msgid ""
+"An error status that shows a mismatch in the SSL certificate domain "
+"presented by the host and the domain requested for validation."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:4
+msgid "TCP stream peer."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:7
+msgid ""
+"TCP stream peer. This object can be used to connect to TCP servers, or also "
+"is returned by a TCP server."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:20
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:34
+msgid "Returns the IP of this peer."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:41
+msgid "Returns the port of this peer."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:48
+msgid "Returns the status of the connection, see [enum Status]."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:55
+msgid ""
+"Returns [code]true[/code] if this peer is currently connected to a host, "
+"[code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:64
+msgid ""
+"Disables Nagle's algorithm to improve latency for small packets.\n"
+"[b]Note:[/b] For applications that send large packets or need to transfer a "
+"lot of data, this can decrease the total available bandwidth."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:71
+msgid ""
+"The initial status of the [StreamPeerTCP]. This is also the status after "
+"disconnecting."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:74
+msgid "A status representing a [StreamPeerTCP] that is connecting to a host."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:77
+msgid "A status representing a [StreamPeerTCP] that is connected to a host."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:80
+msgid "A status representing a [StreamPeerTCP] in error state."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:4
+msgid "A [code].stex[/code] texture."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:7
+msgid "A texture that is loaded from a [code].stex[/code] file."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:18
+msgid "Loads the texture from the given path."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:24
+msgid "The StreamTexture's file path to a [code].stex[/code] file."
+msgstr ""
+
+#: doc/classes/String.xml:4
+msgid "Built-in string class."
+msgstr ""
+
+#: doc/classes/String.xml:7
+msgid ""
+"This is the built-in string class (and the one used by GDScript). It "
+"supports Unicode and provides all necessary means for string handling. "
+"Strings are reference counted and use a copy-on-write approach, so passing "
+"them around is cheap in resources."
+msgstr ""
+
+#: doc/classes/String.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/"
+"gdscript_format_string.html"
+msgstr ""
+
+#: doc/classes/String.xml:19
+msgid "Constructs a new String from the given [bool]."
+msgstr ""
+
+#: doc/classes/String.xml:28
+msgid "Constructs a new String from the given [int]."
+msgstr ""
+
+#: doc/classes/String.xml:37
+msgid "Constructs a new String from the given [float]."
+msgstr ""
+
+#: doc/classes/String.xml:46
+msgid "Constructs a new String from the given [Vector2]."
+msgstr ""
+
+#: doc/classes/String.xml:55
+msgid "Constructs a new String from the given [Vector2i]."
+msgstr ""
+
+#: doc/classes/String.xml:64
+msgid "Constructs a new String from the given [Rect2]."
+msgstr ""
+
+#: doc/classes/String.xml:73
+msgid "Constructs a new String from the given [Rect2i]."
+msgstr ""
+
+#: doc/classes/String.xml:82
+msgid "Constructs a new String from the given [Vector3]."
+msgstr ""
+
+#: doc/classes/String.xml:91
+msgid "Constructs a new String from the given [Vector3i]."
+msgstr ""
+
+#: doc/classes/String.xml:100
+msgid "Constructs a new String from the given [Transform2D]."
+msgstr ""
+
+#: doc/classes/String.xml:109
+msgid "Constructs a new String from the given [Plane]."
+msgstr ""
+
+#: doc/classes/String.xml:118
+msgid "Constructs a new String from the given [Quat]."
+msgstr ""
+
+#: doc/classes/String.xml:127
+msgid "Constructs a new String from the given [AABB]."
+msgstr ""
+
+#: doc/classes/String.xml:136
+msgid "Constructs a new String from the given [Basis]."
+msgstr ""
+
+#: doc/classes/String.xml:145
+msgid "Constructs a new String from the given [Transform]."
+msgstr ""
+
+#: doc/classes/String.xml:154
+msgid "Constructs a new String from the given [Color]."
+msgstr ""
+
+#: doc/classes/String.xml:163
+msgid "Constructs a new String from the given [StringName]."
+msgstr ""
+
+#: doc/classes/String.xml:172
+msgid "Constructs a new String from the given [NodePath]."
+msgstr ""
+
+#: doc/classes/String.xml:181
+msgid "Constructs a new String from the given [RID]."
+msgstr ""
+
+#: doc/classes/String.xml:190
+msgid "Constructs a new String from the given [Callable]."
+msgstr ""
+
+#: doc/classes/String.xml:199
+msgid "Constructs a new String from the given [Signal]."
+msgstr ""
+
+#: doc/classes/String.xml:208
+msgid "Constructs a new String from the given [Dictionary]."
+msgstr ""
+
+#: doc/classes/String.xml:217
+msgid "Constructs a new String from the given [Array]."
+msgstr ""
+
+#: doc/classes/String.xml:226
+msgid "Constructs a new String from the given [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/String.xml:235
+msgid "Constructs a new String from the given [PackedInt32Array]."
+msgstr ""
+
+#: doc/classes/String.xml:244
+msgid "Constructs a new String from the given [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/String.xml:253
+msgid "Constructs a new String from the given [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/String.xml:262
+msgid "Constructs a new String from the given [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/String.xml:271
+msgid "Constructs a new String from the given [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/String.xml:280
+msgid "Constructs a new String from the given [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/String.xml:289
+msgid "Constructs a new String from the given [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/String.xml:298
+msgid "Constructs a new String from the given [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/String.xml:307
+msgid "Returns [code]true[/code] if the string begins with the given string."
+msgstr ""
+
+#: doc/classes/String.xml:314
+msgid "Returns the bigrams (pairs of consecutive letters) of this string."
+msgstr ""
+
+#: doc/classes/String.xml:321
+msgid ""
+"Returns a copy of the string with special characters escaped using the C "
+"language standard."
+msgstr ""
+
+#: doc/classes/String.xml:328
+msgid ""
+"Returns a copy of the string with escaped characters replaced by their "
+"meanings according to the C language standard."
+msgstr ""
+
+#: doc/classes/String.xml:335
+msgid ""
+"Changes the case of some letters. Replaces underscores with spaces, converts "
+"all letters to lowercase, then capitalizes first and every letter following "
+"the space character. For [code]capitalize camelCase mixed_with_underscores[/"
+"code], it will return [code]Capitalize Camelcase Mixed With Underscores[/"
+"code]."
+msgstr ""
+
+#: doc/classes/String.xml:344
+msgid ""
+"Performs a case-sensitive comparison to another string. Returns [code]-1[/"
+"code] if less than, [code]+1[/code] if greater than, or [code]0[/code] if "
+"equal."
+msgstr ""
+
+#: doc/classes/String.xml:357
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:370
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:377
+msgid ""
+"Returns a copy of the string with indentation (leading tabs and spaces) "
+"removed."
+msgstr ""
+
+#: doc/classes/String.xml:384
+msgid "Returns [code]true[/code] if the string is empty."
+msgstr ""
+
+#: doc/classes/String.xml:393
+msgid "Returns [code]true[/code] if the string ends with the given string."
+msgstr ""
+
+#: doc/classes/String.xml:404
+msgid ""
+"Erases [code]chars[/code] characters from the string starting from "
+"[code]position[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:415
+msgid ""
+"Finds the first occurrence of a substring. Returns the starting position of "
+"the substring or -1 if not found. Optionally, the initial search index can "
+"be passed."
+msgstr ""
+
+#: doc/classes/String.xml:424
+msgid ""
+"Finds the last occurrence of a substring. Returns the starting position of "
+"the substring or -1 if not found."
+msgstr ""
+
+#: doc/classes/String.xml:435
+msgid ""
+"Finds the first occurrence of a substring, ignoring case. Returns the "
+"starting position of the substring or -1 if not found. Optionally, the "
+"initial search index can be passed."
+msgstr ""
+
+#: doc/classes/String.xml:446
+msgid ""
+"Formats the string by replacing all occurrences of [code]placeholder[/code] "
+"with [code]values[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:453
+msgid "If the string is a valid file path, returns the base directory name."
+msgstr ""
+
+#: doc/classes/String.xml:460
+msgid ""
+"If the string is a valid file path, returns the full file path without the "
+"extension."
+msgstr ""
+
+#: doc/classes/String.xml:467
+msgid "If the string is a valid file path, returns the extension."
+msgstr ""
+
+#: doc/classes/String.xml:474
+msgid "If the string is a valid file path, returns the filename."
+msgstr ""
+
+#: doc/classes/String.xml:481
+msgid "Hashes the string and returns a 32-bit integer."
+msgstr ""
+
+#: doc/classes/String.xml:488
+msgid ""
+"Converts a string containing a hexadecimal number into an integer. "
+"Hexadecimal strings are expected to be prefixed with \"[code]0x[/code]\" "
+"otherwise [code]0[/code] is returned.\n"
+"[codeblock]\n"
+"print(\"0xff\".hex_to_int()) # Print \"255\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:498
+msgid ""
+"Escapes (encodes) a string to URL friendly format. Also referred to as 'URL "
+"encode'.\n"
+"[codeblock]\n"
+"print(\"https://example.org/?escaped=\" + \"Godot Engine:'docs'\"."
+"http_escape())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:508
+msgid ""
+"Unescapes (decodes) a string in URL encoded format. Also referred to as 'URL "
+"decode'.\n"
+"[codeblock]\n"
+"print(\"https://example.org/?escaped=\" + \"Godot%20Engine%3A%27docs%27\"."
+"http_unescape())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:520
+msgid ""
+"Converts [code]size[/code] represented as number of bytes to human-readable "
+"format using internationalized set of data size units, namely: B, KiB, MiB, "
+"GiB, TiB, PiB, EiB. Note that the next smallest unit is picked automatically "
+"to hold at most 1024 units.\n"
+"[codeblock]\n"
+"var bytes = 133790307\n"
+"var size = String.humanize_size(bytes)\n"
+"print(size) # prints \"127.5 MiB\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:536
+msgid ""
+"Returns a copy of the string with the substring [code]what[/code] inserted "
+"at the given position."
+msgstr ""
+
+#: doc/classes/String.xml:543
+msgid ""
+"If the string is a path to a file or directory, returns [code]true[/code] if "
+"the path is absolute."
+msgstr ""
+
+#: doc/classes/String.xml:550
+msgid ""
+"If the string is a path to a file or directory, returns [code]true[/code] if "
+"the path is relative."
+msgstr ""
+
+#: doc/classes/String.xml:559
+msgid ""
+"Returns [code]true[/code] if this string is a subsequence of the given "
+"string."
+msgstr ""
+
+#: doc/classes/String.xml:568
+msgid ""
+"Returns [code]true[/code] if this string is a subsequence of the given "
+"string, without considering case."
+msgstr ""
+
+#: doc/classes/String.xml:575
+msgid ""
+"Returns [code]true[/code] if this string is free from characters that aren't "
+"allowed in file names, those being:\n"
+"[code]: / \\ ? * \" | % < >[/code]"
+msgstr ""
+
+#: doc/classes/String.xml:583
+msgid "Returns [code]true[/code] if this string contains a valid float."
+msgstr ""
+
+#: doc/classes/String.xml:592
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/String.xml:599
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/String.xml:606
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:613
+msgid "Returns [code]true[/code] if this string contains a valid integer."
+msgstr ""
+
+#: doc/classes/String.xml:620
+msgid "Returns [code]true[/code] if this string contains a valid IP address."
+msgstr ""
+
+#: doc/classes/String.xml:627
+msgid ""
+"Returns a copy of the string with special characters escaped using the JSON "
+"standard."
+msgstr ""
+
+#: doc/classes/String.xml:636
+msgid "Returns a number of characters from the left of the string."
+msgstr ""
+
+#: doc/classes/String.xml:643
+msgid "Returns the string's amount of characters."
+msgstr ""
+
+#: doc/classes/String.xml:652
+msgid "Returns a copy of the string with characters removed from the left."
+msgstr ""
+
+#: doc/classes/String.xml:661
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/String.xml:670
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/String.xml:677
+msgid "Returns the MD5 hash of the string as an array of bytes."
+msgstr ""
+
+#: doc/classes/String.xml:684
+msgid "Returns the MD5 hash of the string as a string."
+msgstr ""
+
+#: doc/classes/String.xml:693
+msgid ""
+"Performs a case-insensitive comparison to another string. Returns [code]-1[/"
+"code] if less than, [code]+1[/code] if greater than, or [code]0[/code] if "
+"equal."
+msgstr ""
+
+#: doc/classes/String.xml:702
+msgid "Returns the character code at position [code]at[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:711
+msgid ""
+"Formats a number to have an exact number of [code]digits[/code] after the "
+"decimal point."
+msgstr ""
+
+#: doc/classes/String.xml:720
+msgid ""
+"Formats a number to have an exact number of [code]digits[/code] before the "
+"decimal point."
+msgstr ""
+
+#: doc/classes/String.xml:727
+msgid "Decode a percent-encoded string. See [method percent_encode]."
+msgstr ""
+
+#: doc/classes/String.xml:734
+msgid ""
+"Percent-encodes a string. Encodes parameters in a URL when sending a HTTP "
+"GET request (and bodies of form-urlencoded POST requests)."
+msgstr ""
+
+#: doc/classes/String.xml:743
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/String.xml:752
+msgid ""
+"Returns original string repeated a number of times. The number of "
+"repetitions is given by the argument."
+msgstr ""
+
+#: doc/classes/String.xml:763
+msgid ""
+"Replaces occurrences of a case-sensitive substring with the given one inside "
+"the string."
+msgstr ""
+
+#: doc/classes/String.xml:774
+msgid ""
+"Replaces occurrences of a case-insensitive substring with the given one "
+"inside the string."
+msgstr ""
+
+#: doc/classes/String.xml:785
+msgid ""
+"Performs a case-sensitive search for a substring, but starts from the end of "
+"the string instead of the beginning."
+msgstr ""
+
+#: doc/classes/String.xml:796
+msgid ""
+"Performs a case-insensitive search for a substring, but starts from the end "
+"of the string instead of the beginning."
+msgstr ""
+
+#: doc/classes/String.xml:805
+msgid "Returns the right side of the string from a given position."
+msgstr ""
+
+#: doc/classes/String.xml:818
+msgid ""
+"Splits the string by a [code]delimiter[/code] string and returns an array of "
+"the substrings, starting from right.\n"
+"The splits in the returned array are sorted in the same order as the "
+"original string, from left to right.\n"
+"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].\n"
+"Example:\n"
+"[codeblock]\n"
+"var some_string = \"One,Two,Three,Four\"\n"
+"var some_array = some_string.rsplit(\",\", true, 1)\n"
+"print(some_array.size()) # Prints 2\n"
+"print(some_array[0]) # Prints \"Four\"\n"
+"print(some_array[1]) # Prints \"Three,Two,One\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:837
+msgid "Returns a copy of the string with characters removed from the right."
+msgstr ""
+
+#: doc/classes/String.xml:844
+msgid "Returns the SHA-1 hash of the string as an array of bytes."
+msgstr ""
+
+#: doc/classes/String.xml:851
+msgid "Returns the SHA-1 hash of the string as a string."
+msgstr ""
+
+#: doc/classes/String.xml:858
+msgid "Returns the SHA-256 hash of the string as an array of bytes."
+msgstr ""
+
+#: doc/classes/String.xml:865
+msgid "Returns the SHA-256 hash of the string as a string."
+msgstr ""
+
+#: doc/classes/String.xml:874
+msgid ""
+"Returns the similarity index of the text compared to this string. 1 means "
+"totally similar and 0 means totally dissimilar."
+msgstr ""
+
+#: doc/classes/String.xml:887
+msgid ""
+"Splits the string by a [code]delimiter[/code] string and returns an array of "
+"the substrings.\n"
+"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 0 means that "
+"all items are split.\n"
+"Example:\n"
+"[codeblock]\n"
+"var some_string = \"One,Two,Three,Four\"\n"
+"var some_array = some_string.split(\",\", true, 1)\n"
+"print(some_array.size()) # Prints 2\n"
+"print(some_array[0]) # Prints \"One\"\n"
+"print(some_array[1]) # Prints \"Two,Three,Four\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:907
+msgid ""
+"Splits the string in floats by using a delimiter string and returns an array "
+"of the substrings.\n"
+"For example, [code]\"1,2.5,3\"[/code] will return [code][1,2.5,3][/code] if "
+"split by [code]\",\"[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:919
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:926
+msgid ""
+"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 (< "
+"32), such as tabulation ([code]\\t[/code] in C) and newline ([code]\\n[/"
+"code] and [code]\\r[/code]) characters, but not spaces."
+msgstr ""
+
+#: doc/classes/String.xml:937
+msgid ""
+"Returns part of the string from the position [code]from[/code] with length "
+"[code]len[/code]. Argument [code]len[/code] is optional and using -1 will "
+"return remaining characters from given position."
+msgstr ""
+
+#: doc/classes/String.xml:944
+msgid ""
+"Converts the String (which is a character array) to [PackedByteArray] (which "
+"is an array of bytes). The conversion is faster compared to [method "
+"to_utf8], as this method assumes that all the characters in the String are "
+"ASCII characters."
+msgstr ""
+
+#: doc/classes/String.xml:951
+msgid ""
+"Converts a string containing a decimal number into a [code]float[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:958
+msgid ""
+"Converts a string containing an integer number into an [code]int[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:965
+msgid "Returns the string converted to lowercase."
+msgstr ""
+
+#: doc/classes/String.xml:972
+msgid "Returns the string converted to uppercase."
+msgstr ""
+
+#: doc/classes/String.xml:979
+msgid ""
+"Converts the String (which is an array of characters) to [PackedByteArray] "
+"(which is an array of bytes). The conversion is a bit slower than [method "
+"to_ascii], but supports all UTF-8 characters. Therefore, you should prefer "
+"this function over [method to_ascii]."
+msgstr ""
+
+#: doc/classes/String.xml:988
+msgid ""
+"Removes a given string from the start if it starts with it or leaves the "
+"string unchanged."
+msgstr ""
+
+#: doc/classes/String.xml:997
+msgid ""
+"Removes a given string from the end if it ends with it or leaves the string "
+"unchanged."
+msgstr ""
+
+#: doc/classes/String.xml:1004
+msgid ""
+"Returns a copy of the string with special characters escaped using the XML "
+"standard."
+msgstr ""
+
+#: doc/classes/String.xml:1011
+msgid ""
+"Returns a copy of the string with escaped characters replaced by their "
+"meanings according to the XML standard."
+msgstr ""
+
+#: doc/classes/StringName.xml:4
+msgid "An optimized string type for unique names."
+msgstr ""
+
+#: doc/classes/StringName.xml:7
+msgid ""
+"[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."
+msgstr ""
+
+#: doc/classes/StringName.xml:18
+msgid "Creates a new [StringName] from the given [String]."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:4
+msgid "Base class for drawing stylized boxes for the UI."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:7
+msgid ""
+"StyleBox is [Resource] that provides an abstract base class for drawing "
+"stylized boxes for the UI. StyleBoxes are used for drawing the styles of "
+"buttons, line edit backgrounds, tree backgrounds, etc. and also for testing "
+"a transparency mask for pointer signals. If mask test fails on a StyleBox "
+"assigned as mask to a control, clicks and motion signals will go through it "
+"to the one below."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:20
+msgid ""
+"Draws this stylebox using a [CanvasItem] with given [RID].\n"
+"You can get a [RID] value using [method Object.get_instance_id] on a "
+"[CanvasItem]-derived node."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:28
+msgid "Returns the size of this [StyleBox] without the margins."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:35
+msgid ""
+"Returns the [CanvasItem] that handles its [constant CanvasItem."
+"NOTIFICATION_DRAW] or [method CanvasItem._draw] callback at this moment."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:44
+msgid "Returns the default value of the specified [enum Margin]."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:53
+msgid ""
+"Returns the content margin offset for the specified [enum Margin].\n"
+"Positive values reduce size inwards, unlike [Control]'s margin values."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:61
+msgid "Returns the minimum size that this stylebox can be shrunk to."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:68
+msgid ""
+"Returns the \"offset\" of a stylebox. This helper function returns a value "
+"equivalent to [code]Vector2(style.get_margin(MARGIN_LEFT), style."
+"get_margin(MARGIN_TOP))[/code]."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:79
+msgid ""
+"Sets the default value of the specified [enum Margin] to given [code]offset[/"
+"code] in pixels."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:90
+msgid "Test a position in a rectangle, return whether it passes the mask test."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:96
+msgid ""
+"The bottom margin for the contents of this style box. Increasing this value "
+"reduces the space available to the contents from the bottom.\n"
+"If this value is negative, it is ignored and a child-specific margin is used "
+"instead. For example for [StyleBoxFlat] the border thickness (if any) is "
+"used instead.\n"
+"It is up to the code using this style box to decide what these contents are: "
+"for example, a [Button] respects this content margin for the textual "
+"contents of the button.\n"
+"[method get_margin] should be used to fetch this value as consumer instead "
+"of reading these properties directly. This is because it correctly respects "
+"negative values and the fallback mentioned above."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:102
+msgid ""
+"The left margin for the contents of this style box.Increasing this value "
+"reduces the space available to the contents from the left.\n"
+"Refer to [member content_margin_bottom] for extra considerations."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:106
+msgid ""
+"The right margin for the contents of this style box. Increasing this value "
+"reduces the space available to the contents from the right.\n"
+"Refer to [member content_margin_bottom] for extra considerations."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:110
+msgid ""
+"The top margin for the contents of this style box. Increasing this value "
+"reduces the space available to the contents from the top.\n"
+"Refer to [member content_margin_bottom] for extra considerations."
+msgstr ""
+
+#: doc/classes/StyleBoxEmpty.xml:4
+msgid "Empty stylebox (does not display anything)."
+msgstr ""
+
+#: doc/classes/StyleBoxEmpty.xml:7
+msgid "Empty stylebox (really does not display anything)."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:4
+msgid ""
+"Customizable [StyleBox] with a given set of parameters (no texture required)."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:7
+msgid ""
+"This [StyleBox] can be used to achieve all kinds of looks without the need "
+"of a texture. Those properties are customizable:\n"
+"- Color\n"
+"- Border width (individual width for each border)\n"
+"- Rounded corners (individual radius for each corner)\n"
+"- Shadow (with blur and offset)\n"
+"Setting corner radius to high values is allowed. As soon as corners would "
+"overlap, the stylebox will switch to a relative system. Example:\n"
+"[codeblock]\n"
+"height = 30\n"
+"corner_radius_top_left = 50\n"
+"corner_radius_bottom_left = 100\n"
+"[/codeblock]\n"
+"The relative system now would take the 1:2 ratio of the two left corners to "
+"calculate the actual corner width. Both corners added will [b]never[/b] be "
+"more than the height. Result:\n"
+"[codeblock]\n"
+"corner_radius_top_left: 10\n"
+"corner_radius_bottom_left: 20\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:33
+msgid ""
+"Returns the given [code]margin[/code]'s border width. See [enum Margin] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:40
+msgid "Returns the smallest border width out of all four borders."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:49
+msgid ""
+"Returns the given [code]corner[/code]'s radius. See [enum Corner] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:58 doc/classes/StyleBoxTexture.xml:18
+msgid ""
+"Returns the size of the given [code]margin[/code]'s expand margin. See [enum "
+"Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:69
+msgid ""
+"Sets the border width to [code]width[/code] pixels for the given "
+"[code]margin[/code]. See [enum Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:78
+msgid "Sets the border width to [code]width[/code] pixels for all margins."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:89
+msgid ""
+"Sets the corner radius to [code]radius[/code] pixels for the given "
+"[code]corner[/code]. See [enum Corner] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:98
+msgid "Sets the corner radius to [code]radius[/code] pixels for all corners."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:113
+msgid ""
+"Sets the corner radius for each corner to [code]radius_top_left[/code], "
+"[code]radius_top_right[/code], [code]radius_bottom_right[/code], and "
+"[code]radius_bottom_left[/code] pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:124 doc/classes/StyleBoxTexture.xml:62
+msgid ""
+"Sets the expand margin to [code]size[/code] pixels for the given "
+"[code]margin[/code]. See [enum Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:133 doc/classes/StyleBoxTexture.xml:36
+msgid "Sets the expand margin to [code]size[/code] pixels for all margins."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:148 doc/classes/StyleBoxTexture.xml:51
+msgid ""
+"Sets the expand margin for each margin to [code]size_left[/code], "
+"[code]size_top[/code], [code]size_right[/code], and [code]size_bottom[/code] "
+"pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:154
+msgid ""
+"Antialiasing draws a small ring around the edges, which fades to "
+"transparency. As a result, edges look much smoother. This is only noticeable "
+"when using rounded corners."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:157
+msgid ""
+"This changes the size of the faded ring. Higher values can be used to "
+"achieve a \"blurry\" effect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:160
+msgid "The background color of the stylebox."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:163
+msgid "If [code]true[/code], the border will fade into the background color."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:166
+msgid "Sets the color of the border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:169
+msgid "Border width for the bottom border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:172
+msgid "Border width for the left border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:175
+msgid "Border width for the right border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:178
+msgid "Border width for the top border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:181
+msgid ""
+"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.\n"
+"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.\n"
+"A corner detail of [code]1[/code] will result in chamfered corners instead "
+"of rounded corners, which is useful for some artistic effects."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:186
+msgid ""
+"The bottom-left corner's radius. If [code]0[/code], the corner is not "
+"rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:189
+msgid ""
+"The bottom-right corner's radius. If [code]0[/code], the corner is not "
+"rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:192
+msgid ""
+"The top-left corner's radius. If [code]0[/code], the corner is not rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:195
+msgid ""
+"The top-right corner's radius. If [code]0[/code], the corner is not rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:198
+msgid "Toggles drawing of the inner part of the stylebox."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:201
+msgid ""
+"Expands the stylebox outside of the control rect on the bottom edge. Useful "
+"in combination with [member border_width_bottom] to draw a border outside "
+"the control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:204
+msgid ""
+"Expands the stylebox outside of the control rect on the left edge. Useful in "
+"combination with [member border_width_left] to draw a border outside the "
+"control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:207
+msgid ""
+"Expands the stylebox outside of the control rect on the right edge. Useful "
+"in combination with [member border_width_right] to draw a border outside the "
+"control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:210
+msgid ""
+"Expands the stylebox outside of the control rect on the top edge. Useful in "
+"combination with [member border_width_top] to draw a border outside the "
+"control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:213
+msgid ""
+"The color of the shadow. This has no effect if [member shadow_size] is lower "
+"than 1."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:216
+msgid ""
+"The shadow offset in pixels. Adjusts the position of the shadow relatively "
+"to the stylebox."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:219
+msgid "The shadow size in pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:4
+msgid "[StyleBox] that displays a single line."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:7
+msgid ""
+"[StyleBox] that displays a single line of a given color and thickness. It "
+"can be used to draw things like separators."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:15
+msgid "The line's color."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:18
+msgid ""
+"The number of pixels the line will extend before the [StyleBoxLine]'s "
+"bounds. If set to a negative value, the line will begin inside the "
+"[StyleBoxLine]'s bounds."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:21
+msgid ""
+"The number of pixels the line will extend past the [StyleBoxLine]'s bounds. "
+"If set to a negative value, the line will end inside the [StyleBoxLine]'s "
+"bounds."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:24
+msgid "The line's thickness in pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:27
+msgid ""
+"If [code]true[/code], the line will be vertical. If [code]false[/code], the "
+"line will be horizontal."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:4
+msgid "Texture-based nine-patch [StyleBox]."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:7
+msgid ""
+"Texture-based nine-patch [StyleBox], in a way similar to [NinePatchRect]. "
+"This stylebox performs a 3×3 scaling of a texture, where only the center "
+"cell is fully stretched. This makes it possible to design bordered styles "
+"regardless of the stylebox's size."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:27
+msgid ""
+"Returns the size of the given [code]margin[/code]. See [enum Margin] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:73
+msgid ""
+"Sets the margin to [code]size[/code] pixels for the given [code]margin[/"
+"code]. See [enum Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:79
+msgid ""
+"Controls how the stylebox's texture will be stretched or tiled horizontally. "
+"See [enum AxisStretchMode] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:82
+msgid ""
+"Controls how the stylebox's texture will be stretched or tiled vertically. "
+"See [enum AxisStretchMode] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:85
+msgid ""
+"If [code]true[/code], the nine-patch texture's center tile will be drawn."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:88
+msgid ""
+"Expands the bottom margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:91
+msgid ""
+"Expands the left margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:94
+msgid ""
+"Expands the right margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:97
+msgid ""
+"Expands the top margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:100
+msgid ""
+"Increases the bottom margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the bottom border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_bottom] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:105
+msgid ""
+"Increases the left margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the left border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_left] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:110
+msgid ""
+"Increases the right margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the right border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_right] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:115
+msgid ""
+"Increases the top margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the top border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_top] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:120
+msgid "Modulates the color of the texture when this style box is drawn."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:123
+msgid "The normal map to use when drawing this style box."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:126
+msgid ""
+"Species a sub-region of the texture to use.\n"
+"This is equivalent to first wrapping the texture in an [AtlasTexture] with "
+"the same region."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:130
+msgid "The texture to use when drawing this style box."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:136
+msgid "Emitted when the stylebox's texture is changed."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:142
+msgid ""
+"Stretch the stylebox's texture. This results in visible distortion unless "
+"the texture size matches the stylebox's size perfectly."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:145
+msgid ""
+"Repeats the stylebox's texture to match the stylebox's size according to the "
+"nine-patch system."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:148
+msgid ""
+"Repeats the stylebox's texture to match the stylebox's size according to the "
+"nine-patch system. Unlike [constant AXIS_STRETCH_MODE_TILE], the texture may "
+"be slightly stretched to make the nine-patch texture tile seamlessly."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:13
+msgid "If [code]true[/code], the sub-viewport will be used in AR/VR process."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:16
+msgid "The clear mode when the sub-viewport is used as a render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:19
+msgid "The update mode when the sub-viewport is used as a render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:22
+msgid "The width and height of the sub-viewport."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:25
+msgid ""
+"The 2D size override of the sub-viewport. If either the width or height is "
+"[code]0[/code], the override is disabled."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:28
+msgid "If [code]true[/code], the 2D size override affects stretch as well."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:33
+msgid "Do not update the render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:36
+msgid ""
+"Update the render target once, then switch to [constant UPDATE_DISABLED]."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:39
+msgid ""
+"Update the render target only when it is visible. This is the default value."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:42
+msgid "Update the render target only when the its parent is visible."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:45
+msgid "Always update the render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:48
+msgid "Always clear the render target before drawing."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:51
+msgid "Never clear the render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:54
+msgid ""
+"Clear the render target next frame, then switch to [constant "
+"CLEAR_MODE_NEVER]."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:4
+msgid "Control for holding [SubViewport]s."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:7
+msgid ""
+"A [Container] node that holds a [SubViewport], automatically setting its "
+"size."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:15
+msgid ""
+"If [code]true[/code], the sub-viewport will be scaled to the control's size."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:18
+msgid ""
+"Divides the sub-viewport's effective resolution by this value while "
+"preserving its scale. This can be used to speed up rendering.\n"
+"For example, a 1280×720 sub-viewport with [member stretch_shrink] set to "
+"[code]2[/code] will be rendered at 640×360 while occupying the same size in "
+"the container.\n"
+"[b]Note:[/b] [member stretch] must be [code]true[/code] for this property to "
+"work."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:4
+msgid "Helper tool to create geometry."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:7
+msgid ""
+"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:\n"
+"[codeblock]\n"
+"var st = SurfaceTool.new()\n"
+"st.begin(Mesh.PRIMITIVE_TRIANGLES)\n"
+"st.add_color(Color(1, 0, 0))\n"
+"st.add_uv(Vector2(0, 0))\n"
+"st.add_vertex(Vector3(0, 0, 0))\n"
+"[/codeblock]\n"
+"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 add_uv] or [method add_color], then the last values would be "
+"used.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:28
+msgid ""
+"Adds an array of bones for the next vertex to use. [code]bones[/code] must "
+"contain 4 integers."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:37
+msgid "Specifies a [Color] for the next vertex to use."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:46
+msgid ""
+"Adds an index to index array if you are using indexed vertices. Does not "
+"need to be called before adding vertices."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:55
+msgid "Specifies a normal for the next vertex to use."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:64
+msgid ""
+"Specifies whether the current vertex (if using only vertex arrays) or "
+"current index (if also using index arrays) should use smooth normals for "
+"normal calculation."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:73
+msgid "Specifies a tangent for the next vertex to use."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:92
+msgid ""
+"Inserts a triangle fan made of array data into [Mesh] being constructed.\n"
+"Requires the primitive type be set to [constant Mesh.PRIMITIVE_TRIANGLES]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:102
+msgid "Specifies a set of UV coordinates to use for the next vertex."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:111
+msgid ""
+"Specifies an optional second set of UV coordinates to use for the next "
+"vertex."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:120
+msgid ""
+"Specifies the position of current vertex. Should be called after specifying "
+"other vertex properties (e.g. Color, UV)."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:129
+msgid ""
+"Specifies weight values for next vertex to use. [code]weights[/code] must "
+"contain 4 values."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:142
+msgid ""
+"Append vertices from a given [Mesh] surface onto the current vertex array "
+"with specified [Transform]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:151
+msgid ""
+"Called before adding any vertices. Takes the primitive type as an argument "
+"(e.g. [constant Mesh.PRIMITIVE_TRIANGLES])."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:158
+msgid "Clear all information passed into the surface tool so far."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:169
+msgid ""
+"Returns a constructed [ArrayMesh] from current information passed in. If an "
+"existing [ArrayMesh] is passed in as an argument, will add an extra surface "
+"to the existing [ArrayMesh].\n"
+"Default flag is [constant Mesh.ARRAY_COMPRESS_DEFAULT]. See "
+"[code]ARRAY_COMPRESS_*[/code] constants in [enum Mesh.ArrayFormat] for other "
+"flags."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:177
+msgid ""
+"Commits the data to the same format used by [method ArrayMesh."
+"add_surface_from_arrays]. This way you can further process the mesh data "
+"using the [ArrayMesh] API."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:188
+msgid "Creates a vertex array from an existing [Mesh]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:201
+msgid ""
+"Creates a vertex array from the specified blend shape of an existing [Mesh]. "
+"This can be used to extract a specific pose from a blend shape."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:208
+msgid "Removes the index array by expanding the vertex array."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:217
+msgid ""
+"Generates normals from vertices so you do not have to do it manually. If "
+"[code]flip[/code] is [code]true[/code], the resulting normals will be "
+"inverted.\n"
+"Requires the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:225
+msgid ""
+"Generates a tangent vector for each vertex. Requires that each vertex have "
+"UVs and normals set already."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:232
+msgid ""
+"Shrinks the vertex array by creating an index array (avoids reusing "
+"vertices)."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:241
+msgid "Sets [Material] to be used by the [Mesh] you are constructing."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:4
+msgid "Tabbed container."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:7
+msgid ""
+"Sets the active tab's [code]visible[/code] property to the value [code]true[/"
+"code]. Sets all other children's to [code]false[/code].\n"
+"Ignores non-[Control] children.\n"
+"Individual tabs are always visible unless you use [method set_tab_disabled] "
+"and [method set_tab_title] to hide it.\n"
+"To hide only a tab's content, nest the content inside a child [Control], so "
+"it receives the [TabContainer]'s visibility setting instead."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:19
+msgid "Returns the child [Control] node located at the active tab index."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:26
+msgid ""
+"Returns the [Popup] node instance if one has been set already with [method "
+"set_popup]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:33
+msgid "Returns the previously active tab index."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:42
+msgid "Returns the currently visible tab's [Control] node."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:49 doc/classes/Tabs.xml:50
+msgid "Returns the number of tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:58 doc/classes/Tabs.xml:59
+msgid ""
+"Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is "
+"disabled."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:67 doc/classes/Tabs.xml:68
+msgid ""
+"Returns the [Texture2D] for the tab at index [code]tab_idx[/code] or "
+"[code]null[/code] if the tab has no [Texture2D]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:76 doc/classes/Tabs.xml:93
+msgid ""
+"Returns the title of the tab at index [code]tab_idx[/code]. Tab titles "
+"default to the name of the indexed child node, but this can be overridden "
+"with [method set_tab_title]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:83
+msgid "Returns the [TabContainer] rearrange group id."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:92
+msgid ""
+"If set on a [Popup] node instance, a popup menu icon appears in the top-"
+"right corner of the [TabContainer]. Clicking it will expand the [Popup] node."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:103
+msgid ""
+"If [code]disabled[/code] is [code]false[/code], hides the tab at index "
+"[code]tab_idx[/code].\n"
+"[b]Note:[/b] Its title text will remain, unless also removed with [method "
+"set_tab_title]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:115
+msgid "Sets an icon for the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:126
+msgid ""
+"Sets a title for the tab at index [code]tab_idx[/code]. Tab titles default "
+"to the name of the indexed child node, but this can be overridden with "
+"[method set_tab_title]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:135
+msgid ""
+"Defines rearrange group id, choose for each [TabContainer] the same value to "
+"enable tab drag between [TabContainer]. Enable drag with "
+"[code]set_drag_to_rearrange_enabled(true)[/code]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:141
+msgid ""
+"The current tab index. When set, this index's [Control] node's "
+"[code]visible[/code] property is set to [code]true[/code] and all others are "
+"set to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:144 doc/classes/Tabs.xml:181
+msgid "If [code]true[/code], tabs can be rearranged with mouse drag."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:147
+msgid ""
+"The alignment of all tabs in the tab container. See the [enum TabAlign] "
+"constants for details."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:150
+msgid ""
+"If [code]true[/code], tabs are visible. If [code]false[/code], tabs' content "
+"and titles are hidden."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:153
+msgid ""
+"If [code]true[/code], children [Control] nodes that are hidden have their "
+"minimum size take into account in the total, instead of only the currently "
+"visible one."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:159
+msgid ""
+"Emitted when the [TabContainer]'s [Popup] button is clicked. See [method "
+"set_popup] for details."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:166 doc/classes/Tabs.xml:212
+msgid "Emitted when switching to another tab."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:173
+msgid "Emitted when a tab is selected, even if it is the current tab."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:179 doc/classes/Tabs.xml:239
+msgid "Align the tabs to the left."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:182 doc/classes/Tabs.xml:242
+msgid "Align the tabs to the center."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:185 doc/classes/Tabs.xml:245
+msgid "Align the tabs to the right."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:190 doc/classes/Tabs.xml:274
+msgid ""
+"Icon for the left arrow button that appears when there are too many tabs to "
+"fit in the container width. When the button is disabled (i.e. the first tab "
+"is visible), it appears semi-transparent."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:193 doc/classes/Tabs.xml:277
+msgid ""
+"Icon for the left 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."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:196 doc/classes/Tabs.xml:280
+msgid "The font used to draw tab names."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:199 doc/classes/Tabs.xml:283
+msgid "Font color of inactive tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:202 doc/classes/Tabs.xml:286
+msgid "Font color of disabled tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:205 doc/classes/Tabs.xml:289
+msgid "Font color of the currently selected tab."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:208
+msgid "Horizontal separation between tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:211 doc/classes/Tabs.xml:295
+msgid ""
+"Icon for the right arrow button that appears when there are too many tabs to "
+"fit in the container width. When the button is disabled (i.e. the last tab "
+"is visible) it appears semi-transparent."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:214 doc/classes/Tabs.xml:298
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:217
+msgid "The icon for the menu button (see [method set_popup])."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:220
+msgid ""
+"The icon for the menu button (see [method set_popup]) when it's being "
+"hovered with the cursor."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:223
+msgid "The style for the background fill."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:226
+msgid "The space at the left and right edges of the tab bar."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:229
+msgid "The style of inactive tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:232
+msgid "The style of disabled tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:235 doc/classes/Tabs.xml:309
+msgid "The style of the currently selected tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:4
+msgid "Tabs control."
+msgstr ""
+
+#: doc/classes/Tabs.xml:7
+msgid ""
+"Simple tabs control, similar to [TabContainer] but is only in charge of "
+"drawing tabs, not interact with children."
+msgstr ""
+
+#: doc/classes/Tabs.xml:20
+msgid "Adds a new tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:29
+msgid "Moves the scroll view to make the tab visible."
+msgstr ""
+
+#: doc/classes/Tabs.xml:36
+msgid ""
+"Returns [code]true[/code] if the offset buttons (the ones that appear when "
+"there's not enough space for all tabs) are visible."
+msgstr ""
+
+#: doc/classes/Tabs.xml:43
+msgid "Returns [code]true[/code] if select with right mouse button is enabled."
+msgstr ""
+
+#: doc/classes/Tabs.xml:75
+msgid "Returns the number of hidden tabs offsetted to the left."
+msgstr ""
+
+#: doc/classes/Tabs.xml:84
+msgid "Returns tab [Rect2] with local position and size."
+msgstr ""
+
+#: doc/classes/Tabs.xml:100
+msgid "Returns the [Tabs]' rearrange group ID."
+msgstr ""
+
+#: doc/classes/Tabs.xml:111
+msgid "Moves a tab from [code]from[/code] to [code]to[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:120
+msgid "Removes the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:129
+msgid ""
+"If [code]true[/code], enables selecting a tab with the right mouse button."
+msgstr ""
+
+#: doc/classes/Tabs.xml:140
+msgid ""
+"If [code]disabled[/code] is [code]false[/code], hides the tab at index "
+"[code]tab_idx[/code].\n"
+"[b]Note:[/b] Its title text will remain unless it is also removed with "
+"[method set_tab_title]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:152
+msgid "Sets an [code]icon[/code] for the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:163
+msgid "Sets a [code]title[/code] for the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:172
+msgid ""
+"Defines the rearrange group ID. Choose for each [Tabs] the same value to "
+"dragging tabs between [Tabs]. Enable drag with "
+"[code]set_drag_to_rearrange_enabled(true)[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:178
+msgid "Select tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:184
+msgid ""
+"if [code]true[/code], the mouse's scroll wheel cab be used to navigate the "
+"scroll view."
+msgstr ""
+
+#: doc/classes/Tabs.xml:187
+msgid "The alignment of all tabs. See [enum TabAlign] for details."
+msgstr ""
+
+#: doc/classes/Tabs.xml:190
+msgid ""
+"Sets when the close button will appear on the tabs. See [enum "
+"CloseButtonDisplayPolicy] for details."
+msgstr ""
+
+#: doc/classes/Tabs.xml:198
+msgid ""
+"Emitted when the active tab is rearranged via mouse drag. See [member "
+"drag_to_rearrange_enabled]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:205
+msgid "Emitted when a tab is right-clicked."
+msgstr ""
+
+#: doc/classes/Tabs.xml:219
+msgid "Emitted when a tab is clicked, even if it is the current tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:226
+msgid "Emitted when a tab is closed."
+msgstr ""
+
+#: doc/classes/Tabs.xml:233
+msgid "Emitted when a tab is hovered by the mouse."
+msgstr ""
+
+#: doc/classes/Tabs.xml:248
+msgid "Represents the size of the [enum TabAlign] enum."
+msgstr ""
+
+#: doc/classes/Tabs.xml:251
+msgid "Never show the close buttons."
+msgstr ""
+
+#: doc/classes/Tabs.xml:254
+msgid "Only show the close button on the currently active tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:257
+msgid "Show the close button on all tabs."
+msgstr ""
+
+#: doc/classes/Tabs.xml:260
+msgid "Represents the size of the [enum CloseButtonDisplayPolicy] enum."
+msgstr ""
+
+#: doc/classes/Tabs.xml:265
+msgid "Background of the close button when it's being hovered with the cursor."
+msgstr ""
+
+#: doc/classes/Tabs.xml:268
+msgid "Background of the close button when it's being pressed."
+msgstr ""
+
+#: doc/classes/Tabs.xml:271
+msgid "The icon for the close button (see [member tab_close_display_policy])."
+msgstr ""
+
+#: doc/classes/Tabs.xml:292
+msgid "The horizontal separation between the tabs."
+msgstr ""
+
+#: doc/classes/Tabs.xml:303
+msgid "The style of an inactive tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:306
+msgid "The style of a disabled tab"
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:4
+msgid "A TCP server."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:7
+msgid ""
+"A TCP server. Listens to connections on a port and returns a [StreamPeerTCP] "
+"when it gets an incoming connection."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:16
+msgid "Returns [code]true[/code] if a connection is available for taking."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:23
+msgid ""
+"Returns [code]true[/code] if the server is currently listening for "
+"connections."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:34
+msgid ""
+"Listen on the [code]port[/code] binding to [code]bind_address[/code].\n"
+"If [code]bind_address[/code] is set as [code]\"*\"[/code] (default), the "
+"server will listen on all available addresses (both IPv4 and IPv6).\n"
+"If [code]bind_address[/code] is set as [code]\"0.0.0.0\"[/code] (for IPv4) "
+"or [code]\"::\"[/code] (for IPv6), the server will listen on all available "
+"addresses matching that IP type.\n"
+"If [code]bind_address[/code] is set to any valid address (e.g. "
+"[code]\"192.168.1.101\"[/code], [code]\"::1\"[/code], etc), the server will "
+"only listen on the interface with that addresses (or fail if no interface "
+"with the given address exists)."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:44
+msgid "Stops listening."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:51
+msgid ""
+"If a connection is available, returns a StreamPeerTCP with the connection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:4
+msgid "Multiline text editing control."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:7
+msgid ""
+"TextEdit is meant for editing large, multiline text. It also has facilities "
+"for editing code, such as syntax highlighting support and multiple levels of "
+"undo/redo."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:24
+msgid "Adds color region (given the delimiters) and its colors."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:35
+msgid "Adds a [code]keyword[/code] and its [Color]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:44
+msgid ""
+"Returns if the given line is foldable, that is, it has indented lines right "
+"below it."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:57
+msgid ""
+"Clears all custom syntax coloring information previously added with [method "
+"add_color_region] or [method add_keyword_color]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:64
+msgid "Clears the undo history."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:71
+msgid "Copy's the current text selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:78
+msgid "Returns the column the editing cursor is at."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:85
+msgid "Returns the line the editing cursor is at."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:96
+msgid ""
+"Moves the cursor at the specified [code]column[/code] index.\n"
+"If [code]adjust_viewport[/code] is set to [code]true[/code], the viewport "
+"will center at the cursor position after the move occurs."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:112
+msgid ""
+"Moves the cursor at the specified [code]line[/code] index.\n"
+"If [code]adjust_viewport[/code] is set to [code]true[/code], the viewport "
+"will center at the cursor position after the move occurs.\n"
+"If [code]can_be_hidden[/code] is set to [code]true[/code], the specified "
+"[code]line[/code] can be hidden using [method set_line_as_hidden]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:121
+msgid "Cut's the current selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:128
+msgid "Deselects the current selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:135
+msgid "Folds all lines that are possible to be folded (see [method can_fold])."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:144
+msgid "Folds the given line, if possible (see [method can_fold])."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:151
+msgid "Returns an array containing the line number of each breakpoint."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:160
+msgid "Returns the [Color] of the specified [code]keyword[/code]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:169
+msgid "Returns the text of a specific line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:176
+msgid "Returns the amount of total lines in the text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:183
+msgid ""
+"Returns the [PopupMenu] of this [TextEdit]. By default, this menu is "
+"displayed when right-clicking on the [TextEdit]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:190
+msgid "Returns the selection begin column."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:197
+msgid "Returns the selection begin line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:204
+msgid "Returns the text inside the selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:211
+msgid "Returns the selection end column."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:218
+msgid "Returns the selection end line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:225
+msgid "Returns a [String] text with the word under the mouse cursor location."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:234
+msgid ""
+"Returns whether the specified [code]keyword[/code] has a color set to it or "
+"not."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:243
+msgid "Insert the specified text at the cursor position."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:252
+msgid "Returns whether the line at the specified index is folded or not."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:261
+msgid "Returns whether the line at the specified index is hidden or not."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:268
+msgid "Returns [code]true[/code] if the selection is active."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:277
+msgid ""
+"Triggers a right-click menu action by the specified index. See [enum "
+"MenuItems] for a list of available indexes."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:284
+msgid "Paste the current selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:291
+msgid "Perform redo operation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:298
+msgid ""
+"Removes all the breakpoints. This will not fire the [signal "
+"breakpoint_toggled] signal."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:313
+msgid ""
+"Perform a search inside the text. Search flags can be specified in the [enum "
+"SearchFlags] enum.\n"
+"Returns an empty [code]PackedInt32Array[/code] if no result was found. "
+"Otherwise, the result line and column can be accessed at indices specified "
+"in the [enum SearchResult] enum, e.g:\n"
+"[codeblock]\n"
+"var result = search(key, flags, line, column)\n"
+"if result.size() > 0:\n"
+" # Result found.\n"
+" var res_line = result[TextEdit.SEARCH_RESULT_LINE]\n"
+" var res_column = result[TextEdit.SEARCH_RESULT_COLUMN]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/TextEdit.xml:336
+msgid "Perform selection, from line/column to line/column."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:343
+msgid "Select all the text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:354
+msgid "If [code]true[/code], hides the line of the specified index."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:363
+msgid "Toggle the folding of the code block at the given line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:370
+msgid "Perform undo operation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:379
+msgid "Unfolds the given line, if folded."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:386
+msgid ""
+"Unhide all lines that were previously set to hidden by [method "
+"set_line_as_hidden]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:392
+msgid "If [code]true[/code], the breakpoint gutter is visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:401
+msgid ""
+"If [code]true[/code], the caret displays as a rectangle.\n"
+"If [code]false[/code], the caret displays as a bar."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:405
+msgid ""
+"If [code]true[/code], a right-click moves the cursor at the mouse position "
+"before displaying the context menu.\n"
+"If [code]false[/code], the context menu disregards mouse location."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:409
+msgid "If [code]true[/code], a right-click displays the context menu."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:412
+msgid ""
+"If [code]true[/code], the \"space\" character will have a visible "
+"representation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:415
+msgid ""
+"If [code]true[/code], the \"tab\" character will have a visible "
+"representation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:419
+msgid ""
+"If [code]true[/code], the fold gutter is visible. This enables folding "
+"groups of indented lines."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:422
+msgid ""
+"If [code]true[/code], all lines that have been set to hidden by [method "
+"set_line_as_hidden], will not be visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:425
+msgid ""
+"If [code]true[/code], all occurrences of the selected text will be "
+"highlighted."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:428
+msgid "If [code]true[/code], the line containing the cursor is highlighted."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:438
+msgid ""
+"If [code]true[/code], read-only mode is enabled. Existing text cannot be "
+"modified and new text cannot be added."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:451
+msgid ""
+"If [code]true[/code], line numbers are displayed to the left of the text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:454
+msgid ""
+"If [code]true[/code], sets the [code]step[/code] of the scrollbars to "
+"[code]0.25[/code] which results in smoother scrolling."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:457
+msgid ""
+"If [code]true[/code], any custom color properties that have been set for "
+"this [TextEdit] will be visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:460
+msgid "String value of the [TextEdit]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:463
+msgid "Vertical scroll sensitivity."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:466
+msgid ""
+"If [code]true[/code], enables text wrapping when it goes beyond the edge of "
+"what is visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:474
+msgid "Emitted when a breakpoint is placed via the breakpoint gutter."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:479
+msgid "Emitted when the cursor changes."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:488
+msgid "Emitted when the info icon is clicked."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:519
+msgid "Match case when searching."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:522
+msgid "Match whole words when searching."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:525
+msgid "Search from end to beginning."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:528
+msgid "Used to access the result column from [method search]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:531
+msgid "Used to access the result line from [method search]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:540
+msgid ""
+"Pastes the clipboard text over the selected text (or at the cursor's "
+"position)."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:543
+msgid "Erases the whole [TextEdit] text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:546
+msgid "Selects the whole [TextEdit] text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:552
+msgid "Redoes the previous action."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:560
+msgid ""
+"Sets the background [Color] of this [TextEdit]. [member syntax_highlighting] "
+"has to be enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:563
+msgid ""
+"Sets the [Color] of the bookmark marker. [member syntax_highlighting] has to "
+"be enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:568 doc/classes/TextEdit.xml:595
+msgid ""
+"Sets the [Color] of the breakpoints. [member breakpoint_gutter] has to be "
+"enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:606
+msgid "Sets the default [Font]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:609
+msgid "Sets the font [Color]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:618
+msgid ""
+"Sets the [Color] of the line numbers. [member show_line_numbers] has to be "
+"enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:621
+msgid "Sets the spacing between the lines."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:624
+msgid "Sets the [Color] of marked text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:629
+msgid "Sets the [StyleBox] of this [TextEdit]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:634
+msgid ""
+"Sets the [StyleBox] of this [TextEdit] when [member readonly] is enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:639
+msgid "Sets the highlight [Color] of text selections."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:646
+msgid "Sets a custom [Texture2D] for tab text characters."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:649
+msgid ""
+"Sets the highlight [Color] of multiple occurrences. [member "
+"highlight_all_occurrences] has to be enabled."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:4
+msgid "Texture for 2D and 3D."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:7
+msgid ""
+"A texture works by registering an image in the video hardware, which then "
+"can be used in 3D models or 2D [Sprite2D] or GUI [Control].\n"
+"Textures are often created by loading them from a file. See [method "
+"@GDScript.load].\n"
+"[Texture2D] is a base for other resources. It cannot be used directly."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:36
+msgid ""
+"Draws the texture using a [CanvasItem] with the [RenderingServer] API at the "
+"specified [code]position[/code]."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:63
+msgid "Draws the texture using a [CanvasItem] with the [RenderingServer] API."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:92
+msgid ""
+"Draws a part of the texture using a [CanvasItem] with the [RenderingServer] "
+"API."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:99
+msgid ""
+"Returns an [Image] with the data from this [Texture2D]. [Image]s can be "
+"accessed and manipulated directly."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:106
+msgid "Returns the texture height."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:113
+msgid "Returns the texture size."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:120
+msgid "Returns the texture width."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:127
+msgid "Returns [code]true[/code] if this [Texture2D] has an alpha channel."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:4
+msgid ""
+"Texture-based button. Supports Pressed, Hover, Disabled and Focused states."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:7
+msgid ""
+"[TextureButton] has the same functionality as [Button], except it uses "
+"sprites instead of Godot's [Theme] resource. It is faster to create, but it "
+"doesn't support localization like more complex [Control]s.\n"
+"The \"normal\" state must contain a texture ([member texture_normal]); other "
+"textures are optional."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:16
+msgid ""
+"If [code]true[/code], the texture stretches to the edges of the node's "
+"bounding rectangle using the [member stretch_mode]. If [code]false[/code], "
+"the texture will not scale with the node."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:19
+msgid ""
+"Controls the texture's behavior when you resize the node's bounding "
+"rectangle, [b]only if[/b] [member expand] is [code]true[/code]. Set it to "
+"one of the [enum StretchMode] constants. See the constants to learn more."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:22
+msgid ""
+"Pure black and white [BitMap] image to use for click detection. On the mask, "
+"white pixels represent the button's clickable area. Use it to create buttons "
+"with curved shapes."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:25
+msgid ""
+"Texture to display when the node is disabled. See [member BaseButton."
+"disabled]."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:28
+msgid "Texture to display when the node has mouse or keyboard focus."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:31
+msgid "Texture to display when the mouse hovers the node."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:34
+msgid ""
+"Texture to display by default, when the node is [b]not[/b] in the disabled, "
+"focused, hover or pressed state."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:37
+msgid ""
+"Texture to display on mouse down over the node, if the node has keyboard "
+"focus and the player presses the Enter key or if the player presses the "
+"[member BaseButton.shortcut] key."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:42 doc/classes/TextureRect.xml:36
+msgid "Scale to fit the node's bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:45 doc/classes/TextureRect.xml:39
+msgid "Tile inside the node's bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:48 doc/classes/TextureRect.xml:42
+msgid ""
+"The texture keeps its original size and stays in the bounding rectangle's "
+"top-left corner."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:51 doc/classes/TextureRect.xml:45
+msgid ""
+"The texture keeps its original size and stays centered in the node's "
+"bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:54 doc/classes/TextureRect.xml:48
+msgid ""
+"Scale the texture to fit the node's bounding rectangle, but maintain the "
+"texture's aspect ratio."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:57
+msgid ""
+"Scale the texture to fit the node's bounding rectangle, center it, and "
+"maintain its aspect ratio."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:60 doc/classes/TextureRect.xml:54
+msgid ""
+"Scale the texture so that the shorter side fits the bounding rectangle. The "
+"other side clips to the node's limits."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:4
+msgid "Base class for 3D texture types."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:7
+msgid ""
+"Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be "
+"used directly, but contains all the functions necessary for accessing the "
+"derived resource types. Data is set on a per-layer basis. For "
+"[Texture2DArray]s, the layer specifies the array layer."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:24
+msgid ""
+"Returns the current format being used by this texture. See [enum Image."
+"Format] for details."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:31
+msgid ""
+"Returns the height of the texture. Height is typically represented by the Y-"
+"axis."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:40
+msgid ""
+"Returns an [Image] resource with the data from specified [code]layer[/code]."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:53
+msgid ""
+"Returns the width of the texture. Width is typically represented by the X-"
+"axis."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:4
+msgid ""
+"Texture-based progress bar. Useful for loading screens and life or stamina "
+"bars."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:7
+msgid ""
+"TextureProgress works like [ProgressBar], but uses up to 3 textures instead "
+"of Godot's [Theme] resource. It can be used to create horizontal, vertical "
+"and radial progress bars."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:33
+msgid "The fill direction. See [enum FillMode] for possible values."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:37
+msgid ""
+"If [code]true[/code], Godot treats the bar's textures like in "
+"[NinePatchRect]. Use the [code]stretch_margin_*[/code] properties like "
+"[member stretch_margin_bottom] to set up the nine patch's 3×3 grid. When "
+"using a radial [member fill_mode], this setting will enable stretching."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:40
+msgid ""
+"Offsets [member texture_progress] if [member fill_mode] is [constant "
+"FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:43
+msgid ""
+"Upper limit for the fill of [member texture_progress] if [member fill_mode] "
+"is [constant FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]. When the "
+"node's [code]value[/code] is equal to its [code]max_value[/code], the "
+"texture fills up to this angle.\n"
+"See [member Range.value], [member Range.max_value]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:47
+msgid ""
+"Starting angle for the fill of [member texture_progress] if [member "
+"fill_mode] is [constant FILL_CLOCKWISE] or [constant "
+"FILL_COUNTER_CLOCKWISE]. When the node's [code]value[/code] is equal to its "
+"[code]min_value[/code], the texture doesn't show up at all. When the "
+"[code]value[/code] increases, the texture fills and tends towards [member "
+"radial_fill_degrees]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:50
+msgid ""
+"The height of the 9-patch's bottom row. A margin of 16 means the 9-slice's "
+"bottom corners and side will have a height of 16 pixels. You can set all 4 "
+"margin values individually to create panels with non-uniform borders."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:53
+msgid "The width of the 9-patch's left column."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:56
+msgid "The width of the 9-patch's right column."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:59
+msgid "The height of the 9-patch's top row."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:62
+msgid ""
+"[Texture2D] that draws over the progress bar. Use it to add highlights or an "
+"upper-frame that hides part of [member texture_progress]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:65
+msgid ""
+"[Texture2D] that clips based on the node's [code]value[/code] and [member "
+"fill_mode]. As [code]value[/code] increased, the texture fills up. It shows "
+"entirely when [code]value[/code] reaches [code]max_value[/code]. It doesn't "
+"show at all if [code]value[/code] is equal to [code]min_value[/code].\n"
+"The [code]value[/code] property comes from [Range]. See [member Range."
+"value], [member Range.min_value], [member Range.max_value]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:69
+msgid "[Texture2D] that draws under the progress bar. The bar's background."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:72
+msgid ""
+"Multiplies the color of the bar's [code]texture_over[/code] texture. The "
+"effect is similar to [member CanvasItem.modulate], except it only affects "
+"this specific texture instead of the entire node."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:75
+msgid ""
+"Multiplies the color of the bar's [code]texture_progress[/code] texture."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:78
+msgid "Multiplies the color of the bar's [code]texture_under[/code] texture."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:83
+msgid "The [member texture_progress] fills from left to right."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:86
+msgid "The [member texture_progress] fills from right to left."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:89
+msgid "The [member texture_progress] fills from top to bottom."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:92
+msgid "The [member texture_progress] fills from bottom to top."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:95
+msgid ""
+"Turns the node into a radial bar. The [member texture_progress] fills "
+"clockwise. See [member radial_center_offset], [member radial_initial_angle] "
+"and [member radial_fill_degrees] to control the way the bar fills up."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:98
+msgid ""
+"Turns the node into a radial bar. The [member texture_progress] fills "
+"counterclockwise. See [member radial_center_offset], [member "
+"radial_initial_angle] and [member radial_fill_degrees] to control the way "
+"the bar fills up."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:101
+msgid ""
+"The [member texture_progress] fills from the center, expanding both towards "
+"the left and the right."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:104
+msgid ""
+"The [member texture_progress] fills from the center, expanding both towards "
+"the top and the bottom."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:107
+msgid ""
+"Turns the node into a radial bar. The [member texture_progress] fills "
+"radially from the center, expanding both clockwise and counterclockwise. See "
+"[member radial_center_offset], [member radial_initial_angle] and [member "
+"radial_fill_degrees] to control the way the bar fills up."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:4
+msgid "Control for drawing textures."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:7
+msgid ""
+"Used to draw icons and sprites in a user interface. The texture's placement "
+"can be controlled with the [member stretch_mode] property. It can scale, "
+"tile, or stay centered inside its bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:15
+msgid "If [code]true[/code], the texture scales to fit its bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:25
+msgid ""
+"Controls the texture's behavior when resizing the node's bounding rectangle. "
+"See [enum StretchMode]."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:28
+msgid "The node's [Texture2D] resource."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:33
+msgid ""
+"Scale to fit the node's bounding rectangle, only if [code]expand[/code] is "
+"[code]true[/code]. Default [code]stretch_mode[/code], for backwards "
+"compatibility. Until you set [code]expand[/code] to [code]true[/code], the "
+"texture will behave like [constant STRETCH_KEEP]."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:51
+msgid ""
+"Scale the texture to fit the node's bounding rectangle, center it and "
+"maintain its aspect ratio."
+msgstr ""
+
+#: doc/classes/Theme.xml:4
+msgid "Theme for controls."
+msgstr ""
+
+#: doc/classes/Theme.xml:7
+msgid ""
+"A theme for skinning controls. Controls can be skinned individually, but for "
+"complex applications, it's more practical to just create a global theme that "
+"defines everything. This theme can be applied to any [Control]; the Control "
+"and its children will automatically use it.\n"
+"Theme resources can alternatively be loaded by writing them in a [code]."
+"theme[/code] file, see the documentation for more information."
+msgstr ""
+
+#: doc/classes/Theme.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/gui/gui_skinning.html"
+msgstr ""
+
+#: doc/classes/Theme.xml:18
+msgid "Clears all values on the theme."
+msgstr ""
+
+#: doc/classes/Theme.xml:29
+msgid ""
+"Clears the [Color] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:40
+msgid ""
+"Clears the constant at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:51
+msgid ""
+"Clears the [Font] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:62
+msgid ""
+"Clears the icon at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:73
+msgid ""
+"Clears [StyleBox] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:80
+msgid "Sets the theme's values to a copy of the default theme values."
+msgstr ""
+
+#: doc/classes/Theme.xml:89
+msgid "Sets the theme's values to a copy of a given theme."
+msgstr ""
+
+#: doc/classes/Theme.xml:100
+msgid ""
+"Returns the [Color] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:109
+msgid ""
+"Returns all the [Color]s as a [PackedStringArray] filled with each [Color]'s "
+"name, for use in [method get_color], if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:120
+msgid ""
+"Returns the constant at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:129
+msgid ""
+"Returns all the constants as a [PackedStringArray] filled with each "
+"constant's name, for use in [method get_constant], if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:140
+msgid ""
+"Returns the [Font] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:149
+msgid ""
+"Returns all the [Font]s as a [PackedStringArray] filled with each [Font]'s "
+"name, for use in [method get_font], if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:160
+msgid ""
+"Returns the icon [Texture2D] at [code]name[/code] if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:169
+msgid ""
+"Returns all the icons as a [PackedStringArray] filled with each "
+"[Texture2D]'s name, for use in [method get_icon], if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:180
+msgid ""
+"Returns the icon [StyleBox] at [code]name[/code] if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:189
+msgid ""
+"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]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:196
+msgid ""
+"Returns all the [StyleBox] types as a [PackedStringArray] filled with each "
+"[StyleBox]'s type, for use in [method get_stylebox] and/or [method "
+"get_stylebox_list], if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:205
+msgid ""
+"Returns all the types in [code]type[/code] as a [PackedStringArray] for use "
+"in any of the [code]get_*[/code] functions, if the theme has [code]type[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:216
+msgid ""
+"Returns [code]true[/code] if [Color] with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:228
+msgid ""
+"Returns [code]true[/code] if constant with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:240
+msgid ""
+"Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]type[/"
+"code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:252
+msgid ""
+"Returns [code]true[/code] if icon [Texture2D] with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:264
+msgid ""
+"Returns [code]true[/code] if [StyleBox] with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:278
+msgid ""
+"Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:292
+msgid ""
+"Sets the theme's constant to [code]constant[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:306
+msgid ""
+"Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:320
+msgid ""
+"Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/"
+"code] in [code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:334
+msgid ""
+"Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:341
+msgid "The theme's default font."
+msgstr ""
+
+#: doc/classes/Thread.xml:4
+msgid "A unit of execution in a process."
+msgstr ""
+
+#: doc/classes/Thread.xml:7
+msgid ""
+"A unit of execution in a process. Can run methods on [Object]s "
+"simultaneously. The use of synchronization via [Mutex] or [Semaphore] is "
+"advised if working with shared objects."
+msgstr ""
+
+#: doc/classes/Thread.xml:17
+msgid ""
+"Returns the current [Thread]'s ID, uniquely identifying it among all threads."
+msgstr ""
+
+#: doc/classes/Thread.xml:24
+msgid ""
+"Returns [code]true[/code] if this [Thread] is currently active. An active "
+"[Thread] cannot start work on a new method but can be joined with [method "
+"wait_to_finish]."
+msgstr ""
+
+#: doc/classes/Thread.xml:39
+msgid ""
+"Starts a new [Thread] that runs [code]method[/code] on object "
+"[code]instance[/code] with [code]userdata[/code] passed as an argument. Even "
+"if no userdata is passed, [code]method[/code] must accept one argument and "
+"it will be null. The [code]priority[/code] of the [Thread] can be changed by "
+"passing a value from the [enum Priority] enum.\n"
+"Returns [constant OK] on success, or [constant ERR_CANT_CREATE] on failure."
+msgstr ""
+
+#: doc/classes/Thread.xml:47
+msgid ""
+"Joins the [Thread] and waits for it to finish. Returns what the method "
+"called returned."
+msgstr ""
+
+#: doc/classes/Thread.xml:53
+msgid "A thread running with lower priority than normally."
+msgstr ""
+
+#: doc/classes/Thread.xml:56
+msgid "A thread with a standard priority."
+msgstr ""
+
+#: doc/classes/Thread.xml:59
+msgid "A thread running with higher priority than normally."
+msgstr ""
+
+#: doc/classes/TileMap.xml:4
+msgid "Node for 2D tile-based maps."
+msgstr ""
+
+#: doc/classes/TileMap.xml:7
+msgid ""
+"Node for 2D tile-based maps. Tilemaps use a [TileSet] which contain a list "
+"of tiles (textures plus optional collision, navigation, and/or occluder "
+"shapes) which are used to create grid-based maps."
+msgstr ""
+
+#: doc/classes/TileMap.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/using_tilemaps.html"
+msgstr ""
+
+#: doc/classes/TileMap.xml:17
+msgid "Clears all cells."
+msgstr ""
+
+#: doc/classes/TileMap.xml:24
+msgid "Clears cells that do not exist in the tileset."
+msgstr ""
+
+#: doc/classes/TileMap.xml:35
+msgid ""
+"Returns the tile index of the given cell. If no tile exists in the cell, "
+"returns [constant INVALID_CELL]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:46
+msgid ""
+"Returns the coordinate of the autotile variation in the tileset. Returns a "
+"zero vector if the cell doesn't have autotiling."
+msgstr ""
+
+#: doc/classes/TileMap.xml:55
+msgid ""
+"Returns the tile index of the cell given by a Vector2. If no tile exists in "
+"the cell, returns [constant INVALID_CELL]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:64
+msgid "Returns [code]true[/code] if the given collision layer bit is set."
+msgstr ""
+
+#: doc/classes/TileMap.xml:73
+msgid "Returns [code]true[/code] if the given collision mask bit is set."
+msgstr ""
+
+#: doc/classes/TileMap.xml:80
+msgid ""
+"Returns a [Vector2] array with the positions of all cells containing a tile "
+"from the tileset (i.e. a tile index different from [code]-1[/code])."
+msgstr ""
+
+#: doc/classes/TileMap.xml:89
+msgid "Returns an array of all cells with the given tile [code]id[/code]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:96
+msgid "Returns a rectangle enclosing the used (non-empty) tiles of the map."
+msgstr ""
+
+#: doc/classes/TileMap.xml:107
+msgid ""
+"Returns [code]true[/code] if the given cell is transposed, i.e. the X and Y "
+"axes are swapped."
+msgstr ""
+
+#: doc/classes/TileMap.xml:118
+msgid "Returns [code]true[/code] if the given cell is flipped in the X axis."
+msgstr ""
+
+#: doc/classes/TileMap.xml:129
+msgid "Returns [code]true[/code] if the given cell is flipped in the Y axis."
+msgstr ""
+
+#: doc/classes/TileMap.xml:140
+msgid ""
+"Returns the global position corresponding to the given tilemap (grid-based) "
+"coordinates.\n"
+"Optionally, the tilemap's half offset can be ignored."
+msgstr ""
+
+#: doc/classes/TileMap.xml:162
+msgid ""
+"Sets the tile index for the cell given by a Vector2.\n"
+"An index of [code]-1[/code] clears the cell.\n"
+"Optionally, the tile can also be flipped, transposed, or given autotile "
+"coordinates.\n"
+"[b]Note:[/b] Data such as navigation polygons and collision shapes are not "
+"immediately updated for performance reasons.\n"
+"If you need these to be immediately updated, you can call [method "
+"update_dirty_quadrants].\n"
+"Overriding this method also overrides it internally, allowing custom logic "
+"to be implemented when tiles are placed/removed:\n"
+"[codeblock]\n"
+"func set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)\n"
+" # Write your custom logic here.\n"
+" # To call the default method:\n"
+" .set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/TileMap.xml:190
+msgid ""
+"Sets the tile index for the given cell.\n"
+"An index of [code]-1[/code] clears the cell.\n"
+"Optionally, the tile can also be flipped or transposed.\n"
+"[b]Note:[/b] Data such as navigation polygons and collision shapes are not "
+"immediately updated for performance reasons.\n"
+"If you need these to be immediately updated, you can call [method "
+"update_dirty_quadrants]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:205
+msgid "Sets the given collision layer bit."
+msgstr ""
+
+#: doc/classes/TileMap.xml:216
+msgid "Sets the given collision mask bit."
+msgstr ""
+
+#: doc/classes/TileMap.xml:225
+msgid ""
+"Applies autotiling rules to the cell (and its adjacent cells) referenced by "
+"its grid-based X and Y coordinates."
+msgstr ""
+
+#: doc/classes/TileMap.xml:236
+msgid ""
+"Applies autotiling rules to the cells in the given region (specified by grid-"
+"based X and Y coordinates).\n"
+"Calling with invalid (or missing) parameters applies autotiling rules for "
+"the entire tilemap."
+msgstr ""
+
+#: doc/classes/TileMap.xml:244
+msgid ""
+"Updates the tile map's quadrants, allowing things such as navigation and "
+"collision shapes to be immediately used if modified."
+msgstr ""
+
+#: doc/classes/TileMap.xml:253
+msgid ""
+"Returns the tilemap (grid-based) coordinates corresponding to the given "
+"local position."
+msgstr ""
+
+#: doc/classes/TileMap.xml:259
+msgid "If [code]true[/code], the cell's UVs will be clipped."
+msgstr ""
+
+#: doc/classes/TileMap.xml:262
+msgid "The custom [Transform2D] to be applied to the TileMap's cells."
+msgstr ""
+
+#: doc/classes/TileMap.xml:265
+msgid ""
+"Amount to offset alternating tiles. See [enum HalfOffset] for possible "
+"values."
+msgstr ""
+
+#: doc/classes/TileMap.xml:268
+msgid ""
+"The TileMap's quadrant size. Optimizes drawing by batching, using chunks of "
+"this size."
+msgstr ""
+
+#: doc/classes/TileMap.xml:271
+msgid "The TileMap's cell size."
+msgstr ""
+
+#: doc/classes/TileMap.xml:274
+msgid "Position for tile origin. See [enum TileOrigin] for possible values."
+msgstr ""
+
+#: doc/classes/TileMap.xml:277
+msgid ""
+"If [code]true[/code], the TileMap's children will be drawn in order of their "
+"Y coordinate."
+msgstr ""
+
+#: doc/classes/TileMap.xml:280
+msgid ""
+"If [code]true[/code], the textures will be centered in the middle of each "
+"tile. This is useful for certain isometric or top-down modes when textures "
+"are made larger or smaller than the tiles (e.g. to avoid flickering on tile "
+"edges). The offset is still applied, but from the center of the tile. If "
+"used, [member compatibility_mode] is ignored.\n"
+"If [code]false[/code], the texture position start in the top-left corner "
+"unless [member compatibility_mode] is enabled."
+msgstr ""
+
+#: doc/classes/TileMap.xml:284
+msgid ""
+"Bounce value for static body collisions (see [code]collision_use_kinematic[/"
+"code])."
+msgstr ""
+
+#: doc/classes/TileMap.xml:287
+msgid ""
+"Friction value for static body collisions (see "
+"[code]collision_use_kinematic[/code])."
+msgstr ""
+
+#: doc/classes/TileMap.xml:290
+msgid "The collision layer(s) for all colliders in the TileMap."
+msgstr ""
+
+#: doc/classes/TileMap.xml:293
+msgid "The collision mask(s) for all colliders in the TileMap."
+msgstr ""
+
+#: doc/classes/TileMap.xml:296
+msgid ""
+"If [code]true[/code], TileMap collisions will be handled as a kinematic "
+"body. If [code]false[/code], collisions will be handled as static body."
+msgstr ""
+
+#: doc/classes/TileMap.xml:299
+msgid ""
+"If [code]true[/code], this tilemap's collision shape will be added to the "
+"collision shape of the parent. The parent has to be a [CollisionObject2D]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:302
+msgid ""
+"If [code]true[/code], the compatibility with the tilemaps made in Godot 3.1 "
+"or earlier is maintained (textures move when the tile origin changes and "
+"rotate if the texture size is not homogeneous). This mode presents problems "
+"when doing [code]flip_h[/code], [code]flip_v[/code] and [code]transpose[/"
+"code] tile operations on non-homogeneous isometric tiles (e.g. 2:1), in "
+"which the texture could not coincide with the collision, thus it is not "
+"recommended for isometric or non-square tiles.\n"
+"If [code]false[/code], the textures do not move when doing [code]flip_h[/"
+"code], [code]flip_v[/code] operations if no offset is used, nor when "
+"changing the tile origin.\n"
+"The compatibility mode doesn't work with the [member centered_textures] "
+"option, because displacing textures with the [member cell_tile_origin] "
+"option or in irregular tiles is not relevant when centering those textures."
+msgstr ""
+
+#: doc/classes/TileMap.xml:307
+msgid "The TileMap orientation mode. See [enum Mode] for possible values."
+msgstr ""
+
+#: doc/classes/TileMap.xml:310
+msgid ""
+"The light mask assigned to all light occluders in the TileMap. The TileSet's "
+"light occluders will cast shadows only from Light2D(s) that have the same "
+"light mask(s)."
+msgstr ""
+
+#: doc/classes/TileMap.xml:313
+msgid "The assigned [TileSet]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:319
+msgid "Emitted when a tilemap setting has changed."
+msgstr ""
+
+#: doc/classes/TileMap.xml:325
+msgid "Returned when a cell doesn't exist."
+msgstr ""
+
+#: doc/classes/TileMap.xml:328
+msgid "Orthogonal orientation mode."
+msgstr ""
+
+#: doc/classes/TileMap.xml:331
+msgid "Isometric orientation mode."
+msgstr ""
+
+#: doc/classes/TileMap.xml:334
+msgid "Custom orientation mode."
+msgstr ""
+
+#: doc/classes/TileMap.xml:337
+msgid "Half offset on the X coordinate."
+msgstr ""
+
+#: doc/classes/TileMap.xml:340
+msgid "Half offset on the Y coordinate."
+msgstr ""
+
+#: doc/classes/TileMap.xml:343
+msgid "Half offset disabled."
+msgstr ""
+
+#: doc/classes/TileMap.xml:346
+msgid "Half offset on the X coordinate (negative)."
+msgstr ""
+
+#: doc/classes/TileMap.xml:349
+msgid "Half offset on the Y coordinate (negative)."
+msgstr ""
+
+#: doc/classes/TileMap.xml:352
+msgid "Tile origin at its top-left corner."
+msgstr ""
+
+#: doc/classes/TileMap.xml:355
+msgid "Tile origin at its center."
+msgstr ""
+
+#: doc/classes/TileMap.xml:358
+msgid "Tile origin at its bottom-left corner."
+msgstr ""
+
+#: doc/classes/TileSet.xml:4
+msgid "Tile library for tilemaps."
+msgstr ""
+
+#: doc/classes/TileSet.xml:7
+msgid ""
+"A TileSet is a library of tiles for a [TileMap]. It contains a list of "
+"tiles, each consisting of a sprite and optional collision shapes.\n"
+"Tiles are referenced by a unique integer ID."
+msgstr ""
+
+#: doc/classes/TileSet.xml:55
+msgid "Clears all bitmask information of the autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:66
+msgid ""
+"Returns the bitmask of the subtile from an autotile given its coordinates.\n"
+"The value is the sum of the values in [enum AutotileBindings] present in the "
+"subtile (e.g. a value of 5 means the bitmask has bindings in both the top "
+"left and top right)."
+msgstr ""
+
+#: doc/classes/TileSet.xml:76
+msgid "Returns the [enum BitmaskMode] of the autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:85
+msgid ""
+"Returns the subtile that's being used as an icon in an atlas/autotile given "
+"its coordinates.\n"
+"The subtile defined as the icon will be used as a fallback when the atlas/"
+"autotile's bitmask information is incomplete. It will also be used to "
+"represent it in the TileSet editor."
+msgstr ""
+
+#: doc/classes/TileSet.xml:97
+msgid ""
+"Returns the light occluder of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:108
+msgid ""
+"Returns the navigation polygon of the subtile from an atlas/autotile given "
+"its coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:117
+msgid "Returns the size of the subtiles in an atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:126
+msgid "Returns the spacing between subtiles of the atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:137
+msgid ""
+"Returns the priority of the subtile from an autotile given its coordinates.\n"
+"When more than one subtile has the same bitmask value, one of them will be "
+"picked randomly for drawing. Its priority will define how often it will be "
+"picked."
+msgstr ""
+
+#: doc/classes/TileSet.xml:149
+msgid ""
+"Returns the drawing index of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:162
+msgid ""
+"Sets the bitmask of the subtile from an autotile given its coordinates.\n"
+"The value is the sum of the values in [enum AutotileBindings] present in the "
+"subtile (e.g. a value of 5 means the bitmask has bindings in both the top "
+"left and top right)."
+msgstr ""
+
+#: doc/classes/TileSet.xml:174
+msgid "Sets the [enum BitmaskMode] of the autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:185
+msgid ""
+"Sets the subtile that will be used as an icon in an atlas/autotile given its "
+"coordinates.\n"
+"The subtile defined as the icon will be used as a fallback when the atlas/"
+"autotile's bitmask information is incomplete. It will also be used to "
+"represent it in the TileSet editor."
+msgstr ""
+
+#: doc/classes/TileSet.xml:199
+msgid ""
+"Sets the light occluder of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:212
+msgid ""
+"Sets the navigation polygon of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:223
+msgid "Sets the size of the subtiles in an atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:234
+msgid "Sets the spacing between subtiles of the atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:247
+msgid ""
+"Sets the priority of the subtile from an autotile given its coordinates.\n"
+"When more than one subtile has the same bitmask value, one of them will be "
+"picked randomly for drawing. Its priority will define how often it will be "
+"picked."
+msgstr ""
+
+#: doc/classes/TileSet.xml:261
+msgid ""
+"Sets the drawing index of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:268
+msgid "Clears all tiles."
+msgstr ""
+
+#: doc/classes/TileSet.xml:277
+msgid "Creates a new tile with the given ID."
+msgstr ""
+
+#: doc/classes/TileSet.xml:286
+msgid "Returns the first tile matching the given name."
+msgstr ""
+
+#: doc/classes/TileSet.xml:293
+msgid ""
+"Returns the ID following the last currently used ID, useful when creating a "
+"new tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:300
+msgid "Returns an array of all currently used tile IDs."
+msgstr ""
+
+#: doc/classes/TileSet.xml:309
+msgid "Removes the given tile ID."
+msgstr ""
+
+#: doc/classes/TileSet.xml:326
+msgid "Adds a shape to the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:335
+msgid "Returns the tile's light occluder."
+msgstr ""
+
+#: doc/classes/TileSet.xml:344
+msgid "Returns the tile's material."
+msgstr ""
+
+#: doc/classes/TileSet.xml:353
+msgid "Returns the tile's modulation color."
+msgstr ""
+
+#: doc/classes/TileSet.xml:362
+msgid "Returns the tile's name."
+msgstr ""
+
+#: doc/classes/TileSet.xml:371
+msgid "Returns the navigation polygon of the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:380
+msgid "Returns the offset of the tile's navigation polygon."
+msgstr ""
+
+#: doc/classes/TileSet.xml:389
+msgid "Returns the tile's normal map texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:398
+msgid "Returns the offset of the tile's light occluder."
+msgstr ""
+
+#: doc/classes/TileSet.xml:407
+msgid "Returns the tile sub-region in the texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:418
+msgid "Returns a tile's given shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:427
+msgid "Returns the number of shapes assigned to a tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:438
+msgid "Returns the offset of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:449
+msgid "Returns the one-way collision value of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:470
+msgid "Returns the [Transform2D] of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:479
+msgid "Returns an array of the tile's shapes."
+msgstr ""
+
+#: doc/classes/TileSet.xml:488
+msgid "Returns the tile's texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:497
+msgid "Returns the texture offset of the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:506
+msgid "Returns the tile's [enum TileMode]."
+msgstr ""
+
+#: doc/classes/TileSet.xml:515
+msgid "Returns the tile's Z index (drawing layer)."
+msgstr ""
+
+#: doc/classes/TileSet.xml:526
+msgid "Sets a light occluder for the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:537
+msgid "Sets the tile's material."
+msgstr ""
+
+#: doc/classes/TileSet.xml:548
+msgid "Sets the tile's modulation color."
+msgstr ""
+
+#: doc/classes/TileSet.xml:559
+msgid "Sets the tile's name."
+msgstr ""
+
+#: doc/classes/TileSet.xml:570
+msgid "Sets the tile's navigation polygon."
+msgstr ""
+
+#: doc/classes/TileSet.xml:581
+msgid "Sets an offset for the tile's navigation polygon."
+msgstr ""
+
+#: doc/classes/TileSet.xml:592
+msgid "Sets the tile's normal map texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:603
+msgid "Sets an offset for the tile's light occluder."
+msgstr ""
+
+#: doc/classes/TileSet.xml:614
+msgid ""
+"Sets the tile's sub-region in the texture. This is common in texture atlases."
+msgstr ""
+
+#: doc/classes/TileSet.xml:627
+msgid "Sets a shape for the tile, enabling collision."
+msgstr ""
+
+#: doc/classes/TileSet.xml:640
+msgid "Sets the offset of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:653
+msgid "Enables one-way collision on a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:678
+msgid "Sets a [Transform2D] on a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:689
+msgid "Sets an array of shapes for the tile, enabling collision."
+msgstr ""
+
+#: doc/classes/TileSet.xml:700
+msgid "Sets the tile's texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:711
+msgid "Sets the tile's texture offset."
+msgstr ""
+
+#: doc/classes/TileSet.xml:722
+msgid "Sets the tile's [enum TileMode]."
+msgstr ""
+
+#: doc/classes/TileSet.xml:733
+msgid "Sets the tile's drawing index."
+msgstr ""
+
+#: doc/classes/Timer.xml:4
+msgid "A countdown timer."
+msgstr ""
+
+#: doc/classes/Timer.xml:7
+msgid ""
+"Counts down a specified interval and emits a signal on reaching 0. Can be "
+"set to repeat or \"one-shot\" mode."
+msgstr ""
+
+#: doc/classes/Timer.xml:16
+msgid "Returns [code]true[/code] if the timer is stopped."
+msgstr ""
+
+#: doc/classes/Timer.xml:25
+msgid ""
+"Starts the timer. Sets [code]wait_time[/code] to [code]time_sec[/code] if "
+"[code]time_sec > 0[/code]. This also resets the remaining time to "
+"[code]wait_time[/code].\n"
+"[b]Note:[/b] this method will not resume a paused timer. See [member paused]."
+msgstr ""
+
+#: doc/classes/Timer.xml:33
+msgid "Stops the timer."
+msgstr ""
+
+#: doc/classes/Timer.xml:39
+msgid ""
+"If [code]true[/code], the timer will automatically start when entering the "
+"scene tree.\n"
+"[b]Note:[/b] This property is automatically set to [code]false[/code] after "
+"the timer enters the scene tree and starts."
+msgstr ""
+
+#: doc/classes/Timer.xml:43
+msgid ""
+"If [code]true[/code], the timer will stop when reaching 0. If [code]false[/"
+"code], it will restart."
+msgstr ""
+
+#: doc/classes/Timer.xml:46
+msgid ""
+"If [code]true[/code], the timer is paused and will not process until it is "
+"unpaused again, even if [method start] is called."
+msgstr ""
+
+#: doc/classes/Timer.xml:49
+msgid "Processing mode. See [enum TimerProcessMode]."
+msgstr ""
+
+#: doc/classes/Timer.xml:52
+msgid ""
+"The timer's remaining time in seconds. Returns 0 if the timer is inactive.\n"
+"[b]Note:[/b] You cannot set this value. To change the timer's remaining "
+"time, use [method start]."
+msgstr ""
+
+#: doc/classes/Timer.xml:56
+msgid "Wait time in seconds."
+msgstr ""
+
+#: doc/classes/Timer.xml:68
+msgid ""
+"Update the timer during the physics step at each frame (fixed framerate "
+"processing)."
+msgstr ""
+
+#: doc/classes/Timer.xml:71
+msgid "Update the timer during the idle time at each frame."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:4
+msgid "Flat button helper class."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:7
+msgid ""
+"This is a helper class to generate a flat [Button] (see [member Button."
+"flat]), creating a [ToolButton] is equivalent to:\n"
+"[codeblock]\n"
+"var btn = Button.new()\n"
+"btn.flat = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ToolButton.xml:24
+msgid "[StyleBox] used when the [ToolButton] is disabled."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:27
+msgid ""
+"[StyleBox] used when the [ToolButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:30
+msgid "[Font] of the [ToolButton]'s text."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:33
+msgid "Default text [Color] of the [ToolButton]."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:36
+msgid "Text [Color] used when the [ToolButton] is disabled."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:39
+msgid "Text [Color] used when the [ToolButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:42
+msgid "Text [Color] used when the [ToolButton] is being pressed."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:45
+msgid "[StyleBox] used when the [ToolButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:48
+msgid "The horizontal space between [ToolButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:51
+msgid "Default [StyleBox] for the [ToolButton]."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:54
+msgid "[StyleBox] used when the [ToolButton] is being pressed."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:4
+msgid "Button for touch screen devices."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:7
+msgid ""
+"Button for touch screen devices. You can set it to be visible on all "
+"screens, or only on touch devices."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:16
+msgid "Returns [code]true[/code] if this button is currently pressed."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:22
+msgid "The button's action. Actions can be handled with [InputEventAction]."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:25
+msgid "The button's bitmask."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:28
+msgid "The button's texture for the normal state."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:31
+msgid "If [code]true[/code], pass-by presses are enabled."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:34
+msgid "The button's texture for the pressed state."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:37
+msgid "The button's shape."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:40
+msgid ""
+"If [code]true[/code], the button's shape is centered in the provided "
+"texture. If no texture is used, this property has no effect."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:43
+msgid "If [code]true[/code], the button's shape is visible."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:46
+msgid ""
+"The button's visibility mode. See [enum VisibilityMode] for possible values."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:52
+msgid "Emitted when the button is pressed (down)."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:57
+msgid "Emitted when the button is released (up)."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:63
+msgid "Always visible."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:66
+msgid "Visible on touch screens only."
+msgstr ""
+
+#: doc/classes/Transform.xml:4
+msgid "3D transformation (3×4 matrix)."
+msgstr ""
+
+#: doc/classes/Transform.xml:7
+msgid ""
+"Represents one or many transformations in 3D space such as translation, "
+"rotation, or scaling. It consists of a [member basis] and an [member "
+"origin]. It is similar to a 3×4 matrix."
+msgstr ""
+
+#: doc/classes/Transform.xml:26
+msgid ""
+"Constructs the Transform from four [Vector3]. Each axis corresponds to local "
+"basis vectors (some of which may be scaled)."
+msgstr ""
+
+#: doc/classes/Transform.xml:37
+msgid "Constructs the Transform from a [Basis] and [Vector3]."
+msgstr ""
+
+#: doc/classes/Transform.xml:46
+msgid "Constructs the Transform from a [Transform2D]."
+msgstr ""
+
+#: doc/classes/Transform.xml:55
+msgid ""
+"Constructs the Transform from a [Quat]. The origin will be Vector3(0, 0, 0)."
+msgstr ""
+
+#: doc/classes/Transform.xml:64
+msgid ""
+"Constructs the Transform from a [Basis]. The origin will be Vector3(0, 0, 0)."
+msgstr ""
+
+#: doc/classes/Transform.xml:71
+msgid ""
+"Returns the inverse of the transform, under the assumption that the "
+"transformation is composed of rotation, scaling and translation."
+msgstr ""
+
+#: doc/classes/Transform.xml:82
+msgid "Interpolates the transform to other Transform by weight amount (0-1)."
+msgstr ""
+
+#: doc/classes/Transform.xml:89 doc/classes/Transform2D.xml:106
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/Transform.xml:98 doc/classes/Transform2D.xml:115
+msgid ""
+"Returns [code]true[/code] if this transform and [code]transform[/code] are "
+"approximately equal, by calling [code]is_equal_approx[/code] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Transform.xml:109
+msgid ""
+"Returns a copy of the transform rotated such that its -Z axis points towards "
+"the [code]target[/code] position.\n"
+"The transform will first be rotated around the given [code]up[/code] vector, "
+"and then fully aligned to the target by a further rotation around an axis "
+"perpendicular to both the [code]target[/code] and [code]up[/code] vectors.\n"
+"Operations take place in global space."
+msgstr ""
+
+#: doc/classes/Transform.xml:118 doc/classes/Transform2D.xml:122
+msgid ""
+"Returns the transform with the basis orthogonal (90 degrees), and normalized "
+"axis vectors."
+msgstr ""
+
+#: doc/classes/Transform.xml:129
+msgid ""
+"Rotates the transform around the given axis by the given angle (in radians), "
+"using matrix multiplication. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Transform.xml:138 doc/classes/Transform2D.xml:140
+msgid ""
+"Scales the transform by the given scale factor, using matrix multiplication."
+msgstr ""
+
+#: doc/classes/Transform.xml:147 doc/classes/Transform2D.xml:149
+msgid ""
+"Translates the transform by the given offset, relative to the transform's "
+"basis vectors.\n"
+"Unlike [method rotated] and [method scaled], this does not use matrix "
+"multiplication."
+msgstr ""
+
+#: doc/classes/Transform.xml:157
+msgid ""
+"Transforms the given [Vector3], [Plane], [AABB], or [PackedVector3Array] by "
+"this transform."
+msgstr ""
+
+#: doc/classes/Transform.xml:166
+msgid ""
+"Inverse-transforms the given [Vector3], [Plane], [AABB], or "
+"[PackedVector3Array] by this transform."
+msgstr ""
+
+#: doc/classes/Transform.xml:172
+msgid ""
+"The basis is a matrix containing 3 [Vector3] as its columns: X axis, Y axis, "
+"and Z axis. These vectors can be interpreted as the basis vectors of local "
+"coordinate system traveling with the object."
+msgstr ""
+
+#: doc/classes/Transform.xml:175
+msgid "The translation offset of the transform."
+msgstr ""
+
+#: doc/classes/Transform.xml:180
+msgid ""
+"[Transform] with no translation, rotation or scaling applied. When applied "
+"to other data structures, [constant IDENTITY] performs no transformation."
+msgstr ""
+
+#: doc/classes/Transform.xml:183
+msgid "[Transform] with mirroring applied perpendicular to the YZ plane."
+msgstr ""
+
+#: doc/classes/Transform.xml:186
+msgid "[Transform] with mirroring applied perpendicular to the XZ plane."
+msgstr ""
+
+#: doc/classes/Transform.xml:189
+msgid "[Transform] with mirroring applied perpendicular to the XY plane."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:4
+msgid "2D transformation (3×2 matrix)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:7
+msgid ""
+"Represents one or many transformations in 2D space such as translation, "
+"rotation, or scaling. It consists of two [member x] and [member y] "
+"[Vector2]s and an [member origin]. It is similar to a 3×2 matrix."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:18
+msgid "Constructs the transform from a 3D [Transform]."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:31
+msgid ""
+"Constructs the transform from 3 [Vector2]s representing x, y, and origin."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:42
+msgid "Constructs the transform from a given angle (in radians) and position."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:58
+msgid "Transforms the given vector by this transform's basis (no translation)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:67
+msgid ""
+"Inverse-transforms the given vector by this transform's basis (no "
+"translation)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:74
+msgid "Returns the transform's origin (translation)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:81
+msgid "Returns the transform's rotation (in radians)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:88
+msgid "Returns the scale."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:99
+msgid ""
+"Returns a transform interpolated between this transform and another by a "
+"given weight (0-1)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:131
+msgid ""
+"Rotates the transform by the given angle (in radians), using matrix "
+"multiplication."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:159
+msgid ""
+"Transforms the given [Vector2], [Rect2], or [PackedVector2Array] by this "
+"transform."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:168
+msgid ""
+"Inverse-transforms the given [Vector2], [Rect2], or [PackedVector2Array] by "
+"this transform."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:174
+msgid "The transform's translation offset."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:177
+msgid ""
+"The X axis of 2×2 basis matrix containing 2 [Vector2]s as its columns: X "
+"axis and Y axis. These vectors can be interpreted as the basis vectors of "
+"local coordinate system traveling with the object."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:180
+msgid ""
+"The Y axis of 2×2 basis matrix containing 2 [Vector2]s as its columns: X "
+"axis and Y axis. These vectors can be interpreted as the basis vectors of "
+"local coordinate system traveling with the object."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:185
+msgid ""
+"[Transform2D] with no translation, rotation or scaling applied. When applied "
+"to other data structures, [constant IDENTITY] performs no transformation."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:188
+msgid "[Transform2D] with mirroring applied parallel to the X axis."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:191
+msgid "[Transform2D] with mirroring applied parallel to the Y axis."
+msgstr ""
+
+#: doc/classes/Translation.xml:4
+msgid "Language Translation."
+msgstr ""
+
+#: doc/classes/Translation.xml:7
+msgid ""
+"Translations are resources that can be loaded and unloaded on demand. They "
+"map a string to another string."
+msgstr ""
+
+#: doc/classes/Translation.xml:10 doc/classes/TranslationServer.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/i18n/"
+"internationalizing_games.html"
+msgstr ""
+
+#: doc/classes/Translation.xml:11 doc/classes/TranslationServer.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html"
+msgstr ""
+
+#: doc/classes/Translation.xml:22
+msgid "Adds a message if nonexistent, followed by its translation."
+msgstr ""
+
+#: doc/classes/Translation.xml:31
+msgid "Erases a message."
+msgstr ""
+
+#: doc/classes/Translation.xml:40
+msgid "Returns a message's translation."
+msgstr ""
+
+#: doc/classes/Translation.xml:47
+msgid "Returns the number of existing messages."
+msgstr ""
+
+#: doc/classes/Translation.xml:54
+msgid "Returns all the messages (keys)."
+msgstr ""
+
+#: doc/classes/Translation.xml:60
+msgid "The locale of the translation."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:4
+msgid "Server that manages all translations."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:7
+msgid ""
+"Server that manages all translations. Translations can be set to it and "
+"removed from it."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:20
+msgid "Adds a [Translation] resource."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:27
+msgid "Clears the server from all translations."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:34
+msgid "Returns an Array of all loaded locales of the game."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:41
+msgid "Returns the current locale of the game."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:50
+msgid ""
+"Returns a locale's language and its variant (e.g. [code]\"en_US\"[/code] "
+"would return [code]\"English (United States)\"[/code])."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:59
+msgid "Removes the given translation from the server."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:68
+msgid "Sets the locale of the game."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:77
+msgid "Returns the current locale's translation for the given message (key)."
+msgstr ""
+
+#: doc/classes/Tree.xml:4
+msgid "Control to show a tree of items."
+msgstr ""
+
+#: doc/classes/Tree.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" var tree = Tree.new()\n"
+" var root = tree.create_item()\n"
+" tree.set_hide_root(true)\n"
+" var child1 = tree.create_item(root)\n"
+" var child2 = tree.create_item(root)\n"
+" var subchild1 = tree.create_item(child1)\n"
+" subchild1.set_text(0, \"Subchild1\")\n"
+"[/codeblock]\n"
+"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]."
+msgstr ""
+
+#: doc/classes/Tree.xml:28
+msgid "Returns [code]true[/code] if the column titles are being shown."
+msgstr ""
+
+#: doc/classes/Tree.xml:35
+msgid "Clears the tree. This removes all items."
+msgstr ""
+
+#: doc/classes/Tree.xml:46
+msgid ""
+"Creates an item in the tree and adds it as a child of [code]parent[/code].\n"
+"If [code]parent[/code] is [code]null[/code], the root item will be the "
+"parent, or the new item will be the root itself if the tree is empty.\n"
+"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."
+msgstr ""
+
+#: doc/classes/Tree.xml:55
+msgid ""
+"Makes the currently focused cell visible.\n"
+"This will scroll the tree if necessary. In [constant SELECT_ROW] mode, this "
+"will not do horizontal scrolling, as all the cells in the selected row is "
+"focused logically.\n"
+"[b]Note:[/b] Despite the name of this method, the focus cursor itself is "
+"only visible in [constant SELECT_MULTI] mode."
+msgstr ""
+
+#: doc/classes/Tree.xml:66
+msgid ""
+"Returns the column index at [code]position[/code], or -1 if no item is there."
+msgstr ""
+
+#: doc/classes/Tree.xml:75
+msgid "Returns the column's title."
+msgstr ""
+
+#: doc/classes/Tree.xml:84
+msgid "Returns the column's width in pixels."
+msgstr ""
+
+#: doc/classes/Tree.xml:91
+msgid ""
+"Returns the rectangle for custom popups. Helper to create custom cell "
+"controls that display a popup. See [method TreeItem.set_cell_mode]."
+msgstr ""
+
+#: doc/classes/Tree.xml:100
+msgid ""
+"Returns the drop section at [code]position[/code], or -100 if no item is "
+"there.\n"
+"Values -1, 0, or 1 will be returned for the \"above item\", \"on item\", and "
+"\"below item\" drop sections, respectively. See [enum DropModeFlags] for a "
+"description of each drop section.\n"
+"To get the item which the returned drop section is relative to, use [method "
+"get_item_at_position]."
+msgstr ""
+
+#: doc/classes/Tree.xml:109
+msgid ""
+"Returns the currently edited item. This is only available for custom cell "
+"mode."
+msgstr ""
+
+#: doc/classes/Tree.xml:116
+msgid ""
+"Returns the column for the currently edited item. This is only available for "
+"custom cell mode."
+msgstr ""
+
+#: doc/classes/Tree.xml:127
+msgid ""
+"Returns the rectangle area for the specified item. If [code]column[/code] is "
+"specified, only get the position and size of that column, otherwise get the "
+"rectangle containing all columns."
+msgstr ""
+
+#: doc/classes/Tree.xml:136
+msgid ""
+"Returns the tree item at the specified position (relative to the tree origin "
+"position)."
+msgstr ""
+
+#: doc/classes/Tree.xml:145
+msgid ""
+"Returns the next selected item after the given one, or [code]null[/code] if "
+"the end is reached.\n"
+"If [code]from[/code] is [code]null[/code], this returns the first selected "
+"item."
+msgstr ""
+
+#: doc/classes/Tree.xml:153
+msgid "Returns the last pressed button's index."
+msgstr ""
+
+#: doc/classes/Tree.xml:160
+msgid ""
+"Returns the tree's root item, or [code]null[/code] if the tree is empty."
+msgstr ""
+
+#: doc/classes/Tree.xml:167
+msgid "Returns the current scrolling position."
+msgstr ""
+
+#: doc/classes/Tree.xml:174
+msgid ""
+"Returns the currently focused item, or [code]null[/code] if no item is "
+"focused.\n"
+"In [constant SELECT_ROW] and [constant SELECT_SINGLE] modes, the focused "
+"item is same as the selected item. In [constant SELECT_MULTI] mode, the "
+"focused item is the item under the focus cursor, not necessarily selected.\n"
+"To get the currently selected item(s), use [method get_next_selected]."
+msgstr ""
+
+#: doc/classes/Tree.xml:183
+msgid ""
+"Returns the currently focused column, or -1 if no column is focused.\n"
+"In [constant SELECT_SINGLE] mode, the focused column is the selected column. "
+"In [constant SELECT_ROW] mode, the focused column is always 0 if any item is "
+"selected. In [constant SELECT_MULTI] mode, the focused column is the column "
+"under the focus cursor, and there are not necessarily any column selected.\n"
+"To tell whether a column of an item is selected, use [method TreeItem."
+"is_selected]."
+msgstr ""
+
+#: doc/classes/Tree.xml:196
+msgid ""
+"If [code]true[/code], the column will have the \"Expand\" flag of [Control]. "
+"Columns that have the \"Expand\" flag will use their \"min_width\" in a "
+"similar fashion to [member Control.size_flags_stretch_ratio]."
+msgstr ""
+
+#: doc/classes/Tree.xml:207
+msgid ""
+"Sets the minimum width of a column. Columns that have the \"Expand\" flag "
+"will use their \"min_width\" in a similar fashion to [member Control."
+"size_flags_stretch_ratio]."
+msgstr ""
+
+#: doc/classes/Tree.xml:218
+msgid "Sets the title of a column."
+msgstr ""
+
+#: doc/classes/Tree.xml:227
+msgid "If [code]true[/code], column titles are visible."
+msgstr ""
+
+#: doc/classes/Tree.xml:233
+msgid ""
+"If [code]true[/code], the currently selected cell may be selected again."
+msgstr ""
+
+#: doc/classes/Tree.xml:236
+msgid "If [code]true[/code], a right mouse button click can select items."
+msgstr ""
+
+#: doc/classes/Tree.xml:239
+msgid "The number of columns."
+msgstr ""
+
+#: doc/classes/Tree.xml:242
+msgid ""
+"The drop mode as an OR combination of flags. See [enum DropModeFlags] "
+"constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. "
+"Setting this during [method Control.can_drop_data] is recommended.\n"
+"This controls the drop sections, i.e. the decision and drawing of possible "
+"drop locations based on the mouse position."
+msgstr ""
+
+#: doc/classes/Tree.xml:247
+msgid "If [code]true[/code], the folding arrow is hidden."
+msgstr ""
+
+#: doc/classes/Tree.xml:250
+msgid "If [code]true[/code], the tree's root is hidden."
+msgstr ""
+
+#: doc/classes/Tree.xml:254
+msgid ""
+"Allows single or multiple selection. See the [enum SelectMode] constants."
+msgstr ""
+
+#: doc/classes/Tree.xml:266
+msgid ""
+"Emitted when a button on the tree was pressed (see [method TreeItem."
+"add_button])."
+msgstr ""
+
+#: doc/classes/Tree.xml:271
+msgid "Emitted when a cell is selected."
+msgstr ""
+
+#: doc/classes/Tree.xml:278
+msgid "Emitted when a column's title is pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:285
+msgid ""
+"Emitted when a cell with the [constant TreeItem.CELL_MODE_CUSTOM] is clicked "
+"to be edited."
+msgstr ""
+
+#: doc/classes/Tree.xml:292
+msgid ""
+"Emitted when the right mouse button is pressed in the empty space of the "
+"tree."
+msgstr ""
+
+#: doc/classes/Tree.xml:299
+msgid ""
+"Emitted when the right mouse button is pressed if right mouse button "
+"selection is active and the tree is empty."
+msgstr ""
+
+#: doc/classes/Tree.xml:304
+msgid "Emitted when an item's label is double-clicked."
+msgstr ""
+
+#: doc/classes/Tree.xml:311
+msgid "Emitted when an item is collapsed by a click on the folding arrow."
+msgstr ""
+
+#: doc/classes/Tree.xml:316
+msgid ""
+"Emitted when a custom button is pressed (i.e. in a [constant TreeItem."
+"CELL_MODE_CUSTOM] mode cell)."
+msgstr ""
+
+#: doc/classes/Tree.xml:321
+msgid "Emitted when an item's icon is double-clicked."
+msgstr ""
+
+#: doc/classes/Tree.xml:326
+msgid "Emitted when an item is edited."
+msgstr ""
+
+#: doc/classes/Tree.xml:331
+msgid "Emitted when an item is edited using the right mouse button."
+msgstr ""
+
+#: doc/classes/Tree.xml:338
+msgid "Emitted when an item is selected with the right mouse button."
+msgstr ""
+
+#: doc/classes/Tree.xml:343
+msgid "Emitted when an item is selected."
+msgstr ""
+
+#: doc/classes/Tree.xml:354
+msgid ""
+"Emitted instead of [code]item_selected[/code] if [code]select_mode[/code] is "
+"[constant SELECT_MULTI]."
+msgstr ""
+
+#: doc/classes/Tree.xml:359
+msgid "Emitted when a left mouse button click does not select any item."
+msgstr ""
+
+#: doc/classes/Tree.xml:365
+msgid ""
+"Allows selection of a single cell at a time. From the perspective of items, "
+"only a single item is allowed to be selected. And there is only one column "
+"selected in the selected item.\n"
+"The focus cursor is always hidden in this mode, but it is positioned at the "
+"current selection, making the currently selected item the currently focused "
+"item."
+msgstr ""
+
+#: doc/classes/Tree.xml:369
+msgid ""
+"Allows selection of a single row at a time. From the perspective of items, "
+"only a single items is allowed to be selected. And all the columns are "
+"selected in the selected item.\n"
+"The focus cursor is always hidden in this mode, but it is positioned at the "
+"first column of the current selection, making the currently selected item "
+"the currently focused item."
+msgstr ""
+
+#: doc/classes/Tree.xml:373
+msgid ""
+"Allows selection of multiple cells at the same time. From the perspective of "
+"items, multiple items are allowed to be selected. And there can be multiple "
+"columns selected in each selected item.\n"
+"The focus cursor is visible in this mode, the item or column under the "
+"cursor is not necessarily selected."
+msgstr ""
+
+#: doc/classes/Tree.xml:377
+msgid ""
+"Disables all drop sections, but still allows to detect the \"on item\" drop "
+"section by [method get_drop_section_at_position].\n"
+"[b]Note:[/b] This is the default flag, it has no effect when combined with "
+"other flags."
+msgstr ""
+
+#: doc/classes/Tree.xml:381
+msgid ""
+"Enables the \"on item\" drop section. This drop section covers the entire "
+"item.\n"
+"When combined with [constant DROP_MODE_INBETWEEN], this drop section halves "
+"the height and stays centered vertically."
+msgstr ""
+
+#: doc/classes/Tree.xml:385
+msgid ""
+"Enables \"above item\" and \"below item\" drop sections. The \"above item\" "
+"drop section covers the top half of the item, and the \"below item\" drop "
+"section covers the bottom half.\n"
+"When combined with [constant DROP_MODE_ON_ITEM], these drop sections halves "
+"the height and stays on top / bottom accordingly."
+msgstr ""
+
+#: doc/classes/Tree.xml:391
+msgid "The arrow icon used when a foldable item is not collapsed."
+msgstr ""
+
+#: doc/classes/Tree.xml:394
+msgid "The arrow icon used when a foldable item is collapsed."
+msgstr ""
+
+#: doc/classes/Tree.xml:397
+msgid ""
+"Default [StyleBox] for the [Tree], i.e. used when the control is not being "
+"focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:400
+msgid "[StyleBox] used when the [Tree] is being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:403
+msgid "The horizontal space between each button in a cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:406
+msgid "[StyleBox] used when a button in the tree is pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:409
+msgid ""
+"The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode "
+"cell is checked."
+msgstr ""
+
+#: doc/classes/Tree.xml:412
+msgid "[StyleBox] used for the cursor, when the [Tree] is being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:415
+msgid "[StyleBox] used for the cursor, when the [Tree] is not being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:418
+msgid ""
+"Default [StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:421
+msgid ""
+"Text [Color] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's "
+"hovered."
+msgstr ""
+
+#: doc/classes/Tree.xml:424
+msgid ""
+"[StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's "
+"hovered."
+msgstr ""
+
+#: doc/classes/Tree.xml:427
+msgid ""
+"[StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's "
+"pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:430
+msgid ""
+"Draws the guidelines if not zero, this acts as a boolean. The guideline is a "
+"horizontal line drawn at the bottom of each item."
+msgstr ""
+
+#: doc/classes/Tree.xml:433
+msgid ""
+"Draws the relationship lines if not zero, this acts as a boolean. "
+"Relationship lines are drawn at the start of child items to show hierarchy."
+msgstr ""
+
+#: doc/classes/Tree.xml:436
+msgid ""
+"[Color] used to draw possible drop locations. See [enum DropModeFlags] "
+"constants for further description of drop locations."
+msgstr ""
+
+#: doc/classes/Tree.xml:448
+msgid "[Color] of the guideline."
+msgstr ""
+
+#: doc/classes/Tree.xml:451
+msgid ""
+"The horizontal space between item cells. This is also used as the margin at "
+"the start of an item when folding is disabled."
+msgstr ""
+
+#: doc/classes/Tree.xml:454
+msgid ""
+"The horizontal margin at the start of an item. This is used when folding is "
+"enabled for the item."
+msgstr ""
+
+#: doc/classes/Tree.xml:457
+msgid "[Color] of the relationship lines."
+msgstr ""
+
+#: doc/classes/Tree.xml:460
+msgid ""
+"The maximum distance between the mouse cursor and the control's border to "
+"trigger border scrolling when dragging."
+msgstr ""
+
+#: doc/classes/Tree.xml:463
+msgid "The speed of border scrolling."
+msgstr ""
+
+#: doc/classes/Tree.xml:466
+msgid ""
+"The arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] mode "
+"cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:469
+msgid ""
+"[StyleBox] for the selected items, used when the [Tree] is not being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:472
+msgid ""
+"[StyleBox] for the selected items, used when the [Tree] is being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:475
+msgid "Default text [Color] of the title button."
+msgstr ""
+
+#: doc/classes/Tree.xml:478
+msgid "[Font] of the title button's text."
+msgstr ""
+
+#: doc/classes/Tree.xml:481
+msgid "[StyleBox] used when the title button is being hovered."
+msgstr ""
+
+#: doc/classes/Tree.xml:484
+msgid "Default [StyleBox] for the title button."
+msgstr ""
+
+#: doc/classes/Tree.xml:487
+msgid "[StyleBox] used when the title button is being pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:490
+msgid ""
+"The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode "
+"cell is unchecked."
+msgstr ""
+
+#: doc/classes/Tree.xml:493
+msgid ""
+"The updown arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] "
+"mode cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:496
+msgid ""
+"The vertical padding inside each item, i.e. the distance between the item's "
+"content and top/bottom border."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:4
+msgid "Control for a single item inside a [Tree]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:7
+msgid ""
+"Control for a single item inside a [Tree]. May have child [TreeItem]s and be "
+"styled as well as contain buttons."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:26
+msgid ""
+"Adds a button with [Texture2D] [code]button[/code] at column [code]column[/"
+"code]. The [code]button_idx[/code] index is used to identify the button when "
+"calling other methods. If not specified, the next available index is used, "
+"which may be retrieved by calling [method get_button_count] immediately "
+"after this method. Optionally, the button can be [code]disabled[/code] and "
+"have a [code]tooltip[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:35
+msgid ""
+"Calls the [code]method[/code] on the actual TreeItem and its children "
+"recursively. Pass parameters as a comma separated list."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:44
+msgid "Resets the background color for the given column to default."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:53
+msgid "Resets the color for the given column to default."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:62
+msgid "Deselects the given column."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:73
+msgid ""
+"Removes the button at index [code]button_idx[/code] in column [code]column[/"
+"code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:84
+msgid ""
+"Returns the [Texture2D] of the button at index [code]button_idx[/code] in "
+"column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:93
+msgid ""
+"Returns the number of buttons in column [code]column[/code]. May be used to "
+"get the most recently added button's index, if no index was specified."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:104
+msgid ""
+"Returns the tooltip string for the button at index [code]button_idx[/code] "
+"in column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:113
+msgid "Returns the column's cell mode."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:120
+msgid "Returns the TreeItem's child items."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:129
+msgid "Returns the custom background color of column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:138
+msgid "Returns the custom color of column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:147
+msgid "Returns [code]true[/code] if [code]expand_right[/code] is set."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:156
+msgid "Returns the given column's icon [Texture2D]. Error if no icon is set."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:165
+msgid "Returns the column's icon's maximum width."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:174
+msgid "Returns the [Color] modulating the column's icon."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:183
+msgid "Returns the icon [Texture2D] region as [Rect2]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:198
+msgid "Returns the next TreeItem in the tree."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:207
+msgid ""
+"Returns the next visible TreeItem in the tree.\n"
+"If [code]wrap[/code] is enabled, the method will wrap around to the first "
+"visible element in the tree when called on the last visible element, "
+"otherwise it returns [code]null[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:215
+msgid "Returns the parent TreeItem."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:222
+msgid "Returns the previous TreeItem in the tree."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:231
+msgid ""
+"Returns the previous visible TreeItem in the tree.\n"
+"If [code]wrap[/code] is enabled, the method will wrap around to the last "
+"visible element in the tree when called on the first visible element, "
+"otherwise it returns [code]null[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:257
+msgid "Returns the given column's text."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:266
+msgid "Returns the given column's text alignment."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:275
+msgid "Returns the given column's tooltip."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:286
+msgid ""
+"Returns [code]true[/code] if the button at index [code]button_idx[/code] for "
+"the given column is disabled."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:295
+msgid "Returns [code]true[/code] if the given column is checked."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:312
+msgid "Returns [code]true[/code] if column [code]column[/code] is editable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:321
+msgid "Returns [code]true[/code] if column [code]column[/code] is selectable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:330
+msgid "Returns [code]true[/code] if column [code]column[/code] is selected."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:337
+msgid "Moves this TreeItem to the bottom in the [Tree] hierarchy."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:344
+msgid "Moves this TreeItem to the top in the [Tree] hierarchy."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:353
+msgid "Removes the given child TreeItem."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:362
+msgid "Selects the column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:375
+msgid ""
+"Sets the given column's button [Texture2D] at index [code]button_idx[/code] "
+"to [code]button[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:388
+msgid ""
+"If [code]true[/code], disables the button at index [code]button_idx[/code] "
+"in column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:399
+msgid ""
+"Sets the given column's cell mode to [code]mode[/code]. See [enum "
+"TreeCellMode] constants."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:410
+msgid "If [code]true[/code], the column [code]column[/code] is checked."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:433
+msgid ""
+"Sets the given column's custom background color and whether to just use it "
+"as an outline."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:444
+msgid "Sets the given column's custom color."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:457
+msgid ""
+"Sets the given column's custom draw callback to [code]callback[/code] method "
+"on [code]object[/code].\n"
+"The [code]callback[/code] should accept two arguments: the [TreeItem] that "
+"is drawn and its position and size as a [Rect2]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:469
+msgid "If [code]true[/code], column [code]column[/code] is editable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:480
+msgid ""
+"If [code]true[/code], column [code]column[/code] is expanded to the right."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:491
+msgid "Sets the given column's icon [Texture2D]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:502
+msgid "Sets the given column's icon's maximum width."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:513
+msgid "Modulates the given column's icon with [code]modulate[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:524
+msgid "Sets the given column's icon's texture region."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:571
+msgid "If [code]true[/code], the given column is selectable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:592
+msgid ""
+"Sets the given column's text alignment. See [enum TextAlign] for possible "
+"values."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:603
+msgid "Sets the given column's tooltip text."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:609
+msgid "If [code]true[/code], the TreeItem is collapsed."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:612
+msgid "The custom minimum height."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:615
+msgid "If [code]true[/code], folding is disabled for this TreeItem."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:620
+msgid "Cell contains a string."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:623
+msgid "Cell can be checked."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:626
+msgid "Cell contains a range."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:629
+msgid "Cell contains an icon."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:634
+msgid "Align text to the left. See [code]set_text_align()[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:637
+msgid "Center text. See [code]set_text_align()[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:640
+msgid "Align text to the right. See [code]set_text_align()[/code]."
+msgstr ""
+
+#: doc/classes/TriangleMesh.xml:4
+msgid "Internal mesh type."
+msgstr ""
+
+#: doc/classes/TriangleMesh.xml:7
+msgid "Mesh type used internally for collision calculations."
+msgstr ""
+
+#: doc/classes/Tween.xml:4
+msgid "Smoothly animates a node's properties over time."
+msgstr ""
+
+#: doc/classes/Tween.xml:7
+msgid ""
+"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.\n"
+"[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.\n"
+"Here is a brief usage example that causes a 2D node to move smoothly between "
+"two positions:\n"
+"[codeblock]\n"
+"var tween = get_node(\"Tween\")\n"
+"tween.interpolate_property($Node2D, \"position\",\n"
+" Vector2(0, 0), Vector2(100, 100), 1,\n"
+" Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)\n"
+"tween.start()\n"
+"[/codeblock]\n"
+"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.\n"
+"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 [code]http://easings.net/"
+"[/code] for some examples). The second accepts an [enum EaseType] constant, "
+"and controls the where [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."
+msgstr ""
+
+#: doc/classes/Tween.xml:45
+msgid ""
+"Follows [code]method[/code] of [code]object[/code] and applies the returned "
+"value on [code]target_method[/code] of [code]target[/code], beginning from "
+"[code]initial_val[/code] for [code]duration[/code] seconds, [code]delay[/"
+"code] later. Methods are called with consecutive values.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:71
+msgid ""
+"Follows [code]property[/code] of [code]object[/code] and applies it on "
+"[code]target_property[/code] of [code]target[/code], beginning from "
+"[code]initial_val[/code] for [code]duration[/code] seconds, [code]delay[/"
+"code] seconds later.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:79
+msgid ""
+"Returns the total time needed for all tweens to end. If you have two tweens, "
+"one lasting 10 seconds and the other 20 seconds, it would return 20 seconds, "
+"as by that time all tweens would have finished."
+msgstr ""
+
+#: doc/classes/Tween.xml:102
+msgid ""
+"Calls [code]callback[/code] of [code]object[/code] after [code]duration[/"
+"code]. [code]arg1[/code]-[code]arg5[/code] are arguments to be passed to the "
+"callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:125
+msgid ""
+"Calls [code]callback[/code] of [code]object[/code] after [code]duration[/"
+"code] on the main thread (similar to [method Object.call_deferred]). "
+"[code]arg1[/code]-[code]arg5[/code] are arguments to be passed to the "
+"callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:148
+msgid ""
+"Animates [code]method[/code] of [code]object[/code] from [code]initial_val[/"
+"code] to [code]final_val[/code] for [code]duration[/code] seconds, "
+"[code]delay[/code] seconds later. Methods are called with consecutive "
+"values.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:172
+msgid ""
+"Animates [code]property[/code] of [code]object[/code] from "
+"[code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] "
+"seconds, [code]delay[/code] seconds later. Setting the initial value to "
+"[code]null[/code] uses the current value of the property.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:180
+msgid ""
+"Returns [code]true[/code] if any tweens are currently running.\n"
+"[b]Note:[/b] This method doesn't consider tweens that have ended."
+msgstr ""
+
+#: doc/classes/Tween.xml:192
+msgid ""
+"Stops animation and removes a tween, given its object and property/method "
+"pair. By default, all tweens are removed, unless [code]key[/code] is "
+"specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:199
+msgid "Stops animation and removes all tweens."
+msgstr ""
+
+#: doc/classes/Tween.xml:210
+msgid ""
+"Resets a tween to its initial value (the one given, not the one before the "
+"tween), given its object and property/method pair. By default, all tweens "
+"are removed, unless [code]key[/code] is specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:217
+msgid ""
+"Resets all tweens to their initial values (the ones given, not those before "
+"the tween)."
+msgstr ""
+
+#: doc/classes/Tween.xml:228
+msgid ""
+"Continues animating a stopped tween, given its object and property/method "
+"pair. By default, all tweens are resumed, unless [code]key[/code] is "
+"specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:235
+msgid "Continues animating all stopped tweens."
+msgstr ""
+
+#: doc/classes/Tween.xml:244
+msgid "Sets the interpolation to the given [code]time[/code] in seconds."
+msgstr ""
+
+#: doc/classes/Tween.xml:253
+msgid ""
+"Activates/deactivates the tween. See also [method stop_all] and [method "
+"resume_all]."
+msgstr ""
+
+#: doc/classes/Tween.xml:260
+msgid "Starts the tween. You can define animations both before and after this."
+msgstr ""
+
+#: doc/classes/Tween.xml:271
+msgid ""
+"Stops a tween, given its object and property/method pair. By default, all "
+"tweens are stopped, unless [code]key[/code] is specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:278
+msgid "Stops animating all tweens."
+msgstr ""
+
+#: doc/classes/Tween.xml:303
+msgid ""
+"Animates [code]method[/code] of [code]object[/code] from the value returned "
+"by [code]initial_method[/code] to [code]final_val[/code] for [code]duration[/"
+"code] seconds, [code]delay[/code] seconds later. Methods are animated by "
+"calling them with consecutive values.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:329
+msgid ""
+"Animates [code]property[/code] of [code]object[/code] from the current value "
+"of the [code]initial_val[/code] property of [code]initial[/code] to "
+"[code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] "
+"seconds later.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:337
+msgid "Returns the current time of the tween."
+msgstr ""
+
+#: doc/classes/Tween.xml:343
+msgid "The tween's animation process thread. See [enum TweenProcessMode]."
+msgstr ""
+
+#: doc/classes/Tween.xml:346
+msgid ""
+"The tween's speed multiplier. For example, set it to [code]1.0[/code] for "
+"normal speed, [code]2.0[/code] for two times normal speed, or [code]0.5[/"
+"code] for half of the normal speed. A value of [code]0[/code] pauses the "
+"animation, but see also [method set_active] or [method stop_all] for this."
+msgstr ""
+
+#: doc/classes/Tween.xml:349
+msgid "If [code]true[/code], the tween loops."
+msgstr ""
+
+#: doc/classes/Tween.xml:355
+msgid "Emitted when all processes in a tween end."
+msgstr ""
+
+#: doc/classes/Tween.xml:364
+msgid "Emitted when a tween ends."
+msgstr ""
+
+#: doc/classes/Tween.xml:373
+msgid "Emitted when a tween starts."
+msgstr ""
+
+#: doc/classes/Tween.xml:386
+msgid "Emitted at each step of the animation."
+msgstr ""
+
+#: doc/classes/Tween.xml:392
+msgid "The tween updates with the [code]_physics_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:395
+msgid "The tween updates with the [code]_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:398
+msgid "The animation is interpolated linearly."
+msgstr ""
+
+#: doc/classes/Tween.xml:401
+msgid "The animation is interpolated using a sine function."
+msgstr ""
+
+#: doc/classes/Tween.xml:404
+msgid ""
+"The animation is interpolated with a quintic (to the power of 5) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:407
+msgid ""
+"The animation is interpolated with a quartic (to the power of 4) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:410
+msgid ""
+"The animation is interpolated with a quadratic (to the power of 2) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:413
+msgid ""
+"The animation is interpolated with an exponential (to the power of x) "
+"function."
+msgstr ""
+
+#: doc/classes/Tween.xml:416
+msgid ""
+"The animation is interpolated with elasticity, wiggling around the edges."
+msgstr ""
+
+#: doc/classes/Tween.xml:419
+msgid ""
+"The animation is interpolated with a cubic (to the power of 3) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:422
+msgid "The animation is interpolated with a function using square roots."
+msgstr ""
+
+#: doc/classes/Tween.xml:425
+msgid "The animation is interpolated by bouncing at the end."
+msgstr ""
+
+#: doc/classes/Tween.xml:428
+msgid "The animation is interpolated backing out at ends."
+msgstr ""
+
+#: doc/classes/Tween.xml:431
+msgid "The interpolation starts slowly and speeds up towards the end."
+msgstr ""
+
+#: doc/classes/Tween.xml:434
+msgid "The interpolation starts quickly and slows down towards the end."
+msgstr ""
+
+#: doc/classes/Tween.xml:437
+msgid ""
+"A combination of [constant EASE_IN] and [constant EASE_OUT]. The "
+"interpolation is slowest at both ends."
+msgstr ""
+
+#: doc/classes/Tween.xml:440
+msgid ""
+"A combination of [constant EASE_IN] and [constant EASE_OUT]. The "
+"interpolation is fastest at both ends."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:4
+msgid "Helper class to implement a UDP server."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:7
+msgid ""
+"A simple server that opens a UDP socket and returns connected "
+"[PacketPeerUDP] upon receiving new packets. See also [method PacketPeerUDP."
+"connect_to_host].\n"
+"Below a small example of how it can be used:\n"
+"[codeblock]\n"
+"# server.gd\n"
+"extends Node\n"
+"\n"
+"var server := UDPServer.new()\n"
+"var peers = []\n"
+"\n"
+"func _ready():\n"
+" server.listen(4242)\n"
+"\n"
+"func _process(delta):\n"
+" if server.is_connection_available():\n"
+" var peer : PacketPeerUDP = server.take_connection()\n"
+" var pkt = peer.get_packet()\n"
+" print(\"Accepted peer: %s:%s\" % [peer.get_packet_ip(), peer."
+"get_packet_port()])\n"
+" print(\"Received data: %s\" % [pkt.get_string_from_utf8()])\n"
+" # Reply so it knows we received the message.\n"
+" peer.put_packet(pkt)\n"
+" # Keep a reference so we can keep contacting the remote peer.\n"
+" peers.append(peer)\n"
+"\n"
+" for i in range(0, peers.size()):\n"
+" pass # Do something with the connected peers.\n"
+"\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# client.gd\n"
+"extends Node\n"
+"\n"
+"var udp := PacketPeerUDP.new()\n"
+"var connected = false\n"
+"\n"
+"func _ready():\n"
+" udp.connect_to_host(\"127.0.0.1\", 4242)\n"
+"\n"
+"func _process(delta):\n"
+" if !connected:\n"
+" # Try to contact server\n"
+" udp.put_packet(\"The answer is... 42!\".to_utf8())\n"
+" if udp.get_available_packet_count() > 0:\n"
+" print(\"Connected: %s\" % udp.get_packet().get_string_from_utf8())\n"
+" connected = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/UDPServer.xml:60
+msgid ""
+"Returns [code]true[/code] if a packet with a new address/port combination is "
+"received on the socket."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:67
+msgid ""
+"Returns [code]true[/code] if the socket is open and listening on a port."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:78
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:85
+msgid ""
+"Stops the server, closing the UDP socket if open. Will not disconnect any "
+"connected [PacketPeerUDP]."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:92
+msgid ""
+"Returns a [PacketPeerUDP] connected to the address/port combination of the "
+"first packet in queue. Will return [code]null[/code] if no packet is in "
+"queue. See also [method PacketPeerUDP.connect_to_host]."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:4
+msgid "Helper to manage undo/redo operations in the editor or custom tools."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:7
+msgid ""
+"Helper to manage undo/redo operations in the editor or custom tools. It "
+"works by registering methods and property changes inside \"actions\".\n"
+"Common behavior is to create an action, then add do/undo calls to functions "
+"or property changes, then committing the action.\n"
+"Here's an example on how to add an action to the Godot editor's own "
+"[UndoRedo], from a plugin:\n"
+"[codeblock]\n"
+"var undo_redo = get_undo_redo() # Method of EditorPlugin.\n"
+"\n"
+"func do_something():\n"
+" pass # Put your code here.\n"
+"\n"
+"func undo_something():\n"
+" pass # Put here the code that reverts what's done by "
+"\"do_something()\".\n"
+"\n"
+"func _on_MyButton_pressed():\n"
+" var node = get_node(\"MyNode2D\")\n"
+" undo_redo.create_action(\"Move the node\")\n"
+" undo_redo.add_do_method(self, \"do_something\")\n"
+" undo_redo.add_undo_method(self, \"undo_something\")\n"
+" undo_redo.add_do_property(node, \"position\", Vector2(100,100))\n"
+" undo_redo.add_undo_property(node, \"position\", node.position)\n"
+" undo_redo.commit_action()\n"
+"[/codeblock]\n"
+"[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.\n"
+"If you don't need to register a method, you can leave [method add_do_method] "
+"and [method add_undo_method] out; the same goes for properties. You can also "
+"register more than one method/property."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:42
+msgid "Register a method that will be called when the action is committed."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:55
+msgid "Register a property value change for \"do\"."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:64
+msgid ""
+"Register a reference for \"do\" that will be erased if the \"do\" history is "
+"lost. This is useful mostly for new nodes created for the \"do\" call. Do "
+"not use for resources."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:75
+msgid "Register a method that will be called when the action is undone."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:88
+msgid "Register a property value change for \"undo\"."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:97
+msgid ""
+"Register a reference for \"undo\" that will be erased if the \"undo\" "
+"history is lost. This is useful mostly for nodes removed with the \"do\" "
+"call (not the \"undo\" call!)."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:106
+msgid ""
+"Clear the undo/redo history and associated references.\n"
+"Passing [code]false[/code] to [code]increase_version[/code] will prevent the "
+"version number to be increased from this."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:114
+msgid ""
+"Commit the action. All \"do\" methods/properties are called/set when this "
+"function is called."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:125
+msgid ""
+"Create a new action. After this is called, do all your calls to [method "
+"add_do_method], [method add_undo_method], [method add_do_property], and "
+"[method add_undo_property], then commit the action with [method "
+"commit_action].\n"
+"The way actions are merged is dictated by the [code]merge_mode[/code] "
+"argument. See [enum MergeMode] for details."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:133
+msgid "Gets the name of the current action."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:140
+msgid ""
+"Gets the version. Every time a new action is committed, the [UndoRedo]'s "
+"version number is increased automatically.\n"
+"This is useful mostly to check if something changed from a saved version."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:148
+msgid "Returns [code]true[/code] if a \"redo\" action is available."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:155
+msgid "Returns [code]true[/code] if an \"undo\" action is available."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:162
+msgid ""
+"Returns [code]true[/code] if the [UndoRedo] is currently committing the "
+"action, i.e. running its \"do\" method or property change (see [method "
+"commit_action])."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:169
+msgid "Redo the last action."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:176
+msgid "Undo the last action."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:183
+msgid "Called when [method undo] or [method redo] was called."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:189
+msgid "Makes \"do\"/\"undo\" operations stay in separate actions."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:192
+msgid ""
+"Makes so that the action's \"do\" operation is from the first action created "
+"and the \"undo\" operation is from the last subsequent action with the same "
+"name."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:195
+msgid "Makes subsequent actions with the same name be merged into one."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:4
+msgid "UPNP network functions."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:7
+msgid ""
+"Provides UPNP functionality to discover [UPNPDevice]s on the local network "
+"and execute commands on them, like managing port mappings (port forwarding) "
+"and querying the local and remote network IP address. Note that methods on "
+"this class are synchronous and block the calling thread.\n"
+"To forward a specific port:\n"
+"[codeblock]\n"
+"const PORT = 7777\n"
+"var upnp = UPNP.new()\n"
+"upnp.discover(2000, 2, \"InternetGatewayDevice\")\n"
+"upnp.add_port_mapping(port)\n"
+"[/codeblock]\n"
+"To close a specific port (e.g. after you have finished using it):\n"
+"[codeblock]\n"
+"upnp.delete_port_mapping(port)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:29
+msgid "Adds the given [UPNPDevice] to the list of discovered devices."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:46
+msgid ""
+"Adds a mapping to forward the external [code]port[/code] (between 1 and "
+"65535) on the default gateway (see [method get_gateway]) to the "
+"[code]internal_port[/code] on the local machine for the given protocol "
+"[code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP "
+"being the default). If a port mapping for the given port and protocol "
+"combination already exists on that gateway device, this method tries to "
+"overwrite it. If that is not desired, you can retrieve the gateway manually "
+"with [method get_gateway] and call [method add_port_mapping] on it, if any.\n"
+"If [code]internal_port[/code] is [code]0[/code] (the default), the same port "
+"number is used for both the external and the internal port (the [code]port[/"
+"code] value).\n"
+"The description ([code]desc[/code]) is shown in some router UIs and can be "
+"used to point out which application added the mapping. The mapping's lease "
+"duration can be limited by specifying a [code]duration[/code] (in seconds). "
+"However, some routers are incompatible with one or both of these, so use "
+"with caution and add fallback logic in case of errors to retry without them "
+"if in doubt.\n"
+"See [enum UPNPResult] for possible return values."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:56
+msgid "Clears the list of discovered devices."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:67
+msgid ""
+"Deletes the port mapping for the given port and protocol combination on the "
+"default gateway (see [method get_gateway]) if one exists. [code]port[/code] "
+"must be a valid port between 1 and 65535, [code]proto[/code] can be either "
+"[code]TCP[/code] or [code]UDP[/code]. See [enum UPNPResult] for possible "
+"return values."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:80
+msgid ""
+"Discovers local [UPNPDevice]s. Clears the list of previously discovered "
+"devices.\n"
+"Filters for IGD (InternetGatewayDevice) type devices by default, as those "
+"manage port forwarding. [code]timeout[/code] is the time to wait for "
+"responses in milliseconds. [code]ttl[/code] is the time-to-live; only touch "
+"this if you know what you're doing.\n"
+"See [enum UPNPResult] for possible return values."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:91
+msgid "Returns the [UPNPDevice] at the given [code]index[/code]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:98
+msgid "Returns the number of discovered [UPNPDevice]s."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:105
+msgid ""
+"Returns the default gateway. That is the first discovered [UPNPDevice] that "
+"is also a valid IGD (InternetGatewayDevice)."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:112
+msgid ""
+"Returns the external [IP] address of the default gateway (see [method "
+"get_gateway]) as string. Returns an empty string on error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:121
+msgid ""
+"Removes the device at [code]index[/code] from the list of discovered devices."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:132
+msgid ""
+"Sets the device at [code]index[/code] from the list of discovered devices to "
+"[code]device[/code]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:138
+msgid "If [code]true[/code], IPv6 is used for [UPNPDevice] discovery."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:141
+msgid ""
+"If [code]0[/code], the local port to use for discovery is chosen "
+"automatically by the system. If [code]1[/code], discovery will be done from "
+"the source port 1900 (same as destination port). Otherwise, the value will "
+"be used as the port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:144
+msgid ""
+"Multicast interface to use for discovery. Uses the default multicast "
+"interface if empty."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:149
+msgid "UPNP command or discovery was successful."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:152
+msgid ""
+"Not authorized to use the command on the [UPNPDevice]. May be returned when "
+"the user disabled UPNP on their router."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:155
+msgid ""
+"No port mapping was found for the given port, protocol combination on the "
+"given [UPNPDevice]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:158
+msgid "Inconsistent parameters."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:161
+msgid ""
+"No such entry in array. May be returned if a given port, protocol "
+"combination is not found on an [UPNPDevice]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:164
+msgid "The action failed."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:167
+msgid ""
+"The [UPNPDevice] does not allow wildcard values for the source IP address."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:170
+msgid "The [UPNPDevice] does not allow wildcard values for the external port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:173
+msgid "The [UPNPDevice] does not allow wildcard values for the internal port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:176
+msgid "The remote host value must be a wildcard."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:179
+msgid "The external port value must be a wildcard."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:182
+msgid ""
+"No port maps are available. May also be returned if port mapping "
+"functionality is not available."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:185
+msgid ""
+"Conflict with other mechanism. May be returned instead of [constant "
+"UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING] if a port mapping conflicts with an "
+"existing one."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:188
+msgid "Conflict with an existing port mapping."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:191
+msgid "External and internal port values must be the same."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:194
+msgid ""
+"Only permanent leases are supported. Do not use the [code]duration[/code] "
+"parameter when adding port mappings."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:197
+msgid "Invalid gateway."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:200
+msgid "Invalid port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:203
+msgid "Invalid protocol."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:206
+msgid "Invalid duration."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:209
+msgid "Invalid arguments."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:212
+msgid "Invalid response."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:215
+msgid "Invalid parameter."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:218
+#: modules/upnp/doc_classes/UPNPDevice.xml:80
+msgid "HTTP error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:221
+msgid "Socket error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:224
+msgid "Error allocating memory."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:227
+msgid ""
+"No gateway available. You may need to call [method discover] first, or "
+"discovery didn't detect any valid IGDs (InternetGatewayDevices)."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:230
+msgid ""
+"No devices available. You may need to call [method discover] first, or "
+"discovery didn't detect any valid [UPNPDevice]s."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:233
+#: modules/upnp/doc_classes/UPNPDevice.xml:104
+msgid "Unknown error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:4
+msgid "UPNP device."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:7
+msgid ""
+"UPNP device. See [UPNP] for UPNP discovery and utility functions. Provides "
+"low-level access to UPNP control commands. Allows to manage port mappings "
+"(port forwarding) and to query network information of the device (like local "
+"and external IP address and status). Note that methods on this class are "
+"synchronous and block the calling thread."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:26
+msgid ""
+"Adds a port mapping to forward the given external port on this [UPNPDevice] "
+"for the given protocol to the local machine. See [method UPNP."
+"add_port_mapping]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:37
+msgid ""
+"Deletes the port mapping identified by the given port and protocol "
+"combination on this device. See [method UPNP.delete_port_mapping]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:44
+msgid ""
+"Returns [code]true[/code] if this is a valid IGD (InternetGatewayDevice) "
+"which potentially supports port forwarding."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:51
+msgid ""
+"Returns the external IP address of this [UPNPDevice] or an empty string."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:57
+msgid "URL to the device description."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:60
+msgid "IDG control URL."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:63
+msgid ""
+"Address of the local machine in the network connecting it to this "
+"[UPNPDevice]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:66
+msgid "IGD service type."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:69
+msgid "IGD status. See [enum IGDStatus]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:72
+msgid "Service type."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:77
+msgid "OK."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:83
+msgid "Empty HTTP response."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:86
+msgid "Returned response contained no URLs."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:89
+msgid "Not a valid IGD."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:92
+msgid "Disconnected."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:95
+msgid "Unknown device."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:98
+msgid "Invalid control."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:101
+msgid "Memory allocation error."
+msgstr ""
+
+#: doc/classes/Variant.xml:4
+msgid "The most important data type in Godot."
+msgstr ""
+
+#: doc/classes/Variant.xml:7
+msgid ""
+"In computer programming, a Variant class is a class that is designed to "
+"store a variety of other types. Dynamic programming languages like PHP, Lua, "
+"JavaScript and GDScript like to use them to store variables' data on the "
+"backend. With these Variants, properties are able to change value types "
+"freely.\n"
+"[codeblock]\n"
+"var foo = 2 # foo is dynamically an integer\n"
+"foo = \"Now foo is a string!\"\n"
+"foo = Reference.new() # foo is an Object\n"
+"var bar: int = 2 # bar is a statically typed integer.\n"
+"# bar = \"Uh oh! I can't make static variables become a different type!\"\n"
+"[/codeblock]\n"
+"Godot tracks all scripting API variables within Variants. Without even "
+"realizing it, you use Variants all the time. When a particular language "
+"enforces its own rules for keeping data typed, then that language is "
+"applying its own custom logic over the base Variant scripting API.\n"
+"- GDScript automatically wrap values in them. It keeps all data in plain "
+"Variants by default and then optionally enforces custom static typing rules "
+"on variable types.\n"
+"- VisualScript tracks properties inside Variants as well, but it also uses "
+"static typing. The GUI interface enforces that properties have a particular "
+"type that doesn't change over time.\n"
+"- C# is statically typed, but uses the Mono [code]object[/code] type in "
+"place of Godot's Variant class when it needs to represent a dynamic value. "
+"[code]object[/code] is the Mono runtime's equivalent of the same concept.\n"
+"- The statically-typed language NativeScript C++ does not define a built-in "
+"Variant-like class. Godot's GDNative bindings provide their own godot::"
+"Variant class for users; Any point at which the C++ code starts interacting "
+"with the Godot runtime is a place where you might have to start wrapping "
+"data inside Variant objects.\n"
+"The global [method @GDScript.typeof] function returns the enumerated value "
+"of the Variant type stored in the current variable (see [enum Variant."
+"Type]).\n"
+"[codeblock]\n"
+"var foo = 2\n"
+"match typeof(foo):\n"
+" TYPE_NIL:\n"
+" print(\"foo is null\")\n"
+" TYPE_INTEGER:\n"
+" print(\"foo is an integer\")\n"
+" TYPE_OBJECT:\n"
+" # Note that Objects are their own special category.\n"
+" # To get the name of the underlying Object type, you need the "
+"`get_class()` method.\n"
+" print(\"foo is a(n) %s\" % foo.get_class()) # inject the class name "
+"into a formatted string.\n"
+" # Note also that there is not yet any way to get a script's "
+"`class_name` string easily.\n"
+" # To fetch that value, you need to dig deeply into a hidden "
+"ProjectSettings setting: an Array of Dictionaries called "
+"\"_global_script_classes\".\n"
+" # Open your project.godot file to see it up close.\n"
+"[/codeblock]\n"
+"A Variant takes up only 20 bytes and can store almost any engine datatype "
+"inside of it. Variants are rarely used to hold information for long periods "
+"of time. Instead, they are used mainly for communication, editing, "
+"serialization and moving data around.\n"
+"Godot has specifically invested in making its Variant class as flexible as "
+"possible; so much so that it is used for a multitude of operations to "
+"facilitate communication between all of Godot's systems.\n"
+"A Variant:\n"
+"- Can store almost any datatype.\n"
+"- Can perform operations between many variants. GDScript uses Variant as its "
+"atomic/native datatype.\n"
+"- Can be hashed, so it can be compared quickly to other variants.\n"
+"- Can be used to convert safely between datatypes.\n"
+"- Can be used to abstract calling methods and their arguments. Godot exports "
+"all its functions through variants.\n"
+"- Can be used to defer calls or move data between threads.\n"
+"- Can be serialized as binary and stored to disk, or transferred via "
+"network.\n"
+"- Can be serialized to text and use it for printing values and editable "
+"settings.\n"
+"- Can work as an exported property, so the editor can edit it universally.\n"
+"- Can be used for dictionaries, arrays, parsers, etc.\n"
+"[b]Containers (Array and Dictionary):[/b] Both are implemented using "
+"variants. A [Dictionary] can match any datatype used as key to any other "
+"datatype. An [Array] just holds an array of Variants. Of course, a Variant "
+"can also hold a [Dictionary] and an [Array] inside, making it even more "
+"flexible.\n"
+"Modifications to a container will modify all references to it. A [Mutex] "
+"should be created to lock it if multi-threaded access is desired."
+msgstr ""
+
+#: doc/classes/Variant.xml:53
+msgid ""
+"https://docs.godotengine.org/en/latest/development/cpp/variant_class.html"
+msgstr ""
+
+#: doc/classes/VBoxContainer.xml:4
+msgid "Vertical box container."
+msgstr ""
+
+#: doc/classes/VBoxContainer.xml:7
+msgid "Vertical box container. See [BoxContainer]."
+msgstr ""
+
+#: doc/classes/VBoxContainer.xml:17
+msgid "The vertical space between the [VBoxContainer]'s elements."
+msgstr ""
+
+#: doc/classes/Vector2.xml:4
+msgid "Vector used for 2D math using floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector2.xml:7
+msgid ""
+"2-element structure that can be used to represent positions in 2D space or "
+"any other pair of numeric values.\n"
+"It uses floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector2.xml:20
+msgid "Constructs a new [Vector2] from [Vector2i]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:31
+msgid ""
+"Constructs a new [Vector2] from the given [code]x[/code] and [code]y[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:38 doc/classes/Vector3.xml:40
+msgid ""
+"Returns a new vector with all components in absolute values (i.e. positive)."
+msgstr ""
+
+#: doc/classes/Vector2.xml:45
+msgid ""
+"Returns the vector's angle in radians with respect to the X axis, or [code]"
+"(1, 0)[/code] vector.\n"
+"Equivalent to the result of [method @GDScript.atan2] when called with the "
+"vector's [member x] and [member y] as parameters: [code]atan2(x, y)[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:55
+msgid "Returns the angle in radians between the two vectors."
+msgstr ""
+
+#: doc/classes/Vector2.xml:64
+msgid ""
+"Returns the angle in radians between the line connecting the two points and "
+"the X coordinate."
+msgstr ""
+
+#: doc/classes/Vector2.xml:71
+msgid "Returns the ratio of [member x] to [member y]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:80 doc/classes/Vector3.xml:58
+msgid ""
+"Returns the vector \"bounced off\" from a plane defined by the given normal."
+msgstr ""
+
+#: doc/classes/Vector2.xml:87
+msgid "Returns the vector with all components rounded up."
+msgstr ""
+
+#: doc/classes/Vector2.xml:96
+msgid "Returns the vector with a maximum length."
+msgstr ""
+
+#: doc/classes/Vector2.xml:105
+msgid ""
+"Returns the 2-dimensional analog of the cross product with the given vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:120
+msgid ""
+"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]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation."
+msgstr ""
+
+#: doc/classes/Vector2.xml:129 doc/classes/Vector3.xml:98
+msgid ""
+"Returns the normalized vector pointing from this vector to [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:138
+msgid ""
+"Returns the squared distance to vector [code]b[/code]. Prefer this function "
+"over [method distance_to] if you need to sort vectors or need the squared "
+"distance for some formula."
+msgstr ""
+
+#: doc/classes/Vector2.xml:147
+msgid "Returns the distance to vector [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:156
+msgid "Returns the dot product with vector [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:163
+msgid "Returns the vector with all components rounded down."
+msgstr ""
+
+#: doc/classes/Vector2.xml:172 doc/classes/Vector3.xml:148
+msgid ""
+"Returns [code]true[/code] if this vector and [code]v[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Vector2.xml:179 doc/classes/Vector3.xml:155
+msgid "Returns [code]true[/code] if the vector is normalized."
+msgstr ""
+
+#: doc/classes/Vector2.xml:186 doc/classes/Vector3.xml:162
+msgid "Returns the vector's length."
+msgstr ""
+
+#: doc/classes/Vector2.xml:193
+msgid ""
+"Returns the vector's length squared. Prefer this method over [method length] "
+"if you need to sort vectors or need the squared length for some formula."
+msgstr ""
+
+#: doc/classes/Vector2.xml:204
+msgid ""
+"Returns the result of the linear interpolation between this vector and "
+"[code]b[/code] by amount [code]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation."
+msgstr ""
+
+#: doc/classes/Vector2.xml:215 doc/classes/Vector3.xml:205
+msgid ""
+"Moves the vector toward [code]to[/code] by the fixed [code]delta[/code] "
+"amount."
+msgstr ""
+
+#: doc/classes/Vector2.xml:222 doc/classes/Vector3.xml:212
+msgid ""
+"Returns the vector scaled to unit length. Equivalent to [code]v / v.length()"
+"[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:231 doc/classes/Vector3.xml:230
+msgid ""
+"Returns a vector composed of the [code]fposmod[/code] of this vector's "
+"components and [code]mod[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:240 doc/classes/Vector3.xml:239
+msgid ""
+"Returns a vector composed of the [code]fposmod[/code] of this vector's "
+"components and [code]modv[/code]'s components."
+msgstr ""
+
+#: doc/classes/Vector2.xml:249 doc/classes/Vector3.xml:248
+msgid "Returns the vector projected onto the vector [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:258 doc/classes/Vector3.xml:257
+msgid "Returns the vector reflected from a plane defined by the given normal."
+msgstr ""
+
+#: doc/classes/Vector2.xml:267
+msgid ""
+"Returns the vector rotated by [code]phi[/code] radians. See also [method "
+"@GDScript.deg2rad]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:274 doc/classes/Vector3.xml:275
+msgid ""
+"Returns the vector with all components rounded to the nearest integer, with "
+"halfway cases rounded away from zero."
+msgstr ""
+
+#: doc/classes/Vector2.xml:281 doc/classes/Vector3.xml:282
+msgid ""
+"Returns the vector with each component set to one or negative one, depending "
+"on the signs of the components."
+msgstr ""
+
+#: doc/classes/Vector2.xml:292 doc/classes/Vector3.xml:293
+msgid ""
+"Returns the result of spherical linear interpolation between this vector and "
+"[code]b[/code], by amount [code]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation.\n"
+"[b]Note:[/b] Both vectors must be normalized."
+msgstr ""
+
+#: doc/classes/Vector2.xml:302 doc/classes/Vector3.xml:303
+msgid ""
+"Returns the component of the vector along a plane defined by the given "
+"normal."
+msgstr ""
+
+#: doc/classes/Vector2.xml:311
+msgid "Returns the vector snapped to a grid with the given size."
+msgstr ""
+
+#: doc/classes/Vector2.xml:318
+msgid "Returns a perpendicular vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:324 doc/classes/Vector3.xml:325
+msgid ""
+"The vector's X component. Also accessible by using the index position [code]"
+"[0][/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:327 doc/classes/Vector3.xml:328
+msgid ""
+"The vector's Y component. Also accessible by using the index position [code]"
+"[1][/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:332 doc/classes/Vector2i.xml:37
+#: doc/classes/Vector3i.xml:39
+msgid "Enumerated value for the X axis."
+msgstr ""
+
+#: doc/classes/Vector2.xml:335 doc/classes/Vector2i.xml:40
+#: doc/classes/Vector3i.xml:42
+msgid "Enumerated value for the Y axis."
+msgstr ""
+
+#: doc/classes/Vector2.xml:338 doc/classes/Vector2i.xml:43
+#: doc/classes/Vector3.xml:345 doc/classes/Vector3i.xml:48
+msgid "Zero vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:341 doc/classes/Vector2i.xml:46
+#: doc/classes/Vector3.xml:348 doc/classes/Vector3i.xml:51
+msgid "One vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:344 doc/classes/Vector3.xml:351
+msgid "Infinity vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:347 doc/classes/Vector2i.xml:49
+#: doc/classes/Vector3.xml:354 doc/classes/Vector3i.xml:54
+msgid "Left unit vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:350 doc/classes/Vector2i.xml:52
+#: doc/classes/Vector3.xml:357 doc/classes/Vector3i.xml:57
+msgid "Right unit vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:353 doc/classes/Vector2i.xml:55
+#: doc/classes/Vector3.xml:360 doc/classes/Vector3i.xml:60
+msgid "Up unit vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:356 doc/classes/Vector2i.xml:58
+#: doc/classes/Vector3.xml:363 doc/classes/Vector3i.xml:63
+msgid "Down unit vector."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:4
+msgid "Vector used for 2D math using integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:7
+msgid ""
+"2-element structure that can be used to represent positions in 2D space or "
+"any other pair of numeric values.\n"
+"It uses integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:22
+msgid ""
+"Constructs a new [Vector2i] from the given [code]x[/code] and [code]y[/code]."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:31
+msgid ""
+"Constructs a new [Vector2i] from [Vector2]. The floating point coordinates "
+"will be truncated."
+msgstr ""
+
+#: doc/classes/Vector3.xml:4
+msgid "Vector used for 3D math using floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector3.xml:7
+msgid ""
+"3-element structure that can be used to represent positions in 3D space or "
+"any other pair of numeric values.\n"
+"It uses floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector3.xml:20
+msgid "Constructs a new [Vector3] from [Vector3i]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:33
+msgid "Returns a [Vector3] with the given components."
+msgstr ""
+
+#: doc/classes/Vector3.xml:49
+msgid "Returns the minimum angle to the given vector."
+msgstr ""
+
+#: doc/classes/Vector3.xml:65
+msgid "Returns a new vector with all components rounded up."
+msgstr ""
+
+#: doc/classes/Vector3.xml:74
+msgid "Returns the cross product with [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:89
+msgid ""
+"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]t[/code]. [code]t[/code] is in the range of [code]0.0 "
+"- 1.0[/code], representing the amount of interpolation."
+msgstr ""
+
+#: doc/classes/Vector3.xml:107
+msgid ""
+"Returns the squared distance to [code]b[/code]. Prefer this function over "
+"[method distance_to] if you need to sort vectors or need the squared "
+"distance for some formula."
+msgstr ""
+
+#: doc/classes/Vector3.xml:116
+msgid "Returns the distance to [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:125
+msgid "Returns the dot product with [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:132
+msgid "Returns a new vector with all components rounded down."
+msgstr ""
+
+#: doc/classes/Vector3.xml:139
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:169
+msgid ""
+"Returns the vector's length squared. Prefer this function over [method "
+"length] if you need to sort vectors or need the squared length for some "
+"formula."
+msgstr ""
+
+#: doc/classes/Vector3.xml:180
+msgid ""
+"Returns the result of the linear interpolation between this vector and "
+"[code]b[/code] by amount [code]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation.."
+msgstr ""
+
+#: doc/classes/Vector3.xml:187
+msgid ""
+"Returns the axis of the vector's largest value. See [code]AXIS_*[/code] "
+"constants."
+msgstr ""
+
+#: doc/classes/Vector3.xml:194
+msgid ""
+"Returns the axis of the vector's smallest value. See [code]AXIS_*[/code] "
+"constants."
+msgstr ""
+
+#: doc/classes/Vector3.xml:221
+msgid "Returns the outer product with [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:268
+msgid ""
+"Rotates the vector around a given axis by [code]phi[/code] radians. The axis "
+"must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Vector3.xml:312
+msgid "Returns a copy of the vector snapped to the lowest neared multiple."
+msgstr ""
+
+#: doc/classes/Vector3.xml:319
+msgid "Returns a diagonal matrix with the vector as main diagonal."
+msgstr ""
+
+#: doc/classes/Vector3.xml:331
+msgid ""
+"The vector's Z component. Also accessible by using the index position [code]"
+"[2][/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:336
+msgid ""
+"Enumerated value for the X axis. Returned by [method max_axis] and [method "
+"min_axis]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:339
+msgid ""
+"Enumerated value for the Y axis. Returned by [method max_axis] and [method "
+"min_axis]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:342
+msgid ""
+"Enumerated value for the Z axis. Returned by [method max_axis] and [method "
+"min_axis]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:366 doc/classes/Vector3i.xml:66
+msgid "Forward unit vector."
+msgstr ""
+
+#: doc/classes/Vector3.xml:369 doc/classes/Vector3i.xml:69
+msgid "Back unit vector."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:4
+msgid "Vector used for 3D math using integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:7
+msgid ""
+"3-element structure that can be used to represent positions in 3D space or "
+"any other pair of numeric values.\n"
+"It uses integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:24
+msgid "Returns a [Vector3i] with the given components."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:33
+msgid ""
+"Constructs a new [Vector3i] from [Vector3]. The floating point coordinates "
+"will be truncated."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:45
+msgid "Enumerated value for the Z axis."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:4
+msgid "Physics body that simulates the behavior of a car."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:7
+msgid ""
+"This node implements all the physics logic needed to simulate a car. It is "
+"based on the raycast vehicle system commonly found in physics engines. You "
+"will need to add a [CollisionShape3D] for the main body of your vehicle and "
+"add [VehicleWheel3D] nodes for the wheels. You should also add a "
+"[MeshInstance3D] to this node for the 3D model of your car but this model "
+"should not include meshes for the wheels. You should control the vehicle by "
+"using the [member brake], [member engine_force], and [member steering] "
+"properties and not change the position or orientation of this node "
+"directly.\n"
+"[b]Note:[/b] The origin point of your VehicleBody3D will determine the "
+"center of gravity of your vehicle so it is better to keep this low and move "
+"the [CollisionShape3D] and [MeshInstance3D] upwards."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:16
+msgid ""
+"Slows down the vehicle by applying a braking force. The vehicle is only "
+"slowed down if the wheels are in contact with a surface. The force you need "
+"to apply to adequately slow down your vehicle depends on the [member "
+"RigidBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try "
+"a value in the 25 - 30 range for hard braking."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:19
+msgid ""
+"Accelerates the vehicle by applying an engine force. The vehicle is only "
+"speed up if the wheels that have [member VehicleWheel3D.use_as_traction] set "
+"to [code]true[/code] and are in contact with a surface. The [member "
+"RigidBody3D.mass] of the vehicle has an effect on the acceleration of the "
+"vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 "
+"range for acceleration.\n"
+"[b]Note:[/b] The simulation does not take the effect of gears into account, "
+"you will need to add logic for this if you wish to simulate gears.\n"
+"A negative value will result in the vehicle reversing."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:25
+msgid ""
+"The steering angle for the vehicle. Setting this to a non-zero value will "
+"result in the vehicle turning when it's moving. Wheels that have [member "
+"VehicleWheel3D.use_as_steering] set to [code]true[/code] will automatically "
+"be rotated."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:4
+msgid "Physics object that simulates the behavior of a wheel."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:7
+msgid ""
+"This node needs to be used as a child node of [VehicleBody3D] and simulates "
+"the behavior of one of its wheels. This node also acts as a collider to "
+"detect if the wheel is touching a surface."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:16
+msgid "Returns the rotational speed of the wheel in revolutions per minute."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:23
+msgid ""
+"Returns a value between 0.0 and 1.0 that indicates whether this wheel is "
+"skidding. 0.0 is skidding (the wheel has lost grip, e.g. icy terrain), 1.0 "
+"means not skidding (the wheel has full grip, e.g. dry asphalt road)."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:30
+msgid "Returns [code]true[/code] if this wheel is in contact with a surface."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:36
+msgid ""
+"Slows down the wheel by applying a braking force. The wheel is only slowed "
+"down if it is in contact with a surface. The force you need to apply to "
+"adequately slow down your vehicle depends on the [member RigidBody3D.mass] "
+"of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 "
+"- 30 range for hard braking."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:39
+msgid ""
+"The damping applied to the spring when the spring is being compressed. This "
+"value should be between 0.0 (no damping) and 1.0. A value of 0.0 means the "
+"car will keep bouncing as the spring keeps its energy. A good value for this "
+"is around 0.3 for a normal car, 0.5 for a race car."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:42
+msgid ""
+"The damping applied to the spring when relaxing. This value should be "
+"between 0.0 (no damping) and 1.0. This value should always be slightly "
+"higher than the [member damping_compression] property. For a [member "
+"damping_compression] value of 0.3, try a relaxation value of 0.5."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:45
+msgid ""
+"Accelerates the wheel by applying an engine force. The wheel is only speed "
+"up if it is in contact with a surface. The [member RigidBody3D.mass] of the "
+"vehicle has an effect on the acceleration of the vehicle. For a vehicle with "
+"a mass set to 1000, try a value in the 25 - 50 range for acceleration.\n"
+"[b]Note:[/b] The simulation does not take the effect of gears into account, "
+"you will need to add logic for this if you wish to simulate gears.\n"
+"A negative value will result in the wheel reversing."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:50
+msgid ""
+"The steering angle for the wheel. Setting this to a non-zero value will "
+"result in the vehicle turning when it's moving."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:53
+msgid ""
+"The maximum force the spring can resist. This value should be higher than a "
+"quarter of the [member RigidBody3D.mass] of the [VehicleBody3D] or the "
+"spring will not carry the weight of the vehicle. Good results are often "
+"obtained by a value that is about 3× to 4× this number."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:56
+msgid ""
+"This value defines the stiffness of the suspension. Use a value lower than "
+"50 for an off-road car, a value between 50 and 100 for a race car and try "
+"something around 200 for something like a Formula 1 car."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:59
+msgid ""
+"This is the distance the suspension can travel. As Godot units are "
+"equivalent to meters, keep this setting relatively low. Try a value between "
+"0.1 and 0.3 depending on the type of car."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:62
+msgid ""
+"If [code]true[/code], this wheel will be turned when the car steers. This "
+"value is used in conjunction with [member VehicleBody3D.steering] and "
+"ignored if you are using the per-wheel [member steering] value instead."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:65
+msgid ""
+"If [code]true[/code], this wheel transfers engine force to the ground to "
+"propel the vehicle forward. This value is used in conjunction with [member "
+"VehicleBody3D.engine_force] and ignored if you are using the per-wheel "
+"[member engine_force] value instead."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:68
+msgid ""
+"This determines how much grip this wheel has. It is combined with the "
+"friction setting of the surface the wheel is in contact with. 0.0 means no "
+"grip, 1.0 is normal grip. For a drift car setup, try setting the grip of the "
+"rear wheels slightly lower than the front wheels, or use a lower value to "
+"simulate tire wear.\n"
+"It's best to set this to 1.0 when starting out."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:72
+msgid "The radius of the wheel in meters."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:75
+msgid ""
+"This is the distance in meters the wheel is lowered from its origin point. "
+"Don't set this to 0.0 and move the wheel into position, instead move the "
+"origin point of your wheel (the gizmo in Godot) to the position the wheel "
+"will take when bottoming out, then use the rest length to move the wheel "
+"down to the position it should be in when the car is in rest."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:78
+msgid ""
+"This value affects the roll of your vehicle. If set to 1.0 for all wheels, "
+"your vehicle will be prone to rolling over, while a value of 0.0 will resist "
+"body roll."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:4
+msgid "Control for playing video streams."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:7
+msgid ""
+"Control node for playing video streams using [VideoStream] resources.\n"
+"Supported video formats are [url=https://www.webmproject.org/]WebM[/url] "
+"([VideoStreamWebm]), [url=https://www.theora.org/]Ogg Theora[/url] "
+"([VideoStreamTheora]), and any format exposed via a GDNative plugin using "
+"[VideoStreamGDNative]."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:17
+msgid ""
+"Returns the video stream's name, or [code]\"<No Stream>\"[/code] if no video "
+"stream is assigned."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:24
+msgid "Returns the current frame as a [Texture2D]."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:31
+msgid ""
+"Returns [code]true[/code] if the video is playing.\n"
+"[b]Note:[/b] The video is still considered playing if paused during playback."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:39
+msgid ""
+"Starts the video playback from the beginning. If the video is paused, this "
+"will not unpause the video."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:46
+msgid ""
+"Stops the video playback and sets the stream position to 0.\n"
+"[b]Note:[/b] Although the stream position will be set to 0, the first frame "
+"of the video stream won't become the current frame."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:53
+msgid "The embedded audio track to play."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:56
+msgid "If [code]true[/code], playback starts when the scene loads."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:59
+msgid "Amount of time in milliseconds to store in buffer while playing."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:62
+msgid "Audio bus to use for sound playback."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:65
+msgid ""
+"If [code]true[/code], the video scales to the control size. Otherwise, the "
+"control minimum size will be automatically adjusted to match the video "
+"stream's dimensions."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:68
+msgid "If [code]true[/code], the video is paused."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:71
+msgid "The assigned video stream. See description for supported formats."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:74
+msgid "The current position of the stream, in seconds."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:77
+msgid "Audio volume as a linear value."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:80
+msgid "Audio volume in dB."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:86
+msgid "Emitted when playback is finished."
+msgstr ""
+
+#: doc/classes/VideoStream.xml:4
+msgid "Base resource for video streams."
+msgstr ""
+
+#: doc/classes/VideoStream.xml:7
+msgid ""
+"Base resource type for all video streams. Classes that derive from "
+"[VideoStream] can all be used as resource types to play back videos in "
+"[VideoPlayer]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:4
+msgid "[VideoStream] resource for for video formats implemented via GDNative."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:7
+msgid ""
+"[VideoStream] resource for for video formats implemented via GDNative.\n"
+"It can be used via [url=https://github.com/KidRigger/godot-"
+"videodecoder]godot-videodecoder[/url] which uses the [url=https://ffmpeg."
+"org]FFmpeg[/url] library."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:17
+msgid "Returns the video file handled by this [VideoStreamGDNative]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:26
+msgid ""
+"Sets the video file that this [VideoStreamGDNative] resource handles. The "
+"supported extensions depend on the GDNative plugins used to expose video "
+"formats."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:4
+msgid "[VideoStream] resource for Ogg Theora videos."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:7
+msgid ""
+"[VideoStream] resource handling the [url=https://www.theora.org/]Ogg Theora[/"
+"url] video format with [code].ogv[/code] extension."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:16
+msgid "Returns the Ogg Theora video file handled by this [VideoStreamTheora]."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:25
+msgid ""
+"Sets the Ogg Theora video file that this [VideoStreamTheora] resource "
+"handles. The [code]file[/code] name should have the [code].o[/code] "
+"extension."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:4
+msgid "[VideoStream] resource for WebM videos."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:7
+msgid ""
+"[VideoStream] resource handling the [url=https://www.webmproject.org/]WebM[/"
+"url] video format with [code].webm[/code] extension."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:16
+msgid "Returns the WebM video file handled by this [VideoStreamWebm]."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:25
+msgid ""
+"Sets the WebM video file that this [VideoStreamWebm] resource handles. The "
+"[code]file[/code] name should have the [code].webm[/code] extension."
+msgstr ""
+
+#: doc/classes/Viewport.xml:4
+msgid "Creates a sub-view into the screen."
+msgstr ""
+
+#: doc/classes/Viewport.xml:7
+msgid ""
+"A Viewport creates a different view into the screen, or a sub-view inside "
+"another viewport. Children 2D Nodes will display on it, and children "
+"Camera3D 3D nodes will render on it too.\n"
+"Optionally, a viewport can have its own 2D or 3D world, so they don't share "
+"what they draw with other viewports.\n"
+"If a viewport is a child of a [SubViewportContainer], it will automatically "
+"take up its size, otherwise it must be set manually.\n"
+"Viewports can also choose to be audio listeners, so they generate positional "
+"audio depending on a 2D or 3D camera child of it.\n"
+"Also, viewports can be assigned to different screens in case the devices "
+"have multiple screens.\n"
+"Finally, viewports can also behave as render targets, in which case they "
+"will not be visible unless the associated texture is used to draw."
+msgstr ""
+
+#: doc/classes/Viewport.xml:16
+msgid "https://docs.godotengine.org/en/latest/tutorials/viewports/index.html"
+msgstr ""
+
+#: doc/classes/Viewport.xml:23
+msgid ""
+"Returns the 3D world of the viewport, or if none the world of the parent "
+"viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:30
+msgid "Returns the 2D world of the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:37
+msgid "Returns the active 3D camera."
+msgstr ""
+
+#: doc/classes/Viewport.xml:44
+msgid "Returns the total transform of the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:51
+msgid "Returns the mouse position relative to the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:60
+msgid "Returns information about the viewport from the rendering pipeline."
+msgstr ""
+
+#: doc/classes/Viewport.xml:69
+msgid "Returns the [enum ShadowAtlasQuadrantSubdiv] of the specified quadrant."
+msgstr ""
+
+#: doc/classes/Viewport.xml:76
+msgid ""
+"Returns the viewport's texture.\n"
+"[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:\n"
+"[codeblock]\n"
+"var img = get_viewport().get_texture().get_data()\n"
+"img.flip_y()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Viewport.xml:88
+msgid "Returns the viewport's RID from the [RenderingServer]."
+msgstr ""
+
+#: doc/classes/Viewport.xml:95
+msgid "Returns the visible rectangle in global screen coordinates."
+msgstr ""
+
+#: doc/classes/Viewport.xml:102
+msgid ""
+"Returns the drag data from the GUI, that was previously returned by [method "
+"Control.get_drag_data]."
+msgstr ""
+
+#: doc/classes/Viewport.xml:109
+msgid ""
+"Returns [code]true[/code] if the viewport is currently performing a drag "
+"operation."
+msgstr ""
+
+#: doc/classes/Viewport.xml:146
+msgid "Stops the input from propagating further down the [SceneTree]."
+msgstr ""
+
+#: doc/classes/Viewport.xml:157
+msgid ""
+"Sets the number of subdivisions to use in the specified quadrant. A higher "
+"number of subdivisions allows you to have more shadows in the scene at once, "
+"but reduces the quality of the shadows. A good practice is to have quadrants "
+"with a varying number of subdivisions and to have as few subdivisions as "
+"possible."
+msgstr ""
+
+#: doc/classes/Viewport.xml:174
+msgid "Forces update of the 2D and 3D worlds."
+msgstr ""
+
+#: doc/classes/Viewport.xml:183
+msgid "Warps the mouse to a position relative to the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:189
+msgid "If [code]true[/code], the viewport will process 2D audio streams."
+msgstr ""
+
+#: doc/classes/Viewport.xml:192
+msgid "If [code]true[/code], the viewport will process 3D audio streams."
+msgstr ""
+
+#: doc/classes/Viewport.xml:199
+msgid ""
+"The canvas transform of the viewport, useful for changing the on-screen "
+"positions of all child [CanvasItem]s. This is relative to the global canvas "
+"transform of the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:202
+msgid "The overlay mode for test rendered geometry in debug purposes."
+msgstr ""
+
+#: doc/classes/Viewport.xml:205
+msgid ""
+"The global canvas transform of the viewport. The canvas transform is "
+"relative to this."
+msgstr ""
+
+#: doc/classes/Viewport.xml:208
+msgid "If [code]true[/code], the viewport will not receive input event."
+msgstr ""
+
+#: doc/classes/Viewport.xml:213
+msgid ""
+"If [code]true[/code], the GUI controls on the viewport will lay pixel "
+"perfectly."
+msgstr ""
+
+#: doc/classes/Viewport.xml:218
+msgid ""
+"The multisample anti-aliasing mode. A higher number results in smoother "
+"edges at the cost of significantly worse performance. A value of 4 is best "
+"unless targeting very high-end systems."
+msgstr ""
+
+#: doc/classes/Viewport.xml:221
+msgid ""
+"If [code]true[/code], the viewport will use [World3D] defined in "
+"[code]world[/code] property."
+msgstr ""
+
+#: doc/classes/Viewport.xml:224
+msgid ""
+"If [code]true[/code], the objects rendered by viewport become subjects of "
+"mouse picking process."
+msgstr ""
+
+#: doc/classes/Viewport.xml:227
+msgid "The subdivision amount of the first quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:230
+msgid "The subdivision amount of the second quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:233
+msgid "The subdivision amount of the third quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:236
+msgid "The subdivision amount of the fourth quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:239
+msgid ""
+"The shadow atlas' resolution (used for omni and spot lights). The value will "
+"be rounded up to the nearest power of 2.\n"
+"[b]Note:[/b] If this is set to 0, shadows won't be visible. Since user-"
+"created viewports default to a value of 0, this value must be set above 0 "
+"manually."
+msgstr ""
+
+#: doc/classes/Viewport.xml:243
+msgid ""
+"If [code]true[/code], the viewport should render its background as "
+"transparent."
+msgstr ""
+
+#: doc/classes/Viewport.xml:246
+msgid "The custom [World3D] which can be used as 3D environment source."
+msgstr ""
+
+#: doc/classes/Viewport.xml:249
+msgid "The custom [World2D] which can be used as 2D environment source."
+msgstr ""
+
+#: doc/classes/Viewport.xml:257
+msgid "Emitted when a Control node grabs keyboard focus."
+msgstr ""
+
+#: doc/classes/Viewport.xml:262
+msgid ""
+"Emitted when the size of the viewport is changed, whether by resizing of "
+"window, or some other means."
+msgstr ""
+
+#: doc/classes/Viewport.xml:268
+msgid "This quadrant will not be used."
+msgstr ""
+
+#: doc/classes/Viewport.xml:271
+msgid "This quadrant will only be used by one shadow map."
+msgstr ""
+
+#: doc/classes/Viewport.xml:274
+msgid "This quadrant will be split in 4 and used by up to 4 shadow maps."
+msgstr ""
+
+#: doc/classes/Viewport.xml:277
+msgid "This quadrant will be split 16 ways and used by up to 16 shadow maps."
+msgstr ""
+
+#: doc/classes/Viewport.xml:280
+msgid "This quadrant will be split 64 ways and used by up to 64 shadow maps."
+msgstr ""
+
+#: doc/classes/Viewport.xml:283
+msgid ""
+"This quadrant will be split 256 ways and used by up to 256 shadow maps. "
+"Unless the [member shadow_atlas_size] is very high, the shadows in this "
+"quadrant will be very low resolution."
+msgstr ""
+
+#: doc/classes/Viewport.xml:286
+msgid ""
+"This quadrant will be split 1024 ways and used by up to 1024 shadow maps. "
+"Unless the [member shadow_atlas_size] is very high, the shadows in this "
+"quadrant will be very low resolution."
+msgstr ""
+
+#: doc/classes/Viewport.xml:289
+msgid "Represents the size of the [enum ShadowAtlasQuadrantSubdiv] enum."
+msgstr ""
+
+#: doc/classes/Viewport.xml:292
+msgid "Amount of objects in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:295
+msgid "Amount of vertices in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:298
+msgid "Amount of material changes in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:301
+msgid "Amount of shader changes in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:304
+msgid "Amount of surface changes in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:307
+msgid "Amount of draw calls in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:310
+msgid "Represents the size of the [enum RenderInfo] enum."
+msgstr ""
+
+#: doc/classes/Viewport.xml:313
+msgid "Objects are displayed normally."
+msgstr ""
+
+#: doc/classes/Viewport.xml:316
+msgid "Objects are displayed without light information."
+msgstr ""
+
+#: doc/classes/Viewport.xml:319
+msgid ""
+"Objected are displayed semi-transparent with additive blending so you can "
+"see where they intersect."
+msgstr ""
+
+#: doc/classes/Viewport.xml:322
+msgid "Objects are displayed in wireframe style."
+msgstr ""
+
+#: doc/classes/Viewport.xml:339
+msgid "Multisample anti-aliasing mode disabled. This is the default value."
+msgstr ""
+
+#: doc/classes/Viewport.xml:342
+msgid "Use 2x Multisample Antialiasing."
+msgstr ""
+
+#: doc/classes/Viewport.xml:345
+msgid "Use 4x Multisample Antialiasing."
+msgstr ""
+
+#: doc/classes/Viewport.xml:348
+msgid ""
+"Use 8x Multisample Antialiasing. Likely unsupported on low-end and older "
+"hardware."
+msgstr ""
+
+#: doc/classes/Viewport.xml:351
+msgid ""
+"Use 16x Multisample Antialiasing. Likely unsupported on medium and low-end "
+"hardware."
+msgstr ""
+
+#: doc/classes/ViewportTexture.xml:4
+msgid "Texture which displays the content of a [Viewport]."
+msgstr ""
+
+#: doc/classes/ViewportTexture.xml:7
+msgid ""
+"Displays the content of a [Viewport] node as a dynamic [Texture2D]. This can "
+"be used to mix controls, 2D, and 3D elements in the same scene.\n"
+"To create a ViewportTexture in code, use the [method Viewport.get_texture] "
+"method on the target viewport."
+msgstr ""
+
+#: doc/classes/ViewportTexture.xml:17
+msgid ""
+"The path to the [Viewport] node to display. This is relative to the scene "
+"root, not to the node which uses the texture."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:4 doc/classes/VisibilityEnabler3D.xml:4
+msgid "Enables certain nodes only when visible."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:7
+msgid ""
+"The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and "
+"other nodes when they are not visible. It will only affect nodes with the "
+"same root node as the VisibilityEnabler2D, and the root node itself.\n"
+"Note that VisibilityEnabler2D will not affect nodes added after scene "
+"initialization."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:19
+#: doc/classes/VisibilityEnabler3D.xml:19
+msgid ""
+"Returns whether the enabler identified by given [enum Enabler] constant is "
+"active."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:30
+#: doc/classes/VisibilityEnabler3D.xml:30
+msgid ""
+"Sets active state of the enabler identified by given [enum Enabler] constant."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:36
+msgid "If [code]true[/code], [RigidBody2D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:39
+msgid "If [code]true[/code], [AnimatedSprite2D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:42
+#: doc/classes/VisibilityEnabler3D.xml:39
+msgid "If [code]true[/code], [AnimationPlayer] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:45
+msgid "If [code]true[/code], [GPUParticles2D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:48
+msgid ""
+"If [code]true[/code], the parent's [method Node._physics_process] will be "
+"stopped."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:51
+msgid ""
+"If [code]true[/code], the parent's [method Node._process] will be stopped."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:56
+#: doc/classes/VisibilityEnabler3D.xml:44
+msgid "This enabler will pause [AnimationPlayer] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:59
+msgid "This enabler will freeze [RigidBody2D] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:62
+msgid "This enabler will stop [GPUParticles2D] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:65
+msgid "This enabler will stop the parent's _process function."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:68
+msgid "This enabler will stop the parent's _physics_process function."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:71
+msgid "This enabler will stop [AnimatedSprite2D] nodes animations."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:74
+#: doc/classes/VisibilityEnabler3D.xml:50
+msgid "Represents the size of the [enum Enabler] enum."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler3D.xml:7
+msgid ""
+"The VisibilityEnabler3D will disable [RigidBody3D] and [AnimationPlayer] "
+"nodes when they are not visible. It will only affect other nodes within the "
+"same scene as the VisibilityEnabler3D itself.\n"
+"Note that VisibilityEnabler3D will not affect nodes added after scene "
+"initialization."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler3D.xml:36
+msgid "If [code]true[/code], [RigidBody3D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler3D.xml:47
+msgid "This enabler will freeze [RigidBody3D] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:4
+#: doc/classes/VisibilityNotifier3D.xml:4
+msgid "Detects when the node is visible on screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:7
+msgid ""
+"The VisibilityNotifier2D detects when it is visible on the screen. It also "
+"notifies when its bounding rectangle enters or exits the screen or a "
+"viewport."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:16
+msgid ""
+"If [code]true[/code], the bounding rectangle is on the screen.\n"
+"[b]Note:[/b] It takes one frame for the node's visibility to be assessed "
+"once added to the scene tree, so this method will return [code]false[/code] "
+"right after it is instantiated, even if it will be on screen in the draw "
+"pass."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:23
+msgid "The VisibilityNotifier2D's bounding rectangle."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:29
+msgid "Emitted when the VisibilityNotifier2D enters the screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:34
+msgid "Emitted when the VisibilityNotifier2D exits the screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:41
+msgid "Emitted when the VisibilityNotifier2D enters a [Viewport]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:48
+msgid "Emitted when the VisibilityNotifier2D exits a [Viewport]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:7
+msgid ""
+"The VisibilityNotifier3D detects when it is visible on the screen. It also "
+"notifies when its bounding rectangle enters or exits the screen or a "
+"[Camera3D]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:16
+msgid ""
+"If [code]true[/code], the bounding box is on the screen.\n"
+"[b]Note:[/b] It takes one frame for the node's visibility to be assessed "
+"once added to the scene tree, so this method will return [code]false[/code] "
+"right after it is instantiated, even if it will be on screen in the draw "
+"pass."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:23
+msgid "The VisibilityNotifier3D's bounding box."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:31
+msgid "Emitted when the VisibilityNotifier3D enters a [Camera3D]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:38
+msgid "Emitted when the VisibilityNotifier3D exits a [Camera3D]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:43
+msgid "Emitted when the VisibilityNotifier3D enters the screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:48
+msgid "Emitted when the VisibilityNotifier3D exits the screen."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:4
+msgid "Parent of all visual 3D nodes."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:7
+msgid ""
+"The [VisualInstance3D] is used to connect a resource to a visual "
+"representation. All visual 3D nodes inherit from the [VisualInstance3D]. In "
+"general, you should not access the [VisualInstance3D] properties directly as "
+"they are accessed and managed by the nodes that inherit from "
+"[VisualInstance3D]. [VisualInstance3D] is the node representation of the "
+"[RenderingServer] instance."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:16
+msgid ""
+"Returns the [AABB] (also known as the bounding box) for this "
+"[VisualInstance3D]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:23
+msgid ""
+"Returns the RID of the resource associated with this [VisualInstance3D]. For "
+"example, if the Node is a [MeshInstance3D], this will return the RID of the "
+"associated [Mesh]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:30
+msgid ""
+"Returns the RID of this instance. This RID is the same as the RID returned "
+"by [method RenderingServer.instance_create]. This RID is needed if you want "
+"to call [RenderingServer] functions directly on this [VisualInstance3D]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:39
+msgid ""
+"Returns [code]true[/code] when the specified layer is enabled in [member "
+"layers] and [code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:46
+msgid ""
+"Returns the transformed [AABB] (also known as the bounding box) for this "
+"[VisualInstance3D].\n"
+"Transformed in this case means the [AABB] plus the position, rotation, and "
+"scale of the [Node3D]'s [Transform]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:56
+msgid ""
+"Sets the resource that is instantiated by this [VisualInstance3D], which "
+"changes how the engine handles the [VisualInstance3D] under the hood. "
+"Equivalent to [method RenderingServer.instance_set_base]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:67
+msgid "Enables a particular layer in [member layers]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:73
+msgid ""
+"The render layer(s) this [VisualInstance3D] is drawn on.\n"
+"This object will only be visible for [Camera3D]s whose cull mask includes "
+"the render object this [VisualInstance3D] is set to."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:4
+msgid "A script implemented in the Visual Script programming environment."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:7
+msgid ""
+"A script implemented in the Visual Script programming environment. The "
+"script extends the functionality of all objects that instance it.\n"
+"[method Object.set_script] extends an existing object, if that object's "
+"class matches one of the script's base classes.\n"
+"You are most likely to use this class via the Visual Script editor or when "
+"writing plugins for it."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/"
+"visual_script/index.html"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:21
+msgid "Add a custom signal with the specified name to the VisualScript."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:30
+msgid "Add a function with the specified name to the VisualScript."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:45
+msgid "Add a node to a function of the VisualScript."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:58
+msgid ""
+"Add a variable to the VisualScript, optionally giving it a default value or "
+"marking it as exported."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:73
+msgid ""
+"Add an argument to a custom signal added with [method add_custom_signal]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:82
+msgid "Get the count of a custom signal's arguments."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:93
+msgid "Get the name of a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:104
+msgid "Get the type of a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:115
+msgid "Remove a specific custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:128
+msgid "Rename a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:141
+msgid "Change the type of a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:154
+msgid "Swap two of the arguments of a custom signal."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:171
+msgid ""
+"Connect two data ports. The value of [code]from_node[/code]'s "
+"[code]from_port[/code] would be fed into [code]to_node[/code]'s "
+"[code]to_port[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:188
+msgid ""
+"Disconnect two data ports previously connected with [method data_connect]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:197
+msgid "Returns the id of a function's entry point node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:206
+msgid "Returns the position of the center of the screen for a given function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:217
+msgid "Returns a node given its id and its function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:228
+msgid "Returns a node's position in pixels."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:237
+msgid "Returns the default (initial) value of a variable."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:246
+msgid "Returns whether a variable is exported."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:255
+msgid ""
+"Returns the information for a given variable as a dictionary. The "
+"information includes its name, type, hint and usage."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:264
+msgid "Returns whether a signal exists with the specified name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:281
+msgid "Returns whether the specified data ports are connected."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:290
+msgid "Returns whether a function exists with the specified name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:301
+msgid "Returns whether a node exists with the given id."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:316
+msgid "Returns whether the specified sequence ports are connected."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:325
+msgid "Returns whether a variable exists with the specified name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:334
+msgid "Remove a custom signal with the given name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:343
+msgid "Remove a specific function and its nodes from the script."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:354
+msgid "Remove a specific node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:363
+msgid "Remove a variable with the given name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:374
+msgid "Change the name of a custom signal."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:385
+msgid "Change the name of a function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:396
+msgid "Change the name of a variable."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:411
+msgid ""
+"Connect two sequence ports. The execution will flow from of [code]from_node[/"
+"code]'s [code]from_output[/code] into [code]to_node[/code].\n"
+"Unlike [method data_connect], there isn't a [code]to_port[/code], since the "
+"target node can have only one sequence port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:427
+msgid ""
+"Disconnect two sequence ports previously connected with [method "
+"sequence_connect]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:438
+msgid "Position the center of the screen for a function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:447
+msgid "Set the base type of the script."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:460
+msgid "Position a node on the screen."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:471
+msgid "Change the default (initial) value of a variable."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:482
+msgid "Change whether a variable is exported."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:493
+msgid ""
+"Set a variable's info, using the same format as [method get_variable_info]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:504
+msgid "Emitted when the ports of a node are changed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:4
+msgid "A Visual Script node representing a constant from the base types."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:7
+msgid ""
+"A Visual Script node representing a constant from base types, such as "
+"[constant Vector3.AXIS_X]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:15
+msgid "The type to get the constant from."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:18
+msgid "The name of the constant to return."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:4
+msgid "A Visual Script node used to call built-in functions."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:7
+msgid ""
+"A built-in function used inside a [VisualScript]. It is usually a math "
+"function or an utility function.\n"
+"See also [@GDScript], for the same functions in the GDScript language."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:16
+msgid "The function to be executed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:21
+msgid "Return the sine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:24
+msgid "Return the cosine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:27
+msgid "Return the tangent of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:30
+msgid "Return the hyperbolic sine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:33
+msgid "Return the hyperbolic cosine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:36
+msgid "Return the hyperbolic tangent of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:39
+msgid "Return the arc sine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:42
+msgid "Return the arc cosine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:45
+msgid "Return the arc tangent of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:48
+msgid ""
+"Return the arc tangent of the input, using the signs of both parameters to "
+"determine the exact angle."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:51
+msgid "Return the square root of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:54
+msgid ""
+"Return the remainder of one input divided by the other, using floating-point "
+"numbers."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:57
+msgid ""
+"Return the positive remainder of one input divided by the other, using "
+"floating-point numbers."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:60
+msgid "Return the input rounded down."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:63
+msgid "Return the input rounded up."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:66
+msgid "Return the input rounded to the nearest integer."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:69
+msgid "Return the absolute value of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:72
+msgid ""
+"Return the sign of the input, turning it into 1, -1, or 0. Useful to "
+"determine if the input is positive or negative."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:75
+msgid "Return the input raised to a given power."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:78
+msgid ""
+"Return the natural logarithm of the input. Note that this is not the typical "
+"base-10 logarithm function calculators use."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:81
+msgid ""
+"Return the mathematical constant [b]e[/b] raised to the specified power of "
+"the input. [b]e[/b] has an approximate value of 2.71828."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:84
+msgid ""
+"Return whether the input is NaN (Not a Number) or not. NaN is usually "
+"produced by dividing 0 by 0, though other ways exist."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:87
+msgid ""
+"Return whether the input is an infinite floating-point number or not. "
+"Infinity is usually produced by dividing a number by 0, though other ways "
+"exist."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:93
+msgid ""
+"Return the number of digit places after the decimal that the first non-zero "
+"digit occurs."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:96
+msgid "Return the input snapped to a given step."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:99
+msgid ""
+"Return a number linearly interpolated between the first two inputs, based on "
+"the third input. Uses the formula [code]a + (a - b) * t[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:106
+msgid "Moves the number toward a value, based on the third input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:109
+msgid ""
+"Return the result of [code]value[/code] decreased by [code]step[/code] * "
+"[code]amount[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:112
+msgid ""
+"Randomize the seed (or the internal state) of the random number generator. "
+"Current implementation reseeds using a number based on time."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:115
+msgid ""
+"Return a random 32 bits integer value. To obtain a random value between 0 to "
+"N (where N is smaller than 2^32 - 1), you can use it with the remainder "
+"function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:118
+msgid ""
+"Return a random floating-point value between 0 and 1. To obtain a random "
+"value between 0 to N, you can use it with multiplication."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:121
+msgid "Return a random floating-point value between the two inputs."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:124
+msgid "Set the seed for the random number generator."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:127
+msgid "Return a random value from the given seed, along with the new seed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:130
+msgid "Convert the input from degrees to radians."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:133
+msgid "Convert the input from radians to degrees."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:136
+msgid "Convert the input from linear volume to decibel volume."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:139
+msgid "Convert the input from decibel volume to linear volume."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:152
+msgid "Return the greater of the two numbers, also known as their maximum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:155
+msgid "Return the lesser of the two numbers, also known as their minimum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:158
+msgid ""
+"Return the input clamped inside the given range, ensuring the result is "
+"never outside it. Equivalent to [code]min(max(input, range_low), range_high)"
+"[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:161
+msgid "Return the nearest power of 2 to the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:164
+msgid "Create a [WeakRef] from the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:167
+msgid "Create a [FuncRef] from the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:170
+msgid "Convert between types."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:173
+msgid ""
+"Return the type of the input as an integer. Check [enum Variant.Type] for "
+"the integers that might be returned."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:176
+msgid "Checks if a type is registered in the [ClassDB]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:179
+msgid "Return a character with the given ascii value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:182
+msgid "Convert the input to a string."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:185
+msgid "Print the given string to the output window."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:188
+msgid "Print the given string to the standard error output."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:191
+msgid ""
+"Print the given string to the standard output, without adding a newline."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:194
+msgid "Serialize a [Variant] to a string."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:197
+msgid ""
+"Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:200
+msgid "Serialize a [Variant] to a [PackedByteArray]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:203
+msgid ""
+"Deserialize a [Variant] from a [PackedByteArray] serialized using [constant "
+"VAR_TO_BYTES]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:206
+msgid ""
+"Return the [Color] with the given name and alpha ranging from 0 to 1.\n"
+"[b]Note:[/b] Names are defined in [code]color_names.inc[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:210
+msgid ""
+"Return a number smoothly interpolated between the first two inputs, based on "
+"the third input. Similar to [constant MATH_LERP], but interpolates faster at "
+"the beginning and slower at the end. Using Hermite interpolation formula:\n"
+"[codeblock]\n"
+"var t = clamp((weight - from) / (to - from), 0.0, 1.0)\n"
+"return t * t * (3.0 - 2.0 * t)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:223
+msgid "Represents the size of the [enum BuiltinFunc] enum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:4
+msgid "Gets a constant from a given class."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:7
+msgid ""
+"This node returns a constant from a given class, such as [constant "
+"TYPE_INT]. See the given class' documentation for available constants.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]value[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:19
+msgid "The constant's parent class."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:22
+msgid ""
+"The constant to return. See the given class for its available constants."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:4
+msgid "A Visual Script node used to annotate the script."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:7
+msgid ""
+"A Visual Script node used to display annotations in the script, so that code "
+"may be documented.\n"
+"Comment nodes can be resized so they encompass a group of nodes."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:16
+msgid "The text inside the comment node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:19
+msgid "The comment node's size (in pixels)."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:22
+msgid "The comment node's title."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComposeArray.xml:4
+msgid "A Visual Script Node used to create array from a list of items."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComposeArray.xml:7
+msgid ""
+"A Visual Script Node used to compose array from the list of elements "
+"provided with custom in-graph UI hard coded in the VisualScript Editor."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCondition.xml:4
+msgid "A Visual Script node which branches the flow."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCondition.xml:7
+msgid ""
+"A Visual Script node that checks a [bool] input port. If [code]true[/code], "
+"it will exit via the \"true\" sequence port. If [code]false[/code], it will "
+"exit via the \"false\" sequence port. After exiting either, it exits via the "
+"\"done\" port. Sequence ports may be left disconnected.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]if (cond) is[/code]\n"
+"- Data (boolean): [code]cond[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]true[/code]\n"
+"- Sequence: [code]false[/code]\n"
+"- Sequence: [code]done[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:4
+msgid "Gets a contant's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:7
+msgid ""
+"This node returns a constant's value.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:19
+msgid "The constant's type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:22
+msgid "The constant's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstructor.xml:4
+msgid "A Visual Script node which calls a base type constructor."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstructor.xml:7
+msgid ""
+"A Visual Script node which calls a base type constructor. It can be used for "
+"type conversion as well."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:4
+msgid "A scripted Visual Script node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:7
+msgid "A custom Visual Script node which can be scripted in powerful ways."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:16
+msgid "Return the node's title."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:23
+msgid "Return the node's category."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:30
+msgid "Return the count of input value ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:39
+msgid "Return the specified input port's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:48
+msgid ""
+"Return the specified input port's type. See the [enum Variant.Type] values."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:55
+msgid "Return the amount of output [b]sequence[/b] ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:64
+msgid "Return the specified [b]sequence[/b] output's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:71
+msgid "Return the amount of output value ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:80
+msgid "Return the specified output's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:89
+msgid "Return the specified output's type. See the [enum Variant.Type] values."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:96
+msgid ""
+"Return the custom node's text, which is shown right next to the input "
+"[b]sequence[/b] port (if there is none, on the place that is usually taken "
+"by it)."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:103
+msgid ""
+"Return the size of the custom node's working memory. See [method _step] for "
+"more details."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:110
+msgid "Return whether the custom node has an input [b]sequence[/b] port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:125
+msgid ""
+"Execute the custom node's logic, returning the index of the output sequence "
+"port to use or a [String] when there is an error.\n"
+"The [code]inputs[/code] array contains the values of the input ports.\n"
+"[code]outputs[/code] is an array whose indices should be set to the "
+"respective outputs.\n"
+"The [code]start_mode[/code] is usually [constant START_MODE_BEGIN_SEQUENCE], "
+"unless you have used the [code]STEP_*[/code] constants.\n"
+"[code]working_mem[/code] is an array which can be used to persist "
+"information between runs of the custom node.\n"
+"When returning, you can mask the returned value with one of the "
+"[code]STEP_*[/code] constants."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:136
+msgid "The start mode used the first time when [method _step] is called."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:139
+msgid ""
+"The start mode used when [method _step] is called after coming back from a "
+"[constant STEP_PUSH_STACK_BIT]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:142
+msgid ""
+"The start mode used when [method _step] is called after resuming from "
+"[constant STEP_YIELD_BIT]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:145
+msgid ""
+"Hint used by [method _step] to tell that control should return to it when "
+"there is no other node left to execute.\n"
+"This is used by [VisualScriptCondition] to redirect the sequence to the "
+"\"Done\" port after the [code]true[/code]/[code]false[/code] branch has "
+"finished execution."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:149
+msgid ""
+"Hint used by [method _step] to tell that control should return back, either "
+"hitting a previous [constant STEP_PUSH_STACK_BIT] or exiting the function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:154
+msgid ""
+"Hint used by [method _step] to tell that control should stop and exit the "
+"function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:157
+msgid ""
+"Hint used by [method _step] to tell that the function should be yielded.\n"
+"Using this requires you to have at least one working memory slot, which is "
+"used for the [VisualScriptFunctionState]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml:4
+#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml:7
+msgid ""
+"A Visual Script node which deconstructs a base type instance into its parts."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml:15
+msgid "The type to deconstruct."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEditor.xml:20
+msgid ""
+"Add a custom Visual Script node to the editor. It'll be placed under "
+"\"Custom Nodes\" with the [code]category[/code] as the parameter."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEditor.xml:31
+msgid ""
+"Remove a custom Visual Script node from the editor. Custom nodes already "
+"placed on scripts won't be removed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEditor.xml:38
+msgid "Emitted when a custom Visual Script node is added or removed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml:4
+msgid "Emits a specified signal."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml:7
+msgid ""
+"Emits a specified signal when it is executed.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]emit[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml:19
+msgid "The signal to emit."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml:4
+#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml:7
+msgid "A Visual Script node returning a singleton from [@GlobalScope]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml:15
+msgid "The singleton's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptIterator.xml:4
+msgid "Steps through items in a given input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptIterator.xml:7
+msgid ""
+"This node steps through each item in a given input. Input can be any "
+"sequence data type, such as an [Array] or [String]. When each item has been "
+"processed, execution passed out the [code]exit[/code] Sequence port.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]for (elem) in (input)[/code]\n"
+"- Data (variant): [code]input[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]each[/code]\n"
+"- Sequence: [code]exit[/code]\n"
+"- Data (variant): [code]elem[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLists.xml:4
+msgid "A Visual Script virtual class for in-graph editable nodes."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLists.xml:7
+msgid ""
+"A Visual Script virtual class that defines the shape and the default "
+"behaviour of the nodes that have to be in-graph editable nodes."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:4
+msgid "Gets a local variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:7
+msgid ""
+"Returns a local variable's value. \"Var Name\" must be supplied, with an "
+"optional type.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:19
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:21
+msgid "The local variable's type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:22
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:24
+msgid "The local variable's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:4
+msgid "Changes a local variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:7
+msgid ""
+"Changes a local variable's value to the given input. The new value is also "
+"provided on an output Data port.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]set[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:4
+msgid "Commonly used mathematical constants."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:7
+msgid ""
+"Provides common math constants, such as Pi, on an output Data port.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:19
+msgid "The math constant."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:24
+msgid "Unity: [code]1[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:27
+msgid "Pi: [code]3.141593[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:30
+msgid "Pi divided by two: [code]1.570796[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:33
+msgid "Tau: [code]6.283185[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:36
+msgid ""
+"Mathematical constant [code]e[/code], the natural log base: [code]2.718282[/"
+"code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:39
+msgid "Square root of two: [code]1.414214[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:42
+msgid "Infinity: [code]inf[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:45
+msgid "Not a number: [code]nan[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:48
+msgid "Represents the size of the [enum MathConstant] enum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:4
+msgid "A node which is part of a [VisualScript]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:7
+msgid ""
+"A node which is part of a [VisualScript]. Not to be confused with [Node], "
+"which is a part of a [SceneTree]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:18
+msgid ""
+"Returns the default value of a given port. The default value is used when "
+"nothing is connected to the port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:25
+msgid "Returns the [VisualScript] instance the node is bound to."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:32
+msgid ""
+"Notify that the node's ports have changed. Usually used in conjunction with "
+"[VisualScriptCustomNode] ."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:43
+msgid "Change the default value of a given port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:50
+msgid "Emitted when the available input/output ports are changed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptOperator.xml:6
+msgid ""
+"[b]Input Ports:[/b]\n"
+"- Data (variant): [code]A[/code]\n"
+"- Data (variant): [code]B[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]result[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptPreload.xml:4
+msgid "Creates a new [Resource] or loads one from the filesystem."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptPreload.xml:7
+msgid ""
+"Creates a new [Resource] or loads one from the filesystem.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (object): [code]res[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptPreload.xml:19
+msgid "The [Resource] to load."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:4
+msgid "Exits a function and returns an optional value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:7
+msgid ""
+"Ends the execution of a function and returns control to the calling "
+"function. Optionally, it can return a [Variant] value.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]result[/code] (optional)\n"
+"[b]Output Ports:[/b]\n"
+"none"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:20
+msgid "If [code]true[/code], the [code]return[/code] input port is available."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:23
+msgid "The return value's data type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSceneNode.xml:4
+msgid "Node reference."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSceneNode.xml:7
+msgid ""
+"A direct reference to a node.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data: [code]node[/code] (obj)"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSceneNode.xml:19
+msgid "The node's path in the scene tree."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelect.xml:4
+msgid "Chooses between two input values."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelect.xml:7
+msgid ""
+"Chooses between two input values based on a Boolean condition.\n"
+"[b]Input Ports:[/b]\n"
+"- Data (boolean): [code]cond[/code]\n"
+"- Data (variant): [code]a[/code]\n"
+"- Data (variant): [code]b[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]out[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelect.xml:21
+msgid "The input variables' type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelf.xml:4
+msgid "Outputs a reference to the current instance."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelf.xml:7
+msgid ""
+"Provides a reference to the node running the visual script.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (object): [code]instance[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSequence.xml:4
+msgid "Executes a series of Sequence ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSequence.xml:7
+msgid ""
+"Steps through a series of one or more output Sequence ports. The "
+"[code]current[/code] data port outputs the currently executing item.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]in order[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]1[/code]\n"
+"- Sequence: [code]2 - n[/code] (optional)\n"
+"- Data (int): [code]current[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSequence.xml:21
+msgid "The number of steps in the sequence."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSwitch.xml:4
+msgid "Branches program flow based on a given input's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSwitch.xml:7
+msgid ""
+"Branches the flow based on an input's value. Use [b]Case Count[/b] in the "
+"Inspector to set the number of branches and each comparison's optional "
+"type.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]'input' is[/code]\n"
+"- Data (variant): [code]=[/code]\n"
+"- Data (variant): [code]=[/code] (optional)\n"
+"- Data (variant): [code]input[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence\n"
+"- Sequence (optional)\n"
+"- Sequence: [code]done[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableGet.xml:4
+msgid "Gets a variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableGet.xml:7
+msgid ""
+"Returns a variable's value. \"Var Name\" must be supplied, with an optional "
+"type.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]value[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableGet.xml:19
+#: modules/visual_script/doc_classes/VisualScriptVariableSet.xml:20
+msgid "The variable's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableSet.xml:4
+msgid "Changes a variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableSet.xml:7
+msgid ""
+"Changes a variable's value to the given input.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]set[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptWhile.xml:4
+msgid "Conditional loop."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptWhile.xml:7
+msgid ""
+"Loops while a condition is [code]true[/code]. Execution continues out the "
+"[code]exit[/code] Sequence port when the loop terminates.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]while(cond)[/code]\n"
+"- Data (bool): [code]cond[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]repeat[/code]\n"
+"- Sequence: [code]exit[/code]"
+msgstr ""
+
+#: doc/classes/VisualShader.xml:4
+msgid "A custom shader program with a visual editor."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:7
+msgid ""
+"This class allows you to define a custom shader program that can be used for "
+"various materials to render objects.\n"
+"The visual shader editor creates the shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:25
+msgid "Adds the specified node to the shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:42
+msgid ""
+"Returns [code]true[/code] if the specified nodes and ports can be connected "
+"together."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:59 doc/classes/VisualShader.xml:93
+msgid "Connects the specified nodes and ports."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:76
+msgid ""
+"Connects the specified nodes and ports, even if they can't be connected. "
+"Such connection is invalid and will not function properly."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:104
+msgid ""
+"Returns the shader node instance with specified [code]type[/code] and "
+"[code]id[/code]."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:113
+msgid "Returns the list of connected nodes with the specified type."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:122
+msgid "Returns the list of all nodes in the shader with the specified type."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:133
+msgid "Returns the position of the specified node within the shader graph."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:158
+msgid ""
+"Returns [code]true[/code] if the specified node and port connection exist."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:169
+msgid "Removes the specified node from the shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:178
+msgid "Sets the mode of this shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:191
+msgid "Sets the position of the specified node."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:198
+msgid "The offset vector of the whole graph."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:205
+msgid "A vertex shader, operating on vertices."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:208
+msgid "A fragment shader, operating on fragments (pixels)."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:211
+msgid "A shader for light calculations."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:214
+msgid "Represents the size of the [enum Type] enum."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:4
+msgid "Base class for nodes in a visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:9
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/shading/visual_shaders.html"
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:16
+msgid ""
+"Returns an [Array] containing default values for all of the input ports of "
+"the node in the form [code][index0, value0, index1, value1, ...][/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:25
+msgid "Returns the default value of the input [code]port[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:34
+msgid ""
+"Sets the default input ports values using an [Array] of the form [code]"
+"[index0, value0, index1, value1, ...][/code]. For example: [code][0, "
+"Vector3(0, 0, 0), 1, Vector3(0, 0, 0)][/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:45
+msgid "Sets the default value for the selected input [code]port[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:51
+msgid ""
+"Sets the output port index which will be showed for preview. If set to "
+"[code]-1[/code] no port will be open for preview."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:57
+msgid ""
+"Emitted when the node requests an editor refresh. Currently called only in "
+"setter of [member VisualShaderNodeTexture.source], "
+"[VisualShaderNodeTexture], and [VisualShaderNodeCubemap] (and their "
+"derivatives)."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:63
+msgid ""
+"Floating-point scalar. Translated to [code]float[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:66
+msgid "Integer scalar. Translated to [code]int[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:69
+msgid ""
+"3D vector of floating-point values. Translated to [code]vec3[/code] type in "
+"shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:72
+msgid "Boolean type. Translated to [code]bool[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:75
+msgid "Transform type. Translated to [code]mat4[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:78
+msgid ""
+"Sampler type. Translated to reference of sampler uniform in shader code. Can "
+"only be used for input ports in non-uniform nodes."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:81
+msgid "Represents the size of the [enum PortType] enum."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanConstant.xml:4
+msgid "A boolean constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanConstant.xml:7
+msgid ""
+"Has only one output port and no inputs.\n"
+"Translated to [code]bool[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanConstant.xml:16
+msgid "A boolean constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanUniform.xml:4
+msgid "A boolean uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanUniform.xml:7
+msgid "Translated to [code]uniform bool[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorConstant.xml:4
+msgid "A [Color] constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorConstant.xml:7
+msgid ""
+"Has two output ports representing RGB and alpha channels of [Color].\n"
+"Translated to [code]vec3 rgb[/code] and [code]float alpha[/code] in the "
+"shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorConstant.xml:16
+msgid "A [Color] constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:4
+msgid "A [Color] function to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:7
+msgid ""
+"Accept a [Color] to the input port and transform it according to [member "
+"function]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:15
+msgid ""
+"A function to be applied to the input color. See [enum Function] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:20
+msgid ""
+"Converts the color to grayscale using the following formula:\n"
+"[codeblock]\n"
+"vec3 c = input;\n"
+"float max1 = max(c.r, c.g);\n"
+"float max2 = max(max1, c.b);\n"
+"float max3 = max(max1, max2);\n"
+"return vec3(max3, max3, max3);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:30
+msgid ""
+"Applies sepia tone effect using the following formula:\n"
+"[codeblock]\n"
+"vec3 c = input;\n"
+"float r = (c.r * 0.393) + (c.g * 0.769) + (c.b * 0.189);\n"
+"float g = (c.r * 0.349) + (c.g * 0.686) + (c.b * 0.168);\n"
+"float b = (c.r * 0.272) + (c.g * 0.534) + (c.b * 0.131);\n"
+"return vec3(r, g, b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:4
+msgid "A [Color] operator to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:7
+msgid "Applies [member operator] to two color inputs."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:15
+#: doc/classes/VisualShaderNodeFloatOp.xml:15
+#: doc/classes/VisualShaderNodeIntOp.xml:15
+msgid ""
+"An operator to be applied to the inputs. See [enum Operator] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:20
+msgid ""
+"Produce a screen effect with the following formula:\n"
+"[codeblock]\n"
+"result = vec3(1.0) - (vec3(1.0) - a) * (vec3(1.0) - b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:26
+msgid ""
+"Produce a difference effect with the following formula:\n"
+"[codeblock]\n"
+"result = abs(a - b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:32
+msgid ""
+"Produce a darken effect with the following formula:\n"
+"[codeblock]\n"
+"result = min(a, b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:38
+msgid ""
+"Produce a lighten effect with the following formula:\n"
+"[codeblock]\n"
+"result = max(a, b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:44
+msgid ""
+"Produce an overlay effect with the following formula:\n"
+"[codeblock]\n"
+"for (int i = 0; i < 3; i++) {\n"
+" float base = a[i];\n"
+" float blend = b[i];\n"
+" if (base < 0.5) {\n"
+" result[i] = 2.0 * base * blend;\n"
+" } else {\n"
+" result[i] = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"
+" }\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:58
+msgid ""
+"Produce a dodge effect with the following formula:\n"
+"[codeblock]\n"
+"result = a / (vec3(1.0) - b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:64
+msgid ""
+"Produce a burn effect with the following formula:\n"
+"[codeblock]\n"
+"result = vec3(1.0) - (vec3(1.0) - a) / b;\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:70
+msgid ""
+"Produce a soft light effect with the following formula:\n"
+"[codeblock]\n"
+"for (int i = 0; i < 3; i++) {\n"
+" float base = a[i];\n"
+" float blend = b[i];\n"
+" if (base < 0.5) {\n"
+" result[i] = base * (blend + 0.5);\n"
+" } else {\n"
+" result[i] = 1.0 - (1.0 - base) * (1.0 - (blend - 0.5));\n"
+" }\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:84
+msgid ""
+"Produce a hard light effect with the following formula:\n"
+"[codeblock]\n"
+"for (int i = 0; i < 3; i++) {\n"
+" float base = a[i];\n"
+" float blend = b[i];\n"
+" if (base < 0.5) {\n"
+" result[i] = base * (2.0 * blend);\n"
+" } else {\n"
+" result[i] = 1.0 - (1.0 - base) * (1.0 - 2.0 * (blend - 0.5));\n"
+" }\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorUniform.xml:4
+msgid "A [Color] uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorUniform.xml:7
+msgid "Translated to [code]uniform vec4[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:4
+msgid "A comparison function for common types within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:7
+msgid ""
+"Compares [code]a[/code] and [code]b[/code] of [member type] by [member "
+"function]. Returns a boolean scalar. Translates to [code]if[/code] "
+"instruction in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:15
+msgid ""
+"Extra condition which is applied if [member type] is set to [constant "
+"CTYPE_VECTOR]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:18
+msgid "A comparison function. See [enum Function] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:21
+msgid ""
+"The type to be used in the comparison. See [enum ComparisonType] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:26
+msgid "A floating-point scalar."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:29
+msgid "An integer scalar."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:32
+msgid "A 3D vector type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:35
+msgid "A boolean type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:38
+msgid "A transform ([code]mat4[/code]) type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:41
+msgid "Comparison for equality ([code]a == b[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:44
+msgid "Comparison for inequality ([code]a != b[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:47
+msgid ""
+"Comparison for greater than ([code]a > b[/code]). Cannot be used if [member "
+"type] set to [constant CTYPE_BOOLEAN] or [constant CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:50
+msgid ""
+"Comparison for greater than or equal ([code]a >= b[/code]). Cannot be used "
+"if [member type] set to [constant CTYPE_BOOLEAN] or [constant "
+"CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:53
+msgid ""
+"Comparison for less than ([code]a < b[/code]). Cannot be used if [member "
+"type] set to [constant CTYPE_BOOLEAN] or [constant CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:56
+msgid ""
+"Comparison for less than or equal ([code]a <= b[/code]). Cannot be used if "
+"[member type] set to [constant CTYPE_BOOLEAN] or [constant CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:59
+msgid ""
+"The result will be true if all of component in vector satisfy the comparison "
+"condition."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:62
+msgid ""
+"The result will be true if any of component in vector satisfy the comparison "
+"condition."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:4
+msgid "A [Cubemap] sampling node to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:7
+msgid ""
+"Translated to [code]texture(cubemap, vec3)[/code] in the shader language. "
+"Returns a color vector and alpha channel as scalar."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:15
+msgid ""
+"The [Cubemap] texture to sample when using [constant SOURCE_TEXTURE] as "
+"[member source]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:18
+msgid ""
+"Defines which source should be used for the sampling. See [enum Source] for "
+"options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:21
+msgid ""
+"Defines the type of data provided by the source texture. See [enum "
+"TextureType] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:26
+msgid ""
+"Use the [Cubemap] set via [member cube_map]. If this is set to [member "
+"source], the [code]samplerCube[/code] port is ignored."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:29
+msgid ""
+"Use the [Cubemap] sampler reference passed via the [code]samplerCube[/code] "
+"port. If this is set to [member source], the [member cube_map] texture is "
+"ignored."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:32
+msgid "No hints are added to the uniform declaration."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:35
+msgid ""
+"Adds [code]hint_albedo[/code] as hint to the uniform declaration for proper "
+"sRGB to linear conversion."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:38
+msgid ""
+"Adds [code]hint_normal[/code] as hint to the uniform declaration, which "
+"internally converts the texture for proper usage as normal map."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemapUniform.xml:4
+msgid "A [Cubemap] uniform node to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemapUniform.xml:7
+msgid ""
+"Translated to [code]uniform samplerCube[/code] in the shader language. The "
+"output value can be used as port for [VisualShaderNodeCubemap]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:4
+msgid ""
+"Virtual class to define custom [VisualShaderNode]s for use in the Visual "
+"Shader Editor."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:7
+msgid ""
+"By inheriting this class you can create a custom [VisualShader] script addon "
+"which will be automatically added to the Visual Shader Editor. The "
+"[VisualShaderNode]'s behavior is defined by overriding the provided virtual "
+"methods.\n"
+"In order for the node to be registered as an editor addon, you must use the "
+"[code]tool[/code] keyword and provide a [code]class_name[/code] for your "
+"custom script. For example:\n"
+"[codeblock]\n"
+"tool\n"
+"extends VisualShaderNodeCustom\n"
+"class_name VisualShaderNodeNoise\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:16
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/"
+"visual_shader_plugins.html"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:23
+msgid ""
+"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].\n"
+"Defining this method is [b]optional[/b]. If not overridden, the node will be "
+"filed under the \"Addons\" category."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:39
+msgid ""
+"Override this method to define the actual shader code of the associated "
+"custom node. The shader code should be returned as a string, which can have "
+"multiple lines (the [code]\"\"\"[/code] multiline string construct can be "
+"used for convenience).\n"
+"The [code]input_vars[/code] and [code]output_vars[/code] arrays contain the "
+"string names of the various input and output variables, as defined by "
+"[code]_get_input_*[/code] and [code]_get_output_*[/code] virtual methods in "
+"this class.\n"
+"The output ports can be assigned values in the shader code. For example, "
+"[code]return output_vars[0] + \" = \" + input_vars[0] + \";\"[/code].\n"
+"You can customize the generated code based on the shader [code]mode[/code] "
+"(see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader."
+"Type]).\n"
+"Defining this method is [b]required[/b]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:50
+msgid ""
+"Override this method to define the description of the associated custom node "
+"in the Visual Shader Editor's members dialog.\n"
+"Defining this method is [b]optional[/b]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:60
+msgid ""
+"Override this method to add shader code on top of the global shader, to "
+"define your own standard library of reusable methods, varyings, constants, "
+"uniforms, etc. The shader code should be returned as a string, which can "
+"have multiple lines (the [code]\"\"\"[/code] multiline string construct can "
+"be used for convenience).\n"
+"Be careful with this functionality as it can cause name conflicts with other "
+"custom nodes, so be sure to give the defined entities unique names.\n"
+"You can customize the generated code based on the shader [code]mode[/code] "
+"(see [enum Shader.Mode]).\n"
+"Defining this method is [b]optional[/b]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:70
+msgid ""
+"Override this method to define the amount of input ports of the associated "
+"custom node.\n"
+"Defining this method is [b]required[/b]. If not overridden, the node has no "
+"input ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:80
+msgid ""
+"Override this method to define the names of input ports of the associated "
+"custom node. The names are used both for the input slots in the editor and "
+"as identifiers in the shader code, and are passed in the [code]input_vars[/"
+"code] array in [method _get_code].\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"input ports are named as [code]\"in\" + str(port)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:90
+msgid ""
+"Override this method to define the returned type of each input port of the "
+"associated custom node (see [enum VisualShaderNode.PortType] for possible "
+"types).\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"input ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] "
+"type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:98
+msgid ""
+"Override this method to define the name of the associated custom node in the "
+"Visual Shader Editor's members dialog and graph.\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"the node will be named as \"Unnamed\"."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:106
+msgid ""
+"Override this method to define the amount of output ports of the associated "
+"custom node.\n"
+"Defining this method is [b]required[/b]. If not overridden, the node has no "
+"output ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:116
+msgid ""
+"Override this method to define the names of output ports of the associated "
+"custom node. The names are used both for the output slots in the editor and "
+"as identifiers in the shader code, and are passed in the [code]output_vars[/"
+"code] array in [method _get_code].\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"output ports are named as [code]\"out\" + str(port)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:126
+msgid ""
+"Override this method to define the returned type of each output port of the "
+"associated custom node (see [enum VisualShaderNode.PortType] for possible "
+"types).\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"output ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] "
+"type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:134
+msgid ""
+"Override this method to define the return icon of the associated custom node "
+"in the Visual Shader Editor's members dialog.\n"
+"Defining this method is [b]optional[/b]. If not overridden, no return icon "
+"is shown."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:142
+msgid ""
+"Override this method to enable high-end mark in the Visual Shader Editor's "
+"members dialog.\n"
+"Defining this method is [b]optional[/b]. If not overridden, it's false."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDeterminant.xml:4
+msgid ""
+"Calculates the determinant of a [Transform] within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDeterminant.xml:7
+msgid "Translates to [code]deteminant(x)[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDotProduct.xml:4
+msgid "Calculates a dot product of two vectors within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDotProduct.xml:7
+msgid "Translates to [code]dot(a, b)[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeExpression.xml:4
+msgid ""
+"A custom visual shader graph expression written in Godot Shading Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeExpression.xml:7
+msgid ""
+"Custom Godot Shading Language expression, with a custom amount of input and "
+"output ports.\n"
+"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."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeExpression.xml:16
+msgid ""
+"An expression in Godot Shading Language, which will be injected at the start "
+"of the graph's matching shader function ([code]vertex[/code], "
+"[code]fragment[/code], or [code]light[/code]), and thus cannot be used to "
+"declare functions, varyings, uniforms, or global constants."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFaceForward.xml:4
+msgid ""
+"Returns the vector that points in the same direction as a reference vector "
+"within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFaceForward.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatConstant.xml:4
+msgid ""
+"A scalar floating-point constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatConstant.xml:7
+msgid "Translated to [code]float[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatConstant.xml:15
+msgid "A floating-point constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:4
+msgid ""
+"A scalar floating-point function to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:7
+msgid ""
+"Accept a floating-point scalar ([code]x[/code]) to the input port and "
+"transform it according to [member function]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:15
+#: doc/classes/VisualShaderNodeIntFunc.xml:15
+msgid ""
+"A function to be applied to the scalar. See [enum Function] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:20
+msgid ""
+"Returns the sine of the parameter. Translates to [code]sin(x)[/code] in the "
+"Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:23
+msgid ""
+"Returns the cosine of the parameter. Translates to [code]cos(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:26
+msgid ""
+"Returns the tangent of the parameter. Translates to [code]tan(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:29
+msgid ""
+"Returns the arc-sine of the parameter. Translates to [code]asin(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:32
+msgid ""
+"Returns the arc-cosine of the parameter. Translates to [code]acos(x)[/code] "
+"in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:35
+msgid ""
+"Returns the arc-tangent of the parameter. Translates to [code]atan(x)[/code] "
+"in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:38
+msgid ""
+"Returns the hyperbolic sine of the parameter. Translates to [code]sinh(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:41
+msgid ""
+"Returns the hyperbolic cosine of the parameter. Translates to [code]cosh(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:44
+msgid ""
+"Returns the hyperbolic tangent of the parameter. Translates to [code]tanh(x)"
+"[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:47
+msgid ""
+"Returns the natural logarithm of the parameter. Translates to [code]log(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:50
+msgid ""
+"Returns the natural exponentiation of the parameter. Translates to "
+"[code]exp(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:53
+msgid ""
+"Returns the square root of the parameter. Translates to [code]sqrt(x)[/code] "
+"in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:56
+#: doc/classes/VisualShaderNodeIntFunc.xml:20
+msgid ""
+"Returns the absolute value of the parameter. Translates to [code]abs(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:59
+#: doc/classes/VisualShaderNodeIntFunc.xml:29
+msgid ""
+"Extracts the sign of the parameter. Translates to [code]sign(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:62
+msgid ""
+"Finds the nearest integer less than or equal to the parameter. Translates to "
+"[code]floor(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:65
+msgid ""
+"Finds the nearest integer to the parameter. Translates to [code]round(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:68
+msgid ""
+"Finds the nearest integer that is greater than or equal to the parameter. "
+"Translates to [code]ceil(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:71
+msgid ""
+"Computes the fractional part of the argument. Translates to [code]fract(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:74
+msgid ""
+"Clamps the value between [code]0.0[/code] and [code]1.0[/code] using "
+"[code]min(max(x, 0.0), 1.0)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:77
+#: doc/classes/VisualShaderNodeIntFunc.xml:26
+msgid "Negates the [code]x[/code] using [code]-(x)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:80
+msgid ""
+"Returns the arc-hyperbolic-cosine of the parameter. Translates to "
+"[code]acosh(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:83
+msgid ""
+"Returns the arc-hyperbolic-sine of the parameter. Translates to "
+"[code]asinh(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:86
+msgid ""
+"Returns the arc-hyperbolic-tangent of the parameter. Translates to "
+"[code]atanh(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:89
+msgid ""
+"Convert a quantity in radians to degrees. Translates to [code]degrees(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:92
+msgid ""
+"Returns 2 raised by the power of the parameter. Translates to [code]exp2(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:95
+msgid ""
+"Returns the inverse of the square root of the parameter. Translates to "
+"[code]inversesqrt(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:98
+msgid ""
+"Returns the base 2 logarithm of the parameter. Translates to [code]log2(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:101
+msgid ""
+"Convert a quantity in degrees to radians. Translates to [code]radians(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:104
+msgid ""
+"Finds reciprocal value of dividing 1 by [code]x[/code] (i.e. [code]1 / x[/"
+"code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:107
+msgid ""
+"Finds the nearest even integer to the parameter. Translates to "
+"[code]roundEven(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:110
+msgid ""
+"Returns a value equal to the nearest integer to [code]x[/code] whose "
+"absolute value is not larger than the absolute value of [code]x[/code]. "
+"Translates to [code]trunc(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:113
+msgid "Subtracts scalar [code]x[/code] from 1 (i.e. [code]1 - x[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:4
+msgid ""
+"A floating-point scalar operator to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:7
+msgid ""
+"Applies [member operator] to two floating-point inputs: [code]a[/code] and "
+"[code]b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:20
+#: doc/classes/VisualShaderNodeIntOp.xml:20
+msgid "Sums two numbers using [code]a + b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:23
+#: doc/classes/VisualShaderNodeIntOp.xml:23
+msgid "Subtracts two numbers using [code]a - b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:26
+#: doc/classes/VisualShaderNodeIntOp.xml:26
+msgid "Multiplies two numbers using [code]a * b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:29
+#: doc/classes/VisualShaderNodeIntOp.xml:29
+msgid "Divides two numbers using [code]a / b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:32
+msgid ""
+"Calculates the remainder of two numbers. Translates to [code]mod(a, b)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:35
+msgid ""
+"Raises the [code]a[/code] to the power of [code]b[/code]. Translates to "
+"[code]pow(a, b)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:38
+#: doc/classes/VisualShaderNodeIntOp.xml:35
+msgid ""
+"Returns the greater of two numbers. Translates to [code]max(a, b)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:41
+msgid ""
+"Returns the lesser of two numbers. Translates to [code]min(a, b)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:44
+msgid ""
+"Returns the arc-tangent of the parameters. Translates to [code]atan(a, b)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:47
+msgid ""
+"Generates a step function by comparing [code]b[/code](x) to [code]a[/code]"
+"(edge). Returns 0.0 if [code]x[/code] is smaller than [code]edge[/code] and "
+"otherwise 1.0. Translates to [code]step(a, b)[/code] in the Godot Shader "
+"Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:4
+msgid "A scalar float uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:7
+msgid "Translated to [code]uniform float[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:15
+#: doc/classes/VisualShaderNodeIntUniform.xml:15
+msgid ""
+"A hint applied to the uniform, which controls the values it can take when "
+"set through the inspector."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:18
+#: doc/classes/VisualShaderNodeIntUniform.xml:18
+msgid ""
+"Minimum value for range hints. Used if [member hint] is set to [constant "
+"HINT_RANGE] or [constant HINT_RANGE_STEP]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:21
+#: doc/classes/VisualShaderNodeIntUniform.xml:21
+msgid ""
+"Maximum value for range hints. Used if [member hint] is set to [constant "
+"HINT_RANGE] or [constant HINT_RANGE_STEP]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:24
+#: doc/classes/VisualShaderNodeIntUniform.xml:24
+msgid ""
+"Step (increment) value for the range hint with step. Used if [member hint] "
+"is set to [constant HINT_RANGE_STEP]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:29
+#: doc/classes/VisualShaderNodeIntUniform.xml:29
+msgid "No hint used."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:32
+#: doc/classes/VisualShaderNodeIntUniform.xml:32
+msgid ""
+"A range hint for scalar value, which limits possible input values between "
+"[member min] and [member max]. Translated to [code]hint_range(min, max)[/"
+"code] in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:35
+#: doc/classes/VisualShaderNodeIntUniform.xml:35
+msgid ""
+"A range hint for scalar value with step, which limits possible input values "
+"between [member min] and [member max], with a step (increment) of [member "
+"step]). Translated to [code]hint_range(min, max, step)[/code] in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFresnel.xml:4
+msgid "A Fresnel effect to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFresnel.xml:7
+msgid ""
+"Returns falloff based on the dot product of surface normal and view "
+"direction of camera (pass associated inputs to it)."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGlobalExpression.xml:4
+msgid ""
+"A custom global visual shader graph expression written in Godot Shading "
+"Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGlobalExpression.xml:7
+msgid ""
+"Custom Godot Shader Language expression, which is placed on top of the "
+"generated shader. You can place various function definitions inside to call "
+"later in [VisualShaderNodeExpression]s (which are injected in the main "
+"shader functions). You can also declare varyings, uniforms and global "
+"constants."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:4
+msgid ""
+"Base class for a family of nodes with variable amount of input and output "
+"ports within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:7
+msgid "Currently, has no direct usage, use the derived classes instead."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:22
+msgid ""
+"Adds an input port with the specified [code]type[/code] (see [enum "
+"VisualShaderNode.PortType]) and [code]name[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:35
+msgid ""
+"Adds an output port with the specified [code]type[/code] (see [enum "
+"VisualShaderNode.PortType]) and [code]name[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:42
+msgid "Removes all previously specified input ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:49
+msgid "Removes all previously specified output ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:56
+msgid ""
+"Returns a free input port ID which can be used in [method add_input_port]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:63
+msgid ""
+"Returns a free output port ID which can be used in [method add_output_port]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:70
+msgid ""
+"Returns the number of input ports in use. Alternative for [method "
+"get_free_input_port_id]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:77
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:84
+msgid ""
+"Returns the number of output ports in use. Alternative for [method "
+"get_free_output_port_id]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:91
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:100
+msgid "Returns [code]true[/code] if the specified input port exists."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:109
+msgid "Returns [code]true[/code] if the specified output port exists."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:118
+msgid ""
+"Returns [code]true[/code] if the specified port name does not override an "
+"existed port name and is valid within the shader."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:127
+msgid "Removes the specified input port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:136
+msgid "Removes the specified output port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:147
+msgid "Renames the specified input port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:158
+msgid ""
+"Sets the specified input port's type (see [enum VisualShaderNode.PortType])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:167
+msgid ""
+"Defines all input ports using a [String] formatted as a colon-separated "
+"list: [code]id,type,name;[/code] (see [method add_input_port])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:178
+msgid "Renames the specified output port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:189
+msgid ""
+"Sets the specified output port's type (see [enum VisualShaderNode.PortType])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:198
+msgid ""
+"Defines all output ports using a [String] formatted as a colon-separated "
+"list: [code]id,type,name;[/code] (see [method add_output_port])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:204
+msgid "The size of the node in the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIf.xml:4
+msgid ""
+"Compares two floating-point numbers in order to return a required vector "
+"within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIf.xml:7
+msgid ""
+"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 > b[/code] and [code]a < b[/code] "
+"respectively."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:4
+msgid "Represents the input shader parameter within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:15
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:21
+msgid ""
+"One of the several input constants in lower-case style like: \"vertex\"([/"
+"code]VERTEX[code]) or \"point_size\"([code]POINT_SIZE[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:27
+msgid "Emitted when input is changed via [member input_name]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntConstant.xml:4
+msgid "A scalar integer constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntConstant.xml:7
+msgid "Translated to [code]int[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntConstant.xml:15
+msgid "An integer constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntFunc.xml:4
+msgid "A scalar integer function to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntFunc.xml:7
+msgid ""
+"Accept an integer scalar ([code]x[/code]) to the input port and transform it "
+"according to [member function]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntFunc.xml:23
+msgid ""
+"Constrains a parameter between [code]min[/code] and [code]max[/code]. "
+"Translates to [code]clamp(x, min, max)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:4
+msgid "An integer scalar operator to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:7
+msgid ""
+"Applies [member operator] to two integer inputs: [code]a[/code] and [code]b[/"
+"code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:32
+msgid "Calculates the remainder of two numbers using [code]a % b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:38
+msgid ""
+"Returns the lesser of two numbers. Translates to [code]max(a, b)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntUniform.xml:4
+msgid "A scalar integer uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntUniform.xml:7
+msgid "Translated to [code]uniform int[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:4
+msgid "Vertical scroll bar."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:7
+msgid ""
+"Vertical version of [ScrollBar], which goes from top (min) to bottom (max)."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:21
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] up. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:36
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] down. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:4
+msgid "Vertical version of [Separator]."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:7
+msgid ""
+"Vertical version of [Separator]. Even though it looks vertical, it is used "
+"to separate objects horizontally."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:17
+msgid ""
+"The width of the area covered by the separator. Effectively works like a "
+"minimum width."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:20
+msgid ""
+"The style for the separator line. Works best with [StyleBoxLine] (remember "
+"to enable [member StyleBoxLine.vertical])."
+msgstr ""
+
+#: doc/classes/VSlider.xml:4
+msgid "Vertical slider."
+msgstr ""
+
+#: doc/classes/VSlider.xml:7
+msgid ""
+"Vertical slider. See [Slider]. This one goes from bottom (min) to top (max)."
+msgstr ""
+
+#: doc/classes/VSlider.xml:24
+msgid "The background of the area below the grabber."
+msgstr ""
+
+#: doc/classes/VSlider.xml:33
+msgid ""
+"The background for the whole slider. Determines the width of the "
+"[code]grabber_area[/code]."
+msgstr ""
+
+#: doc/classes/VSplitContainer.xml:4
+msgid "Vertical split container."
+msgstr ""
+
+#: doc/classes/VSplitContainer.xml:7
+msgid ""
+"Vertical split container. See [SplitContainer]. This goes from top to bottom."
+msgstr ""
+
+#: doc/classes/WeakRef.xml:4
+msgid ""
+"Holds an [Object], but does not contribute to the reference count if the "
+"object is a reference."
+msgstr ""
+
+#: doc/classes/WeakRef.xml:7
+msgid ""
+"A weakref can hold a [Reference], without contributing to the reference "
+"counter. A weakref can be created from an [Object] using [method @GDScript."
+"weakref]. If this object is not a reference, weakref still works, however, "
+"it does not have any effect on the object. Weakrefs are useful in cases "
+"where multiple classes have variables that refer to each other. Without "
+"weakrefs, using these classes could lead to memory leaks, since both "
+"references keep each other from being released. Making part of the variables "
+"a weakref can prevent this cyclic dependency, and allows the references to "
+"be released."
+msgstr ""
+
+#: doc/classes/WeakRef.xml:16
+msgid "Returns the [Object] this weakref is referring to."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:14
+msgid "Closes this data channel, notifying the other peer."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:21
+msgid ""
+"Returns the id assigned to this channel during creation (or auto-assigned "
+"during negotiation).\n"
+"If the channel is not negotiated out-of-band the id will only be available "
+"after the connection is established (will return [code]65535[/code] until "
+"then)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:29
+msgid "Returns the label assigned to this channel during creation."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:36
+msgid ""
+"Returns the [code]maxPacketLifeTime[/code] value assigned to this channel "
+"during creation.\n"
+"Will be [code]65535[/code] if not specified."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:44
+msgid ""
+"Returns the [code]maxRetransmits[/code] value assigned to this channel "
+"during creation.\n"
+"Will be [code]65535[/code] if not specified."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:52
+msgid ""
+"Returns the sub-protocol assigned to this channel during creation. An empty "
+"string if not specified."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:59
+msgid "Returns the current state of this channel, see [enum ChannelState]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:66
+msgid ""
+"Returns [code]true[/code] if this channel was created with out-of-band "
+"configuration."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:73
+msgid ""
+"Returns [code]true[/code] if this channel was created with ordering enabled "
+"(default)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:80
+msgid "Reserved, but not used for now."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:87
+msgid ""
+"Returns [code]true[/code] if the last received packet was transferred as "
+"text. See [member write_mode]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:93
+msgid ""
+"The transfer mode to use when sending outgoing packet. Either text or binary."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:98
+msgid ""
+"Tells the channel to send data over this channel as text. An external peer "
+"(non-Godot) would receive this as a string."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:101
+msgid ""
+"Tells the channel to send data over this channel as binary. An external peer "
+"(non-Godot) would receive this as array buffer or blob."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:104
+msgid "The channel was created, but it's still trying to connect."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:107
+msgid "The channel is currently open, and data can flow over it."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:110
+msgid ""
+"The channel is being closed, no new messages will be accepted, but those "
+"already in queue will be flushed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:113
+msgid "The channel was closed, or connection failed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:4
+msgid ""
+"A simple interface to create a peer-to-peer mesh network composed of "
+"[WebRTCPeerConnection] that is compatible with the [MultiplayerAPI]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:7
+msgid ""
+"This class constructs a full mesh of [WebRTCPeerConnection] (one connection "
+"for each peer) that can be used as a [member MultiplayerAPI.network_peer].\n"
+"You can add each [WebRTCPeerConnection] via [method add_peer] or remove them "
+"via [method remove_peer]. Peers must be added in [constant "
+"WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate "
+"channels. This class will not create offers nor set descriptions, it will "
+"only poll them, and notify connections and disconnections.\n"
+"[signal NetworkedMultiplayerPeer.connection_succeeded] and [signal "
+"NetworkedMultiplayerPeer.server_disconnected] will not be emitted unless "
+"[code]server_compatibility[/code] is [code]true[/code] in [method "
+"initialize]. Beside that data transfer works like in a "
+"[NetworkedMultiplayerPeer]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:24
+msgid ""
+"Add a new peer to the mesh with the given [code]peer_id[/code]. The "
+"[WebRTCPeerConnection] must be in state [constant WebRTCPeerConnection."
+"STATE_NEW].\n"
+"Three channels will be created for reliable, unreliable, and ordered "
+"transport. The value of [code]unreliable_lifetime[/code] will be passed to "
+"the [code]maxPacketLifetime[/code] option when creating unreliable and "
+"ordered channels (see [method WebRTCPeerConnection.create_data_channel])."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:32
+msgid "Close all the add peer connections and channels, freeing all resources."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:41
+msgid ""
+"Return a dictionary representation of the peer with given [code]peer_id[/"
+"code] with three keys. [code]connection[/code] containing the "
+"[WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three "
+"[WebRTCDataChannel], and [code]connected[/code] a boolean representing if "
+"the peer connection is currently connected (all three channels are open)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:48
+msgid ""
+"Returns a dictionary which keys are the peer ids and values the peer "
+"representation as in [method get_peer]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:57
+msgid ""
+"Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers "
+"map (it might not be connected though)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:68
+msgid ""
+"Initialize the multiplayer peer with the given [code]peer_id[/code] (must be "
+"between 1 and 2147483647).\n"
+"If [code]server_compatibilty[/code] is [code]false[/code] (default), the "
+"multiplayer peer will be immediately in state [constant "
+"NetworkedMultiplayerPeer.CONNECTION_CONNECTED] and [signal "
+"NetworkedMultiplayerPeer.connection_succeeded] will not be emitted.\n"
+"If [code]server_compatibilty[/code] is [code]true[/code] the peer will "
+"suppress all [signal NetworkedMultiplayerPeer.peer_connected] signals until "
+"a peer with id [constant NetworkedMultiplayerPeer.TARGET_PEER_SERVER] "
+"connects and then emit [signal NetworkedMultiplayerPeer."
+"connection_succeeded]. After that the signal [signal "
+"NetworkedMultiplayerPeer.peer_connected] will be emitted for every already "
+"connected peer, and any new peer that might connect. If the server peer "
+"disconnects after that, signal [signal NetworkedMultiplayerPeer."
+"server_disconnected] will be emitted and state will become [constant "
+"NetworkedMultiplayerPeer.CONNECTION_CONNECTED]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:79
+msgid ""
+"Remove the peer with given [code]peer_id[/code] from the mesh. If the peer "
+"was connected, and [signal NetworkedMultiplayerPeer.peer_connected] was "
+"emitted for it, then [signal NetworkedMultiplayerPeer.peer_disconnected] "
+"will be emitted."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:4
+msgid "Interface to a WebRTC peer connection."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:7
+msgid ""
+"A WebRTC connection between the local computer and a remote peer. Provides "
+"an interface to connect, maintain and monitor the connection.\n"
+"Setting up a WebRTC connection between two peers from now on) may not seem a "
+"trivial task, but it can be broken down into 3 main steps:\n"
+"- The peer that wants to initiate the connection ([code]A[/code] from now "
+"on) creates an offer and send it to the other peer ([code]B[/code] from now "
+"on).\n"
+"- [code]B[/code] receives the offer, generate and answer, and sends it to "
+"[code]A[/code]).\n"
+"- [code]A[/code] and [code]B[/code] then generates and exchange ICE "
+"candidates with each other.\n"
+"After these steps, the connection should become connected. Keep on reading "
+"or look into the tutorial for more information."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:27
+msgid ""
+"Add an ice candidate generated by a remote peer (and received over the "
+"signaling server). See [signal ice_candidate_created]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:34
+msgid ""
+"Close the peer connection and all data channels associated with it. Note, "
+"you cannot reuse this object for a new connection unless you call [method "
+"initialize]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:47
+msgid ""
+"Returns a new [WebRTCDataChannel] (or [code]null[/code] on failure) with "
+"given [code]label[/code] and optionally configured via the [code]options[/"
+"code] dictionary. This method can only be called when the connection is in "
+"state [constant STATE_NEW].\n"
+"There are two ways to create a working data channel: either call [method "
+"create_data_channel] on only one of the peer and listen to [signal "
+"data_channel_received] on the other, or call [method create_data_channel] on "
+"both peers, with the same values, and the [code]negotiated[/code] option set "
+"to [code]true[/code].\n"
+"Valid [code]options[/code] are:\n"
+"[codeblock]\n"
+"{\n"
+" \"negotiated\": true, # When set to true (default off), means the "
+"channel is negotiated out of band. \"id\" must be set too. "
+"data_channel_received will not be called.\n"
+" \"id\": 1, # When \"negotiated\" is true this value must also be set to "
+"the same value on both peer.\n"
+"\n"
+" # Only one of maxRetransmits and maxPacketLifeTime can be specified, not "
+"both. They make the channel unreliable (but also better at real time).\n"
+" \"maxRetransmits\": 1, # Specify the maximum number of attempt the peer "
+"will make to retransmits packets if they are not acknowledged.\n"
+" \"maxPacketLifeTime\": 100, # Specify the maximum amount of time before "
+"giving up retransmitions of unacknowledged packets (in milliseconds).\n"
+" \"ordered\": true, # When in unreliable mode (i.e. either "
+"\"maxRetransmits\" or \"maxPacketLifetime\" is set), \"ordered\" (true by "
+"default) specify if packet ordering is to be enforced.\n"
+"\n"
+" \"protocol\": \"my-custom-protocol\", # A custom sub-protocol string for "
+"this channel.\n"
+"}\n"
+"[/codeblock]\n"
+"[b]Note:[/b] You must keep a reference to channels created this way, or it "
+"will be closed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:70
+msgid ""
+"Creates a new SDP offer to start a WebRTC connection with a remote peer. At "
+"least one [WebRTCDataChannel] must have been created before calling this "
+"method.\n"
+"If this functions returns [constant OK], [signal "
+"session_description_created] will be called when the session is ready to be "
+"sent."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:78
+msgid "Returns the connection state. See [enum ConnectionState]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:89
+msgid ""
+"Re-initialize this peer connection, closing any previously active "
+"connection, and going back to state [constant STATE_NEW]. A dictionary of "
+"[code]options[/code] can be passed to configure the peer connection.\n"
+"Valid [code]options[/code] are:\n"
+"[codeblock]\n"
+"{\n"
+" \"iceServers\": [\n"
+" {\n"
+" \"urls\": [ \"stun:stun.example.com:3478\" ], # One or more STUN "
+"servers.\n"
+" },\n"
+" {\n"
+" \"urls\": [ \"turn:turn.example.com:3478\" ], # One or more TURN "
+"servers.\n"
+" \"username\": \"a_username\", # Optional username for the TURN "
+"server.\n"
+" \"credentials\": \"a_password\", # Optional password for the "
+"TURN server.\n"
+" }\n"
+" ]\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:111
+msgid ""
+"Call this method frequently (e.g. in [method Node._process] or [method Node."
+"_physics_process]) to properly receive signals."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:122
+msgid ""
+"Sets the SDP description of the local peer. This should be called in "
+"response to [signal session_description_created].\n"
+"If [code]type[/code] is [code]answer[/code] the peer will start emitting "
+"[signal ice_candidate_created]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:134
+msgid ""
+"Sets the SDP description of the remote peer. This should be called with the "
+"values generated by a remote peer and received over the signaling server.\n"
+"If [code]type[/code] is [code]offer[/code] the peer will emit [signal "
+"session_description_created] with the appropriate answer.\n"
+"If [code]type[/code] is [code]answer[/code] the peer will start emitting "
+"[signal ice_candidate_created]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:145
+msgid ""
+"Emitted when a new in-band channel is received, i.e. when the channel was "
+"created with [code]negotiated: false[/code] (default).\n"
+"The object will be an instance of [WebRTCDataChannel]. You must keep a "
+"reference of it or it will be closed automatically. See [method "
+"create_data_channel]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:157
+msgid ""
+"Emitted when a new ICE candidate has been created. The three parameters are "
+"meant to be passed to the remote peer over the signaling server."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:166
+msgid ""
+"Emitted after a successful call to [method create_offer] or [method "
+"set_remote_description] (when it generates an answer). The parameters are "
+"meant to be passed to [method set_local_description] on this object, and "
+"sent to the remote peer over the signaling server."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:172
+msgid ""
+"The connection is new, data channels and an offer can be created in this "
+"state."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:175
+msgid ""
+"The peer is connecting, ICE is in progress, none of the transports has "
+"failed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:178
+msgid "The peer is connected, all ICE transports are connected."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:181
+msgid "At least one ICE transport is disconnected."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:184
+msgid "One or more of the ICE transports failed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:187
+msgid ""
+"The peer connection is closed (after calling [method close] for example)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:4
+msgid "A WebSocket client implementation."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:7
+msgid ""
+"This class implements a WebSocket client compatible with any RFC 6455-"
+"compliant WebSocket server.\n"
+"This client can be optionally used as a network peer for the "
+"[MultiplayerAPI].\n"
+"After starting the client ([method connect_to_url]), you will need to "
+"[method NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside "
+"[method Node._process]).\n"
+"You will receive appropriate signals when connecting, disconnecting, or when "
+"new data is available."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:27
+msgid ""
+"Connects to the given URL requesting one of the given [code]protocols[/code] "
+"as sub-protocol. If the list empty (default), no sub-protocol will be "
+"requested.\n"
+"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.\n"
+"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]).\n"
+"You can optionally pass a list of [code]custom_headers[/code] to be added to "
+"the handshake HTTP request.\n"
+"[b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in "
+"HTML5 exports due to browsers restrictions."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:42
+msgid ""
+"Disconnects this client from the connected host. See [method WebSocketPeer."
+"close] for more information."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:49
+msgid "Return the IP address of the currently connected host."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:56
+msgid "Return the IP port of the currently connected host."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:62
+msgid ""
+"If specified, this [X509Certificate] will be the only one accepted when "
+"connecting to an SSL host. Any other certificate provided by the server will "
+"be regarded as invalid.\n"
+"[b]Note:[/b] Specifying a custom [code]trusted_ssl_certificate[/code] is not "
+"supported in HTML5 exports due to browsers restrictions."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:66
+msgid ""
+"If [code]true[/code], SSL certificate verification is enabled.\n"
+"[b]Note:[/b] You must specify the certificates to be used in the Project "
+"Settings for it to work when exported."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:75
+msgid ""
+"Emitted when the connection to the server is closed. [code]was_clean_close[/"
+"code] will be [code]true[/code] if the connection was shutdown cleanly."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:80
+msgid "Emitted when the connection to the server fails."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:87
+msgid ""
+"Emitted when a connection with the server is established, [code]protocol[/"
+"code] will contain the sub-protocol agreed with the server."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:92
+msgid ""
+"Emitted when a WebSocket message is received.\n"
+"[b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level "
+"multiplayer peer."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:102
+msgid ""
+"Emitted when the server requests a clean close. You should keep polling "
+"until you get a [signal connection_closed] signal to achieve the clean "
+"close. See [method WebSocketPeer.close] for more details."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:4
+msgid "Base class for WebSocket server and client."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:7
+msgid ""
+"Base class for WebSocket server and client, allowing them to be used as "
+"network peer for the [MultiplayerAPI]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:18
+msgid ""
+"Returns the [WebSocketPeer] associated to the given [code]peer_id[/code]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:33
+msgid ""
+"Configures the buffer sizes for this WebSocket peer. Default values can be "
+"specified in the Project Settings under [code]network/limits[/code]. For "
+"server, values are meant per connected peer.\n"
+"The first two parameters define the size and queued packets limits of the "
+"input buffer, the last two of the output buffer.\n"
+"Buffer sizes are expressed in KiB, so [code]4 = 2^12 = 4096 bytes[/code]. "
+"All parameters will be rounded up to the nearest power of two.\n"
+"[b]Note:[/b] HTML5 exports only use the input buffer since the output one is "
+"managed by browsers."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:49
+msgid ""
+"Emitted when a packet is received from a peer.\n"
+"[b]Note:[/b] This signal is only emitted when the client or server is "
+"configured to use Godot multiplayer API."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:4
+msgid "A class representing a specific WebSocket connection."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:7
+msgid ""
+"This class represent a specific WebSocket connection, you can do lower level "
+"operations with it.\n"
+"You can choose to write to the socket in binary or text mode, and you can "
+"recognize the mode used for writing by the other peer."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:21
+msgid ""
+"Closes this WebSocket connection. [code]code[/code] is the status code for "
+"the closure (see RFC 6455 section 7.4 for a list of valid status codes). "
+"[code]reason[/code] is the human readable reason for closing the connection "
+"(can be any UTF-8 string that's smaller than 123 bytes).\n"
+"[b]Note:[/b] To achieve a clean close, you will need to keep polling until "
+"either [signal WebSocketClient.connection_closed] or [signal WebSocketServer."
+"client_disconnected] is received.\n"
+"[b]Note:[/b] The HTML5 export might not support all status codes. Please "
+"refer to browser-specific documentation for more details."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:30
+msgid ""
+"Returns the IP address of the connected peer.\n"
+"[b]Note:[/b] Not available in the HTML5 export."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:38
+msgid ""
+"Returns the remote port of the connected peer.\n"
+"[b]Note:[/b] Not available in the HTML5 export."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:46
+msgid "Gets the current selected write mode. See [enum WriteMode]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:53
+msgid "Returns [code]true[/code] if this peer is currently connected."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:62
+msgid ""
+"Disable Nagle's algorithm on the underling TCP socket (default). See [method "
+"StreamPeerTCP.set_no_delay] for more information.\n"
+"[b]Note:[/b] Not available in the HTML5 export."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:72
+msgid "Sets the socket to use the given [enum WriteMode]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:79
+msgid ""
+"Returns [code]true[/code] if the last received packet was sent as a text "
+"payload. See [enum WriteMode]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:85
+msgid ""
+"Specifies that WebSockets messages should be transferred as text payload "
+"(only valid UTF-8 is allowed)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:88
+msgid ""
+"Specifies that WebSockets messages should be transferred as binary payload "
+"(any byte combination is allowed)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:4
+msgid "A WebSocket server implementation."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:7
+msgid ""
+"This class implements a WebSocket server that can also support the high-"
+"level multiplayer API.\n"
+"After starting the server ([method listen]), you will need to [method "
+"NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside [method "
+"Node._process]). When clients connect, disconnect, or send data, you will "
+"receive the appropriate signal.\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:24
+msgid ""
+"Disconnects the peer identified by [code]id[/code] from the server. See "
+"[method WebSocketPeer.close] for more information."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:51
+msgid "Returns [code]true[/code] if a peer with the given ID is connected."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:58
+msgid ""
+"Returns [code]true[/code] if the server is actively listening on a port."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:71
+msgid ""
+"Starts listening on the given port.\n"
+"You can specify the desired subprotocols via the \"protocols\" array. If the "
+"list empty (default), no sub-protocol will be requested.\n"
+"If [code]true[/code] is passed as [code]gd_mp_api[/code], the server will "
+"behave like a network peer for the [MultiplayerAPI], connections from non-"
+"Godot clients will not work, and [signal data_received] will not be "
+"emitted.\n"
+"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(id)[/code] to "
+"communicate with the peer with given [code]id[/code] (e.g. "
+"[code]get_peer(id).get_available_packet_count[/code])."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:81
+msgid "Stops the server and clear its state."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:87
+msgid ""
+"When not set to [code]*[/code] will restrict incoming connections to the "
+"specified IP address. Setting [code]bind_ip[/code] to [code]127.0.0.1[/code] "
+"will cause the server to listen only to the local host."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:90
+msgid ""
+"When using SSL (see [member private_key] and [member ssl_certificate]), you "
+"can set this to a valid [X509Certificate] to be provided as additional CA "
+"chain information during the SSL handshake."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:93
+msgid ""
+"When set to a valid [CryptoKey] (along with [member ssl_certificate]) will "
+"cause the server to require SSL instead of regular TCP (i.e. the [code]wss://"
+"[/code] protocol)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:96
+msgid ""
+"When set to a valid [X509Certificate] (along with [member private_key]) will "
+"cause the server to require SSL instead of regular TCP (i.e. the [code]wss://"
+"[/code] protocol)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:108
+msgid ""
+"Emitted when a client requests a clean close. You should keep polling until "
+"you get a [signal client_disconnected] signal with the same [code]id[/code] "
+"to achieve the clean close. See [method WebSocketPeer.close] for more "
+"details."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:117
+msgid ""
+"Emitted when a new client connects. \"protocol\" will be the sub-protocol "
+"agreed with the client."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:126
+msgid ""
+"Emitted when a client disconnects. [code]was_clean_close[/code] will be "
+"[code]true[/code] if the connection was shutdown cleanly."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:133
+msgid ""
+"Emitted when a new message is received.\n"
+"[b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level "
+"multiplayer peer."
+msgstr ""
+
+#: doc/classes/World2D.xml:4
+msgid "Class that has everything pertaining to a 2D world."
+msgstr ""
+
+#: doc/classes/World2D.xml:7
+msgid ""
+"Class that has everything pertaining to a 2D world. A physics space, a "
+"visual scenario and a sound space. 2D nodes register their resources into "
+"the current 2D world."
+msgstr ""
+
+#: doc/classes/World2D.xml:16
+msgid ""
+"The [RID] of this world's canvas resource. Used by the [RenderingServer] for "
+"2D drawing."
+msgstr ""
+
+#: doc/classes/World2D.xml:19
+msgid ""
+"The state of this world's physics space. This allows arbitrary querying for "
+"collision."
+msgstr ""
+
+#: doc/classes/World2D.xml:22
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/World3D.xml:4
+msgid "Class that has everything pertaining to a world."
+msgstr ""
+
+#: doc/classes/World3D.xml:7
+msgid ""
+"Class that has everything pertaining to a world. A physics space, a visual "
+"scenario and a sound space. Node3D nodes register their resources into the "
+"current world."
+msgstr ""
+
+#: doc/classes/World3D.xml:18
+msgid ""
+"The World3D's physics direct space state, used for making various queries. "
+"Might be used only during [code]_physics_process[/code]."
+msgstr ""
+
+#: doc/classes/World3D.xml:21
+msgid "The World3D's [Environment]."
+msgstr ""
+
+#: doc/classes/World3D.xml:24
+msgid ""
+"The World3D's fallback_environment will be used if the World3D's "
+"[Environment] fails or is missing."
+msgstr ""
+
+#: doc/classes/World3D.xml:27
+msgid "The World3D's visual scenario."
+msgstr ""
+
+#: doc/classes/World3D.xml:30
+msgid "The World3D's physics space."
+msgstr ""
+
+#: doc/classes/WorldEnvironment.xml:4
+msgid ""
+"Default environment properties for the entire scene (post-processing "
+"effects, lighting and background settings)."
+msgstr ""
+
+#: doc/classes/WorldEnvironment.xml:7
+msgid ""
+"The [WorldEnvironment] node is used to configure the default [Environment] "
+"for the scene.\n"
+"The parameters defined in the [WorldEnvironment] can be overridden by an "
+"[Environment] node set on the current [Camera3D]. Additionally, only one "
+"[WorldEnvironment] may be instanced in a given scene at a time.\n"
+"The [WorldEnvironment] allows the user to specify default lighting "
+"parameters (e.g. ambient lighting), various post-processing effects (e.g. "
+"SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, "
+"skybox). Usually, these are added in order to improve the realism/color "
+"balance of the scene."
+msgstr ""
+
+#: doc/classes/WorldEnvironment.xml:20
+msgid ""
+"The [Environment] resource used by this [WorldEnvironment], defining the "
+"default properties."
+msgstr ""
+
+#: doc/classes/WorldMarginShape3D.xml:4
+msgid "Infinite plane shape for 3D collisions."
+msgstr ""
+
+#: doc/classes/WorldMarginShape3D.xml:7
+msgid ""
+"An infinite plane shape for 3D collisions. Note that the [Plane]'s normal "
+"matters; anything \"below\" the plane will collide with it. If the "
+"[WorldMarginShape3D] is used in a [PhysicsBody3D], it will cause colliding "
+"objects placed \"below\" it to teleport \"above\" the plane."
+msgstr ""
+
+#: doc/classes/WorldMarginShape3D.xml:15
+msgid "The [Plane] used by the [WorldMarginShape3D] for collision."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:4
+msgid "An X509 certificate (e.g. for SSL)."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:7
+msgid ""
+"The X509Certificate class represents an X509 certificate. Certificates can "
+"be loaded and saved like any other [Resource].\n"
+"They can be used as the server certificate in [method StreamPeerSSL."
+"accept_stream] (along with the proper [CryptoKey]), and to specify the only "
+"certificate that should be accepted when connecting to an SSL server via "
+"[method StreamPeerSSL.connect_to_stream].\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:20
+msgid "Loads a certificate from [code]path[/code] (\"*.crt\" file)."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:29
+msgid ""
+"Saves a certificate to the given [code]path[/code] (should be a \"*.crt\" "
+"file)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:4
+msgid ""
+"Low-level class for creating parsers for [url=https://en.wikipedia.org/wiki/"
+"XML]XML[/url] files."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:7
+msgid ""
+"This class can serve as base to make custom XML parsers. Since XML is a very "
+"flexible standard, this interface is low-level so it can be applied to any "
+"possible schema."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:16
+msgid "Gets the amount of attributes in the current element."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:25
+msgid ""
+"Gets the name of the attribute specified by the index in [code]idx[/code] "
+"argument."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:34
+msgid ""
+"Gets the value of the attribute specified by the index in [code]idx[/code] "
+"argument."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:41
+msgid "Gets the current line in the parsed file (currently not implemented)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:50
+msgid ""
+"Gets the value of a certain attribute of the current element by name. This "
+"will raise an error if the element has no such attribute."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:59
+msgid ""
+"Gets the value of a certain attribute of the current element by name. This "
+"will return an empty [String] if the attribute is not found."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:66
+msgid ""
+"Gets the contents of a text node. This will raise an error in any other type "
+"of node."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:73
+msgid ""
+"Gets the name of the current element node. This will raise an error if the "
+"current node type is neither [constant NODE_ELEMENT] nor [constant "
+"NODE_ELEMENT_END]."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:80
+msgid ""
+"Gets the byte offset of the current node since the beginning of the file or "
+"buffer."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:87
+msgid ""
+"Gets the type of the current node. Compare with [enum NodeType] constants."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:96
+msgid "Check whether the current element has a certain attribute."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:103
+msgid ""
+"Check whether the current element is empty (this only works for completely "
+"empty tags, e.g. [code]<element \\>[/code])."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:112
+msgid "Opens an XML file for parsing. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:121
+msgid "Opens an XML raw buffer for parsing. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:128
+msgid "Reads the next node of the file. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:137
+msgid ""
+"Moves the buffer cursor to a certain offset (since the beginning) and read "
+"the next node there. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:144
+msgid ""
+"Skips the current section. If the node contains other elements, they will be "
+"ignored and the cursor will go to the closing of the current element."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:150
+msgid "There's no node (no file or buffer opened)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:153
+msgid "Element (tag)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:156
+msgid "End of element."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:159
+msgid "Text node."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:162
+msgid "Comment node."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:165
+msgid "CDATA content."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:168
+msgid "Unknown node."
+msgstr ""
+
+#: doc/classes/YSort.xml:4
+msgid "Sort all child nodes based on their Y positions."
+msgstr ""
+
+#: doc/classes/YSort.xml:7
+msgid ""
+"Sort all child nodes based on their Y positions. The child node must inherit "
+"from [CanvasItem] for it to be sorted. Nodes that have a higher Y position "
+"will be drawn later, so they will appear on top of nodes that have a lower Y "
+"position.\n"
+"Nesting of YSort nodes is possible. Children YSort nodes will be sorted in "
+"the same space as the parent YSort, allowing to better organize a scene or "
+"divide it in multiple ones, yet keep the unique sorting."
+msgstr ""
+
+#: doc/classes/YSort.xml:16
+msgid ""
+"If [code]true[/code], child nodes are sorted, otherwise sorting is disabled."
+msgstr ""
diff --git a/doc/translations/extract.py b/doc/translations/extract.py
new file mode 100644
index 0000000000..a65f942b92
--- /dev/null
+++ b/doc/translations/extract.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import re
+import shutil
+from collections import OrderedDict
+
+EXTRACT_TAGS = ["description", "brief_description", "member", "constant", "theme_item", "link"]
+HEADER = """\
+# LANGUAGE translation of the Godot Engine class reference.
+# Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine class reference\\n"
+"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8-bit\\n"
+
+"""
+# Some strings used by makerst.py are normally part of the editor translations,
+# so we need to include them manually here for the online docs.
+BASE_STRINGS = [
+ "Description",
+ "Tutorials",
+ "Properties",
+ "Methods",
+ "Theme Properties",
+ "Signals",
+ "Enumerations",
+ "Constants",
+ "Property Descriptions",
+ "Method Descriptions",
+]
+
+## <xml-line-number-hack from="https://stackoverflow.com/a/36430270/10846399">
+import sys
+
+sys.modules["_elementtree"] = None
+import xml.etree.ElementTree as ET
+
+## override the parser to get the line number
+class LineNumberingParser(ET.XMLParser):
+ def _start(self, *args, **kwargs):
+ ## Here we assume the default XML parser which is expat
+ ## and copy its element position attributes into output Elements
+ element = super(self.__class__, self)._start(*args, **kwargs)
+ element._start_line_number = self.parser.CurrentLineNumber
+ element._start_column_number = self.parser.CurrentColumnNumber
+ element._start_byte_index = self.parser.CurrentByteIndex
+ return element
+
+ def _end(self, *args, **kwargs):
+ element = super(self.__class__, self)._end(*args, **kwargs)
+ element._end_line_number = self.parser.CurrentLineNumber
+ element._end_column_number = self.parser.CurrentColumnNumber
+ element._end_byte_index = self.parser.CurrentByteIndex
+ return element
+
+
+## </xml-line-number-hack>
+
+
+class Desc:
+ def __init__(self, line_no, msg, desc_list=None):
+ ## line_no : the line number where the desc is
+ ## msg : the description string
+ ## desc_list : the DescList it belongs to
+ self.line_no = line_no
+ self.msg = msg
+ self.desc_list = desc_list
+
+
+class DescList:
+ def __init__(self, doc, path):
+ ## doc : root xml element of the document
+ ## path : file path of the xml document
+ ## list : list of Desc objects for this document
+ self.doc = doc
+ self.path = path
+ self.list = []
+
+
+def print_error(error):
+ print("ERROR: {}".format(error))
+
+
+## build classes with xml elements recursively
+def _collect_classes_dir(path, classes):
+ if not os.path.isdir(path):
+ print_error("Invalid directory path: {}".format(path))
+ exit(1)
+ for _dir in map(lambda dir: os.path.join(path, dir), os.listdir(path)):
+ if os.path.isdir(_dir):
+ _collect_classes_dir(_dir, classes)
+ elif os.path.isfile(_dir):
+ if not _dir.endswith(".xml"):
+ # print("Got non-.xml file '{}', skipping.".format(path))
+ continue
+ _collect_classes_file(_dir, classes)
+
+
+## opens a file and parse xml add to classes
+def _collect_classes_file(path, classes):
+ if not os.path.isfile(path) or not path.endswith(".xml"):
+ print_error("Invalid xml file path: {}".format(path))
+ exit(1)
+ print("Collecting file: {}".format(os.path.basename(path)))
+
+ try:
+ tree = ET.parse(path, parser=LineNumberingParser())
+ except ET.ParseError as e:
+ print_error("Parse error reading file '{}': {}".format(path, e))
+ exit(1)
+
+ doc = tree.getroot()
+
+ if "name" in doc.attrib:
+ if "version" not in doc.attrib:
+ print_error("Version missing from 'doc', file: {}".format(path))
+
+ name = doc.attrib["name"]
+ if name in classes:
+ print_error("Duplicate class {} at path {}".format(name, path))
+ exit(1)
+ classes[name] = DescList(doc, path)
+ else:
+ print_error("Unknown XML file {}, skipping".format(path))
+
+
+## regions are list of tuples with size 3 (start_index, end_index, indent)
+## indication in string where the codeblock starts, ends, and it's indent
+## if i inside the region returns the indent, else returns -1
+def _get_xml_indent(i, regions):
+ for region in regions:
+ if region[0] < i < region[1]:
+ return region[2]
+ return -1
+
+
+## find and build all regions of codeblock which we need later
+def _make_codeblock_regions(desc, path=""):
+ code_block_end = False
+ code_block_index = 0
+ code_block_regions = []
+ while not code_block_end:
+ code_block_index = desc.find("[codeblock]", code_block_index)
+ if code_block_index < 0:
+ break
+ xml_indent = 0
+ while True:
+ ## [codeblock] always have a trailing new line and some tabs
+ ## those tabs are belongs to xml indentations not code indent
+ if desc[code_block_index + len("[codeblock]\n") + xml_indent] == "\t":
+ xml_indent += 1
+ else:
+ break
+ end_index = desc.find("[/codeblock]", code_block_index)
+ if end_index < 0:
+ print_error("Non terminating codeblock: {}".format(path))
+ exit(1)
+ code_block_regions.append((code_block_index, end_index, xml_indent))
+ code_block_index += 1
+ return code_block_regions
+
+
+def _strip_and_split_desc(desc, code_block_regions):
+ desc_strip = "" ## a stripped desc msg
+ total_indent = 0 ## code indent = total indent - xml indent
+ for i in range(len(desc)):
+ c = desc[i]
+ if c == "\n":
+ c = "\\n"
+ if c == '"':
+ c = '\\"'
+ if c == "\\":
+ c = "\\\\" ## <element \> is invalid for msgmerge
+ if c == "\t":
+ xml_indent = _get_xml_indent(i, code_block_regions)
+ if xml_indent >= 0:
+ total_indent += 1
+ if xml_indent < total_indent:
+ c = "\\t"
+ else:
+ continue
+ else:
+ continue
+ desc_strip += c
+ if c == "\\n":
+ total_indent = 0
+ return desc_strip
+
+
+## make catalog strings from xml elements
+def _make_translation_catalog(classes):
+ unique_msgs = OrderedDict()
+ for class_name in classes:
+ desc_list = classes[class_name]
+ for elem in desc_list.doc.iter():
+ if elem.tag in EXTRACT_TAGS:
+ if not elem.text or len(elem.text) == 0:
+ continue
+ line_no = elem._start_line_number if elem.text[0] != "\n" else elem._start_line_number + 1
+ desc_str = elem.text.strip()
+ code_block_regions = _make_codeblock_regions(desc_str, desc_list.path)
+ desc_msg = _strip_and_split_desc(desc_str, code_block_regions)
+ desc_obj = Desc(line_no, desc_msg, desc_list)
+ desc_list.list.append(desc_obj)
+
+ if desc_msg not in unique_msgs:
+ unique_msgs[desc_msg] = [desc_obj]
+ else:
+ unique_msgs[desc_msg].append(desc_obj)
+ return unique_msgs
+
+
+## generate the catalog file
+def _generate_translation_catalog_file(unique_msgs, output):
+ with open(output, "w", encoding="utf8") as f:
+ f.write(HEADER)
+ for msg in BASE_STRINGS:
+ f.write("#: doc/tools/makerst.py\n")
+ f.write('msgid "{}"\n'.format(msg))
+ f.write('msgstr ""\n\n')
+ for msg in unique_msgs:
+ if len(msg) == 0 or msg in BASE_STRINGS:
+ continue
+
+ f.write("#:")
+ desc_list = unique_msgs[msg]
+ for desc in desc_list:
+ path = desc.desc_list.path.replace("\\", "/")
+ if path.startswith("./"):
+ path = path[2:]
+ f.write(" {}:{}".format(path, desc.line_no))
+ f.write("\n")
+
+ f.write('msgid "{}"\n'.format(msg))
+ f.write('msgstr ""\n\n')
+
+ ## TODO: what if 'nt'?
+ if os.name == "posix":
+ print("Wrapping template at 79 characters for compatibility with Weblate.")
+ os.system("msgmerge -w79 {0} {0} > {0}.wrap".format(output))
+ shutil.move("{}.wrap".format(output), output)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--path", "-p", nargs="+", default=".", help="The directory or directories containing XML files to collect."
+ )
+ parser.add_argument("--output", "-o", default="translation_catalog.pot", help="The path to the output file.")
+ args = parser.parse_args()
+
+ output = os.path.abspath(args.output)
+ if not os.path.isdir(os.path.dirname(output)) or not output.endswith(".pot"):
+ print_error("Invalid output path: {}".format(output))
+ exit(1)
+
+ classes = OrderedDict()
+ for path in args.path:
+ if not os.path.isdir(path):
+ print_error("Invalid working directory path: {}".format(path))
+ exit(1)
+
+ print("\nCurrent working dir: {}".format(path))
+
+ path_classes = OrderedDict() ## dictionary of key=class_name, value=DescList objects
+ _collect_classes_dir(path, path_classes)
+ classes.update(path_classes)
+
+ classes = OrderedDict(sorted(classes.items(), key=lambda kv: kv[0].lower()))
+ unique_msgs = _make_translation_catalog(classes)
+ _generate_translation_catalog_file(unique_msgs, output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/doc/translations/fr.po b/doc/translations/fr.po
new file mode 100644
index 0000000000..6926376c05
--- /dev/null
+++ b/doc/translations/fr.po
@@ -0,0 +1,57458 @@
+# French translation of the Godot Engine class reference.
+# Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# Rémi Verschelde <remi@godotengine.org>, 2020.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine class reference\n"
+"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: \n"
+"Last-Translator: Rémi Verschelde <remi@godotengine.org>\n"
+"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
+"godot-classes/fr/>\n"
+"Language: fr\n"
+"X-Generator: Poedit 2.3\n"
+
+#: doc/tools/makerst.py
+msgid "Description"
+msgstr "Description"
+
+#: doc/tools/makerst.py
+msgid "Tutorials"
+msgstr "Tutoriels"
+
+#: doc/tools/makerst.py
+msgid "Properties"
+msgstr "Propriétés"
+
+#: doc/tools/makerst.py
+msgid "Methods"
+msgstr "Méthodes"
+
+#: doc/tools/makerst.py
+msgid "Theme Properties"
+msgstr "Propriétés de thème"
+
+#: doc/tools/makerst.py
+msgid "Signals"
+msgstr "Signaux"
+
+#: doc/tools/makerst.py
+msgid "Enumerations"
+msgstr "Énumérations"
+
+#: doc/tools/makerst.py
+msgid "Constants"
+msgstr "Constantes"
+
+#: doc/tools/makerst.py
+msgid "Property Descriptions"
+msgstr "Description des propriétés"
+
+#: doc/tools/makerst.py
+msgid "Method Descriptions"
+msgstr "Description des méthodes"
+
+#: modules/gdscript/doc_classes/@GDScript.xml:4
+msgid "Built-in GDScript functions."
+msgstr "Fonctions intégrées à GDScript."
+
+#: modules/gdscript/doc_classes/@GDScript.xml:7
+msgid ""
+"List of core built-in GDScript functions. Math functions and other "
+"utilities. Everything else is provided by objects. (Keywords: builtin, built "
+"in, global functions.)"
+msgstr ""
+"Liste de fonctions de base intégrées à GDScript. Fonctions mathématiques et "
+"autres fonctions utilitaires. Toutes les autres fonctionalités sont fournies "
+"directement par les objets. (Mots-clés : builtin, built-in, intégré, "
+"intégrées, fonctions de base, fonctions globales.)"
+
+#: modules/gdscript/doc_classes/@GDScript.xml:24
+msgid ""
+"Returns a color constructed from integer red, green, blue, and alpha "
+"channels. Each channel should have 8 bits of information ranging from 0 to "
+"255.\n"
+"[code]r8[/code] red channel\n"
+"[code]g8[/code] green channel\n"
+"[code]b8[/code] blue channel\n"
+"[code]a8[/code] alpha channel\n"
+"[codeblock]\n"
+"red = Color8(255, 0, 0)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:42
+msgid ""
+"Returns a color according to the standardized [code]name[/code] with "
+"[code]alpha[/code] ranging from 0 to 1.\n"
+"[codeblock]\n"
+"red = ColorN(\"red\", 1)\n"
+"[/codeblock]\n"
+"Supported color names are the same as the constants defined in [Color]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:55
+msgid ""
+"Returns the absolute value of parameter [code]s[/code] (i.e. unsigned value, "
+"works for integer and float).\n"
+"[codeblock]\n"
+"# a is 1\n"
+"a = abs(-1)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:68
+msgid ""
+"Returns the arc cosine of [code]s[/code] in radians. Use to get the angle of "
+"cosine [code]s[/code].\n"
+"[codeblock]\n"
+"# c is 0.523599 or 30 degrees if converted with rad2deg(s)\n"
+"c = acos(0.866025)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:81
+msgid ""
+"Returns the arc sine of [code]s[/code] in radians. Use to get the angle of "
+"sine [code]s[/code].\n"
+"[codeblock]\n"
+"# s is 0.523599 or 30 degrees if converted with rad2deg(s)\n"
+"s = asin(0.5)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:96
+msgid ""
+"Asserts that the [code]condition[/code] is [code]true[/code]. If the "
+"[code]condition[/code] is [code]false[/code], an error is generated and the "
+"program is halted until you resume it. Only executes in debug builds, or "
+"when running the game from the editor. Use it for debugging purposes, to "
+"make sure a statement is [code]true[/code] during development.\n"
+"The optional [code]message[/code] argument, if given, is shown in addition "
+"to the generic \"Assertion failed\" message. You can use this to provide "
+"additional details about why the assertion failed.\n"
+"[codeblock]\n"
+"# Imagine we always want speed to be between 0 and 20\n"
+"speed = -10\n"
+"assert(speed < 20) # True, the program will continue\n"
+"assert(speed >= 0) # False, the program will stop\n"
+"assert(speed >= 0 && speed < 20) # You can also combine the two conditional "
+"statements in one check\n"
+"assert(speed < 20, \"speed = %f, but the speed limit is 20\" % speed) # Show "
+"a message with clarifying details\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:114
+msgid ""
+"Returns the arc tangent of [code]s[/code] in radians. Use it to get the "
+"angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == "
+"angle[/code].\n"
+"The method cannot know in which quadrant the angle should fall. See [method "
+"atan2] if you always want an exact angle.\n"
+"[codeblock]\n"
+"a = atan(0.5) # a is 0.463648\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:129
+msgid ""
+"Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle "
+"of tangent [code]y/x[/code]. To compute the value, the method takes into "
+"account the sign of both arguments in order to determine the quadrant.\n"
+"[codeblock]\n"
+"a = atan2(0, -1) # a is 3.141593\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:143
+msgid ""
+"Decodes a byte array back to a value. When [code]allow_objects[/code] is "
+"[code]true[/code] decoding objects is allowed.\n"
+"[b]WARNING:[/b] Deserialized object can contain code which gets executed. Do "
+"not use this option if the serialized object comes from untrusted sources to "
+"avoid potential security threats (remote code execution)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:155
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:145
+msgid ""
+"Converts a 2D point expressed in the cartesian coordinate system (X and Y "
+"axis) to the polar coordinate system (a distance from the origin and an "
+"angle)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:164
+msgid ""
+"Rounds [code]s[/code] upward, returning the smallest integral value that is "
+"not less than [code]s[/code].\n"
+"[codeblock]\n"
+"i = ceil(1.45) # i is 2\n"
+"i = ceil(1.001) # i is 2\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:177
+msgid ""
+"Returns a character as a String of the given Unicode code point (which is "
+"compatible with ASCII code).\n"
+"[codeblock]\n"
+"a = char(65) # a is \"A\"\n"
+"a = char(65 + 32) # a is \"a\"\n"
+"a = char(8364) # a is \"€\"\n"
+"[/codeblock]\n"
+"This is the inverse of [method ord]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:196
+msgid ""
+"Clamps [code]value[/code] and returns a value not less than [code]min[/code] "
+"and not more than [code]max[/code].\n"
+"[codeblock]\n"
+"speed = 1000\n"
+"# a is 20\n"
+"a = clamp(speed, 1, 20)\n"
+"\n"
+"speed = -10\n"
+"# a is 1\n"
+"a = clamp(speed, 1, 20)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:216
+msgid ""
+"Converts from a type to another in the best way possible. The [code]type[/"
+"code] parameter uses the [enum Variant.Type] values.\n"
+"[codeblock]\n"
+"a = Vector2(1, 0)\n"
+"# Prints 1\n"
+"print(a.length())\n"
+"a = convert(a, TYPE_STRING)\n"
+"# Prints 6 as \"(1, 0)\" is 6 characters\n"
+"print(a.length())\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:233
+msgid ""
+"Returns the cosine of angle [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"# Prints 1 then -1\n"
+"print(cos(PI * 2))\n"
+"print(cos(PI))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:247
+msgid ""
+"Returns the hyperbolic cosine of [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"# Prints 1.543081\n"
+"print(cosh(1))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:260
+msgid "Converts from decibels to linear energy (audio)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:273
+msgid ""
+"Returns the result of [code]value[/code] decreased by [code]step[/code] * "
+"[code]amount[/code].\n"
+"[codeblock]\n"
+"# a = 59\n"
+"a = dectime(60, 10, 0.1))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:286
+msgid ""
+"Returns degrees converted to radians.\n"
+"[codeblock]\n"
+"# r is 3.141593\n"
+"r = deg2rad(180)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:299
+msgid ""
+"Converts a previously converted instance to a dictionary, back into an "
+"instance. Useful for deserializing."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:310
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:90
+msgid ""
+"Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is "
+"ease-in, 1+ is ease out. Negative values are in-out/out in."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:319
+msgid ""
+"The natural exponential function. It raises the mathematical constant [b]e[/"
+"b] to the power of [code]s[/code] and returns it.\n"
+"[b]e[/b] has an approximate value of 2.71828.\n"
+"For exponents to other bases use the method [method pow].\n"
+"[codeblock]\n"
+"a = exp(2) # Approximately 7.39\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:333
+msgid ""
+"Rounds [code]s[/code] to the closest smaller integer and returns it.\n"
+"[codeblock]\n"
+"# a is 2.0\n"
+"a = floor(2.99)\n"
+"# a is -3.0\n"
+"a = floor(-2.99)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] This method returns a float. If you need an integer, you can "
+"use [code]int(s)[/code] directly."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:351
+msgid ""
+"Returns the floating-point remainder of [code]a/b[/code], keeping the sign "
+"of [code]a[/code].\n"
+"[codeblock]\n"
+"# Remainder is 1.5\n"
+"var remainder = fmod(7, 5.5)\n"
+"[/codeblock]\n"
+"For the integer remainder operation, use the % operator."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:367
+msgid ""
+"Returns the floating-point modulus of [code]a/b[/code] that wraps equally in "
+"positive and negative.\n"
+"[codeblock]\n"
+"var i = -6\n"
+"while i < 5:\n"
+" prints(i, fposmod(i, 3))\n"
+" i += 1\n"
+"[/codeblock]\n"
+"Produces:\n"
+"[codeblock]\n"
+"-6 0\n"
+"-5 1\n"
+"-4 2\n"
+"-3 0\n"
+"-2 1\n"
+"-1 2\n"
+"0 0\n"
+"1 1\n"
+"2 2\n"
+"3 0\n"
+"4 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:398
+msgid ""
+"Returns a reference to the specified function [code]funcname[/code] in the "
+"[code]instance[/code] node. As functions aren't first-class objects in "
+"GDscript, use [code]funcref[/code] to store a [FuncRef] in a variable and "
+"call it later.\n"
+"[codeblock]\n"
+"func foo():\n"
+" return(\"bar\")\n"
+"\n"
+"a = funcref(self, \"foo\")\n"
+"print(a.call_func()) # Prints bar\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:412
+msgid ""
+"Returns an array of dictionaries representing the current call stack.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" foo()\n"
+"\n"
+"func foo():\n"
+" bar()\n"
+"\n"
+"func bar():\n"
+" print(get_stack())\n"
+"[/codeblock]\n"
+"would print\n"
+"[codeblock]\n"
+"[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, "
+"source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:435
+msgid ""
+"Returns the integer hash of the variable passed.\n"
+"[codeblock]\n"
+"print(hash(\"a\")) # Prints 177670\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:447
+msgid ""
+"Returns the passed instance converted to a dictionary (useful for "
+"serializing).\n"
+"[codeblock]\n"
+"var foo = \"bar\"\n"
+"func _ready():\n"
+" var d = inst2dict(self)\n"
+" print(d.keys())\n"
+" print(d.values())\n"
+"[/codeblock]\n"
+"Prints out:\n"
+"[codeblock]\n"
+"[@subpath, @path, foo]\n"
+"[, res://test.gd, bar]\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:468
+msgid ""
+"Returns the Object that corresponds to [code]instance_id[/code]. All Objects "
+"have a unique instance ID.\n"
+"[codeblock]\n"
+"var foo = \"bar\"\n"
+"func _ready():\n"
+" var id = get_instance_id()\n"
+" var inst = instance_from_id(id)\n"
+" print(inst.foo) # Prints bar\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:488
+msgid ""
+"Returns a normalized value considering the given range. This is the opposite "
+"of [method lerp].\n"
+"[codeblock]\n"
+"var middle = lerp(20, 30, 0.75)\n"
+"# `middle` is now 27.5.\n"
+"# Now, we pretend to have forgotten the original ratio and want to get it "
+"back.\n"
+"var ratio = inverse_lerp(20, 30, 27.5)\n"
+"# `ratio` is now 0.75.\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:506
+msgid ""
+"Returns [code]true[/code] if [code]a[/code] and [code]b[/code] are "
+"approximately equal to each other."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:515
+msgid ""
+"Returns whether [code]s[/code] is an infinity value (either positive "
+"infinity or negative infinity)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:524
+msgid ""
+"Returns whether [code]instance[/code] is a valid object (e.g. has not been "
+"deleted from memory)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:533
+msgid "Returns whether [code]s[/code] is a NaN (Not-A-Number) value."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:542
+msgid "Returns [code]true[/code] if [code]s[/code] is zero or almost zero."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:551
+msgid ""
+"Returns length of Variant [code]var[/code]. Length is the character count of "
+"String, element count of Array, size of Dictionary, etc.\n"
+"[b]Note:[/b] Generates a fatal error if Variant can not provide a length.\n"
+"[codeblock]\n"
+"a = [1, 2, 3, 4]\n"
+"len(a) # Returns 4\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:569
+msgid ""
+"Linearly interpolates between two values by a normalized value. This is the "
+"opposite of [method inverse_lerp].\n"
+"If the [code]from[/code] and [code]to[/code] arguments are of type [int] or "
+"[float], the return value is a [float].\n"
+"If both are of the same vector type ([Vector2], [Vector3] or [Color]), the "
+"return value will be of the same type ([code]lerp[/code] then calls the "
+"vector type's [code]linear_interpolate[/code] method).\n"
+"[codeblock]\n"
+"lerp(0, 4, 0.75) # Returns 3.0\n"
+"lerp(Vector2(1, 5), Vector2(3, 2), 0.5) # Returns Vector2(2, 3.5)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:588
+msgid ""
+"Linearly interpolates between two angles (in radians) by a normalized "
+"value.\n"
+"Similar to [method lerp], but interpolates correctly when the angles wrap "
+"around [constant @GDScript.TAU].\n"
+"[codeblock]\n"
+"extends Sprite\n"
+"var elapsed = 0.0\n"
+"func _process(delta):\n"
+" var min_angle = deg2rad(0.0)\n"
+" var max_angle = deg2rad(90.0)\n"
+" rotation = lerp_angle(min_angle, max_angle, elapsed)\n"
+" elapsed += delta\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:607
+msgid ""
+"Converts from linear energy to decibels (audio). This can be used to "
+"implement volume sliders that behave as expected (since volume isn't "
+"linear). Example:\n"
+"[codeblock]\n"
+"# \"Slider\" refers to a node that inherits Range such as HSlider or "
+"VSlider.\n"
+"# Its range must be configured to go from 0 to 1.\n"
+"# Change the bus name if you'd like to change the volume of a specific bus "
+"only.\n"
+"AudioServer.set_bus_volume_db(AudioServer.get_bus_index(\"Master\"), "
+"linear2db($Slider.value))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:622
+msgid ""
+"Loads a resource from the filesystem located at [code]path[/code].\n"
+"[b]Note:[/b] Resource paths can be obtained by right-clicking on a resource "
+"in the FileSystem dock and choosing [b]Copy Path[/b].\n"
+"[codeblock]\n"
+"# Load a scene called main located in the root of the project directory.\n"
+"var main = load(\"res://main.tscn\")\n"
+"[/codeblock]\n"
+"[b]Important:[/b] The path must be absolute, a local path will just return "
+"[code]null[/code]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:637
+msgid ""
+"Natural logarithm. The amount of time needed to reach a certain level of "
+"continuous growth.\n"
+"[b]Note:[/b] This is not the same as the \"log\" function on most "
+"calculators, which uses a base 10 logarithm.\n"
+"[codeblock]\n"
+"log(10) # Returns 2.302585\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:652
+msgid ""
+"Returns the maximum of two values.\n"
+"[codeblock]\n"
+"max(1, 2) # Returns 2\n"
+"max(-3.99, -4) # Returns -3.99\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:667
+msgid ""
+"Returns the minimum of two values.\n"
+"[codeblock]\n"
+"min(1, 2) # Returns 1\n"
+"min(-3.99, -4) # Returns -4\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:684
+msgid ""
+"Moves [code]from[/code] toward [code]to[/code] by the [code]delta[/code] "
+"value.\n"
+"Use a negative [code]delta[/code] value to move away.\n"
+"[codeblock]\n"
+"move_toward(10, 5, 4) # Returns 6\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:697
+msgid ""
+"Returns the nearest larger power of 2 for integer [code]value[/code].\n"
+"[codeblock]\n"
+"nearest_po2(3) # Returns 4\n"
+"nearest_po2(4) # Returns 4\n"
+"nearest_po2(5) # Returns 8\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:711
+msgid ""
+"Returns an integer representing the Unicode code point of the given Unicode "
+"character [code]char[/code].\n"
+"[codeblock]\n"
+"a = ord(\"A\") # a is 65\n"
+"a = ord(\"a\") # a is 97\n"
+"a = ord(\"€\") # a is 8364\n"
+"[/codeblock]\n"
+"This is the inverse of [method char]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:726
+msgid ""
+"Parse JSON text to a Variant (use [method typeof] to check if it is what you "
+"expect).\n"
+"Be aware that the JSON specification does not define integer or float types, "
+"but only a number type. Therefore, parsing a JSON text will convert all "
+"numerical values to [float] types.\n"
+"Note that JSON objects do not preserve key order like Godot dictionaries, "
+"thus you should not rely on keys being in a certain order if a dictionary is "
+"constructed from JSON. In contrast, JSON arrays retain the order of their "
+"elements:\n"
+"[codeblock]\n"
+"p = parse_json('[\"a\", \"b\", \"c\"]')\n"
+"if typeof(p) == TYPE_ARRAY:\n"
+" print(p[0]) # Prints a\n"
+"else:\n"
+" print(\"unexpected results\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:746
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:142
+msgid ""
+"Converts a 2D point expressed in the polar coordinate system (a distance "
+"from the origin [code]r[/code] and an angle [code]th[/code]) to the "
+"cartesian coordinate system (X and Y axis)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:757
+msgid ""
+"Returns the integer modulus of [code]a/b[/code] that wraps equally in "
+"positive and negative.\n"
+"[codeblock]\n"
+"var i = -6\n"
+"while i < 5:\n"
+" prints(i, posmod(i, 3))\n"
+" i += 1\n"
+"[/codeblock]\n"
+"Produces:\n"
+"[codeblock]\n"
+"-6 0\n"
+"-5 1\n"
+"-4 2\n"
+"-3 0\n"
+"-2 1\n"
+"-1 2\n"
+"0 0\n"
+"1 1\n"
+"2 2\n"
+"3 0\n"
+"4 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:788
+msgid ""
+"Returns the result of [code]x[/code] raised to the power of [code]y[/code].\n"
+"[codeblock]\n"
+"pow(2, 5) # Returns 32\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:800
+msgid ""
+"Returns a resource from the filesystem that is loaded during script "
+"parsing.\n"
+"[b]Note:[/b] Resource paths can be obtained by right clicking on a resource "
+"in the Assets Panel and choosing \"Copy Path\".\n"
+"[codeblock]\n"
+"# Load a scene called main located in the root of the project directory.\n"
+"var main = preload(\"res://main.tscn\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:812
+msgid ""
+"Converts one or more arguments to strings in the best way possible and "
+"prints them to the console.\n"
+"[codeblock]\n"
+"a = [1, 2, 3]\n"
+"print(\"a\", \"b\", a) # Prints ab[1, 2, 3]\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:823
+msgid "Like [method print], but prints only when used in debug mode."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:830
+msgid ""
+"Prints a stack track at code location, only works when running with debugger "
+"turned on.\n"
+"Output in the console would look something like this:\n"
+"[codeblock]\n"
+"Frame 0 - res://test.gd:16 in function '_process'\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:841
+msgid ""
+"Prints one or more arguments to strings in the best way possible to standard "
+"error line.\n"
+"[codeblock]\n"
+"printerr(\"prints to stderr\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:851
+msgid ""
+"Prints one or more arguments to strings in the best way possible to console. "
+"No newline is added at the end.\n"
+"[codeblock]\n"
+"printraw(\"A\")\n"
+"printraw(\"B\")\n"
+"# Prints AB\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Due to limitations with Godot's built-in console, this only "
+"prints to the terminal. If you need to print in the editor, use another "
+"method, such as [method print]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:864
+msgid ""
+"Prints one or more arguments to the console with a space between each "
+"argument.\n"
+"[codeblock]\n"
+"prints(\"A\", \"B\", \"C\") # Prints A B C\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:874
+msgid ""
+"Prints one or more arguments to the console with a tab between each "
+"argument.\n"
+"[codeblock]\n"
+"printt(\"A\", \"B\", \"C\") # Prints A B C\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:886
+msgid ""
+"Pushes an error message to Godot's built-in debugger and to the OS "
+"terminal.\n"
+"[codeblock]\n"
+"push_error(\"test error\") # Prints \"test error\" to debugger and terminal "
+"as error call\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:898
+msgid ""
+"Pushes a warning message to Godot's built-in debugger and to the OS "
+"terminal.\n"
+"[codeblock]\n"
+"push_warning(\"test warning\") # Prints \"test warning\" to debugger and "
+"terminal as warning call\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:910
+msgid ""
+"Converts from radians to degrees.\n"
+"[codeblock]\n"
+"rad2deg(0.523599) # Returns 30\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:924
+msgid ""
+"Random range, any floating point value between [code]from[/code] and "
+"[code]to[/code].\n"
+"[codeblock]\n"
+"prints(rand_range(0, 1), rand_range(0, 1)) # Prints e.g. 0.135591 0.405263\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:936
+msgid ""
+"Random from seed: pass a [code]seed[/code], and an array with both number "
+"and new seed is returned. \"Seed\" here refers to the internal state of the "
+"pseudo random number generator. The internal state of the current "
+"implementation is 64 bits."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:943
+msgid ""
+"Returns a random floating point value on the interval [code][0, 1][/code].\n"
+"[codeblock]\n"
+"randf() # Returns e.g. 0.375671\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:953
+msgid ""
+"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).\n"
+"[codeblock]\n"
+"randi() # Returns random integer between 0 and 2^32 - 1\n"
+"randi() % 20 # Returns random integer between 0 and 19\n"
+"randi() % 100 # Returns random integer between 0 and 99\n"
+"randi() % 100 + 1 # Returns random integer between 1 and 100\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:966
+msgid ""
+"Randomizes the seed (or the internal state) of the random number generator. "
+"Current implementation reseeds using a number based on time.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" randomize()\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:977
+msgid ""
+"Returns an array with the given range. Range can be 1 argument N (0 to N-1), "
+"two arguments (initial, final-1) or three arguments (initial, final-1, "
+"increment).\n"
+"[codeblock]\n"
+"for i in range(4):\n"
+" print(i)\n"
+"for i in range(2, 5):\n"
+" print(i)\n"
+"for i in range(0, 6, 2):\n"
+" print(i)\n"
+"[/codeblock]\n"
+"Output:\n"
+"[codeblock]\n"
+"0\n"
+"1\n"
+"2\n"
+"3\n"
+"\n"
+"2\n"
+"3\n"
+"4\n"
+"\n"
+"0\n"
+"2\n"
+"4\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1017
+msgid ""
+"Maps a [code]value[/code] from range [code][istart, istop][/code] to [code]"
+"[ostart, ostop][/code].\n"
+"[codeblock]\n"
+"range_lerp(75, 0, 100, -1, 1) # Returns 0.5\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1029
+msgid ""
+"Returns the integral value that is nearest to [code]s[/code], with halfway "
+"cases rounded away from zero.\n"
+"[codeblock]\n"
+"round(2.6) # Returns 3\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1041
+msgid ""
+"Sets seed for the random number generator.\n"
+"[codeblock]\n"
+"my_seed = \"Godot Rocks\"\n"
+"seed(my_seed.hash())\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1054
+msgid ""
+"Returns the sign of [code]s[/code]: -1 or 1. Returns 0 if [code]s[/code] is "
+"0.\n"
+"[codeblock]\n"
+"sign(-6) # Returns -1\n"
+"sign(0) # Returns 0\n"
+"sign(6) # Returns 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1068
+msgid ""
+"Returns the sine of angle [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"sin(0.523599) # Returns 0.5\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1080
+msgid ""
+"Returns the hyperbolic sine of [code]s[/code].\n"
+"[codeblock]\n"
+"a = log(2.0) # Returns 0.693147\n"
+"sinh(a) # Returns 0.75\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1097
+msgid ""
+"Returns a number smoothly interpolated between the [code]from[/code] and "
+"[code]to[/code], based on the [code]weight[/code]. Similar to [method lerp], "
+"but interpolates faster at the beginning and slower at the end.\n"
+"[codeblock]\n"
+"smoothstep(0, 2, 0.5) # Returns 0.15\n"
+"smoothstep(0, 2, 1.0) # Returns 0.5\n"
+"smoothstep(0, 2, 2.0) # Returns 1.0\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1111
+msgid ""
+"Returns the square root of [code]s[/code].\n"
+"[codeblock]\n"
+"sqrt(9) # Returns 3\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1123
+msgid ""
+"Returns the position of the first non-zero digit, after the decimal point. "
+"Note that the maximum return value is 10, which is a design decision in the "
+"implementation.\n"
+"[codeblock]\n"
+"# n is 0\n"
+"n = step_decimals(5)\n"
+"# n is 4\n"
+"n = step_decimals(1.0005)\n"
+"# n is 9\n"
+"n = step_decimals(0.000000005)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1142
+msgid ""
+"Snaps float value [code]s[/code] to a given [code]step[/code]. This can also "
+"be used to round a floating point number to an arbitrary number of "
+"decimals.\n"
+"[codeblock]\n"
+"stepify(100, 32) # Returns 96\n"
+"stepify(3.14159, 0.01) # Returns 3.14\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1153
+msgid ""
+"Converts one or more arguments to string in the best way possible.\n"
+"[codeblock]\n"
+"var a = [10, 20, 30]\n"
+"var b = str(a);\n"
+"len(a) # Returns 3\n"
+"len(b) # Returns 12\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1168
+msgid ""
+"Converts a formatted string that was returned by [method var2str] to the "
+"original value.\n"
+"[codeblock]\n"
+"a = '{ \"a\": 1, \"b\": 2 }'\n"
+"b = str2var(a)\n"
+"print(b[\"a\"]) # Prints 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1182
+msgid ""
+"Returns the tangent of angle [code]s[/code] in radians.\n"
+"[codeblock]\n"
+"tan(deg2rad(45)) # Returns 1\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1194
+msgid ""
+"Returns the hyperbolic tangent of [code]s[/code].\n"
+"[codeblock]\n"
+"a = log(2.0) # Returns 0.693147\n"
+"tanh(a) # Returns 0.6\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1207
+msgid ""
+"Converts a Variant [code]var[/code] to JSON text and return the result. "
+"Useful for serializing data to store or send over the network.\n"
+"[codeblock]\n"
+"a = { \"a\": 1, \"b\": 2 }\n"
+"b = to_json(a)\n"
+"print(b) # {\"a\":1, \"b\":2}\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1221
+msgid ""
+"Returns whether the given class exists in [ClassDB].\n"
+"[codeblock]\n"
+"type_exists(\"Sprite2D\") # Returns true\n"
+"type_exists(\"Variant\") # Returns false\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1234
+msgid ""
+"Returns the internal type of the given Variant object, using the [enum "
+"Variant.Type] values.\n"
+"[codeblock]\n"
+"p = parse_json('[\"a\", \"b\", \"c\"]')\n"
+"if typeof(p) == TYPE_ARRAY:\n"
+" print(p[0]) # Prints a\n"
+"else:\n"
+" print(\"unexpected results\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1250
+msgid ""
+"Checks that [code]json[/code] is valid JSON data. Returns an empty string if "
+"valid, or an error message otherwise.\n"
+"[codeblock]\n"
+"j = to_json([1, 2, 3])\n"
+"v = validate_json(j)\n"
+"if not v:\n"
+" print(\"valid\")\n"
+"else:\n"
+" prints(\"invalid\", v)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1269
+msgid ""
+"Encodes a variable value to a byte array. When [code]full_objects[/code] is "
+"[code]true[/code] encoding objects is allowed (and can potentially include "
+"code)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1278
+msgid ""
+"Converts a Variant [code]var[/code] to a formatted string that can later be "
+"parsed using [method str2var].\n"
+"[codeblock]\n"
+"a = { \"a\": 1, \"b\": 2 }\n"
+"print(var2str(a))\n"
+"[/codeblock]\n"
+"prints\n"
+"[codeblock]\n"
+"{\n"
+"\"a\": 1,\n"
+"\"b\": 2\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1298
+msgid ""
+"Returns a weak reference to an object.\n"
+"A weak reference to an object is not enough to keep the object alive: when "
+"the only remaining references to a referent are weak references, garbage "
+"collection is free to destroy the referent and reuse its memory for "
+"something else. However, until the object is actually destroyed the weak "
+"reference may return the object even if there are no strong references to it."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1312
+msgid ""
+"Wraps float [code]value[/code] between [code]min[/code] and [code]max[/"
+"code].\n"
+"Usable for creating loop-alike behavior or infinite surfaces.\n"
+"[codeblock]\n"
+"# a is 0.5\n"
+"a = wrapf(10.5, 0.0, 10.0)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# a is 9.5\n"
+"a = wrapf(-0.5, 0.0, 10.0)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# Infinite loop between 0.0 and 0.99\n"
+"f = wrapf(f + 0.1, 0.0, 1.0)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# Infinite rotation (in radians)\n"
+"angle = wrapf(angle + 0.1, 0.0, TAU)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] If you just want to wrap between 0.0 and [code]n[/code] (where "
+"[code]n[/code] is a positive floating-point value), it is better for "
+"performance to use the [method fmod] method like [code]fmod(number, n)[/"
+"code].\n"
+"[code]wrapf[/code] is more flexible than using the [method fmod] approach by "
+"giving the user a simple control over the minimum value. It also fully "
+"supports negative numbers, e.g.\n"
+"[codeblock]\n"
+"# Infinite rotation (in radians)\n"
+"angle = wrapf(angle + 0.1, -PI, PI)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1348
+msgid ""
+"Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/"
+"code].\n"
+"Usable for creating loop-alike behavior or infinite surfaces.\n"
+"[codeblock]\n"
+"# a is 0\n"
+"a = wrapi(10, 0, 10)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# a is 9\n"
+"a = wrapi(-1, 0, 10)\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# Infinite loop between 0 and 9\n"
+"frame = wrapi(frame + 1, 0, 10)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] If you just want to wrap between 0 and [code]n[/code] (where "
+"[code]n[/code] is a positive integer value), it is better for performance to "
+"use the modulo operator like [code]number % n[/code].\n"
+"[code]wrapi[/code] is more flexible than using the modulo approach by giving "
+"the user a simple control over the minimum value. It also fully supports "
+"negative numbers, e.g.\n"
+"[codeblock]\n"
+"# result is -2\n"
+"var result = wrapi(-6, -5, -1)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1378
+msgid ""
+"Stops the function execution and returns the current suspended state to the "
+"calling function.\n"
+"From the caller, call [method GDScriptFunctionState.resume] on the state to "
+"resume execution. This invalidates the state. Within the resumed function, "
+"[code]yield()[/code] returns whatever was passed to the [code]resume()[/"
+"code] function call.\n"
+"If passed an object and a signal, the execution is resumed when the object "
+"emits the given signal. In this case, [code]yield()[/code] returns the "
+"argument passed to [code]emit_signal()[/code] if the signal takes only one "
+"argument, or an array containing all the arguments passed to "
+"[code]emit_signal()[/code] if the signal takes multiple arguments.\n"
+"You can also use [code]yield[/code] to wait for a function to finish:\n"
+"[codeblock]\n"
+"func _ready():\n"
+" yield(countdown(), \"completed\") # waiting for the countdown() function "
+"to complete\n"
+" print('Ready')\n"
+"\n"
+"func countdown():\n"
+" yield(get_tree(), \"idle_frame\") # returns a GDScriptFunctionState "
+"object to _ready()\n"
+" print(3)\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(2)\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(1)\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+"\n"
+"# prints:\n"
+"# 3\n"
+"# 2\n"
+"# 1\n"
+"# Ready\n"
+"[/codeblock]\n"
+"When yielding on a function, the [code]completed[/code] signal will be "
+"emitted automatically when the function returns. It can, therefore, be used "
+"as the [code]signal[/code] parameter of the [code]yield[/code] method to "
+"resume.\n"
+"In order to yield on a function, the resulting function should also return a "
+"[code]GDScriptFunctionState[/code]. Notice [code]yield(get_tree(), "
+"\"idle_frame\")[/code] from the above example."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1409
+msgid ""
+"Constant that represents how many times the diameter of a circle fits around "
+"its perimeter."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1412
+msgid "The circle constant, the circumference of the unit circle."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1415
+msgid "A positive infinity. (For negative infinity, use -INF)."
+msgstr ""
+
+#: modules/gdscript/doc_classes/@GDScript.xml:1418
+msgid ""
+"Macro constant that expands to an expression of type float that represents a "
+"NaN.\n"
+"The NaN values are used to identify undefined or non-representable values "
+"for floating-point elements, such as the square root of negative numbers or "
+"the result of 0/0."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:4
+msgid "Global scope constants and variables."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:7
+msgid ""
+"Global scope constants and variables. This is all that resides in the "
+"globals, constants regarding error codes, keycodes, property hints, etc.\n"
+"Singletons are also documented here, since they can be accessed from "
+"anywhere."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:16
+msgid "The [ARVRServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:19
+msgid "The [AudioServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:22
+msgid "The [CameraServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:25
+msgid "The [ClassDB] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:28
+msgid "The [Engine] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:31
+msgid "The [Geometry] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:34
+msgid ""
+"The [GodotSharp] singleton. Only available when using Godot's Mono build."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:37
+msgid "The [IP] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:40
+msgid "The [InputFilter] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:43
+msgid "The [InputMap] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:46
+msgid "The [JSON] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:49
+msgid ""
+"The [JavaClassWrapper] singleton.\n"
+"[b]Note:[/b] Only implemented on Android."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:53
+msgid ""
+"The [JavaScript] singleton.\n"
+"[b]Note:[/b] Only implemented on HTML5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:57
+msgid "The [Marshalls] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:60
+msgid "The [NavigationMeshGenerator] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:63 doc/classes/@GlobalScope.xml:66
+msgid "The [NavigationServer2D] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:69
+msgid "The [OS] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:72
+msgid "The [Performance] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:75
+msgid "The [PhysicsServer2D] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:78
+msgid "The [PhysicsServer3D] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:81
+msgid "The [ProjectSettings] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:84
+msgid "The [RenderingServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:87
+msgid "The [ResourceLoader] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:90
+msgid "The [ResourceSaver] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:93
+msgid "The [TranslationServer] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:96
+msgid "The [VisualScriptEditor] singleton."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:101
+msgid "Left margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:104
+msgid "Top margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:107
+msgid "Right margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:110
+msgid ""
+"Bottom margin, usually used for [Control] or [StyleBox]-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:113
+msgid "Top-left corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:116
+msgid "Top-right corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:119
+msgid "Bottom-right corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:122
+msgid "Bottom-left corner."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:125
+msgid ""
+"General vertical alignment, usually used for [Separator], [ScrollBar], "
+"[Slider], etc."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:128
+msgid ""
+"General horizontal alignment, usually used for [Separator], [ScrollBar], "
+"[Slider], etc."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:131
+msgid "Horizontal left alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:134
+msgid "Horizontal center alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:137
+msgid "Horizontal right alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:140
+msgid "Vertical top alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:143
+msgid "Vertical center alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:146
+msgid "Vertical bottom alignment, usually for text-derived classes."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:149
+msgid "Keycodes with this bit applied are non-printable."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:152
+msgid "Escape key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:155
+msgid "Tab key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:158
+msgid "Shift+Tab key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:161
+msgid "Backspace key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:164
+msgid "Return key (on the main keyboard)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:167
+msgid "Enter key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:170
+msgid "Insert key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:173
+msgid "Delete key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:176
+msgid "Pause key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:179
+msgid "Print Screen key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:182
+msgid "System Request key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:185
+msgid "Clear key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:188
+msgid "Home key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:191
+msgid "End key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:194
+msgid "Left arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:197
+msgid "Up arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:200
+msgid "Right arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:203
+msgid "Down arrow key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:206
+msgid "Page Up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:209
+msgid "Page Down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:212
+msgid "Shift key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:215
+msgid "Control key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:218
+msgid "Meta key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:221
+msgid "Alt key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:224
+msgid "Caps Lock key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:227
+msgid "Num Lock key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:230
+msgid "Scroll Lock key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:233
+msgid "F1 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:236
+msgid "F2 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:239
+msgid "F3 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:242
+msgid "F4 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:245
+msgid "F5 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:248
+msgid "F6 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:251
+msgid "F7 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:254
+msgid "F8 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:257
+msgid "F9 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:260
+msgid "F10 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:263
+msgid "F11 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:266
+msgid "F12 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:269
+msgid "F13 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:272
+msgid "F14 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:275
+msgid "F15 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:278
+msgid "F16 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:281
+msgid "Multiply (*) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:284
+msgid "Divide (/) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:287
+msgid "Subtract (-) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:290
+msgid "Period (.) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:293
+msgid "Add (+) key on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:296
+msgid "Number 0 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:299
+msgid "Number 1 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:302
+msgid "Number 2 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:305
+msgid "Number 3 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:308
+msgid "Number 4 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:311
+msgid "Number 5 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:314
+msgid "Number 6 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:317
+msgid "Number 7 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:320
+msgid "Number 8 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:323
+msgid "Number 9 on the numeric keypad."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:326
+msgid "Left Super key (Windows key)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:329
+msgid "Right Super key (Windows key)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:332
+msgid "Context menu key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:335
+msgid "Left Hyper key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:338
+msgid "Right Hyper key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:341
+msgid "Help key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:344
+msgid "Left Direction key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:347
+msgid "Right Direction key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:350
+msgid "Back key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:353
+msgid "Forward key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:356
+msgid "Stop key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:359
+msgid "Refresh key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:362
+msgid "Volume down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:365
+msgid "Mute volume key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:368
+msgid "Volume up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:371
+msgid "Bass Boost key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:374
+msgid "Bass up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:377
+msgid "Bass down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:380
+msgid "Treble up key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:383
+msgid "Treble down key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:386
+msgid "Media play key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:389
+msgid "Media stop key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:392
+msgid "Previous song key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:395
+msgid "Next song key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:398
+msgid "Media record key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:401
+msgid "Home page key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:404
+msgid "Favorites key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:407
+msgid "Search key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:410
+msgid "Standby key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:413
+msgid "Open URL / Launch Browser key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:416
+msgid "Launch Mail key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:419
+msgid "Launch Media key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:422
+msgid "Launch Shortcut 0 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:425
+msgid "Launch Shortcut 1 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:428
+msgid "Launch Shortcut 2 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:431
+msgid "Launch Shortcut 3 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:434
+msgid "Launch Shortcut 4 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:437
+msgid "Launch Shortcut 5 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:440
+msgid "Launch Shortcut 6 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:443
+msgid "Launch Shortcut 7 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:446
+msgid "Launch Shortcut 8 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:449
+msgid "Launch Shortcut 9 key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:452
+msgid "Launch Shortcut A key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:455
+msgid "Launch Shortcut B key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:458
+msgid "Launch Shortcut C key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:461
+msgid "Launch Shortcut D key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:464
+msgid "Launch Shortcut E key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:467
+msgid "Launch Shortcut F key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:470
+msgid "Unknown key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:473
+msgid "Space key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:476
+msgid "! key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:479
+msgid "\" key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:482
+msgid "# key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:485
+msgid "$ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:488
+msgid "% key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:491
+msgid "& key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:494
+msgid "' key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:497
+msgid "( key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:500
+msgid ") key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:503
+msgid "* key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:506
+msgid "+ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:509
+msgid ", key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:512
+msgid "- key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:515
+msgid ". key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:518
+msgid "/ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:521
+msgid "Number 0."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:524
+msgid "Number 1."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:527
+msgid "Number 2."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:530
+msgid "Number 3."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:533
+msgid "Number 4."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:536
+msgid "Number 5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:539
+msgid "Number 6."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:542
+msgid "Number 7."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:545
+msgid "Number 8."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:548
+msgid "Number 9."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:551
+msgid ": key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:554
+msgid "; key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:557
+msgid "< key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:560
+msgid "= key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:563
+msgid "> key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:566
+msgid "? key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:569
+msgid "@ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:572
+msgid "A key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:575
+msgid "B key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:578
+msgid "C key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:581
+msgid "D key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:584
+msgid "E key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:587
+msgid "F key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:590
+msgid "G key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:593
+msgid "H key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:596
+msgid "I key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:599
+msgid "J key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:602
+msgid "K key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:605
+msgid "L key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:608
+msgid "M key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:611
+msgid "N key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:614
+msgid "O key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:617
+msgid "P key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:620
+msgid "Q key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:623
+msgid "R key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:626
+msgid "S key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:629
+msgid "T key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:632
+msgid "U key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:635
+msgid "V key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:638
+msgid "W key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:641
+msgid "X key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:644
+msgid "Y key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:647
+msgid "Z key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:650
+msgid "[ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:653
+msgid "\\ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:656
+msgid "] key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:659
+msgid "^ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:662
+msgid "_ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:665
+msgid "` key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:668
+msgid "{ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:671
+msgid "| key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:674
+msgid "} key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:677
+msgid "~ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:680
+msgid "Non-breakable space key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:683
+msgid "¡ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:686
+msgid "¢ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:689
+msgid "£ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:692
+msgid "¤ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:695
+msgid "¥ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:698
+msgid "¦ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:701
+msgid "§ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:704
+msgid "¨ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:707
+msgid "© key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:710
+msgid "ª key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:713
+msgid "« key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:716
+msgid "¬ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:719
+msgid "Soft hyphen key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:722
+msgid "® key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:725
+msgid "¯ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:728
+msgid "° key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:731
+msgid "± key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:734
+msgid "² key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:737
+msgid "³ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:740
+msgid "´ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:743
+msgid "µ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:746
+msgid "¶ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:749
+msgid "· key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:752
+msgid "¸ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:755
+msgid "¹ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:758
+msgid "º key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:761
+msgid "» key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:764
+msgid "¼ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:767
+msgid "½ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:770
+msgid "¾ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:773
+msgid "¿ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:776
+msgid "À key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:779
+msgid "Á key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:782
+msgid "Â key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:785
+msgid "Ã key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:788
+msgid "Ä key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:791
+msgid "Å key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:794
+msgid "Æ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:797
+msgid "Ç key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:800
+msgid "È key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:803
+msgid "É key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:806
+msgid "Ê key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:809
+msgid "Ë key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:812
+msgid "Ì key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:815
+msgid "Í key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:818
+msgid "Î key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:821
+msgid "Ï key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:824
+msgid "Ð key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:827
+msgid "Ñ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:830
+msgid "Ò key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:833
+msgid "Ó key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:836
+msgid "Ô key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:839
+msgid "Õ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:842
+msgid "Ö key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:845
+msgid "× key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:848
+msgid "Ø key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:851
+msgid "Ù key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:854
+msgid "Ú key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:857
+msgid "Û key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:860
+msgid "Ü key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:863
+msgid "Ý key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:866
+msgid "Þ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:869
+msgid "ß key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:872
+msgid "÷ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:875
+msgid "ÿ key."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:878
+msgid "Key Code mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:881
+msgid "Modifier key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:884
+msgid "Shift key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:887
+msgid "Alt key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:890
+msgid "Meta key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:893
+msgid "Ctrl key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:896
+msgid ""
+"Command key mask. On macOS, this is equivalent to [constant KEY_MASK_META]. "
+"On other platforms, this is equivalent to [constant KEY_MASK_CTRL]. This "
+"mask should be preferred to [constant KEY_MASK_META] or [constant "
+"KEY_MASK_CTRL] for system shortcuts as it handles all platforms correctly."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:899
+msgid "Keypad key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:902
+msgid "Group Switch key mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:905
+msgid "Left mouse button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:908
+msgid "Right mouse button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:911
+msgid "Middle mouse button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:914
+msgid "Extra mouse button 1 (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:917
+msgid "Extra mouse button 2 (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:920
+msgid "Mouse wheel up."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:923
+msgid "Mouse wheel down."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:926
+msgid "Mouse wheel left button (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:929
+msgid "Mouse wheel right button (only present on some mice)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:932
+msgid "Left mouse button mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:935
+msgid "Right mouse button mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:938
+msgid "Middle mouse button mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:941
+msgid "Extra mouse button 1 mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:944
+msgid "Extra mouse button 2 mask."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:947
+msgid "Gamepad button 0."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:950
+msgid "Gamepad button 1."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:953
+msgid "Gamepad button 2."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:956
+msgid "Gamepad button 3."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:959
+msgid "Gamepad button 4."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:962
+msgid "Gamepad button 5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:965
+msgid "Gamepad button 6."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:968
+msgid "Gamepad button 7."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:971
+msgid "Gamepad button 8."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:974
+msgid "Gamepad button 9."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:977
+msgid "Gamepad button 10."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:980
+msgid "Gamepad button 11."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:983
+msgid "Gamepad button 12."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:986
+msgid "Gamepad button 13."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:989
+msgid "Gamepad button 14."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:992
+msgid "Gamepad button 15."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:995
+msgid "Represents the maximum number of joystick buttons supported."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:998
+msgid "DualShock circle button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1001
+msgid "DualShock X button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1004
+msgid "DualShock square button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1007
+msgid "DualShock triangle button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1010
+msgid "Xbox controller B button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1013
+msgid "Xbox controller A button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1016
+msgid "Xbox controller X button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1019
+msgid "Xbox controller Y button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1022
+msgid "Nintendo controller A button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1025
+msgid "Nintendo controller B button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1028
+msgid "Nintendo controller X button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1031
+msgid "Nintendo controller Y button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1034
+msgid "Grip (side) buttons on a VR controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1037
+msgid "Push down on the touchpad or main joystick on a VR controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1040
+msgid "Trigger on a VR controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1043
+msgid ""
+"A button on the right Oculus Touch controller, X button on the left "
+"controller (also when used in OpenVR)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1046
+msgid ""
+"B button on the right Oculus Touch controller, Y button on the left "
+"controller (also when used in OpenVR)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1049
+msgid "Menu button on either Oculus Touch controller."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1052
+msgid "Menu button in OpenVR (Except when Oculus Touch controllers are used)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1055
+msgid "Gamepad button Select."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1058
+msgid "Gamepad button Start."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1061
+msgid "Gamepad DPad up."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1064
+msgid "Gamepad DPad down."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1067
+msgid "Gamepad DPad left."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1070
+msgid "Gamepad DPad right."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1073
+msgid "Gamepad left Shoulder button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1076
+msgid "Gamepad left trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1079
+msgid "Gamepad left stick click."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1082
+msgid "Gamepad right Shoulder button."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1085
+msgid "Gamepad right trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1088
+msgid "Gamepad right stick click."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1091 doc/classes/@GlobalScope.xml:1124
+msgid "Gamepad left stick horizontal axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1094 doc/classes/@GlobalScope.xml:1127
+msgid "Gamepad left stick vertical axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1097 doc/classes/@GlobalScope.xml:1130
+msgid "Gamepad right stick horizontal axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1100 doc/classes/@GlobalScope.xml:1133
+msgid "Gamepad right stick vertical axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1103
+msgid "Generic gamepad axis 4."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1106
+msgid "Generic gamepad axis 5."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1109
+msgid "Gamepad left trigger analog axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1112
+msgid "Gamepad right trigger analog axis."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1115
+msgid "Generic gamepad axis 8."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1118
+msgid "Generic gamepad axis 9."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1121
+msgid "Represents the maximum number of joystick axes supported."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1136
+msgid "Gamepad left analog trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1139
+msgid "Gamepad right analog trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1142
+msgid "VR Controller analog trigger."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1145
+msgid "VR Controller analog grip (side buttons)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1148
+msgid ""
+"OpenVR touchpad X axis (Joystick axis on Oculus Touch and Windows MR "
+"controllers)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1151
+msgid ""
+"OpenVR touchpad Y axis (Joystick axis on Oculus Touch and Windows MR "
+"controllers)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1154
+msgid "MIDI note OFF message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1157
+msgid "MIDI note ON message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1160
+msgid "MIDI aftertouch message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1163
+msgid "MIDI control change message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1166
+msgid "MIDI program change message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1169
+msgid "MIDI channel pressure message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1172
+msgid "MIDI pitch bend message."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1175
+msgid ""
+"Methods that return [enum Error] return [constant OK] when no error "
+"occurred. Note that many functions don't return an error code but will print "
+"error messages to standard output.\n"
+"Since [constant OK] has value 0, and all other failure codes are positive "
+"integers, it can also be used in boolean checks, e.g.:\n"
+"[codeblock]\n"
+"var err = method_that_returns_error()\n"
+"if err != OK:\n"
+" print(\"Failure!)\n"
+"# Or, equivalent:\n"
+"if err:\n"
+" print(\"Still failing!)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1187
+msgid "Generic error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1190
+msgid "Unavailable error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1193
+msgid "Unconfigured error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1196
+msgid "Unauthorized error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1199
+msgid "Parameter range error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1202
+msgid "Out of memory (OOM) error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1205
+msgid "File: Not found error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1208
+msgid "File: Bad drive error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1211
+msgid "File: Bad path error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1214
+msgid "File: No permission error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1217
+msgid "File: Already in use error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1220
+msgid "File: Can't open error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1223
+msgid "File: Can't write error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1226
+msgid "File: Can't read error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1229
+msgid "File: Unrecognized error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1232
+msgid "File: Corrupt error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1235
+msgid "File: Missing dependencies error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1238
+msgid "File: End of file (EOF) error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1241
+msgid "Can't open error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1244
+msgid "Can't create error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1247
+msgid "Query failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1250
+msgid "Already in use error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1253
+msgid "Locked error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1256
+msgid "Timeout error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1259
+msgid "Can't connect error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1262
+msgid "Can't resolve error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1265
+msgid "Connection error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1268
+msgid "Can't acquire resource error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1271
+msgid "Can't fork process error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1274
+msgid "Invalid data error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1277
+msgid "Invalid parameter error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1280
+msgid "Already exists error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1283
+msgid "Does not exist error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1286
+msgid "Database: Read error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1289
+msgid "Database: Write error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1292
+msgid "Compilation failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1295
+msgid "Method not found error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1298
+msgid "Linking failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1301
+msgid "Script failed error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1304
+msgid "Cycling link (import cycle) error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1307
+msgid "Invalid declaration error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1310
+msgid "Duplicate symbol error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1313
+msgid "Parse error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1316
+msgid "Busy error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1319
+msgid "Skip error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1322
+msgid "Help error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1325
+msgid "Bug error."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1328
+msgid ""
+"Printer on fire error. (This is an easter egg, no engine methods return this "
+"error code.)"
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1331
+msgid "No hint for the edited property."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1334
+msgid ""
+"Hints that an integer or float property should be within a range specified "
+"via the hint string [code]\"min,max\"[/code] or [code]\"min,max,step\"[/"
+"code]. The hint string can optionally include [code]\"or_greater\"[/code] "
+"and/or [code]\"or_lesser\"[/code] to allow manual input going respectively "
+"above the max or below the min values. Example: [code]\"-360,360,1,"
+"or_greater,or_lesser\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1337
+msgid ""
+"Hints that an integer or float property should be within an exponential "
+"range specified via the hint string [code]\"min,max\"[/code] or [code]\"min,"
+"max,step\"[/code]. The hint string can optionally include [code]\"or_greater"
+"\"[/code] and/or [code]\"or_lesser\"[/code] to allow manual input going "
+"respectively above the max or below the min values. Example: "
+"[code]\"0.01,100,0.01,or_greater\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1340
+msgid ""
+"Hints that an integer, float or string property is an enumerated value to "
+"pick in a list specified via a hint string such as [code]\"Hello,Something,"
+"Else\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1343
+msgid ""
+"Hints that a float property should be edited via an exponential easing "
+"function. The hint string can include [code]\"attenuation\"[/code] to flip "
+"the curve horizontally and/or [code]\"inout\"[/code] to also include in/out "
+"easing."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1346 doc/classes/@GlobalScope.xml:1349
+msgid "Deprecated hint, unused."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1352
+msgid ""
+"Hints that an integer property is a bitmask with named bit flags. For "
+"example, to allow toggling bits 0, 1, 2 and 4, the hint could be something "
+"like [code]\"Bit0,Bit1,Bit2,,Bit4\"[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1355
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 2D "
+"render layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1358
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 2D "
+"physics layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1361
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 3D "
+"render layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1364
+msgid ""
+"Hints that an integer property is a bitmask using the optionally named 3D "
+"physics layers."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1367
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1370
+msgid ""
+"Hints that a string property is a path to a directory. Editing it will show "
+"a file dialog for picking the path."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1373
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1376
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1379
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1382
+msgid ""
+"Hints that a string property is text with line breaks. Editing it will show "
+"a text input field where line breaks can be typed."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1385
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1388
+msgid ""
+"Hints that a color property should be edited without changing its alpha "
+"component, i.e. only R, G and B channels are edited."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1391
+msgid "Hints that an image is compressed using lossy compression."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1394
+msgid "Hints that an image is compressed using lossless compression."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1397
+msgid "The property is serialized and saved in the scene file (default)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1400
+msgid "The property is shown in the editor inspector (default)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1403 doc/classes/@GlobalScope.xml:1406
+msgid "Deprecated usage flag, unused."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1409
+msgid "The property can be checked in the editor inspector."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1412
+msgid "The property is checked in the editor inspector."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1415
+msgid "The property is a translatable string."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1418
+msgid "Used to group properties together in the editor."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1421
+msgid "Used to categorize properties together in the editor."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1424
+msgid "The property does not save its state in [PackedScene]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1427
+msgid "Editing the property prompts the user for restarting the editor."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1430
+msgid ""
+"The property is a script variable which should be serialized and saved in "
+"the scene file."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1433
+msgid "Default usage (storage, editor and network)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1436
+msgid ""
+"Default usage for translatable strings (storage, editor, network and "
+"internationalized)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1439
+msgid ""
+"Default usage but without showing the property in the editor (storage, "
+"network)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1442
+msgid "Flag for a normal method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1445
+msgid "Flag for an editor method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1448 doc/classes/@GlobalScope.xml:1454
+#: doc/classes/@GlobalScope.xml:1460
+msgid "Deprecated method flag, unused."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1451
+msgid "Flag for a constant method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1457
+msgid "Flag for a virtual method."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1463
+msgid "Default method flags."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1466
+msgid "Variable is [code]null[/code]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1469
+msgid "Variable is of type [bool]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1472
+msgid "Variable is of type [int]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1475
+msgid "Variable is of type [float] (real)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1478
+msgid "Variable is of type [String]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1481
+msgid "Variable is of type [Vector2]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1484
+msgid "Variable is of type [Vector2i]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1487
+msgid "Variable is of type [Rect2]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1490
+msgid "Variable is of type [Rect2i]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1493
+msgid "Variable is of type [Vector3]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1496
+msgid "Variable is of type [Vector3i]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1499
+msgid "Variable is of type [Transform2D]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1502
+msgid "Variable is of type [Plane]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1505
+msgid "Variable is of type [Quat]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1508
+msgid "Variable is of type [AABB]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1511
+msgid "Variable is of type [Basis]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1514
+msgid "Variable is of type [Transform]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1517
+msgid "Variable is of type [Color]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1520
+msgid "Variable is of type [StringName]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1523
+msgid "Variable is of type [NodePath]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1526
+msgid "Variable is of type [RID]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1529
+msgid "Variable is of type [Object]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1532
+msgid "Variable is of type [Callable]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1535
+msgid "Variable is of type [Signal]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1538
+msgid "Variable is of type [Dictionary]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1541
+msgid "Variable is of type [Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1544
+msgid "Variable is of type [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1547
+msgid "Variable is of type [PackedInt32Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1550
+msgid "Variable is of type [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1553
+msgid "Variable is of type [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1556
+msgid "Variable is of type [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1559
+msgid "Variable is of type [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1562
+msgid "Variable is of type [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1565
+msgid "Variable is of type [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1568
+msgid "Variable is of type [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1571
+msgid "Represents the size of the [enum Variant.Type] enum."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1574
+msgid "Equality operator ([code]==[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1577
+msgid "Inequality operator ([code]!=[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1580
+msgid "Less than operator ([code]<[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1583
+msgid "Less than or equal operator ([code]<=[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1586
+msgid "Greater than operator ([code]>[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1589
+msgid "Greater than or equal operator ([code]>=[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1592
+msgid "Addition operator ([code]+[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1595
+msgid "Subtraction operator ([code]-[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1598
+msgid "Multiplication operator ([code]*[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1601
+msgid "Division operator ([code]/[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1604
+msgid "Unary negation operator ([code]-[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1607
+msgid "Unary plus operator ([code]+[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1610
+msgid "Remainder/modulo operator ([code]%[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1613
+msgid "String concatenation operator ([code]+[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1616
+msgid "Left shift operator ([code]<<[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1619
+msgid "Right shift operator ([code]>>[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1622
+msgid "Bitwise AND operator ([code]&[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1625
+msgid "Bitwise OR operator ([code]|[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1628
+msgid "Bitwise XOR operator ([code]^[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1631
+msgid "Bitwise NOT operator ([code]~[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1634
+msgid "Logical AND operator ([code]and[/code] or [code]&&[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1637
+msgid "Logical OR operator ([code]or[/code] or [code]||[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1640
+msgid "Logical XOR operator (not implemented in GDScript)."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1643
+msgid "Logical NOT operator ([code]not[/code] or [code]![/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1646
+msgid "Logical IN operator ([code]in[/code])."
+msgstr ""
+
+#: doc/classes/@GlobalScope.xml:1649
+msgid "Represents the size of the [enum Variant.Operator] enum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/@VisualScript.xml:4
+msgid "Built-in visual script functions."
+msgstr ""
+
+#: modules/visual_script/doc_classes/@VisualScript.xml:7
+msgid ""
+"A list of built-in visual script functions, see [VisualScriptBuiltinFunc] "
+"and [VisualScript]."
+msgstr ""
+
+#: doc/classes/AABB.xml:4
+msgid "Axis-Aligned Bounding Box."
+msgstr ""
+
+#: doc/classes/AABB.xml:7
+msgid ""
+"AABB consists of a position, a size, and several utility functions. It is "
+"typically used for fast overlap tests."
+msgstr ""
+
+#: doc/classes/AABB.xml:10 doc/classes/Plane.xml:10 doc/classes/Rect2.xml:11
+#: doc/classes/Rect2i.xml:11 doc/classes/Transform.xml:10
+#: doc/classes/Vector2.xml:11 doc/classes/Vector2i.xml:11
+#: doc/classes/Vector3.xml:11 doc/classes/Vector3i.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/math/index.html"
+msgstr ""
+
+#: doc/classes/AABB.xml:21
+msgid "Optional constructor, accepts position and size."
+msgstr ""
+
+#: doc/classes/AABB.xml:30
+msgid ""
+"Returns [code]true[/code] if this [AABB] completely encloses another one."
+msgstr ""
+
+#: doc/classes/AABB.xml:39
+msgid "Returns this [AABB] expanded to include a given point."
+msgstr ""
+
+#: doc/classes/AABB.xml:46
+msgid "Returns the volume of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:55
+msgid "Gets the position of the 8 endpoints of the [AABB] in space."
+msgstr ""
+
+#: doc/classes/AABB.xml:62
+msgid "Returns the normalized longest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:69
+msgid ""
+"Returns the index of the longest axis of the [AABB] (according to "
+"[Vector3]'s [code]AXIS_*[/code] constants)."
+msgstr ""
+
+#: doc/classes/AABB.xml:76
+msgid "Returns the scalar length of the longest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:83
+msgid "Returns the normalized shortest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:90
+msgid ""
+"Returns the index of the shortest axis of the [AABB] (according to "
+"[Vector3]::AXIS* enum)."
+msgstr ""
+
+#: doc/classes/AABB.xml:97
+msgid "Returns the scalar length of the shortest axis of the [AABB]."
+msgstr ""
+
+#: doc/classes/AABB.xml:106
+msgid ""
+"Returns the support point in a given direction. This is useful for collision "
+"detection algorithms."
+msgstr ""
+
+#: doc/classes/AABB.xml:115
+msgid ""
+"Returns a copy of the [AABB] grown a given amount of units towards all the "
+"sides."
+msgstr ""
+
+#: doc/classes/AABB.xml:122
+msgid "Returns [code]true[/code] if the [AABB] is flat or empty."
+msgstr ""
+
+#: doc/classes/AABB.xml:129
+msgid "Returns [code]true[/code] if the [AABB] is empty."
+msgstr ""
+
+#: doc/classes/AABB.xml:138
+msgid "Returns [code]true[/code] if the [AABB] contains a point."
+msgstr ""
+
+#: doc/classes/AABB.xml:147
+msgid ""
+"Returns the intersection between two [AABB]. An empty AABB (size 0,0,0) is "
+"returned on failure."
+msgstr ""
+
+#: doc/classes/AABB.xml:156
+msgid "Returns [code]true[/code] if the [AABB] overlaps with another."
+msgstr ""
+
+#: doc/classes/AABB.xml:165
+msgid "Returns [code]true[/code] if the [AABB] is on both sides of a plane."
+msgstr ""
+
+#: doc/classes/AABB.xml:176
+msgid ""
+"Returns [code]true[/code] if the [AABB] intersects the line segment between "
+"[code]from[/code] and [code]to[/code]."
+msgstr ""
+
+#: doc/classes/AABB.xml:185
+msgid ""
+"Returns [code]true[/code] if this [AABB] and [code]aabb[/code] are "
+"approximately equal, by calling [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/AABB.xml:194
+msgid ""
+"Returns a larger [AABB] that contains both this [AABB] and [code]with[/code]."
+msgstr ""
+
+#: doc/classes/AABB.xml:200
+msgid ""
+"Ending corner. This is calculated as [code]position + size[/code]. Changing "
+"this property changes [member size] accordingly."
+msgstr ""
+
+#: doc/classes/AABB.xml:203
+msgid "Beginning corner."
+msgstr ""
+
+#: doc/classes/AABB.xml:206 doc/classes/Rect2.xml:180
+msgid "Size from position to end."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:4
+msgid "Base dialog for user notification."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:7
+msgid ""
+"This dialog is useful for small notifications to the user about an event. It "
+"can only be accepted or closed, with the same result."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:22
+msgid ""
+"Adds a button with label [code]text[/code] and a custom [code]action[/code] "
+"to the dialog and returns the created button. [code]action[/code] will be "
+"passed to the [signal custom_action] signal when pressed.\n"
+"If [code]true[/code], [code]right[/code] will place the button to the right "
+"of any sibling buttons."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:32
+msgid ""
+"Adds a button with label [code]name[/code] and a cancel action to the dialog "
+"and returns the created button."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:39
+msgid "Returns the label used for built-in text."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:46
+msgid "Returns the OK [Button] instance."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:55
+msgid ""
+"Registers a [LineEdit] in the dialog. When the enter key is pressed, the "
+"dialog will be accepted."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:61
+msgid "Sets autowrapping for the text in the dialog."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:64
+msgid ""
+"If [code]true[/code], the dialog is hidden when the OK button is pressed. "
+"You can set it to [code]false[/code] if you want to do e.g. input validation "
+"when receiving the [signal confirmed] signal, and handle hiding the dialog "
+"in your own logic.\n"
+"[b]Note:[/b] Some nodes derived from this class can have a different default "
+"value, and potentially their own built-in logic overriding this setting. For "
+"example [FileDialog] defaults to [code]false[/code], and has its own input "
+"validation code that is called when you press OK, which eventually hides the "
+"dialog if the input is valid. As such, this property can't be used in "
+"[FileDialog] to disable hiding the dialog when pressing OK."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:68
+msgid "The text displayed by the dialog."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:82
+msgid "Emitted when the dialog is accepted, i.e. the OK button is pressed."
+msgstr ""
+
+#: doc/classes/AcceptDialog.xml:89
+msgid "Emitted when a custom button is pressed. See [method add_button]."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:4
+msgid "Sprite node that can use multiple textures for animation."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:7 doc/classes/AnimatedSprite3D.xml:7
+msgid ""
+"Animations are created using a [SpriteFrames] resource, which can be "
+"configured in the editor via the SpriteFrames panel."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:16 doc/classes/AnimatedSprite3D.xml:16
+msgid "Returns [code]true[/code] if an animation is currently being played."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:27
+msgid ""
+"Plays the animation named [code]anim[/code]. If no [code]anim[/code] is "
+"provided, the current animation is played. If [code]backwards[/code] is "
+"[code]true[/code], the animation will be played in reverse."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:34 doc/classes/AnimatedSprite3D.xml:32
+msgid "Stops the current animation (does not reset the frame counter)."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:40 doc/classes/AnimatedSprite3D.xml:38
+msgid ""
+"The current animation from the [code]frames[/code] resource. If this value "
+"changes, the [code]frame[/code] counter is reset."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:43 doc/classes/SpriteBase3D.xml:55
+msgid "If [code]true[/code], texture will be centered."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:46 doc/classes/Sprite2D.xml:41
+#: doc/classes/SpriteBase3D.xml:61 doc/classes/TextureRect.xml:18
+msgid "If [code]true[/code], texture is flipped horizontally."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:49 doc/classes/Sprite2D.xml:44
+#: doc/classes/SpriteBase3D.xml:64 doc/classes/TextureRect.xml:21
+msgid "If [code]true[/code], texture is flipped vertically."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:52 doc/classes/AnimatedSprite3D.xml:41
+msgid "The displayed animation frame's index."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:55 doc/classes/AnimatedSprite3D.xml:44
+msgid "The [SpriteFrames] resource containing the animation(s)."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:58 doc/classes/Sprite2D.xml:59
+#: doc/classes/SpriteBase3D.xml:70
+msgid "The texture's drawing offset."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:61 doc/classes/AnimatedSprite3D.xml:47
+msgid "If [code]true[/code], the [member animation] is currently playing."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:64
+msgid "Strength of the specular light effect of this [AnimatedSprite2D]."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:67 doc/classes/Sprite2D.xml:74
+msgid "The color of the specular light effect."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:70
+msgid "The animation speed is multiplied by this value."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:76
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AnimatedSprite2D.xml:81 doc/classes/AnimatedSprite3D.xml:53
+msgid "Emitted when [member frame] changed."
+msgstr ""
+
+#: doc/classes/AnimatedSprite3D.xml:4
+msgid ""
+"2D sprite node in 3D world, that can use multiple 2D textures for animation."
+msgstr ""
+
+#: doc/classes/AnimatedSprite3D.xml:25
+msgid ""
+"Plays the animation named [code]anim[/code]. If no [code]anim[/code] is "
+"provided, the current animation is played."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:4
+msgid "Proxy texture for simple frame-based animations."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:7
+msgid ""
+"[AnimatedTexture] is a resource format for frame-based animations, where "
+"multiple textures can be chained automatically with a predefined delay for "
+"each frame. Unlike [AnimationPlayer] or [AnimatedSprite2D], it isn't a "
+"[Node], but has the advantage of being usable anywhere a [Texture2D] "
+"resource can be used, e.g. in a [TileSet].\n"
+"The playback of the animation is controlled by the [member fps] property as "
+"well as each frame's optional delay (see [method set_frame_delay]). The "
+"animation loops, i.e. it will restart at frame 0 automatically after playing "
+"the last frame.\n"
+"[AnimatedTexture] currently requires all frame textures to have the same "
+"size, otherwise the bigger ones will be cropped to match the smallest one. "
+"Also, it doesn't support [AtlasTexture]. Each frame needs to be separate "
+"image."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:20
+msgid "Returns the given frame's delay value."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:29
+msgid "Returns the given frame's [Texture2D]."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:40
+msgid ""
+"Sets an additional delay (in seconds) between this frame and the next one, "
+"that will be added to the time interval defined by [member fps]. By default, "
+"frames have no delay defined. If a delay value is defined, the final time "
+"interval between this frame and the next will be [code]1.0 / fps + delay[/"
+"code].\n"
+"For example, for an animation with 3 frames, 2 FPS and a frame delay on the "
+"second frame of 1.2, the resulting playback will be:\n"
+"[codeblock]\n"
+"Frame 0: 0.5 s (1 / fps)\n"
+"Frame 1: 1.7 s (1 / fps + 1.2)\n"
+"Frame 2: 0.5 s (1 / fps)\n"
+"Total duration: 2.7 s\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:58
+msgid ""
+"Assigns a [Texture2D] to the given frame. Frame IDs start at 0, so the first "
+"frame has ID 0, and the last frame of the animation has ID [member frames] - "
+"1.\n"
+"You can define any number of textures up to [constant MAX_FRAMES], but keep "
+"in mind that only frames from 0 to [member frames] - 1 will be part of the "
+"animation."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:65
+msgid ""
+"Animation speed in frames per second. This value defines the default time "
+"interval between two frames of the animation, and thus the overall duration "
+"of the animation loop based on the [member frames] property. A value of 0 "
+"means no predefined number of frames per second, the animation will play "
+"according to each frame's frame delay (see [method set_frame_delay]).\n"
+"For example, an animation with 8 frames, no frame delay and a [code]fps[/"
+"code] value of 2 will run for 4 seconds, with each frame lasting 0.5 seconds."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:69
+msgid ""
+"Number of frames to use in the animation. While you can create the frames "
+"independently with [method set_frame_texture], you need to set this value "
+"for the animation to take new frames into account. The maximum number of "
+"frames is [constant MAX_FRAMES]."
+msgstr ""
+
+#: doc/classes/AnimatedTexture.xml:74
+msgid ""
+"The maximum number of frames supported by [AnimatedTexture]. If you need "
+"more frames in your animation, use [AnimationPlayer] or [AnimatedSprite2D]."
+msgstr ""
+
+#: doc/classes/Animation.xml:4
+msgid "Contains data used to animate everything in the engine."
+msgstr ""
+
+#: doc/classes/Animation.xml:7
+msgid ""
+"An Animation resource contains data used to animate everything in the "
+"engine. Animations are divided into tracks, and each track must be linked to "
+"a node. The state of that node can be changed through time, by adding timed "
+"keys (events) to the track.\n"
+"[codeblock]\n"
+"# This creates an animation that makes the node \"Enemy\" move to the right "
+"by\n"
+"# 100 pixels in 1 second.\n"
+"var animation = Animation.new()\n"
+"var track_index = animation.add_track(Animation.TYPE_VALUE)\n"
+"animation.track_set_path(track_index, \"Enemy:position.x\")\n"
+"animation.track_insert_key(track_index, 0.0, 0)\n"
+"animation.track_insert_key(track_index, 0.5, 100)\n"
+"[/codeblock]\n"
+"Animations are just data containers, and must be added to nodes such as an "
+"[AnimationPlayer] to be played back. Animation tracks have different types, "
+"each with its own set of dedicated methods. Check [enum TrackType] to see "
+"available types."
+msgstr ""
+
+#: doc/classes/Animation.xml:20 doc/classes/AnimationPlayer.xml:13
+msgid "https://docs.godotengine.org/en/latest/tutorials/animation/index.html"
+msgstr ""
+
+#: doc/classes/Animation.xml:31
+msgid "Adds a track to the Animation."
+msgstr ""
+
+#: doc/classes/Animation.xml:42
+msgid ""
+"Returns the animation name at the key identified by [code]key_idx[/code]. "
+"The [code]track_idx[/code] must be the index of an Animation Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:55
+msgid ""
+"Inserts a key with value [code]animation[/code] at the given [code]time[/"
+"code] (in seconds). The [code]track_idx[/code] must be the index of an "
+"Animation Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:68
+msgid ""
+"Sets the key identified by [code]key_idx[/code] to value [code]animation[/"
+"code]. The [code]track_idx[/code] must be the index of an Animation Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:79
+msgid ""
+"Returns the end offset of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of an Audio Track.\n"
+"End offset is the number of seconds cut off at the ending of the audio "
+"stream."
+msgstr ""
+
+#: doc/classes/Animation.xml:91
+msgid ""
+"Returns the start offset of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of an Audio Track.\n"
+"Start offset is the number of seconds cut off at the beginning of the audio "
+"stream."
+msgstr ""
+
+#: doc/classes/Animation.xml:103
+msgid ""
+"Returns the audio stream of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of an Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:120
+msgid ""
+"Inserts an Audio Track key at the given [code]time[/code] in seconds. The "
+"[code]track_idx[/code] must be the index of an Audio Track.\n"
+"[code]stream[/code] is the [AudioStream] resource to play. "
+"[code]start_offset[/code] is the number of seconds cut off at the beginning "
+"of the audio stream, while [code]end_offset[/code] is at the ending."
+msgstr ""
+
+#: doc/classes/Animation.xml:134
+msgid ""
+"Sets the end offset of the key identified by [code]key_idx[/code] to value "
+"[code]offset[/code]. The [code]track_idx[/code] must be the index of an "
+"Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:147
+msgid ""
+"Sets the start offset of the key identified by [code]key_idx[/code] to value "
+"[code]offset[/code]. The [code]track_idx[/code] must be the index of an "
+"Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:160
+msgid ""
+"Sets the stream of the key identified by [code]key_idx[/code] to value "
+"[code]offset[/code]. The [code]track_idx[/code] must be the index of an "
+"Audio Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:171
+msgid ""
+"Returns the in handle of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:182
+msgid ""
+"Returns the out handle of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:193
+msgid ""
+"Returns the value of the key identified by [code]key_idx[/code]. The "
+"[code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:210
+msgid ""
+"Inserts a Bezier Track key at the given [code]time[/code] in seconds. The "
+"[code]track_idx[/code] must be the index of a Bezier Track.\n"
+"[code]in_handle[/code] is the left-side weight of the added Bezier curve "
+"point, [code]out_handle[/code] is the right-side one, while [code]value[/"
+"code] is the actual value at this point."
+msgstr ""
+
+#: doc/classes/Animation.xml:222
+msgid ""
+"Returns the interpolated value at the given [code]time[/code] (in seconds). "
+"The [code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:235
+msgid ""
+"Sets the in handle of the key identified by [code]key_idx[/code] to value "
+"[code]in_handle[/code]. The [code]track_idx[/code] must be the index of a "
+"Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:248
+msgid ""
+"Sets the out handle of the key identified by [code]key_idx[/code] to value "
+"[code]out_handle[/code]. The [code]track_idx[/code] must be the index of a "
+"Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:261
+msgid ""
+"Sets the value of the key identified by [code]key_idx[/code] to the given "
+"value. The [code]track_idx[/code] must be the index of a Bezier Track."
+msgstr ""
+
+#: doc/classes/Animation.xml:268
+msgid "Clear the animation (clear all tracks and reset all)."
+msgstr ""
+
+#: doc/classes/Animation.xml:279
+msgid ""
+"Adds a new track that is a copy of the given track from [code]to_animation[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:288
+msgid ""
+"Returns the index of the specified track. If the track is not found, return "
+"-1."
+msgstr ""
+
+#: doc/classes/Animation.xml:295
+msgid "Returns the amount of tracks in the animation."
+msgstr ""
+
+#: doc/classes/Animation.xml:308
+msgid ""
+"Returns all the key indices of a method track, given a position and delta "
+"time."
+msgstr ""
+
+#: doc/classes/Animation.xml:319
+msgid "Returns the method name of a method track."
+msgstr ""
+
+#: doc/classes/Animation.xml:330
+msgid ""
+"Returns the arguments values to be called on a method track for a given key "
+"in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:339
+msgid "Removes a track by specifying the track index."
+msgstr ""
+
+#: doc/classes/Animation.xml:352
+msgid ""
+"Finds the key index by time in a given track. Optionally, only find it if "
+"the exact time is given."
+msgstr ""
+
+#: doc/classes/Animation.xml:361
+msgid ""
+"Returns [code]true[/code] if the track at [code]idx[/code] wraps the "
+"interpolation loop. New tracks wrap the interpolation loop by default."
+msgstr ""
+
+#: doc/classes/Animation.xml:370
+msgid "Returns the interpolation type of a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:379
+msgid "Returns the amount of keys in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:390
+msgid "Returns the time at which the key is located."
+msgstr ""
+
+#: doc/classes/Animation.xml:401
+msgid ""
+"Returns the transition curve (easing) for a specific key (see the built-in "
+"math function [method @GDScript.ease])."
+msgstr ""
+
+#: doc/classes/Animation.xml:412
+msgid "Returns the value of a given key in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:421
+msgid ""
+"Gets the path of a track. For more information on the path format, see "
+"[method track_set_path]."
+msgstr ""
+
+#: doc/classes/Animation.xml:430
+msgid "Gets the type of a track."
+msgstr ""
+
+#: doc/classes/Animation.xml:445
+msgid "Insert a generic key in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:454
+msgid ""
+"Returns [code]true[/code] if the track at index [code]idx[/code] is enabled."
+msgstr ""
+
+#: doc/classes/Animation.xml:463
+msgid ""
+"Returns [code]true[/code] if the given track is imported. Else, return "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:472
+msgid "Moves a track down."
+msgstr ""
+
+#: doc/classes/Animation.xml:483
+msgid ""
+"Changes the index position of track [code]idx[/code] to the one defined in "
+"[code]to_idx[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:492
+msgid "Moves a track up."
+msgstr ""
+
+#: doc/classes/Animation.xml:503
+msgid "Removes a key by index in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:514
+msgid "Removes a key by position (seconds) in a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:525
+msgid "Enables/disables the given track. Tracks are enabled by default."
+msgstr ""
+
+#: doc/classes/Animation.xml:536
+msgid "Sets the given track as imported or not."
+msgstr ""
+
+#: doc/classes/Animation.xml:547
+msgid ""
+"If [code]true[/code], the track at [code]idx[/code] wraps the interpolation "
+"loop."
+msgstr ""
+
+#: doc/classes/Animation.xml:558
+msgid "Sets the interpolation type of a given track."
+msgstr ""
+
+#: doc/classes/Animation.xml:571
+msgid "Sets the time of an existing key."
+msgstr ""
+
+#: doc/classes/Animation.xml:584
+msgid ""
+"Sets the transition curve (easing) for a specific key (see the built-in math "
+"function [method @GDScript.ease])."
+msgstr ""
+
+#: doc/classes/Animation.xml:597
+msgid "Sets the value of an existing key."
+msgstr ""
+
+#: doc/classes/Animation.xml:608
+msgid ""
+"Sets the path of a track. 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. Tracks that control properties or bones must append "
+"their name after the path, separated by [code]\":\"[/code].\n"
+"For example, [code]\"character/skeleton:ankle\"[/code] or [code]\"character/"
+"mesh:transform/local\"[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:620
+msgid ""
+"Swaps the track [code]idx[/code]'s index position with the track "
+"[code]with_idx[/code]."
+msgstr ""
+
+#: doc/classes/Animation.xml:637
+msgid "Insert a transform key for a transform track."
+msgstr ""
+
+#: doc/classes/Animation.xml:648
+msgid ""
+"Returns the interpolated value of a transform track at a given time (in "
+"seconds). An array consisting of 3 elements: position ([Vector3]), rotation "
+"([Quat]) and scale ([Vector3])."
+msgstr ""
+
+#: doc/classes/Animation.xml:661
+msgid ""
+"Returns all the key indices of a value track, given a position and delta "
+"time."
+msgstr ""
+
+#: doc/classes/Animation.xml:670
+msgid "Returns the update mode of a value track."
+msgstr ""
+
+#: doc/classes/Animation.xml:681
+msgid "Sets the update mode (see [enum UpdateMode]) of a value track."
+msgstr ""
+
+#: doc/classes/Animation.xml:687
+msgid ""
+"The total length of the animation (in seconds).\n"
+"[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."
+msgstr ""
+
+#: doc/classes/Animation.xml:691
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Animation.xml:694
+msgid "The animation step value."
+msgstr ""
+
+#: doc/classes/Animation.xml:700
+msgid ""
+"Emitted when there's a change in the list of tracks, e.g. tracks are added, "
+"moved or have changed paths."
+msgstr ""
+
+#: doc/classes/Animation.xml:706
+msgid ""
+"Value tracks set values in node properties, but only those which can be "
+"Interpolated."
+msgstr ""
+
+#: doc/classes/Animation.xml:709
+msgid ""
+"Transform tracks are used to change node local transforms or skeleton pose "
+"bones. Transitions are interpolated."
+msgstr ""
+
+#: doc/classes/Animation.xml:712
+msgid "Method tracks call functions with given arguments per key."
+msgstr ""
+
+#: doc/classes/Animation.xml:715
+msgid ""
+"Bezier tracks are used to interpolate a value using custom curves. They can "
+"also be used to animate sub-properties of vectors and colors (e.g. alpha "
+"value of a [Color])."
+msgstr ""
+
+#: doc/classes/Animation.xml:718
+msgid ""
+"Audio tracks are used to play an audio stream with either type of "
+"[AudioStreamPlayer]. The stream can be trimmed and previewed in the "
+"animation."
+msgstr ""
+
+#: doc/classes/Animation.xml:721
+msgid "Animation tracks play animations in other [AnimationPlayer] nodes."
+msgstr ""
+
+#: doc/classes/Animation.xml:724
+msgid "No interpolation (nearest value)."
+msgstr ""
+
+#: doc/classes/Animation.xml:727
+msgid "Linear interpolation."
+msgstr ""
+
+#: doc/classes/Animation.xml:730
+msgid "Cubic interpolation."
+msgstr ""
+
+#: doc/classes/Animation.xml:733
+msgid "Update between keyframes."
+msgstr ""
+
+#: doc/classes/Animation.xml:736
+msgid "Update at the keyframes and hold the value."
+msgstr ""
+
+#: doc/classes/Animation.xml:739
+msgid "Update at the keyframes."
+msgstr ""
+
+#: doc/classes/Animation.xml:742
+msgid ""
+"Same as linear interpolation, but also interpolates from the current value "
+"(i.e. dynamically at runtime) if the first key isn't at 0 seconds."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:4
+msgid "Base resource for [AnimationTree] nodes."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:7
+msgid ""
+"Base resource for [AnimationTree] nodes. In general, it's not used directly, "
+"but you can create custom ones with custom blending formulas.\n"
+"Inherit this when creating nodes mainly for use in [AnimationNodeBlendTree], "
+"otherwise [AnimationRootNode] should be used instead."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:11 doc/classes/AnimationNodeAdd2.xml:10
+#: doc/classes/AnimationNodeAdd3.xml:14
+#: doc/classes/AnimationNodeAnimation.xml:10
+#: doc/classes/AnimationNodeBlend2.xml:10
+#: doc/classes/AnimationNodeBlend3.xml:14
+#: doc/classes/AnimationNodeBlendSpace1D.xml:13
+#: doc/classes/AnimationNodeBlendSpace2D.xml:12
+#: doc/classes/AnimationNodeBlendTree.xml:10
+#: doc/classes/AnimationNodeOneShot.xml:10
+#: doc/classes/AnimationNodeOutput.xml:9
+#: doc/classes/AnimationNodeStateMachine.xml:15
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:15
+#: doc/classes/AnimationNodeStateMachineTransition.xml:8
+#: doc/classes/AnimationNodeTimeScale.xml:10
+#: doc/classes/AnimationNodeTimeSeek.xml:10
+#: doc/classes/AnimationNodeTransition.xml:10 doc/classes/AnimationTree.xml:9
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree."
+"html"
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:20
+msgid ""
+"Adds an input to the node. This is only useful for nodes created for use in "
+"an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:37
+msgid ""
+"Blend an animation by [code]blend[/code] amount (name must be valid in the "
+"linked [AnimationPlayer]). A [code]time[/code] and [code]delta[/code] may be "
+"passed, as well as whether [code]seek[/code] happened."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:56
+msgid ""
+"Blend an input. This is only useful for nodes created for an "
+"[AnimationNodeBlendTree]. The [code]time[/code] parameter is a relative "
+"delta, unless [code]seek[/code] is [code]true[/code], in which case it is "
+"absolute. A filter mode may be optionally passed (see [enum FilterAction] "
+"for options)."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:77
+msgid ""
+"Blend another animation node (in case this node contains children animation "
+"nodes). This function is only useful if you inherit from [AnimationRootNode] "
+"instead, else editors will not display your node for addition."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:84
+msgid "Gets the text caption for this node (used by some editors)."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:93
+msgid ""
+"Gets a child node by index (used by editors inheriting from "
+"[AnimationRootNode])."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:100
+msgid ""
+"Gets all children nodes in order as a [code]name: node[/code] dictionary. "
+"Only useful when inheriting [AnimationRootNode]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:107
+msgid ""
+"Amount of inputs in this node, only useful for nodes that go into "
+"[AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:116
+msgid "Gets the name of an input by index."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:125
+msgid ""
+"Gets the value of a parameter. Parameters are custom local memory used for "
+"your nodes, given a resource can be reused in multiple trees."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:134
+msgid ""
+"Gets the default value of a parameter. Parameters are custom local memory "
+"used for your nodes, given a resource can be reused in multiple trees."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:141
+msgid ""
+"Gets the property information for parameter. Parameters are custom local "
+"memory used for your nodes, given a resource can be reused in multiple "
+"trees. Format is similar to [method Object.get_property_list]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:148
+msgid ""
+"Returns [code]true[/code] whether you want the blend tree editor to display "
+"filter editing on this node."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:157
+msgid "Returns [code]true[/code] whether a given path is filtered."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:168
+msgid ""
+"User-defined callback called when a custom node is processed. The "
+"[code]time[/code] parameter is a relative delta, unless [code]seek[/code] is "
+"[code]true[/code], in which case it is absolute.\n"
+"Here, call the [method blend_input], [method blend_node] or [method "
+"blend_animation] functions. You can also use [method get_parameter] and "
+"[method set_parameter] to modify local memory.\n"
+"This function should return the time left for the current animation to "
+"finish (if unsure, pass the value from the main blend being called)."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:179
+msgid "Removes an input, call this only when inactive."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:190
+msgid "Adds or removes a path for the filter."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:201
+msgid ""
+"Sets a custom parameter. These are used as local storage, because resources "
+"can be reused across the tree or scenes."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:207
+msgid "If [code]true[/code], filtering is enabled."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:213
+msgid "Called when the node was removed from the graph."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:218
+msgid ""
+"Emitted by nodes that inherit from this class and that have an internal tree "
+"when one of their nodes changes. The nodes that emit this signal are "
+"[AnimationNodeBlendSpace1D], [AnimationNodeBlendSpace2D], "
+"[AnimationNodeStateMachine], and [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:224
+msgid "Do not use filtering."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:227
+msgid "Paths matching the filter will be allowed to pass."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:230
+msgid "Paths matching the filter will be discarded."
+msgstr ""
+
+#: doc/classes/AnimationNode.xml:233
+msgid "Paths matching the filter will be blended (by the blend value)."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd2.xml:4
+msgid "Blends two animations additively inside of an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd2.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"additively based on an amount value in the [code][0.0, 1.0][/code] range."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd2.xml:16 doc/classes/AnimationNodeAdd3.xml:20
+#: doc/classes/AnimationNodeBlend2.xml:16
+#: doc/classes/AnimationNodeBlend3.xml:20
+msgid ""
+"If [code]true[/code], sets the [code]optimization[/code] to [code]false[/"
+"code] when calling [method AnimationNode.blend_input], forcing the blended "
+"animations to update every frame."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd3.xml:4
+msgid ""
+"Blends two of three animations additively inside of an "
+"[AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeAdd3.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"together additively out of three based on a value in the [code][-1.0, 1.0][/"
+"code] range.\n"
+"This node has three inputs:\n"
+"- The base animation to add to\n"
+"- A -add animation to blend with when the blend amount is in the [code]"
+"[-1.0, 0.0][/code] range.\n"
+"- A +add animation to blend with when the blend amount is in the [code][0.0, "
+"1.0][/code] range"
+msgstr ""
+
+#: doc/classes/AnimationNodeAnimation.xml:4
+msgid "Input animation to use in an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeAnimation.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Only features one output "
+"set using the [member animation] property. Use it as an input for "
+"[AnimationNode] that blend animations together."
+msgstr ""
+
+#: doc/classes/AnimationNodeAnimation.xml:16
+msgid ""
+"Animation to use as an output. It is one of the animations provided by "
+"[member AnimationTree.anim_player]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend2.xml:4
+msgid "Blends two animations linearly inside of an [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend2.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"linearly based on an amount value in the [code][0.0, 1.0][/code] range."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend3.xml:4
+msgid ""
+"Blends two of three animations linearly inside of an "
+"[AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlend3.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. Blends two animations "
+"together linearly out of three based on a value in the [code][-1.0, 1.0][/"
+"code] range.\n"
+"This node has three inputs:\n"
+"- The base animation\n"
+"- A -blend animation to blend with when the blend amount is in the [code]"
+"[-1.0, 0.0][/code] range.\n"
+"- A +blend animation to blend with when the blend amount is in the [code]"
+"[0.0, 1.0][/code] range"
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:4
+msgid ""
+"Blends linearly between two of any number of [AnimationNode] of any type "
+"placed on a virtual axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree].\n"
+"This is a virtual axis on which you can add any type of [AnimationNode] "
+"using [method add_blend_point].\n"
+"Outputs the linear blend of the two [AnimationNode]s closest to the node's "
+"current value.\n"
+"You can set the extents of the axis using the [member min_space] and [member "
+"max_space]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:26
+msgid ""
+"Adds a new point that represents a [code]node[/code] on the virtual axis at "
+"a given position set by [code]pos[/code]. You can insert it at a specific "
+"index using the [code]at_index[/code] argument. If you use the default value "
+"for [code]at_index[/code], the point is inserted at the end of the blend "
+"points array."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:33
+msgid "Returns the number of points on the blend axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:42
+msgid ""
+"Returns the [AnimationNode] referenced by the point at index [code]point[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:51
+#: doc/classes/AnimationNodeBlendSpace2D.xml:65
+msgid "Returns the position of the point at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:60
+msgid "Removes the point at index [code]point[/code] from the blend axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:71
+#: doc/classes/AnimationNodeBlendSpace2D.xml:112
+msgid ""
+"Changes the [AnimationNode] referenced by the point at index [code]point[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:82
+#: doc/classes/AnimationNodeBlendSpace2D.xml:123
+msgid ""
+"Updates the position of the point at index [code]point[/code] on the blend "
+"axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:88
+msgid ""
+"The blend space's axis's upper limit for the points' position. See [method "
+"add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:91
+msgid ""
+"The blend space's axis's lower limit for the points' position. See [method "
+"add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:94
+msgid "Position increment to snap to when moving a point on the axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace1D.xml:97
+msgid "Label of the virtual axis of the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:4
+msgid ""
+"Blends linearly between three [AnimationNode] of any type placed in a 2D "
+"space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree].\n"
+"This node allows you to blend linearly between three animations using a "
+"[Vector2] weight.\n"
+"You can add vertices to the blend space with [method add_blend_point] and "
+"automatically triangulate it by setting [member auto_triangles] to "
+"[code]true[/code]. Otherwise, use [method add_triangle] and [method "
+"remove_triangle] to create up the blend space by hand."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:25
+msgid ""
+"Adds a new point that represents a [code]node[/code] at the position set by "
+"[code]pos[/code]. You can insert it at a specific index using the "
+"[code]at_index[/code] argument. If you use the default value for "
+"[code]at_index[/code], the point is inserted at the end of the blend points "
+"array."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:40
+msgid ""
+"Creates a new triangle using three points [code]x[/code], [code]y[/code], "
+"and [code]z[/code]. Triangles can overlap. You can insert the triangle at a "
+"specific index using the [code]at_index[/code] argument. If you use the "
+"default value for [code]at_index[/code], the point is inserted at the end of "
+"the blend points array."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:47
+msgid "Returns the number of points in the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:56
+msgid ""
+"Returns the [AnimationRootNode] referenced by the point at index "
+"[code]point[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:72
+msgid "Returns the number of triangles in the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:83
+msgid ""
+"Returns the position of the point at index [code]point[/code] in the "
+"triangle of index [code]triangle[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:92
+msgid "Removes the point at index [code]point[/code] from the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:101
+msgid ""
+"Removes the triangle at index [code]triangle[/code] from the blend space."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:129
+msgid ""
+"If [code]true[/code], the blend space is triangulated automatically. The "
+"mesh updates every time you add or remove points with [method "
+"add_blend_point] and [method remove_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:132
+msgid ""
+"Controls the interpolation between animations. See [enum BlendMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:135
+msgid ""
+"The blend space's X and Y axes' upper limit for the points' position. See "
+"[method add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:138
+msgid ""
+"The blend space's X and Y axes' lower limit for the points' position. See "
+"[method add_blend_point]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:141
+msgid "Position increment to snap to when moving a point."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:144
+msgid "Name of the blend space's X axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:147
+msgid "Name of the blend space's Y axis."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:153
+msgid ""
+"Emitted every time the blend space's triangles are created, removed, or when "
+"one of their vertices changes position."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:159
+msgid "The interpolation between animations is linear."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:162
+msgid ""
+"The blend space plays the animation of the node the blending position is "
+"closest to. Useful for frame-by-frame 2D animations."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendSpace2D.xml:165
+msgid ""
+"Similar to [constant BLEND_MODE_DISCRETE], but starts the new animation at "
+"the last animation's playback position."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:4
+msgid "[AnimationTree] node resource that contains many blend type nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:7
+msgid ""
+"This node may contain a sub-tree of any other blend type nodes, such as mix, "
+"blend2, blend3, one shot, etc. This is one of the most commonly used roots."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:23
+msgid ""
+"Adds an [AnimationNode] at the given [code]position[/code]. The [code]name[/"
+"code] is used to identify the created sub-node later."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:36
+msgid ""
+"Connects the output of an [AnimationNode] as input for another "
+"[AnimationNode], at the input port specified by [code]input_index[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:47
+msgid "Disconnects the node connected to the specified input."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:56
+msgid "Returns the sub-node with the specified [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:65
+msgid ""
+"Returns the position of the sub-node with the specified [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:74
+msgid ""
+"Returns [code]true[/code] if a sub-node with specified [code]name[/code] "
+"exists."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:83
+msgid "Removes a sub-node."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:94
+msgid "Changes the name of a sub-node."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:105
+msgid "Modifies the position of a sub-node."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:111
+msgid "The global offset of all sub-nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:116
+msgid "The connection was successful."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:119
+msgid "The input node is [code]null[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:122
+msgid "The specified input port is out of range."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:125
+msgid "The output node is [code]null[/code]."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:128
+msgid "Input and output nodes are the same."
+msgstr ""
+
+#: doc/classes/AnimationNodeBlendTree.xml:131
+msgid "The specified connection already exists."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:4
+msgid "Plays an animation once in [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:7
+msgid ""
+"A resource to add to an [AnimationNodeBlendTree]. This node will execute a "
+"sub-animation and return once it finishes. Blend times for fading in and out "
+"can be customized, as well as filters."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:30
+msgid ""
+"If [code]true[/code], the sub-animation will restart automatically after "
+"finishing."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:33
+msgid "The delay after which the automatic restart is triggered, in seconds."
+msgstr ""
+
+#: doc/classes/AnimationNodeOneShot.xml:36
+msgid ""
+"If [member autorestart] is [code]true[/code], a random additional delay (in "
+"seconds) between 0 and this value will be added to [member "
+"autorestart_delay]."
+msgstr ""
+
+#: doc/classes/AnimationNodeOutput.xml:4
+msgid "Generic output node to be added to [AnimationNodeBlendTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:4
+msgid "State machine for control of animations."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:7
+msgid ""
+"Contains multiple nodes representing animation states, connected in a graph. "
+"Node transitions can be configured to happen automatically or via code, "
+"using a shortest-path algorithm. Retrieve the "
+"[AnimationNodeStateMachinePlayback] object from the [AnimationTree] node to "
+"control it programmatically.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var state_machine = $AnimationTree.get(\"parameters/playback\")\n"
+"state_machine.travel(\"some_state\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:28
+msgid ""
+"Adds a new node to the graph. The [code]position[/code] is used for display "
+"in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:41
+msgid "Adds a transition between the given nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:48
+#: doc/classes/AnimationNodeStateMachine.xml:89
+msgid "Returns the graph's end node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:55
+msgid "Returns the draw offset of the graph. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:64
+msgid "Returns the animation node with the given name."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:73
+msgid "Returns the given animation node's name."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:82
+msgid "Returns the given node's coordinates. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:98
+msgid "Returns the given transition."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:105
+msgid "Returns the number of connections in the graph."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:114
+msgid "Returns the given transition's start node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:123
+msgid "Returns the given transition's end node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:132
+msgid "Returns [code]true[/code] if the graph contains the given node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:143
+msgid ""
+"Returns [code]true[/code] if there is a transition between the given nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:152
+msgid "Deletes the given node from the graph."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:163
+msgid "Deletes the transition between the two specified nodes."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:172
+msgid "Deletes the given transition by index."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:183
+msgid "Renames the given node."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:202
+msgid "Sets the given node as the graph end point."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:211
+msgid "Sets the draw offset of the graph. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:222
+msgid "Sets the node's coordinates. Used for display in the editor."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachine.xml:231
+msgid "Sets the given node as the graph start point."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:4
+msgid "Playback control for [AnimationNodeStateMachine]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:7
+msgid ""
+"Allows control of [AnimationTree] state machines created with "
+"[AnimationNodeStateMachine]. Retrieve with [code]$AnimationTree."
+"get(\"parameters/playback\")[/code].\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var state_machine = $AnimationTree.get(\"parameters/playback\")\n"
+"state_machine.travel(\"some_state\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:22
+msgid "Returns the currently playing animation state."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:29
+msgid ""
+"Returns the current travel path as computed internally by the A* algorithm."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:36
+msgid "Returns [code]true[/code] if an animation is playing."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:45
+msgid "Starts playing the given animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:52
+msgid "Stops the currently playing animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachinePlayback.xml:61
+msgid ""
+"Transitions from the current state to another one, following the shortest "
+"path."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:14
+msgid ""
+"Turn on auto advance when this condition is set. The provided name will "
+"become a boolean parameter on the [AnimationTree] that can be controlled "
+"from code (see [url=https://docs.godotengine.org/en/latest/tutorials/"
+"animation/animation_tree.html#controlling-from-code][/url]). For example, if "
+"[member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and "
+"[member advance_condition] is set to [code]\"idle\"[/code]:\n"
+"[codeblock]\n"
+"$animation_tree[\"parameters/conditions/idle\"] = is_on_floor and "
+"(linear_velocity.x == 0)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:20
+msgid ""
+"Turn on the transition automatically when this state is reached. This works "
+"best with [constant SWITCH_MODE_AT_END]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:23
+msgid ""
+"Don't use this transition during [method AnimationNodeStateMachinePlayback."
+"travel] or [member auto_advance]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:26
+msgid ""
+"Lower priority transitions are preferred when travelling through the tree "
+"via [method AnimationNodeStateMachinePlayback.travel] or [member "
+"auto_advance]."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:29
+msgid "The transition type."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:32
+msgid "The time to cross-fade between this state and the next."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:38
+msgid "Emitted when [member advance_condition] is changed."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:44
+msgid ""
+"Switch to the next state immediately. The current state will end and blend "
+"into the beginning of the new one."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:47
+msgid ""
+"Switch to the next state immediately, but will seek the new state to the "
+"playback position of the old state."
+msgstr ""
+
+#: doc/classes/AnimationNodeStateMachineTransition.xml:50
+msgid ""
+"Wait for the current state playback to end, then switch to the beginning of "
+"the next state animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeScale.xml:4
+msgid "A time-scaling animation node to be used with [AnimationTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeScale.xml:7
+msgid ""
+"Allows scaling the speed of the animation (or reversing it) in any children "
+"nodes. Setting it to 0 will pause the animation."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeSeek.xml:4
+msgid "A time-seeking animation node to be used with [AnimationTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeTimeSeek.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:4
+msgid "A generic animation transition node for [AnimationTree]."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:7
+msgid ""
+"Simple state machine for cases which don't require a more advanced "
+"[AnimationNodeStateMachine]. Animations can be connected to the inputs and "
+"transition times can be specified."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:52
+msgid "The number of available input ports for this node."
+msgstr ""
+
+#: doc/classes/AnimationNodeTransition.xml:55
+msgid ""
+"Cross-fading time (in seconds) between each animation connected to the "
+"inputs."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:4
+msgid "Container and player of [Animation] resources."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:7
+msgid ""
+"An animation player is used for general-purpose playback of [Animation] "
+"resources. It contains a dictionary of animations (referenced by name) and "
+"custom blend times between their transitions. Additionally, animations can "
+"be played and blended in different channels.\n"
+"[AnimationPlayer] is more suited than [Tween] for animations where you know "
+"the final values in advance. For example, fading a screen in and out is more "
+"easily done with an [AnimationPlayer] node thanks to the animation tools "
+"provided by the editor. That particular example can also be implemented with "
+"a [Tween] node, but it requires doing everything by code.\n"
+"Updating the target properties of animations occurs at process time."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"animations.html"
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:24
+msgid ""
+"Adds [code]animation[/code] to the player accessible with the key "
+"[code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:33
+msgid ""
+"Shifts position in the animation timeline and immediately updates the "
+"animation. [code]delta[/code] is the time in seconds to shift. Events "
+"between the current frame and [code]delta[/code] are handled."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:42
+msgid "Returns the name of the next animation in the queue."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:53
+msgid ""
+"Triggers the [code]anim_to[/code] animation when the [code]anim_from[/code] "
+"animation completes."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:60
+msgid ""
+"[AnimationPlayer] caches animated nodes. It may not notice if a node "
+"disappears; [method clear_caches] forces it to update the cache again."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:67
+msgid "Clears all queued, unplayed animations."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:76
+msgid ""
+"Returns the name of [code]animation[/code] or an empty string if not found."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:85
+msgid ""
+"Returns the [Animation] with key [code]name[/code] or [code]null[/code] if "
+"not found."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:92
+msgid "Returns the list of stored animation names."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:103
+msgid ""
+"Gets the blend time (in seconds) between two animations, referenced by their "
+"names."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:110
+msgid ""
+"Gets the actual playing speed of current animation or 0 if not playing. This "
+"speed is the [member playback_speed] property multiplied by "
+"[code]custom_speed[/code] argument specified when calling the [method play] "
+"method."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:117
+msgid ""
+"Returns a list of the animation names that are currently queued to play."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:126
+msgid ""
+"Returns [code]true[/code] if the [AnimationPlayer] stores an [Animation] "
+"with key [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:133
+msgid "Returns [code]true[/code] if playing an animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:148
+msgid ""
+"Plays the animation with key [code]name[/code]. Custom blend times and speed "
+"can be set. If [code]custom_speed[/code] is negative and [code]from_end[/"
+"code] is [code]true[/code], the animation will play backwards (which is "
+"equivalent to calling [method play_backwards]).\n"
+"The [AnimationPlayer] keeps track of its current or last played animation "
+"with [member assigned_animation]. If this method is called with that same "
+"animation [code]name[/code], or with no [code]name[/code] parameter, the "
+"assigned animation will resume playing if it was paused, or restart if it "
+"was stopped (see [method stop] for both pause and stop). If the animation "
+"was already playing, it will keep playing.\n"
+"[b]Note:[/b] The animation will be updated the next time the "
+"[AnimationPlayer] is processed. If other variables are updated at the same "
+"time this is called, they may be updated too early. To perform the update "
+"immediately, call [code]advance(0)[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:161
+msgid ""
+"Plays the animation with key [code]name[/code] in reverse.\n"
+"This method is a shorthand for [method play] with [code]custom_speed = -1.0[/"
+"code] and [code]from_end = true[/code], so see its description for more "
+"information."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:171
+msgid ""
+"Queues an animation for playback once the current one is done.\n"
+"[b]Note:[/b] If a looped animation is currently playing, the queued "
+"animation will never play unless the looped animation is stopped somehow."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:181
+msgid "Removes the animation with key [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:192
+msgid ""
+"Renames an existing animation with key [code]name[/code] to [code]newname[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:203
+msgid ""
+"Seeks the animation to the [code]seconds[/code] point in time (in seconds). "
+"If [code]update[/code] is [code]true[/code], the animation updates too, "
+"otherwise it updates at process time. Events between the current frame and "
+"[code]seconds[/code] are skipped."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:216
+msgid ""
+"Specifies a blend time (in seconds) between two animations, referenced by "
+"their names."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:225
+msgid ""
+"Stops or pauses the currently playing animation. If [code]reset[/code] is "
+"[code]true[/code], the animation position is reset to [code]0[/code] and the "
+"playback speed is reset to [code]1.0[/code].\n"
+"If [code]reset[/code] is [code]false[/code], the [member "
+"current_animation_position] will be kept and calling [method play] or "
+"[method play_backwards] without arguments or with the same animation name as "
+"[member assigned_animation] will resume the animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:232
+msgid ""
+"If playing, the current animation; otherwise, the animation last played. "
+"When set, would change the animation, but would not play it unless currently "
+"playing. See also [member current_animation]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:235
+msgid "The name of the animation to play when the scene loads."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:238
+msgid ""
+"The name of the current animation, \"\" if not playing anything. When being "
+"set, does not restart the animation. See also [method play]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:241
+msgid "The length (in seconds) of the currently being played animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:244
+msgid "The position (in seconds) of the currently playing animation."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:247
+msgid "The call mode to use for Call Method tracks."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:250
+msgid ""
+"If [code]true[/code], updates animations in response to process-related "
+"notifications."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:253
+msgid ""
+"The default time in which to blend animations. Ranges from 0 to 4096 with "
+"0.01 precision."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:256
+msgid "The process notification in which to update animations."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:259
+msgid ""
+"The speed scaling ratio. For instance, if this value is 1, then the "
+"animation plays at normal speed. If it's 0.5, then it plays at half speed. "
+"If it's 2, then it plays at double speed."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:262
+msgid "The node from which node path references will travel."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:272
+msgid ""
+"If the currently being played animation changes, this signal will notify of "
+"such change."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:279
+msgid "Notifies when an animation finished playing."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:286
+msgid "Notifies when an animation starts playing."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:291
+msgid ""
+"Notifies when the caches have been cleared, either automatically, or "
+"manually via [method clear_caches]."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:297
+msgid ""
+"Process animation during the physics process. This is especially useful when "
+"animating physics bodies."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:300
+msgid "Process animation during the idle process."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:303
+msgid ""
+"Do not process animation. Use [method advance] to process the animation "
+"manually."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:306
+msgid ""
+"Batch method calls during the animation process, then do the calls after "
+"events are processed. This avoids bugs involving deleting nodes or modifying "
+"the AnimationPlayer while playing."
+msgstr ""
+
+#: doc/classes/AnimationPlayer.xml:309
+msgid "Make method calls immediately when reached in the animation."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:4
+msgid ""
+"A node to be used for advanced animation transitions in an [AnimationPlayer]."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:10
+msgid "https://github.com/godotengine/tps-demo"
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:19
+msgid "Manually advance the animations by the specified time (in seconds)."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:41
+msgid "If [code]true[/code], the [AnimationTree] will be processing."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:44
+msgid "The path to the [AnimationPlayer] used for animating."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:47
+msgid ""
+"The process mode of this [AnimationTree]. See [enum AnimationProcessMode] "
+"for available modes."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:52
+msgid "The root animation node of this [AnimationTree]. See [AnimationNode]."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:57
+msgid ""
+"The animations will progress during the physics frame (i.e. [method Node."
+"_physics_process])."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:60
+msgid ""
+"The animations will progress during the idle frame (i.e. [method Node."
+"_process])."
+msgstr ""
+
+#: doc/classes/AnimationTree.xml:63
+msgid "The animations will only progress manually (see [method advance])."
+msgstr ""
+
+#: doc/classes/Area2D.xml:4
+msgid "2D area for detection and 2D physics influence."
+msgstr ""
+
+#: doc/classes/Area2D.xml:7
+msgid ""
+"2D area that detects [CollisionObject2D] nodes overlapping, entering, or "
+"exiting. Can also alter or override local physics parameters (gravity, "
+"damping)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/using_area_2d.html"
+msgstr ""
+
+#: doc/classes/Area2D.xml:19
+msgid ""
+"Returns an individual bit on the layer mask. Describes whether other areas "
+"will collide with this one on the given layer."
+msgstr ""
+
+#: doc/classes/Area2D.xml:28
+msgid ""
+"Returns an individual bit on the collision mask. Describes whether this area "
+"will collide with others on the given layer."
+msgstr ""
+
+#: doc/classes/Area2D.xml:35
+msgid ""
+"Returns a list of intersecting [Area2D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area2D.xml:42
+msgid ""
+"Returns a list of intersecting [PhysicsBody2D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area2D.xml:51
+msgid ""
+"If [code]true[/code], the given area overlaps the Area2D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/Area2D.xml:61
+msgid ""
+"If [code]true[/code], the given physics body overlaps the Area2D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:74
+msgid ""
+"Set/clear individual bits on the layer mask. This makes getting an area in/"
+"out of only one layer easier."
+msgstr ""
+
+#: doc/classes/Area2D.xml:85
+msgid ""
+"Set/clear individual bits on the collision mask. This makes selecting the "
+"areas scanned easier."
+msgstr ""
+
+#: doc/classes/Area2D.xml:91 doc/classes/Area3D.xml:90
+msgid ""
+"The rate at which objects stop spinning in this area. Represents the angular "
+"velocity lost per second. Values range from [code]0[/code] (no damping) to "
+"[code]1[/code] (full damping)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:94 doc/classes/Area3D.xml:93
+msgid "The name of the area's audio bus."
+msgstr ""
+
+#: doc/classes/Area2D.xml:97 doc/classes/Area3D.xml:96
+msgid ""
+"If [code]true[/code], the area's audio bus overrides the default audio bus."
+msgstr ""
+
+#: doc/classes/Area2D.xml:100 doc/classes/Area3D.xml:99
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/Area2D.xml:103 doc/classes/Area3D.xml:102
+msgid "The physics layers this area scans to determine collision detection."
+msgstr ""
+
+#: doc/classes/Area2D.xml:106 doc/classes/Area3D.xml:105
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Area2D.xml:109 doc/classes/Area3D.xml:108
+msgid ""
+"The falloff factor for point gravity. The greater the value, the faster "
+"gravity decreases with distance."
+msgstr ""
+
+#: doc/classes/Area2D.xml:112 doc/classes/Area3D.xml:111
+msgid ""
+"If [code]true[/code], gravity is calculated from a point (set via [member "
+"gravity_vec]). See also [member space_override]."
+msgstr ""
+
+#: doc/classes/Area2D.xml:115 doc/classes/Area3D.xml:114
+msgid ""
+"The area's gravity vector (not normalized). If gravity is a point (see "
+"[member gravity_point]), this will be the point of attraction."
+msgstr ""
+
+#: doc/classes/Area2D.xml:118 doc/classes/Area3D.xml:117
+msgid ""
+"The rate at which objects stop moving in this area. Represents the linear "
+"velocity lost per second. Values range from [code]0[/code] (no damping) to "
+"[code]1[/code] (full damping)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:121 doc/classes/Area3D.xml:120
+msgid "If [code]true[/code], other monitoring areas can detect this area."
+msgstr ""
+
+#: doc/classes/Area2D.xml:124 doc/classes/Area3D.xml:123
+msgid ""
+"If [code]true[/code], the area detects bodies or areas entering and exiting "
+"it."
+msgstr ""
+
+#: doc/classes/Area2D.xml:127 doc/classes/Area3D.xml:126
+msgid "The area's priority. Higher priority areas are processed first."
+msgstr ""
+
+#: doc/classes/Area2D.xml:130 doc/classes/Area3D.xml:141
+msgid ""
+"Override mode for gravity and damping calculations within this area. See "
+"[enum SpaceOverride] for possible values."
+msgstr ""
+
+#: doc/classes/Area2D.xml:138 doc/classes/Area3D.xml:149
+msgid "Emitted when another area enters."
+msgstr ""
+
+#: doc/classes/Area2D.xml:145 doc/classes/Area3D.xml:156
+msgid "Emitted when another area exits."
+msgstr ""
+
+#: doc/classes/Area2D.xml:158
+msgid ""
+"Emitted when another area enters, reporting which shapes overlapped. "
+"[code]shape_owner_get_owner(shape_find_owner(shape))[/code] returns the "
+"parent object of the owner of the [code]shape[/code]."
+msgstr ""
+
+#: doc/classes/Area2D.xml:171
+msgid ""
+"Emitted when another area exits, reporting which shapes were overlapping."
+msgstr ""
+
+#: doc/classes/Area2D.xml:178
+msgid ""
+"Emitted when a physics body enters.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:186
+msgid ""
+"Emitted when a physics body exits.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:200
+msgid ""
+"Emitted when a physics body enters, reporting which shapes overlapped.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:214
+msgid ""
+"Emitted when a physics body exits, reporting which shapes were overlapping.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:221 doc/classes/Area3D.xml:232
+msgid "This area does not affect gravity/damping."
+msgstr ""
+
+#: doc/classes/Area2D.xml:224 doc/classes/Area3D.xml:235
+msgid ""
+"This area adds its gravity/damping values to whatever has been calculated so "
+"far (in [member priority] order)."
+msgstr ""
+
+#: doc/classes/Area2D.xml:227 doc/classes/Area3D.xml:238
+msgid ""
+"This area adds its gravity/damping values to whatever has been calculated so "
+"far (in [member priority] order), ignoring any lower priority areas."
+msgstr ""
+
+#: doc/classes/Area2D.xml:230 doc/classes/Area3D.xml:241
+msgid ""
+"This area replaces any gravity/damping, even the defaults, ignoring any "
+"lower priority areas."
+msgstr ""
+
+#: doc/classes/Area2D.xml:233 doc/classes/Area3D.xml:244
+msgid ""
+"This area replaces any gravity/damping calculated so far (in [member "
+"priority] order), but keeps calculating the rest of the areas."
+msgstr ""
+
+#: doc/classes/Area3D.xml:4
+msgid "General-purpose area node for detection and 3D physics influence."
+msgstr ""
+
+#: doc/classes/Area3D.xml:7
+msgid ""
+"3D area that detects [CollisionObject3D] nodes overlapping, entering, or "
+"exiting. Can also alter or override local physics parameters (gravity, "
+"damping)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:18
+msgid "Returns an individual bit on the layer mask."
+msgstr ""
+
+#: doc/classes/Area3D.xml:27 modules/csg/doc_classes/CSGShape3D.xml:18
+#: modules/csg/doc_classes/CSGShape3D.xml:27 doc/classes/RayCast2D.xml:70
+#: doc/classes/SoftBody3D.xml:35 doc/classes/SoftBody3D.xml:44
+msgid "Returns an individual bit on the collision mask."
+msgstr ""
+
+#: doc/classes/Area3D.xml:34
+msgid ""
+"Returns a list of intersecting [Area3D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area3D.xml:41
+msgid ""
+"Returns a list of intersecting [PhysicsBody3D]s. For performance reasons "
+"(collisions are all processed at the same time) this list is modified once "
+"during the physics step, not immediately after objects are moved. Consider "
+"using signals instead."
+msgstr ""
+
+#: doc/classes/Area3D.xml:50
+msgid ""
+"If [code]true[/code], the given area overlaps the Area3D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/Area3D.xml:60
+msgid ""
+"If [code]true[/code], the given physics body overlaps the Area3D.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of overlaps is updated once per frame and before the "
+"physics step. Consider using signals instead.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:73
+msgid ""
+"Set/clear individual bits on the layer mask. This simplifies editing this "
+"[Area3D]'s layers."
+msgstr ""
+
+#: doc/classes/Area3D.xml:84
+msgid ""
+"Set/clear individual bits on the collision mask. This simplifies editing "
+"which [Area3D] layers this [Area3D] scans."
+msgstr ""
+
+#: doc/classes/Area3D.xml:129
+msgid ""
+"The degree to which this area applies reverb to its associated audio. Ranges "
+"from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision."
+msgstr ""
+
+#: doc/classes/Area3D.xml:132
+msgid "If [code]true[/code], the area applies reverb to its associated audio."
+msgstr ""
+
+#: doc/classes/Area3D.xml:135
+msgid "The reverb bus name to use for this area's associated audio."
+msgstr ""
+
+#: doc/classes/Area3D.xml:138
+msgid ""
+"The degree to which this area's reverb is a uniform effect. Ranges from "
+"[code]0[/code] to [code]1[/code] with [code]0.1[/code] precision."
+msgstr ""
+
+#: doc/classes/Area3D.xml:169
+msgid ""
+"Emitted when another area enters, reporting which areas overlapped. "
+"[code]shape_owner_get_owner(shape_find_owner(shape))[/code] returns the "
+"parent object of the owner of the [code]shape[/code]."
+msgstr ""
+
+#: doc/classes/Area3D.xml:182
+msgid ""
+"Emitted when another area exits, reporting which areas were overlapping."
+msgstr ""
+
+#: doc/classes/Area3D.xml:189
+msgid ""
+"Emitted when a physics body enters.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:197
+msgid ""
+"Emitted when a physics body exits.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:211
+msgid ""
+"Emitted when a physics body enters, reporting which shapes overlapped.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Area3D.xml:225
+msgid ""
+"Emitted when a physics body exits, reporting which shapes were overlapping.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/Array.xml:4
+msgid "Generic array datatype."
+msgstr ""
+
+#: doc/classes/Array.xml:7
+msgid ""
+"Generic array which can contain several elements of any type, accessible by "
+"a numerical index starting at 0. Negative indices can be used to count from "
+"the back, like in Python (-1 is the last element, -2 the second to last, "
+"etc.).\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var array = [\"One\", 2, 3, \"Four\"]\n"
+"print(array[0]) # One.\n"
+"print(array[2]) # 3.\n"
+"print(array[-1]) # Four.\n"
+"array[2] = \"Three\"\n"
+"print(array[-2]) # Three.\n"
+"[/codeblock]\n"
+"Arrays can be concatenated using the [code]+[/code] operator:\n"
+"[codeblock]\n"
+"var array1 = [\"One\", 2]\n"
+"var array2 = [3, \"Four\"]\n"
+"print(array1 + array2) # [\"One\", 2, 3, \"Four\"]\n"
+"[/codeblock]\n"
+"Arrays are always passed by reference."
+msgstr ""
+
+#: doc/classes/Array.xml:34
+msgid "Constructs an array from a [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/Array.xml:43
+msgid "Constructs an array from a [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:52
+msgid "Constructs an array from a [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:61
+msgid "Constructs an array from a [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/Array.xml:70
+msgid "Constructs an array from a [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:79
+msgid "Constructs an array from a [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:88
+msgid "Constructs an array from a [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:97
+msgid "Constructs an array from a [PackedInt32Array]."
+msgstr ""
+
+#: doc/classes/Array.xml:106
+msgid "Constructs an array from a [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/Array.xml:115 doc/classes/PackedByteArray.xml:28
+#: doc/classes/PackedColorArray.xml:28 doc/classes/PackedFloat32Array.xml:29
+#: doc/classes/PackedFloat64Array.xml:29 doc/classes/PackedInt32Array.xml:29
+#: doc/classes/PackedInt64Array.xml:29 doc/classes/PackedStringArray.xml:28
+#: doc/classes/PackedVector2Array.xml:28 doc/classes/PackedVector3Array.xml:28
+msgid ""
+"Appends an element at the end of the array (alias of [method push_back])."
+msgstr ""
+
+#: doc/classes/Array.xml:122
+msgid ""
+"Returns the last element of the array, or [code]null[/code] if the array is "
+"empty."
+msgstr ""
+
+#: doc/classes/Array.xml:133
+msgid ""
+"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. 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.\n"
+"[b]Note:[/b] Calling [method bsearch] on an unsorted array results in "
+"unexpected behavior."
+msgstr ""
+
+#: doc/classes/Array.xml:149
+msgid ""
+"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.\n"
+"[b]Note:[/b] Calling [method bsearch] on an unsorted array results in "
+"unexpected behavior."
+msgstr ""
+
+#: doc/classes/Array.xml:157
+msgid ""
+"Clears the array. This is equivalent to using [method resize] with a size of "
+"[code]0[/code]."
+msgstr ""
+
+#: doc/classes/Array.xml:166
+msgid "Returns the number of times an element is in the array."
+msgstr ""
+
+#: doc/classes/Array.xml:175
+msgid ""
+"Returns a copy of the array.\n"
+"If [code]deep[/code] is [code]true[/code], a deep copy is performed: all "
+"nested arrays and dictionaries are duplicated and will not be shared with "
+"the original array. If [code]false[/code], a shallow copy is made and "
+"references to the original nested arrays and dictionaries are kept, so that "
+"modifying a sub-array or dictionary in the copy will also impact those "
+"referenced in the source array."
+msgstr ""
+
+#: doc/classes/Array.xml:183 doc/classes/PackedByteArray.xml:64
+#: doc/classes/PackedColorArray.xml:44 doc/classes/PackedFloat32Array.xml:45
+#: doc/classes/PackedFloat64Array.xml:45 doc/classes/PackedInt32Array.xml:45
+#: doc/classes/PackedInt64Array.xml:45 doc/classes/PackedStringArray.xml:44
+#: doc/classes/PackedVector2Array.xml:44 doc/classes/PackedVector3Array.xml:44
+msgid "Returns [code]true[/code] if the array is empty."
+msgstr ""
+
+#: doc/classes/Array.xml:192
+msgid "Removes the first occurrence of a value from the array."
+msgstr ""
+
+#: doc/classes/Array.xml:203
+msgid ""
+"Searches the array for a value and returns its index or -1 if not found. "
+"Optionally, the initial search index can be passed."
+msgstr ""
+
+#: doc/classes/Array.xml:212
+msgid ""
+"Searches the array in reverse order for a value and returns its index or -1 "
+"if not found."
+msgstr ""
+
+#: doc/classes/Array.xml:219
+msgid ""
+"Returns the first element of the array, or [code]null[/code] if the array is "
+"empty."
+msgstr ""
+
+#: doc/classes/Array.xml:228
+msgid ""
+"Returns [code]true[/code] if the array contains the given value.\n"
+"[codeblock]\n"
+"[\"inside\", 7].has(\"inside\") == true\n"
+"[\"inside\", 7].has(\"outside\") == false\n"
+"[\"inside\", 7].has(7) == true\n"
+"[\"inside\", 7].has(\"7\") == false\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Array.xml:241
+msgid "Returns a hashed integer value representing the array contents."
+msgstr ""
+
+#: doc/classes/Array.xml:252
+msgid ""
+"Inserts a new element at a given position in the array. The position must be "
+"valid, or at the end of the array ([code]pos == size()[/code])."
+msgstr ""
+
+#: doc/classes/Array.xml:259 doc/classes/PackedByteArray.xml:107
+#: doc/classes/PackedColorArray.xml:62 doc/classes/PackedFloat32Array.xml:63
+#: doc/classes/PackedFloat64Array.xml:63 doc/classes/PackedInt32Array.xml:63
+#: doc/classes/PackedInt64Array.xml:63 doc/classes/PackedStringArray.xml:62
+#: doc/classes/PackedVector2Array.xml:62 doc/classes/PackedVector3Array.xml:62
+msgid "Reverses the order of the elements in the array."
+msgstr ""
+
+#: doc/classes/Array.xml:266
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Array.xml:273
+msgid ""
+"Returns the minimum value contained in the array if all elements are of "
+"comparable types. If the elements can't be compared, [code]null[/code] is "
+"returned."
+msgstr ""
+
+#: doc/classes/Array.xml:280
+msgid ""
+"Removes and returns the last element of the array. Returns [code]null[/code] "
+"if the array is empty."
+msgstr ""
+
+#: doc/classes/Array.xml:287
+msgid ""
+"Removes and returns the first element of the array. Returns [code]null[/"
+"code] if the array is empty."
+msgstr ""
+
+#: doc/classes/Array.xml:296 doc/classes/PackedByteArray.xml:116
+#: doc/classes/PackedFloat32Array.xml:72 doc/classes/PackedFloat64Array.xml:72
+msgid "Appends an element at the end of the array."
+msgstr ""
+
+#: doc/classes/Array.xml:305
+msgid "Adds an element at the beginning of the array."
+msgstr ""
+
+#: doc/classes/Array.xml:314 doc/classes/PackedByteArray.xml:125
+#: doc/classes/PackedColorArray.xml:80 doc/classes/PackedFloat32Array.xml:81
+#: doc/classes/PackedFloat64Array.xml:81 doc/classes/PackedInt32Array.xml:81
+#: doc/classes/PackedInt64Array.xml:81 doc/classes/PackedStringArray.xml:80
+#: doc/classes/PackedVector2Array.xml:80 doc/classes/PackedVector3Array.xml:80
+msgid "Removes an element from the array by index."
+msgstr ""
+
+#: doc/classes/Array.xml:323
+msgid ""
+"Resizes the array to contain a different number of elements. If the array "
+"size is smaller, elements are cleared, if bigger, new elements are "
+"[code]null[/code]."
+msgstr ""
+
+#: doc/classes/Array.xml:334
+msgid ""
+"Searches the array in reverse order. Optionally, a start search index can be "
+"passed. If negative, the start index is considered relative to the end of "
+"the array."
+msgstr ""
+
+#: doc/classes/Array.xml:341
+msgid ""
+"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 "
+"@GDScript.randi]. Call [method @GDScript.randomize] to ensure that a new "
+"seed will be used each time if you want non-reproducible shuffling."
+msgstr ""
+
+#: doc/classes/Array.xml:348
+msgid "Returns the number of elements in the array."
+msgstr ""
+
+#: doc/classes/Array.xml:363
+msgid ""
+"Duplicates the subset described in the function and returns it in an array, "
+"deeply copying the array if [code]deep[/code] is [code]true[/code]. Lower "
+"and upper index are inclusive, with the [code]step[/code] describing the "
+"change between indices while slicing."
+msgstr ""
+
+#: doc/classes/Array.xml:370
+msgid ""
+"Sorts the array.\n"
+"[b]Note:[/b] Strings are sorted in alphabetical order (as opposed to natural "
+"order). This may lead to unexpected behavior when sorting an array of "
+"strings ending with a sequence of numbers. Consider the following example:\n"
+"[codeblock]\n"
+"var strings = [\"string1\", \"string2\", \"string10\", \"string11\"]\n"
+"strings.sort()\n"
+"print(strings) # Prints [string1, string10, string11, string2]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Array.xml:387
+msgid ""
+"Sorts the array using a custom method. The arguments are an object that "
+"holds the method and the name of such method. The custom method receives two "
+"arguments (a pair of elements from the array) and must return either "
+"[code]true[/code] or [code]false[/code].\n"
+"[b]Note:[/b] you cannot randomize the return value as the heapsort algorithm "
+"expects a deterministic result. Doing so will result in unexpected "
+"behavior.\n"
+"[codeblock]\n"
+"class MyCustomSorter:\n"
+" static func sort_ascending(a, b):\n"
+" if a[0] < b[0]:\n"
+" return true\n"
+" return false\n"
+"\n"
+"var my_items = [[5, \"Potato\"], [9, \"Rice\"], [4, \"Tomato\"]]\n"
+"my_items.sort_custom(MyCustomSorter, \"sort_ascending\")\n"
+"print(my_items) # Prints [[4, Tomato], [5, Potato], [9, Rice]].\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:4
+msgid ""
+"[Mesh] type that provides utility for constructing a surface from arrays."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:7
+msgid ""
+"The [ArrayMesh] is used to construct a [Mesh] by specifying the attributes "
+"as arrays.\n"
+"The most basic example is the creation of a single triangle:\n"
+"[codeblock]\n"
+"var vertices = PackedVector3Array()\n"
+"vertices.push_back(Vector3(0, 1, 0))\n"
+"vertices.push_back(Vector3(1, 0, 0))\n"
+"vertices.push_back(Vector3(0, 0, 1))\n"
+"# Initialize the ArrayMesh.\n"
+"var arr_mesh = ArrayMesh.new()\n"
+"var arrays = []\n"
+"arrays.resize(ArrayMesh.ARRAY_MAX)\n"
+"arrays[ArrayMesh.ARRAY_VERTEX] = vertices\n"
+"# Create the Mesh.\n"
+"arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)\n"
+"var m = MeshInstance3D.new()\n"
+"m.mesh = arr_mesh\n"
+"[/codeblock]\n"
+"The [MeshInstance3D] is ready to be added to the [SceneTree] to be shown."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:27
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/content/procedural_geometry/"
+"arraymesh.html"
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:36
+msgid ""
+"Adds name for a blend shape that will be added with [method "
+"add_surface_from_arrays]. Must be called before surface is added."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:55
+msgid ""
+"Creates a new surface.\n"
+"Surfaces are created to be rendered using a [code]primitive[/code], which "
+"may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, "
+"when using indices, it is recommended to only use points, lines or "
+"triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/"
+"code] for this new surface.\n"
+"The [code]arrays[/code] argument is an array of arrays. See [enum ArrayType] "
+"for the values used in this array. For example, [code]arrays[0][/code] is "
+"the array of vertices. That first vertex sub-array is always required; the "
+"others are optional. Adding an index array puts this function into \"index "
+"mode\" where the vertex and other arrays become the sources of data and the "
+"index array defines the vertex order. All sub-arrays must have the same "
+"length as the vertex array or be empty, except for [constant ARRAY_INDEX] if "
+"it is used.\n"
+"Adding an index array puts this function into \"index mode\" where the "
+"vertex and other arrays become the sources of data, and the index array "
+"defines the order of the vertices.\n"
+"Godot uses clockwise winding order for front faces of triangle primitive "
+"modes."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:66
+msgid "Removes all blend shapes from this [ArrayMesh]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:73
+msgid "Removes all surfaces from this [ArrayMesh]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:80
+msgid "Returns the number of blend shapes that the [ArrayMesh] holds."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:89
+msgid "Returns the name of the blend shape at this index."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:100
+msgid ""
+"Will perform a UV unwrap on the [ArrayMesh] to prepare the mesh for "
+"lightmapping."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:107
+msgid "Will regenerate normal maps for the [ArrayMesh]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:116
+msgid ""
+"Returns the index of the first surface with this name held within this "
+"[ArrayMesh]. If none are found, -1 is returned."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:125
+msgid ""
+"Returns the length in indices of the index array in the requested surface "
+"(see [method add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:134
+msgid ""
+"Returns the length in vertices of the vertex array in the requested surface "
+"(see [method add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:143
+msgid ""
+"Returns the format mask of the requested surface (see [method "
+"add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:152
+msgid "Gets the name assigned to this surface."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:161
+msgid ""
+"Returns the primitive type of the requested surface (see [method "
+"add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:172
+msgid "Sets a name for a given surface."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:185
+msgid ""
+"Updates a specified region of mesh arrays on the GPU.\n"
+"[b]Warning:[/b] Only use if you know what you are doing. You can easily "
+"cause crashes by calling this function with improper arguments."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:192
+msgid "Sets the blend shape mode to one of [enum Mesh.BlendShapeMode]."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:195
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:200
+msgid "Default value used for index_array_len when no indices are present."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:203
+msgid "Amount of weights/bone indices per vertex (always 4)."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:206
+msgid ""
+"[PackedVector3Array], [PackedVector2Array], or [Array] of vertex positions."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:209
+msgid "[PackedVector3Array] of vertex normals."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:212
+msgid ""
+"[PackedFloat32Array] of vertex tangents. Each element in groups of 4 floats, "
+"first 3 floats determine the tangent, and the last the binormal direction as "
+"-1 or 1."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:215
+msgid "[PackedColorArray] of vertex colors."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:218
+msgid "[PackedVector2Array] for UV coordinates."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:221
+msgid "[PackedVector2Array] for second UV coordinates."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:224
+msgid ""
+"[PackedFloat32Array] or [PackedInt32Array] of bone indices. Each element in "
+"groups of 4 floats."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:227
+msgid ""
+"[PackedFloat32Array] of bone weights. Each element in groups of 4 floats."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:230
+msgid ""
+"[PackedInt32Array] of integers used as indices referencing vertices, colors, "
+"normals, tangents, and textures. All of those arrays must have the same "
+"number of elements as the vertex array. No index can be beyond the vertex "
+"array size. When this index array is present, it puts the function into "
+"\"index mode,\" where the index selects the *i*'th vertex, normal, tangent, "
+"color, UV, etc. This means if you want to have different normals or colors "
+"along an edge, you have to duplicate the vertices.\n"
+"For triangles, the index array is interpreted as triples, referring to the "
+"vertices of each triangle. For lines, the index array is in pairs indicating "
+"the start and end of each line."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:234 doc/classes/Mesh.xml:210
+#: doc/classes/RenderingServer.xml:3180
+msgid "Represents the size of the [enum ArrayType] enum."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:237
+msgid "Array format will include vertices (mandatory)."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:240
+msgid "Array format will include normals."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:243
+msgid "Array format will include tangents."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:246
+msgid "Array format will include a color array."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:249
+msgid "Array format will include UVs."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:252
+msgid "Array format will include another set of UVs."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:255
+msgid "Array format will include bone indices."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:258
+msgid "Array format will include bone weights."
+msgstr ""
+
+#: doc/classes/ArrayMesh.xml:261
+msgid "Index array will be used."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:4
+msgid "An anchor point in AR space."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:7
+msgid ""
+"The [ARVRAnchor] point is a spatial node that maps a real world location "
+"identified by the AR platform to a position within the game world. For "
+"example, as long as plane detection in ARKit is on, ARKit will identify and "
+"update the position of planes (tables, floors, etc) and create anchors for "
+"them.\n"
+"This node is mapped to one of the anchors through its unique ID. When you "
+"receive a signal that a new anchor is available, you should add this node to "
+"your scene for that anchor. You can predefine nodes and set the ID; the "
+"nodes will simply remain on 0,0,0 until a plane is recognized.\n"
+"Keep in mind that, as long as plane detection is enabled, the size, placing "
+"and orientation of an anchor will be updated as the detection logic learns "
+"more about the real world out there especially if only part of the surface "
+"is in view."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:18
+msgid "Returns the name given to this anchor."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:25
+msgid ""
+"Returns [code]true[/code] if the anchor is being tracked and [code]false[/"
+"code] if no anchor with this ID is currently known."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:32
+msgid ""
+"If provided by the [ARVRInterface], this returns a mesh object for the "
+"anchor. For an anchor, this can be a shape related to the object being "
+"tracked or it can be a mesh that provides topology related to the anchor and "
+"can be used to create shadows/reflections on surfaces or for generating "
+"collision shapes."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:39
+msgid ""
+"Returns a plane aligned with our anchor; handy for intersection testing."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:46
+msgid ""
+"Returns the estimated size of the plane that was detected. Say when the "
+"anchor relates to a table in the real world, this is the estimated size of "
+"the surface of that table."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:52
+msgid ""
+"The anchor's ID. You can set this before the anchor itself exists. The first "
+"anchor gets an ID of [code]1[/code], the second an ID of [code]2[/code], "
+"etc. When anchors get removed, the engine can then assign the corresponding "
+"ID to new anchors. The most common situation where anchors \"disappear\" is "
+"when the AR server identifies that two anchors represent different parts of "
+"the same plane and merges them."
+msgstr ""
+
+#: doc/classes/ARVRAnchor.xml:60
+msgid ""
+"Emitted when the mesh associated with the anchor changes or when one becomes "
+"available. This is especially important for topology that is constantly "
+"being [code]mesh_updated[/code]."
+msgstr ""
+
+#: doc/classes/ARVRCamera.xml:4
+msgid ""
+"A camera node with a few overrules for AR/VR applied, such as location "
+"tracking."
+msgstr ""
+
+#: doc/classes/ARVRCamera.xml:7
+msgid ""
+"This is a helper spatial node for our camera; note that, if stereoscopic "
+"rendering is applicable (VR-HMD), most of the camera properties are ignored, "
+"as the HMD information overrides them. The only properties that can be "
+"trusted are the near and far planes.\n"
+"The position and orientation of this node is automatically updated by the "
+"ARVR Server to represent the location of the HMD if such tracking is "
+"available and can thus be used by game logic. Note that, in contrast to the "
+"ARVR Controller, the render thread has access to the most up-to-date "
+"tracking data of the HMD and the location of the ARVRCamera can lag a few "
+"milliseconds behind what is used for rendering as a result."
+msgstr ""
+
+#: doc/classes/ARVRCamera.xml:11 doc/classes/ARVRController.xml:12
+#: doc/classes/ARVRInterface.xml:11 doc/classes/ARVROrigin.xml:13
+#: doc/classes/ARVRPositionalTracker.xml:12 doc/classes/ARVRServer.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/vr/index.html"
+msgstr ""
+
+#: doc/classes/ARVRController.xml:4
+msgid "A spatial node representing a spatially-tracked controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:7
+msgid ""
+"This is a helper spatial node that is linked to the tracking of controllers. "
+"It also offers several handy passthroughs to the state of buttons and such "
+"on the controllers.\n"
+"Controllers are linked by their ID. You can create controller nodes before "
+"the controllers are available. If your game always uses two controllers (one "
+"for each hand), you can predefine the controllers with ID 1 and 2; they will "
+"become active as soon as the controllers are identified. If you expect "
+"additional controllers to be used, you should react to the signals and add "
+"ARVRController nodes to your scene.\n"
+"The position of the controller node is automatically updated by the "
+"[ARVRServer]. This makes this node ideal to add child nodes to visualize the "
+"controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:19
+msgid ""
+"If active, returns the name of the associated controller if provided by the "
+"AR/VR SDK used."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:26
+msgid ""
+"Returns the hand holding this controller, if known. See [enum "
+"ARVRPositionalTracker.TrackerHand]."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:33
+msgid ""
+"Returns [code]true[/code] if the bound controller is active. ARVR systems "
+"attempt to track active controllers."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:42
+msgid ""
+"Returns the value of the given axis for things like triggers, touchpads, "
+"etc. that are embedded into the controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:49
+msgid ""
+"Returns the ID of the joystick object bound to this. Every controller "
+"tracked by the [ARVRServer] that has buttons and axis will also be "
+"registered as a joystick within Godot. This means that all the normal "
+"joystick tracking and input mapping will work for buttons and axis found on "
+"the AR/VR controllers. This ID is purely offered as information so you can "
+"link up the controller with its joystick entry."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:56
+msgid ""
+"If provided by the [ARVRInterface], this returns a mesh associated with the "
+"controller. This can be used to visualize the controller."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:65
+msgid ""
+"Returns [code]true[/code] if the button at index [code]button[/code] is "
+"pressed. See [enum JoystickList], in particular the [code]JOY_VR_*[/code] "
+"constants."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:71
+msgid ""
+"The controller's ID.\n"
+"A controller ID of 0 is unbound and will always result in an inactive node. "
+"Controller ID 1 is reserved for the first controller that identifies itself "
+"as the left-hand controller and ID 2 is reserved for the first controller "
+"that identifies itself as the right-hand controller.\n"
+"For any other controller that the [ARVRServer] detects, we continue with "
+"controller ID 3.\n"
+"When a controller is turned off, its slot is freed. This ensures controllers "
+"will keep the same ID even when controllers with lower IDs are turned off."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:77
+msgid ""
+"The degree to which the controller vibrates. Ranges from [code]0.0[/code] to "
+"[code]1.0[/code] with precision [code].01[/code]. If changed, updates "
+"[member ARVRPositionalTracker.rumble] accordingly.\n"
+"This is a useful property to animate if you want the controller to vibrate "
+"for a limited duration."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:86
+msgid "Emitted when a button on this controller is pressed."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:93
+msgid "Emitted when a button on this controller is released."
+msgstr ""
+
+#: doc/classes/ARVRController.xml:100
+msgid ""
+"Emitted when the mesh associated with the controller changes or when one "
+"becomes available. Generally speaking this will be a static mesh after "
+"becoming available."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:4
+msgid "Base class for an AR/VR interface implementation."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:7
+msgid ""
+"This class needs to be implemented to make an AR or VR platform available to "
+"Godot and these should be implemented as C++ modules or GDNative modules "
+"(note that for GDNative the subclass ARVRScriptInterface should be used). "
+"Part of the interface is exposed to GDScript so you can detect, enable and "
+"configure an AR or VR platform.\n"
+"Interfaces should be written in such a way that simply enabling them will "
+"give us a working setup. You can query the available interfaces through "
+"[ARVRServer]."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:18
+msgid ""
+"If this is an AR interface that requires displaying a camera feed as the "
+"background, this method returns the feed ID in the [CameraServer] for this "
+"interface."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:25
+msgid ""
+"Returns a combination of [enum Capabilities] flags providing information "
+"about the capabilities of this interface."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:32
+msgid "Returns the name of this interface (OpenVR, OpenHMD, ARKit, etc)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:39
+msgid ""
+"Returns the resolution at which we should render our intermediate results "
+"before things like lens distortion are applied by the VR platform."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:46
+msgid ""
+"If supported, returns the status of our tracking. This will allow you to "
+"provide feedback to the user whether there are issues with positional "
+"tracking."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:53
+msgid ""
+"Call this to initialize this interface. The first interface that is "
+"initialized is identified as the primary interface and it will be used for "
+"rendering output.\n"
+"After initializing the interface you want to use you then need to enable the "
+"AR/VR mode of a viewport and rendering should commence.\n"
+"[b]Note:[/b] You must enable the AR/VR mode on the main viewport for any "
+"device that uses the main output of Godot, such as for mobile VR.\n"
+"If you do this for a platform that handles its own output (such as OpenVR) "
+"Godot will show just one eye without distortion on screen. Alternatively, "
+"you can add a separate viewport node to your scene and enable AR/VR on that "
+"viewport. It will be used to output to the HMD, leaving you free to do "
+"anything you like in the main window, such as using a separate camera as a "
+"spectator camera or rendering something completely different.\n"
+"While currently not used, you can activate additional interfaces. You may "
+"wish to do this if you want to track controllers from other platforms. "
+"However, at this point in time only one interface can render to an HMD."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:64
+msgid ""
+"Returns [code]true[/code] if the current output of this interface is in "
+"stereo."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:71
+msgid "Turns the interface off."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:77
+msgid "On an AR interface, [code]true[/code] if anchor detection is enabled."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:80
+msgid "[code]true[/code] if this interface been initialized."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:83
+msgid "[code]true[/code] if this is the primary interface."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:88
+msgid "No ARVR capabilities."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:91
+msgid ""
+"This interface can work with normal rendering output (non-HMD based AR)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:94
+msgid "This interface supports stereoscopic rendering."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:97
+msgid "This interface supports AR (video background and real world tracking)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:100
+msgid ""
+"This interface outputs to an external device. If the main viewport is used, "
+"the on screen output is an unmodified buffer of either the left or right eye "
+"(stretched if the viewport size is not changed to the same aspect ratio of "
+"[method get_render_targetsize]). Using a separate viewport node frees up the "
+"main viewport for other purposes."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:103
+msgid ""
+"Mono output, this is mostly used internally when retrieving positioning "
+"information for our camera node or when stereo scopic rendering is not "
+"supported."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:106
+msgid ""
+"Left eye output, this is mostly used internally when rendering the image for "
+"the left eye and obtaining positioning and projection information."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:109
+msgid ""
+"Right eye output, this is mostly used internally when rendering the image "
+"for the right eye and obtaining positioning and projection information."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:112
+msgid "Tracking is behaving as expected."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:115
+msgid ""
+"Tracking is hindered by excessive motion (the player is moving faster than "
+"tracking can keep up)."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:118
+msgid ""
+"Tracking is hindered by insufficient features, it's too dark (for camera-"
+"based tracking), player is blocked, etc."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:121
+msgid ""
+"We don't know the status of the tracking or this interface does not provide "
+"feedback."
+msgstr ""
+
+#: doc/classes/ARVRInterface.xml:124
+msgid ""
+"Tracking is not functional (camera not plugged in or obscured, lighthouses "
+"turned off, etc.)."
+msgstr ""
+
+#: modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml:4
+msgid "GDNative wrapper for an ARVR interface."
+msgstr ""
+
+#: modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml:7
+msgid ""
+"This is a wrapper class for GDNative implementations of the ARVR interface. "
+"To use a GDNative ARVR interface, simply instantiate this object and set "
+"your GDNative library containing the ARVR interface implementation."
+msgstr ""
+
+#: doc/classes/ARVROrigin.xml:4
+msgid "The origin point in AR/VR."
+msgstr ""
+
+#: doc/classes/ARVROrigin.xml:7
+msgid ""
+"This is a special node within the AR/VR system that maps the physical "
+"location of the center of our tracking space to the virtual location within "
+"our game world.\n"
+"There should be only one of these nodes in your scene and you must have one. "
+"All the ARVRCamera, ARVRController and ARVRAnchor nodes should be direct "
+"children of this node for spatial tracking to work correctly.\n"
+"It is the position of this node that you update when your character needs to "
+"move through your game world while we're not moving in the real world. "
+"Movement in the real world is always in relation to this origin point.\n"
+"For example, if your character is driving a car, the ARVROrigin node should "
+"be a child node of this car. Or, if you're implementing a teleport system to "
+"move your character, you should change the position of this node."
+msgstr ""
+
+#: doc/classes/ARVROrigin.xml:19
+msgid ""
+"Allows you to adjust the scale to your game's units. Most AR/VR platforms "
+"assume a scale of 1 game world unit = 1 real world meter.\n"
+"[b]Note:[/b] This method is a passthrough to the [ARVRServer] itself."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:4
+msgid "A tracked object."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:7
+msgid ""
+"An instance of this object represents a device that is tracked, such as a "
+"controller or anchor point. HMDs aren't represented here as they are handled "
+"internally.\n"
+"As controllers are turned on and the AR/VR interface detects them, instances "
+"of this object are automatically added to this list of active tracking "
+"objects accessible through the [ARVRServer].\n"
+"The [ARVRController] and [ARVRAnchor] both consume objects of this type and "
+"should be used in your project. The positional trackers are just under-the-"
+"hood objects that make this all work. These are mostly exposed so that "
+"GDNative-based interfaces can interact with them."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:19
+msgid ""
+"Returns the hand holding this tracker, if known. See [enum TrackerHand] "
+"constants."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:26
+msgid ""
+"If this is a controller that is being tracked, the controller will also be "
+"represented by a joystick entry with this ID."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:33
+msgid ""
+"Returns the mesh related to a controller or anchor point if one is available."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:40
+msgid "Returns the controller or anchor point's name if available."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:47
+msgid "Returns the controller's orientation matrix."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:54
+msgid "Returns the world-space controller position."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:61
+msgid ""
+"Returns the internal tracker ID. This uniquely identifies the tracker per "
+"tracker type and matches the ID you need to specify for nodes such as the "
+"[ARVRController] and [ARVRAnchor] nodes."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:68
+msgid "Returns [code]true[/code] if this device tracks orientation."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:75
+msgid "Returns [code]true[/code] if this device tracks position."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:84
+msgid "Returns the transform combining this device's orientation and position."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:91
+msgid "Returns the tracker's type."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:97
+msgid ""
+"The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to "
+"[code]1.0[/code] with precision [code].01[/code]."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:102
+msgid "The hand this tracker is held in is unknown or not applicable."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:105
+msgid "This tracker is the left hand controller."
+msgstr ""
+
+#: doc/classes/ARVRPositionalTracker.xml:108
+msgid "This tracker is the right hand controller."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:4
+msgid "Server for AR and VR features."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:7
+msgid ""
+"The AR/VR server is the heart of our Advanced and Virtual Reality solution "
+"and handles all the processing."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:21
+msgid ""
+"This is an important function to understand correctly. AR and VR platforms "
+"all handle positioning slightly differently.\n"
+"For platforms that do not offer spatial tracking, our origin point (0,0,0) "
+"is the location of our HMD, but you have little control over the direction "
+"the player is facing in the real world.\n"
+"For platforms that do offer spatial tracking, our origin point depends very "
+"much on the system. For OpenVR, our origin point is usually the center of "
+"the tracking space, on the ground. For other platforms, it's often the "
+"location of the tracking camera.\n"
+"This method allows you to center your tracker on the location of the HMD. It "
+"will take the current location of the HMD and use that to adjust all your "
+"tracking data; in essence, realigning the real world to your player's "
+"current position in the game world.\n"
+"For this method to produce usable results, tracking information must be "
+"available. This often takes a few frames after starting your game.\n"
+"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."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:35
+msgid ""
+"Finds an interface by its name. For instance, if your project uses "
+"capabilities of an AR/VR platform, you can find the interface for that "
+"platform by name and initialize it."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:42
+msgid "Returns the primary interface's transformation."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:51
+msgid ""
+"Returns the interface registered at a given index in our list of interfaces."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:58
+msgid ""
+"Returns the number of interfaces currently registered with the AR/VR server. "
+"If your project supports multiple AR/VR platforms, you can look through the "
+"available interface, and either present the user with a selection or simply "
+"try to initialize each interface and use the first one that returns "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:65
+msgid ""
+"Returns a list of available interfaces the ID and name of each interface."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:72
+msgid ""
+"Returns the absolute timestamp (in μs) of the last [ARVRServer] commit of "
+"the AR/VR eyes to [RenderingServer]. The value comes from an internal call "
+"to [method OS.get_ticks_usec]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:79
+msgid ""
+"Returns the duration (in μs) of the last frame. This is computed as the "
+"difference between [method get_last_commit_usec] and [method "
+"get_last_process_usec] when committing."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:86
+msgid ""
+"Returns the absolute timestamp (in μs) of the last [ARVRServer] process "
+"callback. The value comes from an internal call to [method OS."
+"get_ticks_usec]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:93
+msgid ""
+"Returns the reference frame transform. Mostly used internally and exposed "
+"for GDNative build interfaces."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:102
+msgid "Returns the positional tracker at the given ID."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:109
+msgid "Returns the number of trackers currently registered."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:115
+msgid "The primary [ARVRInterface] currently bound to the [ARVRServer]."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:118
+msgid ""
+"Allows you to adjust the scale to your game's units. Most AR/VR platforms "
+"assume a scale of 1 game world unit = 1 real world meter."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:126
+msgid "Emitted when a new interface has been added."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:133
+msgid "Emitted when an interface is removed."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:144
+msgid ""
+"Emitted when a new tracker has been added. If you don't use a fixed number "
+"of controllers or if you're using [ARVRAnchor]s for an AR solution, it is "
+"important to react to this signal to add the appropriate [ARVRController] or "
+"[ARVRAnchor] nodes related to this new tracker."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:155
+msgid ""
+"Emitted when a tracker is removed. You should remove any [ARVRController] or "
+"[ARVRAnchor] points if applicable. This is not mandatory, the nodes simply "
+"become inactive and will be made active again when a new tracker becomes "
+"available (i.e. a new controller is switched on that takes the place of the "
+"previous one)."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:161
+msgid "The tracker tracks the location of a controller."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:164
+msgid "The tracker tracks the location of a base station."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:167
+msgid "The tracker tracks the location and size of an AR anchor."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:170
+msgid "Used internally to filter trackers of any known type."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:173
+msgid "Used internally if we haven't set the tracker type yet."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:176
+msgid "Used internally to select all trackers."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:179
+msgid ""
+"Fully reset the orientation of the HMD. Regardless of what direction the "
+"user is looking to in the real world. The user will look dead ahead in the "
+"virtual world."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:182
+msgid ""
+"Resets the orientation but keeps the tilt of the device. So if we're looking "
+"down, we keep looking down but heading will be reset."
+msgstr ""
+
+#: doc/classes/ARVRServer.xml:185
+msgid ""
+"Does not reset the orientation of the HMD, only the position of the player "
+"gets centered."
+msgstr ""
+
+#: doc/classes/AStar.xml:4
+msgid ""
+"An implementation of A* to find shortest paths among connected points in "
+"space."
+msgstr ""
+
+#: doc/classes/AStar.xml:7
+msgid ""
+"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.\n"
+"You must add points manually with [method add_point] and create segments "
+"manually with [method connect_points]. Then you can test if there is a path "
+"between two points with the [method are_points_connected] function, get a "
+"path containing indices by [method get_id_path], or one containing actual "
+"coordinates with [method get_point_path].\n"
+"It is also possible to use non-Euclidean distances. To do so, create a class "
+"that extends [code]AStar[/code] and override methods [method _compute_cost] "
+"and [method _estimate_cost]. Both take two indices and return a length, as "
+"is shown in the following example.\n"
+"[codeblock]\n"
+"class MyAStar:\n"
+" extends AStar\n"
+"\n"
+" func _compute_cost(u, v):\n"
+" return abs(u - v)\n"
+"\n"
+" func _estimate_cost(u, v):\n"
+" return min(0, abs(u - v) - 1)\n"
+"[/codeblock]\n"
+"[method _estimate_cost] should return a lower bound of the distance, i.e. "
+"[code]_estimate_cost(u, v) <= _compute_cost(u, v)[/code]. This serves as a "
+"hint to the algorithm because the custom [code]_compute_cost[/code] might be "
+"computation-heavy. If this is not the case, make [method _estimate_cost] "
+"return the same value as [method _compute_cost] to provide the algorithm "
+"with the most accurate information."
+msgstr ""
+
+#: doc/classes/AStar.xml:33
+msgid ""
+"Called when computing the cost between two connected points.\n"
+"Note that this function is hidden in the default [code]AStar[/code] class."
+msgstr ""
+
+#: doc/classes/AStar.xml:45
+msgid ""
+"Called when estimating the cost between a point and the path's ending "
+"point.\n"
+"Note that this function is hidden in the default [code]AStar[/code] class."
+msgstr ""
+
+#: doc/classes/AStar.xml:59
+msgid ""
+"Adds a new point at the given position with the given identifier. The "
+"algorithm prefers points with lower [code]weight_scale[/code] to form a "
+"path. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/"
+"code] must be 1 or larger.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(1, 0, 0), 4) # Adds the point (1, 0, 0) with "
+"weight_scale 4 and id 1\n"
+"[/codeblock]\n"
+"If there already exists a point for the given [code]id[/code], its position "
+"and weight scale are updated to the given values."
+msgstr ""
+
+#: doc/classes/AStar.xml:77
+msgid ""
+"Returns whether the two given points are directly connected by a segment. If "
+"[code]bidirectional[/code] is [code]false[/code], returns whether movement "
+"from [code]id[/code] to [code]to_id[/code] is possible through this segment."
+msgstr ""
+
+#: doc/classes/AStar.xml:84 doc/classes/AStar2D.xml:69
+msgid "Clears all the points and segments."
+msgstr ""
+
+#: doc/classes/AStar.xml:97
+msgid ""
+"Creates a segment between the given points. If [code]bidirectional[/code] is "
+"[code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] "
+"is allowed, not the reverse direction.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(1, 1, 0))\n"
+"astar.add_point(2, Vector3(0, 5, 0))\n"
+"astar.connect_points(1, 2, false)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar.xml:116
+msgid ""
+"Deletes the segment between the given points. If [code]bidirectional[/code] "
+"is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/"
+"code] is prevented, and a unidirectional segment possibly remains."
+msgstr ""
+
+#: doc/classes/AStar.xml:123 doc/classes/AStar2D.xml:106
+msgid "Returns the next available point ID with no point associated to it."
+msgstr ""
+
+#: doc/classes/AStar.xml:134 doc/classes/AStar2D.xml:117
+msgid ""
+"Returns the ID of the closest point to [code]to_position[/code], optionally "
+"taking disabled points into account. Returns -1 if there are no points in "
+"the points pool."
+msgstr ""
+
+#: doc/classes/AStar.xml:143
+msgid ""
+"Returns the closest position to [code]to_position[/code] that resides inside "
+"a segment between two connected points.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(0, 0, 0))\n"
+"astar.add_point(2, Vector3(0, 5, 0))\n"
+"astar.connect_points(1, 2)\n"
+"var res = astar.get_closest_position_in_segment(Vector3(3, 3, 0)) # Returns "
+"(0, 3, 0)\n"
+"[/codeblock]\n"
+"The result is in the segment that goes from [code]y = 0[/code] to [code]y = "
+"5[/code]. It's the closest position in the segment to the given point."
+msgstr ""
+
+#: doc/classes/AStar.xml:162
+msgid ""
+"Returns an array with the IDs of the points that form the path found by "
+"AStar between the given points. The array is ordered from the starting point "
+"to the ending point of the path.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(0, 0, 0))\n"
+"astar.add_point(2, Vector3(0, 1, 0), 1) # Default weight is 1\n"
+"astar.add_point(3, Vector3(1, 1, 0))\n"
+"astar.add_point(4, Vector3(2, 0, 0))\n"
+"\n"
+"astar.connect_points(1, 2, false)\n"
+"astar.connect_points(2, 3, false)\n"
+"astar.connect_points(4, 3, false)\n"
+"astar.connect_points(1, 4, false)\n"
+"\n"
+"var res = astar.get_id_path(1, 3) # Returns [1, 2, 3]\n"
+"[/codeblock]\n"
+"If you change the 2nd point's weight to 3, then the result will be [code][1, "
+"4, 3][/code] instead, because now even though the distance is longer, it's "
+"\"easier\" to get through point 4 than through point 2."
+msgstr ""
+
+#: doc/classes/AStar.xml:184 doc/classes/AStar2D.xml:167
+msgid ""
+"Returns the capacity of the structure backing the points, useful in "
+"conjunction with [code]reserve_space[/code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:193
+msgid ""
+"Returns an array with the IDs of the points that form the connection with "
+"the given point.\n"
+"[codeblock]\n"
+"var astar = AStar.new()\n"
+"astar.add_point(1, Vector3(0, 0, 0))\n"
+"astar.add_point(2, Vector3(0, 1, 0))\n"
+"astar.add_point(3, Vector3(1, 1, 0))\n"
+"astar.add_point(4, Vector3(2, 0, 0))\n"
+"\n"
+"astar.connect_points(1, 2, true)\n"
+"astar.connect_points(1, 3, true)\n"
+"\n"
+"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar.xml:212 doc/classes/AStar2D.xml:195
+msgid "Returns the number of points currently in the points pool."
+msgstr ""
+
+#: doc/classes/AStar.xml:223
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AStar.xml:232 doc/classes/AStar2D.xml:215
+msgid ""
+"Returns the position of the point associated with the given [code]id[/code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:241 doc/classes/AStar2D.xml:224
+msgid ""
+"Returns the weight scale of the point associated with the given [code]id[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:248 doc/classes/AStar2D.xml:231
+msgid "Returns an array of all points."
+msgstr ""
+
+#: doc/classes/AStar.xml:257 doc/classes/AStar2D.xml:240
+msgid ""
+"Returns whether a point associated with the given [code]id[/code] exists."
+msgstr ""
+
+#: doc/classes/AStar.xml:266 doc/classes/AStar2D.xml:249
+msgid ""
+"Returns whether a point is disabled or not for pathfinding. By default, all "
+"points are enabled."
+msgstr ""
+
+#: doc/classes/AStar.xml:275 doc/classes/AStar2D.xml:258
+msgid ""
+"Removes the point associated with the given [code]id[/code] from the points "
+"pool."
+msgstr ""
+
+#: doc/classes/AStar.xml:284 doc/classes/AStar2D.xml:267
+msgid ""
+"Reserves space internally for [code]num_nodes[/code] points, useful if "
+"you're adding a known large number of points at once, for a grid for "
+"instance. New capacity must be greater or equals to old capacity."
+msgstr ""
+
+#: doc/classes/AStar.xml:295 doc/classes/AStar2D.xml:278
+msgid ""
+"Disables or enables the specified point for pathfinding. Useful for making a "
+"temporary obstacle."
+msgstr ""
+
+#: doc/classes/AStar.xml:306 doc/classes/AStar2D.xml:289
+msgid ""
+"Sets the [code]position[/code] for the point with the given [code]id[/code]."
+msgstr ""
+
+#: doc/classes/AStar.xml:317 doc/classes/AStar2D.xml:300
+msgid ""
+"Sets the [code]weight_scale[/code] for the point with the given [code]id[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:4
+msgid "AStar class representation that uses 2D vectors as edges."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:7
+msgid ""
+"This is a wrapper for the [AStar] class which uses 2D vectors instead of 3D "
+"vectors."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:20
+msgid ""
+"Called when computing the cost between two connected points.\n"
+"Note that this function is hidden in the default [code]AStar2D[/code] class."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:32
+msgid ""
+"Called when estimating the cost between a point and the path's ending "
+"point.\n"
+"Note that this function is hidden in the default [code]AStar2D[/code] class."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:46
+msgid ""
+"Adds a new point at the given position with the given identifier. The "
+"algorithm prefers points with lower [code]weight_scale[/code] to form a "
+"path. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/"
+"code] must be 1 or larger.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(1, 0), 4) # Adds the point (1, 0) with "
+"weight_scale 4 and id 1\n"
+"[/codeblock]\n"
+"If there already exists a point for the given [code]id[/code], its position "
+"and weight scale are updated to the given values."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:62
+msgid "Returns whether there is a connection/segment between the given points."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:82
+msgid ""
+"Creates a segment between the given points. If [code]bidirectional[/code] is "
+"[code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] "
+"is allowed, not the reverse direction.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(1, 1))\n"
+"astar.add_point(2, Vector2(0, 5))\n"
+"astar.connect_points(1, 2, false)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar2D.xml:99
+msgid "Deletes the segment between the given points."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:126
+msgid ""
+"Returns the closest position to [code]to_position[/code] that resides inside "
+"a segment between two connected points.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(0, 0))\n"
+"astar.add_point(2, Vector2(0, 5))\n"
+"astar.connect_points(1, 2)\n"
+"var res = astar.get_closest_position_in_segment(Vector2(3, 3)) # Returns (0, "
+"3)\n"
+"[/codeblock]\n"
+"The result is in the segment that goes from [code]y = 0[/code] to [code]y = "
+"5[/code]. It's the closest position in the segment to the given point."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:145
+msgid ""
+"Returns an array with the IDs of the points that form the path found by "
+"AStar2D between the given points. The array is ordered from the starting "
+"point to the ending point of the path.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(0, 0))\n"
+"astar.add_point(2, Vector2(0, 1), 1) # Default weight is 1\n"
+"astar.add_point(3, Vector2(1, 1))\n"
+"astar.add_point(4, Vector2(2, 0))\n"
+"\n"
+"astar.connect_points(1, 2, false)\n"
+"astar.connect_points(2, 3, false)\n"
+"astar.connect_points(4, 3, false)\n"
+"astar.connect_points(1, 4, false)\n"
+"\n"
+"var res = astar.get_id_path(1, 3) # Returns [1, 2, 3]\n"
+"[/codeblock]\n"
+"If you change the 2nd point's weight to 3, then the result will be [code][1, "
+"4, 3][/code] instead, because now even though the distance is longer, it's "
+"\"easier\" to get through point 4 than through point 2."
+msgstr ""
+
+#: doc/classes/AStar2D.xml:176
+msgid ""
+"Returns an array with the IDs of the points that form the connection with "
+"the given point.\n"
+"[codeblock]\n"
+"var astar = AStar2D.new()\n"
+"astar.add_point(1, Vector2(0, 0))\n"
+"astar.add_point(2, Vector2(0, 1))\n"
+"astar.add_point(3, Vector2(1, 1))\n"
+"astar.add_point(4, Vector2(2, 0))\n"
+"\n"
+"astar.connect_points(1, 2, true)\n"
+"astar.connect_points(1, 3, true)\n"
+"\n"
+"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/AStar2D.xml:206
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:4
+msgid ""
+"Packs multiple small textures in a single, bigger one. Helps to optimize "
+"video memory costs and render calls."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:7
+msgid ""
+"[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."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:15
+msgid "The texture that contains the atlas. Can be any [Texture2D] subtype."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:18
+msgid ""
+"If [code]true[/code], clips the area outside of the region to avoid bleeding "
+"of the surrounding texture pixels."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:21
+msgid ""
+"The margin around the region. The [Rect2]'s [member Rect2.size] parameter "
+"(\"w\" and \"h\" in the editor) resizes the texture so it fits within the "
+"margin."
+msgstr ""
+
+#: doc/classes/AtlasTexture.xml:24
+msgid "The AtlasTexture's used region."
+msgstr ""
+
+#: doc/classes/AudioBusLayout.xml:4
+msgid "Stores information about the audio buses."
+msgstr ""
+
+#: doc/classes/AudioBusLayout.xml:7
+msgid ""
+"Stores position, muting, solo, bypass, effects, effect position, volume, and "
+"the connections between buses. See [AudioServer] for usage."
+msgstr ""
+
+#: doc/classes/AudioEffect.xml:4
+msgid "Audio effect for audio."
+msgstr ""
+
+#: doc/classes/AudioEffect.xml:7
+msgid ""
+"Base resource for audio bus. Applies an audio effect on the bus that the "
+"resource is applied on."
+msgstr ""
+
+#: doc/classes/AudioEffectAmplify.xml:4
+msgid ""
+"Adds an amplifying audio effect to an audio bus.\n"
+"Increases or decreases the volume of the selected audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectAmplify.xml:8
+msgid "Increases or decreases the volume being routed through the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectAmplify.xml:16
+msgid ""
+"Amount of amplification in decibels. Positive values make the sound louder, "
+"negative values make it quieter. Value can range from -80 to 24."
+msgstr ""
+
+#: doc/classes/AudioEffectBandLimitFilter.xml:4
+msgid "Adds a band limit filter to the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectBandLimitFilter.xml:7
+msgid ""
+"Limits the frequencies in a range around the [member AudioEffectFilter."
+"cutoff_hz] and allows frequencies outside of this range to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectBandPassFilter.xml:4
+msgid "Adds a band pass filter to the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectBandPassFilter.xml:7
+msgid ""
+"Attenuates the frequencies inside of a range around the [member "
+"AudioEffectFilter.cutoff_hz] and cuts frequencies outside of this band."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:4
+msgid "Adds a chorus audio effect."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:7
+msgid ""
+"Adds a chorus audio effect. The effect applies a filter with voices to "
+"duplicate the audio source and manipulate it through the filter."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:123
+msgid "The effect's raw signal."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:126 doc/classes/AudioEffectChorus.xml:144
+#: doc/classes/AudioEffectChorus.xml:162 doc/classes/AudioEffectChorus.xml:180
+msgid "The voice's cutoff frequency."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:129 doc/classes/AudioEffectChorus.xml:147
+#: doc/classes/AudioEffectChorus.xml:165 doc/classes/AudioEffectChorus.xml:183
+msgid "The voice's signal delay."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:132 doc/classes/AudioEffectChorus.xml:150
+#: doc/classes/AudioEffectChorus.xml:168 doc/classes/AudioEffectChorus.xml:186
+msgid "The voice filter's depth."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:135 doc/classes/AudioEffectChorus.xml:153
+#: doc/classes/AudioEffectChorus.xml:171 doc/classes/AudioEffectChorus.xml:189
+msgid "The voice's volume."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:138 doc/classes/AudioEffectChorus.xml:156
+#: doc/classes/AudioEffectChorus.xml:174 doc/classes/AudioEffectChorus.xml:192
+msgid "The voice's pan level."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:141 doc/classes/AudioEffectChorus.xml:159
+#: doc/classes/AudioEffectChorus.xml:177 doc/classes/AudioEffectChorus.xml:195
+msgid "The voice's filter rate."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:198
+msgid "The amount of voices in the effect."
+msgstr ""
+
+#: doc/classes/AudioEffectChorus.xml:201
+msgid "The effect's processed signal."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:4
+msgid ""
+"Adds a compressor audio effect to an audio bus.\n"
+"Reduces sounds that exceed a certain threshold level, smooths out the "
+"dynamics and increases the overall volume."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:8
+msgid ""
+"Dynamic range compressor reduces the level of the sound when the amplitude "
+"goes over a certain threshold in Decibels. One of the main uses of a "
+"compressor is to increase the dynamic range by clipping as little as "
+"possible (when sound goes over 0dB).\n"
+"Compressor has many uses in the mix:\n"
+"- In the Master bus to compress the whole output (although an "
+"[AudioEffectLimiter] is probably better).\n"
+"- In voice channels to ensure they sound as balanced as possible.\n"
+"- Sidechained. This can reduce the sound level sidechained with another "
+"audio bus for threshold detection. This technique is common in video game "
+"mixing to the level of music and SFX while voices are being heard.\n"
+"- Accentuates transients by using a wider attack, making effects sound more "
+"punchy."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:21
+msgid ""
+"Compressor's reaction time when the signal exceeds the threshold, in "
+"microseconds. Value can range from 20 to 2000."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:24
+msgid "Gain applied to the output signal."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:27
+msgid ""
+"Balance between original signal and effect signal. Value can range from 0 "
+"(totally dry) to 1 (totally wet)."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:30
+msgid ""
+"Amount of compression applied to the audio once it passes the threshold "
+"level. The higher the ratio, the more the loud parts of the audio will be "
+"compressed. Value can range from 1 to 48."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:33
+msgid ""
+"Compressor's delay time to stop reducing the signal after the signal level "
+"falls below the threshold, in milliseconds. Value can range from 20 to 2000."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:36
+msgid "Reduce the sound level using another audio bus for threshold detection."
+msgstr ""
+
+#: doc/classes/AudioEffectCompressor.xml:39
+msgid ""
+"The level above which compression is applied to the audio. Value can range "
+"from -60 to 0."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:4
+msgid ""
+"Adds a delay audio effect to an audio bus. Plays input signal back after a "
+"period of time.\n"
+"Two tap delay and feedback options."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:8
+msgid ""
+"Plays input signal back after a period of time. The delayed signal may be "
+"played back multiple times to create the sound of a repeating, decaying "
+"echo. Delay effects range from a subtle echo effect to a pronounced blending "
+"of previous sounds with new sounds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:16
+msgid ""
+"Output percent of original sound. At 0, only delayed sounds are output. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:19
+msgid "If [code]true[/code], feedback is enabled."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:22
+msgid "Feedback delay time in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:25 doc/classes/AudioEffectDelay.xml:37
+msgid "Sound level for [code]tap1[/code]."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:28
+msgid ""
+"Low-pass filter for feedback, in Hz. Frequencies below this value are "
+"filtered out of the source signal."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:31
+msgid "If [code]true[/code], [code]tap1[/code] will be enabled."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:34
+msgid "[code]tap1[/code] delay time in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:40
+msgid ""
+"Pan position for [code]tap1[/code]. Value can range from -1 (fully left) to "
+"1 (fully right)."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:43
+msgid "If [code]true[/code], [code]tap2[/code] will be enabled."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:46
+msgid "[b]Tap2[/b] delay time in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:49
+msgid "Sound level for [code]tap2[/code]."
+msgstr ""
+
+#: doc/classes/AudioEffectDelay.xml:52
+msgid ""
+"Pan position for [code]tap2[/code]. Value can range from -1 (fully left) to "
+"1 (fully right)."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:4
+msgid ""
+"Adds a distortion audio effect to an Audio bus.\n"
+"Modify the sound to make it dirty."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:8
+msgid ""
+"Modify the sound and make it dirty. Different types are available: clip, "
+"tan, lo-fi (bit crushing), overdrive, or waveshape.\n"
+"By distorting the waveform the frequency content change, which will often "
+"make the sound \"crunchy\" or \"abrasive\". For games, it can simulate sound "
+"coming from some saturated device or speaker very efficiently."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:17
+msgid "Distortion power. Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:20
+msgid ""
+"High-pass filter, in Hz. Frequencies higher than this value will not be "
+"affected by the distortion. Value can range from 1 to 20000."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:23
+msgid "Distortion type."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:26
+msgid ""
+"Increases or decreases the volume after the effect. Value can range from -80 "
+"to 24."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:29
+msgid ""
+"Increases or decreases the volume before the effect. Value can range from "
+"-60 to 60."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:34
+msgid ""
+"Digital distortion effect which cuts off peaks at the top and bottom of the "
+"waveform."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:39
+msgid ""
+"Low-resolution digital distortion effect. You can use it to emulate the "
+"sound of early digital audio devices."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:42
+msgid ""
+"Emulates the warm distortion produced by a field effect transistor, which is "
+"commonly used in solid-state musical instrument amplifiers."
+msgstr ""
+
+#: doc/classes/AudioEffectDistortion.xml:45
+msgid ""
+"Waveshaper distortions are used mainly by electronic musicians to achieve an "
+"extra-abrasive sound."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:4
+msgid ""
+"Base class for audio equalizers. Gives you control over frequencies.\n"
+"Use it to create a custom equalizer if [AudioEffectEQ6], [AudioEffectEQ10] "
+"or [AudioEffectEQ21] don't fit your needs."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:8
+msgid ""
+"AudioEffectEQ gives you control over frequencies. Use it to compensate for "
+"existing deficiencies in audio. AudioEffectEQs are useful on the Master bus "
+"to completely master a mix and give it more character. They are also useful "
+"when a game is run on a mobile device, to adjust the mix to that kind of "
+"speakers (it can be added but disabled when headphones are plugged)."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:17
+msgid "Returns the number of bands of the equalizer."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:26
+msgid "Returns the band's gain at the specified index, in dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ.xml:37
+msgid "Sets band's gain at the specified index, in dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ10.xml:4
+msgid ""
+"Adds a 10-band equalizer audio effect to an Audio bus. Gives you control "
+"over frequencies from 31 Hz to 16000 Hz.\n"
+"Each frequency can be modulated between -60/+24 dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ10.xml:8
+msgid ""
+"Frequency bands:\n"
+"Band 1: 31 Hz\n"
+"Band 2: 62 Hz\n"
+"Band 3: 125 Hz\n"
+"Band 4: 250 Hz\n"
+"Band 5: 500 Hz\n"
+"Band 6: 1000 Hz\n"
+"Band 7: 2000 Hz\n"
+"Band 8: 4000 Hz\n"
+"Band 9: 8000 Hz\n"
+"Band 10: 16000 Hz\n"
+"See also [AudioEffectEQ], [AudioEffectEQ6], [AudioEffectEQ21]."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ21.xml:4
+msgid ""
+"Adds a 21-band equalizer audio effect to an Audio bus. Gives you control "
+"over frequencies from 22 Hz to 22000 Hz.\n"
+"Each frequency can be modulated between -60/+24 dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ21.xml:8
+msgid ""
+"Frequency bands:\n"
+"Band 1: 22 Hz\n"
+"Band 2: 32 Hz\n"
+"Band 3: 44 Hz\n"
+"Band 4: 63 Hz\n"
+"Band 5: 90 Hz\n"
+"Band 6: 125 Hz\n"
+"Band 7: 175 Hz\n"
+"Band 8: 250 Hz\n"
+"Band 9: 350 Hz\n"
+"Band 10: 500 Hz\n"
+"Band 11: 700 Hz\n"
+"Band 12: 1000 Hz\n"
+"Band 13: 1400 Hz\n"
+"Band 14: 2000 Hz\n"
+"Band 15: 2800 Hz\n"
+"Band 16: 4000 Hz\n"
+"Band 17: 5600 Hz\n"
+"Band 18: 8000 Hz\n"
+"Band 19: 11000 Hz\n"
+"Band 20: 16000 Hz\n"
+"Band 21: 22000 Hz\n"
+"See also [AudioEffectEQ], [AudioEffectEQ6], [AudioEffectEQ10]."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ6.xml:4
+msgid ""
+"Adds a 6-band equalizer audio effect to an Audio bus. Gives you control over "
+"frequencies from 32 Hz to 10000 Hz.\n"
+"Each frequency can be modulated between -60/+24 dB."
+msgstr ""
+
+#: doc/classes/AudioEffectEQ6.xml:8
+msgid ""
+"Frequency bands:\n"
+"Band 1: 32 Hz\n"
+"Band 2: 100 Hz\n"
+"Band 3: 320 Hz\n"
+"Band 4: 1000 Hz\n"
+"Band 5: 3200 Hz\n"
+"Band 6: 10000 Hz\n"
+"See also [AudioEffectEQ], [AudioEffectEQ10], [AudioEffectEQ21]."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:4
+msgid "Adds a filter to the audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:7
+msgid "Allows frequencies other than the [member cutoff_hz] to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:15
+msgid "Threshold frequency for the filter, in Hz."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:20
+msgid "Gain amount of the frequencies after the filter."
+msgstr ""
+
+#: doc/classes/AudioEffectFilter.xml:23
+msgid "Amount of boost in the overtones near the cutoff frequency."
+msgstr ""
+
+#: doc/classes/AudioEffectHighPassFilter.xml:4
+msgid "Adds a high-pass filter to the Audio Bus."
+msgstr ""
+
+#: doc/classes/AudioEffectHighPassFilter.xml:7
+msgid ""
+"Cuts frequencies lower than the [member AudioEffectFilter.cutoff_hz] and "
+"allows higher frequencies to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:4
+msgid "Adds a soft-clip limiter audio effect to an Audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:7
+msgid ""
+"A limiter is similar to a compressor, but it's less flexible and designed to "
+"disallow sound going over a given dB threshold. Adding one in the Master bus "
+"is always recommended to reduce the effects of clipping.\n"
+"Soft clipping starts to reduce the peaks a little below the threshold level "
+"and progressively increases its effect as the input level increases such "
+"that the threshold is never exceeded."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:16
+msgid ""
+"The waveform's maximum allowed value, in decibels. Value can range from -20 "
+"to -0.1."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:19
+msgid ""
+"Applies a gain to the limited waves, in decibels. Value can range from 0 to "
+"6."
+msgstr ""
+
+#: doc/classes/AudioEffectLimiter.xml:24
+msgid ""
+"Threshold from which the limiter begins to be active, in decibels. Value can "
+"range from -30 to 0."
+msgstr ""
+
+#: doc/classes/AudioEffectLowPassFilter.xml:4
+msgid "Adds a low-pass filter to the Audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectLowPassFilter.xml:7
+msgid ""
+"Cuts frequencies higher than the [member AudioEffectFilter.cutoff_hz] and "
+"allows lower frequencies to pass."
+msgstr ""
+
+#: doc/classes/AudioEffectNotchFilter.xml:4
+msgid "Adds a notch filter to the Audio bus."
+msgstr ""
+
+#: doc/classes/AudioEffectNotchFilter.xml:7
+msgid ""
+"Attenuates frequencies in a narrow band around the [member AudioEffectFilter."
+"cutoff_hz] and cuts frequencies outside of this range."
+msgstr ""
+
+#: doc/classes/AudioEffectPanner.xml:4
+msgid "Adds a panner audio effect to an Audio bus. Pans sound left or right."
+msgstr ""
+
+#: doc/classes/AudioEffectPanner.xml:7
+msgid ""
+"Determines how much of an audio signal is sent to the left and right buses."
+msgstr ""
+
+#: doc/classes/AudioEffectPanner.xml:15
+msgid "Pan position. Value can range from -1 (fully left) to 1 (fully right)."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:4
+msgid ""
+"Adds a phaser audio effect to an Audio bus.\n"
+"Combines the original signal with a copy that is slightly out of phase with "
+"the original."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:8
+msgid ""
+"Combines phase-shifted signals with the original signal. The movement of the "
+"phase-shifted signals is controlled using a low-frequency oscillator."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:16
+msgid ""
+"Governs how high the filter frequencies sweep. Low value will primarily "
+"affect bass frequencies. High value can sweep high into the treble. Value "
+"can range from 0.1 to 4."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:19
+msgid "Output percent of modified sound. Value can range from 0.1 to 0.9."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:22
+msgid ""
+"Determines the maximum frequency affected by the LFO modulations, in Hz. "
+"Value can range from 10 to 10000."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:25
+msgid ""
+"Determines the minimum frequency affected by the LFO modulations, in Hz. "
+"Value can range from 10 to 10000."
+msgstr ""
+
+#: doc/classes/AudioEffectPhaser.xml:28
+msgid ""
+"Adjusts the rate in Hz at which the effect sweeps up and down across the "
+"frequency range."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:4
+msgid ""
+"Adds a pitch-shifting audio effect to an Audio bus.\n"
+"Raises or lowers the pitch of original sound."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:8
+msgid ""
+"Allows modulation of pitch independently of tempo. All frequencies can be "
+"increased/decreased with minimal effect on transients."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:20
+msgid "Pitch value. Can range from 0 (-1 octave) to 16 (+16 octaves)."
+msgstr ""
+
+#: doc/classes/AudioEffectPitchShift.xml:35
+#: doc/classes/AudioEffectSpectrumAnalyzer.xml:31
+msgid "Represents the size of the [enum FFT_Size] enum."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:4
+msgid "Audio effect used for recording sound from a microphone."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:9
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/audio/"
+"recording_with_microphone.html"
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:16
+msgid "Returns the recorded sample."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:23
+msgid "Returns whether the recording is active or not."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:32
+msgid ""
+"If [code]true[/code], the sound will be recorded. Note that restarting the "
+"recording will remove the previously recorded sample."
+msgstr ""
+
+#: doc/classes/AudioEffectRecord.xml:38
+msgid ""
+"Specifies the format in which the sample will be recorded. See [enum "
+"AudioStreamSample.Format] for available formats."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:4
+msgid ""
+"Adds a reverberation audio effect to an Audio bus.\n"
+"Simulates the sound of acoustic environments such as rooms, concert halls, "
+"caverns, or an open spaces."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:8
+msgid ""
+"Simulates rooms of different sizes. Its parameters can be adjusted to "
+"simulate the sound of a specific room."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:16
+msgid ""
+"Defines how reflective the imaginary room's walls are. Value can range from "
+"0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:19
+msgid ""
+"Output percent of original sound. At 0, only modified sound is outputted. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:22
+msgid ""
+"High-pass filter passes signals with a frequency higher than a certain "
+"cutoff frequency and attenuates signals with frequencies lower than the "
+"cutoff frequency. Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:25
+msgid "Output percent of predelay. Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:28
+msgid ""
+"Time between the original signal and the early reflections of the reverb "
+"signal, in milliseconds."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:31
+msgid ""
+"Dimensions of simulated room. Bigger means more echoes. Value can range from "
+"0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:34
+msgid ""
+"Widens or narrows the stereo image of the reverb tail. 1 means fully widens. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectReverb.xml:37
+msgid ""
+"Output percent of modified sound. At 0, only original sound is outputted. "
+"Value can range from 0 to 1."
+msgstr ""
+
+#: doc/classes/AudioEffectSpectrumAnalyzerInstance.xml:25
+msgid "Use the average value as magnitude."
+msgstr ""
+
+#: doc/classes/AudioEffectSpectrumAnalyzerInstance.xml:28
+msgid "Use the maximum value as magnitude."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:4
+msgid "Server interface for low-level audio access."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:7
+msgid ""
+"[AudioServer] is a low-level server interface for audio access. It is in "
+"charge of creating sample data (playable audio) as well as its playback via "
+"a voice interface."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html"
+msgstr ""
+
+#: doc/classes/AudioServer.xml:19
+msgid "Adds a bus at [code]at_position[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:32
+msgid ""
+"Adds an [AudioEffect] effect to the bus [code]bus_idx[/code] at "
+"[code]at_position[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:39
+msgid ""
+"Name of the current device for audio input (see [method "
+"capture_get_device_list])."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:46
+msgid "Returns the names of all audio input devices detected on the system."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:55
+msgid "Sets which audio input device is used for audio capture."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:62
+msgid "Generates an [AudioBusLayout] using the available buses and effects."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:71
+msgid ""
+"Returns the amount of channels of the bus at index [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:82
+msgid ""
+"Returns the [AudioEffect] at position [code]effect_idx[/code] in bus "
+"[code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:91
+msgid "Returns the number of effects on the bus at [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:104
+msgid ""
+"Returns the [AudioEffectInstance] assigned to the given bus and effect "
+"indices (and optionally channel)."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:113
+msgid "Returns the index of the bus with the name [code]bus_name[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:122
+msgid "Returns the name of the bus with the index [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:133
+msgid ""
+"Returns the peak volume of the left speaker at bus index [code]bus_idx[/"
+"code] and channel index [code]channel[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:144
+msgid ""
+"Returns the peak volume of the right speaker at bus index [code]bus_idx[/"
+"code] and channel index [code]channel[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:153
+msgid ""
+"Returns the name of the bus that the bus at index [code]bus_idx[/code] sends "
+"to."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:162
+msgid "Returns the volume of the bus at index [code]bus_idx[/code] in dB."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:169
+msgid "Returns the names of all audio devices detected on the system."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:176
+msgid "Returns the sample rate at the output of the [AudioServer]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:183
+msgid "Returns the audio driver's output latency."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:190
+msgid "Returns the speaker configuration."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:197
+msgid "Returns the relative time since the last mix occurred."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:204
+msgid "Returns the relative time until the next mix occurs."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:213 doc/classes/AudioServer.xml:292
+msgid ""
+"If [code]true[/code], the bus at index [code]bus_idx[/code] is bypassing "
+"effects."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:224 doc/classes/AudioServer.xml:305
+msgid ""
+"If [code]true[/code], the effect at index [code]effect_idx[/code] on the bus "
+"at index [code]bus_idx[/code] is enabled."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:233 doc/classes/AudioServer.xml:325
+msgid "If [code]true[/code], the bus at index [code]bus_idx[/code] is muted."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:242 doc/classes/AudioServer.xml:358
+msgid ""
+"If [code]true[/code], the bus at index [code]bus_idx[/code] is in solo mode."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:249
+msgid ""
+"Locks the audio driver's main loop.\n"
+"[b]Note:[/b] Remember to unlock it afterwards."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:261
+msgid ""
+"Moves the bus from index [code]index[/code] to index [code]to_index[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:270
+msgid "Removes the bus at index [code]index[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:281
+msgid ""
+"Removes the effect at index [code]effect_idx[/code] from the bus at index "
+"[code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:314
+msgid "Overwrites the currently used [AudioBusLayout]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:336
+msgid ""
+"Sets the name of the bus at index [code]bus_idx[/code] to [code]name[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:347
+msgid ""
+"Connects the output of the bus at [code]bus_idx[/code] to the bus named "
+"[code]send[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:369
+msgid ""
+"Sets the volume of the bus at index [code]bus_idx[/code] to [code]volume_db[/"
+"code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:382
+msgid "Swaps the position of two effects in bus [code]bus_idx[/code]."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:389
+msgid ""
+"Unlocks the audio driver's main loop. (After locking it, you should always "
+"unlock it.)"
+msgstr ""
+
+#: doc/classes/AudioServer.xml:395
+msgid "Number of available audio buses."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:398
+msgid ""
+"Name of the current device for audio output (see [method get_device_list])."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:401
+msgid ""
+"Scales the rate at which audio is played (i.e. setting it to [code]0.5[/"
+"code] will make the audio be played twice as fast)."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:407
+msgid "Emitted when the [AudioBusLayout] changes."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:413
+msgid "Two or fewer speakers were detected."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:416
+msgid "A 3.1 channel surround setup was detected."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:419
+msgid "A 5.1 channel surround setup was detected."
+msgstr ""
+
+#: doc/classes/AudioServer.xml:422
+msgid "A 7.1 channel surround setup was detected."
+msgstr ""
+
+#: doc/classes/AudioStream.xml:4
+msgid "Base class for audio streams."
+msgstr ""
+
+#: doc/classes/AudioStream.xml:7
+msgid ""
+"Base class for audio streams. Audio streams are used for sound effects and "
+"music playback, and support WAV (via [AudioStreamSample]) and OGG (via "
+"[AudioStreamOGGVorbis]) file formats."
+msgstr ""
+
+#: doc/classes/AudioStream.xml:10 doc/classes/AudioStreamPlayer.xml:10
+#: doc/classes/AudioStreamPlayer2D.xml:10
+#: doc/classes/AudioStreamPlayer3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html"
+msgstr ""
+
+#: doc/classes/AudioStream.xml:17
+msgid "Returns the length of the audio stream in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamGenerator.xml:8
+#: doc/classes/AudioStreamGeneratorPlayback.xml:8
+msgid ""
+"https://github.com/godotengine/godot-demo-projects/tree/master/audio/"
+"generator"
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:4
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:7
+msgid "OGG Vorbis audio stream driver."
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:15
+msgid "Contains the audio data in bytes."
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:18
+msgid ""
+"If [code]true[/code], the stream will automatically loop when it reaches the "
+"end."
+msgstr ""
+
+#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml:21
+msgid "Time in seconds at which the stream starts after being looped."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayback.xml:4
+msgid "Meta class for playing back audio."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayback.xml:7
+msgid ""
+"Can play, loop, pause a scroll through audio. See [AudioStream] and "
+"[AudioStreamOGGVorbis] for usage."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:4
+msgid "Plays back audio non-positionally."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:7
+msgid "Plays an audio stream non-positionally."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:17
+msgid "Returns the position in the [AudioStream] in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:24
+msgid ""
+"Returns the [AudioStreamPlayback] object associated with this "
+"[AudioStreamPlayer]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:33
+msgid "Plays the audio from the given [code]from_position[/code], in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:42 doc/classes/AudioStreamPlayer2D.xml:42
+#: doc/classes/AudioStreamPlayer3D.xml:42
+msgid "Sets the position from which audio will be played, in seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:49 doc/classes/AudioStreamPlayer2D.xml:49
+#: doc/classes/AudioStreamPlayer3D.xml:49
+msgid "Stops the audio."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:55 doc/classes/AudioStreamPlayer2D.xml:61
+#: doc/classes/AudioStreamPlayer3D.xml:67
+msgid "If [code]true[/code], audio plays when added to scene tree."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:58 doc/classes/AudioStreamPlayer2D.xml:64
+#: doc/classes/AudioStreamPlayer3D.xml:70
+msgid "Bus on which this audio is playing."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:61
+msgid ""
+"If the audio configuration has more than two speakers, this sets the target "
+"channels. See [enum MixTarget] constants."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:64 doc/classes/AudioStreamPlayer2D.xml:70
+#: doc/classes/AudioStreamPlayer3D.xml:94
+msgid "Changes the pitch and the tempo of the audio."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:67 doc/classes/AudioStreamPlayer2D.xml:73
+#: doc/classes/AudioStreamPlayer3D.xml:97
+msgid "If [code]true[/code], audio is playing."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:70 doc/classes/AudioStreamPlayer2D.xml:76
+#: doc/classes/AudioStreamPlayer3D.xml:100
+msgid "The [AudioStream] object to be played."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:73 doc/classes/AudioStreamPlayer2D.xml:79
+#: doc/classes/AudioStreamPlayer3D.xml:103
+msgid ""
+"If [code]true[/code], the playback is paused. You can resume it by setting "
+"[code]stream_paused[/code] to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:76
+msgid "Volume of sound, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:82 doc/classes/AudioStreamPlayer2D.xml:88
+#: doc/classes/AudioStreamPlayer3D.xml:115
+msgid "Emitted when the audio stops playing."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:88
+msgid "The audio will be played only on the first channel."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:91
+msgid "The audio will be played on all surround channels."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer.xml:94
+msgid ""
+"The audio will be played on the second channel, which is usually the center."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:4
+msgid "Plays audio in 2D."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:7
+msgid "Plays audio that dampens with distance from screen center."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:17
+#: doc/classes/AudioStreamPlayer3D.xml:17
+msgid "Returns the position in the [AudioStream]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:24
+msgid ""
+"Returns the [AudioStreamPlayback] object associated with this "
+"[AudioStreamPlayer2D]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:33
+#: doc/classes/AudioStreamPlayer3D.xml:33
+msgid ""
+"Plays the audio from the given position [code]from_position[/code], in "
+"seconds."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:55
+#: doc/classes/AudioStreamPlayer3D.xml:55
+msgid "Areas in which this sound plays."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:58
+msgid "Dampens audio over distance with this as an exponent."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:67
+msgid "Maximum distance from which audio is still hearable."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer2D.xml:82
+msgid "Base volume without dampening."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:4
+msgid "Plays 3D sound in 3D space."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:7
+msgid ""
+"Plays a sound effect with directed sound effects, dampens with distance if "
+"needed, generates effect of hearable position in space."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:24
+msgid ""
+"Returns the [AudioStreamPlayback] object associated with this "
+"[AudioStreamPlayer3D]."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:58
+msgid "Dampens audio above this frequency, in Hz."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:61
+msgid "Amount how much the filter affects the loudness, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:64
+msgid ""
+"Decides if audio should get quieter with distance linearly, quadratically, "
+"logarithmically, or not be affected by distance, effectively disabling "
+"attenuation."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:73
+msgid "Decides in which step the Doppler effect should be calculated."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:76
+msgid "The angle in which the audio reaches cameras undampened."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:79
+msgid ""
+"If [code]true[/code], the audio should be dampened according to the "
+"direction of the sound."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:82
+msgid ""
+"Dampens audio if camera is outside of [member emission_angle_degrees] and "
+"[member emission_angle_enabled] is set by this factor, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:85
+msgid "Sets the absolute maximum of the soundlevel, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:88
+msgid ""
+"Sets the distance from which the [member out_of_range_mode] takes effect. "
+"Has no effect if set to 0."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:91
+msgid ""
+"Decides if audio should pause when source is outside of [member "
+"max_distance] range."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:106
+msgid "Base sound level unaffected by dampening, in dB."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:109
+msgid "Factor for the attenuation effect."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:121
+msgid "Linear dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:124
+msgid "Squared dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:127
+msgid "Logarithmic dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:130
+msgid "No dampening of loudness according to distance."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:133
+msgid "Mix this audio in, even when it's out of range."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:136
+msgid "Pause this audio when it gets out of range."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:139
+msgid "Disables doppler tracking."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:142
+msgid "Executes doppler tracking in idle step."
+msgstr ""
+
+#: doc/classes/AudioStreamPlayer3D.xml:145
+msgid "Executes doppler tracking in physics step."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:4
+msgid "Plays audio with random pitch shifting."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:7
+msgid "Randomly varies pitch on each start."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:15
+msgid "The current [AudioStream]."
+msgstr ""
+
+#: doc/classes/AudioStreamRandomPitch.xml:18
+msgid "The intensity of random pitch variation."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:4
+msgid "Stores audio data loaded from WAV files."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:7
+msgid ""
+"AudioStreamSample stores sound samples loaded from WAV files. To play the "
+"stored sound, use an [AudioStreamPlayer] (for non-positional audio) or "
+"[AudioStreamPlayer2D]/[AudioStreamPlayer3D] (for positional audio). The "
+"sound can be looped.\n"
+"This class can also be used to store dynamically-generated PCM audio data."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:19
+msgid ""
+"Saves the AudioStreamSample as a WAV file to [code]path[/code]. Samples with "
+"IMA ADPCM format can't be saved.\n"
+"[b]Note:[/b] A [code].wav[/code] extension is automatically appended to "
+"[code]path[/code] if it is missing."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:26
+msgid ""
+"Contains the audio data in bytes.\n"
+"[b]Note:[/b] This property expects signed PCM8 data. To convert unsigned "
+"PCM8 to signed PCM8, subtract 128 from each byte."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:30
+msgid "Audio format. See [enum Format] constants for values."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:33
+msgid "Loop start in bytes."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:36
+msgid "Loop end in bytes."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:39
+msgid "Loop mode. See [enum LoopMode] constants for values."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:42
+msgid "The sample rate for mixing this audio."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:45
+msgid "If [code]true[/code], audio is stereo."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:50
+msgid "8-bit audio codec."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:53
+msgid "16-bit audio codec."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:56
+msgid "Audio is compressed using IMA ADPCM."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:59
+msgid "Audio does not loop."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:62
+msgid ""
+"Audio loops the data between [member loop_begin] and [member loop_end] "
+"playing forward only."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:65
+msgid ""
+"Audio loops the data between [member loop_begin] and [member loop_end] "
+"playing back and forth."
+msgstr ""
+
+#: doc/classes/AudioStreamSample.xml:68
+msgid ""
+"Audio loops the data between [member loop_begin] and [member loop_end] "
+"playing backward only."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:4
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:15
+msgid "Buffer mode. See [enum CopyMode] constants."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:18
+msgid ""
+"The area covered by the BackBufferCopy. Only used if [member copy_mode] is "
+"[constant COPY_MODE_RECT]."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:23
+msgid ""
+"Disables the buffering mode. This means the BackBufferCopy node will "
+"directly use the portion of screen it covers."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:26
+msgid "BackBufferCopy buffers a rectangular region."
+msgstr ""
+
+#: doc/classes/BackBufferCopy.xml:29
+msgid "BackBufferCopy buffers the entire screen."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:4
+msgid "Base class for different kinds of buttons."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:7
+msgid ""
+"BaseButton is the abstract base class for buttons, so it shouldn't be used "
+"directly (it doesn't display anything). Other types of buttons inherit from "
+"it."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:16
+msgid "Called when the button is pressed."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:25
+msgid ""
+"Called when the button is toggled (only if [member toggle_mode] is active)."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:32
+msgid ""
+"Returns the visual state used to draw the button. This is useful mainly when "
+"implementing your own draw code by either overriding _draw() or connecting "
+"to \"draw\" signal. The visual state of the button is defined by the [enum "
+"DrawMode] enum."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:39
+msgid ""
+"Returns [code]true[/code] if the mouse has entered the button and has not "
+"left it yet."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:45
+msgid ""
+"Determines when the button is considered clicked, one of the [enum "
+"ActionMode] constants."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:48
+msgid ""
+"Binary mask to choose which mouse buttons this button will respond to.\n"
+"To allow both left-click and right-click, use [code]BUTTON_MASK_LEFT | "
+"BUTTON_MASK_RIGHT[/code]."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:52
+msgid ""
+"If [code]true[/code], the button is in disabled state and can't be clicked "
+"or toggled."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:55
+msgid ""
+"Focus access mode to use when switching between enabled/disabled (see "
+"[member Control.focus_mode] and [member disabled])."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:59
+msgid "[ButtonGroup] associated to the button."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:62
+msgid ""
+"If [code]true[/code], the button stays pressed when moving the cursor "
+"outside the button while pressing it."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:65
+msgid ""
+"If [code]true[/code], the button's state is pressed. Means the button is "
+"pressed down or toggled (if [member toggle_mode] is active)."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:68
+msgid "[ShortCut] associated to the button."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:71
+msgid ""
+"If [code]true[/code], the button will add information about its shortcut in "
+"the tooltip."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:74
+msgid ""
+"If [code]true[/code], the button is in toggle mode. Makes the button flip "
+"state between pressed and unpressed each time its area is clicked."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:80
+msgid "Emitted when the button starts being held down."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:85
+msgid "Emitted when the button stops being held down."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:90
+msgid ""
+"Emitted when the button is toggled or pressed. This is on [signal "
+"button_down] if [member action_mode] is [constant ACTION_MODE_BUTTON_PRESS] "
+"and on [signal button_up] otherwise."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:97
+msgid ""
+"Emitted when the button was just toggled between pressed and normal states "
+"(only if [member toggle_mode] is active). The new state is contained in the "
+"[code]button_pressed[/code] argument."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:103
+msgid ""
+"The normal state (i.e. not pressed, not hovered, not toggled and enabled) of "
+"buttons."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:106
+msgid "The state of buttons are pressed."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:109
+msgid "The state of buttons are hovered."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:112
+msgid "The state of buttons are disabled."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:115
+msgid "The state of buttons are both hovered and pressed."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:118
+msgid "Require just a press to consider the button clicked."
+msgstr ""
+
+#: doc/classes/BaseButton.xml:121
+msgid ""
+"Require a press and a subsequent release before considering the button "
+"clicked."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:4
+msgid "Default 3D rendering material."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:7
+msgid ""
+"This provides a default material with a wide variety of rendering features "
+"and properties without the need to write shader code. See the tutorial below "
+"for details."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/spatial_material.html"
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:19
+msgid "Returns [code]true[/code], if the specified [enum Feature] is enabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:28
+msgid ""
+"Returns [code]true[/code], if the specified flag is enabled. See [enum "
+"Flags] enumerator for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:37
+msgid ""
+"Returns the [Texture] associated with the specified [enum TextureParam]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:48
+msgid ""
+"If [code]true[/code], enables the specified [enum Feature]. Many features "
+"that are available in [BaseMaterial3D]s need to be enabled before use. This "
+"way the cost for using the feature is only incurred when specified. Features "
+"can also be enabled by setting the corresponding member to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:59
+msgid ""
+"If [code]true[/code], enables the specified flag. Flags are optional "
+"behavior that can be turned on and off. Only one flag can be enabled at a "
+"time with this function, the flag enumerators cannot be bit-masked together "
+"to enable or disable multiple flags at once. Flags can also be enabled by "
+"setting the corresponding member to [code]true[/code]. See [enum Flags] "
+"enumerator for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:70
+msgid ""
+"Sets the texture for the slot specified by [code]param[/code]. See [enum "
+"TextureParam] for available slots."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:76
+msgid "The material's base color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:79
+msgid ""
+"Forces a conversion of the [member albedo_texture] from sRGB space to linear "
+"space."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:82
+msgid ""
+"Texture to multiply by [member albedo_color]. Used for basic texturing of "
+"objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:85
+msgid "Threshold at which the alpha scissor will discard values."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:88
+msgid "The strength of the anisotropy effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:91
+msgid ""
+"If [code]true[/code], anisotropy is enabled. Changes the shape of the "
+"specular blob and aligns it to tangent space. Mesh tangents are needed for "
+"this to work. If the mesh does not contain tangents the anisotropy effect "
+"will appear broken."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:94
+msgid "Texture that offsets the tangent map for anisotropy calculations."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:97
+msgid ""
+"If [code]true[/code], ambient occlusion is enabled. Ambient occlusion "
+"darkens areas based on the [member ao_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:100
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:103
+msgid ""
+"If [code]true[/code], use [code]UV2[/code] coordinates to look up from the "
+"[member ao_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:106
+msgid ""
+"Texture that defines the amount of ambient occlusion for a given point on "
+"the object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:109 doc/classes/BaseMaterial3D.xml:275
+#: doc/classes/BaseMaterial3D.xml:296
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:112
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:115
+msgid "Controls how the object faces the camera. See [enum BillboardMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:118
+msgid ""
+"The material's blend mode.\n"
+"[b]Note:[/b] Values other than [code]Mix[/code] force the object into the "
+"transparent pipeline. See [enum BlendMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:122
+msgid ""
+"Sets the strength of the clearcoat effect. Setting to [code]0[/code] looks "
+"the same as disabling the clearcoat effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:125
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:128
+msgid ""
+"Sets the roughness of the clearcoat pass. A higher value results in a "
+"smoother clearcoat while a lower value results in a rougher clearcoat."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:131
+msgid ""
+"Texture that defines the strength of the clearcoat effect and the glossiness "
+"of the clearcoat. Strength is specified in the red channel while glossiness "
+"is specified in the green channel."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:134
+msgid ""
+"Which side of the object is not drawn when backfaces are rendered. See [enum "
+"CullMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:137
+msgid ""
+"Determines when depth rendering takes place. See [enum DepthDrawMode]. See "
+"also [member transparency]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:140
+msgid "Texture that specifies the color of the detail overlay."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:143
+msgid ""
+"Specifies how the [member detail_albedo] should blend with the current "
+"[code]ALBEDO[/code]. See [enum BlendMode] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:146
+msgid ""
+"If [code]true[/code], enables the detail overlay. Detail is a second texture "
+"that gets mixed over the surface of the object based on [member "
+"detail_mask]. This can be used to add variation to objects, or to blend "
+"between two different albedo/normal textures."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:149
+msgid ""
+"Texture used to specify how the detail textures get blended with the base "
+"textures."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:152
+msgid "Texture that specifies the per-pixel normal of the detail overlay."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:155
+msgid ""
+"Specifies whether to use [code]UV[/code] or [code]UV2[/code] for the detail "
+"layer. See [enum DetailUV] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:158
+msgid ""
+"The algorithm used for diffuse light scattering. See [enum DiffuseMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:161
+msgid "If [code]true[/code], the object receives no ambient light."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:164
+msgid ""
+"If [code]true[/code], the object receives no shadow that would otherwise be "
+"cast onto it."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:167
+msgid "Distance at which the object fades fully and is no longer visible."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:170
+msgid ""
+"Distance at which the object starts to fade. If the object is less than this "
+"distance away it will appear normal."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:173
+msgid ""
+"Specifies which type of fade to use. Can be any of the [enum "
+"DistanceFadeMode]s."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:176
+msgid "The emitted light's color. See [member emission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:179
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:182
+msgid "The emitted light's strength. See [member emission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:185
+msgid "Use [code]UV2[/code] to read from the [member emission_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:188
+msgid ""
+"Sets how [member emission] interacts with [member emission_texture]. Can "
+"either add or multiply. See [enum EmissionOperator] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:191
+msgid "Texture that specifies how much surface emits light at a given point."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:194
+msgid ""
+"If [code]true[/code], the object is rendered at the same size regardless of "
+"distance."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:197
+msgid ""
+"If [code]true[/code], enables the vertex grow setting. See [member "
+"grow_amount]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:200
+msgid "Grows object vertices in the direction of their normals."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:221
+msgid ""
+"A high value makes the material appear more like a metal. Non-metals use "
+"their albedo as the diffuse color and add diffuse to the specular "
+"reflection. With non-metals, the reflection appears on top of the albedo "
+"color. Metals use their albedo as a multiplier to the specular reflection "
+"and set the diffuse color to black resulting in a tinted reflection. "
+"Materials work better when fully metal or fully non-metal, values between "
+"[code]0[/code] and [code]1[/code] should only be used for blending between "
+"metal and non-metal sections. To alter the amount of reflection use [member "
+"roughness]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:224
+msgid ""
+"Sets the size of the specular lobe. The specular lobe is the bright spot "
+"that is reflected from light sources.\n"
+"[b]Note:[/b] unlike [member metallic], this is not energy-conserving, so it "
+"should be left at [code]0.5[/code] in most cases. See also [member "
+"roughness]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:228
+msgid ""
+"Texture used to specify metallic for an object. This is multiplied by "
+"[member metallic]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:231
+msgid ""
+"Specifies the channel of the [member metallic_texture] in which the metallic "
+"information is stored. This is useful when you store the information for "
+"multiple effects in a single texture. For example if you stored metallic in "
+"the red channel, roughness in the blue, and ambient occlusion in the green "
+"you could reduce the number of textures you use."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:234
+msgid ""
+"If [code]true[/code], depth testing is disabled and the object will be drawn "
+"in render order."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:237
+msgid "If [code]true[/code], normal mapping is enabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:240
+msgid "The strength of the normal map's effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:243
+msgid ""
+"Texture used to specify the normal at a given pixel. The "
+"[code]normal_texture[/code] only uses the red and green channels. The normal "
+"read from [code]normal_texture[/code] is oriented around the surface normal "
+"provided by the [Mesh]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:248
+msgid ""
+"The number of horizontal frames in the particle sprite sheet. Only enabled "
+"when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:251
+msgid ""
+"If [code]true[/code], particle animations are looped. Only enabled when "
+"using [constant BILLBOARD_PARTICLES]. See [member billboard_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:254
+msgid ""
+"The number of vertical frames in the particle sprite sheet. Only enabled "
+"when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:257
+msgid "The point size in pixels. See [member use_point_size]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:260
+msgid ""
+"Distance over which the fade effect takes place. The larger the distance the "
+"longer it takes for an object to fade."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:263
+msgid ""
+"If [code]true[/code], the proximity fade effect is enabled. The proximity "
+"fade effect fades out each pixel based on its distance to another object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:266
+msgid ""
+"If [code]true[/code], the refraction effect is enabled. Distorts "
+"transparency based on light from behind the object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:269
+msgid "The strength of the refraction effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:272
+msgid ""
+"Texture that controls the strength of the refraction per-pixel. Multiplied "
+"by [member refraction_scale]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:278
+msgid "Sets the strength of the rim lighting effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:281
+msgid ""
+"If [code]true[/code], rim effect is enabled. Rim lighting increases the "
+"brightness at glancing angles on an object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:284
+msgid ""
+"Texture used to set the strength of the rim lighting effect per-pixel. "
+"Multiplied by [member rim]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:287
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:290
+msgid ""
+"Surface reflection. A value of [code]0[/code] represents a perfect mirror "
+"while a value of [code]1[/code] completely blurs the reflection. See also "
+"[member metallic]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:293
+msgid ""
+"Texture used to control the roughness per-pixel. Multiplied by [member "
+"roughness]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:301
+msgid ""
+"If [code]true[/code], enables the \"shadow to opacity\" render mode where "
+"lighting modifies the alpha so shadowed areas are opaque and non-shadowed "
+"areas are transparent. Useful for overlaying shadows onto a camera feed in "
+"AR."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:304
+msgid "The method for rendering the specular blob. See [enum SpecularMode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:307
+msgid ""
+"If [code]true[/code], subsurface scattering is enabled. Emulates light that "
+"penetrates an object's surface, is scattered, and then emerges."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:312
+msgid "The strength of the subsurface scattering effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:315
+msgid ""
+"Texture used to control the subsurface scattering strength. Stored in the "
+"red texture channel. Multiplied by [member subsurf_scatter_strength]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:318
+msgid "Filter flags for the texture. See [enum TextureFilter] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:321
+msgid "Repeat flags for the texture. See [enum TextureFilter] for options."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:324
+msgid ""
+"The color used by the transmission effect. Represents the light passing "
+"through an object."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:327
+msgid "If [code]true[/code], the transmission effect is enabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:330
+msgid ""
+"Texture used to control the transmission effect per-pixel. Added to [member "
+"transmission]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:333
+msgid ""
+"If [code]true[/code], transparency is enabled on the body. See also [member "
+"blend_mode]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:336
+msgid ""
+"If [code]true[/code], render point size can be changed.\n"
+"[b]Note:[/b] this is only effective for objects whose geometry is point-"
+"based rather than triangle-based. See also [member point_size]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:340
+msgid ""
+"How much to offset the [code]UV[/code] coordinates. This amount will be "
+"added to [code]UV[/code] in the vertex function. This can be used to offset "
+"a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:343
+msgid ""
+"How much to scale the [code]UV[/code] coordinates. This is multiplied by "
+"[code]UV[/code] in the vertex function."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:346
+msgid ""
+"If [code]true[/code], instead of using [code]UV[/code] textures will use a "
+"triplanar texture lookup to determine how to apply textures. Triplanar uses "
+"the orientation of the object's surface to blend between texture "
+"coordinates. It reads from the source texture 3 times, once for each axis "
+"and then blends between the results based on how closely the pixel aligns "
+"with each axis. This is often used for natural features to get a realistic "
+"blend of materials. Because triplanar texturing requires many more texture "
+"reads per-pixel it is much slower than normal UV texturing. Additionally, "
+"because it is blending the texture between the three axes, it is unsuitable "
+"when you are trying to achieve crisp texturing."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:349 doc/classes/BaseMaterial3D.xml:364
+msgid ""
+"A lower number blends the texture more softly while a higher number blends "
+"the texture more sharply."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:352
+msgid ""
+"If [code]true[/code], triplanar mapping for [code]UV[/code] is calculated in "
+"world space rather than object local space. See also [member uv1_triplanar]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:355
+msgid ""
+"How much to offset the [code]UV2[/code] coordinates. This amount will be "
+"added to [code]UV2[/code] in the vertex function. This can be used to offset "
+"a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:358
+msgid ""
+"How much to scale the [code]UV2[/code] coordinates. This is multiplied by "
+"[code]UV2[/code] in the vertex function."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:361
+msgid ""
+"If [code]true[/code], instead of using [code]UV2[/code] textures will use a "
+"triplanar texture lookup to determine how to apply textures. Triplanar uses "
+"the orientation of the object's surface to blend between texture "
+"coordinates. It reads from the source texture 3 times, once for each axis "
+"and then blends between the results based on how closely the pixel aligns "
+"with each axis. This is often used for natural features to get a realistic "
+"blend of materials. Because triplanar texturing requires many more texture "
+"reads per-pixel it is much slower than normal UV texturing. Additionally, "
+"because it is blending the texture between the three axes, it is unsuitable "
+"when you are trying to achieve crisp texturing."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:367
+msgid ""
+"If [code]true[/code], triplanar mapping for [code]UV2[/code] is calculated "
+"in world space rather than object local space. See also [member "
+"uv2_triplanar]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:370
+msgid ""
+"If [code]true[/code], the model's vertex colors are processed as sRGB mode."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:373
+msgid "If [code]true[/code], the vertex color is used as albedo color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:378
+msgid "Texture specifying per-pixel color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:381
+msgid "Texture specifying per-pixel metallic value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:384
+msgid "Texture specifying per-pixel roughness value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:387
+msgid "Texture specifying per-pixel emission color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:390
+msgid "Texture specifying per-pixel normal vector."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:393
+msgid "Texture specifying per-pixel rim value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:396
+msgid "Texture specifying per-pixel clearcoat value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:399
+msgid ""
+"Texture specifying per-pixel flowmap direction for use with [member "
+"anisotropy]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:402
+msgid "Texture specifying per-pixel ambient occlusion value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:405
+msgid "Texture specifying per-pixel height."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:408
+msgid "Texture specifying per-pixel subsurface scattering."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:411
+msgid "Texture specifying per-pixel transmission color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:414
+msgid "Texture specifying per-pixel refraction strength."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:417
+msgid "Texture specifying per-pixel detail mask blending value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:420
+msgid "Texture specifying per-pixel detail color."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:423
+msgid "Texture specifying per-pixel detail normal."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:428
+msgid "Represents the size of the [enum TextureParam] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:431
+msgid ""
+"The texture filter reads from the nearest pixel only. The simplest and "
+"fastest method of filtering, but the texture will look pixelized."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:434 doc/classes/CanvasItem.xml:665
+msgid ""
+"The texture filter blends between the nearest four pixels. Use this for most "
+"cases where you want to avoid a pixelated style."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:445 doc/classes/CanvasItem.xml:676
+msgid "Represents the size of the [enum TextureFilter] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:448
+msgid "Use [code]UV[/code] with the detail texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:451
+msgid "Use [code]UV2[/code] with the detail texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:454
+msgid "The material will not use transparency."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:457
+msgid "The material will use the texture's alpha values for transparency."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:464
+msgid "Represents the size of the [enum Transparency] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:467
+msgid "The object will not receive shadows."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:470
+msgid ""
+"The object will be shaded per pixel. Useful for realistic shading effect."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:473
+msgid ""
+"The object will be shaded per vertex. Useful when you want cheaper shaders "
+"and do not care about visual quality."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:476
+msgid "Represents the size of the [enum ShadingMode] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:479
+msgid "Constant for setting [member emission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:482
+msgid "Constant for setting [member normal_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:485
+msgid "Constant for setting [member rim_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:488
+msgid "Constant for setting [member clearcoat_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:491
+msgid "Constant for setting [member anisotropy_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:494
+msgid "Constant for setting [member ao_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:499
+msgid "Constant for setting [member subsurf_scatter_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:502
+msgid "Constant for setting [member transmission_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:505
+msgid "Constant for setting [member refraction_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:508
+msgid "Constant for setting [member detail_enabled]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:511 doc/classes/EditorFeatureProfile.xml:148
+msgid "Represents the size of the [enum Feature] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:514
+msgid ""
+"Default blend mode. The color of the object is blended over the background "
+"based on the object's alpha value."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:517
+msgid "The color of the object is added to the background."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:520
+msgid "The color of the object is subtracted from the background."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:523
+msgid "The color of the object is multiplied by the background."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:526
+msgid "Default depth draw mode. Depth is drawn only for opaque objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:529
+msgid "Depth draw is calculated for both opaque and transparent objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:532
+msgid "No depth draw."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:535
+msgid "Default cull mode. The back of the object is culled when not visible."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:538
+msgid "The front of the object is culled when not visible."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:541
+msgid "No culling is performed."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:544
+msgid ""
+"Disables the depth test, so this object is drawn on top of all others. "
+"However, objects drawn after it in the draw order may cover it."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:547
+msgid "Set [code]ALBEDO[/code] to the per-vertex color specified in the mesh."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:550
+msgid ""
+"Vertex color is in sRGB space and needs to be converted to linear. Only "
+"applies in the Vulkan renderer."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:553
+msgid ""
+"Uses point size to alter the size of primitive points. Also changes the "
+"albedo texture lookup to use [code]POINT_COORD[/code] instead of [code]UV[/"
+"code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:556
+msgid ""
+"Object is scaled by depth so that it always appears the same size on screen."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:559
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:562 doc/classes/BaseMaterial3D.xml:568
+msgid ""
+"Use triplanar texture lookup for all texture lookups that would normally use "
+"[code]UV[/code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:565 doc/classes/BaseMaterial3D.xml:571
+msgid ""
+"Use triplanar texture lookup for all texture lookups that would normally use "
+"[code]UV2[/code]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:574
+msgid ""
+"Use [code]UV2[/code] coordinates to look up from the [member ao_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:577
+msgid ""
+"Use [code]UV2[/code] coordinates to look up from the [member "
+"emission_texture]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:580
+msgid "Forces the shader to convert albedo from sRGB space to linear space."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:583
+msgid "Disables receiving shadows from other objects."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:586
+msgid "Disables receiving ambient light."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:589
+msgid "Enables the shadow to opacity feature."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:594
+msgid ""
+"Invert values read from a depth texture to convert them to height values "
+"(heightmap)."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:599 doc/classes/CPUParticles2D.xml:355
+#: doc/classes/CPUParticles3D.xml:364 doc/classes/GeometryInstance3D.xml:100
+#: doc/classes/ParticlesMaterial.xml:315
+msgid "Represents the size of the [enum Flags] enum."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:602
+msgid "Default diffuse scattering algorithm."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:605
+msgid "Diffuse scattering ignores roughness."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:608
+msgid "Extends Lambert to cover more than 90 degrees when roughness increases."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:611
+msgid "Attempts to use roughness to emulate microsurfacing."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:614
+msgid "Uses a hard cut for lighting, with smoothing affected by roughness."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:617
+msgid "Default specular blob."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:620 doc/classes/BaseMaterial3D.xml:623
+msgid "Older specular algorithm, included for compatibility."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:626
+msgid "Toon blob which changes size based on roughness."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:629
+msgid "No specular blob."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:632
+msgid "Billboard mode is disabled."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:635
+msgid "The object's Z axis will always face the camera."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:638
+msgid "The object's X axis will always face the camera."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:641
+msgid ""
+"Used for particle systems when assigned to [GPUParticles3D] and "
+"[CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties.\n"
+"The [member ParticlesMaterial.anim_speed] or [member CPUParticles3D."
+"anim_speed] should also be set to a positive value for the animation to play."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:645
+msgid "Used to read from the red channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:648
+msgid "Used to read from the green channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:651
+msgid "Used to read from the blue channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:654
+msgid "Used to read from the alpha channel of a texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:657
+msgid "Currently unused."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:660
+msgid "Adds the emission color to the color from the emission texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:663
+msgid "Multiplies the emission color by the color from the emission texture."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:666
+msgid "Do not use distance fade."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:669
+msgid ""
+"Smoothly fades the object out based on each pixel's distance from the camera "
+"using the alpha channel."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:672
+msgid ""
+"Smoothly fades the object out based on each pixel's distance from the camera "
+"using a dither approach. Dithering discards pixels based on a set pattern to "
+"smoothly fade without enabling transparency. On certain hardware this can be "
+"faster than [constant DISTANCE_FADE_PIXEL_ALPHA]."
+msgstr ""
+
+#: doc/classes/BaseMaterial3D.xml:675
+msgid ""
+"Smoothly fades the object out based on the object's distance from the camera "
+"using a dither approach. Dithering discards pixels based on a set pattern to "
+"smoothly fade without enabling transparency. On certain hardware this can be "
+"faster than [constant DISTANCE_FADE_PIXEL_ALPHA]."
+msgstr ""
+
+#: doc/classes/Basis.xml:4
+msgid "3×3 matrix datatype."
+msgstr ""
+
+#: doc/classes/Basis.xml:7
+msgid ""
+"3×3 matrix used for 3D rotation and scale. Contains 3 vector fields X, Y and "
+"Z as its columns, which can be interpreted as the local basis vectors of a "
+"transformation. Can also be accessed as array of 3D vectors. These vectors "
+"are orthogonal to each other, but are not necessarily normalized (due to "
+"scaling). Almost always used as an orthogonal basis for a [Transform].\n"
+"For such use, it is composed of a scaling and a rotation matrix, in that "
+"order (M = R.S)."
+msgstr ""
+
+#: doc/classes/Basis.xml:11 doc/classes/Transform.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html"
+msgstr ""
+
+#: doc/classes/Basis.xml:20
+msgid "Create a rotation matrix from the given quaternion."
+msgstr ""
+
+#: doc/classes/Basis.xml:29
+msgid ""
+"Create a rotation matrix (in the YXZ convention: first Z, then X, and Y "
+"last) from the specified Euler angles, given in the vector format as (X "
+"angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Basis.xml:40
+msgid ""
+"Create a rotation matrix which rotates around the given axis by the "
+"specified angle, in radians. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:53
+msgid "Create a matrix from 3 axis vectors."
+msgstr ""
+
+#: doc/classes/Basis.xml:60
+msgid "Returns the determinant of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:67
+msgid ""
+"Returns the basis's rotation in the form of Euler angles (in the YXZ "
+"convention: first Z, then X, and Y last). The returned vector contains the "
+"rotation angles in the format (X angle, Y angle, Z angle). See [method "
+"get_rotation_quat] if you need a quaternion instead."
+msgstr ""
+
+#: doc/classes/Basis.xml:74
+msgid ""
+"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 grid map editor. For "
+"further details, refer to the Godot source code."
+msgstr ""
+
+#: doc/classes/Basis.xml:81
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Basis.xml:88
+msgid ""
+"Assuming that the matrix is the combination of a rotation and scaling, "
+"return the absolute value of scaling factors along each axis."
+msgstr ""
+
+#: doc/classes/Basis.xml:95 doc/classes/Transform2D.xml:49
+msgid "Returns the inverse of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:106
+msgid ""
+"Returns [code]true[/code] if this basis and [code]b[/code] are approximately "
+"equal, by calling [code]is_equal_approx[/code] on each component."
+msgstr ""
+
+#: doc/classes/Basis.xml:113
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Basis.xml:124
+msgid ""
+"Introduce an additional rotation around the given axis by phi (radians). The "
+"axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:133
+msgid ""
+"Introduce an additional scaling specified by the given 3D scaling factor."
+msgstr ""
+
+#: doc/classes/Basis.xml:144
+msgid ""
+"Assuming that the matrix is a proper rotation matrix, slerp performs a "
+"spherical-linear interpolation with another rotation matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:153
+msgid "Transposed dot product with the X axis of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:162
+msgid "Transposed dot product with the Y axis of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:171
+msgid "Transposed dot product with the Z axis of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:178
+msgid "Returns the transposed version of the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:187
+msgid "Returns a vector transformed (multiplied) by the matrix."
+msgstr ""
+
+#: doc/classes/Basis.xml:196
+msgid ""
+"Returns a vector transformed (multiplied) by the transposed matrix.\n"
+"[b]Note:[/b] This results in a multiplication by the inverse of the matrix "
+"only if it represents a rotation-reflection."
+msgstr ""
+
+#: doc/classes/Basis.xml:203
+msgid "The basis matrix's X vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:206
+msgid "The basis matrix's Y vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:209
+msgid "The basis matrix's Z vector."
+msgstr ""
+
+#: doc/classes/Basis.xml:214
+msgid ""
+"The identity basis. This is identical to calling [code]Basis()[/code] "
+"without any parameters. This constant can be used to make your code clearer."
+msgstr ""
+
+#: doc/classes/Basis.xml:217
+msgid ""
+"The basis that will flip something along the X axis when used in a "
+"transformation."
+msgstr ""
+
+#: doc/classes/Basis.xml:220
+msgid ""
+"The basis that will flip something along the Y axis when used in a "
+"transformation."
+msgstr ""
+
+#: doc/classes/Basis.xml:223
+msgid ""
+"The basis that will flip something along the Z axis when used in a "
+"transformation."
+msgstr ""
+
+#: doc/classes/BitMap.xml:4
+msgid "Boolean matrix."
+msgstr ""
+
+#: doc/classes/BitMap.xml:7
+msgid ""
+"A two-dimensional array of boolean values, can be used to efficiently store "
+"a binary matrix (every matrix element takes only one bit) and query the "
+"values using natural cartesian coordinates."
+msgstr ""
+
+#: doc/classes/BitMap.xml:18
+msgid ""
+"Creates a bitmap with the specified size, filled with [code]false[/code]."
+msgstr ""
+
+#: doc/classes/BitMap.xml:29
+msgid ""
+"Creates a bitmap that matches the given image dimensions, every element of "
+"the bitmap is set to [code]false[/code] if the alpha value of the image at "
+"that position is equal to [code]threshold[/code] or less, and [code]true[/"
+"code] in other case."
+msgstr ""
+
+#: doc/classes/BitMap.xml:38
+msgid "Returns bitmap's value at the specified position."
+msgstr ""
+
+#: doc/classes/BitMap.xml:45
+msgid "Returns bitmap's dimensions."
+msgstr ""
+
+#: doc/classes/BitMap.xml:52
+msgid ""
+"Returns the amount of bitmap elements that are set to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/BitMap.xml:83
+msgid ""
+"Sets the bitmap's element at the specified position, to the specified value."
+msgstr ""
+
+#: doc/classes/BitMap.xml:94
+msgid "Sets a rectangular portion of the bitmap to the specified value."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:4
+msgid ""
+"Renders text using fonts under the [url=https://www.angelcode.com/products/"
+"bmfont/]BMFont[/url] format.\n"
+"Handles files with the [code].fnt[/code] extension."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:8
+msgid ""
+"Renders text using [code]*.fnt[/code] fonts containing texture atlases. "
+"Supports distance fields. For using vector font files like TTF directly, see "
+"[DynamicFont]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:27
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:40
+msgid ""
+"Adds a kerning pair to the [BitmapFont] as a difference. Kerning pairs are "
+"special cases where a typeface advance is determined by the next character."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:49
+msgid "Adds a texture to the [BitmapFont]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:56
+msgid "Clears all the font data and settings."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:65
+msgid ""
+"Creates a BitmapFont from the [code]*.fnt[/code] file at [code]path[/code]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:76
+msgid ""
+"Returns the size of a character, optionally taking kerning into account if "
+"the next character is provided."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:87
+msgid "Returns a kerning pair as a difference."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:96
+msgid "Returns the font atlas texture at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:103
+msgid "Returns the number of textures in the BitmapFont atlas."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:109
+msgid "Ascent (number of pixels above the baseline)."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:112
+msgid "If [code]true[/code], distance field hint is enabled."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:115
+msgid "The fallback font."
+msgstr ""
+
+#: doc/classes/BitmapFont.xml:118
+msgid "Total font height (ascent plus descent) in pixels."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:4
+msgid "Joint used with [Skeleton2D] to control and animate other nodes."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:7
+msgid ""
+"Use a hierarchy of [code]Bone2D[/code] bound to a [Skeleton2D] to control, "
+"and animate other [Node2D] nodes.\n"
+"You can use [code]Bone2D[/code] and [code]Skeleton2D[/code] nodes to animate "
+"2D meshes created with the Polygon 2D UV editor.\n"
+"Each bone has a [member rest] transform that you can reset to with [method "
+"apply_rest]. These rest poses are relative to the bone's parent.\n"
+"If in the editor, you can set the rest pose of an entire skeleton using a "
+"menu option, from the code, you need to iterate over the bones to set their "
+"individual rest poses."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:19
+msgid "Stores the node's current transforms in [member rest]."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:26
+msgid ""
+"Returns the node's index as part of the entire skeleton. See [Skeleton2D]."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:33
+msgid ""
+"Returns the node's [member rest] [code]Transform2D[/code] if it doesn't have "
+"a parent, or its rest pose relative to its parent."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:39
+msgid ""
+"Length of the bone's representation drawn in the editor's viewport in pixels."
+msgstr ""
+
+#: doc/classes/Bone2D.xml:42
+msgid ""
+"Rest transform of the bone. You can reset the node's transforms to this "
+"value using [method apply_rest]."
+msgstr ""
+
+#: doc/classes/BoneAttachment3D.xml:4
+msgid "A node that will attach to a bone."
+msgstr ""
+
+#: doc/classes/BoneAttachment3D.xml:7
+msgid ""
+"This node must be the child of a [Skeleton3D] node. You can then select a "
+"bone for this node to attach to. The BoneAttachment3D node will copy the "
+"transform of the selected bone."
+msgstr ""
+
+#: doc/classes/BoneAttachment3D.xml:15
+msgid "The name of the attached bone."
+msgstr ""
+
+#: doc/classes/bool.xml:4
+msgid "Boolean built-in type."
+msgstr ""
+
+#: doc/classes/bool.xml:7
+msgid ""
+"Boolean is a built-in type. It can represent any data type that is either a "
+"true or false value. You can think of it as an switch with on or off (1 or "
+"0) setting. It's often used as part of programming logic in condition "
+"statements like [code]if[/code] statements.\n"
+"[b]Note:[/b] In a code below [code]if can_shoot[/code] is equivalent of "
+"[code]if can_shoot == true[/code]. It is good practice to follow the natural "
+"spoken language structure when possible. Use [code]if can_shoot[/code] "
+"rather than [code]if can_shoot == true[/code] and use [code]if not "
+"can_shoot[/code] rather than [code]if can_shoot == false[/code].\n"
+"[codeblock]\n"
+"var can_shoot = true\n"
+"\n"
+"func shoot():\n"
+" if can_shoot:\n"
+" # Perform shooting actions here.\n"
+"[/codeblock]\n"
+"The following code will only create a bullet if both conditions are met: "
+"action \"shoot\" is pressed and if [code]can_shoot[/code] is [code]true[/"
+"code].\n"
+"[b]Note:[/b] [code]Input.is_action_pressed(\"shoot\")[/code] is also a "
+"boolean that is [code]true[/code] when \"shoot\" is pressed and [code]false[/"
+"code] when \"shoot\" isn't pressed.\n"
+"[codeblock]\n"
+"var can_shoot = true\n"
+"\n"
+"func shoot():\n"
+" if can_shoot and Input.is_action_pressed(\"shoot\"):\n"
+" create_bullet()\n"
+"[/codeblock]\n"
+"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.\n"
+"[codeblock]\n"
+"var can_shoot = true\n"
+"onready var cool_down = $CoolDownTimer\n"
+"\n"
+"func shoot():\n"
+" if can_shoot and Input.is_action_pressed(\"shoot\"):\n"
+" create_bullet()\n"
+" can_shoot = false\n"
+" cool_down.start()\n"
+"\n"
+"func _on_CoolDownTimer_timeout():\n"
+" can_shoot = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/bool.xml:49
+msgid ""
+"Cast an [int] value to a boolean value, this method will return [code]true[/"
+"code] if called with an integer value different to 0 and [code]false[/code] "
+"in other case."
+msgstr ""
+
+#: doc/classes/bool.xml:58
+msgid ""
+"Cast a [float] value to a boolean value, this method will return [code]true[/"
+"code] if called with a floating-point value different to 0 and [code]false[/"
+"code] in other case."
+msgstr ""
+
+#: doc/classes/bool.xml:67
+msgid ""
+"Cast a [String] value to a boolean value, this method will return "
+"[code]true[/code] if called with a non-empty string and [code]false[/code] "
+"in other case. Examples: [code]bool(\"False\")[/code] returns [code]true[/"
+"code], [code]bool(\"\")[/code] returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:4
+msgid "Base class for box containers."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:7
+msgid ""
+"Arranges child [Control] nodes vertically or horizontally, and rearranges "
+"them automatically when their minimum size changes."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:18
+msgid ""
+"Adds a [Control] node to the box as a spacer. If [code]begin[/code] is "
+"[code]true[/code], it will insert the [Control] node in front of all other "
+"children."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:24
+msgid ""
+"The alignment of the container's children (must be one of [constant "
+"ALIGN_BEGIN], [constant ALIGN_CENTER], or [constant ALIGN_END])."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:29
+msgid "Aligns children with the beginning of the container."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:32
+msgid "Aligns children with the center of the container."
+msgstr ""
+
+#: doc/classes/BoxContainer.xml:35
+msgid "Aligns children with the end of the container."
+msgstr ""
+
+#: doc/classes/BoxShape3D.xml:4
+msgid "Box shape resource."
+msgstr ""
+
+#: doc/classes/BoxShape3D.xml:7
+msgid "3D box shape that can be a child of a [PhysicsBody3D] or [Area3D]."
+msgstr ""
+
+#: doc/classes/BoxShape3D.xml:15
+msgid ""
+"The box's half extents. The width, height and depth of this shape is twice "
+"the half extents."
+msgstr ""
+
+#: doc/classes/Button.xml:4
+msgid "Standard themed Button."
+msgstr ""
+
+#: doc/classes/Button.xml:7
+msgid ""
+"Button is the standard themed button. It can contain text and an icon, and "
+"will display them according to the current [Theme]."
+msgstr ""
+
+#: doc/classes/Button.xml:15
+msgid ""
+"Text alignment policy for the button's text, use one of the [enum TextAlign] "
+"constants."
+msgstr ""
+
+#: doc/classes/Button.xml:18
+msgid ""
+"When this property is enabled, text that is too large to fit the button is "
+"clipped, when disabled the Button will always be wide enough to hold the "
+"text."
+msgstr ""
+
+#: doc/classes/Button.xml:21
+msgid ""
+"When enabled, the button's icon will expand/shrink to fit the button's size "
+"while keeping its aspect."
+msgstr ""
+
+#: doc/classes/Button.xml:24
+msgid "Flat buttons don't display decoration."
+msgstr ""
+
+#: doc/classes/Button.xml:27
+msgid ""
+"Button's icon, if text is present the icon will be placed before the text."
+msgstr ""
+
+#: doc/classes/Button.xml:30 doc/classes/LinkButton.xml:18
+msgid "The button's text that will be displayed inside the button's area."
+msgstr ""
+
+#: doc/classes/Button.xml:35
+msgid "Align the text to the left."
+msgstr ""
+
+#: doc/classes/Button.xml:38
+msgid "Align the text to the center."
+msgstr ""
+
+#: doc/classes/Button.xml:41
+msgid "Align the text to the right."
+msgstr ""
+
+#: doc/classes/Button.xml:46
+msgid "[StyleBox] used when the [Button] is disabled."
+msgstr ""
+
+#: doc/classes/Button.xml:49
+msgid ""
+"[StyleBox] used when the [Button] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/Button.xml:52
+msgid "[Font] of the [Button]'s text."
+msgstr ""
+
+#: doc/classes/Button.xml:55
+msgid "Default text [Color] of the [Button]."
+msgstr ""
+
+#: doc/classes/Button.xml:58
+msgid "Text [Color] used when the [Button] is disabled."
+msgstr ""
+
+#: doc/classes/Button.xml:61
+msgid "Text [Color] used when the [Button] is being hovered."
+msgstr ""
+
+#: doc/classes/Button.xml:64
+msgid "Text [Color] used when the [Button] is being pressed."
+msgstr ""
+
+#: doc/classes/Button.xml:67
+msgid "[StyleBox] used when the [Button] is being hovered."
+msgstr ""
+
+#: doc/classes/Button.xml:70
+msgid "The horizontal space between [Button]'s icon and text."
+msgstr ""
+
+#: doc/classes/Button.xml:73
+msgid "Default [StyleBox] for the [Button]."
+msgstr ""
+
+#: doc/classes/Button.xml:76
+msgid "[StyleBox] used when the [Button] is being pressed."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:4
+msgid "Group of Buttons."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:7
+msgid ""
+"Group of [Button]. All direct and indirect children buttons become radios. "
+"Only one allows being pressed.\n"
+"[member BaseButton.toggle_mode] should be [code]true[/code]."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:17
+msgid ""
+"Returns an [Array] of [Button]s who have this as their [ButtonGroup] (see "
+"[member BaseButton.group])."
+msgstr ""
+
+#: doc/classes/ButtonGroup.xml:24
+msgid "Returns the current pressed button."
+msgstr ""
+
+#: doc/classes/Callable.xml:4
+msgid "An object representing a method in a certain object that can be called."
+msgstr ""
+
+#: doc/classes/Callable.xml:7
+msgid ""
+"[Callable] is a first class object which can be held in variables and passed "
+"to functions. It represents a given method in an [Object], and is typically "
+"used for signal callbacks.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var callable = Callable(self, \"print_args\")\n"
+"func print_args(arg1, arg2, arg3 = \"\"):\n"
+" prints(arg1, arg2, arg3)\n"
+"func test():\n"
+" callable.call(\"hello\", \"world\") # Prints \"hello world\".\n"
+" callable.call(Vector2.UP, 42, callable) # Prints \"(0, -1) 42 Node(Node."
+"gd)::print_args\".\n"
+" callable.call(\"invalid\") # Invalid call, should have at least 2 "
+"arguments.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Callable.xml:30
+msgid ""
+"Creates a new [Callable] for the method called [code]method_name[/code] in "
+"the specified [code]object[/code]."
+msgstr ""
+
+#: doc/classes/Callable.xml:37
+msgid ""
+"Calls the method represented by this [Callable]. Arguments can be passed and "
+"should match the method's signature."
+msgstr ""
+
+#: doc/classes/Callable.xml:44
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Callable.xml:51
+msgid "Returns the name of the method represented by this [Callable]."
+msgstr ""
+
+#: doc/classes/Callable.xml:58
+msgid "Returns the object on which this [Callable] is called."
+msgstr ""
+
+#: doc/classes/Callable.xml:65
+msgid ""
+"Returns the ID of this [Callable]'s object (see [method Object."
+"get_instance_id])."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:4
+msgid "Camera node for 2D scenes."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:7
+msgid ""
+"Camera node for 2D scenes. It forces the screen (current layer) to scroll "
+"following this node. This makes it easier (and faster) to program scrollable "
+"scenes than manually changing the position of [CanvasItem]-based nodes.\n"
+"This node is intended to be a simple helper to get things going quickly and "
+"it may happen that more functionality is desired to change how the camera "
+"works. To make your own custom camera node, simply inherit from [Node2D] and "
+"change the transform of the canvas by calling get_viewport()."
+"set_canvas_transform(m) in [Viewport]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:17
+msgid "Aligns the camera to the tracked node."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:24
+msgid ""
+"Removes any [Camera2D] from the ancestor [Viewport]'s internal currently-"
+"assigned camera."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:31
+msgid "Forces the camera to update scroll immediately."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:38
+msgid "Returns the camera position."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:45
+msgid ""
+"Returns the location of the [Camera2D]'s screen-center, relative to the "
+"origin."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:54
+msgid ""
+"Returns the specified margin. See also [member drag_margin_bottom], [member "
+"drag_margin_top], [member drag_margin_left], and [member drag_margin_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:63
+msgid ""
+"Returns the specified camera limit. See also [member limit_bottom], [member "
+"limit_top], [member limit_left], and [member limit_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:70
+msgid ""
+"Make this the current 2D camera for the scene (viewport and layer), in case "
+"there are many cameras in the scene."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:77
+msgid ""
+"Sets the camera's position immediately to its current smoothing "
+"destination.\n"
+"This has no effect if smoothing is disabled."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:89
+msgid ""
+"Sets the specified margin. See also [member drag_margin_bottom], [member "
+"drag_margin_top], [member drag_margin_left], and [member drag_margin_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:100
+msgid ""
+"Sets the specified camera limit. See also [member limit_bottom], [member "
+"limit_top], [member limit_left], and [member limit_right]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:106
+msgid "The Camera2D's anchor point. See [enum AnchorMode] constants."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:109
+msgid ""
+"If [code]true[/code], the camera is the active camera for the current scene. "
+"Only one camera can be current, so setting a different camera [code]current[/"
+"code] will disable this one."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:112
+msgid ""
+"The custom [Viewport] node attached to the [Camera2D]. If [code]null[/code] "
+"or not a [Viewport], uses the default viewport instead."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:115
+msgid ""
+"Bottom margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:118
+msgid ""
+"If [code]true[/code], the camera only moves when reaching the horizontal "
+"drag margins. If [code]false[/code], the camera moves horizontally "
+"regardless of margins."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:121
+msgid ""
+"Left margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:124
+msgid ""
+"Right margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:127
+msgid ""
+"Top margin needed to drag the camera. A value of [code]1[/code] makes the "
+"camera move only when reaching the edge of the screen."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:130
+msgid ""
+"If [code]true[/code], the camera only moves when reaching the vertical drag "
+"margins. If [code]false[/code], the camera moves vertically regardless of "
+"margins."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:133
+msgid ""
+"If [code]true[/code], draws the camera's drag margin rectangle in the editor."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:136
+msgid ""
+"If [code]true[/code], draws the camera's limits rectangle in the editor."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:139
+msgid ""
+"If [code]true[/code], draws the camera's screen rectangle in the editor."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:142
+msgid ""
+"Bottom scroll limit in pixels. The camera stops moving when reaching this "
+"value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:145
+msgid ""
+"Left scroll limit in pixels. The camera stops moving when reaching this "
+"value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:148
+msgid ""
+"Right scroll limit in pixels. The camera stops moving when reaching this "
+"value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:151
+msgid ""
+"If [code]true[/code], the camera smoothly stops when reaches its limits."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:154
+msgid ""
+"Top scroll limit in pixels. The camera stops moving when reaching this value."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:157
+msgid ""
+"The camera's offset, useful for looking around or camera shake animations."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:160
+msgid ""
+"The horizontal offset of the camera, relative to the drag margins.\n"
+"[b]Note:[/b] Offset H is used only to force offset relative to margins. It's "
+"not updated in any way if drag margins are enabled and can be used to set "
+"initial offset."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:164
+msgid ""
+"The vertical offset of the camera, relative to the drag margins.\n"
+"[b]Note:[/b] Used the same as [member offset_h]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:168
+msgid "The camera's process callback. See [enum Camera2DProcessMode]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:171
+msgid "If [code]true[/code], the camera rotates with the target."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:174
+msgid ""
+"If [code]true[/code], the camera smoothly moves towards the target at "
+"[member smoothing_speed]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:177
+msgid ""
+"Speed in pixels per second of the camera's smoothing effect when [member "
+"smoothing_enabled] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:180
+msgid ""
+"The camera's zoom relative to the viewport. Values larger than "
+"[code]Vector2(1, 1)[/code] zoom out and smaller values zoom in. For an "
+"example, use [code]Vector2(0.5, 0.5)[/code] for a 2× zoom-in, and "
+"[code]Vector2(4, 4)[/code] for a 4× zoom-out."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:185
+msgid ""
+"The camera's position is fixed so that the top-left corner is always at the "
+"origin."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:188
+msgid ""
+"The camera's position takes into account vertical/horizontal offsets and the "
+"screen size."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:191 doc/classes/ClippedCamera3D.xml:104
+msgid "The camera updates with the [code]_physics_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Camera2D.xml:194 doc/classes/ClippedCamera3D.xml:107
+msgid "The camera updates with the [code]_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:4
+msgid "Camera node, displays from a point of view."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:7
+msgid ""
+"[Camera3D] is a special node that displays what is visible from its current "
+"location. Cameras register themselves in the nearest [Viewport] node (when "
+"ascending the tree). Only one camera can be active per viewport. If no "
+"viewport is available ascending the tree, the camera will register in the "
+"global viewport. In other words, a camera just provides 3D display "
+"capabilities to a [Viewport], and, without one, a scene registered in that "
+"[Viewport] (or higher viewports) can't be displayed."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:18
+msgid ""
+"If this is the current camera, remove it from being current. If "
+"[code]enable_next[/code] is [code]true[/code], request to make the next "
+"camera current, if any."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:25
+msgid "Returns the camera's RID from the [RenderingServer]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:32
+msgid ""
+"Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may "
+"provide different transforms than the [Node] transform."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:41
+msgid ""
+"Returns [code]true[/code] if the given [code]layer[/code] in the [member "
+"cull_mask] is enabled, [code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:48
+msgid ""
+"Returns the camera's frustum planes in world-space units as an array of "
+"[Plane]s in the following order: near, far, left, top, right, bottom. Not to "
+"be confused with [member frustum_offset]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:57
+msgid ""
+"Returns [code]true[/code] if the given position is behind the camera.\n"
+"[b]Note:[/b] A position which returns [code]false[/code] may still be "
+"outside the camera's field of view."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:65
+msgid ""
+"Makes this camera the current camera for the [Viewport] (see class "
+"description). If the camera node is outside the scene tree, it will attempt "
+"to become current once it's added."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:74
+msgid ""
+"Returns a normal vector from the screen point location directed along the "
+"camera. Orthogonal cameras are normalized. Perspective cameras account for "
+"perspective, screen width/height, etc."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:85
+msgid ""
+"Returns the 3D point in worldspace that maps to the given 2D coordinate in "
+"the [Viewport] rectangle on a plane that is the given [code]z_depth[/code] "
+"distance into the scene away from the camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:94
+msgid ""
+"Returns a normal vector in worldspace, that is the result of projecting a "
+"point on the [Viewport] rectangle by the camera projection. This is useful "
+"for casting rays in the form of (origin, normal) for object intersection or "
+"picking."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:103
+msgid ""
+"Returns a 3D position in worldspace, that is the result of projecting a "
+"point on the [Viewport] rectangle by the camera projection. This is useful "
+"for casting rays in the form of (origin, normal) for object intersection or "
+"picking."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:114
+msgid ""
+"Enables or disables the given [code]layer[/code] in the [member cull_mask]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:129
+msgid ""
+"Sets the camera projection to frustum mode (see [constant "
+"PROJECTION_FRUSTUM]), by specifying a [code]size[/code], an [code]offset[/"
+"code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in "
+"world-space units."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:142
+msgid ""
+"Sets the camera projection to orthogonal mode (see [constant "
+"PROJECTION_ORTHOGONAL]), by specifying a [code]size[/code], and the "
+"[code]z_near[/code] and [code]z_far[/code] clip planes in world-space units. "
+"(As a hint, 2D games often use this projection, with values specified in "
+"pixels.)"
+msgstr ""
+
+#: doc/classes/Camera3D.xml:155
+msgid ""
+"Sets the camera projection to perspective mode (see [constant "
+"PROJECTION_PERSPECTIVE]), by specifying a [code]fov[/code] (field of view) "
+"angle in degrees, and the [code]z_near[/code] and [code]z_far[/code] clip "
+"planes in world-space units."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:164
+msgid ""
+"Returns the 2D coordinate in the [Viewport] rectangle that maps to the given "
+"3D point in worldspace."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:170
+msgid ""
+"The culling mask that describes which 3D render layers are rendered by this "
+"camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:173
+msgid ""
+"If [code]true[/code], the ancestor [Viewport] is currently using this camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:176
+msgid ""
+"If not [constant DOPPLER_TRACKING_DISABLED], this camera will simulate the "
+"[url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/url] for "
+"objects changed in particular [code]_process[/code] methods. See [enum "
+"DopplerTracking] for possible values."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:181
+msgid "The [Environment] to use for this camera."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:184
+msgid ""
+"The distance to the far culling boundary for this camera relative to its "
+"local Z axis."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:187
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:190
+msgid ""
+"The camera's frustum offset. This can be changed from the default to create "
+"\"tilted frustum\" effects such as [url=https://zdoom.org/wiki/Y-shearing]Y-"
+"shearing[/url]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:193
+msgid "The horizontal (X) offset of the camera viewport."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:196
+msgid ""
+"The axis to lock during [member fov]/[member size] adjustments. Can be "
+"either [constant KEEP_WIDTH] or [constant KEEP_HEIGHT]."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:199
+msgid ""
+"The distance to the near culling boundary for this camera relative to its "
+"local Z axis."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:202
+msgid ""
+"The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, "
+"objects' Z distance from the camera's local space scales their perceived "
+"size."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:205
+msgid ""
+"The camera's size measured as 1/2 the width or height. Only applicable in "
+"orthogonal mode. Since [member keep_aspect] locks on axis, [code]size[/code] "
+"sets the other axis' size length."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:208
+msgid "The vertical (Y) offset of the camera viewport."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:213
+msgid ""
+"Perspective projection. Objects on the screen becomes smaller when they are "
+"far away."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:216
+msgid ""
+"Orthogonal projection, also known as orthographic projection. Objects remain "
+"the same size on the screen no matter how far away they are."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:219
+msgid ""
+"Frustum projection. This mode allows adjusting [member frustum_offset] to "
+"create \"tilted frustum\" effects."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:222
+msgid ""
+"Preserves the horizontal aspect ratio; also known as Vert- scaling. This is "
+"usually the best option for projects running in portrait mode, as taller "
+"aspect ratios will benefit from a wider vertical FOV."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:225
+msgid ""
+"Preserves the vertical aspect ratio; also known as Hor+ scaling. This is "
+"usually the best option for projects running in landscape mode, as wider "
+"aspect ratios will automatically benefit from a wider horizontal FOV."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:228
+msgid ""
+"Disables [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/"
+"url] simulation (default)."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:231
+msgid ""
+"Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/"
+"url] by tracking positions of objects that are changed in [code]_process[/"
+"code]. Changes in the relative velocity of this camera compared to those "
+"objects affect how Audio is perceived (changing the Audio's [code]pitch "
+"shift[/code])."
+msgstr ""
+
+#: doc/classes/Camera3D.xml:234
+msgid ""
+"Simulate [url=https://en.wikipedia.org/wiki/Doppler_effect]Doppler effect[/"
+"url] by tracking positions of objects that are changed in "
+"[code]_physics_process[/code]. Changes in the relative velocity of this "
+"camera compared to those objects affect how Audio is perceived (changing the "
+"Audio's [code]pitch shift[/code])."
+msgstr ""
+
+#: doc/classes/CameraFeed.xml:4
+msgid ""
+"A camera feed gives you access to a single physical camera attached to your "
+"device."
+msgstr ""
+
+#: doc/classes/CameraFeed.xml:7
+msgid ""
+"A camera feed gives you access to a single physical camera attached to your "
+"device. When enabled, Godot will start capturing frames from the camera "
+"which can then be used.\n"
+"[b]Note:[/b] Many cameras will return YCbCr images which are split into two "
+"textures and need to be combined in a shader. Godot does this automatically "
+"for you if you set the environment to show the camera image in the "
+"background."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:4
+msgid "Server keeping track of different cameras accessible in Godot."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:7
+msgid ""
+"The [CameraServer] keeps track of different cameras accessible in Godot. "
+"These are external cameras such as webcams or the cameras on your phone.\n"
+"It is notably used to provide AR modules with a video feed from the camera."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:19
+msgid "Adds a camera feed to the camera server."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:26
+msgid "Returns an array of [CameraFeed]s."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:35
+msgid "Returns the [CameraFeed] with this id."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:42
+msgid "Returns the number of [CameraFeed]s registered."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:51
+msgid "Removes a [CameraFeed]."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:60
+msgid "Emitted when a [CameraFeed] is added (e.g. webcam is plugged in)."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:67
+msgid "Emitted when a [CameraFeed] is removed (e.g. webcam is unplugged)."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:73
+msgid "The RGBA camera image."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:76
+msgid "The YCbCr camera image."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:79
+msgid "The Y component camera image."
+msgstr ""
+
+#: doc/classes/CameraServer.xml:82
+msgid "The CbCr component camera image."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:4
+msgid "Texture provided by a [CameraFeed]."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:7
+msgid ""
+"This texture gives access to the camera texture provided by a [CameraFeed].\n"
+"[b]Note:[/b] Many cameras supply YCbCr images which need to be converted in "
+"a shader."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:16
+msgid "The ID of the [CameraFeed] for which we want to display the image."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:19
+msgid ""
+"Convenience property that gives access to the active property of the "
+"[CameraFeed]."
+msgstr ""
+
+#: doc/classes/CameraTexture.xml:22
+msgid ""
+"Which image within the [CameraFeed] we want access to, important if the "
+"camera image is split in a Y and CbCr component."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:4
+msgid "Base class of anything 2D."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:7
+msgid ""
+"Base class of anything 2D. Canvas items are laid out in a tree; children "
+"inherit and extend their parent's transform. [CanvasItem] is extended by "
+"[Control] for anything GUI-related, and by [Node2D] for anything related to "
+"the 2D engine.\n"
+"Any [CanvasItem] can draw. For this, [method update] must be called, then "
+"[constant NOTIFICATION_DRAW] will be received on idle time to request "
+"redraw. Because of this, canvas items don't need to be redrawn on every "
+"frame, improving the performance significantly. Several functions for "
+"drawing on the [CanvasItem] are provided (see [code]draw_*[/code] "
+"functions). However, they can only be used inside the [method Object."
+"_notification], signal or [method _draw] virtual functions.\n"
+"Canvas items are drawn in tree order. By default, children are on top of "
+"their parents so a root [CanvasItem] will be drawn behind everything. This "
+"behavior can be changed on a per-item basis.\n"
+"A [CanvasItem] can also be hidden, which will also hide its children. It "
+"provides many ways to change parameters such as modulation (for itself and "
+"its children) and self modulation (only for itself), as well as its blend "
+"mode.\n"
+"Ultimately, a transform notification can be requested, which will notify the "
+"node that its global position changed in case the parent tree changed."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:14 doc/classes/CanvasLayer.xml:10
+#: doc/classes/InputEvent.xml:11 doc/classes/Viewport.xml:15
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html"
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:15 doc/classes/Control.xml:19
+#: doc/classes/Node2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html"
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:22
+msgid ""
+"Overridable function called by the engine (if defined) to draw the canvas "
+"item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:43
+msgid ""
+"Draws an arc between the given angles. The larger the value of "
+"[code]point_count[/code], the smoother the curve."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:60
+msgid ""
+"Draws a string character using a custom font. Returns the advance, depending "
+"on the character width and kerning with an optional next character."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:73
+msgid "Draws a colored circle."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:98
+msgid "Draws a colored polygon of any amount of points, convex or concave."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:113
+msgid "Draws a line from a 2D point to another, with a given color and width."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:138
+msgid ""
+"Draws a [Mesh] in 2D, using the provided texture. See [MeshInstance2D] for "
+"related documentation."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:151
+msgid "Draws multiple, parallel lines with a uniform [code]color[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:164
+msgid ""
+"Draws multiple, parallel lines with a uniform [code]width[/code] and segment-"
+"by-segment coloring. Colors assigned to line segments match by index between "
+"[code]points[/code] and [code]colors[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:185
+msgid ""
+"Draws a [MultiMesh] in 2D with the provided texture. See "
+"[MultiMeshInstance2D] for related documentation."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:210
+msgid "Draws a polygon of any amount of points, convex or concave."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:223
+msgid ""
+"Draws interconnected line segments with a uniform [code]color[/code] and "
+"[code]width[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:236
+msgid ""
+"Draws interconnected line segments with a uniform [code]width[/code] and "
+"segment-by-segment coloring. Colors assigned to line segments match by index "
+"between [code]points[/code] and [code]colors[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:263
+msgid ""
+"Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points "
+"for a triangle, and 4 points for a quad."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:278
+msgid ""
+"Draws a rectangle. If [code]filled[/code] is [code]true[/code], the "
+"rectangle will be filled with the [code]color[/code] specified. If "
+"[code]filled[/code] is [code]false[/code], the rectangle will be drawn as a "
+"stroke with the [code]color[/code] and [code]width[/code] specified.\n"
+"[b]Note:[/b] [code]width[/code] is only effective if [code]filled[/code] is "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:292
+msgid ""
+"Sets a custom transform for drawing via components. Anything drawn "
+"afterwards will be transformed by this."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:301
+msgid ""
+"Sets a custom transform for drawing via matrix. Anything drawn afterwards "
+"will be transformed by this."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:318
+msgid "Draws a string using a custom font."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:329
+msgid "Draws a styled rectangle."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:352
+msgid "Draws a texture at a given position."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:379
+msgid ""
+"Draws a textured rectangle at a given position, optionally modulated by a "
+"color. If [code]transpose[/code] is [code]true[/code], the texture will have "
+"its X and Y coordinates swapped."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:408
+msgid ""
+"Draws a textured rectangle region at a given position, optionally modulated "
+"by a color. If [code]transpose[/code] is [code]true[/code], the texture will "
+"have its X and Y coordinates swapped."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:415 doc/classes/Node3D.xml:18
+msgid ""
+"Forces the transform to update. Transform changes in physics are not instant "
+"for performance reasons. Transforms are accumulated and then set. Use this "
+"if you need an up-to-date transform when doing physics operations."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:422
+msgid "Returns the [RID] of the [World2D] canvas where this item is in."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:429
+msgid "Returns the canvas item RID used by [RenderingServer] for this item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:436
+msgid "Returns the transform matrix of this item's canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:443
+msgid "Returns the global position of the mouse."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:450
+msgid "Returns the global transform matrix of this item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:457
+msgid ""
+"Returns the global transform matrix of this item in relation to the canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:464
+msgid "Returns the mouse position relative to this item's position."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:471
+msgid "Returns the transform matrix of this item."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:478
+msgid "Returns the viewport's boundaries as a [Rect2]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:485
+msgid "Returns this item's transform in relation to the viewport."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:492
+msgid "Returns the [World2D] where this item is in."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:499
+msgid "Hide the [CanvasItem] if it's currently visible."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:506
+msgid ""
+"Returns [code]true[/code] if local transform notifications are communicated "
+"to children."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:513
+msgid ""
+"Returns [code]true[/code] if the node is set as top-level. See [method "
+"set_as_toplevel]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:520
+msgid ""
+"Returns [code]true[/code] if global transform notifications are communicated "
+"to children."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:527
+msgid ""
+"Returns [code]true[/code] if the node is present in the [SceneTree], its "
+"[member visible] property is [code]true[/code] and its inherited visibility "
+"is also [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:536
+msgid "Assigns [code]screen_point[/code] as this node's new local transform."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:545
+msgid ""
+"Transformations issued by [code]event[/code]'s inputs are applied in local "
+"space instead of global space."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:554
+msgid ""
+"If [code]enable[/code] is [code]true[/code], the node won't inherit its "
+"transform from parent canvas items."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:563
+msgid ""
+"If [code]enable[/code] is [code]true[/code], children will be updated with "
+"local transform data."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:572
+msgid ""
+"If [code]enable[/code] is [code]true[/code], children will be updated with "
+"global transform data."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:579
+msgid ""
+"Show the [CanvasItem] if it's currently hidden. For controls that inherit "
+"[Popup], the correct way to make them visible is to call one of the multiple "
+"[code]popup*()[/code] functions instead."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:586
+msgid ""
+"Queue the [CanvasItem] for update. [constant NOTIFICATION_DRAW] will be "
+"called on idle time to request redraw."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:592
+msgid ""
+"The rendering layers in which this [CanvasItem] responds to [Light2D] nodes."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:595
+msgid "The material applied to textures on this [CanvasItem]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:598
+msgid "The color applied to textures on this [CanvasItem]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:601
+msgid ""
+"The color applied to textures on this [CanvasItem]. This is not inherited by "
+"children [CanvasItem]s."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:604
+msgid "If [code]true[/code], the object draws behind its parent."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:607
+msgid "If [code]true[/code], the object draws on top of its parent."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:614
+msgid ""
+"If [code]true[/code], the parent [CanvasItem]'s [member material] property "
+"is used as this one's material."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:617
+msgid ""
+"If [code]true[/code], this [CanvasItem] is drawn. For controls that inherit "
+"[Popup], the correct way to make them visible is to call one of the multiple "
+"[code]popup*()[/code] functions instead."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:623
+msgid ""
+"Emitted when the [CanvasItem] must redraw. This can only be connected "
+"realtime, as deferred will not allow drawing."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:628
+msgid "Emitted when becoming hidden."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:633
+msgid "Emitted when the item rect has changed."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:638
+msgid "Emitted when the visibility (hidden/visible) changes."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:644
+msgid ""
+"The [CanvasItem]'s transform has changed. This notification is only received "
+"if enabled by [method set_notify_transform] or [method "
+"set_notify_local_transform]."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:647
+msgid "The [CanvasItem] is requested to draw."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:650
+msgid "The [CanvasItem]'s visibility has changed."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:653
+msgid "The [CanvasItem] has entered the canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:656
+msgid "The [CanvasItem] has exited the canvas."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:659 doc/classes/CanvasItem.xml:679
+msgid "The [CanvasItem] will inherit the filter from its parent."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:662
+msgid ""
+"The texture filter reads from the nearest pixel only. The simplest and "
+"fastest method of filtering. Useful for pixel art."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:682
+msgid "Texture will not repeat."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:685
+msgid "Texture will repeat normally."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:688
+msgid ""
+"Texture will repeat in a 2x2 tiled mode, where elements at even positions "
+"are mirrored."
+msgstr ""
+
+#: doc/classes/CanvasItem.xml:691
+msgid "Represents the size of the [enum TextureRepeat] enum."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:4
+msgid "A material for [CanvasItem]s."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:7
+msgid ""
+"[CanvasItemMaterial]s provide a means of modifying the textures associated "
+"with a CanvasItem. They specialize in describing blend and lighting "
+"behaviors for textures. Use a [ShaderMaterial] to more fully customize a "
+"material's interactions with a [CanvasItem]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:15
+msgid ""
+"The manner in which a material's rendering is applied to underlying textures."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:18
+msgid "The manner in which material reacts to lighting."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:21
+msgid ""
+"The number of columns in the spritesheet assigned as [Texture2D] for a "
+"[GPUParticles2D] or [CPUParticles2D].\n"
+"[b]Note:[/b] This property is only used and visible in the editor if [member "
+"particles_animation] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:25
+msgid ""
+"If [code]true[/code], the particles animation will loop.\n"
+"[b]Note:[/b] This property is only used and visible in the editor if [member "
+"particles_animation] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:29
+msgid ""
+"The number of rows in the spritesheet assigned as [Texture2D] for a "
+"[GPUParticles2D] or [CPUParticles2D].\n"
+"[b]Note:[/b] This property is only used and visible in the editor if [member "
+"particles_animation] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:33
+msgid ""
+"If [code]true[/code], enable spritesheet-based animation features when "
+"assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member "
+"ParticlesMaterial.anim_speed] or [member CPUParticles2D.anim_speed] should "
+"also be set to a positive value for the animation to play.\n"
+"This property (and other [code]particles_anim_*[/code] properties that "
+"depend on it) has no effect on other types of nodes."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:39
+msgid ""
+"Mix blending mode. Colors are assumed to be independent of the alpha "
+"(opacity) value."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:42
+msgid "Additive blending mode."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:45
+msgid "Subtractive blending mode."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:48
+msgid "Multiplicative blending mode."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:51
+msgid ""
+"Mix blending mode. Colors are assumed to be premultiplied by the alpha "
+"(opacity) value."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:54
+msgid ""
+"Render the material using both light and non-light sensitive material "
+"properties."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:57
+msgid "Render the material as if there were no light."
+msgstr ""
+
+#: doc/classes/CanvasItemMaterial.xml:60
+msgid "Render the material as if there were only light."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:4
+msgid "Canvas drawing layer."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:7
+msgid ""
+"Canvas drawing layer. [CanvasItem] nodes that are direct or indirect "
+"children of a [CanvasLayer] will be drawn in that layer. The layer is a "
+"numeric index that defines the draw order. The default 2D scene renders with "
+"index 0, so a [CanvasLayer] with index -1 will be drawn below, and one with "
+"index 1 will be drawn above. This is very useful for HUDs (in layer 1+ or "
+"above), or backgrounds (in layer -1 or below)."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/canvas_layers.html"
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:18
+msgid "Returns the RID of the canvas used by this layer."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:24
+msgid ""
+"The custom [Viewport] node assigned to the [CanvasLayer]. If [code]null[/"
+"code], uses the default viewport instead."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:27
+msgid ""
+"Sets the layer to follow the viewport in order to simulate a pseudo 3D "
+"effect."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:30
+msgid ""
+"Scales the layer when using [member follow_viewport_enable]. Layers moving "
+"into the foreground should have increasing scales, while layers moving into "
+"the background should have decreasing scales."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:33
+msgid "Layer index for draw order. Lower values are drawn first."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:36
+msgid "The layer's base offset."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:39
+msgid "The layer's rotation in radians."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:42
+msgid "The layer's rotation in degrees."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:45
+msgid "The layer's scale."
+msgstr ""
+
+#: doc/classes/CanvasLayer.xml:48
+msgid "The layer's transform."
+msgstr ""
+
+#: doc/classes/CanvasModulate.xml:4
+msgid "Tint the entire canvas."
+msgstr ""
+
+#: doc/classes/CanvasModulate.xml:7
+msgid ""
+"[CanvasModulate] tints the canvas elements using its assigned [member color]."
+msgstr ""
+
+#: doc/classes/CanvasModulate.xml:15
+msgid "The tint color to apply."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:4 doc/classes/CapsuleMesh.xml:7
+msgid "Class representing a capsule-shaped [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:15
+msgid "Height of the capsule mesh from the center point."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:18
+msgid "Number of radial segments on the capsule mesh."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:21
+msgid "Radius of the capsule mesh."
+msgstr ""
+
+#: doc/classes/CapsuleMesh.xml:24
+msgid "Number of rings along the height of the capsule."
+msgstr ""
+
+#: doc/classes/CapsuleShape2D.xml:4 doc/classes/CapsuleShape2D.xml:7
+msgid "Capsule shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/CapsuleShape2D.xml:15 doc/classes/CapsuleShape3D.xml:15
+msgid "The capsule's height."
+msgstr ""
+
+#: doc/classes/CapsuleShape2D.xml:18 doc/classes/CapsuleShape3D.xml:18
+msgid "The capsule's radius."
+msgstr ""
+
+#: doc/classes/CapsuleShape3D.xml:4 doc/classes/CapsuleShape3D.xml:7
+msgid "Capsule shape for collisions."
+msgstr ""
+
+#: doc/classes/CenterContainer.xml:4
+msgid "Keeps children controls centered."
+msgstr ""
+
+#: doc/classes/CenterContainer.xml:7
+msgid ""
+"CenterContainer keeps children controls centered. This container keeps all "
+"children to their minimum size, in the center."
+msgstr ""
+
+#: doc/classes/CenterContainer.xml:15
+msgid ""
+"If [code]true[/code], centers children relative to the [CenterContainer]'s "
+"top left corner."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:4
+msgid ""
+"Controls how an individual character will be displayed in a [RichTextEffect]."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:7
+msgid ""
+"By setting various properties on this object, you can control how individual "
+"characters will be displayed in a [RichTextEffect]."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:10 doc/classes/RichTextEffect.xml:16
+#: doc/classes/RichTextLabel.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel."
+"html"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:11 doc/classes/RichTextEffect.xml:17
+msgid ""
+"https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:17 doc/classes/CharFXTransform.xml:45
+msgid ""
+"The index of the current character (starting from 0). Setting this property "
+"won't affect drawing."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:20
+msgid ""
+"The Unicode codepoint the character will use. This only affects non-"
+"whitespace characters. [method @GDScript.ord] can be useful here. For "
+"example, the following will replace all characters with asterisks:\n"
+"[codeblock]\n"
+"# `char_fx` is the CharFXTransform parameter from `_process_custom_fx()`.\n"
+"# See the RichTextEffect documentation for details.\n"
+"char_fx.character = ord(\"*\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:28
+msgid "The color the character will be drawn with."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:31
+msgid ""
+"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].\n"
+"[b]Note:[/b] Time still passes while the [RichTextLabel] is hidden."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:35
+msgid ""
+"Contains the arguments passed in the opening BBCode tag. By default, "
+"arguments are strings; if their contents match a type such as [bool], [int] "
+"or [float], they will be converted automatically. Color codes in the form "
+"[code]#rrggbb[/code] or [code]#rgb[/code] will be converted to an opaque "
+"[Color]. String arguments may not contain spaces, even if they're quoted. If "
+"present, quotes will also be present in the final string.\n"
+"For example, the opening BBCode tag [code][example foo=hello bar=true baz=42 "
+"color=#ffffff][/code] will map to the following [Dictionary]:\n"
+"[codeblock]\n"
+"{\"foo\": \"hello\", \"bar\": true, \"baz\": 42, \"color\": Color(1, 1, 1, "
+"1)}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:42
+msgid "The position offset the character will be drawn with (in pixels)."
+msgstr ""
+
+#: doc/classes/CharFXTransform.xml:48
+msgid ""
+"If [code]true[/code], the character will be drawn. If [code]false[/code], "
+"the character will be hidden. Characters around hidden characters will "
+"reflow to take the space of hidden characters. If this is not desired, set "
+"their [member color] to [code]Color(1, 1, 1, 0)[/code] instead."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:4
+msgid "Binary choice user interface widget. See also [CheckButton]."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:7
+msgid ""
+"A checkbox allows the user to make a binary choice (choosing only one of two "
+"possible options). It's similar to [CheckButton] in functionality, but it "
+"has a different appearance. To follow established UX patterns, it's "
+"recommended to use CheckBox when toggling it has [b]no[/b] immediate effect "
+"on something. For instance, it should be used when toggling it will only do "
+"something once a confirmation button is pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:21
+msgid "The vertical offset used when rendering the check icons (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:24
+msgid "The check icon to display when the [CheckBox] is checked."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:27
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is disabled."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:30
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is focused."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:33
+msgid "The [Font] to use for the [CheckBox] text."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:36
+msgid "The [CheckBox] text's font color."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:39
+msgid "The [CheckBox] text's font color when it's disabled."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:42
+msgid "The [CheckBox] text's font color when it's hovered."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:45
+msgid "The [CheckBox] text's font color when it's hovered and pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:48
+msgid "The [CheckBox] text's font color when it's pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:51
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is hovered."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:54
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is hovered and "
+"pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:57
+msgid "The separation between the check icon and the text (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:60 doc/classes/CheckButton.xml:57
+msgid "The [StyleBox] to display as a background."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:63
+msgid ""
+"The [StyleBox] to display as a background when the [CheckBox] is pressed."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:66
+msgid ""
+"If the [CheckBox] is configured as a radio button, the icon to display when "
+"the [CheckBox] is checked."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:69
+msgid ""
+"If the [CheckBox] is configured as a radio button, the icon to display when "
+"the [CheckBox] is unchecked."
+msgstr ""
+
+#: doc/classes/CheckBox.xml:72
+msgid "The check icon to display when the [CheckBox] is unchecked."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:4
+msgid "Checkable button. See also [CheckBox]."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:7
+msgid ""
+"CheckButton is a toggle button displayed as a check field. It's similar to "
+"[CheckBox] in functionality, but it has a different appearance. To follow "
+"established UX patterns, it's recommended to use CheckButton when toggling "
+"it has an [b]immediate[/b] effect on something. For instance, it should be "
+"used if toggling it enables/disables a setting without requiring the user to "
+"press a confirmation button."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:21
+msgid "The vertical offset used when rendering the toggle icons (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:24
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:27
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is focused."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:30
+msgid "The [Font] to use for the [CheckButton] text."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:33
+msgid "The [CheckButton] text's font color."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:36
+msgid "The [CheckButton] text's font color when it's disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:39
+msgid "The [CheckButton] text's font color when it's hovered."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:42
+msgid "The [CheckButton] text's font color when it's hovered and pressed."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:45
+msgid "The [CheckButton] text's font color when it's pressed."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:48
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is hovered."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:51
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is hovered "
+"and pressed."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:54
+msgid "The separation between the toggle icon and the text (in pixels)."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:60
+msgid "The icon to display when the [CheckButton] is unchecked."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:63
+msgid "The icon to display when the [CheckButton] is unchecked and disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:66
+msgid "The icon to display when the [CheckButton] is checked."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:69
+msgid "The icon to display when the [CheckButton] is checked and disabled."
+msgstr ""
+
+#: doc/classes/CheckButton.xml:72
+msgid ""
+"The [StyleBox] to display as a background when the [CheckButton] is pressed."
+msgstr ""
+
+#: doc/classes/CircleShape2D.xml:4
+msgid "Circular shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/CircleShape2D.xml:7
+msgid ""
+"Circular shape for 2D collisions. This shape is useful for modeling balls or "
+"small characters and its collision detection with everything else is very "
+"fast."
+msgstr ""
+
+#: doc/classes/CircleShape2D.xml:15
+msgid "The circle's radius."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:4
+msgid "Class information repository."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:7
+msgid "Provides access to metadata stored for every available class."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:18
+msgid ""
+"Returns [code]true[/code] if you can instance objects from the specified "
+"[code]class[/code], [code]false[/code] in other case."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:27
+msgid "Returns whether the specified [code]class[/code] is available or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:36
+msgid ""
+"Returns a category associated with the class for use in documentation and "
+"the Asset Library. Debug mode required."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:47
+msgid ""
+"Returns the value of the integer constant [code]name[/code] of [code]class[/"
+"code] or its ancestry. Always returns 0 when the constant could not be found."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:58
+msgid ""
+"Returns an array with the names all the integer constants of [code]class[/"
+"code] or its ancestry."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:69
+msgid ""
+"Returns an array with all the methods of [code]class[/code] or its ancestry "
+"if [code]no_inheritance[/code] is [code]false[/code]. Every element of the "
+"array is a [Dictionary] with the following keys: [code]args[/code], "
+"[code]default_args[/code], [code]flags[/code], [code]id[/code], [code]name[/"
+"code], [code]return: (class_name, hint, hint_string, name, type, usage)[/"
+"code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:80
+msgid ""
+"Returns the value of [code]property[/code] of [code]class[/code] or its "
+"ancestry."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:91
+msgid ""
+"Returns an array with all the properties of [code]class[/code] or its "
+"ancestry if [code]no_inheritance[/code] is [code]false[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:102
+msgid ""
+"Returns the [code]signal[/code] data of [code]class[/code] or its ancestry. "
+"The returned value is a [Dictionary] with the following keys: [code]args[/"
+"code], [code]default_args[/code], [code]flags[/code], [code]id[/code], "
+"[code]name[/code], [code]return: (class_name, hint, hint_string, name, type, "
+"usage)[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:113
+msgid ""
+"Returns an array with all the signals of [code]class[/code] or its ancestry "
+"if [code]no_inheritance[/code] is [code]false[/code]. Every element of the "
+"array is a [Dictionary] as described in [method class_get_signal]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:124
+msgid ""
+"Returns whether [code]class[/code] or its ancestry has an integer constant "
+"called [code]name[/code] or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:137
+msgid ""
+"Returns whether [code]class[/code] (or its ancestry if [code]no_inheritance[/"
+"code] is [code]false[/code]) has a method called [code]method[/code] or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:148
+msgid ""
+"Returns whether [code]class[/code] or its ancestry has a signal called "
+"[code]signal[/code] or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:161
+msgid ""
+"Sets [code]property[/code] value of [code]class[/code] to [code]value[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:168
+msgid "Returns the names of all the classes available."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:177
+msgid ""
+"Returns the names of all the classes that directly or indirectly inherit "
+"from [code]class[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:186
+msgid "Returns the parent class of [code]class[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:195
+msgid "Creates an instance of [code]class[/code]."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:204
+msgid "Returns whether this [code]class[/code] is enabled or not."
+msgstr ""
+
+#: doc/classes/ClassDB.xml:215
+msgid ""
+"Returns whether [code]inherits[/code] is an ancestor of [code]class[/code] "
+"or not."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:4
+msgid "A [Camera3D] that includes collision."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:7
+msgid ""
+"This node extends [Camera3D] to add collisions with [Area3D] and/or "
+"[PhysicsBody3D] nodes. The camera cannot move through colliding objects."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:18
+msgid ""
+"Adds a collision exception so the camera does not collide with the specified "
+"node."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:27
+msgid ""
+"Adds a collision exception so the camera does not collide with the specified "
+"[RID]."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:34
+msgid "Removes all collision exceptions."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:41
+msgid "Returns the distance the camera has been offset due to a collision."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:50
+msgid ""
+"Returns [code]true[/code] if the specified bit index is on.\n"
+"[b]Note:[/b] Bit indices range from 0-19."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:60
+msgid "Removes a collision exception with the specified node."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:69
+msgid "Removes a collision exception with the specified [RID]."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:80
+msgid ""
+"Sets the specified bit index to the [code]value[/code].\n"
+"[b]Note:[/b] Bit indices range from 0-19."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:87
+msgid "If [code]true[/code], the camera stops on contact with [Area3D]s."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:90
+msgid ""
+"If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:93
+msgid ""
+"The camera's collision mask. Only objects in at least one collision layer "
+"matching the mask will be detected."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:96
+msgid ""
+"The camera's collision margin. The camera can't get closer than this "
+"distance to a colliding object."
+msgstr ""
+
+#: doc/classes/ClippedCamera3D.xml:99
+msgid "The camera's process callback. See [enum ProcessMode]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:4
+msgid "Base node for 2D collision objects."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:7
+msgid ""
+"CollisionObject2D is the base class for 2D physics objects. It can hold any "
+"number of 2D collision [Shape2D]s. Each shape must be assigned to a [i]shape "
+"owner[/i]. The CollisionObject2D can have any number of shape owners. Shape "
+"owners are not nodes and do not appear in the editor, but are accessible "
+"through code using the [code]shape_owner_*[/code] methods."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:22
+msgid ""
+"Accepts unhandled [InputEvent]s. Requires [member input_pickable] to be "
+"[code]true[/code]. [code]shape_idx[/code] is the child index of the clicked "
+"[Shape2D]. Connect to the [code]input_event[/code] signal to easily pick up "
+"these events."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:31 doc/classes/CollisionObject3D.xml:35
+msgid ""
+"Creates a new shape owner for the given object. Returns [code]owner_id[/"
+"code] of the new owner for future reference."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:38 doc/classes/CollisionObject3D.xml:42
+msgid "Returns the object's [RID]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:47
+msgid ""
+"Returns the [code]one_way_collision_margin[/code] of the shape owner "
+"identified by given [code]owner_id[/code]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:54 doc/classes/CollisionObject3D.xml:49
+msgid ""
+"Returns an [Array] of [code]owner_id[/code] identifiers. You can use these "
+"ids in other methods that take [code]owner_id[/code] as an argument."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:63 doc/classes/CollisionObject3D.xml:58
+msgid "If [code]true[/code], the shape owner and its shapes are disabled."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:72
+msgid ""
+"Returns [code]true[/code] if collisions for the shape owner originating from "
+"this [CollisionObject2D] will not be reported to collided with "
+"[CollisionObject2D]s."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:81 doc/classes/CollisionObject3D.xml:67
+msgid "Removes the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:90 doc/classes/CollisionObject3D.xml:76
+msgid "Returns the [code]owner_id[/code] of the given shape."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:101
+msgid "Adds a [Shape2D] to the shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:110 doc/classes/CollisionObject3D.xml:96
+msgid "Removes all shapes from the shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:119 doc/classes/CollisionObject3D.xml:105
+msgid "Returns the parent object of the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:130
+msgid "Returns the [Shape2D] with the given id from the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:139 doc/classes/CollisionObject3D.xml:125
+msgid "Returns the number of shapes the given shape owner contains."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:150
+msgid ""
+"Returns the child index of the [Shape2D] with the given id from the given "
+"shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:159
+msgid "Returns the shape owner's [Transform2D]."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:170 doc/classes/CollisionObject3D.xml:156
+msgid "Removes a shape from the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:181 doc/classes/CollisionObject3D.xml:167
+msgid "If [code]true[/code], disables the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:192
+msgid ""
+"If [code]enable[/code] is [code]true[/code], collisions for the shape owner "
+"originating from this [CollisionObject2D] will not be reported to collided "
+"with [CollisionObject2D]s."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:203
+msgid ""
+"Sets the [code]one_way_collision_margin[/code] of the shape owner identified "
+"by given [code]owner_id[/code] to [code]margin[/code] pixels."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:214
+msgid "Sets the [Transform2D] of the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:220
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:232
+msgid ""
+"Emitted when an input event occurs. Requires [member input_pickable] to be "
+"[code]true[/code] and at least one [code]collision_layer[/code] bit to be "
+"set. See [method _input_event] for details."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:237
+msgid ""
+"Emitted when the mouse pointer enters any of this object's shapes. Requires "
+"[member input_pickable] to be [code]true[/code] and at least one "
+"[code]collision_layer[/code] bit to be set."
+msgstr ""
+
+#: doc/classes/CollisionObject2D.xml:242
+msgid ""
+"Emitted when the mouse pointer exits all this object's shapes. Requires "
+"[member input_pickable] to be [code]true[/code] and at least one "
+"[code]collision_layer[/code] bit to be set."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:4
+msgid "Base node for collision objects."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:7
+msgid ""
+"CollisionObject3D is the base class for physics objects. It can hold any "
+"number of collision [Shape3D]s. Each shape must be assigned to a [i]shape "
+"owner[/i]. The CollisionObject3D can have any number of shape owners. Shape "
+"owners are not nodes and do not appear in the editor, but are accessible "
+"through code using the [code]shape_owner_*[/code] methods."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:26
+msgid ""
+"Accepts unhandled [InputEvent]s. [code]click_position[/code] is the clicked "
+"location in world space and [code]click_normal[/code] is the normal vector "
+"extending from the clicked surface of the [Shape3D] at [code]shape_idx[/"
+"code]. Connect to the [code]input_event[/code] signal to easily pick up "
+"these events."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:87
+msgid "Adds a [Shape3D] to the shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:116
+msgid "Returns the [Shape3D] with the given id from the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:136
+msgid ""
+"Returns the child index of the [Shape3D] with the given id from the given "
+"shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:145
+msgid "Returns the shape owner's [Transform]."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:178
+msgid "Sets the [Transform] of the given shape owner."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:184
+msgid ""
+"If [code]true[/code], the [CollisionObject3D] will continue to receive input "
+"events as the mouse is dragged across its shapes."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:187
+msgid ""
+"If [code]true[/code], the [CollisionObject3D]'s shapes will respond to "
+"[RayCast3D]s."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:203
+msgid ""
+"Emitted when [method _input_event] receives an event. See its description "
+"for details."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:208
+msgid "Emitted when the mouse pointer enters any of this object's shapes."
+msgstr ""
+
+#: doc/classes/CollisionObject3D.xml:213
+msgid "Emitted when the mouse pointer exits all this object's shapes."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:4
+msgid "Defines a 2D collision polygon."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:7
+msgid ""
+"Provides a 2D collision polygon to a [CollisionObject2D] parent. Polygons "
+"can be drawn in the editor or specified by a list of vertices."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:15
+msgid "Collision build mode. Use one of the [enum BuildMode] constants."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:18
+msgid "If [code]true[/code], no collisions will be detected."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:21
+msgid ""
+"If [code]true[/code], only edges that face up, relative to "
+"[CollisionPolygon2D]'s rotation, will collide with other objects."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:24
+msgid ""
+"The margin used for one-way collision (in pixels). Higher values will make "
+"the shape thicker, and work better for colliders that enter the polygon at a "
+"high velocity."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:27
+msgid ""
+"The polygon's list of vertices. The final point will be connected to the "
+"first. The returned value is a clone of the [PackedVector2Array], not a "
+"reference."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:32
+msgid "Collisions will include the polygon and its contained area."
+msgstr ""
+
+#: doc/classes/CollisionPolygon2D.xml:35
+msgid "Collisions will only include the polygon edges."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:4
+msgid "Editor-only class for defining a collision polygon in 3D space."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:7
+msgid ""
+"Allows editing a collision polygon's vertices on a selected plane. Can also "
+"set a depth perpendicular to that plane. This class is only available in the "
+"editor. It will not appear in the scene tree at run-time. Creates a "
+"[Shape3D] for gameplay. Properties modified during gameplay will have no "
+"effect."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:15
+msgid ""
+"Length that the resulting collision extends in either direction "
+"perpendicular to its polygon."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:18
+msgid "If [code]true[/code], no collision will be produced."
+msgstr ""
+
+#: doc/classes/CollisionPolygon3D.xml:21
+msgid ""
+"Array of vertices which define the polygon.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:4
+msgid "Node that represents collision shape data in 2D space."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:7
+msgid ""
+"Editor facility for creating and editing collision shapes in 2D space. You "
+"can use this node to represent all sorts of collision shapes, for example, "
+"add this to an [Area2D] to give it a detection shape, or add it to a "
+"[PhysicsBody2D] to create a solid object. [b]IMPORTANT[/b]: this is an "
+"Editor-only helper to create shapes, use [method CollisionObject2D."
+"shape_owner_get_shape] to get the actual shape."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:10 doc/classes/CollisionShape3D.xml:10
+#: doc/classes/PhysicsBody2D.xml:10 doc/classes/PhysicsBody3D.xml:10
+#: doc/classes/RigidBody3D.xml:13 doc/classes/Shape2D.xml:10
+#: doc/classes/Shape3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/"
+"physics_introduction.html"
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:16 doc/classes/CollisionShape3D.xml:32
+msgid "A disabled collision shape has no effect in the world."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:19
+msgid ""
+"Sets whether this collision shape should only detect collision on one side "
+"(top or bottom)."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:22
+msgid ""
+"The margin used for one-way collision (in pixels). Higher values will make "
+"the shape thicker, and work better for colliders that enter the shape at a "
+"high velocity."
+msgstr ""
+
+#: doc/classes/CollisionShape2D.xml:25 doc/classes/CollisionShape3D.xml:35
+msgid "The actual shape owned by this collision shape."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:4
+msgid "Node that represents collision shape data in 3D space."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:7
+msgid ""
+"Editor facility for creating and editing collision shapes in 3D space. You "
+"can use this node to represent all sorts of collision shapes, for example, "
+"add this to an [Area3D] to give it a detection shape, or add it to a "
+"[PhysicsBody3D] to create a solid object. [b]IMPORTANT[/b]: this is an "
+"Editor-only helper to create shapes, use [method CollisionObject3D."
+"shape_owner_get_shape] to get the actual shape."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:17
+msgid ""
+"Sets the collision shape's shape to the addition of all its convexed "
+"[MeshInstance3D] siblings geometry."
+msgstr ""
+
+#: doc/classes/CollisionShape3D.xml:26
+msgid ""
+"If this method exists within a script it will be called whenever the shape "
+"resource has been modified."
+msgstr ""
+
+#: doc/classes/Color.xml:4
+msgid "Color in RGBA format with some support for ARGB format."
+msgstr ""
+
+#: doc/classes/Color.xml:7
+msgid ""
+"A color is represented by red, green, and blue [code](r, g, b)[/code] "
+"components. Additionally, [code]a[/code] represents the alpha component, "
+"often used for transparency. Values are in floating-point and usually range "
+"from 0 to 1. Some properties (such as [member CanvasItem.modulate]) may "
+"accept values greater than 1.\n"
+"You can also create a color from standardized color names by using [method "
+"@GDScript.ColorN] or directly using the color constants defined here. The "
+"standardized color set is based on the [url=https://en.wikipedia.org/wiki/"
+"X11_color_names]X11 color names[/url]. \n"
+"If you want to supply values in a range of 0 to 255, you should use [method "
+"@GDScript.Color8]."
+msgstr ""
+
+#: doc/classes/Color.xml:20
+msgid ""
+"Constructs a color from an HTML hexadecimal color string in ARGB or RGB "
+"format. See also [method @GDScript.ColorN].\n"
+"[codeblock]\n"
+"# Each of the following creates the same color RGBA(178, 217, 10, 255).\n"
+"var c1 = Color(\"#ffb2d90a\") # ARGB format with \"#\".\n"
+"var c2 = Color(\"ffb2d90a\") # ARGB format.\n"
+"var c3 = Color(\"#b2d90a\") # RGB format with \"#\".\n"
+"var c4 = Color(\"b2d90a\") # RGB format.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:36
+msgid ""
+"Constructs a color from a 32-bit integer (each byte represents a component "
+"of the RGBA profile).\n"
+"[codeblock]\n"
+"var c = Color(274) # Equivalent to RGBA(0, 0, 1, 18)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:52
+msgid ""
+"Constructs a color from an RGB profile using values between 0 and 1. Alpha "
+"will always be 1.\n"
+"[codeblock]\n"
+"var c = Color(0.2, 1.0, 0.7) # Equivalent to RGBA(51, 255, 178, 255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:70
+msgid ""
+"Constructs a color from an RGBA profile using values between 0 and 1.\n"
+"[codeblock]\n"
+"var c = Color(0.2, 1.0, 0.7, 0.8) # Equivalent to RGBA(51, 255, 178, 204)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:82
+msgid ""
+"Returns a new color resulting from blending this color over another. If the "
+"color is opaque, the result is also opaque. The second color may have a "
+"range of alpha values.\n"
+"[codeblock]\n"
+"var bg = Color(0.0, 1.0, 0.0, 0.5) # Green with alpha of 50%\n"
+"var fg = Color(1.0, 0.0, 0.0, 0.5) # Red with alpha of 50%\n"
+"var blended_color = bg.blend(fg) # Brown with alpha of 75%\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:94
+msgid ""
+"Returns the most contrasting color.\n"
+"[codeblock]\n"
+"var c = Color(0.3, 0.4, 0.9)\n"
+"var contrasted_color = c.contrasted() # Equivalent to RGBA(204, 229, 102, "
+"255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:107
+msgid ""
+"Returns a new color resulting from making this color darker by the specified "
+"percentage (ratio from 0 to 1).\n"
+"[codeblock]\n"
+"var green = Color(0.0, 1.0, 0.0)\n"
+"var darkgreen = green.darkened(0.2) # 20% darker than regular green\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:126
+msgid ""
+"Constructs a color from an HSV profile. [code]h[/code], [code]s[/code], and "
+"[code]v[/code] are values between 0 and 1.\n"
+"[codeblock]\n"
+"var c = Color.from_hsv(0.58, 0.5, 0.79, 0.8) # Equivalent to HSV(210, 50, "
+"79, 0.8) or Color8(100, 151, 201, 0.8)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:136
+msgid ""
+"Returns the inverted color [code](1 - r, 1 - g, 1 - b, a)[/code].\n"
+"[codeblock]\n"
+"var c = Color(0.3, 0.4, 0.9)\n"
+"var inverted_color = c.inverted() # A color of an RGBA(178, 153, 26, 255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:149
+msgid ""
+"Returns [code]true[/code] if this color and [code]color[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Color.xml:158
+msgid ""
+"Returns a new color resulting from making this color lighter by the "
+"specified percentage (ratio from 0 to 1).\n"
+"[codeblock]\n"
+"var green = Color(0.0, 1.0, 0.0)\n"
+"var lightgreen = green.lightened(0.2) # 20% lighter than regular green\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:173
+msgid ""
+"Returns the linear interpolation with another color. The interpolation "
+"factor [code]t[/code] is between 0 and 1.\n"
+"[codeblock]\n"
+"var c1 = Color(1.0, 0.0, 0.0)\n"
+"var c2 = Color(0.0, 1.0, 0.0)\n"
+"var li_c = c1.linear_interpolate(c2, 0.5) # A color of an RGBA(128, 128, 0, "
+"255)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:185
+msgid ""
+"Returns the color's 32-bit integer in ABGR format (each byte represents a "
+"component of the ABGR profile). ABGR is the reversed version of the default "
+"format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_abgr32()) # Prints 4281565439\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:196
+msgid ""
+"Returns the color's 64-bit integer in ABGR format (each word represents a "
+"component of the ABGR profile). ABGR is the reversed version of the default "
+"format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_abgr64()) # Prints -225178692812801\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:207
+msgid ""
+"Returns the color's 32-bit integer in ARGB format (each byte represents a "
+"component of the ARGB profile). ARGB is more compatible with DirectX.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_argb32()) # Prints 4294934323\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:218
+msgid ""
+"Returns the color's 64-bit integer in ARGB format (each word represents a "
+"component of the ARGB profile). ARGB is more compatible with DirectX.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_argb64()) # Prints -2147470541\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:231
+msgid ""
+"Returns the color's HTML hexadecimal color string in ARGB format (ex: "
+"[code]ff34f822[/code]).\n"
+"Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from "
+"the hexadecimal string.\n"
+"[codeblock]\n"
+"var c = Color(1, 1, 1, 0.5)\n"
+"var s1 = c.to_html() # Returns \"7fffffff\"\n"
+"var s2 = c.to_html(false) # Returns \"ffffff\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:244
+msgid ""
+"Returns the color's 32-bit integer in RGBA format (each byte represents a "
+"component of the RGBA profile). RGBA is Godot's default format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_rgba32()) # Prints 4286526463\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:255
+msgid ""
+"Returns the color's 64-bit integer in RGBA format (each word represents a "
+"component of the RGBA profile). RGBA is Godot's default format.\n"
+"[codeblock]\n"
+"var c = Color(1, 0.5, 0.2)\n"
+"print(c.to_rgba64()) # Prints -140736629309441\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Color.xml:265
+msgid "Alpha value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:268
+msgid "Alpha value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:271
+msgid "Blue value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:274
+msgid "Blue value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:277
+msgid "Green value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:280
+msgid "Green value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:283
+msgid "HSV hue value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:286
+msgid "Red value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:289
+msgid "Red value (range 0 to 255)."
+msgstr ""
+
+#: doc/classes/Color.xml:292
+msgid "HSV saturation value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:295
+msgid "HSV value (range 0 to 1)."
+msgstr ""
+
+#: doc/classes/Color.xml:300
+msgid "Alice blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:303
+msgid "Antique white color."
+msgstr ""
+
+#: doc/classes/Color.xml:306
+msgid "Aqua color."
+msgstr ""
+
+#: doc/classes/Color.xml:309
+msgid "Aquamarine color."
+msgstr ""
+
+#: doc/classes/Color.xml:312
+msgid "Azure color."
+msgstr ""
+
+#: doc/classes/Color.xml:315
+msgid "Beige color."
+msgstr ""
+
+#: doc/classes/Color.xml:318
+msgid "Bisque color."
+msgstr ""
+
+#: doc/classes/Color.xml:321
+msgid "Black color."
+msgstr ""
+
+#: doc/classes/Color.xml:324
+msgid "Blanche almond color."
+msgstr ""
+
+#: doc/classes/Color.xml:327
+msgid "Blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:330
+msgid "Blue violet color."
+msgstr ""
+
+#: doc/classes/Color.xml:333
+msgid "Brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:336
+msgid "Burly wood color."
+msgstr ""
+
+#: doc/classes/Color.xml:339
+msgid "Cadet blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:342
+msgid "Chartreuse color."
+msgstr ""
+
+#: doc/classes/Color.xml:345
+msgid "Chocolate color."
+msgstr ""
+
+#: doc/classes/Color.xml:348
+msgid "Coral color."
+msgstr ""
+
+#: doc/classes/Color.xml:351
+msgid "Cornflower color."
+msgstr ""
+
+#: doc/classes/Color.xml:354
+msgid "Corn silk color."
+msgstr ""
+
+#: doc/classes/Color.xml:357
+msgid "Crimson color."
+msgstr ""
+
+#: doc/classes/Color.xml:360
+msgid "Cyan color."
+msgstr ""
+
+#: doc/classes/Color.xml:363
+msgid "Dark blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:366
+msgid "Dark cyan color."
+msgstr ""
+
+#: doc/classes/Color.xml:369
+msgid "Dark goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:372
+msgid "Dark gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:375
+msgid "Dark green color."
+msgstr ""
+
+#: doc/classes/Color.xml:378
+msgid "Dark khaki color."
+msgstr ""
+
+#: doc/classes/Color.xml:381
+msgid "Dark magenta color."
+msgstr ""
+
+#: doc/classes/Color.xml:384
+msgid "Dark olive green color."
+msgstr ""
+
+#: doc/classes/Color.xml:387
+msgid "Dark orange color."
+msgstr ""
+
+#: doc/classes/Color.xml:390
+msgid "Dark orchid color."
+msgstr ""
+
+#: doc/classes/Color.xml:393
+msgid "Dark red color."
+msgstr ""
+
+#: doc/classes/Color.xml:396
+msgid "Dark salmon color."
+msgstr ""
+
+#: doc/classes/Color.xml:399
+msgid "Dark sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:402
+msgid "Dark slate blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:405
+msgid "Dark slate gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:408
+msgid "Dark turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:411
+msgid "Dark violet color."
+msgstr ""
+
+#: doc/classes/Color.xml:414
+msgid "Deep pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:417
+msgid "Deep sky blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:420
+msgid "Dim gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:423
+msgid "Dodger blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:426
+msgid "Firebrick color."
+msgstr ""
+
+#: doc/classes/Color.xml:429
+msgid "Floral white color."
+msgstr ""
+
+#: doc/classes/Color.xml:432
+msgid "Forest green color."
+msgstr ""
+
+#: doc/classes/Color.xml:435
+msgid "Fuchsia color."
+msgstr ""
+
+#: doc/classes/Color.xml:438
+msgid "Gainsboro color."
+msgstr ""
+
+#: doc/classes/Color.xml:441
+msgid "Ghost white color."
+msgstr ""
+
+#: doc/classes/Color.xml:444
+msgid "Gold color."
+msgstr ""
+
+#: doc/classes/Color.xml:447
+msgid "Goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:450
+msgid "Gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:453
+msgid "Green color."
+msgstr ""
+
+#: doc/classes/Color.xml:456
+msgid "Green yellow color."
+msgstr ""
+
+#: doc/classes/Color.xml:459
+msgid "Honeydew color."
+msgstr ""
+
+#: doc/classes/Color.xml:462
+msgid "Hot pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:465
+msgid "Indian red color."
+msgstr ""
+
+#: doc/classes/Color.xml:468
+msgid "Indigo color."
+msgstr ""
+
+#: doc/classes/Color.xml:471
+msgid "Ivory color."
+msgstr ""
+
+#: doc/classes/Color.xml:474
+msgid "Khaki color."
+msgstr ""
+
+#: doc/classes/Color.xml:477
+msgid "Lavender color."
+msgstr ""
+
+#: doc/classes/Color.xml:480
+msgid "Lavender blush color."
+msgstr ""
+
+#: doc/classes/Color.xml:483
+msgid "Lawn green color."
+msgstr ""
+
+#: doc/classes/Color.xml:486
+msgid "Lemon chiffon color."
+msgstr ""
+
+#: doc/classes/Color.xml:489
+msgid "Light blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:492
+msgid "Light coral color."
+msgstr ""
+
+#: doc/classes/Color.xml:495
+msgid "Light cyan color."
+msgstr ""
+
+#: doc/classes/Color.xml:498
+msgid "Light goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:501
+msgid "Light gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:504
+msgid "Light green color."
+msgstr ""
+
+#: doc/classes/Color.xml:507
+msgid "Light pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:510
+msgid "Light salmon color."
+msgstr ""
+
+#: doc/classes/Color.xml:513
+msgid "Light sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:516
+msgid "Light sky blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:519
+msgid "Light slate gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:522
+msgid "Light steel blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:525
+msgid "Light yellow color."
+msgstr ""
+
+#: doc/classes/Color.xml:528
+msgid "Lime color."
+msgstr ""
+
+#: doc/classes/Color.xml:531
+msgid "Lime green color."
+msgstr ""
+
+#: doc/classes/Color.xml:534
+msgid "Linen color."
+msgstr ""
+
+#: doc/classes/Color.xml:537
+msgid "Magenta color."
+msgstr ""
+
+#: doc/classes/Color.xml:540
+msgid "Maroon color."
+msgstr ""
+
+#: doc/classes/Color.xml:543
+msgid "Medium aquamarine color."
+msgstr ""
+
+#: doc/classes/Color.xml:546
+msgid "Medium blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:549
+msgid "Medium orchid color."
+msgstr ""
+
+#: doc/classes/Color.xml:552
+msgid "Medium purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:555
+msgid "Medium sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:558
+msgid "Medium slate blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:561
+msgid "Medium spring green color."
+msgstr ""
+
+#: doc/classes/Color.xml:564
+msgid "Medium turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:567
+msgid "Medium violet red color."
+msgstr ""
+
+#: doc/classes/Color.xml:570
+msgid "Midnight blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:573
+msgid "Mint cream color."
+msgstr ""
+
+#: doc/classes/Color.xml:576
+msgid "Misty rose color."
+msgstr ""
+
+#: doc/classes/Color.xml:579
+msgid "Moccasin color."
+msgstr ""
+
+#: doc/classes/Color.xml:582
+msgid "Navajo white color."
+msgstr ""
+
+#: doc/classes/Color.xml:585
+msgid "Navy blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:588
+msgid "Old lace color."
+msgstr ""
+
+#: doc/classes/Color.xml:591
+msgid "Olive color."
+msgstr ""
+
+#: doc/classes/Color.xml:594
+msgid "Olive drab color."
+msgstr ""
+
+#: doc/classes/Color.xml:597
+msgid "Orange color."
+msgstr ""
+
+#: doc/classes/Color.xml:600
+msgid "Orange red color."
+msgstr ""
+
+#: doc/classes/Color.xml:603
+msgid "Orchid color."
+msgstr ""
+
+#: doc/classes/Color.xml:606
+msgid "Pale goldenrod color."
+msgstr ""
+
+#: doc/classes/Color.xml:609
+msgid "Pale green color."
+msgstr ""
+
+#: doc/classes/Color.xml:612
+msgid "Pale turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:615
+msgid "Pale violet red color."
+msgstr ""
+
+#: doc/classes/Color.xml:618
+msgid "Papaya whip color."
+msgstr ""
+
+#: doc/classes/Color.xml:621
+msgid "Peach puff color."
+msgstr ""
+
+#: doc/classes/Color.xml:624
+msgid "Peru color."
+msgstr ""
+
+#: doc/classes/Color.xml:627
+msgid "Pink color."
+msgstr ""
+
+#: doc/classes/Color.xml:630
+msgid "Plum color."
+msgstr ""
+
+#: doc/classes/Color.xml:633
+msgid "Powder blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:636
+msgid "Purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:639
+msgid "Rebecca purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:642
+msgid "Red color."
+msgstr ""
+
+#: doc/classes/Color.xml:645
+msgid "Rosy brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:648
+msgid "Royal blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:651
+msgid "Saddle brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:654
+msgid "Salmon color."
+msgstr ""
+
+#: doc/classes/Color.xml:657
+msgid "Sandy brown color."
+msgstr ""
+
+#: doc/classes/Color.xml:660
+msgid "Sea green color."
+msgstr ""
+
+#: doc/classes/Color.xml:663
+msgid "Seashell color."
+msgstr ""
+
+#: doc/classes/Color.xml:666
+msgid "Sienna color."
+msgstr ""
+
+#: doc/classes/Color.xml:669
+msgid "Silver color."
+msgstr ""
+
+#: doc/classes/Color.xml:672
+msgid "Sky blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:675
+msgid "Slate blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:678
+msgid "Slate gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:681
+msgid "Snow color."
+msgstr ""
+
+#: doc/classes/Color.xml:684
+msgid "Spring green color."
+msgstr ""
+
+#: doc/classes/Color.xml:687
+msgid "Steel blue color."
+msgstr ""
+
+#: doc/classes/Color.xml:690
+msgid "Tan color."
+msgstr ""
+
+#: doc/classes/Color.xml:693
+msgid "Teal color."
+msgstr ""
+
+#: doc/classes/Color.xml:696
+msgid "Thistle color."
+msgstr ""
+
+#: doc/classes/Color.xml:699
+msgid "Tomato color."
+msgstr ""
+
+#: doc/classes/Color.xml:702
+msgid "Transparent color (white with no alpha)."
+msgstr ""
+
+#: doc/classes/Color.xml:705
+msgid "Turquoise color."
+msgstr ""
+
+#: doc/classes/Color.xml:708
+msgid "Violet color."
+msgstr ""
+
+#: doc/classes/Color.xml:711
+msgid "Web gray color."
+msgstr ""
+
+#: doc/classes/Color.xml:714
+msgid "Web green color."
+msgstr ""
+
+#: doc/classes/Color.xml:717
+msgid "Web maroon color."
+msgstr ""
+
+#: doc/classes/Color.xml:720
+msgid "Web purple color."
+msgstr ""
+
+#: doc/classes/Color.xml:723
+msgid "Wheat color."
+msgstr ""
+
+#: doc/classes/Color.xml:726
+msgid "White color."
+msgstr ""
+
+#: doc/classes/Color.xml:729
+msgid "White smoke color."
+msgstr ""
+
+#: doc/classes/Color.xml:732
+msgid "Yellow color."
+msgstr ""
+
+#: doc/classes/Color.xml:735
+msgid "Yellow green color."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:4
+msgid "Color picker control."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:7
+msgid ""
+"Displays a color picker widget. Useful for selecting a color from an RGB/"
+"RGBA colorspace."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:18
+msgid ""
+"Adds the given color to a list of color presets. The presets are displayed "
+"in the color picker and the user will be able to select them.\n"
+"[b]Note:[/b] the presets list is only for [i]this[/i] color picker."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:28
+msgid ""
+"Removes the given color from the list of color presets of this color picker."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:35
+msgid "Returns the list of colors in the presets of the color picker."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:41 doc/classes/ColorPickerButton.xml:29
+msgid "The currently selected color."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:44
+msgid ""
+"If [code]true[/code], the color will apply only after the user releases the "
+"mouse button, otherwise it will apply immediately even in mouse motion event "
+"(which can cause performance issues)."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:47
+msgid "If [code]true[/code], shows an alpha channel slider (transparency)."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:50
+msgid ""
+"If [code]true[/code], allows editing the color with Hue/Saturation/Value "
+"sliders.\n"
+"[b]Note:[/b] Cannot be enabled if raw mode is on."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:54
+msgid "If [code]true[/code], the \"add preset\" button is enabled."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:57
+msgid "If [code]true[/code], saved color presets are visible."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:60
+msgid ""
+"If [code]true[/code], allows the color R, G, B component values to go beyond "
+"1.0, which can be used for certain special operations that require it (like "
+"tinting without darkening or rendering sprites in HDR).\n"
+"[b]Note:[/b] Cannot be enabled if HSV mode is on."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:69
+msgid "Emitted when the color is changed."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:76
+msgid "Emitted when a preset is added."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:83
+msgid "Emitted when a preset is removed."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:91
+msgid "The icon for the \"Add Preset\" button."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:94
+msgid "Custom texture for the hue selection slider on the right."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:99
+msgid "The width of the hue selection slider."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:104
+msgid "The margin around the [ColorPicker]."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:107
+msgid ""
+"The indicator used to signalize that the color value is outside the 0-1 "
+"range."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:112
+msgid "The icon for the screen color picker button."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:115
+msgid "The height of the saturation-value selection box."
+msgstr ""
+
+#: doc/classes/ColorPicker.xml:118
+msgid "The width of the saturation-value selection box."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:4
+msgid "Button that pops out a [ColorPicker]."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:7
+msgid ""
+"Encapsulates a [ColorPicker] making it accessible by pressing a button. "
+"Pressing the button will toggle the [ColorPicker] visibility."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:16
+msgid "Returns the [ColorPicker] that this node toggles."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:23
+msgid ""
+"Returns the control's [PopupPanel] which allows you to connect to popup "
+"signals. This allows you to handle events when the ColorPicker is shown or "
+"hidden."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:32
+msgid ""
+"If [code]true[/code], the alpha channel in the displayed [ColorPicker] will "
+"be visible."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:41
+msgid "Emitted when the color changes."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:46
+msgid ""
+"Emitted when the [ColorPicker] is created (the button is pressed for the "
+"first time)."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:51
+msgid "Emitted when the [ColorPicker] is closed."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:59
+msgid "The background of the color preview rect on the button."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:62
+msgid "[StyleBox] used when the [ColorPickerButton] is disabled."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:65
+msgid ""
+"[StyleBox] used when the [ColorPickerButton] is focused. It is displayed "
+"over the current [StyleBox], so using [StyleBoxEmpty] will just disable the "
+"focus visual effect."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:68
+msgid "[Font] of the [ColorPickerButton]'s text."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:71
+msgid "Default text [Color] of the [ColorPickerButton]."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:74
+msgid "Text [Color] used when the [ColorPickerButton] is disabled."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:77
+msgid "Text [Color] used when the [ColorPickerButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:80
+msgid "Text [Color] used when the [ColorPickerButton] is being pressed."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:83
+msgid "[StyleBox] used when the [ColorPickerButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:86
+msgid "The horizontal space between [ColorPickerButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:89
+msgid "Default [StyleBox] for the [ColorPickerButton]."
+msgstr ""
+
+#: doc/classes/ColorPickerButton.xml:92
+msgid "[StyleBox] used when the [ColorPickerButton] is being pressed."
+msgstr ""
+
+#: doc/classes/ColorRect.xml:4
+msgid "Colored rectangle."
+msgstr ""
+
+#: doc/classes/ColorRect.xml:7
+msgid "Displays a colored rectangle."
+msgstr ""
+
+#: doc/classes/ColorRect.xml:15
+msgid ""
+"The fill color.\n"
+"[codeblock]\n"
+"$ColorRect.color = Color(1, 0, 0, 1) # Set ColorRect's color to red.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape2D.xml:4
+msgid "Concave polygon 2D shape resource for physics."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape2D.xml:7
+msgid ""
+"Concave polygon 2D shape resource for physics. It is made out of segments "
+"and is optimal for complex polygonal concave collisions. However, it is not "
+"advised to use for [RigidBody2D] nodes. A CollisionPolygon2D in convex "
+"decomposition mode (solids) or several convex objects are advised for that "
+"instead. Otherwise, a concave polygon 2D shape is better for static "
+"collisions.\n"
+"The main difference between a [ConvexPolygonShape2D] and a "
+"[ConcavePolygonShape2D] is that a concave polygon assumes it is concave and "
+"uses a more complex method of collision detection, and a convex one forces "
+"itself to be convex in order to speed up collision detection."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape2D.xml:16
+msgid ""
+"The array of points that make up the [ConcavePolygonShape2D]'s line segments."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:4
+msgid "Concave polygon shape."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:7
+msgid ""
+"Concave polygon shape resource, which can be set into a [PhysicsBody3D] or "
+"area. This shape is created by feeding a list of triangles.\n"
+"Note: when used for collision, [ConcavePolygonShape3D] is intended to work "
+"with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with "
+"[KinematicBody3D] or [RigidBody3D] with a mode other than Static."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:17
+msgid "Returns the faces (an array of triangles)."
+msgstr ""
+
+#: doc/classes/ConcavePolygonShape3D.xml:26
+msgid "Sets the faces (an array of triangles)."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:4
+msgid "A twist joint between two 3D bodies."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:7
+msgid ""
+"The joint can rotate the bodies across an axis defined by the local x-axes "
+"of the [Joint3D].\n"
+"The twist axis is initiated as the X axis of the [Joint3D].\n"
+"Once the Bodies swing, the twist axis is calculated as the middle of the x-"
+"axes of the Joint3D in the local space of the two Bodies."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:35 doc/classes/ConeTwistJoint3D.xml:67
+#: doc/classes/PhysicsServer3D.xml:1400
+msgid ""
+"The speed with which the swing or twist will take place.\n"
+"The higher, the faster."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:39 doc/classes/ConeTwistJoint3D.xml:74
+#: doc/classes/PhysicsServer3D.xml:1407
+msgid ""
+"Defines, how fast the swing- and twist-speed-difference on both sides gets "
+"synced."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:42 doc/classes/ConeTwistJoint3D.xml:71
+msgid ""
+"The ease with which the joint starts to twist. If it's too low, it takes "
+"more force to start twisting the joint."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:45 doc/classes/ConeTwistJoint3D.xml:57
+#: doc/classes/PhysicsServer3D.xml:1390
+msgid ""
+"Swing is rotation from side to side, around the axis perpendicular to the "
+"twist axis.\n"
+"The swing span defines, how much rotation will not get corrected along the "
+"swing axis.\n"
+"Could be defined as looseness in the [ConeTwistJoint3D].\n"
+"If below 0.05, this behavior is locked."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:51 doc/classes/ConeTwistJoint3D.xml:63
+#: doc/classes/PhysicsServer3D.xml:1396
+msgid ""
+"Twist is the rotation around the twist axis, this value defined how far the "
+"joint can twist.\n"
+"Twist is locked if below 0.05."
+msgstr ""
+
+#: doc/classes/ConeTwistJoint3D.xml:77 doc/classes/Generic6DOFJoint3D.xml:404
+#: doc/classes/HingeJoint3D.xml:109 doc/classes/Light3D.xml:124
+#: doc/classes/SliderJoint3D.xml:170
+msgid "Represents the size of the [enum Param] enum."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:4
+msgid "Helper class to handle INI-style files."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:7
+msgid ""
+"This helper class can be used to store [Variant] values on the filesystem "
+"using INI-style formatting. The stored values are identified by a section "
+"and a key:\n"
+"[codeblock]\n"
+"[section]\n"
+"some_key=42\n"
+"string_example=\"Hello World3D!\"\n"
+"a_vector=Vector3( 1, 0, 2 )\n"
+"[/codeblock]\n"
+"The stored data can be saved to or parsed from a file, though ConfigFile "
+"objects can also be used directly without accessing the filesystem.\n"
+"The following example shows how to parse an INI-style file from the system, "
+"read its contents and store new values in it:\n"
+"[codeblock]\n"
+"var config = ConfigFile.new()\n"
+"var err = config.load(\"user://settings.cfg\")\n"
+"if err == OK: # If not, something went wrong with the file loading\n"
+" # Look for the display/width pair, and default to 1024 if missing\n"
+" var screen_width = config.get_value(\"display\", \"width\", 1024)\n"
+" # Store a variable if and only if it hasn't been defined yet\n"
+" if not config.has_section_key(\"audio\", \"mute\"):\n"
+" config.set_value(\"audio\", \"mute\", false)\n"
+" # Save the changes by overwriting the previous file\n"
+" config.save(\"user://settings.cfg\")\n"
+"[/codeblock]\n"
+"Keep in mind that section and property names can't contain spaces. Anything "
+"after a space will be ignored on save and on load.\n"
+"ConfigFiles can also contain manually written comment lines starting with a "
+"semicolon ([code];[/code]). Those lines will be ignored when parsing the "
+"file. Note that comments will be lost when saving the ConfigFile. This can "
+"still be useful for dedicated server configuration files, which are "
+"typically never overwritten without explicit user action."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:40
+msgid ""
+"Deletes the specified section along with all the key-value pairs inside. "
+"Raises an error if the section does not exist."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:51
+msgid ""
+"Deletes the specified key in a section. Raises an error if either the "
+"section or the key do not exist."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:60
+msgid ""
+"Returns an array of all defined key identifiers in the specified section. "
+"Raises an error and returns an empty array if the section does not exist."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:67
+msgid "Returns an array of all defined section identifiers."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:80
+msgid ""
+"Returns the current value for the specified section and key. If either the "
+"section or the key do not exist, the method returns the fallback "
+"[code]default[/code] value. If [code]default[/code] is not specified or set "
+"to [code]null[/code], an error is also raised."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:89
+msgid "Returns [code]true[/code] if the specified section exists."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:100
+msgid "Returns [code]true[/code] if the specified section-key pair exists."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:109
+msgid ""
+"Loads the config file specified as a parameter. The file's contents are "
+"parsed and loaded in the [ConfigFile] object which the method was called "
+"on.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:121
+msgid ""
+"Loads the encrypted config file specified as a parameter, using the provided "
+"[code]key[/code] to decrypt it. The file's contents are parsed and loaded in "
+"the [ConfigFile] object which the method was called on.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:133
+msgid ""
+"Loads the encrypted config file specified as a parameter, using the provided "
+"[code]password[/code] to decrypt it. The file's contents are parsed and "
+"loaded in the [ConfigFile] object which the method was called on.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:143
+msgid ""
+"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.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:153
+msgid ""
+"Saves the contents of the [ConfigFile] object to the file specified as a "
+"parameter. The output file uses an INI-style structure.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:165
+msgid ""
+"Saves the contents of the [ConfigFile] object to the AES-256 encrypted file "
+"specified as a parameter, using the provided [code]key[/code] to encrypt it. "
+"The output file uses an INI-style structure.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:177
+msgid ""
+"Saves the contents of the [ConfigFile] object to the AES-256 encrypted file "
+"specified as a parameter, using the provided [code]password[/code] to "
+"encrypt it. The output file uses an INI-style structure.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/ConfigFile.xml:191
+msgid ""
+"Assigns a value to the specified key of the specified section. If either the "
+"section or the key do not exist, they are created. Passing a [code]null[/"
+"code] value deletes the specified key if it exists, and deletes the section "
+"if it ends up empty once the key has been removed."
+msgstr ""
+
+#: doc/classes/ConfirmationDialog.xml:4
+msgid "Dialog for confirmation of actions."
+msgstr ""
+
+#: doc/classes/ConfirmationDialog.xml:7
+msgid ""
+"Dialog for confirmation of actions. This dialog inherits from "
+"[AcceptDialog], but has by default an OK and Cancel button (in host OS "
+"order).\n"
+"To get cancel action, you can use:\n"
+"[codeblock]\n"
+"get_cancel().connect(\"pressed\", self, \"cancelled\")\n"
+"[/codeblock]."
+msgstr ""
+
+#: doc/classes/ConfirmationDialog.xml:20
+msgid "Returns the cancel button."
+msgstr ""
+
+#: doc/classes/Container.xml:4
+msgid "Base node for containers."
+msgstr ""
+
+#: doc/classes/Container.xml:7
+msgid ""
+"Base node for containers. A [Container] contains other controls and "
+"automatically arranges them in a certain way.\n"
+"A Control can inherit this to create custom container classes."
+msgstr ""
+
+#: doc/classes/Container.xml:21
+msgid ""
+"Fit a child control in a given rect. This is mainly a helper for creating "
+"custom container classes."
+msgstr ""
+
+#: doc/classes/Container.xml:28
+msgid ""
+"Queue resort of the contained children. This is called automatically anyway, "
+"but can be called upon request."
+msgstr ""
+
+#: doc/classes/Container.xml:38
+msgid "Emitted when sorting the children is needed."
+msgstr ""
+
+#: doc/classes/Container.xml:44
+msgid ""
+"Notification for when sorting the children, it must be obeyed immediately."
+msgstr ""
+
+#: doc/classes/Control.xml:4
+msgid ""
+"All user interface nodes inherit from Control. A control's anchors and "
+"margins adapt its position and size relative to its parent."
+msgstr ""
+
+#: doc/classes/Control.xml:7
+msgid ""
+"Base class for all UI-related nodes. [Control] features a bounding rectangle "
+"that defines its extents, an anchor position relative to its parent control "
+"or the current viewport, and margins that represent an offset to the anchor. "
+"The margins update automatically when the node, any of its parents, or the "
+"screen size change.\n"
+"For more information on Godot's UI system, anchors, margins, and containers, "
+"see the related tutorials in the manual. To build flexible UIs, you'll need "
+"a mix of UI elements that inherit from [Control] and [Container] nodes.\n"
+"[b]User Interface nodes and input[/b]\n"
+"Godot sends input events to the scene's root node first, by calling [method "
+"Node._input]. [method Node._input] forwards the event down the node tree to "
+"the nodes under the mouse cursor, or on keyboard focus. To do so, it calls "
+"[code]MainLoop._input_event[/code].\n"
+"[b]FIXME:[/b] No longer valid after DisplayServer split and Input "
+"refactoring.\n"
+"Call [method accept_event] so no other node receives the event. Once you "
+"accepted an input, it becomes handled so [method Node._unhandled_input] will "
+"not process it.\n"
+"Only one [Control] node can be in keyboard focus. Only the node in focus "
+"will receive keyboard events. To get the focus, call [method grab_focus]. "
+"[Control] nodes lose focus when another node grabs it, or if you hide the "
+"node in focus.\n"
+"Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a "
+"[Control] node to ignore mouse or touch events. You'll need it if you place "
+"an icon on top of a button.\n"
+"[Theme] resources change the Control's appearance. If you change the [Theme] "
+"on a [Control] node, it affects all of its children. To override some of the "
+"theme's parameters, call one of the [code]add_theme_*_override[/code] "
+"methods, like [method add_theme_font_override]. You can override the theme "
+"with the inspector."
+msgstr ""
+
+#: doc/classes/Control.xml:18
+msgid "https://docs.godotengine.org/en/latest/tutorials/gui/index.html"
+msgstr ""
+
+#: doc/classes/Control.xml:26
+msgid ""
+"Virtual method to be implemented by the user. Returns whether [method "
+"_gui_input] should not be called for children controls outside this "
+"control's rectangle. Input will be clipped to the Rect of this [Control]. "
+"Similar to [member rect_clip_content], but doesn't affect visibility.\n"
+"If not overridden, defaults to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:34
+msgid ""
+"Virtual method to be implemented by the user. Returns the minimum size for "
+"this control. Alternative to [member rect_min_size] for controlling minimum "
+"size via code. The actual minimum size will be the max value of these two "
+"(in each axis separately).\n"
+"If not overridden, defaults to [constant Vector2.ZERO]."
+msgstr ""
+
+#: doc/classes/Control.xml:44
+msgid ""
+"Virtual method to be implemented by the user. Use this method to process and "
+"accept inputs on UI elements. See [method accept_event].\n"
+"Example: clicking a control.\n"
+"[codeblock]\n"
+"func _gui_input(event):\n"
+" if event is InputEventMouseButton:\n"
+" if event.button_index == BUTTON_LEFT and event.pressed:\n"
+" print(\"I've been clicked D:\")\n"
+"[/codeblock]\n"
+"The event won't trigger if:\n"
+"* clicking outside the control (see [method has_point]);\n"
+"* control has [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];\n"
+"* control is obstructed by another [Control] on top of it, which doesn't "
+"have [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];\n"
+"* control's parent has [member mouse_filter] set to [constant "
+"MOUSE_FILTER_STOP] or has accepted the event;\n"
+"* it happens outside parent's rectangle and the parent has either [member "
+"rect_clip_content] or [method _clips_input] enabled."
+msgstr ""
+
+#: doc/classes/Control.xml:66
+msgid ""
+"Virtual method to be implemented by the user. Returns a [Control] node that "
+"should be used as a tooltip instead of the default one. Use [code]for_text[/"
+"code] parameter to determine what text the tooltip should contain (likely "
+"the contents of [member hint_tooltip]).\n"
+"The returned node must be of type [Control] or Control-derieved. It can have "
+"child nodes of any type. It is freed when the tooltip disappears, so make "
+"sure you always provide a new instance, not e.g. a node from scene. When "
+"[code]null[/code] or non-Control node is returned, the default tooltip will "
+"be used instead.\n"
+"[b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure "
+"it's fully visible, you might want to set its [member rect_min_size] to some "
+"non-zero value.\n"
+"Example of usage with custom-constructed node:\n"
+"[codeblock]\n"
+"func _make_custom_tooltip(for_text):\n"
+" var label = Label.new()\n"
+" label.text = for_text\n"
+" return label\n"
+"[/codeblock]\n"
+"Example of usage with custom scene instance:\n"
+"[codeblock]\n"
+"func _make_custom_tooltip(for_text):\n"
+" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n"
+" tooltip.get_node(\"Label\").text = for_text\n"
+" return tooltip\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:89
+msgid ""
+"Marks an input event as handled. Once you accept an input event, it stops "
+"propagating, even to nodes listening to [method Node._unhandled_input] or "
+"[method Node._unhandled_key_input]."
+msgstr ""
+
+#: doc/classes/Control.xml:100
+msgid ""
+"Overrides the [Color] with given [code]name[/code] in the [member theme] "
+"resource the control uses. If the [code]color[/code] is empty or invalid, "
+"the override is cleared and the color from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:111
+msgid ""
+"Overrides an integer constant with given [code]name[/code] in the [member "
+"theme] resource the control uses. If the [code]constant[/code] is empty or "
+"invalid, the override is cleared and the constant from assigned [Theme] is "
+"used."
+msgstr ""
+
+#: doc/classes/Control.xml:122
+msgid ""
+"Overrides the font with given [code]name[/code] in the [member theme] "
+"resource the control uses. If [code]font[/code] is empty or invalid, the "
+"override is cleared and the font from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:133
+msgid ""
+"Overrides the icon with given [code]name[/code] in the [member theme] "
+"resource the control uses. If [code]icon[/code] is empty or invalid, the "
+"override is cleared and the icon from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:144
+msgid ""
+"Overrides the [Shader] with given [code]name[/code] in the [member theme] "
+"resource the control uses. If [code]shader[/code] is empty or invalid, the "
+"override is cleared and the shader from assigned [Theme] is used."
+msgstr ""
+
+#: doc/classes/Control.xml:155
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Control.xml:166
+msgid ""
+"Godot calls this method to test if [code]data[/code] from a control's "
+"[method get_drag_data] can be dropped at [code]position[/code]. "
+"[code]position[/code] is local to this control.\n"
+"This method should only be used to test the data. Process the data in "
+"[method drop_data].\n"
+"[codeblock]\n"
+"func can_drop_data(position, data):\n"
+" # Check position if it is relevant to you\n"
+" # Otherwise, just check data\n"
+" return typeof(data) == TYPE_DICTIONARY and data.has(\"expected\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:184
+msgid ""
+"Godot calls this method to pass you the [code]data[/code] from a control's "
+"[method get_drag_data] result. Godot first calls [method can_drop_data] to "
+"test if [code]data[/code] is allowed to drop at [code]position[/code] where "
+"[code]position[/code] is local to this control.\n"
+"[codeblock]\n"
+"func can_drop_data(position, data):\n"
+" return typeof(data) == TYPE_DICTIONARY and data.has(\"color\")\n"
+"\n"
+"func drop_data(position, data):\n"
+" color = data[\"color\"]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:202
+msgid ""
+"Forces drag and bypasses [method get_drag_data] and [method "
+"set_drag_preview] by passing [code]data[/code] and [code]preview[/code]. "
+"Drag will start even if the mouse is neither over nor pressed on this "
+"control.\n"
+"The methods [method can_drop_data] and [method drop_data] must be "
+"implemented on controls that want to receive drop data."
+msgstr ""
+
+#: doc/classes/Control.xml:212
+msgid ""
+"Returns the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum. A getter method for [member anchor_bottom], [member "
+"anchor_left], [member anchor_right] and [member anchor_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:219
+msgid ""
+"Returns [member margin_left] and [member margin_top]. See also [member "
+"rect_position]."
+msgstr ""
+
+#: doc/classes/Control.xml:226
+msgid ""
+"Returns combined minimum size from [member rect_min_size] and [method "
+"get_minimum_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:235
+msgid ""
+"Returns the mouse cursor shape the control displays on mouse hover. See "
+"[enum CursorShape]."
+msgstr ""
+
+#: doc/classes/Control.xml:244
+msgid ""
+"Godot calls this method to get data that can be dragged and dropped onto "
+"controls that expect drop data. Returns [code]null[/code] if there is no "
+"data to drag. Controls that want to receive drop data should implement "
+"[method can_drop_data] and [method drop_data]. [code]position[/code] is "
+"local to this control. Drag may be forced with [method force_drag].\n"
+"A preview that will follow the mouse that should represent the data can be "
+"set with [method set_drag_preview]. A good time to set the preview is in "
+"this method.\n"
+"[codeblock]\n"
+"func get_drag_data(position):\n"
+" var mydata = make_data()\n"
+" set_drag_preview(make_preview(mydata))\n"
+" return mydata\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:258
+msgid "Returns [member margin_right] and [member margin_bottom]."
+msgstr ""
+
+#: doc/classes/Control.xml:267
+msgid ""
+"Returns the focus neighbour identified by [code]margin[/code] constant from "
+"[enum Margin] enum. A getter method for [member focus_neighbour_bottom], "
+"[member focus_neighbour_left], [member focus_neighbour_right] and [member "
+"focus_neighbour_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:274
+msgid ""
+"Returns the control that has the keyboard focus or [code]null[/code] if none."
+msgstr ""
+
+#: doc/classes/Control.xml:281
+msgid ""
+"Returns the position and size of the control relative to the top-left corner "
+"of the screen. See [member rect_position] and [member rect_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:290
+msgid ""
+"Returns the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum. A getter method for [member margin_bottom], [member "
+"margin_left], [member margin_right] and [member margin_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:297
+msgid "Returns the minimum size for this control. See [member rect_min_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:304
+msgid "Returns the width/height occupied in the parent control."
+msgstr ""
+
+#: doc/classes/Control.xml:311
+msgid "Returns the parent control node."
+msgstr ""
+
+#: doc/classes/Control.xml:318
+msgid ""
+"Returns the position and size of the control relative to the top-left corner "
+"of the parent Control. See [member rect_position] and [member rect_size]."
+msgstr ""
+
+#: doc/classes/Control.xml:325
+msgid "Returns the rotation (in radians)."
+msgstr ""
+
+#: doc/classes/Control.xml:336
+msgid ""
+"Returns a color from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code].\n"
+"[codeblock]\n"
+"func _ready():\n"
+" modulate = get_theme_color(\"font_color\", \"Button\") #get the color "
+"defined for button fonts\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:351
+msgid ""
+"Returns a constant from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:362
+msgid ""
+"Returns a font from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:373
+msgid ""
+"Returns an icon from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:384
+msgid ""
+"Returns a [StyleBox] from assigned [Theme] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:393
+msgid ""
+"Returns the tooltip, which will appear when the cursor is resting over this "
+"control. See [member hint_tooltip]."
+msgstr ""
+
+#: doc/classes/Control.xml:400
+msgid ""
+"Creates an [InputEventMouseButton] that attempts to click the control. If "
+"the event is received, the control acquires focus.\n"
+"[codeblock]\n"
+"func _process(delta):\n"
+" grab_click_focus() #when clicking another Control node, this node will "
+"be clicked instead\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:411
+msgid ""
+"Steal the focus from another control and become the focused control (see "
+"[member focus_mode])."
+msgstr ""
+
+#: doc/classes/Control.xml:418
+msgid ""
+"Returns [code]true[/code] if this is the current focused control. See "
+"[member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:427
+msgid ""
+"Virtual method to be implemented by the user. Returns whether the given "
+"[code]point[/code] is inside this control.\n"
+"If not overridden, default behavior is checking if the point is within "
+"control's Rect.\n"
+"[b]Note:[/b] If you want to check if a point is inside the control, you can "
+"use [code]get_rect().has_point(point)[/code]."
+msgstr ""
+
+#: doc/classes/Control.xml:440
+msgid ""
+"Returns [code]true[/code] if [Color] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:449
+msgid ""
+"Returns [code]true[/code] if [Color] with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:460
+msgid ""
+"Returns [code]true[/code] if constant with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:469
+msgid ""
+"Returns [code]true[/code] if constant with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:480
+msgid ""
+"Returns [code]true[/code] if font with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:489
+msgid ""
+"Returns [code]true[/code] if font with given [code]name[/code] has a valid "
+"override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:500
+msgid ""
+"Returns [code]true[/code] if icon with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:509
+msgid ""
+"Returns [code]true[/code] if icon with given [code]name[/code] has a valid "
+"override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:518
+msgid ""
+"Returns [code]true[/code] if [Shader] with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:529
+msgid ""
+"Returns [code]true[/code] if [StyleBox] with given [code]name[/code] and "
+"associated with [Control] of given [code]type[/code] exists in assigned "
+"[Theme]."
+msgstr ""
+
+#: doc/classes/Control.xml:538
+msgid ""
+"Returns [code]true[/code] if [StyleBox] with given [code]name[/code] has a "
+"valid override in this [Control] node."
+msgstr ""
+
+#: doc/classes/Control.xml:545
+msgid ""
+"Invalidates the size cache in this node and in parent nodes up to toplevel. "
+"Intended to be used with [method get_minimum_size] when the return value is "
+"changed. Setting [member rect_min_size] directly calls this method "
+"automatically."
+msgstr ""
+
+#: doc/classes/Control.xml:552
+msgid ""
+"Give up the focus. No other control will be able to receive keyboard input."
+msgstr ""
+
+#: doc/classes/Control.xml:567
+msgid ""
+"Sets the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum to value [code]anchor[/code]. A setter method for [member "
+"anchor_bottom], [member anchor_left], [member anchor_right] and [member "
+"anchor_top].\n"
+"If [code]keep_margin[/code] is [code]true[/code], margins aren't updated "
+"after this operation.\n"
+"If [code]push_opposite_anchor[/code] is [code]true[/code] and the opposite "
+"anchor overlaps this anchor, the opposite one will have its value "
+"overridden. For example, when setting left anchor to 1 and the right anchor "
+"has value of 0.5, the right anchor will also get value of 1. If "
+"[code]push_opposite_anchor[/code] was [code]false[/code], the left anchor "
+"would get value 0.5."
+msgstr ""
+
+#: doc/classes/Control.xml:584
+msgid ""
+"Works the same as [method set_anchor], but instead of [code]keep_margin[/"
+"code] argument and automatic update of margin, it allows to set the margin "
+"offset yourself (see [method set_margin])."
+msgstr ""
+
+#: doc/classes/Control.xml:597
+msgid ""
+"Sets both anchor preset and margin preset. See [method set_anchors_preset] "
+"and [method set_margins_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:608
+msgid ""
+"Sets the anchors to a [code]preset[/code] from [enum Control.LayoutPreset] "
+"enum. This is code equivalent of using the Layout menu in 2D editor.\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's position will "
+"also be updated."
+msgstr ""
+
+#: doc/classes/Control.xml:618
+msgid ""
+"Sets [member margin_left] and [member margin_top] at the same time. "
+"Equivalent of changing [member rect_position]."
+msgstr ""
+
+#: doc/classes/Control.xml:627
+msgid ""
+"Forwards the handling of this control's drag and drop to [code]target[/code] "
+"control.\n"
+"Forwarding can be implemented in the target control similar to the methods "
+"[method get_drag_data], [method can_drop_data], and [method drop_data] but "
+"with two differences:\n"
+"1. The function name must be suffixed with [b]_fw[/b]\n"
+"2. The function must take an extra argument that is the control doing the "
+"forwarding\n"
+"[codeblock]\n"
+"# ThisControl.gd\n"
+"extends Control\n"
+"func _ready():\n"
+" set_drag_forwarding(target_control)\n"
+"\n"
+"# TargetControl.gd\n"
+"extends Control\n"
+"func can_drop_data_fw(position, data, from_control):\n"
+" return true\n"
+"\n"
+"func drop_data_fw(position, data, from_control):\n"
+" my_handle_data(data)\n"
+"\n"
+"func get_drag_data_fw(position, from_control):\n"
+" set_drag_preview(my_preview)\n"
+" return my_data()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:657
+msgid ""
+"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.\n"
+"[codeblock]\n"
+"export (Color, RGBA) var color = Color(1, 0, 0, 1)\n"
+"\n"
+"func get_drag_data(position):\n"
+" # Use a control that is not in the tree\n"
+" var cpb = ColorPickerButton.new()\n"
+" cpb.color = color\n"
+" cpb.rect_size = Vector2(50, 50)\n"
+" set_drag_preview(cpb)\n"
+" return color\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Control.xml:677
+msgid "Sets [member margin_right] and [member margin_bottom] at the same time."
+msgstr ""
+
+#: doc/classes/Control.xml:688
+msgid ""
+"Sets the anchor identified by [code]margin[/code] constant from [enum "
+"Margin] enum to [Control] at [code]neighbor[/code] node path. A setter "
+"method for [member focus_neighbour_bottom], [member focus_neighbour_left], "
+"[member focus_neighbour_right] and [member focus_neighbour_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:699
+msgid ""
+"Sets the [member rect_global_position] to given [code]position[/code].\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's anchors will be "
+"updated instead of margins."
+msgstr ""
+
+#: doc/classes/Control.xml:711
+msgid ""
+"Sets the margin identified by [code]margin[/code] constant from [enum "
+"Margin] enum to given [code]offset[/code]. A setter method for [member "
+"margin_bottom], [member margin_left], [member margin_right] and [member "
+"margin_top]."
+msgstr ""
+
+#: doc/classes/Control.xml:724
+msgid ""
+"Sets the margins to a [code]preset[/code] from [enum Control.LayoutPreset] "
+"enum. This is code equivalent of using the Layout menu in 2D editor.\n"
+"Use parameter [code]resize_mode[/code] with constants from [enum Control."
+"LayoutPresetMode] to better determine the resulting size of the [Control]. "
+"Constant size will be ignored if used with presets that change size, e.g. "
+"[code]PRESET_LEFT_WIDE[/code].\n"
+"Use parameter [code]margin[/code] to determine the gap between the [Control] "
+"and the edges."
+msgstr ""
+
+#: doc/classes/Control.xml:737
+msgid ""
+"Sets the [member rect_position] to given [code]position[/code].\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's anchors will be "
+"updated instead of margins."
+msgstr ""
+
+#: doc/classes/Control.xml:747
+msgid "Sets the rotation (in radians)."
+msgstr ""
+
+#: doc/classes/Control.xml:758
+msgid ""
+"Sets the size (see [member rect_size]).\n"
+"If [code]keep_margins[/code] is [code]true[/code], control's anchors will be "
+"updated instead of margins."
+msgstr ""
+
+#: doc/classes/Control.xml:768
+msgid ""
+"Moves the mouse cursor to [code]to_position[/code], relative to [member "
+"rect_position] of this [Control]."
+msgstr ""
+
+#: doc/classes/Control.xml:774
+msgid ""
+"Anchors the bottom edge of the node to the origin, the center, or the end of "
+"its parent control. It changes how the bottom margin updates when the node "
+"moves or changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:777
+msgid ""
+"Anchors the left edge of the node to the origin, the center or the end of "
+"its parent control. It changes how the left margin updates when the node "
+"moves or changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:780
+msgid ""
+"Anchors the right edge of the node to the origin, the center or the end of "
+"its parent control. It changes how the right margin updates when the node "
+"moves or changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:783
+msgid ""
+"Anchors the top edge of the node to the origin, the center or the end of its "
+"parent control. It changes how the top margin updates when the node moves or "
+"changes size. You can use one of the [enum Anchor] constants for "
+"convenience."
+msgstr ""
+
+#: doc/classes/Control.xml:786
+msgid ""
+"The focus access mode for the control (None, Click or All). Only one Control "
+"can be focused at the same time, and it will receive keyboard signals."
+msgstr ""
+
+#: doc/classes/Control.xml:789
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the down arrow on the keyboard or down on a gamepad by default. You can "
+"change the key by editing the [code]ui_down[/code] input action. The node "
+"must be a [Control]. If this property is not set, Godot will give focus to "
+"the closest [Control] to the bottom of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:792
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the left arrow on the keyboard or left on a gamepad by default. You can "
+"change the key by editing the [code]ui_left[/code] input action. The node "
+"must be a [Control]. If this property is not set, Godot will give focus to "
+"the closest [Control] to the left of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:795
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the right arrow on the keyboard or right on a gamepad by default. You can "
+"change the key by editing the [code]ui_right[/code] input action. The node "
+"must be a [Control]. If this property is not set, Godot will give focus to "
+"the closest [Control] to the bottom of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:798
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"the top arrow on the keyboard or top on a gamepad by default. You can change "
+"the key by editing the [code]ui_top[/code] input action. The node must be a "
+"[Control]. If this property is not set, Godot will give focus to the closest "
+"[Control] to the bottom of this one."
+msgstr ""
+
+#: doc/classes/Control.xml:801
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"Tab on a keyboard by default. You can change the key by editing the "
+"[code]ui_focus_next[/code] input action.\n"
+"If this property is not set, Godot will select a \"best guess\" based on "
+"surrounding nodes in the scene tree."
+msgstr ""
+
+#: doc/classes/Control.xml:805
+msgid ""
+"Tells Godot which node it should give keyboard focus to if the user presses "
+"Shift+Tab on a keyboard by default. You can change the key by editing the "
+"[code]ui_focus_prev[/code] input action.\n"
+"If this property is not set, Godot will select a \"best guess\" based on "
+"surrounding nodes in the scene tree."
+msgstr ""
+
+#: doc/classes/Control.xml:809
+msgid ""
+"Controls the direction on the horizontal axis in which the control should "
+"grow if its horizontal minimum size is changed to be greater than its "
+"current size, as the control always has to be at least the minimum size."
+msgstr ""
+
+#: doc/classes/Control.xml:812
+msgid ""
+"Controls the direction on the vertical axis in which the control should grow "
+"if its vertical minimum size is changed to be greater than its current size, "
+"as the control always has to be at least the minimum size."
+msgstr ""
+
+#: doc/classes/Control.xml:815
+msgid ""
+"Changes the tooltip text. The tooltip appears when the user's mouse cursor "
+"stays idle over this control for a few moments, provided that the [member "
+"mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. You can change "
+"the time required for the tooltip to appear with [code]gui/timers/"
+"tooltip_delay_sec[/code] option in Project Settings."
+msgstr ""
+
+#: doc/classes/Control.xml:818
+msgid ""
+"Distance between the node's bottom edge and its parent control, based on "
+"[member anchor_bottom].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:822
+msgid ""
+"Distance between the node's left edge and its parent control, based on "
+"[member anchor_left].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:826
+msgid ""
+"Distance between the node's right edge and its parent control, based on "
+"[member anchor_right].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:830
+msgid ""
+"Distance between the node's top edge and its parent control, based on "
+"[member anchor_top].\n"
+"Margins are often controlled by one or multiple parent [Container] nodes, so "
+"you should not modify them manually if your node is a direct child of a "
+"[Container]. Margins update automatically when you move or resize the node."
+msgstr ""
+
+#: doc/classes/Control.xml:834
+msgid ""
+"The default cursor shape for this control. Useful for Godot plugins and "
+"applications or games that use the system's mouse cursors.\n"
+"[b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the "
+"system."
+msgstr ""
+
+#: doc/classes/Control.xml:838
+msgid ""
+"Controls whether the control will be able to receive mouse button input "
+"events through [method _gui_input] and how these events should be handled. "
+"Also controls whether the control can receive the [signal mouse_entered], "
+"and [signal mouse_exited] signals. See the constants to learn what each does."
+msgstr ""
+
+#: doc/classes/Control.xml:841
+msgid ""
+"Enables whether rendering of children should be clipped to this control's "
+"rectangle. If [code]true[/code], parts of a child which would be visibly "
+"outside of this control's rectangle will not be rendered."
+msgstr ""
+
+#: doc/classes/Control.xml:844
+msgid ""
+"The node's global position, relative to the world (usually to the top-left "
+"corner of the window)."
+msgstr ""
+
+#: doc/classes/Control.xml:847
+msgid ""
+"The minimum size of the node's bounding rectangle. If you set it to a value "
+"greater than (0, 0), the node's bounding rectangle will always have at least "
+"this size, even if its content is smaller. If it's set to (0, 0), the node "
+"sizes automatically to fit its content, be it a texture or child nodes."
+msgstr ""
+
+#: doc/classes/Control.xml:850
+msgid ""
+"By default, the node's pivot is its top-left corner. When you change its "
+"[member rect_scale], it will scale around this pivot. Set this property to "
+"[member rect_size] / 2 to center the pivot in the node's rectangle."
+msgstr ""
+
+#: doc/classes/Control.xml:853
+msgid ""
+"The node's position, relative to its parent. It corresponds to the "
+"rectangle's top-left corner. The property is not affected by [member "
+"rect_pivot_offset]."
+msgstr ""
+
+#: doc/classes/Control.xml:856
+msgid ""
+"The node's rotation around its pivot, in degrees. See [member "
+"rect_pivot_offset] to change the pivot's position."
+msgstr ""
+
+#: doc/classes/Control.xml:859
+msgid ""
+"The node's scale, relative to its [member rect_size]. Change this property "
+"to scale the node around its [member rect_pivot_offset]."
+msgstr ""
+
+#: doc/classes/Control.xml:862
+msgid ""
+"The size of the node's bounding rectangle, in pixels. [Container] nodes "
+"update this property automatically."
+msgstr ""
+
+#: doc/classes/Control.xml:865
+msgid ""
+"Tells the parent [Container] nodes how they should resize and place the node "
+"on the X axis. Use one of the [enum SizeFlags] constants to change the "
+"flags. See the constants to learn what each does."
+msgstr ""
+
+#: doc/classes/Control.xml:868
+msgid ""
+"If the node and at least one of its neighbours uses the [constant "
+"SIZE_EXPAND] size flag, the parent [Container] will let it take more or less "
+"space depending on this property. If this node has a stretch ratio of 2 and "
+"its neighbour a ratio of 1, this node will take two thirds of the available "
+"space."
+msgstr ""
+
+#: doc/classes/Control.xml:871
+msgid ""
+"Tells the parent [Container] nodes how they should resize and place the node "
+"on the Y axis. Use one of the [enum SizeFlags] constants to change the "
+"flags. See the constants to learn what each does."
+msgstr ""
+
+#: doc/classes/Control.xml:874
+msgid ""
+"Changing this property replaces the current [Theme] resource this node and "
+"all its [Control] children use."
+msgstr ""
+
+#: doc/classes/Control.xml:880
+msgid "Emitted when the node gains keyboard focus."
+msgstr ""
+
+#: doc/classes/Control.xml:885
+msgid "Emitted when the node loses keyboard focus."
+msgstr ""
+
+#: doc/classes/Control.xml:892
+msgid "Emitted when the node receives an [InputEvent]."
+msgstr ""
+
+#: doc/classes/Control.xml:897
+msgid "Emitted when the node's minimum size changes."
+msgstr ""
+
+#: doc/classes/Control.xml:902
+msgid ""
+"Emitted when the mouse enters the control's [code]Rect[/code] area, provided "
+"its [member mouse_filter] lets the event reach it."
+msgstr ""
+
+#: doc/classes/Control.xml:907
+msgid ""
+"Emitted when the mouse leaves the control's [code]Rect[/code] area, provided "
+"its [member mouse_filter] lets the event reach it."
+msgstr ""
+
+#: doc/classes/Control.xml:912
+msgid "Emitted when the control changes size."
+msgstr ""
+
+#: doc/classes/Control.xml:917
+msgid ""
+"Emitted when one of the size flags changes. See [member "
+"size_flags_horizontal] and [member size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:927
+msgid "The node cannot grab focus. Use with [member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:930
+msgid ""
+"The node can only grab focus on mouse clicks. Use with [member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:933
+msgid ""
+"The node can grab focus on mouse click or using the arrows and the Tab keys "
+"on the keyboard. Use with [member focus_mode]."
+msgstr ""
+
+#: doc/classes/Control.xml:936
+msgid ""
+"Sent when the node changes size. Use [member rect_size] to get the new size."
+msgstr ""
+
+#: doc/classes/Control.xml:939
+msgid "Sent when the mouse pointer enters the node."
+msgstr ""
+
+#: doc/classes/Control.xml:942
+msgid "Sent when the mouse pointer exits the node."
+msgstr ""
+
+#: doc/classes/Control.xml:945
+msgid "Sent when the node grabs focus."
+msgstr ""
+
+#: doc/classes/Control.xml:948
+msgid "Sent when the node loses focus."
+msgstr ""
+
+#: doc/classes/Control.xml:951
+msgid ""
+"Sent when the node's [member theme] changes, right before Godot redraws the "
+"control. Happens when you call one of the [code]add_theme_*_override[/code] "
+"methods."
+msgstr ""
+
+#: doc/classes/Control.xml:954
+msgid ""
+"Sent when this node is inside a [ScrollContainer] which has begun being "
+"scrolled."
+msgstr ""
+
+#: doc/classes/Control.xml:957
+msgid ""
+"Sent when this node is inside a [ScrollContainer] which has stopped being "
+"scrolled."
+msgstr ""
+
+#: doc/classes/Control.xml:960
+msgid ""
+"Show the system's arrow mouse cursor when the user hovers the node. Use with "
+"[member mouse_default_cursor_shape]."
+msgstr ""
+
+#: doc/classes/Control.xml:963
+msgid ""
+"Show the system's I-beam mouse cursor when the user hovers the node. The I-"
+"beam pointer has a shape similar to \"I\". It tells the user they can "
+"highlight or insert text."
+msgstr ""
+
+#: doc/classes/Control.xml:966
+msgid ""
+"Show the system's pointing hand mouse cursor when the user hovers the node."
+msgstr ""
+
+#: doc/classes/Control.xml:969
+msgid "Show the system's cross mouse cursor when the user hovers the node."
+msgstr ""
+
+#: doc/classes/Control.xml:972
+msgid ""
+"Show the system's wait mouse cursor, often an hourglass, when the user "
+"hovers the node."
+msgstr ""
+
+#: doc/classes/Control.xml:975
+msgid ""
+"Show the system's busy mouse cursor when the user hovers the node. Often an "
+"hourglass."
+msgstr ""
+
+#: doc/classes/Control.xml:978
+msgid ""
+"Show the system's drag mouse cursor, often a closed fist or a cross symbol, "
+"when the user hovers the node. It tells the user they're currently dragging "
+"an item, like a node in the Scene dock."
+msgstr ""
+
+#: doc/classes/Control.xml:981
+msgid ""
+"Show the system's drop mouse cursor when the user hovers the node. It can be "
+"an open hand. It tells the user they can drop an item they're currently "
+"grabbing, like a node in the Scene dock."
+msgstr ""
+
+#: doc/classes/Control.xml:984
+msgid ""
+"Show the system's forbidden mouse cursor when the user hovers the node. "
+"Often a crossed circle."
+msgstr ""
+
+#: doc/classes/Control.xml:987
+msgid ""
+"Show the system's vertical resize mouse cursor when the user hovers the "
+"node. A double-headed vertical arrow. It tells the user they can resize the "
+"window or the panel vertically."
+msgstr ""
+
+#: doc/classes/Control.xml:990
+msgid ""
+"Show the system's horizontal resize mouse cursor when the user hovers the "
+"node. A double-headed horizontal arrow. It tells the user they can resize "
+"the window or the panel horizontally."
+msgstr ""
+
+#: doc/classes/Control.xml:993
+msgid ""
+"Show the system's window resize mouse cursor when the user hovers the node. "
+"The cursor is a double-headed arrow that goes from the bottom left to the "
+"top right. It tells the user they can resize the window or the panel both "
+"horizontally and vertically."
+msgstr ""
+
+#: doc/classes/Control.xml:996
+msgid ""
+"Show the system's window resize mouse cursor when the user hovers the node. "
+"The cursor is a double-headed arrow that goes from the top left to the "
+"bottom right, the opposite of [constant CURSOR_BDIAGSIZE]. It tells the user "
+"they can resize the window or the panel both horizontally and vertically."
+msgstr ""
+
+#: doc/classes/Control.xml:999
+msgid ""
+"Show the system's move mouse cursor when the user hovers the node. It shows "
+"2 double-headed arrows at a 90 degree angle. It tells the user they can move "
+"a UI element freely."
+msgstr ""
+
+#: doc/classes/Control.xml:1002
+msgid ""
+"Show the system's vertical split mouse cursor when the user hovers the node. "
+"On Windows, it's the same as [constant CURSOR_VSIZE]."
+msgstr ""
+
+#: doc/classes/Control.xml:1005
+msgid ""
+"Show the system's horizontal split mouse cursor when the user hovers the "
+"node. On Windows, it's the same as [constant CURSOR_HSIZE]."
+msgstr ""
+
+#: doc/classes/Control.xml:1008
+msgid ""
+"Show the system's help mouse cursor when the user hovers the node, a "
+"question mark."
+msgstr ""
+
+#: doc/classes/Control.xml:1011
+msgid ""
+"Snap all 4 anchors to the top-left of the parent control's bounds. Use with "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1014
+msgid ""
+"Snap all 4 anchors to the top-right of the parent control's bounds. Use with "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1017
+msgid ""
+"Snap all 4 anchors to the bottom-left of the parent control's bounds. Use "
+"with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1020
+msgid ""
+"Snap all 4 anchors to the bottom-right of the parent control's bounds. Use "
+"with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1023
+msgid ""
+"Snap all 4 anchors to the center of the left edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1026
+msgid ""
+"Snap all 4 anchors to the center of the top edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1029
+msgid ""
+"Snap all 4 anchors to the center of the right edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1032
+msgid ""
+"Snap all 4 anchors to the center of the bottom edge of the parent control's "
+"bounds. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1035
+msgid ""
+"Snap all 4 anchors to the center of the parent control's bounds. Use with "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1038
+msgid ""
+"Snap all 4 anchors to the left edge of the parent control. The left margin "
+"becomes relative to the left edge and the top margin relative to the top "
+"left corner of the node's parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1041
+msgid ""
+"Snap all 4 anchors to the top edge of the parent control. The left margin "
+"becomes relative to the top left corner, the top margin relative to the top "
+"edge, and the right margin relative to the top right corner of the node's "
+"parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1044
+msgid ""
+"Snap all 4 anchors to the right edge of the parent control. The right margin "
+"becomes relative to the right edge and the top margin relative to the top "
+"right corner of the node's parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1047
+msgid ""
+"Snap all 4 anchors to the bottom edge of the parent control. The left margin "
+"becomes relative to the bottom left corner, the bottom margin relative to "
+"the bottom edge, and the right margin relative to the bottom right corner of "
+"the node's parent. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1050
+msgid ""
+"Snap all 4 anchors to a vertical line that cuts the parent control in half. "
+"Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1053
+msgid ""
+"Snap all 4 anchors to a horizontal line that cuts the parent control in "
+"half. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1056
+msgid ""
+"Snap all 4 anchors to the respective corners of the parent control. Set all "
+"4 margins to 0 after you applied this preset and the [Control] will fit its "
+"parent control. This is equivalent to the \"Full Rect\" layout option in the "
+"editor. Use with [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1059
+msgid "The control will be resized to its minimum size."
+msgstr ""
+
+#: doc/classes/Control.xml:1062
+msgid "The control's width will not change."
+msgstr ""
+
+#: doc/classes/Control.xml:1065
+msgid "The control's height will not change."
+msgstr ""
+
+#: doc/classes/Control.xml:1068
+msgid "The control's size will not change."
+msgstr ""
+
+#: doc/classes/Control.xml:1071
+msgid ""
+"Tells the parent [Container] to expand the bounds of this node to fill all "
+"the available space without pushing any other node. Use with [member "
+"size_flags_horizontal] and [member size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1074
+msgid ""
+"Tells the parent [Container] to let this node take all the available space "
+"on the axis you flag. If multiple neighboring nodes are set to expand, "
+"they'll share the space based on their stretch ratio. See [member "
+"size_flags_stretch_ratio]. Use with [member size_flags_horizontal] and "
+"[member size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1077
+msgid ""
+"Sets the node's size flags to both fill and expand. See the 2 constants "
+"above for more information."
+msgstr ""
+
+#: doc/classes/Control.xml:1080
+msgid ""
+"Tells the parent [Container] to center the node in itself. It centers the "
+"control based on its bounding box, so it doesn't work with the fill or "
+"expand size flags. Use with [member size_flags_horizontal] and [member "
+"size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1083
+msgid ""
+"Tells the parent [Container] to align the node with its end, either the "
+"bottom or the right edge. It doesn't work with the fill or expand size "
+"flags. Use with [member size_flags_horizontal] and [member "
+"size_flags_vertical]."
+msgstr ""
+
+#: doc/classes/Control.xml:1086
+msgid ""
+"The control will receive mouse button input events through [method "
+"_gui_input] if clicked on. And the control will receive the [signal "
+"mouse_entered] and [signal mouse_exited] signals. These events are "
+"automatically marked as handled, and they will not propagate further to "
+"other controls. This also results in blocking signals in other controls."
+msgstr ""
+
+#: doc/classes/Control.xml:1089
+msgid ""
+"The control will receive mouse button input events through [method "
+"_gui_input] if clicked on. And the control will receive the [signal "
+"mouse_entered] and [signal mouse_exited] signals. If this control does not "
+"handle the event, the parent control (if any) will be considered, and so on "
+"until there is no more parent control to potentially handle it. This also "
+"allows signals to fire in other controls. Even if no control handled it at "
+"all, the event will still be handled automatically, so unhandled input will "
+"not be fired."
+msgstr ""
+
+#: doc/classes/Control.xml:1092
+msgid ""
+"The control will not receive mouse button input events through [method "
+"_gui_input]. The control will also not receive the [signal mouse_entered] "
+"nor [signal mouse_exited] signals. This will not block other controls from "
+"receiving these events or firing the signals. Ignored events will not be "
+"handled automatically."
+msgstr ""
+
+#: doc/classes/Control.xml:1095
+msgid ""
+"The control will grow to the left or top to make up if its minimum size is "
+"changed to be greater than its current size on the respective axis."
+msgstr ""
+
+#: doc/classes/Control.xml:1098
+msgid ""
+"The control will grow to the right or bottom to make up if its minimum size "
+"is changed to be greater than its current size on the respective axis."
+msgstr ""
+
+#: doc/classes/Control.xml:1101
+msgid ""
+"The control will grow in both directions equally to make up if its minimum "
+"size is changed to be greater than its current size."
+msgstr ""
+
+#: doc/classes/Control.xml:1104
+msgid ""
+"Snaps one of the 4 anchor's sides to the origin of the node's [code]Rect[/"
+"code], in the top left. Use it with one of the [code]anchor_*[/code] member "
+"variables, like [member anchor_left]. To change all 4 anchors at once, use "
+"[method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/Control.xml:1107
+msgid ""
+"Snaps one of the 4 anchor's sides to the end of the node's [code]Rect[/"
+"code], in the bottom right. Use it with one of the [code]anchor_*[/code] "
+"member variables, like [member anchor_left]. To change all 4 anchors at "
+"once, use [method set_anchors_preset]."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:4
+msgid "Convex polygon shape for 2D physics."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:7
+msgid ""
+"Convex polygon shape for 2D physics. A convex polygon, whatever its shape, "
+"is internally decomposed into as many convex polygons as needed to ensure "
+"all collision checks against it are always done on convex polygons (which "
+"are faster to check).\n"
+"The main difference between a [ConvexPolygonShape2D] and a "
+"[ConcavePolygonShape2D] is that a concave polygon assumes it is concave and "
+"uses a more complex method of collision detection, and a convex one forces "
+"itself to be convex in order to speed up collision detection."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:19
+msgid ""
+"Based on the set of points provided, this creates and assigns the [member "
+"points] property using the convex hull algorithm. Removing all unneeded "
+"points. See [method Geometry.convex_hull_2d] for details."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape2D.xml:25
+msgid ""
+"The polygon's list of vertices. Can be in either clockwise or "
+"counterclockwise order."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape3D.xml:4
+msgid "Convex polygon shape for 3D physics."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape3D.xml:7
+msgid ""
+"Convex polygon shape resource, which can be added to a [PhysicsBody3D] or "
+"area."
+msgstr ""
+
+#: doc/classes/ConvexPolygonShape3D.xml:15
+msgid "The list of 3D points forming the convex polygon shape."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:4
+msgid "CPU-based 2D particle emitter."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:7
+msgid ""
+"CPU-based 2D particle node used to create a variety of particle systems and "
+"effects.\n"
+"See also [GPUParticles2D], which provides the same functionality with "
+"hardware acceleration, but may not run on older devices."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:11 doc/classes/GPUParticles2D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html"
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:20
+msgid ""
+"Sets this node's properties to match a given [GPUParticles2D] node with an "
+"assigned [ParticlesMaterial]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:29 doc/classes/CPUParticles3D.xml:28
+msgid "Returns the base value of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:38 doc/classes/CPUParticles3D.xml:37
+msgid "Returns the [Curve] of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:47 doc/classes/CPUParticles3D.xml:46
+msgid ""
+"Returns the randomness factor of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:56 doc/classes/CPUParticles3D.xml:55
+msgid ""
+"Returns the enabled state of the given flag (see [enum Flags] for options)."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:63 doc/classes/CPUParticles3D.xml:62
+msgid "Restarts the particle emitter."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:74 doc/classes/CPUParticles3D.xml:73
+msgid "Sets the base value of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:85 doc/classes/CPUParticles3D.xml:84
+msgid "Sets the [Curve] of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:96 doc/classes/CPUParticles3D.xml:95
+msgid ""
+"Sets the randomness factor of the parameter specified by [enum Parameter]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:107 doc/classes/CPUParticles3D.xml:106
+msgid "Enables or disables the given flag (see [enum Flags] for options)."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:113 doc/classes/CPUParticles3D.xml:112
+#: doc/classes/GPUParticles2D.xml:31
+msgid "Number of particles emitted in one emission cycle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:116 doc/classes/CPUParticles3D.xml:115
+msgid "Initial rotation applied to each particle, in degrees."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:119 doc/classes/CPUParticles3D.xml:118
+msgid "Each particle's rotation will be animated along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:122 doc/classes/CPUParticles3D.xml:121
+#: doc/classes/ParticlesMaterial.xml:104
+msgid "Rotation randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:125 doc/classes/CPUParticles3D.xml:124
+msgid ""
+"Initial angular velocity applied to each particle. Sets the speed of "
+"rotation of the particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:128 doc/classes/CPUParticles3D.xml:127
+msgid "Each particle's angular velocity will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:131 doc/classes/CPUParticles3D.xml:130
+#: doc/classes/ParticlesMaterial.xml:114
+msgid "Angular velocity randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:134 doc/classes/CPUParticles3D.xml:133
+#: doc/classes/ParticlesMaterial.xml:117
+msgid "Particle animation offset."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:137 doc/classes/CPUParticles3D.xml:136
+msgid "Each particle's animation offset will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:140 doc/classes/CPUParticles3D.xml:139
+#: doc/classes/ParticlesMaterial.xml:123
+msgid "Animation offset randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:143 doc/classes/CPUParticles3D.xml:142
+#: doc/classes/ParticlesMaterial.xml:126
+msgid "Particle animation speed."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:146 doc/classes/CPUParticles3D.xml:145
+msgid "Each particle's animation speed will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:149 doc/classes/CPUParticles3D.xml:148
+#: doc/classes/ParticlesMaterial.xml:132
+msgid "Animation speed randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:152
+msgid ""
+"Each particle's initial color. If [member texture] is defined, it will be "
+"multiplied by this color."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:155
+msgid "Each particle's color will vary along this [Gradient]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:158 doc/classes/CPUParticles3D.xml:157
+#: doc/classes/ParticlesMaterial.xml:141
+msgid "The rate at which particles lose velocity."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:161 doc/classes/CPUParticles3D.xml:160
+msgid "Damping will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:164 doc/classes/CPUParticles3D.xml:163
+#: doc/classes/ParticlesMaterial.xml:147
+msgid "Damping randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:167 doc/classes/CPUParticles3D.xml:166
+#: doc/classes/ParticlesMaterial.xml:150
+msgid "Unit vector specifying the particles' emission direction."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:170 doc/classes/CPUParticles3D.xml:169
+#: doc/classes/GPUParticles2D.xml:34 doc/classes/GPUParticles3D.xml:54
+msgid "Particle draw order. Uses [enum DrawOrder] values."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:173 doc/classes/CPUParticles3D.xml:175
+msgid ""
+"Sets the [Color]s to modulate particles by when using [constant "
+"EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:176 doc/classes/CPUParticles3D.xml:178
+msgid ""
+"Sets the direction the particles will be emitted in when using [constant "
+"EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:179 doc/classes/CPUParticles3D.xml:181
+msgid ""
+"Sets the initial positions to spawn particles when using [constant "
+"EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:182
+msgid ""
+"The rectangle's extents if [member emission_shape] is set to [constant "
+"EMISSION_SHAPE_RECTANGLE]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:185 doc/classes/CPUParticles3D.xml:184
+msgid ""
+"Particles will be emitted inside this region. See [enum EmissionShape] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:188
+msgid ""
+"The sphere's radius if [member emission_shape] is set to [constant "
+"EMISSION_SHAPE_SPHERE]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:191 doc/classes/CPUParticles3D.xml:190
+#: doc/classes/GPUParticles2D.xml:37 doc/classes/GPUParticles3D.xml:72
+msgid "If [code]true[/code], particles are being emitted."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:194 doc/classes/CPUParticles3D.xml:193
+#: doc/classes/GPUParticles2D.xml:40
+msgid ""
+"How rapidly particles in an emission cycle are emitted. If greater than "
+"[code]0[/code], there will be a gap in emissions before the next cycle "
+"begins."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:197 doc/classes/GPUParticles2D.xml:43
+#: doc/classes/GPUParticles3D.xml:78
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:200 doc/classes/CPUParticles3D.xml:199
+#: doc/classes/ParticlesMaterial.xml:174
+msgid "Align Y axis of particle with the direction of its velocity."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:203 doc/classes/CPUParticles3D.xml:211
+#: doc/classes/GPUParticles2D.xml:46 doc/classes/GPUParticles3D.xml:81
+msgid ""
+"If [code]true[/code], results in fractional delta calculation which has a "
+"smoother particles display effect."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:206 doc/classes/CPUParticles3D.xml:214
+#: doc/classes/ParticlesMaterial.xml:186
+msgid "Gravity applied to every particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:209 doc/classes/CPUParticles3D.xml:217
+#: doc/classes/ParticlesMaterial.xml:189
+msgid "Initial hue variation applied to each particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:212 doc/classes/CPUParticles3D.xml:220
+msgid "Each particle's hue will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:215 doc/classes/CPUParticles3D.xml:223
+#: doc/classes/ParticlesMaterial.xml:195
+msgid "Hue variation randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:218 doc/classes/CPUParticles3D.xml:226
+#: doc/classes/ParticlesMaterial.xml:198
+msgid ""
+"Initial velocity magnitude for each particle. Direction comes from [member "
+"spread] and the node's orientation."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:221 doc/classes/CPUParticles3D.xml:229
+#: doc/classes/ParticlesMaterial.xml:201
+msgid "Initial velocity randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:224 doc/classes/CPUParticles3D.xml:232
+#: doc/classes/GPUParticles2D.xml:49 doc/classes/GPUParticles3D.xml:84
+msgid "Amount of time each particle will exist."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:227 doc/classes/CPUParticles3D.xml:235
+#: doc/classes/ParticlesMaterial.xml:204
+msgid "Particle lifetime randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:230 doc/classes/CPUParticles3D.xml:238
+#: doc/classes/ParticlesMaterial.xml:207
+msgid ""
+"Linear acceleration applied to each particle in the direction of motion."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:233 doc/classes/CPUParticles3D.xml:241
+msgid "Each particle's linear acceleration will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:236 doc/classes/CPUParticles3D.xml:244
+#: doc/classes/ParticlesMaterial.xml:213
+msgid "Linear acceleration randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:239 doc/classes/CPUParticles3D.xml:247
+#: doc/classes/GPUParticles2D.xml:52 doc/classes/GPUParticles3D.xml:87
+msgid ""
+"If [code]true[/code], particles use the parent node's coordinate space. If "
+"[code]false[/code], they use global coordinates."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:242 doc/classes/GPUParticles2D.xml:55
+msgid "Normal map to be used for the [member texture] property."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:245 doc/classes/CPUParticles3D.xml:253
+#: doc/classes/GPUParticles2D.xml:58
+msgid ""
+"If [code]true[/code], only one emission cycle occurs. If set [code]true[/"
+"code] during a cycle, emission will stop at the cycle's end."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:248
+msgid ""
+"Orbital velocity applied to each particle. Makes the particles circle around "
+"origin. Specified in number of full rotations around origin per second."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:251 doc/classes/CPUParticles3D.xml:260
+msgid "Each particle's orbital velocity will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:254 doc/classes/CPUParticles3D.xml:263
+#: doc/classes/ParticlesMaterial.xml:223
+msgid "Orbital velocity randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:257 doc/classes/CPUParticles3D.xml:266
+#: doc/classes/GPUParticles2D.xml:61
+msgid "Particle system starts as if it had already run for this many seconds."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:260 doc/classes/CPUParticles3D.xml:269
+#: doc/classes/ParticlesMaterial.xml:226
+msgid ""
+"Radial acceleration applied to each particle. Makes particle accelerate away "
+"from origin."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:263 doc/classes/CPUParticles3D.xml:272
+msgid "Each particle's radial acceleration will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:266 doc/classes/CPUParticles3D.xml:275
+#: doc/classes/ParticlesMaterial.xml:232
+msgid "Radial acceleration randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:269 doc/classes/CPUParticles3D.xml:278
+#: doc/classes/GPUParticles2D.xml:67
+msgid "Emission lifetime randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:272 doc/classes/CPUParticles3D.xml:281
+#: doc/classes/ParticlesMaterial.xml:235
+msgid "Initial scale applied to each particle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:275 doc/classes/CPUParticles3D.xml:284
+msgid "Each particle's scale will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:278 doc/classes/CPUParticles3D.xml:287
+#: doc/classes/ParticlesMaterial.xml:241
+msgid "Scale randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:281 doc/classes/CPUParticles3D.xml:290
+#: doc/classes/GPUParticles2D.xml:70
+msgid ""
+"Particle system's running speed scaling ratio. A value of [code]0[/code] can "
+"be used to pause the particles."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:284
+msgid ""
+"Each particle's initial direction range from [code]+spread[/code] to [code]-"
+"spread[/code] degrees."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:287 doc/classes/CPUParticles3D.xml:296
+#: doc/classes/ParticlesMaterial.xml:247
+msgid ""
+"Tangential acceleration applied to each particle. Tangential acceleration is "
+"perpendicular to the particle's velocity giving the particles a swirling "
+"motion."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:290 doc/classes/CPUParticles3D.xml:299
+msgid "Each particle's tangential acceleration will vary along this [Curve]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:293 doc/classes/CPUParticles3D.xml:302
+#: doc/classes/ParticlesMaterial.xml:253
+msgid "Tangential acceleration randomness ratio."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:296 doc/classes/GPUParticles2D.xml:73
+msgid "Particle texture. If [code]null[/code], particles will be squares."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:301 doc/classes/CPUParticles3D.xml:307
+#: doc/classes/GPUParticles2D.xml:81 doc/classes/GPUParticles3D.xml:110
+msgid "Particles are drawn in the order emitted."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:304 doc/classes/CPUParticles3D.xml:310
+#: doc/classes/GPUParticles2D.xml:84 doc/classes/GPUParticles3D.xml:113
+msgid "Particles are drawn in order of remaining lifetime."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:307 doc/classes/CPUParticles3D.xml:316
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set initial velocity properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:310 doc/classes/CPUParticles3D.xml:319
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set angular velocity properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:313 doc/classes/CPUParticles3D.xml:322
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set orbital velocity properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:316 doc/classes/CPUParticles3D.xml:325
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set linear acceleration properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:319 doc/classes/CPUParticles3D.xml:328
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set radial acceleration properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:322 doc/classes/CPUParticles3D.xml:331
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set tangential acceleration properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:325 doc/classes/CPUParticles3D.xml:334
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set damping properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:328 doc/classes/CPUParticles3D.xml:337
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set angle properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:331 doc/classes/CPUParticles3D.xml:340
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set scale properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:334 doc/classes/CPUParticles3D.xml:343
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set hue variation properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:337 doc/classes/CPUParticles3D.xml:346
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set animation speed properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:340 doc/classes/CPUParticles3D.xml:349
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_curve] to set animation offset properties."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:343 doc/classes/CPUParticles3D.xml:352
+#: doc/classes/ParticlesMaterial.xml:303
+msgid "Represents the size of the [enum Parameter] enum."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:346 doc/classes/CPUParticles3D.xml:355
+msgid "Use with [method set_particle_flag] to set [member flag_align_y]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:349 doc/classes/CPUParticles2D.xml:352
+msgid "Present for consistency with 3D particle nodes, not used in 2D."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:358 doc/classes/CPUParticles3D.xml:367
+#: doc/classes/ParticlesMaterial.xml:318
+msgid "All particles will be emitted from a single point."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:361
+msgid ""
+"Particles will be emitted on the surface of a sphere flattened to two "
+"dimensions."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:364
+msgid "Particles will be emitted in the area of a rectangle."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:367 doc/classes/CPUParticles3D.xml:376
+msgid ""
+"Particles will be emitted at a position chosen randomly among [member "
+"emission_points]. Particle color will be modulated by [member "
+"emission_colors]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:370 doc/classes/CPUParticles3D.xml:379
+msgid ""
+"Particles will be emitted at a position chosen randomly among [member "
+"emission_points]. Particle velocity and rotation will be set based on "
+"[member emission_normals]. Particle color will be modulated by [member "
+"emission_colors]."
+msgstr ""
+
+#: doc/classes/CPUParticles2D.xml:373 doc/classes/CPUParticles3D.xml:382
+#: doc/classes/ParticlesMaterial.xml:333
+msgid "Represents the size of the [enum EmissionShape] enum."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:4
+msgid "CPU-based 3D particle emitter."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:7
+msgid ""
+"CPU-based 3D particle node used to create a variety of particle systems and "
+"effects.\n"
+"See also [GPUParticles3D], which provides the same functionality with "
+"hardware acceleration, but may not run on older devices."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:19
+msgid ""
+"Sets this node's properties to match a given [GPUParticles3D] node with an "
+"assigned [ParticlesMaterial]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:151 doc/classes/CPUParticles3D.xml:154
+msgid "Unused for 3D particles."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:172
+msgid ""
+"The rectangle's extents if [member emission_shape] is set to [constant "
+"EMISSION_SHAPE_BOX]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:187
+msgid ""
+"The sphere's radius if [enum EmissionShape] is set to [constant "
+"EMISSION_SHAPE_SPHERE]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:196
+msgid ""
+"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 particle system itself."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:202 doc/classes/ParticlesMaterial.xml:177
+msgid "If [code]true[/code], particles will not move on the z axis."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:205 doc/classes/ParticlesMaterial.xml:180
+msgid "If [code]true[/code], particles rotate around Y axis by [member angle]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:208 doc/classes/ParticlesMaterial.xml:183
+msgid ""
+"Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts "
+"particles to X/Z plane."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:250
+msgid ""
+"The [Mesh] used for each particle. If [code]null[/code], particles will be "
+"spheres."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:256
+msgid ""
+"Orbital velocity applied to each particle. Makes the particles circle around "
+"origin in the local XY plane. Specified in number of full rotations around "
+"origin per second.\n"
+"This property is only available when [member flag_disable_z] is [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:293 doc/classes/ParticlesMaterial.xml:244
+msgid ""
+"Each particle's initial direction range from [code]+spread[/code] to [code]-"
+"spread[/code] degrees. Applied to X/Z plane and Y/Z planes."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:313 doc/classes/GPUParticles3D.xml:116
+msgid "Particles are drawn in order of depth."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:358
+msgid "Use with [method set_particle_flag] to set [member flag_rotate_y]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:361
+msgid "Use with [method set_particle_flag] to set [member flag_disable_z]."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:370 doc/classes/ParticlesMaterial.xml:321
+msgid "Particles will be emitted in the volume of a sphere."
+msgstr ""
+
+#: doc/classes/CPUParticles3D.xml:373 doc/classes/ParticlesMaterial.xml:324
+msgid "Particles will be emitted in the volume of a box."
+msgstr ""
+
+#: doc/classes/Crypto.xml:4
+msgid "Access to advanced cryptographic functionalities."
+msgstr ""
+
+#: doc/classes/Crypto.xml:7
+msgid ""
+"The Crypto class allows you to access some more advanced cryptographic "
+"functionalities in Godot.\n"
+"For now, this includes generating cryptographically secure random bytes, and "
+"RSA keys and self-signed X509 certificates generation. More functionalities "
+"are planned for future releases.\n"
+"[codeblock]\n"
+"extends Node\n"
+"\n"
+"var crypto = Crypto.new()\n"
+"var key = CryptoKey.new()\n"
+"var cert = X509Certificate.new()\n"
+"\n"
+"func _ready():\n"
+" # Generate new RSA key.\n"
+" key = crypto.generate_rsa(4096)\n"
+" # Generate new self-signed certificate with the given key.\n"
+" cert = crypto.generate_self_signed_certificate(key, \"CN=mydomain.com,"
+"O=My Game Company,C=IT\")\n"
+" # Save key and certificate in the user folder.\n"
+" key.save(\"user://generated.key\")\n"
+" cert.save(\"user://generated.crt\")\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/Crypto.xml:36
+msgid ""
+"Generates a [PackedByteArray] of cryptographically secure random bytes with "
+"given [code]size[/code]."
+msgstr ""
+
+#: doc/classes/Crypto.xml:45
+msgid ""
+"Generates an RSA [CryptoKey] that can be used for creating self-signed "
+"certificates and passed to [method StreamPeerSSL.accept_stream]."
+msgstr ""
+
+#: doc/classes/Crypto.xml:60
+msgid ""
+"Generates a self-signed [X509Certificate] from the given [CryptoKey] and "
+"[code]issuer_name[/code]. The certificate validity will be defined by "
+"[code]not_before[/code] and [code]not_after[/code] (first valid date and "
+"last valid date). The [code]issuer_name[/code] must contain at least \"CN="
+"\" (common name, i.e. the domain name), \"O=\" (organization, i.e. your "
+"company name), \"C=\" (country, i.e. 2 lettered ISO-3166 code of the country "
+"the organization is based in).\n"
+"A small example to generate an RSA key and a X509 self-signed certificate.\n"
+"[codeblock]\n"
+"var crypto = Crypto.new()\n"
+"# Generate 4096 bits RSA key.\n"
+"var key = crypto.generate_rsa(4096)\n"
+"# Generate self-signed certificate using the given key.\n"
+"var cert = crypto.generate_self_signed_certificate(key, \"CN=example.com,O=A "
+"Game Company,C=IT\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:4
+msgid "A cryptographic key (RSA)."
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:7
+msgid ""
+"The CryptoKey class represents a cryptographic key. Keys can be loaded and "
+"saved like any other [Resource].\n"
+"They can be used to generate a self-signed [X509Certificate] via [method "
+"Crypto.generate_self_signed_certificate] and as private key in [method "
+"StreamPeerSSL.accept_stream] along with the appropriate certificate.\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:20
+msgid "Loads a key from [code]path[/code] (\"*.key\" file)."
+msgstr ""
+
+#: doc/classes/CryptoKey.xml:29
+msgid ""
+"Saves a key to the given [code]path[/code] (should be a \"*.key\" file)."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:4
+msgid "A CSG Box shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:7
+msgid "This node allows you to create a box for use with the CSG system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:15
+msgid "Depth of the box measured from the center of the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:18
+msgid "Height of the box measured from the center of the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:21
+msgid "The material used to render the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGBox3D.xml:24
+msgid "Width of the box measured from the center of the box."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCombiner3D.xml:4
+msgid "A CSG node that allows you to combine other CSG modifiers."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCombiner3D.xml:7
+msgid ""
+"For complex arrangements of shapes, it is sometimes needed to add structure "
+"to your CSG nodes. The CSGCombiner3D node allows you to create this "
+"structure. The node encapsulates the result of the CSG operations of its "
+"children. In this way, it is possible to do operations on one set of shapes "
+"that are children of one CSGCombiner3D node, and a set of separate "
+"operations on a second set of shapes that are children of a second "
+"CSGCombiner3D node, and then do an operation that takes the two end results "
+"as its input to create the final shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:4
+msgid "A CSG Cylinder shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:7
+msgid ""
+"This node allows you to create a cylinder (or cone) for use with the CSG "
+"system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:15
+msgid ""
+"If [code]true[/code] a cone is created, the [member radius] will only apply "
+"to one side."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:18
+msgid "The height of the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:21
+msgid "The material used to render the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:24
+msgid "The radius of the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:27
+msgid ""
+"The number of sides of the cylinder, the higher this number the more detail "
+"there will be in the cylinder."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGCylinder3D.xml:30
+msgid ""
+"If [code]true[/code] the normals of the cylinder are set to give a smooth "
+"effect making the cylinder seem rounded. If [code]false[/code] the cylinder "
+"will have a flat shaded look."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:4
+msgid "A CSG Mesh shape that uses a mesh resource."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:15
+msgid "The [Material] used in drawing the CSG shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGMesh3D.xml:18
+msgid "The [Mesh] resource to use as a CSG shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:4
+msgid "Extrudes a 2D polygon shape to create a 3D mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:7
+msgid "This node takes a 2D polygon shape and extrudes it to create a 3D mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:15
+msgid "Extrusion depth when [member mode] is [constant MODE_DEPTH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:18
+msgid "Material to use for the resulting mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:21
+msgid "Extrusion mode."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:24
+msgid ""
+"If [code]true[/code] the u component of our uv will continuously increase in "
+"unison with the distance traveled along our path when [member mode] is "
+"[constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:27
+msgid ""
+"Interval at which a new extrusion slice is added along the path when [member "
+"mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:30
+msgid ""
+"If [code]true[/code] the start and end of our path are joined together "
+"ensuring there is no seam when [member mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:33
+msgid ""
+"If [code]false[/code] we extrude centered on our path, if [code]true[/code] "
+"we extrude in relation to the position of our CSGPolygon3D when [member "
+"mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:36
+msgid ""
+"The [Shape3D] object containing the path along which we extrude when [member "
+"mode] is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:39
+msgid ""
+"The method by which each slice is rotated along the path when [member mode] "
+"is [constant MODE_PATH]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:42
+msgid "Point array that defines the shape that we'll extrude."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:45
+msgid "Generates smooth normals so smooth shading is applied to our mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:48
+msgid ""
+"Degrees to rotate our extrusion for each slice when [member mode] is "
+"[constant MODE_SPIN]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:51
+msgid "Number of extrusion when [member mode] is [constant MODE_SPIN]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:56
+msgid "Shape3D is extruded to [member depth]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:59
+msgid "Shape3D is extruded by rotating it around an axis."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:62
+msgid ""
+"Shape3D is extruded along a path set by a [Shape3D] set in [member "
+"path_node]."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:65
+msgid "Slice is not rotated."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:68
+msgid "Slice is rotated around the up vector of the path."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPolygon3D.xml:71
+msgid "Slice is rotate to match the path exactly."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPrimitive3D.xml:4
+msgid "Base class for CSG primitives."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPrimitive3D.xml:7
+msgid ""
+"Parent class for various CSG primitives. It contains code and functionality "
+"that is common between them. It cannot be used directly. Instead use one of "
+"the various classes that inherit from it."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGPrimitive3D.xml:15
+msgid "Invert the faces of the mesh."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:4
+msgid "The CSG base class."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:7
+msgid ""
+"This is the CSG base class that provides CSG operation support to the "
+"various CSG nodes in Godot."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:34
+msgid ""
+"Returns an [Array] with two elements, the first is the [Transform] of this "
+"node and the second is the root [Mesh] of this node. Only works when this "
+"node is the root shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:41
+msgid ""
+"Returns [code]true[/code] if this is a root shape and is thus the object "
+"that is rendered."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:52 doc/classes/SoftBody3D.xml:64
+msgid ""
+"Sets individual bits on the layer mask. Use this if you only need to change "
+"one layer's value."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:63 doc/classes/SoftBody3D.xml:75
+msgid ""
+"Sets individual bits on the collision mask. Use this if you only need to "
+"change one layer's value."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:69
+msgid ""
+"Calculate tangents for the CSG shape which allows the use of normal maps. "
+"This is only applied on the root shape, this setting is ignored on any child."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:72
+msgid ""
+"The physics layers this area is in.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:77
+msgid "The physics layers this CSG shape scans for collisions."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:80
+msgid ""
+"The operation that is performed on this shape. This is ignored for the first "
+"CSG child node as the operation is between this node and the previous child "
+"of this nodes parent."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:83
+msgid ""
+"Snap makes the mesh snap to a given distance so that the faces of two meshes "
+"can be perfectly aligned. A lower value results in greater precision but may "
+"be harder to adjust."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:86
+msgid ""
+"Adds a collision shape to the physics engine for our CSG shape. This will "
+"always act like a static body. Note that the collision shape is still active "
+"even if the CSG shape itself is hidden."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:91
+msgid ""
+"Geometry of both primitives is merged, intersecting geometry is removed."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:94
+msgid "Only intersecting geometry remains, the rest is removed."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGShape3D.xml:97
+msgid ""
+"The second shape is subtracted from the first, leaving a dent with its shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:4
+msgid "A CSG Sphere shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:7
+msgid "This node allows you to create a sphere for use with the CSG system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:15
+msgid "The material used to render the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:18
+msgid "Number of vertical slices for the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:21
+msgid "Radius of the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:24
+msgid "Number of horizontal slices for the sphere."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGSphere3D.xml:27
+msgid ""
+"If [code]true[/code] the normals of the sphere are set to give a smooth "
+"effect making the sphere seem rounded. If [code]false[/code] the sphere will "
+"have a flat shaded look."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:4
+msgid "A CSG Torus shape."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:7
+msgid "This node allows you to create a torus for use with the CSG system."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:15
+msgid "The inner radius of the torus."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:18
+msgid "The material used to render the torus."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:21
+msgid "The outer radius of the torus."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:24
+msgid "The number of edges each ring of the torus is constructed of."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:27
+msgid "The number of slices the torus is constructed of."
+msgstr ""
+
+#: modules/csg/doc_classes/CSGTorus3D.xml:30
+msgid ""
+"If [code]true[/code] the normals of the torus are set to give a smooth "
+"effect making the torus seem rounded. If [code]false[/code] the torus will "
+"have a flat shaded look."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:4
+msgid "Generate an axis-aligned cuboid [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:7
+msgid ""
+"Generate an axis-aligned cuboid [PrimitiveMesh].\n"
+"The cube's UV layout is arranged in a 3×2 layout that allows texturing each "
+"face individually. To apply the same texture on all faces, change the "
+"material's UV property to [code]Vector3(3, 2, 1)[/code]."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:16
+msgid "Size of the cuboid mesh."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:19
+msgid "Number of extra edge loops inserted along the Z axis."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:22
+msgid "Number of extra edge loops inserted along the Y axis."
+msgstr ""
+
+#: doc/classes/CubeMesh.xml:25
+msgid "Number of extra edge loops inserted along the X axis."
+msgstr ""
+
+#: doc/classes/Curve.xml:4
+msgid "A mathematic curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:7
+msgid ""
+"A curve that can be saved and re-used for other objects. By default, it "
+"ranges between [code]0[/code] and [code]1[/code] on the Y axis and positions "
+"points relative to the [code]0.5[/code] Y position."
+msgstr ""
+
+#: doc/classes/Curve.xml:26
+msgid ""
+"Adds a point to the curve. For each side, if the [code]*_mode[/code] is "
+"[constant TANGENT_LINEAR], the [code]*_tangent[/code] angle (in degrees) "
+"uses the slope of the curve halfway to the adjacent point. Allows custom "
+"assignments to the [code]*_tangent[/code] angle if [code]*_mode[/code] is "
+"set to [constant TANGENT_FREE]."
+msgstr ""
+
+#: doc/classes/Curve.xml:33
+msgid "Recomputes the baked cache of points for the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:40
+msgid ""
+"Removes points that are closer than [code]CMP_EPSILON[/code] (0.00001) units "
+"to their neighbor on the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:47 doc/classes/Curve2D.xml:33
+#: doc/classes/Curve3D.xml:33
+msgid "Removes all points from the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:54 doc/classes/Curve2D.xml:74
+#: doc/classes/Curve3D.xml:89
+msgid "Returns the number of points describing the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:63
+msgid ""
+"Returns the left [enum TangentMode] for the point at [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:72
+msgid ""
+"Returns the left tangent angle (in degrees) for the point at [code]index[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:81
+msgid "Returns the curve coordinates for the point at [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:90
+msgid ""
+"Returns the right [enum TangentMode] for the point at [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:99
+msgid ""
+"Returns the right tangent angle (in degrees) for the point at [code]index[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:108
+msgid ""
+"Returns the Y value for the point that would exist at the X position "
+"[code]offset[/code] along the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:117
+msgid ""
+"Returns the Y value for the point that would exist at the X position "
+"[code]offset[/code] along the curve using the baked cache. Bakes the curve's "
+"points if not already baked."
+msgstr ""
+
+#: doc/classes/Curve.xml:126
+msgid "Removes the point at [code]index[/code] from the curve."
+msgstr ""
+
+#: doc/classes/Curve.xml:137
+msgid ""
+"Sets the left [enum TangentMode] for the point at [code]index[/code] to "
+"[code]mode[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:148
+msgid ""
+"Sets the left tangent angle for the point at [code]index[/code] to "
+"[code]tangent[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:159
+msgid "Sets the offset from [code]0.5[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:170
+msgid ""
+"Sets the right [enum TangentMode] for the point at [code]index[/code] to "
+"[code]mode[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:181
+msgid ""
+"Sets the right tangent angle for the point at [code]index[/code] to "
+"[code]tangent[/code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:192
+msgid ""
+"Assigns the vertical position [code]y[/code] to the point at [code]index[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Curve.xml:198
+msgid "The number of points to include in the baked (i.e. cached) curve data."
+msgstr ""
+
+#: doc/classes/Curve.xml:201
+msgid "The maximum value the curve can reach."
+msgstr ""
+
+#: doc/classes/Curve.xml:204
+msgid "The minimum value the curve can reach."
+msgstr ""
+
+#: doc/classes/Curve.xml:210
+msgid "Emitted when [member max_value] or [member min_value] is changed."
+msgstr ""
+
+#: doc/classes/Curve.xml:216
+msgid "The tangent on this side of the point is user-defined."
+msgstr ""
+
+#: doc/classes/Curve.xml:219
+msgid ""
+"The curve calculates the tangent on this side of the point as the slope "
+"halfway towards the adjacent point."
+msgstr ""
+
+#: doc/classes/Curve.xml:222
+msgid "The total number of available tangent modes."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:4
+msgid "Describes a Bézier curve in 2D space."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:7
+msgid ""
+"This class describes a Bézier curve in 2D space. It is mainly used to give a "
+"shape to a [Path2D], but can be manually sampled for other purposes.\n"
+"It keeps a cache of precalculated points along the curve, to speed up "
+"further calculations."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:25 doc/classes/Curve3D.xml:25
+msgid ""
+"Adds a point to a curve at [code]position[/code], with control points "
+"[code]in[/code] and [code]out[/code].\n"
+"If [code]at_position[/code] is given, the point is inserted before the point "
+"number [code]at_position[/code], moving that point (and every point after) "
+"after the inserted point. If [code]at_position[/code] is not given, or is an "
+"illegal value ([code]at_position <0[/code] or [code]at_position >= [method "
+"get_point_count][/code]), the point will be appended at the end of the point "
+"list."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:40 doc/classes/Curve3D.xml:40
+msgid ""
+"Returns the total length of the curve, based on the cached points. Given "
+"enough density (see [member bake_interval]), it should be approximate enough."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:47
+msgid "Returns the cache of points as a [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:56
+msgid ""
+"Returns the closest offset to [code]to_point[/code]. This offset is meant to "
+"be used in [method interpolate_baked].\n"
+"[code]to_point[/code] must be in this curve's local space."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:66 doc/classes/Curve3D.xml:81
+msgid ""
+"Returns the closest point (in curve's local space) to [code]to_point[/"
+"code].\n"
+"[code]to_point[/code] must be in this curve's local space."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:83
+msgid ""
+"Returns the position of the control point leading to the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console, and returns [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:92
+msgid ""
+"Returns the position of the control point leading out of the vertex "
+"[code]idx[/code]. If the index is out of bounds, the function sends an error "
+"to the console, and returns [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:101
+msgid ""
+"Returns the position of the vertex [code]idx[/code]. If the index is out of "
+"bounds, the function sends an error to the console, and returns [code](0, 0)"
+"[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:112
+msgid ""
+"Returns the position between the vertex [code]idx[/code] and the vertex "
+"[code]idx + 1[/code], where [code]t[/code] controls if the point is the "
+"first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), "
+"or in between. Values of [code]t[/code] outside the range ([code]0.0 >= t "
+"<=1[/code]) give strange, but predictable results.\n"
+"If [code]idx[/code] is out of bounds it is truncated to the first or last "
+"vertex, and [code]t[/code] is ignored. If the curve has no points, the "
+"function sends an error to the console, and returns [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:124 doc/classes/Curve3D.xml:148
+msgid ""
+"Returns a point within the curve at position [code]offset[/code], where "
+"[code]offset[/code] is measured as a pixel distance along the curve.\n"
+"To do that, it finds the two cached points where the [code]offset[/code] "
+"lies between, then interpolates the values. This interpolation is cubic if "
+"[code]cubic[/code] is set to [code]true[/code], or linear if set to "
+"[code]false[/code].\n"
+"Cubic interpolation tends to follow the curves better, but linear is faster "
+"(and often, precise enough)."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:135 doc/classes/Curve3D.xml:172
+msgid ""
+"Returns the position at the vertex [code]fofs[/code]. It calls [method "
+"interpolate] using the integer part of [code]fofs[/code] as [code]idx[/"
+"code], and its fractional part as [code]t[/code]."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:144 doc/classes/Curve3D.xml:181
+msgid ""
+"Deletes the point [code]idx[/code] from the curve. Sends an error to the "
+"console if [code]idx[/code] is out of bounds."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:155 doc/classes/Curve3D.xml:192
+msgid ""
+"Sets the position of the control point leading to the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:166 doc/classes/Curve3D.xml:203
+msgid ""
+"Sets the position of the control point leading out of the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:177 doc/classes/Curve3D.xml:214
+msgid ""
+"Sets the position for the vertex [code]idx[/code]. If the index is out of "
+"bounds, the function sends an error to the console."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:188 doc/classes/Curve3D.xml:237
+msgid ""
+"Returns a list of points along the curve, with a curvature controlled point "
+"density. That is, the curvier parts will have more points than the "
+"straighter parts.\n"
+"This approximation makes straight segments between each point, then "
+"subdivides those segments until the resulting shape is similar enough.\n"
+"[code]max_stages[/code] controls how many subdivisions a curve segment may "
+"face before it is considered approximate enough. Each subdivision splits the "
+"segment in half, so the default 5 stages may mean up to 32 subdivisions per "
+"curve segment. Increase with care!\n"
+"[code]tolerance_degrees[/code] controls how many degrees the midpoint of a "
+"segment may deviate from the real curve, before the segment has to be "
+"subdivided."
+msgstr ""
+
+#: doc/classes/Curve2D.xml:197
+msgid ""
+"The distance in pixels between two adjacent cached points. Changing it "
+"forces the cache to be recomputed the next time the [method "
+"get_baked_points] or [method get_baked_length] function is called. The "
+"smaller the distance, the more points in the cache and the more memory it "
+"will consume, so use with care."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:4
+msgid "Describes a Bézier curve in 3D space."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:7
+msgid ""
+"This class describes a Bézier curve in 3D space. It is mainly used to give a "
+"shape to a [Path3D], but can be manually sampled for other purposes.\n"
+"It keeps a cache of precalculated points along the curve, to speed up "
+"further calculations."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:47
+msgid "Returns the cache of points as a [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:54
+msgid "Returns the cache of tilts as a [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:61
+msgid ""
+"Returns the cache of up vectors as a [PackedVector3Array].\n"
+"If [member up_vector_enabled] is [code]false[/code], the cache will be empty."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:71
+msgid ""
+"Returns the closest offset to [code]to_point[/code]. This offset is meant to "
+"be used in [method interpolate_baked] or [method "
+"interpolate_baked_up_vector].\n"
+"[code]to_point[/code] must be in this curve's local space."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:98
+msgid ""
+"Returns the position of the control point leading to the vertex [code]idx[/"
+"code]. If the index is out of bounds, the function sends an error to the "
+"console, and returns [code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:107
+msgid ""
+"Returns the position of the control point leading out of the vertex "
+"[code]idx[/code]. If the index is out of bounds, the function sends an error "
+"to the console, and returns [code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:116
+msgid ""
+"Returns the position of the vertex [code]idx[/code]. If the index is out of "
+"bounds, the function sends an error to the console, and returns [code](0, 0, "
+"0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:125
+msgid ""
+"Returns the tilt angle in radians for the point [code]idx[/code]. If the "
+"index is out of bounds, the function sends an error to the console, and "
+"returns [code]0[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:136
+msgid ""
+"Returns the position between the vertex [code]idx[/code] and the vertex "
+"[code]idx + 1[/code], where [code]t[/code] controls if the point is the "
+"first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), "
+"or in between. Values of [code]t[/code] outside the range ([code]0.0 >= t "
+"<=1[/code]) give strange, but predictable results.\n"
+"If [code]idx[/code] is out of bounds it is truncated to the first or last "
+"vertex, and [code]t[/code] is ignored. If the curve has no points, the "
+"function sends an error to the console, and returns [code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:161
+msgid ""
+"Returns an up vector within the curve at position [code]offset[/code], where "
+"[code]offset[/code] is measured as a distance in 3D units along the curve.\n"
+"To do that, it finds the two cached up vectors where the [code]offset[/code] "
+"lies between, then interpolates the values. If [code]apply_tilt[/code] is "
+"[code]true[/code], an interpolated tilt is applied to the interpolated up "
+"vector.\n"
+"If the curve has no up vectors, the function sends an error to the console, "
+"and returns [code](0, 1, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:225
+msgid ""
+"Sets the tilt angle in radians for the point [code]idx[/code]. If the index "
+"is out of bounds, the function sends an error to the console.\n"
+"The tilt controls the rotation along the look-at axis an object traveling "
+"the path would have. In the case of a curve controlling a [PathFollow3D], "
+"this tilt is an offset over the natural tilt the [PathFollow3D] calculates."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:246
+msgid ""
+"The distance in meters between two adjacent cached points. Changing it "
+"forces the cache to be recomputed the next time the [method "
+"get_baked_points] or [method get_baked_length] function is called. The "
+"smaller the distance, the more points in the cache and the more memory it "
+"will consume, so use with care."
+msgstr ""
+
+#: doc/classes/Curve3D.xml:249
+msgid ""
+"If [code]true[/code], the curve will bake up vectors used for orientation. "
+"This is used when [member PathFollow3D.rotation_mode] is set to [constant "
+"PathFollow3D.ROTATION_ORIENTED]. Changing it forces the cache to be "
+"recomputed."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:4
+msgid "A texture that shows a curve."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:7
+msgid ""
+"Renders a given [Curve] provided to it. Simplifies the task of drawing "
+"curves and/or saving them as image files."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:15
+msgid "The [code]curve[/code] rendered onto the texture."
+msgstr ""
+
+#: doc/classes/CurveTexture.xml:18
+msgid "The width of the texture."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:4
+msgid "Class representing a cylindrical [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:7
+msgid ""
+"Class representing a cylindrical [PrimitiveMesh]. This class can be used to "
+"create cones by setting either the [member top_radius] or [member "
+"bottom_radius] properties to 0.0."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:15
+msgid "Bottom radius of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:18
+msgid "Full height of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:21
+msgid "Number of radial segments on the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:24
+msgid "Number of edge rings along the height of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderMesh.xml:27
+msgid "Top radius of the cylinder."
+msgstr ""
+
+#: doc/classes/CylinderShape3D.xml:4 doc/classes/CylinderShape3D.xml:7
+msgid "Cylinder shape for collisions."
+msgstr ""
+
+#: doc/classes/CylinderShape3D.xml:15
+msgid "The cylinder's height."
+msgstr ""
+
+#: doc/classes/CylinderShape3D.xml:18
+msgid "The cylinder's radius."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:4
+msgid "Damped spring constraint for 2D physics."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:7
+msgid ""
+"Damped spring constraint for 2D physics. This resembles a spring joint that "
+"always wants to go back to a given length."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:15
+msgid ""
+"The spring joint's damping ratio. A value between [code]0[/code] and "
+"[code]1[/code]. When the two bodies move into different directions the "
+"system tries to align them to the spring axis again. A high [code]damping[/"
+"code] value forces the attached bodies to align faster."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:18
+msgid ""
+"The spring joint's maximum length. The two attached bodies cannot stretch it "
+"past this value."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:21
+msgid ""
+"When the bodies attached to the spring joint move they stretch or squash it. "
+"The joint always tries to resize towards this length."
+msgstr ""
+
+#: doc/classes/DampedSpringJoint2D.xml:24
+msgid ""
+"The higher the value, the less the bodies attached to the joint will deform "
+"it. The joint applies an opposing force to the bodies, the product of the "
+"stiffness multiplied by the size difference from its resting length."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:4
+msgid "Dictionary type."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:7
+msgid ""
+"Dictionary type. Associative container which contains values referenced by "
+"unique keys. Dictionary are composed of pairs of keys (which must be unique) "
+"and values. You can define a dictionary by placing a comma separated list of "
+"[code]key: value[/code] pairs in curly braces [code]{}[/code].\n"
+"Erasing elements while iterating over them [b]is not supported[/b].\n"
+"Creating a dictionary:\n"
+"[codeblock]\n"
+"var my_dir = {} # Creates an empty dictionary.\n"
+"var points_dir = {\"White\": 50, \"Yellow\": 75, \"Orange\": 100}\n"
+"var my_dir = {\n"
+" key1: value1,\n"
+" key2: value2,\n"
+" key3: value3,\n"
+"}\n"
+"[/codeblock]\n"
+"You can access values of a dictionary by referencing appropriate key in "
+"above example [code]points_dir[\"White\"][/code] would return value of 50.\n"
+"[codeblock]\n"
+"export(String, \"White\", \"Yellow\", \"Orange\") var my_color\n"
+"var points_dir = {\"White\": 50, \"Yellow\": 75, \"Orange\": 100}\n"
+"\n"
+"func _ready():\n"
+" var points = points_dir[my_color]\n"
+"[/codeblock]\n"
+"In the above code [code]points[/code] will be assigned the value that is "
+"paired with the appropriate color selected in [code]my_color[/code].\n"
+"Dictionaries can contain more complex data:\n"
+"[codeblock]\n"
+"my_dir = {\"First Array\": [1, 2, 3, 4]} # Assigns an Array to a String "
+"key.\n"
+"[/codeblock]\n"
+"To add a key to an existing dictionary, access it like an existing key and "
+"assign to it:\n"
+"[codeblock]\n"
+"var points_dir = {\"White\": 50, \"Yellow\": 75, \"Orange\": 100}\n"
+"var points_dir[\"Blue\"] = 150 # Add \"Blue\" as a key and assign 150 as its "
+"value.\n"
+"[/codeblock]\n"
+"Finally, dictionaries can contain different types of keys and values in the "
+"same dictionary:\n"
+"[codeblock]\n"
+"var my_dir = {\"String Key\": 5, 4: [1, 2, 3], 7: \"Hello\"} # This is a "
+"valid dictionary.\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Unlike [Array]s you can't compare dictionaries directly:\n"
+"[codeblock]\n"
+"array1 = [1, 2, 3]\n"
+"array2 = [1, 2, 3]\n"
+"\n"
+"func compare_arrays():\n"
+" print(array1 == array2) # Will print true.\n"
+"\n"
+"dir1 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"dir2 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"\n"
+"func compare_dictionaries():\n"
+" print(dir1 == dir2) # Will NOT print true.\n"
+"[/codeblock]\n"
+"You need to first calculate the dictionary's hash with [method hash] before "
+"you can compare them:\n"
+"[codeblock]\n"
+"dir1 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"dir2 = {\"a\": 1, \"b\": 2, \"c\": 3}\n"
+"\n"
+"func compare_dictionaries():\n"
+" print(dir1.hash() == dir2.hash()) # Will print true.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Dictionary.xml:65
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/"
+"gdscript_basics.html#dictionary"
+msgstr ""
+
+#: doc/classes/Dictionary.xml:72
+msgid "Clear the dictionary, removing all key/value pairs."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:81
+msgid "Creates a copy of the dictionary, and returns it."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:88
+msgid "Returns [code]true[/code] if the dictionary is empty."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:97
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:108
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:117
+msgid "Returns [code]true[/code] if the dictionary has a given key."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:126
+msgid ""
+"Returns [code]true[/code] if the dictionary has all of the keys in the given "
+"array."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:133
+msgid ""
+"Returns a hashed integer value representing the dictionary contents. This "
+"can be used to compare dictionaries by value:\n"
+"[codeblock]\n"
+"var dict1 = {0: 10}\n"
+"var dict2 = {0: 10}\n"
+"# The line below prints `true`, whereas it would have printed `false` if "
+"both variables were compared directly.\n"
+"print(dict1.hash() == dict2.hash())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Dictionary.xml:146
+msgid "Returns the list of keys in the [Dictionary]."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:153
+msgid "Returns the size of the dictionary (in pairs)."
+msgstr ""
+
+#: doc/classes/Dictionary.xml:160
+msgid "Returns the list of values in the [Dictionary]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:4
+msgid "Directional light from a distance, as from the Sun."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:7
+msgid ""
+"A directional light is a type of [Light3D] node that models an infinite "
+"number of parallel rays covering the entire scene. It is used for lights "
+"with strong intensity that are located far away from the scene to model "
+"sunlight or moonlight. The worldspace location of the DirectionalLight3D "
+"transform (origin) is ignored. Only the basis is used to determine light "
+"direction."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:10 doc/classes/Light3D.xml:10
+#: doc/classes/OmniLight3D.xml:10 doc/classes/SpotLight3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html"
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:16
+msgid ""
+"Amount of extra bias for shadow splits that are far away. If self-shadowing "
+"occurs only on the splits far away, increasing this value can fix them."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:19
+msgid ""
+"If [code]true[/code], shadow detail is sacrificed in exchange for smoother "
+"transitions between splits."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:22
+msgid ""
+"Optimizes shadow rendering for detail versus movement. See [enum "
+"ShadowDepthRange]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:27
+msgid "The maximum distance for shadow splits."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:30
+msgid "The light's shadow rendering algorithm. See [enum ShadowMode]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:33
+msgid ""
+"Can be used to fix special cases of self shadowing when objects are "
+"perpendicular to the light."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:36
+msgid ""
+"The distance from camera to shadow split 1. Relative to [member "
+"directional_shadow_max_distance]. Only used when [member "
+"directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or "
+"[code]SHADOW_PARALLEL_4_SPLITS[/code]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:39
+msgid ""
+"The distance from shadow split 1 to split 2. Relative to [member "
+"directional_shadow_max_distance]. Only used when [member "
+"directional_shadow_mode] is [code]SHADOW_PARALLEL_2_SPLITS[/code] or "
+"[code]SHADOW_PARALLEL_4_SPLITS[/code]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:42
+msgid ""
+"The distance from shadow split 2 to split 3. Relative to [member "
+"directional_shadow_max_distance]. Only used when [member "
+"directional_shadow_mode] is [code]SHADOW_PARALLEL_4_SPLITS[/code]."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:48
+msgid ""
+"Renders the entire scene's shadow map from an orthogonal point of view. May "
+"result in blockier shadows on close objects."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:51
+msgid "Splits the view frustum in 2 areas, each with its own shadow map."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:54
+msgid "Splits the view frustum in 4 areas, each with its own shadow map."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:57
+msgid ""
+"Keeps the shadow stable when the camera moves, at the cost of lower "
+"effective shadow resolution."
+msgstr ""
+
+#: doc/classes/DirectionalLight3D.xml:60
+msgid ""
+"Tries to achieve maximum shadow resolution. May result in saw effect on "
+"shadow edges."
+msgstr ""
+
+#: doc/classes/Directory.xml:4
+msgid "Type used to handle the filesystem."
+msgstr ""
+
+#: doc/classes/Directory.xml:7
+msgid ""
+"Directory type. It is used to manage directories and their content (not "
+"restricted to the project folder).\n"
+"When creating a new [Directory], its default opened directory will be "
+"[code]res://[/code]. This may change in the future, so it is advised to "
+"always use [method open] to initialize your [Directory] where you want to "
+"operate, with explicit error checking.\n"
+"Here is an example on how to iterate through the files of a directory:\n"
+"[codeblock]\n"
+"func dir_contents(path):\n"
+" var dir = Directory.new()\n"
+" if dir.open(path) == OK:\n"
+" dir.list_dir_begin()\n"
+" var file_name = dir.get_next()\n"
+" while file_name != \"\":\n"
+" if dir.current_is_dir():\n"
+" print(\"Found directory: \" + file_name)\n"
+" else:\n"
+" print(\"Found file: \" + file_name)\n"
+" file_name = dir.get_next()\n"
+" else:\n"
+" print(\"An error occurred when trying to access the path.\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Directory.xml:27 doc/classes/File.xml:25
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"filesystem.html"
+msgstr ""
+
+#: doc/classes/Directory.xml:36
+msgid ""
+"Changes the currently opened directory to the one passed as an argument. The "
+"argument can be relative to the current directory (e.g. [code]newdir[/code] "
+"or [code]../newdir[/code]), or an absolute path (e.g. [code]/tmp/newdir[/"
+"code] or [code]res://somedir/newdir[/code]).\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:48
+msgid ""
+"Copies the [code]from[/code] file to the [code]to[/code] destination. Both "
+"arguments should be paths to files, either relative or absolute. If the "
+"destination file exists and is not access-protected, it will be "
+"overwritten.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:56
+msgid ""
+"Returns whether the current item processed with the last [method get_next] "
+"call is a directory ([code].[/code] and [code]..[/code] are considered "
+"directories)."
+msgstr ""
+
+#: doc/classes/Directory.xml:65
+msgid ""
+"Returns whether the target directory exists. The argument can be relative to "
+"the current directory, or an absolute path."
+msgstr ""
+
+#: doc/classes/Directory.xml:74
+msgid ""
+"Returns whether the target file exists. The argument can be relative to the "
+"current directory, or an absolute path."
+msgstr ""
+
+#: doc/classes/Directory.xml:81
+msgid ""
+"Returns the absolute path to the currently opened directory (e.g. "
+"[code]res://folder[/code] or [code]C:\\tmp\\folder[/code])."
+msgstr ""
+
+#: doc/classes/Directory.xml:88
+msgid ""
+"Returns the currently opened directory's drive index. See [method get_drive] "
+"to convert returned index to the name of the drive."
+msgstr ""
+
+#: doc/classes/Directory.xml:97
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Directory.xml:104
+msgid ""
+"On Windows, returns the number of drives (partitions) mounted on the current "
+"filesystem. On other platforms, the method returns 0."
+msgstr ""
+
+#: doc/classes/Directory.xml:111
+msgid ""
+"Returns the next element (file or directory) in the current directory "
+"(including [code].[/code] and [code]..[/code], unless "
+"[code]skip_navigational[/code] was given to [method list_dir_begin]).\n"
+"The name of the file or directory is returned (and not its full path). Once "
+"the stream has been fully processed, the method returns an empty String and "
+"closes the stream automatically (i.e. [method list_dir_end] would not be "
+"mandatory in such a case)."
+msgstr ""
+
+#: doc/classes/Directory.xml:119
+msgid ""
+"On UNIX desktop systems, returns the available space on the current "
+"directory's disk. On other platforms, this information is not available and "
+"the method returns 0 or -1."
+msgstr ""
+
+#: doc/classes/Directory.xml:130
+msgid ""
+"Initializes the stream used to list all files and directories using the "
+"[method get_next] function, closing the current opened stream if needed. "
+"Once the stream has been processed, it should typically be closed with "
+"[method list_dir_end].\n"
+"If [code]skip_navigational[/code] is [code]true[/code], [code].[/code] and "
+"[code]..[/code] are filtered out.\n"
+"If [code]skip_hidden[/code] is [code]true[/code], hidden files are filtered "
+"out."
+msgstr ""
+
+#: doc/classes/Directory.xml:139
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/Directory.xml:148
+msgid ""
+"Creates a directory. The argument can be relative to the current directory, "
+"or an absolute path. The target directory should be placed in an already "
+"existing directory (to create the full path recursively, see [method "
+"make_dir_recursive]).\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:158
+msgid ""
+"Creates a target directory and all necessary intermediate directories in its "
+"path, by calling [method make_dir] recursively. The argument can be relative "
+"to the current directory, or an absolute path.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:168
+msgid ""
+"Opens an existing directory of the filesystem. The [code]path[/code] "
+"argument can be within the project tree ([code]res://folder[/code]), the "
+"user directory ([code]user://folder[/code]) or an absolute path of the user "
+"filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\\tmp\\folder[/code]).\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:178
+msgid ""
+"Deletes the target file or an empty directory. The argument can be relative "
+"to the current directory, or an absolute path. If the target directory is "
+"not empty, the operation will fail.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/Directory.xml:190
+msgid ""
+"Renames (move) the [code]from[/code] file to the [code]to[/code] "
+"destination. Both arguments should be paths to files, either relative or "
+"absolute. If the destination file exists and is not access-protected, it "
+"will be overwritten.\n"
+"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:4
+msgid "Helper class to implement a DTLS server."
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:7
+msgid ""
+"This class is used to store the state of a DTLS server. Upon [method setup] "
+"it converts connected [PacketPeerUDP] to [PacketPeerDTLS] accepting them via "
+"[method take_connection] as DTLS clients. Under the hood, this class is used "
+"to store the DTLS state and cookies of the server. The reason of why the "
+"state and cookies are needed is outside of the scope of this documentation.\n"
+"Below a small example of how to use it:\n"
+"[codeblock]\n"
+"# server.gd\n"
+"extends Node\n"
+"\n"
+"var dtls := DTLSServer.new()\n"
+"var server := UDPServer.new()\n"
+"var peers = []\n"
+"\n"
+"func _ready():\n"
+" server.listen(4242)\n"
+" var key = load(\"key.key\") # Your private key.\n"
+" var cert = load(\"cert.crt\") # Your X509 certificate.\n"
+" dtls.setup(key, cert)\n"
+"\n"
+"func _process(delta):\n"
+" while server.is_connection_available():\n"
+" var peer : PacketPeerUDP = server.take_connection()\n"
+" var dtls_peer : PacketPeerDTLS = dtls.take_connection(peer)\n"
+" if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:\n"
+" continue # It is normal that 50% of the connections fails due to "
+"cookie exchange.\n"
+" print(\"Peer connected!\")\n"
+" peers.append(dtls_peer)\n"
+" for p in peers:\n"
+" p.poll() # Must poll to update the state.\n"
+" if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:\n"
+" while p.get_available_packet_count() > 0:\n"
+" print(\"Received message from client: %s\" % p.get_packet()."
+"get_string_from_utf8())\n"
+" p.put_packet(\"Hello DTLS client\".to_utf8())\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# client.gd\n"
+"extends Node\n"
+"\n"
+"var dtls := PacketPeerDTLS.new()\n"
+"var udp := PacketPeerUDP.new()\n"
+"var connected = false\n"
+"\n"
+"func _ready():\n"
+" udp.connect_to_host(\"127.0.0.1\", 4242)\n"
+" dtls.connect_to_peer(udp, false) # Use true in production for "
+"certificate validation!\n"
+"\n"
+"func _process(delta):\n"
+" dtls.poll()\n"
+" if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:\n"
+" if !connected:\n"
+" # Try to contact server\n"
+" dtls.put_packet(\"The answer is... 42!\".to_utf8())\n"
+" while dtls.get_available_packet_count() > 0:\n"
+" print(\"Connected: %s\" % dtls.get_packet()."
+"get_string_from_utf8())\n"
+" connected = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:74
+msgid ""
+"Setup the DTLS server to use the given [code]private_key[/code] and provide "
+"the given [code]certificate[/code] to clients. You can pass the optional "
+"[code]chain[/code] parameter to provide additional CA chain information "
+"along with the certificate."
+msgstr ""
+
+#: doc/classes/DTLSServer.xml:83
+msgid ""
+"Try to initiate the DTLS handshake with the given [code]udp_peer[/code] "
+"which must be already connected (see [method PacketPeerUDP."
+"connect_to_host]).\n"
+"[b]Note[/b]: You must check that the state of the return PacketPeerUDP is "
+"[constant PacketPeerDTLS.STATUS_HANDSHAKING], as it is normal that 50% of "
+"the new connections will be invalid due to cookie exchange."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:4
+msgid "DynamicFont renders vector font files at runtime."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:7
+msgid ""
+"DynamicFont renders vector font files (such as TTF or OTF) dynamically at "
+"runtime instead of using a prerendered texture atlas like [BitmapFont]. This "
+"trades the faster loading time of [BitmapFont]s for the ability to change "
+"font parameters like size and spacing during runtime. [DynamicFontData] is "
+"used for referencing the font file paths. DynamicFont also supports defining "
+"one or more fallbacks fonts, which will be used when displaying a character "
+"not supported by the main font.\n"
+"DynamicFont uses the [url=https://www.freetype.org/]FreeType[/url] library "
+"for rasterization.\n"
+"[codeblock]\n"
+"var dynamic_font = DynamicFont.new()\n"
+"dynamic_font.font_data = load(\"res://BarlowCondensed-Bold.ttf\")\n"
+"dynamic_font.size = 64\n"
+"$\"Label\".set(\"custom_fonts/font\", dynamic_font)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:25
+msgid "Adds a fallback font."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:34
+msgid "Returns the fallback font at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:41
+msgid "Returns the number of fallback fonts."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:50
+msgid ""
+"Returns the spacing for the given [code]type[/code] (see [enum SpacingType])."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:59
+msgid "Removes the fallback font at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:70
+msgid "Sets the fallback font at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:81
+msgid ""
+"Sets the spacing for [code]type[/code] (see [enum SpacingType]) to "
+"[code]value[/code] in pixels (not relative to the font size)."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:87
+msgid "Extra spacing at the bottom in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:90
+msgid "Extra character spacing in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:93
+msgid "Extra space spacing in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:96
+msgid "Extra spacing at the top in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:99
+msgid "The font data."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:102
+msgid ""
+"The font outline's color.\n"
+"[b]Note:[/b] It's recommended to leave this at the default value so that you "
+"can adjust it in individual controls. For example, if the outline is made "
+"black here, it won't be possible to change its color using a Label's font "
+"outline modulate theme item."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:106
+msgid "The font outline's thickness in pixels (not relative to the font size)."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:109
+msgid "The font size in pixels."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:114
+msgid "Spacing at the top."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:117
+msgid "Spacing at the bottom."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:120
+msgid "Character spacing."
+msgstr ""
+
+#: doc/classes/DynamicFont.xml:123
+msgid "Space spacing."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:4
+msgid "Used with [DynamicFont] to describe the location of a font file."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:7
+msgid ""
+"Used with [DynamicFont] to describe the location of a vector font file for "
+"dynamic rendering at runtime."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:15
+msgid "If [code]true[/code], the font is rendered with anti-aliasing."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:18
+msgid "The path to the vector font file."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:21
+msgid "The font hinting mode used by FreeType. See [enum Hinting] for options."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:26
+msgid "Disables font hinting (smoother but less crisp)."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:29
+msgid "Use the light font hinting mode."
+msgstr ""
+
+#: doc/classes/DynamicFontData.xml:32
+msgid "Use the default font hinting mode (crisper but less smooth)."
+msgstr ""
+
+#: doc/classes/EditorExportPlugin.xml:4
+msgid "A script that is executed when exporting projects."
+msgstr ""
+
+#: doc/classes/EditorExportPlugin.xml:23
+msgid ""
+"Virtual method to be overridden by the user. It is called when the export "
+"starts and provides all information about the export."
+msgstr ""
+
+#: doc/classes/EditorExportPlugin.xml:30
+msgid ""
+"Virtual method to be overridden by the user. Called when the export is "
+"finished."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:4
+msgid ""
+"An editor feature profile which can be used to disable specific features."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:7
+msgid ""
+"An editor feature profile can be used to disable specific features of the "
+"Godot editor. When disabled, the features won't appear in the editor, which "
+"makes the editor less cluttered. This is useful in education settings to "
+"reduce confusion or when working in a team. For example, artists and level "
+"designers could use a feature profile that disables the script editor to "
+"avoid accidentally making changes to files they aren't supposed to edit.\n"
+"To manage editor feature profiles visually, use [b]Editor > Manage Feature "
+"Profiles...[/b] at the top of the editor window."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:19
+msgid "Returns the specified [code]feature[/code]'s human-readable name."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:28
+msgid ""
+"Returns [code]true[/code] if the class specified by [code]class_name[/code] "
+"is disabled. When disabled, the class won't appear in the Create New Node "
+"dialog."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:37
+msgid ""
+"Returns [code]true[/code] if editing for the class specified by "
+"[code]class_name[/code] is disabled. When disabled, the class will still "
+"appear in the Create New Node dialog but the inspector will be read-only "
+"when selecting a node that extends the class."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:48
+msgid ""
+"Returns [code]true[/code] if [code]property[/code] is disabled in the class "
+"specified by [code]class_name[/code]. When a property is disabled, it won't "
+"appear in the inspector when selecting a node that extends the class "
+"specified by [code]class_name[/code]."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:57
+msgid ""
+"Returns [code]true[/code] if the [code]feature[/code] is disabled. When a "
+"feature is disabled, it will disappear from the editor entirely."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:66
+msgid ""
+"Loads an editor feature profile from a file. The file must follow the JSON "
+"format obtained by using the feature profile manager's [b]Export[/b] button "
+"or the [method save_to_file] method."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:75
+msgid ""
+"Saves the editor feature profile to a file in JSON format. It can then be "
+"imported using the feature profile manager's [b]Import[/b] button or the "
+"[method load_from_file] button."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:86
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables the class specified "
+"by [code]class_name[/code]. When disabled, the class won't appear in the "
+"Create New Node dialog."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:97
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables editing for the class "
+"specified by [code]class_name[/code]. When disabled, the class will still "
+"appear in the Create New Node dialog but the inspector will be read-only "
+"when selecting a node that extends the class."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:110
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables editing for "
+"[code]property[/code] in the class specified by [code]class_name[/code]. "
+"When a property is disabled, it won't appear in the inspector when selecting "
+"a node that extends the class specified by [code]class_name[/code]."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:121
+msgid ""
+"If [code]disable[/code] is [code]true[/code], disables the editor feature "
+"specified in [code]feature[/code]. When a feature is disabled, it will "
+"disappear from the editor entirely."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:127
+msgid ""
+"The 3D editor. If this feature is disabled, the 3D editor won't display but "
+"3D nodes will still display in the Create New Node dialog."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:130
+msgid ""
+"The Script tab, which contains the script editor and class reference "
+"browser. If this feature is disabled, the Script tab won't display."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:133
+msgid ""
+"The AssetLib tab. If this feature is disabled, the AssetLib tab won't "
+"display."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:136
+msgid ""
+"Scene tree editing. If this feature is disabled, the Scene tree dock will "
+"still be visible but will be read-only."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:139
+msgid ""
+"The Import dock. If this feature is disabled, the Import dock won't be "
+"visible."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:142
+msgid ""
+"The Node dock. If this feature is disabled, signals and groups won't be "
+"visible and modifiable from the editor."
+msgstr ""
+
+#: doc/classes/EditorFeatureProfile.xml:145
+msgid ""
+"The FileSystem dock. If this feature is disabled, the FileSystem dock won't "
+"be visible."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:4
+msgid "A modified version of [FileDialog] used by the editor."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:17
+msgid ""
+"Adds a comma-delimited file extension filter option to the "
+"[EditorFileDialog] with an optional semi-colon-delimited label.\n"
+"For example, [code]\"*.tscn, *.scn; Scenes\"[/code] results in filter text "
+"\"Scenes (*.tscn, *.scn)\"."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:25
+msgid "Removes all filters except for \"All Files (*)\"."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:32
+msgid "Returns the [code]VBoxContainer[/code] used to display the file system."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:39
+msgid ""
+"Notify the [EditorFileDialog] that its view of the data is no longer "
+"accurate. Updates the view contents on next view update."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:45
+msgid ""
+"The location from which the user may select a file, including [code]res://[/"
+"code], [code]user://[/code], and the local file system."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:48
+msgid "The currently occupied directory."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:51
+msgid "The currently selected file."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:54
+msgid "The file system path in the address bar."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:58
+msgid ""
+"If [code]true[/code], the [EditorFileDialog] will not warn the user before "
+"overwriting files."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:61
+msgid ""
+"The view format in which the [EditorFileDialog] displays resources to the "
+"user."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:64
+msgid ""
+"The dialog's open or save mode, which affects the selection behavior. See "
+"[enum FileMode]"
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:67
+msgid ""
+"If [code]true[/code], hidden files and directories will be visible in the "
+"[EditorFileDialog]."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:76
+msgid "Emitted when a directory is selected."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:83
+msgid "Emitted when a file is selected."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:90
+msgid "Emitted when multiple files are selected."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:96
+msgid ""
+"The [EditorFileDialog] can select only one file. Accepting the window will "
+"open the file."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:99
+msgid ""
+"The [EditorFileDialog] can select multiple files. Accepting the window will "
+"open all files."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:102
+msgid ""
+"The [EditorFileDialog] can select only one directory. Accepting the window "
+"will open the directory."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:105
+msgid ""
+"The [EditorFileDialog] can select a file or directory. Accepting the window "
+"will open it."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:108
+msgid ""
+"The [EditorFileDialog] can select only one file. Accepting the window will "
+"save the file."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:111
+msgid ""
+"The [EditorFileDialog] can only view [code]res://[/code] directory contents."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:114
+msgid ""
+"The [EditorFileDialog] can only view [code]user://[/code] directory contents."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:117
+msgid "The [EditorFileDialog] can view the entire local file system."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:120
+msgid "The [EditorFileDialog] displays resources as thumbnails."
+msgstr ""
+
+#: doc/classes/EditorFileDialog.xml:123
+msgid "The [EditorFileDialog] displays resources as a list of filenames."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:4
+msgid "Resource filesystem, as the editor sees it."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:7
+msgid ""
+"This object holds information of all resources in the filesystem, their "
+"types, etc."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:18
+msgid "Gets the type of the file, given the full path."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:25
+msgid "Gets the root directory object."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:34
+msgid "Returns a view into the filesystem at [code]path[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:41
+msgid "Returns the scan progress for 0 to 1 if the FS is being scanned."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:48
+msgid "Returns [code]true[/code] of the filesystem is being scanned."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:55
+msgid "Scan the filesystem for changes."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:62
+msgid "Check if the source of any imported resource changed."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:71
+msgid ""
+"Update a file information. Call this if an external program (not Godot) "
+"modified the file."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:78
+msgid "Scans the script files and updates the list of custom class names."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:85
+msgid "Emitted if the filesystem changed."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:92
+msgid "Remitted if a resource is reimported."
+msgstr ""
+
+#: doc/classes/EditorFileSystem.xml:105
+msgid "Emitted if the source of any imported file changed."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:4
+msgid "A directory for the resource filesystem."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:7
+msgid "A more generalized, low-level variation of the directory concept."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:18
+msgid ""
+"Returns the index of the directory with name [code]name[/code] or [code]-1[/"
+"code] if not found."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:27
+msgid ""
+"Returns the index of the file with name [code]name[/code] or [code]-1[/code] "
+"if not found."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:36
+msgid "Returns the name of the file at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:43
+msgid "Returns the number of files in this directory."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:52
+msgid ""
+"Returns [code]true[/code] if the file at index [code]idx[/code] imported "
+"properly."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:61
+msgid "Returns the path to the file at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:86
+msgid "Returns the file extension of the file at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:93
+msgid "Returns the name of this directory."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:100
+msgid ""
+"Returns the parent directory for this directory or [code]null[/code] if "
+"called on a directory at [code]res://[/code] or [code]user://[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:107
+msgid "Returns the path to this directory."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:116
+msgid "Returns the subdirectory at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/EditorFileSystemDirectory.xml:123
+msgid "Returns the number of subdirectories in this directory."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:4
+msgid ""
+"Registers a custom resource importer in the editor. Use the class to parse "
+"any file and import it as a new resource type."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:7
+msgid ""
+"EditorImportPlugins provide a way to extend the editor's resource import "
+"functionality. Use them to import resources from custom files or to provide "
+"alternatives to the editor's existing importers. Register your "
+"[EditorPlugin] with [method EditorPlugin.add_import_plugin].\n"
+"EditorImportPlugins work by associating with specific file extensions and a "
+"resource type. See [method get_recognized_extensions] and [method "
+"get_resource_type]. They may optionally specify some import presets that "
+"affect the import process. EditorImportPlugins are responsible for creating "
+"the resources and saving them in the [code].import[/code] directory.\n"
+"Below is an example EditorImportPlugin that imports a [Mesh] from a file "
+"with the extension \".special\" or \".spec\":\n"
+"[codeblock]\n"
+"tool\n"
+"extends EditorImportPlugin\n"
+"\n"
+"func get_importer_name():\n"
+" return \"my.special.plugin\"\n"
+"\n"
+"func get_visible_name():\n"
+" return \"Special Mesh Importer\"\n"
+"\n"
+"func get_recognized_extensions():\n"
+" return [\"special\", \"spec\"]\n"
+"\n"
+"func get_save_extension():\n"
+" return \"mesh\"\n"
+"\n"
+"func get_resource_type():\n"
+" return \"Mesh\"\n"
+"\n"
+"func get_preset_count():\n"
+" return 1\n"
+"\n"
+"func get_preset_name(i):\n"
+" return \"Default\"\n"
+"\n"
+"func get_import_options(i):\n"
+" return [{\"name\": \"my_option\", \"default_value\": false}]\n"
+"\n"
+"func import(source_file, save_path, options, platform_variants, gen_files):\n"
+" var file = File.new()\n"
+" if file.open(source_file, File.READ) != OK:\n"
+" return FAILED\n"
+"\n"
+" var mesh = Mesh.new()\n"
+" # Fill the Mesh with data read in \"file\", left as an exercise to the "
+"reader\n"
+"\n"
+" var filename = save_path + \".\" + get_save_extension()\n"
+" ResourceSaver.save(filename, mesh)\n"
+" return OK\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:52
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/"
+"import_plugins.html"
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:61
+msgid ""
+"Gets the options and default values for the preset at this index. Returns an "
+"Array of Dictionaries with the following keys: [code]name[/code], "
+"[code]default_value[/code], [code]property_hint[/code] (optional), "
+"[code]hint_string[/code] (optional), [code]usage[/code] (optional)."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:68
+msgid ""
+"Gets the order of this importer to be run when importing resources. Higher "
+"values will be called later. Use this to ensure the importer runs after the "
+"dependencies are already imported."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:75
+msgid "Gets the unique name of the importer."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:92
+msgid ""
+"Gets the number of initial presets defined by the plugin. Use [method "
+"get_import_options] to get the default options for the preset and [method "
+"get_preset_name] to get the name of the preset."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:101
+msgid "Gets the name of the options preset at this index."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:108
+msgid ""
+"Gets the priority of this plugin for the recognized extension. Higher "
+"priority plugins will be preferred. The default priority is [code]1.0[/code]."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:115
+msgid ""
+"Gets the list of file extensions to associate with this loader (case-"
+"insensitive). e.g. [code][\"obj\"][/code]."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:122
+msgid ""
+"Gets the Godot resource type associated with this loader. e.g. [code]\"Mesh"
+"\"[/code] or [code]\"Animation\"[/code]."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:129
+msgid ""
+"Gets the extension used to save this resource in the [code].import[/code] "
+"directory."
+msgstr ""
+
+#: doc/classes/EditorImportPlugin.xml:136
+msgid "Gets the name to display in the import window."
+msgstr ""
+
+#: doc/classes/EditorInspector.xml:4
+msgid "A tab used to edit properties of the selected node."
+msgstr ""
+
+#: doc/classes/EditorInspector.xml:7
+msgid ""
+"The editor inspector is by default located on the right-hand side of the "
+"editor. It's used to edit the properties of the selected node. For example, "
+"you can select a node such as the Sprite2D then edit its transform through "
+"the inspector tool. The editor inspector is an essential tool in the game "
+"development workflow."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:4
+msgid "Plugin for adding custom property editors on inspector."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:7
+msgid ""
+"This plugins allows adding custom property editors to [EditorInspector].\n"
+"Plugins are registered via [method EditorPlugin.add_inspector_plugin].\n"
+"When an object is edited, the [method can_handle] function is called and "
+"must return [code]true[/code] if the object type is supported.\n"
+"If supported, the function [method parse_begin] will be called, allowing to "
+"place custom controls at the beginning of the class.\n"
+"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.\n"
+"Finally [method parse_end] will be called.\n"
+"On each of these calls, the \"add\" functions can be called."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:24
+msgid "Adds a custom control, not necessarily a property editor."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:35
+msgid "Adds a property editor, this must inherit [EditorProperty]."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:48
+msgid ""
+"Adds an editor that allows modifying multiple properties, this must inherit "
+"[EditorProperty]."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:57
+msgid "Returns [code]true[/code] if this object can be handled by this plugin."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:66
+msgid "Called to allow adding controls at the beginning of the list."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:77
+msgid "Called to allow adding controls at the beginning of the category."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:84
+msgid "Called to allow adding controls at the end of the list."
+msgstr ""
+
+#: doc/classes/EditorInspectorPlugin.xml:103
+msgid ""
+"Called to allow adding property specific editors to the inspector. Usually "
+"these inherit [EditorProperty]. Returning [code]true[/code] removes the "
+"built-in editor for this property, otherwise allows to insert a custom "
+"editor before the built-in one."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:4
+msgid "Godot editor's interface."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:7
+msgid ""
+"EditorInterface gives you control over Godot editor's window. It allows "
+"customizing the window, saving and (re-)loading scenes, rendering mesh "
+"previews, inspecting and editing resources and objects, and provides access "
+"to [EditorSettings], [EditorFileSystem], [EditorResourcePreview], "
+"[ScriptEditor], the editor viewport, and information about scenes."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:18
+msgid "Edits the given [Resource]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:25
+msgid ""
+"Returns the main container of Godot editor's window. You can use it, for "
+"example, to retrieve the size of the container and place your controls "
+"accordingly."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:38
+msgid "Returns the edited (current) scene's root [Node]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:45
+msgid "Returns the [EditorSettings]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:52
+msgid "Returns the editor [Viewport]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:71
+msgid "Returns an [Array] with the file paths of the currently opened scenes."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:78
+msgid "Returns the [EditorFileSystem]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:85
+msgid "Returns the [EditorResourcePreview]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:92
+msgid "Returns the [ScriptEditor]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:105
+msgid "Returns the [EditorSelection]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:116
+msgid ""
+"Shows the given property on the given [code]object[/code] in the Editor's "
+"Inspector dock."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:125
+msgid ""
+"Returns the enabled status of a plugin. The plugin name is the same as its "
+"directory name."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:136
+msgid ""
+"Returns mesh previews rendered at the given size as an [Array] of "
+"[Texture2D]s."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:145
+msgid "Opens the scene at the given path."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:154
+msgid "Reloads the scene at the given path."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:161
+msgid ""
+"Saves the scene. Returns either [code]OK[/code] or [code]ERR_CANT_CREATE[/"
+"code] (see [@GlobalScope] constants)."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:172
+msgid "Saves the scene as a file at [code]path[/code]."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:181
+msgid ""
+"Selects the file, with the path provided by [code]file[/code], in the "
+"FileSystem dock."
+msgstr ""
+
+#: doc/classes/EditorInterface.xml:208
+msgid ""
+"Sets the enabled status of a plugin. The plugin name is the same as its "
+"directory name."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:4
+msgid "Custom gizmo for editing Node3D objects."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:7
+msgid ""
+"Custom gizmo that is used for providing custom visualization and editing "
+"(handles) for Node3D objects. See [EditorNode3DGizmoPlugin] for more "
+"information."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:26
+msgid ""
+"Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be "
+"generated from a regular [Mesh] too. Call this function during [method "
+"redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:41
+msgid ""
+"Adds a list of handles (points) which can be used to deform the object being "
+"edited.\n"
+"There are virtual functions which will be called upon editing of these "
+"handles. Call this function during [method redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:57
+msgid ""
+"Adds lines to the gizmo (as sets of 2 points), with a given material. The "
+"lines are used for visualizing the gizmo. Call this function during [method "
+"redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:84
+msgid ""
+"Adds an unscaled billboard for visualization. Call this function during "
+"[method redraw]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:103
+msgid ""
+"Commit a handle being edited (handles must have been previously added by "
+"[method add_handles]).\n"
+"If the [code]cancel[/code] parameter is [code]true[/code], an option to "
+"restore the edited value to the original is provided."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:113
+msgid ""
+"Gets the name of an edited handle (handles must have been previously added "
+"by [method add_handles]).\n"
+"Handles can be named for reference to the user when editing."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:123
+msgid ""
+"Gets actual value of a handle. This value can be anything and used for "
+"eventually undoing the motion when calling [method commit_handle]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:130
+msgid ""
+"Returns the [EditorNode3DGizmoPlugin] that owns this gizmo. It's useful to "
+"retrieve materials using [method EditorNode3DGizmoPlugin.get_material]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:137
+msgid "Returns the Node3D node associated with this gizmo."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:146
+msgid "Gets whether a handle is highlighted or not."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:153
+msgid ""
+"This function is called when the Node3D this gizmo refers to changes (the "
+"[method Node3D.update_gizmo] is called)."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmo.xml:166
+msgid ""
+"This function is used when the user drags a gizmo handle (previously added "
+"with [method add_handles]) in screen coordinates.\n"
+"The [Camera3D] is also provided so screen coordinates can be converted to "
+"raycasts."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:4
+msgid "Used by the editor to define Node3D gizmo types."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:7
+msgid ""
+"EditorNode3DGizmoPlugin allows you to define a new type of Gizmo. There are "
+"two main ways to do so: extending [EditorNode3DGizmoPlugin] for the simpler "
+"gizmos, or creating a new [EditorNode3DGizmo] type. See the tutorial in the "
+"documentation for more info."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/"
+"spatial_gizmos.html"
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:21
+msgid ""
+"Adds a new material to the internal material list for the plugin. It can "
+"then be accessed with [method get_material]. Should not be overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:28
+msgid ""
+"Override this method to define whether the gizmo can be hidden or not. "
+"Returns [code]true[/code] if not overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:43
+msgid ""
+"Override this method to commit gizmo handles. Called for this plugin's "
+"active gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:52
+msgid ""
+"Override this method to return a custom [EditorNode3DGizmo] for the spatial "
+"nodes of your choice, return [code]null[/code] for the rest of nodes. See "
+"also [method has_gizmo]."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:63
+msgid ""
+"Creates a handle 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_handles]. "
+"Should not be overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:78
+msgid ""
+"Creates an icon 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_unscaled_billboard]. Should not be overridden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:95
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:106
+msgid ""
+"Override this method to provide gizmo's handle names. Called for this "
+"plugin's active gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:117
+msgid ""
+"Gets actual value of a handle from gizmo. Called for this plugin's active "
+"gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:128
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:135
+msgid ""
+"Override this method to provide the name that will appear in the gizmo "
+"visibility menu."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:150
+msgid ""
+"Override this method to define which Node3D nodes have a gizmo from this "
+"plugin. Whenever a [Node3D] node is added to a scene this method is called, "
+"if it returns [code]true[/code] the node gets a generic [EditorNode3DGizmo] "
+"assigned and is added to this plugin's list of active gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:161
+msgid ""
+"Gets whether a handle is highlighted or not. Called for this plugin's active "
+"gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:168
+msgid ""
+"Override this method to define whether Node3D with this gizmo should be "
+"selecteble even when the gizmo is hidden."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:177
+msgid ""
+"Callback to redraw the provided gizmo. Called for this plugin's active "
+"gizmos."
+msgstr ""
+
+#: doc/classes/EditorNode3DGizmoPlugin.xml:192
+msgid ""
+"Update the value of a handle after it has been updated. Called for this "
+"plugin's active gizmos."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:4
+msgid "Used by the editor to extend its functionality."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:7
+msgid ""
+"Plugins are used by the editor to extend functionality. The most common "
+"types of plugins are those which edit a given node or resource type, import "
+"plugins and export plugins. See also [EditorScript] to add functions to the "
+"editor."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/index.html"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:21
+msgid ""
+"Adds a script at [code]path[/code] to the Autoload list as [code]name[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:32
+msgid ""
+"Adds a control to the bottom panel (together with Output, Debug, Animation, "
+"etc). Returns a reference to the button added. It's up to you to hide/show "
+"the button when needed. When your plugin is deactivated, make sure to remove "
+"your custom control with [method remove_control_from_bottom_panel] and free "
+"it with [method Node.queue_free]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:43
+msgid ""
+"Adds a custom control to a container (see [enum CustomControlContainer]). "
+"There are many locations where custom controls can be added in the editor "
+"UI.\n"
+"Please remember that you have to manage the visibility of your custom "
+"controls yourself (and likely hide it after adding it).\n"
+"When your plugin is deactivated, make sure to remove your custom control "
+"with [method remove_control_from_container] and free it with [method Node."
+"queue_free]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:56
+msgid ""
+"Adds the control to a specific dock slot (see [enum DockSlot] for options).\n"
+"If the dock is repositioned and as long as the plugin is active, the editor "
+"will save the dock position on further sessions.\n"
+"When your plugin is deactivated, make sure to remove your custom control "
+"with [method remove_control_from_docks] and free it with [method Node."
+"queue_free]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:73
+msgid ""
+"Adds a custom type, which will appear in the list of nodes or resources. An "
+"icon can be optionally passed.\n"
+"When given node or resource is selected, the base type will be instanced (e."
+"g. \"Node3D\", \"Control\", \"Resource\"), then the script will be loaded "
+"and set to this object.\n"
+"You can use the virtual method [method handles] to check if your custom "
+"object is being edited by checking the script or using the [code]is[/code] "
+"keyword.\n"
+"During run-time, this will be a simple object with a script so this function "
+"does not need to be called then."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:131
+msgid ""
+"Adds a custom menu item to [b]Project > Tools[/b] as [code]name[/code] that "
+"calls [code]callback[/code] on an instance of [code]handler[/code] with a "
+"parameter [code]ud[/code] when user activates it."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:142
+msgid ""
+"Adds a custom submenu under [b]Project > Tools >[/b] [code]name[/code]. "
+"[code]submenu[/code] should be an object of class [PopupMenu]. This submenu "
+"should be cleaned up using [code]remove_tool_menu_item(name)[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:149
+msgid ""
+"This method is called when the editor is about to save the project, switch "
+"to another tab, etc. It asks the plugin to apply any pending state changes "
+"to ensure consistency.\n"
+"This is used, for example, in shader editors to let the plugin know that it "
+"must apply the shader code being written by the user to the object."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:163
+msgid ""
+"Clear all the state and reset the object being edited to zero. This ensures "
+"your plugin does not keep editing a currently existing node, or a node from "
+"the wrong scene."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:170
+msgid ""
+"Called by the engine when the user disables the [EditorPlugin] in the Plugin "
+"tab of the project settings window."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:179
+msgid ""
+"This function is used for plugins that edit specific object types (nodes or "
+"resources). It requests the editor to edit the given object."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:186
+msgid ""
+"Called by the engine when the user enables the [EditorPlugin] in the Plugin "
+"tab of the project settings window."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:211
+msgid ""
+"Called when there is a root node in the current edited scene, [method "
+"handles] is implemented and an [InputEvent] happens in the 2D viewport. "
+"Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] "
+"consumes the [code]event[/code], otherwise forwards [code]event[/code] to "
+"other Editor classes. Example:\n"
+"[codeblock]\n"
+"# Prevents the InputEvent to reach other Editor classes\n"
+"func forward_canvas_gui_input(event):\n"
+" var forward = true\n"
+" return forward\n"
+"[/codeblock]\n"
+"Must [code]return false[/code] in order to forward the [InputEvent] to other "
+"Editor classes. Example:\n"
+"[codeblock]\n"
+"# Consumes InputEventMouseMotion and forwards other InputEvent types\n"
+"func forward_canvas_gui_input(event):\n"
+" var forward = false\n"
+" if event is InputEventMouseMotion:\n"
+" forward = true\n"
+" return forward\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:237
+msgid ""
+"Called when there is a root node in the current edited scene, [method "
+"handles] is implemented and an [InputEvent] happens in the 3D viewport. "
+"Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] "
+"consumes the [code]event[/code], otherwise forwards [code]event[/code] to "
+"other Editor classes. Example:\n"
+"[codeblock]\n"
+"# Prevents the InputEvent to reach other Editor classes\n"
+"func forward_spatial_gui_input(camera, event):\n"
+" var forward = true\n"
+" return forward\n"
+"[/codeblock]\n"
+"Must [code]return false[/code] in order to forward the [InputEvent] to other "
+"Editor classes. Example:\n"
+"[codeblock]\n"
+"# Consumes InputEventMouseMotion and forwards other InputEvent types\n"
+"func forward_spatial_gui_input(camera, event):\n"
+" var forward = false\n"
+" if event is InputEventMouseMotion:\n"
+" forward = true\n"
+" return forward\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:259
+msgid ""
+"This is for editors that edit script-based objects. You can return a list of "
+"breakpoints in the format ([code]script:line[/code]), for example: "
+"[code]res://path_to_script.gd:25[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:266
+msgid ""
+"Returns the [EditorInterface] object that gives you control over Godot "
+"editor's window and its functionalities."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:273
+msgid ""
+"Override this method in your plugin to return a [Texture2D] in order to give "
+"it an icon.\n"
+"For main screen plugins, this appears at the top of the screen, to the right "
+"of the \"2D\", \"3D\", \"Script\", and \"AssetLib\" buttons.\n"
+"Ideally, the plugin icon should be white with a transparent background and "
+"16x16 pixels in size.\n"
+"[codeblock]\n"
+"func get_plugin_icon():\n"
+" # You can use a custom icon:\n"
+" return preload(\"res://addons/my_plugin/my_plugin_icon.svg\")\n"
+" # Or use a built-in icon:\n"
+" return get_editor_interface().get_base_control().get_icon(\"Node\", "
+"\"EditorIcons\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:289
+msgid ""
+"Override this method in your plugin to provide the name of the plugin when "
+"displayed in the Godot editor.\n"
+"For main screen plugins, this appears at the top of the screen, to the right "
+"of the \"2D\", \"3D\", \"Script\", and \"AssetLib\" buttons."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:297
+msgid ""
+"Gets the Editor's dialogue used for making scripts.\n"
+"[b]Note:[/b] Users can configure it before use."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:305
+msgid ""
+"Gets the state of your plugin editor. This is used when saving the scene (so "
+"state is kept when opening it again) and for switching tabs (so state can be "
+"restored when the tab returns)."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:312
+msgid ""
+"Gets the undo/redo object. Most actions in the editor can be undoable, so "
+"use this object to make sure this happens when it's worth it."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:321
+msgid ""
+"Gets the GUI layout of the plugin. This is used to save the project's editor "
+"layout when [method queue_save_layout] is called or the editor layout was "
+"changed(For example changing the position of a dock)."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:330
+msgid ""
+"Implement this function if your plugin edits a specific type of object "
+"(Resource or Node). If you return [code]true[/code], then you will get the "
+"functions [method edit] and [method make_visible] called when the editor "
+"requests them. If you have declared the methods [method "
+"forward_canvas_gui_input] and [method forward_spatial_gui_input] these will "
+"be called too."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:337
+msgid ""
+"Returns [code]true[/code] if this is a main screen editor plugin (it goes in "
+"the workspace selector together with [b]2D[/b], [b]3D[/b], [b]Script[/b] and "
+"[b]AssetLib[/b])."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:360
+msgid ""
+"This function will be called when the editor is requested to become visible. "
+"It is used for plugins that edit a specific object type.\n"
+"Remember that you have to manage the visibility of all your editor controls "
+"manually."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:368
+msgid "Queue save the project's editor layout."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:377
+msgid "Removes an Autoload [code]name[/code] from the list."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:386
+msgid ""
+"Removes the control from the bottom panel. You have to manually [method Node."
+"queue_free] the control."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:397
+msgid ""
+"Removes the control from the specified container. You have to manually "
+"[method Node.queue_free] the control."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:406
+msgid ""
+"Removes the control from the dock. You have to manually [method Node."
+"queue_free] the control."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:415
+msgid "Removes a custom type added by [method add_custom_type]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:464
+msgid "Removes a menu [code]name[/code] from [b]Project > Tools[/b]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:471
+msgid ""
+"This method is called after the editor saves the project or when it's "
+"closed. It asks the plugin to save edited external scenes/resources."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:484
+msgid ""
+"Use this method if you always want to receive inputs from 3D view screen "
+"inside [method forward_spatial_gui_input]. It might be especially usable if "
+"your plugin will want to use raycast in the scene."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:493
+msgid "Restore the state saved by [method get_state]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:502
+msgid "Restore the plugin GUI layout saved by [method get_window_layout]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:509
+msgid "Updates the overlays of the editor (2D/3D) viewport."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:518
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:531
+msgid ""
+"Emitted when the scene is changed in the editor. The argument will return "
+"the root node of the scene that has just become active. If this scene is new "
+"and empty, the argument will be [code]null[/code]."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:538
+msgid ""
+"Emitted when user closes a scene. The argument is file path to a closed "
+"scene."
+msgstr ""
+
+#: doc/classes/EditorPlugin.xml:584
+msgid "Represents the size of the [enum DockSlot] enum."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:4
+msgid "Custom control to edit properties for adding into the inspector."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:7
+msgid ""
+"This control allows property editing for one or multiple properties into "
+"[EditorInspector]. It is added via [EditorInspectorPlugin]."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:18
+msgid ""
+"If any of the controls added can gain keyboard focus, add it here. This "
+"ensures that focus will be restored if the inspector is refreshed."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:33
+msgid ""
+"If one or several properties have changed, this must be called. [code]field[/"
+"code] is used in case your editor can modify fields separately (as an "
+"example, Vector3.x). The [code]changing[/code] argument avoids the editor "
+"requesting this property to be refreshed (leave as [code]false[/code] if "
+"unsure)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:40
+msgid "Gets the edited object."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:47
+msgid ""
+"Gets the edited property. If your editor is for a single property (added via "
+"[method EditorInspectorPlugin.parse_property]), then this will return the "
+"property."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:54
+msgid "Override if you want to allow a custom tooltip over your property."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:63
+msgid ""
+"Adds controls with this function if you want them on the bottom (below the "
+"label)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:70
+msgid "When this virtual function is called, you must update your editor."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:76
+msgid "Used by the inspector, set when property is checkable."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:79
+msgid "Used by the inspector, when the property is checked."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:82
+msgid "Used by the inspector, when the property must draw with error color."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:85
+msgid "Used by the inspector, when the property can add keys for animation."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:88
+msgid "Sets this property to change the label (if you want to show one)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:91
+msgid "Used by the inspector, when the property is read-only."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:101
+msgid ""
+"Emit it if you want multiple properties modified at the same time. Do not "
+"use if added via [method EditorInspectorPlugin.parse_property]."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:110
+msgid "Used by sub-inspectors. Emit it if what was selected was an Object ID."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:119
+msgid ""
+"Do not emit this manually, use the [method emit_changed] method instead."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:128
+msgid "Emitted when a property was checked. Used internally."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:135
+msgid ""
+"Emit it if you want to add this value as an animation key (check for keying "
+"being enabled first)."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:144
+msgid "Emit it if you want to key a property with a single value."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:153
+msgid ""
+"If you want a sub-resource to be edited, emit this signal with the resource."
+msgstr ""
+
+#: doc/classes/EditorProperty.xml:162
+msgid "Emitted when selected. Used internally."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:4
+msgid "Helper to generate previews of resources or files."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:7
+msgid "This object is used to generate previews for resources of files."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:18
+msgid "Create an own, custom preview generator."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:27
+msgid ""
+"Check if the resource changed, if so, it will be invalidated and the "
+"corresponding signal emitted."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:42
+msgid ""
+"Queue a resource being edited for preview (using an instance). Once the "
+"preview is ready, your receiver.receiver_func will be called either "
+"containing the preview texture or an empty texture (if no preview was "
+"possible). Callback must have the format: (path,texture,userdata). Userdata "
+"can be anything."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:57
+msgid ""
+"Queue a resource file for preview (using a path). Once the preview is ready, "
+"your receiver.receiver_func will be called either containing the preview "
+"texture or an empty texture (if no preview was possible). Callback must have "
+"the format: (path,texture,userdata). Userdata can be anything."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:66
+msgid "Removes a custom preview generator."
+msgstr ""
+
+#: doc/classes/EditorResourcePreview.xml:75
+msgid ""
+"Emitted if a preview was invalidated (changed). [code]path[/code] "
+"corresponds to the path of the preview."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:4
+msgid "Custom generator of previews."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:7
+msgid ""
+"Custom code to generate previews. Please check [code]file_dialog/"
+"thumbnail_size[/code] in [EditorSettings] to find out the right size to do "
+"previews at."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:16
+msgid ""
+"If this function returns [code]true[/code], the generator will call [method "
+"generate] or [method generate_from_path] for small previews as well.\n"
+"By default, it returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:28
+msgid ""
+"Generate a preview from a given resource with the specified size. This must "
+"always be implemented.\n"
+"Returning an empty texture is an OK way to fail and let another generator "
+"take care.\n"
+"Care must be taken because this function is always called from a thread (not "
+"the main thread)."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:41
+msgid ""
+"Generate a preview directly from a path with the specified size. "
+"Implementing this is optional, as default code will load and call [method "
+"generate].\n"
+"Returning an empty texture is an OK way to fail and let another generator "
+"take care.\n"
+"Care must be taken because this function is always called from a thread (not "
+"the main thread)."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:50
+msgid ""
+"If this function returns [code]true[/code], the generator will automatically "
+"generate the small previews from the normal preview texture generated by the "
+"methods [method generate] or [method generate_from_path].\n"
+"By default, it returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorResourcePreviewGenerator.xml:60
+msgid ""
+"Returns [code]true[/code] if your generator supports the resource of type "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/EditorSceneImporter.xml:4
+msgid "Imports scenes from third-parties' 3D files."
+msgstr ""
+
+#: doc/classes/EditorSceneImporterAssimp.xml:4
+msgid "FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/url]."
+msgstr ""
+
+#: doc/classes/EditorSceneImporterAssimp.xml:7
+msgid ""
+"This is an FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/"
+"url]. It currently has many known limitations and works best with static "
+"meshes. Most animated meshes won't import correctly.\n"
+"If exporting a FBX scene from Autodesk Maya, use these FBX export settings:\n"
+"[codeblock]\n"
+"- Smoothing Groups\n"
+"- Smooth Mesh\n"
+"- Triangluate (for meshes with blend shapes)\n"
+"- Bake Animation\n"
+"- Resample All\n"
+"- Deformed Models\n"
+"- Skins\n"
+"- Blend Shapes\n"
+"- Curve Filters\n"
+"- Constant Key Reducer\n"
+"- Auto Tangents Only\n"
+"- *Do not check* Constraints (as it will break the file)\n"
+"- Can check Embed Media (embeds textures into the exported FBX file)\n"
+" - Note that when importing embedded media, the texture and mesh will be a "
+"single immutable file.\n"
+" - You will have to re-export then re-import the FBX if the texture has "
+"changed.\n"
+"- Units: Centimeters\n"
+"- Up Axis: Y\n"
+"- Binary format in FBX 2017\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:4
+msgid "Post-processes scenes after import."
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:7
+msgid ""
+"Imported scenes can be automatically modified right after import by setting "
+"their [b]Custom Script[/b] Import property to a [code]tool[/code] script "
+"that inherits from this class.\n"
+"The [method post_import] callback receives the imported scene's root node "
+"and returns the modified version of the scene. Usage example:\n"
+"[codeblock]\n"
+"tool # Needed so it runs in editor\n"
+"extends EditorScenePostImport\n"
+"\n"
+"# This sample changes all node names\n"
+"\n"
+"# Called right after the scene is imported and gets the root node\n"
+"func post_import(scene):\n"
+" # Change all node names to \"modified_[oldnodename]\"\n"
+" iterate(scene)\n"
+" return scene # Remember to return the imported scene\n"
+"\n"
+"func iterate(node):\n"
+" if node != null:\n"
+" node.name = \"modified_\" + node.name\n"
+" for child in node.get_children():\n"
+" iterate(child)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:29
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/workflow/assets/"
+"importing_scenes.html#custom-script"
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:36
+msgid ""
+"Returns the source file path which got imported (e.g. [code]res://scene.dae[/"
+"code])."
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:43
+msgid "Returns the resource folder the imported scene file is located in."
+msgstr ""
+
+#: doc/classes/EditorScenePostImport.xml:52
+msgid ""
+"Called after the scene was imported. This method must return the modified "
+"version of the scene."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:4
+msgid "Base script that can be used to add extension functions to the editor."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:7
+msgid ""
+"Scripts extending this class and implementing its [method _run] method can "
+"be executed from the Script Editor's [b]File > Run[/b] menu option (or by "
+"pressing [code]Ctrl+Shift+X[/code]) while the editor is running. This is "
+"useful for adding custom in-editor functionality to Godot. For more complex "
+"additions, consider using [EditorPlugin]s instead.\n"
+"[b]Note:[/b] Extending scripts need to have [code]tool[/code] mode enabled.\n"
+"[b]Example script:[/b]\n"
+"[codeblock]\n"
+"tool\n"
+"extends EditorScript\n"
+"\n"
+"func _run():\n"
+" print(\"Hello from the Godot Editor!\")\n"
+"[/codeblock]\n"
+"[b]Note:[/b] The script is run in the Editor context, which means the output "
+"is visible in the console window started with the Editor (stdout) instead of "
+"the usual Godot [b]Output[/b] dock."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:26
+msgid "This method is executed by the Editor when [b]File > Run[/b] is used."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:35
+msgid ""
+"Adds [code]node[/code] as a child of the root node in the editor context.\n"
+"[b]Warning:[/b] The implementation of this method is currently disabled."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:43
+msgid "Returns the [EditorInterface] singleton instance."
+msgstr ""
+
+#: doc/classes/EditorScript.xml:50
+msgid "Returns the Editor's currently active scene."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:4
+msgid "Manages the SceneTree selection in the editor."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:7
+msgid "This object manages the SceneTree selection in the editor."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:18
+msgid "Adds a node to the selection."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:25
+msgid "Clear the selection."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:32
+msgid "Gets the list of selected nodes."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:39
+msgid ""
+"Gets the list of selected nodes, optimized for transform operations (i.e. "
+"moving them, rotating, etc). This list avoids situations where a node is "
+"selected and also child/grandchild."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:48
+msgid "Removes a node from the selection."
+msgstr ""
+
+#: doc/classes/EditorSelection.xml:55
+msgid "Emitted when the selection changes."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:4
+msgid "Object that holds the project-independent editor settings."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:7
+msgid ""
+"Object that holds the project-independent editor settings. These settings "
+"are generally visible in the [b]Editor > Editor Settings[/b] menu.\n"
+"Accessing the settings is done by using the regular [Object] API, such as:\n"
+"[codeblock]\n"
+"settings.set(prop,value)\n"
+"settings.get(prop)\n"
+"list_of_settings = settings.get_property_list()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:24
+msgid ""
+"Adds a custom property info to a property. The dictionary must contain:\n"
+"- [code]name[/code]: [String] (the name of the property)\n"
+"- [code]type[/code]: [int] (see [enum Variant.Type])\n"
+"- optionally [code]hint[/code]: [int] (see [enum PropertyHint]) and "
+"[code]hint_string[/code]: [String]\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"editor_settings.set(\"category/property_name\", 0)\n"
+"\n"
+"var property_info = {\n"
+" \"name\": \"category/property_name\",\n"
+" \"type\": TYPE_INT,\n"
+" \"hint\": PROPERTY_HINT_ENUM,\n"
+" \"hint_string\": \"one,two,three\"\n"
+"}\n"
+"\n"
+"editor_settings.add_property_info(property_info)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:49
+msgid "Erase a given setting (pass full property path)."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:56
+msgid "Gets the list of favorite files and directories for this project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:75
+msgid ""
+"Gets the specific project settings path. Projects all have a unique sub-"
+"directory inside the settings path where project specific settings are saved."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:82
+msgid ""
+"Gets the list of recently visited folders in the file dialog for this "
+"project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:97
+msgid ""
+"Gets the global settings path for the engine. Inside this path, you can find "
+"some standard paths such as:\n"
+"[code]settings/tmp[/code] - Used for temporary storage of files\n"
+"[code]settings/templates[/code] - Where export templates are located"
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:132
+msgid "Sets the list of favorite files and directories for this project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:165
+msgid ""
+"Sets the list of recently visited folders in the file dialog for this "
+"project."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:182
+msgid "Emitted when editor settings change."
+msgstr ""
+
+#: doc/classes/EditorSettings.xml:188
+msgid ""
+"Emitted when editor settings change. It used by various editor plugins to "
+"update their visuals on theme changes or logic on configuration changes."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:4
+msgid ""
+"Version Control System (VCS) interface which reads and writes to the local "
+"VCS in use."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:7
+msgid ""
+"Used by the editor to display VCS extracted information in the editor. The "
+"implementation of this API is included in VCS addons, which are essentially "
+"GDNative plugins that need to be put into the project folder. These VCS "
+"addons are scripts which are attached (on demand) to the object instance of "
+"[code]EditorVCSInterface[/code]. All the functions listed below, instead of "
+"performing the task themselves, they call the internally defined functions "
+"in the VCS addons to provide a plug-n-play experience."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:18
+msgid ""
+"Creates a version commit if the addon is initialized, else returns without "
+"doing anything. Uses the files which have been staged previously, with the "
+"commit message set to a value as provided as in the argument."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:27
+msgid ""
+"Returns an [Array] of [Dictionary] objects containing the diff output from "
+"the VCS in use, if a VCS addon is initialized, else returns an empty [Array] "
+"object. The diff contents also consist of some contextual lines which "
+"provide context to the observed line change in the file.\n"
+"Each [Dictionary] object has the line diff contents under the keys:\n"
+"- [code]\"content\"[/code] to store a [String] containing the line contents\n"
+"- [code]\"status\"[/code] to store a [String] which contains [code]\"+\"[/"
+"code] in case the content is a line addition but it stores a [code]\"-\"[/"
+"code] in case of deletion and an empty string in the case the line content "
+"is neither an addition nor a deletion.\n"
+"- [code]\"new_line_number\"[/code] to store an integer containing the new "
+"line number of the line content.\n"
+"- [code]\"line_count\"[/code] to store an integer containing the number of "
+"lines in the line content.\n"
+"- [code]\"old_line_number\"[/code] to store an integer containing the old "
+"line number of the line content.\n"
+"- [code]\"offset\"[/code] to store the offset of the line change since the "
+"first contextual line content."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:41
+msgid ""
+"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.\n"
+"The following integer values are being used to signify that the detected "
+"file is:\n"
+"- [code]0[/code]: New to the VCS working directory\n"
+"- [code]1[/code]: Modified\n"
+"- [code]2[/code]: Renamed\n"
+"- [code]3[/code]: Deleted\n"
+"- [code]4[/code]: Typechanged"
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:54
+msgid "Returns the project name of the VCS working directory."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:61
+msgid ""
+"Returns the name of the VCS if the VCS has been initialized, else return an "
+"empty string."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:70
+msgid ""
+"Initializes the VCS addon if not already. Uses the argument value as the "
+"path to the working directory of the project. Creates the initial commit if "
+"required. Returns [code]true[/code] if no failure occurs, else returns "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:77
+msgid ""
+"Returns [code]true[/code] if the addon is ready to respond to function "
+"calls, else returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:84
+msgid ""
+"Returns [code]true[/code] if the VCS addon has been initialized, else "
+"returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:91
+msgid ""
+"Shuts down the VCS addon to allow cleanup code to run on call. Returns "
+"[code]true[/code] is no failure occurs, else returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:100
+msgid ""
+"Stages the file which should be committed when [method EditorVCSInterface."
+"commit] is called. Argument should contain the absolute path."
+msgstr ""
+
+#: doc/classes/EditorVCSInterface.xml:109
+msgid ""
+"Unstages the file which was staged previously to be committed, so that it is "
+"no longer committed when [method EditorVCSInterface.commit] is called. "
+"Argument should contain the absolute path."
+msgstr ""
+
+#: doc/classes/EncodedObjectAsID.xml:4
+msgid "Holds a reference to an [Object]'s instance ID."
+msgstr ""
+
+#: doc/classes/EncodedObjectAsID.xml:7
+msgid ""
+"Utility class which holds a reference to the internal identifier of an "
+"[Object] instance, as given by [method Object.get_instance_id]. This ID can "
+"then be used to retrieve the object instance with [method @GDScript."
+"instance_from_id].\n"
+"This class is used internally by the editor inspector and script debugger, "
+"but can also be used in plugins to pass and display objects as their IDs."
+msgstr ""
+
+#: doc/classes/EncodedObjectAsID.xml:16
+msgid ""
+"The [Object] identifier stored in this [EncodedObjectAsID] instance. The "
+"object instance can be retrieved with [method @GDScript.instance_from_id]."
+msgstr ""
+
+#: doc/classes/Engine.xml:4
+msgid "Access to basic engine properties."
+msgstr ""
+
+#: doc/classes/Engine.xml:7
+msgid ""
+"The [Engine] class allows you to query and modify the project's run-time "
+"parameters, such as frames per second, time scale, and others."
+msgstr ""
+
+#: doc/classes/Engine.xml:16
+msgid ""
+"Returns engine author information in a Dictionary.\n"
+"[code]lead_developers[/code] - Array of Strings, lead developer names\n"
+"[code]founders[/code] - Array of Strings, founder names\n"
+"[code]project_managers[/code] - Array of Strings, project manager names\n"
+"[code]developers[/code] - Array of Strings, developer names"
+msgstr ""
+
+#: doc/classes/Engine.xml:27
+msgid ""
+"Returns an Array of copyright information Dictionaries.\n"
+"[code]name[/code] - String, component name\n"
+"[code]parts[/code] - Array of Dictionaries {[code]files[/code], "
+"[code]copyright[/code], [code]license[/code]} describing subsections of the "
+"component"
+msgstr ""
+
+#: doc/classes/Engine.xml:36
+msgid ""
+"Returns a Dictionary of Arrays of donor names.\n"
+"{[code]platinum_sponsors[/code], [code]gold_sponsors[/code], "
+"[code]mini_sponsors[/code], [code]gold_donors[/code], [code]silver_donors[/"
+"code], [code]bronze_donors[/code]}"
+msgstr ""
+
+#: doc/classes/Engine.xml:44
+msgid ""
+"Returns the total number of frames drawn. If the render loop is disabled "
+"with [code]--disable-render-loop[/code] via command line, this returns "
+"[code]0[/code]. See also [method get_idle_frames]."
+msgstr ""
+
+#: doc/classes/Engine.xml:51
+msgid "Returns the frames per second of the running game."
+msgstr ""
+
+#: doc/classes/Engine.xml:58
+msgid ""
+"Returns the total number of frames passed since engine initialization which "
+"is advanced on each [b]idle frame[/b], regardless of whether the render loop "
+"is enabled. See also [method get_frames_drawn]."
+msgstr ""
+
+#: doc/classes/Engine.xml:65
+msgid ""
+"Returns Dictionary of licenses used by Godot and included third party "
+"components."
+msgstr ""
+
+#: doc/classes/Engine.xml:72
+msgid "Returns Godot license text."
+msgstr ""
+
+#: doc/classes/Engine.xml:79
+msgid "Returns the main loop object (see [MainLoop] and [SceneTree])."
+msgstr ""
+
+#: doc/classes/Engine.xml:86
+msgid ""
+"Returns the total number of frames passed since engine initialization which "
+"is advanced on each [b]physics frame[/b]."
+msgstr ""
+
+#: doc/classes/Engine.xml:93
+msgid ""
+"Returns the fraction through the current physics tick we are at the time of "
+"rendering the frame. This can be used to implement fixed timestep "
+"interpolation."
+msgstr ""
+
+#: doc/classes/Engine.xml:102
+msgid ""
+"Returns a global singleton with given [code]name[/code]. Often used for "
+"plugins, e.g. GodotPayments."
+msgstr ""
+
+#: doc/classes/Engine.xml:109
+msgid ""
+"Returns the current engine version information in a Dictionary.\n"
+"[code]major[/code] - Holds the major version number as an int\n"
+"[code]minor[/code] - Holds the minor version number as an int\n"
+"[code]patch[/code] - Holds the patch version number as an int\n"
+"[code]hex[/code] - Holds the full version number encoded as a "
+"hexadecimal int with one byte (2 places) per number (see example below)\n"
+"[code]status[/code] - Holds the status (e.g. \"beta\", \"rc1\", "
+"\"rc2\", ... \"stable\") as a String\n"
+"[code]build[/code] - Holds the build name (e.g. \"custom_build\") as a "
+"String\n"
+"[code]hash[/code] - Holds the full Git commit hash as a String\n"
+"[code]year[/code] - Holds the year the version was released in as an "
+"int\n"
+"[code]string[/code] - [code]major[/code] + [code]minor[/code] + "
+"[code]patch[/code] + [code]status[/code] + [code]build[/code] in a single "
+"String\n"
+"The [code]hex[/code] value is encoded as follows, from left to right: one "
+"byte for the major, one byte for the minor, one byte for the patch version. "
+"For example, \"3.1.12\" would be [code]0x03010C[/code]. [b]Note:[/b] It's "
+"still an int internally, and printing it will give you its decimal "
+"representation, which is not particularly meaningful. Use hexadecimal "
+"literals for easy version comparisons from code:\n"
+"[codeblock]\n"
+"if Engine.get_version_info().hex >= 0x030200:\n"
+" # Do things specific to version 3.2 or later\n"
+"else:\n"
+" # Do things specific to versions before 3.2\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Engine.xml:134
+msgid ""
+"Returns [code]true[/code] if a singleton with given [code]name[/code] exists "
+"in global scope."
+msgstr ""
+
+#: doc/classes/Engine.xml:141
+msgid ""
+"Returns [code]true[/code] if the game is inside the fixed process and "
+"physics phase of the game loop."
+msgstr ""
+
+#: doc/classes/Engine.xml:147
+msgid ""
+"If [code]true[/code], it is running inside the editor. Useful for tool "
+"scripts."
+msgstr ""
+
+#: doc/classes/Engine.xml:150
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Engine.xml:153
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Engine.xml:156
+msgid ""
+"The desired frames per second. If the hardware cannot keep up, this setting "
+"may not be respected. A value of 0 means no limit."
+msgstr ""
+
+#: doc/classes/Engine.xml:159
+msgid ""
+"Controls how fast or slow the in-game clock ticks versus the real life one. "
+"It defaults to 1.0. A value of 2.0 means the game moves twice as fast as "
+"real life, whilst a value of 0.5 means the game moves at half the regular "
+"speed."
+msgstr ""
+
+#: doc/classes/Environment.xml:4
+msgid ""
+"Resource for environment nodes (like [WorldEnvironment]) that define "
+"multiple rendering options."
+msgstr ""
+
+#: doc/classes/Environment.xml:7
+msgid ""
+"Resource for environment nodes (like [WorldEnvironment]) that define "
+"multiple environment operations (such as background [Sky] or [Color], "
+"ambient light, fog, depth-of-field...). These parameters affect the final "
+"render of the scene. The order of these operations is:\n"
+"- Depth of Field Blur\n"
+"- Glow\n"
+"- Tonemap (Auto Exposure)\n"
+"- Adjustments"
+msgstr ""
+
+#: doc/classes/Environment.xml:14 doc/classes/WorldEnvironment.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/"
+"environment_and_post_processing.html"
+msgstr ""
+
+#: doc/classes/Environment.xml:15
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/high_dynamic_range.html"
+msgstr ""
+
+#: doc/classes/Environment.xml:24
+msgid ""
+"Returns [code]true[/code] if the glow level [code]idx[/code] is specified, "
+"[code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/Environment.xml:35
+msgid ""
+"Enables or disables the glow level at index [code]idx[/code]. Each level "
+"relies on the previous level. This means that enabling higher glow levels "
+"will slow down the glow effect rendering, even if previous levels aren't "
+"enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:41
+msgid ""
+"The global brightness value of the rendered scene. Effective only if "
+"[code]adjustment_enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:44
+msgid ""
+"Applies the provided [Texture2D] resource to affect the global color aspect "
+"of the rendered scene. Effective only if [code]adjustment_enabled[/code] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:47
+msgid ""
+"The global contrast value of the rendered scene (default value is 1). "
+"Effective only if [code]adjustment_enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:50
+msgid ""
+"If [code]true[/code], enables the [code]adjustment_*[/code] properties "
+"provided by this resource. If [code]false[/code], modifications to the "
+"[code]adjustment_*[/code] properties will have no effect on the rendered "
+"scene."
+msgstr ""
+
+#: doc/classes/Environment.xml:53
+msgid ""
+"The global color saturation value of the rendered scene (default value is "
+"1). Effective only if [code]adjustment_enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:56
+msgid "The ambient light's [Color]."
+msgstr ""
+
+#: doc/classes/Environment.xml:59
+msgid ""
+"The ambient light's energy. The higher the value, the stronger the light."
+msgstr ""
+
+#: doc/classes/Environment.xml:64
+msgid ""
+"Defines the amount of light that the sky brings on the scene. A value of 0 "
+"means that the sky's light emission has no effect on the scene illumination, "
+"thus all ambient illumination is provided by the ambient light. On the "
+"contrary, a value of 1 means that all the light that affects the scene is "
+"provided by the sky, thus the ambient light parameter has no effect on the "
+"scene."
+msgstr ""
+
+#: doc/classes/Environment.xml:69
+msgid ""
+"If [code]true[/code], enables the tonemapping auto exposure mode of the "
+"scene renderer. If [code]true[/code], the renderer will automatically "
+"determine the exposure setting to adapt to the scene's illumination and the "
+"observed light."
+msgstr ""
+
+#: doc/classes/Environment.xml:72
+msgid "The maximum luminance value for the auto exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:75
+msgid "The minimum luminance value for the auto exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:78
+msgid ""
+"The scale of the auto exposure effect. Affects the intensity of auto "
+"exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:81
+msgid ""
+"The speed of the auto exposure effect. Affects the time needed for the "
+"camera to perform auto exposure."
+msgstr ""
+
+#: doc/classes/Environment.xml:84
+msgid "The ID of the camera feed to show in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:87
+msgid ""
+"The maximum layer ID to display. Only effective when using the [constant "
+"BG_CANVAS] background mode."
+msgstr ""
+
+#: doc/classes/Environment.xml:90
+msgid ""
+"The [Color] displayed for clear areas of the scene. Only effective when "
+"using the [constant BG_COLOR] background mode."
+msgstr ""
+
+#: doc/classes/Environment.xml:93
+msgid "The power of the light emitted by the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:96
+msgid "The background mode. See [enum BGMode] for possible values."
+msgstr ""
+
+#: doc/classes/Environment.xml:99
+msgid "The fog's [Color]."
+msgstr ""
+
+#: doc/classes/Environment.xml:102
+msgid "The fog's depth starting distance from the camera."
+msgstr ""
+
+#: doc/classes/Environment.xml:105
+msgid ""
+"The fog depth's intensity curve. A number of presets are available in the "
+"[b]Inspector[/b] by right-clicking the curve."
+msgstr ""
+
+#: doc/classes/Environment.xml:108
+msgid ""
+"If [code]true[/code], the depth fog effect is enabled. When enabled, fog "
+"will appear in the distance (relative to the camera)."
+msgstr ""
+
+#: doc/classes/Environment.xml:111
+msgid ""
+"The fog's depth end distance from the camera. If this value is set to 0, it "
+"will be equal to the current camera's [member Camera3D.far] value."
+msgstr ""
+
+#: doc/classes/Environment.xml:114
+msgid ""
+"If [code]true[/code], fog effects are enabled. [member fog_height_enabled] "
+"and/or [member fog_depth_enabled] must be set to [code]true[/code] to "
+"actually display fog."
+msgstr ""
+
+#: doc/classes/Environment.xml:117
+msgid ""
+"The height fog's intensity. A number of presets are available in the "
+"[b]Inspector[/b] by right-clicking the curve."
+msgstr ""
+
+#: doc/classes/Environment.xml:120
+msgid ""
+"If [code]true[/code], the height fog effect is enabled. When enabled, fog "
+"will appear in a defined height range, regardless of the distance from the "
+"camera. This can be used to simulate \"deep water\" effects with a lower "
+"performance cost compared to a dedicated shader."
+msgstr ""
+
+#: doc/classes/Environment.xml:123
+msgid ""
+"The Y coordinate where the height fog will be the most intense. If this "
+"value is greater than [member fog_height_min], fog will be displayed from "
+"bottom to top. Otherwise, it will be displayed from top to bottom."
+msgstr ""
+
+#: doc/classes/Environment.xml:126
+msgid ""
+"The Y coordinate where the height fog will be the least intense. If this "
+"value is greater than [member fog_height_max], fog will be displayed from "
+"top to bottom. Otherwise, it will be displayed from bottom to top."
+msgstr ""
+
+#: doc/classes/Environment.xml:129
+msgid ""
+"The intensity of the depth fog color transition when looking towards the "
+"sun. The sun's direction is determined automatically using the "
+"DirectionalLight3D node in the scene."
+msgstr ""
+
+#: doc/classes/Environment.xml:132
+msgid "The depth fog's [Color] when looking towards the sun."
+msgstr ""
+
+#: doc/classes/Environment.xml:135
+msgid ""
+"The intensity of the fog light transmittance effect. Amount of light that "
+"the fog transmits."
+msgstr ""
+
+#: doc/classes/Environment.xml:138
+msgid ""
+"Enables fog's light transmission effect. If [code]true[/code], light will be "
+"more visible in the fog to simulate light scattering as in real life."
+msgstr ""
+
+#: doc/classes/Environment.xml:141
+msgid "The glow blending mode."
+msgstr ""
+
+#: doc/classes/Environment.xml:144
+msgid ""
+"The bloom's intensity. If set to a value higher than [code]0[/code], this "
+"will make glow visible in areas darker than the [member glow_hdr_threshold]."
+msgstr ""
+
+#: doc/classes/Environment.xml:147
+msgid "If [code]true[/code], the glow effect is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:150
+msgid ""
+"The higher threshold of the HDR glow. Areas brighter than this threshold "
+"will be clamped for the purposes of the glow effect."
+msgstr ""
+
+#: doc/classes/Environment.xml:153
+msgid "The bleed scale of the HDR glow."
+msgstr ""
+
+#: doc/classes/Environment.xml:156
+msgid ""
+"The lower threshold of the HDR glow. When using the GLES2 renderer (which "
+"doesn't support HDR), this needs to be below [code]1.0[/code] for glow to be "
+"visible. A value of [code]0.9[/code] works well in this case."
+msgstr ""
+
+#: doc/classes/Environment.xml:159
+msgid ""
+"The glow intensity. When using the GLES2 renderer, this should be increased "
+"to 1.5 to compensate for the lack of HDR rendering."
+msgstr ""
+
+#: doc/classes/Environment.xml:162
+msgid ""
+"If [code]true[/code], the 1st level of glow is enabled. This is the most "
+"\"local\" level (least blurry)."
+msgstr ""
+
+#: doc/classes/Environment.xml:165
+msgid "If [code]true[/code], the 2th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:168
+msgid "If [code]true[/code], the 3th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:171
+msgid "If [code]true[/code], the 4th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:174
+msgid "If [code]true[/code], the 5th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:177
+msgid "If [code]true[/code], the 6th level of glow is enabled."
+msgstr ""
+
+#: doc/classes/Environment.xml:180
+msgid ""
+"If [code]true[/code], the 7th level of glow is enabled. This is the most "
+"\"global\" level (blurriest)."
+msgstr ""
+
+#: doc/classes/Environment.xml:185
+msgid ""
+"The glow strength. When using the GLES2 renderer, this should be increased "
+"to 1.3 to compensate for the lack of HDR rendering."
+msgstr ""
+
+#: doc/classes/Environment.xml:190
+msgid "The [Sky] resource used for this [Environment]."
+msgstr ""
+
+#: doc/classes/Environment.xml:197
+msgid "The depth tolerance for screen-space reflections."
+msgstr ""
+
+#: doc/classes/Environment.xml:200
+msgid ""
+"If [code]true[/code], screen-space reflections are enabled. Screen-space "
+"reflections are more accurate than reflections from [GIProbe]s or "
+"[ReflectionProbe]s, but are slower and can't reflect surfaces occluded by "
+"others."
+msgstr ""
+
+#: doc/classes/Environment.xml:203
+msgid ""
+"The fade-in distance for screen-space reflections. Affects the area from the "
+"reflected material to the screen-space reflection)."
+msgstr ""
+
+#: doc/classes/Environment.xml:206
+msgid ""
+"The fade-out distance for screen-space reflections. Affects the area from "
+"the screen-space reflection to the \"global\" reflection."
+msgstr ""
+
+#: doc/classes/Environment.xml:209
+msgid ""
+"The maximum number of steps for screen-space reflections. Higher values are "
+"slower."
+msgstr ""
+
+#: doc/classes/Environment.xml:212
+msgid ""
+"The screen-space ambient occlusion intensity on materials that have an AO "
+"texture defined. Values higher than [code]0[/code] will make the SSAO effect "
+"visible in areas darkened by AO textures."
+msgstr ""
+
+#: doc/classes/Environment.xml:215
+msgid ""
+"The screen-space ambient occlusion bias. This should be kept high enough to "
+"prevent \"smooth\" curves from being affected by ambient occlusion."
+msgstr ""
+
+#: doc/classes/Environment.xml:218
+msgid ""
+"The screen-space ambient occlusion blur quality. See [enum SSAOBlur] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/Environment.xml:221
+msgid "The screen-space ambient occlusion edge sharpness."
+msgstr ""
+
+#: doc/classes/Environment.xml:224
+msgid ""
+"If [code]true[/code], the screen-space ambient occlusion effect is enabled. "
+"This darkens objects' corners and cavities to simulate ambient light not "
+"reaching the entire object as in real life. This works well for small, "
+"dynamic objects, but baked lighting or ambient occlusion textures will do a "
+"better job at displaying ambient occlusion on large static objects. This is "
+"a costly effect and should be disabled first when running into performance "
+"issues."
+msgstr ""
+
+#: doc/classes/Environment.xml:227
+msgid ""
+"The primary screen-space ambient occlusion intensity. See also [member "
+"ssao_radius]."
+msgstr ""
+
+#: doc/classes/Environment.xml:230
+msgid ""
+"The screen-space ambient occlusion intensity in direct light. In real life, "
+"ambient occlusion only applies to indirect light, which means its effects "
+"can't be seen in direct light. Values higher than [code]0[/code] will make "
+"the SSAO effect visible in direct light."
+msgstr ""
+
+#: doc/classes/Environment.xml:233
+msgid "The primary screen-space ambient occlusion radius."
+msgstr ""
+
+#: doc/classes/Environment.xml:236
+msgid "The default exposure used for tonemapping."
+msgstr ""
+
+#: doc/classes/Environment.xml:239
+msgid ""
+"The tonemapping mode to use. Tonemapping is the process that \"converts\" "
+"HDR values to be suitable for rendering on a LDR display. (Godot doesn't "
+"support rendering on HDR displays yet.)"
+msgstr ""
+
+#: doc/classes/Environment.xml:242
+msgid ""
+"The white reference value for tonemapping. Only effective if the [member "
+"tonemap_mode] isn't set to [constant TONE_MAPPER_LINEAR]."
+msgstr ""
+
+#: doc/classes/Environment.xml:247
+msgid ""
+"Clears the background using the clear color defined in [member "
+"ProjectSettings.rendering/environment/default_clear_color]."
+msgstr ""
+
+#: doc/classes/Environment.xml:250
+msgid "Clears the background using a custom clear color."
+msgstr ""
+
+#: doc/classes/Environment.xml:253
+msgid "Displays a user-defined sky in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:256
+msgid "Displays a [CanvasLayer] in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:259
+msgid ""
+"Keeps on screen every pixel drawn in the background. This is the fastest "
+"background mode, but it can only be safely used in fully-interior scenes (no "
+"visible sky or sky reflections). If enabled in a scene where the background "
+"is visible, \"ghost trail\" artifacts will be visible when moving the camera."
+msgstr ""
+
+#: doc/classes/Environment.xml:262 doc/classes/RenderingServer.xml:3476
+msgid "Displays a camera feed in the background."
+msgstr ""
+
+#: doc/classes/Environment.xml:265
+msgid "Represents the size of the [enum BGMode] enum."
+msgstr ""
+
+#: doc/classes/Environment.xml:282
+msgid ""
+"Additive glow blending mode. Mostly used for particles, glows (bloom), lens "
+"flare, bright sources."
+msgstr ""
+
+#: doc/classes/Environment.xml:285
+msgid ""
+"Screen glow blending mode. Increases brightness, used frequently with bloom."
+msgstr ""
+
+#: doc/classes/Environment.xml:288
+msgid ""
+"Soft light glow blending mode. Modifies contrast, exposes shadows and "
+"highlights (vivid bloom)."
+msgstr ""
+
+#: doc/classes/Environment.xml:291
+msgid ""
+"Replace glow blending mode. Replaces all pixels' color by the glow value. "
+"This can be used to simulate a full-screen blur effect by tweaking the glow "
+"parameters to match the original image's brightness."
+msgstr ""
+
+#: doc/classes/Environment.xml:296
+msgid ""
+"Linear tonemapper operator. Reads the linear data and passes it on "
+"unmodified."
+msgstr ""
+
+#: doc/classes/Environment.xml:299
+msgid ""
+"Reinhardt tonemapper operator. Performs a variation on rendered pixels' "
+"colors by this formula: [code]color = color / (1 + color)[/code]."
+msgstr ""
+
+#: doc/classes/Environment.xml:302
+msgid "Filmic tonemapper operator."
+msgstr ""
+
+#: doc/classes/Environment.xml:305
+msgid "Academy Color Encoding System tonemapper operator."
+msgstr ""
+
+#: doc/classes/Environment.xml:308
+msgid "No blur for the screen-space ambient occlusion effect (fastest)."
+msgstr ""
+
+#: doc/classes/Environment.xml:311
+msgid "1×1 blur for the screen-space ambient occlusion effect."
+msgstr ""
+
+#: doc/classes/Environment.xml:314
+msgid "2×2 blur for the screen-space ambient occlusion effect."
+msgstr ""
+
+#: doc/classes/Environment.xml:317
+msgid "3×3 blur for the screen-space ambient occlusion effect (slowest)."
+msgstr ""
+
+#: doc/classes/Expression.xml:4
+msgid "A class that stores an expression you can execute."
+msgstr ""
+
+#: doc/classes/Expression.xml:7
+msgid ""
+"An expression can be made of any arithmetic operation, built-in math "
+"function call, method call of a passed instance, or built-in type "
+"construction call.\n"
+"An example expression text using the built-in math functions could be "
+"[code]sqrt(pow(3,2) + pow(4,2))[/code].\n"
+"In the following example we use a [LineEdit] node to write our expression "
+"and show the result.\n"
+"[codeblock]\n"
+"onready var expression = Expression.new()\n"
+"\n"
+"func _ready():\n"
+" $LineEdit.connect(\"text_entered\", self, \"_on_text_entered\")\n"
+"\n"
+"func _on_text_entered(command):\n"
+" var error = expression.parse(command, [])\n"
+" if error != OK:\n"
+" print(expression.get_error_text())\n"
+" return\n"
+" var result = expression.execute([], null, true)\n"
+" if not expression.has_execute_failed():\n"
+" $LineEdit.text = str(result)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Expression.xml:39
+msgid ""
+"Executes the expression that was previously parsed by [method parse] and "
+"returns the result. Before you use the returned object, you should check if "
+"the method failed by calling [method has_execute_failed].\n"
+"If you defined input variables in [method parse], you can specify their "
+"values in the inputs array, in the same order."
+msgstr ""
+
+#: doc/classes/Expression.xml:47
+msgid "Returns the error text if [method parse] has failed."
+msgstr ""
+
+#: doc/classes/Expression.xml:54
+msgid "Returns [code]true[/code] if [method execute] has failed."
+msgstr ""
+
+#: doc/classes/Expression.xml:65
+msgid ""
+"Parses the expression and returns an [enum Error] code.\n"
+"You can optionally specify names of variables that may appear in the "
+"expression with [code]input_names[/code], so that you can bind them when it "
+"gets executed."
+msgstr ""
+
+#: doc/classes/File.xml:4
+msgid "Type to handle file reading and writing operations."
+msgstr ""
+
+#: doc/classes/File.xml:7
+msgid ""
+"File type. This is used to permanently store data into the user device's "
+"file system and to read from it. This can be used to store game save data or "
+"player configuration files, for example.\n"
+"Here's a sample on how to write and read from a file:\n"
+"[codeblock]\n"
+"func save(content):\n"
+" var file = File.new()\n"
+" file.open(\"user://save_game.dat\", File.WRITE)\n"
+" file.store_string(content)\n"
+" file.close()\n"
+"\n"
+"func load():\n"
+" var file = File.new()\n"
+" file.open(\"user://save_game.dat\", File.READ)\n"
+" var content = file.get_as_text()\n"
+" file.close()\n"
+" return content\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/File.xml:32
+msgid "Closes the currently opened file."
+msgstr ""
+
+#: doc/classes/File.xml:39
+msgid ""
+"Returns [code]true[/code] if the file cursor has read past the end of the "
+"file.\n"
+"[b]Note:[/b] This function will still return [code]false[/code] while at the "
+"end of the file and only activates when reading past it. This can be "
+"confusing but it conforms to how low-level file access works in all "
+"operating systems. There is always [method get_len] and [method "
+"get_position] to implement a custom logic."
+msgstr ""
+
+#: doc/classes/File.xml:49
+msgid ""
+"Returns [code]true[/code] if the file exists in the given path.\n"
+"[b]Note:[/b] Many resources types are imported (e.g. textures or sound "
+"files), and that their source asset will not be included in the exported "
+"game, as only the imported version is used (in the [code]res://.import[/"
+"code] folder). To check for the existence of such resources while taking "
+"into account the remapping to their imported location, use [method "
+"ResourceLoader.exists]. Typically, using [code]File.file_exists[/code] on an "
+"imported resource would work while you are developing in the editor (the "
+"source asset is present in [code]res://[/code], but fail when exported)."
+msgstr ""
+
+#: doc/classes/File.xml:57
+msgid "Returns the next 16 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:64
+msgid "Returns the next 32 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:71
+msgid "Returns the next 64 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:78
+msgid "Returns the next 8 bits from the file as an integer."
+msgstr ""
+
+#: doc/classes/File.xml:85
+msgid ""
+"Returns the whole file as a [String].\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:95
+msgid "Returns next [code]len[/code] bytes of the file as a [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/File.xml:104
+msgid ""
+"Returns the next value of the file in CSV (Comma-Separated Values) format. "
+"You can pass a different delimiter [code]delim[/code] to use other than the "
+"default [code]\",\"[/code] (comma). This delimiter must be one-character "
+"long.\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:112
+msgid "Returns the next 64 bits from the file as a floating-point number."
+msgstr ""
+
+#: doc/classes/File.xml:119
+msgid ""
+"Returns the last error that happened when trying to perform operations. "
+"Compare with the [code]ERR_FILE_*[/code] constants from [enum Error]."
+msgstr ""
+
+#: doc/classes/File.xml:126
+msgid "Returns the next 32 bits from the file as a floating-point number."
+msgstr ""
+
+#: doc/classes/File.xml:133
+msgid "Returns the size of the file in bytes."
+msgstr ""
+
+#: doc/classes/File.xml:140
+msgid ""
+"Returns the next line of the file as a [String].\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:150
+msgid ""
+"Returns an MD5 String representing the file at the given path or an empty "
+"[String] on failure."
+msgstr ""
+
+#: doc/classes/File.xml:159
+msgid ""
+"Returns the last time the [code]file[/code] was modified in unix timestamp "
+"format or returns a [String] \"ERROR IN [code]file[/code]\". This unix "
+"timestamp can be converted to datetime by using [method OS."
+"get_datetime_from_unix_time]."
+msgstr ""
+
+#: doc/classes/File.xml:166
+msgid ""
+"Returns a [String] saved in Pascal format from the file.\n"
+"Text is interpreted as being UTF-8 encoded."
+msgstr ""
+
+#: doc/classes/File.xml:174
+msgid "Returns the path as a [String] for the current open file."
+msgstr ""
+
+#: doc/classes/File.xml:181
+msgid "Returns the absolute path as a [String] for the current open file."
+msgstr ""
+
+#: doc/classes/File.xml:188
+msgid "Returns the file cursor's position."
+msgstr ""
+
+#: doc/classes/File.xml:195
+msgid "Returns the next bits from the file as a floating-point number."
+msgstr ""
+
+#: doc/classes/File.xml:204
+msgid ""
+"Returns a SHA-256 [String] representing the file at the given path or an "
+"empty [String] on failure."
+msgstr ""
+
+#: doc/classes/File.xml:213
+msgid ""
+"Returns the next [Variant] value from the file. If [code]allow_objects[/"
+"code] is [code]true[/code], decoding objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/File.xml:221
+msgid "Returns [code]true[/code] if the file is currently opened."
+msgstr ""
+
+#: doc/classes/File.xml:232
+msgid "Opens the file for writing or reading, depending on the flags."
+msgstr ""
+
+#: doc/classes/File.xml:245
+msgid "Opens a compressed file for reading or writing."
+msgstr ""
+
+#: doc/classes/File.xml:258
+msgid ""
+"Opens an encrypted file in write or read mode. You need to pass a binary key "
+"to encrypt/decrypt it."
+msgstr ""
+
+#: doc/classes/File.xml:271
+msgid ""
+"Opens an encrypted file in write or read mode. You need to pass a password "
+"to encrypt/decrypt it."
+msgstr ""
+
+#: doc/classes/File.xml:280
+msgid ""
+"Changes the file reading/writing cursor to the specified position (in bytes "
+"from the beginning of the file)."
+msgstr ""
+
+#: doc/classes/File.xml:289
+msgid ""
+"Changes the file reading/writing cursor to the specified position (in bytes "
+"from the end of the file).\n"
+"[b]Note:[/b] This is an offset, so you should use negative numbers or the "
+"cursor will be at the end of the file."
+msgstr ""
+
+#: doc/classes/File.xml:299
+msgid "Stores an integer as 16 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:308
+msgid "Stores an integer as 32 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:317
+msgid "Stores an integer as 64 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:326
+msgid "Stores an integer as 8 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:335
+msgid "Stores the given array of bytes in the file."
+msgstr ""
+
+#: doc/classes/File.xml:346
+msgid ""
+"Store the given [PackedStringArray] in the file as a line formatted in the "
+"CSV (Comma-Separated Values) format. You can pass a different delimiter "
+"[code]delim[/code] to use other than the default [code]\",\"[/code] (comma). "
+"This delimiter must be one-character long.\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:356
+msgid "Stores a floating-point number as 64 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:365
+msgid "Stores a floating-point number as 32 bits in the file."
+msgstr ""
+
+#: doc/classes/File.xml:374
+msgid ""
+"Stores the given [String] as a line in the file.\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:384
+msgid ""
+"Stores the given [String] as a line in the file in Pascal format (i.e. also "
+"store the length of the string).\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:394
+msgid "Stores a floating-point number in the file."
+msgstr ""
+
+#: doc/classes/File.xml:403
+msgid ""
+"Stores the given [String] in the file.\n"
+"Text will be encoded as UTF-8."
+msgstr ""
+
+#: doc/classes/File.xml:415
+msgid ""
+"Stores any Variant value in the file. If [code]full_objects[/code] is "
+"[code]true[/code], encoding objects is allowed (and can potentially include "
+"code)."
+msgstr ""
+
+#: doc/classes/File.xml:421
+msgid ""
+"If [code]true[/code], the file's endianness is swapped. Use this if you're "
+"dealing with files written on big-endian machines.\n"
+"[b]Note:[/b] This is about the file format, not CPU type. This is always "
+"reset to [code]false[/code] whenever you open the file."
+msgstr ""
+
+#: doc/classes/File.xml:427
+msgid "Opens the file for read operations."
+msgstr ""
+
+#: doc/classes/File.xml:430
+msgid ""
+"Opens the file for write operations. Create it if the file does not exist "
+"and truncate if it exists."
+msgstr ""
+
+#: doc/classes/File.xml:433
+msgid ""
+"Opens the file for read and write operations. Does not truncate the file."
+msgstr ""
+
+#: doc/classes/File.xml:436
+msgid ""
+"Opens the file for read and write operations. Create it if the file does not "
+"exist and truncate if it exists."
+msgstr ""
+
+#: doc/classes/File.xml:439
+msgid "Uses the [url=http://fastlz.org/]FastLZ[/url] compression method."
+msgstr ""
+
+#: doc/classes/File.xml:442
+msgid ""
+"Uses the [url=https://en.wikipedia.org/wiki/DEFLATE]DEFLATE[/url] "
+"compression method."
+msgstr ""
+
+#: doc/classes/File.xml:445
+msgid ""
+"Uses the [url=https://facebook.github.io/zstd/]Zstandard[/url] compression "
+"method."
+msgstr ""
+
+#: doc/classes/File.xml:448
+msgid "Uses the [url=https://www.gzip.org/]gzip[/url] compression method."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:4
+msgid "Dialog for selecting files or directories in the filesystem."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:7
+msgid ""
+"FileDialog is a preset dialog used to choose files and directories in the "
+"filesystem. It supports filter masks."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:18
+msgid ""
+"Adds [code]filter[/code] as a custom filter; [code]filter[/code] should be "
+"of the form [code]\"filename.extension ; Description\"[/code]. For example, "
+"[code]\"*.png ; PNG Images\"[/code]."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:25
+msgid "Clear all the added filters in the dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:32
+msgid "Clear currently selected items in the dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:39
+msgid "Returns the LineEdit for the selected file."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:46
+msgid ""
+"Returns the vertical box container of the dialog, custom controls can be "
+"added to it."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:53
+msgid "Invalidate and update the current dialog content list."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:59
+msgid "The file system access scope. See enum [code]Access[/code] constants."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:62
+msgid "The current working directory of the file dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:65
+msgid "The currently selected file of the file dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:68
+msgid "The currently selected file path of the file dialog."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:72
+msgid ""
+"The dialog's open or save mode, which affects the selection behavior. See "
+"[enum FileMode]."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:75
+msgid ""
+"The available file type filters. For example, this shows only [code].png[/"
+"code] and [code].gd[/code] files: [code]set_filters(PackedStringArray([\"*."
+"png ; PNG Images\",\"*.gd ; GDScript Files\"]))[/code]."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:78
+msgid ""
+"If [code]true[/code], changing the [code]Mode[/code] property will set the "
+"window title accordingly (e.g. setting mode to [constant "
+"FILE_MODE_OPEN_FILE] will change the window title to \"Open a File\")."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:81
+msgid "If [code]true[/code], the dialog will show hidden files."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:90
+msgid "Emitted when the user selects a directory."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:97
+msgid ""
+"Emitted when the user selects a file by double-clicking it or pressing the "
+"[b]OK[/b] button."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:104
+msgid "Emitted when the user selects multiple files."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:110
+msgid "The dialog allows selecting one, and only one file."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:113
+msgid "The dialog allows selecting multiple files."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:116
+msgid ""
+"The dialog only allows selecting a directory, disallowing the selection of "
+"any file."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:119
+msgid "The dialog allows selecting one file or directory."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:122
+msgid "The dialog will warn when a file exists."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:125
+msgid ""
+"The dialog only allows accessing files under the [Resource] path "
+"([code]res://[/code])."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:128
+msgid ""
+"The dialog only allows accessing files under user data path ([code]user://[/"
+"code])."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:131
+msgid "The dialog allows accessing files on the whole file system."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:136
+msgid ""
+"The color tint for disabled files (when the [FileDialog] is used in open "
+"folder mode)."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:139
+msgid "Custom icon for folders."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:142
+msgid "The color modulation applied to the folder icon."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:145
+msgid "Custom icon for the parent folder arrow."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:148
+msgid "Custom icon for the reload button."
+msgstr ""
+
+#: doc/classes/FileDialog.xml:151
+msgid "Custom icon for the toggle hidden button."
+msgstr ""
+
+#: doc/classes/float.xml:4 doc/classes/float.xml:7
+msgid "Float built-in type."
+msgstr ""
+
+#: doc/classes/float.xml:18
+msgid ""
+"Cast a [bool] value to a floating-point value, [code]float(true)[/code] will "
+"be equal to 1.0 and [code]float(false)[/code] will be equal to 0.0."
+msgstr ""
+
+#: doc/classes/float.xml:27
+msgid ""
+"Cast an [int] value to a floating-point value, [code]float(1)[/code] will be "
+"equal to 1.0."
+msgstr ""
+
+#: doc/classes/float.xml:36
+msgid ""
+"Cast a [String] value to a floating-point value. This method accepts float "
+"value strings like [code]\"1.23\"[/code] and exponential notation strings "
+"for its parameter so calling [code]float(\"1e3\")[/code] will return 1000.0 "
+"and calling [code]float(\"1e-3\")[/code] will return 0.001. Calling this "
+"method with an invalid float string will return 0. This method stops parsing "
+"at the first invalid character and will return the parsed result so far, so "
+"calling [code]float(\"1a3\")[/code] will return 1 while calling "
+"[code]float(\"1e3a2\")[/code] will return 1000.0."
+msgstr ""
+
+#: doc/classes/Font.xml:4
+msgid "Internationalized font and text drawing support."
+msgstr ""
+
+#: doc/classes/Font.xml:7
+msgid ""
+"Font contains a Unicode-compatible character set, as well as the ability to "
+"draw it with variable width, ascent, descent and kerning. For creating fonts "
+"from TTF files (or other font formats), see the editor support for fonts."
+msgstr ""
+
+#: doc/classes/Font.xml:28
+msgid ""
+"Draw [code]string[/code] into a canvas item using the font at a given "
+"position, with [code]modulate[/code] color, and optionally clipping the "
+"width. [code]position[/code] specifies the baseline, not the top. To draw "
+"from the top, [i]ascent[/i] must be added to the Y axis."
+msgstr ""
+
+#: doc/classes/Font.xml:47
+msgid ""
+"Draw character [code]char[/code] into a canvas item using the font at a "
+"given position, with [code]modulate[/code] color, and optionally kerning if "
+"[code]next[/code] is passed. clipping the width. [code]position[/code] "
+"specifies the baseline, not the top. To draw from the top, [i]ascent[/i] "
+"must be added to the Y axis. The width used by the character is returned, "
+"making this function useful for drawing strings character by character."
+msgstr ""
+
+#: doc/classes/Font.xml:54
+msgid "Returns the font ascent (number of pixels above the baseline)."
+msgstr ""
+
+#: doc/classes/Font.xml:61
+msgid "Returns the font descent (number of pixels below the baseline)."
+msgstr ""
+
+#: doc/classes/Font.xml:68
+msgid "Returns the total font height (ascent plus descent) in pixels."
+msgstr ""
+
+#: doc/classes/Font.xml:77
+msgid "Returns the size of a string, taking kerning and advance into account."
+msgstr ""
+
+#: doc/classes/Font.xml:88
+msgid ""
+"Returns the size that the string would have with word wrapping enabled with "
+"a fixed [code]width[/code]."
+msgstr ""
+
+#: doc/classes/Font.xml:95
+msgid "Returns [code]true[/code] if the font has an outline."
+msgstr ""
+
+#: doc/classes/Font.xml:108
+msgid ""
+"After editing a font (changing size, ascent, char rects, etc.). Call this "
+"function to propagate changes to controls that might use it."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:4
+msgid "Reference to a function in an object."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:7
+msgid ""
+"In GDScript, functions are not [i]first-class objects[/i]. This means it is "
+"impossible to store them directly as variables, return them from another "
+"function, or pass them as arguments.\n"
+"However, by creating a [FuncRef] using the [method @GDScript.funcref] "
+"function, a reference to a function in a given object can be created, passed "
+"around and called."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:17
+msgid ""
+"Calls the referenced function previously set by [method set_function] or "
+"[method @GDScript.funcref]."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:26
+msgid ""
+"Calls the referenced function previously set by [method set_function] or "
+"[method @GDScript.funcref]. Contrarily to [method call_func], this method "
+"does not support a variable number of arguments but expects all parameters "
+"to be passed via a single [Array]."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:33
+msgid "Returns whether the object still exists and has the function assigned."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:42
+msgid ""
+"The name of the referenced function to call on the object, without "
+"parentheses or any parameters."
+msgstr ""
+
+#: doc/classes/FuncRef.xml:51
+msgid ""
+"The object containing the referenced function. This object must be of a type "
+"actually inheriting from [Object], not a built-in type such as [int], "
+"[Vector2] or [Dictionary]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:4
+msgid ""
+"An external library containing functions or script classes to use in Godot."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:7
+msgid ""
+"A GDNative library can implement [NativeScript]s, global functions to call "
+"with the [GDNative] class, or low-level engine extensions through interfaces "
+"such as [ARVRInterfaceGDNative]. The library must be compiled for each "
+"platform and architecture that the project will run on."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-"
+"example.html"
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-"
+"cpp-example.html"
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:18
+msgid ""
+"Returns paths to all dependency libraries for the current platform and "
+"architecture."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:25
+msgid ""
+"Returns the path to the dynamic library file for the current platform and "
+"architecture."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:31
+msgid ""
+"This resource in INI-style [ConfigFile] format, as in [code].gdnlib[/code] "
+"files."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:34
+msgid ""
+"If [code]true[/code], Godot loads only one copy of the library and each "
+"script that references the library will share static data like static or "
+"global variables.\n"
+"If [code]false[/code], Godot loads a separate copy of the library into "
+"memory for each script that references it."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:38
+msgid ""
+"If [code]true[/code], the editor will temporarily unload the library "
+"whenever the user switches away from the editor window, allowing the user to "
+"recompile the library without restarting Godot.\n"
+"[b]Note:[/b] If the library defines tool scripts that run inside the editor, "
+"[code]reloadable[/code] must be [code]false[/code]. Otherwise, the editor "
+"will attempt to unload the tool scripts while they're in use and crash."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:42
+msgid ""
+"If [code]true[/code], Godot loads the library at startup rather than the "
+"first time a script uses the library, calling [code]{prefix}"
+"gdnative_singleton[/code] after initializing the library (where [code]"
+"{prefix}[/code] is the value of [member symbol_prefix]). The library remains "
+"loaded as long as Godot is running.\n"
+"[b]Note:[/b] A singleton library cannot be [member reloadable]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/GDNativeLibrary.xml:46
+msgid ""
+"The prefix this library's entry point functions begin with. For example, a "
+"GDNativeLibrary would declare its [code]gdnative_init[/code] function as "
+"[code]godot_gdnative_init[/code] by default.\n"
+"On platforms that require statically linking libraries (currently only iOS), "
+"each library must have a different [code]symbol_prefix[/code]."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:4
+msgid "A script implemented in the GDScript programming language."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:7
+msgid ""
+"A script implemented in the GDScript programming language. The script "
+"extends the functionality of all objects that instance it.\n"
+"[method new] creates a new instance of the script. [method Object."
+"set_script] extends an existing object, if that object's class matches one "
+"of the script's base classes."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/"
+"index.html"
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:18
+msgid "Returns byte code for the script source code."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScript.xml:25
+msgid ""
+"Returns a new instance of the script.\n"
+"For example:\n"
+"[codeblock]\n"
+"var MyClass = load(\"myclass.gd\")\n"
+"var instance = MyClass.new()\n"
+"assert(instance.get_script() == MyClass)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:4
+msgid "State of a function call after yielding."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:7
+msgid ""
+"Calling [method @GDScript.yield] within a function will cause that function "
+"to yield and return its current state as an object of this type. The yielded "
+"function call can then be resumed later by calling [method resume] on this "
+"state object."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:18
+msgid ""
+"Check whether the function call may be resumed. This is not the case if the "
+"function state was already resumed.\n"
+"If [code]extended_check[/code] is enabled, it also checks if the associated "
+"script and object still exist. The extended check is done in debug mode as "
+"part of [method GDScriptFunctionState.resume], but you can use this if you "
+"know you may be trying to resume without knowing for sure the object and/or "
+"script have survived up to that point."
+msgstr ""
+
+#: modules/gdscript/doc_classes/GDScriptFunctionState.xml:28
+msgid ""
+"Resume execution of the yielded function call.\n"
+"If handed an argument, return the argument from the [method @GDScript.yield] "
+"call in the yielded function call. You can pass e.g. an [Array] to hand "
+"multiple arguments.\n"
+"This function returns what the resumed function call returns, possibly "
+"another function state if yielded again."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:4
+msgid ""
+"The generic 6-degrees-of-freedom joint can implement a variety of joint "
+"types by locking certain axes' rotation or translation."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:7
+msgid ""
+"The first 3 DOF axes are linear axes, which represent translation of Bodies, "
+"and the latter 3 DOF axes represent the angular motion. Each axis can be "
+"either locked, or limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:123
+msgid ""
+"The amount of rotational damping across the X axis.\n"
+"The lower, the longer an impulse from one side takes to travel to the other "
+"side."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:127
+msgid "If [code]true[/code], rotation across the X axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:130
+msgid ""
+"When rotating across the X axis, this error tolerance factor defines how "
+"much the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:133
+msgid ""
+"The maximum amount of force that can occur, when rotating around the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:136
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:139
+msgid ""
+"The amount of rotational restitution across the X axis. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:142
+msgid "The speed of all rotations across the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:145
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:148
+msgid ""
+"The amount of rotational damping across the Y axis. The lower, the more "
+"dampening occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:151
+msgid "If [code]true[/code], rotation across the Y axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:154
+msgid ""
+"When rotating across the Y axis, this error tolerance factor defines how "
+"much the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:157
+msgid ""
+"The maximum amount of force that can occur, when rotating around the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:160
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:163
+msgid ""
+"The amount of rotational restitution across the Y axis. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:166
+msgid "The speed of all rotations across the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:169
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:172
+msgid ""
+"The amount of rotational damping across the Z axis. The lower, the more "
+"dampening occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:175
+msgid "If [code]true[/code], rotation across the Z axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:178
+msgid ""
+"When rotating across the Z axis, this error tolerance factor defines how "
+"much the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:181
+msgid ""
+"The maximum amount of force that can occur, when rotating around the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:184
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:187
+msgid ""
+"The amount of rotational restitution across the Z axis. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:190
+msgid "The speed of all rotations across the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:193
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:196
+msgid "If [code]true[/code], a rotating motor at the X axis is enabled."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:199
+msgid "Maximum acceleration for the motor at the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:202
+msgid "Target speed for the motor at the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:205
+msgid "If [code]true[/code], a rotating motor at the Y axis is enabled."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:208
+msgid "Maximum acceleration for the motor at the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:211
+msgid "Target speed for the motor at the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:214
+msgid "If [code]true[/code], a rotating motor at the Z axis is enabled."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:217
+msgid "Maximum acceleration for the motor at the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:220
+msgid "Target speed for the motor at the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:247
+msgid "The amount of damping that happens at the X motion."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:250
+msgid "If [code]true[/code], the linear motion across the X axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:253
+msgid "The minimum difference between the pivot points' X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:256
+msgid ""
+"The amount of restitution on the X axis movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:259
+msgid ""
+"A factor applied to the movement across the X axis. The lower, the slower "
+"the movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:262
+msgid "The maximum difference between the pivot points' X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:265
+msgid "The amount of damping that happens at the Y motion."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:268
+msgid "If [code]true[/code], the linear motion across the Y axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:271
+msgid "The minimum difference between the pivot points' Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:274
+msgid ""
+"The amount of restitution on the Y axis movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:277
+msgid ""
+"A factor applied to the movement across the Y axis. The lower, the slower "
+"the movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:280
+msgid "The maximum difference between the pivot points' Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:283
+msgid "The amount of damping that happens at the Z motion."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:286
+msgid "If [code]true[/code], the linear motion across the Z axis is limited."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:289
+msgid "The minimum difference between the pivot points' Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:292
+msgid ""
+"The amount of restitution on the Z axis movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:295
+msgid ""
+"A factor applied to the movement across the Z axis. The lower, the slower "
+"the movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:298
+msgid "The maximum difference between the pivot points' Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:301
+msgid ""
+"If [code]true[/code], then there is a linear motor on the X axis. It will "
+"attempt to reach the target velocity while staying within the force limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:304
+msgid ""
+"The maximum force the linear motor can apply on the X axis while trying to "
+"reach the target velocity."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:307
+msgid "The speed that the linear motor will attempt to reach on the X axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:310
+msgid ""
+"If [code]true[/code], then there is a linear motor on the Y axis. It will "
+"attempt to reach the target velocity while staying within the force limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:313
+msgid ""
+"The maximum force the linear motor can apply on the Y axis while trying to "
+"reach the target velocity."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:316
+msgid "The speed that the linear motor will attempt to reach on the Y axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:319
+msgid ""
+"If [code]true[/code], then there is a linear motor on the Z axis. It will "
+"attempt to reach the target velocity while staying within the force limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:322
+msgid ""
+"The maximum force the linear motor can apply on the Z axis while trying to "
+"reach the target velocity."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:325
+msgid "The speed that the linear motor will attempt to reach on the Z axis."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:356 doc/classes/PhysicsServer3D.xml:1410
+msgid "The minimum difference between the pivot points' axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:359 doc/classes/PhysicsServer3D.xml:1413
+msgid "The maximum difference between the pivot points' axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:362
+msgid ""
+"A factor applied to the movement across the axes. The lower, the slower the "
+"movement."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:365
+msgid ""
+"The amount of restitution on the axes' movement. The lower, the more "
+"momentum gets lost."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:368 doc/classes/PhysicsServer3D.xml:1422
+msgid ""
+"The amount of damping that happens at the linear motion across the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:371
+msgid "The velocity the linear motor will try to reach."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:374
+msgid ""
+"The maximum force the linear motor will apply while trying to reach the "
+"velocity target."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:377 doc/classes/PhysicsServer3D.xml:1431
+msgid ""
+"The minimum rotation in negative direction to break loose and rotate around "
+"the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:380 doc/classes/PhysicsServer3D.xml:1434
+msgid ""
+"The minimum rotation in positive direction to break loose and rotate around "
+"the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:383
+msgid "The speed of all rotations across the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:386 doc/classes/PhysicsServer3D.xml:1440
+msgid ""
+"The amount of rotational damping across the axes. The lower, the more "
+"dampening occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:389 doc/classes/PhysicsServer3D.xml:1443
+msgid ""
+"The amount of rotational restitution across the axes. The lower, the more "
+"restitution occurs."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:392 doc/classes/PhysicsServer3D.xml:1446
+msgid ""
+"The maximum amount of force that can occur, when rotating around the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:395
+msgid ""
+"When rotating across the axes, this error tolerance factor defines how much "
+"the correction gets slowed down. The lower, the slower."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:398 doc/classes/PhysicsServer3D.xml:1452
+msgid "Target speed for the motor at the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:401 doc/classes/PhysicsServer3D.xml:1455
+msgid "Maximum acceleration for the motor at the axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:407
+msgid "If enabled, linear motion is possible within the given limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:410
+msgid "If enabled, rotational motion is possible within the given limits."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:417
+msgid "If enabled, there is a rotational motor across these axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:420
+msgid "If enabled, there is a linear motor across these axes."
+msgstr ""
+
+#: doc/classes/Generic6DOFJoint3D.xml:423 doc/classes/HingeJoint3D.xml:118
+msgid "Represents the size of the [enum Flag] enum."
+msgstr ""
+
+#: doc/classes/Geometry.xml:4
+msgid "Helper node to calculate generic geometry operations."
+msgstr ""
+
+#: doc/classes/Geometry.xml:7
+msgid ""
+"Geometry provides users with a set of helper functions to create geometric "
+"shapes, compute intersections between shapes, and process various other "
+"geometric operations."
+msgstr ""
+
+#: doc/classes/Geometry.xml:18
+msgid ""
+"Returns an array with 6 [Plane]s that describe the sides of a box centered "
+"at the origin. The box size is defined by [code]extents[/code], which "
+"represents one (positive) corner of the box (i.e. half its actual size)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:35
+msgid ""
+"Returns an array of [Plane]s closely bounding a faceted capsule centered at "
+"the origin with radius [code]radius[/code] and height [code]height[/code]. "
+"The parameter [code]sides[/code] defines how many planes will be generated "
+"for the side part of the capsule, whereas [code]lats[/code] gives the number "
+"of latitudinal steps at the bottom and top of the capsule. The parameter "
+"[code]axis[/code] describes the axis along which the capsule is oriented (0 "
+"for X, 1 for Y, 2 for Z)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:50
+msgid ""
+"Returns an array of [Plane]s closely bounding a faceted cylinder centered at "
+"the origin with radius [code]radius[/code] and height [code]height[/code]. "
+"The parameter [code]sides[/code] defines how many planes will be generated "
+"for the round part of the cylinder. The parameter [code]axis[/code] "
+"describes the axis along which the cylinder is oriented (0 for X, 1 for Y, 2 "
+"for Z)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:61
+msgid ""
+"Clips the polygon defined by the points in [code]points[/code] against the "
+"[code]plane[/code] and returns the points of the clipped polygon."
+msgstr ""
+
+#: doc/classes/Geometry.xml:72
+msgid ""
+"Clips [code]polygon_a[/code] against [code]polygon_b[/code] and returns an "
+"array of clipped polygons. This performs [constant OPERATION_DIFFERENCE] "
+"between polygons. Returns an empty array if [code]polygon_b[/code] "
+"completely overlaps [code]polygon_a[/code].\n"
+"If [code]polygon_b[/code] is enclosed by [code]polygon_a[/code], returns an "
+"outer polygon (boundary) and inner polygon (hole) which could be "
+"distinguished by calling [method is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:84
+msgid ""
+"Clips [code]polyline[/code] against [code]polygon[/code] and returns an "
+"array of clipped polylines. This performs [constant OPERATION_DIFFERENCE] "
+"between the polyline and the polygon. This operation can be thought of as "
+"cutting a line with a closed shape."
+msgstr ""
+
+#: doc/classes/Geometry.xml:93
+msgid ""
+"Given an array of [Vector2]s, returns the convex hull as a list of points in "
+"counterclockwise order. The last point is the same as the first one."
+msgstr ""
+
+#: doc/classes/Geometry.xml:104
+msgid ""
+"Mutually excludes common area defined by intersection of [code]polygon_a[/"
+"code] and [code]polygon_b[/code] (see [method intersect_polygons_2d]) and "
+"returns an array of excluded polygons. This performs [constant "
+"OPERATION_XOR] between polygons. In other words, returns all but common area "
+"between polygons.\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:118
+msgid ""
+"Returns the 3D point on the 3D segment ([code]s1[/code], [code]s2[/code]) "
+"that is closest to [code]point[/code]. The returned point will always be "
+"inside the specified segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:131
+msgid ""
+"Returns the 2D point on the 2D segment ([code]s1[/code], [code]s2[/code]) "
+"that is closest to [code]point[/code]. The returned point will always be "
+"inside the specified segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:144
+msgid ""
+"Returns the 3D point on the 3D line defined by ([code]s1[/code], [code]s2[/"
+"code]) that is closest to [code]point[/code]. The returned point can be "
+"inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. "
+"somewhere on the line extending from the segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:157
+msgid ""
+"Returns the 2D point on the 2D line defined by ([code]s1[/code], [code]s2[/"
+"code]) that is closest to [code]point[/code]. The returned point can be "
+"inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. "
+"somewhere on the line extending from the segment."
+msgstr ""
+
+#: doc/classes/Geometry.xml:172
+msgid ""
+"Given the two 3D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/"
+"code], [code]q2[/code]), finds those two points on the two segments that are "
+"closest to each other. Returns a [PackedVector3Array] that contains this "
+"point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point "
+"on ([code]q1[/code], [code]q2[/code])."
+msgstr ""
+
+#: doc/classes/Geometry.xml:187
+msgid ""
+"Given the two 2D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/"
+"code], [code]q2[/code]), finds those two points on the two segments that are "
+"closest to each other. Returns a [PackedVector2Array] that contains this "
+"point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point "
+"on ([code]q1[/code], [code]q2[/code])."
+msgstr ""
+
+#: doc/classes/Geometry.xml:196
+msgid "Used internally by the engine."
+msgstr ""
+
+#: doc/classes/Geometry.xml:207
+msgid ""
+"Intersects [code]polygon_a[/code] with [code]polygon_b[/code] and returns an "
+"array of intersected polygons. This performs [constant "
+"OPERATION_INTERSECTION] between polygons. In other words, returns common "
+"area shared by polygons. Returns an empty array if no intersection occurs.\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:219
+msgid ""
+"Intersects [code]polyline[/code] with [code]polygon[/code] and returns an "
+"array of intersected polylines. This performs [constant "
+"OPERATION_INTERSECTION] between the polyline and the polygon. This operation "
+"can be thought of as chopping a line with a closed shape."
+msgstr ""
+
+#: doc/classes/Geometry.xml:232
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is inside the circle or if "
+"it's located exactly [i]on[/i] the circle's boundary, otherwise returns "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:243
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is inside [code]polygon[/"
+"code] or if it's located exactly [i]on[/i] polygon's boundary, otherwise "
+"returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:252
+msgid ""
+"Returns [code]true[/code] if [code]polygon[/code]'s vertices are ordered in "
+"clockwise order, otherwise returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:267
+msgid ""
+"Checks if the two lines ([code]from_a[/code], [code]dir_a[/code]) and "
+"([code]from_b[/code], [code]dir_b[/code]) intersect. If yes, return the "
+"point of intersection as [Vector2]. If no intersection takes place, returns "
+"an empty [Variant].\n"
+"[b]Note:[/b] The lines are specified using direction vectors, not end points."
+msgstr ""
+
+#: doc/classes/Geometry.xml:277
+msgid ""
+"Given an array of [Vector2]s representing tiles, builds an atlas. The "
+"returned dictionary has two keys: [code]points[/code] is a vector of "
+"[Vector2] that specifies the positions of each tile, [code]size[/code] "
+"contains the overall size of the whole atlas as [Vector2]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:288
+msgid ""
+"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.\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:302
+msgid ""
+"Inflates or deflates [code]polygon[/code] by [code]delta[/code] units "
+"(pixels). If [code]delta[/code] is positive, makes the polygon grow outward. "
+"If [code]delta[/code] is negative, shrinks the polygon inward. Returns an "
+"array of polygons because inflating/deflating may result in multiple "
+"discrete polygons. Returns an empty array if [code]delta[/code] is negative "
+"and the absolute value of it approximately exceeds the minimum bounding "
+"rectangle dimensions of the polygon.\n"
+"Each polygon's vertices will be rounded as determined by [code]join_type[/"
+"code], see [enum PolyJoinType].\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:319
+msgid ""
+"Inflates or deflates [code]polyline[/code] by [code]delta[/code] units "
+"(pixels), producing polygons. If [code]delta[/code] is positive, makes the "
+"polyline grow outward. Returns an array of polygons because inflating/"
+"deflating may result in multiple discrete polygons. If [code]delta[/code] is "
+"negative, returns an empty array.\n"
+"Each polygon's vertices will be rounded as determined by [code]join_type[/"
+"code], see [enum PolyJoinType].\n"
+"Each polygon's endpoints will be rounded as determined by [code]end_type[/"
+"code], see [enum PolyEndType].\n"
+"The operation may result in an outer polygon (boundary) and inner polygon "
+"(hole) produced which could be distinguished by calling [method "
+"is_polygon_clockwise]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:337
+msgid ""
+"Returns if [code]point[/code] is inside the triangle specified by [code]a[/"
+"code], [code]b[/code] and [code]c[/code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:354
+msgid ""
+"Tests if the 3D ray starting at [code]from[/code] with the direction of "
+"[code]dir[/code] intersects the triangle specified by [code]a[/code], "
+"[code]b[/code] and [code]c[/code]. If yes, returns the point of intersection "
+"as [Vector3]. If no intersection takes place, an empty [Variant] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:369
+msgid ""
+"Given the 2D segment ([code]segment_from[/code], [code]segment_to[/code]), "
+"returns the position on the segment (as a number between 0 and 1) at which "
+"the segment hits the circle that is located at position "
+"[code]circle_position[/code] and has radius [code]circle_radius[/code]. If "
+"the segment does not intersect the circle, -1 is returned (this is also the "
+"case if the line extending the segment would intersect the circle, but the "
+"segment does not)."
+msgstr ""
+
+#: doc/classes/Geometry.xml:382
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Geometry.xml:397
+msgid ""
+"Checks if the segment ([code]from[/code], [code]to[/code]) intersects the "
+"cylinder with height [code]height[/code] that is centered at the origin and "
+"has radius [code]radius[/code]. If no, returns an empty "
+"[PackedVector3Array]. If an intersection takes place, the returned array "
+"contains the point of intersection and the cylinder's normal at the point of "
+"intersection."
+msgstr ""
+
+#: doc/classes/Geometry.xml:412
+msgid ""
+"Checks if the two segments ([code]from_a[/code], [code]to_a[/code]) and "
+"([code]from_b[/code], [code]to_b[/code]) intersect. If yes, return the point "
+"of intersection as [Vector2]. If no intersection takes place, returns an "
+"empty [Variant]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:427
+msgid ""
+"Checks if the segment ([code]from[/code], [code]to[/code]) intersects the "
+"sphere that is located at [code]sphere_position[/code] and has radius "
+"[code]sphere_radius[/code]. If no, returns an empty [PackedVector3Array]. If "
+"yes, returns a [PackedVector3Array] containing the point of intersection and "
+"the sphere's normal at the point of intersection."
+msgstr ""
+
+#: doc/classes/Geometry.xml:444
+msgid ""
+"Tests if the segment ([code]from[/code], [code]to[/code]) intersects the "
+"triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the "
+"point of intersection as [Vector3]. If no intersection takes place, an empty "
+"[Variant] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:453
+msgid ""
+"Triangulates the area specified by discrete set of [code]points[/code] such "
+"that no point is inside the circumcircle of any resulting triangle. Returns "
+"a [PackedInt32Array] where each triangle consists of three consecutive point "
+"indices into [code]points[/code] (i.e. the returned array will have [code]n "
+"* 3[/code] elements, with [code]n[/code] being the number of found "
+"triangles). If the triangulation did not succeed, an empty "
+"[PackedInt32Array] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:462
+msgid ""
+"Triangulates the polygon specified by the points in [code]polygon[/code]. "
+"Returns a [PackedInt32Array] where each triangle consists of three "
+"consecutive point indices into [code]polygon[/code] (i.e. the returned array "
+"will have [code]n * 3[/code] elements, with [code]n[/code] being the number "
+"of found triangles). If the triangulation did not succeed, an empty "
+"[PackedInt32Array] is returned."
+msgstr ""
+
+#: doc/classes/Geometry.xml:468
+msgid ""
+"Create regions where either subject or clip polygons (or both) are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:471
+msgid ""
+"Create regions where subject polygons are filled except where clip polygons "
+"are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:474
+msgid "Create regions where both subject and clip polygons are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:477
+msgid ""
+"Create regions where either subject or clip polygons are filled but not "
+"where both are filled."
+msgstr ""
+
+#: doc/classes/Geometry.xml:480
+msgid ""
+"Squaring is applied uniformally at all convex edge joins at [code]1 * delta[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Geometry.xml:483
+msgid ""
+"While flattened paths can never perfectly trace an arc, they are "
+"approximated by a series of arc chords."
+msgstr ""
+
+#: doc/classes/Geometry.xml:486
+msgid ""
+"There's a necessary limit to mitered joins since offsetting edges that join "
+"at very acute angles will produce excessively long and narrow \"spikes\". "
+"For any given edge join, when miter offsetting would exceed that maximum "
+"distance, \"square\" joining is applied."
+msgstr ""
+
+#: doc/classes/Geometry.xml:489
+msgid ""
+"Endpoints are joined using the [enum PolyJoinType] value and the path filled "
+"as a polygon."
+msgstr ""
+
+#: doc/classes/Geometry.xml:492
+msgid ""
+"Endpoints are joined using the [enum PolyJoinType] value and the path filled "
+"as a polyline."
+msgstr ""
+
+#: doc/classes/Geometry.xml:495
+msgid "Endpoints are squared off with no extension."
+msgstr ""
+
+#: doc/classes/Geometry.xml:498
+msgid "Endpoints are squared off and extended by [code]delta[/code] units."
+msgstr ""
+
+#: doc/classes/Geometry.xml:501
+msgid "Endpoints are rounded off and extended by [code]delta[/code] units."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:4
+msgid "Base node for geometry-based visual instances."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:7
+msgid ""
+"Base node for geometry-based visual instances. Shares some common "
+"functionality like visibility and custom materials."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:18
+msgid ""
+"Returns the [enum GeometryInstance3D.Flags] that have been set for this "
+"object."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:27
+msgid ""
+"Overrides the bounding box of this node with a custom one. To remove it, set "
+"an [AABB] with all fields set to zero."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:38
+msgid ""
+"Sets the [enum GeometryInstance3D.Flags] specified. See [enum "
+"GeometryInstance3D.Flags] for options."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:44
+msgid ""
+"The selected shadow casting flag. See [enum ShadowCastingSetting] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:47
+msgid ""
+"The extra distance added to the GeometryInstance3D's bounding box ([AABB]) "
+"to increase its cull box."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:50
+msgid ""
+"The GeometryInstance3D's max LOD distance.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:54
+msgid ""
+"The GeometryInstance3D's max LOD margin.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:58
+msgid ""
+"The GeometryInstance3D's min LOD distance.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:62
+msgid ""
+"The GeometryInstance3D's min LOD margin.\n"
+"[b]Note:[/b] This property currently has no effect."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:66
+msgid ""
+"The material override for the whole geometry.\n"
+"If a material is assigned to this property, it will be used instead of any "
+"material set in any material slot of the mesh."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:72
+msgid ""
+"If [code]true[/code], this GeometryInstance3D will be used when baking "
+"lights using a [GIProbe]."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:77
+msgid "Will not cast any shadows."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:80
+msgid ""
+"Will cast shadows from all visible faces in the GeometryInstance3D.\n"
+"Will take culling into account, so faces not being rendered will not be "
+"taken into account when shadow casting."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:84
+msgid ""
+"Will cast shadows from all visible faces in the GeometryInstance3D.\n"
+"Will not take culling into account, so all faces will be taken into account "
+"when shadow casting."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:88
+msgid ""
+"Will only show the shadows casted from this object.\n"
+"In other words, the actual mesh will not be visible, only the shadows casted "
+"from the mesh will be."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:92
+msgid ""
+"Will allow the GeometryInstance3D to be used when baking lights using a "
+"[GIProbe]."
+msgstr ""
+
+#: doc/classes/GeometryInstance3D.xml:97
+msgid ""
+"Unused in this class, exposed for consistency with [enum RenderingServer."
+"InstanceFlags]."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:4
+msgid "Real-time global illumination (GI) probe."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:7
+msgid ""
+"[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.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html"
+msgstr ""
+
+#: doc/classes/GIProbe.xml:22
+msgid ""
+"Bakes the effect from all [GeometryInstance3D]s marked with [member "
+"GeometryInstance3D.use_in_baked_light] and [Light3D]s marked with either "
+"[constant Light3D.BAKE_INDIRECT] or [constant Light3D.BAKE_ALL]. If "
+"[code]create_visual_debug[/code] is [code]true[/code], after baking the "
+"light, this will generate a [MultiMesh] that has a cube representing each "
+"solid cell with each cube colored to the cell's albedo color. This can be "
+"used to visualize the [GIProbe]'s data and debug any issues that may be "
+"occurring."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:29
+msgid "Calls [method bake] with [code]create_visual_debug[/code] enabled."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:35
+msgid "The [GIProbeData] resource that holds the data for this [GIProbe]."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:38
+msgid ""
+"The size of the area covered by the [GIProbe]. If you make the extents "
+"larger without increasing the subdivisions with [member subdiv], the size of "
+"each cell will increase and result in lower detailed lighting."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:41
+msgid ""
+"Number of times to subdivide the grid that the [GIProbe] operates on. A "
+"higher number results in finer detail and thus higher visual quality, while "
+"lower numbers result in better performance."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:46
+msgid ""
+"Use 64 subdivisions. This is the lowest quality setting, but the fastest. "
+"Use it if you can, but especially use it on lower-end hardware."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:49
+msgid "Use 128 subdivisions. This is the default quality setting."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:52
+msgid "Use 256 subdivisions."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:55
+msgid ""
+"Use 512 subdivisions. This is the highest quality setting, but the slowest. "
+"On lower-end hardware this could cause the GPU to stall."
+msgstr ""
+
+#: doc/classes/GIProbe.xml:58
+msgid "Represents the size of the [enum Subdiv] enum."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:14
+msgid "Attaches the current thread to the mono runtime."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:21
+msgid "Detaches the current thread from the mono runtime."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:42
+msgid "Returns whether the domain is being finalized."
+msgstr ""
+
+#: modules/mono/doc_classes/GodotSharp.xml:61
+msgid "Returns whether the scripts domain is loaded."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:4
+msgid "2D particle emitter."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:7
+msgid ""
+"2D particle node used to create a variety of particle systems and effects. "
+"[GPUParticles2D] features an emitter that generates some number of particles "
+"at a given rate.\n"
+"Use the [code]process_material[/code] property to add a [ParticlesMaterial] "
+"to configure particle appearance and behavior. Alternatively, you can add a "
+"[ShaderMaterial] which will be applied to all particles."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:18
+msgid "Returns a rectangle containing the positions of all existing particles."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:25
+msgid "Restarts all the existing particles."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:64 doc/classes/GPUParticles3D.xml:96
+msgid ""
+"[Material] for processing particles. Can be a [ParticlesMaterial] or a "
+"[ShaderMaterial]."
+msgstr ""
+
+#: doc/classes/GPUParticles2D.xml:76
+msgid "Editor visibility helper."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:4
+msgid "3D particle emitter."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:7
+msgid ""
+"3D particle node used to create a variety of particle systems and effects. "
+"[GPUParticles3D] features an emitter that generates some number of particles "
+"at a given rate.\n"
+"Use the [code]process_material[/code] property to add a [ParticlesMaterial] "
+"to configure particle appearance and behavior. Alternatively, you can add a "
+"[ShaderMaterial] which will be applied to all particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/"
+"controlling_thousands_of_fish.html"
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:18
+msgid ""
+"Returns the axis-aligned bounding box that contains all the particles that "
+"are active in the current frame."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:27
+msgid "Returns the [Mesh] that is drawn at index [code]pass[/code]."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:34
+msgid "Restarts the particle emission, clearing existing particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:45
+msgid "Sets the [Mesh] that is drawn at index [code]pass[/code]."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:51
+msgid "Number of particles to emit."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:57
+msgid "[Mesh] that is drawn for the first draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:60
+msgid "[Mesh] that is drawn for the second draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:63
+msgid "[Mesh] that is drawn for the third draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:66
+msgid "[Mesh] that is drawn for the fourth draw pass."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:69
+msgid "The number of draw passes when rendering particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:75
+msgid ""
+"Time ratio between each emission. If [code]0[/code], particles are emitted "
+"continuously. If [code]1[/code], all particles are emitted simultaneously."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:90
+msgid ""
+"If [code]true[/code], only [code]amount[/code] particles will be emitted."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:93
+msgid ""
+"Amount of time to preprocess the particles before animation starts. Lets you "
+"start the animation some time after particles have started emitting."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:99
+msgid "Emission randomness ratio."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:102
+msgid ""
+"Speed scaling ratio. A value of [code]0[/code] can be used to pause the "
+"particles."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:105
+msgid ""
+"The [AABB] that determines the area of the world part of which needs to be "
+"visible on screen for the particle system to be active."
+msgstr ""
+
+#: doc/classes/GPUParticles3D.xml:119
+msgid "Maximum number of draw passes supported."
+msgstr ""
+
+#: doc/classes/Gradient.xml:4
+msgid ""
+"A color interpolator resource which can be used to generate colors between "
+"user-defined color points."
+msgstr ""
+
+#: doc/classes/Gradient.xml:7
+msgid ""
+"Given a set of colors, this resource will interpolate them in order. This "
+"means that if you have color 1, color 2 and color 3, the ramp will "
+"interpolate from color 1 to color 2 and from color 2 to color 3. The ramp "
+"will initially have 2 colors (black and white), one (black) at ramp lower "
+"offset 0 and the other (white) at the ramp higher offset 1."
+msgstr ""
+
+#: doc/classes/Gradient.xml:20
+msgid ""
+"Adds the specified color to the end of the ramp, with the specified offset."
+msgstr ""
+
+#: doc/classes/Gradient.xml:29
+msgid "Returns the color of the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:38
+msgid "Returns the offset of the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:45
+msgid "Returns the number of colors in the ramp."
+msgstr ""
+
+#: doc/classes/Gradient.xml:54
+msgid "Returns the interpolated color specified by [code]offset[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:63
+msgid "Removes the color at the index [code]offset[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:74
+msgid "Sets the color of the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:85
+msgid "Sets the offset for the ramp color at index [code]point[/code]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:91
+msgid "Gradient's colors returned as a [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/Gradient.xml:94
+msgid "Gradient's offsets returned as a [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:4
+msgid "Gradient-filled texture."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:7
+msgid ""
+"GradientTexture uses a [Gradient] to fill the texture data. The gradient "
+"will be filled from left to right using colors obtained from the gradient. "
+"This means the texture does not necessarily represent an exact copy of the "
+"gradient, but instead an interpolation of samples obtained from the gradient "
+"at fixed steps (see [member width])."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:15
+msgid "The [Gradient] that will be used to fill the texture."
+msgstr ""
+
+#: doc/classes/GradientTexture.xml:18
+msgid "The number of color samples that will be obtained from the [Gradient]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:4
+msgid ""
+"GraphEdit is an area capable of showing various GraphNodes. It manages "
+"connection events between them."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:7
+msgid ""
+"GraphEdit manages the showing of GraphNodes it contains, as well as "
+"connections and disconnections between them. Signals are sent for each of "
+"these two events. Disconnection between GraphNode slots is disabled by "
+"default.\n"
+"It is greatly advised to enable low-processor usage mode (see [member OS."
+"low_processor_usage_mode]) when using GraphEdits."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:21
+msgid ""
+"Makes possible the connection between two different slot types. The type is "
+"defined with the [method GraphNode.set_slot] method."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:30
+msgid ""
+"Makes possible to disconnect nodes when dragging from the slot at the left "
+"if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:39
+msgid ""
+"Makes possible to disconnect nodes when dragging from the slot at the right "
+"if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:46
+msgid "Removes all connections between nodes."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:61
+msgid ""
+"Create a connection between the [code]from_port[/code] slot of the "
+"[code]from[/code] GraphNode and the [code]to_port[/code] slot of the "
+"[code]to[/code] GraphNode. If the connection already exists, no connection "
+"is created."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:76
+msgid ""
+"Removes the connection between the [code]from_port[/code] slot of the "
+"[code]from[/code] GraphNode and the [code]to_port[/code] slot of the "
+"[code]to[/code] GraphNode. If the connection does not exist, no connection "
+"is removed."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:83
+msgid ""
+"Returns an Array containing the list of connections. A connection consists "
+"in a structure of the form [code]{ from_port: 0, from: \"GraphNode name 0\", "
+"to_port: 1, to: \"GraphNode name 1\" }[/code]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:90
+msgid ""
+"Gets the [HBoxContainer] that contains the zooming and grid snap controls in "
+"the top left of the graph.\n"
+"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."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:106
+msgid ""
+"Returns [code]true[/code] if the [code]from_port[/code] slot of the "
+"[code]from[/code] GraphNode is connected to the [code]to_port[/code] slot of "
+"the [code]to[/code] GraphNode."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:117
+msgid "Returns whether it's possible to connect slots of the specified types."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:128
+msgid ""
+"Makes it not possible to connect between two different slot types. The type "
+"is defined with the [method GraphNode.set_slot] method."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:137
+msgid ""
+"Removes the possibility to disconnect nodes when dragging from the slot at "
+"the left if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:146
+msgid ""
+"Removes the possibility to disconnect nodes when dragging from the slot at "
+"the right if it has the specified type."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:163
+msgid ""
+"Sets the coloration of the connection between [code]from[/code]'s "
+"[code]from_port[/code] and [code]to[/code]'s [code]to_port[/code] with the "
+"color provided in the [code]activity[/code] theme property."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:172
+msgid "Sets the specified [code]node[/code] as the one selected."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:180
+msgid ""
+"If [code]true[/code], enables disconnection of existing connections in the "
+"GraphEdit by dragging the right end."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:183
+msgid "The scroll offset."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:186
+msgid "The snapping distance in pixels."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:189
+msgid "If [code]true[/code], enables snapping."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:192
+msgid "The current zoom value."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:198
+msgid "Emitted at the beginning of a GraphNode movement."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:203
+msgid "Emitted at the end of a GraphNode movement."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:214
+msgid ""
+"Emitted when user dragging connection from input port into empty space of "
+"the graph."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:227
+msgid ""
+"Emitted to the GraphEdit when the connection between the [code]from_slot[/"
+"code] slot of the [code]from[/code] GraphNode and the [code]to_slot[/code] "
+"slot of the [code]to[/code] GraphNode is attempted to be created."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:238
+msgid ""
+"Emitted when user dragging connection from output port into empty space of "
+"the graph."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:243
+msgid "Emitted when the user presses [code]Ctrl + C[/code]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:248
+msgid "Emitted when a GraphNode is attempted to be removed from the GraphEdit."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:261
+msgid ""
+"Emitted to the GraphEdit when the connection between [code]from_slot[/code] "
+"slot of [code]from[/code] GraphNode and [code]to_slot[/code] slot of "
+"[code]to[/code] GraphNode is attempted to be removed."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:266
+msgid ""
+"Emitted when a GraphNode is attempted to be duplicated in the GraphEdit."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:273
+msgid "Emitted when a GraphNode is selected."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:278
+msgid "Emitted when the user presses [code]Ctrl + V[/code]."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:285
+msgid ""
+"Emitted when a popup is requested. Happens on right-clicking in the "
+"GraphEdit. [code]position[/code] is the position of the mouse pointer when "
+"the signal is sent."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:292
+msgid ""
+"Emitted when the scroll offset is changed by the user. It will not be "
+"emitted when changed in code."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:306
+msgid "The background drawn under the grid."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:309
+msgid "Color of major grid lines."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:312
+msgid "Color of minor grid lines."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:315
+msgid "The icon for the zoom out button."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:318
+msgid "The icon for the zoom in button."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:321
+msgid ""
+"The horizontal range within which a port can be grabbed (on both sides)."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:324
+msgid "The vertical range within which a port can be grabbed (on both sides)."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:327
+msgid "The icon for the zoom reset button."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:330
+msgid "The fill color of the selection rectangle."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:333
+msgid "The outline color of the selection rectangle."
+msgstr ""
+
+#: doc/classes/GraphEdit.xml:336
+msgid "The icon for the snap toggle button."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:4
+msgid ""
+"A GraphNode is a container with potentially several input and output slots "
+"allowing connections between GraphNodes. Slots can have different, "
+"incompatible types."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:18
+msgid "Disables all input and output slots of the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:27
+msgid "Disables input and output slot whose index is [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:36
+msgid "Returns the color of the input connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:43
+msgid ""
+"Returns the number of enabled input slots (connections) to the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:52
+msgid "Returns the position of the input connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:61
+msgid "Returns the type of the input connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:70
+msgid "Returns the color of the output connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:77
+msgid ""
+"Returns the number of enabled output slots (connections) of the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:86
+msgid "Returns the position of the output connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:95
+msgid "Returns the type of the output connection [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:104
+msgid "Returns the color set to [code]idx[/code] left (input) slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:113
+msgid "Returns the color set to [code]idx[/code] right (output) slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:122
+msgid "Returns the (integer) type of left (input) [code]idx[/code] slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:131
+msgid "Returns the (integer) type of right (output) [code]idx[/code] slot."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:140
+msgid ""
+"Returns [code]true[/code] if left (input) slot [code]idx[/code] is enabled, "
+"[code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:149
+msgid ""
+"Returns [code]true[/code] if right (output) slot [code]idx[/code] is "
+"enabled, [code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:174
+msgid ""
+"Sets properties of the slot with ID [code]idx[/code].\n"
+"If [code]enable_left[/code]/[code]right[/code], a port will appear and the "
+"slot will be able to be connected from this side.\n"
+"[code]type_left[/code]/[code]right[/code] is an arbitrary type of the port. "
+"Only ports with the same type values can be connected.\n"
+"[code]color_left[/code]/[code]right[/code] is the tint of the port's icon on "
+"this side.\n"
+"[code]custom_left[/code]/[code]right[/code] is a custom texture for this "
+"side's port.\n"
+"[b]Note:[/b] This method only sets properties of the slot. To create the "
+"slot, add a [Control]-derived child to the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:185
+msgid "If [code]true[/code], the GraphNode is a comment node."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:189
+msgid ""
+"The offset of the GraphNode, relative to the scroll offset of the "
+"[GraphEdit].\n"
+"[b]Note:[/b] You cannot use position directly, as [GraphEdit] is a "
+"[Container]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:193
+msgid "Sets the overlay shown above the GraphNode. See [enum Overlay]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:196
+msgid ""
+"If [code]true[/code], the user can resize the GraphNode.\n"
+"[b]Note:[/b] Dragging the handle will only emit the [signal resize_request] "
+"signal, the GraphNode needs to be resized manually."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:200
+msgid "If [code]true[/code], the GraphNode is selected."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:203
+msgid ""
+"If [code]true[/code], the close button will be visible.\n"
+"[b]Note:[/b] Pressing it will only emit the [signal close_request] signal, "
+"the GraphNode needs to be removed manually."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:207
+msgid "The text displayed in the GraphNode's title bar."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:213
+msgid ""
+"Emitted when the GraphNode is requested to be closed. Happens on clicking "
+"the close button (see [member show_close])."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:222
+msgid "Emitted when the GraphNode is dragged."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:227
+msgid "Emitted when the GraphNode is moved."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:232
+msgid ""
+"Emitted when the GraphNode is requested to be displayed over other ones. "
+"Happens on focusing (clicking into) the GraphNode."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:239
+msgid ""
+"Emitted when the GraphNode is requested to be resized. Happens on dragging "
+"the resizer handle (see [member resizable])."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:245
+msgid "No overlay is shown."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:248
+msgid "Show overlay set in the [code]breakpoint[/code] theme property."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:251
+msgid "Show overlay set in the [code]position[/code] theme property."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:256
+msgid ""
+"The background used when [member overlay] is set to [constant "
+"OVERLAY_BREAKPOINT]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:259
+msgid ""
+"The icon for the close button, visible when [member show_close] is enabled."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:262
+msgid "The color modulation applied to the close button icon."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:265
+msgid "The vertical offset of the close button."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:268
+msgid "The [StyleBox] used when [member comment] is enabled."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:271
+msgid ""
+"The [StyleBox] used when [member comment] is enabled and the [GraphNode] is "
+"focused."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:278
+msgid "The default background for [GraphNode]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:281
+msgid "The icon used for representing ports."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:284
+msgid "Horizontal offset for the ports."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:287
+msgid ""
+"The background used when [member overlay] is set to [constant "
+"OVERLAY_POSITION]."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:290
+msgid "The icon used for resizer, visible when [member resizable] is enabled."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:293
+msgid "The color modulation applied to the resizer icon."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:296
+msgid "The background used when the [GraphNode] is selected."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:299
+msgid "The vertical distance between ports."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:302
+msgid "Color of the title text."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:305
+msgid "Font used for the title text."
+msgstr ""
+
+#: doc/classes/GraphNode.xml:308
+msgid "Vertical offset of the title text."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:4
+msgid "Grid container used to arrange elements in a grid like layout."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:7
+msgid ""
+"Grid container will arrange its children in a grid like structure, the grid "
+"columns are specified using the [member columns] property and the number of "
+"rows will be equal to the number of children in the container divided by the "
+"number of columns. For example, if the container has 5 children, and 2 "
+"columns, there will be 3 rows in the container.\n"
+"Notice that grid layout will preserve the columns and rows for every size of "
+"the container, and that empty columns will be expanded automatically."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:16
+msgid ""
+"The number of columns in the [GridContainer]. If modified, [GridContainer] "
+"reorders its children to accommodate the new layout."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:23
+msgid "The horizontal separation of children nodes."
+msgstr ""
+
+#: doc/classes/GridContainer.xml:26
+msgid "The vertical separation of children nodes."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:4
+msgid "Node for 3D tile-based maps."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:7
+msgid ""
+"GridMap lets you place meshes on a grid interactively. It works both from "
+"the editor and from scripts, which can help you create in-game level "
+"editors.\n"
+"GridMaps use a [MeshLibrary] which contains a list of tiles. Each tile is a "
+"mesh with materials plus optional collision and navigation shapes.\n"
+"A GridMap contains a collection of cells. Each grid cell refers to a tile in "
+"the [MeshLibrary]. All cells in the map have the same dimensions.\n"
+"Internally, a GridMap is split into a sparse collection of octants for "
+"efficient rendering and physics processing. Every octant has the same "
+"dimensions and can contain several cells."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:13
+msgid "https://docs.godotengine.org/en/latest/tutorials/3d/using_gridmaps.html"
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:20
+msgid "Clear all cells."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:53
+msgid ""
+"The [MeshLibrary] item index located at the grid-based X, Y and Z "
+"coordinates. If the cell is empty, [constant INVALID_CELL_ITEM] will be "
+"returned."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:66
+msgid ""
+"The orientation of the cell at the grid-based X, Y and Z coordinates. -1 is "
+"returned if the cell is empty."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:75 doc/classes/PhysicsBody2D.xml:35
+#: doc/classes/PhysicsBody3D.xml:35
+msgid "Returns an individual bit on the [member collision_layer]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:84 doc/classes/PhysicsBody2D.xml:44
+#: doc/classes/PhysicsBody3D.xml:44
+msgid "Returns an individual bit on the [member collision_mask]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:91
+msgid ""
+"Returns an array of [Transform] and [Mesh] references corresponding to the "
+"non-empty cells in the grid. The transforms are specified in world space."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:98
+msgid ""
+"Returns an array of [Vector3] with the non-empty cell coordinates in the "
+"grid map."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:121
+msgid ""
+"Returns the position of a grid cell in the GridMap's local coordinate space."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:146
+msgid ""
+"Sets the mesh index for the cell referenced by its grid-based X, Y and Z "
+"coordinates.\n"
+"A negative item index such as [constant INVALID_CELL_ITEM] will clear the "
+"cell.\n"
+"Optionally, the item's orientation can be passed. For valid orientation "
+"values, see [method Basis.get_orthogonal_index]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:173
+msgid "Sets an individual bit on the [member collision_layer]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:184
+msgid "Sets an individual bit on the [member collision_mask]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:193
+msgid ""
+"Returns the coordinates of the grid cell containing the given point.\n"
+"[code]pos[/code] should be in the GridMap's local coordinate space."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:200
+msgid "If [code]true[/code], grid items are centered on the X axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:203
+msgid "If [code]true[/code], grid items are centered on the Y axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:206
+msgid "If [code]true[/code], grid items are centered on the Z axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:209
+msgid ""
+"The size of each octant measured in number of cells. This applies to all "
+"three axis."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:212
+msgid ""
+"The scale of the cell items.\n"
+"This does not affect the size of the grid cells themselves, only the items "
+"in them. This can be used to make cell items overlap their neighbors."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:216
+msgid ""
+"The dimensions of the grid's cells.\n"
+"This does not affect the size of the meshes. See [member cell_scale]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:220
+msgid ""
+"The physics layers this GridMap is in.\n"
+"GridMaps act as static bodies, meaning they aren't affected by gravity or "
+"other forces. They only affect other physics bodies that collide with them."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:224
+msgid "The physics layers this GridMap detects collisions in."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:227
+msgid "The assigned [MeshLibrary]."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:235
+msgid "Emitted when [member cell_size] changes."
+msgstr ""
+
+#: modules/gridmap/doc_classes/GridMap.xml:241
+msgid ""
+"Invalid cell item that can be used in [method set_cell_item] to clear cells "
+"(or represent an empty cell in [method get_cell_item])."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:4
+msgid "Groove constraint for 2D physics."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:7
+msgid ""
+"Groove constraint for 2D physics. This is useful for making a body \"slide\" "
+"through a segment placed in another."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:15
+msgid ""
+"The body B's initial anchor position defined by the joint's origin and a "
+"local offset [member initial_offset] along the joint's Y axis (along the "
+"groove)."
+msgstr ""
+
+#: doc/classes/GrooveJoint2D.xml:18
+msgid ""
+"The groove's length. The groove is from the joint's origin towards [member "
+"length] along the joint's local Y axis."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:4
+msgid "Context to compute cryptographic hashes over multiple iterations."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:7
+msgid ""
+"The HashingContext class provides an interface for computing cryptographic "
+"hashes over multiple iterations. This is useful for example when computing "
+"hashes of big files (so you don't have to load them all in memory), network "
+"streams, and data streams in general (so you don't have to hold buffers).\n"
+"The [enum HashType] enum shows the supported hashing algorithms.\n"
+"[codeblock]\n"
+"const CHUNK_SIZE = 1024\n"
+"\n"
+"func hash_file(path):\n"
+" var ctx = HashingContext.new()\n"
+" var file = File.new()\n"
+" # Start a SHA-256 context.\n"
+" ctx.start(HashingContext.HASH_SHA256)\n"
+" # Check that file exists.\n"
+" if not file.file_exists(path):\n"
+" return\n"
+" # Open the file to hash.\n"
+" file.open(path, File.READ)\n"
+" # Update the context after reading each chunk.\n"
+" while not file.eof_reached():\n"
+" ctx.update(file.get_buffer(CHUNK_SIZE))\n"
+" # Get the computed hash.\n"
+" var res = ctx.finish()\n"
+" # Print the result as hex string and array.\n"
+" printt(res.hex_encode(), Array(res))\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:39
+msgid "Closes the current context, and return the computed hash."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:48
+msgid ""
+"Starts a new hash computation of the given [code]type[/code] (e.g. [constant "
+"HASH_SHA256] to start computation of a SHA-256)."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:57
+msgid "Updates the computation with the given [code]chunk[/code] of data."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:63
+msgid "Hashing algorithm: MD5."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:66
+msgid "Hashing algorithm: SHA-1."
+msgstr ""
+
+#: doc/classes/HashingContext.xml:69
+msgid "Hashing algorithm: SHA-256."
+msgstr ""
+
+#: doc/classes/HBoxContainer.xml:4
+msgid "Horizontal box container."
+msgstr ""
+
+#: doc/classes/HBoxContainer.xml:7
+msgid "Horizontal box container. See [BoxContainer]."
+msgstr ""
+
+#: doc/classes/HBoxContainer.xml:17
+msgid "The horizontal space between the [HBoxContainer]'s elements."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:4
+msgid "Height map shape for 3D physics (Bullet only)."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:7
+msgid ""
+"Height map shape resource, which can be added to a [PhysicsBody3D] or "
+"[Area3D]."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:15
+msgid ""
+"Height map data, pool array must be of [member map_width] * [member "
+"map_depth] size."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:18
+msgid ""
+"Depth of the height map data. Changing this will resize the [member "
+"map_data]."
+msgstr ""
+
+#: doc/classes/HeightMapShape3D.xml:21
+msgid ""
+"Width of the height map data. Changing this will resize the [member "
+"map_data]."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:4
+msgid "A hinge between two 3D bodies."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:7
+msgid ""
+"A HingeJoint3D normally uses the Z axis of body A as the hinge axis, another "
+"axis can be specified when adding it manually though."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:18 doc/classes/SpriteBase3D.xml:24
+msgid "Returns the value of the specified flag."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:27 doc/classes/ParticlesMaterial.xml:29
+#: doc/classes/PinJoint3D.xml:18
+msgid "Returns the value of the specified parameter."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:38
+msgid "If [code]true[/code], enables the specified flag."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:49 doc/classes/PinJoint3D.xml:29
+msgid "Sets the value of the specified parameter."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:55 doc/classes/HingeJoint3D.xml:95
+#: doc/classes/PhysicsServer3D.xml:1301
+msgid ""
+"The speed with which the rotation across the axis perpendicular to the hinge "
+"gets corrected."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:58 doc/classes/HingeJoint3D.xml:112
+msgid ""
+"If [code]true[/code], the hinges maximum and minimum rotation, defined by "
+"[member angular_limit/lower] and [member angular_limit/upper] has effects."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:61 doc/classes/HingeJoint3D.xml:92
+msgid ""
+"The minimum rotation. Only active if [member angular_limit/enable] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:64 doc/classes/HingeJoint3D.xml:100
+#: doc/classes/PhysicsServer3D.xml:1306
+msgid "The lower this value, the more the rotation gets slowed down."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:69 doc/classes/HingeJoint3D.xml:89
+msgid ""
+"The maximum rotation. Only active if [member angular_limit/enable] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:72 doc/classes/HingeJoint3D.xml:115
+msgid "When activated, a motor turns the hinge."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:75 doc/classes/HingeJoint3D.xml:106
+#: doc/classes/PhysicsServer3D.xml:1312
+msgid "Maximum acceleration for the motor."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:78 doc/classes/HingeJoint3D.xml:103
+#: doc/classes/PhysicsServer3D.xml:1309
+msgid "Target speed for the motor."
+msgstr ""
+
+#: doc/classes/HingeJoint3D.xml:81 doc/classes/HingeJoint3D.xml:86
+#: doc/classes/PhysicsServer3D.xml:1292
+msgid ""
+"The speed with which the two bodies get pulled together when they move in "
+"different directions."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:4
+msgid "Horizontal scroll bar."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:7
+msgid ""
+"Horizontal version of [ScrollBar], which goes from left (min) to right (max)."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:17
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] left. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:20 doc/classes/VScrollBar.xml:24
+msgid "Displayed when the mouse cursor hovers over the decrement button."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:23 doc/classes/VScrollBar.xml:27
+msgid ""
+"Used as texture for the grabber, the draggable element representing current "
+"scroll."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:26 doc/classes/VScrollBar.xml:30
+msgid "Used when the mouse hovers over the grabber."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:29 doc/classes/VScrollBar.xml:33
+msgid "Used when the grabber is being dragged."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:32
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] right. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:35 doc/classes/VScrollBar.xml:39
+msgid "Displayed when the mouse cursor hovers over the increment button."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:38 doc/classes/VScrollBar.xml:42
+msgid "Used as background of this [ScrollBar]."
+msgstr ""
+
+#: doc/classes/HScrollBar.xml:41 doc/classes/VScrollBar.xml:45
+msgid "Used as background when the [ScrollBar] has the GUI focus."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:4
+msgid "Horizontal separator."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:7
+msgid ""
+"Horizontal separator. See [Separator]. Even though it looks horizontal, it "
+"is used to separate objects vertically."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:17
+msgid ""
+"The height of the area covered by the separator. Effectively works like a "
+"minimum height."
+msgstr ""
+
+#: doc/classes/HSeparator.xml:20
+msgid "The style for the separator line. Works best with [StyleBoxLine]."
+msgstr ""
+
+#: doc/classes/HSlider.xml:4
+msgid "Horizontal slider."
+msgstr ""
+
+#: doc/classes/HSlider.xml:7
+msgid ""
+"Horizontal slider. See [Slider]. This one goes from left (min) to right "
+"(max)."
+msgstr ""
+
+#: doc/classes/HSlider.xml:17 doc/classes/VSlider.xml:21
+msgid "The texture for the grabber (the draggable element)."
+msgstr ""
+
+#: doc/classes/HSlider.xml:20
+msgid "The background of the area to the left of the grabber."
+msgstr ""
+
+#: doc/classes/HSlider.xml:23 doc/classes/VSlider.xml:27
+msgid "The texture for the grabber when it's disabled."
+msgstr ""
+
+#: doc/classes/HSlider.xml:26 doc/classes/VSlider.xml:30
+msgid "The texture for the grabber when it's focused."
+msgstr ""
+
+#: doc/classes/HSlider.xml:29
+msgid ""
+"The background for the whole slider. Determines the height of the "
+"[code]grabber_area[/code]."
+msgstr ""
+
+#: doc/classes/HSlider.xml:32 doc/classes/VSlider.xml:36
+msgid ""
+"The texture for the ticks, visible when [member Slider.tick_count] is "
+"greater than 0."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:4
+msgid "Horizontal split container."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:7
+msgid ""
+"Horizontal split container. See [SplitContainer]. This goes from left to "
+"right."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:17 doc/classes/VSplitContainer.xml:17
+msgid ""
+"Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically "
+"when it isn't under the cursor. If 0 ([code]false[/code]), it's always "
+"visible."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:22 doc/classes/VSplitContainer.xml:22
+msgid "The icon used for the grabber drawn in the middle area."
+msgstr ""
+
+#: doc/classes/HSplitContainer.xml:25 doc/classes/VSplitContainer.xml:25
+msgid "The space between sides of the container."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:4
+msgid "Hyper-text transfer protocol client."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:7
+msgid ""
+"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. See "
+"[HTTPRequest] for an higher-level alternative.\n"
+"[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.\n"
+"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.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/"
+"http_client_class.html"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:14 doc/classes/HTTPRequest.xml:62
+#: doc/classes/StreamPeerSSL.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates."
+"html"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:21
+msgid "Closes the current connection, allowing reuse of this [HTTPClient]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:36
+msgid ""
+"Connects to a host. This needs to be done before any requests are sent.\n"
+"The host should not have http:// prepended but will strip the protocol "
+"identifier if provided.\n"
+"If no [code]port[/code] is specified (or [code]-1[/code] is used), it is "
+"automatically set to 80 for HTTP and 443 for HTTPS (if [code]use_ssl[/code] "
+"is enabled).\n"
+"[code]verify_host[/code] will check the SSL identity of the host if set to "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:46
+msgid ""
+"Returns the response's body length.\n"
+"[b]Note:[/b] Some Web servers may not send a body length. In this case, the "
+"value returned will be [code]-1[/code]. If using chunked transfer encoding, "
+"the body length will also be [code]-1[/code]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:54
+msgid "Returns the response's HTTP status code."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:61
+msgid "Returns the response headers."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:68
+msgid ""
+"Returns all response headers as a Dictionary of structure [code]{ \"key\": "
+"\"value1; value2\" }[/code] where the case-sensitivity of the keys and "
+"values is kept like the server delivers it. A value is a simple String, this "
+"string can have more than one value where \"; \" is used as separator.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"{\n"
+" \"content-length\": 12,\n"
+" \"Content-Type\": \"application/json; charset=UTF-8\",\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:82
+msgid ""
+"Returns a [enum Status] constant. Need to call [method poll] in order to get "
+"status updates."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:89
+msgid "If [code]true[/code], this [HTTPClient] has a response available."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:96
+msgid "If [code]true[/code], this [HTTPClient] has a response that is chunked."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:103
+msgid ""
+"This needs to be called in order to have any request processed. Check "
+"results with [method get_status]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:112
+msgid ""
+"Generates a GET/POST application/x-www-form-urlencoded style query string "
+"from a provided dictionary, e.g.:\n"
+"[codeblock]\n"
+"var fields = {\"username\": \"user\", \"password\": \"pass\"}\n"
+"var query_string = http_client.query_string_from_dict(fields)\n"
+"# Returns \"username=user&password=pass\"\n"
+"[/codeblock]\n"
+"Furthermore, if a key has a [code]null[/code] value, only the key itself is "
+"added, without equal sign and value. If the value is an array, for each "
+"value in it a pair with the same key is added.\n"
+"[codeblock]\n"
+"var fields = {\"single\": 123, \"not_valued\": null, \"multiple\": [22, 33, "
+"44]}\n"
+"var query_string = http_client.query_string_from_dict(fields)\n"
+"# Returns \"single=123&not_valued&multiple=22&multiple=33&multiple=44\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:130
+msgid "Reads one chunk from the response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:145
+msgid ""
+"Sends a request to the connected host. The URL parameter is just the part "
+"after the host, so for [code]http://somehost.com/index.php[/code], it is "
+"[code]index.php[/code].\n"
+"Headers are HTTP request headers. For available HTTP methods, see [enum "
+"Method].\n"
+"To create a POST request with query strings to push to the server, do:\n"
+"[codeblock]\n"
+"var fields = {\"username\" : \"user\", \"password\" : \"pass\"}\n"
+"var query_string = http_client.query_string_from_dict(fields)\n"
+"var headers = [\"Content-Type: application/x-www-form-urlencoded\", "
+"\"Content-Length: \" + str(query_string.length())]\n"
+"var result = http_client.request(http_client.METHOD_POST, \"index.php\", "
+"headers, query_string)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:168
+msgid ""
+"Sends a raw request to the connected host. The URL parameter is just the "
+"part after the host, so for [code]http://somehost.com/index.php[/code], it "
+"is [code]index.php[/code].\n"
+"Headers are HTTP request headers. For available HTTP methods, see [enum "
+"Method].\n"
+"Sends the body data raw, as a byte array and does not encode it in any way."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:176
+msgid ""
+"If [code]true[/code], execution will block until all data is read from the "
+"response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:179
+msgid "The connection to use for this client."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:182
+msgid ""
+"The size of the buffer used and maximum bytes to read per iteration. See "
+"[method read_response_body_chunk]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:187
+msgid ""
+"HTTP GET method. The GET method requests a representation of the specified "
+"resource. Requests using GET should only retrieve data."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:190
+msgid ""
+"HTTP HEAD method. The HEAD method asks for a response identical to that of a "
+"GET request, but without the response body. This is useful to request "
+"metadata like HTTP headers or to check if a resource exists."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:193
+msgid ""
+"HTTP POST method. The POST method is used to submit an entity to the "
+"specified resource, often causing a change in state or side effects on the "
+"server. This is often used for forms and submitting data or uploading files."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:196
+msgid ""
+"HTTP PUT method. The PUT method asks to replace all current representations "
+"of the target resource with the request payload. (You can think of POST as "
+"\"create or update\" and PUT as \"update\", although many services tend to "
+"not make a clear distinction or change their meaning)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:199
+msgid ""
+"HTTP DELETE method. The DELETE method requests to delete the specified "
+"resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:202
+msgid ""
+"HTTP OPTIONS method. The OPTIONS method asks for a description of the "
+"communication options for the target resource. Rarely used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:205
+msgid ""
+"HTTP TRACE method. The TRACE method performs a message loop-back test along "
+"the path to the target resource. Returns the entire HTTP request received in "
+"the response body. Rarely used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:208
+msgid ""
+"HTTP CONNECT method. The CONNECT method establishes a tunnel to the server "
+"identified by the target resource. Rarely used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:211
+msgid ""
+"HTTP PATCH method. The PATCH method is used to apply partial modifications "
+"to a resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:214
+msgid "Represents the size of the [enum Method] enum."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:217
+msgid "Status: Disconnected from the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:220
+msgid "Status: Currently resolving the hostname for the given URL into an IP."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:223
+msgid "Status: DNS failure: Can't resolve the hostname for the given URL."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:226
+msgid "Status: Currently connecting to server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:229
+msgid "Status: Can't connect to the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:232
+msgid "Status: Connection established."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:235
+msgid "Status: Currently sending request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:238
+msgid "Status: HTTP body received."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:241
+msgid "Status: Error in HTTP connection."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:244
+msgid "Status: Error in SSL handshake."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:247
+msgid ""
+"HTTP status code [code]100 Continue[/code]. Interim response that indicates "
+"everything so far is OK and that the client should continue with the request "
+"(or ignore this status if already finished)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:250
+msgid ""
+"HTTP status code [code]101 Switching Protocol[/code]. Sent in response to an "
+"[code]Upgrade[/code] request header by the client. Indicates the protocol "
+"the server is switching to."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:253
+msgid ""
+"HTTP status code [code]102 Processing[/code] (WebDAV). Indicates that the "
+"server has received and is processing the request, but no response is "
+"available yet."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:256
+msgid ""
+"HTTP status code [code]200 OK[/code]. The request has succeeded. Default "
+"response for successful requests. Meaning varies depending on the request. "
+"GET: The resource has been fetched and is transmitted in the message body. "
+"HEAD: The entity headers are in the message body. POST: The resource "
+"describing the result of the action is transmitted in the message body. "
+"TRACE: The message body contains the request message as received by the "
+"server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:259
+msgid ""
+"HTTP status code [code]201 Created[/code]. The request has succeeded and a "
+"new resource has been created as a result of it. This is typically the "
+"response sent after a PUT request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:262
+msgid ""
+"HTTP status code [code]202 Accepted[/code]. The request has been received "
+"but not yet acted upon. It is non-committal, meaning that there is no way in "
+"HTTP to later send an asynchronous response indicating the outcome of "
+"processing the request. It is intended for cases where another process or "
+"server handles the request, or for batch processing."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:265
+msgid ""
+"HTTP status code [code]203 Non-Authoritative Information[/code]. This "
+"response code means returned meta-information set is not exact set as "
+"available from the origin server, but collected from a local or a third "
+"party copy. Except this condition, 200 OK response should be preferred "
+"instead of this response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:268
+msgid ""
+"HTTP status code [code]204 No Content[/code]. There is no content to send "
+"for this request, but the headers may be useful. The user-agent may update "
+"its cached headers for this resource with the new ones."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:271
+msgid ""
+"HTTP status code [code]205 Reset Content[/code]. The server has fulfilled "
+"the request and desires that the client resets the \"document view\" that "
+"caused the request to be sent to its original state as received from the "
+"origin server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:274
+msgid ""
+"HTTP status code [code]206 Partial Content[/code]. This response code is "
+"used because of a range header sent by the client to separate download into "
+"multiple streams."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:277
+msgid ""
+"HTTP status code [code]207 Multi-Status[/code] (WebDAV). A Multi-Status "
+"response conveys information about multiple resources in situations where "
+"multiple status codes might be appropriate."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:280
+msgid ""
+"HTTP status code [code]208 Already Reported[/code] (WebDAV). Used inside a "
+"DAV: propstat response element to avoid enumerating the internal members of "
+"multiple bindings to the same collection repeatedly."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:283
+msgid ""
+"HTTP status code [code]226 IM Used[/code] (WebDAV). The server has fulfilled "
+"a GET request for the resource, and the response is a representation of the "
+"result of one or more instance-manipulations applied to the current instance."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:286
+msgid ""
+"HTTP status code [code]300 Multiple Choice[/code]. The request has more than "
+"one possible responses and there is no standardized way to choose one of the "
+"responses. User-agent or user should choose one of them."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:289
+msgid ""
+"HTTP status code [code]301 Moved Permanently[/code]. Redirection. This "
+"response code means the URI of requested resource has been changed. The new "
+"URI is usually included in the response."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:292
+msgid ""
+"HTTP status code [code]302 Found[/code]. Temporary redirection. This "
+"response code means the URI of requested resource has been changed "
+"temporarily. New changes in the URI might be made in the future. Therefore, "
+"this same URI should be used by the client in future requests."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:295
+msgid ""
+"HTTP status code [code]303 See Other[/code]. The server is redirecting the "
+"user agent to a different resource, as indicated by a URI in the Location "
+"header field, which is intended to provide an indirect response to the "
+"original request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:298
+msgid ""
+"HTTP status code [code]304 Not Modified[/code]. A conditional GET or HEAD "
+"request has been received and would have resulted in a 200 OK response if it "
+"were not for the fact that the condition evaluated to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:301
+msgid ""
+"HTTP status code [code]305 Use Proxy[/code]. [i]Deprecated. Do not use.[/i]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:304
+msgid ""
+"HTTP status code [code]306 Switch Proxy[/code]. [i]Deprecated. Do not use.[/"
+"i]"
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:307
+msgid ""
+"HTTP status code [code]307 Temporary Redirect[/code]. The target resource "
+"resides temporarily under a different URI and the user agent MUST NOT change "
+"the request method if it performs an automatic redirection to that URI."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:310
+msgid ""
+"HTTP status code [code]308 Permanent Redirect[/code]. The target resource "
+"has been assigned a new permanent URI and any future references to this "
+"resource ought to use one of the enclosed URIs."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:313
+msgid ""
+"HTTP status code [code]400 Bad Request[/code]. The request was invalid. The "
+"server cannot or will not process the request due to something that is "
+"perceived to be a client error (e.g., malformed request syntax, invalid "
+"request message framing, invalid request contents, or deceptive request "
+"routing)."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:316
+msgid ""
+"HTTP status code [code]401 Unauthorized[/code]. Credentials required. The "
+"request has not been applied because it lacks valid authentication "
+"credentials for the target resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:319
+msgid ""
+"HTTP status code [code]402 Payment Required[/code]. This response code is "
+"reserved for future use. Initial aim for creating this code was using it for "
+"digital payment systems, however this is not currently used."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:322
+msgid ""
+"HTTP status code [code]403 Forbidden[/code]. The client does not have access "
+"rights to the content, i.e. they are unauthorized, so server is rejecting to "
+"give proper response. Unlike [code]401[/code], the client's identity is "
+"known to the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:325
+msgid ""
+"HTTP status code [code]404 Not Found[/code]. The server can not find "
+"requested resource. Either the URL is not recognized or the endpoint is "
+"valid but the resource itself does not exist. May also be sent instead of "
+"403 to hide existence of a resource if the client is not authorized."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:328
+msgid ""
+"HTTP status code [code]405 Method Not Allowed[/code]. The request's HTTP "
+"method is known by the server but has been disabled and cannot be used. For "
+"example, an API may forbid DELETE-ing a resource. The two mandatory methods, "
+"GET and HEAD, must never be disabled and should not return this error code."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:331
+msgid ""
+"HTTP status code [code]406 Not Acceptable[/code]. The target resource does "
+"not have a current representation that would be acceptable to the user "
+"agent, according to the proactive negotiation header fields received in the "
+"request. Used when negotiation content."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:334
+msgid ""
+"HTTP status code [code]407 Proxy Authentication Required[/code]. Similar to "
+"401 Unauthorized, but it indicates that the client needs to authenticate "
+"itself in order to use a proxy."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:337
+msgid ""
+"HTTP status code [code]408 Request Timeout[/code]. The server did not "
+"receive a complete request message within the time that it was prepared to "
+"wait."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:340
+msgid ""
+"HTTP status code [code]409 Conflict[/code]. The request could not be "
+"completed due to a conflict with the current state of the target resource. "
+"This code is used in situations where the user might be able to resolve the "
+"conflict and resubmit the request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:343
+msgid ""
+"HTTP status code [code]410 Gone[/code]. The target resource is no longer "
+"available at the origin server and this condition is likely permanent."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:346
+msgid ""
+"HTTP status code [code]411 Length Required[/code]. The server refuses to "
+"accept the request without a defined Content-Length header."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:349
+msgid ""
+"HTTP status code [code]412 Precondition Failed[/code]. One or more "
+"conditions given in the request header fields evaluated to [code]false[/"
+"code] when tested on the server."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:352
+msgid ""
+"HTTP status code [code]413 Entity Too Large[/code]. The server is refusing "
+"to process a request because the request payload is larger than the server "
+"is willing or able to process."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:355
+msgid ""
+"HTTP status code [code]414 Request-URI Too Long[/code]. The server is "
+"refusing to service the request because the request-target is longer than "
+"the server is willing to interpret."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:358
+msgid ""
+"HTTP status code [code]415 Unsupported Media Type[/code]. The origin server "
+"is refusing to service the request because the payload is in a format not "
+"supported by this method on the target resource."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:361
+msgid ""
+"HTTP status code [code]416 Requested Range Not Satisfiable[/code]. None of "
+"the ranges in the request's Range header field overlap the current extent of "
+"the selected resource or the set of ranges requested has been rejected due "
+"to invalid ranges or an excessive request of small or overlapping ranges."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:364
+msgid ""
+"HTTP status code [code]417 Expectation Failed[/code]. The expectation given "
+"in the request's Expect header field could not be met by at least one of the "
+"inbound servers."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:367
+msgid ""
+"HTTP status code [code]418 I'm A Teapot[/code]. Any attempt to brew coffee "
+"with a teapot should result in the error code \"418 I'm a teapot\". The "
+"resulting entity body MAY be short and stout."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:370
+msgid ""
+"HTTP status code [code]421 Misdirected Request[/code]. The request was "
+"directed at a server that is not able to produce a response. This can be "
+"sent by a server that is not configured to produce responses for the "
+"combination of scheme and authority that are included in the request URI."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:373
+msgid ""
+"HTTP status code [code]422 Unprocessable Entity[/code] (WebDAV). The server "
+"understands the content type of the request entity (hence a 415 Unsupported "
+"Media Type status code is inappropriate), and the syntax of the request "
+"entity is correct (thus a 400 Bad Request status code is inappropriate) but "
+"was unable to process the contained instructions."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:376
+msgid ""
+"HTTP status code [code]423 Locked[/code] (WebDAV). The source or destination "
+"resource of a method is locked."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:379
+msgid ""
+"HTTP status code [code]424 Failed Dependency[/code] (WebDAV). The method "
+"could not be performed on the resource because the requested action depended "
+"on another action and that action failed."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:382
+msgid ""
+"HTTP status code [code]426 Upgrade Required[/code]. The server refuses to "
+"perform the request using the current protocol but might be willing to do so "
+"after the client upgrades to a different protocol."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:385
+msgid ""
+"HTTP status code [code]428 Precondition Required[/code]. The origin server "
+"requires the request to be conditional."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:388
+msgid ""
+"HTTP status code [code]429 Too Many Requests[/code]. The user has sent too "
+"many requests in a given amount of time (see \"rate limiting\"). Back off "
+"and increase time between requests or try again later."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:391
+msgid ""
+"HTTP status code [code]431 Request Header Fields Too Large[/code]. The "
+"server is unwilling to process the request because its header fields are too "
+"large. The request MAY be resubmitted after reducing the size of the request "
+"header fields."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:394
+msgid ""
+"HTTP status code [code]451 Response Unavailable For Legal Reasons[/code]. "
+"The server is denying access to the resource as a consequence of a legal "
+"demand."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:397
+msgid ""
+"HTTP status code [code]500 Internal Server Error[/code]. The server "
+"encountered an unexpected condition that prevented it from fulfilling the "
+"request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:400
+msgid ""
+"HTTP status code [code]501 Not Implemented[/code]. The server does not "
+"support the functionality required to fulfill the request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:403
+msgid ""
+"HTTP status code [code]502 Bad Gateway[/code]. The server, while acting as a "
+"gateway or proxy, received an invalid response from an inbound server it "
+"accessed while attempting to fulfill the request. Usually returned by load "
+"balancers or proxies."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:406
+msgid ""
+"HTTP status code [code]503 Service Unavailable[/code]. The server is "
+"currently unable to handle the request due to a temporary overload or "
+"scheduled maintenance, which will likely be alleviated after some delay. Try "
+"again later."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:409
+msgid ""
+"HTTP status code [code]504 Gateway Timeout[/code]. The server, while acting "
+"as a gateway or proxy, did not receive a timely response from an upstream "
+"server it needed to access in order to complete the request. Usually "
+"returned by load balancers or proxies."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:412
+msgid ""
+"HTTP status code [code]505 HTTP Version Not Supported[/code]. The server "
+"does not support, or refuses to support, the major version of HTTP that was "
+"used in the request message."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:415
+msgid ""
+"HTTP status code [code]506 Variant Also Negotiates[/code]. The server has an "
+"internal configuration error: the chosen variant resource is configured to "
+"engage in transparent content negotiation itself, and is therefore not a "
+"proper end point in the negotiation process."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:418
+msgid ""
+"HTTP status code [code]507 Insufficient Storage[/code]. The method could not "
+"be performed on the resource because the server is unable to store the "
+"representation needed to successfully complete the request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:421
+msgid ""
+"HTTP status code [code]508 Loop Detected[/code]. The server terminated an "
+"operation because it encountered an infinite loop while processing a request "
+"with \"Depth: infinity\". This status indicates that the entire operation "
+"failed."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:424
+msgid ""
+"HTTP status code [code]510 Not Extended[/code]. The policy for accessing the "
+"resource has not been met in the request. The server should send back all "
+"the information necessary for the client to issue an extended request."
+msgstr ""
+
+#: doc/classes/HTTPClient.xml:427
+msgid ""
+"HTTP status code [code]511 Network Authentication Required[/code]. The "
+"client needs to authenticate to gain network access."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:4
+msgid "A node with the ability to send HTTP(S) requests."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:7
+msgid ""
+"A node with the ability to send HTTP requests. Uses [HTTPClient] "
+"internally.\n"
+"Can be used to make HTTP requests, i.e. download or upload files or web "
+"content via HTTP.\n"
+"[b]Example of contacting a REST API and printing one of its returned fields:"
+"[/b]\n"
+"[codeblock]\n"
+"func _ready():\n"
+" # Create an HTTP request node and connect its completion signal.\n"
+" var http_request = HTTPRequest.new()\n"
+" add_child(http_request)\n"
+" http_request.connect(\"request_completed\", self, "
+"\"_http_request_completed\")\n"
+"\n"
+" # Perform the HTTP request. The URL below returns some JSON as of "
+"writing.\n"
+" var error = http_request.request(\"https://httpbin.org/get\")\n"
+" if error != OK:\n"
+" push_error(\"An error occurred in the HTTP request.\")\n"
+"\n"
+"\n"
+"# Called when the HTTP request is completed.\n"
+"func _http_request_completed(result, response_code, headers, body):\n"
+" var response = parse_json(body.get_string_from_utf8())\n"
+"\n"
+" # Will print the user agent string used by the HTTPRequest node (as "
+"recognized by httpbin.org).\n"
+" print(response.headers[\"User-Agent\"])\n"
+"[/codeblock]\n"
+"[b]Example of loading and displaying an image using HTTPRequest:[/b]\n"
+"[codeblock]\n"
+"func _ready():\n"
+" # Create an HTTP request node and connect its completion signal.\n"
+" var http_request = HTTPRequest.new()\n"
+" add_child(http_request)\n"
+" http_request.connect(\"request_completed\", self, "
+"\"_http_request_completed\")\n"
+"\n"
+" # Perform the HTTP request. The URL below returns a PNG image as of "
+"writing.\n"
+" var error = http_request.request(\"https://via.placeholder.com/512\")\n"
+" if error != OK:\n"
+" push_error(\"An error occurred in the HTTP request.\")\n"
+"\n"
+"\n"
+"# Called when the HTTP request is completed.\n"
+"func _http_request_completed(result, response_code, headers, body):\n"
+" var image = Image.new()\n"
+" var error = image.load_png_from_buffer(body)\n"
+" if error != OK:\n"
+" push_error(\"Couldn't load the image.\")\n"
+"\n"
+" var texture = ImageTexture.new()\n"
+" texture.create_from_image(image)\n"
+"\n"
+" # Display the image in a TextureRect node.\n"
+" var texture_rect = TextureRect.new()\n"
+" add_child(texture_rect)\n"
+" texture_rect.texture = texture\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:61
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/"
+"http_request_class.html"
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:69
+msgid "Cancels the current request."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:76
+msgid ""
+"Returns the response body length.\n"
+"[b]Note:[/b] Some Web servers may not send a body length. In this case, the "
+"value returned will be [code]-1[/code]. If using chunked transfer encoding, "
+"the body length will also be [code]-1[/code]."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:84
+msgid "Returns the amount of bytes this HTTPRequest downloaded."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:91
+msgid ""
+"Returns the current status of the underlying [HTTPClient]. See [enum "
+"HTTPClient.Status]."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:108
+msgid ""
+"Creates request on the underlying [HTTPClient]. If there is no configuration "
+"errors, it tries to connect using [method HTTPClient.connect_to_host] and "
+"passes parameters onto [method HTTPClient.request].\n"
+"Returns [constant OK] if request is successfully created. (Does not imply "
+"that the server has responded), [constant ERR_UNCONFIGURED] if not in the "
+"tree, [constant ERR_BUSY] if still processing previous request, [constant "
+"ERR_INVALID_PARAMETER] if given string is not a valid URL format, or "
+"[constant ERR_CANT_CONNECT] if not using thread and the [HTTPClient] cannot "
+"connect to host."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:115
+msgid "Maximum allowed size for response bodies."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:118
+msgid ""
+"The size of the buffer used and maximum bytes to read per iteration. See "
+"[member HTTPClient.read_chunk_size].\n"
+"Set this to a higher value (e.g. 65536 for 64 KiB) when downloading large "
+"files to achieve better speeds at the cost of memory."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:122
+msgid "The file to download into. Will output any received file into it."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:125
+msgid "Maximum number of allowed redirects."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:130
+msgid "If [code]true[/code], multithreading is used to improve performance."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:144
+msgid "Emitted when a request is completed."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:150
+msgid "Request successful."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:155
+msgid "Request failed while connecting."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:158
+msgid "Request failed while resolving."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:161
+msgid "Request failed due to connection (read/write) error."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:164
+msgid "Request failed on SSL handshake."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:167
+msgid "Request does not have a response (yet)."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:170
+msgid "Request exceeded its maximum size limit, see [member body_size_limit]."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:173
+msgid "Request failed (currently unused)."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:176
+msgid "HTTPRequest couldn't open the download file."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:179
+msgid "HTTPRequest couldn't write to the download file."
+msgstr ""
+
+#: doc/classes/HTTPRequest.xml:182
+msgid "Request reached its maximum redirect limit, see [member max_redirects]."
+msgstr ""
+
+#: doc/classes/Image.xml:4
+msgid "Image datatype."
+msgstr ""
+
+#: doc/classes/Image.xml:7
+msgid ""
+"Native image datatype. Contains image data, which can be converted to a "
+"[Texture2D], and several functions to interact with it. The maximum width "
+"and height for an [Image] are [constant MAX_WIDTH] and [constant MAX_HEIGHT]."
+msgstr ""
+
+#: doc/classes/Image.xml:22
+msgid ""
+"Alpha-blends [code]src_rect[/code] from [code]src[/code] image to this image "
+"at coordinates [code]dest[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:37
+msgid ""
+"Alpha-blends [code]src_rect[/code] from [code]src[/code] image to this image "
+"using [code]mask[/code] image at coordinates [code]dst[/code]. Alpha "
+"channels are required for both [code]src[/code] and [code]mask[/code]. "
+"[code]dst[/code] pixels and [code]src[/code] pixels will blend if the "
+"corresponding mask pixel's alpha value is not 0. [code]src[/code] image and "
+"[code]mask[/code] image [b]must[/b] have the same size (width and height) "
+"but they can have different formats."
+msgstr ""
+
+#: doc/classes/Image.xml:50
+msgid ""
+"Copies [code]src_rect[/code] from [code]src[/code] image to this image at "
+"coordinates [code]dst[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:65
+msgid ""
+"Blits [code]src_rect[/code] area from [code]src[/code] image to this image "
+"at the coordinates given by [code]dst[/code]. [code]src[/code] pixel is "
+"copied onto [code]dst[/code] if the corresponding [code]mask[/code] pixel's "
+"alpha value is not 0. [code]src[/code] image and [code]mask[/code] image "
+"[b]must[/b] have the same size (width and height) but they can have "
+"different formats."
+msgstr ""
+
+#: doc/classes/Image.xml:74
+msgid ""
+"Converts a bumpmap to a normalmap. A bumpmap provides a height offset per-"
+"pixel, while a normalmap provides a normal direction per pixel."
+msgstr ""
+
+#: doc/classes/Image.xml:81
+msgid "Removes the image's mipmaps."
+msgstr ""
+
+#: doc/classes/Image.xml:94
+msgid ""
+"Compresses the image to use less memory. Can not directly access pixel data "
+"while the image is compressed. Returns error if the chosen compression mode "
+"is not available. See [enum CompressMode] and [enum CompressSource] "
+"constants."
+msgstr ""
+
+#: doc/classes/Image.xml:115
+msgid "Converts the image's format. See [enum Format] constants."
+msgstr ""
+
+#: doc/classes/Image.xml:124
+msgid "Copies [code]src[/code] image to this image."
+msgstr ""
+
+#: doc/classes/Image.xml:139
+msgid ""
+"Creates an empty image of given size and format. See [enum Format] "
+"constants. If [code]use_mipmaps[/code] is [code]true[/code] then generate "
+"mipmaps for this image. See the [method generate_mipmaps]."
+msgstr ""
+
+#: doc/classes/Image.xml:156
+msgid ""
+"Creates a new image of given size and format. See [enum Format] constants. "
+"Fills the image with the given raw data. If [code]use_mipmaps[/code] is "
+"[code]true[/code] then generate mipmaps for this image. See the [method "
+"generate_mipmaps]."
+msgstr ""
+
+#: doc/classes/Image.xml:167
+msgid ""
+"Crops the image to the given [code]width[/code] and [code]height[/code]. If "
+"the specified size is larger than the current size, the extra area is filled "
+"with black pixels."
+msgstr ""
+
+#: doc/classes/Image.xml:174
+msgid ""
+"Decompresses the image if it is compressed. Returns an error if decompress "
+"function is not available."
+msgstr ""
+
+#: doc/classes/Image.xml:181
+msgid ""
+"Returns [constant ALPHA_BLEND] if the image has data for alpha values. "
+"Returns [constant ALPHA_BIT] if all the alpha values are stored in a single "
+"bit. Returns [constant ALPHA_NONE] if no data for alpha values is found."
+msgstr ""
+
+#: doc/classes/Image.xml:196
+msgid ""
+"Stretches the image and enlarges it by a factor of 2. No interpolation is "
+"done."
+msgstr ""
+
+#: doc/classes/Image.xml:205
+msgid "Fills the image with a given [Color]."
+msgstr ""
+
+#: doc/classes/Image.xml:212
+msgid "Blends low-alpha pixels with nearby pixels."
+msgstr ""
+
+#: doc/classes/Image.xml:219
+msgid "Flips the image horizontally."
+msgstr ""
+
+#: doc/classes/Image.xml:226
+msgid "Flips the image vertically."
+msgstr ""
+
+#: doc/classes/Image.xml:235
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Image.xml:242
+msgid "Returns the image's raw data."
+msgstr ""
+
+#: doc/classes/Image.xml:249
+msgid "Returns the image's format. See [enum Format] constants."
+msgstr ""
+
+#: doc/classes/Image.xml:256
+msgid "Returns the image's height."
+msgstr ""
+
+#: doc/classes/Image.xml:265
+msgid ""
+"Returns the offset where the image's mipmap with index [code]mipmap[/code] "
+"is stored in the [code]data[/code] dictionary."
+msgstr ""
+
+#: doc/classes/Image.xml:276
+msgid ""
+"Returns the color of the pixel at [code](x, y)[/code]. This is the same as "
+"[method get_pixelv], but with two integer arguments instead of a [Vector2] "
+"argument."
+msgstr ""
+
+#: doc/classes/Image.xml:285
+msgid ""
+"Returns the color of the pixel at [code]src[/code]. This is the same as "
+"[method get_pixel], but with a [Vector2] argument instead of two integer "
+"arguments."
+msgstr ""
+
+#: doc/classes/Image.xml:294
+msgid ""
+"Returns a new image that is a copy of the image's area specified with "
+"[code]rect[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:301
+msgid "Returns the image's size (width and height)."
+msgstr ""
+
+#: doc/classes/Image.xml:308
+msgid ""
+"Returns a [Rect2] enclosing the visible portion of the image, considering "
+"each pixel with a non-zero alpha channel as visible."
+msgstr ""
+
+#: doc/classes/Image.xml:315
+msgid "Returns the image's width."
+msgstr ""
+
+#: doc/classes/Image.xml:322
+msgid "Returns [code]true[/code] if the image has generated mipmaps."
+msgstr ""
+
+#: doc/classes/Image.xml:329
+msgid "Returns [code]true[/code] if the image is compressed."
+msgstr ""
+
+#: doc/classes/Image.xml:336
+msgid "Returns [code]true[/code] if the image has no data."
+msgstr ""
+
+#: doc/classes/Image.xml:343
+msgid ""
+"Returns [code]true[/code] if all the image's pixels have an alpha value of "
+"0. Returns [code]false[/code] if any pixel has an alpha value higher than 0."
+msgstr ""
+
+#: doc/classes/Image.xml:352
+msgid "Loads an image from file [code]path[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:361
+msgid "Loads an image from the binary contents of a JPEG file."
+msgstr ""
+
+#: doc/classes/Image.xml:370
+msgid "Loads an image from the binary contents of a PNG file."
+msgstr ""
+
+#: doc/classes/Image.xml:379
+msgid "Loads an image from the binary contents of a WebP file."
+msgstr ""
+
+#: doc/classes/Image.xml:386
+msgid ""
+"Converts the image's data to represent coordinates on a 3D plane. This is "
+"used when the image represents a normalmap. A normalmap can add lots of "
+"detail to a 3D surface without increasing the polygon count."
+msgstr ""
+
+#: doc/classes/Image.xml:393
+msgid ""
+"Multiplies color values with alpha values. Resulting color values for a "
+"pixel are [code](color * alpha)/256[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:406
+msgid ""
+"Resizes the image to the given [code]width[/code] and [code]height[/code]. "
+"New pixels are calculated using [code]interpolation[/code]. See "
+"[code]interpolation[/code] constants."
+msgstr ""
+
+#: doc/classes/Image.xml:415
+msgid ""
+"Resizes the image to the nearest power of 2 for the width and height. If "
+"[code]square[/code] is [code]true[/code] then set width and height to be the "
+"same."
+msgstr ""
+
+#: doc/classes/Image.xml:422
+msgid ""
+"Converts a standard RGBE (Red Green Blue Exponent) image to an sRGB image."
+msgstr ""
+
+#: doc/classes/Image.xml:433
+msgid ""
+"Saves the image as an EXR file to [code]path[/code]. If [code]grayscale[/"
+"code] is [code]true[/code] and the image has only one channel, it will be "
+"saved explicitly as monochrome rather than one red channel. This function "
+"will return [constant ERR_UNAVAILABLE] if Godot was compiled without the "
+"TinyEXR module."
+msgstr ""
+
+#: doc/classes/Image.xml:442
+msgid "Saves the image as a PNG file to [code]path[/code]."
+msgstr ""
+
+#: doc/classes/Image.xml:455
+msgid ""
+"Sets the [Color] of the pixel at [code](x, y)[/code]. Example:\n"
+"[codeblock]\n"
+"var img = Image.new()\n"
+"img.create(img_width, img_height, false, Image.FORMAT_RGBA8)\n"
+"img.set_pixel(x, y, color)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Image.xml:471
+msgid ""
+"Sets the [Color] of the pixel at [code](dst.x, dst.y)[/code]. Note that the "
+"[code]dst[/code] values must be integers. Example:\n"
+"[codeblock]\n"
+"var img = Image.new()\n"
+"img.create(img_width, img_height, false, Image.FORMAT_RGBA8)\n"
+"img.set_pixelv(Vector2(x, y), color)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Image.xml:483
+msgid "Shrinks the image by a factor of 2."
+msgstr ""
+
+#: doc/classes/Image.xml:490
+msgid "Converts the raw data from the sRGB colorspace to a linear scale."
+msgstr ""
+
+#: doc/classes/Image.xml:496
+msgid ""
+"Holds all of the image's color data in a given format. See [enum Format] "
+"constants."
+msgstr ""
+
+#: doc/classes/Image.xml:501
+msgid "The maximal width allowed for [Image] resources."
+msgstr ""
+
+#: doc/classes/Image.xml:504
+msgid "The maximal height allowed for [Image] resources."
+msgstr ""
+
+#: doc/classes/Image.xml:507
+msgid "Texture format with a single 8-bit depth representing luminance."
+msgstr ""
+
+#: doc/classes/Image.xml:510
+msgid ""
+"OpenGL texture format with two values, luminance and alpha each stored with "
+"8 bits."
+msgstr ""
+
+#: doc/classes/Image.xml:513
+msgid ""
+"OpenGL texture format [code]RED[/code] with a single component and a "
+"bitdepth of 8."
+msgstr ""
+
+#: doc/classes/Image.xml:516
+msgid ""
+"OpenGL texture format [code]RG[/code] with two components and a bitdepth of "
+"8 for each."
+msgstr ""
+
+#: doc/classes/Image.xml:519
+msgid ""
+"OpenGL texture format [code]RGB[/code] with three components, each with a "
+"bitdepth of 8.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:523
+msgid ""
+"OpenGL texture format [code]RGBA[/code] with four components, each with a "
+"bitdepth of 8.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:527
+msgid ""
+"OpenGL texture format [code]RGBA[/code] with four components, each with a "
+"bitdepth of 4."
+msgstr ""
+
+#: doc/classes/Image.xml:532
+msgid ""
+"OpenGL texture format [code]GL_R32F[/code] where there's one component, a 32-"
+"bit floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:535
+msgid ""
+"OpenGL texture format [code]GL_RG32F[/code] where there are two components, "
+"each a 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/Image.xml:538
+msgid ""
+"OpenGL texture format [code]GL_RGB32F[/code] where there are three "
+"components, each a 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/Image.xml:541
+msgid ""
+"OpenGL texture format [code]GL_RGBA32F[/code] where there are four "
+"components, each a 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/Image.xml:544
+msgid ""
+"OpenGL texture format [code]GL_R32F[/code] where there's one component, a 16-"
+"bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:547
+msgid ""
+"OpenGL texture format [code]GL_RG32F[/code] where there are two components, "
+"each a 16-bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:550
+msgid ""
+"OpenGL texture format [code]GL_RGB32F[/code] where there are three "
+"components, each a 16-bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:553
+msgid ""
+"OpenGL texture format [code]GL_RGBA32F[/code] where there are four "
+"components, each a 16-bit \"half-precision\" floating-point value."
+msgstr ""
+
+#: doc/classes/Image.xml:556
+msgid ""
+"A special OpenGL texture format where the three color components have 9 bits "
+"of precision and all three share a single 5-bit exponent."
+msgstr ""
+
+#: doc/classes/Image.xml:559
+msgid ""
+"The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] "
+"texture format that uses Block Compression 1, and is the smallest variation "
+"of S3TC, only providing 1 bit of alpha and color data being premultiplied "
+"with alpha.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:563
+msgid ""
+"The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] "
+"texture format that uses Block Compression 2, and color data is interpreted "
+"as not having been premultiplied by alpha. Well suited for images with sharp "
+"alpha transitions between translucent and opaque areas.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:567
+msgid ""
+"The [url=https://en.wikipedia.org/wiki/S3_Texture_Compression]S3TC[/url] "
+"texture format also known as Block Compression 3 or BC3 that contains 64 "
+"bits of alpha channel data followed by 64 bits of DXT1-encoded color data. "
+"Color data is not premultiplied by alpha, same as DXT3. DXT5 generally "
+"produces superior results for transparent gradients compared to DXT3.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:571
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"Red_Green_Texture_Compression]Red Green Texture Compression[/url], "
+"normalizing the red channel data using the same compression algorithm that "
+"DXT5 uses for the alpha channel."
+msgstr ""
+
+#: doc/classes/Image.xml:574
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"Red_Green_Texture_Compression]Red Green Texture Compression[/url], "
+"normalizing the red and green channel data using the same compression "
+"algorithm that DXT5 uses for the alpha channel."
+msgstr ""
+
+#: doc/classes/Image.xml:577
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"BPTC_Texture_Compression]BPTC[/url] compression with unsigned normalized "
+"RGBA components.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:581
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"BPTC_Texture_Compression]BPTC[/url] compression with signed floating-point "
+"RGB components."
+msgstr ""
+
+#: doc/classes/Image.xml:584
+msgid ""
+"Texture format that uses [url=https://www.khronos.org/opengl/wiki/"
+"BPTC_Texture_Compression]BPTC[/url] compression with unsigned floating-point "
+"RGB components."
+msgstr ""
+
+#: doc/classes/Image.xml:587
+msgid ""
+"Texture format used on PowerVR-supported mobile platforms, uses 2-bit color "
+"depth with no alpha. More information can be found [url=https://en.wikipedia."
+"org/wiki/PVRTC]here[/url].\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:591
+msgid ""
+"Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with an "
+"alpha component."
+msgstr ""
+
+#: doc/classes/Image.xml:594
+msgid ""
+"Similar to [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC2[/url], but with 4-"
+"bit color depth and no alpha."
+msgstr ""
+
+#: doc/classes/Image.xml:597
+msgid ""
+"Same as [url=https://en.wikipedia.org/wiki/PVRTC]PVRTC4[/url], but with an "
+"alpha component."
+msgstr ""
+
+#: doc/classes/Image.xml:600
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC1]Ericsson Texture Compression format 1[/"
+"url], also referred to as \"ETC1\", and is part of the OpenGL ES graphics "
+"standard. This format cannot store an alpha channel."
+msgstr ""
+
+#: doc/classes/Image.xml:603
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]R11_EAC[/code] variant), which provides one channel of "
+"unsigned data."
+msgstr ""
+
+#: doc/classes/Image.xml:606
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]SIGNED_R11_EAC[/code] variant), which provides one "
+"channel of signed data."
+msgstr ""
+
+#: doc/classes/Image.xml:609
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RG11_EAC[/code] variant), which provides two channels "
+"of unsigned data."
+msgstr ""
+
+#: doc/classes/Image.xml:612
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]SIGNED_RG11_EAC[/code] variant), which provides two "
+"channels of signed data."
+msgstr ""
+
+#: doc/classes/Image.xml:615
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RGB8[/code] variant), which is a follow-up of ETC1 and "
+"compresses RGB888 data.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:619
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RGBA8[/code]variant), which compresses RGBA8888 data "
+"with full alpha support.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:623
+msgid ""
+"[url=https://en.wikipedia.org/wiki/"
+"Ericsson_Texture_Compression#ETC2_and_EAC]Ericsson Texture Compression "
+"format 2[/url] ([code]RGB8_PUNCHTHROUGH_ALPHA1[/code] variant), which "
+"compresses RGBA data to make alpha either fully transparent or fully "
+"opaque.\n"
+"[b]Note:[/b] When creating an [ImageTexture], an sRGB to linear color space "
+"conversion is performed."
+msgstr ""
+
+#: doc/classes/Image.xml:631
+msgid "Represents the size of the [enum Format] enum."
+msgstr ""
+
+#: doc/classes/Image.xml:634
+msgid ""
+"Performs nearest-neighbor interpolation. If the image is resized, it will be "
+"pixelated."
+msgstr ""
+
+#: doc/classes/Image.xml:637
+msgid ""
+"Performs bilinear interpolation. If the image is resized, it will be blurry. "
+"This mode is faster than [constant INTERPOLATE_CUBIC], but it results in "
+"lower quality."
+msgstr ""
+
+#: doc/classes/Image.xml:640
+msgid ""
+"Performs cubic interpolation. If the image is resized, it will be blurry. "
+"This mode often gives better results compared to [constant "
+"INTERPOLATE_BILINEAR], at the cost of being slower."
+msgstr ""
+
+#: doc/classes/Image.xml:643
+msgid ""
+"Performs bilinear separately on the two most-suited mipmap levels, then "
+"linearly interpolates between them.\n"
+"It's slower than [constant INTERPOLATE_BILINEAR], but produces higher-"
+"quality results with much less aliasing artifacts.\n"
+"If the image does not have mipmaps, they will be generated and used "
+"internally, but no mipmaps will be generated on the resulting image.\n"
+"[b]Note:[/b] If you intend to scale multiple copies of the original image, "
+"it's better to call [method generate_mipmaps]] on it in advance, to avoid "
+"wasting processing power in generating them again and again.\n"
+"On the other hand, if the image already has mipmaps, they will be used, and "
+"a new set will be generated for the resulting image."
+msgstr ""
+
+#: doc/classes/Image.xml:650
+msgid ""
+"Performs Lanczos interpolation. This is the slowest image resizing mode, but "
+"it typically gives the best results, especially when downscalng images."
+msgstr ""
+
+#: doc/classes/Image.xml:653
+msgid "Image does not have alpha."
+msgstr ""
+
+#: doc/classes/Image.xml:656
+msgid "Image stores alpha in a single bit."
+msgstr ""
+
+#: doc/classes/Image.xml:659
+msgid "Image uses alpha."
+msgstr ""
+
+#: doc/classes/Image.xml:662
+msgid "Use S3TC compression."
+msgstr ""
+
+#: doc/classes/Image.xml:665
+msgid "Use PVRTC2 compression."
+msgstr ""
+
+#: doc/classes/Image.xml:668
+msgid "Use PVRTC4 compression."
+msgstr ""
+
+#: doc/classes/Image.xml:671
+msgid "Use ETC compression."
+msgstr ""
+
+#: doc/classes/Image.xml:674
+msgid "Use ETC2 compression."
+msgstr ""
+
+#: doc/classes/Image.xml:689
+msgid ""
+"Source texture (before compression) is a regular texture. Default for all "
+"textures."
+msgstr ""
+
+#: doc/classes/Image.xml:692
+msgid "Source texture (before compression) is in sRGB space."
+msgstr ""
+
+#: doc/classes/Image.xml:695
+msgid ""
+"Source texture (before compression) is a normal texture (e.g. it can be "
+"compressed into two channels)."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:4
+msgid "A [Texture2D] based on an [Image]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:7
+msgid ""
+"A [Texture2D] based on an [Image]. Can be created from an [Image] with "
+"[method create_from_image]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:18
+msgid "Create a new [ImageTexture] from an [Image]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:25
+msgid "Returns the format of the [ImageTexture], one of [enum Image.Format]."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:34
+msgid "Resizes the [ImageTexture] to the specified dimensions."
+msgstr ""
+
+#: doc/classes/ImageTexture.xml:45
+msgid ""
+"Replaces the texture's data with a new [code]image[/code]. If "
+"[code]immediate[/code] is [code]true[/code], it will take effect immediately "
+"after the call."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:4
+msgid "Draws simple geometry from code."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:7
+msgid ""
+"Draws simple geometry from code. Uses a drawing mode similar to OpenGL 1.x."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:24
+msgid ""
+"Simple helper to draw an UV sphere with given latitude, longitude and radius."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:33
+msgid ""
+"Adds a vertex in local coordinate space with the currently set color/uv/etc."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:44
+msgid ""
+"Begin drawing (and optionally pass a texture override). When done call "
+"[method end]. For more information on how this works, search for "
+"[code]glBegin()[/code] and [code]glEnd()[/code] references.\n"
+"For the type of primitive, see the [enum Mesh.PrimitiveType] enum."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:52
+msgid "Clears everything that was drawn using begin/end."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:59
+msgid "Ends a drawing context and displays the results."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:68
+msgid "The current drawing color."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:77
+msgid "The next vertex's normal."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:86
+msgid "The next vertex's tangent (and binormal facing)."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:95
+msgid "The next vertex's UV."
+msgstr ""
+
+#: doc/classes/ImmediateGeometry3D.xml:104
+msgid "The next vertex's second layer UV."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:4
+msgid "Generic input event."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:7
+msgid "Base class of all sort of input event. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:10 doc/classes/InputEventJoypadButton.xml:10
+#: doc/classes/InputEventJoypadMotion.xml:10 doc/classes/InputEventKey.xml:10
+#: doc/classes/InputEventMouse.xml:10 doc/classes/InputEventScreenDrag.xml:10
+#: doc/classes/InputEventScreenTouch.xml:11
+#: doc/classes/InputEventWithModifiers.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html"
+msgstr ""
+
+#: doc/classes/InputEvent.xml:20
+msgid ""
+"Returns [code]true[/code] if the given input event and this input event can "
+"be added together (only for events of type [InputEventMouseMotion]).\n"
+"The given input event's position, global position and speed will be copied. "
+"The resulting [code]relative[/code] is a sum of both events. Both events' "
+"modifiers have to be identical."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:28
+msgid "Returns a [String] representation of the event."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:37
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:46
+msgid ""
+"Returns [code]true[/code] if this input event matches a pre-defined action "
+"of any type."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:57
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:66
+msgid ""
+"Returns [code]true[/code] if the given action is released (i.e. not "
+"pressed). Not relevant for events of type [InputEventMouseMotion] or "
+"[InputEventScreenDrag]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:73
+msgid ""
+"Returns [code]true[/code] if this input event's type is one that can be "
+"assigned to an input action."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:80
+msgid ""
+"Returns [code]true[/code] if this input event is an echo event (only for "
+"events of type [InputEventKey])."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:87
+msgid ""
+"Returns [code]true[/code] if this input event is pressed. Not relevant for "
+"events of type [InputEventMouseMotion] or [InputEventScreenDrag]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:96
+msgid ""
+"Returns [code]true[/code] if the given input event is checking for the same "
+"key ([InputEventKey]), button ([InputEventJoypadButton]) or action "
+"([InputEventAction])."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:107
+msgid ""
+"Returns a copy of the given input event which has been offset by "
+"[code]local_ofs[/code] and transformed by [code]xform[/code]. Relevant for "
+"events of type [InputEventMouseButton], [InputEventMouseMotion], "
+"[InputEventScreenTouch], [InputEventScreenDrag], [InputEventMagnifyGesture] "
+"and [InputEventPanGesture]."
+msgstr ""
+
+#: doc/classes/InputEvent.xml:113
+msgid ""
+"The event's device ID.\n"
+"[b]Note:[/b] This device ID will always be [code]-1[/code] for emulated "
+"mouse input from a touchscreen. This can be used to distinguish emulated "
+"mouse input from physical mouse input."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:4
+msgid "Input event type for actions."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:7
+msgid ""
+"Contains a generic action which can be targeted from several types of "
+"inputs. Actions can be created from the [b]Input Map[/b] tab in the "
+"[b]Project > Project Settings[/b] menu. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent."
+"html#actions"
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:16
+msgid "The action's name. Actions are accessed via this [String]."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:19
+msgid ""
+"If [code]true[/code], the action's state is pressed. If [code]false[/code], "
+"the action's state is released."
+msgstr ""
+
+#: doc/classes/InputEventAction.xml:22
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputEventGesture.xml:4
+msgid "Base class for touch control gestures."
+msgstr ""
+
+#: doc/classes/InputEventGesture.xml:14
+msgid ""
+"The local gesture position relative to the [Viewport]. If used in [method "
+"Control._gui_input], the position is relative to the current [Control] that "
+"received this gesture."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:4
+msgid "Input event for gamepad buttons."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:7
+msgid ""
+"Input event type for gamepad buttons. For gamepad analog sticks and "
+"joysticks, see [InputEventJoypadMotion]."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:16
+msgid "Button identifier. One of the [enum JoystickList] button constants."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:19
+msgid ""
+"If [code]true[/code], the button's state is pressed. If [code]false[/code], "
+"the button's state is released."
+msgstr ""
+
+#: doc/classes/InputEventJoypadButton.xml:22
+msgid ""
+"Represents the pressure the user puts on the button with his finger, if the "
+"controller supports it. Ranges from [code]0[/code] to [code]1[/code]."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:4
+msgid ""
+"Input event type for gamepad joysticks and other motions. For buttons, see "
+"[code]InputEventJoypadButton[/code]."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:7
+msgid ""
+"Stores information about joystick motions. One [InputEventJoypadMotion] "
+"represents one axis at a time."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:16
+msgid "Axis identifier. Use one of the [enum JoystickList] axis constants."
+msgstr ""
+
+#: doc/classes/InputEventJoypadMotion.xml:19
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:4
+msgid "Input event type for keyboard events."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:7
+msgid ""
+"Stores key presses on the keyboard. Supports key presses, key releases and "
+"[member echo] events."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:17
+msgid ""
+"Returns the keycode combined with modifier keys such as [code]Shift[/code] "
+"or [code]Alt[/code]. See also [InputEventWithModifiers].\n"
+"To get a human-readable representation of the [InputEventKey] with "
+"modifiers, use [code]OS.get_keycode_string(event."
+"get_keycode_with_modifiers())[/code] where [code]event[/code] is the "
+"[InputEventKey]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:25
+msgid ""
+"Returns the physical keycode combined with modifier keys such as "
+"[code]Shift[/code] or [code]Alt[/code]. See also [InputEventWithModifiers].\n"
+"To get a human-readable representation of the [InputEventKey] with "
+"modifiers, use [code]OS.get_keycode_string(event."
+"get_physical_keycode_with_modifiers())[/code] where [code]event[/code] is "
+"the [InputEventKey]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:32
+msgid ""
+"If [code]true[/code], the key was already pressed before this event. It "
+"means the user is holding the key down."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:35
+msgid ""
+"The key keycode, which corresponds to one of the [enum KeyList] constants. "
+"Represent key in the current keyboard layout.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:39
+msgid ""
+"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.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:43
+msgid ""
+"If [code]true[/code], the key's state is pressed. If [code]false[/code], the "
+"key's state is released."
+msgstr ""
+
+#: doc/classes/InputEventKey.xml:46
+msgid ""
+"The key Unicode identifier (when relevant). Unicode identifiers for the "
+"composite characters and complex scripts may not be available unless IME "
+"input mode is active. See [method Window.set_ime_active] for more "
+"information."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:4
+msgid "Base input event type for mouse events."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:7
+msgid "Stores general mouse events information."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:16
+msgid ""
+"The mouse button mask identifier, one of or a bitwise combination of the "
+"[enum ButtonList] button masks."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:19
+msgid ""
+"The global mouse position relative to the current [Viewport] when used in "
+"[method Control._gui_input], otherwise is at 0,0."
+msgstr ""
+
+#: doc/classes/InputEventMouse.xml:22
+msgid ""
+"The local mouse position relative to the [Viewport]. If used in [method "
+"Control._gui_input], the position is relative to the current [Control] which "
+"is under the mouse."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:4
+msgid "Input event type for mouse button events."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:7
+msgid "Contains mouse click information. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:10
+#: doc/classes/InputEventMouseMotion.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/inputs/"
+"mouse_and_input_coordinates.html"
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:16
+msgid ""
+"The mouse button identifier, one of the [enum ButtonList] button or button "
+"wheel constants."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:19
+msgid "If [code]true[/code], the mouse button's state is a double-click."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:22
+msgid ""
+"The amount (or delta) of the event. When used for high-precision scroll "
+"events, this indicates the scroll amount (vertical or horizontal). This is "
+"only supported on some platforms; the reported sensitivity varies depending "
+"on the platform. May be [code]0[/code] if not supported."
+msgstr ""
+
+#: doc/classes/InputEventMouseButton.xml:25
+msgid ""
+"If [code]true[/code], the mouse button's state is pressed. If [code]false[/"
+"code], the mouse button's state is released."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:4
+msgid "Input event type for mouse motion events."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:7
+msgid ""
+"Contains mouse and pen motion information. Supports relative, absolute "
+"positions and speed. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:16
+msgid ""
+"Represents the pressure the user puts on the pen. Ranges from [code]0.0[/"
+"code] to [code]1.0[/code]."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:19
+msgid ""
+"The mouse position relative to the previous position (position at the last "
+"frame). \n"
+"[b]Note:[/b] Since [InputEventMouseMotion] is only emitted when the mouse "
+"moves, the last event won't have a relative position of [code]Vector2(0, 0)[/"
+"code] when the user stops moving the mouse."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:23
+msgid "The mouse speed in pixels per second."
+msgstr ""
+
+#: doc/classes/InputEventMouseMotion.xml:26
+msgid ""
+"Represents the angles of tilt of the pen. Positive X-coordinate value "
+"indicates a tilt to the right. Positive Y-coordinate value indicates a tilt "
+"toward the user. Ranges from [code]-1.0[/code] to [code]1.0[/code] for both "
+"axes."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:4
+msgid ""
+"Input event type for screen drag events. Only available on mobile devices."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:7
+msgid "Contains screen drag information. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:16
+msgid "The drag event index in the case of a multi-drag event."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:19
+msgid "The drag position."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:22
+msgid "The drag position relative to its start position."
+msgstr ""
+
+#: doc/classes/InputEventScreenDrag.xml:25
+msgid "The drag speed."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:4
+msgid ""
+"Input event type for screen touch events.\n"
+"(only available on mobile devices)"
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:8
+msgid ""
+"Stores multi-touch press/release information. Supports touch press, touch "
+"release and [member index] for multi-touch count and order."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:17
+msgid ""
+"The touch index in the case of a multi-touch event. One index = one finger."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:20
+msgid "The touch position."
+msgstr ""
+
+#: doc/classes/InputEventScreenTouch.xml:23
+msgid ""
+"If [code]true[/code], the touch's state is pressed. If [code]false[/code], "
+"the touch's state is released."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:4
+msgid "Base class for keys events with modifiers."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:7
+msgid ""
+"Contains keys events information with modifiers support like [code]Shift[/"
+"code] or [code]Alt[/code]. See [method Node._input]."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:16
+msgid "State of the [code]Alt[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:19
+msgid "State of the [code]Command[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:22
+msgid "State of the [code]Ctrl[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:25
+msgid "State of the [code]Meta[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputEventWithModifiers.xml:28
+msgid "State of the [code]Shift[/code] modifier."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:4
+msgid "A singleton that deals with inputs."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:7
+msgid ""
+"A singleton that deals with inputs. This includes key presses, mouse buttons "
+"and movement, joypads, and input actions. Actions and their events can be "
+"set in the [b]Input Map[/b] tab in the [b]Project > Project Settings[/b], or "
+"with the [InputMap] class."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/inputs/index.html"
+msgstr ""
+
+#: doc/classes/InputFilter.xml:21
+msgid ""
+"This will simulate pressing the specified action.\n"
+"The strength can be used for non-boolean actions, it's ranged between 0 and "
+"1 representing the intensity of the given action.\n"
+"[b]Note:[/b] This method will not cause any [method Node._input] calls. It "
+"is intended to be used with [method is_action_pressed] and [method "
+"is_action_just_pressed]. If you want to simulate [code]_input[/code], use "
+"[method parse_input_event] instead."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:32
+msgid "If the specified action is already pressed, this will release it."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:43
+msgid ""
+"Adds a new mapping entry (in SDL2 format) to the mapping database. "
+"Optionally update already connected devices."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:50
+msgid ""
+"If the device has an accelerometer, this will return the acceleration. "
+"Otherwise, it returns an empty [Vector3].\n"
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:60
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:67
+msgid ""
+"Returns an [Array] containing the device IDs of all currently connected "
+"joypads."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:74
+msgid "Returns the currently assigned cursor shape (see [enum CursorShape])."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:81
+msgid ""
+"If the device has an accelerometer, this will return the gravity. Otherwise, "
+"it returns an empty [Vector3]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:88
+msgid ""
+"If the device has a gyroscope, this will return the rate of rotation in rad/"
+"s around a device's X, Y, and Z axes. Otherwise, it returns an empty "
+"[Vector3]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:99
+msgid ""
+"Returns the current value of the joypad axis at given index (see [enum "
+"JoystickList])."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:108
+msgid "Returns the index of the provided axis name."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:117
+msgid ""
+"Receives a [enum JoystickList] axis and returns its equivalent name as a "
+"string."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:126
+msgid "Returns the index of the provided button name."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:135
+msgid ""
+"Receives a gamepad button from [enum JoystickList] and returns its "
+"equivalent name as a string."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:144
+msgid ""
+"Returns a SDL2-compatible device GUID on platforms that use gamepad "
+"remapping. Returns [code]\"Default Gamepad\"[/code] otherwise."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:153
+msgid "Returns the name of the joypad at the specified device index."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:162
+msgid "Returns the duration of the current vibration effect in seconds."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:171
+msgid ""
+"Returns the strength of the joypad vibration: x is the strength of the weak "
+"motor, and y is the strength of the strong motor."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:178
+msgid ""
+"Returns the mouse speed for the last time the cursor was moved, and this "
+"until the next frame where the mouse moves. This means that even if the "
+"mouse is not moving, this function will still return the value of the last "
+"motion."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:185
+msgid ""
+"If the device has a magnetometer, this will return the magnetic field "
+"strength in micro-Tesla for all axes."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:192
+msgid ""
+"Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at "
+"the same time, the bits are added together."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:199
+msgid "Returns the mouse mode. See the constants for more information."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:208
+msgid ""
+"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.\n"
+"This is useful for code that needs to run only once when an action is "
+"pressed, instead of every frame while it's pressed."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:218
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:227
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:238
+msgid ""
+"Returns [code]true[/code] if you are pressing the joypad button (see [enum "
+"JoystickList])."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:247
+msgid ""
+"Returns [code]true[/code] if the system knows the specified device. This "
+"means that it sets all button and axis indices exactly as defined in [enum "
+"JoystickList]. Unknown joypads are not expected to match these constants, "
+"but you can still retrieve events from them."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:256
+msgid ""
+"Returns [code]true[/code] if you are pressing the key in the current "
+"keyboard layout. You can pass a [enum KeyList] constant."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:265
+msgid ""
+"Returns [code]true[/code] if you are pressing the mouse button specified "
+"with [enum ButtonList]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:280
+msgid ""
+"Notifies the [InputFilter] singleton that a connection has changed, to "
+"update the state for the [code]device[/code] index.\n"
+"This is used internally and should not have to be called from user scripts. "
+"See [signal joy_connection_changed] for the signal emitted when this is "
+"triggered internally."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:290
+msgid ""
+"Feeds an [InputEvent] to the game. Can be used to artificially trigger input "
+"events from code. Also generates [method Node._input] calls.\n"
+"Example:\n"
+"[codeblock]\n"
+"var a = InputEventAction.new()\n"
+"a.action = \"ui_cancel\"\n"
+"a.pressed = true\n"
+"InputFilter.parse_input_event(a)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/InputFilter.xml:306
+msgid ""
+"Removes all mappings from the internal database that match the given GUID."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:319
+msgid ""
+"Sets a custom mouse cursor image, which is only visible inside the game "
+"window. The hotspot can also be specified. Passing [code]null[/code] to the "
+"image parameter resets to the system cursor. See [enum CursorShape] for the "
+"list of shapes.\n"
+"[code]image[/code]'s size must be lower than 256×256.\n"
+"[code]hotspot[/code] must be within [code]image[/code]'s size.\n"
+"[b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If "
+"using an [AnimatedTexture], only the first frame will be displayed.\n"
+"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
+"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
+"compression mode can't be used for custom cursors."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:332
+msgid ""
+"Sets the default cursor shape to be used in the viewport instead of "
+"[constant CURSOR_ARROW].\n"
+"[b]Note:[/b] If you want to change the default cursor shape for [Control]'s "
+"nodes, use [member Control.mouse_default_cursor_shape] instead.\n"
+"[b]Note:[/b] This method generates an [InputEventMouseMotion] to update "
+"cursor immediately."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:343
+msgid "Sets the mouse mode. See the constants for more information."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:352
+msgid ""
+"Enables or disables the accumulation of similar input events sent by the "
+"operating system. When input accumulation is enabled, all input events "
+"generated during a frame will be merged and emitted when the frame is done "
+"rendering. Therefore, this limits the number of input method calls per "
+"second to the rendering FPS.\n"
+"Input accumulation is enabled by default. It can be disabled to get slightly "
+"more precise/reactive input at the cost of increased CPU usage. In "
+"applications where drawing freehand lines is required, input accumulation "
+"should generally be disabled while the user is drawing the line to get "
+"results that closely follow the actual input."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:368
+msgid ""
+"Starts to vibrate the joypad. Joypads usually come with two rumble motors, a "
+"strong and a weak one. [code]weak_magnitude[/code] is the strength of the "
+"weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the "
+"strength of the strong motor (between 0 and 1). [code]duration[/code] is the "
+"duration of the effect in seconds (a duration of 0 will try to play the "
+"vibration indefinitely).\n"
+"[b]Note:[/b] Not every hardware is compatible with long effect durations; it "
+"is recommended to restart an effect if it has to be played for more than a "
+"few seconds."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:378
+msgid "Stops the vibration of the joypad."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:387
+msgid ""
+"Vibrate Android and iOS devices.\n"
+"[b]Note:[/b] It needs VIBRATE permission for Android at export settings. iOS "
+"does not support duration."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:397
+msgid "Sets the mouse position to the specified vector."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:408
+msgid "Emitted when a joypad device has been connected or disconnected."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:414
+msgid "Makes the mouse cursor visible if it is hidden."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:417
+msgid "Makes the mouse cursor hidden if it is visible."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:420
+msgid ""
+"Captures the mouse. The mouse will be hidden and unable to leave the game "
+"window, but it will still register movement and mouse button presses. On "
+"Windows and Linux, the mouse will use raw input mode, which means the "
+"reported movement will be unaffected by the OS' mouse acceleration settings."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:423
+msgid "Makes the mouse cursor visible but confines it to the game window."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:426
+msgid "Arrow cursor. Standard, default pointing cursor."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:429
+msgid ""
+"I-beam cursor. Usually used to show where the text cursor will appear when "
+"the mouse is clicked."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:432
+msgid ""
+"Pointing hand cursor. Usually used to indicate the pointer is over a link or "
+"other interactable item."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:435
+msgid ""
+"Cross cursor. Typically appears over regions in which a drawing operation "
+"can be performed or for selections."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:438
+msgid ""
+"Wait cursor. Indicates that the application is busy performing an operation. "
+"This cursor shape denotes that the application is still usable during the "
+"operation."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:441
+msgid ""
+"Busy cursor. Indicates that the application is busy performing an operation. "
+"This cursor shape denotes that the application isn't usable during the "
+"operation (e.g. something is blocking its main thread)."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:444
+msgid "Drag cursor. Usually displayed when dragging something."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:447
+msgid ""
+"Can drop cursor. Usually displayed when dragging something to indicate that "
+"it can be dropped at the current position."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:450
+msgid ""
+"Forbidden cursor. Indicates that the current action is forbidden (for "
+"example, when dragging something) or that the control at a position is "
+"disabled."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:453
+msgid ""
+"Vertical resize mouse cursor. A double-headed vertical arrow. It tells the "
+"user they can resize the window or the panel vertically."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:456
+msgid ""
+"Horizontal resize mouse cursor. A double-headed horizontal arrow. It tells "
+"the user they can resize the window or the panel horizontally."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:459
+msgid ""
+"Window resize mouse cursor. The cursor is a double-headed arrow that goes "
+"from the bottom left to the top right. It tells the user they can resize the "
+"window or the panel both horizontally and vertically."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:462
+msgid ""
+"Window resize mouse cursor. The cursor is a double-headed arrow that goes "
+"from the top left to the bottom right, the opposite of [constant "
+"CURSOR_BDIAGSIZE]. It tells the user they can resize the window or the panel "
+"both horizontally and vertically."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:465
+msgid "Move cursor. Indicates that something can be moved."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:468
+msgid ""
+"Vertical split mouse cursor. On Windows, it's the same as [constant "
+"CURSOR_VSIZE]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:471
+msgid ""
+"Horizontal split mouse cursor. On Windows, it's the same as [constant "
+"CURSOR_HSIZE]."
+msgstr ""
+
+#: doc/classes/InputFilter.xml:474
+msgid "Help cursor. Usually a question mark."
+msgstr ""
+
+#: doc/classes/InputMap.xml:4
+msgid "Singleton that manages [InputEventAction]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:7
+msgid ""
+"Manages all [InputEventAction] which can be created/modified from the "
+"project settings menu [b]Project > Project Settings > Input Map[/b] or in "
+"code with [method add_action] and [method action_add_event]. See [method "
+"Node._input]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent."
+"html#inputmap"
+msgstr ""
+
+#: doc/classes/InputMap.xml:21
+msgid ""
+"Adds an [InputEvent] to an action. This [InputEvent] will trigger the action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:32
+msgid "Removes an [InputEvent] from an action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:41
+msgid "Removes all events from an action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:52
+msgid ""
+"Returns [code]true[/code] if the action has the given [InputEvent] "
+"associated with it."
+msgstr ""
+
+#: doc/classes/InputMap.xml:63
+msgid "Sets a deadzone value for the action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:74
+msgid ""
+"Adds an empty action to the [InputMap] with a configurable [code]deadzone[/"
+"code].\n"
+"An [InputEvent] can then be added to this action with [method "
+"action_add_event]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:84
+msgid "Removes an action from the [InputMap]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:95
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/InputMap.xml:104
+msgid "Returns an array of [InputEvent]s associated with a given action."
+msgstr ""
+
+#: doc/classes/InputMap.xml:111
+msgid "Returns an array of all actions in the [InputMap]."
+msgstr ""
+
+#: doc/classes/InputMap.xml:120
+msgid ""
+"Returns [code]true[/code] if the [InputMap] has a registered action with the "
+"given name."
+msgstr ""
+
+#: doc/classes/InputMap.xml:127
+msgid ""
+"Clears all [InputEventAction] in the [InputMap] and load it anew from "
+"[ProjectSettings]."
+msgstr ""
+
+#: doc/classes/InstancePlaceholder.xml:4
+msgid "Placeholder for the root [Node] of a [PackedScene]."
+msgstr ""
+
+#: doc/classes/InstancePlaceholder.xml:7
+msgid ""
+"Turning on the option [b]Load As Placeholder[/b] for an instanced scene in "
+"the editor causes it to be replaced by an [InstancePlaceholder] when running "
+"the game. This makes it possible to delay actually loading the scene until "
+"calling [method create_instance]. This is useful to avoid loading large "
+"scenes all at once by loading parts of it selectively.\n"
+"The [InstancePlaceholder] does not have a transform. This causes any child "
+"nodes to be positioned relatively to the [Viewport] from point (0,0), rather "
+"than their parent as displayed in the editor. Replacing the placeholder with "
+"a scene with a transform will transform children relatively to their parent "
+"again."
+msgstr ""
+
+#: doc/classes/InstancePlaceholder.xml:27
+msgid ""
+"Gets the path to the [PackedScene] resource file that is loaded by default "
+"when calling [method create_instance]."
+msgstr ""
+
+#: doc/classes/int.xml:4
+msgid "Integer built-in type."
+msgstr ""
+
+#: doc/classes/int.xml:7
+msgid ""
+"Signed 64-bit integer type.\n"
+"It can take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. "
+"[code][-9223372036854775808, 9223372036854775807][/code]. Exceeding those "
+"bounds will wrap around.\n"
+"[int] is a [Variant] type, and will thus be used when assigning an integer "
+"value to a [Variant]. It can also be enforced with the [code]: int[/code] "
+"type hint.\n"
+"[codeblock]\n"
+"var my_variant = 0 # int, value 0.\n"
+"my_variant += 4.2 # float, value 4.2.\n"
+"var my_int: int = 1 # int, value 1.\n"
+"my_int = 4.2 # int, value 4, the right value is implicitly cast to int.\n"
+"my_int = int(\"6.7\") # int, value 6, the String is explicitly cast with "
+"int.\n"
+"\n"
+"var max_int = 9223372036854775807\n"
+"print(max_int) # 9223372036854775807, OK.\n"
+"max_int += 1\n"
+"print(max_int) # -9223372036854775808, we overflowed and wrapped around.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/int.xml:32
+msgid ""
+"Cast a [bool] value to an integer value, [code]int(true)[/code] will be "
+"equals to 1 and [code]int(false)[/code] will be equals to 0."
+msgstr ""
+
+#: doc/classes/int.xml:41
+msgid ""
+"Cast a float value to an integer value, this method simply removes the "
+"number fractions, so for example [code]int(2.7)[/code] will be equals to 2, "
+"[code]int(.1)[/code] will be equals to 0 and [code]int(-2.7)[/code] will be "
+"equals to -2."
+msgstr ""
+
+#: doc/classes/int.xml:50
+msgid ""
+"Cast a [String] value to an integer value, this method is an integer parser "
+"from a string, so calling this method with an invalid integer string will "
+"return 0, a valid string will be something like [code]'1.7'[/code]. This "
+"method will ignore all non-number characters, so calling [code]int('1e3')[/"
+"code] will return 13."
+msgstr ""
+
+#: doc/classes/IP.xml:4
+msgid "Internet protocol (IP) support functions such as DNS resolution."
+msgstr ""
+
+#: doc/classes/IP.xml:7
+msgid ""
+"IP contains support functions for the Internet Protocol (IP). TCP/IP support "
+"is in different classes (see [StreamPeerTCP] and [TCP_Server]). IP provides "
+"DNS hostname resolution support, both blocking and threaded."
+msgstr ""
+
+#: doc/classes/IP.xml:18
+msgid ""
+"Removes all of a [code]hostname[/code]'s cached references. If no "
+"[code]hostname[/code] is given, all cached IP addresses are removed."
+msgstr ""
+
+#: doc/classes/IP.xml:27
+msgid ""
+"Removes a given item [code]id[/code] from the queue. This should be used to "
+"free a queue after it has completed to enable more queries to happen."
+msgstr ""
+
+#: doc/classes/IP.xml:34
+msgid "Returns all of the user's current IPv4 and IPv6 addresses as an array."
+msgstr ""
+
+#: doc/classes/IP.xml:41
+msgid ""
+"Returns all network adapters as an array.\n"
+"Each adapter is a dictionary of the form:\n"
+"[codeblock]\n"
+"{\n"
+" \"index\": \"1\", # Interface index.\n"
+" \"name\": \"eth0\", # Interface name.\n"
+" \"friendly\": \"Ethernet One\", # A friendly name (might be empty).\n"
+" \"addresses\": [\"192.168.1.101\"], # An array of IP addresses "
+"associated to this interface.\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/IP.xml:59
+msgid ""
+"Returns a queued hostname's IP address, given its queue [code]id[/code]. "
+"Returns an empty string on error or if resolution hasn't happened yet (see "
+"[method get_resolve_item_status])."
+msgstr ""
+
+#: doc/classes/IP.xml:68
+msgid ""
+"Returns a queued hostname's status as a [enum ResolverStatus] constant, "
+"given its queue [code]id[/code]."
+msgstr ""
+
+#: doc/classes/IP.xml:79
+msgid ""
+"Returns a given hostname's IPv4 or IPv6 address when resolved (blocking-type "
+"method). The address type returned depends on the [enum Type] constant given "
+"as [code]ip_type[/code]."
+msgstr ""
+
+#: doc/classes/IP.xml:90
+msgid ""
+"Creates a queue item to resolve a hostname to an IPv4 or IPv6 address "
+"depending on the [enum Type] constant given as [code]ip_type[/code]. Returns "
+"the queue ID if successful, or [constant RESOLVER_INVALID_ID] on error."
+msgstr ""
+
+#: doc/classes/IP.xml:96
+msgid "DNS hostname resolver status: No status."
+msgstr ""
+
+#: doc/classes/IP.xml:99
+msgid "DNS hostname resolver status: Waiting."
+msgstr ""
+
+#: doc/classes/IP.xml:102
+msgid "DNS hostname resolver status: Done."
+msgstr ""
+
+#: doc/classes/IP.xml:105
+msgid "DNS hostname resolver status: Error."
+msgstr ""
+
+#: doc/classes/IP.xml:108
+msgid ""
+"Maximum number of concurrent DNS resolver queries allowed, [constant "
+"RESOLVER_INVALID_ID] is returned if exceeded."
+msgstr ""
+
+#: doc/classes/IP.xml:111
+msgid ""
+"Invalid ID constant. Returned if [constant RESOLVER_MAX_QUERIES] is exceeded."
+msgstr ""
+
+#: doc/classes/IP.xml:114
+msgid "Address type: None."
+msgstr ""
+
+#: doc/classes/IP.xml:117
+msgid "Address type: Internet protocol version 4 (IPv4)."
+msgstr ""
+
+#: doc/classes/IP.xml:120
+msgid "Address type: Internet protocol version 6 (IPv6)."
+msgstr ""
+
+#: doc/classes/IP.xml:123
+msgid "Address type: Any."
+msgstr ""
+
+#: doc/classes/IP_Unix.xml:4
+msgid "UNIX IP support. See [IP]."
+msgstr ""
+
+#: doc/classes/IP_Unix.xml:7
+msgid "UNIX-specific implementation of IP support functions. See [IP]."
+msgstr ""
+
+#: doc/classes/ItemList.xml:4
+msgid ""
+"Control that provides a list of selectable items (and/or icons) in a single "
+"column, or optionally in multiple columns."
+msgstr ""
+
+#: doc/classes/ItemList.xml:7
+msgid ""
+"This control provides a selectable list of items that may be in a single (or "
+"multiple columns) with option of text, icons, or both text and icon. "
+"Tooltips are supported and may be different for every item in the list.\n"
+"Selectable items in the list may be selected or deselected and multiple "
+"selection may be enabled. Selection with right mouse button may also be "
+"enabled to allow use of popup context menus. Items may also be \"activated\" "
+"by double-clicking them or by pressing Enter.\n"
+"Item text only supports single-line strings, newline characters (e.g. "
+"[code]\\n[/code]) in the string won't produce a newline. Text wrapping is "
+"enabled in [constant ICON_MODE_TOP] mode, but column's width is adjusted to "
+"fully fit its content by default. You need to set [member "
+"fixed_column_width] greater than zero to wrap the text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:22
+msgid "Adds an item to the item list with no text, only an icon."
+msgstr ""
+
+#: doc/classes/ItemList.xml:35
+msgid ""
+"Adds an item to the item list with specified text. Specify an [code]icon[/"
+"code], or use [code]null[/code] as the [code]icon[/code] for a list item "
+"with no icon.\n"
+"If selectable is [code]true[/code], the list item will be selectable."
+msgstr ""
+
+#: doc/classes/ItemList.xml:43
+msgid "Removes all items from the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:50
+msgid ""
+"Ensure current selection is visible, adjusting the scroll position as "
+"necessary."
+msgstr ""
+
+#: doc/classes/ItemList.xml:61
+msgid ""
+"Returns the item index at the given [code]position[/code].\n"
+"When there is no item at that point, -1 will be returned if [code]exact[/"
+"code] is [code]true[/code], and the closest item index will be returned "
+"otherwise."
+msgstr ""
+
+#: doc/classes/ItemList.xml:69
+msgid "Returns the number of items currently in the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:78
+msgid ""
+"Returns the custom background color of the item specified by [code]idx[/"
+"code] index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:87
+msgid ""
+"Returns the custom foreground color of the item specified by [code]idx[/"
+"code] index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:96
+msgid "Returns the icon associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:105
+msgid "Returns a [Color] modulating item's icon at the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:114
+msgid ""
+"Returns the region of item's icon used. The whole icon will be used if the "
+"region has no area."
+msgstr ""
+
+#: doc/classes/ItemList.xml:123
+msgid "Returns the metadata value of the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:132
+msgid "Returns the text associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:141
+msgid "Returns the tooltip hint associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:148
+msgid "Returns an array with the indexes of the selected items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:155
+msgid "Returns the [Object] ID associated with the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:162
+msgid "Returns [code]true[/code] if one or more items are selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:171
+msgid ""
+"Returns [code]true[/code] if the item at the specified index is disabled."
+msgstr ""
+
+#: doc/classes/ItemList.xml:180
+msgid ""
+"Returns [code]true[/code] if the item icon will be drawn transposed, i.e. "
+"the X and Y axes are swapped."
+msgstr ""
+
+#: doc/classes/ItemList.xml:189
+msgid ""
+"Returns [code]true[/code] if the item at the specified index is selectable."
+msgstr ""
+
+#: doc/classes/ItemList.xml:198
+msgid ""
+"Returns [code]true[/code] if the tooltip is enabled for specified item index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:207
+msgid ""
+"Returns [code]true[/code] if the item at the specified index is currently "
+"selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:218
+msgid "Moves item from index [code]from_idx[/code] to [code]to_idx[/code]."
+msgstr ""
+
+#: doc/classes/ItemList.xml:227
+msgid "Removes the item specified by [code]idx[/code] index from the list."
+msgstr ""
+
+#: doc/classes/ItemList.xml:238
+msgid ""
+"Select the item at the specified index.\n"
+"[b]Note:[/b] This method does not trigger the item selection signal."
+msgstr ""
+
+#: doc/classes/ItemList.xml:250
+msgid ""
+"Sets the background color of the item specified by [code]idx[/code] index to "
+"the specified [Color].\n"
+"[codeblock]\n"
+"var some_string = \"Some text\"\n"
+"some_string.set_item_custom_bg_color(0,Color(1, 0, 0, 1) # This will set the "
+"background color of the first item of the control to red.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ItemList.xml:265
+msgid ""
+"Sets the foreground color of the item specified by [code]idx[/code] index to "
+"the specified [Color].\n"
+"[codeblock]\n"
+"var some_string = \"Some text\"\n"
+"some_string.set_item_custom_fg_color(0,Color(1, 0, 0, 1) # This will set the "
+"foreground color of the first item of the control to red.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ItemList.xml:280
+msgid ""
+"Disables (or enables) the item at the specified index.\n"
+"Disabled items cannot be selected and do not trigger activation signals "
+"(when double-clicking or pressing Enter)."
+msgstr ""
+
+#: doc/classes/ItemList.xml:292
+msgid ""
+"Sets (or replaces) the icon's [Texture2D] associated with the specified "
+"index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:303
+msgid ""
+"Sets a modulating [Color] of the item associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:314
+msgid ""
+"Sets the region of item's icon used. The whole icon will be used if the "
+"region has no area."
+msgstr ""
+
+#: doc/classes/ItemList.xml:325
+msgid "Sets whether the item icon will be drawn transposed."
+msgstr ""
+
+#: doc/classes/ItemList.xml:336
+msgid ""
+"Sets a value (of any type) to be stored with the item associated with the "
+"specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:347
+msgid ""
+"Allows or disallows selection of the item associated with the specified "
+"index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:358
+msgid "Sets text of the item associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:369
+msgid "Sets the tooltip hint for the item associated with the specified index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:380
+msgid "Sets whether the tooltip hint is enabled for specified item index."
+msgstr ""
+
+#: doc/classes/ItemList.xml:387
+msgid "Sorts items in the list by their text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:396
+msgid "Ensures the item associated with the specified index is not selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:403
+msgid "Ensures there are no items selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:409
+msgid ""
+"If [code]true[/code], the currently selected item can be selected again."
+msgstr ""
+
+#: doc/classes/ItemList.xml:412
+msgid "If [code]true[/code], right mouse button click can select items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:415
+msgid ""
+"If [code]true[/code], the control will automatically resize the height to "
+"fit its content."
+msgstr ""
+
+#: doc/classes/ItemList.xml:418
+msgid ""
+"The width all columns will be adjusted to.\n"
+"A value of zero disables the adjustment, each item will have a width equal "
+"to the width of its content and the columns will have an uneven width."
+msgstr ""
+
+#: doc/classes/ItemList.xml:422
+msgid ""
+"The size all icons will be adjusted to.\n"
+"If either X or Y component is not greater than zero, icon size won't be "
+"affected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:427
+msgid ""
+"The icon position, whether above or to the left of the text. See the [enum "
+"IconMode] constants."
+msgstr ""
+
+#: doc/classes/ItemList.xml:430
+msgid ""
+"The scale of icon applied after [member fixed_icon_size] and transposing "
+"takes effect."
+msgstr ""
+
+#: doc/classes/ItemList.xml:433
+msgid ""
+"Maximum columns the list will have.\n"
+"If greater than zero, the content will be split among the specified "
+"columns.\n"
+"A value of zero means unlimited columns, i.e. all items will be put in the "
+"same row."
+msgstr ""
+
+#: doc/classes/ItemList.xml:438
+msgid ""
+"Maximum lines of text allowed in each item. Space will be reserved even when "
+"there is not enough lines of text to display.\n"
+"[b]Note:[/b] This property takes effect only when [member icon_mode] is "
+"[constant ICON_MODE_TOP]. To make the text wrap, [member fixed_column_width] "
+"should be greater than zero."
+msgstr ""
+
+#: doc/classes/ItemList.xml:443
+msgid ""
+"Whether all columns will have the same width.\n"
+"If [code]true[/code], the width is equal to the largest column width of all "
+"columns."
+msgstr ""
+
+#: doc/classes/ItemList.xml:447
+msgid ""
+"Allows single or multiple item selection. See the [enum SelectMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/ItemList.xml:455
+msgid ""
+"Triggered when specified list item is activated via double-clicking or by "
+"pressing Enter."
+msgstr ""
+
+#: doc/classes/ItemList.xml:464
+msgid ""
+"Triggered when specified list item has been selected via right mouse "
+"clicking.\n"
+"The click position is also provided to allow appropriate popup of context "
+"menus at the correct location.\n"
+"[member allow_rmb_select] must be enabled."
+msgstr ""
+
+#: doc/classes/ItemList.xml:473
+msgid ""
+"Triggered when specified item has been selected.\n"
+"[member allow_reselect] must be enabled to reselect an item."
+msgstr ""
+
+#: doc/classes/ItemList.xml:483
+msgid ""
+"Triggered when a multiple selection is altered on a list allowing multiple "
+"selection."
+msgstr ""
+
+#: doc/classes/ItemList.xml:488
+msgid ""
+"Triggered when a left mouse click is issued within the rect of the list but "
+"on empty space."
+msgstr ""
+
+#: doc/classes/ItemList.xml:495
+msgid ""
+"Triggered when a right mouse click is issued within the rect of the list but "
+"on empty space.\n"
+"[member allow_rmb_select] must be enabled."
+msgstr ""
+
+#: doc/classes/ItemList.xml:502
+msgid "Icon is drawn above the text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:505
+msgid "Icon is drawn to the left of the text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:508
+msgid "Only allow selecting a single item."
+msgstr ""
+
+#: doc/classes/ItemList.xml:511
+msgid "Allows selecting multiple items by holding Ctrl or Shift."
+msgstr ""
+
+#: doc/classes/ItemList.xml:516
+msgid ""
+"Default [StyleBox] for the [ItemList], i.e. used when the control is not "
+"being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:519
+msgid "[StyleBox] used when the [ItemList] is being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:522
+msgid "[StyleBox] used for the cursor, when the [ItemList] is being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:525
+msgid ""
+"[StyleBox] used for the cursor, when the [ItemList] is not being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:528 doc/classes/Tree.xml:439
+msgid "[Font] of the item's text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:531 doc/classes/Tree.xml:442
+msgid "Default text [Color] of the item."
+msgstr ""
+
+#: doc/classes/ItemList.xml:534 doc/classes/Tree.xml:445
+msgid "Text [Color] used when the item is selected."
+msgstr ""
+
+#: doc/classes/ItemList.xml:537
+msgid ""
+"[Color] of the guideline. The guideline is a line drawn between each row of "
+"items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:540
+msgid "The horizontal spacing between items."
+msgstr ""
+
+#: doc/classes/ItemList.xml:543
+msgid "The spacing between item's icon and text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:546
+msgid "The vertical spacing between each line of text."
+msgstr ""
+
+#: doc/classes/ItemList.xml:549
+msgid ""
+"[StyleBox] for the selected items, used when the [ItemList] is not being "
+"focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:552
+msgid ""
+"[StyleBox] for the selected items, used when the [ItemList] is being focused."
+msgstr ""
+
+#: doc/classes/ItemList.xml:555
+msgid "The vertical spacing between items."
+msgstr ""
+
+#: doc/classes/JavaScript.xml:4
+msgid ""
+"Singleton that connects the engine with the browser's JavaScript context in "
+"HTML5 export."
+msgstr ""
+
+#: doc/classes/JavaScript.xml:7
+msgid ""
+"The JavaScript singleton is implemented only in the HTML5 export. It's used "
+"to access the browser's JavaScript context. This allows interaction with "
+"embedding pages or calling third-party JavaScript APIs."
+msgstr ""
+
+#: doc/classes/JavaScript.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/workflow/export/"
+"exporting_for_web.html#calling-javascript-from-script"
+msgstr ""
+
+#: doc/classes/JavaScript.xml:21
+msgid ""
+"Execute the string [code]code[/code] as JavaScript code within the browser "
+"window. This is a call to the actual global JavaScript function [code]eval()"
+"[/code].\n"
+"If [code]use_global_execution_context[/code] is [code]true[/code], the code "
+"will be evaluated in the global execution context. Otherwise, it is "
+"evaluated in the execution context of a function within the engine's runtime "
+"environment."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:4
+msgid "Base node for all joint constraints in 2D physics."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:7
+msgid ""
+"Base node for all joint constraints in 2D physics. Joints take 2 bodies and "
+"apply a custom constraint."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:15
+msgid ""
+"When [member node_a] and [member node_b] move in different directions the "
+"[code]bias[/code] controls how fast the joint pulls them back to their "
+"original position. The lower the [code]bias[/code] the more the two bodies "
+"can pull on the joint."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:18
+msgid "If [code]true[/code], [member node_a] and [member node_b] can collide."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:21
+msgid "The first body attached to the joint. Must derive from [PhysicsBody2D]."
+msgstr ""
+
+#: doc/classes/Joint2D.xml:24
+msgid ""
+"The second body attached to the joint. Must derive from [PhysicsBody2D]."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:4
+msgid "Base class for all 3D joints."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:7
+msgid ""
+"Joints are used to bind together two physics bodies. They have a solver "
+"priority and can define if the bodies of the two attached nodes should be "
+"able to collide with each other."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:15
+msgid ""
+"If [code]true[/code], the two bodies of the nodes are not able to collide "
+"with each other."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:18
+msgid "The node attached to the first side (A) of the joint."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:21
+msgid "The node attached to the second side (B) of the joint."
+msgstr ""
+
+#: doc/classes/Joint3D.xml:24
+msgid ""
+"The priority used to define which solver is executed first for multiple "
+"joints. The lower the value, the higher the priority."
+msgstr ""
+
+#: doc/classes/JSON.xml:4
+msgid "Helper class for parsing JSON data."
+msgstr ""
+
+#: doc/classes/JSON.xml:7
+msgid ""
+"Helper class for parsing JSON data. For usage example and other important "
+"hints, see [JSONParseResult]."
+msgstr ""
+
+#: doc/classes/JSON.xml:18
+msgid ""
+"Parses a JSON encoded string and returns a [JSONParseResult] containing the "
+"result."
+msgstr ""
+
+#: doc/classes/JSON.xml:31
+msgid ""
+"Converts a [Variant] var to JSON text and returns the result. Useful for "
+"serializing data to store or send over the network."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:4
+msgid "Data class wrapper for decoded JSON."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:7
+msgid ""
+"Returned by [method JSON.parse], [JSONParseResult] contains the decoded JSON "
+"or error information if the JSON source wasn't successfully parsed. You can "
+"check if the JSON source was successfully parsed with [code]if json_result."
+"error == OK[/code]."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:15
+msgid ""
+"The error type if the JSON source was not successfully parsed. See the [enum "
+"Error] constants."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:18
+msgid ""
+"The line number where the error occurred if JSON source was not successfully "
+"parsed."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:21
+msgid ""
+"The error message if JSON source was not successfully parsed. See the [enum "
+"Error] constants."
+msgstr ""
+
+#: doc/classes/JSONParseResult.xml:24
+msgid ""
+"A [Variant] containing the parsed JSON. Use [method @GDScript.typeof] or the "
+"[code]is[/code] keyword to check if it is what you expect. For example, if "
+"the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] "
+"will be returned. If the JSON source starts with braces ([code][][/code]), "
+"an [Array] will be returned.\n"
+"[b]Note:[/b] The JSON specification does not define integer or float types, "
+"but only a number type. Therefore, parsing a JSON text will convert all "
+"numerical values to float types.\n"
+"[b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, "
+"thus, you should not rely on keys being in a certain order if a dictionary "
+"is constructed from JSON. In contrast, JSON arrays retain the order of their "
+"elements:\n"
+"[codeblock]\n"
+"var p = JSON.parse('[\"hello\", \"world\", \"!\"]')\n"
+"if typeof(p.result) == TYPE_ARRAY:\n"
+" print(p.result[0]) # Prints \"hello\"\n"
+"else:\n"
+" print(\"unexpected results\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:4
+msgid "Kinematic body 2D node."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:7
+msgid ""
+"Kinematic bodies are special types of bodies that are meant to be user-"
+"controlled. They are not affected by physics at all; to other types of "
+"bodies, such as a character or a rigid body, these are the same as a static "
+"body. However, they have two main uses:\n"
+"[b]Simulated motion:[/b] When these bodies are moved manually, either from "
+"code or from an [AnimationPlayer] (with [member AnimationPlayer."
+"playback_process_mode] set to \"physics\"), the physics will automatically "
+"compute an estimate of their linear and angular velocity. This makes them "
+"very useful for moving platforms or other AnimationPlayer-controlled objects "
+"(like a door, a bridge that opens, etc).\n"
+"[b]Kinematic characters:[/b] KinematicBody2D also has an API for moving "
+"objects (the [method move_and_collide] and [method move_and_slide] methods) "
+"while performing collision tests. This makes them really useful to implement "
+"characters that collide against a world, but that don't require advanced "
+"physics."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:12 doc/classes/KinematicBody3D.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/"
+"kinematic_character_2d.html"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/"
+"using_kinematic_body_2d.html"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:20 doc/classes/KinematicBody3D.xml:28
+msgid ""
+"Returns the surface normal of the floor at the last collision point. Only "
+"valid after calling [method move_and_slide] or [method "
+"move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:27 doc/classes/KinematicBody3D.xml:35
+msgid ""
+"Returns the linear velocity of the floor at the last collision point. Only "
+"valid after calling [method move_and_slide] or [method "
+"move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:36
+msgid ""
+"Returns a [KinematicCollision2D], which contains information about a "
+"collision that occurred during the last [method move_and_slide] call. Since "
+"the body can collide several times in a single call to [method "
+"move_and_slide], you must specify the index of the collision in the range 0 "
+"to ([method get_slide_count] - 1).\n"
+"[b]Example usage:[/b]\n"
+"[codeblock]\n"
+"for i in get_slide_count():\n"
+" var collision = get_slide_collision(i)\n"
+" print(\"Collided with: \", collision.collider.name)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:49 doc/classes/KinematicBody3D.xml:51
+msgid ""
+"Returns the number of times the body collided and changed direction during "
+"the last call to [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:56 doc/classes/KinematicBody3D.xml:58
+msgid ""
+"Returns [code]true[/code] if the body is on the ceiling. Only updates when "
+"calling [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:63 doc/classes/KinematicBody3D.xml:65
+msgid ""
+"Returns [code]true[/code] if the body is on the floor. Only updates when "
+"calling [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:70 doc/classes/KinematicBody3D.xml:72
+msgid ""
+"Returns [code]true[/code] if the body is on a wall. Only updates when "
+"calling [method move_and_slide]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:85
+msgid ""
+"Moves the body along the vector [code]rel_vec[/code]. The body will stop if "
+"it collides. Returns a [KinematicCollision2D], which contains information "
+"about the collision.\n"
+"If [code]test_only[/code] is [code]true[/code], the body does not move but "
+"the would-be collision information is given."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:105
+msgid ""
+"Moves the body along a vector. If the body collides with another, it will "
+"slide along the other body rather than stop immediately. If the other body "
+"is a [KinematicBody2D] or [RigidBody2D], it will also be affected by the "
+"motion of the other body. You can use this to make moving or rotating "
+"platforms, or to make nodes push other nodes.\n"
+"This method should be used in [method Node._physics_process] (or in a method "
+"called by [method Node._physics_process]), as it uses the physics step's "
+"[code]delta[/code] value automatically in calculations. Otherwise, the "
+"simulation will run at an incorrect speed.\n"
+"[code]linear_velocity[/code] is the velocity vector in pixels per second. "
+"Unlike in [method move_and_collide], you should [i]not[/i] multiply it by "
+"[code]delta[/code] — the physics engine handles applying the velocity. \n"
+"[code]up_direction[/code] is the up direction, used to determine what is a "
+"wall and what is a floor or a ceiling. If set to the default value of "
+"[code]Vector2(0, 0)[/code], everything is considered a wall. This is useful "
+"for topdown games.\n"
+"If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on "
+"slopes when you include gravity in [code]linear_velocity[/code] and the body "
+"is standing still.\n"
+"If the body collides, it will change direction a maximum of "
+"[code]max_slides[/code] times before it stops.\n"
+"[code]floor_max_angle[/code] is the maximum angle (in radians) where a slope "
+"is still considered a floor (or a ceiling), rather than a wall. The default "
+"value equals 45 degrees.\n"
+"If [code]infinite_inertia[/code] is [code]true[/code], body will be able to "
+"push [RigidBody2D] nodes, but it won't also detect any collisions with them. "
+"If [code]false[/code], it will interact with [RigidBody2D] nodes like with "
+"[StaticBody2D].\n"
+"Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a "
+"slide collision occurred. To get detailed information about collisions that "
+"occurred, use [method get_slide_collision]."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:134
+msgid ""
+"Moves the body while keeping it attached to slopes. Similar to [method "
+"move_and_slide].\n"
+"As long as the [code]snap[/code] vector is in contact with the ground, the "
+"body will remain attached to the surface. This means you must disable snap "
+"in order to jump, for example. You can do this by setting [code]snap[/code] "
+"to [code](0, 0)[/code] or by using [method move_and_slide] instead."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:148
+msgid ""
+"Checks for collisions without moving the body. Virtually sets the node's "
+"position, scale and rotation to that of the given [Transform2D], then tries "
+"to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/"
+"code] if a collision would occur."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:154 doc/classes/KinematicBody3D.xml:167
+msgid ""
+"If the body is at least this close to another body, this body will consider "
+"them to be colliding."
+msgstr ""
+
+#: doc/classes/KinematicBody2D.xml:157
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:4
+msgid "Kinematic body 3D node."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:7
+msgid ""
+"Kinematic bodies are special types of bodies that are meant to be user-"
+"controlled. They are not affected by physics at all; to other types of "
+"bodies, such as a character or a rigid body, these are the same as a static "
+"body. However, they have two main uses:\n"
+"[b]Simulated motion:[/b] When these bodies are moved manually, either from "
+"code or from an [AnimationPlayer] (with [member AnimationPlayer."
+"playback_process_mode] set to \"physics\"), the physics will automatically "
+"compute an estimate of their linear and angular velocity. This makes them "
+"very useful for moving platforms or other AnimationPlayer-controlled objects "
+"(like a door, a bridge that opens, etc).\n"
+"[b]Kinematic characters:[/b] KinematicBody3D also has an API for moving "
+"objects (the [method move_and_collide] and [method move_and_slide] methods) "
+"while performing collision tests. This makes them really useful to implement "
+"characters that collide against a world, but that don't require advanced "
+"physics."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:21
+msgid ""
+"Returns [code]true[/code] if the specified [code]axis[/code] is locked. See "
+"also [member move_lock_x], [member move_lock_y] and [member move_lock_z]."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:44
+msgid ""
+"Returns a [KinematicCollision3D], which contains information about a "
+"collision that occurred during the last [method move_and_slide] call. Since "
+"the body can collide several times in a single call to [method "
+"move_and_slide], you must specify the index of the collision in the range 0 "
+"to ([method get_slide_count] - 1)."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:87
+msgid ""
+"Moves the body along the vector [code]rel_vec[/code]. The body will stop if "
+"it collides. Returns a [KinematicCollision3D], which contains information "
+"about the collision.\n"
+"If [code]test_only[/code] is [code]true[/code], the body does not move but "
+"the would-be collision information is given."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:107
+msgid ""
+"Moves the body along a vector. If the body collides with another, it will "
+"slide along the other body rather than stop immediately. If the other body "
+"is a [KinematicBody3D] or [RigidBody3D], it will also be affected by the "
+"motion of the other body. You can use this to make moving or rotating "
+"platforms, or to make nodes push other nodes.\n"
+"This method should be used in [method Node._physics_process] (or in a method "
+"called by [method Node._physics_process]), as it uses the physics step's "
+"[code]delta[/code] value automatically in calculations. Otherwise, the "
+"simulation will run at an incorrect speed.\n"
+"[code]linear_velocity[/code] is the velocity vector (typically meters per "
+"second). Unlike in [method move_and_collide], you should [i]not[/i] multiply "
+"it by [code]delta[/code] — the physics engine handles applying the "
+"velocity. \n"
+"[code]up_direction[/code] is the up direction, used to determine what is a "
+"wall and what is a floor or a ceiling. If set to the default value of "
+"[code]Vector3(0, 0, 0)[/code], everything is considered a wall.\n"
+"If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on "
+"slopes if you include gravity in [code]linear_velocity[/code].\n"
+"If the body collides, it will change direction a maximum of "
+"[code]max_slides[/code] times before it stops.\n"
+"[code]floor_max_angle[/code] is the maximum angle (in radians) where a slope "
+"is still considered a floor (or a ceiling), rather than a wall. The default "
+"value equals 45 degrees.\n"
+"If [code]infinite_inertia[/code] is [code]true[/code], body will be able to "
+"push [RigidBody3D] nodes, but it won't also detect any collisions with them. "
+"If [code]false[/code], it will interact with [RigidBody3D] nodes like with "
+"[StaticBody3D].\n"
+"Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a "
+"slide collision occurred. To get detailed information about collisions that "
+"occurred, use [method get_slide_collision]."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:136
+msgid ""
+"Moves the body while keeping it attached to slopes. Similar to [method "
+"move_and_slide].\n"
+"As long as the [code]snap[/code] vector is in contact with the ground, the "
+"body will remain attached to the surface. This means you must disable snap "
+"in order to jump, for example. You can do this by setting [code]snap[/code] "
+"to [code](0, 0, 0)[/code] or by using [method move_and_slide] instead."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:148
+msgid ""
+"Locks or unlocks the specified [code]axis[/code] depending on the value of "
+"[code]lock[/code]. See also [member move_lock_x], [member move_lock_y] and "
+"[member move_lock_z]."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:161
+msgid ""
+"Checks for collisions without moving the body. Virtually sets the node's "
+"position, scale and rotation to that of the given [Transform], then tries to "
+"move the body along the vector [code]rel_vec[/code]. Returns [code]true[/"
+"code] if a collision would occur."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:170
+msgid "Lock the body's X axis movement."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:173
+msgid "Lock the body's Y axis movement."
+msgstr ""
+
+#: doc/classes/KinematicBody3D.xml:176
+msgid "Lock the body's Z axis movement."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:4
+msgid "Collision data for [KinematicBody2D] collisions."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:7
+msgid ""
+"Contains collision data for [KinematicBody2D] collisions. When a "
+"[KinematicBody2D] is moved using [method KinematicBody2D.move_and_collide], "
+"it stops if it detects a collision with another body. If a collision is "
+"detected, a KinematicCollision2D object is returned.\n"
+"This object contains information about the collision, including the "
+"colliding object, the remaining motion, and the collision position. This "
+"information can be used to calculate a collision response."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:16
+#: doc/classes/KinematicCollision3D.xml:16
+msgid "The colliding body."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:19
+#: doc/classes/KinematicCollision3D.xml:19
+msgid ""
+"The colliding body's unique instance ID. See [method Object.get_instance_id]."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:22
+#: doc/classes/KinematicCollision3D.xml:22
+msgid "The colliding body's metadata. See [Object]."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:25
+#: doc/classes/KinematicCollision3D.xml:25
+msgid "The colliding body's shape."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:28
+msgid "The colliding shape's index. See [CollisionObject2D]."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:31
+#: doc/classes/KinematicCollision3D.xml:31
+msgid "The colliding object's velocity."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:34
+#: doc/classes/KinematicCollision3D.xml:34
+msgid "The moving object's colliding shape."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:37
+#: doc/classes/KinematicCollision3D.xml:37
+msgid "The colliding body's shape's normal at the point of collision."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:40
+#: doc/classes/KinematicCollision3D.xml:40
+msgid "The point of collision, in global coordinates."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:43
+#: doc/classes/KinematicCollision3D.xml:43
+msgid "The moving object's remaining movement vector."
+msgstr ""
+
+#: doc/classes/KinematicCollision2D.xml:46
+#: doc/classes/KinematicCollision3D.xml:46
+msgid "The distance the moving object traveled before collision."
+msgstr ""
+
+#: doc/classes/KinematicCollision3D.xml:4
+msgid "Collision data for [KinematicBody3D] collisions."
+msgstr ""
+
+#: doc/classes/KinematicCollision3D.xml:7
+msgid ""
+"Contains collision data for [KinematicBody3D] collisions. When a "
+"[KinematicBody3D] is moved using [method KinematicBody3D.move_and_collide], "
+"it stops if it detects a collision with another body. If a collision is "
+"detected, a KinematicCollision3D object is returned.\n"
+"This object contains information about the collision, including the "
+"colliding object, the remaining motion, and the collision position. This "
+"information can be used to calculate a collision response."
+msgstr ""
+
+#: doc/classes/KinematicCollision3D.xml:28
+msgid "The colliding shape's index. See [CollisionObject3D]."
+msgstr ""
+
+#: doc/classes/Label.xml:4
+msgid ""
+"Displays plain text in a line or wrapped inside a rectangle. For formatted "
+"text, use [RichTextLabel]."
+msgstr ""
+
+#: doc/classes/Label.xml:7
+msgid ""
+"Label displays plain text on the screen. It gives you control over the "
+"horizontal and vertical alignment, and can wrap the text inside the node's "
+"bounding rectangle. It doesn't support bold, italics or other formatting. "
+"For that, use [RichTextLabel] instead.\n"
+"[b]Note:[/b] Contrarily to most other [Control]s, Label's [member Control."
+"mouse_filter] defaults to [constant Control.MOUSE_FILTER_IGNORE] (i.e. it "
+"doesn't react to mouse input events). This implies that a label won't "
+"display any configured [member Control.hint_tooltip], unless you change its "
+"mouse filter."
+msgstr ""
+
+#: doc/classes/Label.xml:17
+msgid "Returns the amount of lines of text the Label has."
+msgstr ""
+
+#: doc/classes/Label.xml:24
+msgid "Returns the font size in pixels."
+msgstr ""
+
+#: doc/classes/Label.xml:31
+msgid ""
+"Returns the total number of printable characters in the text (excluding "
+"spaces and newlines)."
+msgstr ""
+
+#: doc/classes/Label.xml:38
+msgid ""
+"Returns the number of lines shown. Useful if the [Label]'s height cannot "
+"currently display all lines."
+msgstr ""
+
+#: doc/classes/Label.xml:44
+msgid ""
+"Controls the text's horizontal align. Supports left, center, right, and "
+"fill, or justify. Set it to one of the [enum Align] constants."
+msgstr ""
+
+#: doc/classes/Label.xml:47
+msgid ""
+"If [code]true[/code], wraps the text inside the node's bounding rectangle. "
+"If you resize the node, it will change its height automatically to show all "
+"the text."
+msgstr ""
+
+#: doc/classes/Label.xml:50
+msgid ""
+"If [code]true[/code], the Label only shows the text that fits inside its "
+"bounding rectangle. It also lets you scale the node down freely."
+msgstr ""
+
+#: doc/classes/Label.xml:53
+msgid ""
+"The node ignores the first [code]lines_skipped[/code] lines before it starts "
+"to display text."
+msgstr ""
+
+#: doc/classes/Label.xml:56
+msgid "Limits the lines of text the node shows on screen."
+msgstr ""
+
+#: doc/classes/Label.xml:60
+msgid ""
+"Limits the count of visible characters. If you set [code]percent_visible[/"
+"code] to 50, only up to half of the text's characters will display on "
+"screen. Useful to animate the text in a dialog box."
+msgstr ""
+
+#: doc/classes/Label.xml:64
+msgid "The text to display on screen."
+msgstr ""
+
+#: doc/classes/Label.xml:67
+msgid "If [code]true[/code], all the text displays as UPPERCASE."
+msgstr ""
+
+#: doc/classes/Label.xml:70
+msgid ""
+"Controls the text's vertical align. Supports top, center, bottom, and fill. "
+"Set it to one of the [enum VAlign] constants."
+msgstr ""
+
+#: doc/classes/Label.xml:73
+msgid "Restricts the number of characters to display. Set to -1 to disable."
+msgstr ""
+
+#: doc/classes/Label.xml:78
+msgid "Align rows to the left (default)."
+msgstr ""
+
+#: doc/classes/Label.xml:81
+msgid "Align rows centered."
+msgstr ""
+
+#: doc/classes/Label.xml:84
+msgid "Align rows to the right."
+msgstr ""
+
+#: doc/classes/Label.xml:87
+msgid "Expand row whitespaces to fit the width."
+msgstr ""
+
+#: doc/classes/Label.xml:90
+msgid "Align the whole text to the top."
+msgstr ""
+
+#: doc/classes/Label.xml:93
+msgid "Align the whole text to the center."
+msgstr ""
+
+#: doc/classes/Label.xml:96
+msgid "Align the whole text to the bottom."
+msgstr ""
+
+#: doc/classes/Label.xml:99
+msgid "Align the whole text by spreading the rows."
+msgstr ""
+
+#: doc/classes/Label.xml:104
+msgid "[Font] used for the [Label]'s text."
+msgstr ""
+
+#: doc/classes/Label.xml:107
+msgid "Default text [Color] of the [Label]."
+msgstr ""
+
+#: doc/classes/Label.xml:110
+msgid "[Color] of the text's shadow effect."
+msgstr ""
+
+#: doc/classes/Label.xml:113
+msgid "The tint of [Font]'s outline. See [member DynamicFont.outline_color]."
+msgstr ""
+
+#: doc/classes/Label.xml:116
+msgid "Vertical space between lines in multiline [Label]."
+msgstr ""
+
+#: doc/classes/Label.xml:119
+msgid "Background [StyleBox] for the [Label]."
+msgstr ""
+
+#: doc/classes/Label.xml:122
+msgid ""
+"Boolean value. If set to 1 ([code]true[/code]), the shadow will be displayed "
+"around the whole text as an outline."
+msgstr ""
+
+#: doc/classes/Label.xml:125
+msgid "The horizontal offset of the text's shadow."
+msgstr ""
+
+#: doc/classes/Label.xml:128
+msgid "The vertical offset of the text's shadow."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:4
+msgid "A [Texture2D] capable of storing many smaller textures with offsets."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:7
+msgid ""
+"A [Texture2D] capable of storing many smaller textures with offsets.\n"
+"You can dynamically add pieces ([Texture2D]s) to this [LargeTexture] using "
+"different offsets."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:21
+msgid ""
+"Adds [code]texture[/code] to this [LargeTexture], starting on offset "
+"[code]ofs[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:28
+msgid "Clears the [LargeTexture]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:35
+msgid "Returns the number of pieces currently in this [LargeTexture]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:44
+msgid "Returns the offset of the piece with the index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:53
+msgid "Returns the [Texture2D] of the piece with the index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:64
+msgid ""
+"Sets the offset of the piece with the index [code]idx[/code] to [code]ofs[/"
+"code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:75
+msgid ""
+"Sets the [Texture2D] of the piece with index [code]idx[/code] to "
+"[code]texture[/code]."
+msgstr ""
+
+#: doc/classes/LargeTexture.xml:84
+msgid "Sets the size of this [LargeTexture]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:4
+msgid "Casts light in a 2D environment."
+msgstr ""
+
+#: doc/classes/Light2D.xml:7
+msgid ""
+"Casts light in a 2D environment. Light is defined by a (usually grayscale) "
+"texture, a color, an energy value, a mode (see constants), and various other "
+"parameters (range and shadows-related).\n"
+"[b]Note:[/b] Light2D can also be used as a mask."
+msgstr ""
+
+#: doc/classes/Light2D.xml:11 doc/classes/LightOccluder2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/2d/2d_lights_and_shadows."
+"html"
+msgstr ""
+
+#: doc/classes/Light2D.xml:17
+msgid "The Light2D's [Color]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:20
+msgid "If [code]true[/code], Light2D will only appear when editing the scene."
+msgstr ""
+
+#: doc/classes/Light2D.xml:23
+msgid "If [code]true[/code], Light2D will emit light."
+msgstr ""
+
+#: doc/classes/Light2D.xml:26
+msgid ""
+"The Light2D's energy value. The larger the value, the stronger the light."
+msgstr ""
+
+#: doc/classes/Light2D.xml:29
+msgid "The Light2D's mode. See [enum Mode] constants for values."
+msgstr ""
+
+#: doc/classes/Light2D.xml:32
+msgid "The offset of the Light2D's [code]texture[/code]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:35
+msgid "The height of the Light2D. Used with 2D normal mapping."
+msgstr ""
+
+#: doc/classes/Light2D.xml:38
+msgid ""
+"The layer mask. Only objects with a matching mask will be affected by the "
+"Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:41
+msgid "Maximum layer value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:44
+msgid "Minimum layer value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:47
+msgid ""
+"Maximum [code]z[/code] value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:50
+msgid ""
+"Minimum [code]z[/code] value of objects that are affected by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:53
+msgid "Shadow buffer size."
+msgstr ""
+
+#: doc/classes/Light2D.xml:56
+msgid "[Color] of shadows cast by the Light2D."
+msgstr ""
+
+#: doc/classes/Light2D.xml:59
+msgid "If [code]true[/code], the Light2D will cast shadows."
+msgstr ""
+
+#: doc/classes/Light2D.xml:62
+msgid "Shadow filter type. See [enum ShadowFilter] for possible values."
+msgstr ""
+
+#: doc/classes/Light2D.xml:65
+msgid "Smoothing value for shadows."
+msgstr ""
+
+#: doc/classes/Light2D.xml:68
+msgid ""
+"The shadow mask. Used with [LightOccluder2D] to cast shadows. Only occluders "
+"with a matching light mask will cast shadows."
+msgstr ""
+
+#: doc/classes/Light2D.xml:71
+msgid "[Texture2D] used for the Light2D's appearance."
+msgstr ""
+
+#: doc/classes/Light2D.xml:74
+msgid "The [code]texture[/code]'s scale factor."
+msgstr ""
+
+#: doc/classes/Light2D.xml:79
+msgid ""
+"Adds the value of pixels corresponding to the Light2D to the values of "
+"pixels under it. This is the common behavior of a light."
+msgstr ""
+
+#: doc/classes/Light2D.xml:82
+msgid ""
+"Subtracts the value of pixels corresponding to the Light2D to the values of "
+"pixels under it, resulting in inversed light effect."
+msgstr ""
+
+#: doc/classes/Light2D.xml:85
+msgid ""
+"Mix the value of pixels corresponding to the Light2D to the values of pixels "
+"under it by linear interpolation."
+msgstr ""
+
+#: doc/classes/Light2D.xml:88
+msgid ""
+"The light texture of the Light2D is used as a mask, hiding or revealing "
+"parts of the screen underneath depending on the value of each pixel of the "
+"light (mask) texture."
+msgstr ""
+
+#: doc/classes/Light2D.xml:91
+msgid "No filter applies to the shadow map. See [member shadow_filter]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:94
+msgid ""
+"Percentage closer filtering (5 samples) applies to the shadow map. See "
+"[member shadow_filter]."
+msgstr ""
+
+#: doc/classes/Light2D.xml:97
+msgid ""
+"Percentage closer filtering (13 samples) applies to the shadow map. See "
+"[member shadow_filter]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:4
+msgid "Provides a base class for different kinds of light nodes."
+msgstr ""
+
+#: doc/classes/Light3D.xml:7
+msgid ""
+"Light3D is the abstract base class for light nodes, so it shouldn't be used "
+"directly (it can't be instanced). Other types of light nodes inherit from "
+"it. Light3D contains the common variables and parameters used for lighting."
+msgstr ""
+
+#: doc/classes/Light3D.xml:19
+msgid "Returns the value of the specified [enum Light3D.Param] parameter."
+msgstr ""
+
+#: doc/classes/Light3D.xml:30
+msgid "Sets the value of the specified [enum Light3D.Param] parameter."
+msgstr ""
+
+#: doc/classes/Light3D.xml:36
+msgid ""
+"If [code]true[/code], the light only appears in the editor and will not be "
+"visible at runtime."
+msgstr ""
+
+#: doc/classes/Light3D.xml:39
+msgid "The light's bake mode. See [enum BakeMode]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:42
+msgid "The light's color."
+msgstr ""
+
+#: doc/classes/Light3D.xml:45
+msgid "The light will affect objects in the selected layers."
+msgstr ""
+
+#: doc/classes/Light3D.xml:48
+msgid "The light's strength multiplier."
+msgstr ""
+
+#: doc/classes/Light3D.xml:51
+msgid ""
+"Secondary multiplier used with indirect light (light bounces). Used with "
+"[GIProbe]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:54
+msgid ""
+"If [code]true[/code], the light's effect is reversed, darkening areas and "
+"casting bright shadows."
+msgstr ""
+
+#: doc/classes/Light3D.xml:57
+msgid ""
+"The intensity of the specular blob in objects affected by the light. At "
+"[code]0[/code] the light becomes a pure diffuse light."
+msgstr ""
+
+#: doc/classes/Light3D.xml:60
+msgid ""
+"Used to adjust shadow appearance. Too small a value results in self-"
+"shadowing, while too large a value causes shadows to separate from casters. "
+"Adjust as needed."
+msgstr ""
+
+#: doc/classes/Light3D.xml:63
+msgid "The color of shadows cast by this light."
+msgstr ""
+
+#: doc/classes/Light3D.xml:66
+msgid "Attempts to reduce [member shadow_bias] gap."
+msgstr ""
+
+#: doc/classes/Light3D.xml:69
+msgid "If [code]true[/code], the light will cast shadows."
+msgstr ""
+
+#: doc/classes/Light3D.xml:72
+msgid ""
+"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 [constant GeometryInstance3D."
+"SHADOW_CASTING_SETTING_DOUBLE_SIDED]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:77
+msgid "Constant for accessing [member light_energy]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:80
+msgid "Constant for accessing [member light_indirect_energy]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:83
+msgid "Constant for accessing [member light_specular]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:86
+msgid ""
+"Constant for accessing [member OmniLight3D.omni_range] or [member "
+"SpotLight3D.spot_range]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:89
+msgid ""
+"Constant for accessing [member OmniLight3D.omni_attenuation] or [member "
+"SpotLight3D.spot_attenuation]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:92
+msgid "Constant for accessing [member SpotLight3D.spot_angle]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:95
+msgid "Constant for accessing [member SpotLight3D.spot_angle_attenuation]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:98
+msgid "Constant for accessing [member shadow_contact]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:101
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_max_distance]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:104
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_split_1]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:107
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_split_2]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:110
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_split_3]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:115
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_normal_bias]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:118
+msgid "Constant for accessing [member shadow_bias]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:121
+msgid ""
+"Constant for accessing [member DirectionalLight3D."
+"directional_shadow_bias_split_scale]."
+msgstr ""
+
+#: doc/classes/Light3D.xml:127
+msgid ""
+"Light is ignored when baking.\n"
+"[b]Note:[/b] Hiding a light does [i]not[/i] affect baking."
+msgstr ""
+
+#: doc/classes/Light3D.xml:131
+msgid "Only indirect lighting will be baked (default)."
+msgstr ""
+
+#: doc/classes/Light3D.xml:134
+msgid ""
+"Both direct and indirect light will be baked.\n"
+"[b]Note:[/b] You should hide the light if you don't want it to appear twice "
+"(dynamic and baked)."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:4
+msgid "Occludes light cast by a Light2D, casting shadows."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:7
+msgid ""
+"Occludes light cast by a Light2D, casting shadows. The LightOccluder2D must "
+"be provided with an [OccluderPolygon2D] in order for the shadow to be "
+"computed."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:16
+msgid ""
+"The LightOccluder2D's light mask. The LightOccluder2D will cast shadows only "
+"from Light2D(s) that have the same light mask(s)."
+msgstr ""
+
+#: doc/classes/LightOccluder2D.xml:19
+msgid "The [OccluderPolygon2D] used to compute the shadow."
+msgstr ""
+
+#: doc/classes/Line2D.xml:4
+msgid "A 2D line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:7
+msgid "A line through several points in 2D space."
+msgstr ""
+
+#: doc/classes/Line2D.xml:20
+msgid ""
+"Adds a point at the [code]position[/code]. Appends the point at the end of "
+"the line.\n"
+"If [code]at_position[/code] is given, the point is inserted before the point "
+"number [code]at_position[/code], moving that point (and every point after) "
+"after the inserted point. If [code]at_position[/code] is not given, or is an "
+"illegal value ([code]at_position < 0[/code] or [code]at_position >= [method "
+"get_point_count][/code]), the point will be appended at the end of the point "
+"list."
+msgstr ""
+
+#: doc/classes/Line2D.xml:28
+msgid "Removes all points from the line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:35
+msgid "Returns the Line2D's amount of points."
+msgstr ""
+
+#: doc/classes/Line2D.xml:44
+msgid "Returns point [code]i[/code]'s position."
+msgstr ""
+
+#: doc/classes/Line2D.xml:53
+msgid "Removes the point at index [code]i[/code] from the line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:64
+msgid ""
+"Overwrites the position in point [code]i[/code] with the supplied "
+"[code]position[/code]."
+msgstr ""
+
+#: doc/classes/Line2D.xml:70
+msgid "If [code]true[/code], the line's border will be anti-aliased."
+msgstr ""
+
+#: doc/classes/Line2D.xml:73
+msgid ""
+"Controls the style of the line's first point. Use [enum LineCapMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/Line2D.xml:76
+msgid "The line's color. Will not be used if a gradient is set."
+msgstr ""
+
+#: doc/classes/Line2D.xml:79
+msgid ""
+"Controls the style of the line's last point. Use [enum LineCapMode] "
+"constants."
+msgstr ""
+
+#: doc/classes/Line2D.xml:82
+msgid ""
+"The gradient is drawn through the whole line from start to finish. The "
+"default color will not be used if a gradient is set."
+msgstr ""
+
+#: doc/classes/Line2D.xml:85
+msgid "The style for the points between the start and the end."
+msgstr ""
+
+#: doc/classes/Line2D.xml:88
+msgid ""
+"The points that form the lines. The line is drawn between every point set in "
+"this array."
+msgstr ""
+
+#: doc/classes/Line2D.xml:91
+msgid ""
+"The smoothness of the rounded joints and caps. This is only used if a cap or "
+"joint is set as round."
+msgstr ""
+
+#: doc/classes/Line2D.xml:94
+msgid ""
+"The direction difference in radians between vector points. This value is "
+"only used if [code]joint mode[/code] is set to [constant LINE_JOINT_SHARP]."
+msgstr ""
+
+#: doc/classes/Line2D.xml:97
+msgid ""
+"The texture used for the line's texture. Uses [code]texture_mode[/code] for "
+"drawing style."
+msgstr ""
+
+#: doc/classes/Line2D.xml:100
+msgid ""
+"The style to render the [code]texture[/code] on the line. Use [enum "
+"LineTextureMode] constants."
+msgstr ""
+
+#: doc/classes/Line2D.xml:103
+msgid "The line's width."
+msgstr ""
+
+#: doc/classes/Line2D.xml:106
+msgid ""
+"The line's width varies with the curve. The original width is simply "
+"multiply by the value of the Curve."
+msgstr ""
+
+#: doc/classes/Line2D.xml:111
+msgid ""
+"The line's joints will be pointy. If [code]sharp_limit[/code] is greater "
+"than the rotation of a joint, it becomes a bevel joint instead."
+msgstr ""
+
+#: doc/classes/Line2D.xml:114
+msgid "The line's joints will be bevelled/chamfered."
+msgstr ""
+
+#: doc/classes/Line2D.xml:117
+msgid "The line's joints will be rounded."
+msgstr ""
+
+#: doc/classes/Line2D.xml:120
+msgid "Don't draw a line cap."
+msgstr ""
+
+#: doc/classes/Line2D.xml:123
+msgid "Draws the line cap as a box."
+msgstr ""
+
+#: doc/classes/Line2D.xml:126
+msgid "Draws the line cap as a circle."
+msgstr ""
+
+#: doc/classes/Line2D.xml:129
+msgid ""
+"Takes the left pixels of the texture and renders it over the whole line."
+msgstr ""
+
+#: doc/classes/Line2D.xml:132
+msgid ""
+"Tiles the texture over the line. The texture must be imported with "
+"[b]Repeat[/b] enabled for it to work properly."
+msgstr ""
+
+#: doc/classes/Line2D.xml:135
+msgid ""
+"Stretches the texture across the line. Import the texture with [b]Repeat[/b] "
+"disabled for best results."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:4
+msgid "Control that provides single-line string editing."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:7
+msgid ""
+"LineEdit provides a single-line string editor, used for text fields.\n"
+"It features many built-in shortcuts which will always be available "
+"([code]Ctrl[/code] here maps to [code]Command[/code] on macOS):\n"
+"- Ctrl + C: Copy\n"
+"- Ctrl + X: Cut\n"
+"- Ctrl + V or Ctrl + Y: Paste/\"yank\"\n"
+"- Ctrl + Z: Undo\n"
+"- Ctrl + Shift + Z: Redo\n"
+"- Ctrl + U: Delete text from the cursor position to the beginning of the "
+"line\n"
+"- Ctrl + K: Delete text from the cursor position to the end of the line\n"
+"- Ctrl + A: Select all text\n"
+"- Up/Down arrow: Move the cursor to the beginning/end of the line\n"
+"On macOS, some extra keyboard shortcuts are available:\n"
+"- Ctrl + F: Like the right arrow key, move the cursor one character right\n"
+"- Ctrl + B: Like the left arrow key, move the cursor one character left\n"
+"- Ctrl + P: Like the up arrow key, move the cursor to the previous line\n"
+"- Ctrl + N: Like the down arrow key, move the cursor to the next line\n"
+"- Ctrl + D: Like the Delete key, delete the character on the right side of "
+"cursor\n"
+"- Ctrl + H: Like the Backspace key, delete the character on the left side of "
+"the cursor\n"
+"- Ctrl + A: Like the Home key, move the cursor to the beginning of the line\n"
+"- Ctrl + E: Like the End key, move the cursor to the end of the line\n"
+"- Command + Left arrow: Like the Home key, move the cursor to the beginning "
+"of the line\n"
+"- Command + Right arrow: Like the End key, move the cursor to the end of the "
+"line"
+msgstr ""
+
+#: doc/classes/LineEdit.xml:39
+msgid ""
+"Adds [code]text[/code] after the cursor. If the resulting value is longer "
+"than [member max_length], nothing happens."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:46
+msgid "Erases the [LineEdit] text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:53
+msgid "Clears the current selection."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:60
+msgid ""
+"Returns the [PopupMenu] of this [LineEdit]. By default, this menu is "
+"displayed when right-clicking on the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:69
+msgid "Executes a given action as defined in the [enum MenuItems] enum."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:80
+msgid ""
+"Selects characters inside [LineEdit] between [code]from[/code] and [code]to[/"
+"code]. By default, [code]from[/code] is at the beginning and [code]to[/code] "
+"at the end.\n"
+"[codeblock]\n"
+"text = \"Welcome\"\n"
+"select() # Will select \"Welcome\".\n"
+"select(4) # Will select \"ome\".\n"
+"select(2, 5) # Will select \"lco\".\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/LineEdit.xml:93
+msgid "Selects the whole [String]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:99
+msgid "Text alignment as defined in the [enum Align] enum."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:102 doc/classes/TextEdit.xml:395
+msgid "If [code]true[/code], the caret (visual cursor) blinks."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:105 doc/classes/TextEdit.xml:398
+msgid "Duration (in seconds) of a caret's blinking cycle."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:108
+msgid ""
+"The cursor's position inside the [LineEdit]. When set, the text may scroll "
+"to accommodate it."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:111
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:114
+msgid "If [code]true[/code], the context menu will appear when right-clicked."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:117
+msgid ""
+"If [code]false[/code], existing text cannot be modified and new text cannot "
+"be added."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:120
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:124
+msgid ""
+"Maximum amount of characters that can be entered inside the [LineEdit]. If "
+"[code]0[/code], there is no limit."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:128
+msgid ""
+"Opacity of the [member placeholder_text]. From [code]0[/code] to [code]1[/"
+"code]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:131
+msgid ""
+"Text shown when the [LineEdit] is empty. It is [b]not[/b] the [LineEdit]'s "
+"default value (see [member text])."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:134
+msgid ""
+"Sets the icon that will appear in the right end of the [LineEdit] if there's "
+"no [member text], or always, if [member clear_button_enabled] is set to "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:137
+msgid ""
+"If [code]true[/code], every character is replaced with the secret character "
+"(see [member secret_character])."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:140
+msgid ""
+"The character to use to mask secret input (defaults to \"*\"). Only a single "
+"character can be used as the secret character."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:143
+msgid ""
+"If [code]false[/code], it's impossible to select the text using mouse nor "
+"keyboard."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:146
+msgid "If [code]false[/code], using shortcuts will be disabled."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:149
+msgid ""
+"String value of the [LineEdit].\n"
+"[b]Note:[/b] Changing text using this property won't emit the [signal "
+"text_changed] signal."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:156
+msgid ""
+"Emitted when trying to append text that would overflow the [member "
+"max_length]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:163 doc/classes/TextEdit.xml:513
+msgid "Emitted when the text changes."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:170
+msgid "Emitted when the user presses [constant KEY_ENTER] on the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:176
+msgid "Aligns the text on the left-hand side of the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:179
+msgid "Centers the text in the middle of the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:182
+msgid "Aligns the text on the right-hand side of the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:185
+msgid "Stretches whitespaces to fit the [LineEdit]'s width."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:188 doc/classes/TextEdit.xml:534
+msgid "Cuts (copies and clears) the selected text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:191 doc/classes/TextEdit.xml:537
+msgid "Copies the selected text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:194
+msgid ""
+"Pastes the clipboard text over the selected text (or at the cursor's "
+"position).\n"
+"Non-printable escape characters are automatically stripped from the OS "
+"clipboard via [method String.strip_escapes]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:198
+msgid "Erases the whole [LineEdit] text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:201
+msgid "Selects the whole [LineEdit] text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:204 doc/classes/TextEdit.xml:549
+msgid "Undoes the previous action."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:207
+msgid "Reverse the last undo action."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:210 doc/classes/TextEdit.xml:555
+msgid "Represents the size of the [enum MenuItems] enum."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:215
+msgid "Texture for the clear button. See [member clear_button_enabled]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:218
+msgid "Color used as default tint for the clear button."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:221
+msgid "Color used for the clear button when it's pressed."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:224
+msgid "Color of the [LineEdit]'s visual cursor (caret)."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:227
+msgid "Background used when [LineEdit] has GUI focus."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:230
+msgid "Font used for the text."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:233
+msgid "Default font color."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:236
+msgid "Font color for selected text (inside the selection rectangle)."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:239
+msgid "Font color when editing is disabled."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:242
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:245
+msgid "Default background for the [LineEdit]."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:248
+msgid ""
+"Background used when [LineEdit] is in read-only mode ([member editable] is "
+"set to [code]false[/code])."
+msgstr ""
+
+#: doc/classes/LineEdit.xml:251
+msgid "Color of the selection rectangle."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:4
+msgid "Line shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:7
+msgid ""
+"Line shape for 2D collisions. It works like a 2D plane and will not allow "
+"any physics body to go to the negative side. Not recommended for rigid "
+"bodies, and usually not recommended for static bodies either because it "
+"forces checks against it on every frame."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:15
+msgid "The line's distance from the origin."
+msgstr ""
+
+#: doc/classes/LineShape2D.xml:18
+msgid "The line's normal."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:4
+msgid "Simple button used to represent a link to some resource."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:7
+msgid ""
+"This kind of button is primarily used when the interaction with the button "
+"causes a context change (like linking to a web page)."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:21
+msgid ""
+"Determines when to show the underline. See [enum UnderlineMode] for options."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:26
+msgid "The LinkButton will always show an underline at the bottom of its text."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:29
+msgid ""
+"The LinkButton will show an underline at the bottom of its text when the "
+"mouse cursor is over it."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:32
+msgid "The LinkButton will never show an underline at the bottom of its text."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:37
+msgid ""
+"[StyleBox] used when the [LinkButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:40
+msgid "[Font] of the [LinkButton]'s text."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:43
+msgid "Default text [Color] of the [LinkButton]."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:46
+msgid "Text [Color] used when the [LinkButton] is being hovered."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:49
+msgid "Text [Color] used when the [LinkButton] is being pressed."
+msgstr ""
+
+#: doc/classes/LinkButton.xml:52
+msgid "The vertical space between the baseline of text and the underline."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:4
+msgid "Overrides the location sounds are heard from."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:7
+msgid ""
+"Once added to the scene tree and enabled using [method make_current], this "
+"node will override the location sounds are heard from. This can be used to "
+"listen from a location different from the [Camera3D].\n"
+"[b]Note:[/b] There is no 2D equivalent for this node yet."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:17
+msgid "Disables the listener to use the current camera's listener instead."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:24
+msgid "Returns the listener's global orthonormalized [Transform]."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:31
+msgid ""
+"Returns [code]true[/code] if the listener was made current using [method "
+"make_current], [code]false[/code] otherwise.\n"
+"[b]Note:[/b] There may be more than one Listener3D marked as \"current\" in "
+"the scene tree, but only the one that was made current last will be used."
+msgstr ""
+
+#: doc/classes/Listener3D.xml:39
+msgid "Enables the listener. This will override the current camera's listener."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:4
+msgid "Abstract base class for the game's main loop."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:7
+msgid ""
+"[MainLoop] is the abstract base class for a Godot project's game loop. It is "
+"inherited by [SceneTree], which is the default game loop implementation used "
+"in Godot projects, though it is also possible to write and use one's own "
+"[MainLoop] subclass instead of the scene tree.\n"
+"Upon the application start, a [MainLoop] implementation must be provided to "
+"the OS; otherwise, the application will exit. This happens automatically "
+"(and a [SceneTree] is created) unless a main [Script] is provided from the "
+"command line (with e.g. [code]godot -s my_loop.gd[/code], which should then "
+"be a [MainLoop] implementation.\n"
+"Here is an example script implementing a simple [MainLoop]:\n"
+"[b]FIXME:[/b] No longer valid after DisplayServer split and Input "
+"refactoring.\n"
+"[codeblock]\n"
+"extends MainLoop\n"
+"\n"
+"var time_elapsed = 0\n"
+"var keys_typed = []\n"
+"var quit = false\n"
+"\n"
+"func _initialize():\n"
+" print(\"Initialized:\")\n"
+" print(\" Starting time: %s\" % str(time_elapsed))\n"
+"\n"
+"func _idle(delta):\n"
+" time_elapsed += delta\n"
+" # Return true to end the main loop.\n"
+" return quit\n"
+"\n"
+"func _input_event(event):\n"
+" # Record keys.\n"
+" if event is InputEventKey and event.pressed and !event.echo:\n"
+" keys_typed.append(OS.get_keycode_string(event.keycode))\n"
+" # Quit on Escape press.\n"
+" if event.keycode == KEY_ESCAPE:\n"
+" quit = true\n"
+" # Quit on any mouse click.\n"
+" if event is InputEventMouseButton:\n"
+" quit = true\n"
+"\n"
+"func _finalize():\n"
+" print(\"Finalized:\")\n"
+" print(\" End time: %s\" % str(time_elapsed))\n"
+" print(\" Keys typed: %s\" % var2str(keys_typed))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/MainLoop.xml:51
+msgid "Called before the program exits."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:60
+msgid ""
+"Called each idle frame with the time since the last idle frame as argument "
+"(in seconds). Equivalent to [method Node._process].\n"
+"If implemented, the method must return a boolean value. [code]true[/code] "
+"ends the main loop, while [code]false[/code] lets it proceed to the next "
+"frame."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:68
+msgid "Called once during initialization."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:77
+msgid ""
+"Called each physics frame with the time since the last physics frame as "
+"argument (in seconds). Equivalent to [method Node._physics_process].\n"
+"If implemented, the method must return a boolean value. [code]true[/code] "
+"ends the main loop, while [code]false[/code] lets it proceed to the next "
+"frame."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:85
+msgid ""
+"Should not be called manually, override [method _finalize] instead. Will be "
+"removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:94
+msgid ""
+"Should not be called manually, override [method _idle] instead. Will be "
+"removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:101
+msgid ""
+"Should not be called manually, override [method _initialize] instead. Will "
+"be removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:110
+msgid ""
+"Should not be called manually, override [method _iteration] instead. Will be "
+"removed in Godot 4.0."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:121
+msgid "Emitted when a user responds to a permission request."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:127 doc/classes/Node.xml:945
+msgid ""
+"Notification received from the OS when the application is exceeding its "
+"allocated memory.\n"
+"Specific to the iOS platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:131 doc/classes/Node.xml:949
+msgid ""
+"Notification received when translations may have changed. Can be triggered "
+"by the user changing the locale. Can be used to respond to language changes, "
+"for example to change the UI strings on the fly. Useful when working with "
+"the built-in translation support, like [method Object.tr]."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:134 doc/classes/Node.xml:952
+msgid ""
+"Notification received from the OS when a request for \"About\" information "
+"is sent.\n"
+"Specific to the macOS platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:138 doc/classes/Node.xml:956
+msgid ""
+"Notification received from Godot's crash handler when the engine is about to "
+"crash.\n"
+"Implemented on desktop platforms if the crash handler is enabled."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:142 doc/classes/Node.xml:960
+msgid ""
+"Notification received from the OS when an update of the Input Method Engine "
+"occurs (e.g. change of IME cursor position or composition string).\n"
+"Specific to the macOS platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:146 doc/classes/Node.xml:964
+msgid ""
+"Notification received from the OS when the app is resumed.\n"
+"Specific to the Android platform."
+msgstr ""
+
+#: doc/classes/MainLoop.xml:150 doc/classes/Node.xml:968
+msgid ""
+"Notification received from the OS when the app is paused.\n"
+"Specific to the Android platform."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:4
+msgid "Simple margin container."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:7
+msgid ""
+"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.\n"
+"[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:\n"
+"[codeblock]\n"
+"var margin_value = 100\n"
+"set(\"custom_constants/margin_top\", margin_value)\n"
+"set(\"custom_constants/margin_left\", margin_value)\n"
+"set(\"custom_constants/margin_bottom\", margin_value)\n"
+"set(\"custom_constants/margin_right\", margin_value)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:25
+msgid ""
+"All direct children of [MarginContainer] will have a bottom margin of "
+"[code]margin_bottom[/code] pixels."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:28
+msgid ""
+"All direct children of [MarginContainer] will have a left margin of "
+"[code]margin_left[/code] pixels."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:31
+msgid ""
+"All direct children of [MarginContainer] will have a right margin of "
+"[code]margin_right[/code] pixels."
+msgstr ""
+
+#: doc/classes/MarginContainer.xml:34
+msgid ""
+"All direct children of [MarginContainer] will have a top margin of "
+"[code]margin_top[/code] pixels."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:4
+msgid "Data transformation (marshalling) and encoding helpers."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:7
+msgid "Provides data transformation and encoding utility functions."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:18
+msgid ""
+"Returns a decoded [PackedByteArray] corresponding to the Base64-encoded "
+"string [code]base64_str[/code]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:27
+msgid ""
+"Returns a decoded string corresponding to the Base64-encoded string "
+"[code]base64_str[/code]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:38
+msgid ""
+"Returns a decoded [Variant] corresponding to the Base64-encoded string "
+"[code]base64_str[/code]. If [code]allow_objects[/code] is [code]true[/code], "
+"decoding objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:48
+msgid "Returns a Base64-encoded string of a given [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:57
+msgid ""
+"Returns a Base64-encoded string of the UTF-8 string [code]utf8_str[/code]."
+msgstr ""
+
+#: doc/classes/Marshalls.xml:68
+msgid ""
+"Returns a Base64-encoded string of the [Variant] [code]variant[/code]. If "
+"[code]full_objects[/code] is [code]true[/code], encoding objects is allowed "
+"(and can potentially include code)."
+msgstr ""
+
+#: doc/classes/Material.xml:4
+msgid "Abstract base [Resource] for coloring and shading geometry."
+msgstr ""
+
+#: doc/classes/Material.xml:7
+msgid ""
+"Material is a base [Resource] used for coloring and shading geometry. All "
+"materials inherit from it and almost all [VisualInstance3D] derived nodes "
+"carry a Material. A few flags and parameters are shared between all material "
+"types and are configured here."
+msgstr ""
+
+#: doc/classes/Material.xml:15
+msgid ""
+"Sets the [Material] to be used for the next pass. This renders the object "
+"again using a different material.\n"
+"[b]Note:[/b] only applies to [StandardMaterial3D]s and [ShaderMaterial]s "
+"with type \"Spatial\"."
+msgstr ""
+
+#: doc/classes/Material.xml:19
+msgid ""
+"Sets the render priority for transparent objects in 3D scenes. Higher "
+"priority objects will be sorted in front of lower priority objects.\n"
+"[b]Note:[/b] this only applies to sorting of transparent objects. This will "
+"not impact how transparent objects are sorted relative to opaque objects. "
+"This is because opaque objects are sorted based on depth, while transparent "
+"objects are sorted from back to front (subject to priority)."
+msgstr ""
+
+#: doc/classes/Material.xml:25
+msgid "Maximum value for the [member render_priority] parameter."
+msgstr ""
+
+#: doc/classes/Material.xml:28
+msgid "Minimum value for the [member render_priority] parameter."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:4
+msgid "Special button that brings up a [PopupMenu] when clicked."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:7
+msgid ""
+"Special button that brings up a [PopupMenu] when clicked.\n"
+"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."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:17 doc/classes/OptionButton.xml:106
+msgid "Returns the [PopupMenu] contained in this button."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:26
+msgid ""
+"If [code]true[/code], shortcuts are disabled and cannot be used to trigger "
+"the button."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:36
+msgid ""
+"If [code]true[/code], when the cursor hovers above another [MenuButton] "
+"within the same parent which also has [code]switch_on_hover[/code] enabled, "
+"it will close the current [MenuButton] and open the other one."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:43
+msgid "Emitted when the [PopupMenu] of this MenuButton is about to show."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:51
+msgid "[StyleBox] used when the [MenuButton] is disabled."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:54
+msgid ""
+"[StyleBox] used when the [MenuButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:57
+msgid "[Font] of the [MenuButton]'s text."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:60
+msgid "Default text [Color] of the [MenuButton]."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:63
+msgid "Text [Color] used when the [MenuButton] is disabled."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:66
+msgid "Text [Color] used when the [MenuButton] is being hovered."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:69
+msgid "Text [Color] used when the [MenuButton] is being pressed."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:72
+msgid "[StyleBox] used when the [MenuButton] is being hovered."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:75
+msgid "The horizontal space between [MenuButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:78
+msgid "Default [StyleBox] for the [MenuButton]."
+msgstr ""
+
+#: doc/classes/MenuButton.xml:81
+msgid "[StyleBox] used when the [MenuButton] is being pressed."
+msgstr ""
+
+#: doc/classes/Mesh.xml:4
+msgid "A [Resource] that contains vertex array-based geometry."
+msgstr ""
+
+#: doc/classes/Mesh.xml:7
+msgid ""
+"Mesh is a type of [Resource] that contains vertex array-based geometry, "
+"divided in [i]surfaces[/i]. Each surface contains a completely separate "
+"array and a material used to draw it. Design wise, a mesh with multiple "
+"surfaces is preferred to a single surface, because objects created in 3D "
+"editing software commonly contain multiple materials."
+msgstr ""
+
+#: doc/classes/Mesh.xml:16
+msgid "Calculate a [ConvexPolygonShape3D] from the mesh."
+msgstr ""
+
+#: doc/classes/Mesh.xml:25
+msgid ""
+"Calculate an outline mesh at a defined offset (margin) from the original "
+"mesh.\n"
+"[b]Note:[/b] This method typically returns the vertices in reverse order (e."
+"g. clockwise to counterclockwise)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:33
+msgid "Calculate a [ConcavePolygonShape3D] from the mesh."
+msgstr ""
+
+#: doc/classes/Mesh.xml:40
+msgid "Generate a [TriangleMesh] from the mesh."
+msgstr ""
+
+#: doc/classes/Mesh.xml:47
+msgid ""
+"Returns the smallest [AABB] enclosing this mesh. Not affected by "
+"[code]custom_aabb[/code].\n"
+"[b]Note:[/b] This is only implemented for [ArrayMesh] and [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/Mesh.xml:55
+msgid ""
+"Returns all the vertices that make up the faces of the mesh. Each three "
+"vertices represent one triangle."
+msgstr ""
+
+#: doc/classes/Mesh.xml:62
+msgid "Returns the amount of surfaces that the [Mesh] holds."
+msgstr ""
+
+#: doc/classes/Mesh.xml:71
+msgid ""
+"Returns the arrays for the vertices, normals, uvs, etc. that make up the "
+"requested surface (see [method ArrayMesh.add_surface_from_arrays])."
+msgstr ""
+
+#: doc/classes/Mesh.xml:80
+msgid "Returns the blend shape arrays for the requested surface."
+msgstr ""
+
+#: doc/classes/Mesh.xml:89
+msgid ""
+"Returns a [Material] in a given surface. Surface is rendered using this "
+"material."
+msgstr ""
+
+#: doc/classes/Mesh.xml:100
+msgid ""
+"Sets a [Material] for a given surface. Surface will be rendered using this "
+"material."
+msgstr ""
+
+#: doc/classes/Mesh.xml:106
+msgid "Sets a hint to be used for lightmap resolution."
+msgstr ""
+
+#: doc/classes/Mesh.xml:111
+msgid "Render array as points (one vertex equals one point)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:114
+msgid "Render array as lines (every two vertices a line is created)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:117
+msgid "Render array as line strip."
+msgstr ""
+
+#: doc/classes/Mesh.xml:120
+msgid "Render array as triangles (every three vertices a triangle is created)."
+msgstr ""
+
+#: doc/classes/Mesh.xml:123
+msgid "Render array as triangle strips."
+msgstr ""
+
+#: doc/classes/Mesh.xml:126 doc/classes/RenderingServer.xml:3254
+msgid "Blend shapes are normalized."
+msgstr ""
+
+#: doc/classes/Mesh.xml:129 doc/classes/RenderingServer.xml:3257
+msgid "Blend shapes are relative to base weight."
+msgstr ""
+
+#: doc/classes/Mesh.xml:132
+msgid ""
+"Mesh array contains vertices. All meshes require a vertex array so this "
+"should always be present."
+msgstr ""
+
+#: doc/classes/Mesh.xml:135
+msgid "Mesh array contains normals."
+msgstr ""
+
+#: doc/classes/Mesh.xml:138
+msgid "Mesh array contains tangents."
+msgstr ""
+
+#: doc/classes/Mesh.xml:141
+msgid "Mesh array contains colors."
+msgstr ""
+
+#: doc/classes/Mesh.xml:144
+msgid "Mesh array contains UVs."
+msgstr ""
+
+#: doc/classes/Mesh.xml:147
+msgid "Mesh array contains second UV."
+msgstr ""
+
+#: doc/classes/Mesh.xml:150
+msgid "Mesh array contains bones."
+msgstr ""
+
+#: doc/classes/Mesh.xml:153
+msgid "Mesh array contains bone weights."
+msgstr ""
+
+#: doc/classes/Mesh.xml:156
+msgid "Mesh array uses indices."
+msgstr ""
+
+#: doc/classes/Mesh.xml:159 doc/classes/RenderingServer.xml:3210
+msgid "Flag used to mark a compressed (half float) normal array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:162 doc/classes/RenderingServer.xml:3213
+msgid "Flag used to mark a compressed (half float) tangent array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:165 doc/classes/RenderingServer.xml:3216
+msgid "Flag used to mark a compressed (half float) color array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:168 doc/classes/RenderingServer.xml:3219
+msgid "Flag used to mark a compressed (half float) UV coordinates array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:171 doc/classes/RenderingServer.xml:3222
+msgid ""
+"Flag used to mark a compressed (half float) UV coordinates array for the "
+"second UV coordinates."
+msgstr ""
+
+#: doc/classes/Mesh.xml:174 doc/classes/RenderingServer.xml:3225
+msgid "Flag used to mark a compressed index array."
+msgstr ""
+
+#: doc/classes/Mesh.xml:177 doc/classes/RenderingServer.xml:3228
+msgid "Flag used to mark that the array contains 2D vertices."
+msgstr ""
+
+#: doc/classes/Mesh.xml:180 doc/classes/RenderingServer.xml:3233
+msgid ""
+"Used to set flags [constant ARRAY_COMPRESS_NORMAL], [constant "
+"ARRAY_COMPRESS_TANGENT], [constant ARRAY_COMPRESS_COLOR], [constant "
+"ARRAY_COMPRESS_TEX_UV] and [constant ARRAY_COMPRESS_TEX_UV2] quickly."
+msgstr ""
+
+#: doc/classes/Mesh.xml:183
+msgid "Array of vertices."
+msgstr ""
+
+#: doc/classes/Mesh.xml:186
+msgid "Array of normals."
+msgstr ""
+
+#: doc/classes/Mesh.xml:189
+msgid "Array of tangents as an array of floats, 4 floats per tangent."
+msgstr ""
+
+#: doc/classes/Mesh.xml:192
+msgid "Array of colors."
+msgstr ""
+
+#: doc/classes/Mesh.xml:195
+msgid "Array of UV coordinates."
+msgstr ""
+
+#: doc/classes/Mesh.xml:198
+msgid "Array of second set of UV coordinates."
+msgstr ""
+
+#: doc/classes/Mesh.xml:201
+msgid "Array of bone data."
+msgstr ""
+
+#: doc/classes/Mesh.xml:204
+msgid "Array of weights."
+msgstr ""
+
+#: doc/classes/Mesh.xml:207
+msgid "Array of indices."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:4
+msgid "Helper tool to access and edit [Mesh] data."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:7
+msgid ""
+"MeshDataTool provides access to individual vertices in a [Mesh]. It allows "
+"users to read and edit vertex data of meshes. It also creates an array of "
+"faces and edges.\n"
+"To use MeshDataTool, load a mesh with [method create_from_surface]. When you "
+"are finished editing the data commit the data to a mesh with [method "
+"commit_to_surface].\n"
+"Below is an example of how MeshDataTool may be used.\n"
+"[codeblock]\n"
+"var mdt = MeshDataTool.new()\n"
+"mdt.create_from_surface(mesh, 0)\n"
+"for i in range(mdt.get_vertex_count()):\n"
+" var vertex = mdt.get_vertex(i)\n"
+" ...\n"
+" mdt.set_vertex(i, vertex)\n"
+"mesh.surface_remove(0)\n"
+"mdt.commit_to_surface(mesh)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:28
+msgid "Clears all data currently in MeshDataTool."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:37
+msgid "Adds a new surface to specified [Mesh] with edited data."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:48
+msgid ""
+"Uses specified surface of given [Mesh] to populate data for MeshDataTool.\n"
+"Requires [Mesh] with primitive type [constant Mesh.PRIMITIVE_TRIANGLES]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:56
+msgid "Returns the number of edges in this [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:65
+msgid "Returns array of faces that touch given edge."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:74
+msgid "Returns meta information assigned to given edge."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:85
+msgid ""
+"Returns index of specified vertex connected to given edge.\n"
+"Vertex argument can only be 0 or 1 because edges are comprised of two "
+"vertices."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:93
+msgid "Returns the number of faces in this [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:104
+msgid ""
+"Returns specified edge associated with given face.\n"
+"Edge argument must 2 or less because a face only has three edges."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:114
+msgid "Returns the metadata associated with the given face."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:123
+msgid "Calculates and returns the face normal of the given face."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:134
+msgid ""
+"Returns the specified vertex of the given face.\n"
+"Vertex argument must be 2 or less because faces contain three vertices."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:142
+msgid ""
+"Returns the [Mesh]'s format. Format is an integer made up of [Mesh] format "
+"flags combined together. For example, a mesh containing both vertices and "
+"normals would return a format of [code]3[/code] because [constant ArrayMesh."
+"ARRAY_FORMAT_VERTEX] is [code]1[/code] and [constant ArrayMesh."
+"ARRAY_FORMAT_NORMAL] is [code]2[/code].\n"
+"See [enum ArrayMesh.ArrayFormat] for a list of format flags."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:150
+msgid "Returns the material assigned to the [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:159
+msgid "Returns the vertex at given index."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:168
+msgid "Returns the bones of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:177
+msgid "Returns the color of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:184
+msgid "Returns the total number of vertices in [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:193
+msgid "Returns an array of edges that share the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:202
+msgid "Returns an array of faces that share the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:211
+msgid "Returns the metadata associated with the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:220
+msgid "Returns the normal of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:229
+msgid "Returns the tangent of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:238
+msgid "Returns the UV of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:247
+msgid "Returns the UV2 of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:256
+msgid "Returns bone weights of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:267
+msgid "Sets the metadata of the given edge."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:278
+msgid "Sets the metadata of the given face."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:287
+msgid "Sets the material to be used by newly-constructed [Mesh]."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:298
+msgid "Sets the position of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:309
+msgid "Sets the bones of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:320
+msgid "Sets the color of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:331
+msgid "Sets the metadata associated with the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:342
+msgid "Sets the normal of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:353
+msgid "Sets the tangent of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:364
+msgid "Sets the UV of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:375
+msgid "Sets the UV2 of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshDataTool.xml:386
+msgid "Sets the bone weights of the given vertex."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:4
+msgid "Node used for displaying a [Mesh] in 2D."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:7
+msgid ""
+"Node used for displaying a [Mesh] in 2D. Can be constructed from an existing "
+"[Sprite2D] via a tool in the editor toolbar. Select \"Sprite2D\" then "
+"\"Convert to Mesh2D\", select settings in popup and press \"Create Mesh2D\"."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/2d_meshes.html"
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:16
+msgid "The [Mesh] that will be drawn by the [MeshInstance2D]."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:19 doc/classes/MultiMeshInstance2D.xml:19
+msgid ""
+"The normal map that will be used if using the default [CanvasItemMaterial]."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:22 doc/classes/MultiMeshInstance2D.xml:22
+msgid ""
+"The [Texture2D] that will be used if using the default [CanvasItemMaterial]. "
+"Can be accessed as [code]TEXTURE[/code] in CanvasItem shader."
+msgstr ""
+
+#: doc/classes/MeshInstance2D.xml:28 doc/classes/MultiMeshInstance2D.xml:28
+msgid "Emitted when the [member texture] is changed."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:4
+msgid "Node that instances meshes into a scenario."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:7
+msgid ""
+"MeshInstance3D is a node that takes a [Mesh] resource and adds it to the "
+"current scenario by creating an instance of it. This is the class most often "
+"used render 3D geometry and can be used to instance a single [Mesh] in many "
+"places. This allows reuse of geometry which can save on resources. When a "
+"[Mesh] has to be instanced more than thousands of times at close proximity, "
+"consider using a [MultiMesh] in a [MultiMeshInstance3D] instead."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:16
+msgid ""
+"This helper creates a [StaticBody3D] child node with a "
+"[ConvexPolygonShape3D] collision shape calculated from the mesh geometry. "
+"It's mainly used for testing."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:23
+msgid ""
+"This helper creates a [MeshInstance3D] child node with gizmos at every "
+"vertex calculated from the mesh geometry. It's mainly used for testing."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:30
+msgid ""
+"This helper creates a [StaticBody3D] child node with a "
+"[ConcavePolygonShape3D] collision shape calculated from the mesh geometry. "
+"It's mainly used for testing."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:39
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:48
+msgid ""
+"Returns the override [Material] for the specified surface of the [Mesh] "
+"resource."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:55
+msgid "Returns the number of surface materials."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:66
+msgid ""
+"Sets the override [Material] for the specified surface of the [Mesh] "
+"resource. This material is associated with this [MeshInstance3D] rather than "
+"with the [Mesh] resource."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:72
+msgid "The [Mesh] resource for the instance."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:75
+msgid "[NodePath] to the [Skeleton3D] associated with the instance."
+msgstr ""
+
+#: doc/classes/MeshInstance3D.xml:78
+msgid "Sets the skin to be used by this instance."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:4
+msgid "Library of meshes."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:7
+msgid ""
+"A library of meshes. Contains a list of [Mesh] resources, each with a name "
+"and ID. Each item can also include collision and navigation shapes. This "
+"resource is used in [GridMap]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:16
+msgid "Clears the library."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:25
+msgid ""
+"Creates a new item in the library with the given ID.\n"
+"You can get an unused ID from [method get_last_unused_item_id]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:35
+msgid "Returns the first item with the given name."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:42
+msgid "Returns the list of item IDs in use."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:51
+msgid "Returns the item's mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:60
+msgid "Returns the item's name."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:69
+msgid "Returns the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:78
+msgid "Returns the transform applied to the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:87
+msgid ""
+"When running in the editor, returns a generated item preview (a 3D rendering "
+"in isometric perspective). When used in a running project, returns the "
+"manually-defined item preview which can be set using [method "
+"set_item_preview]. Returns an empty [Texture2D] if no preview was manually "
+"set in a running project."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:96
+msgid ""
+"Returns an item's collision shapes.\n"
+"The array consists of each [Shape3D] followed by its [Transform]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:104
+msgid "Gets an unused ID for a new item."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:113
+msgid "Removes the item."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:124
+msgid "Sets the item's mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:135
+msgid ""
+"Sets the item's name.\n"
+"This name is shown in the editor. It can also be used to look up the item "
+"later using [method find_item_by_name]."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:147
+msgid "Sets the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:158
+msgid "Sets the transform to apply to the item's navigation mesh."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:169
+msgid "Sets a texture to use as the item's preview icon in the editor."
+msgstr ""
+
+#: doc/classes/MeshLibrary.xml:180
+msgid ""
+"Sets an item's collision shapes.\n"
+"The array should consist of [Shape3D] objects, each followed by a "
+"[Transform] that will be applied to it. For shapes that should not have a "
+"transform, use [constant Transform.IDENTITY]."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:4
+msgid "Simple texture that uses a mesh to draw itself."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:7
+msgid ""
+"Simple texture that uses a mesh to draw itself. It's limited because flags "
+"can't be changed and region drawing is not supported."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:15
+msgid "Sets the base texture that the Mesh will use to draw."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:18
+msgid "Sets the size of the image, needed for reference."
+msgstr ""
+
+#: doc/classes/MeshTexture.xml:21
+msgid "Sets the mesh used to draw. It must be a mesh using 2D vertices."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:4
+msgid "Generic mobile VR implementation."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:7
+msgid ""
+"This is a generic mobile VR implementation where you need to provide details "
+"about the phone and HMD used. It does not rely on any existing framework. "
+"This is the most basic interface we have. For the best effect, you need a "
+"mobile phone with a gyroscope and accelerometer.\n"
+"Note that even though there is no positional tracking, the camera will "
+"assume the headset is at a height of 1.85 meters. You can change this by "
+"setting [member eye_height].\n"
+"You can initialise this interface as follows:\n"
+"[codeblock]\n"
+"var interface = ARVRServer.find_interface(\"Native mobile\")\n"
+"if interface and interface.initialize():\n"
+" get_viewport().arvr = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:22
+msgid ""
+"The distance between the display and the lenses inside of the device in "
+"centimeters."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:25
+msgid "The width of the display in centimeters."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:28
+msgid ""
+"The height at which the camera is placed in relation to the ground (i.e. "
+"[ARVROrigin] node)."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:31
+msgid ""
+"The interocular distance, also known as the interpupillary distance. The "
+"distance between the pupils of the left and right eye."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:34
+msgid ""
+"The k1 lens factor is one of the two constants that define the strength of "
+"the lens used and directly influences the lens distortion effect."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:37
+msgid "The k2 lens factor, see k1."
+msgstr ""
+
+#: modules/mobile_vr/doc_classes/MobileVRInterface.xml:40
+msgid ""
+"The oversample setting. Because of the lens distortion we have to render our "
+"buffers at a higher resolution then the screen can natively handle. A value "
+"between 1.5 and 2.0 often provides good results but at the cost of "
+"performance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:4
+msgid "Provides high-performance mesh instancing."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:7
+msgid ""
+"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.\n"
+"MultiMesh is much faster as it can draw thousands of instances with a single "
+"draw call, resulting in less API overhead.\n"
+"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).\n"
+"Since instances may have any behavior, the AABB used for visibility must be "
+"provided by the user."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:13 doc/classes/MultiMeshInstance3D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/"
+"animating_thousands_of_fish.html"
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:14 doc/classes/MultiMeshInstance3D.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/optimization/"
+"using_multimesh.html"
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:21
+msgid "Returns the visibility axis-aligned bounding box."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:30
+msgid "Gets a specific instance's color."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:39
+msgid "Returns the custom data that has been set for a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:48
+msgid "Returns the [Transform] of a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:57
+msgid "Returns the [Transform2D] of a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:68
+msgid ""
+"Sets the color of a specific instance.\n"
+"For the color to take effect, ensure that [member use_colors] is [code]true[/"
+"code] on the [MultiMesh] and [member BaseMaterial3D."
+"vertex_color_use_as_albedo] is [code]true[/code] on the material."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:80
+msgid ""
+"Sets custom data for a specific instance. Although [Color] is used, it is "
+"just a container for 4 floating point numbers.\n"
+"For the custom data to be used, ensure that [member use_custom_data] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:92
+msgid "Sets the [Transform] for a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:103
+msgid "Sets the [Transform2D] for a specific instance."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:115
+msgid ""
+"Number of instances that will get drawn. This clears and (re)sizes the "
+"buffers. By default, all instances are drawn but you can limit this with "
+"[member visible_instance_count]."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:118
+msgid "Mesh to be drawn."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:125
+msgid "Format of transform used to transform mesh, either 2D or 3D."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:128
+msgid ""
+"If [code]true[/code], the [MultiMesh] will use color data (see [member "
+"color_array])."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:131
+msgid ""
+"If [code]true[/code], the [MultiMesh] will use custom data (see [member "
+"custom_data_array])."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:134
+msgid ""
+"Limits the number of instances drawn, -1 draws all instances. Changing this "
+"does not change the sizes of the buffers."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:139
+msgid "Use this when using 2D transforms."
+msgstr ""
+
+#: doc/classes/MultiMesh.xml:142
+msgid "Use this when using 3D transforms."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance2D.xml:4
+msgid "Node that instances a [MultiMesh] in 2D."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance2D.xml:7
+msgid ""
+"[MultiMeshInstance2D] is a specialized node to instance a [MultiMesh] "
+"resource in 2D.\n"
+"Usage is the same as [MultiMeshInstance3D]."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance2D.xml:16
+msgid "The [MultiMesh] that will be drawn by the [MultiMeshInstance2D]."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:4
+msgid "Node that instances a [MultiMesh]."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:7
+msgid ""
+"[MultiMeshInstance3D] is a specialized node to instance "
+"[GeometryInstance3D]s based on a [MultiMesh] resource.\n"
+"This is useful to optimize the rendering of a high amount of instances of a "
+"given mesh (for example trees in a forest or grass strands)."
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/"
+"using_multi_mesh_instance.html"
+msgstr ""
+
+#: doc/classes/MultiMeshInstance3D.xml:19
+msgid ""
+"The [MultiMesh] resource that will be used and shared among all instances of "
+"the [MultiMeshInstance3D]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:4
+msgid "High-level multiplayer API."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:7
+msgid ""
+"This class implements most of the logic behind the high-level multiplayer "
+"API.\n"
+"By default, [SceneTree] has a reference to this class that is used to "
+"provide multiplayer capabilities (i.e. RPC/RSET) across the whole scene.\n"
+"It is possible to override the MultiplayerAPI instance used by specific "
+"Nodes by setting the [member Node.custom_multiplayer] property, effectively "
+"allowing to run both client and server in the same scene."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:18
+msgid ""
+"Clears the current MultiplayerAPI network state (you shouldn't call this "
+"unless you know what you are doing)."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:25
+msgid ""
+"Returns the peer IDs of all connected peers of this MultiplayerAPI's [member "
+"network_peer]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:32
+msgid ""
+"Returns the unique peer ID of this MultiplayerAPI's [member network_peer]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:39
+msgid ""
+"Returns the sender's peer ID for the RPC currently being executed.\n"
+"[b]Note:[/b] If not inside an RPC this method will return 0."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:47 doc/classes/SceneTree.xml:135
+msgid "Returns [code]true[/code] if there is a [member network_peer] set."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:54
+msgid ""
+"Returns [code]true[/code] if this MultiplayerAPI's [member network_peer] is "
+"in server mode (listening for connections)."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:61
+msgid ""
+"Method used for polling the MultiplayerAPI. You only need to worry about "
+"this if you are using [member Node.custom_multiplayer] override or you set "
+"[member SceneTree.multiplayer_poll] to [code]false[/code]. By default, "
+"[SceneTree] will poll its MultiplayerAPI for you.\n"
+"[b]Note:[/b] This method results in RPCs and RSETs being called, so they "
+"will be executed in the same context of this function (e.g. [code]_process[/"
+"code], [code]physics[/code], [Thread])."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:75
+msgid ""
+"Sends the given raw [code]bytes[/code] to a specific peer identified by "
+"[code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). "
+"Default ID is [code]0[/code], i.e. broadcast to all peers."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:84
+msgid ""
+"Sets the base root node to use for RPCs. Instead of an absolute path, a "
+"relative path will be used to find the node upon which the RPC should be "
+"executed.\n"
+"This effectively allows to have different branches of the scene tree to be "
+"managed by different MultiplayerAPI, allowing for example to run both client "
+"and server in the same scene."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:91
+msgid ""
+"If [code]true[/code], the MultiplayerAPI will allow encoding and decoding of "
+"object during RPCs/RSETs.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:95
+msgid ""
+"The peer object to handle the RPC system (effectively enabling networking "
+"when set). Depending on the peer itself, the MultiplayerAPI will become a "
+"network server (check with [method is_network_server]) and will set root "
+"node's network mode to master, or it will become a regular peer with root "
+"node set to puppet. All child nodes are set to inherit the network mode by "
+"default. Handling of networking-related events (connection, disconnection, "
+"new clients) is done by connecting to MultiplayerAPI's signals."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:98
+msgid ""
+"If [code]true[/code], the MultiplayerAPI's [member network_peer] refuses new "
+"incoming connections."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:104
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] successfully "
+"connected to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:109
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] fails to establish "
+"a connection to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:116
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] connects with a new "
+"peer. ID is the peer ID of the new peer. Clients get notified when other "
+"clients connect to the same server. Upon connecting to a server, a client "
+"also receives this signal for the server (with ID being 1)."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:123
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] disconnects from a "
+"peer. Clients get notified when other clients disconnect from the same "
+"server."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:132
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] receive a "
+"[code]packet[/code] with custom data (see [method send_bytes]). ID is the "
+"peer ID of the peer that sent the packet."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:137
+msgid ""
+"Emitted when this MultiplayerAPI's [member network_peer] disconnects from "
+"server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:143
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to disable a "
+"method or property for all RPC calls, making it unavailable. Default for all "
+"methods."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:146
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to set a "
+"method to be called or a property to be changed only on the remote end, not "
+"locally. Analogous to the [code]remote[/code] keyword. Calls and property "
+"changes are accepted from all remote peers, no matter if they are node's "
+"master or puppets."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:149
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to set a "
+"method to be called or a property to be changed only on the network master "
+"for this node. Analogous to the [code]master[/code] keyword. Only accepts "
+"calls or property changes from the node's network puppets, see [method Node."
+"set_network_master]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:152
+msgid ""
+"Used with [method Node.rpc_config] or [method Node.rset_config] to set a "
+"method to be called or a property to be changed only on puppets for this "
+"node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or "
+"property changes from the node's network master, see [method Node."
+"set_network_master]."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:155
+msgid ""
+"Behave like [constant RPC_MODE_REMOTE] but also make the call or property "
+"change locally. Analogous to the [code]remotesync[/code] keyword."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:158
+msgid ""
+"Behave like [constant RPC_MODE_MASTER] but also make the call or property "
+"change locally. Analogous to the [code]mastersync[/code] keyword."
+msgstr ""
+
+#: doc/classes/MultiplayerAPI.xml:161
+msgid ""
+"Behave like [constant RPC_MODE_PUPPET] but also make the call or property "
+"change locally. Analogous to the [code]puppetsync[/code] keyword."
+msgstr ""
+
+#: doc/classes/Mutex.xml:4
+msgid "A synchronization mutex (mutual exclusion)."
+msgstr ""
+
+#: doc/classes/Mutex.xml:7
+msgid ""
+"A synchronization mutex (mutual exclusion). This is used to synchronize "
+"multiple [Thread]s, and is equivalent to a binary [Semaphore]. It guarantees "
+"that only one thread can ever acquire the lock at a time. A mutex can be "
+"used to protect a critical section; however, be careful to avoid deadlocks."
+msgstr ""
+
+#: doc/classes/Mutex.xml:10 doc/classes/Semaphore.xml:10
+#: doc/classes/Thread.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/threads/"
+"using_multiple_threads.html"
+msgstr ""
+
+#: doc/classes/Mutex.xml:17
+msgid "Locks this [Mutex], blocks until it is unlocked by the current owner."
+msgstr ""
+
+#: doc/classes/Mutex.xml:24
+msgid ""
+"Tries locking this [Mutex], but does not block. Returns [constant OK] on "
+"success, [constant ERR_BUSY] otherwise."
+msgstr ""
+
+#: doc/classes/Mutex.xml:31
+msgid "Unlocks this [Mutex], leaving it to other threads."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:14
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_class_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:23
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_method_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:32
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_property_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:41
+msgid ""
+"Returns the documentation string that was previously set with "
+"[code]godot_nativescript_set_signal_documentation[/code]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/NativeScript.xml:48
+msgid ""
+"Constructs a new object of the base type with a script of this type already "
+"attached.\n"
+"[i]Note[/i]: Any arguments passed to this function will be ignored and not "
+"passed to the native constructor function. This will change with in a future "
+"API extension."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:4
+msgid "2D navigation and pathfinding node."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:7
+msgid ""
+"Navigation2D provides navigation and pathfinding within a 2D area, specified "
+"as a collection of [NavigationPolygon] resources. These are automatically "
+"collected from child [NavigationRegion2D] nodes."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:18 doc/classes/Navigation3D.xml:18
+#: doc/classes/NavigationServer2D.xml:175
+msgid ""
+"Returns the point closest to the provided [code]to_point[/code] on the "
+"navigation mesh surface."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:27 doc/classes/Navigation3D.xml:36
+msgid ""
+"Returns the owner region RID for the point returned by [method "
+"get_closest_point]."
+msgstr ""
+
+#: doc/classes/Navigation2D.xml:46
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:4
+msgid "Mesh-based navigation and pathfinding node."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:27
+msgid ""
+"Returns the normal for the point returned by [method get_closest_point]."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:49 doc/classes/NavigationServer3D.xml:212
+msgid ""
+"Returns the closest point between the navigation surface and the segment."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:68
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Navigation3D.xml:78
+msgid ""
+"Defines which direction is up. By default, this is [code](0, 1, 0)[/code], "
+"which is the world's \"up\" direction."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:4
+msgid "2D Agent used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:7
+msgid ""
+"2D Agent that is used in navigation to reach a location while avoiding "
+"static and dynamic obstacles. The dynamic obstacles are avoided using RVO "
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:16 doc/classes/NavigationAgent3D.xml:16
+msgid ""
+"Returns the distance to the target location, using the agent's global "
+"position. The user must set the target location with [method "
+"set_target_location] in order for this to be accurate."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:23
+msgid ""
+"Returns the reachable final location in global coordinates. This can change "
+"if the navigation path is altered in any way."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:30 doc/classes/NavigationAgent3D.xml:30
+msgid "Returns the path from start to finish in global coordinates."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:37
+msgid ""
+"Returns which index the agent is currently on in the navigation path's "
+"[PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:44
+msgid ""
+"Returns the [Navigation2D] node that the agent is using for its navigation "
+"system."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:51
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:58
+msgid "Returns the user defined [Vector2] after setting the target location."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:65 doc/classes/NavigationAgent3D.xml:65
+msgid "Returns true if the navigation path's final location has been reached."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:72 doc/classes/NavigationAgent3D.xml:72
+msgid ""
+"Returns true if the target location is reachable. The target location is set "
+"using [method set_target_location]."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:79 doc/classes/NavigationAgent3D.xml:79
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:88
+msgid ""
+"Sets the [Navigation2D] node used by the agent. Useful when you don't want "
+"to make the agent a child of a [Navigation2D] node."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:97 doc/classes/NavigationAgent3D.xml:97
+msgid ""
+"Sets the user desired final location. This will clear the current navigation "
+"path."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:106 doc/classes/NavigationAgent3D.xml:106
+msgid ""
+"Sends the passed in velocity to the collision avoidance algorithm. It will "
+"adjust the velocity to avoid collisions. Once the adjustment to the velocity "
+"is complete, it will emit the [signal velocity_computed] signal."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:112 doc/classes/NavigationAgent3D.xml:118
+msgid "The maximum number of neighbors for the agent to consider."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:115 doc/classes/NavigationAgent3D.xml:121
+msgid "The maximum speed that an agent can move."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:118 doc/classes/NavigationAgent3D.xml:124
+msgid "The distance to search for other agents."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:121 doc/classes/NavigationAgent3D.xml:127
+msgid ""
+"The maximum distance the agent is allowed away from the ideal path to the "
+"final location. This can happen due to trying to avoid collisions. When the "
+"maximum distance is exceeded, it recalculates the ideal path."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:124 doc/classes/NavigationAgent3D.xml:130
+msgid "The radius of the agent."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:127 doc/classes/NavigationAgent3D.xml:133
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:130 doc/classes/NavigationAgent3D.xml:136
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:136 doc/classes/NavigationAgent3D.xml:142
+msgid "Notifies when the final location is reached."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:141 doc/classes/NavigationAgent3D.xml:147
+msgid "Notifies when the navigation path changes."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:146 doc/classes/NavigationAgent3D.xml:152
+msgid ""
+"Notifies when the player defined target, set with [method "
+"set_target_location], is reached."
+msgstr ""
+
+#: doc/classes/NavigationAgent2D.xml:153 doc/classes/NavigationAgent3D.xml:159
+msgid ""
+"Notifies when the collision avoidance velocity is calculated. Emitted by "
+"[method set_velocity]."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:4
+msgid "3D Agent used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:7
+msgid ""
+"3D Agent that is used in navigation to reach a location while avoiding "
+"static and dynamic obstacles. The dynamic obstacles are avoided using RVO "
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:23
+msgid ""
+"Returns the reachable final location in global coordinates. This can change "
+"if the navigation path is altered in any way. Because of this, it would be "
+"best to check this each frame."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:37
+msgid ""
+"Returns which index the agent is currently on in the navigation path's "
+"[PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:44
+msgid ""
+"Returns the [Navigation3D] node that the agent is using for its navigation "
+"system."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:51
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:58
+msgid "Returns the user defined [Vector3] after setting the target location."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:88
+msgid ""
+"Sets the [Navigation3D] node used by the agent. Useful when you don't want "
+"to make the agent a child of a [Navigation3D] node."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:112
+msgid "The agent height offset to match the navigation mesh height."
+msgstr ""
+
+#: doc/classes/NavigationAgent3D.xml:115
+msgid ""
+"Ignores collisions on the Y axis. Must be true to move on a horizontal plane."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:4
+msgid "2D Obstacle used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:16
+msgid ""
+"Returns the [Navigation2D] node that the obstacle is using for its "
+"navigation system."
+msgstr ""
+
+#: doc/classes/NavigationObstacle2D.xml:25
+msgid ""
+"Sets the [Navigation2D] node used by the obstacle. Useful when you don't "
+"want to make the obstacle a child of a [Navigation2D] node."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:4
+msgid "3D Obstacle used in navigation for collision avoidance."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:16
+msgid ""
+"Returns the [Navigation3D] node that the obstacle is using for its "
+"navigation system."
+msgstr ""
+
+#: doc/classes/NavigationObstacle3D.xml:25
+msgid ""
+"Sets the [Navigation3D] node used by the obstacle. Useful when you don't "
+"want to make the obstacle a child of a [Navigation3D] node."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:4
+msgid ""
+"A node that has methods to draw outlines or use indices of vertices to "
+"create navigation polygons."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:7
+msgid ""
+"There are two ways to create polygons. Either by using the [method "
+"add_outline] method, or using the [method add_polygon] method.\n"
+"Using [method add_outline]:\n"
+"[codeblock]\n"
+"var polygon = NavigationPolygon.new()\n"
+"var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, "
+"50), Vector2(50, 0)])\n"
+"polygon.add_outline(outline)\n"
+"polygon.make_polygons_from_outlines()\n"
+"$NavigationRegion2D.navpoly = polygon\n"
+"[/codeblock]\n"
+"Using [method add_polygon] and indices of the vertices array.\n"
+"[codeblock]\n"
+"var polygon = NavigationPolygon.new()\n"
+"var vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), "
+"Vector2(50, 50), Vector2(50, 0)])\n"
+"polygon.set_vertices(vertices)\n"
+"var indices = PackedInt32Array(0, 3, 1)\n"
+"polygon.add_polygon(indices)\n"
+"$NavigationRegion2D.navpoly = polygon\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:35
+msgid ""
+"Appends a [PackedVector2Array] that contains the vertices of an outline to "
+"the internal array that contains all the outlines. You have to call [method "
+"make_polygons_from_outlines] in order for this array to be converted to "
+"polygons that the engine will use."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:46
+msgid ""
+"Adds a [PackedVector2Array] that contains the vertices of an outline to the "
+"internal array that contains all the outlines at a fixed position. You have "
+"to call [method make_polygons_from_outlines] in order for this array to be "
+"converted to polygons that the engine will use."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:55
+msgid ""
+"Adds a polygon using the indices of the vertices you get when calling "
+"[method get_vertices]."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:62
+msgid ""
+"Clears the array of the outlines, but it doesn't clear the vertices and the "
+"polygons that were created by them."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:69
+msgid ""
+"Clears the array of polygons, but it doesn't clear the array of outlines and "
+"vertices."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:78
+msgid ""
+"Returns a [PackedVector2Array] containing the vertices of an outline that "
+"was created in the editor or by script."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:85
+msgid ""
+"Returns the number of outlines that were created in the editor or by script."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:94
+msgid ""
+"Returns a [PackedInt32Array] containing the indices of the vertices of a "
+"created polygon."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:101
+msgid "Returns the count of all polygons."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:108
+msgid ""
+"Returns a [PackedVector2Array] containing all the vertices being used to "
+"create the polygons."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:115
+msgid "Creates polygons from the outlines added in the editor or by script."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:124
+msgid ""
+"Removes an outline created in the editor or by script. You have to call "
+"[method make_polygons_from_outlines] for the polygons to update."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:135
+msgid ""
+"Changes an outline created in the editor or by script. You have to call "
+"[method make_polygons_from_outlines] for the polygons to update."
+msgstr ""
+
+#: doc/classes/NavigationPolygon.xml:144
+msgid ""
+"Sets the vertices that can be then indexed to create polygons with the "
+"[method add_polygon] method."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:4
+msgid "A region of the navigation map."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:7
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:16
+msgid ""
+"Bakes the [NavigationMesh]. The baking is done in a separate thread because "
+"navigation baking is not a cheap operation. This can be done at runtime. "
+"When it is completed, it automatically sets the new [NavigationMesh]."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:22
+msgid "Determines if the [NavigationRegion3D] is enabled or disabled."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:25
+msgid "The [NavigationMesh] resource to use."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:31
+msgid "Notifies when the navigation mesh bake operation is completed."
+msgstr ""
+
+#: doc/classes/NavigationRegion3D.xml:36
+msgid "Notifies when the [NavigationMesh] has changed."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:4
+msgid "Server interface for low-level 2D navigation access"
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:16 doc/classes/NavigationServer3D.xml:16
+msgid "Creates the agent."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:25 doc/classes/NavigationServer3D.xml:25
+msgid "Returns true if the map got changed the previous frame."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:40 doc/classes/NavigationServer3D.xml:40
+msgid "Callback called at the end of the RVO process."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:51 doc/classes/NavigationServer3D.xml:51
+msgid "Puts the agent in the map."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:62 doc/classes/NavigationServer3D.xml:62
+msgid ""
+"Sets the maximum number of other agents the agent takes into account in the "
+"navigation. The larger this number, the longer the running time of the "
+"simulation. If the number is too low, the simulation will not be safe."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:73 doc/classes/NavigationServer3D.xml:73
+msgid "Sets the maximum speed of the agent. Must be positive."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:84 doc/classes/NavigationServer3D.xml:84
+msgid ""
+"Sets the maximum distance to other agents this agent takes into account in "
+"the navigation. The larger this number, the longer the running time of the "
+"simulation. If the number is too low, the simulation will not be safe."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:95 doc/classes/NavigationServer3D.xml:95
+msgid "Sets the position of the agent in world space."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:106
+#: doc/classes/NavigationServer3D.xml:106
+msgid "Sets the radius of the agent."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:117
+#: doc/classes/NavigationServer3D.xml:117
+msgid "Sets the new target velocity."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:128
+#: doc/classes/NavigationServer3D.xml:128
+msgid ""
+"The minimal amount of time for which the agent's velocities that are "
+"computed by the simulation are safe with respect to other agents. The larger "
+"this number, the sooner this agent will respond to the presence of other "
+"agents, but the less freedom this agent has in choosing its velocities. Must "
+"be positive."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:139
+#: doc/classes/NavigationServer3D.xml:139
+msgid "Sets the current velocity of the agent."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:148
+#: doc/classes/NavigationServer3D.xml:148
+msgid "Destroy the RID"
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:155
+#: doc/classes/NavigationServer3D.xml:155
+msgid "Create a new map."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:164
+#: doc/classes/NavigationServer3D.xml:164
+msgid "Returns the map cell size."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:186
+#: doc/classes/NavigationServer3D.xml:197
+msgid ""
+"Returns the owner region RID for the point returned by [method "
+"map_get_closest_point]."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:195
+msgid ""
+"Returns the edge connection margin of the map. The edge connection margin is "
+"a distance used to connect two regions."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:210
+msgid ""
+"Returns the navigation path to reach the destination from the origin, while "
+"avoiding static obstacles."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:219
+#: doc/classes/NavigationServer3D.xml:254
+msgid "Returns true if the map is active."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:230
+#: doc/classes/NavigationServer3D.xml:265
+msgid "Sets the map active."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:241
+#: doc/classes/NavigationServer3D.xml:276
+msgid "Set the map cell size used to weld the navigation mesh polygons."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:252
+msgid ""
+"Set the map edge connection margin used to weld the compatible region edges."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:259
+#: doc/classes/NavigationServer3D.xml:327
+msgid "Creates a new region."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:270
+#: doc/classes/NavigationServer3D.xml:338
+msgid "Sets the map for the region."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:281
+#: doc/classes/NavigationServer3D.xml:349
+msgid "Sets the navigation mesh for the region."
+msgstr ""
+
+#: doc/classes/NavigationServer2D.xml:292
+#: doc/classes/NavigationServer3D.xml:360
+msgid "Sets the global transformation for the region."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:4
+msgid "Server interface for low-level 3D navigation access"
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:175
+msgid ""
+"Returns the point closest to the provided [code]point[/code] on the "
+"navigation mesh surface."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:186
+msgid ""
+"Returns the normal for the point returned by [method map_get_closest_point]."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:221
+msgid "Returns the edge connection margin of the map."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:236
+msgid "Returns the navigation path to reach the destination from the origin."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:245
+msgid "Returns the map's up direction."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:287
+msgid ""
+"Set the map edge connection margein used to weld the compatible region edges."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:298
+msgid "Sets the map up direction."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:307
+msgid ""
+"Process the collision avoidance agents.\n"
+"The result of this process is needed by the physics server, so this must be "
+"called in the main thread.\n"
+"Note: This function is not thread safe."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:320
+msgid "Bakes the navigation mesh."
+msgstr ""
+
+#: doc/classes/NavigationServer3D.xml:369
+msgid "Control activation of this server."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:4
+msgid ""
+"PacketPeer implementation using the [url=http://enet.bespin.org/index."
+"html]ENet[/url] library."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:7
+msgid ""
+"A PacketPeer implementation that should be passed to [member SceneTree."
+"network_peer] after being initialized as either a client or server. Events "
+"can then be handled by connecting to [SceneTree] signals."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:10
+#: doc/classes/NetworkedMultiplayerPeer.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/networking/"
+"high_level_multiplayer.html"
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:11
+msgid "http://enet.bespin.org/usergroup0.html"
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:20
+msgid ""
+"Closes the connection. Ignored if no connection is currently established. If "
+"this is a server it tries to notify all clients before forcibly "
+"disconnecting them. If this is a client it simply closes the connection to "
+"the server."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:37
+msgid ""
+"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."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:52
+msgid ""
+"Create server that listens to connections via [code]port[/code]. The port "
+"needs to be an available, unused port between 0 and 65535. Note that ports "
+"below 1024 are privileged and may require elevated permissions depending on "
+"the platform. To change the interface the server listens on, use [method "
+"set_bind_ip]. The default IP is the wildcard [code]\"*\"[/code], which "
+"listens on all available interfaces. [code]max_clients[/code] is the maximum "
+"number of clients that are allowed at once, any number up to 4095 may be "
+"used, although the achievable number of simultaneous clients may be far "
+"lower and depends on the application. For additional details on the "
+"bandwidth parameters, see [method create_client]. Returns [constant OK] if a "
+"server 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 server could not be created."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:63
+msgid ""
+"Disconnect the given peer. If \"now\" is set to [code]true[/code], the "
+"connection will be closed immediately without flushing queued messages."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:70
+msgid ""
+"Returns the channel of the last packet fetched via [method PacketPeer."
+"get_packet]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:77
+msgid ""
+"Returns the channel of the next packet that will be retrieved via [method "
+"PacketPeer.get_packet]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:86
+#: modules/websocket/doc_classes/WebSocketServer.xml:33
+msgid "Returns the IP address of the given peer."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:95
+#: modules/websocket/doc_classes/WebSocketServer.xml:42
+msgid "Returns the remote port of the given peer."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:104
+msgid ""
+"The IP used when creating a server. This is set to the wildcard [code]\"*\"[/"
+"code] by default, which binds to all available interfaces. The given IP "
+"needs to be in IPv4 or IPv6 address format, for example: "
+"[code]\"192.168.1.1\"[/code]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:113
+msgid ""
+"Configure the [X509Certificate] to use when [member use_dtls] is [code]true[/"
+"code]. For servers, you must also setup the [CryptoKey] via [method "
+"set_dtls_key]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:122
+msgid ""
+"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]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:128
+msgid ""
+"Enforce ordered packets when using [constant NetworkedMultiplayerPeer."
+"TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant "
+"NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the "
+"only way to use ordering with the RPC system."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:131
+msgid ""
+"The number of channels to be used by ENet. Channels are used to separate "
+"different kinds of data. In reliable or ordered mode, for example, the "
+"packet delivery order is ensured on a per channel basis."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:134
+msgid ""
+"The compression method used for network packets. These have different "
+"tradeoffs of compression speed versus bandwidth, you may need to test which "
+"one works best for your use case if you use compression at all."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:137
+msgid ""
+"Enable or disable certificate verification when [member use_dtls] "
+"[code]true[/code]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:141
+msgid ""
+"Enable or disable the server feature that notifies clients of other peers' "
+"connection/disconnection, and relays messages between them. When this option "
+"is [code]false[/code], clients won't be automatically notified of other "
+"peers and won't be able to send them packets through the server."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:144
+msgid ""
+"Set the default channel to be used to transfer data. By default, this value "
+"is [code]-1[/code] which means that ENet will only use 2 channels, one for "
+"reliable and one for unreliable packets. Channel [code]0[/code] is reserved, "
+"and cannot be used. Setting this member to any value between [code]0[/code] "
+"and [member channel_count] (excluded) will force ENet to use that channel "
+"for sending data."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:148
+msgid ""
+"When enabled, the client or server created by this peer, will use "
+"[PacketPeerDTLS] instead of raw UDP sockets for communicating with the "
+"remote peer. This will make the communication encrypted with DTLS at the "
+"cost of higher resource usage and potentially larger packet size.\n"
+"Note: When creating a DTLS server, make sure you setup the key/certificate "
+"pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS "
+"clients, have a look at the [member dtls_verify] option, and configure the "
+"certificate accordingly via [method set_dtls_certificate]."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:154
+msgid ""
+"No compression. This uses the most bandwidth, but has the upside of "
+"requiring the fewest CPU resources."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:157
+msgid "ENet's built-in range encoding."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:160
+msgid ""
+"[url=http://fastlz.org/]FastLZ[/url] compression. This option uses less CPU "
+"resources compared to [constant COMPRESS_ZLIB], at the expense of using more "
+"bandwidth."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:163
+msgid ""
+"[url=https://www.zlib.net/]Zlib[/url] compression. This option uses less "
+"bandwidth compared to [constant COMPRESS_FASTLZ], at the expense of using "
+"more CPU resources."
+msgstr ""
+
+#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml:166
+msgid "[url=https://facebook.github.io/zstd/]Zstandard[/url] compression."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:4
+msgid "A high-level network interface to simplify multiplayer interactions."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:7
+msgid ""
+"Manages the connection to network peers. Assigns unique IDs to each client "
+"connected to the server."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:17
+msgid ""
+"Returns the current state of the connection. See [enum ConnectionStatus]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:24
+msgid ""
+"Returns the ID of the [NetworkedMultiplayerPeer] who sent the most recent "
+"packet."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:31
+msgid "Returns the ID of this [NetworkedMultiplayerPeer]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:38
+msgid "Waits up to 1 second to receive a new network event."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:47
+msgid ""
+"Sets the peer to which packets will be sent.\n"
+"The [code]id[/code] can be one of: [constant TARGET_PEER_BROADCAST] to send "
+"to all connected peers, [constant TARGET_PEER_SERVER] to send to the peer "
+"acting as server, a valid peer ID to send to that specific peer, a negative "
+"peer ID to send to all peers except that one. By default, the target peer is "
+"[constant TARGET_PEER_BROADCAST]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:54
+msgid ""
+"If [code]true[/code], this [NetworkedMultiplayerPeer] refuses new "
+"connections."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:57
+msgid ""
+"The manner in which to send packets to the [code]target_peer[/code]. See "
+"[enum TransferMode]."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:63
+msgid "Emitted when a connection attempt fails."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:68
+msgid "Emitted when a connection attempt succeeds."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:75
+msgid "Emitted by the server when a client connects."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:82
+msgid "Emitted by the server when a client disconnects."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:87
+msgid "Emitted by clients when the server disconnects."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:93
+msgid ""
+"Packets are not acknowledged, no resend attempts are made for lost packets. "
+"Packets may arrive in any order. Potentially faster than [constant "
+"TRANSFER_MODE_UNRELIABLE_ORDERED]. Use for non-critical data, and always "
+"consider whether the order matters."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:96
+msgid ""
+"Packets are not acknowledged, no resend attempts are made for lost packets. "
+"Packets are received in the order they were sent in. Potentially faster than "
+"[constant TRANSFER_MODE_RELIABLE]. Use for non-critical data or data that "
+"would be outdated if received late due to resend attempt(s) anyway, for "
+"example movement and positional data."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:99
+msgid ""
+"Packets must be received and resend attempts should be made until the "
+"packets are acknowledged. Packets must be received in the order they were "
+"sent in. Most reliable transfer mode, but potentially the slowest due to the "
+"overhead. Use for critical data that must be transmitted and arrive in "
+"order, for example an ability being triggered or a chat message. Consider "
+"carefully if the information really is critical, and use sparingly."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:102
+msgid "The ongoing connection disconnected."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:105
+msgid "A connection attempt is ongoing."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:108
+msgid "The connection attempt succeeded."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:111
+msgid "Packets are sent to the server and then redistributed to other peers."
+msgstr ""
+
+#: doc/classes/NetworkedMultiplayerPeer.xml:114
+msgid "Packets are sent to the server alone."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:4
+msgid ""
+"Scalable texture-based frame that tiles the texture's centers and sides, but "
+"keeps the corners' original size. Perfect for panels and dialog boxes."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:7
+msgid ""
+"Also known as 9-slice panels, NinePatchRect produces clean panels of any "
+"size, based on a small texture. To do so, it splits the texture in a 3×3 "
+"grid. When you scale the node, it tiles the texture's sides horizontally or "
+"vertically, the center on both axes but it doesn't scale or tile the corners."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:18
+msgid ""
+"Returns the size of the margin identified by the given [enum Margin] "
+"constant."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:29
+msgid ""
+"Sets the size of the margin identified by the given [enum Margin] constant "
+"to [code]value[/code] in pixels."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:35 doc/classes/NinePatchRect.xml:38
+#: doc/classes/NinePatchRect.xml:72 doc/classes/NinePatchRect.xml:75
+#: doc/classes/NinePatchRect.xml:78
+msgid "Doesn't do anything at the time of writing."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:41
+msgid ""
+"If [code]true[/code], draw the panel's center. Else, only draw the 9-slice's "
+"borders."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:45
+msgid ""
+"The height of the 9-slice's bottom row. A margin of 16 means the 9-slice's "
+"bottom corners and side will have a height of 16 pixels. You can set all 4 "
+"margin values individually to create panels with non-uniform borders."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:48
+msgid "The height of the 9-slice's left column."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:51
+msgid "The height of the 9-slice's right column."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:54
+msgid "The height of the 9-slice's top row."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:57
+msgid ""
+"Rectangular region of the texture to sample from. If you're working with an "
+"atlas, use this property to define the area the 9-slice should use. All "
+"other properties are relative to this one. If the rect is empty, "
+"NinePatchRect will use the whole texture."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:60
+msgid "The node's texture resource."
+msgstr ""
+
+#: doc/classes/NinePatchRect.xml:66
+msgid "Emitted when the node's texture changes."
+msgstr ""
+
+#: doc/classes/Node.xml:4
+msgid "Base class for all [i]scene[/i] objects."
+msgstr ""
+
+#: doc/classes/Node.xml:7
+msgid ""
+"Nodes are Godot's building blocks. They can be assigned as the child of "
+"another node, resulting in a tree arrangement. A given node can contain any "
+"number of nodes as children with the requirement that all siblings (direct "
+"children of a node) should have unique names.\n"
+"A tree of nodes is called a [i]scene[/i]. Scenes can be saved to the disk "
+"and then instanced into other scenes. This allows for very high flexibility "
+"in the architecture and data model of Godot projects.\n"
+"[b]Scene tree:[/b] The [SceneTree] contains the active tree of nodes. When a "
+"node is added to the scene tree, it receives the [constant "
+"NOTIFICATION_ENTER_TREE] notification and its [method _enter_tree] callback "
+"is triggered. Child nodes are always added [i]after[/i] their parent node, i."
+"e. the [method _enter_tree] callback of a parent node will be triggered "
+"before its child's.\n"
+"Once all nodes have been added in the scene tree, they receive the [constant "
+"NOTIFICATION_READY] notification and their respective [method _ready] "
+"callbacks are triggered. For groups of nodes, the [method _ready] callback "
+"is called in reverse order, starting with the children and moving up to the "
+"parent nodes.\n"
+"This means that when adding a node to the scene tree, the following order "
+"will be used for the callbacks: [method _enter_tree] of the parent, [method "
+"_enter_tree] of the children, [method _ready] of the children and finally "
+"[method _ready] of the parent (recursively for the entire scene tree).\n"
+"[b]Processing:[/b] Nodes can override the \"process\" state, so that they "
+"receive a callback on each frame requesting them to process (do something). "
+"Normal processing (callback [method _process], toggled with [method "
+"set_process]) happens as fast as possible and is dependent on the frame "
+"rate, so the processing time [i]delta[/i] is passed as an argument. Physics "
+"processing (callback [method _physics_process], toggled with [method "
+"set_physics_process]) happens a fixed number of times per second (60 by "
+"default) and is useful for code related to the physics engine.\n"
+"Nodes can also process input events. When present, the [method _input] "
+"function will be called for each input that the program receives. In many "
+"cases, this can be overkill (unless used for simple projects), and the "
+"[method _unhandled_input] function might be preferred; it is called when the "
+"input event was not handled by anyone else (typically, GUI [Control] nodes), "
+"ensuring that the node only receives the events that were meant for it.\n"
+"To keep track of the scene hierarchy (especially when instancing scenes into "
+"other scenes), an \"owner\" can be set for the node with the [member owner] "
+"property. This keeps track of who instanced what. This is mostly useful when "
+"writing editors and tools, though.\n"
+"Finally, when a node is freed with [method Object.free] or [method "
+"queue_free], it will also free all its children.\n"
+"[b]Groups:[/b] Nodes can be added to as many groups as you want to be easy "
+"to manage, you could create groups like \"enemies\" or \"collectables\" for "
+"example, depending on your game. See [method add_to_group], [method "
+"is_in_group] and [method remove_from_group]. You can then retrieve all nodes "
+"in these groups, iterate them and even call methods on groups via the "
+"methods on [SceneTree].\n"
+"[b]Networking with nodes:[/b] After connecting to a server (or making one, "
+"see [NetworkedMultiplayerENet]), it is possible to use the built-in RPC "
+"(remote procedure call) system to communicate over the network. By calling "
+"[method rpc] with a method name, it will be called locally and in all "
+"connected peers (peers = clients and the server that accepts connections). "
+"To identify which node receives the RPC call, Godot will use its [NodePath] "
+"(make sure node names are the same on all peers). Also, take a look at the "
+"high-level networking tutorial and corresponding demos."
+msgstr ""
+
+#: doc/classes/Node.xml:20
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"scenes_and_nodes.html"
+msgstr ""
+
+#: doc/classes/Node.xml:27
+msgid ""
+"Called when the node enters the [SceneTree] (e.g. upon instancing, scene "
+"changing, or after calling [method add_child] in a script). If the node has "
+"children, its [method _enter_tree] callback will be called first, and then "
+"that of the children.\n"
+"Corresponds to the [constant NOTIFICATION_ENTER_TREE] notification in "
+"[method Object._notification]."
+msgstr ""
+
+#: doc/classes/Node.xml:35
+msgid ""
+"Called when the node is about to leave the [SceneTree] (e.g. upon freeing, "
+"scene changing, or after calling [method remove_child] in a script). If the "
+"node has children, its [method _exit_tree] callback will be called last, "
+"after all its children have left the tree.\n"
+"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]."
+msgstr ""
+
+#: doc/classes/Node.xml:43
+msgid ""
+"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.\n"
+"Returning an empty string produces no warning.\n"
+"Call [method update_configuration_warning] when the warning needs to be "
+"updated for this node."
+msgstr ""
+
+#: doc/classes/Node.xml:54
+msgid ""
+"Called when there is an input event. The input event propagates up through "
+"the node tree until a node consumes it.\n"
+"It is only called if input processing is enabled, which is done "
+"automatically if this method is overridden, and can be toggled with [method "
+"set_process_input].\n"
+"To consume the input event and stop it propagating further to other nodes, "
+"[method Viewport.set_input_as_handled] can be called.\n"
+"For gameplay input, [method _unhandled_input] and [method "
+"_unhandled_key_input] are usually a better fit as they allow the GUI to "
+"intercept the events first."
+msgstr ""
+
+#: doc/classes/Node.xml:66
+msgid ""
+"Called during the physics processing step of the main loop. Physics "
+"processing means that the frame rate is synced to the physics, i.e. the "
+"[code]delta[/code] variable should be constant.\n"
+"It is only called if physics processing is enabled, which is done "
+"automatically if this method is overridden, and can be toggled with [method "
+"set_physics_process].\n"
+"Corresponds to the [constant NOTIFICATION_PHYSICS_PROCESS] notification in "
+"[method Object._notification]."
+msgstr ""
+
+#: doc/classes/Node.xml:77
+msgid ""
+"Called during the processing step of the main loop. Processing happens at "
+"every frame and as fast as possible, so the [code]delta[/code] time since "
+"the previous frame is not constant.\n"
+"It is only called if processing is enabled, which is done automatically if "
+"this method is overridden, and can be toggled with [method set_process].\n"
+"Corresponds to the [constant NOTIFICATION_PROCESS] notification in [method "
+"Object._notification]."
+msgstr ""
+
+#: doc/classes/Node.xml:86
+msgid ""
+"Called when the node is \"ready\", i.e. when both the node and its children "
+"have entered the scene tree. If the node has children, their [method _ready] "
+"callbacks get triggered first, and the parent node will receive the ready "
+"notification afterwards.\n"
+"Corresponds to the [constant NOTIFICATION_READY] notification in [method "
+"Object._notification]. See also the [code]onready[/code] keyword for "
+"variables.\n"
+"Usually used for initialization. For even earlier initialization, [method "
+"Object._init] may be used. See also [method _enter_tree].\n"
+"[b]Note:[/b] [method _ready] may be called only once for each node. After "
+"removing a node from the scene tree and adding again, [code]_ready[/code] "
+"will not be called for the second time. This can be bypassed with requesting "
+"another call with [method request_ready], which may be called anywhere "
+"before adding the node again."
+msgstr ""
+
+#: doc/classes/Node.xml:98
+msgid ""
+"Called when an [InputEvent] hasn't been consumed by [method _input] or any "
+"GUI. The input event propagates up through the node tree until a node "
+"consumes it.\n"
+"It is only called if unhandled input processing is enabled, which is done "
+"automatically if this method is overridden, and can be toggled with [method "
+"set_process_unhandled_input].\n"
+"To consume the input event and stop it propagating further to other nodes, "
+"[method Viewport.set_input_as_handled] can be called.\n"
+"For gameplay input, this and [method _unhandled_key_input] are usually a "
+"better fit than [method _input] as they allow the GUI to intercept the "
+"events first."
+msgstr ""
+
+#: doc/classes/Node.xml:110
+msgid ""
+"Called when an [InputEventKey] hasn't been consumed by [method _input] or "
+"any GUI. The input event propagates up through the node tree until a node "
+"consumes it.\n"
+"It is only called if unhandled key input processing is enabled, which is "
+"done automatically if this method is overridden, and can be toggled with "
+"[method set_process_unhandled_key_input].\n"
+"To consume the input event and stop it propagating further to other nodes, "
+"[method Viewport.set_input_as_handled] can be called.\n"
+"For gameplay input, this and [method _unhandled_input] are usually a better "
+"fit than [method _input] as they allow the GUI to intercept the events first."
+msgstr ""
+
+#: doc/classes/Node.xml:124
+msgid ""
+"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.\n"
+"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.\n"
+"[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:\n"
+"[codeblock]\n"
+"if child_node.get_parent():\n"
+" child_node.get_parent().remove_child(child_node)\n"
+"add_child(child_node)\n"
+"[/codeblock]\n"
+"If you need the child node to be added below a specific node in the list of "
+"children, use [method add_child_below_node] instead of this method.\n"
+"[b]Note:[/b] If you want a child to be persisted to a [PackedScene], you "
+"must set [member owner] in addition to calling [method add_child]. This is "
+"typically relevant for [url=https://godot.readthedocs.io/en/latest/tutorials/"
+"misc/running_code_in_the_editor.html]tool scripts[/url] and [url=https://"
+"godot.readthedocs.io/en/latest/tutorials/plugins/editor/index.html]editor "
+"plugins[/url]. If [method add_child] is called without setting [member "
+"owner], the newly added [Node] will not be visible in the scene tree, though "
+"it will be visible in the 2D/3D view."
+msgstr ""
+
+#: doc/classes/Node.xml:146
+msgid ""
+"Adds a child node below the [code]preceding_node[/code].\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:159
+msgid ""
+"Adds the node to a group. Groups are helpers to name and organize a subset "
+"of nodes, for example \"enemies\" or \"collectables\". A node can be in any "
+"number of groups. Nodes can be assigned a group at any time, but will not be "
+"added until they are inside the scene tree (see [method is_inside_tree]). "
+"See notes in the description, and the group methods in [SceneTree].\n"
+"The [code]persistent[/code] option is used when packing node to "
+"[PackedScene] and saving to file. Non-persistent groups aren't stored."
+msgstr ""
+
+#: doc/classes/Node.xml:167
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:176
+msgid ""
+"Duplicates the node, returning a new node.\n"
+"You can fine-tune the behavior using the [code]flags[/code] (see [enum "
+"DuplicateFlags]).\n"
+"[b]Note:[/b] It will not work properly if the node contains a script with "
+"constructor arguments (i.e. needs to supply arguments to [method Object."
+"_init] method). In that case, the node will be duplicated without a script."
+msgstr ""
+
+#: doc/classes/Node.xml:191
+msgid ""
+"Finds a descendant of this node whose name matches [code]mask[/code] as in "
+"[method String.match] (i.e. case-sensitive, but [code]\"*\"[/code] matches "
+"zero or more characters and [code]\"?\"[/code] matches any single character "
+"except [code]\".\"[/code]).\n"
+"[b]Note:[/b] It does not match against the full path, just against "
+"individual node names.\n"
+"If [code]owned[/code] is [code]true[/code], this method only finds nodes "
+"whose owner is this node. This is especially important for scenes "
+"instantiated through a script, because those scenes don't have an owner."
+msgstr ""
+
+#: doc/classes/Node.xml:202
+msgid ""
+"Finds the first parent of the current node whose name matches [code]mask[/"
+"code] as in [method String.match] (i.e. case-sensitive, but [code]\"*\"[/"
+"code] matches zero or more characters and [code]\"?\"[/code] matches any "
+"single character except [code]\".\"[/code]).\n"
+"[b]Note:[/b] It does not match against the full path, just against "
+"individual node names."
+msgstr ""
+
+#: doc/classes/Node.xml:212
+msgid ""
+"Returns a child node by its index (see [method get_child_count]). This "
+"method is often used for iterating all children of a node.\n"
+"To access a child node via its name, use [method get_node]."
+msgstr ""
+
+#: doc/classes/Node.xml:220
+msgid "Returns the number of child nodes."
+msgstr ""
+
+#: doc/classes/Node.xml:227
+msgid "Returns an array of references to node's children."
+msgstr ""
+
+#: doc/classes/Node.xml:234
+msgid "Returns an array listing the groups that the node is a member of."
+msgstr ""
+
+#: doc/classes/Node.xml:241
+msgid ""
+"Returns the node's order in the scene tree branch. For example, if called on "
+"the first child node the position is [code]0[/code]."
+msgstr ""
+
+#: doc/classes/Node.xml:248
+msgid ""
+"Returns the peer ID of the network master for this node. See [method "
+"set_network_master]."
+msgstr ""
+
+#: doc/classes/Node.xml:257
+msgid ""
+"Fetches a node. The [NodePath] can be either a relative path (from the "
+"current node) or an absolute path (in the scene tree) to a node. If the path "
+"does not exist, a [code]null instance[/code] is returned and an error is "
+"logged. Attempts to access methods on the return value will result in an "
+"\"Attempt to call <method> on a null instance.\" error.\n"
+"[b]Note:[/b] Fetching absolute paths only works when the node is inside the "
+"scene tree (see [method is_inside_tree]).\n"
+"[b]Example:[/b] Assume your current node is Character and the following "
+"tree:\n"
+"[codeblock]\n"
+"/root\n"
+"/root/Character\n"
+"/root/Character/Sword\n"
+"/root/Character/Backpack/Dagger\n"
+"/root/MyGame\n"
+"/root/Swamp/Alligator\n"
+"/root/Swamp/Mosquito\n"
+"/root/Swamp/Goblin\n"
+"[/codeblock]\n"
+"Possible paths are:\n"
+"[codeblock]\n"
+"get_node(\"Sword\")\n"
+"get_node(\"Backpack/Dagger\")\n"
+"get_node(\"../Swamp/Alligator\")\n"
+"get_node(\"/root/MyGame\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:285
+msgid ""
+"Fetches a node and one of its resources as specified by the [NodePath]'s "
+"subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested "
+"resources are specified in the [NodePath], the last one will be fetched.\n"
+"The return value is an array of size 3: the first index points to the [Node] "
+"(or [code]null[/code] if not found), the second index points to the "
+"[Resource] (or [code]null[/code] if not found), and the third index is the "
+"remaining [NodePath], if any.\n"
+"For example, assuming that [code]Area2D/CollisionShape2D[/code] is a valid "
+"node and that its [code]shape[/code] property has been assigned a "
+"[RectangleShape2D] resource, one could have this kind of output:\n"
+"[codeblock]\n"
+"print(get_node_and_resource(\"Area2D/CollisionShape2D\")) # "
+"[[CollisionShape2D:1161], Null, ]\n"
+"print(get_node_and_resource(\"Area2D/CollisionShape2D:shape\")) # "
+"[[CollisionShape2D:1161], [RectangleShape2D:1156], ]\n"
+"print(get_node_and_resource(\"Area2D/CollisionShape2D:shape:extents\")) # "
+"[[CollisionShape2D:1161], [RectangleShape2D:1156], :extents]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:301
+msgid ""
+"Similar to [method get_node], but does not log an error if [code]path[/code] "
+"does not point to a valid [Node]."
+msgstr ""
+
+#: doc/classes/Node.xml:308
+msgid ""
+"Returns the parent node of the current node, or an empty [Node] if the node "
+"lacks a parent."
+msgstr ""
+
+#: doc/classes/Node.xml:315
+msgid ""
+"Returns the absolute path of the current node. This only works if the "
+"current node is inside the scene tree (see [method is_inside_tree])."
+msgstr ""
+
+#: doc/classes/Node.xml:324
+msgid ""
+"Returns the relative [NodePath] from this node to the specified [code]node[/"
+"code]. Both nodes must be in the same scene or the function will fail."
+msgstr ""
+
+#: doc/classes/Node.xml:331
+msgid ""
+"Returns the time elapsed since the last physics-bound frame (see [method "
+"_physics_process]). This is always a constant value in physics processing "
+"unless the frames per second is changed via [member Engine."
+"iterations_per_second]."
+msgstr ""
+
+#: doc/classes/Node.xml:338
+msgid ""
+"Returns the time elapsed (in seconds) since the last process callback. This "
+"value may vary from frame to frame."
+msgstr ""
+
+#: doc/classes/Node.xml:345
+msgid ""
+"Returns [code]true[/code] if this is an instance load placeholder. See "
+"[InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/Node.xml:352
+msgid "Returns the [SceneTree] that contains this node."
+msgstr ""
+
+#: doc/classes/Node.xml:359
+msgid "Returns the node's [Viewport]."
+msgstr ""
+
+#: doc/classes/Node.xml:368
+msgid ""
+"Returns [code]true[/code] if the node that the [NodePath] points to exists."
+msgstr ""
+
+#: doc/classes/Node.xml:377
+msgid ""
+"Returns [code]true[/code] if the [NodePath] points to a valid node and its "
+"subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:"
+"shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive "
+"math types) are not considered resources."
+msgstr ""
+
+#: doc/classes/Node.xml:386
+msgid ""
+"Returns [code]true[/code] if the given node is a direct or indirect child of "
+"the current node."
+msgstr ""
+
+#: doc/classes/Node.xml:393
+msgid ""
+"Returns [code]true[/code] if the node is folded (collapsed) in the Scene "
+"dock."
+msgstr ""
+
+#: doc/classes/Node.xml:402
+msgid ""
+"Returns [code]true[/code] if the given node occurs later in the scene "
+"hierarchy than the current node."
+msgstr ""
+
+#: doc/classes/Node.xml:411
+msgid ""
+"Returns [code]true[/code] if this node is in the specified group. See notes "
+"in the description, and the group methods in [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:418
+msgid ""
+"Returns [code]true[/code] if this node is currently inside a [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:425
+msgid ""
+"Returns [code]true[/code] if the local system is the master of this node."
+msgstr ""
+
+#: doc/classes/Node.xml:432
+msgid ""
+"Returns [code]true[/code] if physics processing is enabled (see [method "
+"set_physics_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:439
+msgid ""
+"Returns [code]true[/code] if internal physics processing is enabled (see "
+"[method set_physics_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:446
+msgid ""
+"Returns [code]true[/code] if processing is enabled (see [method "
+"set_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:453
+msgid ""
+"Returns [code]true[/code] if the node is processing input (see [method "
+"set_process_input])."
+msgstr ""
+
+#: doc/classes/Node.xml:460
+msgid ""
+"Returns [code]true[/code] if internal processing is enabled (see [method "
+"set_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:467
+msgid ""
+"Returns [code]true[/code] if the node is processing unhandled input (see "
+"[method set_process_unhandled_input])."
+msgstr ""
+
+#: doc/classes/Node.xml:474
+msgid ""
+"Returns [code]true[/code] if the node is processing unhandled key input (see "
+"[method set_process_unhandled_key_input])."
+msgstr ""
+
+#: doc/classes/Node.xml:485
+msgid ""
+"Moves a child node to a different position (order) among the other children. "
+"Since calls, signals, etc are performed by tree order, changing the order of "
+"children nodes may be useful."
+msgstr ""
+
+#: doc/classes/Node.xml:492
+msgid ""
+"Prints all stray nodes (nodes outside the [SceneTree]). Used for debugging. "
+"Works only in debug builds."
+msgstr ""
+
+#: doc/classes/Node.xml:499
+msgid ""
+"Prints the tree to stdout. Used mainly for debugging purposes. This version "
+"displays the path relative to the current node, and is good for copy/pasting "
+"into the [method get_node] function.\n"
+"[b]Example output:[/b]\n"
+"[codeblock]\n"
+"TheGame\n"
+"TheGame/Menu\n"
+"TheGame/Menu/Label\n"
+"TheGame/Menu/Camera2D\n"
+"TheGame/SplashScreen\n"
+"TheGame/SplashScreen/Camera2D\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:515
+msgid ""
+"Similar to [method print_tree], this prints the tree to stdout. This version "
+"displays a more graphical representation similar to what is displayed in the "
+"scene inspector. It is useful for inspecting larger trees.\n"
+"[b]Example output:[/b]\n"
+"[codeblock]\n"
+" ┖╴TheGame\n"
+" ┠╴Menu\n"
+" ┃ ┠╴Label\n"
+" ┃ ┖╴Camera2D\n"
+" ┖-SplashScreen\n"
+" ┖╴Camera2D\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Node.xml:537
+msgid ""
+"Calls the given method (if present) with the arguments given in [code]args[/"
+"code] on this node and recursively on all its children. If the "
+"[code]parent_first[/code] argument is [code]true[/code], the method will be "
+"called on the current node first, then on all its children. If "
+"[code]parent_first[/code] is [code]false[/code], the children will be called "
+"first."
+msgstr ""
+
+#: doc/classes/Node.xml:546
+msgid ""
+"Notifies the current node and all its children recursively by calling "
+"[method Object.notification] on all of them."
+msgstr ""
+
+#: doc/classes/Node.xml:553
+msgid ""
+"Queues a node for deletion at the end of the current frame. When deleted, "
+"all of its child nodes will be deleted as well. This method ensures it's "
+"safe to delete the node, contrary to [method Object.free]. Use [method "
+"Object.is_queued_for_deletion] to check whether a node will be deleted at "
+"the end of the frame."
+msgstr ""
+
+#: doc/classes/Node.xml:560
+msgid ""
+"Moves this node to the bottom of parent node's children hierarchy. This is "
+"often useful in GUIs ([Control] nodes), because their order of drawing "
+"depends on their order in the tree, i.e. the further they are on the node "
+"list, the higher they are drawn. After using [code]raise[/code], a Control "
+"will be drawn on top of their siblings."
+msgstr ""
+
+#: doc/classes/Node.xml:567
+msgid ""
+"Removes a node and sets all its children as children of the parent node (if "
+"it exists). All event subscriptions that pass by the removed node will be "
+"unsubscribed."
+msgstr ""
+
+#: doc/classes/Node.xml:576
+msgid ""
+"Removes a child node. The node is NOT deleted and must be deleted manually."
+msgstr ""
+
+#: doc/classes/Node.xml:585
+msgid ""
+"Removes a node from a group. See notes in the description, and the group "
+"methods in [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:596
+msgid ""
+"Replaces a node in a scene by the given one. Subscriptions that pass through "
+"this node will be lost."
+msgstr ""
+
+#: doc/classes/Node.xml:603
+msgid ""
+"Requests that [code]_ready[/code] be called again. Note that the method "
+"won't be called immediately, but is scheduled for when the node is added to "
+"the scene tree again (see [method _ready]). [code]_ready[/code] is called "
+"only for the node which requested it, which means that you need to request "
+"ready for each child if you want them to call [code]_ready[/code] too (in "
+"which case, [code]_ready[/code] will be called in the same order as it would "
+"normally)."
+msgstr ""
+
+#: doc/classes/Node.xml:612
+msgid ""
+"Sends a remote procedure call request for the given [code]method[/code] to "
+"peers on the network (and locally), optionally sending all additional "
+"arguments as arguments to the method called by the RPC. The call request "
+"will only be received by nodes with the same [NodePath], including the exact "
+"same node name. Behaviour depends on the RPC configuration for the given "
+"method, see [method rpc_config]. Methods are not exposed to RPCs by default. "
+"See also [method rset] and [method rset_config] for properties. Returns an "
+"empty [Variant].\n"
+"[b]Note:[/b] You can only safely use RPCs on clients after you received the "
+"[code]connected_to_server[/code] signal from the [SceneTree]. You also need "
+"to keep track of the connection state, either by the [SceneTree] signals "
+"like [code]server_disconnected[/code] or by checking [code]SceneTree."
+"network_peer.get_connection_status() == CONNECTION_CONNECTED[/code]."
+msgstr ""
+
+#: doc/classes/Node.xml:624
+msgid ""
+"Changes the RPC mode for the given [code]method[/code] to the given "
+"[code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is "
+"annotating methods and properties with the corresponding keywords "
+"([code]remote[/code], [code]master[/code], [code]puppet[/code], "
+"[code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). "
+"By default, methods are not exposed to networking (and RPCs). See also "
+"[method rset] and [method rset_config] for properties."
+msgstr ""
+
+#: doc/classes/Node.xml:635
+msgid ""
+"Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] "
+"(see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty "
+"[Variant]."
+msgstr ""
+
+#: doc/classes/Node.xml:644
+msgid ""
+"Sends a [method rpc] using an unreliable protocol. Returns an empty "
+"[Variant]."
+msgstr ""
+
+#: doc/classes/Node.xml:655
+msgid ""
+"Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] "
+"using an unreliable protocol (see [method NetworkedMultiplayerPeer."
+"set_target_peer]). Returns an empty [Variant]."
+msgstr ""
+
+#: doc/classes/Node.xml:666
+msgid ""
+"Remotely changes a property's value on other peers (and locally). Behaviour "
+"depends on the RPC configuration for the given property, see [method "
+"rset_config]. See also [method rpc] for RPCs for methods, most information "
+"applies to this method as well."
+msgstr ""
+
+#: doc/classes/Node.xml:677
+msgid ""
+"Changes the RPC mode for the given [code]property[/code] to the given "
+"[code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is "
+"annotating methods and properties with the corresponding keywords "
+"([code]remote[/code], [code]master[/code], [code]puppet[/code], "
+"[code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). "
+"By default, properties are not exposed to networking (and RPCs). See also "
+"[method rpc] and [method rpc_config] for methods."
+msgstr ""
+
+#: doc/classes/Node.xml:690
+msgid ""
+"Remotely changes the property's value on a specific peer identified by "
+"[code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer])."
+msgstr ""
+
+#: doc/classes/Node.xml:701
+msgid ""
+"Remotely changes the property's value on other peers (and locally) using an "
+"unreliable protocol."
+msgstr ""
+
+#: doc/classes/Node.xml:714
+msgid ""
+"Remotely changes property's value on a specific peer identified by "
+"[code]peer_id[/code] using an unreliable protocol (see [method "
+"NetworkedMultiplayerPeer.set_target_peer])."
+msgstr ""
+
+#: doc/classes/Node.xml:723
+msgid "Sets the folded state of the node in the Scene dock."
+msgstr ""
+
+#: doc/classes/Node.xml:734
+msgid ""
+"Sets the node's network master to the peer with the given peer ID. The "
+"network master is the peer that has authority over the node on the network. "
+"Useful in conjunction with the [code]master[/code] and [code]puppet[/code] "
+"keywords. Inherited from the parent node by default, which ultimately "
+"defaults to peer ID 1 (the server). If [code]recursive[/code], the given "
+"peer is recursively set as the master for all children of this node."
+msgstr ""
+
+#: doc/classes/Node.xml:743
+msgid ""
+"Enables or disables physics (i.e. fixed framerate) processing. When a node "
+"is being processed, it will receive a [constant "
+"NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine."
+"iterations_per_second] to change) interval (and the [method "
+"_physics_process] callback will be called if exists). Enabled automatically "
+"if [method _physics_process] is overridden. Any calls to this before [method "
+"_ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:752
+msgid ""
+"Enables or disables internal physics for this node. Internal physics "
+"processing happens in isolation from the normal [method _physics_process] "
+"calls and is used by some nodes internally to guarantee proper functioning "
+"even if the node is paused or physics processing is disabled for scripting "
+"([method set_physics_process]). Only useful for advanced uses to manipulate "
+"built-in nodes' behaviour."
+msgstr ""
+
+#: doc/classes/Node.xml:761
+msgid ""
+"Enables or disables processing. When a node is being processed, it will "
+"receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the "
+"[method _process] callback will be called if exists). Enabled automatically "
+"if [method _process] is overridden. Any calls to this before [method _ready] "
+"will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:770
+msgid ""
+"Enables or disables input processing. This is not required for GUI controls! "
+"Enabled automatically if [method _input] is overridden. Any calls to this "
+"before [method _ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:779
+msgid ""
+"Enables or disabled internal processing for this node. Internal processing "
+"happens in isolation from the normal [method _process] calls and is used by "
+"some nodes internally to guarantee proper functioning even if the node is "
+"paused or processing is disabled for scripting ([method set_process]). Only "
+"useful for advanced uses to manipulate built-in nodes' behaviour."
+msgstr ""
+
+#: doc/classes/Node.xml:788
+msgid ""
+"Enables unhandled input processing. This is not required for GUI controls! "
+"It enables the node to receive all input that was not previously handled "
+"(usually by a [Control]). Enabled automatically if [method _unhandled_input] "
+"is overridden. Any calls to this before [method _ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:797
+msgid ""
+"Enables unhandled key input processing. Enabled automatically if [method "
+"_unhandled_key_input] is overridden. Any calls to this before [method "
+"_ready] will be ignored."
+msgstr ""
+
+#: doc/classes/Node.xml:806
+msgid ""
+"Sets whether this is an instance load placeholder. See [InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/Node.xml:813
+msgid ""
+"Updates the warning displayed for this node in the Scene Dock.\n"
+"Use [method _get_configuration_warning] to setup the warning message to "
+"display."
+msgstr ""
+
+#: doc/classes/Node.xml:820
+msgid ""
+"The override to the default [MultiplayerAPI]. Set to [code]null[/code] to "
+"use the default [SceneTree] one."
+msgstr ""
+
+#: doc/classes/Node.xml:823
+msgid ""
+"When a scene is instanced from a file, its topmost node contains the "
+"filename from which it was loaded."
+msgstr ""
+
+#: doc/classes/Node.xml:826
+msgid ""
+"The [MultiplayerAPI] instance associated with this node. Either the [member "
+"custom_multiplayer], or the default SceneTree one (if inside tree)."
+msgstr ""
+
+#: doc/classes/Node.xml:829
+msgid ""
+"The name of the node. This name is unique among the siblings (other child "
+"nodes from the same parent). When set to an existing name, the node will be "
+"automatically renamed."
+msgstr ""
+
+#: doc/classes/Node.xml:832
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:835
+msgid "Pause mode. How the node will behave if the [SceneTree] is paused."
+msgstr ""
+
+#: doc/classes/Node.xml:838
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node.xml:844
+msgid "Emitted when the node is ready."
+msgstr ""
+
+#: doc/classes/Node.xml:849
+msgid "Emitted when the node is renamed."
+msgstr ""
+
+#: doc/classes/Node.xml:854
+msgid "Emitted when the node enters the tree."
+msgstr ""
+
+#: doc/classes/Node.xml:859
+msgid "Emitted after the node exits the tree and is no longer active."
+msgstr ""
+
+#: doc/classes/Node.xml:864
+msgid ""
+"Emitted when the node is still active but about to exit the tree. This is "
+"the right place for de-initialization (or a \"destructor\", if you will)."
+msgstr ""
+
+#: doc/classes/Node.xml:870
+msgid "Notification received when the node enters a [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:873
+msgid "Notification received when the node is about to exit a [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:876
+msgid "Notification received when the node is moved in the parent."
+msgstr ""
+
+#: doc/classes/Node.xml:879
+msgid "Notification received when the node is ready. See [method _ready]."
+msgstr ""
+
+#: doc/classes/Node.xml:882
+msgid "Notification received when the node is paused."
+msgstr ""
+
+#: doc/classes/Node.xml:885
+msgid "Notification received when the node is unpaused."
+msgstr ""
+
+#: doc/classes/Node.xml:888
+msgid ""
+"Notification received every frame when the physics process flag is set (see "
+"[method set_physics_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:891
+msgid ""
+"Notification received every frame when the process flag is set (see [method "
+"set_process])."
+msgstr ""
+
+#: doc/classes/Node.xml:894
+msgid ""
+"Notification received when a node is set as a child of another node.\n"
+"[b]Note:[/b] This doesn't mean that a node entered the [SceneTree]."
+msgstr ""
+
+#: doc/classes/Node.xml:898
+msgid ""
+"Notification received when a node is unparented (parent removed it from the "
+"list of children)."
+msgstr ""
+
+#: doc/classes/Node.xml:901
+msgid "Notification received when the node is instanced."
+msgstr ""
+
+#: doc/classes/Node.xml:904
+msgid "Notification received when a drag begins."
+msgstr ""
+
+#: doc/classes/Node.xml:907
+msgid "Notification received when a drag ends."
+msgstr ""
+
+#: doc/classes/Node.xml:910
+msgid "Notification received when the node's [NodePath] changed."
+msgstr ""
+
+#: doc/classes/Node.xml:913
+msgid ""
+"Notification received every frame when the internal process flag is set (see "
+"[method set_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:916
+msgid ""
+"Notification received every frame when the internal physics process flag is "
+"set (see [method set_physics_process_internal])."
+msgstr ""
+
+#: doc/classes/Node.xml:919
+msgid ""
+"Notification received from the OS when the mouse enters the game window.\n"
+"Implemented on desktop and web platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:923
+msgid ""
+"Notification received from the OS when the mouse leaves the game window.\n"
+"Implemented on desktop and web platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:927
+msgid ""
+"Notification received from the OS when the game window is focused.\n"
+"Implemented on all platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:931
+msgid ""
+"Notification received from the OS when the game window is unfocused.\n"
+"Implemented on all platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:935
+msgid ""
+"Notification received from the OS when a close request is sent (e.g. closing "
+"the window with a \"Close\" button or Alt+F4).\n"
+"Implemented on desktop platforms."
+msgstr ""
+
+#: doc/classes/Node.xml:939
+msgid ""
+"Notification received from the OS when a go back request is sent (e.g. "
+"pressing the \"Back\" button on Android).\n"
+"Specific to the Android platform."
+msgstr ""
+
+#: doc/classes/Node.xml:972
+msgid ""
+"Inherits pause mode from the node's parent. For the root node, it is "
+"equivalent to [constant PAUSE_MODE_STOP]. Default."
+msgstr ""
+
+#: doc/classes/Node.xml:975
+msgid "Stops processing when the [SceneTree] is paused."
+msgstr ""
+
+#: doc/classes/Node.xml:978
+msgid "Continue to process regardless of the [SceneTree] pause state."
+msgstr ""
+
+#: doc/classes/Node.xml:981
+msgid "Duplicate the node's signals."
+msgstr ""
+
+#: doc/classes/Node.xml:984
+msgid "Duplicate the node's groups."
+msgstr ""
+
+#: doc/classes/Node.xml:987
+msgid "Duplicate the node's scripts."
+msgstr ""
+
+#: doc/classes/Node.xml:990
+msgid ""
+"Duplicate using instancing.\n"
+"An instance stays linked to the original so when the original changes, the "
+"instance changes too."
+msgstr ""
+
+#: doc/classes/Node2D.xml:4
+msgid ""
+"A 2D game object, inherited by all 2D-related nodes. Has a position, "
+"rotation, scale, and Z index."
+msgstr ""
+
+#: doc/classes/Node2D.xml:7
+msgid ""
+"A 2D game object, with a transform (position, rotation, and scale). All 2D "
+"nodes, including physics objects and sprites, inherit from Node2D. Use "
+"Node2D as a parent node to move, scale and rotate children in a 2D project. "
+"Also gives control of the node's render order."
+msgstr ""
+
+#: doc/classes/Node2D.xml:19
+msgid "Multiplies the current scale by the [code]ratio[/code] vector."
+msgstr ""
+
+#: doc/classes/Node2D.xml:28
+msgid ""
+"Returns the angle between the node and the [code]point[/code] in radians."
+msgstr ""
+
+#: doc/classes/Node2D.xml:37
+msgid "Returns the [Transform2D] relative to this node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:46
+msgid "Adds the [code]offset[/code] vector to the node's global position."
+msgstr ""
+
+#: doc/classes/Node2D.xml:55
+msgid ""
+"Rotates the node so it points towards the [code]point[/code], which is "
+"expected to use global coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:66
+msgid ""
+"Applies a local translation on the node's X axis based on the [method Node."
+"_process]'s [code]delta[/code]. If [code]scaled[/code] is [code]false[/"
+"code], normalizes the movement."
+msgstr ""
+
+#: doc/classes/Node2D.xml:77
+msgid ""
+"Applies a local translation on the node's Y axis based on the [method Node."
+"_process]'s [code]delta[/code]. If [code]scaled[/code] is [code]false[/"
+"code], normalizes the movement."
+msgstr ""
+
+#: doc/classes/Node2D.xml:86
+msgid ""
+"Applies a rotation to the node, in radians, starting from its current "
+"rotation."
+msgstr ""
+
+#: doc/classes/Node2D.xml:95
+msgid "Converts a local point's coordinates to global coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:104
+msgid "Converts a global point's coordinates to local coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:113
+msgid ""
+"Translates the node by the given [code]offset[/code] in local coordinates."
+msgstr ""
+
+#: doc/classes/Node2D.xml:119
+msgid "Global position."
+msgstr ""
+
+#: doc/classes/Node2D.xml:122
+msgid "Global rotation in radians."
+msgstr ""
+
+#: doc/classes/Node2D.xml:125
+msgid "Global rotation in degrees."
+msgstr ""
+
+#: doc/classes/Node2D.xml:128
+msgid "Global scale."
+msgstr ""
+
+#: doc/classes/Node2D.xml:131
+msgid "Global [Transform2D]."
+msgstr ""
+
+#: doc/classes/Node2D.xml:134
+msgid "Position, relative to the node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:137
+msgid "Rotation in radians, relative to the node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:140
+msgid "Rotation in degrees, relative to the node's parent."
+msgstr ""
+
+#: doc/classes/Node2D.xml:143
+msgid "The node's scale. Unscaled value: [code](1, 1)[/code]."
+msgstr ""
+
+#: doc/classes/Node2D.xml:146
+msgid "Local [Transform2D]."
+msgstr ""
+
+#: doc/classes/Node2D.xml:149
+msgid ""
+"If [code]true[/code], the node's Z index is relative to its parent's Z "
+"index. If this node's Z index is 2 and its parent's effective Z index is 3, "
+"then this node's effective Z index will be 2 + 3 = 5."
+msgstr ""
+
+#: doc/classes/Node2D.xml:152
+msgid ""
+"Z index. Controls the order in which the nodes render. A node with a higher "
+"Z index will display in front of others."
+msgstr ""
+
+#: doc/classes/Node3D.xml:4
+msgid "Most basic 3D game object, parent of all 3D-related nodes."
+msgstr ""
+
+#: doc/classes/Node3D.xml:7
+msgid ""
+"Most basic 3D game object, with a 3D [Transform] and visibility settings. "
+"All other 3D game objects inherit from Node3D. Use [Node3D] as a parent node "
+"to move, scale, rotate and show/hide children in a 3D project.\n"
+"Affine operations (rotate, scale, translate) happen in parent's local "
+"coordinate system, unless the [Node3D] object is set as top-level. Affine "
+"operations in this coordinate system correspond to direct affine operations "
+"on the [Node3D]'s transform. The word local below refers to this coordinate "
+"system. The coordinate system that is attached to the [Node3D] object itself "
+"is referred to as object-local coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html"
+msgstr ""
+
+#: doc/classes/Node3D.xml:25
+msgid ""
+"Returns the parent [Node3D], or an empty [Object] if no parent exists or "
+"parent is not of type [Node3D]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:32
+msgid ""
+"Returns the current [World3D] resource this [Node3D] node is registered to."
+msgstr ""
+
+#: doc/classes/Node3D.xml:43
+msgid ""
+"Rotates the global (world) transformation around axis, a unit [Vector3], by "
+"specified angle in radians. The rotation axis is in global coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:52
+msgid ""
+"Scales the global (world) transformation by the given [Vector3] scale "
+"factors."
+msgstr ""
+
+#: doc/classes/Node3D.xml:61
+msgid ""
+"Moves the global (world) transformation by [Vector3] offset. The offset is "
+"in global coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:68
+msgid ""
+"Disables rendering of this node. Changes [member visible] to [code]false[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:75
+msgid ""
+"Returns whether node notifies about its local transformation changes. "
+"[Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:82
+msgid ""
+"Returns whether this node uses a scale of [code](1, 1, 1)[/code] or its "
+"local transformation scale."
+msgstr ""
+
+#: doc/classes/Node3D.xml:89
+msgid ""
+"Returns whether this node is set as Toplevel, that is whether it ignores its "
+"parent nodes transformations."
+msgstr ""
+
+#: doc/classes/Node3D.xml:96
+msgid ""
+"Returns whether the node notifies about its global and local transformation "
+"changes. [Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:103
+msgid ""
+"Returns whether the node is visible, taking into consideration that its "
+"parents visibility."
+msgstr ""
+
+#: doc/classes/Node3D.xml:114
+msgid ""
+"Rotates itself so that the local -Z axis points towards the [code]target[/"
+"code] position.\n"
+"The transform will first be rotated around the given [code]up[/code] vector, "
+"and then fully aligned to the target by a further rotation around an axis "
+"perpendicular to both the [code]target[/code] and [code]up[/code] vectors.\n"
+"Operations take place in global space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:129
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Node3D.xml:136
+msgid ""
+"Resets this node's transformations (like scale, skew and taper) preserving "
+"its rotation and translation by performing Gram-Schmidt orthonormalization "
+"on this node's [Transform]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:147
+msgid ""
+"Rotates the local transformation around axis, a unit [Vector3], by specified "
+"angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:158
+msgid ""
+"Rotates the local transformation around axis, a unit [Vector3], by specified "
+"angle in radians. The rotation axis is in object-local coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:167
+msgid "Rotates the local transformation around the X axis by angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:176
+msgid "Rotates the local transformation around the Y axis by angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:185
+msgid "Rotates the local transformation around the Z axis by angle in radians."
+msgstr ""
+
+#: doc/classes/Node3D.xml:194
+msgid ""
+"Scales the local transformation by given 3D scale factors in object-local "
+"coordinate system."
+msgstr ""
+
+#: doc/classes/Node3D.xml:203
+msgid ""
+"Makes the node ignore its parents transformations. Node transformations are "
+"only in global space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:212
+msgid ""
+"Sets whether the node uses a scale of [code](1, 1, 1)[/code] or its local "
+"transformation scale. Changes to the local transformation scale are "
+"preserved."
+msgstr ""
+
+#: doc/classes/Node3D.xml:219
+msgid ""
+"Reset all transformations for this node (sets its [Transform] to the "
+"identity matrix)."
+msgstr ""
+
+#: doc/classes/Node3D.xml:228
+msgid ""
+"Sets whether the node ignores notification that its transformation (global "
+"or local) changed."
+msgstr ""
+
+#: doc/classes/Node3D.xml:237
+msgid ""
+"Sets whether the node notifies about its local transformation changes. "
+"[Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:246
+msgid ""
+"Sets whether the node notifies about its global and local transformation "
+"changes. [Node3D] will not propagate this by default."
+msgstr ""
+
+#: doc/classes/Node3D.xml:253
+msgid ""
+"Enables rendering of this node. Changes [member visible] to [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:262
+msgid ""
+"Transforms [code]local_point[/code] from this node's local space to world "
+"space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:271
+msgid ""
+"Transforms [code]global_point[/code] from world space to this node's local "
+"space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:280
+msgid ""
+"Changes the node's position by the given offset [Vector3].\n"
+"Note that the translation [code]offset[/code] is affected by the node's "
+"scale, so if scaled by e.g. [code](10, 1, 1)[/code], a translation by an "
+"offset of [code](2, 0, 0)[/code] would actually add 20 ([code]2 * 10[/code]) "
+"to the X coordinate."
+msgstr ""
+
+#: doc/classes/Node3D.xml:290
+msgid ""
+"Changes the node's position by the given offset [Vector3] in local space."
+msgstr ""
+
+#: doc/classes/Node3D.xml:297
+msgid "Updates the [Node3DGizmo] of this node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:303
+msgid ""
+"The [Node3DGizmo] for this node. Used for example in [EditorNode3DGizmo] as "
+"custom visualization and editing handles in Editor."
+msgstr ""
+
+#: doc/classes/Node3D.xml:306
+msgid "World3D space (global) [Transform] of this node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:309
+msgid ""
+"Rotation part of the local transformation in radians, specified in terms of "
+"YXZ-Euler angles in the format (X angle, Y angle, Z angle).\n"
+"[b]Note:[/b] In the mathematical sense, rotation is a matrix and not a "
+"vector. The three Euler angles, which are the three independent parameters "
+"of the Euler-angle parametrization of the rotation matrix, are stored in a "
+"[Vector3] data structure not because the rotation is a vector, but only "
+"because [Vector3] exists as a convenient data-structure to store 3 floating-"
+"point numbers. Therefore, applying affine operations on the rotation \"vector"
+"\" is not meaningful."
+msgstr ""
+
+#: doc/classes/Node3D.xml:313
+msgid ""
+"Rotation part of the local transformation in degrees, specified in terms of "
+"YXZ-Euler angles in the format (X angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Node3D.xml:316
+msgid "Scale part of the local transformation."
+msgstr ""
+
+#: doc/classes/Node3D.xml:319
+msgid "Local space [Transform] of this node, with respect to the parent node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:322
+msgid "Local translation of this node."
+msgstr ""
+
+#: doc/classes/Node3D.xml:325
+msgid "If [code]true[/code], this node is drawn."
+msgstr ""
+
+#: doc/classes/Node3D.xml:331
+msgid "Emitted when node visibility changes."
+msgstr ""
+
+#: doc/classes/Node3D.xml:337
+msgid ""
+"Node3D nodes receives this notification when their global transform changes. "
+"This means that either the current or a parent node changed its transform.\n"
+"In order for [constant NOTIFICATION_TRANSFORM_CHANGED] to work, users first "
+"need to ask for it, with [method set_notify_transform]."
+msgstr ""
+
+#: doc/classes/Node3D.xml:341
+msgid ""
+"Node3D nodes receives this notification when they are registered to new "
+"[World3D] resource."
+msgstr ""
+
+#: doc/classes/Node3D.xml:344
+msgid ""
+"Node3D nodes receives this notification when they are unregistered from "
+"current [World3D] resource."
+msgstr ""
+
+#: doc/classes/Node3D.xml:347
+msgid "Node3D nodes receives this notification when their visibility changes."
+msgstr ""
+
+#: doc/classes/NodePath.xml:4
+msgid "Pre-parsed scene tree path."
+msgstr ""
+
+#: doc/classes/NodePath.xml:7
+msgid ""
+"A pre-parsed relative or absolute path in a scene tree, for use with [method "
+"Node.get_node] and similar functions. It can reference a node, a resource "
+"within a node, or a property of a node or resource. For instance, "
+"[code]\"Path2D/PathFollow2D/Sprite2D:texture:size\"[/code] would refer to "
+"the [code]size[/code] property of the [code]texture[/code] resource on the "
+"node named [code]\"Sprite2D\"[/code] which is a child of the other named "
+"nodes in the path.\n"
+"You will usually just pass a string to [method Node.get_node] and it will be "
+"automatically converted, but you may occasionally want to parse a path ahead "
+"of time with [NodePath] or the literal syntax [code]@\"path\"[/code]. "
+"Exporting a [NodePath] variable will give you a node selection widget in the "
+"properties panel of the editor, which can often be useful.\n"
+"A [NodePath] is composed of a list of slash-separated node names (like a "
+"filesystem path) and an optional colon-separated list of \"subnames\" which "
+"can be resources or properties.\n"
+"Some examples of NodePaths include the following:\n"
+"[codeblock]\n"
+"# No leading slash means it is relative to the current node.\n"
+"@\"A\" # Immediate child A\n"
+"@\"A/B\" # A's child B\n"
+"@\".\" # The current node.\n"
+"@\"..\" # The parent node.\n"
+"@\"../C\" # A sibling node C.\n"
+"# A leading slash means it is absolute from the SceneTree.\n"
+"@\"/root\" # Equivalent to get_tree().get_root().\n"
+"@\"/root/Main\" # If your main scene's root node were named \"Main\".\n"
+"@\"/root/MyAutoload\" # If you have an autoloaded node or scene.\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:33
+msgid ""
+"Creates a NodePath from a string, e.g. [code]\"Path2D/PathFollow2D/Sprite2D:"
+"texture:size\"[/code]. A path is absolute if it starts with a slash. "
+"Absolute paths are only valid in the global scene tree, not within "
+"individual scenes. In a relative path, [code]\".\"[/code] and [code]\"..\"[/"
+"code] indicate the current node and its parent.\n"
+"The \"subnames\" optionally included after the path to the target node can "
+"point to resources or properties, and can also be nested.\n"
+"Examples of valid NodePaths (assuming that those nodes exist and have the "
+"referenced resources or properties):\n"
+"[codeblock]\n"
+"# Points to the Sprite2D node\n"
+"\"Path2D/PathFollow2D/Sprite2D\"\n"
+"# Points to the Sprite2D node and its \"texture\" resource.\n"
+"# get_node() would retrieve \"Sprite2D\", while get_node_and_resource()\n"
+"# would retrieve both the Sprite2D node and the \"texture\" resource.\n"
+"\"Path2D/PathFollow2D/Sprite2D:texture\"\n"
+"# Points to the Sprite2D node and its \"position\" property.\n"
+"\"Path2D/PathFollow2D/Sprite2D:position\"\n"
+"# Points to the Sprite2D node and the \"x\" component of its \"position\" "
+"property.\n"
+"\"Path2D/PathFollow2D/Sprite2D:position:x\"\n"
+"# Absolute path (from \"root\")\n"
+"\"/root/Level/Path2D\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:56
+msgid ""
+"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).\n"
+"[codeblock]\n"
+"# This will be parsed as a node path to the \"x\" property in the \"position"
+"\" node\n"
+"var node_path = NodePath(\"position:x\")\n"
+"# This will be parsed as a node path to the \"x\" component of the \"position"
+"\" property in the current node\n"
+"var property_path = node_path.get_as_property_path()\n"
+"print(property_path) # :position:x\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:70
+msgid ""
+"Returns all subnames concatenated with a colon character ([code]:[/code]) as "
+"separator, i.e. the right side of the first colon in a node path.\n"
+"[codeblock]\n"
+"var nodepath = NodePath(\"Path2D/PathFollow2D/Sprite2D:texture:load_path\")\n"
+"print(nodepath.get_concatenated_subnames()) # texture:load_path\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:83
+msgid ""
+"Gets the node name indicated by [code]idx[/code] (0 to [method "
+"get_name_count]).\n"
+"[codeblock]\n"
+"var node_path = NodePath(\"Path2D/PathFollow2D/Sprite2D\")\n"
+"print(node_path.get_name(0)) # Path2D\n"
+"print(node_path.get_name(1)) # PathFollow2D\n"
+"print(node_path.get_name(2)) # Sprite\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:96
+msgid ""
+"Gets the number of node names which make up the path. Subnames (see [method "
+"get_subname_count]) are not included.\n"
+"For example, [code]\"Path2D/PathFollow2D/Sprite2D\"[/code] has 3 names."
+msgstr ""
+
+#: doc/classes/NodePath.xml:106
+msgid ""
+"Gets the resource or property name indicated by [code]idx[/code] (0 to "
+"[method get_subname_count]).\n"
+"[codeblock]\n"
+"var node_path = NodePath(\"Path2D/PathFollow2D/Sprite2D:texture:load_path"
+"\")\n"
+"print(node_path.get_subname(0)) # texture\n"
+"print(node_path.get_subname(1)) # load_path\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/NodePath.xml:118
+msgid ""
+"Gets the number of resource or property names (\"subnames\") in the path. "
+"Each subname is listed after a colon character ([code]:[/code]) in the node "
+"path.\n"
+"For example, [code]\"Path2D/PathFollow2D/Sprite2D:texture:load_path\"[/code] "
+"has 2 subnames."
+msgstr ""
+
+#: doc/classes/NodePath.xml:126
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/NodePath.xml:133
+msgid "Returns [code]true[/code] if the node path is empty."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:4
+msgid "[OpenSimplexNoise] filled texture."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:7
+msgid ""
+"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.\n"
+"NoiseTexture can also generate normalmap textures.\n"
+"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:\n"
+"[codeblock]\n"
+"var texture = preload(\"res://noise.tres\")\n"
+"yield(texture, \"changed\")\n"
+"var image = texture.get_data()\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:22
+msgid ""
+"If [code]true[/code], the resulting texture contains a normal map created "
+"from the original noise interpreted as a bump map."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:25
+msgid ""
+"Strength of the bump maps used in this texture. A higher value will make the "
+"bump maps appear larger while a lower value will make them appear softer."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:28
+msgid "Height of the generated texture."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:31
+msgid "The [OpenSimplexNoise] instance used to generate the noise."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:34
+msgid ""
+"Whether the texture can be tiled without visible seams or not. Seamless "
+"textures take longer to generate."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/NoiseTexture.xml:37
+msgid "Width of the generated texture."
+msgstr ""
+
+#: doc/classes/Object.xml:4
+msgid "Base class for all non built-in types."
+msgstr ""
+
+#: doc/classes/Object.xml:7
+msgid ""
+"Every class which is not a built-in type inherits from this class.\n"
+"You can construct Objects from scripting languages, using [code]Object.new()"
+"[/code] in GDScript, [code]new Object[/code] in C#, or the \"Construct Object"
+"\" node in VisualScript.\n"
+"Objects do not manage memory. If a class inherits from Object, you will have "
+"to delete instances of it manually. To do so, call the [method free] method "
+"from your script or delete the instance from C++.\n"
+"Some classes that extend Object add memory management. This is the case of "
+"[Reference], which counts references and deletes itself automatically when "
+"no longer referenced. [Node], another fundamental type, deletes all its "
+"children when freed from memory.\n"
+"Objects export properties, which are mainly useful for storage and editing, "
+"but not really so much in programming. Properties are exported in [method "
+"_get_property_list] and handled in [method _get] and [method _set]. However, "
+"scripting languages and C++ have simpler means to export them.\n"
+"Property membership can be tested directly in GDScript using [code]in[/"
+"code]:\n"
+"[codeblock]\n"
+"var n = Node2D.new()\n"
+"print(\"position\" in n) # Prints \"True\".\n"
+"print(\"other_property\" in n) # Prints \"False\".\n"
+"[/codeblock]\n"
+"Objects also receive notifications. Notifications are a simple way to notify "
+"the object about different events, so they can all be handled together. See "
+"[method _notification]."
+msgstr ""
+
+#: doc/classes/Object.xml:29
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method get].\n"
+"Returns the given property. Returns [code]null[/code] if the [code]property[/"
+"code] does not exist."
+msgstr ""
+
+#: doc/classes/Object.xml:37
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method get_property_list].\n"
+"Returns the object's property list as an [Array] of dictionaries.\n"
+"Each property's [Dictionary] must contain at least [code]name: String[/code] "
+"and [code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it "
+"can also include [code]hint: int[/code] (see [enum PropertyHint]), "
+"[code]hint_string: String[/code], and [code]usage: int[/code] (see [enum "
+"PropertyUsageFlags])."
+msgstr ""
+
+#: doc/classes/Object.xml:46
+msgid "Called when the object is initialized."
+msgstr ""
+
+#: doc/classes/Object.xml:55
+msgid ""
+"Called whenever the object receives a notification, which is identified in "
+"[code]what[/code] by a constant. The base [Object] has two constants "
+"[constant NOTIFICATION_POSTINITIALIZE] and [constant "
+"NOTIFICATION_PREDELETE], but subclasses such as [Node] define a lot more "
+"notifications which are also received by this method."
+msgstr ""
+
+#: doc/classes/Object.xml:66
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method set].\n"
+"Sets a property. Returns [code]true[/code] if the [code]property[/code] "
+"exists."
+msgstr ""
+
+#: doc/classes/Object.xml:74
+msgid ""
+"Virtual method which can be overridden to customize the return value of "
+"[method to_string], and thus the object's representation where it is "
+"converted to a string, e.g. with [code]print(obj)[/code].\n"
+"Returns a [String] representing the object. If not overridden, defaults to "
+"[code]\"[ClassName:RID]\"[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:86
+msgid ""
+"Adds a user-defined [code]signal[/code]. Arguments are optional, but can be "
+"added as an [Array] of dictionaries, each containing [code]name: String[/"
+"code] and [code]type: int[/code] (see [enum Variant.Type]) entries."
+msgstr ""
+
+#: doc/classes/Object.xml:95
+msgid ""
+"Calls the [code]method[/code] on the object and returns the result. This "
+"method supports a variable number of arguments, so parameters are passed as "
+"a comma separated list. Example:\n"
+"[codeblock]\n"
+"call(\"set\", \"position\", Vector2(42.0, 0.0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:107
+msgid ""
+"Calls the [code]method[/code] on the object during idle time. This method "
+"supports a variable number of arguments, so parameters are passed as a comma "
+"separated list. Example:\n"
+"[codeblock]\n"
+"call_deferred(\"set\", \"position\", Vector2(42.0, 0.0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:121
+msgid ""
+"Calls the [code]method[/code] on the object and returns the result. "
+"Contrarily to [method call], this method does not support a variable number "
+"of arguments but expects all parameters to be via a single [Array].\n"
+"[codeblock]\n"
+"callv(\"set\", [ \"position\", Vector2(42.0, 0.0) ])\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:131
+msgid ""
+"Returns [code]true[/code] if the object can translate strings. See [method "
+"set_message_translation] and [method tr]."
+msgstr ""
+
+#: doc/classes/Object.xml:146
+msgid ""
+"[b]FIXME:[/b] The syntax changed with the addition of [Callable], this "
+"should be updated.\n"
+"Connects a [code]signal[/code] to a [code]method[/code] on a [code]target[/"
+"code] object. Pass optional [code]binds[/code] to the call as an [Array] of "
+"parameters. These parameters will be passed to the 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.\n"
+"A [code]signal[/code] can only be connected once to a [code]method[/code]. "
+"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.\n"
+"If the [code]target[/code] is destroyed in the game's lifecycle, the "
+"connection will be lost.\n"
+"Examples:\n"
+"[codeblock]\n"
+"connect(\"pressed\", self, \"_on_Button_pressed\") # BaseButton signal\n"
+"connect(\"text_entered\", self, \"_on_LineEdit_text_entered\") # LineEdit "
+"signal\n"
+"connect(\"hit\", self, \"_on_Player_hit\", [ weapon_type, damage ]) # User-"
+"defined signal\n"
+"[/codeblock]\n"
+"An example of the relationship between [code]binds[/code] passed to [method "
+"connect] and parameters used when calling [method emit_signal]:\n"
+"[codeblock]\n"
+"connect(\"hit\", self, \"_on_Player_hit\", [ weapon_type, damage ]) # "
+"weapon_type and damage are passed last\n"
+"emit_signal(\"hit\", \"Dark lord\", 5) # \"Dark lord\" and 5 are passed "
+"first\n"
+"func _on_Player_hit(hit_by, level, weapon_type, damage):\n"
+" print(\"Hit by %s (lvl %d) with weapon %s for %d damage\" % [hit_by, "
+"level, weapon_type, damage])\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:173
+msgid ""
+"[b]FIXME:[/b] The syntax changed with the addition of [Callable], this "
+"should be updated.\n"
+"Disconnects a [code]signal[/code] from a [code]method[/code] on the given "
+"[code]target[/code].\n"
+"If you try to disconnect a connection that does not exist, the method will "
+"throw an error. Use [method is_connected] to ensure that the connection "
+"exists."
+msgstr ""
+
+#: doc/classes/Object.xml:184
+msgid ""
+"Emits the given [code]signal[/code]. The signal must exist, so it should be "
+"a built-in signal of this class or one of its parent classes, or a user-"
+"defined signal. This method supports a variable number of arguments, so "
+"parameters are passed as a comma separated list. Example:\n"
+"[codeblock]\n"
+"emit_signal(\"hit\", weapon_type, damage)\n"
+"emit_signal(\"game_over\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:195
+msgid ""
+"Deletes the object from memory. Any pre-existing reference to the freed "
+"object will now return [code]null[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:204
+msgid ""
+"Returns the [Variant] value of the given [code]property[/code]. If the "
+"[code]property[/code] doesn't exist, this will return [code]null[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:211
+msgid "Returns the object's class as a [String]."
+msgstr ""
+
+#: doc/classes/Object.xml:218
+msgid ""
+"Returns an [Array] of dictionaries with information about signals that are "
+"connected to the object.\n"
+"Each [Dictionary] contains three String entries:\n"
+"- [code]source[/code] is a reference to the signal emitter.\n"
+"- [code]signal_name[/code] is the name of the connected signal.\n"
+"- [code]method_name[/code] is the name of the method to which the signal is "
+"connected."
+msgstr ""
+
+#: doc/classes/Object.xml:231
+msgid ""
+"Gets the object's property indexed by the given [NodePath]. The node path "
+"should be relative to the current object and can use the colon character "
+"([code]:[/code]) to access nested properties. Examples: [code]\"position:x"
+"\"[/code] or [code]\"material:next_pass:blend_mode\"[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:238
+msgid ""
+"Returns the object's unique instance ID.\n"
+"This ID can be saved in [EncodedObjectAsID], and can be used to retrieve the "
+"object instance with [method @GDScript.instance_from_id]."
+msgstr ""
+
+#: doc/classes/Object.xml:248
+msgid "Returns the object's metadata entry for the given [code]name[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:255
+msgid "Returns the object's metadata as a [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/Object.xml:262
+msgid "Returns the object's methods and their signatures as an [Array]."
+msgstr ""
+
+#: doc/classes/Object.xml:269
+msgid ""
+"Returns the object's property list as an [Array] of dictionaries.\n"
+"Each property's [Dictionary] contain at least [code]name: String[/code] and "
+"[code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it can "
+"also include [code]hint: int[/code] (see [enum PropertyHint]), "
+"[code]hint_string: String[/code], and [code]usage: int[/code] (see [enum "
+"PropertyUsageFlags])."
+msgstr ""
+
+#: doc/classes/Object.xml:277
+msgid ""
+"Returns the object's [Script] instance, or [code]null[/code] if none is "
+"assigned."
+msgstr ""
+
+#: doc/classes/Object.xml:286
+msgid "Returns an [Array] of connections for the given [code]signal[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:293
+msgid "Returns the list of signals as an [Array] of dictionaries."
+msgstr ""
+
+#: doc/classes/Object.xml:302
+msgid ""
+"Returns [code]true[/code] if a metadata entry is found with the given "
+"[code]name[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:311
+msgid ""
+"Returns [code]true[/code] if the object contains the given [code]method[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Object.xml:320
+msgid "Returns [code]true[/code] if the given [code]signal[/code] exists."
+msgstr ""
+
+#: doc/classes/Object.xml:329
+msgid ""
+"Returns [code]true[/code] if the given user-defined [code]signal[/code] "
+"exists. Only signals added using [method add_user_signal] are taken into "
+"account."
+msgstr ""
+
+#: doc/classes/Object.xml:336
+msgid "Returns [code]true[/code] if signal emission blocking is enabled."
+msgstr ""
+
+#: doc/classes/Object.xml:345
+msgid ""
+"Returns [code]true[/code] if the object inherits from the given [code]class[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Object.xml:356
+msgid ""
+"[b]FIXME:[/b] The syntax changed with the addition of [Callable], this "
+"should be updated.\n"
+"Returns [code]true[/code] if a connection exists for a given [code]signal[/"
+"code], [code]target[/code], and [code]method[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:364
+msgid ""
+"Returns [code]true[/code] if the [method Node.queue_free] method was called "
+"for the object."
+msgstr ""
+
+#: doc/classes/Object.xml:375
+msgid ""
+"Send a given notification to the object, which will also trigger a call to "
+"the [method _notification] method of all classes that the object inherits "
+"from.\n"
+"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."
+msgstr ""
+
+#: doc/classes/Object.xml:383
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Object.xml:392
+msgid "Removes a given entry from the object's metadata."
+msgstr ""
+
+#: doc/classes/Object.xml:403
+msgid ""
+"Assigns a new value to the given property. If the [code]property[/code] does "
+"not exist, nothing will happen."
+msgstr ""
+
+#: doc/classes/Object.xml:412
+msgid "If set to [code]true[/code], signal emission is blocked."
+msgstr ""
+
+#: doc/classes/Object.xml:423
+msgid ""
+"Assigns a new value to the given property, after the current frame's physics "
+"step. This is equivalent to calling [method set] via [method call_deferred], "
+"i.e. [code]call_deferred(\"set\", property, value)[/code]."
+msgstr ""
+
+#: doc/classes/Object.xml:434
+msgid ""
+"Assigns a new value to the property identified by the [NodePath]. The node "
+"path should be relative to the current object and can use the colon "
+"character ([code]:[/code]) to access nested properties. Example:\n"
+"[codeblock]\n"
+"set_indexed(\"position\", Vector2(42, 0))\n"
+"set_indexed(\"position:y\", -10)\n"
+"print(position) # (42, -10)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Object.xml:448
+msgid ""
+"Defines whether the object can translate strings (with calls to [method "
+"tr]). Enabled by default."
+msgstr ""
+
+#: doc/classes/Object.xml:459
+msgid ""
+"Adds or changes a given entry in the object's metadata. Metadata are "
+"serialized, and can take any [Variant] value."
+msgstr ""
+
+#: doc/classes/Object.xml:468
+msgid ""
+"Assigns a script to the object. Each object can have a single script "
+"assigned to it, which are used to extend its functionality.\n"
+"If the object already had a script, the previous script instance will be "
+"freed and its variables and state will be lost. The new script's [method "
+"_init] method will be called."
+msgstr ""
+
+#: doc/classes/Object.xml:476
+msgid ""
+"Returns a [String] representing the object. If not overridden, defaults to "
+"[code]\"[ClassName:RID]\"[/code].\n"
+"Override the method [method _to_string] to customize the [String] "
+"representation."
+msgstr ""
+
+#: doc/classes/Object.xml:486
+msgid ""
+"Translates a message using translation catalogs configured in the Project "
+"Settings.\n"
+"Only works if message translation is enabled (which it is by default), "
+"otherwise it returns the [code]message[/code] unchanged. See [method "
+"set_message_translation]."
+msgstr ""
+
+#: doc/classes/Object.xml:494
+msgid "Emitted whenever the object's script is changed."
+msgstr ""
+
+#: doc/classes/Object.xml:500
+msgid "Called right when the object is initialized. Not available in script."
+msgstr ""
+
+#: doc/classes/Object.xml:503
+msgid "Called before the object is about to be deleted."
+msgstr ""
+
+#: doc/classes/Object.xml:506
+msgid ""
+"Connects a signal in deferred mode. This way, signal emissions are stored in "
+"a queue, then set on idle time."
+msgstr ""
+
+#: doc/classes/Object.xml:509
+msgid "Persisting connections are saved when the object is serialized to file."
+msgstr ""
+
+#: doc/classes/Object.xml:512
+msgid "One-shot connections disconnect themselves after emission."
+msgstr ""
+
+#: doc/classes/Object.xml:515
+msgid ""
+"Connect a signal as reference counted. This means that a given signal can be "
+"connected several times to the same target, and will only be fully "
+"disconnected once no references are left."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:4
+msgid "Defines a 2D polygon for LightOccluder2D."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:7
+msgid ""
+"Editor facility that helps you draw a 2D polygon used as resource for "
+"[LightOccluder2D]."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:15
+msgid ""
+"If [code]true[/code], closes the polygon. A closed OccluderPolygon2D "
+"occludes the light coming from any direction. An opened OccluderPolygon2D "
+"occludes the light only at its outline's direction."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:18
+msgid "The culling mode to use."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:21
+msgid ""
+"A [Vector2] array with the index for polygon's vertices positions.\n"
+"[b]Note:[/b] The returned value is a copy of the underlying array, rather "
+"than a reference."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:27
+msgid "Culling is disabled. See [member cull_mode]."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:30
+msgid ""
+"Culling is performed in the clockwise direction. See [member cull_mode]."
+msgstr ""
+
+#: doc/classes/OccluderPolygon2D.xml:33
+msgid ""
+"Culling is performed in the counterclockwise direction. See [member "
+"cull_mode]."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:4
+msgid "Omnidirectional light, such as a light bulb or a candle."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:7
+msgid ""
+"An Omnidirectional light is a type of [Light3D] that emits light in all "
+"directions. The light is attenuated by distance and this attenuation can be "
+"configured by changing its energy, radius, and attenuation parameters."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:16
+msgid ""
+"The light's attenuation (drop-off) curve. A number of presets are available "
+"in the [b]Inspector[/b] by right-clicking the curve."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:19
+msgid "The light's radius."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:22
+msgid "See [enum ShadowMode]."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:27
+msgid ""
+"Shadows are rendered to a dual-paraboloid texture. Faster than [constant "
+"SHADOW_CUBE], but lower-quality."
+msgstr ""
+
+#: doc/classes/OmniLight3D.xml:30
+msgid ""
+"Shadows are rendered to a cubemap. Slower than [constant "
+"SHADOW_DUAL_PARABOLOID], but higher-quality."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:4
+msgid "Noise generator based on Open Simplex."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:7
+msgid ""
+"This resource allows you to configure and sample a fractal noise space. Here "
+"is a brief usage example that configures an OpenSimplexNoise and gets "
+"samples at various positions and dimensions:\n"
+"[codeblock]\n"
+"var noise = OpenSimplexNoise.new()\n"
+"\n"
+"# Configure\n"
+"noise.seed = randi()\n"
+"noise.octaves = 4\n"
+"noise.period = 20.0\n"
+"noise.persistence = 0.8\n"
+"\n"
+"# Sample\n"
+"print(\"Values:\")\n"
+"print(noise.get_noise_2d(1.0, 1.0))\n"
+"print(noise.get_noise_3d(0.5, 3.0, 15.0))\n"
+"print(noise.get_noise_4d(0.5, 1.9, 4.7, 0.0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:35
+msgid ""
+"Generate a noise image with the requested [code]width[/code] and "
+"[code]height[/code], based on the current noise parameters."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:44
+msgid ""
+"Returns the 1D noise value [code][-1,1][/code] at the given x-coordinate.\n"
+"[b]Note:[/b] This method actually returns the 2D noise value [code][-1,1][/"
+"code] with fixed y-coordinate value 0.0."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:56
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:65
+msgid "Returns the 2D noise value [code][-1,1][/code] at the given position."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:78
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:87
+msgid "Returns the 3D noise value [code][-1,1][/code] at the given position."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:102
+msgid "Returns the 4D noise value [code][-1,1][/code] at the given position."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:111
+msgid ""
+"Generate a tileable noise image, based on the current noise parameters. "
+"Generated seamless images are always square ([code]size[/code] × [code]size[/"
+"code])."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:117
+msgid "Difference in period between [member octaves]."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:120
+msgid ""
+"Number of OpenSimplex noise layers that are sampled to get the fractal "
+"noise. Higher values result in more detailed noise but take more time to "
+"generate.\n"
+"[b]Note:[/b] The maximum allowed value is 9."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:124
+msgid ""
+"Period of the base octave. A lower period results in a higher-frequency "
+"noise (more value changes across the same distance)."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:127
+msgid ""
+"Contribution factor of the different octaves. A [code]persistence[/code] "
+"value of 1 means all the octaves have the same contribution, a value of 0.5 "
+"means each octave contributes half as much as the previous one."
+msgstr ""
+
+#: modules/opensimplex/doc_classes/OpenSimplexNoise.xml:130
+msgid ""
+"Seed used to generate random values, different seeds will generate different "
+"noise maps."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:4
+msgid "Button control that provides selectable options when pressed."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:7
+msgid ""
+"OptionButton is a type button that provides a selectable list of items when "
+"pressed. The item selected becomes the \"current\" item and is displayed as "
+"the button text."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:22
+msgid ""
+"Adds an item, with a [code]texture[/code] icon, text [code]label[/code] and "
+"(optionally) [code]id[/code]. If no [code]id[/code] is passed, the item "
+"index will be used as the item's ID. New items are appended at the end."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:33
+msgid ""
+"Adds an item, with text [code]label[/code] and (optionally) [code]id[/code]. "
+"If no [code]id[/code] is passed, the item index will be used as the item's "
+"ID. New items are appended at the end."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:40
+msgid ""
+"Adds a separator to the list of items. Separators help to group items. "
+"Separator also takes up an index and is appended at the end."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:47
+msgid "Clears all the items in the [OptionButton]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:54
+msgid "Returns the amount of items in the OptionButton, including separators."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:63 doc/classes/PopupMenu.xml:267
+msgid "Returns the icon of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:72
+msgid "Returns the ID of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:81
+msgid "Returns the index of the item with the given [code]id[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:90
+msgid ""
+"Retrieves the metadata of an item. Metadata may be any type and can be used "
+"to store extra information about an item, such as an external string ID."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:99 doc/classes/PopupMenu.xml:321
+msgid "Returns the text of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:113
+msgid ""
+"Returns the ID of the selected item, or [code]0[/code] if no item is "
+"selected."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:120
+msgid ""
+"Gets the metadata of the selected item. Metadata for items can be set using "
+"[method set_item_metadata]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:129
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:138
+msgid "Removes the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:147
+msgid ""
+"Selects an item by index and makes it the current item. This will work even "
+"if the item is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:158
+msgid ""
+"Sets whether the item at index [code]idx[/code] is disabled.\n"
+"Disabled items are drawn differently in the dropdown and are not selectable "
+"by the user. If the current selected item is set as disabled, it will remain "
+"selected."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:170
+msgid "Sets the icon of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:181
+msgid "Sets the ID of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:192
+msgid ""
+"Sets the metadata of an item. Metadata may be of any type and can be used to "
+"store extra information about an item, such as an external string ID."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:203 doc/classes/PopupMenu.xml:554
+msgid "Sets the text of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:211
+msgid ""
+"The index of the currently selected item, or [code]-1[/code] if no item is "
+"selected."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:220
+msgid ""
+"Emitted the when user navigates to an item using the [code]ui_up[/code] or "
+"[code]ui_down[/code] actions. The index of the item selected is passed as "
+"argument."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:227
+msgid ""
+"Emitted when the current item has been changed by the user. The index of the "
+"item selected is passed as argument."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:235
+msgid "The arrow icon to be drawn on the right end of the button."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:238
+msgid ""
+"The horizontal space between the arrow icon and the right edge of the button."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:241
+msgid "[StyleBox] used when the [OptionButton] is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:244
+msgid ""
+"[StyleBox] used when the [OptionButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:247
+msgid "[Font] of the [OptionButton]'s text."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:250
+msgid "Default text [Color] of the [OptionButton]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:253
+msgid "Text [Color] used when the [OptionButton] is disabled."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:256
+msgid "Text [Color] used when the [OptionButton] is being hovered."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:259
+msgid "Text [Color] used when the [OptionButton] is being pressed."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:262
+msgid "[StyleBox] used when the [OptionButton] is being hovered."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:265
+msgid "The horizontal space between [OptionButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:268
+msgid "Default [StyleBox] for the [OptionButton]."
+msgstr ""
+
+#: doc/classes/OptionButton.xml:271
+msgid "[StyleBox] used when the [OptionButton] is being pressed."
+msgstr ""
+
+#: doc/classes/OS.xml:4
+msgid "Operating System functions."
+msgstr ""
+
+#: doc/classes/OS.xml:7
+msgid ""
+"Operating System functions. OS wraps the most common functionality to "
+"communicate with the host operating system, such as the clipboard, video "
+"driver, date and time, timers, environment variables, execution of binaries, "
+"command line, etc."
+msgstr ""
+
+#: doc/classes/OS.xml:16
+msgid ""
+"Returns [code]true[/code] if the current host platform is using multiple "
+"threads."
+msgstr ""
+
+#: doc/classes/OS.xml:23
+msgid ""
+"Shuts down system MIDI driver.\n"
+"[b]Note:[/b] This method is implemented on Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:33
+msgid ""
+"Delay execution of the current thread by [code]msec[/code] milliseconds."
+msgstr ""
+
+#: doc/classes/OS.xml:42
+msgid ""
+"Delay execution of the current thread by [code]usec[/code] microseconds."
+msgstr ""
+
+#: doc/classes/OS.xml:51
+msgid ""
+"Dumps the memory allocation ringlist to a file (only works in debug).\n"
+"Entry format per line: \"Address - Size - Description\"."
+msgstr ""
+
+#: doc/classes/OS.xml:61
+msgid ""
+"Dumps all used resources to file (only works in debug).\n"
+"Entry format per line: \"Resource Type : Resource Location\".\n"
+"At the end of the file is a statistic of all used Resource Types."
+msgstr ""
+
+#: doc/classes/OS.xml:80
+msgid ""
+"Execute the file at the given path with the arguments passed as an array of "
+"strings. Platform path resolution will take place. The resolved file must "
+"exist and be executable.\n"
+"The arguments are used in the given order and separated by a space, so "
+"[code]OS.execute(\"ping\", [\"-w\", \"3\", \"godotengine.org\"], false)[/"
+"code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's "
+"shell.\n"
+"This method has slightly different behavior based on whether the "
+"[code]blocking[/code] mode is enabled.\n"
+"If [code]blocking[/code] is [code]true[/code], the Godot thread will pause "
+"its execution while waiting for the process to terminate. The shell output "
+"of the process will be written to the [code]output[/code] array as a single "
+"string. When the process terminates, the Godot thread will resume "
+"execution.\n"
+"If [code]blocking[/code] is [code]false[/code], the Godot thread will "
+"continue while the new process runs. It is not possible to retrieve the "
+"shell output in non-blocking mode, so [code]output[/code] will be empty.\n"
+"The return value also depends on the blocking mode. When blocking, the "
+"method will return an exit code of the process. When non-blocking, the "
+"method returns a process ID, which you can use to monitor the process (and "
+"potentially terminate it with [method kill]). If the process forking (non-"
+"blocking) or opening (blocking) fails, the method will return [code]-1[/"
+"code] or another exit code.\n"
+"Example of blocking mode and retrieving the shell output:\n"
+"[codeblock]\n"
+"var output = []\n"
+"var exit_code = OS.execute(\"ls\", [\"-l\", \"/tmp\"], true, output)\n"
+"[/codeblock]\n"
+"Example of non-blocking mode, running another instance of the project and "
+"storing its process ID:\n"
+"[codeblock]\n"
+"var pid = OS.execute(OS.get_executable_path(), [], false)\n"
+"[/codeblock]\n"
+"If you wish to access a shell built-in or perform a composite command, a "
+"platform-specific shell can be invoked. For example:\n"
+"[codeblock]\n"
+"OS.execute(\"CMD.exe\", [\"/C\", \"cd %TEMP% && dir\"], true, output)\n"
+"[/codeblock]\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and "
+"Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:108
+msgid "Returns the keycode of the given string (e.g. \"Escape\")."
+msgstr ""
+
+#: doc/classes/OS.xml:115
+msgid "Returns the command line arguments passed to the engine."
+msgstr ""
+
+#: doc/classes/OS.xml:122
+msgid ""
+"Returns an array of MIDI device names.\n"
+"The returned array will be empty if the system MIDI driver has not "
+"previously been initialised with [method open_midi_inputs].\n"
+"[b]Note:[/b] This method is implemented on Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:133
+msgid ""
+"Returns current date as a dictionary of keys: [code]year[/code], "
+"[code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] "
+"(Daylight Savings Time)."
+msgstr ""
+
+#: doc/classes/OS.xml:142
+msgid ""
+"Returns current datetime as a dictionary of keys: [code]year[/code], "
+"[code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] "
+"(Daylight Savings Time), [code]hour[/code], [code]minute[/code], "
+"[code]second[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:151
+msgid ""
+"Gets a dictionary of time values corresponding to the given UNIX epoch time "
+"(in seconds).\n"
+"The returned Dictionary's values will be the same as [method get_datetime], "
+"with the exception of Daylight Savings Time as it cannot be determined from "
+"the epoch."
+msgstr ""
+
+#: doc/classes/OS.xml:161
+msgid "Returns an environment variable."
+msgstr ""
+
+#: doc/classes/OS.xml:168
+msgid "Returns the path to the current engine executable."
+msgstr ""
+
+#: doc/classes/OS.xml:175
+msgid ""
+"With this function you can get the list of dangerous permissions that have "
+"been granted to the Android application.\n"
+"[b]Note:[/b] This method is implemented on Android."
+msgstr ""
+
+#: doc/classes/OS.xml:185
+msgid ""
+"Returns the given keycode as a string (e.g. Return values: [code]\"Escape\"[/"
+"code], [code]\"Shift+Escape\"[/code]).\n"
+"See also [member InputEventKey.keycode] and [method InputEventKey."
+"get_keycode_with_modifiers]."
+msgstr ""
+
+#: doc/classes/OS.xml:193
+msgid "Returns the host OS locale."
+msgstr ""
+
+#: doc/classes/OS.xml:200
+msgid ""
+"Returns the model name of the current device.\n"
+"[b]Note:[/b] This method is implemented on Android and iOS. Returns "
+"[code]\"GenericDevice\"[/code] on unsupported platforms."
+msgstr ""
+
+#: doc/classes/OS.xml:208
+msgid ""
+"Returns the name of the host OS. Possible values are: [code]\"Android\"[/"
+"code], [code]\"Haiku\"[/code], [code]\"iOS\"[/code], [code]\"HTML5\"[/code], "
+"[code]\"OSX\"[/code], [code]\"Server\"[/code], [code]\"Windows\"[/code], "
+"[code]\"UWP\"[/code], [code]\"X11\"[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:215
+msgid ""
+"Returns the project's process ID.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and "
+"Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:223
+msgid "Returns the number of threads available on the host machine."
+msgstr ""
+
+#: doc/classes/OS.xml:230
+msgid ""
+"Returns the amount of time in milliseconds it took for the boot logo to "
+"appear."
+msgstr ""
+
+#: doc/classes/OS.xml:237
+msgid "Returns the maximum amount of static memory used (only works in debug)."
+msgstr ""
+
+#: doc/classes/OS.xml:244
+msgid "Returns the amount of static memory being used by the program in bytes."
+msgstr ""
+
+#: doc/classes/OS.xml:253
+msgid ""
+"Returns the actual path to commonly used folders across different platforms. "
+"Available locations are specified in [enum SystemDir].\n"
+"[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:261
+msgid "Returns the epoch time of the operating system in milliseconds."
+msgstr ""
+
+#: doc/classes/OS.xml:268
+msgid "Returns the epoch time of the operating system in seconds."
+msgstr ""
+
+#: doc/classes/OS.xml:275
+msgid ""
+"Returns the amount of time passed in milliseconds since the engine started."
+msgstr ""
+
+#: doc/classes/OS.xml:282
+msgid ""
+"Returns the amount of time passed in microseconds since the engine started."
+msgstr ""
+
+#: doc/classes/OS.xml:291
+msgid "Returns current time as a dictionary of keys: hour, minute, second."
+msgstr ""
+
+#: doc/classes/OS.xml:298
+msgid ""
+"Returns the current time zone as a dictionary with the keys: bias and name."
+msgstr ""
+
+#: doc/classes/OS.xml:305
+msgid ""
+"Returns a string that is unique to the device.\n"
+"[b]Note:[/b] Returns an empty string on HTML5 and UWP, as this method isn't "
+"implemented on those platforms yet."
+msgstr ""
+
+#: doc/classes/OS.xml:313
+msgid "Returns the current UNIX epoch timestamp."
+msgstr ""
+
+#: doc/classes/OS.xml:322
+msgid ""
+"Gets an epoch time value from a dictionary of time values.\n"
+"[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].\n"
+"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."
+msgstr ""
+
+#: doc/classes/OS.xml:331
+msgid ""
+"Returns the absolute directory path where user data is written ([code]user://"
+"[/code]).\n"
+"On Linux, this is [code]~/.local/share/godot/app_userdata/[project_name][/"
+"code], or [code]~/.local/share/[custom_name][/code] if "
+"[code]use_custom_user_dir[/code] is set.\n"
+"On macOS, this is [code]~/Library/Application Support/Godot/app_userdata/"
+"[project_name][/code], or [code]~/Library/Application Support/[custom_name][/"
+"code] if [code]use_custom_user_dir[/code] is set.\n"
+"On Windows, this is [code]%APPDATA%\\Godot\\app_userdata\\[project_name][/"
+"code], or [code]%APPDATA%\\[custom_name][/code] if "
+"[code]use_custom_user_dir[/code] is set. [code]%APPDATA%[/code] expands to "
+"[code]%USERPROFILE%\\AppData\\Roaming[/code].\n"
+"If the project name is empty, [code]user://[/code] falls back to [code]res://"
+"[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:344
+msgid "Returns [code]true[/code] if an environment variable exists."
+msgstr ""
+
+#: doc/classes/OS.xml:353
+msgid ""
+"Returns [code]true[/code] if the feature for the given feature tag is "
+"supported in the currently running instance, depending on platform, build "
+"etc. Can be used to check whether you're currently running a debug build, on "
+"a certain platform or arch, etc. Refer to the [url=https://docs.godotengine."
+"org/en/latest/getting_started/workflow/export/feature_tags.html]Feature "
+"Tags[/url] documentation for more details.\n"
+"[b]Note:[/b] Tag names are case-sensitive."
+msgstr ""
+
+#: doc/classes/OS.xml:361
+msgid ""
+"Returns [code]true[/code] if the Godot binary used to run the project is a "
+"[i]debug[/i] export template, or when running in the editor.\n"
+"Returns [code]false[/code] if the Godot binary used to run the project is a "
+"[i]release[/i] export template.\n"
+"To check whether the Godot binary used to run the project is an export "
+"template (debug or release), use [code]OS.has_feature(\"standalone\")[/code] "
+"instead."
+msgstr ""
+
+#: doc/classes/OS.xml:372
+msgid ""
+"Returns [code]true[/code] if the input keycode corresponds to a Unicode "
+"character."
+msgstr ""
+
+#: doc/classes/OS.xml:379
+msgid ""
+"Returns [code]true[/code] if the engine was executed with [code]-v[/code] "
+"(verbose stdout)."
+msgstr ""
+
+#: doc/classes/OS.xml:386
+msgid ""
+"If [code]true[/code], the [code]user://[/code] file system is persistent, so "
+"that its state is the same after a player quits and starts the game again. "
+"Relevant to the HTML5 platform, where this persistence may be unavailable."
+msgstr ""
+
+#: doc/classes/OS.xml:395
+msgid ""
+"Kill (terminate) the process identified by the given process ID ([code]pid[/"
+"code]), e.g. the one returned by [method execute] in non-blocking mode.\n"
+"[b]Note:[/b] This method can also be used to kill processes that were not "
+"spawned by the game.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and "
+"Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:404
+msgid ""
+"Initialises the singleton for the system MIDI driver.\n"
+"[b]Note:[/b] This method is implemented on Linux, macOS and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:414
+msgid ""
+"Shows all resources in the game. Optionally, the list can be written to a "
+"file by specifying a file path in [code]tofile[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:421
+msgid "Shows the list of loaded textures sorted by size in memory."
+msgstr ""
+
+#: doc/classes/OS.xml:430
+msgid "Shows the number of resources loaded by the game of the given types."
+msgstr ""
+
+#: doc/classes/OS.xml:439
+msgid "Shows all resources currently used by the game."
+msgstr ""
+
+#: doc/classes/OS.xml:448
+msgid ""
+"At the moment this function is only used by [code]AudioDriverOpenSL[/code] "
+"to request permission for [code]RECORD_AUDIO[/code] on Android."
+msgstr ""
+
+#: doc/classes/OS.xml:455
+msgid ""
+"With this function you can request dangerous permissions since normal "
+"permissions are automatically granted at install time in Android "
+"application.\n"
+"[b]Note:[/b] This method is implemented on Android."
+msgstr ""
+
+#: doc/classes/OS.xml:465
+msgid "Sets the name of the current thread."
+msgstr ""
+
+#: doc/classes/OS.xml:474
+msgid "Enables backup saves if [code]enabled[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/OS.xml:483
+msgid ""
+"Requests the OS to open a resource with the most appropriate program. For "
+"example:\n"
+"- [code]OS.shell_open(\"C:\\\\Users\\name\\Downloads\")[/code] on Windows "
+"opens the file explorer at the user's Downloads folder.\n"
+"- [code]OS.shell_open(\"https://godotengine.org\")[/code] opens the default "
+"web browser on the official Godot website.\n"
+"- [code]OS.shell_open(\"mailto:example@example.com\")[/code] opens the "
+"default email client with the \"To\" field set to [code]example@example.com[/"
+"code]. See [url=https://blog.escapecreative.com/customizing-mailto-"
+"links/]Customizing [code]mailto:[/code] Links[/url] for a list of fields "
+"that can be added.\n"
+"[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS "
+"and Windows."
+msgstr ""
+
+#: doc/classes/OS.xml:493
+msgid ""
+"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).\n"
+"[b]Note:[/b] This value will be ignored if using [method SceneTree.quit] "
+"with an [code]exit_code[/code] argument passed."
+msgstr ""
+
+#: doc/classes/OS.xml:497
+msgid ""
+"If [code]true[/code], the engine optimizes for low processor usage by only "
+"refreshing the screen if needed. Can improve battery consumption on mobile."
+msgstr ""
+
+#: doc/classes/OS.xml:500
+msgid ""
+"The amount of sleeping between frames when the low-processor usage mode is "
+"enabled (in microseconds). Higher values will result in lower CPU usage."
+msgstr ""
+
+#: doc/classes/OS.xml:505
+msgid ""
+"The GLES2 rendering backend. It uses OpenGL ES 2.0 on mobile devices, OpenGL "
+"2.1 on desktop platforms and WebGL 1.0 on the web."
+msgstr ""
+
+#: doc/classes/OS.xml:508
+msgid "The Vulkan rendering backend."
+msgstr ""
+
+#: doc/classes/OS.xml:511
+msgid "Sunday."
+msgstr ""
+
+#: doc/classes/OS.xml:514
+msgid "Monday."
+msgstr ""
+
+#: doc/classes/OS.xml:517
+msgid "Tuesday."
+msgstr ""
+
+#: doc/classes/OS.xml:520
+msgid "Wednesday."
+msgstr ""
+
+#: doc/classes/OS.xml:523
+msgid "Thursday."
+msgstr ""
+
+#: doc/classes/OS.xml:526
+msgid "Friday."
+msgstr ""
+
+#: doc/classes/OS.xml:529
+msgid "Saturday."
+msgstr ""
+
+#: doc/classes/OS.xml:532
+msgid "January."
+msgstr ""
+
+#: doc/classes/OS.xml:535
+msgid "February."
+msgstr ""
+
+#: doc/classes/OS.xml:538
+msgid "March."
+msgstr ""
+
+#: doc/classes/OS.xml:541
+msgid "April."
+msgstr ""
+
+#: doc/classes/OS.xml:544
+msgid "May."
+msgstr ""
+
+#: doc/classes/OS.xml:547
+msgid "June."
+msgstr ""
+
+#: doc/classes/OS.xml:550
+msgid "July."
+msgstr ""
+
+#: doc/classes/OS.xml:553
+msgid "August."
+msgstr ""
+
+#: doc/classes/OS.xml:556
+msgid "September."
+msgstr ""
+
+#: doc/classes/OS.xml:559
+msgid "October."
+msgstr ""
+
+#: doc/classes/OS.xml:562
+msgid "November."
+msgstr ""
+
+#: doc/classes/OS.xml:565
+msgid "December."
+msgstr ""
+
+#: doc/classes/OS.xml:568
+msgid "Desktop directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:571
+msgid "DCIM (Digital Camera Images) directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:574
+msgid "Documents directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:577
+msgid "Downloads directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:580
+msgid "Movies directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:583
+msgid "Music directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:586
+msgid "Pictures directory path."
+msgstr ""
+
+#: doc/classes/OS.xml:589
+msgid "Ringtones directory path."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:4
+msgid "A packed [Array] of bytes."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:7
+msgid ""
+"An [Array] specifically designed to hold bytes. Packs data tightly, so it "
+"saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:19
+msgid ""
+"Constructs a new [PackedByteArray]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:37
+msgid "Appends a [PackedByteArray] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:46
+msgid ""
+"Returns a new [PackedByteArray] with the data compressed. Set the "
+"compression mode using one of [enum File.CompressionMode]'s constants."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:57
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:71
+msgid ""
+"Returns a copy of the array's contents as [String]. Fast alternative to "
+"[method get_string_from_utf8] if the content is ASCII-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]."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:78
+msgid ""
+"Returns a copy of the array's contents as [String]. Slower than [method "
+"get_string_from_ascii] but supports UTF-8 encoded data. Use this function if "
+"you are unsure about the source of the data. For user input this function "
+"should always be preferred."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:85
+msgid ""
+"Returns a hexadecimal representation of this array as a [String].\n"
+"[codeblock]\n"
+"var array = PackedByteArray([11, 46, 255])\n"
+"print(array.hex_encode()) # Prints: 0b2eff\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:100 doc/classes/PackedColorArray.xml:55
+#: doc/classes/PackedFloat32Array.xml:56 doc/classes/PackedFloat64Array.xml:56
+#: doc/classes/PackedStringArray.xml:55 doc/classes/PackedVector2Array.xml:55
+#: doc/classes/PackedVector3Array.xml:55
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:134 doc/classes/PackedColorArray.xml:89
+#: doc/classes/PackedFloat32Array.xml:90 doc/classes/PackedFloat64Array.xml:90
+#: doc/classes/PackedInt32Array.xml:90 doc/classes/PackedInt64Array.xml:90
+#: doc/classes/PackedStringArray.xml:89 doc/classes/PackedVector2Array.xml:89
+#: doc/classes/PackedVector3Array.xml:89
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:145
+msgid "Changes the byte at the given index."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:152 doc/classes/PackedColorArray.xml:107
+#: doc/classes/PackedFloat32Array.xml:108
+#: doc/classes/PackedFloat64Array.xml:108 doc/classes/PackedStringArray.xml:107
+#: doc/classes/PackedVector2Array.xml:107
+#: doc/classes/PackedVector3Array.xml:107
+msgid "Returns the size of the array."
+msgstr ""
+
+#: doc/classes/PackedByteArray.xml:163
+msgid ""
+"Returns the slice of the [PackedByteArray] between indices (inclusive) as a "
+"new [PackedByteArray]. Any negative index is considered to be from the end "
+"of the array."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:4
+msgid "A packed [Array] of [Color]s."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:7
+msgid ""
+"An [Array] specifically designed to hold [Color]. Packs data tightly, so it "
+"saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:19
+msgid ""
+"Constructs a new [PackedColorArray]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:37
+msgid "Appends a [PackedColorArray] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:71 doc/classes/PackedInt32Array.xml:72
+#: doc/classes/PackedInt64Array.xml:72
+msgid "Appends a value to the array."
+msgstr ""
+
+#: doc/classes/PackedColorArray.xml:100
+msgid "Changes the [Color] at the given index."
+msgstr ""
+
+#: doc/classes/PackedDataContainerRef.xml:4
+msgid "Reference version of [PackedDataContainer]."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:4
+msgid "A packed [Array] of 32-bit floating-point values."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 32-bit floating-point values. Packs "
+"data tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"If you need to pack 64-bit floats tightly, see [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:20
+msgid ""
+"Constructs a new [PackedFloat32Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:38
+msgid "Appends a [PackedFloat32Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedFloat32Array.xml:101
+#: doc/classes/PackedFloat64Array.xml:101
+msgid "Changes the float at the given index."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:4
+msgid "A packed [Array] of 64-bit floating-point values."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 64-bit floating-point values. Packs "
+"data tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"If you only need to pack 32-bit floats tightly, see [PackedFloat32Array] for "
+"a more memory-friendly alternative."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:20
+msgid ""
+"Constructs a new [PackedFloat64Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedFloat64Array.xml:38
+msgid "Appends a [PackedFloat64Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:4
+msgid "A packed [Array] of 32-bit integers."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 32-bit integer values. Packs data "
+"tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"[b]Note:[/b] This type stores signed 32-bit integers, which means it can "
+"take values in the interval [code][-2^31, 2^31 - 1][/code], i.e. [code]"
+"[-2147483648, 2147483647][/code]. Exceeding those bounds will wrap around. "
+"In comparison, [int] uses signed 64-bit integers which can hold much larger "
+"values. If you need to pack 64-bit integers tightly, see [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:20
+msgid ""
+"Constructs a new [PackedInt32Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:38
+msgid "Appends a [PackedInt32Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:56 doc/classes/PackedInt64Array.xml:56
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:101 doc/classes/PackedInt64Array.xml:101
+msgid "Changes the integer at the given index."
+msgstr ""
+
+#: doc/classes/PackedInt32Array.xml:108 doc/classes/PackedInt64Array.xml:108
+msgid "Returns the array size."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:4
+msgid "A packed [Array] of 64-bit integers."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold 64-bit integer values. Packs data "
+"tightly, so it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference.\n"
+"[b]Note:[/b] This type stores signed 64-bit integers, which means it can "
+"take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. [code]"
+"[-9223372036854775808, 9223372036854775807][/code]. Exceeding those bounds "
+"will wrap around. If you only need to pack 32-bit integers tightly, see "
+"[PackedInt32Array] for a more memory-friendly alternative."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:20
+msgid ""
+"Constructs a new [PackedInt64Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedInt64Array.xml:38
+msgid "Appends a [PackedInt64Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:4
+msgid "An abstraction of a serialized scene."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:7
+msgid ""
+"A simplified interface to a scene file. Provides access to operations and "
+"checks that can be performed on the scene resource itself.\n"
+"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]).\n"
+"[b]Note:[/b] The node doesn't need to own itself.\n"
+"[b]Example of saving a node with different owners:[/b] The following example "
+"creates 3 objects: [code]Node2D[/code] ([code]node[/code]), "
+"[code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/"
+"code] ([code]collision[/code]). [code]collision[/code] is a child of "
+"[code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/"
+"code] is owned by [code]node[/code] and [code]pack[/code] will therefore "
+"only save those two nodes, but not [code]collision[/code].\n"
+"[codeblock]\n"
+"# Create the objects\n"
+"var node = Node2D.new()\n"
+"var rigid = RigidBody2D.new()\n"
+"var collision = CollisionShape2D.new()\n"
+"\n"
+"# Create the object hierarchy\n"
+"rigid.add_child(collision)\n"
+"node.add_child(rigid)\n"
+"\n"
+"# Change owner of rigid, but not of collision\n"
+"rigid.owner = node\n"
+"\n"
+"var scene = PackedScene.new()\n"
+"# Only node and rigid are now packed\n"
+"var result = scene.pack(node)\n"
+"if result == OK:\n"
+" ResourceSaver.save(\"res://path/name.scn\", scene) # Or \"user://...\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/PackedScene.xml:38
+msgid "Returns [code]true[/code] if the scene file has nodes."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:45
+msgid ""
+"Returns the [code]SceneState[/code] representing the scene file contents."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:54
+msgid ""
+"Instantiates the scene's node hierarchy. Triggers child scene "
+"instantiation(s). Triggers a [constant Node.NOTIFICATION_INSTANCED] "
+"notification on the root node."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:63
+msgid ""
+"Pack will ignore any sub-nodes not owned by given node. See [member Node."
+"owner]."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:69
+msgid ""
+"A dictionary representation of the scene contents.\n"
+"Available keys include \"rnames\" and \"variants\" for resources, "
+"\"node_count\", \"nodes\", \"node_paths\" for nodes, \"editable_instances\" "
+"for base scene children overrides, \"conn_count\" and \"conns\" for signal "
+"connections, and \"version\" for the format style of the PackedScene."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:75
+msgid "If passed to [method instance], blocks edits to the scene state."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:78
+msgid ""
+"If passed to [method instance], provides local scene resources to the local "
+"scene.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/PackedScene.xml:82
+msgid ""
+"If passed to [method instance], provides local scene resources to the local "
+"scene. Only the main scene should receive the main edit state.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:4
+msgid "A packed [Array] of [String]s."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:7
+msgid ""
+"An [Array] specifically designed to hold [String]s. Packs data tightly, so "
+"it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:19
+msgid ""
+"Constructs a new [PackedStringArray]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:37
+msgid "Appends a [PackedStringArray] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:71
+msgid "Appends a string element at end of the array."
+msgstr ""
+
+#: doc/classes/PackedStringArray.xml:100
+msgid "Changes the [String] at the given index."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:4
+msgid "A packed [Array] of [Vector2]s."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold [Vector2]. Packs data tightly, so "
+"it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:19
+msgid ""
+"Constructs a new [PackedVector2Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:37
+msgid "Appends a [PackedVector2Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:71
+msgid "Inserts a [Vector2] at the end."
+msgstr ""
+
+#: doc/classes/PackedVector2Array.xml:100
+msgid "Changes the [Vector2] at the given index."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:4
+msgid "A packed [Array] of [Vector3]s."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:7
+msgid ""
+"An [Array] specifically designed to hold [Vector3]. Packs data tightly, so "
+"it saves memory for large array sizes.\n"
+"[b]Note:[/b] This type is passed by value and not by reference."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:19
+msgid ""
+"Constructs a new [PackedVector3Array]. Optionally, you can pass in a generic "
+"[Array] that will be converted."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:37
+msgid "Appends a [PackedVector3Array] at the end of this array."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:71
+msgid "Inserts a [Vector3] at the end."
+msgstr ""
+
+#: doc/classes/PackedVector3Array.xml:100
+msgid "Changes the [Vector3] at the given index."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:4
+msgid "Abstraction and base class for packet-based protocols."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:7
+msgid ""
+"PacketPeer is an abstraction and base class for packet-based protocols (such "
+"as UDP). It provides an API for sending and receiving packets both as raw "
+"data or variables. This makes it easy to transfer data over a protocol, "
+"without having to encode data as low-level bytes or having to worry about "
+"network ordering."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:16
+msgid "Returns the number of packets currently available in the ring-buffer."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:23
+msgid "Gets a raw packet."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:30
+msgid ""
+"Returns the error state of the last packet received (via [method get_packet] "
+"and [method get_var])."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:39
+msgid ""
+"Gets a Variant. If [code]allow_objects[/code] is [code]true[/code], decoding "
+"objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:49
+msgid "Sends a raw packet."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:60
+msgid ""
+"Sends a [Variant] as a packet. If [code]full_objects[/code] is [code]true[/"
+"code], encoding objects is allowed (and can potentially include code)."
+msgstr ""
+
+#: doc/classes/PacketPeer.xml:66
+msgid ""
+"Maximum buffer size allowed when encoding [Variant]s. Raise this value to "
+"support heavier memory allocations.\n"
+"The [method put_var] method allocates memory on the stack, and the buffer "
+"used will grow automatically to the closest power of two to match the size "
+"of the [Variant]. If the [Variant] is bigger than "
+"[code]encode_buffer_max_size[/code], the method will error out with "
+"[constant ERR_OUT_OF_MEMORY]."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:4
+msgid "DTLS packet peer."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:7
+msgid ""
+"This class represents a DTLS peer connection. It can be used to connect to a "
+"DTLS server, and is returned by [method DTLSServer.take_connection]."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:24
+msgid ""
+"Connects a [code]peer[/code] beginning the DTLS handshake using the "
+"underlying [PacketPeerUDP] which must be connected (see [method "
+"PacketPeerUDP.connect_to_host]). If [code]validate_certs[/code] is "
+"[code]true[/code], [PacketPeerDTLS] will validate that the certificate "
+"presented by the remote peer and match it with the [code]for_hostname[/code] "
+"argument. You can specify a custom [X509Certificate] to use for validation "
+"via the [code]valid_certificate[/code] argument."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:31
+msgid "Disconnects this peer, terminating the DTLS session."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:38 doc/classes/StreamPeerSSL.xml:55
+msgid "Returns the status of the connection. See [enum Status] for values."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:45
+msgid ""
+"Poll the connection to check for incoming packets. Call this frequently to "
+"update the status and keep the connection working."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:51
+msgid "A status representing a [PacketPeerDTLS] that is disconnected."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:54
+msgid ""
+"A status representing a [PacketPeerDTLS] that is currently performing the "
+"handshake with a remote peer."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:57
+msgid ""
+"A status representing a [PacketPeerDTLS] that is connected to a remote peer."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:60
+msgid "A status representing a [PacketPeerDTLS] in a generic error state."
+msgstr ""
+
+#: doc/classes/PacketPeerDTLS.xml:63
+msgid ""
+"An error status that shows a mismatch in the DTLS certificate domain "
+"presented by the host and the domain requested for validation."
+msgstr ""
+
+#: doc/classes/PacketPeerStream.xml:4
+msgid "Wrapper to use a PacketPeer over a StreamPeer."
+msgstr ""
+
+#: doc/classes/PacketPeerStream.xml:7
+msgid ""
+"PacketStreamPeer provides a wrapper for working using packets over a stream. "
+"This allows for using packet based code with StreamPeers. PacketPeerStream "
+"implements a custom protocol over the StreamPeer, so the user should not "
+"read or write to the wrapped StreamPeer directly."
+msgstr ""
+
+#: doc/classes/PacketPeerStream.xml:19
+msgid "The wrapped [StreamPeer] object."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:4
+msgid "UDP packet peer."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:7
+msgid ""
+"UDP packet peer. Can be used to send raw UDP packets as well as [Variant]s."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:16
+msgid "Closes the UDP socket the [PacketPeerUDP] is currently listening on."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:27
+msgid ""
+"Calling this method connects this UDP peer to the given [code]host[/code]/"
+"[code]port[/code] pair. UDP is in reality connectionless, so this option "
+"only means that incoming packets from different addresses are automatically "
+"discarded, and that outgoing packets are always sent to the connected "
+"address (future calls to [method set_dest_address] are not allowed). This "
+"method does not send any data to the remote peer, to do that, use [method "
+"PacketPeer.put_var] or [method PacketPeer.put_packet] as usual. See also "
+"[UDPServer].\n"
+"Note: 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."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:35
+msgid ""
+"Returns the IP of the remote peer that sent the last packet(that was "
+"received with [method PacketPeer.get_packet] or [method PacketPeer.get_var])."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:42
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:49
+msgid ""
+"Returns [code]true[/code] if the UDP socket is open and has been connected "
+"to a remote address. See [method connect_to_host]."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:56
+msgid "Returns whether this [PacketPeerUDP] is listening."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:67
+msgid ""
+"Joins the multicast group specified by [code]multicast_address[/code] using "
+"the interface identified by [code]interface_name[/code].\n"
+"You can join the same multicast group with multiple interfaces. Use [method "
+"IP.get_local_interfaces] to know which are available.\n"
+"Note: Some Android devices might require the "
+"[code]CHANGE_WIFI_MULTICAST_STATE[/code] permission for multicast to work."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:80
+msgid ""
+"Removes the interface identified by [code]interface_name[/code] from the "
+"multicast group specified by [code]multicast_address[/code]."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:93
+msgid ""
+"Makes this [PacketPeerUDP] listen on the [code]port[/code] binding to "
+"[code]bind_address[/code] with a buffer size [code]recv_buf_size[/code].\n"
+"If [code]bind_address[/code] is set to [code]\"*\"[/code] (default), the "
+"peer will listen on all available addresses (both IPv4 and IPv6).\n"
+"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.\n"
+"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)."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:105
+msgid ""
+"Enable or disable sending of broadcast packets (e.g. "
+"[code]set_dest_address(\"255.255.255.255\", 4343)[/code]. This option is "
+"disabled by default.\n"
+"Note: Some Android devices might require the "
+"[code]CHANGE_WIFI_MULTICAST_STATE[/code] permission and this option to be "
+"enabled to receive broadcast packets too."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:117
+msgid ""
+"Sets the destination address and port for sending packets and variables. A "
+"hostname will be resolved using DNS if needed.\n"
+"Note: [method set_broadcast_enabled] must be enabled before sending packets "
+"to a broadcast address (e.g. [code]255.255.255.255[/code])."
+msgstr ""
+
+#: doc/classes/PacketPeerUDP.xml:125
+msgid ""
+"Waits for a packet to arrive on the listening port. See [method listen]."
+msgstr ""
+
+#: doc/classes/Panel.xml:4
+msgid "Provides an opaque background for [Control] children."
+msgstr ""
+
+#: doc/classes/Panel.xml:7
+msgid ""
+"Panel is a [Control] that displays an opaque background. It's commonly used "
+"as a parent and container for other types of [Control] nodes."
+msgstr ""
+
+#: doc/classes/Panel.xml:25
+msgid "The style of this [Panel]."
+msgstr ""
+
+#: doc/classes/PanelContainer.xml:4
+msgid "Panel container type."
+msgstr ""
+
+#: doc/classes/PanelContainer.xml:7
+msgid ""
+"Panel container type. This container fits controls inside of the delimited "
+"area of a stylebox. It's useful for giving controls an outline."
+msgstr ""
+
+#: doc/classes/PanelContainer.xml:20
+msgid "The style of [PanelContainer]'s background."
+msgstr ""
+
+#: doc/classes/PanoramaSkyMaterial.xml:4
+msgid "A [Material] used with [Sky] to draw a background texture."
+msgstr ""
+
+#: doc/classes/PanoramaSkyMaterial.xml:7
+msgid ""
+"A resource referenced in a [Sky] that is used to draw a background. The "
+"Panorama sky material functions similar to skyboxes in other engines, except "
+"it uses an equirectangular sky map instead of a cube map.\n"
+"Using an HDR panorama is strongly recommended for accurate, high-quality "
+"reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR "
+"([code].exr[/code]) image formats for this purpose.\n"
+"You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/"
+"cubemap_to_panorama.html]this tool[/url] to convert a cube map to an "
+"equirectangular sky map."
+msgstr ""
+
+#: doc/classes/PanoramaSkyMaterial.xml:17
+msgid "[Texture2D] to be applied to the [PanoramaSkyMaterial]."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:4
+msgid "A node used to create a parallax scrolling background."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:7
+msgid ""
+"A ParallaxBackground uses one or more [ParallaxLayer] child nodes to create "
+"a parallax effect. Each [ParallaxLayer] can move at a different speed using "
+"[member ParallaxLayer.motion_offset]. This creates an illusion of depth in a "
+"2D game. If not used with a [Camera2D], you must manually calculate the "
+"[member scroll_offset]."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:16
+msgid "The base position offset for all [ParallaxLayer] children."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:19
+msgid "The base motion scale for all [ParallaxLayer] children."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:22
+msgid ""
+"If [code]true[/code], elements in [ParallaxLayer] child aren't affected by "
+"the zoom level of the camera."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:25
+msgid ""
+"Top-left limits for scrolling to begin. If the camera is outside of this "
+"limit, the background will stop scrolling. Must be lower than [member "
+"scroll_limit_end] to work."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:28
+msgid ""
+"Bottom-right limits for scrolling to end. If the camera is outside of this "
+"limit, the background will stop scrolling. Must be higher than [member "
+"scroll_limit_begin] to work."
+msgstr ""
+
+#: doc/classes/ParallaxBackground.xml:31
+msgid ""
+"The ParallaxBackground's scroll value. Calculated automatically when using a "
+"[Camera2D], but can be used to manually manage scrolling when no camera is "
+"present."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:4
+msgid "A parallax scrolling layer to be used with [ParallaxBackground]."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:7
+msgid ""
+"A ParallaxLayer must be the child of a [ParallaxBackground] node. Each "
+"ParallaxLayer can be set to move at different speeds relative to the camera "
+"movement or the [member ParallaxBackground.scroll_offset] value.\n"
+"This node's children will be affected by its scroll offset.\n"
+"[b]Note:[/b] Any changes to this node's position and scale made after it "
+"enters the scene will be ignored."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:17
+msgid ""
+"The ParallaxLayer's [Texture2D] mirroring. Useful for creating an infinite "
+"scrolling background. If an axis is set to [code]0[/code], the [Texture2D] "
+"will not be mirrored."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:20
+msgid ""
+"The ParallaxLayer's offset relative to the parent ParallaxBackground's "
+"[member ParallaxBackground.scroll_offset]."
+msgstr ""
+
+#: doc/classes/ParallaxLayer.xml:23
+msgid ""
+"Multiplies the ParallaxLayer's motion. If an axis is set to [code]0[/code], "
+"it will not scroll."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:4
+msgid "Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:7
+msgid ""
+"ParticlesMaterial defines particle properties and behavior. It is used in "
+"the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] "
+"emitter nodes.\n"
+"Some of this material's properties are applied to each particle when "
+"emitted, while others can have a [CurveTexture] applied to vary values over "
+"the lifetime of the particle.\n"
+"When a randomness ratio is applied to a property it is used to scale that "
+"property by a random amount. The random ratio is used to interpolate between "
+"[code]1.0[/code] and a random number less than one, the result is multiplied "
+"by the property to obtain the randomized property. For example a random "
+"ratio of [code]0.4[/code] would scale the original property between "
+"[code]0.4-1.0[/code] of its original value."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:20
+msgid "Returns [code]true[/code] if the specified flag is enabled."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:38
+msgid "Returns the randomness ratio associated with the specified parameter."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:47
+msgid "Returns the [Texture2D] used by the specified parameter."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:58
+msgid ""
+"If [code]true[/code], enables the specified flag. See [enum Flags] for "
+"options."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:69
+msgid "Sets the specified [enum Parameter]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:80
+msgid "Sets the randomness ratio for the specified [enum Parameter]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:91
+msgid "Sets the [Texture2D] for the specified [enum Parameter]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:97
+msgid ""
+"Initial rotation applied to each particle, in degrees.\n"
+"Only applied when [member flag_disable_z] or [member flag_rotate_y] are "
+"[code]true[/code] or the [BaseMaterial3D] being used to draw the particle is "
+"using [constant BaseMaterial3D.BILLBOARD_PARTICLES]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:101
+msgid "Each particle's rotation will be animated along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:107
+msgid ""
+"Initial angular velocity applied to each particle. Sets the speed of "
+"rotation of the particle.\n"
+"Only applied when [member flag_disable_z] or [member flag_rotate_y] are "
+"[code]true[/code] or the [BaseMaterial3D] being used to draw the particle is "
+"using [constant BaseMaterial3D.BILLBOARD_PARTICLES]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:111
+msgid "Each particle's angular velocity will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:120
+msgid "Each particle's animation offset will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:129
+msgid "Each particle's animation speed will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:135
+msgid ""
+"Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/"
+"code] is defined, it will be multiplied by this color. To have particle "
+"display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D."
+"vertex_color_use_as_albedo] to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:138
+msgid "Each particle's color will vary along this [GradientTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:144
+msgid "Damping will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:153
+msgid ""
+"The box's extents if [code]emission_shape[/code] is set to [constant "
+"EMISSION_SHAPE_BOX]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:156
+msgid ""
+"Particle color will be modulated by color determined by sampling this "
+"texture at the same point as the [member emission_point_texture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:159
+msgid ""
+"Particle velocity and rotation will be set by sampling this texture at the "
+"same point as the [member emission_point_texture]. Used only in [constant "
+"EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from mesh or "
+"node by selecting \"Create Emission Points from Mesh/Node\" under the "
+"\"Particles\" tool in the toolbar."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:162
+msgid ""
+"The number of emission points if [code]emission_shape[/code] is set to "
+"[constant EMISSION_SHAPE_POINTS] or [constant "
+"EMISSION_SHAPE_DIRECTED_POINTS]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:165
+msgid ""
+"Particles will be emitted at positions determined by sampling this texture "
+"at a random position. Used with [constant EMISSION_SHAPE_POINTS] and "
+"[constant EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from "
+"mesh or node by selecting \"Create Emission Points from Mesh/Node\" under "
+"the \"Particles\" tool in the toolbar."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:168
+msgid ""
+"Particles will be emitted inside this region. Use [enum EmissionShape] "
+"constants for values."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:171
+msgid ""
+"The sphere's radius if [code]emission_shape[/code] is set to [constant "
+"EMISSION_SHAPE_SPHERE]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:192
+msgid "Each particle's hue will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:210
+msgid ""
+"Each particle's linear acceleration will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:216
+msgid ""
+"Orbital velocity applied to each particle. Makes the particles circle around "
+"origin. Specified in number of full rotations around origin per second.\n"
+"Only available when [member flag_disable_z] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:220
+msgid "Each particle's orbital velocity will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:229
+msgid ""
+"Each particle's radial acceleration will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:238
+msgid "Each particle's scale will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:250
+msgid ""
+"Each particle's tangential acceleration will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:256
+msgid "Trail particles' color will vary along this [GradientTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:259
+msgid ""
+"Emitter will emit [code]amount[/code] divided by [code]trail_divisor[/code] "
+"particles. The remaining particles will be used as trail(s)."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:262
+msgid "Trail particles' size will vary along this [CurveTexture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:267
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set initial velocity properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:270
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set angular velocity properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:273
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set orbital velocity properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:276
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set linear acceleration properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:279
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set radial acceleration properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:282
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set tangential acceleration properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:285
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set damping properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:288
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set angle properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:291
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set scale properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:294
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set hue variation properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:297
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set animation speed properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:300
+msgid ""
+"Use with [method set_param], [method set_param_randomness], and [method "
+"set_param_texture] to set animation offset properties."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:306
+msgid "Use with [method set_flag] to set [member flag_align_y]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:309
+msgid "Use with [method set_flag] to set [member flag_rotate_y]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:312
+msgid "Use with [method set_flag] to set [member flag_disable_z]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:327
+msgid ""
+"Particles will be emitted at a position determined by sampling a random "
+"point on the [member emission_point_texture]. Particle color will be "
+"modulated by [member emission_color_texture]."
+msgstr ""
+
+#: doc/classes/ParticlesMaterial.xml:330
+msgid ""
+"Particles will be emitted at a position determined by sampling a random "
+"point on the [member emission_point_texture]. Particle velocity and rotation "
+"will be set based on [member emission_normal_texture]. Particle color will "
+"be modulated by [member emission_color_texture]."
+msgstr ""
+
+#: doc/classes/Path2D.xml:4
+msgid "Contains a [Curve2D] path for [PathFollow2D] nodes to follow."
+msgstr ""
+
+#: doc/classes/Path2D.xml:7
+msgid ""
+"Can have [PathFollow2D] child nodes moving along the [Curve2D]. See "
+"[PathFollow2D] for more information on usage.\n"
+"[b]Note:[/b] The path is considered as relative to the moved nodes (children "
+"of [PathFollow2D]). As such, the curve should usually start with a zero "
+"vector ([code](0, 0)[/code])."
+msgstr ""
+
+#: doc/classes/Path2D.xml:16
+msgid "A [Curve2D] describing the path."
+msgstr ""
+
+#: doc/classes/Path3D.xml:4
+msgid "Contains a [Curve3D] path for [PathFollow3D] nodes to follow."
+msgstr ""
+
+#: doc/classes/Path3D.xml:7
+msgid ""
+"Can have [PathFollow3D] child nodes moving along the [Curve3D]. See "
+"[PathFollow3D] for more information on the usage.\n"
+"Note that the path is considered as relative to the moved nodes (children of "
+"[PathFollow3D]). As such, the curve should usually start with a zero vector "
+"[code](0, 0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Path3D.xml:16
+msgid "A [Curve3D] describing the path."
+msgstr ""
+
+#: doc/classes/Path3D.xml:22
+msgid "Emitted when the [member curve] changes."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:4
+msgid "Point sampler for a [Path2D]."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:7
+msgid ""
+"This node takes its parent [Path2D], and returns the coordinates of a point "
+"within it, given a distance from the first vertex.\n"
+"It is useful for making other nodes follow a path, without coding the "
+"movement pattern. For that, the nodes must be children of this node. The "
+"descendant nodes will then move accordingly when setting an offset in this "
+"node."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:16
+msgid ""
+"If [code]true[/code], the position between two cached points is interpolated "
+"cubically, and linearly otherwise.\n"
+"The points along the [Curve2D] of the [Path2D] are precomputed before use, "
+"for faster calculations. The point at the requested offset is then "
+"calculated interpolating between two adjacent cached points. This may "
+"present a problem if the curve makes sharp turns, as the cached points may "
+"not follow the curve closely enough.\n"
+"There are two answers to this problem: either increase the number of cached "
+"points and increase memory consumption, or make a cubic interpolation "
+"between two points at the cost of (slightly) slower calculations."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:21 doc/classes/PathFollow3D.xml:21
+msgid "The node's offset along the curve."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:24
+msgid ""
+"How far to look ahead of the curve to calculate the tangent if the node is "
+"rotating. E.g. shorter lookaheads will lead to faster rotations."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:27 doc/classes/PathFollow3D.xml:24
+msgid ""
+"If [code]true[/code], any offset outside the path's length will wrap around, "
+"instead of stopping at the ends. Use it for cyclic paths."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:30
+msgid "The distance along the path in pixels."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:33
+msgid ""
+"If [code]true[/code], this node rotates to follow the path, making its "
+"descendants rotate."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:36
+msgid ""
+"The distance along the path as a number in the range 0.0 (for the first "
+"vertex) to 1.0 (for the last). This is just another way of expressing the "
+"offset within the path, as the offset supplied is multiplied internally by "
+"the path's length."
+msgstr ""
+
+#: doc/classes/PathFollow2D.xml:39 doc/classes/PathFollow3D.xml:36
+msgid "The node's offset perpendicular to the curve."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:4
+msgid "Point sampler for a [Path3D]."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:7
+msgid ""
+"This node takes its parent [Path3D], and returns the coordinates of a point "
+"within it, given a distance from the first vertex.\n"
+"It is useful for making other nodes follow a path, without coding the "
+"movement pattern. For that, the nodes must be children of this node. The "
+"descendant nodes will then move accordingly when setting an offset in this "
+"node."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:16
+msgid ""
+"If [code]true[/code], the position between two cached points is interpolated "
+"cubically, and linearly otherwise.\n"
+"The points along the [Curve3D] of the [Path3D] are precomputed before use, "
+"for faster calculations. The point at the requested offset is then "
+"calculated interpolating between two adjacent cached points. This may "
+"present a problem if the curve makes sharp turns, as the cached points may "
+"not follow the curve closely enough.\n"
+"There are two answers to this problem: either increase the number of cached "
+"points and increase memory consumption, or make a cubic interpolation "
+"between two points at the cost of (slightly) slower calculations."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:27
+msgid ""
+"The distance from the first vertex, measured in 3D units along the path. "
+"This sets this node's position to a point within the path."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:30
+msgid ""
+"Allows or forbids rotation on one or more axes, depending on the [enum "
+"RotationMode] constants being used."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:33
+msgid ""
+"The distance from the first vertex, considering 0.0 as the first vertex and "
+"1.0 as the last. This is just another way of expressing the offset within "
+"the path, as the offset supplied is multiplied internally by the path's "
+"length."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:41
+msgid "Forbids the PathFollow3D to rotate."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:44
+msgid "Allows the PathFollow3D to rotate in the Y axis only."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:47
+msgid "Allows the PathFollow3D to rotate in both the X, and Y axes."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:50
+msgid "Allows the PathFollow3D to rotate in any axis."
+msgstr ""
+
+#: doc/classes/PathFollow3D.xml:53
+msgid ""
+"Uses the up vector information in a [Curve3D] to enforce orientation. This "
+"rotation mode requires the [Path3D]'s [member Curve3D.up_vector_enabled] "
+"property to be set to [code]true[/code]."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:4
+msgid "Creates packages that can be loaded into a running project."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:7
+msgid ""
+"The [PCKPacker] is used to create packages that can be loaded into a running "
+"project using [method ProjectSettings.load_resource_pack].\n"
+"[codeblock]\n"
+"var packer = PCKPacker.new()\n"
+"packer.pck_start(\"test.pck\")\n"
+"packer.add_file(\"res://text.txt\", \"text.txt\")\n"
+"packer.flush()\n"
+"[/codeblock]\n"
+"The above [PCKPacker] creates package [code]test.pck[/code], then adds a "
+"file named [code]text.txt[/code] at the root of the package."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:27
+msgid ""
+"Adds the [code]source_path[/code] file to the current PCK package at the "
+"[code]pck_path[/code] internal path (should start with [code]res://[/code])."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:36
+msgid ""
+"Writes the files specified using all [method add_file] calls since the last "
+"flush. If [code]verbose[/code] is [code]true[/code], a list of files added "
+"will be printed to the console for easier debugging."
+msgstr ""
+
+#: doc/classes/PCKPacker.xml:47
+msgid ""
+"Creates a new PCK file with the name [code]pck_name[/code]. The [code].pck[/"
+"code] file extension isn't added automatically, so it should be part of "
+"[code]pck_name[/code] (even though it's not required)."
+msgstr ""
+
+#: doc/classes/Performance.xml:4
+msgid "Exposes performance-related data."
+msgstr ""
+
+#: doc/classes/Performance.xml:7
+msgid ""
+"This class provides access to a number of different monitors related to "
+"performance, such as memory usage, draw calls, and FPS. These are the same "
+"as the values displayed in the [b]Monitor[/b] tab in the editor's "
+"[b]Debugger[/b] panel. By using the [method get_monitor] method of this "
+"class, you can access this data from your code.\n"
+"[b]Note:[/b] A few of these monitors are only available in debug mode and "
+"will always return 0 when used in a release build.\n"
+"[b]Note:[/b] Many of these monitors are not updated in real-time, so there "
+"may be a short delay between changes."
+msgstr ""
+
+#: doc/classes/Performance.xml:20
+msgid ""
+"Returns the value of one of the available monitors. You should provide one "
+"of the [enum Monitor] constants as the argument, like this:\n"
+"[codeblock]\n"
+"print(Performance.get_monitor(Performance.TIME_FPS)) # Prints the FPS to the "
+"console\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Performance.xml:29
+msgid "Number of frames per second."
+msgstr ""
+
+#: doc/classes/Performance.xml:32
+msgid "Time it took to complete one frame, in seconds."
+msgstr ""
+
+#: doc/classes/Performance.xml:35
+msgid "Time it took to complete one physics frame, in seconds."
+msgstr ""
+
+#: doc/classes/Performance.xml:38
+msgid ""
+"Static memory currently used, in bytes. Not available in release builds."
+msgstr ""
+
+#: doc/classes/Performance.xml:41
+msgid "Available static memory. Not available in release builds."
+msgstr ""
+
+#: doc/classes/Performance.xml:44
+msgid ""
+"Largest amount of memory the message queue buffer has used, in bytes. The "
+"message queue is used for deferred functions calls and notifications."
+msgstr ""
+
+#: doc/classes/Performance.xml:47
+msgid "Number of objects currently instanced (including nodes)."
+msgstr ""
+
+#: doc/classes/Performance.xml:50
+msgid "Number of resources currently used."
+msgstr ""
+
+#: doc/classes/Performance.xml:53
+msgid ""
+"Number of nodes currently instanced in the scene tree. This also includes "
+"the root node."
+msgstr ""
+
+#: doc/classes/Performance.xml:56
+msgid ""
+"Number of orphan nodes, i.e. nodes which are not parented to a node of the "
+"scene tree."
+msgstr ""
+
+#: doc/classes/Performance.xml:59
+msgid "3D objects drawn per frame."
+msgstr ""
+
+#: doc/classes/Performance.xml:62
+msgid "Vertices drawn per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:65
+msgid "Material changes per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:68
+msgid "Shader changes per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:71
+msgid "Render surface changes per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:74
+msgid "Draw calls per frame. 3D only."
+msgstr ""
+
+#: doc/classes/Performance.xml:77 doc/classes/RenderingServer.xml:3711
+msgid ""
+"The amount of video memory used, i.e. texture and vertex memory combined."
+msgstr ""
+
+#: doc/classes/Performance.xml:80 doc/classes/RenderingServer.xml:3714
+msgid "The amount of texture memory used."
+msgstr ""
+
+#: doc/classes/Performance.xml:83 doc/classes/RenderingServer.xml:3717
+msgid "The amount of vertex memory used."
+msgstr ""
+
+#: doc/classes/Performance.xml:86 doc/classes/RenderingServer.xml:3708
+msgid "Unimplemented in the GLES2 rendering backend, always returns 0."
+msgstr ""
+
+#: doc/classes/Performance.xml:89
+msgid "Number of active [RigidBody2D] nodes in the game."
+msgstr ""
+
+#: doc/classes/Performance.xml:92
+msgid "Number of collision pairs in the 2D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:95
+msgid "Number of islands in the 2D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:98
+msgid "Number of active [RigidBody3D] and [VehicleBody3D] nodes in the game."
+msgstr ""
+
+#: doc/classes/Performance.xml:101
+msgid "Number of collision pairs in the 3D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:104
+msgid "Number of islands in the 3D physics engine."
+msgstr ""
+
+#: doc/classes/Performance.xml:107
+msgid "Output latency of the [AudioServer]."
+msgstr ""
+
+#: doc/classes/Performance.xml:110
+msgid "Represents the size of the [enum Monitor] enum."
+msgstr ""
+
+#: doc/classes/PHashTranslation.xml:4
+msgid "Optimized translation."
+msgstr ""
+
+#: doc/classes/PHashTranslation.xml:7
+msgid ""
+"Optimized translation. Uses real-time compressed translations, which results "
+"in very small dictionaries."
+msgstr ""
+
+#: doc/classes/PHashTranslation.xml:18
+msgid ""
+"Generates and sets an optimized translation from the given [Translation] "
+"resource."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:4
+msgid "[Sky] [Material] used for a physically based sky."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:7
+msgid ""
+"The [PhysicalSkyMaterial] uses the Preetham analytic daylight model to draw "
+"a sky based on physical properties. This results in a substantially more "
+"realistic sky than the [ProceduralSkyMaterial], but it is slightly slower "
+"and less flexible.\n"
+"The [PhysicalSkyMaterial] only supports one sun. The color, energy, and "
+"direction of the sun are taken from the first [DirectionalLight3D] in the "
+"scene tree.\n"
+"As it is based on a daylight model, the sky fades to black as the sunset "
+"ends. If you want a full day/night cycle, you will have to add a night sky "
+"by converting this to a [ShaderMaterial] and adding a night sky directly "
+"into the resulting shader."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:17
+msgid ""
+"Sets the amount of dithering to use. Dithering helps reduce banding that "
+"appears from the smooth changes in color in the sky. Use the lowest value "
+"possible, higher amounts may add fuzziness to the sky."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:20
+msgid ""
+"Sets the exposure of the sky. Higher exposure values make the entire sky "
+"brighter."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:23
+msgid ""
+"Modulates the [Color] on the bottom half of the sky to represent the ground."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:26
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:29
+msgid ""
+"Controls the [Color] of the mie scattering effect. While not physically "
+"accurate, this allows for the creation of alien looking planets."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:32
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:35
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:38
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:41
+msgid ""
+"Sets the size of the sun disk. Default value is based on Sol's perceived "
+"size from Earth."
+msgstr ""
+
+#: doc/classes/PhysicalSkyMaterial.xml:44
+msgid ""
+"Sets the thickness of the atmosphere. High turbidity creates a foggy looking "
+"atmosphere, while a low turbidity results in a clearer atmosphere."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:4
+msgid "Base class for all objects affected by physics in 2D space."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:7
+msgid ""
+"PhysicsBody2D is an abstract base class for implementing a physics body. All "
+"*Body2D types inherit from it."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:19 doc/classes/PhysicsBody3D.xml:19
+#: doc/classes/SoftBody3D.xml:19
+msgid "Adds a body to the list of bodies that this body can't collide with."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:26 doc/classes/PhysicsBody3D.xml:26
+#: doc/classes/SoftBody3D.xml:26
+msgid ""
+"Returns an array of nodes that were added as collision exceptions for this "
+"body."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:53 doc/classes/PhysicsBody3D.xml:53
+#: doc/classes/SoftBody3D.xml:53
+msgid ""
+"Removes a body from the list of bodies that this body can't collide with."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:64 doc/classes/PhysicsBody3D.xml:64
+msgid ""
+"Sets individual bits on the [member collision_layer] bitmask. Use this if "
+"you only need to change one layer's value."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:75 doc/classes/PhysicsBody3D.xml:75
+msgid ""
+"Sets individual bits on the [member collision_mask] bitmask. Use this if you "
+"only need to change one layer's value."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:81 doc/classes/PhysicsBody3D.xml:81
+msgid ""
+"The physics layers this area is in.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:86 doc/classes/PhysicsBody3D.xml:86
+msgid "The physics layers this area scans for collisions."
+msgstr ""
+
+#: doc/classes/PhysicsBody2D.xml:90
+msgid ""
+"Both [member collision_layer] and [member collision_mask]. Returns [member "
+"collision_layer] when accessed. Updates [member collision_layer] and [member "
+"collision_mask] when modified."
+msgstr ""
+
+#: doc/classes/PhysicsBody3D.xml:4
+msgid "Base class for all objects affected by physics in 3D space."
+msgstr ""
+
+#: doc/classes/PhysicsBody3D.xml:7
+msgid ""
+"PhysicsBody3D is an abstract base class for implementing a physics body. All "
+"*Body types inherit from it."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:4
+msgid "Direct access object to a physics body in the [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:7
+msgid ""
+"Provides direct access to a physics body in the [PhysicsServer2D], allowing "
+"safe changes to physics properties. This object is passed via the direct "
+"state callback of rigid/character bodies, and is intended for changing the "
+"direct state of that body. See [method RigidBody2D._integrate_forces]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:10
+#: doc/classes/PhysicsDirectSpaceState2D.xml:10
+#: doc/classes/PhysicsDirectSpaceState3D.xml:10 doc/classes/RayCast2D.xml:14
+#: doc/classes/RayCast3D.xml:14 doc/classes/World2D.xml:10
+#: doc/classes/World3D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html"
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:19 doc/classes/RigidBody2D.xml:31
+msgid "Adds a constant directional force without affecting rotation."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:30
+#: doc/classes/PhysicsDirectBodyState3D.xml:30 doc/classes/RigidBody2D.xml:42
+msgid ""
+"Adds a positioned force to the body. Both the force and the offset from the "
+"body origin are in global coordinates."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:39 doc/classes/RigidBody2D.xml:51
+msgid "Adds a constant rotational force."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:48 doc/classes/RigidBody2D.xml:60
+msgid "Applies a directional impulse without affecting rotation."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:59
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time-independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason, it should only be used when simulating one-time impacts "
+"(use the \"_force\" functions otherwise). The offset uses the rotation of "
+"the global coordinate system, but is centered at the object's origin."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:68 doc/classes/RigidBody2D.xml:80
+msgid "Applies a rotational impulse to the body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:77
+#: doc/classes/PhysicsDirectBodyState3D.xml:78
+msgid "Returns the collider's [RID]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:86
+#: doc/classes/PhysicsDirectBodyState3D.xml:87
+msgid "Returns the collider's object id."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:95
+msgid ""
+"Returns the collider object. This depends on how it was created (will return "
+"a scene node if such was used to create it)."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:104
+#: doc/classes/PhysicsDirectBodyState3D.xml:105
+msgid "Returns the contact position in the collider."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:113
+#: doc/classes/PhysicsDirectBodyState3D.xml:114
+msgid "Returns the collider's shape index."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:122
+msgid ""
+"Returns the collided shape's metadata. This metadata is different from "
+"[method Object.get_meta], and is set with [method PhysicsServer2D."
+"shape_set_data]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:131
+#: doc/classes/PhysicsDirectBodyState3D.xml:123
+msgid "Returns the linear velocity vector at the collider's contact point."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:138
+msgid ""
+"Returns the number of contacts this body has with other bodies.\n"
+"[b]Note:[/b] By default, this returns 0 unless bodies are configured to "
+"monitor contacts. See [member RigidBody2D.contact_monitor]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:148
+#: doc/classes/PhysicsDirectBodyState3D.xml:149
+msgid "Returns the local normal at the contact point."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:157
+#: doc/classes/PhysicsDirectBodyState3D.xml:158
+msgid "Returns the local position of the contact point."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:166
+#: doc/classes/PhysicsDirectBodyState3D.xml:167
+msgid "Returns the local shape index of the collision."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:173
+#: doc/classes/PhysicsDirectBodyState3D.xml:174
+msgid "Returns the current state of the space, useful for queries."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:180
+#: doc/classes/PhysicsDirectBodyState3D.xml:181
+msgid "Calls the built-in force integration code."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:186
+#: doc/classes/PhysicsDirectBodyState3D.xml:187 doc/classes/RigidBody2D.xml:121
+msgid "The body's rotational velocity."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:189
+#: doc/classes/PhysicsDirectBodyState3D.xml:192
+msgid "The inverse of the inertia of the body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:192
+#: doc/classes/PhysicsDirectBodyState3D.xml:195
+msgid "The inverse of the mass of the body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:195
+#: doc/classes/PhysicsDirectBodyState3D.xml:198 doc/classes/RigidBody2D.xml:155
+msgid "The body's linear velocity."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:198
+#: doc/classes/PhysicsDirectBodyState3D.xml:203
+msgid "If [code]true[/code], this body is currently sleeping (not active)."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:201
+#: doc/classes/PhysicsDirectBodyState3D.xml:206
+msgid "The timestep (delta) used for the simulation."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:204
+#: doc/classes/PhysicsDirectBodyState3D.xml:209
+msgid ""
+"The rate at which the body stops rotating, if there are not any other forces "
+"moving it."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:207
+#: doc/classes/PhysicsDirectBodyState3D.xml:212
+msgid "The total gravity vector being currently applied to this body."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:210
+#: doc/classes/PhysicsDirectBodyState3D.xml:215
+msgid ""
+"The rate at which the body stops moving, if there are not any other forces "
+"moving it."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2D.xml:213
+#: doc/classes/PhysicsDirectBodyState3D.xml:218
+msgid "The body's transformation matrix."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2DSW.xml:4
+msgid "Software implementation of [PhysicsDirectBodyState2D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState2DSW.xml:7
+msgid ""
+"Software implementation of [PhysicsDirectBodyState2D]. This object exposes "
+"no new methods or properties and should not be used, as "
+"[PhysicsDirectBodyState2D] selects the best implementation available."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:4
+msgid "Direct access object to a physics body in the [PhysicsServer3D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:7
+msgid ""
+"Provides direct access to a physics body in the [PhysicsServer3D], allowing "
+"safe changes to physics properties. This object is passed via the direct "
+"state callback of rigid/character bodies, and is intended for changing the "
+"direct state of that body. See [method RigidBody3D._integrate_forces]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:18 doc/classes/RigidBody3D.xml:31
+msgid ""
+"Adds a constant directional force without affecting rotation.\n"
+"This is equivalent to [code]add_force(force, Vector3(0,0,0))[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:39
+msgid "Adds a constant rotational force without affecting position."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:48
+msgid ""
+"Applies a single directional impulse without affecting rotation.\n"
+"This is equivalent to [code]apply_impulse(Vector3(0, 0, 0), impulse)[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:60
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time-independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason it should only be used when simulating one-time impacts. The "
+"position uses the rotation of the global coordinate system, but is centered "
+"at the object's origin."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:69
+msgid ""
+"Apply a torque impulse (which will be affected by the body mass and shape). "
+"This will rotate the body around the vector [code]j[/code] passed as "
+"parameter."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:96
+msgid "Returns the collider object."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:130
+msgid ""
+"Returns the number of contacts this body has with other bodies.\n"
+"[b]Note:[/b] By default, this returns 0 unless bodies are configured to "
+"monitor contacts. See [member RigidBody3D.contact_monitor]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectBodyState3D.xml:140
+msgid "Impulse created by the contact. Only implemented for Bullet physics."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:4
+msgid "Direct access object to a space in the [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:7
+msgid ""
+"Direct access object to a space in the [PhysicsServer2D]. It's used mainly "
+"to do queries against objects and areas residing in a given space."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:19
+msgid ""
+"Checks how far the shape can travel toward a point. If the shape can not "
+"move, the array will be empty.\n"
+"[b]Note:[/b] Both the shape and the motion are supplied through a "
+"[PhysicsShapeQueryParameters2D] object. The method will return an array with "
+"two floats between 0 and 1, both representing a fraction of [code]motion[/"
+"code]. The first is how far the shape can move without triggering a "
+"collision, and the second is the point at which a collision will occur. If "
+"no collision is detected, the returned array will be [code][1, 1][/code]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:31
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters2D] object, against the space. The resulting "
+"array contains a list of points where the shape intersects another. Like "
+"with [method intersect_shape], the number of returned results can be limited "
+"to save processing time."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:40
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters2D] object, against the space. If it collides "
+"with more than one shape, the nearest one is selected. If the shape did not "
+"intersect anything, then an empty dictionary is returned instead.\n"
+"[b]Note:[/b] This method does not take into account the [code]motion[/code] "
+"property of the object. The returned object is a dictionary containing the "
+"following fields:\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]linear_velocity[/code]: The colliding object's velocity [Vector2]. If "
+"the object is an [Area2D], the result is [code](0, 0)[/code].\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]point[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:67
+msgid ""
+"Checks whether a point is inside any shape. The shapes the point is inside "
+"of are returned in an array containing dictionaries with the following "
+"fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"Additionally, the method can take an [code]exclude[/code] array of objects "
+"or [RID]s that are to be excluded from collisions, a [code]collision_mask[/"
+"code] bitmask representing the physics layers to check in, or booleans to "
+"determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, "
+"respectively."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:112
+msgid ""
+"Intersects a ray in a given space. The returned object is a dictionary with "
+"the following fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]position[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"If the ray did not intersect anything, then an empty dictionary is returned "
+"instead.\n"
+"Additionally, the method can take an [code]exclude[/code] array of objects "
+"or [RID]s that are to be excluded from collisions, a [code]collision_mask[/"
+"code] bitmask representing the physics layers to check in, or booleans to "
+"determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, "
+"respectively."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState2D.xml:132
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters2D] object, against the space.\n"
+"[b]Note:[/b] This method does not take into account the [code]motion[/code] "
+"property of the object. The intersected shapes are returned in an array "
+"containing dictionaries with the following fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]metadata[/code]: The intersecting shape's metadata. This metadata is "
+"different from [method Object.get_meta], and is set with [method "
+"PhysicsServer2D.shape_set_data].\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"The number of intersections can be limited with the [code]max_results[/code] "
+"parameter, to reduce the processing time."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:4
+msgid "Direct access object to a space in the [PhysicsServer3D]."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:7
+msgid ""
+"Direct access object to a space in the [PhysicsServer3D]. It's used mainly "
+"to do queries against objects and areas residing in a given space."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:21
+msgid ""
+"Checks whether the shape can travel to a point. The method will return an "
+"array with two floats between 0 and 1, both representing a fraction of "
+"[code]motion[/code]. The first is how far the shape can move without "
+"triggering a collision, and the second is the point at which a collision "
+"will occur. If no collision is detected, the returned array will be [code]"
+"[1, 1][/code].\n"
+"If the shape can not move, the returned array will be [code][0, 0][/code] "
+"under Bullet, and empty under GodotPhysics."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:33
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters3D] object, against the space. The resulting "
+"array contains a list of points where the shape intersects another. Like "
+"with [method intersect_shape], the number of returned results can be limited "
+"to save processing time."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:42
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters3D] object, against the space. If it collides "
+"with more than one shape, the nearest one is selected. The returned object "
+"is a dictionary containing the following fields:\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]linear_velocity[/code]: The colliding object's velocity [Vector3]. If "
+"the object is an [Area3D], the result is [code](0, 0, 0)[/code].\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]point[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"If the shape did not intersect anything, then an empty dictionary is "
+"returned instead."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:68
+msgid ""
+"Intersects a ray in a given space. The returned object is a dictionary with "
+"the following fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]normal[/code]: The object's surface normal at the intersection point.\n"
+"[code]position[/code]: The intersection point.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"If the ray did not intersect anything, then an empty dictionary is returned "
+"instead.\n"
+"Additionally, the method can take an [code]exclude[/code] array of objects "
+"or [RID]s that are to be excluded from collisions, a [code]collision_mask[/"
+"code] bitmask representing the physics layers to check in, or booleans to "
+"determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, "
+"respectively."
+msgstr ""
+
+#: doc/classes/PhysicsDirectSpaceState3D.xml:87
+msgid ""
+"Checks the intersections of a shape, given through a "
+"[PhysicsShapeQueryParameters3D] object, against the space. The intersected "
+"shapes are returned in an array containing dictionaries with the following "
+"fields:\n"
+"[code]collider[/code]: The colliding object.\n"
+"[code]collider_id[/code]: The colliding object's ID.\n"
+"[code]rid[/code]: The intersecting object's [RID].\n"
+"[code]shape[/code]: The shape index of the colliding shape.\n"
+"The number of intersections can be limited with the [code]max_results[/code] "
+"parameter, to reduce the processing time."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:4
+msgid "A material for physics properties."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:7
+msgid ""
+"Provides a means of modifying the collision properties of a [PhysicsBody3D]."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:17
+msgid ""
+"The body's bounciness. Values range from [code]0[/code] (no bounce) to "
+"[code]1[/code] (full bounciness)."
+msgstr ""
+
+#: doc/classes/PhysicsMaterial.xml:20
+msgid ""
+"The body's friction. Values range from [code]0[/code] (frictionless) to "
+"[code]1[/code] (maximum friction)."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:4
+msgid "Server interface for low-level 2D physics access."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:7
+msgid ""
+"PhysicsServer2D is the server responsible for all 2D physics. It can create "
+"many kinds of physics objects, but does not insert them on the node tree."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:24 doc/classes/PhysicsServer3D.xml:24
+msgid ""
+"Adds a shape to the area, along with a transform matrix. Shapes are usually "
+"referenced by their index, so you should track which shape has a given index."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:45 doc/classes/PhysicsServer2D.xml:418
+#: doc/classes/PhysicsServer3D.xml:35 doc/classes/PhysicsServer3D.xml:409
+msgid ""
+"Assigns the area to a descendant of [Object], so it can exist in the node "
+"tree."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:54 doc/classes/PhysicsServer3D.xml:44
+msgid ""
+"Removes all shapes from an area. It does not delete the shapes, so they can "
+"be reassigned later."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:61
+msgid "Creates an [Area2D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:78 doc/classes/PhysicsServer2D.xml:505
+#: doc/classes/PhysicsServer3D.xml:60 doc/classes/PhysicsServer3D.xml:492
+msgid "Gets the instance ID of the object the area is assigned to."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:89
+msgid ""
+"Returns an area parameter value. See [enum AreaParameter] for a list of "
+"available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:100 doc/classes/PhysicsServer3D.xml:82
+msgid "Returns the [RID] of the nth shape of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:109 doc/classes/PhysicsServer3D.xml:91
+msgid "Returns the number of shapes assigned to an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:120 doc/classes/PhysicsServer3D.xml:102
+msgid "Returns the transform matrix of a shape within an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:129 doc/classes/PhysicsServer3D.xml:111
+msgid "Returns the space assigned to the area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:138 doc/classes/PhysicsServer3D.xml:120
+msgid "Returns the space override mode for the area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:147 doc/classes/PhysicsServer3D.xml:129
+msgid "Returns the transform matrix for an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:158 doc/classes/PhysicsServer3D.xml:149
+msgid ""
+"Removes a shape from an area. It does not delete the shape, so it can be "
+"reassigned later."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:181 doc/classes/PhysicsServer3D.xml:172
+msgid "Assigns the area to one or many physics layers."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:192 doc/classes/PhysicsServer3D.xml:183
+msgid "Sets which physics layers the area will monitor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:205 doc/classes/PhysicsServer3D.xml:196
+msgid ""
+"Sets the function to call when any body/area enters or exits the area. This "
+"callback will be called for any object interacting with the area, and takes "
+"five parameters:\n"
+"1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on "
+"whether the object entered or exited the area.\n"
+"2: [RID] of the object that entered/exited the area.\n"
+"3: Instance ID of the object that entered/exited the area.\n"
+"4: The shape index of the object that entered/exited the area.\n"
+"5: The shape index of the area where the object entered/exited."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:233
+msgid ""
+"Sets the value for an area parameter. See [enum AreaParameter] for a list of "
+"available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:246 doc/classes/PhysicsServer3D.xml:248
+msgid ""
+"Substitutes a given area shape by another. The old shape is selected by its "
+"index, the new one by its [RID]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:259
+msgid "Disables a given shape in an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:272 doc/classes/PhysicsServer3D.xml:273
+msgid "Sets the transform matrix for an area shape."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:283 doc/classes/PhysicsServer3D.xml:284
+msgid "Assigns a space to the area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:294
+msgid ""
+"Sets the space override mode for the area. See [enum AreaSpaceOverrideMode] "
+"for a list of available modes."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:305 doc/classes/PhysicsServer3D.xml:306
+msgid "Sets the transform matrix for an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:326 doc/classes/PhysicsServer3D.xml:327
+msgid "Adds a body to the list of bodies exempt from collisions."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:339
+msgid ""
+"Adds a positioned force to the applied force and torque. As with [method "
+"body_apply_impulse], both the force and the offset from the body origin are "
+"in global coordinates. A force differs from an impulse in that, while the "
+"two are forces, the impulse clears itself after being applied."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:354 doc/classes/PhysicsServer3D.xml:354
+msgid ""
+"Adds a shape to the body, along with a transform matrix. Shapes are usually "
+"referenced by their index, so you should track which shape has a given index."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:387
+msgid ""
+"Adds a positioned impulse to the applied force and torque. Both the force "
+"and the offset from the body origin are in global coordinates."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:427 doc/classes/PhysicsServer3D.xml:418
+msgid "Removes all shapes from a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:434
+msgid "Creates a physics body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:451 doc/classes/PhysicsServer3D.xml:438
+msgid "Returns the physics layer or layers a body belongs to."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:460
+msgid "Returns the physics layer or layers a body can collide with."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:469
+msgid "Returns the continuous collision detection mode."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:478
+msgid "Returns the [PhysicsDirectBodyState2D] of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:487 doc/classes/PhysicsServer3D.xml:474
+msgid ""
+"Returns the maximum contacts that can be reported. See [method "
+"body_set_max_contacts_reported]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:496 doc/classes/PhysicsServer3D.xml:483
+msgid "Returns the body mode."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:516
+msgid ""
+"Returns the value of a body parameter. See [enum BodyParameter] for a list "
+"of available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:527 doc/classes/PhysicsServer3D.xml:514
+msgid "Returns the [RID] of the nth shape of a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:536 doc/classes/PhysicsServer3D.xml:523
+msgid "Returns the number of shapes assigned to a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:547
+msgid "Returns the metadata of a shape of a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:558 doc/classes/PhysicsServer3D.xml:534
+msgid "Returns the transform matrix of a body shape."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:567 doc/classes/PhysicsServer3D.xml:543
+msgid "Returns the [RID] of the space assigned to a body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:578 doc/classes/PhysicsServer3D.xml:554
+msgid "Returns a body state."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:587 doc/classes/PhysicsServer3D.xml:582
+msgid ""
+"Returns whether a body uses a callback function to calculate its own physics "
+"(see [method body_set_force_integration_callback])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:598
+msgid "Removes a body from the list of bodies exempt from collisions."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:609 doc/classes/PhysicsServer3D.xml:614
+msgid ""
+"Removes a shape from a body. The shape is not deleted, so it can be reused "
+"afterwards."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:620 doc/classes/PhysicsServer3D.xml:637
+#: doc/classes/RigidBody3D.xml:119
+msgid ""
+"Sets an axis velocity. The velocity in the given vector axis will be set as "
+"the given vector length. This is useful for jumping behavior."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:631 doc/classes/PhysicsServer3D.xml:648
+msgid "Sets the physics layer or layers a body belongs to."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:642 doc/classes/PhysicsServer3D.xml:659
+msgid "Sets the physics layer or layers a body can collide with."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:653
+msgid ""
+"Sets the continuous collision detection mode using one of the [enum CCDMode] "
+"constants.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:669 doc/classes/PhysicsServer3D.xml:686
+msgid ""
+"Sets the function used to calculate physics for an object, if that object "
+"allows it (see [method body_set_omit_force_integration])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:680 doc/classes/PhysicsServer3D.xml:707
+msgid ""
+"Sets the maximum contacts to report. Bodies can keep a log of the contacts "
+"with other bodies, this is enabled by setting the maximum amount of contacts "
+"reported to a number greater than 0."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:691
+msgid "Sets the body mode using one of the [enum BodyMode] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:702 doc/classes/PhysicsServer3D.xml:729
+msgid ""
+"Sets whether a body uses a callback function to calculate its own physics "
+"(see [method body_set_force_integration_callback])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:715
+msgid ""
+"Sets a body parameter. See [enum BodyParameter] for a list of available "
+"parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:728 doc/classes/PhysicsServer3D.xml:766
+msgid ""
+"Substitutes a given body shape by another. The old shape is selected by its "
+"index, the new one by its [RID]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:743
+msgid ""
+"Enables one way collision on body if [code]enable[/code] is [code]true[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:756
+msgid "Disables shape in body if [code]disable[/code] is [code]true[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:769
+msgid ""
+"Sets metadata of a shape within a body. This metadata is different from "
+"[method Object.set_meta], and can be retrieved on shape queries."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:782 doc/classes/PhysicsServer3D.xml:791
+msgid "Sets the transform matrix for a body shape."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:793 doc/classes/PhysicsServer3D.xml:802
+msgid "Assigns a space to the body (see [method space_create])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:806
+msgid "Sets a body state using one of the [enum BodyState] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:825
+msgid ""
+"Returns [code]true[/code] if a collision would result from moving in the "
+"given direction from a given point in space. Margin increases the size of "
+"the shapes involved in the collision detection. [PhysicsTestMotionResult2D] "
+"can be passed to return additional information in."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:864
+msgid ""
+"Creates a damped spring joint between two bodies. If not specified, the "
+"second body is assumed to be the joint itself."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:875
+msgid "Returns the value of a damped spring joint parameter."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:888
+msgid ""
+"Sets a damped spring joint parameter. See [enum DampedStringParam] for a "
+"list of available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:897
+msgid ""
+"Destroys any of the objects created by PhysicsServer2D. If the [RID] passed "
+"is not one of the objects that can be created by PhysicsServer2D, an error "
+"will be sent to the console."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:906
+msgid ""
+"Returns information about the current state of the 2D physics engine. See "
+"[enum ProcessInfo] for a list of available states."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:923
+msgid ""
+"Creates a groove joint between two bodies. If not specified, the bodies are "
+"assumed to be the joint itself."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:934
+msgid "Returns the value of a joint parameter."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:943
+msgid "Returns a joint's type (see [enum JointType])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:956
+msgid ""
+"Sets a joint parameter. See [enum JointParam] for a list of available "
+"parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:975
+msgid ""
+"Creates a pin joint between two bodies. If not specified, the second body is "
+"assumed to be the joint itself."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1002
+msgid "Activates or deactivates the 2D physics engine."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1011 doc/classes/PhysicsServer3D.xml:1156
+msgid "Returns the shape data."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1020
+msgid "Returns a shape's type (see [enum ShapeType])."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1031 doc/classes/PhysicsServer3D.xml:1176
+msgid ""
+"Sets the shape data that defines its shape and size. The data to be passed "
+"depends on the kind of shape created [method shape_get_type]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1038 doc/classes/PhysicsServer3D.xml:1207
+msgid ""
+"Creates a space. A space is a collection of parameters for the physics "
+"engine that can be assigned to an area or a body. It can be assigned to an "
+"area with [method area_set_space], or to a body with [method body_set_space]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1047
+msgid ""
+"Returns the state of a space, a [PhysicsDirectSpaceState2D]. This object can "
+"be used to make collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1058 doc/classes/PhysicsServer3D.xml:1227
+msgid "Returns the value of a space parameter."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1067 doc/classes/PhysicsServer3D.xml:1236
+msgid "Returns whether the space is active."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1078 doc/classes/PhysicsServer3D.xml:1247
+msgid ""
+"Marks a space as active. It will not have an effect, unless it is assigned "
+"to an area or body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1091
+msgid ""
+"Sets the value for a space parameter. See [enum SpaceParameter] for a list "
+"of available parameters."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1097 doc/classes/PhysicsServer3D.xml:1602
+msgid ""
+"Constant to set/get the maximum distance a pair of bodies has to move before "
+"their collision status has to be recalculated."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1100 doc/classes/PhysicsServer3D.xml:1605
+msgid ""
+"Constant to set/get the maximum distance a shape can be from another before "
+"they are considered separated."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1103 doc/classes/PhysicsServer3D.xml:1608
+msgid ""
+"Constant to set/get the maximum distance a shape can penetrate another shape "
+"before it is considered a collision."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1106 doc/classes/PhysicsServer3D.xml:1611
+msgid ""
+"Constant to set/get the threshold linear velocity of activity. A body marked "
+"as potentially inactive for both linear and angular velocity will be put to "
+"sleep after the time given."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1109 doc/classes/PhysicsServer3D.xml:1614
+msgid ""
+"Constant to set/get the threshold angular velocity of activity. A body "
+"marked as potentially inactive for both linear and angular velocity will be "
+"put to sleep after the time given."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1112 doc/classes/PhysicsServer3D.xml:1617
+msgid ""
+"Constant to set/get the maximum time of activity. A body marked as "
+"potentially inactive for both linear and angular velocity will be put to "
+"sleep after this time."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1115 doc/classes/PhysicsServer3D.xml:1622
+msgid ""
+"Constant to set/get the default solver bias for all physics constraints. A "
+"solver bias is a factor controlling how much two objects \"rebound\", after "
+"violating a constraint, to avoid leaving them in that state because of "
+"numerical imprecision."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1120
+msgid ""
+"This is the constant for creating line shapes. A line shape is an infinite "
+"line with an origin point, and a normal. Thus, it can be used for front/"
+"behind checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1125
+msgid ""
+"This is the constant for creating segment shapes. A segment shape is a line "
+"from a point A to a point B. It can be checked for intersections."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1128
+msgid ""
+"This is the constant for creating circle shapes. A circle shape only has a "
+"radius. It can be used for intersections and inside/outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1131
+msgid ""
+"This is the constant for creating rectangle shapes. A rectangle shape is "
+"defined by a width and a height. It can be used for intersections and inside/"
+"outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1134
+msgid ""
+"This is the constant for creating capsule shapes. A capsule shape is defined "
+"by a radius and a length. It can be used for intersections and inside/"
+"outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1137
+msgid ""
+"This is the constant for creating convex polygon shapes. A polygon is "
+"defined by a list of points. It can be used for intersections and inside/"
+"outside checks. Unlike the [member CollisionPolygon2D.polygon] property, "
+"polygons modified with [method shape_set_data] do not verify that the points "
+"supplied form is a convex polygon."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1140
+msgid ""
+"This is the constant for creating concave polygon shapes. A polygon is "
+"defined by a list of points. It can be used for intersections checks, but "
+"not for inside/outside checks."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1143 doc/classes/PhysicsServer3D.xml:1497
+msgid ""
+"This constant is used internally by the engine. Any attempt to create this "
+"kind of shape results in an error."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1146 doc/classes/PhysicsServer3D.xml:1500
+msgid "Constant to set/get gravity strength in an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1149 doc/classes/PhysicsServer3D.xml:1503
+msgid "Constant to set/get gravity vector/center in an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1152 doc/classes/PhysicsServer3D.xml:1506
+msgid ""
+"Constant to set/get whether the gravity vector of an area is a direction, or "
+"a center point."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1155 doc/classes/PhysicsServer3D.xml:1509
+msgid ""
+"Constant to set/get the falloff factor for point gravity of an area. The "
+"greater this value is, the faster the strength of gravity decreases with the "
+"square of distance."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1158 doc/classes/PhysicsServer3D.xml:1512
+msgid ""
+"This constant was used to set/get the falloff factor for point gravity. It "
+"has been superseded by [constant AREA_PARAM_GRAVITY_DISTANCE_SCALE]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1161 doc/classes/PhysicsServer3D.xml:1515
+msgid "Constant to set/get the linear dampening factor of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1164 doc/classes/PhysicsServer3D.xml:1518
+msgid "Constant to set/get the angular dampening factor of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1167 doc/classes/PhysicsServer3D.xml:1521
+msgid "Constant to set/get the priority (order of processing) of an area."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1170 doc/classes/PhysicsServer3D.xml:1524
+msgid ""
+"This area does not affect gravity/damp. These are generally areas that exist "
+"only to detect collisions, and objects entering or exiting them."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1173 doc/classes/PhysicsServer3D.xml:1527
+msgid ""
+"This area adds its gravity/damp values to whatever has been calculated so "
+"far. This way, many overlapping areas can combine their physics to make "
+"interesting effects."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1176 doc/classes/PhysicsServer3D.xml:1530
+msgid ""
+"This area adds its gravity/damp values to whatever has been calculated so "
+"far. Then stops taking into account the rest of the areas, even the default "
+"one."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1179 doc/classes/PhysicsServer3D.xml:1533
+msgid ""
+"This area replaces any gravity/damp, even the default one, and stops taking "
+"into account the rest of the areas."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1182 doc/classes/PhysicsServer3D.xml:1536
+msgid ""
+"This area replaces any gravity/damp calculated so far, but keeps calculating "
+"the rest of the areas, down to the default one."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1185 doc/classes/PhysicsServer3D.xml:1539
+msgid "Constant for static bodies."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1188 doc/classes/PhysicsServer3D.xml:1542
+msgid "Constant for kinematic bodies."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1191 doc/classes/PhysicsServer3D.xml:1545
+msgid "Constant for rigid bodies."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1194 doc/classes/PhysicsServer3D.xml:1548
+msgid ""
+"Constant for rigid bodies in character mode. In this mode, a body can not "
+"rotate, and only its linear velocity is affected by physics."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1197 doc/classes/PhysicsServer3D.xml:1551
+msgid "Constant to set/get a body's bounce factor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1200 doc/classes/PhysicsServer3D.xml:1554
+msgid "Constant to set/get a body's friction."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1203 doc/classes/PhysicsServer3D.xml:1557
+msgid "Constant to set/get a body's mass."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1206
+msgid "Constant to set/get a body's inertia."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1209 doc/classes/PhysicsServer3D.xml:1560
+msgid "Constant to set/get a body's gravity multiplier."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1212 doc/classes/PhysicsServer3D.xml:1563
+msgid "Constant to set/get a body's linear dampening factor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1215 doc/classes/PhysicsServer3D.xml:1566
+msgid "Constant to set/get a body's angular dampening factor."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1218 doc/classes/PhysicsServer3D.xml:1569
+msgid "Represents the size of the [enum BodyParameter] enum."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1221 doc/classes/PhysicsServer3D.xml:1572
+msgid "Constant to set/get the current transform matrix of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1224 doc/classes/PhysicsServer3D.xml:1575
+msgid "Constant to set/get the current linear velocity of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1227 doc/classes/PhysicsServer3D.xml:1578
+msgid "Constant to set/get the current angular velocity of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1230 doc/classes/PhysicsServer3D.xml:1581
+msgid "Constant to sleep/wake up a body, or to get whether it is sleeping."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1233 doc/classes/PhysicsServer3D.xml:1584
+msgid "Constant to set/get whether the body can sleep."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1236
+msgid "Constant to create pin joints."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1239
+msgid "Constant to create groove joints."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1242
+msgid "Constant to create damped spring joints."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1251
+msgid ""
+"Sets the resting length of the spring joint. The joint will always try to go "
+"to back this length when pulled apart."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1254
+msgid ""
+"Sets the stiffness of the spring joint. The joint applies a force equal to "
+"the stiffness times the distance from its resting length."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1257
+msgid ""
+"Sets the damping ratio of the spring joint. A value of 0 indicates an "
+"undamped spring, while 1 causes the system to reach equilibrium as fast as "
+"possible (critical damping)."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1260
+msgid ""
+"Disables continuous collision detection. This is the fastest way to detect "
+"body collisions, but can miss small, fast-moving objects."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1263
+msgid ""
+"Enables continuous collision detection by raycasting. It is faster than "
+"shapecasting, but less precise."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1266
+msgid ""
+"Enables continuous collision detection by shapecasting. It is the slowest "
+"CCD method, and the most precise."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1269 doc/classes/PhysicsServer3D.xml:1587
+msgid ""
+"The value of the first parameter and area callback function receives, when "
+"an object enters one of its shapes."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1272 doc/classes/PhysicsServer3D.xml:1590
+msgid ""
+"The value of the first parameter and area callback function receives, when "
+"an object exits one of its shapes."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1275 doc/classes/PhysicsServer3D.xml:1593
+msgid "Constant to get the number of objects that are not sleeping."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1278 doc/classes/PhysicsServer3D.xml:1596
+msgid "Constant to get the number of possible collisions."
+msgstr ""
+
+#: doc/classes/PhysicsServer2D.xml:1281 doc/classes/PhysicsServer3D.xml:1599
+msgid ""
+"Constant to get the number of space regions where a collision could occur."
+msgstr ""
+
+#: doc/classes/PhysicsServer2DSW.xml:4
+msgid "Software implementation of [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer2DSW.xml:7
+msgid ""
+"This class exposes no new methods or properties and should not be used, as "
+"[PhysicsServer2D] automatically selects the best implementation available."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:4
+msgid "Server interface for low-level physics access."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:7
+msgid ""
+"PhysicsServer3D is the server responsible for all 3D physics. It can create "
+"many kinds of physics objects, but does not insert them on the node tree."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:51
+msgid "Creates an [Area3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:71
+msgid ""
+"Returns an area parameter value. A list of available parameters is on the "
+"[enum AreaParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:138
+msgid "If [code]true[/code], area collides with rays."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:224
+msgid ""
+"Sets the value for an area parameter. A list of available parameters is on "
+"the [enum AreaParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:235
+msgid "Sets object pickable with rays."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:295
+msgid ""
+"Sets the space override mode for the area. The modes are described in the "
+"[enum AreaSpaceOverrideMode] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:387
+msgid ""
+"Gives the body a push at a [code]position[/code] in the direction of the "
+"[code]impulse[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:398
+msgid "Gives the body a push to rotate it."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:429
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:447
+msgid ""
+"Returns the physics layer or layers a body can collide with.\n"
+"-"
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:457
+msgid "Returns the [PhysicsDirectBodyState3D] of the body."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:503
+msgid ""
+"Returns the value of a body parameter. A list of available parameters is on "
+"the [enum BodyParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:573
+msgid ""
+"If [code]true[/code], the continuous collision detection mode is enabled."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:591
+msgid "If [code]true[/code], the body can be detected by rays."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:602
+msgid ""
+"Removes a body from the list of bodies exempt from collisions.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:670
+msgid ""
+"If [code]true[/code], the continuous collision detection mode is enabled.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:718
+msgid "Sets the body mode, from one of the [enum BodyMode] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:742
+msgid ""
+"Sets a body parameter. A list of available parameters is on the [enum "
+"BodyParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:753
+msgid "Sets the body pickable with rays if [code]enabled[/code] is set."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:815
+msgid "Sets a body state (see [enum BodyState] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:826
+msgid ""
+"Gets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:839
+msgid ""
+"Sets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:848
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:861
+msgid ""
+"Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:874
+msgid ""
+"Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] "
+"constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:889
+msgid ""
+"Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:904
+msgid ""
+"Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] "
+"constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:913
+msgid "Returns an Info defined by the [enum ProcessInfo] input given."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:924
+msgid "Gets a hinge_joint flag (see [enum HingeJointFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:935
+msgid "Gets a hinge_joint parameter (see [enum HingeJointParam])."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:948
+msgid "Sets a hinge_joint flag (see [enum HingeJointFlag] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:961
+msgid "Sets a hinge_joint parameter (see [enum HingeJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:976
+msgid "Creates a [ConeTwistJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:991
+msgid "Creates a [Generic6DOFJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1006
+msgid "Creates a [HingeJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1021
+msgid "Creates a [PinJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1036
+msgid "Creates a [SliderJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1045
+msgid "Gets the priority value of the Joint3D."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1054
+msgid "Returns the type of the Joint3D."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1065
+msgid "Sets the priority value of the Joint3D."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1074
+msgid ""
+"Returns position of the joint in the local space of body a of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1083
+msgid ""
+"Returns position of the joint in the local space of body b of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1094
+msgid "Gets a pin_joint parameter (see [enum PinJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1105
+msgid "Sets position of the joint in the local space of body a of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1116
+msgid "Sets position of the joint in the local space of body b of the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1129
+msgid "Sets a pin_joint parameter (see [enum PinJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1138
+msgid "Activates or deactivates the 3D physics engine."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1147
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1165
+msgid "Returns the type of shape (see [enum ShapeType] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1187 doc/classes/PhysicsServer3D.xml:1200
+msgid "Gets a slider_joint parameter (see [enum SliderJointParam] constants)."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1216
+msgid ""
+"Returns the state of a space, a [PhysicsDirectSpaceState3D]. This object can "
+"be used to make collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1260
+msgid ""
+"Sets the value for a space parameter. A list of available parameters is on "
+"the [enum SpaceParameter] constants."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1266
+msgid "The [Joint3D] is a [PinJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1269
+msgid "The [Joint3D] is a [HingeJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1272
+msgid "The [Joint3D] is a [SliderJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1275
+msgid "The [Joint3D] is a [ConeTwistJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1278
+msgid "The [Joint3D] is a [Generic6DOFJoint3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1281
+msgid ""
+"The strength with which the pinned objects try to stay in positional "
+"relation to each other.\n"
+"The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1285
+msgid ""
+"The strength with which the pinned objects try to stay in velocity relation "
+"to each other.\n"
+"The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1289
+msgid ""
+"If above 0, this value is the maximum value for an impulse that this Joint3D "
+"puts on its ends."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1295
+msgid "The maximum rotation across the Hinge."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1298
+msgid "The minimum rotation across the Hinge."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1315
+msgid "If [code]true[/code], the Hinge has a maximum and a minimum rotation."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1318
+msgid "If [code]true[/code], a motor turns the Hinge."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1321 doc/classes/SliderJoint3D.xml:81
+#: doc/classes/SliderJoint3D.xml:104
+msgid ""
+"The maximum difference between the pivot points on their X axis before "
+"damping happens."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1324 doc/classes/SliderJoint3D.xml:72
+#: doc/classes/SliderJoint3D.xml:107
+msgid ""
+"The minimum difference between the pivot points on their X axis before "
+"damping happens."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1327 doc/classes/SliderJoint3D.xml:78
+#: doc/classes/SliderJoint3D.xml:110
+msgid ""
+"A factor applied to the movement across the slider axis once the limits get "
+"surpassed. The lower, the slower the movement."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1330 doc/classes/SliderJoint3D.xml:113
+msgid ""
+"The amount of restitution once the limits are surpassed. The lower, the more "
+"velocityenergy gets lost."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1333 doc/classes/SliderJoint3D.xml:116
+msgid "The amount of damping once the slider limits are surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1336 doc/classes/SliderJoint3D.xml:90
+#: doc/classes/SliderJoint3D.xml:119
+msgid ""
+"A factor applied to the movement across the slider axis as long as the "
+"slider is in the limits. The lower, the slower the movement."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1339 doc/classes/SliderJoint3D.xml:87
+#: doc/classes/SliderJoint3D.xml:122
+msgid "The amount of restitution inside the slider limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1342 doc/classes/SliderJoint3D.xml:84
+#: doc/classes/SliderJoint3D.xml:125
+msgid "The amount of damping inside the slider limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1345 doc/classes/SliderJoint3D.xml:99
+#: doc/classes/SliderJoint3D.xml:128
+msgid "A factor applied to the movement across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1348 doc/classes/SliderJoint3D.xml:96
+#: doc/classes/SliderJoint3D.xml:131
+msgid ""
+"The amount of restitution when movement is across axes orthogonal to the "
+"slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1351 doc/classes/SliderJoint3D.xml:93
+#: doc/classes/SliderJoint3D.xml:134
+msgid ""
+"The amount of damping when movement is across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1354 doc/classes/SliderJoint3D.xml:48
+#: doc/classes/SliderJoint3D.xml:137
+msgid "The upper limit of rotation in the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1357 doc/classes/SliderJoint3D.xml:37
+#: doc/classes/SliderJoint3D.xml:140
+msgid "The lower limit of rotation in the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1360 doc/classes/SliderJoint3D.xml:143
+msgid "A factor applied to the all rotation once the limit is surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1363 doc/classes/SliderJoint3D.xml:146
+msgid "The amount of restitution of the rotation when the limit is surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1366 doc/classes/SliderJoint3D.xml:149
+msgid "The amount of damping of the rotation when the limit is surpassed."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1369
+msgid "A factor that gets applied to the all rotation in the limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1372 doc/classes/SliderJoint3D.xml:54
+#: doc/classes/SliderJoint3D.xml:155
+msgid "The amount of restitution of the rotation in the limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1375 doc/classes/SliderJoint3D.xml:51
+#: doc/classes/SliderJoint3D.xml:158
+msgid "The amount of damping of the rotation in the limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1378
+msgid ""
+"A factor that gets applied to the all rotation across axes orthogonal to the "
+"slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1381 doc/classes/SliderJoint3D.xml:63
+#: doc/classes/SliderJoint3D.xml:164
+msgid ""
+"The amount of restitution of the rotation across axes orthogonal to the "
+"slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1384 doc/classes/SliderJoint3D.xml:60
+#: doc/classes/SliderJoint3D.xml:167
+msgid ""
+"The amount of damping of the rotation across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1387
+msgid "Represents the size of the [enum SliderJointParam] enum."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1404
+msgid ""
+"The ease with which the Joint3D twists, if it's too low, it takes more force "
+"to twist the joint."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1416
+msgid ""
+"A factor that gets applied to the movement across the axes. The lower, the "
+"slower the movement."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1419
+msgid ""
+"The amount of restitution on the axes movement. The lower, the more velocity-"
+"energy gets lost."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1425
+msgid "The velocity that the joint's linear motor will attempt to reach."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1428
+msgid ""
+"The maximum force that the linear motor can apply while trying to reach the "
+"target velocity."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1437
+msgid "A factor that gets multiplied onto all rotations across the axes."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1449
+msgid ""
+"When correcting the crossing of limits in rotation across the axes, this "
+"error tolerance factor defines how much the correction gets slowed down. The "
+"lower, the slower."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1458
+msgid ""
+"If [code]set[/code] there is linear motion possible within the given limits."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1461
+msgid "If [code]set[/code] there is rotational motion possible."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1464
+msgid "If [code]set[/code] there is a rotational motor across these axes."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1467
+msgid ""
+"If [code]set[/code] there is a linear motor on this axis that targets a "
+"specific velocity."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1470
+msgid "The [Shape3D] is a [WorldMarginShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1473
+msgid "The [Shape3D] is a [RayShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1476
+msgid "The [Shape3D] is a [SphereShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1479
+msgid "The [Shape3D] is a [BoxShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1482
+msgid "The [Shape3D] is a [CapsuleShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1485
+msgid "The [Shape3D] is a [CylinderShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1488
+msgid "The [Shape3D] is a [ConvexPolygonShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1491
+msgid "The [Shape3D] is a [ConcavePolygonShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsServer3D.xml:1494
+msgid "The [Shape3D] is a [HeightMapShape3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:4
+msgid "Parameters to be sent to a 2D shape physics query."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:7
+msgid ""
+"This class contains the shape and other parameters for 2D intersection/"
+"collision queries. See also [PhysicsShapeQueryResult2D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:18
+msgid ""
+"Sets the [Shape2D] that will be used for collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:24
+msgid "If [code]true[/code], the query will take [Area2D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:27
+msgid ""
+"If [code]true[/code], the query will take [PhysicsBody2D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:30
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:30
+msgid "The physics layer(s) the query will take into account (as a bitmask)."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:33
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:33
+msgid ""
+"The list of objects or object [RID]s that will be excluded from collisions."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:36
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:36 doc/classes/Shape3D.xml:16
+msgid "The collision margin for the shape."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:39
+msgid "The motion of the shape being queried for."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:42
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:39
+msgid "The queried shape's [RID]. See also [method set_shape]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters2D.xml:45
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:42
+msgid "The queried shape's transform matrix."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:4
+msgid "Parameters to be sent to a 3D shape physics query."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:7
+msgid ""
+"This class contains the shape and other parameters for 3D intersection/"
+"collision queries. See also [PhysicsShapeQueryResult3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:18
+msgid ""
+"Sets the [Shape3D] that will be used for collision/intersection queries."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:24
+msgid "If [code]true[/code], the query will take [Area3D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryParameters3D.xml:27
+msgid ""
+"If [code]true[/code], the query will take [PhysicsBody3D]s into account."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:4
+msgid "Result of a 2D shape query in [PhysicsServer2D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:7
+msgid ""
+"The result of a 2D shape query in [PhysicsServer2D]. See also "
+"[PhysicsShapeQueryParameters2D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:16
+#: doc/classes/PhysicsShapeQueryResult3D.xml:16
+msgid "Returns the number of objects that intersected with the shape."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:25
+#: doc/classes/PhysicsShapeQueryResult3D.xml:25
+msgid ""
+"Returns the [Object] that intersected with the shape at index [code]idx[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:34
+#: doc/classes/PhysicsShapeQueryResult3D.xml:34
+msgid ""
+"Returns the instance ID of the [Object] that intersected with the shape at "
+"index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:43
+msgid ""
+"Returns the child index of the object's [Shape2D] that intersected with the "
+"shape at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult2D.xml:52
+#: doc/classes/PhysicsShapeQueryResult3D.xml:52
+msgid ""
+"Returns the [RID] of the object that intersected with the shape at index "
+"[code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult3D.xml:4
+msgid "Result of a 3D shape query in [PhysicsServer3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult3D.xml:7
+msgid ""
+"The result of a 3D shape query in [PhysicsServer3D]. See also "
+"[PhysicsShapeQueryParameters3D]."
+msgstr ""
+
+#: doc/classes/PhysicsShapeQueryResult3D.xml:43
+msgid ""
+"Returns the child index of the object's [Shape3D] that intersected with the "
+"shape at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PinJoint2D.xml:4
+msgid "Pin joint for 2D shapes."
+msgstr ""
+
+#: doc/classes/PinJoint2D.xml:7
+msgid ""
+"Pin joint for 2D rigid bodies. It pins two bodies (rigid or static) together."
+msgstr ""
+
+#: doc/classes/PinJoint2D.xml:15
+msgid ""
+"The higher this value, the more the bond to the pinned partner can flex."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:4
+msgid "Pin joint for 3D shapes."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:7
+msgid ""
+"Pin joint for 3D rigid bodies. It pins 2 bodies (rigid or static) together."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:35 doc/classes/PinJoint3D.xml:46
+msgid ""
+"The force with which the pinned objects stay in positional relation to each "
+"other. The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:38 doc/classes/PinJoint3D.xml:49
+msgid ""
+"The force with which the pinned objects stay in velocity relation to each "
+"other. The higher, the stronger."
+msgstr ""
+
+#: doc/classes/PinJoint3D.xml:41 doc/classes/PinJoint3D.xml:52
+msgid ""
+"If above 0, this value is the maximum value for an impulse that this Joint3D "
+"produces."
+msgstr ""
+
+#: doc/classes/Plane.xml:4
+msgid "Plane in hessian form."
+msgstr ""
+
+#: doc/classes/Plane.xml:7
+msgid ""
+"Plane represents a normalized plane equation. Basically, \"normal\" is the "
+"normal of the plane (a,b,c normalized), and \"d\" is the distance from the "
+"origin to the plane (in the direction of \"normal\"). \"Over\" or \"Above\" "
+"the plane is considered the side of the plane towards where the normal is "
+"pointing."
+msgstr ""
+
+#: doc/classes/Plane.xml:25
+msgid ""
+"Creates a plane from the four parameters. The three components of the "
+"resulting plane's [member normal] are [code]a[/code], [code]b[/code] and "
+"[code]c[/code], and the plane has a distance of [code]d[/code] from the "
+"origin."
+msgstr ""
+
+#: doc/classes/Plane.xml:38
+msgid "Creates a plane from the three points, given in clockwise order."
+msgstr ""
+
+#: doc/classes/Plane.xml:49
+msgid "Creates a plane from the normal and the plane's distance to the origin."
+msgstr ""
+
+#: doc/classes/Plane.xml:56
+msgid "Returns the center of the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:65
+msgid ""
+"Returns the shortest distance from the plane to the position [code]point[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Plane.xml:72
+msgid "Returns a point on the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:83
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is inside the plane (by a "
+"very minimum [code]epsilon[/code] threshold)."
+msgstr ""
+
+#: doc/classes/Plane.xml:94
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Plane.xml:105
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Plane.xml:116
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Plane.xml:125
+msgid ""
+"Returns [code]true[/code] if this plane and [code]plane[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Plane.xml:134
+msgid ""
+"Returns [code]true[/code] if [code]point[/code] is located above the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:141
+msgid "Returns a copy of the plane, normalized."
+msgstr ""
+
+#: doc/classes/Plane.xml:150
+msgid ""
+"Returns the orthogonal projection of point [code]p[/code] into a point in "
+"the plane."
+msgstr ""
+
+#: doc/classes/Plane.xml:156
+msgid ""
+"Distance from the origin to the plane, in the direction of [member normal]."
+msgstr ""
+
+#: doc/classes/Plane.xml:159
+msgid ""
+"The normal of the plane. \"Over\" or \"Above\" the plane is considered the "
+"side of the plane towards where the normal is pointing."
+msgstr ""
+
+#: doc/classes/Plane.xml:162
+msgid "The [member normal]'s X component."
+msgstr ""
+
+#: doc/classes/Plane.xml:165
+msgid "The [member normal]'s Y component."
+msgstr ""
+
+#: doc/classes/Plane.xml:168
+msgid "The [member normal]'s Z component."
+msgstr ""
+
+#: doc/classes/Plane.xml:173
+msgid "A plane that extends in the Y and Z axes."
+msgstr ""
+
+#: doc/classes/Plane.xml:176
+msgid "A plane that extends in the X and Z axes."
+msgstr ""
+
+#: doc/classes/Plane.xml:179
+msgid "A plane that extends in the X and Y axes."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:4
+msgid "Class representing a planar [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:7
+msgid ""
+"Class representing a planar [PrimitiveMesh]. This flat mesh does not have a "
+"thickness. By default, this mesh is aligned on the X and Z axes; this "
+"default rotation isn't suited for use with billboarded materials. For "
+"billboarded materials, use [QuadMesh] instead."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:15
+msgid "Size of the generated plane."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:18
+msgid "Number of subdivision along the Z axis."
+msgstr ""
+
+#: doc/classes/PlaneMesh.xml:21
+msgid "Number of subdivision along the X axis."
+msgstr ""
+
+#: modules/gdnative/doc_classes/PluginScript.xml:14
+msgid "Returns a new instance of the script."
+msgstr ""
+
+#: doc/classes/PointMesh.xml:4
+msgid "Mesh with a single Point primitive."
+msgstr ""
+
+#: doc/classes/PointMesh.xml:7
+msgid ""
+"The PointMesh is made from a single point. Instead of relying on triangles, "
+"points are rendered as a single rectangle on the screen with a constant "
+"size. They are intended to be used with Particle systems, but can be used as "
+"a cheap way to render constant size billboarded sprites (for example in a "
+"point cloud).\n"
+"PointMeshes, must be used with a material that has a point size. Point size "
+"can be accessed in a shader with [code]POINT_SIZE[/code], or in a "
+"[BaseMaterial3D] by setting [member BaseMaterial3D.use_point_size] and the "
+"variable [member BaseMaterial3D.point_size].\n"
+"When using PointMeshes, properties that normally alter vertices will be "
+"ignored, including billboard mode, grow, and cull face."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:4
+msgid "A 2D polygon."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:7
+msgid ""
+"A Polygon2D is defined by a set of points. Each point is connected to the "
+"next, with the final point being connected to the first, resulting in a "
+"closed polygon. Polygon2Ds can be filled with color (solid or gradient) or "
+"filled with a given texture."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:20
+msgid ""
+"Adds a bone with the specified [code]path[/code] and [code]weights[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:27
+msgid "Removes all bones from this [Polygon2D]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:36
+msgid "Removes the specified bone from this [Polygon2D]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:43
+msgid "Returns the number of bones in this [Polygon2D]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:52
+msgid "Returns the path to the node associated with the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:61
+msgid "Returns the height values of the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:72
+msgid "Sets the path to the node associated with the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:83
+msgid "Sets the weight values for the specified bone."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:89
+msgid "If [code]true[/code], polygon edges will be anti-aliased."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:94
+msgid ""
+"The polygon's fill color. If [code]texture[/code] is defined, it will be "
+"multiplied by this color. It will also be the default color for vertices not "
+"set in [code]vertex_colors[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:99
+msgid ""
+"Added padding applied to the bounding box when using [code]invert[/code]. "
+"Setting this value too small may result in a \"Bad Polygon\" error."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:102
+msgid ""
+"If [code]true[/code], polygon will be inverted, containing the area outside "
+"the defined points and extending to the [code]invert_border[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:107
+msgid "The offset applied to each vertex."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:110
+msgid ""
+"The polygon's list of vertices. The final point will be connected to the "
+"first.\n"
+"[b]Note:[/b] This returns a copy of the [PackedVector2Array] rather than a "
+"reference."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:124
+msgid ""
+"The polygon's fill texture. Use [code]uv[/code] to set texture coordinates."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:127
+msgid ""
+"Amount to offset the polygon's [code]texture[/code]. If [code](0, 0)[/code] "
+"the texture's origin (its top-left corner) will be placed at the polygon's "
+"[code]position[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:130
+msgid "The texture's rotation in radians."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:133
+msgid "The texture's rotation in degrees."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:136
+msgid ""
+"Amount to multiply the [code]uv[/code] coordinates when using a "
+"[code]texture[/code]. Larger values make the texture smaller, and vice versa."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:139
+msgid ""
+"Texture coordinates for each vertex of the polygon. There should be one "
+"[code]uv[/code] per polygon vertex. If there are fewer, undefined vertices "
+"will use [code](0, 0)[/code]."
+msgstr ""
+
+#: doc/classes/Polygon2D.xml:142
+msgid ""
+"Color for each vertex. Colors are interpolated between vertices, resulting "
+"in smooth gradients. There should be one per polygon vertex. If there are "
+"fewer, undefined vertices will use [code]color[/code]."
+msgstr ""
+
+#: doc/classes/Popup.xml:4
+msgid "Base container control for popups and dialogs."
+msgstr ""
+
+#: doc/classes/Popup.xml:7
+msgid ""
+"Popup is a base [Control] used to show dialogs and popups. It's a subwindow "
+"and modal by default (see [Control]) and has helpers for custom popup "
+"behavior."
+msgstr ""
+
+#: doc/classes/Popup.xml:23
+msgid "Emitted when a popup is hidden."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:4
+msgid "PopupMenu displays a list of options."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:7
+msgid ""
+"[PopupMenu] is a [Control] that displays a list of options. They are popular "
+"in toolbars or context menus."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:22
+msgid ""
+"Adds a new checkable item with text [code]label[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:37
+msgid ""
+"Adds a new checkable item and assigns the specified [ShortCut] to it. Sets "
+"the label of the checkbox to the [ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:54
+msgid ""
+"Adds a new checkable item with text [code]label[/code] and icon "
+"[code]texture[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:71
+msgid ""
+"Adds a new checkable item and assigns the specified [ShortCut] and icon "
+"[code]texture[/code] to it. Sets the label of the checkbox to the "
+"[ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:88
+msgid ""
+"Adds a new item with text [code]label[/code] and icon [code]texture[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:104
+msgid "Same as [method add_icon_check_item], but uses a radio check button."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:119
+msgid ""
+"Same as [method add_icon_check_shortcut], but uses a radio check button."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:134
+msgid ""
+"Adds a new item and assigns the specified [ShortCut] and icon [code]texture[/"
+"code] to it. Sets the label of the checkbox to the [ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:148
+msgid ""
+"Adds a new item with text [code]label[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:166
+msgid ""
+"Adds a new multistate item with text [code]label[/code].\n"
+"Contrarily to normal binary items, multistate items can have more than two "
+"states, as defined by [code]max_states[/code]. Each press or activate of the "
+"item will increase the state by one. The default value is defined by "
+"[code]default_state[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:181
+msgid ""
+"Adds a new radio check button with text [code]label[/code].\n"
+"An [code]id[/code] can optionally be provided, as well as an accelerator "
+"([code]accel[/code]). If no [code]id[/code] is provided, one will be created "
+"from the index. If no [code]accel[/code] is provided then the default "
+"[code]0[/code] will be assigned to it. See [method get_item_accelerator] for "
+"more info on accelerators.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:196
+msgid ""
+"Adds a new radio check button and assigns a [ShortCut] to it. Sets the label "
+"of the checkbox to the [ShortCut]'s name.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually. See "
+"[method set_item_checked] for more info on how to control it."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:207
+msgid "Adds a separator between items. Separators also occupy an index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:220
+msgid ""
+"Adds a [ShortCut].\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:234
+msgid ""
+"Adds an item that will act as a submenu of the parent [PopupMenu] node when "
+"clicked. The [code]submenu[/code] argument is the name of the child "
+"[PopupMenu] node that will be shown when the item is clicked.\n"
+"An [code]id[/code] can optionally be provided. If no [code]id[/code] is "
+"provided, one will be created from the index."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:242
+msgid "Removes all items from the [PopupMenu]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:251
+msgid ""
+"Returns the accelerator of the item at index [code]idx[/code]. Accelerators "
+"are special combinations of keys that activate the item, no matter which "
+"control is focused."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:258
+msgid "Returns the number of items in the [PopupMenu]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:276
+msgid ""
+"Returns the id of the item at index [code]idx[/code]. [code]id[/code] can be "
+"manually assigned, while index can not."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:285
+msgid ""
+"Returns the index of the item containing the specified [code]id[/code]. "
+"Index is automatically assigned to each item by the engine. Index can not be "
+"set manually."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:294
+msgid ""
+"Returns the metadata of the specified item, which might be of any type. You "
+"can set it with [method set_item_metadata], which provides a simple way of "
+"assigning context data to items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:303
+msgid ""
+"Returns the [ShortCut] associated with the specified [code]idx[/code] item."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:312
+msgid ""
+"Returns the submenu name of the item at index [code]idx[/code]. See [method "
+"add_submenu_item] for more info on how to add a submenu."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:330
+msgid ""
+"Returns the tooltip associated with the specified index index [code]idx[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:339
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is checkable "
+"in some way, i.e. if it has a checkbox or radio button.\n"
+"[b]Note:[/b] Checkable items just display a checkmark or radio button, but "
+"don't have any built-in checking behavior and must be checked/unchecked "
+"manually."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:349
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is checked."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:358
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] is disabled. "
+"When it is disabled it can't be selected, or its action invoked.\n"
+"See [method set_item_disabled] for more info on how to disable an item."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:368
+msgid ""
+"Returns [code]true[/code] if the item at index [code]idx[/code] has radio "
+"button-style checkability.\n"
+"[b]Note:[/b] This is purely cosmetic; you must add the logic for checking/"
+"unchecking items in radio groups."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:378
+msgid ""
+"Returns [code]true[/code] if the item is a separator. If it is, it will be "
+"displayed as a line. See [method add_separator] for more info on how to add "
+"a separator."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:387
+msgid "Returns [code]true[/code] if the specified item's shortcut is disabled."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:396
+msgid ""
+"Removes the item at index [code]idx[/code] from the menu.\n"
+"[b]Note:[/b] The indices of items after the removed item will be shifted by "
+"one."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:408
+msgid ""
+"Sets the accelerator of the item at index [code]idx[/code]. Accelerators are "
+"special combinations of keys that activate the item, no matter which control "
+"is focused."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:419
+msgid ""
+"Sets whether the item at index [code]idx[/code] has a checkbox. If "
+"[code]false[/code], sets the type of the item to plain text.\n"
+"[b]Note:[/b] Checkable items just display a checkmark, but don't have any "
+"built-in checking behavior and must be checked/unchecked manually."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:431
+msgid ""
+"Sets the type of the item at the specified index [code]idx[/code] to radio "
+"button. If [code]false[/code], sets the type of the item to plain text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:442
+msgid ""
+"Mark the item at index [code]idx[/code] as a separator, which means that it "
+"would be displayed as a line. If [code]false[/code], sets the type of the "
+"item to plain text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:453
+msgid "Sets the checkstate status of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:464
+msgid ""
+"Enables/disables the item at index [code]idx[/code]. When it is disabled, it "
+"can't be selected and its action can't be invoked."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:475
+msgid "Replaces the [Texture2D] icon of the specified [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:486
+msgid "Sets the [code]id[/code] of the item at index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:497
+msgid ""
+"Sets the metadata of an item, which may be of any type. You can later get it "
+"with [method get_item_metadata], which provides a simple way of assigning "
+"context data to items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:508
+msgid ""
+"Sets the state of an multistate item. See [method add_multistate_item] for "
+"details."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:521
+msgid "Sets a [ShortCut] for the specified item [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:532
+msgid "Disables the [ShortCut] of the specified index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:543
+msgid ""
+"Sets the submenu of the item at index [code]idx[/code]. The submenu is the "
+"name of a child [PopupMenu] node that would be shown when the item is "
+"clicked."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:565
+msgid ""
+"Sets the [String] tooltip of the item at the specified index [code]idx[/"
+"code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:574
+msgid ""
+"Toggles the check state of the item of the specified index [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:583
+msgid ""
+"Cycle to the next state of an multistate item. See [method "
+"add_multistate_item] for details."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:589
+msgid "If [code]true[/code], allows to navigate [PopupMenu] with letter keys."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:592
+msgid ""
+"If [code]true[/code], hides the [PopupMenu] when a checkbox or radio button "
+"is selected."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:595
+msgid "If [code]true[/code], hides the [PopupMenu] when an item is selected."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:598
+msgid ""
+"If [code]true[/code], hides the [PopupMenu] when a state item is selected."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:601
+msgid ""
+"Sets the delay time in seconds for the submenu item to popup on mouse "
+"hovering. If the popup menu is added as a child of another (acting as a "
+"submenu), it will inherit the delay time of the parent menu item."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:609
+msgid ""
+"Emitted when user navigated to an item of some [code]id[/code] using "
+"[code]ui_up[/code] or [code]ui_down[/code] action."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:616
+msgid ""
+"Emitted when an item of some [code]id[/code] is pressed or its accelerator "
+"is activated."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:623
+msgid ""
+"Emitted when an item of some [code]index[/code] is pressed or its "
+"accelerator is activated."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:631
+msgid "[Texture2D] icon for the checked checkbox items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:634
+msgid "[Font] used for the menu items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:637
+msgid "The default text [Color] for menu items' names."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:640
+msgid ""
+"The text [Color] used for shortcuts and accelerators that show next to the "
+"menu item name when defined. See [method get_item_accelerator] for more info "
+"on accelerators."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:643
+msgid "[Color] used for disabled menu items' text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:646
+msgid "[Color] used for the hovered text."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:649
+msgid "[StyleBox] displayed when the [PopupMenu] item is hovered."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:652
+msgid ""
+"The horizontal space between the item's name and the shortcut text/submenu "
+"arrow."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:655
+msgid ""
+"[StyleBox] for the left side of labeled separator. See [method "
+"add_separator]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:658
+msgid ""
+"[StyleBox] for the right side of labeled separator. See [method "
+"add_separator]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:661
+msgid "Default [StyleBox] of the [PopupMenu] items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:664
+msgid "[StyleBox] used when the [PopupMenu] item is disabled."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:667
+msgid "[Texture2D] icon for the checked radio button items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:670
+msgid "[Texture2D] icon for the unchecked radio button items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:673
+msgid "[StyleBox] used for the separators. See [method add_separator]."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:676
+msgid "[Texture2D] icon for the submenu arrow."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:679
+msgid "[Texture2D] icon for the unchecked checkbox items."
+msgstr ""
+
+#: doc/classes/PopupMenu.xml:682
+msgid "The vertical space between each menu item."
+msgstr ""
+
+#: doc/classes/PopupPanel.xml:4
+msgid "Class for displaying popups with a panel background."
+msgstr ""
+
+#: doc/classes/PopupPanel.xml:7
+msgid ""
+"Class for displaying popups with a panel background. In some cases it might "
+"be simpler to use than [Popup], since it provides a configurable background. "
+"If you are making windows, better check [Window]."
+msgstr ""
+
+#: doc/classes/PopupPanel.xml:17
+msgid "The background panel style of this [PopupPanel]."
+msgstr ""
+
+#: doc/classes/Position2D.xml:4
+msgid "Generic 2D position hint for editing."
+msgstr ""
+
+#: doc/classes/Position2D.xml:7
+msgid ""
+"Generic 2D position hint for editing. It's just like a plain [Node2D], but "
+"it displays as a cross in the 2D editor at all times. You can set cross' "
+"visual size by using the gizmo in the 2D editor while the node is selected."
+msgstr ""
+
+#: doc/classes/Position3D.xml:4
+msgid "Generic 3D position hint for editing."
+msgstr ""
+
+#: doc/classes/Position3D.xml:7
+msgid ""
+"Generic 3D position hint for editing. It's just like a plain [Node3D], but "
+"it displays as a cross in the 3D editor at all times."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:4
+msgid ""
+"Base class for all primitive meshes. Handles applying a [Material] to a "
+"primitive mesh."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:7
+msgid ""
+"Base class for all primitive meshes. Handles applying a [Material] to a "
+"primitive mesh. Examples include [CapsuleMesh], [CubeMesh], [CylinderMesh], "
+"[PlaneMesh], [PrismMesh], [QuadMesh], and [SphereMesh]."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:16
+msgid ""
+"Returns mesh arrays used to constitute surface of [Mesh]. Mesh arrays can be "
+"used with [ArrayMesh] to create new surfaces."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:22
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:25
+msgid ""
+"If set, the order of the vertices in each triangle are reversed resulting in "
+"the backside of the mesh being drawn.\n"
+"This gives the same result as using [constant BaseMaterial3D.CULL_BACK] in "
+"[member BaseMaterial3D.cull_mode]."
+msgstr ""
+
+#: doc/classes/PrimitiveMesh.xml:29
+msgid "The current [Material] of the primitive mesh."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:4 doc/classes/PrismMesh.xml:7
+msgid "Class representing a prism-shaped [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:15
+msgid ""
+"Displacement of the upper edge along the X axis. 0.0 positions edge straight "
+"above the bottom-left edge."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:18
+msgid "Size of the prism."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:21
+msgid "Number of added edge loops along the Z axis."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:24
+msgid "Number of added edge loops along the Y axis."
+msgstr ""
+
+#: doc/classes/PrismMesh.xml:27
+msgid "Number of added edge loops along the X axis."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:4
+msgid ""
+"A [Material] used with [Sky] to generate a background based on user input "
+"parameters."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:7
+msgid ""
+"ProceduralSkyMaterial provides a way to create an effective background "
+"quickly by defining procedural parameters for the sun, the sky and the "
+"ground. The sky and ground are very similar, they are defined by a color at "
+"the horizon, another color, and finally an easing curve to interpolate "
+"between these two colors. Similarly, the sun is described by a position in "
+"the sky, a color, and an easing curve. However, the sun also defines a "
+"minimum and maximum angle, these two values define at what distance the "
+"easing curve begins and ends from the sun, and thus end up defining the size "
+"of the sun in the sky.\n"
+"The [ProceduralSkyMaterial] uses a lightweight shader to draw the sky and is "
+"thus suited for real time updates. When you do not need a quick sky that is "
+"not realistic, this is a good option.\n"
+"The [ProceduralSkyMaterial] supports up to 4 suns. Each sun takes its color, "
+"energy, and direction from the corresponding [DirectionalLight3D] in the "
+"scene."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:17
+msgid ""
+"Color of the ground at the bottom. Blends with [member ground_horizon_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:20
+msgid ""
+"How quickly the [member ground_horizon_color] fades into the [member "
+"ground_bottom_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:23
+msgid "Amount of energy contribution from the ground."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:26
+msgid ""
+"Color of the ground at the horizon. Blends with [member ground_bottom_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:29
+msgid ""
+"How quickly the [member sky_horizon_color] fades into the [member "
+"sky_top_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:32
+msgid "Amount of energy contribution from the sky."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:35
+msgid "Color of the sky at the horizon. Blends with [member sky_top_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:38
+msgid "Color of the sky at the top. Blends with [member sky_horizon_color]."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:41
+msgid "Distance from center of sun where it fades out completely."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:44
+msgid "Distance from sun where it goes from solid to starting to fade."
+msgstr ""
+
+#: doc/classes/ProceduralSkyMaterial.xml:47
+msgid ""
+"How quickly the sun fades away between [member sun_angle_min] and [member "
+"sun_angle_max]."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:4
+msgid "General-purpose progress bar."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:7
+msgid "General-purpose progress bar. Shows fill percentage from right to left."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:15
+msgid "If [code]true[/code], the fill percentage is displayed on the bar."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:24
+msgid "The style of the background."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:27
+msgid "The style of the progress (i.e. the part that fills the bar)."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:30
+msgid ""
+"Font used to draw the fill percentage if [member percent_visible] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:33
+msgid "The color of the text."
+msgstr ""
+
+#: doc/classes/ProgressBar.xml:36
+msgid "The color of the text's shadow."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:4
+msgid "Contains global variables accessible from everywhere."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:20
+msgid ""
+"Adds a custom property info to a property. The dictionary must contain:\n"
+"- [code]name[/code]: [String] (the property's name)\n"
+"- [code]type[/code]: [int] (see [enum Variant.Type])\n"
+"- optionally [code]hint[/code]: [int] (see [enum PropertyHint]) and "
+"[code]hint_string[/code]: [String]\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"ProjectSettings.set(\"category/property_name\", 0)\n"
+"\n"
+"var property_info = {\n"
+" \"name\": \"category/property_name\",\n"
+" \"type\": TYPE_INT,\n"
+" \"hint\": PROPERTY_HINT_ENUM,\n"
+" \"hint_string\": \"one,two,three\"\n"
+"}\n"
+"\n"
+"ProjectSettings.add_property_info(property_info)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:45
+msgid "Clears the whole configuration (not recommended, may break things)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:54
+msgid ""
+"Returns the order of a configuration value (influences when saved to the "
+"config file)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:63
+msgid ""
+"Returns the value of a setting.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"print(ProjectSettings.get_setting(\"application/config/name\"))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:76
+msgid ""
+"Converts a localized path ([code]res://[/code]) to a full native OS path."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:85
+msgid "Returns [code]true[/code] if a configuration value is present."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:96
+msgid ""
+"Loads the contents of the .pck or .zip file specified by [code]pack[/code] "
+"into the resource filesystem ([code]res://[/code]). Returns [code]true[/"
+"code] on success.\n"
+"[b]Note:[/b] If a file from [code]pack[/code] shares the same path as a file "
+"already in the resource filesystem, any attempts to load that file will use "
+"the file from [code]pack[/code] unless [code]replace_files[/code] is set to "
+"[code]false[/code]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:106
+msgid "Convert a path to a localized path ([code]res://[/code] path)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:115
+msgid ""
+"Returns [code]true[/code] if the specified property exists and its initial "
+"value differs from the current value."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:124
+msgid ""
+"Returns the specified property's initial value. Returns [code]null[/code] if "
+"the property does not exist."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:131
+msgid "Saves the configuration to the [code]project.godot[/code] file."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:140
+msgid "Saves the configuration to a custom file."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:151
+msgid ""
+"Sets the specified property's initial value. This is the value the property "
+"reverts to."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:162
+msgid ""
+"Sets the order of a configuration value (influences when saved to the config "
+"file)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:173
+msgid ""
+"Sets the value of a setting.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"ProjectSettings.set_setting(\"application/config/name\", \"Example\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:183
+msgid "Background color for the boot splash."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:186
+msgid ""
+"If [code]true[/code], scale the boot splash image to the full window length "
+"when engine starts. If [code]false[/code], the engine will leave it at the "
+"default pixel size."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:189
+msgid "Path to an image used as the boot splash."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:192
+msgid ""
+"If [code]true[/code], applies linear filtering when scaling the image "
+"(recommended for high resolution artwork). If [code]false[/code], uses "
+"nearest-neighbor interpolation (recommended for pixel art)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:195
+msgid ""
+"This user directory is used for storing persistent data ([code]user://[/"
+"code] filesystem). If left empty, [code]user://[/code] resolves to a project-"
+"specific folder in Godot's own configuration folder (see [method OS."
+"get_user_data_dir]). If a custom directory name is defined, this name will "
+"be used instead and appended to the system-specific user data directory "
+"(same parent folder as the Godot configuration folder documented in [method "
+"OS.get_user_data_dir]).\n"
+"The [member application/config/use_custom_user_dir] setting must be enabled "
+"for this to take effect."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:199
+msgid ""
+"The project's description, displayed as a tooltip in the Project Manager "
+"when hovering the project."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:202
+msgid ""
+"Icon used for the project, set when project loads. Exporters will also use "
+"this icon when possible."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:205
+msgid ""
+"Icon set in [code].icns[/code] format used on macOS to set the game's icon. "
+"This is done automatically on start by calling [method DisplayServer."
+"set_native_icon]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:208
+msgid ""
+"The project's name. It is used both by the Project Manager and by exporters. "
+"The project name can be translated by translating its value in localization "
+"files."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:211
+msgid ""
+"Specifies a file to override project settings. For example: [code]user://"
+"custom_settings.cfg[/code].\n"
+"[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)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:215
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:218
+msgid ""
+"Icon set in [code].ico[/code] format used on Windows to set the game's icon. "
+"This is done automatically on start by calling [method DisplayServer."
+"set_native_icon]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:221
+msgid ""
+"If [code]true[/code], disables printing to standard error in an exported "
+"build."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:224
+msgid ""
+"If [code]true[/code], disables printing to standard output in an exported "
+"build."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:227
+msgid ""
+"Forces a delay between frames in the main loop (in milliseconds). This may "
+"be useful if you plan to disable vertical synchronization."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:230
+msgid ""
+"If [code]true[/code], enables low-processor usage mode. This setting only "
+"works on desktop platforms. The screen is not redrawn if nothing changes "
+"visually. This is meant for writing applications and editors, but is pretty "
+"useless (and can hurt performance) in most games."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:233
+msgid ""
+"Amount of sleeping between frames when the low-processor usage mode is "
+"enabled (in microseconds). Higher values will result in lower CPU usage."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:236
+msgid "Path to the main scene file that will be loaded when the project runs."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:239 doc/classes/ProjectSettings.xml:242
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:245
+msgid ""
+"Default [AudioBusLayout] resource file to use in the project, unless "
+"overridden by the scene."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:248
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:251
+msgid ""
+"If [code]true[/code], microphone input will be allowed. This requires "
+"appropriate permissions to be set when exporting to Android or iOS."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:254
+msgid ""
+"Mixing rate used for audio. In general, it's better to not touch this and "
+"leave it to the host operating system."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:257
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:260
+msgid ""
+"Setting to hardcode audio delay when playing video. Best to leave this "
+"untouched unless you know what you are doing."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:263
+msgid ""
+"Default compression level for gzip. Affects compressed scenes and resources."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:266
+msgid ""
+"Default compression level for Zlib. Affects compressed scenes and resources."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:269
+msgid ""
+"Default compression level for Zstandard. Affects compressed scenes and "
+"resources."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:272
+msgid "Enables long-distance matching in Zstandard."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:275
+msgid ""
+"Largest size limit (in power of 2) allowed when compressing using long-"
+"distance matching with Zstandard."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:278
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:281
+msgid ""
+"If [code]true[/code], enables warnings when a constant is used as a function."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:284
+msgid ""
+"If [code]true[/code], enables warnings when deprecated keywords are used."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:287
+msgid ""
+"If [code]true[/code], enables specific GDScript warnings (see [code]debug/"
+"gdscript/warnings/*[/code] settings). If [code]false[/code], disables all "
+"GDScript warnings."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:290
+msgid ""
+"If [code]true[/code], scripts in the [code]res://addons[/code] folder will "
+"not generate warnings."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:293
+msgid ""
+"If [code]true[/code], enables warnings when a function is declared with the "
+"same name as a constant."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:296
+msgid ""
+"If [code]true[/code], enables warnings when a function is declared with the "
+"same name as a variable. This will turn into an error in a future version "
+"when first-class functions become supported in GDScript."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:299
+msgid ""
+"If [code]true[/code], enables warnings when a function assigned to a "
+"variable may yield and return a function state instead of a value."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:302
+msgid ""
+"If [code]true[/code], enables warnings when using a function as if it was a "
+"property."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:305
+msgid ""
+"If [code]true[/code], enables warnings when a ternary operator may emit "
+"values with incompatible types."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:308
+msgid ""
+"If [code]true[/code], enables warnings when dividing an integer by another "
+"integer (the decimal part will be discarded)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:311
+msgid ""
+"If [code]true[/code], enables warnings when passing a floating-point value "
+"to a function that expects an integer (it will be converted and lose "
+"precision)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:314
+msgid ""
+"If [code]true[/code], enables warnings when using a property as if it was a "
+"function."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:317
+msgid ""
+"If [code]true[/code], enables warnings when calling a function without using "
+"its return value (by assigning it to a variable or using it as a function "
+"argument). Such return values are sometimes used to denote possible errors "
+"using the [enum Error] enum."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:320
+msgid ""
+"If [code]true[/code], enables warnings when defining a local or subclass "
+"member variable that would shadow a variable at an upper level (such as a "
+"member variable)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:323
+msgid ""
+"If [code]true[/code], enables warnings when calling an expression that has "
+"no effect on the surrounding code, such as writing [code]2 + 2[/code] as a "
+"statement."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:326
+msgid ""
+"If [code]true[/code], enables warnings when calling a ternary expression "
+"that has no effect on the surrounding code, such as writing [code]42 if "
+"active else 0[/code] as a statement."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:329
+msgid ""
+"If [code]true[/code], all warnings will be reported as if they were errors."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:332
+msgid ""
+"If [code]true[/code], enables warnings when using a variable that wasn't "
+"previously assigned."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:335
+msgid ""
+"If [code]true[/code], enables warnings when assigning a variable using an "
+"assignment operator like [code]+=[/code] if the variable wasn't previously "
+"assigned."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:338
+msgid ""
+"If [code]true[/code], enables warnings when unreachable code is detected "
+"(such as after a [code]return[/code] statement that will always be executed)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:341
+msgid ""
+"If [code]true[/code], enables warnings when using an expression whose type "
+"may not be compatible with the function parameter expected."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:344
+msgid "If [code]true[/code], enables warnings when performing an unsafe cast."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:347
+msgid ""
+"If [code]true[/code], enables warnings when calling a method whose presence "
+"is not guaranteed at compile-time in the class."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:350
+msgid ""
+"If [code]true[/code], enables warnings when accessing a property whose "
+"presence is not guaranteed at compile-time in the class."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:353
+msgid ""
+"If [code]true[/code], enables warnings when a function parameter is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:356
+msgid ""
+"If [code]true[/code], enables warnings when a member variable is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:359
+msgid "If [code]true[/code], enables warnings when a signal is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:362
+msgid "If [code]true[/code], enables warnings when a local variable is unused."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:365
+msgid ""
+"If [code]true[/code], enables warnings when a variable is declared with the "
+"same name as a function. This will turn into an error in a future version "
+"when first-class functions become supported in GDScript."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:368
+msgid ""
+"If [code]true[/code], enables warnings when assigning the result of a "
+"function that returns [code]void[/code] to a variable."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:371
+msgid "Message to be displayed before the backtrace when the engine crashes."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:374
+msgid ""
+"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.\n"
+"If [member display/window/vsync/use_vsync] is enabled, it takes precedence "
+"and the forced FPS number cannot exceed the monitor's refresh rate.\n"
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:379
+msgid "Maximum call stack allowed for debugging GDScript."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:382
+msgid "Maximum amount of functions per frame allowed when profiling."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:385
+msgid "Print frames per second to standard output every second."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:388
+msgid ""
+"Print more information to standard output when running. It displays "
+"information such as memory leaks, which scenes and resources are being "
+"loaded, etc."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:391
+msgid "Maximum call stack in visual scripting, to avoid infinite recursion."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:394
+msgid ""
+"Color of the contact points between collision shapes, visible when \"Visible "
+"Collision Shapes\" is enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:397
+msgid ""
+"Maximum number of contact points between collision shapes to display when "
+"\"Visible Collision Shapes\" is enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:400
+msgid ""
+"Color of the collision shapes, visible when \"Visible Collision Shapes\" is "
+"enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:403
+msgid ""
+"Color of the disabled navigation geometry, visible when \"Visible Navigation"
+"\" is enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:406
+msgid ""
+"Color of the navigation geometry, visible when \"Visible Navigation\" is "
+"enabled in the Debug menu."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:409
+msgid "Custom image for the mouse cursor (limited to 256×256)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:412
+msgid "Hotspot for the custom mouse cursor image."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:415
+msgid "Position offset for tooltips, relative to the mouse cursor's hotspot."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:418
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:421
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:424
+msgid "Default orientation on mobile devices."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:427
+msgid ""
+"If [code]true[/code], the home indicator is hidden automatically. This only "
+"affects iOS devices without a physical home button."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:430
+msgid "Force the window to be always on top."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:433
+msgid "Force the window to be borderless."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:436
+msgid "Sets the window to full screen when it starts."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:439
+msgid ""
+"Sets the game's main viewport height. On desktop platforms, this is the "
+"default window size. Stretch mode settings also use this as a reference when "
+"enabled."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:442
+msgid "Allows the window to be resizable by default."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:445
+msgid ""
+"If greater than zero, overrides the window height when running the game. "
+"Useful for testing stretch modes."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:448
+msgid ""
+"If greater than zero, overrides the window width when running the game. "
+"Useful for testing stretch modes."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:451
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:454
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:457
+msgid ""
+"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.)\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:461
+msgid ""
+"Search path for project-specific script templates. Script templates will be "
+"search both in the editor-specific path and in this project-specific path."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:464
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:467
+msgid ""
+"Default value for [member ScrollContainer.scroll_deadzone], which will be "
+"used for all [ScrollContainer]s unless overridden."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:470
+msgid ""
+"If [code]true[/code], swaps OK and Cancel buttons in dialogs on Windows and "
+"UWP to follow interface conventions."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:473
+msgid ""
+"Path to a custom [Theme] resource file to use for the project ([code]theme[/"
+"code] or generic [code]tres[/code]/[code]res[/code] extension)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:476
+msgid ""
+"Path to a custom [Font] resource to use as default for all GUI elements of "
+"the project."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:479
+msgid "If [code]true[/code], makes sure the theme used works with HiDPI."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:482
+msgid ""
+"Timer setting for incremental search in [Tree], [ItemList], etc. controls "
+"(in milliseconds)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:485
+msgid "Timer for detecting idle in [TextEdit] (in seconds)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:488
+msgid "Default delay for tooltips (in seconds)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:491
+msgid ""
+"Default [InputEventAction] to confirm a focused button, menu or list item, "
+"or validate input.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:495
+msgid ""
+"Default [InputEventAction] to discard a modal or pending input.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:499
+msgid ""
+"Default [InputEventAction] to move down in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:503
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:507
+msgid ""
+"Default [InputEventAction] to focus the next [Control] in the scene. The "
+"focus behavior can be configured via [member Control.focus_next].\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:511
+msgid ""
+"Default [InputEventAction] to focus the previous [Control] in the scene. The "
+"focus behavior can be configured via [member Control.focus_previous].\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:515
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:519
+msgid ""
+"Default [InputEventAction] to move left in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:523
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:527
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:531
+msgid ""
+"Default [InputEventAction] to move right in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:535
+msgid ""
+"Default [InputEventAction] to select an item in a [Control] (e.g. in an "
+"[ItemList] or a [Tree]).\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:539
+msgid ""
+"Default [InputEventAction] to move up in the UI.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:543
+msgid ""
+"If [code]true[/code], sends mouse input events when tapping or swiping on "
+"the touchscreen."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:546
+msgid ""
+"If [code]true[/code], sends touch input events when clicking or dragging the "
+"mouse."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:549
+msgid "Optional name for the 2D physics layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:552
+msgid "Optional name for the 2D physics layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:555
+msgid "Optional name for the 2D physics layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:558
+msgid "Optional name for the 2D physics layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:561
+msgid "Optional name for the 2D physics layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:564
+msgid "Optional name for the 2D physics layer 14."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:567
+msgid "Optional name for the 2D physics layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:570
+msgid "Optional name for the 2D physics layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:573
+msgid "Optional name for the 2D physics layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:576
+msgid "Optional name for the 2D physics layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:579
+msgid "Optional name for the 2D physics layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:582
+msgid "Optional name for the 2D physics layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:585
+msgid "Optional name for the 2D physics layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:588
+msgid "Optional name for the 2D physics layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:591
+msgid "Optional name for the 2D physics layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:594
+msgid "Optional name for the 2D physics layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:597
+msgid "Optional name for the 2D physics layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:600
+msgid "Optional name for the 2D physics layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:603
+msgid "Optional name for the 2D physics layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:606
+msgid "Optional name for the 2D physics layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:609
+msgid "Optional name for the 2D render layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:612
+msgid "Optional name for the 2D render layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:615
+msgid "Optional name for the 2D render layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:618
+msgid "Optional name for the 2D render layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:621
+msgid "Optional name for the 2D render layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:624
+msgid "Optional name for the 2D render layer 14."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:627
+msgid "Optional name for the 2D render layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:630
+msgid "Optional name for the 2D render layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:633
+msgid "Optional name for the 2D render layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:636
+msgid "Optional name for the 2D render layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:639
+msgid "Optional name for the 2D render layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:642
+msgid "Optional name for the 2D render layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:645
+msgid "Optional name for the 2D render layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:648
+msgid "Optional name for the 2D render layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:651
+msgid "Optional name for the 2D render layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:654
+msgid "Optional name for the 2D render layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:657
+msgid "Optional name for the 2D render layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:660
+msgid "Optional name for the 2D render layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:663
+msgid "Optional name for the 2D render layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:666
+msgid "Optional name for the 2D render layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:669
+msgid "Optional name for the 3D physics layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:672
+msgid "Optional name for the 3D physics layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:675
+msgid "Optional name for the 3D physics layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:678
+msgid "Optional name for the 3D physics layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:681
+msgid "Optional name for the 3D physics layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:684
+msgid "Optional name for the 3D physics layer 14."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:687
+msgid "Optional name for the 3D physics layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:690
+msgid "Optional name for the 3D physics layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:693
+msgid "Optional name for the 3D physics layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:696
+msgid "Optional name for the 3D physics layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:699
+msgid "Optional name for the 3D physics layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:702
+msgid "Optional name for the 3D physics layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:705
+msgid "Optional name for the 3D physics layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:708
+msgid "Optional name for the 3D physics layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:711
+msgid "Optional name for the 3D physics layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:714
+msgid "Optional name for the 3D physics layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:717
+msgid "Optional name for the 3D physics layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:720
+msgid "Optional name for the 3D physics layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:723
+msgid "Optional name for the 3D physics layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:726
+msgid "Optional name for the 3D physics layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:729
+msgid "Optional name for the 3D render layer 1."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:732
+msgid "Optional name for the 3D render layer 10."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:735
+msgid "Optional name for the 3D render layer 11."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:738
+msgid "Optional name for the 3D render layer 12."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:741
+msgid "Optional name for the 3D render layer 13."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:744
+msgid "Optional name for the 3D render layer 14"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:747
+msgid "Optional name for the 3D render layer 15."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:750
+msgid "Optional name for the 3D render layer 16."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:753
+msgid "Optional name for the 3D render layer 17."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:756
+msgid "Optional name for the 3D render layer 18."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:759
+msgid "Optional name for the 3D render layer 19."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:762
+msgid "Optional name for the 3D render layer 2."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:765
+msgid "Optional name for the 3D render layer 20."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:768
+msgid "Optional name for the 3D render layer 3."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:771
+msgid "Optional name for the 3D render layer 4."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:774
+msgid "Optional name for the 3D render layer 5."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:777
+msgid "Optional name for the 3D render layer 6."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:780
+msgid "Optional name for the 3D render layer 7."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:783
+msgid "Optional name for the 3D render layer 8."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:786
+msgid "Optional name for the 3D render layer 9."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:789
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:792
+msgid ""
+"If non-empty, this locale will be used when running the project from the "
+"editor."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:795
+msgid "If [code]true[/code], logs all output to files."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:798
+msgid ""
+"Path to logs within the project. Using an [code]user://[/code] path is "
+"recommended."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:801
+msgid "Specifies the maximum amount of log files allowed (used for rotation)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:804
+msgid ""
+"Godot uses a message queue to defer some function calls. If you run out of "
+"space on it (you will see an error), you can increase the size here."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:807
+msgid ""
+"This is used by servers when used in multi-threading mode (servers and "
+"visual). RIDs are preallocated to avoid stalling the server requesting them "
+"on threads. If servers get stalled too often when loading resources in a "
+"thread, increase this number."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:822
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:825
+msgid ""
+"Maximum number of errors allowed to be sent from the debugger. Over this "
+"value, content is dropped. This helps not to stall the debugger connection."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:828
+msgid ""
+"Maximum amount of messages in the debugger queue. Over this value, content "
+"is dropped. This helps to limit the debugger memory usage."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:831
+msgid ""
+"Maximum number of warnings allowed to be sent from the debugger. Over this "
+"value, content is dropped. This helps not to stall the debugger connection."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:834
+msgid ""
+"Default size of packet peer stream for deserializing Godot data. Over this "
+"size, data is dropped."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:837
+msgid "Timeout (in seconds) for connection attempts using TCP."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:840
+msgid "Maximum size (in kiB) for the [WebRTCDataChannel] input buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:843
+msgid "Maximum size (in kiB) for the [WebSocketClient] input buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:846
+msgid "Maximum number of concurrent input packets for [WebSocketClient]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:849
+msgid "Maximum size (in kiB) for the [WebSocketClient] output buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:852
+msgid "Maximum number of concurrent output packets for [WebSocketClient]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:855
+msgid "Maximum size (in kiB) for the [WebSocketServer] input buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:858
+msgid "Maximum number of concurrent input packets for [WebSocketServer]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:861
+msgid "Maximum size (in kiB) for the [WebSocketServer] output buffer."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:864
+msgid "Maximum number of concurrent output packets for [WebSocketServer]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:867
+msgid ""
+"Amount of read ahead used by remote filesystem. Higher values decrease the "
+"effects of latency at the cost of higher bandwidth usage."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:870
+msgid "Page size used by remote filesystem (in bytes)."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:873
+msgid ""
+"CA certificates bundle to use for SSL connections. If not defined, Godot's "
+"internal CA certificates are used."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:876
+msgid ""
+"When creating node names automatically, set the type of casing in this "
+"project. This is mostly an editor setting."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:879
+msgid ""
+"What to use to separate node name from number. This is mostly an editor "
+"setting."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:882
+msgid "Size of the hash table used for the broad-phase 2D hash grid algorithm."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:885
+msgid "Cell size used for the broad-phase 2D hash grid algorithm."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:888
+msgid "The default angular damp in 2D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:891
+msgid ""
+"The default gravity strength in 2D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity strength to 98.\n"
+"PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), "
+"PhysicsServer2D.AREA_PARAM_GRAVITY, 98)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:899
+msgid ""
+"The default gravity direction in 2D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity vector at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity direction to `Vector2(0, 1)`.\n"
+"PhysicsServer2D.area_set_param(get_viewport().find_world_2d().get_space(), "
+"PhysicsServer2D.AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:907
+msgid "The default linear damp in 2D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:910
+msgid ""
+"Threshold defining the surface size that constitutes a large object with "
+"regard to cells in the broad-phase 2D hash grid algorithm."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:913
+msgid ""
+"Sets which physics engine to use for 2D physics.\n"
+"\"DEFAULT\" and \"GodotPhysics\" are the same, as there is currently no "
+"alternative 2D physics server implemented."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:917
+msgid ""
+"Threshold angular velocity under which a 2D physics body will be considered "
+"inactive. See [constant PhysicsServer2D."
+"SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:920
+msgid ""
+"Threshold linear velocity under which a 2D physics body will be considered "
+"inactive. See [constant PhysicsServer2D."
+"SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:923
+msgid ""
+"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.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:927
+msgid ""
+"Time (in seconds) of inactivity before which a 2D physics body will put to "
+"sleep. See [constant PhysicsServer2D.SPACE_PARAM_BODY_TIME_TO_SLEEP]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:930
+msgid ""
+"Sets whether the 3D physics world will be created with support for "
+"[SoftBody3D] physics. Only applies to the Bullet physics engine."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:933
+msgid "The default angular damp in 3D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:936
+msgid ""
+"The default gravity strength in 3D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity strength to 9.8.\n"
+"PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), "
+"PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:944
+msgid ""
+"The default gravity direction in 3D.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the default gravity vector at runtime, use the following code sample:\n"
+"[codeblock]\n"
+"# Set the default gravity direction to `Vector3(0, -1, 0)`.\n"
+"PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), "
+"PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3(0, -1, 0))\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:952
+msgid "The default linear damp in 3D."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:955
+msgid ""
+"Sets which physics engine to use for 3D physics.\n"
+"\"DEFAULT\" is currently the [url=https://bulletphysics.org]Bullet[/url] "
+"physics engine. The \"GodotPhysics\" engine is still supported as an "
+"alternative."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:959
+msgid "Enables [member Viewport.physics_object_picking] on the root viewport."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:962
+msgid ""
+"The number of fixed iterations per second. This controls how often physics "
+"simulation and [method Node._physics_process] methods are run.\n"
+"[b]Note:[/b] This property is only read when the project starts. To change "
+"the physics FPS at runtime, set [member Engine.iterations_per_second] "
+"instead."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:966
+msgid ""
+"Fix to improve physics jitter, specially on monitors where refresh rate is "
+"different than the physics FPS.\n"
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:970
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:973
+msgid ""
+"[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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:976
+msgid ""
+"Max amount of elements renderable in a frame. If more than this are visible "
+"per frame, they will be dropped. Keep in mind elements refer to mesh "
+"surfaces and not meshes themselves."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:979
+msgid ""
+"Some NVIDIA GPU drivers have a bug which produces flickering issues for the "
+"[code]draw_rect[/code] method, especially as used in [TileMap]. Refer to "
+"[url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/"
+"url] for details.\n"
+"If [code]true[/code], this option enables a \"safe\" code path for such "
+"NVIDIA GPUs at the cost of performance. This option only impacts the GLES2 "
+"rendering backend, and only desktop platforms. It is not necessary when "
+"using the Vulkan backend."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:983
+msgid ""
+"If [code]true[/code], forces snapping of polygons to pixels in 2D rendering. "
+"May help in some pixel art styles."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:986
+msgid ""
+"Disables depth pre-pass for some GPU vendors (usually mobile), as their "
+"architecture already does this."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:989
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:992
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:995
+msgid ""
+"Lower-end override for [member rendering/quality/directional_shadow/size] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:998
+msgid ""
+"The video driver to use (\"GLES2\" or \"Vulkan\").\n"
+"[b]Note:[/b] The backend in use can be overridden at runtime via the [code]--"
+"rendering-driver[/code] command line argument.\n"
+"[b]FIXME:[/b] No longer valid after DisplayServer split:\n"
+"In such cases, this property is not updated, so use [code]OS."
+"get_current_video_driver[/code] to query it at run-time."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1012
+msgid ""
+"Sets the number of MSAA samples to use. 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.\n"
+"[b]Note:[/b] MSAA is not available on HTML5 export using the GLES2 backend."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1020
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1031
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1034
+msgid ""
+"Lower-end override for [member rendering/quality/intended_usage/"
+"framebuffer_allocation] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1037
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1040
+msgid ""
+"Size of cubemap faces for [ReflectionProbe]s. A higher number requires more "
+"VRAM and may make reflection probe updating slower."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1043
+msgid ""
+"Lower-end override for [member rendering/quality/reflection_atlas/"
+"reflection_size] on mobile devices, due to performance concerns or driver "
+"support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1046
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1049
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1052
+msgid ""
+"Lower-end override for [member rendering/quality/reflections/ggx_samples] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1055
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1058
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1061
+msgid ""
+"Lower-end override for [member rendering/quality/reflections/"
+"texture_array_reflections] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1066
+msgid ""
+"If [code]true[/code], uses faster but lower-quality Blinn model to generate "
+"blurred reflections instead of the GGX model."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1069
+msgid ""
+"Lower-end override for [member rendering/quality/shading/"
+"force_blinn_over_ggx] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1072
+msgid ""
+"If [code]true[/code], uses faster but lower-quality Lambert material "
+"lighting model instead of Burley."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1075
+msgid ""
+"Lower-end override for [member rendering/quality/shading/"
+"force_lambert_over_burley] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1078
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1081
+msgid ""
+"Lower-end override for [member rendering/quality/shading/"
+"force_vertex_shading] on mobile devices, due to performance concerns or "
+"driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1084 doc/classes/ProjectSettings.xml:1087
+#: doc/classes/ProjectSettings.xml:1090 doc/classes/ProjectSettings.xml:1093
+msgid ""
+"Subdivision quadrant size for shadow mapping. See shadow mapping "
+"documentation."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1096
+msgid ""
+"Size for shadow atlas (used for OmniLights and SpotLights). See "
+"documentation."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1099
+msgid ""
+"Lower-end override for [member rendering/quality/shadow_atlas/size] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1102
+msgid ""
+"Shadow filter mode. Higher-quality settings result in smoother shadows that "
+"flicker less when moving. \"Disabled\" is the fastest option, but also has "
+"the lowest quality. \"PCF5\" is smoother but is also slower. \"PCF13\" is "
+"the smoothest option, but is also the slowest."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1105
+msgid ""
+"Lower-end override for [member rendering/quality/shadows/filter_mode] on "
+"mobile devices, due to performance concerns or driver support."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1118
+msgid ""
+"Thread model for rendering. Rendering on a thread can vastly improve "
+"performance, but synchronizing to the main thread can cause a bit more "
+"jitter."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1121
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1124
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1127
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1130
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProjectSettings.xml:1133
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ProximityGroup3D.xml:4 doc/classes/ProximityGroup3D.xml:7
+msgid "General-purpose proximity detection node."
+msgstr ""
+
+#: doc/classes/QuadMesh.xml:4
+msgid "Class representing a square mesh."
+msgstr ""
+
+#: doc/classes/QuadMesh.xml:7
+msgid ""
+"Class representing a square [PrimitiveMesh]. This flat mesh does not have a "
+"thickness. By default, this mesh is aligned on the X and Y axes; this "
+"default rotation is more suited for use with billboarded materials. Unlike "
+"[PlaneMesh], this mesh doesn't provide subdivision options."
+msgstr ""
+
+#: doc/classes/QuadMesh.xml:15
+msgid "Size on the X and Y axes."
+msgstr ""
+
+#: doc/classes/Quat.xml:4
+msgid "Quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:7
+msgid ""
+"A unit quaternion used for representing 3D rotations.\n"
+"It is similar to [Basis], which implements matrix representation of "
+"rotations, and can be parametrized using both an axis-angle pair or Euler "
+"angles. But due to its compactness and the way it is stored in memory, "
+"certain operations (obtaining axis-angle and performing SLERP, in "
+"particular) are more efficient and robust against floating-point errors.\n"
+"Quaternions need to be (re)normalized."
+msgstr ""
+
+#: doc/classes/Quat.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms."
+"html#interpolating-with-quaternions"
+msgstr ""
+
+#: doc/classes/Quat.xml:21
+msgid "Returns the rotation matrix corresponding to the given quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:30
+msgid ""
+"Returns a quaternion that will perform a rotation specified by Euler angles "
+"(in the YXZ convention: first Z, then X, and Y last), given in the vector "
+"format as (X angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Quat.xml:41
+msgid ""
+"Returns a quaternion that will rotate around the given axis by the specified "
+"angle. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Quat.xml:56
+msgid "Returns a quaternion defined by these values."
+msgstr ""
+
+#: doc/classes/Quat.xml:71
+msgid ""
+"Performs a cubic spherical-linear interpolation with another quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:80
+msgid "Returns the dot product of two quaternions."
+msgstr ""
+
+#: doc/classes/Quat.xml:87
+msgid ""
+"Returns Euler angles (in the YXZ convention: 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)."
+msgstr ""
+
+#: doc/classes/Quat.xml:94
+msgid "Returns the inverse of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:103
+msgid ""
+"Returns [code]true[/code] if this quaterion and [code]quat[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Quat.xml:110
+msgid "Returns whether the quaternion is normalized or not."
+msgstr ""
+
+#: doc/classes/Quat.xml:117
+msgid "Returns the length of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:124
+msgid "Returns the length of the quaternion, squared."
+msgstr ""
+
+#: doc/classes/Quat.xml:131
+msgid "Returns a copy of the quaternion, normalized to unit length."
+msgstr ""
+
+#: doc/classes/Quat.xml:142
+msgid ""
+"Sets the quaternion to a rotation which rotates around axis by the specified "
+"angle, in radians. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Quat.xml:151
+msgid ""
+"Sets the quaternion to a rotation specified by Euler angles (in the YXZ "
+"convention: first Z, then X, and Y last), given in the vector format as (X "
+"angle, Y angle, Z angle)."
+msgstr ""
+
+#: doc/classes/Quat.xml:162
+msgid "Performs a spherical-linear interpolation with another quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:173
+msgid ""
+"Performs a spherical-linear interpolation with another quaterion without "
+"checking if the rotation path is not bigger than 90°."
+msgstr ""
+
+#: doc/classes/Quat.xml:182
+msgid "Transforms the vector [code]v[/code] by this quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:188
+msgid "W component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:191
+msgid "X component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:194
+msgid "Y component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:197
+msgid "Z component of the quaternion."
+msgstr ""
+
+#: doc/classes/Quat.xml:202
+msgid ""
+"The identity rotation. Equivalent to an identity matrix. If a vector is "
+"transformed by an identity quaternion, it will not change."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:4
+msgid "A class for generating pseudo-random numbers."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:7
+msgid ""
+"RandomNumberGenerator is a class for generating pseudo-random numbers. It "
+"currently uses [url=http://www.pcg-random.org/]PCG32[/url].\n"
+"[b]Note:[/b] The underlying algorithm is an implementation detail. As a "
+"result, it should not be depended upon for reproducible random streams "
+"across Godot versions.\n"
+"To generate a random float number (within a given range) based on a time-"
+"dependant seed:\n"
+"[codeblock]\n"
+"var rng = RandomNumberGenerator.new()\n"
+"func _ready():\n"
+" rng.randomize()\n"
+" var my_random_number = rng.randf_range(-10.0, 10.0)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:24
+msgid ""
+"Generates a pseudo-random float between [code]0.0[/code] and [code]1.0[/"
+"code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:35
+msgid ""
+"Generates a pseudo-random float between [code]from[/code] and [code]to[/"
+"code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:46
+msgid ""
+"Generates a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-"
+"distributed[/url] pseudo-random number, using Box-Muller transform with the "
+"specified [code]mean[/code] and a standard [code]deviation[/code]. This is "
+"also called Gaussian distribution."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:53
+msgid ""
+"Generates a pseudo-random 32-bit unsigned integer between [code]0[/code] and "
+"[code]4294967295[/code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:64
+msgid ""
+"Generates a pseudo-random 32-bit signed integer between [code]from[/code] "
+"and [code]to[/code] (inclusive)."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:71
+msgid "Setups a time-based seed to generator."
+msgstr ""
+
+#: doc/classes/RandomNumberGenerator.xml:77
+msgid ""
+"The seed used by the random number generator. A given seed will give a "
+"reproducible sequence of pseudo-random numbers.\n"
+"[b]Note:[/b] The RNG does not have an avalanche effect, and can output "
+"similar random streams given similar seeds. Consider using a hash function "
+"to improve your seed quality if they're sourced externally."
+msgstr ""
+
+#: doc/classes/Range.xml:4
+msgid "Abstract base class for range-based controls."
+msgstr ""
+
+#: doc/classes/Range.xml:7
+msgid ""
+"Range is a base class for [Control] nodes that change a floating-point "
+"[i]value[/i] between a [i]minimum[/i] and a [i]maximum[/i], using [i]step[/"
+"i] and [i]page[/i], for example a [ScrollBar]."
+msgstr ""
+
+#: doc/classes/Range.xml:18
+msgid ""
+"Binds two ranges together along with any ranges previously grouped with "
+"either of them. When any of range's member variables change, it will share "
+"the new value with all other ranges in its group."
+msgstr ""
+
+#: doc/classes/Range.xml:25
+msgid "Stops range from sharing its member variables with any other."
+msgstr ""
+
+#: doc/classes/Range.xml:31
+msgid ""
+"If [code]true[/code], [member value] may be greater than [member max_value]."
+msgstr ""
+
+#: doc/classes/Range.xml:34
+msgid ""
+"If [code]true[/code], [member value] may be less than [member min_value]."
+msgstr ""
+
+#: doc/classes/Range.xml:37
+msgid ""
+"If [code]true[/code], and [code]min_value[/code] is greater than 0, "
+"[code]value[/code] will be represented exponentially rather than linearly."
+msgstr ""
+
+#: doc/classes/Range.xml:40
+msgid ""
+"Maximum value. Range is clamped if [code]value[/code] is greater than "
+"[code]max_value[/code]."
+msgstr ""
+
+#: doc/classes/Range.xml:43
+msgid ""
+"Minimum value. Range is clamped if [code]value[/code] is less than "
+"[code]min_value[/code]."
+msgstr ""
+
+#: doc/classes/Range.xml:46
+msgid ""
+"Page size. Used mainly for [ScrollBar]. ScrollBar's length is its size "
+"multiplied by [code]page[/code] over the difference between [code]min_value[/"
+"code] and [code]max_value[/code]."
+msgstr ""
+
+#: doc/classes/Range.xml:49
+msgid "The value mapped between 0 and 1."
+msgstr ""
+
+#: doc/classes/Range.xml:52
+msgid ""
+"If [code]true[/code], [code]value[/code] will always be rounded to the "
+"nearest integer."
+msgstr ""
+
+#: doc/classes/Range.xml:55
+msgid ""
+"If greater than 0, [code]value[/code] will always be rounded to a multiple "
+"of [code]step[/code]. If [code]rounded[/code] is also [code]true[/code], "
+"[code]value[/code] will first be rounded to a multiple of [code]step[/code] "
+"then rounded to the nearest integer."
+msgstr ""
+
+#: doc/classes/Range.xml:58
+msgid "Range's current value."
+msgstr ""
+
+#: doc/classes/Range.xml:64
+msgid ""
+"Emitted when [member min_value], [member max_value], [member page], or "
+"[member step] change."
+msgstr ""
+
+#: doc/classes/Range.xml:71
+msgid "Emitted when [member value] changes."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:4 doc/classes/RayCast3D.xml:4
+msgid "Query the closest object intersecting a ray."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:7
+msgid ""
+"A RayCast represents a line from its origin to its destination position, "
+"[code]cast_to[/code]. It is used to query the 2D space in order to find the "
+"closest object along the path of the ray.\n"
+"RayCast2D can ignore some objects by adding them to the exception list via "
+"[code]add_exception[/code], by setting proper filtering with collision "
+"layers, or by filtering object types with type masks.\n"
+"RayCast2D can be configured to report collisions with [Area2D]s ([member "
+"collide_with_areas]) and/or [PhysicsBody2D]s ([member "
+"collide_with_bodies]).\n"
+"Only enabled raycasts will be able to query the space and report "
+"collisions.\n"
+"RayCast2D calculates intersection every physics frame (see [Node]), and the "
+"result is cached so it can be used later until the next frame. If multiple "
+"queries are required between physics frames (or during the same frame) use "
+"[method force_raycast_update] after adjusting the raycast."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:23 doc/classes/RayCast3D.xml:23
+msgid ""
+"Adds a collision exception so the ray does not report collisions with the "
+"specified node."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:32 doc/classes/RayCast3D.xml:32
+msgid ""
+"Adds a collision exception so the ray does not report collisions with the "
+"specified [RID]."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:39 doc/classes/RayCast3D.xml:39
+msgid "Removes all collision exceptions for this ray."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:46
+msgid ""
+"Updates the collision information for the ray. Use this method to update the "
+"collision information immediately instead of waiting for the next "
+"[code]_physics_process[/code] call, for example if the ray or its parent has "
+"changed state.\n"
+"[b]Note:[/b] [code]enabled == true[/code] is not required for this to work."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:54 doc/classes/RayCast3D.xml:55
+msgid ""
+"Returns the first object that the ray intersects, or [code]null[/code] if no "
+"object is intersecting the ray (i.e. [method is_colliding] returns "
+"[code]false[/code])."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:61 doc/classes/RayCast3D.xml:62
+msgid ""
+"Returns the shape ID of the first object that the ray intersects, or "
+"[code]0[/code] if no object is intersecting the ray (i.e. [method "
+"is_colliding] returns [code]false[/code])."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:77 doc/classes/RayCast3D.xml:79
+msgid ""
+"Returns the normal of the intersecting object's shape at the collision point."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:84
+msgid ""
+"Returns the collision point at which the ray intersects the closest object.\n"
+"[b]Note:[/b] this point is in the [b]global[/b] coordinate system."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:92 doc/classes/RayCast3D.xml:94
+msgid ""
+"Returns whether any object is intersecting with the ray's vector "
+"(considering the vector length)."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:101 doc/classes/RayCast3D.xml:103
+msgid ""
+"Removes a collision exception so the ray does report collisions with the "
+"specified node."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:110 doc/classes/RayCast3D.xml:112
+msgid ""
+"Removes a collision exception so the ray does report collisions with the "
+"specified [RID]."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:121
+msgid ""
+"Sets or clears individual bits on the collision mask. This makes selecting "
+"the areas scanned easier."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:127 doc/classes/RayCast3D.xml:130
+msgid ""
+"The ray's destination point, relative to the RayCast's [code]position[/code]."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:130
+msgid "If [code]true[/code], collision with [Area2D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:133
+msgid "If [code]true[/code], collision with [PhysicsBody2D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:136 doc/classes/RayCast3D.xml:139
+msgid ""
+"The ray's collision mask. Only objects in at least one collision layer "
+"enabled in the mask will be detected."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:139 doc/classes/RayCast3D.xml:142
+msgid "If [code]true[/code], collisions will be reported."
+msgstr ""
+
+#: doc/classes/RayCast2D.xml:142
+msgid ""
+"If [code]true[/code], the parent node will be excluded from collision "
+"detection."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:7
+msgid ""
+"A RayCast represents a line from its origin to its destination position, "
+"[code]cast_to[/code]. It is used to query the 3D space in order to find the "
+"closest object along the path of the ray.\n"
+"RayCast3D can ignore some objects by adding them to the exception list via "
+"[code]add_exception[/code] or by setting proper filtering with collision "
+"layers and masks.\n"
+"RayCast3D can be configured to report collisions with [Area3D]s ([member "
+"collide_with_areas]) and/or [PhysicsBody3D]s ([member "
+"collide_with_bodies]).\n"
+"Only enabled raycasts will be able to query the space and report "
+"collisions.\n"
+"RayCast3D calculates intersection every physics frame (see [Node]), and the "
+"result is cached so it can be used later until the next frame. If multiple "
+"queries are required between physics frames (or during the same frame), use "
+"[method force_raycast_update] after adjusting the raycast."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:46
+msgid ""
+"Updates the collision information for the ray.\n"
+"Use this method to update the collision information immediately instead of "
+"waiting for the next [code]_physics_process[/code] call, for example if the "
+"ray or its parent has changed state.\n"
+"[b]Note:[/b] [code]enabled == true[/code] is not required for this to work."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:71
+msgid ""
+"Returns [code]true[/code] if the bit index passed is turned on.\n"
+"[b]Note:[/b] Bit indices range from 0-19."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:86
+msgid ""
+"Returns the collision point at which the ray intersects the closest object.\n"
+"[b]Note:[/b] This point is in the [b]global[/b] coordinate system."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:123
+msgid ""
+"Sets the bit index passed to the [code]value[/code] passed.\n"
+"[b]Note:[/b] Bit indexes range from 0-19."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:133
+msgid "If [code]true[/code], collision with [Area3D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:136
+msgid "If [code]true[/code], collision with [PhysicsBody3D]s will be reported."
+msgstr ""
+
+#: doc/classes/RayCast3D.xml:145
+msgid ""
+"If [code]true[/code], collisions will be ignored for this RayCast3D's "
+"immediate parent."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:4
+msgid "Ray shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:7
+msgid ""
+"Ray shape for 2D collisions. A ray is not really a collision body; instead, "
+"it tries to separate itself from whatever is touching its far endpoint. It's "
+"often useful for characters."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:15 doc/classes/RayShape3D.xml:15
+msgid "The ray's length."
+msgstr ""
+
+#: doc/classes/RayShape2D.xml:18 doc/classes/RayShape3D.xml:18
+msgid "If [code]true[/code], allow the shape to return the correct normal."
+msgstr ""
+
+#: doc/classes/RayShape3D.xml:4
+msgid "Ray shape for 3D collisions."
+msgstr ""
+
+#: doc/classes/RayShape3D.xml:7
+msgid ""
+"Ray shape for 3D collisions, which can be set into a [PhysicsBody3D] or "
+"[Area3D]. A ray is not really a collision body; instead, it tries to "
+"separate itself from whatever is touching its far endpoint. It's often "
+"useful for characters."
+msgstr ""
+
+#: doc/classes/Rect2.xml:4
+msgid "2D axis-aligned bounding box using floating point coordinates."
+msgstr ""
+
+#: doc/classes/Rect2.xml:7
+msgid ""
+"[Rect2] consists of a position, a size, and several utility functions. It is "
+"typically used for fast overlap tests.\n"
+"It uses floating point coordinates."
+msgstr ""
+
+#: doc/classes/Rect2.xml:22
+msgid "Constructs a [Rect2] by position and size."
+msgstr ""
+
+#: doc/classes/Rect2.xml:37
+msgid "Constructs a [Rect2] by x, y, width, and height."
+msgstr ""
+
+#: doc/classes/Rect2.xml:46
+msgid "Constructs a [Rect2] from a [Rect2i]."
+msgstr ""
+
+#: doc/classes/Rect2.xml:53
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Rect2.xml:62
+msgid "Returns the intersection of this [Rect2] and b."
+msgstr ""
+
+#: doc/classes/Rect2.xml:71
+msgid ""
+"Returns [code]true[/code] if this [Rect2] completely encloses another one."
+msgstr ""
+
+#: doc/classes/Rect2.xml:80
+msgid "Returns this [Rect2] expanded to include a given point."
+msgstr ""
+
+#: doc/classes/Rect2.xml:87
+msgid "Returns the area of the [Rect2]."
+msgstr ""
+
+#: doc/classes/Rect2.xml:96
+msgid ""
+"Returns a copy of the [Rect2] grown a given amount of units towards all the "
+"sides."
+msgstr ""
+
+#: doc/classes/Rect2.xml:111
+msgid ""
+"Returns a copy of the [Rect2] grown a given amount of units towards each "
+"direction individually."
+msgstr ""
+
+#: doc/classes/Rect2.xml:122
+msgid ""
+"Returns a copy of the [Rect2] grown a given amount of units towards the "
+"[enum Margin] direction."
+msgstr ""
+
+#: doc/classes/Rect2.xml:129
+msgid "Returns [code]true[/code] if the [Rect2] is flat or empty."
+msgstr ""
+
+#: doc/classes/Rect2.xml:138
+msgid "Returns [code]true[/code] if the [Rect2] contains a point."
+msgstr ""
+
+#: doc/classes/Rect2.xml:149
+msgid ""
+"Returns [code]true[/code] if the [Rect2] overlaps with [code]b[/code] (i.e. "
+"they have at least one point in common).\n"
+"If [code]include_borders[/code] is [code]true[/code], they will also be "
+"considered overlapping if their borders touch, even without intersection."
+msgstr ""
+
+#: doc/classes/Rect2.xml:159
+msgid ""
+"Returns [code]true[/code] if this [Rect2] and [code]rect[/code] are "
+"approximately equal, by calling [code]is_equal_approx[/code] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Rect2.xml:168
+msgid "Returns a larger [Rect2] that contains this [Rect2] and [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Rect2.xml:174
+msgid "Ending corner."
+msgstr ""
+
+#: doc/classes/Rect2.xml:177
+msgid "Position (starting corner)."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:4
+msgid "2D axis-aligned bounding box using integer coordinates."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:7
+msgid ""
+"[Rect2i] consists of a position, a size, and several utility functions. It "
+"is typically used for fast overlap tests.\n"
+"It uses integer coordinates."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:22
+msgid "Constructs a [Rect2i] by position and size."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:37
+msgid "Constructs a [Rect2i] by x, y, width, and height."
+msgstr ""
+
+#: doc/classes/Rect2i.xml:46
+msgid ""
+"Constructs a new [Rect2i] from [Rect2]. The floating point coordinates will "
+"be truncated."
+msgstr ""
+
+#: doc/classes/RectangleShape2D.xml:4
+msgid "Rectangle shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/RectangleShape2D.xml:7
+msgid ""
+"Rectangle shape for 2D collisions. This shape is useful for modeling box-"
+"like 2D objects."
+msgstr ""
+
+#: doc/classes/RectangleShape2D.xml:15
+msgid ""
+"The rectangle's half extents. The width and height of this shape is twice "
+"the half extents."
+msgstr ""
+
+#: doc/classes/Reference.xml:4
+msgid "Base class for reference-counted objects."
+msgstr ""
+
+#: doc/classes/Reference.xml:7
+msgid ""
+"Base class for any object that keeps a reference count. [Resource] and many "
+"other helper objects inherit this class.\n"
+"References keep an internal reference counter so that they are automatically "
+"released when no longer in use, and only then. References therefore do not "
+"need to be freed manually with [method Object.free].\n"
+"In the vast majority of use cases, instantiating and using [Reference]-"
+"derived types is all you need to do. The methods provided in this class are "
+"only for advanced users, and can cause issues if misused."
+msgstr ""
+
+#: doc/classes/Reference.xml:18
+msgid ""
+"Initializes the internal reference counter. Use this only if you really know "
+"what you are doing.\n"
+"Returns whether the initialization was successful."
+msgstr ""
+
+#: doc/classes/Reference.xml:26
+msgid ""
+"Increments the internal reference counter. Use this only if you really know "
+"what you are doing.\n"
+"Returns [code]true[/code] if the increment was successful, [code]false[/"
+"code] otherwise."
+msgstr ""
+
+#: doc/classes/Reference.xml:34
+msgid ""
+"Decrements the internal reference counter. Use this only if you really know "
+"what you are doing.\n"
+"Returns [code]true[/code] if the decrement was successful, [code]false[/"
+"code] otherwise."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:4
+msgid "Reference frame for GUI."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:7
+msgid ""
+"A rectangle box that displays only a [member border_color] border color "
+"around its rectangle. [ReferenceRect] has no fill [Color]."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:15
+msgid "Sets the border [Color] of the [ReferenceRect]."
+msgstr ""
+
+#: doc/classes/ReferenceRect.xml:18
+msgid ""
+"If set to [code]true[/code], the [ReferenceRect] will only be visible while "
+"in editor. Otherwise, [ReferenceRect] will be visible in game."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:4
+msgid "Captures its surroundings to create reflections."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:7
+msgid ""
+"Captures its surroundings as a cubemap, and stores versions of it with "
+"increasing levels of blur to simulate different material roughnesses.\n"
+"The [ReflectionProbe] is used to create high-quality reflections at the cost "
+"of performance. It can be combined with [GIProbe]s and Screen Space "
+"Reflections to achieve high quality reflections. [ReflectionProbe]s render "
+"all objects within their [member cull_mask], so updating them can be quite "
+"expensive. It is best to update them once with the important static objects "
+"and then leave them."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html"
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:17
+msgid ""
+"If [code]true[/code], enables box projection. This makes reflections look "
+"more correct in rectangle-shaped rooms by offsetting the reflection center "
+"depending on the camera's location."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:20
+msgid ""
+"Sets the cull mask which determines what objects are drawn by this probe. "
+"Every [VisualInstance3D] with a layer included in this cull mask will be "
+"rendered by the probe. It is best to only include large objects which are "
+"likely to take up a lot of space in the reflection in order to save on "
+"rendering cost."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:23
+msgid ""
+"If [code]true[/code], computes shadows in the reflection probe. This makes "
+"the reflection probe slower to render; you may want to disable this if using "
+"the [constant UPDATE_ALWAYS] [member update_mode]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:26
+msgid ""
+"The size of the reflection probe. The larger the extents the more space "
+"covered by the probe which will lower the perceived resolution. It is best "
+"to keep the extents only as large as you need them."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:29
+msgid ""
+"Defines the reflection intensity. Intensity modulates the strength of the "
+"reflection."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:32
+msgid ""
+"Sets the ambient light color to be used when this probe is set to [member "
+"interior_enable]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:35
+msgid ""
+"Sets the contribution value for how much the reflection affects the ambient "
+"light for this reflection probe when set to [member interior_enable]. Useful "
+"so that ambient light matches the color of the room."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:38
+msgid ""
+"Sets the energy multiplier for this reflection probe's ambient light "
+"contribution when set to [member interior_enable]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:41
+msgid ""
+"If [code]true[/code], reflections will ignore sky contribution. Ambient "
+"lighting is then controlled by the [code]interior_ambient_*[/code] "
+"properties."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:44
+msgid ""
+"Sets the max distance away from the probe an object can be before it is "
+"culled."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:47
+msgid ""
+"Sets the origin offset to be used when this reflection probe is in box "
+"project mode."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:50
+msgid ""
+"Sets how frequently the probe is updated. Can be [constant UPDATE_ONCE] or "
+"[constant UPDATE_ALWAYS]."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:55
+msgid ""
+"Update the probe once on the next frame. The corresponding radiance map will "
+"be generated over the following six frames. This is slower to update than "
+"[constant UPDATE_ALWAYS] but can result in higher quality reflections."
+msgstr ""
+
+#: doc/classes/ReflectionProbe.xml:58
+msgid ""
+"Update the probe every frame. This is needed when you want to capture "
+"dynamic objects. However, it results in an increased render time. Use "
+"[constant UPDATE_ONCE] whenever possible."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:4
+msgid "Class for searching text for patterns using regular expressions."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:7
+msgid ""
+"A regular expression (or regex) is a compact language that can be used to "
+"recognise strings that follow a specific pattern, such as URLs, email "
+"addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/"
+"code] would find any string that is [code]ab[/code] followed by any number "
+"from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can "
+"easily find various tutorials and detailed explanations on the Internet.\n"
+"To begin, the RegEx object needs to be compiled with the search pattern "
+"using [method compile] before it can be used.\n"
+"[codeblock]\n"
+"var regex = RegEx.new()\n"
+"regex.compile(\"\\\\w-(\\\\d+)\")\n"
+"[/codeblock]\n"
+"The search pattern must be escaped first for GDScript before it is escaped "
+"for the expression. For example, [code]compile(\"\\\\d+\")[/code] would be "
+"read by RegEx as [code]\\d+[/code]. Similarly, [code]compile(\"\\\"(?:\\\\\\"
+"\\.|[^\\\"])*\\\"\")[/code] would be read as [code]\"(?:\\\\.|[^\"])*\"[/"
+"code].\n"
+"Using [method search] you can find the pattern within the given text. If a "
+"pattern is found, [RegExMatch] is returned and you can retrieve details of "
+"the results using functions such as [method RegExMatch.get_string] and "
+"[method RegExMatch.get_start].\n"
+"[codeblock]\n"
+"var regex = RegEx.new()\n"
+"regex.compile(\"\\\\w-(\\\\d+)\")\n"
+"var result = regex.search(\"abc n-0123\")\n"
+"if result:\n"
+" print(result.get_string()) # Would print n-0123\n"
+"[/codeblock]\n"
+"The results of capturing groups [code]()[/code] can be retrieved by passing "
+"the group number to the various functions in [RegExMatch]. Group 0 is the "
+"default and will always refer to the entire pattern. In the above example, "
+"calling [code]result.get_string(1)[/code] would give you [code]0123[/code].\n"
+"This version of RegEx also supports named capturing groups, and the names "
+"can be used to retrieve the results. If two or more groups have the same "
+"name, the name would only refer to the first one with a match.\n"
+"[codeblock]\n"
+"var regex = RegEx.new()\n"
+"regex.compile(\"d(?<digit>[0-9]+)|x(?<digit>[0-9a-f]+)\")\n"
+"var result = regex.search(\"the number is x2f\")\n"
+"if result:\n"
+" print(result.get_string(\"digit\")) # Would print 2f\n"
+"[/codeblock]\n"
+"If you need to process multiple results, [method search_all] generates a "
+"list of all non-overlapping results. This can be combined with a [code]for[/"
+"code] loop for convenience.\n"
+"[codeblock]\n"
+"for result in regex.search_all(\"d01, d03, d0c, x3f and x42\"):\n"
+" print(result.get_string(\"digit\"))\n"
+"# Would print 01 03 3f 42\n"
+"# Note that d0c would not match\n"
+"[/codeblock]\n"
+"[b]Note:[/b] Godot's regex implementation is based on the [url=https://www."
+"pcre.org/]PCRE2[/url] library. You can view the full pattern reference "
+"[url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url].\n"
+"[b]Tip:[/b] You can use [url=https://regexr.com/]Regexr[/url] to test "
+"regular expressions online."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:48
+msgid ""
+"This method resets the state of the object, as if it was freshly created. "
+"Namely, it unassigns the regular expression of this object."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:57
+msgid ""
+"Compiles and assign the search pattern to use. Returns [constant OK] if the "
+"compilation is successful. If an error is encountered, details are printed "
+"to standard output and an error is returned."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:64
+msgid "Returns the number of capturing groups in compiled pattern."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:71
+msgid ""
+"Returns an array of names of named capturing groups in the compiled pattern. "
+"They are ordered by appearance."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:78
+msgid "Returns the original search pattern that was compiled."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:85
+msgid "Returns whether this object has a valid search pattern assigned."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:98
+msgid ""
+"Searches the text for the compiled pattern. Returns a [RegExMatch] container "
+"of the first matching result if found, otherwise [code]null[/code]. The "
+"region to search within can be specified without modifying where the start "
+"and end anchor would be."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:111
+msgid ""
+"Searches the text for the compiled pattern. Returns an array of [RegExMatch] "
+"containers for each non-overlapping result. If no results were found, an "
+"empty array is returned instead. The region to search within can be "
+"specified without modifying where the start and end anchor would be."
+msgstr ""
+
+#: modules/regex/doc_classes/RegEx.xml:128
+msgid ""
+"Searches the text for the compiled pattern and replaces it with the "
+"specified string. Escapes and backreferences such as [code]$1[/code] and "
+"[code]$name[/code] are expanded and resolved. By default, only the first "
+"instance is replaced, but it can be changed for all instances (global "
+"replacement). The region to search within can be specified without modifying "
+"where the start and end anchor would be."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:4
+msgid "Contains the results of a [RegEx] search."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:7
+msgid ""
+"Contains the results of a single [RegEx] match returned by [method RegEx."
+"search] and [method RegEx.search_all]. It can be used to find the position "
+"and range of the match and its capturing groups, and it can extract its "
+"substring for you."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:18
+msgid ""
+"Returns the end position of the match within the source string. The end "
+"position of capturing groups can be retrieved by providing its group number "
+"as an integer or its string name (if it's a named group). The default value "
+"of 0 refers to the whole pattern.\n"
+"Returns -1 if the group did not match or doesn't exist."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:26
+msgid "Returns the number of capturing groups."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:35
+msgid ""
+"Returns the starting position of the match within the source string. The "
+"starting position of capturing groups can be retrieved by providing its "
+"group number as an integer or its string name (if it's a named group). The "
+"default value of 0 refers to the whole pattern.\n"
+"Returns -1 if the group did not match or doesn't exist."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:45
+msgid ""
+"Returns the substring of the match from the source string. Capturing groups "
+"can be retrieved by providing its group number as an integer or its string "
+"name (if it's a named group). The default value of 0 refers to the whole "
+"pattern.\n"
+"Returns an empty string if the group did not match or doesn't exist."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:52
+msgid ""
+"A dictionary of named groups and its corresponding group number. Only groups "
+"with that were matched are included. If multiple groups have the same name, "
+"that name would refer to the first matching one."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:55
+msgid "An [Array] of the match and its capturing groups."
+msgstr ""
+
+#: modules/regex/doc_classes/RegExMatch.xml:58
+msgid ""
+"The source string used with the search pattern to find this matching result."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:4
+msgid ""
+"RemoteTransform2D pushes its own [Transform2D] to another [CanvasItem] "
+"derived Node in the scene."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:7
+msgid ""
+"RemoteTransform2D pushes its own [Transform2D] to another [CanvasItem] "
+"derived Node (called the remote node) in the scene.\n"
+"It can be set to update another Node's position, rotation and/or scale. It "
+"can use either global or local coordinates."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:17
+msgid ""
+"[RemoteTransform2D] caches the remote node. It may not notice if the remote "
+"node disappears; [method force_update_cache] forces it to update the cache "
+"again."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:23
+msgid ""
+"The [NodePath] to the remote node, relative to the RemoteTransform2D's "
+"position in the scene."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:26 doc/classes/RemoteTransform3D.xml:26
+msgid "If [code]true[/code], the remote node's position is updated."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:29 doc/classes/RemoteTransform3D.xml:29
+msgid "If [code]true[/code], the remote node's rotation is updated."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:32 doc/classes/RemoteTransform3D.xml:32
+msgid "If [code]true[/code], the remote node's scale is updated."
+msgstr ""
+
+#: doc/classes/RemoteTransform2D.xml:35 doc/classes/RemoteTransform3D.xml:35
+msgid ""
+"If [code]true[/code], global coordinates are used. If [code]false[/code], "
+"local coordinates are used."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:4
+msgid ""
+"RemoteTransform3D pushes its own [Transform] to another [Node3D] derived "
+"Node in the scene."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:7
+msgid ""
+"RemoteTransform3D pushes its own [Transform] to another [Node3D] derived "
+"Node (called the remote node) in the scene.\n"
+"It can be set to update another Node's position, rotation and/or scale. It "
+"can use either global or local coordinates."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:17
+msgid ""
+"[RemoteTransform3D] caches the remote node. It may not notice if the remote "
+"node disappears; [method force_update_cache] forces it to update the cache "
+"again."
+msgstr ""
+
+#: doc/classes/RemoteTransform3D.xml:23
+msgid ""
+"The [NodePath] to the remote node, relative to the RemoteTransform3D's "
+"position in the scene."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:4
+msgid "Server for anything visible."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:7
+msgid ""
+"Server for anything visible. The visual server is the API backend for "
+"everything visible. The whole scene system mounts on it to display.\n"
+"The visual server is completely opaque, the internals are entirely "
+"implementation specific and cannot be accessed.\n"
+"The visual server can be used to bypass the scene system entirely.\n"
+"Resources are created using the [code]*_create[/code] functions.\n"
+"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].\n"
+"In 3D, all visual objects must be associated with a scenario. The scenario "
+"is a visual representation of the world. If accessing the visual server from "
+"a running game, the scenario can be accessed from the scene tree from any "
+"[Node3D] node with [method Node3D.get_world]. Otherwise, a scenario can be "
+"created with [method scenario_create].\n"
+"Similarly in 2D, a canvas is needed to draw all canvas items.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:18
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers."
+"html"
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:33
+msgid "Sets images to be rendered in the window margin."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:48
+msgid ""
+"Sets margin size, where black bars (or images, if [method "
+"black_bars_set_images] was used) are rendered."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:55
+msgid ""
+"Creates a camera and adds it to the RenderingServer. It can be accessed with "
+"the RID that is returned. This RID will be used in all [code]camera_*[/code] "
+"RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:67
+msgid ""
+"Sets the cull mask associated with this camera. The cull mask describes "
+"which 3D layers are rendered by this camera. Equivalent to [member Camera3D."
+"cull_mask]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:78
+msgid ""
+"Sets the environment used by this camera. Equivalent to [member Camera3D."
+"environment]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:95
+msgid ""
+"Sets camera to use frustum projection. This mode allows adjusting the "
+"[code]offset[/code] argument to create \"tilted frustum\" effects."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:110
+msgid ""
+"Sets camera to use orthogonal projection, also known as orthographic "
+"projection. Objects remain the same size on the screen no matter how far "
+"away they are."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:125
+msgid ""
+"Sets camera to use perspective projection. Objects on the screen becomes "
+"smaller when they are far away."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:136
+msgid "Sets [Transform] of camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:147
+msgid ""
+"If [code]true[/code], preserves the horizontal aspect ratio which is "
+"equivalent to [constant Camera3D.KEEP_WIDTH]. If [code]false[/code], "
+"preserves the vertical aspect ratio which is equivalent to [constant "
+"Camera3D.KEEP_HEIGHT]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:154
+msgid ""
+"Creates a canvas and returns the assigned [RID]. It can be accessed with the "
+"RID that is returned. This RID will be used in all [code]canvas_*[/code] "
+"RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:164
+msgid "Clears the [CanvasItem] and removes all commands in it."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:177
+msgid "Sets the [CanvasItem] to copy a rect to the backbuffer."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:188
+msgid "Sets the index for the [CanvasItem]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:199
+msgid "Sets a new material to the [CanvasItem]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:210
+msgid "Sets if the [CanvasItem] uses its parent's material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:221
+msgid ""
+"If this is enabled, the Z index of the parent will be added to the "
+"children's Z index."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:232
+msgid ""
+"Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are "
+"drawn first)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:243
+msgid ""
+"Attaches the canvas light to the canvas. Removes it from its previous canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:250
+msgid ""
+"Creates a canvas light and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]canvas_light_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:262
+msgid ""
+"Attaches a light occluder to the canvas. Removes it from its previous canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:269
+msgid ""
+"Creates a light occluder and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]canvas_light_ocluder_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:281
+msgid "Enables or disables light occluder."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:292 doc/classes/RenderingServer.xml:369
+msgid ""
+"The light mask. See [LightOccluder2D] for more information on light masks."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:303
+msgid "Sets a light occluder's polygon."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:314
+msgid "Sets a light occluder's [Transform2D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:325
+msgid "Sets the color for a light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:336
+msgid "Enables or disables a canvas light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:347
+msgid "Sets a canvas light's energy."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:358
+msgid "Sets a canvas light's height."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:380
+msgid ""
+"The binary mask used to determine which layers this canvas light's shadows "
+"affects. See [LightOccluder2D] for more information on light masks."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:393
+msgid "The layer range that gets rendered with this light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:404
+msgid "The mode of the light, see [enum CanvasLightMode] constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:415
+msgid ""
+"Sets the texture's scale factor of the light. Equivalent to [member Light2D."
+"texture_scale]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:426
+msgid ""
+"Sets the width of the shadow buffer, size gets scaled to the next power of "
+"two for this."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:437
+msgid "Sets the color of the canvas light's shadow."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:448
+msgid "Enables or disables the canvas light's shadow."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:459
+msgid ""
+"Sets the canvas light's shadow's filter, see [enum CanvasLightShadowFilter] "
+"constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:470
+msgid "Smoothens the shadow. The lower, the smoother."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:481
+msgid ""
+"Sets texture to be used by light. Equivalent to [member Light2D.texture]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:492
+msgid ""
+"Sets the offset of the light's texture. Equivalent to [member Light2D."
+"offset]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:503
+msgid "Sets the canvas light's [Transform2D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:516
+msgid ""
+"Sets the Z range of objects that will be affected by this light. Equivalent "
+"to [member Light2D.range_z_min] and [member Light2D.range_z_max]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:523
+msgid ""
+"Creates a new light occluder polygon and adds it to the RenderingServer. It "
+"can be accessed with the RID that is returned. This RID will be used in all "
+"[code]canvas_occluder_polygon_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:535
+msgid ""
+"Sets an occluder polygons cull mode. See [enum "
+"CanvasOccluderPolygonCullMode] constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:548
+msgid "Sets the shape of the occluder polygon."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:559
+msgid "Sets the shape of the occluder polygon as lines."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:572
+msgid ""
+"A copy of the canvas item will be drawn with a local offset of the mirroring "
+"[Vector2]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:583
+msgid "Modulates all colors in the given canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:590
+msgid ""
+"Creates a directional light and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID can be used in most "
+"[code]light_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this directional light to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:599
+msgid ""
+"Creates an environment and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]environment_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:619
+msgid ""
+"Sets the values to be used with the \"Adjustment\" post-process effect. See "
+"[Environment] for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:650
+msgid ""
+"Sets the [i]BGMode[/i] of the environment. Equivalent to [member Environment."
+"background_mode]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:661
+msgid ""
+"Color displayed for clear areas of the scene (if using Custom color or Color"
+"+Sky background modes)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:672
+msgid "Sets the intensity of the background color."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:683
+msgid "Sets the maximum layer to use if using Canvas background mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:700
+msgid ""
+"Sets the variables to be used with the scene fog. See [Environment] for more "
+"details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:721
+msgid ""
+"Sets the variables to be used with the fog depth effect. See [Environment] "
+"for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:738
+msgid ""
+"Sets the variables to be used with the fog height effect. See [Environment] "
+"for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:777
+msgid ""
+"Sets the [Sky] to be used as the environment's background when using "
+"[i]BGMode[/i] sky. Equivalent to [member Environment.sky]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:788
+msgid ""
+"Sets a custom field of view for the background [Sky]. Equivalent to [member "
+"Environment.sky_custom_fov]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:799
+msgid ""
+"Sets the rotation of the background [Sky] expressed as a [Basis]. Equivalent "
+"to [member Environment.sky_rotation], where the rotation vector is used to "
+"construct the [Basis]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:842
+msgid ""
+"Sets the variables to be used with the \"screen space reflections\" post-"
+"process effect. See [Environment] for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:867
+msgid ""
+"Sets the variables to be used with the \"tonemap\" post-process effect. See "
+"[Environment] for more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:874
+msgid "Removes buffers and clears testcubes."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:885
+msgid ""
+"Forces a frame to be drawn when the function is called. Drawing a frame "
+"updates all [Viewport]s that are set to update. Use with extreme caution."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:892
+msgid "Synchronizes threads."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:901
+msgid "Tries to free an object in the RenderingServer."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:910
+msgid "Returns a certain information, see [enum RenderInfo] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:917
+msgid "Returns the id of the test cube. Creates one if none exists."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:924
+msgid "Returns the id of the test texture. Creates one if none exists."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:931
+msgid ""
+"Returns the name of the video adapter (e.g. \"GeForce GTX 1080/PCIe/"
+"SSE2\").\n"
+"[b]Note:[/b] When running a headless or server binary, this function returns "
+"an empty string."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:939
+msgid ""
+"Returns the vendor of the video adapter (e.g. \"NVIDIA Corporation\").\n"
+"[b]Note:[/b] When running a headless or server binary, this function returns "
+"an empty string."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:947
+msgid "Returns the id of a white texture. Creates one if none exists."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:954
+msgid ""
+"Returns [code]true[/code] if changes have been made to the RenderingServer's "
+"data. [method force_draw] is usually called if this happens."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:963
+msgid "Not yet implemented. Always returns [code]false[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:972
+msgid ""
+"Returns [code]true[/code] if the OS supports a certain feature. Features "
+"might be [code]s3tc[/code], [code]etc[/code], [code]etc2[/code] and "
+"[code]pvrtc[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:985
+msgid ""
+"Sets up [ImmediateGeometry3D] internals to prepare for drawing. Equivalent "
+"to [method ImmediateGeometry3D.begin]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:994
+msgid ""
+"Clears everything that was set up between [method immediate_begin] and "
+"[method immediate_end]. Equivalent to [method ImmediateGeometry3D.clear]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1005
+msgid ""
+"Sets the color to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1012
+msgid ""
+"Creates an immediate geometry and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]immediate_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this immediate geometry to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1023
+msgid ""
+"Ends drawing the [ImmediateGeometry3D] and displays it. Equivalent to "
+"[method ImmediateGeometry3D.end]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1032
+msgid "Returns the material assigned to the [ImmediateGeometry3D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1043
+msgid ""
+"Sets the normal to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_normal]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1054
+msgid "Sets the material to be used to draw the [ImmediateGeometry3D]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1065
+msgid ""
+"Sets the tangent to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_tangent]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1076
+msgid ""
+"Sets the UV to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_uv]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1087
+msgid ""
+"Sets the UV2 to be used with next vertex. Equivalent to [method "
+"ImmediateGeometry3D.set_uv2]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1098
+msgid ""
+"Adds the next vertex using the information provided in advance. Equivalent "
+"to [method ImmediateGeometry3D.add_vertex]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1109
+msgid ""
+"Adds the next vertex using the information provided in advance. This is a "
+"helper class that calls [method immediate_vertex] under the hood. Equivalent "
+"to [method ImmediateGeometry3D.add_vertex]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1116
+msgid ""
+"Initializes the visual server. This function is called internally by "
+"platform-dependent code during engine initialization. If called from a "
+"running game, it will not do anything."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1127
+msgid ""
+"Attaches a unique Object ID to instance. Object ID must be attached to "
+"instance for proper culling with [method instances_cull_aabb], [method "
+"instances_cull_convex], and [method instances_cull_ray]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1138
+msgid ""
+"Attaches a skeleton to an instance. Removes the previous skeleton from the "
+"instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1145
+msgid ""
+"Creates a visual instance and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]instance_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"An instance is a way of placing a 3D object in the scenario. Objects like "
+"particles, meshes, and reflection probes need to be associated with an "
+"instance to be visible in the scenario using [method instance_set_base]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1158
+msgid ""
+"Creates a visual instance, adds it to the RenderingServer, and sets both "
+"base and scenario. It can be accessed with the RID that is returned. This "
+"RID will be used in all [code]instance_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1170 doc/classes/RenderingServer.xml:1198
+#: doc/classes/RenderingServer.xml:1488
+msgid "Not implemented in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1181
+msgid ""
+"Sets the shadow casting setting to one of [enum ShadowCastingSetting]. "
+"Equivalent to [member GeometryInstance3D.cast_shadow]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1211
+msgid ""
+"Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for "
+"more details."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1222
+msgid ""
+"Sets a material that will override the material for all surfaces on the mesh "
+"associated with this instance. Equivalent to [member GeometryInstance3D."
+"material_override]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1233
+msgid ""
+"Sets the base of the instance. A base can be any of the 3D objects that are "
+"created in the RenderingServer that can be displayed. For example, any of "
+"the light types, mesh, multimesh, immediate geometry, particle system, "
+"reflection probe, lightmap capture, and the GI probe are all types that can "
+"be set as the base of an instance in order to be displayed in the scenario."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1246
+msgid "Sets the weight for a given blend shape associated with this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1257
+msgid ""
+"Sets a custom AABB to use when culling objects from the view frustum. "
+"Equivalent to [method GeometryInstance3D.set_custom_aabb]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1268
+msgid "Function not implemented in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1279
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1290
+msgid ""
+"Sets the render layers that this instance will be drawn to. Equivalent to "
+"[member VisualInstance3D.layers]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1301
+msgid ""
+"Sets the scenario that the instance is in. The scenario is the 3D world that "
+"the objects will be displayed in."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1314
+msgid ""
+"Sets the material of a specific surface. Equivalent to [method "
+"MeshInstance3D.set_surface_material]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1325
+msgid ""
+"Sets the world space transform of the instance. Equivalent to [member Node3D."
+"transform]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1338
+msgid "Sets the lightmap to use with this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1349
+msgid ""
+"Sets whether an instance is drawn or not. Equivalent to [member Node3D."
+"visible]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1360
+msgid ""
+"Returns an array of object IDs intersecting with the provided AABB. Only "
+"visual 3D nodes are considered, such as [MeshInstance3D] or "
+"[DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the "
+"actual nodes. A scenario RID must be provided, which is available in the "
+"[World3D] you want to query. This forces an update for all resources queued "
+"to update.\n"
+"[b]Warning:[/b] This function is primarily intended for editor usage. For in-"
+"game use cases, prefer physics collision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1372
+msgid ""
+"Returns an array of object IDs intersecting with the provided convex shape. "
+"Only visual 3D nodes are considered, such as [MeshInstance3D] or "
+"[DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the "
+"actual nodes. A scenario RID must be provided, which is available in the "
+"[World3D] you want to query. This forces an update for all resources queued "
+"to update.\n"
+"[b]Warning:[/b] This function is primarily intended for editor usage. For in-"
+"game use cases, prefer physics collision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1386
+msgid ""
+"Returns an array of object IDs intersecting with the provided 3D ray. Only "
+"visual 3D nodes are considered, such as [MeshInstance3D] or "
+"[DirectionalLight3D]. Use [method @GDScript.instance_from_id] to obtain the "
+"actual nodes. A scenario RID must be provided, which is available in the "
+"[World3D] you want to query. This forces an update for all resources queued "
+"to update.\n"
+"[b]Warning:[/b] This function is primarily intended for editor usage. For in-"
+"game use cases, prefer physics collision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1398
+msgid ""
+"If [code]true[/code], this directional light will blend between shadow map "
+"splits resulting in a smoother transition between them. Equivalent to "
+"[member DirectionalLight3D.directional_shadow_blend_splits]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1409
+msgid ""
+"Sets the shadow depth range mode for this directional light. Equivalent to "
+"[member DirectionalLight3D.directional_shadow_depth_range]. See [enum "
+"LightDirectionalShadowDepthRangeMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1420
+msgid ""
+"Sets the shadow mode for this directional light. Equivalent to [member "
+"DirectionalLight3D.directional_shadow_mode]. See [enum "
+"LightDirectionalShadowMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1431
+msgid ""
+"Sets whether to use a dual paraboloid or a cubemap for the shadow map. Dual "
+"paraboloid is faster but may suffer from artifacts. Equivalent to [member "
+"OmniLight3D.omni_shadow_mode]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1442
+msgid ""
+"Sets the color of the light. Equivalent to [member Light3D.light_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1453
+msgid ""
+"Sets the cull mask for this Light3D. Lights only affect objects in the "
+"selected layers. Equivalent to [member Light3D.light_cull_mask]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1464
+msgid ""
+"If [code]true[/code], light will subtract light instead of adding light. "
+"Equivalent to [member Light3D.light_negative]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1477
+msgid ""
+"Sets the specified light parameter. See [enum LightParam] for options. "
+"Equivalent to [method Light3D.set_param]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1499
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1510
+msgid ""
+"If [code]true[/code], light will cast shadows. Equivalent to [member Light3D."
+"shadow_enabled]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1521
+msgid ""
+"Sets the color of the shadow cast by the light. Equivalent to [member "
+"Light3D.shadow_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1532
+msgid "Sets whether GI probes capture light information from this light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1539
+msgid ""
+"Creates a lightmap capture and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]lightmap_capture_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this lightmap capture to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1550
+msgid "Returns the size of the lightmap capture area."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1559
+msgid "Returns the energy multiplier used by the lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1568
+msgid "Returns the octree used by the lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1577
+msgid ""
+"Returns the cell subdivision amount used by this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1586
+msgid "Returns the cell transform for this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1597
+msgid "Sets the size of the area covered by the lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1608
+msgid "Sets the energy multiplier for this lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1619
+msgid "Sets the octree to be used by this lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1630
+msgid "Sets the subdivision level of this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1641
+msgid "Sets the octree cell transform for this lightmap capture's octree."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1654
+msgid ""
+"Returns a mesh of a sphere with the given amount of horizontal and vertical "
+"subdivisions."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1661
+msgid ""
+"Creates an empty material and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]material_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1673
+msgid "Returns the value of a certain material's parameter."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1684
+msgid "Sets an object's next material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1697
+msgid "Sets a material's parameter."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1708
+msgid "Sets a material's render priority."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1719
+msgid "Sets a shader material's shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1748
+msgid "Removes all surfaces from a mesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1755
+msgid ""
+"Creates a new mesh and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all [code]mesh_*[/"
+"code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this mesh to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1766
+msgid "Returns a mesh's blend shape count."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1775
+msgid "Returns a mesh's blend shape mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1784
+msgid "Returns a mesh's custom aabb."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1793
+msgid "Returns a mesh's number of surfaces."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1804
+msgid "Sets a mesh's blend shape mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1815
+msgid "Sets a mesh's custom aabb."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1826
+msgid "Returns a mesh's surface's buffer arrays."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1837
+msgid "Returns a mesh's surface's arrays for blend shapes."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1852 doc/classes/RenderingServer.xml:1865
+msgid "Function is unused in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1876
+msgid "Returns a mesh's surface's material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1889
+msgid "Sets a mesh's surface's material."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1904
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1927
+msgid ""
+"Creates a new multimesh on the RenderingServer and returns an [RID] handle. "
+"This RID will be used in all [code]multimesh_*[/code] RenderingServer "
+"functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this multimesh to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1938
+msgid ""
+"Calculates and returns the axis-aligned bounding box that encloses all "
+"instances within the multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1955
+msgid "Returns the number of instances allocated for this multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1964
+msgid ""
+"Returns the RID of the mesh that will be used in drawing this multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1973
+msgid "Returns the number of visible instances for this multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1984
+msgid "Returns the color by which the specified instance will be modulated."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:1995
+msgid "Returns the custom data associated with the specified instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2006
+msgid "Returns the [Transform] of the specified instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2017
+msgid ""
+"Returns the [Transform2D] of the specified instance. For use when the "
+"multimesh is set to use 2D transforms."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2030
+msgid ""
+"Sets the color by which this instance will be modulated. Equivalent to "
+"[method MultiMesh.set_instance_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2043
+msgid ""
+"Sets the custom data for this instance. Custom data is passed as a [Color], "
+"but is interpreted as a [code]vec4[/code] in the shader. Equivalent to "
+"[method MultiMesh.set_instance_custom_data]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2056
+msgid ""
+"Sets the [Transform] for this instance. Equivalent to [method MultiMesh."
+"set_instance_transform]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2069
+msgid ""
+"Sets the [Transform2D] for this instance. For use when multimesh is used in "
+"2D. Equivalent to [method MultiMesh.set_instance_transform_2d]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2090
+msgid ""
+"Sets the mesh to be drawn by the multimesh. Equivalent to [member MultiMesh."
+"mesh]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2101
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2108
+msgid ""
+"Creates a new omni light and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID can be used in most "
+"[code]light_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this omni light to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2117
+msgid ""
+"Creates a particle system and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]particles_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach these particles to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2128
+msgid ""
+"Calculates and returns the axis-aligned bounding box that contains all the "
+"particles. Equivalent to [method GPUParticles3D.capture_aabb]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2137
+msgid "Returns [code]true[/code] if particles are currently set to emitting."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2146
+msgid ""
+"Returns [code]true[/code] if particles are not emitting and particles are "
+"set to inactive."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2155
+msgid ""
+"Add particle system to list of particle systems that need to be updated. "
+"Update will take place on the next frame, or on the next call to [method "
+"instances_cull_aabb], [method instances_cull_convex], or [method "
+"instances_cull_ray]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2164
+msgid ""
+"Reset the particles on the next update. Equivalent to [method GPUParticles3D."
+"restart]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2175
+msgid ""
+"Sets the number of particles to be drawn and allocates the memory for them. "
+"Equivalent to [member GPUParticles3D.amount]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2186
+msgid ""
+"Sets a custom axis-aligned bounding box for the particle system. Equivalent "
+"to [member GPUParticles3D.visibility_aabb]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2197
+msgid ""
+"Sets the draw order of the particles to one of the named enums from [enum "
+"ParticlesDrawOrder]. See [enum ParticlesDrawOrder] for options. Equivalent "
+"to [member GPUParticles3D.draw_order]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2210
+msgid ""
+"Sets the mesh to be used for the specified draw pass. Equivalent to [member "
+"GPUParticles3D.draw_pass_1], [member GPUParticles3D.draw_pass_2], [member "
+"GPUParticles3D.draw_pass_3], and [member GPUParticles3D.draw_pass_4]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2221
+msgid ""
+"Sets the number of draw passes to use. Equivalent to [member GPUParticles3D."
+"draw_passes]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2232
+msgid ""
+"Sets the [Transform] that will be used by the particles when they first emit."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2243
+msgid ""
+"If [code]true[/code], particles will emit over time. Setting to false does "
+"not reset the particles, but only stops their emission. Equivalent to "
+"[member GPUParticles3D.emitting]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2254
+msgid ""
+"Sets the explosiveness ratio. Equivalent to [member GPUParticles3D."
+"explosiveness]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2265
+msgid ""
+"Sets the frame rate that the particle system rendering will be fixed to. "
+"Equivalent to [member GPUParticles3D.fixed_fps]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2276
+msgid ""
+"If [code]true[/code], uses fractional delta which smooths the movement of "
+"the particles. Equivalent to [member GPUParticles3D.fract_delta]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2287
+msgid ""
+"Sets the lifetime of each particle in the system. Equivalent to [member "
+"GPUParticles3D.lifetime]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2298
+msgid ""
+"If [code]true[/code], particles will emit once and then stop. Equivalent to "
+"[member GPUParticles3D.one_shot]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2309
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2320
+msgid ""
+"Sets the material for processing the particles. Note: this is not the "
+"material used to draw the materials. Equivalent to [member GPUParticles3D."
+"process_material]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2331
+msgid ""
+"Sets the emission randomness ratio. This randomizes the emission of "
+"particles within their phase. Equivalent to [member GPUParticles3D."
+"randomness]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2342
+msgid ""
+"Sets the speed scale of the particle system. Equivalent to [member "
+"GPUParticles3D.speed_scale]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2353
+msgid ""
+"If [code]true[/code], particles use local coordinates. If [code]false[/code] "
+"they use global coordinates. Equivalent to [member GPUParticles3D."
+"local_coords]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2360
+msgid ""
+"Creates a reflection probe and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]reflection_probe_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this reflection probe to an instance using "
+"[method instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2373
+msgid ""
+"If [code]true[/code], reflections will ignore sky contribution. Equivalent "
+"to [member ReflectionProbe.interior_enable]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2384
+msgid ""
+"Sets the render cull mask for this reflection probe. Only instances with a "
+"matching cull mask will be rendered by this probe. Equivalent to [member "
+"ReflectionProbe.cull_mask]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2395
+msgid ""
+"If [code]true[/code], uses box projection. This can make reflections look "
+"more correct in certain situations. Equivalent to [member ReflectionProbe."
+"box_projection]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2406
+msgid ""
+"If [code]true[/code], computes shadows in the reflection probe. This makes "
+"the reflection much slower to compute. Equivalent to [member ReflectionProbe."
+"enable_shadows]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2417
+msgid ""
+"Sets the size of the area that the reflection probe will capture. Equivalent "
+"to [member ReflectionProbe.extents]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2428
+msgid ""
+"Sets the intensity of the reflection probe. Intensity modulates the strength "
+"of the reflection. Equivalent to [member ReflectionProbe.intensity]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2439
+msgid ""
+"Sets the ambient light color for this reflection probe when set to interior "
+"mode. Equivalent to [member ReflectionProbe.interior_ambient_color]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2450
+msgid ""
+"Sets the energy multiplier for this reflection probes ambient light "
+"contribution when set to interior mode. Equivalent to [member "
+"ReflectionProbe.interior_ambient_energy]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2461
+msgid ""
+"Sets the contribution value for how much the reflection affects the ambient "
+"light for this reflection probe when set to interior mode. Useful so that "
+"ambient light matches the color of the room. Equivalent to [member "
+"ReflectionProbe.interior_ambient_contrib]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2472
+msgid ""
+"Sets the max distance away from the probe an object can be before it is "
+"culled. Equivalent to [member ReflectionProbe.max_distance]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2483
+msgid ""
+"Sets the origin offset to be used when this reflection probe is in box "
+"project mode. Equivalent to [member ReflectionProbe.origin_offset]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2494
+msgid ""
+"Sets how often the reflection probe updates. Can either be once or every "
+"frame. See [enum ReflectionProbeUpdateMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2507
+msgid ""
+"Schedules a callback to the corresponding named [code]method[/code] on "
+"[code]where[/code] after a frame has been drawn.\n"
+"The callback method must use only 1 argument which will be called with "
+"[code]userdata[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2515
+msgid ""
+"Creates a scenario and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all "
+"[code]scenario_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"The scenario is the 3D world that all the visual instances exist in."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2528
+msgid ""
+"Sets the [enum ScenarioDebugMode] for this scenario. See [enum "
+"ScenarioDebugMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2539
+msgid "Sets the environment that will be used with this scenario."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2550
+msgid ""
+"Sets the fallback environment to be used by this scenario. The fallback "
+"environment is used if no environment is set. Internally, this is used by "
+"the editor to provide a default environment."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2565
+msgid ""
+"Sets a boot image. The color defines the background color. If [code]scale[/"
+"code] is [code]true[/code], the image will be scaled to fit the screen size. "
+"If [code]use_filter[/code] is [code]true[/code], the image will be scaled "
+"with linear interpolation. If [code]use_filter[/code] is [code]false[/code], "
+"the image will be scaled with nearest-neighbor interpolation."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2574
+msgid ""
+"If [code]true[/code], the engine will generate wireframes for use with the "
+"wireframe debug mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2583
+msgid ""
+"Sets the default clear color which is used when a specific clear color has "
+"not been selected."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2590
+msgid ""
+"Creates an empty shader and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]shader_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2600
+msgid "Returns a shader's code."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2611
+msgid "Returns a default texture from a shader searched by name."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2630
+msgid "Returns the parameters of a shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2641
+msgid "Sets a shader's code."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2654
+msgid "Sets a shader's default texture. Overwrites the texture given by name."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2667
+msgid "Allocates the GPU buffers for this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2678
+msgid "Returns the [Transform] set for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2689
+msgid "Returns the [Transform2D] set for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2702
+msgid "Sets the [Transform] for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2715
+msgid "Sets the [Transform2D] for a specific bone of this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2722
+msgid ""
+"Creates a skeleton and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all "
+"[code]skeleton_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2732
+msgid "Returns the number of bones allocated for this skeleton."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2739
+msgid ""
+"Creates an empty sky and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID will be used in all [code]sky_*[/"
+"code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2751
+msgid ""
+"Sets the material that the sky uses to render the background and reflection "
+"maps."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2758
+msgid ""
+"Creates a spot light and adds it to the RenderingServer. It can be accessed "
+"with the RID that is returned. This RID can be used in most [code]light_*[/"
+"code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method.\n"
+"To place in a scene, attach this spot light to an instance using [method "
+"instance_set_base] using the returned RID."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2787
+msgid "Sets a viewport's camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2798
+msgid "Sets a viewport's canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2811
+msgid ""
+"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.\n"
+"For example, you can set the root viewport to not render at all with the "
+"following code:\n"
+"[codeblock]\n"
+"func _ready():\n"
+" get_viewport().set_attach_to_screen_rect(Rect2())\n"
+" $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n"
+"[/codeblock]\n"
+"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]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2825
+msgid ""
+"Creates an empty viewport and adds it to the RenderingServer. It can be "
+"accessed with the RID that is returned. This RID will be used in all "
+"[code]viewport_*[/code] RenderingServer functions.\n"
+"Once finished with your RID, you will want to free the RID using the "
+"RenderingServer's [method free_rid] static method."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2837
+msgid ""
+"Returns a viewport's render information. For options, see the [enum "
+"ViewportRenderInfo] constants."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2846
+msgid "Returns the viewport's last rendered frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2857
+msgid "Detaches a viewport from a canvas and vice versa."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2868
+msgid "If [code]true[/code], sets the viewport active, else sets it inactive."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2883
+msgid ""
+"Sets the stacking order for a viewport's canvas.\n"
+"[code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] "
+"specifies the stacking order of the canvas among those in the same layer."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2897
+msgid "Sets the transformation of a viewport's canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2908
+msgid ""
+"Sets the clear mode of a viewport. See [enum ViewportClearMode] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2919
+msgid ""
+"Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for "
+"options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2930
+msgid ""
+"If [code]true[/code], rendering of a viewport's environment is disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2941
+msgid "Sets the viewport's global transformation matrix."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2952
+msgid "If [code]true[/code], the viewport's canvas is not rendered."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2963
+msgid "Currently unimplemented in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2974
+msgid "Sets the anti-aliasing mode. See [enum ViewportMSAA] for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2985
+msgid "Sets the viewport's parent to another viewport."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:2996
+msgid ""
+"If [code]true[/code], render the contents of the viewport directly to "
+"screen. This allows a low-level optimization where you can skip drawing a "
+"viewport to the root viewport. While this optimization can result in a "
+"significant increase in speed (especially on older devices), it comes at a "
+"cost of usability. When this is enabled, you cannot read from the viewport "
+"or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of "
+"certain window settings, such as the various stretch modes. Another "
+"consequence to be aware of is that in 2D the rendering happens in window "
+"coordinates, so if you have a viewport that is double the size of the "
+"window, and you set this, then only the portion that fits within the window "
+"will be drawn, no automatic scaling is possible, even if your game scene is "
+"significantly larger than the window size."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3007
+msgid ""
+"Sets a viewport's scenario.\n"
+"The scenario contains information about the [enum ScenarioDebugMode], "
+"environment information, reflection atlas etc."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3021
+msgid "Sets the shadow atlas quadrant's subdivision."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3032
+msgid ""
+"Sets the size of the shadow atlas's images (used for omni and spot lights). "
+"The value will be rounded up to the nearest power of 2."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3045
+msgid "Sets the viewport's width and height."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3056
+msgid ""
+"If [code]true[/code], the viewport renders its background as transparent."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3067
+msgid ""
+"Sets when the viewport should be updated. See [enum ViewportUpdateMode] "
+"constants for options."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3078
+msgid ""
+"If [code]true[/code], the viewport uses augmented or virtual reality "
+"technologies. See [ARVRInterface]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3085
+msgid ""
+"Emitted at the end of the frame, after the RenderingServer has finished "
+"updating all the Viewports."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3090
+msgid ""
+"Emitted at the beginning of the frame, before the RenderingServer updates "
+"all the Viewports."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3096
+msgid "Marks an error that shows that the index array is empty."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3099
+msgid "Number of weights/bones per vertex."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3102
+msgid "The minimum Z-layer for canvas items."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3105
+msgid "The maximum Z-layer for canvas items."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3108
+msgid ""
+"Max number of glow levels that can be used with glow post-process effect."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3111
+msgid "Unused enum in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3114
+msgid "The minimum renderpriority of all materials."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3117
+msgid "The maximum renderpriority of all materials."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3138
+msgid "Shader is a 3D shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3141
+msgid "Shader is a 2D shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3144
+msgid "Shader is a particle shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3147
+msgid "Shader is a sky shader."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3150
+msgid "Represents the size of the [enum ShaderMode] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3153
+msgid "Array is a vertex array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3156
+msgid "Array is a normal array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3159
+msgid "Array is a tangent array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3162
+msgid "Array is a color array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3165
+msgid "Array is an UV coordinates array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3168
+msgid "Array is an UV coordinates array for the second UV coordinates."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3171
+msgid "Array contains bone information."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3174
+msgid "Array is weight information."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3177
+msgid "Array is index array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3183
+msgid "Flag used to mark a vertex array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3186
+msgid "Flag used to mark a normal array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3189
+msgid "Flag used to mark a tangent array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3192
+msgid "Flag used to mark a color array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3195
+msgid "Flag used to mark an UV coordinates array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3198
+msgid ""
+"Flag used to mark an UV coordinates array for the second UV coordinates."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3201
+msgid "Flag used to mark a bone information array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3204
+msgid "Flag used to mark a weights array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3207
+msgid "Flag used to mark an index array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3236
+msgid "Primitive to draw consists of points."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3239
+msgid "Primitive to draw consists of lines."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3242
+msgid "Primitive to draw consists of a line strip from start to end."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3245
+msgid "Primitive to draw consists of triangles."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3248
+msgid ""
+"Primitive to draw consists of a triangle strip (the last 3 vertices are "
+"always combined to make a triangle)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3251
+msgid "Represents the size of the [enum PrimitiveType] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3260
+msgid "Use [Transform2D] to store MultiMesh transform."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3263
+msgid "Use [Transform] to store MultiMesh transform."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3266
+msgid "Is a directional (sun) light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3269
+msgid "Is an omni light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3272
+msgid "Is a spot light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3275
+msgid "The light's energy."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3280
+msgid "The light's influence on specularity."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3283
+msgid "The light's range."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3286
+msgid "The light's attenuation."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3289
+msgid "The spotlight's angle."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3292
+msgid "The spotlight's attenuation."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3295
+msgid "Scales the shadow color."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3298
+msgid "Max distance that shadows will be rendered."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3301
+msgid "Proportion of shadow atlas occupied by the first split."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3304
+msgid "Proportion of shadow atlas occupied by the second split."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3307
+msgid ""
+"Proportion of shadow atlas occupied by the third split. The fourth split "
+"occupies the rest."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3312
+msgid ""
+"Normal bias used to offset shadow lookup by object normal. Can be used to "
+"fix self-shadowing artifacts."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3315
+msgid "Bias the shadow lookup to fix self-shadowing artifacts."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3318
+msgid ""
+"Increases bias on further splits to fix self-shadowing that only occurs far "
+"away from the camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3321
+msgid "Represents the size of the [enum LightParam] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3324
+msgid "Use a dual paraboloid shadow map for omni lights."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3327
+msgid ""
+"Use a cubemap shadow map for omni lights. Slower but better quality than "
+"dual paraboloid."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3330
+msgid "Use orthogonal shadow projection for directional light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3333
+msgid "Use 2 splits for shadow projection when using directional light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3336
+msgid "Use 4 splits for shadow projection when using directional light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3339
+msgid ""
+"Keeps shadows stable as camera moves but has lower effective resolution."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3342
+msgid ""
+"Optimize use of shadow maps, increasing the effective resolution. But may "
+"result in shadows moving or flickering slightly."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3345
+msgid "Reflection probe will update reflections once and then stop."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3348
+msgid ""
+"Reflection probe will update each frame. This mode is necessary to capture "
+"moving objects."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3351
+msgid "Draw particles in the order that they appear in the particles array."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3354
+msgid "Sort particles based on their lifetime."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3357
+msgid "Sort particles based on their distance to the camera."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3360
+msgid "Do not update the viewport."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3363
+msgid "Update the viewport once then set to disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3366
+msgid "Update the viewport whenever it is visible."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3371
+msgid "Always update the viewport."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3374
+msgid "The viewport is always cleared before drawing."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3377
+msgid "The viewport is never cleared before drawing."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3380
+msgid ""
+"The viewport is cleared once, then the clear mode is set to [constant "
+"VIEWPORT_CLEAR_NEVER]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3383
+msgid "Multisample antialiasing is disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3386
+msgid "Multisample antialiasing is set to 2×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3389
+msgid "Multisample antialiasing is set to 4×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3392
+msgid "Multisample antialiasing is set to 8×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3395
+msgid "Multisample antialiasing is set to 16×."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3398
+msgid ""
+"Multisample antialiasing is set to 2× on external texture. Special mode for "
+"GLES2 Android VR (Oculus Quest and Go)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3401
+msgid ""
+"Multisample antialiasing is set to 4× on external texture. Special mode for "
+"GLES2 Android VR (Oculus Quest and Go)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3404
+msgid "Number of objects drawn in a single frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3407
+msgid "Number of vertices drawn in a single frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3410
+msgid "Number of material changes during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3413
+msgid "Number of shader changes during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3416
+msgid "Number of surface changes during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3419
+msgid "Number of draw calls during this frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3422
+msgid "Represents the size of the [enum ViewportRenderInfo] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3425
+msgid "Debug draw is disabled. Default setting."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3428
+msgid "Debug draw sets objects to unshaded."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3433
+msgid "Overwrites clear color to [code](0,0,0,0)[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3436
+msgid "Debug draw draws objects in wireframe."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3461
+msgid "Use the clear color as background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3464
+msgid "Use a specified color as the background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3467
+msgid "Use a sky resource for the background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3470
+msgid ""
+"Use a specified canvas layer as the background. This can be useful for "
+"instantiating a 2D scene in a 3D world."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3473
+msgid ""
+"Do not clear the background, use whatever was rendered last frame as the "
+"background."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3479
+msgid "Represents the size of the [enum EnvironmentBG] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3506
+msgid "Output color as they came in."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3509
+msgid "Use the Reinhard tonemapper."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3512
+msgid "Use the filmic tonemapper."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3515
+msgid "Use the ACES tonemapper."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3518
+msgid "Disables the blur set for SSAO. Will make SSAO look noisier."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3521
+msgid "Perform a 1x1 blur on the SSAO output."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3524
+msgid "Performs a 2x2 blur on the SSAO output."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3527
+msgid "Performs a 3x3 blur on the SSAO output. Use this for smoothest SSAO."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3530
+msgid "Lowest quality of screen space ambient occlusion."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3533
+msgid "Medium quality screen space ambient occlusion."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3536
+msgid "Highest quality screen space ambient occlusion."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3555
+msgid "Do not use a debug mode."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3558
+msgid "Draw all objects as wireframe models."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3561
+msgid ""
+"Draw all objects in a way that displays how much overdraw is occurring. "
+"Overdraw occurs when a section of pixels is drawn and shaded and then "
+"another object covers it up. To optimize a scene, you should reduce overdraw."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3564
+msgid ""
+"Draw all objects without shading. Equivalent to setting all objects shaders "
+"to [code]unshaded[/code]."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3567
+msgid "The instance does not have a type."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3570
+msgid "The instance is a mesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3573
+msgid "The instance is a multimesh."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3576
+msgid "The instance is an immediate geometry."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3579
+msgid "The instance is a particle emitter."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3582
+msgid "The instance is a light."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3585
+msgid "The instance is a reflection probe."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3588
+msgid "The instance is a GI probe."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3591
+msgid "The instance is a lightmap capture."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3594
+msgid "Represents the size of the [enum InstanceType] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3597
+msgid ""
+"A combination of the flags of geometry instances (mesh, multimesh, immediate "
+"and particles)."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3600
+msgid "Allows the instance to be used in baked lighting."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3605
+msgid "When set, manually requests to draw geometry on next frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3608
+msgid "Represents the size of the [enum InstanceFlags] enum."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3611
+msgid "Disable shadows from this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3614
+msgid "Cast shadows from this instance."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3617
+msgid ""
+"Disable backface culling when rendering the shadow of the object. This is "
+"slightly slower but may result in more correct shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3620
+msgid ""
+"Only render the shadows from the object. The object itself will not be drawn."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3623
+msgid "The nine patch gets stretched where needed."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3626
+msgid "The nine patch gets filled with tiles where needed."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3629
+msgid ""
+"The nine patch gets filled with tiles where needed and stretches them a bit "
+"if needed."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3658
+msgid "Adds light color additive to the canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3661
+msgid "Adds light color subtractive to the canvas."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3664
+msgid "The light adds color depending on transparency."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3667
+msgid "The light adds color depending on mask."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3670
+msgid "Do not apply a filter to canvas light shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3673
+msgid "Use PCF5 filtering to filter canvas light shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3676
+msgid "Use PCF13 filtering to filter canvas light shadows."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3681
+msgid "Culling of the canvas occluder is disabled."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3684
+msgid "Culling of the canvas occluder is clockwise."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3687
+msgid "Culling of the canvas occluder is counterclockwise."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3690
+msgid "The amount of objects in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3693
+msgid "The amount of vertices in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3696
+msgid "The amount of modified materials in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3699
+msgid "The amount of shader rebinds in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3702
+msgid "The amount of surface changes in the frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3705
+msgid "The amount of draw calls in frame."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3720
+msgid "Hardware supports shaders. This enum is currently unused in Godot 3.x."
+msgstr ""
+
+#: doc/classes/RenderingServer.xml:3723
+msgid ""
+"Hardware supports multithreading. This enum is currently unused in Godot 3.x."
+msgstr ""
+
+#: doc/classes/Resource.xml:4
+msgid "Base class for all resources."
+msgstr ""
+
+#: doc/classes/Resource.xml:7
+msgid ""
+"Resource is the base class for all Godot-specific resource types, serving "
+"primarily as data containers. They are reference counted and freed when no "
+"longer in use. They are also cached once loaded from disk, so that any "
+"further attempts to load a resource from a given path will return the same "
+"reference (all this in contrast to a [Node], which is not reference counted "
+"and can be instanced from disk as many times as desired). Resources can be "
+"saved externally on disk or bundled into another object, such as a [Node] or "
+"another resource."
+msgstr ""
+
+#: doc/classes/Resource.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"resources.html"
+msgstr ""
+
+#: doc/classes/Resource.xml:17
+msgid ""
+"Virtual function which can be overridden to customize the behavior value of "
+"[method setup_local_to_scene]."
+msgstr ""
+
+#: doc/classes/Resource.xml:26
+msgid ""
+"Duplicates the resource, returning a new resource. By default, sub-resources "
+"are shared between resource copies for efficiency, this can be changed by "
+"passing [code]true[/code] to the [code]subresources[/code] argument."
+msgstr ""
+
+#: doc/classes/Resource.xml:33
+msgid ""
+"If [member resource_local_to_scene] is enabled and the resource was loaded "
+"from a [PackedScene] instantiation, returns the local scene where this "
+"resource's unique copy is in use. Otherwise, returns [code]null[/code]."
+msgstr ""
+
+#: doc/classes/Resource.xml:40
+msgid ""
+"Returns the RID of the resource (or an empty RID). Many resources (such as "
+"[Texture2D], [Mesh], etc) are high-level abstractions of resources stored in "
+"a server, so this function will return the original RID."
+msgstr ""
+
+#: doc/classes/Resource.xml:47
+msgid ""
+"This method is called when a resource with [member resource_local_to_scene] "
+"enabled is loaded from a [PackedScene] instantiation. Its behavior can be "
+"customized by overriding [method _setup_local_to_scene] from script.\n"
+"For most resources, this method performs no base logic. [ViewportTexture] "
+"performs custom logic to properly set the proxy texture and flags in the "
+"local viewport."
+msgstr ""
+
+#: doc/classes/Resource.xml:57
+msgid ""
+"Sets the path of the resource, potentially overriding an existing cache "
+"entry for this path. This differs from setting [member resource_path], as "
+"the latter would error out if another resource was already cached for the "
+"given path."
+msgstr ""
+
+#: doc/classes/Resource.xml:63
+msgid ""
+"If [code]true[/code], the resource will be made unique in each instance of "
+"its local scene. It can thus be modified in a scene instance without "
+"impacting other instances of that same scene."
+msgstr ""
+
+#: doc/classes/Resource.xml:66
+msgid "The name of the resource. This is an optional identifier."
+msgstr ""
+
+#: doc/classes/Resource.xml:69
+msgid ""
+"The path to the resource. In case it has its own file, it will return its "
+"filepath. If it's tied to the scene, it will return the scene's path, "
+"followed by the resource's index."
+msgstr ""
+
+#: doc/classes/Resource.xml:75
+msgid "Emitted whenever the resource changes."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:4
+msgid "Loads a specific resource type from a file."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:7
+msgid ""
+"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.\n"
+"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].\n"
+"[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] ([StreamTexture]) first, so they can be loaded with "
+"better efficiency on the graphics card."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:22
+msgid ""
+"If implemented, gets the dependencies of a given resource. If "
+"[code]add_types[/code] is [code]true[/code], paths should be appended "
+"[code]::TypeName[/code], where [code]TypeName[/code] is the class name of "
+"the dependency.\n"
+"[b]Note:[/b] Custom resource types defined by scripts aren't known by the "
+"[ClassDB], so you might just return [code]\"Resource\"[/code] for them."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:30
+msgid "Gets the list of extensions for files this loader is able to read."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:39
+msgid ""
+"Gets the class name of the resource associated with the given path. If the "
+"loader cannot handle it, it should return [code]\"\"[/code].\n"
+"[b]Note:[/b] Custom resource types defined by scripts aren't known by the "
+"[ClassDB], so you might just return [code]\"Resource\"[/code] for them."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:49
+msgid ""
+"Tells which resource class this loader can load.\n"
+"[b]Note:[/b] Custom resource types defined by scripts aren't known by the "
+"[ClassDB], so you might just handle [code]\"Resource\"[/code] for them."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:61
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/ResourceFormatLoader.xml:72
+msgid ""
+"If implemented, renames dependencies within the given resource and saves it. "
+"[code]renames[/code] is a dictionary [code]{ String => String }[/code] "
+"mapping old dependency paths to new paths.\n"
+"Returns [constant OK] on success, or an [enum Error] constant in case of "
+"failure."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:4
+msgid "Saves a specific resource type to a file."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:7
+msgid ""
+"The engine can save resources when you do it from the editor, or when you "
+"use the [ResourceSaver] singleton. This is accomplished thanks to multiple "
+"[ResourceFormatSaver]s, each handling its own format and called "
+"automatically by the engine.\n"
+"By default, Godot saves resources as [code].tres[/code] (text-based), [code]."
+"res[/code] (binary) or another built-in format, but you can choose to create "
+"your own format by extending this class. 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 "
+"ResourceFormatSavers, it will be called automatically when saving resources "
+"of its recognized type(s). You may also implement a [ResourceFormatLoader]."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:19
+msgid ""
+"Returns the list of extensions available for saving the resource object, "
+"provided it is recognized (see [method recognize])."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:28
+msgid "Returns whether the given resource object can be saved by this saver."
+msgstr ""
+
+#: doc/classes/ResourceFormatSaver.xml:41
+msgid ""
+"Saves the given resource object to a file at the target [code]path[/code]. "
+"[code]flags[/code] is a bitmask composed with [enum ResourceSaver."
+"SaverFlags] constants.\n"
+"Returns [constant OK] on success, or an [enum Error] constant in case of "
+"failure."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:4
+msgid "Singleton used to load resource files."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:7
+msgid ""
+"Singleton used to load resource files from the filesystem.\n"
+"It uses the many [ResourceFormatLoader] classes registered in the engine "
+"(either built-in or from a plugin) to load files into memory and convert "
+"them to a format that can be used by the engine.\n"
+"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."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:22
+msgid ""
+"Returns whether a recognized resource exists for the given [code]path[/"
+"code].\n"
+"An optional [code]type_hint[/code] can be used to further specify the "
+"[Resource] type that should be handled by the [ResourceFormatLoader]."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:32
+msgid ""
+"Returns the dependencies for the resource at the given [code]path[/code]."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:41
+msgid "Returns the list of recognized extensions for a resource type."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:50
+msgid ""
+"Returns whether a cached resource is available for the given [code]path[/"
+"code].\n"
+"Once a resource has been loaded by the engine, it is cached in memory for "
+"faster access, and future calls to the [method load] method will use the "
+"cached version. The cached resource can be overridden by using [method "
+"Resource.take_over_path] on a new resource for that same path."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:64
+msgid ""
+"Loads a resource at the given [code]path[/code], caching the result for "
+"further access.\n"
+"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.\n"
+"An optional [code]type_hint[/code] can be used to further specify the "
+"[Resource] type that should be handled by the [ResourceFormatLoader].\n"
+"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.\n"
+"Returns an empty resource if no ResourceFormatLoader could handle the file."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:77
+msgid ""
+"Returns the resource loaded by [method load_threaded_request].\n"
+"If this is called before the loading thread is done (i.e. [method "
+"load_threaded_get_status] is not [constant THREAD_LOAD_LOADED]), the calling "
+"thread will be blocked until the resource has finished loading."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:89
+msgid ""
+"Returns the status of a threaded loading operation started with [method "
+"load_threaded_request] for the resource at [code]path[/code]. See [enum "
+"ThreadLoadStatus] for possible return values.\n"
+"An array variable can optionally be passed via [code]progress[/code], and "
+"will return a one-element array containing the percentage of completion of "
+"the threaded loading."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:103
+msgid ""
+"Loads the resource using threads. If [code]use_sub_threads[/code] is "
+"[code]true[/code], multiple threads will be used to load the resource, which "
+"makes loading faster, but may affect the main thread (and thus cause game "
+"slowdowns)."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:112
+msgid ""
+"Changes the behavior on missing sub-resources. The default behavior is to "
+"abort loading."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:118
+msgid ""
+"The resource is invalid, or has not been loaded with [method "
+"load_threaded_request]."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:121
+msgid "The resource is still being loaded."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:124
+msgid "Some error occurred during loading and it failed."
+msgstr ""
+
+#: doc/classes/ResourceLoader.xml:127
+msgid ""
+"The resource was loaded successfully and can be accessed via [method "
+"load_threaded_get]."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:4
+msgid "Resource Preloader Node."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:7
+msgid ""
+"This node is used to preload sub-resources inside a scene, so when the scene "
+"is loaded, all the resources are ready to use and can be retrieved from the "
+"preloader.\n"
+"GDScript has a simplified [method @GDScript.preload] built-in method which "
+"can be used in most situations, leaving the use of [ResourcePreloader] for "
+"more advanced scenarios."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:21
+msgid ""
+"Adds a resource to the preloader with the given [code]name[/code]. If a "
+"resource with the given [code]name[/code] already exists, the new resource "
+"will be renamed to \"[code]name[/code] N\" where N is an incrementing number "
+"starting from 2."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:30
+msgid "Returns the resource associated to [code]name[/code]."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:37
+msgid "Returns the list of resources inside the preloader."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:46
+msgid ""
+"Returns [code]true[/code] if the preloader contains a resource associated to "
+"[code]name[/code]."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:55
+msgid ""
+"Removes the resource associated to [code]name[/code] from the preloader."
+msgstr ""
+
+#: doc/classes/ResourcePreloader.xml:66
+msgid ""
+"Renames a resource inside the preloader from [code]name[/code] to "
+"[code]newname[/code]."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:4
+msgid "Singleton for saving Godot-specific resource types."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:7
+msgid ""
+"Singleton for saving Godot-specific resource types to the filesystem.\n"
+"It uses the many [ResourceFormatSaver] classes registered in the engine "
+"(either built-in or from a plugin) to save engine-specific resource data to "
+"text-based (e.g. [code].tres[/code] or [code].tscn[/code]) or binary files "
+"(e.g. [code].res[/code] or [code].scn[/code])."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:19
+msgid ""
+"Returns the list of extensions available for saving a resource of a given "
+"type."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:32
+msgid ""
+"Saves a resource to disk to the given path, using a [ResourceFormatSaver] "
+"that recognizes the resource object.\n"
+"The [code]flags[/code] bitmask can be specified to customize the save "
+"behavior.\n"
+"Returns [constant OK] on success."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:40
+msgid "Save the resource with a path relative to the scene which uses it."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:43
+msgid "Bundles external resources."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:46
+msgid ""
+"Changes the [member Resource.resource_path] of the saved resource to match "
+"its new location."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:49
+msgid ""
+"Do not save editor-specific metadata (identified by their [code]__editor[/"
+"code] prefix)."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:52
+msgid "Save as big endian (see [member File.endian_swap])."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:55
+msgid ""
+"Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only "
+"available for binary resource types."
+msgstr ""
+
+#: doc/classes/ResourceSaver.xml:58
+msgid ""
+"Take over the paths of the saved subresources (see [method Resource."
+"take_over_path])."
+msgstr ""
+
+#: doc/classes/RichTextEffect.xml:4
+msgid "A custom effect for use with [RichTextLabel]."
+msgstr ""
+
+#: doc/classes/RichTextEffect.xml:7
+msgid ""
+"A custom effect for use with [RichTextLabel].\n"
+"[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.\n"
+"[codeblock]\n"
+"# The RichTextEffect will be usable like this: `[example]Some text[/"
+"example]`\n"
+"var bbcode = \"example\"\n"
+"[/codeblock]\n"
+"[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."
+msgstr ""
+
+#: doc/classes/RichTextEffect.xml:26
+msgid ""
+"Override this method to modify properties in [code]char_fx[/code]. The "
+"method must return [code]true[/code] if the character could be transformed "
+"successfully. If the method returns [code]false[/code], it will skip "
+"transformation to avoid displaying broken text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:4
+msgid "Label that displays rich text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:7
+msgid ""
+"Rich text can contain custom text, fonts, images and some basic formatting. "
+"The label manages these as an internal tag stack. It also adapts itself to "
+"given width/heights.\n"
+"[b]Note:[/b] Assignments to [member bbcode_text] clear the tag stack and "
+"reconstruct it from the property's contents. Any edits made to [member "
+"bbcode_text] will erase previous edits made from other manual sources such "
+"as [method append_bbcode] and the [code]push_*[/code] / [method pop] methods."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:24
+msgid ""
+"Adds an image's opening and closing tags to the tag stack, optionally "
+"providing a [code]width[/code] and [code]height[/code] to resize the image.\n"
+"If [code]width[/code] or [code]height[/code] is set to 0, the image size "
+"will be adjusted in order to keep the original aspect ratio."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:34
+msgid "Adds raw non-BBCode-parsed text to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:43
+msgid ""
+"Parses [code]bbcode[/code] and adds tags to the tag stack as needed. Returns "
+"the result of the parsing, [constant OK] if successful."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:50
+msgid "Clears the tag stack and sets [member bbcode_text] to an empty string."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:57
+msgid "Returns the height of the content."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:64
+msgid ""
+"Returns the total number of newlines in the tag stack's text tags. Considers "
+"wrapped text as one line."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:71
+msgid ""
+"Returns the total number of characters from text tags. Does not include "
+"BBCodes."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:78
+msgid "Returns the vertical scrollbar."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:85
+msgid "Returns the number of visible lines."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:94
+msgid ""
+"Installs a custom effect. [code]effect[/code] should be a valid "
+"[RichTextEffect]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:101
+msgid "Adds a newline tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:110
+msgid ""
+"The assignment version of [method append_bbcode]. Clears the tag stack and "
+"inserts the new content. Returns [constant OK] if parses [code]bbcode[/code] "
+"successfully."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:119
+msgid "Parses BBCode parameter [code]expressions[/code] into a dictionary."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:126
+msgid ""
+"Terminates the current tag. Use after [code]push_*[/code] methods to close "
+"BBCodes manually. Does not need to follow [code]add_*[/code] methods."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:135
+msgid ""
+"Adds an [code][align][/code] tag based on the given [code]align[/code] "
+"value. See [enum Align] for possible values."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:142
+msgid ""
+"Adds a [code][font][/code] tag with a bold font to the tag stack. This is "
+"the same as adding a [code][b][/code] tag if not currently in a [code][i][/"
+"code] tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:149
+msgid ""
+"Adds a [code][font][/code] tag with a bold italics font to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:156
+msgid ""
+"Adds a [code][cell][/code] tag to the tag stack. Must be inside a [code]"
+"[table][/code] tag. See [method push_table] for details."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:165
+msgid "Adds a [code][color][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:174
+msgid ""
+"Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for "
+"its duration."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:183
+msgid ""
+"Adds an [code][indent][/code] tag to the tag stack. Multiplies [code]level[/"
+"code] by current [member tab_size] to determine new margin length."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:190
+msgid ""
+"Adds a [code][font][/code] tag with a italics font to the tag stack. This is "
+"the same as adding a [code][i][/code] tag if not currently in a [code][b][/"
+"code] tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:199
+msgid ""
+"Adds a [code][list][/code] tag to the tag stack. Similar to the BBCodes "
+"[code][ol][/code] or [code][ul][/code], but supports more list types. Not "
+"fully implemented!"
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:208
+msgid ""
+"Adds a [code][meta][/code] tag to the tag stack. Similar to the BBCode [code]"
+"[url=something]{text}[/url][/code], but supports non-[String] metadata types."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:215
+msgid "Adds a [code][font][/code] tag with a monospace font to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:222
+msgid "Adds a [code][font][/code] tag with a normal font to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:229
+msgid "Adds a [code][s][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:238
+msgid "Adds a [code][table=columns][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:245
+msgid "Adds a [code][u][/code] tag to the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:254
+msgid ""
+"Removes a line of content from the label. Returns [code]true[/code] if the "
+"line exists.\n"
+"The [code]line[/code] argument is the index of the line to remove, it can "
+"take values in the interval [code][0, get_line_count() - 1][/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:264
+msgid "Scrolls the window's top line to match [code]line[/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:277
+msgid ""
+"Edits the selected column's expansion options. If [code]expand[/code] is "
+"[code]true[/code], the column expands in proportion to its expansion ratio "
+"versus the other columns' ratios.\n"
+"For example, 2 columns with ratios 3 and 4 plus 70 pixels in available width "
+"would expand 30 and 40 pixels, respectively.\n"
+"If [code]expand[/code] is [code]false[/code], the column will not contribute "
+"to the total ratio."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:285
+msgid "If [code]true[/code], the label uses BBCode formatting."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:288
+msgid ""
+"The label's text in BBCode format. Is not representative of manual "
+"modifications to the internal tag stack. Erases changes made by other "
+"methods when edited.\n"
+"[b]Note:[/b] It is unadvised to use [code]+=[/code] operator with "
+"[code]bbcode_text[/code] (e.g. [code]bbcode_text += \"some string\"[/code]) "
+"as it replaces the whole text and can cause slowdowns. Use [method "
+"append_bbcode] for adding text instead."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:292
+msgid ""
+"The currently installed custom effects. This is an array of "
+"[RichTextEffect]s.\n"
+"To add a custom effect, it's more convenient to use [method install_effect]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:296
+msgid ""
+"If [code]true[/code], the label underlines meta tags such as [code][url]"
+"{text}[/url][/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:299
+msgid "If [code]true[/code], the label uses the custom font color."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:302
+msgid ""
+"The range of characters to display, as a [float] between 0.0 and 1.0. When "
+"assigned an out of range value, it's the same as assigning 1.0.\n"
+"[b]Note:[/b] Setting this property updates [member visible_characters] based "
+"on current [method get_total_character_count]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:307
+msgid ""
+"If [code]true[/code], the scrollbar is visible. Setting this to [code]false[/"
+"code] does not block scrolling completely. See [method scroll_to_line]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:310
+msgid ""
+"If [code]true[/code], the window scrolls down to display new content "
+"automatically."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:313
+msgid "If [code]true[/code], the label allows text selection."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:316
+msgid ""
+"The number of spaces associated with a single tab length. Does not affect "
+"[code]\\t[/code] in text tags, only indent tags."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:319
+msgid ""
+"The raw text of the label.\n"
+"When set, clears the tag stack and adds a raw text tag to the top of it. "
+"Does not parse BBCodes. Does not modify [member bbcode_text]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:323
+msgid ""
+"The restricted number of characters to display in the label. If [code]-1[/"
+"code], all characters will be displayed."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:331
+msgid ""
+"Triggered when the user clicks on content between meta tags. If the meta is "
+"defined in text, e.g. [code][url={\"data\"=\"hi\"}]hi[/url][/code], then the "
+"parameter for this signal will be a [String] type. If a particular type or "
+"an object is desired, the [method push_meta] method must be used to manually "
+"insert the data into the tag stack."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:338
+msgid "Triggers when the mouse exits a meta tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:345
+msgid "Triggers when the mouse enters a meta tag."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:351
+msgid "Makes text left aligned."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:354
+msgid "Makes text centered."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:357
+msgid "Makes text right aligned."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:360
+msgid "Makes text fill width."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:363
+msgid "Each list item has a number marker."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:366
+msgid "Each list item has a letter marker."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:369
+msgid "Each list item has a filled circle marker."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:412
+msgid "The font used for bold text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:415
+msgid "The font used for bold italics text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:418
+msgid "The default text color."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:421
+msgid "The background The background used when the [RichTextLabel] is focused."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:424
+msgid ""
+"The color of selected text, used when [member selection_enabled] is "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:427
+msgid "The color of the font's shadow."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:430
+msgid "The font used for italics text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:433
+msgid "The vertical space between lines."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:436
+msgid "The font used for monospace text."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:439
+msgid "The normal background for the [RichTextLabel]."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:442
+msgid "The default text font."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:445
+msgid "The color of the selection box."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:448
+msgid ""
+"Boolean value. If 1 ([code]true[/code]), the shadow will be displayed around "
+"the whole text as an outline."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:451
+msgid "The horizontal offset of the font's shadow."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:454
+msgid "The vertical offset of the font's shadow."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:457
+msgid "The horizontal separation of elements in a table."
+msgstr ""
+
+#: doc/classes/RichTextLabel.xml:460
+msgid "The vertical separation of elements in a table."
+msgstr ""
+
+#: doc/classes/RID.xml:4
+msgid "Handle for a [Resource]'s unique ID."
+msgstr ""
+
+#: doc/classes/RID.xml:7
+msgid ""
+"The RID type is used to access the unique integer ID of a resource. They are "
+"opaque, which means they do not grant access to the associated resource by "
+"themselves. They are used by and with the low-level Server classes such as "
+"[RenderingServer]."
+msgstr ""
+
+#: doc/classes/RID.xml:18
+msgid ""
+"Creates a new RID instance with the ID of a given resource. When not handed "
+"a valid resource, silently stores the unused ID 0."
+msgstr ""
+
+#: doc/classes/RID.xml:25
+msgid "Returns the ID of the referenced resource."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:4
+msgid "A body that is controlled by the 2D physics engine."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:7
+msgid ""
+"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.\n"
+"A RigidBody2D has 4 behavior [member mode]s: Rigid, Static, Character, and "
+"Kinematic.\n"
+"[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.\n"
+"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.\n"
+"If you need to override the default physics behavior or add a transformation "
+"at runtime, you can write a custom force integration. See [member "
+"custom_integrator]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:22
+msgid ""
+"Allows you to read and safely modify the simulation state for the object. "
+"Use this instead of [method Node._physics_process] if you need to directly "
+"change the body's [code]position[/code] or other physics properties. By "
+"default, it works in addition to the usual physics behavior, but [member "
+"custom_integrator] allows you to disable the default behavior and write "
+"custom force integration for a body."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:71
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time-independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason it should only be used when simulating one-time impacts (use "
+"the \"_force\" functions otherwise). The position uses the rotation of the "
+"global coordinate system, but is centered at the object's origin."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:87
+msgid ""
+"Returns a list of the bodies colliding with this one. Use [member "
+"contacts_reported] to set the maximum number reported. You must also set "
+"[member contact_monitor] to [code]true[/code].\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of collisions is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:97
+msgid ""
+"Sets the body's velocity on the given axis. The velocity in the given vector "
+"axis will be set as the given vector length. This is useful for jumping "
+"behavior."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:112
+msgid ""
+"Returns [code]true[/code] if a collision would result from moving in the "
+"given vector. [code]margin[/code] increases the size of the shapes involved "
+"in the collision detection, and [code]result[/code] is an object of type "
+"[PhysicsTestMotionResult2D], which contains additional information about the "
+"collision (should there be one)."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:118
+msgid ""
+"Damps the body's [member angular_velocity]. If [code]-1[/code], the body "
+"will use the [b]Default Angular Damp[/b] defined in [b]Project > Project "
+"Settings > Physics > 2d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:124
+msgid "The body's total applied force."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:127
+msgid "The body's total applied torque."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:130
+msgid ""
+"If [code]true[/code], the body will not calculate forces and will act as a "
+"static body if there is no movement. The body will wake up when other forces "
+"are applied via collisions or by using [method apply_impulse] or [method "
+"add_force]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:133
+msgid ""
+"If [code]true[/code], the body will emit signals when it collides with "
+"another RigidBody2D. See also [member contacts_reported]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:136
+msgid "The maximum number of contacts to report."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:139
+msgid ""
+"Continuous collision detection mode.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide instead of moving it and correcting its movement after collision. "
+"Continuous collision detection is slower, but more precise and misses fewer "
+"collisions with small, fast-moving objects. Raycasting and shapecasting "
+"methods are available. See [enum CCDMode] for details."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:143
+msgid ""
+"If [code]true[/code], internal force integration is disabled for this body. "
+"Aside from collision response, the body will only move as determined by the "
+"[method _integrate_forces] function."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:146
+msgid ""
+"Multiplies the gravity applied to the body. The body's gravity is calculated "
+"from the [b]Default Gravity[/b] value in [b]Project > Project Settings > "
+"Physics > 2d[/b] and/or any additional gravity vector applied by [Area2D]s."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:149
+msgid ""
+"The body's moment of inertia. This is like mass, but for rotation: it "
+"determines how much torque it takes to rotate the body. The moment of "
+"inertia is usually computed automatically from the mass and the shapes, but "
+"this function allows you to set a custom value. Set 0 inertia to return to "
+"automatically computing it."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:152
+msgid ""
+"Damps the body's [member linear_velocity]. If [code]-1[/code], the body will "
+"use the [b]Default Linear Damp[/b] in [b]Project > Project Settings > "
+"Physics > 2d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:158 doc/classes/RigidBody3D.xml:174
+msgid "The body's mass."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:161
+msgid "The body's mode. See [enum Mode] for possible values."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:164 doc/classes/RigidBody3D.xml:180
+#: doc/classes/StaticBody2D.xml:22 doc/classes/StaticBody3D.xml:22
+msgid ""
+"The physics material override for the body.\n"
+"If a material is assigned to this property, it will be used instead of any "
+"other physics material, such as an inherited one."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:168
+msgid ""
+"If [code]true[/code], the body is sleeping and will not calculate forces "
+"until woken up by a collision or by using [method apply_impulse] or [method "
+"add_force]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:171
+msgid ""
+"The body's weight based on its mass and the [b]Default Gravity[/b] value in "
+"[b]Project > Project Settings > Physics > 2d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:179
+msgid ""
+"Emitted when a body enters into contact with this one. [member "
+"contact_monitor] must be [code]true[/code] and [member contacts_reported] "
+"greater than [code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:186
+msgid ""
+"Emitted when a body exits contact with this one. [member contact_monitor] "
+"must be [code]true[/code] and [member contacts_reported] greater than "
+"[code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:199
+msgid ""
+"Emitted when a body enters into contact with this one. Reports colliding "
+"shape information. See [CollisionObject2D] for shape index information. "
+"[member contact_monitor] must be [code]true[/code] and [member "
+"contacts_reported] greater than [code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:212
+msgid ""
+"Emitted when a body shape exits contact with this one. Reports colliding "
+"shape information. See [CollisionObject2D] for shape index information. "
+"[member contact_monitor] must be [code]true[/code] and [member "
+"contacts_reported] greater than [code]0[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:217
+msgid "Emitted when [member sleeping] changes."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:223
+msgid ""
+"Rigid mode. The body behaves as a physical object. It collides with other "
+"bodies and responds to forces applied to it. This is the default mode."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:226
+msgid "Static mode. The body behaves like a [StaticBody2D] and does not move."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:229
+msgid ""
+"Character mode. Similar to [constant MODE_RIGID], but the body can not "
+"rotate."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:232
+msgid ""
+"Kinematic mode. The body behaves like a [KinematicBody2D], and must be moved "
+"by code."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:235
+msgid ""
+"Continuous collision detection disabled. This is the fastest way to detect "
+"body collisions, but can miss small, fast-moving objects."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:238
+msgid ""
+"Continuous collision detection enabled using raycasting. This is faster than "
+"shapecasting but less precise."
+msgstr ""
+
+#: doc/classes/RigidBody2D.xml:241
+msgid ""
+"Continuous collision detection enabled using shapecasting. This is the "
+"slowest CCD method and the most precise."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:4
+msgid ""
+"Physics Body whose position is determined through physics simulation in 3D "
+"space."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:7
+msgid ""
+"This is the node that implements full 3D physics. This means that you do not "
+"control a RigidBody3D directly. Instead, you can apply forces to it "
+"(gravity, impulses, etc.), and the physics simulation will calculate the "
+"resulting movement, collision, bouncing, rotating, etc.\n"
+"A RigidBody3D has 4 behavior [member mode]s: Rigid, Static, Character, and "
+"Kinematic.\n"
+"[b]Note:[/b] Don't change a RigidBody3D's position every frame or very "
+"often. Sporadic changes work fine, but physics runs at a different "
+"granularity (fixed Hz) than usual rendering (process callback) and maybe "
+"even in a separate thread, so changing this from a process loop may result "
+"in strange behavior. If you need to directly affect the body's state, use "
+"[method _integrate_forces], which allows you to directly access the physics "
+"state.\n"
+"If you need to override the default physics behavior, you can write a custom "
+"force integration function. See [member custom_integrator]."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:22
+msgid ""
+"Called during physics processing, allowing you to read and safely modify the "
+"simulation state for the object. By default, it works in addition to the "
+"usual physics behavior, but the [member custom_integrator] property allows "
+"you to disable the default behavior and do fully custom force integration "
+"for a body."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:43
+msgid "Adds a constant force (i.e. acceleration)."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:52
+msgid ""
+"Adds a constant rotational force (i.e. a motor) without affecting position."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:61
+msgid ""
+"Applies a directional impulse without affecting rotation.\n"
+"This is equivalent to [code]apply_impulse(Vector3(0,0,0), impulse)[/code]."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:73
+msgid ""
+"Applies a positioned impulse to the body. An impulse is time independent! "
+"Applying an impulse every frame would result in a framerate-dependent force. "
+"For this reason it should only be used when simulating one-time impacts. The "
+"position uses the rotation of the global coordinate system, but is centered "
+"at the object's origin."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:82
+msgid ""
+"Applies a torque impulse which will be affected by the body mass and shape. "
+"This will rotate the body around the [code]impulse[/code] vector passed."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:91
+msgid ""
+"Returns [code]true[/code] if the specified linear or rotational axis is "
+"locked."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:98
+msgid ""
+"Returns a list of the bodies colliding with this one. By default, number of "
+"max contacts reported is at 0, see the [member contacts_reported] property "
+"to increase it.\n"
+"[b]Note:[/b] The result of this test is not immediate after moving objects. "
+"For performance, list of collisions is updated once per frame and before the "
+"physics step. Consider using signals instead."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:110
+msgid "Locks the specified linear or rotational axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:125
+msgid "Damps RigidBody3D's rotational forces."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:128
+msgid "RigidBody3D's rotational velocity."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:131
+msgid "Lock the body's rotation in the X axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:134
+msgid "Lock the body's rotation in the Y axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:137
+msgid "Lock the body's rotation in the Z axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:140
+msgid "Lock the body's movement in the X axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:143
+msgid "Lock the body's movement in the Y axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:146
+msgid "Lock the body's movement in the Z axis."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:149
+msgid ""
+"If [code]true[/code], the RigidBody3D will not calculate forces and will act "
+"as a static body while there is no movement. It will wake up when forces are "
+"applied through other collisions or when the [code]apply_impulse[/code] "
+"method is used."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:152
+msgid ""
+"If [code]true[/code], the RigidBody3D will emit signals when it collides "
+"with another RigidBody3D."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:155
+msgid ""
+"The maximum contacts to report. Bodies can keep a log of the contacts with "
+"other bodies, this is enabled by setting the maximum amount of contacts "
+"reported to a number greater than 0."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:158
+msgid ""
+"If [code]true[/code], continuous collision detection is used.\n"
+"Continuous collision detection tries to predict where a moving body will "
+"collide, instead of moving it and correcting its movement if it collided. "
+"Continuous collision detection is more precise, and misses fewer impacts by "
+"small, fast-moving objects. Not using continuous collision detection is "
+"faster to compute, but can miss small, fast-moving objects."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:162
+msgid ""
+"If [code]true[/code], internal force integration will be disabled (like "
+"gravity or air friction) for this body. Other than collision response, the "
+"body will only move as determined by the [method _integrate_forces] "
+"function, if defined."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:165
+msgid ""
+"This is multiplied by the global 3D gravity setting found in [b]Project > "
+"Project Settings > Physics > 3d[/b] to produce RigidBody3D's gravity. For "
+"example, a value of 1 will be normal gravity, 2 will apply double gravity, "
+"and 0.5 will apply half gravity to this object."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:168
+msgid ""
+"The body's linear damp. Cannot be less than -1.0. If this value is different "
+"from -1.0, any linear damp derived from the world or areas will be "
+"overridden."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:171
+msgid ""
+"The body's linear velocity. Can be used sporadically, but [b]don't set this "
+"every frame[/b], because physics may run in another thread and runs at a "
+"different granularity. Use [method _integrate_forces] as your process loop "
+"for precise control of the body state."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:177
+msgid "The body mode. See [enum Mode] for possible values."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:184
+msgid ""
+"If [code]true[/code], the body is sleeping and will not calculate forces "
+"until woken up by a collision or the [code]apply_impulse[/code] method."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:187
+msgid ""
+"The body's weight based on its mass and the global 3D gravity. Global values "
+"are set in [b]Project > Project Settings > Physics > 3d[/b]."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:195
+msgid ""
+"Emitted when a body enters into contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:202
+msgid ""
+"Emitted when a body shape exits contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:215
+msgid ""
+"Emitted when a body enters into contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work.\n"
+"This signal not only receives the body that collided with this one, but also "
+"its [RID] ([code]body_id[/code]), the shape index from the colliding body "
+"([code]body_shape[/code]), and the shape index from this body "
+"([code]local_shape[/code]) the other body collided with."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:229
+msgid ""
+"Emitted when a body shape exits contact with this one. Contact monitor and "
+"contacts reported must be enabled for this to work.\n"
+"This signal not only receives the body that stopped colliding with this one, "
+"but also its [RID] ([code]body_id[/code]), the shape index from the "
+"colliding body ([code]body_shape[/code]), and the shape index from this body "
+"([code]local_shape[/code]) the other body stopped colliding with."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:235
+msgid ""
+"Emitted when the body changes its sleeping state. Either by sleeping or "
+"waking up."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:241
+msgid ""
+"Rigid body mode. This is the \"natural\" state of a rigid body. It is "
+"affected by forces, and can move, rotate, and be affected by user code."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:244
+msgid ""
+"Static mode. The body behaves like a [StaticBody3D], and can only move by "
+"user code."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:247
+msgid ""
+"Character body mode. This behaves like a rigid body, but can not rotate."
+msgstr ""
+
+#: doc/classes/RigidBody3D.xml:250
+msgid ""
+"Kinematic body mode. The body behaves like a [KinematicBody3D], and can only "
+"move by user code."
+msgstr ""
+
+#: doc/classes/SceneState.xml:4
+msgid "A script interface to a scene file's data."
+msgstr ""
+
+#: doc/classes/SceneState.xml:7
+msgid ""
+"Maintains a list of resources, nodes, exported, and overridden properties, "
+"and built-in scripts associated with a scene.\n"
+"This class cannot be instantiated directly, it is retrieved for a given "
+"scene as the result of [method PackedScene.get_state]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:19
+msgid ""
+"Returns the list of bound parameters for the signal at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:26
+msgid ""
+"Returns the number of signal connections in the scene.\n"
+"The [code]idx[/code] argument used to query connection metadata in other "
+"[code]get_connection_*[/code] methods in the interval [code][0, "
+"get_connection_count() - 1][/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:36
+msgid ""
+"Returns the connection flags for the signal at [code]idx[/code]. See [enum "
+"Object.ConnectFlags] constants."
+msgstr ""
+
+#: doc/classes/SceneState.xml:45
+msgid "Returns the method connected to the signal at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:54
+msgid "Returns the name of the signal at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:63
+msgid ""
+"Returns the path to the node that owns the signal at [code]idx[/code], "
+"relative to the root node."
+msgstr ""
+
+#: doc/classes/SceneState.xml:72
+msgid ""
+"Returns the path to the node that owns the method connected to the signal at "
+"[code]idx[/code], relative to the root node."
+msgstr ""
+
+#: doc/classes/SceneState.xml:79
+msgid ""
+"Returns the number of nodes in the scene.\n"
+"The [code]idx[/code] argument used to query node data in other "
+"[code]get_node_*[/code] methods in the interval [code][0, get_node_count() - "
+"1][/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:89
+msgid ""
+"Returns the list of group names associated with the node at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:98
+msgid ""
+"Returns the node's index, which is its position relative to its siblings. "
+"This is only relevant and saved in scenes for cases where new nodes are "
+"added to an instanced or inherited scene among siblings from the base scene. "
+"Despite the name, this index is not related to the [code]idx[/code] argument "
+"used here and in other methods."
+msgstr ""
+
+#: doc/classes/SceneState.xml:107
+msgid ""
+"Returns a [PackedScene] for the node at [code]idx[/code] (i.e. the whole "
+"branch starting at this node, with its child nodes and resources), or "
+"[code]null[/code] if the node is not an instance."
+msgstr ""
+
+#: doc/classes/SceneState.xml:116
+msgid ""
+"Returns the path to the represented scene file if the node at [code]idx[/"
+"code] is an [InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:125
+msgid "Returns the name of the node at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:134
+msgid ""
+"Returns the path to the owner of the node at [code]idx[/code], relative to "
+"the root node."
+msgstr ""
+
+#: doc/classes/SceneState.xml:145
+msgid ""
+"Returns the path to the node at [code]idx[/code].\n"
+"If [code]for_parent[/code] is [code]true[/code], returns the path of the "
+"[code]idx[/code] node's parent instead."
+msgstr ""
+
+#: doc/classes/SceneState.xml:155
+msgid ""
+"Returns the number of exported or overridden properties for the node at "
+"[code]idx[/code].\n"
+"The [code]prop_idx[/code] argument used to query node property data in other "
+"[code]get_node_property_*[/code] methods in the interval [code][0, "
+"get_node_property_count() - 1][/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:167
+msgid ""
+"Returns the name of the property at [code]prop_idx[/code] for the node at "
+"[code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:178
+msgid ""
+"Returns the value of the property at [code]prop_idx[/code] for the node at "
+"[code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:187
+msgid "Returns the type of the node at [code]idx[/code]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:196
+msgid ""
+"Returns [code]true[/code] if the node at [code]idx[/code] is an "
+"[InstancePlaceholder]."
+msgstr ""
+
+#: doc/classes/SceneState.xml:202
+msgid ""
+"If passed to [method PackedScene.instance], blocks edits to the scene state."
+msgstr ""
+
+#: doc/classes/SceneState.xml:205
+msgid ""
+"If passed to [method PackedScene.instance], provides inherited scene "
+"resources to the local scene.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/SceneState.xml:209
+msgid ""
+"If passed to [method PackedScene.instance], provides local scene resources "
+"to the local scene. Only the main scene should receive the main edit state.\n"
+"[b]Note:[/b] Only available in editor builds."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:4
+msgid "Manages the game loop via a hierarchy of nodes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"[SceneTree] is the default [MainLoop] implementation used by scenes, and is "
+"thus in charge of the game loop."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"scene_tree.html"
+msgstr ""
+
+#: doc/classes/SceneTree.xml:13
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/viewports/"
+"multiple_resolutions.html"
+msgstr ""
+
+#: doc/classes/SceneTree.xml:24
+msgid "Calls [code]method[/code] on each member of the given group."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:37
+msgid ""
+"Calls [code]method[/code] on each member of the given group, respecting the "
+"given [enum GroupCallFlags]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:46
+msgid ""
+"Changes the running scene to the one at the given [code]path[/code], after "
+"loading it into a [PackedScene] and creating a new instance.\n"
+"Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the "
+"[code]path[/code] cannot be loaded into a [PackedScene], or [constant "
+"ERR_CANT_CREATE] if that scene cannot be instantiated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:56
+msgid ""
+"Changes the running scene to a new instance of the given [PackedScene].\n"
+"Returns [constant OK] on success or [constant ERR_CANT_CREATE] if the scene "
+"cannot be instantiated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:68
+msgid ""
+"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.\n"
+"Commonly used to create a one-shot delay timer as in the following example:\n"
+"[codeblock]\n"
+"func some_function():\n"
+" print(\"start\")\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(\"end\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/SceneTree.xml:82
+msgid ""
+"Returns the current frame number, i.e. the total frame count since the "
+"application started."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:89
+msgid ""
+"Returns the peer IDs of all connected peers of this [SceneTree]'s [member "
+"network_peer]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:96
+msgid "Returns the unique peer ID of this [SceneTree]'s [member network_peer]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:103
+msgid "Returns the number of nodes in this [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:112
+msgid "Returns a list of all nodes assigned to the given group."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:119
+msgid "Returns the sender's peer ID for the most recently received RPC call."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:128
+msgid "Returns [code]true[/code] if the given group exists."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:142
+msgid ""
+"Returns [code]true[/code] if this [SceneTree]'s [member network_peer] is in "
+"server mode (listening for connections)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:153
+msgid "Sends the given notification to all members of the [code]group[/code]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:166
+msgid ""
+"Sends the given notification to all members of the [code]group[/code], "
+"respecting the given [enum GroupCallFlags]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:175
+msgid ""
+"Queues the given object for deletion, delaying the call to [method Object."
+"free] to after the current frame."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:184
+msgid ""
+"Quits the application. 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."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:191
+msgid ""
+"Reloads the currently active scene.\n"
+"Returns [constant OK] on success, [constant ERR_UNCONFIGURED] if no [member "
+"current_scene] was defined yet, [constant ERR_CANT_OPEN] if [member "
+"current_scene] cannot be loaded into a [PackedScene], or [constant "
+"ERR_CANT_CREATE] if the scene cannot be instantiated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:201
+msgid ""
+"If [code]true[/code], the application automatically accepts quitting. "
+"Enabled by default.\n"
+"For mobile platforms, see [method set_quit_on_go_back]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:215
+msgid ""
+"Sets the given [code]property[/code] to [code]value[/code] on all members of "
+"the given group."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:230
+msgid ""
+"Sets the given [code]property[/code] to [code]value[/code] on all members of "
+"the given group, respecting the given [enum GroupCallFlags]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:239
+msgid ""
+"If [code]true[/code], the application quits automatically on going back (e."
+"g. on Android). Enabled by default.\n"
+"To handle 'Go Back' button when this option is disabled, use [constant "
+"DisplayServer.WINDOW_EVENT_GO_BACK_REQUEST]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:246
+msgid "The current scene."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:249
+msgid ""
+"If [code]true[/code], collision shapes will be visible when running the game "
+"from the editor for debugging purposes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:252
+msgid ""
+"If [code]true[/code], navigation polygons will be visible when running the "
+"game from the editor for debugging purposes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:255
+msgid "The root of the edited scene."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:258
+msgid "The default [MultiplayerAPI] instance for this [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:261
+msgid ""
+"If [code]true[/code] (default value), enables automatic polling of the "
+"[MultiplayerAPI] for this SceneTree during [signal idle_frame].\n"
+"If [code]false[/code], you need to manually call [method MultiplayerAPI."
+"poll] to process network packets and deliver RPCs/RSETs. This allows running "
+"RPCs/RSETs in a different loop (e.g. physics, thread, specific time step) "
+"and for manual [Mutex] protection when accessing the [MultiplayerAPI] from "
+"threads."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:265
+msgid ""
+"The peer object to handle the RPC system (effectively enabling networking "
+"when set). Depending on the peer itself, the [SceneTree] will become a "
+"network server (check with [method is_network_server]) and will set the root "
+"node's network mode to master, or it will become a regular peer with the "
+"root node set to puppet. All child nodes are set to inherit the network mode "
+"by default. Handling of networking-related events (connection, "
+"disconnection, new clients) is done by connecting to [SceneTree]'s signals."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:268
+msgid ""
+"If [code]true[/code], the [SceneTree] is paused. Doing so will have the "
+"following behavior:\n"
+"- 2D and 3D physics will be stopped.\n"
+"- [method Node._process], [method Node._physics_process] and [method Node."
+"_input] will not be called anymore in nodes."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:273
+msgid ""
+"If [code]true[/code], the [SceneTree]'s [member network_peer] refuses new "
+"incoming connections."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:276
+msgid "The [SceneTree]'s root [Window]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:282
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] successfully "
+"connected to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:287
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] fails to establish "
+"a connection to a server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:296
+msgid ""
+"Emitted when files are dragged from the OS file manager and dropped in the "
+"game window. The arguments are a list of file paths and the identifier of "
+"the screen where the drag originated."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:301
+msgid ""
+"Emitted immediately before [method Node._process] is called on every node in "
+"the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:308
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] connects with a "
+"new peer. ID is the peer ID of the new peer. Clients get notified when other "
+"clients connect to the same server. Upon connecting to a server, a client "
+"also receives this signal for the server (with ID being 1)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:315
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] disconnects from a "
+"peer. Clients get notified when other clients disconnect from the same "
+"server."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:322
+msgid "Emitted whenever a node is added to the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:329
+msgid ""
+"Emitted when a node's configuration changed. Only emitted in [code]tool[/"
+"code] mode."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:336
+msgid "Emitted whenever a node is removed from the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:343
+msgid "Emitted whenever a node is renamed."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:348
+msgid ""
+"Emitted immediately before [method Node._physics_process] is called on every "
+"node in the [SceneTree]."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:353
+msgid ""
+"Emitted whenever this [SceneTree]'s [member network_peer] disconnected from "
+"server. Only emitted on clients."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:358
+msgid ""
+"Emitted whenever the [SceneTree] hierarchy changed (children being moved or "
+"renamed, etc.)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:364
+msgid "Call a group with no flags (default)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:367
+msgid "Call a group in reverse scene order."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:370
+msgid "Call a group immediately (calls are normally made on idle)."
+msgstr ""
+
+#: doc/classes/SceneTree.xml:373
+msgid "Call a group only once even if the call is executed many times."
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:4
+msgid "One-shot timer."
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:7
+msgid ""
+"A one-shot timer managed by the scene tree, which emits [signal timeout] on "
+"completion. See also [method SceneTree.create_timer].\n"
+"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:\n"
+"[codeblock]\n"
+"func some_function():\n"
+" print(\"Timer started.\")\n"
+" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+" print(\"Timer ended.\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:22
+msgid "The time remaining."
+msgstr ""
+
+#: doc/classes/SceneTreeTimer.xml:28 doc/classes/Timer.xml:62
+msgid "Emitted when the timer reaches 0."
+msgstr ""
+
+#: doc/classes/Script.xml:4
+msgid "A class stored as a resource."
+msgstr ""
+
+#: doc/classes/Script.xml:7
+msgid ""
+"A class stored as a resource. A script extends the functionality of all "
+"objects that instance it.\n"
+"The [code]new[/code] method of a script subclass creates a new instance. "
+"[method Object.set_script] extends an existing object, if that object's "
+"class matches one of the script's base classes."
+msgstr ""
+
+#: doc/classes/Script.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/step_by_step/"
+"scripting.html"
+msgstr ""
+
+#: doc/classes/Script.xml:18
+msgid "Returns [code]true[/code] if the script can be instanced."
+msgstr ""
+
+#: doc/classes/Script.xml:25
+msgid "Returns the script directly inherited by this script."
+msgstr ""
+
+#: doc/classes/Script.xml:32
+msgid "Returns the script's base type."
+msgstr ""
+
+#: doc/classes/Script.xml:41
+msgid "Returns the default value of the specified property."
+msgstr ""
+
+#: doc/classes/Script.xml:48
+msgid "Returns a dictionary containing constant names and their values."
+msgstr ""
+
+#: doc/classes/Script.xml:55
+msgid "Returns the list of methods in this [Script]."
+msgstr ""
+
+#: doc/classes/Script.xml:62
+msgid "Returns the list of properties in this [Script]."
+msgstr ""
+
+#: doc/classes/Script.xml:69
+msgid "Returns the list of user signals defined in this [Script]."
+msgstr ""
+
+#: doc/classes/Script.xml:78
+msgid ""
+"Returns [code]true[/code] if the script, or a base class, defines a signal "
+"with the given name."
+msgstr ""
+
+#: doc/classes/Script.xml:85
+msgid "Returns [code]true[/code] if the script contains non-empty source code."
+msgstr ""
+
+#: doc/classes/Script.xml:94
+msgid ""
+"Returns [code]true[/code] if [code]base_object[/code] is an instance of this "
+"script."
+msgstr ""
+
+#: doc/classes/Script.xml:101
+msgid ""
+"Returns [code]true[/code] if the script is a tool script. A tool script can "
+"run in the editor."
+msgstr ""
+
+#: doc/classes/Script.xml:110
+msgid "Reloads the script's class implementation. Returns an error code."
+msgstr ""
+
+#: doc/classes/Script.xml:116
+msgid ""
+"The script source code or an empty string if source code is not available. "
+"When set, does not reload the class implementation automatically."
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:4
+msgid "The Editor's popup dialog for creating new [Script] files."
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:7
+msgid ""
+"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.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" dialog.config(\"Node\", \"res://new_node.gd\") # For in-engine types\n"
+" dialog.config(\"\\\"res://base_node.gd\\\"\", \"res://derived_node.gd\") "
+"# For script types\n"
+" dialog.popup_centered()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:30
+msgid "Prefills required fields to configure the ScriptCreateDialog for use."
+msgstr ""
+
+#: doc/classes/ScriptCreateDialog.xml:43
+msgid "Emitted when the user clicks the OK button."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:4
+msgid "Godot editor's script editor."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:39
+msgid "Returns a [Script] that is currently active in editor."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:56
+msgid ""
+"Returns an array with all [Script] objects which are currently open in "
+"editor."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:65
+msgid "Goes to the specified line in the current script."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:84
+msgid ""
+"Emitted when user changed active script. Argument is a freshly activated "
+"[Script]."
+msgstr ""
+
+#: doc/classes/ScriptEditor.xml:91
+msgid ""
+"Emitted when editor is about to close the active script. Argument is a "
+"[Script] that is going to be closed."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:4
+msgid "Base class for scroll bars."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:7
+msgid ""
+"Scrollbars are a [Range]-based [Control], that display a draggable area (the "
+"size of the page). Horizontal ([HScrollBar]) and Vertical ([VScrollBar]) "
+"versions are available."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:15
+msgid ""
+"Overrides the step used when clicking increment and decrement buttons or "
+"when using arrow keys when the [ScrollBar] is focused."
+msgstr ""
+
+#: doc/classes/ScrollBar.xml:23
+msgid "Emitted when the scrollbar is being scrolled."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:4
+msgid "A helper node for displaying scrollable elements such as lists."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:7
+msgid ""
+"A ScrollContainer node meant to contain a [Control] child.\n"
+"ScrollContainers will automatically create a scrollbar child ([HScrollBar], "
+"[VScrollBar], or both) when needed and will only draw the Control within the "
+"ScrollContainer area. Scrollbars will automatically be drawn at the right "
+"(for vertical) or bottom (for horizontal) and will enable dragging to move "
+"the viewable Control (and its children) within the ScrollContainer. "
+"Scrollbars will also automatically resize the grabber based on the [member "
+"Control.rect_min_size] of the Control relative to the ScrollContainer.\n"
+"Works great with a [Panel] control. You can set [code]EXPAND[/code] on the "
+"children's size flags, so they will upscale to the ScrollContainer's size if "
+"it's larger (scroll is invisible for the chosen dimension)."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:18
+msgid ""
+"Returns the horizontal scrollbar [HScrollBar] of this [ScrollContainer]."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:25
+msgid "Returns the vertical scrollbar [VScrollBar] of this [ScrollContainer]."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:31
+msgid ""
+"If [code]true[/code], the ScrollContainer will automatically scroll to "
+"focused children (including indirect children) to make sure they are fully "
+"visible."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:37 doc/classes/TextEdit.xml:441
+msgid "The current horizontal scroll value."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:40
+msgid "If [code]true[/code], enables horizontal scrolling."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:43 doc/classes/TextEdit.xml:444
+msgid "The current vertical scroll value."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:46
+msgid "If [code]true[/code], enables vertical scrolling."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:52
+msgid "Emitted when scrolling stops."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:57
+msgid "Emitted when scrolling is started."
+msgstr ""
+
+#: doc/classes/ScrollContainer.xml:65
+msgid "The background [StyleBox] of the [ScrollContainer]."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:4
+msgid "Segment shape for 2D collisions."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:7
+msgid ""
+"Segment shape for 2D collisions. Consists of two points, [code]a[/code] and "
+"[code]b[/code]."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:15
+msgid "The segment's first point position."
+msgstr ""
+
+#: doc/classes/SegmentShape2D.xml:18
+msgid "The segment's second point position."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:4
+msgid "A synchronization semaphore."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:7
+msgid ""
+"A synchronization semaphore which can be used to synchronize multiple "
+"[Thread]s. Initialized to zero on creation. Be careful to avoid deadlocks. "
+"For a binary version, see [Mutex]."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:17
+msgid "Lowers the [Semaphore], allowing one more thread in."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:24
+msgid ""
+"Like [method wait], but won't block, so if the value is zero, fails "
+"immediately and returns [constant ERR_BUSY]. If non-zero, it returns "
+"[constant OK] to report success."
+msgstr ""
+
+#: doc/classes/Semaphore.xml:31
+msgid "Waits for the [Semaphore], if its value is zero, blocks until non-zero."
+msgstr ""
+
+#: doc/classes/Separator.xml:4
+msgid "Base class for separators."
+msgstr ""
+
+#: doc/classes/Separator.xml:7
+msgid ""
+"Separator is a [Control] used for separating other controls. It's purely a "
+"visual decoration. Horizontal ([HSeparator]) and Vertical ([VSeparator]) "
+"versions are available."
+msgstr ""
+
+#: doc/classes/Shader.xml:4
+msgid "A custom shader program."
+msgstr ""
+
+#: doc/classes/Shader.xml:7
+msgid ""
+"This class allows you to define a custom shader program that can be used by "
+"a [ShaderMaterial]. Shaders allow you to write your own custom behavior for "
+"rendering objects or updating particle information. For a detailed "
+"explanation and usage, please see the tutorials linked below."
+msgstr ""
+
+#: doc/classes/Shader.xml:10 doc/classes/ShaderMaterial.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/shading/index.html"
+msgstr ""
+
+#: doc/classes/Shader.xml:11
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/shading/your_first_shader/"
+"what_are_shaders.html"
+msgstr ""
+
+#: doc/classes/Shader.xml:20
+msgid ""
+"Returns the texture that is set as default for the specified parameter.\n"
+"[b]Note:[/b] [code]param[/code] must match the name of the uniform in the "
+"code exactly."
+msgstr ""
+
+#: doc/classes/Shader.xml:28
+msgid ""
+"Returns the shader mode for the shader, either [constant MODE_CANVAS_ITEM], "
+"[constant MODE_SPATIAL] or [constant MODE_PARTICLES]."
+msgstr ""
+
+#: doc/classes/Shader.xml:37
+msgid ""
+"Returns [code]true[/code] if the shader has this param defined as a uniform "
+"in its code.\n"
+"[b]Note:[/b] [code]param[/code] must match the name of the uniform in the "
+"code exactly."
+msgstr ""
+
+#: doc/classes/Shader.xml:49
+msgid ""
+"Sets the default texture to be used with a texture uniform. The default is "
+"used if a texture is not set in the [ShaderMaterial].\n"
+"[b]Note:[/b] [code]param[/code] must match the name of the uniform in the "
+"code exactly."
+msgstr ""
+
+#: doc/classes/Shader.xml:56
+msgid ""
+"Returns the shader's code as the user has written it, not the full generated "
+"code used internally."
+msgstr ""
+
+#: doc/classes/Shader.xml:61
+msgid "Mode used to draw all 3D objects."
+msgstr ""
+
+#: doc/classes/Shader.xml:64
+msgid "Mode used to draw all 2D objects."
+msgstr ""
+
+#: doc/classes/Shader.xml:67
+msgid ""
+"Mode used to calculate particle information on a per-particle basis. Not "
+"used for drawing."
+msgstr ""
+
+#: doc/classes/Shader.xml:70
+msgid ""
+"Mode used for drawing skies. Only works with shaders attached to [Sky] "
+"objects."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:4
+msgid "A material that uses a custom [Shader] program."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:7
+msgid ""
+"A material that uses a custom [Shader] program to render either items to "
+"screen or process particles. You can create multiple materials for the same "
+"shader but configure different values for the uniforms defined in the shader."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:19
+msgid ""
+"Returns the current value set for this material of a uniform in the shader."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:28
+msgid ""
+"Returns [code]true[/code] if the property identified by [code]name[/code] "
+"can be reverted to a default value."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:37
+msgid ""
+"Returns the default value of the material property with given [code]name[/"
+"code]."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:48
+msgid ""
+"Changes the value set for this material of a uniform in the shader. [b]Note:"
+"[/b] [code]param[/code] must match the name of the uniform in the code "
+"exactly."
+msgstr ""
+
+#: doc/classes/ShaderMaterial.xml:54
+msgid "The [Shader] program used to render this material."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:4
+msgid "Base class for all 2D shapes."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:7
+msgid "Base class for all 2D shapes. All 2D shape types inherit from this."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:23
+msgid ""
+"Returns [code]true[/code] if this shape is colliding with another.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), and the transformation matrix of that shape "
+"([code]shape_xform[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:37
+msgid ""
+"Returns a list of the points where this shape touches another. If there are "
+"no collisions the list is empty.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), and the transformation matrix of that shape "
+"([code]shape_xform[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:55
+msgid ""
+"Returns whether this shape would collide with another, if a given movement "
+"was applied.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the movement to test on this shape "
+"([code]local_motion[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), the transformation matrix of that shape "
+"([code]shape_xform[/code]), and the movement to test onto the other object "
+"([code]shape_motion[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:73
+msgid ""
+"Returns a list of the points where this shape would touch another, if a "
+"given movement was applied. If there are no collisions the list is empty.\n"
+"This method needs the transformation matrix for this shape "
+"([code]local_xform[/code]), the movement to test on this shape "
+"([code]local_motion[/code]), the shape to check collisions with "
+"([code]with_shape[/code]), the transformation matrix of that shape "
+"([code]shape_xform[/code]), and the movement to test onto the other object "
+"([code]shape_motion[/code])."
+msgstr ""
+
+#: doc/classes/Shape2D.xml:80
+msgid "The shape's custom solver bias."
+msgstr ""
+
+#: doc/classes/Shape3D.xml:4
+msgid "Base class for all 3D shape resources."
+msgstr ""
+
+#: doc/classes/Shape3D.xml:7
+msgid ""
+"Base class for all 3D shape resources. Nodes that inherit from this can be "
+"used as shapes for a [PhysicsBody3D] or [Area3D] objects."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:4
+msgid "A shortcut for binding input."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:7
+msgid ""
+"A shortcut for binding input.\n"
+"Shortcuts are commonly used for interacting with a [Control] element from a "
+"[InputEvent]."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:17
+msgid "Returns the shortcut's [InputEvent] as a [String]."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:26
+msgid ""
+"Returns [code]true[/code] if the shortcut's [InputEvent] equals [code]event[/"
+"code]."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:33
+msgid "If [code]true[/code], this shortcut is valid."
+msgstr ""
+
+#: doc/classes/ShortCut.xml:39
+msgid ""
+"The shortcut's [InputEvent].\n"
+"Generally the [InputEvent] is a keyboard key, though it can be any "
+"[InputEvent]."
+msgstr ""
+
+#: doc/classes/Signal.xml:4
+msgid "Class representing a signal defined in an object."
+msgstr ""
+
+#: doc/classes/Signal.xml:19
+msgid ""
+"Creates a new signal named [code]signal_name[/code] in the given object."
+msgstr ""
+
+#: doc/classes/Signal.xml:32
+msgid ""
+"Connects this signal to the specified [Callable], optionally providing binds "
+"and connection flags."
+msgstr ""
+
+#: doc/classes/Signal.xml:41
+msgid "Disconnects this signal from the specified [Callable]."
+msgstr ""
+
+#: doc/classes/Signal.xml:48
+msgid "Emits this signal to all connected objects."
+msgstr ""
+
+#: doc/classes/Signal.xml:55
+msgid "Returns the list of [Callable]s connected to this signal."
+msgstr ""
+
+#: doc/classes/Signal.xml:62
+msgid "Returns the name of this signal."
+msgstr ""
+
+#: doc/classes/Signal.xml:69
+msgid "Returns the object emitting this signal."
+msgstr ""
+
+#: doc/classes/Signal.xml:76
+msgid ""
+"Returns the ID of the object emitting this signal (see [method Object."
+"get_instance_id])."
+msgstr ""
+
+#: doc/classes/Signal.xml:85
+msgid ""
+"Returns [code]true[/code] if the specified [Callable] is connected to this "
+"signal."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:4
+msgid "Skeleton for 2D characters and animated objects."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:7
+msgid ""
+"Skeleton2D parents a hierarchy of [Bone2D] objects. It is a requirement of "
+"[Bone2D]. Skeleton2D holds a reference to the rest pose of its children and "
+"acts as a single point of access to its bones."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html"
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:19
+msgid ""
+"Returns a [Bone2D] from the node hierarchy parented by Skeleton2D. The "
+"object to return is identified by the parameter [code]idx[/code]. Bones are "
+"indexed by descending the node hierarchy from top to bottom, adding the "
+"children of each branch before moving to the next sibling."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:26
+msgid ""
+"Returns the number of [Bone2D] nodes in the node hierarchy parented by "
+"Skeleton2D."
+msgstr ""
+
+#: doc/classes/Skeleton2D.xml:33
+msgid "Returns the [RID] of a Skeleton2D instance."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:4
+msgid "Skeleton for characters and animated objects."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:7
+msgid ""
+"Skeleton3D provides a hierarchical interface for managing bones, including "
+"pose, rest and animation (see [Animation]). It can also use ragdoll "
+"physics.\n"
+"The overall transform of a bone with respect to the skeleton is determined "
+"by the following hierarchical order: rest pose, custom pose and pose.\n"
+"Note that \"global pose\" below refers to the overall transform of the bone "
+"with respect to skeleton, so it not the actual global/world transform of the "
+"bone."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:20
+msgid ""
+"Adds a bone, with name [code]name[/code]. [method get_bone_count] will "
+"become the bone index."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:31 doc/classes/Skeleton3D.xml:124
+#: doc/classes/Skeleton3D.xml:255
+msgid "[i]Deprecated soon.[/i]"
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:38
+msgid "Clear all the bones in this skeleton."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:53
+msgid "Returns the bone index that matches [code]name[/code] as its name."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:60
+msgid "Returns the amount of bones in the skeleton."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:69
+msgid ""
+"Returns the custom pose of the specified bone. Custom pose is applied on top "
+"of the rest pose."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:78
+msgid ""
+"Returns the overall transform of the specified bone, with respect to the "
+"skeleton. Being relative to the skeleton frame, this is not the actual "
+"\"global\" transform of the bone."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:87
+msgid "Returns the name of the bone at index [code]index[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:96
+msgid ""
+"Returns the bone index which is the parent of the bone at [code]bone_idx[/"
+"code]. If -1, then bone has no parent.\n"
+"[b]Note:[/b] The parent bone returned will always be less than "
+"[code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:106
+msgid ""
+"Returns the pose transform of the specified bone. Pose is applied on top of "
+"the custom pose, which is applied on top the rest pose."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:115
+msgid "Returns the rest transform for a bone [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:221
+msgid ""
+"Sets the bone index [code]parent_idx[/code] as the parent of the bone at "
+"[code]bone_idx[/code]. If -1, then bone has no parent.\n"
+"[b]Note:[/b] [code]parent_idx[/code] must be less than [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:233
+msgid "Returns the pose transform for bone [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Skeleton3D.xml:244
+msgid "Sets the rest transform for bone [code]bone_idx[/code]."
+msgstr ""
+
+#: doc/classes/Sky.xml:4
+msgid "Background that uses a [Material] to draw a sky."
+msgstr ""
+
+#: doc/classes/Sky.xml:7
+msgid ""
+"The [Sky] class uses a [Material] to draw the background and update the "
+"reflection/radiance cubemaps."
+msgstr ""
+
+#: doc/classes/Sky.xml:15
+msgid ""
+"Sets the method for generating the radiance map from the sky. The radiance "
+"map is a cubemap with increasingly blurry versions of the sky corresponding "
+"to different levels of roughness. Radiance maps can be expensive to "
+"calculate. See [enum ProcessMode] for options."
+msgstr ""
+
+#: doc/classes/Sky.xml:18
+msgid ""
+"The [Sky]'s radiance map size. The higher the radiance map size, the more "
+"detailed the lighting from the [Sky] will be.\n"
+"See [enum RadianceSize] constants for values.\n"
+"[b]Note:[/b] Some hardware will have trouble with higher radiance sizes, "
+"especially [constant RADIANCE_SIZE_512] and above. Only use such high values "
+"on high-end hardware."
+msgstr ""
+
+#: doc/classes/Sky.xml:23
+msgid ""
+"[Material] used to draw the background. Can be [PanoramaSkyMaterial], "
+"[ProceduralSkyMaterial], [PhysicalSkyMaterial], or even a [ShaderMaterial] "
+"if you want to use your own custom shader."
+msgstr ""
+
+#: doc/classes/Sky.xml:28
+msgid "Radiance texture size is 32×32 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:31
+msgid "Radiance texture size is 64×64 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:34
+msgid "Radiance texture size is 128×128 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:37
+msgid "Radiance texture size is 256×256 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:40
+msgid "Radiance texture size is 512×512 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:43
+msgid "Radiance texture size is 1024×1024 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:46
+msgid "Radiance texture size is 2048×2048 pixels."
+msgstr ""
+
+#: doc/classes/Sky.xml:49
+msgid "Represents the size of the [enum RadianceSize] enum."
+msgstr ""
+
+#: doc/classes/Sky.xml:52
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/Sky.xml:55
+msgid ""
+"Uses the fast filtering algorithm to process the radiance map. In general "
+"this results in lower quality, but substantially faster run times.\n"
+"[b]Note:[/b] The fast filtering algorithm is limited to 256x256 cubemaps, so "
+"[member radiance_size] must be set to [constant RADIANCE_SIZE_256]."
+msgstr ""
+
+#: doc/classes/Slider.xml:4 doc/classes/Slider.xml:7
+msgid "Base class for GUI sliders."
+msgstr ""
+
+#: doc/classes/Slider.xml:15
+msgid ""
+"If [code]true[/code], the slider can be interacted with. If [code]false[/"
+"code], the value can be changed only by code."
+msgstr ""
+
+#: doc/classes/Slider.xml:19
+msgid "If [code]true[/code], the value can be changed using the mouse wheel."
+msgstr ""
+
+#: doc/classes/Slider.xml:23
+msgid ""
+"Number of ticks displayed on the slider, including border ticks. Ticks are "
+"uniformly-distributed value markers."
+msgstr ""
+
+#: doc/classes/Slider.xml:26
+msgid ""
+"If [code]true[/code], the slider will display ticks for minimum and maximum "
+"values."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:4
+msgid "Piston kind of slider between two bodies in 3D."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:7
+msgid "Slides across the X axis of the pivot object."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:33
+msgid ""
+"The amount of damping of the rotation when the limit is surpassed.\n"
+"A lower damping value allows a rotation initiated by body A to travel to "
+"body B slower."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:40
+msgid ""
+"The amount of restitution of the rotation when the limit is surpassed.\n"
+"Does not affect damping."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:44
+msgid ""
+"A factor applied to the all rotation once the limit is surpassed.\n"
+"Makes all rotation slower when between 0 and 1."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:57 doc/classes/SliderJoint3D.xml:152
+msgid "A factor applied to the all rotation in the limits."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:66 doc/classes/SliderJoint3D.xml:161
+msgid ""
+"A factor applied to the all rotation across axes orthogonal to the slider."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:69
+msgid ""
+"The amount of damping that happens once the limit defined by [member "
+"linear_limit/lower_distance] and [member linear_limit/upper_distance] is "
+"surpassed."
+msgstr ""
+
+#: doc/classes/SliderJoint3D.xml:75
+msgid ""
+"The amount of restitution once the limits are surpassed. The lower, the more "
+"velocity-energy gets lost."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:4
+msgid "A soft mesh physics body."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:7
+msgid ""
+"A deformable physics body. Used to create elastic or deformable objects such "
+"as cloth, rubber, or other flexible materials."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html"
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:83
+msgid ""
+"The physics layers this SoftBody3D is in.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:88
+msgid "The physics layers this SoftBody3D scans for collisions."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:97
+msgid ""
+"[NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:104
+msgid "If [code]true[/code], the [SoftBody3D] will respond to [RayCast3D]s."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:107
+msgid ""
+"Increasing this value will improve the resulting simulation, but can affect "
+"performance. Use with care."
+msgstr ""
+
+#: doc/classes/SoftBody3D.xml:110
+msgid "The SoftBody3D's mass."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:4 doc/classes/SphereMesh.xml:7
+msgid "Class representing a spherical [PrimitiveMesh]."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:15
+msgid "Full height of the sphere."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:18
+msgid ""
+"If [code]true[/code], a hemisphere is created rather than a full sphere.\n"
+"[b]Note:[/b] To get a regular hemisphere, the height and radius of the "
+"sphere must be equal."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:22
+msgid "Number of radial segments on the sphere."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:25
+msgid "Radius of sphere."
+msgstr ""
+
+#: doc/classes/SphereMesh.xml:28
+msgid "Number of segments along the height of the sphere."
+msgstr ""
+
+#: doc/classes/SphereShape3D.xml:4
+msgid "Sphere shape for 3D collisions."
+msgstr ""
+
+#: doc/classes/SphereShape3D.xml:7
+msgid ""
+"Sphere shape for 3D collisions, which can be set into a [PhysicsBody3D] or "
+"[Area3D]. This shape is useful for modeling sphere-like 3D objects."
+msgstr ""
+
+#: doc/classes/SphereShape3D.xml:15
+msgid "The sphere's radius. The shape's diameter is double the radius."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:4
+msgid "Numerical input text field."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:7
+msgid ""
+"SpinBox is a numerical input text field. It allows entering integers and "
+"floats.\n"
+"[b]Example:[/b]\n"
+"[codeblock]\n"
+"var spin_box = SpinBox.new()\n"
+"add_child(spin_box)\n"
+"var line_edit = spin_box.get_line_edit()\n"
+"line_edit.context_menu_enabled = false\n"
+"spin_box.align = LineEdit.ALIGN_RIGHT\n"
+"[/codeblock]\n"
+"The above code will create a [SpinBox], disable context menu on it and set "
+"the text alignment to right.\n"
+"See [Range] class for more options over the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:26
+msgid "Applies the current value of this [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:33
+msgid ""
+"Returns the [LineEdit] instance from this [SpinBox]. You can use it to "
+"access properties and methods of [LineEdit]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:39
+msgid "Sets the text alignment of the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:42
+msgid ""
+"If [code]true[/code], the [SpinBox] will be editable. Otherwise, it will be "
+"read only."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:45
+msgid ""
+"Adds the specified [code]prefix[/code] string before the numerical value of "
+"the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:48
+msgid ""
+"Adds the specified [code]prefix[/code] string after the numerical value of "
+"the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SpinBox.xml:55
+msgid "Sets a custom [Texture2D] for up and down arrows of the [SpinBox]."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:4
+msgid "Container for splitting and adjusting."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:7
+msgid ""
+"Container for splitting two [Control]s vertically or horizontally, with a "
+"grabber that allows adjusting the split offset or ratio."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:16
+msgid ""
+"Clamps the [member split_offset] value to not go outside the currently "
+"possible minimal and maximum values."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:22
+msgid ""
+"If [code]true[/code], the area of the first [Control] will be collapsed and "
+"the dragger will be disabled."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:25
+msgid ""
+"Determines the dragger's visibility. See [enum DraggerVisibility] for "
+"details."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:28
+msgid ""
+"The initial offset of the splitting between the two [Control]s, with "
+"[code]0[/code] being at the end of the first [Control]."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:36
+msgid "Emitted when the dragger is dragged by user."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:42
+msgid "The split dragger is visible when the cursor hovers it."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:45
+msgid "The split dragger is never visible."
+msgstr ""
+
+#: doc/classes/SplitContainer.xml:48
+msgid "The split dragger is never visible and its space collapsed."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:4
+msgid "A spotlight, such as a reflector spotlight or a lantern."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:7
+msgid ""
+"A Spotlight is a type of [Light3D] node that emits lights in a specific "
+"direction, in the shape of a cone. The light is attenuated through the "
+"distance. This attenuation can be configured by changing the energy, radius "
+"and attenuation parameters of [Light3D]."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:16
+msgid "The spotlight's angle in degrees."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:19
+msgid "The spotlight's angular attenuation curve."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:22
+msgid "The spotlight's light energy attenuation curve."
+msgstr ""
+
+#: doc/classes/SpotLight3D.xml:25
+msgid "The maximal range that can be reached by the spotlight."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:4
+msgid "A helper node, mostly used in 3rd person cameras."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:7
+msgid ""
+"The SpringArm3D node is a node that casts a ray (or collision shape) along "
+"its z axis and moves all its direct children to the collision point, minus a "
+"margin.\n"
+"The most common use case for this is to make a 3rd person camera that reacts "
+"to collisions in the environment.\n"
+"The SpringArm3D will either cast a ray, or if a shape is given, it will cast "
+"the shape in the direction of its z axis.\n"
+"If you use the SpringArm3D as a camera controller for your player, you might "
+"need to exclude the player's collider from the SpringArm3D's collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:21
+msgid ""
+"Adds the [PhysicsBody3D] object with the given [RID] to the list of "
+"[PhysicsBody3D] objects excluded from the collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:28
+msgid ""
+"Clears the list of [PhysicsBody3D] objects excluded from the collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:35
+msgid ""
+"Returns the proportion between the current arm length (after checking for "
+"collisions) and the [member spring_length]. Ranges from 0 to 1."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:44
+msgid ""
+"Removes the given [RID] from the list of [PhysicsBody3D] objects excluded "
+"from the collision check."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:50
+msgid "The layers against which the collision check shall be done."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:53
+msgid ""
+"When the collision check is made, a candidate length for the SpringArm3D is "
+"given.\n"
+"The margin is then subtracted to this length and the translation is applied "
+"to the child objects of the SpringArm3D.\n"
+"This margin is useful for when the SpringArm3D has a [Camera3D] as a child "
+"node: without the margin, the [Camera3D] would be placed on the exact point "
+"of collision, while with the margin the [Camera3D] would be placed close to "
+"the point of collision."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:58
+msgid ""
+"The [Shape3D] to use for the SpringArm3D.\n"
+"When the shape is set, the SpringArm3D will cast the [Shape3D] on its z axis "
+"instead of performing a ray cast."
+msgstr ""
+
+#: doc/classes/SpringArm3D.xml:62
+msgid ""
+"The maximum extent of the SpringArm3D. This is used as a length for both the "
+"ray and the shape cast used internally to calculate the desired position of "
+"the SpringArm3D's child nodes.\n"
+"To know more about how to perform a shape cast or a ray cast, please consult "
+"the [PhysicsDirectSpaceState3D] documentation."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:4
+msgid "General-purpose sprite node."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:7
+msgid ""
+"A node that displays a 2D texture. The texture displayed can be a region "
+"from a larger atlas texture, or a frame from a sprite sheet animation."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:16
+msgid ""
+"Returns a [Rect2] representing the Sprite2D's boundary in local coordinates. "
+"Can be used to detect if the Sprite2D was clicked. Example:\n"
+"[codeblock]\n"
+"func _input(event):\n"
+" if event is InputEventMouseButton and event.pressed and event."
+"button_index == BUTTON_LEFT:\n"
+" if get_rect().has_point(to_local(event.position)):\n"
+" print(\"A click!\")\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:31
+msgid ""
+"Returns [code]true[/code], if the pixel at the given position is opaque and "
+"[code]false[/code] in other case.\n"
+"[b]Note:[/b] It also returns [code]false[/code], if the sprite's texture is "
+"[code]null[/code] or if the given position is invalid."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:38
+msgid "If [code]true[/code], texture is centered."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:47 doc/classes/Sprite3D.xml:16
+msgid ""
+"Current frame to display from sprite sheet. [member vframes] or [member "
+"hframes] must be greater than 1."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:50 doc/classes/Sprite3D.xml:19
+msgid ""
+"Coordinates of the frame to display from sprite sheet. This is as an alias "
+"for the [member frame] property. [member vframes] or [member hframes] must "
+"be greater than 1."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:53 doc/classes/Sprite3D.xml:22
+msgid "The number of columns in the sprite sheet."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:56
+msgid "The normal map gives depth to the Sprite2D."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:62
+msgid ""
+"If [code]true[/code], texture is cut from a larger atlas texture. See "
+"[member region_rect]."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:65
+msgid "If [code]true[/code], the outermost pixels get blurred out."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:68 doc/classes/Sprite3D.xml:28
+msgid ""
+"The region of the atlas texture to display. [member region_enabled] must be "
+"[code]true[/code]."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:71
+msgid "Strength of the specular light effect of this [Sprite2D]."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:77
+msgid "The specular map is used for more control on the shininess effect."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:80 doc/classes/Sprite3D.xml:31
+msgid "[Texture2D] object to draw."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:83 doc/classes/Sprite3D.xml:34
+msgid "The number of rows in the sprite sheet."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:89 doc/classes/Sprite3D.xml:40
+msgid "Emitted when the [member frame] changes."
+msgstr ""
+
+#: doc/classes/Sprite2D.xml:94
+msgid "Emitted when the [member texture] changes."
+msgstr ""
+
+#: doc/classes/Sprite3D.xml:4
+msgid "2D sprite node in a 3D world."
+msgstr ""
+
+#: doc/classes/Sprite3D.xml:7
+msgid ""
+"A node that displays a 2D texture in a 3D environment. The texture displayed "
+"can be a region from a larger atlas texture, or a frame from a sprite sheet "
+"animation.\n"
+"[b]Note:[/b] There are [url=https://github.com/godotengine/godot/"
+"issues/20855]known performance issues[/url] when using [Sprite3D]. Consider "
+"using a [MeshInstance3D] with a [QuadMesh] as the mesh instead. You can "
+"still have billboarding by enabling billboard properties in the QuadMesh's "
+"[StandardMaterial3D]."
+msgstr ""
+
+#: doc/classes/Sprite3D.xml:25
+msgid ""
+"If [code]true[/code], texture will be cut from a larger atlas texture. See "
+"[member region_rect]."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:4
+msgid "2D sprite node in 3D environment."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:7
+msgid "A node that displays 2D texture information in a 3D environment."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:31
+msgid "Returns the rectangle representing this sprite."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:42
+msgid "If [code]true[/code], the specified flag will be enabled."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:50
+msgid "The direction in which the front of the texture faces."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:58
+msgid ""
+"If [code]true[/code], texture can be seen from the back as well, if "
+"[code]false[/code], it is invisible when looking at it from behind."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:67
+msgid ""
+"A color value that gets multiplied on, could be used for mood-coloring or to "
+"simulate the color of light."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:73
+msgid ""
+"The objects visibility on a scale from [code]0[/code] fully invisible to "
+"[code]1[/code] fully visible."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:76
+msgid "The size of one pixel's width on the sprite to scale it in 3D."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:79
+msgid ""
+"If [code]true[/code], the [Light3D] in the [Environment] has effects on the "
+"sprite."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:82
+msgid ""
+"If [code]true[/code], the texture's transparency and the opacity are used to "
+"make those parts of the sprite invisible."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:87
+msgid ""
+"If set, the texture's transparency and the opacity are used to make those "
+"parts of the sprite invisible."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:90
+msgid "If set, lights in the environment affect the sprite."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:93
+msgid ""
+"If set, texture can be seen from the back as well, if not, it is invisible "
+"when looking at it from behind."
+msgstr ""
+
+#: doc/classes/SpriteBase3D.xml:96
+msgid "Represents the size of the [enum DrawFlags] enum."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:4
+msgid "Sprite frame library for AnimatedSprite2D."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:7
+msgid ""
+"Sprite frame library for [AnimatedSprite2D]. Contains frames and animation "
+"data for playback."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:18
+msgid "Adds a new animation to the library."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:31
+msgid "Adds a frame to the given animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:40
+msgid "Removes all frames from the given animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:47
+msgid "Removes all animations. A \"default\" animation will be created."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:56
+msgid "If [code]true[/code], the given animation will loop."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:63
+msgid ""
+"Returns an array containing the names associated to each animation. Values "
+"are placed in alphabetical order."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:72 doc/classes/SpriteFrames.xml:154
+msgid "The animation's speed in frames per second."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:83
+msgid "Returns the animation's selected frame."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:92
+msgid "Returns the number of frames in the animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:101
+msgid "If [code]true[/code], the named animation exists."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:110
+msgid "Removes the given animation."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:121
+msgid "Removes the animation's selected frame."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:132
+msgid "Changes the animation's name to [code]newname[/code]."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:143
+msgid "If [code]true[/code], the animation will loop."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:167
+msgid "Sets the texture of the given frame."
+msgstr ""
+
+#: doc/classes/SpriteFrames.xml:173
+msgid "Compatibility property, always equals to an empty array."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:4
+msgid "Static body for 2D physics."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:7
+msgid ""
+"Static body for 2D physics. A StaticBody2D is a body that is not intended to "
+"move. It is ideal for implementing objects in the environment, such as walls "
+"or platforms.\n"
+"Additionally, a constant linear or angular velocity can be set for the "
+"static body, which will affect colliding bodies as if it were moving (for "
+"example, a conveyor belt)."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:16
+msgid ""
+"The body's constant angular velocity. This does not rotate the body, but "
+"affects colliding bodies, as if it were rotating."
+msgstr ""
+
+#: doc/classes/StaticBody2D.xml:19
+msgid ""
+"The body's constant linear velocity. This does not move the body, but "
+"affects colliding bodies, as if it were moving."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:4
+msgid "Static body for 3D physics."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:7
+msgid ""
+"Static body for 3D physics. A static body is a simple body that is not "
+"intended to move. In contrast to [RigidBody3D], they don't consume any CPU "
+"resources as long as they don't move.\n"
+"Additionally, a constant linear or angular velocity can be set for the "
+"static body, so even if it doesn't move, it affects other bodies as if it "
+"was moving (this is useful for simulating conveyor belts or conveyor wheels)."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:16
+msgid ""
+"The body's constant angular velocity. This does not rotate the body, but "
+"affects other bodies that touch it, as if it was in a state of rotation."
+msgstr ""
+
+#: doc/classes/StaticBody3D.xml:19
+msgid ""
+"The body's constant linear velocity. This does not move the body, but "
+"affects other bodies that touch it, as if it was in a state of movement."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:4
+msgid "Abstraction and base class for stream-based protocols."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:7
+msgid ""
+"StreamPeer is an abstraction and base class for stream-based protocols (such "
+"as TCP or UNIX sockets). It provides an API for sending and receiving data "
+"through streams as raw data or strings."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:16
+msgid "Gets a signed 16-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:23
+msgid "Gets a signed 32-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:30
+msgid "Gets a signed 64-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:37
+msgid "Gets a signed byte from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:44
+msgid "Returns the amount of bytes this [StreamPeer] has available."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:53
+msgid ""
+"Returns a chunk data with the received bytes. The amount of bytes to be "
+"received can be requested in the [code]bytes[/code] argument. If not enough "
+"bytes are available, the function will block until the desired amount is "
+"received. This function returns two values, an [enum @GlobalScope.Error] "
+"code and a data array."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:60
+msgid "Gets a double-precision float from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:67
+msgid "Gets a single-precision float from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:76
+msgid ""
+"Returns a chunk data with the received bytes. The amount of bytes to be "
+"received can be requested in the \"bytes\" argument. If not enough bytes are "
+"available, the function will return how many were actually received. This "
+"function returns two values, an [enum @GlobalScope.Error] code, and a data "
+"array."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:85
+msgid ""
+"Gets a string with byte-length [code]bytes[/code] from the stream. If "
+"[code]bytes[/code] is negative (default) the length will be read from the "
+"stream using the reverse process of [method put_string]."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:92
+msgid "Gets an unsigned 16-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:99
+msgid "Gets an unsigned 32-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:106
+msgid "Gets an unsigned 64-bit value from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:113
+msgid "Gets an unsigned byte from the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:122
+msgid ""
+"Gets an UTF-8 string with byte-length [code]bytes[/code] from the stream "
+"(this decodes the string sent as UTF-8). If [code]bytes[/code] is negative "
+"(default) the length will be read from the stream using the reverse process "
+"of [method put_utf8_string]."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:131
+msgid ""
+"Gets a Variant from the stream. If [code]allow_objects[/code] is [code]true[/"
+"code], decoding objects is allowed.\n"
+"[b]Warning:[/b] Deserialized objects can contain code which gets executed. "
+"Do not use this option if the serialized object comes from untrusted sources "
+"to avoid potential security threats such as remote code execution."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:141
+msgid "Puts a signed 16-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:150
+msgid "Puts a signed 32-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:159
+msgid "Puts a signed 64-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:168
+msgid "Puts a signed byte into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:177
+msgid ""
+"Sends a chunk of data through the connection, blocking if necessary until "
+"the data is done sending. This function returns an [enum @GlobalScope.Error] "
+"code."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:186
+msgid "Puts a double-precision float into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:195
+msgid "Puts a single-precision float into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:204
+msgid ""
+"Sends a chunk of data through the connection. If all the data could not be "
+"sent at once, only part of it will. This function returns two values, an "
+"[enum @GlobalScope.Error] code and an integer, describing how much data was "
+"actually sent."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:213
+msgid ""
+"Puts a zero-terminated ASCII string into the stream prepended by a 32-bit "
+"unsigned integer representing its size.\n"
+"Note: To put an ASCII string without prepending its size, you can use "
+"[method put_data]:\n"
+"[codeblock]\n"
+"put_data(\"Hello world\".to_ascii())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:226
+msgid "Puts an unsigned 16-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:235
+msgid "Puts an unsigned 32-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:244
+msgid "Puts an unsigned 64-bit value into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:253
+msgid "Puts an unsigned byte into the stream."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:262
+msgid ""
+"Puts a zero-terminated UTF-8 string into the stream prepended by a 32 bits "
+"unsigned integer representing its size.\n"
+"Note: To put an UTF-8 string without prepending its size, you can use "
+"[method put_data]:\n"
+"[codeblock]\n"
+"put_data(\"Hello world\".to_utf8())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:277
+msgid ""
+"Puts a Variant into the stream. If [code]full_objects[/code] is [code]true[/"
+"code] encoding objects is allowed (and can potentially include code)."
+msgstr ""
+
+#: doc/classes/StreamPeer.xml:283
+msgid ""
+"If [code]true[/code], this [StreamPeer] will using big-endian format for "
+"encoding and decoding."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:4
+msgid "SSL stream peer."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:7
+msgid ""
+"SSL stream peer. This object can be used to connect to an SSL server or "
+"accept a single SSL client connection."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:25
+msgid ""
+"Accepts a peer connection as a server using the given [code]private_key[/"
+"code] and providing the given [code]certificate[/code] to the client. You "
+"can pass the optional [code]chain[/code] parameter to provide additional CA "
+"chain information along with the certificate."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:40
+msgid ""
+"Connects to a peer using an underlying [StreamPeer] [code]stream[/code]. If "
+"[code]validate_certs[/code] is [code]true[/code], [StreamPeerSSL] will "
+"validate that the certificate presented by the peer matches the "
+"[code]for_hostname[/code].\n"
+"[b]Note:[/b] Specifying a custom [code]valid_certificate[/code] is not "
+"supported in HTML5 exports due to browsers restrictions."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:48 doc/classes/StreamPeerTCP.xml:27
+msgid "Disconnects from host."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:62
+msgid ""
+"Poll the connection to check for incoming bytes. Call this right before "
+"[method StreamPeer.get_available_bytes] for it to work properly."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:72
+msgid "A status representing a [StreamPeerSSL] that is disconnected."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:75
+msgid "A status representing a [StreamPeerSSL] during handshaking."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:78
+msgid "A status representing a [StreamPeerSSL] that is connected to a host."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:81
+msgid "A status representing a [StreamPeerSSL] in error state."
+msgstr ""
+
+#: doc/classes/StreamPeerSSL.xml:84
+msgid ""
+"An error status that shows a mismatch in the SSL certificate domain "
+"presented by the host and the domain requested for validation."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:4
+msgid "TCP stream peer."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:7
+msgid ""
+"TCP stream peer. This object can be used to connect to TCP servers, or also "
+"is returned by a TCP server."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:20
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:34
+msgid "Returns the IP of this peer."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:41
+msgid "Returns the port of this peer."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:48
+msgid "Returns the status of the connection, see [enum Status]."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:55
+msgid ""
+"Returns [code]true[/code] if this peer is currently connected to a host, "
+"[code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:64
+msgid ""
+"Disables Nagle's algorithm to improve latency for small packets.\n"
+"[b]Note:[/b] For applications that send large packets or need to transfer a "
+"lot of data, this can decrease the total available bandwidth."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:71
+msgid ""
+"The initial status of the [StreamPeerTCP]. This is also the status after "
+"disconnecting."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:74
+msgid "A status representing a [StreamPeerTCP] that is connecting to a host."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:77
+msgid "A status representing a [StreamPeerTCP] that is connected to a host."
+msgstr ""
+
+#: doc/classes/StreamPeerTCP.xml:80
+msgid "A status representing a [StreamPeerTCP] in error state."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:4
+msgid "A [code].stex[/code] texture."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:7
+msgid "A texture that is loaded from a [code].stex[/code] file."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:18
+msgid "Loads the texture from the given path."
+msgstr ""
+
+#: doc/classes/StreamTexture.xml:24
+msgid "The StreamTexture's file path to a [code].stex[/code] file."
+msgstr ""
+
+#: doc/classes/String.xml:4
+msgid "Built-in string class."
+msgstr ""
+
+#: doc/classes/String.xml:7
+msgid ""
+"This is the built-in string class (and the one used by GDScript). It "
+"supports Unicode and provides all necessary means for string handling. "
+"Strings are reference counted and use a copy-on-write approach, so passing "
+"them around is cheap in resources."
+msgstr ""
+
+#: doc/classes/String.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/"
+"gdscript_format_string.html"
+msgstr ""
+
+#: doc/classes/String.xml:19
+msgid "Constructs a new String from the given [bool]."
+msgstr ""
+
+#: doc/classes/String.xml:28
+msgid "Constructs a new String from the given [int]."
+msgstr ""
+
+#: doc/classes/String.xml:37
+msgid "Constructs a new String from the given [float]."
+msgstr ""
+
+#: doc/classes/String.xml:46
+msgid "Constructs a new String from the given [Vector2]."
+msgstr ""
+
+#: doc/classes/String.xml:55
+msgid "Constructs a new String from the given [Vector2i]."
+msgstr ""
+
+#: doc/classes/String.xml:64
+msgid "Constructs a new String from the given [Rect2]."
+msgstr ""
+
+#: doc/classes/String.xml:73
+msgid "Constructs a new String from the given [Rect2i]."
+msgstr ""
+
+#: doc/classes/String.xml:82
+msgid "Constructs a new String from the given [Vector3]."
+msgstr ""
+
+#: doc/classes/String.xml:91
+msgid "Constructs a new String from the given [Vector3i]."
+msgstr ""
+
+#: doc/classes/String.xml:100
+msgid "Constructs a new String from the given [Transform2D]."
+msgstr ""
+
+#: doc/classes/String.xml:109
+msgid "Constructs a new String from the given [Plane]."
+msgstr ""
+
+#: doc/classes/String.xml:118
+msgid "Constructs a new String from the given [Quat]."
+msgstr ""
+
+#: doc/classes/String.xml:127
+msgid "Constructs a new String from the given [AABB]."
+msgstr ""
+
+#: doc/classes/String.xml:136
+msgid "Constructs a new String from the given [Basis]."
+msgstr ""
+
+#: doc/classes/String.xml:145
+msgid "Constructs a new String from the given [Transform]."
+msgstr ""
+
+#: doc/classes/String.xml:154
+msgid "Constructs a new String from the given [Color]."
+msgstr ""
+
+#: doc/classes/String.xml:163
+msgid "Constructs a new String from the given [StringName]."
+msgstr ""
+
+#: doc/classes/String.xml:172
+msgid "Constructs a new String from the given [NodePath]."
+msgstr ""
+
+#: doc/classes/String.xml:181
+msgid "Constructs a new String from the given [RID]."
+msgstr ""
+
+#: doc/classes/String.xml:190
+msgid "Constructs a new String from the given [Callable]."
+msgstr ""
+
+#: doc/classes/String.xml:199
+msgid "Constructs a new String from the given [Signal]."
+msgstr ""
+
+#: doc/classes/String.xml:208
+msgid "Constructs a new String from the given [Dictionary]."
+msgstr ""
+
+#: doc/classes/String.xml:217
+msgid "Constructs a new String from the given [Array]."
+msgstr ""
+
+#: doc/classes/String.xml:226
+msgid "Constructs a new String from the given [PackedByteArray]."
+msgstr ""
+
+#: doc/classes/String.xml:235
+msgid "Constructs a new String from the given [PackedInt32Array]."
+msgstr ""
+
+#: doc/classes/String.xml:244
+msgid "Constructs a new String from the given [PackedInt64Array]."
+msgstr ""
+
+#: doc/classes/String.xml:253
+msgid "Constructs a new String from the given [PackedFloat32Array]."
+msgstr ""
+
+#: doc/classes/String.xml:262
+msgid "Constructs a new String from the given [PackedFloat64Array]."
+msgstr ""
+
+#: doc/classes/String.xml:271
+msgid "Constructs a new String from the given [PackedStringArray]."
+msgstr ""
+
+#: doc/classes/String.xml:280
+msgid "Constructs a new String from the given [PackedVector2Array]."
+msgstr ""
+
+#: doc/classes/String.xml:289
+msgid "Constructs a new String from the given [PackedVector3Array]."
+msgstr ""
+
+#: doc/classes/String.xml:298
+msgid "Constructs a new String from the given [PackedColorArray]."
+msgstr ""
+
+#: doc/classes/String.xml:307
+msgid "Returns [code]true[/code] if the string begins with the given string."
+msgstr ""
+
+#: doc/classes/String.xml:314
+msgid "Returns the bigrams (pairs of consecutive letters) of this string."
+msgstr ""
+
+#: doc/classes/String.xml:321
+msgid ""
+"Returns a copy of the string with special characters escaped using the C "
+"language standard."
+msgstr ""
+
+#: doc/classes/String.xml:328
+msgid ""
+"Returns a copy of the string with escaped characters replaced by their "
+"meanings according to the C language standard."
+msgstr ""
+
+#: doc/classes/String.xml:335
+msgid ""
+"Changes the case of some letters. Replaces underscores with spaces, converts "
+"all letters to lowercase, then capitalizes first and every letter following "
+"the space character. For [code]capitalize camelCase mixed_with_underscores[/"
+"code], it will return [code]Capitalize Camelcase Mixed With Underscores[/"
+"code]."
+msgstr ""
+
+#: doc/classes/String.xml:344
+msgid ""
+"Performs a case-sensitive comparison to another string. Returns [code]-1[/"
+"code] if less than, [code]+1[/code] if greater than, or [code]0[/code] if "
+"equal."
+msgstr ""
+
+#: doc/classes/String.xml:357
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:370
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:377
+msgid ""
+"Returns a copy of the string with indentation (leading tabs and spaces) "
+"removed."
+msgstr ""
+
+#: doc/classes/String.xml:384
+msgid "Returns [code]true[/code] if the string is empty."
+msgstr ""
+
+#: doc/classes/String.xml:393
+msgid "Returns [code]true[/code] if the string ends with the given string."
+msgstr ""
+
+#: doc/classes/String.xml:404
+msgid ""
+"Erases [code]chars[/code] characters from the string starting from "
+"[code]position[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:415
+msgid ""
+"Finds the first occurrence of a substring. Returns the starting position of "
+"the substring or -1 if not found. Optionally, the initial search index can "
+"be passed."
+msgstr ""
+
+#: doc/classes/String.xml:424
+msgid ""
+"Finds the last occurrence of a substring. Returns the starting position of "
+"the substring or -1 if not found."
+msgstr ""
+
+#: doc/classes/String.xml:435
+msgid ""
+"Finds the first occurrence of a substring, ignoring case. Returns the "
+"starting position of the substring or -1 if not found. Optionally, the "
+"initial search index can be passed."
+msgstr ""
+
+#: doc/classes/String.xml:446
+msgid ""
+"Formats the string by replacing all occurrences of [code]placeholder[/code] "
+"with [code]values[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:453
+msgid "If the string is a valid file path, returns the base directory name."
+msgstr ""
+
+#: doc/classes/String.xml:460
+msgid ""
+"If the string is a valid file path, returns the full file path without the "
+"extension."
+msgstr ""
+
+#: doc/classes/String.xml:467
+msgid "If the string is a valid file path, returns the extension."
+msgstr ""
+
+#: doc/classes/String.xml:474
+msgid "If the string is a valid file path, returns the filename."
+msgstr ""
+
+#: doc/classes/String.xml:481
+msgid "Hashes the string and returns a 32-bit integer."
+msgstr ""
+
+#: doc/classes/String.xml:488
+msgid ""
+"Converts a string containing a hexadecimal number into an integer. "
+"Hexadecimal strings are expected to be prefixed with \"[code]0x[/code]\" "
+"otherwise [code]0[/code] is returned.\n"
+"[codeblock]\n"
+"print(\"0xff\".hex_to_int()) # Print \"255\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:498
+msgid ""
+"Escapes (encodes) a string to URL friendly format. Also referred to as 'URL "
+"encode'.\n"
+"[codeblock]\n"
+"print(\"https://example.org/?escaped=\" + \"Godot Engine:'docs'\"."
+"http_escape())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:508
+msgid ""
+"Unescapes (decodes) a string in URL encoded format. Also referred to as 'URL "
+"decode'.\n"
+"[codeblock]\n"
+"print(\"https://example.org/?escaped=\" + \"Godot%20Engine%3A%27docs%27\"."
+"http_unescape())\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:520
+msgid ""
+"Converts [code]size[/code] represented as number of bytes to human-readable "
+"format using internationalized set of data size units, namely: B, KiB, MiB, "
+"GiB, TiB, PiB, EiB. Note that the next smallest unit is picked automatically "
+"to hold at most 1024 units.\n"
+"[codeblock]\n"
+"var bytes = 133790307\n"
+"var size = String.humanize_size(bytes)\n"
+"print(size) # prints \"127.5 MiB\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:536
+msgid ""
+"Returns a copy of the string with the substring [code]what[/code] inserted "
+"at the given position."
+msgstr ""
+
+#: doc/classes/String.xml:543
+msgid ""
+"If the string is a path to a file or directory, returns [code]true[/code] if "
+"the path is absolute."
+msgstr ""
+
+#: doc/classes/String.xml:550
+msgid ""
+"If the string is a path to a file or directory, returns [code]true[/code] if "
+"the path is relative."
+msgstr ""
+
+#: doc/classes/String.xml:559
+msgid ""
+"Returns [code]true[/code] if this string is a subsequence of the given "
+"string."
+msgstr ""
+
+#: doc/classes/String.xml:568
+msgid ""
+"Returns [code]true[/code] if this string is a subsequence of the given "
+"string, without considering case."
+msgstr ""
+
+#: doc/classes/String.xml:575
+msgid ""
+"Returns [code]true[/code] if this string is free from characters that aren't "
+"allowed in file names, those being:\n"
+"[code]: / \\ ? * \" | % < >[/code]"
+msgstr ""
+
+#: doc/classes/String.xml:583
+msgid "Returns [code]true[/code] if this string contains a valid float."
+msgstr ""
+
+#: doc/classes/String.xml:592
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/String.xml:599
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/String.xml:606
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:613
+msgid "Returns [code]true[/code] if this string contains a valid integer."
+msgstr ""
+
+#: doc/classes/String.xml:620
+msgid "Returns [code]true[/code] if this string contains a valid IP address."
+msgstr ""
+
+#: doc/classes/String.xml:627
+msgid ""
+"Returns a copy of the string with special characters escaped using the JSON "
+"standard."
+msgstr ""
+
+#: doc/classes/String.xml:636
+msgid "Returns a number of characters from the left of the string."
+msgstr ""
+
+#: doc/classes/String.xml:643
+msgid "Returns the string's amount of characters."
+msgstr ""
+
+#: doc/classes/String.xml:652
+msgid "Returns a copy of the string with characters removed from the left."
+msgstr ""
+
+#: doc/classes/String.xml:661
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/String.xml:670
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/String.xml:677
+msgid "Returns the MD5 hash of the string as an array of bytes."
+msgstr ""
+
+#: doc/classes/String.xml:684
+msgid "Returns the MD5 hash of the string as a string."
+msgstr ""
+
+#: doc/classes/String.xml:693
+msgid ""
+"Performs a case-insensitive comparison to another string. Returns [code]-1[/"
+"code] if less than, [code]+1[/code] if greater than, or [code]0[/code] if "
+"equal."
+msgstr ""
+
+#: doc/classes/String.xml:702
+msgid "Returns the character code at position [code]at[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:711
+msgid ""
+"Formats a number to have an exact number of [code]digits[/code] after the "
+"decimal point."
+msgstr ""
+
+#: doc/classes/String.xml:720
+msgid ""
+"Formats a number to have an exact number of [code]digits[/code] before the "
+"decimal point."
+msgstr ""
+
+#: doc/classes/String.xml:727
+msgid "Decode a percent-encoded string. See [method percent_encode]."
+msgstr ""
+
+#: doc/classes/String.xml:734
+msgid ""
+"Percent-encodes a string. Encodes parameters in a URL when sending a HTTP "
+"GET request (and bodies of form-urlencoded POST requests)."
+msgstr ""
+
+#: doc/classes/String.xml:743
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/String.xml:752
+msgid ""
+"Returns original string repeated a number of times. The number of "
+"repetitions is given by the argument."
+msgstr ""
+
+#: doc/classes/String.xml:763
+msgid ""
+"Replaces occurrences of a case-sensitive substring with the given one inside "
+"the string."
+msgstr ""
+
+#: doc/classes/String.xml:774
+msgid ""
+"Replaces occurrences of a case-insensitive substring with the given one "
+"inside the string."
+msgstr ""
+
+#: doc/classes/String.xml:785
+msgid ""
+"Performs a case-sensitive search for a substring, but starts from the end of "
+"the string instead of the beginning."
+msgstr ""
+
+#: doc/classes/String.xml:796
+msgid ""
+"Performs a case-insensitive search for a substring, but starts from the end "
+"of the string instead of the beginning."
+msgstr ""
+
+#: doc/classes/String.xml:805
+msgid "Returns the right side of the string from a given position."
+msgstr ""
+
+#: doc/classes/String.xml:818
+msgid ""
+"Splits the string by a [code]delimiter[/code] string and returns an array of "
+"the substrings, starting from right.\n"
+"The splits in the returned array are sorted in the same order as the "
+"original string, from left to right.\n"
+"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].\n"
+"Example:\n"
+"[codeblock]\n"
+"var some_string = \"One,Two,Three,Four\"\n"
+"var some_array = some_string.rsplit(\",\", true, 1)\n"
+"print(some_array.size()) # Prints 2\n"
+"print(some_array[0]) # Prints \"Four\"\n"
+"print(some_array[1]) # Prints \"Three,Two,One\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:837
+msgid "Returns a copy of the string with characters removed from the right."
+msgstr ""
+
+#: doc/classes/String.xml:844
+msgid "Returns the SHA-1 hash of the string as an array of bytes."
+msgstr ""
+
+#: doc/classes/String.xml:851
+msgid "Returns the SHA-1 hash of the string as a string."
+msgstr ""
+
+#: doc/classes/String.xml:858
+msgid "Returns the SHA-256 hash of the string as an array of bytes."
+msgstr ""
+
+#: doc/classes/String.xml:865
+msgid "Returns the SHA-256 hash of the string as a string."
+msgstr ""
+
+#: doc/classes/String.xml:874
+msgid ""
+"Returns the similarity index of the text compared to this string. 1 means "
+"totally similar and 0 means totally dissimilar."
+msgstr ""
+
+#: doc/classes/String.xml:887
+msgid ""
+"Splits the string by a [code]delimiter[/code] string and returns an array of "
+"the substrings.\n"
+"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 0 means that "
+"all items are split.\n"
+"Example:\n"
+"[codeblock]\n"
+"var some_string = \"One,Two,Three,Four\"\n"
+"var some_array = some_string.split(\",\", true, 1)\n"
+"print(some_array.size()) # Prints 2\n"
+"print(some_array[0]) # Prints \"One\"\n"
+"print(some_array[1]) # Prints \"Two,Three,Four\"\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/String.xml:907
+msgid ""
+"Splits the string in floats by using a delimiter string and returns an array "
+"of the substrings.\n"
+"For example, [code]\"1,2.5,3\"[/code] will return [code][1,2.5,3][/code] if "
+"split by [code]\",\"[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:919
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/String.xml:926
+msgid ""
+"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 (< "
+"32), such as tabulation ([code]\\t[/code] in C) and newline ([code]\\n[/"
+"code] and [code]\\r[/code]) characters, but not spaces."
+msgstr ""
+
+#: doc/classes/String.xml:937
+msgid ""
+"Returns part of the string from the position [code]from[/code] with length "
+"[code]len[/code]. Argument [code]len[/code] is optional and using -1 will "
+"return remaining characters from given position."
+msgstr ""
+
+#: doc/classes/String.xml:944
+msgid ""
+"Converts the String (which is a character array) to [PackedByteArray] (which "
+"is an array of bytes). The conversion is faster compared to [method "
+"to_utf8], as this method assumes that all the characters in the String are "
+"ASCII characters."
+msgstr ""
+
+#: doc/classes/String.xml:951
+msgid ""
+"Converts a string containing a decimal number into a [code]float[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:958
+msgid ""
+"Converts a string containing an integer number into an [code]int[/code]."
+msgstr ""
+
+#: doc/classes/String.xml:965
+msgid "Returns the string converted to lowercase."
+msgstr ""
+
+#: doc/classes/String.xml:972
+msgid "Returns the string converted to uppercase."
+msgstr ""
+
+#: doc/classes/String.xml:979
+msgid ""
+"Converts the String (which is an array of characters) to [PackedByteArray] "
+"(which is an array of bytes). The conversion is a bit slower than [method "
+"to_ascii], but supports all UTF-8 characters. Therefore, you should prefer "
+"this function over [method to_ascii]."
+msgstr ""
+
+#: doc/classes/String.xml:988
+msgid ""
+"Removes a given string from the start if it starts with it or leaves the "
+"string unchanged."
+msgstr ""
+
+#: doc/classes/String.xml:997
+msgid ""
+"Removes a given string from the end if it ends with it or leaves the string "
+"unchanged."
+msgstr ""
+
+#: doc/classes/String.xml:1004
+msgid ""
+"Returns a copy of the string with special characters escaped using the XML "
+"standard."
+msgstr ""
+
+#: doc/classes/String.xml:1011
+msgid ""
+"Returns a copy of the string with escaped characters replaced by their "
+"meanings according to the XML standard."
+msgstr ""
+
+#: doc/classes/StringName.xml:4
+msgid "An optimized string type for unique names."
+msgstr ""
+
+#: doc/classes/StringName.xml:7
+msgid ""
+"[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."
+msgstr ""
+
+#: doc/classes/StringName.xml:18
+msgid "Creates a new [StringName] from the given [String]."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:4
+msgid "Base class for drawing stylized boxes for the UI."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:7
+msgid ""
+"StyleBox is [Resource] that provides an abstract base class for drawing "
+"stylized boxes for the UI. StyleBoxes are used for drawing the styles of "
+"buttons, line edit backgrounds, tree backgrounds, etc. and also for testing "
+"a transparency mask for pointer signals. If mask test fails on a StyleBox "
+"assigned as mask to a control, clicks and motion signals will go through it "
+"to the one below."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:20
+msgid ""
+"Draws this stylebox using a [CanvasItem] with given [RID].\n"
+"You can get a [RID] value using [method Object.get_instance_id] on a "
+"[CanvasItem]-derived node."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:28
+msgid "Returns the size of this [StyleBox] without the margins."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:35
+msgid ""
+"Returns the [CanvasItem] that handles its [constant CanvasItem."
+"NOTIFICATION_DRAW] or [method CanvasItem._draw] callback at this moment."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:44
+msgid "Returns the default value of the specified [enum Margin]."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:53
+msgid ""
+"Returns the content margin offset for the specified [enum Margin].\n"
+"Positive values reduce size inwards, unlike [Control]'s margin values."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:61
+msgid "Returns the minimum size that this stylebox can be shrunk to."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:68
+msgid ""
+"Returns the \"offset\" of a stylebox. This helper function returns a value "
+"equivalent to [code]Vector2(style.get_margin(MARGIN_LEFT), style."
+"get_margin(MARGIN_TOP))[/code]."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:79
+msgid ""
+"Sets the default value of the specified [enum Margin] to given [code]offset[/"
+"code] in pixels."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:90
+msgid "Test a position in a rectangle, return whether it passes the mask test."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:96
+msgid ""
+"The bottom margin for the contents of this style box. Increasing this value "
+"reduces the space available to the contents from the bottom.\n"
+"If this value is negative, it is ignored and a child-specific margin is used "
+"instead. For example for [StyleBoxFlat] the border thickness (if any) is "
+"used instead.\n"
+"It is up to the code using this style box to decide what these contents are: "
+"for example, a [Button] respects this content margin for the textual "
+"contents of the button.\n"
+"[method get_margin] should be used to fetch this value as consumer instead "
+"of reading these properties directly. This is because it correctly respects "
+"negative values and the fallback mentioned above."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:102
+msgid ""
+"The left margin for the contents of this style box.Increasing this value "
+"reduces the space available to the contents from the left.\n"
+"Refer to [member content_margin_bottom] for extra considerations."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:106
+msgid ""
+"The right margin for the contents of this style box. Increasing this value "
+"reduces the space available to the contents from the right.\n"
+"Refer to [member content_margin_bottom] for extra considerations."
+msgstr ""
+
+#: doc/classes/StyleBox.xml:110
+msgid ""
+"The top margin for the contents of this style box. Increasing this value "
+"reduces the space available to the contents from the top.\n"
+"Refer to [member content_margin_bottom] for extra considerations."
+msgstr ""
+
+#: doc/classes/StyleBoxEmpty.xml:4
+msgid "Empty stylebox (does not display anything)."
+msgstr ""
+
+#: doc/classes/StyleBoxEmpty.xml:7
+msgid "Empty stylebox (really does not display anything)."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:4
+msgid ""
+"Customizable [StyleBox] with a given set of parameters (no texture required)."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:7
+msgid ""
+"This [StyleBox] can be used to achieve all kinds of looks without the need "
+"of a texture. Those properties are customizable:\n"
+"- Color\n"
+"- Border width (individual width for each border)\n"
+"- Rounded corners (individual radius for each corner)\n"
+"- Shadow (with blur and offset)\n"
+"Setting corner radius to high values is allowed. As soon as corners would "
+"overlap, the stylebox will switch to a relative system. Example:\n"
+"[codeblock]\n"
+"height = 30\n"
+"corner_radius_top_left = 50\n"
+"corner_radius_bottom_left = 100\n"
+"[/codeblock]\n"
+"The relative system now would take the 1:2 ratio of the two left corners to "
+"calculate the actual corner width. Both corners added will [b]never[/b] be "
+"more than the height. Result:\n"
+"[codeblock]\n"
+"corner_radius_top_left: 10\n"
+"corner_radius_bottom_left: 20\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:33
+msgid ""
+"Returns the given [code]margin[/code]'s border width. See [enum Margin] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:40
+msgid "Returns the smallest border width out of all four borders."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:49
+msgid ""
+"Returns the given [code]corner[/code]'s radius. See [enum Corner] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:58 doc/classes/StyleBoxTexture.xml:18
+msgid ""
+"Returns the size of the given [code]margin[/code]'s expand margin. See [enum "
+"Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:69
+msgid ""
+"Sets the border width to [code]width[/code] pixels for the given "
+"[code]margin[/code]. See [enum Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:78
+msgid "Sets the border width to [code]width[/code] pixels for all margins."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:89
+msgid ""
+"Sets the corner radius to [code]radius[/code] pixels for the given "
+"[code]corner[/code]. See [enum Corner] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:98
+msgid "Sets the corner radius to [code]radius[/code] pixels for all corners."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:113
+msgid ""
+"Sets the corner radius for each corner to [code]radius_top_left[/code], "
+"[code]radius_top_right[/code], [code]radius_bottom_right[/code], and "
+"[code]radius_bottom_left[/code] pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:124 doc/classes/StyleBoxTexture.xml:62
+msgid ""
+"Sets the expand margin to [code]size[/code] pixels for the given "
+"[code]margin[/code]. See [enum Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:133 doc/classes/StyleBoxTexture.xml:36
+msgid "Sets the expand margin to [code]size[/code] pixels for all margins."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:148 doc/classes/StyleBoxTexture.xml:51
+msgid ""
+"Sets the expand margin for each margin to [code]size_left[/code], "
+"[code]size_top[/code], [code]size_right[/code], and [code]size_bottom[/code] "
+"pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:154
+msgid ""
+"Antialiasing draws a small ring around the edges, which fades to "
+"transparency. As a result, edges look much smoother. This is only noticeable "
+"when using rounded corners."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:157
+msgid ""
+"This changes the size of the faded ring. Higher values can be used to "
+"achieve a \"blurry\" effect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:160
+msgid "The background color of the stylebox."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:163
+msgid "If [code]true[/code], the border will fade into the background color."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:166
+msgid "Sets the color of the border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:169
+msgid "Border width for the bottom border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:172
+msgid "Border width for the left border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:175
+msgid "Border width for the right border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:178
+msgid "Border width for the top border."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:181
+msgid ""
+"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.\n"
+"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.\n"
+"A corner detail of [code]1[/code] will result in chamfered corners instead "
+"of rounded corners, which is useful for some artistic effects."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:186
+msgid ""
+"The bottom-left corner's radius. If [code]0[/code], the corner is not "
+"rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:189
+msgid ""
+"The bottom-right corner's radius. If [code]0[/code], the corner is not "
+"rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:192
+msgid ""
+"The top-left corner's radius. If [code]0[/code], the corner is not rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:195
+msgid ""
+"The top-right corner's radius. If [code]0[/code], the corner is not rounded."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:198
+msgid "Toggles drawing of the inner part of the stylebox."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:201
+msgid ""
+"Expands the stylebox outside of the control rect on the bottom edge. Useful "
+"in combination with [member border_width_bottom] to draw a border outside "
+"the control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:204
+msgid ""
+"Expands the stylebox outside of the control rect on the left edge. Useful in "
+"combination with [member border_width_left] to draw a border outside the "
+"control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:207
+msgid ""
+"Expands the stylebox outside of the control rect on the right edge. Useful "
+"in combination with [member border_width_right] to draw a border outside the "
+"control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:210
+msgid ""
+"Expands the stylebox outside of the control rect on the top edge. Useful in "
+"combination with [member border_width_top] to draw a border outside the "
+"control rect."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:213
+msgid ""
+"The color of the shadow. This has no effect if [member shadow_size] is lower "
+"than 1."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:216
+msgid ""
+"The shadow offset in pixels. Adjusts the position of the shadow relatively "
+"to the stylebox."
+msgstr ""
+
+#: doc/classes/StyleBoxFlat.xml:219
+msgid "The shadow size in pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:4
+msgid "[StyleBox] that displays a single line."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:7
+msgid ""
+"[StyleBox] that displays a single line of a given color and thickness. It "
+"can be used to draw things like separators."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:15
+msgid "The line's color."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:18
+msgid ""
+"The number of pixels the line will extend before the [StyleBoxLine]'s "
+"bounds. If set to a negative value, the line will begin inside the "
+"[StyleBoxLine]'s bounds."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:21
+msgid ""
+"The number of pixels the line will extend past the [StyleBoxLine]'s bounds. "
+"If set to a negative value, the line will end inside the [StyleBoxLine]'s "
+"bounds."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:24
+msgid "The line's thickness in pixels."
+msgstr ""
+
+#: doc/classes/StyleBoxLine.xml:27
+msgid ""
+"If [code]true[/code], the line will be vertical. If [code]false[/code], the "
+"line will be horizontal."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:4
+msgid "Texture-based nine-patch [StyleBox]."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:7
+msgid ""
+"Texture-based nine-patch [StyleBox], in a way similar to [NinePatchRect]. "
+"This stylebox performs a 3×3 scaling of a texture, where only the center "
+"cell is fully stretched. This makes it possible to design bordered styles "
+"regardless of the stylebox's size."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:27
+msgid ""
+"Returns the size of the given [code]margin[/code]. See [enum Margin] for "
+"possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:73
+msgid ""
+"Sets the margin to [code]size[/code] pixels for the given [code]margin[/"
+"code]. See [enum Margin] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:79
+msgid ""
+"Controls how the stylebox's texture will be stretched or tiled horizontally. "
+"See [enum AxisStretchMode] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:82
+msgid ""
+"Controls how the stylebox's texture will be stretched or tiled vertically. "
+"See [enum AxisStretchMode] for possible values."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:85
+msgid ""
+"If [code]true[/code], the nine-patch texture's center tile will be drawn."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:88
+msgid ""
+"Expands the bottom margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:91
+msgid ""
+"Expands the left margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:94
+msgid ""
+"Expands the right margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:97
+msgid ""
+"Expands the top margin of this style box when drawing, causing it to be "
+"drawn larger than requested."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:100
+msgid ""
+"Increases the bottom margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the bottom border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_bottom] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:105
+msgid ""
+"Increases the left margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the left border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_left] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:110
+msgid ""
+"Increases the right margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the right border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_right] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:115
+msgid ""
+"Increases the top margin of the 3×3 texture box.\n"
+"A higher value means more of the source texture is considered to be part of "
+"the top border of the 3×3 box.\n"
+"This is also the value used as fallback for [member StyleBox."
+"content_margin_top] if it is negative."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:120
+msgid "Modulates the color of the texture when this style box is drawn."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:123
+msgid "The normal map to use when drawing this style box."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:126
+msgid ""
+"Species a sub-region of the texture to use.\n"
+"This is equivalent to first wrapping the texture in an [AtlasTexture] with "
+"the same region."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:130
+msgid "The texture to use when drawing this style box."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:136
+msgid "Emitted when the stylebox's texture is changed."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:142
+msgid ""
+"Stretch the stylebox's texture. This results in visible distortion unless "
+"the texture size matches the stylebox's size perfectly."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:145
+msgid ""
+"Repeats the stylebox's texture to match the stylebox's size according to the "
+"nine-patch system."
+msgstr ""
+
+#: doc/classes/StyleBoxTexture.xml:148
+msgid ""
+"Repeats the stylebox's texture to match the stylebox's size according to the "
+"nine-patch system. Unlike [constant AXIS_STRETCH_MODE_TILE], the texture may "
+"be slightly stretched to make the nine-patch texture tile seamlessly."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:13
+msgid "If [code]true[/code], the sub-viewport will be used in AR/VR process."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:16
+msgid "The clear mode when the sub-viewport is used as a render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:19
+msgid "The update mode when the sub-viewport is used as a render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:22
+msgid "The width and height of the sub-viewport."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:25
+msgid ""
+"The 2D size override of the sub-viewport. If either the width or height is "
+"[code]0[/code], the override is disabled."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:28
+msgid "If [code]true[/code], the 2D size override affects stretch as well."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:33
+msgid "Do not update the render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:36
+msgid ""
+"Update the render target once, then switch to [constant UPDATE_DISABLED]."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:39
+msgid ""
+"Update the render target only when it is visible. This is the default value."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:42
+msgid "Update the render target only when the its parent is visible."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:45
+msgid "Always update the render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:48
+msgid "Always clear the render target before drawing."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:51
+msgid "Never clear the render target."
+msgstr ""
+
+#: doc/classes/SubViewport.xml:54
+msgid ""
+"Clear the render target next frame, then switch to [constant "
+"CLEAR_MODE_NEVER]."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:4
+msgid "Control for holding [SubViewport]s."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:7
+msgid ""
+"A [Container] node that holds a [SubViewport], automatically setting its "
+"size."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:15
+msgid ""
+"If [code]true[/code], the sub-viewport will be scaled to the control's size."
+msgstr ""
+
+#: doc/classes/SubViewportContainer.xml:18
+msgid ""
+"Divides the sub-viewport's effective resolution by this value while "
+"preserving its scale. This can be used to speed up rendering.\n"
+"For example, a 1280×720 sub-viewport with [member stretch_shrink] set to "
+"[code]2[/code] will be rendered at 640×360 while occupying the same size in "
+"the container.\n"
+"[b]Note:[/b] [member stretch] must be [code]true[/code] for this property to "
+"work."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:4
+msgid "Helper tool to create geometry."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:7
+msgid ""
+"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:\n"
+"[codeblock]\n"
+"var st = SurfaceTool.new()\n"
+"st.begin(Mesh.PRIMITIVE_TRIANGLES)\n"
+"st.add_color(Color(1, 0, 0))\n"
+"st.add_uv(Vector2(0, 0))\n"
+"st.add_vertex(Vector3(0, 0, 0))\n"
+"[/codeblock]\n"
+"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 add_uv] or [method add_color], then the last values would be "
+"used.\n"
+"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.\n"
+"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."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:28
+msgid ""
+"Adds an array of bones for the next vertex to use. [code]bones[/code] must "
+"contain 4 integers."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:37
+msgid "Specifies a [Color] for the next vertex to use."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:46
+msgid ""
+"Adds an index to index array if you are using indexed vertices. Does not "
+"need to be called before adding vertices."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:55
+msgid "Specifies a normal for the next vertex to use."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:64
+msgid ""
+"Specifies whether the current vertex (if using only vertex arrays) or "
+"current index (if also using index arrays) should use smooth normals for "
+"normal calculation."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:73
+msgid "Specifies a tangent for the next vertex to use."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:92
+msgid ""
+"Inserts a triangle fan made of array data into [Mesh] being constructed.\n"
+"Requires the primitive type be set to [constant Mesh.PRIMITIVE_TRIANGLES]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:102
+msgid "Specifies a set of UV coordinates to use for the next vertex."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:111
+msgid ""
+"Specifies an optional second set of UV coordinates to use for the next "
+"vertex."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:120
+msgid ""
+"Specifies the position of current vertex. Should be called after specifying "
+"other vertex properties (e.g. Color, UV)."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:129
+msgid ""
+"Specifies weight values for next vertex to use. [code]weights[/code] must "
+"contain 4 values."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:142
+msgid ""
+"Append vertices from a given [Mesh] surface onto the current vertex array "
+"with specified [Transform]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:151
+msgid ""
+"Called before adding any vertices. Takes the primitive type as an argument "
+"(e.g. [constant Mesh.PRIMITIVE_TRIANGLES])."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:158
+msgid "Clear all information passed into the surface tool so far."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:169
+msgid ""
+"Returns a constructed [ArrayMesh] from current information passed in. If an "
+"existing [ArrayMesh] is passed in as an argument, will add an extra surface "
+"to the existing [ArrayMesh].\n"
+"Default flag is [constant Mesh.ARRAY_COMPRESS_DEFAULT]. See "
+"[code]ARRAY_COMPRESS_*[/code] constants in [enum Mesh.ArrayFormat] for other "
+"flags."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:177
+msgid ""
+"Commits the data to the same format used by [method ArrayMesh."
+"add_surface_from_arrays]. This way you can further process the mesh data "
+"using the [ArrayMesh] API."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:188
+msgid "Creates a vertex array from an existing [Mesh]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:201
+msgid ""
+"Creates a vertex array from the specified blend shape of an existing [Mesh]. "
+"This can be used to extract a specific pose from a blend shape."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:208
+msgid "Removes the index array by expanding the vertex array."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:217
+msgid ""
+"Generates normals from vertices so you do not have to do it manually. If "
+"[code]flip[/code] is [code]true[/code], the resulting normals will be "
+"inverted.\n"
+"Requires the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES]."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:225
+msgid ""
+"Generates a tangent vector for each vertex. Requires that each vertex have "
+"UVs and normals set already."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:232
+msgid ""
+"Shrinks the vertex array by creating an index array (avoids reusing "
+"vertices)."
+msgstr ""
+
+#: doc/classes/SurfaceTool.xml:241
+msgid "Sets [Material] to be used by the [Mesh] you are constructing."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:4
+msgid "Tabbed container."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:7
+msgid ""
+"Sets the active tab's [code]visible[/code] property to the value [code]true[/"
+"code]. Sets all other children's to [code]false[/code].\n"
+"Ignores non-[Control] children.\n"
+"Individual tabs are always visible unless you use [method set_tab_disabled] "
+"and [method set_tab_title] to hide it.\n"
+"To hide only a tab's content, nest the content inside a child [Control], so "
+"it receives the [TabContainer]'s visibility setting instead."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:19
+msgid "Returns the child [Control] node located at the active tab index."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:26
+msgid ""
+"Returns the [Popup] node instance if one has been set already with [method "
+"set_popup]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:33
+msgid "Returns the previously active tab index."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:42
+msgid "Returns the currently visible tab's [Control] node."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:49 doc/classes/Tabs.xml:50
+msgid "Returns the number of tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:58 doc/classes/Tabs.xml:59
+msgid ""
+"Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is "
+"disabled."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:67 doc/classes/Tabs.xml:68
+msgid ""
+"Returns the [Texture2D] for the tab at index [code]tab_idx[/code] or "
+"[code]null[/code] if the tab has no [Texture2D]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:76 doc/classes/Tabs.xml:93
+msgid ""
+"Returns the title of the tab at index [code]tab_idx[/code]. Tab titles "
+"default to the name of the indexed child node, but this can be overridden "
+"with [method set_tab_title]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:83
+msgid "Returns the [TabContainer] rearrange group id."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:92
+msgid ""
+"If set on a [Popup] node instance, a popup menu icon appears in the top-"
+"right corner of the [TabContainer]. Clicking it will expand the [Popup] node."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:103
+msgid ""
+"If [code]disabled[/code] is [code]false[/code], hides the tab at index "
+"[code]tab_idx[/code].\n"
+"[b]Note:[/b] Its title text will remain, unless also removed with [method "
+"set_tab_title]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:115
+msgid "Sets an icon for the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:126
+msgid ""
+"Sets a title for the tab at index [code]tab_idx[/code]. Tab titles default "
+"to the name of the indexed child node, but this can be overridden with "
+"[method set_tab_title]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:135
+msgid ""
+"Defines rearrange group id, choose for each [TabContainer] the same value to "
+"enable tab drag between [TabContainer]. Enable drag with "
+"[code]set_drag_to_rearrange_enabled(true)[/code]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:141
+msgid ""
+"The current tab index. When set, this index's [Control] node's "
+"[code]visible[/code] property is set to [code]true[/code] and all others are "
+"set to [code]false[/code]."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:144 doc/classes/Tabs.xml:181
+msgid "If [code]true[/code], tabs can be rearranged with mouse drag."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:147
+msgid ""
+"The alignment of all tabs in the tab container. See the [enum TabAlign] "
+"constants for details."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:150
+msgid ""
+"If [code]true[/code], tabs are visible. If [code]false[/code], tabs' content "
+"and titles are hidden."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:153
+msgid ""
+"If [code]true[/code], children [Control] nodes that are hidden have their "
+"minimum size take into account in the total, instead of only the currently "
+"visible one."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:159
+msgid ""
+"Emitted when the [TabContainer]'s [Popup] button is clicked. See [method "
+"set_popup] for details."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:166 doc/classes/Tabs.xml:212
+msgid "Emitted when switching to another tab."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:173
+msgid "Emitted when a tab is selected, even if it is the current tab."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:179 doc/classes/Tabs.xml:239
+msgid "Align the tabs to the left."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:182 doc/classes/Tabs.xml:242
+msgid "Align the tabs to the center."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:185 doc/classes/Tabs.xml:245
+msgid "Align the tabs to the right."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:190 doc/classes/Tabs.xml:274
+msgid ""
+"Icon for the left arrow button that appears when there are too many tabs to "
+"fit in the container width. When the button is disabled (i.e. the first tab "
+"is visible), it appears semi-transparent."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:193 doc/classes/Tabs.xml:277
+msgid ""
+"Icon for the left 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."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:196 doc/classes/Tabs.xml:280
+msgid "The font used to draw tab names."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:199 doc/classes/Tabs.xml:283
+msgid "Font color of inactive tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:202 doc/classes/Tabs.xml:286
+msgid "Font color of disabled tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:205 doc/classes/Tabs.xml:289
+msgid "Font color of the currently selected tab."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:208
+msgid "Horizontal separation between tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:211 doc/classes/Tabs.xml:295
+msgid ""
+"Icon for the right arrow button that appears when there are too many tabs to "
+"fit in the container width. When the button is disabled (i.e. the last tab "
+"is visible) it appears semi-transparent."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:214 doc/classes/Tabs.xml:298
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:217
+msgid "The icon for the menu button (see [method set_popup])."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:220
+msgid ""
+"The icon for the menu button (see [method set_popup]) when it's being "
+"hovered with the cursor."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:223
+msgid "The style for the background fill."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:226
+msgid "The space at the left and right edges of the tab bar."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:229
+msgid "The style of inactive tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:232
+msgid "The style of disabled tabs."
+msgstr ""
+
+#: doc/classes/TabContainer.xml:235 doc/classes/Tabs.xml:309
+msgid "The style of the currently selected tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:4
+msgid "Tabs control."
+msgstr ""
+
+#: doc/classes/Tabs.xml:7
+msgid ""
+"Simple tabs control, similar to [TabContainer] but is only in charge of "
+"drawing tabs, not interact with children."
+msgstr ""
+
+#: doc/classes/Tabs.xml:20
+msgid "Adds a new tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:29
+msgid "Moves the scroll view to make the tab visible."
+msgstr ""
+
+#: doc/classes/Tabs.xml:36
+msgid ""
+"Returns [code]true[/code] if the offset buttons (the ones that appear when "
+"there's not enough space for all tabs) are visible."
+msgstr ""
+
+#: doc/classes/Tabs.xml:43
+msgid "Returns [code]true[/code] if select with right mouse button is enabled."
+msgstr ""
+
+#: doc/classes/Tabs.xml:75
+msgid "Returns the number of hidden tabs offsetted to the left."
+msgstr ""
+
+#: doc/classes/Tabs.xml:84
+msgid "Returns tab [Rect2] with local position and size."
+msgstr ""
+
+#: doc/classes/Tabs.xml:100
+msgid "Returns the [Tabs]' rearrange group ID."
+msgstr ""
+
+#: doc/classes/Tabs.xml:111
+msgid "Moves a tab from [code]from[/code] to [code]to[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:120
+msgid "Removes the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:129
+msgid ""
+"If [code]true[/code], enables selecting a tab with the right mouse button."
+msgstr ""
+
+#: doc/classes/Tabs.xml:140
+msgid ""
+"If [code]disabled[/code] is [code]false[/code], hides the tab at index "
+"[code]tab_idx[/code].\n"
+"[b]Note:[/b] Its title text will remain unless it is also removed with "
+"[method set_tab_title]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:152
+msgid "Sets an [code]icon[/code] for the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:163
+msgid "Sets a [code]title[/code] for the tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:172
+msgid ""
+"Defines the rearrange group ID. Choose for each [Tabs] the same value to "
+"dragging tabs between [Tabs]. Enable drag with "
+"[code]set_drag_to_rearrange_enabled(true)[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:178
+msgid "Select tab at index [code]tab_idx[/code]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:184
+msgid ""
+"if [code]true[/code], the mouse's scroll wheel cab be used to navigate the "
+"scroll view."
+msgstr ""
+
+#: doc/classes/Tabs.xml:187
+msgid "The alignment of all tabs. See [enum TabAlign] for details."
+msgstr ""
+
+#: doc/classes/Tabs.xml:190
+msgid ""
+"Sets when the close button will appear on the tabs. See [enum "
+"CloseButtonDisplayPolicy] for details."
+msgstr ""
+
+#: doc/classes/Tabs.xml:198
+msgid ""
+"Emitted when the active tab is rearranged via mouse drag. See [member "
+"drag_to_rearrange_enabled]."
+msgstr ""
+
+#: doc/classes/Tabs.xml:205
+msgid "Emitted when a tab is right-clicked."
+msgstr ""
+
+#: doc/classes/Tabs.xml:219
+msgid "Emitted when a tab is clicked, even if it is the current tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:226
+msgid "Emitted when a tab is closed."
+msgstr ""
+
+#: doc/classes/Tabs.xml:233
+msgid "Emitted when a tab is hovered by the mouse."
+msgstr ""
+
+#: doc/classes/Tabs.xml:248
+msgid "Represents the size of the [enum TabAlign] enum."
+msgstr ""
+
+#: doc/classes/Tabs.xml:251
+msgid "Never show the close buttons."
+msgstr ""
+
+#: doc/classes/Tabs.xml:254
+msgid "Only show the close button on the currently active tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:257
+msgid "Show the close button on all tabs."
+msgstr ""
+
+#: doc/classes/Tabs.xml:260
+msgid "Represents the size of the [enum CloseButtonDisplayPolicy] enum."
+msgstr ""
+
+#: doc/classes/Tabs.xml:265
+msgid "Background of the close button when it's being hovered with the cursor."
+msgstr ""
+
+#: doc/classes/Tabs.xml:268
+msgid "Background of the close button when it's being pressed."
+msgstr ""
+
+#: doc/classes/Tabs.xml:271
+msgid "The icon for the close button (see [member tab_close_display_policy])."
+msgstr ""
+
+#: doc/classes/Tabs.xml:292
+msgid "The horizontal separation between the tabs."
+msgstr ""
+
+#: doc/classes/Tabs.xml:303
+msgid "The style of an inactive tab."
+msgstr ""
+
+#: doc/classes/Tabs.xml:306
+msgid "The style of a disabled tab"
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:4
+msgid "A TCP server."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:7
+msgid ""
+"A TCP server. Listens to connections on a port and returns a [StreamPeerTCP] "
+"when it gets an incoming connection."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:16
+msgid "Returns [code]true[/code] if a connection is available for taking."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:23
+msgid ""
+"Returns [code]true[/code] if the server is currently listening for "
+"connections."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:34
+msgid ""
+"Listen on the [code]port[/code] binding to [code]bind_address[/code].\n"
+"If [code]bind_address[/code] is set as [code]\"*\"[/code] (default), the "
+"server will listen on all available addresses (both IPv4 and IPv6).\n"
+"If [code]bind_address[/code] is set as [code]\"0.0.0.0\"[/code] (for IPv4) "
+"or [code]\"::\"[/code] (for IPv6), the server will listen on all available "
+"addresses matching that IP type.\n"
+"If [code]bind_address[/code] is set to any valid address (e.g. "
+"[code]\"192.168.1.101\"[/code], [code]\"::1\"[/code], etc), the server will "
+"only listen on the interface with that addresses (or fail if no interface "
+"with the given address exists)."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:44
+msgid "Stops listening."
+msgstr ""
+
+#: doc/classes/TCP_Server.xml:51
+msgid ""
+"If a connection is available, returns a StreamPeerTCP with the connection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:4
+msgid "Multiline text editing control."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:7
+msgid ""
+"TextEdit is meant for editing large, multiline text. It also has facilities "
+"for editing code, such as syntax highlighting support and multiple levels of "
+"undo/redo."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:24
+msgid "Adds color region (given the delimiters) and its colors."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:35
+msgid "Adds a [code]keyword[/code] and its [Color]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:44
+msgid ""
+"Returns if the given line is foldable, that is, it has indented lines right "
+"below it."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:57
+msgid ""
+"Clears all custom syntax coloring information previously added with [method "
+"add_color_region] or [method add_keyword_color]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:64
+msgid "Clears the undo history."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:71
+msgid "Copy's the current text selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:78
+msgid "Returns the column the editing cursor is at."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:85
+msgid "Returns the line the editing cursor is at."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:96
+msgid ""
+"Moves the cursor at the specified [code]column[/code] index.\n"
+"If [code]adjust_viewport[/code] is set to [code]true[/code], the viewport "
+"will center at the cursor position after the move occurs."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:112
+msgid ""
+"Moves the cursor at the specified [code]line[/code] index.\n"
+"If [code]adjust_viewport[/code] is set to [code]true[/code], the viewport "
+"will center at the cursor position after the move occurs.\n"
+"If [code]can_be_hidden[/code] is set to [code]true[/code], the specified "
+"[code]line[/code] can be hidden using [method set_line_as_hidden]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:121
+msgid "Cut's the current selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:128
+msgid "Deselects the current selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:135
+msgid "Folds all lines that are possible to be folded (see [method can_fold])."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:144
+msgid "Folds the given line, if possible (see [method can_fold])."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:151
+msgid "Returns an array containing the line number of each breakpoint."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:160
+msgid "Returns the [Color] of the specified [code]keyword[/code]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:169
+msgid "Returns the text of a specific line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:176
+msgid "Returns the amount of total lines in the text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:183
+msgid ""
+"Returns the [PopupMenu] of this [TextEdit]. By default, this menu is "
+"displayed when right-clicking on the [TextEdit]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:190
+msgid "Returns the selection begin column."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:197
+msgid "Returns the selection begin line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:204
+msgid "Returns the text inside the selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:211
+msgid "Returns the selection end column."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:218
+msgid "Returns the selection end line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:225
+msgid "Returns a [String] text with the word under the mouse cursor location."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:234
+msgid ""
+"Returns whether the specified [code]keyword[/code] has a color set to it or "
+"not."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:243
+msgid "Insert the specified text at the cursor position."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:252
+msgid "Returns whether the line at the specified index is folded or not."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:261
+msgid "Returns whether the line at the specified index is hidden or not."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:268
+msgid "Returns [code]true[/code] if the selection is active."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:277
+msgid ""
+"Triggers a right-click menu action by the specified index. See [enum "
+"MenuItems] for a list of available indexes."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:284
+msgid "Paste the current selection."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:291
+msgid "Perform redo operation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:298
+msgid ""
+"Removes all the breakpoints. This will not fire the [signal "
+"breakpoint_toggled] signal."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:313
+msgid ""
+"Perform a search inside the text. Search flags can be specified in the [enum "
+"SearchFlags] enum.\n"
+"Returns an empty [code]PackedInt32Array[/code] if no result was found. "
+"Otherwise, the result line and column can be accessed at indices specified "
+"in the [enum SearchResult] enum, e.g:\n"
+"[codeblock]\n"
+"var result = search(key, flags, line, column)\n"
+"if result.size() > 0:\n"
+" # Result found.\n"
+" var res_line = result[TextEdit.SEARCH_RESULT_LINE]\n"
+" var res_column = result[TextEdit.SEARCH_RESULT_COLUMN]\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/TextEdit.xml:336
+msgid "Perform selection, from line/column to line/column."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:343
+msgid "Select all the text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:354
+msgid "If [code]true[/code], hides the line of the specified index."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:363
+msgid "Toggle the folding of the code block at the given line."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:370
+msgid "Perform undo operation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:379
+msgid "Unfolds the given line, if folded."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:386
+msgid ""
+"Unhide all lines that were previously set to hidden by [method "
+"set_line_as_hidden]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:392
+msgid "If [code]true[/code], the breakpoint gutter is visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:401
+msgid ""
+"If [code]true[/code], the caret displays as a rectangle.\n"
+"If [code]false[/code], the caret displays as a bar."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:405
+msgid ""
+"If [code]true[/code], a right-click moves the cursor at the mouse position "
+"before displaying the context menu.\n"
+"If [code]false[/code], the context menu disregards mouse location."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:409
+msgid "If [code]true[/code], a right-click displays the context menu."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:412
+msgid ""
+"If [code]true[/code], the \"space\" character will have a visible "
+"representation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:415
+msgid ""
+"If [code]true[/code], the \"tab\" character will have a visible "
+"representation."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:419
+msgid ""
+"If [code]true[/code], the fold gutter is visible. This enables folding "
+"groups of indented lines."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:422
+msgid ""
+"If [code]true[/code], all lines that have been set to hidden by [method "
+"set_line_as_hidden], will not be visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:425
+msgid ""
+"If [code]true[/code], all occurrences of the selected text will be "
+"highlighted."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:428
+msgid "If [code]true[/code], the line containing the cursor is highlighted."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:438
+msgid ""
+"If [code]true[/code], read-only mode is enabled. Existing text cannot be "
+"modified and new text cannot be added."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:451
+msgid ""
+"If [code]true[/code], line numbers are displayed to the left of the text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:454
+msgid ""
+"If [code]true[/code], sets the [code]step[/code] of the scrollbars to "
+"[code]0.25[/code] which results in smoother scrolling."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:457
+msgid ""
+"If [code]true[/code], any custom color properties that have been set for "
+"this [TextEdit] will be visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:460
+msgid "String value of the [TextEdit]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:463
+msgid "Vertical scroll sensitivity."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:466
+msgid ""
+"If [code]true[/code], enables text wrapping when it goes beyond the edge of "
+"what is visible."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:474
+msgid "Emitted when a breakpoint is placed via the breakpoint gutter."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:479
+msgid "Emitted when the cursor changes."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:488
+msgid "Emitted when the info icon is clicked."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:519
+msgid "Match case when searching."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:522
+msgid "Match whole words when searching."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:525
+msgid "Search from end to beginning."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:528
+msgid "Used to access the result column from [method search]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:531
+msgid "Used to access the result line from [method search]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:540
+msgid ""
+"Pastes the clipboard text over the selected text (or at the cursor's "
+"position)."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:543
+msgid "Erases the whole [TextEdit] text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:546
+msgid "Selects the whole [TextEdit] text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:552
+msgid "Redoes the previous action."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:560
+msgid ""
+"Sets the background [Color] of this [TextEdit]. [member syntax_highlighting] "
+"has to be enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:563
+msgid ""
+"Sets the [Color] of the bookmark marker. [member syntax_highlighting] has to "
+"be enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:568 doc/classes/TextEdit.xml:595
+msgid ""
+"Sets the [Color] of the breakpoints. [member breakpoint_gutter] has to be "
+"enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:606
+msgid "Sets the default [Font]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:609
+msgid "Sets the font [Color]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:618
+msgid ""
+"Sets the [Color] of the line numbers. [member show_line_numbers] has to be "
+"enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:621
+msgid "Sets the spacing between the lines."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:624
+msgid "Sets the [Color] of marked text."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:629
+msgid "Sets the [StyleBox] of this [TextEdit]."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:634
+msgid ""
+"Sets the [StyleBox] of this [TextEdit] when [member readonly] is enabled."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:639
+msgid "Sets the highlight [Color] of text selections."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:646
+msgid "Sets a custom [Texture2D] for tab text characters."
+msgstr ""
+
+#: doc/classes/TextEdit.xml:649
+msgid ""
+"Sets the highlight [Color] of multiple occurrences. [member "
+"highlight_all_occurrences] has to be enabled."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:4
+msgid "Texture for 2D and 3D."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:7
+msgid ""
+"A texture works by registering an image in the video hardware, which then "
+"can be used in 3D models or 2D [Sprite2D] or GUI [Control].\n"
+"Textures are often created by loading them from a file. See [method "
+"@GDScript.load].\n"
+"[Texture2D] is a base for other resources. It cannot be used directly."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:36
+msgid ""
+"Draws the texture using a [CanvasItem] with the [RenderingServer] API at the "
+"specified [code]position[/code]."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:63
+msgid "Draws the texture using a [CanvasItem] with the [RenderingServer] API."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:92
+msgid ""
+"Draws a part of the texture using a [CanvasItem] with the [RenderingServer] "
+"API."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:99
+msgid ""
+"Returns an [Image] with the data from this [Texture2D]. [Image]s can be "
+"accessed and manipulated directly."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:106
+msgid "Returns the texture height."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:113
+msgid "Returns the texture size."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:120
+msgid "Returns the texture width."
+msgstr ""
+
+#: doc/classes/Texture2D.xml:127
+msgid "Returns [code]true[/code] if this [Texture2D] has an alpha channel."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:4
+msgid ""
+"Texture-based button. Supports Pressed, Hover, Disabled and Focused states."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:7
+msgid ""
+"[TextureButton] has the same functionality as [Button], except it uses "
+"sprites instead of Godot's [Theme] resource. It is faster to create, but it "
+"doesn't support localization like more complex [Control]s.\n"
+"The \"normal\" state must contain a texture ([member texture_normal]); other "
+"textures are optional."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:16
+msgid ""
+"If [code]true[/code], the texture stretches to the edges of the node's "
+"bounding rectangle using the [member stretch_mode]. If [code]false[/code], "
+"the texture will not scale with the node."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:19
+msgid ""
+"Controls the texture's behavior when you resize the node's bounding "
+"rectangle, [b]only if[/b] [member expand] is [code]true[/code]. Set it to "
+"one of the [enum StretchMode] constants. See the constants to learn more."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:22
+msgid ""
+"Pure black and white [BitMap] image to use for click detection. On the mask, "
+"white pixels represent the button's clickable area. Use it to create buttons "
+"with curved shapes."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:25
+msgid ""
+"Texture to display when the node is disabled. See [member BaseButton."
+"disabled]."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:28
+msgid "Texture to display when the node has mouse or keyboard focus."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:31
+msgid "Texture to display when the mouse hovers the node."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:34
+msgid ""
+"Texture to display by default, when the node is [b]not[/b] in the disabled, "
+"focused, hover or pressed state."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:37
+msgid ""
+"Texture to display on mouse down over the node, if the node has keyboard "
+"focus and the player presses the Enter key or if the player presses the "
+"[member BaseButton.shortcut] key."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:42 doc/classes/TextureRect.xml:36
+msgid "Scale to fit the node's bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:45 doc/classes/TextureRect.xml:39
+msgid "Tile inside the node's bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:48 doc/classes/TextureRect.xml:42
+msgid ""
+"The texture keeps its original size and stays in the bounding rectangle's "
+"top-left corner."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:51 doc/classes/TextureRect.xml:45
+msgid ""
+"The texture keeps its original size and stays centered in the node's "
+"bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:54 doc/classes/TextureRect.xml:48
+msgid ""
+"Scale the texture to fit the node's bounding rectangle, but maintain the "
+"texture's aspect ratio."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:57
+msgid ""
+"Scale the texture to fit the node's bounding rectangle, center it, and "
+"maintain its aspect ratio."
+msgstr ""
+
+#: doc/classes/TextureButton.xml:60 doc/classes/TextureRect.xml:54
+msgid ""
+"Scale the texture so that the shorter side fits the bounding rectangle. The "
+"other side clips to the node's limits."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:4
+msgid "Base class for 3D texture types."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:7
+msgid ""
+"Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be "
+"used directly, but contains all the functions necessary for accessing the "
+"derived resource types. Data is set on a per-layer basis. For "
+"[Texture2DArray]s, the layer specifies the array layer."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:24
+msgid ""
+"Returns the current format being used by this texture. See [enum Image."
+"Format] for details."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:31
+msgid ""
+"Returns the height of the texture. Height is typically represented by the Y-"
+"axis."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:40
+msgid ""
+"Returns an [Image] resource with the data from specified [code]layer[/code]."
+msgstr ""
+
+#: doc/classes/TextureLayered.xml:53
+msgid ""
+"Returns the width of the texture. Width is typically represented by the X-"
+"axis."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:4
+msgid ""
+"Texture-based progress bar. Useful for loading screens and life or stamina "
+"bars."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:7
+msgid ""
+"TextureProgress works like [ProgressBar], but uses up to 3 textures instead "
+"of Godot's [Theme] resource. It can be used to create horizontal, vertical "
+"and radial progress bars."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:33
+msgid "The fill direction. See [enum FillMode] for possible values."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:37
+msgid ""
+"If [code]true[/code], Godot treats the bar's textures like in "
+"[NinePatchRect]. Use the [code]stretch_margin_*[/code] properties like "
+"[member stretch_margin_bottom] to set up the nine patch's 3×3 grid. When "
+"using a radial [member fill_mode], this setting will enable stretching."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:40
+msgid ""
+"Offsets [member texture_progress] if [member fill_mode] is [constant "
+"FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:43
+msgid ""
+"Upper limit for the fill of [member texture_progress] if [member fill_mode] "
+"is [constant FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]. When the "
+"node's [code]value[/code] is equal to its [code]max_value[/code], the "
+"texture fills up to this angle.\n"
+"See [member Range.value], [member Range.max_value]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:47
+msgid ""
+"Starting angle for the fill of [member texture_progress] if [member "
+"fill_mode] is [constant FILL_CLOCKWISE] or [constant "
+"FILL_COUNTER_CLOCKWISE]. When the node's [code]value[/code] is equal to its "
+"[code]min_value[/code], the texture doesn't show up at all. When the "
+"[code]value[/code] increases, the texture fills and tends towards [member "
+"radial_fill_degrees]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:50
+msgid ""
+"The height of the 9-patch's bottom row. A margin of 16 means the 9-slice's "
+"bottom corners and side will have a height of 16 pixels. You can set all 4 "
+"margin values individually to create panels with non-uniform borders."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:53
+msgid "The width of the 9-patch's left column."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:56
+msgid "The width of the 9-patch's right column."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:59
+msgid "The height of the 9-patch's top row."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:62
+msgid ""
+"[Texture2D] that draws over the progress bar. Use it to add highlights or an "
+"upper-frame that hides part of [member texture_progress]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:65
+msgid ""
+"[Texture2D] that clips based on the node's [code]value[/code] and [member "
+"fill_mode]. As [code]value[/code] increased, the texture fills up. It shows "
+"entirely when [code]value[/code] reaches [code]max_value[/code]. It doesn't "
+"show at all if [code]value[/code] is equal to [code]min_value[/code].\n"
+"The [code]value[/code] property comes from [Range]. See [member Range."
+"value], [member Range.min_value], [member Range.max_value]."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:69
+msgid "[Texture2D] that draws under the progress bar. The bar's background."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:72
+msgid ""
+"Multiplies the color of the bar's [code]texture_over[/code] texture. The "
+"effect is similar to [member CanvasItem.modulate], except it only affects "
+"this specific texture instead of the entire node."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:75
+msgid ""
+"Multiplies the color of the bar's [code]texture_progress[/code] texture."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:78
+msgid "Multiplies the color of the bar's [code]texture_under[/code] texture."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:83
+msgid "The [member texture_progress] fills from left to right."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:86
+msgid "The [member texture_progress] fills from right to left."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:89
+msgid "The [member texture_progress] fills from top to bottom."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:92
+msgid "The [member texture_progress] fills from bottom to top."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:95
+msgid ""
+"Turns the node into a radial bar. The [member texture_progress] fills "
+"clockwise. See [member radial_center_offset], [member radial_initial_angle] "
+"and [member radial_fill_degrees] to control the way the bar fills up."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:98
+msgid ""
+"Turns the node into a radial bar. The [member texture_progress] fills "
+"counterclockwise. See [member radial_center_offset], [member "
+"radial_initial_angle] and [member radial_fill_degrees] to control the way "
+"the bar fills up."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:101
+msgid ""
+"The [member texture_progress] fills from the center, expanding both towards "
+"the left and the right."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:104
+msgid ""
+"The [member texture_progress] fills from the center, expanding both towards "
+"the top and the bottom."
+msgstr ""
+
+#: doc/classes/TextureProgress.xml:107
+msgid ""
+"Turns the node into a radial bar. The [member texture_progress] fills "
+"radially from the center, expanding both clockwise and counterclockwise. See "
+"[member radial_center_offset], [member radial_initial_angle] and [member "
+"radial_fill_degrees] to control the way the bar fills up."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:4
+msgid "Control for drawing textures."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:7
+msgid ""
+"Used to draw icons and sprites in a user interface. The texture's placement "
+"can be controlled with the [member stretch_mode] property. It can scale, "
+"tile, or stay centered inside its bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:15
+msgid "If [code]true[/code], the texture scales to fit its bounding rectangle."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:25
+msgid ""
+"Controls the texture's behavior when resizing the node's bounding rectangle. "
+"See [enum StretchMode]."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:28
+msgid "The node's [Texture2D] resource."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:33
+msgid ""
+"Scale to fit the node's bounding rectangle, only if [code]expand[/code] is "
+"[code]true[/code]. Default [code]stretch_mode[/code], for backwards "
+"compatibility. Until you set [code]expand[/code] to [code]true[/code], the "
+"texture will behave like [constant STRETCH_KEEP]."
+msgstr ""
+
+#: doc/classes/TextureRect.xml:51
+msgid ""
+"Scale the texture to fit the node's bounding rectangle, center it and "
+"maintain its aspect ratio."
+msgstr ""
+
+#: doc/classes/Theme.xml:4
+msgid "Theme for controls."
+msgstr ""
+
+#: doc/classes/Theme.xml:7
+msgid ""
+"A theme for skinning controls. Controls can be skinned individually, but for "
+"complex applications, it's more practical to just create a global theme that "
+"defines everything. This theme can be applied to any [Control]; the Control "
+"and its children will automatically use it.\n"
+"Theme resources can alternatively be loaded by writing them in a [code]."
+"theme[/code] file, see the documentation for more information."
+msgstr ""
+
+#: doc/classes/Theme.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/gui/gui_skinning.html"
+msgstr ""
+
+#: doc/classes/Theme.xml:18
+msgid "Clears all values on the theme."
+msgstr ""
+
+#: doc/classes/Theme.xml:29
+msgid ""
+"Clears the [Color] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:40
+msgid ""
+"Clears the constant at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:51
+msgid ""
+"Clears the [Font] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:62
+msgid ""
+"Clears the icon at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:73
+msgid ""
+"Clears [StyleBox] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:80
+msgid "Sets the theme's values to a copy of the default theme values."
+msgstr ""
+
+#: doc/classes/Theme.xml:89
+msgid "Sets the theme's values to a copy of a given theme."
+msgstr ""
+
+#: doc/classes/Theme.xml:100
+msgid ""
+"Returns the [Color] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:109
+msgid ""
+"Returns all the [Color]s as a [PackedStringArray] filled with each [Color]'s "
+"name, for use in [method get_color], if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:120
+msgid ""
+"Returns the constant at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:129
+msgid ""
+"Returns all the constants as a [PackedStringArray] filled with each "
+"constant's name, for use in [method get_constant], if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:140
+msgid ""
+"Returns the [Font] at [code]name[/code] if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:149
+msgid ""
+"Returns all the [Font]s as a [PackedStringArray] filled with each [Font]'s "
+"name, for use in [method get_font], if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:160
+msgid ""
+"Returns the icon [Texture2D] at [code]name[/code] if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:169
+msgid ""
+"Returns all the icons as a [PackedStringArray] filled with each "
+"[Texture2D]'s name, for use in [method get_icon], if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:180
+msgid ""
+"Returns the icon [StyleBox] at [code]name[/code] if the theme has "
+"[code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:189
+msgid ""
+"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]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:196
+msgid ""
+"Returns all the [StyleBox] types as a [PackedStringArray] filled with each "
+"[StyleBox]'s type, for use in [method get_stylebox] and/or [method "
+"get_stylebox_list], if the theme has [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:205
+msgid ""
+"Returns all the types in [code]type[/code] as a [PackedStringArray] for use "
+"in any of the [code]get_*[/code] functions, if the theme has [code]type[/"
+"code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:216
+msgid ""
+"Returns [code]true[/code] if [Color] with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:228
+msgid ""
+"Returns [code]true[/code] if constant with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:240
+msgid ""
+"Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]type[/"
+"code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:252
+msgid ""
+"Returns [code]true[/code] if icon [Texture2D] with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:264
+msgid ""
+"Returns [code]true[/code] if [StyleBox] with [code]name[/code] is in "
+"[code]type[/code].\n"
+"Returns [code]false[/code] if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:278
+msgid ""
+"Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:292
+msgid ""
+"Sets the theme's constant to [code]constant[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:306
+msgid ""
+"Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:320
+msgid ""
+"Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/"
+"code] in [code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:334
+msgid ""
+"Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in "
+"[code]type[/code].\n"
+"Does nothing if the theme does not have [code]type[/code]."
+msgstr ""
+
+#: doc/classes/Theme.xml:341
+msgid "The theme's default font."
+msgstr ""
+
+#: doc/classes/Thread.xml:4
+msgid "A unit of execution in a process."
+msgstr ""
+
+#: doc/classes/Thread.xml:7
+msgid ""
+"A unit of execution in a process. Can run methods on [Object]s "
+"simultaneously. The use of synchronization via [Mutex] or [Semaphore] is "
+"advised if working with shared objects."
+msgstr ""
+
+#: doc/classes/Thread.xml:17
+msgid ""
+"Returns the current [Thread]'s ID, uniquely identifying it among all threads."
+msgstr ""
+
+#: doc/classes/Thread.xml:24
+msgid ""
+"Returns [code]true[/code] if this [Thread] is currently active. An active "
+"[Thread] cannot start work on a new method but can be joined with [method "
+"wait_to_finish]."
+msgstr ""
+
+#: doc/classes/Thread.xml:39
+msgid ""
+"Starts a new [Thread] that runs [code]method[/code] on object "
+"[code]instance[/code] with [code]userdata[/code] passed as an argument. Even "
+"if no userdata is passed, [code]method[/code] must accept one argument and "
+"it will be null. The [code]priority[/code] of the [Thread] can be changed by "
+"passing a value from the [enum Priority] enum.\n"
+"Returns [constant OK] on success, or [constant ERR_CANT_CREATE] on failure."
+msgstr ""
+
+#: doc/classes/Thread.xml:47
+msgid ""
+"Joins the [Thread] and waits for it to finish. Returns what the method "
+"called returned."
+msgstr ""
+
+#: doc/classes/Thread.xml:53
+msgid "A thread running with lower priority than normally."
+msgstr ""
+
+#: doc/classes/Thread.xml:56
+msgid "A thread with a standard priority."
+msgstr ""
+
+#: doc/classes/Thread.xml:59
+msgid "A thread running with higher priority than normally."
+msgstr ""
+
+#: doc/classes/TileMap.xml:4
+msgid "Node for 2D tile-based maps."
+msgstr ""
+
+#: doc/classes/TileMap.xml:7
+msgid ""
+"Node for 2D tile-based maps. Tilemaps use a [TileSet] which contain a list "
+"of tiles (textures plus optional collision, navigation, and/or occluder "
+"shapes) which are used to create grid-based maps."
+msgstr ""
+
+#: doc/classes/TileMap.xml:10
+msgid "https://docs.godotengine.org/en/latest/tutorials/2d/using_tilemaps.html"
+msgstr ""
+
+#: doc/classes/TileMap.xml:17
+msgid "Clears all cells."
+msgstr ""
+
+#: doc/classes/TileMap.xml:24
+msgid "Clears cells that do not exist in the tileset."
+msgstr ""
+
+#: doc/classes/TileMap.xml:35
+msgid ""
+"Returns the tile index of the given cell. If no tile exists in the cell, "
+"returns [constant INVALID_CELL]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:46
+msgid ""
+"Returns the coordinate of the autotile variation in the tileset. Returns a "
+"zero vector if the cell doesn't have autotiling."
+msgstr ""
+
+#: doc/classes/TileMap.xml:55
+msgid ""
+"Returns the tile index of the cell given by a Vector2. If no tile exists in "
+"the cell, returns [constant INVALID_CELL]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:64
+msgid "Returns [code]true[/code] if the given collision layer bit is set."
+msgstr ""
+
+#: doc/classes/TileMap.xml:73
+msgid "Returns [code]true[/code] if the given collision mask bit is set."
+msgstr ""
+
+#: doc/classes/TileMap.xml:80
+msgid ""
+"Returns a [Vector2] array with the positions of all cells containing a tile "
+"from the tileset (i.e. a tile index different from [code]-1[/code])."
+msgstr ""
+
+#: doc/classes/TileMap.xml:89
+msgid "Returns an array of all cells with the given tile [code]id[/code]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:96
+msgid "Returns a rectangle enclosing the used (non-empty) tiles of the map."
+msgstr ""
+
+#: doc/classes/TileMap.xml:107
+msgid ""
+"Returns [code]true[/code] if the given cell is transposed, i.e. the X and Y "
+"axes are swapped."
+msgstr ""
+
+#: doc/classes/TileMap.xml:118
+msgid "Returns [code]true[/code] if the given cell is flipped in the X axis."
+msgstr ""
+
+#: doc/classes/TileMap.xml:129
+msgid "Returns [code]true[/code] if the given cell is flipped in the Y axis."
+msgstr ""
+
+#: doc/classes/TileMap.xml:140
+msgid ""
+"Returns the global position corresponding to the given tilemap (grid-based) "
+"coordinates.\n"
+"Optionally, the tilemap's half offset can be ignored."
+msgstr ""
+
+#: doc/classes/TileMap.xml:162
+msgid ""
+"Sets the tile index for the cell given by a Vector2.\n"
+"An index of [code]-1[/code] clears the cell.\n"
+"Optionally, the tile can also be flipped, transposed, or given autotile "
+"coordinates.\n"
+"[b]Note:[/b] Data such as navigation polygons and collision shapes are not "
+"immediately updated for performance reasons.\n"
+"If you need these to be immediately updated, you can call [method "
+"update_dirty_quadrants].\n"
+"Overriding this method also overrides it internally, allowing custom logic "
+"to be implemented when tiles are placed/removed:\n"
+"[codeblock]\n"
+"func set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)\n"
+" # Write your custom logic here.\n"
+" # To call the default method:\n"
+" .set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/TileMap.xml:190
+msgid ""
+"Sets the tile index for the given cell.\n"
+"An index of [code]-1[/code] clears the cell.\n"
+"Optionally, the tile can also be flipped or transposed.\n"
+"[b]Note:[/b] Data such as navigation polygons and collision shapes are not "
+"immediately updated for performance reasons.\n"
+"If you need these to be immediately updated, you can call [method "
+"update_dirty_quadrants]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:205
+msgid "Sets the given collision layer bit."
+msgstr ""
+
+#: doc/classes/TileMap.xml:216
+msgid "Sets the given collision mask bit."
+msgstr ""
+
+#: doc/classes/TileMap.xml:225
+msgid ""
+"Applies autotiling rules to the cell (and its adjacent cells) referenced by "
+"its grid-based X and Y coordinates."
+msgstr ""
+
+#: doc/classes/TileMap.xml:236
+msgid ""
+"Applies autotiling rules to the cells in the given region (specified by grid-"
+"based X and Y coordinates).\n"
+"Calling with invalid (or missing) parameters applies autotiling rules for "
+"the entire tilemap."
+msgstr ""
+
+#: doc/classes/TileMap.xml:244
+msgid ""
+"Updates the tile map's quadrants, allowing things such as navigation and "
+"collision shapes to be immediately used if modified."
+msgstr ""
+
+#: doc/classes/TileMap.xml:253
+msgid ""
+"Returns the tilemap (grid-based) coordinates corresponding to the given "
+"local position."
+msgstr ""
+
+#: doc/classes/TileMap.xml:259
+msgid "If [code]true[/code], the cell's UVs will be clipped."
+msgstr ""
+
+#: doc/classes/TileMap.xml:262
+msgid "The custom [Transform2D] to be applied to the TileMap's cells."
+msgstr ""
+
+#: doc/classes/TileMap.xml:265
+msgid ""
+"Amount to offset alternating tiles. See [enum HalfOffset] for possible "
+"values."
+msgstr ""
+
+#: doc/classes/TileMap.xml:268
+msgid ""
+"The TileMap's quadrant size. Optimizes drawing by batching, using chunks of "
+"this size."
+msgstr ""
+
+#: doc/classes/TileMap.xml:271
+msgid "The TileMap's cell size."
+msgstr ""
+
+#: doc/classes/TileMap.xml:274
+msgid "Position for tile origin. See [enum TileOrigin] for possible values."
+msgstr ""
+
+#: doc/classes/TileMap.xml:277
+msgid ""
+"If [code]true[/code], the TileMap's children will be drawn in order of their "
+"Y coordinate."
+msgstr ""
+
+#: doc/classes/TileMap.xml:280
+msgid ""
+"If [code]true[/code], the textures will be centered in the middle of each "
+"tile. This is useful for certain isometric or top-down modes when textures "
+"are made larger or smaller than the tiles (e.g. to avoid flickering on tile "
+"edges). The offset is still applied, but from the center of the tile. If "
+"used, [member compatibility_mode] is ignored.\n"
+"If [code]false[/code], the texture position start in the top-left corner "
+"unless [member compatibility_mode] is enabled."
+msgstr ""
+
+#: doc/classes/TileMap.xml:284
+msgid ""
+"Bounce value for static body collisions (see [code]collision_use_kinematic[/"
+"code])."
+msgstr ""
+
+#: doc/classes/TileMap.xml:287
+msgid ""
+"Friction value for static body collisions (see "
+"[code]collision_use_kinematic[/code])."
+msgstr ""
+
+#: doc/classes/TileMap.xml:290
+msgid "The collision layer(s) for all colliders in the TileMap."
+msgstr ""
+
+#: doc/classes/TileMap.xml:293
+msgid "The collision mask(s) for all colliders in the TileMap."
+msgstr ""
+
+#: doc/classes/TileMap.xml:296
+msgid ""
+"If [code]true[/code], TileMap collisions will be handled as a kinematic "
+"body. If [code]false[/code], collisions will be handled as static body."
+msgstr ""
+
+#: doc/classes/TileMap.xml:299
+msgid ""
+"If [code]true[/code], this tilemap's collision shape will be added to the "
+"collision shape of the parent. The parent has to be a [CollisionObject2D]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:302
+msgid ""
+"If [code]true[/code], the compatibility with the tilemaps made in Godot 3.1 "
+"or earlier is maintained (textures move when the tile origin changes and "
+"rotate if the texture size is not homogeneous). This mode presents problems "
+"when doing [code]flip_h[/code], [code]flip_v[/code] and [code]transpose[/"
+"code] tile operations on non-homogeneous isometric tiles (e.g. 2:1), in "
+"which the texture could not coincide with the collision, thus it is not "
+"recommended for isometric or non-square tiles.\n"
+"If [code]false[/code], the textures do not move when doing [code]flip_h[/"
+"code], [code]flip_v[/code] operations if no offset is used, nor when "
+"changing the tile origin.\n"
+"The compatibility mode doesn't work with the [member centered_textures] "
+"option, because displacing textures with the [member cell_tile_origin] "
+"option or in irregular tiles is not relevant when centering those textures."
+msgstr ""
+
+#: doc/classes/TileMap.xml:307
+msgid "The TileMap orientation mode. See [enum Mode] for possible values."
+msgstr ""
+
+#: doc/classes/TileMap.xml:310
+msgid ""
+"The light mask assigned to all light occluders in the TileMap. The TileSet's "
+"light occluders will cast shadows only from Light2D(s) that have the same "
+"light mask(s)."
+msgstr ""
+
+#: doc/classes/TileMap.xml:313
+msgid "The assigned [TileSet]."
+msgstr ""
+
+#: doc/classes/TileMap.xml:319
+msgid "Emitted when a tilemap setting has changed."
+msgstr ""
+
+#: doc/classes/TileMap.xml:325
+msgid "Returned when a cell doesn't exist."
+msgstr ""
+
+#: doc/classes/TileMap.xml:328
+msgid "Orthogonal orientation mode."
+msgstr ""
+
+#: doc/classes/TileMap.xml:331
+msgid "Isometric orientation mode."
+msgstr ""
+
+#: doc/classes/TileMap.xml:334
+msgid "Custom orientation mode."
+msgstr ""
+
+#: doc/classes/TileMap.xml:337
+msgid "Half offset on the X coordinate."
+msgstr ""
+
+#: doc/classes/TileMap.xml:340
+msgid "Half offset on the Y coordinate."
+msgstr ""
+
+#: doc/classes/TileMap.xml:343
+msgid "Half offset disabled."
+msgstr ""
+
+#: doc/classes/TileMap.xml:346
+msgid "Half offset on the X coordinate (negative)."
+msgstr ""
+
+#: doc/classes/TileMap.xml:349
+msgid "Half offset on the Y coordinate (negative)."
+msgstr ""
+
+#: doc/classes/TileMap.xml:352
+msgid "Tile origin at its top-left corner."
+msgstr ""
+
+#: doc/classes/TileMap.xml:355
+msgid "Tile origin at its center."
+msgstr ""
+
+#: doc/classes/TileMap.xml:358
+msgid "Tile origin at its bottom-left corner."
+msgstr ""
+
+#: doc/classes/TileSet.xml:4
+msgid "Tile library for tilemaps."
+msgstr ""
+
+#: doc/classes/TileSet.xml:7
+msgid ""
+"A TileSet is a library of tiles for a [TileMap]. It contains a list of "
+"tiles, each consisting of a sprite and optional collision shapes.\n"
+"Tiles are referenced by a unique integer ID."
+msgstr ""
+
+#: doc/classes/TileSet.xml:55
+msgid "Clears all bitmask information of the autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:66
+msgid ""
+"Returns the bitmask of the subtile from an autotile given its coordinates.\n"
+"The value is the sum of the values in [enum AutotileBindings] present in the "
+"subtile (e.g. a value of 5 means the bitmask has bindings in both the top "
+"left and top right)."
+msgstr ""
+
+#: doc/classes/TileSet.xml:76
+msgid "Returns the [enum BitmaskMode] of the autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:85
+msgid ""
+"Returns the subtile that's being used as an icon in an atlas/autotile given "
+"its coordinates.\n"
+"The subtile defined as the icon will be used as a fallback when the atlas/"
+"autotile's bitmask information is incomplete. It will also be used to "
+"represent it in the TileSet editor."
+msgstr ""
+
+#: doc/classes/TileSet.xml:97
+msgid ""
+"Returns the light occluder of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:108
+msgid ""
+"Returns the navigation polygon of the subtile from an atlas/autotile given "
+"its coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:117
+msgid "Returns the size of the subtiles in an atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:126
+msgid "Returns the spacing between subtiles of the atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:137
+msgid ""
+"Returns the priority of the subtile from an autotile given its coordinates.\n"
+"When more than one subtile has the same bitmask value, one of them will be "
+"picked randomly for drawing. Its priority will define how often it will be "
+"picked."
+msgstr ""
+
+#: doc/classes/TileSet.xml:149
+msgid ""
+"Returns the drawing index of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:162
+msgid ""
+"Sets the bitmask of the subtile from an autotile given its coordinates.\n"
+"The value is the sum of the values in [enum AutotileBindings] present in the "
+"subtile (e.g. a value of 5 means the bitmask has bindings in both the top "
+"left and top right)."
+msgstr ""
+
+#: doc/classes/TileSet.xml:174
+msgid "Sets the [enum BitmaskMode] of the autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:185
+msgid ""
+"Sets the subtile that will be used as an icon in an atlas/autotile given its "
+"coordinates.\n"
+"The subtile defined as the icon will be used as a fallback when the atlas/"
+"autotile's bitmask information is incomplete. It will also be used to "
+"represent it in the TileSet editor."
+msgstr ""
+
+#: doc/classes/TileSet.xml:199
+msgid ""
+"Sets the light occluder of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:212
+msgid ""
+"Sets the navigation polygon of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:223
+msgid "Sets the size of the subtiles in an atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:234
+msgid "Sets the spacing between subtiles of the atlas/autotile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:247
+msgid ""
+"Sets the priority of the subtile from an autotile given its coordinates.\n"
+"When more than one subtile has the same bitmask value, one of them will be "
+"picked randomly for drawing. Its priority will define how often it will be "
+"picked."
+msgstr ""
+
+#: doc/classes/TileSet.xml:261
+msgid ""
+"Sets the drawing index of the subtile from an atlas/autotile given its "
+"coordinates."
+msgstr ""
+
+#: doc/classes/TileSet.xml:268
+msgid "Clears all tiles."
+msgstr ""
+
+#: doc/classes/TileSet.xml:277
+msgid "Creates a new tile with the given ID."
+msgstr ""
+
+#: doc/classes/TileSet.xml:286
+msgid "Returns the first tile matching the given name."
+msgstr ""
+
+#: doc/classes/TileSet.xml:293
+msgid ""
+"Returns the ID following the last currently used ID, useful when creating a "
+"new tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:300
+msgid "Returns an array of all currently used tile IDs."
+msgstr ""
+
+#: doc/classes/TileSet.xml:309
+msgid "Removes the given tile ID."
+msgstr ""
+
+#: doc/classes/TileSet.xml:326
+msgid "Adds a shape to the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:335
+msgid "Returns the tile's light occluder."
+msgstr ""
+
+#: doc/classes/TileSet.xml:344
+msgid "Returns the tile's material."
+msgstr ""
+
+#: doc/classes/TileSet.xml:353
+msgid "Returns the tile's modulation color."
+msgstr ""
+
+#: doc/classes/TileSet.xml:362
+msgid "Returns the tile's name."
+msgstr ""
+
+#: doc/classes/TileSet.xml:371
+msgid "Returns the navigation polygon of the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:380
+msgid "Returns the offset of the tile's navigation polygon."
+msgstr ""
+
+#: doc/classes/TileSet.xml:389
+msgid "Returns the tile's normal map texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:398
+msgid "Returns the offset of the tile's light occluder."
+msgstr ""
+
+#: doc/classes/TileSet.xml:407
+msgid "Returns the tile sub-region in the texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:418
+msgid "Returns a tile's given shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:427
+msgid "Returns the number of shapes assigned to a tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:438
+msgid "Returns the offset of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:449
+msgid "Returns the one-way collision value of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:470
+msgid "Returns the [Transform2D] of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:479
+msgid "Returns an array of the tile's shapes."
+msgstr ""
+
+#: doc/classes/TileSet.xml:488
+msgid "Returns the tile's texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:497
+msgid "Returns the texture offset of the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:506
+msgid "Returns the tile's [enum TileMode]."
+msgstr ""
+
+#: doc/classes/TileSet.xml:515
+msgid "Returns the tile's Z index (drawing layer)."
+msgstr ""
+
+#: doc/classes/TileSet.xml:526
+msgid "Sets a light occluder for the tile."
+msgstr ""
+
+#: doc/classes/TileSet.xml:537
+msgid "Sets the tile's material."
+msgstr ""
+
+#: doc/classes/TileSet.xml:548
+msgid "Sets the tile's modulation color."
+msgstr ""
+
+#: doc/classes/TileSet.xml:559
+msgid "Sets the tile's name."
+msgstr ""
+
+#: doc/classes/TileSet.xml:570
+msgid "Sets the tile's navigation polygon."
+msgstr ""
+
+#: doc/classes/TileSet.xml:581
+msgid "Sets an offset for the tile's navigation polygon."
+msgstr ""
+
+#: doc/classes/TileSet.xml:592
+msgid "Sets the tile's normal map texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:603
+msgid "Sets an offset for the tile's light occluder."
+msgstr ""
+
+#: doc/classes/TileSet.xml:614
+msgid ""
+"Sets the tile's sub-region in the texture. This is common in texture atlases."
+msgstr ""
+
+#: doc/classes/TileSet.xml:627
+msgid "Sets a shape for the tile, enabling collision."
+msgstr ""
+
+#: doc/classes/TileSet.xml:640
+msgid "Sets the offset of a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:653
+msgid "Enables one-way collision on a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:678
+msgid "Sets a [Transform2D] on a tile's shape."
+msgstr ""
+
+#: doc/classes/TileSet.xml:689
+msgid "Sets an array of shapes for the tile, enabling collision."
+msgstr ""
+
+#: doc/classes/TileSet.xml:700
+msgid "Sets the tile's texture."
+msgstr ""
+
+#: doc/classes/TileSet.xml:711
+msgid "Sets the tile's texture offset."
+msgstr ""
+
+#: doc/classes/TileSet.xml:722
+msgid "Sets the tile's [enum TileMode]."
+msgstr ""
+
+#: doc/classes/TileSet.xml:733
+msgid "Sets the tile's drawing index."
+msgstr ""
+
+#: doc/classes/Timer.xml:4
+msgid "A countdown timer."
+msgstr ""
+
+#: doc/classes/Timer.xml:7
+msgid ""
+"Counts down a specified interval and emits a signal on reaching 0. Can be "
+"set to repeat or \"one-shot\" mode."
+msgstr ""
+
+#: doc/classes/Timer.xml:16
+msgid "Returns [code]true[/code] if the timer is stopped."
+msgstr ""
+
+#: doc/classes/Timer.xml:25
+msgid ""
+"Starts the timer. Sets [code]wait_time[/code] to [code]time_sec[/code] if "
+"[code]time_sec > 0[/code]. This also resets the remaining time to "
+"[code]wait_time[/code].\n"
+"[b]Note:[/b] this method will not resume a paused timer. See [member paused]."
+msgstr ""
+
+#: doc/classes/Timer.xml:33
+msgid "Stops the timer."
+msgstr ""
+
+#: doc/classes/Timer.xml:39
+msgid ""
+"If [code]true[/code], the timer will automatically start when entering the "
+"scene tree.\n"
+"[b]Note:[/b] This property is automatically set to [code]false[/code] after "
+"the timer enters the scene tree and starts."
+msgstr ""
+
+#: doc/classes/Timer.xml:43
+msgid ""
+"If [code]true[/code], the timer will stop when reaching 0. If [code]false[/"
+"code], it will restart."
+msgstr ""
+
+#: doc/classes/Timer.xml:46
+msgid ""
+"If [code]true[/code], the timer is paused and will not process until it is "
+"unpaused again, even if [method start] is called."
+msgstr ""
+
+#: doc/classes/Timer.xml:49
+msgid "Processing mode. See [enum TimerProcessMode]."
+msgstr ""
+
+#: doc/classes/Timer.xml:52
+msgid ""
+"The timer's remaining time in seconds. Returns 0 if the timer is inactive.\n"
+"[b]Note:[/b] You cannot set this value. To change the timer's remaining "
+"time, use [method start]."
+msgstr ""
+
+#: doc/classes/Timer.xml:56
+msgid "Wait time in seconds."
+msgstr ""
+
+#: doc/classes/Timer.xml:68
+msgid ""
+"Update the timer during the physics step at each frame (fixed framerate "
+"processing)."
+msgstr ""
+
+#: doc/classes/Timer.xml:71
+msgid "Update the timer during the idle time at each frame."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:4
+msgid "Flat button helper class."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:7
+msgid ""
+"This is a helper class to generate a flat [Button] (see [member Button."
+"flat]), creating a [ToolButton] is equivalent to:\n"
+"[codeblock]\n"
+"var btn = Button.new()\n"
+"btn.flat = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/ToolButton.xml:24
+msgid "[StyleBox] used when the [ToolButton] is disabled."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:27
+msgid ""
+"[StyleBox] used when the [ToolButton] is focused. It is displayed over the "
+"current [StyleBox], so using [StyleBoxEmpty] will just disable the focus "
+"visual effect."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:30
+msgid "[Font] of the [ToolButton]'s text."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:33
+msgid "Default text [Color] of the [ToolButton]."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:36
+msgid "Text [Color] used when the [ToolButton] is disabled."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:39
+msgid "Text [Color] used when the [ToolButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:42
+msgid "Text [Color] used when the [ToolButton] is being pressed."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:45
+msgid "[StyleBox] used when the [ToolButton] is being hovered."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:48
+msgid "The horizontal space between [ToolButton]'s icon and text."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:51
+msgid "Default [StyleBox] for the [ToolButton]."
+msgstr ""
+
+#: doc/classes/ToolButton.xml:54
+msgid "[StyleBox] used when the [ToolButton] is being pressed."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:4
+msgid "Button for touch screen devices."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:7
+msgid ""
+"Button for touch screen devices. You can set it to be visible on all "
+"screens, or only on touch devices."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:16
+msgid "Returns [code]true[/code] if this button is currently pressed."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:22
+msgid "The button's action. Actions can be handled with [InputEventAction]."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:25
+msgid "The button's bitmask."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:28
+msgid "The button's texture for the normal state."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:31
+msgid "If [code]true[/code], pass-by presses are enabled."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:34
+msgid "The button's texture for the pressed state."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:37
+msgid "The button's shape."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:40
+msgid ""
+"If [code]true[/code], the button's shape is centered in the provided "
+"texture. If no texture is used, this property has no effect."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:43
+msgid "If [code]true[/code], the button's shape is visible."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:46
+msgid ""
+"The button's visibility mode. See [enum VisibilityMode] for possible values."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:52
+msgid "Emitted when the button is pressed (down)."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:57
+msgid "Emitted when the button is released (up)."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:63
+msgid "Always visible."
+msgstr ""
+
+#: doc/classes/TouchScreenButton.xml:66
+msgid "Visible on touch screens only."
+msgstr ""
+
+#: doc/classes/Transform.xml:4
+msgid "3D transformation (3×4 matrix)."
+msgstr ""
+
+#: doc/classes/Transform.xml:7
+msgid ""
+"Represents one or many transformations in 3D space such as translation, "
+"rotation, or scaling. It consists of a [member basis] and an [member "
+"origin]. It is similar to a 3×4 matrix."
+msgstr ""
+
+#: doc/classes/Transform.xml:26
+msgid ""
+"Constructs the Transform from four [Vector3]. Each axis corresponds to local "
+"basis vectors (some of which may be scaled)."
+msgstr ""
+
+#: doc/classes/Transform.xml:37
+msgid "Constructs the Transform from a [Basis] and [Vector3]."
+msgstr ""
+
+#: doc/classes/Transform.xml:46
+msgid "Constructs the Transform from a [Transform2D]."
+msgstr ""
+
+#: doc/classes/Transform.xml:55
+msgid ""
+"Constructs the Transform from a [Quat]. The origin will be Vector3(0, 0, 0)."
+msgstr ""
+
+#: doc/classes/Transform.xml:64
+msgid ""
+"Constructs the Transform from a [Basis]. The origin will be Vector3(0, 0, 0)."
+msgstr ""
+
+#: doc/classes/Transform.xml:71
+msgid ""
+"Returns the inverse of the transform, under the assumption that the "
+"transformation is composed of rotation, scaling and translation."
+msgstr ""
+
+#: doc/classes/Transform.xml:82
+msgid "Interpolates the transform to other Transform by weight amount (0-1)."
+msgstr ""
+
+#: doc/classes/Transform.xml:89 doc/classes/Transform2D.xml:106
+msgid ""
+"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)."
+msgstr ""
+
+#: doc/classes/Transform.xml:98 doc/classes/Transform2D.xml:115
+msgid ""
+"Returns [code]true[/code] if this transform and [code]transform[/code] are "
+"approximately equal, by calling [code]is_equal_approx[/code] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Transform.xml:109
+msgid ""
+"Returns a copy of the transform rotated such that its -Z axis points towards "
+"the [code]target[/code] position.\n"
+"The transform will first be rotated around the given [code]up[/code] vector, "
+"and then fully aligned to the target by a further rotation around an axis "
+"perpendicular to both the [code]target[/code] and [code]up[/code] vectors.\n"
+"Operations take place in global space."
+msgstr ""
+
+#: doc/classes/Transform.xml:118 doc/classes/Transform2D.xml:122
+msgid ""
+"Returns the transform with the basis orthogonal (90 degrees), and normalized "
+"axis vectors."
+msgstr ""
+
+#: doc/classes/Transform.xml:129
+msgid ""
+"Rotates the transform around the given axis by the given angle (in radians), "
+"using matrix multiplication. The axis must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Transform.xml:138 doc/classes/Transform2D.xml:140
+msgid ""
+"Scales the transform by the given scale factor, using matrix multiplication."
+msgstr ""
+
+#: doc/classes/Transform.xml:147 doc/classes/Transform2D.xml:149
+msgid ""
+"Translates the transform by the given offset, relative to the transform's "
+"basis vectors.\n"
+"Unlike [method rotated] and [method scaled], this does not use matrix "
+"multiplication."
+msgstr ""
+
+#: doc/classes/Transform.xml:157
+msgid ""
+"Transforms the given [Vector3], [Plane], [AABB], or [PackedVector3Array] by "
+"this transform."
+msgstr ""
+
+#: doc/classes/Transform.xml:166
+msgid ""
+"Inverse-transforms the given [Vector3], [Plane], [AABB], or "
+"[PackedVector3Array] by this transform."
+msgstr ""
+
+#: doc/classes/Transform.xml:172
+msgid ""
+"The basis is a matrix containing 3 [Vector3] as its columns: X axis, Y axis, "
+"and Z axis. These vectors can be interpreted as the basis vectors of local "
+"coordinate system traveling with the object."
+msgstr ""
+
+#: doc/classes/Transform.xml:175
+msgid "The translation offset of the transform."
+msgstr ""
+
+#: doc/classes/Transform.xml:180
+msgid ""
+"[Transform] with no translation, rotation or scaling applied. When applied "
+"to other data structures, [constant IDENTITY] performs no transformation."
+msgstr ""
+
+#: doc/classes/Transform.xml:183
+msgid "[Transform] with mirroring applied perpendicular to the YZ plane."
+msgstr ""
+
+#: doc/classes/Transform.xml:186
+msgid "[Transform] with mirroring applied perpendicular to the XZ plane."
+msgstr ""
+
+#: doc/classes/Transform.xml:189
+msgid "[Transform] with mirroring applied perpendicular to the XY plane."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:4
+msgid "2D transformation (3×2 matrix)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:7
+msgid ""
+"Represents one or many transformations in 2D space such as translation, "
+"rotation, or scaling. It consists of two [member x] and [member y] "
+"[Vector2]s and an [member origin]. It is similar to a 3×2 matrix."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:18
+msgid "Constructs the transform from a 3D [Transform]."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:31
+msgid ""
+"Constructs the transform from 3 [Vector2]s representing x, y, and origin."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:42
+msgid "Constructs the transform from a given angle (in radians) and position."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:58
+msgid "Transforms the given vector by this transform's basis (no translation)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:67
+msgid ""
+"Inverse-transforms the given vector by this transform's basis (no "
+"translation)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:74
+msgid "Returns the transform's origin (translation)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:81
+msgid "Returns the transform's rotation (in radians)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:88
+msgid "Returns the scale."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:99
+msgid ""
+"Returns a transform interpolated between this transform and another by a "
+"given weight (0-1)."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:131
+msgid ""
+"Rotates the transform by the given angle (in radians), using matrix "
+"multiplication."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:159
+msgid ""
+"Transforms the given [Vector2], [Rect2], or [PackedVector2Array] by this "
+"transform."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:168
+msgid ""
+"Inverse-transforms the given [Vector2], [Rect2], or [PackedVector2Array] by "
+"this transform."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:174
+msgid "The transform's translation offset."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:177
+msgid ""
+"The X axis of 2×2 basis matrix containing 2 [Vector2]s as its columns: X "
+"axis and Y axis. These vectors can be interpreted as the basis vectors of "
+"local coordinate system traveling with the object."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:180
+msgid ""
+"The Y axis of 2×2 basis matrix containing 2 [Vector2]s as its columns: X "
+"axis and Y axis. These vectors can be interpreted as the basis vectors of "
+"local coordinate system traveling with the object."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:185
+msgid ""
+"[Transform2D] with no translation, rotation or scaling applied. When applied "
+"to other data structures, [constant IDENTITY] performs no transformation."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:188
+msgid "[Transform2D] with mirroring applied parallel to the X axis."
+msgstr ""
+
+#: doc/classes/Transform2D.xml:191
+msgid "[Transform2D] with mirroring applied parallel to the Y axis."
+msgstr ""
+
+#: doc/classes/Translation.xml:4
+msgid "Language Translation."
+msgstr ""
+
+#: doc/classes/Translation.xml:7
+msgid ""
+"Translations are resources that can be loaded and unloaded on demand. They "
+"map a string to another string."
+msgstr ""
+
+#: doc/classes/Translation.xml:10 doc/classes/TranslationServer.xml:10
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/i18n/"
+"internationalizing_games.html"
+msgstr ""
+
+#: doc/classes/Translation.xml:11 doc/classes/TranslationServer.xml:11
+msgid "https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html"
+msgstr ""
+
+#: doc/classes/Translation.xml:22
+msgid "Adds a message if nonexistent, followed by its translation."
+msgstr ""
+
+#: doc/classes/Translation.xml:31
+msgid "Erases a message."
+msgstr ""
+
+#: doc/classes/Translation.xml:40
+msgid "Returns a message's translation."
+msgstr ""
+
+#: doc/classes/Translation.xml:47
+msgid "Returns the number of existing messages."
+msgstr ""
+
+#: doc/classes/Translation.xml:54
+msgid "Returns all the messages (keys)."
+msgstr ""
+
+#: doc/classes/Translation.xml:60
+msgid "The locale of the translation."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:4
+msgid "Server that manages all translations."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:7
+msgid ""
+"Server that manages all translations. Translations can be set to it and "
+"removed from it."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:20
+msgid "Adds a [Translation] resource."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:27
+msgid "Clears the server from all translations."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:34
+msgid "Returns an Array of all loaded locales of the game."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:41
+msgid "Returns the current locale of the game."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:50
+msgid ""
+"Returns a locale's language and its variant (e.g. [code]\"en_US\"[/code] "
+"would return [code]\"English (United States)\"[/code])."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:59
+msgid "Removes the given translation from the server."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:68
+msgid "Sets the locale of the game."
+msgstr ""
+
+#: doc/classes/TranslationServer.xml:77
+msgid "Returns the current locale's translation for the given message (key)."
+msgstr ""
+
+#: doc/classes/Tree.xml:4
+msgid "Control to show a tree of items."
+msgstr ""
+
+#: doc/classes/Tree.xml:7
+msgid ""
+"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.\n"
+"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.\n"
+"[codeblock]\n"
+"func _ready():\n"
+" var tree = Tree.new()\n"
+" var root = tree.create_item()\n"
+" tree.set_hide_root(true)\n"
+" var child1 = tree.create_item(root)\n"
+" var child2 = tree.create_item(root)\n"
+" var subchild1 = tree.create_item(child1)\n"
+" subchild1.set_text(0, \"Subchild1\")\n"
+"[/codeblock]\n"
+"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]."
+msgstr ""
+
+#: doc/classes/Tree.xml:28
+msgid "Returns [code]true[/code] if the column titles are being shown."
+msgstr ""
+
+#: doc/classes/Tree.xml:35
+msgid "Clears the tree. This removes all items."
+msgstr ""
+
+#: doc/classes/Tree.xml:46
+msgid ""
+"Creates an item in the tree and adds it as a child of [code]parent[/code].\n"
+"If [code]parent[/code] is [code]null[/code], the root item will be the "
+"parent, or the new item will be the root itself if the tree is empty.\n"
+"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."
+msgstr ""
+
+#: doc/classes/Tree.xml:55
+msgid ""
+"Makes the currently focused cell visible.\n"
+"This will scroll the tree if necessary. In [constant SELECT_ROW] mode, this "
+"will not do horizontal scrolling, as all the cells in the selected row is "
+"focused logically.\n"
+"[b]Note:[/b] Despite the name of this method, the focus cursor itself is "
+"only visible in [constant SELECT_MULTI] mode."
+msgstr ""
+
+#: doc/classes/Tree.xml:66
+msgid ""
+"Returns the column index at [code]position[/code], or -1 if no item is there."
+msgstr ""
+
+#: doc/classes/Tree.xml:75
+msgid "Returns the column's title."
+msgstr ""
+
+#: doc/classes/Tree.xml:84
+msgid "Returns the column's width in pixels."
+msgstr ""
+
+#: doc/classes/Tree.xml:91
+msgid ""
+"Returns the rectangle for custom popups. Helper to create custom cell "
+"controls that display a popup. See [method TreeItem.set_cell_mode]."
+msgstr ""
+
+#: doc/classes/Tree.xml:100
+msgid ""
+"Returns the drop section at [code]position[/code], or -100 if no item is "
+"there.\n"
+"Values -1, 0, or 1 will be returned for the \"above item\", \"on item\", and "
+"\"below item\" drop sections, respectively. See [enum DropModeFlags] for a "
+"description of each drop section.\n"
+"To get the item which the returned drop section is relative to, use [method "
+"get_item_at_position]."
+msgstr ""
+
+#: doc/classes/Tree.xml:109
+msgid ""
+"Returns the currently edited item. This is only available for custom cell "
+"mode."
+msgstr ""
+
+#: doc/classes/Tree.xml:116
+msgid ""
+"Returns the column for the currently edited item. This is only available for "
+"custom cell mode."
+msgstr ""
+
+#: doc/classes/Tree.xml:127
+msgid ""
+"Returns the rectangle area for the specified item. If [code]column[/code] is "
+"specified, only get the position and size of that column, otherwise get the "
+"rectangle containing all columns."
+msgstr ""
+
+#: doc/classes/Tree.xml:136
+msgid ""
+"Returns the tree item at the specified position (relative to the tree origin "
+"position)."
+msgstr ""
+
+#: doc/classes/Tree.xml:145
+msgid ""
+"Returns the next selected item after the given one, or [code]null[/code] if "
+"the end is reached.\n"
+"If [code]from[/code] is [code]null[/code], this returns the first selected "
+"item."
+msgstr ""
+
+#: doc/classes/Tree.xml:153
+msgid "Returns the last pressed button's index."
+msgstr ""
+
+#: doc/classes/Tree.xml:160
+msgid ""
+"Returns the tree's root item, or [code]null[/code] if the tree is empty."
+msgstr ""
+
+#: doc/classes/Tree.xml:167
+msgid "Returns the current scrolling position."
+msgstr ""
+
+#: doc/classes/Tree.xml:174
+msgid ""
+"Returns the currently focused item, or [code]null[/code] if no item is "
+"focused.\n"
+"In [constant SELECT_ROW] and [constant SELECT_SINGLE] modes, the focused "
+"item is same as the selected item. In [constant SELECT_MULTI] mode, the "
+"focused item is the item under the focus cursor, not necessarily selected.\n"
+"To get the currently selected item(s), use [method get_next_selected]."
+msgstr ""
+
+#: doc/classes/Tree.xml:183
+msgid ""
+"Returns the currently focused column, or -1 if no column is focused.\n"
+"In [constant SELECT_SINGLE] mode, the focused column is the selected column. "
+"In [constant SELECT_ROW] mode, the focused column is always 0 if any item is "
+"selected. In [constant SELECT_MULTI] mode, the focused column is the column "
+"under the focus cursor, and there are not necessarily any column selected.\n"
+"To tell whether a column of an item is selected, use [method TreeItem."
+"is_selected]."
+msgstr ""
+
+#: doc/classes/Tree.xml:196
+msgid ""
+"If [code]true[/code], the column will have the \"Expand\" flag of [Control]. "
+"Columns that have the \"Expand\" flag will use their \"min_width\" in a "
+"similar fashion to [member Control.size_flags_stretch_ratio]."
+msgstr ""
+
+#: doc/classes/Tree.xml:207
+msgid ""
+"Sets the minimum width of a column. Columns that have the \"Expand\" flag "
+"will use their \"min_width\" in a similar fashion to [member Control."
+"size_flags_stretch_ratio]."
+msgstr ""
+
+#: doc/classes/Tree.xml:218
+msgid "Sets the title of a column."
+msgstr ""
+
+#: doc/classes/Tree.xml:227
+msgid "If [code]true[/code], column titles are visible."
+msgstr ""
+
+#: doc/classes/Tree.xml:233
+msgid ""
+"If [code]true[/code], the currently selected cell may be selected again."
+msgstr ""
+
+#: doc/classes/Tree.xml:236
+msgid "If [code]true[/code], a right mouse button click can select items."
+msgstr ""
+
+#: doc/classes/Tree.xml:239
+msgid "The number of columns."
+msgstr ""
+
+#: doc/classes/Tree.xml:242
+msgid ""
+"The drop mode as an OR combination of flags. See [enum DropModeFlags] "
+"constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. "
+"Setting this during [method Control.can_drop_data] is recommended.\n"
+"This controls the drop sections, i.e. the decision and drawing of possible "
+"drop locations based on the mouse position."
+msgstr ""
+
+#: doc/classes/Tree.xml:247
+msgid "If [code]true[/code], the folding arrow is hidden."
+msgstr ""
+
+#: doc/classes/Tree.xml:250
+msgid "If [code]true[/code], the tree's root is hidden."
+msgstr ""
+
+#: doc/classes/Tree.xml:254
+msgid ""
+"Allows single or multiple selection. See the [enum SelectMode] constants."
+msgstr ""
+
+#: doc/classes/Tree.xml:266
+msgid ""
+"Emitted when a button on the tree was pressed (see [method TreeItem."
+"add_button])."
+msgstr ""
+
+#: doc/classes/Tree.xml:271
+msgid "Emitted when a cell is selected."
+msgstr ""
+
+#: doc/classes/Tree.xml:278
+msgid "Emitted when a column's title is pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:285
+msgid ""
+"Emitted when a cell with the [constant TreeItem.CELL_MODE_CUSTOM] is clicked "
+"to be edited."
+msgstr ""
+
+#: doc/classes/Tree.xml:292
+msgid ""
+"Emitted when the right mouse button is pressed in the empty space of the "
+"tree."
+msgstr ""
+
+#: doc/classes/Tree.xml:299
+msgid ""
+"Emitted when the right mouse button is pressed if right mouse button "
+"selection is active and the tree is empty."
+msgstr ""
+
+#: doc/classes/Tree.xml:304
+msgid "Emitted when an item's label is double-clicked."
+msgstr ""
+
+#: doc/classes/Tree.xml:311
+msgid "Emitted when an item is collapsed by a click on the folding arrow."
+msgstr ""
+
+#: doc/classes/Tree.xml:316
+msgid ""
+"Emitted when a custom button is pressed (i.e. in a [constant TreeItem."
+"CELL_MODE_CUSTOM] mode cell)."
+msgstr ""
+
+#: doc/classes/Tree.xml:321
+msgid "Emitted when an item's icon is double-clicked."
+msgstr ""
+
+#: doc/classes/Tree.xml:326
+msgid "Emitted when an item is edited."
+msgstr ""
+
+#: doc/classes/Tree.xml:331
+msgid "Emitted when an item is edited using the right mouse button."
+msgstr ""
+
+#: doc/classes/Tree.xml:338
+msgid "Emitted when an item is selected with the right mouse button."
+msgstr ""
+
+#: doc/classes/Tree.xml:343
+msgid "Emitted when an item is selected."
+msgstr ""
+
+#: doc/classes/Tree.xml:354
+msgid ""
+"Emitted instead of [code]item_selected[/code] if [code]select_mode[/code] is "
+"[constant SELECT_MULTI]."
+msgstr ""
+
+#: doc/classes/Tree.xml:359
+msgid "Emitted when a left mouse button click does not select any item."
+msgstr ""
+
+#: doc/classes/Tree.xml:365
+msgid ""
+"Allows selection of a single cell at a time. From the perspective of items, "
+"only a single item is allowed to be selected. And there is only one column "
+"selected in the selected item.\n"
+"The focus cursor is always hidden in this mode, but it is positioned at the "
+"current selection, making the currently selected item the currently focused "
+"item."
+msgstr ""
+
+#: doc/classes/Tree.xml:369
+msgid ""
+"Allows selection of a single row at a time. From the perspective of items, "
+"only a single items is allowed to be selected. And all the columns are "
+"selected in the selected item.\n"
+"The focus cursor is always hidden in this mode, but it is positioned at the "
+"first column of the current selection, making the currently selected item "
+"the currently focused item."
+msgstr ""
+
+#: doc/classes/Tree.xml:373
+msgid ""
+"Allows selection of multiple cells at the same time. From the perspective of "
+"items, multiple items are allowed to be selected. And there can be multiple "
+"columns selected in each selected item.\n"
+"The focus cursor is visible in this mode, the item or column under the "
+"cursor is not necessarily selected."
+msgstr ""
+
+#: doc/classes/Tree.xml:377
+msgid ""
+"Disables all drop sections, but still allows to detect the \"on item\" drop "
+"section by [method get_drop_section_at_position].\n"
+"[b]Note:[/b] This is the default flag, it has no effect when combined with "
+"other flags."
+msgstr ""
+
+#: doc/classes/Tree.xml:381
+msgid ""
+"Enables the \"on item\" drop section. This drop section covers the entire "
+"item.\n"
+"When combined with [constant DROP_MODE_INBETWEEN], this drop section halves "
+"the height and stays centered vertically."
+msgstr ""
+
+#: doc/classes/Tree.xml:385
+msgid ""
+"Enables \"above item\" and \"below item\" drop sections. The \"above item\" "
+"drop section covers the top half of the item, and the \"below item\" drop "
+"section covers the bottom half.\n"
+"When combined with [constant DROP_MODE_ON_ITEM], these drop sections halves "
+"the height and stays on top / bottom accordingly."
+msgstr ""
+
+#: doc/classes/Tree.xml:391
+msgid "The arrow icon used when a foldable item is not collapsed."
+msgstr ""
+
+#: doc/classes/Tree.xml:394
+msgid "The arrow icon used when a foldable item is collapsed."
+msgstr ""
+
+#: doc/classes/Tree.xml:397
+msgid ""
+"Default [StyleBox] for the [Tree], i.e. used when the control is not being "
+"focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:400
+msgid "[StyleBox] used when the [Tree] is being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:403
+msgid "The horizontal space between each button in a cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:406
+msgid "[StyleBox] used when a button in the tree is pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:409
+msgid ""
+"The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode "
+"cell is checked."
+msgstr ""
+
+#: doc/classes/Tree.xml:412
+msgid "[StyleBox] used for the cursor, when the [Tree] is being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:415
+msgid "[StyleBox] used for the cursor, when the [Tree] is not being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:418
+msgid ""
+"Default [StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:421
+msgid ""
+"Text [Color] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's "
+"hovered."
+msgstr ""
+
+#: doc/classes/Tree.xml:424
+msgid ""
+"[StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's "
+"hovered."
+msgstr ""
+
+#: doc/classes/Tree.xml:427
+msgid ""
+"[StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's "
+"pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:430
+msgid ""
+"Draws the guidelines if not zero, this acts as a boolean. The guideline is a "
+"horizontal line drawn at the bottom of each item."
+msgstr ""
+
+#: doc/classes/Tree.xml:433
+msgid ""
+"Draws the relationship lines if not zero, this acts as a boolean. "
+"Relationship lines are drawn at the start of child items to show hierarchy."
+msgstr ""
+
+#: doc/classes/Tree.xml:436
+msgid ""
+"[Color] used to draw possible drop locations. See [enum DropModeFlags] "
+"constants for further description of drop locations."
+msgstr ""
+
+#: doc/classes/Tree.xml:448
+msgid "[Color] of the guideline."
+msgstr ""
+
+#: doc/classes/Tree.xml:451
+msgid ""
+"The horizontal space between item cells. This is also used as the margin at "
+"the start of an item when folding is disabled."
+msgstr ""
+
+#: doc/classes/Tree.xml:454
+msgid ""
+"The horizontal margin at the start of an item. This is used when folding is "
+"enabled for the item."
+msgstr ""
+
+#: doc/classes/Tree.xml:457
+msgid "[Color] of the relationship lines."
+msgstr ""
+
+#: doc/classes/Tree.xml:460
+msgid ""
+"The maximum distance between the mouse cursor and the control's border to "
+"trigger border scrolling when dragging."
+msgstr ""
+
+#: doc/classes/Tree.xml:463
+msgid "The speed of border scrolling."
+msgstr ""
+
+#: doc/classes/Tree.xml:466
+msgid ""
+"The arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] mode "
+"cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:469
+msgid ""
+"[StyleBox] for the selected items, used when the [Tree] is not being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:472
+msgid ""
+"[StyleBox] for the selected items, used when the [Tree] is being focused."
+msgstr ""
+
+#: doc/classes/Tree.xml:475
+msgid "Default text [Color] of the title button."
+msgstr ""
+
+#: doc/classes/Tree.xml:478
+msgid "[Font] of the title button's text."
+msgstr ""
+
+#: doc/classes/Tree.xml:481
+msgid "[StyleBox] used when the title button is being hovered."
+msgstr ""
+
+#: doc/classes/Tree.xml:484
+msgid "Default [StyleBox] for the title button."
+msgstr ""
+
+#: doc/classes/Tree.xml:487
+msgid "[StyleBox] used when the title button is being pressed."
+msgstr ""
+
+#: doc/classes/Tree.xml:490
+msgid ""
+"The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode "
+"cell is unchecked."
+msgstr ""
+
+#: doc/classes/Tree.xml:493
+msgid ""
+"The updown arrow icon to display for the [constant TreeItem.CELL_MODE_RANGE] "
+"mode cell."
+msgstr ""
+
+#: doc/classes/Tree.xml:496
+msgid ""
+"The vertical padding inside each item, i.e. the distance between the item's "
+"content and top/bottom border."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:4
+msgid "Control for a single item inside a [Tree]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:7
+msgid ""
+"Control for a single item inside a [Tree]. May have child [TreeItem]s and be "
+"styled as well as contain buttons."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:26
+msgid ""
+"Adds a button with [Texture2D] [code]button[/code] at column [code]column[/"
+"code]. The [code]button_idx[/code] index is used to identify the button when "
+"calling other methods. If not specified, the next available index is used, "
+"which may be retrieved by calling [method get_button_count] immediately "
+"after this method. Optionally, the button can be [code]disabled[/code] and "
+"have a [code]tooltip[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:35
+msgid ""
+"Calls the [code]method[/code] on the actual TreeItem and its children "
+"recursively. Pass parameters as a comma separated list."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:44
+msgid "Resets the background color for the given column to default."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:53
+msgid "Resets the color for the given column to default."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:62
+msgid "Deselects the given column."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:73
+msgid ""
+"Removes the button at index [code]button_idx[/code] in column [code]column[/"
+"code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:84
+msgid ""
+"Returns the [Texture2D] of the button at index [code]button_idx[/code] in "
+"column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:93
+msgid ""
+"Returns the number of buttons in column [code]column[/code]. May be used to "
+"get the most recently added button's index, if no index was specified."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:104
+msgid ""
+"Returns the tooltip string for the button at index [code]button_idx[/code] "
+"in column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:113
+msgid "Returns the column's cell mode."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:120
+msgid "Returns the TreeItem's child items."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:129
+msgid "Returns the custom background color of column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:138
+msgid "Returns the custom color of column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:147
+msgid "Returns [code]true[/code] if [code]expand_right[/code] is set."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:156
+msgid "Returns the given column's icon [Texture2D]. Error if no icon is set."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:165
+msgid "Returns the column's icon's maximum width."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:174
+msgid "Returns the [Color] modulating the column's icon."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:183
+msgid "Returns the icon [Texture2D] region as [Rect2]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:198
+msgid "Returns the next TreeItem in the tree."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:207
+msgid ""
+"Returns the next visible TreeItem in the tree.\n"
+"If [code]wrap[/code] is enabled, the method will wrap around to the first "
+"visible element in the tree when called on the last visible element, "
+"otherwise it returns [code]null[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:215
+msgid "Returns the parent TreeItem."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:222
+msgid "Returns the previous TreeItem in the tree."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:231
+msgid ""
+"Returns the previous visible TreeItem in the tree.\n"
+"If [code]wrap[/code] is enabled, the method will wrap around to the last "
+"visible element in the tree when called on the first visible element, "
+"otherwise it returns [code]null[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:257
+msgid "Returns the given column's text."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:266
+msgid "Returns the given column's text alignment."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:275
+msgid "Returns the given column's tooltip."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:286
+msgid ""
+"Returns [code]true[/code] if the button at index [code]button_idx[/code] for "
+"the given column is disabled."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:295
+msgid "Returns [code]true[/code] if the given column is checked."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:312
+msgid "Returns [code]true[/code] if column [code]column[/code] is editable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:321
+msgid "Returns [code]true[/code] if column [code]column[/code] is selectable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:330
+msgid "Returns [code]true[/code] if column [code]column[/code] is selected."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:337
+msgid "Moves this TreeItem to the bottom in the [Tree] hierarchy."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:344
+msgid "Moves this TreeItem to the top in the [Tree] hierarchy."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:353
+msgid "Removes the given child TreeItem."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:362
+msgid "Selects the column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:375
+msgid ""
+"Sets the given column's button [Texture2D] at index [code]button_idx[/code] "
+"to [code]button[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:388
+msgid ""
+"If [code]true[/code], disables the button at index [code]button_idx[/code] "
+"in column [code]column[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:399
+msgid ""
+"Sets the given column's cell mode to [code]mode[/code]. See [enum "
+"TreeCellMode] constants."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:410
+msgid "If [code]true[/code], the column [code]column[/code] is checked."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:433
+msgid ""
+"Sets the given column's custom background color and whether to just use it "
+"as an outline."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:444
+msgid "Sets the given column's custom color."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:457
+msgid ""
+"Sets the given column's custom draw callback to [code]callback[/code] method "
+"on [code]object[/code].\n"
+"The [code]callback[/code] should accept two arguments: the [TreeItem] that "
+"is drawn and its position and size as a [Rect2]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:469
+msgid "If [code]true[/code], column [code]column[/code] is editable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:480
+msgid ""
+"If [code]true[/code], column [code]column[/code] is expanded to the right."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:491
+msgid "Sets the given column's icon [Texture2D]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:502
+msgid "Sets the given column's icon's maximum width."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:513
+msgid "Modulates the given column's icon with [code]modulate[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:524
+msgid "Sets the given column's icon's texture region."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:571
+msgid "If [code]true[/code], the given column is selectable."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:592
+msgid ""
+"Sets the given column's text alignment. See [enum TextAlign] for possible "
+"values."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:603
+msgid "Sets the given column's tooltip text."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:609
+msgid "If [code]true[/code], the TreeItem is collapsed."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:612
+msgid "The custom minimum height."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:615
+msgid "If [code]true[/code], folding is disabled for this TreeItem."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:620
+msgid "Cell contains a string."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:623
+msgid "Cell can be checked."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:626
+msgid "Cell contains a range."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:629
+msgid "Cell contains an icon."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:634
+msgid "Align text to the left. See [code]set_text_align()[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:637
+msgid "Center text. See [code]set_text_align()[/code]."
+msgstr ""
+
+#: doc/classes/TreeItem.xml:640
+msgid "Align text to the right. See [code]set_text_align()[/code]."
+msgstr ""
+
+#: doc/classes/TriangleMesh.xml:4
+msgid "Internal mesh type."
+msgstr ""
+
+#: doc/classes/TriangleMesh.xml:7
+msgid "Mesh type used internally for collision calculations."
+msgstr ""
+
+#: doc/classes/Tween.xml:4
+msgid "Smoothly animates a node's properties over time."
+msgstr ""
+
+#: doc/classes/Tween.xml:7
+msgid ""
+"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.\n"
+"[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.\n"
+"Here is a brief usage example that causes a 2D node to move smoothly between "
+"two positions:\n"
+"[codeblock]\n"
+"var tween = get_node(\"Tween\")\n"
+"tween.interpolate_property($Node2D, \"position\",\n"
+" Vector2(0, 0), Vector2(100, 100), 1,\n"
+" Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)\n"
+"tween.start()\n"
+"[/codeblock]\n"
+"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.\n"
+"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 [code]http://easings.net/"
+"[/code] for some examples). The second accepts an [enum EaseType] constant, "
+"and controls the where [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."
+msgstr ""
+
+#: doc/classes/Tween.xml:45
+msgid ""
+"Follows [code]method[/code] of [code]object[/code] and applies the returned "
+"value on [code]target_method[/code] of [code]target[/code], beginning from "
+"[code]initial_val[/code] for [code]duration[/code] seconds, [code]delay[/"
+"code] later. Methods are called with consecutive values.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:71
+msgid ""
+"Follows [code]property[/code] of [code]object[/code] and applies it on "
+"[code]target_property[/code] of [code]target[/code], beginning from "
+"[code]initial_val[/code] for [code]duration[/code] seconds, [code]delay[/"
+"code] seconds later.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:79
+msgid ""
+"Returns the total time needed for all tweens to end. If you have two tweens, "
+"one lasting 10 seconds and the other 20 seconds, it would return 20 seconds, "
+"as by that time all tweens would have finished."
+msgstr ""
+
+#: doc/classes/Tween.xml:102
+msgid ""
+"Calls [code]callback[/code] of [code]object[/code] after [code]duration[/"
+"code]. [code]arg1[/code]-[code]arg5[/code] are arguments to be passed to the "
+"callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:125
+msgid ""
+"Calls [code]callback[/code] of [code]object[/code] after [code]duration[/"
+"code] on the main thread (similar to [method Object.call_deferred]). "
+"[code]arg1[/code]-[code]arg5[/code] are arguments to be passed to the "
+"callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:148
+msgid ""
+"Animates [code]method[/code] of [code]object[/code] from [code]initial_val[/"
+"code] to [code]final_val[/code] for [code]duration[/code] seconds, "
+"[code]delay[/code] seconds later. Methods are called with consecutive "
+"values.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:172
+msgid ""
+"Animates [code]property[/code] of [code]object[/code] from "
+"[code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] "
+"seconds, [code]delay[/code] seconds later. Setting the initial value to "
+"[code]null[/code] uses the current value of the property.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:180
+msgid ""
+"Returns [code]true[/code] if any tweens are currently running.\n"
+"[b]Note:[/b] This method doesn't consider tweens that have ended."
+msgstr ""
+
+#: doc/classes/Tween.xml:192
+msgid ""
+"Stops animation and removes a tween, given its object and property/method "
+"pair. By default, all tweens are removed, unless [code]key[/code] is "
+"specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:199
+msgid "Stops animation and removes all tweens."
+msgstr ""
+
+#: doc/classes/Tween.xml:210
+msgid ""
+"Resets a tween to its initial value (the one given, not the one before the "
+"tween), given its object and property/method pair. By default, all tweens "
+"are removed, unless [code]key[/code] is specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:217
+msgid ""
+"Resets all tweens to their initial values (the ones given, not those before "
+"the tween)."
+msgstr ""
+
+#: doc/classes/Tween.xml:228
+msgid ""
+"Continues animating a stopped tween, given its object and property/method "
+"pair. By default, all tweens are resumed, unless [code]key[/code] is "
+"specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:235
+msgid "Continues animating all stopped tweens."
+msgstr ""
+
+#: doc/classes/Tween.xml:244
+msgid "Sets the interpolation to the given [code]time[/code] in seconds."
+msgstr ""
+
+#: doc/classes/Tween.xml:253
+msgid ""
+"Activates/deactivates the tween. See also [method stop_all] and [method "
+"resume_all]."
+msgstr ""
+
+#: doc/classes/Tween.xml:260
+msgid "Starts the tween. You can define animations both before and after this."
+msgstr ""
+
+#: doc/classes/Tween.xml:271
+msgid ""
+"Stops a tween, given its object and property/method pair. By default, all "
+"tweens are stopped, unless [code]key[/code] is specified."
+msgstr ""
+
+#: doc/classes/Tween.xml:278
+msgid "Stops animating all tweens."
+msgstr ""
+
+#: doc/classes/Tween.xml:303
+msgid ""
+"Animates [code]method[/code] of [code]object[/code] from the value returned "
+"by [code]initial_method[/code] to [code]final_val[/code] for [code]duration[/"
+"code] seconds, [code]delay[/code] seconds later. Methods are animated by "
+"calling them with consecutive values.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:329
+msgid ""
+"Animates [code]property[/code] of [code]object[/code] from the current value "
+"of the [code]initial_val[/code] property of [code]initial[/code] to "
+"[code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] "
+"seconds later.\n"
+"Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] "
+"for [code]ease_type[/code] parameters. These values control the timing and "
+"direction of the interpolation. See the class description for more "
+"information."
+msgstr ""
+
+#: doc/classes/Tween.xml:337
+msgid "Returns the current time of the tween."
+msgstr ""
+
+#: doc/classes/Tween.xml:343
+msgid "The tween's animation process thread. See [enum TweenProcessMode]."
+msgstr ""
+
+#: doc/classes/Tween.xml:346
+msgid ""
+"The tween's speed multiplier. For example, set it to [code]1.0[/code] for "
+"normal speed, [code]2.0[/code] for two times normal speed, or [code]0.5[/"
+"code] for half of the normal speed. A value of [code]0[/code] pauses the "
+"animation, but see also [method set_active] or [method stop_all] for this."
+msgstr ""
+
+#: doc/classes/Tween.xml:349
+msgid "If [code]true[/code], the tween loops."
+msgstr ""
+
+#: doc/classes/Tween.xml:355
+msgid "Emitted when all processes in a tween end."
+msgstr ""
+
+#: doc/classes/Tween.xml:364
+msgid "Emitted when a tween ends."
+msgstr ""
+
+#: doc/classes/Tween.xml:373
+msgid "Emitted when a tween starts."
+msgstr ""
+
+#: doc/classes/Tween.xml:386
+msgid "Emitted at each step of the animation."
+msgstr ""
+
+#: doc/classes/Tween.xml:392
+msgid "The tween updates with the [code]_physics_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:395
+msgid "The tween updates with the [code]_process[/code] callback."
+msgstr ""
+
+#: doc/classes/Tween.xml:398
+msgid "The animation is interpolated linearly."
+msgstr ""
+
+#: doc/classes/Tween.xml:401
+msgid "The animation is interpolated using a sine function."
+msgstr ""
+
+#: doc/classes/Tween.xml:404
+msgid ""
+"The animation is interpolated with a quintic (to the power of 5) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:407
+msgid ""
+"The animation is interpolated with a quartic (to the power of 4) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:410
+msgid ""
+"The animation is interpolated with a quadratic (to the power of 2) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:413
+msgid ""
+"The animation is interpolated with an exponential (to the power of x) "
+"function."
+msgstr ""
+
+#: doc/classes/Tween.xml:416
+msgid ""
+"The animation is interpolated with elasticity, wiggling around the edges."
+msgstr ""
+
+#: doc/classes/Tween.xml:419
+msgid ""
+"The animation is interpolated with a cubic (to the power of 3) function."
+msgstr ""
+
+#: doc/classes/Tween.xml:422
+msgid "The animation is interpolated with a function using square roots."
+msgstr ""
+
+#: doc/classes/Tween.xml:425
+msgid "The animation is interpolated by bouncing at the end."
+msgstr ""
+
+#: doc/classes/Tween.xml:428
+msgid "The animation is interpolated backing out at ends."
+msgstr ""
+
+#: doc/classes/Tween.xml:431
+msgid "The interpolation starts slowly and speeds up towards the end."
+msgstr ""
+
+#: doc/classes/Tween.xml:434
+msgid "The interpolation starts quickly and slows down towards the end."
+msgstr ""
+
+#: doc/classes/Tween.xml:437
+msgid ""
+"A combination of [constant EASE_IN] and [constant EASE_OUT]. The "
+"interpolation is slowest at both ends."
+msgstr ""
+
+#: doc/classes/Tween.xml:440
+msgid ""
+"A combination of [constant EASE_IN] and [constant EASE_OUT]. The "
+"interpolation is fastest at both ends."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:4
+msgid "Helper class to implement a UDP server."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:7
+msgid ""
+"A simple server that opens a UDP socket and returns connected "
+"[PacketPeerUDP] upon receiving new packets. See also [method PacketPeerUDP."
+"connect_to_host].\n"
+"Below a small example of how it can be used:\n"
+"[codeblock]\n"
+"# server.gd\n"
+"extends Node\n"
+"\n"
+"var server := UDPServer.new()\n"
+"var peers = []\n"
+"\n"
+"func _ready():\n"
+" server.listen(4242)\n"
+"\n"
+"func _process(delta):\n"
+" if server.is_connection_available():\n"
+" var peer : PacketPeerUDP = server.take_connection()\n"
+" var pkt = peer.get_packet()\n"
+" print(\"Accepted peer: %s:%s\" % [peer.get_packet_ip(), peer."
+"get_packet_port()])\n"
+" print(\"Received data: %s\" % [pkt.get_string_from_utf8()])\n"
+" # Reply so it knows we received the message.\n"
+" peer.put_packet(pkt)\n"
+" # Keep a reference so we can keep contacting the remote peer.\n"
+" peers.append(peer)\n"
+"\n"
+" for i in range(0, peers.size()):\n"
+" pass # Do something with the connected peers.\n"
+"\n"
+"[/codeblock]\n"
+"[codeblock]\n"
+"# client.gd\n"
+"extends Node\n"
+"\n"
+"var udp := PacketPeerUDP.new()\n"
+"var connected = false\n"
+"\n"
+"func _ready():\n"
+" udp.connect_to_host(\"127.0.0.1\", 4242)\n"
+"\n"
+"func _process(delta):\n"
+" if !connected:\n"
+" # Try to contact server\n"
+" udp.put_packet(\"The answer is... 42!\".to_utf8())\n"
+" if udp.get_available_packet_count() > 0:\n"
+" print(\"Connected: %s\" % udp.get_packet().get_string_from_utf8())\n"
+" connected = true\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/UDPServer.xml:60
+msgid ""
+"Returns [code]true[/code] if a packet with a new address/port combination is "
+"received on the socket."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:67
+msgid ""
+"Returns [code]true[/code] if the socket is open and listening on a port."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:78
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:85
+msgid ""
+"Stops the server, closing the UDP socket if open. Will not disconnect any "
+"connected [PacketPeerUDP]."
+msgstr ""
+
+#: doc/classes/UDPServer.xml:92
+msgid ""
+"Returns a [PacketPeerUDP] connected to the address/port combination of the "
+"first packet in queue. Will return [code]null[/code] if no packet is in "
+"queue. See also [method PacketPeerUDP.connect_to_host]."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:4
+msgid "Helper to manage undo/redo operations in the editor or custom tools."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:7
+msgid ""
+"Helper to manage undo/redo operations in the editor or custom tools. It "
+"works by registering methods and property changes inside \"actions\".\n"
+"Common behavior is to create an action, then add do/undo calls to functions "
+"or property changes, then committing the action.\n"
+"Here's an example on how to add an action to the Godot editor's own "
+"[UndoRedo], from a plugin:\n"
+"[codeblock]\n"
+"var undo_redo = get_undo_redo() # Method of EditorPlugin.\n"
+"\n"
+"func do_something():\n"
+" pass # Put your code here.\n"
+"\n"
+"func undo_something():\n"
+" pass # Put here the code that reverts what's done by "
+"\"do_something()\".\n"
+"\n"
+"func _on_MyButton_pressed():\n"
+" var node = get_node(\"MyNode2D\")\n"
+" undo_redo.create_action(\"Move the node\")\n"
+" undo_redo.add_do_method(self, \"do_something\")\n"
+" undo_redo.add_undo_method(self, \"undo_something\")\n"
+" undo_redo.add_do_property(node, \"position\", Vector2(100,100))\n"
+" undo_redo.add_undo_property(node, \"position\", node.position)\n"
+" undo_redo.commit_action()\n"
+"[/codeblock]\n"
+"[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.\n"
+"If you don't need to register a method, you can leave [method add_do_method] "
+"and [method add_undo_method] out; the same goes for properties. You can also "
+"register more than one method/property."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:42
+msgid "Register a method that will be called when the action is committed."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:55
+msgid "Register a property value change for \"do\"."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:64
+msgid ""
+"Register a reference for \"do\" that will be erased if the \"do\" history is "
+"lost. This is useful mostly for new nodes created for the \"do\" call. Do "
+"not use for resources."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:75
+msgid "Register a method that will be called when the action is undone."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:88
+msgid "Register a property value change for \"undo\"."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:97
+msgid ""
+"Register a reference for \"undo\" that will be erased if the \"undo\" "
+"history is lost. This is useful mostly for nodes removed with the \"do\" "
+"call (not the \"undo\" call!)."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:106
+msgid ""
+"Clear the undo/redo history and associated references.\n"
+"Passing [code]false[/code] to [code]increase_version[/code] will prevent the "
+"version number to be increased from this."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:114
+msgid ""
+"Commit the action. All \"do\" methods/properties are called/set when this "
+"function is called."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:125
+msgid ""
+"Create a new action. After this is called, do all your calls to [method "
+"add_do_method], [method add_undo_method], [method add_do_property], and "
+"[method add_undo_property], then commit the action with [method "
+"commit_action].\n"
+"The way actions are merged is dictated by the [code]merge_mode[/code] "
+"argument. See [enum MergeMode] for details."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:133
+msgid "Gets the name of the current action."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:140
+msgid ""
+"Gets the version. Every time a new action is committed, the [UndoRedo]'s "
+"version number is increased automatically.\n"
+"This is useful mostly to check if something changed from a saved version."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:148
+msgid "Returns [code]true[/code] if a \"redo\" action is available."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:155
+msgid "Returns [code]true[/code] if an \"undo\" action is available."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:162
+msgid ""
+"Returns [code]true[/code] if the [UndoRedo] is currently committing the "
+"action, i.e. running its \"do\" method or property change (see [method "
+"commit_action])."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:169
+msgid "Redo the last action."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:176
+msgid "Undo the last action."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:183
+msgid "Called when [method undo] or [method redo] was called."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:189
+msgid "Makes \"do\"/\"undo\" operations stay in separate actions."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:192
+msgid ""
+"Makes so that the action's \"do\" operation is from the first action created "
+"and the \"undo\" operation is from the last subsequent action with the same "
+"name."
+msgstr ""
+
+#: doc/classes/UndoRedo.xml:195
+msgid "Makes subsequent actions with the same name be merged into one."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:4
+msgid "UPNP network functions."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:7
+msgid ""
+"Provides UPNP functionality to discover [UPNPDevice]s on the local network "
+"and execute commands on them, like managing port mappings (port forwarding) "
+"and querying the local and remote network IP address. Note that methods on "
+"this class are synchronous and block the calling thread.\n"
+"To forward a specific port:\n"
+"[codeblock]\n"
+"const PORT = 7777\n"
+"var upnp = UPNP.new()\n"
+"upnp.discover(2000, 2, \"InternetGatewayDevice\")\n"
+"upnp.add_port_mapping(port)\n"
+"[/codeblock]\n"
+"To close a specific port (e.g. after you have finished using it):\n"
+"[codeblock]\n"
+"upnp.delete_port_mapping(port)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:29
+msgid "Adds the given [UPNPDevice] to the list of discovered devices."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:46
+msgid ""
+"Adds a mapping to forward the external [code]port[/code] (between 1 and "
+"65535) on the default gateway (see [method get_gateway]) to the "
+"[code]internal_port[/code] on the local machine for the given protocol "
+"[code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP "
+"being the default). If a port mapping for the given port and protocol "
+"combination already exists on that gateway device, this method tries to "
+"overwrite it. If that is not desired, you can retrieve the gateway manually "
+"with [method get_gateway] and call [method add_port_mapping] on it, if any.\n"
+"If [code]internal_port[/code] is [code]0[/code] (the default), the same port "
+"number is used for both the external and the internal port (the [code]port[/"
+"code] value).\n"
+"The description ([code]desc[/code]) is shown in some router UIs and can be "
+"used to point out which application added the mapping. The mapping's lease "
+"duration can be limited by specifying a [code]duration[/code] (in seconds). "
+"However, some routers are incompatible with one or both of these, so use "
+"with caution and add fallback logic in case of errors to retry without them "
+"if in doubt.\n"
+"See [enum UPNPResult] for possible return values."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:56
+msgid "Clears the list of discovered devices."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:67
+msgid ""
+"Deletes the port mapping for the given port and protocol combination on the "
+"default gateway (see [method get_gateway]) if one exists. [code]port[/code] "
+"must be a valid port between 1 and 65535, [code]proto[/code] can be either "
+"[code]TCP[/code] or [code]UDP[/code]. See [enum UPNPResult] for possible "
+"return values."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:80
+msgid ""
+"Discovers local [UPNPDevice]s. Clears the list of previously discovered "
+"devices.\n"
+"Filters for IGD (InternetGatewayDevice) type devices by default, as those "
+"manage port forwarding. [code]timeout[/code] is the time to wait for "
+"responses in milliseconds. [code]ttl[/code] is the time-to-live; only touch "
+"this if you know what you're doing.\n"
+"See [enum UPNPResult] for possible return values."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:91
+msgid "Returns the [UPNPDevice] at the given [code]index[/code]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:98
+msgid "Returns the number of discovered [UPNPDevice]s."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:105
+msgid ""
+"Returns the default gateway. That is the first discovered [UPNPDevice] that "
+"is also a valid IGD (InternetGatewayDevice)."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:112
+msgid ""
+"Returns the external [IP] address of the default gateway (see [method "
+"get_gateway]) as string. Returns an empty string on error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:121
+msgid ""
+"Removes the device at [code]index[/code] from the list of discovered devices."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:132
+msgid ""
+"Sets the device at [code]index[/code] from the list of discovered devices to "
+"[code]device[/code]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:138
+msgid "If [code]true[/code], IPv6 is used for [UPNPDevice] discovery."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:141
+msgid ""
+"If [code]0[/code], the local port to use for discovery is chosen "
+"automatically by the system. If [code]1[/code], discovery will be done from "
+"the source port 1900 (same as destination port). Otherwise, the value will "
+"be used as the port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:144
+msgid ""
+"Multicast interface to use for discovery. Uses the default multicast "
+"interface if empty."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:149
+msgid "UPNP command or discovery was successful."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:152
+msgid ""
+"Not authorized to use the command on the [UPNPDevice]. May be returned when "
+"the user disabled UPNP on their router."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:155
+msgid ""
+"No port mapping was found for the given port, protocol combination on the "
+"given [UPNPDevice]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:158
+msgid "Inconsistent parameters."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:161
+msgid ""
+"No such entry in array. May be returned if a given port, protocol "
+"combination is not found on an [UPNPDevice]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:164
+msgid "The action failed."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:167
+msgid ""
+"The [UPNPDevice] does not allow wildcard values for the source IP address."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:170
+msgid "The [UPNPDevice] does not allow wildcard values for the external port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:173
+msgid "The [UPNPDevice] does not allow wildcard values for the internal port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:176
+msgid "The remote host value must be a wildcard."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:179
+msgid "The external port value must be a wildcard."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:182
+msgid ""
+"No port maps are available. May also be returned if port mapping "
+"functionality is not available."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:185
+msgid ""
+"Conflict with other mechanism. May be returned instead of [constant "
+"UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING] if a port mapping conflicts with an "
+"existing one."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:188
+msgid "Conflict with an existing port mapping."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:191
+msgid "External and internal port values must be the same."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:194
+msgid ""
+"Only permanent leases are supported. Do not use the [code]duration[/code] "
+"parameter when adding port mappings."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:197
+msgid "Invalid gateway."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:200
+msgid "Invalid port."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:203
+msgid "Invalid protocol."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:206
+msgid "Invalid duration."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:209
+msgid "Invalid arguments."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:212
+msgid "Invalid response."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:215
+msgid "Invalid parameter."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:218
+#: modules/upnp/doc_classes/UPNPDevice.xml:80
+msgid "HTTP error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:221
+msgid "Socket error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:224
+msgid "Error allocating memory."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:227
+msgid ""
+"No gateway available. You may need to call [method discover] first, or "
+"discovery didn't detect any valid IGDs (InternetGatewayDevices)."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:230
+msgid ""
+"No devices available. You may need to call [method discover] first, or "
+"discovery didn't detect any valid [UPNPDevice]s."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNP.xml:233
+#: modules/upnp/doc_classes/UPNPDevice.xml:104
+msgid "Unknown error."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:4
+msgid "UPNP device."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:7
+msgid ""
+"UPNP device. See [UPNP] for UPNP discovery and utility functions. Provides "
+"low-level access to UPNP control commands. Allows to manage port mappings "
+"(port forwarding) and to query network information of the device (like local "
+"and external IP address and status). Note that methods on this class are "
+"synchronous and block the calling thread."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:26
+msgid ""
+"Adds a port mapping to forward the given external port on this [UPNPDevice] "
+"for the given protocol to the local machine. See [method UPNP."
+"add_port_mapping]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:37
+msgid ""
+"Deletes the port mapping identified by the given port and protocol "
+"combination on this device. See [method UPNP.delete_port_mapping]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:44
+msgid ""
+"Returns [code]true[/code] if this is a valid IGD (InternetGatewayDevice) "
+"which potentially supports port forwarding."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:51
+msgid ""
+"Returns the external IP address of this [UPNPDevice] or an empty string."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:57
+msgid "URL to the device description."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:60
+msgid "IDG control URL."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:63
+msgid ""
+"Address of the local machine in the network connecting it to this "
+"[UPNPDevice]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:66
+msgid "IGD service type."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:69
+msgid "IGD status. See [enum IGDStatus]."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:72
+msgid "Service type."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:77
+msgid "OK."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:83
+msgid "Empty HTTP response."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:86
+msgid "Returned response contained no URLs."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:89
+msgid "Not a valid IGD."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:92
+msgid "Disconnected."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:95
+msgid "Unknown device."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:98
+msgid "Invalid control."
+msgstr ""
+
+#: modules/upnp/doc_classes/UPNPDevice.xml:101
+msgid "Memory allocation error."
+msgstr ""
+
+#: doc/classes/Variant.xml:4
+msgid "The most important data type in Godot."
+msgstr ""
+
+#: doc/classes/Variant.xml:7
+msgid ""
+"In computer programming, a Variant class is a class that is designed to "
+"store a variety of other types. Dynamic programming languages like PHP, Lua, "
+"JavaScript and GDScript like to use them to store variables' data on the "
+"backend. With these Variants, properties are able to change value types "
+"freely.\n"
+"[codeblock]\n"
+"var foo = 2 # foo is dynamically an integer\n"
+"foo = \"Now foo is a string!\"\n"
+"foo = Reference.new() # foo is an Object\n"
+"var bar: int = 2 # bar is a statically typed integer.\n"
+"# bar = \"Uh oh! I can't make static variables become a different type!\"\n"
+"[/codeblock]\n"
+"Godot tracks all scripting API variables within Variants. Without even "
+"realizing it, you use Variants all the time. When a particular language "
+"enforces its own rules for keeping data typed, then that language is "
+"applying its own custom logic over the base Variant scripting API.\n"
+"- GDScript automatically wrap values in them. It keeps all data in plain "
+"Variants by default and then optionally enforces custom static typing rules "
+"on variable types.\n"
+"- VisualScript tracks properties inside Variants as well, but it also uses "
+"static typing. The GUI interface enforces that properties have a particular "
+"type that doesn't change over time.\n"
+"- C# is statically typed, but uses the Mono [code]object[/code] type in "
+"place of Godot's Variant class when it needs to represent a dynamic value. "
+"[code]object[/code] is the Mono runtime's equivalent of the same concept.\n"
+"- The statically-typed language NativeScript C++ does not define a built-in "
+"Variant-like class. Godot's GDNative bindings provide their own godot::"
+"Variant class for users; Any point at which the C++ code starts interacting "
+"with the Godot runtime is a place where you might have to start wrapping "
+"data inside Variant objects.\n"
+"The global [method @GDScript.typeof] function returns the enumerated value "
+"of the Variant type stored in the current variable (see [enum Variant."
+"Type]).\n"
+"[codeblock]\n"
+"var foo = 2\n"
+"match typeof(foo):\n"
+" TYPE_NIL:\n"
+" print(\"foo is null\")\n"
+" TYPE_INTEGER:\n"
+" print(\"foo is an integer\")\n"
+" TYPE_OBJECT:\n"
+" # Note that Objects are their own special category.\n"
+" # To get the name of the underlying Object type, you need the "
+"`get_class()` method.\n"
+" print(\"foo is a(n) %s\" % foo.get_class()) # inject the class name "
+"into a formatted string.\n"
+" # Note also that there is not yet any way to get a script's "
+"`class_name` string easily.\n"
+" # To fetch that value, you need to dig deeply into a hidden "
+"ProjectSettings setting: an Array of Dictionaries called "
+"\"_global_script_classes\".\n"
+" # Open your project.godot file to see it up close.\n"
+"[/codeblock]\n"
+"A Variant takes up only 20 bytes and can store almost any engine datatype "
+"inside of it. Variants are rarely used to hold information for long periods "
+"of time. Instead, they are used mainly for communication, editing, "
+"serialization and moving data around.\n"
+"Godot has specifically invested in making its Variant class as flexible as "
+"possible; so much so that it is used for a multitude of operations to "
+"facilitate communication between all of Godot's systems.\n"
+"A Variant:\n"
+"- Can store almost any datatype.\n"
+"- Can perform operations between many variants. GDScript uses Variant as its "
+"atomic/native datatype.\n"
+"- Can be hashed, so it can be compared quickly to other variants.\n"
+"- Can be used to convert safely between datatypes.\n"
+"- Can be used to abstract calling methods and their arguments. Godot exports "
+"all its functions through variants.\n"
+"- Can be used to defer calls or move data between threads.\n"
+"- Can be serialized as binary and stored to disk, or transferred via "
+"network.\n"
+"- Can be serialized to text and use it for printing values and editable "
+"settings.\n"
+"- Can work as an exported property, so the editor can edit it universally.\n"
+"- Can be used for dictionaries, arrays, parsers, etc.\n"
+"[b]Containers (Array and Dictionary):[/b] Both are implemented using "
+"variants. A [Dictionary] can match any datatype used as key to any other "
+"datatype. An [Array] just holds an array of Variants. Of course, a Variant "
+"can also hold a [Dictionary] and an [Array] inside, making it even more "
+"flexible.\n"
+"Modifications to a container will modify all references to it. A [Mutex] "
+"should be created to lock it if multi-threaded access is desired."
+msgstr ""
+
+#: doc/classes/Variant.xml:53
+msgid ""
+"https://docs.godotengine.org/en/latest/development/cpp/variant_class.html"
+msgstr ""
+
+#: doc/classes/VBoxContainer.xml:4
+msgid "Vertical box container."
+msgstr ""
+
+#: doc/classes/VBoxContainer.xml:7
+msgid "Vertical box container. See [BoxContainer]."
+msgstr ""
+
+#: doc/classes/VBoxContainer.xml:17
+msgid "The vertical space between the [VBoxContainer]'s elements."
+msgstr ""
+
+#: doc/classes/Vector2.xml:4
+msgid "Vector used for 2D math using floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector2.xml:7
+msgid ""
+"2-element structure that can be used to represent positions in 2D space or "
+"any other pair of numeric values.\n"
+"It uses floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector2.xml:20
+msgid "Constructs a new [Vector2] from [Vector2i]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:31
+msgid ""
+"Constructs a new [Vector2] from the given [code]x[/code] and [code]y[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:38 doc/classes/Vector3.xml:40
+msgid ""
+"Returns a new vector with all components in absolute values (i.e. positive)."
+msgstr ""
+
+#: doc/classes/Vector2.xml:45
+msgid ""
+"Returns the vector's angle in radians with respect to the X axis, or [code]"
+"(1, 0)[/code] vector.\n"
+"Equivalent to the result of [method @GDScript.atan2] when called with the "
+"vector's [member x] and [member y] as parameters: [code]atan2(x, y)[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:55
+msgid "Returns the angle in radians between the two vectors."
+msgstr ""
+
+#: doc/classes/Vector2.xml:64
+msgid ""
+"Returns the angle in radians between the line connecting the two points and "
+"the X coordinate."
+msgstr ""
+
+#: doc/classes/Vector2.xml:71
+msgid "Returns the ratio of [member x] to [member y]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:80 doc/classes/Vector3.xml:58
+msgid ""
+"Returns the vector \"bounced off\" from a plane defined by the given normal."
+msgstr ""
+
+#: doc/classes/Vector2.xml:87
+msgid "Returns the vector with all components rounded up."
+msgstr ""
+
+#: doc/classes/Vector2.xml:96
+msgid "Returns the vector with a maximum length."
+msgstr ""
+
+#: doc/classes/Vector2.xml:105
+msgid ""
+"Returns the 2-dimensional analog of the cross product with the given vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:120
+msgid ""
+"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]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation."
+msgstr ""
+
+#: doc/classes/Vector2.xml:129 doc/classes/Vector3.xml:98
+msgid ""
+"Returns the normalized vector pointing from this vector to [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:138
+msgid ""
+"Returns the squared distance to vector [code]b[/code]. Prefer this function "
+"over [method distance_to] if you need to sort vectors or need the squared "
+"distance for some formula."
+msgstr ""
+
+#: doc/classes/Vector2.xml:147
+msgid "Returns the distance to vector [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:156
+msgid "Returns the dot product with vector [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:163
+msgid "Returns the vector with all components rounded down."
+msgstr ""
+
+#: doc/classes/Vector2.xml:172 doc/classes/Vector3.xml:148
+msgid ""
+"Returns [code]true[/code] if this vector and [code]v[/code] are "
+"approximately equal, by running [method @GDScript.is_equal_approx] on each "
+"component."
+msgstr ""
+
+#: doc/classes/Vector2.xml:179 doc/classes/Vector3.xml:155
+msgid "Returns [code]true[/code] if the vector is normalized."
+msgstr ""
+
+#: doc/classes/Vector2.xml:186 doc/classes/Vector3.xml:162
+msgid "Returns the vector's length."
+msgstr ""
+
+#: doc/classes/Vector2.xml:193
+msgid ""
+"Returns the vector's length squared. Prefer this method over [method length] "
+"if you need to sort vectors or need the squared length for some formula."
+msgstr ""
+
+#: doc/classes/Vector2.xml:204
+msgid ""
+"Returns the result of the linear interpolation between this vector and "
+"[code]b[/code] by amount [code]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation."
+msgstr ""
+
+#: doc/classes/Vector2.xml:215 doc/classes/Vector3.xml:205
+msgid ""
+"Moves the vector toward [code]to[/code] by the fixed [code]delta[/code] "
+"amount."
+msgstr ""
+
+#: doc/classes/Vector2.xml:222 doc/classes/Vector3.xml:212
+msgid ""
+"Returns the vector scaled to unit length. Equivalent to [code]v / v.length()"
+"[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:231 doc/classes/Vector3.xml:230
+msgid ""
+"Returns a vector composed of the [code]fposmod[/code] of this vector's "
+"components and [code]mod[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:240 doc/classes/Vector3.xml:239
+msgid ""
+"Returns a vector composed of the [code]fposmod[/code] of this vector's "
+"components and [code]modv[/code]'s components."
+msgstr ""
+
+#: doc/classes/Vector2.xml:249 doc/classes/Vector3.xml:248
+msgid "Returns the vector projected onto the vector [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:258 doc/classes/Vector3.xml:257
+msgid "Returns the vector reflected from a plane defined by the given normal."
+msgstr ""
+
+#: doc/classes/Vector2.xml:267
+msgid ""
+"Returns the vector rotated by [code]phi[/code] radians. See also [method "
+"@GDScript.deg2rad]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:274 doc/classes/Vector3.xml:275
+msgid ""
+"Returns the vector with all components rounded to the nearest integer, with "
+"halfway cases rounded away from zero."
+msgstr ""
+
+#: doc/classes/Vector2.xml:281 doc/classes/Vector3.xml:282
+msgid ""
+"Returns the vector with each component set to one or negative one, depending "
+"on the signs of the components."
+msgstr ""
+
+#: doc/classes/Vector2.xml:292 doc/classes/Vector3.xml:293
+msgid ""
+"Returns the result of spherical linear interpolation between this vector and "
+"[code]b[/code], by amount [code]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation.\n"
+"[b]Note:[/b] Both vectors must be normalized."
+msgstr ""
+
+#: doc/classes/Vector2.xml:302 doc/classes/Vector3.xml:303
+msgid ""
+"Returns the component of the vector along a plane defined by the given "
+"normal."
+msgstr ""
+
+#: doc/classes/Vector2.xml:311
+msgid "Returns the vector snapped to a grid with the given size."
+msgstr ""
+
+#: doc/classes/Vector2.xml:318
+msgid "Returns a perpendicular vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:324 doc/classes/Vector3.xml:325
+msgid ""
+"The vector's X component. Also accessible by using the index position [code]"
+"[0][/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:327 doc/classes/Vector3.xml:328
+msgid ""
+"The vector's Y component. Also accessible by using the index position [code]"
+"[1][/code]."
+msgstr ""
+
+#: doc/classes/Vector2.xml:332 doc/classes/Vector2i.xml:37
+#: doc/classes/Vector3i.xml:39
+msgid "Enumerated value for the X axis."
+msgstr ""
+
+#: doc/classes/Vector2.xml:335 doc/classes/Vector2i.xml:40
+#: doc/classes/Vector3i.xml:42
+msgid "Enumerated value for the Y axis."
+msgstr ""
+
+#: doc/classes/Vector2.xml:338 doc/classes/Vector2i.xml:43
+#: doc/classes/Vector3.xml:345 doc/classes/Vector3i.xml:48
+msgid "Zero vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:341 doc/classes/Vector2i.xml:46
+#: doc/classes/Vector3.xml:348 doc/classes/Vector3i.xml:51
+msgid "One vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:344 doc/classes/Vector3.xml:351
+msgid "Infinity vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:347 doc/classes/Vector2i.xml:49
+#: doc/classes/Vector3.xml:354 doc/classes/Vector3i.xml:54
+msgid "Left unit vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:350 doc/classes/Vector2i.xml:52
+#: doc/classes/Vector3.xml:357 doc/classes/Vector3i.xml:57
+msgid "Right unit vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:353 doc/classes/Vector2i.xml:55
+#: doc/classes/Vector3.xml:360 doc/classes/Vector3i.xml:60
+msgid "Up unit vector."
+msgstr ""
+
+#: doc/classes/Vector2.xml:356 doc/classes/Vector2i.xml:58
+#: doc/classes/Vector3.xml:363 doc/classes/Vector3i.xml:63
+msgid "Down unit vector."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:4
+msgid "Vector used for 2D math using integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:7
+msgid ""
+"2-element structure that can be used to represent positions in 2D space or "
+"any other pair of numeric values.\n"
+"It uses integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:22
+msgid ""
+"Constructs a new [Vector2i] from the given [code]x[/code] and [code]y[/code]."
+msgstr ""
+
+#: doc/classes/Vector2i.xml:31
+msgid ""
+"Constructs a new [Vector2i] from [Vector2]. The floating point coordinates "
+"will be truncated."
+msgstr ""
+
+#: doc/classes/Vector3.xml:4
+msgid "Vector used for 3D math using floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector3.xml:7
+msgid ""
+"3-element structure that can be used to represent positions in 3D space or "
+"any other pair of numeric values.\n"
+"It uses floating point coordinates."
+msgstr ""
+
+#: doc/classes/Vector3.xml:20
+msgid "Constructs a new [Vector3] from [Vector3i]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:33
+msgid "Returns a [Vector3] with the given components."
+msgstr ""
+
+#: doc/classes/Vector3.xml:49
+msgid "Returns the minimum angle to the given vector."
+msgstr ""
+
+#: doc/classes/Vector3.xml:65
+msgid "Returns a new vector with all components rounded up."
+msgstr ""
+
+#: doc/classes/Vector3.xml:74
+msgid "Returns the cross product with [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:89
+msgid ""
+"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]t[/code]. [code]t[/code] is in the range of [code]0.0 "
+"- 1.0[/code], representing the amount of interpolation."
+msgstr ""
+
+#: doc/classes/Vector3.xml:107
+msgid ""
+"Returns the squared distance to [code]b[/code]. Prefer this function over "
+"[method distance_to] if you need to sort vectors or need the squared "
+"distance for some formula."
+msgstr ""
+
+#: doc/classes/Vector3.xml:116
+msgid "Returns the distance to [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:125
+msgid "Returns the dot product with [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:132
+msgid "Returns a new vector with all components rounded down."
+msgstr ""
+
+#: doc/classes/Vector3.xml:139
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:169
+msgid ""
+"Returns the vector's length squared. Prefer this function over [method "
+"length] if you need to sort vectors or need the squared length for some "
+"formula."
+msgstr ""
+
+#: doc/classes/Vector3.xml:180
+msgid ""
+"Returns the result of the linear interpolation between this vector and "
+"[code]b[/code] by amount [code]t[/code]. [code]t[/code] is in the range of "
+"[code]0.0 - 1.0[/code], representing the amount of interpolation.."
+msgstr ""
+
+#: doc/classes/Vector3.xml:187
+msgid ""
+"Returns the axis of the vector's largest value. See [code]AXIS_*[/code] "
+"constants."
+msgstr ""
+
+#: doc/classes/Vector3.xml:194
+msgid ""
+"Returns the axis of the vector's smallest value. See [code]AXIS_*[/code] "
+"constants."
+msgstr ""
+
+#: doc/classes/Vector3.xml:221
+msgid "Returns the outer product with [code]b[/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:268
+msgid ""
+"Rotates the vector around a given axis by [code]phi[/code] radians. The axis "
+"must be a normalized vector."
+msgstr ""
+
+#: doc/classes/Vector3.xml:312
+msgid "Returns a copy of the vector snapped to the lowest neared multiple."
+msgstr ""
+
+#: doc/classes/Vector3.xml:319
+msgid "Returns a diagonal matrix with the vector as main diagonal."
+msgstr ""
+
+#: doc/classes/Vector3.xml:331
+msgid ""
+"The vector's Z component. Also accessible by using the index position [code]"
+"[2][/code]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:336
+msgid ""
+"Enumerated value for the X axis. Returned by [method max_axis] and [method "
+"min_axis]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:339
+msgid ""
+"Enumerated value for the Y axis. Returned by [method max_axis] and [method "
+"min_axis]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:342
+msgid ""
+"Enumerated value for the Z axis. Returned by [method max_axis] and [method "
+"min_axis]."
+msgstr ""
+
+#: doc/classes/Vector3.xml:366 doc/classes/Vector3i.xml:66
+msgid "Forward unit vector."
+msgstr ""
+
+#: doc/classes/Vector3.xml:369 doc/classes/Vector3i.xml:69
+msgid "Back unit vector."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:4
+msgid "Vector used for 3D math using integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:7
+msgid ""
+"3-element structure that can be used to represent positions in 3D space or "
+"any other pair of numeric values.\n"
+"It uses integer coordinates."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:24
+msgid "Returns a [Vector3i] with the given components."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:33
+msgid ""
+"Constructs a new [Vector3i] from [Vector3]. The floating point coordinates "
+"will be truncated."
+msgstr ""
+
+#: doc/classes/Vector3i.xml:45
+msgid "Enumerated value for the Z axis."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:4
+msgid "Physics body that simulates the behavior of a car."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:7
+msgid ""
+"This node implements all the physics logic needed to simulate a car. It is "
+"based on the raycast vehicle system commonly found in physics engines. You "
+"will need to add a [CollisionShape3D] for the main body of your vehicle and "
+"add [VehicleWheel3D] nodes for the wheels. You should also add a "
+"[MeshInstance3D] to this node for the 3D model of your car but this model "
+"should not include meshes for the wheels. You should control the vehicle by "
+"using the [member brake], [member engine_force], and [member steering] "
+"properties and not change the position or orientation of this node "
+"directly.\n"
+"[b]Note:[/b] The origin point of your VehicleBody3D will determine the "
+"center of gravity of your vehicle so it is better to keep this low and move "
+"the [CollisionShape3D] and [MeshInstance3D] upwards."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:16
+msgid ""
+"Slows down the vehicle by applying a braking force. The vehicle is only "
+"slowed down if the wheels are in contact with a surface. The force you need "
+"to apply to adequately slow down your vehicle depends on the [member "
+"RigidBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try "
+"a value in the 25 - 30 range for hard braking."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:19
+msgid ""
+"Accelerates the vehicle by applying an engine force. The vehicle is only "
+"speed up if the wheels that have [member VehicleWheel3D.use_as_traction] set "
+"to [code]true[/code] and are in contact with a surface. The [member "
+"RigidBody3D.mass] of the vehicle has an effect on the acceleration of the "
+"vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 "
+"range for acceleration.\n"
+"[b]Note:[/b] The simulation does not take the effect of gears into account, "
+"you will need to add logic for this if you wish to simulate gears.\n"
+"A negative value will result in the vehicle reversing."
+msgstr ""
+
+#: doc/classes/VehicleBody3D.xml:25
+msgid ""
+"The steering angle for the vehicle. Setting this to a non-zero value will "
+"result in the vehicle turning when it's moving. Wheels that have [member "
+"VehicleWheel3D.use_as_steering] set to [code]true[/code] will automatically "
+"be rotated."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:4
+msgid "Physics object that simulates the behavior of a wheel."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:7
+msgid ""
+"This node needs to be used as a child node of [VehicleBody3D] and simulates "
+"the behavior of one of its wheels. This node also acts as a collider to "
+"detect if the wheel is touching a surface."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:16
+msgid "Returns the rotational speed of the wheel in revolutions per minute."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:23
+msgid ""
+"Returns a value between 0.0 and 1.0 that indicates whether this wheel is "
+"skidding. 0.0 is skidding (the wheel has lost grip, e.g. icy terrain), 1.0 "
+"means not skidding (the wheel has full grip, e.g. dry asphalt road)."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:30
+msgid "Returns [code]true[/code] if this wheel is in contact with a surface."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:36
+msgid ""
+"Slows down the wheel by applying a braking force. The wheel is only slowed "
+"down if it is in contact with a surface. The force you need to apply to "
+"adequately slow down your vehicle depends on the [member RigidBody3D.mass] "
+"of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 "
+"- 30 range for hard braking."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:39
+msgid ""
+"The damping applied to the spring when the spring is being compressed. This "
+"value should be between 0.0 (no damping) and 1.0. A value of 0.0 means the "
+"car will keep bouncing as the spring keeps its energy. A good value for this "
+"is around 0.3 for a normal car, 0.5 for a race car."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:42
+msgid ""
+"The damping applied to the spring when relaxing. This value should be "
+"between 0.0 (no damping) and 1.0. This value should always be slightly "
+"higher than the [member damping_compression] property. For a [member "
+"damping_compression] value of 0.3, try a relaxation value of 0.5."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:45
+msgid ""
+"Accelerates the wheel by applying an engine force. The wheel is only speed "
+"up if it is in contact with a surface. The [member RigidBody3D.mass] of the "
+"vehicle has an effect on the acceleration of the vehicle. For a vehicle with "
+"a mass set to 1000, try a value in the 25 - 50 range for acceleration.\n"
+"[b]Note:[/b] The simulation does not take the effect of gears into account, "
+"you will need to add logic for this if you wish to simulate gears.\n"
+"A negative value will result in the wheel reversing."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:50
+msgid ""
+"The steering angle for the wheel. Setting this to a non-zero value will "
+"result in the vehicle turning when it's moving."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:53
+msgid ""
+"The maximum force the spring can resist. This value should be higher than a "
+"quarter of the [member RigidBody3D.mass] of the [VehicleBody3D] or the "
+"spring will not carry the weight of the vehicle. Good results are often "
+"obtained by a value that is about 3× to 4× this number."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:56
+msgid ""
+"This value defines the stiffness of the suspension. Use a value lower than "
+"50 for an off-road car, a value between 50 and 100 for a race car and try "
+"something around 200 for something like a Formula 1 car."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:59
+msgid ""
+"This is the distance the suspension can travel. As Godot units are "
+"equivalent to meters, keep this setting relatively low. Try a value between "
+"0.1 and 0.3 depending on the type of car."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:62
+msgid ""
+"If [code]true[/code], this wheel will be turned when the car steers. This "
+"value is used in conjunction with [member VehicleBody3D.steering] and "
+"ignored if you are using the per-wheel [member steering] value instead."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:65
+msgid ""
+"If [code]true[/code], this wheel transfers engine force to the ground to "
+"propel the vehicle forward. This value is used in conjunction with [member "
+"VehicleBody3D.engine_force] and ignored if you are using the per-wheel "
+"[member engine_force] value instead."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:68
+msgid ""
+"This determines how much grip this wheel has. It is combined with the "
+"friction setting of the surface the wheel is in contact with. 0.0 means no "
+"grip, 1.0 is normal grip. For a drift car setup, try setting the grip of the "
+"rear wheels slightly lower than the front wheels, or use a lower value to "
+"simulate tire wear.\n"
+"It's best to set this to 1.0 when starting out."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:72
+msgid "The radius of the wheel in meters."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:75
+msgid ""
+"This is the distance in meters the wheel is lowered from its origin point. "
+"Don't set this to 0.0 and move the wheel into position, instead move the "
+"origin point of your wheel (the gizmo in Godot) to the position the wheel "
+"will take when bottoming out, then use the rest length to move the wheel "
+"down to the position it should be in when the car is in rest."
+msgstr ""
+
+#: doc/classes/VehicleWheel3D.xml:78
+msgid ""
+"This value affects the roll of your vehicle. If set to 1.0 for all wheels, "
+"your vehicle will be prone to rolling over, while a value of 0.0 will resist "
+"body roll."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:4
+msgid "Control for playing video streams."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:7
+msgid ""
+"Control node for playing video streams using [VideoStream] resources.\n"
+"Supported video formats are [url=https://www.webmproject.org/]WebM[/url] "
+"([VideoStreamWebm]), [url=https://www.theora.org/]Ogg Theora[/url] "
+"([VideoStreamTheora]), and any format exposed via a GDNative plugin using "
+"[VideoStreamGDNative]."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:17
+msgid ""
+"Returns the video stream's name, or [code]\"<No Stream>\"[/code] if no video "
+"stream is assigned."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:24
+msgid "Returns the current frame as a [Texture2D]."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:31
+msgid ""
+"Returns [code]true[/code] if the video is playing.\n"
+"[b]Note:[/b] The video is still considered playing if paused during playback."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:39
+msgid ""
+"Starts the video playback from the beginning. If the video is paused, this "
+"will not unpause the video."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:46
+msgid ""
+"Stops the video playback and sets the stream position to 0.\n"
+"[b]Note:[/b] Although the stream position will be set to 0, the first frame "
+"of the video stream won't become the current frame."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:53
+msgid "The embedded audio track to play."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:56
+msgid "If [code]true[/code], playback starts when the scene loads."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:59
+msgid "Amount of time in milliseconds to store in buffer while playing."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:62
+msgid "Audio bus to use for sound playback."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:65
+msgid ""
+"If [code]true[/code], the video scales to the control size. Otherwise, the "
+"control minimum size will be automatically adjusted to match the video "
+"stream's dimensions."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:68
+msgid "If [code]true[/code], the video is paused."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:71
+msgid "The assigned video stream. See description for supported formats."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:74
+msgid "The current position of the stream, in seconds."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:77
+msgid "Audio volume as a linear value."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:80
+msgid "Audio volume in dB."
+msgstr ""
+
+#: doc/classes/VideoPlayer.xml:86
+msgid "Emitted when playback is finished."
+msgstr ""
+
+#: doc/classes/VideoStream.xml:4
+msgid "Base resource for video streams."
+msgstr ""
+
+#: doc/classes/VideoStream.xml:7
+msgid ""
+"Base resource type for all video streams. Classes that derive from "
+"[VideoStream] can all be used as resource types to play back videos in "
+"[VideoPlayer]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:4
+msgid "[VideoStream] resource for for video formats implemented via GDNative."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:7
+msgid ""
+"[VideoStream] resource for for video formats implemented via GDNative.\n"
+"It can be used via [url=https://github.com/KidRigger/godot-"
+"videodecoder]godot-videodecoder[/url] which uses the [url=https://ffmpeg."
+"org]FFmpeg[/url] library."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:17
+msgid "Returns the video file handled by this [VideoStreamGDNative]."
+msgstr ""
+
+#: modules/gdnative/doc_classes/VideoStreamGDNative.xml:26
+msgid ""
+"Sets the video file that this [VideoStreamGDNative] resource handles. The "
+"supported extensions depend on the GDNative plugins used to expose video "
+"formats."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:4
+msgid "[VideoStream] resource for Ogg Theora videos."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:7
+msgid ""
+"[VideoStream] resource handling the [url=https://www.theora.org/]Ogg Theora[/"
+"url] video format with [code].ogv[/code] extension."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:16
+msgid "Returns the Ogg Theora video file handled by this [VideoStreamTheora]."
+msgstr ""
+
+#: modules/theora/doc_classes/VideoStreamTheora.xml:25
+msgid ""
+"Sets the Ogg Theora video file that this [VideoStreamTheora] resource "
+"handles. The [code]file[/code] name should have the [code].o[/code] "
+"extension."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:4
+msgid "[VideoStream] resource for WebM videos."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:7
+msgid ""
+"[VideoStream] resource handling the [url=https://www.webmproject.org/]WebM[/"
+"url] video format with [code].webm[/code] extension."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:16
+msgid "Returns the WebM video file handled by this [VideoStreamWebm]."
+msgstr ""
+
+#: modules/webm/doc_classes/VideoStreamWebm.xml:25
+msgid ""
+"Sets the WebM video file that this [VideoStreamWebm] resource handles. The "
+"[code]file[/code] name should have the [code].webm[/code] extension."
+msgstr ""
+
+#: doc/classes/Viewport.xml:4
+msgid "Creates a sub-view into the screen."
+msgstr ""
+
+#: doc/classes/Viewport.xml:7
+msgid ""
+"A Viewport creates a different view into the screen, or a sub-view inside "
+"another viewport. Children 2D Nodes will display on it, and children "
+"Camera3D 3D nodes will render on it too.\n"
+"Optionally, a viewport can have its own 2D or 3D world, so they don't share "
+"what they draw with other viewports.\n"
+"If a viewport is a child of a [SubViewportContainer], it will automatically "
+"take up its size, otherwise it must be set manually.\n"
+"Viewports can also choose to be audio listeners, so they generate positional "
+"audio depending on a 2D or 3D camera child of it.\n"
+"Also, viewports can be assigned to different screens in case the devices "
+"have multiple screens.\n"
+"Finally, viewports can also behave as render targets, in which case they "
+"will not be visible unless the associated texture is used to draw."
+msgstr ""
+
+#: doc/classes/Viewport.xml:16
+msgid "https://docs.godotengine.org/en/latest/tutorials/viewports/index.html"
+msgstr ""
+
+#: doc/classes/Viewport.xml:23
+msgid ""
+"Returns the 3D world of the viewport, or if none the world of the parent "
+"viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:30
+msgid "Returns the 2D world of the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:37
+msgid "Returns the active 3D camera."
+msgstr ""
+
+#: doc/classes/Viewport.xml:44
+msgid "Returns the total transform of the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:51
+msgid "Returns the mouse position relative to the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:60
+msgid "Returns information about the viewport from the rendering pipeline."
+msgstr ""
+
+#: doc/classes/Viewport.xml:69
+msgid "Returns the [enum ShadowAtlasQuadrantSubdiv] of the specified quadrant."
+msgstr ""
+
+#: doc/classes/Viewport.xml:76
+msgid ""
+"Returns the viewport's texture.\n"
+"[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:\n"
+"[codeblock]\n"
+"var img = get_viewport().get_texture().get_data()\n"
+"img.flip_y()\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/Viewport.xml:88
+msgid "Returns the viewport's RID from the [RenderingServer]."
+msgstr ""
+
+#: doc/classes/Viewport.xml:95
+msgid "Returns the visible rectangle in global screen coordinates."
+msgstr ""
+
+#: doc/classes/Viewport.xml:102
+msgid ""
+"Returns the drag data from the GUI, that was previously returned by [method "
+"Control.get_drag_data]."
+msgstr ""
+
+#: doc/classes/Viewport.xml:109
+msgid ""
+"Returns [code]true[/code] if the viewport is currently performing a drag "
+"operation."
+msgstr ""
+
+#: doc/classes/Viewport.xml:146
+msgid "Stops the input from propagating further down the [SceneTree]."
+msgstr ""
+
+#: doc/classes/Viewport.xml:157
+msgid ""
+"Sets the number of subdivisions to use in the specified quadrant. A higher "
+"number of subdivisions allows you to have more shadows in the scene at once, "
+"but reduces the quality of the shadows. A good practice is to have quadrants "
+"with a varying number of subdivisions and to have as few subdivisions as "
+"possible."
+msgstr ""
+
+#: doc/classes/Viewport.xml:174
+msgid "Forces update of the 2D and 3D worlds."
+msgstr ""
+
+#: doc/classes/Viewport.xml:183
+msgid "Warps the mouse to a position relative to the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:189
+msgid "If [code]true[/code], the viewport will process 2D audio streams."
+msgstr ""
+
+#: doc/classes/Viewport.xml:192
+msgid "If [code]true[/code], the viewport will process 3D audio streams."
+msgstr ""
+
+#: doc/classes/Viewport.xml:199
+msgid ""
+"The canvas transform of the viewport, useful for changing the on-screen "
+"positions of all child [CanvasItem]s. This is relative to the global canvas "
+"transform of the viewport."
+msgstr ""
+
+#: doc/classes/Viewport.xml:202
+msgid "The overlay mode for test rendered geometry in debug purposes."
+msgstr ""
+
+#: doc/classes/Viewport.xml:205
+msgid ""
+"The global canvas transform of the viewport. The canvas transform is "
+"relative to this."
+msgstr ""
+
+#: doc/classes/Viewport.xml:208
+msgid "If [code]true[/code], the viewport will not receive input event."
+msgstr ""
+
+#: doc/classes/Viewport.xml:213
+msgid ""
+"If [code]true[/code], the GUI controls on the viewport will lay pixel "
+"perfectly."
+msgstr ""
+
+#: doc/classes/Viewport.xml:218
+msgid ""
+"The multisample anti-aliasing mode. A higher number results in smoother "
+"edges at the cost of significantly worse performance. A value of 4 is best "
+"unless targeting very high-end systems."
+msgstr ""
+
+#: doc/classes/Viewport.xml:221
+msgid ""
+"If [code]true[/code], the viewport will use [World3D] defined in "
+"[code]world[/code] property."
+msgstr ""
+
+#: doc/classes/Viewport.xml:224
+msgid ""
+"If [code]true[/code], the objects rendered by viewport become subjects of "
+"mouse picking process."
+msgstr ""
+
+#: doc/classes/Viewport.xml:227
+msgid "The subdivision amount of the first quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:230
+msgid "The subdivision amount of the second quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:233
+msgid "The subdivision amount of the third quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:236
+msgid "The subdivision amount of the fourth quadrant on the shadow atlas."
+msgstr ""
+
+#: doc/classes/Viewport.xml:239
+msgid ""
+"The shadow atlas' resolution (used for omni and spot lights). The value will "
+"be rounded up to the nearest power of 2.\n"
+"[b]Note:[/b] If this is set to 0, shadows won't be visible. Since user-"
+"created viewports default to a value of 0, this value must be set above 0 "
+"manually."
+msgstr ""
+
+#: doc/classes/Viewport.xml:243
+msgid ""
+"If [code]true[/code], the viewport should render its background as "
+"transparent."
+msgstr ""
+
+#: doc/classes/Viewport.xml:246
+msgid "The custom [World3D] which can be used as 3D environment source."
+msgstr ""
+
+#: doc/classes/Viewport.xml:249
+msgid "The custom [World2D] which can be used as 2D environment source."
+msgstr ""
+
+#: doc/classes/Viewport.xml:257
+msgid "Emitted when a Control node grabs keyboard focus."
+msgstr ""
+
+#: doc/classes/Viewport.xml:262
+msgid ""
+"Emitted when the size of the viewport is changed, whether by resizing of "
+"window, or some other means."
+msgstr ""
+
+#: doc/classes/Viewport.xml:268
+msgid "This quadrant will not be used."
+msgstr ""
+
+#: doc/classes/Viewport.xml:271
+msgid "This quadrant will only be used by one shadow map."
+msgstr ""
+
+#: doc/classes/Viewport.xml:274
+msgid "This quadrant will be split in 4 and used by up to 4 shadow maps."
+msgstr ""
+
+#: doc/classes/Viewport.xml:277
+msgid "This quadrant will be split 16 ways and used by up to 16 shadow maps."
+msgstr ""
+
+#: doc/classes/Viewport.xml:280
+msgid "This quadrant will be split 64 ways and used by up to 64 shadow maps."
+msgstr ""
+
+#: doc/classes/Viewport.xml:283
+msgid ""
+"This quadrant will be split 256 ways and used by up to 256 shadow maps. "
+"Unless the [member shadow_atlas_size] is very high, the shadows in this "
+"quadrant will be very low resolution."
+msgstr ""
+
+#: doc/classes/Viewport.xml:286
+msgid ""
+"This quadrant will be split 1024 ways and used by up to 1024 shadow maps. "
+"Unless the [member shadow_atlas_size] is very high, the shadows in this "
+"quadrant will be very low resolution."
+msgstr ""
+
+#: doc/classes/Viewport.xml:289
+msgid "Represents the size of the [enum ShadowAtlasQuadrantSubdiv] enum."
+msgstr ""
+
+#: doc/classes/Viewport.xml:292
+msgid "Amount of objects in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:295
+msgid "Amount of vertices in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:298
+msgid "Amount of material changes in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:301
+msgid "Amount of shader changes in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:304
+msgid "Amount of surface changes in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:307
+msgid "Amount of draw calls in frame."
+msgstr ""
+
+#: doc/classes/Viewport.xml:310
+msgid "Represents the size of the [enum RenderInfo] enum."
+msgstr ""
+
+#: doc/classes/Viewport.xml:313
+msgid "Objects are displayed normally."
+msgstr ""
+
+#: doc/classes/Viewport.xml:316
+msgid "Objects are displayed without light information."
+msgstr ""
+
+#: doc/classes/Viewport.xml:319
+msgid ""
+"Objected are displayed semi-transparent with additive blending so you can "
+"see where they intersect."
+msgstr ""
+
+#: doc/classes/Viewport.xml:322
+msgid "Objects are displayed in wireframe style."
+msgstr ""
+
+#: doc/classes/Viewport.xml:339
+msgid "Multisample anti-aliasing mode disabled. This is the default value."
+msgstr ""
+
+#: doc/classes/Viewport.xml:342
+msgid "Use 2x Multisample Antialiasing."
+msgstr ""
+
+#: doc/classes/Viewport.xml:345
+msgid "Use 4x Multisample Antialiasing."
+msgstr ""
+
+#: doc/classes/Viewport.xml:348
+msgid ""
+"Use 8x Multisample Antialiasing. Likely unsupported on low-end and older "
+"hardware."
+msgstr ""
+
+#: doc/classes/Viewport.xml:351
+msgid ""
+"Use 16x Multisample Antialiasing. Likely unsupported on medium and low-end "
+"hardware."
+msgstr ""
+
+#: doc/classes/ViewportTexture.xml:4
+msgid "Texture which displays the content of a [Viewport]."
+msgstr ""
+
+#: doc/classes/ViewportTexture.xml:7
+msgid ""
+"Displays the content of a [Viewport] node as a dynamic [Texture2D]. This can "
+"be used to mix controls, 2D, and 3D elements in the same scene.\n"
+"To create a ViewportTexture in code, use the [method Viewport.get_texture] "
+"method on the target viewport."
+msgstr ""
+
+#: doc/classes/ViewportTexture.xml:17
+msgid ""
+"The path to the [Viewport] node to display. This is relative to the scene "
+"root, not to the node which uses the texture."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:4 doc/classes/VisibilityEnabler3D.xml:4
+msgid "Enables certain nodes only when visible."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:7
+msgid ""
+"The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and "
+"other nodes when they are not visible. It will only affect nodes with the "
+"same root node as the VisibilityEnabler2D, and the root node itself.\n"
+"Note that VisibilityEnabler2D will not affect nodes added after scene "
+"initialization."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:19
+#: doc/classes/VisibilityEnabler3D.xml:19
+msgid ""
+"Returns whether the enabler identified by given [enum Enabler] constant is "
+"active."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:30
+#: doc/classes/VisibilityEnabler3D.xml:30
+msgid ""
+"Sets active state of the enabler identified by given [enum Enabler] constant."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:36
+msgid "If [code]true[/code], [RigidBody2D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:39
+msgid "If [code]true[/code], [AnimatedSprite2D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:42
+#: doc/classes/VisibilityEnabler3D.xml:39
+msgid "If [code]true[/code], [AnimationPlayer] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:45
+msgid "If [code]true[/code], [GPUParticles2D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:48
+msgid ""
+"If [code]true[/code], the parent's [method Node._physics_process] will be "
+"stopped."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:51
+msgid ""
+"If [code]true[/code], the parent's [method Node._process] will be stopped."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:56
+#: doc/classes/VisibilityEnabler3D.xml:44
+msgid "This enabler will pause [AnimationPlayer] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:59
+msgid "This enabler will freeze [RigidBody2D] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:62
+msgid "This enabler will stop [GPUParticles2D] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:65
+msgid "This enabler will stop the parent's _process function."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:68
+msgid "This enabler will stop the parent's _physics_process function."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:71
+msgid "This enabler will stop [AnimatedSprite2D] nodes animations."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler2D.xml:74
+#: doc/classes/VisibilityEnabler3D.xml:50
+msgid "Represents the size of the [enum Enabler] enum."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler3D.xml:7
+msgid ""
+"The VisibilityEnabler3D will disable [RigidBody3D] and [AnimationPlayer] "
+"nodes when they are not visible. It will only affect other nodes within the "
+"same scene as the VisibilityEnabler3D itself.\n"
+"Note that VisibilityEnabler3D will not affect nodes added after scene "
+"initialization."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler3D.xml:36
+msgid "If [code]true[/code], [RigidBody3D] nodes will be paused."
+msgstr ""
+
+#: doc/classes/VisibilityEnabler3D.xml:47
+msgid "This enabler will freeze [RigidBody3D] nodes."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:4
+#: doc/classes/VisibilityNotifier3D.xml:4
+msgid "Detects when the node is visible on screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:7
+msgid ""
+"The VisibilityNotifier2D detects when it is visible on the screen. It also "
+"notifies when its bounding rectangle enters or exits the screen or a "
+"viewport."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:16
+msgid ""
+"If [code]true[/code], the bounding rectangle is on the screen.\n"
+"[b]Note:[/b] It takes one frame for the node's visibility to be assessed "
+"once added to the scene tree, so this method will return [code]false[/code] "
+"right after it is instantiated, even if it will be on screen in the draw "
+"pass."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:23
+msgid "The VisibilityNotifier2D's bounding rectangle."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:29
+msgid "Emitted when the VisibilityNotifier2D enters the screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:34
+msgid "Emitted when the VisibilityNotifier2D exits the screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:41
+msgid "Emitted when the VisibilityNotifier2D enters a [Viewport]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier2D.xml:48
+msgid "Emitted when the VisibilityNotifier2D exits a [Viewport]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:7
+msgid ""
+"The VisibilityNotifier3D detects when it is visible on the screen. It also "
+"notifies when its bounding rectangle enters or exits the screen or a "
+"[Camera3D]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:16
+msgid ""
+"If [code]true[/code], the bounding box is on the screen.\n"
+"[b]Note:[/b] It takes one frame for the node's visibility to be assessed "
+"once added to the scene tree, so this method will return [code]false[/code] "
+"right after it is instantiated, even if it will be on screen in the draw "
+"pass."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:23
+msgid "The VisibilityNotifier3D's bounding box."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:31
+msgid "Emitted when the VisibilityNotifier3D enters a [Camera3D]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:38
+msgid "Emitted when the VisibilityNotifier3D exits a [Camera3D]'s view."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:43
+msgid "Emitted when the VisibilityNotifier3D enters the screen."
+msgstr ""
+
+#: doc/classes/VisibilityNotifier3D.xml:48
+msgid "Emitted when the VisibilityNotifier3D exits the screen."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:4
+msgid "Parent of all visual 3D nodes."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:7
+msgid ""
+"The [VisualInstance3D] is used to connect a resource to a visual "
+"representation. All visual 3D nodes inherit from the [VisualInstance3D]. In "
+"general, you should not access the [VisualInstance3D] properties directly as "
+"they are accessed and managed by the nodes that inherit from "
+"[VisualInstance3D]. [VisualInstance3D] is the node representation of the "
+"[RenderingServer] instance."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:16
+msgid ""
+"Returns the [AABB] (also known as the bounding box) for this "
+"[VisualInstance3D]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:23
+msgid ""
+"Returns the RID of the resource associated with this [VisualInstance3D]. For "
+"example, if the Node is a [MeshInstance3D], this will return the RID of the "
+"associated [Mesh]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:30
+msgid ""
+"Returns the RID of this instance. This RID is the same as the RID returned "
+"by [method RenderingServer.instance_create]. This RID is needed if you want "
+"to call [RenderingServer] functions directly on this [VisualInstance3D]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:39
+msgid ""
+"Returns [code]true[/code] when the specified layer is enabled in [member "
+"layers] and [code]false[/code] otherwise."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:46
+msgid ""
+"Returns the transformed [AABB] (also known as the bounding box) for this "
+"[VisualInstance3D].\n"
+"Transformed in this case means the [AABB] plus the position, rotation, and "
+"scale of the [Node3D]'s [Transform]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:56
+msgid ""
+"Sets the resource that is instantiated by this [VisualInstance3D], which "
+"changes how the engine handles the [VisualInstance3D] under the hood. "
+"Equivalent to [method RenderingServer.instance_set_base]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:67
+msgid "Enables a particular layer in [member layers]."
+msgstr ""
+
+#: doc/classes/VisualInstance3D.xml:73
+msgid ""
+"The render layer(s) this [VisualInstance3D] is drawn on.\n"
+"This object will only be visible for [Camera3D]s whose cull mask includes "
+"the render object this [VisualInstance3D] is set to."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:4
+msgid "A script implemented in the Visual Script programming environment."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:7
+msgid ""
+"A script implemented in the Visual Script programming environment. The "
+"script extends the functionality of all objects that instance it.\n"
+"[method Object.set_script] extends an existing object, if that object's "
+"class matches one of the script's base classes.\n"
+"You are most likely to use this class via the Visual Script editor or when "
+"writing plugins for it."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:12
+msgid ""
+"https://docs.godotengine.org/en/latest/getting_started/scripting/"
+"visual_script/index.html"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:21
+msgid "Add a custom signal with the specified name to the VisualScript."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:30
+msgid "Add a function with the specified name to the VisualScript."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:45
+msgid "Add a node to a function of the VisualScript."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:58
+msgid ""
+"Add a variable to the VisualScript, optionally giving it a default value or "
+"marking it as exported."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:73
+msgid ""
+"Add an argument to a custom signal added with [method add_custom_signal]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:82
+msgid "Get the count of a custom signal's arguments."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:93
+msgid "Get the name of a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:104
+msgid "Get the type of a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:115
+msgid "Remove a specific custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:128
+msgid "Rename a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:141
+msgid "Change the type of a custom signal's argument."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:154
+msgid "Swap two of the arguments of a custom signal."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:171
+msgid ""
+"Connect two data ports. The value of [code]from_node[/code]'s "
+"[code]from_port[/code] would be fed into [code]to_node[/code]'s "
+"[code]to_port[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:188
+msgid ""
+"Disconnect two data ports previously connected with [method data_connect]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:197
+msgid "Returns the id of a function's entry point node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:206
+msgid "Returns the position of the center of the screen for a given function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:217
+msgid "Returns a node given its id and its function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:228
+msgid "Returns a node's position in pixels."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:237
+msgid "Returns the default (initial) value of a variable."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:246
+msgid "Returns whether a variable is exported."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:255
+msgid ""
+"Returns the information for a given variable as a dictionary. The "
+"information includes its name, type, hint and usage."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:264
+msgid "Returns whether a signal exists with the specified name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:281
+msgid "Returns whether the specified data ports are connected."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:290
+msgid "Returns whether a function exists with the specified name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:301
+msgid "Returns whether a node exists with the given id."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:316
+msgid "Returns whether the specified sequence ports are connected."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:325
+msgid "Returns whether a variable exists with the specified name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:334
+msgid "Remove a custom signal with the given name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:343
+msgid "Remove a specific function and its nodes from the script."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:354
+msgid "Remove a specific node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:363
+msgid "Remove a variable with the given name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:374
+msgid "Change the name of a custom signal."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:385
+msgid "Change the name of a function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:396
+msgid "Change the name of a variable."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:411
+msgid ""
+"Connect two sequence ports. The execution will flow from of [code]from_node[/"
+"code]'s [code]from_output[/code] into [code]to_node[/code].\n"
+"Unlike [method data_connect], there isn't a [code]to_port[/code], since the "
+"target node can have only one sequence port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:427
+msgid ""
+"Disconnect two sequence ports previously connected with [method "
+"sequence_connect]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:438
+msgid "Position the center of the screen for a function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:447
+msgid "Set the base type of the script."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:460
+msgid "Position a node on the screen."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:471
+msgid "Change the default (initial) value of a variable."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:482
+msgid "Change whether a variable is exported."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:493
+msgid ""
+"Set a variable's info, using the same format as [method get_variable_info]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScript.xml:504
+msgid "Emitted when the ports of a node are changed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:4
+msgid "A Visual Script node representing a constant from the base types."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:7
+msgid ""
+"A Visual Script node representing a constant from base types, such as "
+"[constant Vector3.AXIS_X]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:15
+msgid "The type to get the constant from."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml:18
+msgid "The name of the constant to return."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:4
+msgid "A Visual Script node used to call built-in functions."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:7
+msgid ""
+"A built-in function used inside a [VisualScript]. It is usually a math "
+"function or an utility function.\n"
+"See also [@GDScript], for the same functions in the GDScript language."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:16
+msgid "The function to be executed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:21
+msgid "Return the sine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:24
+msgid "Return the cosine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:27
+msgid "Return the tangent of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:30
+msgid "Return the hyperbolic sine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:33
+msgid "Return the hyperbolic cosine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:36
+msgid "Return the hyperbolic tangent of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:39
+msgid "Return the arc sine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:42
+msgid "Return the arc cosine of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:45
+msgid "Return the arc tangent of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:48
+msgid ""
+"Return the arc tangent of the input, using the signs of both parameters to "
+"determine the exact angle."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:51
+msgid "Return the square root of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:54
+msgid ""
+"Return the remainder of one input divided by the other, using floating-point "
+"numbers."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:57
+msgid ""
+"Return the positive remainder of one input divided by the other, using "
+"floating-point numbers."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:60
+msgid "Return the input rounded down."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:63
+msgid "Return the input rounded up."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:66
+msgid "Return the input rounded to the nearest integer."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:69
+msgid "Return the absolute value of the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:72
+msgid ""
+"Return the sign of the input, turning it into 1, -1, or 0. Useful to "
+"determine if the input is positive or negative."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:75
+msgid "Return the input raised to a given power."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:78
+msgid ""
+"Return the natural logarithm of the input. Note that this is not the typical "
+"base-10 logarithm function calculators use."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:81
+msgid ""
+"Return the mathematical constant [b]e[/b] raised to the specified power of "
+"the input. [b]e[/b] has an approximate value of 2.71828."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:84
+msgid ""
+"Return whether the input is NaN (Not a Number) or not. NaN is usually "
+"produced by dividing 0 by 0, though other ways exist."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:87
+msgid ""
+"Return whether the input is an infinite floating-point number or not. "
+"Infinity is usually produced by dividing a number by 0, though other ways "
+"exist."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:93
+msgid ""
+"Return the number of digit places after the decimal that the first non-zero "
+"digit occurs."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:96
+msgid "Return the input snapped to a given step."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:99
+msgid ""
+"Return a number linearly interpolated between the first two inputs, based on "
+"the third input. Uses the formula [code]a + (a - b) * t[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:106
+msgid "Moves the number toward a value, based on the third input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:109
+msgid ""
+"Return the result of [code]value[/code] decreased by [code]step[/code] * "
+"[code]amount[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:112
+msgid ""
+"Randomize the seed (or the internal state) of the random number generator. "
+"Current implementation reseeds using a number based on time."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:115
+msgid ""
+"Return a random 32 bits integer value. To obtain a random value between 0 to "
+"N (where N is smaller than 2^32 - 1), you can use it with the remainder "
+"function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:118
+msgid ""
+"Return a random floating-point value between 0 and 1. To obtain a random "
+"value between 0 to N, you can use it with multiplication."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:121
+msgid "Return a random floating-point value between the two inputs."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:124
+msgid "Set the seed for the random number generator."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:127
+msgid "Return a random value from the given seed, along with the new seed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:130
+msgid "Convert the input from degrees to radians."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:133
+msgid "Convert the input from radians to degrees."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:136
+msgid "Convert the input from linear volume to decibel volume."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:139
+msgid "Convert the input from decibel volume to linear volume."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:152
+msgid "Return the greater of the two numbers, also known as their maximum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:155
+msgid "Return the lesser of the two numbers, also known as their minimum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:158
+msgid ""
+"Return the input clamped inside the given range, ensuring the result is "
+"never outside it. Equivalent to [code]min(max(input, range_low), range_high)"
+"[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:161
+msgid "Return the nearest power of 2 to the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:164
+msgid "Create a [WeakRef] from the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:167
+msgid "Create a [FuncRef] from the input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:170
+msgid "Convert between types."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:173
+msgid ""
+"Return the type of the input as an integer. Check [enum Variant.Type] for "
+"the integers that might be returned."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:176
+msgid "Checks if a type is registered in the [ClassDB]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:179
+msgid "Return a character with the given ascii value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:182
+msgid "Convert the input to a string."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:185
+msgid "Print the given string to the output window."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:188
+msgid "Print the given string to the standard error output."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:191
+msgid ""
+"Print the given string to the standard output, without adding a newline."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:194
+msgid "Serialize a [Variant] to a string."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:197
+msgid ""
+"Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:200
+msgid "Serialize a [Variant] to a [PackedByteArray]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:203
+msgid ""
+"Deserialize a [Variant] from a [PackedByteArray] serialized using [constant "
+"VAR_TO_BYTES]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:206
+msgid ""
+"Return the [Color] with the given name and alpha ranging from 0 to 1.\n"
+"[b]Note:[/b] Names are defined in [code]color_names.inc[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:210
+msgid ""
+"Return a number smoothly interpolated between the first two inputs, based on "
+"the third input. Similar to [constant MATH_LERP], but interpolates faster at "
+"the beginning and slower at the end. Using Hermite interpolation formula:\n"
+"[codeblock]\n"
+"var t = clamp((weight - from) / (to - from), 0.0, 1.0)\n"
+"return t * t * (3.0 - 2.0 * t)\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml:223
+msgid "Represents the size of the [enum BuiltinFunc] enum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:4
+msgid "Gets a constant from a given class."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:7
+msgid ""
+"This node returns a constant from a given class, such as [constant "
+"TYPE_INT]. See the given class' documentation for available constants.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]value[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:19
+msgid "The constant's parent class."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptClassConstant.xml:22
+msgid ""
+"The constant to return. See the given class for its available constants."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:4
+msgid "A Visual Script node used to annotate the script."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:7
+msgid ""
+"A Visual Script node used to display annotations in the script, so that code "
+"may be documented.\n"
+"Comment nodes can be resized so they encompass a group of nodes."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:16
+msgid "The text inside the comment node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:19
+msgid "The comment node's size (in pixels)."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComment.xml:22
+msgid "The comment node's title."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComposeArray.xml:4
+msgid "A Visual Script Node used to create array from a list of items."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptComposeArray.xml:7
+msgid ""
+"A Visual Script Node used to compose array from the list of elements "
+"provided with custom in-graph UI hard coded in the VisualScript Editor."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCondition.xml:4
+msgid "A Visual Script node which branches the flow."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCondition.xml:7
+msgid ""
+"A Visual Script node that checks a [bool] input port. If [code]true[/code], "
+"it will exit via the \"true\" sequence port. If [code]false[/code], it will "
+"exit via the \"false\" sequence port. After exiting either, it exits via the "
+"\"done\" port. Sequence ports may be left disconnected.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]if (cond) is[/code]\n"
+"- Data (boolean): [code]cond[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]true[/code]\n"
+"- Sequence: [code]false[/code]\n"
+"- Sequence: [code]done[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:4
+msgid "Gets a contant's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:7
+msgid ""
+"This node returns a constant's value.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:19
+msgid "The constant's type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstant.xml:22
+msgid "The constant's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstructor.xml:4
+msgid "A Visual Script node which calls a base type constructor."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptConstructor.xml:7
+msgid ""
+"A Visual Script node which calls a base type constructor. It can be used for "
+"type conversion as well."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:4
+msgid "A scripted Visual Script node."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:7
+msgid "A custom Visual Script node which can be scripted in powerful ways."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:16
+msgid "Return the node's title."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:23
+msgid "Return the node's category."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:30
+msgid "Return the count of input value ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:39
+msgid "Return the specified input port's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:48
+msgid ""
+"Return the specified input port's type. See the [enum Variant.Type] values."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:55
+msgid "Return the amount of output [b]sequence[/b] ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:64
+msgid "Return the specified [b]sequence[/b] output's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:71
+msgid "Return the amount of output value ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:80
+msgid "Return the specified output's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:89
+msgid "Return the specified output's type. See the [enum Variant.Type] values."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:96
+msgid ""
+"Return the custom node's text, which is shown right next to the input "
+"[b]sequence[/b] port (if there is none, on the place that is usually taken "
+"by it)."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:103
+msgid ""
+"Return the size of the custom node's working memory. See [method _step] for "
+"more details."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:110
+msgid "Return whether the custom node has an input [b]sequence[/b] port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:125
+msgid ""
+"Execute the custom node's logic, returning the index of the output sequence "
+"port to use or a [String] when there is an error.\n"
+"The [code]inputs[/code] array contains the values of the input ports.\n"
+"[code]outputs[/code] is an array whose indices should be set to the "
+"respective outputs.\n"
+"The [code]start_mode[/code] is usually [constant START_MODE_BEGIN_SEQUENCE], "
+"unless you have used the [code]STEP_*[/code] constants.\n"
+"[code]working_mem[/code] is an array which can be used to persist "
+"information between runs of the custom node.\n"
+"When returning, you can mask the returned value with one of the "
+"[code]STEP_*[/code] constants."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:136
+msgid "The start mode used the first time when [method _step] is called."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:139
+msgid ""
+"The start mode used when [method _step] is called after coming back from a "
+"[constant STEP_PUSH_STACK_BIT]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:142
+msgid ""
+"The start mode used when [method _step] is called after resuming from "
+"[constant STEP_YIELD_BIT]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:145
+msgid ""
+"Hint used by [method _step] to tell that control should return to it when "
+"there is no other node left to execute.\n"
+"This is used by [VisualScriptCondition] to redirect the sequence to the "
+"\"Done\" port after the [code]true[/code]/[code]false[/code] branch has "
+"finished execution."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:149
+msgid ""
+"Hint used by [method _step] to tell that control should return back, either "
+"hitting a previous [constant STEP_PUSH_STACK_BIT] or exiting the function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:154
+msgid ""
+"Hint used by [method _step] to tell that control should stop and exit the "
+"function."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml:157
+msgid ""
+"Hint used by [method _step] to tell that the function should be yielded.\n"
+"Using this requires you to have at least one working memory slot, which is "
+"used for the [VisualScriptFunctionState]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml:4
+#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml:7
+msgid ""
+"A Visual Script node which deconstructs a base type instance into its parts."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml:15
+msgid "The type to deconstruct."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEditor.xml:20
+msgid ""
+"Add a custom Visual Script node to the editor. It'll be placed under "
+"\"Custom Nodes\" with the [code]category[/code] as the parameter."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEditor.xml:31
+msgid ""
+"Remove a custom Visual Script node from the editor. Custom nodes already "
+"placed on scripts won't be removed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEditor.xml:38
+msgid "Emitted when a custom Visual Script node is added or removed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml:4
+msgid "Emits a specified signal."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml:7
+msgid ""
+"Emits a specified signal when it is executed.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]emit[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml:19
+msgid "The signal to emit."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml:4
+#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml:7
+msgid "A Visual Script node returning a singleton from [@GlobalScope]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml:15
+msgid "The singleton's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptIterator.xml:4
+msgid "Steps through items in a given input."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptIterator.xml:7
+msgid ""
+"This node steps through each item in a given input. Input can be any "
+"sequence data type, such as an [Array] or [String]. When each item has been "
+"processed, execution passed out the [code]exit[/code] Sequence port.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]for (elem) in (input)[/code]\n"
+"- Data (variant): [code]input[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]each[/code]\n"
+"- Sequence: [code]exit[/code]\n"
+"- Data (variant): [code]elem[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLists.xml:4
+msgid "A Visual Script virtual class for in-graph editable nodes."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLists.xml:7
+msgid ""
+"A Visual Script virtual class that defines the shape and the default "
+"behaviour of the nodes that have to be in-graph editable nodes."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:4
+msgid "Gets a local variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:7
+msgid ""
+"Returns a local variable's value. \"Var Name\" must be supplied, with an "
+"optional type.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:19
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:21
+msgid "The local variable's type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVar.xml:22
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:24
+msgid "The local variable's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:4
+msgid "Changes a local variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml:7
+msgid ""
+"Changes a local variable's value to the given input. The new value is also "
+"provided on an output Data port.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]set[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:4
+msgid "Commonly used mathematical constants."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:7
+msgid ""
+"Provides common math constants, such as Pi, on an output Data port.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]get[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:19
+msgid "The math constant."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:24
+msgid "Unity: [code]1[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:27
+msgid "Pi: [code]3.141593[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:30
+msgid "Pi divided by two: [code]1.570796[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:33
+msgid "Tau: [code]6.283185[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:36
+msgid ""
+"Mathematical constant [code]e[/code], the natural log base: [code]2.718282[/"
+"code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:39
+msgid "Square root of two: [code]1.414214[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:42
+msgid "Infinity: [code]inf[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:45
+msgid "Not a number: [code]nan[/code]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptMathConstant.xml:48
+msgid "Represents the size of the [enum MathConstant] enum."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:4
+msgid "A node which is part of a [VisualScript]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:7
+msgid ""
+"A node which is part of a [VisualScript]. Not to be confused with [Node], "
+"which is a part of a [SceneTree]."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:18
+msgid ""
+"Returns the default value of a given port. The default value is used when "
+"nothing is connected to the port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:25
+msgid "Returns the [VisualScript] instance the node is bound to."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:32
+msgid ""
+"Notify that the node's ports have changed. Usually used in conjunction with "
+"[VisualScriptCustomNode] ."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:43
+msgid "Change the default value of a given port."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptNode.xml:50
+msgid "Emitted when the available input/output ports are changed."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptOperator.xml:6
+msgid ""
+"[b]Input Ports:[/b]\n"
+"- Data (variant): [code]A[/code]\n"
+"- Data (variant): [code]B[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]result[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptPreload.xml:4
+msgid "Creates a new [Resource] or loads one from the filesystem."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptPreload.xml:7
+msgid ""
+"Creates a new [Resource] or loads one from the filesystem.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (object): [code]res[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptPreload.xml:19
+msgid "The [Resource] to load."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:4
+msgid "Exits a function and returns an optional value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:7
+msgid ""
+"Ends the execution of a function and returns control to the calling "
+"function. Optionally, it can return a [Variant] value.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]result[/code] (optional)\n"
+"[b]Output Ports:[/b]\n"
+"none"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:20
+msgid "If [code]true[/code], the [code]return[/code] input port is available."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptReturn.xml:23
+msgid "The return value's data type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSceneNode.xml:4
+msgid "Node reference."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSceneNode.xml:7
+msgid ""
+"A direct reference to a node.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data: [code]node[/code] (obj)"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSceneNode.xml:19
+msgid "The node's path in the scene tree."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelect.xml:4
+msgid "Chooses between two input values."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelect.xml:7
+msgid ""
+"Chooses between two input values based on a Boolean condition.\n"
+"[b]Input Ports:[/b]\n"
+"- Data (boolean): [code]cond[/code]\n"
+"- Data (variant): [code]a[/code]\n"
+"- Data (variant): [code]b[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]out[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelect.xml:21
+msgid "The input variables' type."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelf.xml:4
+msgid "Outputs a reference to the current instance."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSelf.xml:7
+msgid ""
+"Provides a reference to the node running the visual script.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (object): [code]instance[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSequence.xml:4
+msgid "Executes a series of Sequence ports."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSequence.xml:7
+msgid ""
+"Steps through a series of one or more output Sequence ports. The "
+"[code]current[/code] data port outputs the currently executing item.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]in order[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]1[/code]\n"
+"- Sequence: [code]2 - n[/code] (optional)\n"
+"- Data (int): [code]current[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSequence.xml:21
+msgid "The number of steps in the sequence."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSwitch.xml:4
+msgid "Branches program flow based on a given input's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptSwitch.xml:7
+msgid ""
+"Branches the flow based on an input's value. Use [b]Case Count[/b] in the "
+"Inspector to set the number of branches and each comparison's optional "
+"type.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]'input' is[/code]\n"
+"- Data (variant): [code]=[/code]\n"
+"- Data (variant): [code]=[/code] (optional)\n"
+"- Data (variant): [code]input[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence\n"
+"- Sequence (optional)\n"
+"- Sequence: [code]done[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableGet.xml:4
+msgid "Gets a variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableGet.xml:7
+msgid ""
+"Returns a variable's value. \"Var Name\" must be supplied, with an optional "
+"type.\n"
+"[b]Input Ports:[/b]\n"
+"none\n"
+"[b]Output Ports:[/b]\n"
+"- Data (variant): [code]value[/code]"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableGet.xml:19
+#: modules/visual_script/doc_classes/VisualScriptVariableSet.xml:20
+msgid "The variable's name."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableSet.xml:4
+msgid "Changes a variable's value."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptVariableSet.xml:7
+msgid ""
+"Changes a variable's value to the given input.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence\n"
+"- Data (variant): [code]set[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence"
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptWhile.xml:4
+msgid "Conditional loop."
+msgstr ""
+
+#: modules/visual_script/doc_classes/VisualScriptWhile.xml:7
+msgid ""
+"Loops while a condition is [code]true[/code]. Execution continues out the "
+"[code]exit[/code] Sequence port when the loop terminates.\n"
+"[b]Input Ports:[/b]\n"
+"- Sequence: [code]while(cond)[/code]\n"
+"- Data (bool): [code]cond[/code]\n"
+"[b]Output Ports:[/b]\n"
+"- Sequence: [code]repeat[/code]\n"
+"- Sequence: [code]exit[/code]"
+msgstr ""
+
+#: doc/classes/VisualShader.xml:4
+msgid "A custom shader program with a visual editor."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:7
+msgid ""
+"This class allows you to define a custom shader program that can be used for "
+"various materials to render objects.\n"
+"The visual shader editor creates the shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:25
+msgid "Adds the specified node to the shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:42
+msgid ""
+"Returns [code]true[/code] if the specified nodes and ports can be connected "
+"together."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:59 doc/classes/VisualShader.xml:93
+msgid "Connects the specified nodes and ports."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:76
+msgid ""
+"Connects the specified nodes and ports, even if they can't be connected. "
+"Such connection is invalid and will not function properly."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:104
+msgid ""
+"Returns the shader node instance with specified [code]type[/code] and "
+"[code]id[/code]."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:113
+msgid "Returns the list of connected nodes with the specified type."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:122
+msgid "Returns the list of all nodes in the shader with the specified type."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:133
+msgid "Returns the position of the specified node within the shader graph."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:158
+msgid ""
+"Returns [code]true[/code] if the specified node and port connection exist."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:169
+msgid "Removes the specified node from the shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:178
+msgid "Sets the mode of this shader."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:191
+msgid "Sets the position of the specified node."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:198
+msgid "The offset vector of the whole graph."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:205
+msgid "A vertex shader, operating on vertices."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:208
+msgid "A fragment shader, operating on fragments (pixels)."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:211
+msgid "A shader for light calculations."
+msgstr ""
+
+#: doc/classes/VisualShader.xml:214
+msgid "Represents the size of the [enum Type] enum."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:4
+msgid "Base class for nodes in a visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:9
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/shading/visual_shaders.html"
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:16
+msgid ""
+"Returns an [Array] containing default values for all of the input ports of "
+"the node in the form [code][index0, value0, index1, value1, ...][/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:25
+msgid "Returns the default value of the input [code]port[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:34
+msgid ""
+"Sets the default input ports values using an [Array] of the form [code]"
+"[index0, value0, index1, value1, ...][/code]. For example: [code][0, "
+"Vector3(0, 0, 0), 1, Vector3(0, 0, 0)][/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:45
+msgid "Sets the default value for the selected input [code]port[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:51
+msgid ""
+"Sets the output port index which will be showed for preview. If set to "
+"[code]-1[/code] no port will be open for preview."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:57
+msgid ""
+"Emitted when the node requests an editor refresh. Currently called only in "
+"setter of [member VisualShaderNodeTexture.source], "
+"[VisualShaderNodeTexture], and [VisualShaderNodeCubemap] (and their "
+"derivatives)."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:63
+msgid ""
+"Floating-point scalar. Translated to [code]float[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:66
+msgid "Integer scalar. Translated to [code]int[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:69
+msgid ""
+"3D vector of floating-point values. Translated to [code]vec3[/code] type in "
+"shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:72
+msgid "Boolean type. Translated to [code]bool[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:75
+msgid "Transform type. Translated to [code]mat4[/code] type in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:78
+msgid ""
+"Sampler type. Translated to reference of sampler uniform in shader code. Can "
+"only be used for input ports in non-uniform nodes."
+msgstr ""
+
+#: doc/classes/VisualShaderNode.xml:81
+msgid "Represents the size of the [enum PortType] enum."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanConstant.xml:4
+msgid "A boolean constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanConstant.xml:7
+msgid ""
+"Has only one output port and no inputs.\n"
+"Translated to [code]bool[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanConstant.xml:16
+msgid "A boolean constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanUniform.xml:4
+msgid "A boolean uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeBooleanUniform.xml:7
+msgid "Translated to [code]uniform bool[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorConstant.xml:4
+msgid "A [Color] constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorConstant.xml:7
+msgid ""
+"Has two output ports representing RGB and alpha channels of [Color].\n"
+"Translated to [code]vec3 rgb[/code] and [code]float alpha[/code] in the "
+"shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorConstant.xml:16
+msgid "A [Color] constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:4
+msgid "A [Color] function to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:7
+msgid ""
+"Accept a [Color] to the input port and transform it according to [member "
+"function]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:15
+msgid ""
+"A function to be applied to the input color. See [enum Function] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:20
+msgid ""
+"Converts the color to grayscale using the following formula:\n"
+"[codeblock]\n"
+"vec3 c = input;\n"
+"float max1 = max(c.r, c.g);\n"
+"float max2 = max(max1, c.b);\n"
+"float max3 = max(max1, max2);\n"
+"return vec3(max3, max3, max3);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorFunc.xml:30
+msgid ""
+"Applies sepia tone effect using the following formula:\n"
+"[codeblock]\n"
+"vec3 c = input;\n"
+"float r = (c.r * 0.393) + (c.g * 0.769) + (c.b * 0.189);\n"
+"float g = (c.r * 0.349) + (c.g * 0.686) + (c.b * 0.168);\n"
+"float b = (c.r * 0.272) + (c.g * 0.534) + (c.b * 0.131);\n"
+"return vec3(r, g, b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:4
+msgid "A [Color] operator to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:7
+msgid "Applies [member operator] to two color inputs."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:15
+#: doc/classes/VisualShaderNodeFloatOp.xml:15
+#: doc/classes/VisualShaderNodeIntOp.xml:15
+msgid ""
+"An operator to be applied to the inputs. See [enum Operator] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:20
+msgid ""
+"Produce a screen effect with the following formula:\n"
+"[codeblock]\n"
+"result = vec3(1.0) - (vec3(1.0) - a) * (vec3(1.0) - b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:26
+msgid ""
+"Produce a difference effect with the following formula:\n"
+"[codeblock]\n"
+"result = abs(a - b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:32
+msgid ""
+"Produce a darken effect with the following formula:\n"
+"[codeblock]\n"
+"result = min(a, b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:38
+msgid ""
+"Produce a lighten effect with the following formula:\n"
+"[codeblock]\n"
+"result = max(a, b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:44
+msgid ""
+"Produce an overlay effect with the following formula:\n"
+"[codeblock]\n"
+"for (int i = 0; i < 3; i++) {\n"
+" float base = a[i];\n"
+" float blend = b[i];\n"
+" if (base < 0.5) {\n"
+" result[i] = 2.0 * base * blend;\n"
+" } else {\n"
+" result[i] = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"
+" }\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:58
+msgid ""
+"Produce a dodge effect with the following formula:\n"
+"[codeblock]\n"
+"result = a / (vec3(1.0) - b);\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:64
+msgid ""
+"Produce a burn effect with the following formula:\n"
+"[codeblock]\n"
+"result = vec3(1.0) - (vec3(1.0) - a) / b;\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:70
+msgid ""
+"Produce a soft light effect with the following formula:\n"
+"[codeblock]\n"
+"for (int i = 0; i < 3; i++) {\n"
+" float base = a[i];\n"
+" float blend = b[i];\n"
+" if (base < 0.5) {\n"
+" result[i] = base * (blend + 0.5);\n"
+" } else {\n"
+" result[i] = 1.0 - (1.0 - base) * (1.0 - (blend - 0.5));\n"
+" }\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorOp.xml:84
+msgid ""
+"Produce a hard light effect with the following formula:\n"
+"[codeblock]\n"
+"for (int i = 0; i < 3; i++) {\n"
+" float base = a[i];\n"
+" float blend = b[i];\n"
+" if (base < 0.5) {\n"
+" result[i] = base * (2.0 * blend);\n"
+" } else {\n"
+" result[i] = 1.0 - (1.0 - base) * (1.0 - 2.0 * (blend - 0.5));\n"
+" }\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorUniform.xml:4
+msgid "A [Color] uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeColorUniform.xml:7
+msgid "Translated to [code]uniform vec4[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:4
+msgid "A comparison function for common types within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:7
+msgid ""
+"Compares [code]a[/code] and [code]b[/code] of [member type] by [member "
+"function]. Returns a boolean scalar. Translates to [code]if[/code] "
+"instruction in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:15
+msgid ""
+"Extra condition which is applied if [member type] is set to [constant "
+"CTYPE_VECTOR]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:18
+msgid "A comparison function. See [enum Function] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:21
+msgid ""
+"The type to be used in the comparison. See [enum ComparisonType] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:26
+msgid "A floating-point scalar."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:29
+msgid "An integer scalar."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:32
+msgid "A 3D vector type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:35
+msgid "A boolean type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:38
+msgid "A transform ([code]mat4[/code]) type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:41
+msgid "Comparison for equality ([code]a == b[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:44
+msgid "Comparison for inequality ([code]a != b[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:47
+msgid ""
+"Comparison for greater than ([code]a > b[/code]). Cannot be used if [member "
+"type] set to [constant CTYPE_BOOLEAN] or [constant CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:50
+msgid ""
+"Comparison for greater than or equal ([code]a >= b[/code]). Cannot be used "
+"if [member type] set to [constant CTYPE_BOOLEAN] or [constant "
+"CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:53
+msgid ""
+"Comparison for less than ([code]a < b[/code]). Cannot be used if [member "
+"type] set to [constant CTYPE_BOOLEAN] or [constant CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:56
+msgid ""
+"Comparison for less than or equal ([code]a <= b[/code]). Cannot be used if "
+"[member type] set to [constant CTYPE_BOOLEAN] or [constant CTYPE_TRANSFORM]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:59
+msgid ""
+"The result will be true if all of component in vector satisfy the comparison "
+"condition."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCompare.xml:62
+msgid ""
+"The result will be true if any of component in vector satisfy the comparison "
+"condition."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:4
+msgid "A [Cubemap] sampling node to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:7
+msgid ""
+"Translated to [code]texture(cubemap, vec3)[/code] in the shader language. "
+"Returns a color vector and alpha channel as scalar."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:15
+msgid ""
+"The [Cubemap] texture to sample when using [constant SOURCE_TEXTURE] as "
+"[member source]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:18
+msgid ""
+"Defines which source should be used for the sampling. See [enum Source] for "
+"options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:21
+msgid ""
+"Defines the type of data provided by the source texture. See [enum "
+"TextureType] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:26
+msgid ""
+"Use the [Cubemap] set via [member cube_map]. If this is set to [member "
+"source], the [code]samplerCube[/code] port is ignored."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:29
+msgid ""
+"Use the [Cubemap] sampler reference passed via the [code]samplerCube[/code] "
+"port. If this is set to [member source], the [member cube_map] texture is "
+"ignored."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:32
+msgid "No hints are added to the uniform declaration."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:35
+msgid ""
+"Adds [code]hint_albedo[/code] as hint to the uniform declaration for proper "
+"sRGB to linear conversion."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemap.xml:38
+msgid ""
+"Adds [code]hint_normal[/code] as hint to the uniform declaration, which "
+"internally converts the texture for proper usage as normal map."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemapUniform.xml:4
+msgid "A [Cubemap] uniform node to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCubemapUniform.xml:7
+msgid ""
+"Translated to [code]uniform samplerCube[/code] in the shader language. The "
+"output value can be used as port for [VisualShaderNodeCubemap]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:4
+msgid ""
+"Virtual class to define custom [VisualShaderNode]s for use in the Visual "
+"Shader Editor."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:7
+msgid ""
+"By inheriting this class you can create a custom [VisualShader] script addon "
+"which will be automatically added to the Visual Shader Editor. The "
+"[VisualShaderNode]'s behavior is defined by overriding the provided virtual "
+"methods.\n"
+"In order for the node to be registered as an editor addon, you must use the "
+"[code]tool[/code] keyword and provide a [code]class_name[/code] for your "
+"custom script. For example:\n"
+"[codeblock]\n"
+"tool\n"
+"extends VisualShaderNodeCustom\n"
+"class_name VisualShaderNodeNoise\n"
+"[/codeblock]"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:16
+msgid ""
+"https://docs.godotengine.org/en/latest/tutorials/plugins/editor/"
+"visual_shader_plugins.html"
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:23
+msgid ""
+"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].\n"
+"Defining this method is [b]optional[/b]. If not overridden, the node will be "
+"filed under the \"Addons\" category."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:39
+msgid ""
+"Override this method to define the actual shader code of the associated "
+"custom node. The shader code should be returned as a string, which can have "
+"multiple lines (the [code]\"\"\"[/code] multiline string construct can be "
+"used for convenience).\n"
+"The [code]input_vars[/code] and [code]output_vars[/code] arrays contain the "
+"string names of the various input and output variables, as defined by "
+"[code]_get_input_*[/code] and [code]_get_output_*[/code] virtual methods in "
+"this class.\n"
+"The output ports can be assigned values in the shader code. For example, "
+"[code]return output_vars[0] + \" = \" + input_vars[0] + \";\"[/code].\n"
+"You can customize the generated code based on the shader [code]mode[/code] "
+"(see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader."
+"Type]).\n"
+"Defining this method is [b]required[/b]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:50
+msgid ""
+"Override this method to define the description of the associated custom node "
+"in the Visual Shader Editor's members dialog.\n"
+"Defining this method is [b]optional[/b]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:60
+msgid ""
+"Override this method to add shader code on top of the global shader, to "
+"define your own standard library of reusable methods, varyings, constants, "
+"uniforms, etc. The shader code should be returned as a string, which can "
+"have multiple lines (the [code]\"\"\"[/code] multiline string construct can "
+"be used for convenience).\n"
+"Be careful with this functionality as it can cause name conflicts with other "
+"custom nodes, so be sure to give the defined entities unique names.\n"
+"You can customize the generated code based on the shader [code]mode[/code] "
+"(see [enum Shader.Mode]).\n"
+"Defining this method is [b]optional[/b]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:70
+msgid ""
+"Override this method to define the amount of input ports of the associated "
+"custom node.\n"
+"Defining this method is [b]required[/b]. If not overridden, the node has no "
+"input ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:80
+msgid ""
+"Override this method to define the names of input ports of the associated "
+"custom node. The names are used both for the input slots in the editor and "
+"as identifiers in the shader code, and are passed in the [code]input_vars[/"
+"code] array in [method _get_code].\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"input ports are named as [code]\"in\" + str(port)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:90
+msgid ""
+"Override this method to define the returned type of each input port of the "
+"associated custom node (see [enum VisualShaderNode.PortType] for possible "
+"types).\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"input ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] "
+"type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:98
+msgid ""
+"Override this method to define the name of the associated custom node in the "
+"Visual Shader Editor's members dialog and graph.\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"the node will be named as \"Unnamed\"."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:106
+msgid ""
+"Override this method to define the amount of output ports of the associated "
+"custom node.\n"
+"Defining this method is [b]required[/b]. If not overridden, the node has no "
+"output ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:116
+msgid ""
+"Override this method to define the names of output ports of the associated "
+"custom node. The names are used both for the output slots in the editor and "
+"as identifiers in the shader code, and are passed in the [code]output_vars[/"
+"code] array in [method _get_code].\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"output ports are named as [code]\"out\" + str(port)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:126
+msgid ""
+"Override this method to define the returned type of each output port of the "
+"associated custom node (see [enum VisualShaderNode.PortType] for possible "
+"types).\n"
+"Defining this method is [b]optional[/b], but recommended. If not overridden, "
+"output ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] "
+"type."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:134
+msgid ""
+"Override this method to define the return icon of the associated custom node "
+"in the Visual Shader Editor's members dialog.\n"
+"Defining this method is [b]optional[/b]. If not overridden, no return icon "
+"is shown."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeCustom.xml:142
+msgid ""
+"Override this method to enable high-end mark in the Visual Shader Editor's "
+"members dialog.\n"
+"Defining this method is [b]optional[/b]. If not overridden, it's false."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDeterminant.xml:4
+msgid ""
+"Calculates the determinant of a [Transform] within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDeterminant.xml:7
+msgid "Translates to [code]deteminant(x)[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDotProduct.xml:4
+msgid "Calculates a dot product of two vectors within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeDotProduct.xml:7
+msgid "Translates to [code]dot(a, b)[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeExpression.xml:4
+msgid ""
+"A custom visual shader graph expression written in Godot Shading Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeExpression.xml:7
+msgid ""
+"Custom Godot Shading Language expression, with a custom amount of input and "
+"output ports.\n"
+"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."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeExpression.xml:16
+msgid ""
+"An expression in Godot Shading Language, which will be injected at the start "
+"of the graph's matching shader function ([code]vertex[/code], "
+"[code]fragment[/code], or [code]light[/code]), and thus cannot be used to "
+"declare functions, varyings, uniforms, or global constants."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFaceForward.xml:4
+msgid ""
+"Returns the vector that points in the same direction as a reference vector "
+"within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFaceForward.xml:7
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatConstant.xml:4
+msgid ""
+"A scalar floating-point constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatConstant.xml:7
+msgid "Translated to [code]float[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatConstant.xml:15
+msgid "A floating-point constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:4
+msgid ""
+"A scalar floating-point function to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:7
+msgid ""
+"Accept a floating-point scalar ([code]x[/code]) to the input port and "
+"transform it according to [member function]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:15
+#: doc/classes/VisualShaderNodeIntFunc.xml:15
+msgid ""
+"A function to be applied to the scalar. See [enum Function] for options."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:20
+msgid ""
+"Returns the sine of the parameter. Translates to [code]sin(x)[/code] in the "
+"Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:23
+msgid ""
+"Returns the cosine of the parameter. Translates to [code]cos(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:26
+msgid ""
+"Returns the tangent of the parameter. Translates to [code]tan(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:29
+msgid ""
+"Returns the arc-sine of the parameter. Translates to [code]asin(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:32
+msgid ""
+"Returns the arc-cosine of the parameter. Translates to [code]acos(x)[/code] "
+"in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:35
+msgid ""
+"Returns the arc-tangent of the parameter. Translates to [code]atan(x)[/code] "
+"in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:38
+msgid ""
+"Returns the hyperbolic sine of the parameter. Translates to [code]sinh(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:41
+msgid ""
+"Returns the hyperbolic cosine of the parameter. Translates to [code]cosh(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:44
+msgid ""
+"Returns the hyperbolic tangent of the parameter. Translates to [code]tanh(x)"
+"[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:47
+msgid ""
+"Returns the natural logarithm of the parameter. Translates to [code]log(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:50
+msgid ""
+"Returns the natural exponentiation of the parameter. Translates to "
+"[code]exp(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:53
+msgid ""
+"Returns the square root of the parameter. Translates to [code]sqrt(x)[/code] "
+"in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:56
+#: doc/classes/VisualShaderNodeIntFunc.xml:20
+msgid ""
+"Returns the absolute value of the parameter. Translates to [code]abs(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:59
+#: doc/classes/VisualShaderNodeIntFunc.xml:29
+msgid ""
+"Extracts the sign of the parameter. Translates to [code]sign(x)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:62
+msgid ""
+"Finds the nearest integer less than or equal to the parameter. Translates to "
+"[code]floor(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:65
+msgid ""
+"Finds the nearest integer to the parameter. Translates to [code]round(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:68
+msgid ""
+"Finds the nearest integer that is greater than or equal to the parameter. "
+"Translates to [code]ceil(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:71
+msgid ""
+"Computes the fractional part of the argument. Translates to [code]fract(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:74
+msgid ""
+"Clamps the value between [code]0.0[/code] and [code]1.0[/code] using "
+"[code]min(max(x, 0.0), 1.0)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:77
+#: doc/classes/VisualShaderNodeIntFunc.xml:26
+msgid "Negates the [code]x[/code] using [code]-(x)[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:80
+msgid ""
+"Returns the arc-hyperbolic-cosine of the parameter. Translates to "
+"[code]acosh(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:83
+msgid ""
+"Returns the arc-hyperbolic-sine of the parameter. Translates to "
+"[code]asinh(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:86
+msgid ""
+"Returns the arc-hyperbolic-tangent of the parameter. Translates to "
+"[code]atanh(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:89
+msgid ""
+"Convert a quantity in radians to degrees. Translates to [code]degrees(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:92
+msgid ""
+"Returns 2 raised by the power of the parameter. Translates to [code]exp2(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:95
+msgid ""
+"Returns the inverse of the square root of the parameter. Translates to "
+"[code]inversesqrt(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:98
+msgid ""
+"Returns the base 2 logarithm of the parameter. Translates to [code]log2(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:101
+msgid ""
+"Convert a quantity in degrees to radians. Translates to [code]radians(x)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:104
+msgid ""
+"Finds reciprocal value of dividing 1 by [code]x[/code] (i.e. [code]1 / x[/"
+"code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:107
+msgid ""
+"Finds the nearest even integer to the parameter. Translates to "
+"[code]roundEven(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:110
+msgid ""
+"Returns a value equal to the nearest integer to [code]x[/code] whose "
+"absolute value is not larger than the absolute value of [code]x[/code]. "
+"Translates to [code]trunc(x)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatFunc.xml:113
+msgid "Subtracts scalar [code]x[/code] from 1 (i.e. [code]1 - x[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:4
+msgid ""
+"A floating-point scalar operator to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:7
+msgid ""
+"Applies [member operator] to two floating-point inputs: [code]a[/code] and "
+"[code]b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:20
+#: doc/classes/VisualShaderNodeIntOp.xml:20
+msgid "Sums two numbers using [code]a + b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:23
+#: doc/classes/VisualShaderNodeIntOp.xml:23
+msgid "Subtracts two numbers using [code]a - b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:26
+#: doc/classes/VisualShaderNodeIntOp.xml:26
+msgid "Multiplies two numbers using [code]a * b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:29
+#: doc/classes/VisualShaderNodeIntOp.xml:29
+msgid "Divides two numbers using [code]a / b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:32
+msgid ""
+"Calculates the remainder of two numbers. Translates to [code]mod(a, b)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:35
+msgid ""
+"Raises the [code]a[/code] to the power of [code]b[/code]. Translates to "
+"[code]pow(a, b)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:38
+#: doc/classes/VisualShaderNodeIntOp.xml:35
+msgid ""
+"Returns the greater of two numbers. Translates to [code]max(a, b)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:41
+msgid ""
+"Returns the lesser of two numbers. Translates to [code]min(a, b)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:44
+msgid ""
+"Returns the arc-tangent of the parameters. Translates to [code]atan(a, b)[/"
+"code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatOp.xml:47
+msgid ""
+"Generates a step function by comparing [code]b[/code](x) to [code]a[/code]"
+"(edge). Returns 0.0 if [code]x[/code] is smaller than [code]edge[/code] and "
+"otherwise 1.0. Translates to [code]step(a, b)[/code] in the Godot Shader "
+"Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:4
+msgid "A scalar float uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:7
+msgid "Translated to [code]uniform float[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:15
+#: doc/classes/VisualShaderNodeIntUniform.xml:15
+msgid ""
+"A hint applied to the uniform, which controls the values it can take when "
+"set through the inspector."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:18
+#: doc/classes/VisualShaderNodeIntUniform.xml:18
+msgid ""
+"Minimum value for range hints. Used if [member hint] is set to [constant "
+"HINT_RANGE] or [constant HINT_RANGE_STEP]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:21
+#: doc/classes/VisualShaderNodeIntUniform.xml:21
+msgid ""
+"Maximum value for range hints. Used if [member hint] is set to [constant "
+"HINT_RANGE] or [constant HINT_RANGE_STEP]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:24
+#: doc/classes/VisualShaderNodeIntUniform.xml:24
+msgid ""
+"Step (increment) value for the range hint with step. Used if [member hint] "
+"is set to [constant HINT_RANGE_STEP]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:29
+#: doc/classes/VisualShaderNodeIntUniform.xml:29
+msgid "No hint used."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:32
+#: doc/classes/VisualShaderNodeIntUniform.xml:32
+msgid ""
+"A range hint for scalar value, which limits possible input values between "
+"[member min] and [member max]. Translated to [code]hint_range(min, max)[/"
+"code] in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFloatUniform.xml:35
+#: doc/classes/VisualShaderNodeIntUniform.xml:35
+msgid ""
+"A range hint for scalar value with step, which limits possible input values "
+"between [member min] and [member max], with a step (increment) of [member "
+"step]). Translated to [code]hint_range(min, max, step)[/code] in shader code."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFresnel.xml:4
+msgid "A Fresnel effect to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeFresnel.xml:7
+msgid ""
+"Returns falloff based on the dot product of surface normal and view "
+"direction of camera (pass associated inputs to it)."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGlobalExpression.xml:4
+msgid ""
+"A custom global visual shader graph expression written in Godot Shading "
+"Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGlobalExpression.xml:7
+msgid ""
+"Custom Godot Shader Language expression, which is placed on top of the "
+"generated shader. You can place various function definitions inside to call "
+"later in [VisualShaderNodeExpression]s (which are injected in the main "
+"shader functions). You can also declare varyings, uniforms and global "
+"constants."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:4
+msgid ""
+"Base class for a family of nodes with variable amount of input and output "
+"ports within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:7
+msgid "Currently, has no direct usage, use the derived classes instead."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:22
+msgid ""
+"Adds an input port with the specified [code]type[/code] (see [enum "
+"VisualShaderNode.PortType]) and [code]name[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:35
+msgid ""
+"Adds an output port with the specified [code]type[/code] (see [enum "
+"VisualShaderNode.PortType]) and [code]name[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:42
+msgid "Removes all previously specified input ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:49
+msgid "Removes all previously specified output ports."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:56
+msgid ""
+"Returns a free input port ID which can be used in [method add_input_port]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:63
+msgid ""
+"Returns a free output port ID which can be used in [method add_output_port]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:70
+msgid ""
+"Returns the number of input ports in use. Alternative for [method "
+"get_free_input_port_id]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:77
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:84
+msgid ""
+"Returns the number of output ports in use. Alternative for [method "
+"get_free_output_port_id]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:91
+msgid ""
+"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])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:100
+msgid "Returns [code]true[/code] if the specified input port exists."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:109
+msgid "Returns [code]true[/code] if the specified output port exists."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:118
+msgid ""
+"Returns [code]true[/code] if the specified port name does not override an "
+"existed port name and is valid within the shader."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:127
+msgid "Removes the specified input port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:136
+msgid "Removes the specified output port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:147
+msgid "Renames the specified input port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:158
+msgid ""
+"Sets the specified input port's type (see [enum VisualShaderNode.PortType])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:167
+msgid ""
+"Defines all input ports using a [String] formatted as a colon-separated "
+"list: [code]id,type,name;[/code] (see [method add_input_port])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:178
+msgid "Renames the specified output port."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:189
+msgid ""
+"Sets the specified output port's type (see [enum VisualShaderNode.PortType])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:198
+msgid ""
+"Defines all output ports using a [String] formatted as a colon-separated "
+"list: [code]id,type,name;[/code] (see [method add_output_port])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeGroupBase.xml:204
+msgid "The size of the node in the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIf.xml:4
+msgid ""
+"Compares two floating-point numbers in order to return a required vector "
+"within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIf.xml:7
+msgid ""
+"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 > b[/code] and [code]a < b[/code] "
+"respectively."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:4
+msgid "Represents the input shader parameter within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:15
+msgid ""
+"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]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:21
+msgid ""
+"One of the several input constants in lower-case style like: \"vertex\"([/"
+"code]VERTEX[code]) or \"point_size\"([code]POINT_SIZE[/code])."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeInput.xml:27
+msgid "Emitted when input is changed via [member input_name]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntConstant.xml:4
+msgid "A scalar integer constant to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntConstant.xml:7
+msgid "Translated to [code]int[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntConstant.xml:15
+msgid "An integer constant which represents a state of this node."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntFunc.xml:4
+msgid "A scalar integer function to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntFunc.xml:7
+msgid ""
+"Accept an integer scalar ([code]x[/code]) to the input port and transform it "
+"according to [member function]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntFunc.xml:23
+msgid ""
+"Constrains a parameter between [code]min[/code] and [code]max[/code]. "
+"Translates to [code]clamp(x, min, max)[/code] in the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:4
+msgid "An integer scalar operator to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:7
+msgid ""
+"Applies [member operator] to two integer inputs: [code]a[/code] and [code]b[/"
+"code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:32
+msgid "Calculates the remainder of two numbers using [code]a % b[/code]."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntOp.xml:38
+msgid ""
+"Returns the lesser of two numbers. Translates to [code]max(a, b)[/code] in "
+"the Godot Shader Language."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntUniform.xml:4
+msgid "A scalar integer uniform to be used within the visual shader graph."
+msgstr ""
+
+#: doc/classes/VisualShaderNodeIntUniform.xml:7
+msgid "Translated to [code]uniform int[/code] in the shader language."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:4
+msgid "Vertical scroll bar."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:7
+msgid ""
+"Vertical version of [ScrollBar], which goes from top (min) to bottom (max)."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:21
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] up. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/VScrollBar.xml:36
+msgid ""
+"Icon used as a button to scroll the [ScrollBar] down. Supports custom step "
+"using the [member ScrollBar.custom_step] property."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:4
+msgid "Vertical version of [Separator]."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:7
+msgid ""
+"Vertical version of [Separator]. Even though it looks vertical, it is used "
+"to separate objects horizontally."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:17
+msgid ""
+"The width of the area covered by the separator. Effectively works like a "
+"minimum width."
+msgstr ""
+
+#: doc/classes/VSeparator.xml:20
+msgid ""
+"The style for the separator line. Works best with [StyleBoxLine] (remember "
+"to enable [member StyleBoxLine.vertical])."
+msgstr ""
+
+#: doc/classes/VSlider.xml:4
+msgid "Vertical slider."
+msgstr ""
+
+#: doc/classes/VSlider.xml:7
+msgid ""
+"Vertical slider. See [Slider]. This one goes from bottom (min) to top (max)."
+msgstr ""
+
+#: doc/classes/VSlider.xml:24
+msgid "The background of the area below the grabber."
+msgstr ""
+
+#: doc/classes/VSlider.xml:33
+msgid ""
+"The background for the whole slider. Determines the width of the "
+"[code]grabber_area[/code]."
+msgstr ""
+
+#: doc/classes/VSplitContainer.xml:4
+msgid "Vertical split container."
+msgstr ""
+
+#: doc/classes/VSplitContainer.xml:7
+msgid ""
+"Vertical split container. See [SplitContainer]. This goes from top to bottom."
+msgstr ""
+
+#: doc/classes/WeakRef.xml:4
+msgid ""
+"Holds an [Object], but does not contribute to the reference count if the "
+"object is a reference."
+msgstr ""
+
+#: doc/classes/WeakRef.xml:7
+msgid ""
+"A weakref can hold a [Reference], without contributing to the reference "
+"counter. A weakref can be created from an [Object] using [method @GDScript."
+"weakref]. If this object is not a reference, weakref still works, however, "
+"it does not have any effect on the object. Weakrefs are useful in cases "
+"where multiple classes have variables that refer to each other. Without "
+"weakrefs, using these classes could lead to memory leaks, since both "
+"references keep each other from being released. Making part of the variables "
+"a weakref can prevent this cyclic dependency, and allows the references to "
+"be released."
+msgstr ""
+
+#: doc/classes/WeakRef.xml:16
+msgid "Returns the [Object] this weakref is referring to."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:14
+msgid "Closes this data channel, notifying the other peer."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:21
+msgid ""
+"Returns the id assigned to this channel during creation (or auto-assigned "
+"during negotiation).\n"
+"If the channel is not negotiated out-of-band the id will only be available "
+"after the connection is established (will return [code]65535[/code] until "
+"then)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:29
+msgid "Returns the label assigned to this channel during creation."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:36
+msgid ""
+"Returns the [code]maxPacketLifeTime[/code] value assigned to this channel "
+"during creation.\n"
+"Will be [code]65535[/code] if not specified."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:44
+msgid ""
+"Returns the [code]maxRetransmits[/code] value assigned to this channel "
+"during creation.\n"
+"Will be [code]65535[/code] if not specified."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:52
+msgid ""
+"Returns the sub-protocol assigned to this channel during creation. An empty "
+"string if not specified."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:59
+msgid "Returns the current state of this channel, see [enum ChannelState]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:66
+msgid ""
+"Returns [code]true[/code] if this channel was created with out-of-band "
+"configuration."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:73
+msgid ""
+"Returns [code]true[/code] if this channel was created with ordering enabled "
+"(default)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:80
+msgid "Reserved, but not used for now."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:87
+msgid ""
+"Returns [code]true[/code] if the last received packet was transferred as "
+"text. See [member write_mode]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:93
+msgid ""
+"The transfer mode to use when sending outgoing packet. Either text or binary."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:98
+msgid ""
+"Tells the channel to send data over this channel as text. An external peer "
+"(non-Godot) would receive this as a string."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:101
+msgid ""
+"Tells the channel to send data over this channel as binary. An external peer "
+"(non-Godot) would receive this as array buffer or blob."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:104
+msgid "The channel was created, but it's still trying to connect."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:107
+msgid "The channel is currently open, and data can flow over it."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:110
+msgid ""
+"The channel is being closed, no new messages will be accepted, but those "
+"already in queue will be flushed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCDataChannel.xml:113
+msgid "The channel was closed, or connection failed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:4
+msgid ""
+"A simple interface to create a peer-to-peer mesh network composed of "
+"[WebRTCPeerConnection] that is compatible with the [MultiplayerAPI]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:7
+msgid ""
+"This class constructs a full mesh of [WebRTCPeerConnection] (one connection "
+"for each peer) that can be used as a [member MultiplayerAPI.network_peer].\n"
+"You can add each [WebRTCPeerConnection] via [method add_peer] or remove them "
+"via [method remove_peer]. Peers must be added in [constant "
+"WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate "
+"channels. This class will not create offers nor set descriptions, it will "
+"only poll them, and notify connections and disconnections.\n"
+"[signal NetworkedMultiplayerPeer.connection_succeeded] and [signal "
+"NetworkedMultiplayerPeer.server_disconnected] will not be emitted unless "
+"[code]server_compatibility[/code] is [code]true[/code] in [method "
+"initialize]. Beside that data transfer works like in a "
+"[NetworkedMultiplayerPeer]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:24
+msgid ""
+"Add a new peer to the mesh with the given [code]peer_id[/code]. The "
+"[WebRTCPeerConnection] must be in state [constant WebRTCPeerConnection."
+"STATE_NEW].\n"
+"Three channels will be created for reliable, unreliable, and ordered "
+"transport. The value of [code]unreliable_lifetime[/code] will be passed to "
+"the [code]maxPacketLifetime[/code] option when creating unreliable and "
+"ordered channels (see [method WebRTCPeerConnection.create_data_channel])."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:32
+msgid "Close all the add peer connections and channels, freeing all resources."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:41
+msgid ""
+"Return a dictionary representation of the peer with given [code]peer_id[/"
+"code] with three keys. [code]connection[/code] containing the "
+"[WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three "
+"[WebRTCDataChannel], and [code]connected[/code] a boolean representing if "
+"the peer connection is currently connected (all three channels are open)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:48
+msgid ""
+"Returns a dictionary which keys are the peer ids and values the peer "
+"representation as in [method get_peer]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:57
+msgid ""
+"Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers "
+"map (it might not be connected though)."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:68
+msgid ""
+"Initialize the multiplayer peer with the given [code]peer_id[/code] (must be "
+"between 1 and 2147483647).\n"
+"If [code]server_compatibilty[/code] is [code]false[/code] (default), the "
+"multiplayer peer will be immediately in state [constant "
+"NetworkedMultiplayerPeer.CONNECTION_CONNECTED] and [signal "
+"NetworkedMultiplayerPeer.connection_succeeded] will not be emitted.\n"
+"If [code]server_compatibilty[/code] is [code]true[/code] the peer will "
+"suppress all [signal NetworkedMultiplayerPeer.peer_connected] signals until "
+"a peer with id [constant NetworkedMultiplayerPeer.TARGET_PEER_SERVER] "
+"connects and then emit [signal NetworkedMultiplayerPeer."
+"connection_succeeded]. After that the signal [signal "
+"NetworkedMultiplayerPeer.peer_connected] will be emitted for every already "
+"connected peer, and any new peer that might connect. If the server peer "
+"disconnects after that, signal [signal NetworkedMultiplayerPeer."
+"server_disconnected] will be emitted and state will become [constant "
+"NetworkedMultiplayerPeer.CONNECTION_CONNECTED]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCMultiplayer.xml:79
+msgid ""
+"Remove the peer with given [code]peer_id[/code] from the mesh. If the peer "
+"was connected, and [signal NetworkedMultiplayerPeer.peer_connected] was "
+"emitted for it, then [signal NetworkedMultiplayerPeer.peer_disconnected] "
+"will be emitted."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:4
+msgid "Interface to a WebRTC peer connection."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:7
+msgid ""
+"A WebRTC connection between the local computer and a remote peer. Provides "
+"an interface to connect, maintain and monitor the connection.\n"
+"Setting up a WebRTC connection between two peers from now on) may not seem a "
+"trivial task, but it can be broken down into 3 main steps:\n"
+"- The peer that wants to initiate the connection ([code]A[/code] from now "
+"on) creates an offer and send it to the other peer ([code]B[/code] from now "
+"on).\n"
+"- [code]B[/code] receives the offer, generate and answer, and sends it to "
+"[code]A[/code]).\n"
+"- [code]A[/code] and [code]B[/code] then generates and exchange ICE "
+"candidates with each other.\n"
+"After these steps, the connection should become connected. Keep on reading "
+"or look into the tutorial for more information."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:27
+msgid ""
+"Add an ice candidate generated by a remote peer (and received over the "
+"signaling server). See [signal ice_candidate_created]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:34
+msgid ""
+"Close the peer connection and all data channels associated with it. Note, "
+"you cannot reuse this object for a new connection unless you call [method "
+"initialize]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:47
+msgid ""
+"Returns a new [WebRTCDataChannel] (or [code]null[/code] on failure) with "
+"given [code]label[/code] and optionally configured via the [code]options[/"
+"code] dictionary. This method can only be called when the connection is in "
+"state [constant STATE_NEW].\n"
+"There are two ways to create a working data channel: either call [method "
+"create_data_channel] on only one of the peer and listen to [signal "
+"data_channel_received] on the other, or call [method create_data_channel] on "
+"both peers, with the same values, and the [code]negotiated[/code] option set "
+"to [code]true[/code].\n"
+"Valid [code]options[/code] are:\n"
+"[codeblock]\n"
+"{\n"
+" \"negotiated\": true, # When set to true (default off), means the "
+"channel is negotiated out of band. \"id\" must be set too. "
+"data_channel_received will not be called.\n"
+" \"id\": 1, # When \"negotiated\" is true this value must also be set to "
+"the same value on both peer.\n"
+"\n"
+" # Only one of maxRetransmits and maxPacketLifeTime can be specified, not "
+"both. They make the channel unreliable (but also better at real time).\n"
+" \"maxRetransmits\": 1, # Specify the maximum number of attempt the peer "
+"will make to retransmits packets if they are not acknowledged.\n"
+" \"maxPacketLifeTime\": 100, # Specify the maximum amount of time before "
+"giving up retransmitions of unacknowledged packets (in milliseconds).\n"
+" \"ordered\": true, # When in unreliable mode (i.e. either "
+"\"maxRetransmits\" or \"maxPacketLifetime\" is set), \"ordered\" (true by "
+"default) specify if packet ordering is to be enforced.\n"
+"\n"
+" \"protocol\": \"my-custom-protocol\", # A custom sub-protocol string for "
+"this channel.\n"
+"}\n"
+"[/codeblock]\n"
+"[b]Note:[/b] You must keep a reference to channels created this way, or it "
+"will be closed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:70
+msgid ""
+"Creates a new SDP offer to start a WebRTC connection with a remote peer. At "
+"least one [WebRTCDataChannel] must have been created before calling this "
+"method.\n"
+"If this functions returns [constant OK], [signal "
+"session_description_created] will be called when the session is ready to be "
+"sent."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:78
+msgid "Returns the connection state. See [enum ConnectionState]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:89
+msgid ""
+"Re-initialize this peer connection, closing any previously active "
+"connection, and going back to state [constant STATE_NEW]. A dictionary of "
+"[code]options[/code] can be passed to configure the peer connection.\n"
+"Valid [code]options[/code] are:\n"
+"[codeblock]\n"
+"{\n"
+" \"iceServers\": [\n"
+" {\n"
+" \"urls\": [ \"stun:stun.example.com:3478\" ], # One or more STUN "
+"servers.\n"
+" },\n"
+" {\n"
+" \"urls\": [ \"turn:turn.example.com:3478\" ], # One or more TURN "
+"servers.\n"
+" \"username\": \"a_username\", # Optional username for the TURN "
+"server.\n"
+" \"credentials\": \"a_password\", # Optional password for the "
+"TURN server.\n"
+" }\n"
+" ]\n"
+"}\n"
+"[/codeblock]"
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:111
+msgid ""
+"Call this method frequently (e.g. in [method Node._process] or [method Node."
+"_physics_process]) to properly receive signals."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:122
+msgid ""
+"Sets the SDP description of the local peer. This should be called in "
+"response to [signal session_description_created].\n"
+"If [code]type[/code] is [code]answer[/code] the peer will start emitting "
+"[signal ice_candidate_created]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:134
+msgid ""
+"Sets the SDP description of the remote peer. This should be called with the "
+"values generated by a remote peer and received over the signaling server.\n"
+"If [code]type[/code] is [code]offer[/code] the peer will emit [signal "
+"session_description_created] with the appropriate answer.\n"
+"If [code]type[/code] is [code]answer[/code] the peer will start emitting "
+"[signal ice_candidate_created]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:145
+msgid ""
+"Emitted when a new in-band channel is received, i.e. when the channel was "
+"created with [code]negotiated: false[/code] (default).\n"
+"The object will be an instance of [WebRTCDataChannel]. You must keep a "
+"reference of it or it will be closed automatically. See [method "
+"create_data_channel]."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:157
+msgid ""
+"Emitted when a new ICE candidate has been created. The three parameters are "
+"meant to be passed to the remote peer over the signaling server."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:166
+msgid ""
+"Emitted after a successful call to [method create_offer] or [method "
+"set_remote_description] (when it generates an answer). The parameters are "
+"meant to be passed to [method set_local_description] on this object, and "
+"sent to the remote peer over the signaling server."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:172
+msgid ""
+"The connection is new, data channels and an offer can be created in this "
+"state."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:175
+msgid ""
+"The peer is connecting, ICE is in progress, none of the transports has "
+"failed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:178
+msgid "The peer is connected, all ICE transports are connected."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:181
+msgid "At least one ICE transport is disconnected."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:184
+msgid "One or more of the ICE transports failed."
+msgstr ""
+
+#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml:187
+msgid ""
+"The peer connection is closed (after calling [method close] for example)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:4
+msgid "A WebSocket client implementation."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:7
+msgid ""
+"This class implements a WebSocket client compatible with any RFC 6455-"
+"compliant WebSocket server.\n"
+"This client can be optionally used as a network peer for the "
+"[MultiplayerAPI].\n"
+"After starting the client ([method connect_to_url]), you will need to "
+"[method NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside "
+"[method Node._process]).\n"
+"You will receive appropriate signals when connecting, disconnecting, or when "
+"new data is available."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:27
+msgid ""
+"Connects to the given URL requesting one of the given [code]protocols[/code] "
+"as sub-protocol. If the list empty (default), no sub-protocol will be "
+"requested.\n"
+"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.\n"
+"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]).\n"
+"You can optionally pass a list of [code]custom_headers[/code] to be added to "
+"the handshake HTTP request.\n"
+"[b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in "
+"HTML5 exports due to browsers restrictions."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:42
+msgid ""
+"Disconnects this client from the connected host. See [method WebSocketPeer."
+"close] for more information."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:49
+msgid "Return the IP address of the currently connected host."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:56
+msgid "Return the IP port of the currently connected host."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:62
+msgid ""
+"If specified, this [X509Certificate] will be the only one accepted when "
+"connecting to an SSL host. Any other certificate provided by the server will "
+"be regarded as invalid.\n"
+"[b]Note:[/b] Specifying a custom [code]trusted_ssl_certificate[/code] is not "
+"supported in HTML5 exports due to browsers restrictions."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:66
+msgid ""
+"If [code]true[/code], SSL certificate verification is enabled.\n"
+"[b]Note:[/b] You must specify the certificates to be used in the Project "
+"Settings for it to work when exported."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:75
+msgid ""
+"Emitted when the connection to the server is closed. [code]was_clean_close[/"
+"code] will be [code]true[/code] if the connection was shutdown cleanly."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:80
+msgid "Emitted when the connection to the server fails."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:87
+msgid ""
+"Emitted when a connection with the server is established, [code]protocol[/"
+"code] will contain the sub-protocol agreed with the server."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:92
+msgid ""
+"Emitted when a WebSocket message is received.\n"
+"[b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level "
+"multiplayer peer."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketClient.xml:102
+msgid ""
+"Emitted when the server requests a clean close. You should keep polling "
+"until you get a [signal connection_closed] signal to achieve the clean "
+"close. See [method WebSocketPeer.close] for more details."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:4
+msgid "Base class for WebSocket server and client."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:7
+msgid ""
+"Base class for WebSocket server and client, allowing them to be used as "
+"network peer for the [MultiplayerAPI]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:18
+msgid ""
+"Returns the [WebSocketPeer] associated to the given [code]peer_id[/code]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:33
+msgid ""
+"Configures the buffer sizes for this WebSocket peer. Default values can be "
+"specified in the Project Settings under [code]network/limits[/code]. For "
+"server, values are meant per connected peer.\n"
+"The first two parameters define the size and queued packets limits of the "
+"input buffer, the last two of the output buffer.\n"
+"Buffer sizes are expressed in KiB, so [code]4 = 2^12 = 4096 bytes[/code]. "
+"All parameters will be rounded up to the nearest power of two.\n"
+"[b]Note:[/b] HTML5 exports only use the input buffer since the output one is "
+"managed by browsers."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml:49
+msgid ""
+"Emitted when a packet is received from a peer.\n"
+"[b]Note:[/b] This signal is only emitted when the client or server is "
+"configured to use Godot multiplayer API."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:4
+msgid "A class representing a specific WebSocket connection."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:7
+msgid ""
+"This class represent a specific WebSocket connection, you can do lower level "
+"operations with it.\n"
+"You can choose to write to the socket in binary or text mode, and you can "
+"recognize the mode used for writing by the other peer."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:21
+msgid ""
+"Closes this WebSocket connection. [code]code[/code] is the status code for "
+"the closure (see RFC 6455 section 7.4 for a list of valid status codes). "
+"[code]reason[/code] is the human readable reason for closing the connection "
+"(can be any UTF-8 string that's smaller than 123 bytes).\n"
+"[b]Note:[/b] To achieve a clean close, you will need to keep polling until "
+"either [signal WebSocketClient.connection_closed] or [signal WebSocketServer."
+"client_disconnected] is received.\n"
+"[b]Note:[/b] The HTML5 export might not support all status codes. Please "
+"refer to browser-specific documentation for more details."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:30
+msgid ""
+"Returns the IP address of the connected peer.\n"
+"[b]Note:[/b] Not available in the HTML5 export."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:38
+msgid ""
+"Returns the remote port of the connected peer.\n"
+"[b]Note:[/b] Not available in the HTML5 export."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:46
+msgid "Gets the current selected write mode. See [enum WriteMode]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:53
+msgid "Returns [code]true[/code] if this peer is currently connected."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:62
+msgid ""
+"Disable Nagle's algorithm on the underling TCP socket (default). See [method "
+"StreamPeerTCP.set_no_delay] for more information.\n"
+"[b]Note:[/b] Not available in the HTML5 export."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:72
+msgid "Sets the socket to use the given [enum WriteMode]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:79
+msgid ""
+"Returns [code]true[/code] if the last received packet was sent as a text "
+"payload. See [enum WriteMode]."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:85
+msgid ""
+"Specifies that WebSockets messages should be transferred as text payload "
+"(only valid UTF-8 is allowed)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketPeer.xml:88
+msgid ""
+"Specifies that WebSockets messages should be transferred as binary payload "
+"(any byte combination is allowed)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:4
+msgid "A WebSocket server implementation."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:7
+msgid ""
+"This class implements a WebSocket server that can also support the high-"
+"level multiplayer API.\n"
+"After starting the server ([method listen]), you will need to [method "
+"NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside [method "
+"Node._process]). When clients connect, disconnect, or send data, you will "
+"receive the appropriate signal.\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:24
+msgid ""
+"Disconnects the peer identified by [code]id[/code] from the server. See "
+"[method WebSocketPeer.close] for more information."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:51
+msgid "Returns [code]true[/code] if a peer with the given ID is connected."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:58
+msgid ""
+"Returns [code]true[/code] if the server is actively listening on a port."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:71
+msgid ""
+"Starts listening on the given port.\n"
+"You can specify the desired subprotocols via the \"protocols\" array. If the "
+"list empty (default), no sub-protocol will be requested.\n"
+"If [code]true[/code] is passed as [code]gd_mp_api[/code], the server will "
+"behave like a network peer for the [MultiplayerAPI], connections from non-"
+"Godot clients will not work, and [signal data_received] will not be "
+"emitted.\n"
+"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(id)[/code] to "
+"communicate with the peer with given [code]id[/code] (e.g. "
+"[code]get_peer(id).get_available_packet_count[/code])."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:81
+msgid "Stops the server and clear its state."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:87
+msgid ""
+"When not set to [code]*[/code] will restrict incoming connections to the "
+"specified IP address. Setting [code]bind_ip[/code] to [code]127.0.0.1[/code] "
+"will cause the server to listen only to the local host."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:90
+msgid ""
+"When using SSL (see [member private_key] and [member ssl_certificate]), you "
+"can set this to a valid [X509Certificate] to be provided as additional CA "
+"chain information during the SSL handshake."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:93
+msgid ""
+"When set to a valid [CryptoKey] (along with [member ssl_certificate]) will "
+"cause the server to require SSL instead of regular TCP (i.e. the [code]wss://"
+"[/code] protocol)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:96
+msgid ""
+"When set to a valid [X509Certificate] (along with [member private_key]) will "
+"cause the server to require SSL instead of regular TCP (i.e. the [code]wss://"
+"[/code] protocol)."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:108
+msgid ""
+"Emitted when a client requests a clean close. You should keep polling until "
+"you get a [signal client_disconnected] signal with the same [code]id[/code] "
+"to achieve the clean close. See [method WebSocketPeer.close] for more "
+"details."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:117
+msgid ""
+"Emitted when a new client connects. \"protocol\" will be the sub-protocol "
+"agreed with the client."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:126
+msgid ""
+"Emitted when a client disconnects. [code]was_clean_close[/code] will be "
+"[code]true[/code] if the connection was shutdown cleanly."
+msgstr ""
+
+#: modules/websocket/doc_classes/WebSocketServer.xml:133
+msgid ""
+"Emitted when a new message is received.\n"
+"[b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level "
+"multiplayer peer."
+msgstr ""
+
+#: doc/classes/World2D.xml:4
+msgid "Class that has everything pertaining to a 2D world."
+msgstr ""
+
+#: doc/classes/World2D.xml:7
+msgid ""
+"Class that has everything pertaining to a 2D world. A physics space, a "
+"visual scenario and a sound space. 2D nodes register their resources into "
+"the current 2D world."
+msgstr ""
+
+#: doc/classes/World2D.xml:16
+msgid ""
+"The [RID] of this world's canvas resource. Used by the [RenderingServer] for "
+"2D drawing."
+msgstr ""
+
+#: doc/classes/World2D.xml:19
+msgid ""
+"The state of this world's physics space. This allows arbitrary querying for "
+"collision."
+msgstr ""
+
+#: doc/classes/World2D.xml:22
+msgid ""
+"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."
+msgstr ""
+
+#: doc/classes/World3D.xml:4
+msgid "Class that has everything pertaining to a world."
+msgstr ""
+
+#: doc/classes/World3D.xml:7
+msgid ""
+"Class that has everything pertaining to a world. A physics space, a visual "
+"scenario and a sound space. Node3D nodes register their resources into the "
+"current world."
+msgstr ""
+
+#: doc/classes/World3D.xml:18
+msgid ""
+"The World3D's physics direct space state, used for making various queries. "
+"Might be used only during [code]_physics_process[/code]."
+msgstr ""
+
+#: doc/classes/World3D.xml:21
+msgid "The World3D's [Environment]."
+msgstr ""
+
+#: doc/classes/World3D.xml:24
+msgid ""
+"The World3D's fallback_environment will be used if the World3D's "
+"[Environment] fails or is missing."
+msgstr ""
+
+#: doc/classes/World3D.xml:27
+msgid "The World3D's visual scenario."
+msgstr ""
+
+#: doc/classes/World3D.xml:30
+msgid "The World3D's physics space."
+msgstr ""
+
+#: doc/classes/WorldEnvironment.xml:4
+msgid ""
+"Default environment properties for the entire scene (post-processing "
+"effects, lighting and background settings)."
+msgstr ""
+
+#: doc/classes/WorldEnvironment.xml:7
+msgid ""
+"The [WorldEnvironment] node is used to configure the default [Environment] "
+"for the scene.\n"
+"The parameters defined in the [WorldEnvironment] can be overridden by an "
+"[Environment] node set on the current [Camera3D]. Additionally, only one "
+"[WorldEnvironment] may be instanced in a given scene at a time.\n"
+"The [WorldEnvironment] allows the user to specify default lighting "
+"parameters (e.g. ambient lighting), various post-processing effects (e.g. "
+"SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, "
+"skybox). Usually, these are added in order to improve the realism/color "
+"balance of the scene."
+msgstr ""
+
+#: doc/classes/WorldEnvironment.xml:20
+msgid ""
+"The [Environment] resource used by this [WorldEnvironment], defining the "
+"default properties."
+msgstr ""
+
+#: doc/classes/WorldMarginShape3D.xml:4
+msgid "Infinite plane shape for 3D collisions."
+msgstr ""
+
+#: doc/classes/WorldMarginShape3D.xml:7
+msgid ""
+"An infinite plane shape for 3D collisions. Note that the [Plane]'s normal "
+"matters; anything \"below\" the plane will collide with it. If the "
+"[WorldMarginShape3D] is used in a [PhysicsBody3D], it will cause colliding "
+"objects placed \"below\" it to teleport \"above\" the plane."
+msgstr ""
+
+#: doc/classes/WorldMarginShape3D.xml:15
+msgid "The [Plane] used by the [WorldMarginShape3D] for collision."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:4
+msgid "An X509 certificate (e.g. for SSL)."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:7
+msgid ""
+"The X509Certificate class represents an X509 certificate. Certificates can "
+"be loaded and saved like any other [Resource].\n"
+"They can be used as the server certificate in [method StreamPeerSSL."
+"accept_stream] (along with the proper [CryptoKey]), and to specify the only "
+"certificate that should be accepted when connecting to an SSL server via "
+"[method StreamPeerSSL.connect_to_stream].\n"
+"[b]Note:[/b] Not available in HTML5 exports."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:20
+msgid "Loads a certificate from [code]path[/code] (\"*.crt\" file)."
+msgstr ""
+
+#: doc/classes/X509Certificate.xml:29
+msgid ""
+"Saves a certificate to the given [code]path[/code] (should be a \"*.crt\" "
+"file)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:4
+msgid ""
+"Low-level class for creating parsers for [url=https://en.wikipedia.org/wiki/"
+"XML]XML[/url] files."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:7
+msgid ""
+"This class can serve as base to make custom XML parsers. Since XML is a very "
+"flexible standard, this interface is low-level so it can be applied to any "
+"possible schema."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:16
+msgid "Gets the amount of attributes in the current element."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:25
+msgid ""
+"Gets the name of the attribute specified by the index in [code]idx[/code] "
+"argument."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:34
+msgid ""
+"Gets the value of the attribute specified by the index in [code]idx[/code] "
+"argument."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:41
+msgid "Gets the current line in the parsed file (currently not implemented)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:50
+msgid ""
+"Gets the value of a certain attribute of the current element by name. This "
+"will raise an error if the element has no such attribute."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:59
+msgid ""
+"Gets the value of a certain attribute of the current element by name. This "
+"will return an empty [String] if the attribute is not found."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:66
+msgid ""
+"Gets the contents of a text node. This will raise an error in any other type "
+"of node."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:73
+msgid ""
+"Gets the name of the current element node. This will raise an error if the "
+"current node type is neither [constant NODE_ELEMENT] nor [constant "
+"NODE_ELEMENT_END]."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:80
+msgid ""
+"Gets the byte offset of the current node since the beginning of the file or "
+"buffer."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:87
+msgid ""
+"Gets the type of the current node. Compare with [enum NodeType] constants."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:96
+msgid "Check whether the current element has a certain attribute."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:103
+msgid ""
+"Check whether the current element is empty (this only works for completely "
+"empty tags, e.g. [code]<element \\>[/code])."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:112
+msgid "Opens an XML file for parsing. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:121
+msgid "Opens an XML raw buffer for parsing. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:128
+msgid "Reads the next node of the file. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:137
+msgid ""
+"Moves the buffer cursor to a certain offset (since the beginning) and read "
+"the next node there. This returns an error code."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:144
+msgid ""
+"Skips the current section. If the node contains other elements, they will be "
+"ignored and the cursor will go to the closing of the current element."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:150
+msgid "There's no node (no file or buffer opened)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:153
+msgid "Element (tag)."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:156
+msgid "End of element."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:159
+msgid "Text node."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:162
+msgid "Comment node."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:165
+msgid "CDATA content."
+msgstr ""
+
+#: doc/classes/XMLParser.xml:168
+msgid "Unknown node."
+msgstr ""
+
+#: doc/classes/YSort.xml:4
+msgid "Sort all child nodes based on their Y positions."
+msgstr ""
+
+#: doc/classes/YSort.xml:7
+msgid ""
+"Sort all child nodes based on their Y positions. The child node must inherit "
+"from [CanvasItem] for it to be sorted. Nodes that have a higher Y position "
+"will be drawn later, so they will appear on top of nodes that have a lower Y "
+"position.\n"
+"Nesting of YSort nodes is possible. Children YSort nodes will be sorted in "
+"the same space as the parent YSort, allowing to better organize a scene or "
+"divide it in multiple ones, yet keep the unique sorting."
+msgstr ""
+
+#: doc/classes/YSort.xml:16
+msgid ""
+"If [code]true[/code], child nodes are sorted, otherwise sorting is disabled."
+msgstr ""
diff --git a/drivers/SCsub b/drivers/SCsub
index 41c20d81ad..cc7bcbc640 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -1,41 +1,42 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.drivers_sources = []
# OS drivers
-SConscript('unix/SCsub')
-SConscript('windows/SCsub')
+SConscript("unix/SCsub")
+SConscript("windows/SCsub")
# Sounds drivers
-SConscript('alsa/SCsub')
-SConscript('coreaudio/SCsub')
-SConscript('pulseaudio/SCsub')
-if (env["platform"] == "windows"):
+SConscript("alsa/SCsub")
+SConscript("coreaudio/SCsub")
+SConscript("pulseaudio/SCsub")
+if env["platform"] == "windows":
SConscript("wasapi/SCsub")
-if env['xaudio2']:
+if env["xaudio2"]:
SConscript("xaudio2/SCsub")
# Midi drivers
-SConscript('alsamidi/SCsub')
-SConscript('coremidi/SCsub')
-SConscript('winmidi/SCsub')
+SConscript("alsamidi/SCsub")
+SConscript("coremidi/SCsub")
+SConscript("winmidi/SCsub")
# Graphics drivers
-if (env["platform"] != "server" and env["platform"] != "javascript"):
-# SConscript('gles2/SCsub')
- SConscript('vulkan/SCsub')
- SConscript('gl_context/SCsub')
+if env["platform"] != "server" and env["platform"] != "javascript":
+ # SConscript('gles2/SCsub')
+ SConscript("vulkan/SCsub")
+ SConscript("gl_context/SCsub")
else:
- SConscript('dummy/SCsub')
+ SConscript("dummy/SCsub")
# Core dependencies
SConscript("png/SCsub")
SConscript("spirv-reflect/SCsub")
-if env['vsproj']:
+if env["vsproj"]:
import os
+
path = os.getcwd()
# Change directory so the path resolves correctly in the function call.
os.chdir("..")
diff --git a/drivers/alsa/SCsub b/drivers/alsa/SCsub
index 28b315ae66..91e1140b75 100644
--- a/drivers/alsa/SCsub
+++ b/drivers/alsa/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 400ce31bf7..48e694dd3a 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -60,7 +60,7 @@ Error AudioDriverALSA::init_device() {
fprintf(stderr, "ALSA ERR: %s\n", snd_strerror(status)); \
if (pcm_handle) { \
snd_pcm_close(pcm_handle); \
- pcm_handle = NULL; \
+ pcm_handle = nullptr; \
} \
ERR_FAIL_COND_V(m_cond, ERR_CANT_OPEN); \
}
@@ -98,7 +98,7 @@ Error AudioDriverALSA::init_device() {
status = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2);
CHECK_FAIL(status < 0);
- status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL);
+ status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, nullptr);
CHECK_FAIL(status < 0);
// In ALSA the period size seems to be the one that will determine the actual latency
@@ -113,12 +113,12 @@ Error AudioDriverALSA::init_device() {
status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size);
CHECK_FAIL(status < 0);
- status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL);
+ status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, nullptr);
CHECK_FAIL(status < 0);
print_verbose("Audio buffer frames: " + itos(period_size) + " calculated latency: " + itos(period_size * 1000 / mix_rate) + "ms");
- status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL);
+ status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, nullptr);
CHECK_FAIL(status < 0);
status = snd_pcm_hw_params(pcm_handle, hwparams);
@@ -262,11 +262,11 @@ Array AudioDriverALSA::get_device_list() {
if (snd_device_name_hint(-1, "pcm", &hints) < 0)
return list;
- for (void **n = hints; *n != NULL; n++) {
+ for (void **n = hints; *n != nullptr; n++) {
char *name = snd_device_name_get_hint(*n, "NAME");
char *desc = snd_device_name_get_hint(*n, "DESC");
- if (name != NULL && !strncmp(name, "plughw", 6)) {
+ if (name != nullptr && !strncmp(name, "plughw", 6)) {
if (desc) {
list.push_back(String(name) + ";" + String(desc));
} else {
@@ -274,9 +274,9 @@ Array AudioDriverALSA::get_device_list() {
}
}
- if (desc != NULL)
+ if (desc != nullptr)
free(desc);
- if (name != NULL)
+ if (name != nullptr)
free(name);
}
snd_device_name_free_hint(hints);
@@ -314,7 +314,7 @@ void AudioDriverALSA::finish_device() {
if (pcm_handle) {
snd_pcm_close(pcm_handle);
- pcm_handle = NULL;
+ pcm_handle = nullptr;
}
}
@@ -325,15 +325,15 @@ void AudioDriverALSA::finish() {
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
finish_device();
}
AudioDriverALSA::AudioDriverALSA() :
- thread(NULL),
- pcm_handle(NULL),
+ thread(nullptr),
+ pcm_handle(nullptr),
device_name("Default"),
new_device("Default") {
}
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index a8caf0fbae..50bd9e853d 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -28,12 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "servers/audio_server.h"
-
#ifdef ALSA_ENABLED
+#ifndef AUDIO_DRIVER_ALSA_H
+#define AUDIO_DRIVER_ALSA_H
+
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "servers/audio_server.h"
#include <alsa/asoundlib.h>
@@ -87,4 +89,6 @@ public:
~AudioDriverALSA();
};
-#endif
+#endif // AUDIO_DRIVER_ALSA_H
+
+#endif // ALSA_ENABLED
diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub
index 4c24925192..4e1b5f2a36 100644
--- a/drivers/alsamidi/SCsub
+++ b/drivers/alsamidi/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
# Driver source files
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index 0cecf1de3e..e3e54ea267 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -132,18 +132,18 @@ Error MIDIDriverALSAMidi::open() {
return ERR_CANT_OPEN;
int i = 0;
- for (void **n = hints; *n != NULL; n++) {
+ for (void **n = hints; *n != nullptr; n++) {
char *name = snd_device_name_get_hint(*n, "NAME");
- if (name != NULL) {
+ if (name != nullptr) {
snd_rawmidi_t *midi_in;
- int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK);
+ int ret = snd_rawmidi_open(&midi_in, nullptr, name, SND_RAWMIDI_NONBLOCK);
if (ret >= 0) {
connected_inputs.insert(i++, midi_in);
}
}
- if (name != NULL)
+ if (name != nullptr)
free(name);
}
snd_device_name_free_hint(hints);
@@ -161,7 +161,7 @@ void MIDIDriverALSAMidi::close() {
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
for (int i = 0; i < connected_inputs.size(); i++) {
@@ -202,7 +202,7 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() {
MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
- thread = NULL;
+ thread = nullptr;
exit_thread = false;
}
diff --git a/drivers/coreaudio/SCsub b/drivers/coreaudio/SCsub
index 4c24925192..4e1b5f2a36 100644
--- a/drivers/coreaudio/SCsub
+++ b/drivers/coreaudio/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
# Driver source files
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 1e95bcf5d9..21c3649445 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -79,8 +79,8 @@ Error AudioDriverCoreAudio::init() {
#endif
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- AudioComponent comp = AudioComponentFindNext(NULL, &desc);
- ERR_FAIL_COND_V(comp == NULL, FAILED);
+ AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
+ ERR_FAIL_COND_V(comp == nullptr, FAILED);
OSStatus result = AudioComponentInstanceNew(comp, &audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -335,7 +335,7 @@ void AudioDriverCoreAudio::finish() {
ERR_PRINT("AudioComponentInstanceDispose failed");
}
- audio_unit = NULL;
+ audio_unit = nullptr;
unlock();
}
}
@@ -351,8 +351,8 @@ Error AudioDriverCoreAudio::capture_init() {
#endif
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- AudioComponent comp = AudioComponentFindNext(NULL, &desc);
- ERR_FAIL_COND_V(comp == NULL, FAILED);
+ AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
+ ERR_FAIL_COND_V(comp == nullptr, FAILED);
OSStatus result = AudioComponentInstanceNew(comp, &input_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -380,7 +380,7 @@ Error AudioDriverCoreAudio::capture_init() {
size = sizeof(AudioDeviceID);
AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId);
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &deviceId);
ERR_FAIL_COND_V(result != noErr, FAILED);
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
@@ -469,7 +469,7 @@ void AudioDriverCoreAudio::capture_finish() {
ERR_PRINT("AudioComponentInstanceDispose failed");
}
- input_unit = NULL;
+ input_unit = nullptr;
unlock();
}
}
@@ -513,18 +513,18 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
prop.mElement = kAudioObjectPropertyElementMaster;
UInt32 size = 0;
- AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, NULL, &size);
+ AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size);
- AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL, &size, audioDevices);
+ AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
UInt32 deviceCount = size / sizeof(AudioDeviceID);
for (UInt32 i = 0; i < deviceCount; i++) {
prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
- AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size);
+ AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
- AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList);
+ AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
@@ -538,7 +538,7 @@ Array AudioDriverCoreAudio::_get_device_list(bool capture) {
size = sizeof(CFStringRef);
prop.mSelector = kAudioObjectPropertyName;
- AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, &cfname);
+ AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, &cfname);
CFIndex length = CFStringGetLength(cfname);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
@@ -569,18 +569,18 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
prop.mElement = kAudioObjectPropertyElementMaster;
UInt32 size = 0;
- AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, NULL, &size);
+ AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &prop, 0, nullptr, &size);
AudioDeviceID *audioDevices = (AudioDeviceID *)malloc(size);
- AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL, &size, audioDevices);
+ AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, nullptr, &size, audioDevices);
UInt32 deviceCount = size / sizeof(AudioDeviceID);
for (UInt32 i = 0; i < deviceCount && !found; i++) {
prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
- AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size);
+ AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, nullptr, &size);
AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
- AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList);
+ AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, bufferList);
UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
@@ -594,7 +594,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
size = sizeof(CFStringRef);
prop.mSelector = kAudioObjectPropertyName;
- AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, &cfname);
+ AudioObjectGetPropertyData(audioDevices[i], &prop, 0, nullptr, &size, &cfname);
CFIndex length = CFStringGetLength(cfname);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
@@ -620,7 +620,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
UInt32 elem = capture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice;
AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId);
+ OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &deviceId);
ERR_FAIL_COND(result != noErr);
found = true;
@@ -677,8 +677,8 @@ String AudioDriverCoreAudio::capture_get_device() {
#endif
AudioDriverCoreAudio::AudioDriverCoreAudio() :
- audio_unit(NULL),
- input_unit(NULL),
+ audio_unit(nullptr),
+ input_unit(nullptr),
active(false),
device_name("Default"),
capture_device_name("Default"),
diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub
index 4c24925192..4e1b5f2a36 100644
--- a/drivers/coremidi/SCsub
+++ b/drivers/coremidi/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
# Driver source files
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/coremidi/midi_driver_coremidi.cpp b/drivers/coremidi/midi_driver_coremidi.cpp
index d807896e61..2cd322813b 100644
--- a/drivers/coremidi/midi_driver_coremidi.cpp
+++ b/drivers/coremidi/midi_driver_coremidi.cpp
@@ -47,8 +47,8 @@ void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc
Error MIDIDriverCoreMidi::open() {
- CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII);
- OSStatus result = MIDIClientCreate(name, NULL, NULL, &client);
+ CFStringRef name = CFStringCreateWithCString(nullptr, "Godot", kCFStringEncodingASCII);
+ OSStatus result = MIDIClientCreate(name, nullptr, nullptr, &client);
CFRelease(name);
if (result != noErr) {
ERR_PRINT("MIDIClientCreate failed, code: " + itos(result));
@@ -99,7 +99,7 @@ PackedStringArray MIDIDriverCoreMidi::get_connected_inputs() {
for (int i = 0; i < connected_sources.size(); i++) {
MIDIEndpointRef source = connected_sources[i];
- CFStringRef ref = NULL;
+ CFStringRef ref = nullptr;
char name[256];
MIDIObjectGetStringProperty(source, kMIDIPropertyDisplayName, &ref);
diff --git a/drivers/dummy/SCsub b/drivers/dummy/SCsub
index 28b315ae66..91e1140b75 100644
--- a/drivers/dummy/SCsub
+++ b/drivers/dummy/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 4df28e3ea4..0bcfed2dcf 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -35,8 +35,8 @@
#include "core/rid_owner.h"
#include "core/self_list.h"
#include "scene/resources/mesh.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
class RasterizerSceneDummy : public RasterizerScene {
public:
@@ -55,36 +55,37 @@ public:
RID sky_create() { return RID(); }
void sky_set_radiance_size(RID p_sky, int p_radiance_size) {}
- void sky_set_mode(RID p_sky, VS::SkyMode p_samples) {}
+ void sky_set_mode(RID p_sky, RS::SkyMode p_samples) {}
void sky_set_texture(RID p_sky, RID p_panorama) {}
void sky_set_texture(RID p_sky, RID p_cube_map, int p_radiance_size) {}
+ void sky_set_material(RID p_sky, RID p_material) {}
/* ENVIRONMENT API */
RID environment_create() { return RID(); }
- void environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {}
+ void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {}
void environment_set_sky(RID p_env, RID p_sky) {}
void environment_set_sky_custom_fov(RID p_env, float p_scale) {}
void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {}
void environment_set_bg_color(RID p_env, const Color &p_color) {}
void environment_set_bg_energy(RID p_env, float p_energy) {}
void environment_set_canvas_max_layer(RID p_env, int p_max_layer) {}
- void environment_set_ambient_light(RID p_env, const Color &p_color, VS::EnvironmentAmbientSource p_ambient = VS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, VS::EnvironmentReflectionSource p_reflection_source = VS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) {}
+ void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) {}
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) {}
#endif
- void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {}
+ void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, 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 environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
void 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, bool p_roughness) {}
- virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {}
- virtual void environment_set_ssao_quality(VS::EnvironmentSSAOQuality p_quality, bool p_half_size) {}
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {}
+ virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) {}
- void environment_set_tonemap(RID p_env, VS::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 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) {}
void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {}
@@ -93,13 +94,13 @@ public:
void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {}
bool is_environment(RID p_env) const { return false; }
- VS::EnvironmentBG environment_get_background(RID p_env) const { return VS::ENV_BG_KEEP; }
+ RS::EnvironmentBG environment_get_background(RID p_env) const { return RS::ENV_BG_KEEP; }
int environment_get_canvas_max_layer(RID p_env) const { return 0; }
virtual RID camera_effects_create() { return RID(); }
- virtual void camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter) {}
- virtual void camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape) {}
+ 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) {}
virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) {}
virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {}
@@ -132,10 +133,10 @@ public:
void set_scene_pass(uint64_t p_pass) {}
virtual void set_time(double p_time, double p_step) {}
- void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {}
+ void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) {}
virtual RID render_buffers_create() { return RID(); }
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) {}
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa) {}
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) {}
virtual bool screen_space_roughness_limiter_is_active() const { return false; }
@@ -161,28 +162,28 @@ public:
struct DummySurface {
uint32_t format;
- VS::PrimitiveType primitive;
+ RS::PrimitiveType primitive;
Vector<uint8_t> array;
int vertex_count;
Vector<uint8_t> index_array;
int index_count;
AABB aabb;
- Vector<Vector<uint8_t> > blend_shapes;
+ Vector<Vector<uint8_t>> blend_shapes;
Vector<AABB> bone_aabbs;
};
struct DummyMesh {
Vector<DummySurface> surfaces;
int blend_shape_count;
- VS::BlendShapeMode blend_shape_mode;
+ RS::BlendShapeMode blend_shape_mode;
};
mutable RID_PtrOwner<DummyTexture> texture_owner;
mutable RID_PtrOwner<DummyMesh> mesh_owner;
virtual RID texture_2d_create(const Ref<Image> &p_image) { return RID(); }
- virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type) { return RID(); }
- virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) { return RID(); }
+ virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) { return RID(); }
+ virtual RID texture_3d_create(const Vector<Ref<Image>> &p_slices) { return RID(); }
virtual RID texture_proxy_create(RID p_base) { return RID(); }
virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) {}
@@ -208,11 +209,11 @@ public:
virtual void texture_set_path(RID p_texture, const String &p_path) {}
virtual String texture_get_path(RID p_texture) const { return String(); }
- virtual void texture_set_detect_3d_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) {}
- virtual void texture_set_detect_normal_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) {}
- virtual void texture_set_detect_roughness_callback(RID p_texture, VS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {}
+ virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {}
+ virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {}
+ virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {}
- virtual void texture_debug_usage(List<VS::TextureInfo> *r_info) {}
+ virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) {}
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {}
virtual Size2 texture_size_with_proxy(RID p_proxy) { return Size2(); }
@@ -224,7 +225,7 @@ public:
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, VisualServer::TextureType p_type = VS::TEXTURE_TYPE_2D, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) {
+ 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) {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!t);
t->width = p_width;
@@ -277,7 +278,7 @@ public:
return t->format;
}
- VisualServer::TextureType texture_get_type(RID p_texture) const { return VS::TEXTURE_TYPE_2D; }
+ RenderingServer::TextureType texture_get_type(RID p_texture) const { return RS::TEXTURE_TYPE_2D; }
uint32_t texture_get_texid(RID p_texture) const { return 0; }
uint32_t texture_get_width(RID p_texture) const { return 0; }
uint32_t texture_get_height(RID p_texture) const { return 0; }
@@ -298,13 +299,13 @@ public:
void texture_set_shrink_all_x2_on_set_data(bool p_enable) {}
- void texture_debug_usage(List<VS::TextureInfo> *r_info) {}
+ void texture_debug_usage(List<RS::TextureInfo> *r_info) {}
RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const { return RID(); }
- void texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {}
- void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {}
- void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {}
+ void texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {}
+ void texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {}
+ void texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {}
void textures_keep_original(bool p_enable) {}
@@ -313,6 +314,11 @@ public:
void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {}
#endif
+ /* SKY API */
+
+ RID sky_create() { return RID(); }
+ void sky_set_texture(RID p_sky, RID p_cube_map, int p_radiance_size) {}
+
/* SHADER API */
RID shader_create() { return RID(); }
@@ -347,14 +353,14 @@ public:
DummyMesh *mesh = memnew(DummyMesh);
ERR_FAIL_COND_V(!mesh, RID());
mesh->blend_shape_count = 0;
- mesh->blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED;
+ mesh->blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
return mesh_owner.make_rid(mesh);
}
- void mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface) {}
+ void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {}
#if 0
- void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::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>()) {
+ 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>()) {
DummyMesh *m = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!m);
@@ -384,14 +390,14 @@ public:
return m->blend_shape_count;
}
- void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) {
+ void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
DummyMesh *m = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!m);
m->blend_shape_mode = p_mode;
}
- VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const {
+ RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const {
DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, VS::BLEND_SHAPE_MODE_NORMALIZED);
+ ERR_FAIL_COND_V(!m, RS::BLEND_SHAPE_MODE_NORMALIZED);
return m->blend_shape_mode;
}
@@ -433,9 +439,9 @@ public:
return m->surfaces[p_surface].format;
}
- VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
+ RS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
DummyMesh *m = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!m, VS::PRIMITIVE_POINTS);
+ ERR_FAIL_COND_V(!m, RS::PRIMITIVE_POINTS);
return m->surfaces[p_surface].primitive;
}
@@ -468,7 +474,7 @@ public:
}
#endif
- VS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const { return VS::SurfaceData(); }
+ RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const { return RS::SurfaceData(); }
int mesh_get_surface_count(RID p_mesh) const {
DummyMesh *m = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND_V(!m, 0);
@@ -485,7 +491,7 @@ public:
virtual RID multimesh_create() { return RID(); }
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) {}
+ 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) {}
int multimesh_get_instance_count(RID p_multimesh) const { return 0; }
void multimesh_set_mesh(RID p_multimesh, RID p_mesh) {}
@@ -510,7 +516,7 @@ public:
/* IMMEDIATE API */
RID immediate_create() { return RID(); }
- void immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture = 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) {}
@@ -537,14 +543,14 @@ public:
/* Light API */
- RID light_create(VS::LightType p_type) { return RID(); }
+ RID light_create(RS::LightType p_type) { return RID(); }
- RID directional_light_create() { return light_create(VS::LIGHT_DIRECTIONAL); }
- RID omni_light_create() { return light_create(VS::LIGHT_OMNI); }
- RID spot_light_create() { return light_create(VS::LIGHT_SPOT); }
+ 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); }
void light_set_color(RID p_light, const Color &p_color) {}
- void light_set_param(RID p_light, VS::LightParam p_param, float p_value) {}
+ void light_set_param(RID p_light, RS::LightParam p_param, float p_value) {}
void light_set_shadow(RID p_light, bool p_enabled) {}
void light_set_shadow_color(RID p_light, const Color &p_color) {}
void light_set_projector(RID p_light, RID p_texture) {}
@@ -553,22 +559,22 @@ public:
void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {}
void light_set_use_gi(RID p_light, bool p_enabled) {}
- void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {}
+ void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {}
- void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) {}
+ void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {}
void light_directional_set_blend_splits(RID p_light, bool p_enable) {}
bool light_directional_get_blend_splits(RID p_light) const { return false; }
- void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) {}
- VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const { return VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; }
+ void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) {}
+ RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const { return RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; }
- VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) { return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; }
- VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) { return VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; }
+ RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; }
+ RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) { return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; }
bool light_has_shadow(RID p_light) const { return false; }
- VS::LightType light_get_type(RID p_light) const { return VS::LIGHT_OMNI; }
+ RS::LightType light_get_type(RID p_light) const { return RS::LIGHT_OMNI; }
AABB light_get_aabb(RID p_light) const { return AABB(); }
- float light_get_param(RID p_light, VS::LightParam p_param) { return 0.0; }
+ float light_get_param(RID p_light, RS::LightParam p_param) { return 0.0; }
Color light_get_color(RID p_light) { return Color(); }
bool light_get_use_gi(RID p_light) { return false; }
uint64_t light_get_version(RID p_light) const { return 0; }
@@ -577,7 +583,7 @@ public:
RID reflection_probe_create() { return RID(); }
- void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) {}
+ void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {}
void reflection_probe_set_intensity(RID p_probe, float p_intensity) {}
void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) {}
void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) {}
@@ -592,7 +598,7 @@ public:
void reflection_probe_set_resolution(RID p_probe, int p_resolution) {}
AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); }
- VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; }
+ RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; }
uint32_t reflection_probe_get_cull_mask(RID p_probe) const { return 0; }
Vector3 reflection_probe_get_extents(RID p_probe) const { return Vector3(); }
Vector3 reflection_probe_get_origin_offset(RID p_probe) const { return Vector3(); }
@@ -713,7 +719,7 @@ public:
float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
- ERR_FAIL_COND_V(!capture, NULL);
+ ERR_FAIL_COND_V(!capture, nullptr);
return &capture->octree;
}
@@ -736,7 +742,7 @@ public:
void particles_set_fractional_delta(RID p_particles, bool p_enable) {}
void particles_restart(RID p_particles) {}
- void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) {}
+ void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {}
void particles_set_draw_passes(RID p_particles, int p_count) {}
void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {}
@@ -770,12 +776,12 @@ public:
virtual void render_target_disable_clear_request(RID p_render_target) {}
virtual void render_target_do_clear_request(RID p_render_target) {}
- VS::InstanceType get_base_type(RID p_rid) const {
+ RS::InstanceType get_base_type(RID p_rid) const {
if (mesh_owner.owns(p_rid)) {
- return VS::INSTANCE_MESH;
+ return RS::INSTANCE_MESH;
}
- return VS::INSTANCE_NONE;
+ return RS::INSTANCE_NONE;
}
bool free(RID p_rid) {
@@ -797,9 +803,9 @@ public:
void render_info_begin_capture() {}
void render_info_end_capture() {}
- int get_captured_render_info(VS::RenderInfo p_info) { return 0; }
+ int get_captured_render_info(RS::RenderInfo p_info) { return 0; }
- int get_render_info(VS::RenderInfo p_info) { return 0; }
+ int 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(); }
@@ -819,7 +825,7 @@ public:
class RasterizerCanvasDummy : public RasterizerCanvas {
public:
- virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { return 0; }
+ virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { return 0; }
virtual void free_texture_binding(TextureBindingID p_binding) {}
virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) { return 0; }
@@ -835,7 +841,7 @@ public:
virtual RID occluder_polygon_create() { return RID(); }
virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) {}
- virtual void occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) {}
+ virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {}
void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h
index e5ae945706..2a7d01dd78 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 = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/gl_context/SCsub b/drivers/gl_context/SCsub
index b9f0ea2254..ddeec6f4c6 100644
--- a/drivers/gl_context/SCsub
+++ b/drivers/gl_context/SCsub
@@ -1,8 +1,8 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
-if (env["platform"] in ["haiku", "osx", "windows", "x11"]):
+if env["platform"] in ["haiku", "osx", "windows", "linuxbsd"]:
# Thirdparty source files
thirdparty_dir = "#thirdparty/glad/"
thirdparty_sources = [
@@ -12,8 +12,8 @@ if (env["platform"] in ["haiku", "osx", "windows", "x11"]):
env.Prepend(CPPPATH=[thirdparty_dir])
- env.Append(CPPDEFINES=['GLAD_ENABLED'])
- env.Append(CPPDEFINES=['GLES_OVER_GL'])
+ env.Append(CPPDEFINES=["GLAD_ENABLED"])
+ env.Append(CPPDEFINES=["GLES_OVER_GL"])
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
diff --git a/drivers/gles2/SCsub b/drivers/gles2/SCsub
index 9923e52c73..987ddcd16e 100644
--- a/drivers/gles2/SCsub
+++ b/drivers/gles2/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index 24927c4bb8..069eeaba6c 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/project_settings.h"
#include "rasterizer_scene_gles2.h"
-#include "servers/visual/visual_server_raster.h"
+#include "servers/rendering/rendering_server_raster.h"
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
@@ -85,7 +85,7 @@ void RasterizerCanvasGLES2::_set_uniforms() {
state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR, light->color * light->energy);
state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS, light->light_shader_pos);
state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT, light->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA, light->mode == VS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0);
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA, light->mode == RS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0);
if (state.using_shadow) {
RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.getornull(light->shadow_buffer);
@@ -124,7 +124,7 @@ void RasterizerCanvasGLES2::canvas_begin() {
viewport_width = storage->frame.current_rt->width;
viewport_height = storage->frame.current_rt->height;
viewport_x = storage->frame.current_rt->x;
- viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y;
+ viewport_y = DisplayServer::get_singleton()->window_get_size().height - viewport_height - storage->frame.current_rt->y;
glScissor(viewport_x, viewport_y, viewport_width, viewport_height);
glViewport(viewport_x, viewport_y, viewport_width, viewport_height);
glEnable(GL_SCISSOR_TEST);
@@ -152,8 +152,8 @@ void RasterizerCanvasGLES2::canvas_begin() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
// set up default uniforms
@@ -168,7 +168,7 @@ void RasterizerCanvasGLES2::canvas_begin() {
canvas_transform.translate(-(storage->frame.current_rt->width / 2.0f), -(storage->frame.current_rt->height / 2.0f), 0.0f);
canvas_transform.scale(Vector3(2.0f / storage->frame.current_rt->width, csy * -2.0f / storage->frame.current_rt->height, 1.0f));
} else {
- Vector2 ssize = OS::get_singleton()->get_window_size();
+ Vector2 ssize = DisplayServer::get_singleton()->window_get_size();
canvas_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
canvas_transform.scale(Vector3(2.0f / ssize.width, -2.0f / ssize.height, 1.0f));
}
@@ -188,14 +188,14 @@ void RasterizerCanvasGLES2::canvas_end() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
glDisableVertexAttribArray(i);
}
if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) {
//reset viewport to full window size
- int viewport_width = OS::get_singleton()->get_window_size().width;
- int viewport_height = OS::get_singleton()->get_window_size().height;
+ int viewport_width = DisplayServer::get_singleton()->window_get_size().width;
+ int viewport_height = DisplayServer::get_singleton()->window_get_size().height;
glViewport(0, 0, viewport_width, viewport_height);
glScissor(0, 0, viewport_width, viewport_height);
}
@@ -208,7 +208,7 @@ void RasterizerCanvasGLES2::canvas_end() {
RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) {
- RasterizerStorageGLES2::Texture *tex_return = NULL;
+ RasterizerStorageGLES2::Texture *tex_return = nullptr;
if (p_texture.is_valid()) {
@@ -216,7 +216,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
if (!texture) {
state.current_tex = RID();
- state.current_tex_ptr = NULL;
+ state.current_tex_ptr = nullptr;
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
@@ -224,7 +224,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
} else {
if (texture->redraw_if_visible) {
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
texture = texture->get_ptr();
@@ -243,7 +243,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
}
} else {
state.current_tex = RID();
- state.current_tex_ptr = NULL;
+ state.current_tex_ptr = nullptr;
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
@@ -266,7 +266,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
} else {
if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
normal_map = normal_map->get_ptr();
@@ -293,59 +293,59 @@ void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_coun
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
#ifndef GLES_OVER_GL
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW);
#endif
uint32_t buffer_ofs = 0;
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
buffer_ofs += sizeof(Vector2) * p_vertex_count;
if (p_singlecolor) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
Color m = *p_colors;
- glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
+ glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
} else if (!p_colors) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} else {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(Color) * p_vertex_count;
}
if (p_uvs) {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(Vector2) * p_vertex_count;
} else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV);
}
if (p_weights && p_bones) {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights);
- glEnableVertexAttribArray(VS::ARRAY_WEIGHTS);
- glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_WEIGHTS);
+ glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(float) * 4 * p_vertex_count;
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones);
- glEnableVertexAttribArray(VS::ARRAY_BONES);
- glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_BONES);
+ glVertexAttribPointer(RS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(int) * 4 * p_vertex_count;
} else {
- glDisableVertexAttribArray(VS::ARRAY_WEIGHTS);
- glDisableVertexAttribArray(VS::ARRAY_BONES);
+ glDisableVertexAttribArray(RS::ARRAY_WEIGHTS);
+ glDisableVertexAttribArray(RS::ARRAY_BONES);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
#ifndef GLES_OVER_GL
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, nullptr, GL_DYNAMIC_DRAW);
#endif
if (storage->config.support_32_bits_indices) { //should check for
@@ -369,36 +369,36 @@ void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
#ifndef GLES_OVER_GL
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW);
#endif
uint32_t buffer_ofs = 0;
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
buffer_ofs += sizeof(Vector2) * p_vertex_count;
if (p_singlecolor) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
Color m = *p_colors;
- glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
+ glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
} else if (!p_colors) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} else {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(Color) * p_vertex_count;
}
if (p_uvs) {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
} else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV);
}
glDrawArrays(p_primitive, 0, p_vertex_count);
@@ -411,43 +411,43 @@ void RasterizerCanvasGLES2::_draw_generic_indices(GLuint p_primitive, const int
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
#ifndef GLES_OVER_GL
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW);
#endif
uint32_t buffer_ofs = 0;
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), nullptr);
buffer_ofs += sizeof(Vector2) * p_vertex_count;
if (p_singlecolor) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
Color m = *p_colors;
- glVertexAttrib4f(VS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
+ glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a);
} else if (!p_colors) {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} else {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors);
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(Color) * p_vertex_count;
}
if (p_uvs) {
glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs));
buffer_ofs += sizeof(Vector2) * p_vertex_count;
} else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
#ifndef GLES_OVER_GL
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, nullptr, GL_DYNAMIC_DRAW);
#endif
if (storage->config.support_32_bits_indices) { //should check for
@@ -510,20 +510,20 @@ void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_v
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
#ifndef GLES_OVER_GL
// Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData
- glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, nullptr, GL_DYNAMIC_DRAW);
#endif
glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), buffer_data);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), nullptr);
if (p_colors) {
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_offset * sizeof(float)));
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
+ glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_offset * sizeof(float)));
+ glEnableVertexAttribArray(RS::ARRAY_COLOR);
}
if (p_uvs) {
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(uv_offset * sizeof(float)));
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(uv_offset * sizeof(float)));
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
}
glDrawArrays(prim[p_points], 0, p_points);
@@ -564,8 +564,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
_bind_canvas_texture(RID(), RID());
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4fv(VS::ARRAY_COLOR, line->color.components);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttrib4fv(RS::ARRAY_COLOR, line->color.components);
state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
@@ -579,7 +579,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (line->antialiased)
glEnable(GL_LINE_SMOOTH);
#endif
- _draw_gui_primitive(2, verts, NULL, NULL);
+ _draw_gui_primitive(2, verts, nullptr, nullptr);
#ifdef GLES_OVER_GL
if (line->antialiased)
@@ -595,7 +595,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
line->to - t
};
- _draw_gui_primitive(4, verts, NULL, NULL);
+ _draw_gui_primitive(4, verts, nullptr, nullptr);
#ifdef GLES_OVER_GL
if (line->antialiased) {
glEnable(GL_LINE_SMOOTH);
@@ -604,7 +604,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
verts[j],
verts[(j + 1) % 4],
};
- _draw_gui_primitive(2, vertsl, NULL, NULL);
+ _draw_gui_primitive(2, vertsl, nullptr, nullptr);
}
glDisable(GL_LINE_SMOOTH);
}
@@ -616,8 +616,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
Item::CommandRect *r = static_cast<Item::CommandRect *>(command);
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttrib4fv(RS::ARRAY_COLOR, r->modulate.components);
bool can_tile = true;
if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) {
@@ -696,13 +696,13 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
bool untile = false;
- if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) {
+ if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & RS::TEXTURE_FLAG_REPEAT)) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
untile = true;
}
- _draw_gui_primitive(4, points, NULL, uvs);
+ _draw_gui_primitive(4, points, nullptr, uvs);
if (untile) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -717,7 +717,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
};
state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, Vector2());
- _draw_gui_primitive(4, points, NULL, uvs);
+ _draw_gui_primitive(4, points, nullptr, uvs);
}
} else {
@@ -753,7 +753,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
bool untile = false;
- if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) {
+ if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & RS::TEXTURE_FLAG_REPEAT)) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
untile = true;
@@ -816,8 +816,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.use_material((void *)p_material);
}
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
- glVertexAttrib4fv(VS::ARRAY_COLOR, np->color.components);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
+ glVertexAttrib4fv(RS::ARRAY_COLOR, np->color.components);
RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map);
@@ -968,13 +968,13 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR((sizeof(float) * 2)));
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), nullptr);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR((sizeof(float) * 2)));
- glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, NULL);
+ glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -1008,7 +1008,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
_bind_canvas_texture(RID(), RID());
- _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true);
+ _draw_polygon(indices, num_points * 3, num_points + 1, points, nullptr, &circle->color, true);
} break;
case Item::Command::TYPE_POLYGON: {
@@ -1072,18 +1072,18 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
}
- for (int k = 0; k < VS::ARRAY_MAX - 1; k++) {
+ for (int k = 0; k < RS::ARRAY_MAX - 1; k++) {
if (s->attribs[k].enabled) {
glEnableVertexAttribArray(k);
glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset));
} else {
glDisableVertexAttribArray(k);
switch (k) {
- case VS::ARRAY_NORMAL: {
- glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
+ case RS::ARRAY_NORMAL: {
+ glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
} break;
- case VS::ARRAY_COLOR: {
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ case RS::ARRAY_COLOR: {
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} break;
default: {
@@ -1099,7 +1099,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
}
}
- for (int j = 1; j < VS::ARRAY_MAX - 1; j++) {
+ for (int j = 1; j < RS::ARRAY_MAX - 1; j++) {
glDisableVertexAttribArray(j);
}
}
@@ -1118,7 +1118,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (!mesh_data)
break;
- state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != VS::MULTIMESH_CUSTOM_DATA_NONE);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCING, true);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
@@ -1162,18 +1162,18 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
}
- for (int k = 0; k < VS::ARRAY_MAX - 1; k++) {
+ for (int k = 0; k < RS::ARRAY_MAX - 1; k++) {
if (s->attribs[k].enabled) {
glEnableVertexAttribArray(k);
glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset));
} else {
glDisableVertexAttribArray(k);
switch (k) {
- case VS::ARRAY_NORMAL: {
- glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
+ case RS::ARRAY_NORMAL: {
+ glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
} break;
- case VS::ARRAY_COLOR: {
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ case RS::ARRAY_COLOR: {
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} break;
default: {
@@ -1189,7 +1189,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]);
glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]);
- if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) {
+ if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) {
glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]);
} else {
glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 2, 0.0, 0.0, 1.0, 0.0);
@@ -1197,7 +1197,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
}
if (multi_mesh->color_floats) {
- if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ if (multi_mesh->color_format == RS::MULTIMESH_COLOR_8BIT) {
uint8_t *color_data = (uint8_t *)(buffer + color_ofs);
glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0);
} else {
@@ -1208,7 +1208,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
}
if (multi_mesh->custom_data_floats) {
- if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ if (multi_mesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) {
uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs);
glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0);
} else {
@@ -1241,13 +1241,13 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
_bind_canvas_texture(RID(), RID());
if (pline->triangles.size()) {
- _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
+ _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), nullptr, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
#ifdef GLES_OVER_GL
glEnable(GL_LINE_SMOOTH);
if (pline->multiline) {
//needs to be different
} else {
- _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
+ _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), nullptr, pline->line_colors.ptr(), pline->line_colors.size() == 1);
}
glDisable(GL_LINE_SMOOTH);
#endif
@@ -1265,12 +1265,12 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
while (todo) {
int to_draw = MIN(max_per_call, todo);
- _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1);
+ _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], nullptr, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1);
todo -= to_draw;
offset += to_draw * 2;
}
} else {
- _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
+ _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), nullptr, pline->line_colors.ptr(), pline->line_colors.size() == 1);
}
#ifdef GLES_OVER_GL
@@ -1301,9 +1301,9 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
if (primitive->colors.size() == 1 && primitive->points.size() > 1) {
Color c = primitive->colors[0];
- glVertexAttrib4f(VS::ARRAY_COLOR, c.r, c.g, c.b, c.a);
+ glVertexAttrib4f(RS::ARRAY_COLOR, c.r, c.g, c.b, c.a);
} else if (primitive->colors.empty()) {
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
}
_draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr());
@@ -1402,7 +1402,7 @@ void RasterizerCanvasGLES2::_copy_screen(const Rect2 &p_rect) {
2, 3, 0
};
- _draw_polygon(indexpos, 6, 4, vertpos, uvpos, NULL, false);
+ _draw_polygon(indexpos, 6, 4, vertpos, uvpos, nullptr, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, false);
@@ -1426,16 +1426,16 @@ void RasterizerCanvasGLES2::_copy_texscreen(const Rect2 &p_rect) {
void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) {
- Item *current_clip = NULL;
+ Item *current_clip = nullptr;
- RasterizerStorageGLES2::Shader *shader_cache = NULL;
+ RasterizerStorageGLES2::Shader *shader_cache = nullptr;
bool rebind_shader = true;
bool prev_use_skeleton = false;
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, false);
state.current_tex = RID();
- state.current_tex_ptr = NULL;
+ state.current_tex_ptr = nullptr;
state.current_normal = RID();
state.canvas_texscreen_used = false;
@@ -1475,14 +1475,14 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
}
- RasterizerStorageGLES2::Skeleton *skeleton = NULL;
+ RasterizerStorageGLES2::Skeleton *skeleton = nullptr;
{
//skeleton handling
if (ci->skeleton.is_valid() && storage->skeleton_owner.owns(ci->skeleton)) {
skeleton = storage->skeleton_owner.getornull(ci->skeleton);
if (!skeleton->use_2d) {
- skeleton = NULL;
+ skeleton = nullptr;
} else {
state.skeleton_transform = p_base_transform * skeleton->base_transform_2d;
state.skeleton_transform_inverse = state.skeleton_transform.affine_inverse();
@@ -1490,7 +1490,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
}
- bool use_skeleton = skeleton != NULL;
+ bool use_skeleton = skeleton != nullptr;
if (prev_use_skeleton != use_skeleton) {
rebind_shader = true;
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, use_skeleton);
@@ -1513,13 +1513,13 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
if (material != canvas_last_material || rebind_shader) {
- RasterizerStorageGLES2::Shader *shader_ptr = NULL;
+ RasterizerStorageGLES2::Shader *shader_ptr = nullptr;
if (material_ptr) {
shader_ptr = material_ptr->shader;
- if (shader_ptr && shader_ptr->mode != VS::SHADER_CANVAS_ITEM) {
- shader_ptr = NULL; // not a canvas item shader, don't use.
+ if (shader_ptr && shader_ptr->mode != RS::SHADER_CANVAS_ITEM) {
+ shader_ptr = nullptr; // not a canvas item shader, don't use.
}
}
@@ -1542,7 +1542,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
if (shader_ptr != shader_cache) {
if (shader_ptr->canvas_item.uses_time) {
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id);
@@ -1582,7 +1582,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
if (t->redraw_if_visible) {
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
t = t->get_ptr();
@@ -1674,7 +1674,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
_set_uniforms();
if (unshaded || (state.uniforms.final_modulate.a > 0.001 && (!shader_cache || shader_cache->canvas_item.light_mode != RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked))
- _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr);
+ _canvas_item_render_commands(p_item_list, nullptr, reclip, material_ptr);
rebind_shader = true; // hacked in for now.
@@ -1682,7 +1682,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
Light *light = p_light;
bool light_used = false;
- VS::CanvasLightMode mode = VS::CANVAS_LIGHT_MODE_ADD;
+ RS::CanvasLightMode mode = RS::CANVAS_LIGHT_MODE_ADD;
state.uniforms.final_modulate = ci->final_modulate; // remove the canvas modulate
while (light) {
@@ -1697,17 +1697,17 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
switch (mode) {
- case VS::CANVAS_LIGHT_MODE_ADD: {
+ case RS::CANVAS_LIGHT_MODE_ADD: {
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} break;
- case VS::CANVAS_LIGHT_MODE_SUB: {
+ case RS::CANVAS_LIGHT_MODE_SUB: {
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
} break;
- case VS::CANVAS_LIGHT_MODE_MIX:
- case VS::CANVAS_LIGHT_MODE_MASK: {
+ case RS::CANVAS_LIGHT_MODE_MIX:
+ case RS::CANVAS_LIGHT_MODE_MASK: {
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1726,12 +1726,12 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, has_shadow);
if (has_shadow) {
state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_NONE);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF3);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF5);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF7);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF9);
- state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF13);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_NONE);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF3);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF5);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF7);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF9);
+ state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF13);
}
state.canvas_shader.bind();
@@ -1753,9 +1753,9 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
glActiveTexture(GL_TEXTURE0);
- _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); //redraw using light
+ _canvas_item_render_commands(p_item_list, nullptr, reclip, material_ptr); //redraw using light
- state.using_light = NULL;
+ state.using_light = nullptr;
}
light = light->next_ptr;
@@ -1846,7 +1846,7 @@ void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, cons
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- VS::CanvasOccluderPolygonCullMode cull = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+ RS::CanvasOccluderPolygonCullMode cull = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
for (int i = 0; i < 4; i++) {
@@ -1903,31 +1903,31 @@ void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, cons
state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX, instance->xform_cache);
- VS::CanvasOccluderPolygonCullMode transformed_cull_cache = instance->cull_cache;
+ RS::CanvasOccluderPolygonCullMode transformed_cull_cache = instance->cull_cache;
- if (transformed_cull_cache != VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED &&
+ if (transformed_cull_cache != RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED &&
(p_light_xform.basis_determinant() * instance->xform_cache.basis_determinant()) < 0) {
transformed_cull_cache =
- transformed_cull_cache == VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ?
- VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE :
- VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE;
+ transformed_cull_cache == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ?
+ RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE :
+ RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE;
}
if (cull != transformed_cull_cache) {
cull = transformed_cull_cache;
switch (cull) {
- case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: {
+ case RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: {
glDisable(GL_CULL_FACE);
} break;
- case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: {
+ case RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: {
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
} break;
- case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: {
+ case RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: {
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
@@ -1937,8 +1937,8 @@ void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, cons
}
glBindBuffer(GL_ARRAY_BUFFER, cc->vertex_id);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cc->index_id);
glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0);
@@ -1979,8 +1979,8 @@ void RasterizerCanvasGLES2::reset_canvas() {
void RasterizerCanvasGLES2::_bind_quad_buffer() {
glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices);
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, NULL);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
}
void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) {
@@ -1995,7 +1995,7 @@ void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float
if (storage->frame.current_rt) {
half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height);
} else {
- half_size = OS::get_singleton()->get_window_size();
+ half_size = DisplayServer::get_singleton()->window_get_size();
}
half_size *= 0.5;
Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y);
@@ -2022,14 +2022,14 @@ void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float
// and cleanup
glBindBuffer(GL_ARRAY_BUFFER, 0);
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
glDisableVertexAttribArray(i);
}
}
void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) {
- Vector2 window_size = OS::get_singleton()->get_window_size();
+ Vector2 window_size = DisplayServer::get_singleton()->window_get_size();
int window_h = window_size.height;
int window_w = window_size.width;
@@ -2117,7 +2117,7 @@ void RasterizerCanvasGLES2::initialize() {
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
glGenBuffers(1, &data.polygon_buffer);
glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer);
- glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, poly_size, nullptr, GL_DYNAMIC_DRAW);
data.polygon_buffer_size = poly_size;
@@ -2128,7 +2128,7 @@ void RasterizerCanvasGLES2::initialize() {
index_size *= 1024; // kb
glGenBuffers(1, &data.polygon_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
data.polygon_index_buffer_size = index_size;
@@ -2140,7 +2140,7 @@ void RasterizerCanvasGLES2::initialize() {
glGenBuffers(1, &data.ninepatch_vertices);
glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices);
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -2210,7 +2210,7 @@ void RasterizerCanvasGLES2::initialize() {
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false));
- state.using_light = NULL;
+ state.using_light = nullptr;
state.using_transparent_rt = false;
state.using_skeleton = false;
}
diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h
index f6ae6a60c0..2d6355e948 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.h
+++ b/drivers/gles2/rasterizer_canvas_gles2.h
@@ -32,7 +32,7 @@
#define RASTERIZERCANVASGLES2_H
#include "rasterizer_storage_gles2.h"
-#include "servers/visual/rasterizer.h"
+#include "servers/rendering/rasterizer.h"
#include "shaders/canvas.glsl.gen.h"
#include "shaders/lens_distorted.glsl.gen.h"
@@ -116,7 +116,7 @@ public:
virtual void canvas_end();
_FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs);
- _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights = NULL, const int *p_bones = NULL);
+ _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights = nullptr, const int *p_bones = nullptr);
_FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
_FORCE_INLINE_ void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 02b956fd44..37b729d568 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -221,7 +221,7 @@ void RasterizerGLES2::initialize() {
if (OS::get_singleton()->is_stdout_verbose()) {
if (GLAD_GL_ARB_debug_output) {
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- glDebugMessageCallbackARB(_gl_debug_print, NULL);
+ glDebugMessageCallbackARB(_gl_debug_print, nullptr);
glEnable(_EXT_DEBUG_OUTPUT);
} else {
print_line("OpenGL debugging not supported!");
@@ -233,12 +233,12 @@ void RasterizerGLES2::initialize() {
#ifdef CAN_DEBUG
#ifdef GLES_OVER_GL
if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) {
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
/* glDebugMessageInsertARB(
GL_DEBUG_SOURCE_API_ARB,
GL_DEBUG_TYPE_OTHER_ARB, 1,
@@ -256,14 +256,14 @@ void RasterizerGLES2::initialize() {
print_line("godot: ENABLING GL DEBUG");
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- callback(_gl_debug_print, NULL);
+ callback(_gl_debug_print, nullptr);
glEnable(_EXT_DEBUG_OUTPUT);
}
}
#endif // GLES_OVER_GL
#endif // CAN_DEBUG
- print_line("OpenGL ES 2.0 Renderer: " + VisualServer::get_singleton()->get_video_adapter_name());
+ print_line("OpenGL ES 2.0 Renderer: " + RenderingServer::get_singleton()->get_video_adapter_name());
storage->initialize();
canvas->initialize();
scene->initialize();
@@ -316,15 +316,15 @@ void RasterizerGLES2::set_current_render_target(RID p_render_target) {
glViewport(0, 0, rt->width, rt->height);
} else {
- storage->frame.current_rt = NULL;
+ storage->frame.current_rt = nullptr;
storage->frame.clear_request = false;
- glViewport(0, 0, OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
+ glViewport(0, 0, DisplayServer::get_singleton()->window_get_size().width, DisplayServer::get_singleton()->window_get_size().height);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
}
}
void RasterizerGLES2::restore_render_target(bool p_3d_was_drawn) {
- ERR_FAIL_COND(storage->frame.current_rt == NULL);
+ ERR_FAIL_COND(storage->frame.current_rt == nullptr);
RasterizerStorageGLES2::RenderTarget *rt = storage->frame.current_rt;
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glViewport(0, 0, rt->width, rt->height);
@@ -359,7 +359,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), RS::TEXTURE_TYPE_2D, p_use_filter ? RS::TEXTURE_FLAG_FILTER : 0);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index 9a5501f13d..027a634ae8 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -34,7 +34,7 @@
#include "rasterizer_canvas_gles2.h"
#include "rasterizer_scene_gles2.h"
#include "rasterizer_storage_gles2.h"
-#include "servers/visual/rasterizer.h"
+#include "servers/rendering/rasterizer.h"
class RasterizerGLES2 : public Rasterizer {
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index c433886545..2ba2147de9 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -37,7 +37,7 @@
#include "core/vmap.h"
#include "rasterizer_canvas_gles2.h"
#include "servers/camera/camera_feed.h"
-#include "servers/visual/visual_server_raster.h"
+#include "servers/rendering/rendering_server_raster.h"
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
@@ -142,7 +142,7 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) {
glGenTextures(1, &shadow_atlas->color);
glBindTexture(GL_TEXTURE_2D, shadow_atlas->color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadow_atlas->size, shadow_atlas->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadow_atlas->size, shadow_atlas->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -152,7 +152,7 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) {
//just depth texture
glGenTextures(1, &shadow_atlas->depth);
glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
- glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -456,10 +456,10 @@ int RasterizerSceneGLES2::get_directional_light_shadow_size(RID p_light_intance)
ERR_FAIL_COND_V(!light_instance, 0);
switch (light_instance->light_ptr->directional_shadow_mode) {
- case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
+ case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
break; //none
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
shadow_size /= 2;
break;
}
@@ -525,7 +525,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance
const ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
- bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS;
+ bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == RS::REFLECTION_PROBE_UPDATE_ALWAYS;
rpi->dirty = false;
return need_redraw;
}
@@ -566,7 +566,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
// Mobile hardware (PowerVR specially) prefers this approach,
// the previous approach with manual lod levels kills the game.
for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, nullptr);
}
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
@@ -575,7 +575,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
for (int i = 0; i < 6; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
glBindTexture(GL_TEXTURE_2D, rpi->color[i]);
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size, 0, format, type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size, 0, format, type, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rpi->color[i], 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -610,7 +610,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
- for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX - 1; i++) {
glDisableVertexAttribArray(i);
}
}
@@ -646,7 +646,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, storage->resources.mipmap_blur_color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, storage->resources.mipmap_blur_color, 0);
glViewport(0, 0, size, size);
glActiveTexture(GL_TEXTURE0);
@@ -690,7 +690,7 @@ RID RasterizerSceneGLES2::environment_create() {
return environment_owner.make_rid(env);
}
-void RasterizerSceneGLES2::environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {
+void RasterizerSceneGLES2::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -755,7 +755,7 @@ void RasterizerSceneGLES2::environment_set_camera_feed_id(RID p_env, int p_camer
env->camera_feed_id = p_camera_feed_id;
}
-void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
+void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -767,7 +767,7 @@ void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable
env->dof_blur_far_quality = p_quality;
}
-void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
+void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -779,7 +779,7 @@ void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enabl
env->dof_blur_near_quality = p_quality;
}
-void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {
+void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -806,12 +806,12 @@ void RasterizerSceneGLES2::environment_set_ssr(RID p_env, bool p_enable, int p_m
ERR_FAIL_COND(!env);
}
-void RasterizerSceneGLES2::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
+void RasterizerSceneGLES2::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, RS::EnvironmentSSAOQuality p_quality, RenderingServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
}
-void RasterizerSceneGLES2::environment_set_tonemap(RID p_env, VS::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 RasterizerSceneGLES2::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);
ERR_FAIL_COND(!env);
}
@@ -866,9 +866,9 @@ bool RasterizerSceneGLES2::is_environment(RID p_env) {
return environment_owner.owns(p_env);
}
-VS::EnvironmentBG RasterizerSceneGLES2::environment_get_background(RID p_env) {
+RS::EnvironmentBG RasterizerSceneGLES2::environment_get_background(RID p_env) {
const Environment *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, VS::ENV_BG_MAX);
+ ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);
return env->bg_mode;
}
@@ -914,7 +914,7 @@ void RasterizerSceneGLES2::light_instance_set_shadow_transform(RID p_light_insta
LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
ERR_FAIL_COND(!light_instance);
- if (light_instance->light_ptr->type != VS::LIGHT_DIRECTIONAL) {
+ if (light_instance->light_ptr->type != RS::LIGHT_DIRECTIONAL) {
p_pass = 0;
}
@@ -956,7 +956,7 @@ void RasterizerSceneGLES2::gi_probe_instance_set_bounds(RID p_probe, const Vecto
void RasterizerSceneGLES2::_add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass) {
- RasterizerStorageGLES2::Material *material = NULL;
+ RasterizerStorageGLES2::Material *material = nullptr;
RID material_src;
if (p_instance->material_override.is_valid()) {
@@ -971,7 +971,7 @@ void RasterizerSceneGLES2::_add_geometry(RasterizerStorageGLES2::Geometry *p_geo
material = storage->material_owner.getornull(material_src);
if (!material->shader || !material->shader->valid) {
- material = NULL;
+ material = nullptr;
}
}
@@ -1022,7 +1022,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
//shader does not use discard and does not write a vertex position, use generic material
- if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) {
+ if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) {
p_material = storage->material_owner.getornull(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided);
mirror = false;
} else {
@@ -1048,7 +1048,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
e->use_accum = false;
e->light_index = RenderList::MAX_LIGHTS;
e->use_accum_ptr = &e->use_accum;
- e->instancing = (e->instance->base_type == VS::INSTANCE_MULTIMESH) ? 1 : 0;
+ e->instancing = (e->instance->base_type == RS::INSTANCE_MULTIMESH) ? 1 : 0;
e->front_facing = false;
if (e->geometry->last_pass != render_pass) {
@@ -1162,7 +1162,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
//directional sort key
e->light_type1 = 1;
- e->light_type2 = li->light_ptr->type == VisualServer::LIGHT_OMNI ? 0 : 1;
+ e->light_type2 = li->light_ptr->type == RenderingServer::LIGHT_OMNI ? 0 : 1;
e->light_index = li->light_index;
copy = true;
@@ -1181,7 +1181,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
// do not add anything here, as lights are duplicated elements..
if (p_material->shader->spatial.uses_time) {
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
}
@@ -1224,7 +1224,7 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p
switch (instance->base_type) {
- case VS::INSTANCE_MESH: {
+ case RS::INSTANCE_MESH: {
RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getornull(instance->base);
ERR_CONTINUE(!mesh);
@@ -1236,12 +1236,12 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p
RasterizerStorageGLES2::Surface *surface = mesh->surfaces[j];
- _add_geometry(surface, instance, NULL, material_index, p_depth_pass, p_shadow_pass);
+ _add_geometry(surface, instance, nullptr, material_index, p_depth_pass, p_shadow_pass);
}
} break;
- case VS::INSTANCE_MULTIMESH: {
+ case RS::INSTANCE_MULTIMESH: {
RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(instance->base);
ERR_CONTINUE(!multi_mesh);
@@ -1260,11 +1260,11 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p
}
} break;
- case VS::INSTANCE_IMMEDIATE: {
+ case RS::INSTANCE_IMMEDIATE: {
RasterizerStorageGLES2::Immediate *im = storage->immediate_owner.getornull(instance->base);
ERR_CONTINUE(!im);
- _add_geometry(im, instance, NULL, -1, p_depth_pass, p_shadow_pass);
+ _add_geometry(im, instance, nullptr, -1, p_depth_pass, p_shadow_pass);
} break;
@@ -1426,7 +1426,7 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m
}
if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
t = t->get_ptr();
@@ -1459,7 +1459,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
switch (p_element->instance->base_type) {
- case VS::INSTANCE_MESH: {
+ case RS::INSTANCE_MESH: {
RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id);
@@ -1468,18 +1468,18 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
}
- for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX - 1; i++) {
if (s->attribs[i].enabled) {
glEnableVertexAttribArray(i);
glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset));
} else {
glDisableVertexAttribArray(i);
switch (i) {
- case VS::ARRAY_NORMAL: {
- glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
+ case RS::ARRAY_NORMAL: {
+ glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
} break;
- case VS::ARRAY_COLOR: {
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ case RS::ARRAY_COLOR: {
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} break;
default: {
@@ -1502,7 +1502,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
Vector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer;
- if (!s->attribs[VS::ARRAY_BONES].enabled || !s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ if (!s->attribs[RS::ARRAY_BONES].enabled || !s->attribs[RS::ARRAY_WEIGHTS].enabled) {
break; // the whole instance has a skeleton, but this surface is not affected by it.
}
@@ -1511,10 +1511,10 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
transform_buffer.resize(s->array_len * 12);
}
- const size_t bones_offset = s->attribs[VS::ARRAY_BONES].offset;
- const size_t bones_stride = s->attribs[VS::ARRAY_BONES].stride;
- const size_t bone_weight_offset = s->attribs[VS::ARRAY_WEIGHTS].offset;
- const size_t bone_weight_stride = s->attribs[VS::ARRAY_WEIGHTS].stride;
+ const size_t bones_offset = s->attribs[RS::ARRAY_BONES].offset;
+ const size_t bones_stride = s->attribs[RS::ARRAY_BONES].stride;
+ const size_t bone_weight_offset = s->attribs[RS::ARRAY_WEIGHTS].offset;
+ const size_t bone_weight_stride = s->attribs[RS::ARRAY_WEIGHTS].stride;
{
float *write = transform_buffer.ptrw();
@@ -1530,7 +1530,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
size_t bones[4];
float bone_weight[4];
- if (s->attribs[VS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) {
+ if (s->attribs[RS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) {
// read as byte
const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride);
bones[0] = bones_ptr[0];
@@ -1546,7 +1546,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
bones[3] = bones_ptr[3];
}
- if (s->attribs[VS::ARRAY_WEIGHTS].type == GL_FLOAT) {
+ if (s->attribs[RS::ARRAY_WEIGHTS].type == GL_FLOAT) {
// read as float
const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride));
bone_weight[0] = weight_ptr[0];
@@ -1621,7 +1621,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
} break;
- case VS::INSTANCE_MULTIMESH: {
+ case RS::INSTANCE_MULTIMESH: {
RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id);
@@ -1630,18 +1630,18 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
}
- for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX - 1; i++) {
if (s->attribs[i].enabled) {
glEnableVertexAttribArray(i);
glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset));
} else {
glDisableVertexAttribArray(i);
switch (i) {
- case VS::ARRAY_NORMAL: {
- glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
+ case RS::ARRAY_NORMAL: {
+ glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1);
} break;
- case VS::ARRAY_COLOR: {
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ case RS::ARRAY_COLOR: {
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
} break;
default: {
@@ -1662,7 +1662,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste
} break;
- case VS::INSTANCE_IMMEDIATE: {
+ case RS::INSTANCE_IMMEDIATE: {
} break;
default: {
@@ -1674,7 +1674,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
switch (p_element->instance->base_type) {
- case VS::INSTANCE_MESH: {
+ case RS::INSTANCE_MESH: {
RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
@@ -1688,22 +1688,22 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
storage->info.render.vertices_count += s->array_len;
}
/*
- if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ if (p_element->instance->skeleton.is_valid() && s->attribs[RS::ARRAY_BONES].enabled && s->attribs[RS::ARRAY_WEIGHTS].enabled) {
//clean up after skeleton
glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer);
- glDisableVertexAttribArray(VS::ARRAY_MAX + 0);
- glDisableVertexAttribArray(VS::ARRAY_MAX + 1);
- glDisableVertexAttribArray(VS::ARRAY_MAX + 2);
+ glDisableVertexAttribArray(RS::ARRAY_MAX + 0);
+ glDisableVertexAttribArray(RS::ARRAY_MAX + 1);
+ glDisableVertexAttribArray(RS::ARRAY_MAX + 2);
- glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0);
- glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0);
- glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0);
+ glVertexAttrib4f(RS::ARRAY_MAX + 0, 1, 0, 0, 0);
+ glVertexAttrib4f(RS::ARRAY_MAX + 1, 0, 1, 0, 0);
+ glVertexAttrib4f(RS::ARRAY_MAX + 2, 0, 0, 1, 0);
}
*/
} break;
- case VS::INSTANCE_MULTIMESH: {
+ case RS::INSTANCE_MULTIMESH: {
RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner);
RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
@@ -1734,7 +1734,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
}
if (multi_mesh->color_floats) {
- if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ if (multi_mesh->color_format == RS::MULTIMESH_COLOR_8BIT) {
uint8_t *color_data = (uint8_t *)(buffer + color_ofs);
glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0);
} else {
@@ -1745,7 +1745,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
}
if (multi_mesh->custom_data_floats) {
- if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ if (multi_mesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) {
uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs);
glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0);
} else {
@@ -1764,7 +1764,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
} break;
- case VS::INSTANCE_IMMEDIATE: {
+ case RS::INSTANCE_IMMEDIATE: {
const RasterizerStorageGLES2::Immediate *im = static_cast<const RasterizerStorageGLES2::Immediate *>(p_element->geometry);
if (im->building) {
@@ -1792,7 +1792,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(c.texture);
if (t->redraw_if_visible) {
- VisualServerRaster::redraw_request();
+ RenderingServerRaster::redraw_request();
}
t = t->get_ptr();
@@ -1816,53 +1816,53 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
}
if (!c.normals.empty()) {
- glEnableVertexAttribArray(VS::ARRAY_NORMAL);
+ glEnableVertexAttribArray(RS::ARRAY_NORMAL);
glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr());
- glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs));
+ glVertexAttribPointer(RS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs));
buf_ofs += sizeof(Vector3) * vertices;
} else {
- glDisableVertexAttribArray(VS::ARRAY_NORMAL);
+ glDisableVertexAttribArray(RS::ARRAY_NORMAL);
}
if (!c.tangents.empty()) {
- glEnableVertexAttribArray(VS::ARRAY_TANGENT);
+ glEnableVertexAttribArray(RS::ARRAY_TANGENT);
glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr());
- glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), CAST_INT_TO_UCHAR_PTR(buf_ofs));
+ glVertexAttribPointer(RS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), CAST_INT_TO_UCHAR_PTR(buf_ofs));
buf_ofs += sizeof(Plane) * vertices;
} else {
- glDisableVertexAttribArray(VS::ARRAY_TANGENT);
+ glDisableVertexAttribArray(RS::ARRAY_TANGENT);
}
if (!c.colors.empty()) {
- glEnableVertexAttribArray(VS::ARRAY_COLOR);
+ glEnableVertexAttribArray(RS::ARRAY_COLOR);
glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr());
- glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buf_ofs));
+ glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buf_ofs));
buf_ofs += sizeof(Color) * vertices;
} else {
- glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ glDisableVertexAttribArray(RS::ARRAY_COLOR);
}
if (!c.uvs.empty()) {
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr());
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs));
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs));
buf_ofs += sizeof(Vector2) * vertices;
} else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV);
}
if (!c.uv2s.empty()) {
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV2);
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV2);
glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uv2s.ptr());
- glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs));
+ glVertexAttribPointer(RS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs));
buf_ofs += sizeof(Vector2) * vertices;
} else {
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV2);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV2);
}
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr());
- glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs));
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs));
glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size());
}
@@ -1901,18 +1901,18 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, true);
switch (p_light->light_ptr->type) {
- case VS::LIGHT_DIRECTIONAL: {
+ case RS::LIGHT_DIRECTIONAL: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, true);
switch (p_light->light_ptr->directional_shadow_mode) {
- case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
//no need
} break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true);
} break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true);
} break;
}
@@ -1931,7 +1931,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
}
} break;
- case VS::LIGHT_OMNI: {
+ case RS::LIGHT_OMNI: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true);
if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
@@ -1946,7 +1946,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
}
} break;
- case VS::LIGHT_SPOT: {
+ case RS::LIGHT_SPOT: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true);
if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
@@ -1969,8 +1969,8 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
RasterizerStorageGLES2::Light *light_ptr = light->light_ptr;
//common parameters
- float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY];
- float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
+ float energy = light_ptr->param[RS::LIGHT_PARAM_ENERGY];
+ float specular = light_ptr->param[RS::LIGHT_PARAM_SPECULAR];
float sign = (light_ptr->negative && !accum_pass) ? -1 : 1; //inverse color for base pass lights only
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular);
@@ -1982,7 +1982,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
//specific parameters
switch (light_ptr->type) {
- case VS::LIGHT_DIRECTIONAL: {
+ case RS::LIGHT_DIRECTIONAL: {
//not using inverse for performance, view should be normalized anyway
Vector3 direction = p_view_transform.basis.xform_inv(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
@@ -1995,15 +1995,15 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
Color split_offsets;
switch (light_ptr->directional_shadow_mode) {
- case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
shadow_count = 1;
} break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
shadow_count = 2;
} break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
shadow_count = 4;
} break;
}
@@ -2015,7 +2015,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
uint32_t width = light->directional_rect.size.x;
uint32_t height = light->directional_rect.size.y;
- if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ if (light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
width /= 2;
height /= 2;
@@ -2029,7 +2029,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
y += height;
}
- } else if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+ } else if (light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
height /= 2;
@@ -2067,16 +2067,16 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]);
}
} break;
- case VS::LIGHT_OMNI: {
+ case RS::LIGHT_OMNI: {
Vector3 position = p_view_transform.xform_inv(light->transform.origin);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position);
- float range = light_ptr->param[VS::LIGHT_PARAM_RANGE];
+ float range = light_ptr->param[RS::LIGHT_PARAM_RANGE];
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range);
- float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
+ float attenuation = light_ptr->param[RS::LIGHT_PARAM_ATTENUATION];
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
@@ -2101,7 +2101,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
uint32_t width = shadow_size;
uint32_t height = shadow_size;
- if (light->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+ if (light->light_ptr->omni_shadow_detail == RS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
height /= 2;
} else {
width /= 2;
@@ -2121,7 +2121,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
}
} break;
- case VS::LIGHT_SPOT: {
+ case RS::LIGHT_SPOT: {
Vector3 position = p_view_transform.xform_inv(light->transform.origin);
@@ -2129,10 +2129,10 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
- float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
- float range = light_ptr->param[VS::LIGHT_PARAM_RANGE];
- float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION];
- float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE];
+ float attenuation = light_ptr->param[RS::LIGHT_PARAM_ATTENUATION];
+ float range = light_ptr->param[RS::LIGHT_PARAM_RANGE];
+ float spot_attenuation = light_ptr->param[RS::LIGHT_PARAM_SPOT_ATTENUATION];
+ float angle = light_ptr->param[RS::LIGHT_PARAM_SPOT_ANGLE];
angle = Math::cos(Math::deg2rad(angle));
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation);
@@ -2259,19 +2259,19 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool prev_instancing = false;
bool prev_depth_prepass = false;
state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false);
- RasterizerStorageGLES2::Material *prev_material = NULL;
- RasterizerStorageGLES2::Geometry *prev_geometry = NULL;
- RasterizerStorageGLES2::Skeleton *prev_skeleton = NULL;
- RasterizerStorageGLES2::GeometryOwner *prev_owner = NULL;
+ RasterizerStorageGLES2::Material *prev_material = nullptr;
+ RasterizerStorageGLES2::Geometry *prev_geometry = nullptr;
+ RasterizerStorageGLES2::Skeleton *prev_skeleton = nullptr;
+ RasterizerStorageGLES2::GeometryOwner *prev_owner = nullptr;
Transform view_transform_inverse = p_view_transform.inverse();
CameraMatrix projection_inverse = p_projection.inverse();
bool prev_base_pass = false;
- LightInstance *prev_light = NULL;
+ LightInstance *prev_light = nullptr;
bool prev_vertex_lit = false;
- ReflectionProbeInstance *prev_refprobe_1 = NULL;
- ReflectionProbeInstance *prev_refprobe_2 = NULL;
+ ReflectionProbeInstance *prev_refprobe_1 = nullptr;
+ ReflectionProbeInstance *prev_refprobe_2 = nullptr;
int prev_blend_mode = -2; //will always catch the first go
@@ -2299,7 +2299,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
using_fog = true;
}
- RasterizerStorageGLES2::Texture *prev_lightmap = NULL;
+ RasterizerStorageGLES2::Texture *prev_lightmap = nullptr;
float lightmap_energy = 1.0;
bool prev_use_lightmap_capture = false;
@@ -2313,10 +2313,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool rebind = false;
bool accum_pass = *e->use_accum_ptr;
*e->use_accum_ptr = true; //set to accum for next time this is found
- LightInstance *light = NULL;
- ReflectionProbeInstance *refprobe_1 = NULL;
- ReflectionProbeInstance *refprobe_2 = NULL;
- RasterizerStorageGLES2::Texture *lightmap = NULL;
+ LightInstance *light = nullptr;
+ ReflectionProbeInstance *refprobe_1 = nullptr;
+ ReflectionProbeInstance *refprobe_2 = nullptr;
+ RasterizerStorageGLES2::Texture *lightmap = nullptr;
bool use_lightmap_capture = false;
bool rebind_light = false;
bool rebind_reflection = false;
@@ -2432,13 +2432,13 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
}
if (refprobe_1 != prev_refprobe_1 || refprobe_2 != prev_refprobe_2) {
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != NULL);
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != NULL);
- if (refprobe_1 != NULL && refprobe_1 != prev_refprobe_1) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != nullptr);
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != nullptr);
+ if (refprobe_1 != nullptr && refprobe_1 != prev_refprobe_1) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5);
glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_1->cubemap);
}
- if (refprobe_2 != NULL && refprobe_2 != prev_refprobe_2) {
+ if (refprobe_2 != nullptr && refprobe_2 != prev_refprobe_2) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6);
glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_2->cubemap);
}
@@ -2467,8 +2467,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
}
if (lightmap != prev_lightmap) {
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, lightmap != NULL);
- if (lightmap != NULL) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, lightmap != nullptr);
+ if (lightmap != nullptr) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
glBindTexture(GL_TEXTURE_2D, lightmap->tex_id);
}
@@ -2490,7 +2490,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
rebind = true;
}
- bool instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH;
+ bool instancing = e->instance->base_type == RS::INSTANCE_MULTIMESH;
if (instancing != prev_instancing) {
@@ -2501,16 +2501,16 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
if (skeleton != prev_skeleton) {
-
- if (skeleton) {
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true);
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, storage->config.use_skeleton_software);
- } else {
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false);
- state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, false);
+ if ((prev_skeleton == nullptr) != (skeleton == nullptr)) {
+ if (skeleton) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, storage->config.use_skeleton_software);
+ } else {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, false);
+ }
+ rebind = true;
}
-
- rebind = true;
}
if (e->owner != prev_owner || e->geometry != prev_geometry || skeleton != prev_skeleton) {
@@ -2641,7 +2641,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
prev_use_lightmap_capture = use_lightmap_capture;
}
- _setup_light_type(NULL, NULL); //clear light stuff
+ _setup_light_type(nullptr, nullptr); //clear light stuff
state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false);
state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false);
state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false);
@@ -2726,10 +2726,10 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, vertices, GL_DYNAMIC_DRAW);
// bind sky vertex array....
- glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, CAST_INT_TO_UCHAR_PTR(sizeof(Vector3)));
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, CAST_INT_TO_UCHAR_PTR(sizeof(Vector3)));
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, asymmetrical);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, !asymmetrical);
@@ -2752,8 +2752,8 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableVertexAttribArray(VS::ARRAY_VERTEX);
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glDisableVertexAttribArray(RS::ARRAY_VERTEX);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV);
glBindBuffer(GL_ARRAY_BUFFER, 0);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, false);
@@ -2845,9 +2845,9 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal());
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, true);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_far_quality == RS::ENV_DOF_BLUR_QUALITY_LOW);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == RS::ENV_DOF_BLUR_QUALITY_MEDIUM);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_far_quality == RS::ENV_DOF_BLUR_QUALITY_HIGH);
state.effect_blur_shader.bind();
int qsteps[3] = { 4, 10, 20 };
@@ -2901,7 +2901,7 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
if (!storage->frame.current_rt->used_dof_blur_near) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
int vp_h = storage->frame.current_rt->height;
@@ -2911,9 +2911,9 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, true);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, true);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_near_quality == RS::ENV_DOF_BLUR_QUALITY_LOW);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == RS::ENV_DOF_BLUR_QUALITY_MEDIUM);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_near_quality == RS::ENV_DOF_BLUR_QUALITY_HIGH);
state.effect_blur_shader.bind();
int qsteps[3] = { 4, 10, 20 };
@@ -3003,7 +3003,7 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
if (env->glow_enabled) {
- for (int i = 0; i < VS::MAX_GLOW_LEVELS; i++) {
+ for (int i = 0; i < RS::MAX_GLOW_LEVELS; i++) {
if (env->glow_levels & (1 << i)) {
if (i >= storage->frame.current_rt->mip_maps[1].sizes.size()) {
@@ -3156,9 +3156,9 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
}
}
- state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_SCREEN);
- state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_SOFTLIGHT);
- state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_REPLACE);
+ state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_SCREEN);
+ state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT);
+ state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_REPLACE);
}
//Adjustments
@@ -3216,7 +3216,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
storage->info.render.object_count += p_cull_count;
GLuint current_fb = 0;
- Environment *env = NULL;
+ Environment *env = nullptr;
int viewport_width, viewport_height;
int viewport_x = 0;
@@ -3261,7 +3261,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
viewport_x = storage->frame.current_rt->x;
if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) {
- viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y;
+ viewport_y = DisplayServer::get_singleton()->window_get_size().height - viewport_height - storage->frame.current_rt->y;
} else {
viewport_y = storage->frame.current_rt->y;
}
@@ -3288,7 +3288,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
LightInstance *light = light_instance_owner.getornull(light_rid);
- if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) {
+ if (light->light_ptr->type == RS::LIGHT_DIRECTIONAL) {
render_directional_lights++;
//as going in reverse, directional lights are always first anyway
}
@@ -3300,7 +3300,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
}
} else {
- render_light_instances = NULL;
+ render_light_instances = nullptr;
render_directional_lights = 0;
render_light_instance_count = 0;
}
@@ -3318,11 +3318,11 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
}
} else {
- reflection_probe_instances = NULL;
+ reflection_probe_instances = nullptr;
reflection_probe_count = 0;
}
- if (env && env->bg_mode == VS::ENV_BG_CANVAS) {
+ if (env && env->bg_mode == RS::ENV_BG_CANVAS) {
// If using canvas background, copy 2d to screen copy texture
// TODO: When GLES2 renders to current_rt->mip_maps[], this copy will no longer be needed
_copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->copy_screen_effect.fbo);
@@ -3358,22 +3358,22 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
clear_color = Color(0, 0, 0, 0);
storage->frame.clear_request = false;
- } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR || env->bg_mode == VS::ENV_BG_SKY) {
+ } else if (!env || env->bg_mode == RS::ENV_BG_CLEAR_COLOR || env->bg_mode == RS::ENV_BG_SKY) {
if (storage->frame.clear_request) {
clear_color = storage->frame.clear_request_color;
storage->frame.clear_request = false;
}
- } else if (env->bg_mode == VS::ENV_BG_CANVAS || env->bg_mode == VS::ENV_BG_COLOR || env->bg_mode == VS::ENV_BG_COLOR_SKY) {
+ } else if (env->bg_mode == RS::ENV_BG_CANVAS || env->bg_mode == RS::ENV_BG_COLOR || env->bg_mode == RS::ENV_BG_COLOR_SKY) {
clear_color = env->bg_color;
storage->frame.clear_request = false;
- } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) {
+ } else if (env->bg_mode == RS::ENV_BG_CAMERA_FEED) {
feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id);
storage->frame.clear_request = false;
} else {
storage->frame.clear_request = false;
}
- if (!env || env->bg_mode != VS::ENV_BG_KEEP) {
+ if (!env || env->bg_mode != RS::ENV_BG_KEEP) {
glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
glClear(GL_COLOR_BUFFER_BIT);
}
@@ -3385,26 +3385,26 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glDisable(GL_SCISSOR_TEST);
}
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// render sky
- RasterizerStorageGLES2::Sky *sky = NULL;
+ RasterizerStorageGLES2::Sky *sky = nullptr;
GLuint env_radiance_tex = 0;
if (env) {
switch (env->bg_mode) {
- case VS::ENV_BG_COLOR_SKY:
- case VS::ENV_BG_SKY: {
+ case RS::ENV_BG_COLOR_SKY:
+ case RS::ENV_BG_SKY: {
sky = storage->sky_owner.getornull(env->sky);
if (sky) {
env_radiance_tex = sky->radiance;
}
} break;
- case VS::ENV_BG_CAMERA_FEED: {
+ case RS::ENV_BG_CAMERA_FEED: {
if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) {
// copy our camera feed to our background
@@ -3419,12 +3419,12 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
if (feed->get_datatype() == CameraFeed::FEED_RGB) {
RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE);
- VS::get_singleton()->texture_bind(camera_RGBA, 0);
+ RS::get_singleton()->texture_bind(camera_RGBA, 0);
} else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) {
RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE);
- VS::get_singleton()->texture_bind(camera_YCbCr, 0);
+ RS::get_singleton()->texture_bind(camera_YCbCr, 0);
storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true);
@@ -3432,8 +3432,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE);
RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE);
- VS::get_singleton()->texture_bind(camera_Y, 0);
- VS::get_singleton()->texture_bind(camera_CbCr, 1);
+ RS::get_singleton()->texture_bind(camera_Y, 0);
+ RS::get_singleton()->texture_bind(camera_CbCr, 1);
storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, true);
storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true);
@@ -3444,8 +3444,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
storage->bind_quad_array();
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableVertexAttribArray(VS::ARRAY_VERTEX);
- glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glDisableVertexAttribArray(RS::ARRAY_VERTEX);
+ glDisableVertexAttribArray(RS::ARRAY_TEX_UV);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// turn off everything used
@@ -3464,7 +3464,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
clear_color = Color(0.0, 1.0, 0.0, 1.0);
}
} break;
- case VS::ENV_BG_CANVAS: {
+ case RS::ENV_BG_CANVAS: {
// use screen copy as background
_copy_texture_to_buffer(storage->frame.current_rt->copy_screen_effect.color, current_fb);
} break;
@@ -3484,7 +3484,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
_render_render_list(render_list.elements, render_list.element_count, cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, false, false);
// then draw the sky after
- if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) {
+ if (env && env->bg_mode == RS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) {
if (sky && sky->panorama.is_valid()) {
_draw_sky(sky, p_cam_projection, cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation);
@@ -3616,7 +3616,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
// TODO directional light
- if (light->type == VS::LIGHT_DIRECTIONAL) {
+ if (light->type == RS::LIGHT_DIRECTIONAL) {
// set pssm stuff
// TODO set this only when changed
@@ -3651,7 +3651,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
width = light_instance->directional_rect.size.width;
height = light_instance->directional_rect.size.height;
- if (light->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ if (light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
width /= 2;
height /= 2;
@@ -3665,7 +3665,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
y += height;
}
- } else if (light->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+ } else if (light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
height /= 2;
@@ -3676,10 +3676,10 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
}
}
- float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]);
- zfar = light->param[VS::LIGHT_PARAM_RANGE];
- bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult;
- normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult;
+ float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, light->param[RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]);
+ zfar = light->param[RS::LIGHT_PARAM_RANGE];
+ bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult;
+ normal_bias = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult;
fbo = directional_shadow.fbo;
} else {
@@ -3708,9 +3708,9 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
width = shadow_size;
height = shadow_size;
- if (light->type == VS::LIGHT_OMNI) {
+ if (light->type == RS::LIGHT_OMNI) {
// cubemap only
- if (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) {
+ if (light->omni_shadow_mode == RS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) {
int cubemap_index = shadow_cubemaps.size() - 1;
// find an appropriate cubemap to render to
@@ -3727,7 +3727,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
light_transform = light_instance->shadow_transform[0].transform;
custom_vp_size = shadow_cubemaps[cubemap_index].size;
- zfar = light->param[VS::LIGHT_PARAM_RANGE];
+ zfar = light->param[RS::LIGHT_PARAM_RANGE];
current_cubemap = cubemap_index;
} else {
@@ -3736,7 +3736,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
light_projection = light_instance->shadow_transform[0].camera;
light_transform = light_instance->shadow_transform[0].transform;
- if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+ if (light->omni_shadow_detail == RS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
height /= 2;
y += p_pass * height;
@@ -3747,22 +3747,22 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
state.dual_parbolloid_direction = p_pass == 0 ? 1.0 : -1.0;
flip_facing = (p_pass == 1);
- zfar = light->param[VS::LIGHT_PARAM_RANGE];
- bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS];
+ zfar = light->param[RS::LIGHT_PARAM_RANGE];
+ bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS];
state.dual_parbolloid_zfar = zfar;
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, true);
}
- } else if (light->type == VS::LIGHT_SPOT) {
+ } else if (light->type == RS::LIGHT_SPOT) {
light_projection = light_instance->shadow_transform[0].camera;
light_transform = light_instance->shadow_transform[0].transform;
flip_facing = false;
- zfar = light->param[VS::LIGHT_PARAM_RANGE];
- bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS];
- normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS];
+ zfar = light->param[RS::LIGHT_PARAM_RANGE];
+ bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS];
+ normal_bias = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS];
}
}
@@ -3806,13 +3806,13 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true);
- _render_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, flip_facing, false, true);
+ _render_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, RID(), nullptr, 0, bias, normal_bias, flip_facing, false, true);
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false);
state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, false);
// convert cubemap to dual paraboloid if needed
- if (light->type == VS::LIGHT_OMNI && (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) && p_pass == 5) {
+ if (light->type == RS::LIGHT_OMNI && (light->omni_shadow_mode == RS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) && p_pass == 5) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo);
@@ -3827,14 +3827,14 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_FLIP, i == 1);
state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_NEAR, light_projection.get_z_near());
state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_FAR, light_projection.get_z_far());
- state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::BIAS, light->param[VS::LIGHT_PARAM_SHADOW_BIAS]);
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::BIAS, light->param[RS::LIGHT_PARAM_SHADOW_BIAS]);
uint32_t local_width = width;
uint32_t local_height = height;
uint32_t local_x = x;
uint32_t local_y = y;
- if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+ if (light->omni_shadow_detail == RS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
local_height /= 2;
local_y += i * local_height;
} else {
@@ -3922,7 +3922,7 @@ bool RasterizerSceneGLES2::free(RID p_rid) {
return true;
}
-void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {
+void RasterizerSceneGLES2::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) {
}
void RasterizerSceneGLES2::initialize() {
@@ -3977,7 +3977,7 @@ void RasterizerSceneGLES2::initialize() {
{
glGenBuffers(1, &state.sky_verts);
glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts);
- glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@@ -3987,7 +3987,7 @@ void RasterizerSceneGLES2::initialize() {
glGenBuffers(1, &state.immediate_buffer);
glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
- glBufferData(GL_ARRAY_BUFFER, immediate_buffer_size * 1024, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, immediate_buffer_size * 1024, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@@ -4010,7 +4010,7 @@ void RasterizerSceneGLES2::initialize() {
for (int i = 0; i < 6; i++) {
- glTexImage2D(_cube_side_enum[i], 0, storage->config.depth_internalformat, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, NULL);
+ glTexImage2D(_cube_side_enum[i], 0, storage->config.depth_internalformat, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -4050,7 +4050,7 @@ void RasterizerSceneGLES2::initialize() {
glGenTextures(1, &directional_shadow.color);
glBindTexture(GL_TEXTURE_2D, directional_shadow.color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -4061,7 +4061,7 @@ void RasterizerSceneGLES2::initialize() {
glGenTextures(1, &directional_shadow.depth);
glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
- glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 174cdd8e2e..56c0e632c2 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -236,7 +236,7 @@ public:
/* ENVIRONMENT API */
struct Environment {
- VS::EnvironmentBG bg_mode;
+ RS::EnvironmentBG bg_mode;
RID sky;
float sky_custom_fov;
@@ -259,7 +259,7 @@ public:
float glow_intensity;
float glow_strength;
float glow_bloom;
- VS::EnvironmentGlowBlendMode glow_blend_mode;
+ RS::EnvironmentGlowBlendMode glow_blend_mode;
float glow_hdr_bleed_threshold;
float glow_hdr_bleed_scale;
float glow_hdr_luminance_cap;
@@ -269,13 +269,13 @@ public:
float dof_blur_far_distance;
float dof_blur_far_transition;
float dof_blur_far_amount;
- VS::EnvironmentDOFBlurQuality dof_blur_far_quality;
+ RS::EnvironmentDOFBlurQuality dof_blur_far_quality;
bool dof_blur_near_enabled;
float dof_blur_near_distance;
float dof_blur_near_transition;
float dof_blur_near_amount;
- VS::EnvironmentDOFBlurQuality dof_blur_near_quality;
+ RS::EnvironmentDOFBlurQuality dof_blur_near_quality;
bool adjustments_enabled;
float adjustments_brightness;
@@ -300,7 +300,7 @@ public:
float fog_height_curve;
Environment() :
- bg_mode(VS::ENV_BG_CLEAR_COLOR),
+ bg_mode(RS::ENV_BG_CLEAR_COLOR),
sky_custom_fov(0.0),
bg_energy(1.0),
sky_ambient(0),
@@ -313,7 +313,7 @@ public:
glow_intensity(0.8),
glow_strength(1.0),
glow_bloom(0.0),
- glow_blend_mode(VS::ENV_GLOW_BLEND_MODE_SOFTLIGHT),
+ glow_blend_mode(RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT),
glow_hdr_bleed_threshold(1.0),
glow_hdr_bleed_scale(2.0),
glow_hdr_luminance_cap(12.0),
@@ -322,12 +322,12 @@ public:
dof_blur_far_distance(10),
dof_blur_far_transition(5),
dof_blur_far_amount(0.1),
- dof_blur_far_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM),
+ dof_blur_far_quality(RS::ENV_DOF_BLUR_QUALITY_MEDIUM),
dof_blur_near_enabled(false),
dof_blur_near_distance(2),
dof_blur_near_transition(1),
dof_blur_near_amount(0.1),
- dof_blur_near_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM),
+ dof_blur_near_quality(RS::ENV_DOF_BLUR_QUALITY_MEDIUM),
adjustments_enabled(false),
adjustments_brightness(1.0),
adjustments_contrast(1.0),
@@ -353,7 +353,7 @@ public:
virtual RID environment_create();
- virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg);
+ virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg);
virtual void environment_set_sky(RID p_env, RID p_sky);
virtual void environment_set_sky_custom_fov(RID p_env, float p_scale);
virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation);
@@ -363,15 +363,15 @@ public:
virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0);
virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id);
- virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
- virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale);
+ virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality);
+ virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, RS::EnvironmentDOFBlurQuality p_quality);
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale);
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
- virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
- virtual void environment_set_tonemap(RID p_env, VS::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);
+ virtual void 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);
virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp);
@@ -381,7 +381,7 @@ public:
virtual bool is_environment(RID p_env);
- virtual VS::EnvironmentBG environment_get_background(RID p_env);
+ virtual RS::EnvironmentBG environment_get_background(RID p_env);
virtual int environment_get_canvas_max_layer(RID p_env);
/* LIGHT INSTANCE */
@@ -575,7 +575,7 @@ public:
_FORCE_INLINE_ Element *add_element() {
if (element_count + alpha_element_count >= max_elements)
- return NULL;
+ return nullptr;
elements[element_count] = &base_elements[element_count];
return elements[element_count++];
@@ -583,7 +583,7 @@ public:
_FORCE_INLINE_ Element *add_alpha_element() {
if (element_count + alpha_element_count >= max_elements) {
- return NULL;
+ return nullptr;
}
int idx = max_elements - alpha_element_count - 1;
@@ -650,7 +650,7 @@ public:
virtual bool free(RID p_rid);
virtual void set_scene_pass(uint64_t p_pass);
- virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw);
+ virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw);
void iteration();
void initialize();
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 55b1c7e560..b8c7815f6a 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -34,7 +34,7 @@
#include "core/project_settings.h"
#include "rasterizer_canvas_gles2.h"
#include "rasterizer_scene_gles2.h"
-#include "servers/visual/shader_language.h"
+#include "servers/rendering/shader_language.h"
GLuint RasterizerStorageGLES2::system_fbo = 0;
@@ -127,11 +127,11 @@ PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC glCompressedTexSubImage3DOES;
void RasterizerStorageGLES2::bind_quad_array() const {
glBindBuffer(GL_ARRAY_BUFFER, resources.quadie);
- glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
- glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
- glEnableVertexAttribArray(VS::ARRAY_VERTEX);
- glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
}
Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const {
@@ -549,15 +549,15 @@ RID RasterizerStorageGLES2::texture_create() {
return texture_owner.make_rid(texture);
}
-void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) {
+void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingServer::TextureType p_type, uint32_t p_flags) {
GLenum format;
GLenum internal_format;
GLenum type;
bool compressed = false;
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
- p_flags &= ~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video
+ if (p_flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ p_flags &= ~RS::TEXTURE_FLAG_MIPMAPS; // no mipies for video
}
Texture *texture = texture_owner.getornull(p_texture);
@@ -570,15 +570,15 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->type = p_type;
switch (p_type) {
- case VS::TEXTURE_TYPE_2D: {
+ case RS::TEXTURE_TYPE_2D: {
texture->target = GL_TEXTURE_2D;
texture->images.resize(1);
} break;
- case VS::TEXTURE_TYPE_CUBEMAP: {
+ case RS::TEXTURE_TYPE_CUBEMAP: {
texture->target = GL_TEXTURE_CUBE_MAP;
texture->images.resize(6);
} break;
- case VS::TEXTURE_TYPE_2D_ARRAY: {
+ case RS::TEXTURE_TYPE_2D_ARRAY: {
if (config.texture_array_supported) {
texture->target = GL_TEXTURE_2D_ARRAY;
texture->images.resize(p_depth_3d);
@@ -587,7 +587,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
return;
}
} break;
- case VS::TEXTURE_TYPE_3D: {
+ case RS::TEXTURE_TYPE_3D: {
if (config.texture_3d_supported) {
texture->target = GL_TEXTURE_3D;
texture->images.resize(p_depth_3d);
@@ -611,12 +611,12 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
bool is_po2 = p_width == po2_width && p_height == po2_height;
- if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) {
+ if (!is_po2 && (p_flags & RS::TEXTURE_FLAG_REPEAT || p_flags & RS::TEXTURE_FLAG_MIPMAPS)) {
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ if (p_flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) {
//not supported
ERR_PRINT("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled.");
- texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS);
+ texture->flags &= ~(RS::TEXTURE_FLAG_REPEAT | RS::TEXTURE_FLAG_MIPMAPS);
} else {
texture->alloc_height = po2_height;
texture->alloc_width = po2_width;
@@ -640,7 +640,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
glBindTexture(texture->target, texture->tex_id);
#if defined(GLES_OVER_GL) || defined(ANDROID_ENABLED)
- if ((p_type == VS::TEXTURE_TYPE_3D && config.texture_3d_supported) || (p_type == VS::TEXTURE_TYPE_2D_ARRAY && config.texture_array_supported)) {
+ if ((p_type == RS::TEXTURE_TYPE_3D && config.texture_3d_supported) || (p_type == RS::TEXTURE_TYPE_2D_ARRAY && config.texture_array_supported)) {
int width = p_width;
int height = p_height;
@@ -648,23 +648,23 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
int mipmaps = 0;
- while (width > 0 || height > 0 || (p_type == VS::TEXTURE_TYPE_3D && depth > 0)) {
+ while (width > 0 || height > 0 || (p_type == RS::TEXTURE_TYPE_3D && depth > 0)) {
width = MAX(1, width);
height = MAX(1, height);
depth = MAX(1, depth);
- glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, NULL);
+ glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, nullptr);
width /= 2;
height /= 2;
- if (p_type == VS::TEXTURE_TYPE_3D) {
+ if (p_type == RS::TEXTURE_TYPE_3D) {
depth /= 2;
}
mipmaps++;
- if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS))
+ if (!(p_flags & RS::TEXTURE_FLAG_MIPMAPS))
break;
}
#ifdef GLES_OVER_GL
@@ -674,9 +674,9 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
} else
#endif
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ if (p_flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) {
//prealloc if video
- glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL);
+ glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, nullptr);
}
texture->active = true;
@@ -686,7 +686,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
- if ((texture->type == VS::TEXTURE_TYPE_2D_ARRAY && !config.texture_array_supported) || (texture->type == VS::TEXTURE_TYPE_3D && !config.texture_3d_supported)) {
+ if ((texture->type == RS::TEXTURE_TYPE_2D_ARRAY && !config.texture_array_supported) || (texture->type == RS::TEXTURE_TYPE_3D && !config.texture_3d_supported)) {
return;
}
ERR_FAIL_COND(!texture->active);
@@ -699,7 +699,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
GLenum internal_format;
bool compressed = false;
- if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
+ if (config.keep_original_textures && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
texture->images.write[p_layer] = p_image;
}
@@ -717,7 +717,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
img->resize_to_po2(false);
}
- if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
+ if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
texture->alloc_height = MAX(1, texture->alloc_height / 2);
texture->alloc_width = MAX(1, texture->alloc_width / 2);
@@ -734,17 +734,17 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
GLenum blit_target = GL_TEXTURE_2D;
switch (texture->type) {
- case VS::TEXTURE_TYPE_2D: {
+ case RS::TEXTURE_TYPE_2D: {
blit_target = GL_TEXTURE_2D;
} break;
- case VS::TEXTURE_TYPE_CUBEMAP: {
+ case RS::TEXTURE_TYPE_CUBEMAP: {
ERR_FAIL_INDEX(p_layer, 6);
blit_target = _cube_side_enum[p_layer];
} break;
- case VS::TEXTURE_TYPE_2D_ARRAY: {
+ case RS::TEXTURE_TYPE_2D_ARRAY: {
blit_target = GL_TEXTURE_2D_ARRAY;
} break;
- case VS::TEXTURE_TYPE_3D: {
+ case RS::TEXTURE_TYPE_3D: {
blit_target = GL_TEXTURE_3D;
} break;
}
@@ -758,17 +758,17 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
texture->ignore_mipmaps = compressed && !img->has_mipmaps();
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps)
+ if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps)
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR);
else {
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering
@@ -777,9 +777,9 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering
}
- if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
+ if (((texture->flags & RS::TEXTURE_FLAG_REPEAT) || (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
- if (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) {
+ if (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
} else {
@@ -793,7 +793,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
- int mipmaps = ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1;
+ int mipmaps = ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1;
int w = img->get_width();
int h = img->get_height();
@@ -804,7 +804,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
int size, ofs;
img->get_mipmap_offset_and_size(i, ofs, size);
- if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) {
+ if (texture->type == RS::TEXTURE_TYPE_2D || texture->type == RS::TEXTURE_TYPE_CUBEMAP) {
if (compressed) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
@@ -816,7 +816,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ if (texture->flags & RS::TEXTURE_FLAG_USED_FOR_STREAMING) {
glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
} else {
glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
@@ -854,7 +854,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
texture->stored_cube_sides |= (1 << p_layer);
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
+ if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture->target);
}
@@ -875,7 +875,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
ERR_FAIL_COND_V(!texture->active, Ref<Image>());
ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>());
- if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) {
+ if (texture->type == RS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) {
return texture->images[p_layer];
}
@@ -946,7 +946,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer)
glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
glBindTexture(GL_TEXTURE_2D, temp_color_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -997,16 +997,16 @@ void RasterizerStorageGLES2::texture_set_flags(RID p_texture, uint32_t p_flags)
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
- bool had_mipmaps = texture->flags & VS::TEXTURE_FLAG_MIPMAPS;
+ bool had_mipmaps = texture->flags & RS::TEXTURE_FLAG_MIPMAPS;
texture->flags = p_flags;
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
+ if (((texture->flags & RS::TEXTURE_FLAG_REPEAT) || (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
- if (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) {
+ if (texture->flags & RS::TEXTURE_FLAG_MIRRORED_REPEAT) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
} else {
@@ -1019,21 +1019,21 @@ void RasterizerStorageGLES2::texture_set_flags(RID p_texture, uint32_t p_flags)
glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) {
+ if ((texture->flags & RS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) {
if (!had_mipmaps && texture->mipmaps == 1) {
glGenerateMipmap(texture->target);
}
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR);
} else {
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering
@@ -1059,10 +1059,10 @@ Image::Format RasterizerStorageGLES2::texture_get_format(RID p_texture) const {
return texture->format;
}
-VisualServer::TextureType RasterizerStorageGLES2::texture_get_type(RID p_texture) const {
+RenderingServer::TextureType RasterizerStorageGLES2::texture_get_type(RID p_texture) const {
Texture *texture = texture_owner.getornull(p_texture);
- ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D);
+ ERR_FAIL_COND_V(!texture, RS::TEXTURE_TYPE_2D);
return texture->type;
}
@@ -1135,7 +1135,7 @@ String RasterizerStorageGLES2::texture_get_path(RID p_texture) const {
return texture->path;
}
-void RasterizerStorageGLES2::texture_debug_usage(List<VS::TextureInfo> *r_info) {
+void RasterizerStorageGLES2::texture_debug_usage(List<RS::TextureInfo> *r_info) {
List<RID> textures;
texture_owner.get_owned_list(&textures);
@@ -1144,7 +1144,7 @@ void RasterizerStorageGLES2::texture_debug_usage(List<VS::TextureInfo> *r_info)
Texture *t = texture_owner.getornull(E->get());
if (!t)
continue;
- VS::TextureInfo tinfo;
+ RS::TextureInfo tinfo;
tinfo.path = t->path;
tinfo.format = t->format;
tinfo.width = t->alloc_width;
@@ -1180,7 +1180,7 @@ void RasterizerStorageGLES2::texture_set_proxy(RID p_texture, RID p_proxy) {
if (texture->proxy) {
texture->proxy->proxy_owners.erase(texture);
- texture->proxy = NULL;
+ texture->proxy = nullptr;
}
if (p_proxy.is_valid()) {
@@ -1200,7 +1200,7 @@ void RasterizerStorageGLES2::texture_set_force_redraw_if_visible(RID p_texture,
texture->redraw_if_visible = p_enable;
}
-void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {
+void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -1208,7 +1208,7 @@ void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, Visua
texture->detect_3d_ud = p_userdata;
}
-void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {
+void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -1216,7 +1216,7 @@ void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, Vis
texture->detect_srgb_ud = p_userdata;
}
-void RasterizerStorageGLES2::texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {
+void RasterizerStorageGLES2::texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -1265,7 +1265,7 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
- for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX - 1; i++) {
glDisableVertexAttribArray(i);
}
}
@@ -1301,7 +1301,7 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
// Mobile hardware (PowerVR specially) prefers this approach,
// the previous approach with manual lod levels kills the game.
for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, nullptr);
}
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
@@ -1330,7 +1330,7 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
//make framebuffer size the texture size, need to use a separate texture for compatibility
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0);
if (lod == 1) {
@@ -1397,7 +1397,7 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
RID RasterizerStorageGLES2::shader_create() {
Shader *shader = memnew(Shader);
- shader->mode = VS::SHADER_SPATIAL;
+ shader->mode = RS::SHADER_SPATIAL;
shader->shader = &scene->state.scene_shader;
RID rid = shader_owner.make_rid(shader);
_shader_make_dirty(shader);
@@ -1421,14 +1421,16 @@ void RasterizerStorageGLES2::shader_set_code(RID p_shader, const String &p_code)
shader->code = p_code;
String mode_string = ShaderLanguage::get_shader_type(p_code);
- VS::ShaderMode mode;
+ RS::ShaderMode mode;
if (mode_string == "canvas_item")
- mode = VS::SHADER_CANVAS_ITEM;
+ mode = RS::SHADER_CANVAS_ITEM;
else if (mode_string == "particles")
- mode = VS::SHADER_PARTICLES;
+ mode = RS::SHADER_PARTICLES;
+ else if (mode_string == "sky")
+ mode = RS::SHADER_SKY;
else
- mode = VS::SHADER_SPATIAL;
+ mode = RS::SHADER_SPATIAL;
if (shader->custom_code_id && mode != shader->mode) {
shader->shader->free_custom_shader(shader->custom_code_id);
@@ -1438,10 +1440,10 @@ void RasterizerStorageGLES2::shader_set_code(RID p_shader, const String &p_code)
shader->mode = mode;
// TODO handle all shader types
- if (mode == VS::SHADER_CANVAS_ITEM) {
+ if (mode == RS::SHADER_CANVAS_ITEM) {
shader->shader = &canvas->state.canvas_shader;
- } else if (mode == VS::SHADER_SPATIAL) {
+ } else if (mode == RS::SHADER_SPATIAL) {
shader->shader = &scene->state.scene_shader;
} else {
return;
@@ -1475,11 +1477,11 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
}
ShaderCompilerGLES2::GeneratedCode gen_code;
- ShaderCompilerGLES2::IdentifierActions *actions = NULL;
+ ShaderCompilerGLES2::IdentifierActions *actions = nullptr;
switch (p_shader->mode) {
- case VS::SHADER_CANVAS_ITEM: {
+ case RS::SHADER_CANVAS_ITEM: {
p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL;
p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX;
@@ -1506,7 +1508,7 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
actions->uniforms = &p_shader->uniforms;
} break;
- case VS::SHADER_SPATIAL: {
+ case RS::SHADER_SPATIAL: {
p_shader->spatial.blend_mode = Shader::Spatial::BLEND_MODE_MIX;
p_shader->spatial.depth_draw_mode = Shader::Spatial::DEPTH_DRAW_OPAQUE;
p_shader->spatial.cull_mode = Shader::Spatial::CULL_MODE_BACK;
@@ -1947,8 +1949,8 @@ void RasterizerStorageGLES2::material_remove_instance_owner(RID p_material, Rast
}
void RasterizerStorageGLES2::material_set_render_priority(RID p_material, int priority) {
- ERR_FAIL_COND(priority < VS::MATERIAL_RENDER_PRIORITY_MIN);
- ERR_FAIL_COND(priority > VS::MATERIAL_RENDER_PRIORITY_MAX);
+ ERR_FAIL_COND(priority < RS::MATERIAL_RENDER_PRIORITY_MIN);
+ ERR_FAIL_COND(priority > RS::MATERIAL_RENDER_PRIORITY_MAX);
Material *material = material_owner.getornull(p_material);
ERR_FAIL_COND(!material);
@@ -1973,7 +1975,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) {
bool can_cast_shadow = false;
bool is_animated = false;
- if (p_material->shader && p_material->shader->mode == VS::SHADER_SPATIAL) {
+ if (p_material->shader && p_material->shader->mode == RS::SHADER_SPATIAL) {
if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX &&
(!p_material->shader->spatial.uses_alpha || p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) {
@@ -2085,14 +2087,14 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
uint32_t p_format = format;
- static int src_size[VS::ARRAY_MAX];
- static int dst_size[VS::ARRAY_MAX];
- static int to_convert[VS::ARRAY_MAX];
+ static int src_size[RS::ARRAY_MAX];
+ static int dst_size[RS::ARRAY_MAX];
+ static int to_convert[RS::ARRAY_MAX];
int src_stride = 0;
int dst_stride = 0;
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
to_convert[i] = 0;
if (!(p_format & (1 << i))) {
@@ -2103,11 +2105,11 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
switch (i) {
- case VS::ARRAY_VERTEX: {
+ case RS::ARRAY_VERTEX: {
- if (p_format & VS::ARRAY_COMPRESS_VERTEX) {
+ if (p_format & RS::ARRAY_COMPRESS_VERTEX) {
- if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
src_size[i] = 4;
dst_size[i] = 8;
to_convert[i] = 2;
@@ -2117,10 +2119,10 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
to_convert[i] = 3;
}
- format &= ~VS::ARRAY_COMPRESS_VERTEX;
+ format &= ~RS::ARRAY_COMPRESS_VERTEX;
} else {
- if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
src_size[i] = 8;
dst_size[i] = 8;
} else {
@@ -2130,9 +2132,9 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
}
} break;
- case VS::ARRAY_NORMAL: {
+ case RS::ARRAY_NORMAL: {
- if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
+ if (p_format & RS::ARRAY_COMPRESS_NORMAL) {
src_size[i] = 4;
dst_size[i] = 4;
} else {
@@ -2141,9 +2143,9 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
}
} break;
- case VS::ARRAY_TANGENT: {
+ case RS::ARRAY_TANGENT: {
- if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
+ if (p_format & RS::ARRAY_COMPRESS_TANGENT) {
src_size[i] = 4;
dst_size[i] = 4;
} else {
@@ -2152,9 +2154,9 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
}
} break;
- case VS::ARRAY_COLOR: {
+ case RS::ARRAY_COLOR: {
- if (p_format & VS::ARRAY_COMPRESS_COLOR) {
+ if (p_format & RS::ARRAY_COMPRESS_COLOR) {
src_size[i] = 4;
dst_size[i] = 4;
} else {
@@ -2163,12 +2165,12 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
}
} break;
- case VS::ARRAY_TEX_UV: {
+ case RS::ARRAY_TEX_UV: {
- if (p_format & VS::ARRAY_COMPRESS_TEX_UV) {
+ if (p_format & RS::ARRAY_COMPRESS_TEX_UV) {
src_size[i] = 4;
to_convert[i] = 2;
- format &= ~VS::ARRAY_COMPRESS_TEX_UV;
+ format &= ~RS::ARRAY_COMPRESS_TEX_UV;
} else {
src_size[i] = 8;
}
@@ -2176,12 +2178,12 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
dst_size[i] = 8;
} break;
- case VS::ARRAY_TEX_UV2: {
+ case RS::ARRAY_TEX_UV2: {
- if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) {
+ if (p_format & RS::ARRAY_COMPRESS_TEX_UV2) {
src_size[i] = 4;
to_convert[i] = 2;
- format &= ~VS::ARRAY_COMPRESS_TEX_UV2;
+ format &= ~RS::ARRAY_COMPRESS_TEX_UV2;
} else {
src_size[i] = 8;
}
@@ -2189,9 +2191,9 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
dst_size[i] = 8;
} break;
- case VS::ARRAY_BONES: {
+ case RS::ARRAY_BONES: {
- if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) {
+ if (p_format & RS::ARRAY_FLAG_USE_16_BIT_BONES) {
src_size[i] = 8;
dst_size[i] = 8;
} else {
@@ -2200,9 +2202,9 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
}
} break;
- case VS::ARRAY_WEIGHTS: {
+ case RS::ARRAY_WEIGHTS: {
- if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) {
+ if (p_format & RS::ARRAY_COMPRESS_WEIGHTS) {
src_size[i] = 8;
dst_size[i] = 8;
} else {
@@ -2211,7 +2213,7 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
}
} break;
- case VS::ARRAY_INDEX: {
+ case RS::ARRAY_INDEX: {
src_size[i] = 0;
dst_size[i] = 0;
@@ -2232,7 +2234,7 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
int src_offset = 0;
int dst_offset = 0;
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
if (src_size[i] == 0) {
continue; //no go
@@ -2270,27 +2272,27 @@ static Vector<uint8_t> _unpack_half_floats(const Vector<uint8_t> &array, uint32_
return ret;
}
-void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS::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, const Vector<AABB> &p_bone_aabbs) {
+void RasterizerStorageGLES2::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, const Vector<AABB> &p_bone_aabbs) {
Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!mesh);
- ERR_FAIL_COND(!(p_format & VS::ARRAY_FORMAT_VERTEX));
+ ERR_FAIL_COND(!(p_format & RS::ARRAY_FORMAT_VERTEX));
//must have index and bones, both.
{
- uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS;
+ uint32_t bones_weight = RS::ARRAY_FORMAT_BONES | RS::ARRAY_FORMAT_WEIGHTS;
ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none.");
}
//bool has_morph = p_blend_shapes.size();
- Surface::Attrib attribs[VS::ARRAY_MAX];
+ Surface::Attrib attribs[RS::ARRAY_MAX];
int stride = 0;
bool uses_half_float = false;
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
attribs[i].index = i;
@@ -2306,15 +2308,15 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
switch (i) {
- case VS::ARRAY_VERTEX: {
+ case RS::ARRAY_VERTEX: {
- if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
attribs[i].size = 2;
} else {
- attribs[i].size = (p_format & VS::ARRAY_COMPRESS_VERTEX) ? 4 : 3;
+ attribs[i].size = (p_format & RS::ARRAY_COMPRESS_VERTEX) ? 4 : 3;
}
- if (p_format & VS::ARRAY_COMPRESS_VERTEX) {
+ if (p_format & RS::ARRAY_COMPRESS_VERTEX) {
attribs[i].type = _GL_HALF_FLOAT_OES;
stride += attribs[i].size * 2;
uses_half_float = true;
@@ -2326,11 +2328,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
attribs[i].normalized = GL_FALSE;
} break;
- case VS::ARRAY_NORMAL: {
+ case RS::ARRAY_NORMAL: {
attribs[i].size = 3;
- if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
+ if (p_format & RS::ARRAY_COMPRESS_NORMAL) {
attribs[i].type = GL_BYTE;
stride += 4; //pad extra byte
attribs[i].normalized = GL_TRUE;
@@ -2341,11 +2343,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
} break;
- case VS::ARRAY_TANGENT: {
+ case RS::ARRAY_TANGENT: {
attribs[i].size = 4;
- if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
+ if (p_format & RS::ARRAY_COMPRESS_TANGENT) {
attribs[i].type = GL_BYTE;
stride += 4;
attribs[i].normalized = GL_TRUE;
@@ -2356,11 +2358,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
} break;
- case VS::ARRAY_COLOR: {
+ case RS::ARRAY_COLOR: {
attribs[i].size = 4;
- if (p_format & VS::ARRAY_COMPRESS_COLOR) {
+ if (p_format & RS::ARRAY_COMPRESS_COLOR) {
attribs[i].type = GL_UNSIGNED_BYTE;
stride += 4;
attribs[i].normalized = GL_TRUE;
@@ -2371,11 +2373,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
} break;
- case VS::ARRAY_TEX_UV: {
+ case RS::ARRAY_TEX_UV: {
attribs[i].size = 2;
- if (p_format & VS::ARRAY_COMPRESS_TEX_UV) {
+ if (p_format & RS::ARRAY_COMPRESS_TEX_UV) {
attribs[i].type = _GL_HALF_FLOAT_OES;
stride += 4;
uses_half_float = true;
@@ -2387,11 +2389,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
attribs[i].normalized = GL_FALSE;
} break;
- case VS::ARRAY_TEX_UV2: {
+ case RS::ARRAY_TEX_UV2: {
attribs[i].size = 2;
- if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) {
+ if (p_format & RS::ARRAY_COMPRESS_TEX_UV2) {
attribs[i].type = _GL_HALF_FLOAT_OES;
stride += 4;
uses_half_float = true;
@@ -2402,11 +2404,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
attribs[i].normalized = GL_FALSE;
} break;
- case VS::ARRAY_BONES: {
+ case RS::ARRAY_BONES: {
attribs[i].size = 4;
- if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) {
+ if (p_format & RS::ARRAY_FLAG_USE_16_BIT_BONES) {
attribs[i].type = GL_UNSIGNED_SHORT;
stride += 8;
} else {
@@ -2418,11 +2420,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
attribs[i].integer = true;
} break;
- case VS::ARRAY_WEIGHTS: {
+ case RS::ARRAY_WEIGHTS: {
attribs[i].size = 4;
- if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) {
+ if (p_format & RS::ARRAY_COMPRESS_WEIGHTS) {
attribs[i].type = GL_UNSIGNED_SHORT;
stride += 8;
@@ -2434,7 +2436,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
} break;
- case VS::ARRAY_INDEX: {
+ case RS::ARRAY_INDEX: {
attribs[i].size = 1;
@@ -2452,7 +2454,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
}
}
- for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX - 1; i++) {
attribs[i].stride = stride;
}
@@ -2498,9 +2500,9 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
return; //do not go any further, above function used unpacked stuff will be used instead.
}
- if (p_format & VS::ARRAY_FORMAT_INDEX) {
+ if (p_format & RS::ARRAY_FORMAT_INDEX) {
- index_array_size = attribs[VS::ARRAY_INDEX].stride * p_index_count;
+ index_array_size = attribs[RS::ARRAY_INDEX].stride * p_index_count;
}
ERR_FAIL_COND(p_index_array.size() != index_array_size);
@@ -2543,7 +2545,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
surface->skeleton_bone_used.write[i] = !(surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0);
}
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
surface->attribs[i] = attribs[i];
}
@@ -2553,11 +2555,11 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
glGenBuffers(1, &surface->vertex_id);
glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id);
- glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), (p_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), (p_format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
- if (p_format & VS::ARRAY_FORMAT_INDEX) {
+ if (p_format & RS::ARRAY_FORMAT_INDEX) {
const uint8_t *ir = p_index_array.ptr();
glGenBuffers(1, &surface->index_id);
@@ -2614,16 +2616,16 @@ int RasterizerStorageGLES2::mesh_get_blend_shape_count(RID p_mesh) const {
return mesh->blend_shape_count;
}
-void RasterizerStorageGLES2::mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) {
+void RasterizerStorageGLES2::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND(!mesh);
mesh->blend_shape_mode = p_mode;
}
-VS::BlendShapeMode RasterizerStorageGLES2::mesh_get_blend_shape_mode(RID p_mesh) const {
+RS::BlendShapeMode RasterizerStorageGLES2::mesh_get_blend_shape_mode(RID p_mesh) const {
const Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, VS::BLEND_SHAPE_MODE_NORMALIZED);
+ ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
return mesh->blend_shape_mode;
}
@@ -2721,10 +2723,10 @@ uint32_t RasterizerStorageGLES2::mesh_surface_get_format(RID p_mesh, int p_surfa
return mesh->surfaces[p_surface]->format;
}
-VS::PrimitiveType RasterizerStorageGLES2::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
+RS::PrimitiveType RasterizerStorageGLES2::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
const Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, VS::PRIMITIVE_MAX);
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_MAX);
+ ERR_FAIL_COND_V(!mesh, RS::PRIMITIVE_MAX);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RS::PRIMITIVE_MAX);
return mesh->surfaces[p_surface]->primitive;
}
@@ -2737,10 +2739,10 @@ AABB RasterizerStorageGLES2::mesh_surface_get_aabb(RID p_mesh, int p_surface) co
return mesh->surfaces[p_surface]->aabb;
}
-Vector<Vector<uint8_t> > RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const {
+Vector<Vector<uint8_t>> RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const {
const Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, Vector<Vector<uint8_t> >());
- ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<Vector<uint8_t> >());
+ ERR_FAIL_COND_V(!mesh, Vector<Vector<uint8_t>>());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<Vector<uint8_t>>());
#ifndef TOOLS_ENABLED
ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data");
#endif
@@ -2813,7 +2815,7 @@ AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const {
if (mesh->custom_aabb != AABB())
return mesh->custom_aabb;
- Skeleton *sk = NULL;
+ Skeleton *sk = nullptr;
if (p_skeleton.is_valid()) {
sk = skeleton_owner.getornull(p_skeleton);
}
@@ -2825,7 +2827,7 @@ AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const {
for (int i = 0; i < mesh->surfaces.size(); i++) {
AABB laabb;
- if ((mesh->surfaces[i]->format & VS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->skeleton_bone_aabb.size()) {
+ if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->skeleton_bone_aabb.size()) {
int bs = mesh->surfaces[i]->skeleton_bone_aabb.size();
const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr();
@@ -2937,7 +2939,7 @@ RID RasterizerStorageGLES2::multimesh_create() {
return multimesh_owner.make_rid(multimesh);
}
-void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data) {
+void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, RS::MultimeshColorFormat p_color_format, RS::MultimeshCustomDataFormat p_data) {
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
@@ -2955,23 +2957,23 @@ void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances
multimesh->data.resize(0);
}
- if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) {
+ if (multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D) {
multimesh->xform_floats = 8;
} else {
multimesh->xform_floats = 12;
}
- if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) {
multimesh->color_floats = 1;
- } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) {
multimesh->color_floats = 4;
} else {
multimesh->color_floats = 0;
}
- if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) {
multimesh->custom_data_floats = 1;
- } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) {
multimesh->custom_data_floats = 4;
} else {
multimesh->custom_data_floats = 0;
@@ -2985,7 +2987,7 @@ void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances
int color_from = 0;
int custom_data_from = 0;
- if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) {
+ if (multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D) {
multimesh->data.write[i + 0] = 1.0;
multimesh->data.write[i + 1] = 0.0;
multimesh->data.write[i + 2] = 0.0;
@@ -3013,7 +3015,7 @@ void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances
custom_data_from = 12;
}
- if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) {
union {
uint32_t colu;
float colf;
@@ -3022,7 +3024,7 @@ void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances
cu.colu = 0xFFFFFFFF;
multimesh->data.write[i + color_from + 0] = cu.colf;
custom_data_from = color_from + 1;
- } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) {
multimesh->data.write[i + color_from + 0] = 1.0;
multimesh->data.write[i + color_from + 1] = 1.0;
multimesh->data.write[i + color_from + 2] = 1.0;
@@ -3030,7 +3032,7 @@ void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances
custom_data_from = color_from + 4;
}
- if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) {
union {
uint32_t colu;
float colf;
@@ -3038,7 +3040,7 @@ void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances
cu.colu = 0;
multimesh->data.write[i + custom_data_from + 0] = cu.colf;
- } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) {
multimesh->data.write[i + custom_data_from + 0] = 0.0;
multimesh->data.write[i + custom_data_from + 1] = 0.0;
multimesh->data.write[i + custom_data_from + 2] = 0.0;
@@ -3092,7 +3094,7 @@ void RasterizerStorageGLES2::multimesh_instance_set_transform(RID p_multimesh, i
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->size);
- ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D);
+ ERR_FAIL_COND(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D);
int stride = multimesh->color_floats + multimesh->custom_data_floats + multimesh->xform_floats;
@@ -3123,7 +3125,7 @@ void RasterizerStorageGLES2::multimesh_instance_set_transform_2d(RID p_multimesh
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->size);
- ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D);
+ ERR_FAIL_COND(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_3D);
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index];
@@ -3149,13 +3151,13 @@ void RasterizerStorageGLES2::multimesh_instance_set_color(RID p_multimesh, int p
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->size);
- ERR_FAIL_COND(multimesh->color_format == VS::MULTIMESH_COLOR_NONE);
- ERR_FAIL_INDEX(multimesh->color_format, VS::MULTIMESH_COLOR_MAX);
+ ERR_FAIL_COND(multimesh->color_format == RS::MULTIMESH_COLOR_NONE);
+ ERR_FAIL_INDEX(multimesh->color_format, RS::MULTIMESH_COLOR_MAX);
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats];
- if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) {
uint8_t *data8 = (uint8_t *)dataptr;
data8[0] = CLAMP(p_color.r * 255.0, 0, 255);
@@ -3163,7 +3165,7 @@ void RasterizerStorageGLES2::multimesh_instance_set_color(RID p_multimesh, int p
data8[2] = CLAMP(p_color.b * 255.0, 0, 255);
data8[3] = CLAMP(p_color.a * 255.0, 0, 255);
- } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) {
dataptr[0] = p_color.r;
dataptr[1] = p_color.g;
dataptr[2] = p_color.b;
@@ -3182,13 +3184,13 @@ void RasterizerStorageGLES2::multimesh_instance_set_custom_data(RID p_multimesh,
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
ERR_FAIL_INDEX(p_index, multimesh->size);
- ERR_FAIL_COND(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE);
- ERR_FAIL_INDEX(multimesh->custom_data_format, VS::MULTIMESH_CUSTOM_DATA_MAX);
+ ERR_FAIL_COND(multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_NONE);
+ ERR_FAIL_INDEX(multimesh->custom_data_format, RS::MULTIMESH_CUSTOM_DATA_MAX);
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats];
- if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) {
uint8_t *data8 = (uint8_t *)dataptr;
data8[0] = CLAMP(p_custom_data.r * 255.0, 0, 255);
@@ -3196,7 +3198,7 @@ void RasterizerStorageGLES2::multimesh_instance_set_custom_data(RID p_multimesh,
data8[2] = CLAMP(p_custom_data.b * 255.0, 0, 255);
data8[3] = CLAMP(p_custom_data.a * 255.0, 0, 255);
- } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) {
dataptr[0] = p_custom_data.r;
dataptr[1] = p_custom_data.g;
dataptr[2] = p_custom_data.b;
@@ -3222,7 +3224,7 @@ Transform RasterizerStorageGLES2::multimesh_instance_get_transform(RID p_multime
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Transform());
ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform());
- ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D, Transform());
+ ERR_FAIL_COND_V(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D, Transform());
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index];
@@ -3249,7 +3251,7 @@ Transform2D RasterizerStorageGLES2::multimesh_instance_get_transform_2d(RID p_mu
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Transform2D());
ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform2D());
- ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D, Transform2D());
+ ERR_FAIL_COND_V(multimesh->transform_format == RS::MULTIMESH_TRANSFORM_3D, Transform2D());
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index];
@@ -3270,13 +3272,13 @@ Color RasterizerStorageGLES2::multimesh_instance_get_color(RID p_multimesh, int
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
- ERR_FAIL_COND_V(multimesh->color_format == VS::MULTIMESH_COLOR_NONE, Color());
- ERR_FAIL_INDEX_V(multimesh->color_format, VS::MULTIMESH_COLOR_MAX, Color());
+ ERR_FAIL_COND_V(multimesh->color_format == RS::MULTIMESH_COLOR_NONE, Color());
+ ERR_FAIL_INDEX_V(multimesh->color_format, RS::MULTIMESH_COLOR_MAX, Color());
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats];
- if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ if (multimesh->color_format == RS::MULTIMESH_COLOR_8BIT) {
union {
uint32_t colu;
float colf;
@@ -3286,7 +3288,7 @@ Color RasterizerStorageGLES2::multimesh_instance_get_color(RID p_multimesh, int
return Color::hex(BSWAP32(cu.colu));
- } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ } else if (multimesh->color_format == RS::MULTIMESH_COLOR_FLOAT) {
Color c;
c.r = dataptr[0];
c.g = dataptr[1];
@@ -3303,13 +3305,13 @@ Color RasterizerStorageGLES2::multimesh_instance_get_custom_data(RID p_multimesh
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
- ERR_FAIL_COND_V(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE, Color());
- ERR_FAIL_INDEX_V(multimesh->custom_data_format, VS::MULTIMESH_CUSTOM_DATA_MAX, Color());
+ ERR_FAIL_COND_V(multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_NONE, Color());
+ ERR_FAIL_INDEX_V(multimesh->custom_data_format, RS::MULTIMESH_CUSTOM_DATA_MAX, Color());
int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats];
- if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) {
union {
uint32_t colu;
float colf;
@@ -3319,7 +3321,7 @@ Color RasterizerStorageGLES2::multimesh_instance_get_custom_data(RID p_multimesh
return Color::hex(BSWAP32(cu.colu));
- } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ } else if (multimesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_FLOAT) {
Color c;
c.r = dataptr[0];
c.g = dataptr[1];
@@ -3398,7 +3400,7 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() {
AABB aabb;
- if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) {
+ if (multimesh->transform_format == RS::MULTIMESH_TRANSFORM_2D) {
for (int i = 0; i < count; i += stride) {
@@ -3470,7 +3472,7 @@ RID RasterizerStorageGLES2::immediate_create() {
return immediate_owner.make_rid(im);
}
-void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture) {
+void RasterizerStorageGLES2::immediate_begin(RID p_immediate, RS::PrimitiveType p_primitive, RID p_texture) {
Immediate *im = immediate_owner.getornull(p_immediate);
ERR_FAIL_COND(!im);
ERR_FAIL_COND(im->building);
@@ -3497,17 +3499,17 @@ void RasterizerStorageGLES2::immediate_vertex(RID p_immediate, const Vector3 &p_
im->aabb.expand_to(p_vertex);
}
- if (im->mask & VS::ARRAY_FORMAT_NORMAL)
+ if (im->mask & RS::ARRAY_FORMAT_NORMAL)
c->normals.push_back(chunk_normal);
- if (im->mask & VS::ARRAY_FORMAT_TANGENT)
+ if (im->mask & RS::ARRAY_FORMAT_TANGENT)
c->tangents.push_back(chunk_tangent);
- if (im->mask & VS::ARRAY_FORMAT_COLOR)
+ if (im->mask & RS::ARRAY_FORMAT_COLOR)
c->colors.push_back(chunk_color);
- if (im->mask & VS::ARRAY_FORMAT_TEX_UV)
+ if (im->mask & RS::ARRAY_FORMAT_TEX_UV)
c->uvs.push_back(chunk_uv);
- if (im->mask & VS::ARRAY_FORMAT_TEX_UV2)
+ if (im->mask & RS::ARRAY_FORMAT_TEX_UV2)
c->uv2s.push_back(chunk_uv2);
- im->mask |= VS::ARRAY_FORMAT_VERTEX;
+ im->mask |= RS::ARRAY_FORMAT_VERTEX;
c->vertices.push_back(p_vertex);
}
@@ -3516,7 +3518,7 @@ void RasterizerStorageGLES2::immediate_normal(RID p_immediate, const Vector3 &p_
ERR_FAIL_COND(!im);
ERR_FAIL_COND(!im->building);
- im->mask |= VS::ARRAY_FORMAT_NORMAL;
+ im->mask |= RS::ARRAY_FORMAT_NORMAL;
chunk_normal = p_normal;
}
@@ -3525,7 +3527,7 @@ void RasterizerStorageGLES2::immediate_tangent(RID p_immediate, const Plane &p_t
ERR_FAIL_COND(!im);
ERR_FAIL_COND(!im->building);
- im->mask |= VS::ARRAY_FORMAT_TANGENT;
+ im->mask |= RS::ARRAY_FORMAT_TANGENT;
chunk_tangent = p_tangent;
}
@@ -3534,7 +3536,7 @@ void RasterizerStorageGLES2::immediate_color(RID p_immediate, const Color &p_col
ERR_FAIL_COND(!im);
ERR_FAIL_COND(!im->building);
- im->mask |= VS::ARRAY_FORMAT_COLOR;
+ im->mask |= RS::ARRAY_FORMAT_COLOR;
chunk_color = p_color;
}
@@ -3543,7 +3545,7 @@ void RasterizerStorageGLES2::immediate_uv(RID p_immediate, const Vector2 &tex_uv
ERR_FAIL_COND(!im);
ERR_FAIL_COND(!im->building);
- im->mask |= VS::ARRAY_FORMAT_TEX_UV;
+ im->mask |= RS::ARRAY_FORMAT_TEX_UV;
chunk_uv = tex_uv;
}
@@ -3552,7 +3554,7 @@ void RasterizerStorageGLES2::immediate_uv2(RID p_immediate, const Vector2 &tex_u
ERR_FAIL_COND(!im);
ERR_FAIL_COND(!im->building);
- im->mask |= VS::ARRAY_FORMAT_TEX_UV2;
+ im->mask |= RS::ARRAY_FORMAT_TEX_UV2;
chunk_uv2 = tex_uv;
}
@@ -3624,9 +3626,9 @@ void RasterizerStorageGLES2::skeleton_allocate(RID p_skeleton, int p_bones, bool
glBindTexture(GL_TEXTURE_2D, skeleton->tex_id);
#ifdef GLES_OVER_GL
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, nullptr);
#else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, nullptr);
#endif
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -3810,34 +3812,34 @@ void RasterizerStorageGLES2::update_dirty_skeletons() {
/* Light API */
-RID RasterizerStorageGLES2::light_create(VS::LightType p_type) {
+RID RasterizerStorageGLES2::light_create(RS::LightType p_type) {
Light *light = memnew(Light);
light->type = p_type;
- light->param[VS::LIGHT_PARAM_ENERGY] = 1.0;
- light->param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
- light->param[VS::LIGHT_PARAM_SPECULAR] = 0.5;
- light->param[VS::LIGHT_PARAM_RANGE] = 1.0;
- light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;
- light->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45;
- light->param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
- light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
- light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
- light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
- light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1;
- light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1;
+ light->param[RS::LIGHT_PARAM_ENERGY] = 1.0;
+ light->param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+ light->param[RS::LIGHT_PARAM_SPECULAR] = 0.5;
+ light->param[RS::LIGHT_PARAM_RANGE] = 1.0;
+ light->param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45;
+ light->param[RS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45;
+ light->param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
+ light->param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
+ light->param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
+ light->param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
+ light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1;
+ light->param[RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1;
light->color = Color(1, 1, 1, 1);
light->shadow = false;
light->negative = false;
light->cull_mask = 0xFFFFFFFF;
- light->directional_shadow_mode = VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
- light->omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
- light->omni_shadow_detail = VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
+ light->directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ light->omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ light->omni_shadow_detail = RS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
light->directional_blend_splits = false;
- light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
+ light->directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
light->reverse_cull = false;
light->use_gi = true;
light->version = 0;
@@ -3852,20 +3854,20 @@ void RasterizerStorageGLES2::light_set_color(RID p_light, const Color &p_color)
light->color = p_color;
}
-void RasterizerStorageGLES2::light_set_param(RID p_light, VS::LightParam p_param, float p_value) {
+void RasterizerStorageGLES2::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
- ERR_FAIL_INDEX(p_param, VS::LIGHT_PARAM_MAX);
+ ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
switch (p_param) {
- case VS::LIGHT_PARAM_RANGE:
- case VS::LIGHT_PARAM_SPOT_ANGLE:
- case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
- case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
- case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
- case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
- case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
- case VS::LIGHT_PARAM_SHADOW_BIAS: {
+ case RS::LIGHT_PARAM_RANGE:
+ case RS::LIGHT_PARAM_SPOT_ANGLE:
+ case RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
+ case RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
+ case RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
+ case RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
+ case RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
+ case RS::LIGHT_PARAM_SHADOW_BIAS: {
light->version++;
light->instance_change_notify(true, false);
} break;
@@ -3937,7 +3939,7 @@ void RasterizerStorageGLES2::light_set_use_gi(RID p_light, bool p_enabled) {
light->instance_change_notify(true, false);
}
-void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {
+void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
@@ -3947,14 +3949,14 @@ void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOm
light->instance_change_notify(true, false);
}
-VS::LightOmniShadowMode RasterizerStorageGLES2::light_omni_get_shadow_mode(RID p_light) {
+RS::LightOmniShadowMode RasterizerStorageGLES2::light_omni_get_shadow_mode(RID p_light) {
Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_OMNI_SHADOW_CUBE);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE);
return light->omni_shadow_mode;
}
-void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) {
+void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, RS::LightOmniShadowDetail p_detail) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
@@ -3964,7 +3966,7 @@ void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, VS::Light
light->instance_change_notify(true, false);
}
-void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) {
+void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
@@ -3990,37 +3992,37 @@ bool RasterizerStorageGLES2::light_directional_get_blend_splits(RID p_light) con
return light->directional_blend_splits;
}
-VS::LightDirectionalShadowMode RasterizerStorageGLES2::light_directional_get_shadow_mode(RID p_light) {
+RS::LightDirectionalShadowMode RasterizerStorageGLES2::light_directional_get_shadow_mode(RID p_light) {
Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
return light->directional_shadow_mode;
}
-void RasterizerStorageGLES2::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) {
+void RasterizerStorageGLES2::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND(!light);
light->directional_range_mode = p_range_mode;
}
-VS::LightDirectionalShadowDepthRangeMode RasterizerStorageGLES2::light_directional_get_shadow_depth_range_mode(RID p_light) const {
+RS::LightDirectionalShadowDepthRangeMode RasterizerStorageGLES2::light_directional_get_shadow_depth_range_mode(RID p_light) const {
Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
return light->directional_range_mode;
}
-VS::LightType RasterizerStorageGLES2::light_get_type(RID p_light) const {
+RS::LightType RasterizerStorageGLES2::light_get_type(RID p_light) const {
Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
return light->type;
}
-float RasterizerStorageGLES2::light_get_param(RID p_light, VS::LightParam p_param) {
+float RasterizerStorageGLES2::light_get_param(RID p_light, RS::LightParam p_param) {
Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND_V(!light, 0.0);
- ERR_FAIL_INDEX_V(p_param, VS::LIGHT_PARAM_MAX, 0.0);
+ ERR_FAIL_INDEX_V(p_param, RS::LIGHT_PARAM_MAX, 0.0);
return light->param[p_param];
}
@@ -4059,18 +4061,18 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const {
switch (light->type) {
- case VS::LIGHT_SPOT: {
- float len = light->param[VS::LIGHT_PARAM_RANGE];
- float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len;
+ case RS::LIGHT_SPOT: {
+ float len = light->param[RS::LIGHT_PARAM_RANGE];
+ float size = Math::tan(Math::deg2rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len;
return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
};
- case VS::LIGHT_OMNI: {
- float r = light->param[VS::LIGHT_PARAM_RANGE];
+ case RS::LIGHT_OMNI: {
+ float r = light->param[RS::LIGHT_PARAM_RANGE];
return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2);
};
- case VS::LIGHT_DIRECTIONAL: {
+ case RS::LIGHT_DIRECTIONAL: {
return AABB();
};
}
@@ -4095,13 +4097,13 @@ RID RasterizerStorageGLES2::reflection_probe_create() {
reflection_probe->box_projection = false;
reflection_probe->enable_shadows = false;
reflection_probe->cull_mask = (1 << 20) - 1;
- reflection_probe->update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE;
+ reflection_probe->update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE;
reflection_probe->resolution = 128;
return reflection_probe_owner.make_rid(reflection_probe);
}
-void RasterizerStorageGLES2::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) {
+void RasterizerStorageGLES2::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND(!reflection_probe);
@@ -4218,10 +4220,10 @@ AABB RasterizerStorageGLES2::reflection_probe_get_aabb(RID p_probe) const {
return aabb;
}
-VS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const {
+RS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS);
+ ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS);
return reflection_probe->update_mode;
}
@@ -4463,7 +4465,7 @@ float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const {
const Vector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
- ERR_FAIL_COND_V(!capture, NULL);
+ ERR_FAIL_COND_V(!capture, nullptr);
return &capture->octree;
}
@@ -4516,7 +4518,7 @@ void RasterizerStorageGLES2::particles_set_fractional_delta(RID p_particles, boo
void RasterizerStorageGLES2::particles_set_process_material(RID p_particles, RID p_material) {
}
-void RasterizerStorageGLES2::particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) {
+void RasterizerStorageGLES2::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
}
void RasterizerStorageGLES2::particles_set_draw_passes(RID p_particles, int p_passes) {
@@ -4577,37 +4579,37 @@ void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, Rasterizer
void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
- Instantiable *inst = NULL;
+ Instantiable *inst = nullptr;
switch (p_instance->base_type) {
- case VS::INSTANCE_MESH: {
+ case RS::INSTANCE_MESH: {
inst = mesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- case VS::INSTANCE_MULTIMESH: {
+ case RS::INSTANCE_MULTIMESH: {
inst = multimesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- case VS::INSTANCE_IMMEDIATE: {
+ case RS::INSTANCE_IMMEDIATE: {
inst = immediate_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- /*case VS::INSTANCE_PARTICLES: {
+ /*case RS::INSTANCE_PARTICLES: {
inst = particles_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;*/
- case VS::INSTANCE_REFLECTION_PROBE: {
+ case RS::INSTANCE_REFLECTION_PROBE: {
inst = reflection_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- case VS::INSTANCE_LIGHT: {
+ case RS::INSTANCE_LIGHT: {
inst = light_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- /*case VS::INSTANCE_GI_PROBE: {
+ /*case RS::INSTANCE_GI_PROBE: {
inst = gi_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;*/
- case VS::INSTANCE_LIGHTMAP_CAPTURE: {
+ case RS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
@@ -4621,38 +4623,38 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene
void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
- Instantiable *inst = NULL;
+ Instantiable *inst = nullptr;
switch (p_instance->base_type) {
- case VS::INSTANCE_MESH: {
+ case RS::INSTANCE_MESH: {
inst = mesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- case VS::INSTANCE_MULTIMESH: {
+ case RS::INSTANCE_MULTIMESH: {
inst = multimesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- case VS::INSTANCE_IMMEDIATE: {
+ case RS::INSTANCE_IMMEDIATE: {
inst = immediate_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- /*case VS::INSTANCE_PARTICLES: {
+ /*case RS::INSTANCE_PARTICLES: {
inst = particles_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;*/
- case VS::INSTANCE_REFLECTION_PROBE: {
+ case RS::INSTANCE_REFLECTION_PROBE: {
inst = reflection_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- case VS::INSTANCE_LIGHT: {
+ case RS::INSTANCE_LIGHT: {
inst = light_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
- /*case VS::INSTANCE_GI_PROBE: {
+ /*case RS::INSTANCE_GI_PROBE: {
inst = gi_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break; */
- case VS::INSTANCE_LIGHTMAP_CAPTURE: {
+ case RS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
@@ -4719,9 +4721,9 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glGenTextures(1, &rt->color);
glBindTexture(GL_TEXTURE_2D, rt->color);
- glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, nullptr);
- if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+ if (texture->flags & RS::TEXTURE_FLAG_FILTER) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -4742,7 +4744,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glGenTextures(1, &rt->depth);
glBindTexture(GL_TEXTURE_2D, rt->depth);
- glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -4803,7 +4805,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
/* For MSAA */
#ifndef JAVASCRIPT_ENABLED
- if (rt->msaa >= VS::VIEWPORT_MSAA_2X && rt->msaa <= VS::VIEWPORT_MSAA_16X && config.multisample_supported) {
+ if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_16X && config.multisample_supported) {
rt->multisample_active = true;
@@ -4839,7 +4841,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glGenTextures(1, &rt->multisample_color);
glBindTexture(GL_TEXTURE_2D, rt->multisample_color);
- glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, nullptr);
// multisample buffer is same size as front buffer, so just use nearest
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -4892,9 +4894,9 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color);
if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -4959,7 +4961,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color);
for (int l = 0; l < level + 1; l++) {
- glTexImage2D(GL_TEXTURE_2D, l, color_internal_format, width, height, 0, color_format, color_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, l, color_internal_format, width, height, 0, color_format, color_type, nullptr);
width = MAX(1, (width / 2));
height = MAX(1, (height / 2));
}
@@ -4973,7 +4975,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
for (int l = 0; l < level + 1; l++) {
glGenTextures(1, &rt->mip_maps[i].sizes.write[l].color);
glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[l].color);
- glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, width, height, 0, color_format, color_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, width, height, 0, color_format, color_type, nullptr);
width = MAX(1, (width / 2));
height = MAX(1, (height / 2));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -5132,7 +5134,7 @@ RID RasterizerStorageGLES2::render_target_create() {
Texture *t = memnew(Texture);
- t->type = VS::TEXTURE_TYPE_2D;
+ t->type = RS::TEXTURE_TYPE_2D;
t->flags = 0;
t->width = 0;
t->height = 0;
@@ -5233,7 +5235,7 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar
// allocate a texture
t = memnew(Texture);
- t->type = VS::TEXTURE_TYPE_2D;
+ t->type = RS::TEXTURE_TYPE_2D;
t->flags = 0;
t->width = 0;
t->height = 0;
@@ -5276,7 +5278,7 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar
// Switch our texture on our frame buffer
#if ANDROID_ENABLED
- if (rt->msaa >= VS::VIEWPORT_MSAA_EXT_2X && rt->msaa <= VS::VIEWPORT_MSAA_EXT_4X) {
+ if (rt->msaa >= RS::VIEWPORT_MSAA_EXT_2X && rt->msaa <= RS::VIEWPORT_MSAA_EXT_4X) {
// This code only applies to the Oculus Go and Oculus Quest. Due to the the tiled nature
// of the GPU we can do a single render pass by rendering directly into our texture chains
// texture and apply MSAA as we render.
@@ -5285,7 +5287,7 @@ void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_tar
// the normal MSAA modes need to be used to enable our two pass approach
static const int msaa_value[] = { 2, 4 };
- int msaa = msaa_value[rt->msaa - VS::VIEWPORT_MSAA_EXT_2X];
+ int msaa = msaa_value[rt->msaa - RS::VIEWPORT_MSAA_EXT_2X];
if (rt->external.depth == 0) {
// create a multisample depth buffer, we're not reusing Godots because Godot's didn't get created..
@@ -5368,7 +5370,7 @@ void RasterizerStorageGLES2::render_target_set_as_unused(RID p_render_target) {
rt->used_in_frame = false;
}
-void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {
+void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
@@ -5410,12 +5412,12 @@ RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) {
glGenTextures(1, &cls->distance);
glBindTexture(GL_TEXTURE_2D, cls->distance);
if (config.use_rgba_2d_shadows) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
} else {
#ifdef GLES_OVER_GL
- glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, nullptr);
#else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, nullptr);
#endif
}
@@ -5542,22 +5544,22 @@ void RasterizerStorageGLES2::canvas_light_occluder_set_polylines(RID p_occluder,
}
}
-VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
+RS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
if (mesh_owner.owns(p_rid)) {
- return VS::INSTANCE_MESH;
+ return RS::INSTANCE_MESH;
} else if (light_owner.owns(p_rid)) {
- return VS::INSTANCE_LIGHT;
+ return RS::INSTANCE_LIGHT;
} else if (multimesh_owner.owns(p_rid)) {
- return VS::INSTANCE_MULTIMESH;
+ return RS::INSTANCE_MULTIMESH;
} else if (immediate_owner.owns(p_rid)) {
- return VS::INSTANCE_IMMEDIATE;
+ return RS::INSTANCE_IMMEDIATE;
} else if (reflection_probe_owner.owns(p_rid)) {
- return VS::INSTANCE_REFLECTION_PROBE;
+ return RS::INSTANCE_REFLECTION_PROBE;
} else if (lightmap_capture_data_owner.owns(p_rid)) {
- return VS::INSTANCE_LIGHTMAP_CAPTURE;
+ return RS::INSTANCE_LIGHTMAP_CAPTURE;
} else {
- return VS::INSTANCE_NONE;
+ return RS::INSTANCE_NONE;
}
}
@@ -5609,7 +5611,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
while (shader->materials.first()) {
Material *m = shader->materials.first()->self();
- m->shader = NULL;
+ m->shader = nullptr;
_material_make_dirty(m);
shader->materials.remove(shader->materials.first());
@@ -5708,7 +5710,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
}
}
- multimesh_allocate(p_rid, 0, VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_NONE);
+ multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_3D, RS::MULTIMESH_COLOR_NONE);
update_dirty_multimeshes();
@@ -5815,25 +5817,25 @@ void RasterizerStorageGLES2::render_info_end_capture() {
info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count;
}
-int RasterizerStorageGLES2::get_captured_render_info(VS::RenderInfo p_info) {
+int RasterizerStorageGLES2::get_captured_render_info(RS::RenderInfo p_info) {
switch (p_info) {
- case VS::INFO_OBJECTS_IN_FRAME: {
+ case RS::INFO_OBJECTS_IN_FRAME: {
return info.snap.object_count;
} break;
- case VS::INFO_VERTICES_IN_FRAME: {
+ case RS::INFO_VERTICES_IN_FRAME: {
return info.snap.vertices_count;
} break;
- case VS::INFO_MATERIAL_CHANGES_IN_FRAME: {
+ case RS::INFO_MATERIAL_CHANGES_IN_FRAME: {
return info.snap.material_switch_count;
} break;
- case VS::INFO_SHADER_CHANGES_IN_FRAME: {
+ case RS::INFO_SHADER_CHANGES_IN_FRAME: {
return info.snap.shader_rebind_count;
} break;
- case VS::INFO_SURFACE_CHANGES_IN_FRAME: {
+ case RS::INFO_SURFACE_CHANGES_IN_FRAME: {
return info.snap.surface_switch_count;
} break;
- case VS::INFO_DRAW_CALLS_IN_FRAME: {
+ case RS::INFO_DRAW_CALLS_IN_FRAME: {
return info.snap.draw_call_count;
} break;
default: {
@@ -5842,27 +5844,27 @@ int RasterizerStorageGLES2::get_captured_render_info(VS::RenderInfo p_info) {
}
}
-int RasterizerStorageGLES2::get_render_info(VS::RenderInfo p_info) {
+int RasterizerStorageGLES2::get_render_info(RS::RenderInfo p_info) {
switch (p_info) {
- case VS::INFO_OBJECTS_IN_FRAME:
+ case RS::INFO_OBJECTS_IN_FRAME:
return info.render_final.object_count;
- case VS::INFO_VERTICES_IN_FRAME:
+ case RS::INFO_VERTICES_IN_FRAME:
return info.render_final.vertices_count;
- case VS::INFO_MATERIAL_CHANGES_IN_FRAME:
+ case RS::INFO_MATERIAL_CHANGES_IN_FRAME:
return info.render_final.material_switch_count;
- case VS::INFO_SHADER_CHANGES_IN_FRAME:
+ case RS::INFO_SHADER_CHANGES_IN_FRAME:
return info.render_final.shader_rebind_count;
- case VS::INFO_SURFACE_CHANGES_IN_FRAME:
+ case RS::INFO_SURFACE_CHANGES_IN_FRAME:
return info.render_final.surface_switch_count;
- case VS::INFO_DRAW_CALLS_IN_FRAME:
+ case RS::INFO_DRAW_CALLS_IN_FRAME:
return info.render_final.draw_call_count;
- case VS::INFO_USAGE_VIDEO_MEM_TOTAL:
+ case RS::INFO_USAGE_VIDEO_MEM_TOTAL:
return 0; //no idea
- case VS::INFO_VIDEO_MEM_USED:
+ case RS::INFO_VIDEO_MEM_USED:
return info.vertex_mem + info.texture_mem;
- case VS::INFO_TEXTURE_MEM_USED:
+ case RS::INFO_TEXTURE_MEM_USED:
return info.texture_mem;
- case VS::INFO_VERTEX_MEM_USED:
+ case RS::INFO_VERTEX_MEM_USED:
return info.vertex_mem;
default:
return 0; //no idea either
@@ -5940,7 +5942,7 @@ void RasterizerStorageGLES2::initialize() {
#ifdef IPHONE_ENABLED
// appears that IPhone doesn't need to dlopen TODO: test this rigorously before removing
- //void *gles2_lib = dlopen(NULL, RTLD_LAZY);
+ //void *gles2_lib = dlopen(nullptr, RTLD_LAZY);
//glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE");
//glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE");
#elif ANDROID_ENABLED
@@ -6012,7 +6014,7 @@ void RasterizerStorageGLES2::initialize() {
GLuint depth;
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
- glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, config.depth_type, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -6044,7 +6046,7 @@ void RasterizerStorageGLES2::initialize() {
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
- glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -6072,7 +6074,7 @@ void RasterizerStorageGLES2::initialize() {
frame.count = 0;
frame.delta = 0;
- frame.current_rt = NULL;
+ frame.current_rt = nullptr;
frame.clear_request = false;
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &config.max_vertex_texture_image_units);
@@ -6188,7 +6190,7 @@ void RasterizerStorageGLES2::initialize() {
glGenTextures(1, &resources.white_tex_array);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, resources.white_tex_array);
- glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata);
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
glBindTexture(GL_TEXTURE_2D, 0);
@@ -6250,7 +6252,7 @@ void RasterizerStorageGLES2::initialize() {
#endif
config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
- config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter");
+ config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/texture_filters/use_nearest_mipmap_filter");
}
void RasterizerStorageGLES2::finalize() {
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index 6fbfe57778..29651936fb 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -32,8 +32,8 @@
#define RASTERIZERSTORAGEGLES2_H
#include "core/self_list.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual/shader_language.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/shader_language.h"
#include "shader_compiler_gles2.h"
#include "shader_gles2.h"
@@ -249,7 +249,7 @@ public:
int width, height, depth;
int alloc_width, alloc_height;
Image::Format format;
- VS::TextureType type;
+ RS::TextureType type;
GLenum target;
GLenum gl_format_cache;
@@ -275,28 +275,28 @@ public:
RenderTarget *render_target;
- Vector<Ref<Image> > images;
+ Vector<Ref<Image>> images;
bool redraw_if_visible;
- VisualServer::TextureDetectCallback detect_3d;
+ RenderingServer::TextureDetectCallback detect_3d;
void *detect_3d_ud;
- VisualServer::TextureDetectCallback detect_srgb;
+ RenderingServer::TextureDetectCallback detect_srgb;
void *detect_srgb_ud;
- VisualServer::TextureDetectCallback detect_normal;
+ RenderingServer::TextureDetectCallback detect_normal;
void *detect_normal_ud;
Texture() :
- proxy(NULL),
+ proxy(nullptr),
flags(0),
width(0),
height(0),
alloc_width(0),
alloc_height(0),
format(Image::FORMAT_L8),
- type(VS::TEXTURE_TYPE_2D),
+ type(RS::TEXTURE_TYPE_2D),
target(0),
data_size(0),
total_data_size(0),
@@ -307,14 +307,14 @@ public:
active(false),
tex_id(0),
stored_cube_sides(0),
- render_target(NULL),
+ render_target(nullptr),
redraw_if_visible(false),
- detect_3d(NULL),
- detect_3d_ud(NULL),
- detect_srgb(NULL),
- detect_srgb_ud(NULL),
- detect_normal(NULL),
- detect_normal_ud(NULL) {
+ detect_3d(nullptr),
+ detect_3d_ud(nullptr),
+ detect_srgb(nullptr),
+ detect_srgb_ud(nullptr),
+ detect_normal(nullptr),
+ detect_normal_ud(nullptr) {
}
_ALWAYS_INLINE_ Texture *get_ptr() {
@@ -331,7 +331,7 @@ public:
}
for (Set<Texture *>::Element *E = proxy_owners.front(); E; E = E->next()) {
- E->get()->proxy = NULL;
+ E->get()->proxy = nullptr;
}
if (proxy) {
@@ -345,14 +345,14 @@ public:
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const;
virtual RID texture_create();
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
+ virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RS::TextureType p_type, uint32_t p_flags = RS::TEXTURE_FLAGS_DEFAULT);
virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
virtual 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_layer = 0);
virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags);
virtual uint32_t texture_get_flags(RID p_texture) const;
virtual Image::Format texture_get_format(RID p_texture) const;
- virtual VS::TextureType texture_get_type(RID p_texture) const;
+ virtual RS::TextureType texture_get_type(RID p_texture) const;
virtual uint32_t texture_get_texid(RID p_texture) const;
virtual uint32_t texture_get_width(RID p_texture) const;
virtual uint32_t texture_get_height(RID p_texture) const;
@@ -365,7 +365,7 @@ public:
virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable);
- virtual void texture_debug_usage(List<VS::TextureInfo> *r_info);
+ virtual void texture_debug_usage(List<RS::TextureInfo> *r_info);
virtual RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
@@ -374,9 +374,9 @@ public:
virtual void texture_set_proxy(RID p_texture, RID p_proxy);
virtual Size2 texture_size_with_proxy(RID p_texture) const;
- virtual void texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
- virtual void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
- virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
+ virtual void texture_set_detect_3d_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata);
+ virtual void texture_set_detect_srgb_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata);
+ virtual void texture_set_detect_normal_callback(RID p_texture, RenderingServer::TextureDetectCallback p_callback, void *p_userdata);
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable);
@@ -402,7 +402,7 @@ public:
RID self;
- VS::ShaderMode mode;
+ RS::ShaderMode mode;
ShaderGLES2 *shader;
String code;
SelfList<Material>::List materials;
@@ -508,7 +508,7 @@ public:
Shader() :
dirty_list(this) {
- shader = NULL;
+ shader = nullptr;
valid = false;
custom_code_id = 0;
version = 1;
@@ -541,7 +541,7 @@ public:
Map<StringName, Variant> params;
SelfList<Material> list;
SelfList<Material> dirty_list;
- Vector<Pair<StringName, RID> > textures;
+ Vector<Pair<StringName, RID>> textures;
float line_width;
int render_priority;
@@ -561,7 +561,7 @@ public:
dirty_list(this) {
can_cast_shadow_cache = false;
is_animated_cache = false;
- shader = NULL;
+ shader = nullptr;
line_width = 1.0;
last_pass = 0;
render_priority = 0;
@@ -617,7 +617,7 @@ public:
uint32_t offset;
};
- Attrib attribs[VS::ARRAY_MAX];
+ Attrib attribs[RS::ARRAY_MAX];
Mesh *mesh;
uint32_t format;
@@ -641,7 +641,7 @@ public:
int array_byte_size;
int index_array_byte_size;
- VS::PrimitiveType primitive;
+ RS::PrimitiveType primitive;
Vector<AABB> skeleton_bone_aabb;
Vector<bool> skeleton_bone_used;
@@ -650,17 +650,17 @@ public:
Vector<uint8_t> data;
Vector<uint8_t> index_data;
- Vector<Vector<uint8_t> > blend_shape_data;
+ Vector<Vector<uint8_t>> blend_shape_data;
int total_data_size;
Surface() :
- mesh(NULL),
+ mesh(nullptr),
array_len(0),
index_array_len(0),
array_byte_size(0),
index_array_byte_size(0),
- primitive(VS::PRIMITIVE_POINTS),
+ primitive(RS::PRIMITIVE_POINTS),
active(false),
total_data_size(0) {
}
@@ -675,7 +675,7 @@ public:
Vector<Surface *> surfaces;
int blend_shape_count;
- VS::BlendShapeMode blend_shape_mode;
+ RS::BlendShapeMode blend_shape_mode;
AABB custom_aabb;
@@ -694,7 +694,7 @@ public:
Mesh() :
blend_shape_count(0),
- blend_shape_mode(VS::BLEND_SHAPE_MODE_NORMALIZED) {
+ blend_shape_mode(RS::BLEND_SHAPE_MODE_NORMALIZED) {
}
};
@@ -702,13 +702,13 @@ public:
virtual RID mesh_create();
- virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::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>());
+ virtual 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>());
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_amount);
virtual int mesh_get_blend_shape_count(RID p_mesh) const;
- virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode);
- virtual VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
+ virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode);
+ virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
@@ -722,10 +722,10 @@ public:
virtual Vector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const;
virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
- virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
+ virtual RS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const;
- virtual Vector<Vector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const;
+ virtual Vector<Vector<uint8_t>> mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const;
virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const;
virtual void mesh_remove_surface(RID p_mesh, int p_surface);
@@ -744,9 +744,9 @@ public:
RID mesh;
int size;
- VS::MultimeshTransformFormat transform_format;
- VS::MultimeshColorFormat color_format;
- VS::MultimeshCustomDataFormat custom_data_format;
+ RS::MultimeshTransformFormat transform_format;
+ RS::MultimeshColorFormat color_format;
+ RS::MultimeshCustomDataFormat custom_data_format;
Vector<float> data;
@@ -766,9 +766,9 @@ public:
MultiMesh() :
size(0),
- transform_format(VS::MULTIMESH_TRANSFORM_2D),
- color_format(VS::MULTIMESH_COLOR_NONE),
- custom_data_format(VS::MULTIMESH_CUSTOM_DATA_NONE),
+ transform_format(RS::MULTIMESH_TRANSFORM_2D),
+ color_format(RS::MULTIMESH_COLOR_NONE),
+ custom_data_format(RS::MULTIMESH_CUSTOM_DATA_NONE),
update_list(this),
mesh_list(this),
visible_instances(-1),
@@ -786,7 +786,7 @@ public:
virtual RID multimesh_create();
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data = VS::MULTIMESH_CUSTOM_DATA_NONE);
+ virtual void multimesh_allocate(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, RS::MultimeshColorFormat p_color_format, RS::MultimeshCustomDataFormat p_data = RS::MULTIMESH_CUSTOM_DATA_NONE);
virtual int multimesh_get_instance_count(RID p_multimesh) const;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
@@ -817,7 +817,7 @@ public:
struct Chunk {
RID texture;
- VS::PrimitiveType primitive;
+ RS::PrimitiveType primitive;
Vector<Vector3> vertices;
Vector<Vector3> normals;
Vector<Plane> tangents;
@@ -846,7 +846,7 @@ public:
mutable RID_PtrOwner<Immediate> immediate_owner;
virtual RID immediate_create();
- virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture = RID());
+ virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_primitive, 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);
@@ -906,8 +906,8 @@ public:
/* Light API */
struct Light : Instantiable {
- VS::LightType type;
- float param[VS::LIGHT_PARAM_MAX];
+ RS::LightType type;
+ float param[RS::LIGHT_PARAM_MAX];
Color color;
Color shadow_color;
@@ -921,11 +921,11 @@ public:
uint32_t cull_mask;
- VS::LightOmniShadowMode omni_shadow_mode;
- VS::LightOmniShadowDetail omni_shadow_detail;
+ RS::LightOmniShadowMode omni_shadow_mode;
+ RS::LightOmniShadowDetail omni_shadow_detail;
- VS::LightDirectionalShadowMode directional_shadow_mode;
- VS::LightDirectionalShadowDepthRangeMode directional_range_mode;
+ RS::LightDirectionalShadowMode directional_shadow_mode;
+ RS::LightDirectionalShadowDepthRangeMode directional_range_mode;
bool directional_blend_splits;
@@ -934,10 +934,10 @@ public:
mutable RID_PtrOwner<Light> light_owner;
- virtual RID light_create(VS::LightType p_type);
+ virtual RID light_create(RS::LightType p_type);
virtual void light_set_color(RID p_light, const Color &p_color);
- virtual void light_set_param(RID p_light, VS::LightParam p_param, float p_value);
+ virtual void light_set_param(RID p_light, RS::LightParam p_param, float p_value);
virtual void light_set_shadow(RID p_light, bool p_enabled);
virtual void light_set_shadow_color(RID p_light, const Color &p_color);
virtual void light_set_projector(RID p_light, RID p_texture);
@@ -946,23 +946,23 @@ public:
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled);
virtual void light_set_use_gi(RID p_light, bool p_enabled);
- virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode);
- virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail);
+ virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode);
+ virtual void light_omni_set_shadow_detail(RID p_light, RS::LightOmniShadowDetail p_detail);
- virtual void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode);
+ virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode);
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable);
virtual bool light_directional_get_blend_splits(RID p_light) const;
- virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
- virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
+ virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
+ virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
- virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode);
- virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
+ virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode);
+ virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
virtual bool light_has_shadow(RID p_light) const;
- virtual VS::LightType light_get_type(RID p_light) const;
- virtual float light_get_param(RID p_light, VS::LightParam p_param);
+ virtual RS::LightType light_get_type(RID p_light) const;
+ virtual float light_get_param(RID p_light, RS::LightParam p_param);
virtual Color light_get_color(RID p_light);
virtual bool light_get_use_gi(RID p_light);
@@ -973,7 +973,7 @@ public:
struct ReflectionProbe : Instantiable {
- VS::ReflectionProbeUpdateMode update_mode;
+ RS::ReflectionProbeUpdateMode update_mode;
float intensity;
Color interior_ambient;
float interior_ambient_energy;
@@ -992,7 +992,7 @@ public:
virtual RID reflection_probe_create();
- virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode);
+ virtual void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode);
virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity);
virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient);
virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy);
@@ -1007,7 +1007,7 @@ public:
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution);
virtual AABB reflection_probe_get_aabb(RID p_probe) const;
- virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
+ virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const;
virtual int reflection_probe_get_resolution(RID p_probe) const;
@@ -1111,7 +1111,7 @@ public:
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable);
virtual void particles_restart(RID p_particles);
- virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order);
+ virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order);
virtual void particles_set_draw_passes(RID p_particles, int p_passes);
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh);
@@ -1203,7 +1203,7 @@ public:
bool flags[RENDER_TARGET_FLAG_MAX];
bool used_in_frame;
- VS::ViewportMSAA msaa;
+ RS::ViewportMSAA msaa;
RID texture;
@@ -1223,7 +1223,7 @@ public:
width(0),
height(0),
used_in_frame(false),
- msaa(VS::VIEWPORT_MSAA_DISABLED),
+ msaa(RS::VIEWPORT_MSAA_DISABLED),
used_dof_blur_near(false),
mip_maps_allocated(false) {
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) {
@@ -1247,7 +1247,7 @@ public:
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
virtual void render_target_set_as_unused(RID p_render_target);
- virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa);
+ virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa);
/* CANVAS SHADOW */
@@ -1279,7 +1279,7 @@ public:
virtual RID canvas_light_occluder_create();
virtual void canvas_light_occluder_set_polylines(RID p_occluder, const Vector<Vector2> &p_lines);
- virtual VS::InstanceType get_base_type(RID p_rid) const;
+ virtual RS::InstanceType get_base_type(RID p_rid) const;
virtual bool free(RID p_rid);
@@ -1309,9 +1309,9 @@ public:
virtual void render_info_begin_capture();
virtual void render_info_end_capture();
- virtual int get_captured_render_info(VS::RenderInfo p_info);
+ virtual int get_captured_render_info(RS::RenderInfo p_info);
- virtual int get_render_info(VS::RenderInfo p_info);
+ virtual int get_render_info(RS::RenderInfo p_info);
virtual String get_video_adapter_name() const;
virtual String get_video_adapter_vendor() const;
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 620fcdbdca..699d6e1484 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -226,7 +226,7 @@ void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const Stri
_dump_function_deps(p_node, E->get(), p_func_code, r_to_add, r_added);
- SL::FunctionNode *fnode = NULL;
+ SL::FunctionNode *fnode = nullptr;
for (int i = 0; i < p_node->functions.size(); i++) {
if (p_node->functions[i].name == E->get()) {
@@ -639,12 +639,12 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += _mkid(arr_node->name);
}
- if (arr_node->call_expression != NULL) {
+ if (arr_node->call_expression != nullptr) {
code += ".";
code += _dump_node_code(arr_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
}
- if (arr_node->index_expression != NULL) {
+ if (arr_node->index_expression != nullptr) {
code += "[";
code += _dump_node_code(arr_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "]";
@@ -923,7 +923,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ".";
code += member_node->name;
- if (member_node->index_expression != NULL) {
+ if (member_node->index_expression != nullptr) {
code += "[";
code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "]";
@@ -934,7 +934,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
return code.as_string();
}
-Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
+Error ShaderCompilerGLES2::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());
@@ -945,7 +945,7 @@ Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code,
print_line(itos(i + 1) + " " + shader[i]);
}
- _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
+ _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
return err;
}
@@ -975,210 +975,210 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
/** CANVAS ITEM SHADER **/
- actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy";
- actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv";
- actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "point_size";
-
- actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix";
- actions[VS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix_instance";
- actions[VS::SHADER_CANVAS_ITEM].renames["TIME"] = "time";
- actions[VS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass";
- actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom";
-
- actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color";
- actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal";
- actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map";
- actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth";
- actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture";
- actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size";
- actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture";
- actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv";
- actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture";
- actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
- actions[VS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord";
- actions[VS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord";
-
- actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec";
- actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height";
- actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color";
- actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv";
- actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light";
- actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color";
- actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec";
-
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy";
+ actions[RS::SHADER_CANVAS_ITEM].renames["UV"] = "uv";
+ actions[RS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "point_size";
+
+ actions[RS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix";
+ actions[RS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions[RS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix_instance";
+ actions[RS::SHADER_CANVAS_ITEM].renames["TIME"] = "time";
+ actions[RS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass";
+ actions[RS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom";
+
+ actions[RS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color";
+ actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal";
+ actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map";
+ actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth";
+ actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture";
+ actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size";
+ actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture";
+ actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv";
+ actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
+ actions[RS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord";
+ actions[RS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord";
+
+ actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec";
+ actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height";
+ actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color";
+ actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv";
+ actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light";
+ actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color";
+ actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec";
+
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions[RS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n";
// Ported from GLES3
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["sinh"] = "#define SINH_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["cosh"] = "#define COSH_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["tanh"] = "#define TANH_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["asinh"] = "#define ASINH_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["acosh"] = "#define ACOSH_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["atanh"] = "#define ATANH_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["determinant"] = "#define DETERMINANT_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["transpose"] = "#define TRANSPOSE_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n";
- actions[VS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["sinh"] = "#define SINH_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["cosh"] = "#define COSH_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["tanh"] = "#define TANH_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["asinh"] = "#define ASINH_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["acosh"] = "#define ACOSH_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["atanh"] = "#define ATANH_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["determinant"] = "#define DETERMINANT_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["transpose"] = "#define TRANSPOSE_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n";
+ actions[RS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n";
/** SPATIAL SHADER **/
- actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
- actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
- actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
- actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix";
- actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
-
- actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
- actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
- actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
- actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
- actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position";
- actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
- actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
- actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
- actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "point_size";
+ actions[RS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
+ actions[RS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
+ actions[RS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
+ actions[RS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions[RS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix";
+ actions[RS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
+
+ actions[RS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
+ actions[RS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
+ actions[RS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
+ actions[RS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
+ actions[RS::SHADER_SPATIAL].renames["POSITION"] = "position";
+ actions[RS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
+ actions[RS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
+ actions[RS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
+ actions[RS::SHADER_SPATIAL].renames["POINT_SIZE"] = "point_size";
// gl_InstanceID is not available in OpenGL ES 2.0
- actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0";
+ actions[RS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0";
//builtins
- actions[VS::SHADER_SPATIAL].renames["TIME"] = "time";
- actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
-
- actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
- actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
- actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
- actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
- actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
- actions[VS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
- actions[VS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
- actions[VS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
- actions[VS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
- actions[VS::SHADER_SPATIAL].renames["RIM"] = "rim";
- actions[VS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
- actions[VS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
- actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
- actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
- actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
- actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
- actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
- actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
- actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
- actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
- actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
- actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
- actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
- actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
- actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_texture";
+ actions[RS::SHADER_SPATIAL].renames["TIME"] = "time";
+ actions[RS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
+
+ actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
+ actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions[RS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
+ actions[RS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
+ actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
+ actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
+ actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
+ actions[RS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
+ actions[RS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
+ actions[RS::SHADER_SPATIAL].renames["RIM"] = "rim";
+ actions[RS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
+ actions[RS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
+ actions[RS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions[RS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
+ actions[RS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions[RS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
+ actions[RS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
+ actions[RS::SHADER_SPATIAL].renames["AO"] = "ao";
+ actions[RS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions[RS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
+ actions[RS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
+ actions[RS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions[RS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
+ actions[RS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions[RS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_texture";
// Defined in GLES3, but not available in GLES2
- //actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth";
- actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
- actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ //actions[RS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth";
+ actions[RS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
+ actions[RS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
//for light
- actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view";
- actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
- actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light";
- actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
- actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
- actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
-
- actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
- actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
- actions[VS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
- actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
- actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
- actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
- actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
- actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
- actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
- actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
- actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
- actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
-
- actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
- actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["DEPTH_TEXTURE"] = "#define DEPTH_TEXTURE_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
-
- actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions[RS::SHADER_SPATIAL].renames["VIEW"] = "view";
+ actions[RS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
+ actions[RS::SHADER_SPATIAL].renames["LIGHT"] = "light";
+ actions[RS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
+ actions[RS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions[RS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions[RS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
+ actions[RS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
+ actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions[RS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
+ actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions[RS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["DEPTH_TEXTURE"] = "#define DEPTH_TEXTURE_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions[RS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
// Ported from GLES3
- actions[VS::SHADER_SPATIAL].usage_defines["sinh"] = "#define SINH_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["cosh"] = "#define COSH_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["tanh"] = "#define TANH_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["asinh"] = "#define ASINH_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["acosh"] = "#define ACOSH_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["atanh"] = "#define ATANH_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["determinant"] = "#define DETERMINANT_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["transpose"] = "#define TRANSPOSE_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n";
-
- actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["sinh"] = "#define SINH_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["cosh"] = "#define COSH_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["tanh"] = "#define TANH_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["asinh"] = "#define ASINH_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["acosh"] = "#define ACOSH_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["atanh"] = "#define ATANH_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["determinant"] = "#define DETERMINANT_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["transpose"] = "#define TRANSPOSE_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n";
+
+ actions[RS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
// Defined in GLES3, could be implemented in GLES2 too if there's a need for it
- //actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ //actions[RS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
// Defined in GLES3, might not be possible in GLES2 as gl_FrontFacing is not available
- //actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
- //actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+ //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");
if (!force_lambert) {
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
}
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+ 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");
if (!force_blinn) {
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
} else {
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
}
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
// No defines for particle shaders in GLES2, there are no GPU particles
diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h
index e39ef5e7bd..757dcdd4f2 100644
--- a/drivers/gles2/shader_compiler_gles2.h
+++ b/drivers/gles2/shader_compiler_gles2.h
@@ -33,15 +33,15 @@
#include "core/pair.h"
#include "core/string_builder.h"
-#include "servers/visual/shader_language.h"
-#include "servers/visual/shader_types.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/shader_language.h"
+#include "servers/rendering/shader_types.h"
+#include "servers/rendering_server.h"
class ShaderCompilerGLES2 {
public:
struct IdentifierActions {
- Map<StringName, Pair<int *, int> > render_mode_values;
+ Map<StringName, Pair<int *, int>> render_mode_values;
Map<StringName, bool *> render_mode_flags;
Map<StringName, bool *> usage_flag_pointers;
Map<StringName, bool *> write_flag_pointers;
@@ -91,10 +91,10 @@ private:
Set<StringName> used_rmode_defines;
Set<StringName> internal_functions;
- DefaultIdentifierActions actions[VS::SHADER_MAX];
+ DefaultIdentifierActions actions[RS::SHADER_MAX];
public:
- Error compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
+ Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
ShaderCompilerGLES2();
};
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index f03f1ffa4f..2c335c6c5a 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -55,7 +55,7 @@
#endif
-ShaderGLES2 *ShaderGLES2::active = NULL;
+ShaderGLES2 *ShaderGLES2::active = nullptr;
//#define DEBUG_SHADER
@@ -103,10 +103,10 @@ bool ShaderGLES2::bind() {
}
void ShaderGLES2::unbind() {
- version = NULL;
+ version = nullptr;
glUseProgram(0);
uniforms_dirty = true;
- active = NULL;
+ active = nullptr;
}
static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) {
@@ -196,19 +196,19 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
CharString code_string2;
CharString code_globals;
- CustomCode *cc = NULL;
+ CustomCode *cc = nullptr;
if (conditional_version.code_version > 0) {
cc = custom_code_map.getptr(conditional_version.code_version);
- ERR_FAIL_COND_V(!cc, NULL);
+ ERR_FAIL_COND_V(!cc, nullptr);
v.code_version = cc->version;
}
// program
v.id = glCreateProgram();
- ERR_FAIL_COND_V(v.id == 0, NULL);
+ ERR_FAIL_COND_V(v.id == 0, nullptr);
if (cc) {
for (int i = 0; i < cc->custom_defines.size(); i++) {
@@ -244,7 +244,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
#endif
v.vert_id = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
+ glShaderSource(v.vert_id, strings.size(), &strings[0], nullptr);
glCompileShader(v.vert_id);
GLint status;
@@ -281,7 +281,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
v.id = 0;
}
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
strings.resize(string_base_size);
@@ -320,7 +320,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
#endif
v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
+ glShaderSource(v.frag_id, strings.size(), &strings[0], nullptr);
glCompileShader(v.frag_id);
glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
@@ -357,7 +357,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
v.id = 0;
}
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
glAttachShader(v.id, v.frag_id);
@@ -384,7 +384,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
v.id = 0;
ERR_PRINT("No OpenGL program link log. What the frick?");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
if (iloglen == 0) {
@@ -407,7 +407,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
glDeleteProgram(v.id);
v.id = 0;
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
// get uniform locations
@@ -553,7 +553,7 @@ void ShaderGLES2::setup(
}
void ShaderGLES2::finish() {
- const VersionKey *V = NULL;
+ const VersionKey *V = nullptr;
while ((V = version_map.next(V))) {
Version &v = version_map[*V];
@@ -565,7 +565,7 @@ void ShaderGLES2::finish() {
}
void ShaderGLES2::clear_caches() {
- const VersionKey *V = NULL;
+ const VersionKey *V = nullptr;
while ((V = version_map.next(V))) {
Version &v = version_map[*V];
@@ -578,7 +578,7 @@ void ShaderGLES2::clear_caches() {
version_map.clear();
custom_code_map.clear();
- version = NULL;
+ version = nullptr;
last_custom_code = 1;
uniforms_dirty = true;
}
@@ -1093,7 +1093,7 @@ void ShaderGLES2::use_material(void *p_material) {
}
ShaderGLES2::ShaderGLES2() {
- version = NULL;
+ version = nullptr;
last_custom_code = 1;
uniforms_dirty = true;
}
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index f2953c9ae8..d20d5bc585 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -44,7 +44,7 @@
#include "core/math/camera_matrix.h"
#include "core/pair.h"
#include "core/variant.h"
-#include "servers/visual/shader_language.h"
+#include "servers/rendering/shader_language.h"
#include <stdio.h>
@@ -121,7 +121,7 @@ private:
id = 0;
vert_id = 0;
frag_id = 0;
- uniform_location = NULL;
+ uniform_location = nullptr;
code_version = 0;
ok = false;
}
@@ -179,7 +179,7 @@ private:
int max_image_units;
- Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > > uniform_values;
+ Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value>>> uniform_values;
protected:
_FORCE_INLINE_ int _get_uniform(int p_which) const;
diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub
index d7ae0243e6..bcd6ea79fb 100644
--- a/drivers/gles2/shaders/SCsub
+++ b/drivers/gles2/shaders/SCsub
@@ -1,23 +1,23 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
-if 'GLES2_GLSL' in env['BUILDERS']:
- env.GLES2_GLSL('copy.glsl');
-# env.GLES2_GLSL('resolve.glsl');
- env.GLES2_GLSL('canvas.glsl');
- env.GLES2_GLSL('canvas_shadow.glsl');
- env.GLES2_GLSL('scene.glsl');
- env.GLES2_GLSL('cubemap_filter.glsl');
- env.GLES2_GLSL('cube_to_dp.glsl');
-# env.GLES2_GLSL('blend_shape.glsl');
-# env.GLES2_GLSL('screen_space_reflection.glsl');
- env.GLES2_GLSL('effect_blur.glsl');
-# env.GLES2_GLSL('subsurf_scattering.glsl');
-# env.GLES2_GLSL('ssao.glsl');
-# env.GLES2_GLSL('ssao_minify.glsl');
-# env.GLES2_GLSL('ssao_blur.glsl');
-# env.GLES2_GLSL('exposure.glsl');
- env.GLES2_GLSL('tonemap.glsl');
-# env.GLES2_GLSL('particles.glsl');
- env.GLES2_GLSL('lens_distorted.glsl');
+if "GLES2_GLSL" in env["BUILDERS"]:
+ env.GLES2_GLSL("copy.glsl")
+ # env.GLES2_GLSL('resolve.glsl');
+ env.GLES2_GLSL("canvas.glsl")
+ env.GLES2_GLSL("canvas_shadow.glsl")
+ env.GLES2_GLSL("scene.glsl")
+ env.GLES2_GLSL("cubemap_filter.glsl")
+ env.GLES2_GLSL("cube_to_dp.glsl")
+ # env.GLES2_GLSL('blend_shape.glsl');
+ # env.GLES2_GLSL('screen_space_reflection.glsl');
+ env.GLES2_GLSL("effect_blur.glsl")
+ # env.GLES2_GLSL('subsurf_scattering.glsl');
+ # env.GLES2_GLSL('ssao.glsl');
+ # env.GLES2_GLSL('ssao_minify.glsl');
+ # env.GLES2_GLSL('ssao_blur.glsl');
+ # env.GLES2_GLSL('exposure.glsl');
+ env.GLES2_GLSL("tonemap.glsl")
+ # env.GLES2_GLSL('particles.glsl');
+ env.GLES2_GLSL("lens_distorted.glsl")
diff --git a/drivers/gles2/shaders/blend_shape.glsl b/drivers/gles2/shaders/blend_shape.glsl
index a1e954e33d..0d0b3e24e4 100644
--- a/drivers/gles2/shaders/blend_shape.glsl
+++ b/drivers/gles2/shaders/blend_shape.glsl
@@ -2,7 +2,7 @@
[vertex]
/*
-from VisualServer:
+from RenderingServer:
ARRAY_VERTEX=0,
ARRAY_NORMAL=1,
diff --git a/drivers/png/SCsub b/drivers/png/SCsub
index 87b54cecaf..db08be0c47 100644
--- a/drivers/png/SCsub
+++ b/drivers/png/SCsub
@@ -1,11 +1,11 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env_png = env.Clone()
# Thirdparty source files
-if env['builtin_libpng']:
+if env["builtin_libpng"]:
thirdparty_dir = "#thirdparty/libpng/"
thirdparty_sources = [
"png.c",
@@ -32,6 +32,7 @@ if env['builtin_libpng']:
# Currently .ASM filter_neon.S does not compile on NT.
import os
+
use_neon = "neon_enabled" in env and env["neon_enabled"] and os.name != "nt"
if use_neon:
env_png.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT", 2)])
@@ -45,7 +46,7 @@ if env['builtin_libpng']:
if use_neon:
env_neon = env_thirdparty.Clone()
if "S_compiler" in env:
- env_neon['CC'] = env['S_compiler']
+ env_neon["CC"] = env["S_compiler"]
neon_sources = []
neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/arm_init.c"))
neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon_intrinsics.c"))
@@ -56,4 +57,4 @@ if env['builtin_libpng']:
# Godot source files
env_png.add_source_files(env.drivers_sources, "*.cpp")
-Export('env')
+Export("env")
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index efd488fd5c..f17abcb54c 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -110,7 +110,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) {
uint8_t *writer = buffer.ptrw();
// read image data to buffer and release libpng resources
- success = png_image_finish_read(&png_img, NULL, writer, stride, NULL);
+ success = png_image_finish_read(&png_img, nullptr, writer, stride, nullptr);
ERR_FAIL_COND_V_MSG(check_error(png_img), ERR_FILE_CORRUPT, png_img.message);
ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
@@ -175,7 +175,7 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) {
uint8_t *writer = p_buffer.ptrw();
success = png_image_write_to_memory(&png_img, &writer[buffer_offset],
- &compressed_size, 0, reader, 0, NULL);
+ &compressed_size, 0, reader, 0, nullptr);
ERR_FAIL_COND_V_MSG(check_error(png_img), FAILED, png_img.message);
}
if (!success) {
@@ -189,7 +189,7 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) {
uint8_t *writer = p_buffer.ptrw();
success = png_image_write_to_memory(&png_img, &writer[buffer_offset],
- &compressed_size, 0, reader, 0, NULL);
+ &compressed_size, 0, reader, 0, nullptr);
ERR_FAIL_COND_V_MSG(check_error(png_img), FAILED, png_img.message);
ERR_FAIL_COND_V(!success, FAILED);
}
diff --git a/drivers/pulseaudio/SCsub b/drivers/pulseaudio/SCsub
index 28b315ae66..91e1140b75 100644
--- a/drivers/pulseaudio/SCsub
+++ b/drivers/pulseaudio/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
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 ee9278fb8f..8a47f6cf96 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -98,7 +98,7 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this);
if (pa_op) {
while (pa_status == 0) {
- int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ int ret = pa_mainloop_iterate(pa_ml, 1, nullptr);
if (ret < 0) {
ERR_PRINT("pa_mainloop_iterate error");
}
@@ -128,7 +128,7 @@ void AudioDriverPulseAudio::detect_channels(bool capture) {
if (pa_op) {
while (pa_status == 0) {
- int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ int ret = pa_mainloop_iterate(pa_ml, 1, nullptr);
if (ret < 0) {
ERR_PRINT("pa_mainloop_iterate error");
}
@@ -203,7 +203,7 @@ Error AudioDriverPulseAudio::init_device() {
pa_map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
pa_str = pa_stream_new(pa_ctx, "Sound", &spec, &pa_map);
- if (pa_str == NULL) {
+ if (pa_str == nullptr) {
ERR_PRINT("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
ERR_FAIL_V(ERR_CANT_OPEN);
}
@@ -220,9 +220,9 @@ Error AudioDriverPulseAudio::init_device() {
attr.maxlength = (uint32_t)-1;
attr.minreq = (uint32_t)-1;
- const char *dev = device_name == "Default" ? NULL : device_name.utf8().get_data();
+ const char *dev = device_name == "Default" ? nullptr : device_name.utf8().get_data();
pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
- int error_code = pa_stream_connect_playback(pa_str, dev, &attr, flags, NULL, NULL);
+ int error_code = pa_stream_connect_playback(pa_str, dev, &attr, flags, nullptr, nullptr);
ERR_FAIL_COND_V(error_code < 0, ERR_CANT_OPEN);
samples_in.resize(buffer_frames * channels);
@@ -244,31 +244,31 @@ Error AudioDriverPulseAudio::init() {
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
pa_ml = pa_mainloop_new();
- ERR_FAIL_COND_V(pa_ml == NULL, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN);
pa_ctx = pa_context_new(pa_mainloop_get_api(pa_ml), "Godot");
- ERR_FAIL_COND_V(pa_ctx == NULL, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V(pa_ctx == nullptr, ERR_CANT_OPEN);
pa_ready = 0;
pa_context_set_state_callback(pa_ctx, pa_state_cb, (void *)this);
- int ret = pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL);
+ int ret = pa_context_connect(pa_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
if (ret < 0) {
if (pa_ctx) {
pa_context_unref(pa_ctx);
- pa_ctx = NULL;
+ pa_ctx = nullptr;
}
if (pa_ml) {
pa_mainloop_free(pa_ml);
- pa_ml = NULL;
+ pa_ml = nullptr;
}
return ERR_CANT_OPEN;
}
while (pa_ready == 0) {
- ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ ret = pa_mainloop_iterate(pa_ml, 1, nullptr);
if (ret < 0) {
ERR_PRINT("pa_mainloop_iterate error");
}
@@ -278,12 +278,12 @@ Error AudioDriverPulseAudio::init() {
if (pa_ctx) {
pa_context_disconnect(pa_ctx);
pa_context_unref(pa_ctx);
- pa_ctx = NULL;
+ pa_ctx = nullptr;
}
if (pa_ml) {
pa_mainloop_free(pa_ml);
- pa_ml = NULL;
+ pa_ml = nullptr;
}
return ERR_CANT_OPEN;
@@ -377,7 +377,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
int ret;
do {
- ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL);
+ ret = pa_mainloop_iterate(ad->pa_ml, 0, nullptr);
} while (ret > 0);
if (avail_bytes > 0 && pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) {
@@ -385,7 +385,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
if (bytes > 0) {
size_t bytes_to_write = MIN(bytes, avail_bytes);
const void *ptr = ad->samples_out.ptr();
- ret = pa_stream_write(ad->pa_str, (char *)ptr + write_ofs, bytes_to_write, NULL, 0LL, PA_SEEK_RELATIVE);
+ ret = pa_stream_write(ad->pa_str, (char *)ptr + write_ofs, bytes_to_write, nullptr, 0LL, PA_SEEK_RELATIVE);
if (ret != 0) {
ERR_PRINT("PulseAudio: pa_stream_write error: " + String(pa_strerror(ret)));
} else {
@@ -432,7 +432,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
pa_operation *pa_op = pa_context_get_server_info(ad->pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)ad);
if (pa_op) {
while (ad->pa_status == 0) {
- ret = pa_mainloop_iterate(ad->pa_ml, 1, NULL);
+ ret = pa_mainloop_iterate(ad->pa_ml, 1, nullptr);
if (ret < 0) {
ERR_PRINT("pa_mainloop_iterate error");
}
@@ -463,7 +463,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
if (ad->pa_rec_str && pa_stream_get_state(ad->pa_rec_str) == PA_STREAM_READY) {
size_t bytes = pa_stream_readable_size(ad->pa_rec_str);
if (bytes > 0) {
- const void *ptr = NULL;
+ const void *ptr = nullptr;
size_t maxbytes = ad->input_buffer.size() * sizeof(int16_t);
bytes = MIN(bytes, maxbytes);
@@ -555,7 +555,7 @@ Array AudioDriverPulseAudio::get_device_list() {
pa_devices.clear();
pa_devices.push_back("Default");
- if (pa_ctx == NULL) {
+ if (pa_ctx == nullptr) {
return pa_devices;
}
@@ -566,7 +566,7 @@ Array AudioDriverPulseAudio::get_device_list() {
pa_operation *pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, (void *)this);
if (pa_op) {
while (pa_status == 0) {
- int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ int ret = pa_mainloop_iterate(pa_ml, 1, nullptr);
if (ret < 0) {
ERR_PRINT("pa_mainloop_iterate error");
}
@@ -613,7 +613,7 @@ void AudioDriverPulseAudio::finish_device() {
if (pa_str) {
pa_stream_disconnect(pa_str);
pa_stream_unref(pa_str);
- pa_str = NULL;
+ pa_str = nullptr;
}
}
@@ -630,17 +630,17 @@ void AudioDriverPulseAudio::finish() {
if (pa_ctx) {
pa_context_disconnect(pa_ctx);
pa_context_unref(pa_ctx);
- pa_ctx = NULL;
+ pa_ctx = nullptr;
}
if (pa_ml) {
pa_mainloop_free(pa_ml);
- pa_ml = NULL;
+ pa_ml = nullptr;
}
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
Error AudioDriverPulseAudio::capture_init_device() {
@@ -680,12 +680,12 @@ Error AudioDriverPulseAudio::capture_init_device() {
attr.fragsize = input_buffer_size * sizeof(int16_t);
pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
- if (pa_rec_str == NULL) {
+ if (pa_rec_str == nullptr) {
ERR_PRINT("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
ERR_FAIL_V(ERR_CANT_OPEN);
}
- const char *dev = capture_device_name == "Default" ? NULL : capture_device_name.utf8().get_data();
+ const char *dev = capture_device_name == "Default" ? nullptr : capture_device_name.utf8().get_data();
pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
int error_code = pa_stream_connect_record(pa_rec_str, dev, &attr, flags);
if (error_code < 0) {
@@ -709,7 +709,7 @@ void AudioDriverPulseAudio::capture_finish_device() {
ERR_PRINT("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret)));
}
pa_stream_unref(pa_rec_str);
- pa_rec_str = NULL;
+ pa_rec_str = nullptr;
}
}
@@ -757,7 +757,7 @@ Array AudioDriverPulseAudio::capture_get_device_list() {
pa_rec_devices.clear();
pa_rec_devices.push_back("Default");
- if (pa_ctx == NULL) {
+ if (pa_ctx == nullptr) {
return pa_rec_devices;
}
@@ -768,7 +768,7 @@ Array AudioDriverPulseAudio::capture_get_device_list() {
pa_operation *pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, (void *)this);
if (pa_op) {
while (pa_status == 0) {
- int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ int ret = pa_mainloop_iterate(pa_ml, 1, nullptr);
if (ret < 0) {
ERR_PRINT("pa_mainloop_iterate error");
}
@@ -794,11 +794,11 @@ String AudioDriverPulseAudio::capture_get_device() {
}
AudioDriverPulseAudio::AudioDriverPulseAudio() :
- thread(NULL),
- pa_ml(NULL),
- pa_ctx(NULL),
- pa_str(NULL),
- pa_rec_str(NULL),
+ thread(nullptr),
+ pa_ml(nullptr),
+ pa_ctx(nullptr),
+ pa_str(nullptr),
+ pa_rec_str(nullptr),
device_name("Default"),
new_device("Default"),
default_device(""),
diff --git a/drivers/spirv-reflect/SCsub b/drivers/spirv-reflect/SCsub
index 8ff27da114..d0ffaf068d 100644
--- a/drivers/spirv-reflect/SCsub
+++ b/drivers/spirv-reflect/SCsub
@@ -1,17 +1,17 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env_spirv_reflect = env.Clone()
env_spirv_reflect.disable_warnings()
thirdparty_dir = "#thirdparty/spirv-reflect/"
thirdparty_sources = [
- "spirv_reflect.c"
+ "spirv_reflect.c",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_spirv_reflect.add_source_files(env.drivers_sources, thirdparty_sources)
-Export('env')
+Export("env")
diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub
index 4888f56099..91ef613546 100644
--- a/drivers/unix/SCsub
+++ b/drivers/unix/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
-env["check_c_headers"] = [ [ "mntent.h", "HAVE_MNTENT" ] ]
+env["check_c_headers"] = [["mntent.h", "HAVE_MNTENT"]]
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 715bc56003..00103684c7 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -129,7 +129,7 @@ String DirAccessUnix::get_next() {
dirent *entry = readdir(dir_stream);
- if (entry == NULL) {
+ if (entry == nullptr) {
list_dir_end();
return "";
}
@@ -173,7 +173,7 @@ void DirAccessUnix::list_dir_end() {
if (dir_stream)
closedir(dir_stream);
- dir_stream = 0;
+ dir_stream = nullptr;
_cisdir = false;
}
@@ -207,7 +207,7 @@ static void _get_drives(List<String> *list) {
char strings[4096];
while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
- if (mnt.mnt_dir != NULL && _filter_drive(&mnt)) {
+ if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) {
// Avoid duplicates
if (!list->find(mnt.mnt_dir)) {
list->push_back(mnt.mnt_dir);
@@ -306,7 +306,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
// prev_dir is the directory we are changing out of
String prev_dir;
char real_current_dir_name[2048];
- ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
+ ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG);
if (prev_dir.parse_utf8(real_current_dir_name))
prev_dir = real_current_dir_name; //no utf8, maybe latin?
@@ -327,7 +327,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
String base = _get_root_path();
if (base != String() && !try_dir.begins_with(base)) {
- ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
+ ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG);
String new_dir;
new_dir.parse_utf8(real_current_dir_name);
@@ -410,14 +410,14 @@ String DirAccessUnix::get_filesystem_type() const {
DirAccessUnix::DirAccessUnix() {
- dir_stream = 0;
+ dir_stream = nullptr;
_cisdir = false;
/* determine drive count */
// set current directory to an absolute path of the current directory
char real_current_dir_name[2048];
- ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == NULL);
+ ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == nullptr);
if (current_dir.parse_utf8(real_current_dir_name))
current_dir = real_current_dir_name;
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 91164dc3f9..4aa408a1f0 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -76,7 +76,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
if (f)
fclose(f);
- f = NULL;
+ f = nullptr;
path_src = p_path;
path = fix_path(p_path);
@@ -119,7 +119,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
f = fopen(path.utf8().get_data(), mode_string);
- if (f == NULL) {
+ if (f == nullptr) {
switch (errno) {
case ENOENT: {
last_error = ERR_FILE_NOT_FOUND;
@@ -155,7 +155,7 @@ void FileAccessUnix::close() {
return;
fclose(f);
- f = NULL;
+ f = nullptr;
if (close_notification_func) {
close_notification_func(path, flags);
@@ -175,7 +175,7 @@ void FileAccessUnix::close() {
bool FileAccessUnix::is_open() const {
- return (f != NULL);
+ return (f != nullptr);
}
String FileAccessUnix::get_path() const {
@@ -352,10 +352,10 @@ FileAccess *FileAccessUnix::create_libc() {
return memnew(FileAccessUnix);
}
-CloseNotificationFunc FileAccessUnix::close_notification_func = NULL;
+CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr;
FileAccessUnix::FileAccessUnix() :
- f(NULL),
+ f(nullptr),
flags(0),
last_error(OK) {
}
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 08c099f771..5e3dedfc2f 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -107,13 +107,13 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
};
hints.ai_flags &= ~AI_NUMERICHOST;
- int s = getaddrinfo(p_hostname.utf8().get_data(), NULL, &hints, &result);
+ int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
ERR_PRINT("getaddrinfo failed! Cannot resolve hostname.");
return IP_Address();
};
- if (result == NULL || result->ai_addr == NULL) {
+ if (result == nullptr || result->ai_addr == nullptr) {
ERR_PRINT("Invalid response from getaddrinfo");
if (result)
freeaddrinfo(result);
@@ -175,7 +175,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size);
int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
- NULL, addrs, &buf_size);
+ nullptr, addrs, &buf_size);
if (err == NO_ERROR) {
break;
};
@@ -189,7 +189,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
IP_ADAPTER_ADDRESSES *adapter = addrs;
- while (adapter != NULL) {
+ while (adapter != nullptr) {
Interface_Info info;
info.name = adapter->AdapterName;
@@ -197,7 +197,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
info.index = String::num_uint64(adapter->IfIndex);
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
- while (address != NULL) {
+ while (address != nullptr) {
int family = address->Address.lpSockaddr->sa_family;
if (family != AF_INET && family != AF_INET6)
continue;
@@ -219,13 +219,13 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
- struct ifaddrs *ifAddrStruct = NULL;
- struct ifaddrs *ifa = NULL;
+ struct ifaddrs *ifAddrStruct = nullptr;
+ struct ifaddrs *ifa = nullptr;
int family;
getifaddrs(&ifAddrStruct);
- for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
+ for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
@@ -248,7 +248,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr));
}
- if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
+ if (ifAddrStruct != nullptr) freeifaddrs(ifAddrStruct);
}
#endif
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 4adeeb1d9b..7c6543c3a2 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -86,7 +86,7 @@
#define SOCK_CLOSE closesocket
// connect is broken on windows under certain conditions, reasons unknown:
// See https://github.com/godotengine/webrtc-native/issues/6
-#define SOCK_CONNECT(p_sock, p_addr, p_addr_len) ::WSAConnect(p_sock, p_addr, p_addr_len, NULL, NULL, NULL, NULL)
+#define SOCK_CONNECT(p_sock, p_addr, p_addr_len) ::WSAConnect(p_sock, p_addr, p_addr_len, nullptr, nullptr, nullptr, nullptr)
// Workaround missing flag in MinGW
#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
@@ -155,7 +155,7 @@ NetSocket *NetSocketPosix::_create_func() {
void NetSocketPosix::make_default() {
#if defined(WINDOWS_ENABLED)
- if (_create == NULL) {
+ if (_create == nullptr) {
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
}
@@ -165,10 +165,10 @@ void NetSocketPosix::make_default() {
void NetSocketPosix::cleanup() {
#if defined(WINDOWS_ENABLED)
- if (_create != NULL) {
+ if (_create != nullptr) {
WSACleanup();
}
- _create = NULL;
+ _create = nullptr;
#endif
}
@@ -446,15 +446,15 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
#if defined(WINDOWS_ENABLED)
bool ready = false;
fd_set rd, wr, ex;
- fd_set *rdp = NULL;
- fd_set *wrp = NULL;
+ fd_set *rdp = nullptr;
+ fd_set *wrp = nullptr;
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_ZERO(&ex);
FD_SET(_sock, &ex);
struct timeval timeout = { p_timeout, 0 };
- // For blocking operation, pass NULL timeout pointer to select.
- struct timeval *tp = NULL;
+ // For blocking operation, pass nullptr timeout pointer to select.
+ struct timeval *tp = nullptr;
if (p_timeout >= 0) {
// If timeout is non-negative, we want to specify the timeout instead.
tp = &timeout;
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 458488f3e9..53c60951b7 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -41,7 +41,7 @@
#include "drivers/unix/net_socket_posix.h"
#include "drivers/unix/rw_lock_posix.h"
#include "drivers/unix/thread_posix.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
#ifdef __APPLE__
#include <mach-o/dyld.h>
@@ -109,7 +109,7 @@ void OS_Unix::initialize_debugging() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = handle_interrupt;
- sigaction(SIGINT, &action, NULL);
+ sigaction(SIGINT, &action, nullptr);
}
}
@@ -172,24 +172,24 @@ String OS_Unix::get_name() const {
uint64_t OS_Unix::get_unix_time() const {
- return time(NULL);
+ return time(nullptr);
};
uint64_t OS_Unix::get_system_time_secs() const {
struct timeval tv_now;
- gettimeofday(&tv_now, NULL);
+ gettimeofday(&tv_now, nullptr);
return uint64_t(tv_now.tv_sec);
}
uint64_t OS_Unix::get_system_time_msecs() const {
struct timeval tv_now;
- gettimeofday(&tv_now, NULL);
+ gettimeofday(&tv_now, nullptr);
return uint64_t(tv_now.tv_sec) * 1000 + uint64_t(tv_now.tv_usec) / 1000;
}
OS::Date OS_Unix::get_date(bool utc) const {
- time_t t = time(NULL);
+ time_t t = time(nullptr);
struct tm *lt;
if (utc)
lt = gmtime(&t);
@@ -209,7 +209,7 @@ OS::Date OS_Unix::get_date(bool utc) const {
}
OS::Time OS_Unix::get_time(bool utc) const {
- time_t t = time(NULL);
+ time_t t = time(nullptr);
struct tm *lt;
if (utc)
lt = gmtime(&t);
@@ -224,7 +224,7 @@ OS::Time OS_Unix::get_time(bool utc) const {
}
OS::TimeZoneInfo OS_Unix::get_time_zone_info() const {
- time_t t = time(NULL);
+ time_t t = time(nullptr);
struct tm *lt = localtime(&t);
char name[16];
strftime(name, 16, "%Z", lt);
@@ -379,7 +379,7 @@ int OS_Unix::get_process_id() const {
bool OS_Unix::has_environment(const String &p_var) const {
- return getenv(p_var.utf8().get_data()) != NULL;
+ return getenv(p_var.utf8().get_data()) != nullptr;
}
String OS_Unix::get_locale() const {
@@ -433,7 +433,7 @@ Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const S
p_symbol_handle = dlsym(p_library_handle, p_name.utf8().get_data());
error = dlerror();
- if (error != NULL) {
+ if (error != nullptr) {
ERR_FAIL_COND_V_MSG(!p_optional, ERR_CANT_RESOLVE, "Can't resolve symbol " + p_name + ". Error: " + error + ".");
return ERR_CANT_RESOLVE;
@@ -511,7 +511,7 @@ String OS_Unix::get_executable_path() const {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
char buf[MAXPATHLEN];
size_t len = sizeof(buf);
- if (sysctl(mib, 4, buf, &len, NULL, 0) != 0) {
+ if (sysctl(mib, 4, buf, &len, nullptr, 0) != 0) {
WARN_PRINT("Couldn't get executable path from sysctl");
return OS::get_executable_path();
}
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index c381890834..90679ddf1d 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -85,7 +85,7 @@ public:
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;
diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp
index bb3eebd267..f219a0905c 100644
--- a/drivers/unix/rw_lock_posix.cpp
+++ b/drivers/unix/rw_lock_posix.cpp
@@ -91,7 +91,7 @@ void RWLockPosix::make_default() {
RWLockPosix::RWLockPosix() {
//rwlock=PTHREAD_RWLOCK_INITIALIZER; fails on OSX
- pthread_rwlock_init(&rwlock, NULL);
+ pthread_rwlock_init(&rwlock, nullptr);
}
RWLockPosix::~RWLockPosix() {
diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp
index 59001f057d..dc9112bf14 100644
--- a/drivers/unix/syslog_logger.cpp
+++ b/drivers/unix/syslog_logger.cpp
@@ -68,4 +68,4 @@ void SyslogLogger::print_error(const char *p_function, const char *p_file, int p
SyslogLogger::~SyslogLogger() {
}
-#endif \ No newline at end of file
+#endif
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index 21f49a7e38..c227aec6d6 100644
--- a/drivers/unix/thread_posix.cpp
+++ b/drivers/unix/thread_posix.cpp
@@ -75,7 +75,7 @@ void *ThreadPosix::thread_callback(void *userdata) {
ScriptServer::thread_exit();
- return NULL;
+ return nullptr;
}
Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
@@ -108,7 +108,7 @@ void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) {
ERR_FAIL_COND(!tp);
ERR_FAIL_COND(tp->pthread == 0);
- pthread_join(tp->pthread, NULL);
+ pthread_join(tp->pthread, nullptr);
tp->pthread = 0;
}
diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub
index 85a5ae8d26..91d0e42f80 100644
--- a/drivers/vulkan/SCsub
+++ b/drivers/vulkan/SCsub
@@ -1,10 +1,28 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
-if env['builtin_vulkan']:
+if env["platform"] == "android":
+ # Use NDK Vulkan headers
+ thirdparty_dir = env["ANDROID_NDK_ROOT"] + "/sources/third_party/vulkan/src"
+ thirdparty_includes = [
+ thirdparty_dir,
+ thirdparty_dir + "/include",
+ thirdparty_dir + "/layers",
+ thirdparty_dir + "/layers/generated",
+ ]
+ env.Prepend(CPPPATH=thirdparty_includes)
+
+ # Build Vulkan memory allocator
+ env_thirdparty = env.Clone()
+ env_thirdparty.disable_warnings()
+
+ thirdparty_dir = "#thirdparty/vulkan"
+ vma_sources = [thirdparty_dir + "/android/vk_mem_alloc.cpp"]
+ env_thirdparty.add_source_files(env.drivers_sources, vma_sources)
+elif env["builtin_vulkan"]:
# Use bundled Vulkan headers
thirdparty_dir = "#thirdparty/vulkan"
env.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include", thirdparty_dir + "/loader"])
@@ -27,48 +45,56 @@ if env['builtin_vulkan']:
]
vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"]
- if env['platform'] == "windows":
+ if env["platform"] == "windows":
loader_sources.append("dirent_on_windows.c")
loader_sources.append("dxgi_loader.c")
- env_thirdparty.AppendUnique(CPPDEFINES=[
- 'VK_USE_PLATFORM_WIN32_KHR',
- 'VULKAN_NON_CMAKE_BUILD',
- 'WIN32_LEAN_AND_MEAN',
- 'API_NAME=\\"%s\\"' % 'Vulkan'
- ])
- if not env.msvc: # Windows 7+, missing in mingw headers
- env_thirdparty.AppendUnique(CPPDEFINES=[
- "CM_GETIDLIST_FILTER_CLASS=0x00000200",
- "CM_GETIDLIST_FILTER_PRESENT=0x00000100"
- ])
- elif env['platform'] == "osx":
- env_thirdparty.AppendUnique(CPPDEFINES=[
- 'VK_USE_PLATFORM_MACOS_MVK',
- 'VULKAN_NON_CMAKE_BUILD',
- 'SYSCONFDIR=\\"%s\\"' % '/etc',
- 'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
- 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
- ])
- elif env['platform'] == "iphone":
- env_thirdparty.AppendUnique(CPPDEFINES=[
- 'VK_USE_PLATFORM_IOS_MVK',
- 'VULKAN_NON_CMAKE_BUILD',
- 'SYSCONFDIR=\\"%s\\"' % '/etc',
- 'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
- 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
- ])
- elif env['platform'] == "x11":
- env_thirdparty.AppendUnique(CPPDEFINES=[
- 'VK_USE_PLATFORM_XLIB_KHR',
- 'VULKAN_NON_CMAKE_BUILD',
- 'SYSCONFDIR=\\"%s\\"' % '/etc',
- 'FALLBACK_DATA_DIRS=\\"%s\\"' % '/usr/local/share:/usr/share',
- 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % '/etc/xdg'
- ])
+ env_thirdparty.AppendUnique(
+ CPPDEFINES=[
+ "VK_USE_PLATFORM_WIN32_KHR",
+ "VULKAN_NON_CMAKE_BUILD",
+ "WIN32_LEAN_AND_MEAN",
+ 'API_NAME=\\"%s\\"' % "Vulkan",
+ ]
+ )
+ if not env.msvc: # Windows 7+, missing in mingw headers
+ env_thirdparty.AppendUnique(
+ CPPDEFINES=["CM_GETIDLIST_FILTER_CLASS=0x00000200", "CM_GETIDLIST_FILTER_PRESENT=0x00000100"]
+ )
+ elif env["platform"] == "osx":
+ env_thirdparty.AppendUnique(
+ CPPDEFINES=[
+ "VK_USE_PLATFORM_MACOS_MVK",
+ "VULKAN_NON_CMAKE_BUILD",
+ 'SYSCONFDIR=\\"%s\\"' % "/etc",
+ 'FALLBACK_DATA_DIRS=\\"%s\\"' % "/usr/local/share:/usr/share",
+ 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg",
+ ]
+ )
+ elif env["platform"] == "iphone":
+ env_thirdparty.AppendUnique(
+ CPPDEFINES=[
+ "VK_USE_PLATFORM_IOS_MVK",
+ "VULKAN_NON_CMAKE_BUILD",
+ 'SYSCONFDIR=\\"%s\\"' % "/etc",
+ 'FALLBACK_DATA_DIRS=\\"%s\\"' % "/usr/local/share:/usr/share",
+ 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg",
+ ]
+ )
+ elif env["platform"] == "linuxbsd":
+ env_thirdparty.AppendUnique(
+ CPPDEFINES=[
+ "VK_USE_PLATFORM_XLIB_KHR",
+ "VULKAN_NON_CMAKE_BUILD",
+ 'SYSCONFDIR=\\"%s\\"' % "/etc",
+ 'FALLBACK_DATA_DIRS=\\"%s\\"' % "/usr/local/share:/usr/share",
+ 'FALLBACK_CONFIG_DIRS=\\"%s\\"' % "/etc/xdg",
+ ]
+ )
import platform
- if (platform.system() == "Linux"):
+
+ if platform.system() == "Linux":
# In glibc since 2.17 and musl libc since 1.1.24. Used by loader.c.
- env_thirdparty.AppendUnique(CPPDEFINES=['HAVE_SECURE_GETENV'])
+ env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources]
env_thirdparty.add_source_files(env.drivers_sources, loader_sources)
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 361982b28d..2769469838 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "rendering_device_vulkan.h"
+
#include "core/hashfuncs.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
@@ -57,7 +58,7 @@ void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
//direct dependencies must be freed
- Map<RID, Set<RID> >::Element *E = dependency_map.find(p_id);
+ Map<RID, Set<RID>>::Element *E = dependency_map.find(p_id);
if (E) {
while (E->get().size()) {
@@ -72,7 +73,7 @@ void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
if (E) {
for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) {
- Map<RID, Set<RID> >::Element *G = dependency_map.find(F->get());
+ Map<RID, Set<RID>>::Element *G = dependency_map.find(F->get());
ERR_CONTINUE(!G);
ERR_CONTINUE(!G->get().has(p_id));
G->get().erase(p_id);
@@ -1234,13 +1235,13 @@ const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXT
Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mapping) {
VkBufferCreateInfo bufferInfo;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- bufferInfo.pNext = NULL;
+ bufferInfo.pNext = nullptr;
bufferInfo.flags = 0;
bufferInfo.size = p_size;
bufferInfo.usage = p_usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufferInfo.queueFamilyIndexCount = 0;
- bufferInfo.pQueueFamilyIndices = 0;
+ bufferInfo.pQueueFamilyIndices = nullptr;
VmaAllocationCreateInfo allocInfo;
allocInfo.flags = 0;
@@ -1248,10 +1249,10 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size,
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
- allocInfo.pool = NULL;
- allocInfo.pUserData = NULL;
+ allocInfo.pool = nullptr;
+ allocInfo.pUserData = nullptr;
- VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, NULL);
+ VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, nullptr);
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size) + ", error " + itos(err) + ".");
p_buffer->size = p_size;
p_buffer->buffer_info.buffer = p_buffer->buffer;
@@ -1265,8 +1266,8 @@ Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) {
ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER);
vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation);
- p_buffer->buffer = NULL;
- p_buffer->allocation = NULL;
+ p_buffer->buffer = VK_NULL_HANDLE;
+ p_buffer->allocation = nullptr;
p_buffer->size = 0;
return OK;
@@ -1276,13 +1277,13 @@ Error RenderingDeviceVulkan::_insert_staging_block() {
VkBufferCreateInfo bufferInfo;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- bufferInfo.pNext = NULL;
+ bufferInfo.pNext = nullptr;
bufferInfo.flags = 0;
bufferInfo.size = staging_buffer_block_size;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufferInfo.queueFamilyIndexCount = 0;
- bufferInfo.pQueueFamilyIndices = 0;
+ bufferInfo.pQueueFamilyIndices = nullptr;
VmaAllocationCreateInfo allocInfo;
allocInfo.flags = 0;
@@ -1290,12 +1291,12 @@ Error RenderingDeviceVulkan::_insert_staging_block() {
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
- allocInfo.pool = NULL;
- allocInfo.pUserData = NULL;
+ allocInfo.pool = nullptr;
+ allocInfo.pUserData = nullptr;
StagingBufferBlock block;
- VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &block.buffer, &block.allocation, NULL);
+ VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &block.buffer, &block.allocation, nullptr);
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vmaCreateBuffer failed with error " + itos(err) + ".");
block.frame_used = 0;
@@ -1459,7 +1460,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
//map staging buffer (It's CPU and coherent)
- void *data_ptr = NULL;
+ void *data_ptr = nullptr;
{
VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr);
ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
@@ -1492,11 +1493,11 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas
VkMemoryBarrier mem_barrier;
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
- mem_barrier.pNext = NULL;
+ mem_barrier.pNext = nullptr;
mem_barrier.srcAccessMask = p_src_access;
mem_barrier.dstAccessMask = p_dst_sccess;
- vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL);
+ vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, nullptr, 0, nullptr);
}
void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) {
@@ -1539,7 +1540,7 @@ void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_f
VkBufferMemoryBarrier buffer_mem_barrier;
buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
- buffer_mem_barrier.pNext = NULL;
+ buffer_mem_barrier.pNext = nullptr;
buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
buffer_mem_barrier.srcAccessMask = p_src_access;
@@ -1548,33 +1549,43 @@ void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_f
buffer_mem_barrier.offset = p_from;
buffer_mem_barrier.size = p_size;
- vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, NULL, 1, &buffer_mem_barrier, 0, NULL);
+ vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, nullptr, 1, &buffer_mem_barrier, 0, nullptr);
}
/*****************/
/**** TEXTURE ****/
/*****************/
-RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t> > &p_data) {
+RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data) {
_THREAD_SAFE_METHOD_
VkImageCreateInfo image_create_info;
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- image_create_info.pNext = NULL;
+ image_create_info.pNext = nullptr;
image_create_info.flags = 0;
- VkImageFormatListCreateInfoKHR format_list_create_info;
- Vector<VkFormat> allowed_formats;
+#ifndef _MSC_VER
+#warning TODO check for support via RenderingDevice to enable on mobile when possible
+#endif
+
+#ifndef ANDROID_ENABLED
+ // vkCreateImage fails with format list on Android (VK_ERROR_OUT_OF_HOST_MEMORY)
+ VkImageFormatListCreateInfoKHR format_list_create_info; //keep out of the if, needed for creation
+ Vector<VkFormat> allowed_formats; //keep out of the if, needed for creation
+#endif
if (p_format.shareable_formats.size()) {
image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+
+#ifndef ANDROID_ENABLED
+
for (int i = 0; i < p_format.shareable_formats.size(); i++) {
allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]);
}
format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
- format_list_create_info.pNext = NULL;
+ format_list_create_info.pNext = nullptr;
format_list_create_info.viewFormatCount = allowed_formats.size();
format_list_create_info.pViewFormats = allowed_formats.ptr();
image_create_info.pNext = &format_list_create_info;
@@ -1583,7 +1594,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
"If supplied a list of shareable formats, the current format must be present in the list");
ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(),
"If supplied a list of shareable formats, the current view format override must be present in the list");
+#endif
}
+
if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) {
image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
@@ -1665,7 +1678,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_create_info.queueFamilyIndexCount = 0;
- image_create_info.pQueueFamilyIndices = NULL;
+ image_create_info.pQueueFamilyIndices = nullptr;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
uint32_t required_mipmaps = get_image_required_mipmaps(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth);
@@ -1744,8 +1757,8 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
allocInfo.requiredFlags = 0;
allocInfo.preferredFlags = 0;
allocInfo.memoryTypeBits = 0;
- allocInfo.pool = NULL;
- allocInfo.pUserData = NULL;
+ allocInfo.pool = nullptr;
+ allocInfo.pUserData = nullptr;
Texture texture;
@@ -1759,6 +1772,8 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
texture.depth = image_create_info.extent.depth;
texture.layers = image_create_info.arrayLayers;
texture.mipmaps = image_create_info.mipLevels;
+ texture.base_mipmap = 0;
+ texture.base_layer = 0;
texture.usage_flags = p_format.usage_bits;
texture.samples = p_format.samples;
texture.allowed_shared_formats = p_format.shareable_formats;
@@ -1806,7 +1821,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- image_view_create_info.pNext = NULL;
+ image_view_create_info.pNext = nullptr;
image_view_create_info.flags = 0;
image_view_create_info.image = texture.image;
@@ -1852,7 +1867,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
- err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view);
+ err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
if (err) {
vmaDestroyImage(allocator, texture.image, texture.allocation);
@@ -1863,7 +1878,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -1877,7 +1892,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers;
- vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
RID id = texture_owner.make_rid(texture);
@@ -1910,7 +1925,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- image_view_create_info.pNext = NULL;
+ image_view_create_info.pNext = nullptr;
image_view_create_info.flags = 0;
image_view_create_info.image = texture.image;
@@ -1961,7 +1976,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
- VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view);
+ VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateImageView failed with error " + itos(err) + ".");
texture.owner = p_with_texture;
@@ -1999,10 +2014,12 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height);
texture.mipmaps = 1;
texture.layers = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1;
+ texture.base_mipmap = p_mipmap;
+ texture.base_layer = p_layer;
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- image_view_create_info.pNext = NULL;
+ image_view_create_info.pNext = nullptr;
image_view_create_info.flags = 0;
image_view_create_info.image = texture.image;
@@ -2059,7 +2076,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
- VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view);
+ VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateImageView failed with error " + itos(err) + ".");
texture.owner = p_with_texture;
@@ -2121,7 +2138,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.oldLayout = texture->layout;
@@ -2136,7 +2153,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
uint32_t mipmap_offset = 0;
@@ -2169,7 +2186,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
uint8_t *write_ptr;
{ //map
- void *data_ptr = NULL;
+ void *data_ptr = nullptr;
VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr);
ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
write_ptr = (uint8_t *)data_ptr;
@@ -2258,7 +2275,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
@@ -2272,7 +2289,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
return OK;
@@ -2380,7 +2397,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
{ //Source image barrier
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_memory_barrier.oldLayout = tex->layout;
@@ -2395,7 +2412,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
uint32_t computed_w = tex->width;
@@ -2437,7 +2454,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
{ //restore src
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
@@ -2451,7 +2468,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
image_memory_barrier.subresourceRange.baseArrayLayer = p_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
_flush(true);
@@ -2546,7 +2563,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
{ //Source
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_memory_barrier.oldLayout = src_tex->layout;
@@ -2561,12 +2578,12 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
{ //Dest
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.oldLayout = dst_tex->layout;
@@ -2581,7 +2598,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
//COPY
@@ -2617,7 +2634,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
{ //restore src
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
@@ -2631,14 +2648,14 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
{ //make dst readable
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
@@ -2653,7 +2670,160 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
image_memory_barrier.subresourceRange.layerCount = 1;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
+ }
+ }
+
+ return OK;
+}
+Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw) {
+ _THREAD_SAFE_METHOD_
+
+ Texture *src_tex = texture_owner.getornull(p_from_texture);
+ ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
+
+ ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER,
+ "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER,
+ "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved.");
+
+ ERR_FAIL_COND_V_MSG(src_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Source texture must be 2D (or a slice of a 3D/Cube texture)");
+ ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");
+
+ Texture *dst_tex = texture_owner.getornull(p_to_texture);
+ ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER);
+
+ ERR_FAIL_COND_V_MSG(p_sync_with_draw && dst_tex->bound, ERR_INVALID_PARAMETER,
+ "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture.");
+ ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER,
+ "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved.");
+
+ ERR_FAIL_COND_V_MSG(dst_tex->type != TEXTURE_TYPE_2D, ERR_INVALID_PARAMETER, "Destination texture must be 2D (or a slice of a 3D/Cube texture).");
+ ERR_FAIL_COND_V_MSG(dst_tex->samples != TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Destination texture must not be multisampled.");
+
+ ERR_FAIL_COND_V_MSG(src_tex->format != dst_tex->format, ERR_INVALID_PARAMETER, "Source and Destionation textures must be the same format.");
+ ERR_FAIL_COND_V_MSG(src_tex->width != dst_tex->width && src_tex->height != dst_tex->height && src_tex->depth != dst_tex->depth, ERR_INVALID_PARAMETER, "Source and Destionation textures must have the same dimensions.");
+
+ ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER,
+ "Source and destination texture must be of the same type (color or depth).");
+
+ VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer;
+
+ {
+
+ //PRE Copy the image
+
+ { //Source
+ VkImageMemoryBarrier image_memory_barrier;
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.pNext = nullptr;
+ image_memory_barrier.srcAccessMask = 0;
+ image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ image_memory_barrier.oldLayout = src_tex->layout;
+ image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.image = src_tex->image;
+ image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask;
+ image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap;
+ image_memory_barrier.subresourceRange.levelCount = 1;
+ image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer;
+ image_memory_barrier.subresourceRange.layerCount = 1;
+
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
+ }
+ { //Dest
+ VkImageMemoryBarrier image_memory_barrier;
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.pNext = nullptr;
+ image_memory_barrier.srcAccessMask = 0;
+ image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ image_memory_barrier.oldLayout = dst_tex->layout;
+ image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.image = dst_tex->image;
+ image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
+ image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap;
+ image_memory_barrier.subresourceRange.levelCount = 1;
+ image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer;
+ image_memory_barrier.subresourceRange.layerCount = 1;
+
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
+ }
+
+ //COPY
+
+ {
+
+ VkImageResolve image_copy_region;
+ image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask;
+ image_copy_region.srcSubresource.baseArrayLayer = src_tex->base_layer;
+ image_copy_region.srcSubresource.layerCount = 1;
+ image_copy_region.srcSubresource.mipLevel = src_tex->base_mipmap;
+ image_copy_region.srcOffset.x = 0;
+ image_copy_region.srcOffset.y = 0;
+ image_copy_region.srcOffset.z = 0;
+
+ image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask;
+ image_copy_region.dstSubresource.baseArrayLayer = dst_tex->base_layer;
+ image_copy_region.dstSubresource.layerCount = 1;
+ image_copy_region.dstSubresource.mipLevel = dst_tex->base_mipmap;
+ image_copy_region.dstOffset.x = 0;
+ image_copy_region.dstOffset.y = 0;
+ image_copy_region.dstOffset.z = 0;
+
+ image_copy_region.extent.width = src_tex->width;
+ image_copy_region.extent.height = src_tex->height;
+ image_copy_region.extent.depth = src_tex->depth;
+
+ vkCmdResolveImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
+ }
+
+ // RESTORE LAYOUT for SRC and DST
+
+ { //restore src
+ VkImageMemoryBarrier image_memory_barrier;
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.pNext = nullptr;
+ image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ image_memory_barrier.newLayout = src_tex->layout;
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.image = src_tex->image;
+ image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask;
+ image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap;
+ image_memory_barrier.subresourceRange.levelCount = 1;
+ image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer;
+ image_memory_barrier.subresourceRange.layerCount = 1;
+
+ vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
+ }
+
+ { //make dst readable
+
+ VkImageMemoryBarrier image_memory_barrier;
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.pNext = nullptr;
+ image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ image_memory_barrier.newLayout = dst_tex->layout;
+
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.image = dst_tex->image;
+ image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap;
+ image_memory_barrier.subresourceRange.levelCount = 1;
+ image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer;
+ image_memory_barrier.subresourceRange.layerCount = 1;
+
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
}
@@ -2691,7 +2861,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = 0;
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.oldLayout = src_tex->layout;
@@ -2701,13 +2871,13 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = src_tex->image;
image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap;
+ image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap;
image_memory_barrier.subresourceRange.levelCount = p_mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer;
+ image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer;
image_memory_barrier.subresourceRange.layerCount = p_layers;
layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
VkClearColorValue clear_color;
@@ -2718,9 +2888,9 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
VkImageSubresourceRange range;
range.aspectMask = src_tex->read_aspect_mask;
- range.baseArrayLayer = p_base_layer;
+ range.baseArrayLayer = src_tex->base_layer + p_base_layer;
range.layerCount = p_layers;
- range.baseMipLevel = p_base_mipmap;
+ range.baseMipLevel = src_tex->base_mipmap + p_base_mipmap;
range.levelCount = p_mipmaps;
vkCmdClearColorImage(command_buffer, src_tex->image, layout, &clear_color, 1, &range);
@@ -2729,7 +2899,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
@@ -2739,12 +2909,12 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = src_tex->image;
image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap;
+ image_memory_barrier.subresourceRange.baseMipLevel = src_tex->base_mipmap + p_base_mipmap;
image_memory_barrier.subresourceRange.levelCount = p_mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer;
+ image_memory_barrier.subresourceRange.baseArrayLayer = src_tex->base_layer + p_base_layer;
image_memory_barrier.subresourceRange.layerCount = p_layers;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
return OK;
@@ -2839,6 +3009,21 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
}
} break;
+ case INITIAL_ACTION_DROP: {
+ if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ } else {
+ description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ }
+ } break;
case INITIAL_ACTION_CONTINUE: {
if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
@@ -2944,27 +3129,27 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount = 0; //unsupported for now
- subpass.pInputAttachments = NULL;
+ subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = color_references.size();
subpass.pColorAttachments = color_references.ptr();
subpass.pDepthStencilAttachment = depth_stencil_references.ptr();
subpass.pResolveAttachments = resolve_references.ptr();
subpass.preserveAttachmentCount = 0;
- subpass.pPreserveAttachments = NULL;
+ subpass.pPreserveAttachments = nullptr;
VkRenderPassCreateInfo render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- render_pass_create_info.pNext = NULL;
+ render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
render_pass_create_info.attachmentCount = attachments.size();
render_pass_create_info.pAttachments = attachments.ptr();
render_pass_create_info.subpassCount = 1;
render_pass_create_info.pSubpasses = &subpass;
render_pass_create_info.dependencyCount = 0;
- render_pass_create_info.pDependencies = NULL;
+ render_pass_create_info.pDependencies = nullptr;
VkRenderPass render_pass;
- VkResult res = vkCreateRenderPass(device, &render_pass_create_info, NULL, &render_pass);
+ VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass failed with error " + itos(res) + ".");
if (r_color_attachment_count) {
@@ -3083,7 +3268,7 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
VkSamplerCreateInfo sampler_create_info;
sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
- sampler_create_info.pNext = NULL;
+ sampler_create_info.pNext = nullptr;
sampler_create_info.flags = 0;
sampler_create_info.magFilter = p_state.mag_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
@@ -3113,7 +3298,7 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw;
VkSampler sampler;
- VkResult res = vkCreateSampler(device, &sampler_create_info, NULL, &sampler);
+ VkResult res = vkCreateSampler(device, &sampler_create_info, nullptr, &sampler);
ERR_FAIL_COND_V_MSG(res, RID(), "vkCreateSampler failed with error " + itos(res) + ".");
return sampler_owner.make_rid(sampler);
@@ -3178,7 +3363,7 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
}
vdcache.create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vdcache.create_info.pNext = NULL;
+ vdcache.create_info.pNext = nullptr;
vdcache.create_info.flags = 0;
vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_formats.size();
@@ -3546,7 +3731,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
}
layout_binding.binding = binding;
layout_binding.stageFlags = shader_stage_masks[p_stage];
- layout_binding.pImmutableSamplers = NULL; //no support for this yet
+ layout_binding.pImmutableSamplers = nullptr; //no support for this yet
info.stages = 1 << p_stage;
info.binding = binding;
@@ -3568,8 +3753,8 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages) {
//descriptor layouts
- Vector<Vector<VkDescriptorSetLayoutBinding> > set_bindings;
- Vector<Vector<UniformInfo> > uniform_info;
+ Vector<Vector<VkDescriptorSetLayoutBinding>> set_bindings;
+ Vector<Vector<UniformInfo>> uniform_info;
Shader::PushConstant push_constant;
push_constant.push_constant_size = 0;
push_constant.push_constants_vk_stage = 0;
@@ -3600,7 +3785,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader.");
uint32_t binding_count = 0;
- result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, NULL);
+ result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, nullptr);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating descriptor bindings.");
@@ -3742,7 +3927,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
layout_binding.binding = info.binding;
layout_binding.stageFlags = shader_stage_masks[stage];
- layout_binding.pImmutableSamplers = NULL; //no support for this yet
+ layout_binding.pImmutableSamplers = nullptr; //no support for this yet
info.stages = 1 << stage;
info.binding = info.binding;
@@ -3760,7 +3945,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
if (stage == SHADER_STAGE_VERTEX) {
uint32_t iv_count = 0;
- result = spvReflectEnumerateInputVariables(&module, &iv_count, NULL);
+ result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating input variables.");
@@ -3783,7 +3968,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
if (stage == SHADER_STAGE_FRAGMENT) {
uint32_t ov_count = 0;
- result = spvReflectEnumerateOutputVariables(&module, &ov_count, NULL);
+ result = spvReflectEnumerateOutputVariables(&module, &ov_count, nullptr);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating output variables.");
@@ -3803,7 +3988,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
}
}
uint32_t pc_count = 0;
- result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, NULL);
+ result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, nullptr);
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating push constants.");
@@ -3817,7 +4002,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining push constants.");
#if 0
- if (pconstants[0] == NULL) {
+ if (pconstants[0] == nullptr) {
FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE);
f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t));
memdelete(f);
@@ -3857,7 +4042,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
for (int i = 0; i < p_stages.size(); i++) {
VkShaderModuleCreateInfo shader_module_create_info;
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shader_module_create_info.pNext = NULL;
+ shader_module_create_info.pNext = nullptr;
shader_module_create_info.flags = 0;
shader_module_create_info.codeSize = p_stages[i].spir_v.size();
const uint8_t *r = p_stages[i].spir_v.ptr();
@@ -3865,7 +4050,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
shader_module_create_info.pCode = (const uint32_t *)r;
VkShaderModule module;
- VkResult res = vkCreateShaderModule(device, &shader_module_create_info, NULL, &module);
+ VkResult res = vkCreateShaderModule(device, &shader_module_create_info, nullptr, &module);
if (res) {
success = false;
error_text = "Error (" + itos(res) + ") creating shader module for stage: " + String(shader_stage_names[p_stages[i].shader_stage]);
@@ -3882,12 +4067,12 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
VkPipelineShaderStageCreateInfo shader_stage;
shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- shader_stage.pNext = NULL;
+ shader_stage.pNext = nullptr;
shader_stage.flags = 0;
shader_stage.stage = shader_stage_bits[p_stages[i].shader_stage];
shader_stage.module = module;
shader_stage.pName = "main";
- shader_stage.pSpecializationInfo = NULL;
+ shader_stage.pSpecializationInfo = nullptr;
shader.pipeline_stages.push_back(shader_stage);
}
@@ -3900,13 +4085,13 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
//empty ones are fine if they were not used according to spec (binding count will be 0)
VkDescriptorSetLayoutCreateInfo layout_create_info;
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layout_create_info.pNext = NULL;
+ layout_create_info.pNext = nullptr;
layout_create_info.flags = 0;
layout_create_info.bindingCount = set_bindings[i].size();
layout_create_info.pBindings = set_bindings[i].ptr();
VkDescriptorSetLayout layout;
- VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &layout);
+ VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, nullptr, &layout);
if (res) {
error_text = "Error (" + itos(res) + ") creating descriptor set layout for set " + itos(i);
success = false;
@@ -3943,7 +4128,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
//create pipeline layout
VkPipelineLayoutCreateInfo pipeline_layout_create_info;
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipeline_layout_create_info.pNext = NULL;
+ pipeline_layout_create_info.pNext = nullptr;
pipeline_layout_create_info.flags = 0;
pipeline_layout_create_info.setLayoutCount = shader.sets.size();
@@ -3965,10 +4150,10 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
pipeline_layout_create_info.pPushConstantRanges = &push_constant_range;
} else {
pipeline_layout_create_info.pushConstantRangeCount = 0;
- pipeline_layout_create_info.pPushConstantRanges = NULL;
+ pipeline_layout_create_info.pPushConstantRanges = nullptr;
}
- VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, NULL, &shader.pipeline_layout);
+ VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &shader.pipeline_layout);
if (err) {
error_text = "Error (" + itos(err) + ") creating pipeline layout.";
@@ -3979,11 +4164,11 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages
if (!success) {
//clean up if failed
for (int i = 0; i < shader.pipeline_stages.size(); i++) {
- vkDestroyShaderModule(device, shader.pipeline_stages[i].module, NULL);
+ vkDestroyShaderModule(device, shader.pipeline_stages[i].module, nullptr);
}
for (int i = 0; i < shader.sets.size(); i++) {
- vkDestroyDescriptorSetLayout(device, shader.sets[i].descriptor_set_layout, NULL);
+ vkDestroyDescriptorSetLayout(device, shader.sets[i].descriptor_set_layout, nullptr);
}
ERR_FAIL_V_MSG(RID(), error_text);
@@ -4064,7 +4249,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF
VkBufferViewCreateInfo view_create_info;
view_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
- view_create_info.pNext = NULL;
+ view_create_info.pNext = nullptr;
view_create_info.flags = 0;
view_create_info.buffer = texture_buffer.buffer.buffer;
view_create_info.format = vulkan_formats[p_format];
@@ -4073,7 +4258,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF
texture_buffer.view = VK_NULL_HANDLE;
- VkResult res = vkCreateBufferView(device, &view_create_info, NULL, &texture_buffer.view);
+ VkResult res = vkCreateBufferView(device, &view_create_info, nullptr, &texture_buffer.view);
if (res) {
_buffer_free(&texture_buffer.buffer);
ERR_FAIL_V_MSG(RID(), "Unable to create buffer view, error " + itos(res) + ".");
@@ -4088,7 +4273,7 @@ RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_a
descriptor_pools[p_key] = Set<DescriptorPool *>();
}
- DescriptorPool *pool = NULL;
+ DescriptorPool *pool = nullptr;
for (Set<DescriptorPool *>::Element *E = descriptor_pools[p_key].front(); E; E = E->next()) {
if (E->get()->usage < max_descriptors_per_pool) {
@@ -4104,7 +4289,7 @@ RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_a
VkDescriptorPoolCreateInfo descriptor_pool_create_info;
descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- descriptor_pool_create_info.pNext = NULL;
+ descriptor_pool_create_info.pNext = nullptr;
descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // can't think how somebody may NOT need this flag..
descriptor_pool_create_info.maxSets = max_descriptors_per_pool;
Vector<VkDescriptorPoolSize> sizes;
@@ -4169,10 +4354,10 @@ RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_a
descriptor_pool_create_info.poolSizeCount = sizes.size();
descriptor_pool_create_info.pPoolSizes = sizes.ptr();
- VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_create_info, NULL, &pool->pool);
+ VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &pool->pool);
if (res) {
memdelete(pool);
- ERR_FAIL_COND_V_MSG(res, NULL, "vkCreateDescriptorPool failed with error " + itos(res) + ".");
+ ERR_FAIL_COND_V_MSG(res, nullptr, "vkCreateDescriptorPool failed with error " + itos(res) + ".");
}
descriptor_pools[p_key].insert(pool);
}
@@ -4189,7 +4374,7 @@ void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key
ERR_FAIL_COND(p_pool->usage == 0);
p_pool->usage--;
if (p_pool->usage == 0) {
- vkDestroyDescriptorPool(device, p_pool->pool, NULL);
+ vkDestroyDescriptorPool(device, p_pool->pool, nullptr);
descriptor_pools[p_key].erase(p_pool);
memdelete(p_pool);
if (descriptor_pools[p_key].empty()) {
@@ -4223,9 +4408,9 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
DescriptorPoolKey pool_key;
//to keep them alive until update call
- List<Vector<VkDescriptorBufferInfo> > buffer_infos;
- List<Vector<VkBufferView> > buffer_views;
- List<Vector<VkDescriptorImageInfo> > image_infos;
+ List<Vector<VkDescriptorBufferInfo>> buffer_infos;
+ List<Vector<VkBufferView>> buffer_views;
+ List<Vector<VkDescriptorImageInfo>> image_infos;
//used for verification to make sure a uniform set does not use a framebuffer bound texture
Vector<RID> attachable_textures;
Vector<Texture *> mutable_sampled_textures;
@@ -4249,8 +4434,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
VkWriteDescriptorSet write; //common header
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write.pNext = NULL;
- write.dstSet = NULL; //will assign afterwards when everything is valid
+ write.pNext = nullptr;
+ write.dstSet = VK_NULL_HANDLE; //will assign afterwards when everything is valid
write.dstBinding = set_uniform.binding;
uint32_t type_size = 1;
@@ -4282,8 +4467,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
write.descriptorCount = uniform.ids.size();
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
- write.pBufferInfo = NULL;
- write.pTexelBufferView = NULL;
+ write.pBufferInfo = nullptr;
+ write.pTexelBufferView = nullptr;
type_size = uniform.ids.size();
@@ -4318,6 +4503,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]);
}
+ if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
+ //can also be used as storage, add to mutable sampled
+ mutable_sampled_textures.push_back(texture);
+ }
if (texture->owner.is_valid()) {
texture = texture_owner.getornull(texture->owner);
ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
@@ -4326,19 +4515,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info.push_back(img_info);
-
- if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- //can also be used as storage, add to mutable sampled
- mutable_sampled_textures.push_back(texture);
- }
}
write.dstArrayElement = 0;
write.descriptorCount = uniform.ids.size() / 2;
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
- write.pBufferInfo = NULL;
- write.pTexelBufferView = NULL;
+ write.pBufferInfo = nullptr;
+ write.pTexelBufferView = nullptr;
type_size = uniform.ids.size() / 2;
@@ -4363,13 +4547,18 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
VkDescriptorImageInfo img_info;
- img_info.sampler = NULL;
+ img_info.sampler = VK_NULL_HANDLE;
img_info.imageView = texture->view;
if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) {
attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j]);
}
+ if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
+ //can also be used as storage, add to mutable sampled
+ mutable_sampled_textures.push_back(texture);
+ }
+
if (texture->owner.is_valid()) {
texture = texture_owner.getornull(texture->owner);
ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
@@ -4378,19 +4567,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info.push_back(img_info);
-
- if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- //can also be used as storage, add to mutable sampled
- mutable_sampled_textures.push_back(texture);
- }
}
write.dstArrayElement = 0;
write.descriptorCount = uniform.ids.size();
write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
- write.pBufferInfo = NULL;
- write.pTexelBufferView = NULL;
+ write.pBufferInfo = nullptr;
+ write.pTexelBufferView = nullptr;
type_size = uniform.ids.size();
} break;
@@ -4416,9 +4600,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform.");
VkDescriptorImageInfo img_info;
- img_info.sampler = NULL;
+ img_info.sampler = VK_NULL_HANDLE;
img_info.imageView = texture->view;
+ if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
+ //can also be used as storage, add to mutable sampled
+ mutable_storage_textures.push_back(texture);
+ }
+
if (texture->owner.is_valid()) {
texture = texture_owner.getornull(texture->owner);
ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
@@ -4427,19 +4616,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
image_info.push_back(img_info);
-
- if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
- //can also be used as storage, add to mutable sampled
- mutable_storage_textures.push_back(texture);
- }
}
write.dstArrayElement = 0;
write.descriptorCount = uniform.ids.size();
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write.pImageInfo = image_infos.push_back(image_info)->get().ptr();
- write.pBufferInfo = NULL;
- write.pTexelBufferView = NULL;
+ write.pBufferInfo = nullptr;
+ write.pTexelBufferView = nullptr;
type_size = uniform.ids.size();
@@ -4467,7 +4651,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
write.dstArrayElement = 0;
write.descriptorCount = uniform.ids.size();
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- write.pImageInfo = NULL;
+ write.pImageInfo = nullptr;
write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr();
write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr();
@@ -4533,9 +4717,9 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
write.dstArrayElement = 0;
write.descriptorCount = 1;
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- write.pImageInfo = NULL;
+ write.pImageInfo = nullptr;
write.pBufferInfo = &buffer->buffer_info;
- write.pTexelBufferView = NULL;
+ write.pTexelBufferView = nullptr;
} break;
case UNIFORM_TYPE_STORAGE_BUFFER: {
@@ -4552,9 +4736,9 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
write.dstArrayElement = 0;
write.descriptorCount = 1;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- write.pImageInfo = NULL;
+ write.pImageInfo = nullptr;
write.pBufferInfo = &buffer->buffer_info;
- write.pTexelBufferView = NULL;
+ write.pTexelBufferView = nullptr;
} break;
case UNIFORM_TYPE_INPUT_ATTACHMENT: {
@@ -4578,7 +4762,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
VkDescriptorSetAllocateInfo descriptor_set_allocate_info;
descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- descriptor_set_allocate_info.pNext = NULL;
+ descriptor_set_allocate_info.pNext = nullptr;
descriptor_set_allocate_info.descriptorPool = pool->pool;
descriptor_set_allocate_info.descriptorSetCount = 1;
descriptor_set_allocate_info.pSetLayouts = &shader->sets[p_shader_set].descriptor_set_layout;
@@ -4619,7 +4803,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (int i = 0; i < writes.size(); i++) {
writes.write[i].dstSet = descriptor_set;
}
- vkUpdateDescriptorSets(device, writes.size(), writes.ptr(), 0, NULL);
+ vkUpdateDescriptorSets(device, writes.size(), writes.ptr(), 0, nullptr);
}
return id;
@@ -4638,7 +4822,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
VkPipelineStageFlags dst_stage_mask;
VkAccessFlags dst_access;
- Buffer *buffer = NULL;
+ Buffer *buffer = nullptr;
if (vertex_buffer_owner.owns(p_buffer)) {
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
@@ -4684,7 +4868,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
_THREAD_SAFE_METHOD_
- Buffer *buffer = NULL;
+ Buffer *buffer = nullptr;
if (vertex_buffer_owner.owns(p_buffer)) {
buffer = vertex_buffer_owner.getornull(p_buffer);
} else if (index_buffer_owner.owns(p_buffer)) {
@@ -4783,12 +4967,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
} else {
//does not use vertices
pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- pipeline_vertex_input_state_create_info.pNext = NULL;
+ pipeline_vertex_input_state_create_info.pNext = nullptr;
pipeline_vertex_input_state_create_info.flags = 0;
pipeline_vertex_input_state_create_info.vertexBindingDescriptionCount = 0;
- pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = NULL;
+ pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = nullptr;
pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0;
- pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = NULL;
+ pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = nullptr;
ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),
"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");
@@ -4799,7 +4983,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info;
input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- input_assembly_create_info.pNext = NULL;
+ input_assembly_create_info.pNext = nullptr;
input_assembly_create_info.flags = 0;
static const VkPrimitiveTopology topology_list[RENDER_PRIMITIVE_MAX] = {
@@ -4822,24 +5006,24 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
//tesselation
VkPipelineTessellationStateCreateInfo tesselation_create_info;
tesselation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
- tesselation_create_info.pNext = NULL;
+ tesselation_create_info.pNext = nullptr;
tesselation_create_info.flags = 0;
ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, RID());
tesselation_create_info.patchControlPoints = p_rasterization_state.patch_control_points;
VkPipelineViewportStateCreateInfo viewport_state_create_info;
viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewport_state_create_info.pNext = NULL;
+ viewport_state_create_info.pNext = nullptr;
viewport_state_create_info.flags = 0;
viewport_state_create_info.viewportCount = 1; //if VR extensions are supported at some point, this will have to be customizable in the framebuffer format
- viewport_state_create_info.pViewports = NULL;
+ viewport_state_create_info.pViewports = nullptr;
viewport_state_create_info.scissorCount = 1;
- viewport_state_create_info.pScissors = NULL;
+ viewport_state_create_info.pScissors = nullptr;
//rasterization
VkPipelineRasterizationStateCreateInfo rasterization_state_create_info;
rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterization_state_create_info.pNext = NULL;
+ rasterization_state_create_info.pNext = nullptr;
rasterization_state_create_info.flags = 0;
rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp;
rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives;
@@ -4862,7 +5046,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
//multisample
VkPipelineMultisampleStateCreateInfo multisample_state_create_info;
multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisample_state_create_info.pNext = NULL;
+ multisample_state_create_info.pNext = nullptr;
multisample_state_create_info.flags = 0;
multisample_state_create_info.rasterizationSamples = rasterization_sample_count[p_multisample_state.sample_count];
@@ -4882,7 +5066,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
}
multisample_state_create_info.pSampleMask = sample_mask.ptr();
} else {
- multisample_state_create_info.pSampleMask = NULL;
+ multisample_state_create_info.pSampleMask = nullptr;
}
multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
@@ -4892,7 +5076,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info;
depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- depth_stencil_state_create_info.pNext = NULL;
+ depth_stencil_state_create_info.pNext = nullptr;
depth_stencil_state_create_info.flags = 0;
depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test;
depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write;
@@ -4931,7 +5115,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
//blend state
VkPipelineColorBlendStateCreateInfo color_blend_state_create_info;
color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- color_blend_state_create_info.pNext = NULL;
+ color_blend_state_create_info.pNext = nullptr;
color_blend_state_create_info.flags = 0;
color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op;
ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID());
@@ -4988,7 +5172,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
VkPipelineDynamicStateCreateInfo dynamic_state_create_info;
dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
- dynamic_state_create_info.pNext = NULL;
+ dynamic_state_create_info.pNext = nullptr;
dynamic_state_create_info.flags = 0;
Vector<VkDynamicState> dynamic_states; //vulkan is weird..
@@ -5030,7 +5214,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info;
graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- graphics_pipeline_create_info.pNext = NULL;
+ graphics_pipeline_create_info.pNext = nullptr;
graphics_pipeline_create_info.flags = 0;
graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size();
@@ -5048,11 +5232,11 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
graphics_pipeline_create_info.renderPass = fb_format.render_pass;
graphics_pipeline_create_info.subpass = 0;
- graphics_pipeline_create_info.basePipelineHandle = NULL;
+ graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
graphics_pipeline_create_info.basePipelineIndex = 0;
RenderPipeline pipeline;
- VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline);
+ VkResult err = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &graphics_pipeline_create_info, nullptr, &pipeline.pipeline);
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateGraphicsPipelines failed with error " + itos(err) + ".");
pipeline.set_formats = shader->set_formats;
@@ -5116,16 +5300,16 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) {
VkComputePipelineCreateInfo compute_pipeline_create_info;
compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
- compute_pipeline_create_info.pNext = NULL;
+ compute_pipeline_create_info.pNext = nullptr;
compute_pipeline_create_info.flags = 0;
compute_pipeline_create_info.stage = shader->pipeline_stages[0];
compute_pipeline_create_info.layout = shader->pipeline_layout;
- compute_pipeline_create_info.basePipelineHandle = NULL;
+ compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
compute_pipeline_create_info.basePipelineIndex = 0;
ComputePipeline pipeline;
- VkResult err = vkCreateComputePipelines(device, NULL, 1, &compute_pipeline_create_info, NULL, &pipeline.pipeline);
+ VkResult err = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline);
ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + ".");
pipeline.set_formats = shader->set_formats;
@@ -5150,12 +5334,12 @@ bool RenderingDeviceVulkan::compute_pipeline_is_valid(RID p_pipeline) {
/**** SCREEN ****/
/****************/
-int RenderingDeviceVulkan::screen_get_width(int p_screen) const {
+int RenderingDeviceVulkan::screen_get_width(DisplayServer::WindowID p_screen) const {
_THREAD_SAFE_METHOD_
return context->window_get_width(p_screen);
}
-int RenderingDeviceVulkan::screen_get_height(int p_screen) const {
+int RenderingDeviceVulkan::screen_get_height(DisplayServer::WindowID p_screen) const {
_THREAD_SAFE_METHOD_
return context->window_get_height(p_screen);
@@ -5189,12 +5373,12 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuff
/**** DRAW LIST ****/
/*******************/
-RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(int p_screen, const Color &p_clear_color) {
+RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(DisplayServer::WindowID p_screen, const Color &p_clear_color) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time.");
- ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
draw_list = memnew(DrawList);
@@ -5207,7 +5391,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in
VkRenderPassBeginInfo render_pass_begin;
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin.pNext = NULL;
+ render_pass_begin.pNext = nullptr;
render_pass_begin.renderPass = context->window_get_render_pass(p_screen);
render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen);
@@ -5268,7 +5452,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
VkFramebufferCreateInfo framebuffer_create_info;
framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- framebuffer_create_info.pNext = NULL;
+ framebuffer_create_info.pNext = nullptr;
framebuffer_create_info.flags = 0;
framebuffer_create_info.renderPass = version.render_pass;
Vector<VkImageView> attachments;
@@ -5285,7 +5469,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
framebuffer_create_info.height = p_framebuffer->size.height;
framebuffer_create_info.layers = 1;
- VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, NULL, &version.framebuffer);
+ VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr, &version.framebuffer);
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkCreateFramebuffer failed with error " + itos(err) + ".");
p_framebuffer->framebuffers.insert(vk, version);
@@ -5301,7 +5485,7 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
VkRenderPassBeginInfo render_pass_begin;
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin.pNext = NULL;
+ render_pass_begin.pNext = nullptr;
render_pass_begin.renderPass = render_pass;
render_pass_begin.framebuffer = vkframebuffer;
@@ -5404,8 +5588,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time.");
- ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer);
ERR_FAIL_COND_V(!framebuffer, INVALID_ID);
@@ -5542,11 +5726,11 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
VkCommandPoolCreateInfo cmd_pool_info;
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- cmd_pool_info.pNext = NULL;
+ cmd_pool_info.pNext = nullptr;
cmd_pool_info.queueFamilyIndex = context->get_graphics_queue();
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- VkResult res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &split_draw_list_allocators.write[i].command_pool);
+ VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &split_draw_list_allocators.write[i].command_pool);
ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "vkCreateCommandPool failed with error " + itos(res) + ".");
for (int j = 0; j < frame_count; j++) {
@@ -5556,7 +5740,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
VkCommandBufferAllocateInfo cmdbuf;
//no command buffer exists, create it.
cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- cmdbuf.pNext = NULL;
+ cmdbuf.pNext = nullptr;
cmdbuf.commandPool = split_draw_list_allocators[i].command_pool;
cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
cmdbuf.commandBufferCount = 1;
@@ -5593,7 +5777,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
VkCommandBufferInheritanceInfo inheritance_info;
inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
- inheritance_info.pNext = NULL;
+ inheritance_info.pNext = nullptr;
inheritance_info.renderPass = render_pass;
inheritance_info.subpass = 0;
inheritance_info.framebuffer = vkframebuffer;
@@ -5603,21 +5787,21 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmdbuf_begin.pNext = NULL;
+ cmdbuf_begin.pNext = nullptr;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
cmdbuf_begin.pInheritanceInfo = &inheritance_info;
VkResult res = vkResetCommandBuffer(command_buffer, 0);
if (res) {
memdelete_arr(draw_list);
- draw_list = NULL;
+ draw_list = nullptr;
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkResetCommandBuffer failed with error " + itos(res) + ".");
}
res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin);
if (res) {
memdelete_arr(draw_list);
- draw_list = NULL;
+ draw_list = nullptr;
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkBeginCommandBuffer failed with error " + itos(res) + ".");
}
@@ -5658,30 +5842,30 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) {
if (p_id < 0) {
- return NULL;
+ return nullptr;
}
if (!draw_list) {
- return NULL;
+ return nullptr;
} else if (p_id == ID_TYPE_DRAW_LIST) {
if (draw_list_split) {
- return NULL;
+ return nullptr;
}
return draw_list;
} else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) {
if (!draw_list_split) {
- return NULL;
+ return nullptr;
}
uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); //mask
if (index >= draw_list_count) {
- return NULL;
+ return nullptr;
}
return &draw_list[index];
} else {
- return NULL;
+ return nullptr;
}
}
@@ -5927,7 +6111,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
#endif
if (!dl->state.sets[i].bound) {
//All good, see if this requires re-binding
- vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, NULL);
+ vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, nullptr);
dl->state.sets[i].bound = true;
}
}
@@ -6046,13 +6230,13 @@ void RenderingDeviceVulkan::draw_list_end() {
vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers);
vkCmdEndRenderPass(frames[frame].draw_command_buffer);
memdelete_arr(draw_list);
- draw_list = NULL;
+ draw_list = nullptr;
} else {
//just end the list
vkCmdEndRenderPass(draw_list->command_buffer);
memdelete(draw_list);
- draw_list = NULL;
+ draw_list = nullptr;
}
for (int i = 0; i < draw_list_bound_textures.size(); i++) {
@@ -6085,8 +6269,8 @@ void RenderingDeviceVulkan::draw_list_end() {
RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin() {
- ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time.");
- ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
+ ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
compute_list = memnew(ComputeList);
compute_list->command_buffer = frames[frame].draw_command_buffer;
@@ -6189,7 +6373,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.oldLayout = textures_to_sampled[i]->layout;
@@ -6199,12 +6383,12 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = textures_to_sampled[i]->image;
image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = 0;
+ image_memory_barrier.subresourceRange.baseMipLevel = textures_to_sampled[i]->base_mipmap;
image_memory_barrier.subresourceRange.levelCount = textures_to_sampled[i]->mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = 0;
+ image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_sampled[i]->base_layer;
image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers;
- vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
textures_to_sampled[i]->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6220,7 +6404,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.oldLayout = textures_to_storage[i]->layout;
@@ -6230,12 +6414,12 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = textures_to_storage[i]->image;
image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = 0;
+ image_memory_barrier.subresourceRange.baseMipLevel = textures_to_storage[i]->base_mipmap;
image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = 0;
+ image_memory_barrier.subresourceRange.baseArrayLayer = textures_to_storage[i]->base_layer;
image_memory_barrier.subresourceRange.layerCount = textures_to_storage[i]->layers;
- vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL;
@@ -6329,7 +6513,7 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
#endif
if (!cl->state.sets[i].bound) {
//All good, see if this requires re-binding
- vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, NULL);
+ vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr);
cl->state.sets[i].bound = true;
}
}
@@ -6352,7 +6536,7 @@ void RenderingDeviceVulkan::compute_list_end() {
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_memory_barrier.pNext = NULL;
+ image_memory_barrier.pNext = nullptr;
image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
image_memory_barrier.oldLayout = E->get()->layout;
@@ -6362,18 +6546,18 @@ void RenderingDeviceVulkan::compute_list_end() {
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = E->get()->image;
image_memory_barrier.subresourceRange.aspectMask = E->get()->read_aspect_mask;
- image_memory_barrier.subresourceRange.baseMipLevel = 0;
+ image_memory_barrier.subresourceRange.baseMipLevel = E->get()->base_mipmap;
image_memory_barrier.subresourceRange.levelCount = E->get()->mipmaps;
- image_memory_barrier.subresourceRange.baseArrayLayer = 0;
+ image_memory_barrier.subresourceRange.baseArrayLayer = E->get()->base_layer;
image_memory_barrier.subresourceRange.layerCount = E->get()->layers;
- vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
+ vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
E->get()->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
memdelete(compute_list);
- compute_list = NULL;
+ compute_list = nullptr;
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
#else
@@ -6389,7 +6573,7 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame
VkRenderPassBeginInfo render_pass_begin;
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin.pNext = NULL;
+ render_pass_begin.pNext = nullptr;
render_pass_begin.renderPass = context->get_render_pass();
render_pass_begin.framebuffer = context->get_frame_framebuffer(frame);
@@ -6547,9 +6731,9 @@ void RenderingDeviceVulkan::swap_buffers() {
{
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmdbuf_begin.pNext = NULL;
+ cmdbuf_begin.pNext = nullptr;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- cmdbuf_begin.pInheritanceInfo = NULL;
+ cmdbuf_begin.pInheritanceInfo = nullptr;
VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0);
ERR_FAIL_COND_MSG(err, "vkResetCommandBuffer failed with error " + itos(err) + ".");
@@ -6588,7 +6772,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
while (frames[p_frame].render_pipelines_to_dispose_of.front()) {
RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();
- vkDestroyPipeline(device, pipeline->pipeline, NULL);
+ vkDestroyPipeline(device, pipeline->pipeline, nullptr);
frames[p_frame].render_pipelines_to_dispose_of.pop_front();
}
@@ -6596,7 +6780,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
while (frames[p_frame].compute_pipelines_to_dispose_of.front()) {
ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get();
- vkDestroyPipeline(device, pipeline->pipeline, NULL);
+ vkDestroyPipeline(device, pipeline->pipeline, nullptr);
frames[p_frame].compute_pipelines_to_dispose_of.pop_front();
}
@@ -6615,7 +6799,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
while (frames[p_frame].buffer_views_to_dispose_of.front()) {
VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get();
- vkDestroyBufferView(device, buffer_view, NULL);
+ vkDestroyBufferView(device, buffer_view, nullptr);
frames[p_frame].buffer_views_to_dispose_of.pop_front();
}
@@ -6626,15 +6810,15 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
//descriptor set layout for each set
for (int i = 0; i < shader->sets.size(); i++) {
- vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, NULL);
+ vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr);
}
//pipeline layout
- vkDestroyPipelineLayout(device, shader->pipeline_layout, NULL);
+ vkDestroyPipelineLayout(device, shader->pipeline_layout, nullptr);
//shaders themselves
for (int i = 0; i < shader->pipeline_stages.size(); i++) {
- vkDestroyShaderModule(device, shader->pipeline_stages[i].module, NULL);
+ vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr);
}
frames[p_frame].shaders_to_dispose_of.pop_front();
@@ -6644,7 +6828,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
while (frames[p_frame].samplers_to_dispose_of.front()) {
VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get();
- vkDestroySampler(device, sampler, NULL);
+ vkDestroySampler(device, sampler, nullptr);
frames[p_frame].samplers_to_dispose_of.pop_front();
}
@@ -6655,8 +6839,8 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
for (Map<Framebuffer::VersionKey, Framebuffer::Version>::Element *E = framebuffer->framebuffers.front(); E; E = E->next()) {
//first framebuffer, then render pass because it depends on it
- vkDestroyFramebuffer(device, E->get().framebuffer, NULL);
- vkDestroyRenderPass(device, E->get().render_pass, NULL);
+ vkDestroyFramebuffer(device, E->get().framebuffer, nullptr);
+ vkDestroyRenderPass(device, E->get().render_pass, nullptr);
}
frames[p_frame].framebuffers_to_dispose_of.pop_front();
@@ -6669,7 +6853,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
if (texture->bound) {
WARN_PRINT("Deleted a texture while it was bound..");
}
- vkDestroyImageView(device, texture->view, NULL);
+ vkDestroyImageView(device, texture->view, nullptr);
if (texture->owner.is_null()) {
//actually owns the image and the allocation too
vmaDestroyImage(allocator, texture->image, texture->allocation);
@@ -6708,9 +6892,9 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
if (p_current_frame) {
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmdbuf_begin.pNext = NULL;
+ cmdbuf_begin.pNext = nullptr;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- cmdbuf_begin.pInheritanceInfo = NULL;
+ cmdbuf_begin.pInheritanceInfo = nullptr;
VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
@@ -6720,9 +6904,9 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
if (p_current_frame) {
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmdbuf_begin.pNext = NULL;
+ cmdbuf_begin.pNext = nullptr;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- cmdbuf_begin.pInheritanceInfo = NULL;
+ cmdbuf_begin.pInheritanceInfo = nullptr;
VkResult err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
@@ -6757,11 +6941,11 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
{ //create command pool, one per frame is recommended
VkCommandPoolCreateInfo cmd_pool_info;
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- cmd_pool_info.pNext = NULL;
+ cmd_pool_info.pNext = nullptr;
cmd_pool_info.queueFamilyIndex = p_context->get_graphics_queue();
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- VkResult res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &frames[i].command_pool);
+ VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &frames[i].command_pool);
ERR_FAIL_COND_MSG(res, "vkCreateCommandPool failed with error " + itos(res) + ".");
}
@@ -6770,7 +6954,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
VkCommandBufferAllocateInfo cmdbuf;
//no command buffer exists, create it.
cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- cmdbuf.pNext = NULL;
+ cmdbuf.pNext = nullptr;
cmdbuf.commandPool = frames[i].command_pool;
cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmdbuf.commandBufferCount = 1;
@@ -6787,12 +6971,12 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
VkQueryPoolCreateInfo query_pool_create_info;
query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_create_info.flags = 0;
- query_pool_create_info.pNext = NULL;
+ query_pool_create_info.pNext = nullptr;
query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
query_pool_create_info.queryCount = max_timestamp_query_elements;
query_pool_create_info.pipelineStatistics = 0;
- vkCreateQueryPool(device, &query_pool_create_info, NULL, &frames[i].timestamp_pool);
+ vkCreateQueryPool(device, &query_pool_create_info, nullptr, &frames[i].timestamp_pool);
frames[i].timestamp_names = memnew_arr(String, max_timestamp_query_elements);
frames[i].timestamp_cpu_values = memnew_arr(uint64_t, max_timestamp_query_elements);
@@ -6809,9 +6993,9 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
//setting up things can be done in the meantime until swap_buffers(), which is called before advance.
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmdbuf_begin.pNext = NULL;
+ cmdbuf_begin.pNext = nullptr;
cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- cmdbuf_begin.pInheritanceInfo = NULL;
+ cmdbuf_begin.pInheritanceInfo = nullptr;
VkResult err = vkBeginCommandBuffer(frames[0].setup_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
@@ -6853,11 +7037,11 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
//check to make sure DescriptorPoolKey is good
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
- draw_list = NULL;
+ draw_list = nullptr;
draw_list_count = 0;
draw_list_split = false;
- compute_list = NULL;
+ compute_list = nullptr;
}
template <class T>
@@ -6880,7 +7064,7 @@ void RenderingDeviceVulkan::capture_timestamp(const String &p_name, bool p_sync_
VkMemoryBarrier memoryBarrier;
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
- memoryBarrier.pNext = NULL;
+ memoryBarrier.pNext = nullptr;
memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
@@ -6912,7 +7096,7 @@ void RenderingDeviceVulkan::capture_timestamp(const String &p_name, bool p_sync_
VK_ACCESS_HOST_READ_BIT |
VK_ACCESS_HOST_WRITE_BIT;
- vkCmdPipelineBarrier(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, NULL, 0, NULL);
+ vkCmdPipelineBarrier(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
}
vkCmdWriteTimestamp(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frames[frame].timestamp_pool, frames[frame].timestamp_count);
frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
@@ -6928,9 +7112,42 @@ uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const {
return frames[frame].index;
}
+static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
+ uint64_t u1 = (u & 0xffffffff);
+ uint64_t v1 = (v & 0xffffffff);
+ uint64_t t = (u1 * v1);
+ uint64_t w3 = (t & 0xffffffff);
+ uint64_t k = (t >> 32);
+
+ u >>= 32;
+ t = (u * v1) + k;
+ k = (t & 0xffffffff);
+ uint64_t w1 = (t >> 32);
+
+ v >>= 32;
+ t = (u1 * v) + k;
+ k = (t >> 32);
+
+ h = (u * v) + w1 + k;
+ l = (t << 32) + w3;
+}
+
uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
- return frames[frame].timestamp_result_values[p_index] * limits.timestampPeriod;
+
+ // this sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs.
+ // so, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible
+ // need to do 128 bits fixed point multiplication to get the rigth value
+
+ uint64_t shift_bits = 16;
+
+ uint64_t h, l;
+
+ mult64to128(frames[frame].timestamp_result_values[p_index], uint64_t(double(limits.timestampPeriod) * double(1 << shift_bits)), h, l);
+ l >>= shift_bits;
+ l |= h << (64 - shift_bits);
+
+ return l;
}
uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
@@ -7030,8 +7247,8 @@ void RenderingDeviceVulkan::finalize() {
for (int i = 0; i < frame_count; i++) {
int f = (frame + i) % frame_count;
_free_pending_resources(f);
- vkDestroyCommandPool(device, frames[i].command_pool, NULL);
- vkDestroyQueryPool(device, frames[i].timestamp_pool, NULL);
+ vkDestroyCommandPool(device, frames[i].command_pool, nullptr);
+ vkDestroyQueryPool(device, frames[i].timestamp_pool, nullptr);
memdelete_arr(frames[i].timestamp_names);
memdelete_arr(frames[i].timestamp_cpu_values);
memdelete_arr(frames[i].timestamp_result_names);
@@ -7040,7 +7257,7 @@ void RenderingDeviceVulkan::finalize() {
}
for (int i = 0; i < split_draw_list_allocators.size(); i++) {
- vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, NULL);
+ vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, nullptr);
}
memdelete_arr(frames);
@@ -7048,6 +7265,19 @@ void RenderingDeviceVulkan::finalize() {
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation);
}
+ vmaDestroyAllocator(allocator);
+
+ while (vertex_formats.size()) {
+ Map<VertexFormatID, VertexDescriptionCache>::Element *temp = vertex_formats.front();
+ memdelete_arr(temp->get().bindings);
+ memdelete_arr(temp->get().attributes);
+ vertex_formats.erase(temp);
+ }
+
+ for (int i = 0; i < framebuffer_formats.size(); i++) {
+ vkDestroyRenderPass(device, framebuffer_formats[i].render_pass, nullptr);
+ }
+ framebuffer_formats.clear();
//all these should be clear at this point
ERR_FAIL_COND(descriptor_pools.size());
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 30c10e922e..2c92f3466e 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -34,11 +34,13 @@
#include "core/oa_hash_map.h"
#include "core/os/thread_safe.h"
#include "core/rid_owner.h"
-#include "servers/visual/rendering_device.h"
+#include "servers/rendering/rendering_device.h"
#ifdef DEBUG_ENABLED
+#ifndef _DEBUG
#define _DEBUG
#endif
+#endif
#include "vk_mem_alloc.h"
#include <vulkan/vulkan.h>
//todo:
@@ -78,7 +80,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h);
uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format);
static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format);
- static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = NULL, uint32_t *r_blockh = NULL, uint32_t *r_depth = NULL);
+ static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = nullptr, uint32_t *r_blockh = nullptr, uint32_t *r_depth = nullptr);
static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
static bool format_has_stencil(DataFormat p_format);
@@ -98,8 +100,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkDevice device;
- Map<RID, Set<RID> > dependency_map; //IDs to IDs that depend on it
- Map<RID, Set<RID> > reverse_dependency_map; //same as above, but in reverse
+ Map<RID, Set<RID>> dependency_map; //IDs to IDs that depend on it
+ Map<RID, Set<RID>> reverse_dependency_map; //same as above, but in reverse
void _add_dependency(RID p_id, RID p_depends_on);
void _free_dependencies(RID p_id);
@@ -136,6 +138,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t layers;
uint32_t mipmaps;
uint32_t usage_flags;
+ uint32_t base_mipmap;
+ uint32_t base_layer;
Vector<DataFormat> allowed_shared_formats;
@@ -207,8 +211,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkDescriptorBufferInfo buffer_info; //used for binding
Buffer() {
size = 0;
- buffer = NULL;
- allocation = NULL;
+ buffer = VK_NULL_HANDLE;
+ allocation = nullptr;
}
};
@@ -260,7 +264,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
};
- VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = NULL);
+ VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = nullptr);
// This is a cache and it's never freed, it ensures
// IDs for a given format are always unique.
@@ -602,7 +606,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t usage;
};
- Map<DescriptorPoolKey, Set<DescriptorPool *> > descriptor_pools;
+ Map<DescriptorPoolKey, Set<DescriptorPool *>> descriptor_pools;
uint32_t max_descriptors_per_pool;
DescriptorPool *_descriptor_pool_allocate(const DescriptorPoolKey &p_key);
@@ -968,7 +972,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
void _free_rids(T &p_owner, const char *p_type);
public:
- virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t> > &p_data = Vector<Vector<uint8_t> >());
+ virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D);
@@ -981,6 +985,7 @@ public:
virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false);
virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false);
+ virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw = false);
/*********************/
/**** FRAMEBUFFER ****/
@@ -1052,15 +1057,15 @@ public:
/**** SCREEN ****/
/****************/
- virtual int screen_get_width(int p_screen = 0) const;
- virtual int screen_get_height(int p_screen = 0) const;
+ virtual int screen_get_width(DisplayServer::WindowID p_screen = 0) const;
+ virtual int screen_get_height(DisplayServer::WindowID p_screen = 0) const;
virtual FramebufferFormatID screen_get_framebuffer_format() const;
/********************/
/**** DRAW LISTS ****/
/********************/
- virtual DrawListID draw_list_begin_for_screen(int p_screen = 0, const Color &p_clear_color = Color());
+ virtual DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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());
virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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());
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index c8ff342713..0ce9ccce4c 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -51,20 +51,20 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
void *pUserData) {
// This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors.
- if (strstr(pCallbackData->pMessage, "Mapping an image with layout") != NULL &&
- strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != NULL) {
+ if (strstr(pCallbackData->pMessage, "Mapping an image with layout") != nullptr &&
+ strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr) {
return VK_FALSE;
}
// This needs to be ignored because Validator is wrong here.
- if (strstr(pCallbackData->pMessage, "SPIR-V module not valid: Pointer operand") != NULL &&
- strstr(pCallbackData->pMessage, "must be a memory object") != NULL) {
+ if (strstr(pCallbackData->pMessage, "SPIR-V module not valid: Pointer operand") != nullptr &&
+ strstr(pCallbackData->pMessage, "must be a memory object") != nullptr) {
return VK_FALSE;
}
// Workaround for Vulkan-Loader usability bug: https://github.com/KhronosGroup/Vulkan-Loader/issues/262.
- if (strstr(pCallbackData->pMessage, "wrong ELF class: ELFCLASS32") != NULL) {
+ if (strstr(pCallbackData->pMessage, "wrong ELF class: ELFCLASS32") != nullptr) {
return VK_FALSE;
}
- if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != NULL) {
+ if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
return VK_FALSE;
}
@@ -92,7 +92,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
"\n\t\tObject[" + String::num_int64(object) + "]" +
" - " + string_VkObjectType(pCallbackData->pObjects[object].objectType) +
", Handle " + String::num_int64(pCallbackData->pObjects[object].objectHandle);
- if (NULL != pCallbackData->pObjects[object].pObjectName && strlen(pCallbackData->pObjects[object].pObjectName) > 0) {
+ if (nullptr != pCallbackData->pObjects[object].pObjectName && strlen(pCallbackData->pObjects[object].pObjectName) > 0) {
objects_string += ", Name \"" + String(pCallbackData->pObjects[object].pObjectName) + "\"";
}
}
@@ -172,7 +172,7 @@ Error VulkanContext::_create_validation_layers() {
"VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation",
"VK_LAYER_GOOGLE_unique_objects" };
VkBool32 validation_found = 0;
- err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
+ err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
const char **instance_validation_layers = instance_validation_layers_alt1;
if (instance_layer_count > 0) {
@@ -222,12 +222,12 @@ Error VulkanContext::_initialize_extensions() {
VkBool32 platformSurfaceExtFound = 0;
memset(extension_names, 0, sizeof(extension_names));
- err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL);
+ err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
if (instance_extension_count > 0) {
VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count);
- err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, instance_extensions);
+ err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions);
if (err) {
free(instance_extensions);
ERR_FAIL_V(ERR_CANT_CREATE);
@@ -286,7 +286,7 @@ Error VulkanContext::_create_physical_device() {
CharString namecs = name.utf8();
const VkApplicationInfo app = {
/*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*pApplicationName*/ cs.get_data(),
/*applicationVersion*/ 0,
/*pEngineName*/ namecs.get_data(),
@@ -295,7 +295,7 @@ Error VulkanContext::_create_physical_device() {
};
VkInstanceCreateInfo inst_info = {
/*sType*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*pApplicationInfo*/ &app,
/*enabledLayerCount*/ enabled_layer_count,
@@ -313,7 +313,7 @@ Error VulkanContext::_create_physical_device() {
if (use_validation_layers) {
// VK_EXT_debug_utils style
dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
- dbg_messenger_create_info.pNext = NULL;
+ dbg_messenger_create_info.pNext = nullptr;
dbg_messenger_create_info.flags = 0;
dbg_messenger_create_info.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
@@ -327,7 +327,7 @@ Error VulkanContext::_create_physical_device() {
uint32_t gpu_count;
- VkResult err = vkCreateInstance(&inst_info, NULL, &inst);
+ VkResult err = vkCreateInstance(&inst_info, nullptr, &inst);
ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
"Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
"vkCreateInstance Failure");
@@ -342,7 +342,7 @@ Error VulkanContext::_create_physical_device() {
"vkCreateInstance Failure");
/* Make initial call to query gpu_count, then second call for gpu info*/
- err = vkEnumeratePhysicalDevices(inst, &gpu_count, NULL);
+ err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
ERR_FAIL_COND_V_MSG(gpu_count == 0, ERR_CANT_CREATE,
@@ -366,12 +366,12 @@ Error VulkanContext::_create_physical_device() {
enabled_extension_count = 0;
memset(extension_names, 0, sizeof(extension_names));
- err = vkEnumerateDeviceExtensionProperties(gpu, NULL, &device_extension_count, NULL);
+ err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
if (device_extension_count > 0) {
VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count);
- err = vkEnumerateDeviceExtensionProperties(gpu, NULL, &device_extension_count, device_extensions);
+ err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions);
if (err) {
free(device_extensions);
ERR_FAIL_V(ERR_CANT_CREATE);
@@ -449,16 +449,16 @@ Error VulkanContext::_create_physical_device() {
(PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdInsertDebugUtilsLabelEXT");
SetDebugUtilsObjectNameEXT =
(PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(inst, "vkSetDebugUtilsObjectNameEXT");
- if (NULL == CreateDebugUtilsMessengerEXT || NULL == DestroyDebugUtilsMessengerEXT ||
- NULL == SubmitDebugUtilsMessageEXT || NULL == CmdBeginDebugUtilsLabelEXT ||
- NULL == CmdEndDebugUtilsLabelEXT || NULL == CmdInsertDebugUtilsLabelEXT ||
- NULL == SetDebugUtilsObjectNameEXT) {
+ if (nullptr == CreateDebugUtilsMessengerEXT || nullptr == DestroyDebugUtilsMessengerEXT ||
+ nullptr == SubmitDebugUtilsMessageEXT || nullptr == CmdBeginDebugUtilsLabelEXT ||
+ nullptr == CmdEndDebugUtilsLabelEXT || nullptr == CmdInsertDebugUtilsLabelEXT ||
+ nullptr == SetDebugUtilsObjectNameEXT) {
ERR_FAIL_V_MSG(ERR_CANT_CREATE,
"GetProcAddr: Failed to init VK_EXT_debug_utils\n"
"GetProcAddr: Failure");
}
- err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, NULL, &dbg_messenger);
+ err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, nullptr, &dbg_messenger);
switch (err) {
case VK_SUCCESS:
break;
@@ -478,7 +478,7 @@ Error VulkanContext::_create_physical_device() {
vkGetPhysicalDeviceProperties(gpu, &gpu_props);
/* Call with NULL data to get count */
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, NULL);
+ vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
queue_props = (VkQueueFamilyProperties *)malloc(queue_family_count * sizeof(VkQueueFamilyProperties));
@@ -492,7 +492,7 @@ Error VulkanContext::_create_physical_device() {
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
- ERR_FAIL_COND_V_MSG(fp##entrypoint == NULL, ERR_CANT_CREATE, \
+ ERR_FAIL_COND_V_MSG(fp##entrypoint == nullptr, ERR_CANT_CREATE, \
"vkGetInstanceProcAddr failed to find vk" #entrypoint); \
}
@@ -511,7 +511,7 @@ Error VulkanContext::_create_device() {
float queue_priorities[1] = { 0.0 };
VkDeviceQueueCreateInfo queues[2];
queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queues[0].pNext = NULL;
+ queues[0].pNext = nullptr;
queues[0].queueFamilyIndex = graphics_queue_family_index;
queues[0].queueCount = 1;
queues[0].pQueuePriorities = queue_priorities;
@@ -519,12 +519,12 @@ Error VulkanContext::_create_device() {
VkDeviceCreateInfo sdevice = {
/*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*queueCreateInfoCount*/ 1,
/*pQueueCreateInfos*/ queues,
/*enabledLayerCount*/ 0,
- /*ppEnabledLayerNames*/ NULL,
+ /*ppEnabledLayerNames*/ nullptr,
/*enabledExtensionCount*/ enabled_extension_count,
/*ppEnabledExtensionNames*/ (const char *const *)extension_names,
/*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here
@@ -532,14 +532,14 @@ Error VulkanContext::_create_device() {
};
if (separate_present_queue) {
queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queues[1].pNext = NULL;
+ queues[1].pNext = nullptr;
queues[1].queueFamilyIndex = present_queue_family_index;
queues[1].queueCount = 1;
queues[1].pQueuePriorities = queue_priorities;
queues[1].flags = 0;
sdevice.queueCreateInfoCount = 2;
}
- err = vkCreateDevice(gpu, &sdevice, NULL, &device);
+ err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
return OK;
}
@@ -593,12 +593,12 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) {
_create_device();
- static PFN_vkGetDeviceProcAddr g_gdpa = NULL;
+ static PFN_vkGetDeviceProcAddr g_gdpa = nullptr;
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
if (!g_gdpa) g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(inst, "vkGetDeviceProcAddr"); \
fp##entrypoint = (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \
- ERR_FAIL_COND_V_MSG(fp##entrypoint == NULL, ERR_CANT_CREATE, \
+ ERR_FAIL_COND_V_MSG(fp##entrypoint == nullptr, ERR_CANT_CREATE, \
"vkGetDeviceProcAddr failed to find vk" #entrypoint); \
}
@@ -622,7 +622,7 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) {
// Get the list of VkFormat's that are supported:
uint32_t formatCount;
- VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, NULL);
+ VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, surfFormats);
@@ -662,7 +662,7 @@ Error VulkanContext::_create_semaphores() {
// rendering and waiting for drawing to be complete before presenting
VkSemaphoreCreateInfo semaphoreCreateInfo = {
/*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
};
@@ -670,21 +670,21 @@ Error VulkanContext::_create_semaphores() {
// ahead of the image presents
VkFenceCreateInfo fence_ci = {
/*sType*/ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ VK_FENCE_CREATE_SIGNALED_BIT
};
for (uint32_t i = 0; i < FRAME_LAG; i++) {
- err = vkCreateFence(device, &fence_ci, NULL, &fences[i]);
+ err = vkCreateFence(device, &fence_ci, nullptr, &fences[i]);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- err = vkCreateSemaphore(device, &semaphoreCreateInfo, NULL, &image_acquired_semaphores[i]);
+ err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &image_acquired_semaphores[i]);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- err = vkCreateSemaphore(device, &semaphoreCreateInfo, NULL, &draw_complete_semaphores[i]);
+ err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &draw_complete_semaphores[i]);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
if (separate_present_queue) {
- err = vkCreateSemaphore(device, &semaphoreCreateInfo, NULL, &image_ownership_semaphores[i]);
+ err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &image_ownership_semaphores[i]);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
}
@@ -696,7 +696,9 @@ Error VulkanContext::_create_semaphores() {
return OK;
}
-int VulkanContext::_window_create(VkSurfaceKHR p_surface, int p_width, int p_height) {
+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);
if (!queues_initialized) {
// We use a single GPU, but we need a surface to initialize the
@@ -710,39 +712,37 @@ int VulkanContext::_window_create(VkSurfaceKHR p_surface, int p_width, int p_hei
window.width = p_width;
window.height = p_height;
Error err = _update_swap_chain(&window);
- ERR_FAIL_COND_V(err != OK, -1);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
- int id = last_window_id;
- windows[id] = window;
- last_window_id++;
- return id;
+ windows[p_window_id] = window;
+ return OK;
}
-void VulkanContext::window_resize(int p_window, int p_width, int p_height) {
+void VulkanContext::window_resize(DisplayServer::WindowID p_window, int p_width, int p_height) {
ERR_FAIL_COND(!windows.has(p_window));
windows[p_window].width = p_width;
windows[p_window].height = p_height;
_update_swap_chain(&windows[p_window]);
}
-int VulkanContext::window_get_width(int p_window) {
+int VulkanContext::window_get_width(DisplayServer::WindowID p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), -1);
return windows[p_window].width;
}
-int VulkanContext::window_get_height(int p_window) {
+int VulkanContext::window_get_height(DisplayServer::WindowID p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), -1);
return windows[p_window].height;
}
-VkRenderPass VulkanContext::window_get_render_pass(int p_window) {
+VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
Window *w = &windows[p_window];
//vulkan use of currentbuffer
return w->render_pass;
}
-VkFramebuffer VulkanContext::window_get_framebuffer(int p_window) {
+VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE);
Window *w = &windows[p_window];
@@ -750,10 +750,10 @@ VkFramebuffer VulkanContext::window_get_framebuffer(int p_window) {
return w->swapchain_image_resources[w->current_buffer].framebuffer;
}
-void VulkanContext::window_destroy(int p_window_id) {
+void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) {
ERR_FAIL_COND(!windows.has(p_window_id));
_clean_up_swap_chain(&windows[p_window_id]);
- vkDestroySurfaceKHR(inst, windows[p_window_id].surface, NULL);
+ vkDestroySurfaceKHR(inst, windows[p_window_id].surface, nullptr);
windows.erase(p_window_id);
}
@@ -765,20 +765,20 @@ Error VulkanContext::_clean_up_swap_chain(Window *window) {
vkDeviceWaitIdle(device);
//this destroys images associated it seems
- fpDestroySwapchainKHR(device, window->swapchain, NULL);
+ fpDestroySwapchainKHR(device, window->swapchain, nullptr);
window->swapchain = VK_NULL_HANDLE;
- vkDestroyRenderPass(device, window->render_pass, NULL);
+ vkDestroyRenderPass(device, window->render_pass, nullptr);
if (window->swapchain_image_resources) {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
- vkDestroyImageView(device, window->swapchain_image_resources[i].view, NULL);
- vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, NULL);
+ vkDestroyImageView(device, window->swapchain_image_resources[i].view, nullptr);
+ vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, nullptr);
}
free(window->swapchain_image_resources);
- window->swapchain_image_resources = NULL;
+ window->swapchain_image_resources = nullptr;
}
if (separate_present_queue) {
- vkDestroyCommandPool(device, window->present_cmd_pool, NULL);
+ vkDestroyCommandPool(device, window->present_cmd_pool, nullptr);
}
return OK;
}
@@ -796,7 +796,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
uint32_t presentModeCount;
- err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, NULL);
+ err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
ERR_FAIL_COND_V(!presentModes, ERR_CANT_CREATE);
@@ -918,7 +918,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
VkSwapchainCreateInfoKHR swapchain_ci = {
/*sType*/ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*surface*/ window->surface,
/*minImageCount*/ desiredNumOfSwapchainImages,
@@ -932,19 +932,19 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*imageUsage*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
/*imageSharingMode*/ VK_SHARING_MODE_EXCLUSIVE,
/*queueFamilyIndexCount*/ 0,
- /*pQueueFamilyIndices*/ NULL,
+ /*pQueueFamilyIndices*/ nullptr,
/*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform,
/*compositeAlpha*/ compositeAlpha,
/*presentMode*/ swapchainPresentMode,
/*clipped*/ true,
- /*oldSwapchain*/ NULL,
+ /*oldSwapchain*/ VK_NULL_HANDLE,
};
- err = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &window->swapchain);
+ err = fpCreateSwapchainKHR(device, &swapchain_ci, nullptr, &window->swapchain);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
uint32_t sp_image_count;
- err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, NULL);
+ err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, nullptr);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
if (swapchainImageCount == 0) {
@@ -972,7 +972,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
VkImageViewCreateInfo color_image_view = {
/*sType*/ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*image*/ swapchainImages[i],
/*viewType*/ VK_IMAGE_VIEW_TYPE_2D,
@@ -994,7 +994,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
color_image_view.image = window->swapchain_image_resources[i].image;
- err = vkCreateImageView(device, &color_image_view, NULL, &window->swapchain_image_resources[i].view);
+ err = vkCreateImageView(device, &color_image_view, nullptr, &window->swapchain_image_resources[i].view);
if (err) {
free(swapchainImages);
ERR_FAIL_V(ERR_CANT_CREATE);
@@ -1028,33 +1028,33 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*flags*/ 0,
/*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS,
/*inputAttachmentCount*/ 0,
- /*pInputAttachments*/ NULL,
+ /*pInputAttachments*/ nullptr,
/*colorAttachmentCount*/ 1,
/*pColorAttachments*/ &color_reference,
- /*pResolveAttachments*/ NULL,
- /*pDepthStencilAttachment*/ NULL,
+ /*pResolveAttachments*/ nullptr,
+ /*pDepthStencilAttachment*/ nullptr,
/*preserveAttachmentCount*/ 0,
- /*pPreserveAttachments*/ NULL,
+ /*pPreserveAttachments*/ nullptr,
};
const VkRenderPassCreateInfo rp_info = {
/*sTyp*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*attachmentCount*/ 1,
/*pAttachments*/ &attachment,
/*subpassCount*/ 1,
/*pSubpasses*/ &subpass,
/*dependencyCount*/ 0,
- /*pDependencies*/ NULL,
+ /*pDependencies*/ nullptr,
};
- err = vkCreateRenderPass(device, &rp_info, NULL, &window->render_pass);
+ err = vkCreateRenderPass(device, &rp_info, nullptr, &window->render_pass);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
const VkFramebufferCreateInfo fb_info = {
/*sType*/ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*renderPass*/ window->render_pass,
/*attachmentCount*/ 1,
@@ -1064,7 +1064,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
/*layers*/ 1,
};
- err = vkCreateFramebuffer(device, &fb_info, NULL, &window->swapchain_image_resources[i].framebuffer);
+ err = vkCreateFramebuffer(device, &fb_info, nullptr, &window->swapchain_image_resources[i].framebuffer);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
}
@@ -1074,15 +1074,15 @@ Error VulkanContext::_update_swap_chain(Window *window) {
if (separate_present_queue) {
const VkCommandPoolCreateInfo present_cmd_pool_info = {
/*sType*/ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ 0,
/*queueFamilyIndex*/ present_queue_family_index,
};
- err = vkCreateCommandPool(device, &present_cmd_pool_info, NULL, &window->present_cmd_pool);
+ err = vkCreateCommandPool(device, &present_cmd_pool_info, nullptr, &window->present_cmd_pool);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
const VkCommandBufferAllocateInfo present_cmd_info = {
/*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*commandPool*/ window->present_cmd_pool,
/*level*/ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
/*commandBufferCount*/ 1,
@@ -1094,16 +1094,16 @@ Error VulkanContext::_update_swap_chain(Window *window) {
const VkCommandBufferBeginInfo cmd_buf_info = {
/*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*flags*/ VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
- /*pInheritanceInfo*/ NULL,
+ /*pInheritanceInfo*/ nullptr,
};
err = vkBeginCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkImageMemoryBarrier image_ownership_barrier = {
/*sType*/ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*srcAccessMask*/ 0,
/*dstAccessMask*/ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
/*oldLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
@@ -1115,7 +1115,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
};
vkCmdPipelineBarrier(window->swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &image_ownership_barrier);
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_ownership_barrier);
err = vkEndCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
@@ -1163,16 +1163,16 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
//use a fence to wait for everything done
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.pNext = NULL;
- submit_info.pWaitDstStageMask = NULL;
+ submit_info.pNext = nullptr;
+ submit_info.pWaitDstStageMask = nullptr;
submit_info.waitSemaphoreCount = 0;
- submit_info.pWaitSemaphores = NULL;
+ submit_info.pWaitSemaphores = nullptr;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = command_buffer_queue.ptr();
submit_info.signalSemaphoreCount = 0;
- submit_info.pSignalSemaphores = NULL;
+ submit_info.pSignalSemaphores = nullptr;
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
- command_buffer_queue.write[0] = NULL;
+ command_buffer_queue.write[0] = nullptr;
ERR_FAIL_COND(err);
vkDeviceWaitIdle(device);
}
@@ -1183,14 +1183,14 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.pNext = NULL;
- submit_info.pWaitDstStageMask = NULL;
+ submit_info.pNext = nullptr;
+ submit_info.pWaitDstStageMask = nullptr;
submit_info.waitSemaphoreCount = 0;
- submit_info.pWaitSemaphores = NULL;
+ submit_info.pWaitSemaphores = nullptr;
submit_info.commandBufferCount = command_buffer_count - 1;
submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1;
submit_info.signalSemaphoreCount = 0;
- submit_info.pSignalSemaphores = NULL;
+ submit_info.pSignalSemaphores = nullptr;
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
ERR_FAIL_COND(err);
vkDeviceWaitIdle(device);
@@ -1274,10 +1274,10 @@ Error VulkanContext::swap_buffers() {
// engine has fully released ownership to the application, and it is
// okay to render to the image.
- const VkCommandBuffer *commands_ptr = NULL;
+ const VkCommandBuffer *commands_ptr = nullptr;
uint32_t commands_to_submit = 0;
- if (command_buffer_queue[0] == NULL) {
+ if (command_buffer_queue[0] == nullptr) {
//no setup command, but commands to submit, submit from the first and skip command
if (command_buffer_count > 1) {
commands_ptr = command_buffer_queue.ptr() + 1;
@@ -1291,7 +1291,7 @@ Error VulkanContext::swap_buffers() {
VkPipelineStageFlags pipe_stage_flags;
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.pNext = NULL;
+ submit_info.pNext = nullptr;
submit_info.pWaitDstStageMask = &pipe_stage_flags;
pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
@@ -1303,7 +1303,7 @@ Error VulkanContext::swap_buffers() {
err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- command_buffer_queue.write[0] = NULL;
+ command_buffer_queue.write[0] = nullptr;
command_buffer_count = 1;
if (separate_present_queue) {
@@ -1339,13 +1339,13 @@ Error VulkanContext::swap_buffers() {
// otherwise wait for draw complete
VkPresentInfoKHR present = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
- /*pNext*/ NULL,
+ /*pNext*/ nullptr,
/*waitSemaphoreCount*/ 1,
/*pWaitSemaphores*/ (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index],
/*swapchainCount*/ 0,
- /*pSwapchain*/ NULL,
- /*pImageIndices*/ NULL,
- /*pResults*/ NULL,
+ /*pSwapchain*/ nullptr,
+ /*pImageIndices*/ nullptr,
+ /*pResults*/ nullptr,
};
VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size());
@@ -1483,25 +1483,35 @@ VkPhysicalDeviceLimits VulkanContext::get_device_limits() const {
}
VulkanContext::VulkanContext() {
- queue_props = NULL;
+ queue_props = nullptr;
command_buffer_count = 0;
- instance_validation_layers = NULL;
+ instance_validation_layers = nullptr;
use_validation_layers = true;
VK_KHR_incremental_present_enabled = true;
VK_GOOGLE_display_timing_enabled = true;
command_buffer_queue.resize(1); //first one is the setup command always
- command_buffer_queue.write[0] = NULL;
+ command_buffer_queue.write[0] = nullptr;
command_buffer_count = 1;
queues_initialized = false;
buffers_prepared = false;
swapchainImageCount = 0;
- last_window_id = 0;
}
VulkanContext::~VulkanContext() {
if (queue_props) {
free(queue_props);
}
+ for (uint32_t i = 0; i < FRAME_LAG; i++) {
+ vkDestroyFence(device, fences[i], nullptr);
+ vkDestroySemaphore(device, image_acquired_semaphores[i], nullptr);
+ vkDestroySemaphore(device, draw_complete_semaphores[i], nullptr);
+ if (separate_present_queue) {
+ vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr);
+ }
+ }
+ DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr);
+ vkDestroyDevice(device, nullptr);
+ vkDestroyInstance(inst, nullptr);
}
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 458cb6d793..e587104e3c 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -34,6 +34,7 @@
#include "core/error_list.h"
#include "core/map.h"
#include "core/ustring.h"
+#include "servers/display_server.h"
#include <vulkan/vulkan.h>
class VulkanContext {
@@ -44,8 +45,6 @@ class VulkanContext {
FRAME_LAG = 2
};
- bool use_validation_layers;
-
VkInstance inst;
VkSurfaceKHR surface;
VkPhysicalDevice gpu;
@@ -106,8 +105,7 @@ class VulkanContext {
}
};
- Map<int, Window> windows;
- int last_window_id;
+ Map<DisplayServer::WindowID, Window> windows;
uint32_t swapchainImageCount;
//commands
@@ -173,7 +171,7 @@ protected:
virtual const char *_get_platform_surface_extension() const = 0;
// virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0;
- virtual int _window_create(VkSurfaceKHR p_surface, int p_width, int p_height);
+ virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height);
VkInstance _get_instance() {
return inst;
@@ -181,18 +179,20 @@ protected:
bool buffers_prepared;
+ bool use_validation_layers;
+
public:
VkDevice get_device();
VkPhysicalDevice get_physical_device();
int get_swapchain_image_count() const;
uint32_t get_graphics_queue() const;
- void window_resize(int p_window_id, int p_width, int p_height);
- int window_get_width(int p_window = 0);
- int window_get_height(int p_window = 0);
- void window_destroy(int p_window_id);
- VkFramebuffer window_get_framebuffer(int p_window = 0);
- VkRenderPass window_get_render_pass(int p_window = 0);
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
+ int window_get_width(DisplayServer::WindowID p_window = 0);
+ int window_get_height(DisplayServer::WindowID p_window = 0);
+ void window_destroy(DisplayServer::WindowID p_window_id);
+ VkFramebuffer window_get_framebuffer(DisplayServer::WindowID p_window = 0);
+ VkRenderPass window_get_render_pass(DisplayServer::WindowID p_window = 0);
VkFormat get_screen_format() const;
VkPhysicalDeviceLimits get_device_limits() const;
diff --git a/drivers/wasapi/SCsub b/drivers/wasapi/SCsub
index 4c24925192..4e1b5f2a36 100644
--- a/drivers/wasapi/SCsub
+++ b/drivers/wasapi/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
# Driver source files
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index fa78771993..ab2976f02c 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -54,10 +54,10 @@ const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
-#define SAFE_RELEASE(memory) \
- if ((memory) != NULL) { \
- (memory)->Release(); \
- (memory) = NULL; \
+#define SAFE_RELEASE(memory) \
+ if ((memory) != nullptr) { \
+ (memory)->Release(); \
+ (memory) = nullptr; \
}
#define REFTIMES_PER_SEC 10000000
@@ -75,11 +75,11 @@ class CMMNotificationClient : public IMMNotificationClient {
public:
CMMNotificationClient() :
_cRef(1),
- _pEnumerator(NULL) {}
+ _pEnumerator(nullptr) {}
virtual ~CMMNotificationClient() {
- if ((_pEnumerator) != NULL) {
+ if ((_pEnumerator) != nullptr) {
(_pEnumerator)->Release();
- (_pEnumerator) = NULL;
+ (_pEnumerator) = nullptr;
}
}
@@ -103,7 +103,7 @@ public:
AddRef();
*ppvInterface = (IMMNotificationClient *)this;
} else {
- *ppvInterface = NULL;
+ *ppvInterface = nullptr;
return E_NOINTERFACE;
}
return S_OK;
@@ -143,23 +143,23 @@ static CMMNotificationClient notif_client;
Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) {
WAVEFORMATEX *pwfex;
- IMMDeviceEnumerator *enumerator = NULL;
- IMMDevice *device = NULL;
+ IMMDeviceEnumerator *enumerator = nullptr;
+ IMMDevice *device = nullptr;
- CoInitialize(NULL);
+ CoInitialize(nullptr);
- HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
+ HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
if (p_device->device_name == "Default") {
hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device);
} else {
- IMMDeviceCollection *devices = NULL;
+ IMMDeviceCollection *devices = nullptr;
hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- LPWSTR strId = NULL;
+ LPWSTR strId = nullptr;
bool found = false;
UINT count = 0;
@@ -167,12 +167,12 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
for (ULONG i = 0; i < count && !found; i++) {
- IMMDevice *tmp_device = NULL;
+ IMMDevice *tmp_device = nullptr;
hr = devices->Item(i, &tmp_device);
ERR_BREAK(hr != S_OK);
- IPropertyStore *props = NULL;
+ IPropertyStore *props = nullptr;
hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
ERR_BREAK(hr != S_OK);
@@ -202,7 +202,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
CoTaskMemFree(strId);
}
- if (device == NULL) {
+ if (device == nullptr) {
hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device);
}
}
@@ -224,7 +224,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
}
- hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&p_device->audio_client);
+ hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
SAFE_RELEASE(device)
if (reinit) {
@@ -246,7 +246,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
print_verbose("WASAPI: wBitsPerSample = " + itos(pwfex->wBitsPerSample));
print_verbose("WASAPI: cbSize = " + itos(pwfex->cbSize));
- WAVEFORMATEX *closest = NULL;
+ WAVEFORMATEX *closest = nullptr;
hr = p_device->audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, pwfex, &closest);
if (hr == S_FALSE) {
WARN_PRINT("WASAPI: Mix format is not supported by the Device");
@@ -295,7 +295,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
}
- hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL);
+ hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, nullptr);
ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
if (p_capture) {
@@ -424,14 +424,14 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
Array list;
- IMMDeviceCollection *devices = NULL;
- IMMDeviceEnumerator *enumerator = NULL;
+ IMMDeviceCollection *devices = nullptr;
+ IMMDeviceEnumerator *enumerator = nullptr;
list.push_back(String("Default"));
- CoInitialize(NULL);
+ CoInitialize(nullptr);
- HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
+ HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
ERR_FAIL_COND_V(hr != S_OK, Array());
hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
@@ -442,12 +442,12 @@ Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
ERR_FAIL_COND_V(hr != S_OK, Array());
for (ULONG i = 0; i < count; i++) {
- IMMDevice *device = NULL;
+ IMMDevice *device = nullptr;
hr = devices->Item(i, &device);
ERR_BREAK(hr != S_OK);
- IPropertyStore *props = NULL;
+ IPropertyStore *props = nullptr;
hr = device->OpenPropertyStore(STGM_READ, &props);
ERR_BREAK(hr != S_OK);
@@ -594,7 +594,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
// Check how much frames are available on the WASAPI buffer
UINT32 write_frames = MIN(ad->buffer_frames - cur_frames, avail_frames);
if (write_frames > 0) {
- BYTE *buffer = NULL;
+ BYTE *buffer = nullptr;
hr = ad->audio_output.render_client->GetBuffer(write_frames, &buffer);
if (hr == S_OK) {
@@ -693,7 +693,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
HRESULT hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
if (hr == S_OK) {
while (packet_length != 0) {
- hr = ad->audio_input.capture_client->GetBuffer(&data, &num_frames_available, &flags, NULL, NULL);
+ hr = ad->audio_input.capture_client->GetBuffer(&data, &num_frames_available, &flags, nullptr, nullptr);
ERR_BREAK(hr != S_OK);
// fixme: Only works for floating point atm
@@ -796,7 +796,7 @@ void AudioDriverWASAPI::finish() {
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
finish_capture_device();
@@ -855,7 +855,7 @@ String AudioDriverWASAPI::capture_get_device() {
AudioDriverWASAPI::AudioDriverWASAPI() {
- thread = NULL;
+ thread = nullptr;
samples_in.clear();
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index 3ea61c6010..01a4666812 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -59,9 +59,9 @@ class AudioDriverWASAPI : public AudioDriver {
String new_device;
AudioDeviceWASAPI() :
- audio_client(NULL),
- render_client(NULL),
- capture_client(NULL),
+ audio_client(nullptr),
+ render_client(nullptr),
+ capture_client(nullptr),
active(false),
format_tag(0),
bits_per_sample(0),
diff --git a/drivers/windows/SCsub b/drivers/windows/SCsub
index 28b315ae66..91e1140b75 100644
--- a/drivers/windows/SCsub
+++ b/drivers/windows/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index cf09f79832..a8618b05d7 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -67,7 +67,7 @@ Error DirAccessWindows::list_dir_begin() {
_cishidden = false;
list_dir_end();
- p->h = FindFirstFileExW((current_dir + "\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, NULL, 0);
+ p->h = FindFirstFileExW((current_dir + "\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, nullptr, 0);
return (p->h == INVALID_HANDLE_VALUE) ? ERR_CANT_OPEN : OK;
}
@@ -175,7 +175,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
p_dir = "\\\\?\\" + p_dir; //done according to
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx
- success = CreateDirectoryW(p_dir.c_str(), NULL);
+ success = CreateDirectoryW(p_dir.c_str(), nullptr);
err = GetLastError();
if (success) {
@@ -206,7 +206,13 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) {
if (p_include_drive) {
return current_dir;
} else {
- return current_dir.right(current_dir.find(":") + 1);
+ if (_get_root_string() == "") {
+ int p = current_dir.find(":");
+ if (p != -1) {
+ return current_dir.right(p + 1);
+ }
+ }
+ return current_dir;
}
}
@@ -269,11 +275,11 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {
if (p_path.to_lower() == p_new_path.to_lower()) {
WCHAR tmpfile[MAX_PATH];
- if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), NULL, 0, tmpfile)) {
+ if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), nullptr, 0, tmpfile)) {
return FAILED;
}
- if (!::ReplaceFileW(tmpfile, p_path.c_str(), NULL, 0, NULL, NULL)) {
+ if (!::ReplaceFileW(tmpfile, p_path.c_str(), nullptr, 0, nullptr, nullptr)) {
DeleteFileW(tmpfile);
return FAILED;
}
@@ -343,7 +349,7 @@ FileType DirAccessWindows::get_file_type(const String& p_file) const {
size_t DirAccessWindows::get_space_left() {
uint64_t bytes = 0;
- if (!GetDiskFreeSpaceEx(NULL, (PULARGE_INTEGER)&bytes, NULL, NULL))
+ if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr))
return 0;
//this is either 0 or a value in bytes.
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 01d2b8716f..69078b3326 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -117,7 +117,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
errno_t errcode = _wfopen_s(&f, path.c_str(), mode_string);
- if (f == NULL) {
+ if (f == nullptr) {
switch (errcode) {
case ENOENT: {
last_error = ERR_FILE_NOT_FOUND;
@@ -140,7 +140,7 @@ void FileAccessWindows::close() {
return;
fclose(f);
- f = NULL;
+ f = nullptr;
if (save_path != "") {
@@ -164,7 +164,7 @@ void FileAccessWindows::close() {
rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0;
} else {
//atomic replace for existing file
- rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), NULL, 2 | 4, NULL, NULL);
+ rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), nullptr, 2 | 4, nullptr, nullptr);
}
if (rename_error) {
attempts--;
@@ -196,7 +196,7 @@ String FileAccessWindows::get_path_absolute() const {
bool FileAccessWindows::is_open() const {
- return (f != NULL);
+ return (f != nullptr);
}
void FileAccessWindows::seek(size_t p_position) {
@@ -318,7 +318,7 @@ bool FileAccessWindows::file_exists(const String &p_name) {
//printf("opening file %s\n", p_fname.c_str());
String filename = fix_path(p_name);
_wfopen_s(&g, filename.c_str(), L"rb");
- if (g == NULL) {
+ if (g == nullptr) {
return false;
} else {
@@ -354,7 +354,7 @@ Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_
}
FileAccessWindows::FileAccessWindows() :
- f(NULL),
+ f(nullptr),
flags(0),
prev_op(0),
last_error(OK) {
diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp
index a7f34b64ca..aea2db2603 100644
--- a/drivers/windows/thread_windows.cpp
+++ b/drivers/windows/thread_windows.cpp
@@ -64,7 +64,7 @@ Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void
ThreadWindows *tr = memnew(ThreadWindows);
tr->callback = p_callback;
tr->user = p_user;
- tr->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
+ tr->handle = CreateEvent(nullptr, TRUE, FALSE, nullptr);
QueueUserWorkItem(thread_callback, tr, WT_EXECUTELONGFUNCTION);
@@ -91,7 +91,7 @@ void ThreadWindows::make_default() {
}
ThreadWindows::ThreadWindows() :
- handle(NULL) {
+ handle(nullptr) {
}
ThreadWindows::~ThreadWindows() {
diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub
index 4c24925192..4e1b5f2a36 100644
--- a/drivers/winmidi/SCsub
+++ b/drivers/winmidi/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
# Driver source files
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/xaudio2/SCsub b/drivers/xaudio2/SCsub
index de750525ab..6778ad281e 100644
--- a/drivers/xaudio2/SCsub
+++ b/drivers/xaudio2/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.drivers_sources, "*.cpp")
-env.Append(CPPDEFINES=['XAUDIO2_ENABLED'])
-env.Append(LINKFLAGS=['xaudio2_8.lib'])
+env.Append(CPPDEFINES=["XAUDIO2_ENABLED"])
+env.Append(LINKFLAGS=["xaudio2_8.lib"])
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index 9c7cb4f0f3..120bfa2b36 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -43,7 +43,7 @@ Error AudioDriverXAudio2::init() {
thread_exited = false;
exit_thread = false;
pcm_open = false;
- samples_in = NULL;
+ samples_in = nullptr;
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far
@@ -193,11 +193,11 @@ void AudioDriverXAudio2::finish() {
mastering_voice->DestroyVoice();
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
AudioDriverXAudio2::AudioDriverXAudio2() :
- thread(NULL),
+ thread(nullptr),
current_buffer(0) {
wave_format = { 0 };
for (int i = 0; i < AUDIO_BUFFERS; i++) {
diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h
index 108891a288..eb4a6d6e95 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.h
+++ b/drivers/xaudio2/audio_driver_xaudio2.h
@@ -50,7 +50,7 @@ class AudioDriverXAudio2 : public AudioDriver {
HANDLE buffer_end_event;
XAudio2DriverVoiceCallback() :
- buffer_end_event(CreateEvent(NULL, FALSE, FALSE, NULL)) {}
+ buffer_end_event(CreateEvent(nullptr, FALSE, FALSE, nullptr)) {}
void STDMETHODCALLTYPE OnBufferEnd(void *pBufferContext) {
SetEvent(buffer_end_event);
}
diff --git a/editor/SCsub b/editor/SCsub
index 4431166ee6..13ae85bbf0 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -1,43 +1,42 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.editor_sources = []
import os
import os.path
from platform_methods import run_in_subprocess
-from compat import open_utf8
import editor_builders
def _make_doc_data_class_path(to_path):
# NOTE: It is safe to generate this file here, since this is still executed serially
- g = open_utf8(os.path.join(to_path, "doc_data_class_path.gen.h"), "w")
+ g = open(os.path.join(to_path, "doc_data_class_path.gen.h"), "w", encoding="utf-8")
g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n")
g.write("struct _DocDataClassPath { const char* name; const char* path; };\n")
- g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n");
+ g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n")
for c in sorted(env.doc_class_path):
- g.write("\t{\"" + c + "\", \"" + env.doc_class_path[c] + "\"},\n")
- g.write("\t{NULL, NULL}\n")
+ g.write('\t{"' + c + '", "' + env.doc_class_path[c] + '"},\n')
+ g.write("\t{nullptr, nullptr}\n")
g.write("};\n")
g.close()
-if env['tools']:
+if env["tools"]:
# Register exporters
reg_exporters_inc = '#include "register_exporters.h"\n'
- reg_exporters = 'void register_exporters() {\n'
+ reg_exporters = "void register_exporters() {\n"
for e in env.platform_exporters:
env.add_source_files(env.editor_sources, "#platform/" + e + "/export/export.cpp")
- reg_exporters += '\tregister_' + e + '_exporter();\n'
+ reg_exporters += "\tregister_" + e + "_exporter();\n"
reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
- reg_exporters += '}\n'
+ reg_exporters += "}\n"
# NOTE: It is safe to generate this file here, since this is still executed serially
- with open_utf8("register_exporters.gen.cpp", "w") as f:
+ with open("register_exporters.gen.cpp", "w", encoding="utf-8") as f:
f.write(reg_exporters_inc)
f.write(reg_exporters)
@@ -51,12 +50,12 @@ if env['tools']:
for d in doc_dirs:
try:
- for f in os.listdir(os.path.join(env.Dir('#').abspath, d)):
+ for f in os.listdir(os.path.join(env.Dir("#").abspath, d)):
docs.append("#" + os.path.join(d, f))
except OSError:
pass
- _make_doc_data_class_path(os.path.join(env.Dir('#').abspath, "editor/doc"))
+ _make_doc_data_class_path(os.path.join(env.Dir("#").abspath, "editor"))
docs = sorted(docs)
env.Depends("#editor/doc_data_compressed.gen.h", docs)
@@ -64,29 +63,36 @@ if env['tools']:
import glob
- path = env.Dir('.').abspath
+ path = env.Dir(".").abspath
- # Translations
+ # Editor translations
tlist = glob.glob(path + "/translations/*.po")
- env.Depends('#editor/translations.gen.h', tlist)
- env.CommandNoCache('#editor/translations.gen.h', tlist, run_in_subprocess(editor_builders.make_translations_header))
+ env.Depends("#editor/editor_translations.gen.h", tlist)
+ env.CommandNoCache(
+ "#editor/editor_translations.gen.h", tlist, run_in_subprocess(editor_builders.make_editor_translations_header)
+ )
+
+ # Documentation translations
+ tlist = glob.glob(env.Dir("#doc").abspath + "/translations/*.po")
+ env.Depends("#editor/doc_translations.gen.h", tlist)
+ env.CommandNoCache(
+ "#editor/doc_translations.gen.h", tlist, run_in_subprocess(editor_builders.make_doc_translations_header)
+ )
# Fonts
flist = glob.glob(path + "/../thirdparty/fonts/*.ttf")
flist.extend(glob.glob(path + "/../thirdparty/fonts/*.otf"))
flist.sort()
- env.Depends('#editor/builtin_fonts.gen.h', flist)
- env.CommandNoCache('#editor/builtin_fonts.gen.h', flist, run_in_subprocess(editor_builders.make_fonts_header))
+ env.Depends("#editor/builtin_fonts.gen.h", flist)
+ env.CommandNoCache("#editor/builtin_fonts.gen.h", flist, run_in_subprocess(editor_builders.make_fonts_header))
env.add_source_files(env.editor_sources, "*.cpp")
- SConscript('collada/SCsub')
- SConscript('doc/SCsub')
- SConscript('debugger/SCsub')
- SConscript('fileserver/SCsub')
- SConscript('icons/SCsub')
- SConscript('import/SCsub')
- SConscript('plugins/SCsub')
+ SConscript("debugger/SCsub")
+ SConscript("fileserver/SCsub")
+ SConscript("icons/SCsub")
+ SConscript("import/SCsub")
+ SConscript("plugins/SCsub")
lib = env.add_library("editor", env.editor_sources)
env.Prepend(LIBS=[lib])
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index e0839a9f27..e6a020bf41 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -215,20 +215,20 @@ void AnimationBezierTrackEdit::_draw_line_clipped(const Vector2 &p_from, const V
void AnimationBezierTrackEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- bezier_icon = get_icon("KeyBezierPoint", "EditorIcons");
- bezier_handle_icon = get_icon("KeyBezierHandle", "EditorIcons");
- selected_icon = get_icon("KeyBezierSelected", "EditorIcons");
+ bezier_icon = get_theme_icon("KeyBezierPoint", "EditorIcons");
+ bezier_handle_icon = get_theme_icon("KeyBezierHandle", "EditorIcons");
+ selected_icon = get_theme_icon("KeyBezierSelected", "EditorIcons");
if (handle_mode_option->get_item_count() == 0) {
- handle_mode_option->add_icon_item(get_icon("BezierHandlesFree", "EditorIcons"), TTR("Free"), HANDLE_MODE_FREE);
- handle_mode_option->add_icon_item(get_icon("BezierHandlesBalanced", "EditorIcons"), TTR("Balanced"), HANDLE_MODE_BALANCED);
- handle_mode_option->add_icon_item(get_icon("BezierHandlesMirror", "EditorIcons"), TTR("Mirror"), HANDLE_MODE_MIRROR);
+ handle_mode_option->add_icon_item(get_theme_icon("BezierHandlesFree", "EditorIcons"), TTR("Free"), HANDLE_MODE_FREE);
+ handle_mode_option->add_icon_item(get_theme_icon("BezierHandlesBalanced", "EditorIcons"), TTR("Balanced"), HANDLE_MODE_BALANCED);
+ handle_mode_option->add_icon_item(get_theme_icon("BezierHandlesMirror", "EditorIcons"), TTR("Mirror"), HANDLE_MODE_MIRROR);
}
}
if (p_what == NOTIFICATION_RESIZED) {
int right_limit = get_size().width - timeline->get_buttons_width();
- int hsep = get_constant("hseparation", "ItemList");
- int vsep = get_constant("vseparation", "ItemList");
+ int hsep = get_theme_constant("hseparation", "ItemList");
+ int vsep = get_theme_constant("vseparation", "ItemList");
handle_mode_option->set_position(Vector2(right_limit + hsep, get_size().height - handle_mode_option->get_combined_minimum_size().height - vsep));
handle_mode_option->set_size(Vector2(timeline->get_buttons_width() - hsep * 2, handle_mode_option->get_combined_minimum_size().height));
@@ -240,15 +240,15 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
int limit = timeline->get_name_limit();
if (has_focus()) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
accent.a *= 0.7;
draw_rect(Rect2(Point2(), get_size()), accent, false);
}
- Ref<Font> font = get_font("font", "Label");
- Color color = get_color("font_color", "Label");
- int hsep = get_constant("hseparation", "ItemList");
- int vsep = get_constant("vseparation", "ItemList");
+ Ref<Font> font = get_theme_font("font", "Label");
+ Color color = get_theme_color("font_color", "Label");
+ int hsep = get_theme_constant("hseparation", "ItemList");
+ int vsep = get_theme_constant("vseparation", "ItemList");
Color linecolor = color;
linecolor.a = 0.2;
@@ -258,7 +258,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
draw_line(Point2(right_limit, 0), Point2(right_limit, get_size().height), linecolor);
- Ref<Texture2D> close_icon = get_icon("Close", "EditorIcons");
+ Ref<Texture2D> close_icon = get_theme_icon("Close", "EditorIcons");
close_icon_rect.position = Vector2(get_size().width - close_icon->get_width() - hsep, hsep);
close_icon_rect.size = close_icon->get_size();
@@ -277,7 +277,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
{
NodePath path = animation->track_get_path(track);
- Node *node = NULL;
+ Node *node = nullptr;
if (root && root->has_node(path)) {
node = root->get_node(path);
@@ -340,7 +340,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
subtracks[i] = rect;
} else {
- Color ac = get_color("accent_color", "Editor");
+ Color ac = get_theme_color("accent_color", "Editor");
ac.a = 0.5;
draw_rect(rect, ac);
}
@@ -349,7 +349,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
vofs += font->get_height() + vsep;
}
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
{ //guides
float min_left_scale = font->get_height() + vsep;
@@ -391,7 +391,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
{ //draw OTHER curves
float scale = timeline->get_zoom_scale();
- Ref<Texture2D> point = get_icon("KeyValue", "EditorIcons");
+ Ref<Texture2D> point = get_theme_icon("KeyValue", "EditorIcons");
for (Map<int, Color>::Element *E = subtrack_colors.front(); E; E = E->next()) {
_draw_track(E->key(), E->get());
@@ -410,7 +410,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
//draw edited curve
- const Color highlight = get_color("highlight_color", "Editor");
+ const Color highlight = get_theme_color("highlight_color", "Editor");
_draw_track(track, highlight);
}
@@ -540,7 +540,7 @@ void AnimationBezierTrackEdit::_play_position_draw() {
int px = (-timeline->get_value() + play_position_pos) * scale + timeline->get_name_limit();
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
play_position->draw_line(Point2(px, 0), Point2(px, h), color);
}
}
@@ -657,9 +657,9 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
if (selection.size()) {
menu->add_separator();
- menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
+ menu->add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
menu->add_separator();
- menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
+ menu->add_icon_item(get_theme_icon("Remove", "EditorIcons"), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
}
menu->set_as_minsize();
@@ -1076,7 +1076,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
undo_redo->create_action(TTR("Anim Duplicate Keys"));
- List<Pair<int, float> > new_selection_values;
+ List<Pair<int, float>> new_selection_values;
for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
@@ -1103,7 +1103,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
//reselect duplicated
selection.clear();
- for (List<Pair<int, float> >::Element *E = new_selection_values.front(); E; E = E->next()) {
+ for (List<Pair<int, float>>::Element *E = new_selection_values.front(); E; E = E->next()) {
int track = E->get().first;
float time = E->get().second;
@@ -1162,11 +1162,11 @@ void AnimationBezierTrackEdit::_bind_methods() {
}
AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
- undo_redo = NULL;
- timeline = NULL;
- root = NULL;
- menu = NULL;
- block_animation_update_ptr = NULL;
+ undo_redo = nullptr;
+ timeline = nullptr;
+ root = nullptr;
+ menu = nullptr;
+ block_animation_update_ptr = nullptr;
moving_selection_attempt = false;
moving_selection = false;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 095dbd6849..f10e439f10 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -31,13 +31,13 @@
#include "animation_track_editor.h"
#include "animation_track_editor_plugins.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "editor/animation_bezier_editor.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor_node.h"
#include "editor_scale.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "servers/audio/audio_stream.h"
class AnimationTrackKeyEdit : public Object {
@@ -242,7 +242,7 @@ public:
args.write[idx] = Variant::construct(t, (const Variant **)ptrs, 1, err);
} else {
- args.write[idx] = Variant::construct(t, NULL, 0, err);
+ args.write[idx] = Variant::construct(t, nullptr, 0, err);
}
change_notify_deserved = true;
d_new["args"] = args;
@@ -693,7 +693,7 @@ public:
key_ofs = 0;
track = -1;
setting = false;
- root_path = NULL;
+ root_path = nullptr;
}
};
@@ -752,7 +752,7 @@ public:
if (animation != p_anim)
return;
- for (Map<int, List<float> >::Element *E = key_ofs_map.front(); E; E = E->next()) {
+ for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) {
for (List<float>::Element *F = E->value().front(); F; F = F->next()) {
@@ -777,7 +777,7 @@ public:
bool update_obj = false;
bool change_notify_deserved = false;
- for (Map<int, List<float> >::Element *E = key_ofs_map.front(); E; E = E->next()) {
+ for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) {
int track = E->key();
for (List<float>::Element *F = E->value().front(); F; F = F->next()) {
@@ -905,7 +905,7 @@ public:
args.write[idx] = Variant::construct(t, (const Variant **)ptrs, 1, err);
} else {
- args.write[idx] = Variant::construct(t, NULL, 0, err);
+ args.write[idx] = Variant::construct(t, nullptr, 0, err);
}
change_notify_deserved = true;
d_new["args"] = args;
@@ -1060,7 +1060,7 @@ public:
bool _get(const StringName &p_name, Variant &r_ret) const {
- for (Map<int, List<float> >::Element *E = key_ofs_map.front(); E; E = E->next()) {
+ for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) {
int track = E->key();
for (List<float>::Element *F = E->value().front(); F; F = F->next()) {
@@ -1208,7 +1208,7 @@ public:
bool show_time = true;
bool same_track_type = true;
bool same_key_type = true;
- for (Map<int, List<float> >::Element *E = key_ofs_map.front(); E; E = E->next()) {
+ for (Map<int, List<float>>::Element *E = key_ofs_map.front(); E; E = E->next()) {
int track = E->key();
ERR_FAIL_INDEX(track, animation->get_track_count());
@@ -1362,7 +1362,7 @@ public:
Ref<Animation> animation;
- Map<int, List<float> > key_ofs_map;
+ Map<int, List<float>> key_ofs_map;
Map<int, NodePath> base_map;
PropertyInfo hint;
@@ -1389,7 +1389,7 @@ public:
AnimationMultiTrackKeyEdit() {
use_fps = false;
setting = false;
- root_path = NULL;
+ root_path = nullptr;
}
};
@@ -1402,7 +1402,7 @@ void AnimationTimelineEdit::_zoom_changed(double) {
float AnimationTimelineEdit::get_zoom_scale() const {
- float zv = zoom->get_value();
+ float zv = zoom->get_max() - zoom->get_value();
if (zv < 1) {
zv = 1.0 - zv;
return Math::pow(1.0f + zv, 8.0f) * 100;
@@ -1442,11 +1442,11 @@ void AnimationTimelineEdit::_anim_loop_pressed() {
int AnimationTimelineEdit::get_buttons_width() const {
- Ref<Texture2D> interp_mode = get_icon("TrackContinuous", "EditorIcons");
- Ref<Texture2D> interp_type = get_icon("InterpRaw", "EditorIcons");
- Ref<Texture2D> loop_type = get_icon("InterpWrapClamp", "EditorIcons");
- Ref<Texture2D> remove_icon = get_icon("Remove", "EditorIcons");
- Ref<Texture2D> down_icon = get_icon("select_arrow", "Tree");
+ Ref<Texture2D> interp_mode = get_theme_icon("TrackContinuous", "EditorIcons");
+ Ref<Texture2D> interp_type = get_theme_icon("InterpRaw", "EditorIcons");
+ Ref<Texture2D> loop_type = get_theme_icon("InterpWrapClamp", "EditorIcons");
+ Ref<Texture2D> remove_icon = get_theme_icon("Remove", "EditorIcons");
+ Ref<Texture2D> down_icon = get_theme_icon("select_arrow", "Tree");
int total_w = interp_mode->get_width() + interp_type->get_width() + loop_type->get_width() + remove_icon->get_width();
total_w += (down_icon->get_width() + 4 * EDSCALE) * 4;
@@ -1456,7 +1456,7 @@ int AnimationTimelineEdit::get_buttons_width() const {
int AnimationTimelineEdit::get_name_limit() const {
- Ref<Texture2D> hsize_icon = get_icon("Hsize", "EditorIcons");
+ Ref<Texture2D> hsize_icon = get_theme_icon("Hsize", "EditorIcons");
int limit = MAX(name_limit, add_track->get_minimum_size().width + hsize_icon->get_width());
@@ -1468,17 +1468,17 @@ int AnimationTimelineEdit::get_name_limit() const {
void AnimationTimelineEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- add_track->set_icon(get_icon("Add", "EditorIcons"));
- loop->set_icon(get_icon("Loop", "EditorIcons"));
- time_icon->set_texture(get_icon("Time", "EditorIcons"));
+ add_track->set_icon(get_theme_icon("Add", "EditorIcons"));
+ loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
+ time_icon->set_texture(get_theme_icon("Time", "EditorIcons"));
add_track->get_popup()->clear();
- add_track->get_popup()->add_icon_item(get_icon("KeyValue", "EditorIcons"), TTR("Property Track"));
- add_track->get_popup()->add_icon_item(get_icon("KeyXform", "EditorIcons"), TTR("3D Transform Track"));
- add_track->get_popup()->add_icon_item(get_icon("KeyCall", "EditorIcons"), TTR("Call Method Track"));
- add_track->get_popup()->add_icon_item(get_icon("KeyBezier", "EditorIcons"), TTR("Bezier Curve Track"));
- add_track->get_popup()->add_icon_item(get_icon("KeyAudio", "EditorIcons"), TTR("Audio Playback Track"));
- add_track->get_popup()->add_icon_item(get_icon("KeyAnimation", "EditorIcons"), TTR("Animation Playback Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon("KeyValue", "EditorIcons"), TTR("Property Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon("KeyXform", "EditorIcons"), TTR("3D Transform Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon("KeyCall", "EditorIcons"), TTR("Call Method Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon("KeyBezier", "EditorIcons"), TTR("Bezier Curve Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon("KeyAudio", "EditorIcons"), TTR("Audio Playback Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon("KeyAnimation", "EditorIcons"), TTR("Animation Playback Track"));
}
if (p_what == NOTIFICATION_RESIZED) {
@@ -1493,8 +1493,8 @@ void AnimationTimelineEdit::_notification(int p_what) {
if (!animation.is_valid())
return;
- Ref<Font> font = get_font("font", "Label");
- Color color = get_color("font_color", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
+ Color color = get_theme_color("font_color", "Label");
int zoomw = key_range;
float scale = get_zoom_scale();
@@ -1504,7 +1504,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
if (l <= 0)
l = 0.001; //avoid crashor
- Ref<Texture2D> hsize_icon = get_icon("Hsize", "EditorIcons");
+ Ref<Texture2D> hsize_icon = get_theme_icon("Hsize", "EditorIcons");
hsize_rect = Rect2(get_name_limit() - hsize_icon->get_width() - 2 * EDSCALE, (get_size().height - hsize_icon->get_height()) / 2, hsize_icon->get_width(), hsize_icon->get_height());
draw_texture(hsize_icon, hsize_rect.position);
@@ -1554,7 +1554,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
int end_px = (l - get_value()) * scale;
int begin_px = -get_value() * scale;
- Color notimecol = get_color("dark_color_2", "Editor");
+ Color notimecol = get_theme_color("dark_color_2", "Editor");
Color timecolor = color;
timecolor.a = 0.2;
Color linecolor = color;
@@ -1685,9 +1685,9 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation) {
Size2 AnimationTimelineEdit::get_minimum_size() const {
Size2 ms = add_track->get_minimum_size();
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
ms.height = MAX(ms.height, font->get_height());
- ms.width = get_buttons_width() + add_track->get_minimum_size().width + get_icon("Hsize", "EditorIcons")->get_width() + 2;
+ ms.width = get_buttons_width() + add_track->get_minimum_size().width + get_theme_icon("Hsize", "EditorIcons")->get_width() + 2;
return ms;
}
@@ -1746,11 +1746,11 @@ void AnimationTimelineEdit::_play_position_draw() {
int px = (-get_value() + play_position_pos) * scale + get_name_limit();
if (px >= get_name_limit() && px < (play_position->get_size().width - get_buttons_width())) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
play_position->draw_texture(
- get_icon("TimelineIndicator", "EditorIcons"),
- Point2(px - get_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0),
+ get_theme_icon("TimelineIndicator", "EditorIcons"),
+ Point2(px - get_theme_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0),
color);
}
}
@@ -1859,7 +1859,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
use_fps = false;
editing = false;
name_limit = 150 * EDSCALE;
- zoom = NULL;
+ zoom = nullptr;
play_position_pos = 0;
play_position = memnew(Control);
@@ -1921,23 +1921,23 @@ void AnimationTrackEdit::_notification(int p_what) {
int limit = timeline->get_name_limit();
if (has_focus()) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
accent.a *= 0.7;
// Offside so the horizontal sides aren't cutoff.
draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), accent, false);
}
- Ref<Font> font = get_font("font", "Label");
- Color color = get_color("font_color", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
+ Color color = get_theme_color("font_color", "Label");
Ref<Texture2D> type_icons[6] = {
- get_icon("KeyValue", "EditorIcons"),
- get_icon("KeyXform", "EditorIcons"),
- get_icon("KeyCall", "EditorIcons"),
- get_icon("KeyBezier", "EditorIcons"),
- get_icon("KeyAudio", "EditorIcons"),
- get_icon("KeyAnimation", "EditorIcons")
+ get_theme_icon("KeyValue", "EditorIcons"),
+ get_theme_icon("KeyXform", "EditorIcons"),
+ get_theme_icon("KeyCall", "EditorIcons"),
+ get_theme_icon("KeyBezier", "EditorIcons"),
+ get_theme_icon("KeyAudio", "EditorIcons"),
+ get_theme_icon("KeyAnimation", "EditorIcons")
};
- int hsep = get_constant("hseparation", "ItemList");
+ int hsep = get_theme_constant("hseparation", "ItemList");
Color linecolor = color;
linecolor.a = 0.2;
@@ -1945,7 +1945,7 @@ void AnimationTrackEdit::_notification(int p_what) {
{
- Ref<Texture2D> check = animation->track_is_enabled(track) ? get_icon("checked", "CheckBox") : get_icon("unchecked", "CheckBox");
+ Ref<Texture2D> check = animation->track_is_enabled(track) ? get_theme_icon("checked", "CheckBox") : get_theme_icon("unchecked", "CheckBox");
int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but..
@@ -1958,7 +1958,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += type_icon->get_width() + hsep;
NodePath path = animation->track_get_path(track);
- Node *node = NULL;
+ Node *node = nullptr;
if (root && root->has_node(path)) {
node = root->get_node(path);
}
@@ -1966,7 +1966,7 @@ void AnimationTrackEdit::_notification(int p_what) {
String text;
Color text_color = color;
if (node && EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
- text_color = get_color("accent_color", "Editor");
+ text_color = get_theme_color("accent_color", "Editor");
}
if (in_group) {
@@ -2045,25 +2045,25 @@ void AnimationTrackEdit::_notification(int p_what) {
{
Ref<Texture2D> wrap_icon[2] = {
- get_icon("InterpWrapClamp", "EditorIcons"),
- get_icon("InterpWrapLoop", "EditorIcons"),
+ get_theme_icon("InterpWrapClamp", "EditorIcons"),
+ get_theme_icon("InterpWrapLoop", "EditorIcons"),
};
Ref<Texture2D> interp_icon[3] = {
- get_icon("InterpRaw", "EditorIcons"),
- get_icon("InterpLinear", "EditorIcons"),
- get_icon("InterpCubic", "EditorIcons")
+ get_theme_icon("InterpRaw", "EditorIcons"),
+ get_theme_icon("InterpLinear", "EditorIcons"),
+ get_theme_icon("InterpCubic", "EditorIcons")
};
Ref<Texture2D> cont_icon[4] = {
- get_icon("TrackContinuous", "EditorIcons"),
- get_icon("TrackDiscrete", "EditorIcons"),
- get_icon("TrackTrigger", "EditorIcons"),
- get_icon("TrackCapture", "EditorIcons")
+ get_theme_icon("TrackContinuous", "EditorIcons"),
+ get_theme_icon("TrackDiscrete", "EditorIcons"),
+ get_theme_icon("TrackTrigger", "EditorIcons"),
+ get_theme_icon("TrackCapture", "EditorIcons")
};
int ofs = get_size().width - timeline->get_buttons_width();
- Ref<Texture2D> down_icon = get_icon("select_arrow", "Tree");
+ Ref<Texture2D> down_icon = get_theme_icon("select_arrow", "Tree");
draw_line(Point2(ofs, 0), Point2(ofs, get_size().height), linecolor, Math::round(EDSCALE));
@@ -2100,7 +2100,7 @@ void AnimationTrackEdit::_notification(int p_what) {
update_mode_rect.size.x += down_icon->get_width();
bezier_edit_rect = Rect2();
} else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
- Ref<Texture2D> bezier_icon = get_icon("EditBezier", "EditorIcons");
+ Ref<Texture2D> bezier_icon = get_theme_icon("EditBezier", "EditorIcons");
update_mode_rect.size.x += down_icon->get_width();
bezier_edit_rect.position = update_mode_rect.position + (update_mode_rect.size - bezier_icon->get_size()) / 2;
bezier_edit_rect.size = bezier_icon->get_size();
@@ -2185,7 +2185,7 @@ void AnimationTrackEdit::_notification(int p_what) {
{
//erase
- Ref<Texture2D> icon = get_icon("Remove", "EditorIcons");
+ Ref<Texture2D> icon = get_theme_icon("Remove", "EditorIcons");
remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width()) / 2;
remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
@@ -2202,7 +2202,7 @@ void AnimationTrackEdit::_notification(int p_what) {
}
if (dropping_at != 0) {
- Color drop_color = get_color("accent_color", "Editor");
+ Color drop_color = get_theme_color("accent_color", "Editor");
if (dropping_at < 0) {
draw_line(Vector2(0, 0), Vector2(get_size().width, 0), drop_color, Math::round(EDSCALE));
} else {
@@ -2249,7 +2249,7 @@ void AnimationTrackEdit::draw_key_link(int p_index, float p_pixels_sec, int p_x,
if (current != next)
return;
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
color.a = 0.5;
int from_x = MAX(p_x, p_clip_left);
@@ -2273,15 +2273,15 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
const Variant &v = animation->track_get_key_value(track, p_index);
Variant::Type valid_type = Variant::NIL;
if (!_is_value_key_valid(v, valid_type)) {
- icon_to_draw = get_icon("KeyInvalid", "EditorIcons");
+ icon_to_draw = get_theme_icon("KeyInvalid", "EditorIcons");
}
}
Vector2 ofs(p_x - icon_to_draw->get_width() / 2, int(get_size().height - icon_to_draw->get_height()) / 2);
if (animation->track_get_type(track) == Animation::TYPE_METHOD) {
- Ref<Font> font = get_font("font", "Label");
- Color color = get_color("font_color", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
+ Color color = get_theme_color("font_color", "Label");
color.a = 0.5;
Dictionary d = animation->track_get_key_value(track, p_index);
@@ -2387,19 +2387,19 @@ void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animati
update();
Ref<Texture2D> type_icons[6] = {
- get_icon("KeyValue", "EditorIcons"),
- get_icon("KeyXform", "EditorIcons"),
- get_icon("KeyCall", "EditorIcons"),
- get_icon("KeyBezier", "EditorIcons"),
- get_icon("KeyAudio", "EditorIcons"),
- get_icon("KeyAnimation", "EditorIcons")
+ get_theme_icon("KeyValue", "EditorIcons"),
+ get_theme_icon("KeyXform", "EditorIcons"),
+ get_theme_icon("KeyCall", "EditorIcons"),
+ get_theme_icon("KeyBezier", "EditorIcons"),
+ get_theme_icon("KeyAudio", "EditorIcons"),
+ get_theme_icon("KeyAnimation", "EditorIcons")
};
ERR_FAIL_INDEX(track, animation->get_track_count());
node_path = animation->track_get_path(p_track);
type_icon = type_icons[animation->track_get_type(track)];
- selected_icon = get_icon("KeySelected", "EditorIcons");
+ selected_icon = get_theme_icon("KeySelected", "EditorIcons");
}
NodePath AnimationTrackEdit::get_path() const {
@@ -2408,9 +2408,9 @@ NodePath AnimationTrackEdit::get_path() const {
Size2 AnimationTrackEdit::get_minimum_size() const {
- Ref<Texture2D> texture = get_icon("Object", "EditorIcons");
- Ref<Font> font = get_font("font", "Label");
- int separation = get_constant("vseparation", "ItemList");
+ Ref<Texture2D> texture = get_theme_icon("Object", "EditorIcons");
+ Ref<Font> font = get_theme_font("font", "Label");
+ int separation = get_theme_constant("vseparation", "ItemList");
int max_h = MAX(texture->get_height(), font->get_height());
max_h = MAX(max_h, get_key_height());
@@ -2442,7 +2442,7 @@ void AnimationTrackEdit::_play_position_draw() {
int px = (-timeline->get_value() + play_position_pos) * scale + timeline->get_name_limit();
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
}
}
@@ -2471,6 +2471,7 @@ void AnimationTrackEdit::_path_entered(const String &p_text) {
undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text);
undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
undo_redo->commit_action();
+ path_popup->hide();
}
bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const {
@@ -2482,7 +2483,7 @@ bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path);
- Object *obj = NULL;
+ Object *obj = nullptr;
if (res.is_valid()) {
obj = res.ptr();
} else if (node) {
@@ -2689,14 +2690,14 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
}
menu->clear();
- menu->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
- menu->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
- menu->add_icon_item(get_icon("TrackTrigger", "EditorIcons"), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
- menu->add_icon_item(get_icon("TrackCapture", "EditorIcons"), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
+ menu->add_icon_item(get_theme_icon("TrackContinuous", "EditorIcons"), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
+ menu->add_icon_item(get_theme_icon("TrackDiscrete", "EditorIcons"), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
+ menu->add_icon_item(get_theme_icon("TrackTrigger", "EditorIcons"), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
+ menu->add_icon_item(get_theme_icon("TrackCapture", "EditorIcons"), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
menu->set_as_minsize();
- Vector2 popup_pos = get_global_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
- menu->set_global_position(popup_pos);
+ Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
+ menu->set_position(popup_pos);
menu->popup();
accept_event();
}
@@ -2708,13 +2709,13 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
}
menu->clear();
- menu->add_icon_item(get_icon("InterpRaw", "EditorIcons"), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
- menu->add_icon_item(get_icon("InterpLinear", "EditorIcons"), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
- menu->add_icon_item(get_icon("InterpCubic", "EditorIcons"), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
+ menu->add_icon_item(get_theme_icon("InterpRaw", "EditorIcons"), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
+ menu->add_icon_item(get_theme_icon("InterpLinear", "EditorIcons"), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
+ menu->add_icon_item(get_theme_icon("InterpCubic", "EditorIcons"), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
menu->set_as_minsize();
- Vector2 popup_pos = get_global_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
- menu->set_global_position(popup_pos);
+ Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
+ menu->set_position(popup_pos);
menu->popup();
accept_event();
}
@@ -2726,12 +2727,12 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
}
menu->clear();
- menu->add_icon_item(get_icon("InterpWrapClamp", "EditorIcons"), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
- menu->add_icon_item(get_icon("InterpWrapLoop", "EditorIcons"), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
+ menu->add_icon_item(get_theme_icon("InterpWrapClamp", "EditorIcons"), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
+ menu->add_icon_item(get_theme_icon("InterpWrapLoop", "EditorIcons"), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
menu->set_as_minsize();
- Vector2 popup_pos = get_global_position() + loop_mode_rect.position + Vector2(0, loop_mode_rect.size.height);
- menu->set_global_position(popup_pos);
+ Vector2 popup_pos = get_screen_position() + loop_mode_rect.position + Vector2(0, loop_mode_rect.size.height);
+ menu->set_position(popup_pos);
menu->popup();
accept_event();
}
@@ -2822,17 +2823,17 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
menu->clear();
- menu->add_icon_item(get_icon("Key", "EditorIcons"), TTR("Insert Key"), MENU_KEY_INSERT);
+ menu->add_icon_item(get_theme_icon("Key", "EditorIcons"), TTR("Insert Key"), MENU_KEY_INSERT);
if (editor->is_selection_active()) {
menu->add_separator();
- menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
+ menu->add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
menu->add_separator();
- menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete Key(s)"), MENU_KEY_DELETE);
+ menu->add_icon_item(get_theme_icon("Remove", "EditorIcons"), TTR("Delete Key(s)"), MENU_KEY_DELETE);
}
menu->set_as_minsize();
- Vector2 popup_pos = get_global_transform().xform(get_local_mouse_position());
- menu->set_global_position(popup_pos);
+ Vector2 popup_pos = get_screen_transform().xform(get_local_mouse_position());
+ menu->set_position(popup_pos);
menu->popup();
insert_at_pos = offset + timeline->get_value();
@@ -2843,17 +2844,20 @@ 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 (!path) {
+ path_popup = memnew(Popup);
+ path_popup->set_wrap_controls(true);
+ add_child(path_popup);
path = memnew(LineEdit);
- add_child(path);
- path->set_as_toplevel(true);
+ path_popup->add_child(path);
+ path->set_anchors_and_margins_preset(PRESET_WIDE);
path->connect("text_entered", callable_mp(this, &AnimationTrackEdit::_path_entered));
}
path->set_text(animation->track_get_path(track));
- Vector2 theme_ofs = path->get_stylebox("normal", "LineEdit")->get_offset();
- path->set_position(get_global_position() + path_rect.position - theme_ofs);
- path->set_size(path_rect.size);
- path->show_modal();
+ Vector2 theme_ofs = path->get_theme_stylebox("normal", "LineEdit")->get_offset();
+ path_popup->set_position(get_screen_position() + path_rect.position - theme_ofs);
+ path_popup->set_size(path_rect.size);
+ path_popup->popup();
path->grab_focus();
path->set_cursor_position(path->get_text().length());
clicking_on_name = false;
@@ -3086,11 +3090,12 @@ void AnimationTrackEdit::_bind_methods() {
}
AnimationTrackEdit::AnimationTrackEdit() {
- undo_redo = NULL;
- timeline = NULL;
- root = NULL;
- path = NULL;
- menu = NULL;
+ undo_redo = nullptr;
+ timeline = nullptr;
+ root = nullptr;
+ path = nullptr;
+ path_popup = nullptr;
+ menu = nullptr;
clicking_on_name = false;
dropping_at = 0;
@@ -3135,7 +3140,7 @@ AnimationTrackEdit *AnimationTrackEditPlugin::create_value_track_edit(Object *p_
Callable::CallError ce;
return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_value_track_edit", (const Variant **)&argptrs, 6, ce).operator Object *());
}
- return NULL;
+ return nullptr;
}
AnimationTrackEdit *AnimationTrackEditPlugin::create_audio_track_edit() {
@@ -3143,14 +3148,14 @@ AnimationTrackEdit *AnimationTrackEditPlugin::create_audio_track_edit() {
if (get_script_instance()) {
return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_audio_track_edit").operator Object *());
}
- return NULL;
+ return nullptr;
}
AnimationTrackEdit *AnimationTrackEditPlugin::create_animation_track_edit(Object *p_object) {
if (get_script_instance()) {
return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_animation_track_edit", p_object).operator Object *());
}
- return NULL;
+ return nullptr;
}
///////////////////////////////////////
@@ -3158,18 +3163,18 @@ AnimationTrackEdit *AnimationTrackEditPlugin::create_animation_track_edit(Object
void AnimationTrackEditGroup::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<Font> font = get_font("font", "Label");
- int separation = get_constant("hseparation", "ItemList");
- Color color = get_color("font_color", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
+ int separation = get_theme_constant("hseparation", "ItemList");
+ Color color = get_theme_color("font_color", "Label");
if (root && root->has_node(node)) {
Node *n = root->get_node(node);
if (n && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
- color = get_color("accent_color", "Editor");
+ color = get_theme_color("accent_color", "Editor");
}
}
- Color bgcol = get_color("dark_color_2", "Editor");
+ Color bgcol = get_theme_color("dark_color_2", "Editor");
bgcol.a *= 0.6;
draw_rect(Rect2(Point2(), get_size()), bgcol);
Color linecolor = color;
@@ -3187,7 +3192,7 @@ void AnimationTrackEditGroup::_notification(int p_what) {
int px = (-timeline->get_value() + timeline->get_play_position()) * timeline->get_zoom_scale() + timeline->get_name_limit();
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(2 * EDSCALE));
}
}
@@ -3203,8 +3208,8 @@ void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture2D> &p_type, co
Size2 AnimationTrackEditGroup::get_minimum_size() const {
- Ref<Font> font = get_font("font", "Label");
- int separation = get_constant("vseparation", "ItemList");
+ Ref<Font> font = get_theme_font("font", "Label");
+ int separation = get_theme_constant("vseparation", "ItemList");
return Vector2(0, MAX(font->get_height(), icon->get_height()) + separation);
}
@@ -3299,7 +3304,7 @@ Ref<Animation> AnimationTrackEditor::get_current_animation() const {
}
void AnimationTrackEditor::_root_removed(Node *p_root) {
- root = NULL;
+ root = nullptr;
}
void AnimationTrackEditor::set_root(Node *p_root) {
@@ -3443,7 +3448,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
if (insert_frame != Engine::get_singleton()->get_frames_drawn()) {
//clear insert list for the frame if frame changed
- if (insert_confirm->is_visible_in_tree())
+ if (insert_confirm->is_visible())
return; //do nothing
insert_data.clear();
insert_query = false;
@@ -3496,7 +3501,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
insert_confirm_bezier->set_visible(all_bezier);
insert_confirm->get_ok()->set_text(TTR("Create"));
- insert_confirm->popup_centered_minsize();
+ insert_confirm->popup_centered();
insert_query = true;
} else {
call_deferred("_insert_delay");
@@ -3549,7 +3554,7 @@ void AnimationTrackEditor::_insert_delay() {
insert_queue = false;
}
-void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform) {
+void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform &p_xform) {
if (!keying)
return;
@@ -3897,7 +3902,7 @@ PropertyInfo AnimationTrackEditor::_find_hint_for_track(int p_idx, NodePath &r_b
return PropertyInfo();
}
-static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool *r_valid = NULL) {
+static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool *r_valid = nullptr) {
Vector<String> subindices;
if (r_valid) {
*r_valid = true;
@@ -4095,7 +4100,7 @@ bool AnimationTrackEditor::is_selection_active() const {
}
bool AnimationTrackEditor::is_snap_enabled() const {
- return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ return snap->is_pressed() ^ InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
}
void AnimationTrackEditor::_update_tracks() {
@@ -4118,7 +4123,7 @@ void AnimationTrackEditor::_update_tracks() {
bool use_filter = selected_filter->is_pressed();
for (int i = 0; i < animation->get_track_count(); i++) {
- AnimationTrackEdit *track_edit = NULL;
+ AnimationTrackEdit *track_edit = nullptr;
//find hint and info for plugin
@@ -4179,7 +4184,7 @@ void AnimationTrackEditor::_update_tracks() {
if (animation->track_get_type(i) == Animation::TYPE_ANIMATION) {
NodePath path = animation->track_get_path(i);
- Node *node = NULL;
+ Node *node = nullptr;
if (root && root->has_node(path)) {
node = root->get_node(path);
}
@@ -4194,7 +4199,7 @@ void AnimationTrackEditor::_update_tracks() {
}
}
- if (track_edit == NULL) {
+ if (track_edit == nullptr) {
//no valid plugin_found
track_edit = memnew(AnimationTrackEdit);
}
@@ -4207,7 +4212,7 @@ void AnimationTrackEditor::_update_tracks() {
if (!group_sort.has(base_path)) {
AnimationTrackEditGroup *g = memnew(AnimationTrackEditGroup);
- Ref<Texture2D> icon = get_icon("Node", "EditorIcons");
+ Ref<Texture2D> icon = get_theme_icon("Node", "EditorIcons");
String name = base_path;
String tooltip;
if (root && root->has_node(base_path)) {
@@ -4225,7 +4230,7 @@ void AnimationTrackEditor::_update_tracks() {
g->set_timeline(timeline);
groups.push_back(g);
VBoxContainer *vb = memnew(VBoxContainer);
- vb->add_constant_override("separation", 0);
+ vb->add_theme_constant_override("separation", 0);
vb->add_child(g);
track_vbox->add_child(vb);
group_sort[base_path] = vb;
@@ -4368,12 +4373,12 @@ MenuButton *AnimationTrackEditor::get_edit_menu() {
void AnimationTrackEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- zoom_icon->set_texture(get_icon("Zoom", "EditorIcons"));
- snap->set_icon(get_icon("Snap", "EditorIcons"));
- view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
- selected_filter->set_icon(get_icon("AnimationFilter", "EditorIcons"));
- imported_anim_warning->set_icon(get_icon("NodeWarning", "EditorIcons"));
- main_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
+ zoom_icon->set_texture(get_theme_icon("Zoom", "EditorIcons"));
+ snap->set_icon(get_theme_icon("Snap", "EditorIcons"));
+ view_group->set_icon(get_theme_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
+ selected_filter->set_icon(get_theme_icon("AnimationFilter", "EditorIcons"));
+ imported_anim_warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons"));
+ main_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
}
if (p_what == NOTIFICATION_READY) {
@@ -4441,8 +4446,8 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
ERR_FAIL_COND(!node);
NodePath path_to = root->get_path_to(node);
- if (adding_track_type == Animation::TYPE_TRANSFORM && !node->is_class("Spatial")) {
- EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to Spatial-based nodes."));
+ if (adding_track_type == Animation::TYPE_TRANSFORM && !node->is_class("Node3D")) {
+ EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to 3D-based nodes."));
return;
}
@@ -4633,10 +4638,10 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key."));
return;
}
- Spatial *base = Object::cast_to<Spatial>(root->get_node(animation->track_get_path(p_track)));
+ Node3D *base = Object::cast_to<Node3D>(root->get_node(animation->track_get_path(p_track)));
if (!base) {
- EditorNode::get_singleton()->show_warning(TTR("Track is not of type Spatial, can't insert key"));
+ EditorNode::get_singleton()->show_warning(TTR("Track is not of type Node3D, can't insert key"));
return;
}
@@ -4747,7 +4752,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
params.push_back(arg);
} else {
Callable::CallError ce;
- Variant arg = Variant::construct(E->get().arguments[i].type, NULL, 0, ce);
+ Variant arg = Variant::construct(E->get().arguments[i].type, nullptr, 0, ce);
params.push_back(arg);
}
}
@@ -4833,21 +4838,21 @@ void AnimationTrackEditor::_clear_key_edit() {
if (key_edit) {
//if key edit is the object being inspected, remove it first
if (EditorNode::get_singleton()->get_inspector()->get_edited_object() == key_edit) {
- EditorNode::get_singleton()->push_item(NULL);
+ EditorNode::get_singleton()->push_item(nullptr);
}
//then actually delete it
memdelete(key_edit);
- key_edit = NULL;
+ key_edit = nullptr;
}
if (multi_key_edit) {
if (EditorNode::get_singleton()->get_inspector()->get_edited_object() == multi_key_edit) {
- EditorNode::get_singleton()->push_item(NULL);
+ EditorNode::get_singleton()->push_item(nullptr);
}
memdelete(multi_key_edit);
- multi_key_edit = NULL;
+ multi_key_edit = nullptr;
}
}
@@ -4892,7 +4897,7 @@ void AnimationTrackEditor::_update_key_edit() {
multi_key_edit = memnew(AnimationMultiTrackKeyEdit);
multi_key_edit->animation = animation;
- Map<int, List<float> > key_ofs_map;
+ Map<int, List<float>> key_ofs_map;
Map<int, NodePath> base_map;
int first_track = -1;
for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
@@ -5050,8 +5055,8 @@ float AnimationTrackEditor::get_moving_selection_offset() const {
void AnimationTrackEditor::_box_selection_draw() {
const Rect2 selection_rect = Rect2(Point2(), box_selection->get_size());
- box_selection->draw_rect(selection_rect, get_color("box_selection_fill_color", "Editor"));
- box_selection->draw_rect(selection_rect, get_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE));
+ box_selection->draw_rect(selection_rect, get_theme_color("box_selection_fill_color", "Editor"));
+ box_selection->draw_rect(selection_rect, get_theme_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE));
}
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
@@ -5186,7 +5191,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
undo_redo->create_action(TTR("Anim Duplicate Keys"));
- List<Pair<int, float> > new_selection_values;
+ List<Pair<int, float>> new_selection_values;
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
@@ -5224,7 +5229,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
//reselect duplicated
Map<SelectedKey, KeyInfo> new_selection;
- for (List<Pair<int, float> >::Element *E = new_selection_values.front(); E; E = E->next()) {
+ for (List<Pair<int, float>>::Element *E = new_selection_values.front(); E; E = E->next()) {
int track = E->get().first;
float time = E->get().second;
@@ -5259,17 +5264,17 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
for (int i = 0; i < animation->get_track_count(); i++) {
NodePath path = animation->track_get_path(i);
- Node *node = NULL;
+ Node *node = nullptr;
if (root && root->has_node(path)) {
node = root->get_node(path);
}
String text;
- Ref<Texture2D> icon = get_icon("Node", "EditorIcons");
+ Ref<Texture2D> icon = get_theme_icon("Node", "EditorIcons");
if (node) {
- if (has_icon(node->get_class(), "EditorIcons")) {
- icon = get_icon(node->get_class(), "EditorIcons");
+ if (has_theme_icon(node->get_class(), "EditorIcons")) {
+ icon = get_theme_icon(node->get_class(), "EditorIcons");
}
text = node->get_name();
@@ -5309,7 +5314,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
it->set_metadata(0, md);
}
- track_copy_dialog->popup_centered_minsize(Size2(350, 500) * EDSCALE);
+ track_copy_dialog->popup_centered(Size2(350, 500) * EDSCALE);
} break;
case EDIT_COPY_TRACKS_CONFIRM: {
@@ -5356,7 +5361,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->create_action(TTR("Paste Tracks"));
for (int i = 0; i < track_clipboard.size(); i++) {
undo_redo->add_do_method(animation.ptr(), "add_track", track_clipboard[i].track_type);
- Node *exists = NULL;
+ Node *exists = nullptr;
NodePath path = track_clipboard[i].base_path;
if (root) {
@@ -5578,7 +5583,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case EDIT_CLEAN_UP_ANIMATION: {
- cleanup_dialog->popup_centered_minsize(Size2(300, 0) * EDSCALE);
+ cleanup_dialog->popup_centered(Size2(300, 0) * EDSCALE);
} break;
case EDIT_CLEAN_UP_ANIMATION_CONFIRM: {
@@ -5602,7 +5607,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
bool prop_exists = false;
Variant::Type valid_type = Variant::NIL;
- Object *obj = NULL;
+ Object *obj = nullptr;
RES res;
Vector<StringName> leftover_path;
@@ -5652,7 +5657,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
void AnimationTrackEditor::_view_group_toggle() {
_update_tracks();
- view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
+ view_group->set_icon(get_theme_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
}
bool AnimationTrackEditor::is_grouping_tracks() {
@@ -5748,7 +5753,7 @@ void AnimationTrackEditor::_bind_methods() {
}
AnimationTrackEditor::AnimationTrackEditor() {
- root = NULL;
+ root = nullptr;
undo_redo = EditorNode::get_singleton()->get_undo_redo();
@@ -5763,7 +5768,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
timeline_scroll->add_child(timeline_vbox);
timeline_vbox->set_v_size_flags(SIZE_EXPAND_FILL);
timeline_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
- timeline_vbox->add_constant_override("separation", 0);
+ timeline_vbox->add_theme_constant_override("separation", 0);
info_message = memnew(Label);
info_message->set_text(TTR("Select an AnimationPlayer node to create and edit animations."));
@@ -5814,7 +5819,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
track_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
scroll->set_enable_h_scroll(false);
scroll->set_enable_v_scroll(true);
- track_vbox->add_constant_override("separation", 0);
+ track_vbox->add_theme_constant_override("separation", 0);
HBoxContainer *bottom_hb = memnew(HBoxContainer);
add_child(bottom_hb);
@@ -5940,8 +5945,8 @@ AnimationTrackEditor::AnimationTrackEditor() {
icvb->add_child(insert_confirm_bezier);
keying = false;
moving_selection = 0;
- key_edit = NULL;
- multi_key_edit = NULL;
+ key_edit = nullptr;
+ multi_key_edit = nullptr;
box_selection = memnew(Control);
add_child(box_selection);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 26f9c15f6c..96a60cc135 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -140,6 +140,7 @@ class AnimationTrackEdit : public Control {
};
AnimationTimelineEdit *timeline;
UndoRedo *undo_redo;
+ Popup *path_popup;
LineEdit *path;
Node *root;
Control *play_position; //separate control used to draw so updates for only position changed are much faster
@@ -378,7 +379,7 @@ class AnimationTrackEditor : public VBoxContainer {
void _root_removed(Node *p_root);
- PropertyInfo _find_hint_for_track(int p_idx, NodePath &r_base_path, Variant *r_current_val = NULL);
+ PropertyInfo _find_hint_for_track(int p_idx, NodePath &r_base_path, Variant *r_current_val = nullptr);
void _timeline_value_changed(double);
@@ -430,7 +431,7 @@ class AnimationTrackEditor : public VBoxContainer {
Rect2 box_select_rect;
void _scroll_input(const Ref<InputEvent> &p_event);
- Vector<Ref<AnimationTrackEditPlugin> > track_edit_plugins;
+ Vector<Ref<AnimationTrackEditPlugin>> track_edit_plugins;
void _cancel_bezier_edit();
void _bezier_edit(int p_for_track);
@@ -512,7 +513,7 @@ public:
void set_anim_pos(float p_pos);
void insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists = false);
void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance);
- void insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform);
+ void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform &p_xform);
void show_select_node_warning(bool p_show);
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index fc47a69a2c..695c294ad2 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -33,8 +33,8 @@
#include "editor/audio_stream_preview.h"
#include "editor_resource_preview.h"
#include "editor_scale.h"
-#include "scene/2d/animated_sprite.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/animated_sprite_2d.h"
+#include "scene/2d/sprite_2d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/animation/animation_player.h"
#include "servers/audio/audio_stream.h"
@@ -42,12 +42,12 @@
/// BOOL ///
int AnimationTrackEditBool::get_key_height() const {
- Ref<Texture2D> checked = get_icon("checked", "CheckBox");
+ Ref<Texture2D> checked = get_theme_icon("checked", "CheckBox");
return checked->get_height();
}
Rect2 AnimationTrackEditBool::get_key_rect(int p_index, float p_pixels_sec) {
- Ref<Texture2D> checked = get_icon("checked", "CheckBox");
+ Ref<Texture2D> checked = get_theme_icon("checked", "CheckBox");
return Rect2(-checked->get_width() / 2, 0, checked->get_width(), get_size().height);
}
@@ -58,7 +58,7 @@ bool AnimationTrackEditBool::is_key_selectable_by_distance() const {
void AnimationTrackEditBool::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {
bool checked = get_animation()->track_get_key_value(get_track(), p_index);
- Ref<Texture2D> icon = get_icon(checked ? "checked" : "unchecked", "CheckBox");
+ Ref<Texture2D> icon = get_theme_icon(checked ? "checked" : "unchecked", "CheckBox");
Vector2 ofs(p_x - icon->get_width() / 2, int(get_size().height - icon->get_height()) / 2);
@@ -71,7 +71,7 @@ void AnimationTrackEditBool::draw_key(int p_index, float p_pixels_sec, int p_x,
draw_texture(icon, ofs);
if (p_selected) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
draw_rect_clipped(Rect2(ofs, icon->get_size()), color, false);
}
}
@@ -80,12 +80,12 @@ void AnimationTrackEditBool::draw_key(int p_index, float p_pixels_sec, int p_x,
int AnimationTrackEditColor::get_key_height() const {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return font->get_height() * 0.8;
}
Rect2 AnimationTrackEditColor::get_key_rect(int p_index, float p_pixels_sec) {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
return Rect2(-fh / 2, 0, fh, get_size().height);
}
@@ -97,7 +97,7 @@ bool AnimationTrackEditColor::is_key_selectable_by_distance() const {
void AnimationTrackEditColor::draw_key_link(int p_index, float p_pixels_sec, int p_x, int p_next_x, int p_clip_left, int p_clip_right) {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = (font->get_height() * 0.8);
int x_from = p_x + fh / 2 - 1;
@@ -146,7 +146,7 @@ void AnimationTrackEditColor::draw_key(int p_index, float p_pixels_sec, int p_x,
Color color = get_animation()->track_get_key_value(get_track(), p_index);
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
Rect2 rect(Vector2(p_x - fh / 2, int(get_size().height - fh) / 2), Size2(fh, fh));
@@ -158,7 +158,7 @@ void AnimationTrackEditColor::draw_key(int p_index, float p_pixels_sec, int p_x,
draw_rect_clipped(rect, color);
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect_clipped(rect, accent, false);
}
}
@@ -185,7 +185,7 @@ int AnimationTrackEditAudio::get_key_height() const {
return AnimationTrackEdit::get_key_height();
}
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return int(font->get_height() * 1.5);
}
Rect2 AnimationTrackEditAudio::get_key_rect(int p_index, float p_pixels_sec) {
@@ -218,7 +218,7 @@ Rect2 AnimationTrackEditAudio::get_key_rect(int p_index, float p_pixels_sec) {
return Rect2(0, 0, len * p_pixels_sec, get_size().height);
} else {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
return Rect2(0, 0, fh, get_size().height);
}
@@ -279,7 +279,7 @@ void AnimationTrackEditAudio::draw_key(int p_index, float p_pixels_sec, int p_x,
if (to_x <= from_x)
return;
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
float fh = int(font->get_height() * 1.5);
Rect2 rect = Rect2(from_x, (get_size().height - fh) / 2, to_x - from_x, fh);
draw_rect(rect, Color(0.25, 0.25, 0.25));
@@ -303,22 +303,22 @@ void AnimationTrackEditAudio::draw_key(int p_index, float p_pixels_sec, int p_x,
Vector<Color> color;
color.push_back(Color(0.75, 0.75, 0.75));
- VS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, color);
+ RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, color);
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
} else {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
Rect2 rect(Vector2(p_x, int(get_size().height - fh) / 2), Size2(fh, fh));
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
draw_rect(rect, color);
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
}
@@ -344,7 +344,7 @@ int AnimationTrackEditSpriteFrame::get_key_height() const {
return AnimationTrackEdit::get_key_height();
}
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return int(font->get_height() * 2);
}
Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_sec) {
@@ -357,7 +357,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se
Size2 size;
- if (Object::cast_to<Sprite>(object) || Object::cast_to<Sprite3D>(object)) {
+ if (Object::cast_to<Sprite2D>(object) || Object::cast_to<Sprite3D>(object)) {
Ref<Texture2D> texture = object->call("get_texture");
if (!texture.is_valid()) {
@@ -379,7 +379,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se
if (vframes > 1) {
size.y /= vframes;
}
- } else if (Object::cast_to<AnimatedSprite>(object) || Object::cast_to<AnimatedSprite3D>(object)) {
+ } else if (Object::cast_to<AnimatedSprite2D>(object) || Object::cast_to<AnimatedSprite3D>(object)) {
Ref<SpriteFrames> sf = object->call("get_sprite_frames");
if (sf.is_null()) {
@@ -413,7 +413,7 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se
size = size.floor();
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int height = int(font->get_height() * 2);
int width = height * size.width / size.height;
@@ -436,7 +436,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in
Ref<Texture2D> texture;
Rect2 region;
- if (Object::cast_to<Sprite>(object) || Object::cast_to<Sprite3D>(object)) {
+ if (Object::cast_to<Sprite2D>(object) || Object::cast_to<Sprite3D>(object)) {
texture = object->call("get_texture");
if (!texture.is_valid()) {
@@ -473,7 +473,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in
region.position.x += region.size.x * coords.x;
region.position.y += region.size.y * coords.y;
- } else if (Object::cast_to<AnimatedSprite>(object) || Object::cast_to<AnimatedSprite3D>(object)) {
+ } else if (Object::cast_to<AnimatedSprite2D>(object) || Object::cast_to<AnimatedSprite3D>(object)) {
Ref<SpriteFrames> sf = object->call("get_sprite_frames");
if (sf.is_null()) {
@@ -507,7 +507,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in
region.size = texture->get_size();
}
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int height = int(font->get_height() * 2);
int width = height * region.size.width / region.size.height;
@@ -520,7 +520,7 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in
if (rect.position.x > p_clip_right)
return;
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
Color bg = accent;
bg.a = 0.15;
@@ -551,7 +551,7 @@ int AnimationTrackEditSubAnim::get_key_height() const {
return AnimationTrackEdit::get_key_height();
}
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return int(font->get_height() * 1.5);
}
Rect2 AnimationTrackEditSubAnim::get_key_rect(int p_index, float p_pixels_sec) {
@@ -580,7 +580,7 @@ Rect2 AnimationTrackEditSubAnim::get_key_rect(int p_index, float p_pixels_sec) {
return Rect2(0, 0, len * p_pixels_sec, get_size().height);
} else {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
return Rect2(0, 0, fh, get_size().height);
}
@@ -633,12 +633,12 @@ void AnimationTrackEditSubAnim::draw_key(int p_index, float p_pixels_sec, int p_
if (to_x <= from_x)
return;
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 1.5;
Rect2 rect(from_x, int(get_size().height - fh) / 2, to_x - from_x, fh);
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
Color bg = color;
bg.r = 1 - color.r;
bg.g = 1 - color.g;
@@ -673,7 +673,7 @@ void AnimationTrackEditSubAnim::draw_key(int p_index, float p_pixels_sec, int p_
}
if (lines.size() > 2) {
- VS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, colorv);
+ RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, colorv);
}
int limit = to_x - from_x - 4;
@@ -682,19 +682,19 @@ void AnimationTrackEditSubAnim::draw_key(int p_index, float p_pixels_sec, int p_
}
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
} else {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
Rect2 rect(Vector2(p_x, int(get_size().height - fh) / 2), Size2(fh, fh));
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
draw_rect(rect, color);
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
}
@@ -709,13 +709,13 @@ void AnimationTrackEditSubAnim::set_node(Object *p_object) {
int AnimationTrackEditVolumeDB::get_key_height() const {
- Ref<Texture2D> volume_texture = get_icon("ColorTrackVu", "EditorIcons");
+ Ref<Texture2D> volume_texture = get_theme_icon("ColorTrackVu", "EditorIcons");
return volume_texture->get_height() * 1.2;
}
void AnimationTrackEditVolumeDB::draw_bg(int p_clip_left, int p_clip_right) {
- Ref<Texture2D> volume_texture = get_icon("ColorTrackVu", "EditorIcons");
+ Ref<Texture2D> volume_texture = get_theme_icon("ColorTrackVu", "EditorIcons");
int tex_h = volume_texture->get_height();
int y_from = (get_size().height - tex_h) / 2;
@@ -727,7 +727,7 @@ void AnimationTrackEditVolumeDB::draw_bg(int p_clip_left, int p_clip_right) {
void AnimationTrackEditVolumeDB::draw_fg(int p_clip_left, int p_clip_right) {
- Ref<Texture2D> volume_texture = get_icon("ColorTrackVu", "EditorIcons");
+ Ref<Texture2D> volume_texture = get_theme_icon("ColorTrackVu", "EditorIcons");
int tex_h = volume_texture->get_height();
int y_from = (get_size().height - tex_h) / 2;
int db0 = y_from + (24 / 80.0) * tex_h;
@@ -762,12 +762,12 @@ void AnimationTrackEditVolumeDB::draw_key_link(int p_index, float p_pixels_sec,
to_x = p_clip_right;
}
- Ref<Texture2D> volume_texture = get_icon("ColorTrackVu", "EditorIcons");
+ Ref<Texture2D> volume_texture = get_theme_icon("ColorTrackVu", "EditorIcons");
int tex_h = volume_texture->get_height();
int y_from = (get_size().height - tex_h) / 2;
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
color.a *= 0.7;
draw_line(Point2(from_x, y_from + h * tex_h), Point2(to_x, y_from + h_n * tex_h), color, 2);
@@ -790,7 +790,7 @@ void AnimationTrackEditTypeAudio::_preview_changed(ObjectID p_which) {
int AnimationTrackEditTypeAudio::get_key_height() const {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return int(font->get_height() * 1.5);
}
Rect2 AnimationTrackEditTypeAudio::get_key_rect(int p_index, float p_pixels_sec) {
@@ -854,7 +854,7 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
}
}
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
float fh = int(font->get_height() * 1.5);
float len = stream->get_length();
@@ -926,9 +926,9 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
Vector<Color> color;
color.push_back(Color(0.75, 0.75, 0.75));
- VS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, color);
+ RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, color);
- Color cut_color = get_color("accent_color", "Editor");
+ Color cut_color = get_theme_color("accent_color", "Editor");
cut_color.a = 0.7;
if (start_ofs > 0 && pixel_begin > p_clip_left) {
draw_rect(Rect2(pixel_begin, rect.position.y, 1, rect.size.y), cut_color);
@@ -938,7 +938,7 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
}
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
}
@@ -1133,7 +1133,7 @@ int AnimationTrackEditTypeAnimation::get_key_height() const {
return AnimationTrackEdit::get_key_height();
}
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return int(font->get_height() * 1.5);
}
Rect2 AnimationTrackEditTypeAnimation::get_key_rect(int p_index, float p_pixels_sec) {
@@ -1162,7 +1162,7 @@ Rect2 AnimationTrackEditTypeAnimation::get_key_rect(int p_index, float p_pixels_
return Rect2(0, 0, len * p_pixels_sec, get_size().height);
} else {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
return Rect2(0, 0, fh, get_size().height);
}
@@ -1215,12 +1215,12 @@ void AnimationTrackEditTypeAnimation::draw_key(int p_index, float p_pixels_sec,
if (to_x <= from_x)
return;
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 1.5;
Rect2 rect(from_x, int(get_size().height - fh) / 2, to_x - from_x, fh);
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
Color bg = color;
bg.r = 1 - color.r;
bg.g = 1 - color.g;
@@ -1255,7 +1255,7 @@ void AnimationTrackEditTypeAnimation::draw_key(int p_index, float p_pixels_sec,
}
if (lines.size() > 2) {
- VS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, colorv);
+ RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), lines, colorv);
}
int limit = to_x - from_x - 4;
@@ -1264,19 +1264,19 @@ void AnimationTrackEditTypeAnimation::draw_key(int p_index, float p_pixels_sec,
}
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
} else {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
int fh = font->get_height() * 0.8;
Rect2 rect(Vector2(p_x, int(get_size().height - fh) / 2), Size2(fh, fh));
- Color color = get_color("font_color", "Label");
+ Color color = get_theme_color("font_color", "Label");
draw_rect(rect, color);
if (p_selected) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
draw_rect(rect, accent, false);
}
}
@@ -1300,14 +1300,14 @@ AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_value_track_edit(Obj
return audio;
}
- if (p_property == "frame" && (p_object->is_class("Sprite") || p_object->is_class("Sprite3D") || p_object->is_class("AnimatedSprite") || p_object->is_class("AnimatedSprite3D"))) {
+ if (p_property == "frame" && (p_object->is_class("Sprite2D") || p_object->is_class("Sprite3D") || p_object->is_class("AnimatedSprite2D") || p_object->is_class("AnimatedSprite3D"))) {
AnimationTrackEditSpriteFrame *sprite = memnew(AnimationTrackEditSpriteFrame);
sprite->set_node(p_object);
return sprite;
}
- if (p_property == "frame_coords" && (p_object->is_class("Sprite") || p_object->is_class("Sprite3D"))) {
+ if (p_property == "frame_coords" && (p_object->is_class("Sprite2D") || p_object->is_class("Sprite3D"))) {
AnimationTrackEditSpriteFrame *sprite = memnew(AnimationTrackEditSpriteFrame);
sprite->set_as_coords();
@@ -1335,7 +1335,7 @@ AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_value_track_edit(Obj
return memnew(AnimationTrackEditColor);
}
- return NULL;
+ return nullptr;
}
AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_audio_track_edit() {
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp
index f14b12b132..9f6785ec06 100644
--- a/editor/array_property_edit.cpp
+++ b/editor/array_property_edit.cpp
@@ -43,7 +43,7 @@ Variant ArrayPropertyEdit::get_array() const {
Variant arr = o->get(property);
if (!arr.is_array()) {
Callable::CallError ce;
- arr = Variant::construct(default_type, NULL, 0, ce);
+ arr = Variant::construct(default_type, nullptr, 0, ce);
}
return arr;
}
@@ -110,7 +110,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
new_type = arr.get(size - 1).get_type();
}
if (new_type != Variant::NIL) {
- init = Variant::construct(new_type, NULL, 0, ce);
+ init = Variant::construct(new_type, nullptr, 0, ce);
for (int i = size; i < newsize; i++) {
ur->add_do_method(this, "_set_value", i, init);
}
@@ -140,7 +140,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Variant value = arr.get(idx);
if (value.get_type() != type && type >= 0 && type < Variant::VARIANT_MAX) {
Callable::CallError ce;
- Variant new_value = Variant::construct(Variant::Type(type), NULL, 0, ce);
+ Variant new_value = Variant::construct(Variant::Type(type), nullptr, 0, ce);
UndoRedo *ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Array Value Type"));
diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp
index 64d435a901..fe28c913a7 100644
--- a/editor/audio_stream_preview.cpp
+++ b/editor/audio_stream_preview.cpp
@@ -212,7 +212,7 @@ void AudioStreamPreviewGenerator::_bind_methods() {
ADD_SIGNAL(MethodInfo("preview_updated", PropertyInfo(Variant::INT, "obj_id")));
}
-AudioStreamPreviewGenerator *AudioStreamPreviewGenerator::singleton = NULL;
+AudioStreamPreviewGenerator *AudioStreamPreviewGenerator::singleton = nullptr;
void AudioStreamPreviewGenerator::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
@@ -221,7 +221,7 @@ void AudioStreamPreviewGenerator::_notification(int p_what) {
if (!E->get().generating) {
if (E->get().thread) {
Thread::wait_to_finish(E->get().thread);
- E->get().thread = NULL;
+ E->get().thread = nullptr;
}
if (!ObjectDB::get_instance(E->key())) { //no longer in use, get rid of preview
to_erase.push_back(E->key());
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index ddd702fc6c..77e20b971c 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -30,7 +30,7 @@
#include "code_editor.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "core/string_builder.h"
#include "editor/editor_scale.h"
@@ -69,10 +69,10 @@ GotoLineDialog::GotoLineDialog() {
set_title(TTR("Go to Line"));
VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE);
add_child(vbc);
Label *l = memnew(Label);
@@ -82,7 +82,7 @@ GotoLineDialog::GotoLineDialog() {
line = memnew(LineEdit);
vbc->add_child(line);
register_text_enter(line);
- text_editor = NULL;
+ text_editor = nullptr;
set_hide_on_ok(false);
}
@@ -91,25 +91,25 @@ void FindReplaceBar::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
- find_prev->set_icon(get_icon("MoveUp", "EditorIcons"));
- find_next->set_icon(get_icon("MoveDown", "EditorIcons"));
- hide_button->set_normal_texture(get_icon("Close", "EditorIcons"));
- hide_button->set_hover_texture(get_icon("Close", "EditorIcons"));
- hide_button->set_pressed_texture(get_icon("Close", "EditorIcons"));
+ find_prev->set_icon(get_theme_icon("MoveUp", "EditorIcons"));
+ find_next->set_icon(get_theme_icon("MoveDown", "EditorIcons"));
+ hide_button->set_normal_texture(get_theme_icon("Close", "EditorIcons"));
+ hide_button->set_hover_texture(get_theme_icon("Close", "EditorIcons"));
+ hide_button->set_pressed_texture(get_theme_icon("Close", "EditorIcons"));
hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size());
} else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
set_process_unhandled_input(is_visible_in_tree());
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- find_prev->set_icon(get_icon("MoveUp", "EditorIcons"));
- find_next->set_icon(get_icon("MoveDown", "EditorIcons"));
- hide_button->set_normal_texture(get_icon("Close", "EditorIcons"));
- hide_button->set_hover_texture(get_icon("Close", "EditorIcons"));
- hide_button->set_pressed_texture(get_icon("Close", "EditorIcons"));
+ find_prev->set_icon(get_theme_icon("MoveUp", "EditorIcons"));
+ find_next->set_icon(get_theme_icon("MoveDown", "EditorIcons"));
+ hide_button->set_normal_texture(get_theme_icon("Close", "EditorIcons"));
+ hide_button->set_hover_texture(get_theme_icon("Close", "EditorIcons"));
+ hide_button->set_pressed_texture(get_theme_icon("Close", "EditorIcons"));
hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size());
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
- matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor"));
+ matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor"));
}
}
@@ -226,6 +226,10 @@ void FindReplaceBar::_replace_all() {
text_edit->begin_complex_operation();
+ if (selection_enabled && is_selection_only()) {
+ text_edit->cursor_set_line(selection_begin.width);
+ text_edit->cursor_set_column(selection_begin.height);
+ }
if (search_current()) {
do {
// replace area
@@ -243,7 +247,7 @@ void FindReplaceBar::_replace_all() {
if (selection_enabled && is_selection_only()) {
if (match_from < selection_begin || match_to > selection_end) {
- continue;
+ break; // Done.
}
// Replace but adjust selection bounds.
@@ -277,7 +281,7 @@ void FindReplaceBar::_replace_all() {
}
text_edit->set_v_scroll(vsval);
- matches_label->add_color_override("font_color", rc > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor"));
+ matches_label->add_theme_color_override("font_color", rc > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor"));
matches_label->set_text(vformat(TTR("%d replaced."), rc));
text_edit->call_deferred("connect", "text_changed", Callable(this, "_editor_text_changed"));
@@ -289,6 +293,10 @@ void FindReplaceBar::_get_search_from(int &r_line, int &r_col) {
r_line = text_edit->cursor_get_line();
r_col = text_edit->cursor_get_column();
+ if (text_edit->is_selection_active() && is_selection_only()) {
+ return;
+ }
+
if (r_line == result_line && r_col >= result_col && r_col <= result_col + get_search_text().length()) {
r_col = result_col;
}
@@ -331,7 +339,7 @@ void FindReplaceBar::_update_matches_label() {
} else {
matches_label->show();
- matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor"));
+ matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor"));
matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count));
}
}
@@ -505,7 +513,7 @@ void FindReplaceBar::_search_text_changed(const String &p_text) {
void FindReplaceBar::_search_text_entered(const String &p_text) {
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
search_prev();
} else {
search_next();
@@ -517,7 +525,7 @@ void FindReplaceBar::_replace_text_entered(const String &p_text) {
if (selection_only->is_pressed() && text_edit->is_selection_active()) {
_replace_all();
_hide_bar();
- } else if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ } else if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
_replace();
search_prev();
} else {
@@ -712,7 +720,7 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
if (magnify_gesture.is_valid()) {
- Ref<DynamicFont> font = text_editor->get_font("font");
+ Ref<DynamicFont> font = text_editor->get_theme_font("font");
if (font.is_valid()) {
if (font->get_size() != (int)font_size) {
@@ -760,7 +768,7 @@ void CodeTextEditor::_zoom_changed() {
}
void CodeTextEditor::_reset_zoom() {
- Ref<DynamicFont> font = text_editor->get_font("font"); // Reset source font size to default.
+ Ref<DynamicFont> font = text_editor->get_theme_font("font"); // Reset source font size to default.
if (font.is_valid()) {
EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14);
@@ -828,41 +836,41 @@ Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOp
Ref<Texture2D> tex;
switch (p_option.kind) {
case ScriptCodeCompletionOption::KIND_CLASS: {
- if (has_icon(p_option.display, "EditorIcons")) {
- tex = get_icon(p_option.display, "EditorIcons");
+ if (has_theme_icon(p_option.display, "EditorIcons")) {
+ tex = get_theme_icon(p_option.display, "EditorIcons");
} else {
- tex = get_icon("Object", "EditorIcons");
+ tex = get_theme_icon("Object", "EditorIcons");
}
} break;
case ScriptCodeCompletionOption::KIND_ENUM:
- tex = get_icon("Enum", "EditorIcons");
+ tex = get_theme_icon("Enum", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_FILE_PATH:
- tex = get_icon("File", "EditorIcons");
+ tex = get_theme_icon("File", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_NODE_PATH:
- tex = get_icon("NodePath", "EditorIcons");
+ tex = get_theme_icon("NodePath", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_VARIABLE:
- tex = get_icon("Variant", "EditorIcons");
+ tex = get_theme_icon("Variant", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_CONSTANT:
- tex = get_icon("MemberConstant", "EditorIcons");
+ tex = get_theme_icon("MemberConstant", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_MEMBER:
- tex = get_icon("MemberProperty", "EditorIcons");
+ tex = get_theme_icon("MemberProperty", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_SIGNAL:
- tex = get_icon("MemberSignal", "EditorIcons");
+ tex = get_theme_icon("MemberSignal", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_FUNCTION:
- tex = get_icon("MemberMethod", "EditorIcons");
+ tex = get_theme_icon("MemberMethod", "EditorIcons");
break;
case ScriptCodeCompletionOption::KIND_PLAIN_TEXT:
- tex = get_icon("CubeMesh", "EditorIcons");
+ tex = get_theme_icon("CubeMesh", "EditorIcons");
break;
default:
- tex = get_icon("String", "EditorIcons");
+ tex = get_theme_icon("String", "EditorIcons");
break;
}
return tex;
@@ -877,7 +885,7 @@ void CodeTextEditor::_font_resize_timeout() {
bool CodeTextEditor::_add_font_size(int p_delta) {
- Ref<DynamicFont> font = text_editor->get_font("font");
+ Ref<DynamicFont> font = text_editor->get_theme_font("font");
if (font.is_valid()) {
int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE);
@@ -1454,18 +1462,18 @@ void CodeTextEditor::goto_error() {
void CodeTextEditor::_update_font() {
- text_editor->add_font_override("font", get_font("source", "EditorFonts"));
+ text_editor->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
- error->add_font_override("font", get_font("status_source", "EditorFonts"));
- error->add_color_override("font_color", get_color("error_color", "Editor"));
+ error->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts"));
+ error->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
- Ref<Font> status_bar_font = get_font("status_source", "EditorFonts");
- error->add_font_override("font", status_bar_font);
+ Ref<Font> status_bar_font = get_theme_font("status_source", "EditorFonts");
+ error->add_theme_font_override("font", status_bar_font);
int count = status_bar->get_child_count();
for (int i = 0; i < count; i++) {
Control *n = Object::cast_to<Control>(status_bar->get_child(i));
if (n)
- n->add_font_override("font", status_bar_font);
+ n->add_theme_font_override("font", status_bar_font);
}
}
@@ -1516,7 +1524,7 @@ void CodeTextEditor::_set_show_warnings_panel(bool p_show) {
}
void CodeTextEditor::_toggle_scripts_pressed() {
- toggle_scripts_button->set_icon(ScriptEditor::get_singleton()->toggle_scripts_panel() ? get_icon("Back", "EditorIcons") : get_icon("Forward", "EditorIcons"));
+ toggle_scripts_button->set_icon(ScriptEditor::get_singleton()->toggle_scripts_panel() ? get_theme_icon("Back", "EditorIcons") : get_theme_icon("Forward", "EditorIcons"));
}
void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) {
@@ -1540,8 +1548,8 @@ void CodeTextEditor::_notification(int p_what) {
_update_font();
} break;
case NOTIFICATION_ENTER_TREE: {
- warning_button->set_icon(get_icon("NodeWarning", "EditorIcons"));
- add_constant_override("separation", 4 * EDSCALE);
+ warning_button->set_icon(get_theme_icon("NodeWarning", "EditorIcons"));
+ add_theme_constant_override("separation", 4 * EDSCALE);
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
if (toggle_scripts_button->is_visible()) {
@@ -1650,13 +1658,13 @@ void CodeTextEditor::show_toggle_scripts_button() {
}
void CodeTextEditor::update_toggle_scripts_button() {
- toggle_scripts_button->set_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? get_icon("Back", "EditorIcons") : get_icon("Forward", "EditorIcons"));
+ toggle_scripts_button->set_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? get_theme_icon("Back", "EditorIcons") : get_theme_icon("Forward", "EditorIcons"));
toggle_scripts_button->set_tooltip(TTR("Toggle Scripts Panel") + " (" + ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text() + ")");
}
CodeTextEditor::CodeTextEditor() {
- code_complete_func = NULL;
+ code_complete_func = nullptr;
ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KEY_MASK_CMD | KEY_EQUAL);
ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS);
ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KEY_MASK_CMD | KEY_0);
@@ -1729,8 +1737,8 @@ CodeTextEditor::CodeTextEditor() {
warning_count_label->set_default_cursor_shape(CURSOR_POINTING_HAND);
warning_count_label->set_mouse_filter(MOUSE_FILTER_STOP);
warning_count_label->set_tooltip(TTR("Warnings"));
- warning_count_label->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor"));
- warning_count_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+ warning_count_label->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor"));
+ warning_count_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts"));
warning_count_label->connect("gui_input", callable_mp(this, &CodeTextEditor::_warning_label_gui_input));
is_warnings_panel_opened = false;
@@ -1740,7 +1748,7 @@ CodeTextEditor::CodeTextEditor() {
line_and_col_txt = memnew(Label);
status_bar->add_child(line_and_col_txt);
line_and_col_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
- line_and_col_txt->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+ line_and_col_txt->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts"));
line_and_col_txt->set_tooltip(TTR("Line and column numbers."));
line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP);
diff --git a/editor/collada/SCsub b/editor/collada/SCsub
deleted file mode 100644
index 2b1e889fb0..0000000000
--- a/editor/collada/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp
deleted file mode 100644
index 231173e459..0000000000
--- a/editor/collada/collada.cpp
+++ /dev/null
@@ -1,2574 +0,0 @@
-/*************************************************************************/
-/* collada.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collada.h"
-
-#include <stdio.h>
-
-//#define DEBUG_DEFAULT_ANIMATION
-//#define DEBUG_COLLADA
-#ifdef DEBUG_COLLADA
-#define COLLADA_PRINT(m_what) print_line(m_what)
-#else
-#define COLLADA_PRINT(m_what)
-#endif
-
-#define COLLADA_IMPORT_SCALE_SCENE
-
-/* HELPERS */
-
-String Collada::Effect::get_texture_path(const String &p_source, Collada &state) const {
-
- const String &image = p_source;
- ERR_FAIL_COND_V(!state.state.image_map.has(image), "");
- return state.state.image_map[image].path;
-}
-
-Transform Collada::get_root_transform() const {
-
- Transform unit_scale_transform;
-#ifndef COLLADA_IMPORT_SCALE_SCENE
- unit_scale_transform.scale(Vector3(state.unit_scale, state.unit_scale, state.unit_scale));
-#endif
- return unit_scale_transform;
-}
-
-void Collada::Vertex::fix_unit_scale(Collada &state) {
-#ifdef COLLADA_IMPORT_SCALE_SCENE
- vertex *= state.state.unit_scale;
-#endif
-}
-
-static String _uri_to_id(const String &p_uri) {
-
- if (p_uri.begins_with("#"))
- return p_uri.substr(1, p_uri.size() - 1);
- else
- return p_uri;
-}
-
-/** HELPER FUNCTIONS **/
-
-Transform Collada::fix_transform(const Transform &p_transform) {
-
- Transform tr = p_transform;
-
-#ifndef NO_UP_AXIS_SWAP
-
- if (state.up_axis != Vector3::AXIS_Y) {
-
- for (int i = 0; i < 3; i++)
- SWAP(tr.basis[1][i], tr.basis[state.up_axis][i]);
- for (int i = 0; i < 3; i++)
- SWAP(tr.basis[i][1], tr.basis[i][state.up_axis]);
-
- SWAP(tr.origin[1], tr.origin[state.up_axis]);
-
- tr.basis[state.up_axis][0] = -tr.basis[state.up_axis][0];
- tr.basis[state.up_axis][1] = -tr.basis[state.up_axis][1];
- tr.basis[0][state.up_axis] = -tr.basis[0][state.up_axis];
- tr.basis[1][state.up_axis] = -tr.basis[1][state.up_axis];
- tr.origin[state.up_axis] = -tr.origin[state.up_axis];
- }
-#endif
-
- //tr.scale(Vector3(state.unit_scale.unit_scale.unit_scale));
- return tr;
- //return state.matrix_fix * p_transform;
-}
-
-static Transform _read_transform_from_array(const Vector<float> &array, int ofs = 0) {
-
- Transform tr;
- // i wonder why collada matrices are transposed, given that's opposed to opengl..
- tr.basis.elements[0][0] = array[0 + ofs];
- tr.basis.elements[0][1] = array[1 + ofs];
- tr.basis.elements[0][2] = array[2 + ofs];
- tr.basis.elements[1][0] = array[4 + ofs];
- tr.basis.elements[1][1] = array[5 + ofs];
- tr.basis.elements[1][2] = array[6 + ofs];
- tr.basis.elements[2][0] = array[8 + ofs];
- tr.basis.elements[2][1] = array[9 + ofs];
- tr.basis.elements[2][2] = array[10 + ofs];
- tr.origin.x = array[3 + ofs];
- tr.origin.y = array[7 + ofs];
- tr.origin.z = array[11 + ofs];
- return tr;
-}
-
-/* STRUCTURES */
-
-Transform Collada::Node::compute_transform(Collada &state) const {
-
- Transform xform;
-
- for (int i = 0; i < xform_list.size(); i++) {
-
- Transform xform_step;
- const XForm &xf = xform_list[i];
- switch (xf.op) {
-
- case XForm::OP_ROTATE: {
- if (xf.data.size() >= 4) {
-
- xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg2rad(xf.data[3]));
- }
- } break;
- case XForm::OP_SCALE: {
-
- if (xf.data.size() >= 3) {
-
- xform_step.scale(Vector3(xf.data[0], xf.data[1], xf.data[2]));
- }
-
- } break;
- case XForm::OP_TRANSLATE: {
-
- if (xf.data.size() >= 3) {
-
- xform_step.origin = Vector3(xf.data[0], xf.data[1], xf.data[2]);
- }
-
- } break;
- case XForm::OP_MATRIX: {
-
- if (xf.data.size() >= 16) {
- xform_step = _read_transform_from_array(xf.data, 0);
- }
-
- } break;
- default: {
- }
- }
-
- xform = xform * xform_step;
- }
-
-#ifdef COLLADA_IMPORT_SCALE_SCENE
- xform.origin *= state.state.unit_scale;
-#endif
- return xform;
-}
-
-Transform Collada::Node::get_transform() const {
-
- return default_transform;
-}
-
-Transform Collada::Node::get_global_transform() const {
-
- if (parent)
- return parent->get_global_transform() * default_transform;
- else
- return default_transform;
-}
-
-Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const {
-
- ERR_FAIL_COND_V(keys.size() == 0, Vector<float>());
- int i = 0;
-
- for (i = 0; i < keys.size(); i++) {
-
- if (keys[i].time > p_time)
- break;
- }
-
- if (i == 0)
- return keys[0].data;
- if (i == keys.size())
- return keys[keys.size() - 1].data;
-
- switch (keys[i].interp_type) {
-
- case INTERP_BEZIER: //wait for bezier
- case INTERP_LINEAR: {
-
- float c = (p_time - keys[i - 1].time) / (keys[i].time - keys[i - 1].time);
-
- if (keys[i].data.size() == 16) {
- //interpolate a matrix
- Transform src = _read_transform_from_array(keys[i - 1].data);
- Transform dst = _read_transform_from_array(keys[i].data);
-
- Transform interp = c < 0.001 ? src : src.interpolate_with(dst, c);
-
- Vector<float> ret;
- ret.resize(16);
- Transform tr;
- // i wonder why collada matrices are transposed, given that's opposed to opengl..
- ret.write[0] = interp.basis.elements[0][0];
- ret.write[1] = interp.basis.elements[0][1];
- ret.write[2] = interp.basis.elements[0][2];
- ret.write[4] = interp.basis.elements[1][0];
- ret.write[5] = interp.basis.elements[1][1];
- ret.write[6] = interp.basis.elements[1][2];
- ret.write[8] = interp.basis.elements[2][0];
- ret.write[9] = interp.basis.elements[2][1];
- ret.write[10] = interp.basis.elements[2][2];
- ret.write[3] = interp.origin.x;
- ret.write[7] = interp.origin.y;
- ret.write[11] = interp.origin.z;
- ret.write[12] = 0;
- ret.write[13] = 0;
- ret.write[14] = 0;
- ret.write[15] = 1;
-
- return ret;
- } else {
-
- Vector<float> dest;
- dest.resize(keys[i].data.size());
- for (int j = 0; j < dest.size(); j++) {
-
- dest.write[j] = keys[i].data[j] * c + keys[i - 1].data[j] * (1.0 - c);
- }
- return dest;
- //interpolate one by one
- }
- } break;
- }
-
- ERR_FAIL_V(Vector<float>());
-}
-
-void Collada::_parse_asset(XMLParser &parser) {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
-
- if (name == "up_axis") {
-
- parser.read();
- if (parser.get_node_data() == "X_UP")
- state.up_axis = Vector3::AXIS_X;
- if (parser.get_node_data() == "Y_UP")
- state.up_axis = Vector3::AXIS_Y;
- if (parser.get_node_data() == "Z_UP")
- state.up_axis = Vector3::AXIS_Z;
-
- COLLADA_PRINT("up axis: " + parser.get_node_data());
- } else if (name == "unit") {
-
- state.unit_scale = parser.get_attribute_value("meter").to_double();
- COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "asset")
- break; //end of <asset>
- }
-}
-
-void Collada::_parse_image(XMLParser &parser) {
-
- String id = parser.get_attribute_value("id");
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- Image image;
-
- if (state.version < State::Version(1, 4, 0)) {
- /* <1.4 */
- String path = parser.get_attribute_value("source").strip_edges();
- if (path.find("://") == -1 && path.is_rel_path()) {
- // path is relative to file being loaded, so convert to a resource path
- image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.percent_decode()));
- }
- } else {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
-
- if (name == "init_from") {
-
- parser.read();
- String path = parser.get_node_data().strip_edges().percent_decode();
-
- if (path.find("://") == -1 && path.is_rel_path()) {
- // path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
-
- } else if (path.find("file:///") == 0) {
- path = path.replace_first("file:///", "");
- path = ProjectSettings::get_singleton()->localize_path(path);
- }
-
- image.path = path;
-
- } else if (name == "data") {
-
- ERR_PRINT("COLLADA Embedded image data not supported!");
-
- } else if (name == "extra" && !parser.is_empty())
- parser.skip_section();
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "image")
- break; //end of <asset>
- }
- }
-
- state.image_map[id] = image;
-}
-
-void Collada::_parse_material(XMLParser &parser) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- Material material;
-
- String id = parser.get_attribute_value("id");
- if (parser.has_attribute("name"))
- material.name = parser.get_attribute_value("name");
-
- if (state.version < State::Version(1, 4, 0)) {
- /* <1.4 */
- ERR_PRINT("Collada Materials < 1.4 are not supported (yet)");
- } else {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
-
- material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material")
- break; //end of <asset>
- }
- }
-
- state.material_map[id] = material;
-}
-
-//! reads floats from inside of xml element until end of xml element
-Vector<float> Collada::_read_float_array(XMLParser &parser) {
-
- if (parser.is_empty())
- return Vector<float>();
-
- Vector<String> splitters;
- splitters.push_back(" ");
- splitters.push_back("\n");
- splitters.push_back("\r");
- splitters.push_back("\t");
-
- Vector<float> array;
- while (parser.read() == OK) {
- // TODO: check for comments inside the element
- // and ignore them.
-
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
- // parse float data
- String str = parser.get_node_data();
- array = str.split_floats_mk(splitters, false);
- //array=str.split_floats(" ",false);
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
- break; // end parsing text
- }
-
- return array;
-}
-
-Vector<String> Collada::_read_string_array(XMLParser &parser) {
-
- if (parser.is_empty())
- return Vector<String>();
-
- Vector<String> array;
- while (parser.read() == OK) {
- // TODO: check for comments inside the element
- // and ignore them.
-
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
- // parse String data
- String str = parser.get_node_data();
- array = str.split_spaces();
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
- break; // end parsing text
- }
-
- return array;
-}
-
-Transform Collada::_read_transform(XMLParser &parser) {
-
- if (parser.is_empty())
- return Transform();
-
- Vector<String> array;
- while (parser.read() == OK) {
- // TODO: check for comments inside the element
- // and ignore them.
-
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
- // parse float data
- String str = parser.get_node_data();
- array = str.split_spaces();
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
- break; // end parsing text
- }
-
- ERR_FAIL_COND_V(array.size() != 16, Transform());
- Vector<float> farr;
- farr.resize(16);
- for (int i = 0; i < 16; i++) {
- farr.write[i] = array[i].to_double();
- }
-
- return _read_transform_from_array(farr);
-}
-
-String Collada::_read_empty_draw_type(XMLParser &parser) {
-
- String empty_draw_type = "";
-
- if (parser.is_empty())
- return empty_draw_type;
-
- while (parser.read() == OK) {
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
- empty_draw_type = parser.get_node_data();
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
- break; // end parsing text
- }
- return empty_draw_type;
-}
-
-Variant Collada::_parse_param(XMLParser &parser) {
-
- if (parser.is_empty())
- return Variant();
-
- String from = parser.get_node_name();
- Variant data;
-
- while (parser.read() == OK) {
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "float") {
-
- parser.read();
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
-
- data = parser.get_node_data().to_double();
- }
- } else if (parser.get_node_name() == "float2") {
-
- Vector<float> v2 = _read_float_array(parser);
-
- if (v2.size() >= 2) {
-
- data = Vector2(v2[0], v2[1]);
- }
- } else if (parser.get_node_name() == "float3") {
-
- Vector<float> v3 = _read_float_array(parser);
-
- if (v3.size() >= 3) {
-
- data = Vector3(v3[0], v3[1], v3[2]);
- }
- } else if (parser.get_node_name() == "float4") {
-
- Vector<float> v4 = _read_float_array(parser);
-
- if (v4.size() >= 4) {
-
- data = Color(v4[0], v4[1], v4[2], v4[3]);
- }
- } else if (parser.get_node_name() == "sampler2D") {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "source") {
-
- parser.read();
-
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
-
- data = parser.get_node_data();
- }
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "sampler2D")
- break;
- }
- } else if (parser.get_node_name() == "surface") {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "init_from") {
-
- parser.read();
-
- if (parser.get_node_type() == XMLParser::NODE_TEXT) {
-
- data = parser.get_node_data();
- }
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "surface")
- break;
- }
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == from)
- break;
- }
-
- COLLADA_PRINT("newparam ending " + parser.get_node_name());
- return data;
-}
-
-void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &id) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- // first come the tags we descend, but ignore the top-levels
-
- COLLADA_PRINT("node name: " + parser.get_node_name());
-
- if (!parser.is_empty() && (parser.get_node_name() == "profile_COMMON" || parser.get_node_name() == "technique" || parser.get_node_name() == "extra")) {
-
- _parse_effect_material(parser, effect, id); // try again
-
- } else if (parser.get_node_name() == "newparam") {
- String name = parser.get_attribute_value("sid");
- Variant value = _parse_param(parser);
- effect.params[name] = value;
- COLLADA_PRINT("param: " + name + " value:" + String(value));
-
- } else if (parser.get_node_name() == "constant" ||
- parser.get_node_name() == "lambert" ||
- parser.get_node_name() == "phong" ||
- parser.get_node_name() == "blinn") {
-
- COLLADA_PRINT("shade model: " + parser.get_node_name());
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String what = parser.get_node_name();
-
- if (what == "emission" ||
- what == "diffuse" ||
- what == "specular" ||
- what == "reflective") {
-
- // color or texture types
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "color") {
-
- Vector<float> colorarr = _read_float_array(parser);
- COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
-
- if (colorarr.size() >= 3) {
-
- // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
- Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
- if (what == "diffuse")
- effect.diffuse.color = color;
- if (what == "specular")
- effect.specular.color = color;
- if (what == "emission")
- effect.emission.color = color;
-
- COLLADA_PRINT(what + " color: " + color);
- }
-
- } else if (parser.get_node_name() == "texture") {
-
- String sampler = parser.get_attribute_value("texture");
- if (!effect.params.has(sampler)) {
- ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
- } else {
- String surface = effect.params[sampler];
-
- if (!effect.params.has(surface)) {
- ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
- } else {
- String uri = effect.params[surface];
-
- if (what == "diffuse") {
- effect.diffuse.texture = uri;
- } else if (what == "specular") {
- effect.specular.texture = uri;
- } else if (what == "emission") {
- effect.emission.texture = uri;
- } else if (what == "bump") {
- if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
- WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
- }
-
- effect.bump.texture = uri;
- }
-
- COLLADA_PRINT(what + " texture: " + uri);
- }
- }
- } else if (!parser.is_empty())
- parser.skip_section();
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == what)
- break;
- }
-
- } else if (what == "shininess") {
- effect.shininess = _parse_param(parser);
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && (parser.get_node_name() == "constant" ||
- parser.get_node_name() == "lambert" ||
- parser.get_node_name() == "phong" ||
- parser.get_node_name() == "blinn"))
- break;
- }
- } else if (parser.get_node_name() == "double_sided" || parser.get_node_name() == "show_double_sided") { // colladamax / google earth
-
- // 3DS Max / Google Earth double sided extension
- parser.read();
- effect.found_double_sided = true;
- effect.double_sided = parser.get_node_data().to_int();
- COLLADA_PRINT("double sided: " + itos(parser.get_node_data().to_int()));
- } else if (parser.get_node_name() == "unshaded") {
- parser.read();
- effect.unshaded = parser.get_node_data().to_int();
- } else if (parser.get_node_name() == "bump") {
-
- // color or texture types
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "texture") {
-
- String sampler = parser.get_attribute_value("texture");
- if (!effect.params.has(sampler)) {
- ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
- } else {
- String surface = effect.params[sampler];
-
- if (!effect.params.has(surface)) {
- ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
- } else {
- String uri = effect.params[surface];
-
- if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
- WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
- }
-
- effect.bump.texture = uri;
- COLLADA_PRINT(" bump: " + uri);
- }
- }
- } else if (!parser.is_empty())
- parser.skip_section();
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "bump")
- break;
- }
-
- } else if (!parser.is_empty())
- parser.skip_section();
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END &&
- (parser.get_node_name() == "effect" ||
- parser.get_node_name() == "profile_COMMON" ||
- parser.get_node_name() == "technique" ||
- parser.get_node_name() == "extra"))
- break;
- }
-}
-
-void Collada::_parse_effect(XMLParser &parser) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- String id = parser.get_attribute_value("id");
-
- Effect effect;
- if (parser.has_attribute("name"))
- effect.name = parser.get_attribute_value("name");
- _parse_effect_material(parser, effect, id);
-
- state.effect_map[id] = effect;
-
- COLLADA_PRINT("Effect ID:" + id);
-}
-
-void Collada::_parse_camera(XMLParser &parser) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- String id = parser.get_attribute_value("id");
-
- state.camera_data_map[id] = CameraData();
- CameraData &camera = state.camera_data_map[id];
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
-
- if (name == "perspective") {
-
- camera.mode = CameraData::MODE_PERSPECTIVE;
- } else if (name == "orthographic") {
-
- camera.mode = CameraData::MODE_ORTHOGONAL;
- } else if (name == "xfov") {
-
- parser.read();
- camera.perspective.x_fov = parser.get_node_data().to_double();
-
- } else if (name == "yfov") {
-
- parser.read();
- camera.perspective.y_fov = parser.get_node_data().to_double();
- } else if (name == "xmag") {
-
- parser.read();
- camera.orthogonal.x_mag = parser.get_node_data().to_double();
-
- } else if (name == "ymag") {
-
- parser.read();
- camera.orthogonal.y_mag = parser.get_node_data().to_double();
- } else if (name == "aspect_ratio") {
-
- parser.read();
- camera.aspect = parser.get_node_data().to_double();
-
- } else if (name == "znear") {
-
- parser.read();
- camera.z_near = parser.get_node_data().to_double();
-
- } else if (name == "zfar") {
-
- parser.read();
- camera.z_far = parser.get_node_data().to_double();
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "camera")
- break; //end of <asset>
- }
-
- COLLADA_PRINT("Camera ID:" + id);
-}
-
-void Collada::_parse_light(XMLParser &parser) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- String id = parser.get_attribute_value("id");
-
- state.light_data_map[id] = LightData();
- LightData &light = state.light_data_map[id];
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
-
- if (name == "ambient") {
-
- light.mode = LightData::MODE_AMBIENT;
- } else if (name == "directional") {
-
- light.mode = LightData::MODE_DIRECTIONAL;
- } else if (name == "point") {
-
- light.mode = LightData::MODE_OMNI;
- } else if (name == "spot") {
-
- light.mode = LightData::MODE_SPOT;
- } else if (name == "color") {
-
- parser.read();
- Vector<float> colorarr = _read_float_array(parser);
- COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
-
- if (colorarr.size() >= 4) {
- // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
- Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
- light.color = color;
- }
-
- } else if (name == "constant_attenuation") {
-
- parser.read();
- light.constant_att = parser.get_node_data().to_double();
- } else if (name == "linear_attenuation") {
-
- parser.read();
- light.linear_att = parser.get_node_data().to_double();
- } else if (name == "quadratic_attenuation") {
-
- parser.read();
- light.quad_att = parser.get_node_data().to_double();
- } else if (name == "falloff_angle") {
-
- parser.read();
- light.spot_angle = parser.get_node_data().to_double();
-
- } else if (name == "falloff_exponent") {
-
- parser.read();
- light.spot_exp = parser.get_node_data().to_double();
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "light")
- break; //end of <asset>
- }
-
- COLLADA_PRINT("Light ID:" + id);
-}
-
-void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_name) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- //load everything into a pre dictionary
-
- state.curve_data_map[p_id] = CurveData();
-
- CurveData &curvedata = state.curve_data_map[p_id];
- curvedata.name = p_name;
-
- COLLADA_PRINT("curve name: " + p_name);
-
- String current_source;
- // handles geometry node and the curve children in this loop
- // read sources with arrays and accessor for each curve
- if (parser.is_empty()) {
- return;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "source") {
-
- String id = parser.get_attribute_value("id");
- curvedata.sources[id] = CurveData::Source();
- current_source = id;
- COLLADA_PRINT("source data: " + id);
-
- } else if (section == "float_array" || section == "array") {
- // create a new array and read it.
- if (curvedata.sources.has(current_source)) {
-
- curvedata.sources[current_source].array = _read_float_array(parser);
- COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
- }
- } else if (section == "Name_array") {
- // create a new array and read it.
- if (curvedata.sources.has(current_source)) {
-
- curvedata.sources[current_source].sarray = _read_string_array(parser);
- COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
- }
-
- } else if (section == "technique_common") {
- //skip it
- } else if (section == "accessor") { // child of source (below a technique tag)
-
- if (curvedata.sources.has(current_source)) {
- curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
- COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
- }
- } else if (section == "control_vertices") {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "input") {
-
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
-
- curvedata.control_vertices[semantic] = source;
-
- COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
- break;
- }
-
- } else if (!parser.is_empty()) {
-
- parser.skip_section();
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "spline")
- break;
- }
-}
-
-void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name) {
-
- if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
- if (!parser.is_empty())
- parser.skip_section();
- return;
- }
-
- //load everything into a pre dictionary
-
- state.mesh_data_map[p_id] = MeshData();
-
- MeshData &meshdata = state.mesh_data_map[p_id];
- meshdata.name = p_name;
-
- COLLADA_PRINT("mesh name: " + p_name);
-
- String current_source;
- // handles geometry node and the mesh children in this loop
- // read sources with arrays and accessor for each mesh
- if (parser.is_empty()) {
- return;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "source") {
-
- String id = parser.get_attribute_value("id");
- meshdata.sources[id] = MeshData::Source();
- current_source = id;
- COLLADA_PRINT("source data: " + id);
-
- } else if (section == "float_array" || section == "array") {
- // create a new array and read it.
- if (meshdata.sources.has(current_source)) {
-
- meshdata.sources[current_source].array = _read_float_array(parser);
- COLLADA_PRINT("section: " + current_source + " read " + itos(meshdata.sources[current_source].array.size()) + " values.");
- }
- } else if (section == "technique_common") {
- //skip it
- } else if (section == "accessor") { // child of source (below a technique tag)
-
- if (meshdata.sources.has(current_source)) {
- meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
- COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
- }
- } else if (section == "vertices") {
-
- MeshData::Vertices vert;
- String id = parser.get_attribute_value("id");
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "input") {
-
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
-
- vert.sources[semantic] = source;
-
- COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
- break;
- }
-
- meshdata.vertices[id] = vert;
-
- } else if (section == "triangles" || section == "polylist" || section == "polygons") {
-
- bool polygons = (section == "polygons");
- if (polygons) {
- WARN_PRINT("Primitive type \"polygons\" is not well supported (concave shapes may fail). To ensure that the geometry is properly imported, please re-export using \"triangles\" or \"polylist\".");
- }
- MeshData::Primitives prim;
-
- if (parser.has_attribute("material"))
- prim.material = parser.get_attribute_value("material");
- prim.count = parser.get_attribute_value("count").to_int();
- prim.vertex_size = 0;
- int last_ref = 0;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "input") {
-
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
-
- if (semantic == "TEXCOORD") {
- /*
- if (parser.has_attribute("set"))// a texcoord
- semantic+=parser.get_attribute_value("set");
- else
- semantic="TEXCOORD0";*/
- semantic = "TEXCOORD" + itos(last_ref++);
- }
- int offset = parser.get_attribute_value("offset").to_int();
-
- MeshData::Primitives::SourceRef sref;
- sref.source = source;
- sref.offset = offset;
- prim.sources[semantic] = sref;
- prim.vertex_size = MAX(prim.vertex_size, offset + 1);
-
- COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
-
- } else if (parser.get_node_name() == "p") { //indices
-
- Vector<float> values = _read_float_array(parser);
- if (polygons) {
-
- ERR_CONTINUE(prim.vertex_size == 0);
- prim.polygons.push_back(values.size() / prim.vertex_size);
- int from = prim.indices.size();
- prim.indices.resize(from + values.size());
- for (int i = 0; i < values.size(); i++)
- prim.indices.write[from + i] = values[i];
-
- } else if (prim.vertex_size > 0) {
- prim.indices = values;
- }
-
- COLLADA_PRINT("read " + itos(values.size()) + " index values");
-
- } else if (parser.get_node_name() == "vcount") { // primitive
-
- Vector<float> values = _read_float_array(parser);
- prim.polygons = values;
- COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
- break;
- }
-
- meshdata.primitives.push_back(prim);
-
- } else if (parser.get_node_name() == "double_sided") {
-
- parser.read();
- meshdata.found_double_sided = true;
- meshdata.double_sided = parser.get_node_data().to_int();
-
- } else if (parser.get_node_name() == "polygons") {
- ERR_PRINT("Primitive type \"polygons\" not supported, re-export using \"polylist\" or \"triangles\".");
- } else if (!parser.is_empty()) {
-
- parser.skip_section();
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "mesh")
- break;
- }
-}
-
-void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
-
- state.skin_controller_data_map[p_id] = SkinControllerData();
- SkinControllerData &skindata = state.skin_controller_data_map[p_id];
-
- skindata.base = _uri_to_id(parser.get_attribute_value("source"));
-
- String current_source;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "bind_shape_matrix") {
-
- skindata.bind_shape = _read_transform(parser);
-#ifdef COLLADA_IMPORT_SCALE_SCENE
- skindata.bind_shape.origin *= state.unit_scale;
-
-#endif
- COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
-
- } else if (section == "source") {
-
- String id = parser.get_attribute_value("id");
- skindata.sources[id] = SkinControllerData::Source();
- current_source = id;
- COLLADA_PRINT("source data: " + id);
-
- } else if (section == "float_array" || section == "array") {
- // create a new array and read it.
- if (skindata.sources.has(current_source)) {
-
- skindata.sources[current_source].array = _read_float_array(parser);
- COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
- }
- } else if (section == "Name_array" || section == "IDREF_array") {
- // create a new array and read it.
-
- if (section == "IDREF_array")
- skindata.use_idrefs = true;
- if (skindata.sources.has(current_source)) {
-
- skindata.sources[current_source].sarray = _read_string_array(parser);
- if (section == "IDREF_array") {
- Vector<String> sa = skindata.sources[current_source].sarray;
- for (int i = 0; i < sa.size(); i++)
- state.idref_joints.insert(sa[i]);
- }
- COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
- }
- } else if (section == "technique_common") {
- //skip it
- } else if (section == "accessor") { // child of source (below a technique tag)
-
- if (skindata.sources.has(current_source)) {
-
- int stride = 1;
- if (parser.has_attribute("stride"))
- stride = parser.get_attribute_value("stride").to_int();
-
- skindata.sources[current_source].stride = stride;
- COLLADA_PRINT("section: " + current_source + " stride " + itos(skindata.sources[current_source].stride));
- }
-
- } else if (section == "joints") {
-
- SkinControllerData::Joints joint;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "input") {
-
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
-
- joint.sources[semantic] = source;
-
- COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
- break;
- }
-
- skindata.joints = joint;
-
- } else if (section == "vertex_weights") {
-
- SkinControllerData::Weights weights;
-
- weights.count = parser.get_attribute_value("count").to_int();
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "input") {
-
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
-
- int offset = parser.get_attribute_value("offset").to_int();
-
- SkinControllerData::Weights::SourceRef sref;
- sref.source = source;
- sref.offset = offset;
- weights.sources[semantic] = sref;
-
- COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
-
- } else if (parser.get_node_name() == "v") { //indices
-
- Vector<float> values = _read_float_array(parser);
- weights.indices = values;
- COLLADA_PRINT("read " + itos(values.size()) + " index values");
-
- } else if (parser.get_node_name() == "vcount") { // weightsitive
-
- Vector<float> values = _read_float_array(parser);
- weights.sets = values;
- COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
- break;
- }
-
- skindata.weights = weights;
- }
- /*
- else if (!parser.is_empty())
- parser.skip_section();
- */
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "skin")
- break;
- }
-
- /* STORE REST MATRICES */
-
- Vector<Transform> rests;
- ERR_FAIL_COND(!skindata.joints.sources.has("JOINT"));
- ERR_FAIL_COND(!skindata.joints.sources.has("INV_BIND_MATRIX"));
-
- String joint_arr = skindata.joints.sources["JOINT"];
- String ibm = skindata.joints.sources["INV_BIND_MATRIX"];
-
- ERR_FAIL_COND(!skindata.sources.has(joint_arr));
- ERR_FAIL_COND(!skindata.sources.has(ibm));
-
- SkinControllerData::Source &joint_source = skindata.sources[joint_arr];
- SkinControllerData::Source &ibm_source = skindata.sources[ibm];
-
- ERR_FAIL_COND(joint_source.sarray.size() != ibm_source.array.size() / 16);
-
- for (int i = 0; i < joint_source.sarray.size(); i++) {
-
- String name = joint_source.sarray[i];
- Transform xform = _read_transform_from_array(ibm_source.array, i * 16); //<- this is a mistake, it must be applied to vertices
- xform.affine_invert(); // inverse for rest, because it's an inverse
-#ifdef COLLADA_IMPORT_SCALE_SCENE
- xform.origin *= state.unit_scale;
-#endif
- skindata.bone_rest_map[name] = xform;
- }
-}
-
-void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
-
- state.morph_controller_data_map[p_id] = MorphControllerData();
- MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
-
- morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
- morphdata.mode = parser.get_attribute_value("method");
- String current_source;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "source") {
-
- String id = parser.get_attribute_value("id");
- morphdata.sources[id] = MorphControllerData::Source();
- current_source = id;
- COLLADA_PRINT("source data: " + id);
-
- } else if (section == "float_array" || section == "array") {
- // create a new array and read it.
- if (morphdata.sources.has(current_source)) {
-
- morphdata.sources[current_source].array = _read_float_array(parser);
- COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
- }
- } else if (section == "Name_array" || section == "IDREF_array") {
- // create a new array and read it.
-
- /*
- if (section=="IDREF_array")
- morphdata.use_idrefs=true;
- */
- if (morphdata.sources.has(current_source)) {
-
- morphdata.sources[current_source].sarray = _read_string_array(parser);
- /*
- if (section=="IDREF_array") {
- Vector<String> sa = morphdata.sources[current_source].sarray;
- for(int i=0;i<sa.size();i++)
- state.idref_joints.insert(sa[i]);
- }*/
- COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
- }
- } else if (section == "technique_common") {
- //skip it
- } else if (section == "accessor") { // child of source (below a technique tag)
-
- if (morphdata.sources.has(current_source)) {
-
- int stride = 1;
- if (parser.has_attribute("stride"))
- stride = parser.get_attribute_value("stride").to_int();
-
- morphdata.sources[current_source].stride = stride;
- COLLADA_PRINT("section: " + current_source + " stride " + itos(morphdata.sources[current_source].stride));
- }
-
- } else if (section == "targets") {
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "input") {
-
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
-
- morphdata.targets[semantic] = source;
-
- COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
- break;
- }
- }
- /*
- else if (!parser.is_empty())
- parser.skip_section();
- */
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "morph")
- break;
- }
-
- if (morphdata.targets.has("MORPH_WEIGHT")) {
-
- state.morph_name_map[morphdata.targets["MORPH_WEIGHT"]] = p_id;
- }
-}
-
-void Collada::_parse_controller(XMLParser &parser) {
-
- String id = parser.get_attribute_value("id");
-
- if (parser.is_empty()) {
- return;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "skin") {
- _parse_skin_controller(parser, id);
- } else if (section == "morph") {
- _parse_morph_controller(parser, id);
- }
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "controller")
- break;
- }
-}
-
-Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
-
- String type = parser.get_node_name();
- NodeGeometry *geom = memnew(NodeGeometry);
- geom->controller = type == "instance_controller";
- geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
-
- if (parser.is_empty()) //nothing else to parse...
- return geom;
- // try to find also many materials and skeletons!
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "instance_material") {
-
- String symbol = parser.get_attribute_value("symbol");
- String target = _uri_to_id(parser.get_attribute_value("target"));
-
- NodeGeometry::Material mat;
- mat.target = target;
- geom->material_map[symbol] = mat;
- COLLADA_PRINT("uses material: '" + target + "' on primitive'" + symbol + "'");
- } else if (parser.get_node_name() == "skeleton") {
-
- parser.read();
- String uri = _uri_to_id(parser.get_node_data());
- if (uri != "") {
- geom->skeletons.push_back(uri);
- }
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == type)
- break;
- }
-
- if (geom->controller) {
-
- if (geom->skeletons.empty()) {
- //XSI style
-
- if (state.skin_controller_data_map.has(geom->source)) {
- SkinControllerData *skin = &state.skin_controller_data_map[geom->source];
- //case where skeletons reference bones with IDREF (XSI)
- ERR_FAIL_COND_V(!skin->joints.sources.has("JOINT"), geom);
- String joint_arr = skin->joints.sources["JOINT"];
- ERR_FAIL_COND_V(!skin->sources.has(joint_arr), geom);
- Collada::SkinControllerData::Source &joint_source = skin->sources[joint_arr];
- geom->skeletons = joint_source.sarray; //quite crazy, but should work.
- }
- }
- }
-
- return geom;
-}
-
-Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
-
- NodeCamera *cam = memnew(NodeCamera);
- cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
-
- if (state.up_axis == Vector3::AXIS_Z) //collada weirdness
- cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
-
- if (parser.is_empty()) //nothing else to parse...
- return cam;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_camera")
- break;
- }
-
- return cam;
-}
-
-Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
-
- NodeLight *cam = memnew(NodeLight);
- cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
-
- if (state.up_axis == Vector3::AXIS_Z) //collada weirdness
- cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
-
- if (parser.is_empty()) //nothing else to parse...
- return cam;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_light")
- break;
- }
-
- return cam;
-}
-
-Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
-
- String instance_type = parser.get_node_name();
-
- if (instance_type == "instance_geometry" || instance_type == "instance_controller") {
- return _parse_visual_instance_geometry(parser);
- } else if (instance_type == "instance_camera") {
-
- return _parse_visual_instance_camera(parser);
- } else if (instance_type == "instance_light") {
- return _parse_visual_instance_light(parser);
- }
-
- if (parser.is_empty()) //nothing else to parse...
- return NULL;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == instance_type)
- break;
- }
-
- return NULL;
-}
-
-Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
-
- String name;
-
- String id = parser.get_attribute_value_safe("id");
-
- bool found_name = false;
-
- if (id == "") {
-
- id = "%NODEID%" + itos(Math::rand());
-
- } else {
- found_name = true;
- }
-
- Vector<Node::XForm> xform_list;
- Vector<Node *> children;
-
- String empty_draw_type = "";
-
- Node *node = NULL;
-
- name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
- if (name == "") {
-
- name = id;
- } else {
- found_name = true;
- }
-
- if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
- // handle a bone
-
- NodeJoint *joint = memnew(NodeJoint);
-
- if (parser.has_attribute("sid")) { //bones may not have sid
- joint->sid = parser.get_attribute_value("sid");
- //state.bone_map[joint->sid]=joint;
- } else if (state.idref_joints.has(name)) {
- joint->sid = name; //kind of a cheat but..
- } else if (parser.has_attribute("name")) {
- joint->sid = parser.get_attribute_value_safe("name");
- }
-
- if (joint->sid != "") {
- state.sid_to_node_map[joint->sid] = id;
- }
-
- node = joint;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "translate") {
- Node::XForm xf;
- if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
- }
- xf.op = Node::XForm::OP_TRANSLATE;
-
- Vector<float> xlt = _read_float_array(parser);
- xf.data = xlt;
- xform_list.push_back(xf);
-
- } else if (section == "rotate") {
- Node::XForm xf;
- if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
- }
- xf.op = Node::XForm::OP_ROTATE;
-
- Vector<float> rot = _read_float_array(parser);
- xf.data = rot;
-
- xform_list.push_back(xf);
-
- } else if (section == "scale") {
- Node::XForm xf;
- if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
- }
-
- xf.op = Node::XForm::OP_SCALE;
-
- Vector<float> scale = _read_float_array(parser);
-
- xf.data = scale;
-
- xform_list.push_back(xf);
-
- } else if (section == "matrix") {
- Node::XForm xf;
- if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
- }
- xf.op = Node::XForm::OP_MATRIX;
-
- Vector<float> matrix = _read_float_array(parser);
-
- xf.data = matrix;
- String mtx;
- for (int i = 0; i < matrix.size(); i++)
- mtx += " " + rtos(matrix[i]);
-
- xform_list.push_back(xf);
-
- } else if (section == "visibility") {
- Node::XForm xf;
- if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
- }
- xf.op = Node::XForm::OP_VISIBILITY;
-
- Vector<float> visible = _read_float_array(parser);
-
- xf.data = visible;
-
- xform_list.push_back(xf);
-
- } else if (section == "empty_draw_type") {
- empty_draw_type = _read_empty_draw_type(parser);
- } else if (section == "technique" || section == "extra") {
-
- } else if (section != "node") {
- //usually what defines the type of node
- if (section.begins_with("instance_")) {
-
- if (!node) {
-
- node = _parse_visual_node_instance_data(parser);
-
- } else {
- ERR_PRINT("Multiple instance_* not supported.");
- }
- }
-
- } else {
-
- /* Found a child node!! what to do..*/
-
- Node *child = _parse_visual_scene_node(parser);
- children.push_back(child);
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "node")
- break;
- }
-
- if (!node) {
-
- node = memnew(Node); //generic node, nothing of relevance found
- }
-
- node->noname = !found_name;
- node->xform_list = xform_list;
- node->children = children;
- for (int i = 0; i < children.size(); i++) {
- node->children[i]->parent = node;
- }
-
- node->name = name;
- node->id = id;
- node->empty_draw_type = empty_draw_type;
-
- if (node->children.size() == 1) {
- if (node->children[0]->noname && !node->noname) {
- node->children[0]->name = node->name;
- node->name = node->name + "-base";
- }
- }
-
- node->default_transform = node->compute_transform(*this);
- state.scene_map[id] = node;
-
- return node;
-}
-
-void Collada::_parse_visual_scene(XMLParser &parser) {
-
- String id = parser.get_attribute_value("id");
-
- if (parser.is_empty()) {
- return;
- }
-
- state.visual_scene_map[id] = VisualScene();
- VisualScene &vscene = state.visual_scene_map[id];
-
- if (parser.has_attribute("name"))
- vscene.name = parser.get_attribute_value("name");
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String section = parser.get_node_name();
-
- if (section == "node") {
- vscene.root_nodes.push_back(_parse_visual_scene_node(parser));
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "visual_scene")
- break;
- }
-
- COLLADA_PRINT("Scene ID:" + id);
-}
-
-void Collada::_parse_animation(XMLParser &parser) {
-
- if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
- if (!parser.is_empty())
- parser.skip_section();
-
- return;
- }
-
- Map<String, Vector<float> > float_sources;
- Map<String, Vector<String> > string_sources;
- Map<String, int> source_strides;
- Map<String, Map<String, String> > samplers;
- Map<String, Vector<String> > source_param_names;
- Map<String, Vector<String> > source_param_types;
-
- String id = "";
- if (parser.has_attribute("id"))
- id = parser.get_attribute_value("id");
-
- String current_source;
- String current_sampler;
- Vector<String> channel_sources;
- Vector<String> channel_targets;
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
- if (name == "source") {
-
- current_source = parser.get_attribute_value("id");
- source_param_names[current_source] = Vector<String>();
- source_param_types[current_source] = Vector<String>();
-
- } else if (name == "float_array") {
-
- if (current_source != "") {
- float_sources[current_source] = _read_float_array(parser);
- }
-
- } else if (name == "Name_array") {
-
- if (current_source != "") {
- string_sources[current_source] = _read_string_array(parser);
- }
- } else if (name == "accessor") {
-
- if (current_source != "" && parser.has_attribute("stride")) {
- source_strides[current_source] = parser.get_attribute_value("stride").to_int();
- }
- } else if (name == "sampler") {
-
- current_sampler = parser.get_attribute_value("id");
- samplers[current_sampler] = Map<String, String>();
- } else if (name == "param") {
-
- if (parser.has_attribute("name"))
- source_param_names[current_source].push_back(parser.get_attribute_value("name"));
- else
- source_param_names[current_source].push_back("");
-
- if (parser.has_attribute("type"))
- source_param_types[current_source].push_back(parser.get_attribute_value("type"));
- else
- source_param_types[current_source].push_back("");
-
- } else if (name == "input") {
-
- if (current_sampler != "") {
-
- samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
- }
-
- } else if (name == "channel") {
-
- channel_sources.push_back(parser.get_attribute_value("source"));
- channel_targets.push_back(parser.get_attribute_value("target"));
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation")
- break; //end of <asset>
- }
-
- for (int i = 0; i < channel_sources.size(); i++) {
-
- String source = _uri_to_id(channel_sources[i]);
- String target = channel_targets[i];
- ERR_CONTINUE(!samplers.has(source));
- Map<String, String> &sampler = samplers[source];
-
- ERR_CONTINUE(!sampler.has("INPUT")); //no input semantic? wtf?
- String input_id = _uri_to_id(sampler["INPUT"]);
- COLLADA_PRINT("input id is " + input_id);
- ERR_CONTINUE(!float_sources.has(input_id));
-
- ERR_CONTINUE(!sampler.has("OUTPUT"));
- String output_id = _uri_to_id(sampler["OUTPUT"]);
- ERR_CONTINUE(!float_sources.has(output_id));
-
- ERR_CONTINUE(!source_param_names.has(output_id));
-
- Vector<String> &names = source_param_names[output_id];
-
- for (int l = 0; l < names.size(); l++) {
-
- String name = names[l];
-
- Vector<float> &time_keys = float_sources[input_id];
- int key_count = time_keys.size();
-
- AnimationTrack track; //begin crating track
- track.id = id;
-
- track.keys.resize(key_count);
-
- for (int j = 0; j < key_count; j++) {
- track.keys.write[j].time = time_keys[j];
- state.animation_length = MAX(state.animation_length, time_keys[j]);
- }
-
- //now read actual values
-
- int stride = 1;
-
- if (source_strides.has(output_id))
- stride = source_strides[output_id];
- int output_len = stride / names.size();
-
- ERR_CONTINUE(output_len == 0);
- ERR_CONTINUE(!float_sources.has(output_id));
-
- Vector<float> &output = float_sources[output_id];
-
- ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output.");
-
- for (int j = 0; j < key_count; j++) {
- track.keys.write[j].data.resize(output_len);
- for (int k = 0; k < output_len; k++)
- track.keys.write[j].data.write[k] = output[l + j * stride + k]; //super weird but should work:
- }
-
- if (sampler.has("INTERPOLATION")) {
-
- String interp_id = _uri_to_id(sampler["INTERPOLATION"]);
- ERR_CONTINUE(!string_sources.has(interp_id));
- Vector<String> &interps = string_sources[interp_id];
- ERR_CONTINUE(interps.size() != key_count);
-
- for (int j = 0; j < key_count; j++) {
- if (interps[j] == "BEZIER")
- track.keys.write[j].interp_type = AnimationTrack::INTERP_BEZIER;
- else
- track.keys.write[j].interp_type = AnimationTrack::INTERP_LINEAR;
- }
- }
-
- if (sampler.has("IN_TANGENT") && sampler.has("OUT_TANGENT")) {
- //bezier control points..
- String intangent_id = _uri_to_id(sampler["IN_TANGENT"]);
- ERR_CONTINUE(!float_sources.has(intangent_id));
- Vector<float> &intangents = float_sources[intangent_id];
-
- ERR_CONTINUE(intangents.size() != key_count * 2 * names.size());
-
- String outangent_id = _uri_to_id(sampler["OUT_TANGENT"]);
- ERR_CONTINUE(!float_sources.has(outangent_id));
- Vector<float> &outangents = float_sources[outangent_id];
- ERR_CONTINUE(outangents.size() != key_count * 2 * names.size());
-
- for (int j = 0; j < key_count; j++) {
- track.keys.write[j].in_tangent = Vector2(intangents[j * 2 * names.size() + 0 + l * 2], intangents[j * 2 * names.size() + 1 + l * 2]);
- track.keys.write[j].out_tangent = Vector2(outangents[j * 2 * names.size() + 0 + l * 2], outangents[j * 2 * names.size() + 1 + l * 2]);
- }
- }
-
- if (target.find("/") != -1) { //transform component
- track.target = target.get_slicec('/', 0);
- track.param = target.get_slicec('/', 1);
- if (track.param.find(".") != -1)
- track.component = track.param.get_slice(".", 1).to_upper();
- track.param = track.param.get_slice(".", 0);
- if (names.size() > 1 && track.component == "") {
- //this is a guess because the collada spec is ambiguous here...
- //i suppose if you have many names (outputs) you can't use a component and i should abide to that.
- track.component = name;
- }
- } else {
- track.target = target;
- }
-
- state.animation_tracks.push_back(track);
-
- if (!state.referenced_tracks.has(target))
- state.referenced_tracks[target] = Vector<int>();
-
- state.referenced_tracks[target].push_back(state.animation_tracks.size() - 1);
-
- if (id != "") {
- if (!state.by_id_tracks.has(id))
- state.by_id_tracks[id] = Vector<int>();
-
- state.by_id_tracks[id].push_back(state.animation_tracks.size() - 1);
- }
-
- COLLADA_PRINT("loaded animation with " + itos(key_count) + " keys");
- }
- }
-}
-
-void Collada::_parse_animation_clip(XMLParser &parser) {
-
- if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
- if (!parser.is_empty())
- parser.skip_section();
-
- return;
- }
-
- AnimationClip clip;
-
- if (parser.has_attribute("name"))
- clip.name = parser.get_attribute_value("name");
- else if (parser.has_attribute("id"))
- clip.name = parser.get_attribute_value("id");
- if (parser.has_attribute("start"))
- clip.begin = parser.get_attribute_value("start").to_double();
- if (parser.has_attribute("end"))
- clip.end = parser.get_attribute_value("end").to_double();
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
- if (name == "instance_animation") {
-
- String url = _uri_to_id(parser.get_attribute_value("url"));
- clip.tracks.push_back(url);
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation_clip")
- break; //end of <asset>
- }
-
- state.animation_clips.push_back(clip);
-}
-
-void Collada::_parse_scene(XMLParser &parser) {
-
- if (parser.is_empty()) {
- return;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
-
- if (name == "instance_visual_scene") {
-
- state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
- } else if (name == "instance_physics_scene") {
-
- state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
- }
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene")
- break; //end of <asset>
- }
-}
-
-void Collada::_parse_library(XMLParser &parser) {
-
- if (parser.is_empty()) {
- return;
- }
-
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser.get_node_name();
- COLLADA_PRINT("library name is: " + name);
- if (name == "image") {
-
- _parse_image(parser);
- } else if (name == "material") {
-
- _parse_material(parser);
- } else if (name == "effect") {
-
- _parse_effect(parser);
- } else if (name == "camera") {
-
- _parse_camera(parser);
- } else if (name == "light") {
-
- _parse_light(parser);
- } else if (name == "geometry") {
-
- String id = parser.get_attribute_value("id");
- String name2 = parser.get_attribute_value_safe("name");
- while (parser.read() == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "mesh") {
- state.mesh_name_map[id] = (name2 != "") ? name2 : id;
- _parse_mesh_geometry(parser, id, name2);
- } else if (parser.get_node_name() == "spline") {
- state.mesh_name_map[id] = (name2 != "") ? name2 : id;
- _parse_curve_geometry(parser, id, name2);
- } else if (!parser.is_empty())
- parser.skip_section();
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "geometry")
- break;
- }
-
- } else if (name == "controller") {
-
- _parse_controller(parser);
- } else if (name == "animation") {
-
- _parse_animation(parser);
- } else if (name == "animation_clip") {
-
- _parse_animation_clip(parser);
- } else if (name == "visual_scene") {
-
- COLLADA_PRINT("visual scene");
- _parse_visual_scene(parser);
- } else if (!parser.is_empty())
- parser.skip_section();
-
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name().begins_with("library_"))
- break; //end of <asset>
- }
-}
-
-void Collada::_joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner) {
-
- if (p_node->type == Node::TYPE_JOINT) {
-
- NodeJoint *nj = static_cast<NodeJoint *>(p_node);
- nj->owner = p_owner;
-
- for (int i = 0; i < nj->children.size(); i++) {
-
- _joint_set_owner(nj->children.write[i], p_owner);
- }
- }
-}
-
-void Collada::_create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton) {
-
- Node *node = *p_node;
-
- if (node->type == Node::TYPE_JOINT) {
-
- if (!p_skeleton) {
-
- // ohohohoohoo it's a joint node, time to work!
- NodeSkeleton *sk = memnew(NodeSkeleton);
- *p_node = sk;
- sk->children.push_back(node);
- sk->parent = node->parent;
- node->parent = sk;
- p_skeleton = sk;
- }
-
- NodeJoint *nj = static_cast<NodeJoint *>(node);
- nj->owner = p_skeleton;
- } else {
- p_skeleton = NULL;
- }
-
- for (int i = 0; i < node->children.size(); i++) {
- _create_skeletons(&node->children.write[i], p_skeleton);
- }
-}
-
-bool Collada::_remove_node(Node *p_parent, Node *p_node) {
-
- for (int i = 0; i < p_parent->children.size(); i++) {
-
- if (p_parent->children[i] == p_node) {
- p_parent->children.remove(i);
- return true;
- }
- if (_remove_node(p_parent->children[i], p_node))
- return true;
- }
-
- return false;
-}
-
-void Collada::_remove_node(VisualScene *p_vscene, Node *p_node) {
-
- for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
- if (p_vscene->root_nodes[i] == p_node) {
-
- p_vscene->root_nodes.remove(i);
- return;
- }
- if (_remove_node(p_vscene->root_nodes[i], p_node))
- return;
- }
-
- ERR_PRINT("ERROR: Not found node to remove?");
-}
-
-void Collada::_merge_skeletons(VisualScene *p_vscene, Node *p_node) {
-
- if (p_node->type == Node::TYPE_GEOMETRY) {
-
- NodeGeometry *gnode = static_cast<NodeGeometry *>(p_node);
- if (gnode->controller) {
-
- // recount skeletons used
- Set<NodeSkeleton *> skeletons;
-
- for (int i = 0; i < gnode->skeletons.size(); i++) {
-
- String nodeid = gnode->skeletons[i];
-
- ERR_CONTINUE(!state.scene_map.has(nodeid)); //weird, it should have it...
-
- NodeJoint *nj = SAFE_CAST<NodeJoint *>(state.scene_map[nodeid]);
- ERR_CONTINUE(!nj); //broken collada
- ERR_CONTINUE(!nj->owner); //weird, node should have a skeleton owner
-
- skeletons.insert(nj->owner);
- }
-
- if (skeletons.size() > 1) {
-
- //do the merger!!
- Set<NodeSkeleton *>::Element *E = skeletons.front();
- NodeSkeleton *base = E->get();
-
- for (E = E->next(); E; E = E->next()) {
-
- NodeSkeleton *merged = E->get();
- _remove_node(p_vscene, merged);
- for (int i = 0; i < merged->children.size(); i++) {
-
- _joint_set_owner(merged->children[i], base);
- base->children.push_back(merged->children[i]);
- merged->children[i]->parent = base;
- }
-
- merged->children.clear(); //take children from it
- memdelete(merged);
- }
- }
- }
- }
-
- for (int i = 0; i < p_node->children.size(); i++) {
- _merge_skeletons(p_vscene, p_node->children[i]);
- }
-}
-
-void Collada::_merge_skeletons2(VisualScene *p_vscene) {
-
- for (Map<String, SkinControllerData>::Element *E = state.skin_controller_data_map.front(); E; E = E->next()) {
-
- SkinControllerData &cd = E->get();
-
- NodeSkeleton *skeleton = NULL;
-
- for (Map<String, Transform>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) {
-
- String name;
-
- if (!state.sid_to_node_map.has(F->key())) {
- continue;
- }
-
- name = state.sid_to_node_map[F->key()];
-
- ERR_CONTINUE(!state.scene_map.has(name));
-
- Node *node = state.scene_map[name];
- ERR_CONTINUE(node->type != Node::TYPE_JOINT);
-
- NodeSkeleton *sk = NULL;
-
- while (node && !sk) {
-
- if (node->type == Node::TYPE_SKELETON) {
- sk = static_cast<NodeSkeleton *>(node);
- }
- node = node->parent;
- }
-
- ERR_CONTINUE(!sk);
-
- if (!skeleton) {
- skeleton = sk;
- continue;
- }
-
- if (skeleton != sk) {
- //whoa.. wtf, merge.
- _remove_node(p_vscene, sk);
- for (int i = 0; i < sk->children.size(); i++) {
-
- _joint_set_owner(sk->children[i], skeleton);
- skeleton->children.push_back(sk->children[i]);
- sk->children[i]->parent = skeleton;
- }
-
- sk->children.clear(); //take children from it
- memdelete(sk);
- }
- }
- }
-}
-
-bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) {
-
- Node *node = p_node;
-
- if (node->type == Node::TYPE_SKELETON && node->parent && node->parent->type == Node::TYPE_NODE && node->parent->children.size() == 1) {
- //replace parent by this...
- Node *parent = node->parent;
-
- //i wonder if this is alright.. i think it is since created skeleton (first joint) is already animated by bone..
- node->id = parent->id;
- node->name = parent->name;
- node->xform_list = parent->xform_list;
- node->default_transform = parent->default_transform;
-
- state.scene_map[node->id] = node;
- node->parent = parent->parent;
-
- if (parent->parent) {
- Node *gp = parent->parent;
- bool found = false;
- for (int i = 0; i < gp->children.size(); i++) {
-
- if (gp->children[i] == parent) {
- gp->children.write[i] = node;
- found = true;
- break;
- }
- }
- if (!found) {
- ERR_PRINT("BUG");
- }
- } else {
-
- bool found = false;
-
- for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
-
- if (p_vscene->root_nodes[i] == parent) {
-
- p_vscene->root_nodes.write[i] = node;
- found = true;
- break;
- }
- }
- if (!found) {
- ERR_PRINT("BUG");
- }
- }
-
- parent->children.clear();
- memdelete(parent);
- return true;
- }
-
- for (int i = 0; i < node->children.size(); i++) {
-
- if (_optimize_skeletons(p_vscene, node->children[i]))
- return false; //stop processing, go up
- }
-
- return false;
-}
-
-bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom) {
-
- // Bind Shape Matrix scales the bones and makes them gigantic, so the matrix then shrinks the model?
- // Solution: apply the Bind Shape Matrix to the VERTICES, and if the object comes scaled, it seems to be left alone!
-
- if (p_node->type == Node::TYPE_GEOMETRY) {
-
- NodeGeometry *ng = static_cast<NodeGeometry *>(p_node);
- if (ng->ignore_anim)
- return false; //already made child of skeleton and processeg
-
- if (ng->controller && ng->skeletons.size()) {
-
- String nodeid = ng->skeletons[0];
-
- ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
- NodeJoint *nj = SAFE_CAST<NodeJoint *>(state.scene_map[nodeid]);
- ERR_FAIL_COND_V(!nj, false);
- ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
-
- NodeSkeleton *sk = nj->owner;
-
- Node *p = sk->parent;
- bool node_is_parent_of_skeleton = false;
-
- while (p) {
- if (p == p_node) {
- node_is_parent_of_skeleton = true;
- break;
- }
- p = p->parent; // try again
- }
-
- ERR_FAIL_COND_V(node_is_parent_of_skeleton, false);
-
- //this should be correct
- ERR_FAIL_COND_V(!state.skin_controller_data_map.has(ng->source), false);
- SkinControllerData &skin = state.skin_controller_data_map[ng->source];
- Transform skel_inv = sk->get_global_transform().affine_inverse();
- p_node->default_transform = skel_inv * (skin.bind_shape /* p_node->get_global_transform()*/); // i honestly have no idea what to do with a previous model xform.. most exporters ignore it
-
- //make rests relative to the skeleton (they seem to be always relative to world)
- for (Map<String, Transform>::Element *E = skin.bone_rest_map.front(); E; E = E->next()) {
-
- E->get() = skel_inv * E->get(); //make the bone rest local to the skeleton
- state.bone_rest_map[E->key()] = E->get(); // make it remember where the bone is globally, now that it's relative
- }
-
- //but most exporters seem to work only if i do this..
- //p_node->default_transform = p_node->get_global_transform();
-
- //p_node->default_transform=Transform(); //this seems to be correct, because bind shape makes the object local to the skeleton
- p_node->ignore_anim = true; // collada may animate this later, if it does, then this is not supported (redo your original asset and don't animate the base mesh)
- p_node->parent = sk;
- //sk->children.push_back(0,p_node); //avoid INFINITE loop
- p_mgeom->push_back(p_node);
- return true;
- }
- }
-
- for (int i = 0; i < p_node->children.size(); i++) {
-
- if (_move_geometry_to_skeletons(p_vscene, p_node->children[i], p_mgeom)) {
- p_node->children.remove(i);
- i--;
- }
- }
-
- return false;
-}
-
-void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) {
-
- if (p_node->type == Node::TYPE_GEOMETRY) {
-
- NodeGeometry *nj = static_cast<NodeGeometry *>(p_node);
-
- if (nj->controller) {
-
- String base = nj->source;
-
- while (base != "" && !state.mesh_data_map.has(base)) {
-
- if (state.skin_controller_data_map.has(base)) {
-
- SkinControllerData &sk = state.skin_controller_data_map[base];
- base = sk.base;
- } else if (state.morph_controller_data_map.has(base)) {
-
- state.morph_ownership_map[base] = nj->id;
- break;
- } else {
- ERR_FAIL_MSG("Invalid scene.");
- }
- }
- }
- }
-
- for (int i = 0; i < p_node->children.size(); i++) {
-
- _find_morph_nodes(p_vscene, p_node->children[i]);
- }
-}
-
-void Collada::_optimize() {
-
- for (Map<String, VisualScene>::Element *E = state.visual_scene_map.front(); E; E = E->next()) {
-
- VisualScene &vs = E->get();
- for (int i = 0; i < vs.root_nodes.size(); i++) {
- _create_skeletons(&vs.root_nodes.write[i]);
- }
-
- for (int i = 0; i < vs.root_nodes.size(); i++) {
- _merge_skeletons(&vs, vs.root_nodes[i]);
- }
-
- _merge_skeletons2(&vs);
-
- for (int i = 0; i < vs.root_nodes.size(); i++) {
- _optimize_skeletons(&vs, vs.root_nodes[i]);
- }
-
- for (int i = 0; i < vs.root_nodes.size(); i++) {
-
- List<Node *> mgeom;
- if (_move_geometry_to_skeletons(&vs, vs.root_nodes[i], &mgeom)) {
- vs.root_nodes.remove(i);
- i--;
- }
-
- while (!mgeom.empty()) {
-
- Node *n = mgeom.front()->get();
- n->parent->children.push_back(n);
- mgeom.pop_front();
- }
- }
-
- for (int i = 0; i < vs.root_nodes.size(); i++) {
- _find_morph_nodes(&vs, vs.root_nodes[i]);
- }
- }
-}
-
-int Collada::get_uv_channel(String p_name) {
-
- if (!channel_map.has(p_name)) {
-
- ERR_FAIL_COND_V(channel_map.size() == 2, 0);
-
- channel_map[p_name] = channel_map.size();
- }
-
- return channel_map[p_name];
-}
-
-Error Collada::load(const String &p_path, int p_flags) {
-
- Ref<XMLParser> parserr = memnew(XMLParser);
- XMLParser &parser = *parserr.ptr();
- Error err = parser.open(p_path);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot open Collada file '" + p_path + "'.");
-
- state.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
- state.import_flags = p_flags;
- /* Skip headers */
- while ((err = parser.read()) == OK) {
-
- if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser.get_node_name() == "COLLADA") {
- break;
- } else if (!parser.is_empty())
- parser.skip_section(); // unknown section, likely headers
- }
- }
-
- ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CORRUPT, "Corrupted Collada file '" + p_path + "'.");
-
- /* Start loading Collada */
-
- {
- //version
- String version = parser.get_attribute_value("version");
- state.version.major = version.get_slice(".", 0).to_int();
- state.version.minor = version.get_slice(".", 1).to_int();
- state.version.rev = version.get_slice(".", 2).to_int();
- COLLADA_PRINT("Collada VERSION: " + version);
- }
-
- while ((err = parser.read()) == OK) {
-
- /* Read all the main sections.. */
-
- if (parser.get_node_type() != XMLParser::NODE_ELEMENT)
- continue; //no idea what this may be, but skipping anyway
-
- String section = parser.get_node_name();
-
- COLLADA_PRINT("section: " + section);
-
- if (section == "asset") {
- _parse_asset(parser);
-
- } else if (section.begins_with("library_")) {
-
- _parse_library(parser);
- } else if (section == "scene") {
-
- _parse_scene(parser);
- } else if (!parser.is_empty()) {
- parser.skip_section(); // unknown section, likely headers
- }
- }
-
- _optimize();
- return OK;
-}
-
-Collada::Collada() {
-}
diff --git a/editor/collada/collada.h b/editor/collada/collada.h
deleted file mode 100644
index 10ed42260b..0000000000
--- a/editor/collada/collada.h
+++ /dev/null
@@ -1,647 +0,0 @@
-/*************************************************************************/
-/* collada.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLADA_H
-#define COLLADA_H
-
-#include "core/io/xml_parser.h"
-#include "core/map.h"
-#include "core/project_settings.h"
-#include "scene/resources/material.h"
-
-class Collada {
-public:
- enum ImportFlags {
- IMPORT_FLAG_SCENE = 1,
- IMPORT_FLAG_ANIMATION = 2
- };
-
- struct Image {
-
- String path;
- };
-
- struct Material {
-
- String name;
- String instance_effect;
- };
-
- struct Effect {
-
- String name;
- Map<String, Variant> params;
-
- struct Channel {
-
- int uv_idx;
- String texture;
- Color color;
- Channel() { uv_idx = 0; }
- };
-
- Channel diffuse, specular, emission, bump;
- float shininess;
- bool found_double_sided;
- bool double_sided;
- bool unshaded;
-
- String get_texture_path(const String &p_source, Collada &state) const;
-
- Effect() {
- diffuse.color = Color(1, 1, 1, 1);
- double_sided = true;
- found_double_sided = false;
- shininess = 40;
- unshaded = false;
- }
- };
-
- struct CameraData {
-
- enum Mode {
- MODE_PERSPECTIVE,
- MODE_ORTHOGONAL
- };
-
- Mode mode;
-
- union {
- struct {
- float x_fov;
- float y_fov;
- } perspective;
- struct {
- float x_mag;
- float y_mag;
- } orthogonal;
- };
-
- float aspect;
- float z_near;
- float z_far;
-
- CameraData() :
- mode(MODE_PERSPECTIVE),
- aspect(1),
- z_near(0.1),
- z_far(100) {
- perspective.x_fov = 0;
- perspective.y_fov = 0;
- }
- };
-
- struct LightData {
-
- enum Mode {
- MODE_AMBIENT,
- MODE_DIRECTIONAL,
- MODE_OMNI,
- MODE_SPOT
- };
-
- Mode mode;
-
- Color color;
-
- float constant_att;
- float linear_att;
- float quad_att;
-
- float spot_angle;
- float spot_exp;
-
- LightData() :
- mode(MODE_AMBIENT),
- color(Color(1, 1, 1, 1)),
- constant_att(0),
- linear_att(0),
- quad_att(0),
- spot_angle(45),
- spot_exp(1) {
- }
- };
-
- struct MeshData {
-
- String name;
- struct Source {
-
- Vector<float> array;
- int stride;
- };
-
- Map<String, Source> sources;
-
- struct Vertices {
-
- Map<String, String> sources;
- };
-
- Map<String, Vertices> vertices;
-
- struct Primitives {
-
- struct SourceRef {
-
- String source;
- int offset;
- };
-
- String material;
- Map<String, SourceRef> sources;
- Vector<float> polygons;
- Vector<float> indices;
- int count;
- int vertex_size;
- };
-
- Vector<Primitives> primitives;
-
- bool found_double_sided;
- bool double_sided;
-
- MeshData() {
- found_double_sided = false;
- double_sided = true;
- }
- };
-
- struct CurveData {
-
- String name;
- bool closed;
-
- struct Source {
-
- Vector<String> sarray;
- Vector<float> array;
- int stride;
- };
-
- Map<String, Source> sources;
-
- Map<String, String> control_vertices;
-
- CurveData() {
-
- closed = false;
- }
- };
- struct SkinControllerData {
-
- String base;
- bool use_idrefs;
-
- Transform bind_shape;
-
- struct Source {
-
- Vector<String> sarray; //maybe for names
- Vector<float> array;
- int stride;
- Source() {
- stride = 1;
- }
- };
-
- Map<String, Source> sources;
-
- struct Joints {
-
- Map<String, String> sources;
- } joints;
-
- struct Weights {
-
- struct SourceRef {
-
- String source;
- int offset;
- };
-
- String material;
- Map<String, SourceRef> sources;
- Vector<float> sets;
- Vector<float> indices;
- int count;
- } weights;
-
- Map<String, Transform> bone_rest_map;
-
- SkinControllerData() { use_idrefs = false; }
- };
-
- struct MorphControllerData {
-
- String mesh;
- String mode;
-
- struct Source {
-
- int stride;
- Vector<String> sarray; //maybe for names
- Vector<float> array;
- Source() { stride = 1; }
- };
-
- Map<String, Source> sources;
-
- Map<String, String> targets;
- MorphControllerData() {}
- };
-
- struct Vertex {
-
- int idx;
- Vector3 vertex;
- Vector3 normal;
- Vector3 uv;
- Vector3 uv2;
- Plane tangent;
- Color color;
- int uid;
- struct Weight {
- int bone_idx;
- float weight;
- bool operator<(const Weight w) const { return weight > w.weight; } //heaviest first
- };
-
- Vector<Weight> weights;
-
- void fix_weights() {
-
- weights.sort();
- if (weights.size() > 4) {
- //cap to 4 and make weights add up 1
- weights.resize(4);
- float total = 0;
- for (int i = 0; i < 4; i++)
- total += weights[i].weight;
- if (total)
- for (int i = 0; i < 4; i++)
- weights.write[i].weight /= total;
- }
- }
-
- void fix_unit_scale(Collada &state);
-
- bool operator<(const Vertex &p_vert) const {
-
- if (uid == p_vert.uid) {
- if (vertex == p_vert.vertex) {
- if (normal == p_vert.normal) {
- if (uv == p_vert.uv) {
- if (uv2 == p_vert.uv2) {
-
- if (!weights.empty() || !p_vert.weights.empty()) {
-
- if (weights.size() == p_vert.weights.size()) {
-
- for (int i = 0; i < weights.size(); i++) {
- if (weights[i].bone_idx != p_vert.weights[i].bone_idx)
- return weights[i].bone_idx < p_vert.weights[i].bone_idx;
-
- if (weights[i].weight != p_vert.weights[i].weight)
- return weights[i].weight < p_vert.weights[i].weight;
- }
- } else {
- return weights.size() < p_vert.weights.size();
- }
- }
-
- return (color < p_vert.color);
- } else
- return (uv2 < p_vert.uv2);
- } else
- return (uv < p_vert.uv);
- } else
- return (normal < p_vert.normal);
- } else
- return vertex < p_vert.vertex;
- } else
- return uid < p_vert.uid;
- }
-
- Vertex() {
- uid = 0;
- idx = 0;
- }
- };
- struct Node {
-
- enum Type {
-
- TYPE_NODE,
- TYPE_JOINT,
- TYPE_SKELETON, //this bone is not collada, it's added afterwards as optimization
- TYPE_LIGHT,
- TYPE_CAMERA,
- TYPE_GEOMETRY
- };
-
- struct XForm {
-
- enum Op {
- OP_ROTATE,
- OP_SCALE,
- OP_TRANSLATE,
- OP_MATRIX,
- OP_VISIBILITY
- };
-
- String id;
- Op op;
- Vector<float> data;
- };
-
- Type type;
-
- String name;
- String id;
- String empty_draw_type;
- bool noname;
- Vector<XForm> xform_list;
- Transform default_transform;
- Transform post_transform;
- Vector<Node *> children;
-
- Node *parent;
-
- Transform compute_transform(Collada &state) const;
- Transform get_global_transform() const;
- Transform get_transform() const;
-
- bool ignore_anim;
-
- Node() {
- noname = false;
- type = TYPE_NODE;
- parent = NULL;
- ignore_anim = false;
- }
- virtual ~Node() {
- for (int i = 0; i < children.size(); i++)
- memdelete(children[i]);
- };
- };
-
- struct NodeSkeleton : public Node {
-
- NodeSkeleton() { type = TYPE_SKELETON; }
- };
-
- struct NodeJoint : public Node {
-
- NodeSkeleton *owner;
- String sid;
- NodeJoint() {
- type = TYPE_JOINT;
- owner = NULL;
- }
- };
-
- struct NodeGeometry : public Node {
-
- bool controller;
- String source;
-
- struct Material {
- String target;
- };
-
- Map<String, Material> material_map;
- Vector<String> skeletons;
-
- NodeGeometry() { type = TYPE_GEOMETRY; }
- };
-
- struct NodeCamera : public Node {
-
- String camera;
-
- NodeCamera() { type = TYPE_CAMERA; }
- };
-
- struct NodeLight : public Node {
-
- String light;
-
- NodeLight() { type = TYPE_LIGHT; }
- };
-
- struct VisualScene {
-
- String name;
- Vector<Node *> root_nodes;
-
- ~VisualScene() {
- for (int i = 0; i < root_nodes.size(); i++)
- memdelete(root_nodes[i]);
- }
- };
-
- struct AnimationClip {
-
- String name;
- float begin;
- float end;
- Vector<String> tracks;
-
- AnimationClip() {
- begin = 0;
- end = 1;
- }
- };
-
- struct AnimationTrack {
-
- String id;
- String target;
- String param;
- String component;
- bool property;
-
- enum InterpolationType {
- INTERP_LINEAR,
- INTERP_BEZIER
- };
-
- struct Key {
-
- enum Type {
- TYPE_FLOAT,
- TYPE_MATRIX
- };
-
- float time;
- Vector<float> data;
- Point2 in_tangent;
- Point2 out_tangent;
- InterpolationType interp_type;
-
- Key() { interp_type = INTERP_LINEAR; }
- };
-
- Vector<float> get_value_at_time(float p_time) const;
-
- Vector<Key> keys;
-
- AnimationTrack() { property = false; }
- };
-
- /****************/
- /* IMPORT STATE */
- /****************/
-
- struct State {
-
- int import_flags;
-
- float unit_scale;
- Vector3::Axis up_axis;
- bool z_up;
-
- struct Version {
-
- int major, minor, rev;
-
- bool operator<(const Version &p_ver) const { return (major == p_ver.major) ? ((minor == p_ver.minor) ? (rev < p_ver.rev) : minor < p_ver.minor) : major < p_ver.major; }
- Version(int p_major = 0, int p_minor = 0, int p_rev = 0) {
- major = p_major;
- minor = p_minor;
- rev = p_rev;
- }
- } version;
-
- Map<String, CameraData> camera_data_map;
- Map<String, MeshData> mesh_data_map;
- Map<String, LightData> light_data_map;
- Map<String, CurveData> curve_data_map;
-
- Map<String, String> mesh_name_map;
- Map<String, String> morph_name_map;
- Map<String, String> morph_ownership_map;
- Map<String, SkinControllerData> skin_controller_data_map;
- Map<String, MorphControllerData> morph_controller_data_map;
-
- Map<String, Image> image_map;
- Map<String, Material> material_map;
- Map<String, Effect> effect_map;
-
- Map<String, VisualScene> visual_scene_map;
- Map<String, Node *> scene_map;
- Set<String> idref_joints;
- Map<String, String> sid_to_node_map;
- //Map<String,NodeJoint*> bone_map;
-
- Map<String, Transform> bone_rest_map;
-
- String local_path;
- String root_visual_scene;
- String root_physics_scene;
-
- Vector<AnimationClip> animation_clips;
- Vector<AnimationTrack> animation_tracks;
- Map<String, Vector<int> > referenced_tracks;
- Map<String, Vector<int> > by_id_tracks;
-
- float animation_length;
-
- State() :
- import_flags(0),
- unit_scale(1.0),
- up_axis(Vector3::AXIS_Y),
- animation_length(0) {
- }
- } state;
-
- Error load(const String &p_path, int p_flags = 0);
-
- Collada();
-
- Transform fix_transform(const Transform &p_transform);
-
- Transform get_root_transform() const;
-
- int get_uv_channel(String p_name);
-
-private: // private stuff
- Map<String, int> channel_map;
-
- void _parse_asset(XMLParser &parser);
- void _parse_image(XMLParser &parser);
- void _parse_material(XMLParser &parser);
- void _parse_effect_material(XMLParser &parser, Effect &effect, String &id);
- void _parse_effect(XMLParser &parser);
- void _parse_camera(XMLParser &parser);
- void _parse_light(XMLParser &parser);
- void _parse_animation_clip(XMLParser &parser);
-
- void _parse_mesh_geometry(XMLParser &parser, String p_id, String p_name);
- void _parse_curve_geometry(XMLParser &parser, String p_id, String p_name);
-
- void _parse_skin_controller(XMLParser &parser, String p_id);
- void _parse_morph_controller(XMLParser &parser, String p_id);
- void _parse_controller(XMLParser &parser);
-
- Node *_parse_visual_instance_geometry(XMLParser &parser);
- Node *_parse_visual_instance_camera(XMLParser &parser);
- Node *_parse_visual_instance_light(XMLParser &parser);
-
- Node *_parse_visual_node_instance_data(XMLParser &parser);
- Node *_parse_visual_scene_node(XMLParser &parser);
- void _parse_visual_scene(XMLParser &parser);
-
- void _parse_animation(XMLParser &parser);
- void _parse_scene(XMLParser &parser);
- void _parse_library(XMLParser &parser);
-
- Variant _parse_param(XMLParser &parser);
- Vector<float> _read_float_array(XMLParser &parser);
- Vector<String> _read_string_array(XMLParser &parser);
- Transform _read_transform(XMLParser &parser);
- String _read_empty_draw_type(XMLParser &parser);
-
- void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
- void _create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton = NULL);
- void _find_morph_nodes(VisualScene *p_vscene, Node *p_node);
- bool _remove_node(Node *p_parent, Node *p_node);
- void _remove_node(VisualScene *p_vscene, Node *p_node);
- void _merge_skeletons2(VisualScene *p_vscene);
- void _merge_skeletons(VisualScene *p_vscene, Node *p_node);
- bool _optimize_skeletons(VisualScene *p_vscene, Node *p_node);
-
- bool _move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom);
-
- void _optimize();
-};
-
-#endif // COLLADA_H
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index eea92fb7ed..bef5c3c2b0 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -40,7 +40,7 @@
static Node *_find_first_script(Node *p_root, Node *p_node) {
if (p_node != p_root && p_node->get_owner() != p_root) {
- return NULL;
+ return nullptr;
}
if (!p_node->get_script().is_null()) {
return p_node;
@@ -54,7 +54,7 @@ static Node *_find_first_script(Node *p_root, Node *p_node) {
}
}
- return NULL;
+ return nullptr;
}
class ConnectDialogBinds : public Object {
@@ -115,7 +115,7 @@ void ConnectDialog::ok_pressed() {
if (dst_method->get_text() == "") {
error->set_text(TTR("Method in target node must be specified."));
- error->popup_centered_minsize();
+ error->popup_centered();
return;
}
Node *target = tree->get_selected();
@@ -125,7 +125,7 @@ void ConnectDialog::ok_pressed() {
if (target->get_script().is_null()) {
if (!target->has_method(dst_method->get_text())) {
error->set_text(TTR("Target method not found. Specify a valid method or attach a script to the target node."));
- error->popup_centered_minsize();
+ error->popup_centered();
return;
}
}
@@ -315,7 +315,7 @@ void ConnectDialog::init(ConnectionData c, bool bEdit) {
source = static_cast<Node *>(c.source);
signal = c.signal;
- tree->set_selected(NULL);
+ tree->set_selected(nullptr);
tree->set_marked(source, true);
if (c.target) {
@@ -341,7 +341,7 @@ void ConnectDialog::init(ConnectionData c, bool bEdit) {
void ConnectDialog::popup_dialog(const String &p_for_signal) {
from_signal->set_text(p_for_signal);
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ error_label->add_theme_color_override("font_color", error_label->get_theme_color("error_color", "Editor"));
if (!advanced->is_pressed())
error_label->set_visible(!_find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root()));
@@ -351,14 +351,14 @@ void ConnectDialog::popup_dialog(const String &p_for_signal) {
void ConnectDialog::_advanced_pressed() {
if (advanced->is_pressed()) {
- set_custom_minimum_size(Size2(900, 500) * EDSCALE);
+ set_min_size(Size2(900, 500) * EDSCALE);
connect_to_label->set_text(TTR("Connect to Node:"));
tree->set_connect_to_script_mode(false);
vbc_right->show();
error_label->hide();
} else {
- set_custom_minimum_size(Size2(600, 500) * EDSCALE);
+ set_min_size(Size2(600, 500) * EDSCALE);
set_size(Size2());
connect_to_label->set_text(TTR("Connect to Script:"));
tree->set_connect_to_script_mode(true);
@@ -369,23 +369,23 @@ void ConnectDialog::_advanced_pressed() {
_update_ok_enabled();
- set_position((get_viewport_rect().size - get_custom_minimum_size()) / 2);
+ popup_centered();
}
ConnectDialog::ConnectDialog() {
- set_custom_minimum_size(Size2(600, 500) * EDSCALE);
+ set_min_size(Size2(600, 500) * EDSCALE);
VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
HBoxContainer *main_hb = memnew(HBoxContainer);
vbc->add_child(main_hb);
- main_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+ main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
VBoxContainer *vbc_left = memnew(VBoxContainer);
main_hb->add_child(vbc_left);
- vbc_left->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_left->set_h_size_flags(Control::SIZE_EXPAND_FILL);
from_signal = memnew(LineEdit);
from_signal->set_editable(false);
@@ -407,13 +407,13 @@ ConnectDialog::ConnectDialog() {
vbc_right = memnew(VBoxContainer);
main_hb->add_child(vbc_right);
- vbc_right->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_right->set_h_size_flags(Control::SIZE_EXPAND_FILL);
vbc_right->hide();
HBoxContainer *add_bind_hb = memnew(HBoxContainer);
type_list = memnew(OptionButton);
- type_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ type_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_bind_hb->add_child(type_list);
type_list->add_item("bool", Variant::BOOL);
type_list->add_item("int", Variant::INT);
@@ -451,7 +451,7 @@ ConnectDialog::ConnectDialog() {
vbc_left->add_margin_child(TTR("Receiver Method:"), dstm_hb);
dst_method = memnew(LineEdit);
- dst_method->set_h_size_flags(SIZE_EXPAND_FILL);
+ dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL);
dst_method->connect("text_entered", callable_mp(this, &ConnectDialog::_text_entered));
dstm_hb->add_child(dst_method);
@@ -477,8 +477,6 @@ ConnectDialog::ConnectDialog() {
oneshot->set_tooltip(TTR("Disconnects the signal after its first emission."));
vbc_right->add_child(oneshot);
- set_as_toplevel(true);
-
cdbinds = memnew(ConnectDialogBinds);
error = memnew(AcceptDialog);
@@ -499,7 +497,7 @@ ConnectDialog::~ConnectDialog() {
Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const {
EditorHelpBit *help_bit = memnew(EditorHelpBit);
- help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
+ help_bit->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel"));
help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
String text = TTR("Signal:") + " [u][b]" + p_text.get_slice("::", 0) + "[/b][/u]";
@@ -576,7 +574,7 @@ void ConnectionsDock::_make_or_edit_connection() {
}
// IMPORTANT NOTE: _disconnect and _connect cause an update_tree, which will delete the object "it" is pointing to.
- it = NULL;
+ it = nullptr;
if (add_script_function) {
editor->emit_signal("script_add_function_request", target, cToMake.method, script_function_args);
@@ -909,24 +907,24 @@ void ConnectionsDock::update_tree() {
else
name = scr->get_class();
- if (has_icon(scr->get_class(), "EditorIcons")) {
- icon = get_icon(scr->get_class(), "EditorIcons");
+ if (has_theme_icon(scr->get_class(), "EditorIcons")) {
+ icon = get_theme_icon(scr->get_class(), "EditorIcons");
}
}
} else {
ClassDB::get_signal_list(base, &node_signals2, true);
- if (has_icon(base, "EditorIcons")) {
- icon = get_icon(base, "EditorIcons");
+ if (has_theme_icon(base, "EditorIcons")) {
+ icon = get_theme_icon(base, "EditorIcons");
}
name = base;
}
if (!icon.is_valid()) {
- icon = get_icon("Object", "EditorIcons");
+ icon = get_theme_icon("Object", "EditorIcons");
}
- TreeItem *pitem = NULL;
+ TreeItem *pitem = nullptr;
if (node_signals2.size()) {
pitem = tree->create_item(root);
@@ -934,7 +932,7 @@ void ConnectionsDock::update_tree() {
pitem->set_icon(0, icon);
pitem->set_selectable(0, false);
pitem->set_editable(0, false);
- pitem->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
+ pitem->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
node_signals2.sort();
}
@@ -970,14 +968,14 @@ void ConnectionsDock::update_tree() {
sinfo["name"] = signal_name;
sinfo["args"] = argnames;
item->set_metadata(0, sinfo);
- item->set_icon(0, get_icon("Signal", "EditorIcons"));
+ item->set_icon(0, get_theme_icon("Signal", "EditorIcons"));
// Set tooltip with the signal's documentation.
{
String descr;
bool found = false;
- Map<StringName, Map<StringName, String> >::Element *G = descr_cache.find(base);
+ Map<StringName, Map<StringName, String>>::Element *G = descr_cache.find(base);
if (G) {
Map<StringName, String>::Element *F = G->get().find(signal_name);
if (F) {
@@ -992,7 +990,7 @@ void ConnectionsDock::update_tree() {
while (F && descr == String()) {
for (int i = 0; i < F->get().signals.size(); i++) {
if (F->get().signals[i].name == signal_name.operator String()) {
- descr = F->get().signals[i].description.strip_edges();
+ descr = DTR(F->get().signals[i].description.strip_edges());
break;
}
}
@@ -1045,7 +1043,7 @@ void ConnectionsDock::update_tree() {
item2->set_text(0, path);
Connection cd = c;
item2->set_metadata(0, cd);
- item2->set_icon(0, get_icon("Slot", "EditorIcons"));
+ item2->set_icon(0, get_theme_icon("Slot", "EditorIcons"));
}
}
@@ -1072,7 +1070,7 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
tree->set_select_mode(Tree::SELECT_ROW);
tree->set_hide_root(true);
vbc->add_child(tree);
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->set_allow_rmb_select(true);
connect_button = memnew(Button);
@@ -1083,11 +1081,9 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
connect_button->connect("pressed", callable_mp(this, &ConnectionsDock::_connect_pressed));
connect_dialog = memnew(ConnectDialog);
- connect_dialog->set_as_toplevel(true);
add_child(connect_dialog);
disconnect_all_dialog = memnew(ConfirmationDialog);
- disconnect_all_dialog->set_as_toplevel(true);
add_child(disconnect_all_dialog);
disconnect_all_dialog->connect("confirmed", callable_mp(this, &ConnectionsDock::_disconnect_all));
disconnect_all_dialog->set_text(TTR("Are you sure you want to remove all connections from this signal?"));
@@ -1110,7 +1106,7 @@ ConnectionsDock::ConnectionsDock(EditorNode *p_editor) {
tree->connect("item_activated", callable_mp(this, &ConnectionsDock::_tree_item_activated));
tree->connect("item_rmb_selected", callable_mp(this, &ConnectionsDock::_rmb_pressed));
- add_constant_override("separation", 3 * EDSCALE);
+ add_theme_constant_override("separation", 3 * EDSCALE);
}
ConnectionsDock::~ConnectionsDock() {
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index 988a8a1271..91d0d5c32c 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -173,7 +173,7 @@ class ConnectionsDock : public VBoxContainer {
PopupMenu *slot_menu;
UndoRedo *undo_redo;
- Map<StringName, Map<StringName, String> > descr_cache;
+ Map<StringName, Map<StringName, String>> descr_cache;
void _make_or_edit_connection();
void _connect(ConnectDialog::ConnectionData cToMake);
@@ -203,7 +203,7 @@ public:
void set_node(Node *p_node);
void update_tree();
- ConnectionsDock(EditorNode *p_editor = NULL);
+ ConnectionsDock(EditorNode *p_editor = nullptr);
~ConnectionsDock();
};
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 3e09a9a760..6cbb1b1791 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -193,7 +193,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p
item->set_text(0, p_type + " (" + ScriptServer::get_global_class_path(p_type).get_file() + ")");
}
if (!can_instance) {
- item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
+ item->set_custom_color(0, search_options->get_theme_color("disabled_font_color", "Editor"));
item->set_selectable(0, false);
} else if (!(*to_select && (*to_select)->get_text(0) == search_box->get_text())) {
String search_term = search_box->get_text().to_lower();
@@ -248,7 +248,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p
item->set_collapsed(collapse);
}
- const String &description = EditorHelp::get_doc_data()->class_list[p_type].brief_description;
+ const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description);
item->set_tooltip(0, description);
item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, base_type));
@@ -310,11 +310,11 @@ void CreateDialog::_update_search() {
EditorData &ed = EditorNode::get_editor_data();
root->set_text(0, base_type);
- if (has_icon(base_type, "EditorIcons")) {
- root->set_icon(0, get_icon(base_type, "EditorIcons"));
+ if (search_options->has_theme_icon(base_type, "EditorIcons")) {
+ root->set_icon(0, search_options->get_theme_icon(base_type, "EditorIcons"));
}
- TreeItem *to_select = search_box->get_text() == base_type ? root : NULL;
+ TreeItem *to_select = search_box->get_text() == base_type ? root : nullptr;
for (List<StringName>::Element *I = type_list.front(); I; I = I->next()) {
@@ -417,7 +417,7 @@ void CreateDialog::_update_search() {
favorite->set_pressed(favorite_list.find(to_select->get_text(0)) != -1);
}
- get_ok()->set_disabled(root->get_children() == NULL);
+ get_ok()->set_disabled(root->get_children() == nullptr);
}
void CreateDialog::_confirmed() {
@@ -460,23 +460,22 @@ void CreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", callable_mp(this, &CreateDialog::_confirmed));
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
- favorite->set_icon(get_icon("Favorites", "EditorIcons"));
+ favorite->set_icon(search_options->get_theme_icon("Favorites", "EditorIcons"));
} break;
case NOTIFICATION_EXIT_TREE: {
disconnect("confirmed", callable_mp(this, &CreateDialog::_confirmed));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible_in_tree()) {
+ if (is_visible()) {
search_box->call_deferred("grab_focus"); // still not visible
search_box->select_all();
+ } else {
+ EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "create_new_node", Rect2(get_position(), get_size()));
+ search_loaded_scripts.clear();
}
} break;
- case NOTIFICATION_POPUP_HIDE: {
- EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "create_new_node", get_rect());
- search_loaded_scripts.clear();
- } break;
}
}
@@ -539,7 +538,7 @@ Object *CreateDialog::instance_selected() {
}
}
- return NULL;
+ return nullptr;
}
void CreateDialog::_item_selected() {
@@ -556,13 +555,13 @@ void CreateDialog::_item_selected() {
if (!EditorHelp::get_doc_data()->class_list.has(name))
return;
- help_bit->set_text(EditorHelp::get_doc_data()->class_list[name].brief_description);
+ help_bit->set_text(DTR(EditorHelp::get_doc_data()->class_list[name].brief_description));
get_ok()->set_disabled(false);
}
void CreateDialog::_hide_requested() {
- _closed(); // From WindowDialog.
+ _cancel_pressed(); // From AcceptDialog.
}
void CreateDialog::_favorite_toggled() {
@@ -662,7 +661,7 @@ Variant CreateDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
ToolButton *tb = memnew(ToolButton);
tb->set_icon(ti->get_icon(0));
tb->set_text(ti->get_text(0));
- set_drag_preview(tb);
+ favorites->set_drag_preview(tb);
return d;
}
@@ -743,8 +742,6 @@ CreateDialog::CreateDialog() {
is_replace_mode = false;
- set_resizable(true);
-
HSplitContainer *hsc = memnew(HSplitContainer);
add_child(hsc);
@@ -754,7 +751,7 @@ CreateDialog::CreateDialog() {
VBoxContainer *fav_vb = memnew(VBoxContainer);
vsc->add_child(fav_vb);
fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
- fav_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ fav_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
favorites = memnew(Tree);
fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
@@ -763,13 +760,16 @@ CreateDialog::CreateDialog() {
favorites->set_allow_reselect(true);
favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
- favorites->set_drag_forwarding(this);
- favorites->add_constant_override("draw_guides", 1);
+#ifndef _MSC_VER
+#warning cant forward drag data to a non control, must be fixed
+#endif
+ //favorites->set_drag_forwarding(this);
+ favorites->add_theme_constant_override("draw_guides", 1);
VBoxContainer *rec_vb = memnew(VBoxContainer);
vsc->add_child(rec_vb);
rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
- rec_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ rec_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
recent = memnew(Tree);
rec_vb->add_margin_child(TTR("Recent:"), recent, true);
@@ -778,15 +778,15 @@ CreateDialog::CreateDialog() {
recent->set_allow_reselect(true);
recent->connect("cell_selected", callable_mp(this, &CreateDialog::_history_selected));
recent->connect("item_activated", callable_mp(this, &CreateDialog::_history_activated));
- recent->add_constant_override("draw_guides", 1);
+ recent->add_theme_constant_override("draw_guides", 1);
VBoxContainer *vbc = memnew(VBoxContainer);
hsc->add_child(vbc);
vbc->set_custom_minimum_size(Size2(300, 0) * EDSCALE);
- vbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
HBoxContainer *search_hb = memnew(HBoxContainer);
search_box = memnew(LineEdit);
- search_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_hb->add_child(search_box);
favorite = memnew(Button);
favorite->set_flat(true);
diff --git a/editor/debugger/SCsub b/editor/debugger/SCsub
index 2b1e889fb0..359d04e5df 100644
--- a/editor/debugger/SCsub
+++ b/editor/debugger/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index 9587daf93e..00ed2bbc4c 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -125,7 +125,7 @@ void EditorDebuggerInspector::_object_selected(ObjectID p_object) {
}
ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
- EditorDebuggerRemoteObject *debugObj = NULL;
+ EditorDebuggerRemoteObject *debugObj = nullptr;
SceneDebuggerObject obj;
obj.deserialize(p_arr);
@@ -211,7 +211,7 @@ void EditorDebuggerInspector::clear_cache() {
for (Map<ObjectID, EditorDebuggerRemoteObject *>::Element *E = remote_objects.front(); E; E = E->next()) {
EditorNode *editor = EditorNode::get_singleton();
if (editor->get_editor_history()->get_current() == E->value()->get_instance_id()) {
- editor->push_item(NULL);
+ editor->push_item(nullptr);
}
memdelete(E->value());
}
@@ -221,7 +221,7 @@ void EditorDebuggerInspector::clear_cache() {
Object *EditorDebuggerInspector::get_object(ObjectID p_id) {
if (remote_objects.has(p_id))
return remote_objects[p_id];
- return NULL;
+ return nullptr;
}
void EditorDebuggerInspector::add_stack_variable(const Array &p_array) {
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index f4a8102b79..3302b50103 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -47,14 +47,14 @@ void _for_all(TabContainer *p_node, const Func &p_func) {
}
}
-EditorDebuggerNode *EditorDebuggerNode::singleton = NULL;
+EditorDebuggerNode *EditorDebuggerNode::singleton = nullptr;
EditorDebuggerNode::EditorDebuggerNode() {
if (!singleton)
singleton = this;
- add_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT));
- add_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT));
+ add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT));
+ add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT));
tabs = memnew(TabContainer);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
@@ -64,7 +64,7 @@ EditorDebuggerNode::EditorDebuggerNode() {
Ref<StyleBoxEmpty> empty;
empty.instance();
- tabs->add_style_override("panel", empty);
+ tabs->add_theme_style_override("panel", empty);
auto_switch_remote_scene_tree = EDITOR_DEF("debugger/auto_switch_to_remote_scene_tree", false);
_add_debugger();
@@ -110,7 +110,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
if (tabs->get_tab_count() > 1) {
node->clear_style();
tabs->set_tabs_visible(true);
- tabs->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
+ tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles"));
}
return node;
@@ -223,10 +223,10 @@ void EditorDebuggerNode::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (tabs->get_tab_count() > 1) {
- add_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT));
- add_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT));
+ add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT));
+ add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT));
- tabs->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
+ tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles"));
}
} break;
default:
@@ -262,9 +262,9 @@ void EditorDebuggerNode::_notification(int p_what) {
} else {
debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")");
if (error_count == 0) {
- debugger_button->set_icon(get_icon("Warning", "EditorIcons"));
+ debugger_button->set_icon(get_theme_icon("Warning", "EditorIcons"));
} else {
- debugger_button->set_icon(get_icon("Error", "EditorIcons"));
+ debugger_button->set_icon(get_theme_icon("Error", "EditorIcons"));
}
}
last_error_count = error_count;
@@ -291,13 +291,13 @@ void EditorDebuggerNode::_notification(int p_what) {
// Take connections.
if (server->is_connection_available()) {
- ScriptEditorDebugger *debugger = NULL;
+ ScriptEditorDebugger *debugger = nullptr;
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
if (debugger || dbg->is_session_active())
return;
debugger = dbg;
});
- if (debugger == NULL) {
+ if (debugger == nullptr) {
if (tabs->get_tab_count() <= 4) { // Max 4 debugging sessions active.
debugger = _add_debugger();
} else {
@@ -356,7 +356,7 @@ void EditorDebuggerNode::_debugger_changed(int p_tab) {
if (get_inspected_remote_object()) {
// Clear inspected object, you can only inspect objects in selected debugger.
// Hopefully, in the future, we will have one inspector per debugger.
- EditorNode::get_singleton()->push_item(NULL);
+ EditorNode::get_singleton()->push_item(nullptr);
}
if (remote_scene_tree->is_visible_in_tree()) {
get_current_debugger()->request_remote_tree();
@@ -371,7 +371,6 @@ void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) {
script_menu->set_text(TTR("Debug"));
script_menu->set_switch_on_hover(true);
PopupMenu *p = script_menu->get_popup();
- p->set_hide_on_window_lose_focus(true);
p->add_shortcut(ED_GET_SHORTCUT("debugger/step_into"), DEBUG_STEP);
p->add_shortcut(ED_GET_SHORTCUT("debugger/step_over"), DEBUG_NEXT);
p->add_separator();
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index 6181ccdb5f..9467442c9a 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -85,9 +85,9 @@ private:
};
Ref<EditorDebuggerServer> server;
- TabContainer *tabs = NULL;
- Button *debugger_button = NULL;
- MenuButton *script_menu = NULL;
+ TabContainer *tabs = nullptr;
+ Button *debugger_button = nullptr;
+ MenuButton *script_menu = nullptr;
Ref<Script> stack_script; // Why?!?
@@ -95,7 +95,7 @@ private:
int last_warning_count = 0;
float inspect_edited_object_timeout = 0;
- EditorDebuggerTree *remote_scene_tree = NULL;
+ EditorDebuggerTree *remote_scene_tree = nullptr;
float remote_scene_tree_timeout = 0.0;
bool auto_switch_remote_scene_tree = false;
bool debug_with_external_editor = false;
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index 441f6082c3..c2b94c79bb 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_node.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/resources/packed_scene.h"
+#include "servers/display_server.h"
EditorDebuggerTree::EditorDebuggerTree() {
set_v_size_flags(SIZE_EXPAND_FILL);
@@ -106,9 +107,9 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position) {
item->select(0);
item_menu->clear();
- item_menu->add_icon_item(get_icon("CreateNewSceneFrom", "EditorIcons"), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
- item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
- item_menu->set_global_position(get_global_mouse_position());
+ item_menu->add_icon_item(get_theme_icon("CreateNewSceneFrom", "EditorIcons"), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
+ item_menu->add_icon_item(get_theme_icon("CopyNodePath", "EditorIcons"), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
+ item_menu->set_position(get_screen_transform().xform(get_local_mouse_position()));
item_menu->popup();
}
@@ -132,9 +133,9 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
const String filter = EditorNode::get_singleton()->get_scene_tree_dock()->get_filter();
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
- List<Pair<TreeItem *, int> > parents;
+ List<Pair<TreeItem *, int>> parents;
for (int i = 0; i < p_tree->nodes.size(); i++) {
- TreeItem *parent = NULL;
+ TreeItem *parent = nullptr;
if (parents.size()) { // Find last parent.
Pair<TreeItem *, int> &p = parents[0];
parent = p.first;
@@ -190,7 +191,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
// Check if parent expects more children.
for (int j = 0; j < parents.size(); j++) {
if (parents[j].first == item) {
- parent = NULL;
+ parent = nullptr;
break; // Might have more children.
}
}
@@ -210,7 +211,7 @@ String EditorDebuggerTree::get_selected_path() {
String EditorDebuggerTree::_get_path(TreeItem *p_item) {
ERR_FAIL_COND_V(!p_item, "");
- if (p_item->get_parent() == NULL) {
+ if (p_item->get_parent() == nullptr) {
return "/root";
}
String text = p_item->get_text(0);
@@ -229,7 +230,7 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
case ITEM_MENU_SAVE_REMOTE_NODE: {
file_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
List<String> extensions;
Ref<PackedScene> sd = memnew(PackedScene);
@@ -257,7 +258,7 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
text = text.substr(slash + 1);
}
}
- OS::get_singleton()->set_clipboard(text);
+ DisplayServer::get_singleton()->clipboard_set(text);
} break;
}
}
diff --git a/editor/debugger/editor_debugger_tree.h b/editor/debugger/editor_debugger_tree.h
index d9084bc596..342eb23194 100644
--- a/editor/debugger/editor_debugger_tree.h
+++ b/editor/debugger/editor_debugger_tree.h
@@ -50,8 +50,8 @@ private:
int debugger_id = 0;
bool updating_scene_tree = false;
Set<ObjectID> unfold_cache;
- PopupMenu *item_menu = NULL;
- EditorFileDialog *file_dialog = NULL;
+ PopupMenu *item_menu = nullptr;
+ EditorFileDialog *file_dialog = nullptr;
String _get_path(TreeItem *p_item);
void _scene_tree_folded(Object *p_obj);
diff --git a/editor/debugger/editor_network_profiler.cpp b/editor/debugger/editor_network_profiler.cpp
index 21ef66d1aa..b8c795d9ca 100644
--- a/editor/debugger/editor_network_profiler.cpp
+++ b/editor/debugger/editor_network_profiler.cpp
@@ -41,14 +41,14 @@ void EditorNetworkProfiler::_bind_methods() {
void EditorNetworkProfiler::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- activate->set_icon(get_icon("Play", "EditorIcons"));
- clear_button->set_icon(get_icon("Clear", "EditorIcons"));
- incoming_bandwidth_text->set_right_icon(get_icon("ArrowDown", "EditorIcons"));
- outgoing_bandwidth_text->set_right_icon(get_icon("ArrowUp", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Play", "EditorIcons"));
+ clear_button->set_icon(get_theme_icon("Clear", "EditorIcons"));
+ incoming_bandwidth_text->set_right_icon(get_theme_icon("ArrowDown", "EditorIcons"));
+ outgoing_bandwidth_text->set_right_icon(get_theme_icon("ArrowUp", "EditorIcons"));
// This needs to be done here to set the faded color when the profiler is first opened
- incoming_bandwidth_text->add_color_override("font_color_uneditable", get_color("font_color", "Editor") * Color(1, 1, 1, 0.5));
- outgoing_bandwidth_text->add_color_override("font_color_uneditable", get_color("font_color", "Editor") * Color(1, 1, 1, 0.5));
+ incoming_bandwidth_text->add_theme_color_override("font_color_uneditable", get_theme_color("font_color", "Editor") * Color(1, 1, 1, 0.5));
+ outgoing_bandwidth_text->add_theme_color_override("font_color_uneditable", get_theme_color("font_color", "Editor") * Color(1, 1, 1, 0.5));
}
}
@@ -77,10 +77,10 @@ void EditorNetworkProfiler::_update_frame() {
void EditorNetworkProfiler::_activate_pressed() {
if (activate->is_pressed()) {
- activate->set_icon(get_icon("Stop", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Stop", "EditorIcons"));
activate->set_text(TTR("Stop"));
} else {
- activate->set_icon(get_icon("Play", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Play", "EditorIcons"));
activate->set_text(TTR("Start"));
}
emit_signal("enable_profiling", activate->is_pressed());
@@ -118,12 +118,12 @@ void EditorNetworkProfiler::set_bandwidth(int p_incoming, int p_outgoing) {
outgoing_bandwidth_text->set_text(vformat(TTR("%s/s"), String::humanize_size(p_outgoing)));
// Make labels more prominent when the bandwidth is greater than 0 to attract user attention
- incoming_bandwidth_text->add_color_override(
+ incoming_bandwidth_text->add_theme_color_override(
"font_color_uneditable",
- get_color("font_color", "Editor") * Color(1, 1, 1, p_incoming > 0 ? 1 : 0.5));
- outgoing_bandwidth_text->add_color_override(
+ get_theme_color("font_color", "Editor") * Color(1, 1, 1, p_incoming > 0 ? 1 : 0.5));
+ outgoing_bandwidth_text->add_theme_color_override(
"font_color_uneditable",
- get_color("font_color", "Editor") * Color(1, 1, 1, p_outgoing > 0 ? 1 : 0.5));
+ get_theme_color("font_color", "Editor") * Color(1, 1, 1, p_outgoing > 0 ? 1 : 0.5));
}
bool EditorNetworkProfiler::is_profiling() {
@@ -133,7 +133,7 @@ bool EditorNetworkProfiler::is_profiling() {
EditorNetworkProfiler::EditorNetworkProfiler() {
HBoxContainer *hb = memnew(HBoxContainer);
- hb->add_constant_override("separation", 8 * EDSCALE);
+ hb->add_theme_constant_override("separation", 8 * EDSCALE);
add_child(hb);
activate = memnew(Button);
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 2f3ad210b2..1577e24ac0 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -132,11 +132,11 @@ String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_ca
Color EditorProfiler::_get_color_from_signature(const StringName &p_signature) const {
- Color bc = get_color("error_color", "Editor");
+ Color bc = get_theme_color("error_color", "Editor");
double rot = ABS(double(p_signature.hash()) / double(0x7FFFFFFF));
Color c;
c.set_hsv(rot, bc.get_s(), bc.get_v());
- return c.linear_interpolate(get_color("base_color", "Editor"), 0.07);
+ return c.linear_interpolate(get_theme_color("base_color", "Editor"), 0.07);
}
void EditorProfiler::_item_edited() {
@@ -176,7 +176,7 @@ void EditorProfiler::_update_plot() {
}
uint8_t *wr = graph_image.ptrw();
- const Color background_color = get_color("dark_color_2", "Editor");
+ const Color background_color = get_theme_color("dark_color_2", "Editor");
// Clear the previous frame and set the background color.
for (int i = 0; i < desired_len; i += 4) {
@@ -420,10 +420,10 @@ void EditorProfiler::_update_frame() {
void EditorProfiler::_activate_pressed() {
if (activate->is_pressed()) {
- activate->set_icon(get_icon("Stop", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Stop", "EditorIcons"));
activate->set_text(TTR("Stop"));
} else {
- activate->set_icon(get_icon("Play", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Play", "EditorIcons"));
activate->set_text(TTR("Start"));
}
emit_signal("enable_profiling", activate->is_pressed());
@@ -438,8 +438,8 @@ void EditorProfiler::_clear_pressed() {
void EditorProfiler::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- activate->set_icon(get_icon("Play", "EditorIcons"));
- clear_button->set_icon(get_icon("Clear", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Play", "EditorIcons"));
+ clear_button->set_icon(get_theme_icon("Clear", "EditorIcons"));
}
}
@@ -611,8 +611,8 @@ bool EditorProfiler::is_profiling() {
return activate->is_pressed();
}
-Vector<Vector<String> > EditorProfiler::get_data_as_csv() const {
- Vector<Vector<String> > res;
+Vector<Vector<String>> EditorProfiler::get_data_as_csv() const {
+ Vector<Vector<String>> res;
if (frame_metrics.empty()) {
return res;
@@ -712,7 +712,7 @@ EditorProfiler::EditorProfiler() {
hb->add_child(cursor_metric_edit);
cursor_metric_edit->connect("value_changed", callable_mp(this, &EditorProfiler::_cursor_metric_changed));
- hb->add_constant_override("separation", 8 * EDSCALE);
+ hb->add_theme_constant_override("separation", 8 * EDSCALE);
h_split = memnew(HSplitContainer);
add_child(h_split);
diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h
index 0a442ddd5c..4afd2c8302 100644
--- a/editor/debugger/editor_profiler.h
+++ b/editor/debugger/editor_profiler.h
@@ -169,7 +169,7 @@ public:
void clear();
- Vector<Vector<String> > get_data_as_csv() const;
+ Vector<Vector<String>> get_data_as_csv() const;
EditorProfiler();
};
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index 52aa418922..d2edba5970 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -128,11 +128,11 @@ String EditorVisualProfiler::_get_time_as_text(float p_time) {
Color EditorVisualProfiler::_get_color_from_signature(const StringName &p_signature) const {
- Color bc = get_color("error_color", "Editor");
+ Color bc = get_theme_color("error_color", "Editor");
double rot = ABS(double(p_signature.hash()) / double(0x7FFFFFFF));
Color c;
c.set_hsv(rot, bc.get_s(), bc.get_v());
- return c.linear_interpolate(get_color("base_color", "Editor"), 0.07);
+ return c.linear_interpolate(get_theme_color("base_color", "Editor"), 0.07);
}
void EditorVisualProfiler::_item_selected() {
@@ -327,7 +327,7 @@ void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
int cursor_metric = _get_cursor_index();
- Ref<Texture> track_icon = get_icon("TrackColor", "EditorIcons");
+ Ref<Texture> track_icon = get_theme_icon("TrackColor", "EditorIcons");
ERR_FAIL_INDEX(cursor_metric, frame_metrics.size());
@@ -418,11 +418,11 @@ void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
void EditorVisualProfiler::_activate_pressed() {
if (activate->is_pressed()) {
- activate->set_icon(get_icon("Stop", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Stop", "EditorIcons"));
activate->set_text(TTR("Stop"));
_clear_pressed(); //always clear on start
} else {
- activate->set_icon(get_icon("Play", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Play", "EditorIcons"));
activate->set_text(TTR("Start"));
}
emit_signal("enable_profiling", activate->is_pressed());
@@ -437,8 +437,8 @@ void EditorVisualProfiler::_clear_pressed() {
void EditorVisualProfiler::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- activate->set_icon(get_icon("Play", "EditorIcons"));
- clear_button->set_icon(get_icon("Clear", "EditorIcons"));
+ activate->set_icon(get_theme_icon("Play", "EditorIcons"));
+ clear_button->set_icon(get_theme_icon("Clear", "EditorIcons"));
}
}
@@ -446,7 +446,7 @@ void EditorVisualProfiler::_graph_tex_draw() {
if (last_metric < 0)
return;
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
if (seeking) {
int max_frames = frame_metrics.size();
@@ -678,8 +678,8 @@ bool EditorVisualProfiler::is_profiling() {
return activate->is_pressed();
}
-Vector<Vector<String> > EditorVisualProfiler::get_data_as_csv() const {
- Vector<Vector<String> > res;
+Vector<Vector<String>> EditorVisualProfiler::get_data_as_csv() const {
+ Vector<Vector<String>> res;
#if 0
if (frame_metrics.empty()) {
return res;
@@ -777,7 +777,7 @@ EditorVisualProfiler::EditorVisualProfiler() {
hb->add_child(cursor_metric_edit);
cursor_metric_edit->connect("value_changed", callable_mp(this, &EditorVisualProfiler::_cursor_metric_changed));
- hb->add_constant_override("separation", 8 * EDSCALE);
+ hb->add_theme_constant_override("separation", 8 * EDSCALE);
h_split = memnew(HSplitContainer);
add_child(h_split);
diff --git a/editor/debugger/editor_visual_profiler.h b/editor/debugger/editor_visual_profiler.h
index 5194c08b96..d3a758557c 100644
--- a/editor/debugger/editor_visual_profiler.h
+++ b/editor/debugger/editor_visual_profiler.h
@@ -146,7 +146,7 @@ public:
void clear();
- Vector<Vector<String> > get_data_as_csv() const;
+ Vector<Vector<String>> get_data_as_csv() const;
EditorVisualProfiler();
};
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 3d567ed2b3..1971abadc4 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -42,10 +42,10 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
-#include "editor/plugins/spatial_editor_plugin.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/property_editor.h"
#include "main/performance.h"
-#include "scene/3d/camera.h"
+#include "scene/3d/camera_3d.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/label.h"
@@ -58,6 +58,7 @@
#include "scene/gui/texture_button.h"
#include "scene/gui/tree.h"
#include "scene/resources/packed_scene.h"
+#include "servers/display_server.h"
using CameraOverride = EditorDebuggerNode::CameraOverride;
@@ -73,15 +74,15 @@ void ScriptEditorDebugger::_put_msg(String p_message, Array p_data) {
void ScriptEditorDebugger::debug_copy() {
String msg = reason->get_text();
if (msg == "") return;
- OS::get_singleton()->set_clipboard(msg);
+ DisplayServer::get_singleton()->clipboard_set(msg);
}
void ScriptEditorDebugger::debug_skip_breakpoints() {
skip_breakpoints_value = !skip_breakpoints_value;
if (skip_breakpoints_value)
- skip_breakpoints->set_icon(get_icon("DebugSkipBreakpointsOn", "EditorIcons"));
+ skip_breakpoints->set_icon(get_theme_icon("DebugSkipBreakpointsOn", "EditorIcons"));
else
- skip_breakpoints->set_icon(get_icon("DebugSkipBreakpointsOff", "EditorIcons"));
+ skip_breakpoints->set_icon(get_theme_icon("DebugSkipBreakpointsOff", "EditorIcons"));
Array msg;
msg.push_back(skip_breakpoints_value);
@@ -116,7 +117,7 @@ void ScriptEditorDebugger::debug_continue() {
// Allow focus stealing only if we actually run this client for security.
if (remote_pid && EditorNode::get_singleton()->has_child_process(remote_pid))
- OS::get_singleton()->enable_for_stealing_focus(remote_pid);
+ DisplayServer::get_singleton()->enable_for_stealing_focus(remote_pid);
_clear_execution();
_put_msg("continue", Array());
@@ -129,15 +130,15 @@ void ScriptEditorDebugger::update_tabs() {
} else {
errors_tab->set_name(TTR("Errors") + " (" + itos(error_count + warning_count) + ")");
if (error_count == 0) {
- tabs->set_tab_icon(errors_tab->get_index(), get_icon("Warning", "EditorIcons"));
+ tabs->set_tab_icon(errors_tab->get_index(), get_theme_icon("Warning", "EditorIcons"));
} else {
- tabs->set_tab_icon(errors_tab->get_index(), get_icon("Error", "EditorIcons"));
+ tabs->set_tab_icon(errors_tab->get_index(), get_theme_icon("Error", "EditorIcons"));
}
}
}
void ScriptEditorDebugger::clear_style() {
- tabs->add_style_override("panel", NULL);
+ tabs->add_theme_style_override("panel", nullptr);
}
void ScriptEditorDebugger::save_node(ObjectID p_id, const String &p_file) {
@@ -165,7 +166,7 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) {
file->store_csv_line(line);
// values
- List<Vector<float> >::Element *E = perf_history.back();
+ List<Vector<float>>::Element *E = perf_history.back();
while (E) {
Vector<float> &perf_data = E->get();
@@ -178,7 +179,7 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) {
}
file->store_string("\n");
- Vector<Vector<String> > profiler_data = profiler->get_data_as_csv();
+ Vector<Vector<String>> profiler_data = profiler->get_data_as_csv();
for (int i = 0; i < profiler_data.size(); i++) {
file->store_csv_line(profiler_data[i]);
}
@@ -253,7 +254,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
_update_buttons_state();
_set_reason_text(error, MESSAGE_ERROR);
emit_signal("breaked", true, can_continue);
- OS::get_singleton()->move_window_to_foreground();
+ DisplayServer::get_singleton()->window_move_to_foreground();
if (error != "") {
tabs->set_current_tab(0);
}
@@ -310,8 +311,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
it->set_text(3, String::humanize_size(bytes));
total += bytes;
- if (has_icon(type, "EditorIcons"))
- it->set_icon(0, get_icon(type, "EditorIcons"));
+ if (has_theme_icon(type, "EditorIcons"))
+ it->set_icon(0, get_theme_icon(type, "EditorIcons"));
}
vmem_total->set_tooltip(TTR("Bytes:") + " " + itos(total));
@@ -442,7 +443,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
TreeItem *error = error_tree->create_item(r);
error->set_collapsed(true);
- error->set_icon(0, get_icon(oe.warning ? "Warning" : "Error", "EditorIcons"));
+ error->set_icon(0, get_theme_icon(oe.warning ? "Warning" : "Error", "EditorIcons"));
error->set_text(0, time);
error->set_text_align(0, TreeItem::ALIGN_LEFT);
@@ -660,13 +661,13 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType p_type) {
switch (p_type) {
case MESSAGE_ERROR:
- reason->add_color_override("font_color", get_color("error_color", "Editor"));
+ reason->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
break;
case MESSAGE_WARNING:
- reason->add_color_override("font_color", get_color("warning_color", "Editor"));
+ reason->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"));
break;
default:
- reason->add_color_override("font_color", get_color("success_color", "Editor"));
+ reason->add_theme_color_override("font_color", get_theme_color("success_color", "Editor"));
}
reason->set_text(p_reason);
reason->set_tooltip(p_reason.word_wrap(80));
@@ -693,8 +694,8 @@ void ScriptEditorDebugger::_performance_draw() {
info_message->hide();
- Ref<StyleBox> graph_sb = get_stylebox("normal", "TextEdit");
- Ref<Font> graph_font = get_font("font", "TextEdit");
+ Ref<StyleBox> graph_sb = get_theme_stylebox("normal", "TextEdit");
+ Ref<Font> graph_font = get_theme_font("font", "TextEdit");
int cols = Math::ceil(Math::sqrt((float)which.size()));
int rows = Math::ceil((float)which.size() / cols);
@@ -714,7 +715,7 @@ void ScriptEditorDebugger::_performance_draw() {
r.position += graph_sb->get_offset();
r.size -= graph_sb->get_minimum_size();
int pi = which[i];
- Color c = get_color("accent_color", "Editor");
+ Color c = get_theme_color("accent_color", "Editor");
float h = (float)which[i] / (float)(perf_items.size());
// Use a darker color on light backgrounds for better visibility
float value_multiplier = EditorSettings::get_singleton()->is_dark_theme() ? 1.4 : 0.55;
@@ -728,7 +729,7 @@ void ScriptEditorDebugger::_performance_draw() {
float spacing = point_sep / float(cols);
float from = r.size.width;
- List<Vector<float> >::Element *E = perf_history.front();
+ List<Vector<float>>::Element *E = perf_history.front();
float prev = -1;
while (from >= 0 && E) {
@@ -753,20 +754,20 @@ void ScriptEditorDebugger::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
- skip_breakpoints->set_icon(get_icon("DebugSkipBreakpointsOff", "EditorIcons"));
- copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
+ skip_breakpoints->set_icon(get_theme_icon("DebugSkipBreakpointsOff", "EditorIcons"));
+ copy->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
- step->set_icon(get_icon("DebugStep", "EditorIcons"));
- next->set_icon(get_icon("DebugNext", "EditorIcons"));
- dobreak->set_icon(get_icon("Pause", "EditorIcons"));
- docontinue->set_icon(get_icon("DebugContinue", "EditorIcons"));
+ step->set_icon(get_theme_icon("DebugStep", "EditorIcons"));
+ next->set_icon(get_theme_icon("DebugNext", "EditorIcons"));
+ dobreak->set_icon(get_theme_icon("Pause", "EditorIcons"));
+ docontinue->set_icon(get_theme_icon("DebugContinue", "EditorIcons"));
le_set->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_live_edit_set));
le_clear->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_live_edit_clear));
error_tree->connect("item_selected", callable_mp(this, &ScriptEditorDebugger::_error_selected));
error_tree->connect("item_activated", callable_mp(this, &ScriptEditorDebugger::_error_activated));
- vmem_refresh->set_icon(get_icon("Reload", "EditorIcons"));
+ vmem_refresh->set_icon(get_theme_icon("Reload", "EditorIcons"));
- reason->add_color_override("font_color", get_color("error_color", "Editor"));
+ reason->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
} break;
case NOTIFICATION_PROCESS: {
@@ -790,12 +791,12 @@ void ScriptEditorDebugger::_notification(int p_what) {
} else if (camera_override >= CameraOverride::OVERRIDE_3D_1) {
int viewport_idx = camera_override - CameraOverride::OVERRIDE_3D_1;
- SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(viewport_idx);
- Camera *const cam = viewport->get_camera();
+ Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(viewport_idx);
+ Camera3D *const cam = viewport->get_camera();
Array msg;
msg.push_back(cam->get_camera_transform());
- if (cam->get_projection() == Camera::PROJECTION_ORTHOGONAL) {
+ if (cam->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
msg.push_back(false);
msg.push_back(cam->get_size());
} else {
@@ -810,7 +811,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
const uint64_t until = OS::get_singleton()->get_ticks_msec() + 20;
- while (peer->has_message()) {
+ while (peer.is_valid() && peer->has_message()) {
Array arr = peer->get_message();
if (arr.size() != 2 || arr[0].get_type() != Variant::STRING || arr[1].get_type() != Variant::ARRAY) {
@@ -829,16 +830,16 @@ void ScriptEditorDebugger::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- if (tabs->has_stylebox_override("panel")) {
- tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
+ if (tabs->has_theme_stylebox_override("panel")) {
+ tabs->add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles"));
}
- copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
- step->set_icon(get_icon("DebugStep", "EditorIcons"));
- next->set_icon(get_icon("DebugNext", "EditorIcons"));
- dobreak->set_icon(get_icon("Pause", "EditorIcons"));
- docontinue->set_icon(get_icon("DebugContinue", "EditorIcons"));
- vmem_refresh->set_icon(get_icon("Reload", "EditorIcons"));
+ copy->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
+ step->set_icon(get_theme_icon("DebugStep", "EditorIcons"));
+ next->set_icon(get_theme_icon("DebugNext", "EditorIcons"));
+ dobreak->set_icon(get_theme_icon("Pause", "EditorIcons"));
+ docontinue->set_icon(get_theme_icon("DebugContinue", "EditorIcons"));
+ vmem_refresh->set_icon(get_theme_icon("Reload", "EditorIcons"));
} break;
}
}
@@ -922,7 +923,7 @@ void ScriptEditorDebugger::stop() {
res_path_cache.clear();
profiler_signature.clear();
- inspector->edit(NULL);
+ inspector->edit(nullptr);
_update_buttons_state();
}
@@ -972,13 +973,13 @@ void ScriptEditorDebugger::_stack_dump_frame_selected() {
msg.push_back(frame);
_put_msg("get_stack_frame_vars", msg);
} else {
- inspector->edit(NULL);
+ inspector->edit(nullptr);
}
}
void ScriptEditorDebugger::_export_csv() {
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_dialog->popup_centered_ratio();
}
@@ -1388,7 +1389,7 @@ 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_icon("ActionCopy", "EditorIcons"), TTR("Copy Error"), 0);
+ item_menu->add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Error"), 0);
}
if (item_menu->get_item_count() > 0) {
@@ -1404,9 +1405,9 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
String type;
- if (ti->get_icon(0) == get_icon("Warning", "EditorIcons")) {
+ if (ti->get_icon(0) == get_theme_icon("Warning", "EditorIcons")) {
type = "W ";
- } else if (ti->get_icon(0) == get_icon("Error", "EditorIcons")) {
+ } else if (ti->get_icon(0) == get_theme_icon("Error", "EditorIcons")) {
type = "E ";
}
@@ -1420,7 +1421,7 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
ci = ci->get_next();
}
- OS::get_singleton()->set_clipboard(text);
+ DisplayServer::get_singleton()->clipboard_set(text);
}
void ScriptEditorDebugger::_tab_changed(int p_tab) {
@@ -1461,7 +1462,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
tabs = memnew(TabContainer);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
- tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
+ tabs->add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles"));
tabs->connect("tab_changed", callable_mp(this, &ScriptEditorDebugger::_tab_changed));
add_child(tabs);
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index e7ce917543..9cb7dc2edf 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -107,9 +107,9 @@ private:
Button *docontinue;
// Reference to "Remote" tab in scene tree. Needed by _live_edit_set and buttons state.
// Each debugger should have it's tree in the future I guess.
- const Tree *editor_remote_tree = NULL;
+ const Tree *editor_remote_tree = nullptr;
- List<Vector<float> > perf_history;
+ List<Vector<float>> perf_history;
Vector<float> perf_max;
Vector<TreeItem *> perf_items;
@@ -255,7 +255,7 @@ public:
bool is_skip_breakpoints();
virtual Size2 get_minimum_size() const;
- ScriptEditorDebugger(EditorNode *p_editor = NULL);
+ ScriptEditorDebugger(EditorNode *p_editor = nullptr);
~ScriptEditorDebugger();
};
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 0c95a64d06..2302fb0780 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -63,7 +63,7 @@ void DependencyEditor::_load_pressed(Object *p_item, int p_cell, int p_button) {
search->popup_centered_ratio(0.65); // So it doesn't completely cover the dialog below it.
}
-void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String, Map<String, String> > &candidates) {
+void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String, Map<String, String>> &candidates) {
for (int i = 0; i < efsd->get_subdir_count(); i++) {
_fix_and_find(efsd->get_subdir(i), candidates);
@@ -124,7 +124,7 @@ void DependencyEditor::_fix_all() {
if (!EditorFileSystem::get_singleton()->get_filesystem())
return;
- Map<String, Map<String, String> > candidates;
+ Map<String, Map<String, String>> candidates;
for (List<String>::Element *E = missing.front(); E; E = E->next()) {
@@ -140,7 +140,7 @@ void DependencyEditor::_fix_all() {
Map<String, String> remaps;
- for (Map<String, Map<String, String> >::Element *E = candidates.front(); E; E = E->next()) {
+ for (Map<String, Map<String, String>>::Element *E = candidates.front(); E; E = E->next()) {
for (Map<String, String>::Element *F = E->get().front(); F; F = F->next()) {
@@ -174,7 +174,7 @@ void DependencyEditor::_update_list() {
TreeItem *root = tree->create_item();
- Ref<Texture2D> folder = get_icon("folder", "FileDialog");
+ Ref<Texture2D> folder = tree->get_theme_icon("folder", "FileDialog");
bool broken = false;
@@ -256,7 +256,7 @@ DependencyEditor::DependencyEditor() {
vb->add_child(hbc);
MarginContainer *mc = memnew(MarginContainer);
- mc->set_v_size_flags(SIZE_EXPAND_FILL);
+ mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
mc->add_child(tree);
vb->add_child(mc);
@@ -264,7 +264,7 @@ DependencyEditor::DependencyEditor() {
set_title(TTR("Dependency Editor"));
search = memnew(EditorFileDialog);
search->connect("file_selected", callable_mp(this, &DependencyEditor::_searched));
- search->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ search->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
search->set_title(TTR("Search Replacement Resource:"));
add_child(search);
}
@@ -422,17 +422,17 @@ void DependencyRemoveDialog::_build_removed_dependency_tree(const Vector<Removed
if (!tree_items.has(rd.dependency_folder)) {
TreeItem *folder_item = owners->create_item(owners->get_root());
folder_item->set_text(0, rd.dependency_folder);
- folder_item->set_icon(0, get_icon("Folder", "EditorIcons"));
+ folder_item->set_icon(0, owners->get_theme_icon("Folder", "EditorIcons"));
tree_items[rd.dependency_folder] = folder_item;
}
TreeItem *dependency_item = owners->create_item(tree_items[rd.dependency_folder]);
dependency_item->set_text(0, rd.dependency);
- dependency_item->set_icon(0, get_icon("Warning", "EditorIcons"));
+ dependency_item->set_icon(0, owners->get_theme_icon("Warning", "EditorIcons"));
tree_items[rd.dependency] = dependency_item;
} else {
TreeItem *dependency_item = owners->create_item(owners->get_root());
dependency_item->set_text(0, rd.dependency);
- dependency_item->set_icon(0, get_icon("Warning", "EditorIcons"));
+ dependency_item->set_icon(0, owners->get_theme_icon("Warning", "EditorIcons"));
tree_items[rd.dependency] = dependency_item;
}
}
@@ -580,7 +580,7 @@ DependencyRemoveDialog::DependencyRemoveDialog() {
owners = memnew(Tree);
owners->set_hide_root(true);
vb->add_child(owners);
- owners->set_v_size_flags(SIZE_EXPAND_FILL);
+ owners->set_v_size_flags(Control::SIZE_EXPAND_FILL);
}
//////////////
@@ -592,7 +592,7 @@ void DependencyErrorDialog::show(Mode p_mode, const String &p_for_file, const Ve
set_title(TTR("Error loading:") + " " + p_for_file.get_file());
files->clear();
- TreeItem *root = files->create_item(NULL);
+ TreeItem *root = files->create_item(nullptr);
for (int i = 0; i < report.size(); i++) {
String dep;
@@ -636,9 +636,9 @@ DependencyErrorDialog::DependencyErrorDialog() {
files = memnew(Tree);
files->set_hide_root(true);
vb->add_margin_child(TTR("Load failed due to missing dependencies:"), files, true);
- files->set_v_size_flags(SIZE_EXPAND_FILL);
+ files->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- set_custom_minimum_size(Size2(500, 220) * EDSCALE);
+ set_min_size(Size2(500, 220) * EDSCALE);
get_ok()->set_text(TTR("Open Anyway"));
get_cancel()->set_text(TTR("Close"));
@@ -662,7 +662,7 @@ void OrphanResourcesDialog::ok_pressed() {
return;
delete_confirm->set_text(vformat(TTR("Permanently delete %d item(s)? (No undo!)"), paths.size()));
- delete_confirm->popup_centered_clamped(delete_confirm->get_minimum_size());
+ delete_confirm->popup_centered();
}
bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd, HashMap<String, int> &refs, TreeItem *p_parent) {
@@ -674,11 +674,11 @@ bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd, HashMa
for (int i = 0; i < efsd->get_subdir_count(); i++) {
- TreeItem *dir_item = NULL;
+ TreeItem *dir_item = nullptr;
if (p_parent) {
dir_item = files->create_item(p_parent);
dir_item->set_text(0, efsd->get_subdir(i)->get_name());
- dir_item->set_icon(0, get_icon("folder", "FileDialog"));
+ dir_item->set_icon(0, files->get_theme_icon("folder", "FileDialog"));
}
bool children = _fill_owners(efsd->get_subdir(i), refs, dir_item);
@@ -717,7 +717,7 @@ bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd, HashMa
int ds = efsd->get_file_deps(i).size();
ti->set_text(1, itos(ds));
if (ds) {
- ti->add_button(1, get_icon("GuiVisibilityVisible", "EditorIcons"), -1, false, TTR("Show Dependencies"));
+ ti->add_button(1, files->get_theme_icon("GuiVisibilityVisible", "EditorIcons"), -1, false, TTR("Show Dependencies"));
}
ti->set_metadata(0, path);
has_children = true;
@@ -730,7 +730,7 @@ bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd, HashMa
void OrphanResourcesDialog::refresh() {
HashMap<String, int> refs;
- _fill_owners(EditorFileSystem::get_singleton()->get_filesystem(), refs, NULL);
+ _fill_owners(EditorFileSystem::get_singleton()->get_filesystem(), refs, nullptr);
files->clear();
TreeItem *root = files->create_item();
_fill_owners(EditorFileSystem::get_singleton()->get_filesystem(), refs, root);
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index be8d34f406..ee74072731 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -52,7 +52,7 @@ class DependencyEditor : public AcceptDialog {
String editing;
List<String> missing;
- void _fix_and_find(EditorFileSystemDirectory *efsd, Map<String, Map<String, String> > &candidates);
+ void _fix_and_find(EditorFileSystemDirectory *efsd, Map<String, Map<String, String>> &candidates);
void _searched(const String &p_path);
void _load_pressed(Object *p_item, int p_cell, int p_button);
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
index 82db639379..7169986b14 100644
--- a/editor/dictionary_property_edit.cpp
+++ b/editor/dictionary_property_edit.cpp
@@ -96,7 +96,7 @@ Node *DictionaryPropertyEdit::get_node() {
Object *o = ObjectDB::get_instance(obj);
if (!o)
- return NULL;
+ return nullptr;
return cast_to<Node>(o);
}
diff --git a/editor/doc/SCsub b/editor/doc/SCsub
deleted file mode 100644
index 2b1e889fb0..0000000000
--- a/editor/doc/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp
deleted file mode 100644
index 38ff9cd5fc..0000000000
--- a/editor/doc/doc_data.cpp
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*************************************************************************/
-/* doc_data.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "doc_data.h"
-
-#include "core/engine.h"
-#include "core/global_constants.h"
-#include "core/io/compression.h"
-#include "core/io/marshalls.h"
-#include "core/os/dir_access.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
-#include "core/version.h"
-#include "scene/resources/theme.h"
-
-void DocData::merge_from(const DocData &p_data) {
-
- for (Map<String, ClassDoc>::Element *E = class_list.front(); E; E = E->next()) {
-
- ClassDoc &c = E->get();
-
- if (!p_data.class_list.has(c.name))
- continue;
-
- const ClassDoc &cf = p_data.class_list[c.name];
-
- c.description = cf.description;
- c.brief_description = cf.brief_description;
- c.tutorials = cf.tutorials;
-
- for (int i = 0; i < c.methods.size(); i++) {
-
- MethodDoc &m = c.methods.write[i];
-
- for (int j = 0; j < cf.methods.size(); j++) {
-
- if (cf.methods[j].name != m.name)
- continue;
- if (cf.methods[j].arguments.size() != m.arguments.size())
- continue;
- // since polymorphic functions are allowed we need to check the type of
- // the arguments so we make sure they are different.
- int arg_count = cf.methods[j].arguments.size();
- Vector<bool> arg_used;
- arg_used.resize(arg_count);
- for (int l = 0; l < arg_count; ++l)
- arg_used.write[l] = false;
- // also there is no guarantee that argument ordering will match, so we
- // have to check one by one so we make sure we have an exact match
- for (int k = 0; k < arg_count; ++k) {
- for (int l = 0; l < arg_count; ++l)
- if (cf.methods[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) {
- arg_used.write[l] = true;
- break;
- }
- }
- bool not_the_same = false;
- for (int l = 0; l < arg_count; ++l)
- if (!arg_used[l]) // at least one of the arguments was different
- not_the_same = true;
- if (not_the_same)
- continue;
-
- const MethodDoc &mf = cf.methods[j];
-
- m.description = mf.description;
- break;
- }
- }
-
- for (int i = 0; i < c.signals.size(); i++) {
-
- MethodDoc &m = c.signals.write[i];
-
- for (int j = 0; j < cf.signals.size(); j++) {
-
- if (cf.signals[j].name != m.name)
- continue;
- const MethodDoc &mf = cf.signals[j];
-
- m.description = mf.description;
- break;
- }
- }
-
- for (int i = 0; i < c.constants.size(); i++) {
-
- ConstantDoc &m = c.constants.write[i];
-
- for (int j = 0; j < cf.constants.size(); j++) {
-
- if (cf.constants[j].name != m.name)
- continue;
- const ConstantDoc &mf = cf.constants[j];
-
- m.description = mf.description;
- break;
- }
- }
-
- for (int i = 0; i < c.properties.size(); i++) {
-
- PropertyDoc &p = c.properties.write[i];
-
- for (int j = 0; j < cf.properties.size(); j++) {
-
- if (cf.properties[j].name != p.name)
- continue;
- const PropertyDoc &pf = cf.properties[j];
-
- p.description = pf.description;
- break;
- }
- }
-
- for (int i = 0; i < c.theme_properties.size(); i++) {
-
- PropertyDoc &p = c.theme_properties.write[i];
-
- for (int j = 0; j < cf.theme_properties.size(); j++) {
-
- if (cf.theme_properties[j].name != p.name)
- continue;
- const PropertyDoc &pf = cf.theme_properties[j];
-
- p.description = pf.description;
- break;
- }
- }
- }
-}
-
-void DocData::remove_from(const DocData &p_data) {
- for (Map<String, ClassDoc>::Element *E = p_data.class_list.front(); E; E = E->next()) {
- if (class_list.has(E->key()))
- class_list.erase(E->key());
- }
-}
-
-static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) {
-
- if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
- p_method.return_enum = p_retinfo.class_name;
- if (p_method.return_enum.begins_with("_")) //proxy class
- p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length());
- p_method.return_type = "int";
- } else if (p_retinfo.class_name != StringName()) {
- p_method.return_type = p_retinfo.class_name;
- } else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- p_method.return_type = p_retinfo.hint_string;
- } else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
- p_method.return_type = "Variant";
- } else if (p_retinfo.type == Variant::NIL) {
- p_method.return_type = "void";
- } else {
- p_method.return_type = Variant::get_type_name(p_retinfo.type);
- }
-}
-
-static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) {
-
- p_argument.name = p_arginfo.name;
-
- if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
- p_argument.enumeration = p_arginfo.class_name;
- if (p_argument.enumeration.begins_with("_")) //proxy class
- p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length());
- p_argument.type = "int";
- } else if (p_arginfo.class_name != StringName()) {
- p_argument.type = p_arginfo.class_name;
- } else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- p_argument.type = p_arginfo.hint_string;
- } else if (p_arginfo.type == Variant::NIL) {
- // Parameters cannot be void, so PROPERTY_USAGE_NIL_IS_VARIANT is not necessary
- p_argument.type = "Variant";
- } else {
- p_argument.type = Variant::get_type_name(p_arginfo.type);
- }
-}
-
-static Variant get_documentation_default_value(const StringName &p_class_name, const StringName &p_property_name, bool &r_default_value_valid) {
-
- Variant default_value = Variant();
- r_default_value_valid = false;
-
- if (ClassDB::can_instance(p_class_name)) {
- default_value = ClassDB::class_get_default_property_value(p_class_name, p_property_name, &r_default_value_valid);
- } else {
- // Cannot get default value of classes that can't be instanced
- List<StringName> inheriting_classes;
- ClassDB::get_direct_inheriters_from_class(p_class_name, &inheriting_classes);
- for (List<StringName>::Element *E2 = inheriting_classes.front(); E2; E2 = E2->next()) {
- if (ClassDB::can_instance(E2->get())) {
- default_value = ClassDB::class_get_default_property_value(E2->get(), p_property_name, &r_default_value_valid);
- if (r_default_value_valid)
- break;
- }
- }
- }
-
- return default_value;
-}
-
-void DocData::generate(bool p_basic_types) {
-
- List<StringName> classes;
- ClassDB::get_class_list(&classes);
- classes.sort_custom<StringName::AlphCompare>();
- // Move ProjectSettings, so that other classes can register properties there.
- classes.move_to_back(classes.find("ProjectSettings"));
-
- bool skip_setter_getter_methods = true;
-
- while (classes.size()) {
-
- Set<StringName> setters_getters;
-
- String name = classes.front()->get();
- String cname = name;
- if (cname.begins_with("_")) //proxy class
- cname = cname.substr(1, name.length());
-
- class_list[cname] = ClassDoc();
- ClassDoc &c = class_list[cname];
- c.name = cname;
- c.inherits = ClassDB::get_parent_class(name);
-
- List<PropertyInfo> properties;
- List<PropertyInfo> own_properties;
- if (name == "ProjectSettings") {
- //special case for project settings, so settings can be documented
- ProjectSettings::get_singleton()->get_property_list(&properties);
- own_properties = properties;
- } else {
- ClassDB::get_property_list(name, &properties);
- ClassDB::get_property_list(name, &own_properties, true);
- }
-
- List<PropertyInfo>::Element *EO = own_properties.front();
- for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- bool inherited = EO == NULL;
- if (EO && EO->get() == E->get()) {
- inherited = false;
- EO = EO->next();
- }
-
- if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_INTERNAL)
- continue;
-
- PropertyDoc prop;
-
- prop.name = E->get().name;
-
- prop.overridden = inherited;
-
- bool default_value_valid = false;
- Variant default_value;
-
- if (name == "ProjectSettings") {
- // Special case for project settings, so that settings are not taken from the current project's settings
- if (E->get().name == "script" ||
- ProjectSettings::get_singleton()->get_order(E->get().name) >= ProjectSettings::NO_BUILTIN_ORDER_BASE) {
- continue;
- }
- if (E->get().usage & PROPERTY_USAGE_EDITOR) {
- default_value = ProjectSettings::get_singleton()->property_get_revert(E->get().name);
- default_value_valid = true;
- }
- } else {
- default_value = get_documentation_default_value(name, E->get().name, default_value_valid);
-
- if (inherited) {
- bool base_default_value_valid = false;
- Variant base_default_value = get_documentation_default_value(ClassDB::get_parent_class(name), E->get().name, base_default_value_valid);
- if (!default_value_valid || !base_default_value_valid || default_value == base_default_value)
- continue;
- }
- }
-
- //used to track uninitialized values using valgrind
- //print_line("getting default value for " + String(name) + "." + String(E->get().name));
- if (default_value_valid && default_value.get_type() != Variant::OBJECT) {
- prop.default_value = default_value.get_construct_string().replace("\n", "");
- }
-
- StringName setter = ClassDB::get_property_setter(name, E->get().name);
- StringName getter = ClassDB::get_property_getter(name, E->get().name);
-
- prop.setter = setter;
- prop.getter = getter;
-
- bool found_type = false;
- if (getter != StringName()) {
- MethodBind *mb = ClassDB::get_method(name, getter);
- if (mb) {
- PropertyInfo retinfo = mb->get_return_info();
-
- found_type = true;
- if (retinfo.type == Variant::INT && retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
- prop.enumeration = retinfo.class_name;
- prop.type = "int";
- } else if (retinfo.class_name != StringName()) {
- prop.type = retinfo.class_name;
- } else if (retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
-
- prop.type = retinfo.hint_string;
- } else if (retinfo.type == Variant::NIL && retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
-
- prop.type = "Variant";
- } else if (retinfo.type == Variant::NIL) {
- prop.type = "void";
- } else {
- prop.type = Variant::get_type_name(retinfo.type);
- }
- }
-
- setters_getters.insert(getter);
- }
-
- if (setter != StringName()) {
-
- setters_getters.insert(setter);
- }
-
- if (!found_type) {
-
- if (E->get().type == Variant::OBJECT && E->get().hint == PROPERTY_HINT_RESOURCE_TYPE)
- prop.type = E->get().hint_string;
- else
- prop.type = Variant::get_type_name(E->get().type);
- }
-
- c.properties.push_back(prop);
- }
-
- List<MethodInfo> method_list;
- ClassDB::get_method_list(name, &method_list, true);
- method_list.sort();
-
- for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
-
- if (E->get().name == "" || (E->get().name[0] == '_' && !(E->get().flags & METHOD_FLAG_VIRTUAL)))
- continue; //hidden, don't count
-
- if (skip_setter_getter_methods && setters_getters.has(E->get().name)) {
- // Don't skip parametric setters and getters, i.e. method which require
- // one or more parameters to define what property should be set or retrieved.
- // E.g. CPUParticles::set_param(Parameter param, float value).
- if (E->get().arguments.size() == 0 /* getter */ || (E->get().arguments.size() == 1 && E->get().return_val.type == Variant::NIL /* setter */)) {
- continue;
- }
- }
-
- MethodDoc method;
-
- method.name = E->get().name;
-
- if (E->get().flags & METHOD_FLAG_VIRTUAL)
- method.qualifiers = "virtual";
-
- if (E->get().flags & METHOD_FLAG_CONST) {
- if (method.qualifiers != "")
- method.qualifiers += " ";
- method.qualifiers += "const";
- } else if (E->get().flags & METHOD_FLAG_VARARG) {
- if (method.qualifiers != "")
- method.qualifiers += " ";
- method.qualifiers += "vararg";
- }
-
- for (int i = -1; i < E->get().arguments.size(); i++) {
-
- if (i == -1) {
-#ifdef DEBUG_METHODS_ENABLED
- return_doc_from_retinfo(method, E->get().return_val);
-#endif
- } else {
-
- const PropertyInfo &arginfo = E->get().arguments[i];
- ArgumentDoc argument;
- argument_doc_from_arginfo(argument, arginfo);
-
- int darg_idx = i - (E->get().arguments.size() - E->get().default_arguments.size());
- if (darg_idx >= 0) {
- Variant default_arg = E->get().default_arguments[darg_idx];
- argument.default_value = default_arg.get_construct_string();
- }
-
- method.arguments.push_back(argument);
- }
- }
-
- c.methods.push_back(method);
- }
-
- List<MethodInfo> signal_list;
- ClassDB::get_signal_list(name, &signal_list, true);
-
- if (signal_list.size()) {
-
- for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
-
- MethodDoc signal;
- signal.name = EV->get().name;
- for (int i = 0; i < EV->get().arguments.size(); i++) {
-
- const PropertyInfo &arginfo = EV->get().arguments[i];
- ArgumentDoc argument;
- argument_doc_from_arginfo(argument, arginfo);
-
- signal.arguments.push_back(argument);
- }
-
- c.signals.push_back(signal);
- }
- }
-
- List<String> constant_list;
- ClassDB::get_integer_constant_list(name, &constant_list, true);
-
- for (List<String>::Element *E = constant_list.front(); E; E = E->next()) {
-
- ConstantDoc constant;
- constant.name = E->get();
- constant.value = itos(ClassDB::get_integer_constant(name, E->get()));
- constant.enumeration = ClassDB::get_integer_constant_enum(name, E->get());
- c.constants.push_back(constant);
- }
-
- //theme stuff
-
- {
- List<StringName> l;
- Theme::get_default()->get_constant_list(cname, &l);
- for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
-
- PropertyDoc pd;
- pd.name = E->get();
- pd.type = "int";
- pd.default_value = itos(Theme::get_default()->get_constant(E->get(), cname));
- c.theme_properties.push_back(pd);
- }
-
- l.clear();
- Theme::get_default()->get_color_list(cname, &l);
- for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
-
- PropertyDoc pd;
- pd.name = E->get();
- pd.type = "Color";
- pd.default_value = Variant(Theme::get_default()->get_color(E->get(), cname)).get_construct_string();
- c.theme_properties.push_back(pd);
- }
-
- l.clear();
- Theme::get_default()->get_icon_list(cname, &l);
- for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
-
- PropertyDoc pd;
- pd.name = E->get();
- pd.type = "Texture2D";
- c.theme_properties.push_back(pd);
- }
- l.clear();
- Theme::get_default()->get_font_list(cname, &l);
- for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
-
- PropertyDoc pd;
- pd.name = E->get();
- pd.type = "Font";
- c.theme_properties.push_back(pd);
- }
- l.clear();
- Theme::get_default()->get_stylebox_list(cname, &l);
- for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
-
- PropertyDoc pd;
- pd.name = E->get();
- pd.type = "StyleBox";
- c.theme_properties.push_back(pd);
- }
- }
-
- classes.pop_front();
- }
-
- {
- // So we can document the concept of Variant even if it's not a usable class per se.
- class_list["Variant"] = ClassDoc();
- class_list["Variant"].name = "Variant";
- }
-
- if (!p_basic_types)
- return;
-
- // Add Variant types.
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i == Variant::NIL)
- continue; // Not exposed outside of 'null', should not be in class list.
- if (i == Variant::OBJECT)
- continue; // Use the core type instead.
-
- String cname = Variant::get_type_name(Variant::Type(i));
-
- class_list[cname] = ClassDoc();
- ClassDoc &c = class_list[cname];
- c.name = cname;
-
- Callable::CallError cerror;
- Variant v = Variant::construct(Variant::Type(i), NULL, 0, cerror);
-
- List<MethodInfo> method_list;
- v.get_method_list(&method_list);
- method_list.sort();
- Variant::get_constructor_list(Variant::Type(i), &method_list);
-
- for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
-
- MethodInfo &mi = E->get();
- MethodDoc method;
-
- method.name = mi.name;
-
- for (int j = 0; j < mi.arguments.size(); j++) {
-
- PropertyInfo arginfo = mi.arguments[j];
- ArgumentDoc ad;
- argument_doc_from_arginfo(ad, mi.arguments[j]);
- ad.name = arginfo.name;
-
- int darg_idx = mi.default_arguments.size() - mi.arguments.size() + j;
- if (darg_idx >= 0) {
- Variant default_arg = mi.default_arguments[darg_idx];
- ad.default_value = default_arg.get_construct_string();
- }
-
- method.arguments.push_back(ad);
- }
-
- return_doc_from_retinfo(method, mi.return_val);
-
- if (mi.flags & METHOD_FLAG_VARARG) {
- if (method.qualifiers != "")
- method.qualifiers += " ";
- method.qualifiers += "vararg";
- }
-
- c.methods.push_back(method);
- }
-
- List<PropertyInfo> properties;
- v.get_property_list(&properties);
- for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
-
- PropertyInfo pi = E->get();
- PropertyDoc property;
- property.name = pi.name;
- property.type = Variant::get_type_name(pi.type);
- property.default_value = v.get(pi.name).get_construct_string();
-
- c.properties.push_back(property);
- }
-
- List<StringName> constants;
- Variant::get_constants_for_type(Variant::Type(i), &constants);
-
- for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
-
- ConstantDoc constant;
- constant.name = E->get();
- Variant value = Variant::get_constant_value(Variant::Type(i), E->get());
- constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string();
- c.constants.push_back(constant);
- }
- }
-
- //built in constants and functions
-
- {
-
- String cname = "@GlobalScope";
- class_list[cname] = ClassDoc();
- ClassDoc &c = class_list[cname];
- c.name = cname;
-
- for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
-
- ConstantDoc cd;
- cd.name = GlobalConstants::get_global_constant_name(i);
- cd.value = itos(GlobalConstants::get_global_constant_value(i));
- cd.enumeration = GlobalConstants::get_global_constant_enum(i);
- c.constants.push_back(cd);
- }
-
- List<Engine::Singleton> singletons;
- Engine::get_singleton()->get_singletons(&singletons);
-
- //servers (this is kind of hackish)
- for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
-
- PropertyDoc pd;
- Engine::Singleton &s = E->get();
- if (!s.ptr) {
- continue;
- }
- pd.name = s.name;
- pd.type = s.ptr->get_class();
- while (String(ClassDB::get_parent_class(pd.type)) != "Object")
- pd.type = ClassDB::get_parent_class(pd.type);
- if (pd.type.begins_with("_"))
- pd.type = pd.type.substr(1, pd.type.length());
- c.properties.push_back(pd);
- }
- }
-
- //built in script reference
-
- {
-
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
-
- ScriptLanguage *lang = ScriptServer::get_language(i);
- String cname = "@" + lang->get_name();
- class_list[cname] = ClassDoc();
- ClassDoc &c = class_list[cname];
- c.name = cname;
-
- List<MethodInfo> minfo;
-
- lang->get_public_functions(&minfo);
-
- for (List<MethodInfo>::Element *E = minfo.front(); E; E = E->next()) {
-
- MethodInfo &mi = E->get();
- MethodDoc md;
- md.name = mi.name;
-
- if (mi.flags & METHOD_FLAG_VARARG) {
- if (md.qualifiers != "")
- md.qualifiers += " ";
- md.qualifiers += "vararg";
- }
-
- return_doc_from_retinfo(md, mi.return_val);
-
- for (int j = 0; j < mi.arguments.size(); j++) {
-
- ArgumentDoc ad;
- argument_doc_from_arginfo(ad, mi.arguments[j]);
-
- int darg_idx = j - (mi.arguments.size() - mi.default_arguments.size());
- if (darg_idx >= 0) {
- Variant default_arg = E->get().default_arguments[darg_idx];
- ad.default_value = default_arg.get_construct_string();
- }
-
- md.arguments.push_back(ad);
- }
-
- c.methods.push_back(md);
- }
-
- List<Pair<String, Variant> > cinfo;
- lang->get_public_constants(&cinfo);
-
- for (List<Pair<String, Variant> >::Element *E = cinfo.front(); E; E = E->next()) {
-
- ConstantDoc cd;
- cd.name = E->get().first;
- cd.value = E->get().second;
- c.constants.push_back(cd);
- }
- }
- }
-}
-
-static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &methods) {
-
- String section = parser->get_node_name();
- String element = section.substr(0, section.length() - 1);
-
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- if (parser->get_node_name() == element) {
-
- DocData::MethodDoc method;
- ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- method.name = parser->get_attribute_value("name");
- if (parser->has_attribute("qualifiers"))
- method.qualifiers = parser->get_attribute_value("qualifiers");
-
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name = parser->get_node_name();
- if (name == "return") {
-
- ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- method.return_type = parser->get_attribute_value("type");
- if (parser->has_attribute("enum")) {
- method.return_enum = parser->get_attribute_value("enum");
- }
- } else if (name == "argument") {
-
- DocData::ArgumentDoc argument;
- ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- argument.name = parser->get_attribute_value("name");
- ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- argument.type = parser->get_attribute_value("type");
- if (parser->has_attribute("enum")) {
- argument.enumeration = parser->get_attribute_value("enum");
- }
-
- method.arguments.push_back(argument);
-
- } else if (name == "description") {
-
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- method.description = parser->get_node_data();
- }
-
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == element)
- break;
- }
-
- methods.push_back(method);
-
- } else {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + ".");
- }
-
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section)
- break;
- }
-
- return OK;
-}
-
-Error DocData::load_classes(const String &p_dir) {
-
- Error err;
- DirAccessRef da = DirAccess::open(p_dir, &err);
- if (!da) {
- return err;
- }
-
- da->list_dir_begin();
- String path;
- path = da->get_next();
- while (path != String()) {
- if (!da->current_is_dir() && path.ends_with("xml")) {
- Ref<XMLParser> parser = memnew(XMLParser);
- Error err2 = parser->open(p_dir.plus_file(path));
- if (err2)
- return err2;
-
- _load(parser);
- }
- path = da->get_next();
- }
-
- da->list_dir_end();
-
- return OK;
-}
-Error DocData::erase_classes(const String &p_dir) {
-
- Error err;
- DirAccessRef da = DirAccess::open(p_dir, &err);
- if (!da) {
- return err;
- }
-
- List<String> to_erase;
-
- da->list_dir_begin();
- String path;
- path = da->get_next();
- while (path != String()) {
- if (!da->current_is_dir() && path.ends_with("xml")) {
- to_erase.push_back(path);
- }
- path = da->get_next();
- }
- da->list_dir_end();
-
- while (to_erase.size()) {
- da->remove(to_erase.front()->get());
- to_erase.pop_front();
- }
-
- return OK;
-}
-Error DocData::_load(Ref<XMLParser> parser) {
-
- Error err = OK;
-
- while ((err = parser->read()) == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "?xml") {
- parser->skip_section();
- }
-
- if (parser->get_node_type() != XMLParser::NODE_ELEMENT)
- continue; //no idea what this may be, but skipping anyway
-
- ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT);
-
- ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- String name = parser->get_attribute_value("name");
- class_list[name] = ClassDoc();
- ClassDoc &c = class_list[name];
-
- c.name = name;
- if (parser->has_attribute("inherits"))
- c.inherits = parser->get_attribute_value("inherits");
-
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name2 = parser->get_node_name();
-
- if (name2 == "brief_description") {
-
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.brief_description = parser->get_node_data();
-
- } else if (name2 == "description") {
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.description = parser->get_node_data();
- } else if (name2 == "tutorials") {
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name3 = parser->get_node_name();
-
- if (name3 == "link") {
-
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.tutorials.push_back(parser->get_node_data().strip_edges());
- } else {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
- }
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "tutorials")
- break; // End of <tutorials>.
- }
- } else if (name2 == "methods") {
-
- Error err2 = _parse_methods(parser, c.methods);
- ERR_FAIL_COND_V(err2, err2);
-
- } else if (name2 == "signals") {
-
- Error err2 = _parse_methods(parser, c.signals);
- ERR_FAIL_COND_V(err2, err2);
- } else if (name2 == "members") {
-
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name3 = parser->get_node_name();
-
- if (name3 == "member") {
-
- PropertyDoc prop2;
-
- ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- prop2.name = parser->get_attribute_value("name");
- ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- prop2.type = parser->get_attribute_value("type");
- if (parser->has_attribute("setter"))
- prop2.setter = parser->get_attribute_value("setter");
- if (parser->has_attribute("getter"))
- prop2.getter = parser->get_attribute_value("getter");
- if (parser->has_attribute("enum"))
- prop2.enumeration = parser->get_attribute_value("enum");
- if (!parser->is_empty()) {
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- prop2.description = parser->get_node_data();
- }
- c.properties.push_back(prop2);
- } else {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
- }
-
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "members")
- break; // End of <members>.
- }
-
- } else if (name2 == "theme_items") {
-
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name3 = parser->get_node_name();
-
- if (name3 == "theme_item") {
-
- PropertyDoc prop2;
-
- ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- prop2.name = parser->get_attribute_value("name");
- ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- prop2.type = parser->get_attribute_value("type");
- if (!parser->is_empty()) {
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- prop2.description = parser->get_node_data();
- }
- c.theme_properties.push_back(prop2);
- } else {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
- }
-
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "theme_items")
- break; // End of <theme_items>.
- }
-
- } else if (name2 == "constants") {
-
- while (parser->read() == OK) {
-
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-
- String name3 = parser->get_node_name();
-
- if (name3 == "constant") {
-
- ConstantDoc constant2;
- ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- constant2.name = parser->get_attribute_value("name");
- ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT);
- constant2.value = parser->get_attribute_value("value");
- if (parser->has_attribute("enum")) {
- constant2.enumeration = parser->get_attribute_value("enum");
- }
- if (!parser->is_empty()) {
- parser->read();
- if (parser->get_node_type() == XMLParser::NODE_TEXT)
- constant2.description = parser->get_node_data();
- }
- c.constants.push_back(constant2);
- } else {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
- }
-
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "constants")
- break; // End of <constants>.
- }
-
- } else {
-
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name2 + ".");
- }
-
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "class")
- break; // End of <class>.
- }
- }
-
- return OK;
-}
-
-static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) {
-
- if (p_string == "")
- return;
- String tab;
- for (int i = 0; i < p_tablevel; i++)
- tab += "\t";
- f->store_string(tab + p_string + "\n");
-}
-
-Error DocData::save_classes(const String &p_default_path, const Map<String, String> &p_class_path) {
-
- for (Map<String, ClassDoc>::Element *E = class_list.front(); E; E = E->next()) {
-
- ClassDoc &c = E->get();
-
- String save_path;
- if (p_class_path.has(c.name)) {
- save_path = p_class_path[c.name];
- } else {
- save_path = p_default_path;
- }
-
- Error err;
- String save_file = save_path.plus_file(c.name + ".xml");
- FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err);
-
- ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");
-
- _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
-
- String header = "<class name=\"" + c.name + "\"";
- if (c.inherits != "")
- header += " inherits=\"" + c.inherits + "\"";
- header += String(" version=\"") + VERSION_BRANCH + "\"";
- header += ">";
- _write_string(f, 0, header);
-
- _write_string(f, 1, "<brief_description>");
- _write_string(f, 2, c.brief_description.strip_edges().xml_escape());
- _write_string(f, 1, "</brief_description>");
-
- _write_string(f, 1, "<description>");
- _write_string(f, 2, c.description.strip_edges().xml_escape());
- _write_string(f, 1, "</description>");
-
- _write_string(f, 1, "<tutorials>");
- for (int i = 0; i < c.tutorials.size(); i++) {
- _write_string(f, 2, "<link>" + c.tutorials.get(i).xml_escape() + "</link>");
- }
- _write_string(f, 1, "</tutorials>");
-
- _write_string(f, 1, "<methods>");
-
- c.methods.sort();
-
- for (int i = 0; i < c.methods.size(); i++) {
-
- const MethodDoc &m = c.methods[i];
-
- String qualifiers;
- if (m.qualifiers != "")
- qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\"";
-
- _write_string(f, 2, "<method name=\"" + m.name + "\"" + qualifiers + ">");
-
- if (m.return_type != "") {
-
- String enum_text;
- if (m.return_enum != String()) {
- enum_text = " enum=\"" + m.return_enum + "\"";
- }
- _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + ">");
- _write_string(f, 3, "</return>");
- }
-
- for (int j = 0; j < m.arguments.size(); j++) {
-
- const ArgumentDoc &a = m.arguments[j];
-
- String enum_text;
- if (a.enumeration != String()) {
- enum_text = " enum=\"" + a.enumeration + "\"";
- }
-
- if (a.default_value != "")
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\">");
- else
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + ">");
-
- _write_string(f, 3, "</argument>");
- }
-
- _write_string(f, 3, "<description>");
- _write_string(f, 4, m.description.strip_edges().xml_escape());
- _write_string(f, 3, "</description>");
-
- _write_string(f, 2, "</method>");
- }
-
- _write_string(f, 1, "</methods>");
-
- if (c.properties.size()) {
- _write_string(f, 1, "<members>");
-
- c.properties.sort();
-
- for (int i = 0; i < c.properties.size(); i++) {
-
- String additional_attributes;
- if (c.properties[i].enumeration != String()) {
- additional_attributes += " enum=\"" + c.properties[i].enumeration + "\"";
- }
- if (c.properties[i].default_value != String()) {
- additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
- }
-
- const PropertyDoc &p = c.properties[i];
-
- if (c.properties[i].overridden) {
- _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\" override=\"true\"" + additional_attributes + " />");
- } else {
- _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\"" + additional_attributes + ">");
- _write_string(f, 3, p.description.strip_edges().xml_escape());
- _write_string(f, 2, "</member>");
- }
- }
- _write_string(f, 1, "</members>");
- }
-
- if (c.signals.size()) {
-
- c.signals.sort();
-
- _write_string(f, 1, "<signals>");
- for (int i = 0; i < c.signals.size(); i++) {
-
- const MethodDoc &m = c.signals[i];
- _write_string(f, 2, "<signal name=\"" + m.name + "\">");
- for (int j = 0; j < m.arguments.size(); j++) {
-
- const ArgumentDoc &a = m.arguments[j];
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\">");
- _write_string(f, 3, "</argument>");
- }
-
- _write_string(f, 3, "<description>");
- _write_string(f, 4, m.description.strip_edges().xml_escape());
- _write_string(f, 3, "</description>");
-
- _write_string(f, 2, "</signal>");
- }
-
- _write_string(f, 1, "</signals>");
- }
-
- _write_string(f, 1, "<constants>");
-
- for (int i = 0; i < c.constants.size(); i++) {
-
- const ConstantDoc &k = c.constants[i];
- if (k.enumeration != String()) {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">");
- } else {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">");
- }
- _write_string(f, 3, k.description.strip_edges().xml_escape());
- _write_string(f, 2, "</constant>");
- }
-
- _write_string(f, 1, "</constants>");
-
- if (c.theme_properties.size()) {
-
- c.theme_properties.sort();
-
- _write_string(f, 1, "<theme_items>");
- for (int i = 0; i < c.theme_properties.size(); i++) {
-
- const PropertyDoc &p = c.theme_properties[i];
-
- if (p.default_value != "")
- _write_string(f, 2, "<theme_item name=\"" + p.name + "\" type=\"" + p.type + "\" default=\"" + p.default_value.xml_escape(true) + "\">");
- else
- _write_string(f, 2, "<theme_item name=\"" + p.name + "\" type=\"" + p.type + "\">");
-
- _write_string(f, 3, p.description.strip_edges().xml_escape());
-
- _write_string(f, 2, "</theme_item>");
- }
- _write_string(f, 1, "</theme_items>");
- }
-
- _write_string(f, 0, "</class>");
- }
-
- return OK;
-}
-
-Error DocData::load_compressed(const uint8_t *p_data, int p_compressed_size, int p_uncompressed_size) {
-
- Vector<uint8_t> data;
- data.resize(p_uncompressed_size);
- Compression::decompress(data.ptrw(), p_uncompressed_size, p_data, p_compressed_size, Compression::MODE_DEFLATE);
- class_list.clear();
-
- Ref<XMLParser> parser = memnew(XMLParser);
- Error err = parser->open_buffer(data);
- if (err)
- return err;
-
- _load(parser);
-
- return OK;
-}
diff --git a/editor/doc/doc_dump.cpp b/editor/doc/doc_dump.cpp
deleted file mode 100644
index b0a89ff4b8..0000000000
--- a/editor/doc/doc_dump.cpp
+++ /dev/null
@@ -1,308 +0,0 @@
-/*************************************************************************/
-/* doc_dump.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "doc_dump.h"
-
-#include "core/os/file_access.h"
-#include "core/version.h"
-#include "scene/main/node.h"
-
-static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) {
-
- String tab;
- for (int i = 0; i < p_tablevel; i++)
- tab += "\t";
- f->store_string(tab + p_string + "\n");
-}
-
-struct _ConstantSort {
-
- String name;
- int value;
- bool operator<(const _ConstantSort &p_c) const {
-
- String left_a = name.find("_") == -1 ? name : name.substr(0, name.find("_"));
- String left_b = p_c.name.find("_") == -1 ? p_c.name : p_c.name.substr(0, p_c.name.find("_"));
- if (left_a == left_b)
- return value < p_c.value;
- else
- return left_a < left_b;
- }
-};
-
-static String _escape_string(const String &p_str) {
-
- String ret = p_str;
- ret = ret.replace("&", "&amp;");
- ret = ret.replace("<", "&gt;");
- ret = ret.replace(">", "&lt;");
- ret = ret.replace("'", "&apos;");
- ret = ret.replace("\"", "&quot;");
- for (char i = 1; i < 32; i++) {
-
- char chr[2] = { i, 0 };
- ret = ret.replace(chr, "&#" + String::num(i) + ";");
- }
- ret = ret.utf8();
- return ret;
-}
-void DocDump::dump(const String &p_file) {
-
- List<StringName> class_list;
- ClassDB::get_class_list(&class_list);
-
- class_list.sort_custom<StringName::AlphCompare>();
-
- FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE);
-
- _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
- _write_string(f, 0, String("<doc version=\"") + VERSION_BRANCH + "\" name=\"Engine Types\">");
-
- while (class_list.size()) {
-
- String name = class_list.front()->get();
-
- String header = "<class name=\"" + name + "\"";
- String inherits = ClassDB::get_parent_class(name);
- if (inherits != "")
- header += " inherits=\"" + inherits + "\"";
- _write_string(f, 0, header);
-
- _write_string(f, 1, "<brief_description>");
- _write_string(f, 1, "</brief_description>");
-
- _write_string(f, 1, "<description>");
- _write_string(f, 1, "</description>");
-
- _write_string(f, 1, "<methods>");
-
- List<MethodInfo> method_list;
- ClassDB::get_method_list(name, &method_list, true);
- method_list.sort();
-
- for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
- if (E->get().name == "" || E->get().name[0] == '_')
- continue; //hidden
-
- MethodBind *m = ClassDB::get_method(name, E->get().name);
-
- String qualifiers;
- if (E->get().flags & METHOD_FLAG_CONST)
- qualifiers += "qualifiers=\"const\"";
-
- _write_string(f, 2, "<method name=\"" + _escape_string(E->get().name) + "\" " + qualifiers + " >");
-
- for (int i = -1; i < E->get().arguments.size(); i++) {
-
- PropertyInfo arginfo;
-
- if (i == -1) {
-
- arginfo = E->get().return_val;
- String type_name = (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) ? arginfo.hint_string : Variant::get_type_name(arginfo.type);
-
- if (arginfo.type == Variant::NIL)
- continue;
- _write_string(f, 3, "<return type=\"" + type_name + "\">");
- } else {
-
- arginfo = E->get().arguments[i];
-
- String type_name;
-
- if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE)
- type_name = arginfo.hint_string;
- else if (arginfo.type == Variant::NIL)
- type_name = "Variant";
- else
- type_name = Variant::get_type_name(arginfo.type);
-
- if (m && m->has_default_argument(i)) {
- Variant default_arg = m->get_default_argument(i);
- String default_arg_text = String(_escape_string(m->get_default_argument(i)));
-
- switch (default_arg.get_type()) {
-
- case Variant::NIL:
- default_arg_text = "NULL";
- break;
- // atomic types
- case Variant::BOOL:
- if (bool(default_arg))
- default_arg_text = "true";
- else
- default_arg_text = "false";
- break;
- case Variant::INT:
- case Variant::FLOAT:
- //keep it
- break;
- case Variant::STRING:
- case Variant::STRING_NAME:
- default_arg_text = "@\"" + default_arg_text + "\"";
- break;
- case Variant::NODE_PATH:
- default_arg_text = "\"" + default_arg_text + "\"";
- break;
- case Variant::TRANSFORM:
- if (default_arg.operator Transform() == Transform()) {
- default_arg_text = "";
- }
-
- default_arg_text = Variant::get_type_name(default_arg.get_type()) + "(" + default_arg_text + ")";
- break;
-
- case Variant::VECTOR2:
- case Variant::RECT2:
- case Variant::VECTOR3:
- case Variant::PLANE:
- case Variant::QUAT:
- case Variant::AABB:
- case Variant::BASIS:
- case Variant::COLOR:
- case Variant::PACKED_BYTE_ARRAY:
- case Variant::PACKED_INT32_ARRAY:
- case Variant::PACKED_FLOAT32_ARRAY:
- case Variant::PACKED_INT64_ARRAY:
- case Variant::PACKED_FLOAT64_ARRAY:
- case Variant::PACKED_STRING_ARRAY:
- case Variant::PACKED_VECTOR3_ARRAY:
- case Variant::PACKED_COLOR_ARRAY:
- default_arg_text = Variant::get_type_name(default_arg.get_type()) + "(" + default_arg_text + ")";
- break;
- case Variant::OBJECT:
- case Variant::DICTIONARY:
- case Variant::ARRAY:
- case Variant::_RID:
-
- default: {
- }
- }
-
- _write_string(f, 3, "<argument index=\"" + itos(i) + "\" name=\"" + _escape_string(arginfo.name) + "\" type=\"" + type_name + "\" default=\"" + _escape_string(default_arg_text) + "\">");
- } else
- _write_string(f, 3, "<argument index=\"" + itos(i) + "\" name=\"" + arginfo.name + "\" type=\"" + type_name + "\">");
- }
-
- String hint;
- switch (arginfo.hint) {
- case PROPERTY_HINT_DIR: hint = "A directory."; break;
- case PROPERTY_HINT_RANGE: hint = "Range - min: " + arginfo.hint_string.get_slice(",", 0) + " max: " + arginfo.hint_string.get_slice(",", 1) + " step: " + arginfo.hint_string.get_slice(",", 2); break;
- case PROPERTY_HINT_ENUM:
- hint = "Values: ";
- for (int j = 0; j < arginfo.hint_string.get_slice_count(","); j++) {
- if (j > 0) hint += ", ";
- hint += arginfo.hint_string.get_slice(",", j) + "=" + itos(j);
- }
- break;
- case PROPERTY_HINT_LENGTH: hint = "Length: " + arginfo.hint_string; break;
- case PROPERTY_HINT_FLAGS:
- hint = "Values: ";
- for (int j = 0; j < arginfo.hint_string.get_slice_count(","); j++) {
- if (j > 0) hint += ", ";
- hint += arginfo.hint_string.get_slice(",", j) + "=" + itos((uint64_t)1 << j);
- }
- break;
- case PROPERTY_HINT_FILE: hint = "A file:"; break;
- default: {
- }
- //case PROPERTY_HINT_RESOURCE_TYPE: hint="Type: "+arginfo.hint_string; break;
- };
- if (hint != "")
- _write_string(f, 4, hint);
-
- _write_string(f, 3, (i == -1) ? "</return>" : "</argument>");
- }
-
- _write_string(f, 3, "<description>");
- _write_string(f, 3, "</description>");
-
- _write_string(f, 2, "</method>");
- }
-
- _write_string(f, 1, "</methods>");
-
- List<MethodInfo> signal_list;
- ClassDB::get_signal_list(name, &signal_list, true);
-
- if (signal_list.size()) {
-
- _write_string(f, 1, "<signals>");
- for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
-
- _write_string(f, 2, "<signal name=\"" + EV->get().name + "\">");
- for (int i = 0; i < EV->get().arguments.size(); i++) {
- PropertyInfo arginfo = EV->get().arguments[i];
- _write_string(f, 3, "<argument index=\"" + itos(i) + "\" name=\"" + arginfo.name + "\" type=\"" + Variant::get_type_name(arginfo.type) + "\">");
- _write_string(f, 3, "</argument>");
- }
- _write_string(f, 3, "<description>");
- _write_string(f, 3, "</description>");
-
- _write_string(f, 2, "</signal>");
- }
-
- _write_string(f, 1, "</signals>");
- }
-
- _write_string(f, 1, "<constants>");
-
- List<String> constant_list;
- ClassDB::get_integer_constant_list(name, &constant_list, true);
-
- /* constants are sorted in a special way */
-
- List<_ConstantSort> constant_sort;
-
- for (List<String>::Element *E = constant_list.front(); E; E = E->next()) {
- _ConstantSort cs;
- cs.name = E->get();
- cs.value = ClassDB::get_integer_constant(name, E->get());
- constant_sort.push_back(cs);
- }
-
- constant_sort.sort();
-
- for (List<_ConstantSort>::Element *E = constant_sort.front(); E; E = E->next()) {
-
- _write_string(f, 2, "<constant name=\"" + E->get().name + "\" value=\"" + itos(E->get().value) + "\">");
- _write_string(f, 2, "</constant>");
- }
-
- _write_string(f, 1, "</constants>");
- _write_string(f, 0, "</class>");
-
- class_list.erase(name);
- }
-
- _write_string(f, 0, "</doc>");
- f->close();
- memdelete(f);
-}
diff --git a/editor/doc/doc_dump.h b/editor/doc/doc_dump.h
deleted file mode 100644
index f8f1b6f805..0000000000
--- a/editor/doc/doc_dump.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*************************************************************************/
-/* doc_dump.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 DOC_DUMP_H
-#define DOC_DUMP_H
-
-#include "core/class_db.h"
-
-class DocDump {
-public:
- static void dump(const String &p_file);
-};
-
-#endif // DOC_DUMP_H
diff --git a/editor/doc_data.cpp b/editor/doc_data.cpp
new file mode 100644
index 0000000000..096be1fe4b
--- /dev/null
+++ b/editor/doc_data.cpp
@@ -0,0 +1,1217 @@
+/*************************************************************************/
+/* doc_data.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "doc_data.h"
+
+#include "core/engine.h"
+#include "core/global_constants.h"
+#include "core/io/compression.h"
+#include "core/io/marshalls.h"
+#include "core/os/dir_access.h"
+#include "core/project_settings.h"
+#include "core/script_language.h"
+#include "core/version.h"
+#include "scene/resources/theme.h"
+
+void DocData::merge_from(const DocData &p_data) {
+
+ for (Map<String, ClassDoc>::Element *E = class_list.front(); E; E = E->next()) {
+
+ ClassDoc &c = E->get();
+
+ if (!p_data.class_list.has(c.name))
+ continue;
+
+ const ClassDoc &cf = p_data.class_list[c.name];
+
+ c.description = cf.description;
+ c.brief_description = cf.brief_description;
+ c.tutorials = cf.tutorials;
+
+ for (int i = 0; i < c.methods.size(); i++) {
+
+ MethodDoc &m = c.methods.write[i];
+
+ for (int j = 0; j < cf.methods.size(); j++) {
+
+ if (cf.methods[j].name != m.name)
+ continue;
+ if (cf.methods[j].arguments.size() != m.arguments.size())
+ continue;
+ // since polymorphic functions are allowed we need to check the type of
+ // the arguments so we make sure they are different.
+ int arg_count = cf.methods[j].arguments.size();
+ Vector<bool> arg_used;
+ arg_used.resize(arg_count);
+ for (int l = 0; l < arg_count; ++l)
+ arg_used.write[l] = false;
+ // also there is no guarantee that argument ordering will match, so we
+ // have to check one by one so we make sure we have an exact match
+ for (int k = 0; k < arg_count; ++k) {
+ for (int l = 0; l < arg_count; ++l)
+ if (cf.methods[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) {
+ arg_used.write[l] = true;
+ break;
+ }
+ }
+ bool not_the_same = false;
+ for (int l = 0; l < arg_count; ++l)
+ if (!arg_used[l]) // at least one of the arguments was different
+ not_the_same = true;
+ if (not_the_same)
+ continue;
+
+ const MethodDoc &mf = cf.methods[j];
+
+ m.description = mf.description;
+ break;
+ }
+ }
+
+ for (int i = 0; i < c.signals.size(); i++) {
+
+ MethodDoc &m = c.signals.write[i];
+
+ for (int j = 0; j < cf.signals.size(); j++) {
+
+ if (cf.signals[j].name != m.name)
+ continue;
+ const MethodDoc &mf = cf.signals[j];
+
+ m.description = mf.description;
+ break;
+ }
+ }
+
+ for (int i = 0; i < c.constants.size(); i++) {
+
+ ConstantDoc &m = c.constants.write[i];
+
+ for (int j = 0; j < cf.constants.size(); j++) {
+
+ if (cf.constants[j].name != m.name)
+ continue;
+ const ConstantDoc &mf = cf.constants[j];
+
+ m.description = mf.description;
+ break;
+ }
+ }
+
+ for (int i = 0; i < c.properties.size(); i++) {
+
+ PropertyDoc &p = c.properties.write[i];
+
+ for (int j = 0; j < cf.properties.size(); j++) {
+
+ if (cf.properties[j].name != p.name)
+ continue;
+ const PropertyDoc &pf = cf.properties[j];
+
+ p.description = pf.description;
+ break;
+ }
+ }
+
+ for (int i = 0; i < c.theme_properties.size(); i++) {
+
+ PropertyDoc &p = c.theme_properties.write[i];
+
+ for (int j = 0; j < cf.theme_properties.size(); j++) {
+
+ if (cf.theme_properties[j].name != p.name)
+ continue;
+ const PropertyDoc &pf = cf.theme_properties[j];
+
+ p.description = pf.description;
+ break;
+ }
+ }
+ }
+}
+
+void DocData::remove_from(const DocData &p_data) {
+ for (Map<String, ClassDoc>::Element *E = p_data.class_list.front(); E; E = E->next()) {
+ if (class_list.has(E->key()))
+ class_list.erase(E->key());
+ }
+}
+
+static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) {
+
+ if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ p_method.return_enum = p_retinfo.class_name;
+ if (p_method.return_enum.begins_with("_")) //proxy class
+ p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length());
+ p_method.return_type = "int";
+ } else if (p_retinfo.class_name != StringName()) {
+ p_method.return_type = p_retinfo.class_name;
+ } else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ p_method.return_type = p_retinfo.hint_string;
+ } else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
+ p_method.return_type = "Variant";
+ } else if (p_retinfo.type == Variant::NIL) {
+ p_method.return_type = "void";
+ } else {
+ p_method.return_type = Variant::get_type_name(p_retinfo.type);
+ }
+}
+
+static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) {
+
+ p_argument.name = p_arginfo.name;
+
+ if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ p_argument.enumeration = p_arginfo.class_name;
+ if (p_argument.enumeration.begins_with("_")) //proxy class
+ p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length());
+ p_argument.type = "int";
+ } else if (p_arginfo.class_name != StringName()) {
+ p_argument.type = p_arginfo.class_name;
+ } else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ p_argument.type = p_arginfo.hint_string;
+ } else if (p_arginfo.type == Variant::NIL) {
+ // Parameters cannot be void, so PROPERTY_USAGE_NIL_IS_VARIANT is not necessary
+ p_argument.type = "Variant";
+ } else {
+ p_argument.type = Variant::get_type_name(p_arginfo.type);
+ }
+}
+
+static Variant get_documentation_default_value(const StringName &p_class_name, const StringName &p_property_name, bool &r_default_value_valid) {
+
+ Variant default_value = Variant();
+ r_default_value_valid = false;
+
+ if (ClassDB::can_instance(p_class_name)) {
+ default_value = ClassDB::class_get_default_property_value(p_class_name, p_property_name, &r_default_value_valid);
+ } else {
+ // Cannot get default value of classes that can't be instanced
+ List<StringName> inheriting_classes;
+ ClassDB::get_direct_inheriters_from_class(p_class_name, &inheriting_classes);
+ for (List<StringName>::Element *E2 = inheriting_classes.front(); E2; E2 = E2->next()) {
+ if (ClassDB::can_instance(E2->get())) {
+ default_value = ClassDB::class_get_default_property_value(E2->get(), p_property_name, &r_default_value_valid);
+ if (r_default_value_valid)
+ break;
+ }
+ }
+ }
+
+ return default_value;
+}
+
+void DocData::generate(bool p_basic_types) {
+
+ List<StringName> classes;
+ ClassDB::get_class_list(&classes);
+ classes.sort_custom<StringName::AlphCompare>();
+ // Move ProjectSettings, so that other classes can register properties there.
+ classes.move_to_back(classes.find("ProjectSettings"));
+
+ bool skip_setter_getter_methods = true;
+
+ while (classes.size()) {
+
+ Set<StringName> setters_getters;
+
+ String name = classes.front()->get();
+ String cname = name;
+ if (cname.begins_with("_")) //proxy class
+ cname = cname.substr(1, name.length());
+
+ class_list[cname] = ClassDoc();
+ ClassDoc &c = class_list[cname];
+ c.name = cname;
+ c.inherits = ClassDB::get_parent_class(name);
+
+ List<PropertyInfo> properties;
+ List<PropertyInfo> own_properties;
+ if (name == "ProjectSettings") {
+ //special case for project settings, so settings can be documented
+ ProjectSettings::get_singleton()->get_property_list(&properties);
+ own_properties = properties;
+ } else {
+ ClassDB::get_property_list(name, &properties);
+ ClassDB::get_property_list(name, &own_properties, true);
+ }
+
+ List<PropertyInfo>::Element *EO = own_properties.front();
+ for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ bool inherited = EO == nullptr;
+ if (EO && EO->get() == E->get()) {
+ inherited = false;
+ EO = EO->next();
+ }
+
+ if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_INTERNAL)
+ continue;
+
+ PropertyDoc prop;
+
+ prop.name = E->get().name;
+
+ prop.overridden = inherited;
+
+ bool default_value_valid = false;
+ Variant default_value;
+
+ if (name == "ProjectSettings") {
+ // Special case for project settings, so that settings are not taken from the current project's settings
+ if (E->get().name == "script" ||
+ ProjectSettings::get_singleton()->get_order(E->get().name) >= ProjectSettings::NO_BUILTIN_ORDER_BASE) {
+ continue;
+ }
+ if (E->get().usage & PROPERTY_USAGE_EDITOR) {
+ default_value = ProjectSettings::get_singleton()->property_get_revert(E->get().name);
+ default_value_valid = true;
+ }
+ } else {
+ default_value = get_documentation_default_value(name, E->get().name, default_value_valid);
+
+ if (inherited) {
+ bool base_default_value_valid = false;
+ Variant base_default_value = get_documentation_default_value(ClassDB::get_parent_class(name), E->get().name, base_default_value_valid);
+ if (!default_value_valid || !base_default_value_valid || default_value == base_default_value)
+ continue;
+ }
+ }
+
+ //used to track uninitialized values using valgrind
+ //print_line("getting default value for " + String(name) + "." + String(E->get().name));
+ if (default_value_valid && default_value.get_type() != Variant::OBJECT) {
+ prop.default_value = default_value.get_construct_string().replace("\n", "");
+ }
+
+ StringName setter = ClassDB::get_property_setter(name, E->get().name);
+ StringName getter = ClassDB::get_property_getter(name, E->get().name);
+
+ prop.setter = setter;
+ prop.getter = getter;
+
+ bool found_type = false;
+ if (getter != StringName()) {
+ MethodBind *mb = ClassDB::get_method(name, getter);
+ if (mb) {
+ PropertyInfo retinfo = mb->get_return_info();
+
+ found_type = true;
+ if (retinfo.type == Variant::INT && retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ prop.enumeration = retinfo.class_name;
+ prop.type = "int";
+ } else if (retinfo.class_name != StringName()) {
+ prop.type = retinfo.class_name;
+ } else if (retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+
+ prop.type = retinfo.hint_string;
+ } else if (retinfo.type == Variant::NIL && retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
+
+ prop.type = "Variant";
+ } else if (retinfo.type == Variant::NIL) {
+ prop.type = "void";
+ } else {
+ prop.type = Variant::get_type_name(retinfo.type);
+ }
+ }
+
+ setters_getters.insert(getter);
+ }
+
+ if (setter != StringName()) {
+
+ setters_getters.insert(setter);
+ }
+
+ if (!found_type) {
+
+ if (E->get().type == Variant::OBJECT && E->get().hint == PROPERTY_HINT_RESOURCE_TYPE)
+ prop.type = E->get().hint_string;
+ else
+ prop.type = Variant::get_type_name(E->get().type);
+ }
+
+ c.properties.push_back(prop);
+ }
+
+ List<MethodInfo> method_list;
+ ClassDB::get_method_list(name, &method_list, true);
+ method_list.sort();
+
+ for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
+
+ if (E->get().name == "" || (E->get().name[0] == '_' && !(E->get().flags & METHOD_FLAG_VIRTUAL)))
+ continue; //hidden, don't count
+
+ if (skip_setter_getter_methods && setters_getters.has(E->get().name)) {
+ // Don't skip parametric setters and getters, i.e. method which require
+ // one or more parameters to define what property should be set or retrieved.
+ // E.g. CPUParticles3D::set_param(Parameter param, float value).
+ if (E->get().arguments.size() == 0 /* getter */ || (E->get().arguments.size() == 1 && E->get().return_val.type == Variant::NIL /* setter */)) {
+ continue;
+ }
+ }
+
+ MethodDoc method;
+
+ method.name = E->get().name;
+
+ if (E->get().flags & METHOD_FLAG_VIRTUAL)
+ method.qualifiers = "virtual";
+
+ if (E->get().flags & METHOD_FLAG_CONST) {
+ if (method.qualifiers != "")
+ method.qualifiers += " ";
+ method.qualifiers += "const";
+ } else if (E->get().flags & METHOD_FLAG_VARARG) {
+ if (method.qualifiers != "")
+ method.qualifiers += " ";
+ method.qualifiers += "vararg";
+ }
+
+ for (int i = -1; i < E->get().arguments.size(); i++) {
+
+ if (i == -1) {
+#ifdef DEBUG_METHODS_ENABLED
+ return_doc_from_retinfo(method, E->get().return_val);
+#endif
+ } else {
+
+ const PropertyInfo &arginfo = E->get().arguments[i];
+ ArgumentDoc argument;
+ argument_doc_from_arginfo(argument, arginfo);
+
+ int darg_idx = i - (E->get().arguments.size() - E->get().default_arguments.size());
+ if (darg_idx >= 0) {
+ Variant default_arg = E->get().default_arguments[darg_idx];
+ argument.default_value = default_arg.get_construct_string();
+ }
+
+ method.arguments.push_back(argument);
+ }
+ }
+
+ c.methods.push_back(method);
+ }
+
+ List<MethodInfo> signal_list;
+ ClassDB::get_signal_list(name, &signal_list, true);
+
+ if (signal_list.size()) {
+
+ for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
+
+ MethodDoc signal;
+ signal.name = EV->get().name;
+ for (int i = 0; i < EV->get().arguments.size(); i++) {
+
+ const PropertyInfo &arginfo = EV->get().arguments[i];
+ ArgumentDoc argument;
+ argument_doc_from_arginfo(argument, arginfo);
+
+ signal.arguments.push_back(argument);
+ }
+
+ c.signals.push_back(signal);
+ }
+ }
+
+ List<String> constant_list;
+ ClassDB::get_integer_constant_list(name, &constant_list, true);
+
+ for (List<String>::Element *E = constant_list.front(); E; E = E->next()) {
+
+ ConstantDoc constant;
+ constant.name = E->get();
+ constant.value = itos(ClassDB::get_integer_constant(name, E->get()));
+ constant.enumeration = ClassDB::get_integer_constant_enum(name, E->get());
+ c.constants.push_back(constant);
+ }
+
+ //theme stuff
+
+ {
+ List<StringName> l;
+ Theme::get_default()->get_constant_list(cname, &l);
+ for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
+
+ PropertyDoc pd;
+ pd.name = E->get();
+ pd.type = "int";
+ pd.default_value = itos(Theme::get_default()->get_constant(E->get(), cname));
+ c.theme_properties.push_back(pd);
+ }
+
+ l.clear();
+ Theme::get_default()->get_color_list(cname, &l);
+ for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
+
+ PropertyDoc pd;
+ pd.name = E->get();
+ pd.type = "Color";
+ pd.default_value = Variant(Theme::get_default()->get_color(E->get(), cname)).get_construct_string();
+ c.theme_properties.push_back(pd);
+ }
+
+ l.clear();
+ Theme::get_default()->get_icon_list(cname, &l);
+ for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
+
+ PropertyDoc pd;
+ pd.name = E->get();
+ pd.type = "Texture2D";
+ c.theme_properties.push_back(pd);
+ }
+ l.clear();
+ Theme::get_default()->get_font_list(cname, &l);
+ for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
+
+ PropertyDoc pd;
+ pd.name = E->get();
+ pd.type = "Font";
+ c.theme_properties.push_back(pd);
+ }
+ l.clear();
+ Theme::get_default()->get_stylebox_list(cname, &l);
+ for (List<StringName>::Element *E = l.front(); E; E = E->next()) {
+
+ PropertyDoc pd;
+ pd.name = E->get();
+ pd.type = "StyleBox";
+ c.theme_properties.push_back(pd);
+ }
+ }
+
+ classes.pop_front();
+ }
+
+ {
+ // So we can document the concept of Variant even if it's not a usable class per se.
+ class_list["Variant"] = ClassDoc();
+ class_list["Variant"].name = "Variant";
+ }
+
+ if (!p_basic_types)
+ return;
+
+ // Add Variant types.
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i == Variant::NIL)
+ continue; // Not exposed outside of 'null', should not be in class list.
+ if (i == Variant::OBJECT)
+ continue; // Use the core type instead.
+
+ String cname = Variant::get_type_name(Variant::Type(i));
+
+ class_list[cname] = ClassDoc();
+ ClassDoc &c = class_list[cname];
+ c.name = cname;
+
+ Callable::CallError cerror;
+ Variant v = Variant::construct(Variant::Type(i), nullptr, 0, cerror);
+
+ List<MethodInfo> method_list;
+ v.get_method_list(&method_list);
+ method_list.sort();
+ Variant::get_constructor_list(Variant::Type(i), &method_list);
+
+ for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
+
+ MethodInfo &mi = E->get();
+ MethodDoc method;
+
+ method.name = mi.name;
+
+ for (int j = 0; j < mi.arguments.size(); j++) {
+
+ PropertyInfo arginfo = mi.arguments[j];
+ ArgumentDoc ad;
+ argument_doc_from_arginfo(ad, mi.arguments[j]);
+ ad.name = arginfo.name;
+
+ int darg_idx = mi.default_arguments.size() - mi.arguments.size() + j;
+ if (darg_idx >= 0) {
+ Variant default_arg = mi.default_arguments[darg_idx];
+ ad.default_value = default_arg.get_construct_string();
+ }
+
+ method.arguments.push_back(ad);
+ }
+
+ return_doc_from_retinfo(method, mi.return_val);
+
+ if (mi.flags & METHOD_FLAG_VARARG) {
+ if (method.qualifiers != "")
+ method.qualifiers += " ";
+ method.qualifiers += "vararg";
+ }
+
+ c.methods.push_back(method);
+ }
+
+ List<PropertyInfo> properties;
+ v.get_property_list(&properties);
+ for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+
+ PropertyInfo pi = E->get();
+ PropertyDoc property;
+ property.name = pi.name;
+ property.type = Variant::get_type_name(pi.type);
+ property.default_value = v.get(pi.name).get_construct_string();
+
+ c.properties.push_back(property);
+ }
+
+ List<StringName> constants;
+ Variant::get_constants_for_type(Variant::Type(i), &constants);
+
+ for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+
+ ConstantDoc constant;
+ constant.name = E->get();
+ Variant value = Variant::get_constant_value(Variant::Type(i), E->get());
+ constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string();
+ c.constants.push_back(constant);
+ }
+ }
+
+ //built in constants and functions
+
+ {
+
+ String cname = "@GlobalScope";
+ class_list[cname] = ClassDoc();
+ ClassDoc &c = class_list[cname];
+ c.name = cname;
+
+ for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
+
+ ConstantDoc cd;
+ cd.name = GlobalConstants::get_global_constant_name(i);
+ cd.value = itos(GlobalConstants::get_global_constant_value(i));
+ cd.enumeration = GlobalConstants::get_global_constant_enum(i);
+ c.constants.push_back(cd);
+ }
+
+ List<Engine::Singleton> singletons;
+ Engine::get_singleton()->get_singletons(&singletons);
+
+ //servers (this is kind of hackish)
+ for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
+
+ PropertyDoc pd;
+ Engine::Singleton &s = E->get();
+ if (!s.ptr) {
+ continue;
+ }
+ pd.name = s.name;
+ pd.type = s.ptr->get_class();
+ while (String(ClassDB::get_parent_class(pd.type)) != "Object")
+ pd.type = ClassDB::get_parent_class(pd.type);
+ if (pd.type.begins_with("_"))
+ pd.type = pd.type.substr(1, pd.type.length());
+ c.properties.push_back(pd);
+ }
+ }
+
+ //built in script reference
+
+ {
+
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+
+ ScriptLanguage *lang = ScriptServer::get_language(i);
+ String cname = "@" + lang->get_name();
+ class_list[cname] = ClassDoc();
+ ClassDoc &c = class_list[cname];
+ c.name = cname;
+
+ List<MethodInfo> minfo;
+
+ lang->get_public_functions(&minfo);
+
+ for (List<MethodInfo>::Element *E = minfo.front(); E; E = E->next()) {
+
+ MethodInfo &mi = E->get();
+ MethodDoc md;
+ md.name = mi.name;
+
+ if (mi.flags & METHOD_FLAG_VARARG) {
+ if (md.qualifiers != "")
+ md.qualifiers += " ";
+ md.qualifiers += "vararg";
+ }
+
+ return_doc_from_retinfo(md, mi.return_val);
+
+ for (int j = 0; j < mi.arguments.size(); j++) {
+
+ ArgumentDoc ad;
+ argument_doc_from_arginfo(ad, mi.arguments[j]);
+
+ int darg_idx = j - (mi.arguments.size() - mi.default_arguments.size());
+ if (darg_idx >= 0) {
+ Variant default_arg = E->get().default_arguments[darg_idx];
+ ad.default_value = default_arg.get_construct_string();
+ }
+
+ md.arguments.push_back(ad);
+ }
+
+ c.methods.push_back(md);
+ }
+
+ List<Pair<String, Variant>> cinfo;
+ lang->get_public_constants(&cinfo);
+
+ for (List<Pair<String, Variant>>::Element *E = cinfo.front(); E; E = E->next()) {
+
+ ConstantDoc cd;
+ cd.name = E->get().first;
+ cd.value = E->get().second;
+ c.constants.push_back(cd);
+ }
+ }
+ }
+}
+
+static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &methods) {
+
+ String section = parser->get_node_name();
+ String element = section.substr(0, section.length() - 1);
+
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser->get_node_name() == element) {
+
+ DocData::MethodDoc method;
+ ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
+ method.name = parser->get_attribute_value("name");
+ if (parser->has_attribute("qualifiers"))
+ method.qualifiers = parser->get_attribute_value("qualifiers");
+
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser->get_node_name();
+ if (name == "return") {
+
+ ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
+ method.return_type = parser->get_attribute_value("type");
+ if (parser->has_attribute("enum")) {
+ method.return_enum = parser->get_attribute_value("enum");
+ }
+ } else if (name == "argument") {
+
+ DocData::ArgumentDoc argument;
+ ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
+ argument.name = parser->get_attribute_value("name");
+ ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
+ argument.type = parser->get_attribute_value("type");
+ if (parser->has_attribute("enum")) {
+ argument.enumeration = parser->get_attribute_value("enum");
+ }
+
+ method.arguments.push_back(argument);
+
+ } else if (name == "description") {
+
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ method.description = parser->get_node_data();
+ }
+
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == element)
+ break;
+ }
+
+ methods.push_back(method);
+
+ } else {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + ".");
+ }
+
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section)
+ break;
+ }
+
+ return OK;
+}
+
+Error DocData::load_classes(const String &p_dir) {
+
+ Error err;
+ DirAccessRef da = DirAccess::open(p_dir, &err);
+ if (!da) {
+ return err;
+ }
+
+ da->list_dir_begin();
+ String path;
+ path = da->get_next();
+ while (path != String()) {
+ if (!da->current_is_dir() && path.ends_with("xml")) {
+ Ref<XMLParser> parser = memnew(XMLParser);
+ Error err2 = parser->open(p_dir.plus_file(path));
+ if (err2)
+ return err2;
+
+ _load(parser);
+ }
+ path = da->get_next();
+ }
+
+ da->list_dir_end();
+
+ return OK;
+}
+Error DocData::erase_classes(const String &p_dir) {
+
+ Error err;
+ DirAccessRef da = DirAccess::open(p_dir, &err);
+ if (!da) {
+ return err;
+ }
+
+ List<String> to_erase;
+
+ da->list_dir_begin();
+ String path;
+ path = da->get_next();
+ while (path != String()) {
+ if (!da->current_is_dir() && path.ends_with("xml")) {
+ to_erase.push_back(path);
+ }
+ path = da->get_next();
+ }
+ da->list_dir_end();
+
+ while (to_erase.size()) {
+ da->remove(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ return OK;
+}
+Error DocData::_load(Ref<XMLParser> parser) {
+
+ Error err = OK;
+
+ while ((err = parser->read()) == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "?xml") {
+ parser->skip_section();
+ }
+
+ if (parser->get_node_type() != XMLParser::NODE_ELEMENT)
+ continue; //no idea what this may be, but skipping anyway
+
+ ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT);
+
+ ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
+ String name = parser->get_attribute_value("name");
+ class_list[name] = ClassDoc();
+ ClassDoc &c = class_list[name];
+
+ c.name = name;
+ if (parser->has_attribute("inherits"))
+ c.inherits = parser->get_attribute_value("inherits");
+
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name2 = parser->get_node_name();
+
+ if (name2 == "brief_description") {
+
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ c.brief_description = parser->get_node_data();
+
+ } else if (name2 == "description") {
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ c.description = parser->get_node_data();
+ } else if (name2 == "tutorials") {
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name3 = parser->get_node_name();
+
+ if (name3 == "link") {
+
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ c.tutorials.push_back(parser->get_node_data().strip_edges());
+ } else {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
+ }
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "tutorials")
+ break; // End of <tutorials>.
+ }
+ } else if (name2 == "methods") {
+
+ Error err2 = _parse_methods(parser, c.methods);
+ ERR_FAIL_COND_V(err2, err2);
+
+ } else if (name2 == "signals") {
+
+ Error err2 = _parse_methods(parser, c.signals);
+ ERR_FAIL_COND_V(err2, err2);
+ } else if (name2 == "members") {
+
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name3 = parser->get_node_name();
+
+ if (name3 == "member") {
+
+ PropertyDoc prop2;
+
+ ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
+ prop2.name = parser->get_attribute_value("name");
+ ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
+ prop2.type = parser->get_attribute_value("type");
+ if (parser->has_attribute("setter"))
+ prop2.setter = parser->get_attribute_value("setter");
+ if (parser->has_attribute("getter"))
+ prop2.getter = parser->get_attribute_value("getter");
+ if (parser->has_attribute("enum"))
+ prop2.enumeration = parser->get_attribute_value("enum");
+ if (!parser->is_empty()) {
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ prop2.description = parser->get_node_data();
+ }
+ c.properties.push_back(prop2);
+ } else {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
+ }
+
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "members")
+ break; // End of <members>.
+ }
+
+ } else if (name2 == "theme_items") {
+
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name3 = parser->get_node_name();
+
+ if (name3 == "theme_item") {
+
+ PropertyDoc prop2;
+
+ ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
+ prop2.name = parser->get_attribute_value("name");
+ ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
+ prop2.type = parser->get_attribute_value("type");
+ if (!parser->is_empty()) {
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ prop2.description = parser->get_node_data();
+ }
+ c.theme_properties.push_back(prop2);
+ } else {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
+ }
+
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "theme_items")
+ break; // End of <theme_items>.
+ }
+
+ } else if (name2 == "constants") {
+
+ while (parser->read() == OK) {
+
+ if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name3 = parser->get_node_name();
+
+ if (name3 == "constant") {
+
+ ConstantDoc constant2;
+ ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
+ constant2.name = parser->get_attribute_value("name");
+ ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT);
+ constant2.value = parser->get_attribute_value("value");
+ if (parser->has_attribute("enum")) {
+ constant2.enumeration = parser->get_attribute_value("enum");
+ }
+ if (!parser->is_empty()) {
+ parser->read();
+ if (parser->get_node_type() == XMLParser::NODE_TEXT)
+ constant2.description = parser->get_node_data();
+ }
+ c.constants.push_back(constant2);
+ } else {
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + ".");
+ }
+
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "constants")
+ break; // End of <constants>.
+ }
+
+ } else {
+
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name2 + ".");
+ }
+
+ } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "class")
+ break; // End of <class>.
+ }
+ }
+
+ return OK;
+}
+
+static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) {
+
+ if (p_string == "")
+ return;
+ String tab;
+ for (int i = 0; i < p_tablevel; i++)
+ tab += "\t";
+ f->store_string(tab + p_string + "\n");
+}
+
+Error DocData::save_classes(const String &p_default_path, const Map<String, String> &p_class_path) {
+
+ for (Map<String, ClassDoc>::Element *E = class_list.front(); E; E = E->next()) {
+
+ ClassDoc &c = E->get();
+
+ String save_path;
+ if (p_class_path.has(c.name)) {
+ save_path = p_class_path[c.name];
+ } else {
+ save_path = p_default_path;
+ }
+
+ Error err;
+ String save_file = save_path.plus_file(c.name + ".xml");
+ FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err);
+
+ ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");
+
+ _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
+
+ String header = "<class name=\"" + c.name + "\"";
+ if (c.inherits != "")
+ header += " inherits=\"" + c.inherits + "\"";
+ header += String(" version=\"") + VERSION_BRANCH + "\"";
+ header += ">";
+ _write_string(f, 0, header);
+
+ _write_string(f, 1, "<brief_description>");
+ _write_string(f, 2, c.brief_description.strip_edges().xml_escape());
+ _write_string(f, 1, "</brief_description>");
+
+ _write_string(f, 1, "<description>");
+ _write_string(f, 2, c.description.strip_edges().xml_escape());
+ _write_string(f, 1, "</description>");
+
+ _write_string(f, 1, "<tutorials>");
+ for (int i = 0; i < c.tutorials.size(); i++) {
+ _write_string(f, 2, "<link>" + c.tutorials.get(i).xml_escape() + "</link>");
+ }
+ _write_string(f, 1, "</tutorials>");
+
+ _write_string(f, 1, "<methods>");
+
+ c.methods.sort();
+
+ for (int i = 0; i < c.methods.size(); i++) {
+
+ const MethodDoc &m = c.methods[i];
+
+ String qualifiers;
+ if (m.qualifiers != "")
+ qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\"";
+
+ _write_string(f, 2, "<method name=\"" + m.name + "\"" + qualifiers + ">");
+
+ if (m.return_type != "") {
+
+ String enum_text;
+ if (m.return_enum != String()) {
+ enum_text = " enum=\"" + m.return_enum + "\"";
+ }
+ _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + ">");
+ _write_string(f, 3, "</return>");
+ }
+
+ for (int j = 0; j < m.arguments.size(); j++) {
+
+ const ArgumentDoc &a = m.arguments[j];
+
+ String enum_text;
+ if (a.enumeration != String()) {
+ enum_text = " enum=\"" + a.enumeration + "\"";
+ }
+
+ if (a.default_value != "")
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\">");
+ else
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + ">");
+
+ _write_string(f, 3, "</argument>");
+ }
+
+ _write_string(f, 3, "<description>");
+ _write_string(f, 4, m.description.strip_edges().xml_escape());
+ _write_string(f, 3, "</description>");
+
+ _write_string(f, 2, "</method>");
+ }
+
+ _write_string(f, 1, "</methods>");
+
+ if (c.properties.size()) {
+ _write_string(f, 1, "<members>");
+
+ c.properties.sort();
+
+ for (int i = 0; i < c.properties.size(); i++) {
+
+ String additional_attributes;
+ if (c.properties[i].enumeration != String()) {
+ additional_attributes += " enum=\"" + c.properties[i].enumeration + "\"";
+ }
+ if (c.properties[i].default_value != String()) {
+ additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
+ }
+
+ const PropertyDoc &p = c.properties[i];
+
+ if (c.properties[i].overridden) {
+ _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\" override=\"true\"" + additional_attributes + " />");
+ } else {
+ _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\"" + additional_attributes + ">");
+ _write_string(f, 3, p.description.strip_edges().xml_escape());
+ _write_string(f, 2, "</member>");
+ }
+ }
+ _write_string(f, 1, "</members>");
+ }
+
+ if (c.signals.size()) {
+
+ c.signals.sort();
+
+ _write_string(f, 1, "<signals>");
+ for (int i = 0; i < c.signals.size(); i++) {
+
+ const MethodDoc &m = c.signals[i];
+ _write_string(f, 2, "<signal name=\"" + m.name + "\">");
+ for (int j = 0; j < m.arguments.size(); j++) {
+
+ const ArgumentDoc &a = m.arguments[j];
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\">");
+ _write_string(f, 3, "</argument>");
+ }
+
+ _write_string(f, 3, "<description>");
+ _write_string(f, 4, m.description.strip_edges().xml_escape());
+ _write_string(f, 3, "</description>");
+
+ _write_string(f, 2, "</signal>");
+ }
+
+ _write_string(f, 1, "</signals>");
+ }
+
+ _write_string(f, 1, "<constants>");
+
+ for (int i = 0; i < c.constants.size(); i++) {
+
+ const ConstantDoc &k = c.constants[i];
+ if (k.enumeration != String()) {
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">");
+ } else {
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">");
+ }
+ _write_string(f, 3, k.description.strip_edges().xml_escape());
+ _write_string(f, 2, "</constant>");
+ }
+
+ _write_string(f, 1, "</constants>");
+
+ if (c.theme_properties.size()) {
+
+ c.theme_properties.sort();
+
+ _write_string(f, 1, "<theme_items>");
+ for (int i = 0; i < c.theme_properties.size(); i++) {
+
+ const PropertyDoc &p = c.theme_properties[i];
+
+ if (p.default_value != "")
+ _write_string(f, 2, "<theme_item name=\"" + p.name + "\" type=\"" + p.type + "\" default=\"" + p.default_value.xml_escape(true) + "\">");
+ else
+ _write_string(f, 2, "<theme_item name=\"" + p.name + "\" type=\"" + p.type + "\">");
+
+ _write_string(f, 3, p.description.strip_edges().xml_escape());
+
+ _write_string(f, 2, "</theme_item>");
+ }
+ _write_string(f, 1, "</theme_items>");
+ }
+
+ _write_string(f, 0, "</class>");
+ }
+
+ return OK;
+}
+
+Error DocData::load_compressed(const uint8_t *p_data, int p_compressed_size, int p_uncompressed_size) {
+
+ Vector<uint8_t> data;
+ data.resize(p_uncompressed_size);
+ Compression::decompress(data.ptrw(), p_uncompressed_size, p_data, p_compressed_size, Compression::MODE_DEFLATE);
+ class_list.clear();
+
+ Ref<XMLParser> parser = memnew(XMLParser);
+ Error err = parser->open_buffer(data);
+ if (err)
+ return err;
+
+ _load(parser);
+
+ return OK;
+}
diff --git a/editor/doc/doc_data.h b/editor/doc_data.h
index 073705f0b1..073705f0b1 100644
--- a/editor/doc/doc_data.h
+++ b/editor/doc_data.h
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index a223cee360..b0bcc2b448 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -37,20 +37,23 @@
#include "core/version.h"
#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");
+ _tpl_text->add_theme_font_override("normal_font", font);
+ _tpl_text->add_theme_constant_override("line_separation", 6 * EDSCALE);
+ _license_text->add_theme_font_override("normal_font", font);
+ _license_text->add_theme_constant_override("line_separation", 6 * EDSCALE);
+ _logo->set_texture(base->get_theme_icon("Logo", "EditorIcons"));
+}
+
void EditorAbout::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED: {
-
- Control *base = EditorNode::get_singleton()->get_gui_base();
- Ref<Font> font = base->get_font("source", "EditorFonts");
- _tpl_text->add_font_override("normal_font", font);
- _tpl_text->add_constant_override("line_separation", 6 * EDSCALE);
- _license_text->add_font_override("normal_font", font);
- _license_text->add_constant_override("line_separation", 6 * EDSCALE);
- _logo->set_texture(base->get_icon("Logo", "EditorIcons"));
+ case NOTIFICATION_ENTER_TREE: {
+ _theme_changed();
} break;
}
}
@@ -95,9 +98,9 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St
il->set_same_column_width(true);
il->set_auto_height(true);
il->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- il->add_constant_override("hseparation", 16 * EDSCALE);
+ il->add_theme_constant_override("hseparation", 16 * EDSCALE);
while (*names_ptr) {
- il->add_item(String::utf8(*names_ptr++), NULL, false);
+ il->add_item(String::utf8(*names_ptr++), nullptr, false);
}
il->set_max_columns(il->get_item_count() < 4 || single_column ? 1 : 16);
vbc->add_child(il);
@@ -115,13 +118,13 @@ EditorAbout::EditorAbout() {
set_title(TTR("Thanks from the Godot community!"));
set_hide_on_ok(true);
- set_resizable(true);
VBoxContainer *vbc = memnew(VBoxContainer);
+ vbc->connect("theme_changed", callable_mp(this, &EditorAbout::_theme_changed));
HBoxContainer *hbc = memnew(HBoxContainer);
hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->set_alignment(BoxContainer::ALIGN_CENTER);
- hbc->add_constant_override("separation", 30 * EDSCALE);
+ hbc->add_theme_constant_override("separation", 30 * EDSCALE);
add_child(vbc);
vbc->add_child(hbc);
diff --git a/editor/editor_about.h b/editor/editor_about.h
index 51438ee953..83e9e9f490 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -57,6 +57,8 @@ private:
RichTextLabel *_tpl_text;
TextureRect *_logo;
+ void _theme_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 73c70f422d..74c4102003 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -85,7 +85,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
package_path = p_path;
Set<String> files_sorted;
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(p_path.utf8().get_data(), &io);
@@ -102,7 +102,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
//get filename
unz_file_info info;
char fname[16384];
- unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String name = fname;
files_sorted.insert(name);
@@ -110,19 +110,19 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
ret = unzGoToNextFile(pkg);
}
- Map<String, Ref<Texture2D> > extension_guess;
+ Map<String, Ref<Texture2D>> extension_guess;
{
- extension_guess["png"] = get_icon("ImageTexture", "EditorIcons");
- extension_guess["jpg"] = get_icon("ImageTexture", "EditorIcons");
- extension_guess["atlastex"] = get_icon("AtlasTexture", "EditorIcons");
- extension_guess["scn"] = get_icon("PackedScene", "EditorIcons");
- extension_guess["tscn"] = get_icon("PackedScene", "EditorIcons");
- extension_guess["shader"] = get_icon("Shader", "EditorIcons");
- extension_guess["gd"] = get_icon("GDScript", "EditorIcons");
- extension_guess["vs"] = get_icon("VisualScript", "EditorIcons");
+ extension_guess["png"] = tree->get_theme_icon("ImageTexture", "EditorIcons");
+ extension_guess["jpg"] = tree->get_theme_icon("ImageTexture", "EditorIcons");
+ extension_guess["atlastex"] = tree->get_theme_icon("AtlasTexture", "EditorIcons");
+ extension_guess["scn"] = tree->get_theme_icon("PackedScene", "EditorIcons");
+ extension_guess["tscn"] = tree->get_theme_icon("PackedScene", "EditorIcons");
+ extension_guess["shader"] = tree->get_theme_icon("Shader", "EditorIcons");
+ extension_guess["gd"] = tree->get_theme_icon("GDScript", "EditorIcons");
+ extension_guess["vs"] = tree->get_theme_icon("VisualScript", "EditorIcons");
}
- Ref<Texture2D> generic_extension = get_icon("Object", "EditorIcons");
+ Ref<Texture2D> generic_extension = tree->get_theme_icon("Object", "EditorIcons");
unzClose(pkg);
@@ -131,7 +131,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
TreeItem *root = tree->create_item();
root->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
root->set_checked(0, true);
- root->set_icon(0, get_icon("folder", "FileDialog"));
+ root->set_icon(0, tree->get_theme_icon("folder", "FileDialog"));
root->set_text(0, "res://");
root->set_editable(0, true);
Map<String, TreeItem *> dir_map;
@@ -180,7 +180,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
if (isdir) {
dir_map[path] = ti;
ti->set_text(0, path.get_file() + "/");
- ti->set_icon(0, get_icon("folder", "FileDialog"));
+ ti->set_icon(0, tree->get_theme_icon("folder", "FileDialog"));
ti->set_metadata(0, String());
} else {
String file = path.get_file();
@@ -194,7 +194,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
String res_path = "res://" + path;
if (FileAccess::exists(res_path)) {
- ti->set_custom_color(0, get_color("error_color", "Editor"));
+ ti->set_custom_color(0, tree->get_theme_color("error_color", "Editor"));
ti->set_tooltip(0, vformat(TTR("%s (Already Exists)"), res_path));
ti->set_checked(0, false);
} else {
@@ -212,7 +212,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
void EditorAssetInstaller::ok_pressed() {
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(package_path.utf8().get_data(), &io);
@@ -234,7 +234,7 @@ void EditorAssetInstaller::ok_pressed() {
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String name = fname;
@@ -297,10 +297,10 @@ void EditorAssetInstaller::ok_pressed() {
}
msg += failed_files[i];
}
- if (EditorNode::get_singleton() != NULL)
+ if (EditorNode::get_singleton() != nullptr)
EditorNode::get_singleton()->show_warning(msg);
} else {
- if (EditorNode::get_singleton() != NULL)
+ if (EditorNode::get_singleton() != nullptr)
EditorNode::get_singleton()->show_warning(TTR("Package installed successfully!"), TTR("Success!"));
}
EditorFileSystem::get_singleton()->scan_changes();
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index d77216697e..7e499facd5 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -30,8 +30,8 @@
#include "editor_audio_buses.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_saver.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "editor_node.h"
#include "editor_scale.h"
@@ -69,27 +69,27 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_READY: {
for (int i = 0; i < CHANNELS_MAX; i++) {
- channel[i].vu_l->set_under_texture(get_icon("BusVuEmpty", "EditorIcons"));
- channel[i].vu_l->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
- channel[i].vu_r->set_under_texture(get_icon("BusVuEmpty", "EditorIcons"));
- channel[i].vu_r->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
+ channel[i].vu_l->set_under_texture(get_theme_icon("BusVuEmpty", "EditorIcons"));
+ channel[i].vu_l->set_progress_texture(get_theme_icon("BusVuFull", "EditorIcons"));
+ channel[i].vu_r->set_under_texture(get_theme_icon("BusVuEmpty", "EditorIcons"));
+ channel[i].vu_r->set_progress_texture(get_theme_icon("BusVuFull", "EditorIcons"));
channel[i].prev_active = true;
}
- disabled_vu = get_icon("BusVuFrozen", "EditorIcons");
+ disabled_vu = get_theme_icon("BusVuFrozen", "EditorIcons");
Color solo_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1.0, 0.89, 0.22) : Color(1.0, 0.92, 0.44);
Color mute_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1.0, 0.16, 0.16) : Color(1.0, 0.44, 0.44);
Color bypass_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(0.13, 0.8, 1.0) : Color(0.44, 0.87, 1.0);
- solo->set_icon(get_icon("AudioBusSolo", "EditorIcons"));
- solo->add_color_override("icon_color_pressed", solo_color);
- mute->set_icon(get_icon("AudioBusMute", "EditorIcons"));
- mute->add_color_override("icon_color_pressed", mute_color);
- bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons"));
- bypass->add_color_override("icon_color_pressed", bypass_color);
+ solo->set_icon(get_theme_icon("AudioBusSolo", "EditorIcons"));
+ solo->add_theme_color_override("icon_color_pressed", solo_color);
+ mute->set_icon(get_theme_icon("AudioBusMute", "EditorIcons"));
+ mute->add_theme_color_override("icon_color_pressed", mute_color);
+ bypass->set_icon(get_theme_icon("AudioBusBypass", "EditorIcons"));
+ bypass->add_theme_color_override("icon_color_pressed", bypass_color);
- bus_options->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
+ bus_options->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
update_bus();
set_process(true);
@@ -97,15 +97,15 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_DRAW: {
if (is_master) {
- draw_style_box(get_stylebox("disabled", "Button"), Rect2(Vector2(), get_size()));
+ draw_style_box(get_theme_stylebox("disabled", "Button"), Rect2(Vector2(), get_size()));
} else if (has_focus()) {
- draw_style_box(get_stylebox("focus", "Button"), Rect2(Vector2(), get_size()));
+ draw_style_box(get_theme_stylebox("focus", "Button"), Rect2(Vector2(), get_size()));
} else {
- draw_style_box(get_stylebox("panel", "TabContainer"), Rect2(Vector2(), get_size()));
+ draw_style_box(get_theme_stylebox("panel", "TabContainer"), Rect2(Vector2(), get_size()));
}
if (get_index() != 0 && hovering_drop) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
accent.a *= 0.7;
draw_rect(Rect2(Point2(), get_size()), accent, false);
}
@@ -168,20 +168,20 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
for (int i = 0; i < CHANNELS_MAX; i++) {
- channel[i].vu_l->set_under_texture(get_icon("BusVuEmpty", "EditorIcons"));
- channel[i].vu_l->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
- channel[i].vu_r->set_under_texture(get_icon("BusVuEmpty", "EditorIcons"));
- channel[i].vu_r->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
+ channel[i].vu_l->set_under_texture(get_theme_icon("BusVuEmpty", "EditorIcons"));
+ channel[i].vu_l->set_progress_texture(get_theme_icon("BusVuFull", "EditorIcons"));
+ channel[i].vu_r->set_under_texture(get_theme_icon("BusVuEmpty", "EditorIcons"));
+ channel[i].vu_r->set_progress_texture(get_theme_icon("BusVuFull", "EditorIcons"));
channel[i].prev_active = true;
}
- disabled_vu = get_icon("BusVuFrozen", "EditorIcons");
+ disabled_vu = get_theme_icon("BusVuFrozen", "EditorIcons");
- solo->set_icon(get_icon("AudioBusSolo", "EditorIcons"));
- mute->set_icon(get_icon("AudioBusMute", "EditorIcons"));
- bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons"));
+ solo->set_icon(get_theme_icon("AudioBusSolo", "EditorIcons"));
+ mute->set_icon(get_theme_icon("AudioBusMute", "EditorIcons"));
+ bypass->set_icon(get_theme_icon("AudioBusBypass", "EditorIcons"));
- bus_options->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
+ bus_options->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
} break;
case NOTIFICATION_MOUSE_EXIT:
case NOTIFICATION_DRAG_END: {
@@ -325,7 +325,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) {
const float p_db = this->_normalized_volume_to_scaled_db(p_normalized);
- if (Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) {
// Snap the value when holding Ctrl for easier editing.
// To do so, it needs to be converted back to normalized volume (as the slider uses that unit).
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
@@ -386,7 +386,7 @@ float EditorAudioBus::_scaled_db_to_normalized_volume(float db) {
void EditorAudioBus::_show_value(float slider_value) {
float db;
- if (Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) {
// Display the correct (snapped) value when holding Ctrl
db = Math::round(_normalized_volume_to_scaled_db(slider_value));
} else {
@@ -586,7 +586,7 @@ Variant EditorAudioBus::get_drag_data(const Point2 &p_point) {
Panel *p = memnew(Panel);
c->add_child(p);
p->set_modulate(Color(1, 1, 1, 0.7));
- p->add_style_override("panel", get_stylebox("focus", "Button"));
+ p->add_theme_style_override("panel", get_theme_stylebox("focus", "Button"));
p->set_size(get_size());
p->set_position(-p_point);
set_drag_preview(c);
@@ -819,10 +819,10 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
Ref<StyleBoxEmpty> sbempty = memnew(StyleBoxEmpty);
for (int i = 0; i < hbc->get_child_count(); i++) {
Control *child = Object::cast_to<Control>(hbc->get_child(i));
- child->add_style_override("normal", sbempty);
- child->add_style_override("hover", sbempty);
- child->add_style_override("focus", sbempty);
- child->add_style_override("pressed", sbempty);
+ child->add_theme_style_override("normal", sbempty);
+ child->add_theme_style_override("hover", sbempty);
+ child->add_theme_style_override("focus", sbempty);
+ child->add_theme_style_override("pressed", sbempty);
}
HSeparator *separator = memnew(HSeparator);
@@ -854,7 +854,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
audio_value_preview_box->set_as_toplevel(true);
Ref<StyleBoxFlat> panel_style = memnew(StyleBoxFlat);
panel_style->set_bg_color(Color(0.0f, 0.0f, 0.0f, 0.8f));
- audio_value_preview_box->add_style_override("panel", panel_style);
+ audio_value_preview_box->add_theme_style_override("panel", panel_style);
audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS);
audio_value_preview_box->hide();
@@ -953,10 +953,10 @@ void EditorAudioBusDrop::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- draw_style_box(get_stylebox("normal", "Button"), Rect2(Vector2(), get_size()));
+ draw_style_box(get_theme_stylebox("normal", "Button"), Rect2(Vector2(), get_size()));
if (hovering_drop) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
accent.a *= 0.7;
draw_rect(Rect2(Point2(), get_size()), accent, false);
}
@@ -1007,7 +1007,7 @@ void EditorAudioBuses::_update_buses() {
memdelete(bus_hb->get_child(0));
}
- drop_end = NULL;
+ drop_end = nullptr;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
@@ -1035,7 +1035,7 @@ void EditorAudioBuses::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- bus_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
+ bus_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
} break;
case NOTIFICATION_READY: {
@@ -1045,7 +1045,7 @@ void EditorAudioBuses::_notification(int p_what) {
if (drop_end) {
drop_end->queue_delete();
- drop_end = NULL;
+ drop_end = nullptr;
}
} break;
case NOTIFICATION_PROCESS: {
@@ -1204,7 +1204,7 @@ void EditorAudioBuses::_select_layout() {
void EditorAudioBuses::_save_as_layout() {
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Audio Bus Layout As..."));
file_dialog->set_current_path(edited_path);
file_dialog->popup_centered_ratio();
@@ -1213,7 +1213,7 @@ void EditorAudioBuses::_save_as_layout() {
void EditorAudioBuses::_new_layout() {
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Location for New Layout..."));
file_dialog->set_current_path(edited_path);
file_dialog->popup_centered_ratio();
@@ -1222,7 +1222,7 @@ void EditorAudioBuses::_new_layout() {
void EditorAudioBuses::_load_layout() {
- file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_dialog->set_title(TTR("Open Audio Bus Layout"));
file_dialog->set_current_path(edited_path);
file_dialog->popup_centered_ratio();
@@ -1249,7 +1249,7 @@ void EditorAudioBuses::_load_default_layout() {
void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
- if (file_dialog->get_mode() == EditorFileDialog::MODE_OPEN_FILE) {
+ if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_OPEN_FILE) {
Ref<AudioBusLayout> state = ResourceLoader::load(p_string, "", true);
if (state.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an audio bus layout."));
@@ -1263,7 +1263,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
EditorNode::get_singleton()->get_undo_redo()->clear_history();
call_deferred("_select_layout");
- } else if (file_dialog->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
+ } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
if (new_layout) {
Ref<AudioBusLayout> empty_state;
@@ -1296,7 +1296,7 @@ void EditorAudioBuses::_bind_methods() {
EditorAudioBuses::EditorAudioBuses() {
- drop_end = NULL;
+ drop_end = nullptr;
top_hb = memnew(HBoxContainer);
add_child(top_hb);
@@ -1402,7 +1402,7 @@ void AudioBusesEditorPlugin::edit(Object *p_node) {
bool AudioBusesEditorPlugin::handles(Object *p_node) const {
- return (Object::cast_to<AudioBusLayout>(p_node) != NULL);
+ return (Object::cast_to<AudioBusLayout>(p_node) != nullptr);
}
void AudioBusesEditorPlugin::make_visible(bool p_visible) {
@@ -1423,7 +1423,7 @@ void EditorAudioMeterNotches::add_notch(float p_normalized_offset, float p_db_va
Size2 EditorAudioMeterNotches::get_minimum_size() const {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
float font_height = font->get_height();
float width = 0;
@@ -1460,7 +1460,7 @@ void EditorAudioMeterNotches::_notification(int p_what) {
void EditorAudioMeterNotches::_draw_audio_notches() {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
float font_height = font->get_height();
for (int i = 0; i < notches.size(); i++) {
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index 72098c7232..be1551629d 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -133,7 +133,7 @@ public:
void update_bus();
void update_send();
- EditorAudioBus(EditorAudioBuses *p_buses = NULL, bool p_is_master = false);
+ EditorAudioBus(EditorAudioBuses *p_buses = nullptr, bool p_is_master = false);
};
class EditorAudioBusDrop : public Control {
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 83a1e2fca2..6917b2b775 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -35,7 +35,7 @@
#include "editor_node.h"
#include "editor_scale.h"
#include "project_settings_editor.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
#define PREVIEW_LIST_MAX_SIZE 10
@@ -48,8 +48,6 @@ void EditorAutoloadSettings::_notification(int p_what) {
ResourceLoader::get_recognized_extensions_for_type("Script", &afn);
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &afn);
- EditorFileDialog *file_dialog = autoload_add_path->get_file_dialog();
-
for (List<String>::Element *E = afn.front(); E; E = E->next()) {
file_dialog->add_filter("*." + E->get());
@@ -61,6 +59,9 @@ void EditorAutoloadSettings::_notification(int p_what) {
get_tree()->get_root()->call_deferred("add_child", info.node);
}
}
+ browse_button->set_icon(get_theme_icon("Folder", "EditorIcons"));
+ } else if (p_what == NOTIFICATION_THEME_CHANGED) {
+ browse_button->set_icon(get_theme_icon("Folder", "EditorIcons"));
}
}
@@ -116,8 +117,8 @@ bool EditorAutoloadSettings::_autoload_name_is_valid(const String &p_name, Strin
void EditorAutoloadSettings::_autoload_add() {
- if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_line_edit()->get_text()))
- autoload_add_path->get_line_edit()->set_text("");
+ if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text()))
+ autoload_add_path->set_text("");
autoload_add_name->set_text("");
add_autoload->set_disabled(true);
@@ -240,7 +241,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
case BUTTON_MOVE_UP:
case BUTTON_MOVE_DOWN: {
- TreeItem *swap = NULL;
+ TreeItem *swap = nullptr;
if (p_button == BUTTON_MOVE_UP) {
swap = ti->get_prev();
@@ -326,7 +327,7 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) {
void EditorAutoloadSettings::_autoload_text_entered(const String p_name) {
- if (autoload_add_path->get_line_edit()->get_text() != "" && _autoload_name_is_valid(p_name, NULL)) {
+ if (autoload_add_path->get_text() != "" && _autoload_name_is_valid(p_name, nullptr)) {
_autoload_add();
}
}
@@ -334,19 +335,19 @@ void EditorAutoloadSettings::_autoload_text_entered(const String p_name) {
void EditorAutoloadSettings::_autoload_path_text_changed(const String p_path) {
add_autoload->set_disabled(
- p_path == "" || !_autoload_name_is_valid(autoload_add_name->get_text(), NULL));
+ p_path == "" || !_autoload_name_is_valid(autoload_add_name->get_text(), nullptr));
}
void EditorAutoloadSettings::_autoload_text_changed(const String p_name) {
add_autoload->set_disabled(
- autoload_add_path->get_line_edit()->get_text() == "" || !_autoload_name_is_valid(p_name, NULL));
+ autoload_add_path->get_text() == "" || !_autoload_name_is_valid(p_name, nullptr));
}
Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
RES res = ResourceLoader::load(p_path);
- ERR_FAIL_COND_V_MSG(res.is_null(), NULL, "Can't autoload: " + p_path + ".");
- Node *n = NULL;
+ ERR_FAIL_COND_V_MSG(res.is_null(), nullptr, "Can't autoload: " + p_path + ".");
+ Node *n = nullptr;
if (res->is_class("PackedScene")) {
Ref<PackedScene> ps = res;
n = ps->instance();
@@ -354,17 +355,17 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_FAIL_COND_V_MSG(!valid_type, NULL, "Script does not inherit a Node: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!valid_type, nullptr, "Script does not inherit a Node: " + p_path + ".");
Object *obj = ClassDB::instance(ibt);
- ERR_FAIL_COND_V_MSG(obj == NULL, NULL, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_COND_V_MSG(obj == nullptr, nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + ".");
n = Object::cast_to<Node>(obj);
n->set_script(s);
}
- ERR_FAIL_COND_V_MSG(!n, NULL, "Path in autoload not a node or script: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!n, nullptr, "Path in autoload not a node or script: " + p_path + ".");
return n;
}
@@ -429,7 +430,7 @@ void EditorAutoloadSettings::update_autoload() {
to_remove.erase(name);
need_to_add = false;
} else {
- info.node = NULL;
+ info.node = nullptr;
}
}
}
@@ -452,10 +453,10 @@ void EditorAutoloadSettings::update_autoload() {
item->set_editable(2, true);
item->set_text(2, TTR("Enable"));
item->set_checked(2, info.is_singleton);
- item->add_button(3, get_icon("Load", "EditorIcons"), BUTTON_OPEN);
- item->add_button(3, get_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP);
- item->add_button(3, get_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN);
- item->add_button(3, get_icon("Remove", "EditorIcons"), BUTTON_DELETE);
+ item->add_button(3, get_theme_icon("Load", "EditorIcons"), BUTTON_OPEN);
+ item->add_button(3, get_theme_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP);
+ item->add_button(3, get_theme_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN);
+ item->add_button(3, get_theme_icon("Remove", "EditorIcons"), BUTTON_DELETE);
item->set_selectable(3, false);
}
@@ -474,7 +475,7 @@ void EditorAutoloadSettings::update_autoload() {
if (info.node) {
info.node->queue_delete();
- info.node = NULL;
+ info.node = nullptr;
}
}
@@ -505,7 +506,7 @@ void EditorAutoloadSettings::update_autoload() {
if (!info->in_editor && !info->is_singleton) {
// No reason to keep this node
memdelete(info->node);
- info->node = NULL;
+ info->node = nullptr;
}
}
@@ -523,7 +524,7 @@ Variant EditorAutoloadSettings::get_drag_data_fw(const Point2 &p_point, Control
PackedStringArray autoloads;
- TreeItem *next = tree->get_next_selected(NULL);
+ TreeItem *next = tree->get_next_selected(nullptr);
while (next) {
autoloads.push_back(next->get_text(0));
@@ -604,7 +605,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant &
int order = ProjectSettings::get_singleton()->get_order("autoload/" + name);
AutoLoadInfo aux;
- List<AutoLoadInfo>::Element *E = NULL;
+ List<AutoLoadInfo>::Element *E = nullptr;
if (!move_to_back) {
aux.order = order;
@@ -805,9 +806,9 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
}
}
- if (!info.is_singleton && !info.in_editor && info.node != NULL) {
+ if (!info.is_singleton && !info.in_editor && info.node != nullptr) {
memdelete(info.node);
- info.node = NULL;
+ info.node = nullptr;
}
}
@@ -823,13 +824,24 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
l->set_text(TTR("Path:"));
hbc->add_child(l);
- autoload_add_path = memnew(EditorLineEditFileChooser);
- autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL);
- autoload_add_path->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE);
- autoload_add_path->get_file_dialog()->connect("file_selected", callable_mp(this, &EditorAutoloadSettings::_autoload_file_callback));
- autoload_add_path->get_line_edit()->connect("text_changed", callable_mp(this, &EditorAutoloadSettings::_autoload_path_text_changed));
-
+ autoload_add_path = memnew(LineEdit);
hbc->add_child(autoload_add_path);
+ autoload_add_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ autoload_add_path->connect("text_changed", callable_mp(this, &EditorAutoloadSettings::_autoload_path_text_changed));
+
+ browse_button = memnew(Button);
+ hbc->add_child(browse_button);
+ browse_button->connect("pressed", callable_mp(this, &EditorAutoloadSettings::_browse_autoload_add_path));
+
+ file_dialog = memnew(EditorFileDialog);
+ hbc->add_child(file_dialog);
+ file_dialog->connect("file_selected", callable_mp(this, &EditorAutoloadSettings::_set_autoload_add_path));
+ file_dialog->connect("dir_selected", callable_mp(this, &EditorAutoloadSettings::_set_autoload_add_path));
+ file_dialog->connect("files_selected", callable_mp(this, &EditorAutoloadSettings::_set_autoload_add_path));
+
+ hbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ file_dialog->connect("file_selected", callable_mp(this, &EditorAutoloadSettings::_autoload_file_callback));
l = memnew(Label);
l->set_text(TTR("Node Name:"));
@@ -890,3 +902,14 @@ EditorAutoloadSettings::~EditorAutoloadSettings() {
}
}
}
+
+void EditorAutoloadSettings::_set_autoload_add_path(const String &p_text) {
+
+ autoload_add_path->set_text(p_text);
+ autoload_add_path->emit_signal("text_entered", p_text);
+}
+
+void EditorAutoloadSettings::_browse_autoload_add_path() {
+
+ file_dialog->popup_centered_ratio();
+} \ No newline at end of file
diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h
index 653a1b0a78..94a581401c 100644
--- a/editor/editor_autoload_settings.h
+++ b/editor/editor_autoload_settings.h
@@ -63,7 +63,7 @@ class EditorAutoloadSettings : public VBoxContainer {
AutoLoadInfo() {
is_singleton = false;
in_editor = false;
- node = NULL;
+ node = nullptr;
}
};
@@ -74,11 +74,13 @@ class EditorAutoloadSettings : public VBoxContainer {
String selected_autoload;
Tree *tree;
- EditorLineEditFileChooser *autoload_add_path;
LineEdit *autoload_add_name;
Button *add_autoload;
+ LineEdit *autoload_add_path;
+ Button *browse_button;
+ EditorFileDialog *file_dialog;
- bool _autoload_name_is_valid(const String &p_name, String *r_error = NULL);
+ bool _autoload_name_is_valid(const String &p_name, String *r_error = nullptr);
void _autoload_add();
void _autoload_selected();
@@ -96,6 +98,9 @@ class EditorAutoloadSettings : public VBoxContainer {
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_control) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_control);
+ void _set_autoload_add_path(const String &p_text);
+ void _browse_autoload_add_path();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/editor_builders.py b/editor/editor_builders.py
index 910c53e2ff..ea32e24f6e 100644
--- a/editor/editor_builders.py
+++ b/editor/editor_builders.py
@@ -6,26 +6,26 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
import os
import os.path
from platform_methods import subprocess_main
-from compat import encode_utf8, byte_to_str, open_utf8
def make_doc_header(target, source, env):
dst = target[0]
- g = open_utf8(dst, "w")
+ g = open(dst, "w", encoding="utf-8")
buf = ""
docbegin = ""
docend = ""
for src in source:
if not src.endswith(".xml"):
continue
- with open_utf8(src, "r") as f:
+ with open(src, "r", encoding="utf-8") as f:
content = f.read()
buf += content
- buf = encode_utf8(docbegin + buf + docend)
+ buf = (docbegin + buf + docend).encode("utf-8")
decomp_size = len(buf)
import zlib
+
buf = zlib.compress(buf)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
@@ -35,7 +35,7 @@ def make_doc_header(target, source, env):
g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const unsigned char _doc_data_compressed[] = {\n")
for i in range(len(buf)):
- g.write("\t" + byte_to_str(buf[i]) + ",\n")
+ g.write("\t" + str(buf[i]) + ",\n")
g.write("};\n")
g.write("#endif")
@@ -47,7 +47,7 @@ def make_fonts_header(target, source, env):
dst = target[0]
- g = open_utf8(dst, "w")
+ g = open(dst, "w", encoding="utf-8")
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef _EDITOR_FONTS_H\n")
@@ -56,7 +56,7 @@ def make_fonts_header(target, source, env):
# saving uncompressed, since freetype will reference from memory pointer
xl_names = []
for i in range(len(source)):
- with open(source[i], "rb")as f:
+ with open(source[i], "rb") as f:
buf = f.read()
name = os.path.splitext(os.path.basename(source[i]))[0]
@@ -64,7 +64,7 @@ def make_fonts_header(target, source, env):
g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n")
g.write("static const unsigned char _font_" + name + "[] = {\n")
for j in range(len(buf)):
- g.write("\t" + byte_to_str(buf[j]) + ",\n")
+ g.write("\t" + str(buf[j]) + ",\n")
g.write("};\n")
@@ -73,15 +73,15 @@ def make_fonts_header(target, source, env):
g.close()
-def make_translations_header(target, source, env):
+def make_translations_header(target, source, env, category):
dst = target[0]
- g = open_utf8(dst, "w")
+ g = open(dst, "w", encoding="utf-8")
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- g.write("#ifndef _EDITOR_TRANSLATIONS_H\n")
- g.write("#define _EDITOR_TRANSLATIONS_H\n")
+ g.write("#ifndef _{}_TRANSLATIONS_H\n".format(category.upper()))
+ g.write("#define _{}_TRANSLATIONS_H\n".format(category.upper()))
import zlib
import os.path
@@ -96,29 +96,40 @@ def make_translations_header(target, source, env):
buf = zlib.compress(buf)
name = os.path.splitext(os.path.basename(sorted_paths[i]))[0]
- g.write("static const unsigned char _translation_" + name + "_compressed[] = {\n")
+ g.write("static const unsigned char _{}_translation_{}_compressed[] = {{\n".format(category, name))
for j in range(len(buf)):
- g.write("\t" + byte_to_str(buf[j]) + ",\n")
+ g.write("\t" + str(buf[j]) + ",\n")
g.write("};\n")
xl_names.append([name, len(buf), str(decomp_size)])
- g.write("struct EditorTranslationList {\n")
+ g.write("struct {}TranslationList {{\n".format(category.capitalize()))
g.write("\tconst char* lang;\n")
g.write("\tint comp_size;\n")
g.write("\tint uncomp_size;\n")
g.write("\tconst unsigned char* data;\n")
g.write("};\n\n")
- g.write("static EditorTranslationList _editor_translations[] = {\n")
+ g.write("static {}TranslationList _{}_translations[] = {{\n".format(category.capitalize(), category))
for x in xl_names:
- g.write("\t{ \"" + x[0] + "\", " + str(x[1]) + ", " + str(x[2]) + ", _translation_" + x[0] + "_compressed},\n")
- g.write("\t{NULL, 0, 0, NULL}\n")
+ g.write(
+ '\t{{ "{}", {}, {}, _{}_translation_{}_compressed }},\n'.format(x[0], str(x[1]), str(x[2]), category, x[0])
+ )
+ g.write("\t{nullptr, 0, 0, nullptr}\n")
g.write("};\n")
g.write("#endif")
g.close()
-if __name__ == '__main__':
+
+def make_editor_translations_header(target, source, env):
+ make_translations_header(target, source, env, "editor")
+
+
+def make_doc_translations_header(target, source, env):
+ make_translations_header(target, source, env, "doc")
+
+
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 192e7d286f..942b4a8ee6 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -270,7 +270,7 @@ EditorPlugin *EditorData::get_editor(Object *p_object) {
return editor_plugins[i];
}
- return NULL;
+ return nullptr;
}
EditorPlugin *EditorData::get_subeditor(Object *p_object) {
@@ -281,7 +281,7 @@ EditorPlugin *EditorData::get_subeditor(Object *p_object) {
return editor_plugins[i];
}
- return NULL;
+ return nullptr;
}
Vector<EditorPlugin *> EditorData::get_subeditors(Object *p_object) {
@@ -302,7 +302,7 @@ EditorPlugin *EditorData::get_editor(String p_name) {
return editor_plugins[i];
}
- return NULL;
+ return nullptr;
}
void EditorData::copy_object_params(Object *p_object) {
@@ -464,7 +464,7 @@ UndoRedo &EditorData::get_undo_redo() {
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
- p_plugin->undo_redo = NULL;
+ p_plugin->undo_redo = nullptr;
editor_plugins.erase(p_plugin);
}
@@ -479,7 +479,7 @@ int EditorData::get_editor_plugin_count() const {
}
EditorPlugin *EditorData::get_editor_plugin(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, editor_plugins.size(), NULL);
+ ERR_FAIL_INDEX_V(p_idx, editor_plugins.size(), nullptr);
return editor_plugins[p_idx];
}
@@ -506,7 +506,7 @@ Object *EditorData::instance_custom_type(const String &p_type, const String &p_i
Ref<Script> script = get_custom_types()[p_inherits][i].script;
Object *ob = ClassDB::instance(p_inherits);
- ERR_FAIL_COND_V(!ob, NULL);
+ ERR_FAIL_COND_V(!ob, nullptr);
if (ob->is_class("Node")) {
ob->call("set_name", p_type);
}
@@ -516,12 +516,12 @@ Object *EditorData::instance_custom_type(const String &p_type, const String &p_i
}
}
- return NULL;
+ return nullptr;
}
void EditorData::remove_custom_type(const String &p_type) {
- for (Map<String, Vector<CustomType> >::Element *E = custom_types.front(); E; E = E->next()) {
+ for (Map<String, Vector<CustomType>>::Element *E = custom_types.front(); E; E = E->next()) {
for (int i = 0; i < E->get().size(); i++) {
if (E->get()[i].name == p_type) {
@@ -540,7 +540,7 @@ int EditorData::add_edited_scene(int p_at_pos) {
if (p_at_pos < 0)
p_at_pos = edited_scene.size();
EditedScene es;
- es.root = NULL;
+ es.root = nullptr;
es.path = String();
es.history_current = -1;
es.version = 0;
@@ -680,10 +680,10 @@ void EditorData::set_edited_scene(int p_idx) {
}
Node *EditorData::get_edited_scene_root(int p_idx) {
if (p_idx < 0) {
- ERR_FAIL_INDEX_V(current_edited_scene, edited_scene.size(), NULL);
+ ERR_FAIL_INDEX_V(current_edited_scene, edited_scene.size(), nullptr);
return edited_scene[current_edited_scene].root;
} else {
- ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), NULL);
+ ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), nullptr);
return edited_scene[p_idx].root;
}
}
@@ -915,7 +915,7 @@ Object *EditorData::script_class_instance(const String &p_class) {
return obj;
}
}
- return NULL;
+ return nullptr;
}
Ref<Script> EditorData::script_class_load_script(const String &p_class) const {
@@ -1018,7 +1018,7 @@ void EditorSelection::add_node(Node *p_node) {
changed = true;
nl_changed = true;
- Object *meta = NULL;
+ Object *meta = nullptr;
for (List<Object *>::Element *E = editor_plugins.front(); E; E = E->next()) {
meta = E->get()->call("_get_editor_data", p_node);
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 8a6f2f63f6..4f5d68bfed 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -135,7 +135,7 @@ private:
String name;
Variant value;
};
- Map<String, Vector<CustomType> > custom_types;
+ Map<String, Vector<CustomType>> custom_types;
List<PropertyData> clipboard;
UndoRedo undo_redo;
@@ -181,7 +181,7 @@ public:
void add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
Object *instance_custom_type(const String &p_type, const String &p_inherits);
void remove_custom_type(const String &p_type);
- const Map<String, Vector<CustomType> > &get_custom_types() const { return custom_types; }
+ const Map<String, Vector<CustomType>> &get_custom_types() const { return custom_types; }
int add_edited_scene(int p_at_pos);
void move_edited_scene_index(int p_idx, int p_to_idx);
@@ -265,7 +265,7 @@ public:
template <class T>
T *get_node_editor_data(Node *p_node) {
if (!selection.has(p_node))
- return NULL;
+ return nullptr;
return Object::cast_to<T>(selection[p_node]);
}
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 20fe349ef6..cb87656382 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_settings.h"
#include "editor_scale.h"
+#include "servers/display_server.h"
void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p_dir, const String &p_select_path) {
@@ -43,7 +44,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
String path = p_dir->get_path();
p_item->set_metadata(0, p_dir->get_path());
- p_item->set_icon(0, get_icon("Folder", "EditorIcons"));
+ p_item->set_icon(0, tree->get_theme_icon("Folder", "EditorIcons"));
if (!p_item->get_parent()) {
p_item->set_text(0, "res://");
@@ -68,7 +69,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
void EditorDirDialog::reload(const String &p_path) {
- if (!is_visible_in_tree()) {
+ if (!is_visible()) {
must_reload = true;
return;
}
@@ -102,7 +103,7 @@ void EditorDirDialog::_notification(int p_what) {
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (must_reload && is_visible_in_tree()) {
+ if (must_reload && is_visible()) {
reload();
}
}
@@ -141,11 +142,11 @@ void EditorDirDialog::_make_dir() {
TreeItem *ti = tree->get_selected();
if (!ti) {
mkdirerr->set_text(TTR("Please select a base directory first."));
- mkdirerr->popup_centered_minsize();
+ mkdirerr->popup_centered();
return;
}
- makedialog->popup_centered_minsize(Size2(250, 80));
+ makedialog->popup_centered(Size2(250, 80));
makedirname->grab_focus();
}
@@ -162,7 +163,7 @@ void EditorDirDialog::_make_dir_confirm() {
Error err = d->make_dir(makedirname->get_text());
if (err != OK) {
- mkdirerr->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ mkdirerr->popup_centered(Size2(250, 80) * EDSCALE);
} else {
opened_paths.insert(dir);
//reload(dir.plus_file(makedirname->get_text()));
@@ -188,7 +189,7 @@ EditorDirDialog::EditorDirDialog() {
tree->connect("item_activated", callable_mp(this, &EditorDirDialog::_item_activated));
- makedir = add_button(TTR("Create Folder"), OS::get_singleton()->get_swap_ok_cancel(), "makedir");
+ makedir = add_button(TTR("Create Folder"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "makedir");
makedir->connect("pressed", callable_mp(this, &EditorDirDialog::_make_dir));
makedialog = memnew(ConfirmationDialog);
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 4941f295d7..e8167070d4 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -358,12 +358,12 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
zipOpenNewFileInZip(zip,
path.utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
@@ -582,6 +582,14 @@ String EditorExportPlugin::get_ios_cpp_code() const {
return ios_cpp_code;
}
+void EditorExportPlugin::add_ios_project_static_lib(const String &p_path) {
+ ios_project_static_libs.push_back(p_path);
+}
+
+Vector<String> EditorExportPlugin::get_ios_project_static_libs() const {
+ return ios_project_static_libs;
+}
+
void EditorExportPlugin::_export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features) {
if (get_script_instance()) {
@@ -617,6 +625,7 @@ void EditorExportPlugin::skip() {
void EditorExportPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_shared_object", "path", "tags"), &EditorExportPlugin::add_shared_object);
+ ClassDB::bind_method(D_METHOD("add_ios_project_static_lib", "path"), &EditorExportPlugin::add_ios_project_static_lib);
ClassDB::bind_method(D_METHOD("add_file", "path", "file", "remap"), &EditorExportPlugin::add_file);
ClassDB::bind_method(D_METHOD("add_ios_framework", "path"), &EditorExportPlugin::add_ios_framework);
ClassDB::bind_method(D_METHOD("add_ios_plist_content", "plist_content"), &EditorExportPlugin::add_ios_plist_content);
@@ -664,7 +673,7 @@ EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_contai
EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
FeatureContainers features = p_platform.get_feature_containers(p_preset);
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
//initial export plugin callback
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) { //script based
@@ -676,7 +685,7 @@ EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_pla
}
EditorExportPlatform::ExportNotifier::~ExportNotifier() {
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) {
export_plugins.write[i]->_export_end_script();
@@ -712,7 +721,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
_edit_filter_list(paths, p_preset->get_include_filter(), false);
_edit_filter_list(paths, p_preset->get_exclude_filter(), true);
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ 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);
@@ -1070,7 +1079,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, co
FileAccess *src_f;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io);
+ zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
ZipData zd;
zd.ep = &ep;
@@ -1080,7 +1089,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, co
if (err != OK && err != ERR_SKIP)
ERR_PRINT("Failed to export project files");
- zipClose(zip, NULL);
+ zipClose(zip, nullptr);
return OK;
}
@@ -1153,7 +1162,7 @@ EditorExportPlatform::EditorExportPlatform() {
////
-EditorExport *EditorExport::singleton = NULL;
+EditorExport *EditorExport::singleton = nullptr;
void EditorExport::_save() {
@@ -1284,7 +1293,7 @@ void EditorExport::remove_export_plugin(const Ref<EditorExportPlugin> &p_plugin)
export_plugins.erase(p_plugin);
}
-Vector<Ref<EditorExportPlugin> > EditorExport::get_export_plugins() {
+Vector<Ref<EditorExportPlugin>> EditorExport::get_export_plugins() {
return export_plugins;
}
@@ -1686,7 +1695,7 @@ void EditorExportPlatformPC::set_fixup_embedded_pck_func(FixUpEmbeddedPckFunc p_
EditorExportPlatformPC::EditorExportPlatformPC() {
chmod_flags = -1;
- fixup_embedded_pck_func = NULL;
+ fixup_embedded_pck_func = nullptr;
}
///////////////////////
diff --git a/editor/editor_export.h b/editor/editor_export.h
index 139d672cb8..f47fe9c95e 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -212,7 +212,7 @@ protected:
FeatureContainers get_feature_containers(const Ref<EditorExportPreset> &p_preset);
bool exists_export_template(String template_file_name, String *err) const;
- String find_export_template(String template_file_name, String *err = NULL) const;
+ String find_export_template(String template_file_name, String *err = nullptr) const;
void gen_export_flags(Vector<String> &r_flags, int p_flags);
public:
@@ -238,9 +238,9 @@ public:
virtual String get_name() const = 0;
virtual Ref<Texture2D> get_logo() const = 0;
- Error export_project_files(const Ref<EditorExportPreset> &p_preset, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func = NULL);
+ Error export_project_files(const Ref<EditorExportPreset> &p_preset, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func = nullptr);
- Error save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path, Vector<SharedObject> *p_so_files = NULL, bool p_embed = false, int64_t *r_embedded_start = NULL, int64_t *r_embedded_size = NULL);
+ Error save_pack(const Ref<EditorExportPreset> &p_preset, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
Error save_zip(const Ref<EditorExportPreset> &p_preset, const String &p_path);
virtual bool poll_export() { return false; }
@@ -291,6 +291,7 @@ class EditorExportPlugin : public Reference {
bool skipped;
Vector<String> ios_frameworks;
+ Vector<String> ios_project_static_libs;
String ios_plist_content;
String ios_linker_flags;
Vector<String> ios_bundle_files;
@@ -322,6 +323,7 @@ protected:
void add_shared_object(const String &p_path, const Vector<String> &tags);
void add_ios_framework(const String &p_path);
+ void add_ios_project_static_lib(const String &p_path);
void add_ios_plist_content(const String &p_plist_content);
void add_ios_linker_flags(const String &p_flags);
void add_ios_bundle_file(const String &p_path);
@@ -336,6 +338,7 @@ protected:
public:
Vector<String> get_ios_frameworks() const;
+ Vector<String> get_ios_project_static_libs() const;
String get_ios_plist_content() const;
String get_ios_linker_flags() const;
Vector<String> get_ios_bundle_files() const;
@@ -347,9 +350,9 @@ public:
class EditorExport : public Node {
GDCLASS(EditorExport, Node);
- Vector<Ref<EditorExportPlatform> > export_platforms;
- Vector<Ref<EditorExportPreset> > export_presets;
- Vector<Ref<EditorExportPlugin> > export_plugins;
+ Vector<Ref<EditorExportPlatform>> export_platforms;
+ Vector<Ref<EditorExportPreset>> export_presets;
+ Vector<Ref<EditorExportPlugin>> export_plugins;
Timer *save_timer;
bool block_save;
@@ -379,7 +382,7 @@ public:
void add_export_plugin(const Ref<EditorExportPlugin> &p_plugin);
void remove_export_plugin(const Ref<EditorExportPlugin> &p_plugin);
- Vector<Ref<EditorExportPlugin> > get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> get_export_plugins();
void load_config();
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 959507535b..e2b79efb43 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -153,7 +153,7 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) {
Array dis_props;
- for (Map<StringName, Set<StringName> >::Element *E = disabled_properties.front(); E; E = E->next()) {
+ for (Map<StringName, Set<StringName>>::Element *E = disabled_properties.front(); E; E = E->next()) {
for (Set<StringName>::Element *F = E->get().front(); F; F = F->next()) {
dis_props.push_back(String(E->key()) + ":" + String(F->get()));
}
@@ -420,7 +420,7 @@ void EditorFeatureProfileManager::_profile_action(int p_action) {
} break;
case PROFILE_NEW: {
- new_profile_dialog->popup_centered_minsize();
+ new_profile_dialog->popup_centered();
new_profile_name->clear();
new_profile_name->grab_focus();
} break;
@@ -430,7 +430,7 @@ void EditorFeatureProfileManager::_profile_action(int p_action) {
ERR_FAIL_COND(selected == String());
erase_profile_dialog->set_text(vformat(TTR("Erase profile '%s'? (no undo)"), selected));
- erase_profile_dialog->popup_centered_minsize();
+ erase_profile_dialog->popup_centered();
} break;
}
}
@@ -485,7 +485,7 @@ void EditorFeatureProfileManager::_fill_classes_from(TreeItem *p_parent, const S
bool disabled_editor = edited->is_class_editor_disabled(p_class);
bool disabled_properties = edited->has_class_properties_disabled(p_class);
if (disabled) {
- class_item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
+ class_item->set_custom_color(0, class_list->get_theme_color("disabled_font_color", "Editor"));
} else if (disabled_editor && disabled_properties) {
text += " " + TTR("(Editor Disabled, Properties Disabled)");
} else if (disabled_properties) {
@@ -787,7 +787,7 @@ Ref<EditorFeatureProfile> EditorFeatureProfileManager::get_current_profile() {
return current;
}
-EditorFeatureProfileManager *EditorFeatureProfileManager::singleton = NULL;
+EditorFeatureProfileManager *EditorFeatureProfileManager::singleton = nullptr;
void EditorFeatureProfileManager::_bind_methods() {
@@ -805,7 +805,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
current_profile_name = memnew(LineEdit);
name_hbc->add_child(current_profile_name);
current_profile_name->set_editable(false);
- current_profile_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ current_profile_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
profile_actions[PROFILE_CLEAR] = memnew(Button(TTR("Unset")));
name_hbc->add_child(profile_actions[PROFILE_CLEAR]);
profile_actions[PROFILE_CLEAR]->set_disabled(true);
@@ -815,7 +815,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
HBoxContainer *profiles_hbc = memnew(HBoxContainer);
profile_list = memnew(OptionButton);
- profile_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ profile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
profiles_hbc->add_child(profile_list);
profile_list->connect("item_selected", callable_mp(this, &EditorFeatureProfileManager::_profile_selected));
@@ -849,12 +849,12 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
main_vbc->add_margin_child(TTR("Available Profiles:"), profiles_hbc);
h_split = memnew(HSplitContainer);
- h_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ h_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
main_vbc->add_child(h_split);
VBoxContainer *class_list_vbc = memnew(VBoxContainer);
h_split->add_child(class_list_vbc);
- class_list_vbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ class_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
class_list = memnew(Tree);
class_list_vbc->add_margin_child(TTR("Enabled Classes:"), class_list, true);
@@ -865,7 +865,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
VBoxContainer *property_list_vbc = memnew(VBoxContainer);
h_split->add_child(property_list_vbc);
- property_list_vbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
property_list = memnew(Tree);
property_list_vbc->add_margin_child(TTR("Class Options"), property_list, true);
@@ -891,7 +891,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
import_profiles = memnew(EditorFileDialog);
add_child(import_profiles);
- import_profiles->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ import_profiles->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
import_profiles->add_filter("*.profile; " + TTR("Godot Feature Profile"));
import_profiles->connect("files_selected", callable_mp(this, &EditorFeatureProfileManager::_import_profiles));
import_profiles->set_title(TTR("Import Profile(s)"));
@@ -899,7 +899,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
export_profile = memnew(EditorFileDialog);
add_child(export_profile);
- export_profile->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
export_profile->add_filter("*.profile; " + TTR("Godot Feature Profile"));
export_profile->connect("file_selected", callable_mp(this, &EditorFeatureProfileManager::_export_profile));
export_profile->set_title(TTR("Export Profile"));
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index a5ab73da60..5ae2398027 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -58,7 +58,7 @@ public:
private:
Set<StringName> disabled_classes;
Set<StringName> disabled_editors;
- Map<StringName, Set<StringName> > disabled_properties;
+ Map<StringName, Set<StringName>> disabled_properties;
bool features_disabled[FEATURE_MAX];
static const char *feature_names[FEATURE_MAX];
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 250fa6b3e0..6a06c6657e 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -42,12 +42,13 @@
#include "scene/gui/center_container.h"
#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
+#include "servers/display_server.h"
-EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func = NULL;
-EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func = NULL;
+EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func = nullptr;
+EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func = nullptr;
-EditorFileDialog::RegisterFunc EditorFileDialog::register_func = NULL;
-EditorFileDialog::RegisterFunc EditorFileDialog::unregister_func = NULL;
+EditorFileDialog::RegisterFunc EditorFileDialog::register_func = nullptr;
+EditorFileDialog::RegisterFunc EditorFileDialog::unregister_func = nullptr;
VBoxContainer *EditorFileDialog::get_vbox() {
return vbox;
@@ -58,17 +59,17 @@ void EditorFileDialog::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
// update icons
- mode_thumbnails->set_icon(get_icon("FileThumbnail", "EditorIcons"));
- mode_list->set_icon(get_icon("FileList", "EditorIcons"));
- dir_prev->set_icon(get_icon("Back", "EditorIcons"));
- dir_next->set_icon(get_icon("Forward", "EditorIcons"));
- dir_up->set_icon(get_icon("ArrowUp", "EditorIcons"));
- refresh->set_icon(get_icon("Reload", "EditorIcons"));
- favorite->set_icon(get_icon("Favorites", "EditorIcons"));
- show_hidden->set_icon(get_icon("GuiVisibilityVisible", "EditorIcons"));
-
- fav_up->set_icon(get_icon("MoveUp", "EditorIcons"));
- fav_down->set_icon(get_icon("MoveDown", "EditorIcons"));
+ mode_thumbnails->set_icon(item_list->get_theme_icon("FileThumbnail", "EditorIcons"));
+ mode_list->set_icon(item_list->get_theme_icon("FileList", "EditorIcons"));
+ dir_prev->set_icon(item_list->get_theme_icon("Back", "EditorIcons"));
+ dir_next->set_icon(item_list->get_theme_icon("Forward", "EditorIcons"));
+ dir_up->set_icon(item_list->get_theme_icon("ArrowUp", "EditorIcons"));
+ refresh->set_icon(item_list->get_theme_icon("Reload", "EditorIcons"));
+ favorite->set_icon(item_list->get_theme_icon("Favorites", "EditorIcons"));
+ show_hidden->set_icon(item_list->get_theme_icon("GuiVisibilityVisible", "EditorIcons"));
+
+ fav_up->set_icon(item_list->get_theme_icon("MoveUp", "EditorIcons"));
+ fav_down->set_icon(item_list->get_theme_icon("MoveDown", "EditorIcons"));
} else if (p_what == NOTIFICATION_PROCESS) {
@@ -78,14 +79,11 @@ void EditorFileDialog::_notification(int p_what) {
preview_wheel_index++;
if (preview_wheel_index >= 8)
preview_wheel_index = 0;
- Ref<Texture2D> frame = get_icon("Progress" + itos(preview_wheel_index + 1), "EditorIcons");
+ Ref<Texture2D> frame = item_list->get_theme_icon("Progress" + itos(preview_wheel_index + 1), "EditorIcons");
preview->set_texture(frame);
preview_wheel_timeout = 0.1;
}
}
- } else if (p_what == NOTIFICATION_POPUP_HIDE) {
-
- set_process_unhandled_input(false);
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
@@ -95,18 +93,23 @@ void EditorFileDialog::_notification(int p_what) {
set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
// update icons
- mode_thumbnails->set_icon(get_icon("FileThumbnail", "EditorIcons"));
- mode_list->set_icon(get_icon("FileList", "EditorIcons"));
- dir_prev->set_icon(get_icon("Back", "EditorIcons"));
- dir_next->set_icon(get_icon("Forward", "EditorIcons"));
- dir_up->set_icon(get_icon("ArrowUp", "EditorIcons"));
- refresh->set_icon(get_icon("Reload", "EditorIcons"));
- favorite->set_icon(get_icon("Favorites", "EditorIcons"));
-
- fav_up->set_icon(get_icon("MoveUp", "EditorIcons"));
- fav_down->set_icon(get_icon("MoveDown", "EditorIcons"));
+ mode_thumbnails->set_icon(item_list->get_theme_icon("FileThumbnail", "EditorIcons"));
+ mode_list->set_icon(item_list->get_theme_icon("FileList", "EditorIcons"));
+ dir_prev->set_icon(item_list->get_theme_icon("Back", "EditorIcons"));
+ dir_next->set_icon(item_list->get_theme_icon("Forward", "EditorIcons"));
+ dir_up->set_icon(item_list->get_theme_icon("ArrowUp", "EditorIcons"));
+ refresh->set_icon(item_list->get_theme_icon("Reload", "EditorIcons"));
+ favorite->set_icon(item_list->get_theme_icon("Favorites", "EditorIcons"));
+
+ fav_up->set_icon(item_list->get_theme_icon("MoveUp", "EditorIcons"));
+ fav_down->set_icon(item_list->get_theme_icon("MoveDown", "EditorIcons"));
// DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD
invalidate();
+ } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (!is_visible()) {
+ set_process_unhandled_input(false);
+ }
}
}
@@ -114,7 +117,7 @@ void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && is_window_modal_on_top()) {
+ if (k.is_valid()) {
if (k->is_pressed()) {
@@ -176,7 +179,7 @@ void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
}
if (handled) {
- accept_event();
+ set_input_as_handled();
}
}
}
@@ -208,15 +211,15 @@ void EditorFileDialog::update_dir() {
get_ok()->set_disabled(_is_open_should_be_disabled());
switch (mode) {
- case MODE_OPEN_FILE:
- case MODE_OPEN_FILES:
+ case FILE_MODE_OPEN_FILE:
+ case FILE_MODE_OPEN_FILES:
get_ok()->set_text(TTR("Open"));
break;
- case MODE_OPEN_DIR:
+ case FILE_MODE_OPEN_DIR:
get_ok()->set_text(TTR("Select Current Folder"));
break;
- case MODE_OPEN_ANY:
- case MODE_SAVE_FILE:
+ case FILE_MODE_OPEN_ANY:
+ case FILE_MODE_SAVE_FILE:
// FIXME: Implement, or refactor to avoid duplication with set_mode
break;
}
@@ -251,23 +254,23 @@ void EditorFileDialog::_post_popup() {
update_file_list();
invalidated = false;
}
- if (mode == MODE_SAVE_FILE)
+ if (mode == FILE_MODE_SAVE_FILE)
file->grab_focus();
else
item_list->grab_focus();
- if (mode == MODE_OPEN_DIR) {
+ if (mode == FILE_MODE_OPEN_DIR) {
file_box->set_visible(false);
} else {
file_box->set_visible(true);
}
- if (is_visible_in_tree() && get_current_file() != "")
+ if (is_visible() && get_current_file() != "")
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
- if (is_visible_in_tree()) {
- Ref<Texture2D> folder = get_icon("folder", "FileDialog");
- const Color folder_color = get_color("folder_icon_modulate", "FileDialog");
+ if (is_visible()) {
+ Ref<Texture2D> folder = item_list->get_theme_icon("folder", "FileDialog");
+ const Color folder_color = item_list->get_theme_color("folder_icon_modulate", "FileDialog");
recent->clear();
bool res = access == ACCESS_RESOURCES;
@@ -346,7 +349,7 @@ void EditorFileDialog::_request_single_thumbnail(const String &p_path) {
void EditorFileDialog::_action_pressed() {
- if (mode == MODE_OPEN_FILES) {
+ if (mode == FILE_MODE_OPEN_FILES) {
String fbase = dir_access->get_current_dir();
@@ -367,11 +370,11 @@ void EditorFileDialog::_action_pressed() {
String f = dir_access->get_current_dir().plus_file(file->get_text());
- if ((mode == MODE_OPEN_ANY || mode == MODE_OPEN_FILE) && dir_access->file_exists(f)) {
+ if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
_save_to_recent();
hide();
emit_signal("file_selected", f);
- } else if (mode == MODE_OPEN_ANY || mode == MODE_OPEN_DIR) {
+ } else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) {
String path = dir_access->get_current_dir();
@@ -393,7 +396,7 @@ void EditorFileDialog::_action_pressed() {
emit_signal("dir_selected", path);
}
- if (mode == MODE_SAVE_FILE) {
+ if (mode == FILE_MODE_SAVE_FILE) {
bool valid = false;
@@ -446,7 +449,7 @@ void EditorFileDialog::_action_pressed() {
if (!valid) {
- exterr->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ exterr->popup_centered(Size2(250, 80) * EDSCALE);
return;
}
@@ -481,7 +484,7 @@ void EditorFileDialog::_item_selected(int p_item) {
file->set_text(d["name"]);
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
- } else if (mode == MODE_OPEN_DIR) {
+ } else if (mode == FILE_MODE_OPEN_DIR) {
get_ok()->set_text(TTR("Select This Folder"));
}
@@ -512,19 +515,19 @@ void EditorFileDialog::_items_clear_selection() {
// If nothing is selected, then block Open button.
switch (mode) {
- case MODE_OPEN_FILE:
- case MODE_OPEN_FILES:
+ case FILE_MODE_OPEN_FILE:
+ case FILE_MODE_OPEN_FILES:
get_ok()->set_text(TTR("Open"));
get_ok()->set_disabled(!item_list->is_anything_selected());
break;
- case MODE_OPEN_DIR:
+ case FILE_MODE_OPEN_DIR:
get_ok()->set_disabled(false);
get_ok()->set_text(TTR("Select Current Folder"));
break;
- case MODE_OPEN_ANY:
- case MODE_SAVE_FILE:
+ case FILE_MODE_OPEN_ANY:
+ case FILE_MODE_SAVE_FILE:
// FIXME: Implement, or refactor to avoid duplication with set_mode
break;
}
@@ -586,16 +589,16 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p
}
if (single_item_selected) {
- item_menu->add_icon_item(get_icon("ActionCopy", "EditorIcons"), TTR("Copy Path"), ITEM_MENU_COPY_PATH);
+ item_menu->add_icon_item(item_list->get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Path"), ITEM_MENU_COPY_PATH);
}
if (allow_delete) {
- item_menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete"), ITEM_MENU_DELETE, KEY_DELETE);
+ item_menu->add_icon_item(item_list->get_theme_icon("Remove", "EditorIcons"), TTR("Delete"), ITEM_MENU_DELETE, KEY_DELETE);
}
if (single_item_selected) {
item_menu->add_separator();
Dictionary item_meta = item_list->get_item_metadata(p_item);
String item_text = item_meta["dir"] ? TTR("Open in File Manager") : TTR("Show in File Manager");
- item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(item_list->get_theme_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER);
}
if (item_menu->get_item_count() > 0) {
@@ -615,11 +618,11 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) {
item_menu->set_size(Size2(1, 1));
if (can_create_dir) {
- item_menu->add_icon_item(get_icon("folder", "FileDialog"), TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KEY_MASK_CMD | KEY_N);
+ item_menu->add_icon_item(item_list->get_theme_icon("folder", "FileDialog"), TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KEY_MASK_CMD | KEY_N);
}
- item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5);
+ item_menu->add_icon_item(item_list->get_theme_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5);
item_menu->add_separator();
- item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(item_list->get_theme_icon("Filesystem", "EditorIcons"), TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
item_menu->set_position(item_list->get_global_position() + p_pos);
item_menu->popup();
@@ -631,7 +634,7 @@ void EditorFileDialog::_item_menu_id_pressed(int p_option) {
case ITEM_MENU_COPY_PATH: {
Dictionary item_meta = item_list->get_item_metadata(item_list->get_current());
- OS::get_singleton()->set_clipboard(item_meta["path"]);
+ DisplayServer::get_singleton()->clipboard_set(item_meta["path"]);
} break;
case ITEM_MENU_DELETE: {
@@ -667,18 +670,18 @@ void EditorFileDialog::_item_menu_id_pressed(int p_option) {
bool EditorFileDialog::_is_open_should_be_disabled() {
- if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE)
+ if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_SAVE_FILE)
return false;
Vector<int> items = item_list->get_selected_items();
if (items.size() == 0)
- return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder.
+ return mode != FILE_MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder.
for (int i = 0; i < items.size(); i++) {
Dictionary d = item_list->get_item_metadata(items.get(i));
- if (((mode == MODE_OPEN_FILE || mode == MODE_OPEN_FILES) && d["dir"]) || (mode == MODE_OPEN_DIR && !d["dir"]))
+ if (((mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES) && d["dir"]) || (mode == FILE_MODE_OPEN_DIR && !d["dir"]))
return true;
}
@@ -724,11 +727,11 @@ void EditorFileDialog::update_file_list() {
item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
if (thumbnail_size < 64) {
- folder_thumbnail = get_icon("FolderMediumThumb", "EditorIcons");
- file_thumbnail = get_icon("FileMediumThumb", "EditorIcons");
+ folder_thumbnail = item_list->get_theme_icon("FolderMediumThumb", "EditorIcons");
+ file_thumbnail = item_list->get_theme_icon("FileMediumThumb", "EditorIcons");
} else {
- folder_thumbnail = get_icon("FolderBigThumb", "EditorIcons");
- file_thumbnail = get_icon("FileBigThumb", "EditorIcons");
+ folder_thumbnail = item_list->get_theme_icon("FolderBigThumb", "EditorIcons");
+ file_thumbnail = item_list->get_theme_icon("FileBigThumb", "EditorIcons");
}
preview_vb->hide();
@@ -748,8 +751,8 @@ void EditorFileDialog::update_file_list() {
dir_access->list_dir_begin();
- Ref<Texture2D> folder = get_icon("folder", "FileDialog");
- const Color folder_color = get_color("folder_icon_modulate", "FileDialog");
+ Ref<Texture2D> folder = item_list->get_theme_icon("folder", "FileDialog");
+ const Color folder_color = item_list->get_theme_color("folder_icon_modulate", "FileDialog");
List<String> files;
List<String> dirs;
@@ -978,7 +981,7 @@ void EditorFileDialog::set_current_file(const String &p_file) {
file->grab_focus();
}
- if (is_visible_in_tree())
+ if (is_visible())
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
}
void EditorFileDialog::set_current_path(const String &p_path) {
@@ -998,39 +1001,39 @@ void EditorFileDialog::set_current_path(const String &p_path) {
}
}
-void EditorFileDialog::set_mode(Mode p_mode) {
+void EditorFileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
- case MODE_OPEN_FILE:
+ case FILE_MODE_OPEN_FILE:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open a File"));
can_create_dir = false;
break;
- case MODE_OPEN_FILES:
+ case FILE_MODE_OPEN_FILES:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open File(s)"));
can_create_dir = false;
break;
- case MODE_OPEN_DIR:
+ case FILE_MODE_OPEN_DIR:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open a Directory"));
can_create_dir = true;
break;
- case MODE_OPEN_ANY:
+ case FILE_MODE_OPEN_ANY:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open a File or Directory"));
can_create_dir = true;
break;
- case MODE_SAVE_FILE:
+ case FILE_MODE_SAVE_FILE:
get_ok()->set_text(TTR("Save"));
set_title(TTR("Save a File"));
can_create_dir = true;
break;
}
- if (mode == MODE_OPEN_FILES) {
+ if (mode == FILE_MODE_OPEN_FILES) {
item_list->set_select_mode(ItemList::SELECT_MULTI);
} else {
item_list->set_select_mode(ItemList::SELECT_SINGLE);
@@ -1043,7 +1046,7 @@ void EditorFileDialog::set_mode(Mode p_mode) {
}
}
-EditorFileDialog::Mode EditorFileDialog::get_mode() const {
+EditorFileDialog::FileMode EditorFileDialog::get_file_mode() const {
return mode;
}
@@ -1077,7 +1080,7 @@ void EditorFileDialog::set_access(Access p_access) {
void EditorFileDialog::invalidate() {
- if (is_visible_in_tree()) {
+ if (is_visible()) {
update_file_list();
_update_favorites();
invalidated = false;
@@ -1102,14 +1105,14 @@ void EditorFileDialog::_make_dir_confirm() {
_push_history();
EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes
} else {
- mkdirerr->popup_centered_minsize(Size2(250, 50) * EDSCALE);
+ mkdirerr->popup_centered(Size2(250, 50) * EDSCALE);
}
makedirname->set_text(""); // reset label
}
void EditorFileDialog::_make_dir() {
- makedialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ makedialog->popup_centered(Size2(250, 80) * EDSCALE);
makedirname->grab_focus();
}
@@ -1224,8 +1227,8 @@ void EditorFileDialog::_update_favorites() {
bool res = access == ACCESS_RESOURCES;
String current = get_current_dir();
- Ref<Texture2D> folder_icon = get_icon("Folder", "EditorIcons");
- const Color folder_color = get_color("folder_icon_modulate", "FileDialog");
+ Ref<Texture2D> folder_icon = item_list->get_theme_icon("Folder", "EditorIcons");
+ const Color folder_color = item_list->get_theme_color("folder_icon_modulate", "FileDialog");
favorites->clear();
favorite->set_pressed(false);
@@ -1383,8 +1386,8 @@ void EditorFileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_dir", "dir"), &EditorFileDialog::set_current_dir);
ClassDB::bind_method(D_METHOD("set_current_file", "file"), &EditorFileDialog::set_current_file);
ClassDB::bind_method(D_METHOD("set_current_path", "path"), &EditorFileDialog::set_current_path);
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &EditorFileDialog::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &EditorFileDialog::get_mode);
+ ClassDB::bind_method(D_METHOD("set_file_mode", "mode"), &EditorFileDialog::set_file_mode);
+ ClassDB::bind_method(D_METHOD("get_file_mode"), &EditorFileDialog::get_file_mode);
ClassDB::bind_method(D_METHOD("get_vbox"), &EditorFileDialog::get_vbox);
ClassDB::bind_method(D_METHOD("set_access", "access"), &EditorFileDialog::set_access);
ClassDB::bind_method(D_METHOD("get_access"), &EditorFileDialog::get_access);
@@ -1408,18 +1411,18 @@ void EditorFileDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access");
ADD_PROPERTY(PropertyInfo(Variant::INT, "display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"), "set_display_mode", "get_display_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "file_mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_file_mode", "get_file_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR), "set_current_dir", "get_current_dir");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*"), "set_current_file", "get_current_file");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path"), "set_current_path", "get_current_path");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_overwrite_warning"), "set_disable_overwrite_warning", "is_overwrite_warning_disabled");
- BIND_ENUM_CONSTANT(MODE_OPEN_FILE);
- BIND_ENUM_CONSTANT(MODE_OPEN_FILES);
- BIND_ENUM_CONSTANT(MODE_OPEN_DIR);
- BIND_ENUM_CONSTANT(MODE_OPEN_ANY);
- BIND_ENUM_CONSTANT(MODE_SAVE_FILE);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILE);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILES);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_DIR);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_ANY);
+ BIND_ENUM_CONSTANT(FILE_MODE_SAVE_FILE);
BIND_ENUM_CONSTANT(ACCESS_RESOURCES);
BIND_ENUM_CONSTANT(ACCESS_USERDATA);
@@ -1483,8 +1486,6 @@ bool EditorFileDialog::is_overwrite_warning_disabled() const {
EditorFileDialog::EditorFileDialog() {
- set_resizable(true);
-
show_hidden_files = default_show_hidden_files;
display_mode = default_display_mode;
local_history_pos = 0;
@@ -1492,7 +1493,7 @@ EditorFileDialog::EditorFileDialog() {
VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
- mode = MODE_SAVE_FILE;
+ mode = FILE_MODE_SAVE_FILE;
set_title(TTR("Save a File"));
ED_SHORTCUT("file_dialog/go_back", TTR("Go Back"), KEY_MASK_ALT | KEY_LEFT);
@@ -1532,7 +1533,7 @@ EditorFileDialog::EditorFileDialog() {
dir = memnew(LineEdit);
pathhb->add_child(dir);
- dir->set_h_size_flags(SIZE_EXPAND_FILL);
+ dir->set_h_size_flags(Control::SIZE_EXPAND_FILL);
refresh = memnew(ToolButton);
refresh->set_tooltip(TTR("Refresh files."));
@@ -1578,6 +1579,7 @@ EditorFileDialog::EditorFileDialog() {
drives = memnew(OptionButton);
drives->connect("item_selected", callable_mp(this, &EditorFileDialog::_select_drive));
+ pathhb->add_child(drives);
makedir = memnew(Button);
makedir->set_text(TTR("Create Folder"));
@@ -1588,7 +1590,7 @@ EditorFileDialog::EditorFileDialog() {
vbc->add_child(pathhb);
vbc->add_child(list_hb);
- list_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+ list_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
VSplitContainer *vsc = memnew(VSplitContainer);
list_hb->add_child(vsc);
@@ -1596,7 +1598,7 @@ EditorFileDialog::EditorFileDialog() {
VBoxContainer *fav_vb = memnew(VBoxContainer);
vsc->add_child(fav_vb);
fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
- fav_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ fav_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
HBoxContainer *fav_hb = memnew(HBoxContainer);
fav_vb->add_child(fav_hb);
fav_hb->add_child(memnew(Label(TTR("Favorites:"))));
@@ -1610,13 +1612,13 @@ EditorFileDialog::EditorFileDialog() {
favorites = memnew(ItemList);
fav_vb->add_child(favorites);
- favorites->set_v_size_flags(SIZE_EXPAND_FILL);
+ favorites->set_v_size_flags(Control::SIZE_EXPAND_FILL);
favorites->connect("item_selected", callable_mp(this, &EditorFileDialog::_favorite_selected));
VBoxContainer *rec_vb = memnew(VBoxContainer);
vsc->add_child(rec_vb);
rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
- rec_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ rec_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
recent = memnew(ItemList);
recent->set_allow_reselect(true);
rec_vb->add_margin_child(TTR("Recent:"), recent, true);
@@ -1627,18 +1629,18 @@ EditorFileDialog::EditorFileDialog() {
item_vb->set_custom_minimum_size(Size2(320, 0) * EDSCALE);
HBoxContainer *preview_hb = memnew(HBoxContainer);
- preview_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+ preview_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
item_vb->add_child(preview_hb);
VBoxContainer *list_vb = memnew(VBoxContainer);
- list_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ list_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
list_vb->add_child(memnew(Label(TTR("Directories & Files:"))));
preview_hb->add_child(list_vb);
// Item (files and folders) list with context menu.
item_list = memnew(ItemList);
- item_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ item_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
item_list->connect("item_rmb_selected", callable_mp(this, &EditorFileDialog::_item_list_item_rmb_selected));
item_list->connect("rmb_clicked", callable_mp(this, &EditorFileDialog::_item_list_rmb_clicked));
item_list->set_allow_rmb_select(true);
@@ -1662,14 +1664,14 @@ EditorFileDialog::EditorFileDialog() {
file_box->add_child(memnew(Label(TTR("File:"))));
file = memnew(LineEdit);
file->set_stretch_ratio(4);
- file->set_h_size_flags(SIZE_EXPAND_FILL);
+ file->set_h_size_flags(Control::SIZE_EXPAND_FILL);
file_box->add_child(file);
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);
- filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->set_clip_text(true); // Too many extensions overflow it.
file_box->add_child(filter);
- file_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ file_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
item_vb->add_child(file_box);
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
@@ -1686,7 +1688,7 @@ EditorFileDialog::EditorFileDialog() {
filter->connect("item_selected", callable_mp(this, &EditorFileDialog::_filter_selected));
confirm_save = memnew(ConfirmationDialog);
- confirm_save->set_as_toplevel(true);
+ //confirm_save->set_as_toplevel(true);
add_child(confirm_save);
confirm_save->connect("confirmed", callable_mp(this, &EditorFileDialog::_save_confirm_pressed));
@@ -1732,42 +1734,3 @@ EditorFileDialog::~EditorFileDialog() {
unregister_func(this);
memdelete(dir_access);
}
-
-void EditorLineEditFileChooser::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED)
- button->set_icon(get_icon("Folder", "EditorIcons"));
-}
-
-void EditorLineEditFileChooser::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_button"), &EditorLineEditFileChooser::get_button);
- ClassDB::bind_method(D_METHOD("get_line_edit"), &EditorLineEditFileChooser::get_line_edit);
- ClassDB::bind_method(D_METHOD("get_file_dialog"), &EditorLineEditFileChooser::get_file_dialog);
-}
-
-void EditorLineEditFileChooser::_chosen(const String &p_text) {
-
- line_edit->set_text(p_text);
- line_edit->emit_signal("text_entered", p_text);
-}
-
-void EditorLineEditFileChooser::_browse() {
-
- dialog->popup_centered_ratio();
-}
-
-EditorLineEditFileChooser::EditorLineEditFileChooser() {
-
- line_edit = memnew(LineEdit);
- add_child(line_edit);
- line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- button = memnew(Button);
- add_child(button);
- button->connect("pressed", callable_mp(this, &EditorLineEditFileChooser::_browse));
- dialog = memnew(EditorFileDialog);
- add_child(dialog);
- dialog->connect("file_selected", callable_mp(this, &EditorLineEditFileChooser::_chosen));
- dialog->connect("dir_selected", callable_mp(this, &EditorLineEditFileChooser::_chosen));
- dialog->connect("files_selected", callable_mp(this, &EditorLineEditFileChooser::_chosen));
-}
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 998ac33761..8efb8f5368 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -60,12 +60,12 @@ public:
ACCESS_FILESYSTEM
};
- enum Mode {
- MODE_OPEN_FILE,
- MODE_OPEN_FILES,
- MODE_OPEN_DIR,
- MODE_OPEN_ANY,
- MODE_SAVE_FILE
+ enum FileMode {
+ FILE_MODE_OPEN_FILE,
+ FILE_MODE_OPEN_FILES,
+ FILE_MODE_OPEN_DIR,
+ FILE_MODE_OPEN_ANY,
+ FILE_MODE_SAVE_FILE
};
typedef Ref<Texture2D> (*GetIconFunc)(const String &);
@@ -92,7 +92,7 @@ private:
Access access;
//Button *action;
VBoxContainer *vbox;
- Mode mode;
+ FileMode mode;
bool can_create_dir;
LineEdit *dir;
@@ -221,8 +221,8 @@ public:
void set_display_mode(DisplayMode p_mode);
DisplayMode get_display_mode() const;
- void set_mode(Mode p_mode);
- Mode get_mode() const;
+ void set_file_mode(FileMode p_mode);
+ FileMode get_file_mode() const;
VBoxContainer *get_vbox();
LineEdit *get_line_edit() { return file; }
@@ -245,29 +245,7 @@ public:
~EditorFileDialog();
};
-class EditorLineEditFileChooser : public HBoxContainer {
-
- GDCLASS(EditorLineEditFileChooser, HBoxContainer);
- Button *button;
- LineEdit *line_edit;
- EditorFileDialog *dialog;
-
- void _chosen(const String &p_text);
- void _browse();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- Button *get_button() { return button; }
- LineEdit *get_line_edit() { return line_edit; }
- EditorFileDialog *get_file_dialog() { return dialog; }
-
- EditorLineEditFileChooser();
-};
-
-VARIANT_ENUM_CAST(EditorFileDialog::Mode);
+VARIANT_ENUM_CAST(EditorFileDialog::FileMode);
VARIANT_ENUM_CAST(EditorFileDialog::Access);
VARIANT_ENUM_CAST(EditorFileDialog::DisplayMode);
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index b5ec08ef60..c211d5852a 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -41,7 +41,7 @@
#include "editor_resource_preview.h"
#include "editor_settings.h"
-EditorFileSystem *EditorFileSystem::singleton = NULL;
+EditorFileSystem *EditorFileSystem::singleton = nullptr;
//the name is the version, to keep compatibility with different versions of Godot
#define CACHE_FILE_NAME "filesystem_cache6"
@@ -75,7 +75,7 @@ int EditorFileSystemDirectory::get_subdir_count() const {
EditorFileSystemDirectory *EditorFileSystemDirectory::get_subdir(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, subdirs.size(), NULL);
+ ERR_FAIL_INDEX_V(p_idx, subdirs.size(), nullptr);
return subdirs[p_idx];
}
@@ -176,7 +176,7 @@ void EditorFileSystemDirectory::_bind_methods() {
EditorFileSystemDirectory::EditorFileSystemDirectory() {
modified_time = 0;
- parent = NULL;
+ parent = nullptr;
verified = false;
}
@@ -300,7 +300,7 @@ void EditorFileSystem::_scan_filesystem() {
sp.progress = &scan_progress;
new_filesystem = memnew(EditorFileSystemDirectory);
- new_filesystem->parent = NULL;
+ new_filesystem->parent = nullptr;
DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
d->change_dir("res://");
@@ -383,7 +383,7 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
break;
} else if (err != OK) {
@@ -430,7 +430,7 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&md5_stream, lines, error_text, next_tag, assign, value, NULL, true);
+ err = VariantParser::parse_tag_assign_eof(&md5_stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) {
break;
@@ -622,7 +622,7 @@ void EditorFileSystem::scan() {
memdelete(filesystem);
//file_type_cache.clear();
filesystem = new_filesystem;
- new_filesystem = NULL;
+ new_filesystem = nullptr;
_update_scan_actions();
scanning = false;
emit_signal("filesystem_changed");
@@ -1124,8 +1124,8 @@ void EditorFileSystem::_notification(int p_what) {
}
Thread::wait_to_finish(active_thread);
memdelete(active_thread);
- thread = NULL;
- thread_sources = NULL;
+ thread = nullptr;
+ thread_sources = nullptr;
WARN_PRINT("Scan thread aborted...");
set_process(false);
}
@@ -1134,8 +1134,8 @@ void EditorFileSystem::_notification(int p_what) {
memdelete(filesystem);
if (new_filesystem)
memdelete(new_filesystem);
- filesystem = NULL;
- new_filesystem = NULL;
+ filesystem = nullptr;
+ new_filesystem = nullptr;
} break;
case NOTIFICATION_PROCESS: {
@@ -1152,7 +1152,7 @@ void EditorFileSystem::_notification(int p_what) {
Thread::wait_to_finish(thread_sources);
memdelete(thread_sources);
- thread_sources = NULL;
+ thread_sources = nullptr;
if (_update_scan_actions())
emit_signal("filesystem_changed");
emit_signal("sources_changed", sources_changed.size() > 0);
@@ -1166,10 +1166,10 @@ void EditorFileSystem::_notification(int p_what) {
if (filesystem)
memdelete(filesystem);
filesystem = new_filesystem;
- new_filesystem = NULL;
+ new_filesystem = nullptr;
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
_update_scan_actions();
emit_signal("filesystem_changed");
emit_signal("sources_changed", sources_changed.size() > 0);
@@ -1308,7 +1308,7 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
String EditorFileSystem::get_file_type(const String &p_file) const {
- EditorFileSystemDirectory *fs = NULL;
+ EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
if (!_find_file(p_file, &fs, cpos)) {
@@ -1322,13 +1322,13 @@ String EditorFileSystem::get_file_type(const String &p_file) const {
EditorFileSystemDirectory *EditorFileSystem::find_file(const String &p_file, int *r_index) const {
if (!filesystem || scanning)
- return NULL;
+ return nullptr;
- EditorFileSystemDirectory *fs = NULL;
+ EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
if (!_find_file(p_file, &fs, cpos)) {
- return NULL;
+ return nullptr;
}
if (r_index)
@@ -1340,12 +1340,12 @@ EditorFileSystemDirectory *EditorFileSystem::find_file(const String &p_file, int
EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p_path) {
if (!filesystem || scanning)
- return NULL;
+ return nullptr;
String f = ProjectSettings::get_singleton()->localize_path(p_path);
if (!f.begins_with("res://"))
- return NULL;
+ return nullptr;
f = f.substr(6, f.length());
f = f.replace("\\", "/");
@@ -1358,7 +1358,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
Vector<String> path = f.split("/");
if (path.size() == 0)
- return NULL;
+ return nullptr;
EditorFileSystemDirectory *fs = filesystem;
@@ -1374,7 +1374,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
}
if (idx == -1) {
- return NULL;
+ return nullptr;
} else {
fs = fs->get_subdir(idx);
@@ -1483,7 +1483,7 @@ void EditorFileSystem::_queue_update_script_classes() {
void EditorFileSystem::update_file(const String &p_file) {
- EditorFileSystemDirectory *fs = NULL;
+ EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
if (!_find_file(p_file, &fs, cpos)) {
@@ -1558,7 +1558,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
String importer_name;
- Map<String, Map<StringName, Variant> > source_file_options;
+ Map<String, Map<StringName, Variant>> source_file_options;
Map<String, String> base_paths;
for (int i = 0; i < p_files.size(); i++) {
@@ -1610,7 +1610,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
Error err = importer->import_group_file(p_group_file, source_file_options, base_paths);
//all went well, overwrite config files with proper remaps and md5s
- for (Map<String, Map<StringName, Variant> >::Element *E = source_file_options.front(); E; E = E->next()) {
+ for (Map<String, Map<StringName, Variant>>::Element *E = source_file_options.front(); E; E = E->next()) {
const String &file = E->key();
String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(file);
@@ -1684,7 +1684,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
}
md5s->close();
- EditorFileSystemDirectory *fs = NULL;
+ EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
bool found = _find_file(file, &fs, cpos);
ERR_FAIL_COND_V_MSG(!found, ERR_UNCONFIGURED, "Can't find file '" + file + "'.");
@@ -1718,7 +1718,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
void EditorFileSystem::_reimport_file(const String &p_file) {
- EditorFileSystemDirectory *fs = NULL;
+ EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
bool found = _find_file(p_file, &fs, cpos);
ERR_FAIL_COND_MSG(!found, "Can't find file '" + p_file + "'.");
@@ -1921,7 +1921,7 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
}
-void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String> > &group_files, Set<String> &groups_to_reimport) {
+void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String>> &group_files, Set<String> &groups_to_reimport) {
int fc = efd->files.size();
const EditorFileSystemDirectory::FileInfo *const *files = efd->files.ptr();
@@ -1980,7 +1980,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
}
//group may have changed, so also update group reference
- EditorFileSystemDirectory *fs = NULL;
+ EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
if (_find_file(p_files[i], &fs, cpos)) {
@@ -1998,9 +1998,9 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
//reimport groups
if (groups_to_reimport.size()) {
- Map<String, Vector<String> > group_files;
+ Map<String, Vector<String>> group_files;
_find_group_files(filesystem, group_files, groups_to_reimport);
- for (Map<String, Vector<String> >::Element *E = group_files.front(); E; E = E->next()) {
+ for (Map<String, Vector<String>>::Element *E = group_files.front(); E; E = E->next()) {
Error err = _reimport_group(E->key(), E->get());
if (err == OK) {
@@ -2131,14 +2131,14 @@ EditorFileSystem::EditorFileSystem() {
singleton = this;
filesystem = memnew(EditorFileSystemDirectory); //like, empty
- filesystem->parent = NULL;
+ filesystem->parent = nullptr;
- thread = NULL;
+ thread = nullptr;
scanning = false;
importing = false;
use_threads = true;
- thread_sources = NULL;
- new_filesystem = NULL;
+ thread_sources = nullptr;
+ new_filesystem = nullptr;
abort_scan = false;
scanning_changes = false;
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 381acc0fe2..55a2ed3d09 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -129,9 +129,9 @@ class EditorFileSystem : public Node {
ItemAction() {
action = ACTION_NONE;
- dir = NULL;
- new_dir = NULL;
- new_file = NULL;
+ dir = nullptr;
+ new_dir = nullptr;
+ new_file = nullptr;
}
};
@@ -240,7 +240,7 @@ class EditorFileSystem : public Node {
bool using_fat32_or_exfat; // Workaround for projects in FAT32 or exFAT filesystem (pendrives, most of the time)
- void _find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String> > &group_files, Set<String> &groups_to_reimport);
+ void _find_group_files(EditorFileSystemDirectory *efd, Map<String, Vector<String>> &group_files, Set<String> &groups_to_reimport);
void _move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location);
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index 171b7a2176..8aadf02ea6 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -231,7 +231,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
// Default font
MAKE_DEFAULT_FONT(df, default_font_size);
- p_theme->set_default_theme_font(df);
+ p_theme->set_font("font", "Node", df); // Default theme font
p_theme->set_font("main", "EditorFonts", df);
// Bold font
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index b26fa77e16..a36e2f360e 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -30,7 +30,7 @@
#include "editor_help.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "doc_data_compressed.gen.h"
#include "editor/plugins/script_editor_plugin.h"
@@ -39,24 +39,22 @@
#include "editor_settings.h"
#define CONTRIBUTE_URL "https://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html"
-#define CONTRIBUTE2_URL "https://github.com/godotengine/godot-docs"
-#define REQUEST_URL "https://github.com/godotengine/godot-docs/issues/new"
-DocData *EditorHelp::doc = NULL;
+DocData *EditorHelp::doc = nullptr;
void EditorHelp::_init_colors() {
- title_color = get_color("accent_color", "Editor");
- text_color = get_color("default_color", "RichTextLabel");
- headline_color = get_color("headline_color", "EditorHelp");
+ title_color = get_theme_color("accent_color", "Editor");
+ text_color = get_theme_color("default_color", "RichTextLabel");
+ headline_color = get_theme_color("headline_color", "EditorHelp");
base_type_color = title_color.linear_interpolate(text_color, 0.5);
comment_color = text_color * Color(1, 1, 1, 0.6);
symbol_color = comment_color;
value_color = text_color * Color(1, 1, 1, 0.6);
qualifier_color = text_color * Color(1, 1, 1, 0.8);
- type_color = get_color("accent_color", "Editor").linear_interpolate(text_color, 0.5);
- class_desc->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
- class_desc->add_constant_override("line_separation", Math::round(5 * EDSCALE));
+ type_color = get_theme_color("accent_color", "Editor").linear_interpolate(text_color, 0.5);
+ class_desc->add_theme_color_override("selection_color", get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
+ class_desc->add_theme_constant_override("line_separation", Math::round(5 * EDSCALE));
}
void EditorHelp::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
@@ -109,7 +107,7 @@ void EditorHelp::_class_desc_select(const String &p_select) {
String link = p_select.substr(tag_end + 1, p_select.length()).lstrip(" ");
String topic;
- Map<String, int> *table = NULL;
+ Map<String, int> *table = nullptr;
if (tag == "method") {
topic = "class_method";
@@ -173,14 +171,14 @@ void EditorHelp::_class_desc_input(const Ref<InputEvent> &p_input) {
void EditorHelp::_class_desc_resized() {
// Add extra horizontal margins for better readability.
// The margins increase as the width of the editor help container increases.
- Ref<Font> doc_code_font = get_font("doc_source", "EditorFonts");
+ Ref<Font> doc_code_font = get_theme_font("doc_source", "EditorFonts");
real_t char_width = doc_code_font->get_char_size('x').width;
const int display_margin = MAX(30 * EDSCALE, get_parent_anchorable_rect().size.width - char_width * 120 * EDSCALE) * 0.5;
- Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_stylebox("normal", "RichTextLabel")->duplicate();
+ Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox("normal", "RichTextLabel")->duplicate();
class_desc_stylebox->set_default_margin(MARGIN_LEFT, display_margin);
class_desc_stylebox->set_default_margin(MARGIN_RIGHT, display_margin);
- class_desc->add_style_override("normal", class_desc_stylebox);
+ class_desc->add_theme_style_override("normal", class_desc_stylebox);
}
void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
@@ -197,8 +195,8 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
t = p_enum.get_slice(".", 0);
}
}
- const Color text_color = get_color("default_color", "RichTextLabel");
- const Color type_color = get_color("accent_color", "Editor").linear_interpolate(text_color, 0.5);
+ const Color text_color = get_theme_color("default_color", "RichTextLabel");
+ const Color type_color = get_theme_color("accent_color", "Editor").linear_interpolate(text_color, 0.5);
class_desc->push_color(type_color);
if (can_ref) {
if (p_enum.empty()) {
@@ -346,10 +344,10 @@ void EditorHelp::_update_doc() {
DocData::ClassDoc cd = doc->class_list[edited_class]; //make a copy, so we can sort without worrying
- Ref<Font> doc_font = get_font("doc", "EditorFonts");
- Ref<Font> doc_bold_font = get_font("doc_bold", "EditorFonts");
- Ref<Font> doc_title_font = get_font("doc_title", "EditorFonts");
- Ref<Font> doc_code_font = get_font("doc_source", "EditorFonts");
+ Ref<Font> doc_font = get_theme_font("doc", "EditorFonts");
+ Ref<Font> doc_bold_font = get_theme_font("doc_bold", "EditorFonts");
+ Ref<Font> doc_title_font = get_theme_font("doc_title", "EditorFonts");
+ Ref<Font> doc_code_font = get_theme_font("doc_source", "EditorFonts");
String link_color_text = title_color.to_html(false);
// Class name
@@ -433,7 +431,7 @@ void EditorHelp::_update_doc() {
class_desc->push_color(text_color);
class_desc->push_font(doc_bold_font);
class_desc->push_indent(1);
- _add_text(cd.brief_description);
+ _add_text(DTR(cd.brief_description));
class_desc->pop();
class_desc->pop();
class_desc->pop();
@@ -458,7 +456,7 @@ void EditorHelp::_update_doc() {
class_desc->push_color(text_color);
class_desc->push_font(doc_font);
class_desc->push_indent(1);
- _add_text(cd.description);
+ _add_text(DTR(cd.description));
class_desc->pop();
class_desc->pop();
class_desc->pop();
@@ -480,7 +478,7 @@ void EditorHelp::_update_doc() {
class_desc->add_newline();
for (int i = 0; i < cd.tutorials.size(); i++) {
- const String link = cd.tutorials[i];
+ const String link = DTR(cd.tutorials[i]);
String linktxt = link;
const int seppos = linktxt.find("//");
if (seppos != -1) {
@@ -726,7 +724,7 @@ void EditorHelp::_update_doc() {
class_desc->push_font(doc_font);
class_desc->add_text(" ");
class_desc->push_color(comment_color);
- _add_text(cd.theme_properties[i].description);
+ _add_text(DTR(cd.theme_properties[i].description));
class_desc->pop();
class_desc->pop();
}
@@ -796,7 +794,7 @@ void EditorHelp::_update_doc() {
class_desc->push_font(doc_font);
class_desc->push_color(comment_color);
class_desc->push_indent(1);
- _add_text(cd.signals[i].description);
+ _add_text(DTR(cd.signals[i].description));
class_desc->pop(); // indent
class_desc->pop();
class_desc->pop(); // font
@@ -812,7 +810,7 @@ void EditorHelp::_update_doc() {
// Constants and enums
if (cd.constants.size()) {
- Map<String, Vector<DocData::ConstantDoc> > enums;
+ Map<String, Vector<DocData::ConstantDoc>> enums;
Vector<DocData::ConstantDoc> constants;
for (int i = 0; i < cd.constants.size(); i++) {
@@ -842,7 +840,7 @@ void EditorHelp::_update_doc() {
class_desc->add_newline();
- for (Map<String, Vector<DocData::ConstantDoc> >::Element *E = enums.front(); E; E = E->next()) {
+ for (Map<String, Vector<DocData::ConstantDoc>>::Element *E = enums.front(); E; E = E->next()) {
enum_line[E->key()] = class_desc->get_line_count() - 2;
@@ -893,7 +891,7 @@ void EditorHelp::_update_doc() {
//class_desc->add_text(" ");
class_desc->push_indent(1);
class_desc->push_color(comment_color);
- _add_text(enum_list[i].description);
+ _add_text(DTR(enum_list[i].description));
class_desc->pop();
class_desc->pop();
class_desc->pop(); // indent
@@ -959,7 +957,7 @@ void EditorHelp::_update_doc() {
class_desc->push_font(doc_font);
class_desc->push_indent(1);
class_desc->push_color(comment_color);
- _add_text(constants[i].description);
+ _add_text(DTR(constants[i].description));
class_desc->pop();
class_desc->pop();
class_desc->pop(); // indent
@@ -1070,9 +1068,9 @@ void EditorHelp::_update_doc() {
class_desc->push_font(doc_font);
class_desc->push_indent(1);
if (cd.properties[i].description.strip_edges() != String()) {
- _add_text(cd.properties[i].description);
+ _add_text(DTR(cd.properties[i].description));
} else {
- class_desc->add_image(get_icon("Error", "EditorIcons"));
+ class_desc->add_image(get_theme_icon("Error", "EditorIcons"));
class_desc->add_text(" ");
class_desc->push_color(comment_color);
class_desc->append_bbcode(TTR("There is currently no description for this property. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text));
@@ -1123,9 +1121,9 @@ void EditorHelp::_update_doc() {
class_desc->push_font(doc_font);
class_desc->push_indent(1);
if (methods_filtered[i].description.strip_edges() != String()) {
- _add_text(methods_filtered[i].description);
+ _add_text(DTR(methods_filtered[i].description));
} else {
- class_desc->add_image(get_icon("Error", "EditorIcons"));
+ class_desc->add_image(get_theme_icon("Error", "EditorIcons"));
class_desc->add_text(" ");
class_desc->push_color(comment_color);
class_desc->append_bbcode(TTR("There is currently no description for this method. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text));
@@ -1188,7 +1186,7 @@ void EditorHelp::_help_callback(const String &p_topic) {
if (constant_line.has(name))
line = constant_line[name];
else {
- Map<String, Map<String, int> >::Element *iter = enum_values_line.front();
+ Map<String, Map<String, int>>::Element *iter = enum_values_line.front();
while (true) {
if (iter->value().has(name)) {
line = iter->value()[name];
@@ -1209,12 +1207,12 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
DocData *doc = EditorHelp::get_doc_data();
String base_path;
- Ref<Font> doc_font = p_rt->get_font("doc", "EditorFonts");
- Ref<Font> doc_bold_font = p_rt->get_font("doc_bold", "EditorFonts");
- Ref<Font> doc_code_font = p_rt->get_font("doc_source", "EditorFonts");
+ Ref<Font> doc_font = p_rt->get_theme_font("doc", "EditorFonts");
+ Ref<Font> doc_bold_font = p_rt->get_theme_font("doc_bold", "EditorFonts");
+ Ref<Font> doc_code_font = p_rt->get_theme_font("doc_source", "EditorFonts");
- Color font_color_hl = p_rt->get_color("headline_color", "EditorHelp");
- Color accent_color = p_rt->get_color("accent_color", "Editor");
+ Color font_color_hl = p_rt->get_theme_color("headline_color", "EditorHelp");
+ Color accent_color = p_rt->get_theme_color("accent_color", "Editor");
Color link_color = accent_color.linear_interpolate(font_color_hl, 0.8);
Color code_color = accent_color.linear_interpolate(font_color_hl, 0.6);
@@ -1449,7 +1447,6 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
void EditorHelp::_add_text(const String &p_bbcode) {
-
_add_text_to_rt(p_bbcode, class_desc);
}
@@ -1489,8 +1486,8 @@ void EditorHelp::go_to_class(const String &p_class, int p_scroll) {
_goto_desc(p_class, p_scroll);
}
-Vector<Pair<String, int> > EditorHelp::get_sections() {
- Vector<Pair<String, int> > sections;
+Vector<Pair<String, int>> EditorHelp::get_sections() {
+ Vector<Pair<String, int>> sections;
for (int i = 0; i < section_line.size(); i++) {
sections.push_back(Pair<String, int>(section_line[i].first, i));
@@ -1546,7 +1543,7 @@ EditorHelp::EditorHelp() {
class_desc = memnew(RichTextLabel);
add_child(class_desc);
class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
- class_desc->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
+ class_desc->add_theme_color_override("selection_color", get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
class_desc->connect("meta_clicked", callable_mp(this, &EditorHelp::_class_desc_select));
class_desc->connect("gui_input", callable_mp(this, &EditorHelp::_class_desc_input));
@@ -1611,9 +1608,14 @@ void EditorHelpBit::_bind_methods() {
void EditorHelpBit::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY: {
+ rich_text->clear();
+ _add_text_to_rt(text, rich_text);
+
+ } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- rich_text->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
+ rich_text->add_theme_color_override("selection_color", get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
} break;
default: break;
}
@@ -1621,8 +1623,9 @@ void EditorHelpBit::_notification(int p_what) {
void EditorHelpBit::set_text(const String &p_text) {
+ text = p_text;
rich_text->clear();
- _add_text_to_rt(p_text, rich_text);
+ _add_text_to_rt(text, rich_text);
}
EditorHelpBit::EditorHelpBit() {
@@ -1630,7 +1633,7 @@ EditorHelpBit::EditorHelpBit() {
rich_text = memnew(RichTextLabel);
add_child(rich_text);
rich_text->connect("meta_clicked", callable_mp(this, &EditorHelpBit::_meta_clicked));
- rich_text->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
+ rich_text->add_theme_color_override("selection_color", get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
rich_text->set_override_selected_font_color(false);
set_custom_minimum_size(Size2(0, 70 * EDSCALE));
}
@@ -1694,13 +1697,13 @@ void FindBar::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- find_prev->set_icon(get_icon("MoveUp", "EditorIcons"));
- find_next->set_icon(get_icon("MoveDown", "EditorIcons"));
- hide_button->set_normal_texture(get_icon("Close", "EditorIcons"));
- hide_button->set_hover_texture(get_icon("Close", "EditorIcons"));
- hide_button->set_pressed_texture(get_icon("Close", "EditorIcons"));
+ find_prev->set_icon(get_theme_icon("MoveUp", "EditorIcons"));
+ find_next->set_icon(get_theme_icon("MoveDown", "EditorIcons"));
+ hide_button->set_normal_texture(get_theme_icon("Close", "EditorIcons"));
+ hide_button->set_hover_texture(get_theme_icon("Close", "EditorIcons"));
+ hide_button->set_pressed_texture(get_theme_icon("Close", "EditorIcons"));
hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size());
- matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor"));
+ matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor"));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -1781,7 +1784,7 @@ void FindBar::_update_matches_label() {
} else {
matches_label->show();
- matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor"));
+ matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor"));
matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count));
}
}
@@ -1829,7 +1832,7 @@ void FindBar::_search_text_changed(const String &p_text) {
void FindBar::_search_text_entered(const String &p_text) {
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
search_prev();
} else {
search_next();
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 83c279aec3..2e053e674f 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -32,7 +32,7 @@
#define EDITOR_HELP_H
#include "editor/code_editor.h"
-#include "editor/doc/doc_data.h"
+#include "editor/doc_data.h"
#include "editor/editor_plugin.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/menu_button.h"
@@ -108,14 +108,14 @@ class EditorHelp : public VBoxContainer {
String edited_class;
- Vector<Pair<String, int> > section_line;
+ Vector<Pair<String, int>> section_line;
Map<String, int> method_line;
Map<String, int> signal_line;
Map<String, int> property_line;
Map<String, int> theme_property_line;
Map<String, int> constant_line;
Map<String, int> enum_line;
- Map<String, Map<String, int> > enum_values_line;
+ Map<String, Map<String, int>> enum_values_line;
int description_line;
RichTextLabel *class_desc;
@@ -175,7 +175,7 @@ public:
void go_to_help(const String &p_help);
void go_to_class(const String &p_class, int p_scroll = 0);
- Vector<Pair<String, int> > get_sections();
+ Vector<Pair<String, int>> get_sections();
void scroll_to_section(int p_section_index);
void popup_search();
@@ -192,14 +192,16 @@ public:
~EditorHelp();
};
-class EditorHelpBit : public PanelContainer {
+class EditorHelpBit : public MarginContainer {
- GDCLASS(EditorHelpBit, PanelContainer);
+ GDCLASS(EditorHelpBit, MarginContainer);
RichTextLabel *rich_text;
void _go_to_help(String p_what);
void _meta_clicked(String p_select);
+ String text;
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index f7ce2dd4fc..01a50cad2c 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -37,13 +37,13 @@
void EditorHelpSearch::_update_icons() {
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(results_tree->get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
- case_sensitive_button->set_icon(get_icon("MatchCase", "EditorIcons"));
- hierarchy_button->set_icon(get_icon("ClassList", "EditorIcons"));
+ search_box->add_theme_icon_override("right_icon", results_tree->get_theme_icon("Search", "EditorIcons"));
+ case_sensitive_button->set_icon(results_tree->get_theme_icon("MatchCase", "EditorIcons"));
+ hierarchy_button->set_icon(results_tree->get_theme_icon("ClassList", "EditorIcons"));
- if (is_visible_in_tree())
+ if (is_visible())
_update_results();
}
@@ -57,7 +57,7 @@ void EditorHelpSearch::_update_results() {
if (hierarchy_button->is_pressed())
search_flags |= SEARCH_SHOW_HIERARCHY;
- search = Ref<Runner>(memnew(Runner(this, results_tree, term, search_flags)));
+ search = Ref<Runner>(memnew(Runner(results_tree, results_tree, term, search_flags)));
set_process(true);
}
@@ -105,6 +105,13 @@ void EditorHelpSearch::_confirmed() {
void EditorHelpSearch::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible()) {
+ results_tree->call_deferred("clear"); // Wait for the Tree's mouse event propagation.
+ get_ok()->set_disabled(true);
+ EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size()));
+ }
+ } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
_update_icons();
@@ -114,12 +121,7 @@ void EditorHelpSearch::_notification(int p_what) {
connect("confirmed", callable_mp(this, &EditorHelpSearch::_confirmed));
_update_icons();
} break;
- case NOTIFICATION_POPUP_HIDE: {
- results_tree->call_deferred("clear"); // Wait for the Tree's mouse event propagation.
- get_ok()->set_disabled(true);
- EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", get_rect());
- } break;
case NOTIFICATION_PROCESS: {
// Update background search.
@@ -184,7 +186,7 @@ EditorHelpSearch::EditorHelpSearch() {
old_search = false;
set_hide_on_ok(false);
- set_resizable(true);
+
set_title(TTR("Search Help"));
get_ok()->set_disabled(true);
@@ -200,7 +202,7 @@ EditorHelpSearch::EditorHelpSearch() {
search_box = memnew(LineEdit);
search_box->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
- search_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_box->connect("gui_input", callable_mp(this, &EditorHelpSearch::_search_box_gui_input));
search_box->connect("text_changed", callable_mp(this, &EditorHelpSearch::_search_box_text_changed));
register_text_enter(search_box);
@@ -210,7 +212,7 @@ EditorHelpSearch::EditorHelpSearch() {
case_sensitive_button->set_tooltip(TTR("Case Sensitive"));
case_sensitive_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results));
case_sensitive_button->set_toggle_mode(true);
- case_sensitive_button->set_focus_mode(FOCUS_NONE);
+ case_sensitive_button->set_focus_mode(Control::FOCUS_NONE);
hbox->add_child(case_sensitive_button);
hierarchy_button = memnew(ToolButton);
@@ -218,7 +220,7 @@ EditorHelpSearch::EditorHelpSearch() {
hierarchy_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results));
hierarchy_button->set_toggle_mode(true);
hierarchy_button->set_pressed(true);
- hierarchy_button->set_focus_mode(FOCUS_NONE);
+ hierarchy_button->set_focus_mode(Control::FOCUS_NONE);
hbox->add_child(hierarchy_button);
filter_combo = memnew(OptionButton);
@@ -237,7 +239,7 @@ EditorHelpSearch::EditorHelpSearch() {
// Create the results tree.
results_tree = memnew(Tree);
- results_tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
results_tree->set_columns(2);
results_tree->set_column_title(0, TTR("Name"));
results_tree->set_column_title(1, TTR("Member Type"));
@@ -315,7 +317,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
iterator_doc = EditorHelp::get_doc_data()->class_list.front();
matches.clear();
- matched_item = NULL;
+ matched_item = nullptr;
return true;
}
@@ -479,10 +481,10 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_
TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) {
Ref<Texture2D> icon = empty_icon;
- if (ui_service->has_icon(p_doc->name, "EditorIcons"))
- icon = ui_service->get_icon(p_doc->name, "EditorIcons");
+ if (ui_service->has_theme_icon(p_doc->name, "EditorIcons"))
+ icon = ui_service->get_theme_icon(p_doc->name, "EditorIcons");
else if (ClassDB::class_exists(p_doc->name) && ClassDB::is_parent_class(p_doc->name, "Object"))
- icon = ui_service->get_icon("Object", "EditorIcons");
+ icon = ui_service->get_theme_icon("Object", "EditorIcons");
String tooltip = p_doc->brief_description.strip_edges();
TreeItem *item = results_tree->create_item(p_parent);
@@ -557,10 +559,10 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons
Ref<Texture2D> icon;
String text;
if (search_flags & SEARCH_SHOW_HIERARCHY) {
- icon = ui_service->get_icon(p_icon, "EditorIcons");
+ icon = ui_service->get_theme_icon(p_icon, "EditorIcons");
text = p_name;
} else {
- icon = ui_service->get_icon(p_icon, "EditorIcons");
+ icon = ui_service->get_theme_icon(p_icon, "EditorIcons");
/*// In flat mode, show the class icon.
if (ui_service->has_icon(p_class_name, "EditorIcons"))
icon = ui_service->get_icon(p_class_name, "EditorIcons");
@@ -598,6 +600,6 @@ EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree,
results_tree(p_results_tree),
term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()),
search_flags(p_search_flags),
- empty_icon(ui_service->get_icon("ArrowRight", "EditorIcons")),
- disabled_color(ui_service->get_color("disabled_font_color", "Editor")) {
+ empty_icon(ui_service->get_theme_icon("ArrowRight", "EditorIcons")),
+ disabled_color(ui_service->get_theme_color("disabled_font_color", "Editor")) {
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index ed5a411d8b..a0f8b59117 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -41,7 +41,7 @@
Size2 EditorProperty::get_minimum_size() const {
Size2 ms;
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
ms.height = font->get_height();
for (int i = 0; i < get_child_count(); i++) {
@@ -62,17 +62,17 @@ Size2 EditorProperty::get_minimum_size() const {
}
if (keying) {
- Ref<Texture2D> key = get_icon("Key", "EditorIcons");
- ms.width += key->get_width() + get_constant("hseparator", "Tree");
+ Ref<Texture2D> key = get_theme_icon("Key", "EditorIcons");
+ ms.width += key->get_width() + get_theme_constant("hseparator", "Tree");
}
if (checkable) {
- Ref<Texture2D> check = get_icon("checked", "CheckBox");
- ms.width += check->get_width() + get_constant("hseparation", "CheckBox") + get_constant("hseparator", "Tree");
+ Ref<Texture2D> check = get_theme_icon("checked", "CheckBox");
+ ms.width += check->get_width() + get_theme_constant("hseparation", "CheckBox") + get_theme_constant("hseparator", "Tree");
}
- if (bottom_editor != NULL && bottom_editor->is_visible()) {
- ms.height += get_constant("vseparation", "Tree");
+ if (bottom_editor != nullptr && bottom_editor->is_visible()) {
+ ms.height += get_theme_constant("vseparation", "Tree");
Size2 bems = bottom_editor->get_combined_minimum_size();
//bems.width += get_constant("item_margin", "Tree");
ms.height += bems.height;
@@ -103,7 +103,7 @@ void EditorProperty::_notification(int p_what) {
{
int child_room = size.width * (1.0 - split_ratio);
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
int height = font->get_height();
bool no_children = true;
@@ -136,19 +136,19 @@ void EditorProperty::_notification(int p_what) {
int m = 0; //get_constant("item_margin", "Tree");
- bottom_rect = Rect2(m, rect.size.height + get_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height);
+ bottom_rect = Rect2(m, rect.size.height + get_theme_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height);
}
if (keying) {
Ref<Texture2D> key;
if (use_keying_next()) {
- key = get_icon("KeyNext", "EditorIcons");
+ key = get_theme_icon("KeyNext", "EditorIcons");
} else {
- key = get_icon("Key", "EditorIcons");
+ key = get_theme_icon("Key", "EditorIcons");
}
- rect.size.x -= key->get_width() + get_constant("hseparator", "Tree");
+ rect.size.x -= key->get_width() + get_theme_constant("hseparator", "Tree");
if (no_children) {
text_size -= key->get_width() + 4 * EDSCALE;
@@ -180,8 +180,8 @@ void EditorProperty::_notification(int p_what) {
}
if (p_what == NOTIFICATION_DRAW) {
- Ref<Font> font = get_font("font", "Tree");
- Color dark_color = get_color("dark_color_2", "Editor");
+ Ref<Font> font = get_theme_font("font", "Tree");
+ Color dark_color = get_theme_color("dark_color_2", "Editor");
Size2 size = get_size();
if (bottom_editor) {
@@ -191,7 +191,7 @@ void EditorProperty::_notification(int p_what) {
}
if (selected) {
- Ref<StyleBox> sb = get_stylebox("selected", "Tree");
+ Ref<StyleBox> sb = get_theme_stylebox("selected", "Tree");
draw_style_box(sb, Rect2(Vector2(), size));
}
@@ -204,9 +204,9 @@ void EditorProperty::_notification(int p_what) {
Color color;
if (draw_red) {
- color = get_color("error_color", "Editor");
+ color = get_theme_color("error_color", "Editor");
} else {
- color = get_color("property_color", "Editor");
+ color = get_theme_color("property_color", "Editor");
}
if (label.find(".") != -1) {
color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides
@@ -218,9 +218,9 @@ void EditorProperty::_notification(int p_what) {
if (checkable) {
Ref<Texture2D> checkbox;
if (checked)
- checkbox = get_icon("GuiChecked", "EditorIcons");
+ checkbox = get_theme_icon("GuiChecked", "EditorIcons");
else
- checkbox = get_icon("GuiUnchecked", "EditorIcons");
+ checkbox = get_theme_icon("GuiUnchecked", "EditorIcons");
Color color2(1, 1, 1);
if (check_hover) {
@@ -230,16 +230,16 @@ void EditorProperty::_notification(int p_what) {
}
check_rect = Rect2(ofs, ((size.height - checkbox->get_height()) / 2), checkbox->get_width(), checkbox->get_height());
draw_texture(checkbox, check_rect.position, color2);
- ofs += get_constant("hseparator", "Tree") + checkbox->get_width() + get_constant("hseparation", "CheckBox");
+ ofs += get_theme_constant("hseparator", "Tree") + checkbox->get_width() + get_theme_constant("hseparation", "CheckBox");
text_limit -= ofs;
} else {
check_rect = Rect2();
}
if (can_revert) {
- Ref<Texture2D> reload_icon = get_icon("ReloadSmall", "EditorIcons");
- text_limit -= reload_icon->get_width() + get_constant("hseparator", "Tree") * 2;
- revert_rect = Rect2(text_limit + get_constant("hseparator", "Tree"), (size.height - reload_icon->get_height()) / 2, reload_icon->get_width(), reload_icon->get_height());
+ Ref<Texture2D> reload_icon = get_theme_icon("ReloadSmall", "EditorIcons");
+ text_limit -= reload_icon->get_width() + get_theme_constant("hseparator", "Tree") * 2;
+ revert_rect = Rect2(text_limit + get_theme_constant("hseparator", "Tree"), (size.height - reload_icon->get_height()) / 2, reload_icon->get_width(), reload_icon->get_height());
Color color2(1, 1, 1);
if (revert_hover) {
@@ -260,12 +260,12 @@ void EditorProperty::_notification(int p_what) {
Ref<Texture2D> key;
if (use_keying_next()) {
- key = get_icon("KeyNext", "EditorIcons");
+ key = get_theme_icon("KeyNext", "EditorIcons");
} else {
- key = get_icon("Key", "EditorIcons");
+ key = get_theme_icon("Key", "EditorIcons");
}
- ofs = size.width - key->get_width() - get_constant("hseparator", "Tree");
+ ofs = size.width - key->get_width() - get_theme_constant("hseparator", "Tree");
Color color2(1, 1, 1);
if (keying_hover) {
@@ -646,7 +646,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
emit_signal("property_keyed", property, use_keying_next());
if (use_keying_next()) {
- if (property == "frame_coords" && (object->is_class("Sprite") || object->is_class("Sprite3D"))) {
+ if (property == "frame_coords" && (object->is_class("Sprite2D") || object->is_class("Sprite3D"))) {
Vector2 new_coords = object->get(property);
new_coords.x++;
if (new_coords.x >= object->get("hframes").operator int64_t()) {
@@ -776,13 +776,14 @@ Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
tooltip_text = p_text;
EditorHelpBit *help_bit = memnew(EditorHelpBit);
- help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
+ //help_bit->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel"));
help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
+ String text;
PackedStringArray slices = p_text.split("::", false);
if (!slices.empty()) {
String property_name = slices[0].strip_edges();
- String text = TTR("Property:") + " [u][b]" + property_name + "[/b][/u]";
+ text = TTR("Property:") + " [u][b]" + property_name + "[/b][/u]";
if (slices.size() > 1) {
String property_doc = slices[1].strip_edges();
@@ -790,7 +791,7 @@ Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
text += "\n" + property_doc;
}
}
- help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene
+ help_bit->set_text(text);
}
return help_bit;
@@ -855,7 +856,7 @@ void EditorProperty::_bind_methods() {
EditorProperty::EditorProperty() {
draw_top_bg = true;
- object = NULL;
+ object = nullptr;
split_ratio = 0.5;
selectable = true;
text_size = 0;
@@ -872,8 +873,8 @@ EditorProperty::EditorProperty() {
property_usage = 0;
selected = false;
selected_focusable = -1;
- label_reference = NULL;
- bottom_editor = NULL;
+ label_reference = nullptr;
+ bottom_editor = nullptr;
}
////////////////////////////////////////////////
////////////////////////////////////////////////
@@ -887,7 +888,7 @@ void EditorInspectorPlugin::add_custom_control(Control *control) {
void EditorInspectorPlugin::add_property_editor(const String &p_for_property, Control *p_prop) {
- ERR_FAIL_COND(Object::cast_to<EditorProperty>(p_prop) == NULL);
+ ERR_FAIL_COND(Object::cast_to<EditorProperty>(p_prop) == nullptr);
AddedEditor ae;
ae.properties.push_back(p_for_property);
@@ -987,9 +988,9 @@ void EditorInspectorCategory::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
draw_rect(Rect2(Vector2(), get_size()), bg_color);
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
- int hs = get_constant("hseparation", "Tree");
+ int hs = get_theme_constant("hseparation", "Tree");
int w = font->get_string_size(label).width;
if (icon.is_valid()) {
@@ -1003,7 +1004,7 @@ void EditorInspectorCategory::_notification(int p_what) {
ofs += hs + icon->get_width();
}
- Color color = get_color("font_color", "Tree");
+ Color color = get_theme_color("font_color", "Tree");
draw_string(font, Point2(ofs, font->get_ascent() + (get_size().height - font->get_height()) / 2).floor(), label, color, get_size().width);
}
}
@@ -1012,7 +1013,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
tooltip_text = p_text;
EditorHelpBit *help_bit = memnew(EditorHelpBit);
- help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
+ help_bit->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel"));
help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
PackedStringArray slices = p_text.split("::", false);
@@ -1026,7 +1027,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
text += "\n" + property_doc;
}
}
- help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene
+ help_bit->set_text(text); //hack so it uses proper theme once inside scene
}
return help_bit;
@@ -1034,7 +1035,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
Size2 EditorInspectorCategory::get_minimum_size() const {
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
Size2 ms;
ms.width = 1;
@@ -1042,7 +1043,7 @@ Size2 EditorInspectorCategory::get_minimum_size() const {
if (icon.is_valid()) {
ms.height = MAX(icon->get_height(), ms.height);
}
- ms.height += get_constant("vseparation", "Tree");
+ ms.height += get_theme_constant("vseparation", "Tree");
return ms;
}
@@ -1074,14 +1075,14 @@ void EditorInspectorSection::_notification(int p_what) {
if (p_what == NOTIFICATION_SORT_CHILDREN) {
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
Ref<Texture2D> arrow;
if (foldable) {
if (object->editor_is_section_unfolded(section)) {
- arrow = get_icon("arrow", "Tree");
+ arrow = get_theme_icon("arrow", "Tree");
} else {
- arrow = get_icon("arrow_collapsed", "Tree");
+ arrow = get_theme_icon("arrow_collapsed", "Tree");
}
}
@@ -1092,8 +1093,8 @@ void EditorInspectorSection::_notification(int p_what) {
offset.y = MAX(offset.y, arrow->get_height());
}
- offset.y += get_constant("vseparation", "Tree");
- offset.x += get_constant("inspector_margin", "Editor");
+ offset.y += get_theme_constant("vseparation", "Tree");
+ offset.x += get_theme_constant("inspector_margin", "Editor");
Rect2 rect(offset, size - offset);
@@ -1120,24 +1121,24 @@ void EditorInspectorSection::_notification(int p_what) {
if (foldable) {
if (object->editor_is_section_unfolded(section)) {
- arrow = get_icon("arrow", "Tree");
+ arrow = get_theme_icon("arrow", "Tree");
} else {
- arrow = get_icon("arrow_collapsed", "Tree");
+ arrow = get_theme_icon("arrow_collapsed", "Tree");
}
}
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
int h = font->get_height();
if (arrow.is_valid()) {
h = MAX(h, arrow->get_height());
}
- h += get_constant("vseparation", "Tree");
+ h += get_theme_constant("vseparation", "Tree");
draw_rect(Rect2(Vector2(), Vector2(get_size().width, h)), bg_color);
const int arrow_margin = 3;
- Color color = get_color("font_color", "Tree");
+ Color color = get_theme_color("font_color", "Tree");
draw_string(font, Point2(Math::round((16 + arrow_margin) * EDSCALE), font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width);
if (arrow.is_valid()) {
@@ -1163,9 +1164,9 @@ Size2 EditorInspectorSection::get_minimum_size() const {
ms.height = MAX(ms.height, minsize.height);
}
- Ref<Font> font = get_font("font", "Tree");
- ms.height += font->get_height() + get_constant("vseparation", "Tree");
- ms.width += get_constant("inspector_margin", "Editor");
+ Ref<Font> font = get_theme_font("font", "Tree");
+ ms.height += font->get_height() + get_theme_constant("vseparation", "Tree");
+ ms.width += get_theme_constant("inspector_margin", "Editor");
return ms;
}
@@ -1201,7 +1202,7 @@ void EditorInspectorSection::_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) {
- Ref<Font> font = get_font("font", "Tree");
+ Ref<Font> font = get_theme_font("font", "Tree");
if (mb->get_position().y > font->get_height()) { //clicked outside
return;
}
@@ -1256,7 +1257,7 @@ void EditorInspectorSection::_bind_methods() {
}
EditorInspectorSection::EditorInspectorSection() {
- object = NULL;
+ object = nullptr;
foldable = false;
vbox = memnew(VBoxContainer);
vbox_added = false;
@@ -1296,7 +1297,7 @@ EditorProperty *EditorInspector::instantiate_property_editor(Object *p_object, V
}
}
}
- return NULL;
+ return nullptr;
}
void EditorInspector::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
@@ -1454,7 +1455,7 @@ void EditorInspector::update_tree() {
if (!object)
return;
- List<Ref<EditorInspectorPlugin> > valid_plugins;
+ List<Ref<EditorInspectorPlugin>> valid_plugins;
for (int i = inspector_plugin_count - 1; i >= 0; i--) { //start by last, so lastly added can override newly added
if (!inspector_plugins[i]->can_handle(object))
@@ -1472,12 +1473,14 @@ void EditorInspector::update_tree() {
}
}
- // TreeItem *current_category = NULL;
+ // TreeItem *current_category = nullptr;
String filter = search_box ? search_box->get_text() : "";
String group;
String group_base;
- VBoxContainer *category_vbox = NULL;
+ String subgroup;
+ String subgroup_base;
+ VBoxContainer *category_vbox = nullptr;
List<PropertyInfo>
plist;
@@ -1488,9 +1491,9 @@ void EditorInspector::update_tree() {
item_path[""] = main_vbox;
- Color sscolor = get_color("prop_subsection", "Editor");
+ Color sscolor = get_theme_color("prop_subsection", "Editor");
- for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
+ for (List<Ref<EditorInspectorPlugin>>::Element *E = valid_plugins.front(); E; E = E->next()) {
Ref<EditorInspectorPlugin> ped = E->get();
ped->parse_begin(object);
_parse_added_editors(main_vbox, ped);
@@ -1502,10 +1505,19 @@ void EditorInspector::update_tree() {
//make sure the property can be edited
- if (p.usage & PROPERTY_USAGE_GROUP) {
+ if (p.usage & PROPERTY_USAGE_SUBGROUP) {
+
+ subgroup = p.name;
+ subgroup_base = p.hint_string;
+
+ continue;
+
+ } else if (p.usage & PROPERTY_USAGE_GROUP) {
group = p.name;
group_base = p.hint_string;
+ subgroup = "";
+ subgroup_base = "";
continue;
@@ -1513,6 +1525,8 @@ void EditorInspector::update_tree() {
group = "";
group_base = "";
+ subgroup = "";
+ subgroup_base = "";
if (!show_categories)
continue;
@@ -1534,13 +1548,13 @@ void EditorInspector::update_tree() {
EditorInspectorCategory *category = memnew(EditorInspectorCategory);
main_vbox->add_child(category);
- category_vbox = NULL; //reset
+ category_vbox = nullptr; //reset
String type = p.name;
category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
category->label = type;
- category->bg_color = get_color("prop_category", "Editor");
+ category->bg_color = get_theme_color("prop_category", "Editor");
if (use_doc_hints) {
StringName type2 = p.name;
if (!class_descr_cache.has(type2)) {
@@ -1551,13 +1565,13 @@ void EditorInspector::update_tree() {
if (E) {
descr = E->get().brief_description;
}
- class_descr_cache[type2] = descr;
+ class_descr_cache[type2] = DTR(descr);
}
category->set_tooltip(p.name + "::" + (class_descr_cache[type2] == "" ? "" : class_descr_cache[type2]));
}
- for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
+ for (List<Ref<EditorInspectorPlugin>>::Element *E = valid_plugins.front(); E; E = E->next()) {
Ref<EditorInspectorPlugin> ped = E->get();
ped->parse_category(object, p.name);
_parse_added_editors(main_vbox, ped);
@@ -1568,7 +1582,7 @@ void EditorInspector::update_tree() {
} else if (!(p.usage & PROPERTY_USAGE_EDITOR) || _is_property_disabled_by_feature_profile(p.name))
continue;
- if (p.usage & PROPERTY_USAGE_HIGH_END_GFX && VS::get_singleton()->is_low_end())
+ if (p.usage & PROPERTY_USAGE_HIGH_END_GFX && RS::get_singleton()->is_low_end())
continue; //do not show this property in low end gfx
if (p.name == "script" && (hide_script || bool(object->call("_hide_script_from_inspector")))) {
@@ -1576,18 +1590,33 @@ void EditorInspector::update_tree() {
}
String basename = p.name;
+
+ if (subgroup != "") {
+ if (subgroup_base != "") {
+ if (basename.begins_with(subgroup_base)) {
+ basename = basename.replace_first(subgroup_base, "");
+ } else if (subgroup_base.begins_with(basename)) {
+ //keep it, this is used pretty often
+ } else {
+ subgroup = ""; //no longer using subgroup base, clear
+ }
+ }
+ }
if (group != "") {
- if (group_base != "") {
+ if (group_base != "" && subgroup == "") {
if (basename.begins_with(group_base)) {
basename = basename.replace_first(group_base, "");
} else if (group_base.begins_with(basename)) {
//keep it, this is used pretty often
} else {
group = ""; //no longer using group base, clear
+ subgroup = "";
}
}
}
-
+ if (subgroup != "") {
+ basename = subgroup + "/" + basename;
+ }
if (group != "") {
basename = group + "/" + basename;
}
@@ -1620,7 +1649,7 @@ void EditorInspector::update_tree() {
continue;
}
- if (category_vbox == NULL) {
+ if (category_vbox == nullptr) {
category_vbox = memnew(VBoxContainer);
main_vbox->add_child(category_vbox);
}
@@ -1658,7 +1687,7 @@ void EditorInspector::update_tree() {
if (current_vbox == main_vbox) {
//do not add directly to the main vbox, given it has no spacing
- if (category_vbox == NULL) {
+ if (category_vbox == nullptr) {
category_vbox = memnew(VBoxContainer);
}
current_vbox = category_vbox;
@@ -1688,7 +1717,7 @@ void EditorInspector::update_tree() {
String descr;
bool found = false;
- Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(classname);
+ Map<StringName, Map<StringName, String>>::Element *E = descr_cache.find(classname);
if (E) {
Map<StringName, String>::Element *F = E->get().find(propname);
if (F) {
@@ -1703,10 +1732,22 @@ void EditorInspector::update_tree() {
while (F && descr == String()) {
for (int i = 0; i < F->get().properties.size(); i++) {
if (F->get().properties[i].name == propname.operator String()) {
- descr = F->get().properties[i].description.strip_edges();
+ descr = DTR(F->get().properties[i].description.strip_edges());
break;
}
}
+
+ Vector<String> slices = propname.operator String().split("/");
+ if (slices.size() == 2 && slices[0].begins_with("custom_")) {
+ // Likely a theme property.
+ for (int i = 0; i < F->get().theme_properties.size(); i++) {
+ if (F->get().theme_properties[i].name == slices[1]) {
+ descr = DTR(F->get().theme_properties[i].description.strip_edges());
+ break;
+ }
+ }
+ }
+
if (!F->get().inherits.empty()) {
F = dd->class_list.find(F->get().inherits);
} else {
@@ -1719,7 +1760,7 @@ void EditorInspector::update_tree() {
doc_hint = descr;
}
- for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
+ for (List<Ref<EditorInspectorPlugin>>::Element *E = valid_plugins.front(); E; E = E->next()) {
Ref<EditorInspectorPlugin> ped = E->get();
bool exclusive = ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage);
@@ -1802,7 +1843,7 @@ void EditorInspector::update_tree() {
}
}
- for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
+ for (List<Ref<EditorInspectorPlugin>>::Element *E = valid_plugins.front(); E; E = E->next()) {
Ref<EditorInspectorPlugin> ped = E->get();
ped->parse_end();
_parse_added_editors(main_vbox, ped);
@@ -1933,7 +1974,7 @@ void EditorInspector::collapse_all_folding() {
E->get()->fold();
}
- for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
+ 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()->collapse_all_folding();
}
@@ -1944,7 +1985,7 @@ void EditorInspector::expand_all_folding() {
for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) {
E->get()->unfold();
}
- for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
+ 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()->expand_all_folding();
}
@@ -1966,9 +2007,9 @@ void EditorInspector::set_sub_inspector(bool p_enable) {
return;
if (sub_inspector) {
- add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor"));
+ add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg", "Editor"));
} else {
- add_style_override("bg", get_stylebox("bg", "Tree"));
+ add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
}
}
@@ -2130,7 +2171,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
if (E->get().name == p_path) {
Callable::CallError ce;
- to_create = Variant::construct(E->get().type, NULL, 0, ce);
+ to_create = Variant::construct(E->get().type, nullptr, 0, ce);
break;
}
}
@@ -2154,7 +2195,7 @@ void EditorInspector::_property_selected(const String &p_path, int p_focusable)
property_selected = p_path;
property_focusable = p_focusable;
//deselect the others
- for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
+ for (Map<StringName, List<EditorProperty *>>::Element *F = editor_property_map.front(); F; F = F->next()) {
if (F->key() == property_selected)
continue;
for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) {
@@ -2178,7 +2219,7 @@ void EditorInspector::_resource_selected(const String &p_path, RES p_resource) {
void EditorInspector::_node_removed(Node *p_node) {
if (p_node == object) {
- edit(NULL);
+ edit(nullptr);
}
}
@@ -2191,21 +2232,21 @@ void EditorInspector::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
if (sub_inspector) {
- add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor"));
+ add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg", "Editor"));
} else {
- add_style_override("bg", get_stylebox("bg", "Tree"));
+ add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
}
}
if (p_what == NOTIFICATION_PREDELETE) {
- edit(NULL); //just in case
+ edit(nullptr); //just in case
}
if (p_what == NOTIFICATION_EXIT_TREE) {
if (!sub_inspector) {
get_tree()->disconnect("node_removed", callable_mp(this, &EditorInspector::_node_removed));
}
- edit(NULL);
+ edit(nullptr);
}
if (p_what == NOTIFICATION_PROCESS) {
@@ -2217,7 +2258,7 @@ void EditorInspector::_notification(int p_what) {
if (refresh_countdown > 0) {
refresh_countdown -= get_process_delta_time();
if (refresh_countdown <= 0) {
- for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
+ 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();
@@ -2254,9 +2295,9 @@ void EditorInspector::_notification(int p_what) {
if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
if (sub_inspector) {
- add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor"));
+ add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg", "Editor"));
} else if (is_inside_tree()) {
- add_style_override("bg", get_stylebox("bg", "Tree"));
+ add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
}
update_tree();
@@ -2315,11 +2356,11 @@ void EditorInspector::_bind_methods() {
}
EditorInspector::EditorInspector() {
- object = NULL;
- undo_redo = NULL;
+ object = nullptr;
+ undo_redo = nullptr;
main_vbox = memnew(VBoxContainer);
main_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
- main_vbox->add_constant_override("separation", 0);
+ main_vbox->add_theme_constant_override("separation", 0);
add_child(main_vbox);
set_enable_h_scroll(false);
set_enable_v_scroll(true);
@@ -2336,7 +2377,7 @@ EditorInspector::EditorInspector() {
update_tree_pending = false;
refresh_countdown = 0;
read_only = false;
- search_box = NULL;
+ search_box = nullptr;
keying = false;
_prop_edited = "property_edited";
set_process(true);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 7a1542d30f..b49a4424f6 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -261,7 +261,7 @@ class EditorInspector : public ScrollContainer {
VBoxContainer *main_vbox;
//map use to cache the instanced editors
- Map<StringName, List<EditorProperty *> > editor_property_map;
+ Map<StringName, List<EditorProperty *>> editor_property_map;
List<EditorInspectorSection *> sections;
Set<StringName> pending;
@@ -291,7 +291,7 @@ class EditorInspector : public ScrollContainer {
int property_focusable;
int update_scroll_request;
- Map<StringName, Map<StringName, String> > descr_cache;
+ Map<StringName, Map<StringName, String>> descr_cache;
Map<StringName, String> class_descr_cache;
Set<StringName> restart_request_props;
diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp
index 776fbd9314..dbd043c494 100644
--- a/editor/editor_layouts_dialog.cpp
+++ b/editor/editor_layouts_dialog.cpp
@@ -52,12 +52,12 @@ void EditorLayoutsDialog::_line_gui_input(const Ref<InputEvent> &p_event) {
if (get_hide_on_ok())
hide();
ok_pressed();
- accept_event();
+ set_input_as_handled();
} break;
case KEY_ESCAPE: {
hide();
- accept_event();
+ set_input_as_handled();
} break;
}
}
@@ -110,15 +110,15 @@ EditorLayoutsDialog::EditorLayoutsDialog() {
makevb = memnew(VBoxContainer);
add_child(makevb);
- makevb->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5);
- makevb->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5);
+ makevb->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5);
+ makevb->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5);
layout_names = memnew(ItemList);
makevb->add_child(layout_names);
layout_names->set_visible(true);
layout_names->set_margin(MARGIN_TOP, 5);
- layout_names->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5);
- layout_names->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5);
+ layout_names->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5);
+ layout_names->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5);
layout_names->set_v_size_flags(Control::SIZE_EXPAND_FILL);
layout_names->set_select_mode(ItemList::SELECT_MULTI);
layout_names->set_allow_rmb_select(true);
@@ -126,8 +126,8 @@ EditorLayoutsDialog::EditorLayoutsDialog() {
name = memnew(LineEdit);
makevb->add_child(name);
name->set_margin(MARGIN_TOP, 5);
- name->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5);
- name->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5);
+ name->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5);
+ name->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5);
name->connect("gui_input", callable_mp(this, &EditorLayoutsDialog::_line_gui_input));
name->connect("focus_entered", callable_mp(layout_names, &ItemList::unselect_all));
}
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 0e50a5e95c..c89a7bcf23 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -62,12 +62,12 @@ void EditorLog::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
//button->set_icon(get_icon("Console","EditorIcons"));
- log->add_font_override("normal_font", get_font("output_source", "EditorFonts"));
+ log->add_theme_font_override("normal_font", get_theme_font("output_source", "EditorFonts"));
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
- Ref<DynamicFont> df_output_code = get_font("output_source", "EditorFonts");
+ Ref<DynamicFont> df_output_code = get_theme_font("output_source", "EditorFonts");
if (df_output_code.is_valid()) {
- if (log != NULL) {
- log->add_font_override("normal_font", get_font("output_source", "EditorFonts"));
+ if (log != nullptr) {
+ log->add_theme_font_override("normal_font", get_theme_font("output_source", "EditorFonts"));
}
}
}
@@ -101,22 +101,22 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) {
case MSG_TYPE_STD: {
} break;
case MSG_TYPE_ERROR: {
- log->push_color(get_color("error_color", "Editor"));
- Ref<Texture2D> icon = get_icon("Error", "EditorIcons");
+ log->push_color(get_theme_color("error_color", "Editor"));
+ Ref<Texture2D> icon = get_theme_icon("Error", "EditorIcons");
log->add_image(icon);
log->add_text(" ");
tool_button->set_icon(icon);
} break;
case MSG_TYPE_WARNING: {
- log->push_color(get_color("warning_color", "Editor"));
- Ref<Texture2D> icon = get_icon("Warning", "EditorIcons");
+ log->push_color(get_theme_color("warning_color", "Editor"));
+ Ref<Texture2D> icon = get_theme_icon("Warning", "EditorIcons");
log->add_image(icon);
log->add_text(" ");
tool_button->set_icon(icon);
} break;
case MSG_TYPE_EDITOR: {
// Distinguish editor messages from messages printed by the project
- log->push_color(get_color("font_color", "Editor") * Color(1, 1, 1, 0.6));
+ log->push_color(get_theme_color("font_color", "Editor") * Color(1, 1, 1, 0.6));
} break;
}
@@ -181,7 +181,7 @@ EditorLog::EditorLog() {
current = Thread::get_caller_id();
- add_constant_override("separation", get_constant("separation", "VBoxContainer"));
+ add_theme_constant_override("separation", get_theme_constant("separation", "VBoxContainer"));
EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this);
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 323684effe..6f6287ccb5 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -32,6 +32,7 @@
#include "core/bind/core_bind.h"
#include "core/class_db.h"
+#include "core/input/input_filter.h"
#include "core/io/config_file.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
@@ -39,7 +40,6 @@
#include "core/io/stream_peer_ssl.h"
#include "core/message_queue.h"
#include "core/os/file_access.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/path_remap.h"
@@ -47,7 +47,6 @@
#include "core/project_settings.h"
#include "core/translation.h"
#include "core/version.h"
-#include "main/input_default.h"
#include "main/main.h"
#include "scene/gui/center_container.h"
#include "scene/gui/control.h"
@@ -62,9 +61,9 @@
#include "scene/gui/texture_progress.h"
#include "scene/gui/tool_button.h"
#include "scene/resources/packed_scene.h"
-#include "servers/navigation_2d_server.h"
-#include "servers/navigation_server.h"
-#include "servers/physics_2d_server.h"
+#include "servers/navigation_server_2d.h"
+#include "servers/navigation_server_3d.h"
+#include "servers/physics_server_2d.h"
#include "editor/audio_stream_preview.h"
#include "editor/debugger/editor_debugger_node.h"
@@ -115,32 +114,33 @@
#include "editor/plugins/asset_library_editor_plugin.h"
#include "editor/plugins/audio_stream_editor_plugin.h"
#include "editor/plugins/baked_lightmap_editor_plugin.h"
-#include "editor/plugins/camera_editor_plugin.h"
+#include "editor/plugins/camera_3d_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
-#include "editor/plugins/collision_polygon_editor_plugin.h"
+#include "editor/plugins/collision_polygon_3d_editor_plugin.h"
#include "editor/plugins/collision_shape_2d_editor_plugin.h"
#include "editor/plugins/cpu_particles_2d_editor_plugin.h"
-#include "editor/plugins/cpu_particles_editor_plugin.h"
+#include "editor/plugins/cpu_particles_3d_editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/debugger_editor_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
#include "editor/plugins/gi_probe_editor_plugin.h"
+#include "editor/plugins/gpu_particles_2d_editor_plugin.h"
+#include "editor/plugins/gpu_particles_3d_editor_plugin.h"
#include "editor/plugins/gradient_editor_plugin.h"
#include "editor/plugins/item_list_editor_plugin.h"
#include "editor/plugins/light_occluder_2d_editor_plugin.h"
#include "editor/plugins/line_2d_editor_plugin.h"
#include "editor/plugins/material_editor_plugin.h"
#include "editor/plugins/mesh_editor_plugin.h"
-#include "editor/plugins/mesh_instance_editor_plugin.h"
+#include "editor/plugins/mesh_instance_3d_editor_plugin.h"
#include "editor/plugins/mesh_library_editor_plugin.h"
#include "editor/plugins/multimesh_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
-#include "editor/plugins/particles_2d_editor_plugin.h"
-#include "editor/plugins/particles_editor_plugin.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/path_2d_editor_plugin.h"
-#include "editor/plugins/path_editor_plugin.h"
-#include "editor/plugins/physical_bone_plugin.h"
+#include "editor/plugins/path_3d_editor_plugin.h"
+#include "editor/plugins/physical_bone_3d_editor_plugin.h"
#include "editor/plugins/polygon_2d_editor_plugin.h"
#include "editor/plugins/resource_preloader_editor_plugin.h"
#include "editor/plugins/root_motion_editor_plugin.h"
@@ -148,10 +148,9 @@
#include "editor/plugins/script_text_editor.h"
#include "editor/plugins/shader_editor_plugin.h"
#include "editor/plugins/skeleton_2d_editor_plugin.h"
-#include "editor/plugins/skeleton_editor_plugin.h"
-#include "editor/plugins/skeleton_ik_editor_plugin.h"
-#include "editor/plugins/spatial_editor_plugin.h"
-#include "editor/plugins/sprite_editor_plugin.h"
+#include "editor/plugins/skeleton_3d_editor_plugin.h"
+#include "editor/plugins/skeleton_ik_3d_editor_plugin.h"
+#include "editor/plugins/sprite_2d_editor_plugin.h"
#include "editor/plugins/sprite_frames_editor_plugin.h"
#include "editor/plugins/style_box_editor_plugin.h"
#include "editor/plugins/text_editor.h"
@@ -170,20 +169,23 @@
#include "editor/register_exporters.h"
#include "editor/run_settings_dialog.h"
#include "editor/settings_config_dialog.h"
-
+#include "scene/main/window.h"
+#include "servers/display_server.h"
#include <stdio.h>
#include <stdlib.h>
-EditorNode *EditorNode::singleton = NULL;
+EditorNode *EditorNode::singleton = nullptr;
void EditorNode::_update_scene_tabs() {
bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
- OS::get_singleton()->global_menu_clear("_dock");
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
+ DisplayServer::get_singleton()->global_menu_clear("_dock");
+ }
scene_tabs->clear_tabs();
- Ref<Texture2D> script_icon = gui_base->get_icon("Script", "EditorIcons");
+ Ref<Texture2D> script_icon = gui_base->get_theme_icon("Script", "EditorIcons");
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
Node *type_node = editor_data.get_edited_scene_root(i);
@@ -196,15 +198,19 @@ void EditorNode::_update_scene_tabs() {
bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
scene_tabs->add_tab(editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), icon);
- OS::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), GLOBAL_SCENE, i);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i);
+ }
if (show_rb && editor_data.get_scene_root_script(i).is_valid()) {
scene_tabs->set_tab_right_button(i, script_icon);
}
}
- OS::get_singleton()->global_menu_add_separator("_dock");
- OS::get_singleton()->global_menu_add_item("_dock", TTR("New Window"), GLOBAL_NEW_WINDOW, Variant());
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
+ DisplayServer::get_singleton()->global_menu_add_separator("_dock");
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", TTR("New Window"), callable_mp(this, &EditorNode::_global_menu_new_window));
+ }
scene_tabs->set_current_tab(editor_data.get_edited_scene());
@@ -253,16 +259,13 @@ void EditorNode::_update_title() {
if (unsaved_cache)
title += " (*)";
- OS::get_singleton()->set_window_title(title);
+ DisplayServer::get_singleton()->window_set_title(title);
}
void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
- if (Node::get_viewport()->get_modal_stack_top())
- return; //ignore because of modal window
-
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && k->is_pressed() && !k->is_echo() && !gui_base->get_viewport()->gui_has_modal_stack()) {
+ if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
EditorPlugin *old_editor = editor_plugin_screen;
@@ -297,7 +300,7 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
}
if (old_editor != editor_plugin_screen) {
- get_tree()->set_input_as_handled();
+ get_tree()->get_root()->set_input_as_handled();
}
}
}
@@ -335,13 +338,13 @@ void EditorNode::_notification(int p_what) {
// update the icon itself only when the spinner is visible
if (EditorSettings::get_singleton()->get("interface/editor/show_update_spinner")) {
- update_spinner->set_icon(gui_base->get_icon("Progress" + itos(update_spinner_step + 1), "EditorIcons"));
+ update_spinner->set_icon(gui_base->get_theme_icon("Progress" + itos(update_spinner_step + 1), "EditorIcons"));
}
}
editor_selection->update();
- scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
+ //scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
{ //TODO should only happen on settings changed
int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
@@ -355,13 +358,26 @@ void EditorNode::_notification(int p_what) {
scene_root->set_default_canvas_item_texture_repeat(tr);
}
- VS::DOFBokehShape dof_shape = VS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape")));
- VS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
- VS::DOFBlurQuality dof_quality = VS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality")));
- bool dof_jitter = GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter");
- VS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
- VS::get_singleton()->environment_set_ssao_quality(VS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"));
- VS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter"), GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve"));
+ 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"));
+ RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_curve"));
+ bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
+ RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
+ 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);
+ 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);
}
ResourceImporterTexture::get_singleton()->update_imports();
@@ -374,15 +390,14 @@ void EditorNode::_notification(int p_what) {
get_tree()->get_root()->set_as_audio_listener(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
get_tree()->set_auto_accept_quit(false);
- get_tree()->connect("files_dropped", callable_mp(this, &EditorNode::_dropped_files));
- get_tree()->connect("global_menu_action", callable_mp(this, &EditorNode::_global_menu_action));
+ get_tree()->get_root()->connect("files_dropped", callable_mp(this, &EditorNode::_dropped_files));
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
case NOTIFICATION_EXIT_TREE: {
editor_data.save_editor_external_data();
- FileAccess::set_file_close_fail_notify_callback(NULL);
+ FileAccess::set_file_close_fail_notify_callback(nullptr);
log->deinit(); // do not get messages anymore
editor_data.clear_edited_scenes();
} break;
@@ -402,9 +417,9 @@ void EditorNode::_notification(int p_what) {
_initializing_addons = false;
}
- VisualServer::get_singleton()->viewport_set_hide_scenario(get_scene_root()->get_viewport_rid(), true);
- VisualServer::get_singleton()->viewport_set_hide_canvas(get_scene_root()->get_viewport_rid(), true);
- VisualServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_hide_scenario(get_scene_root()->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_hide_canvas(get_scene_root()->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(), true);
feature_profile_manager->notify_changed();
@@ -417,7 +432,7 @@ void EditorNode::_notification(int p_what) {
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_FOCUS_IN: {
// Restore the original FPS cap after focusing back on the editor
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
@@ -425,18 +440,18 @@ void EditorNode::_notification(int p_what) {
EditorFileSystem::get_singleton()->scan_changes();
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_WM_FOCUS_OUT: {
// Set a low FPS cap to decrease CPU/GPU usage while the editor is unfocused
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/unfocused_low_processor_mode_sleep_usec")));
} break;
- case MainLoop::NOTIFICATION_WM_ABOUT: {
+ case NOTIFICATION_WM_ABOUT: {
show_about();
} break;
- case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
_menu_option_confirm(FILE_QUIT, false);
} break;
@@ -448,17 +463,17 @@ void EditorNode::_notification(int p_what) {
theme_base->set_theme(theme);
gui_base->set_theme(theme);
- gui_base->add_style_override("panel", gui_base->get_stylebox("Background", "EditorStyles"));
- scene_root_parent->add_style_override("panel", gui_base->get_stylebox("Content", "EditorStyles"));
- bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer"));
- scene_tabs->add_style_override("tab_fg", gui_base->get_stylebox("SceneTabFG", "EditorStyles"));
- scene_tabs->add_style_override("tab_bg", gui_base->get_stylebox("SceneTabBG", "EditorStyles"));
+ gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox("Background", "EditorStyles"));
+ scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox("Content", "EditorStyles"));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("panel", "TabContainer"));
+ scene_tabs->add_theme_style_override("tab_fg", gui_base->get_theme_stylebox("SceneTabFG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_bg", gui_base->get_theme_stylebox("SceneTabBG", "EditorStyles"));
- file_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
- project_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
- debug_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
- settings_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
- help_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
+ file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
+ project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
+ debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
+ settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
+ help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
if (EDITOR_GET("interface/scene_tabs/resize_if_many_tabs")) {
scene_tabs->set_min_width(int(EDITOR_GET("interface/scene_tabs/minimum_width")) * EDSCALE);
@@ -471,7 +486,7 @@ void EditorNode::_notification(int p_what) {
// debugger area
if (EditorDebuggerNode::get_singleton()->is_visible())
- bottom_panel->add_style_override("panel", gui_base->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles"));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles"));
// update_icons
for (int i = 0; i < singleton->main_editor_buttons.size(); i++) {
@@ -482,36 +497,38 @@ void EditorNode::_notification(int p_what) {
if (icon.is_valid()) {
tb->set_icon(icon);
- } else if (singleton->gui_base->has_icon(p_editor->get_name(), "EditorIcons")) {
- tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons"));
+ } else if (singleton->gui_base->has_theme_icon(p_editor->get_name(), "EditorIcons")) {
+ tb->set_icon(singleton->gui_base->get_theme_icon(p_editor->get_name(), "EditorIcons"));
}
}
_build_icon_type_cache();
- play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons"));
- play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons"));
- play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons"));
- pause_button->set_icon(gui_base->get_icon("Pause", "EditorIcons"));
- stop_button->set_icon(gui_base->get_icon("Stop", "EditorIcons"));
+ play_button->set_icon(gui_base->get_theme_icon("MainPlay", "EditorIcons"));
+ play_scene_button->set_icon(gui_base->get_theme_icon("PlayScene", "EditorIcons"));
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon("PlayCustom", "EditorIcons"));
+ pause_button->set_icon(gui_base->get_theme_icon("Pause", "EditorIcons"));
+ stop_button->set_icon(gui_base->get_theme_icon("Stop", "EditorIcons"));
- prev_scene->set_icon(gui_base->get_icon("PrevScene", "EditorIcons"));
- distraction_free->set_icon(gui_base->get_icon("DistractionFree", "EditorIcons"));
- scene_tab_add->set_icon(gui_base->get_icon("Add", "EditorIcons"));
+ prev_scene->set_icon(gui_base->get_theme_icon("PrevScene", "EditorIcons"));
+ distraction_free->set_icon(gui_base->get_theme_icon("DistractionFree", "EditorIcons"));
+ scene_tab_add->set_icon(gui_base->get_theme_icon("Add", "EditorIcons"));
- bottom_panel_raise->set_icon(gui_base->get_icon("ExpandBottomDock", "EditorIcons"));
+ bottom_panel_raise->set_icon(gui_base->get_theme_icon("ExpandBottomDock", "EditorIcons"));
// clear_button->set_icon(gui_base->get_icon("Close", "EditorIcons")); don't have access to that node. needs to become a class property
dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons"));
dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons"));
PopupMenu *p = help_menu->get_popup();
- p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_icon("HelpSearch", "EditorIcons"));
- p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_icon("Instance", "EditorIcons"));
- p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_icon("Instance", "EditorIcons"));
- p->set_item_icon(p->get_item_index(HELP_ISSUES), gui_base->get_icon("Instance", "EditorIcons"));
- p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_icon("Instance", "EditorIcons"));
- p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_icon("Godot", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_theme_icon("HelpSearch", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_theme_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_theme_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_theme_icon("Godot", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_theme_icon("Godot", "EditorIcons"));
_update_update_spinner();
} break;
@@ -547,7 +564,7 @@ void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_nam
void EditorNode::_resources_changed(const Vector<String> &p_resources) {
- List<Ref<Resource> > changed;
+ List<Ref<Resource>> changed;
int rc = p_resources.size();
for (int i = 0; i < rc; i++) {
@@ -573,7 +590,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) {
}
if (changed.size()) {
- for (List<Ref<Resource> >::Element *E = changed.front(); E; E = E->next()) {
+ for (List<Ref<Resource>>::Element *E = changed.front(); E; E = E->next()) {
E->get()->reload_from_file();
}
}
@@ -822,7 +839,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
}
}
- file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
saving_resource = p_resource;
current_option = RESOURCE_SAVE_AS;
@@ -859,7 +876,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->set_current_path(p_resource->get_path());
if (extensions.size()) {
String ext = p_resource->get_path().get_extension().to_lower();
- if (extensions.find(ext) == NULL) {
+ if (extensions.find(ext) == nullptr) {
file->set_current_path(p_resource->get_path().replacen("." + ext, "." + extensions.front()->get()));
}
}
@@ -1105,7 +1122,7 @@ void EditorNode::_find_node_types(Node *p_node, int &count_2d, int &count_3d) {
if (p_node->is_class("CanvasItem"))
count_2d++;
- else if (p_node->is_class("Spatial"))
+ else if (p_node->is_class("Node3D"))
count_3d++;
for (int i = 0; i < p_node->get_child_count(); i++)
@@ -1116,7 +1133,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
EditorProgress save("save", TTR("Saving Scene"), 4);
- if (editor_data.get_edited_scene_root() != NULL) {
+ if (editor_data.get_edited_scene_root() != nullptr) {
save.step(TTR("Analyzing"), 0);
int c2d = 0;
@@ -1137,7 +1154,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
if (is2d) {
img = scene_root->get_texture()->get_data();
} else {
- img = SpatialEditor::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_data();
}
if (img.is_valid()) {
@@ -1210,7 +1227,7 @@ bool EditorNode::_validate_scene_recursive(const String &p_filename, Node *p_nod
return false;
}
-static bool _find_edited_resources(const Ref<Resource> &p_resource, Set<Ref<Resource> > &edited_resources) {
+static bool _find_edited_resources(const Ref<Resource> &p_resource, Set<Ref<Resource>> &edited_resources) {
if (p_resource->is_edited()) {
edited_resources.insert(p_resource);
@@ -1247,11 +1264,11 @@ int EditorNode::_save_external_resources() {
flg |= ResourceSaver::FLAG_COMPRESS;
flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
- Set<Ref<Resource> > edited_subresources;
+ Set<Ref<Resource>> edited_subresources;
int saved = 0;
- List<Ref<Resource> > cached;
+ List<Ref<Resource>> cached;
ResourceCache::get_cached_resources(&cached);
- for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) {
+ for (List<Ref<Resource>>::Element *E = cached.front(); E; E = E->next()) {
Ref<Resource> res = E->get();
if (!res->get_path().is_resource_file())
@@ -1266,7 +1283,7 @@ int EditorNode::_save_external_resources() {
// clear later, because user may have put the same subresource in two different resources,
// which will be shared until the next reload
- for (Set<Ref<Resource> >::Element *E = edited_subresources.front(); E; E = E->next()) {
+ for (Set<Ref<Resource>>::Element *E = edited_subresources.front(); E; E = E->next()) {
Ref<Resource> res = E->get();
res->set_edited(false);
}
@@ -1466,7 +1483,7 @@ void EditorNode::_dialog_action(String p_file) {
int scene_idx = (current_option == FILE_SAVE_SCENE || current_option == FILE_SAVE_AS_SCENE) ? -1 : tab_closing;
- if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
+ if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
bool same_open_scene = false;
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
if (editor_data.get_scene_path(i) == p_file && i != scene_idx)
@@ -1490,7 +1507,7 @@ void EditorNode::_dialog_action(String p_file) {
} break;
case FILE_SAVE_AND_RUN: {
- if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
+ if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
_save_default_environment();
_save_scene_with_preview(p_file);
@@ -1555,7 +1572,7 @@ void EditorNode::_dialog_action(String p_file) {
save_resource_in_path(saving_resource, p_file);
saving_resource = Ref<Resource>();
ObjectID current = editor_history.get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
ERR_FAIL_COND(!current_obj);
current_obj->_change_notify();
} break;
@@ -1620,7 +1637,7 @@ void EditorNode::_dialog_action(String p_file) {
} break;
default: { //save scene?
- if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
+ if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
_save_scene_with_preview(p_file);
}
@@ -1701,10 +1718,10 @@ void EditorNode::edit_item(Object *p_object) {
void EditorNode::push_item(Object *p_object, const String &p_property, bool p_inspector_only) {
if (!p_object) {
- get_inspector()->edit(NULL);
- node_dock->set_node(NULL);
- scene_tree_dock->set_selected(NULL);
- inspector_dock->update(NULL);
+ get_inspector()->edit(nullptr);
+ node_dock->set_node(nullptr);
+ scene_tree_dock->set_selected(nullptr);
+ inspector_dock->update(nullptr);
return;
}
@@ -1765,17 +1782,17 @@ static bool overrides_external_editor(Object *p_object) {
void EditorNode::_edit_current() {
ObjectID current = editor_history.get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
bool inspector_only = editor_history.is_current_inspector_only();
this->current = current_obj;
if (!current_obj) {
- scene_tree_dock->set_selected(NULL);
- get_inspector()->edit(NULL);
- node_dock->set_node(NULL);
- inspector_dock->update(NULL);
+ scene_tree_dock->set_selected(nullptr);
+ get_inspector()->edit(nullptr);
+ node_dock->set_node(nullptr);
+ inspector_dock->update(nullptr);
_display_top_editors(false);
@@ -1796,9 +1813,9 @@ void EditorNode::_edit_current() {
Resource *current_res = Object::cast_to<Resource>(current_obj);
ERR_FAIL_COND(!current_res);
get_inspector()->edit(current_res);
- scene_tree_dock->set_selected(NULL);
- node_dock->set_node(NULL);
- inspector_dock->update(NULL);
+ scene_tree_dock->set_selected(nullptr);
+ node_dock->set_node(nullptr);
+ inspector_dock->update(nullptr);
EditorNode::get_singleton()->get_import_dock()->set_edit_path(current_res->get_path());
int subr_idx = current_res->get_path().find("::");
@@ -1827,9 +1844,9 @@ void EditorNode::_edit_current() {
scene_tree_dock->set_selected(current_node);
inspector_dock->update(current_node);
} else {
- node_dock->set_node(NULL);
- scene_tree_dock->set_selected(NULL);
- inspector_dock->update(NULL);
+ node_dock->set_node(nullptr);
+ scene_tree_dock->set_selected(nullptr);
+ inspector_dock->update(nullptr);
}
if (get_edited_scene() && get_edited_scene()->get_filename() != String()) {
@@ -1841,7 +1858,7 @@ void EditorNode::_edit_current() {
} else {
- Node *selected_node = NULL;
+ Node *selected_node = nullptr;
if (current_obj->is_class("EditorDebuggerRemoteObject")) {
editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
@@ -1870,9 +1887,9 @@ void EditorNode::_edit_current() {
}
get_inspector()->edit(current_obj);
- node_dock->set_node(NULL);
+ node_dock->set_node(nullptr);
scene_tree_dock->set_selected(selected_node);
- inspector_dock->update(NULL);
+ inspector_dock->update(nullptr);
}
if (current_obj == prev_inspected_object) {
@@ -1898,7 +1915,7 @@ void EditorNode::_edit_current() {
for (int i = 0; i < editor_table.size(); i++) {
if (editor_table[i] == main_plugin && !main_editor_buttons[i]->is_visible()) {
- main_plugin = NULL; //if button is not visible, then no plugin active
+ main_plugin = nullptr; //if button is not visible, then no plugin active
}
}
@@ -1970,11 +1987,11 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
}
play_button->set_pressed(false);
- play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons"));
+ play_button->set_icon(gui_base->get_theme_icon("MainPlay", "EditorIcons"));
play_scene_button->set_pressed(false);
- play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons"));
+ play_scene_button->set_icon(gui_base->get_theme_icon("PlayScene", "EditorIcons"));
play_custom_scene_button->set_pressed(false);
- play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons"));
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon("PlayCustom", "EditorIcons"));
String main_scene;
String run_filename;
@@ -2057,14 +2074,14 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
emit_signal("play_pressed");
if (p_current) {
play_scene_button->set_pressed(true);
- play_scene_button->set_icon(gui_base->get_icon("Reload", "EditorIcons"));
+ play_scene_button->set_icon(gui_base->get_theme_icon("Reload", "EditorIcons"));
} else if (p_custom != "") {
run_custom_filename = p_custom;
play_custom_scene_button->set_pressed(true);
- play_custom_scene_button->set_icon(gui_base->get_icon("Reload", "EditorIcons"));
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon("Reload", "EditorIcons"));
} else {
play_button->set_pressed(true);
- play_button->set_icon(gui_base->get_icon("Reload", "EditorIcons"));
+ play_button->set_icon(gui_base->get_theme_icon("Reload", "EditorIcons"));
}
stop_button->set_disabled(false);
@@ -2085,7 +2102,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_NEW_INHERITED_SCENE:
case FILE_OPEN_SCENE: {
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
file->clear_filters();
@@ -2158,7 +2175,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename();
save_confirmation->get_ok()->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_minsize();
+ save_confirmation->popup_centered();
break;
}
} else if (p_option == FILE_CLOSE) {
@@ -2212,7 +2229,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
break;
}
- file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
List<String> extensions;
Ref<PackedScene> sd = memnew(PackedScene);
@@ -2227,7 +2244,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file->set_current_path(scene->get_filename());
if (extensions.size()) {
String ext = scene->get_filename().get_extension().to_lower();
- if (extensions.find(ext) == NULL) {
+ if (extensions.find(ext) == nullptr) {
file->set_current_path(scene->get_filename().replacen("." + ext, "." + extensions.front()->get()));
}
}
@@ -2254,7 +2271,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
confirmation->get_cancel()->set_text(TTR("No"));
confirmation->get_ok()->set_text(TTR("Yes"));
confirmation->set_text(TTR("This scene has never been saved. Save before running?"));
- confirmation->popup_centered_minsize();
+ confirmation->popup_centered();
break;
}
@@ -2326,7 +2343,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
confirmation->get_ok()->set_text(TTR("Open"));
confirmation->set_text(TTR("Current scene not saved. Open anyway?"));
- confirmation->popup_centered_minsize();
+ confirmation->popup_centered();
break;
}
@@ -2341,7 +2358,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case EDIT_UNDO: {
- if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
+ if (InputFilter::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message("Can't undo while mouse buttons are pressed.", EditorLog::MSG_TYPE_EDITOR);
} else {
String action = editor_data.get_undo_redo().get_current_action_name();
@@ -2355,7 +2372,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case EDIT_REDO: {
- if (Input::get_singleton()->get_mouse_button_mask() & 0x7) {
+ if (InputFilter::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message("Can't redo while mouse buttons are pressed.", EditorLog::MSG_TYPE_EDITOR);
} else {
if (!editor_data.get_undo_redo().redo()) {
@@ -2384,7 +2401,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (unsaved_cache && !p_confirmed) {
confirmation->get_ok()->set_text(TTR("Revert"));
confirmation->set_text(TTR("This action cannot be undone. Revert anyway?"));
- confirmation->popup_centered_minsize();
+ confirmation->popup_centered();
break;
}
@@ -2424,11 +2441,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
editor_run.stop();
run_custom_filename.clear();
play_button->set_pressed(false);
- play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons"));
+ play_button->set_icon(gui_base->get_theme_icon("MainPlay", "EditorIcons"));
play_scene_button->set_pressed(false);
- play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons"));
+ play_scene_button->set_icon(gui_base->get_theme_icon("PlayScene", "EditorIcons"));
play_custom_scene_button->set_pressed(false);
- play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons"));
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon("PlayCustom", "EditorIcons"));
stop_button->set_disabled(true);
if (bool(EDITOR_GET("run/output/always_close_output_on_stop"))) {
@@ -2487,11 +2504,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
export_template_manager->install_android_template();
} else {
if (DirAccess::exists("res://android/build")) {
- remove_android_build_template->popup_centered_minsize();
+ remove_android_build_template->popup_centered();
} else if (export_template_manager->can_install_android_template()) {
- install_android_build_template->popup_centered_minsize();
+ install_android_build_template->popup_centered();
} else {
- custom_build_manage_templates->popup_centered_minsize();
+ custom_build_manage_templates->popup_centered();
}
}
} break;
@@ -2513,7 +2530,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
confirmation->get_ok()->set_text(p_option == FILE_QUIT ? TTR("Quit") : TTR("Yes"));
confirmation->set_text(p_option == FILE_QUIT ? TTR("Exit the editor?") : TTR("Open Project Manager?"));
- confirmation->popup_centered_minsize();
+ confirmation->popup_centered();
} else {
_discard_changes();
break;
@@ -2534,11 +2551,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
save_confirmation->get_ok()->set_text(TTR("Save & Quit"));
save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes the following scene(s) before opening Project Manager?")) + unsaved_scenes);
- save_confirmation->popup_centered_minsize();
+ save_confirmation->popup_centered();
}
}
- OS::get_singleton()->request_attention();
+ DisplayServer::get_singleton()->window_request_attention();
break;
}
@@ -2586,13 +2603,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SETTINGS_TOGGLE_FULLSCREEN: {
- OS::get_singleton()->set_window_fullscreen(!OS::get_singleton()->is_window_fullscreen());
+ DisplayServer::get_singleton()->window_set_mode(DisplayServer::get_singleton()->window_get_mode() == DisplayServer::WINDOW_MODE_FULLSCREEN ? DisplayServer::WINDOW_MODE_WINDOWED : DisplayServer::WINDOW_MODE_FULLSCREEN);
} break;
case SETTINGS_TOGGLE_CONSOLE: {
- bool was_visible = OS::get_singleton()->is_console_visible();
- OS::get_singleton()->set_console_visible(!was_visible);
+ bool was_visible = DisplayServer::get_singleton()->is_console_visible();
+ DisplayServer::get_singleton()->console_set_visible(!was_visible);
EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", was_visible);
} break;
case EDITOR_SCREENSHOT: {
@@ -2601,7 +2618,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SETTINGS_PICK_MAIN_SCENE: {
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
file->clear_filters();
@@ -2627,14 +2644,17 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case HELP_QA: {
OS::get_singleton()->shell_open("https://godotengine.org/qa/");
} break;
- case HELP_ISSUES: {
+ case HELP_REPORT_A_BUG: {
OS::get_singleton()->shell_open("https://github.com/godotengine/godot/issues");
} break;
+ case HELP_SEND_DOCS_FEEDBACK: {
+ OS::get_singleton()->shell_open("https://github.com/godotengine/godot-docs/issues");
+ } break;
case HELP_COMMUNITY: {
OS::get_singleton()->shell_open("https://godotengine.org/community");
} break;
case HELP_ABOUT: {
- about->popup_centered_minsize(Size2(780, 500) * EDSCALE);
+ about->popup_centered(Size2(780, 500) * EDSCALE);
} break;
case SET_VIDEO_DRIVER_SAVE_AND_RESTART: {
@@ -2663,10 +2683,10 @@ void EditorNode::_screenshot(bool p_use_utc) {
void EditorNode::_save_screenshot(NodePath p_path) {
- Viewport *viewport = EditorInterface::get_singleton()->get_editor_viewport()->get_viewport();
- viewport->set_clear_mode(Viewport::CLEAR_MODE_ONLY_NEXT_FRAME);
+ SubViewport *viewport = Object::cast_to<SubViewport>(EditorInterface::get_singleton()->get_editor_viewport()->get_viewport());
+ viewport->set_clear_mode(SubViewport::CLEAR_MODE_ONLY_NEXT_FRAME);
Ref<Image> img = viewport->get_texture()->get_data();
- viewport->set_clear_mode(Viewport::CLEAR_MODE_ALWAYS);
+ viewport->set_clear_mode(SubViewport::CLEAR_MODE_ALWAYS);
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
}
@@ -2737,7 +2757,7 @@ void EditorNode::_discard_changes(const String &p_str) {
case SCENE_TAB_CLOSE: {
Node *scene = editor_data.get_edited_scene_root(tab_closing);
- if (scene != NULL) {
+ if (scene != nullptr) {
String scene_filename = scene->get_filename();
if (scene_filename != "") {
previous_scenes.push_back(scene_filename);
@@ -2884,8 +2904,8 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
if (icon.is_valid()) {
tb->set_icon(icon);
- } else if (singleton->gui_base->has_icon(p_editor->get_name(), "EditorIcons")) {
- tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons"));
+ } else if (singleton->gui_base->has_theme_icon(p_editor->get_name(), "EditorIcons")) {
+ tb->set_icon(singleton->gui_base->get_theme_icon(p_editor->get_name(), "EditorIcons"));
}
tb->set_name(p_editor->get_name());
@@ -3117,7 +3137,7 @@ Dictionary EditorNode::_get_main_scene_state() {
void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
- if (get_edited_scene() != p_for_scene && p_for_scene != NULL)
+ if (get_edited_scene() != p_for_scene && p_for_scene != nullptr)
return; //not for this scene
changing_scene = false;
@@ -3269,7 +3289,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!p_force_open_imported && FileAccess::exists(p_scene + ".import")) {
open_imported->set_text(vformat(TTR("Scene '%s' was automatically imported, so it can't be modified.\nTo make changes to it, a new inherited scene can be created."), p_scene.get_file()));
- open_imported->popup_centered_minsize();
+ open_imported->popup_centered();
new_inherited_button->grab_focus();
open_import_request = p_scene;
return OK;
@@ -3333,7 +3353,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
dependency_errors.erase(lpath); //at least not self path
- for (Map<String, Set<String> >::Element *E = dependency_errors.front(); E; E = E->next()) {
+ for (Map<String, Set<String>>::Element *E = dependency_errors.front(); E; E = E->next()) {
String txt = vformat(TTR("Scene '%s' has broken dependencies:"), E->key()) + "\n";
for (Set<String>::Element *F = E->get().front(); F; F = F->next()) {
@@ -3412,7 +3432,7 @@ void EditorNode::open_request(const String &p_path) {
if (!opening_prev) {
List<String>::Element *prev_scene = previous_scenes.find(p_path);
- if (prev_scene != NULL) {
+ if (prev_scene != nullptr) {
prev_scene->erase();
}
}
@@ -3553,7 +3573,7 @@ void EditorNode::add_io_error(const String &p_error) {
void EditorNode::_load_error_notify(void *p_ud, const String &p_text) {
EditorNode *en = (EditorNode *)p_ud;
- en->load_errors->add_image(en->gui_base->get_icon("Error", "EditorIcons"));
+ en->load_errors->add_image(en->gui_base->get_theme_icon("Error", "EditorIcons"));
en->load_errors->add_text(p_text + "\n");
en->load_error_dialog->popup_centered_ratio(0.5);
}
@@ -3593,8 +3613,8 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<EditorSelection>();
ClassDB::register_class<EditorFileDialog>();
ClassDB::register_virtual_class<EditorSettings>();
- ClassDB::register_class<EditorSpatialGizmo>();
- ClassDB::register_class<EditorSpatialGizmoPlugin>();
+ ClassDB::register_class<EditorNode3DGizmo>();
+ ClassDB::register_class<EditorNode3DGizmoPlugin>();
ClassDB::register_virtual_class<EditorResourcePreview>();
ClassDB::register_class<EditorResourcePreviewGenerator>();
ClassDB::register_virtual_class<EditorFileSystem>();
@@ -3612,6 +3632,7 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<ScriptCreateDialog>();
ClassDB::register_class<EditorFeatureProfile>();
ClassDB::register_class<EditorSpinSlider>();
+ ClassDB::register_virtual_class<FileSystemDock>();
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
ClassDB::register_class<EditorScenePostImport>();
@@ -3633,7 +3654,7 @@ void EditorNode::stop_child_process(OS::ProcessID p_pid) {
}
Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) const {
- ERR_FAIL_COND_V(!p_object, NULL);
+ ERR_FAIL_COND_V(!p_object, nullptr);
Ref<Script> script = p_object->get_script();
@@ -3660,7 +3681,7 @@ Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) cons
}
}
- return NULL;
+ return nullptr;
}
StringName EditorNode::get_object_custom_type_name(const Object *p_object) const {
@@ -3706,11 +3727,11 @@ Ref<ImageTexture> EditorNode::_load_custom_class_icon(const String &p_path) cons
return icon;
}
}
- return NULL;
+ return nullptr;
}
Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String &p_fallback) const {
- ERR_FAIL_COND_V(!p_object || !gui_base, NULL);
+ ERR_FAIL_COND_V(!p_object || !gui_base, nullptr);
Ref<Script> script = p_object->get_script();
if (script.is_null() && p_object->is_class("Script")) {
@@ -3745,20 +3766,20 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String
if (p_object->has_meta("_editor_icon"))
return p_object->get_meta("_editor_icon");
- if (gui_base->has_icon(p_object->get_class(), "EditorIcons"))
- return gui_base->get_icon(p_object->get_class(), "EditorIcons");
+ if (gui_base->has_theme_icon(p_object->get_class(), "EditorIcons"))
+ return gui_base->get_theme_icon(p_object->get_class(), "EditorIcons");
if (p_fallback.length())
- return gui_base->get_icon(p_fallback, "EditorIcons");
+ return gui_base->get_theme_icon(p_fallback, "EditorIcons");
- return NULL;
+ return nullptr;
}
Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p_fallback) const {
- ERR_FAIL_COND_V_MSG(p_class.empty(), NULL, "Class name cannot be empty.");
+ ERR_FAIL_COND_V_MSG(p_class.empty(), nullptr, "Class name cannot be empty.");
- if (gui_base->has_icon(p_class, "EditorIcons")) {
- return gui_base->get_icon(p_class, "EditorIcons");
+ if (gui_base->has_theme_icon(p_class, "EditorIcons")) {
+ return gui_base->get_theme_icon(p_class, "EditorIcons");
}
if (ScriptServer::is_global_class(p_class)) {
@@ -3772,7 +3793,7 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
while (script.is_valid()) {
String current_icon_path;
- script->get_language()->get_global_class_name(script->get_path(), NULL, &current_icon_path);
+ script->get_language()->get_global_class_name(script->get_path(), nullptr, &current_icon_path);
icon = _load_custom_class_icon(current_icon_path);
if (icon.is_valid()) {
return icon;
@@ -3781,14 +3802,14 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
if (icon.is_null()) {
- icon = gui_base->get_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons");
+ icon = gui_base->get_theme_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons");
}
return icon;
}
- const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();
- for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) {
+ const Map<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types();
+ for (const Map<String, Vector<EditorData::CustomType>>::Element *E = p_map.front(); E; E = E->next()) {
const Vector<EditorData::CustomType> &ct = E->value();
for (int i = 0; i < ct.size(); ++i) {
if (ct[i].name == p_class) {
@@ -3799,10 +3820,10 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
}
- if (p_fallback.length() && gui_base->has_icon(p_fallback, "EditorIcons"))
- return gui_base->get_icon(p_fallback, "EditorIcons");
+ if (p_fallback.length() && gui_base->has_theme_icon(p_fallback, "EditorIcons"))
+ return gui_base->get_theme_icon(p_fallback, "EditorIcons");
- return NULL;
+ return nullptr;
}
void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
@@ -3921,7 +3942,7 @@ void EditorNode::show_accept(const String &p_text, const String &p_title) {
current_option = -1;
accept->get_ok()->set_text(p_title);
accept->set_text(p_text);
- accept->popup_centered_minsize();
+ accept->popup_centered();
}
void EditorNode::show_warning(const String &p_text, const String &p_title) {
@@ -3929,7 +3950,7 @@ void EditorNode::show_warning(const String &p_text, const String &p_title) {
if (warning->is_inside_tree()) {
warning->set_text(p_text);
warning->set_title(p_title);
- warning->popup_centered_minsize();
+ warning->popup_centered();
} else {
WARN_PRINT(p_title + " " + p_text);
}
@@ -3937,7 +3958,91 @@ void EditorNode::show_warning(const String &p_text, const String &p_title) {
void EditorNode::_copy_warning(const String &p_str) {
- OS::get_singleton()->set_clipboard(warning->get_text());
+ DisplayServer::get_singleton()->clipboard_set(warning->get_text());
+}
+
+void EditorNode::_dock_floating_close_request(Control *p_control) {
+ // Through the MarginContainer to the Window.
+ Window *window = (Window *)p_control->get_parent()->get_parent();
+ int window_slot = window->get_meta("dock_slot");
+
+ p_control->get_parent()->remove_child(p_control);
+ dock_slot[window_slot]->add_child(p_control);
+ dock_slot[window_slot]->move_child(p_control, MIN((int)window->get_meta("dock_index"), dock_slot[window_slot]->get_child_count()));
+ dock_slot[window_slot]->set_current_tab(window->get_meta("dock_index"));
+
+ window->queue_delete();
+
+ _update_dock_containers();
+
+ floating_docks.erase(p_control);
+}
+
+void EditorNode::_dock_make_float() {
+ Control *dock = dock_slot[dock_popup_selected]->get_current_tab_control();
+ ERR_FAIL_COND(!dock);
+
+ const Size2i borders = Size2i(4, 4) * EDSCALE;
+ Size2 dock_size = dock->get_size() + borders * 2; //remember size
+ Point2 dock_screen_pos = dock->get_global_position() + get_tree()->get_root()->get_position() - borders;
+
+ print_line("dock pos: " + dock->get_global_position() + " window pos: " + get_tree()->get_root()->get_position());
+ int dock_index = dock->get_index();
+ dock_slot[dock_popup_selected]->remove_child(dock);
+
+ Window *window = memnew(Window);
+ window->set_title(dock->get_name());
+ Panel *p = memnew(Panel);
+ p->set_mode(Panel::MODE_FOREGROUND);
+ p->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ window->add_child(p);
+ MarginContainer *margin = memnew(MarginContainer);
+ margin->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ margin->add_theme_constant_override("margin_right", borders.width);
+ margin->add_theme_constant_override("margin_top", borders.height);
+ margin->add_theme_constant_override("margin_left", borders.width);
+ margin->add_theme_constant_override("margin_bottom", borders.height);
+ window->add_child(margin);
+ dock->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ margin->add_child(dock);
+ window->set_wrap_controls(true);
+ window->set_size(dock_size);
+ window->set_position(dock_screen_pos);
+ window->set_transient(true);
+ window->connect("close_requested", callable_mp(this, &EditorNode::_dock_floating_close_request), varray(dock));
+ window->set_meta("dock_slot", dock_popup_selected);
+ window->set_meta("dock_index", dock_index);
+ gui_base->add_child(window);
+
+ dock_select_popup->hide();
+
+ _update_dock_containers();
+
+ floating_docks.push_back(dock);
+}
+
+void EditorNode::_update_dock_containers() {
+
+ for (int i = 0; i < DOCK_SLOT_MAX; i++) {
+ if (dock_slot[i]->get_tab_count() == 0 && dock_slot[i]->is_visible()) {
+ dock_slot[i]->hide();
+ }
+ if (dock_slot[i]->get_tab_count() > 0 && !dock_slot[i]->is_visible()) {
+ dock_slot[i]->show();
+ }
+ }
+ for (int i = 0; i < vsplits.size(); i++) {
+ bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
+ if (in_use)
+ vsplits[i]->show();
+ else
+ vsplits[i]->hide();
+ }
+
+ if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible())
+ right_hsplit->show();
+ else
+ right_hsplit->hide();
}
void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
@@ -3985,18 +4090,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
dock_slot[nrect]->show();
dock_select->update();
- for (int i = 0; i < vsplits.size(); i++) {
- bool in_use = dock_slot[i * 2 + 0]->get_tab_count() || dock_slot[i * 2 + 1]->get_tab_count();
- if (in_use)
- vsplits[i]->show();
- else
- vsplits[i]->hide();
- }
-
- if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible())
- right_hsplit->show();
- else
- right_hsplit->hide();
+ _update_dock_containers();
_edit_current();
_save_docks();
@@ -4050,7 +4144,7 @@ void EditorNode::_dock_select_draw() {
Color used = Color(0.6, 0.6, 0.6, 0.8);
Color used_selected = Color(0.8, 0.8, 0.8, 0.8);
- Color tab_selected = theme_base->get_color("mono_color", "Editor");
+ Color tab_selected = theme_base->get_theme_color("mono_color", "Editor");
Color unused = used;
unused.a = 0.4;
Color unusable = unused;
@@ -4328,7 +4422,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
String name = names[j];
//find it, in a horribly inefficient way
int atidx = -1;
- Control *node = NULL;
+ Control *node = nullptr;
for (int k = 0; k < DOCK_SLOT_MAX; k++) {
if (!dock_slot[k]->has_node(name))
continue;
@@ -4453,7 +4547,7 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
current_option = -1;
pick_main_scene->set_text(TTR("No main scene has ever been defined, select one?\nYou can change it later in \"Project Settings\" under the 'application' category."));
- pick_main_scene->popup_centered_minsize();
+ pick_main_scene->popup_centered();
return false;
}
@@ -4461,7 +4555,7 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
current_option = -1;
pick_main_scene->set_text(vformat(TTR("Selected scene '%s' does not exist, select a valid one?\nYou can change it later in \"Project Settings\" under the 'application' category."), main_scene));
- pick_main_scene->popup_centered_minsize();
+ pick_main_scene->popup_centered();
return false;
}
@@ -4469,7 +4563,7 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
current_option = -1;
pick_main_scene->set_text(vformat(TTR("Selected scene '%s' is not a scene file, select a valid one?\nYou can change it later in \"Project Settings\" under the 'application' category."), main_scene));
- pick_main_scene->popup_centered_minsize();
+ pick_main_scene->popup_centered();
return false;
}
@@ -4589,7 +4683,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
if (unsaved) {
save_confirmation->get_ok()->set_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene->get_filename() != "" ? scene->get_filename() : "unsaved scene"));
- save_confirmation->popup_centered_minsize();
+ save_confirmation->popup_centered();
} else {
_discard_changes();
}
@@ -4813,9 +4907,9 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) {
bottom_panel_items[i].control->set_visible(i == p_idx);
}
if (EditorDebuggerNode::get_singleton() == bottom_panel_items[p_idx].control) { // this is the debug panel which uses tabs, so the top section should be smaller
- bottom_panel->add_style_override("panel", gui_base->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles"));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("BottomPanelDebuggerOverride", "EditorStyles"));
} else {
- bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer"));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("panel", "TabContainer"));
}
center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
center_split->set_collapsed(false);
@@ -4825,7 +4919,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) {
bottom_panel_raise->show();
} else {
- bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer"));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("panel", "TabContainer"));
bottom_panel_items[p_idx].button->set_pressed(false);
bottom_panel_items[p_idx].control->set_visible(false);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
@@ -4894,7 +4988,7 @@ void EditorNode::add_control_to_dock(DockSlot p_slot, Control *p_control) {
void EditorNode::remove_control_from_dock(Control *p_control) {
- Control *dock = NULL;
+ Control *dock = nullptr;
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
if (p_control->get_parent() == dock_slot[i]) {
dock = dock_slot[i];
@@ -4918,7 +5012,7 @@ Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) {
{
//todo make proper previews
- Ref<ImageTexture> pic = gui_base->get_icon("FileBigThumb", "EditorIcons");
+ Ref<ImageTexture> pic = gui_base->get_theme_icon("FileBigThumb", "EditorIcons");
Ref<Image> img = pic->get_data();
img = img->duplicate();
img->resize(48, 48); //meh
@@ -4970,10 +5064,10 @@ Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *
if (p_paths[i].ends_with("/")) {
label->set_text(p_paths[i].substr(0, p_paths[i].length() - 1).get_file());
- icon->set_texture(gui_base->get_icon("Folder", "EditorIcons"));
+ icon->set_texture(gui_base->get_theme_icon("Folder", "EditorIcons"));
} else {
label->set_text(p_paths[i].get_file());
- icon->set_texture(gui_base->get_icon("File", "EditorIcons"));
+ icon->set_texture(gui_base->get_theme_icon("File", "EditorIcons"));
}
icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
icon->set_size(Size2(16, 16));
@@ -5017,7 +5111,7 @@ void EditorNode::add_tool_menu_item(const String &p_name, Object *p_handler, con
void EditorNode::add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu) {
ERR_FAIL_NULL(p_submenu);
- ERR_FAIL_COND(p_submenu->get_parent() != NULL);
+ ERR_FAIL_COND(p_submenu->get_parent() != nullptr);
tool_menu->add_child(p_submenu);
tool_menu->add_submenu_item(p_name, p_submenu->get_name(), TOOLS_CUSTOM);
@@ -5041,21 +5135,19 @@ void EditorNode::remove_tool_menu_item(const String &p_name) {
}
}
-void EditorNode::_global_menu_action(const Variant &p_id, const Variant &p_meta) {
+void EditorNode::_global_menu_scene(const Variant &p_tag) {
+ int idx = (int)p_tag;
+ scene_tabs->set_current_tab(idx);
+}
- int id = (int)p_id;
- if (id == GLOBAL_NEW_WINDOW) {
- if (OS::get_singleton()->get_main_loop()) {
- List<String> args;
- args.push_back("-e");
- String exec = OS::get_singleton()->get_executable_path();
+void EditorNode::_global_menu_new_window(const Variant &p_tag) {
+ if (OS::get_singleton()->get_main_loop()) {
+ List<String> args;
+ args.push_back("-p");
+ String exec = OS::get_singleton()->get_executable_path();
- OS::ProcessID pid = 0;
- OS::get_singleton()->execute(exec, args, false, &pid);
- }
- } else if (id == GLOBAL_SCENE) {
- int idx = (int)p_meta;
- scene_tabs->set_current_tab(idx);
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
}
}
@@ -5120,10 +5212,10 @@ void EditorNode::reload_scene(const String &p_path) {
//first of all, reload internal textures, materials, meshes, etc. as they might have changed on disk
- List<Ref<Resource> > cached;
+ List<Ref<Resource>> cached;
ResourceCache::get_cached_resources(&cached);
- List<Ref<Resource> > to_clear; //clear internal resources from previous scene from being used
- for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) {
+ List<Ref<Resource>> to_clear; //clear internal resources from previous scene from being used
+ for (List<Ref<Resource>>::Element *E = cached.front(); E; E = E->next()) {
if (E->get()->get_path().begins_with(p_path + "::")) { //subresources of existing scene
to_clear.push_back(E->get());
@@ -5254,9 +5346,9 @@ void EditorNode::remove_resource_conversion_plugin(const Ref<EditorResourceConve
resource_conversion_plugins.erase(p_plugin);
}
-Vector<Ref<EditorResourceConversionPlugin> > EditorNode::find_resource_conversion_plugin(const Ref<Resource> &p_for_resource) {
+Vector<Ref<EditorResourceConversionPlugin>> EditorNode::find_resource_conversion_plugin(const Ref<Resource> &p_for_resource) {
- Vector<Ref<EditorResourceConversionPlugin> > ret;
+ Vector<Ref<EditorResourceConversionPlugin>> ret;
for (int i = 0; i < resource_conversion_plugins.size(); i++) {
if (resource_conversion_plugins[i].is_valid() && resource_conversion_plugins[i]->handles(p_for_resource)) {
@@ -5276,9 +5368,9 @@ void EditorNode::_update_video_driver_color() {
// TODO: Probably should de-hardcode this and add to editor settings.
if (video_driver->get_text() == "GLES2") {
- video_driver->add_color_override("font_color", Color::hex(0x5586a4ff));
+ video_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
} else if (video_driver->get_text() == "Vulkan") {
- video_driver->add_color_override("font_color", theme_base->get_color("vulkan_color", "Editor"));
+ video_driver->add_theme_color_override("font_color", theme_base->get_theme_color("vulkan_color", "Editor"));
}
}
@@ -5286,14 +5378,14 @@ void EditorNode::_video_driver_selected(int p_which) {
String driver = video_driver->get_item_metadata(p_which);
- String current = OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver());
+ String current = ""; //OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver());
if (driver == current) {
return;
}
video_driver_request = driver;
- video_restart_dialog->popup_centered_minsize();
+ video_restart_dialog->popup_centered();
video_driver->select(video_driver_current);
_update_video_driver_color();
}
@@ -5375,6 +5467,7 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history);
+
ClassDB::bind_method("edit_item_resource", &EditorNode::edit_item_resource);
ClassDB::bind_method(D_METHOD("get_gui_base"), &EditorNode::get_gui_base);
@@ -5405,7 +5498,7 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err
static void _execute_thread(void *p_ud) {
EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud;
- Error err = OS::get_singleton()->execute(eta->path, eta->args, true, NULL, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
+ Error err = OS::get_singleton()->execute(eta->path, eta->args, true, nullptr, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
print_verbose("Thread exit status: " + itos(eta->exitcode));
if (err != OK) {
eta->exitcode = err;
@@ -5465,15 +5558,15 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
EditorNode::EditorNode() {
- Input::get_singleton()->set_use_accumulated_input(true);
+ InputFilter::get_singleton()->set_use_accumulated_input(true);
Resource::_get_local_scene_func = _resource_get_edited_scene;
- VisualServer::get_singleton()->set_debug_generate_wireframes(true);
+ RenderingServer::get_singleton()->set_debug_generate_wireframes(true);
- NavigationServer::get_singleton()->set_active(false); // no nav by default if editor
+ NavigationServer3D::get_singleton()->set_active(false); // no nav by default if editor
- PhysicsServer::get_singleton()->set_active(false); // no physics by default if editor
- Physics2DServer::get_singleton()->set_active(false); // no physics by default if editor
+ PhysicsServer3D::get_singleton()->set_active(false); // no physics by default if editor
+ PhysicsServer2D::get_singleton()->set_active(false); // no physics by default if editor
ScriptServer::set_scripting_enabled(false); // no scripting by default if editor
EditorHelp::generate_doc(); //before any editor classes are created
@@ -5481,15 +5574,22 @@ EditorNode::EditorNode() {
ResourceLoader::clear_translation_remaps(); //no remaps using during editor
ResourceLoader::clear_path_remaps();
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ InputFilter *id = InputFilter::get_singleton();
if (id) {
- if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
+ bool found_touchscreen = false;
+ for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
+ if (DisplayServer::get_singleton()->screen_is_touchscreen(i)) {
+ found_touchscreen = true;
+ }
+ }
+
+ if (!found_touchscreen && InputFilter::get_singleton()) {
//only if no touchscreen ui hint, set emulation
id->set_emulate_touch_from_mouse(false); //just disable just in case
}
- id->set_custom_mouse_cursor(RES());
+ DisplayServer::get_singleton()->cursor_set_custom_image(RES());
}
singleton = this;
@@ -5518,8 +5618,12 @@ EditorNode::EditorNode() {
switch (display_scale) {
case 0: {
// Try applying a suitable display scale automatically
- const int screen = OS::get_singleton()->get_current_screen();
- editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+ const int screen = DisplayServer::get_singleton()->window_get_current_screen();
+#ifdef OSX_ENABLED
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_scale(screen));
+#else
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000 ? 2.0 : 1.0);
+#endif
} break;
case 1: {
@@ -5553,7 +5657,7 @@ EditorNode::EditorNode() {
}
// Define a minimum window size to prevent UI elements from overlapping or being cut off
- OS::get_singleton()->set_min_window_size(Size2(1024, 600) * EDSCALE);
+ DisplayServer::get_singleton()->window_set_min_size(Size2(1024, 600) * EDSCALE);
ResourceLoader::set_abort_on_missing_resources(false);
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
@@ -5712,7 +5816,7 @@ EditorNode::EditorNode() {
theme_base->set_theme(theme);
gui_base->set_theme(theme);
- gui_base->add_style_override("panel", gui_base->get_stylebox("Background", "EditorStyles"));
+ gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox("Background", "EditorStyles"));
resource_preview = memnew(EditorResourcePreview);
add_child(resource_preview);
@@ -5727,7 +5831,7 @@ EditorNode::EditorNode() {
main_vbox = memnew(VBoxContainer);
gui_base->add_child(main_vbox);
main_vbox->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8);
- main_vbox->add_constant_override("separation", 8 * EDSCALE);
+ main_vbox->add_theme_constant_override("separation", 8 * EDSCALE);
menu_hb = memnew(HBoxContainer);
main_vbox->add_child(menu_hb);
@@ -5831,6 +5935,14 @@ EditorNode::EditorNode() {
dock_select->set_v_size_flags(Control::SIZE_EXPAND_FILL);
dock_vb->add_child(dock_select);
+ dock_float = memnew(Button);
+ dock_float->set_text(TTR("Make Floating"));
+ dock_float->set_focus_mode(Control::FOCUS_NONE);
+ dock_float->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
+ dock_float->connect("pressed", callable_mp(this, &EditorNode::_dock_make_float));
+
+ dock_vb->add_child(dock_float);
+
dock_select_popup->set_as_minsize();
dock_select_rect_over = -1;
dock_popup_selected = -1;
@@ -5860,7 +5972,7 @@ EditorNode::EditorNode() {
VBoxContainer *srt = memnew(VBoxContainer);
srt->set_v_size_flags(Control::SIZE_EXPAND_FILL);
top_split->add_child(srt);
- srt->add_constant_override("separation", 0);
+ srt->add_theme_constant_override("separation", 0);
tab_preview_panel = memnew(Panel);
tab_preview_panel->set_size(Size2(100, 100) * EDSCALE);
@@ -5875,8 +5987,8 @@ EditorNode::EditorNode() {
tab_preview_panel->add_child(tab_preview);
scene_tabs = memnew(Tabs);
- scene_tabs->add_style_override("tab_fg", gui_base->get_stylebox("SceneTabFG", "EditorStyles"));
- scene_tabs->add_style_override("tab_bg", gui_base->get_stylebox("SceneTabBG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_fg", gui_base->get_theme_stylebox("SceneTabFG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_bg", gui_base->get_theme_stylebox("SceneTabBG", "EditorStyles"));
scene_tabs->set_select_with_rmb(true);
scene_tabs->add_tab("unsaved");
scene_tabs->set_tab_align(Tabs::ALIGN_LEFT);
@@ -5898,7 +6010,6 @@ EditorNode::EditorNode() {
scene_tabs_context_menu = memnew(PopupMenu);
tabbar_container->add_child(scene_tabs_context_menu);
scene_tabs_context_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- scene_tabs_context_menu->set_hide_on_window_lose_focus(true);
srt->add_child(tabbar_container);
tabbar_container->add_child(scene_tabs);
@@ -5910,34 +6021,34 @@ EditorNode::EditorNode() {
#endif
distraction_free->set_tooltip(TTR("Toggle distraction-free mode."));
distraction_free->connect("pressed", callable_mp(this, &EditorNode::_toggle_distraction_free_mode));
- distraction_free->set_icon(gui_base->get_icon("DistractionFree", "EditorIcons"));
+ distraction_free->set_icon(gui_base->get_theme_icon("DistractionFree", "EditorIcons"));
distraction_free->set_toggle_mode(true);
scene_tab_add = memnew(ToolButton);
tabbar_container->add_child(scene_tab_add);
tabbar_container->add_child(distraction_free);
scene_tab_add->set_tooltip(TTR("Add a new scene."));
- scene_tab_add->set_icon(gui_base->get_icon("Add", "EditorIcons"));
- scene_tab_add->add_color_override("icon_color_normal", Color(0.6f, 0.6f, 0.6f, 0.8f));
+ scene_tab_add->set_icon(gui_base->get_theme_icon("Add", "EditorIcons"));
+ scene_tab_add->add_theme_color_override("icon_color_normal", Color(0.6f, 0.6f, 0.6f, 0.8f));
scene_tab_add->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(FILE_NEW_SCENE));
scene_root_parent = memnew(PanelContainer);
scene_root_parent->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
- scene_root_parent->add_style_override("panel", gui_base->get_stylebox("Content", "EditorStyles"));
+ scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox("Content", "EditorStyles"));
scene_root_parent->set_draw_behind_parent(true);
srt->add_child(scene_root_parent);
scene_root_parent->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- scene_root = memnew(Viewport);
+ scene_root = memnew(SubViewport);
//scene_root->set_usage(Viewport::USAGE_2D); canvas BG mode prevents usage of this as 2D
- VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true);
scene_root->set_disable_input(true);
scene_root->set_as_audio_listener_2d(true);
viewport = memnew(VBoxContainer);
viewport->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- viewport->add_constant_override("separation", 0);
+ viewport->add_theme_constant_override("separation", 0);
scene_root_parent->add_child(viewport);
HBoxContainer *left_menu_hb = memnew(HBoxContainer);
@@ -5947,11 +6058,11 @@ EditorNode::EditorNode() {
file_menu->set_flat(false);
file_menu->set_switch_on_hover(true);
file_menu->set_text(TTR("Scene"));
- file_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
+ file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
left_menu_hb->add_child(file_menu);
prev_scene = memnew(ToolButton);
- prev_scene->set_icon(gui_base->get_icon("PrevScene", "EditorIcons"));
+ prev_scene->set_icon(gui_base->get_theme_icon("PrevScene", "EditorIcons"));
prev_scene->set_tooltip(TTR("Go to previously opened scene."));
prev_scene->set_disabled(true);
prev_scene->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(FILE_OPEN_PREV));
@@ -6003,7 +6114,7 @@ EditorNode::EditorNode() {
file_menu->set_tooltip(TTR("Operations with scene files."));
p = file_menu->get_popup();
- p->set_hide_on_window_lose_focus(true);
+
p->add_shortcut(ED_SHORTCUT("editor/new_scene", TTR("New Scene")), FILE_NEW_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/new_inherited_scene", TTR("New Inherited Scene...")), FILE_NEW_INHERITED_SCENE);
p->add_shortcut(ED_SHORTCUT("editor/open_scene", TTR("Open Scene..."), KEY_MASK_CMD + KEY_O), FILE_OPEN_SCENE);
@@ -6051,11 +6162,11 @@ EditorNode::EditorNode() {
project_menu->set_switch_on_hover(true);
project_menu->set_tooltip(TTR("Miscellaneous project or scene-wide tools."));
project_menu->set_text(TTR("Project"));
- project_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
+ project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
left_menu_hb->add_child(project_menu);
p = project_menu->get_popup();
- p->set_hide_on_window_lose_focus(true);
+
p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings...")), RUN_SETTINGS);
p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
@@ -6101,19 +6212,20 @@ EditorNode::EditorNode() {
debug_menu->set_flat(false);
debug_menu->set_switch_on_hover(true);
debug_menu->set_text(TTR("Debug"));
- debug_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
+ debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
left_menu_hb->add_child(debug_menu);
+
menu_hb->add_spacer();
settings_menu = memnew(MenuButton);
settings_menu->set_flat(false);
settings_menu->set_switch_on_hover(true);
settings_menu->set_text(TTR("Editor"));
- settings_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
+ settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
left_menu_hb->add_child(settings_menu);
p = settings_menu->get_popup();
- p->set_hide_on_window_lose_focus(true);
+
p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings...")), SETTINGS_PREFERENCES);
p->add_separator();
@@ -6157,20 +6269,20 @@ EditorNode::EditorNode() {
help_menu->set_flat(false);
help_menu->set_switch_on_hover(true);
help_menu->set_text(TTR("Help"));
- help_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles"));
+ help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
left_menu_hb->add_child(help_menu);
p = help_menu->get_popup();
- p->set_hide_on_window_lose_focus(true);
p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_MASK_SHIFT | KEY_F1), HELP_SEARCH);
+ p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_MASK_SHIFT | KEY_F1), HELP_SEARCH);
p->add_separator();
- p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS);
- p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA);
- p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/issue_tracker", TTR("Issue Tracker")), HELP_ISSUES);
- p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY);
+ 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);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY);
p->add_separator();
- p->add_icon_shortcut(gui_base->get_icon("Godot", "EditorIcons"), ED_SHORTCUT("editor/about", TTR("About")), HELP_ABOUT);
+ p->add_icon_shortcut(gui_base->get_theme_icon("Godot", "EditorIcons"), ED_SHORTCUT("editor/about", TTR("About")), HELP_ABOUT);
HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb);
@@ -6178,7 +6290,7 @@ EditorNode::EditorNode() {
play_button = memnew(ToolButton);
play_hb->add_child(play_button);
play_button->set_toggle_mode(true);
- play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons"));
+ play_button->set_icon(gui_base->get_theme_icon("MainPlay", "EditorIcons"));
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_PLAY));
play_button->set_tooltip(TTR("Play the project."));
@@ -6190,7 +6302,7 @@ EditorNode::EditorNode() {
pause_button = memnew(ToolButton);
pause_button->set_toggle_mode(true);
- pause_button->set_icon(gui_base->get_icon("Pause", "EditorIcons"));
+ pause_button->set_icon(gui_base->get_theme_icon("Pause", "EditorIcons"));
pause_button->set_focus_mode(Control::FOCUS_NONE);
pause_button->set_tooltip(TTR("Pause the scene execution for debugging."));
pause_button->set_disabled(true);
@@ -6204,7 +6316,7 @@ EditorNode::EditorNode() {
stop_button = memnew(ToolButton);
play_hb->add_child(stop_button);
stop_button->set_focus_mode(Control::FOCUS_NONE);
- stop_button->set_icon(gui_base->get_icon("Stop", "EditorIcons"));
+ stop_button->set_icon(gui_base->get_theme_icon("Stop", "EditorIcons"));
stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_STOP));
stop_button->set_tooltip(TTR("Stop the scene."));
stop_button->set_disabled(true);
@@ -6222,7 +6334,7 @@ EditorNode::EditorNode() {
play_hb->add_child(play_scene_button);
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons"));
+ play_scene_button->set_icon(gui_base->get_theme_icon("PlayScene", "EditorIcons"));
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_PLAY_SCENE));
play_scene_button->set_tooltip(TTR("Play the edited scene."));
#ifdef OSX_ENABLED
@@ -6235,7 +6347,7 @@ EditorNode::EditorNode() {
play_hb->add_child(play_custom_scene_button);
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons"));
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon("PlayCustom", "EditorIcons"));
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_PLAY_CUSTOM_SCENE));
play_custom_scene_button->set_tooltip(TTR("Play custom scene"));
#ifdef OSX_ENABLED
@@ -6252,11 +6364,15 @@ EditorNode::EditorNode() {
video_driver->set_flat(true);
video_driver->set_focus_mode(Control::FOCUS_NONE);
video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected));
- video_driver->add_font_override("font", gui_base->get_font("bold", "EditorFonts"));
+ video_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
// TODO re-enable when GLES2 is ported
video_driver->set_disabled(true);
right_menu_hb->add_child(video_driver);
+#ifndef _MSC_VER
+#warning neeeds to be reimplemented
+#endif
+#if 0
String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/quality/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;
@@ -6272,7 +6388,7 @@ EditorNode::EditorNode() {
}
_update_video_driver_color();
-
+#endif
video_restart_dialog = memnew(ConfirmationDialog);
video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
video_restart_dialog->get_ok()->set_text(TTR("Save & Restart"));
@@ -6290,7 +6406,7 @@ EditorNode::EditorNode() {
update_spinner = memnew(MenuButton);
update_spinner->set_tooltip(TTR("Spins when the editor window redraws."));
right_menu_hb->add_child(update_spinner);
- update_spinner->set_icon(gui_base->get_icon("Progress1", "EditorIcons"));
+ update_spinner->set_icon(gui_base->get_theme_icon("Progress1", "EditorIcons"));
update_spinner->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
p = update_spinner->get_popup();
p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY);
@@ -6366,7 +6482,7 @@ EditorNode::EditorNode() {
// Bottom panels
bottom_panel = memnew(PanelContainer);
- bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer"));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("panel", "TabContainer"));
center_split->add_child(bottom_panel);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
@@ -6388,7 +6504,7 @@ EditorNode::EditorNode() {
bottom_panel_hb->add_child(version_label);
bottom_panel_raise = memnew(ToolButton);
- bottom_panel_raise->set_icon(gui_base->get_icon("ExpandBottomDock", "EditorIcons"));
+ bottom_panel_raise->set_icon(gui_base->get_theme_icon("ExpandBottomDock", "EditorIcons"));
bottom_panel_raise->set_shortcut(ED_SHORTCUT("editor/bottom_panel_expand", TTR("Expand Bottom Panel"), KEY_MASK_SHIFT | KEY_F12));
@@ -6413,7 +6529,7 @@ EditorNode::EditorNode() {
confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
save_confirmation = memnew(ConfirmationDialog);
- save_confirmation->add_button(TTR("Don't Save"), OS::get_singleton()->get_swap_ok_cancel(), "discard");
+ save_confirmation->add_button(TTR("Don't Save"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "discard");
gui_base->add_child(save_confirmation);
save_confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
save_confirmation->connect("custom_action", callable_mp(this, &EditorNode::_discard_changes));
@@ -6440,7 +6556,7 @@ EditorNode::EditorNode() {
file_templates->set_title(TTR("Import Templates From ZIP File"));
gui_base->add_child(file_templates);
- file_templates->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_templates->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_templates->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_templates->clear_filters();
file_templates->add_filter("*.tpz ; " + TTR("Template Package"));
@@ -6451,7 +6567,7 @@ EditorNode::EditorNode() {
file_export_lib = memnew(EditorFileDialog);
file_export_lib->set_title(TTR("Export Library"));
- file_export_lib->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_export_lib->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_export_lib->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
file_export_lib_merge = memnew(CheckBox);
file_export_lib_merge->set_text(TTR("Merge With Existing"));
@@ -6462,7 +6578,7 @@ EditorNode::EditorNode() {
file_script = memnew(EditorFileDialog);
file_script->set_title(TTR("Open & Run a Script"));
file_script->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- file_script->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_script->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
List<String> sexts;
ResourceLoader::get_recognized_extensions_for_type("Script", &sexts);
for (List<String>::Element *E = sexts.front(); E; E = E->next()) {
@@ -6472,7 +6588,7 @@ EditorNode::EditorNode() {
file_script->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
file_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- file_menu->connect("about_to_show", callable_mp(this, &EditorNode::_update_file_menu_opened));
+ file_menu->connect("about_to_popup", callable_mp(this, &EditorNode::_update_file_menu_opened));
file_menu->get_popup()->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed));
settings_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
@@ -6487,7 +6603,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(DebuggerEditorPlugin(this, debug_menu)));
add_editor_plugin(memnew(AnimationPlayerEditorPlugin(this)));
add_editor_plugin(memnew(CanvasItemEditorPlugin(this)));
- add_editor_plugin(memnew(SpatialEditorPlugin(this)));
+ add_editor_plugin(memnew(Node3DEditorPlugin(this)));
add_editor_plugin(memnew(ScriptEditorPlugin(this)));
EditorAudioBuses *audio_bus_editor = EditorAudioBuses::register_editor();
@@ -6513,18 +6629,19 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(ShaderEditorPlugin(this)));
add_editor_plugin(memnew(VisualShaderEditorPlugin(this)));
- add_editor_plugin(memnew(CameraEditorPlugin(this)));
+ add_editor_plugin(memnew(Camera3DEditorPlugin(this)));
add_editor_plugin(memnew(ThemeEditorPlugin(this)));
add_editor_plugin(memnew(MultiMeshEditorPlugin(this)));
- add_editor_plugin(memnew(MeshInstanceEditorPlugin(this)));
+ add_editor_plugin(memnew(MeshInstance3DEditorPlugin(this)));
add_editor_plugin(memnew(AnimationTreeEditorPlugin(this)));
add_editor_plugin(memnew(MeshLibraryEditorPlugin(this)));
add_editor_plugin(memnew(StyleBoxEditorPlugin(this)));
- add_editor_plugin(memnew(SpriteEditorPlugin(this)));
+ add_editor_plugin(memnew(Sprite2DEditorPlugin(this)));
add_editor_plugin(memnew(Skeleton2DEditorPlugin(this)));
- add_editor_plugin(memnew(ParticlesEditorPlugin(this)));
+ add_editor_plugin(memnew(GPUParticles2DEditorPlugin(this)));
+ add_editor_plugin(memnew(GPUParticles3DEditorPlugin(this)));
add_editor_plugin(memnew(CPUParticles2DEditorPlugin(this)));
- add_editor_plugin(memnew(CPUParticlesEditorPlugin(this)));
+ add_editor_plugin(memnew(CPUParticles3DEditorPlugin(this)));
add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this)));
add_editor_plugin(memnew(ItemListEditorPlugin(this)));
add_editor_plugin(memnew(Polygon3DEditorPlugin(this)));
@@ -6533,11 +6650,10 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(TileMapEditorPlugin(this)));
add_editor_plugin(memnew(SpriteFramesEditorPlugin(this)));
add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
- add_editor_plugin(memnew(Particles2DEditorPlugin(this)));
add_editor_plugin(memnew(GIProbeEditorPlugin(this)));
- // add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
+ //add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
add_editor_plugin(memnew(Path2DEditorPlugin(this)));
- add_editor_plugin(memnew(PathEditorPlugin(this)));
+ add_editor_plugin(memnew(Path3DEditorPlugin(this)));
add_editor_plugin(memnew(Line2DEditorPlugin(this)));
add_editor_plugin(memnew(Polygon2DEditorPlugin(this)));
add_editor_plugin(memnew(LightOccluder2DEditorPlugin(this)));
@@ -6548,9 +6664,9 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(TextureEditorPlugin(this)));
add_editor_plugin(memnew(AudioStreamEditorPlugin(this)));
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
- add_editor_plugin(memnew(SkeletonEditorPlugin(this)));
- add_editor_plugin(memnew(SkeletonIKEditorPlugin(this)));
- add_editor_plugin(memnew(PhysicalBonePlugin(this)));
+ add_editor_plugin(memnew(Skeleton3DEditorPlugin(this)));
+ add_editor_plugin(memnew(SkeletonIK3DEditorPlugin(this)));
+ add_editor_plugin(memnew(PhysicalBone3DEditorPlugin(this)));
add_editor_plugin(memnew(MeshEditorPlugin(this)));
add_editor_plugin(memnew(MaterialEditorPlugin(this)));
@@ -6583,6 +6699,18 @@ EditorNode::EditorNode() {
particles_mat_convert.instance();
resource_conversion_plugins.push_back(particles_mat_convert);
+ Ref<ProceduralSkyMaterialConversionPlugin> procedural_sky_mat_convert;
+ procedural_sky_mat_convert.instance();
+ resource_conversion_plugins.push_back(procedural_sky_mat_convert);
+
+ Ref<PanoramaSkyMaterialConversionPlugin> panorama_sky_mat_convert;
+ panorama_sky_mat_convert.instance();
+ resource_conversion_plugins.push_back(panorama_sky_mat_convert);
+
+ Ref<PhysicalSkyMaterialConversionPlugin> physical_sky_mat_convert;
+ physical_sky_mat_convert.instance();
+ resource_conversion_plugins.push_back(physical_sky_mat_convert);
+
Ref<VisualShaderConversionPlugin> vshader_convert;
vshader_convert.instance();
resource_conversion_plugins.push_back(vshader_convert);
@@ -6591,7 +6719,7 @@ EditorNode::EditorNode() {
update_spinner_step_frame = Engine::get_singleton()->get_frames_drawn();
update_spinner_step = 0;
- editor_plugin_screen = NULL;
+ editor_plugin_screen = nullptr;
editor_plugins_over = memnew(EditorPluginList);
editor_plugins_force_over = memnew(EditorPluginList);
editor_plugins_force_input_forwarding = memnew(EditorPluginList);
@@ -6602,7 +6730,7 @@ EditorNode::EditorNode() {
EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin);
_edit_current();
- current = NULL;
+ current = nullptr;
saving_resource = Ref<Resource>();
reference_resource_mem = true;
@@ -6612,14 +6740,14 @@ EditorNode::EditorNode() {
open_imported = memnew(ConfirmationDialog);
open_imported->get_ok()->set_text(TTR("Open Anyway"));
- new_inherited_button = open_imported->add_button(TTR("New Inherited"), !OS::get_singleton()->get_swap_ok_cancel(), "inherit");
+ new_inherited_button = open_imported->add_button(TTR("New Inherited"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "inherit");
open_imported->connect("confirmed", callable_mp(this, &EditorNode::_open_imported));
open_imported->connect("custom_action", callable_mp(this, &EditorNode::_inherit_imported));
gui_base->add_child(open_imported);
saved_version = 1;
unsaved_cache = true;
- _last_instanced_scene = NULL;
+ _last_instanced_scene = nullptr;
quick_open = memnew(EditorQuickOpen);
gui_base->add_child(quick_open);
@@ -6704,6 +6832,9 @@ EditorNode::EditorNode() {
screenshot_timer->connect("timeout", callable_mp(this, &EditorNode::_request_screenshot));
add_child(screenshot_timer);
screenshot_timer->set_owner(get_owner());
+
+ String exec = OS::get_singleton()->get_executable_path();
+ EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); // Save editor executable path for third-party tools
}
EditorNode::~EditorNode() {
@@ -6752,7 +6883,7 @@ bool EditorPluginList::forward_gui_input(const Ref<InputEvent> &p_event) {
return discard;
}
-bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
+bool EditorPluginList::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
bool discard = false;
for (int i = 0; i < plugins_list.size(); i++) {
diff --git a/editor/editor_node.h b/editor/editor_node.h
index e2badff88d..c6f04b0749 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -84,6 +84,8 @@ class Tabs;
class TextureProgress;
class ToolButton;
class VSplitContainer;
+class Window;
+class SubViewport;
class EditorNode : public Node {
@@ -192,7 +194,8 @@ private:
HELP_SEARCH,
HELP_DOCS,
HELP_QA,
- HELP_ISSUES,
+ HELP_REPORT_A_BUG,
+ HELP_SEND_DOCS_FEEDBACK,
HELP_COMMUNITY,
HELP_ABOUT,
@@ -206,7 +209,7 @@ private:
TOOL_MENU_BASE = 1000
};
- Viewport *scene_root; //root of the scene being edited
+ SubViewport *scene_root; //root of the scene being edited
PanelContainer *scene_root_parent;
Control *theme_base;
@@ -348,11 +351,14 @@ private:
Button *new_inherited_button;
String open_import_request;
+ Vector<Control *> floating_docks;
+
TabContainer *dock_slot[DOCK_SLOT_MAX];
Rect2 dock_select_rect[DOCK_SLOT_MAX];
int dock_select_rect_over;
PopupPanel *dock_select_popup;
Control *dock_select;
+ Button *dock_float;
ToolButton *dock_tab_move_left;
ToolButton *dock_tab_move_right;
int dock_popup_selected;
@@ -493,7 +499,8 @@ private:
void _add_to_recent_scenes(const String &p_scene);
void _update_recent_scenes();
void _open_recent_scene(int p_idx);
- void _global_menu_action(const Variant &p_id, const Variant &p_meta);
+ void _global_menu_scene(const Variant &p_tag);
+ void _global_menu_new_window(const Variant &p_tag);
void _dropped_files(const Vector<String> &p_files, int p_screen);
void _add_dropped_files_recursive(const Vector<String> &p_files, String to_path);
String _recent_scene;
@@ -513,7 +520,7 @@ private:
Set<FileDialog *> file_dialogs;
Set<EditorFileDialog *> editor_file_dialogs;
- Map<String, Ref<Texture2D> > icon_type_cache;
+ Map<String, Ref<Texture2D>> icon_type_cache;
void _build_icon_type_cache();
bool _initializing_addons;
@@ -536,7 +543,7 @@ private:
void _find_node_types(Node *p_node, int &count_2d, int &count_3d);
void _save_scene_with_preview(String p_file, int p_idx = -1);
- Map<String, Set<String> > dependency_errors;
+ Map<String, Set<String>> dependency_errors;
static void _dependency_error_report(void *ud, const String &p_path, const String &p_dep, const String &p_type) {
EditorNode *en = (EditorNode *)ud;
@@ -560,6 +567,8 @@ private:
bool _find_scene_in_use(Node *p_node, const String &p_path) const;
+ void _update_dock_containers();
+
void _dock_select_input(const Ref<InputEvent> &p_input);
void _dock_move_left();
void _dock_move_right();
@@ -567,6 +576,8 @@ private:
void _dock_pre_popup(int p_which);
void _dock_split_dragged(int ofs);
void _dock_popup_exit();
+ void _dock_floating_close_request(Control *p_control);
+ void _dock_make_float();
void _scene_tab_changed(int p_tab);
void _scene_tab_closed(int p_tab, int option = SCENE_TAB_CLOSE);
void _scene_tab_hover(int p_tab);
@@ -622,7 +633,7 @@ private:
void _update_update_spinner();
- Vector<Ref<EditorResourceConversionPlugin> > resource_conversion_plugins;
+ Vector<Ref<EditorResourceConversionPlugin>> resource_conversion_plugins;
PrintHandlerList print_handler;
static void _print_handler(void *p_this, const String &p_string, bool p_error);
@@ -724,7 +735,7 @@ public:
Node *get_edited_scene() { return editor_data.get_edited_scene_root(); }
- Viewport *get_scene_root() { return scene_root; } //root of the scene being edited
+ SubViewport *get_scene_root() { return scene_root; } //root of the scene being edited
void fix_dependencies(const String &p_for_file);
void clear_scene() { _cleanup_scene(); }
@@ -844,7 +855,7 @@ public:
void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
- Vector<Ref<EditorResourceConversionPlugin> > find_resource_conversion_plugin(const Ref<Resource> &p_for_resource);
+ Vector<Ref<EditorResourceConversionPlugin>> find_resource_conversion_plugin(const Ref<Resource> &p_for_resource);
static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); }
static void add_build_callback(EditorBuildCallback p_callback);
@@ -884,7 +895,7 @@ public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
void forward_canvas_draw_over_viewport(Control *p_overlay);
void forward_canvas_force_draw_over_viewport(Control *p_overlay);
- bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
+ bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
void forward_spatial_draw_over_viewport(Control *p_overlay);
void forward_spatial_force_draw_over_viewport(Control *p_overlay);
void add_plugin(EditorPlugin *p_plugin);
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index 305dc03568..804ad62bbb 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -149,6 +149,6 @@ EditorPath::EditorPath(EditorHistory *p_history) {
history = p_history;
set_clip_text(true);
set_text_align(ALIGN_LEFT);
- get_popup()->connect("about_to_show", callable_mp(this, &EditorPath::_about_to_show));
+ get_popup()->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show));
get_popup()->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed));
}
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 10ecdb19c0..746ebc8292 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -38,20 +38,20 @@
#include "editor_resource_preview.h"
#include "main/main.h"
#include "plugins/canvas_item_editor_plugin.h"
-#include "plugins/spatial_editor_plugin.h"
-#include "scene/3d/camera.h"
+#include "plugins/node_3d_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
#include "scene/gui/popup_menu.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) {
- Vector<Ref<Mesh> > meshes;
+ Vector<Ref<Mesh>> meshes;
for (int i = 0; i < p_meshes.size(); i++) {
meshes.push_back(p_meshes[i]);
}
- Vector<Ref<Texture2D> > textures = make_mesh_previews(meshes, NULL, p_preview_size);
+ Vector<Ref<Texture2D>> textures = make_mesh_previews(meshes, nullptr, p_preview_size);
Array ret;
for (int i = 0; i < textures.size(); i++) {
ret.push_back(textures[i]);
@@ -60,33 +60,33 @@ Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_
return ret;
}
-Vector<Ref<Texture2D> > EditorInterface::make_mesh_previews(const Vector<Ref<Mesh> > &p_meshes, Vector<Transform> *p_transforms, int p_preview_size) {
+Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform> *p_transforms, int p_preview_size) {
int size = p_preview_size;
- RID scenario = VS::get_singleton()->scenario_create();
+ RID scenario = RS::get_singleton()->scenario_create();
- RID viewport = VS::get_singleton()->viewport_create();
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ALWAYS);
- VS::get_singleton()->viewport_set_scenario(viewport, scenario);
- VS::get_singleton()->viewport_set_size(viewport, size, size);
- VS::get_singleton()->viewport_set_transparent_background(viewport, true);
- VS::get_singleton()->viewport_set_active(viewport, true);
- RID viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
+ RID viewport = RS::get_singleton()->viewport_create();
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ALWAYS);
+ RS::get_singleton()->viewport_set_scenario(viewport, scenario);
+ RS::get_singleton()->viewport_set_size(viewport, size, size);
+ RS::get_singleton()->viewport_set_transparent_background(viewport, true);
+ RS::get_singleton()->viewport_set_active(viewport, true);
+ RID viewport_texture = RS::get_singleton()->viewport_get_texture(viewport);
- RID camera = VS::get_singleton()->camera_create();
- VS::get_singleton()->viewport_attach_camera(viewport, camera);
+ RID camera = RS::get_singleton()->camera_create();
+ RS::get_singleton()->viewport_attach_camera(viewport, camera);
- RID light = VS::get_singleton()->directional_light_create();
- RID light_instance = VS::get_singleton()->instance_create2(light, scenario);
+ RID light = RS::get_singleton()->directional_light_create();
+ RID light_instance = RS::get_singleton()->instance_create2(light, scenario);
- RID light2 = VS::get_singleton()->directional_light_create();
- VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
- RID light_instance2 = VS::get_singleton()->instance_create2(light2, scenario);
+ RID light2 = RS::get_singleton()->directional_light_create();
+ RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
+ RID light_instance2 = RS::get_singleton()->instance_create2(light2, scenario);
EditorProgress ep("mlib", TTR("Creating Mesh Previews"), p_meshes.size());
- Vector<Ref<Texture2D> > textures;
+ Vector<Ref<Texture2D>> textures;
for (int i = 0; i < p_meshes.size(); i++) {
@@ -97,12 +97,12 @@ Vector<Ref<Texture2D> > EditorInterface::make_mesh_previews(const Vector<Ref<Mes
}
Transform mesh_xform;
- if (p_transforms != NULL) {
+ if (p_transforms != nullptr) {
mesh_xform = (*p_transforms)[i];
}
- RID inst = VS::get_singleton()->instance_create2(mesh->get_rid(), scenario);
- VS::get_singleton()->instance_set_transform(inst, mesh_xform);
+ RID inst = RS::get_singleton()->instance_create2(mesh->get_rid(), scenario);
+ RS::get_singleton()->instance_set_transform(inst, mesh_xform);
AABB aabb = mesh->get_aabb();
Vector3 ofs = aabb.position + aabb.size * 0.5;
@@ -121,32 +121,32 @@ Vector<Ref<Texture2D> > EditorInterface::make_mesh_previews(const Vector<Ref<Mes
xform.invert();
xform = mesh_xform * xform;
- VS::get_singleton()->camera_set_transform(camera, xform * Transform(Basis(), Vector3(0, 0, 3)));
- VS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01, 1000.0);
+ RS::get_singleton()->camera_set_transform(camera, xform * Transform(Basis(), Vector3(0, 0, 3)));
+ RS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01, 1000.0);
- VS::get_singleton()->instance_set_transform(light_instance, xform * Transform().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0)));
- VS::get_singleton()->instance_set_transform(light_instance2, xform * Transform().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0)));
+ RS::get_singleton()->instance_set_transform(light_instance, xform * Transform().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0)));
+ RS::get_singleton()->instance_set_transform(light_instance2, xform * Transform().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0)));
ep.step(TTR("Thumbnail..."), i);
Main::iteration();
Main::iteration();
- Ref<Image> img = VS::get_singleton()->texture_2d_get(viewport_texture);
+ Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
ERR_CONTINUE(!img.is_valid() || img->empty());
Ref<ImageTexture> it(memnew(ImageTexture));
it->create_from_image(img);
- VS::get_singleton()->free(inst);
+ RS::get_singleton()->free(inst);
textures.push_back(it);
}
- VS::get_singleton()->free(viewport);
- VS::get_singleton()->free(light);
- VS::get_singleton()->free(light_instance);
- VS::get_singleton()->free(light2);
- VS::get_singleton()->free(light_instance2);
- VS::get_singleton()->free(camera);
- VS::get_singleton()->free(scenario);
+ RS::get_singleton()->free(viewport);
+ RS::get_singleton()->free(light);
+ RS::get_singleton()->free(light_instance);
+ RS::get_singleton()->free(light2);
+ RS::get_singleton()->free(light_instance2);
+ RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(scenario);
return textures;
}
@@ -194,7 +194,7 @@ Array EditorInterface::get_open_scenes() const {
int scns_amount = scenes.size();
for (int idx_scn = 0; idx_scn < scns_amount; idx_scn++) {
- if (scenes[idx_scn].root == NULL)
+ if (scenes[idx_scn].root == nullptr)
continue;
ret.push_back(scenes[idx_scn].root->get_filename());
}
@@ -226,6 +226,10 @@ EditorFileSystem *EditorInterface::get_resource_file_system() {
return EditorFileSystem::get_singleton();
}
+FileSystemDock *EditorInterface::get_file_system_dock() {
+ return EditorNode::get_singleton()->get_filesystem_dock();
+}
+
EditorSelection *EditorInterface::get_selection() {
return EditorNode::get_singleton()->get_editor_selection();
}
@@ -274,7 +278,7 @@ void EditorInterface::set_distraction_free_mode(bool p_enter) {
EditorNode::get_singleton()->set_distraction_free_mode(p_enter);
}
-EditorInterface *EditorInterface::singleton = NULL;
+EditorInterface *EditorInterface::singleton = nullptr;
void EditorInterface::_bind_methods() {
@@ -295,6 +299,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file);
ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path);
ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path);
+ ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock);
ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled);
ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled);
@@ -332,7 +337,7 @@ void EditorPlugin::remove_autoload_singleton(const String &p_name) {
}
ToolButton *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const String &p_title) {
- ERR_FAIL_NULL_V(p_control, NULL);
+ ERR_FAIL_NULL_V(p_control, nullptr);
return EditorNode::get_singleton()->add_bottom_panel_item(p_title, p_control);
}
@@ -366,24 +371,24 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
case CONTAINER_SPATIAL_EDITOR_MENU: {
- SpatialEditor::get_singleton()->add_control_to_menu_panel(p_control);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(p_control);
} break;
case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT: {
- SpatialEditor::get_singleton()->get_palette_split()->add_child(p_control);
- SpatialEditor::get_singleton()->get_palette_split()->move_child(p_control, 0);
+ Node3DEditor::get_singleton()->get_palette_split()->add_child(p_control);
+ Node3DEditor::get_singleton()->get_palette_split()->move_child(p_control, 0);
} break;
case CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT: {
- SpatialEditor::get_singleton()->get_palette_split()->add_child(p_control);
- SpatialEditor::get_singleton()->get_palette_split()->move_child(p_control, 1);
+ Node3DEditor::get_singleton()->get_palette_split()->add_child(p_control);
+ Node3DEditor::get_singleton()->get_palette_split()->move_child(p_control, 1);
} break;
case CONTAINER_SPATIAL_EDITOR_BOTTOM: {
- SpatialEditor::get_singleton()->get_shader_split()->add_child(p_control);
+ Node3DEditor::get_singleton()->get_shader_split()->add_child(p_control);
} break;
case CONTAINER_CANVAS_EDITOR_MENU: {
@@ -440,18 +445,18 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
case CONTAINER_SPATIAL_EDITOR_MENU: {
- SpatialEditor::get_singleton()->remove_control_from_menu_panel(p_control);
+ Node3DEditor::get_singleton()->remove_control_from_menu_panel(p_control);
} break;
case CONTAINER_SPATIAL_EDITOR_SIDE_LEFT:
case CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT: {
- SpatialEditor::get_singleton()->get_palette_split()->remove_child(p_control);
+ Node3DEditor::get_singleton()->get_palette_split()->remove_child(p_control);
} break;
case CONTAINER_SPATIAL_EDITOR_BOTTOM: {
- SpatialEditor::get_singleton()->get_shader_split()->remove_child(p_control);
+ Node3DEditor::get_singleton()->get_shader_split()->remove_child(p_control);
} break;
case CONTAINER_CANVAS_EDITOR_MENU: {
@@ -557,10 +562,10 @@ void EditorPlugin::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
// Updates the overlays of the 2D viewport or, if in 3D mode, of every 3D viewport.
int EditorPlugin::update_overlays() const {
- if (SpatialEditor::get_singleton()->is_visible()) {
+ if (Node3DEditor::get_singleton()->is_visible()) {
int count = 0;
- for (uint32_t i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) {
- SpatialEditorViewport *vp = SpatialEditor::get_singleton()->get_editor_viewport(i);
+ for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {
+ Node3DEditorViewport *vp = Node3DEditor::get_singleton()->get_editor_viewport(i);
if (vp->is_visible()) {
vp->update_surface();
count++;
@@ -574,7 +579,7 @@ int EditorPlugin::update_overlays() const {
}
}
-bool EditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
+bool EditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (get_script_instance() && get_script_instance()->has_method("forward_spatial_gui_input")) {
return get_script_instance()->call("forward_spatial_gui_input", p_camera, p_event);
@@ -719,12 +724,12 @@ void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporte
EditorExport::get_singleton()->remove_export_plugin(p_exporter);
}
-void EditorPlugin::add_spatial_gizmo_plugin(const Ref<EditorSpatialGizmoPlugin> &p_gizmo_plugin) {
- SpatialEditor::get_singleton()->add_gizmo_plugin(p_gizmo_plugin);
+void EditorPlugin::add_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
+ Node3DEditor::get_singleton()->add_gizmo_plugin(p_gizmo_plugin);
}
-void EditorPlugin::remove_spatial_gizmo_plugin(const Ref<EditorSpatialGizmoPlugin> &p_gizmo_plugin) {
- SpatialEditor::get_singleton()->remove_gizmo_plugin(p_gizmo_plugin);
+void EditorPlugin::remove_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
+ Node3DEditor::get_singleton()->remove_gizmo_plugin(p_gizmo_plugin);
}
void EditorPlugin::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
@@ -860,7 +865,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
- ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "get_plugin_icon"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen"));
@@ -909,7 +914,7 @@ void EditorPlugin::_bind_methods() {
}
EditorPlugin::EditorPlugin() :
- undo_redo(NULL),
+ undo_redo(nullptr),
input_event_forwarding_always_enabled(false),
force_draw_over_forwarding_enabled(false),
last_main_screen_name("") {
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index dee63e4322..2ca96ceed2 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -42,17 +42,18 @@
#include "scene/resources/texture.h"
class EditorNode;
-class Spatial;
-class Camera;
+class Node3D;
+class Camera3D;
class EditorSelection;
class EditorExport;
class EditorSettings;
class EditorImportPlugin;
class EditorExportPlugin;
-class EditorSpatialGizmoPlugin;
+class EditorNode3DGizmoPlugin;
class EditorResourcePreview;
class EditorFileSystem;
class EditorToolAddons;
+class FileSystemDock;
class ScriptEditor;
class EditorInterface : public Node {
@@ -88,6 +89,8 @@ public:
EditorResourcePreview *get_resource_previewer();
EditorFileSystem *get_resource_file_system();
+ FileSystemDock *get_file_system_dock();
+
Control *get_base_control();
void set_plugin_enabled(const String &p_plugin, bool p_enabled);
@@ -98,7 +101,7 @@ public:
Error save_scene();
void save_scene_as(const String &p_scene, bool p_with_preview = true);
- Vector<Ref<Texture2D> > make_mesh_previews(const Vector<Ref<Mesh> > &p_meshes, Vector<Transform> *p_transforms, int p_preview_size);
+ Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform> *p_transforms, int p_preview_size);
void set_main_screen_editor(const String &p_name);
void set_distraction_free_mode(bool p_enter);
@@ -182,7 +185,7 @@ public:
virtual void forward_canvas_draw_over_viewport(Control *p_overlay);
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay);
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
+ virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
virtual void forward_spatial_draw_over_viewport(Control *p_overlay);
virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay);
@@ -224,8 +227,8 @@ public:
void add_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
void remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
- void add_spatial_gizmo_plugin(const Ref<EditorSpatialGizmoPlugin> &p_gizmo_plugin);
- void remove_spatial_gizmo_plugin(const Ref<EditorSpatialGizmoPlugin> &p_gizmo_plugin);
+ void add_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
+ void remove_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
@@ -265,7 +268,7 @@ class EditorPlugins {
public:
static int get_plugin_count() { return creation_func_count; }
static EditorPlugin *create(int p_idx, EditorNode *p_editor) {
- ERR_FAIL_INDEX_V(p_idx, creation_func_count, NULL);
+ ERR_FAIL_INDEX_V(p_idx, creation_func_count, nullptr);
return creation_funcs[p_idx](p_editor);
}
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index 76dbadf67e..62a76786ae 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -40,7 +40,7 @@
void EditorPluginSettings::_notification(int p_what) {
- if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) {
+ if (p_what == NOTIFICATION_WM_FOCUS_IN) {
update_plugins();
} else if (p_what == Node::NOTIFICATION_READY) {
plugin_config_dialog->connect_compat("plugin_ready", EditorNode::get_singleton(), "_on_plugin_ready");
@@ -137,19 +137,12 @@ void EditorPluginSettings::update_plugins() {
item->set_metadata(1, script);
item->set_text(2, author);
item->set_metadata(2, description);
- item->set_cell_mode(3, TreeItem::CELL_MODE_RANGE);
- item->set_range_config(3, 0, 1, 1);
- item->set_text(3, "Inactive,Active");
+ item->set_cell_mode(3, TreeItem::CELL_MODE_CHECK);
+ item->set_text(3, TTR("Enable"));
+ bool is_active = EditorNode::get_singleton()->is_addon_plugin_enabled(d2);
+ item->set_checked(3, is_active);
item->set_editable(3, true);
- item->add_button(4, get_icon("Edit", "EditorIcons"), BUTTON_PLUGIN_EDIT, false, TTR("Edit Plugin"));
-
- if (EditorNode::get_singleton()->is_addon_plugin_enabled(d2)) {
- item->set_custom_color(3, get_color("success_color", "Editor"));
- item->set_range(3, 1);
- } else {
- item->set_custom_color(3, get_color("disabled_font_color", "Editor"));
- item->set_range(3, 0);
- }
+ item->add_button(4, get_theme_icon("Edit", "EditorIcons"), BUTTON_PLUGIN_EDIT, false, TTR("Edit Plugin"));
}
}
}
@@ -164,7 +157,7 @@ void EditorPluginSettings::_plugin_activity_changed() {
TreeItem *ti = plugin_list->get_edited();
ERR_FAIL_COND(!ti);
- bool active = ti->get_range(3);
+ bool active = ti->is_checked(3);
String name = ti->get_metadata(0);
EditorNode::get_singleton()->set_addon_plugin_enabled(name, active, true);
@@ -173,14 +166,9 @@ void EditorPluginSettings::_plugin_activity_changed() {
if (is_active != active) {
updating = true;
- ti->set_range(3, is_active ? 1 : 0);
+ ti->set_checked(3, is_active);
updating = false;
}
-
- if (is_active)
- ti->set_custom_color(3, get_color("success_color", "Editor"));
- else
- ti->set_custom_color(3, get_color("disabled_font_color", "Editor"));
}
void EditorPluginSettings::_create_clicked() {
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 9ff34f8fb4..cf478f20e5 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -35,7 +35,7 @@
#include "editor_node.h"
#include "editor_properties_array_dict.h"
#include "editor_scale.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
///////////////////// NULL /////////////////////////
@@ -140,9 +140,9 @@ void EditorPropertyMultilineText::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
- Ref<Texture2D> df = get_icon("DistractionFree", "EditorIcons");
+ Ref<Texture2D> df = get_theme_icon("DistractionFree", "EditorIcons");
open_big_text->set_icon(df);
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
text->set_custom_minimum_size(Vector2(0, font->get_height() * 6));
} break;
@@ -165,8 +165,8 @@ EditorPropertyMultilineText::EditorPropertyMultilineText() {
open_big_text = memnew(ToolButton);
open_big_text->connect("pressed", callable_mp(this, &EditorPropertyMultilineText::_open_big_text));
hb->add_child(open_big_text);
- big_text_dialog = NULL;
- big_text = NULL;
+ big_text_dialog = nullptr;
+ big_text = nullptr;
}
///////////////////// TEXT ENUM /////////////////////////
@@ -240,10 +240,10 @@ void EditorPropertyPath::_path_pressed() {
}
if (folder) {
- dialog->set_mode(EditorFileDialog::MODE_OPEN_DIR);
+ dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
dialog->set_current_dir(full_path);
} else {
- dialog->set_mode(save_mode ? EditorFileDialog::MODE_SAVE_FILE : EditorFileDialog::MODE_OPEN_FILE);
+ dialog->set_file_mode(save_mode ? EditorFileDialog::FILE_MODE_SAVE_FILE : EditorFileDialog::FILE_MODE_OPEN_FILE);
for (int i = 0; i < extensions.size(); i++) {
String e = extensions[i].strip_edges();
if (e != String()) {
@@ -278,7 +278,7 @@ void EditorPropertyPath::set_save_mode() {
void EditorPropertyPath::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- path_edit->set_icon(get_icon("Folder", "EditorIcons"));
+ path_edit->set_icon(get_theme_icon("Folder", "EditorIcons"));
}
}
@@ -303,7 +303,7 @@ EditorPropertyPath::EditorPropertyPath() {
path_edit->set_clip_text(true);
path_hb->add_child(path_edit);
add_focusable(path);
- dialog = NULL;
+ dialog = nullptr;
path_edit->connect("pressed", callable_mp(this, &EditorPropertyPath::_path_pressed));
folder = false;
global = false;
@@ -448,7 +448,7 @@ void EditorPropertyMember::_bind_methods() {
}
EditorPropertyMember::EditorPropertyMember() {
- selector = NULL;
+ selector = nullptr;
property = memnew(Button);
property->set_clip_text(true);
add_child(property);
@@ -604,7 +604,7 @@ public:
Vector<String> tooltips;
virtual Size2 get_minimum_size() const {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
return Vector2(0, font->get_height() * 2);
}
@@ -646,7 +646,7 @@ public:
int h = bsize * 2 + 1;
int vofs = (rect.size.height - h) / 2;
- Color color = get_color("highlight_color", "Editor");
+ Color color = get_theme_color("highlight_color", "Editor");
for (int i = 0; i < 2; i++) {
Point2 ofs(4, vofs);
@@ -749,10 +749,10 @@ void EditorPropertyLayers::_button_pressed() {
layers->set_item_checked(idx, grid->value & (1 << i));
}
- Rect2 gp = button->get_global_rect();
+ Rect2 gp = button->get_screen_rect();
layers->set_as_minsize();
- Vector2 popup_pos = gp.position - Vector2(layers->get_combined_minimum_size().x, 0);
- layers->set_global_position(popup_pos);
+ Vector2 popup_pos = gp.position - Vector2(layers->get_contents_minimum_size().x, 0);
+ layers->set_position(popup_pos);
layers->popup();
}
@@ -920,7 +920,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
}
if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
- preset->set_global_position(easing_draw->get_global_transform().xform(mb->get_position()));
+ preset->set_position(easing_draw->get_screen_transform().xform(mb->get_position()));
preset->popup();
// Ensure the easing doesn't appear as being dragged
@@ -976,13 +976,13 @@ void EditorPropertyEasing::_draw_easing() {
float prev = 1.0;
const float exp = get_edited_object()->get(get_edited_property());
- const Ref<Font> f = get_font("font", "Label");
- const Color font_color = get_color("font_color", "Label");
+ const Ref<Font> f = get_theme_font("font", "Label");
+ const Color font_color = get_theme_color("font_color", "Label");
Color line_color;
if (dragging) {
- line_color = get_color("accent_color", "Editor");
+ line_color = get_theme_color("accent_color", "Editor");
} else {
- line_color = get_color("font_color", "Label") * Color(1, 1, 1, 0.9);
+ line_color = get_theme_color("font_color", "Label") * Color(1, 1, 1, 0.9);
}
Vector<Point2> lines;
@@ -1058,15 +1058,15 @@ void EditorPropertyEasing::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
preset->clear();
- preset->add_icon_item(get_icon("CurveConstant", "EditorIcons"), "Zero", EASING_ZERO);
- preset->add_icon_item(get_icon("CurveLinear", "EditorIcons"), "Linear", EASING_LINEAR);
- preset->add_icon_item(get_icon("CurveIn", "EditorIcons"), "In", EASING_IN);
- preset->add_icon_item(get_icon("CurveOut", "EditorIcons"), "Out", EASING_OUT);
+ preset->add_icon_item(get_theme_icon("CurveConstant", "EditorIcons"), "Zero", EASING_ZERO);
+ preset->add_icon_item(get_theme_icon("CurveLinear", "EditorIcons"), "Linear", EASING_LINEAR);
+ preset->add_icon_item(get_theme_icon("CurveIn", "EditorIcons"), "In", EASING_IN);
+ preset->add_icon_item(get_theme_icon("CurveOut", "EditorIcons"), "Out", EASING_OUT);
if (full) {
- preset->add_icon_item(get_icon("CurveInOut", "EditorIcons"), "In-Out", EASING_IN_OUT);
- preset->add_icon_item(get_icon("CurveOutIn", "EditorIcons"), "Out-In", EASING_OUT_IN);
+ preset->add_icon_item(get_theme_icon("CurveInOut", "EditorIcons"), "In-Out", EASING_IN_OUT);
+ preset->add_icon_item(get_theme_icon("CurveOutIn", "EditorIcons"), "Out-In", EASING_OUT_IN);
}
- easing_draw->set_custom_minimum_size(Size2(0, get_font("font", "Label")->get_height() * 2));
+ easing_draw->set_custom_minimum_size(Size2(0, get_theme_font("font", "Label")->get_height() * 2));
} break;
}
}
@@ -1126,7 +1126,7 @@ void EditorPropertyVector2::update_property() {
void EditorPropertyVector2::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 2; i++) {
Color c = base;
@@ -1208,7 +1208,7 @@ void EditorPropertyRect2::update_property() {
}
void EditorPropertyRect2::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 4; i++) {
Color c = base;
@@ -1288,7 +1288,7 @@ void EditorPropertyVector3::update_property() {
}
void EditorPropertyVector3::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 3; i++) {
Color c = base;
@@ -1368,7 +1368,7 @@ void EditorPropertyPlane::update_property() {
}
void EditorPropertyPlane::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 3; i++) {
Color c = base;
@@ -1450,7 +1450,7 @@ void EditorPropertyQuat::update_property() {
}
void EditorPropertyQuat::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 3; i++) {
Color c = base;
@@ -1537,7 +1537,7 @@ void EditorPropertyAABB::update_property() {
}
void EditorPropertyAABB::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 6; i++) {
Color c = base;
@@ -1611,7 +1611,7 @@ void EditorPropertyTransform2D::update_property() {
}
void EditorPropertyTransform2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 6; i++) {
Color c = base;
@@ -1690,7 +1690,7 @@ void EditorPropertyBasis::update_property() {
}
void EditorPropertyBasis::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 9; i++) {
Color c = base;
@@ -1775,7 +1775,7 @@ void EditorPropertyTransform::update_property() {
}
void EditorPropertyTransform::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_color("accent_color", "Editor");
+ Color base = get_theme_color("accent_color", "Editor");
for (int i = 0; i < 12; i++) {
Color c = base;
@@ -1882,7 +1882,7 @@ EditorPropertyColor::EditorPropertyColor() {
void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
NodePath path = p_path;
- Node *base_node = NULL;
+ Node *base_node = nullptr;
if (!use_path_from_scene_root) {
base_node = Object::cast_to<Node>(get_edited_object());
@@ -1945,7 +1945,7 @@ void EditorPropertyNodePath::update_property() {
}
assign->set_flat(true);
- Node *base_node = NULL;
+ Node *base_node = nullptr;
if (base_hint != NodePath()) {
if (get_tree()->get_root()->has_node(base_hint)) {
base_node = get_tree()->get_root()->get_node(base_hint);
@@ -1983,7 +1983,7 @@ void EditorPropertyNodePath::setup(const NodePath &p_base_hint, Vector<StringNam
void EditorPropertyNodePath::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Ref<Texture2D> t = get_icon("Clear", "EditorIcons");
+ Ref<Texture2D> t = get_theme_icon("Clear", "EditorIcons");
clear->set_icon(t);
}
}
@@ -2008,7 +2008,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() {
hbc->add_child(clear);
use_path_from_scene_root = false;
- scene_tree = NULL; //do not allocate unnecessarily
+ scene_tree = nullptr; //do not allocate unnecessarily
}
///////////////////// RID /////////////////////////
@@ -2074,7 +2074,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
file->connect("file_selected", callable_mp(this, &EditorPropertyResource::_file_selected));
add_child(file);
}
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
String type = base_type;
List<String> extensions;
@@ -2121,7 +2121,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
List<PropertyInfo> property_list;
res_orig->get_property_list(&property_list);
- List<Pair<String, Variant> > propvalues;
+ List<Pair<String, Variant>> propvalues;
for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
@@ -2144,7 +2144,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
ERR_FAIL_COND(res.is_null());
- for (List<Pair<String, Variant> >::Element *E = propvalues.front(); E; E = E->next()) {
+ for (List<Pair<String, Variant>>::Element *E = propvalues.front(); E; E = E->next()) {
Pair<String, Variant> &p = E->get();
res->set(p.first, p.second);
@@ -2196,7 +2196,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
file_system_dock->navigate_to_path(res->get_path());
// Ensure that the FileSystem dock is visible.
TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(file_system_dock->get_position_in_parent());
+ tab_container->set_current_tab(file_system_dock->get_index());
} break;
default: {
@@ -2206,7 +2206,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
int to_type = p_which - CONVERT_BASE_ID;
- Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res);
+ Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res);
ERR_FAIL_INDEX(to_type, conversions.size());
@@ -2248,7 +2248,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
return;
}
- Object *obj = NULL;
+ Object *obj = nullptr;
if (ScriptServer::is_global_class(intype)) {
obj = ClassDB::instance(ScriptServer::get_global_class_native_base(intype));
@@ -2294,7 +2294,7 @@ void EditorPropertyResource::_resource_preview(const String &p_path, const Ref<T
}
if (p_preview.is_valid()) {
- preview->set_margin(MARGIN_LEFT, assign->get_icon()->get_width() + assign->get_stylebox("normal")->get_default_margin(MARGIN_LEFT) + get_constant("hseparation", "Button"));
+ preview->set_margin(MARGIN_LEFT, assign->get_icon()->get_width() + assign->get_theme_stylebox("normal")->get_default_margin(MARGIN_LEFT) + get_theme_constant("hseparation", "Button"));
if (type == "GradientTexture") {
preview->set_stretch_mode(TextureRect::STRETCH_SCALE);
assign->set_custom_minimum_size(Size2(1, 1));
@@ -2318,8 +2318,8 @@ void EditorPropertyResource::_update_menu_items() {
menu->clear();
if (get_edited_property() == "script" && base_type == "Script" && Object::cast_to<Node>(get_edited_object())) {
- menu->add_icon_item(get_icon("ScriptCreate", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
- menu->add_icon_item(get_icon("ScriptExtend", "EditorIcons"), TTR("Extend Script"), OBJ_MENU_EXTEND_SCRIPT);
+ menu->add_icon_item(get_theme_icon("ScriptCreate", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
+ menu->add_icon_item(get_theme_icon("ScriptExtend", "EditorIcons"), TTR("Extend Script"), OBJ_MENU_EXTEND_SCRIPT);
menu->add_separator();
} else if (base_type != "") {
int idx = 0;
@@ -2381,7 +2381,7 @@ void EditorPropertyResource::_update_menu_items() {
inheritors_array.push_back(t);
if (!icon.is_valid())
- icon = get_icon(has_icon(t, "EditorIcons") ? t : "Object", "EditorIcons");
+ icon = get_theme_icon(has_theme_icon(t, "EditorIcons") ? t : "Object", "EditorIcons");
int id = TYPE_BASE_ID + idx;
menu->add_icon_item(icon, vformat(TTR("New %s"), t), id);
@@ -2394,14 +2394,14 @@ void EditorPropertyResource::_update_menu_items() {
menu->add_separator();
}
- menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD);
+ menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD);
if (!res.is_null()) {
- menu->add_icon_item(get_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT);
- menu->add_icon_item(get_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR);
- menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
- menu->add_icon_item(get_icon("Save", "EditorIcons"), TTR("Save"), OBJ_MENU_SAVE);
+ menu->add_icon_item(get_theme_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT);
+ menu->add_icon_item(get_theme_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR);
+ menu->add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
+ menu->add_icon_item(get_theme_icon("Save", "EditorIcons"), TTR("Save"), OBJ_MENU_SAVE);
RES r = res;
if (r.is_valid() && r->get_path().is_resource_file()) {
menu->add_separator();
@@ -2438,19 +2438,19 @@ void EditorPropertyResource::_update_menu_items() {
if (!res.is_null()) {
- Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res);
+ Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(res);
if (conversions.size()) {
menu->add_separator();
}
for (int i = 0; i < conversions.size(); i++) {
String what = conversions[i]->converts_to();
Ref<Texture2D> icon;
- if (has_icon(what, "EditorIcons")) {
+ if (has_theme_icon(what, "EditorIcons")) {
- icon = get_icon(what, "EditorIcons");
+ icon = get_theme_icon(what, "EditorIcons");
} else {
- icon = get_icon(what, "Resource");
+ icon = get_theme_icon(what, "Resource");
}
menu->add_icon_item(icon, vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i);
@@ -2462,11 +2462,11 @@ void EditorPropertyResource::_update_menu() {
_update_menu_items();
- Rect2 gt = edit->get_global_rect();
+ Rect2 gt = edit->get_screen_rect();
menu->set_as_minsize();
- int ms = menu->get_combined_minimum_size().width;
+ int ms = menu->get_contents_minimum_size().width;
Vector2 popup_pos = gt.position + gt.size - Vector2(ms, 0);
- menu->set_global_position(popup_pos);
+ menu->set_position(popup_pos);
menu->popup();
}
@@ -2490,10 +2490,10 @@ void EditorPropertyResource::_button_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
_update_menu_items();
- Vector2 pos = mb->get_global_position();
+ Vector2 pos = get_screen_position() + mb->get_position();
//pos = assign->get_global_transform().xform(pos);
menu->set_as_minsize();
- menu->set_global_position(pos);
+ menu->set_position(pos);
menu->popup();
}
}
@@ -2598,10 +2598,10 @@ void EditorPropertyResource::update_property() {
sub_inspector->refresh();
} else {
if (sub_inspector) {
- set_bottom_editor(NULL);
+ set_bottom_editor(nullptr);
memdelete(sub_inspector_vbox);
- sub_inspector = NULL;
- sub_inspector_vbox = NULL;
+ sub_inspector = nullptr;
+ sub_inspector_vbox = nullptr;
if (opened_editor) {
EditorNode::get_singleton()->hide_top_editors();
opened_editor = false;
@@ -2663,7 +2663,7 @@ 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) {
- Ref<Texture2D> t = get_icon("select_arrow", "Tree");
+ Ref<Texture2D> t = get_theme_icon("select_arrow", "Tree");
edit->set_icon(t);
}
@@ -2718,7 +2718,7 @@ void EditorPropertyResource::expand_all_folding() {
void EditorPropertyResource::_button_draw() {
if (dropping) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
assign->draw_rect(Rect2(Point2(), assign->get_size()), color, false);
}
}
@@ -2823,8 +2823,8 @@ void EditorPropertyResource::_bind_methods() {
EditorPropertyResource::EditorPropertyResource() {
opened_editor = false;
- sub_inspector = NULL;
- sub_inspector_vbox = NULL;
+ sub_inspector = nullptr;
+ sub_inspector_vbox = nullptr;
use_sub_inspector = bool(EDITOR_GET("interface/inspector/open_resources_in_current_inspector"));
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -2860,8 +2860,8 @@ EditorPropertyResource::EditorPropertyResource() {
edit->connect("gui_input", callable_mp(this, &EditorPropertyResource::_button_input));
add_focusable(edit);
- file = NULL;
- scene_tree = NULL;
+ file = nullptr;
+ scene_tree = nullptr;
dropping = false;
add_to_group("_editor_resource_properties");
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index c2a6aeb582..b4ce60171b 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -184,9 +184,9 @@ void EditorPropertyArray::_change_type(Object *p_button, int p_index) {
Button *button = Object::cast_to<Button>(p_button);
changing_type_idx = p_index;
- Rect2 rect = button->get_global_rect();
+ Rect2 rect = button->get_screen_rect();
change_type->set_as_minsize();
- change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0));
+ change_type->set_position(rect.position + rect.size - Vector2(change_type->get_contents_minimum_size().x, 0));
change_type->popup();
}
@@ -199,7 +199,7 @@ void EditorPropertyArray::_change_type_menu(int p_index) {
Variant value;
Callable::CallError ce;
- value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
+ value = Variant::construct(Variant::Type(p_index), nullptr, 0, ce);
Variant array = object->get_array();
array.set(changing_type_idx, value);
@@ -263,9 +263,9 @@ void EditorPropertyArray::update_property() {
edit->set_text(String("(Nil) ") + arrtype);
edit->set_pressed(false);
if (vbox) {
- set_bottom_editor(NULL);
+ set_bottom_editor(nullptr);
memdelete(vbox);
- vbox = NULL;
+ vbox = nullptr;
}
return;
}
@@ -340,7 +340,7 @@ void EditorPropertyArray::update_property() {
for (int i = 0; i < amount; i++) {
String prop_name = "indices/" + itos(i + offset);
- EditorProperty *prop = NULL;
+ EditorProperty *prop = nullptr;
Variant value = array.get(i + offset);
Variant::Type value_type = value.get_type();
@@ -353,7 +353,7 @@ void EditorPropertyArray::update_property() {
editor->setup("Object");
prop = editor;
} else {
- prop = EditorInspector::instantiate_property_editor(NULL, value_type, "", subtype_hint, subtype_hint_string, 0);
+ prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", subtype_hint, subtype_hint_string, 0);
}
prop->set_object_and_property(object.ptr(), prop_name);
@@ -373,13 +373,13 @@ void EditorPropertyArray::update_property() {
if (is_untyped_array) {
Button *edit = memnew(Button);
- edit->set_icon(get_icon("Edit", "EditorIcons"));
+ edit->set_icon(get_theme_icon("Edit", "EditorIcons"));
hb->add_child(edit);
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type), varray(edit, i + offset));
} else {
Button *remove = memnew(Button);
- remove->set_icon(get_icon("Remove", "EditorIcons"));
+ remove->set_icon(get_theme_icon("Remove", "EditorIcons"));
remove->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed), varray(i + offset));
hb->add_child(remove);
}
@@ -391,9 +391,9 @@ void EditorPropertyArray::update_property() {
} else {
if (vbox) {
- set_bottom_editor(NULL);
+ set_bottom_editor(nullptr);
memdelete(vbox);
- vbox = NULL;
+ vbox = nullptr;
}
}
}
@@ -419,7 +419,7 @@ void EditorPropertyArray::_edit_pressed() {
Variant array = get_edited_object()->get(get_edited_property());
if (!array.is_array()) {
Callable::CallError ce;
- array = Variant::construct(array_type, NULL, 0, ce);
+ array = Variant::construct(array_type, nullptr, 0, ce);
get_edited_object()->set(get_edited_property(), array);
}
@@ -450,7 +450,7 @@ void EditorPropertyArray::_length_changed(double p_page) {
for (int i = previous_size; i < size; i++) {
if (array.get(i).get_type() == Variant::NIL) {
Callable::CallError ce;
- array.set(i, Variant::construct(subtype, NULL, 0, ce));
+ array.set(i, Variant::construct(subtype, nullptr, 0, ce));
}
}
}
@@ -460,7 +460,7 @@ void EditorPropertyArray::_length_changed(double p_page) {
// Pool*Array don't initialize their elements, have to do it manually
for (int i = previous_size; i < size; i++) {
Callable::CallError ce;
- array.set(i, Variant::construct(array.get(i).get_type(), NULL, 0, ce));
+ array.set(i, Variant::construct(array.get(i).get_type(), nullptr, 0, ce));
}
}
@@ -505,9 +505,9 @@ EditorPropertyArray::EditorPropertyArray() {
edit->set_toggle_mode(true);
add_child(edit);
add_focusable(edit);
- vbox = NULL;
- page = NULL;
- length = NULL;
+ vbox = nullptr;
+ page = nullptr;
+ length = nullptr;
updating = false;
change_type = memnew(PopupMenu);
add_child(change_type);
@@ -553,9 +553,9 @@ void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) {
Button *button = Object::cast_to<Button>(p_button);
- Rect2 rect = button->get_global_rect();
+ Rect2 rect = button->get_screen_rect();
change_type->set_as_minsize();
- change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0));
+ change_type->set_position(rect.position + rect.size - Vector2(change_type->get_contents_minimum_size().x, 0));
change_type->popup();
changing_type_idx = p_index;
}
@@ -585,7 +585,7 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) {
if (changing_type_idx < 0) {
Variant value;
Callable::CallError ce;
- value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
+ value = Variant::construct(Variant::Type(p_index), nullptr, 0, ce);
if (changing_type_idx == -1) {
object->set_new_item_key(value);
} else {
@@ -601,7 +601,7 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) {
Variant value;
Callable::CallError ce;
- value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
+ value = Variant::construct(Variant::Type(p_index), nullptr, 0, ce);
Variant key = dict.get_key_at_index(changing_type_idx);
dict[key] = value;
} else {
@@ -624,9 +624,9 @@ void EditorPropertyDictionary::update_property() {
edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property.
edit->set_pressed(false);
if (vbox) {
- set_bottom_editor(NULL);
+ set_bottom_editor(nullptr);
memdelete(vbox);
- vbox = NULL;
+ vbox = nullptr;
}
return;
}
@@ -683,7 +683,7 @@ void EditorPropertyDictionary::update_property() {
dict = dict.duplicate();
object->set_dict(dict);
- VBoxContainer *add_vbox = NULL;
+ VBoxContainer *add_vbox = nullptr;
for (int i = 0; i < amount + 2; i++) {
String prop_name;
@@ -702,7 +702,7 @@ void EditorPropertyDictionary::update_property() {
value = object->get_new_item_value();
}
- EditorProperty *prop = NULL;
+ EditorProperty *prop = nullptr;
switch (value.get_type()) {
case Variant::NIL: {
@@ -909,9 +909,9 @@ void EditorPropertyDictionary::update_property() {
for (int j = 0; j < 4; j++) {
flat->set_default_margin(Margin(j), 2 * EDSCALE);
}
- flat->set_bg_color(get_color("prop_subsection", "Editor"));
+ flat->set_bg_color(get_theme_color("prop_subsection", "Editor"));
- pc->add_style_override("panel", flat);
+ pc->add_theme_style_override("panel", flat);
add_vbox = memnew(VBoxContainer);
pc->add_child(add_vbox);
}
@@ -944,7 +944,7 @@ void EditorPropertyDictionary::update_property() {
hb->add_child(prop);
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *edit = memnew(Button);
- edit->set_icon(get_icon("Edit", "EditorIcons"));
+ edit->set_icon(get_theme_icon("Edit", "EditorIcons"));
hb->add_child(edit);
edit->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type), varray(edit, change_index));
@@ -962,9 +962,9 @@ void EditorPropertyDictionary::update_property() {
} else {
if (vbox) {
- set_bottom_editor(NULL);
+ set_bottom_editor(nullptr);
memdelete(vbox);
- vbox = NULL;
+ vbox = nullptr;
}
}
}
@@ -981,7 +981,7 @@ void EditorPropertyDictionary::_edit_pressed() {
Variant prop_val = get_edited_object()->get(get_edited_property());
if (prop_val.get_type() == Variant::NIL) {
Callable::CallError ce;
- prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce);
+ prop_val = Variant::construct(Variant::DICTIONARY, nullptr, 0, ce);
get_edited_object()->set(get_edited_property(), prop_val);
}
@@ -1012,8 +1012,8 @@ EditorPropertyDictionary::EditorPropertyDictionary() {
edit->set_toggle_mode(true);
add_child(edit);
add_focusable(edit);
- vbox = NULL;
- page = NULL;
+ vbox = nullptr;
+ page = nullptr;
updating = false;
change_type = memnew(PopupMenu);
add_child(change_type);
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 3c401a6fc7..2a4300f833 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -99,7 +99,7 @@ void EditorResourcePreviewGenerator::_bind_methods() {
EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
}
-EditorResourcePreview *EditorResourcePreview::singleton = NULL;
+EditorResourcePreview *EditorResourcePreview::singleton = nullptr;
void EditorResourcePreview::_thread_func(void *ud) {
@@ -109,9 +109,10 @@ void EditorResourcePreview::_thread_func(void *ud) {
void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
- MutexLock lock(preview_mutex);
String path = p_str;
{
+ MutexLock lock(preview_mutex);
+
uint32_t hash = 0;
uint64_t modified_time = 0;
@@ -167,7 +168,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
r_texture = generated;
- int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size
+ int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_theme_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size
small_thumbnail_size *= EDSCALE;
if (preview_generators[i]->can_generate_small_preview()) {
@@ -364,7 +365,6 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
cache[path_id].order = order++;
p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
- preview_mutex.unlock();
return;
}
@@ -391,7 +391,6 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
if (cache.has(p_path)) {
cache[p_path].order = order++;
p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
- preview_mutex.unlock();
return;
}
@@ -436,9 +435,10 @@ void EditorResourcePreview::_bind_methods() {
void EditorResourcePreview::check_for_invalidation(const String &p_path) {
- MutexLock lock(preview_mutex);
bool call_invalidated = false;
{
+ MutexLock lock(preview_mutex);
+
if (cache.has(p_path)) {
uint64_t modified_time = FileAccess::get_modified_time(p_path);
@@ -465,16 +465,16 @@ void EditorResourcePreview::stop() {
preview_sem.post();
while (!exited) {
OS::get_singleton()->delay_usec(10000);
- VisualServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
+ RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server
}
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
}
EditorResourcePreview::EditorResourcePreview() {
- thread = NULL;
+ thread = nullptr;
singleton = this;
order = 0;
exit = false;
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index 0e1684963c..dc5a3b9c93 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -94,7 +94,7 @@ class EditorResourcePreview : public Node {
static void _thread_func(void *ud);
void _thread();
- Vector<Ref<EditorResourcePreviewGenerator> > preview_generators;
+ Vector<Ref<EditorResourcePreviewGenerator>> preview_generators;
protected:
static void _bind_methods();
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 9f0e1f2349..b4ddb7ebfa 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -32,6 +32,7 @@
#include "core/project_settings.h"
#include "editor_settings.h"
+#include "servers/display_server.h"
EditorRun::Status EditorRun::get_status() const {
@@ -70,19 +71,19 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
int screen = EditorSettings::get_singleton()->get("run/window_placement/screen");
if (screen == 0) {
// Same as editor
- screen = OS::get_singleton()->get_current_screen();
+ screen = DisplayServer::get_singleton()->window_get_current_screen();
} else if (screen == 1) {
// Previous monitor (wrap to the other end if needed)
screen = Math::wrapi(
- OS::get_singleton()->get_current_screen() - 1,
+ DisplayServer::get_singleton()->window_get_current_screen() - 1,
0,
- OS::get_singleton()->get_screen_count());
+ DisplayServer::get_singleton()->get_screen_count());
} else if (screen == 2) {
// Next monitor (wrap to the other end if needed)
screen = Math::wrapi(
- OS::get_singleton()->get_current_screen() + 1,
+ DisplayServer::get_singleton()->window_get_current_screen() + 1,
0,
- OS::get_singleton()->get_screen_count());
+ DisplayServer::get_singleton()->get_screen_count());
} else {
// Fixed monitor ID
// There are 3 special options, so decrement the option ID by 3 to get the monitor ID
@@ -94,8 +95,8 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
}
Rect2 screen_rect;
- screen_rect.position = OS::get_singleton()->get_screen_position(screen);
- screen_rect.size = OS::get_singleton()->get_screen_size(screen);
+ screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen);
+ screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen);
Size2 desired_size;
desired_size.x = ProjectSettings::get_singleton()->get("display/window/size/width");
@@ -120,7 +121,9 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
case 1: { // centered
int display_scale = 1;
#ifdef OSX_ENABLED
- if (OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000) {
+ display_scale = DisplayServer::get_singleton()->screen_get_scale(screen);
+#else
+ if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000) {
display_scale = 2;
}
#endif
diff --git a/editor/editor_run_script.cpp b/editor/editor_run_script.cpp
index 628055cac6..c03fd4f6f5 100644
--- a/editor/editor_run_script.cpp
+++ b/editor/editor_run_script.cpp
@@ -56,7 +56,7 @@ Node *EditorScript::get_scene() {
if (!editor) {
EditorNode::add_io_error("EditorScript::get_scene: " + TTR("Write your logic in the _run() method."));
- return NULL;
+ return nullptr;
}
return editor->get_edited_scene();
@@ -73,7 +73,7 @@ void EditorScript::_run() {
Callable::CallError ce;
ce.error = Callable::CallError::CALL_OK;
- get_script_instance()->call("_run", NULL, 0, ce);
+ get_script_instance()->call("_run", nullptr, 0, ce);
if (ce.error != Callable::CallError::CALL_OK) {
EditorNode::add_io_error(TTR("Couldn't run script:") + "\n " + s->get_path() + "\n" + TTR("Did you forget the '_run' method?"));
@@ -95,5 +95,5 @@ void EditorScript::_bind_methods() {
EditorScript::EditorScript() {
- editor = NULL;
+ editor = nullptr;
}
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index fe28efedeb..bccc38ca1b 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -127,7 +127,7 @@ public:
}
SectionedInspectorFilter() {
- edited = NULL;
+ edited = nullptr;
}
};
@@ -142,7 +142,7 @@ void SectionedInspector::_section_selected() {
return;
selected_category = sections->get_selected()->get_metadata(0);
- filter->set_section(selected_category, sections->get_selected()->get_children() == NULL);
+ filter->set_section(selected_category, sections->get_selected()->get_children() == nullptr);
inspector->set_property_prefix(selected_category + "/");
}
@@ -177,8 +177,8 @@ void SectionedInspector::edit(Object *p_object) {
obj = ObjectID();
sections->clear();
- filter->set_edited(NULL);
- inspector->edit(NULL);
+ filter->set_edited(nullptr);
+ inspector->edit(nullptr);
return;
}
@@ -257,7 +257,7 @@ void SectionedInspector::update_category_list() {
for (int i = 0; i < sc; i++) {
TreeItem *parent = section_map[metasection];
- parent->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
+ parent->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
if (i > 0) {
metasection += "/" + sectionarr[i];
@@ -308,8 +308,8 @@ SectionedInspector::SectionedInspector() :
sections(memnew(Tree)),
filter(memnew(SectionedInspectorFilter)),
inspector(memnew(EditorInspector)),
- search_box(NULL) {
- add_constant_override("autohide", 1); // Fixes the dragger always showing up
+ search_box(nullptr) {
+ add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up
VBoxContainer *left_vb = memnew(VBoxContainer);
left_vb->set_custom_minimum_size(Size2(190, 0) * EDSCALE);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index ae16a50279..5d5bb1242d 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -44,15 +44,16 @@
#include "core/os/os.h"
#include "core/project_settings.h"
#include "core/version.h"
+#include "editor/doc_translations.gen.h"
#include "editor/editor_node.h"
-#include "editor/translations.gen.h"
+#include "editor/editor_translations.gen.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
// PRIVATE METHODS
-Ref<EditorSettings> EditorSettings::singleton = NULL;
+Ref<EditorSettings> EditorSettings::singleton = nullptr;
// Properties
@@ -125,7 +126,7 @@ bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name.operator String() == "shortcuts") {
Array arr;
- for (const Map<String, Ref<ShortCut> >::Element *E = shortcuts.front(); E; E = E->next()) {
+ for (const Map<String, Ref<ShortCut>>::Element *E = shortcuts.front(); E; E = E->next()) {
Ref<ShortCut> sc = E->get();
@@ -176,7 +177,7 @@ void EditorSettings::_get_property_list(List<PropertyInfo> *p_list) const {
_THREAD_SAFE_METHOD_
- const String *k = NULL;
+ const String *k = nullptr;
Set<_EVCSort> vclist;
while ((k = props.next(k))) {
@@ -340,6 +341,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/separate_distraction_mode", false);
_initial_set("interface/editor/automatically_open_screenshots", true);
+ _initial_set("interface/editor/single_window_mode", false);
+ hints["interface/editor/single_window_mode"] = PropertyInfo(Variant::BOOL, "interface/editor/single_window_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/hide_console_window", false);
_initial_set("interface/editor/save_each_scene_on_quit", true); // Regression
_initial_set("interface/editor/quit_confirmation", true);
@@ -598,7 +601,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("run/window_placement/rect", 1);
hints["run/window_placement/rect"] = PropertyInfo(Variant::INT, "run/window_placement/rect", PROPERTY_HINT_ENUM, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen");
String screen_hints = "Same as Editor,Previous Monitor,Next Monitor";
- for (int i = 0; i < OS::get_singleton()->get_screen_count(); i++) {
+ for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
screen_hints += ",Monitor " + itos(i + 1);
}
_initial_set("run/window_placement/rect_custom_position", Vector2());
@@ -777,7 +780,7 @@ void EditorSettings::create() {
if (singleton.ptr())
return; //pointless
- DirAccess *dir = NULL;
+ DirAccess *dir = nullptr;
String data_path;
String data_dir;
@@ -982,14 +985,12 @@ void EditorSettings::setup_language() {
String lang = get("interface/editor/editor_language");
if (lang == "en")
- return; //none to do
+ return; // Default, nothing to do.
+ // Load editor translation for configured/detected locale.
EditorTranslationList *etl = _editor_translations;
-
while (etl->data) {
-
if (etl->lang == lang) {
-
Vector<uint8_t> data;
data.resize(etl->uncomp_size);
Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
@@ -997,7 +998,7 @@ void EditorSettings::setup_language() {
FileAccessMemory *fa = memnew(FileAccessMemory);
fa->open_custom(data.ptr(), data.size());
- Ref<Translation> tr = TranslationLoaderPO::load_translation(fa, NULL, "translation_" + String(etl->lang));
+ Ref<Translation> tr = TranslationLoaderPO::load_translation(fa);
if (tr.is_valid()) {
tr->set_locale(etl->lang);
@@ -1008,6 +1009,29 @@ void EditorSettings::setup_language() {
etl++;
}
+
+ // Load class reference translation.
+ DocTranslationList *dtl = _doc_translations;
+ while (dtl->data) {
+ if (dtl->lang == lang) {
+ Vector<uint8_t> data;
+ data.resize(dtl->uncomp_size);
+ Compression::decompress(data.ptrw(), dtl->uncomp_size, dtl->data, dtl->comp_size, Compression::MODE_DEFLATE);
+
+ FileAccessMemory *fa = memnew(FileAccessMemory);
+ fa->open_custom(data.ptr(), data.size());
+
+ Ref<Translation> tr = TranslationLoaderPO::load_translation(fa);
+
+ if (tr.is_valid()) {
+ tr->set_locale(dtl->lang);
+ TranslationServer::get_singleton()->set_doc_translation(tr);
+ break;
+ }
+ }
+
+ dtl++;
+ }
}
void EditorSettings::setup_network() {
@@ -1476,7 +1500,7 @@ void EditorSettings::add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcu
bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const {
- const Map<String, Ref<ShortCut> >::Element *E = shortcuts.find(p_name);
+ const Map<String, Ref<ShortCut>>::Element *E = shortcuts.find(p_name);
ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_name + ".");
return E->get()->is_shortcut(p_event);
@@ -1484,7 +1508,7 @@ 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);
+ const Map<String, Ref<ShortCut>>::Element *E = shortcuts.find(p_name);
if (!E)
return Ref<ShortCut>();
@@ -1493,7 +1517,7 @@ Ref<ShortCut> EditorSettings::get_shortcut(const String &p_name) const {
void EditorSettings::get_shortcut_list(List<String> *r_shortcuts) {
- for (const Map<String, Ref<ShortCut> >::Element *E = shortcuts.front(); E; E = E->next()) {
+ for (const Map<String, Ref<ShortCut>>::Element *E = shortcuts.front(); E; E = E->next()) {
r_shortcuts->push_back(E->key());
}
@@ -1502,7 +1526,7 @@ void EditorSettings::get_shortcut_list(List<String> *r_shortcuts) {
Ref<ShortCut> ED_GET_SHORTCUT(const String &p_path) {
if (!EditorSettings::get_singleton()) {
- return NULL;
+ return nullptr;
}
Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index d4dd19ee10..29b89ef1a8 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -95,7 +95,7 @@ private:
int last_order;
Ref<Resource> clipboard;
- Map<String, Ref<ShortCut> > shortcuts;
+ Map<String, Ref<ShortCut>> shortcuts;
String resource_path;
String settings_dir;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 0ede0a3b7a..4eefe844d2 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -29,8 +29,9 @@
/*************************************************************************/
#include "editor_spin_slider.h"
+
+#include "core/input/input_filter.h"
#include "core/math/expression.h"
-#include "core/os/input.h"
#include "editor_node.h"
#include "editor_scale.h"
@@ -67,7 +68,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
grabbing_spinner_dist_cache = 0;
pre_grab_value = get_value();
grabbing_spinner = false;
- grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position();
+ grabbing_spinner_mouse_pos = InputFilter::get_singleton()->get_mouse_position();
}
} else {
@@ -75,8 +76,8 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
if (grabbing_spinner) {
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
- Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE);
+ InputFilter::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos);
update();
} else {
_focus_entered();
@@ -105,7 +106,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
grabbing_spinner_dist_cache += diff_x;
if (!grabbing_spinner && ABS(grabbing_spinner_dist_cache) > 4 * EDSCALE) {
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_CAPTURED);
grabbing_spinner = true;
}
@@ -176,11 +177,11 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
void EditorSpinSlider::_notification(int p_what) {
- if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT ||
- p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN ||
+ if (p_what == NOTIFICATION_WM_FOCUS_OUT ||
+ p_what == NOTIFICATION_WM_FOCUS_IN ||
p_what == NOTIFICATION_EXIT_TREE) {
if (grabbing_spinner) {
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE);
grabbing_spinner = false;
grabbing_spinner_attempt = false;
}
@@ -191,30 +192,30 @@ void EditorSpinSlider::_notification(int p_what) {
// when it's edited. The LineEdit "focus" stylebox uses the "normal" stylebox's
// default margins.
Ref<StyleBoxFlat> stylebox =
- EditorNode::get_singleton()->get_theme_base()->get_stylebox("normal", "LineEdit")->duplicate();
+ EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox("normal", "LineEdit")->duplicate();
// EditorSpinSliders with a label have more space on the left, so add an
// higher margin to match the location where the text begins.
// The margin values below were determined by empirical testing.
stylebox->set_default_margin(MARGIN_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE);
- value_input->add_style_override("normal", stylebox);
+ value_input->add_theme_style_override("normal", stylebox);
}
if (p_what == NOTIFICATION_DRAW) {
updown_offset = -1;
- Ref<StyleBox> sb = get_stylebox("normal", "LineEdit");
+ Ref<StyleBox> sb = get_theme_stylebox("normal", "LineEdit");
if (!flat) {
draw_style_box(sb, Rect2(Vector2(), get_size()));
}
- Ref<Font> font = get_font("font", "LineEdit");
+ Ref<Font> font = get_theme_font("font", "LineEdit");
int sep_base = 4 * EDSCALE;
int sep = sep_base + sb->get_offset().x; //make it have the same margin on both sides, looks better
int string_width = font->get_string_size(label).width;
int number_width = get_size().width - sb->get_minimum_size().width - string_width - sep;
- Ref<Texture2D> updown = get_icon("updown", "SpinBox");
+ Ref<Texture2D> updown = get_theme_icon("updown", "SpinBox");
if (get_step() == 1) {
number_width -= updown->get_width();
@@ -224,7 +225,7 @@ void EditorSpinSlider::_notification(int p_what) {
int vofs = (get_size().height - font->get_height()) / 2 + font->get_ascent();
- Color fc = get_color("font_color", "LineEdit");
+ Color fc = get_theme_color("font_color", "LineEdit");
Color lc;
if (use_custom_label_color) {
lc = custom_label_color;
@@ -233,12 +234,12 @@ void EditorSpinSlider::_notification(int p_what) {
}
if (flat && label != String()) {
- Color label_bg_color = get_color("dark_color_3", "Editor");
+ Color label_bg_color = get_theme_color("dark_color_3", "Editor");
draw_rect(Rect2(Vector2(), Vector2(sb->get_offset().x * 2 + string_width, get_size().height)), label_bg_color);
}
if (has_focus()) {
- Ref<StyleBox> focus = get_stylebox("focus", "LineEdit");
+ Ref<StyleBox> focus = get_theme_stylebox("focus", "LineEdit");
draw_style_box(focus, Rect2(Vector2(), get_size()));
}
@@ -247,7 +248,7 @@ void EditorSpinSlider::_notification(int p_what) {
draw_string(font, Vector2(Math::round(sb->get_offset().x + string_width + sep), vofs), numstr, fc, number_width);
if (get_step() == 1) {
- Ref<Texture2D> updown2 = get_icon("updown", "SpinBox");
+ Ref<Texture2D> updown2 = get_theme_icon("updown", "SpinBox");
int updown_vofs = (get_size().height - updown2->get_height()) / 2;
updown_offset = get_size().width - sb->get_margin(MARGIN_RIGHT) - updown2->get_width();
Color c(1, 1, 1);
@@ -272,7 +273,7 @@ void EditorSpinSlider::_notification(int p_what) {
Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
draw_rect(grabber_rect, c);
- bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input->is_visible();
+ bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input_popup->is_visible();
if (grabber->is_visible() != display_grabber) {
if (display_grabber) {
grabber->show();
@@ -284,9 +285,9 @@ void EditorSpinSlider::_notification(int p_what) {
if (display_grabber) {
Ref<Texture2D> grabber_tex;
if (mouse_over_grabber) {
- grabber_tex = get_icon("grabber_highlight", "HSlider");
+ grabber_tex = get_theme_icon("grabber_highlight", "HSlider");
} else {
- grabber_tex = get_icon("grabber", "HSlider");
+ grabber_tex = get_theme_icon("grabber", "HSlider");
}
if (grabber->get_texture() != grabber_tex) {
@@ -297,7 +298,7 @@ void EditorSpinSlider::_notification(int p_what) {
grabber->set_position(get_global_position() + grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5);
if (mousewheel_over_grabber) {
- Input::get_singleton()->warp_mouse_position(grabber->get_position() + grabber_rect.size);
+ InputFilter::get_singleton()->warp_mouse_position(grabber->get_position() + grabber_rect.size);
}
grabber_range = width;
@@ -316,12 +317,7 @@ void EditorSpinSlider::_notification(int p_what) {
update();
}
if (p_what == NOTIFICATION_FOCUS_ENTER) {
- /* Sorry, I don't like this, it makes navigating the different fields with arrows more difficult.
- * Just press enter to edit.
- * if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) {
- _focus_entered();
- }*/
- if ((Input::get_singleton()->is_action_pressed("ui_focus_next") || Input::get_singleton()->is_action_pressed("ui_focus_prev")) && !value_input_just_closed) {
+ if ((InputFilter::get_singleton()->is_action_pressed("ui_focus_next") || InputFilter::get_singleton()->is_action_pressed("ui_focus_prev")) && !value_input_just_closed) {
_focus_entered();
}
value_input_just_closed = false;
@@ -330,8 +326,8 @@ void EditorSpinSlider::_notification(int p_what) {
Size2 EditorSpinSlider::get_minimum_size() const {
- Ref<StyleBox> sb = get_stylebox("normal", "LineEdit");
- Ref<Font> font = get_font("font", "LineEdit");
+ Ref<StyleBox> sb = get_theme_stylebox("normal", "LineEdit");
+ Ref<Font> font = get_theme_font("font", "LineEdit");
Size2 ms = sb->get_minimum_size();
ms.height += font->get_height();
@@ -366,7 +362,7 @@ void EditorSpinSlider::_evaluate_input_text() {
return;
}
- Variant v = expr->execute(Array(), NULL, false);
+ Variant v = expr->execute(Array(), nullptr, false);
if (v.get_type() == Variant::NIL)
return;
set_value(v);
@@ -375,7 +371,7 @@ void EditorSpinSlider::_evaluate_input_text() {
//text_entered signal
void EditorSpinSlider::_value_input_entered(const String &p_text) {
value_input_just_closed = true;
- value_input->hide();
+ value_input_popup->hide();
}
//modal_closed signal
@@ -398,7 +394,7 @@ void EditorSpinSlider::_value_focus_exited() {
// -> modal_close was not called
// -> need to close/hide manually
if (!value_input_just_closed) { //value_input_just_closed should do the same
- value_input->hide();
+ value_input_popup->hide();
//tab was pressed
} else {
//enter, click, esc
@@ -441,11 +437,11 @@ void EditorSpinSlider::set_custom_label_color(bool p_use_custom_label_color, Col
}
void EditorSpinSlider::_focus_entered() {
- Rect2 gr = get_global_rect();
+ Rect2 gr = get_screen_rect();
value_input->set_text(get_text_value());
- value_input->set_position(gr.position);
- value_input->set_size(gr.size);
- value_input->call_deferred("show_modal");
+ value_input_popup->set_position(gr.position);
+ value_input_popup->set_size(gr.size);
+ value_input_popup->call_deferred("popup");
value_input->call_deferred("grab_focus");
value_input->call_deferred("select_all");
value_input->set_focus_next(find_next_valid_focus()->get_path());
@@ -492,11 +488,13 @@ EditorSpinSlider::EditorSpinSlider() {
mousewheel_over_grabber = false;
grabbing_grabber = false;
grabber_range = 1;
+ value_input_popup = memnew(Popup);
+ add_child(value_input_popup);
value_input = memnew(LineEdit);
- add_child(value_input);
- value_input->set_as_toplevel(true);
- value_input->hide();
- value_input->connect("modal_closed", callable_mp(this, &EditorSpinSlider::_value_input_closed));
+ value_input_popup->add_child(value_input);
+ value_input_popup->set_wrap_controls(true);
+ value_input->set_anchors_and_margins_preset(PRESET_WIDE);
+ value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed));
value_input->connect("text_entered", callable_mp(this, &EditorSpinSlider::_value_input_entered));
value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited));
value_input_just_closed = false;
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index 81a7b981cc..db74f5fb70 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -62,6 +62,7 @@ class EditorSpinSlider : public Range {
Vector2 grabbing_spinner_mouse_pos;
double pre_grab_value;
+ Popup *value_input_popup;
LineEdit *value_input;
bool value_input_just_closed;
diff --git a/editor/editor_sub_scene.cpp b/editor/editor_sub_scene.cpp
index 3ebd8f0475..1205e0b37c 100644
--- a/editor/editor_sub_scene.cpp
+++ b/editor/editor_sub_scene.cpp
@@ -46,7 +46,7 @@ void EditorSubScene::_path_changed(const String &p_path) {
if (scene) {
memdelete(scene);
- scene = NULL;
+ scene = nullptr;
}
if (p_path == "")
@@ -61,7 +61,7 @@ void EditorSubScene::_path_changed(const String &p_path) {
if (!scene)
return;
- _fill_tree(scene, NULL);
+ _fill_tree(scene, nullptr);
}
void EditorSubScene::_path_browse() {
@@ -70,11 +70,11 @@ void EditorSubScene::_path_browse() {
}
void EditorSubScene::_notification(int p_what) {
-
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (is_visible() && scene == NULL)
+ if (is_visible() && scene == nullptr) {
_path_browse();
+ }
}
}
@@ -209,7 +209,7 @@ void EditorSubScene::move(Node *p_new_parent, Node *p_new_owner) {
if (!is_root) {
memdelete(scene);
}
- scene = NULL;
+ scene = nullptr;
//return selnode;
}
@@ -226,7 +226,7 @@ void EditorSubScene::_bind_methods() {
EditorSubScene::EditorSubScene() {
- scene = NULL;
+ scene = nullptr;
is_root = false;
set_title(TTR("Select Node(s) to Import"));
@@ -240,7 +240,7 @@ EditorSubScene::EditorSubScene() {
path = memnew(LineEdit);
path->connect("text_entered", callable_mp(this, &EditorSubScene::_path_changed));
hb->add_child(path);
- path->set_h_size_flags(SIZE_EXPAND_FILL);
+ path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Button *b = memnew(Button);
b->set_text(TTR("Browse"));
hb->add_child(b);
@@ -248,7 +248,7 @@ EditorSubScene::EditorSubScene() {
vb->add_margin_child(TTR("Scene Path:"), hb);
tree = memnew(Tree);
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ 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));
@@ -266,7 +266,7 @@ EditorSubScene::EditorSubScene() {
file_dialog->add_filter("*." + E->get());
}
- file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ 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 39d4b70a6a..576ee436de 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -187,8 +187,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
exceptions.insert("EditorHandle");
exceptions.insert("Editor3DHandle");
exceptions.insert("Godot");
- exceptions.insert("PanoramaSky");
- exceptions.insert("ProceduralSky");
+ exceptions.insert("Sky");
exceptions.insert("EditorControlAnchor");
exceptions.insert("DefaultProjectIcon");
exceptions.insert("GuiCloseCustomizable");
@@ -249,7 +248,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
}
}
- ImageLoaderSVG::set_convert_colors(NULL);
+ ImageLoaderSVG::set_convert_colors(nullptr);
#else
WARN_PRINT("SVG support disabled, editor icons won't be rendered.");
#endif
@@ -419,7 +418,7 @@ 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 != NULL && 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) {
// 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"));
@@ -428,7 +427,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
editor_register_and_generate_icons(theme, dark_theme, thumb_size);
}
// thumbnail size has changed, so we regenerate the medium sizes
- if (p_theme != NULL && fabs((double)p_theme->get_constant("thumb_size", "Editor") - thumb_size) > 0.00001) {
+ if (p_theme != nullptr && fabs((double)p_theme->get_constant("thumb_size", "Editor") - thumb_size) > 0.00001) {
editor_register_and_generate_icons(p_theme, dark_theme, thumb_size, true);
}
@@ -911,14 +910,17 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_window->set_border_color(tab_color);
style_window->set_border_width(MARGIN_TOP, 24 * EDSCALE);
style_window->set_expand_margin_size(MARGIN_TOP, 24 * EDSCALE);
- theme->set_stylebox("panel", "WindowDialog", style_window);
- theme->set_color("title_color", "WindowDialog", font_color);
- theme->set_icon("close", "WindowDialog", theme->get_icon("GuiClose", "EditorIcons"));
- theme->set_icon("close_highlight", "WindowDialog", theme->get_icon("GuiClose", "EditorIcons"));
- theme->set_constant("close_h_ofs", "WindowDialog", 22 * EDSCALE);
- theme->set_constant("close_v_ofs", "WindowDialog", 20 * EDSCALE);
- theme->set_constant("title_height", "WindowDialog", 24 * EDSCALE);
- theme->set_font("title_font", "WindowDialog", theme->get_font("title", "EditorFonts"));
+
+ theme->set_stylebox("panel", "Window", style_default);
+ theme->set_stylebox("panel_window", "Window", style_window);
+ theme->set_color("title_color", "Window", font_color);
+ theme->set_icon("close", "Window", theme->get_icon("GuiClose", "EditorIcons"));
+ theme->set_icon("close_highlight", "Window", theme->get_icon("GuiClose", "EditorIcons"));
+ theme->set_constant("close_h_ofs", "Window", 22 * EDSCALE);
+ theme->set_constant("close_v_ofs", "Window", 20 * EDSCALE);
+ theme->set_constant("title_height", "Window", 24 * EDSCALE);
+ theme->set_constant("resize_margin", "Window", 4 * EDSCALE);
+ theme->set_font("title_font", "Window", theme->get_font("title", "EditorFonts"));
// complex window, for now only Editor settings and Project settings
Ref<StyleBoxFlat> style_complex_window = style_window->duplicate();
@@ -959,12 +961,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("grabber", "HSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons"));
theme->set_stylebox("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2));
theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
+ theme->set_stylebox("grabber_area_highlight", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
// VSlider
theme->set_icon("grabber", "VSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons"));
theme->set_icon("grabber_highlight", "VSlider", theme->get_icon("GuiSliderGrabberHl", "EditorIcons"));
theme->set_stylebox("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0));
theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
+ theme->set_stylebox("grabber_area_highlight", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
//RichTextLabel
theme->set_color("default_color", "RichTextLabel", font_color);
@@ -979,6 +983,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Panel
theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4));
+ theme->set_stylebox("panel_fg", "Panel", style_default);
// Label
theme->set_stylebox("normal", "Label", style_empty);
@@ -992,6 +997,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// LinkButton
theme->set_stylebox("focus", "LinkButton", style_empty);
theme->set_color("font_color", "LinkButton", font_color);
+ theme->set_color("font_color_hover", "LinkButton", font_color_hl);
+ theme->set_color("font_color_pressed", "LinkButton", accent_color);
+ theme->set_color("font_color_disabled", "LinkButton", font_color_disabled);
// TooltipPanel
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 6e9630804f..4d9bfc56c8 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -33,8 +33,8 @@
#include "scene/resources/theme.h"
-Ref<Theme> create_editor_theme(Ref<Theme> p_theme = NULL);
+Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
-Ref<Theme> create_custom_theme(Ref<Theme> p_theme = NULL);
+Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr);
#endif
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index c420cf44e7..6f3a8d9ea7 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -30,7 +30,7 @@
#include "editor_vcs_interface.h"
-EditorVCSInterface *EditorVCSInterface::singleton = NULL;
+EditorVCSInterface *EditorVCSInterface::singleton = nullptr;
void EditorVCSInterface::_bind_methods() {
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 9328a5e04d..7cb18432a7 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -30,10 +30,10 @@
#include "export_template_manager.h"
+#include "core/input/input_filter.h"
#include "core/io/json.h"
#include "core/io/zip_io.h"
#include "core/os/dir_access.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor_node.h"
@@ -82,11 +82,11 @@ void ExportTemplateManager::_update_template_list() {
String(VERSION_STATUS) != String("rc");
Label *current = memnew(Label);
- current->set_h_size_flags(SIZE_EXPAND_FILL);
+ current->set_h_size_flags(Control::SIZE_EXPAND_FILL);
current_hb->add_child(current);
if (templates.has(current_version)) {
- current->add_color_override("font_color", get_color("success_color", "Editor"));
+ current->add_theme_color_override("font_color", current->get_theme_color("success_color", "Editor"));
// Only display a redownload button if it can be downloaded in the first place
if (downloads_available) {
@@ -103,7 +103,7 @@ void ExportTemplateManager::_update_template_list() {
uninstall->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(current_version));
} else {
- current->add_color_override("font_color", get_color("error_color", "Editor"));
+ current->add_theme_color_override("font_color", current->get_theme_color("error_color", "Editor"));
Button *redownload = memnew(Button);
redownload->set_text(TTR("Download"));
@@ -121,13 +121,13 @@ void ExportTemplateManager::_update_template_list() {
HBoxContainer *hbc = memnew(HBoxContainer);
Label *version = memnew(Label);
- version->set_modulate(get_color("disabled_font_color", "Editor"));
+ version->set_modulate(current->get_theme_color("disabled_font_color", "Editor"));
String text = E->get();
if (text == current_version) {
text += " " + TTR("(Current)");
}
version->set_text(text);
- version->set_h_size_flags(SIZE_EXPAND_FILL);
+ version->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(version);
Button *uninstall = memnew(Button);
@@ -145,7 +145,7 @@ void ExportTemplateManager::_download_template(const String &p_version) {
while (template_list->get_child_count()) {
memdelete(template_list->get_child(0));
}
- template_downloader->popup_centered_minsize();
+ template_downloader->popup_centered();
template_list_state->set_text(TTR("Retrieving mirrors, please wait..."));
template_download_progress->set_max(100);
template_download_progress->set_value(0);
@@ -157,7 +157,7 @@ void ExportTemplateManager::_download_template(const String &p_version) {
void ExportTemplateManager::_uninstall_template(const String &p_version) {
remove_confirm->set_text(vformat(TTR("Remove template version '%s'?"), p_version));
- remove_confirm->popup_centered_minsize();
+ remove_confirm->popup_centered();
to_remove = p_version;
}
@@ -184,7 +184,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
// unzClose() will take care of closing the file stored in the unzFile,
// so we don't need to `memdelete(fa)` in this method.
- FileAccess *fa = NULL;
+ FileAccess *fa = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&fa);
unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io);
@@ -203,7 +203,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String file = fname;
@@ -258,7 +258,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
ret = unzGoToFirstFile(pkg);
- EditorProgress *p = NULL;
+ EditorProgress *p = nullptr;
if (p_use_progress) {
p = memnew(EditorProgress("ltask", TTR("Extracting Export Templates"), fc));
}
@@ -270,7 +270,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
//get filename
unz_file_info info;
char fname[16384];
- unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String file_path(String(fname).simplify_path());
@@ -342,7 +342,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
void ExportTemplateManager::popup_manager() {
_update_template_list();
- popup_centered_minsize(Size2(400, 400) * EDSCALE);
+ popup_centered(Size2(400, 400) * EDSCALE);
}
void ExportTemplateManager::ok_pressed() {
@@ -446,7 +446,7 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int
void ExportTemplateManager::_begin_template_download(const String &p_url) {
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
OS::get_singleton()->shell_open(p_url);
return;
}
@@ -483,6 +483,11 @@ void ExportTemplateManager::_window_template_downloader_closed() {
void ExportTemplateManager::_notification(int p_what) {
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ if (!is_visible()) {
+ set_process(false);
+ }
+ }
if (p_what == NOTIFICATION_PROCESS) {
update_countdown -= get_process_delta_time();
@@ -536,12 +541,6 @@ void ExportTemplateManager::_notification(int p_what) {
set_process(false);
}
}
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (!is_visible_in_tree()) {
- set_process(false);
- }
- }
}
bool ExportTemplateManager::can_install_android_template() {
@@ -588,7 +587,7 @@ Error ExportTemplateManager::install_android_template() {
const String &source_zip = templates_path.plus_file("android_source.zip");
ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN);
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(source_zip.utf8().get_data(), &io);
@@ -612,7 +611,7 @@ Error ExportTemplateManager::install_android_template() {
// Get file path.
unz_file_info info;
char fpath[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, nullptr, 0, nullptr, 0);
String path = fpath;
String base_dir = path.get_base_dir();
@@ -674,7 +673,7 @@ ExportTemplateManager::ExportTemplateManager() {
installed_scroll->add_child(installed_vb);
installed_scroll->set_enable_v_scroll(true);
installed_scroll->set_enable_h_scroll(false);
- installed_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ installed_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
get_cancel()->set_text(TTR("Close"));
get_ok()->set_text(TTR("Install From File"));
@@ -688,7 +687,7 @@ ExportTemplateManager::ExportTemplateManager() {
template_open->set_title(TTR("Select Template File"));
template_open->add_filter("*.tpz ; " + TTR("Godot Export Templates"));
template_open->set_access(FileDialog::ACCESS_FILESYSTEM);
- template_open->set_mode(FileDialog::MODE_OPEN_FILE);
+ template_open->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
template_open->connect("file_selected", callable_mp(this, &ExportTemplateManager::_install_from_file), varray(true));
add_child(template_open);
@@ -708,7 +707,7 @@ ExportTemplateManager::ExportTemplateManager() {
template_downloader->get_ok()->set_text(TTR("Close"));
template_downloader->set_exclusive(true);
add_child(template_downloader);
- template_downloader->connect("popup_hide", callable_mp(this, &ExportTemplateManager::_window_template_downloader_closed));
+ template_downloader->connect("cancelled", callable_mp(this, &ExportTemplateManager::_window_template_downloader_closed));
VBoxContainer *vbc = memnew(VBoxContainer);
template_downloader->add_child(vbc);
diff --git a/editor/file_type_cache.cpp b/editor/file_type_cache.cpp
deleted file mode 100644
index 52ab80cc48..0000000000
--- a/editor/file_type_cache.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*************************************************************************/
-/* file_type_cache.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "file_type_cache.h"
-
-#include "core/os/file_access.h"
-#include "core/project_settings.h"
-
-FileTypeCache *FileTypeCache::singleton = NULL;
-
-bool FileTypeCache::has_file(const String &p_path) const {
-
- GLOBAL_LOCK_FUNCTION
- return file_type_map.has(p_path);
-}
-
-String FileTypeCache::get_file_type(const String &p_path) const {
-
- GLOBAL_LOCK_FUNCTION
- ERR_FAIL_COND_V(!file_type_map.has(p_path), "");
- return file_type_map[p_path];
-}
-void FileTypeCache::set_file_type(const String &p_path, const String &p_type) {
-
- GLOBAL_LOCK_FUNCTION
- file_type_map[p_path] = p_type;
-}
-
-void FileTypeCache::load() {
-
- GLOBAL_LOCK_FUNCTION
- String project = ProjectSettings::get_singleton()->get_resource_path();
- FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::READ);
-
- if (!f) {
-
- WARN_PRINT("Can't open file_type_cache.cch.");
- return;
- }
-
- file_type_map.clear();
- while (!f->eof_reached()) {
-
- String path = f->get_line();
- if (f->eof_reached())
- break;
- String type = f->get_line();
- set_file_type(path, type);
- }
-
- memdelete(f);
-}
-
-void FileTypeCache::save() {
-
- GLOBAL_LOCK_FUNCTION
- String project = ProjectSettings::get_singleton()->get_resource_path();
- FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::WRITE);
-
- ERR_FAIL_COND_MSG(!f, "Can't open file_type_cache.cch for writing, not saving file type cache!");
-
- const String *K = NULL;
-
- while ((K = file_type_map.next(K))) {
-
- f->store_line(*K);
- f->store_line(file_type_map[*K]);
- }
-
- memdelete(f);
-}
-
-FileTypeCache::FileTypeCache() {
-
- ERR_FAIL_COND_MSG(singleton, "FileTypeCache singleton already exist.");
- singleton = this;
-}
diff --git a/editor/file_type_cache.h b/editor/file_type_cache.h
deleted file mode 100644
index 216effea00..0000000000
--- a/editor/file_type_cache.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*************************************************************************/
-/* file_type_cache.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 FILE_TYPE_CACHE_H
-#define FILE_TYPE_CACHE_H
-
-#include "core/object.h"
-
-class FileTypeCache : Object {
-
- GDCLASS(FileTypeCache, Object);
-
- HashMap<String, String> file_type_map;
-
- static FileTypeCache *singleton;
-
-public:
- static FileTypeCache *get_singleton() { return singleton; }
-
- bool has_file(const String &p_path) const;
- String get_file_type(const String &p_path) const;
- void set_file_type(const String &p_path, const String &p_type);
-
- void load();
- void save();
-
- FileTypeCache();
-};
-
-#endif // FILE_TYPE_CACHE_H
diff --git a/editor/fileserver/SCsub b/editor/fileserver/SCsub
index 2b1e889fb0..359d04e5df 100644
--- a/editor/fileserver/SCsub
+++ b/editor/fileserver/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 6c69f46941..236ae16ccf 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -42,16 +42,17 @@
#include "editor_scale.h"
#include "editor_settings.h"
#include "import_dock.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
+#include "servers/display_server.h"
Ref<Texture2D> FileSystemDock::_get_tree_item_icon(EditorFileSystemDirectory *p_dir, int p_idx) {
Ref<Texture2D> file_icon;
if (!p_dir->get_file_import_is_valid(p_idx)) {
- file_icon = get_icon("ImportFail", "EditorIcons");
+ file_icon = get_theme_icon("ImportFail", "EditorIcons");
} else {
String file_type = p_dir->get_file_type(p_idx);
- file_icon = (has_icon(file_type, "EditorIcons")) ? get_icon(file_type, "EditorIcons") : get_icon("File", "EditorIcons");
+ file_icon = (has_theme_icon(file_type, "EditorIcons")) ? get_theme_icon(file_type, "EditorIcons") : get_theme_icon("File", "EditorIcons");
}
return file_icon;
}
@@ -66,8 +67,8 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
dname = "res://";
subdirectory_item->set_text(0, dname);
- subdirectory_item->set_icon(0, get_icon("Folder", "EditorIcons"));
- subdirectory_item->set_icon_modulate(0, get_color("folder_icon_modulate", "FileDialog"));
+ subdirectory_item->set_icon(0, get_theme_icon("Folder", "EditorIcons"));
+ subdirectory_item->set_icon_modulate(0, get_theme_color("folder_icon_modulate", "FileDialog"));
subdirectory_item->set_selectable(0, true);
String lpath = p_dir->get_path();
subdirectory_item->set_metadata(0, lpath);
@@ -121,7 +122,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
file_item->set_as_cursor(0);
}
if (main_scene == file_metadata) {
- file_item->set_custom_color(0, get_color("accent_color", "Editor"));
+ file_item->set_custom_color(0, get_theme_color("accent_color", "Editor"));
}
Array udata;
udata.push_back(tree_update_id);
@@ -187,7 +188,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
// Handles the favorites.
TreeItem *favorites = tree->create_item(root);
- favorites->set_icon(0, get_icon("Favorites", "EditorIcons"));
+ favorites->set_icon(0, get_theme_icon("Favorites", "EditorIcons"));
favorites->set_text(0, TTR("Favorites:"));
favorites->set_metadata(0, "Favorites");
favorites->set_collapsed(p_uncollapsed_paths.find("Favorites") < 0);
@@ -198,8 +199,8 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
if (!fave.begins_with("res://"))
continue;
- Ref<Texture2D> folder_icon = get_icon("Folder", "EditorIcons");
- const Color folder_color = get_color("folder_icon_modulate", "FileDialog");
+ Ref<Texture2D> folder_icon = get_theme_icon("Folder", "EditorIcons");
+ const Color folder_color = get_theme_color("folder_icon_modulate", "FileDialog");
String text;
Ref<Texture2D> icon;
@@ -219,7 +220,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
if (dir) {
icon = _get_tree_item_icon(dir, index);
} else {
- icon = get_icon("File", "EditorIcons");
+ icon = get_theme_icon("File", "EditorIcons");
}
color = Color(1, 1, 1);
}
@@ -306,20 +307,21 @@ void FileSystemDock::_notification(int p_what) {
EditorResourcePreview::get_singleton()->connect("preview_invalidated", callable_mp(this, &FileSystemDock::_preview_invalidated));
String ei = "EditorIcons";
- button_reload->set_icon(get_icon("Reload", ei));
- button_toggle_display_mode->set_icon(get_icon("Panels2", ei));
+
+ button_reload->set_icon(get_theme_icon("Reload", ei));
+ button_toggle_display_mode->set_icon(get_theme_icon("Panels2", ei));
button_file_list_display_mode->connect("pressed", callable_mp(this, &FileSystemDock::_toggle_file_display));
files->connect("item_activated", callable_mp(this, &FileSystemDock::_file_list_activate_file));
button_hist_next->connect("pressed", callable_mp(this, &FileSystemDock::_fw_history));
button_hist_prev->connect("pressed", callable_mp(this, &FileSystemDock::_bw_history));
- tree_search_box->set_right_icon(get_icon("Search", ei));
+ tree_search_box->set_right_icon(get_theme_icon("Search", ei));
tree_search_box->set_clear_button_enabled(true);
- file_list_search_box->set_right_icon(get_icon("Search", ei));
+ file_list_search_box->set_right_icon(get_theme_icon("Search", ei));
file_list_search_box->set_clear_button_enabled(true);
- button_hist_next->set_icon(get_icon("Forward", ei));
- button_hist_prev->set_icon(get_icon("Back", ei));
+ button_hist_next->set_icon(get_theme_icon("Forward", ei));
+ button_hist_prev->set_icon(get_theme_icon("Back", ei));
file_list_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_list_rmb_option));
tree_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option));
@@ -369,19 +371,19 @@ void FileSystemDock::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
// Update icons.
String ei = "EditorIcons";
- button_reload->set_icon(get_icon("Reload", ei));
- button_toggle_display_mode->set_icon(get_icon("Panels2", ei));
- button_hist_next->set_icon(get_icon("Forward", ei));
- button_hist_prev->set_icon(get_icon("Back", ei));
+ button_reload->set_icon(get_theme_icon("Reload", ei));
+ button_toggle_display_mode->set_icon(get_theme_icon("Panels2", ei));
+ button_hist_next->set_icon(get_theme_icon("Forward", ei));
+ button_hist_prev->set_icon(get_theme_icon("Back", ei));
if (file_list_display_mode == FILE_LIST_DISPLAY_LIST) {
- button_file_list_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons"));
+ button_file_list_display_mode->set_icon(get_theme_icon("FileThumbnail", "EditorIcons"));
} else {
- button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons"));
+ button_file_list_display_mode->set_icon(get_theme_icon("FileList", "EditorIcons"));
}
- tree_search_box->set_right_icon(get_icon("Search", ei));
+ tree_search_box->set_right_icon(get_theme_icon("Search", ei));
tree_search_box->set_clear_button_enabled(true);
- file_list_search_box->set_right_icon(get_icon("Search", ei));
+ file_list_search_box->set_right_icon(get_theme_icon("Search", ei));
file_list_search_box->set_clear_button_enabled(true);
// Update always show folders.
@@ -532,11 +534,11 @@ void FileSystemDock::_toggle_file_display() {
void FileSystemDock::_set_file_display(bool p_active) {
if (p_active) {
file_list_display_mode = FILE_LIST_DISPLAY_LIST;
- button_file_list_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons"));
+ button_file_list_display_mode->set_icon(get_theme_icon("FileThumbnail", "EditorIcons"));
button_file_list_display_mode->set_tooltip(TTR("View items as a grid of thumbnails."));
} else {
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
- button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons"));
+ button_file_list_display_mode->set_icon(get_theme_icon("FileList", "EditorIcons"));
button_file_list_display_mode->set_tooltip(TTR("View items as a list."));
}
@@ -628,13 +630,13 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
if (thumbnail_size < 64) {
- folder_thumbnail = get_icon("FolderMediumThumb", ei);
- file_thumbnail = get_icon("FileMediumThumb", ei);
- file_thumbnail_broken = get_icon("FileDeadMediumThumb", ei);
+ folder_thumbnail = get_theme_icon("FolderMediumThumb", ei);
+ file_thumbnail = get_theme_icon("FileMediumThumb", ei);
+ file_thumbnail_broken = get_theme_icon("FileDeadMediumThumb", ei);
} else {
- folder_thumbnail = get_icon("FolderBigThumb", ei);
- file_thumbnail = get_icon("FileBigThumb", ei);
- file_thumbnail_broken = get_icon("FileDeadBigThumb", ei);
+ folder_thumbnail = get_theme_icon("FolderBigThumb", ei);
+ file_thumbnail = get_theme_icon("FileBigThumb", ei);
+ file_thumbnail_broken = get_theme_icon("FileDeadBigThumb", ei);
}
} else {
// No thumbnails.
@@ -645,8 +647,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->set_fixed_icon_size(Size2());
}
- Ref<Texture2D> folder_icon = (use_thumbnails) ? folder_thumbnail : get_icon("folder", "FileDialog");
- const Color folder_color = get_color("folder_icon_modulate", "FileDialog");
+ Ref<Texture2D> folder_icon = (use_thumbnails) ? folder_thumbnail : get_theme_icon("folder", "FileDialog");
+ const Color folder_color = get_theme_color("folder_icon_modulate", "FileDialog");
// Build the FileInfo list.
List<FileInfo> filelist;
@@ -766,10 +768,10 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
// Select the icons.
if (!finfo->import_broken) {
- type_icon = (has_icon(ftype, ei)) ? get_icon(ftype, ei) : get_icon(oi, ei);
+ type_icon = (has_theme_icon(ftype, ei)) ? get_theme_icon(ftype, ei) : get_theme_icon(oi, ei);
big_icon = file_thumbnail;
} else {
- type_icon = get_icon("ImportFail", ei);
+ type_icon = get_theme_icon("ImportFail", ei);
big_icon = file_thumbnail_broken;
tooltip += "\n" + TTR("Status: Import of file failed. Please fix file and reimport manually.");
}
@@ -789,7 +791,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
}
if (fpath == main_scene) {
- files->set_item_custom_fg_color(item_index, get_color("accent_color", "Editor"));
+ files->set_item_custom_fg_color(item_index, get_theme_color("accent_color", "Editor"));
}
// Generate the preview.
@@ -841,7 +843,7 @@ void FileSystemDock::_tree_activate_file() {
if (selected) {
String path = selected->get_metadata(0);
TreeItem *parent = selected->get_parent();
- bool is_favorite = parent != NULL && parent->get_metadata(0) == "Favorites";
+ bool is_favorite = parent != nullptr && parent->get_metadata(0) == "Favorites";
if ((!is_favorite && path.ends_with("/")) || path == "Favorites") {
bool collapsed = selected->is_collapsed();
@@ -953,7 +955,7 @@ void FileSystemDock::_push_to_history() {
}
void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files, Vector<String> &folders) const {
- if (efsd == NULL)
+ if (efsd == nullptr)
return;
for (int i = 0; i < efsd->get_subdir_count(); i++) {
@@ -1085,10 +1087,10 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
void FileSystemDock::_update_resource_paths_after_move(const Map<String, String> &p_renames) const {
// Rename all resources loaded, be it subresources or actual resources.
- List<Ref<Resource> > cached;
+ List<Ref<Resource>> cached;
ResourceCache::get_cached_resources(&cached);
- for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) {
+ for (List<Ref<Resource>>::Element *E = cached.front(); E; E = E->next()) {
Ref<Resource> r = E->get();
String base_path = r->get_path();
@@ -1287,12 +1289,12 @@ void FileSystemDock::_make_scene_confirm() {
editor->get_editor_data().set_scene_path(idx, scene_name);
}
-void FileSystemDock::_file_deleted(String p_file) {
- emit_signal("file_deleted", p_file);
+void FileSystemDock::_file_removed(String p_file) {
+ emit_signal("file_removed", p_file);
}
-void FileSystemDock::_folder_deleted(String p_folder) {
- emit_signal("folder_deleted", p_folder);
+void FileSystemDock::_folder_removed(String p_folder) {
+ emit_signal("folder_removed", p_folder);
}
void FileSystemDock::_rename_operation_confirm() {
@@ -1412,7 +1414,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
bool can_move = _check_existing();
if (!can_move) {
// Ask to do something.
- overwrite_dialog->popup_centered_minsize();
+ overwrite_dialog->popup_centered();
return;
}
}
@@ -1676,7 +1678,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
rename_dialog_text->set_text(name);
rename_dialog_text->select(0, name.length());
}
- rename_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ rename_dialog->popup_centered(Size2(250, 80) * EDSCALE);
rename_dialog_text->grab_focus();
}
}
@@ -1720,7 +1722,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
duplicate_dialog_text->set_text(name);
duplicate_dialog_text->select(0, name.length());
}
- duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ duplicate_dialog->popup_centered(Size2(250, 80) * EDSCALE);
duplicate_dialog_text->grab_focus();
}
} break;
@@ -1742,14 +1744,14 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
case FILE_NEW_FOLDER: {
make_dir_dialog_text->set_text("new folder");
make_dir_dialog_text->select_all();
- make_dir_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ make_dir_dialog->popup_centered(Size2(250, 80) * EDSCALE);
make_dir_dialog_text->grab_focus();
} break;
case FILE_NEW_SCENE: {
make_scene_dialog_text->set_text("new scene");
make_scene_dialog_text->select_all();
- make_scene_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ make_scene_dialog->popup_centered(Size2(250, 80) * EDSCALE);
make_scene_dialog_text->grab_focus();
} break;
@@ -1765,7 +1767,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
case FILE_COPY_PATH: {
if (!p_selected.empty()) {
String fpath = p_selected[0];
- OS::get_singleton()->set_clipboard(fpath);
+ DisplayServer::get_singleton()->clipboard_set(fpath);
}
} break;
@@ -1869,7 +1871,7 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from)
return Variant();
}
- bool is_favorite = selected->get_parent() != NULL && tree->get_root()->get_children() == selected->get_parent();
+ bool is_favorite = selected->get_parent() != nullptr && tree->get_root()->get_children() == selected->get_parent();
all_favorites &= is_favorite;
all_not_favorites &= !is_favorite;
selected = tree->get_next_selected(selected);
@@ -2178,28 +2180,28 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (all_files) {
if (all_files_scenes) {
if (filenames.size() == 1) {
- p_popup->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open Scene"), FILE_OPEN);
- p_popup->add_icon_item(get_icon("CreateNewSceneFrom", "EditorIcons"), TTR("New Inherited Scene"), FILE_INHERIT);
+ p_popup->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open Scene"), FILE_OPEN);
+ p_popup->add_icon_item(get_theme_icon("CreateNewSceneFrom", "EditorIcons"), TTR("New Inherited Scene"), FILE_INHERIT);
if (ProjectSettings::get_singleton()->get("application/run/main_scene") != filenames[0]) {
- p_popup->add_icon_item(get_icon("PlayScene", "EditorIcons"), TTR("Set As Main Scene"), FILE_MAIN_SCENE);
+ p_popup->add_icon_item(get_theme_icon("PlayScene", "EditorIcons"), TTR("Set As Main Scene"), FILE_MAIN_SCENE);
}
} else {
- p_popup->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open Scenes"), FILE_OPEN);
+ p_popup->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open Scenes"), FILE_OPEN);
}
- p_popup->add_icon_item(get_icon("Instance", "EditorIcons"), TTR("Instance"), FILE_INSTANCE);
+ p_popup->add_icon_item(get_theme_icon("Instance", "EditorIcons"), TTR("Instance"), FILE_INSTANCE);
p_popup->add_separator();
} else if (filenames.size() == 1) {
- p_popup->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open"), FILE_OPEN);
+ p_popup->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open"), FILE_OPEN);
p_popup->add_separator();
}
}
if (p_paths.size() >= 1) {
if (!all_favorites) {
- p_popup->add_icon_item(get_icon("Favorites", "EditorIcons"), TTR("Add to Favorites"), FILE_ADD_FAVORITE);
+ p_popup->add_icon_item(get_theme_icon("Favorites", "EditorIcons"), TTR("Add to Favorites"), FILE_ADD_FAVORITE);
}
if (!all_not_favorites) {
- p_popup->add_icon_item(get_icon("NonFavorite", "EditorIcons"), TTR("Remove from Favorites"), FILE_REMOVE_FAVORITE);
+ p_popup->add_icon_item(get_theme_icon("NonFavorite", "EditorIcons"), TTR("Remove from Favorites"), FILE_REMOVE_FAVORITE);
}
p_popup->add_separator();
}
@@ -2212,36 +2214,36 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
}
} else if (all_folders && foldernames.size() > 0) {
- p_popup->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open"), FILE_OPEN);
+ p_popup->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open"), FILE_OPEN);
p_popup->add_separator();
}
if (p_paths.size() == 1) {
- p_popup->add_icon_item(get_icon("ActionCopy", "EditorIcons"), TTR("Copy Path"), FILE_COPY_PATH);
+ p_popup->add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Path"), FILE_COPY_PATH);
if (p_paths[0] != "res://") {
- p_popup->add_icon_item(get_icon("Rename", "EditorIcons"), TTR("Rename..."), FILE_RENAME);
- p_popup->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Duplicate..."), FILE_DUPLICATE);
+ p_popup->add_icon_item(get_theme_icon("Rename", "EditorIcons"), TTR("Rename..."), FILE_RENAME);
+ p_popup->add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), TTR("Duplicate..."), FILE_DUPLICATE);
}
}
if (p_paths.size() > 1 || p_paths[0] != "res://") {
- p_popup->add_icon_item(get_icon("MoveUp", "EditorIcons"), TTR("Move To..."), FILE_MOVE);
- p_popup->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete"), FILE_REMOVE);
+ p_popup->add_icon_item(get_theme_icon("MoveUp", "EditorIcons"), TTR("Move To..."), FILE_MOVE);
+ p_popup->add_icon_item(get_theme_icon("Remove", "EditorIcons"), TTR("Delete"), FILE_REMOVE);
}
if (p_paths.size() == 1) {
p_popup->add_separator();
if (p_display_path_dependent_options) {
- p_popup->add_icon_item(get_icon("Folder", "EditorIcons"), TTR("New Folder..."), FILE_NEW_FOLDER);
- p_popup->add_icon_item(get_icon("PackedScene", "EditorIcons"), TTR("New Scene..."), FILE_NEW_SCENE);
- p_popup->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script..."), FILE_NEW_SCRIPT);
- p_popup->add_icon_item(get_icon("Object", "EditorIcons"), TTR("New Resource..."), FILE_NEW_RESOURCE);
+ p_popup->add_icon_item(get_theme_icon("Folder", "EditorIcons"), TTR("New Folder..."), FILE_NEW_FOLDER);
+ p_popup->add_icon_item(get_theme_icon("PackedScene", "EditorIcons"), TTR("New Scene..."), FILE_NEW_SCENE);
+ p_popup->add_icon_item(get_theme_icon("Script", "EditorIcons"), TTR("New Script..."), FILE_NEW_SCRIPT);
+ p_popup->add_icon_item(get_theme_icon("Object", "EditorIcons"), TTR("New Resource..."), FILE_NEW_RESOURCE);
p_popup->add_separator();
}
String fpath = p_paths[0];
String item_text = fpath.ends_with("/") ? TTR("Open in File Manager") : TTR("Show in File Manager");
- p_popup->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, FILE_SHOW_IN_EXPLORER);
+ p_popup->add_icon_item(get_theme_icon("Filesystem", "EditorIcons"), item_text, FILE_SHOW_IN_EXPLORER);
}
}
@@ -2251,8 +2253,8 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
if (paths.size() == 1) {
if (paths[0].ends_with("/")) {
- tree_popup->add_icon_item(get_icon("GuiTreeArrowDown", "EditorIcons"), TTR("Expand All"), FOLDER_EXPAND_ALL);
- tree_popup->add_icon_item(get_icon("GuiTreeArrowRight", "EditorIcons"), TTR("Collapse All"), FOLDER_COLLAPSE_ALL);
+ tree_popup->add_icon_item(get_theme_icon("GuiTreeArrowDown", "EditorIcons"), TTR("Expand All"), FOLDER_EXPAND_ALL);
+ tree_popup->add_icon_item(get_theme_icon("GuiTreeArrowRight", "EditorIcons"), TTR("Collapse All"), FOLDER_COLLAPSE_ALL);
tree_popup->add_separator();
}
}
@@ -2272,10 +2274,10 @@ void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) {
path = "res://";
tree_popup->clear();
tree_popup->set_size(Size2(1, 1));
- tree_popup->add_icon_item(get_icon("Folder", "EditorIcons"), TTR("New Folder..."), FILE_NEW_FOLDER);
- tree_popup->add_icon_item(get_icon("PackedScene", "EditorIcons"), TTR("New Scene..."), FILE_NEW_SCENE);
- tree_popup->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script..."), FILE_NEW_SCRIPT);
- tree_popup->add_icon_item(get_icon("Object", "EditorIcons"), TTR("New Resource..."), FILE_NEW_RESOURCE);
+ tree_popup->add_icon_item(get_theme_icon("Folder", "EditorIcons"), TTR("New Folder..."), FILE_NEW_FOLDER);
+ tree_popup->add_icon_item(get_theme_icon("PackedScene", "EditorIcons"), TTR("New Scene..."), FILE_NEW_SCENE);
+ tree_popup->add_icon_item(get_theme_icon("Script", "EditorIcons"), TTR("New Script..."), FILE_NEW_SCRIPT);
+ tree_popup->add_icon_item(get_theme_icon("Object", "EditorIcons"), TTR("New Resource..."), FILE_NEW_RESOURCE);
tree_popup->set_position(tree->get_global_position() + p_pos);
tree_popup->popup();
}
@@ -2315,12 +2317,12 @@ void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) {
file_list_popup->clear();
file_list_popup->set_size(Size2(1, 1));
- file_list_popup->add_icon_item(get_icon("Folder", "EditorIcons"), TTR("New Folder..."), FILE_NEW_FOLDER);
- file_list_popup->add_icon_item(get_icon("PackedScene", "EditorIcons"), TTR("New Scene..."), FILE_NEW_SCENE);
- file_list_popup->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script..."), FILE_NEW_SCRIPT);
- file_list_popup->add_icon_item(get_icon("Object", "EditorIcons"), TTR("New Resource..."), FILE_NEW_RESOURCE);
+ file_list_popup->add_icon_item(get_theme_icon("Folder", "EditorIcons"), TTR("New Folder..."), FILE_NEW_FOLDER);
+ file_list_popup->add_icon_item(get_theme_icon("PackedScene", "EditorIcons"), TTR("New Scene..."), FILE_NEW_SCENE);
+ file_list_popup->add_icon_item(get_theme_icon("Script", "EditorIcons"), TTR("New Script..."), FILE_NEW_SCRIPT);
+ file_list_popup->add_icon_item(get_theme_icon("Object", "EditorIcons"), TTR("New Resource..."), FILE_NEW_RESOURCE);
file_list_popup->add_separator();
- file_list_popup->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open in File Manager"), FILE_SHOW_IN_EXPLORER);
+ file_list_popup->add_icon_item(get_theme_icon("Filesystem", "EditorIcons"), TTR("Open in File Manager"), FILE_SHOW_IN_EXPLORER);
file_list_popup->set_position(files->get_global_position() + p_pos);
file_list_popup->popup();
}
@@ -2348,8 +2350,6 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
}
void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
- if (get_viewport()->get_modal_stack_top())
- return; // Ignore because of modal window.
Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
@@ -2366,8 +2366,6 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
}
void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
- if (get_viewport()->get_modal_stack_top())
- return; // Ignore because of modal window.
Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
@@ -2492,7 +2490,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
add_child(top_vbc);
HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
- toolbar_hbc->add_constant_override("separation", 0);
+ toolbar_hbc->add_theme_constant_override("separation", 0);
top_vbc->add_child(toolbar_hbc);
button_hist_prev = memnew(ToolButton);
@@ -2529,7 +2527,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
toolbar_hbc->add_child(button_toggle_display_mode);
HBoxContainer *toolbar2_hbc = memnew(HBoxContainer);
- toolbar2_hbc->add_constant_override("separation", 0);
+ toolbar2_hbc->add_theme_constant_override("separation", 0);
top_vbc->add_child(toolbar2_hbc);
tree_search_box = memnew(LineEdit);
@@ -2539,11 +2537,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
toolbar2_hbc->add_child(tree_search_box);
file_list_popup = memnew(PopupMenu);
- file_list_popup->set_hide_on_window_lose_focus(true);
+
add_child(file_list_popup);
tree_popup = memnew(PopupMenu);
- tree_popup->set_hide_on_window_lose_focus(true);
+
add_child(tree_popup);
split_box = memnew(VSplitContainer);
@@ -2613,8 +2611,8 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
add_child(owners_editor);
remove_dialog = memnew(DependencyRemoveDialog);
- remove_dialog->connect("file_removed", callable_mp(this, &FileSystemDock::_file_deleted));
- remove_dialog->connect("folder_removed", callable_mp(this, &FileSystemDock::_folder_deleted));
+ remove_dialog->connect("file_removed", callable_mp(this, &FileSystemDock::_file_removed));
+ remove_dialog->connect("folder_removed", callable_mp(this, &FileSystemDock::_folder_removed));
add_child(remove_dialog);
move_dialog = memnew(EditorDirDialog);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 00f8cd9d50..6d2d8510d1 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -210,8 +210,8 @@ private:
void _update_favorites_list_after_move(const Map<String, String> &p_files_renames, const Map<String, String> &p_folders_renames) const;
void _update_project_settings_after_move(const Map<String, String> &p_renames) const;
- void _file_deleted(String p_file);
- void _folder_deleted(String p_folder);
+ void _file_removed(String p_file);
+ void _folder_removed(String p_folder);
void _files_moved(String p_old_file, String p_new_file);
void _folder_moved(String p_old_folder, String p_new_folder);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 5a7d4cede7..d73180c831 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -299,14 +299,14 @@ const char *FindInFilesDialog::SIGNAL_REPLACE_REQUESTED = "replace_requested";
FindInFilesDialog::FindInFilesDialog() {
- set_custom_minimum_size(Size2(500 * EDSCALE, 0));
+ set_min_size(Size2(500 * EDSCALE, 0));
set_title(TTR("Find in Files"));
VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE);
add_child(vbc);
GridContainer *gc = memnew(GridContainer);
@@ -318,7 +318,7 @@ FindInFilesDialog::FindInFilesDialog() {
gc->add_child(find_label);
_search_text_line_edit = memnew(LineEdit);
- _search_text_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ _search_text_line_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
_search_text_line_edit->connect("text_changed", callable_mp(this, &FindInFilesDialog::_on_search_text_modified));
_search_text_line_edit->connect("text_entered", callable_mp(this, &FindInFilesDialog::_on_search_text_entered));
gc->add_child(_search_text_line_edit);
@@ -329,7 +329,7 @@ FindInFilesDialog::FindInFilesDialog() {
gc->add_child(_replace_label);
_replace_text_line_edit = memnew(LineEdit);
- _replace_text_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ _replace_text_line_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
_replace_text_line_edit->connect("text_entered", callable_mp(this, &FindInFilesDialog::_on_replace_text_entered));
_replace_text_line_edit->hide();
gc->add_child(_replace_text_line_edit);
@@ -362,7 +362,7 @@ FindInFilesDialog::FindInFilesDialog() {
hbc->add_child(prefix_label);
_folder_line_edit = memnew(LineEdit);
- _folder_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ _folder_line_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(_folder_line_edit);
Button *folder_button = memnew(Button);
@@ -371,7 +371,7 @@ FindInFilesDialog::FindInFilesDialog() {
hbc->add_child(folder_button);
_folder_dialog = memnew(FileDialog);
- _folder_dialog->set_mode(FileDialog::MODE_OPEN_DIR);
+ _folder_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
_folder_dialog->connect("dir_selected", callable_mp(this, &FindInFilesDialog::_on_folder_selected));
add_child(_folder_dialog);
@@ -464,6 +464,7 @@ Set<String> FindInFilesDialog::get_filter() const {
void FindInFilesDialog::_notification(int p_what) {
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
if (is_visible()) {
// Doesn't work more than once if not deferred...
_search_text_line_edit->call_deferred("grab_focus");
@@ -576,7 +577,7 @@ FindInFilesPanel::FindInFilesPanel() {
hbc->add_child(find_label);
_search_text_label = memnew(Label);
- _search_text_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts"));
+ _search_text_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("source", "EditorFonts"));
hbc->add_child(_search_text_label);
_progress_bar = memnew(ProgressBar);
@@ -604,7 +605,7 @@ FindInFilesPanel::FindInFilesPanel() {
}
_results_display = memnew(Tree);
- _results_display->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts"));
+ _results_display->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("source", "EditorFonts"));
_results_display->set_v_size_flags(SIZE_EXPAND_FILL);
_results_display->connect("item_selected", callable_mp(this, &FindInFilesPanel::_on_result_selected));
_results_display->connect("item_edited", callable_mp(this, &FindInFilesPanel::_on_item_edited));
@@ -707,7 +708,7 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
TreeItem *file_item;
Map<String, TreeItem *>::Element *E = _file_items.find(fpath);
- if (E == NULL) {
+ if (E == nullptr) {
file_item = _results_display->create_item();
file_item->set_text(0, fpath);
file_item->set_metadata(0, fpath);
@@ -734,7 +735,7 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
item->set_text(text_index, item_text);
item->set_custom_draw(text_index, this, "_draw_result_text");
- Ref<Font> font = _results_display->get_font("font");
+ Ref<Font> font = _results_display->get_theme_font("font");
float raw_text_width = font->get_string_size(text).x;
float item_text_width = font->get_string_size(item_text).x;
@@ -780,11 +781,11 @@ void FindInFilesPanel::_on_item_edited() {
TreeItem *item = _results_display->get_selected();
if (item->is_checked(0)) {
- item->set_custom_color(1, _results_display->get_color("font_color"));
+ item->set_custom_color(1, _results_display->get_theme_color("font_color"));
} else {
// Grey out
- Color color = _results_display->get_color("font_color");
+ Color color = _results_display->get_theme_color("font_color");
color.a /= 2.0;
item->set_custom_color(1, color);
}
@@ -812,7 +813,7 @@ void FindInFilesPanel::_on_result_selected() {
TreeItem *item = _results_display->get_selected();
Map<TreeItem *, Result>::Element *E = _result_items.find(item);
- if (E == NULL)
+ if (E == nullptr)
return;
Result r = E->value();
@@ -844,7 +845,7 @@ void FindInFilesPanel::_on_replace_all_clicked() {
continue;
Map<TreeItem *, Result>::Element *F = _result_items.find(item);
- ERR_FAIL_COND(F == NULL);
+ ERR_FAIL_COND(F == nullptr);
locations.push_back(F->value());
}
diff --git a/editor/find_in_files.h b/editor/find_in_files.h
index 7002f750b7..41adb156b6 100644
--- a/editor/find_in_files.h
+++ b/editor/find_in_files.h
@@ -120,10 +120,11 @@ public:
Set<String> get_filter() const;
protected:
- static void _bind_methods();
-
void _notification(int p_what);
+
+ void _visibility_changed();
void custom_action(const String &p_action);
+ static void _bind_methods();
private:
void _on_folder_button_pressed();
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index b4c9a01f2a..7e5d2e87d6 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -68,7 +68,7 @@ void GroupDialog::_load_nodes(Node *p_current) {
keep = false;
}
- TreeItem *node = NULL;
+ TreeItem *node = nullptr;
NodePath path = scene_tree->get_edited_scene_root()->get_path_to(p_current);
if (keep && p_current->is_in_group(selected_group)) {
if (remove_filter->get_text().is_subsequence_ofi(String(p_current->get_name()))) {
@@ -94,7 +94,7 @@ void GroupDialog::_load_nodes(Node *p_current) {
if (!_can_edit(p_current, selected_group)) {
node->set_selectable(0, false);
- node->set_custom_color(0, get_color("disabled_font_color", "Editor"));
+ node->set_custom_color(0, groups->get_theme_color("disabled_font_color", "Editor"));
}
}
@@ -122,7 +122,7 @@ bool GroupDialog::_can_edit(Node *p_node, String p_group) {
}
void GroupDialog::_add_pressed() {
- TreeItem *selected = nodes_to_add->get_next_selected(NULL);
+ TreeItem *selected = nodes_to_add->get_next_selected(nullptr);
if (!selected) {
return;
@@ -151,7 +151,7 @@ void GroupDialog::_add_pressed() {
}
void GroupDialog::_removed_pressed() {
- TreeItem *selected = nodes_to_remove->get_next_selected(NULL);
+ TreeItem *selected = nodes_to_remove->get_next_selected(nullptr);
if (!selected) {
return;
@@ -204,7 +204,7 @@ void GroupDialog::_add_group(String p_name) {
TreeItem *new_group = groups->create_item(groups_root);
new_group->set_text(0, name);
- new_group->add_button(0, get_icon("Remove", "EditorIcons"), 0);
+ new_group->add_button(0, groups->get_theme_icon("Remove", "EditorIcons"), 0);
new_group->set_editable(0, true);
new_group->select(0);
groups->ensure_cursor_is_visible();
@@ -361,12 +361,12 @@ void GroupDialog::_delete_group_item(const String &p_name) {
void GroupDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- add_button->set_icon(get_icon("Forward", "EditorIcons"));
- remove_button->set_icon(get_icon("Back", "EditorIcons"));
+ add_button->set_icon(groups->get_theme_icon("Forward", "EditorIcons"));
+ remove_button->set_icon(groups->get_theme_icon("Back", "EditorIcons"));
- add_filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ add_filter->set_right_icon(groups->get_theme_icon("Search", "EditorIcons"));
add_filter->set_clear_button_enabled(true);
- remove_filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ remove_filter->set_right_icon(groups->get_theme_icon("Search", "EditorIcons"));
remove_filter->set_clear_button_enabled(true);
} break;
}
@@ -399,21 +399,21 @@ void GroupDialog::_bind_methods() {
}
GroupDialog::GroupDialog() {
- set_custom_minimum_size(Size2(600, 400) * EDSCALE);
+ set_min_size(Size2(600, 400) * EDSCALE);
scene_tree = SceneTree::get_singleton();
VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
- vbc->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
+ vbc->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
HBoxContainer *hbc = memnew(HBoxContainer);
vbc->add_child(hbc);
- hbc->set_v_size_flags(SIZE_EXPAND_FILL);
+ hbc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
VBoxContainer *vbc_left = memnew(VBoxContainer);
hbc->add_child(vbc_left);
- vbc_left->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_left->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *group_title = memnew(Label);
group_title->set_text(TTR("Groups"));
@@ -425,19 +425,19 @@ GroupDialog::GroupDialog() {
groups->set_select_mode(Tree::SELECT_SINGLE);
groups->set_allow_reselect(true);
groups->set_allow_rmb_select(true);
- groups->set_v_size_flags(SIZE_EXPAND_FILL);
- groups->add_constant_override("draw_guides", 1);
+ groups->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ groups->add_theme_constant_override("draw_guides", 1);
groups->connect("item_selected", callable_mp(this, &GroupDialog::_group_selected));
groups->connect("button_pressed", callable_mp(this, &GroupDialog::_delete_group_pressed));
groups->connect("item_edited", callable_mp(this, &GroupDialog::_group_renamed));
HBoxContainer *chbc = memnew(HBoxContainer);
vbc_left->add_child(chbc);
- chbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ chbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_group_text = memnew(LineEdit);
chbc->add_child(add_group_text);
- add_group_text->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_group_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_group_text->connect("text_entered", callable_mp(this, &GroupDialog::_add_group_pressed));
Button *add_group_button = memnew(Button);
@@ -447,7 +447,7 @@ GroupDialog::GroupDialog() {
VBoxContainer *vbc_add = memnew(VBoxContainer);
hbc->add_child(vbc_add);
- vbc_add->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_add->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *out_of_group_title = memnew(Label);
out_of_group_title->set_text(TTR("Nodes Not in Group"));
@@ -458,23 +458,23 @@ GroupDialog::GroupDialog() {
nodes_to_add->set_hide_root(true);
nodes_to_add->set_hide_folding(true);
nodes_to_add->set_select_mode(Tree::SELECT_MULTI);
- nodes_to_add->set_v_size_flags(SIZE_EXPAND_FILL);
- nodes_to_add->add_constant_override("draw_guides", 1);
+ nodes_to_add->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ nodes_to_add->add_theme_constant_override("draw_guides", 1);
HBoxContainer *add_filter_hbc = memnew(HBoxContainer);
- add_filter_hbc->add_constant_override("separate", 0);
+ add_filter_hbc->add_theme_constant_override("separate", 0);
vbc_add->add_child(add_filter_hbc);
add_filter = memnew(LineEdit);
- add_filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_filter->set_placeholder(TTR("Filter nodes"));
add_filter_hbc->add_child(add_filter);
add_filter->connect("text_changed", callable_mp(this, &GroupDialog::_add_filter_changed));
VBoxContainer *vbc_buttons = memnew(VBoxContainer);
hbc->add_child(vbc_buttons);
- vbc_buttons->set_h_size_flags(SIZE_SHRINK_CENTER);
- vbc_buttons->set_v_size_flags(SIZE_SHRINK_CENTER);
+ vbc_buttons->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
+ vbc_buttons->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
add_button = memnew(ToolButton);
add_button->set_text(TTR("Add"));
@@ -493,7 +493,7 @@ GroupDialog::GroupDialog() {
VBoxContainer *vbc_remove = memnew(VBoxContainer);
hbc->add_child(vbc_remove);
- vbc_remove->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_remove->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *in_group_title = memnew(Label);
in_group_title->set_text(TTR("Nodes in Group"));
@@ -501,18 +501,18 @@ GroupDialog::GroupDialog() {
nodes_to_remove = memnew(Tree);
vbc_remove->add_child(nodes_to_remove);
- nodes_to_remove->set_v_size_flags(SIZE_EXPAND_FILL);
+ nodes_to_remove->set_v_size_flags(Control::SIZE_EXPAND_FILL);
nodes_to_remove->set_hide_root(true);
nodes_to_remove->set_hide_folding(true);
nodes_to_remove->set_select_mode(Tree::SELECT_MULTI);
- nodes_to_remove->add_constant_override("draw_guides", 1);
+ nodes_to_remove->add_theme_constant_override("draw_guides", 1);
HBoxContainer *remove_filter_hbc = memnew(HBoxContainer);
- remove_filter_hbc->add_constant_override("separate", 0);
+ remove_filter_hbc->add_theme_constant_override("separate", 0);
vbc_remove->add_child(remove_filter_hbc);
remove_filter = memnew(LineEdit);
- remove_filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ remove_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
remove_filter->set_placeholder(TTR("Filter nodes"));
remove_filter_hbc->add_child(remove_filter);
remove_filter->connect("text_changed", callable_mp(this, &GroupDialog::_remove_filter_changed));
@@ -524,11 +524,9 @@ GroupDialog::GroupDialog() {
group_empty->set_autowrap(true);
group_empty->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
nodes_to_remove->add_child(group_empty);
- group_empty->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
+ group_empty->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
set_title(TTR("Group Editor"));
- set_as_toplevel(true);
- set_resizable(true);
error = memnew(ConfirmationDialog);
add_child(error);
@@ -639,7 +637,7 @@ void GroupsEditor::update_tree() {
TreeItem *item = tree->create_item(root);
item->set_text(0, gi.name);
if (can_be_deleted) {
- item->add_button(0, get_icon("Remove", "EditorIcons"), 0);
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), 0);
} else {
item->set_selectable(0, false);
}
@@ -664,12 +662,12 @@ void GroupsEditor::_bind_methods() {
GroupsEditor::GroupsEditor() {
- node = NULL;
+ node = nullptr;
VBoxContainer *vbc = this;
group_dialog = memnew(GroupDialog);
- group_dialog->set_as_toplevel(true);
+
add_child(group_dialog);
group_dialog->connect("group_edited", callable_mp(this, &GroupsEditor::update_tree));
@@ -682,7 +680,7 @@ GroupsEditor::GroupsEditor() {
vbc->add_child(hbc);
group_name = memnew(LineEdit);
- group_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ group_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(group_name);
group_name->connect("text_entered", callable_mp(this, &GroupsEditor::_add_group));
@@ -693,11 +691,11 @@ GroupsEditor::GroupsEditor() {
tree = memnew(Tree);
tree->set_hide_root(true);
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbc->add_child(tree);
tree->connect("button_pressed", callable_mp(this, &GroupsEditor::_remove_group));
- tree->add_constant_override("draw_guides", 1);
- add_constant_override("separation", 3 * EDSCALE);
+ tree->add_theme_constant_override("draw_guides", 1);
+ add_theme_constant_override("separation", 3 * EDSCALE);
}
GroupsEditor::~GroupsEditor() {
diff --git a/editor/groups_editor.h b/editor/groups_editor.h
index 84c653bdea..40c7b3c75a 100644
--- a/editor/groups_editor.h
+++ b/editor/groups_editor.h
@@ -41,9 +41,9 @@
#include "scene/gui/tool_button.h"
#include "scene/gui/tree.h"
-class GroupDialog : public WindowDialog {
+class GroupDialog : public AcceptDialog {
- GDCLASS(GroupDialog, WindowDialog);
+ GDCLASS(GroupDialog, AcceptDialog);
ConfirmationDialog *error;
diff --git a/editor/icons/AcceptDialog.svg b/editor/icons/AcceptDialog.svg
index e0bf7b8336..07e54d722f 100644
--- a/editor/icons/AcceptDialog.svg
+++ b/editor/icons/AcceptDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm9.4746 1.6367 1.4141 1.4141-4.9492 4.9492-2.8281-2.8281 1.4141-1.4141 1.4141 1.4141z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm9.4746 1.6367 1.4141 1.4141-4.9492 4.9492-2.8281-2.8281 1.4141-1.4141 1.4141 1.4141z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/AnimatedSprite.svg b/editor/icons/AnimatedSprite2D.svg
index 411ddda015..411ddda015 100644
--- a/editor/icons/AnimatedSprite.svg
+++ b/editor/icons/AnimatedSprite2D.svg
diff --git a/editor/icons/Area.svg b/editor/icons/Area3D.svg
index 21ebe3c251..21ebe3c251 100644
--- a/editor/icons/Area.svg
+++ b/editor/icons/Area3D.svg
diff --git a/editor/icons/BoneAttachment.svg b/editor/icons/BoneAttachment3D.svg
index 0b7dede0b6..0b7dede0b6 100644
--- a/editor/icons/BoneAttachment.svg
+++ b/editor/icons/BoneAttachment3D.svg
diff --git a/editor/icons/BoxShape.svg b/editor/icons/BoxShape3D.svg
index 171e95f4fa..171e95f4fa 100644
--- a/editor/icons/BoxShape.svg
+++ b/editor/icons/BoxShape3D.svg
diff --git a/editor/icons/CPUParticles.svg b/editor/icons/CPUParticles3D.svg
index af4115c93f..af4115c93f 100644
--- a/editor/icons/CPUParticles.svg
+++ b/editor/icons/CPUParticles3D.svg
diff --git a/editor/icons/Camera.svg b/editor/icons/Camera3D.svg
index af1cb8a2e9..af1cb8a2e9 100644
--- a/editor/icons/Camera.svg
+++ b/editor/icons/Camera3D.svg
diff --git a/editor/icons/CapsuleShape.svg b/editor/icons/CapsuleShape3D.svg
index ba035ca196..ba035ca196 100644
--- a/editor/icons/CapsuleShape.svg
+++ b/editor/icons/CapsuleShape3D.svg
diff --git a/editor/icons/ClippedCamera.svg b/editor/icons/ClippedCamera3D.svg
index 8c80c04e27..8c80c04e27 100644
--- a/editor/icons/ClippedCamera.svg
+++ b/editor/icons/ClippedCamera3D.svg
diff --git a/editor/icons/CollisionPolygon.svg b/editor/icons/CollisionPolygon3D.svg
index 5e849ae4e3..5e849ae4e3 100644
--- a/editor/icons/CollisionPolygon.svg
+++ b/editor/icons/CollisionPolygon3D.svg
diff --git a/editor/icons/CollisionShape.svg b/editor/icons/CollisionShape3D.svg
index 8f14996a97..8f14996a97 100644
--- a/editor/icons/CollisionShape.svg
+++ b/editor/icons/CollisionShape3D.svg
diff --git a/editor/icons/ConcavePolygonShape.svg b/editor/icons/ConcavePolygonShape3D.svg
index 001ab82826..001ab82826 100644
--- a/editor/icons/ConcavePolygonShape.svg
+++ b/editor/icons/ConcavePolygonShape3D.svg
diff --git a/editor/icons/ConeTwistJoint.svg b/editor/icons/ConeTwistJoint3D.svg
index 0e5e98a17b..0e5e98a17b 100644
--- a/editor/icons/ConeTwistJoint.svg
+++ b/editor/icons/ConeTwistJoint3D.svg
diff --git a/editor/icons/ConfirmationDialog.svg b/editor/icons/ConfirmationDialog.svg
index d1f13fbb3b..2d6e45b51f 100644
--- a/editor/icons/ConfirmationDialog.svg
+++ b/editor/icons/ConfirmationDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6.9863 1.002c.34689-.0022844.6986.055762 1.0391.17969 1.3618.4956 2.1813 1.9126 1.9297 3.3398-.19105 1.0835-.96172 1.9461-1.9551 2.3008v.17773h-1-1v-.8418a1.0001 1.0001 0 0 1 1-1.1582c.49193 0 .89895-.34177.98438-.82617.085424-.4845-.18031-.94508-.64258-1.1133-.46227-.1683-.96106.013453-1.207.43945a1.0002 1.0002 0 0 1 -1.7324-1c.54346-.94148 1.5433-1.4912 2.584-1.498zm-.98633 6.998h2v1h-2z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6.9863 1.002c.34689-.0022844.6986.055762 1.0391.17969 1.3618.4956 2.1813 1.9126 1.9297 3.3398-.19105 1.0835-.96172 1.9461-1.9551 2.3008v.17773h-1-1v-.8418a1.0001 1.0001 0 0 1 1-1.1582c.49193 0 .89895-.34177.98438-.82617.085424-.4845-.18031-.94508-.64258-1.1133-.46227-.1683-.96106.013453-1.207.43945a1.0002 1.0002 0 0 1 -1.7324-1c.54346-.94148 1.5433-1.4912 2.584-1.498zm-.98633 6.998h2v1h-2z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/ConvexPolygonShape.svg b/editor/icons/ConvexPolygonShape3D.svg
index bfb9230586..bfb9230586 100644
--- a/editor/icons/ConvexPolygonShape.svg
+++ b/editor/icons/ConvexPolygonShape3D.svg
diff --git a/editor/icons/CylinderShape.svg b/editor/icons/CylinderShape3D.svg
index f0aa5833d2..f0aa5833d2 100644
--- a/editor/icons/CylinderShape.svg
+++ b/editor/icons/CylinderShape3D.svg
diff --git a/editor/icons/DirectionalLight.svg b/editor/icons/DirectionalLight3D.svg
index faac2be134..faac2be134 100644
--- a/editor/icons/DirectionalLight.svg
+++ b/editor/icons/DirectionalLight3D.svg
diff --git a/editor/icons/EditorFileDialog.svg b/editor/icons/EditorFileDialog.svg
new file mode 100644
index 0000000000..95906234ab
--- /dev/null
+++ b/editor/icons/EditorFileDialog.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/FileDialog.svg b/editor/icons/FileDialog.svg
index 7708659c21..95906234ab 100644
--- a/editor/icons/FileDialog.svg
+++ b/editor/icons/FileDialog.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm3 2h3c1 0 1 2 2 2h3v4h-8z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/Particles2D.svg b/editor/icons/GPUParticles2D.svg
index 7151194e36..7151194e36 100644
--- a/editor/icons/Particles2D.svg
+++ b/editor/icons/GPUParticles2D.svg
diff --git a/editor/icons/Particles.svg b/editor/icons/GPUParticles3D.svg
index f1378e3f8c..f1378e3f8c 100644
--- a/editor/icons/Particles.svg
+++ b/editor/icons/GPUParticles3D.svg
diff --git a/editor/icons/Generic6DOFJoint.svg b/editor/icons/Generic6DOFJoint3D.svg
index 30d892e7a1..30d892e7a1 100644
--- a/editor/icons/Generic6DOFJoint.svg
+++ b/editor/icons/Generic6DOFJoint3D.svg
diff --git a/editor/icons/GizmoSpatialSamplePlayer.svg b/editor/icons/Gizmo3DSamplePlayer.svg
index ee471124dc..ee471124dc 100644
--- a/editor/icons/GizmoSpatialSamplePlayer.svg
+++ b/editor/icons/Gizmo3DSamplePlayer.svg
diff --git a/editor/icons/GizmoCPUParticles.svg b/editor/icons/GizmoCPUParticles3D.svg
index d4e86d9c42..d4e86d9c42 100644
--- a/editor/icons/GizmoCPUParticles.svg
+++ b/editor/icons/GizmoCPUParticles3D.svg
diff --git a/editor/icons/GizmoParticles.svg b/editor/icons/GizmoGPUParticles3D.svg
index 1c5d8c5f2d..1c5d8c5f2d 100644
--- a/editor/icons/GizmoParticles.svg
+++ b/editor/icons/GizmoGPUParticles3D.svg
diff --git a/editor/icons/HeightMapShape.svg b/editor/icons/HeightMapShape3D.svg
index 2e0bf53565..2e0bf53565 100644
--- a/editor/icons/HeightMapShape.svg
+++ b/editor/icons/HeightMapShape3D.svg
diff --git a/editor/icons/HingeJoint.svg b/editor/icons/HingeJoint3D.svg
index 21b3e29cb5..21b3e29cb5 100644
--- a/editor/icons/HingeJoint.svg
+++ b/editor/icons/HingeJoint3D.svg
diff --git a/editor/icons/ImmediateGeometry.svg b/editor/icons/ImmediateGeometry3D.svg
index 5679d5906f..5679d5906f 100644
--- a/editor/icons/ImmediateGeometry.svg
+++ b/editor/icons/ImmediateGeometry3D.svg
diff --git a/editor/icons/KinematicBody.svg b/editor/icons/KinematicBody3D.svg
index 16078fbdec..16078fbdec 100644
--- a/editor/icons/KinematicBody.svg
+++ b/editor/icons/KinematicBody3D.svg
diff --git a/editor/icons/Listener.svg b/editor/icons/Listener3D.svg
index 96eaeaffa9..96eaeaffa9 100644
--- a/editor/icons/Listener.svg
+++ b/editor/icons/Listener3D.svg
diff --git a/editor/icons/MeshInstance.svg b/editor/icons/MeshInstance3D.svg
index 68344b7dbd..68344b7dbd 100644
--- a/editor/icons/MeshInstance.svg
+++ b/editor/icons/MeshInstance3D.svg
diff --git a/editor/icons/MultiMeshInstance.svg b/editor/icons/MultiMeshInstance3D.svg
index c114a725db..c114a725db 100644
--- a/editor/icons/MultiMeshInstance.svg
+++ b/editor/icons/MultiMeshInstance3D.svg
diff --git a/editor/icons/Navigation.svg b/editor/icons/Navigation3D.svg
index d5a8f8618b..d5a8f8618b 100644
--- a/editor/icons/Navigation.svg
+++ b/editor/icons/Navigation3D.svg
diff --git a/editor/icons/NavigationAgent.svg b/editor/icons/NavigationAgent3D.svg
index 44c991d44c..44c991d44c 100644
--- a/editor/icons/NavigationAgent.svg
+++ b/editor/icons/NavigationAgent3D.svg
diff --git a/editor/icons/NavigationObstacle.svg b/editor/icons/NavigationObstacle3D.svg
index 42481a6067..42481a6067 100644
--- a/editor/icons/NavigationObstacle.svg
+++ b/editor/icons/NavigationObstacle3D.svg
diff --git a/editor/icons/NavigationRegion.svg b/editor/icons/NavigationRegion3D.svg
index 61f43497b4..61f43497b4 100644
--- a/editor/icons/NavigationRegion.svg
+++ b/editor/icons/NavigationRegion3D.svg
diff --git a/editor/icons/Spatial.svg b/editor/icons/Node3D.svg
index 6a469dde13..6a469dde13 100644
--- a/editor/icons/Spatial.svg
+++ b/editor/icons/Node3D.svg
diff --git a/editor/icons/OmniLight.svg b/editor/icons/OmniLight3D.svg
index 6fa0454e8c..6fa0454e8c 100644
--- a/editor/icons/OmniLight.svg
+++ b/editor/icons/OmniLight3D.svg
diff --git a/editor/icons/Path.svg b/editor/icons/Path3D.svg
index cde9a06903..cde9a06903 100644
--- a/editor/icons/Path.svg
+++ b/editor/icons/Path3D.svg
diff --git a/editor/icons/PathFollow.svg b/editor/icons/PathFollow3D.svg
index 8e904ab5a5..8e904ab5a5 100644
--- a/editor/icons/PathFollow.svg
+++ b/editor/icons/PathFollow3D.svg
diff --git a/editor/icons/PhysicalBone.svg b/editor/icons/PhysicalBone3D.svg
index 0a34eb6e48..0a34eb6e48 100644
--- a/editor/icons/PhysicalBone.svg
+++ b/editor/icons/PhysicalBone3D.svg
diff --git a/editor/icons/PinJoint.svg b/editor/icons/PinJoint3D.svg
index 147553d316..147553d316 100644
--- a/editor/icons/PinJoint.svg
+++ b/editor/icons/PinJoint3D.svg
diff --git a/editor/icons/Popup.svg b/editor/icons/Popup.svg
index 93f7e5000d..a497b7a7fc 100644
--- a/editor/icons/Popup.svg
+++ b/editor/icons/Popup.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2v10c0 1.1046.89543 2 2 2h10c1.1046 0 2-.89543 2-2v-10c0-1.1046-.89543-2-2-2zm4 2h2v6h-2zm0 8h2v2h-2z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/PopupDialog.svg b/editor/icons/PopupDialog.svg
deleted file mode 100644
index d871e56a63..0000000000
--- a/editor/icons/PopupDialog.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="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm6 1h2v5h-2zm0 6h2v2h-2z" fill="#a5efac"/></svg> \ No newline at end of file
diff --git a/editor/icons/PopupMenu.svg b/editor/icons/PopupMenu.svg
index dd7b2bb0fd..ebf62208e0 100644
--- a/editor/icons/PopupMenu.svg
+++ b/editor/icons/PopupMenu.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7a1 1 0 0 0 -1-1zm1 2h10v2h-10zm0 3h10v2h-10z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-7a1 1 0 0 0 -1-1zm1 2h10v2h-10zm0 3h10v2h-10z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/PopupPanel.svg b/editor/icons/PopupPanel.svg
index 47a5448f5b..b45a3c9c3c 100644
--- a/editor/icons/PopupPanel.svg
+++ b/editor/icons/PopupPanel.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4c-.55228 0-1 .44772-1 1v7c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-7c0-.55228-.44772-1-1-1z" fill="#a5efac"/></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v4h6v-4zm1 1h4l-2 2zm0 4c-.55228 0-1 .44772-1 1v7c0 .55228.44772 1 1 1h12c.55228 0 1-.44772 1-1v-7c0-.55228-.44772-1-1-1z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/ProximityGroup.svg b/editor/icons/ProximityGroup3D.svg
index 7df1cc9093..7df1cc9093 100644
--- a/editor/icons/ProximityGroup.svg
+++ b/editor/icons/ProximityGroup3D.svg
diff --git a/editor/icons/RayCast.svg b/editor/icons/RayCast3D.svg
index e782b27e9f..e782b27e9f 100644
--- a/editor/icons/RayCast.svg
+++ b/editor/icons/RayCast3D.svg
diff --git a/editor/icons/RayShape.svg b/editor/icons/RayShape3D.svg
index 37c2206740..37c2206740 100644
--- a/editor/icons/RayShape.svg
+++ b/editor/icons/RayShape3D.svg
diff --git a/editor/icons/RemoteTransform.svg b/editor/icons/RemoteTransform3D.svg
index 2bdf8cd858..2bdf8cd858 100644
--- a/editor/icons/RemoteTransform.svg
+++ b/editor/icons/RemoteTransform3D.svg
diff --git a/editor/icons/RigidBody.svg b/editor/icons/RigidBody3D.svg
index 5d766f7c3d..5d766f7c3d 100644
--- a/editor/icons/RigidBody.svg
+++ b/editor/icons/RigidBody3D.svg
diff --git a/editor/icons/SCsub b/editor/icons/SCsub
index b39c74c66a..f0d51999f0 100644
--- a/editor/icons/SCsub
+++ b/editor/icons/SCsub
@@ -1,21 +1,21 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
from platform_methods import run_in_subprocess
import editor_icons_builders
-make_editor_icons_builder = Builder(action=run_in_subprocess(editor_icons_builders.make_editor_icons_action),
- suffix='.h',
- src_suffix='.svg')
+make_editor_icons_builder = Builder(
+ action=run_in_subprocess(editor_icons_builders.make_editor_icons_action), suffix=".h", src_suffix=".svg"
+)
-env['BUILDERS']['MakeEditorIconsBuilder'] = make_editor_icons_builder
+env["BUILDERS"]["MakeEditorIconsBuilder"] = make_editor_icons_builder
# Editor's own icons
icon_sources = Glob("*.svg")
# Module icons
for module_icons in env.module_icons_paths:
- icon_sources += Glob('#' + module_icons + "/*.svg")
+ icon_sources += Glob("#" + module_icons + "/*.svg")
-env.Alias('editor_icons', [env.MakeEditorIconsBuilder('#editor/editor_icons.gen.h', icon_sources)])
+env.Alias("editor_icons", [env.MakeEditorIconsBuilder("#editor/editor_icons.gen.h", icon_sources)])
diff --git a/editor/icons/ScriptCreateDialog.svg b/editor/icons/ScriptCreateDialog.svg
index 751b799ba9..78a69c5e59 100644
--- a/editor/icons/ScriptCreateDialog.svg
+++ b/editor/icons/ScriptCreateDialog.svg
@@ -1 +1 @@
-<svg height="17.067" viewBox="0 0 16 16" width="17.067" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><path d="m6 1v1c-.55228 0-1 .44772-1 1v10h-1v-2h-2v2c.0002826.35698.19084.68674.5.86523.15194.088045.32439.13452.5.13477v1h6v-5l3-2v-3h3v-2c0-1.1046-.89543-2-2-2z" fill="#a5efac" transform="translate(0 1036.4)"/><path d="m6 1c-1.1046 0-2 .89543-2 2v7h-3v3c0 1.1046.89543 2 2 2s2-.89543 2-2v-10c0-.55228.44772-1 1-1s1 .44772 1 1v3h5v-1h-4v-2c0-1.1046-.89543-2-2-2zm-4 10h2v2c0 .55228-.44772 1-1 1s-1-.44772-1-1z" fill="#87e29f" transform="translate(0 1036.4)"/><circle cx="3" cy="1048.4" fill="#e0e0e0" r="0"/><g fill="#87e29f"><ellipse cx="12" cy="1048.4" rx=".5" ry="3"/><ellipse cx="913.91" cy="513.79" rx=".5" ry="3" transform="matrix(.5 .8660254 -.8660254 .5 0 0)"/><ellipse cx="901.91" cy="-534.57" rx=".5" ry="3" transform="matrix(-.5 .8660254 -.8660254 -.5 0 0)"/></g></g></svg> \ No newline at end of file
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8zm5.5722656 1h3.9980464a1.1426143 1.1426143 0 0 1 1.142579 1.1425781v1.1425781h-1.712891-2.2851562v-.5703124-.5722657c0-.6310659-.5115295-1.1425781-1.1425782-1.1425781zm0 .5722656c.3155215 0 .5703125.254791.5703125.5703125v.5722657.5703124.5722657h.5722657 2.2851562v3.9980471a1.1426143 1.1426143 0 0 1 -1.1425781 1.142578h-4c.6310487 0 1.1425781-.511529 1.1425781-1.142578v-5.7128909c0-.0785019.01823-.1545692.046875-.2226562v-.0019531c.02868-.0672829.0683226-.1266374.1191406-.1777344.00097-.00096.0029352-.0010048.0039063-.0019532.0513303-.0508898.1121075-.0944618.1796875-.1230468.0683505-.028909.1437752-.0429688.2226562-.0429688zm-2.2851562 5.1406254h1.1425781v1.142578c0 .315522-.2567441.572265-.5722656.572265-.0776611 0-.15125-.016852-.21875-.044922-.00206-.000799-.0038594-.003049-.0058594-.003906-.0656506-.028192-.1236101-.067817-.1738281-.117187a.57130715.57130715 0 0 1 -.0097656-.009766c-.0490902-.050487-.0893425-.107988-.1171876-.173828-.028908-.06835-.0449218-.143776-.0449218-.222656z"/><circle cx="-23.915255" cy="3.118624" r="0"/></g></svg> \ No newline at end of file
diff --git a/editor/icons/Skeleton.svg b/editor/icons/Skeleton3D.svg
index 015c842125..015c842125 100644
--- a/editor/icons/Skeleton.svg
+++ b/editor/icons/Skeleton3D.svg
diff --git a/editor/icons/SkeletonIK.svg b/editor/icons/SkeletonIK3D.svg
index e69f6e8bf3..e69f6e8bf3 100644
--- a/editor/icons/SkeletonIK.svg
+++ b/editor/icons/SkeletonIK3D.svg
diff --git a/editor/icons/Sky.svg b/editor/icons/Sky.svg
new file mode 100644
index 0000000000..356a966fe9
--- /dev/null
+++ b/editor/icons/Sky.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="1040.4" y2="1050.4"><stop offset="0" stop-color="#1ec3ff"/><stop offset="1" stop-color="#b2e1ff"/></linearGradient><g transform="translate(0 -1037.4)"><path d="m8 1040.4a7 7 0 0 0 -7 7 7 7 0 0 0 .68555 3h12.631a7 7 0 0 0 .68359-3 7 7 0 0 0 -7-7z" fill="url(#a)"/><path d="m10 7c-.554 0-1 .446-1 1h-1c-.554 0-1 .446-1 1s.446 1 1 1h2c.554 0 1-.446 1-1h1c.554 0 1-.446 1-1s-.446-1-1-1zm-7 3c-.554 0-1 .446-1 1s.446 1 1 1h1c.554 0 1-.446 1-1s-.446-1-1-1z" fill="#fff" transform="translate(0 1037.4)"/></g></svg> \ No newline at end of file
diff --git a/editor/icons/SliderJoint.svg b/editor/icons/SliderJoint3D.svg
index fdd7487bbf..fdd7487bbf 100644
--- a/editor/icons/SliderJoint.svg
+++ b/editor/icons/SliderJoint3D.svg
diff --git a/editor/icons/SoftBody.svg b/editor/icons/SoftBody3D.svg
index 2c907df847..2c907df847 100644
--- a/editor/icons/SoftBody.svg
+++ b/editor/icons/SoftBody3D.svg
diff --git a/editor/icons/SpatialMaterial.svg b/editor/icons/SpatialMaterial.svg
deleted file mode 100644
index cfd994a0fe..0000000000
--- a/editor/icons/SpatialMaterial.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="m7.9629 1.002a1.0001 1.0001 0 0 0 -.41016.10352l-3.7891 1.8945h8.4727l-3.7891-1.8945a1.0001 1.0001 0 0 0 -.48438-.10352z" fill="#ff7070"/><path d="m3.7637 3-2.2109 1.1055a1.0001 1.0001 0 0 0 -.55273.89453h3.2363l3.7637-1.8809 3.7637 1.8809h3.2363a1.0001 1.0001 0 0 0 -.55273-.89453l-2.2109-1.1055h-8.4727z" fill="#ffeb70"/><path d="m1 5v2h2v-.38086l.76172.38086h8.4766l.76172-.38086v.38086h2v-2h-3.2363l-3.7637 1.8828-3.7637-1.8828h-3.2363z" fill="#9dff70"/><path d="m1 7v2h2v-2zm2.7617 0 3.2383 1.6191v.38086h2v-.38086l3.2383-1.6191zm9.2383 0v2h2v-2z" fill="#70ffb9"/><path d="m1 9v2h3.2344l-1.2344-.61719v-1.3828h-2zm6 0v2h2v-2zm6 0v1.3828l-1.2344.61719h3.2344v-2h-2z" fill="#70deff"/><path d="m3.7637 13 3.7891 1.8945a1.0001 1.0001 0 0 0 .48438.10547 1.0001 1.0001 0 0 0 .41016-.10547l3.7891-1.8945h-8.4727z" fill="#ff70ac"/><path d="m1 11a1.0001 1.0001 0 0 0 .55273.89453l2.2109 1.1055h8.4727l2.2109-1.1055a1.0001 1.0001 0 0 0 .55273-.89453h-3.2344l-2.7656 1.3828v-1.3828h-2v1.3828l-2.7656-1.3828h-3.2344z" fill="#9f70ff"/></svg> \ No newline at end of file
diff --git a/editor/icons/SphereShape.svg b/editor/icons/SphereShape3D.svg
index 4da18a1a38..4da18a1a38 100644
--- a/editor/icons/SphereShape.svg
+++ b/editor/icons/SphereShape3D.svg
diff --git a/editor/icons/SpotLight.svg b/editor/icons/SpotLight3D.svg
index 6a35ee3890..6a35ee3890 100644
--- a/editor/icons/SpotLight.svg
+++ b/editor/icons/SpotLight3D.svg
diff --git a/editor/icons/SpringArm.svg b/editor/icons/SpringArm3D.svg
index eb0c1ebd7d..eb0c1ebd7d 100644
--- a/editor/icons/SpringArm.svg
+++ b/editor/icons/SpringArm3D.svg
diff --git a/editor/icons/Sprite.svg b/editor/icons/Sprite2D.svg
index 26a10625fc..26a10625fc 100644
--- a/editor/icons/Sprite.svg
+++ b/editor/icons/Sprite2D.svg
diff --git a/editor/icons/StaticBody.svg b/editor/icons/StaticBody3D.svg
index de819bd76b..de819bd76b 100644
--- a/editor/icons/StaticBody.svg
+++ b/editor/icons/StaticBody3D.svg
diff --git a/editor/icons/SubViewport.svg b/editor/icons/SubViewport.svg
new file mode 100644
index 0000000000..103b1006ad
--- /dev/null
+++ b/editor/icons/SubViewport.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-.5304.0000801-1.0390625.2108475-1.4140625.5859375-.37509.37501-.5858575.8836225-.5859375 1.4140625v8c.0000803.5304.2108475 1.039063.5859375 1.414062.37501.375091.8836225.585858 1.4140625.585938h10c1.1046 0 2-.89543 2-2v-8c0-1.1046-.89543-2-2-2zm0 1h10c.55228.0000096.99999.44772 1 1v8c-.00001.55228-.44772.99999-1 1h-10c-.55228-.00001-.99999-.44772-1-1v-8c.0000096-.55228.44772-.99999 1-1zm3 1c-.5304.0001-1.0390625.2108375-1.4140625.5859375-.37509.375-.5858575.8836225-.5859375 1.4140625v4c.00008.5304.2108475 1.039062.5859375 1.414062.37501.3751.8836225.585838 1.4140625.585938h4c1.1046 0 2-.8954 2-2v-4c0-1.1046-.89543-2-2-2zm0 1h4c.55228 0 .99999.4477 1 1v4c-.00001.5523-.44772 1-1 1h-4c-.55228 0-.99999-.4477-1-1v-4c.00001-.5523.44772-1 1-1z" fill="#e0e0e0" fill-opacity=".996078"/></svg> \ No newline at end of file
diff --git a/editor/icons/ViewportContainer.svg b/editor/icons/SubViewportContainer.svg
index 18dcddc15f..18dcddc15f 100644
--- a/editor/icons/ViewportContainer.svg
+++ b/editor/icons/SubViewportContainer.svg
diff --git a/editor/icons/VehicleBody.svg b/editor/icons/VehicleBody3D.svg
index a509730602..a509730602 100644
--- a/editor/icons/VehicleBody.svg
+++ b/editor/icons/VehicleBody3D.svg
diff --git a/editor/icons/VehicleWheel.svg b/editor/icons/VehicleWheel3D.svg
index bd870c0118..bd870c0118 100644
--- a/editor/icons/VehicleWheel.svg
+++ b/editor/icons/VehicleWheel3D.svg
diff --git a/editor/icons/VisibilityEnabler.svg b/editor/icons/VisibilityEnabler3D.svg
index 70e4f081c2..70e4f081c2 100644
--- a/editor/icons/VisibilityEnabler.svg
+++ b/editor/icons/VisibilityEnabler3D.svg
diff --git a/editor/icons/VisibilityNotifier.svg b/editor/icons/VisibilityNotifier3D.svg
index c908d5c99d..c908d5c99d 100644
--- a/editor/icons/VisibilityNotifier.svg
+++ b/editor/icons/VisibilityNotifier3D.svg
diff --git a/editor/icons/Window.svg b/editor/icons/Window.svg
new file mode 100644
index 0000000000..a02a86d56a
--- /dev/null
+++ b/editor/icons/Window.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8z" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/WindowDialog.svg b/editor/icons/WindowDialog.svg
deleted file mode 100644
index 3c7be2a58d..0000000000
--- a/editor/icons/WindowDialog.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="m3 1c-1.1046 0-2 .8954-2 2v1h14v-1c0-1.1046-.89543-2-2-2zm9 1h1v1h-1zm-11 3v8c0 1.1046.89543 2 2 2h10c1.1046 0 2-.8954 2-2v-8z" fill="#a5efac"/></svg> \ No newline at end of file
diff --git a/editor/icons/World.svg b/editor/icons/World3D.svg
index 3db96a75a6..3db96a75a6 100644
--- a/editor/icons/World.svg
+++ b/editor/icons/World3D.svg
diff --git a/editor/icons/WorldMarginShape.svg b/editor/icons/WorldMarginShape.svg
deleted file mode 100644
index 2c90cf6d53..0000000000
--- a/editor/icons/WorldMarginShape.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 1044.4 7 3 7-3-7-3z" fill="#a2d2ff" fill-rule="evenodd" transform="translate(0 -1036.4)"/></svg> \ No newline at end of file
diff --git a/editor/icons/PlaneShape.svg b/editor/icons/WorldMarginShape3D.svg
index 2c90cf6d53..2c90cf6d53 100644
--- a/editor/icons/PlaneShape.svg
+++ b/editor/icons/WorldMarginShape3D.svg
diff --git a/editor/icons/ARVRAnchor.svg b/editor/icons/XRAnchor3D.svg
index f1571b3fcc..f1571b3fcc 100644
--- a/editor/icons/ARVRAnchor.svg
+++ b/editor/icons/XRAnchor3D.svg
diff --git a/editor/icons/ARVRCamera.svg b/editor/icons/XRCamera3D.svg
index f59a8c8b4a..f59a8c8b4a 100644
--- a/editor/icons/ARVRCamera.svg
+++ b/editor/icons/XRCamera3D.svg
diff --git a/editor/icons/ARVRController.svg b/editor/icons/XRController3D.svg
index 40e5b8dce1..40e5b8dce1 100644
--- a/editor/icons/ARVRController.svg
+++ b/editor/icons/XRController3D.svg
diff --git a/editor/icons/ARVROrigin.svg b/editor/icons/XROrigin3D.svg
index dbb93ba7a5..dbb93ba7a5 100644
--- a/editor/icons/ARVROrigin.svg
+++ b/editor/icons/XROrigin3D.svg
diff --git a/editor/icons/editor_icons_builders.py b/editor/icons/editor_icons_builders.py
index ea2c2e57d1..d7145abe50 100644
--- a/editor/icons/editor_icons_builders.py
+++ b/editor/icons/editor_icons_builders.py
@@ -3,9 +3,10 @@
All such functions are invoked in a subprocess on Windows to prevent build flakiness.
"""
+
import os
+from io import StringIO
from platform_methods import subprocess_main
-from compat import StringIO
def make_editor_icons_action(target, source, env):
@@ -21,16 +22,16 @@ def make_editor_icons_action(target, source, env):
icons_string.write('\t"')
- with open(fname, 'rb') as svgf:
+ with open(fname, "rb") as svgf:
b = svgf.read(1)
- while(len(b) == 1):
+ while len(b) == 1:
icons_string.write("\\" + str(hex(ord(b)))[1:])
b = svgf.read(1)
icons_string.write('"')
if fname != svg_icons[-1]:
icons_string.write(",")
- icons_string.write('\n')
+ icons_string.write("\n")
s = StringIO()
s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
@@ -39,7 +40,7 @@ def make_editor_icons_action(target, source, env):
s.write("static const int editor_icons_count = {};\n".format(len(svg_icons)))
s.write("static const char *editor_icons_sources[] = {\n")
s.write(icons_string.getvalue())
- s.write('};\n\n')
+ s.write("};\n\n")
s.write("static const char *editor_icons_names[] = {\n")
# this is used to store the indices of thumbnail icons
@@ -62,11 +63,11 @@ def make_editor_icons_action(target, source, env):
if fname != svg_icons[-1]:
s.write(",")
- s.write('\n')
+ s.write("\n")
index += 1
- s.write('};\n')
+ s.write("};\n")
if thumb_medium_indices:
s.write("\n\n")
@@ -90,5 +91,5 @@ def make_editor_icons_action(target, source, env):
icons_string.close()
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/editor/import/SCsub b/editor/import/SCsub
index 2b1e889fb0..359d04e5df 100644
--- a/editor/import/SCsub
+++ b/editor/import/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
new file mode 100644
index 0000000000..9e49fa9066
--- /dev/null
+++ b/editor/import/collada.cpp
@@ -0,0 +1,2582 @@
+/*************************************************************************/
+/* collada.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collada.h"
+
+#include <stdio.h>
+
+//#define DEBUG_DEFAULT_ANIMATION
+//#define DEBUG_COLLADA
+#ifdef DEBUG_COLLADA
+#define COLLADA_PRINT(m_what) print_line(m_what)
+#else
+#define COLLADA_PRINT(m_what)
+#endif
+
+#define COLLADA_IMPORT_SCALE_SCENE
+
+/* HELPERS */
+
+String Collada::Effect::get_texture_path(const String &p_source, Collada &state) const {
+
+ const String &image = p_source;
+ ERR_FAIL_COND_V(!state.state.image_map.has(image), "");
+ return state.state.image_map[image].path;
+}
+
+Transform Collada::get_root_transform() const {
+
+ Transform unit_scale_transform;
+#ifndef COLLADA_IMPORT_SCALE_SCENE
+ unit_scale_transform.scale(Vector3(state.unit_scale, state.unit_scale, state.unit_scale));
+#endif
+ return unit_scale_transform;
+}
+
+void Collada::Vertex::fix_unit_scale(Collada &state) {
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ vertex *= state.state.unit_scale;
+#endif
+}
+
+static String _uri_to_id(const String &p_uri) {
+
+ if (p_uri.begins_with("#"))
+ return p_uri.substr(1, p_uri.size() - 1);
+ else
+ return p_uri;
+}
+
+/** HELPER FUNCTIONS **/
+
+Transform Collada::fix_transform(const Transform &p_transform) {
+
+ Transform tr = p_transform;
+
+#ifndef NO_UP_AXIS_SWAP
+
+ if (state.up_axis != Vector3::AXIS_Y) {
+
+ for (int i = 0; i < 3; i++)
+ SWAP(tr.basis[1][i], tr.basis[state.up_axis][i]);
+ for (int i = 0; i < 3; i++)
+ SWAP(tr.basis[i][1], tr.basis[i][state.up_axis]);
+
+ SWAP(tr.origin[1], tr.origin[state.up_axis]);
+
+ tr.basis[state.up_axis][0] = -tr.basis[state.up_axis][0];
+ tr.basis[state.up_axis][1] = -tr.basis[state.up_axis][1];
+ tr.basis[0][state.up_axis] = -tr.basis[0][state.up_axis];
+ tr.basis[1][state.up_axis] = -tr.basis[1][state.up_axis];
+ tr.origin[state.up_axis] = -tr.origin[state.up_axis];
+ }
+#endif
+
+ //tr.scale(Vector3(state.unit_scale.unit_scale.unit_scale));
+ return tr;
+ //return state.matrix_fix * p_transform;
+}
+
+static Transform _read_transform_from_array(const Vector<float> &array, int ofs = 0) {
+
+ Transform tr;
+ // i wonder why collada matrices are transposed, given that's opposed to opengl..
+ tr.basis.elements[0][0] = array[0 + ofs];
+ tr.basis.elements[0][1] = array[1 + ofs];
+ tr.basis.elements[0][2] = array[2 + ofs];
+ tr.basis.elements[1][0] = array[4 + ofs];
+ tr.basis.elements[1][1] = array[5 + ofs];
+ tr.basis.elements[1][2] = array[6 + ofs];
+ tr.basis.elements[2][0] = array[8 + ofs];
+ tr.basis.elements[2][1] = array[9 + ofs];
+ tr.basis.elements[2][2] = array[10 + ofs];
+ tr.origin.x = array[3 + ofs];
+ tr.origin.y = array[7 + ofs];
+ tr.origin.z = array[11 + ofs];
+ return tr;
+}
+
+/* STRUCTURES */
+
+Transform Collada::Node::compute_transform(Collada &state) const {
+
+ Transform xform;
+
+ for (int i = 0; i < xform_list.size(); i++) {
+
+ Transform xform_step;
+ const XForm &xf = xform_list[i];
+ switch (xf.op) {
+
+ case XForm::OP_ROTATE: {
+ if (xf.data.size() >= 4) {
+
+ xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg2rad(xf.data[3]));
+ }
+ } break;
+ case XForm::OP_SCALE: {
+
+ if (xf.data.size() >= 3) {
+
+ xform_step.scale(Vector3(xf.data[0], xf.data[1], xf.data[2]));
+ }
+
+ } break;
+ case XForm::OP_TRANSLATE: {
+
+ if (xf.data.size() >= 3) {
+
+ xform_step.origin = Vector3(xf.data[0], xf.data[1], xf.data[2]);
+ }
+
+ } break;
+ case XForm::OP_MATRIX: {
+
+ if (xf.data.size() >= 16) {
+ xform_step = _read_transform_from_array(xf.data, 0);
+ }
+
+ } break;
+ default: {
+ }
+ }
+
+ xform = xform * xform_step;
+ }
+
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ xform.origin *= state.state.unit_scale;
+#endif
+ return xform;
+}
+
+Transform Collada::Node::get_transform() const {
+
+ return default_transform;
+}
+
+Transform Collada::Node::get_global_transform() const {
+
+ if (parent)
+ return parent->get_global_transform() * default_transform;
+ else
+ return default_transform;
+}
+
+Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const {
+
+ ERR_FAIL_COND_V(keys.size() == 0, Vector<float>());
+ int i = 0;
+
+ for (i = 0; i < keys.size(); i++) {
+
+ if (keys[i].time > p_time)
+ break;
+ }
+
+ if (i == 0)
+ return keys[0].data;
+ if (i == keys.size())
+ return keys[keys.size() - 1].data;
+
+ switch (keys[i].interp_type) {
+
+ case INTERP_BEZIER: //wait for bezier
+ case INTERP_LINEAR: {
+
+ float c = (p_time - keys[i - 1].time) / (keys[i].time - keys[i - 1].time);
+
+ if (keys[i].data.size() == 16) {
+ //interpolate a matrix
+ Transform src = _read_transform_from_array(keys[i - 1].data);
+ Transform dst = _read_transform_from_array(keys[i].data);
+
+ Transform interp = c < 0.001 ? src : src.interpolate_with(dst, c);
+
+ Vector<float> ret;
+ ret.resize(16);
+ Transform tr;
+ // i wonder why collada matrices are transposed, given that's opposed to opengl..
+ ret.write[0] = interp.basis.elements[0][0];
+ ret.write[1] = interp.basis.elements[0][1];
+ ret.write[2] = interp.basis.elements[0][2];
+ ret.write[4] = interp.basis.elements[1][0];
+ ret.write[5] = interp.basis.elements[1][1];
+ ret.write[6] = interp.basis.elements[1][2];
+ ret.write[8] = interp.basis.elements[2][0];
+ ret.write[9] = interp.basis.elements[2][1];
+ ret.write[10] = interp.basis.elements[2][2];
+ ret.write[3] = interp.origin.x;
+ ret.write[7] = interp.origin.y;
+ ret.write[11] = interp.origin.z;
+ ret.write[12] = 0;
+ ret.write[13] = 0;
+ ret.write[14] = 0;
+ ret.write[15] = 1;
+
+ return ret;
+ } else {
+
+ Vector<float> dest;
+ dest.resize(keys[i].data.size());
+ for (int j = 0; j < dest.size(); j++) {
+
+ dest.write[j] = keys[i].data[j] * c + keys[i - 1].data[j] * (1.0 - c);
+ }
+ return dest;
+ //interpolate one by one
+ }
+ } break;
+ }
+
+ ERR_FAIL_V(Vector<float>());
+}
+
+void Collada::_parse_asset(XMLParser &parser) {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+
+ if (name == "up_axis") {
+
+ parser.read();
+ if (parser.get_node_data() == "X_UP")
+ state.up_axis = Vector3::AXIS_X;
+ if (parser.get_node_data() == "Y_UP")
+ state.up_axis = Vector3::AXIS_Y;
+ if (parser.get_node_data() == "Z_UP")
+ state.up_axis = Vector3::AXIS_Z;
+
+ COLLADA_PRINT("up axis: " + parser.get_node_data());
+ } else if (name == "unit") {
+
+ state.unit_scale = parser.get_attribute_value("meter").to_double();
+ COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "asset")
+ break; //end of <asset>
+ }
+}
+
+void Collada::_parse_image(XMLParser &parser) {
+
+ String id = parser.get_attribute_value("id");
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ Image image;
+
+ if (state.version < State::Version(1, 4, 0)) {
+ /* <1.4 */
+ String path = parser.get_attribute_value("source").strip_edges();
+ if (path.find("://") == -1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.percent_decode()));
+ }
+ } else {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+
+ if (name == "init_from") {
+
+ parser.read();
+ String path = parser.get_node_data().strip_edges().percent_decode();
+
+ if (path.find("://") == -1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
+
+ } else if (path.find("file:///") == 0) {
+ path = path.replace_first("file:///", "");
+ path = ProjectSettings::get_singleton()->localize_path(path);
+ }
+
+ image.path = path;
+
+ } else if (name == "data") {
+
+ ERR_PRINT("COLLADA Embedded image data not supported!");
+
+ } else if (name == "extra" && !parser.is_empty())
+ parser.skip_section();
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "image")
+ break; //end of <asset>
+ }
+ }
+
+ state.image_map[id] = image;
+}
+
+void Collada::_parse_material(XMLParser &parser) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ Material material;
+
+ String id = parser.get_attribute_value("id");
+ if (parser.has_attribute("name"))
+ material.name = parser.get_attribute_value("name");
+
+ if (state.version < State::Version(1, 4, 0)) {
+ /* <1.4 */
+ ERR_PRINT("Collada Materials < 1.4 are not supported (yet)");
+ } else {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
+
+ material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material")
+ break; //end of <asset>
+ }
+ }
+
+ state.material_map[id] = material;
+}
+
+//! reads floats from inside of xml element until end of xml element
+Vector<float> Collada::_read_float_array(XMLParser &parser) {
+
+ if (parser.is_empty())
+ return Vector<float>();
+
+ Vector<String> splitters;
+ splitters.push_back(" ");
+ splitters.push_back("\n");
+ splitters.push_back("\r");
+ splitters.push_back("\t");
+
+ Vector<float> array;
+ while (parser.read() == OK) {
+ // TODO: check for comments inside the element
+ // and ignore them.
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ // parse float data
+ String str = parser.get_node_data();
+ array = str.split_floats_mk(splitters, false);
+ //array=str.split_floats(" ",false);
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
+ break; // end parsing text
+ }
+
+ return array;
+}
+
+Vector<String> Collada::_read_string_array(XMLParser &parser) {
+
+ if (parser.is_empty())
+ return Vector<String>();
+
+ Vector<String> array;
+ while (parser.read() == OK) {
+ // TODO: check for comments inside the element
+ // and ignore them.
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ // parse String data
+ String str = parser.get_node_data();
+ array = str.split_spaces();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
+ break; // end parsing text
+ }
+
+ return array;
+}
+
+Transform Collada::_read_transform(XMLParser &parser) {
+
+ if (parser.is_empty())
+ return Transform();
+
+ Vector<String> array;
+ while (parser.read() == OK) {
+ // TODO: check for comments inside the element
+ // and ignore them.
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ // parse float data
+ String str = parser.get_node_data();
+ array = str.split_spaces();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
+ break; // end parsing text
+ }
+
+ ERR_FAIL_COND_V(array.size() != 16, Transform());
+ Vector<float> farr;
+ farr.resize(16);
+ for (int i = 0; i < 16; i++) {
+ farr.write[i] = array[i].to_double();
+ }
+
+ return _read_transform_from_array(farr);
+}
+
+String Collada::_read_empty_draw_type(XMLParser &parser) {
+
+ String empty_draw_type = "";
+
+ if (parser.is_empty())
+ return empty_draw_type;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+ empty_draw_type = parser.get_node_data();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END)
+ break; // end parsing text
+ }
+ return empty_draw_type;
+}
+
+Variant Collada::_parse_param(XMLParser &parser) {
+
+ if (parser.is_empty())
+ return Variant();
+
+ String from = parser.get_node_name();
+ Variant data;
+
+ while (parser.read() == OK) {
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "float") {
+
+ parser.read();
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+
+ data = parser.get_node_data().to_double();
+ }
+ } else if (parser.get_node_name() == "float2") {
+
+ Vector<float> v2 = _read_float_array(parser);
+
+ if (v2.size() >= 2) {
+
+ data = Vector2(v2[0], v2[1]);
+ }
+ } else if (parser.get_node_name() == "float3") {
+
+ Vector<float> v3 = _read_float_array(parser);
+
+ if (v3.size() >= 3) {
+
+ data = Vector3(v3[0], v3[1], v3[2]);
+ }
+ } else if (parser.get_node_name() == "float4") {
+
+ Vector<float> v4 = _read_float_array(parser);
+
+ if (v4.size() >= 4) {
+
+ data = Color(v4[0], v4[1], v4[2], v4[3]);
+ }
+ } else if (parser.get_node_name() == "sampler2D") {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "source") {
+
+ parser.read();
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+
+ data = parser.get_node_data();
+ }
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "sampler2D")
+ break;
+ }
+ } else if (parser.get_node_name() == "surface") {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "init_from") {
+
+ parser.read();
+
+ if (parser.get_node_type() == XMLParser::NODE_TEXT) {
+
+ data = parser.get_node_data();
+ }
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "surface")
+ break;
+ }
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == from)
+ break;
+ }
+
+ COLLADA_PRINT("newparam ending " + parser.get_node_name());
+ return data;
+}
+
+void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &id) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ // first come the tags we descend, but ignore the top-levels
+
+ COLLADA_PRINT("node name: " + parser.get_node_name());
+
+ if (!parser.is_empty() && (parser.get_node_name() == "profile_COMMON" || parser.get_node_name() == "technique" || parser.get_node_name() == "extra")) {
+
+ _parse_effect_material(parser, effect, id); // try again
+
+ } else if (parser.get_node_name() == "newparam") {
+ String name = parser.get_attribute_value("sid");
+ Variant value = _parse_param(parser);
+ effect.params[name] = value;
+ COLLADA_PRINT("param: " + name + " value:" + String(value));
+
+ } else if (parser.get_node_name() == "constant" ||
+ parser.get_node_name() == "lambert" ||
+ parser.get_node_name() == "phong" ||
+ parser.get_node_name() == "blinn") {
+
+ COLLADA_PRINT("shade model: " + parser.get_node_name());
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String what = parser.get_node_name();
+
+ if (what == "emission" ||
+ what == "diffuse" ||
+ what == "specular" ||
+ what == "reflective") {
+
+ // color or texture types
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "color") {
+
+ Vector<float> colorarr = _read_float_array(parser);
+ COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
+
+ if (colorarr.size() >= 3) {
+
+ // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
+ Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
+ if (what == "diffuse")
+ effect.diffuse.color = color;
+ if (what == "specular")
+ effect.specular.color = color;
+ if (what == "emission")
+ effect.emission.color = color;
+
+ COLLADA_PRINT(what + " color: " + color);
+ }
+
+ } else if (parser.get_node_name() == "texture") {
+
+ String sampler = parser.get_attribute_value("texture");
+ if (!effect.params.has(sampler)) {
+ ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
+ } else {
+ String surface = effect.params[sampler];
+
+ if (!effect.params.has(surface)) {
+ ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
+ } else {
+ String uri = effect.params[surface];
+
+ if (what == "diffuse") {
+ effect.diffuse.texture = uri;
+ } else if (what == "specular") {
+ effect.specular.texture = uri;
+ } else if (what == "emission") {
+ effect.emission.texture = uri;
+ } else if (what == "bump") {
+ if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
+ }
+
+ effect.bump.texture = uri;
+ }
+
+ COLLADA_PRINT(what + " texture: " + uri);
+ }
+ }
+ } else if (!parser.is_empty())
+ parser.skip_section();
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == what)
+ break;
+ }
+
+ } else if (what == "shininess") {
+ effect.shininess = _parse_param(parser);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && (parser.get_node_name() == "constant" ||
+ parser.get_node_name() == "lambert" ||
+ parser.get_node_name() == "phong" ||
+ parser.get_node_name() == "blinn"))
+ break;
+ }
+ } else if (parser.get_node_name() == "double_sided" || parser.get_node_name() == "show_double_sided") { // colladamax / google earth
+
+ // 3DS Max / Google Earth double sided extension
+ parser.read();
+ effect.found_double_sided = true;
+ effect.double_sided = parser.get_node_data().to_int();
+ COLLADA_PRINT("double sided: " + itos(parser.get_node_data().to_int()));
+ } else if (parser.get_node_name() == "unshaded") {
+ parser.read();
+ effect.unshaded = parser.get_node_data().to_int();
+ } else if (parser.get_node_name() == "bump") {
+
+ // color or texture types
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "texture") {
+
+ String sampler = parser.get_attribute_value("texture");
+ if (!effect.params.has(sampler)) {
+ ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
+ } else {
+ String surface = effect.params[sampler];
+
+ if (!effect.params.has(surface)) {
+ ERR_PRINT(String("Couldn't find surface: " + surface + " in material:" + id).utf8().get_data());
+ } else {
+ String uri = effect.params[surface];
+
+ if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
+ }
+
+ effect.bump.texture = uri;
+ COLLADA_PRINT(" bump: " + uri);
+ }
+ }
+ } else if (!parser.is_empty())
+ parser.skip_section();
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "bump")
+ break;
+ }
+
+ } else if (!parser.is_empty())
+ parser.skip_section();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END &&
+ (parser.get_node_name() == "effect" ||
+ parser.get_node_name() == "profile_COMMON" ||
+ parser.get_node_name() == "technique" ||
+ parser.get_node_name() == "extra"))
+ break;
+ }
+}
+
+void Collada::_parse_effect(XMLParser &parser) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ String id = parser.get_attribute_value("id");
+
+ Effect effect;
+ if (parser.has_attribute("name"))
+ effect.name = parser.get_attribute_value("name");
+ _parse_effect_material(parser, effect, id);
+
+ state.effect_map[id] = effect;
+
+ COLLADA_PRINT("Effect ID:" + id);
+}
+
+void Collada::_parse_camera(XMLParser &parser) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ String id = parser.get_attribute_value("id");
+
+ state.camera_data_map[id] = CameraData();
+ CameraData &camera = state.camera_data_map[id];
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+
+ if (name == "perspective") {
+
+ camera.mode = CameraData::MODE_PERSPECTIVE;
+ } else if (name == "orthographic") {
+
+ camera.mode = CameraData::MODE_ORTHOGONAL;
+ } else if (name == "xfov") {
+
+ parser.read();
+ camera.perspective.x_fov = parser.get_node_data().to_double();
+
+ } else if (name == "yfov") {
+
+ parser.read();
+ camera.perspective.y_fov = parser.get_node_data().to_double();
+ } else if (name == "xmag") {
+
+ parser.read();
+ camera.orthogonal.x_mag = parser.get_node_data().to_double();
+
+ } else if (name == "ymag") {
+
+ parser.read();
+ camera.orthogonal.y_mag = parser.get_node_data().to_double();
+ } else if (name == "aspect_ratio") {
+
+ parser.read();
+ camera.aspect = parser.get_node_data().to_double();
+
+ } else if (name == "znear") {
+
+ parser.read();
+ camera.z_near = parser.get_node_data().to_double();
+
+ } else if (name == "zfar") {
+
+ parser.read();
+ camera.z_far = parser.get_node_data().to_double();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "camera")
+ break; //end of <asset>
+ }
+
+ COLLADA_PRINT("Camera ID:" + id);
+}
+
+void Collada::_parse_light(XMLParser &parser) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ String id = parser.get_attribute_value("id");
+
+ state.light_data_map[id] = LightData();
+ LightData &light = state.light_data_map[id];
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+
+ if (name == "ambient") {
+
+ light.mode = LightData::MODE_AMBIENT;
+ } else if (name == "directional") {
+
+ light.mode = LightData::MODE_DIRECTIONAL;
+ } else if (name == "point") {
+
+ light.mode = LightData::MODE_OMNI;
+ } else if (name == "spot") {
+
+ light.mode = LightData::MODE_SPOT;
+ } else if (name == "color") {
+
+ parser.read();
+ Vector<float> colorarr = _read_float_array(parser);
+ COLLADA_PRINT("colorarr size: " + rtos(colorarr.size()));
+
+ if (colorarr.size() >= 4) {
+ // alpha strangely not alright? maybe it needs to be multiplied by value as a channel intensity
+ Color color(colorarr[0], colorarr[1], colorarr[2], 1.0);
+ light.color = color;
+ }
+
+ } else if (name == "constant_attenuation") {
+
+ parser.read();
+ light.constant_att = parser.get_node_data().to_double();
+ } else if (name == "linear_attenuation") {
+
+ parser.read();
+ light.linear_att = parser.get_node_data().to_double();
+ } else if (name == "quadratic_attenuation") {
+
+ parser.read();
+ light.quad_att = parser.get_node_data().to_double();
+ } else if (name == "falloff_angle") {
+
+ parser.read();
+ light.spot_angle = parser.get_node_data().to_double();
+
+ } else if (name == "falloff_exponent") {
+
+ parser.read();
+ light.spot_exp = parser.get_node_data().to_double();
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "light")
+ break; //end of <asset>
+ }
+
+ COLLADA_PRINT("Light ID:" + id);
+}
+
+void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_name) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ //load everything into a pre dictionary
+
+ state.curve_data_map[p_id] = CurveData();
+
+ CurveData &curvedata = state.curve_data_map[p_id];
+ curvedata.name = p_name;
+
+ COLLADA_PRINT("curve name: " + p_name);
+
+ String current_source;
+ // handles geometry node and the curve children in this loop
+ // read sources with arrays and accessor for each curve
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "source") {
+
+ String id = parser.get_attribute_value("id");
+ curvedata.sources[id] = CurveData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (curvedata.sources.has(current_source)) {
+
+ curvedata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "Name_array") {
+ // create a new array and read it.
+ if (curvedata.sources.has(current_source)) {
+
+ curvedata.sources[current_source].sarray = _read_string_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(curvedata.sources[current_source].array.size()) + " values.");
+ }
+
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (curvedata.sources.has(current_source)) {
+ curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
+ }
+ } else if (section == "control_vertices") {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "input") {
+
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ curvedata.control_vertices[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
+ break;
+ }
+
+ } else if (!parser.is_empty()) {
+
+ parser.skip_section();
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "spline")
+ break;
+ }
+}
+
+void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name) {
+
+ if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+ return;
+ }
+
+ //load everything into a pre dictionary
+
+ state.mesh_data_map[p_id] = MeshData();
+
+ MeshData &meshdata = state.mesh_data_map[p_id];
+ meshdata.name = p_name;
+
+ COLLADA_PRINT("mesh name: " + p_name);
+
+ String current_source;
+ // handles geometry node and the mesh children in this loop
+ // read sources with arrays and accessor for each mesh
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "source") {
+
+ String id = parser.get_attribute_value("id");
+ meshdata.sources[id] = MeshData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (meshdata.sources.has(current_source)) {
+
+ meshdata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(meshdata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (meshdata.sources.has(current_source)) {
+ meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
+ }
+ } else if (section == "vertices") {
+
+ MeshData::Vertices vert;
+ String id = parser.get_attribute_value("id");
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "input") {
+
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ vert.sources[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
+ break;
+ }
+
+ meshdata.vertices[id] = vert;
+
+ } else if (section == "triangles" || section == "polylist" || section == "polygons") {
+
+ bool polygons = (section == "polygons");
+ if (polygons) {
+ WARN_PRINT("Primitive type \"polygons\" is not well supported (concave shapes may fail). To ensure that the geometry is properly imported, please re-export using \"triangles\" or \"polylist\".");
+ }
+ MeshData::Primitives prim;
+
+ if (parser.has_attribute("material"))
+ prim.material = parser.get_attribute_value("material");
+ prim.count = parser.get_attribute_value("count").to_int();
+ prim.vertex_size = 0;
+ int last_ref = 0;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "input") {
+
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ if (semantic == "TEXCOORD") {
+ /*
+ if (parser.has_attribute("set"))// a texcoord
+ semantic+=parser.get_attribute_value("set");
+ else
+ semantic="TEXCOORD0";*/
+ semantic = "TEXCOORD" + itos(last_ref++);
+ }
+ int offset = parser.get_attribute_value("offset").to_int();
+
+ MeshData::Primitives::SourceRef sref;
+ sref.source = source;
+ sref.offset = offset;
+ prim.sources[semantic] = sref;
+ prim.vertex_size = MAX(prim.vertex_size, offset + 1);
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
+
+ } else if (parser.get_node_name() == "p") { //indices
+
+ Vector<float> values = _read_float_array(parser);
+ if (polygons) {
+
+ ERR_CONTINUE(prim.vertex_size == 0);
+ prim.polygons.push_back(values.size() / prim.vertex_size);
+ int from = prim.indices.size();
+ prim.indices.resize(from + values.size());
+ for (int i = 0; i < values.size(); i++)
+ prim.indices.write[from + i] = values[i];
+
+ } else if (prim.vertex_size > 0) {
+ prim.indices = values;
+ }
+
+ COLLADA_PRINT("read " + itos(values.size()) + " index values");
+
+ } else if (parser.get_node_name() == "vcount") { // primitive
+
+ Vector<float> values = _read_float_array(parser);
+ prim.polygons = values;
+ COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
+ break;
+ }
+
+ meshdata.primitives.push_back(prim);
+
+ } else if (parser.get_node_name() == "double_sided") {
+
+ parser.read();
+ meshdata.found_double_sided = true;
+ meshdata.double_sided = parser.get_node_data().to_int();
+
+ } else if (parser.get_node_name() == "polygons") {
+ ERR_PRINT("Primitive type \"polygons\" not supported, re-export using \"polylist\" or \"triangles\".");
+ } else if (!parser.is_empty()) {
+
+ parser.skip_section();
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "mesh")
+ break;
+ }
+}
+
+void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
+
+ state.skin_controller_data_map[p_id] = SkinControllerData();
+ SkinControllerData &skindata = state.skin_controller_data_map[p_id];
+
+ skindata.base = _uri_to_id(parser.get_attribute_value("source"));
+
+ String current_source;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "bind_shape_matrix") {
+
+ skindata.bind_shape = _read_transform(parser);
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ skindata.bind_shape.origin *= state.unit_scale;
+
+#endif
+ COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
+
+ } else if (section == "source") {
+
+ String id = parser.get_attribute_value("id");
+ skindata.sources[id] = SkinControllerData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (skindata.sources.has(current_source)) {
+
+ skindata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "Name_array" || section == "IDREF_array") {
+ // create a new array and read it.
+
+ if (section == "IDREF_array")
+ skindata.use_idrefs = true;
+ if (skindata.sources.has(current_source)) {
+
+ skindata.sources[current_source].sarray = _read_string_array(parser);
+ if (section == "IDREF_array") {
+ Vector<String> sa = skindata.sources[current_source].sarray;
+ for (int i = 0; i < sa.size(); i++)
+ state.idref_joints.insert(sa[i]);
+ }
+ COLLADA_PRINT("section: " + current_source + " read " + itos(skindata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (skindata.sources.has(current_source)) {
+
+ int stride = 1;
+ if (parser.has_attribute("stride"))
+ stride = parser.get_attribute_value("stride").to_int();
+
+ skindata.sources[current_source].stride = stride;
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(skindata.sources[current_source].stride));
+ }
+
+ } else if (section == "joints") {
+
+ SkinControllerData::Joints joint;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "input") {
+
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ joint.sources[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
+ break;
+ }
+
+ skindata.joints = joint;
+
+ } else if (section == "vertex_weights") {
+
+ SkinControllerData::Weights weights;
+
+ weights.count = parser.get_attribute_value("count").to_int();
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "input") {
+
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ int offset = parser.get_attribute_value("offset").to_int();
+
+ SkinControllerData::Weights::SourceRef sref;
+ sref.source = source;
+ sref.offset = offset;
+ weights.sources[semantic] = sref;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source + " offset: " + itos(offset));
+
+ } else if (parser.get_node_name() == "v") { //indices
+
+ Vector<float> values = _read_float_array(parser);
+ weights.indices = values;
+ COLLADA_PRINT("read " + itos(values.size()) + " index values");
+
+ } else if (parser.get_node_name() == "vcount") { // weightsitive
+
+ Vector<float> values = _read_float_array(parser);
+ weights.sets = values;
+ COLLADA_PRINT("read " + itos(values.size()) + " polygon values");
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
+ break;
+ }
+
+ skindata.weights = weights;
+ }
+ /*
+ else if (!parser.is_empty())
+ parser.skip_section();
+ */
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "skin")
+ break;
+ }
+
+ /* STORE REST MATRICES */
+
+ Vector<Transform> rests;
+ ERR_FAIL_COND(!skindata.joints.sources.has("JOINT"));
+ ERR_FAIL_COND(!skindata.joints.sources.has("INV_BIND_MATRIX"));
+
+ String joint_arr = skindata.joints.sources["JOINT"];
+ String ibm = skindata.joints.sources["INV_BIND_MATRIX"];
+
+ ERR_FAIL_COND(!skindata.sources.has(joint_arr));
+ ERR_FAIL_COND(!skindata.sources.has(ibm));
+
+ SkinControllerData::Source &joint_source = skindata.sources[joint_arr];
+ SkinControllerData::Source &ibm_source = skindata.sources[ibm];
+
+ ERR_FAIL_COND(joint_source.sarray.size() != ibm_source.array.size() / 16);
+
+ for (int i = 0; i < joint_source.sarray.size(); i++) {
+
+ String name = joint_source.sarray[i];
+ Transform xform = _read_transform_from_array(ibm_source.array, i * 16); //<- this is a mistake, it must be applied to vertices
+ xform.affine_invert(); // inverse for rest, because it's an inverse
+#ifdef COLLADA_IMPORT_SCALE_SCENE
+ xform.origin *= state.unit_scale;
+#endif
+ skindata.bone_rest_map[name] = xform;
+ }
+}
+
+void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
+
+ state.morph_controller_data_map[p_id] = MorphControllerData();
+ MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
+
+ morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
+ morphdata.mode = parser.get_attribute_value("method");
+ String current_source;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "source") {
+
+ String id = parser.get_attribute_value("id");
+ morphdata.sources[id] = MorphControllerData::Source();
+ current_source = id;
+ COLLADA_PRINT("source data: " + id);
+
+ } else if (section == "float_array" || section == "array") {
+ // create a new array and read it.
+ if (morphdata.sources.has(current_source)) {
+
+ morphdata.sources[current_source].array = _read_float_array(parser);
+ COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "Name_array" || section == "IDREF_array") {
+ // create a new array and read it.
+
+ /*
+ if (section=="IDREF_array")
+ morphdata.use_idrefs=true;
+ */
+ if (morphdata.sources.has(current_source)) {
+
+ morphdata.sources[current_source].sarray = _read_string_array(parser);
+ /*
+ if (section=="IDREF_array") {
+ Vector<String> sa = morphdata.sources[current_source].sarray;
+ for(int i=0;i<sa.size();i++)
+ state.idref_joints.insert(sa[i]);
+ }*/
+ COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values.");
+ }
+ } else if (section == "technique_common") {
+ //skip it
+ } else if (section == "accessor") { // child of source (below a technique tag)
+
+ if (morphdata.sources.has(current_source)) {
+
+ int stride = 1;
+ if (parser.has_attribute("stride"))
+ stride = parser.get_attribute_value("stride").to_int();
+
+ morphdata.sources[current_source].stride = stride;
+ COLLADA_PRINT("section: " + current_source + " stride " + itos(morphdata.sources[current_source].stride));
+ }
+
+ } else if (section == "targets") {
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "input") {
+
+ String semantic = parser.get_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_attribute_value("source"));
+
+ morphdata.targets[semantic] = source;
+
+ COLLADA_PRINT(section + " input semantic: " + semantic + " source: " + source);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == section)
+ break;
+ }
+ }
+ /*
+ else if (!parser.is_empty())
+ parser.skip_section();
+ */
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "morph")
+ break;
+ }
+
+ if (morphdata.targets.has("MORPH_WEIGHT")) {
+
+ state.morph_name_map[morphdata.targets["MORPH_WEIGHT"]] = p_id;
+ }
+}
+
+void Collada::_parse_controller(XMLParser &parser) {
+
+ String id = parser.get_attribute_value("id");
+
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "skin") {
+ _parse_skin_controller(parser, id);
+ } else if (section == "morph") {
+ _parse_morph_controller(parser, id);
+ }
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "controller")
+ break;
+ }
+}
+
+Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
+
+ String type = parser.get_node_name();
+ NodeGeometry *geom = memnew(NodeGeometry);
+ geom->controller = type == "instance_controller";
+ geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
+
+ if (parser.is_empty()) //nothing else to parse...
+ return geom;
+ // try to find also many materials and skeletons!
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "instance_material") {
+
+ String symbol = parser.get_attribute_value("symbol");
+ String target = _uri_to_id(parser.get_attribute_value("target"));
+
+ NodeGeometry::Material mat;
+ mat.target = target;
+ geom->material_map[symbol] = mat;
+ COLLADA_PRINT("uses material: '" + target + "' on primitive'" + symbol + "'");
+ } else if (parser.get_node_name() == "skeleton") {
+
+ parser.read();
+ String uri = _uri_to_id(parser.get_node_data());
+ if (uri != "") {
+ geom->skeletons.push_back(uri);
+ }
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == type)
+ break;
+ }
+
+ if (geom->controller) {
+
+ if (geom->skeletons.empty()) {
+ //XSI style
+
+ if (state.skin_controller_data_map.has(geom->source)) {
+ SkinControllerData *skin = &state.skin_controller_data_map[geom->source];
+ //case where skeletons reference bones with IDREF (XSI)
+ ERR_FAIL_COND_V(!skin->joints.sources.has("JOINT"), geom);
+ String joint_arr = skin->joints.sources["JOINT"];
+ ERR_FAIL_COND_V(!skin->sources.has(joint_arr), geom);
+ Collada::SkinControllerData::Source &joint_source = skin->sources[joint_arr];
+ geom->skeletons = joint_source.sarray; //quite crazy, but should work.
+ }
+ }
+ }
+
+ return geom;
+}
+
+Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
+
+ NodeCamera *cam = memnew(NodeCamera);
+ cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
+
+ if (state.up_axis == Vector3::AXIS_Z) //collada weirdness
+ cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
+
+ if (parser.is_empty()) //nothing else to parse...
+ return cam;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_camera")
+ break;
+ }
+
+ return cam;
+}
+
+Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
+
+ NodeLight *cam = memnew(NodeLight);
+ cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
+
+ if (state.up_axis == Vector3::AXIS_Z) //collada weirdness
+ cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
+
+ if (parser.is_empty()) //nothing else to parse...
+ return cam;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "instance_light")
+ break;
+ }
+
+ return cam;
+}
+
+Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
+
+ String instance_type = parser.get_node_name();
+
+ if (instance_type == "instance_geometry" || instance_type == "instance_controller") {
+ return _parse_visual_instance_geometry(parser);
+ } else if (instance_type == "instance_camera") {
+
+ return _parse_visual_instance_camera(parser);
+ } else if (instance_type == "instance_light") {
+ return _parse_visual_instance_light(parser);
+ }
+
+ if (parser.is_empty()) //nothing else to parse...
+ return nullptr;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == instance_type)
+ break;
+ }
+
+ return nullptr;
+}
+
+Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
+
+ String name;
+
+ String id = parser.get_attribute_value_safe("id");
+
+ bool found_name = false;
+
+ if (id == "") {
+
+ id = "%NODEID%" + itos(Math::rand());
+
+ } else {
+ found_name = true;
+ }
+
+ Vector<Node::XForm> xform_list;
+ Vector<Node *> children;
+
+ String empty_draw_type = "";
+
+ Node *node = nullptr;
+
+ name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
+ if (name == "") {
+
+ name = id;
+ } else {
+ found_name = true;
+ }
+
+ if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
+ // handle a bone
+
+ NodeJoint *joint = memnew(NodeJoint);
+
+ if (parser.has_attribute("sid")) { //bones may not have sid
+ joint->sid = parser.get_attribute_value("sid");
+ //state.bone_map[joint->sid]=joint;
+ } else if (state.idref_joints.has(name)) {
+ joint->sid = name; //kind of a cheat but..
+ } else if (parser.has_attribute("name")) {
+ joint->sid = parser.get_attribute_value_safe("name");
+ }
+
+ if (joint->sid != "") {
+ state.sid_to_node_map[joint->sid] = id;
+ }
+
+ node = joint;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "translate") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_TRANSLATE;
+
+ Vector<float> xlt = _read_float_array(parser);
+ xf.data = xlt;
+ xform_list.push_back(xf);
+
+ } else if (section == "rotate") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_ROTATE;
+
+ Vector<float> rot = _read_float_array(parser);
+ xf.data = rot;
+
+ xform_list.push_back(xf);
+
+ } else if (section == "scale") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+
+ xf.op = Node::XForm::OP_SCALE;
+
+ Vector<float> scale = _read_float_array(parser);
+
+ xf.data = scale;
+
+ xform_list.push_back(xf);
+
+ } else if (section == "matrix") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_MATRIX;
+
+ Vector<float> matrix = _read_float_array(parser);
+
+ xf.data = matrix;
+ String mtx;
+ for (int i = 0; i < matrix.size(); i++)
+ mtx += " " + rtos(matrix[i]);
+
+ xform_list.push_back(xf);
+
+ } else if (section == "visibility") {
+ Node::XForm xf;
+ if (parser.has_attribute("sid")) {
+ xf.id = parser.get_attribute_value("sid");
+ }
+ xf.op = Node::XForm::OP_VISIBILITY;
+
+ Vector<float> visible = _read_float_array(parser);
+
+ xf.data = visible;
+
+ xform_list.push_back(xf);
+
+ } else if (section == "empty_draw_type") {
+ empty_draw_type = _read_empty_draw_type(parser);
+ } else if (section == "technique" || section == "extra") {
+
+ } else if (section != "node") {
+ //usually what defines the type of node
+ if (section.begins_with("instance_")) {
+
+ if (!node) {
+
+ node = _parse_visual_node_instance_data(parser);
+
+ } else {
+ ERR_PRINT("Multiple instance_* not supported.");
+ }
+ }
+
+ } else {
+
+ /* Found a child node!! what to do..*/
+
+ Node *child = _parse_visual_scene_node(parser);
+ children.push_back(child);
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "node")
+ break;
+ }
+
+ if (!node) {
+
+ node = memnew(Node); //generic node, nothing of relevance found
+ }
+
+ node->noname = !found_name;
+ node->xform_list = xform_list;
+ node->children = children;
+ for (int i = 0; i < children.size(); i++) {
+ node->children[i]->parent = node;
+ }
+
+ node->name = name;
+ node->id = id;
+ node->empty_draw_type = empty_draw_type;
+
+ if (node->children.size() == 1) {
+ if (node->children[0]->noname && !node->noname) {
+ node->children[0]->name = node->name;
+ node->name = node->name + "-base";
+ }
+ }
+
+ node->default_transform = node->compute_transform(*this);
+ state.scene_map[id] = node;
+
+ return node;
+}
+
+void Collada::_parse_visual_scene(XMLParser &parser) {
+
+ String id = parser.get_attribute_value("id");
+
+ if (parser.is_empty()) {
+ return;
+ }
+
+ state.visual_scene_map[id] = VisualScene();
+ VisualScene &vscene = state.visual_scene_map[id];
+
+ if (parser.has_attribute("name"))
+ vscene.name = parser.get_attribute_value("name");
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String section = parser.get_node_name();
+
+ if (section == "node") {
+ vscene.root_nodes.push_back(_parse_visual_scene_node(parser));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "visual_scene")
+ break;
+ }
+
+ COLLADA_PRINT("Scene ID:" + id);
+}
+
+void Collada::_parse_animation(XMLParser &parser) {
+
+ if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+
+ return;
+ }
+
+ Map<String, Vector<float>> float_sources;
+ Map<String, Vector<String>> string_sources;
+ Map<String, int> source_strides;
+ Map<String, Map<String, String>> samplers;
+ Map<String, Vector<String>> source_param_names;
+ Map<String, Vector<String>> source_param_types;
+
+ String id = "";
+ if (parser.has_attribute("id"))
+ id = parser.get_attribute_value("id");
+
+ String current_source;
+ String current_sampler;
+ Vector<String> channel_sources;
+ Vector<String> channel_targets;
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+ if (name == "source") {
+
+ current_source = parser.get_attribute_value("id");
+ source_param_names[current_source] = Vector<String>();
+ source_param_types[current_source] = Vector<String>();
+
+ } else if (name == "float_array") {
+
+ if (current_source != "") {
+ float_sources[current_source] = _read_float_array(parser);
+ }
+
+ } else if (name == "Name_array") {
+
+ if (current_source != "") {
+ string_sources[current_source] = _read_string_array(parser);
+ }
+ } else if (name == "accessor") {
+
+ if (current_source != "" && parser.has_attribute("stride")) {
+ source_strides[current_source] = parser.get_attribute_value("stride").to_int();
+ }
+ } else if (name == "sampler") {
+
+ current_sampler = parser.get_attribute_value("id");
+ samplers[current_sampler] = Map<String, String>();
+ } else if (name == "param") {
+
+ if (parser.has_attribute("name"))
+ source_param_names[current_source].push_back(parser.get_attribute_value("name"));
+ else
+ source_param_names[current_source].push_back("");
+
+ if (parser.has_attribute("type"))
+ source_param_types[current_source].push_back(parser.get_attribute_value("type"));
+ else
+ source_param_types[current_source].push_back("");
+
+ } else if (name == "input") {
+
+ if (current_sampler != "") {
+
+ samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
+ }
+
+ } else if (name == "channel") {
+
+ channel_sources.push_back(parser.get_attribute_value("source"));
+ channel_targets.push_back(parser.get_attribute_value("target"));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation")
+ break; //end of <asset>
+ }
+
+ for (int i = 0; i < channel_sources.size(); i++) {
+
+ String source = _uri_to_id(channel_sources[i]);
+ String target = channel_targets[i];
+ ERR_CONTINUE(!samplers.has(source));
+ Map<String, String> &sampler = samplers[source];
+
+ ERR_CONTINUE(!sampler.has("INPUT")); //no input semantic? wtf?
+ String input_id = _uri_to_id(sampler["INPUT"]);
+ COLLADA_PRINT("input id is " + input_id);
+ ERR_CONTINUE(!float_sources.has(input_id));
+
+ ERR_CONTINUE(!sampler.has("OUTPUT"));
+ String output_id = _uri_to_id(sampler["OUTPUT"]);
+ ERR_CONTINUE(!float_sources.has(output_id));
+
+ ERR_CONTINUE(!source_param_names.has(output_id));
+
+ Vector<String> &names = source_param_names[output_id];
+
+ for (int l = 0; l < names.size(); l++) {
+
+ String name = names[l];
+
+ Vector<float> &time_keys = float_sources[input_id];
+ int key_count = time_keys.size();
+
+ AnimationTrack track; //begin crating track
+ track.id = id;
+
+ track.keys.resize(key_count);
+
+ for (int j = 0; j < key_count; j++) {
+ track.keys.write[j].time = time_keys[j];
+ state.animation_length = MAX(state.animation_length, time_keys[j]);
+ }
+
+ //now read actual values
+
+ int stride = 1;
+
+ if (source_strides.has(output_id))
+ stride = source_strides[output_id];
+ int output_len = stride / names.size();
+
+ ERR_CONTINUE(output_len == 0);
+ ERR_CONTINUE(!float_sources.has(output_id));
+
+ Vector<float> &output = float_sources[output_id];
+
+ ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output.");
+
+ for (int j = 0; j < key_count; j++) {
+ track.keys.write[j].data.resize(output_len);
+ for (int k = 0; k < output_len; k++)
+ track.keys.write[j].data.write[k] = output[l + j * stride + k]; //super weird but should work:
+ }
+
+ if (sampler.has("INTERPOLATION")) {
+
+ String interp_id = _uri_to_id(sampler["INTERPOLATION"]);
+ ERR_CONTINUE(!string_sources.has(interp_id));
+ Vector<String> &interps = string_sources[interp_id];
+ ERR_CONTINUE(interps.size() != key_count);
+
+ for (int j = 0; j < key_count; j++) {
+ if (interps[j] == "BEZIER")
+ track.keys.write[j].interp_type = AnimationTrack::INTERP_BEZIER;
+ else
+ track.keys.write[j].interp_type = AnimationTrack::INTERP_LINEAR;
+ }
+ }
+
+ if (sampler.has("IN_TANGENT") && sampler.has("OUT_TANGENT")) {
+ //bezier control points..
+ String intangent_id = _uri_to_id(sampler["IN_TANGENT"]);
+ ERR_CONTINUE(!float_sources.has(intangent_id));
+ Vector<float> &intangents = float_sources[intangent_id];
+
+ ERR_CONTINUE(intangents.size() != key_count * 2 * names.size());
+
+ String outangent_id = _uri_to_id(sampler["OUT_TANGENT"]);
+ ERR_CONTINUE(!float_sources.has(outangent_id));
+ Vector<float> &outangents = float_sources[outangent_id];
+ ERR_CONTINUE(outangents.size() != key_count * 2 * names.size());
+
+ for (int j = 0; j < key_count; j++) {
+ track.keys.write[j].in_tangent = Vector2(intangents[j * 2 * names.size() + 0 + l * 2], intangents[j * 2 * names.size() + 1 + l * 2]);
+ track.keys.write[j].out_tangent = Vector2(outangents[j * 2 * names.size() + 0 + l * 2], outangents[j * 2 * names.size() + 1 + l * 2]);
+ }
+ }
+
+ if (target.find("/") != -1) { //transform component
+ track.target = target.get_slicec('/', 0);
+ track.param = target.get_slicec('/', 1);
+ if (track.param.find(".") != -1)
+ track.component = track.param.get_slice(".", 1).to_upper();
+ track.param = track.param.get_slice(".", 0);
+ if (names.size() > 1 && track.component == "") {
+ //this is a guess because the collada spec is ambiguous here...
+ //i suppose if you have many names (outputs) you can't use a component and i should abide to that.
+ track.component = name;
+ }
+ } else {
+ track.target = target;
+ }
+
+ state.animation_tracks.push_back(track);
+
+ if (!state.referenced_tracks.has(target))
+ state.referenced_tracks[target] = Vector<int>();
+
+ state.referenced_tracks[target].push_back(state.animation_tracks.size() - 1);
+
+ if (id != "") {
+ if (!state.by_id_tracks.has(id))
+ state.by_id_tracks[id] = Vector<int>();
+
+ state.by_id_tracks[id].push_back(state.animation_tracks.size() - 1);
+ }
+
+ COLLADA_PRINT("loaded animation with " + itos(key_count) + " keys");
+ }
+ }
+}
+
+void Collada::_parse_animation_clip(XMLParser &parser) {
+
+ if (!(state.import_flags & IMPORT_FLAG_ANIMATION)) {
+ if (!parser.is_empty())
+ parser.skip_section();
+
+ return;
+ }
+
+ AnimationClip clip;
+
+ if (parser.has_attribute("name"))
+ clip.name = parser.get_attribute_value("name");
+ else if (parser.has_attribute("id"))
+ clip.name = parser.get_attribute_value("id");
+ if (parser.has_attribute("start"))
+ clip.begin = parser.get_attribute_value("start").to_double();
+ if (parser.has_attribute("end"))
+ clip.end = parser.get_attribute_value("end").to_double();
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+ if (name == "instance_animation") {
+
+ String url = _uri_to_id(parser.get_attribute_value("url"));
+ clip.tracks.push_back(url);
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation_clip")
+ break; //end of <asset>
+ }
+
+ state.animation_clips.push_back(clip);
+}
+
+void Collada::_parse_scene(XMLParser &parser) {
+
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+
+ if (name == "instance_visual_scene") {
+
+ state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
+ } else if (name == "instance_physics_scene") {
+
+ state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
+ }
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene")
+ break; //end of <asset>
+ }
+}
+
+void Collada::_parse_library(XMLParser &parser) {
+
+ if (parser.is_empty()) {
+ return;
+ }
+
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ String name = parser.get_node_name();
+ COLLADA_PRINT("library name is: " + name);
+ if (name == "image") {
+
+ _parse_image(parser);
+ } else if (name == "material") {
+
+ _parse_material(parser);
+ } else if (name == "effect") {
+
+ _parse_effect(parser);
+ } else if (name == "camera") {
+
+ _parse_camera(parser);
+ } else if (name == "light") {
+
+ _parse_light(parser);
+ } else if (name == "geometry") {
+
+ String id = parser.get_attribute_value("id");
+ String name2 = parser.get_attribute_value_safe("name");
+ while (parser.read() == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "mesh") {
+ state.mesh_name_map[id] = (name2 != "") ? name2 : id;
+ _parse_mesh_geometry(parser, id, name2);
+ } else if (parser.get_node_name() == "spline") {
+ state.mesh_name_map[id] = (name2 != "") ? name2 : id;
+ _parse_curve_geometry(parser, id, name2);
+ } else if (!parser.is_empty())
+ parser.skip_section();
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "geometry")
+ break;
+ }
+
+ } else if (name == "controller") {
+
+ _parse_controller(parser);
+ } else if (name == "animation") {
+
+ _parse_animation(parser);
+ } else if (name == "animation_clip") {
+
+ _parse_animation_clip(parser);
+ } else if (name == "visual_scene") {
+
+ COLLADA_PRINT("visual scene");
+ _parse_visual_scene(parser);
+ } else if (!parser.is_empty())
+ parser.skip_section();
+
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name().begins_with("library_"))
+ break; //end of <asset>
+ }
+}
+
+void Collada::_joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner) {
+
+ if (p_node->type == Node::TYPE_JOINT) {
+
+ NodeJoint *nj = static_cast<NodeJoint *>(p_node);
+ nj->owner = p_owner;
+
+ for (int i = 0; i < nj->children.size(); i++) {
+
+ _joint_set_owner(nj->children.write[i], p_owner);
+ }
+ }
+}
+
+void Collada::_create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton) {
+
+ Node *node = *p_node;
+
+ if (node->type == Node::TYPE_JOINT) {
+
+ if (!p_skeleton) {
+
+ // ohohohoohoo it's a joint node, time to work!
+ NodeSkeleton *sk = memnew(NodeSkeleton);
+ *p_node = sk;
+ sk->children.push_back(node);
+ sk->parent = node->parent;
+ node->parent = sk;
+ p_skeleton = sk;
+ }
+
+ NodeJoint *nj = static_cast<NodeJoint *>(node);
+ nj->owner = p_skeleton;
+ } else {
+ p_skeleton = nullptr;
+ }
+
+ for (int i = 0; i < node->children.size(); i++) {
+ _create_skeletons(&node->children.write[i], p_skeleton);
+ }
+}
+
+bool Collada::_remove_node(Node *p_parent, Node *p_node) {
+
+ for (int i = 0; i < p_parent->children.size(); i++) {
+
+ if (p_parent->children[i] == p_node) {
+ p_parent->children.remove(i);
+ return true;
+ }
+ if (_remove_node(p_parent->children[i], p_node))
+ return true;
+ }
+
+ return false;
+}
+
+void Collada::_remove_node(VisualScene *p_vscene, Node *p_node) {
+
+ for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
+ if (p_vscene->root_nodes[i] == p_node) {
+
+ p_vscene->root_nodes.remove(i);
+ return;
+ }
+ if (_remove_node(p_vscene->root_nodes[i], p_node))
+ return;
+ }
+
+ ERR_PRINT("ERROR: Not found node to remove?");
+}
+
+void Collada::_merge_skeletons(VisualScene *p_vscene, Node *p_node) {
+
+ if (p_node->type == Node::TYPE_GEOMETRY) {
+
+ NodeGeometry *gnode = static_cast<NodeGeometry *>(p_node);
+ if (gnode->controller) {
+
+ // recount skeletons used
+ Set<NodeSkeleton *> skeletons;
+
+ for (int i = 0; i < gnode->skeletons.size(); i++) {
+
+ String nodeid = gnode->skeletons[i];
+
+ ERR_CONTINUE(!state.scene_map.has(nodeid)); //weird, it should have it...
+
+#ifdef NO_SAFE_CAST
+ NodeJoint *nj = static_cast<NodeJoint *>(state.scene_map[nodeid]);
+#else
+ NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
+#endif
+ ERR_CONTINUE(!nj); //broken collada
+ ERR_CONTINUE(!nj->owner); //weird, node should have a skeleton owner
+
+ skeletons.insert(nj->owner);
+ }
+
+ if (skeletons.size() > 1) {
+
+ //do the merger!!
+ Set<NodeSkeleton *>::Element *E = skeletons.front();
+ NodeSkeleton *base = E->get();
+
+ for (E = E->next(); E; E = E->next()) {
+
+ NodeSkeleton *merged = E->get();
+ _remove_node(p_vscene, merged);
+ for (int i = 0; i < merged->children.size(); i++) {
+
+ _joint_set_owner(merged->children[i], base);
+ base->children.push_back(merged->children[i]);
+ merged->children[i]->parent = base;
+ }
+
+ merged->children.clear(); //take children from it
+ memdelete(merged);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->children.size(); i++) {
+ _merge_skeletons(p_vscene, p_node->children[i]);
+ }
+}
+
+void Collada::_merge_skeletons2(VisualScene *p_vscene) {
+
+ for (Map<String, SkinControllerData>::Element *E = state.skin_controller_data_map.front(); E; E = E->next()) {
+
+ SkinControllerData &cd = E->get();
+
+ NodeSkeleton *skeleton = nullptr;
+
+ for (Map<String, Transform>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) {
+
+ String name;
+
+ if (!state.sid_to_node_map.has(F->key())) {
+ continue;
+ }
+
+ name = state.sid_to_node_map[F->key()];
+
+ ERR_CONTINUE(!state.scene_map.has(name));
+
+ Node *node = state.scene_map[name];
+ ERR_CONTINUE(node->type != Node::TYPE_JOINT);
+
+ NodeSkeleton *sk = nullptr;
+
+ while (node && !sk) {
+
+ if (node->type == Node::TYPE_SKELETON) {
+ sk = static_cast<NodeSkeleton *>(node);
+ }
+ node = node->parent;
+ }
+
+ ERR_CONTINUE(!sk);
+
+ if (!skeleton) {
+ skeleton = sk;
+ continue;
+ }
+
+ if (skeleton != sk) {
+ //whoa.. wtf, merge.
+ _remove_node(p_vscene, sk);
+ for (int i = 0; i < sk->children.size(); i++) {
+
+ _joint_set_owner(sk->children[i], skeleton);
+ skeleton->children.push_back(sk->children[i]);
+ sk->children[i]->parent = skeleton;
+ }
+
+ sk->children.clear(); //take children from it
+ memdelete(sk);
+ }
+ }
+ }
+}
+
+bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) {
+
+ Node *node = p_node;
+
+ if (node->type == Node::TYPE_SKELETON && node->parent && node->parent->type == Node::TYPE_NODE && node->parent->children.size() == 1) {
+ //replace parent by this...
+ Node *parent = node->parent;
+
+ //i wonder if this is alright.. i think it is since created skeleton (first joint) is already animated by bone..
+ node->id = parent->id;
+ node->name = parent->name;
+ node->xform_list = parent->xform_list;
+ node->default_transform = parent->default_transform;
+
+ state.scene_map[node->id] = node;
+ node->parent = parent->parent;
+
+ if (parent->parent) {
+ Node *gp = parent->parent;
+ bool found = false;
+ for (int i = 0; i < gp->children.size(); i++) {
+
+ if (gp->children[i] == parent) {
+ gp->children.write[i] = node;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERR_PRINT("BUG");
+ }
+ } else {
+
+ bool found = false;
+
+ for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
+
+ if (p_vscene->root_nodes[i] == parent) {
+
+ p_vscene->root_nodes.write[i] = node;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERR_PRINT("BUG");
+ }
+ }
+
+ parent->children.clear();
+ memdelete(parent);
+ return true;
+ }
+
+ for (int i = 0; i < node->children.size(); i++) {
+
+ if (_optimize_skeletons(p_vscene, node->children[i]))
+ return false; //stop processing, go up
+ }
+
+ return false;
+}
+
+bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom) {
+
+ // Bind Shape Matrix scales the bones and makes them gigantic, so the matrix then shrinks the model?
+ // Solution: apply the Bind Shape Matrix to the VERTICES, and if the object comes scaled, it seems to be left alone!
+
+ if (p_node->type == Node::TYPE_GEOMETRY) {
+
+ NodeGeometry *ng = static_cast<NodeGeometry *>(p_node);
+ if (ng->ignore_anim)
+ return false; //already made child of skeleton and processeg
+
+ if (ng->controller && ng->skeletons.size()) {
+
+ String nodeid = ng->skeletons[0];
+
+ ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
+#ifdef NO_SAFE_CAST
+ NodeJoint *nj = static_cast<NodeJoint *>(state.scene_map[nodeid]);
+#else
+ NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
+#endif
+ ERR_FAIL_COND_V(!nj, false);
+ ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
+
+ NodeSkeleton *sk = nj->owner;
+
+ Node *p = sk->parent;
+ bool node_is_parent_of_skeleton = false;
+
+ while (p) {
+ if (p == p_node) {
+ node_is_parent_of_skeleton = true;
+ break;
+ }
+ p = p->parent; // try again
+ }
+
+ ERR_FAIL_COND_V(node_is_parent_of_skeleton, false);
+
+ //this should be correct
+ ERR_FAIL_COND_V(!state.skin_controller_data_map.has(ng->source), false);
+ SkinControllerData &skin = state.skin_controller_data_map[ng->source];
+ Transform skel_inv = sk->get_global_transform().affine_inverse();
+ p_node->default_transform = skel_inv * (skin.bind_shape /* p_node->get_global_transform()*/); // i honestly have no idea what to do with a previous model xform.. most exporters ignore it
+
+ //make rests relative to the skeleton (they seem to be always relative to world)
+ for (Map<String, Transform>::Element *E = skin.bone_rest_map.front(); E; E = E->next()) {
+
+ E->get() = skel_inv * E->get(); //make the bone rest local to the skeleton
+ state.bone_rest_map[E->key()] = E->get(); // make it remember where the bone is globally, now that it's relative
+ }
+
+ //but most exporters seem to work only if i do this..
+ //p_node->default_transform = p_node->get_global_transform();
+
+ //p_node->default_transform=Transform(); //this seems to be correct, because bind shape makes the object local to the skeleton
+ p_node->ignore_anim = true; // collada may animate this later, if it does, then this is not supported (redo your original asset and don't animate the base mesh)
+ p_node->parent = sk;
+ //sk->children.push_back(0,p_node); //avoid INFINITE loop
+ p_mgeom->push_back(p_node);
+ return true;
+ }
+ }
+
+ for (int i = 0; i < p_node->children.size(); i++) {
+
+ if (_move_geometry_to_skeletons(p_vscene, p_node->children[i], p_mgeom)) {
+ p_node->children.remove(i);
+ i--;
+ }
+ }
+
+ return false;
+}
+
+void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) {
+
+ if (p_node->type == Node::TYPE_GEOMETRY) {
+
+ NodeGeometry *nj = static_cast<NodeGeometry *>(p_node);
+
+ if (nj->controller) {
+
+ String base = nj->source;
+
+ while (base != "" && !state.mesh_data_map.has(base)) {
+
+ if (state.skin_controller_data_map.has(base)) {
+
+ SkinControllerData &sk = state.skin_controller_data_map[base];
+ base = sk.base;
+ } else if (state.morph_controller_data_map.has(base)) {
+
+ state.morph_ownership_map[base] = nj->id;
+ break;
+ } else {
+ ERR_FAIL_MSG("Invalid scene.");
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < p_node->children.size(); i++) {
+
+ _find_morph_nodes(p_vscene, p_node->children[i]);
+ }
+}
+
+void Collada::_optimize() {
+
+ for (Map<String, VisualScene>::Element *E = state.visual_scene_map.front(); E; E = E->next()) {
+
+ VisualScene &vs = E->get();
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _create_skeletons(&vs.root_nodes.write[i]);
+ }
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _merge_skeletons(&vs, vs.root_nodes[i]);
+ }
+
+ _merge_skeletons2(&vs);
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _optimize_skeletons(&vs, vs.root_nodes[i]);
+ }
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+
+ List<Node *> mgeom;
+ if (_move_geometry_to_skeletons(&vs, vs.root_nodes[i], &mgeom)) {
+ vs.root_nodes.remove(i);
+ i--;
+ }
+
+ while (!mgeom.empty()) {
+
+ Node *n = mgeom.front()->get();
+ n->parent->children.push_back(n);
+ mgeom.pop_front();
+ }
+ }
+
+ for (int i = 0; i < vs.root_nodes.size(); i++) {
+ _find_morph_nodes(&vs, vs.root_nodes[i]);
+ }
+ }
+}
+
+int Collada::get_uv_channel(String p_name) {
+
+ if (!channel_map.has(p_name)) {
+
+ ERR_FAIL_COND_V(channel_map.size() == 2, 0);
+
+ channel_map[p_name] = channel_map.size();
+ }
+
+ return channel_map[p_name];
+}
+
+Error Collada::load(const String &p_path, int p_flags) {
+
+ Ref<XMLParser> parserr = memnew(XMLParser);
+ XMLParser &parser = *parserr.ptr();
+ Error err = parser.open(p_path);
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot open Collada file '" + p_path + "'.");
+
+ state.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
+ state.import_flags = p_flags;
+ /* Skip headers */
+ while ((err = parser.read()) == OK) {
+
+ if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
+
+ if (parser.get_node_name() == "COLLADA") {
+ break;
+ } else if (!parser.is_empty())
+ parser.skip_section(); // unknown section, likely headers
+ }
+ }
+
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CORRUPT, "Corrupted Collada file '" + p_path + "'.");
+
+ /* Start loading Collada */
+
+ {
+ //version
+ String version = parser.get_attribute_value("version");
+ state.version.major = version.get_slice(".", 0).to_int();
+ state.version.minor = version.get_slice(".", 1).to_int();
+ state.version.rev = version.get_slice(".", 2).to_int();
+ COLLADA_PRINT("Collada VERSION: " + version);
+ }
+
+ while ((err = parser.read()) == OK) {
+
+ /* Read all the main sections.. */
+
+ if (parser.get_node_type() != XMLParser::NODE_ELEMENT)
+ continue; //no idea what this may be, but skipping anyway
+
+ String section = parser.get_node_name();
+
+ COLLADA_PRINT("section: " + section);
+
+ if (section == "asset") {
+ _parse_asset(parser);
+
+ } else if (section.begins_with("library_")) {
+
+ _parse_library(parser);
+ } else if (section == "scene") {
+
+ _parse_scene(parser);
+ } else if (!parser.is_empty()) {
+ parser.skip_section(); // unknown section, likely headers
+ }
+ }
+
+ _optimize();
+ return OK;
+}
+
+Collada::Collada() {
+}
diff --git a/editor/import/collada.h b/editor/import/collada.h
new file mode 100644
index 0000000000..b74332fb22
--- /dev/null
+++ b/editor/import/collada.h
@@ -0,0 +1,647 @@
+/*************************************************************************/
+/* collada.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLADA_H
+#define COLLADA_H
+
+#include "core/io/xml_parser.h"
+#include "core/map.h"
+#include "core/project_settings.h"
+#include "scene/resources/material.h"
+
+class Collada {
+public:
+ enum ImportFlags {
+ IMPORT_FLAG_SCENE = 1,
+ IMPORT_FLAG_ANIMATION = 2
+ };
+
+ struct Image {
+
+ String path;
+ };
+
+ struct Material {
+
+ String name;
+ String instance_effect;
+ };
+
+ struct Effect {
+
+ String name;
+ Map<String, Variant> params;
+
+ struct Channel {
+
+ int uv_idx;
+ String texture;
+ Color color;
+ Channel() { uv_idx = 0; }
+ };
+
+ Channel diffuse, specular, emission, bump;
+ float shininess;
+ bool found_double_sided;
+ bool double_sided;
+ bool unshaded;
+
+ String get_texture_path(const String &p_source, Collada &state) const;
+
+ Effect() {
+ diffuse.color = Color(1, 1, 1, 1);
+ double_sided = true;
+ found_double_sided = false;
+ shininess = 40;
+ unshaded = false;
+ }
+ };
+
+ struct CameraData {
+
+ enum Mode {
+ MODE_PERSPECTIVE,
+ MODE_ORTHOGONAL
+ };
+
+ Mode mode;
+
+ union {
+ struct {
+ float x_fov;
+ float y_fov;
+ } perspective;
+ struct {
+ float x_mag;
+ float y_mag;
+ } orthogonal;
+ };
+
+ float aspect;
+ float z_near;
+ float z_far;
+
+ CameraData() :
+ mode(MODE_PERSPECTIVE),
+ aspect(1),
+ z_near(0.1),
+ z_far(100) {
+ perspective.x_fov = 0;
+ perspective.y_fov = 0;
+ }
+ };
+
+ struct LightData {
+
+ enum Mode {
+ MODE_AMBIENT,
+ MODE_DIRECTIONAL,
+ MODE_OMNI,
+ MODE_SPOT
+ };
+
+ Mode mode;
+
+ Color color;
+
+ float constant_att;
+ float linear_att;
+ float quad_att;
+
+ float spot_angle;
+ float spot_exp;
+
+ LightData() :
+ mode(MODE_AMBIENT),
+ color(Color(1, 1, 1, 1)),
+ constant_att(0),
+ linear_att(0),
+ quad_att(0),
+ spot_angle(45),
+ spot_exp(1) {
+ }
+ };
+
+ struct MeshData {
+
+ String name;
+ struct Source {
+
+ Vector<float> array;
+ int stride;
+ };
+
+ Map<String, Source> sources;
+
+ struct Vertices {
+
+ Map<String, String> sources;
+ };
+
+ Map<String, Vertices> vertices;
+
+ struct Primitives {
+
+ struct SourceRef {
+
+ String source;
+ int offset;
+ };
+
+ String material;
+ Map<String, SourceRef> sources;
+ Vector<float> polygons;
+ Vector<float> indices;
+ int count;
+ int vertex_size;
+ };
+
+ Vector<Primitives> primitives;
+
+ bool found_double_sided;
+ bool double_sided;
+
+ MeshData() {
+ found_double_sided = false;
+ double_sided = true;
+ }
+ };
+
+ struct CurveData {
+
+ String name;
+ bool closed;
+
+ struct Source {
+
+ Vector<String> sarray;
+ Vector<float> array;
+ int stride;
+ };
+
+ Map<String, Source> sources;
+
+ Map<String, String> control_vertices;
+
+ CurveData() {
+
+ closed = false;
+ }
+ };
+ struct SkinControllerData {
+
+ String base;
+ bool use_idrefs;
+
+ Transform bind_shape;
+
+ struct Source {
+
+ Vector<String> sarray; //maybe for names
+ Vector<float> array;
+ int stride;
+ Source() {
+ stride = 1;
+ }
+ };
+
+ Map<String, Source> sources;
+
+ struct Joints {
+
+ Map<String, String> sources;
+ } joints;
+
+ struct Weights {
+
+ struct SourceRef {
+
+ String source;
+ int offset;
+ };
+
+ String material;
+ Map<String, SourceRef> sources;
+ Vector<float> sets;
+ Vector<float> indices;
+ int count;
+ } weights;
+
+ Map<String, Transform> bone_rest_map;
+
+ SkinControllerData() { use_idrefs = false; }
+ };
+
+ struct MorphControllerData {
+
+ String mesh;
+ String mode;
+
+ struct Source {
+
+ int stride;
+ Vector<String> sarray; //maybe for names
+ Vector<float> array;
+ Source() { stride = 1; }
+ };
+
+ Map<String, Source> sources;
+
+ Map<String, String> targets;
+ MorphControllerData() {}
+ };
+
+ struct Vertex {
+
+ int idx;
+ Vector3 vertex;
+ Vector3 normal;
+ Vector3 uv;
+ Vector3 uv2;
+ Plane tangent;
+ Color color;
+ int uid;
+ struct Weight {
+ int bone_idx;
+ float weight;
+ bool operator<(const Weight w) const { return weight > w.weight; } //heaviest first
+ };
+
+ Vector<Weight> weights;
+
+ void fix_weights() {
+
+ weights.sort();
+ if (weights.size() > 4) {
+ //cap to 4 and make weights add up 1
+ weights.resize(4);
+ float total = 0;
+ for (int i = 0; i < 4; i++)
+ total += weights[i].weight;
+ if (total)
+ for (int i = 0; i < 4; i++)
+ weights.write[i].weight /= total;
+ }
+ }
+
+ void fix_unit_scale(Collada &state);
+
+ bool operator<(const Vertex &p_vert) const {
+
+ if (uid == p_vert.uid) {
+ if (vertex == p_vert.vertex) {
+ if (normal == p_vert.normal) {
+ if (uv == p_vert.uv) {
+ if (uv2 == p_vert.uv2) {
+
+ if (!weights.empty() || !p_vert.weights.empty()) {
+
+ if (weights.size() == p_vert.weights.size()) {
+
+ for (int i = 0; i < weights.size(); i++) {
+ if (weights[i].bone_idx != p_vert.weights[i].bone_idx)
+ return weights[i].bone_idx < p_vert.weights[i].bone_idx;
+
+ if (weights[i].weight != p_vert.weights[i].weight)
+ return weights[i].weight < p_vert.weights[i].weight;
+ }
+ } else {
+ return weights.size() < p_vert.weights.size();
+ }
+ }
+
+ return (color < p_vert.color);
+ } else
+ return (uv2 < p_vert.uv2);
+ } else
+ return (uv < p_vert.uv);
+ } else
+ return (normal < p_vert.normal);
+ } else
+ return vertex < p_vert.vertex;
+ } else
+ return uid < p_vert.uid;
+ }
+
+ Vertex() {
+ uid = 0;
+ idx = 0;
+ }
+ };
+ struct Node {
+
+ enum Type {
+
+ TYPE_NODE,
+ TYPE_JOINT,
+ TYPE_SKELETON, //this bone is not collada, it's added afterwards as optimization
+ TYPE_LIGHT,
+ TYPE_CAMERA,
+ TYPE_GEOMETRY
+ };
+
+ struct XForm {
+
+ enum Op {
+ OP_ROTATE,
+ OP_SCALE,
+ OP_TRANSLATE,
+ OP_MATRIX,
+ OP_VISIBILITY
+ };
+
+ String id;
+ Op op;
+ Vector<float> data;
+ };
+
+ Type type;
+
+ String name;
+ String id;
+ String empty_draw_type;
+ bool noname;
+ Vector<XForm> xform_list;
+ Transform default_transform;
+ Transform post_transform;
+ Vector<Node *> children;
+
+ Node *parent;
+
+ Transform compute_transform(Collada &state) const;
+ Transform get_global_transform() const;
+ Transform get_transform() const;
+
+ bool ignore_anim;
+
+ Node() {
+ noname = false;
+ type = TYPE_NODE;
+ parent = nullptr;
+ ignore_anim = false;
+ }
+ virtual ~Node() {
+ for (int i = 0; i < children.size(); i++)
+ memdelete(children[i]);
+ };
+ };
+
+ struct NodeSkeleton : public Node {
+
+ NodeSkeleton() { type = TYPE_SKELETON; }
+ };
+
+ struct NodeJoint : public Node {
+
+ NodeSkeleton *owner;
+ String sid;
+ NodeJoint() {
+ type = TYPE_JOINT;
+ owner = nullptr;
+ }
+ };
+
+ struct NodeGeometry : public Node {
+
+ bool controller;
+ String source;
+
+ struct Material {
+ String target;
+ };
+
+ Map<String, Material> material_map;
+ Vector<String> skeletons;
+
+ NodeGeometry() { type = TYPE_GEOMETRY; }
+ };
+
+ struct NodeCamera : public Node {
+
+ String camera;
+
+ NodeCamera() { type = TYPE_CAMERA; }
+ };
+
+ struct NodeLight : public Node {
+
+ String light;
+
+ NodeLight() { type = TYPE_LIGHT; }
+ };
+
+ struct VisualScene {
+
+ String name;
+ Vector<Node *> root_nodes;
+
+ ~VisualScene() {
+ for (int i = 0; i < root_nodes.size(); i++)
+ memdelete(root_nodes[i]);
+ }
+ };
+
+ struct AnimationClip {
+
+ String name;
+ float begin;
+ float end;
+ Vector<String> tracks;
+
+ AnimationClip() {
+ begin = 0;
+ end = 1;
+ }
+ };
+
+ struct AnimationTrack {
+
+ String id;
+ String target;
+ String param;
+ String component;
+ bool property;
+
+ enum InterpolationType {
+ INTERP_LINEAR,
+ INTERP_BEZIER
+ };
+
+ struct Key {
+
+ enum Type {
+ TYPE_FLOAT,
+ TYPE_MATRIX
+ };
+
+ float time;
+ Vector<float> data;
+ Point2 in_tangent;
+ Point2 out_tangent;
+ InterpolationType interp_type;
+
+ Key() { interp_type = INTERP_LINEAR; }
+ };
+
+ Vector<float> get_value_at_time(float p_time) const;
+
+ Vector<Key> keys;
+
+ AnimationTrack() { property = false; }
+ };
+
+ /****************/
+ /* IMPORT STATE */
+ /****************/
+
+ struct State {
+
+ int import_flags;
+
+ float unit_scale;
+ Vector3::Axis up_axis;
+ bool z_up;
+
+ struct Version {
+
+ int major, minor, rev;
+
+ bool operator<(const Version &p_ver) const { return (major == p_ver.major) ? ((minor == p_ver.minor) ? (rev < p_ver.rev) : minor < p_ver.minor) : major < p_ver.major; }
+ Version(int p_major = 0, int p_minor = 0, int p_rev = 0) {
+ major = p_major;
+ minor = p_minor;
+ rev = p_rev;
+ }
+ } version;
+
+ Map<String, CameraData> camera_data_map;
+ Map<String, MeshData> mesh_data_map;
+ Map<String, LightData> light_data_map;
+ Map<String, CurveData> curve_data_map;
+
+ Map<String, String> mesh_name_map;
+ Map<String, String> morph_name_map;
+ Map<String, String> morph_ownership_map;
+ Map<String, SkinControllerData> skin_controller_data_map;
+ Map<String, MorphControllerData> morph_controller_data_map;
+
+ Map<String, Image> image_map;
+ Map<String, Material> material_map;
+ Map<String, Effect> effect_map;
+
+ Map<String, VisualScene> visual_scene_map;
+ Map<String, Node *> scene_map;
+ Set<String> idref_joints;
+ Map<String, String> sid_to_node_map;
+ //Map<String,NodeJoint*> bone_map;
+
+ Map<String, Transform> bone_rest_map;
+
+ String local_path;
+ String root_visual_scene;
+ String root_physics_scene;
+
+ Vector<AnimationClip> animation_clips;
+ Vector<AnimationTrack> animation_tracks;
+ Map<String, Vector<int>> referenced_tracks;
+ Map<String, Vector<int>> by_id_tracks;
+
+ float animation_length;
+
+ State() :
+ import_flags(0),
+ unit_scale(1.0),
+ up_axis(Vector3::AXIS_Y),
+ animation_length(0) {
+ }
+ } state;
+
+ Error load(const String &p_path, int p_flags = 0);
+
+ Collada();
+
+ Transform fix_transform(const Transform &p_transform);
+
+ Transform get_root_transform() const;
+
+ int get_uv_channel(String p_name);
+
+private: // private stuff
+ Map<String, int> channel_map;
+
+ void _parse_asset(XMLParser &parser);
+ void _parse_image(XMLParser &parser);
+ void _parse_material(XMLParser &parser);
+ void _parse_effect_material(XMLParser &parser, Effect &effect, String &id);
+ void _parse_effect(XMLParser &parser);
+ void _parse_camera(XMLParser &parser);
+ void _parse_light(XMLParser &parser);
+ void _parse_animation_clip(XMLParser &parser);
+
+ void _parse_mesh_geometry(XMLParser &parser, String p_id, String p_name);
+ void _parse_curve_geometry(XMLParser &parser, String p_id, String p_name);
+
+ void _parse_skin_controller(XMLParser &parser, String p_id);
+ void _parse_morph_controller(XMLParser &parser, String p_id);
+ void _parse_controller(XMLParser &parser);
+
+ Node *_parse_visual_instance_geometry(XMLParser &parser);
+ Node *_parse_visual_instance_camera(XMLParser &parser);
+ Node *_parse_visual_instance_light(XMLParser &parser);
+
+ Node *_parse_visual_node_instance_data(XMLParser &parser);
+ Node *_parse_visual_scene_node(XMLParser &parser);
+ void _parse_visual_scene(XMLParser &parser);
+
+ void _parse_animation(XMLParser &parser);
+ void _parse_scene(XMLParser &parser);
+ void _parse_library(XMLParser &parser);
+
+ Variant _parse_param(XMLParser &parser);
+ Vector<float> _read_float_array(XMLParser &parser);
+ Vector<String> _read_string_array(XMLParser &parser);
+ Transform _read_transform(XMLParser &parser);
+ String _read_empty_draw_type(XMLParser &parser);
+
+ void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner);
+ void _create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton = nullptr);
+ void _find_morph_nodes(VisualScene *p_vscene, Node *p_node);
+ bool _remove_node(Node *p_parent, Node *p_node);
+ void _remove_node(VisualScene *p_vscene, Node *p_node);
+ void _merge_skeletons2(VisualScene *p_vscene);
+ void _merge_skeletons(VisualScene *p_vscene, Node *p_node);
+ bool _optimize_skeletons(VisualScene *p_vscene, Node *p_node);
+
+ bool _move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, List<Node *> *p_mgeom);
+
+ void _optimize();
+};
+
+#endif // COLLADA_H
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 2f97f4aa31..697ddfba96 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -31,14 +31,14 @@
#include "editor_import_collada.h"
#include "core/os/os.h"
-#include "editor/collada/collada.h"
#include "editor/editor_node.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/light.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/path.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "editor/import/collada.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/path_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/packed_scene.h"
@@ -47,18 +47,18 @@
struct ColladaImport {
Collada collada;
- Spatial *scene;
+ Node3D *scene;
- Vector<Ref<Animation> > animations;
+ Vector<Ref<Animation>> animations;
struct NodeMap {
//String path;
- Spatial *node;
+ Node3D *node;
int bone;
List<int> anim_tracks;
NodeMap() {
- node = NULL;
+ node = nullptr;
bone = -1;
}
};
@@ -73,23 +73,23 @@ struct ColladaImport {
Map<String, NodeMap> node_map; //map from collada node to engine node
Map<String, String> node_name_map; //map from collada node to engine node
- Map<String, Ref<ArrayMesh> > mesh_cache;
- Map<String, Ref<Curve3D> > curve_cache;
- Map<String, Ref<Material> > material_cache;
- Map<Collada::Node *, Skeleton *> skeleton_map;
+ Map<String, Ref<ArrayMesh>> mesh_cache;
+ Map<String, Ref<Curve3D>> curve_cache;
+ Map<String, Ref<Material>> material_cache;
+ Map<Collada::Node *, Skeleton3D *> skeleton_map;
- Map<Skeleton *, Map<String, int> > skeleton_bone_map;
+ Map<Skeleton3D *, Map<String, int>> skeleton_bone_map;
Set<String> valid_animated_nodes;
Vector<int> valid_animated_properties;
Map<String, bool> bones_with_animation;
- Error _populate_skeleton(Skeleton *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent);
+ 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, Spatial *p_parent);
+ Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
Error _create_resources(Collada::Node *p_node, bool p_use_compression);
Error _create_material(const String &p_target);
- Error _create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh> > p_morph_meshes = Vector<Ref<ArrayMesh> >(), bool p_use_compression = false, bool p_use_mesh_material = false);
+ Error _create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes = Vector<Ref<ArrayMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false);
void _fix_param_animation_tracks();
void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks);
@@ -110,7 +110,7 @@ struct ColladaImport {
}
};
-Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent) {
+Error ColladaImport::_populate_skeleton(Skeleton3D *p_skeleton, Collada::Node *p_node, int &r_bone, int p_parent) {
if (p_node->type != Collada::Node::TYPE_JOINT)
return OK;
@@ -174,7 +174,7 @@ Error ColladaImport::_create_scene_skeletons(Collada::Node *p_node) {
if (p_node->type == Collada::Node::TYPE_SKELETON) {
- Skeleton *sk = memnew(Skeleton);
+ Skeleton3D *sk = memnew(Skeleton3D);
int bone = 0;
for (int i = 0; i < p_node->children.size(); i++) {
@@ -193,15 +193,15 @@ Error ColladaImport::_create_scene_skeletons(Collada::Node *p_node) {
return OK;
}
-Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
+Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
- Spatial *node = NULL;
+ Node3D *node = nullptr;
switch (p_node->type) {
case Collada::Node::TYPE_NODE: {
- node = memnew(Spatial);
+ node = memnew(Node3D);
} break;
case Collada::Node::TYPE_JOINT: {
@@ -223,7 +223,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
if (!bool(GLOBAL_DEF("collada/use_ambient", false)))
return OK;
//well, it's an ambient light..
- Light *l = memnew(DirectionalLight);
+ Light3D *l = memnew(DirectionalLight3D);
//l->set_color(Light::COLOR_AMBIENT,ld.color);
//l->set_color(Light::COLOR_DIFFUSE,Color(0,0,0));
//l->set_color(Light::COLOR_SPECULAR,Color(0,0,0));
@@ -232,7 +232,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
} else if (ld.mode == Collada::LightData::MODE_DIRECTIONAL) {
//well, it's an ambient light..
- Light *l = memnew(DirectionalLight);
+ Light3D *l = memnew(DirectionalLight3D);
/*
if (found_ambient) //use it here
l->set_color(Light::COLOR_AMBIENT,ambient);
@@ -243,12 +243,12 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
node = l;
} else {
- Light *l;
+ Light3D *l;
if (ld.mode == Collada::LightData::MODE_OMNI)
- l = memnew(OmniLight);
+ l = memnew(OmniLight3D);
else {
- l = memnew(SpotLight);
+ l = memnew(SpotLight3D);
//l->set_parameter(Light::PARAM_SPOT_ANGLE,ld.spot_angle);
//l->set_parameter(Light::PARAM_SPOT_ATTENUATION,ld.spot_exp);
}
@@ -262,13 +262,13 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
} else {
- node = memnew(Spatial);
+ node = memnew(Node3D);
}
} break;
case Collada::Node::TYPE_CAMERA: {
Collada::NodeCamera *cam = static_cast<Collada::NodeCamera *>(p_node);
- Camera *camera = memnew(Camera);
+ Camera3D *camera = memnew(Camera3D);
if (collada.state.camera_data_map.has(cam->camera)) {
@@ -280,12 +280,12 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
if (cd.orthogonal.y_mag) {
- camera->set_keep_aspect_mode(Camera::KEEP_HEIGHT);
+ camera->set_keep_aspect_mode(Camera3D::KEEP_HEIGHT);
camera->set_orthogonal(cd.orthogonal.y_mag * 2.0, cd.z_near, cd.z_far);
} else if (!cd.orthogonal.y_mag && cd.orthogonal.x_mag) {
- camera->set_keep_aspect_mode(Camera::KEEP_WIDTH);
+ camera->set_keep_aspect_mode(Camera3D::KEEP_WIDTH);
camera->set_orthogonal(cd.orthogonal.x_mag * 2.0, cd.z_near, cd.z_far);
}
@@ -314,17 +314,17 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
if (collada.state.curve_data_map.has(ng->source)) {
- node = memnew(Path);
+ node = memnew(Path3D);
} else {
//mesh since nothing else
- node = memnew(MeshInstance);
- //Object::cast_to<MeshInstance>(node)->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT, true);
+ node = memnew(MeshInstance3D);
+ //Object::cast_to<MeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
}
} break;
case Collada::Node::TYPE_SKELETON: {
ERR_FAIL_COND_V(!skeleton_map.has(p_node), ERR_CANT_CREATE);
- Skeleton *sk = skeleton_map[p_node];
+ Skeleton3D *sk = skeleton_map[p_node];
node = sk;
} break;
}
@@ -489,7 +489,7 @@ Error ColladaImport::_create_material(const String &p_target) {
return OK;
}
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh> > p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
bool local_xform_mirror = p_local_xform.basis.determinant() < 0;
@@ -536,7 +536,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
/* NORMAL SOURCE */
- const Collada::MeshData::Source *normal_src = NULL;
+ const Collada::MeshData::Source *normal_src = nullptr;
int normal_ofs = 0;
if (p.sources.has("NORMAL")) {
@@ -547,7 +547,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
normal_src = &meshdata.sources[normal_source_id];
}
- const Collada::MeshData::Source *binormal_src = NULL;
+ const Collada::MeshData::Source *binormal_src = nullptr;
int binormal_ofs = 0;
if (p.sources.has("TEXBINORMAL")) {
@@ -558,7 +558,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
binormal_src = &meshdata.sources[binormal_source_id];
}
- const Collada::MeshData::Source *tangent_src = NULL;
+ const Collada::MeshData::Source *tangent_src = nullptr;
int tangent_ofs = 0;
if (p.sources.has("TEXTANGENT")) {
@@ -569,7 +569,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
tangent_src = &meshdata.sources[tangent_source_id];
}
- const Collada::MeshData::Source *uv_src = NULL;
+ const Collada::MeshData::Source *uv_src = nullptr;
int uv_ofs = 0;
if (p.sources.has("TEXCOORD0")) {
@@ -580,7 +580,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
uv_src = &meshdata.sources[uv_source_id];
}
- const Collada::MeshData::Source *uv2_src = NULL;
+ const Collada::MeshData::Source *uv2_src = nullptr;
int uv2_ofs = 0;
if (p.sources.has("TEXCOORD1")) {
@@ -591,7 +591,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
uv2_src = &meshdata.sources[uv2_source_id];
}
- const Collada::MeshData::Source *color_src = NULL;
+ const Collada::MeshData::Source *color_src = nullptr;
int color_ofs = 0;
if (p.sources.has("COLOR")) {
@@ -608,13 +608,13 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
/* ADD WEIGHTS IF EXIST */
/************************/
- Map<int, Vector<Collada::Vertex::Weight> > pre_weights;
+ Map<int, Vector<Collada::Vertex::Weight>> pre_weights;
bool has_weights = false;
if (p_skin_controller) {
- const Collada::SkinControllerData::Source *weight_src = NULL;
+ const Collada::SkinControllerData::Source *weight_src = nullptr;
int weight_ofs = 0;
if (p_skin_controller->weights.sources.has("WEIGHT")) {
@@ -922,10 +922,10 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
if (has_weights) {
Vector<float> weights;
Vector<int> bones;
- weights.resize(VS::ARRAY_WEIGHTS_SIZE);
- bones.resize(VS::ARRAY_WEIGHTS_SIZE);
+ weights.resize(RS::ARRAY_WEIGHTS_SIZE);
+ bones.resize(RS::ARRAY_WEIGHTS_SIZE);
//float sum=0.0;
- for (int l = 0; l < VS::ARRAY_WEIGHTS_SIZE; l++) {
+ for (int l = 0; l < RS::ARRAY_WEIGHTS_SIZE; l++) {
if (l < vertex_array[k].weights.size()) {
weights.write[l] = vertex_array[k].weights[l].weight;
bones.write[l] = vertex_array[k].weights[l].bone_idx;
@@ -963,7 +963,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me
////////////////////////////
Array d = surftool->commit_to_arrays();
- d.resize(VS::ARRAY_MAX);
+ d.resize(RS::ARRAY_MAX);
Array mr;
@@ -1010,12 +1010,12 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
if (p_node->type == Collada::Node::TYPE_GEOMETRY && node_map.has(p_node->id)) {
- Spatial *node = node_map[p_node->id].node;
+ Node3D *node = node_map[p_node->id].node;
Collada::NodeGeometry *ng = static_cast<Collada::NodeGeometry *>(p_node);
- if (Object::cast_to<Path>(node)) {
+ if (Object::cast_to<Path3D>(node)) {
- Path *path = Object::cast_to<Path>(node);
+ Path3D *path = Object::cast_to<Path3D>(node);
if (curve_cache.has(ng->source)) {
@@ -1047,7 +1047,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
const Collada::CurveData::Source &interps = cd.sources[cd.control_vertices["INTERPOLATION"]];
ERR_FAIL_COND_V(interps.stride != 1, ERR_INVALID_DATA);
- const Collada::CurveData::Source *tilts = NULL;
+ const Collada::CurveData::Source *tilts = nullptr;
if (cd.control_vertices.has("TILT") && cd.sources.has(cd.control_vertices["TILT"]))
tilts = &cd.sources[cd.control_vertices["TILT"]];
@@ -1083,20 +1083,20 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
}
- if (Object::cast_to<MeshInstance>(node)) {
+ if (Object::cast_to<MeshInstance3D>(node)) {
Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node);
- MeshInstance *mi = Object::cast_to<MeshInstance>(node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node);
ERR_FAIL_COND_V(!mi, ERR_BUG);
- Collada::SkinControllerData *skin = NULL;
- Collada::MorphControllerData *morph = NULL;
+ Collada::SkinControllerData *skin = nullptr;
+ Collada::MorphControllerData *morph = nullptr;
String meshid;
Transform apply_xform;
Vector<int> bone_remap;
- Vector<Ref<ArrayMesh> > morphs;
+ Vector<Ref<ArrayMesh>> morphs;
if (ng2->controller) {
@@ -1114,7 +1114,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
String skname = skeletons[0];
ERR_FAIL_COND_V(!node_map.has(skname), ERR_INVALID_DATA);
NodeMap nmsk = node_map[skname];
- Skeleton *sk = Object::cast_to<Skeleton>(nmsk.node);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(nmsk.node);
ERR_FAIL_COND_V(!sk, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!skeleton_bone_map.has(sk), ERR_INVALID_DATA);
Map<String, int> &bone_remap_map = skeleton_bone_map[sk];
@@ -1173,7 +1173,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
Ref<ArrayMesh> mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2];
mesh->set_name(meshdata.name);
- Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, NULL, Vector<Ref<ArrayMesh> >(), false);
+ Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ArrayMesh>>(), false);
ERR_FAIL_COND_V(err, err);
morphs.push_back(mesh);
@@ -1265,7 +1265,7 @@ Error ColladaImport::load(const String &p_path, int p_flags, bool p_force_make_t
ERR_FAIL_COND_V(!collada.state.visual_scene_map.has(collada.state.root_visual_scene), ERR_INVALID_DATA);
Collada::VisualScene &vs = collada.state.visual_scene_map[collada.state.root_visual_scene];
- scene = memnew(Spatial); // root
+ scene = memnew(Node3D); // root
//determine what's going on with the lights
for (int i = 0; i < vs.root_nodes.size(); i++) {
@@ -1530,7 +1530,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
String path = scene->get_path_to(nm.node);
if (nm.bone >= 0) {
- Skeleton *sk = static_cast<Skeleton *>(nm.node);
+ Skeleton3D *sk = static_cast<Skeleton3D *>(nm.node);
String name = sk->get_bone_name(nm.bone);
path = path + ":" + name;
}
@@ -1621,7 +1621,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
if (nm.bone >= 0) {
//make bone transform relative to rest (in case of skeleton)
- Skeleton *sk = Object::cast_to<Skeleton>(nm.node);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(nm.node);
if (sk) {
xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
@@ -1662,7 +1662,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
NodeMap &nm = node_map[E->key()];
String path = scene->get_path_to(nm.node);
ERR_CONTINUE(nm.bone < 0);
- Skeleton *sk = static_cast<Skeleton *>(nm.node);
+ Skeleton3D *sk = static_cast<Skeleton3D *>(nm.node);
String name = sk->get_bone_name(nm.bone);
path = path + ":" + name;
@@ -1777,7 +1777,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
Error err = state.load(p_path, flags, p_flags & EditorSceneImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_flags & EditorSceneImporter::IMPORT_USE_COMPRESSION);
- ERR_FAIL_COND_V_MSG(err != OK, NULL, "Cannot load scene from file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Cannot load scene from file '" + p_path + "'.");
if (state.missing_textures.size()) {
diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h
index 822a6450be..932a064e76 100644
--- a/editor/import/editor_import_collada.h
+++ b/editor/import/editor_import_collada.h
@@ -40,7 +40,7 @@ class EditorSceneImporterCollada : public EditorSceneImporter {
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- 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);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporterCollada();
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index 4383b1b084..be4679b6d3 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -52,7 +52,7 @@ public:
virtual int get_import_order() const;
virtual void get_import_options(List<ImportOption> *r_options, int p_preset) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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, Variant *r_metadata = NULL);
+ 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, Variant *r_metadata = nullptr);
};
#endif //EDITOR_IMPORT_PLUGIN_H
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index 731d094745..6ad2aa4142 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -37,9 +37,9 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "modules/regex/regex.h"
-#include "scene/3d/bone_attachment.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/mesh_instance.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/surface_tool.h"
@@ -1266,7 +1266,7 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
}
Vector<uint8_t> data;
- const uint8_t *data_ptr = NULL;
+ const uint8_t *data_ptr = nullptr;
int data_size = 0;
if (d.has("uri")) {
@@ -1307,7 +1307,7 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
if (mimetype.findn("png") != -1) {
//is a png
- ERR_FAIL_COND_V(Image::_png_mem_loader_func == NULL, ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE);
const Ref<Image> img = Image::_png_mem_loader_func(data_ptr, data_size);
@@ -1323,7 +1323,7 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b
if (mimetype.findn("jpeg") != -1) {
//is a jpg
- ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == NULL, ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE);
const Ref<Image> img = Image::_jpg_mem_loader_func(data_ptr, data_size);
@@ -1838,7 +1838,7 @@ Error EditorSceneImporterGLTF::_determine_skeletons(GLTFState &state) {
skeleton_sets.get_representatives(groups_representatives);
Vector<GLTFNodeIndex> highest_group_members;
- Vector<Vector<GLTFNodeIndex> > groups;
+ Vector<Vector<GLTFNodeIndex>> groups;
for (int i = 0; i < groups_representatives.size(); ++i) {
Vector<GLTFNodeIndex> group;
skeleton_sets.get_members(group, groups_representatives[i]);
@@ -2108,7 +2108,7 @@ Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) {
GLTFSkeleton &gltf_skeleton = state.skeletons.write[skel_i];
- Skeleton *skeleton = memnew(Skeleton);
+ Skeleton3D *skeleton = memnew(Skeleton3D);
gltf_skeleton.godot_skeleton = skeleton;
// Make a unique name, no gltf node represents this skeleton
@@ -2485,12 +2485,12 @@ void EditorSceneImporterGLTF::_assign_scene_names(GLTFState &state) {
}
}
-BoneAttachment *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index) {
+BoneAttachment3D *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
const GLTFNode *bone_node = state.nodes[gltf_node->parent];
- BoneAttachment *bone_attachment = memnew(BoneAttachment);
+ BoneAttachment3D *bone_attachment = memnew(BoneAttachment3D);
print_verbose("glTF: Creating bone attachment for: " + gltf_node->name);
ERR_FAIL_COND_V(!bone_node->joint, nullptr);
@@ -2500,12 +2500,12 @@ BoneAttachment *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState &st
return bone_attachment;
}
-MeshInstance *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->mesh, state.meshes.size(), nullptr);
- MeshInstance *mi = memnew(MeshInstance);
+ MeshInstance3D *mi = memnew(MeshInstance3D);
print_verbose("glTF: Creating mesh for: " + gltf_node->name);
GLTFMesh &mesh = state.meshes.write[gltf_node->mesh];
@@ -2522,12 +2522,12 @@ MeshInstance *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state,
return mi;
}
-Camera *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+Camera3D *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->camera, state.cameras.size(), nullptr);
- Camera *camera = memnew(Camera);
+ Camera3D *camera = memnew(Camera3D);
print_verbose("glTF: Creating camera for: " + gltf_node->name);
const GLTFCamera &c = state.cameras[gltf_node->camera];
@@ -2540,26 +2540,26 @@ Camera *EditorSceneImporterGLTF::_generate_camera(GLTFState &state, Node *scene_
return camera;
}
-Spatial *EditorSceneImporterGLTF::_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
+Node3D *EditorSceneImporterGLTF::_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
- Spatial *spatial = memnew(Spatial);
+ Node3D *spatial = memnew(Node3D);
print_verbose("glTF: Creating spatial for: " + gltf_node->name);
return spatial;
}
-void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index) {
+void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
const GLTFNode *gltf_node = state.nodes[node_index];
- Spatial *current_node = nullptr;
+ Node3D *current_node = nullptr;
// Is our parent a skeleton
- Skeleton *active_skeleton = Object::cast_to<Skeleton>(scene_parent);
+ Skeleton3D *active_skeleton = Object::cast_to<Skeleton3D>(scene_parent);
if (gltf_node->skeleton >= 0) {
- Skeleton *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton;
+ Skeleton3D *skeleton = state.skeletons[gltf_node->skeleton].godot_skeleton;
if (active_skeleton != skeleton) {
ERR_FAIL_COND_MSG(active_skeleton != nullptr, "glTF: Generating scene detected direct parented Skeletons");
@@ -2577,7 +2577,7 @@ void EditorSceneImporterGLTF::_generate_scene_node(GLTFState &state, Node *scene
// If we have an active skeleton, and the node is node skinned, we need to create a bone attachment
if (current_node == nullptr && active_skeleton != nullptr && gltf_node->skin < 0) {
- BoneAttachment *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index);
+ BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index);
scene_parent->add_child(bone_attachment);
bone_attachment->set_owner(scene_root);
@@ -2776,7 +2776,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
const GLTFNode *node = state.nodes[E->key()];
if (node->skeleton >= 0) {
- const Skeleton *sk = Object::cast_to<Skeleton>(state.scene_nodes.find(node_index)->get());
+ const Skeleton3D *sk = Object::cast_to<Skeleton3D>(state.scene_nodes.find(node_index)->get());
ERR_FAIL_COND(sk == nullptr);
const String path = ap->get_parent()->get_path_to(sk);
@@ -2853,7 +2853,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
xform.basis.set_quat_scale(rot, scale);
xform.origin = pos;
- const Skeleton *skeleton = state.skeletons[node->skeleton].godot_skeleton;
+ const Skeleton3D *skeleton = state.skeletons[node->skeleton].godot_skeleton;
const int bone_idx = skeleton->find_bone(node->name);
xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform;
@@ -2922,7 +2922,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
ap->add_animation(name, animation);
}
-void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial *scene_root) {
+void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Node3D *scene_root) {
for (GLTFNodeIndex node_i = 0; node_i < state.nodes.size(); ++node_i) {
const GLTFNode *node = state.nodes[node_i];
@@ -2930,12 +2930,12 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial
const GLTFSkinIndex skin_i = node->skin;
Map<GLTFNodeIndex, Node *>::Element *mi_element = state.scene_nodes.find(node_i);
- MeshInstance *mi = Object::cast_to<MeshInstance>(mi_element->get());
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get());
ERR_FAIL_COND(mi == nullptr);
const GLTFSkeletonIndex skel_i = state.skins[node->skin].skeleton;
const GLTFSkeleton &gltf_skeleton = state.skeletons[skel_i];
- Skeleton *skeleton = gltf_skeleton.godot_skeleton;
+ Skeleton3D *skeleton = gltf_skeleton.godot_skeleton;
ERR_FAIL_COND(skeleton == nullptr);
mi->get_parent()->remove_child(mi);
@@ -2949,9 +2949,9 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Spatial
}
}
-Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_bake_fps) {
+Node3D *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, const int p_bake_fps) {
- Spatial *root = memnew(Spatial);
+ Node3D *root = memnew(Node3D);
// scene_name is already unique
root->set_name(state.scene_name);
@@ -2985,19 +2985,19 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla
//text file
Error err = _parse_glb(p_path, state);
if (err)
- return NULL;
+ return nullptr;
} else {
//text file
Error err = _parse_json(p_path, state);
if (err)
- return NULL;
+ return nullptr;
}
- ERR_FAIL_COND_V(!state.json.has("asset"), NULL);
+ ERR_FAIL_COND_V(!state.json.has("asset"), nullptr);
Dictionary asset = state.json["asset"];
- ERR_FAIL_COND_V(!asset.has("version"), NULL);
+ ERR_FAIL_COND_V(!asset.has("version"), nullptr);
String version = asset["version"];
@@ -3008,83 +3008,83 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla
/* STEP 0 PARSE SCENE */
Error err = _parse_scenes(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 1 PARSE NODES */
err = _parse_nodes(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 2 PARSE BUFFERS */
err = _parse_buffers(state, p_path.get_base_dir());
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 3 PARSE BUFFER VIEWS */
err = _parse_buffer_views(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 4 PARSE ACCESSORS */
err = _parse_accessors(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 5 PARSE IMAGES */
err = _parse_images(state, p_path.get_base_dir());
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 6 PARSE TEXTURES */
err = _parse_textures(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 7 PARSE TEXTURES */
err = _parse_materials(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 9 PARSE SKINS */
err = _parse_skins(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 10 DETERMINE SKELETONS */
err = _determine_skeletons(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 11 CREATE SKELETONS */
err = _create_skeletons(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 12 CREATE SKINS */
err = _create_skins(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 13 PARSE MESHES (we have enough info now) */
err = _parse_meshes(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 14 PARSE CAMERAS */
err = _parse_cameras(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 15 PARSE ANIMATIONS */
err = _parse_animations(state);
if (err != OK)
- return NULL;
+ return nullptr;
/* STEP 16 ASSIGN SCENE NAMES */
_assign_scene_names(state);
/* STEP 17 MAKE SCENE! */
- Spatial *scene = _generate_scene(state, p_bake_fps);
+ Node3D *scene = _generate_scene(state, p_bake_fps);
return scene;
}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index 5d2711483b..d127a87782 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -32,12 +32,12 @@
#define EDITOR_SCENE_IMPORTER_GLTF_H
#include "editor/import/resource_importer_scene.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
class AnimationPlayer;
-class BoneAttachment;
-class MeshInstance;
+class BoneAttachment3D;
+class MeshInstance3D;
class EditorSceneImporterGLTF : public EditorSceneImporter {
@@ -192,7 +192,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<GLTFNodeIndex> roots;
// The created Skeleton for the scene
- Skeleton *godot_skeleton;
+ Skeleton3D *godot_skeleton;
// Set of unique bone names for the skeleton
Set<String> unique_names;
@@ -284,7 +284,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Channel<Vector3> translation_track;
Channel<Quat> rotation_track;
Channel<Vector3> scale_track;
- Vector<Channel<float> > weight_tracks;
+ Vector<Channel<float>> weight_tracks;
};
String name;
@@ -302,18 +302,18 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
bool use_named_skin_binds;
Vector<GLTFNode *> nodes;
- Vector<Vector<uint8_t> > buffers;
+ Vector<Vector<uint8_t>> buffers;
Vector<GLTFBufferView> buffer_views;
Vector<GLTFAccessor> accessors;
Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to.
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
String scene_name;
Vector<int> root_nodes;
Vector<GLTFTexture> textures;
- Vector<Ref<Texture2D> > images;
+ Vector<Ref<Texture2D>> images;
Vector<GLTFSkin> skins;
Vector<GLTFCamera> cameras;
@@ -395,15 +395,15 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Error _parse_animations(GLTFState &state);
- BoneAttachment *_generate_bone_attachment(GLTFState &state, Skeleton *skeleton, const GLTFNodeIndex node_index);
- MeshInstance *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
- Camera *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
- Spatial *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index);
+ MeshInstance3D *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
+ Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index);
- void _generate_scene_node(GLTFState &state, Node *scene_parent, Spatial *scene_root, const GLTFNodeIndex node_index);
- Spatial *_generate_scene(GLTFState &state, const int p_bake_fps);
+ void _generate_scene_node(GLTFState &state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);
+ Node3D *_generate_scene(GLTFState &state, const int p_bake_fps);
- void _process_mesh_instances(GLTFState &state, Spatial *scene_root);
+ void _process_mesh_instances(GLTFState &state, Node3D *scene_root);
void _assign_scene_names(GLTFState &state);
@@ -415,7 +415,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- 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);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporterGLTF();
diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h
index dd95cb687a..927fac566e 100644
--- a/editor/import/resource_importer_bitmask.h
+++ b/editor/import/resource_importer_bitmask.h
@@ -51,7 +51,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterBitMap();
~ResourceImporterBitMap();
diff --git a/editor/import/resource_importer_csv.h b/editor/import/resource_importer_csv.h
index 2030dd1f99..7aa48f68de 100644
--- a/editor/import/resource_importer_csv.h
+++ b/editor/import/resource_importer_csv.h
@@ -49,7 +49,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterCSV();
};
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index 3119fb088b..1d7bed3975 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -96,7 +96,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
ERR_FAIL_COND_V(line.size() <= 1, ERR_PARSE_ERROR);
Vector<String> locales;
- Vector<Ref<Translation> > translations;
+ Vector<Ref<Translation>> translations;
for (int i = 1; i < line.size(); i++) {
diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h
index ec33d6aa16..742f6b8f60 100644
--- a/editor/import/resource_importer_csv_translation.h
+++ b/editor/import/resource_importer_csv_translation.h
@@ -49,7 +49,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterCSVTranslation();
};
diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h
index 6ad77eec1b..abb74d0665 100644
--- a/editor/import/resource_importer_image.h
+++ b/editor/import/resource_importer_image.h
@@ -50,7 +50,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterImage();
};
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index d472070808..a4cbc81b26 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -259,7 +259,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
Ref<Image> image;
image.instance();
- Error err = ImageLoader::load_image(p_source_file, image, NULL, false, 1.0);
+ Error err = ImageLoader::load_image(p_source_file, image, nullptr, false, 1.0);
if (err != OK)
return err;
@@ -383,7 +383,7 @@ const char *ResourceImporterLayeredTexture::compression_formats[] = {
"etc",
"etc2",
"pvrtc",
- NULL
+ nullptr
};
String ResourceImporterLayeredTexture::get_import_settings_string() const {
@@ -438,7 +438,7 @@ bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_p
return valid;
}
-ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL;
+ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = nullptr;
ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() {
diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h
index 6a6bc89a81..40e5c9023e 100644
--- a/editor/import/resource_importer_layered_texture.h
+++ b/editor/import/resource_importer_layered_texture.h
@@ -114,7 +114,7 @@ public:
void _save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps);
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
void update_imports();
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 7fd3bcc478..6a6eadfa5c 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -32,8 +32,8 @@
#include "core/io/resource_saver.h"
#include "core/os/file_access.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
#include "scene/resources/mesh.h"
#include "scene/resources/surface_tool.h"
@@ -42,7 +42,7 @@ uint32_t EditorOBJImporter::get_import_flags() const {
return IMPORT_SCENE;
}
-static Error _parse_material_library(const String &p_path, Map<String, Ref<StandardMaterial3D> > &material_map, List<String> *r_missing_deps) {
+static Error _parse_material_library(const String &p_path, Map<String, Ref<StandardMaterial3D>> &material_map, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path));
@@ -203,7 +203,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand
return OK;
}
-static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List<String> *r_missing_deps) {
+static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List<String> *r_missing_deps) {
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
@@ -221,7 +221,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
Vector<Vector2> uvs;
String name;
- Map<String, Map<String, Ref<StandardMaterial3D> > > material_map;
+ Map<String, Map<String, Ref<StandardMaterial3D>>> material_map;
Ref<SurfaceTool> surf_tool = memnew(SurfaceTool);
surf_tool->begin(Mesh::PRIMITIVE_TRIANGLES);
@@ -397,7 +397,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p
current_material_library = l.replace("mtllib", "").strip_edges();
if (!material_map.has(current_material_library)) {
- Map<String, Ref<StandardMaterial3D> > lib;
+ Map<String, Ref<StandardMaterial3D>> lib;
Error err = _parse_material_library(current_material_library, lib, r_missing_deps);
if (err == ERR_CANT_OPEN) {
String dir = p_path.get_base_dir();
@@ -420,7 +420,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;
+ 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);
@@ -428,14 +428,14 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
if (r_err) {
*r_err = err;
}
- return NULL;
+ return nullptr;
}
- Spatial *scene = memnew(Spatial);
+ Node3D *scene = memnew(Node3D);
- for (List<Ref<Mesh> >::Element *E = meshes.front(); E; E = E->next()) {
+ for (List<Ref<Mesh>>::Element *E = meshes.front(); E; E = E->next()) {
- MeshInstance *mi = memnew(MeshInstance);
+ MeshInstance3D *mi = memnew(MeshInstance3D);
mi->set_mesh(E->get());
mi->set_name(E->get()->get_name());
scene->add_child(mi);
@@ -500,9 +500,9 @@ bool ResourceImporterOBJ::get_option_visibility(const String &p_option, const Ma
Error ResourceImporterOBJ::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) {
- List<Ref<Mesh> > meshes;
+ List<Ref<Mesh>> meshes;
- Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], NULL);
+ Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], nullptr);
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG);
diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h
index 678be45106..7485e60f7b 100644
--- a/editor/import/resource_importer_obj.h
+++ b/editor/import/resource_importer_obj.h
@@ -40,7 +40,7 @@ class EditorOBJImporter : public EditorSceneImporter {
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorOBJImporter();
@@ -62,7 +62,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterOBJ();
};
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 5651197fa3..b5766a48a0 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -32,19 +32,19 @@
#include "core/io/resource_saver.h"
#include "editor/editor_node.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/navigation.h"
-#include "scene/3d/physics_body.h"
-#include "scene/3d/vehicle_body.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/navigation_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/3d/vehicle_body_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
-#include "scene/resources/box_shape.h"
+#include "scene/resources/box_shape_3d.h"
#include "scene/resources/packed_scene.h"
-#include "scene/resources/ray_shape.h"
+#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/resource_format_text.h"
-#include "scene/resources/sphere_shape.h"
-#include "scene/resources/world_margin_shape.h"
+#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/world_margin_shape_3d.h"
uint32_t EditorSceneImporter::get_import_flags() const {
@@ -72,7 +72,7 @@ Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags,
return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps);
}
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
@@ -81,7 +81,7 @@ Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint3
return get_script_instance()->call("_import_animation", p_path, p_flags);
}
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf),
@@ -170,7 +170,7 @@ String ResourceImporterScene::get_visible_name() const {
void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const {
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
E->get()->get_extensions(p_extensions);
}
}
@@ -276,15 +276,15 @@ static String _fixstr(const String &p_what, const String &p_str) {
return what;
}
-static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape> > &r_shape_list, bool p_convex) {
+static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
if (!p_convex) {
- Ref<Shape> shape = mesh->create_trimesh_shape();
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
} else {
- Vector<Ref<Shape> > cd = mesh->convex_decompose();
+ 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]);
@@ -293,7 +293,7 @@ static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape> > &r_shape_li
}
}
-Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape> > > &collision_map, LightBakeMode p_light_bake_mode) {
+Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape3D>>> &collision_map, LightBakeMode p_light_bake_mode) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -311,12 +311,12 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (!isroot && _teststr(name, "noimp")) {
memdelete(p_node);
- return NULL;
+ return nullptr;
}
- if (Object::cast_to<MeshInstance>(p_node)) {
+ if (Object::cast_to<MeshInstance3D>(p_node)) {
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<ArrayMesh> m = mi->get_mesh();
@@ -344,7 +344,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (p_light_bake_mode != LIGHT_BAKE_DISABLED) {
- mi->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT, true);
+ mi->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
}
}
@@ -377,12 +377,12 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
if (isroot)
return p_node;
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
if (mi) {
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
@@ -400,11 +400,11 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
fixed_name = _fixstr(name, "convcolonly");
}
- ERR_FAIL_COND_V(fixed_name == String(), NULL);
+ ERR_FAIL_COND_V(fixed_name == String(), nullptr);
if (shapes.size()) {
- StaticBody *col = memnew(StaticBody);
+ StaticBody3D *col = memnew(StaticBody3D);
col->set_transform(mi->get_transform());
col->set_name(fixed_name);
p_node->replace_by(col);
@@ -412,9 +412,9 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node = col;
int idx = 0;
- for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape *cshape = memnew(CollisionShape);
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
col->add_child(cshape);
@@ -427,55 +427,55 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
} else if (p_node->has_meta("empty_draw_type")) {
String empty_draw_type = String(p_node->get_meta("empty_draw_type"));
- StaticBody *sb = memnew(StaticBody);
+ StaticBody3D *sb = memnew(StaticBody3D);
sb->set_name(_fixstr(name, "colonly"));
- Object::cast_to<Spatial>(sb)->set_transform(Object::cast_to<Spatial>(p_node)->get_transform());
+ Object::cast_to<Node3D>(sb)->set_transform(Object::cast_to<Node3D>(p_node)->get_transform());
p_node->replace_by(sb);
memdelete(p_node);
- p_node = NULL;
- CollisionShape *colshape = memnew(CollisionShape);
+ p_node = nullptr;
+ CollisionShape3D *colshape = memnew(CollisionShape3D);
if (empty_draw_type == "CUBE") {
- BoxShape *boxShape = memnew(BoxShape);
+ BoxShape3D *boxShape = memnew(BoxShape3D);
boxShape->set_extents(Vector3(1, 1, 1));
colshape->set_shape(boxShape);
- colshape->set_name("BoxShape");
+ colshape->set_name("BoxShape3D");
} else if (empty_draw_type == "SINGLE_ARROW") {
- RayShape *rayShape = memnew(RayShape);
+ RayShape3D *rayShape = memnew(RayShape3D);
rayShape->set_length(1);
colshape->set_shape(rayShape);
- colshape->set_name("RayShape");
- Object::cast_to<Spatial>(sb)->rotate_x(Math_PI / 2);
+ colshape->set_name("RayShape3D");
+ Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2);
} else if (empty_draw_type == "IMAGE") {
- WorldMarginShape *world_margin_shape = memnew(WorldMarginShape);
+ WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D);
colshape->set_shape(world_margin_shape);
- colshape->set_name("WorldMarginShape");
+ colshape->set_name("WorldMarginShape3D");
} else {
- SphereShape *sphereShape = memnew(SphereShape);
+ SphereShape3D *sphereShape = memnew(SphereShape3D);
sphereShape->set_radius(1);
colshape->set_shape(sphereShape);
- colshape->set_name("SphereShape");
+ colshape->set_name("SphereShape3D");
}
sb->add_child(colshape);
colshape->set_owner(sb->get_owner());
}
- } else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance>(p_node)) {
+ } else if (_teststr(name, "rigid") && Object::cast_to<MeshInstance3D>(p_node)) {
if (isroot)
return p_node;
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else {
_gen_shape_list(mesh, shapes, true);
}
- RigidBody *rigid_body = memnew(RigidBody);
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(_fixstr(name, "rigid"));
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
@@ -486,9 +486,9 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
mi->set_owner(rigid_body->get_owner());
int idx = 0;
- for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape *cshape = memnew(CollisionShape);
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
rigid_body->add_child(cshape);
@@ -498,14 +498,14 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
- } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance>(p_node)) {
+ } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance3D>(p_node)) {
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
@@ -530,15 +530,15 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
if (shapes.size()) {
- StaticBody *col = memnew(StaticBody);
+ 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<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape *cshape = memnew(CollisionShape);
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
col->add_child(cshape);
@@ -550,22 +550,22 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
}
- } else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance>(p_node)) {
+ } else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance3D>(p_node)) {
if (isroot)
return p_node;
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<ArrayMesh> mesh = mi->get_mesh();
- ERR_FAIL_COND_V(mesh.is_null(), NULL);
- NavigationRegion *nmi = memnew(NavigationRegion);
+ 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);
nmi->set_navigation_mesh(nmesh);
- Object::cast_to<Spatial>(nmi)->set_transform(mi->get_transform());
+ Object::cast_to<Node3D>(nmi)->set_transform(mi->get_transform());
p_node->replace_by(nmi);
memdelete(p_node);
p_node = nmi;
@@ -575,8 +575,8 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
return p_node;
Node *owner = p_node->get_owner();
- Spatial *s = Object::cast_to<Spatial>(p_node);
- VehicleBody *bv = memnew(VehicleBody);
+ 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);
@@ -595,8 +595,8 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
return p_node;
Node *owner = p_node->get_owner();
- Spatial *s = Object::cast_to<Spatial>(p_node);
- VehicleWheel *bv = memnew(VehicleWheel);
+ 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);
@@ -609,16 +609,16 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
p_node = bv;
- } else if (Object::cast_to<MeshInstance>(p_node)) {
+ } else if (Object::cast_to<MeshInstance3D>(p_node)) {
//last attempt, maybe collision inside the mesh data
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
Ref<ArrayMesh> mesh = mi->get_mesh();
if (!mesh.is_null()) {
- List<Ref<Shape> > shapes;
+ List<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(mesh->get_name(), "col")) {
@@ -632,15 +632,15 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
}
if (shapes.size()) {
- StaticBody *col = memnew(StaticBody);
+ 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<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
+ for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape *cshape = memnew(CollisionShape);
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(E->get());
col->add_child(cshape);
@@ -934,14 +934,14 @@ void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Trans
List<PropertyInfo> pi;
p_node->get_property_list(&pi);
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_node);
if (mi) {
Ref<ArrayMesh> mesh = mi->get_mesh();
if (mesh.is_valid() && !meshes.has(mesh)) {
- Spatial *s = mi;
+ Node3D *s = mi;
Transform transform;
while (s) {
transform = transform * s->get_transform();
@@ -957,7 +957,7 @@ void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Trans
}
}
-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) {
+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;
@@ -1141,7 +1141,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, int p_preset) const {
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), "Spatial"));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_type", PROPERTY_HINT_TYPE_STRING, "Node"), "Node3D"));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "nodes/root_name"), "Scene Root"));
List<String> script_extentions;
@@ -1209,7 +1209,7 @@ Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporte
Ref<EditorSceneImporter> importer;
String ext = p_path.get_extension().to_lower();
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
if (E->get().ptr() == p_exception)
continue;
@@ -1229,7 +1229,7 @@ Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporte
break;
}
- ERR_FAIL_COND_V(!importer.is_valid(), NULL);
+ ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
List<String> missing;
Error err;
@@ -1241,7 +1241,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
Ref<EditorSceneImporter> importer;
String ext = p_path.get_extension().to_lower();
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
if (E->get().ptr() == p_exception)
continue;
@@ -1261,7 +1261,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
break;
}
- ERR_FAIL_COND_V(!importer.is_valid(), NULL);
+ ERR_FAIL_COND_V(!importer.is_valid(), nullptr);
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
@@ -1276,7 +1276,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
EditorProgress progress("import", TTR("Import Scene"), 104);
progress.step(TTR("Importing Scene..."), 0);
- for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (Set<Ref<EditorSceneImporter>>::Element *E = importers.front(); E; E = E->next()) {
List<String> extensions;
E->get()->get_extensions(&extensions);
@@ -1327,13 +1327,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
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.
- Ref<Script> root_script = NULL;
+ Ref<Script> root_script = nullptr;
if (ScriptServer::is_global_class(root_type)) {
root_script = ResourceLoader::load(ScriptServer::get_global_class_path(root_type));
root_type = ScriptServer::get_global_class_base(root_type);
}
- if (root_type != "Spatial") {
+ if (root_type != "Node3D") {
Node *base_node = Object::cast_to<Node>(ClassDB::instance(root_type));
if (base_node) {
@@ -1348,9 +1348,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
scene->set_script(Variant(root_script));
}
- if (Object::cast_to<Spatial>(scene)) {
+ if (Object::cast_to<Node3D>(scene)) {
float root_scale = p_options["nodes/root_scale"];
- Object::cast_to<Spatial>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
+ Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
}
if (p_options["nodes/root_name"] != "Scene Root")
@@ -1368,7 +1368,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float anim_optimizer_maxang = p_options["animation/optimizer/max_angle"];
int light_bake_mode = p_options["meshes/light_baking"];
- Map<Ref<Mesh>, List<Ref<Shape> > > collision_map;
+ Map<Ref<Mesh>, List<Ref<Shape3D>>> collision_map;
scene = _fix_node(scene, scene, collision_map, LightBakeMode(light_bake_mode));
@@ -1456,9 +1456,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
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;
+ 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"]);
@@ -1533,7 +1533,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return OK;
}
-ResourceImporterScene *ResourceImporterScene::singleton = NULL;
+ResourceImporterScene *ResourceImporterScene::singleton = nullptr;
ResourceImporterScene::ResourceImporterScene() {
singleton = this;
@@ -1550,10 +1550,10 @@ Node *EditorSceneImporterESCN::import_scene(const String &p_path, uint32_t p_fla
Error error;
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
- ERR_FAIL_COND_V_MSG(!ps.is_valid(), NULL, "Cannot load scene as text resource from path '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
Node *scene = ps->instance();
- ERR_FAIL_COND_V(!scene, NULL);
+ ERR_FAIL_COND_V(!scene, nullptr);
return scene;
}
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 20e7af15b5..f48f181951 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -34,7 +34,7 @@
#include "core/io/resource_importer.h"
#include "scene/resources/animation.h"
#include "scene/resources/mesh.h"
-#include "scene/resources/shape.h"
+#include "scene/resources/shape_3d.h"
class Material;
@@ -66,7 +66,7 @@ public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporter() {}
@@ -93,7 +93,7 @@ public:
class ResourceImporterScene : public ResourceImporter {
GDCLASS(ResourceImporterScene, ResourceImporter);
- Set<Ref<EditorSceneImporter> > importers;
+ Set<Ref<EditorSceneImporter>> importers;
static ResourceImporterScene *singleton;
@@ -125,7 +125,7 @@ class ResourceImporterScene : public ResourceImporter {
public:
static ResourceImporterScene *get_singleton() { return singleton; }
- const Set<Ref<EditorSceneImporter> > &get_importers() const { return importers; }
+ const Set<Ref<EditorSceneImporter>> &get_importers() const { return importers; }
void add_importer(Ref<EditorSceneImporter> p_importer) { importers.insert(p_importer); }
void remove_importer(Ref<EditorSceneImporter> p_importer) { importers.erase(p_importer); }
@@ -145,16 +145,16 @@ public:
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);
+ 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 *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape> > > &collision_map, LightBakeMode p_light_bake_mode);
+ 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);
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
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);
@@ -168,7 +168,7 @@ class EditorSceneImporterESCN : public EditorSceneImporter {
public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
};
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 0090d30b9c..f8ed9304b6 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -36,7 +36,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
-void ResourceImporterTexture::_texture_reimport_roughness(const Ref<StreamTexture> &p_tex, const String &p_normal_path, VS::TextureDetectRoughnessChannel p_channel) {
+void ResourceImporterTexture::_texture_reimport_roughness(const Ref<StreamTexture> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) {
MutexLock lock(singleton->mutex);
@@ -424,7 +424,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
String normal_map = p_options["roughness/src_normal"];
Ref<Image> normal_image;
- Image::RoughnessChannel roughness_channel;
+ Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R;
if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) {
normal_image.instance();
@@ -434,7 +434,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
}
Ref<Image> image;
image.instance();
- Error err = ImageLoader::load_image(p_source_file, image, NULL, hdr_as_srgb, scale);
+ Error err = ImageLoader::load_image(p_source_file, image, nullptr, hdr_as_srgb, scale);
if (err != OK)
return err;
@@ -575,7 +575,7 @@ const char *ResourceImporterTexture::compression_formats[] = {
"etc",
"etc2",
"pvrtc",
- NULL
+ nullptr
};
String ResourceImporterTexture::get_import_settings_string() const {
@@ -630,7 +630,7 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co
return valid;
}
-ResourceImporterTexture *ResourceImporterTexture::singleton = NULL;
+ResourceImporterTexture *ResourceImporterTexture::singleton = nullptr;
ResourceImporterTexture::ResourceImporterTexture() {
diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h
index ed0fe1be89..e1c71ff1b8 100644
--- a/editor/import/resource_importer_texture.h
+++ b/editor/import/resource_importer_texture.h
@@ -35,7 +35,7 @@
#include "core/io/resource_importer.h"
#include "core/os/file_access.h"
#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
class StreamTexture;
@@ -63,16 +63,16 @@ protected:
int flags;
String normal_path_for_roughness;
- VS::TextureDetectRoughnessChannel channel_for_roughness;
+ RS::TextureDetectRoughnessChannel channel_for_roughness;
MakeInfo() {
flags = 0;
- channel_for_roughness = VS::TEXTURE_DETECT_ROUGNHESS_R;
+ channel_for_roughness = RS::TEXTURE_DETECT_ROUGNHESS_R;
}
};
Map<StringName, MakeInfo> make_flags;
- static void _texture_reimport_roughness(const Ref<StreamTexture> &p_tex, const String &p_normal_path, VisualServer::TextureDetectRoughnessChannel p_channel);
+ static void _texture_reimport_roughness(const Ref<StreamTexture> &p_tex, const String &p_normal_path, RenderingServer::TextureDetectRoughnessChannel p_channel);
static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex);
static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex);
@@ -104,7 +104,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
void update_imports();
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index 3172cc7279..2765bb7fae 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -192,7 +192,7 @@ static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_tr
}
}
-Error ResourceImporterTextureAtlas::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) {
+Error ResourceImporterTextureAtlas::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) {
ERR_FAIL_COND_V(p_source_file_options.size() == 0, ERR_BUG); //should never happen
@@ -202,7 +202,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
pack_data_files.resize(p_source_file_options.size());
int idx = 0;
- for (const Map<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
+ for (const Map<String, Map<StringName, Variant>>::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
PackData &pack_data = pack_data_files.write[idx];
const String &source = E->key();
@@ -251,7 +251,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
Ref<BitMap> bit_map;
bit_map.instance();
bit_map->create_from_image_alpha(image);
- Vector<Vector<Vector2> > polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height()));
+ Vector<Vector<Vector2>> polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height()));
for (int j = 0; j < polygons.size(); j++) {
@@ -323,7 +323,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
//save the images
idx = 0;
- for (const Map<String, Map<StringName, Variant> >::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
+ for (const Map<String, Map<StringName, Variant>>::Element *E = p_source_file_options.front(); E; E = E->next(), idx++) {
PackData &pack_data = pack_data_files.write[idx];
diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h
index e455a157cf..c61fa5c040 100644
--- a/editor/import/resource_importer_texture_atlas.h
+++ b/editor/import/resource_importer_texture_atlas.h
@@ -40,7 +40,7 @@ class ResourceImporterTextureAtlas : public ResourceImporter {
Rect2 region;
bool is_mesh;
Vector<int> chart_pieces; //one for region, many for mesh
- Vector<Vector<Vector2> > chart_vertices; //for mesh
+ Vector<Vector<Vector2>> chart_vertices; //for mesh
Ref<Image> image;
};
@@ -63,8 +63,8 @@ public:
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual String get_option_group_file() const;
- 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 = NULL, Variant *r_metadata = NULL);
- 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);
+ 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);
+ 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);
ResourceImporterTextureAtlas();
};
diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h
index 6df5b88b13..bc2f023e6b 100644
--- a/editor/import/resource_importer_wav.h
+++ b/editor/import/resource_importer_wav.h
@@ -162,7 +162,7 @@ public:
}
}
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterWAV();
};
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 3ef88105fe..22f6aedeaa 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -112,19 +112,19 @@ void ImportDock::set_edit_path(const String &p_path) {
_update_options(config);
- List<Ref<ResourceImporter> > importers;
+ List<Ref<ResourceImporter>> importers;
ResourceFormatImporter::get_singleton()->get_importers_for_extension(p_path.get_extension(), &importers);
- List<Pair<String, String> > importer_names;
+ List<Pair<String, String>> importer_names;
- for (List<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (List<Ref<ResourceImporter>>::Element *E = importers.front(); E; E = E->next()) {
importer_names.push_back(Pair<String, String>(E->get()->get_visible_name(), E->get()->get_importer_name()));
}
- importer_names.sort_custom<PairSort<String, String> >();
+ importer_names.sort_custom<PairSort<String, String>>();
import_as->clear();
- for (List<Pair<String, String> >::Element *E = importer_names.front(); E; E = E->next()) {
+ 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()) {
@@ -240,19 +240,19 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
params->update();
- List<Ref<ResourceImporter> > importers;
+ List<Ref<ResourceImporter>> importers;
ResourceFormatImporter::get_singleton()->get_importers_for_extension(p_paths[0].get_extension(), &importers);
- List<Pair<String, String> > importer_names;
+ List<Pair<String, String>> importer_names;
- for (List<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) {
+ for (List<Ref<ResourceImporter>>::Element *E = importers.front(); E; E = E->next()) {
importer_names.push_back(Pair<String, String>(E->get()->get_visible_name(), E->get()->get_importer_name()));
}
- importer_names.sort_custom<PairSort<String, String> >();
+ importer_names.sort_custom<PairSort<String, String>>();
import_as->clear();
- for (List<Pair<String, String> >::Element *E = importer_names.front(); E; E = E->next()) {
+ 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()) {
@@ -424,7 +424,7 @@ void ImportDock::_reimport_attempt() {
if (need_restart) {
label_warning->set_visible(used_in_resources);
- reimport_confirm->popup_centered_minsize();
+ reimport_confirm->popup_centered();
return;
}
@@ -450,8 +450,8 @@ void ImportDock::_reimport() {
String importer_name = params->importer->get_importer_name();
- if (params->checking) {
- //update only what edited (checkboxes)
+ 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]);
@@ -492,13 +492,13 @@ void ImportDock::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- imported->add_style_override("normal", get_stylebox("normal", "LineEdit"));
+ imported->add_theme_style_override("normal", get_theme_stylebox("normal", "LineEdit"));
} break;
case NOTIFICATION_ENTER_TREE: {
import_opts->edit(params);
- label_warning->add_color_override("font_color", get_color("warning_color", "Editor"));
+ label_warning->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"));
} break;
}
}
@@ -526,7 +526,7 @@ ImportDock::ImportDock() {
set_name("Import");
imported = memnew(Label);
- imported->add_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_stylebox("normal", "LineEdit"));
+ imported->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("normal", "LineEdit"));
imported->set_clip_text(true);
add_child(imported);
HBoxContainer *hb = memnew(HBoxContainer);
@@ -558,7 +558,7 @@ ImportDock::ImportDock() {
hb->add_spacer();
reimport_confirm = memnew(ConfirmationDialog);
- reimport_confirm->get_ok()->set_text(TTR("Save scenes, re-import and restart"));
+ reimport_confirm->get_ok()->set_text(TTR("Save Scenes, Re-Import, and Restart"));
add_child(reimport_confirm);
reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_restart));
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 2729d9ecb5..3715547bdc 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -112,7 +112,7 @@ void InspectorDock::_menu_option(int p_option) {
editor_data->get_undo_redo().clear_history();
- editor->get_editor_plugins_over()->edit(NULL);
+ editor->get_editor_plugins_over()->edit(nullptr);
editor->get_editor_plugins_over()->edit(current);
} break;
@@ -140,7 +140,7 @@ void InspectorDock::_new_resource() {
}
void InspectorDock::_load_resource(const String &p_type) {
- load_resource_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ load_resource_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type(p_type, &extensions);
@@ -166,7 +166,7 @@ void InspectorDock::_resource_file_selected(String p_file) {
void InspectorDock::_save_resource(bool save_as) const {
ObjectID current = EditorNode::get_singleton()->get_editor_history()->get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -180,7 +180,7 @@ void InspectorDock::_save_resource(bool save_as) const {
void InspectorDock::_unref_resource() const {
ObjectID current = EditorNode::get_singleton()->get_editor_history()->get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -191,7 +191,7 @@ void InspectorDock::_unref_resource() const {
void InspectorDock::_copy_resource() const {
ObjectID current = EditorNode::get_singleton()->get_editor_history()->get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : NULL;
+ Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -214,7 +214,7 @@ void InspectorDock::_prepare_history() {
history_menu->get_popup()->clear();
- Ref<Texture2D> base_icon = get_icon("Object", "EditorIcons");
+ Ref<Texture2D> base_icon = get_theme_icon("Object", "EditorIcons");
Set<ObjectID> already;
for (int i = editor_history->get_history_len() - 1; i >= history_to; i--) {
@@ -310,14 +310,14 @@ void InspectorDock::_property_keyed(const String &p_keyed, const Variant &p_valu
}
void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform &p_key) {
- Spatial *s = Object::cast_to<Spatial>(sp);
+ Node3D *s = Object::cast_to<Node3D>(sp);
if (!s)
return;
AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(s, p_sub, p_key);
}
void InspectorDock::_warning_pressed() {
- warning_dialog->popup_centered_minsize();
+ warning_dialog->popup_centered();
}
Container *InspectorDock::get_addon_area() {
@@ -328,15 +328,15 @@ void InspectorDock::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
set_theme(editor->get_gui_base()->get_theme());
- resource_new_button->set_icon(get_icon("New", "EditorIcons"));
- resource_load_button->set_icon(get_icon("Load", "EditorIcons"));
- resource_save_button->set_icon(get_icon("Save", "EditorIcons"));
- backward_button->set_icon(get_icon("Back", "EditorIcons"));
- forward_button->set_icon(get_icon("Forward", "EditorIcons"));
- history_menu->set_icon(get_icon("History", "EditorIcons"));
- object_menu->set_icon(get_icon("Tools", "EditorIcons"));
- warning->set_icon(get_icon("NodeWarning", "EditorIcons"));
- warning->add_color_override("font_color", get_color("warning_color", "Editor"));
+ resource_new_button->set_icon(get_theme_icon("New", "EditorIcons"));
+ resource_load_button->set_icon(get_theme_icon("Load", "EditorIcons"));
+ resource_save_button->set_icon(get_theme_icon("Save", "EditorIcons"));
+ backward_button->set_icon(get_theme_icon("Back", "EditorIcons"));
+ forward_button->set_icon(get_theme_icon("Forward", "EditorIcons"));
+ history_menu->set_icon(get_theme_icon("History", "EditorIcons"));
+ object_menu->set_icon(get_theme_icon("Tools", "EditorIcons"));
+ warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons"));
+ warning->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"));
} break;
}
}
@@ -397,7 +397,7 @@ void InspectorDock::update(Object *p_object) {
editor_path->set_disabled(true);
editor_path->set_text("");
editor_path->set_tooltip("");
- editor_path->set_icon(NULL);
+ editor_path->set_icon(nullptr);
return;
}
@@ -435,7 +435,7 @@ void InspectorDock::update(Object *p_object) {
p->add_separator();
p->add_shortcut(ED_SHORTCUT("property_editor/make_subresources_unique", TTR("Make Sub-Resources Unique")), OBJECT_UNIQUE_RESOURCES);
p->add_separator();
- p->add_icon_shortcut(get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP);
+ p->add_icon_shortcut(get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP);
}
List<MethodInfo> methods;
@@ -496,21 +496,21 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
resource_new_button = memnew(ToolButton);
resource_new_button->set_tooltip(TTR("Create a new resource in memory and edit it."));
- resource_new_button->set_icon(get_icon("New", "EditorIcons"));
+ resource_new_button->set_icon(get_theme_icon("New", "EditorIcons"));
general_options_hb->add_child(resource_new_button);
resource_new_button->connect("pressed", callable_mp(this, &InspectorDock::_new_resource));
resource_new_button->set_focus_mode(Control::FOCUS_NONE);
resource_load_button = memnew(ToolButton);
resource_load_button->set_tooltip(TTR("Load an existing resource from disk and edit it."));
- resource_load_button->set_icon(get_icon("Load", "EditorIcons"));
+ resource_load_button->set_icon(get_theme_icon("Load", "EditorIcons"));
general_options_hb->add_child(resource_load_button);
resource_load_button->connect("pressed", callable_mp(this, &InspectorDock::_open_resource_selector));
resource_load_button->set_focus_mode(Control::FOCUS_NONE);
resource_save_button = memnew(MenuButton);
resource_save_button->set_tooltip(TTR("Save the currently edited resource."));
- resource_save_button->set_icon(get_icon("Save", "EditorIcons"));
+ resource_save_button->set_icon(get_theme_icon("Save", "EditorIcons"));
general_options_hb->add_child(resource_save_button);
resource_save_button->get_popup()->add_item(TTR("Save"), RESOURCE_SAVE);
resource_save_button->get_popup()->add_item(TTR("Save As..."), RESOURCE_SAVE_AS);
@@ -522,7 +522,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
backward_button = memnew(ToolButton);
general_options_hb->add_child(backward_button);
- backward_button->set_icon(get_icon("Back", "EditorIcons"));
+ backward_button->set_icon(get_theme_icon("Back", "EditorIcons"));
backward_button->set_flat(true);
backward_button->set_tooltip(TTR("Go to the previous edited object in history."));
backward_button->set_disabled(true);
@@ -530,7 +530,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
forward_button = memnew(ToolButton);
general_options_hb->add_child(forward_button);
- forward_button->set_icon(get_icon("Forward", "EditorIcons"));
+ forward_button->set_icon(get_theme_icon("Forward", "EditorIcons"));
forward_button->set_flat(true);
forward_button->set_tooltip(TTR("Go to the next edited object in history."));
forward_button->set_disabled(true);
@@ -538,9 +538,9 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
history_menu = memnew(MenuButton);
history_menu->set_tooltip(TTR("History of recently edited objects."));
- history_menu->set_icon(get_icon("History", "EditorIcons"));
+ history_menu->set_icon(get_theme_icon("History", "EditorIcons"));
general_options_hb->add_child(history_menu);
- history_menu->connect("about_to_show", callable_mp(this, &InspectorDock::_prepare_history));
+ history_menu->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_history));
history_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_select_history));
HBoxContainer *node_info_hb = memnew(HBoxContainer);
@@ -551,7 +551,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
node_info_hb->add_child(editor_path);
object_menu = memnew(MenuButton);
- object_menu->set_icon(get_icon("Tools", "EditorIcons"));
+ object_menu->set_icon(get_theme_icon("Tools", "EditorIcons"));
node_info_hb->add_child(object_menu);
object_menu->set_tooltip(TTR("Object properties."));
object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option));
@@ -564,15 +564,15 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
search = memnew(LineEdit);
search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search->set_placeholder(TTR("Filter properties"));
- search->set_right_icon(get_icon("Search", "EditorIcons"));
+ search->set_right_icon(get_theme_icon("Search", "EditorIcons"));
search->set_clear_button_enabled(true);
add_child(search);
warning = memnew(Button);
add_child(warning);
warning->set_text(TTR("Changes may be lost!"));
- warning->set_icon(get_icon("NodeWarning", "EditorIcons"));
- warning->add_color_override("font_color", get_color("warning_color", "Editor"));
+ warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons"));
+ warning->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"));
warning->set_clip_text(true);
warning->hide();
warning->connect("pressed", callable_mp(this, &InspectorDock::_warning_pressed));
diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp
new file mode 100644
index 0000000000..724782ac44
--- /dev/null
+++ b/editor/node_3d_editor_gizmos.cpp
@@ -0,0 +1,4647 @@
+/*************************************************************************/
+/* node_3d_editor_gizmos.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "node_3d_editor_gizmos.h"
+
+#include "core/math/geometry.h"
+#include "core/math/quick_hull.h"
+#include "scene/3d/audio_stream_player_3d.h"
+#include "scene/3d/baked_lightmap.h"
+#include "scene/3d/collision_polygon_3d.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/cpu_particles_3d.h"
+#include "scene/3d/decal.h"
+#include "scene/3d/gi_probe.h"
+#include "scene/3d/gpu_particles_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/listener_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/physics_joint_3d.h"
+#include "scene/3d/position_3d.h"
+#include "scene/3d/ray_cast_3d.h"
+#include "scene/3d/reflection_probe.h"
+#include "scene/3d/soft_body_3d.h"
+#include "scene/3d/spring_arm_3d.h"
+#include "scene/3d/sprite_3d.h"
+#include "scene/3d/vehicle_body_3d.h"
+#include "scene/3d/visibility_notifier_3d.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
+#include "scene/resources/cylinder_shape_3d.h"
+#include "scene/resources/height_map_shape_3d.h"
+#include "scene/resources/primitive_meshes.h"
+#include "scene/resources/ray_shape_3d.h"
+#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/surface_tool.h"
+#include "scene/resources/world_margin_shape_3d.h"
+
+#define HANDLE_HALF_SIZE 9.5
+
+bool EditorNode3DGizmo::is_editable() const {
+
+ ERR_FAIL_COND_V(!spatial_node, false);
+ Node *edited_root = spatial_node->get_tree()->get_edited_scene_root();
+ if (spatial_node == edited_root)
+ return true;
+ if (spatial_node->get_owner() == edited_root)
+ return true;
+
+ if (edited_root->is_editable_instance(spatial_node->get_owner()))
+ return true;
+
+ return false;
+}
+
+void EditorNode3DGizmo::clear() {
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ if (instances[i].instance.is_valid())
+ RS::get_singleton()->free(instances[i].instance);
+ }
+
+ billboard_handle = false;
+ collision_segments.clear();
+ collision_mesh = Ref<TriangleMesh>();
+ instances.clear();
+ handles.clear();
+ secondary_handles.clear();
+}
+
+void EditorNode3DGizmo::redraw() {
+
+ if (get_script_instance() && get_script_instance()->has_method("redraw")) {
+ get_script_instance()->call("redraw");
+ return;
+ }
+
+ ERR_FAIL_COND(!gizmo_plugin);
+ gizmo_plugin->redraw(this);
+}
+
+String EditorNode3DGizmo::get_handle_name(int p_idx) const {
+
+ if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) {
+ return get_script_instance()->call("get_handle_name", p_idx);
+ }
+
+ ERR_FAIL_COND_V(!gizmo_plugin, "");
+ return gizmo_plugin->get_handle_name(this, p_idx);
+}
+
+bool EditorNode3DGizmo::is_handle_highlighted(int p_idx) const {
+
+ if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) {
+ return get_script_instance()->call("is_handle_highlighted", p_idx);
+ }
+
+ ERR_FAIL_COND_V(!gizmo_plugin, false);
+ return gizmo_plugin->is_handle_highlighted(this, p_idx);
+}
+
+Variant EditorNode3DGizmo::get_handle_value(int p_idx) {
+
+ if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) {
+ return get_script_instance()->call("get_handle_value", p_idx);
+ }
+
+ ERR_FAIL_COND_V(!gizmo_plugin, Variant());
+ return gizmo_plugin->get_handle_value(this, p_idx);
+}
+
+void EditorNode3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ if (get_script_instance() && get_script_instance()->has_method("set_handle")) {
+ get_script_instance()->call("set_handle", p_idx, p_camera, p_point);
+ return;
+ }
+
+ ERR_FAIL_COND(!gizmo_plugin);
+ gizmo_plugin->set_handle(this, p_idx, p_camera, p_point);
+}
+
+void EditorNode3DGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ if (get_script_instance() && get_script_instance()->has_method("commit_handle")) {
+ get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel);
+ return;
+ }
+
+ ERR_FAIL_COND(!gizmo_plugin);
+ gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel);
+}
+
+void EditorNode3DGizmo::set_spatial_node(Node3D *p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ spatial_node = p_node;
+}
+
+void EditorNode3DGizmo::Instance::create_instance(Node3D *p_base, bool p_hidden) {
+
+ instance = RS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario());
+ RS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id());
+ if (skin_reference.is_valid()) {
+ RS::get_singleton()->instance_attach_skeleton(instance, skin_reference->get_skeleton());
+ }
+ if (extra_margin)
+ RS::get_singleton()->instance_set_extra_visibility_margin(instance, 1);
+ 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
+}
+
+void EditorNode3DGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const Ref<SkinReference> &p_skin_reference, const Ref<Material> &p_material) {
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+ ins.billboard = p_billboard;
+ ins.mesh = p_mesh;
+ ins.skin_reference = p_skin_reference;
+ ins.material = p_material;
+ if (valid) {
+ ins.create_instance(spatial_node, hidden);
+ RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
+ if (ins.material.is_valid()) {
+ RS::get_singleton()->instance_geometry_set_material_override(ins.instance, p_material->get_rid());
+ }
+ }
+
+ instances.push_back(ins);
+}
+
+void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) {
+ if (p_lines.empty()) {
+ return;
+ }
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+
+ a[Mesh::ARRAY_VERTEX] = p_lines;
+
+ Vector<Color> color;
+ color.resize(p_lines.size());
+ {
+ Color *w = color.ptrw();
+ for (int i = 0; i < p_lines.size(); i++) {
+ if (is_selected())
+ w[i] = Color(1, 1, 1, 0.8) * p_modulate;
+ else
+ w[i] = Color(1, 1, 1, 0.2) * p_modulate;
+ }
+ }
+
+ a[Mesh::ARRAY_COLOR] = color;
+
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, 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());
+ }
+ if (md) {
+ mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
+ }
+ }
+
+ ins.billboard = p_billboard;
+ ins.mesh = mesh;
+ if (valid) {
+ ins.create_instance(spatial_node, hidden);
+ RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
+ }
+
+ instances.push_back(ins);
+}
+
+void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, float p_scale, const Color &p_modulate) {
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+ Vector<Vector3> vs;
+ Vector<Vector2> uv;
+ Vector<Color> colors;
+
+ vs.push_back(Vector3(-p_scale, p_scale, 0));
+ vs.push_back(Vector3(p_scale, p_scale, 0));
+ vs.push_back(Vector3(p_scale, -p_scale, 0));
+ vs.push_back(Vector3(-p_scale, -p_scale, 0));
+
+ uv.push_back(Vector2(0, 0));
+ uv.push_back(Vector2(1, 0));
+ uv.push_back(Vector2(1, 1));
+ uv.push_back(Vector2(0, 1));
+
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = vs;
+ a[Mesh::ARRAY_TEX_UV] = uv;
+ Vector<int> indices;
+ indices.push_back(0);
+ indices.push_back(1);
+ indices.push_back(2);
+ indices.push_back(0);
+ indices.push_back(2);
+ indices.push_back(3);
+ a[Mesh::ARRAY_INDEX] = indices;
+ a[Mesh::ARRAY_COLOR] = colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+ mesh->surface_set_material(0, p_material);
+
+ float md = 0;
+ for (int i = 0; i < vs.size(); i++) {
+
+ md = MAX(0, vs[i].length());
+ }
+ if (md) {
+ mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
+ }
+
+ selectable_icon_size = p_scale;
+ mesh->set_custom_aabb(AABB(Vector3(-selectable_icon_size, -selectable_icon_size, -selectable_icon_size) * 100.0f, Vector3(selectable_icon_size, selectable_icon_size, selectable_icon_size) * 200.0f));
+
+ ins.mesh = mesh;
+ ins.unscaled = true;
+ ins.billboard = true;
+ if (valid) {
+ ins.create_instance(spatial_node, hidden);
+ RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
+ }
+
+ selectable_icon_size = p_scale;
+
+ instances.push_back(ins);
+}
+
+void EditorNode3DGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh) {
+ collision_mesh = p_tmesh;
+}
+
+void EditorNode3DGizmo::add_collision_segments(const Vector<Vector3> &p_lines) {
+
+ int from = collision_segments.size();
+ collision_segments.resize(from + p_lines.size());
+ for (int i = 0; i < p_lines.size(); i++) {
+
+ collision_segments.write[from + i] = p_lines[i];
+ }
+}
+
+void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard, bool p_secondary) {
+
+ billboard_handle = p_billboard;
+
+ if (!is_selected() || !is_editable())
+ return;
+
+ ERR_FAIL_COND(!spatial_node);
+
+ Instance ins;
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+
+ Array a;
+ a.resize(RS::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = p_handles;
+ Vector<Color> colors;
+ {
+ colors.resize(p_handles.size());
+ Color *w = colors.ptrw();
+ for (int i = 0; i < p_handles.size(); i++) {
+
+ Color col(1, 1, 1, 1);
+ if (is_handle_highlighted(i))
+ col = Color(0, 0, 1, 0.9);
+
+ if (Node3DEditor::get_singleton()->get_over_gizmo_handle() != i)
+ col.a = 0.8;
+
+ w[i] = col;
+ }
+ }
+ a[RS::ARRAY_COLOR] = colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
+ mesh->surface_set_material(0, p_material);
+
+ if (p_billboard) {
+ float md = 0;
+ for (int i = 0; i < p_handles.size(); i++) {
+
+ md = MAX(0, p_handles[i].length());
+ }
+ if (md) {
+ mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
+ }
+ }
+
+ ins.mesh = mesh;
+ ins.billboard = p_billboard;
+ ins.extra_margin = true;
+ if (valid) {
+ ins.create_instance(spatial_node, hidden);
+ RS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
+ }
+ instances.push_back(ins);
+ if (!p_secondary) {
+ int chs = handles.size();
+ handles.resize(chs + p_handles.size());
+ for (int i = 0; i < p_handles.size(); i++) {
+ handles.write[i + chs] = p_handles[i];
+ }
+ } else {
+
+ int chs = secondary_handles.size();
+ secondary_handles.resize(chs + p_handles.size());
+ for (int i = 0; i < p_handles.size(); i++) {
+ secondary_handles.write[i + chs] = p_handles[i];
+ }
+ }
+}
+
+void EditorNode3DGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position) {
+ ERR_FAIL_COND(!spatial_node);
+
+ CubeMesh cubem;
+ cubem.set_size(p_size);
+
+ Array arrays = cubem.surface_get_arrays(0);
+ PackedVector3Array vertex = arrays[RS::ARRAY_VERTEX];
+ Vector3 *w = vertex.ptrw();
+
+ for (int i = 0; i < vertex.size(); ++i) {
+ w[i] += p_position;
+ }
+
+ arrays[RS::ARRAY_VERTEX] = vertex;
+
+ Ref<ArrayMesh> m = memnew(ArrayMesh);
+ m->add_surface_from_arrays(cubem.surface_get_primitive_type(0), arrays);
+ m->surface_set_material(0, p_material);
+ add_mesh(m);
+}
+
+bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum) {
+
+ ERR_FAIL_COND_V(!spatial_node, false);
+ ERR_FAIL_COND_V(!valid, false);
+
+ if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false;
+
+ if (selectable_icon_size > 0.0f) {
+ Vector3 origin = spatial_node->get_global_transform().get_origin();
+
+ const Plane *p = p_frustum.ptr();
+ int fc = p_frustum.size();
+
+ bool any_out = false;
+
+ for (int j = 0; j < fc; j++) {
+
+ if (p[j].is_point_over(origin)) {
+ any_out = true;
+ break;
+ }
+ }
+
+ return !any_out;
+ }
+
+ if (collision_segments.size()) {
+
+ const Plane *p = p_frustum.ptr();
+ int fc = p_frustum.size();
+
+ int vc = collision_segments.size();
+ const Vector3 *vptr = collision_segments.ptr();
+ Transform t = spatial_node->get_global_transform();
+
+ bool any_out = false;
+ for (int j = 0; j < fc; j++) {
+ for (int i = 0; i < vc; i++) {
+ Vector3 v = t.xform(vptr[i]);
+ if (p[j].is_point_over(v)) {
+ any_out = true;
+ break;
+ }
+ }
+ if (any_out) break;
+ }
+
+ if (!any_out) return true;
+ }
+
+ if (collision_mesh.is_valid()) {
+ Transform t = spatial_node->get_global_transform();
+
+ Vector3 mesh_scale = t.get_basis().get_scale();
+ t.orthonormalize();
+
+ Transform it = t.affine_inverse();
+
+ Vector<Plane> transformed_frustum;
+
+ for (int i = 0; i < 4; i++) {
+ transformed_frustum.push_back(it.xform(p_frustum[i]));
+ }
+
+ if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), mesh_scale)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
+
+ ERR_FAIL_COND_V(!spatial_node, false);
+ ERR_FAIL_COND_V(!valid, false);
+
+ if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false;
+
+ if (r_gizmo_handle && !hidden) {
+
+ Transform t = spatial_node->get_global_transform();
+ if (billboard_handle) {
+ t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+ }
+
+ float min_d = 1e20;
+ int idx = -1;
+
+ for (int i = 0; i < secondary_handles.size(); i++) {
+
+ Vector3 hpos = t.xform(secondary_handles[i]);
+ Vector2 p = p_camera->unproject_position(hpos);
+
+ if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
+
+ real_t dp = p_camera->get_transform().origin.distance_to(hpos);
+ if (dp < min_d) {
+
+ r_pos = t.xform(hpos);
+ r_normal = p_camera->get_transform().basis.get_axis(2);
+ min_d = dp;
+ idx = i + handles.size();
+ }
+ }
+ }
+
+ if (p_sec_first && idx != -1) {
+
+ *r_gizmo_handle = idx;
+ return true;
+ }
+
+ min_d = 1e20;
+
+ for (int i = 0; i < handles.size(); i++) {
+
+ Vector3 hpos = t.xform(handles[i]);
+ Vector2 p = p_camera->unproject_position(hpos);
+
+ if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
+
+ real_t dp = p_camera->get_transform().origin.distance_to(hpos);
+ if (dp < min_d) {
+
+ r_pos = t.xform(hpos);
+ r_normal = p_camera->get_transform().basis.get_axis(2);
+ min_d = dp;
+ idx = i;
+ }
+ }
+ }
+
+ if (idx >= 0) {
+ *r_gizmo_handle = idx;
+ return true;
+ }
+ }
+
+ if (selectable_icon_size > 0.0f) {
+
+ 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));
+ }
+
+ float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
+
+ if (p_camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
+ float aspect = p_camera->get_viewport()->get_visible_rect().size.aspect();
+ float size = p_camera->get_size();
+ scale = size / aspect;
+ }
+
+ Point2 center = p_camera->unproject_position(t.origin);
+
+ Transform orig_camera_transform = p_camera->get_camera_transform();
+
+ 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));
+ }
+
+ Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
+ Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale);
+
+ Point2 p0 = p_camera->unproject_position(c0);
+ Point2 p1 = p_camera->unproject_position(c1);
+
+ p_camera->set_global_transform(orig_camera_transform);
+
+ Rect2 rect(p0, (p1 - p0).abs());
+
+ rect.set_position(center - rect.get_size() / 2.0);
+
+ if (rect.has_point(p_point)) {
+ r_pos = t.origin;
+ r_normal = -p_camera->project_ray_normal(p_point);
+ return true;
+ }
+
+ return false;
+ }
+
+ if (collision_segments.size()) {
+
+ Plane camp(p_camera->get_transform().origin, (-p_camera->get_transform().basis.get_axis(2)).normalized());
+
+ int vc = collision_segments.size();
+ const Vector3 *vptr = collision_segments.ptr();
+ Transform t = spatial_node->get_global_transform();
+ if (billboard_handle) {
+ t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+ }
+
+ Vector3 cp;
+ float cpd = 1e20;
+
+ for (int i = 0; i < vc / 2; i++) {
+
+ Vector3 a = t.xform(vptr[i * 2 + 0]);
+ Vector3 b = t.xform(vptr[i * 2 + 1]);
+ Vector2 s[2];
+ s[0] = p_camera->unproject_position(a);
+ s[1] = p_camera->unproject_position(b);
+
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s);
+
+ float pd = p.distance_to(p_point);
+
+ if (pd < cpd) {
+
+ float d = s[0].distance_to(s[1]);
+ Vector3 tcp;
+ if (d > 0) {
+
+ float d2 = s[0].distance_to(p) / d;
+ tcp = a + (b - a) * d2;
+
+ } else {
+ tcp = a;
+ }
+
+ if (camp.distance_to(tcp) < p_camera->get_znear())
+ continue;
+ cp = tcp;
+ cpd = pd;
+ }
+ }
+
+ if (cpd < 8) {
+
+ r_pos = cp;
+ r_normal = -p_camera->project_ray_normal(p_point);
+ return true;
+ }
+
+ return false;
+ }
+
+ if (collision_mesh.is_valid()) {
+ Transform gt = spatial_node->get_global_transform();
+
+ if (billboard_handle) {
+ gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+ }
+
+ Transform ai = gt.affine_inverse();
+ Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point));
+ Vector3 ray_dir = ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
+ Vector3 rpos, rnorm;
+
+ if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm)) {
+
+ r_pos = gt.xform(rpos);
+ r_normal = gt.basis.xform(rnorm).normalized();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void EditorNode3DGizmo::create() {
+
+ ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND(valid);
+ valid = true;
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ instances.write[i].create_instance(spatial_node, hidden);
+ }
+
+ transform();
+}
+
+void EditorNode3DGizmo::transform() {
+
+ ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND(!valid);
+ for (int i = 0; i < instances.size(); i++) {
+ RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform());
+ }
+}
+
+void EditorNode3DGizmo::free() {
+
+ ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND(!valid);
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ if (instances[i].instance.is_valid())
+ RS::get_singleton()->free(instances[i].instance);
+ instances.write[i].instance = RID();
+ }
+
+ clear();
+
+ valid = false;
+}
+
+void EditorNode3DGizmo::set_hidden(bool p_hidden) {
+ hidden = p_hidden;
+ int layer = hidden ? 0 : 1 << Node3DEditorViewport::GIZMO_EDIT_LAYER;
+ for (int i = 0; i < instances.size(); ++i) {
+ RS::get_singleton()->instance_set_layer_mask(instances[i].instance, layer);
+ }
+}
+
+void EditorNode3DGizmo::set_plugin(EditorNode3DGizmoPlugin *p_plugin) {
+ gizmo_plugin = p_plugin;
+}
+
+void EditorNode3DGizmo::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("add_lines", "lines", "material", "billboard", "modulate"), &EditorNode3DGizmo::add_lines, DEFVAL(false), DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "billboard", "skeleton", "material"), &EditorNode3DGizmo::add_mesh, DEFVAL(false), DEFVAL(Ref<SkinReference>()), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorNode3DGizmo::add_collision_segments);
+ ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorNode3DGizmo::add_collision_triangles);
+ ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale", "modulate"), &EditorNode3DGizmo::add_unscaled_billboard, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("add_handles", "handles", "material", "billboard", "secondary"), &EditorNode3DGizmo::add_handles, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorNode3DGizmo::_set_spatial_node);
+ ClassDB::bind_method(D_METHOD("get_spatial_node"), &EditorNode3DGizmo::get_spatial_node);
+ ClassDB::bind_method(D_METHOD("get_plugin"), &EditorNode3DGizmo::get_plugin);
+ ClassDB::bind_method(D_METHOD("clear"), &EditorNode3DGizmo::clear);
+ ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorNode3DGizmo::set_hidden);
+
+ BIND_VMETHOD(MethodInfo("redraw"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", PropertyInfo(Variant::INT, "index")));
+
+ MethodInfo hvget(Variant::NIL, "get_handle_value", PropertyInfo(Variant::INT, "index"));
+ hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_VMETHOD(hvget);
+
+ BIND_VMETHOD(MethodInfo("set_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point")));
+ MethodInfo cm = MethodInfo("commit_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel"));
+ cm.default_arguments.push_back(false);
+ BIND_VMETHOD(cm);
+}
+
+EditorNode3DGizmo::EditorNode3DGizmo() {
+ valid = false;
+ billboard_handle = false;
+ hidden = false;
+ base = nullptr;
+ selected = false;
+ instanced = false;
+ spatial_node = nullptr;
+ gizmo_plugin = nullptr;
+ selectable_icon_size = -1.0f;
+}
+
+EditorNode3DGizmo::~EditorNode3DGizmo() {
+
+ if (gizmo_plugin != nullptr) gizmo_plugin->unregister_gizmo(this);
+ clear();
+}
+
+Vector3 EditorNode3DGizmo::get_handle_pos(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx, handles.size(), Vector3());
+
+ return handles[p_idx];
+}
+
+//// light gizmo
+
+Light3DGizmoPlugin::Light3DGizmoPlugin() {
+
+ // Enable vertex colors for the materials below as the gizmo color depends on the light color.
+ create_material("lines_primary", Color(1, 1, 1), false, false, true);
+ create_material("lines_secondary", Color(1, 1, 1, 0.35), false, false, true);
+ create_material("lines_billboard", Color(1, 1, 1), true, false, true);
+
+ create_icon_material("light_directional_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoDirectionalLight", "EditorIcons"));
+ create_icon_material("light_omni_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoLight", "EditorIcons"));
+ create_icon_material("light_spot_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoSpotLight", "EditorIcons"));
+
+ create_handle_material("handles");
+ create_handle_material("handles_billboard", true);
+}
+
+bool Light3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Light3D>(p_spatial) != nullptr;
+}
+
+String Light3DGizmoPlugin::get_name() const {
+ return "Light3D";
+}
+
+int Light3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ if (p_idx == 0)
+ return "Radius";
+ else
+ return "Aperture";
+}
+
+Variant Light3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ if (p_idx == 0)
+ return light->get_param(Light3D::PARAM_RANGE);
+ if (p_idx == 1)
+ return light->get_param(Light3D::PARAM_SPOT_ANGLE);
+
+ return Variant();
+}
+
+static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform &p_arc_xform) {
+
+ //bleh, discrete is simpler
+ static const int arc_test_points = 64;
+ float min_d = 1e20;
+ Vector3 min_p;
+
+ for (int i = 0; i < arc_test_points; i++) {
+
+ float a = i * Math_PI * 0.5 / arc_test_points;
+ float an = (i + 1) * Math_PI * 0.5 / arc_test_points;
+ Vector3 p = Vector3(Math::cos(a), 0, -Math::sin(a)) * p_arc_radius;
+ Vector3 n = Vector3(Math::cos(an), 0, -Math::sin(an)) * p_arc_radius;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(p, n, p_from, p_to, ra, rb);
+
+ float d = ra.distance_to(rb);
+ if (d < min_d) {
+ min_d = d;
+ min_p = ra;
+ }
+ }
+
+ //min_p = p_arc_xform.affine_inverse().xform(min_p);
+ float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle();
+ return a * 180.0 / Math_PI;
+}
+
+void Light3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ Transform gt = light->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+ if (p_idx == 0) {
+
+ if (Object::cast_to<SpotLight3D>(light)) {
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), Vector3(0, 0, -4096), s[0], s[1], ra, rb);
+
+ float d = -ra.z;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d <= 0) // Equal is here for negative zero.
+ d = 0;
+
+ light->set_param(Light3D::PARAM_RANGE, d);
+ } else if (Object::cast_to<OmniLight3D>(light)) {
+
+ Plane cp = Plane(gt.origin, p_camera->get_transform().basis.get_axis(2));
+
+ Vector3 inters;
+ if (cp.intersects_ray(ray_from, ray_dir, &inters)) {
+
+ float r = inters.distance_to(gt.origin);
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ r = Math::stepify(r, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ light->set_param(Light3D::PARAM_RANGE, r);
+ }
+ }
+
+ } else if (p_idx == 1) {
+
+ float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], light->get_param(Light3D::PARAM_RANGE), gt);
+ light->set_param(Light3D::PARAM_SPOT_ANGLE, CLAMP(a, 0.01, 89.99));
+ }
+}
+
+void Light3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ if (p_cancel) {
+
+ light->set_param(p_idx == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
+
+ } else if (p_idx == 0) {
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Light Radius"));
+ ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE));
+ ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore);
+ ur->commit_action();
+ } else if (p_idx == 1) {
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Light Radius"));
+ ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE));
+ ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore);
+ ur->commit_action();
+ }
+}
+
+void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+
+ Color color = light->get_color();
+ // Make the gizmo color as bright as possible for better visibility
+ color.set_hsv(color.get_h(), color.get_s(), 1);
+
+ p_gizmo->clear();
+
+ if (Object::cast_to<DirectionalLight3D>(light)) {
+
+ Ref<Material> material = get_material("lines_primary", p_gizmo);
+ Ref<Material> icon = get_material("light_directional_icon", p_gizmo);
+
+ const int arrow_points = 7;
+ const float arrow_length = 1.5;
+
+ Vector3 arrow[arrow_points] = {
+ Vector3(0, 0, -1),
+ Vector3(0, 0.8, 0),
+ Vector3(0, 0.3, 0),
+ Vector3(0, 0.3, arrow_length),
+ Vector3(0, -0.3, arrow_length),
+ Vector3(0, -0.3, 0),
+ Vector3(0, -0.8, 0)
+ };
+
+ int arrow_sides = 2;
+
+ Vector<Vector3> lines;
+
+ for (int i = 0; i < arrow_sides; i++) {
+ for (int j = 0; j < arrow_points; j++) {
+ Basis ma(Vector3(0, 0, 1), Math_PI * i / arrow_sides);
+
+ Vector3 v1 = arrow[j] - Vector3(0, 0, arrow_length);
+ Vector3 v2 = arrow[(j + 1) % arrow_points] - Vector3(0, 0, arrow_length);
+
+ lines.push_back(ma.xform(v1));
+ lines.push_back(ma.xform(v2));
+ }
+ }
+
+ p_gizmo->add_lines(lines, material, false, color);
+ p_gizmo->add_unscaled_billboard(icon, 0.05, color);
+ }
+
+ if (Object::cast_to<OmniLight3D>(light)) {
+
+ // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation
+ const Ref<Material> lines_material = get_material("lines_secondary", p_gizmo);
+ const Ref<Material> lines_billboard_material = get_material("lines_billboard", p_gizmo);
+ const Ref<Material> icon = get_material("light_omni_icon", p_gizmo);
+
+ OmniLight3D *on = Object::cast_to<OmniLight3D>(light);
+ const float r = on->get_param(Light3D::PARAM_RANGE);
+ Vector<Vector3> points;
+ Vector<Vector3> points_billboard;
+
+ for (int i = 0; i < 120; i++) {
+
+ // Create a circle
+ const float ra = Math::deg2rad((float)(i * 3));
+ const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ // Draw axis-aligned circles
+ points.push_back(Vector3(a.x, 0, a.y));
+ points.push_back(Vector3(b.x, 0, b.y));
+ points.push_back(Vector3(0, a.x, a.y));
+ points.push_back(Vector3(0, b.x, b.y));
+ points.push_back(Vector3(a.x, a.y, 0));
+ points.push_back(Vector3(b.x, b.y, 0));
+
+ // Draw a billboarded circle
+ points_billboard.push_back(Vector3(a.x, a.y, 0));
+ points_billboard.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ p_gizmo->add_lines(points, lines_material, true, color);
+ p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
+ p_gizmo->add_unscaled_billboard(icon, 0.05, color);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(r, 0, 0));
+ p_gizmo->add_handles(handles, get_material("handles_billboard"), true);
+ }
+
+ if (Object::cast_to<SpotLight3D>(light)) {
+
+ const Ref<Material> material_primary = get_material("lines_primary", p_gizmo);
+ const Ref<Material> material_secondary = get_material("lines_secondary", p_gizmo);
+ const Ref<Material> icon = get_material("light_spot_icon", p_gizmo);
+
+ Vector<Vector3> points_primary;
+ Vector<Vector3> points_secondary;
+ SpotLight3D *sl = Object::cast_to<SpotLight3D>(light);
+
+ float r = sl->get_param(Light3D::PARAM_RANGE);
+ float w = r * Math::sin(Math::deg2rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ float d = r * Math::cos(Math::deg2rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+
+ for (int i = 0; i < 120; i++) {
+
+ // Draw a circle
+ const float ra = Math::deg2rad((float)(i * 3));
+ const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
+
+ points_primary.push_back(Vector3(a.x, a.y, -d));
+ points_primary.push_back(Vector3(b.x, b.y, -d));
+
+ if (i % 15 == 0) {
+ // Draw 8 lines from the cone origin to the sides of the circle
+ points_secondary.push_back(Vector3(a.x, a.y, -d));
+ points_secondary.push_back(Vector3());
+ }
+ }
+
+ points_primary.push_back(Vector3(0, 0, -r));
+ points_primary.push_back(Vector3());
+
+ p_gizmo->add_lines(points_primary, material_primary, false, color);
+ p_gizmo->add_lines(points_secondary, material_secondary, false, color);
+
+ const float ra = 16 * Math_PI * 2.0 / 64.0;
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(0, 0, -r));
+ handles.push_back(Vector3(a.x, a.y, -d));
+
+ p_gizmo->add_handles(handles, get_material("handles"));
+ p_gizmo->add_unscaled_billboard(icon, 0.05, color);
+ }
+}
+
+//////
+
+//// player gizmo
+AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
+
+ create_icon_material("stream_player_3d_icon", Node3DEditor::get_singleton()->get_theme_icon("Gizmo3DSamplePlayer", "EditorIcons"));
+ create_material("stream_player_3d_material_primary", gizmo_color);
+ create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35));
+ create_handle_material("handles");
+}
+
+bool AudioStreamPlayer3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<AudioStreamPlayer3D>(p_spatial) != nullptr;
+}
+
+String AudioStreamPlayer3DGizmoPlugin::get_name() const {
+ return "AudioStreamPlayer3D";
+}
+
+int AudioStreamPlayer3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String AudioStreamPlayer3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ return "Emission Radius";
+}
+
+Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+ return player->get_emission_angle();
+}
+
+void AudioStreamPlayer3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+
+ Transform gt = player->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+ Vector3 ray_to = ray_from + ray_dir * 4096;
+
+ ray_from = gi.xform(ray_from);
+ ray_to = gi.xform(ray_to);
+
+ float closest_dist = 1e20;
+ float closest_angle = 1e20;
+
+ for (int i = 0; i < 180; i++) {
+
+ float a = i * Math_PI / 180.0;
+ float an = (i + 1) * Math_PI / 180.0;
+
+ Vector3 from(Math::sin(a), 0, -Math::cos(a));
+ Vector3 to(Math::sin(an), 0, -Math::cos(an));
+
+ Vector3 r1, r2;
+ Geometry::get_closest_points_between_segments(from, to, ray_from, ray_to, r1, r2);
+ float d = r1.distance_to(r2);
+ if (d < closest_dist) {
+ closest_dist = d;
+ closest_angle = i;
+ }
+ }
+
+ if (closest_angle < 91) {
+ player->set_emission_angle(closest_angle);
+ }
+}
+
+void AudioStreamPlayer3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+
+ player->set_emission_angle(p_restore);
+
+ } else {
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle"));
+ ur->add_do_method(player, "set_emission_angle", player->get_emission_angle());
+ ur->add_undo_method(player, "set_emission_angle", p_restore);
+ ur->commit_action();
+ }
+}
+
+void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ const AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ const Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
+
+ if (player->is_emission_angle_enabled()) {
+
+ const float pc = player->get_emission_angle();
+ const float ofs = -Math::cos(Math::deg2rad(pc));
+ const float radius = Math::sin(Math::deg2rad(pc));
+
+ Vector<Vector3> points_primary;
+ points_primary.resize(200);
+
+ for (int i = 0; i < 100; i++) {
+
+ const float a = i * 2.0 * Math_PI / 100.0;
+ const float an = (i + 1) * 2.0 * Math_PI / 100.0;
+
+ const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
+ const Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs);
+
+ points_primary.write[i * 2 + 0] = from;
+ points_primary.write[i * 2 + 1] = to;
+ }
+
+ const Ref<Material> material_primary = get_material("stream_player_3d_material_primary", p_gizmo);
+ p_gizmo->add_lines(points_primary, material_primary);
+
+ Vector<Vector3> points_secondary;
+ points_secondary.resize(16);
+
+ for (int i = 0; i < 8; i++) {
+
+ const float a = i * 2.0 * Math_PI / 8.0;
+ const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
+
+ points_secondary.write[i * 2 + 0] = from;
+ points_secondary.write[i * 2 + 1] = Vector3();
+ }
+
+ const Ref<Material> material_secondary = get_material("stream_player_3d_material_secondary", p_gizmo);
+ p_gizmo->add_lines(points_secondary, material_secondary);
+
+ Vector<Vector3> handles;
+ const float ha = Math::deg2rad(player->get_emission_angle());
+ handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
+ p_gizmo->add_handles(handles, get_material("handles"));
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+}
+
+//////
+
+Camera3DGizmoPlugin::Camera3DGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
+
+ create_material("camera_material", gizmo_color);
+ create_handle_material("handles");
+}
+
+bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Camera3D>(p_spatial) != nullptr;
+}
+
+String Camera3DGizmoPlugin::get_name() const {
+ return "Camera3D";
+}
+
+int Camera3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+
+ if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
+ return "FOV";
+ } else {
+ return "Size";
+ }
+}
+
+Variant Camera3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+
+ if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
+ return camera->get_fov();
+ } else {
+
+ return camera->get_size();
+ }
+}
+
+void Camera3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+
+ Transform gt = camera->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
+ Transform gt2 = camera->get_global_transform();
+ float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt2);
+ camera->set("fov", CLAMP(a * 2.0, 1, 179));
+ } else {
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb);
+ float d = ra.x * 2.0;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ d = CLAMP(d, 0.1, 16384);
+
+ camera->set("size", d);
+ }
+}
+
+void Camera3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+
+ if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
+
+ if (p_cancel) {
+
+ camera->set("fov", p_restore);
+ } else {
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Camera FOV"));
+ ur->add_do_property(camera, "fov", camera->get_fov());
+ ur->add_undo_property(camera, "fov", p_restore);
+ ur->commit_action();
+ }
+
+ } else {
+
+ if (p_cancel) {
+
+ camera->set("size", p_restore);
+ } else {
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Camera Size"));
+ ur->add_do_property(camera, "size", camera->get_size());
+ ur->add_undo_property(camera, "size", p_restore);
+ ur->commit_action();
+ }
+ }
+}
+
+void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector<Vector3> handles;
+
+ Ref<Material> material = get_material("camera_material", p_gizmo);
+
+#define ADD_TRIANGLE(m_a, m_b, m_c) \
+ { \
+ lines.push_back(m_a); \
+ lines.push_back(m_b); \
+ lines.push_back(m_b); \
+ lines.push_back(m_c); \
+ lines.push_back(m_c); \
+ lines.push_back(m_a); \
+ }
+
+#define ADD_QUAD(m_a, m_b, m_c, m_d) \
+ { \
+ lines.push_back(m_a); \
+ lines.push_back(m_b); \
+ lines.push_back(m_b); \
+ lines.push_back(m_c); \
+ lines.push_back(m_c); \
+ lines.push_back(m_d); \
+ lines.push_back(m_d); \
+ lines.push_back(m_a); \
+ }
+
+ switch (camera->get_projection()) {
+
+ case Camera3D::PROJECTION_PERSPECTIVE: {
+
+ // The real FOV is halved for accurate representation
+ float fov = camera->get_fov() / 2.0;
+
+ Vector3 side = Vector3(Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)));
+ Vector3 nside = side;
+ nside.x = -nside.x;
+ Vector3 up = Vector3(0, side.x, 0);
+
+ ADD_TRIANGLE(Vector3(), side + up, side - up);
+ ADD_TRIANGLE(Vector3(), nside + up, nside - up);
+ ADD_TRIANGLE(Vector3(), side + up, nside + up);
+ ADD_TRIANGLE(Vector3(), side - up, nside - up);
+
+ handles.push_back(side);
+ side.x *= 0.25;
+ nside.x *= 0.25;
+ Vector3 tup(0, up.y * 3 / 2, side.z);
+ ADD_TRIANGLE(tup, side + up, nside + up);
+
+ } break;
+ case Camera3D::PROJECTION_ORTHOGONAL: {
+
+ float size = camera->get_size();
+
+ float hsize = size * 0.5;
+ Vector3 right(hsize, 0, 0);
+ Vector3 up(0, hsize, 0);
+ Vector3 back(0, 0, -1.0);
+ Vector3 front(0, 0, 0);
+
+ ADD_QUAD(-up - right, -up + right, up + right, up - right);
+ ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back);
+ ADD_QUAD(up + right, up + right + back, up - right + back, up - right);
+ ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right);
+
+ handles.push_back(right + back);
+
+ right.x *= 0.25;
+ Vector3 tup(0, up.y * 3 / 2, back.z);
+ ADD_TRIANGLE(tup, right + up + back, -right + up + back);
+
+ } break;
+ case Camera3D::PROJECTION_FRUSTUM: {
+ float hsize = camera->get_size() / 2.0;
+
+ Vector3 side = Vector3(hsize, 0, -camera->get_znear()).normalized();
+ Vector3 nside = side;
+ nside.x = -nside.x;
+ Vector3 up = Vector3(0, side.x, 0);
+ Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0);
+
+ ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset);
+ ADD_TRIANGLE(Vector3(), nside + up + offset, nside - up + offset);
+ ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset);
+ ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset);
+
+ side.x *= 0.25;
+ nside.x *= 0.25;
+ Vector3 tup(0, up.y * 3 / 2, side.z);
+ ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset);
+ }
+ }
+
+#undef ADD_TRIANGLE
+#undef ADD_QUAD
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_handles(handles, get_material("handles"));
+
+ ClippedCamera3D *clipcam = Object::cast_to<ClippedCamera3D>(camera);
+ if (clipcam) {
+ Node3D *parent = Object::cast_to<Node3D>(camera->get_parent());
+ if (!parent) {
+ return;
+ }
+ Vector3 cam_normal = -camera->get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
+ Vector3 cam_x = camera->get_global_transform().basis.get_axis(Vector3::AXIS_X).normalized();
+ Vector3 cam_y = camera->get_global_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
+ Vector3 cam_pos = camera->get_global_transform().origin;
+ Vector3 parent_pos = parent->get_global_transform().origin;
+
+ Plane parent_plane(parent_pos, cam_normal);
+ Vector3 ray_from = parent_plane.project(cam_pos);
+
+ lines.clear();
+ lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
+ lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
+
+ lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
+ lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
+
+ lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
+ lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
+
+ lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
+ lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
+
+ if (parent_plane.distance_to(cam_pos) < 0) {
+ lines.push_back(ray_from);
+ lines.push_back(cam_pos);
+ }
+
+ Transform local = camera->get_global_transform().affine_inverse();
+ for (int i = 0; i < lines.size(); i++) {
+ lines.write[i] = local.xform(lines[i]);
+ }
+
+ p_gizmo->add_lines(lines, material);
+ }
+}
+
+//////
+
+MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() {
+}
+
+bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftBody3D>(p_spatial) == nullptr;
+}
+
+String MeshInstance3DGizmoPlugin::get_name() const {
+ return "MeshInstance3D";
+}
+
+int MeshInstance3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+bool MeshInstance3DGizmoPlugin::can_be_hidden() const {
+ return false;
+}
+
+void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ MeshInstance3D *mesh = Object::cast_to<MeshInstance3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Mesh> m = mesh->get_mesh();
+
+ if (!m.is_valid())
+ return; //none
+
+ Ref<TriangleMesh> tm = m->generate_triangle_mesh();
+ if (tm.is_valid()) {
+ p_gizmo->add_collision_triangles(tm);
+ }
+}
+
+/////
+Sprite3DGizmoPlugin::Sprite3DGizmoPlugin() {
+}
+
+bool Sprite3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Sprite3D>(p_spatial) != nullptr;
+}
+
+String Sprite3DGizmoPlugin::get_name() const {
+ return "Sprite3D";
+}
+
+int Sprite3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+bool Sprite3DGizmoPlugin::can_be_hidden() const {
+ return false;
+}
+
+void Sprite3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<TriangleMesh> tm = sprite->generate_triangle_mesh();
+ if (tm.is_valid()) {
+ p_gizmo->add_collision_triangles(tm);
+ }
+}
+
+///
+
+Position3DGizmoPlugin::Position3DGizmoPlugin() {
+ pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ cursor_points = Vector<Vector3>();
+
+ Vector<Color> cursor_colors;
+ float cs = 0.25;
+ cursor_points.push_back(Vector3(+cs, 0, 0));
+ cursor_points.push_back(Vector3(-cs, 0, 0));
+ cursor_points.push_back(Vector3(0, +cs, 0));
+ cursor_points.push_back(Vector3(0, -cs, 0));
+ cursor_points.push_back(Vector3(0, 0, +cs));
+ cursor_points.push_back(Vector3(0, 0, -cs));
+ cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_x_color", "Editor"));
+ cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_x_color", "Editor"));
+ cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_y_color", "Editor"));
+ cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_y_color", "Editor"));
+ cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_z_color", "Editor"));
+ cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_z_color", "Editor"));
+
+ Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
+ mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+ d[Mesh::ARRAY_VERTEX] = cursor_points;
+ d[Mesh::ARRAY_COLOR] = cursor_colors;
+ pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
+ pos3d_mesh->surface_set_material(0, mat);
+}
+
+bool Position3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Position3D>(p_spatial) != nullptr;
+}
+
+String Position3DGizmoPlugin::get_name() const {
+ return "Position3D";
+}
+
+int Position3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void Position3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ p_gizmo->clear();
+ p_gizmo->add_mesh(pos3d_mesh);
+ p_gizmo->add_collision_segments(cursor_points);
+}
+
+/////
+
+Skeleton3DGizmoPlugin::Skeleton3DGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
+ create_material("skeleton_material", gizmo_color);
+}
+
+bool Skeleton3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Skeleton3D>(p_spatial) != nullptr;
+}
+
+String Skeleton3DGizmoPlugin::get_name() const {
+ return "Skeleton3D";
+}
+
+int Skeleton3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Material> material = get_material("skeleton_material", p_gizmo);
+
+ Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
+
+ surface_tool->begin(Mesh::PRIMITIVE_LINES);
+ surface_tool->set_material(material);
+ Vector<Transform> grests;
+ grests.resize(skel->get_bone_count());
+
+ Vector<int> bones;
+ Vector<float> weights;
+ bones.resize(4);
+ weights.resize(4);
+
+ for (int i = 0; i < 4; i++) {
+ bones.write[i] = 0;
+ weights.write[i] = 0;
+ }
+
+ weights.write[0] = 1;
+
+ AABB aabb;
+
+ Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
+ Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
+
+ for (int i_bone = 0; i_bone < skel->get_bone_count(); i_bone++) {
+
+ int i = skel->get_process_order(i_bone);
+
+ int parent = skel->get_bone_parent(i);
+
+ if (parent >= 0) {
+ grests.write[i] = grests[parent] * skel->get_bone_rest(i);
+
+ Vector3 v0 = grests[parent].origin;
+ Vector3 v1 = grests[i].origin;
+ Vector3 d = (v1 - v0).normalized();
+ float dist = v0.distance_to(v1);
+
+ //find closest axis
+ int closest = -1;
+ float closest_d = 0.0;
+
+ for (int j = 0; j < 3; j++) {
+ float dp = Math::abs(grests[parent].basis[j].normalized().dot(d));
+ if (j == 0 || dp > closest_d)
+ closest = j;
+ }
+
+ //find closest other
+ Vector3 first;
+ Vector3 points[4];
+ int pointidx = 0;
+ for (int j = 0; j < 3; j++) {
+
+ bones.write[0] = parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(rootcolor);
+ surface_tool->add_vertex(v0 - grests[parent].basis[j].normalized() * dist * 0.05);
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(rootcolor);
+ surface_tool->add_vertex(v0 + grests[parent].basis[j].normalized() * dist * 0.05);
+
+ if (j == closest)
+ continue;
+
+ Vector3 axis;
+ if (first == Vector3()) {
+ axis = d.cross(d.cross(grests[parent].basis[j])).normalized();
+ first = axis;
+ } else {
+ axis = d.cross(first).normalized();
+ }
+
+ for (int k = 0; k < 2; k++) {
+
+ if (k == 1)
+ axis = -axis;
+ Vector3 point = v0 + d * dist * 0.2;
+ point += axis * dist * 0.1;
+
+ bones.write[0] = parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(v0);
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(point);
+
+ bones.write[0] = parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(point);
+ bones.write[0] = i;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(v1);
+ points[pointidx++] = point;
+ }
+ }
+
+ SWAP(points[1], points[2]);
+ for (int j = 0; j < 4; j++) {
+
+ bones.write[0] = parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(points[j]);
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(points[(j + 1) % 4]);
+ }
+
+ /*
+ bones[0]=parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(0.4,1,0.4,0.4));
+ surface_tool->add_vertex(v0);
+ bones[0]=i;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(0.4,1,0.4,0.4));
+ surface_tool->add_vertex(v1);
+*/
+ } else {
+
+ grests.write[i] = skel->get_bone_rest(i);
+ bones.write[0] = i;
+ }
+ /*
+ Transform t = grests[i];
+ t.orthonormalize();
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+
+ for(int j=0;j<4;j++) {
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
+ surface_tool->add_vertex(t.xform(face_points[j]*0.04));
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
+ surface_tool->add_vertex(t.xform(face_points[(j+1)%4]*0.04));
+ }
+
+ }
+ */
+ }
+
+ Ref<ArrayMesh> m = surface_tool->commit();
+ p_gizmo->add_mesh(m, false, skel->register_skin(Ref<Skin>()));
+}
+
+////
+
+PhysicalBone3DGizmoPlugin::PhysicalBone3DGizmoPlugin() {
+ create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
+}
+
+bool PhysicalBone3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<PhysicalBone3D>(p_spatial) != nullptr;
+}
+
+String PhysicalBone3DGizmoPlugin::get_name() const {
+ return "PhysicalBone3D";
+}
+
+int PhysicalBone3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void PhysicalBone3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ p_gizmo->clear();
+
+ PhysicalBone3D *physical_bone = Object::cast_to<PhysicalBone3D>(p_gizmo->get_spatial_node());
+
+ if (!physical_bone)
+ return;
+
+ Skeleton3D *sk(physical_bone->find_skeleton_parent());
+ if (!sk)
+ return;
+
+ PhysicalBone3D *pb(sk->get_physical_bone(physical_bone->get_bone_id()));
+ if (!pb)
+ return;
+
+ PhysicalBone3D *pbp(sk->get_physical_bone_parent(physical_bone->get_bone_id()));
+ if (!pbp)
+ return;
+
+ Vector<Vector3> points;
+
+ switch (physical_bone->get_joint_type()) {
+ case PhysicalBone3D::JOINT_TYPE_PIN: {
+
+ Joint3DGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points);
+ } break;
+ case PhysicalBone3D::JOINT_TYPE_CONE: {
+
+ const PhysicalBone3D::ConeJointData *cjd(static_cast<const PhysicalBone3D::ConeJointData *>(physical_bone->get_joint_data()));
+ Joint3DGizmoPlugin::CreateConeTwistJointGizmo(
+ physical_bone->get_joint_offset(),
+ physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
+ pb->get_global_transform(),
+ pbp->get_global_transform(),
+ cjd->swing_span,
+ cjd->twist_span,
+ &points,
+ &points);
+ } break;
+ case PhysicalBone3D::JOINT_TYPE_HINGE: {
+
+ const PhysicalBone3D::HingeJointData *hjd(static_cast<const PhysicalBone3D::HingeJointData *>(physical_bone->get_joint_data()));
+ Joint3DGizmoPlugin::CreateHingeJointGizmo(
+ physical_bone->get_joint_offset(),
+ physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
+ pb->get_global_transform(),
+ pbp->get_global_transform(),
+ hjd->angular_limit_lower,
+ hjd->angular_limit_upper,
+ hjd->angular_limit_enabled,
+ points,
+ &points,
+ &points);
+ } break;
+ case PhysicalBone3D::JOINT_TYPE_SLIDER: {
+
+ const PhysicalBone3D::SliderJointData *sjd(static_cast<const PhysicalBone3D::SliderJointData *>(physical_bone->get_joint_data()));
+ Joint3DGizmoPlugin::CreateSliderJointGizmo(
+ physical_bone->get_joint_offset(),
+ physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
+ pb->get_global_transform(),
+ pbp->get_global_transform(),
+ sjd->angular_limit_lower,
+ sjd->angular_limit_upper,
+ sjd->linear_limit_lower,
+ sjd->linear_limit_upper,
+ points,
+ &points,
+ &points);
+ } break;
+ case PhysicalBone3D::JOINT_TYPE_6DOF: {
+
+ const PhysicalBone3D::SixDOFJointData *sdofjd(static_cast<const PhysicalBone3D::SixDOFJointData *>(physical_bone->get_joint_data()));
+ Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo(
+ physical_bone->get_joint_offset(),
+
+ physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
+ pb->get_global_transform(),
+ pbp->get_global_transform(),
+
+ sdofjd->axis_data[0].angular_limit_lower,
+ sdofjd->axis_data[0].angular_limit_upper,
+ sdofjd->axis_data[0].linear_limit_lower,
+ sdofjd->axis_data[0].linear_limit_upper,
+ sdofjd->axis_data[0].angular_limit_enabled,
+ sdofjd->axis_data[0].linear_limit_enabled,
+
+ sdofjd->axis_data[1].angular_limit_lower,
+ sdofjd->axis_data[1].angular_limit_upper,
+ sdofjd->axis_data[1].linear_limit_lower,
+ sdofjd->axis_data[1].linear_limit_upper,
+ sdofjd->axis_data[1].angular_limit_enabled,
+ sdofjd->axis_data[1].linear_limit_enabled,
+
+ sdofjd->axis_data[2].angular_limit_lower,
+ sdofjd->axis_data[2].angular_limit_upper,
+ sdofjd->axis_data[2].linear_limit_lower,
+ sdofjd->axis_data[2].linear_limit_upper,
+ sdofjd->axis_data[2].angular_limit_enabled,
+ sdofjd->axis_data[2].linear_limit_enabled,
+
+ points,
+ &points,
+ &points);
+ } break;
+ default:
+ return;
+ }
+
+ Ref<Material> material = get_material("joint_material", p_gizmo);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_lines(points, material);
+}
+
+/////
+
+RayCast3DGizmoPlugin::RayCast3DGizmoPlugin() {
+
+ 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 RayCast3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<RayCast3D>(p_spatial) != nullptr;
+}
+
+String RayCast3DGizmoPlugin::get_name() const {
+ return "RayCast3D";
+}
+
+int RayCast3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void RayCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ RayCast3D *raycast = Object::cast_to<RayCast3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+
+ lines.push_back(Vector3());
+ lines.push_back(raycast->get_cast_to());
+
+ const Ref<StandardMaterial3D> material =
+ get_material(raycast->is_enabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+}
+
+/////
+
+void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ SpringArm3D *spring_arm = Object::cast_to<SpringArm3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+
+ lines.push_back(Vector3());
+ lines.push_back(Vector3(0, 0, 1.0) * spring_arm->get_length());
+
+ Ref<StandardMaterial3D> material = get_material("shape_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+}
+
+SpringArm3DGizmoPlugin::SpringArm3DGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+}
+
+bool SpringArm3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<SpringArm3D>(p_spatial) != nullptr;
+}
+
+String SpringArm3DGizmoPlugin::get_name() const {
+ return "SpringArm3D";
+}
+
+int SpringArm3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+/////
+
+VehicleWheel3DGizmoPlugin::VehicleWheel3DGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+}
+
+bool VehicleWheel3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<VehicleWheel3D>(p_spatial) != nullptr;
+}
+
+String VehicleWheel3DGizmoPlugin::get_name() const {
+ return "VehicleWheel3D";
+}
+
+int VehicleWheel3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ VehicleWheel3D *car_wheel = Object::cast_to<VehicleWheel3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> points;
+
+ float r = car_wheel->get_radius();
+ const int skip = 10;
+ for (int i = 0; i <= 360; i += skip) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + skip);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ points.push_back(Vector3(0, a.x, a.y));
+ points.push_back(Vector3(0, b.x, b.y));
+
+ const int springsec = 4;
+
+ for (int j = 0; j < springsec; j++) {
+ float t = car_wheel->get_suspension_rest_length() * 5;
+ points.push_back(Vector3(a.x, i / 360.0 * t / springsec + j * (t / springsec), a.y) * 0.2);
+ points.push_back(Vector3(b.x, (i + skip) / 360.0 * t / springsec + j * (t / springsec), b.y) * 0.2);
+ }
+ }
+
+ //travel
+ points.push_back(Vector3(0, 0, 0));
+ points.push_back(Vector3(0, car_wheel->get_suspension_rest_length(), 0));
+
+ //axis
+ points.push_back(Vector3(r * 0.2, car_wheel->get_suspension_rest_length(), 0));
+ points.push_back(Vector3(-r * 0.2, car_wheel->get_suspension_rest_length(), 0));
+ //axis
+ points.push_back(Vector3(r * 0.2, 0, 0));
+ points.push_back(Vector3(-r * 0.2, 0, 0));
+
+ //forward line
+ points.push_back(Vector3(0, -r, 0));
+ points.push_back(Vector3(0, -r, r * 2));
+ points.push_back(Vector3(0, -r, r * 2));
+ points.push_back(Vector3(r * 2 * 0.2, -r, r * 2 * 0.8));
+ points.push_back(Vector3(0, -r, r * 2));
+ points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8));
+
+ Ref<Material> material = get_material("shape_material", p_gizmo);
+
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
+}
+
+///////////
+
+SoftBody3DGizmoPlugin::SoftBody3DGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+ create_handle_material("handles");
+}
+
+bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<SoftBody3D>(p_spatial) != nullptr;
+}
+
+String SoftBody3DGizmoPlugin::get_name() const {
+ return "SoftBody3D";
+}
+
+int SoftBody3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
+
+void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ if (!soft_body || soft_body->get_mesh().is_null()) {
+ return;
+ }
+
+ // find mesh
+
+ Vector<Vector3> lines;
+
+ soft_body->get_mesh()->generate_debug_mesh_lines(lines);
+
+ if (!lines.size()) {
+ return;
+ }
+
+ Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh();
+
+ Vector<Vector3> points;
+ soft_body->get_mesh()->generate_debug_mesh_indices(points);
+
+ Ref<Material> material = get_material("shape_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_handles(points, get_material("handles"));
+ p_gizmo->add_collision_triangles(tm);
+}
+
+String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ return "SoftBody3D pin point";
+}
+
+Variant SoftBody3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ return Variant(soft_body->is_point_pinned(p_idx));
+}
+
+void SoftBody3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ soft_body->pin_point_toggle(p_idx);
+}
+
+bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int idx) const {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ return soft_body->is_point_pinned(idx);
+}
+
+///////////
+
+VisibilityNotifier3DGizmoPlugin::VisibilityNotifier3DGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7));
+ create_material("visibility_notifier_material", gizmo_color);
+ gizmo_color.a = 0.1;
+ create_material("visibility_notifier_solid_material", gizmo_color);
+ create_handle_material("handles");
+}
+
+bool VisibilityNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<VisibilityNotifier3D>(p_spatial) != nullptr;
+}
+
+String VisibilityNotifier3DGizmoPlugin::get_name() const {
+ return "VisibilityNotifier3D";
+}
+
+int VisibilityNotifier3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String VisibilityNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Size X";
+ case 1: return "Size Y";
+ case 2: return "Size Z";
+ case 3: return "Pos X";
+ case 4: return "Pos Y";
+ case 5: return "Pos Z";
+ }
+
+ return "";
+}
+
+Variant VisibilityNotifier3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node());
+ return notifier->get_aabb();
+}
+void VisibilityNotifier3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node());
+
+ Transform gt = notifier->get_global_transform();
+
+ Transform gi = gt.affine_inverse();
+
+ bool move = p_idx >= 3;
+ p_idx = p_idx % 3;
+
+ AABB aabb = notifier->get_aabb();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ Vector3 ofs = aabb.position + aabb.size * 0.5;
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ if (move) {
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
+ notifier->set_aabb(aabb);
+
+ } else {
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx] - ofs[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+ //resize
+ aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
+ aabb.size[p_idx] = d * 2;
+ notifier->set_aabb(aabb);
+ }
+}
+
+void VisibilityNotifier3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+ notifier->set_aabb(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Notifier AABB"));
+ ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
+ ur->add_undo_method(notifier, "set_aabb", p_restore);
+ ur->commit_action();
+}
+
+void VisibilityNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ AABB aabb = notifier->get_aabb();
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
+ ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
+ handles.push_back(ax);
+ }
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = 1.0;
+ handles.push_back(center + ax);
+ lines.push_back(center);
+ lines.push_back(center + ax);
+ }
+
+ Ref<Material> material = get_material("visibility_notifier_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+ }
+
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+////
+
+CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() {
+ create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoCPUParticles3D", "EditorIcons"));
+}
+
+bool CPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<CPUParticles3D>(p_spatial) != nullptr;
+}
+
+String CPUParticles3DGizmoPlugin::get_name() const {
+ return "CPUParticles3D";
+}
+
+int CPUParticles3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+bool CPUParticles3DGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
+
+void CPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ Ref<Material> icon = get_material("particles_icon", p_gizmo);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+}
+
+////
+
+GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
+ create_material("particles_material", gizmo_color);
+ gizmo_color.a = 0.1;
+ create_material("particles_solid_material", gizmo_color);
+ create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoGPUParticles3D", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+bool GPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<GPUParticles3D>(p_spatial) != nullptr;
+}
+
+String GPUParticles3DGizmoPlugin::get_name() const {
+ return "GPUParticles3D";
+}
+
+int GPUParticles3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+bool GPUParticles3DGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
+
+String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Size X";
+ case 1: return "Size Y";
+ case 2: return "Size Z";
+ case 3: return "Pos X";
+ case 4: return "Pos Y";
+ case 5: return "Pos Z";
+ }
+
+ return "";
+}
+Variant GPUParticles3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+ return particles->get_visibility_aabb();
+}
+void GPUParticles3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+
+ Transform gt = particles->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ bool move = p_idx >= 3;
+ p_idx = p_idx % 3;
+
+ AABB aabb = particles->get_visibility_aabb();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ Vector3 ofs = aabb.position + aabb.size * 0.5;
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ if (move) {
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
+ particles->set_visibility_aabb(aabb);
+
+ } else {
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
+
+ float d = ra[p_idx] - ofs[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+ //resize
+ aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
+ aabb.size[p_idx] = d * 2;
+ particles->set_visibility_aabb(aabb);
+ }
+}
+
+void GPUParticles3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+ particles->set_visibility_aabb(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Particles AABB"));
+ ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
+ ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
+ ur->commit_action();
+}
+
+void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ AABB aabb = particles->get_visibility_aabb();
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
+ ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
+ handles.push_back(ax);
+ }
+
+ Vector3 center = aabb.position + aabb.size * 0.5;
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = 1.0;
+ handles.push_back(center + ax);
+ lines.push_back(center);
+ lines.push_back(center + ax);
+ }
+
+ Ref<Material> material = get_material("particles_material", p_gizmo);
+ Ref<Material> icon = get_material("particles_icon", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+ }
+
+ p_gizmo->add_handles(handles, get_material("handles"));
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+}
+////
+
+ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
+
+ create_material("reflection_probe_material", gizmo_color);
+
+ gizmo_color.a = 0.5;
+ create_material("reflection_internal_material", gizmo_color);
+
+ gizmo_color.a = 0.1;
+ create_material("reflection_probe_solid_material", gizmo_color);
+
+ create_icon_material("reflection_probe_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoReflectionProbe", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+bool ReflectionProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<ReflectionProbe>(p_spatial) != nullptr;
+}
+
+String ReflectionProbeGizmoPlugin::get_name() const {
+ return "ReflectionProbe";
+}
+
+int ReflectionProbeGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ case 3: return "Origin X";
+ case 4: return "Origin Y";
+ case 5: return "Origin Z";
+ }
+
+ return "";
+}
+Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ return AABB(probe->get_extents(), probe->get_origin_offset());
+}
+void ReflectionProbeGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ Transform gt = probe->get_global_transform();
+
+ Transform gi = gt.affine_inverse();
+
+ if (p_idx < 3) {
+ Vector3 extents = probe->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ probe->set_extents(extents);
+ } else {
+
+ p_idx -= 3;
+
+ Vector3 origin = probe->get_origin_offset();
+ origin[p_idx] = 0;
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb);
+ // Adjust the actual position to account for the gizmo handle position
+ float d = ra[p_idx] + 0.25;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ origin[p_idx] = d;
+ probe->set_origin_offset(origin);
+ }
+}
+
+void ReflectionProbeGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+
+ AABB restore = p_restore;
+
+ if (p_cancel) {
+ probe->set_extents(restore.position);
+ probe->set_origin_offset(restore.size);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Probe Extents"));
+ ur->add_do_method(probe, "set_extents", probe->get_extents());
+ ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
+ ur->add_undo_method(probe, "set_extents", restore.position);
+ ur->add_undo_method(probe, "set_origin_offset", restore.size);
+ ur->commit_action();
+}
+
+void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector<Vector3> internal_lines;
+ Vector3 extents = probe->get_extents();
+
+ AABB aabb;
+ aabb.position = -extents;
+ aabb.size = extents * 2;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ for (int i = 0; i < 8; i++) {
+ Vector3 ep = aabb.get_endpoint(i);
+ internal_lines.push_back(probe->get_origin_offset());
+ internal_lines.push_back(ep);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 orig_handle = probe->get_origin_offset();
+ orig_handle[i] -= 0.25;
+ lines.push_back(orig_handle);
+ handles.push_back(orig_handle);
+
+ orig_handle[i] += 0.5;
+ lines.push_back(orig_handle);
+ }
+
+ Ref<Material> material = get_material("reflection_probe_material", p_gizmo);
+ Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo);
+ Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_lines(internal_lines, material_internal);
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, probe->get_extents() * 2.0);
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+///////////////////////////////
+
+////
+
+DecalGizmoPlugin::DecalGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0));
+
+ create_material("decal_material", gizmo_color);
+
+ create_handle_material("handles");
+}
+
+bool DecalGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Decal>(p_spatial) != nullptr;
+}
+
+String DecalGizmoPlugin::get_name() const {
+ return "Decal";
+}
+
+int DecalGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ }
+
+ return "";
+}
+Variant DecalGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+ return decal->get_extents();
+}
+void DecalGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+ Transform gt = decal->get_global_transform();
+
+ Transform gi = gt.affine_inverse();
+
+ Vector3 extents = decal->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ decal->set_extents(extents);
+}
+
+void DecalGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+
+ Vector3 restore = p_restore;
+
+ if (p_cancel) {
+ decal->set_extents(restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Decal Extents"));
+ ur->add_do_method(decal, "set_extents", decal->get_extents());
+ ur->add_undo_method(decal, "set_extents", restore);
+ ur->commit_action();
+}
+
+void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector3 extents = decal->get_extents();
+
+ AABB aabb;
+ aabb.position = -extents;
+ aabb.size = extents * 2;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ if (a.y == b.y) {
+ lines.push_back(a);
+ lines.push_back(b);
+ } else {
+ Vector3 ah = a.linear_interpolate(b, 0.2);
+ lines.push_back(a);
+ lines.push_back(ah);
+ Vector3 bh = b.linear_interpolate(a, 0.2);
+ lines.push_back(b);
+ lines.push_back(bh);
+ }
+ }
+
+ lines.push_back(Vector3(0, extents.y, 0));
+ lines.push_back(Vector3(0, extents.y * 1.2, 0));
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ Ref<Material> material = get_material("decal_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+///////////////////////////////
+GIProbeGizmoPlugin::GIProbeGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6));
+
+ create_material("gi_probe_material", gizmo_color);
+
+ // This gizmo draws a lot of lines. Use a low opacity to make it not too intrusive.
+ gizmo_color.a = 0.1;
+ create_material("gi_probe_internal_material", gizmo_color);
+
+ gizmo_color.a = 0.05;
+ create_material("gi_probe_solid_material", gizmo_color);
+
+ create_icon_material("gi_probe_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoGIProbe", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+bool GIProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<GIProbe>(p_spatial) != nullptr;
+}
+
+String GIProbeGizmoPlugin::get_name() const {
+ return "GIProbe";
+}
+
+int GIProbeGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String GIProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ }
+
+ return "";
+}
+Variant GIProbeGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+ return probe->get_extents();
+}
+void GIProbeGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+
+ Transform gt = probe->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 extents = probe->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ probe->set_extents(extents);
+}
+
+void GIProbeGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+
+ Vector3 restore = p_restore;
+
+ if (p_cancel) {
+ probe->set_extents(restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Probe Extents"));
+ ur->add_do_method(probe, "set_extents", probe->get_extents());
+ ur->add_undo_method(probe, "set_extents", restore);
+ ur->commit_action();
+}
+
+void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
+
+ Ref<Material> material = get_material("gi_probe_material", p_gizmo);
+ Ref<Material> icon = get_material("gi_probe_icon", p_gizmo);
+ Ref<Material> material_internal = get_material("gi_probe_internal_material", p_gizmo);
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector3 extents = probe->get_extents();
+
+ static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 };
+
+ AABB aabb = AABB(-extents, extents * 2);
+ int subdiv = subdivs[probe->get_subdiv()];
+ float cell_size = aabb.get_longest_axis_size() / subdiv;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ p_gizmo->add_lines(lines, material);
+
+ lines.clear();
+
+ for (int i = 1; i < subdiv; i++) {
+
+ for (int j = 0; j < 3; j++) {
+
+ if (cell_size * i > aabb.size[j]) {
+ continue;
+ }
+
+ Vector2 dir;
+ dir[j] = 1.0;
+ Vector2 ta, tb;
+ int j_n1 = (j + 1) % 3;
+ int j_n2 = (j + 2) % 3;
+ ta[j_n1] = 1.0;
+ tb[j_n2] = 1.0;
+
+ for (int k = 0; k < 4; k++) {
+
+ Vector3 from = aabb.position, to = aabb.position;
+ from[j] += cell_size * i;
+ to[j] += cell_size * i;
+
+ if (k & 1) {
+ to[j_n1] += aabb.size[j_n1];
+ } else {
+
+ to[j_n2] += aabb.size[j_n2];
+ }
+
+ if (k & 2) {
+ from[j_n1] += aabb.size[j_n1];
+ from[j_n2] += aabb.size[j_n2];
+ }
+
+ lines.push_back(from);
+ lines.push_back(to);
+ }
+ }
+ }
+
+ p_gizmo->add_lines(lines, material_internal);
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size());
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+
+////
+#if 0
+BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
+
+ create_material("baked_indirect_light_material", gizmo_color);
+
+ gizmo_color.a = 0.1;
+ create_material("baked_indirect_light_internal_material", gizmo_color);
+
+ create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons"));
+ create_handle_material("handles");
+}
+
+String BakedIndirectLightGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ switch (p_idx) {
+ case 0: return "Extents X";
+ case 1: return "Extents Y";
+ case 2: return "Extents Z";
+ }
+
+ return "";
+}
+Variant BakedIndirectLightGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+ return baker->get_extents();
+}
+void BakedIndirectLightGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+
+ Transform gt = baker->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 extents = baker->get_extents();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ extents[p_idx] = d;
+ baker->set_extents(extents);
+}
+
+void BakedIndirectLightGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+
+ Vector3 restore = p_restore;
+
+ if (p_cancel) {
+ baker->set_extents(restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Probe Extents"));
+ ur->add_do_method(baker, "set_extents", baker->get_extents());
+ ur->add_undo_method(baker, "set_extents", restore);
+ ur->commit_action();
+}
+
+bool BakedIndirectLightGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<BakedLightmap>(p_spatial) != nullptr;
+}
+
+String BakedIndirectLightGizmoPlugin::get_name() const {
+ return "BakedLightmap";
+}
+
+int BakedIndirectLightGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void BakedIndirectLightGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
+
+ Ref<Material> material = get_material("baked_indirect_light_material", p_gizmo);
+ Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo);
+ Ref<Material> material_internal = get_material("baked_indirect_light_internal_material", p_gizmo);
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+ Vector3 extents = baker->get_extents();
+
+ AABB aabb = AABB(-extents, extents * 2);
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ p_gizmo->add_lines(lines, material);
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ if (p_gizmo->is_selected()) {
+ p_gizmo->add_solid_box(material_internal, aabb.get_size());
+ }
+
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+ p_gizmo->add_handles(handles, get_material("handles"));
+}
+#endif
+////
+
+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);
+ 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);
+ create_handle_material("handles");
+}
+
+bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<CollisionShape3D>(p_spatial) != nullptr;
+}
+
+String CollisionShape3DGizmoPlugin::get_name() const {
+ return "CollisionShape3D";
+}
+
+int CollisionShape3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ const CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+
+ Ref<Shape3D> s = cs->get_shape();
+ if (s.is_null())
+ return "";
+
+ if (Object::cast_to<SphereShape3D>(*s)) {
+
+ return "Radius";
+ }
+
+ if (Object::cast_to<BoxShape3D>(*s)) {
+
+ return "Extents";
+ }
+
+ if (Object::cast_to<CapsuleShape3D>(*s)) {
+
+ return p_idx == 0 ? "Radius" : "Height";
+ }
+
+ if (Object::cast_to<CylinderShape3D>(*s)) {
+
+ return p_idx == 0 ? "Radius" : "Height";
+ }
+
+ if (Object::cast_to<RayShape3D>(*s)) {
+
+ return "Length";
+ }
+
+ return "";
+}
+
+Variant CollisionShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+
+ Ref<Shape3D> s = cs->get_shape();
+ if (s.is_null())
+ return Variant();
+
+ if (Object::cast_to<SphereShape3D>(*s)) {
+
+ Ref<SphereShape3D> ss = s;
+ return ss->get_radius();
+ }
+
+ if (Object::cast_to<BoxShape3D>(*s)) {
+
+ Ref<BoxShape3D> bs = s;
+ return bs->get_extents();
+ }
+
+ if (Object::cast_to<CapsuleShape3D>(*s)) {
+
+ Ref<CapsuleShape3D> cs2 = s;
+ return p_idx == 0 ? cs2->get_radius() : cs2->get_height();
+ }
+
+ if (Object::cast_to<CylinderShape3D>(*s)) {
+
+ Ref<CylinderShape3D> cs2 = s;
+ return p_idx == 0 ? cs2->get_radius() : cs2->get_height();
+ }
+
+ if (Object::cast_to<RayShape3D>(*s)) {
+
+ Ref<RayShape3D> cs2 = s;
+ return cs2->get_length();
+ }
+
+ return Variant();
+}
+void CollisionShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+
+ Ref<Shape3D> s = cs->get_shape();
+ if (s.is_null())
+ return;
+
+ Transform gt = cs->get_global_transform();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ if (Object::cast_to<SphereShape3D>(*s)) {
+
+ Ref<SphereShape3D> ss = s;
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
+ float d = ra.x;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ ss->set_radius(d);
+ }
+
+ if (Object::cast_to<RayShape3D>(*s)) {
+
+ Ref<RayShape3D> rs = s;
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb);
+ float d = ra.z;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ rs->set_length(d);
+ }
+
+ if (Object::cast_to<BoxShape3D>(*s)) {
+
+ Vector3 axis;
+ axis[p_idx] = 1.0;
+ Ref<BoxShape3D> bs = s;
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ float d = ra[p_idx];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ Vector3 he = bs->get_extents();
+ he[p_idx] = d;
+ bs->set_extents(he);
+ }
+
+ if (Object::cast_to<CapsuleShape3D>(*s)) {
+
+ Vector3 axis;
+ axis[p_idx == 0 ? 0 : 2] = 1.0;
+ Ref<CapsuleShape3D> cs2 = s;
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ float d = axis.dot(ra);
+ if (p_idx == 1)
+ d -= cs2->get_radius();
+
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ if (p_idx == 0)
+ cs2->set_radius(d);
+ else if (p_idx == 1)
+ cs2->set_height(d * 2.0);
+ }
+
+ if (Object::cast_to<CylinderShape3D>(*s)) {
+
+ Vector3 axis;
+ axis[p_idx == 0 ? 0 : 1] = 1.0;
+ Ref<CylinderShape3D> cs2 = s;
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ float d = axis.dot(ra);
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001)
+ d = 0.001;
+
+ if (p_idx == 0)
+ cs2->set_radius(d);
+ else if (p_idx == 1)
+ cs2->set_height(d * 2.0);
+ }
+}
+void CollisionShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+
+ Ref<Shape3D> s = cs->get_shape();
+ if (s.is_null())
+ return;
+
+ if (Object::cast_to<SphereShape3D>(*s)) {
+
+ Ref<SphereShape3D> ss = s;
+ if (p_cancel) {
+ ss->set_radius(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Sphere Shape Radius"));
+ ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
+ ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
+ ur->commit_action();
+ }
+
+ if (Object::cast_to<BoxShape3D>(*s)) {
+
+ Ref<BoxShape3D> ss = s;
+ if (p_cancel) {
+ ss->set_extents(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Box Shape Extents"));
+ ur->add_do_method(ss.ptr(), "set_extents", ss->get_extents());
+ ur->add_undo_method(ss.ptr(), "set_extents", p_restore);
+ ur->commit_action();
+ }
+
+ if (Object::cast_to<CapsuleShape3D>(*s)) {
+
+ Ref<CapsuleShape3D> ss = s;
+ if (p_cancel) {
+ if (p_idx == 0)
+ ss->set_radius(p_restore);
+ else
+ ss->set_height(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ if (p_idx == 0) {
+ ur->create_action(TTR("Change Capsule Shape Radius"));
+ ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
+ ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
+ } else {
+ ur->create_action(TTR("Change Capsule Shape Height"));
+ ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
+ ur->add_undo_method(ss.ptr(), "set_height", p_restore);
+ }
+
+ ur->commit_action();
+ }
+
+ if (Object::cast_to<CylinderShape3D>(*s)) {
+
+ Ref<CylinderShape3D> ss = s;
+ if (p_cancel) {
+ if (p_idx == 0)
+ ss->set_radius(p_restore);
+ else
+ ss->set_height(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ if (p_idx == 0) {
+ ur->create_action(TTR("Change Cylinder Shape Radius"));
+ ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
+ ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
+ } else {
+ ur->create_action(
+ ///
+
+ ////////
+ TTR("Change Cylinder Shape Height"));
+ ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
+ ur->add_undo_method(ss.ptr(), "set_height", p_restore);
+ }
+
+ ur->commit_action();
+ }
+
+ if (Object::cast_to<RayShape3D>(*s)) {
+
+ Ref<RayShape3D> ss = s;
+ if (p_cancel) {
+ ss->set_length(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Ray Shape Length"));
+ ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
+ ur->add_undo_method(ss.ptr(), "set_length", p_restore);
+ ur->commit_action();
+ }
+}
+void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Shape3D> s = cs->get_shape();
+ if (s.is_null())
+ return;
+
+ const Ref<Material> material =
+ get_material(!cs->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
+ Ref<Material> handles_material = get_material("handles");
+
+ if (Object::cast_to<SphereShape3D>(*s)) {
+
+ Ref<SphereShape3D> sp = s;
+ float r = sp->get_radius();
+
+ Vector<Vector3> points;
+
+ for (int i = 0; i <= 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ points.push_back(Vector3(a.x, 0, a.y));
+ points.push_back(Vector3(b.x, 0, b.y));
+ points.push_back(Vector3(0, a.x, a.y));
+ points.push_back(Vector3(0, b.x, b.y));
+ points.push_back(Vector3(a.x, a.y, 0));
+ points.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ Vector<Vector3> collision_segments;
+
+ for (int i = 0; i < 64; i++) {
+
+ float ra = i * Math_PI * 2.0 / 64.0;
+ float rb = (i + 1) * Math_PI * 2.0 / 64.0;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y));
+ collision_segments.push_back(Vector3(b.x, 0, b.y));
+ collision_segments.push_back(Vector3(0, a.x, a.y));
+ collision_segments.push_back(Vector3(0, b.x, b.y));
+ collision_segments.push_back(Vector3(a.x, a.y, 0));
+ collision_segments.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(collision_segments);
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(r, 0, 0));
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<BoxShape3D>(*s)) {
+
+ Ref<BoxShape3D> bs = s;
+ Vector<Vector3> lines;
+ AABB aabb;
+ aabb.position = -bs->get_extents();
+ aabb.size = aabb.position * -2;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ax;
+ ax[i] = bs->get_extents()[i];
+ handles.push_back(ax);
+ }
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<CapsuleShape3D>(*s)) {
+
+ Ref<CapsuleShape3D> cs2 = s;
+ float radius = cs2->get_radius();
+ float height = cs2->get_height();
+
+ Vector<Vector3> points;
+
+ Vector3 d(0, height * 0.5, 0);
+ for (int i = 0; i < 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(b.x, 0, b.y) + d);
+
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ points.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 90 == 0) {
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+
+ Vector3 dud = i < 180 ? d : -d;
+
+ points.push_back(Vector3(0, a.x, a.y) + dud);
+ points.push_back(Vector3(0, b.x, b.y) + dud);
+ points.push_back(Vector3(a.y, a.x, 0) + dud);
+ points.push_back(Vector3(b.y, b.x, 0) + dud);
+ }
+
+ p_gizmo->add_lines(points, material);
+
+ Vector<Vector3> collision_segments;
+
+ for (int i = 0; i < 64; i++) {
+
+ float ra = i * Math_PI * 2.0 / 64.0;
+ float rb = (i + 1) * Math_PI * 2.0 / 64.0;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
+ collision_segments.push_back(Vector3(b.x, 0, b.y) + d);
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
+ collision_segments.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 16 == 0) {
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
+ collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+
+ Vector3 dud = i < 32 ? d : -d;
+
+ collision_segments.push_back(Vector3(0, a.x, a.y) + dud);
+ collision_segments.push_back(Vector3(0, b.x, b.y) + dud);
+ collision_segments.push_back(Vector3(a.y, a.x, 0) + dud);
+ collision_segments.push_back(Vector3(b.y, b.x, 0) + dud);
+ }
+
+ p_gizmo->add_collision_segments(collision_segments);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(cs2->get_radius(), 0, 0));
+ handles.push_back(Vector3(0, cs2->get_height() * 0.5 + cs2->get_radius(), 0));
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<CylinderShape3D>(*s)) {
+
+ Ref<CylinderShape3D> cs2 = s;
+ float radius = cs2->get_radius();
+ float height = cs2->get_height();
+
+ Vector<Vector3> points;
+
+ Vector3 d(0, height * 0.5, 0);
+ for (int i = 0; i < 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(b.x, 0, b.y) + d);
+
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ points.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 90 == 0) {
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+ }
+
+ p_gizmo->add_lines(points, material);
+
+ Vector<Vector3> collision_segments;
+
+ for (int i = 0; i < 64; i++) {
+
+ float ra = i * Math_PI * 2.0 / 64.0;
+ float rb = (i + 1) * Math_PI * 2.0 / 64.0;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
+ collision_segments.push_back(Vector3(b.x, 0, b.y) + d);
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
+ collision_segments.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 16 == 0) {
+
+ collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
+ collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+ }
+
+ p_gizmo->add_collision_segments(collision_segments);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(cs2->get_radius(), 0, 0));
+ handles.push_back(Vector3(0, cs2->get_height() * 0.5, 0));
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<WorldMarginShape3D>(*s)) {
+
+ Ref<WorldMarginShape3D> ps = s;
+ Plane p = ps->get_plane();
+ Vector<Vector3> points;
+
+ Vector3 n1 = p.get_any_perpendicular_normal();
+ Vector3 n2 = p.normal.cross(n1).normalized();
+
+ Vector3 pface[4] = {
+ p.normal * p.d + n1 * 10.0 + n2 * 10.0,
+ p.normal * p.d + n1 * 10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * 10.0,
+ };
+
+ points.push_back(pface[0]);
+ points.push_back(pface[1]);
+ points.push_back(pface[1]);
+ points.push_back(pface[2]);
+ points.push_back(pface[2]);
+ points.push_back(pface[3]);
+ points.push_back(pface[3]);
+ points.push_back(pface[0]);
+ points.push_back(p.normal * p.d);
+ points.push_back(p.normal * p.d + p.normal * 3);
+
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
+ }
+
+ if (Object::cast_to<ConvexPolygonShape3D>(*s)) {
+
+ Vector<Vector3> points = Object::cast_to<ConvexPolygonShape3D>(*s)->get_points();
+
+ if (points.size() > 3) {
+
+ Vector<Vector3> varr = Variant(points);
+ Geometry::MeshData md;
+ Error err = QuickHull::build(varr, md);
+ if (err == OK) {
+ Vector<Vector3> points2;
+ points2.resize(md.edges.size() * 2);
+ for (int i = 0; i < md.edges.size(); i++) {
+ points2.write[i * 2 + 0] = md.vertices[md.edges[i].a];
+ points2.write[i * 2 + 1] = md.vertices[md.edges[i].b];
+ }
+
+ p_gizmo->add_lines(points2, material);
+ p_gizmo->add_collision_segments(points2);
+ }
+ }
+ }
+
+ if (Object::cast_to<ConcavePolygonShape3D>(*s)) {
+
+ Ref<ConcavePolygonShape3D> cs2 = s;
+ Ref<ArrayMesh> mesh = cs2->get_debug_mesh();
+ p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), material);
+ p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines());
+ }
+
+ if (Object::cast_to<RayShape3D>(*s)) {
+
+ Ref<RayShape3D> rs = s;
+
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ points.push_back(Vector3(0, 0, rs->get_length()));
+ p_gizmo->add_lines(points, material);
+ p_gizmo->add_collision_segments(points);
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(0, 0, rs->get_length()));
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<HeightMapShape3D>(*s)) {
+
+ Ref<HeightMapShape3D> hms = s;
+
+ Ref<ArrayMesh> mesh = hms->get_debug_mesh();
+ p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), material);
+ }
+}
+
+/////
+
+CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() {
+ 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 CollisionPolygon3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<CollisionPolygon3D>(p_spatial) != nullptr;
+}
+
+String CollisionPolygon3DGizmoPlugin::get_name() const {
+ return "CollisionPolygon3D";
+}
+
+int CollisionPolygon3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ CollisionPolygon3D *polygon = Object::cast_to<CollisionPolygon3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector2> points = polygon->get_polygon();
+ float depth = polygon->get_depth() * 0.5;
+
+ Vector<Vector3> lines;
+ for (int i = 0; i < points.size(); i++) {
+
+ int n = (i + 1) % points.size();
+ lines.push_back(Vector3(points[i].x, points[i].y, depth));
+ lines.push_back(Vector3(points[n].x, points[n].y, depth));
+ lines.push_back(Vector3(points[i].x, points[i].y, -depth));
+ lines.push_back(Vector3(points[n].x, points[n].y, -depth));
+ lines.push_back(Vector3(points[i].x, points[i].y, depth));
+ lines.push_back(Vector3(points[i].x, points[i].y, -depth));
+ }
+
+ const Ref<Material> material =
+ get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+}
+
+////
+
+NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() {
+ create_material("navigation_edge_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)));
+ create_material("navigation_edge_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)));
+ create_material("navigation_solid_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)));
+ create_material("navigation_solid_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4)));
+}
+
+bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<NavigationRegion3D>(p_spatial) != nullptr;
+}
+
+String NavigationRegion3DGizmoPlugin::get_name() const {
+ return "NavigationRegion3D";
+}
+
+int NavigationRegion3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+
+ NavigationRegion3D *navmesh = Object::cast_to<NavigationRegion3D>(p_gizmo->get_spatial_node());
+
+ Ref<Material> edge_material = get_material("navigation_edge_material", p_gizmo);
+ Ref<Material> edge_material_disabled = get_material("navigation_edge_material_disabled", p_gizmo);
+ Ref<Material> solid_material = get_material("navigation_solid_material", p_gizmo);
+ Ref<Material> solid_material_disabled = get_material("navigation_solid_material_disabled", p_gizmo);
+
+ p_gizmo->clear();
+ Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
+ if (navmeshie.is_null())
+ return;
+
+ Vector<Vector3> vertices = navmeshie->get_vertices();
+ const Vector3 *vr = vertices.ptr();
+ List<Face3> faces;
+ for (int i = 0; i < navmeshie->get_polygon_count(); i++) {
+ Vector<int> p = navmeshie->get_polygon(i);
+
+ for (int j = 2; j < p.size(); j++) {
+ Face3 f;
+ f.vertex[0] = vr[p[0]];
+ f.vertex[1] = vr[p[j - 1]];
+ f.vertex[2] = vr[p[j]];
+
+ faces.push_back(f);
+ }
+ }
+
+ if (faces.empty())
+ return;
+
+ Map<_EdgeKey, bool> edge_map;
+ Vector<Vector3> tmeshfaces;
+ tmeshfaces.resize(faces.size() * 3);
+
+ {
+ Vector3 *tw = tmeshfaces.ptrw();
+ int tidx = 0;
+
+ for (List<Face3>::Element *E = faces.front(); E; E = E->next()) {
+
+ const Face3 &f = E->get();
+
+ for (int j = 0; j < 3; j++) {
+
+ tw[tidx++] = f.vertex[j];
+ _EdgeKey ek;
+ ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
+ if (ek.from < ek.to)
+ SWAP(ek.from, ek.to);
+
+ Map<_EdgeKey, bool>::Element *F = edge_map.find(ek);
+
+ if (F) {
+
+ F->get() = false;
+
+ } else {
+
+ edge_map[ek] = true;
+ }
+ }
+ }
+ }
+ Vector<Vector3> lines;
+
+ for (Map<_EdgeKey, bool>::Element *E = edge_map.front(); E; E = E->next()) {
+
+ if (E->get()) {
+ lines.push_back(E->key().from);
+ lines.push_back(E->key().to);
+ }
+ }
+
+ Ref<TriangleMesh> tmesh = memnew(TriangleMesh);
+ tmesh->create(tmeshfaces);
+
+ if (lines.size())
+ p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled);
+ p_gizmo->add_collision_triangles(tmesh);
+ Ref<ArrayMesh> m = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[0] = tmeshfaces;
+ m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+ m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled);
+ p_gizmo->add_mesh(m);
+ p_gizmo->add_collision_segments(lines);
+}
+
+//////
+
+#define BODY_A_RADIUS 0.25
+#define BODY_B_RADIUS 0.27
+
+Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Transform &p_body_transform) {
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
+
+ Vector3 v_x, v_y, v_z;
+
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
+
+ v_z = v_x.cross(Vector3(0, 1, 0));
+ v_z.normalize();
+
+ v_y = v_z.cross(v_x);
+ v_y.normalize();
+
+ Basis base;
+ base.set(v_x, v_y, v_z);
+
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
+
+ return base;
+}
+
+Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform) {
+
+ switch (p_axis) {
+ case Vector3::AXIS_X:
+ return look_body_toward_x(joint_transform, body_transform);
+ case Vector3::AXIS_Y:
+ return look_body_toward_y(joint_transform, body_transform);
+ case Vector3::AXIS_Z:
+ return look_body_toward_z(joint_transform, body_transform);
+ default:
+ return Basis();
+ }
+}
+
+Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform) {
+
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
+
+ const Vector3 p_front(p_joint_transform.basis.get_axis(0));
+
+ Vector3 v_x, v_y, v_z;
+
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
+
+ v_y = p_front.cross(v_x);
+ v_y.normalize();
+
+ v_z = v_y.cross(p_front);
+ v_z.normalize();
+
+ // Clamp X to FRONT axis
+ v_x = p_front;
+ v_x.normalize();
+
+ Basis base;
+ base.set(v_x, v_y, v_z);
+
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
+
+ return base;
+}
+
+Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform) {
+
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
+
+ const Vector3 p_up(p_joint_transform.basis.get_axis(1));
+
+ Vector3 v_x, v_y, v_z;
+
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
+
+ v_z = v_x.cross(p_up);
+ v_z.normalize();
+
+ v_x = p_up.cross(v_z);
+ v_x.normalize();
+
+ // Clamp Y to UP axis
+ v_y = p_up;
+ v_y.normalize();
+
+ Basis base;
+ base.set(v_x, v_y, v_z);
+
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
+
+ return base;
+}
+
+Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform) {
+
+ const Vector3 &p_eye(p_joint_transform.origin);
+ const Vector3 &p_target(p_body_transform.origin);
+
+ const Vector3 p_lateral(p_joint_transform.basis.get_axis(2));
+
+ Vector3 v_x, v_y, v_z;
+
+ // Look the body with X
+ v_x = p_target - p_eye;
+ v_x.normalize();
+
+ v_z = p_lateral;
+ v_z.normalize();
+
+ v_y = v_z.cross(v_x);
+ v_y.normalize();
+
+ // Clamp X to Z axis
+ v_x = v_y.cross(v_z);
+ v_x.normalize();
+
+ Basis base;
+ base.set(v_x, v_y, v_z);
+
+ // Absorb current joint transform
+ base = p_joint_transform.basis.inverse() * base;
+
+ return base;
+}
+
+void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) {
+
+ if (p_limit_lower == p_limit_upper) {
+
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(0.5, 0, 0))).origin);
+
+ } else {
+
+ if (p_limit_lower > p_limit_upper) {
+ p_limit_lower = -Math_PI;
+ p_limit_upper = Math_PI;
+ }
+
+ const int points = 32;
+
+ for (int i = 0; i < points; i++) {
+
+ real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points;
+ real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points;
+
+ Vector3 from;
+ Vector3 to;
+ switch (p_axis) {
+ case Vector3::AXIS_X:
+ if (p_inverse) {
+ from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius;
+ to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius;
+ } else {
+ from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius;
+ to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius;
+ }
+ break;
+ case Vector3::AXIS_Y:
+ if (p_inverse) {
+ from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius;
+ to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius;
+ } else {
+ from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius;
+ to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius;
+ }
+ break;
+ case Vector3::AXIS_Z:
+ from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius;
+ to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius;
+ break;
+ }
+
+ if (i == points - 1) {
+ r_points.push_back(p_offset.translated(to).origin);
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ }
+ if (i == 0) {
+ r_points.push_back(p_offset.translated(from).origin);
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ }
+
+ r_points.push_back(p_offset.translated(from).origin);
+ r_points.push_back(p_offset.translated(to).origin);
+ }
+
+ r_points.push_back(p_offset.translated(Vector3(0, p_radius * 1.5, 0)).origin);
+ r_points.push_back(p_offset.translated(Vector3()).origin);
+ }
+}
+
+void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) {
+
+ float r = 1.0;
+ float w = r * Math::sin(p_swing);
+ float d = r * Math::cos(p_swing);
+
+ //swing
+ for (int i = 0; i < 360; i += 10) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 10);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
+
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, b.x, b.y))).origin);
+
+ if (i % 90 == 0) {
+
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin);
+ }
+ }
+
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(1, 0, 0))).origin);
+
+ /// Twist
+ float ts = Math::rad2deg(p_twist);
+ ts = MIN(ts, 720);
+
+ for (int i = 0; i < int(ts); i += 5) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 5);
+ float c = i / 720.0;
+ float cn = (i + 5) / 720.0;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn;
+
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(c, a.x, a.y))).origin);
+ r_points.push_back(p_offset.translated(p_base.xform(Vector3(cn, b.x, b.y))).origin);
+ }
+}
+
+////
+
+Joint3DGizmoPlugin::Joint3DGizmoPlugin() {
+ create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
+ create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)));
+ create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)));
+}
+
+bool Joint3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Joint3D>(p_spatial) != nullptr;
+}
+
+String Joint3DGizmoPlugin::get_name() const {
+ return "Joint3D";
+}
+
+int Joint3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ Joint3D *joint = Object::cast_to<Joint3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Node3D *node_body_a = nullptr;
+ if (!joint->get_node_a().is_empty()) {
+ node_body_a = Object::cast_to<Node3D>(joint->get_node(joint->get_node_a()));
+ }
+
+ Node3D *node_body_b = nullptr;
+ if (!joint->get_node_b().is_empty()) {
+ node_body_b = Object::cast_to<Node3D>(joint->get_node(joint->get_node_b()));
+ }
+
+ if (!node_body_a && !node_body_b) {
+ return;
+ }
+
+ Ref<Material> common_material = get_material("joint_material", p_gizmo);
+ Ref<Material> body_a_material = get_material("joint_body_a_material", p_gizmo);
+ Ref<Material> body_b_material = get_material("joint_body_b_material", p_gizmo);
+
+ Vector<Vector3> points;
+ Vector<Vector3> body_a_points;
+ Vector<Vector3> body_b_points;
+
+ if (Object::cast_to<PinJoint3D>(joint)) {
+ CreatePinJointGizmo(Transform(), points);
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_lines(points, common_material);
+ }
+
+ HingeJoint3D *hinge = Object::cast_to<HingeJoint3D>(joint);
+ if (hinge) {
+
+ CreateHingeJointGizmo(
+ Transform(),
+ hinge->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ hinge->get_param(HingeJoint3D::PARAM_LIMIT_LOWER),
+ hinge->get_param(HingeJoint3D::PARAM_LIMIT_UPPER),
+ hinge->get_flag(HingeJoint3D::FLAG_USE_LIMIT),
+ points,
+ node_body_a ? &body_a_points : nullptr,
+ node_body_b ? &body_b_points : nullptr);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(points, common_material);
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+
+ SliderJoint3D *slider = Object::cast_to<SliderJoint3D>(joint);
+ if (slider) {
+
+ CreateSliderJointGizmo(
+ Transform(),
+ slider->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_LOWER),
+ slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_UPPER),
+ slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_LOWER),
+ slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_UPPER),
+ points,
+ node_body_a ? &body_a_points : nullptr,
+ node_body_b ? &body_b_points : nullptr);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(points, common_material);
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+
+ ConeTwistJoint3D *cone = Object::cast_to<ConeTwistJoint3D>(joint);
+ if (cone) {
+
+ CreateConeTwistJointGizmo(
+ Transform(),
+ cone->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+ cone->get_param(ConeTwistJoint3D::PARAM_SWING_SPAN),
+ cone->get_param(ConeTwistJoint3D::PARAM_TWIST_SPAN),
+ node_body_a ? &body_a_points : nullptr,
+ node_body_b ? &body_b_points : nullptr);
+
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+
+ Generic6DOFJoint3D *gen = Object::cast_to<Generic6DOFJoint3D>(joint);
+ if (gen) {
+
+ CreateGeneric6DOFJointGizmo(
+ Transform(),
+ gen->get_global_transform(),
+ node_body_a ? node_body_a->get_global_transform() : Transform(),
+ node_body_b ? node_body_b->get_global_transform() : Transform(),
+
+ gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT),
+ gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT),
+ gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT),
+ gen->get_param_x(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT),
+ gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT),
+ gen->get_flag_x(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT),
+
+ gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT),
+ gen->get_param_y(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT),
+ gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT),
+ gen->get_param_y(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT),
+ gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT),
+ gen->get_flag_y(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT),
+
+ gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT),
+ gen->get_param_z(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT),
+ gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_LOWER_LIMIT),
+ gen->get_param_z(Generic6DOFJoint3D::PARAM_LINEAR_UPPER_LIMIT),
+ gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_ANGULAR_LIMIT),
+ gen->get_flag_z(Generic6DOFJoint3D::FLAG_ENABLE_LINEAR_LIMIT),
+
+ points,
+ node_body_a ? &body_a_points : nullptr,
+ node_body_a ? &body_b_points : nullptr);
+
+ p_gizmo->add_collision_segments(points);
+ p_gizmo->add_collision_segments(body_a_points);
+ p_gizmo->add_collision_segments(body_b_points);
+
+ p_gizmo->add_lines(points, common_material);
+ p_gizmo->add_lines(body_a_points, body_a_material);
+ p_gizmo->add_lines(body_b_points, body_b_material);
+ }
+}
+
+void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) {
+ float cs = 0.25;
+
+ r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin);
+ r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin);
+}
+
+void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+
+ r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
+ r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
+
+ if (!p_use_limit) {
+ p_limit_upper = -1;
+ p_limit_lower = 0;
+ }
+
+ if (r_body_a_points) {
+
+ JointGizmosDrawer::draw_circle(Vector3::AXIS_Z,
+ BODY_A_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a),
+ p_limit_lower,
+ p_limit_upper,
+ *r_body_a_points);
+ }
+
+ if (r_body_b_points) {
+ JointGizmosDrawer::draw_circle(Vector3::AXIS_Z,
+ BODY_B_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b),
+ p_limit_lower,
+ p_limit_upper,
+ *r_body_b_points);
+ }
+}
+
+void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+
+ p_linear_limit_lower = -p_linear_limit_lower;
+ p_linear_limit_upper = -p_linear_limit_upper;
+
+ float cs = 0.25;
+ r_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
+ r_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
+
+ if (p_linear_limit_lower >= p_linear_limit_upper) {
+
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, 0, 0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, 0, 0)).origin);
+
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin);
+
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin);
+ r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin);
+
+ } else {
+
+ r_points.push_back(p_offset.translated(Vector3(+cs * 2, 0, 0)).origin);
+ r_points.push_back(p_offset.translated(Vector3(-cs * 2, 0, 0)).origin);
+ }
+
+ if (r_body_a_points)
+ JointGizmosDrawer::draw_circle(
+ Vector3::AXIS_X,
+ BODY_A_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a),
+ p_angular_limit_lower,
+ p_angular_limit_upper,
+ *r_body_a_points);
+
+ if (r_body_b_points)
+ JointGizmosDrawer::draw_circle(
+ Vector3::AXIS_X,
+ BODY_B_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b),
+ p_angular_limit_lower,
+ p_angular_limit_upper,
+ *r_body_b_points,
+ true);
+}
+
+void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
+
+ if (r_body_a_points)
+ JointGizmosDrawer::draw_cone(
+ p_offset,
+ JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a),
+ p_swing,
+ p_twist,
+ *r_body_a_points);
+
+ if (r_body_b_points)
+ JointGizmosDrawer::draw_cone(
+ p_offset,
+ JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b),
+ p_swing,
+ p_twist,
+ *r_body_b_points);
+}
+
+void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo(
+ const Transform &p_offset,
+ const Transform &p_trs_joint,
+ const Transform &p_trs_body_a,
+ const Transform &p_trs_body_b,
+ real_t p_angular_limit_lower_x,
+ real_t p_angular_limit_upper_x,
+ real_t p_linear_limit_lower_x,
+ real_t p_linear_limit_upper_x,
+ bool p_enable_angular_limit_x,
+ bool p_enable_linear_limit_x,
+ real_t p_angular_limit_lower_y,
+ real_t p_angular_limit_upper_y,
+ real_t p_linear_limit_lower_y,
+ real_t p_linear_limit_upper_y,
+ bool p_enable_angular_limit_y,
+ bool p_enable_linear_limit_y,
+ real_t p_angular_limit_lower_z,
+ real_t p_angular_limit_upper_z,
+ real_t p_linear_limit_lower_z,
+ real_t p_linear_limit_upper_z,
+ bool p_enable_angular_limit_z,
+ bool p_enable_linear_limit_z,
+ Vector<Vector3> &r_points,
+ Vector<Vector3> *r_body_a_points,
+ Vector<Vector3> *r_body_b_points) {
+
+ float cs = 0.25;
+
+ for (int ax = 0; ax < 3; ax++) {
+ float ll = 0;
+ float ul = 0;
+ float lll = 0;
+ float lul = 0;
+
+ int a1 = 0;
+ int a2 = 0;
+ int a3 = 0;
+ bool enable_ang = false;
+ bool enable_lin = false;
+
+ switch (ax) {
+ case 0:
+ ll = p_angular_limit_lower_x;
+ ul = p_angular_limit_upper_x;
+ lll = -p_linear_limit_lower_x;
+ lul = -p_linear_limit_upper_x;
+ enable_ang = p_enable_angular_limit_x;
+ enable_lin = p_enable_linear_limit_x;
+ a1 = 0;
+ a2 = 1;
+ a3 = 2;
+ break;
+ case 1:
+ ll = p_angular_limit_lower_y;
+ ul = p_angular_limit_upper_y;
+ lll = -p_linear_limit_lower_y;
+ lul = -p_linear_limit_upper_y;
+ enable_ang = p_enable_angular_limit_y;
+ enable_lin = p_enable_linear_limit_y;
+ a1 = 1;
+ a2 = 2;
+ a3 = 0;
+ break;
+ case 2:
+ ll = p_angular_limit_lower_z;
+ ul = p_angular_limit_upper_z;
+ lll = -p_linear_limit_lower_z;
+ lul = -p_linear_limit_upper_z;
+ enable_ang = p_enable_angular_limit_z;
+ enable_lin = p_enable_linear_limit_z;
+ a1 = 2;
+ a2 = 0;
+ a3 = 1;
+ break;
+ }
+
+#define ADD_VTX(x, y, z) \
+ { \
+ Vector3 v; \
+ v[a1] = (x); \
+ v[a2] = (y); \
+ v[a3] = (z); \
+ r_points.push_back(p_offset.translated(v).origin); \
+ }
+
+ if (enable_lin && lll >= lul) {
+
+ ADD_VTX(lul, 0, 0);
+ ADD_VTX(lll, 0, 0);
+
+ ADD_VTX(lul, -cs, -cs);
+ ADD_VTX(lul, -cs, cs);
+ ADD_VTX(lul, -cs, cs);
+ ADD_VTX(lul, cs, cs);
+ ADD_VTX(lul, cs, cs);
+ ADD_VTX(lul, cs, -cs);
+ ADD_VTX(lul, cs, -cs);
+ ADD_VTX(lul, -cs, -cs);
+
+ ADD_VTX(lll, -cs, -cs);
+ ADD_VTX(lll, -cs, cs);
+ ADD_VTX(lll, -cs, cs);
+ ADD_VTX(lll, cs, cs);
+ ADD_VTX(lll, cs, cs);
+ ADD_VTX(lll, cs, -cs);
+ ADD_VTX(lll, cs, -cs);
+ ADD_VTX(lll, -cs, -cs);
+
+ } else {
+
+ ADD_VTX(+cs * 2, 0, 0);
+ ADD_VTX(-cs * 2, 0, 0);
+ }
+
+ if (!enable_ang) {
+ ll = 0;
+ ul = -1;
+ }
+
+ if (r_body_a_points)
+ JointGizmosDrawer::draw_circle(
+ static_cast<Vector3::Axis>(ax),
+ BODY_A_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_a),
+ ll,
+ ul,
+ *r_body_a_points,
+ true);
+
+ if (r_body_b_points)
+ JointGizmosDrawer::draw_circle(
+ static_cast<Vector3::Axis>(ax),
+ BODY_B_RADIUS,
+ p_offset,
+ JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_b),
+ ll,
+ ul,
+ *r_body_b_points);
+ }
+
+#undef ADD_VTX
+}
diff --git a/editor/node_3d_editor_gizmos.h b/editor/node_3d_editor_gizmos.h
new file mode 100644
index 0000000000..8bc52b6ba9
--- /dev/null
+++ b/editor/node_3d_editor_gizmos.h
@@ -0,0 +1,452 @@
+/*************************************************************************/
+/* node_3d_editor_gizmos.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPATIAL_EDITOR_GIZMOS_H
+#define SPATIAL_EDITOR_GIZMOS_H
+
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
+
+class Camera3D;
+
+class Light3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Light3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ Light3DGizmoPlugin();
+};
+
+class AudioStreamPlayer3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(AudioStreamPlayer3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ AudioStreamPlayer3DGizmoPlugin();
+};
+
+class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ Camera3DGizmoPlugin();
+};
+
+class MeshInstance3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(MeshInstance3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ bool can_be_hidden() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ MeshInstance3DGizmoPlugin();
+};
+
+class Sprite3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Sprite3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ bool can_be_hidden() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ Sprite3DGizmoPlugin();
+};
+
+class Position3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Position3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+ Ref<ArrayMesh> pos3d_mesh;
+ Vector<Vector3> cursor_points;
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ Position3DGizmoPlugin();
+};
+
+class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Skeleton3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ Skeleton3DGizmoPlugin();
+};
+
+class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(PhysicalBone3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ PhysicalBone3DGizmoPlugin();
+};
+
+class RayCast3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(RayCast3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ RayCast3DGizmoPlugin();
+};
+
+class SpringArm3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(SpringArm3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ SpringArm3DGizmoPlugin();
+};
+
+class VehicleWheel3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(VehicleWheel3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ VehicleWheel3DGizmoPlugin();
+};
+
+class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(SoftBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
+ bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int idx) const;
+
+ SoftBody3DGizmoPlugin();
+};
+
+class VisibilityNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(VisibilityNotifier3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ VisibilityNotifier3DGizmoPlugin();
+};
+
+class CPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(CPUParticles3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+ CPUParticles3DGizmoPlugin();
+};
+
+class GPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(GPUParticles3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ GPUParticles3DGizmoPlugin();
+};
+
+class ReflectionProbeGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(ReflectionProbeGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ ReflectionProbeGizmoPlugin();
+};
+
+class DecalGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(DecalGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ DecalGizmoPlugin();
+};
+
+class GIProbeGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(GIProbeGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ GIProbeGizmoPlugin();
+};
+
+#if 0
+class BakedIndirectLightGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(BakedIndirectLightGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ BakedIndirectLightGizmoPlugin();
+};
+#endif
+class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ CollisionShape3DGizmoPlugin();
+};
+
+class CollisionPolygon3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(CollisionPolygon3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+ CollisionPolygon3DGizmoPlugin();
+};
+
+class NavigationRegion3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(NavigationRegion3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+ struct _EdgeKey {
+
+ Vector3 from;
+ Vector3 to;
+
+ bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; }
+ };
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ NavigationRegion3DGizmoPlugin();
+};
+
+class JointGizmosDrawer {
+public:
+ static Basis look_body(const Transform &p_joint_transform, const Transform &p_body_transform);
+ static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform);
+ static Basis look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform);
+ static Basis look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform);
+ /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis
+ /// with axis X and Y that are looking toward the body and oriented toward up
+ static Basis look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform);
+
+ // Draw circle around p_axis
+ static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse = false);
+ static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points);
+};
+
+class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Joint3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial);
+ String get_name() const;
+ int get_priority() const;
+ void redraw(EditorNode3DGizmo *p_gizmo);
+
+ static void CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points);
+ static void CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+ static void CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+ static void CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
+ static void CreateGeneric6DOFJointGizmo(
+ const Transform &p_offset,
+ const Transform &p_trs_joint,
+ const Transform &p_trs_body_a,
+ const Transform &p_trs_body_b,
+ real_t p_angular_limit_lower_x,
+ real_t p_angular_limit_upper_x,
+ real_t p_linear_limit_lower_x,
+ real_t p_linear_limit_upper_x,
+ bool p_enable_angular_limit_x,
+ bool p_enable_linear_limit_x,
+ real_t p_angular_limit_lower_y,
+ real_t p_angular_limit_upper_y,
+ real_t p_linear_limit_lower_y,
+ real_t p_linear_limit_upper_y,
+ bool p_enable_angular_limit_y,
+ bool p_enable_linear_limit_y,
+ real_t p_angular_limit_lower_z,
+ real_t p_angular_limit_upper_z,
+ real_t p_linear_limit_lower_z,
+ real_t p_linear_limit_upper_z,
+ bool p_enable_angular_limit_z,
+ bool p_enable_linear_limit_z,
+ Vector<Vector3> &r_points,
+ Vector<Vector3> *r_body_a_points,
+ Vector<Vector3> *r_body_b_points);
+
+ Joint3DGizmoPlugin();
+};
+
+#endif // SPATIAL_EDITOR_GIZMOS_H
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 3013406152..a076b1eecc 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -55,12 +55,12 @@ void NodeDock::_bind_methods() {
void NodeDock::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- connections_button->set_icon(get_icon("Signals", "EditorIcons"));
- groups_button->set_icon(get_icon("Groups", "EditorIcons"));
+ connections_button->set_icon(get_theme_icon("Signals", "EditorIcons"));
+ groups_button->set_icon(get_theme_icon("Groups", "EditorIcons"));
}
}
-NodeDock *NodeDock::singleton = NULL;
+NodeDock *NodeDock::singleton = nullptr;
void NodeDock::update_lists() {
diff --git a/editor/pane_drag.cpp b/editor/pane_drag.cpp
index b143f86ada..ce90fa94dc 100644
--- a/editor/pane_drag.cpp
+++ b/editor/pane_drag.cpp
@@ -45,7 +45,7 @@ void PaneDrag::_notification(int p_what) {
case NOTIFICATION_DRAW: {
- Ref<Texture2D> icon = mouse_over ? get_icon("PaneDragHover", "EditorIcons") : get_icon("PaneDrag", "EditorIcons");
+ Ref<Texture2D> icon = mouse_over ? get_theme_icon("PaneDragHover", "EditorIcons") : get_theme_icon("PaneDrag", "EditorIcons");
if (!icon.is_null())
icon->draw(get_canvas_item(), Point2(0, 0));
@@ -62,7 +62,7 @@ void PaneDrag::_notification(int p_what) {
}
Size2 PaneDrag::get_minimum_size() const {
- Ref<Texture2D> icon = get_icon("PaneDrag", "EditorIcons");
+ Ref<Texture2D> icon = get_theme_icon("PaneDrag", "EditorIcons");
if (!icon.is_null())
return icon->get_size();
return Size2();
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 1e7c625abb..4317a5e80f 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -131,14 +131,15 @@ void PluginConfigDialog::_on_required_text_changed(const String &) {
void PluginConfigDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+ name_edit->grab_focus();
+ }
+ } break;
case NOTIFICATION_READY: {
connect("confirmed", callable_mp(this, &PluginConfigDialog::_on_confirmed));
get_cancel()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_cancelled));
} break;
-
- case NOTIFICATION_POST_POPUP: {
- name_edit->grab_focus();
- } break;
}
}
diff --git a/editor/plugins/SCsub b/editor/plugins/SCsub
index 2b1e889fb0..359d04e5df 100644
--- a/editor/plugins/SCsub
+++ b/editor/plugins/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.editor_sources, "*.cpp")
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 8d5444db73..c26daa3857 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -204,9 +204,9 @@ void AbstractPolygon2DEditor::_notification(int p_what) {
disable_polygon_editing(false, String());
- button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
- button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
- button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons"));
+ button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons"));
+ button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons"));
+ button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons"));
button_edit->set_pressed(true);
get_tree()->connect("node_removed", callable_mp(this, &AbstractPolygon2DEditor::_node_removed));
@@ -218,7 +218,7 @@ void AbstractPolygon2DEditor::_notification(int p_what) {
void AbstractPolygon2DEditor::_node_removed(Node *p_node) {
if (p_node == _get_node()) {
- edit(NULL);
+ edit(nullptr);
hide();
canvas_item_editor->update_viewport();
@@ -310,7 +310,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
create_resource->set_text(String("No polygon resource on this node.\nCreate and assign one?"));
- create_resource->popup_centered_minsize();
+ create_resource->popup_centered();
}
return (mb.is_valid() && mb->get_button_index() == 1);
}
@@ -573,7 +573,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
// All polygon points are sharp, so use the sharp handle icon
- const Ref<Texture2D> handle = get_icon("EditorPathSharpHandle", "EditorIcons");
+ const Ref<Texture2D> handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons");
const Vertex active_point = get_active_point();
const int n_polygons = _get_polygon_count();
@@ -651,7 +651,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, modulate);
if (vertex == hover_point) {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
String num = String::num(vertex.vertex);
Size2 num_size = font->get_string_size(num);
p_overlay->draw_string(font, point - num_size * 0.5, num, Color(1.0, 1.0, 1.0, 0.5));
@@ -661,7 +661,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
if (edge_point.valid()) {
- Ref<Texture2D> add_handle = get_icon("EditorHandleAdd", "EditorIcons");
+ Ref<Texture2D> add_handle = get_theme_icon("EditorHandleAdd", "EditorIcons");
p_overlay->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5);
}
}
@@ -690,7 +690,7 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {
canvas_item_editor->update_viewport();
} else {
- _set_node(NULL);
+ _set_node(nullptr);
}
}
@@ -801,7 +801,7 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c
AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive) {
- canvas_item_editor = NULL;
+ canvas_item_editor = nullptr;
editor = p_editor;
undo_redo = EditorNode::get_undo_redo();
@@ -854,7 +854,7 @@ void AbstractPolygon2DEditorPlugin::make_visible(bool p_visible) {
} else {
polygon_editor->hide();
- polygon_editor->edit(NULL);
+ polygon_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 7916ac71ea..eb50df2166 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -73,7 +73,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
ap->get_animation_list(&names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get());
+ animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get());
animations_to_add.push_back(E->get());
}
}
@@ -97,7 +97,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
menu->add_separator();
menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
+ menu->set_position(blend_space_draw->get_screen_transform().xform(mb->get_position()));
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
@@ -197,18 +197,18 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
- Color linecolor = get_color("font_color", "Label");
+ Color linecolor = get_theme_color("font_color", "Label");
Color linecolor_soft = linecolor;
linecolor_soft.a *= 0.5;
- Ref<Font> font = get_font("font", "Label");
- Ref<Texture2D> icon = get_icon("KeyValue", "EditorIcons");
- Ref<Texture2D> icon_selected = get_icon("KeySelected", "EditorIcons");
+ Ref<Font> font = get_theme_font("font", "Label");
+ Ref<Texture2D> icon = get_theme_icon("KeyValue", "EditorIcons");
+ Ref<Texture2D> icon_selected = get_theme_icon("KeySelected", "EditorIcons");
Size2 s = blend_space_draw->get_size();
if (blend_space_draw->has_focus()) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);
}
@@ -280,7 +280,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
{
Color color;
if (tool_blend->is_pressed()) {
- color = get_color("accent_color", "Editor");
+ color = get_theme_color("accent_color", "Editor");
} else {
color = linecolor;
color.a *= 0.5;
@@ -532,15 +532,15 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() {
void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
- panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- tool_blend->set_icon(get_icon("EditPivot", "EditorIcons"));
- tool_select->set_icon(get_icon("ToolSelect", "EditorIcons"));
- tool_create->set_icon(get_icon("EditKey", "EditorIcons"));
- tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
- snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
- open_editor->set_icon(get_icon("Edit", "EditorIcons"));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ tool_blend->set_icon(get_theme_icon("EditPivot", "EditorIcons"));
+ tool_select->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tool_create->set_icon(get_theme_icon("EditKey", "EditorIcons"));
+ tool_erase->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ snap->set_icon(get_theme_icon("SnapGrid", "EditorIcons"));
+ open_editor->set_icon(get_theme_icon("Edit", "EditorIcons"));
}
if (p_what == NOTIFICATION_PROCESS) {
@@ -589,7 +589,7 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
}
}
-AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = NULL;
+AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
singleton = this;
@@ -735,7 +735,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
- open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened));
undo_redo = EditorNode::get_undo_redo();
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 663f2dde05..4343535eb6 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -30,9 +30,9 @@
#include "animation_blend_space_2d_editor.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
#include "core/math/delaunay.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/editor_scale.h"
@@ -40,7 +40,7 @@
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) {
@@ -100,7 +100,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
List<StringName> names;
ap->get_animation_list(&names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get());
+ animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get());
animations_to_add.push_back(E->get());
}
}
@@ -124,7 +124,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
menu->add_separator();
menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
+ menu->set_position(blend_space_draw->get_screen_transform().xform(mb->get_position()));
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size());
add_point_pos.y = 1.0 - add_point_pos.y;
@@ -406,17 +406,17 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) {
void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
- Color linecolor = get_color("font_color", "Label");
+ Color linecolor = get_theme_color("font_color", "Label");
Color linecolor_soft = linecolor;
linecolor_soft.a *= 0.5;
- Ref<Font> font = get_font("font", "Label");
- Ref<Texture2D> icon = get_icon("KeyValue", "EditorIcons");
- Ref<Texture2D> icon_selected = get_icon("KeySelected", "EditorIcons");
+ Ref<Font> font = get_theme_font("font", "Label");
+ Ref<Texture2D> icon = get_theme_icon("KeyValue", "EditorIcons");
+ Ref<Texture2D> icon_selected = get_theme_icon("KeySelected", "EditorIcons");
Size2 s = blend_space_draw->get_size();
if (blend_space_draw->has_focus()) {
- Color color = get_color("accent_color", "Editor");
+ Color color = get_theme_color("accent_color", "Editor");
blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);
}
blend_space_draw->draw_line(Point2(1, 0), Point2(1, s.height - 1), linecolor);
@@ -502,7 +502,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
Color color;
if (i == selected_triangle) {
- color = get_color("accent_color", "Editor");
+ color = get_theme_color("accent_color", "Editor");
color.a *= 0.5;
} else {
color = linecolor;
@@ -563,7 +563,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
{
Color color;
if (tool_blend->is_pressed()) {
- color = get_color("accent_color", "Editor");
+ color = get_theme_color("accent_color", "Editor");
} else {
color = linecolor;
color.a *= 0.5;
@@ -754,21 +754,21 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
- panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- tool_blend->set_icon(get_icon("EditPivot", "EditorIcons"));
- tool_select->set_icon(get_icon("ToolSelect", "EditorIcons"));
- tool_create->set_icon(get_icon("EditKey", "EditorIcons"));
- tool_triangle->set_icon(get_icon("ToolTriangle", "EditorIcons"));
- tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
- snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
- open_editor->set_icon(get_icon("Edit", "EditorIcons"));
- auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons"));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ tool_blend->set_icon(get_theme_icon("EditPivot", "EditorIcons"));
+ tool_select->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tool_create->set_icon(get_theme_icon("EditKey", "EditorIcons"));
+ tool_triangle->set_icon(get_theme_icon("ToolTriangle", "EditorIcons"));
+ tool_erase->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ snap->set_icon(get_theme_icon("SnapGrid", "EditorIcons"));
+ open_editor->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ auto_triangles->set_icon(get_theme_icon("AutoTriangle", "EditorIcons"));
interpolation->clear();
- interpolation->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), "", 0);
- interpolation->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), "", 1);
- interpolation->add_icon_item(get_icon("TrackCapture", "EditorIcons"), "", 2);
+ interpolation->add_icon_item(get_theme_icon("TrackContinuous", "EditorIcons"), "", 0);
+ interpolation->add_icon_item(get_theme_icon("TrackDiscrete", "EditorIcons"), "", 1);
+ interpolation->add_icon_item(get_theme_icon("TrackCapture", "EditorIcons"), "", 2);
}
if (p_what == NOTIFICATION_PROCESS) {
@@ -810,7 +810,7 @@ void AnimationNodeBlendSpace2DEditor::_open_editor() {
}
void AnimationNodeBlendSpace2DEditor::_removed_from_graph() {
- EditorNode::get_singleton()->edit_item(NULL);
+ EditorNode::get_singleton()->edit_item(nullptr);
}
void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() {
@@ -833,7 +833,7 @@ void AnimationNodeBlendSpace2DEditor::_bind_methods() {
ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph);
}
-AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL;
+AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = nullptr;
AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
@@ -1042,7 +1042,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
- open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_file_opened));
undo_redo = EditorNode::get_undo_redo();
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 5e53adf471..54c60aba71 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -30,8 +30,8 @@
#include "animation_blend_tree_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/editor_inspector.h"
@@ -40,7 +40,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/gui/progress_bar.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) {
@@ -145,7 +145,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
name->set_text(E->get());
name->set_expand_to_text_length(true);
node->add_child(name);
- node->set_slot(0, false, 0, Color(), true, 0, get_color("font_color", "Label"));
+ 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("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out), varray(name, agnode), CONNECT_DEFERRED);
base = 1;
@@ -157,7 +157,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
Label *in_name = memnew(Label);
node->add_child(in_name);
in_name->set_text(agnode->get_input_name(i));
- node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color());
+ node->set_slot(base + i, true, 0, get_theme_color("font_color", "Label"), false, 0, Color());
}
List<PropertyInfo> pinfo;
@@ -185,7 +185,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
node->add_child(memnew(HSeparator));
Button *open_in_editor = memnew(Button);
open_in_editor->set_text(TTR("Open Editor"));
- open_in_editor->set_icon(get_icon("Edit", "EditorIcons"));
+ open_in_editor->set_icon(get_theme_icon("Edit", "EditorIcons"));
node->add_child(open_in_editor);
open_in_editor->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_open_in_editor), varray(E->get()), CONNECT_DEFERRED);
open_in_editor->set_h_size_flags(SIZE_SHRINK_CENTER);
@@ -196,7 +196,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
node->add_child(memnew(HSeparator));
Button *edit_filters = memnew(Button);
edit_filters->set_text(TTR("Edit Filters"));
- edit_filters->set_icon(get_icon("AnimationFilter", "EditorIcons"));
+ edit_filters->set_icon(get_theme_icon("AnimationFilter", "EditorIcons"));
node->add_child(edit_filters);
edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters), varray(E->get()), CONNECT_DEFERRED);
edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
@@ -207,7 +207,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
MenuButton *mb = memnew(MenuButton);
mb->set_text(anim->get_animation());
- mb->set_icon(get_icon("Animation", "EditorIcons"));
+ mb->set_icon(get_theme_icon("Animation", "EditorIcons"));
Array options;
node->add_child(memnew(HSeparator));
@@ -242,16 +242,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
}
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
+ Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
Color c = sb->get_border_color();
Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
mono_color.a = 0.85;
c = mono_color;
- node->add_color_override("title_color", c);
+ node->add_theme_color_override("title_color", c);
c.a = 0.7;
- node->add_color_override("close_color", c);
- node->add_color_override("resizer_color", c);
+ node->add_theme_color_override("close_color", c);
+ node->add_theme_color_override("resizer_color", c);
}
}
@@ -536,7 +536,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
updating = true;
Set<String> paths;
- HashMap<String, Set<String> > types;
+ HashMap<String, Set<String>> types;
{
List<StringName> animations;
player->get_animation_list(&animations);
@@ -579,7 +579,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
NodePath path = E->get();
- TreeItem *ti = NULL;
+ TreeItem *ti = nullptr;
String accum;
for (int i = 0; i < path.get_name_count(); i++) {
String name = path.get_name(i);
@@ -608,7 +608,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
}
}
- Node *node = NULL;
+ Node *node = nullptr;
if (base->has_node(accum)) {
node = base->get_node(accum);
}
@@ -619,7 +619,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
String concat = path.get_concatenated_subnames();
- Skeleton *skeleton = Object::cast_to<Skeleton>(node);
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
if (skeleton && skeleton->find_bone(concat) != -1) {
//path in skeleton
const String &bone = concat;
@@ -643,7 +643,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti->set_text(0, F->get());
ti->set_selectable(0, false);
ti->set_editable(0, false);
- ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons"));
+ ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons"));
} else {
ti = parenthood[accum];
}
@@ -654,7 +654,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
ti->set_checked(0, anode->is_path_filtered(path));
- ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons"));
+ ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons"));
ti->set_metadata(0, path);
} else {
@@ -705,12 +705,12 @@ void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) {
if (!_update_filters(anode))
return;
- filter_dialog->popup_centered_minsize(Size2(500, 500) * EDSCALE);
+ filter_dialog->popup_centered(Size2(500, 500) * EDSCALE);
}
void AnimationNodeBlendTreeEditor::_removed_from_graph() {
if (is_visible()) {
- EditorNode::get_singleton()->edit_item(NULL);
+ EditorNode::get_singleton()->edit_item(nullptr);
}
}
@@ -718,8 +718,8 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())
_update_graph();
@@ -756,7 +756,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree();
- AnimationPlayer *player = NULL;
+ AnimationPlayer *player = nullptr;
if (graph_player->has_node(graph_player->get_animation_player())) {
player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player()));
}
@@ -802,7 +802,7 @@ void AnimationNodeBlendTreeEditor::_bind_methods() {
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
}
-AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = NULL;
+AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr;
void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) {
@@ -931,7 +931,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
add_node->set_text(TTR("Add Node..."));
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node));
- add_node->connect("about_to_show", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu));
+ add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu));
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot"));
@@ -975,7 +975,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
- open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendTreeEditor::_file_opened));
undo_redo = EditorNode::get_undo_redo();
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index af12335a27..d96a3b0bab 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -30,28 +30,28 @@
#include "animation_player_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/animation_track_editor.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning.
-#include "editor/plugins/spatial_editor_plugin.h" // For onion skinning.
-#include "scene/main/viewport.h"
-#include "servers/visual_server.h"
+#include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning.
+#include "scene/main/window.h"
+#include "servers/rendering_server.h"
void AnimationPlayerEditor::_node_removed(Node *p_node) {
if (player && player == p_node) {
- player = NULL;
+ player = nullptr;
set_process(false);
track_editor->set_animation(Ref<Animation>());
- track_editor->set_root(NULL);
+ track_editor->set_root(nullptr);
track_editor->show_select_node_warning(true);
_update_player();
}
@@ -105,33 +105,33 @@ void AnimationPlayerEditor::_notification(int p_what) {
get_tree()->connect("node_removed", callable_mp(this, &AnimationPlayerEditor::_node_removed));
- add_style_override("panel", editor->get_gui_base()->get_stylebox("panel", "Panel"));
+ add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("panel", "Panel"));
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- add_style_override("panel", editor->get_gui_base()->get_stylebox("panel", "Panel"));
+ add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("panel", "Panel"));
} break;
case NOTIFICATION_THEME_CHANGED: {
- autoplay->set_icon(get_icon("AutoPlay", "EditorIcons"));
+ autoplay->set_icon(get_theme_icon("AutoPlay", "EditorIcons"));
- play->set_icon(get_icon("PlayStart", "EditorIcons"));
- play_from->set_icon(get_icon("Play", "EditorIcons"));
- play_bw->set_icon(get_icon("PlayStartBackwards", "EditorIcons"));
- play_bw_from->set_icon(get_icon("PlayBackwards", "EditorIcons"));
+ play->set_icon(get_theme_icon("PlayStart", "EditorIcons"));
+ play_from->set_icon(get_theme_icon("Play", "EditorIcons"));
+ play_bw->set_icon(get_theme_icon("PlayStartBackwards", "EditorIcons"));
+ play_bw_from->set_icon(get_theme_icon("PlayBackwards", "EditorIcons"));
- autoplay_icon = get_icon("AutoPlay", "EditorIcons");
- stop->set_icon(get_icon("Stop", "EditorIcons"));
+ autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons");
+ stop->set_icon(get_theme_icon("Stop", "EditorIcons"));
- onion_toggle->set_icon(get_icon("Onion", "EditorIcons"));
- onion_skinning->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
+ onion_toggle->set_icon(get_theme_icon("Onion", "EditorIcons"));
+ onion_skinning->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
- pin->set_icon(get_icon("Pin", "EditorIcons"));
+ pin->set_icon(get_theme_icon("Pin", "EditorIcons"));
- tool_anim->add_style_override("normal", get_stylebox("normal", "Button"));
- track_editor->get_edit_menu()->add_style_override("normal", get_stylebox("normal", "Button"));
+ tool_anim->add_theme_style_override("normal", get_theme_stylebox("normal", "Button"));
+ track_editor->get_edit_menu()->add_theme_style_override("normal", get_theme_stylebox("normal", "Button"));
-#define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_icon(m_icon, "EditorIcons"))
+#define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_theme_icon(m_icon, "EditorIcons"))
ITEM_ICON(TOOL_NEW_ANIM, "New");
ITEM_ICON(TOOL_LOAD_ANIM, "Load");
@@ -299,7 +299,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
} else {
track_editor->set_animation(Ref<Animation>());
- track_editor->set_root(NULL);
+ track_editor->set_root(nullptr);
}
autoplay->set_pressed(current == player->get_autoplay());
@@ -349,7 +349,7 @@ void AnimationPlayerEditor::_animation_rename() {
}
void AnimationPlayerEditor::_animation_load() {
ERR_FAIL_COND(!player);
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file->clear_filters();
List<String> extensions;
@@ -392,7 +392,7 @@ void AnimationPlayerEditor::_animation_save(const Ref<Resource> &p_resource) {
void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource) {
- file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
List<String> extensions;
ResourceSaver::get_recognized_extensions(p_resource, &extensions);
@@ -407,7 +407,7 @@ void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource)
file->set_current_path(p_resource->get_path());
if (extensions.size()) {
String ext = p_resource->get_path().get_extension().to_lower();
- if (extensions.find(ext) == NULL) {
+ if (extensions.find(ext) == nullptr) {
file->set_current_path(p_resource->get_path().replacen("." + ext, "." + extensions.front()->get()));
}
}
@@ -434,7 +434,7 @@ void AnimationPlayerEditor::_animation_remove() {
return;
delete_dialog->set_text(TTR("Delete Animation?"));
- delete_dialog->popup_centered_minsize();
+ delete_dialog->popup_centered();
}
void AnimationPlayerEditor::_animation_remove_confirmed() {
@@ -488,7 +488,7 @@ double AnimationPlayerEditor::_get_editor_step() const {
ERR_FAIL_COND_V(!anim.is_valid(), 0.0);
// Use more precise snapping when holding Shift
- return Input::get_singleton()->is_key_pressed(KEY_SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
+ return InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
}
return 0.0;
@@ -501,7 +501,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
String new_name = name->get_text();
if (new_name == "" || new_name.find(":") != -1 || new_name.find("/") != -1) {
error_dialog->set_text(TTR("Invalid animation name!"));
- error_dialog->popup_centered_minsize();
+ error_dialog->popup_centered();
return;
}
@@ -512,7 +512,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
if (player->has_animation(new_name)) {
error_dialog->set_text(TTR("Animation name already exists!"));
- error_dialog->popup_centered_minsize();
+ error_dialog->popup_centered();
return;
}
@@ -729,7 +729,7 @@ void AnimationPlayerEditor::_animation_edit() {
}
} else {
track_editor->set_animation(Ref<Animation>());
- track_editor->set_root(NULL);
+ track_editor->set_root(nullptr);
}
}
@@ -845,10 +845,10 @@ void AnimationPlayerEditor::_update_player() {
frame->set_editable(animlist.size() != 0);
animation->set_disabled(animlist.size() == 0);
autoplay->set_disabled(animlist.size() == 0);
- tool_anim->set_disabled(player == NULL);
+ tool_anim->set_disabled(player == nullptr);
onion_toggle->set_disabled(animlist.size() == 0);
onion_skinning->set_disabled(animlist.size() == 0);
- pin->set_disabled(player == NULL);
+ pin->set_disabled(player == nullptr);
if (!player) {
AnimationPlayerEditor::singleton->get_track_editor()->update_keying();
@@ -947,8 +947,8 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o
alpha += alpha_step;
if (onion.captures_valid[cidx]) {
- VS::get_singleton()->canvas_item_add_texture_rect_region(
- ci, dst_rect, VS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha));
+ RS::get_singleton()->canvas_item_add_texture_rect_region(
+ ci, dst_rect, RS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha));
}
cidx++;
@@ -961,8 +961,8 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o
alpha -= alpha_step;
if (onion.captures_valid[cidx]) {
- VS::get_singleton()->canvas_item_add_texture_rect_region(
- ci, dst_rect, VS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha));
+ RS::get_singleton()->canvas_item_add_texture_rect_region(
+ ci, dst_rect, RS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha));
}
cidx++;
@@ -1058,7 +1058,7 @@ void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) {
if (player == p_pl && is_visible_in_tree()) {
_update_player();
- if (blend_editor.dialog->is_visible_in_tree())
+ if (blend_editor.dialog->is_visible())
_animation_blend(); // Update.
}
}
@@ -1152,7 +1152,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
if (!animation->get_item_count()) {
error_dialog->set_text(TTR("No animation to copy!"));
- error_dialog->popup_centered_minsize();
+ error_dialog->popup_centered();
return;
}
@@ -1165,7 +1165,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
Ref<Animation> anim2 = EditorSettings::get_singleton()->get_resource_clipboard();
if (!anim2.is_valid()) {
error_dialog->set_text(TTR("No animation resource on clipboard!"));
- error_dialog->popup_centered_minsize();
+ error_dialog->popup_centered();
return;
}
@@ -1195,7 +1195,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
if (!animation->get_item_count()) {
error_dialog->set_text(TTR("No animation to edit!"));
- error_dialog->popup_centered_minsize();
+ error_dialog->popup_centered();
return;
}
@@ -1318,17 +1318,17 @@ void AnimationPlayerEditor::_allocate_onion_layers() {
bool is_present = onion.differences_only && i == captures - 1;
// Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport.
- onion.captures.write[i] = VS::get_singleton()->viewport_create();
+ onion.captures.write[i] = RS::get_singleton()->viewport_create();
- VS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height);
- VS::get_singleton()->viewport_set_update_mode(onion.captures[i], VS::VIEWPORT_UPDATE_ALWAYS);
- VS::get_singleton()->viewport_set_transparent_background(onion.captures[i], !is_present);
- VS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas);
+ RS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height);
+ RS::get_singleton()->viewport_set_update_mode(onion.captures[i], RS::VIEWPORT_UPDATE_ALWAYS);
+ RS::get_singleton()->viewport_set_transparent_background(onion.captures[i], !is_present);
+ RS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas);
}
// Reset the capture canvas item to the current root viewport texture (defensive).
- VS::get_singleton()->canvas_item_clear(onion.capture.canvas_item);
- VS::get_singleton()->canvas_item_add_texture_rect(onion.capture.canvas_item, Rect2(Point2(), capture_size), get_tree()->get_root()->get_texture()->get_rid());
+ RS::get_singleton()->canvas_item_clear(onion.capture.canvas_item);
+ RS::get_singleton()->canvas_item_add_texture_rect(onion.capture.canvas_item, Rect2(Point2(), capture_size), get_tree()->get_root()->get_texture()->get_rid());
onion.capture_size = capture_size;
}
@@ -1337,7 +1337,7 @@ void AnimationPlayerEditor::_free_onion_layers() {
for (int i = 0; i < onion.captures.size(); i++) {
if (onion.captures[i].is_valid()) {
- VS::get_singleton()->free(onion.captures[i]);
+ RS::get_singleton()->free(onion.captures[i]);
}
}
onion.captures.clear();
@@ -1385,9 +1385,9 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// Hide superfluous elements that would make the overlay unnecessary cluttered.
Dictionary canvas_edit_state;
Dictionary spatial_edit_state;
- if (SpatialEditor::get_singleton()->is_visible()) {
+ if (Node3DEditor::get_singleton()->is_visible()) {
// 3D
- spatial_edit_state = SpatialEditor::get_singleton()->get_state();
+ spatial_edit_state = Node3DEditor::get_singleton()->get_state();
Dictionary new_state = spatial_edit_state.duplicate();
new_state["show_grid"] = false;
new_state["show_origin"] = false;
@@ -1404,7 +1404,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
}
new_state["viewports"] = vp;
// TODO: Save/restore only affected entries.
- SpatialEditor::get_singleton()->set_state(new_state);
+ Node3DEditor::get_singleton()->set_state(new_state);
} else { // CanvasItemEditor
// 2D
canvas_edit_state = CanvasItemEditor::get_singleton()->get_state();
@@ -1420,19 +1420,19 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// Tweak the root viewport to ensure it's rendered before our target.
RID root_vp = get_tree()->get_root()->get_viewport_rid();
- Rect2 root_vp_screen_rect = get_tree()->get_root()->get_attach_to_screen_rect();
- VS::get_singleton()->viewport_attach_to_screen(root_vp, Rect2());
- VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_ALWAYS);
+ Rect2 root_vp_screen_rect = Rect2(Vector2(), get_tree()->get_root()->get_size());
+ RS::get_singleton()->viewport_attach_to_screen(root_vp, Rect2());
+ RS::get_singleton()->viewport_set_update_mode(root_vp, RS::VIEWPORT_UPDATE_ALWAYS);
RID present_rid;
if (onion.differences_only) {
// Capture present scene as it is.
- VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, RID());
+ RS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, RID());
present_rid = onion.captures[onion.captures.size() - 1];
- VS::get_singleton()->viewport_set_active(present_rid, true);
- VS::get_singleton()->viewport_set_parent_viewport(root_vp, present_rid);
- VS::get_singleton()->draw(false);
- VS::get_singleton()->viewport_set_active(present_rid, false);
+ RS::get_singleton()->viewport_set_active(present_rid, true);
+ RS::get_singleton()->viewport_set_parent_viewport(root_vp, present_rid);
+ RS::get_singleton()->draw(false);
+ RS::get_singleton()->viewport_set_active(present_rid, false);
}
// Backup current animation state.
@@ -1441,10 +1441,10 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// Render every past/future step with the capture shader.
- VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid());
+ 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("differences_only", onion.differences_only);
- onion.capture.material->set_shader_param("present", onion.differences_only ? VS::get_singleton()->viewport_get_texture(present_rid) : RID());
+ onion.capture.material->set_shader_param("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID());
int step_off_a = onion.past ? -onion.steps : 0;
int step_off_b = onion.future ? onion.steps : 0;
@@ -1465,22 +1465,22 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
onion.captures_valid.write[cidx] = valid;
if (valid) {
player->seek(pos, true);
- get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials.
+ get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds.
values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D).
- VS::get_singleton()->viewport_set_active(onion.captures[cidx], true);
- VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]);
- VS::get_singleton()->draw(false);
- VS::get_singleton()->viewport_set_active(onion.captures[cidx], false);
+ RS::get_singleton()->viewport_set_active(onion.captures[cidx], true);
+ RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]);
+ RS::get_singleton()->draw(false);
+ RS::get_singleton()->viewport_set_active(onion.captures[cidx], false);
}
cidx++;
}
// Restore root viewport.
- VS::get_singleton()->viewport_set_parent_viewport(root_vp, RID());
- VS::get_singleton()->viewport_attach_to_screen(root_vp, root_vp_screen_rect);
- VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+ RS::get_singleton()->viewport_set_parent_viewport(root_vp, RID());
+ RS::get_singleton()->viewport_attach_to_screen(root_vp, root_vp_screen_rect);
+ RS::get_singleton()->viewport_set_update_mode(root_vp, RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
// Restore animation state
// (Seeking with update=true wouldn't do the trick because the current value of the properties
@@ -1489,9 +1489,9 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
player->restore_animated_values(values_backup);
// Restore state of main editors.
- if (SpatialEditor::get_singleton()->is_visible()) {
+ if (Node3DEditor::get_singleton()->is_visible()) {
// 3D
- SpatialEditor::get_singleton()->set_state(spatial_edit_state);
+ Node3DEditor::get_singleton()->set_state(spatial_edit_state);
} else { // CanvasItemEditor
// 2D
CanvasItemEditor::get_singleton()->set_state(canvas_edit_state);
@@ -1549,7 +1549,7 @@ void AnimationPlayerEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_stop_onion_skinning"), &AnimationPlayerEditor::_stop_onion_skinning);
}
-AnimationPlayerEditor *AnimationPlayerEditor::singleton = NULL;
+AnimationPlayerEditor *AnimationPlayerEditor::singleton = nullptr;
AnimationPlayer *AnimationPlayerEditor::get_player() const {
@@ -1565,7 +1565,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
set_focus_mode(FOCUS_ALL);
- player = NULL;
+ player = nullptr;
HBoxContainer *hb = memnew(HBoxContainer);
add_child(hb);
@@ -1764,9 +1764,9 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
onion.last_frame = 0;
onion.can_overlay = false;
onion.capture_size = Size2();
- onion.capture.canvas = VS::get_singleton()->canvas_create();
- onion.capture.canvas_item = VS::get_singleton()->canvas_item_create();
- VS::get_singleton()->canvas_item_set_parent(onion.capture.canvas_item, onion.capture.canvas);
+ onion.capture.canvas = RS::get_singleton()->canvas_create();
+ onion.capture.canvas_item = RS::get_singleton()->canvas_item_create();
+ RS::get_singleton()->canvas_item_set_parent(onion.capture.canvas_item, onion.capture.canvas);
onion.capture.material = Ref<ShaderMaterial>(memnew(ShaderMaterial));
@@ -1792,14 +1792,14 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
COLOR = vec4(capture_samp.rgb * dir_color.rgb, bkg_mask * diff_mask); \
} \
");
- VS::get_singleton()->material_set_shader(onion.capture.material->get_rid(), onion.capture.shader->get_rid());
+ RS::get_singleton()->material_set_shader(onion.capture.material->get_rid(), onion.capture.shader->get_rid());
}
AnimationPlayerEditor::~AnimationPlayerEditor() {
_free_onion_layers();
- VS::get_singleton()->free(onion.capture.canvas);
- VS::get_singleton()->free(onion.capture.canvas_item);
+ RS::get_singleton()->free(onion.capture.canvas);
+ RS::get_singleton()->free(onion.capture.canvas_item);
}
void AnimationPlayerEditorPlugin::_notification(int p_what) {
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index cae959e1f4..c06f62a8c1 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -30,9 +30,9 @@
#include "animation_state_machine_editor.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
#include "core/math/delaunay.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/editor_scale.h"
@@ -40,7 +40,7 @@
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
@@ -97,7 +97,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
List<StringName> names;
ap->get_animation_list(&names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get());
+ animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get());
animations_to_add.push_back(E->get());
}
}
@@ -121,7 +121,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
menu->add_separator();
menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position()));
+ menu->set_position(state_machine_draw->get_screen_transform().xform(mb->get_position()));
menu->popup();
add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset();
}
@@ -149,16 +149,16 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (node_rects[i].name.has_point(mb->get_position())) { //edit name
- Ref<StyleBox> line_sb = get_stylebox("normal", "LineEdit");
+ Ref<StyleBox> line_sb = get_theme_stylebox("normal", "LineEdit");
Rect2 edit_rect = node_rects[i].name;
edit_rect.position -= line_sb->get_offset();
edit_rect.size += line_sb->get_minimum_size();
- name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position));
- name_edit->set_size(edit_rect.size);
+ name_edit_popup->set_position(state_machine_draw->get_screen_transform().xform(edit_rect.position));
+ name_edit_popup->set_size(edit_rect.size);
name_edit->set_text(node_rects[i].node_name);
- name_edit->show_modal();
+ name_edit_popup->popup();
name_edit->grab_focus();
name_edit->select_all();
@@ -504,9 +504,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance) {
- Color linecolor = get_color("font_color", "Label");
+ Color linecolor = get_theme_color("font_color", "Label");
Color icon_color(1, 1, 1);
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
if (!p_enabled) {
linecolor.a *= 0.2;
@@ -515,12 +515,12 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
}
Ref<Texture2D> icons[6] = {
- get_icon("TransitionImmediateBig", "EditorIcons"),
- get_icon("TransitionSyncBig", "EditorIcons"),
- get_icon("TransitionEndBig", "EditorIcons"),
- get_icon("TransitionImmediateAutoBig", "EditorIcons"),
- get_icon("TransitionSyncAutoBig", "EditorIcons"),
- get_icon("TransitionEndAutoBig", "EditorIcons")
+ get_theme_icon("TransitionImmediateBig", "EditorIcons"),
+ get_theme_icon("TransitionSyncBig", "EditorIcons"),
+ get_theme_icon("TransitionEndBig", "EditorIcons"),
+ get_theme_icon("TransitionImmediateAutoBig", "EditorIcons"),
+ get_theme_icon("TransitionSyncAutoBig", "EditorIcons"),
+ get_theme_icon("TransitionEndAutoBig", "EditorIcons")
};
if (p_selected) {
@@ -573,18 +573,18 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
- Ref<StyleBox> style = get_stylebox("state_machine_frame", "GraphNode");
- Ref<StyleBox> style_selected = get_stylebox("state_machine_selectedframe", "GraphNode");
+ Ref<StyleBox> style = get_theme_stylebox("state_machine_frame", "GraphNode");
+ Ref<StyleBox> style_selected = get_theme_stylebox("state_machine_selectedframe", "GraphNode");
- Ref<Font> font = get_font("title_font", "GraphNode");
- Color font_color = get_color("title_color", "GraphNode");
- Ref<Texture2D> play = get_icon("Play", "EditorIcons");
- Ref<Texture2D> auto_play = get_icon("AutoPlay", "EditorIcons");
- Ref<Texture2D> edit = get_icon("Edit", "EditorIcons");
- Color accent = get_color("accent_color", "Editor");
- Color linecolor = get_color("font_color", "Label");
+ Ref<Font> font = get_theme_font("title_font", "GraphNode");
+ Color font_color = get_theme_color("title_color", "GraphNode");
+ Ref<Texture2D> play = get_theme_icon("Play", "EditorIcons");
+ Ref<Texture2D> auto_play = get_theme_icon("AutoPlay", "EditorIcons");
+ Ref<Texture2D> edit = get_theme_icon("Edit", "EditorIcons");
+ Color accent = get_theme_color("accent_color", "Editor");
+ Color linecolor = get_theme_color("font_color", "Label");
linecolor.a *= 0.3;
- Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode");
+ Ref<StyleBox> playing_overlay = get_theme_stylebox("position", "GraphNode");
bool playing = false;
StringName current;
@@ -686,7 +686,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
_connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false);
}
- Ref<Texture2D> tr_reference_icon = get_icon("TransitionImmediateBig", "EditorIcons");
+ Ref<Texture2D> tr_reference_icon = get_theme_icon("TransitionImmediateBig", "EditorIcons");
float tr_bidi_offset = int(tr_reference_icon->get_height() * 0.8);
//draw transition lines
@@ -879,7 +879,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
float pos = CLAMP(play_pos, 0, len);
float c = pos / len;
- Color fg = get_color("font_color", "Label");
+ Color fg = get_theme_color("font_color", "Label");
Color bg = fg;
bg.a *= 0.3;
@@ -905,26 +905,26 @@ void AnimationNodeStateMachineEditor::_update_graph() {
void AnimationNodeStateMachineEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
- panel->add_style_override("panel", get_stylebox("bg", "Tree"));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
- tool_select->set_icon(get_icon("ToolSelect", "EditorIcons"));
- tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons"));
- tool_connect->set_icon(get_icon("ToolConnect", "EditorIcons"));
+ tool_select->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tool_create->set_icon(get_theme_icon("ToolAddNode", "EditorIcons"));
+ tool_connect->set_icon(get_theme_icon("ToolConnect", "EditorIcons"));
transition_mode->clear();
- transition_mode->add_icon_item(get_icon("TransitionImmediate", "EditorIcons"), TTR("Immediate"));
- transition_mode->add_icon_item(get_icon("TransitionSync", "EditorIcons"), TTR("Sync"));
- transition_mode->add_icon_item(get_icon("TransitionEnd", "EditorIcons"), TTR("At End"));
+ transition_mode->add_icon_item(get_theme_icon("TransitionImmediate", "EditorIcons"), TTR("Immediate"));
+ transition_mode->add_icon_item(get_theme_icon("TransitionSync", "EditorIcons"), TTR("Sync"));
+ transition_mode->add_icon_item(get_theme_icon("TransitionEnd", "EditorIcons"), TTR("At End"));
- tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
- tool_autoplay->set_icon(get_icon("AutoPlay", "EditorIcons"));
- tool_end->set_icon(get_icon("AutoEnd", "EditorIcons"));
+ tool_erase->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ tool_autoplay->set_icon(get_theme_icon("AutoPlay", "EditorIcons"));
+ tool_end->set_icon(get_theme_icon("AutoEnd", "EditorIcons"));
play_mode->clear();
- play_mode->add_icon_item(get_icon("PlayTravel", "EditorIcons"), TTR("Travel"));
- play_mode->add_icon_item(get_icon("Play", "EditorIcons"), TTR("Immediate"));
+ play_mode->add_icon_item(get_theme_icon("PlayTravel", "EditorIcons"), TTR("Travel"));
+ play_mode->add_icon_item(get_theme_icon("Play", "EditorIcons"), TTR("Immediate"));
}
if (p_what == NOTIFICATION_PROCESS) {
@@ -1082,7 +1082,7 @@ void AnimationNodeStateMachineEditor::_open_editor(const String &p_name) {
void AnimationNodeStateMachineEditor::_removed_from_graph() {
- EditorNode::get_singleton()->edit_item(NULL);
+ EditorNode::get_singleton()->edit_item(nullptr);
}
void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
@@ -1110,7 +1110,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
- name_edit->hide();
+ name_edit_popup->hide();
updating = false;
state_machine_draw->update();
@@ -1241,7 +1241,7 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor);
}
-AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL;
+AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = nullptr;
AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
@@ -1357,17 +1357,18 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
animations_menu->set_name("animations");
animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_animation_type));
+ name_edit_popup = memnew(Popup);
+ add_child(name_edit_popup);
name_edit = memnew(LineEdit);
- state_machine_draw->add_child(name_edit);
- name_edit->hide();
+ name_edit_popup->add_child(name_edit);
+ name_edit->set_anchors_and_margins_preset(PRESET_WIDE);
name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited));
name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out));
- name_edit->set_as_toplevel(true);
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
- open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
open_file->connect("file_selected", callable_mp(this, &AnimationNodeStateMachineEditor::_file_opened));
undo_redo = EditorNode::get_undo_redo();
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 132e66b28d..5c4fc87df5 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -50,6 +50,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
ToolButton *tool_select;
ToolButton *tool_create;
ToolButton *tool_connect;
+ Popup *name_edit_popup;
LineEdit *name_edit;
HBoxContainer *tool_erase_hb;
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index c9706a7f68..e771c5610f 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -34,9 +34,9 @@
#include "animation_blend_space_2d_editor.h"
#include "animation_blend_tree_editor_plugin.h"
#include "animation_state_machine_editor.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
#include "core/math/delaunay.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/editor_scale.h"
@@ -44,7 +44,7 @@
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/scene_string_names.h"
void AnimationTreeEditor::edit(AnimationTree *p_tree) {
@@ -169,7 +169,7 @@ void AnimationTreeEditor::_notification(int p_what) {
void AnimationTreeEditor::_bind_methods() {
}
-AnimationTreeEditor *AnimationTreeEditor::singleton = NULL;
+AnimationTreeEditor *AnimationTreeEditor::singleton = nullptr;
void AnimationTreeEditor::add_plugin(AnimationTreeNodeEditorPlugin *p_editor) {
ERR_FAIL_COND(p_editor->get_parent());
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 80b7e6ffc8..14c44b7973 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -30,8 +30,8 @@
#include "asset_library_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/io/json.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor/editor_node.h"
@@ -62,10 +62,10 @@ void EditorAssetLibraryItem::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- icon->set_normal_texture(get_icon("ProjectIconLoading", "EditorIcons"));
- category->add_color_override("font_color", Color(0.5, 0.5, 0.5));
- author->add_color_override("font_color", Color(0.5, 0.5, 0.5));
- price->add_color_override("font_color", Color(0.5, 0.5, 0.5));
+ icon->set_normal_texture(get_theme_icon("ProjectIconLoading", "EditorIcons"));
+ category->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
+ author->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
+ price->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
}
}
@@ -99,11 +99,11 @@ EditorAssetLibraryItem::EditorAssetLibraryItem() {
border->set_default_margin(MARGIN_RIGHT, 5 * EDSCALE);
border->set_default_margin(MARGIN_BOTTOM, 5 * EDSCALE);
border->set_default_margin(MARGIN_TOP, 5 * EDSCALE);
- add_style_override("panel", border);
+ add_theme_style_override("panel", border);
HBoxContainer *hb = memnew(HBoxContainer);
// Add some spacing to visually separate the icon from the asset details.
- hb->add_constant_override("separation", 15 * EDSCALE);
+ hb->add_theme_constant_override("separation", 15 * EDSCALE);
add_child(hb);
icon = memnew(TextureButton);
@@ -116,7 +116,7 @@ EditorAssetLibraryItem::EditorAssetLibraryItem() {
VBoxContainer *vb = memnew(VBoxContainer);
hb->add_child(vb);
- vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
title = memnew(LinkButton);
title->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
@@ -137,7 +137,7 @@ EditorAssetLibraryItem::EditorAssetLibraryItem() {
vb->add_child(price);
set_custom_minimum_size(Size2(250, 100) * EDSCALE);
- set_h_size_flags(SIZE_EXPAND_FILL);
+ set_h_size_flags(Control::SIZE_EXPAND_FILL);
}
//////////////////////////////////////////////////////////////////////////////
@@ -156,7 +156,7 @@ 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 = get_icon("PlayOverlay", "EditorIcons")->get_data();
+ Ref<Image> overlay = previews->get_theme_icon("PlayOverlay", "EditorIcons")->get_data();
Ref<Image> thumbnail = p_image->get_data();
thumbnail = thumbnail->duplicate();
Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2);
@@ -172,7 +172,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
preview_images[i].button->set_icon(tex);
// Make it clearer that clicking it will open an external link
- preview_images[i].button->set_default_cursor_shape(CURSOR_POINTING_HAND);
+ preview_images[i].button->set_default_cursor_shape(Control::CURSOR_POINTING_HAND);
} else {
preview_images[i].button->set_icon(p_image);
}
@@ -198,7 +198,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
void EditorAssetLibraryItemDescription::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- previews_bg->add_style_override("panel", get_stylebox("normal", "TextEdit"));
+ previews_bg->add_theme_style_override("panel", previews->get_theme_stylebox("normal", "TextEdit"));
} break;
}
}
@@ -219,7 +219,7 @@ void EditorAssetLibraryItemDescription::_preview_click(int p_id) {
if (!preview_images[i].is_video) {
if (preview_images[i].image.is_valid()) {
preview->set_texture(preview_images[i].image);
- minimum_size_changed();
+ child_controls_changed();
}
} else {
_link_click(preview_images[i].video_link);
@@ -256,12 +256,12 @@ void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, cons
preview.is_video = p_video;
preview.button = memnew(Button);
preview.button->set_flat(true);
- preview.button->set_icon(get_icon("ThumbnailWait", "EditorIcons"));
+ preview.button->set_icon(previews->get_theme_icon("ThumbnailWait", "EditorIcons"));
preview.button->set_toggle_mode(true);
preview.button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDescription::_preview_click), varray(p_id));
preview_hb->add_child(preview.button);
if (!p_video) {
- preview.image = get_icon("ThumbnailWait", "EditorIcons");
+ preview.image = previews->get_theme_icon("ThumbnailWait", "EditorIcons");
}
preview_images.push_back(preview);
if (preview_images.size() == 1 && !p_video) {
@@ -275,7 +275,7 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() {
add_child(hbox);
VBoxContainer *desc_vbox = memnew(VBoxContainer);
hbox->add_child(desc_vbox);
- hbox->add_constant_override("separation", 15 * EDSCALE);
+ hbox->add_theme_constant_override("separation", 15 * EDSCALE);
item = memnew(EditorAssetLibraryItem);
@@ -284,14 +284,14 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() {
description = memnew(RichTextLabel);
desc_vbox->add_child(description);
- description->set_v_size_flags(SIZE_EXPAND_FILL);
+ description->set_v_size_flags(Control::SIZE_EXPAND_FILL);
description->connect("meta_clicked", callable_mp(this, &EditorAssetLibraryItemDescription::_link_click));
- description->add_constant_override("line_separation", Math::round(5 * EDSCALE));
+ description->add_theme_constant_override("line_separation", Math::round(5 * EDSCALE));
VBoxContainer *previews_vbox = memnew(VBoxContainer);
hbox->add_child(previews_vbox);
- previews_vbox->add_constant_override("separation", 15 * EDSCALE);
- previews_vbox->set_v_size_flags(SIZE_EXPAND_FILL);
+ previews_vbox->add_theme_constant_override("separation", 15 * EDSCALE);
+ previews_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
preview = memnew(TextureRect);
previews_vbox->add_child(preview);
@@ -308,7 +308,7 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() {
previews->set_enable_v_scroll(false);
previews->set_enable_h_scroll(true);
preview_hb = memnew(HBoxContainer);
- preview_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+ preview_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
previews->add_child(preview_hb);
get_ok()->set_text(TTR("Download"));
@@ -375,7 +375,7 @@ 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_minsize();
+ download_error->popup_centered();
return;
}
@@ -393,7 +393,7 @@ void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asse
icon->set_texture(p_preview);
asset_id = p_asset_id;
if (!p_preview.is_valid())
- icon->set_texture(get_icon("FileBrokenBigThumb", "EditorIcons"));
+ icon->set_texture(get_theme_icon("FileBrokenBigThumb", "EditorIcons"));
host = p_download_url;
sha256 = p_sha256_hash;
_make_request();
@@ -406,8 +406,8 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) {
// FIXME: The editor crashes if 'NOTICATION_THEME_CHANGED' is used.
case NOTIFICATION_ENTER_TREE: {
- add_style_override("panel", get_stylebox("panel", "TabContainer"));
- dismiss->set_normal_texture(get_icon("Close", "EditorIcons"));
+ add_theme_style_override("panel", get_theme_stylebox("panel", "TabContainer"));
+ dismiss->set_normal_texture(get_theme_icon("Close", "EditorIcons"));
} break;
case NOTIFICATION_PROCESS: {
@@ -507,13 +507,13 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
VBoxContainer *vb = memnew(VBoxContainer);
hb->add_child(vb);
- vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
HBoxContainer *title_hb = memnew(HBoxContainer);
vb->add_child(title_hb);
title = memnew(Label);
title_hb->add_child(title);
- title->set_h_size_flags(SIZE_EXPAND_FILL);
+ title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
dismiss = memnew(TextureButton);
dismiss->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_close));
@@ -525,7 +525,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
status = memnew(Label(TTR("Idle")));
vb->add_child(status);
- status->add_color_override("font_color", Color(0.5, 0.5, 0.5));
+ status->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
progress = memnew(ProgressBar);
vb->add_child(progress);
@@ -571,8 +571,8 @@ void EditorAssetLibrary::_notification(int p_what) {
case NOTIFICATION_READY: {
- error_tr->set_texture(get_icon("Error", "EditorIcons"));
- filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ error_tr->set_texture(get_theme_icon("Error", "EditorIcons"));
+ filter->set_right_icon(get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
error_label->raise();
@@ -602,10 +602,10 @@ void EditorAssetLibrary::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree"));
- downloads_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
- error_tr->set_texture(get_icon("Error", "EditorIcons"));
- filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ downloads_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
+ error_tr->set_texture(get_theme_icon("Error", "EditorIcons"));
+ filter->set_right_icon(get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
} break;
}
@@ -635,7 +635,7 @@ void EditorAssetLibrary::_install_asset() {
EditorAssetLibraryItemDownload *d = Object::cast_to<EditorAssetLibraryItemDownload>(downloads_hb->get_child(i));
if (d && d->get_asset_id() == description->get_asset_id()) {
- if (EditorNode::get_singleton() != NULL)
+ if (EditorNode::get_singleton() != nullptr)
EditorNode::get_singleton()->show_warning(TTR("Download for this asset is already in progress!"));
return;
}
@@ -774,7 +774,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
}
if (!image_set && final) {
- obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("FileBrokenBigThumb", "EditorIcons"));
+ obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_theme_icon("FileBrokenBigThumb", "EditorIcons"));
}
}
}
@@ -819,7 +819,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
WARN_PRINT("Error getting image file from URL: " + image_queue[p_queue_id].image_url);
Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target);
if (obj) {
- obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("FileBrokenBigThumb", "EditorIcons"));
+ obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_theme_icon("FileBrokenBigThumb", "EditorIcons"));
}
}
@@ -976,7 +976,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
to = p_page_count;
hbc->add_spacer();
- hbc->add_constant_override("separation", 5 * EDSCALE);
+ hbc->add_theme_constant_override("separation", 5 * EDSCALE);
Button *first = memnew(Button);
first->set_text(TTR("First"));
@@ -1191,8 +1191,8 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
asset_items = memnew(GridContainer);
asset_items->set_columns(2);
- asset_items->add_constant_override("hseparation", 10 * EDSCALE);
- asset_items->add_constant_override("vseparation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("hseparation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("vseparation", 10 * EDSCALE);
library_vb->add_child(asset_items);
@@ -1260,7 +1260,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
description = memnew(EditorAssetLibraryItemDescription);
add_child(description);
- description->popup_centered_minsize();
+ description->popup_centered();
description->connect("confirmed", callable_mp(this, &EditorAssetLibrary::_install_asset));
description->configure(r["title"], r["asset_id"], category_map[r["category_id"]], r["category_id"], r["author"], r["author_id"], r["cost"], r["version"], r["version_string"], r["description"], r["download_url"], r["browse_url"], r["download_hash"]);
@@ -1305,7 +1305,7 @@ void EditorAssetLibrary::_asset_file_selected(const String &p_file) {
if (asset_installer) {
memdelete(asset_installer);
- asset_installer = NULL;
+ asset_installer = nullptr;
}
asset_installer = memnew(EditorAssetInstaller);
@@ -1353,11 +1353,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
HBoxContainer *search_hb = memnew(HBoxContainer);
library_main->add_child(search_hb);
- library_main->add_constant_override("separation", 10 * EDSCALE);
+ library_main->add_theme_constant_override("separation", 10 * EDSCALE);
filter = memnew(LineEdit);
search_hb->add_child(filter);
- filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->connect("text_entered", callable_mp(this, &EditorAssetLibrary::_search_text_entered));
search = memnew(Button(TTR("Search")));
search->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), make_binds(0));
@@ -1392,7 +1392,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
search_hb2->add_child(sort);
- sort->set_h_size_flags(SIZE_EXPAND_FILL);
+ sort->set_h_size_flags(Control::SIZE_EXPAND_FILL);
sort->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_rerun_search));
search_hb2->add_child(memnew(VSeparator));
@@ -1401,7 +1401,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
categories = memnew(OptionButton);
categories->add_item(TTR("All"));
search_hb2->add_child(categories);
- categories->set_h_size_flags(SIZE_EXPAND_FILL);
+ categories->set_h_size_flags(Control::SIZE_EXPAND_FILL);
categories->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_rerun_search));
search_hb2->add_child(memnew(VSeparator));
@@ -1417,7 +1417,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
repository->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_repository_changed));
search_hb2->add_child(repository);
- repository->set_h_size_flags(SIZE_EXPAND_FILL);
+ repository->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_hb2->add_child(memnew(VSeparator));
@@ -1435,7 +1435,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_scroll_bg = memnew(PanelContainer);
library_main->add_child(library_scroll_bg);
- library_scroll_bg->set_v_size_flags(SIZE_EXPAND_FILL);
+ library_scroll_bg->set_v_size_flags(Control::SIZE_EXPAND_FILL);
library_scroll = memnew(ScrollContainer);
library_scroll->set_enable_v_scroll(true);
@@ -1452,11 +1452,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
PanelContainer *library_vb_border = memnew(PanelContainer);
library_scroll->add_child(library_vb_border);
- library_vb_border->add_style_override("panel", border2);
- library_vb_border->set_h_size_flags(SIZE_EXPAND_FILL);
+ library_vb_border->add_theme_style_override("panel", border2);
+ library_vb_border->set_h_size_flags(Control::SIZE_EXPAND_FILL);
library_vb = memnew(VBoxContainer);
- library_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ library_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
library_vb_border->add_child(library_vb);
@@ -1474,8 +1474,8 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
asset_items = memnew(GridContainer);
asset_items->set_columns(2);
- asset_items->add_constant_override("hseparation", 10 * EDSCALE);
- asset_items->add_constant_override("vseparation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("hseparation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("vseparation", 10 * EDSCALE);
library_vb->add_child(asset_items);
@@ -1489,18 +1489,18 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
last_queue_id = 0;
- library_vb->add_constant_override("separation", 20 * EDSCALE);
+ library_vb->add_theme_constant_override("separation", 20 * EDSCALE);
error_hb = memnew(HBoxContainer);
library_main->add_child(error_hb);
error_label = memnew(Label);
- error_label->add_color_override("color", get_color("error_color", "Editor"));
+ error_label->add_theme_color_override("color", get_theme_color("error_color", "Editor"));
error_hb->add_child(error_label);
error_tr = memnew(TextureRect);
error_tr->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
error_hb->add_child(error_tr);
- description = NULL;
+ description = nullptr;
set_process(true);
set_process_unhandled_input(true);
@@ -1516,11 +1516,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
asset_open->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
asset_open->add_filter("*.zip ; " + TTR("Assets ZIP File"));
- asset_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ asset_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
add_child(asset_open);
asset_open->connect("file_selected", callable_mp(this, &EditorAssetLibrary::_asset_file_selected));
- asset_installer = NULL;
+ asset_installer = nullptr;
}
///////
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 7a1722c73b..0459ac7618 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -43,10 +43,10 @@ void AudioStreamEditor::_notification(int p_what) {
}
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- _play_button->set_icon(get_icon("MainPlay", "EditorIcons"));
- _stop_button->set_icon(get_icon("Stop", "EditorIcons"));
- _preview->set_frame_color(get_color("dark_color_2", "Editor"));
- set_frame_color(get_color("dark_color_1", "Editor"));
+ _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
+ _stop_button->set_icon(get_theme_icon("Stop", "EditorIcons"));
+ _preview->set_frame_color(get_theme_color("dark_color_2", "Editor"));
+ set_frame_color(get_theme_color("dark_color_1", "Editor"));
_indicator->update();
_preview->update();
@@ -87,9 +87,9 @@ void AudioStreamEditor::_draw_preview() {
}
Vector<Color> color;
- color.push_back(get_color("contrast_color_2", "Editor"));
+ color.push_back(get_theme_color("contrast_color_2", "Editor"));
- VS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, color);
+ RS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, color);
}
void AudioStreamEditor::_preview_changed(ObjectID p_which) {
@@ -110,11 +110,11 @@ void AudioStreamEditor::_play() {
if (_player->is_playing()) {
_player->stop();
- _play_button->set_icon(get_icon("MainPlay", "EditorIcons"));
+ _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
set_process(false);
} else {
_player->play(_current);
- _play_button->set_icon(get_icon("Pause", "EditorIcons"));
+ _play_button->set_icon(get_theme_icon("Pause", "EditorIcons"));
set_process(true);
}
}
@@ -122,7 +122,7 @@ void AudioStreamEditor::_play() {
void AudioStreamEditor::_stop() {
_player->stop();
- _play_button->set_icon(get_icon("MainPlay", "EditorIcons"));
+ _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
_current = 0;
_indicator->update();
set_process(false);
@@ -130,7 +130,7 @@ void AudioStreamEditor::_stop() {
void AudioStreamEditor::_on_finished() {
- _play_button->set_icon(get_icon("MainPlay", "EditorIcons"));
+ _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons"));
if (_current == _player->get_stream()->get_length()) {
_current = 0;
_indicator->update();
@@ -146,7 +146,7 @@ void AudioStreamEditor::_draw_indicator() {
Rect2 rect = _preview->get_rect();
float len = stream->get_length();
float ofs_x = _current / len * rect.size.width;
- _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), get_color("accent_color", "Editor"), 1);
+ _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), get_theme_color("accent_color", "Editor"), 1);
_current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /");
}
@@ -225,7 +225,7 @@ AudioStreamEditor::AudioStreamEditor() {
_preview->add_child(_indicator);
HBoxContainer *hbox = memnew(HBoxContainer);
- hbox->add_constant_override("separation", 0);
+ hbox->add_theme_constant_override("separation", 0);
vbox->add_child(hbox);
_play_button = memnew(ToolButton);
@@ -241,12 +241,12 @@ AudioStreamEditor::AudioStreamEditor() {
_current_label = memnew(Label);
_current_label->set_align(Label::ALIGN_RIGHT);
_current_label->set_h_size_flags(SIZE_EXPAND_FILL);
- _current_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+ _current_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts"));
_current_label->set_modulate(Color(1, 1, 1, 0.5));
hbox->add_child(_current_label);
_duration_label = memnew(Label);
- _duration_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts"));
+ _duration_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts"));
hbox->add_child(_duration_label);
}
diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp
index 6bc9562c5a..ba161244d6 100644
--- a/editor/plugins/baked_lightmap_editor_plugin.cpp
+++ b/editor/plugins/baked_lightmap_editor_plugin.cpp
@@ -81,25 +81,25 @@ void BakedLightmapEditorPlugin::make_visible(bool p_visible) {
}
}
-EditorProgress *BakedLightmapEditorPlugin::tmp_progress = NULL;
+EditorProgress *BakedLightmapEditorPlugin::tmp_progress = nullptr;
void BakedLightmapEditorPlugin::bake_func_begin(int p_steps) {
- ERR_FAIL_COND(tmp_progress != NULL);
+ ERR_FAIL_COND(tmp_progress != nullptr);
tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), p_steps, true));
}
bool BakedLightmapEditorPlugin::bake_func_step(int p_step, const String &p_description) {
- ERR_FAIL_COND_V(tmp_progress == NULL, false);
+ ERR_FAIL_COND_V(tmp_progress == nullptr, false);
return tmp_progress->step(p_description, p_step, false);
}
void BakedLightmapEditorPlugin::bake_func_end() {
- ERR_FAIL_COND(tmp_progress == NULL);
+ ERR_FAIL_COND(tmp_progress == nullptr);
memdelete(tmp_progress);
- tmp_progress = NULL;
+ tmp_progress = nullptr;
}
void BakedLightmapEditorPlugin::_bind_methods() {
@@ -116,7 +116,7 @@ BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
bake->hide();
bake->connect("pressed", this, "_bake");
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
- lightmap = NULL;
+ lightmap = nullptr;
BakedLightmap::bake_begin_function = bake_func_begin;
BakedLightmap::bake_step_function = bake_func_step;
diff --git a/editor/plugins/camera_3d_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..8bc1374269
--- /dev/null
+++ b/editor/plugins/camera_3d_editor_plugin.cpp
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* camera_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "camera_3d_editor_plugin.h"
+
+#include "node_3d_editor_plugin.h"
+
+void Camera3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ Node3DEditor::get_singleton()->set_custom_camera(nullptr);
+ hide();
+ }
+}
+
+void Camera3DEditor::_pressed() {
+
+ Node *sn = (node && preview->is_pressed()) ? node : nullptr;
+ Node3DEditor::get_singleton()->set_custom_camera(sn);
+}
+
+void Camera3DEditor::_bind_methods() {
+}
+
+void Camera3DEditor::edit(Node *p_camera) {
+
+ node = p_camera;
+
+ if (!node) {
+ preview->set_pressed(false);
+ Node3DEditor::get_singleton()->set_custom_camera(nullptr);
+ } else {
+
+ if (preview->is_pressed())
+ Node3DEditor::get_singleton()->set_custom_camera(p_camera);
+ else
+ Node3DEditor::get_singleton()->set_custom_camera(nullptr);
+ }
+}
+
+Camera3DEditor::Camera3DEditor() {
+
+ preview = memnew(Button);
+ add_child(preview);
+
+ preview->set_text(TTR("Preview"));
+ preview->set_toggle_mode(true);
+ preview->set_anchor(MARGIN_LEFT, Control::ANCHOR_END);
+ preview->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END);
+ preview->set_margin(MARGIN_LEFT, -60);
+ preview->set_margin(MARGIN_RIGHT, 0);
+ preview->set_margin(MARGIN_TOP, 0);
+ preview->set_margin(MARGIN_BOTTOM, 10);
+ preview->connect("pressed", callable_mp(this, &Camera3DEditor::_pressed));
+}
+
+void Camera3DEditorPlugin::edit(Object *p_object) {
+
+ Node3DEditor::get_singleton()->set_can_preview(Object::cast_to<Camera3D>(p_object));
+ //camera_editor->edit(Object::cast_to<Node>(p_object));
+}
+
+bool Camera3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("Camera3D");
+}
+
+void Camera3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ //Node3DEditor::get_singleton()->set_can_preview(Object::cast_to<Camera3D>(p_object));
+ } else {
+ Node3DEditor::get_singleton()->set_can_preview(nullptr);
+ }
+}
+
+Camera3DEditorPlugin::Camera3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ /* camera_editor = memnew( CameraEditor );
+ editor->get_viewport()->add_child(camera_editor);
+
+ camera_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
+ camera_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
+ camera_editor->set_margin(MARGIN_LEFT,60);
+ camera_editor->set_margin(MARGIN_RIGHT,0);
+ camera_editor->set_margin(MARGIN_TOP,0);
+ camera_editor->set_margin(MARGIN_BOTTOM,10);
+
+
+ camera_editor->hide();
+*/
+}
+
+Camera3DEditorPlugin::~Camera3DEditorPlugin() {
+}
diff --git a/editor/plugins/camera_3d_editor_plugin.h b/editor/plugins/camera_3d_editor_plugin.h
new file mode 100644
index 0000000000..1e57ac7cd2
--- /dev/null
+++ b/editor/plugins/camera_3d_editor_plugin.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* camera_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CAMERA_EDITOR_PLUGIN_H
+#define CAMERA_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/camera_3d.h"
+
+class Camera3DEditor : public Control {
+
+ GDCLASS(Camera3DEditor, Control);
+
+ Panel *panel;
+ Button *preview;
+ Node *node;
+
+ void _pressed();
+
+protected:
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ void edit(Node *p_camera);
+ Camera3DEditor();
+};
+
+class Camera3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(Camera3DEditorPlugin, EditorPlugin);
+
+ //CameraEditor *camera_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const { return "Camera3D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ Camera3DEditorPlugin(EditorNode *p_node);
+ ~Camera3DEditorPlugin();
+};
+
+#endif // CAMERA_EDITOR_PLUGIN_H
diff --git a/editor/plugins/camera_editor_plugin.cpp b/editor/plugins/camera_editor_plugin.cpp
deleted file mode 100644
index 8726c8c552..0000000000
--- a/editor/plugins/camera_editor_plugin.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*************************************************************************/
-/* camera_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "camera_editor_plugin.h"
-
-#include "spatial_editor_plugin.h"
-
-void CameraEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- SpatialEditor::get_singleton()->set_custom_camera(NULL);
- hide();
- }
-}
-
-void CameraEditor::_pressed() {
-
- Node *sn = (node && preview->is_pressed()) ? node : NULL;
- SpatialEditor::get_singleton()->set_custom_camera(sn);
-}
-
-void CameraEditor::_bind_methods() {
-}
-
-void CameraEditor::edit(Node *p_camera) {
-
- node = p_camera;
-
- if (!node) {
- preview->set_pressed(false);
- SpatialEditor::get_singleton()->set_custom_camera(NULL);
- } else {
-
- if (preview->is_pressed())
- SpatialEditor::get_singleton()->set_custom_camera(p_camera);
- else
- SpatialEditor::get_singleton()->set_custom_camera(NULL);
- }
-}
-
-CameraEditor::CameraEditor() {
-
- preview = memnew(Button);
- add_child(preview);
-
- preview->set_text(TTR("Preview"));
- preview->set_toggle_mode(true);
- preview->set_anchor(MARGIN_LEFT, Control::ANCHOR_END);
- preview->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END);
- preview->set_margin(MARGIN_LEFT, -60);
- preview->set_margin(MARGIN_RIGHT, 0);
- preview->set_margin(MARGIN_TOP, 0);
- preview->set_margin(MARGIN_BOTTOM, 10);
- preview->connect("pressed", callable_mp(this, &CameraEditor::_pressed));
-}
-
-void CameraEditorPlugin::edit(Object *p_object) {
-
- SpatialEditor::get_singleton()->set_can_preview(Object::cast_to<Camera>(p_object));
- //camera_editor->edit(Object::cast_to<Node>(p_object));
-}
-
-bool CameraEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Camera");
-}
-
-void CameraEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- //SpatialEditor::get_singleton()->set_can_preview(Object::cast_to<Camera>(p_object));
- } else {
- SpatialEditor::get_singleton()->set_can_preview(NULL);
- }
-}
-
-CameraEditorPlugin::CameraEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- /* camera_editor = memnew( CameraEditor );
- editor->get_viewport()->add_child(camera_editor);
-
- camera_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
- camera_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
- camera_editor->set_margin(MARGIN_LEFT,60);
- camera_editor->set_margin(MARGIN_RIGHT,0);
- camera_editor->set_margin(MARGIN_TOP,0);
- camera_editor->set_margin(MARGIN_BOTTOM,10);
-
-
- camera_editor->hide();
-*/
-}
-
-CameraEditorPlugin::~CameraEditorPlugin() {
-}
diff --git a/editor/plugins/camera_editor_plugin.h b/editor/plugins/camera_editor_plugin.h
deleted file mode 100644
index 9758a1ffbd..0000000000
--- a/editor/plugins/camera_editor_plugin.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*************************************************************************/
-/* camera_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CAMERA_EDITOR_PLUGIN_H
-#define CAMERA_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/3d/camera.h"
-
-class CameraEditor : public Control {
-
- GDCLASS(CameraEditor, Control);
-
- Panel *panel;
- Button *preview;
- Node *node;
-
- void _pressed();
-
-protected:
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
-public:
- void edit(Node *p_camera);
- CameraEditor();
-};
-
-class CameraEditorPlugin : public EditorPlugin {
-
- GDCLASS(CameraEditorPlugin, EditorPlugin);
-
- //CameraEditor *camera_editor;
- EditorNode *editor;
-
-public:
- virtual String get_name() const { return "Camera"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- CameraEditorPlugin(EditorNode *p_node);
- ~CameraEditorPlugin();
-};
-
-#endif // CAMERA_EDITOR_PLUGIN_H
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 5629e3854d..cd3df08276 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -30,7 +30,7 @@
#include "canvas_item_editor_plugin.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "core/print_string.h"
#include "core/project_settings.h"
@@ -40,17 +40,17 @@
#include "editor/editor_settings.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
+#include "scene/2d/gpu_particles_2d.h"
#include "scene/2d/light_2d.h"
-#include "scene/2d/particles_2d.h"
#include "scene/2d/polygon_2d.h"
#include "scene/2d/skeleton_2d.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/sprite_2d.h"
#include "scene/2d/touch_screen_button.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/nine_patch_rect.h"
-#include "scene/gui/viewport_container.h"
+#include "scene/gui/subviewport_container.h"
#include "scene/main/canvas_layer.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
#define MIN_ZOOM 0.01
@@ -99,7 +99,7 @@ public:
label = memnew(Label);
label->set_text(TTR("Grid Offset:"));
child_container->add_child(label);
- label->set_h_size_flags(SIZE_EXPAND_FILL);
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid_offset_x = memnew(SpinBox);
grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE);
@@ -107,7 +107,7 @@ public:
grid_offset_x->set_allow_lesser(true);
grid_offset_x->set_allow_greater(true);
grid_offset_x->set_suffix("px");
- grid_offset_x->set_h_size_flags(SIZE_EXPAND_FILL);
+ grid_offset_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(grid_offset_x);
grid_offset_y = memnew(SpinBox);
@@ -116,20 +116,20 @@ public:
grid_offset_y->set_allow_lesser(true);
grid_offset_y->set_allow_greater(true);
grid_offset_y->set_suffix("px");
- grid_offset_y->set_h_size_flags(SIZE_EXPAND_FILL);
+ grid_offset_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(grid_offset_y);
label = memnew(Label);
label->set_text(TTR("Grid Step:"));
child_container->add_child(label);
- label->set_h_size_flags(SIZE_EXPAND_FILL);
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid_step_x = memnew(SpinBox);
grid_step_x->set_min(0.01);
grid_step_x->set_max(SPIN_BOX_GRID_RANGE);
grid_step_x->set_allow_greater(true);
grid_step_x->set_suffix("px");
- grid_step_x->set_h_size_flags(SIZE_EXPAND_FILL);
+ grid_step_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(grid_step_x);
grid_step_y = memnew(SpinBox);
@@ -137,7 +137,7 @@ public:
grid_step_y->set_max(SPIN_BOX_GRID_RANGE);
grid_step_y->set_allow_greater(true);
grid_step_y->set_suffix("px");
- grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL);
+ grid_step_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(grid_step_y);
child_container = memnew(GridContainer);
@@ -146,7 +146,7 @@ public:
label = memnew(Label);
label->set_text(TTR("Primary Line Every:"));
- label->set_h_size_flags(SIZE_EXPAND_FILL);
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(label);
primary_grid_steps = memnew(SpinBox);
@@ -155,7 +155,7 @@ public:
primary_grid_steps->set_max(100);
primary_grid_steps->set_allow_greater(true);
primary_grid_steps->set_suffix(TTR("steps"));
- primary_grid_steps->set_h_size_flags(SIZE_EXPAND_FILL);
+ primary_grid_steps->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(primary_grid_steps);
container->add_child(memnew(HSeparator));
@@ -169,25 +169,25 @@ public:
label = memnew(Label);
label->set_text(TTR("Rotation Offset:"));
child_container->add_child(label);
- label->set_h_size_flags(SIZE_EXPAND_FILL);
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
rotation_offset = memnew(SpinBox);
rotation_offset->set_min(-SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_suffix("deg");
- rotation_offset->set_h_size_flags(SIZE_EXPAND_FILL);
+ rotation_offset->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(rotation_offset);
label = memnew(Label);
label->set_text(TTR("Rotation Step:"));
child_container->add_child(label);
- label->set_h_size_flags(SIZE_EXPAND_FILL);
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
rotation_step = memnew(SpinBox);
rotation_step->set_min(-SPIN_BOX_ROTATION_RANGE);
rotation_step->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_step->set_suffix("deg");
- rotation_step->set_h_size_flags(SIZE_EXPAND_FILL);
+ rotation_step->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(rotation_step);
container->add_child(memnew(HSeparator));
@@ -198,13 +198,13 @@ public:
label = memnew(Label);
label->set_text(TTR("Scale Step:"));
child_container->add_child(label);
- label->set_h_size_flags(SIZE_EXPAND_FILL);
+ label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
scale_step = memnew(SpinBox);
scale_step->set_min(SPIN_BOX_SCALE_MIN);
scale_step->set_max(SPIN_BOX_SCALE_MAX);
scale_step->set_allow_greater(true);
- scale_step->set_h_size_flags(SIZE_EXPAND_FILL);
+ scale_step->set_h_size_flags(Control::SIZE_EXPAND_FILL);
scale_step->set_step(0.01f);
child_container->add_child(scale_step);
}
@@ -334,7 +334,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
- bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool is_snap_active = smart_snap_active ^ InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
// Smart snap using the canvas position
Vector2 output = p_target;
@@ -462,7 +462,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
}
float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
- if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) && snap_rotation_step != 0) {
+ if (((smart_snap_active || snap_rotation) ^ InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) && snap_rotation_step != 0) {
if (snap_relative) {
return Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step);
} else {
@@ -477,7 +477,7 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventKey> k = p_ev;
- if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
+ if (!is_visible_in_tree())
return;
if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) {
@@ -503,7 +503,7 @@ Object *CanvasItemEditor::_get_editor_data(Object *p_what) {
CanvasItem *ci = Object::cast_to<CanvasItem>(p_what);
if (!ci)
- return NULL;
+ return nullptr;
return memnew(CanvasItemEditorSelectedItem);
}
@@ -667,7 +667,7 @@ void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResu
Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from));
Vector<Vector2> bone_shape;
- if (!_get_bone_shape(&bone_shape, NULL, E))
+ if (!_get_bone_shape(&bone_shape, nullptr, E))
continue;
// Check if the point is inside the Polygon2D
@@ -1284,7 +1284,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
// Pan the viewport
Point2i relative;
if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
- relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect());
+ relative = InputFilter::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect());
} else {
relative = m->get_relative();
}
@@ -1343,7 +1343,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
if (drag_selection.size() == 1) {
new_pos = snap_point(drag_from, SNAP_NODE_SIDES | SNAP_NODE_CENTER | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, drag_selection[0]);
} else {
- new_pos = snap_point(drag_from, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, NULL, drag_selection);
+ new_pos = snap_point(drag_from, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, nullptr, drag_selection);
}
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
@@ -1912,13 +1912,14 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
bool uniform = m->get_shift();
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool is_ctrl = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
Point2 offset = drag_to_local - drag_from_local;
Size2 scale = canvas_item->call("get_scale");
+ Size2 original_scale = scale;
float ratio = scale.y / scale.x;
if (drag_type == DRAG_SCALE_BOTH) {
Size2 scale_factor = drag_to_local / drag_from_local;
@@ -1931,6 +1932,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE;
Size2 parent_scale = parent_xform.get_scale();
scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y);
+
if (drag_type == DRAG_SCALE_X) {
scale.x += scale_factor.x;
if (uniform) {
@@ -1945,8 +1947,13 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
if (snap_scale && !is_ctrl) {
- scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step;
- scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step;
+ if (snap_relative) {
+ scale.x = original_scale.x * (roundf((scale.x / original_scale.x) / snap_scale_step) * snap_scale_step);
+ scale.y = original_scale.y * (roundf((scale.y / original_scale.y) / snap_scale_step) * snap_scale_step);
+ } else {
+ scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step;
+ scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step;
+ }
}
canvas_item->call("set_scale", scale);
@@ -2028,10 +2035,10 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (m.is_valid()) {
// Save the ik chain for reapplying before IK solve
- Vector<List<Dictionary> > all_bones_ik_states;
+ Vector<List<Dictionary>> all_bones_ik_states;
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
List<Dictionary> bones_ik_states;
- _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
+ _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states);
all_bones_ik_states.push_back(bones_ik_states);
}
@@ -2046,7 +2053,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
}
- Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, NULL, drag_selection);
+ Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, nullptr, drag_selection);
if (drag_type == DRAG_MOVE_X) {
new_pos.y = previous_pos.y;
@@ -2130,10 +2137,10 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_selection.size() > 0) {
// Save the ik chain for reapplying before IK solve
- Vector<List<Dictionary> > all_bones_ik_states;
+ Vector<List<Dictionary>> all_bones_ik_states;
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
List<Dictionary> bones_ik_states;
- _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
+ _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states);
all_bones_ik_states.push_back(bones_ik_states);
}
@@ -2207,10 +2214,10 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && tool == TOOL_SELECT &&
(k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)) {
// Confirm canvas items move by arrow keys
- if ((!Input::get_singleton()->is_key_pressed(KEY_UP)) &&
- (!Input::get_singleton()->is_key_pressed(KEY_DOWN)) &&
- (!Input::get_singleton()->is_key_pressed(KEY_LEFT)) &&
- (!Input::get_singleton()->is_key_pressed(KEY_RIGHT))) {
+ if ((!InputFilter::get_singleton()->is_key_pressed(KEY_UP)) &&
+ (!InputFilter::get_singleton()->is_key_pressed(KEY_DOWN)) &&
+ (!InputFilter::get_singleton()->is_key_pressed(KEY_LEFT)) &&
+ (!InputFilter::get_singleton()->is_key_pressed(KEY_RIGHT))) {
_commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true);
drag_type = DRAG_NONE;
}
@@ -2284,7 +2291,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
selection_menu_additive_selection = b->get_shift();
- selection_menu->set_global_position(b->get_global_position());
+ selection_menu->set_position(get_screen_transform().xform(b->get_position()));
selection_menu->popup();
return true;
}
@@ -2299,7 +2306,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
return true;
// Find the item to select
- CanvasItem *canvas_item = NULL;
+ CanvasItem *canvas_item = nullptr;
// Retrieve the bones
Vector<_SelectResult> selection = Vector<_SelectResult>();
@@ -2588,9 +2595,9 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
}
void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Margin p_side) {
- Color color = get_color("font_color", "Editor");
+ Color color = get_theme_color("font_color", "Editor");
color.a = 0.8;
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
Size2 text_size = font->get_string_size(p_string);
switch (p_side) {
case MARGIN_LEFT:
@@ -2626,7 +2633,7 @@ void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_posi
void CanvasItemEditor::_draw_focus() {
// Draw the focus around the base viewport
if (viewport->has_focus()) {
- get_stylebox("Focus", "EditorStyles")->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size()));
+ get_theme_stylebox("Focus", "EditorStyles")->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size()));
}
}
@@ -2657,18 +2664,18 @@ void CanvasItemEditor::_draw_guides() {
}
// Dragged guide
- Color text_color = get_color("font_color", "Editor");
+ Color text_color = get_theme_color("font_color", "Editor");
text_color.a = 0.5;
if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_V_GUIDE) {
String str = vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x));
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
Size2 text_size = font->get_string_size(str);
viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, text_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 = vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y));
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
Size2 text_size = font->get_string_size(str);
viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, text_color);
viewport->draw_line(Point2(0, dragged_guide_pos.y), Point2(viewport->get_size().x, dragged_guide_pos.y), guide_color, Math::round(EDSCALE));
@@ -2690,11 +2697,11 @@ void CanvasItemEditor::_draw_smart_snapping() {
}
void CanvasItemEditor::_draw_rulers() {
- Color bg_color = get_color("dark_color_2", "Editor");
- Color graduation_color = get_color("font_color", "Editor").linear_interpolate(bg_color, 0.5);
- Color font_color = get_color("font_color", "Editor");
+ Color bg_color = get_theme_color("dark_color_2", "Editor");
+ Color graduation_color = get_theme_color("font_color", "Editor").linear_interpolate(bg_color, 0.5);
+ Color font_color = get_theme_color("font_color", "Editor");
font_color.a = 0.8;
- Ref<Font> font = get_font("rulers", "EditorFonts");
+ Ref<Font> font = get_theme_font("rulers", "EditorFonts");
// The rule transform
Transform2D ruler_transform = Transform2D();
@@ -2856,7 +2863,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
return;
if (ruler_tool_active) {
- Color ruler_primary_color = get_color("accent_color", "Editor");
+ Color ruler_primary_color = get_theme_color("accent_color", "Editor");
Color ruler_secondary_color = ruler_primary_color;
ruler_secondary_color.a = 0.5;
@@ -2873,8 +2880,8 @@ void CanvasItemEditor::_draw_ruler_tool() {
viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE));
}
- Ref<Font> font = get_font("bold", "EditorFonts");
- Color font_color = get_color("font_color", "Editor");
+ Ref<Font> font = get_theme_font("bold", "EditorFonts");
+ Color font_color = get_theme_color("font_color", "Editor");
Color font_secondary_color = font_color;
font_secondary_color.a = 0.5;
float text_height = font->get_height();
@@ -2974,8 +2981,8 @@ void CanvasItemEditor::_draw_ruler_tool() {
} else {
if (grid_snap_active) {
- Ref<Texture2D> position_icon = get_icon("EditorPosition", "EditorIcons");
- viewport->draw_texture(get_icon("EditorPosition", "EditorIcons"), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
+ Ref<Texture2D> position_icon = get_theme_icon("EditorPosition", "EditorIcons");
+ viewport->draw_texture(get_theme_icon("EditorPosition", "EditorIcons"), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
}
}
}
@@ -3187,19 +3194,21 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
}
void CanvasItemEditor::_draw_selection() {
- Ref<Texture2D> pivot_icon = get_icon("EditorPivot", "EditorIcons");
- Ref<Texture2D> position_icon = get_icon("EditorPosition", "EditorIcons");
- Ref<Texture2D> previous_position_icon = get_icon("EditorPositionPrevious", "EditorIcons");
+ Ref<Texture2D> pivot_icon = get_theme_icon("EditorPivot", "EditorIcons");
+ Ref<Texture2D> position_icon = get_theme_icon("EditorPosition", "EditorIcons");
+ Ref<Texture2D> previous_position_icon = get_theme_icon("EditorPositionPrevious", "EditorIcons");
RID ci = viewport->get_canvas_item();
- List<CanvasItem *> selection = _get_edited_canvas_items(false, false);
+ List<CanvasItem *> selection = _get_edited_canvas_items(true, false);
bool single = selection.size() == 1;
for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get());
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ bool item_locked = canvas_item->has_meta("_edit_lock_");
+
// Draw the previous position if we are dragging the node
if (show_helpers &&
(drag_type == DRAG_MOVE || drag_type == DRAG_ROTATE ||
@@ -3239,6 +3248,10 @@ void CanvasItemEditor::_draw_selection() {
Color c = Color(1, 0.6, 0.4, 0.7);
+ if (item_locked) {
+ c = Color(0.7, 0.7, 0.7, 0.7);
+ }
+
for (int i = 0; i < 4; i++) {
viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, Math::round(2 * EDSCALE));
}
@@ -3251,7 +3264,7 @@ void CanvasItemEditor::_draw_selection() {
viewport->draw_set_transform_matrix(viewport->get_transform());
}
- if (single && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks
+ if (single && !item_locked && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks
// Draw the pivot
if (canvas_item->_edit_use_pivot()) {
@@ -3297,8 +3310,8 @@ void CanvasItemEditor::_draw_selection() {
}
// Draw the move handles
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
- bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
+ bool is_ctrl = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool is_alt = InputFilter::get_singleton()->is_key_pressed(KEY_ALT);
if (tool == TOOL_MOVE && show_transformation_gizmos) {
if (_is_node_movable(canvas_item)) {
Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
@@ -3312,16 +3325,16 @@ void CanvasItemEditor::_draw_selection() {
points.push_back(Vector2(move_factor.x * EDSCALE, -5 * EDSCALE));
points.push_back(Vector2((move_factor.x + 10) * EDSCALE, 0));
- viewport->draw_colored_polygon(points, get_color("axis_x_color", "Editor"));
- viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_color("axis_x_color", "Editor"), Math::round(EDSCALE));
+ viewport->draw_colored_polygon(points, get_theme_color("axis_x_color", "Editor"));
+ viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_theme_color("axis_x_color", "Editor"), Math::round(EDSCALE));
points.clear();
points.push_back(Vector2(5 * EDSCALE, move_factor.y * EDSCALE));
points.push_back(Vector2(-5 * EDSCALE, move_factor.y * EDSCALE));
points.push_back(Vector2(0, (move_factor.y + 10) * EDSCALE));
- viewport->draw_colored_polygon(points, get_color("axis_y_color", "Editor"));
- viewport->draw_line(Point2(), Point2(0, move_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE));
+ viewport->draw_colored_polygon(points, get_theme_color("axis_y_color", "Editor"));
+ viewport->draw_line(Point2(), Point2(0, move_factor.y * EDSCALE), get_theme_color("axis_y_color", "Editor"), Math::round(EDSCALE));
viewport->draw_set_transform_matrix(viewport->get_transform());
}
@@ -3334,7 +3347,7 @@ void CanvasItemEditor::_draw_selection() {
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
- bool uniform = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool uniform = InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT);
Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
if (drag_type == DRAG_SCALE_X) {
@@ -3351,12 +3364,12 @@ void CanvasItemEditor::_draw_selection() {
viewport->draw_set_transform_matrix(simple_xform);
Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- viewport->draw_rect(x_handle_rect, get_color("axis_x_color", "Editor"));
- viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_color("axis_x_color", "Editor"), Math::round(EDSCALE));
+ viewport->draw_rect(x_handle_rect, get_theme_color("axis_x_color", "Editor"));
+ viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_theme_color("axis_x_color", "Editor"), Math::round(EDSCALE));
Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- viewport->draw_rect(y_handle_rect, get_color("axis_y_color", "Editor"));
- viewport->draw_line(Point2(), Point2(0, scale_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE));
+ viewport->draw_rect(y_handle_rect, get_theme_color("axis_y_color", "Editor"));
+ viewport->draw_line(Point2(), Point2(0, scale_factor.y * EDSCALE), get_theme_color("axis_y_color", "Editor"), Math::round(EDSCALE));
viewport->draw_set_transform_matrix(viewport->get_transform());
}
@@ -3371,11 +3384,11 @@ void CanvasItemEditor::_draw_selection() {
viewport->draw_rect(
Rect2(bsfrom, bsto - bsfrom),
- get_color("box_selection_fill_color", "Editor"));
+ get_theme_color("box_selection_fill_color", "Editor"));
viewport->draw_rect(
Rect2(bsfrom, bsto - bsfrom),
- get_color("box_selection_stroke_color", "Editor"),
+ get_theme_color("box_selection_stroke_color", "Editor"),
false,
Math::round(EDSCALE));
}
@@ -3385,7 +3398,7 @@ void CanvasItemEditor::_draw_selection() {
viewport->draw_line(
transform.xform(drag_rotation_center),
transform.xform(drag_to),
- get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
+ get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
Math::round(2 * EDSCALE));
}
}
@@ -3427,7 +3440,7 @@ void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_c
}
}
if (points.size() >= 2) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, points[0], points[1], p_color);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, points[0], points[1], p_color);
}
}
@@ -3435,8 +3448,8 @@ void CanvasItemEditor::_draw_axis() {
if (show_origin) {
- _draw_straight_line(Point2(), Point2(1, 0), get_color("axis_x_color", "Editor") * Color(1, 1, 1, 0.75));
- _draw_straight_line(Point2(), Point2(0, 1), get_color("axis_y_color", "Editor") * Color(1, 1, 1, 0.75));
+ _draw_straight_line(Point2(), Point2(1, 0), get_theme_color("axis_x_color", "Editor") * Color(1, 1, 1, 0.75));
+ _draw_straight_line(Point2(), Point2(0, 1), get_theme_color("axis_y_color", "Editor") * Color(1, 1, 1, 0.75));
}
if (show_viewport) {
@@ -3455,7 +3468,7 @@ void CanvasItemEditor::_draw_axis() {
};
for (int i = 0; i < 4; i++) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color);
}
}
}
@@ -3512,8 +3525,8 @@ void CanvasItemEditor::_draw_bones() {
outline_colors.push_back(bone_outline_color);
}
- VisualServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors);
- VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID());
+ RenderingServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors);
+ RenderingServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID());
}
}
}
@@ -3547,7 +3560,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
Transform2D xform = transform * canvas_xform * parent_xform;
// Draw the node's position
- Ref<Texture2D> position_icon = get_icon("EditorPositionUnselected", "EditorIcons");
+ Ref<Texture2D> position_icon = get_theme_icon("EditorPositionUnselected", "EditorIcons");
Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
@@ -3564,7 +3577,7 @@ void CanvasItemEditor::_draw_hover() {
Ref<Texture2D> node_icon = hovering_results[i].icon;
String node_name = hovering_results[i].name;
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
Size2 node_name_size = font->get_string_size(node_name);
Size2 item_size = Size2(node_icon->get_size().x + 4 + node_name_size.x, MAX(node_icon->get_size().y, node_name_size.y - 3));
@@ -3615,13 +3628,13 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
if (canvas_item) {
float offset = 0;
- Ref<Texture2D> lock = get_icon("LockViewport", "EditorIcons");
+ Ref<Texture2D> lock = get_theme_icon("LockViewport", "EditorIcons");
if (p_node->has_meta("_edit_lock_") && show_edit_locks) {
lock->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
offset += lock->get_size().x;
}
- Ref<Texture2D> group = get_icon("GroupViewport", "EditorIcons");
+ Ref<Texture2D> group = get_theme_icon("GroupViewport", "EditorIcons");
if (canvas_item->has_meta("_edit_group_") && show_edit_locks) {
group->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
//offset += group->get_size().x;
@@ -3744,7 +3757,7 @@ void CanvasItemEditor::_draw_viewport() {
}
RID ci = viewport->get_canvas_item();
- VisualServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D());
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D());
EditorPluginList *over_plugin_list = editor->get_editor_plugins_over();
if (!over_plugin_list->empty()) {
@@ -3893,7 +3906,7 @@ void CanvasItemEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons"));
+ select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons"));
for (int i = 0; i < 4; i++) {
select_sb->set_margin_size(Margin(i), 4);
select_sb->set_default_margin(Margin(i), 4);
@@ -3906,7 +3919,7 @@ void CanvasItemEditor::_notification(int p_what) {
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons"));
+ select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons"));
}
if (p_what == NOTIFICATION_EXIT_TREE) {
@@ -3915,85 +3928,85 @@ void CanvasItemEditor::_notification(int p_what) {
}
if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- select_button->set_icon(get_icon("ToolSelect", "EditorIcons"));
- list_select_button->set_icon(get_icon("ListSelect", "EditorIcons"));
- move_button->set_icon(get_icon("ToolMove", "EditorIcons"));
- scale_button->set_icon(get_icon("ToolScale", "EditorIcons"));
- rotate_button->set_icon(get_icon("ToolRotate", "EditorIcons"));
- smart_snap_button->set_icon(get_icon("Snap", "EditorIcons"));
- grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons"));
- snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
- skeleton_menu->set_icon(get_icon("Bone", "EditorIcons"));
- override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons"));
- pan_button->set_icon(get_icon("ToolPan", "EditorIcons"));
- ruler_button->set_icon(get_icon("Ruler", "EditorIcons"));
- pivot_button->set_icon(get_icon("EditPivot", "EditorIcons"));
- select_handle = get_icon("EditorHandle", "EditorIcons");
- anchor_handle = get_icon("EditorControlAnchor", "EditorIcons");
- lock_button->set_icon(get_icon("Lock", "EditorIcons"));
- unlock_button->set_icon(get_icon("Unlock", "EditorIcons"));
- group_button->set_icon(get_icon("Group", "EditorIcons"));
- ungroup_button->set_icon(get_icon("Ungroup", "EditorIcons"));
- key_loc_button->set_icon(get_icon("KeyPosition", "EditorIcons"));
- key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons"));
- key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons"));
- key_insert_button->set_icon(get_icon("Key", "EditorIcons"));
- key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons"));
- animation_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
-
- zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons"));
- zoom_plus->set_icon(get_icon("ZoomMore", "EditorIcons"));
-
- presets_menu->set_icon(get_icon("ControlLayout", "EditorIcons"));
+ select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ list_select_button->set_icon(get_theme_icon("ListSelect", "EditorIcons"));
+ move_button->set_icon(get_theme_icon("ToolMove", "EditorIcons"));
+ scale_button->set_icon(get_theme_icon("ToolScale", "EditorIcons"));
+ rotate_button->set_icon(get_theme_icon("ToolRotate", "EditorIcons"));
+ smart_snap_button->set_icon(get_theme_icon("Snap", "EditorIcons"));
+ grid_snap_button->set_icon(get_theme_icon("SnapGrid", "EditorIcons"));
+ snap_config_menu->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
+ skeleton_menu->set_icon(get_theme_icon("Bone", "EditorIcons"));
+ override_camera_button->set_icon(get_theme_icon("Camera2D", "EditorIcons"));
+ pan_button->set_icon(get_theme_icon("ToolPan", "EditorIcons"));
+ ruler_button->set_icon(get_theme_icon("Ruler", "EditorIcons"));
+ pivot_button->set_icon(get_theme_icon("EditPivot", "EditorIcons"));
+ select_handle = get_theme_icon("EditorHandle", "EditorIcons");
+ anchor_handle = get_theme_icon("EditorControlAnchor", "EditorIcons");
+ lock_button->set_icon(get_theme_icon("Lock", "EditorIcons"));
+ unlock_button->set_icon(get_theme_icon("Unlock", "EditorIcons"));
+ group_button->set_icon(get_theme_icon("Group", "EditorIcons"));
+ ungroup_button->set_icon(get_theme_icon("Ungroup", "EditorIcons"));
+ key_loc_button->set_icon(get_theme_icon("KeyPosition", "EditorIcons"));
+ key_rot_button->set_icon(get_theme_icon("KeyRotation", "EditorIcons"));
+ key_scale_button->set_icon(get_theme_icon("KeyScale", "EditorIcons"));
+ key_insert_button->set_icon(get_theme_icon("Key", "EditorIcons"));
+ key_auto_insert_button->set_icon(get_theme_icon("AutoKey", "EditorIcons"));
+ animation_menu->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
+
+ zoom_minus->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
+ zoom_plus->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
+
+ presets_menu->set_icon(get_theme_icon("ControlLayout", "EditorIcons"));
PopupMenu *p = presets_menu->get_popup();
p->clear();
- p->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_MARGINS_PRESET_TOP_LEFT);
- p->add_icon_item(get_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT);
- p->add_icon_item(get_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT);
- p->add_icon_item(get_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT);
+ p->add_icon_item(get_theme_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_MARGINS_PRESET_TOP_LEFT);
+ p->add_icon_item(get_theme_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT);
+ p->add_icon_item(get_theme_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT);
+ p->add_icon_item(get_theme_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT);
p->add_separator();
- p->add_icon_item(get_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT);
- p->add_icon_item(get_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_MARGINS_PRESET_CENTER_TOP);
- p->add_icon_item(get_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT);
- p->add_icon_item(get_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM);
- p->add_icon_item(get_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_MARGINS_PRESET_CENTER);
+ p->add_icon_item(get_theme_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT);
+ p->add_icon_item(get_theme_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_MARGINS_PRESET_CENTER_TOP);
+ p->add_icon_item(get_theme_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT);
+ p->add_icon_item(get_theme_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM);
+ p->add_icon_item(get_theme_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_MARGINS_PRESET_CENTER);
p->add_separator();
- p->add_icon_item(get_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE);
- p->add_icon_item(get_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_MARGINS_PRESET_TOP_WIDE);
- p->add_icon_item(get_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE);
- p->add_icon_item(get_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE);
- p->add_icon_item(get_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE);
- p->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE);
+ p->add_icon_item(get_theme_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE);
+ p->add_icon_item(get_theme_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_MARGINS_PRESET_TOP_WIDE);
+ p->add_icon_item(get_theme_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE);
+ p->add_icon_item(get_theme_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE);
+ p->add_icon_item(get_theme_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE);
+ p->add_icon_item(get_theme_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE);
p->add_separator();
- p->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_MARGINS_PRESET_WIDE);
- p->add_icon_item(get_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO);
+ p->add_icon_item(get_theme_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_MARGINS_PRESET_WIDE);
+ p->add_icon_item(get_theme_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO);
p->add_separator();
p->add_submenu_item(TTR("Anchors only"), "Anchors");
- p->set_item_icon(21, get_icon("Anchor", "EditorIcons"));
+ p->set_item_icon(21, get_theme_icon("Anchor", "EditorIcons"));
anchors_popup->clear();
- anchors_popup->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT);
- anchors_popup->add_icon_item(get_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT);
- anchors_popup->add_icon_item(get_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT);
- anchors_popup->add_icon_item(get_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT);
anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT);
- anchors_popup->add_icon_item(get_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP);
- anchors_popup->add_icon_item(get_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT);
- anchors_popup->add_icon_item(get_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM);
- anchors_popup->add_icon_item(get_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_PRESET_CENTER);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_PRESET_CENTER);
anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE);
- anchors_popup->add_icon_item(get_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE);
- anchors_popup->add_icon_item(get_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE);
- anchors_popup->add_icon_item(get_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE);
- anchors_popup->add_icon_item(get_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE);
- anchors_popup->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE);
anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_PRESET_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_PRESET_WIDE);
- anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons"));
+ anchor_mode_button->set_icon(get_theme_icon("Anchor", "EditorIcons"));
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
@@ -4306,10 +4319,20 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
float prev_zoom = zoom;
zoom = p_zoom;
- Point2 ofs = p_position;
- ofs = ofs / prev_zoom - ofs / zoom;
- view_offset.x = Math::round(view_offset.x + ofs.x);
- view_offset.y = Math::round(view_offset.y + ofs.y);
+
+ view_offset += p_position / prev_zoom - p_position / zoom;
+
+ // We want to align in-scene pixels to screen pixels, this prevents blurry rendering
+ // in small details (texts, lines).
+ // This correction adds a jitter movement when zooming, so we correct only when the
+ // zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway)
+ float closest_zoom_factor = Math::round(zoom);
+ if (Math::is_zero_approx(zoom - closest_zoom_factor)) {
+ // make sure scene pixel at view_offset is aligned on a screen pixel
+ Vector2 view_offset_int = view_offset.floor();
+ Vector2 view_offset_frac = view_offset - view_offset_int;
+ view_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor;
+ }
_update_zoom_label();
update_viewport();
@@ -4901,7 +4924,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
bool preview = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE));
preview = !preview;
- VS::get_singleton()->canvas_set_disable_scale(!preview);
+ RS::get_singleton()->canvas_set_disable_scale(!preview);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE), preview);
} break;
@@ -5410,21 +5433,21 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
bottom_split = memnew(VSplitContainer);
add_child(bottom_split);
- bottom_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ bottom_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
palette_split = memnew(HSplitContainer);
bottom_split->add_child(palette_split);
- palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ palette_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
viewport_scrollable = memnew(Control);
palette_split->add_child(viewport_scrollable);
viewport_scrollable->set_mouse_filter(MOUSE_FILTER_PASS);
viewport_scrollable->set_clip_contents(true);
- viewport_scrollable->set_v_size_flags(SIZE_EXPAND_FILL);
- viewport_scrollable->set_h_size_flags(SIZE_EXPAND_FILL);
+ viewport_scrollable->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ viewport_scrollable->set_h_size_flags(Control::SIZE_EXPAND_FILL);
viewport_scrollable->connect("draw", callable_mp(this, &CanvasItemEditor::_update_scrollbars));
- ViewportContainer *scene_tree = memnew(ViewportContainer);
+ SubViewportContainer *scene_tree = memnew(SubViewportContainer);
viewport_scrollable->add_child(scene_tree);
scene_tree->set_stretch(true);
scene_tree->set_anchors_and_margins_preset(Control::PRESET_WIDE);
@@ -5435,7 +5458,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
zoom_hb = memnew(HBoxContainer);
// Bring the zoom percentage closer to the zoom buttons
- zoom_hb->add_constant_override("separation", Math::round(-8 * EDSCALE));
+ zoom_hb->add_theme_constant_override("separation", Math::round(-8 * EDSCALE));
controls_vb->add_child(zoom_hb);
viewport = memnew(CanvasItemEditorViewport(p_editor, this));
@@ -5452,7 +5475,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
info_overlay->set_margin(MARGIN_LEFT, 10);
info_overlay->set_margin(MARGIN_BOTTOM, -15);
info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN);
- info_overlay->add_constant_override("separation", 10);
+ info_overlay->add_theme_constant_override("separation", 10);
viewport_scrollable->add_child(info_overlay);
Theme *info_overlay_theme = memnew(Theme);
@@ -5467,8 +5490,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
warning_child_of_container = memnew(Label);
warning_child_of_container->hide();
warning_child_of_container->set_text(TTR("Warning: Children of a container get their position and size determined only by their parent."));
- warning_child_of_container->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor"));
- warning_child_of_container->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts"));
+ warning_child_of_container->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor"));
+ warning_child_of_container->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
add_control_to_info_overlay(warning_child_of_container);
h_scroll = memnew(HScrollBar);
@@ -5773,7 +5796,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
selection_menu = memnew(PopupMenu);
add_child(selection_menu);
- selection_menu->set_custom_minimum_size(Vector2(100, 0));
+ selection_menu->set_min_size(Vector2(100, 0));
selection_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_selection_result_pressed));
selection_menu->connect("popup_hide", callable_mp(this, &CanvasItemEditor::_selection_menu_hide));
@@ -5790,7 +5813,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
call_deferred("set_state", get_state());
}
-CanvasItemEditor *CanvasItemEditor::singleton = NULL;
+CanvasItemEditor *CanvasItemEditor::singleton = nullptr;
void CanvasItemEditorPlugin::edit(Object *p_object) {
@@ -5808,13 +5831,13 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
canvas_item_editor->show();
canvas_item_editor->set_physics_process(true);
- VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false);
+ RenderingServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false);
} else {
canvas_item_editor->hide();
canvas_item_editor->set_physics_process(false);
- VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), true);
}
}
@@ -5876,9 +5899,9 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
ERR_FAIL_COND(res.is_null());
Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- if (texture != NULL || scene != NULL) {
- if (texture != NULL) {
- Sprite *sprite = memnew(Sprite);
+ if (texture != nullptr || scene != nullptr) {
+ if (texture != nullptr) {
+ Sprite2D *sprite = memnew(Sprite2D);
sprite->set_texture(texture);
sprite->set_modulate(Color(1, 1, 1, 0.7f));
preview_node->add_child(sprite);
@@ -5943,7 +5966,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
+ editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr);
}
if (parent) {
@@ -6039,7 +6062,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
// Without root dropping multiple files is not allowed
if (!target_node && selected_files.size() > 1) {
accept->set_text(TTR("Cannot instantiate multiple nodes without root."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
@@ -6054,7 +6077,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
continue;
}
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- if (scene != NULL && scene.is_valid()) {
+ if (scene != nullptr && scene.is_valid()) {
if (!target_node) {
// Without root node act the same as "Load Inherited Scene"
Error err = EditorNode::get_singleton()->load_scene(path, false, true);
@@ -6069,12 +6092,12 @@ void CanvasItemEditorViewport::_perform_drop_data() {
}
} else {
Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
- if (texture != NULL && texture.is_valid()) {
+ if (texture != nullptr && texture.is_valid()) {
Node *child;
if (default_type == "Light2D")
child = memnew(Light2D);
- else if (default_type == "Particles2D")
- child = memnew(Particles2D);
+ else if (default_type == "GPUParticles2D")
+ child = memnew(GPUParticles2D);
else if (default_type == "Polygon2D")
child = memnew(Polygon2D);
else if (default_type == "TouchScreenButton")
@@ -6084,7 +6107,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
else if (default_type == "NinePatchRect")
child = memnew(NinePatchRect);
else
- child = memnew(Sprite); // default
+ child = memnew(Sprite2D); // default
_create_nodes(target_node, child, path, drop_pos);
}
@@ -6100,7 +6123,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
}
files_str = files_str.substr(0, files_str.length() - 1);
accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
- accept->popup_centered_minsize();
+ accept->popup_centered();
}
}
@@ -6166,7 +6189,7 @@ void CanvasItemEditorViewport::_show_resource_type_selector() {
check->set_pressed(check->get_text() == default_type);
}
selector->set_title(vformat(TTR("Add %s"), default_type));
- selector->popup_centered_minsize();
+ selector->popup_centered();
}
bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
@@ -6181,8 +6204,8 @@ bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
}
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
- bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
+ bool is_shift = InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool is_alt = InputFilter::get_singleton()->is_key_pressed(KEY_ALT);
selected_files.clear();
Dictionary d = p_data;
@@ -6199,7 +6222,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
list.push_back(root_node);
} else {
drop_pos = p_point;
- target_node = NULL;
+ target_node = nullptr;
}
}
@@ -6223,7 +6246,7 @@ void CanvasItemEditorViewport::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit));
- label->add_color_override("font_color", get_color("warning_color", "Editor"));
+ label->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"));
} break;
case NOTIFICATION_EXIT_TREE: {
disconnect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit));
@@ -6237,18 +6260,18 @@ void CanvasItemEditorViewport::_bind_methods() {
}
CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasItemEditor *p_canvas_item_editor) {
- default_type = "Sprite";
+ default_type = "Sprite2D";
// Node2D
- types.push_back("Sprite");
+ types.push_back("Sprite2D");
types.push_back("Light2D");
- types.push_back("Particles2D");
+ types.push_back("GPUParticles2D");
types.push_back("Polygon2D");
types.push_back("TouchScreenButton");
// Control
types.push_back("TextureRect");
types.push_back("NinePatchRect");
- target_node = NULL;
+ target_node = nullptr;
editor = p_node;
editor_data = editor->get_scene_tree_dock()->get_editor_data();
canvas_item_editor = p_canvas_item_editor;
@@ -6261,12 +6284,12 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
editor->get_gui_base()->add_child(selector);
selector->set_title(TTR("Change Default Type"));
selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
- selector->connect("popup_hide", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
+ selector->connect("cancelled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
VBoxContainer *vbc = memnew(VBoxContainer);
selector->add_child(vbc);
- vbc->set_h_size_flags(SIZE_EXPAND_FILL);
- vbc->set_v_size_flags(SIZE_EXPAND_FILL);
+ vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vbc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbc->set_custom_minimum_size(Size2(200, 260) * EDSCALE);
btn_group = memnew(VBoxContainer);
@@ -6283,21 +6306,21 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
}
label = memnew(Label);
- label->add_color_override("font_color_shadow", Color(0, 0, 0, 1));
- label->add_constant_override("shadow_as_outline", 1 * EDSCALE);
+ label->add_theme_color_override("font_color_shadow", Color(0, 0, 0, 1));
+ label->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
label->hide();
canvas_item_editor->get_controls_container()->add_child(label);
label_desc = memnew(Label);
label_desc->set_text(TTR("Drag & drop + Shift : Add node as sibling\nDrag & drop + Alt : Change node type"));
- label_desc->add_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1));
- label_desc->add_color_override("font_color_shadow", Color(0.2f, 0.2f, 0.2f, 1));
- label_desc->add_constant_override("shadow_as_outline", 1 * EDSCALE);
- label_desc->add_constant_override("line_spacing", 0);
+ label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1));
+ label_desc->add_theme_color_override("font_color_shadow", Color(0.2f, 0.2f, 0.2f, 1));
+ label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
+ label_desc->add_theme_constant_override("line_spacing", 0);
label_desc->hide();
canvas_item_editor->get_controls_container()->add_child(label_desc);
- VS::get_singleton()->canvas_set_disable_scale(true);
+ RS::get_singleton()->canvas_set_disable_scale(true);
}
CanvasItemEditorViewport::~CanvasItemEditorViewport() {
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 3c4cacf5c8..9f1a92f563 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -33,12 +33,12 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/2d/canvas_item.h"
#include "scene/gui/box_container.h"
#include "scene/gui/check_box.h"
#include "scene/gui/label.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/spin_box.h"
+#include "scene/main/canvas_item.h"
class CanvasItemEditorViewport;
@@ -613,7 +613,7 @@ public:
SNAP_DEFAULT = SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL,
};
- Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = NULL, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>());
+ Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>());
float snap_angle(float p_target, float p_start = 0) const;
Transform2D get_canvas_transform() const { return transform; }
@@ -687,7 +687,7 @@ class CanvasItemEditorViewport : public Control {
CanvasItemEditor *canvas_item_editor;
Node2D *preview_node;
AcceptDialog *accept;
- WindowDialog *selector;
+ AcceptDialog *selector;
Label *selector_label;
Label *label;
Label *label_desc;
diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
index 3d32c0b698..87e9987aa1 100644
--- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
@@ -42,7 +42,7 @@ void CollisionPolygon2DEditor::_set_node(Node *p_polygon) {
CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) :
AbstractPolygon2DEditor(p_editor) {
- node = NULL;
+ node = nullptr;
}
CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) :
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..26adc5156b
--- /dev/null
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -0,0 +1,608 @@
+/*************************************************************************/
+/* collision_polygon_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_polygon_3d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "core/input/input_filter.h"
+#include "core/os/file_access.h"
+#include "core/os/keyboard.h"
+#include "editor/editor_settings.h"
+#include "node_3d_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
+
+void CollisionPolygon3DEditor::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_READY: {
+
+ button_create->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ button_edit->set_icon(get_theme_icon("MovePoint", "EditorIcons"));
+ button_edit->set_pressed(true);
+ get_tree()->connect("node_removed", callable_mp(this, &CollisionPolygon3DEditor::_node_removed));
+
+ } break;
+ case NOTIFICATION_PROCESS: {
+ if (!node) {
+ return;
+ }
+
+ if (_get_depth() != prev_depth) {
+ _polygon_draw();
+ prev_depth = _get_depth();
+ }
+
+ } break;
+ }
+}
+void CollisionPolygon3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ if (imgeom->get_parent() == p_node)
+ p_node->remove_child(imgeom);
+ hide();
+ set_process(false);
+ }
+}
+
+void CollisionPolygon3DEditor::_menu_option(int p_option) {
+
+ switch (p_option) {
+
+ case MODE_CREATE: {
+
+ mode = MODE_CREATE;
+ button_create->set_pressed(true);
+ button_edit->set_pressed(false);
+ } break;
+ case MODE_EDIT: {
+
+ mode = MODE_EDIT;
+ button_create->set_pressed(false);
+ button_edit->set_pressed(true);
+ } break;
+ }
+}
+
+void CollisionPolygon3DEditor::_wip_close() {
+
+ undo_redo->create_action(TTR("Create Polygon3D"));
+ undo_redo->add_undo_method(node, "set_polygon", node->call("get_polygon"));
+ undo_redo->add_do_method(node, "set_polygon", wip);
+ undo_redo->add_do_method(this, "_polygon_draw");
+ undo_redo->add_undo_method(this, "_polygon_draw");
+ wip.clear();
+ wip_active = false;
+ mode = MODE_EDIT;
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ edited_point = -1;
+ undo_redo->commit_action();
+}
+
+bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+
+ if (!node)
+ return false;
+
+ Transform gt = node->get_global_transform();
+ Transform gi = gt.affine_inverse();
+ float depth = _get_depth() * 0.5;
+ Vector3 n = gt.basis.get_axis(2).normalized();
+ Plane p(gt.origin + n * depth, n);
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+
+ Vector2 gpoint = mb->get_position();
+ Vector3 ray_from = p_camera->project_ray_origin(gpoint);
+ Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+
+ Vector3 spoint;
+
+ if (!p.intersects_ray(ray_from, ray_dir, &spoint))
+ return false;
+
+ spoint = gi.xform(spoint);
+
+ Vector2 cpoint(spoint.x, spoint.y);
+
+ //DO NOT snap here, it's confusing in 3D for adding points.
+ //Let the snap happen when the point is being moved, instead.
+ //cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint);
+
+ Vector<Vector2> poly = node->call("get_polygon");
+
+ //first check if a point is to be added (segment split)
+ real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
+
+ switch (mode) {
+
+ case MODE_CREATE: {
+
+ if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+
+ if (!wip_active) {
+
+ wip.clear();
+ wip.push_back(cpoint);
+ wip_active = true;
+ edited_point_pos = cpoint;
+ snap_ignore = false;
+ _polygon_draw();
+ edited_point = 1;
+ return true;
+ } else {
+
+ if (wip.size() > 1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x, wip[0].y, depth))).distance_to(gpoint) < grab_threshold) {
+ //wip closed
+ _wip_close();
+
+ return true;
+ } else {
+
+ wip.push_back(cpoint);
+ edited_point = wip.size();
+ snap_ignore = false;
+ _polygon_draw();
+ return true;
+ }
+ }
+ } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ _wip_close();
+ }
+
+ } break;
+
+ case MODE_EDIT: {
+
+ if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed()) {
+
+ if (mb->get_control()) {
+
+ if (poly.size() < 3) {
+
+ undo_redo->create_action(TTR("Edit Poly"));
+ undo_redo->add_undo_method(node, "set_polygon", poly);
+ poly.push_back(cpoint);
+ undo_redo->add_do_method(node, "set_polygon", poly);
+ undo_redo->add_do_method(this, "_polygon_draw");
+ undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->commit_action();
+ return true;
+ }
+
+ //search edges
+ int closest_idx = -1;
+ Vector2 closest_pos;
+ real_t closest_dist = 1e10;
+ for (int i = 0; i < poly.size(); i++) {
+
+ Vector2 points[2] = {
+ p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth))),
+ p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, poly[(i + 1) % poly.size()].y, depth)))
+ };
+
+ Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, points);
+ if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2)
+ continue; //not valid to reuse point
+
+ real_t d = cp.distance_to(gpoint);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest_pos = cp;
+ closest_idx = i;
+ }
+ }
+
+ if (closest_idx >= 0) {
+
+ pre_move_edit = poly;
+ poly.insert(closest_idx + 1, cpoint);
+ edited_point = closest_idx + 1;
+ edited_point_pos = cpoint;
+ node->call("set_polygon", poly);
+ _polygon_draw();
+ snap_ignore = true;
+
+ return true;
+ }
+ } else {
+
+ //look for points to move
+
+ int closest_idx = -1;
+ Vector2 closest_pos;
+ real_t closest_dist = 1e10;
+ for (int i = 0; i < poly.size(); i++) {
+
+ Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth)));
+
+ real_t d = cp.distance_to(gpoint);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest_pos = cp;
+ closest_idx = i;
+ }
+ }
+
+ if (closest_idx >= 0) {
+
+ pre_move_edit = poly;
+ edited_point = closest_idx;
+ edited_point_pos = poly[closest_idx];
+ _polygon_draw();
+ snap_ignore = false;
+ return true;
+ }
+ }
+ } else {
+
+ snap_ignore = false;
+
+ if (edited_point != -1) {
+
+ //apply
+
+ ERR_FAIL_INDEX_V(edited_point, poly.size(), false);
+ poly.write[edited_point] = edited_point_pos;
+ undo_redo->create_action(TTR("Edit Poly"));
+ undo_redo->add_do_method(node, "set_polygon", poly);
+ undo_redo->add_undo_method(node, "set_polygon", pre_move_edit);
+ undo_redo->add_do_method(this, "_polygon_draw");
+ undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->commit_action();
+
+ edited_point = -1;
+ return true;
+ }
+ }
+ }
+ if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
+
+ int closest_idx = -1;
+ Vector2 closest_pos;
+ real_t closest_dist = 1e10;
+ for (int i = 0; i < poly.size(); i++) {
+
+ Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth)));
+
+ real_t d = cp.distance_to(gpoint);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest_pos = cp;
+ closest_idx = i;
+ }
+ }
+
+ if (closest_idx >= 0) {
+
+ undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
+ undo_redo->add_undo_method(node, "set_polygon", poly);
+ poly.remove(closest_idx);
+ undo_redo->add_do_method(node, "set_polygon", poly);
+ undo_redo->add_do_method(this, "_polygon_draw");
+ undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->commit_action();
+ return true;
+ }
+ }
+
+ } break;
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+ if (edited_point != -1 && (wip_active || mm->get_button_mask() & BUTTON_MASK_LEFT)) {
+
+ Vector2 gpoint = mm->get_position();
+
+ Vector3 ray_from = p_camera->project_ray_origin(gpoint);
+ Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+
+ Vector3 spoint;
+
+ if (!p.intersects_ray(ray_from, ray_dir, &spoint))
+ return false;
+
+ spoint = gi.xform(spoint);
+
+ Vector2 cpoint(spoint.x, spoint.y);
+
+ if (snap_ignore && !InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ snap_ignore = false;
+ }
+
+ if (!snap_ignore && Node3DEditor::get_singleton()->is_snap_enabled()) {
+ cpoint = cpoint.snapped(Vector2(
+ Node3DEditor::get_singleton()->get_translate_snap(),
+ Node3DEditor::get_singleton()->get_translate_snap()));
+ }
+ edited_point_pos = cpoint;
+
+ _polygon_draw();
+ }
+ }
+
+ return false;
+}
+
+float CollisionPolygon3DEditor::_get_depth() {
+
+ if (bool(node->call("_has_editable_3d_polygon_no_depth")))
+ return 0;
+
+ return float(node->call("get_depth"));
+}
+
+void CollisionPolygon3DEditor::_polygon_draw() {
+
+ if (!node)
+ return;
+
+ Vector<Vector2> poly;
+
+ if (wip_active)
+ poly = wip;
+ else
+ poly = node->call("get_polygon");
+
+ float depth = _get_depth() * 0.5;
+
+ imgeom->clear();
+ imgeom->set_material_override(line_material);
+ imgeom->begin(Mesh::PRIMITIVE_LINES, Ref<Texture2D>());
+
+ Rect2 rect;
+
+ for (int i = 0; i < poly.size(); i++) {
+
+ Vector2 p, p2;
+ p = i == edited_point ? edited_point_pos : poly[i];
+ if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point))
+ p2 = edited_point_pos;
+ else
+ p2 = poly[(i + 1) % poly.size()];
+
+ if (i == 0)
+ rect.position = p;
+ else
+ rect.expand_to(p);
+
+ Vector3 point = Vector3(p.x, p.y, depth);
+ Vector3 next_point = Vector3(p2.x, p2.y, depth);
+
+ imgeom->set_color(Color(1, 0.3, 0.1, 0.8));
+ imgeom->add_vertex(point);
+ imgeom->set_color(Color(1, 0.3, 0.1, 0.8));
+ imgeom->add_vertex(next_point);
+
+ //Color col=Color(1,0.3,0.1,0.8);
+ //vpc->draw_line(point,next_point,col,2);
+ //vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ }
+
+ rect = rect.grow(1);
+
+ AABB r;
+ r.position.x = rect.position.x;
+ r.position.y = rect.position.y;
+ r.position.z = depth;
+ r.size.x = rect.size.x;
+ r.size.y = rect.size.y;
+ r.size.z = 0;
+
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position);
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(0.3, 0, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position);
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(0.0, 0.3, 0));
+
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0) - Vector3(0.3, 0, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0) + Vector3(0, 0.3, 0));
+
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0) - Vector3(0, 0.3, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0) + Vector3(0.3, 0, 0));
+
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + r.size);
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + r.size - Vector3(0.3, 0, 0));
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + r.size);
+ imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
+ imgeom->add_vertex(r.position + r.size - Vector3(0.0, 0.3, 0));
+
+ imgeom->end();
+
+ m->clear_surfaces();
+
+ if (poly.size() == 0)
+ return;
+
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ Vector<Vector3> va;
+ {
+
+ va.resize(poly.size());
+ Vector3 *w = va.ptrw();
+ for (int i = 0; i < poly.size(); i++) {
+
+ Vector2 p, p2;
+ p = i == edited_point ? edited_point_pos : poly[i];
+
+ Vector3 point = Vector3(p.x, p.y, depth);
+ w[i] = point;
+ }
+ }
+ a[Mesh::ARRAY_VERTEX] = va;
+ m->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
+ m->surface_set_material(0, handle_material);
+}
+
+void CollisionPolygon3DEditor::edit(Node *p_collision_polygon) {
+
+ if (p_collision_polygon) {
+
+ node = Object::cast_to<Node3D>(p_collision_polygon);
+ //Enable the pencil tool if the polygon is empty
+ if (Vector<Vector2>(node->call("get_polygon")).size() == 0) {
+ _menu_option(MODE_CREATE);
+ }
+ wip.clear();
+ wip_active = false;
+ edited_point = -1;
+ p_collision_polygon->add_child(imgeom);
+ _polygon_draw();
+ set_process(true);
+ prev_depth = -1;
+
+ } else {
+ node = nullptr;
+
+ if (imgeom->get_parent())
+ imgeom->get_parent()->remove_child(imgeom);
+
+ set_process(false);
+ }
+}
+
+void CollisionPolygon3DEditor::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_polygon_draw"), &CollisionPolygon3DEditor::_polygon_draw);
+}
+
+CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
+
+ node = nullptr;
+ editor = p_editor;
+ undo_redo = EditorNode::get_undo_redo();
+
+ add_child(memnew(VSeparator));
+ button_create = memnew(ToolButton);
+ add_child(button_create);
+ button_create->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_CREATE));
+ button_create->set_toggle_mode(true);
+
+ button_edit = memnew(ToolButton);
+ add_child(button_edit);
+ button_edit->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+
+ mode = MODE_EDIT;
+ wip_active = false;
+ imgeom = memnew(ImmediateGeometry3D);
+ imgeom->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
+
+ line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ line_material->set_albedo(Color(1, 1, 1));
+
+ handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
+ handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ Ref<Texture2D> handle = editor->get_gui_base()->get_theme_icon("Editor3DHandle", "EditorIcons");
+ handle_material->set_point_size(handle->get_width());
+ handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
+
+ pointsm = memnew(MeshInstance3D);
+ imgeom->add_child(pointsm);
+ m.instance();
+ pointsm->set_mesh(m);
+ pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
+
+ snap_ignore = false;
+}
+
+CollisionPolygon3DEditor::~CollisionPolygon3DEditor() {
+
+ memdelete(imgeom);
+}
+
+void Polygon3DEditorPlugin::edit(Object *p_object) {
+
+ collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
+}
+
+bool Polygon3DEditorPlugin::handles(Object *p_object) const {
+
+ return Object::cast_to<Node3D>(p_object) && bool(p_object->call("_is_editable_3d_polygon"));
+}
+
+void Polygon3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ collision_polygon_editor->show();
+ } else {
+
+ collision_polygon_editor->hide();
+ collision_polygon_editor->edit(nullptr);
+ }
+}
+
+Polygon3DEditorPlugin::Polygon3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ collision_polygon_editor = memnew(CollisionPolygon3DEditor(p_node));
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+
+ collision_polygon_editor->hide();
+}
+
+Polygon3DEditorPlugin::~Polygon3DEditorPlugin() {
+}
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.h b/editor/plugins/collision_polygon_3d_editor_plugin.h
new file mode 100644
index 0000000000..9751b1f79e
--- /dev/null
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.h
@@ -0,0 +1,119 @@
+/*************************************************************************/
+/* collision_polygon_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_POLYGON_EDITOR_PLUGIN_H
+#define COLLISION_POLYGON_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/collision_polygon_3d.h"
+#include "scene/3d/immediate_geometry_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/tool_button.h"
+
+class CanvasItemEditor;
+
+class CollisionPolygon3DEditor : public HBoxContainer {
+
+ GDCLASS(CollisionPolygon3DEditor, HBoxContainer);
+
+ UndoRedo *undo_redo;
+ enum Mode {
+
+ MODE_CREATE,
+ MODE_EDIT,
+
+ };
+
+ Mode mode;
+
+ ToolButton *button_create;
+ ToolButton *button_edit;
+
+ Ref<StandardMaterial3D> line_material;
+ Ref<StandardMaterial3D> handle_material;
+
+ EditorNode *editor;
+ Panel *panel;
+ Node3D *node;
+ ImmediateGeometry3D *imgeom;
+ MeshInstance3D *pointsm;
+ Ref<ArrayMesh> m;
+
+ MenuButton *options;
+
+ int edited_point;
+ Vector2 edited_point_pos;
+ Vector<Vector2> pre_move_edit;
+ Vector<Vector2> wip;
+ bool wip_active;
+ bool snap_ignore;
+
+ float prev_depth;
+
+ void _wip_close();
+ void _polygon_draw();
+ void _menu_option(int p_option);
+
+ float _get_depth();
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
+ void edit(Node *p_collision_polygon);
+ CollisionPolygon3DEditor(EditorNode *p_editor);
+ ~CollisionPolygon3DEditor();
+};
+
+class Polygon3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(Polygon3DEditorPlugin, EditorPlugin);
+
+ CollisionPolygon3DEditor *collision_polygon_editor;
+ EditorNode *editor;
+
+public:
+ virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
+
+ virtual String get_name() const { return "Polygon3DEditor"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ Polygon3DEditorPlugin(EditorNode *p_node);
+ ~Polygon3DEditorPlugin();
+};
+
+#endif // COLLISION_POLYGON_EDITOR_PLUGIN_H
diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_editor_plugin.cpp
deleted file mode 100644
index 1562286073..0000000000
--- a/editor/plugins/collision_polygon_editor_plugin.cpp
+++ /dev/null
@@ -1,608 +0,0 @@
-/*************************************************************************/
-/* collision_polygon_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_polygon_editor_plugin.h"
-
-#include "canvas_item_editor_plugin.h"
-#include "core/os/file_access.h"
-#include "core/os/input.h"
-#include "core/os/keyboard.h"
-#include "editor/editor_settings.h"
-#include "scene/3d/camera.h"
-#include "spatial_editor_plugin.h"
-
-void Polygon3DEditor::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_READY: {
-
- button_create->set_icon(get_icon("Edit", "EditorIcons"));
- button_edit->set_icon(get_icon("MovePoint", "EditorIcons"));
- button_edit->set_pressed(true);
- get_tree()->connect("node_removed", callable_mp(this, &Polygon3DEditor::_node_removed));
-
- } break;
- case NOTIFICATION_PROCESS: {
- if (!node) {
- return;
- }
-
- if (_get_depth() != prev_depth) {
- _polygon_draw();
- prev_depth = _get_depth();
- }
-
- } break;
- }
-}
-void Polygon3DEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- if (imgeom->get_parent() == p_node)
- p_node->remove_child(imgeom);
- hide();
- set_process(false);
- }
-}
-
-void Polygon3DEditor::_menu_option(int p_option) {
-
- switch (p_option) {
-
- case MODE_CREATE: {
-
- mode = MODE_CREATE;
- button_create->set_pressed(true);
- button_edit->set_pressed(false);
- } break;
- case MODE_EDIT: {
-
- mode = MODE_EDIT;
- button_create->set_pressed(false);
- button_edit->set_pressed(true);
- } break;
- }
-}
-
-void Polygon3DEditor::_wip_close() {
-
- undo_redo->create_action(TTR("Create Polygon3D"));
- undo_redo->add_undo_method(node, "set_polygon", node->call("get_polygon"));
- undo_redo->add_do_method(node, "set_polygon", wip);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
- wip.clear();
- wip_active = false;
- mode = MODE_EDIT;
- button_edit->set_pressed(true);
- button_create->set_pressed(false);
- edited_point = -1;
- undo_redo->commit_action();
-}
-
-bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
-
- if (!node)
- return false;
-
- Transform gt = node->get_global_transform();
- Transform gi = gt.affine_inverse();
- float depth = _get_depth() * 0.5;
- Vector3 n = gt.basis.get_axis(2).normalized();
- Plane p(gt.origin + n * depth, n);
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
-
- Vector2 gpoint = mb->get_position();
- Vector3 ray_from = p_camera->project_ray_origin(gpoint);
- Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
-
- Vector3 spoint;
-
- if (!p.intersects_ray(ray_from, ray_dir, &spoint))
- return false;
-
- spoint = gi.xform(spoint);
-
- Vector2 cpoint(spoint.x, spoint.y);
-
- //DO NOT snap here, it's confusing in 3D for adding points.
- //Let the snap happen when the point is being moved, instead.
- //cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint);
-
- Vector<Vector2> poly = node->call("get_polygon");
-
- //first check if a point is to be added (segment split)
- real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
-
- switch (mode) {
-
- case MODE_CREATE: {
-
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
-
- if (!wip_active) {
-
- wip.clear();
- wip.push_back(cpoint);
- wip_active = true;
- edited_point_pos = cpoint;
- snap_ignore = false;
- _polygon_draw();
- edited_point = 1;
- return true;
- } else {
-
- if (wip.size() > 1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x, wip[0].y, depth))).distance_to(gpoint) < grab_threshold) {
- //wip closed
- _wip_close();
-
- return true;
- } else {
-
- wip.push_back(cpoint);
- edited_point = wip.size();
- snap_ignore = false;
- _polygon_draw();
- return true;
- }
- }
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
- _wip_close();
- }
-
- } break;
-
- case MODE_EDIT: {
-
- if (mb->get_button_index() == BUTTON_LEFT) {
- if (mb->is_pressed()) {
-
- if (mb->get_control()) {
-
- if (poly.size() < 3) {
-
- undo_redo->create_action(TTR("Edit Poly"));
- undo_redo->add_undo_method(node, "set_polygon", poly);
- poly.push_back(cpoint);
- undo_redo->add_do_method(node, "set_polygon", poly);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
- undo_redo->commit_action();
- return true;
- }
-
- //search edges
- int closest_idx = -1;
- Vector2 closest_pos;
- real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
-
- Vector2 points[2] = {
- p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth))),
- p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, poly[(i + 1) % poly.size()].y, depth)))
- };
-
- Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, points);
- if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2)
- continue; //not valid to reuse point
-
- real_t d = cp.distance_to(gpoint);
- if (d < closest_dist && d < grab_threshold) {
- closest_dist = d;
- closest_pos = cp;
- closest_idx = i;
- }
- }
-
- if (closest_idx >= 0) {
-
- pre_move_edit = poly;
- poly.insert(closest_idx + 1, cpoint);
- edited_point = closest_idx + 1;
- edited_point_pos = cpoint;
- node->call("set_polygon", poly);
- _polygon_draw();
- snap_ignore = true;
-
- return true;
- }
- } else {
-
- //look for points to move
-
- int closest_idx = -1;
- Vector2 closest_pos;
- real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
-
- Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth)));
-
- real_t d = cp.distance_to(gpoint);
- if (d < closest_dist && d < grab_threshold) {
- closest_dist = d;
- closest_pos = cp;
- closest_idx = i;
- }
- }
-
- if (closest_idx >= 0) {
-
- pre_move_edit = poly;
- edited_point = closest_idx;
- edited_point_pos = poly[closest_idx];
- _polygon_draw();
- snap_ignore = false;
- return true;
- }
- }
- } else {
-
- snap_ignore = false;
-
- if (edited_point != -1) {
-
- //apply
-
- ERR_FAIL_INDEX_V(edited_point, poly.size(), false);
- poly.write[edited_point] = edited_point_pos;
- undo_redo->create_action(TTR("Edit Poly"));
- undo_redo->add_do_method(node, "set_polygon", poly);
- undo_redo->add_undo_method(node, "set_polygon", pre_move_edit);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
- undo_redo->commit_action();
-
- edited_point = -1;
- return true;
- }
- }
- }
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
-
- int closest_idx = -1;
- Vector2 closest_pos;
- real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
-
- Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth)));
-
- real_t d = cp.distance_to(gpoint);
- if (d < closest_dist && d < grab_threshold) {
- closest_dist = d;
- closest_pos = cp;
- closest_idx = i;
- }
- }
-
- if (closest_idx >= 0) {
-
- undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
- undo_redo->add_undo_method(node, "set_polygon", poly);
- poly.remove(closest_idx);
- undo_redo->add_do_method(node, "set_polygon", poly);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
- undo_redo->commit_action();
- return true;
- }
- }
-
- } break;
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
- if (edited_point != -1 && (wip_active || mm->get_button_mask() & BUTTON_MASK_LEFT)) {
-
- Vector2 gpoint = mm->get_position();
-
- Vector3 ray_from = p_camera->project_ray_origin(gpoint);
- Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
-
- Vector3 spoint;
-
- if (!p.intersects_ray(ray_from, ray_dir, &spoint))
- return false;
-
- spoint = gi.xform(spoint);
-
- Vector2 cpoint(spoint.x, spoint.y);
-
- if (snap_ignore && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
- snap_ignore = false;
- }
-
- if (!snap_ignore && SpatialEditor::get_singleton()->is_snap_enabled()) {
- cpoint = cpoint.snapped(Vector2(
- SpatialEditor::get_singleton()->get_translate_snap(),
- SpatialEditor::get_singleton()->get_translate_snap()));
- }
- edited_point_pos = cpoint;
-
- _polygon_draw();
- }
- }
-
- return false;
-}
-
-float Polygon3DEditor::_get_depth() {
-
- if (bool(node->call("_has_editable_3d_polygon_no_depth")))
- return 0;
-
- return float(node->call("get_depth"));
-}
-
-void Polygon3DEditor::_polygon_draw() {
-
- if (!node)
- return;
-
- Vector<Vector2> poly;
-
- if (wip_active)
- poly = wip;
- else
- poly = node->call("get_polygon");
-
- float depth = _get_depth() * 0.5;
-
- imgeom->clear();
- imgeom->set_material_override(line_material);
- imgeom->begin(Mesh::PRIMITIVE_LINES, Ref<Texture2D>());
-
- Rect2 rect;
-
- for (int i = 0; i < poly.size(); i++) {
-
- Vector2 p, p2;
- p = i == edited_point ? edited_point_pos : poly[i];
- if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point))
- p2 = edited_point_pos;
- else
- p2 = poly[(i + 1) % poly.size()];
-
- if (i == 0)
- rect.position = p;
- else
- rect.expand_to(p);
-
- Vector3 point = Vector3(p.x, p.y, depth);
- Vector3 next_point = Vector3(p2.x, p2.y, depth);
-
- imgeom->set_color(Color(1, 0.3, 0.1, 0.8));
- imgeom->add_vertex(point);
- imgeom->set_color(Color(1, 0.3, 0.1, 0.8));
- imgeom->add_vertex(next_point);
-
- //Color col=Color(1,0.3,0.1,0.8);
- //vpc->draw_line(point,next_point,col,2);
- //vpc->draw_texture(handle,point-handle->get_size()*0.5);
- }
-
- rect = rect.grow(1);
-
- AABB r;
- r.position.x = rect.position.x;
- r.position.y = rect.position.y;
- r.position.z = depth;
- r.size.x = rect.size.x;
- r.size.y = rect.size.y;
- r.size.z = 0;
-
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position);
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(0.3, 0, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position);
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(0.0, 0.3, 0));
-
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0) - Vector3(0.3, 0, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0) + Vector3(0, 0.3, 0));
-
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0) - Vector3(0, 0.3, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0) + Vector3(0.3, 0, 0));
-
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + r.size);
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + r.size - Vector3(0.3, 0, 0));
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + r.size);
- imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2));
- imgeom->add_vertex(r.position + r.size - Vector3(0.0, 0.3, 0));
-
- imgeom->end();
-
- m->clear_surfaces();
-
- if (poly.size() == 0)
- return;
-
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- Vector<Vector3> va;
- {
-
- va.resize(poly.size());
- Vector3 *w = va.ptrw();
- for (int i = 0; i < poly.size(); i++) {
-
- Vector2 p, p2;
- p = i == edited_point ? edited_point_pos : poly[i];
-
- Vector3 point = Vector3(p.x, p.y, depth);
- w[i] = point;
- }
- }
- a[Mesh::ARRAY_VERTEX] = va;
- m->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
- m->surface_set_material(0, handle_material);
-}
-
-void Polygon3DEditor::edit(Node *p_collision_polygon) {
-
- if (p_collision_polygon) {
-
- node = Object::cast_to<Spatial>(p_collision_polygon);
- //Enable the pencil tool if the polygon is empty
- if (Vector<Vector2>(node->call("get_polygon")).size() == 0) {
- _menu_option(MODE_CREATE);
- }
- wip.clear();
- wip_active = false;
- edited_point = -1;
- p_collision_polygon->add_child(imgeom);
- _polygon_draw();
- set_process(true);
- prev_depth = -1;
-
- } else {
- node = NULL;
-
- if (imgeom->get_parent())
- imgeom->get_parent()->remove_child(imgeom);
-
- set_process(false);
- }
-}
-
-void Polygon3DEditor::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_polygon_draw"), &Polygon3DEditor::_polygon_draw);
-}
-
-Polygon3DEditor::Polygon3DEditor(EditorNode *p_editor) {
-
- node = NULL;
- editor = p_editor;
- undo_redo = EditorNode::get_undo_redo();
-
- add_child(memnew(VSeparator));
- button_create = memnew(ToolButton);
- add_child(button_create);
- button_create->connect("pressed", callable_mp(this, &Polygon3DEditor::_menu_option), varray(MODE_CREATE));
- button_create->set_toggle_mode(true);
-
- button_edit = memnew(ToolButton);
- add_child(button_edit);
- button_edit->connect("pressed", callable_mp(this, &Polygon3DEditor::_menu_option), varray(MODE_EDIT));
- button_edit->set_toggle_mode(true);
-
- mode = MODE_EDIT;
- wip_active = false;
- imgeom = memnew(ImmediateGeometry);
- imgeom->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
-
- line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_albedo(Color(1, 1, 1));
-
- handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
- handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- Ref<Texture2D> handle = editor->get_gui_base()->get_icon("Editor3DHandle", "EditorIcons");
- handle_material->set_point_size(handle->get_width());
- handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
-
- pointsm = memnew(MeshInstance);
- imgeom->add_child(pointsm);
- m.instance();
- pointsm->set_mesh(m);
- pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
-
- snap_ignore = false;
-}
-
-Polygon3DEditor::~Polygon3DEditor() {
-
- memdelete(imgeom);
-}
-
-void Polygon3DEditorPlugin::edit(Object *p_object) {
-
- collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
-}
-
-bool Polygon3DEditorPlugin::handles(Object *p_object) const {
-
- return Object::cast_to<Spatial>(p_object) && bool(p_object->call("_is_editable_3d_polygon"));
-}
-
-void Polygon3DEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- collision_polygon_editor->show();
- } else {
-
- collision_polygon_editor->hide();
- collision_polygon_editor->edit(NULL);
- }
-}
-
-Polygon3DEditorPlugin::Polygon3DEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- collision_polygon_editor = memnew(Polygon3DEditor(p_node));
- SpatialEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
-
- collision_polygon_editor->hide();
-}
-
-Polygon3DEditorPlugin::~Polygon3DEditorPlugin() {
-}
diff --git a/editor/plugins/collision_polygon_editor_plugin.h b/editor/plugins/collision_polygon_editor_plugin.h
deleted file mode 100644
index 3b6c25ac17..0000000000
--- a/editor/plugins/collision_polygon_editor_plugin.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*************************************************************************/
-/* collision_polygon_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_POLYGON_EDITOR_PLUGIN_H
-#define COLLISION_POLYGON_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/3d/collision_polygon.h"
-#include "scene/3d/immediate_geometry.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/gui/tool_button.h"
-
-class CanvasItemEditor;
-
-class Polygon3DEditor : public HBoxContainer {
-
- GDCLASS(Polygon3DEditor, HBoxContainer);
-
- UndoRedo *undo_redo;
- enum Mode {
-
- MODE_CREATE,
- MODE_EDIT,
-
- };
-
- Mode mode;
-
- ToolButton *button_create;
- ToolButton *button_edit;
-
- Ref<StandardMaterial3D> line_material;
- Ref<StandardMaterial3D> handle_material;
-
- EditorNode *editor;
- Panel *panel;
- Spatial *node;
- ImmediateGeometry *imgeom;
- MeshInstance *pointsm;
- Ref<ArrayMesh> m;
-
- MenuButton *options;
-
- int edited_point;
- Vector2 edited_point_pos;
- Vector<Vector2> pre_move_edit;
- Vector<Vector2> wip;
- bool wip_active;
- bool snap_ignore;
-
- float prev_depth;
-
- void _wip_close();
- void _polygon_draw();
- void _menu_option(int p_option);
-
- float _get_depth();
-
-protected:
- void _notification(int p_what);
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
-public:
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
- void edit(Node *p_collision_polygon);
- Polygon3DEditor(EditorNode *p_editor);
- ~Polygon3DEditor();
-};
-
-class Polygon3DEditorPlugin : public EditorPlugin {
-
- GDCLASS(Polygon3DEditorPlugin, EditorPlugin);
-
- Polygon3DEditor *collision_polygon_editor;
- EditorNode *editor;
-
-public:
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
-
- virtual String get_name() const { return "Polygon3DEditor"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- Polygon3DEditorPlugin(EditorNode *p_node);
- ~Polygon3DEditorPlugin();
-};
-
-#endif // COLLISION_POLYGON_EDITOR_PLUGIN_H
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 01b4a61a85..594dd0d0cb 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -39,6 +39,13 @@
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/segment_shape_2d.h"
+void CollisionShape2DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ }
+}
+
Variant CollisionShape2DEditor::get_handle_value(int idx) const {
switch (shape_type) {
@@ -435,7 +442,7 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- Ref<Texture2D> h = get_icon("EditorHandle", "EditorIcons");
+ Ref<Texture2D> h = get_theme_icon("EditorHandle", "EditorIcons");
Vector2 size = h->get_size() * 0.5;
handles.clear();
@@ -525,6 +532,20 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
}
}
+void CollisionShape2DEditor::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+ get_tree()->connect("node_removed", callable_mp(this, &CollisionShape2DEditor::_node_removed));
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &CollisionShape2DEditor::_node_removed));
+ } break;
+ }
+}
+
void CollisionShape2DEditor::edit(Node *p_node) {
if (!canvas_item_editor) {
@@ -540,7 +561,7 @@ void CollisionShape2DEditor::edit(Node *p_node) {
edit_handle = -1;
shape_type = -1;
- node = NULL;
+ node = nullptr;
}
canvas_item_editor->update_viewport();
@@ -553,8 +574,8 @@ void CollisionShape2DEditor::_bind_methods() {
CollisionShape2DEditor::CollisionShape2DEditor(EditorNode *p_editor) {
- node = NULL;
- canvas_item_editor = NULL;
+ node = nullptr;
+ canvas_item_editor = nullptr;
editor = p_editor;
undo_redo = p_editor->get_undo_redo();
@@ -576,7 +597,7 @@ bool CollisionShape2DEditorPlugin::handles(Object *p_obj) const {
void CollisionShape2DEditorPlugin::make_visible(bool visible) {
if (!visible) {
- edit(NULL);
+ edit(nullptr);
}
}
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index 025420a886..6bb621c476 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -71,6 +71,8 @@ class CollisionShape2DEditor : public Control {
void _get_current_shape_type();
protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
static void _bind_methods();
public:
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index 119528dfc8..ef4d7d7646 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -60,7 +60,7 @@ void CPUParticles2DEditorPlugin::make_visible(bool p_visible) {
void CPUParticles2DEditorPlugin::_file_selected(const String &p_file) {
source_emission_file = p_file;
- emission_mask->popup_centered_minsize();
+ emission_mask->popup_centered();
}
void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
@@ -73,7 +73,7 @@ void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
} break;
case MENU_CLEAR_EMISSION_MASK: {
- emission_mask->popup_centered_minsize();
+ emission_mask->popup_centered();
} break;
case MENU_RESTART: {
@@ -241,7 +241,7 @@ void CPUParticles2DEditorPlugin::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
menu->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles2DEditorPlugin::_menu_callback));
- menu->set_icon(menu->get_popup()->get_icon("Particles2D", "EditorIcons"));
+ menu->set_icon(epoints->get_theme_icon("CPUParticles2D", "EditorIcons"));
file->connect("file_selected", callable_mp(this, &CPUParticles2DEditorPlugin::_file_selected));
}
}
@@ -251,7 +251,7 @@ void CPUParticles2DEditorPlugin::_bind_methods() {
CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) {
- particles = NULL;
+ particles = nullptr;
editor = p_node;
undo_redo = editor->get_undo_redo();
@@ -262,11 +262,9 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) {
toolbar->add_child(memnew(VSeparator));
menu = memnew(MenuButton);
- menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
- menu->get_popup()->add_separator();
menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART);
- // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
- menu->set_text(TTR("Particles"));
+ menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
+ menu->set_text(TTR("CPUParticles2D"));
menu->set_switch_on_hover(true);
toolbar->add_child(menu);
@@ -276,7 +274,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) {
for (List<String>::Element *E = ext.front(); E; E = E->next()) {
file->add_filter("*." + E->get() + "; " + E->get().to_upper());
}
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
toolbar->add_child(file);
epoints = memnew(SpinBox);
diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..59a353a581
--- /dev/null
+++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
@@ -0,0 +1,144 @@
+/*************************************************************************/
+/* cpu_particles_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "cpu_particles_3d_editor_plugin.h"
+
+#include "editor/plugins/node_3d_editor_plugin.h"
+
+void CPUParticles3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ hide();
+ }
+}
+
+void CPUParticles3DEditor::_notification(int p_notification) {
+
+ if (p_notification == NOTIFICATION_ENTER_TREE) {
+ options->set_icon(get_theme_icon("CPUParticles3D", "EditorIcons"));
+ }
+}
+
+void CPUParticles3DEditor::_menu_option(int p_option) {
+
+ switch (p_option) {
+
+ case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
+
+ emission_tree_dialog->popup_centered_ratio();
+
+ } break;
+
+ case MENU_OPTION_RESTART: {
+
+ node->restart();
+
+ } break;
+ }
+}
+
+void CPUParticles3DEditor::edit(CPUParticles3D *p_particles) {
+
+ base_node = p_particles;
+ node = p_particles;
+}
+
+void CPUParticles3DEditor::_generate_emission_points() {
+
+ /// hacer codigo aca
+ Vector<Vector3> points;
+ Vector<Vector3> normals;
+
+ if (!_generate(points, normals)) {
+ return;
+ }
+
+ if (normals.size() == 0) {
+ node->set_emission_shape(CPUParticles3D::EMISSION_SHAPE_POINTS);
+ node->set_emission_points(points);
+ } else {
+ node->set_emission_shape(CPUParticles3D::EMISSION_SHAPE_DIRECTED_POINTS);
+ node->set_emission_points(points);
+ node->set_emission_normals(normals);
+ }
+}
+
+void CPUParticles3DEditor::_bind_methods() {
+}
+
+CPUParticles3DEditor::CPUParticles3DEditor() {
+
+ particles_editor_hb = memnew(HBoxContainer);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
+ options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
+ particles_editor_hb->add_child(options);
+ particles_editor_hb->hide();
+
+ options->set_text(TTR("CPUParticles3D"));
+ options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART);
+ options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
+ options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option));
+}
+
+void CPUParticles3DEditorPlugin::edit(Object *p_object) {
+
+ particles_editor->edit(Object::cast_to<CPUParticles3D>(p_object));
+}
+
+bool CPUParticles3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("CPUParticles3D");
+}
+
+void CPUParticles3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ particles_editor->show();
+ particles_editor->particles_editor_hb->show();
+ } else {
+ particles_editor->particles_editor_hb->hide();
+ particles_editor->hide();
+ particles_editor->edit(nullptr);
+ }
+}
+
+CPUParticles3DEditorPlugin::CPUParticles3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ particles_editor = memnew(CPUParticles3DEditor);
+ editor->get_viewport()->add_child(particles_editor);
+
+ particles_editor->hide();
+}
+
+CPUParticles3DEditorPlugin::~CPUParticles3DEditorPlugin() {
+}
diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.h b/editor/plugins/cpu_particles_3d_editor_plugin.h
new file mode 100644
index 0000000000..796c842e07
--- /dev/null
+++ b/editor/plugins/cpu_particles_3d_editor_plugin.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* cpu_particles_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CPU_PARTICLES_EDITOR_PLUGIN_H
+#define CPU_PARTICLES_EDITOR_PLUGIN_H
+
+#include "editor/plugins/gpu_particles_3d_editor_plugin.h"
+#include "scene/3d/cpu_particles_3d.h"
+
+class CPUParticles3DEditor : public GPUParticles3DEditorBase {
+
+ GDCLASS(CPUParticles3DEditor, GPUParticles3DEditorBase);
+
+ enum Menu {
+
+ MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
+ MENU_OPTION_CLEAR_EMISSION_VOLUME,
+ MENU_OPTION_RESTART
+
+ };
+
+ CPUParticles3D *node;
+
+ void _menu_option(int);
+
+ friend class CPUParticles3DEditorPlugin;
+
+ virtual void _generate_emission_points();
+
+protected:
+ void _notification(int p_notification);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ void edit(CPUParticles3D *p_particles);
+ CPUParticles3DEditor();
+};
+
+class CPUParticles3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(CPUParticles3DEditorPlugin, EditorPlugin);
+
+ CPUParticles3DEditor *particles_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const { return "CPUParticles3D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ CPUParticles3DEditorPlugin(EditorNode *p_node);
+ ~CPUParticles3DEditorPlugin();
+};
+
+#endif // CPU_PARTICLES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/cpu_particles_editor_plugin.cpp b/editor/plugins/cpu_particles_editor_plugin.cpp
deleted file mode 100644
index 2161041ee6..0000000000
--- a/editor/plugins/cpu_particles_editor_plugin.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*************************************************************************/
-/* cpu_particles_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "cpu_particles_editor_plugin.h"
-
-#include "editor/plugins/spatial_editor_plugin.h"
-
-void CPUParticlesEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- hide();
- }
-}
-
-void CPUParticlesEditor::_notification(int p_notification) {
-
- if (p_notification == NOTIFICATION_ENTER_TREE) {
- options->set_icon(options->get_popup()->get_icon("CPUParticles", "EditorIcons"));
- }
-}
-
-void CPUParticlesEditor::_menu_option(int p_option) {
-
- switch (p_option) {
-
- case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
-
- emission_tree_dialog->popup_centered_ratio();
-
- } break;
-
- case MENU_OPTION_RESTART: {
-
- node->restart();
-
- } break;
- }
-}
-
-void CPUParticlesEditor::edit(CPUParticles *p_particles) {
-
- base_node = p_particles;
- node = p_particles;
-}
-
-void CPUParticlesEditor::_generate_emission_points() {
-
- /// hacer codigo aca
- Vector<Vector3> points;
- Vector<Vector3> normals;
-
- if (!_generate(points, normals)) {
- return;
- }
-
- if (normals.size() == 0) {
- node->set_emission_shape(CPUParticles::EMISSION_SHAPE_POINTS);
- node->set_emission_points(points);
- } else {
- node->set_emission_shape(CPUParticles::EMISSION_SHAPE_DIRECTED_POINTS);
- node->set_emission_points(points);
- node->set_emission_normals(normals);
- }
-}
-
-void CPUParticlesEditor::_bind_methods() {
-}
-
-CPUParticlesEditor::CPUParticlesEditor() {
-
- particles_editor_hb = memnew(HBoxContainer);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
- options = memnew(MenuButton);
- options->set_switch_on_hover(true);
- particles_editor_hb->add_child(options);
- particles_editor_hb->hide();
-
- options->set_text(TTR("CPUParticles"));
- options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART);
- options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticlesEditor::_menu_option));
-}
-
-void CPUParticlesEditorPlugin::edit(Object *p_object) {
-
- particles_editor->edit(Object::cast_to<CPUParticles>(p_object));
-}
-
-bool CPUParticlesEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("CPUParticles");
-}
-
-void CPUParticlesEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- particles_editor->show();
- particles_editor->particles_editor_hb->show();
- } else {
- particles_editor->particles_editor_hb->hide();
- particles_editor->hide();
- particles_editor->edit(NULL);
- }
-}
-
-CPUParticlesEditorPlugin::CPUParticlesEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- particles_editor = memnew(CPUParticlesEditor);
- editor->get_viewport()->add_child(particles_editor);
-
- particles_editor->hide();
-}
-
-CPUParticlesEditorPlugin::~CPUParticlesEditorPlugin() {
-}
diff --git a/editor/plugins/cpu_particles_editor_plugin.h b/editor/plugins/cpu_particles_editor_plugin.h
deleted file mode 100644
index 4cf143fc0c..0000000000
--- a/editor/plugins/cpu_particles_editor_plugin.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*************************************************************************/
-/* cpu_particles_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CPU_PARTICLES_EDITOR_PLUGIN_H
-#define CPU_PARTICLES_EDITOR_PLUGIN_H
-
-#include "editor/plugins/particles_editor_plugin.h"
-#include "scene/3d/cpu_particles.h"
-
-class CPUParticlesEditor : public ParticlesEditorBase {
-
- GDCLASS(CPUParticlesEditor, ParticlesEditorBase);
-
- enum Menu {
-
- MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
- MENU_OPTION_CLEAR_EMISSION_VOLUME,
- MENU_OPTION_RESTART
-
- };
-
- CPUParticles *node;
-
- void _menu_option(int);
-
- friend class CPUParticlesEditorPlugin;
-
- virtual void _generate_emission_points();
-
-protected:
- void _notification(int p_notification);
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
-public:
- void edit(CPUParticles *p_particles);
- CPUParticlesEditor();
-};
-
-class CPUParticlesEditorPlugin : public EditorPlugin {
-
- GDCLASS(CPUParticlesEditorPlugin, EditorPlugin);
-
- CPUParticlesEditor *particles_editor;
- EditorNode *editor;
-
-public:
- virtual String get_name() const { return "CPUParticles"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- CPUParticlesEditorPlugin(EditorNode *p_node);
- ~CPUParticlesEditorPlugin();
-};
-
-#endif // CPU_PARTICLES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 878787231d..71c5a78e0b 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -32,7 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/core_string_names.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
@@ -210,7 +210,7 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
else
tangent = 9999 * (dir.y >= 0 ? 1 : -1);
- bool link = !Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool link = !InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT);
if (_selected_tangent == TANGENT_LEFT) {
curve.set_point_left_tangent(_selected_point, tangent);
@@ -511,7 +511,7 @@ void CurveEditor::set_hover_point_index(int index) {
}
void CurveEditor::update_view_transform() {
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
const real_t margin = font->get_height() + 2 * EDSCALE;
float min_y = 0;
@@ -626,7 +626,7 @@ void CurveEditor::_draw() {
// Background
Vector2 view_size = get_rect().size;
- draw_style_box(get_stylebox("bg", "Tree"), Rect2(Point2(), view_size));
+ draw_style_box(get_theme_stylebox("bg", "Tree"), Rect2(Point2(), view_size));
// Grid
@@ -635,8 +635,8 @@ void CurveEditor::_draw() {
Vector2 min_edge = get_world_pos(Vector2(0, view_size.y));
Vector2 max_edge = get_world_pos(Vector2(view_size.x, 0));
- const Color grid_color0 = get_color("mono_color", "Editor") * Color(1, 1, 1, 0.15);
- const Color grid_color1 = get_color("mono_color", "Editor") * Color(1, 1, 1, 0.07);
+ const Color grid_color0 = get_theme_color("mono_color", "Editor") * Color(1, 1, 1, 0.15);
+ const Color grid_color1 = get_theme_color("mono_color", "Editor") * Color(1, 1, 1, 0.07);
draw_line(Vector2(min_edge.x, curve.get_min_value()), Vector2(max_edge.x, curve.get_min_value()), grid_color0);
draw_line(Vector2(max_edge.x, curve.get_max_value()), Vector2(min_edge.x, curve.get_max_value()), grid_color0);
draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0);
@@ -656,9 +656,9 @@ void CurveEditor::_draw() {
draw_set_transform_matrix(Transform2D());
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
float font_height = font->get_height();
- Color text_color = get_color("font_color", "Editor");
+ Color text_color = get_theme_color("font_color", "Editor");
{
// X axis
@@ -686,7 +686,7 @@ void CurveEditor::_draw() {
if (_selected_point >= 0) {
- const Color tangent_color = get_color("accent_color", "Editor");
+ const Color tangent_color = get_theme_color("accent_color", "Editor");
int i = _selected_point;
Vector2 pos = curve.get_point_position(i);
@@ -708,8 +708,8 @@ void CurveEditor::_draw() {
draw_set_transform_matrix(_world_to_view);
- const Color line_color = get_color("font_color", "Editor");
- const Color edge_line_color = get_color("highlight_color", "Editor");
+ const Color line_color = get_theme_color("font_color", "Editor");
+ const Color edge_line_color = get_theme_color("highlight_color", "Editor");
CanvasItemPlotCurve plot_func(*this, line_color, edge_line_color);
plot_curve_accurate(curve, 4.f / view_size.x, plot_func);
@@ -718,8 +718,8 @@ void CurveEditor::_draw() {
draw_set_transform_matrix(Transform2D());
- const Color point_color = get_color("font_color", "Editor");
- const Color selected_point_color = get_color("accent_color", "Editor");
+ const Color point_color = get_theme_color("font_color", "Editor");
+ const Color selected_point_color = get_theme_color("accent_color", "Editor");
for (int i = 0; i < curve.get_point_count(); ++i) {
Vector2 pos = curve.get_point_position(i);
@@ -755,7 +755,7 @@ void CurveEditor::_bind_methods() {
bool EditorInspectorPluginCurve::can_handle(Object *p_object) {
- return Object::cast_to<Curve>(p_object) != NULL;
+ return Object::cast_to<Curve>(p_object) != nullptr;
}
void EditorInspectorPluginCurve::parse_begin(Object *p_object) {
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index c4069ac2ab..566ff378c3 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -54,7 +54,6 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
// Main editor debug menu.
debug_menu = p_debug_menu;
PopupMenu *p = debug_menu->get_popup();
- p->set_hide_on_window_lose_focus(true);
p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged."));
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 3c173ab783..a8c4bddccf 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -328,19 +328,19 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Si
if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
- VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
+ RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
preview_done = false;
- VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
+ RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
while (!preview_done) {
OS::get_singleton()->delay_usec(10);
}
- Ref<Image> img = VS::get_singleton()->texture_2d_get(viewport_texture);
- VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
+ Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
+ RS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>());
@@ -358,35 +358,35 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Si
EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
- scenario = VS::get_singleton()->scenario_create();
+ scenario = RS::get_singleton()->scenario_create();
- viewport = VS::get_singleton()->viewport_create();
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED);
- VS::get_singleton()->viewport_set_scenario(viewport, scenario);
- VS::get_singleton()->viewport_set_size(viewport, 128, 128);
- VS::get_singleton()->viewport_set_transparent_background(viewport, true);
- VS::get_singleton()->viewport_set_active(viewport, true);
- viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
+ viewport = RS::get_singleton()->viewport_create();
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_DISABLED);
+ RS::get_singleton()->viewport_set_scenario(viewport, scenario);
+ RS::get_singleton()->viewport_set_size(viewport, 128, 128);
+ RS::get_singleton()->viewport_set_transparent_background(viewport, true);
+ RS::get_singleton()->viewport_set_active(viewport, true);
+ viewport_texture = RS::get_singleton()->viewport_get_texture(viewport);
- camera = VS::get_singleton()->camera_create();
- VS::get_singleton()->viewport_attach_camera(viewport, camera);
- VS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3)));
- VS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10);
+ camera = RS::get_singleton()->camera_create();
+ RS::get_singleton()->viewport_attach_camera(viewport, camera);
+ RS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3)));
+ RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10);
- light = VS::get_singleton()->directional_light_create();
- light_instance = VS::get_singleton()->instance_create2(light, scenario);
- VS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
+ light = RS::get_singleton()->directional_light_create();
+ light_instance = RS::get_singleton()->instance_create2(light, scenario);
+ RS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
- light2 = VS::get_singleton()->directional_light_create();
- VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
- //VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
+ light2 = RS::get_singleton()->directional_light_create();
+ RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
+ //RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
- light_instance2 = VS::get_singleton()->instance_create2(light2, scenario);
+ light_instance2 = RS::get_singleton()->instance_create2(light2, scenario);
- VS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
+ RS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
- sphere = VS::get_singleton()->mesh_create();
- sphere_instance = VS::get_singleton()->instance_create2(sphere, scenario);
+ sphere = RS::get_singleton()->mesh_create();
+ sphere_instance = RS::get_singleton()->instance_create2(sphere, scenario);
int lats = 32;
int lons = 32;
@@ -453,25 +453,25 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
}
Array arr;
- arr.resize(VS::ARRAY_MAX);
- arr[VS::ARRAY_VERTEX] = vertices;
- arr[VS::ARRAY_NORMAL] = normals;
- arr[VS::ARRAY_TANGENT] = tangents;
- arr[VS::ARRAY_TEX_UV] = uvs;
- VS::get_singleton()->mesh_add_surface_from_arrays(sphere, VS::PRIMITIVE_TRIANGLES, arr);
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = vertices;
+ arr[RS::ARRAY_NORMAL] = normals;
+ arr[RS::ARRAY_TANGENT] = tangents;
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ RS::get_singleton()->mesh_add_surface_from_arrays(sphere, RS::PRIMITIVE_TRIANGLES, arr);
}
EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
- VS::get_singleton()->free(sphere);
- VS::get_singleton()->free(sphere_instance);
- VS::get_singleton()->free(viewport);
- VS::get_singleton()->free(light);
- VS::get_singleton()->free(light_instance);
- VS::get_singleton()->free(light2);
- VS::get_singleton()->free(light_instance2);
- VS::get_singleton()->free(camera);
- VS::get_singleton()->free(scenario);
+ RS::get_singleton()->free(sphere);
+ RS::get_singleton()->free(sphere_instance);
+ RS::get_singleton()->free(viewport);
+ RS::get_singleton()->free(light);
+ RS::get_singleton()->free(light_instance);
+ RS::get_singleton()->free(light2);
+ RS::get_singleton()->free(light_instance2);
+ RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(scenario);
}
///////////////////////////////////////////////////////////////////////////
@@ -706,7 +706,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
Ref<Mesh> mesh = p_from;
ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture2D>());
- VS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid());
+ RS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid());
AABB aabb = mesh->get_aabb();
Vector3 ofs = aabb.position + aabb.size * 0.5;
@@ -723,21 +723,21 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
xform.basis.scale(Vector3(m, m, m));
xform.origin = -xform.basis.xform(ofs); //-ofs*m;
xform.origin.z -= rot_aabb.size.z * 2;
- VS::get_singleton()->instance_set_transform(mesh_instance, xform);
+ RS::get_singleton()->instance_set_transform(mesh_instance, xform);
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
preview_done = false;
- VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
+ RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
while (!preview_done) {
OS::get_singleton()->delay_usec(10);
}
- Ref<Image> img = VS::get_singleton()->texture_2d_get(viewport_texture);
+ Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
- VS::get_singleton()->instance_set_base(mesh_instance, RID());
+ RS::get_singleton()->instance_set_base(mesh_instance, RID());
img->convert(Image::FORMAT_RGBA8);
@@ -759,49 +759,49 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
- scenario = VS::get_singleton()->scenario_create();
+ scenario = RS::get_singleton()->scenario_create();
- viewport = VS::get_singleton()->viewport_create();
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED);
- VS::get_singleton()->viewport_set_scenario(viewport, scenario);
- VS::get_singleton()->viewport_set_size(viewport, 128, 128);
- VS::get_singleton()->viewport_set_transparent_background(viewport, true);
- VS::get_singleton()->viewport_set_active(viewport, true);
- viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
+ viewport = RS::get_singleton()->viewport_create();
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_DISABLED);
+ RS::get_singleton()->viewport_set_scenario(viewport, scenario);
+ RS::get_singleton()->viewport_set_size(viewport, 128, 128);
+ RS::get_singleton()->viewport_set_transparent_background(viewport, true);
+ RS::get_singleton()->viewport_set_active(viewport, true);
+ viewport_texture = RS::get_singleton()->viewport_get_texture(viewport);
- camera = VS::get_singleton()->camera_create();
- VS::get_singleton()->viewport_attach_camera(viewport, camera);
- VS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3)));
- //VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
- VS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0);
+ camera = RS::get_singleton()->camera_create();
+ RS::get_singleton()->viewport_attach_camera(viewport, camera);
+ RS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3)));
+ //RS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
+ RS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0);
- light = VS::get_singleton()->directional_light_create();
- light_instance = VS::get_singleton()->instance_create2(light, scenario);
- VS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
+ light = RS::get_singleton()->directional_light_create();
+ light_instance = RS::get_singleton()->instance_create2(light, scenario);
+ RS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
- light2 = VS::get_singleton()->directional_light_create();
- VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
- //VS::get_singleton()->light_set_color(light2, VS::LIGHT_COLOR_SPECULAR, Color(0.0, 0.0, 0.0));
- light_instance2 = VS::get_singleton()->instance_create2(light2, scenario);
+ light2 = RS::get_singleton()->directional_light_create();
+ RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7));
+ //RS::get_singleton()->light_set_color(light2, RS::LIGHT_COLOR_SPECULAR, Color(0.0, 0.0, 0.0));
+ light_instance2 = RS::get_singleton()->instance_create2(light2, scenario);
- VS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
+ RS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
- //sphere = VS::get_singleton()->mesh_create();
- mesh_instance = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_scenario(mesh_instance, scenario);
+ //sphere = RS::get_singleton()->mesh_create();
+ mesh_instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_scenario(mesh_instance, scenario);
}
EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
- //VS::get_singleton()->free(sphere);
- VS::get_singleton()->free(mesh_instance);
- VS::get_singleton()->free(viewport);
- VS::get_singleton()->free(light);
- VS::get_singleton()->free(light_instance);
- VS::get_singleton()->free(light2);
- VS::get_singleton()->free(light_instance2);
- VS::get_singleton()->free(camera);
- VS::get_singleton()->free(scenario);
+ //RS::get_singleton()->free(sphere);
+ RS::get_singleton()->free(mesh_instance);
+ RS::get_singleton()->free(viewport);
+ RS::get_singleton()->free(light);
+ RS::get_singleton()->free(light_instance);
+ RS::get_singleton()->free(light2);
+ RS::get_singleton()->free(light_instance2);
+ RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(scenario);
}
///////////////////////////////////////////////////////////////////////////
@@ -849,16 +849,16 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
font->draw(canvas_item, pos, sampled_text);
preview_done = false;
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
- VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
+ 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) {
OS::get_singleton()->delay_usec(10);
}
- VS::get_singleton()->canvas_item_clear(canvas_item);
+ RS::get_singleton()->canvas_item_clear(canvas_item);
- Ref<Image> img = VS::get_singleton()->texture_2d_get(viewport_texture);
+ Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
img->convert(Image::FORMAT_RGBA8);
@@ -891,22 +891,22 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2
EditorFontPreviewPlugin::EditorFontPreviewPlugin() {
- viewport = VS::get_singleton()->viewport_create();
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED);
- VS::get_singleton()->viewport_set_size(viewport, 128, 128);
- VS::get_singleton()->viewport_set_active(viewport, true);
- viewport_texture = VS::get_singleton()->viewport_get_texture(viewport);
+ viewport = RS::get_singleton()->viewport_create();
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_DISABLED);
+ RS::get_singleton()->viewport_set_size(viewport, 128, 128);
+ RS::get_singleton()->viewport_set_active(viewport, true);
+ viewport_texture = RS::get_singleton()->viewport_get_texture(viewport);
- canvas = VS::get_singleton()->canvas_create();
- canvas_item = VS::get_singleton()->canvas_item_create();
+ canvas = RS::get_singleton()->canvas_create();
+ canvas_item = RS::get_singleton()->canvas_item_create();
- VS::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VS::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
+ RS::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ RS::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
}
EditorFontPreviewPlugin::~EditorFontPreviewPlugin() {
- VS::get_singleton()->free(canvas_item);
- VS::get_singleton()->free(canvas);
- VS::get_singleton()->free(viewport);
+ RS::get_singleton()->free(canvas_item);
+ RS::get_singleton()->free(canvas);
+ RS::get_singleton()->free(viewport);
}
diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp
index c077c23e8a..6a171c4703 100644
--- a/editor/plugins/gi_probe_editor_plugin.cpp
+++ b/editor/plugins/gi_probe_editor_plugin.cpp
@@ -87,16 +87,16 @@ void GIProbeEditorPlugin::_notification(int p_what) {
Color color;
if (size_mb <= 16.0 + CMP_EPSILON) {
// Fast.
- color = bake_info->get_color("success_color", "Editor");
+ color = bake_info->get_theme_color("success_color", "Editor");
} else if (size_mb <= 64.0 + CMP_EPSILON) {
// Medium.
- color = bake_info->get_color("warning_color", "Editor");
+ color = bake_info->get_theme_color("warning_color", "Editor");
} else {
// Slow.
- color = bake_info->get_color("error_color", "Editor");
+ color = bake_info->get_theme_color("error_color", "Editor");
}
+ bake_info->add_theme_color_override("font_color", color);
- bake_info->add_color_override("font_color", color);
bake_info->set_text(text);
}
}
@@ -113,25 +113,25 @@ void GIProbeEditorPlugin::make_visible(bool p_visible) {
}
}
-EditorProgress *GIProbeEditorPlugin::tmp_progress = NULL;
+EditorProgress *GIProbeEditorPlugin::tmp_progress = nullptr;
void GIProbeEditorPlugin::bake_func_begin(int p_steps) {
- ERR_FAIL_COND(tmp_progress != NULL);
+ ERR_FAIL_COND(tmp_progress != nullptr);
tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake GI Probe"), p_steps));
}
void GIProbeEditorPlugin::bake_func_step(int p_step, const String &p_description) {
- ERR_FAIL_COND(tmp_progress == NULL);
+ ERR_FAIL_COND(tmp_progress == nullptr);
tmp_progress->step(p_description, p_step, false);
}
void GIProbeEditorPlugin::bake_func_end() {
- ERR_FAIL_COND(tmp_progress == NULL);
+ ERR_FAIL_COND(tmp_progress == nullptr);
memdelete(tmp_progress);
- tmp_progress = NULL;
+ tmp_progress = nullptr;
}
void GIProbeEditorPlugin::_giprobe_save_path_and_bake(const String &p_path) {
@@ -153,7 +153,7 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bake_hb->hide();
bake = memnew(ToolButton);
- bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons"));
+ bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons"));
bake->set_text(TTR("Bake GI Probe"));
bake->connect("pressed", callable_mp(this, &GIProbeEditorPlugin::_bake));
bake_hb->add_child(bake);
@@ -163,9 +163,9 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
bake_hb->add_child(bake_info);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb);
- gi_probe = NULL;
+ gi_probe = nullptr;
probe_file = memnew(EditorFileDialog);
- probe_file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ probe_file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
probe_file->add_filter("*.res");
probe_file->connect("file_selected", callable_mp(this, &GIProbeEditorPlugin::_giprobe_save_path_and_bake));
get_editor_interface()->get_base_control()->add_child(probe_file);
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..5c35285c22
--- /dev/null
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -0,0 +1,432 @@
+/*************************************************************************/
+/* gpu_particles_2d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "gpu_particles_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "core/io/image_loader.h"
+#include "scene/2d/cpu_particles_2d.h"
+#include "scene/gui/separator.h"
+#include "scene/resources/particles_material.h"
+
+void GPUParticles2DEditorPlugin::edit(Object *p_object) {
+
+ particles = Object::cast_to<GPUParticles2D>(p_object);
+}
+
+bool GPUParticles2DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("GPUParticles2D");
+}
+
+void GPUParticles2DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+
+ toolbar->show();
+ } else {
+
+ toolbar->hide();
+ }
+}
+
+void GPUParticles2DEditorPlugin::_file_selected(const String &p_file) {
+
+ source_emission_file = p_file;
+ emission_mask->popup_centered();
+}
+
+void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
+
+ switch (p_idx) {
+ case MENU_GENERATE_VISIBILITY_RECT: {
+ float gen_time = particles->get_lifetime();
+ if (gen_time < 1.0)
+ generate_seconds->set_value(1.0);
+ else
+ generate_seconds->set_value(trunc(gen_time) + 1.0);
+ generate_visibility_rect->popup_centered();
+ } break;
+ case MENU_LOAD_EMISSION_MASK: {
+
+ file->popup_centered_ratio();
+
+ } break;
+ case MENU_CLEAR_EMISSION_MASK: {
+
+ emission_mask->popup_centered();
+ } break;
+ case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
+
+ CPUParticles2D *cpu_particles = memnew(CPUParticles2D);
+ cpu_particles->convert_from_particles(particles);
+ 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_z_index(particles->get_z_index());
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Convert to CPUParticles2D"));
+ ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", particles, cpu_particles, true, false);
+ ur->add_do_reference(cpu_particles);
+ ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, particles, false, false);
+ ur->add_undo_reference(particles);
+ ur->commit_action();
+
+ } break;
+ case MENU_RESTART: {
+
+ particles->restart();
+ }
+ }
+}
+
+void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
+
+ float time = generate_seconds->get_value();
+
+ float running = 0.0;
+
+ EditorProgress ep("gen_vrect", TTR("Generating Visibility Rect"), int(time));
+
+ bool was_emitting = particles->is_emitting();
+ if (!was_emitting) {
+ particles->set_emitting(true);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ Rect2 rect;
+ while (running < time) {
+
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec();
+ ep.step("Generating...", int(running), true);
+ OS::get_singleton()->delay_usec(1000);
+
+ Rect2 capture = particles->capture_rect();
+ if (rect == Rect2())
+ rect = capture;
+ else
+ rect = rect.merge(capture);
+
+ running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
+ }
+
+ if (!was_emitting) {
+ particles->set_emitting(false);
+ }
+
+ undo_redo->create_action(TTR("Generate Visibility Rect"));
+ undo_redo->add_do_method(particles, "set_visibility_rect", rect);
+ undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect());
+ undo_redo->commit_action();
+}
+
+void GPUParticles2DEditorPlugin::_generate_emission_mask() {
+
+ Ref<ParticlesMaterial> pm = particles->get_process_material();
+ if (!pm.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material"));
+ return;
+ }
+
+ Ref<Image> img;
+ img.instance();
+ Error err = ImageLoader::load_image(source_emission_file, img);
+ ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'.");
+
+ if (img->is_compressed()) {
+ img->decompress();
+ }
+ img->convert(Image::FORMAT_RGBA8);
+ ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
+ Size2i s = Size2(img->get_width(), img->get_height());
+ ERR_FAIL_COND(s.width == 0 || s.height == 0);
+
+ Vector<Point2> valid_positions;
+ Vector<Point2> valid_normals;
+ Vector<uint8_t> valid_colors;
+
+ valid_positions.resize(s.width * s.height);
+
+ EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected();
+
+ if (emode == EMISSION_MODE_BORDER_DIRECTED) {
+ valid_normals.resize(s.width * s.height);
+ }
+
+ bool capture_colors = emission_colors->is_pressed();
+
+ if (capture_colors) {
+ valid_colors.resize(s.width * s.height * 4);
+ }
+
+ int vpc = 0;
+
+ {
+ Vector<uint8_t> data = img->get_data();
+ const uint8_t *r = data.ptr();
+
+ for (int i = 0; i < s.width; i++) {
+ for (int j = 0; j < s.height; j++) {
+
+ uint8_t a = r[(j * s.width + i) * 4 + 3];
+
+ if (a > 128) {
+
+ if (emode == EMISSION_MODE_SOLID) {
+
+ if (capture_colors) {
+ valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
+ valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
+ valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
+ valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
+ }
+ valid_positions.write[vpc++] = Point2(i, j);
+
+ } else {
+
+ bool on_border = false;
+ for (int x = i - 1; x <= i + 1; x++) {
+ for (int y = j - 1; y <= j + 1; y++) {
+
+ if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
+ on_border = true;
+ break;
+ }
+ }
+
+ if (on_border)
+ break;
+ }
+
+ if (on_border) {
+ valid_positions.write[vpc] = Point2(i, j);
+
+ if (emode == EMISSION_MODE_BORDER_DIRECTED) {
+ Vector2 normal;
+ for (int x = i - 2; x <= i + 2; x++) {
+ for (int y = j - 2; y <= j + 2; y++) {
+
+ if (x == i && y == j)
+ continue;
+
+ if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
+ normal += Vector2(x - i, y - j).normalized();
+ }
+ }
+ }
+
+ normal.normalize();
+ valid_normals.write[vpc] = normal;
+ }
+
+ if (capture_colors) {
+ valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
+ valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
+ valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
+ valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
+ }
+
+ vpc++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ valid_positions.resize(vpc);
+ if (valid_normals.size()) {
+ valid_normals.resize(vpc);
+ }
+
+ ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image...");
+
+ Vector<uint8_t> texdata;
+
+ int w = 2048;
+ int h = (vpc / 2048) + 1;
+
+ texdata.resize(w * h * 2 * sizeof(float));
+
+ {
+ uint8_t *tw = texdata.ptrw();
+ float *twf = (float *)tw;
+ for (int i = 0; i < vpc; i++) {
+
+ twf[i * 2 + 0] = valid_positions[i].x;
+ twf[i * 2 + 1] = valid_positions[i].y;
+ }
+ }
+
+ img.instance();
+ img->create(w, h, false, Image::FORMAT_RGF, texdata);
+
+ Ref<ImageTexture> imgt;
+ imgt.instance();
+ imgt->create_from_image(img);
+
+ pm->set_emission_point_texture(imgt);
+ pm->set_emission_point_count(vpc);
+
+ if (capture_colors) {
+
+ Vector<uint8_t> colordata;
+ colordata.resize(w * h * 4); //use RG texture
+
+ {
+ uint8_t *tw = colordata.ptrw();
+ for (int i = 0; i < vpc * 4; i++) {
+
+ tw[i] = valid_colors[i];
+ }
+ }
+
+ img.instance();
+ img->create(w, h, false, Image::FORMAT_RGBA8, colordata);
+
+ imgt.instance();
+ imgt->create_from_image(img);
+ pm->set_emission_color_texture(imgt);
+ }
+
+ if (valid_normals.size()) {
+ pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+
+ Vector<uint8_t> normdata;
+ normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
+
+ {
+ uint8_t *tw = normdata.ptrw();
+ float *twf = (float *)tw;
+ for (int i = 0; i < vpc; i++) {
+ twf[i * 2 + 0] = valid_normals[i].x;
+ twf[i * 2 + 1] = valid_normals[i].y;
+ }
+ }
+
+ img.instance();
+ img->create(w, h, false, Image::FORMAT_RGF, normdata);
+
+ imgt.instance();
+ imgt->create_from_image(img);
+ pm->set_emission_normal_texture(imgt);
+
+ } else {
+ pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+ }
+}
+
+void GPUParticles2DEditorPlugin::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ menu->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles2DEditorPlugin::_menu_callback));
+ menu->set_icon(menu->get_theme_icon("GPUParticles2D", "EditorIcons"));
+ file->connect("file_selected", callable_mp(this, &GPUParticles2DEditorPlugin::_file_selected));
+ }
+}
+
+void GPUParticles2DEditorPlugin::_bind_methods() {
+}
+
+GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin(EditorNode *p_node) {
+
+ particles = nullptr;
+ editor = p_node;
+ undo_redo = editor->get_undo_redo();
+
+ toolbar = memnew(HBoxContainer);
+ add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
+ toolbar->hide();
+
+ toolbar->add_child(memnew(VSeparator));
+
+ menu = memnew(MenuButton);
+ menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART);
+ menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT);
+ menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
+ // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
+ menu->get_popup()->add_item(TTR("Convert to CPUParticles2D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
+ menu->set_text(TTR("GPUParticles2D"));
+ menu->set_switch_on_hover(true);
+ toolbar->add_child(menu);
+
+ file = memnew(EditorFileDialog);
+ List<String> ext;
+ ImageLoader::get_recognized_extensions(&ext);
+ for (List<String>::Element *E = ext.front(); E; E = E->next()) {
+ file->add_filter("*." + E->get() + "; " + E->get().to_upper());
+ }
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ toolbar->add_child(file);
+
+ epoints = memnew(SpinBox);
+ epoints->set_min(1);
+ epoints->set_max(8192);
+ epoints->set_step(1);
+ epoints->set_value(512);
+ file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints);
+
+ generate_visibility_rect = memnew(ConfirmationDialog);
+ generate_visibility_rect->set_title(TTR("Generate Visibility Rect"));
+ VBoxContainer *genvb = memnew(VBoxContainer);
+ generate_visibility_rect->add_child(genvb);
+ generate_seconds = memnew(SpinBox);
+ genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
+ generate_seconds->set_min(0.1);
+ generate_seconds->set_max(25);
+ generate_seconds->set_value(2);
+
+ toolbar->add_child(generate_visibility_rect);
+
+ generate_visibility_rect->connect("confirmed", callable_mp(this, &GPUParticles2DEditorPlugin::_generate_visibility_rect));
+
+ emission_mask = memnew(ConfirmationDialog);
+ emission_mask->set_title(TTR("Load Emission Mask"));
+ VBoxContainer *emvb = memnew(VBoxContainer);
+ emission_mask->add_child(emvb);
+ emission_mask_mode = memnew(OptionButton);
+ emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode);
+ emission_mask_mode->add_item(TTR("Solid Pixels"), EMISSION_MODE_SOLID);
+ emission_mask_mode->add_item(TTR("Border Pixels"), EMISSION_MODE_BORDER);
+ emission_mask_mode->add_item(TTR("Directed Border Pixels"), EMISSION_MODE_BORDER_DIRECTED);
+ emission_colors = memnew(CheckBox);
+ emission_colors->set_text(TTR("Capture from Pixel"));
+ emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
+
+ toolbar->add_child(emission_mask);
+
+ emission_mask->connect("confirmed", callable_mp(this, &GPUParticles2DEditorPlugin::_generate_emission_mask));
+}
+
+GPUParticles2DEditorPlugin::~GPUParticles2DEditorPlugin() {
+}
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h
new file mode 100644
index 0000000000..008d04a211
--- /dev/null
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.h
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* gpu_particles_2d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PARTICLES_2D_EDITOR_PLUGIN_H
+#define PARTICLES_2D_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/2d/collision_polygon_2d.h"
+#include "scene/2d/gpu_particles_2d.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/file_dialog.h"
+
+class GPUParticles2DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin);
+
+ enum {
+
+ MENU_GENERATE_VISIBILITY_RECT,
+ MENU_LOAD_EMISSION_MASK,
+ MENU_CLEAR_EMISSION_MASK,
+ MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
+ MENU_RESTART
+ };
+
+ enum EmissionMode {
+ EMISSION_MODE_SOLID,
+ EMISSION_MODE_BORDER,
+ EMISSION_MODE_BORDER_DIRECTED
+ };
+
+ GPUParticles2D *particles;
+
+ EditorFileDialog *file;
+ EditorNode *editor;
+
+ HBoxContainer *toolbar;
+ MenuButton *menu;
+
+ SpinBox *epoints;
+
+ ConfirmationDialog *generate_visibility_rect;
+ SpinBox *generate_seconds;
+
+ ConfirmationDialog *emission_mask;
+ OptionButton *emission_mask_mode;
+ CheckBox *emission_colors;
+
+ String source_emission_file;
+
+ UndoRedo *undo_redo;
+ void _file_selected(const String &p_file);
+ void _menu_callback(int p_idx);
+ void _generate_visibility_rect();
+ void _generate_emission_mask();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ virtual String get_name() const { return "GPUParticles2D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ GPUParticles2DEditorPlugin(EditorNode *p_node);
+ ~GPUParticles2DEditorPlugin();
+};
+
+#endif // PARTICLES_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..7f80acc176
--- /dev/null
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -0,0 +1,490 @@
+/*************************************************************************/
+/* gpu_particles_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "gpu_particles_3d_editor_plugin.h"
+
+#include "core/io/resource_loader.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/cpu_particles_3d.h"
+#include "scene/resources/particles_material.h"
+
+bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) {
+
+ bool use_normals = emission_fill->get_selected() == 1;
+
+ if (emission_fill->get_selected() < 2) {
+
+ float area_accum = 0;
+ Map<float, int> triangle_area_map;
+
+ for (int i = 0; i < geometry.size(); i++) {
+
+ float area = geometry[i].get_area();
+ if (area < CMP_EPSILON)
+ continue;
+ triangle_area_map[area_accum] = i;
+ area_accum += area;
+ }
+
+ if (!triangle_area_map.size() || area_accum == 0) {
+
+ EditorNode::get_singleton()->show_warning(TTR("The geometry's faces don't contain any area."));
+ return false;
+ }
+
+ int emissor_count = emission_amount->get_value();
+
+ for (int i = 0; i < emissor_count; i++) {
+
+ float areapos = Math::random(0.0f, area_accum);
+
+ Map<float, int>::Element *E = triangle_area_map.find_closest(areapos);
+ ERR_FAIL_COND_V(!E, false);
+ int index = E->get();
+ ERR_FAIL_INDEX_V(index, geometry.size(), false);
+
+ // ok FINALLY get face
+ Face3 face = geometry[index];
+ //now compute some position inside the face...
+
+ Vector3 pos = face.get_random_point_inside();
+
+ points.push_back(pos);
+
+ if (use_normals) {
+ Vector3 normal = face.get_plane().normal;
+ normals.push_back(normal);
+ }
+ }
+ } else {
+
+ int gcount = geometry.size();
+
+ if (gcount == 0) {
+
+ EditorNode::get_singleton()->show_warning(TTR("The geometry doesn't contain any faces."));
+ return false;
+ }
+
+ const Face3 *r = geometry.ptr();
+
+ AABB aabb;
+
+ for (int i = 0; i < gcount; i++) {
+
+ for (int j = 0; j < 3; j++) {
+
+ if (i == 0 && j == 0)
+ aabb.position = r[i].vertex[j];
+ else
+ aabb.expand_to(r[i].vertex[j]);
+ }
+ }
+
+ int emissor_count = emission_amount->get_value();
+
+ for (int i = 0; i < emissor_count; i++) {
+
+ int attempts = 5;
+
+ for (int j = 0; j < attempts; j++) {
+
+ Vector3 dir;
+ dir[Math::rand() % 3] = 1.0;
+ Vector3 ofs = (Vector3(1, 1, 1) - dir) * Vector3(Math::randf(), Math::randf(), Math::randf()) * aabb.size + aabb.position;
+
+ Vector3 ofsv = ofs + aabb.size * dir;
+
+ //space it a little
+ ofs -= dir;
+ ofsv += dir;
+
+ float max = -1e7, min = 1e7;
+
+ for (int k = 0; k < gcount; k++) {
+
+ const Face3 &f3 = r[k];
+
+ Vector3 res;
+ if (f3.intersects_segment(ofs, ofsv, &res)) {
+
+ res -= ofs;
+ float d = dir.dot(res);
+
+ if (d < min)
+ min = d;
+ if (d > max)
+ max = d;
+ }
+ }
+
+ if (max < min)
+ continue; //lost attempt
+
+ float val = min + (max - min) * Math::randf();
+
+ Vector3 point = ofs + dir * val;
+
+ points.push_back(point);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+void GPUParticles3DEditorBase::_node_selected(const NodePath &p_path) {
+
+ Node *sel = get_node(p_path);
+ if (!sel)
+ return;
+
+ if (!sel->is_class("Node3D")) {
+
+ EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't inherit from Node3D."), sel->get_name()));
+ return;
+ }
+
+ VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sel);
+ if (!vi) {
+
+ EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain geometry."), sel->get_name()));
+ return;
+ }
+
+ geometry = vi->get_faces(VisualInstance3D::FACES_SOLID);
+
+ if (geometry.size() == 0) {
+
+ EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain face geometry."), sel->get_name()));
+ return;
+ }
+
+ Transform geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform();
+
+ int gc = geometry.size();
+ Face3 *w = geometry.ptrw();
+
+ for (int i = 0; i < gc; i++) {
+ for (int j = 0; j < 3; j++) {
+ w[i].vertex[j] = geom_xform.xform(w[i].vertex[j]);
+ }
+ }
+
+ emission_dialog->popup_centered(Size2(300, 130));
+}
+
+void GPUParticles3DEditorBase::_bind_methods() {
+}
+
+GPUParticles3DEditorBase::GPUParticles3DEditorBase() {
+
+ emission_dialog = memnew(ConfirmationDialog);
+ emission_dialog->set_title(TTR("Create Emitter"));
+ add_child(emission_dialog);
+ VBoxContainer *emd_vb = memnew(VBoxContainer);
+ emission_dialog->add_child(emd_vb);
+
+ emission_amount = memnew(SpinBox);
+ emission_amount->set_min(1);
+ emission_amount->set_max(100000);
+ emission_amount->set_value(512);
+ emd_vb->add_margin_child(TTR("Emission Points:"), emission_amount);
+
+ emission_fill = memnew(OptionButton);
+ emission_fill->add_item(TTR("Surface Points"));
+ emission_fill->add_item(TTR("Surface Points+Normal (Directed)"));
+ emission_fill->add_item(TTR("Volume"));
+ emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill);
+
+ emission_dialog->get_ok()->set_text(TTR("Create"));
+ emission_dialog->connect("confirmed", callable_mp(this, &GPUParticles3DEditorBase::_generate_emission_points));
+
+ emission_tree_dialog = memnew(SceneTreeDialog);
+ add_child(emission_tree_dialog);
+ emission_tree_dialog->connect("selected", callable_mp(this, &GPUParticles3DEditorBase::_node_selected));
+}
+
+void GPUParticles3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ hide();
+ }
+}
+
+void GPUParticles3DEditor::_notification(int p_notification) {
+
+ if (p_notification == NOTIFICATION_ENTER_TREE) {
+ options->set_icon(options->get_popup()->get_theme_icon("GPUParticles3D", "EditorIcons"));
+ get_tree()->connect("node_removed", callable_mp(this, &GPUParticles3DEditor::_node_removed));
+ }
+}
+
+void GPUParticles3DEditor::_menu_option(int p_option) {
+
+ switch (p_option) {
+
+ case MENU_OPTION_GENERATE_AABB: {
+ float gen_time = node->get_lifetime();
+
+ if (gen_time < 1.0)
+ generate_seconds->set_value(1.0);
+ else
+ generate_seconds->set_value(trunc(gen_time) + 1.0);
+ generate_aabb->popup_centered();
+ } break;
+ case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
+ Ref<ParticlesMaterial> material = node->get_process_material();
+ if (material.is_null()) {
+ EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+ return;
+ }
+
+ emission_tree_dialog->popup_centered_ratio();
+
+ } break;
+ case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
+
+ CPUParticles3D *cpu_particles = memnew(CPUParticles3D);
+ cpu_particles->convert_from_particles(node);
+ 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());
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Convert to CPUParticles3D"));
+ ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, cpu_particles, true, false);
+ ur->add_do_reference(cpu_particles);
+ ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, node, false, false);
+ ur->add_undo_reference(node);
+ ur->commit_action();
+
+ } break;
+ case MENU_OPTION_RESTART: {
+
+ node->restart();
+
+ } break;
+ }
+}
+
+void GPUParticles3DEditor::_generate_aabb() {
+
+ float time = generate_seconds->get_value();
+
+ float running = 0.0;
+
+ EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
+
+ bool was_emitting = node->is_emitting();
+ if (!was_emitting) {
+ node->set_emitting(true);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ AABB rect;
+
+ while (running < time) {
+
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec();
+ ep.step("Generating...", int(running), true);
+ OS::get_singleton()->delay_usec(1000);
+
+ AABB capture = node->capture_aabb();
+ if (rect == AABB())
+ rect = capture;
+ else
+ rect.merge_with(capture);
+
+ running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
+ }
+
+ if (!was_emitting) {
+ node->set_emitting(false);
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Generate Visibility AABB"));
+ ur->add_do_method(node, "set_visibility_aabb", rect);
+ ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
+ ur->commit_action();
+}
+
+void GPUParticles3DEditor::edit(GPUParticles3D *p_particles) {
+
+ base_node = p_particles;
+ node = p_particles;
+}
+
+void GPUParticles3DEditor::_generate_emission_points() {
+
+ /// hacer codigo aca
+ Vector<Vector3> points;
+ Vector<Vector3> normals;
+
+ if (!_generate(points, normals)) {
+ return;
+ }
+
+ int point_count = points.size();
+
+ int w = 2048;
+ int h = (point_count / 2048) + 1;
+
+ Vector<uint8_t> point_img;
+ point_img.resize(w * h * 3 * sizeof(float));
+
+ {
+ uint8_t *iw = point_img.ptrw();
+ zeromem(iw, w * h * 3 * sizeof(float));
+ const Vector3 *r = points.ptr();
+ float *wf = (float *)iw;
+ for (int i = 0; i < point_count; i++) {
+ wf[i * 3 + 0] = r[i].x;
+ wf[i * 3 + 1] = r[i].y;
+ wf[i * 3 + 2] = r[i].z;
+ }
+ }
+
+ Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
+
+ Ref<ImageTexture> tex;
+ tex.instance();
+
+ Ref<ParticlesMaterial> material = node->get_process_material();
+ ERR_FAIL_COND(material.is_null());
+
+ if (normals.size() > 0) {
+
+ material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+ material->set_emission_point_count(point_count);
+ material->set_emission_point_texture(tex);
+
+ Vector<uint8_t> point_img2;
+ point_img2.resize(w * h * 3 * sizeof(float));
+
+ {
+ uint8_t *iw = point_img2.ptrw();
+ zeromem(iw, w * h * 3 * sizeof(float));
+ const Vector3 *r = normals.ptr();
+ float *wf = (float *)iw;
+ for (int i = 0; i < point_count; i++) {
+ wf[i * 3 + 0] = r[i].x;
+ wf[i * 3 + 1] = r[i].y;
+ wf[i * 3 + 2] = r[i].z;
+ }
+ }
+
+ Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
+
+ Ref<ImageTexture> tex2;
+ tex2.instance();
+
+ material->set_emission_normal_texture(tex2);
+ } else {
+
+ material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+ material->set_emission_point_count(point_count);
+ material->set_emission_point_texture(tex);
+ }
+}
+
+void GPUParticles3DEditor::_bind_methods() {
+}
+
+GPUParticles3DEditor::GPUParticles3DEditor() {
+
+ node = nullptr;
+ particles_editor_hb = memnew(HBoxContainer);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
+ options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
+ particles_editor_hb->add_child(options);
+ particles_editor_hb->hide();
+
+ options->set_text(TTR("GPUParticles3D"));
+ options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART);
+ options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB);
+ options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
+ options->get_popup()->add_item(TTR("Convert to CPUParticles3D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
+
+ options->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles3DEditor::_menu_option));
+
+ generate_aabb = memnew(ConfirmationDialog);
+ generate_aabb->set_title(TTR("Generate Visibility AABB"));
+ VBoxContainer *genvb = memnew(VBoxContainer);
+ generate_aabb->add_child(genvb);
+ generate_seconds = memnew(SpinBox);
+ genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
+ generate_seconds->set_min(0.1);
+ generate_seconds->set_max(25);
+ generate_seconds->set_value(2);
+
+ add_child(generate_aabb);
+
+ generate_aabb->connect("confirmed", callable_mp(this, &GPUParticles3DEditor::_generate_aabb));
+}
+
+void GPUParticles3DEditorPlugin::edit(Object *p_object) {
+
+ particles_editor->edit(Object::cast_to<GPUParticles3D>(p_object));
+}
+
+bool GPUParticles3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("GPUParticles3D");
+}
+
+void GPUParticles3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ particles_editor->show();
+ particles_editor->particles_editor_hb->show();
+ } else {
+ particles_editor->particles_editor_hb->hide();
+ particles_editor->hide();
+ particles_editor->edit(nullptr);
+ }
+}
+
+GPUParticles3DEditorPlugin::GPUParticles3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ particles_editor = memnew(GPUParticles3DEditor);
+ editor->get_viewport()->add_child(particles_editor);
+
+ particles_editor->hide();
+}
+
+GPUParticles3DEditorPlugin::~GPUParticles3DEditorPlugin() {
+}
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.h b/editor/plugins/gpu_particles_3d_editor_plugin.h
new file mode 100644
index 0000000000..cf1cff32c0
--- /dev/null
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.h
@@ -0,0 +1,121 @@
+/*************************************************************************/
+/* gpu_particles_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PARTICLES_EDITOR_PLUGIN_H
+#define PARTICLES_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/gpu_particles_3d.h"
+#include "scene/gui/spin_box.h"
+
+class GPUParticles3DEditorBase : public Control {
+
+ GDCLASS(GPUParticles3DEditorBase, Control);
+
+protected:
+ Node3D *base_node;
+ Panel *panel;
+ MenuButton *options;
+ HBoxContainer *particles_editor_hb;
+
+ SceneTreeDialog *emission_tree_dialog;
+
+ ConfirmationDialog *emission_dialog;
+ SpinBox *emission_amount;
+ OptionButton *emission_fill;
+
+ Vector<Face3> geometry;
+
+ bool _generate(Vector<Vector3> &points, Vector<Vector3> &normals);
+ virtual void _generate_emission_points() = 0;
+ void _node_selected(const NodePath &p_path);
+
+ static void _bind_methods();
+
+public:
+ GPUParticles3DEditorBase();
+};
+
+class GPUParticles3DEditor : public GPUParticles3DEditorBase {
+
+ GDCLASS(GPUParticles3DEditor, GPUParticles3DEditorBase);
+
+ ConfirmationDialog *generate_aabb;
+ SpinBox *generate_seconds;
+ GPUParticles3D *node;
+
+ enum Menu {
+
+ MENU_OPTION_GENERATE_AABB,
+ MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
+ MENU_OPTION_CLEAR_EMISSION_VOLUME,
+ MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
+ MENU_OPTION_RESTART,
+
+ };
+
+ void _generate_aabb();
+
+ void _menu_option(int);
+
+ friend class GPUParticles3DEditorPlugin;
+
+ virtual void _generate_emission_points();
+
+protected:
+ void _notification(int p_notification);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ void edit(GPUParticles3D *p_particles);
+ GPUParticles3DEditor();
+};
+
+class GPUParticles3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(GPUParticles3DEditorPlugin, EditorPlugin);
+
+ GPUParticles3DEditor *particles_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const { return "GPUParticles3D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ GPUParticles3DEditorPlugin(EditorNode *p_node);
+ ~GPUParticles3DEditorPlugin();
+};
+
+#endif // PARTICLES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index ff03fcf159..67de610ae7 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -32,7 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "editor/editor_scale.h"
-#include "spatial_editor_plugin.h"
+#include "node_3d_editor_plugin.h"
Size2 GradientEditor::get_minimum_size() const {
return Size2(0, 60) * EDSCALE;
@@ -79,7 +79,7 @@ GradientEditor::GradientEditor() {
bool EditorInspectorPluginGradient::can_handle(Object *p_object) {
- return Object::cast_to<Gradient>(p_object) != NULL;
+ return Object::cast_to<Gradient>(p_object) != nullptr;
}
void EditorInspectorPluginGradient::parse_begin(Object *p_object) {
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index ba640883c7..1dbc78804b 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -163,7 +163,7 @@ void ItemListOptionButtonPlugin::erase(int p_idx) {
ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() {
- ob = NULL;
+ ob = nullptr;
}
///////////////////////////////////////////////////////////////
@@ -205,7 +205,7 @@ void ItemListPopupMenuPlugin::erase(int p_idx) {
ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
- pp = NULL;
+ pp = nullptr;
}
///////////////////////////////////////////////////////////////
@@ -244,7 +244,7 @@ void ItemListItemListPlugin::erase(int p_idx) {
ItemListItemListPlugin::ItemListItemListPlugin() {
- pp = NULL;
+ pp = nullptr;
}
///////////////////////////////////////////////////////////////
@@ -254,7 +254,7 @@ ItemListItemListPlugin::ItemListItemListPlugin() {
void ItemListEditor::_node_removed(Node *p_node) {
if (p_node == item_list) {
- item_list = NULL;
+ item_list = nullptr;
hide();
dialog->hide();
}
@@ -264,8 +264,8 @@ void ItemListEditor::_notification(int p_notification) {
if (p_notification == NOTIFICATION_ENTER_TREE || p_notification == NOTIFICATION_THEME_CHANGED) {
- add_button->set_icon(get_icon("Add", "EditorIcons"));
- del_button->set_icon(get_icon("Remove", "EditorIcons"));
+ add_button->set_icon(get_theme_icon("Add", "EditorIcons"));
+ del_button->set_icon(get_theme_icon("Remove", "EditorIcons"));
} else if (p_notification == NOTIFICATION_READY) {
get_tree()->connect("node_removed", callable_mp(this, &ItemListEditor::_node_removed));
@@ -311,7 +311,7 @@ void ItemListEditor::edit(Node *p_item_list) {
if (!item_list) {
selected_idx = -1;
- property_editor->edit(NULL);
+ property_editor->edit(nullptr);
return;
}
@@ -329,7 +329,7 @@ void ItemListEditor::edit(Node *p_item_list) {
}
selected_idx = -1;
- property_editor->edit(NULL);
+ property_editor->edit(nullptr);
}
bool ItemListEditor::handles(Object *p_object) const {
@@ -349,7 +349,7 @@ void ItemListEditor::_bind_methods() {
ItemListEditor::ItemListEditor() {
selected_idx = -1;
- item_list = NULL;
+ item_list = nullptr;
toolbar_button = memnew(ToolButton);
toolbar_button->set_text(TTR("Items"));
@@ -408,7 +408,7 @@ void ItemListEditorPlugin::make_visible(bool p_visible) {
} else {
item_list_editor->hide();
- item_list_editor->edit(NULL);
+ item_list_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index 22df287f97..f8550a884b 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -112,7 +112,7 @@ void LightOccluder2DEditor::_create_resource() {
LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) :
AbstractPolygon2DEditor(p_editor) {
- node = NULL;
+ node = nullptr;
}
LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) :
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index 4ac9d0af3b..5b887390a6 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -64,7 +64,7 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con
Line2DEditor::Line2DEditor(EditorNode *p_editor) :
AbstractPolygon2DEditor(p_editor) {
- node = NULL;
+ node = nullptr;
}
Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) :
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index b39465f618..eb14495b9c 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -31,8 +31,9 @@
#include "material_editor_plugin.h"
#include "editor/editor_scale.h"
-#include "scene/gui/viewport_container.h"
+#include "scene/gui/subviewport_container.h"
#include "scene/resources/particles_material.h"
+#include "scene/resources/sky_material.h"
void MaterialEditor::_notification(int p_what) {
@@ -43,15 +44,15 @@ void MaterialEditor::_notification(int p_what) {
if (first_enter) {
//it's in propertyeditor so.. could be moved around
- light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1", "EditorIcons"));
- light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off", "EditorIcons"));
- light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2", "EditorIcons"));
- light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off", "EditorIcons"));
+ light_1_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight1", "EditorIcons"));
+ light_1_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight1Off", "EditorIcons"));
+ light_2_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight2", "EditorIcons"));
+ light_2_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight2Off", "EditorIcons"));
- sphere_switch->set_normal_texture(get_icon("MaterialPreviewSphereOff", "EditorIcons"));
- sphere_switch->set_pressed_texture(get_icon("MaterialPreviewSphere", "EditorIcons"));
- box_switch->set_normal_texture(get_icon("MaterialPreviewCubeOff", "EditorIcons"));
- box_switch->set_pressed_texture(get_icon("MaterialPreviewCube", "EditorIcons"));
+ sphere_switch->set_normal_texture(get_theme_icon("MaterialPreviewSphereOff", "EditorIcons"));
+ sphere_switch->set_pressed_texture(get_theme_icon("MaterialPreviewSphere", "EditorIcons"));
+ box_switch->set_normal_texture(get_theme_icon("MaterialPreviewCubeOff", "EditorIcons"));
+ box_switch->set_pressed_texture(get_theme_icon("MaterialPreviewCube", "EditorIcons"));
first_enter = false;
}
@@ -59,7 +60,7 @@ void MaterialEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<Texture2D> checkerboard = get_icon("Checkerboard", "EditorIcons");
+ Ref<Texture2D> checkerboard = get_theme_icon("Checkerboard", "EditorIcons");
Size2 size = get_size();
draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
@@ -94,6 +95,7 @@ void MaterialEditor::_button_pressed(Node *p_button) {
sphere_instance->hide();
box_switch->set_pressed(true);
sphere_switch->set_pressed(false);
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false);
}
if (p_button == sphere_switch) {
@@ -101,6 +103,7 @@ void MaterialEditor::_button_pressed(Node *p_button) {
sphere_instance->show();
box_switch->set_pressed(false);
sphere_switch->set_pressed(true);
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true);
}
}
@@ -109,12 +112,12 @@ void MaterialEditor::_bind_methods() {
MaterialEditor::MaterialEditor() {
- vc = memnew(ViewportContainer);
+ vc = memnew(SubViewportContainer);
vc->set_stretch(true);
add_child(vc);
vc->set_anchors_and_margins_preset(PRESET_WIDE);
- viewport = memnew(Viewport);
- Ref<World> world;
+ viewport = memnew(SubViewport);
+ Ref<World3D> world;
world.instance();
viewport->set_world(world); //use own world
vc->add_child(viewport);
@@ -122,25 +125,25 @@ MaterialEditor::MaterialEditor() {
viewport->set_transparent_background(true);
viewport->set_msaa(Viewport::MSAA_4X);
- camera = memnew(Camera);
+ camera = memnew(Camera3D);
camera->set_transform(Transform(Basis(), Vector3(0, 0, 3)));
camera->set_perspective(45, 0.1, 10);
camera->make_current();
viewport->add_child(camera);
- light1 = memnew(DirectionalLight);
+ light1 = memnew(DirectionalLight3D);
light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
- light2 = memnew(DirectionalLight);
+ light2 = memnew(DirectionalLight3D);
light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
light2->set_color(Color(0.7, 0.7, 0.7));
viewport->add_child(light2);
- sphere_instance = memnew(MeshInstance);
+ sphere_instance = memnew(MeshInstance3D);
viewport->add_child(sphere_instance);
- box_instance = memnew(MeshInstance);
+ box_instance = memnew(MeshInstance3D);
viewport->add_child(box_instance);
Transform box_xform;
@@ -154,7 +157,6 @@ MaterialEditor::MaterialEditor() {
sphere_instance->set_mesh(sphere_mesh);
box_mesh.instance();
box_instance->set_mesh(box_mesh);
- box_instance->hide();
set_custom_minimum_size(Size2(1, 150) * EDSCALE);
@@ -193,6 +195,15 @@ MaterialEditor::MaterialEditor() {
light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed), varray(light_2_switch));
first_enter = true;
+
+ if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
+ box_instance->hide();
+ } else {
+ box_instance->show();
+ sphere_instance->hide();
+ box_switch->set_pressed(true);
+ sphere_switch->set_pressed(false);
+ }
}
///////////////////////
@@ -221,8 +232,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
env.instance();
- Ref<ProceduralSky> proc_sky = memnew(ProceduralSky(true));
- env->set_sky(proc_sky);
+ Ref<Sky> sky = memnew(Sky());
+ env->set_sky(sky);
env->set_background(Environment::BG_COLOR);
env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY);
env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY);
@@ -255,14 +266,14 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
Ref<Shader> shader;
shader.instance();
- String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
shader->set_code(code);
smat->set_shader(shader);
List<PropertyInfo> params;
- VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
@@ -272,7 +283,7 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
if (texture.is_valid()) {
smat->set_shader_param(E->get().name, texture);
} else {
- Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
smat->set_shader_param(E->get().name, value);
}
}
@@ -301,17 +312,17 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_
Ref<Shader> shader;
shader.instance();
- String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
shader->set_code(code);
smat->set_shader(shader);
List<PropertyInfo> params;
- VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
- Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
smat->set_shader_param(E->get().name, value);
}
@@ -339,17 +350,131 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
Ref<Shader> shader;
shader.instance();
- String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid());
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+ shader->set_code(code);
+
+ smat->set_shader(shader);
+
+ List<PropertyInfo> params;
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+ for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ smat->set_shader_param(E->get().name, value);
+ }
+
+ smat->set_render_priority(mat->get_render_priority());
+ return smat;
+}
+
+String ProceduralSkyMaterialConversionPlugin::converts_to() const {
+
+ return "ShaderMaterial";
+}
+bool ProceduralSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+
+ Ref<ProceduralSkyMaterial> mat = p_resource;
+ return mat.is_valid();
+}
+Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+
+ Ref<ProceduralSkyMaterial> mat = p_resource;
+ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+ Ref<ShaderMaterial> smat;
+ smat.instance();
+
+ Ref<Shader> shader;
+ shader.instance();
+
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+ shader->set_code(code);
+
+ smat->set_shader(shader);
+
+ List<PropertyInfo> params;
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+ for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ smat->set_shader_param(E->get().name, value);
+ }
+
+ smat->set_render_priority(mat->get_render_priority());
+ return smat;
+}
+
+String PanoramaSkyMaterialConversionPlugin::converts_to() const {
+
+ return "ShaderMaterial";
+}
+bool PanoramaSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+
+ Ref<PanoramaSkyMaterial> mat = p_resource;
+ return mat.is_valid();
+}
+Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+
+ Ref<PanoramaSkyMaterial> mat = p_resource;
+ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+ Ref<ShaderMaterial> smat;
+ smat.instance();
+
+ Ref<Shader> shader;
+ shader.instance();
+
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+ shader->set_code(code);
+
+ smat->set_shader(shader);
+
+ List<PropertyInfo> params;
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+ for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ smat->set_shader_param(E->get().name, value);
+ }
+
+ smat->set_render_priority(mat->get_render_priority());
+ return smat;
+}
+
+String PhysicalSkyMaterialConversionPlugin::converts_to() const {
+
+ return "ShaderMaterial";
+}
+bool PhysicalSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+
+ Ref<PhysicalSkyMaterial> mat = p_resource;
+ return mat.is_valid();
+}
+Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+
+ Ref<PhysicalSkyMaterial> mat = p_resource;
+ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+ Ref<ShaderMaterial> smat;
+ smat.instance();
+
+ Ref<Shader> shader;
+ shader.instance();
+
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
shader->set_code(code);
smat->set_shader(shader);
List<PropertyInfo> params;
- VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) {
- Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name);
smat->set_shader_param(E->get().name, value);
}
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index 95a6c4bf8f..50036e4f72 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -36,24 +36,24 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/light.h"
-#include "scene/3d/mesh_instance.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/material.h"
-class ViewportContainer;
+class SubViewportContainer;
class MaterialEditor : public Control {
GDCLASS(MaterialEditor, Control);
- ViewportContainer *vc;
- Viewport *viewport;
- MeshInstance *sphere_instance;
- MeshInstance *box_instance;
- DirectionalLight *light1;
- DirectionalLight *light2;
- Camera *camera;
+ SubViewportContainer *vc;
+ SubViewport *viewport;
+ MeshInstance3D *sphere_instance;
+ MeshInstance3D *box_instance;
+ DirectionalLight3D *light1;
+ DirectionalLight3D *light2;
+ Camera3D *camera;
Ref<SphereMesh> sphere_mesh;
Ref<CubeMesh> box_mesh;
@@ -127,4 +127,31 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const;
};
+class ProceduralSkyMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(ProceduralSkyMaterialConversionPlugin, EditorResourceConversionPlugin);
+
+public:
+ virtual String converts_to() const;
+ virtual bool handles(const Ref<Resource> &p_resource) const;
+ virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const;
+};
+
+class PanoramaSkyMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(PanoramaSkyMaterialConversionPlugin, EditorResourceConversionPlugin);
+
+public:
+ virtual String converts_to() const;
+ virtual bool handles(const Ref<Resource> &p_resource) const;
+ virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const;
+};
+
+class PhysicalSkyMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(PhysicalSkyMaterialConversionPlugin, EditorResourceConversionPlugin);
+
+public:
+ virtual String converts_to() const;
+ virtual bool handles(const Ref<Resource> &p_resource) const;
+ virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const;
+};
+
#endif // MATERIAL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 5a17f0d4f1..5e657c3b71 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -57,10 +57,10 @@ void MeshEditor::_notification(int p_what) {
if (first_enter) {
//it's in propertyeditor so. could be moved around
- light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1", "EditorIcons"));
- light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off", "EditorIcons"));
- light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2", "EditorIcons"));
- light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off", "EditorIcons"));
+ light_1_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight1", "EditorIcons"));
+ light_1_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight1Off", "EditorIcons"));
+ light_2_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight2", "EditorIcons"));
+ light_2_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight2Off", "EditorIcons"));
first_enter = false;
}
}
@@ -115,31 +115,31 @@ void MeshEditor::_bind_methods() {
MeshEditor::MeshEditor() {
- viewport = memnew(Viewport);
- Ref<World> world;
+ viewport = memnew(SubViewport);
+ Ref<World3D> world;
world.instance();
viewport->set_world(world); //use own world
add_child(viewport);
viewport->set_disable_input(true);
viewport->set_msaa(Viewport::MSAA_2X);
set_stretch(true);
- camera = memnew(Camera);
+ camera = memnew(Camera3D);
camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1)));
camera->set_perspective(45, 0.1, 10);
viewport->add_child(camera);
- light1 = memnew(DirectionalLight);
+ light1 = memnew(DirectionalLight3D);
light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
- light2 = memnew(DirectionalLight);
+ light2 = memnew(DirectionalLight3D);
light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1)));
light2->set_color(Color(0.7, 0.7, 0.7));
viewport->add_child(light2);
- rotation = memnew(Spatial);
+ rotation = memnew(Node3D);
viewport->add_child(rotation);
- mesh_instance = memnew(MeshInstance);
+ mesh_instance = memnew(MeshInstance3D);
rotation->add_child(mesh_instance);
set_custom_minimum_size(Size2(1, 150) * EDSCALE);
@@ -173,7 +173,7 @@ MeshEditor::MeshEditor() {
bool EditorInspectorPluginMesh::can_handle(Object *p_object) {
- return Object::cast_to<Mesh>(p_object) != NULL;
+ return Object::cast_to<Mesh>(p_object) != nullptr;
}
void EditorInspectorPluginMesh::parse_begin(Object *p_object) {
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index 87c4a1776b..072e21f260 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -33,25 +33,25 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/light.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/gui/viewport_container.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/subviewport_container.h"
#include "scene/resources/material.h"
-class MeshEditor : public ViewportContainer {
+class MeshEditor : public SubViewportContainer {
- GDCLASS(MeshEditor, ViewportContainer);
+ GDCLASS(MeshEditor, SubViewportContainer);
float rot_x;
float rot_y;
- Viewport *viewport;
- MeshInstance *mesh_instance;
- Spatial *rotation;
- DirectionalLight *light1;
- DirectionalLight *light2;
- Camera *camera;
+ SubViewport *viewport;
+ MeshInstance3D *mesh_instance;
+ Node3D *rotation;
+ DirectionalLight3D *light1;
+ DirectionalLight3D *light2;
+ Camera3D *camera;
Ref<Mesh> mesh;
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..7819f62bc7
--- /dev/null
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -0,0 +1,528 @@
+/*************************************************************************/
+/* mesh_instance_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "mesh_instance_3d_editor_plugin.h"
+
+#include "editor/editor_scale.h"
+#include "node_3d_editor_plugin.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/gui/box_container.h"
+
+void MeshInstance3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ options->hide();
+ }
+}
+
+void MeshInstance3DEditor::edit(MeshInstance3D *p_mesh) {
+
+ node = p_mesh;
+}
+
+void MeshInstance3DEditor::_menu_option(int p_option) {
+
+ Ref<Mesh> mesh = node->get_mesh();
+ if (mesh.is_null()) {
+ err_dialog->set_text(TTR("Mesh is empty!"));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ switch (p_option) {
+ case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
+
+ EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ if (selection.empty()) {
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
+ if (shape.is_null()) {
+ err_dialog->set_text(TTR("Couldn't create a Trimesh collision shape."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shape);
+ StaticBody3D *body = memnew(StaticBody3D);
+ body->add_child(cshape);
+
+ Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
+
+ ur->create_action(TTR("Create Static Trimesh Body"));
+ ur->add_do_method(node, "add_child", body);
+ ur->add_do_method(body, "set_owner", owner);
+ ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_reference(body);
+ ur->add_undo_method(node, "remove_child", body);
+ ur->commit_action();
+ return;
+ }
+
+ ur->create_action(TTR("Create Static Trimesh Body"));
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ MeshInstance3D *instance = Object::cast_to<MeshInstance3D>(E->get());
+ if (!instance)
+ continue;
+
+ Ref<Mesh> m = instance->get_mesh();
+ if (m.is_null())
+ continue;
+
+ Ref<Shape3D> shape = m->create_trimesh_shape();
+ if (shape.is_null())
+ continue;
+
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shape);
+ StaticBody3D *body = memnew(StaticBody3D);
+ body->add_child(cshape);
+
+ Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner();
+
+ ur->add_do_method(instance, "add_child", body);
+ ur->add_do_method(body, "set_owner", owner);
+ ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_reference(body);
+ ur->add_undo_method(instance, "remove_child", body);
+ }
+
+ ur->commit_action();
+
+ } break;
+
+ case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: {
+
+ if (node == get_tree()->get_edited_scene_root()) {
+ err_dialog->set_text(TTR("This doesn't work on scene root!"));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
+ if (shape.is_null())
+ return;
+
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shape);
+
+ Node *owner = node->get_owner();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action(TTR("Create Trimesh Static Shape"));
+
+ ur->add_do_method(node->get_parent(), "add_child", cshape);
+ ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
+ ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_reference(cshape);
+ ur->add_undo_method(node->get_parent(), "remove_child", cshape);
+ ur->commit_action();
+ } break;
+ case MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE: {
+
+ if (node == get_tree()->get_edited_scene_root()) {
+ err_dialog->set_text(TTR("Can't create a single convex collision shape for the scene root."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Ref<Shape3D> shape = mesh->create_convex_shape();
+
+ if (shape.is_null()) {
+ err_dialog->set_text(TTR("Couldn't create a single convex collision shape."));
+ err_dialog->popup_centered();
+ return;
+ }
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action(TTR("Create Single Convex Shape"));
+
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shape);
+ cshape->set_transform(node->get_transform());
+
+ Node *owner = node->get_owner();
+
+ ur->add_do_method(node->get_parent(), "add_child", cshape);
+ ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
+ ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_reference(cshape);
+ ur->add_undo_method(node->get_parent(), "remove_child", cshape);
+
+ ur->commit_action();
+
+ } break;
+ case MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES: {
+
+ if (node == get_tree()->get_edited_scene_root()) {
+ err_dialog->set_text(TTR("Can't create multiple convex collision shapes for the scene root."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+
+ if (!shapes.size()) {
+ err_dialog->set_text(TTR("Couldn't create any collision shapes."));
+ err_dialog->popup_centered();
+ return;
+ }
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action(TTR("Create Multiple Convex Shapes"));
+
+ for (int i = 0; i < shapes.size(); i++) {
+
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shapes[i]);
+ cshape->set_transform(node->get_transform());
+
+ Node *owner = node->get_owner();
+
+ ur->add_do_method(node->get_parent(), "add_child", cshape);
+ ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
+ ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_reference(cshape);
+ ur->add_undo_method(node->get_parent(), "remove_child", cshape);
+ }
+ ur->commit_action();
+
+ } break;
+
+ case MENU_OPTION_CREATE_NAVMESH: {
+
+ Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
+
+ if (nmesh.is_null())
+ return;
+
+ nmesh->create_from_mesh(mesh);
+ NavigationRegion3D *nmi = memnew(NavigationRegion3D);
+ nmi->set_navigation_mesh(nmesh);
+
+ Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create Navigation Mesh"));
+
+ ur->add_do_method(node, "add_child", nmi);
+ ur->add_do_method(nmi, "set_owner", owner);
+
+ ur->add_do_reference(nmi);
+ ur->add_undo_method(node, "remove_child", nmi);
+ ur->commit_action();
+ } break;
+
+ case MENU_OPTION_CREATE_OUTLINE_MESH: {
+
+ outline_dialog->popup_centered(Vector2(200, 90));
+ } break;
+ case MENU_OPTION_CREATE_UV2: {
+
+ Ref<ArrayMesh> mesh2 = node->get_mesh();
+ if (!mesh2.is_valid()) {
+ err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Error err = mesh2->lightmap_unwrap(node->get_global_transform());
+ if (err != OK) {
+ err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?"));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ } break;
+ case MENU_OPTION_DEBUG_UV1: {
+ Ref<Mesh> mesh2 = node->get_mesh();
+ if (!mesh2.is_valid()) {
+ err_dialog->set_text(TTR("No mesh to debug."));
+ err_dialog->popup_centered();
+ return;
+ }
+ _create_uv_lines(0);
+ } break;
+ case MENU_OPTION_DEBUG_UV2: {
+ Ref<Mesh> mesh2 = node->get_mesh();
+ if (!mesh2.is_valid()) {
+ err_dialog->set_text(TTR("No mesh to debug."));
+ err_dialog->popup_centered();
+ return;
+ }
+ _create_uv_lines(1);
+ } break;
+ }
+}
+
+struct MeshInstance3DEditorEdgeSort {
+
+ Vector2 a;
+ Vector2 b;
+
+ bool operator<(const MeshInstance3DEditorEdgeSort &p_b) const {
+ if (a == p_b.a)
+ return b < p_b.b;
+ else
+ return a < p_b.a;
+ }
+
+ MeshInstance3DEditorEdgeSort() {}
+ MeshInstance3DEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) {
+ if (p_a < p_b) {
+ a = p_a;
+ b = p_b;
+ } else {
+ b = p_a;
+ a = p_b;
+ }
+ }
+};
+
+void MeshInstance3DEditor::_create_uv_lines(int p_layer) {
+
+ Ref<Mesh> mesh = node->get_mesh();
+ ERR_FAIL_COND(!mesh.is_valid());
+
+ Set<MeshInstance3DEditorEdgeSort> edges;
+ uv_lines.clear();
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
+ continue;
+ Array a = mesh->surface_get_arrays(i);
+
+ Vector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2];
+ if (uv.size() == 0) {
+ err_dialog->set_text(TTR("Model has no UV in this layer"));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ const Vector2 *r = uv.ptr();
+
+ Vector<int> indices = a[Mesh::ARRAY_INDEX];
+ const int *ri = nullptr;
+
+ int ic;
+
+ if (indices.size()) {
+ ic = indices.size();
+ ri = indices.ptr();
+ } else {
+ ic = uv.size();
+ }
+
+ for (int j = 0; j < ic; j += 3) {
+
+ for (int k = 0; k < 3; k++) {
+
+ MeshInstance3DEditorEdgeSort edge;
+ if (ri) {
+ edge.a = r[ri[j + k]];
+ edge.b = r[ri[j + ((k + 1) % 3)]];
+ } else {
+ edge.a = r[j + k];
+ edge.b = r[j + ((k + 1) % 3)];
+ }
+
+ if (edges.has(edge))
+ continue;
+
+ uv_lines.push_back(edge.a);
+ uv_lines.push_back(edge.b);
+ edges.insert(edge);
+ }
+ }
+ }
+
+ debug_uv_dialog->popup_centered();
+}
+
+void MeshInstance3DEditor::_debug_uv_draw() {
+
+ if (uv_lines.size() == 0)
+ return;
+
+ debug_uv->set_clip_contents(true);
+ debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0));
+ debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
+ debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7));
+}
+
+void MeshInstance3DEditor::_create_outline_mesh() {
+
+ Ref<Mesh> mesh = node->get_mesh();
+ if (mesh.is_null()) {
+ err_dialog->set_text(TTR("MeshInstance3D lacks a Mesh."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ if (mesh->get_surface_count() == 0) {
+ err_dialog->set_text(TTR("Mesh has not surface to create outlines from."));
+ err_dialog->popup_centered();
+ return;
+ } else if (mesh->get_surface_count() == 1 && mesh->surface_get_primitive_type(0) != Mesh::PRIMITIVE_TRIANGLES) {
+ err_dialog->set_text(TTR("Mesh primitive type is not PRIMITIVE_TRIANGLES."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Ref<Mesh> mesho = mesh->create_outline(outline_size->get_value());
+
+ if (mesho.is_null()) {
+ err_dialog->set_text(TTR("Could not create outline."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ MeshInstance3D *mi = memnew(MeshInstance3D);
+ mi->set_mesh(mesho);
+ Node *owner = node->get_owner();
+ if (get_tree()->get_edited_scene_root() == node) {
+ owner = node;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action(TTR("Create Outline"));
+
+ ur->add_do_method(node, "add_child", mi);
+ ur->add_do_method(mi, "set_owner", owner);
+
+ ur->add_do_reference(mi);
+ ur->add_undo_method(node, "remove_child", mi);
+ ur->commit_action();
+}
+
+void MeshInstance3DEditor::_bind_methods() {
+}
+
+MeshInstance3DEditor::MeshInstance3DEditor() {
+
+ options = memnew(MenuButton);
+ options->set_switch_on_hover(true);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
+
+ options->set_text(TTR("Mesh"));
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("MeshInstance3D", "EditorIcons"));
+
+ options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
+ options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
+ options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection."));
+ options->get_popup()->add_item(TTR("Create Single Convex Collision Sibling"), MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE);
+ options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection."));
+ options->get_popup()->add_item(TTR("Create Multiple Convex Collision Siblings"), MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES);
+ options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between the two above options."));
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item(TTR("Create Outline Mesh..."), MENU_OPTION_CREATE_OUTLINE_MESH);
+ options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a static outline mesh. The outline mesh will have its normals flipped automatically.\nThis can be used instead of the StandardMaterial Grow property when using that property isn't possible."));
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1);
+ options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2);
+ options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2);
+
+ options->get_popup()->connect("id_pressed", callable_mp(this, &MeshInstance3DEditor::_menu_option));
+
+ outline_dialog = memnew(ConfirmationDialog);
+ outline_dialog->set_title(TTR("Create Outline Mesh"));
+ outline_dialog->get_ok()->set_text(TTR("Create"));
+
+ VBoxContainer *outline_dialog_vbc = memnew(VBoxContainer);
+ outline_dialog->add_child(outline_dialog_vbc);
+ //outline_dialog->set_child_rect(outline_dialog_vbc);
+
+ outline_size = memnew(SpinBox);
+ outline_size->set_min(0.001);
+ outline_size->set_max(1024);
+ outline_size->set_step(0.001);
+ outline_size->set_value(0.05);
+ outline_dialog_vbc->add_margin_child(TTR("Outline Size:"), outline_size);
+
+ add_child(outline_dialog);
+ outline_dialog->connect("confirmed", callable_mp(this, &MeshInstance3DEditor::_create_outline_mesh));
+
+ err_dialog = memnew(AcceptDialog);
+ add_child(err_dialog);
+
+ debug_uv_dialog = memnew(AcceptDialog);
+ debug_uv_dialog->set_title(TTR("UV Channel Debug"));
+ add_child(debug_uv_dialog);
+ debug_uv = memnew(Control);
+ debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE);
+ debug_uv->connect("draw", callable_mp(this, &MeshInstance3DEditor::_debug_uv_draw));
+ debug_uv_dialog->add_child(debug_uv);
+}
+
+void MeshInstance3DEditorPlugin::edit(Object *p_object) {
+
+ mesh_editor->edit(Object::cast_to<MeshInstance3D>(p_object));
+}
+
+bool MeshInstance3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("MeshInstance3D");
+}
+
+void MeshInstance3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ mesh_editor->options->show();
+ } else {
+
+ mesh_editor->options->hide();
+ mesh_editor->edit(nullptr);
+ }
+}
+
+MeshInstance3DEditorPlugin::MeshInstance3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ mesh_editor = memnew(MeshInstance3DEditor);
+ editor->get_viewport()->add_child(mesh_editor);
+
+ mesh_editor->options->hide();
+}
+
+MeshInstance3DEditorPlugin::~MeshInstance3DEditorPlugin() {
+}
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h
new file mode 100644
index 0000000000..a5d90c42d5
--- /dev/null
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.h
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* mesh_instance_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 MESH_INSTANCE_EDITOR_PLUGIN_H
+#define MESH_INSTANCE_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/spin_box.h"
+
+class MeshInstance3DEditor : public Control {
+
+ GDCLASS(MeshInstance3DEditor, Control);
+
+ enum Menu {
+
+ MENU_OPTION_CREATE_STATIC_TRIMESH_BODY,
+ MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE,
+ MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE,
+ MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES,
+ MENU_OPTION_CREATE_NAVMESH,
+ MENU_OPTION_CREATE_OUTLINE_MESH,
+ MENU_OPTION_CREATE_UV2,
+ MENU_OPTION_DEBUG_UV1,
+ MENU_OPTION_DEBUG_UV2,
+ };
+
+ MeshInstance3D *node;
+
+ MenuButton *options;
+
+ ConfirmationDialog *outline_dialog;
+ SpinBox *outline_size;
+
+ AcceptDialog *err_dialog;
+
+ AcceptDialog *debug_uv_dialog;
+ Control *debug_uv;
+ Vector<Vector2> uv_lines;
+
+ void _menu_option(int p_option);
+ void _create_outline_mesh();
+
+ void _create_uv_lines(int p_layer);
+ friend class MeshInstance3DEditorPlugin;
+
+ void _debug_uv_draw();
+
+protected:
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ void edit(MeshInstance3D *p_mesh);
+ MeshInstance3DEditor();
+};
+
+class MeshInstance3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(MeshInstance3DEditorPlugin, EditorPlugin);
+
+ MeshInstance3DEditor *mesh_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const { return "MeshInstance3D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ MeshInstance3DEditorPlugin(EditorNode *p_node);
+ ~MeshInstance3DEditorPlugin();
+};
+
+#endif // MESH_EDITOR_PLUGIN_H
diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp
deleted file mode 100644
index e5b948aad7..0000000000
--- a/editor/plugins/mesh_instance_editor_plugin.cpp
+++ /dev/null
@@ -1,531 +0,0 @@
-/*************************************************************************/
-/* mesh_instance_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "mesh_instance_editor_plugin.h"
-
-#include "editor/editor_scale.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/navigation_region.h"
-#include "scene/3d/physics_body.h"
-#include "scene/gui/box_container.h"
-#include "spatial_editor_plugin.h"
-
-void MeshInstanceEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- options->hide();
- }
-}
-
-void MeshInstanceEditor::edit(MeshInstance *p_mesh) {
-
- node = p_mesh;
-}
-
-void MeshInstanceEditor::_menu_option(int p_option) {
-
- Ref<Mesh> mesh = node->get_mesh();
- if (mesh.is_null()) {
- err_dialog->set_text(TTR("Mesh is empty!"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- switch (p_option) {
- case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
-
- EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
-
- List<Node *> selection = editor_selection->get_selected_node_list();
-
- if (selection.empty()) {
- Ref<Shape> shape = mesh->create_trimesh_shape();
- if (shape.is_null()) {
- err_dialog->set_text(TTR("Couldn't create a Trimesh collision shape."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shape);
- StaticBody *body = memnew(StaticBody);
- body->add_child(cshape);
-
- Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
-
- ur->create_action(TTR("Create Static Trimesh Body"));
- ur->add_do_method(node, "add_child", body);
- ur->add_do_method(body, "set_owner", owner);
- ur->add_do_method(cshape, "set_owner", owner);
- ur->add_do_reference(body);
- ur->add_undo_method(node, "remove_child", body);
- ur->commit_action();
- return;
- }
-
- ur->create_action(TTR("Create Static Trimesh Body"));
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- MeshInstance *instance = Object::cast_to<MeshInstance>(E->get());
- if (!instance)
- continue;
-
- Ref<Mesh> m = instance->get_mesh();
- if (m.is_null())
- continue;
-
- Ref<Shape> shape = m->create_trimesh_shape();
- if (shape.is_null())
- continue;
-
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shape);
- StaticBody *body = memnew(StaticBody);
- body->add_child(cshape);
-
- Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner();
-
- ur->add_do_method(instance, "add_child", body);
- ur->add_do_method(body, "set_owner", owner);
- ur->add_do_method(cshape, "set_owner", owner);
- ur->add_do_reference(body);
- ur->add_undo_method(instance, "remove_child", body);
- }
-
- ur->commit_action();
-
- } break;
-
- case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: {
-
- if (node == get_tree()->get_edited_scene_root()) {
- err_dialog->set_text(TTR("This doesn't work on scene root!"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Ref<Shape> shape = mesh->create_trimesh_shape();
- if (shape.is_null())
- return;
-
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shape);
-
- Node *owner = node->get_owner();
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
-
- ur->create_action(TTR("Create Trimesh Static Shape"));
-
- ur->add_do_method(node->get_parent(), "add_child", cshape);
- ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
- ur->add_do_method(cshape, "set_owner", owner);
- ur->add_do_reference(cshape);
- ur->add_undo_method(node->get_parent(), "remove_child", cshape);
- ur->commit_action();
- } break;
- case MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE: {
-
- if (node == get_tree()->get_edited_scene_root()) {
- err_dialog->set_text(TTR("Can't create a single convex collision shape for the scene root."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Ref<Shape> shape = mesh->create_convex_shape();
-
- if (shape.is_null()) {
- err_dialog->set_text(TTR("Couldn't create a single convex collision shape."));
- err_dialog->popup_centered_minsize();
- return;
- }
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
-
- ur->create_action(TTR("Create Single Convex Shape"));
-
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shape);
- cshape->set_transform(node->get_transform());
-
- Node *owner = node->get_owner();
-
- ur->add_do_method(node->get_parent(), "add_child", cshape);
- ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
- ur->add_do_method(cshape, "set_owner", owner);
- ur->add_do_reference(cshape);
- ur->add_undo_method(node->get_parent(), "remove_child", cshape);
-
- ur->commit_action();
-
- } break;
- case MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES: {
-
- if (node == get_tree()->get_edited_scene_root()) {
- err_dialog->set_text(TTR("Can't create multiple convex collision shapes for the scene root."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Vector<Ref<Shape> > shapes = mesh->convex_decompose();
-
- if (!shapes.size()) {
- err_dialog->set_text(TTR("Couldn't create any collision shapes."));
- err_dialog->popup_centered_minsize();
- return;
- }
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
-
- ur->create_action(TTR("Create Multiple Convex Shapes"));
-
- for (int i = 0; i < shapes.size(); i++) {
-
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shapes[i]);
- cshape->set_transform(node->get_transform());
-
- Node *owner = node->get_owner();
-
- ur->add_do_method(node->get_parent(), "add_child", cshape);
- ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
- ur->add_do_method(cshape, "set_owner", owner);
- ur->add_do_reference(cshape);
- ur->add_undo_method(node->get_parent(), "remove_child", cshape);
- }
- ur->commit_action();
-
- } break;
-
- case MENU_OPTION_CREATE_NAVMESH: {
-
- Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
-
- if (nmesh.is_null())
- return;
-
- nmesh->create_from_mesh(mesh);
- NavigationRegion *nmi = memnew(NavigationRegion);
- nmi->set_navigation_mesh(nmesh);
-
- Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Create Navigation Mesh"));
-
- ur->add_do_method(node, "add_child", nmi);
- ur->add_do_method(nmi, "set_owner", owner);
-
- ur->add_do_reference(nmi);
- ur->add_undo_method(node, "remove_child", nmi);
- ur->commit_action();
- } break;
-
- case MENU_OPTION_CREATE_OUTLINE_MESH: {
-
- outline_dialog->popup_centered(Vector2(200, 90));
- } break;
- case MENU_OPTION_CREATE_UV2: {
-
- Ref<ArrayMesh> mesh2 = node->get_mesh();
- if (!mesh2.is_valid()) {
- err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Error err = mesh2->lightmap_unwrap(node->get_global_transform());
- if (err != OK) {
- err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- } break;
- case MENU_OPTION_DEBUG_UV1: {
- Ref<Mesh> mesh2 = node->get_mesh();
- if (!mesh2.is_valid()) {
- err_dialog->set_text(TTR("No mesh to debug."));
- err_dialog->popup_centered_minsize();
- return;
- }
- _create_uv_lines(0);
- } break;
- case MENU_OPTION_DEBUG_UV2: {
- Ref<Mesh> mesh2 = node->get_mesh();
- if (!mesh2.is_valid()) {
- err_dialog->set_text(TTR("No mesh to debug."));
- err_dialog->popup_centered_minsize();
- return;
- }
- _create_uv_lines(1);
- } break;
- }
-}
-
-struct MeshInstanceEditorEdgeSort {
-
- Vector2 a;
- Vector2 b;
-
- bool operator<(const MeshInstanceEditorEdgeSort &p_b) const {
- if (a == p_b.a)
- return b < p_b.b;
- else
- return a < p_b.a;
- }
-
- MeshInstanceEditorEdgeSort() {}
- MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) {
- if (p_a < p_b) {
- a = p_a;
- b = p_b;
- } else {
- b = p_a;
- a = p_b;
- }
- }
-};
-
-void MeshInstanceEditor::_create_uv_lines(int p_layer) {
-
- Ref<Mesh> mesh = node->get_mesh();
- ERR_FAIL_COND(!mesh.is_valid());
-
- Set<MeshInstanceEditorEdgeSort> edges;
- uv_lines.clear();
- for (int i = 0; i < mesh->get_surface_count(); i++) {
- if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
- continue;
- Array a = mesh->surface_get_arrays(i);
-
- Vector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2];
- if (uv.size() == 0) {
- err_dialog->set_text(TTR("Model has no UV in this layer"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- const Vector2 *r = uv.ptr();
-
- Vector<int> indices = a[Mesh::ARRAY_INDEX];
- const int *ri;
-
- int ic;
- bool use_indices;
-
- if (indices.size()) {
- ic = indices.size();
- ri = indices.ptr();
- use_indices = true;
- } else {
- ic = uv.size();
- use_indices = false;
- }
-
- for (int j = 0; j < ic; j += 3) {
-
- for (int k = 0; k < 3; k++) {
-
- MeshInstanceEditorEdgeSort edge;
- if (use_indices) {
- edge.a = r[ri[j + k]];
- edge.b = r[ri[j + ((k + 1) % 3)]];
- } else {
- edge.a = r[j + k];
- edge.b = r[j + ((k + 1) % 3)];
- }
-
- if (edges.has(edge))
- continue;
-
- uv_lines.push_back(edge.a);
- uv_lines.push_back(edge.b);
- edges.insert(edge);
- }
- }
- }
-
- debug_uv_dialog->popup_centered_minsize();
-}
-
-void MeshInstanceEditor::_debug_uv_draw() {
-
- if (uv_lines.size() == 0)
- return;
-
- debug_uv->set_clip_contents(true);
- debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0));
- debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
- debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7));
-}
-
-void MeshInstanceEditor::_create_outline_mesh() {
-
- Ref<Mesh> mesh = node->get_mesh();
- if (mesh.is_null()) {
- err_dialog->set_text(TTR("MeshInstance lacks a Mesh!"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- if (mesh->get_surface_count() == 0) {
- err_dialog->set_text(TTR("Mesh has not surface to create outlines from!"));
- err_dialog->popup_centered_minsize();
- return;
- } else if (mesh->get_surface_count() == 1 && mesh->surface_get_primitive_type(0) != Mesh::PRIMITIVE_TRIANGLES) {
- err_dialog->set_text(TTR("Mesh primitive type is not PRIMITIVE_TRIANGLES!"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Ref<Mesh> mesho = mesh->create_outline(outline_size->get_value());
-
- if (mesho.is_null()) {
- err_dialog->set_text(TTR("Could not create outline!"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- MeshInstance *mi = memnew(MeshInstance);
- mi->set_mesh(mesho);
- Node *owner = node->get_owner();
- if (get_tree()->get_edited_scene_root() == node) {
- owner = node;
- }
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
-
- ur->create_action(TTR("Create Outline"));
-
- ur->add_do_method(node, "add_child", mi);
- ur->add_do_method(mi, "set_owner", owner);
-
- ur->add_do_reference(mi);
- ur->add_undo_method(node, "remove_child", mi);
- ur->commit_action();
-}
-
-void MeshInstanceEditor::_bind_methods() {
-}
-
-MeshInstanceEditor::MeshInstanceEditor() {
-
- options = memnew(MenuButton);
- options->set_switch_on_hover(true);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
-
- options->set_text(TTR("Mesh"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance", "EditorIcons"));
-
- options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a StaticBody and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection."));
- options->get_popup()->add_item(TTR("Create Single Convex Collision Sibling"), MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection."));
- options->get_popup()->add_item(TTR("Create Multiple Convex Collision Siblings"), MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between the two above options."));
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Create Outline Mesh..."), MENU_OPTION_CREATE_OUTLINE_MESH);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a static outline mesh. The outline mesh will have its normals flipped automatically.\nThis can be used instead of the SpatialMaterial Grow property when using that property isn't possible."));
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1);
- options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2);
- options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2);
-
- options->get_popup()->connect("id_pressed", callable_mp(this, &MeshInstanceEditor::_menu_option));
-
- outline_dialog = memnew(ConfirmationDialog);
- outline_dialog->set_title(TTR("Create Outline Mesh"));
- outline_dialog->get_ok()->set_text(TTR("Create"));
-
- VBoxContainer *outline_dialog_vbc = memnew(VBoxContainer);
- outline_dialog->add_child(outline_dialog_vbc);
- //outline_dialog->set_child_rect(outline_dialog_vbc);
-
- outline_size = memnew(SpinBox);
- outline_size->set_min(0.001);
- outline_size->set_max(1024);
- outline_size->set_step(0.001);
- outline_size->set_value(0.05);
- outline_dialog_vbc->add_margin_child(TTR("Outline Size:"), outline_size);
-
- add_child(outline_dialog);
- outline_dialog->connect("confirmed", callable_mp(this, &MeshInstanceEditor::_create_outline_mesh));
-
- err_dialog = memnew(AcceptDialog);
- add_child(err_dialog);
-
- debug_uv_dialog = memnew(AcceptDialog);
- debug_uv_dialog->set_title(TTR("UV Channel Debug"));
- add_child(debug_uv_dialog);
- debug_uv = memnew(Control);
- debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE);
- debug_uv->connect("draw", callable_mp(this, &MeshInstanceEditor::_debug_uv_draw));
- debug_uv_dialog->add_child(debug_uv);
-}
-
-void MeshInstanceEditorPlugin::edit(Object *p_object) {
-
- mesh_editor->edit(Object::cast_to<MeshInstance>(p_object));
-}
-
-bool MeshInstanceEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("MeshInstance");
-}
-
-void MeshInstanceEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- mesh_editor->options->show();
- } else {
-
- mesh_editor->options->hide();
- mesh_editor->edit(NULL);
- }
-}
-
-MeshInstanceEditorPlugin::MeshInstanceEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- mesh_editor = memnew(MeshInstanceEditor);
- editor->get_viewport()->add_child(mesh_editor);
-
- mesh_editor->options->hide();
-}
-
-MeshInstanceEditorPlugin::~MeshInstanceEditorPlugin() {
-}
diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_editor_plugin.h
deleted file mode 100644
index 5ca9aa3fec..0000000000
--- a/editor/plugins/mesh_instance_editor_plugin.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*************************************************************************/
-/* mesh_instance_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 MESH_INSTANCE_EDITOR_PLUGIN_H
-#define MESH_INSTANCE_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/gui/spin_box.h"
-
-class MeshInstanceEditor : public Control {
-
- GDCLASS(MeshInstanceEditor, Control);
-
- enum Menu {
-
- MENU_OPTION_CREATE_STATIC_TRIMESH_BODY,
- MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE,
- MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE,
- MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES,
- MENU_OPTION_CREATE_NAVMESH,
- MENU_OPTION_CREATE_OUTLINE_MESH,
- MENU_OPTION_CREATE_UV2,
- MENU_OPTION_DEBUG_UV1,
- MENU_OPTION_DEBUG_UV2,
- };
-
- MeshInstance *node;
-
- MenuButton *options;
-
- ConfirmationDialog *outline_dialog;
- SpinBox *outline_size;
-
- AcceptDialog *err_dialog;
-
- AcceptDialog *debug_uv_dialog;
- Control *debug_uv;
- Vector<Vector2> uv_lines;
-
- void _menu_option(int p_option);
- void _create_outline_mesh();
-
- void _create_uv_lines(int p_layer);
- friend class MeshInstanceEditorPlugin;
-
- void _debug_uv_draw();
-
-protected:
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
-public:
- void edit(MeshInstance *p_mesh);
- MeshInstanceEditor();
-};
-
-class MeshInstanceEditorPlugin : public EditorPlugin {
-
- GDCLASS(MeshInstanceEditorPlugin, EditorPlugin);
-
- MeshInstanceEditor *mesh_editor;
- EditorNode *editor;
-
-public:
- virtual String get_name() const { return "MeshInstance"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- MeshInstanceEditorPlugin(EditorNode *p_node);
- ~MeshInstanceEditorPlugin();
-};
-
-#endif // MESH_EDITOR_PLUGIN_H
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 71976d509b..a3e3d88ae2 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -33,12 +33,12 @@
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "main/main.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/navigation_region.h"
-#include "scene/3d/physics_body.h"
-#include "scene/main/viewport.h"
+#include "node_3d_editor_plugin.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
-#include "spatial_editor_plugin.h"
void MeshLibraryEditor::edit(const Ref<MeshLibrary> &p_mesh_library) {
@@ -71,16 +71,16 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
if (!p_merge)
p_library->clear();
- Map<int, MeshInstance *> mesh_instances;
+ Map<int, MeshInstance3D *> mesh_instances;
for (int i = 0; i < p_scene->get_child_count(); i++) {
Node *child = p_scene->get_child(i);
- if (!Object::cast_to<MeshInstance>(child)) {
+ if (!Object::cast_to<MeshInstance3D>(child)) {
if (child->get_child_count() > 0) {
child = child->get_child(0);
- if (!Object::cast_to<MeshInstance>(child)) {
+ if (!Object::cast_to<MeshInstance3D>(child)) {
continue;
}
@@ -88,7 +88,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
continue;
}
- MeshInstance *mi = Object::cast_to<MeshInstance>(child);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(child);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_null())
continue;
@@ -118,10 +118,10 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
- if (!Object::cast_to<StaticBody>(child2))
+ if (!Object::cast_to<StaticBody3D>(child2))
continue;
- StaticBody *sb = Object::cast_to<StaticBody>(child2);
+ StaticBody3D *sb = Object::cast_to<StaticBody3D>(child2);
List<uint32_t> shapes;
sb->get_shape_owners(&shapes);
@@ -135,7 +135,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) {
- Ref<Shape> collision = sb->shape_owner_get_shape(E->get(), k);
+ Ref<Shape3D> collision = sb->shape_owner_get_shape(E->get(), k);
if (!collision.is_valid())
continue;
MeshLibrary::ShapeData shape_data;
@@ -152,9 +152,9 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
Transform navmesh_transform;
for (int j = 0; j < mi->get_child_count(); j++) {
Node *child2 = mi->get_child(j);
- if (!Object::cast_to<NavigationRegion>(child2))
+ if (!Object::cast_to<NavigationRegion3D>(child2))
continue;
- NavigationRegion *sb = Object::cast_to<NavigationRegion>(child2);
+ NavigationRegion3D *sb = Object::cast_to<NavigationRegion3D>(child2);
navmesh = sb->get_navigation_mesh();
navmesh_transform = sb->get_transform();
if (!navmesh.is_null())
@@ -170,7 +170,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
if (1) {
- Vector<Ref<Mesh> > meshes;
+ Vector<Ref<Mesh>> meshes;
Vector<Transform> transforms;
Vector<int> ids = p_library->get_item_list();
for (int i = 0; i < ids.size(); i++) {
@@ -182,7 +182,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
}
}
- Vector<Ref<Texture2D> > textures = EditorInterface::get_singleton()->make_mesh_previews(meshes, &transforms, EditorSettings::get_singleton()->get("editors/grid_map/preview_size"));
+ Vector<Ref<Texture2D>> textures = EditorInterface::get_singleton()->make_mesh_previews(meshes, &transforms, EditorSettings::get_singleton()->get("editors/grid_map/preview_size"));
int j = 0;
for (int i = 0; i < ids.size(); i++) {
@@ -253,7 +253,7 @@ void MeshLibraryEditor::_bind_methods() {
MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
file = memnew(EditorFileDialog);
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
//not for now?
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
@@ -267,10 +267,10 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
file->connect("file_selected", callable_mp(this, &MeshLibraryEditor::_import_scene_cbk));
menu = memnew(MenuButton);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(menu);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(menu);
menu->set_position(Point2(1, 1));
menu->set_text(TTR("Mesh Library"));
- menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshLibrary", "EditorIcons"));
+ menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("MeshLibrary", "EditorIcons"));
menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM);
menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM);
menu->get_popup()->add_separator();
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index 27d400c035..4f482c2b43 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -30,14 +30,14 @@
#include "multimesh_editor_plugin.h"
-#include "scene/3d/mesh_instance.h"
+#include "node_3d_editor_plugin.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/box_container.h"
-#include "spatial_editor_plugin.h"
void MultiMeshEditor::_node_removed(Node *p_node) {
if (p_node == node) {
- node = NULL;
+ node = nullptr;
hide();
}
}
@@ -56,13 +56,13 @@ void MultiMeshEditor::_populate() {
if (multimesh.is_null()) {
err_dialog->set_text(TTR("No mesh source specified (and no MultiMesh set in node)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
if (multimesh->get_mesh().is_null()) {
err_dialog->set_text(TTR("No mesh source specified (and MultiMesh contains no Mesh)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
@@ -74,16 +74,16 @@ void MultiMeshEditor::_populate() {
if (!ms_node) {
err_dialog->set_text(TTR("Mesh source is invalid (invalid path)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
- MeshInstance *ms_instance = Object::cast_to<MeshInstance>(ms_node);
+ MeshInstance3D *ms_instance = Object::cast_to<MeshInstance3D>(ms_node);
if (!ms_instance) {
- err_dialog->set_text(TTR("Mesh source is invalid (not a MeshInstance)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->set_text(TTR("Mesh source is invalid (not a MeshInstance3D)."));
+ err_dialog->popup_centered();
return;
}
@@ -92,7 +92,7 @@ void MultiMeshEditor::_populate() {
if (mesh.is_null()) {
err_dialog->set_text(TTR("Mesh source is invalid (contains no Mesh resource)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
}
@@ -100,7 +100,7 @@ void MultiMeshEditor::_populate() {
if (surface_source->get_text() == "") {
err_dialog->set_text(TTR("No surface source specified."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
@@ -109,27 +109,27 @@ void MultiMeshEditor::_populate() {
if (!ss_node) {
err_dialog->set_text(TTR("Surface source is invalid (invalid path)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
- GeometryInstance *ss_instance = Object::cast_to<MeshInstance>(ss_node);
+ GeometryInstance3D *ss_instance = Object::cast_to<MeshInstance3D>(ss_node);
if (!ss_instance) {
err_dialog->set_text(TTR("Surface source is invalid (no geometry)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
Transform geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform();
- Vector<Face3> geometry = ss_instance->get_faces(VisualInstance::FACES_SOLID);
+ Vector<Face3> geometry = ss_instance->get_faces(VisualInstance3D::FACES_SOLID);
if (geometry.size() == 0) {
err_dialog->set_text(TTR("Surface source is invalid (no faces)."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
@@ -261,7 +261,7 @@ void MultiMeshEditor::_menu_option(int p_option) {
}
}
-void MultiMeshEditor::edit(MultiMeshInstance *p_multimesh) {
+void MultiMeshEditor::edit(MultiMeshInstance3D *p_multimesh) {
node = p_multimesh;
}
@@ -284,10 +284,10 @@ MultiMeshEditor::MultiMeshEditor() {
options = memnew(MenuButton);
options->set_switch_on_hover(true);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text("MultiMesh");
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MultiMeshInstance", "EditorIcons"));
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("MultiMeshInstance3D", "EditorIcons"));
options->get_popup()->add_item(TTR("Populate Surface"));
options->get_popup()->connect("id_pressed", callable_mp(this, &MultiMeshEditor::_menu_option));
@@ -371,7 +371,7 @@ MultiMeshEditor::MultiMeshEditor() {
populate_dialog->add_child(std);
std->connect("selected", callable_mp(this, &MultiMeshEditor::_browsed));
- _last_pp_node = NULL;
+ _last_pp_node = nullptr;
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
@@ -379,12 +379,12 @@ MultiMeshEditor::MultiMeshEditor() {
void MultiMeshEditorPlugin::edit(Object *p_object) {
- multimesh_editor->edit(Object::cast_to<MultiMeshInstance>(p_object));
+ multimesh_editor->edit(Object::cast_to<MultiMeshInstance3D>(p_object));
}
bool MultiMeshEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("MultiMeshInstance");
+ return p_object->is_class("MultiMeshInstance3D");
}
void MultiMeshEditorPlugin::make_visible(bool p_visible) {
@@ -394,7 +394,7 @@ void MultiMeshEditorPlugin::make_visible(bool p_visible) {
} else {
multimesh_editor->options->hide();
- multimesh_editor->edit(NULL);
+ multimesh_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/multimesh_editor_plugin.h b/editor/plugins/multimesh_editor_plugin.h
index 2c7b98cfbc..15c9b91fee 100644
--- a/editor/plugins/multimesh_editor_plugin.h
+++ b/editor/plugins/multimesh_editor_plugin.h
@@ -33,7 +33,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/3d/multimesh_instance.h"
+#include "scene/3d/multimesh_instance_3d.h"
#include "scene/gui/spin_box.h"
class MultiMeshEditor : public Control {
@@ -44,11 +44,11 @@ class MultiMeshEditor : public Control {
AcceptDialog *err_dialog;
MenuButton *options;
- MultiMeshInstance *_last_pp_node;
+ MultiMeshInstance3D *_last_pp_node;
bool browsing_source;
Panel *panel;
- MultiMeshInstance *node;
+ MultiMeshInstance3D *node;
LineEdit *surface_source;
LineEdit *mesh_source;
@@ -78,7 +78,7 @@ protected:
static void _bind_methods();
public:
- void edit(MultiMeshInstance *p_multimesh);
+ void edit(MultiMeshInstance3D *p_multimesh);
MultiMeshEditor();
};
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index 6671d0b6b4..e41b32ac86 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -123,7 +123,7 @@ void NavigationPolygonEditor::_create_resource() {
NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) :
AbstractPolygon2DEditor(p_editor) {
- node = NULL;
+ node = nullptr;
}
NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) :
diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h
index 10f8cbc0a5..0bc35e2498 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.h
+++ b/editor/plugins/navigation_polygon_editor_plugin.h
@@ -32,7 +32,7 @@
#define NAVIGATIONPOLYGONEDITORPLUGIN_H
#include "editor/plugins/abstract_polygon_2d_editor.h"
-#include "scene/2d/navigation_polygon.h"
+#include "scene/2d/navigation_region_2d.h"
class NavigationPolygonEditor : public AbstractPolygon2DEditor {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..354c951a7c
--- /dev/null
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -0,0 +1,6817 @@
+/*************************************************************************/
+/* node_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "node_3d_editor_plugin.h"
+
+#include "core/input/input_filter.h"
+#include "core/math/camera_matrix.h"
+#include "core/os/keyboard.h"
+#include "core/print_string.h"
+#include "core/project_settings.h"
+#include "core/sort_array.h"
+#include "editor/debugger/editor_debugger_node.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "editor/node_3d_editor_gizmos.h"
+#include "editor/plugins/animation_player_editor_plugin.h"
+#include "editor/plugins/script_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/gui/subviewport_container.h"
+#include "scene/resources/packed_scene.h"
+#include "scene/resources/surface_tool.h"
+#include "servers/display_server.h"
+
+#define DISTANCE_DEFAULT 4
+
+#define GIZMO_ARROW_SIZE 0.35
+#define GIZMO_RING_HALF_WIDTH 0.1
+#define GIZMO_SCALE_DEFAULT 0.15
+#define GIZMO_PLANE_SIZE 0.2
+#define GIZMO_PLANE_DST 0.3
+#define GIZMO_CIRCLE_SIZE 1.1
+#define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
+#define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
+
+#define ZOOM_MIN_DISTANCE 0.001
+#define ZOOM_MULTIPLIER 1.08
+#define ZOOM_INDICATOR_DELAY_S 1.5
+
+#define FREELOOK_MIN_SPEED 0.01
+#define FREELOOK_SPEED_MULTIPLIER 1.08
+
+#define MIN_Z 0.01
+#define MAX_Z 1000000.0
+
+#define MIN_FOV 0.01
+#define MAX_FOV 179
+
+void ViewportRotationControl::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ axis_menu_options.clear();
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_RIGHT);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_TOP);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_FRONT);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_LEFT);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_BOTTOM);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_REAR);
+
+ axis_colors.clear();
+ axis_colors.push_back(get_theme_color("axis_x_color", "Editor"));
+ axis_colors.push_back(get_theme_color("axis_y_color", "Editor"));
+ axis_colors.push_back(get_theme_color("axis_z_color", "Editor"));
+ update();
+
+ if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) {
+ connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited));
+ }
+ }
+
+ if (p_what == NOTIFICATION_DRAW && viewport != nullptr) {
+ _draw();
+ }
+}
+
+void ViewportRotationControl::_draw() {
+ Vector2i center = get_size() / 2.0;
+ float radius = get_size().x / 2.0;
+
+ if (focused_axis > -2 || orbiting) {
+ draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25));
+ }
+
+ Vector<Axis2D> axis_to_draw;
+ _get_sorted_axis(axis_to_draw);
+ for (int i = 0; i < axis_to_draw.size(); ++i) {
+ _draw_axis(axis_to_draw[i]);
+ }
+}
+
+void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) {
+ bool focused = focused_axis == p_axis.axis;
+ bool positive = p_axis.axis < 3;
+ bool front = (Math::abs(p_axis.z_axis) <= 0.001 && positive) || p_axis.z_axis > 0.001;
+ int direction = p_axis.axis % 3;
+
+ Color axis_color = axis_colors[direction];
+
+ if (!front) {
+ axis_color = axis_color.darkened(0.4);
+ }
+ Color c = focused ? Color(0.9, 0.9, 0.9) : axis_color;
+
+ if (positive) {
+ Vector2i center = get_size() / 2.0;
+ draw_line(center, p_axis.screen_point, c, 1.5 * EDSCALE);
+ }
+
+ if (front) {
+ String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z");
+ draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c);
+ draw_char(get_theme_font("rotation_control", "EditorFonts"), p_axis.screen_point + Vector2i(-4, 5) * EDSCALE, axis_name, "", Color(0.3, 0.3, 0.3));
+ } else {
+ draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS * (0.55 + (0.2 * (1.0 + p_axis.z_axis))), c);
+ }
+}
+
+void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
+ Vector2i center = get_size() / 2.0;
+ float radius = get_size().x / 2.0;
+
+ float axis_radius = radius - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE;
+ Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse();
+
+ for (int i = 0; i < 3; ++i) {
+ Vector3 axis_3d = camera_basis.get_axis(i);
+ Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * axis_radius;
+
+ if (Math::abs(axis_3d.z) < 1.0) {
+ Axis2D pos_axis;
+ pos_axis.axis = i;
+ pos_axis.screen_point = center + axis_vector;
+ pos_axis.z_axis = axis_3d.z;
+ r_axis.push_back(pos_axis);
+
+ Axis2D neg_axis;
+ neg_axis.axis = i + 3;
+ neg_axis.screen_point = center - axis_vector;
+ neg_axis.z_axis = -axis_3d.z;
+ r_axis.push_back(neg_axis);
+ } else {
+ // Special case when the camera is aligned with one axis
+ Axis2D axis;
+ axis.axis = i + (axis_3d.z < 0 ? 0 : 3);
+ axis.screen_point = center;
+ axis.z_axis = 1.0;
+ r_axis.push_back(axis);
+ }
+ }
+
+ r_axis.sort_custom<Axis2DCompare>();
+}
+
+void ViewportRotationControl::_gui_input(Ref<InputEvent> p_event) {
+ const Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ Vector2 pos = mb->get_position();
+ if (mb->is_pressed()) {
+ if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
+ orbiting = true;
+ }
+ } else {
+ if (focused_axis > -1) {
+ viewport->_menu_option(axis_menu_options[focused_axis]);
+ _update_focus();
+ }
+ orbiting = false;
+ }
+ }
+
+ const Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ if (orbiting) {
+ viewport->_nav_orbit(mm, viewport->_get_warped_mouse_motion(mm));
+ focused_axis = -1;
+ } else {
+ _update_focus();
+ }
+ }
+}
+
+void ViewportRotationControl::_update_focus() {
+ int original_focus = focused_axis;
+ focused_axis = -2;
+ Vector2 mouse_pos = get_local_mouse_position();
+
+ if (mouse_pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
+ focused_axis = -1;
+ }
+
+ Vector<Axis2D> axes;
+ _get_sorted_axis(axes);
+
+ for (int i = 0; i < axes.size(); i++) {
+ const Axis2D &axis = axes[i];
+ if (mouse_pos.distance_to(axis.screen_point) < AXIS_CIRCLE_RADIUS) {
+ focused_axis = axis.axis;
+ }
+ }
+
+ if (focused_axis != original_focus) {
+ update();
+ }
+}
+
+void ViewportRotationControl::_on_mouse_exited() {
+ focused_axis = -2;
+ update();
+}
+
+void ViewportRotationControl::set_viewport(Node3DEditorViewport *p_viewport) {
+ viewport = p_viewport;
+}
+
+void ViewportRotationControl::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_gui_input"), &ViewportRotationControl::_gui_input);
+}
+
+void Node3DEditorViewport::_update_camera(float p_interp_delta) {
+
+ bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL;
+
+ Cursor old_camera_cursor = camera_cursor;
+ camera_cursor = cursor;
+
+ if (p_interp_delta > 0) {
+
+ //-------
+ // Perform smoothing
+
+ if (is_freelook_active()) {
+
+ // Higher inertia should increase "lag" (lerp with factor between 0 and 1)
+ // Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1.
+ real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
+ inertia = MAX(0.001, inertia);
+ real_t factor = (1.0 / inertia) * p_interp_delta;
+
+ // We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
+ camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1));
+
+ float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ orbit_inertia = MAX(0.0001, orbit_inertia);
+ camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+ camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+
+ if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) {
+ camera_cursor.x_rot = cursor.x_rot;
+ }
+
+ if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) {
+ camera_cursor.y_rot = cursor.y_rot;
+ }
+
+ Vector3 forward = to_camera_transform(camera_cursor).basis.xform(Vector3(0, 0, -1));
+ camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance;
+
+ } else {
+
+ //when not being manipulated, move softly
+ float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
+ //when being manipulated, move more quickly
+ float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
+ float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
+
+ float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
+
+ //determine if being manipulated
+ bool manipulated = InputFilter::get_singleton()->get_mouse_button_mask() & (2 | 4);
+ manipulated |= InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT);
+ manipulated |= InputFilter::get_singleton()->is_key_pressed(KEY_ALT);
+ manipulated |= InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
+
+ float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
+ float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
+ zoom_inertia = MAX(0.0001, zoom_inertia);
+
+ camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+ camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+
+ if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) {
+ camera_cursor.x_rot = cursor.x_rot;
+ }
+
+ if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) {
+ camera_cursor.y_rot = cursor.y_rot;
+ }
+
+ camera_cursor.pos = old_camera_cursor.pos.linear_interpolate(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia)));
+ camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia)));
+ }
+ }
+
+ //-------
+ // Apply camera transform
+
+ float tolerance = 0.001;
+ bool equal = true;
+ if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) {
+ equal = false;
+ }
+
+ if (equal && old_camera_cursor.pos.distance_squared_to(camera_cursor.pos) > tolerance * tolerance) {
+ equal = false;
+ }
+
+ if (equal && Math::abs(old_camera_cursor.distance - camera_cursor.distance) > tolerance) {
+ equal = false;
+ }
+
+ if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) {
+
+ camera->set_global_transform(to_camera_transform(camera_cursor));
+
+ if (orthogonal) {
+ float half_fov = Math::deg2rad(get_fov()) / 2.0;
+ float height = 2.0 * cursor.distance * Math::tan(half_fov);
+ camera->set_orthogonal(height, get_znear(), get_zfar());
+ } else {
+ camera->set_perspective(get_fov(), get_znear(), get_zfar());
+ }
+
+ update_transform_gizmo_view();
+ rotation_control->update();
+ }
+}
+
+Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
+ Transform camera_transform;
+ camera_transform.translate(p_cursor.pos);
+ camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot);
+ camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot);
+
+ if (orthogonal)
+ camera_transform.translate(0, 0, (get_zfar() - get_znear()) / 2.0);
+ else
+ camera_transform.translate(0, 0, p_cursor.distance);
+
+ return camera_transform;
+}
+
+int Node3DEditorViewport::get_selected_count() const {
+
+ Map<Node *, Object *> &selection = editor_selection->get_selection();
+
+ int count = 0;
+
+ for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->key());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ count++;
+ }
+
+ return count;
+}
+
+float Node3DEditorViewport::get_znear() const {
+
+ return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z);
+}
+float Node3DEditorViewport::get_zfar() const {
+
+ return CLAMP(spatial_editor->get_zfar(), MIN_Z, MAX_Z);
+}
+float Node3DEditorViewport::get_fov() const {
+
+ return CLAMP(spatial_editor->get_fov(), MIN_FOV, MAX_FOV);
+}
+
+Transform Node3DEditorViewport::_get_camera_transform() const {
+
+ return camera->get_global_transform();
+}
+
+Vector3 Node3DEditorViewport::_get_camera_position() const {
+
+ return _get_camera_transform().origin;
+}
+
+Point2 Node3DEditorViewport::_point_to_screen(const Vector3 &p_point) {
+
+ return camera->unproject_position(p_point) * subviewport_container->get_stretch_shrink();
+}
+
+Vector3 Node3DEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
+
+ return camera->project_ray_origin(p_pos / subviewport_container->get_stretch_shrink());
+}
+
+Vector3 Node3DEditorViewport::_get_camera_normal() const {
+
+ return -_get_camera_transform().basis.get_axis(2);
+}
+
+Vector3 Node3DEditorViewport::_get_ray(const Vector2 &p_pos) const {
+
+ return camera->project_ray_normal(p_pos / subviewport_container->get_stretch_shrink());
+}
+
+void Node3DEditorViewport::_clear_selected() {
+
+ editor_selection->clear();
+}
+
+void Node3DEditorViewport::_select_clicked(bool p_append, bool p_single, bool p_allow_locked) {
+
+ if (clicked.is_null())
+ return;
+
+ Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked));
+ Node3D *selected = Object::cast_to<Node3D>(node);
+ if (!selected)
+ return;
+
+ if (!p_allow_locked) {
+ // Replace the node by the group if grouped
+ while (node && node != editor->get_edited_scene()->get_parent()) {
+ Node3D *selected_tmp = Object::cast_to<Node3D>(node);
+ if (selected_tmp && node->has_meta("_edit_group_")) {
+ selected = selected_tmp;
+ }
+ node = node->get_parent();
+ }
+ }
+
+ if (p_allow_locked || !_is_node_locked(selected)) {
+ _select(selected, clicked_wants_append, true);
+ }
+}
+
+void Node3DEditorViewport::_select(Node *p_node, bool p_append, bool p_single) {
+
+ if (!p_append) {
+ editor_selection->clear();
+ }
+
+ if (editor_selection->is_selected(p_node)) {
+ //erase
+ editor_selection->remove_node(p_node);
+ } else {
+
+ editor_selection->add_node(p_node);
+ }
+
+ if (p_single) {
+ if (Engine::get_singleton()->is_editor_hint())
+ editor->call("edit_node", p_node);
+ }
+}
+
+ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) {
+
+ if (r_gizmo_handle)
+ *r_gizmo_handle = -1;
+
+ Vector3 ray = _get_ray(p_pos);
+ Vector3 pos = _get_ray_pos(p_pos);
+ Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink();
+
+ Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
+ Set<Ref<EditorNode3DGizmo>> found_gizmos;
+
+ Node *edited_scene = get_tree()->get_edited_scene_root();
+ ObjectID closest;
+ Node *item = nullptr;
+ float closest_dist = 1e20;
+ int selected_handle = -1;
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
+
+ if (!spat)
+ continue;
+
+ Ref<EditorNode3DGizmo> seg = spat->get_gizmo();
+
+ if ((!seg.is_valid()) || found_gizmos.has(seg)) {
+ continue;
+ }
+
+ found_gizmos.insert(seg);
+ Vector3 point;
+ Vector3 normal;
+
+ int handle = -1;
+ bool inters = seg->intersect_ray(camera, shrinked_pos, point, normal, &handle, p_alt_select);
+
+ if (!inters)
+ continue;
+
+ float dist = pos.distance_to(point);
+
+ if (dist < 0)
+ continue;
+
+ 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();
+ }
+
+ closest = item->get_instance_id();
+ closest_dist = dist;
+ selected_handle = handle;
+ }
+ }
+
+ if (!item)
+ return ObjectID();
+
+ if (!editor_selection->is_selected(item) || (r_gizmo_handle && selected_handle >= 0)) {
+
+ if (r_gizmo_handle)
+ *r_gizmo_handle = selected_handle;
+ }
+
+ return closest;
+}
+
+void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) {
+
+ Vector3 ray = _get_ray(p_pos);
+ Vector3 pos = _get_ray_pos(p_pos);
+
+ Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
+ Set<Ref<EditorNode3DGizmo>> found_gizmos;
+
+ r_includes_current = false;
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
+
+ if (!spat)
+ continue;
+
+ Ref<EditorNode3DGizmo> seg = spat->get_gizmo();
+
+ if (!seg.is_valid())
+ continue;
+
+ if (found_gizmos.has(seg))
+ continue;
+
+ found_gizmos.insert(seg);
+ Vector3 point;
+ Vector3 normal;
+
+ int handle = -1;
+ bool inters = seg->intersect_ray(camera, p_pos, point, normal, nullptr, p_alt_select);
+
+ if (!inters)
+ continue;
+
+ float dist = pos.distance_to(point);
+
+ if (dist < 0)
+ continue;
+
+ if (editor_selection->is_selected(spat))
+ r_includes_current = true;
+
+ _RayResult res;
+ res.item = spat;
+ res.depth = dist;
+ res.handle = handle;
+ results.push_back(res);
+ }
+
+ if (results.empty())
+ return;
+
+ results.sort();
+}
+
+Vector3 Node3DEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
+
+ CameraMatrix cm;
+ if (orthogonal) {
+ cm.set_orthogonal(camera->get_size(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
+ } else {
+ cm.set_perspective(get_fov(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
+ }
+ Vector2 screen_he = cm.get_viewport_half_extents();
+
+ Transform camera_transform;
+ camera_transform.translate(cursor.pos);
+ camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
+ camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
+ camera_transform.translate(0, 0, cursor.distance);
+
+ return camera_transform.xform(Vector3(((p_vector3.x / get_size().width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / get_size().height)) * 2.0 - 1.0) * screen_he.y, -(get_znear() + p_vector3.z)));
+}
+
+void Node3DEditorViewport::_select_region() {
+
+ if (cursor.region_begin == cursor.region_end)
+ return; //nothing really
+
+ float z_offset = MAX(0.0, 5.0 - get_znear());
+
+ Vector3 box[4] = {
+ Vector3(
+ MIN(cursor.region_begin.x, cursor.region_end.x),
+ MIN(cursor.region_begin.y, cursor.region_end.y),
+ z_offset),
+ Vector3(
+ MAX(cursor.region_begin.x, cursor.region_end.x),
+ MIN(cursor.region_begin.y, cursor.region_end.y),
+ z_offset),
+ Vector3(
+ MAX(cursor.region_begin.x, cursor.region_end.x),
+ MAX(cursor.region_begin.y, cursor.region_end.y),
+ z_offset),
+ Vector3(
+ MIN(cursor.region_begin.x, cursor.region_end.x),
+ MAX(cursor.region_begin.y, cursor.region_end.y),
+ z_offset)
+ };
+
+ Vector<Plane> frustum;
+
+ Vector3 cam_pos = _get_camera_position();
+
+ for (int i = 0; i < 4; i++) {
+
+ Vector3 a = _get_screen_to_space(box[i]);
+ Vector3 b = _get_screen_to_space(box[(i + 1) % 4]);
+ if (orthogonal) {
+ frustum.push_back(Plane(a, (a - b).normalized()));
+ } else {
+ frustum.push_back(Plane(a, b, cam_pos));
+ }
+ }
+
+ if (!orthogonal) {
+ Plane near(cam_pos, -_get_camera_normal());
+ near.d -= get_znear();
+
+ frustum.push_back(near);
+
+ Plane far = -near;
+ far.d += get_zfar();
+
+ frustum.push_back(far);
+ }
+
+ Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
+ Vector<Node *> selected;
+
+ Node *edited_scene = get_tree()->get_edited_scene_root();
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ Node3D *sp = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
+ if (!sp || _is_node_locked(sp))
+ continue;
+
+ 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();
+ }
+
+ // Replace the node by the group if grouped
+ if (item->is_class("Node3D")) {
+ Node3D *sel = Object::cast_to<Node3D>(item);
+ while (item && item != editor->get_edited_scene()->get_parent()) {
+ Node3D *selected_tmp = Object::cast_to<Node3D>(item);
+ if (selected_tmp && item->has_meta("_edit_group_")) {
+ sel = selected_tmp;
+ }
+ item = item->get_parent();
+ }
+ item = sel;
+ }
+
+ if (selected.find(item) != -1) continue;
+
+ if (_is_node_locked(item)) continue;
+
+ Ref<EditorNode3DGizmo> seg = sp->get_gizmo();
+
+ if (!seg.is_valid())
+ continue;
+
+ if (seg->intersect_frustum(camera, frustum)) {
+ selected.push_back(item);
+ }
+ }
+
+ bool single = selected.size() == 1;
+ for (int i = 0; i < selected.size(); i++) {
+ _select(selected[i], true, single);
+ }
+}
+
+void Node3DEditorViewport::_update_name() {
+
+ String view_mode = orthogonal ? TTR("Orthogonal") : TTR("Perspective");
+
+ if (auto_orthogonal) {
+ view_mode += " [auto]";
+ }
+
+ if (name != "")
+ view_menu->set_text(name + " " + view_mode);
+ else
+ view_menu->set_text(view_mode);
+
+ view_menu->set_size(Vector2(0, 0)); // resets the button size
+}
+
+void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
+
+ _edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y));
+ _edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y));
+ _edit.plane = TRANSFORM_VIEW;
+ spatial_editor->update_transform_gizmo();
+ _edit.center = spatial_editor->get_gizmo_transform().origin;
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ se->original = se->sp->get_global_gizmo_transform();
+ se->original_local = se->sp->get_local_gizmo_transform();
+ }
+}
+
+static int _get_key_modifier_setting(const String &p_property) {
+
+ switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
+
+ case 0: return 0;
+ case 1: return KEY_SHIFT;
+ case 2: return KEY_ALT;
+ case 3: return KEY_META;
+ case 4: return KEY_CONTROL;
+ }
+ return 0;
+}
+
+static int _get_key_modifier(Ref<InputEventWithModifiers> e) {
+ if (e->get_shift())
+ return KEY_SHIFT;
+ if (e->get_alt())
+ return KEY_ALT;
+ if (e->get_control())
+ return KEY_CONTROL;
+ if (e->get_metakey())
+ return KEY_META;
+ return 0;
+}
+
+bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) {
+
+ if (!spatial_editor->is_gizmo_visible())
+ return false;
+ if (get_selected_count() == 0) {
+ if (p_highlight_only)
+ spatial_editor->select_gizmo_highlight_axis(-1);
+ return false;
+ }
+
+ Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
+ Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
+
+ Transform gt = spatial_editor->get_gizmo_transform();
+ float gs = gizmo_scale;
+
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
+
+ int col_axis = -1;
+ float col_d = 1e20;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
+ float grabber_radius = gs * GIZMO_ARROW_SIZE;
+
+ Vector3 r;
+
+ if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
+ float d = r.distance_to(ray_pos);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+ }
+ }
+ }
+
+ bool is_plane_translate = false;
+ // plane select
+ if (col_axis == -1) {
+ col_d = 1e20;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
+ Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
+
+ Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
+
+ Vector3 r;
+ Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
+
+ if (plane.intersects_ray(ray_pos, ray, &r)) {
+
+ float dist = r.distance_to(grabber_pos);
+ if (dist < (gs * GIZMO_PLANE_SIZE)) {
+
+ float d = ray_pos.distance_to(r);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+
+ is_plane_translate = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (col_axis != -1) {
+
+ if (p_highlight_only) {
+
+ spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_translate ? 6 : 0));
+
+ } else {
+ //handle plane translate
+ _edit.mode = TRANSFORM_TRANSLATE;
+ _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+ _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_translate ? 3 : 0));
+ }
+ return true;
+ }
+ }
+
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
+
+ int col_axis = -1;
+ float col_d = 1e20;
+
+ for (int i = 0; i < 3; i++) {
+
+ Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
+ Vector3 r;
+ if (!plane.intersects_ray(ray_pos, ray, &r))
+ continue;
+
+ float dist = r.distance_to(gt.origin);
+
+ if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
+
+ float d = ray_pos.distance_to(r);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+ }
+ }
+ }
+
+ if (col_axis != -1) {
+
+ if (p_highlight_only) {
+
+ spatial_editor->select_gizmo_highlight_axis(col_axis + 3);
+ } else {
+ //handle rotate
+ _edit.mode = TRANSFORM_ROTATE;
+ _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+ _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
+ }
+ return true;
+ }
+ }
+
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) {
+
+ int col_axis = -1;
+ float col_d = 1e20;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET;
+ float grabber_radius = gs * GIZMO_ARROW_SIZE;
+
+ Vector3 r;
+
+ if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
+ float d = r.distance_to(ray_pos);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+ }
+ }
+ }
+
+ bool is_plane_scale = false;
+ // plane select
+ if (col_axis == -1) {
+ col_d = 1e20;
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
+ Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
+
+ Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
+
+ Vector3 r;
+ Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
+
+ if (plane.intersects_ray(ray_pos, ray, &r)) {
+
+ float dist = r.distance_to(grabber_pos);
+ if (dist < (gs * GIZMO_PLANE_SIZE)) {
+
+ float d = ray_pos.distance_to(r);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+
+ is_plane_scale = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (col_axis != -1) {
+
+ if (p_highlight_only) {
+
+ spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9));
+
+ } else {
+ //handle scale
+ _edit.mode = TRANSFORM_SCALE;
+ _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+ _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0));
+ }
+ return true;
+ }
+ }
+
+ if (p_highlight_only)
+ spatial_editor->select_gizmo_highlight_axis(-1);
+
+ return false;
+}
+
+void Node3DEditorViewport::_surface_mouse_enter() {
+
+ if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
+ surface->grab_focus();
+}
+
+void Node3DEditorViewport::_surface_mouse_exit() {
+
+ _remove_preview();
+}
+
+void Node3DEditorViewport::_surface_focus_enter() {
+
+ view_menu->set_disable_shortcuts(false);
+}
+
+void Node3DEditorViewport::_surface_focus_exit() {
+
+ view_menu->set_disable_shortcuts(true);
+}
+bool Node3DEditorViewport ::_is_node_locked(const Node *p_node) {
+ return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
+}
+void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
+
+ _find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift());
+
+ Node *scene = editor->get_edited_scene();
+
+ 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())) {
+ //invalid result
+ selection_results.remove(i);
+ i--;
+ }
+ }
+
+ clicked_wants_append = b->get_shift();
+
+ if (selection_results.size() == 1) {
+
+ clicked = selection_results[0].item->get_instance_id();
+ selection_results.clear();
+
+ if (clicked.is_valid()) {
+ _select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != Node3DEditor::TOOL_MODE_LIST_SELECT);
+ clicked = ObjectID();
+ }
+
+ } else if (!selection_results.empty()) {
+
+ NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
+ StringName root_name = root_path.get_name(root_path.get_name_count() - 1);
+
+ for (int i = 0; i < selection_results.size(); i++) {
+
+ Node3D *spat = selection_results[i].item;
+
+ Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node");
+
+ String node_path = "/" + root_name + "/" + root_path.rel_path_to(spat->get_path());
+
+ int locked = 0;
+ if (_is_node_locked(spat)) {
+ locked = 1;
+ } else {
+ Node *ed_scene = editor->get_edited_scene();
+ Node *node = spat;
+
+ while (node && node != ed_scene->get_parent()) {
+ Node3D *selected_tmp = Object::cast_to<Node3D>(node);
+ if (selected_tmp && node->has_meta("_edit_group_")) {
+ locked = 2;
+ }
+ node = node->get_parent();
+ }
+ }
+
+ String suffix = String();
+ if (locked == 1) {
+ suffix = " (" + TTR("Locked") + ")";
+ } else if (locked == 2) {
+ suffix = " (" + TTR("Grouped") + ")";
+ }
+ selection_menu->add_item((String)spat->get_name() + suffix);
+ selection_menu->set_item_icon(i, icon);
+ selection_menu->set_item_metadata(i, node_path);
+ selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path);
+ }
+
+ selection_menu->set_position(get_screen_transform().xform(b->get_position()));
+ selection_menu->popup();
+ }
+}
+
+void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
+
+ if (previewing)
+ return; //do NONE
+
+ {
+ EditorNode *en = editor;
+ EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
+ if (!force_input_forwarding_list->empty()) {
+ bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
+ if (discard)
+ return;
+ }
+ }
+ {
+ EditorNode *en = editor;
+ EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
+ if (!over_plugin_list->empty()) {
+ bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
+ if (discard)
+ return;
+ }
+ }
+
+ Ref<InputEventMouseButton> b = p_event;
+
+ if (b.is_valid()) {
+ emit_signal("clicked", this);
+
+ float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor();
+ switch (b->get_button_index()) {
+
+ case 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: {
+ if (is_freelook_active())
+ scale_freelook_speed(1.0 / zoom_factor);
+ else
+ scale_cursor_distance(zoom_factor);
+ } break;
+
+ case 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()) {
+ //restore
+ _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true);
+ _edit.gizmo = Ref<EditorNode3DGizmo>();
+ }
+
+ if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) {
+
+ if (b->get_alt()) {
+
+ if (nav_scheme == NAVIGATION_MAYA)
+ break;
+
+ _list_select(b);
+ return;
+ }
+ }
+
+ if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) {
+ //cancel motion
+ _edit.mode = TRANSFORM_NONE;
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ sp->set_global_transform(se->original);
+ }
+ surface->update();
+ set_message(TTR("Transform Aborted."), 3);
+ }
+
+ if (b->is_pressed()) {
+ const int mod = _get_key_modifier(b);
+ if (!orthogonal) {
+ if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
+ set_freelook_active(true);
+ }
+ }
+ } else {
+ set_freelook_active(false);
+ }
+
+ if (freelook_active && !surface->has_focus()) {
+ // Focus usually doesn't trigger on right-click, but in case of freelook it should,
+ // otherwise using keyboard navigation would misbehave
+ surface->grab_focus();
+ }
+
+ } break;
+ case BUTTON_MIDDLE: {
+
+ if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) {
+
+ switch (_edit.plane) {
+
+ case TRANSFORM_VIEW: {
+
+ _edit.plane = TRANSFORM_X_AXIS;
+ set_message(TTR("X-Axis Transform."), 2);
+ name = "";
+ _update_name();
+ } break;
+ case TRANSFORM_X_AXIS: {
+
+ _edit.plane = TRANSFORM_Y_AXIS;
+ set_message(TTR("Y-Axis Transform."), 2);
+
+ } break;
+ case TRANSFORM_Y_AXIS: {
+
+ _edit.plane = TRANSFORM_Z_AXIS;
+ set_message(TTR("Z-Axis Transform."), 2);
+
+ } break;
+ case TRANSFORM_Z_AXIS: {
+
+ _edit.plane = TRANSFORM_VIEW;
+ set_message(TTR("View Plane Transform."), 2);
+
+ } break;
+ case TRANSFORM_YZ:
+ case TRANSFORM_XZ:
+ case TRANSFORM_XY: {
+ } break;
+ }
+ }
+ } break;
+ case 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()) {
+ break;
+ }
+
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_LIST_SELECT) {
+ _list_select(b);
+ break;
+ }
+
+ _edit.mouse_pos = b->get_position();
+ _edit.snap = spatial_editor->is_snap_enabled();
+ _edit.mode = TRANSFORM_NONE;
+
+ //gizmo has priority over everything
+
+ bool can_select_gizmos = true;
+
+ {
+ int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
+ can_select_gizmos = view_menu->get_popup()->is_item_checked(idx);
+ }
+
+ if (can_select_gizmos && spatial_editor->get_selected()) {
+
+ Ref<EditorNode3DGizmo> seg = spatial_editor->get_selected()->get_gizmo();
+ if (seg.is_valid()) {
+ int handle = -1;
+ Vector3 point;
+ Vector3 normal;
+ bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b->get_shift());
+ if (inters && handle != -1) {
+
+ _edit.gizmo = seg;
+ _edit.gizmo_handle = handle;
+ _edit.gizmo_initial_value = seg->get_handle_value(handle);
+ break;
+ }
+ }
+ }
+
+ if (_gizmo_select(_edit.mouse_pos))
+ break;
+
+ 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) {
+
+ /* HANDLE ROTATION */
+ if (get_selected_count() == 0)
+ break; //bye
+ //handle rotate
+ _edit.mode = TRANSFORM_ROTATE;
+ _compute_edit(b->get_position());
+ break;
+ }
+
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
+
+ if (get_selected_count() == 0)
+ break; //bye
+ //handle translate
+ _edit.mode = TRANSFORM_TRANSLATE;
+ _compute_edit(b->get_position());
+ break;
+ }
+
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) {
+
+ if (get_selected_count() == 0)
+ break; //bye
+ //handle scale
+ _edit.mode = TRANSFORM_SCALE;
+ _compute_edit(b->get_position());
+ break;
+ }
+
+ // todo scale
+
+ int gizmo_handle = -1;
+
+ clicked = _select_ray(b->get_position(), b->get_shift(), clicked_includes_current, &gizmo_handle, b->get_shift());
+
+ //clicking is always deferred to either move or release
+
+ clicked_wants_append = b->get_shift();
+
+ if (clicked.is_null()) {
+
+ if (!clicked_wants_append)
+ _clear_selected();
+
+ //default to regionselect
+ cursor.region_select = true;
+ cursor.region_begin = b->get_position();
+ cursor.region_end = b->get_position();
+ }
+
+ if (clicked.is_valid() && gizmo_handle >= 0) {
+
+ Node3D *spa = Object::cast_to<Node3D>(ObjectDB::get_instance(clicked));
+ if (spa) {
+
+ Ref<EditorNode3DGizmo> seg = spa->get_gizmo();
+ if (seg.is_valid()) {
+
+ _edit.gizmo = seg;
+ _edit.gizmo_handle = gizmo_handle;
+ _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle);
+ break;
+ }
+ }
+ }
+
+ surface->update();
+ } else {
+
+ if (_edit.gizmo.is_valid()) {
+
+ _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false);
+ _edit.gizmo = Ref<EditorNode3DGizmo>();
+ break;
+ }
+ if (clicked.is_valid()) {
+ _select_clicked(clicked_wants_append, true);
+ // Processing was deferred.
+ clicked = ObjectID();
+ }
+
+ if (cursor.region_select) {
+
+ if (!clicked_wants_append) _clear_selected();
+
+ _select_region();
+ cursor.region_select = false;
+ surface->update();
+ }
+
+ if (_edit.mode != TRANSFORM_NONE) {
+
+ static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" };
+ undo_redo->create_action(_transform_name[_edit.mode]);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
+ undo_redo->add_undo_method(sp, "set_global_transform", se->original);
+ }
+ undo_redo->commit_action();
+ _edit.mode = TRANSFORM_NONE;
+ set_message("");
+ }
+
+ surface->update();
+ }
+
+ } break;
+ }
+ }
+
+ Ref<InputEventMouseMotion> m = p_event;
+
+ if (m.is_valid()) {
+
+ _edit.mouse_pos = m->get_position();
+
+ if (spatial_editor->get_selected()) {
+
+ Ref<EditorNode3DGizmo> seg = spatial_editor->get_selected()->get_gizmo();
+ if (seg.is_valid()) {
+
+ int selected_handle = -1;
+
+ int handle = -1;
+ Vector3 point;
+ Vector3 normal;
+ bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, false);
+ if (inters && handle != -1) {
+
+ selected_handle = handle;
+ }
+
+ if (selected_handle != spatial_editor->get_over_gizmo_handle()) {
+ spatial_editor->set_over_gizmo_handle(selected_handle);
+ spatial_editor->get_selected()->update_gizmo();
+ if (selected_handle != -1)
+ spatial_editor->select_gizmo_highlight_axis(-1);
+ }
+ }
+ }
+
+ if (spatial_editor->get_over_gizmo_handle() == -1 && !(m->get_button_mask() & 1) && !_edit.gizmo.is_valid()) {
+
+ _gizmo_select(_edit.mouse_pos, true);
+ }
+
+ NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ NavigationMode nav_mode = NAVIGATION_NONE;
+
+ if (_edit.gizmo.is_valid()) {
+
+ _edit.gizmo->set_handle(_edit.gizmo_handle, camera, m->get_position());
+ Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle);
+ String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
+ set_message(n + ": " + String(v));
+
+ } else if (m->get_button_mask() & 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()) {
+ nav_mode = NAVIGATION_PAN;
+ } else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_control()) {
+ nav_mode = NAVIGATION_ZOOM;
+ } else if (nav_scheme == NAVIGATION_MODO && m->get_alt()) {
+ nav_mode = NAVIGATION_ORBIT;
+ } else {
+ if (clicked.is_valid()) {
+
+ if (!clicked_includes_current) {
+
+ _select_clicked(clicked_wants_append, true);
+ // Processing was deferred.
+ }
+
+ _compute_edit(_edit.mouse_pos);
+ clicked = ObjectID();
+
+ _edit.mode = TRANSFORM_TRANSLATE;
+ }
+
+ if (cursor.region_select) {
+ cursor.region_end = m->get_position();
+ surface->update();
+ return;
+ }
+
+ if (_edit.mode == TRANSFORM_NONE)
+ return;
+
+ 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");
+ int snap_step_decimals = Math::range_step_decimals(snap);
+
+ switch (_edit.mode) {
+
+ case TRANSFORM_SCALE: {
+
+ Vector3 motion_mask;
+ Plane plane;
+ bool plane_mv = false;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ motion_mask = Vector3(0, 0, 0);
+ plane = Plane(_edit.center, _get_camera_normal());
+ break;
+ case TRANSFORM_X_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+ break;
+ case TRANSFORM_Y_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+ break;
+ case TRANSFORM_Z_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+ break;
+ case TRANSFORM_YZ:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
+ plane_mv = true;
+ break;
+ case TRANSFORM_XZ:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0);
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
+ plane_mv = true;
+ break;
+ case TRANSFORM_XY:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
+ plane_mv = true;
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection))
+ break;
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
+ break;
+
+ Vector3 motion = intersection - click;
+ if (_edit.plane != TRANSFORM_VIEW) {
+
+ if (!plane_mv) {
+
+ motion = motion_mask.dot(motion) * motion_mask;
+
+ } else {
+
+ // Alternative planar scaling mode
+ if (_get_key_modifier(m) != KEY_SHIFT) {
+ motion = motion_mask.dot(motion) * motion_mask;
+ }
+ }
+
+ } else {
+ float center_click_dist = click.distance_to(_edit.center);
+ float center_inters_dist = intersection.distance_to(_edit.center);
+ if (center_click_dist == 0)
+ break;
+
+ float scale = center_inters_dist - center_click_dist;
+ motion = Vector3(scale, scale, scale);
+ }
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_scale_snap() / 100;
+ }
+ Vector3 motion_snapped = motion;
+ motion_snapped.snap(Vector3(snap, snap, snap));
+ // This might not be necessary anymore after issue #288 is solved (in 4.0?).
+ set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ Transform original = se->original;
+ Transform original_local = se->original_local;
+ Transform base = Transform(Basis(), _edit.center);
+ Transform t;
+ Vector3 local_scale;
+
+ if (local_coords) {
+
+ Basis g = original.basis.orthonormalized();
+ Vector3 local_motion = g.inverse().xform(motion);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ local_motion.snap(Vector3(snap, snap, snap));
+ }
+
+ local_scale = original_local.basis.get_scale() * (local_motion + Vector3(1, 1, 1));
+
+ // Prevent scaling to 0 it would break the gizmo
+ Basis check = original_local.basis;
+ check.scale(local_scale);
+ if (check.determinant() != 0) {
+
+ // Apply scale
+ sp->set_scale(local_scale);
+ }
+
+ } else {
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ motion.snap(Vector3(snap, snap, snap));
+ }
+
+ Transform r;
+ r.basis.scale(motion + Vector3(1, 1, 1));
+ t = base * (r * (base.inverse() * original));
+
+ // Apply scale
+ sp->set_global_transform(t);
+ }
+ }
+
+ surface->update();
+
+ } break;
+
+ case TRANSFORM_TRANSLATE: {
+
+ Vector3 motion_mask;
+ Plane plane;
+ bool plane_mv = false;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ plane = Plane(_edit.center, _get_camera_normal());
+ break;
+ case TRANSFORM_X_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+ break;
+ case TRANSFORM_Y_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+ break;
+ case TRANSFORM_Z_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
+ break;
+ case TRANSFORM_YZ:
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
+ plane_mv = true;
+ break;
+ case TRANSFORM_XZ:
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
+ plane_mv = true;
+ break;
+ case TRANSFORM_XY:
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
+ plane_mv = true;
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection))
+ break;
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
+ break;
+
+ Vector3 motion = intersection - click;
+ if (_edit.plane != TRANSFORM_VIEW) {
+ if (!plane_mv) {
+ motion = motion_mask.dot(motion) * motion_mask;
+ }
+ }
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_translate_snap();
+ }
+ Vector3 motion_snapped = motion;
+ motion_snapped.snap(Vector3(snap, snap, snap));
+ set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ Transform original = se->original;
+ Transform t;
+
+ if (local_coords) {
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ Basis g = original.basis.orthonormalized();
+ Vector3 local_motion = g.inverse().xform(motion);
+ local_motion.snap(Vector3(snap, snap, snap));
+
+ motion = g.xform(local_motion);
+ }
+
+ } else {
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ motion.snap(Vector3(snap, snap, snap));
+ }
+ }
+
+ // Apply translation
+ t = original;
+ t.origin += motion;
+ sp->set_global_transform(t);
+ }
+
+ surface->update();
+
+ } break;
+
+ case TRANSFORM_ROTATE: {
+
+ Plane plane;
+ Vector3 axis;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ plane = Plane(_edit.center, _get_camera_normal());
+ break;
+ case TRANSFORM_X_AXIS:
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
+ axis = Vector3(1, 0, 0);
+ break;
+ case TRANSFORM_Y_AXIS:
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
+ axis = Vector3(0, 1, 0);
+ break;
+ case TRANSFORM_Z_AXIS:
+ plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
+ axis = Vector3(0, 0, 1);
+ break;
+ case TRANSFORM_YZ:
+ case TRANSFORM_XZ:
+ case TRANSFORM_XY:
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection))
+ break;
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
+ break;
+
+ 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));
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_rotate_snap();
+ }
+ angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
+ angle -= Math::fmod(angle, snap);
+ set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
+ angle = Math::deg2rad(angle);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ Transform t;
+
+ if (local_coords) {
+
+ Transform original_local = se->original_local;
+ Basis rot = Basis(axis, angle);
+
+ t.basis = original_local.get_basis().orthonormalized() * rot;
+ t.origin = original_local.origin;
+
+ // Apply rotation
+ sp->set_transform(t);
+ sp->set_scale(original_local.basis.get_scale()); // re-apply original scale
+
+ } else {
+
+ Transform original = se->original;
+ Transform r;
+ Transform base = Transform(Basis(), _edit.center);
+
+ r.basis.rotate(plane.normal, angle);
+ t = base * r * base.inverse() * original;
+
+ // Apply rotation
+ sp->set_global_transform(t);
+ }
+ }
+
+ surface->update();
+
+ } break;
+ default: {
+ }
+ }
+ }
+
+ } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) {
+
+ if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
+ nav_mode = NAVIGATION_ZOOM;
+ } else if (freelook_active) {
+ nav_mode = NAVIGATION_LOOK;
+ } else if (orthogonal) {
+ nav_mode = NAVIGATION_PAN;
+ }
+
+ } else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
+
+ 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")) {
+ nav_mode = NAVIGATION_ZOOM;
+ } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
+ // 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())
+ 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);
+
+ if (mod) {
+ 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")) {
+ nav_mode = NAVIGATION_ZOOM;
+ } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
+ // Always allow Alt as a modifier to better support graphic tablets.
+ nav_mode = NAVIGATION_ORBIT;
+ }
+ }
+ }
+
+ switch (nav_mode) {
+ case NAVIGATION_PAN: {
+ _nav_pan(m, _get_warped_mouse_motion(m));
+
+ } break;
+
+ case NAVIGATION_ZOOM: {
+ _nav_zoom(m, m->get_relative());
+
+ } break;
+
+ case NAVIGATION_ORBIT: {
+ _nav_orbit(m, _get_warped_mouse_motion(m));
+
+ } break;
+
+ case NAVIGATION_LOOK: {
+ _nav_look(m, _get_warped_mouse_motion(m));
+
+ } break;
+
+ default: {
+ }
+ }
+ }
+
+ Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
+ if (magnify_gesture.is_valid()) {
+
+ if (is_freelook_active())
+ scale_freelook_speed(magnify_gesture->get_factor());
+ else
+ scale_cursor_distance(1.0 / magnify_gesture->get_factor());
+ }
+
+ Ref<InputEventPanGesture> pan_gesture = p_event;
+ if (pan_gesture.is_valid()) {
+
+ NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ NavigationMode nav_mode = NAVIGATION_NONE;
+
+ if (nav_scheme == NAVIGATION_GODOT) {
+
+ const int mod = _get_key_modifier(pan_gesture);
+
+ 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")) {
+ nav_mode = NAVIGATION_ZOOM;
+ } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
+ // Always allow Alt as a modifier to better support graphic tablets.
+ nav_mode = NAVIGATION_ORBIT;
+ }
+
+ } else if (nav_scheme == NAVIGATION_MAYA) {
+ if (pan_gesture->get_alt())
+ nav_mode = NAVIGATION_PAN;
+ }
+
+ switch (nav_mode) {
+ case NAVIGATION_PAN: {
+ _nav_pan(m, pan_gesture->get_delta());
+
+ } break;
+
+ case NAVIGATION_ZOOM: {
+ _nav_zoom(m, pan_gesture->get_delta());
+
+ } break;
+
+ case NAVIGATION_ORBIT: {
+ _nav_orbit(m, pan_gesture->get_delta());
+
+ } break;
+
+ case NAVIGATION_LOOK: {
+ _nav_look(m, pan_gesture->get_delta());
+
+ } break;
+
+ default: {
+ }
+ }
+ }
+
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid()) {
+ if (!k->is_pressed())
+ return;
+
+ if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
+ if (_edit.mode != TRANSFORM_NONE) {
+ _edit.snap = !_edit.snap;
+ }
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
+ _menu_option(VIEW_BOTTOM);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) {
+ _menu_option(VIEW_TOP);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) {
+ _menu_option(VIEW_REAR);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) {
+ _menu_option(VIEW_FRONT);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) {
+ _menu_option(VIEW_LEFT);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) {
+ _menu_option(VIEW_RIGHT);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/focus_origin", p_event)) {
+ _menu_option(VIEW_CENTER_TO_ORIGIN);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) {
+ _menu_option(VIEW_CENTER_TO_SELECTION);
+ }
+ // Orthgonal mode doesn't work in freelook.
+ if (!freelook_active && ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
+ _menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
+ _update_name();
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/align_transform_with_view", p_event)) {
+ _menu_option(VIEW_ALIGN_TRANSFORM_WITH_VIEW);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/align_rotation_with_view", p_event)) {
+ _menu_option(VIEW_ALIGN_ROTATION_WITH_VIEW);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) {
+ if (!get_selected_count() || _edit.mode != TRANSFORM_NONE)
+ return;
+
+ if (!AnimationPlayerEditor::singleton->get_track_editor()->has_keying()) {
+ set_message(TTR("Keying is disabled (no key inserted)."));
+ return;
+ }
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ spatial_editor->emit_signal("transform_key_request", sp, "", sp->get_transform());
+ }
+
+ set_message(TTR("Animation Key Inserted."));
+ }
+
+ // Freelook doesn't work in orthogonal mode.
+ if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
+ set_freelook_active(!is_freelook_active());
+
+ } else if (k->get_keycode() == KEY_ESCAPE) {
+ set_freelook_active(false);
+ }
+
+ if (k->get_keycode() == KEY_SPACE) {
+ if (!k->is_pressed()) emit_signal("toggle_maximize_view", this);
+ }
+ }
+
+ // freelook uses most of the useful shortcuts, like save, so its ok
+ // to consider freelook active as end of the line for future events.
+ if (freelook_active)
+ accept_event();
+}
+
+void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
+
+ const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+
+ real_t pan_speed = 1 / 150.0;
+ int pan_speed_modifier = 10;
+ if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
+ pan_speed *= pan_speed_modifier;
+
+ Transform camera_transform;
+
+ camera_transform.translate(cursor.pos);
+ camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
+ camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
+ Vector3 translation(-p_relative.x * pan_speed, p_relative.y * pan_speed, 0);
+ translation *= cursor.distance / DISTANCE_DEFAULT;
+ camera_transform.translate(translation);
+ cursor.pos = camera_transform.origin;
+}
+
+void Node3DEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
+
+ const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+
+ real_t zoom_speed = 1 / 80.0;
+ int zoom_speed_modifier = 10;
+ if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
+ zoom_speed *= zoom_speed_modifier;
+
+ NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
+ if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
+ if (p_relative.x > 0)
+ scale_cursor_distance(1 - p_relative.x * zoom_speed);
+ else if (p_relative.x < 0)
+ scale_cursor_distance(1.0 / (1 + p_relative.x * zoom_speed));
+ } else {
+ if (p_relative.y > 0)
+ scale_cursor_distance(1 + p_relative.y * zoom_speed);
+ else if (p_relative.y < 0)
+ scale_cursor_distance(1.0 / (1 - p_relative.y * zoom_speed));
+ }
+}
+
+void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
+
+ if (lock_rotation) {
+ _nav_pan(p_event, p_relative);
+ return;
+ }
+
+ if (orthogonal && auto_orthogonal) {
+ _menu_option(VIEW_PERSPECTIVE);
+ }
+
+ real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
+ real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+
+ if (invert_y_axis) {
+ cursor.x_rot -= p_relative.y * radians_per_pixel;
+ } else {
+ cursor.x_rot += p_relative.y * radians_per_pixel;
+ }
+ cursor.y_rot += p_relative.x * radians_per_pixel;
+ if (cursor.x_rot > Math_PI / 2.0)
+ cursor.x_rot = Math_PI / 2.0;
+ if (cursor.x_rot < -Math_PI / 2.0)
+ cursor.x_rot = -Math_PI / 2.0;
+ name = "";
+ _update_name();
+}
+
+void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
+
+ if (orthogonal) {
+ _nav_pan(p_event, p_relative);
+ return;
+ }
+
+ if (orthogonal && auto_orthogonal) {
+ _menu_option(VIEW_PERSPECTIVE);
+ }
+
+ real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
+ real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+
+ // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
+ Transform prev_camera_transform = to_camera_transform(cursor);
+
+ if (invert_y_axis) {
+ cursor.x_rot -= p_relative.y * radians_per_pixel;
+ } else {
+ cursor.x_rot += p_relative.y * radians_per_pixel;
+ }
+ cursor.y_rot += p_relative.x * radians_per_pixel;
+ if (cursor.x_rot > Math_PI / 2.0)
+ cursor.x_rot = Math_PI / 2.0;
+ if (cursor.x_rot < -Math_PI / 2.0)
+ cursor.x_rot = -Math_PI / 2.0;
+
+ // Look is like the opposite of Orbit: the focus point rotates around the camera
+ Transform camera_transform = to_camera_transform(cursor);
+ Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 diff = prev_pos - pos;
+ cursor.pos += diff;
+
+ name = "";
+ _update_name();
+}
+
+void Node3DEditorViewport::set_freelook_active(bool active_now) {
+
+ if (!freelook_active && active_now) {
+ // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
+ cursor = camera_cursor;
+
+ // Make sure eye_pos is synced, because freelook referential is eye pos rather than orbit pos
+ Vector3 forward = to_camera_transform(cursor).basis.xform(Vector3(0, 0, -1));
+ cursor.eye_pos = cursor.pos - cursor.distance * forward;
+ // Also sync the camera cursor, otherwise switching to freelook will be trippy if inertia is active
+ camera_cursor.eye_pos = cursor.eye_pos;
+
+ if (EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_speed_zoom_link")) {
+ // Re-adjust freelook speed from the current zoom level
+ real_t base_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
+ freelook_speed = base_speed * cursor.distance;
+ }
+
+ // Hide mouse like in an FPS (warping doesn't work)
+ DisplayServer::get_singleton()->mouse_set_mode(DisplayServer::MOUSE_MODE_CAPTURED);
+
+ } else if (freelook_active && !active_now) {
+ // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
+ cursor = camera_cursor;
+
+ // Restore mouse
+ DisplayServer::get_singleton()->mouse_set_mode(DisplayServer::MOUSE_MODE_VISIBLE);
+ }
+
+ freelook_active = active_now;
+}
+
+void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
+
+ // Prevents zero distance which would short-circuit any scaling
+ if (cursor.distance < ZOOM_MIN_DISTANCE)
+ cursor.distance = ZOOM_MIN_DISTANCE;
+
+ cursor.distance *= scale;
+
+ if (cursor.distance < ZOOM_MIN_DISTANCE)
+ cursor.distance = ZOOM_MIN_DISTANCE;
+
+ zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
+ surface->update();
+}
+
+void Node3DEditorViewport::scale_freelook_speed(real_t scale) {
+
+ // Prevents zero distance which would short-circuit any scaling
+ if (freelook_speed < FREELOOK_MIN_SPEED)
+ freelook_speed = FREELOOK_MIN_SPEED;
+
+ freelook_speed *= scale;
+
+ if (freelook_speed < FREELOOK_MIN_SPEED)
+ freelook_speed = FREELOOK_MIN_SPEED;
+
+ zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
+ surface->update();
+}
+
+Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const {
+ Point2i relative;
+ if (bool(EDITOR_DEF("editors/3d/navigation/warped_mouse_panning", false))) {
+ relative = InputFilter::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect());
+ } else {
+ relative = p_ev_mouse_motion->get_relative();
+ }
+ return relative;
+}
+
+static bool is_shortcut_pressed(const String &p_path) {
+ Ref<ShortCut> shortcut = ED_GET_SHORTCUT(p_path);
+ if (shortcut.is_null()) {
+ return false;
+ }
+ InputEventKey *k = Object::cast_to<InputEventKey>(shortcut->get_shortcut().ptr());
+ if (k == nullptr) {
+ return false;
+ }
+ const InputFilter &input = *InputFilter::get_singleton();
+ int keycode = k->get_keycode();
+ return input.is_key_pressed(keycode);
+}
+
+void Node3DEditorViewport::_update_freelook(real_t delta) {
+
+ if (!is_freelook_active()) {
+ return;
+ }
+
+ const Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1));
+ const Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0));
+ const Vector3 up = camera->get_transform().basis.xform(Vector3(0, 1, 0));
+
+ Vector3 direction;
+
+ if (is_shortcut_pressed("spatial_editor/freelook_left")) {
+ direction -= right;
+ }
+ if (is_shortcut_pressed("spatial_editor/freelook_right")) {
+ direction += right;
+ }
+ if (is_shortcut_pressed("spatial_editor/freelook_forward")) {
+ direction += forward;
+ }
+ if (is_shortcut_pressed("spatial_editor/freelook_backwards")) {
+ direction -= forward;
+ }
+ if (is_shortcut_pressed("spatial_editor/freelook_up")) {
+ direction += up;
+ }
+ if (is_shortcut_pressed("spatial_editor/freelook_down")) {
+ direction -= up;
+ }
+
+ real_t speed = freelook_speed;
+
+ if (is_shortcut_pressed("spatial_editor/freelook_speed_modifier")) {
+ speed *= 3.0;
+ }
+ if (is_shortcut_pressed("spatial_editor/freelook_slow_modifier")) {
+ speed *= 0.333333;
+ }
+
+ const Vector3 motion = direction * speed * delta;
+ cursor.pos += motion;
+ cursor.eye_pos += motion;
+}
+
+void Node3DEditorViewport::set_message(String p_message, float p_time) {
+
+ message = p_message;
+ message_time = p_time;
+}
+
+void Node3DEditorPlugin::edited_scene_changed() {
+ for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) {
+ Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(i);
+ if (viewport->is_visible()) {
+ viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED);
+ }
+ }
+}
+
+void Node3DEditorViewport::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ bool visible = is_visible_in_tree();
+
+ set_process(visible);
+
+ if (visible) {
+ orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
+ _update_name();
+ _update_camera(0);
+ } else {
+ set_freelook_active(false);
+ }
+ call_deferred("update_transform_gizmo_view");
+ rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo"));
+ }
+
+ if (p_what == NOTIFICATION_RESIZED) {
+
+ call_deferred("update_transform_gizmo_view");
+ }
+
+ if (p_what == NOTIFICATION_READY) {
+ // The crosshair icon doesn't depend on the editor theme.
+ crosshair->set_texture(get_theme_icon("Crosshair", "EditorIcons"));
+ // Set the anchors and margins after changing the icon to ensure it's centered correctly.
+ crosshair->set_anchors_and_margins_preset(PRESET_CENTER);
+ }
+
+ if (p_what == NOTIFICATION_PROCESS) {
+
+ real_t delta = get_process_delta_time();
+
+ if (zoom_indicator_delay > 0) {
+ zoom_indicator_delay -= delta;
+ if (zoom_indicator_delay <= 0) {
+ surface->update();
+ }
+ }
+
+ _update_freelook(delta);
+
+ Node *scene_root = editor->get_scene_tree_dock()->get_editor_data()->get_edited_scene_root();
+ if (previewing_cinema && scene_root != nullptr) {
+ Camera3D *cam = scene_root->get_viewport()->get_camera();
+ if (cam != nullptr && cam != previewing) {
+ //then switch the viewport's camera to the scene's viewport camera
+ if (previewing != nullptr) {
+ previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ }
+ previewing = cam;
+ previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera());
+ surface->update();
+ }
+ }
+
+ _update_camera(delta);
+
+ Map<Node *, Object *> &selection = editor_selection->get_selection();
+
+ bool changed = false;
+ bool exist = false;
+
+ for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->key());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ Transform t = sp->get_global_gizmo_transform();
+
+ exist = true;
+ if (se->last_xform == t && !se->last_xform_dirty)
+ continue;
+ changed = true;
+ se->last_xform_dirty = false;
+ se->last_xform = t;
+
+ VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp);
+
+ se->aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
+
+ t.translate(se->aabb.position);
+
+ // apply AABB scaling before item's global transform
+ Basis aabb_s;
+ aabb_s.scale(se->aabb.size);
+ t.basis = t.basis * aabb_s;
+
+ RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
+ }
+
+ if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
+ spatial_editor->update_transform_gizmo();
+ }
+
+ if (message_time > 0) {
+
+ if (message != last_message) {
+ surface->update();
+ last_message = message;
+ }
+
+ message_time -= get_physics_process_delta_time();
+ if (message_time < 0)
+ surface->update();
+ }
+
+ //update shadow atlas if changed
+
+ int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size");
+ 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_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 if changed
+
+ int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/screen_filters/msaa");
+ viewport->set_msaa(Viewport::MSAA(msaa_mode));
+ int ssaa_mode = GLOBAL_GET("rendering/quality/screen_filters/screen_space_aa");
+ viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
+
+ 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);
+ }
+
+ Camera3D *current_camera;
+
+ if (previewing) {
+ current_camera = previewing;
+ } else {
+ current_camera = camera;
+ }
+
+ // Display the crosshair only while freelooking. Hide it otherwise,
+ // as the crosshair can be distracting.
+ crosshair->set_visible(freelook_active);
+
+ if (show_info) {
+ String text;
+ text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n";
+ text += "Y: " + rtos(current_camera->get_translation().y).pad_decimals(1) + "\n";
+ text += "Z: " + rtos(current_camera->get_translation().z).pad_decimals(1) + "\n";
+ text += TTR("Pitch") + ": " + itos(Math::round(current_camera->get_rotation_degrees().x)) + "\n";
+ text += TTR("Yaw") + ": " + itos(Math::round(current_camera->get_rotation_degrees().y)) + "\n\n";
+ text += TTR("Objects Drawn") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_OBJECTS_IN_FRAME)) + "\n";
+ text += TTR("Material Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_MATERIAL_CHANGES_IN_FRAME)) + "\n";
+ text += TTR("Shader Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SHADER_CHANGES_IN_FRAME)) + "\n";
+ text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n";
+ text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n";
+ text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME));
+
+ info_label->set_text(text);
+ }
+
+ // FPS Counter.
+ bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
+
+ if (show_fps != fps_label->is_visible()) {
+ fps_label->set_visible(show_fps);
+ RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps);
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ cpu_time_history[i] = 0;
+ gpu_time_history[i] = 0;
+ }
+ cpu_time_history_index = 0;
+ cpu_time_history_index = 0;
+ }
+ if (show_fps) {
+
+ cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid());
+ cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY;
+ float cpu_time = 0.0;
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ cpu_time += cpu_time_history[i];
+ }
+ cpu_time /= FRAME_TIME_HISTORY;
+
+ 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;
+ float gpu_time = 0.0;
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ gpu_time += gpu_time_history[i];
+ }
+ gpu_time /= FRAME_TIME_HISTORY;
+
+ String text;
+ text += TTR("CPU Time") + ": " + String::num(cpu_time, 1) + " ms\n";
+ text += TTR("GPU Time") + ": " + String::num(gpu_time, 1) + " ms\n";
+ text += TTR("FPS") + ": " + itos(1000.0 / gpu_time);
+
+ fps_label->set_text(text);
+ }
+
+ bool show_cinema = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
+ cinema_label->set_visible(show_cinema);
+ if (show_cinema) {
+ float cinema_half_width = cinema_label->get_size().width / 2.0f;
+ cinema_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -cinema_half_width);
+ }
+
+ if (lock_rotation) {
+ float locked_half_width = locked_label->get_size().width / 2.0f;
+ locked_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -locked_half_width);
+ }
+ }
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw));
+ surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput));
+ surface->connect("mouse_entered", callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter));
+ surface->connect("mouse_exited", callable_mp(this, &Node3DEditorViewport::_surface_mouse_exit));
+ surface->connect("focus_entered", callable_mp(this, &Node3DEditorViewport::_surface_focus_enter));
+ surface->connect("focus_exited", callable_mp(this, &Node3DEditorViewport::_surface_focus_exit));
+
+ _init_gizmo_instance(index);
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ _finish_gizmo_instances();
+ }
+
+ if (p_what == NOTIFICATION_THEME_CHANGED) {
+
+ view_menu->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons"));
+ preview_camera->set_icon(get_theme_icon("Camera3D", "EditorIcons"));
+
+ view_menu->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_theme_style_override("hover", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_theme_style_override("pressed", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_theme_style_override("focus", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_theme_style_override("disabled", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+
+ preview_camera->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_theme_style_override("hover", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_theme_style_override("pressed", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_theme_style_override("focus", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_theme_style_override("disabled", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+
+ info_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ fps_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ cinema_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ locked_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles"));
+ }
+}
+
+static void draw_indicator_bar(Control &surface, real_t fill, Ref<Texture2D> icon) {
+
+ // Adjust bar size from control height
+ Vector2 surface_size = surface.get_size();
+ real_t h = surface_size.y / 2.0;
+ real_t y = (surface_size.y - h) / 2.0;
+
+ Rect2 r(10, y, 6, h);
+ real_t sy = r.size.y * fill;
+
+ // Note: because this bar appears over the viewport, it has to stay readable for any background color
+ // Draw both neutral dark and bright colors to account this
+ surface.draw_rect(r, Color(1, 1, 1, 0.2));
+ surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6));
+ surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE));
+
+ Vector2 icon_size = icon->get_size();
+ Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2);
+ surface.draw_texture(icon, icon_pos);
+}
+
+void Node3DEditorViewport::_draw() {
+
+ EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over();
+ if (!over_plugin_list->empty()) {
+ over_plugin_list->forward_spatial_draw_over_viewport(surface);
+ }
+
+ EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
+ if (!force_over_plugin_list->empty()) {
+ force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface);
+ }
+
+ if (surface->has_focus()) {
+ Size2 size = surface->get_size();
+ Rect2 r = Rect2(Point2(), size);
+ get_theme_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r);
+ }
+
+ if (cursor.region_select) {
+ const Rect2 selection_rect = Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin);
+
+ surface->draw_rect(
+ selection_rect,
+ get_theme_color("box_selection_fill_color", "Editor"));
+
+ surface->draw_rect(
+ selection_rect,
+ get_theme_color("box_selection_stroke_color", "Editor"),
+ false,
+ Math::round(EDSCALE));
+ }
+
+ RID ci = surface->get_canvas_item();
+
+ if (message_time > 0) {
+ Ref<Font> font = get_theme_font("font", "Label");
+ Point2 msgpos = Point2(5, get_size().y - 20);
+ font->draw(ci, msgpos + Point2(1, 1), message, Color(0, 0, 0, 0.8));
+ font->draw(ci, msgpos + Point2(-1, -1), message, Color(0, 0, 0, 0.8));
+ font->draw(ci, msgpos, message, Color(1, 1, 1, 1));
+ }
+
+ if (_edit.mode == TRANSFORM_ROTATE) {
+
+ Point2 center = _point_to_screen(_edit.center);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ ci,
+ _edit.mouse_pos,
+ center,
+ get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
+ Math::round(2 * EDSCALE));
+ }
+ if (previewing) {
+
+ Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ float aspect = ss.aspect();
+ Size2 s = get_size();
+
+ Rect2 draw_rect;
+
+ switch (previewing->get_keep_aspect_mode()) {
+ case Camera3D::KEEP_WIDTH: {
+
+ draw_rect.size = Size2(s.width, s.width / aspect);
+ draw_rect.position.x = 0;
+ draw_rect.position.y = (s.height - draw_rect.size.y) * 0.5;
+
+ } break;
+ case Camera3D::KEEP_HEIGHT: {
+
+ draw_rect.size = Size2(s.height * aspect, s.height);
+ draw_rect.position.y = 0;
+ draw_rect.position.x = (s.width - draw_rect.size.x) * 0.5;
+
+ } break;
+ }
+
+ draw_rect = Rect2(Vector2(), s).clip(draw_rect);
+
+ surface->draw_rect(draw_rect, Color(0.6, 0.6, 0.1, 0.5), false, Math::round(2 * EDSCALE));
+
+ } else {
+
+ if (zoom_indicator_delay > 0.0) {
+
+ if (is_freelook_active()) {
+ // Show speed
+
+ real_t min_speed = FREELOOK_MIN_SPEED;
+ real_t max_speed = camera->get_zfar();
+ real_t scale_length = (max_speed - min_speed);
+
+ if (!Math::is_zero_approx(scale_length)) {
+ real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
+
+ // There is no real maximum speed so that factor can become negative,
+ // Let's make it look asymptotic instead (will decrease slower and slower).
+ if (logscale_t < 0.25)
+ logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
+
+ draw_indicator_bar(*surface, 1.0 - logscale_t, get_theme_icon("ViewportSpeed", "EditorIcons"));
+ }
+
+ } else {
+ // Show zoom
+
+ real_t min_distance = ZOOM_MIN_DISTANCE; // TODO Why not pick znear to limit zoom?
+ real_t max_distance = camera->get_zfar();
+ real_t scale_length = (max_distance - min_distance);
+
+ if (!Math::is_zero_approx(scale_length)) {
+ real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
+
+ // There is no real maximum distance so that factor can become negative,
+ // Let's make it look asymptotic instead (will decrease slower and slower).
+ if (logscale_t < 0.25)
+ logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
+
+ draw_indicator_bar(*surface, logscale_t, get_theme_icon("ViewportZoom", "EditorIcons"));
+ }
+ }
+ }
+ }
+}
+
+void Node3DEditorViewport::_menu_option(int p_option) {
+
+ switch (p_option) {
+
+ case VIEW_TOP: {
+
+ cursor.y_rot = 0;
+ cursor.x_rot = Math_PI / 2.0;
+ set_message(TTR("Top View."), 2);
+ name = TTR("Top");
+ _set_auto_orthogonal();
+ _update_name();
+
+ } break;
+ case VIEW_BOTTOM: {
+
+ cursor.y_rot = 0;
+ cursor.x_rot = -Math_PI / 2.0;
+ set_message(TTR("Bottom View."), 2);
+ name = TTR("Bottom");
+ _set_auto_orthogonal();
+ _update_name();
+
+ } break;
+ case VIEW_LEFT: {
+
+ cursor.x_rot = 0;
+ cursor.y_rot = Math_PI / 2.0;
+ set_message(TTR("Left View."), 2);
+ name = TTR("Left");
+ _set_auto_orthogonal();
+ _update_name();
+
+ } break;
+ case VIEW_RIGHT: {
+
+ cursor.x_rot = 0;
+ cursor.y_rot = -Math_PI / 2.0;
+ set_message(TTR("Right View."), 2);
+ name = TTR("Right");
+ _set_auto_orthogonal();
+ _update_name();
+
+ } break;
+ case VIEW_FRONT: {
+
+ cursor.x_rot = 0;
+ cursor.y_rot = 0;
+ set_message(TTR("Front View."), 2);
+ name = TTR("Front");
+ _set_auto_orthogonal();
+ _update_name();
+
+ } break;
+ case VIEW_REAR: {
+
+ cursor.x_rot = 0;
+ cursor.y_rot = Math_PI;
+ set_message(TTR("Rear View."), 2);
+ name = TTR("Rear");
+ _set_auto_orthogonal();
+ _update_name();
+
+ } break;
+ case VIEW_CENTER_TO_ORIGIN: {
+
+ cursor.pos = Vector3(0, 0, 0);
+
+ } break;
+ case VIEW_CENTER_TO_SELECTION: {
+
+ focus_selection();
+
+ } break;
+ case VIEW_ALIGN_TRANSFORM_WITH_VIEW: {
+
+ if (!get_selected_count())
+ break;
+
+ Transform camera_transform = camera->get_global_transform();
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Align Transform with View"));
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ Transform xform;
+ if (orthogonal) {
+ xform = sp->get_global_transform();
+ xform.basis.set_euler(camera_transform.basis.get_euler());
+ } else {
+ xform = camera_transform;
+ xform.scale_basis(sp->get_scale());
+ }
+
+ undo_redo->add_do_method(sp, "set_global_transform", xform);
+ undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
+ }
+ undo_redo->commit_action();
+ focus_selection();
+
+ } break;
+ case VIEW_ALIGN_ROTATION_WITH_VIEW: {
+
+ if (!get_selected_count())
+ break;
+
+ Transform camera_transform = camera->get_global_transform();
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Align Rotation with View"));
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_rotation());
+ undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation());
+ }
+ undo_redo->commit_action();
+
+ } break;
+ case VIEW_ENVIRONMENT: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ if (current) {
+
+ camera->set_environment(RES());
+ } else {
+
+ camera->set_environment(Node3DEditor::get_singleton()->get_viewport_environment());
+ }
+
+ view_menu->get_popup()->set_item_checked(idx, current);
+
+ } break;
+ case VIEW_PERSPECTIVE: {
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false);
+ orthogonal = false;
+ auto_orthogonal = false;
+ call_deferred("update_transform_gizmo_view");
+ _update_name();
+
+ } break;
+ case VIEW_ORTHOGONAL: {
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true);
+ orthogonal = true;
+ auto_orthogonal = false;
+ call_deferred("update_transform_gizmo_view");
+ _update_name();
+
+ } break;
+ case VIEW_AUTO_ORTHOGONAL: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ view_menu->get_popup()->set_item_checked(idx, current);
+ if (auto_orthogonal) {
+ auto_orthogonal = false;
+ _update_name();
+ }
+ } break;
+ case VIEW_LOCK_ROTATION: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ lock_rotation = !current;
+ view_menu->get_popup()->set_item_checked(idx, !current);
+ if (lock_rotation) {
+ locked_label->show();
+ } else {
+ locked_label->hide();
+ }
+
+ } break;
+ case VIEW_AUDIO_LISTENER: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ viewport->set_as_audio_listener(current);
+ view_menu->get_popup()->set_item_checked(idx, current);
+
+ } break;
+ case VIEW_AUDIO_DOPPLER: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ camera->set_doppler_tracking(current ? Camera3D::DOPPLER_TRACKING_IDLE_STEP : Camera3D::DOPPLER_TRACKING_DISABLED);
+ view_menu->get_popup()->set_item_checked(idx, current);
+
+ } break;
+ case VIEW_CINEMATIC_PREVIEW: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ view_menu->get_popup()->set_item_checked(idx, current);
+ previewing_cinema = true;
+ _toggle_cinema_preview(current);
+
+ if (current) {
+ preview_camera->hide();
+ } else {
+ if (previewing != nullptr)
+ preview_camera->show();
+ }
+ } break;
+ case VIEW_GIZMOS: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ if (current)
+ camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
+ else
+ camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_GRID_LAYER));
+ view_menu->get_popup()->set_item_checked(idx, current);
+
+ } break;
+ case VIEW_HALF_RESOLUTION: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ current = !current;
+ view_menu->get_popup()->set_item_checked(idx, current);
+ } break;
+ case VIEW_INFORMATION: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ view_menu->get_popup()->set_item_checked(idx, !current);
+
+ } break;
+ case VIEW_FRAME_TIME: {
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME);
+ bool current = view_menu->get_popup()->is_item_checked(idx);
+ view_menu->get_popup()->set_item_checked(idx, !current);
+
+ } break;
+ case VIEW_DISPLAY_NORMAL:
+ case VIEW_DISPLAY_WIREFRAME:
+ case VIEW_DISPLAY_OVERDRAW:
+ case VIEW_DISPLAY_SHADELESS:
+ case VIEW_DISPLAY_LIGHTING:
+ case VIEW_DISPLAY_NORMAL_BUFFER:
+ case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS:
+ case VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS:
+ case VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO:
+ case VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING:
+ case VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION:
+ case VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE:
+ case VIEW_DISPLAY_DEBUG_SSAO:
+ case VIEW_DISPLAY_DEBUG_PSSM_SPLITS:
+ case VIEW_DISPLAY_DEBUG_DECAL_ATLAS:
+ case VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER: {
+
+ static const int display_options[] = {
+ VIEW_DISPLAY_NORMAL,
+ VIEW_DISPLAY_WIREFRAME,
+ VIEW_DISPLAY_OVERDRAW,
+ VIEW_DISPLAY_SHADELESS,
+ VIEW_DISPLAY_LIGHTING,
+ VIEW_DISPLAY_NORMAL_BUFFER,
+ VIEW_DISPLAY_WIREFRAME,
+ VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
+ VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
+ VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO,
+ VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING,
+ VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
+ VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
+ VIEW_DISPLAY_DEBUG_SSAO,
+ VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
+ VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
+ VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
+ VIEW_MAX
+ };
+ static const Viewport::DebugDraw debug_draw_modes[] = {
+ Viewport::DEBUG_DRAW_DISABLED,
+ Viewport::DEBUG_DRAW_WIREFRAME,
+ Viewport::DEBUG_DRAW_OVERDRAW,
+ Viewport::DEBUG_DRAW_UNSHADED,
+ Viewport::DEBUG_DRAW_LIGHTING,
+ Viewport::DEBUG_DRAW_NORMAL_BUFFER,
+ Viewport::DEBUG_DRAW_WIREFRAME,
+ Viewport::DEBUG_DRAW_SHADOW_ATLAS,
+ Viewport::DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
+ Viewport::DEBUG_DRAW_GI_PROBE_ALBEDO,
+ Viewport::DEBUG_DRAW_GI_PROBE_LIGHTING,
+ Viewport::DEBUG_DRAW_GI_PROBE_EMISSION,
+ Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
+ Viewport::DEBUG_DRAW_SSAO,
+ Viewport::DEBUG_DRAW_ROUGHNESS_LIMITER,
+ Viewport::DEBUG_DRAW_PSSM_SPLITS,
+ Viewport::DEBUG_DRAW_DECAL_ATLAS,
+ };
+
+ int idx = 0;
+
+ while (display_options[idx] != VIEW_MAX) {
+
+ int id = display_options[idx];
+ int item_idx = view_menu->get_popup()->get_item_index(id);
+ if (item_idx != -1) {
+ view_menu->get_popup()->set_item_checked(item_idx, id == p_option);
+ }
+ item_idx = display_submenu->get_item_index(id);
+ if (item_idx != -1) {
+ display_submenu->set_item_checked(item_idx, id == p_option);
+ }
+
+ if (id == p_option) {
+ viewport->set_debug_draw(debug_draw_modes[idx]);
+ }
+ idx++;
+ }
+ } break;
+ }
+}
+
+void Node3DEditorViewport::_set_auto_orthogonal() {
+ if (!orthogonal && view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL))) {
+ _menu_option(VIEW_ORTHOGONAL);
+ auto_orthogonal = true;
+ }
+}
+
+void Node3DEditorViewport::_preview_exited_scene() {
+
+ preview_camera->disconnect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview));
+ preview_camera->set_pressed(false);
+ _toggle_camera_preview(false);
+ preview_camera->connect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview));
+ view_menu->show();
+}
+
+void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
+
+ uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx);
+
+ for (int i = 0; i < 3; i++) {
+ move_gizmo_instance[i] = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid());
+ RS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
+ 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);
+
+ 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());
+ RS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
+ 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);
+
+ 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());
+ RS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
+ 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);
+
+ 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());
+ RS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
+ 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);
+
+ 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());
+ RS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
+ 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);
+ }
+}
+
+void Node3DEditorViewport::_finish_gizmo_instances() {
+
+ for (int i = 0; i < 3; i++) {
+ RS::get_singleton()->free(move_gizmo_instance[i]);
+ RS::get_singleton()->free(move_plane_gizmo_instance[i]);
+ RS::get_singleton()->free(rotate_gizmo_instance[i]);
+ RS::get_singleton()->free(scale_gizmo_instance[i]);
+ RS::get_singleton()->free(scale_plane_gizmo_instance[i]);
+ }
+}
+void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) {
+
+ ERR_FAIL_COND(p_activate && !preview);
+ ERR_FAIL_COND(!p_activate && !previewing);
+
+ if (!p_activate) {
+
+ previewing->disconnect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ previewing = nullptr;
+ RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
+ if (!preview)
+ preview_camera->hide();
+ view_menu->set_disabled(false);
+ surface->update();
+
+ } else {
+
+ previewing = preview;
+ previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
+ view_menu->set_disabled(true);
+ surface->update();
+ }
+}
+
+void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) {
+ previewing_cinema = p_activate;
+ if (!previewing_cinema) {
+ if (previewing != nullptr)
+ previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+
+ previewing = nullptr;
+ RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
+ preview_camera->set_pressed(false);
+ if (!preview) {
+ preview_camera->hide();
+ } else {
+ preview_camera->show();
+ }
+ view_menu->show();
+ surface->update();
+ }
+}
+
+void Node3DEditorViewport::_selection_result_pressed(int p_result) {
+
+ if (selection_results.size() <= p_result)
+ return;
+
+ clicked = selection_results[p_result].item->get_instance_id();
+
+ if (clicked.is_valid()) {
+ _select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != Node3DEditor::TOOL_MODE_LIST_SELECT);
+ clicked = ObjectID();
+ }
+}
+
+void Node3DEditorViewport::_selection_menu_hide() {
+
+ selection_results.clear();
+ selection_menu->clear();
+ selection_menu->set_size(Vector2(0, 0));
+}
+
+void Node3DEditorViewport::set_can_preview(Camera3D *p_preview) {
+
+ preview = p_preview;
+
+ if (!preview_camera->is_pressed() && !previewing_cinema)
+ preview_camera->set_visible(p_preview);
+}
+
+void Node3DEditorViewport::update_transform_gizmo_view() {
+
+ if (!is_visible_in_tree())
+ return;
+
+ Transform xform = spatial_editor->get_gizmo_transform();
+
+ Transform camera_xform = camera->get_transform();
+
+ if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) {
+ for (int i = 0; i < 3; i++) {
+ RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
+ }
+ return;
+ }
+
+ Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
+ Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
+ Plane p(camera_xform.origin, camz);
+ float gizmo_d = Math::abs(p.distance_to(xform.origin));
+ float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
+ float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
+ float dd = Math::abs(d0 - d1);
+ if (dd == 0)
+ dd = 0.0001;
+
+ float gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
+ // At low viewport heights, multiply the gizmo scale based on the viewport height.
+ // This prevents the gizmo from growing very large and going outside the viewport.
+ const int viewport_base_height = 400 * MAX(1, EDSCALE);
+ gizmo_scale =
+ (gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) *
+ MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height /
+ subviewport_container->get_stretch_shrink();
+ Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
+
+ xform.basis.scale(scale);
+
+ for (int i = 0; i < 3; i++) {
+ RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
+ RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
+ RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
+ RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
+ RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
+ }
+}
+
+void Node3DEditorViewport::set_state(const Dictionary &p_state) {
+
+ if (p_state.has("position"))
+ cursor.pos = p_state["position"];
+ if (p_state.has("x_rotation"))
+ cursor.x_rot = p_state["x_rotation"];
+ if (p_state.has("y_rotation"))
+ cursor.y_rot = p_state["y_rotation"];
+ if (p_state.has("distance"))
+ cursor.distance = p_state["distance"];
+
+ if (p_state.has("use_orthogonal")) {
+ bool orth = p_state["use_orthogonal"];
+
+ if (orth)
+ _menu_option(VIEW_ORTHOGONAL);
+ else
+ _menu_option(VIEW_PERSPECTIVE);
+ }
+ if (p_state.has("view_name")) {
+ name = p_state["view_name"];
+ _update_name();
+ }
+ if (p_state.has("auto_orthogonal")) {
+ auto_orthogonal = p_state["auto_orthogonal"];
+ _update_name();
+ }
+ if (p_state.has("auto_orthogonal_enabled")) {
+ bool enabled = p_state["auto_orthogonal_enabled"];
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), enabled);
+ }
+ if (p_state.has("display_mode")) {
+ int display = p_state["display_mode"];
+
+ int idx = view_menu->get_popup()->get_item_index(display);
+ if (!view_menu->get_popup()->is_item_checked(idx))
+ _menu_option(display);
+ }
+ if (p_state.has("lock_rotation")) {
+ lock_rotation = p_state["lock_rotation"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION);
+ view_menu->get_popup()->set_item_checked(idx, lock_rotation);
+ }
+ if (p_state.has("use_environment")) {
+ bool env = p_state["use_environment"];
+
+ if (env != camera->get_environment().is_valid())
+ _menu_option(VIEW_ENVIRONMENT);
+ }
+ if (p_state.has("listener")) {
+ bool listener = p_state["listener"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
+ viewport->set_as_audio_listener(listener);
+ view_menu->get_popup()->set_item_checked(idx, listener);
+ }
+ if (p_state.has("doppler")) {
+ bool doppler = p_state["doppler"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER);
+ camera->set_doppler_tracking(doppler ? Camera3D::DOPPLER_TRACKING_IDLE_STEP : Camera3D::DOPPLER_TRACKING_DISABLED);
+ view_menu->get_popup()->set_item_checked(idx, doppler);
+ }
+ if (p_state.has("gizmos")) {
+ bool gizmos = p_state["gizmos"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
+ if (view_menu->get_popup()->is_item_checked(idx) != gizmos)
+ _menu_option(VIEW_GIZMOS);
+ }
+ if (p_state.has("information")) {
+ bool information = p_state["information"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
+ if (view_menu->get_popup()->is_item_checked(idx) != information)
+ _menu_option(VIEW_INFORMATION);
+ }
+ if (p_state.has("frame_time")) {
+ bool fps = p_state["frame_time"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME);
+ if (view_menu->get_popup()->is_item_checked(idx) != fps)
+ _menu_option(VIEW_FRAME_TIME);
+ }
+ if (p_state.has("half_res")) {
+ bool half_res = p_state["half_res"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
+ view_menu->get_popup()->set_item_checked(idx, half_res);
+ }
+ if (p_state.has("cinematic_preview")) {
+ previewing_cinema = p_state["cinematic_preview"];
+
+ int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW);
+ view_menu->get_popup()->set_item_checked(idx, previewing_cinema);
+ }
+
+ if (preview_camera->is_connected("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview))) {
+ preview_camera->disconnect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview));
+ }
+ if (p_state.has("previewing")) {
+ Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
+ if (Object::cast_to<Camera3D>(pv)) {
+ previewing = Object::cast_to<Camera3D>(pv);
+ previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
+ view_menu->set_disabled(true);
+ surface->update();
+ preview_camera->set_pressed(true);
+ preview_camera->show();
+ }
+ }
+ preview_camera->connect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview));
+}
+
+Dictionary Node3DEditorViewport::get_state() const {
+
+ Dictionary d;
+ d["position"] = cursor.pos;
+ d["x_rotation"] = cursor.x_rot;
+ d["y_rotation"] = cursor.y_rot;
+ d["distance"] = cursor.distance;
+ d["use_environment"] = camera->get_environment().is_valid();
+ d["use_orthogonal"] = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL;
+ d["view_name"] = name;
+ d["auto_orthogonal"] = auto_orthogonal;
+ d["auto_orthogonal_enabled"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL));
+ if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL)))
+ d["display_mode"] = VIEW_DISPLAY_NORMAL;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME)))
+ d["display_mode"] = VIEW_DISPLAY_WIREFRAME;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW)))
+ d["display_mode"] = VIEW_DISPLAY_OVERDRAW;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS)))
+ d["display_mode"] = VIEW_DISPLAY_SHADELESS;
+ d["listener"] = viewport->is_audio_listener();
+ d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
+ d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
+ d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
+ d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
+ d["half_res"] = subviewport_container->get_stretch_shrink() > 1;
+ d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
+ if (previewing)
+ d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
+ if (lock_rotation)
+ d["lock_rotation"] = lock_rotation;
+
+ return d;
+}
+
+void Node3DEditorViewport::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred.
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &Node3DEditorViewport::drop_data_fw);
+
+ ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
+ ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
+}
+
+void Node3DEditorViewport::reset() {
+
+ orthogonal = false;
+ auto_orthogonal = false;
+ lock_rotation = false;
+ message_time = 0;
+ message = "";
+ last_message = "";
+ name = "";
+
+ cursor.x_rot = 0.5;
+ cursor.y_rot = 0.5;
+ cursor.distance = 4;
+ cursor.region_select = false;
+ cursor.pos = Vector3();
+ _update_name();
+}
+
+void Node3DEditorViewport::focus_selection() {
+ if (!get_selected_count())
+ return;
+
+ Vector3 center;
+ int count = 0;
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ center += sp->get_global_gizmo_transform().origin;
+ count++;
+ }
+
+ if (count != 0) {
+ center /= float(count);
+ }
+
+ cursor.pos = center;
+}
+
+void Node3DEditorViewport::assign_pending_data_pointers(Node3D *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept) {
+ preview_node = p_preview_node;
+ preview_bounds = p_preview_bounds;
+ accept = p_accept;
+}
+
+Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const {
+ const float MAX_DISTANCE = 10;
+
+ Vector3 world_ray = _get_ray(p_pos);
+ Vector3 world_pos = _get_ray_pos(p_pos);
+
+ Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario());
+ Set<Ref<EditorNode3DGizmo>> found_gizmos;
+
+ float closest_dist = MAX_DISTANCE;
+
+ Vector3 point = world_pos + world_ray * MAX_DISTANCE;
+ Vector3 normal = Vector3(0.0, 0.0, 0.0);
+
+ for (int i = 0; i < instances.size(); i++) {
+
+ MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(instances[i]));
+
+ if (!mesh_instance)
+ continue;
+
+ Ref<EditorNode3DGizmo> seg = mesh_instance->get_gizmo();
+
+ if ((!seg.is_valid()) || found_gizmos.has(seg)) {
+ continue;
+ }
+
+ found_gizmos.insert(seg);
+
+ Vector3 hit_point;
+ Vector3 hit_normal;
+ bool inters = seg->intersect_ray(camera, p_pos, hit_point, hit_normal, nullptr, false);
+
+ if (!inters)
+ continue;
+
+ float dist = world_pos.distance_to(hit_point);
+
+ if (dist < 0)
+ continue;
+
+ if (dist < closest_dist) {
+ closest_dist = dist;
+ point = hit_point;
+ normal = hit_normal;
+ }
+ }
+ Vector3 offset = Vector3();
+ for (int i = 0; i < 3; i++) {
+ if (normal[i] > 0.0)
+ offset[i] = (preview_bounds->get_size()[i] - (preview_bounds->get_size()[i] + preview_bounds->get_position()[i]));
+ else if (normal[i] < 0.0)
+ offset[i] = -(preview_bounds->get_size()[i] + preview_bounds->get_position()[i]);
+ }
+ return point + offset;
+}
+
+AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_toplevel_transform) {
+ AABB bounds;
+
+ const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_parent);
+ if (mesh_instance) {
+ bounds = mesh_instance->get_aabb();
+ }
+
+ for (int i = 0; i < p_parent->get_child_count(); i++) {
+ Node3D *child = Object::cast_to<Node3D>(p_parent->get_child(i));
+ if (child) {
+ AABB child_bounds = _calculate_spatial_bounds(child, false);
+
+ if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Node3D")) {
+ bounds = child_bounds;
+ } else {
+ bounds.merge_with(child_bounds);
+ }
+ }
+ }
+
+ if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Node3D")) {
+ bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
+ }
+
+ if (!p_exclude_toplevel_transform) {
+ bounds = p_parent->get_transform().xform(bounds);
+ }
+
+ return bounds;
+}
+
+void Node3DEditorViewport::_create_preview(const Vector<String> &files) const {
+ for (int i = 0; i < files.size(); i++) {
+ String path = files[i];
+ RES res = ResourceLoader::load(path);
+ ERR_CONTINUE(res.is_null());
+ Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
+ Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
+ if (mesh != nullptr || scene != nullptr) {
+ if (mesh != nullptr) {
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(mesh);
+ preview_node->add_child(mesh_instance);
+ } else {
+ if (scene.is_valid()) {
+ Node *instance = scene->instance();
+ if (instance) {
+ preview_node->add_child(instance);
+ }
+ }
+ }
+ editor->get_scene_root()->add_child(preview_node);
+ }
+ }
+ *preview_bounds = _calculate_spatial_bounds(preview_node);
+}
+
+void Node3DEditorViewport::_remove_preview() {
+ if (preview_node->get_parent()) {
+ for (int i = preview_node->get_child_count() - 1; i >= 0; i--) {
+ Node *node = preview_node->get_child(i);
+ node->queue_delete();
+ preview_node->remove_child(node);
+ }
+ editor->get_scene_root()->remove_child(preview_node);
+ }
+}
+
+bool Node3DEditorViewport::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) {
+ if (p_desired_node->get_filename() == p_target_scene_path) {
+ return true;
+ }
+
+ int childCount = p_desired_node->get_child_count();
+ for (int i = 0; i < childCount; i++) {
+ Node *child = p_desired_node->get_child(i);
+ if (_cyclical_dependency_exists(p_target_scene_path, child)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
+ RES res = ResourceLoader::load(path);
+ ERR_FAIL_COND_V(res.is_null(), false);
+
+ Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
+ Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
+
+ Node *instanced_scene = nullptr;
+
+ if (mesh != nullptr || scene != nullptr) {
+ if (mesh != nullptr) {
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(mesh);
+ mesh_instance->set_name(path.get_file().get_basename());
+ instanced_scene = mesh_instance;
+ } else {
+ if (!scene.is_valid()) { // invalid scene
+ return false;
+ } else {
+ instanced_scene = scene->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ }
+ }
+ }
+
+ if (instanced_scene == nullptr) {
+ return false;
+ }
+
+ if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing
+ if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) {
+ memdelete(instanced_scene);
+ return false;
+ }
+ }
+
+ if (scene != nullptr) {
+ instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
+ }
+
+ editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
+ editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_reference(instanced_scene);
+ editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene);
+
+ String new_name = parent->validate_child_name(instanced_scene);
+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
+ editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
+ editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+
+ Transform global_transform;
+ Node3D *parent_spatial = Object::cast_to<Node3D>(parent);
+ if (parent_spatial)
+ global_transform = parent_spatial->get_global_gizmo_transform();
+
+ global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
+
+ editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform);
+
+ return true;
+}
+
+void Node3DEditorViewport::_perform_drop_data() {
+ _remove_preview();
+
+ Vector<String> error_files;
+
+ editor_data->get_undo_redo().create_action(TTR("Create Node"));
+
+ for (int i = 0; i < selected_files.size(); i++) {
+ String path = selected_files[i];
+ RES res = ResourceLoader::load(path);
+ if (res.is_null()) {
+ continue;
+ }
+ Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
+ Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
+ if (mesh != nullptr || scene != nullptr) {
+ bool success = _create_instance(target_node, path, drop_pos);
+ if (!success) {
+ error_files.push_back(path);
+ }
+ }
+ }
+
+ editor_data->get_undo_redo().commit_action();
+
+ if (error_files.size() > 0) {
+ String files_str;
+ for (int i = 0; i < error_files.size(); i++) {
+ files_str += error_files[i].get_file().get_basename() + ",";
+ }
+ files_str = files_str.substr(0, files_str.length() - 1);
+ accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
+ accept->popup_centered();
+ }
+}
+
+bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+
+ bool can_instance = false;
+
+ if (!preview_node->is_inside_tree()) {
+ Dictionary d = p_data;
+ if (d.has("type") && (String(d["type"]) == "files")) {
+ Vector<String> files = d["files"];
+
+ List<String> scene_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
+ List<String> mesh_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions);
+
+ for (int i = 0; i < files.size(); i++) {
+ if (mesh_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
+ RES res = ResourceLoader::load(files[i]);
+ if (res.is_null()) {
+ continue;
+ }
+
+ String type = res->get_class();
+ if (type == "PackedScene") {
+ Ref<PackedScene> sdata = ResourceLoader::load(files[i]);
+ Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instanced_scene) {
+ continue;
+ }
+ memdelete(instanced_scene);
+ } else if (type == "Mesh" || type == "ArrayMesh" || type == "PrimitiveMesh") {
+ Ref<Mesh> mesh = ResourceLoader::load(files[i]);
+ if (!mesh.is_valid()) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ can_instance = true;
+ break;
+ }
+ }
+ if (can_instance) {
+ _create_preview(files);
+ }
+ }
+ } else {
+ can_instance = true;
+ }
+
+ if (can_instance) {
+ Transform global_transform = Transform(Basis(), _get_instance_position(p_point));
+ preview_node->set_global_transform(global_transform);
+ }
+
+ return can_instance;
+}
+
+void Node3DEditorViewport::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;
+
+ bool is_shift = InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT);
+
+ selected_files.clear();
+ Dictionary d = p_data;
+ if (d.has("type") && String(d["type"]) == "files") {
+ selected_files = d["files"];
+ }
+
+ List<Node *> list = editor->get_editor_selection()->get_selected_node_list();
+ if (list.size() == 0) {
+ Node *root_node = editor->get_edited_scene();
+ if (root_node) {
+ list.push_back(root_node);
+ } else {
+ accept->set_text(TTR("No parent to instance a child at."));
+ accept->popup_centered();
+ _remove_preview();
+ return;
+ }
+ }
+ if (list.size() != 1) {
+ accept->set_text(TTR("This operation requires a single selected node."));
+ accept->popup_centered();
+ _remove_preview();
+ return;
+ }
+
+ target_node = list[0];
+ if (is_shift && target_node != editor->get_edited_scene()) {
+ target_node = target_node->get_parent();
+ }
+ drop_pos = p_point;
+
+ _perform_drop_data();
+}
+
+Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
+
+ cpu_time_history_index = 0;
+ gpu_time_history_index = 0;
+
+ _edit.mode = TRANSFORM_NONE;
+ _edit.plane = TRANSFORM_VIEW;
+ _edit.edited_gizmo = 0;
+ _edit.snap = 1;
+ _edit.gizmo_handle = 0;
+
+ index = p_index;
+ editor = p_editor;
+ editor_data = editor->get_scene_tree_dock()->get_editor_data();
+ editor_selection = editor->get_editor_selection();
+ undo_redo = editor->get_undo_redo();
+
+ clicked_includes_current = false;
+ orthogonal = false;
+ auto_orthogonal = false;
+ lock_rotation = false;
+ message_time = 0;
+ zoom_indicator_delay = 0.0;
+
+ spatial_editor = p_spatial_editor;
+ SubViewportContainer *c = memnew(SubViewportContainer);
+ subviewport_container = c;
+ c->set_stretch(true);
+ add_child(c);
+ c->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ viewport = memnew(SubViewport);
+ viewport->set_disable_input(true);
+
+ c->add_child(viewport);
+ surface = memnew(Control);
+ surface->set_drag_forwarding(this);
+ add_child(surface);
+ surface->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ surface->set_clip_contents(true);
+ camera = memnew(Camera3D);
+ camera->set_disable_gizmo(true);
+ camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
+ viewport->add_child(camera);
+ camera->make_current();
+ surface->set_focus_mode(FOCUS_ALL);
+
+ crosshair = memnew(TextureRect);
+ crosshair->set_mouse_filter(MOUSE_FILTER_IGNORE);
+ surface->add_child(crosshair);
+
+ VBoxContainer *vbox = memnew(VBoxContainer);
+ surface->add_child(vbox);
+ vbox->set_position(Point2(10, 10) * EDSCALE);
+
+ view_menu = memnew(MenuButton);
+ view_menu->set_flat(false);
+ vbox->add_child(view_menu);
+ view_menu->set_h_size_flags(0);
+
+ display_submenu = memnew(PopupMenu);
+ view_menu->get_popup()->add_child(display_submenu);
+
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/right_view"), VIEW_RIGHT);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_radio_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
+ view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
+ view_menu->get_popup()->add_check_item(TTR("Auto Orthogonal Enabled"), VIEW_AUTO_ORTHOGONAL);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), true);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_lock_rotation", TTR("Lock View Rotation")), VIEW_LOCK_ROTATION);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_lighting", TTR("Display Lighting")), VIEW_DISPLAY_LIGHTING);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
+ display_submenu->add_radio_check_item(TTR("Directional Shadow Splits"), VIEW_DISPLAY_DEBUG_PSSM_SPLITS);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("Normal Buffer"), VIEW_DISPLAY_NORMAL_BUFFER);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("Shadow Atlas"), VIEW_DISPLAY_DEBUG_SHADOW_ATLAS);
+ display_submenu->add_radio_check_item(TTR("Directional Shadow"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("Decal Atlas"), VIEW_DISPLAY_DEBUG_DECAL_ATLAS);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("GIProbe Lighting"), VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING);
+ display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO);
+ display_submenu->add_radio_check_item(TTR("GIProbe Emission"), VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("Scene Luminance"), VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
+ display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("Roughness Limiter"), VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER);
+ display_submenu->set_name("display_advanced");
+ view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View Frame Time")), VIEW_FRAME_TIME);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER);
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Enable Doppler")), VIEW_AUDIO_DOPPLER);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
+
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_cinematic_preview", TTR("Cinematic Preview")), VIEW_CINEMATIC_PREVIEW);
+
+ view_menu->get_popup()->add_separator();
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_origin"), VIEW_CENTER_TO_ORIGIN);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_transform_with_view"), VIEW_ALIGN_TRANSFORM_WITH_VIEW);
+ view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_rotation_with_view"), VIEW_ALIGN_ROTATION_WITH_VIEW);
+ view_menu->get_popup()->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option));
+ display_submenu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option));
+ view_menu->set_disable_shortcuts(true);
+#ifndef _MSC_VER
+#warning this needs to be fixed
+#endif
+ //if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
+ if (false) {
+ // Alternate display modes only work when using the Vulkan renderer; make this explicit.
+ const int normal_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL);
+ const int wireframe_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME);
+ const int overdraw_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW);
+ const int shadeless_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS);
+ const String unsupported_tooltip = TTR("Not available when using the GLES2 renderer.");
+
+ view_menu->get_popup()->set_item_disabled(normal_idx, true);
+ view_menu->get_popup()->set_item_tooltip(normal_idx, unsupported_tooltip);
+ view_menu->get_popup()->set_item_disabled(wireframe_idx, true);
+ view_menu->get_popup()->set_item_tooltip(wireframe_idx, unsupported_tooltip);
+ view_menu->get_popup()->set_item_disabled(overdraw_idx, true);
+ view_menu->get_popup()->set_item_tooltip(overdraw_idx, unsupported_tooltip);
+ view_menu->get_popup()->set_item_disabled(shadeless_idx, true);
+ view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip);
+ }
+
+ ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A);
+ ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D);
+ ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W);
+ ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S);
+ ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_E);
+ ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_Q);
+ ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT);
+ ED_SHORTCUT("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), KEY_ALT);
+
+ preview_camera = memnew(CheckBox);
+ preview_camera->set_text(TTR("Preview"));
+ vbox->add_child(preview_camera);
+ preview_camera->set_h_size_flags(0);
+ preview_camera->hide();
+ preview_camera->connect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview));
+ previewing = nullptr;
+ gizmo_scale = 1.0;
+
+ preview_node = nullptr;
+
+ info_label = memnew(Label);
+ info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
+ info_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -90 * EDSCALE);
+ info_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
+ info_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
+ info_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
+ info_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
+ surface->add_child(info_label);
+ info_label->hide();
+
+ fps_label = memnew(Label);
+ fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
+ fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
+ fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
+ fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
+ fps_label->set_tooltip(TTR("Note: The FPS is estimated on a 60hz refresh rate."));
+ fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show.
+ surface->add_child(fps_label);
+ fps_label->hide();
+
+ cinema_label = memnew(Label);
+ cinema_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
+ cinema_label->set_h_grow_direction(GROW_DIRECTION_END);
+ cinema_label->set_align(Label::ALIGN_CENTER);
+ surface->add_child(cinema_label);
+ cinema_label->set_text(TTR("Cinematic Preview"));
+ cinema_label->hide();
+ previewing_cinema = false;
+
+ locked_label = memnew(Label);
+ locked_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE);
+ locked_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
+ locked_label->set_h_grow_direction(GROW_DIRECTION_END);
+ locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
+ locked_label->set_align(Label::ALIGN_CENTER);
+ surface->add_child(locked_label);
+ locked_label->set_text(TTR("View Rotation Locked"));
+ locked_label->hide();
+
+ top_right_vbox = memnew(VBoxContainer);
+ top_right_vbox->set_anchors_and_margins_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 2.0 * EDSCALE);
+ top_right_vbox->set_h_grow_direction(GROW_DIRECTION_BEGIN);
+
+ rotation_control = memnew(ViewportRotationControl);
+ rotation_control->set_custom_minimum_size(Size2(80, 80) * EDSCALE);
+ rotation_control->set_h_size_flags(SIZE_SHRINK_END);
+ rotation_control->set_viewport(this);
+ top_right_vbox->add_child(rotation_control);
+
+ fps_label = memnew(Label);
+ fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
+ fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
+ fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
+ fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
+ fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance."));
+ fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show.
+ top_right_vbox->add_child(fps_label);
+ fps_label->hide();
+
+ surface->add_child(top_right_vbox);
+
+ accept = nullptr;
+
+ freelook_active = false;
+ freelook_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
+
+ selection_menu = memnew(PopupMenu);
+ add_child(selection_menu);
+ selection_menu->set_min_size(Size2(100, 0) * EDSCALE);
+ selection_menu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_selection_result_pressed));
+ selection_menu->connect("popup_hide", callable_mp(this, &Node3DEditorViewport::_selection_menu_hide));
+
+ if (p_index == 0) {
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER), true);
+ viewport->set_as_audio_listener(true);
+ }
+
+ name = "";
+ _update_name();
+
+ EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view));
+}
+
+//////////////////////////////////////////////////////////////
+
+void Node3DEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) {
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+
+ if (mb->is_pressed()) {
+ Vector2 size = get_size();
+
+ int h_sep = get_theme_constant("separation", "HSplitContainer");
+ int v_sep = get_theme_constant("separation", "VSplitContainer");
+
+ int mid_w = size.width * ratio_h;
+ int mid_h = size.height * ratio_v;
+
+ dragging_h = mb->get_position().x > (mid_w - h_sep / 2) && mb->get_position().x < (mid_w + h_sep / 2);
+ dragging_v = mb->get_position().y > (mid_h - v_sep / 2) && mb->get_position().y < (mid_h + v_sep / 2);
+
+ drag_begin_pos = mb->get_position();
+ drag_begin_ratio.x = ratio_h;
+ drag_begin_ratio.y = ratio_v;
+
+ switch (view) {
+ case VIEW_USE_1_VIEWPORT: {
+
+ dragging_h = false;
+ dragging_v = false;
+
+ } break;
+ case VIEW_USE_2_VIEWPORTS: {
+
+ dragging_h = false;
+
+ } break;
+ case VIEW_USE_2_VIEWPORTS_ALT: {
+
+ dragging_v = false;
+
+ } break;
+ case VIEW_USE_3_VIEWPORTS:
+ case VIEW_USE_3_VIEWPORTS_ALT:
+ case VIEW_USE_4_VIEWPORTS: {
+
+ // Do nothing.
+
+ } break;
+ }
+ } else {
+ dragging_h = false;
+ dragging_v = false;
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+
+ if (view == VIEW_USE_3_VIEWPORTS || view == VIEW_USE_3_VIEWPORTS_ALT || view == VIEW_USE_4_VIEWPORTS) {
+ Vector2 size = get_size();
+
+ int h_sep = get_theme_constant("separation", "HSplitContainer");
+ int v_sep = get_theme_constant("separation", "VSplitContainer");
+
+ int mid_w = size.width * ratio_h;
+ int mid_h = size.height * ratio_v;
+
+ bool was_hovering_h = hovering_h;
+ bool was_hovering_v = hovering_v;
+ hovering_h = mm->get_position().x > (mid_w - h_sep / 2) && mm->get_position().x < (mid_w + h_sep / 2);
+ hovering_v = mm->get_position().y > (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2);
+
+ if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) {
+ update();
+ }
+ }
+
+ if (dragging_h) {
+ float new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width;
+ new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
+ ratio_h = new_ratio;
+ queue_sort();
+ update();
+ }
+ if (dragging_v) {
+ float new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
+ new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
+ ratio_v = new_ratio;
+ queue_sort();
+ update();
+ }
+ }
+}
+
+void Node3DEditorViewportContainer::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_MOUSE_ENTER || p_what == NOTIFICATION_MOUSE_EXIT) {
+
+ mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
+ update();
+ }
+
+ if (p_what == NOTIFICATION_DRAW && mouseover) {
+
+ Ref<Texture2D> h_grabber = get_theme_icon("grabber", "HSplitContainer");
+ Ref<Texture2D> v_grabber = get_theme_icon("grabber", "VSplitContainer");
+
+ Ref<Texture2D> hdiag_grabber = get_theme_icon("GuiViewportHdiagsplitter", "EditorIcons");
+ Ref<Texture2D> vdiag_grabber = get_theme_icon("GuiViewportVdiagsplitter", "EditorIcons");
+ Ref<Texture2D> vh_grabber = get_theme_icon("GuiViewportVhsplitter", "EditorIcons");
+
+ Vector2 size = get_size();
+
+ int h_sep = get_theme_constant("separation", "HSplitContainer");
+
+ int v_sep = get_theme_constant("separation", "VSplitContainer");
+
+ int mid_w = size.width * ratio_h;
+ int mid_h = size.height * ratio_v;
+
+ int size_left = mid_w - h_sep / 2;
+ int size_bottom = size.height - mid_h - v_sep / 2;
+
+ switch (view) {
+
+ case VIEW_USE_1_VIEWPORT: {
+
+ // Nothing to show.
+
+ } break;
+ case VIEW_USE_2_VIEWPORTS: {
+
+ draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_VSPLIT);
+
+ } break;
+ case VIEW_USE_2_VIEWPORTS_ALT: {
+
+ draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
+ set_default_cursor_shape(CURSOR_HSPLIT);
+
+ } break;
+ case VIEW_USE_3_VIEWPORTS: {
+
+ if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
+ draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4));
+ set_default_cursor_shape(CURSOR_DRAG);
+ } else if ((hovering_v && !dragging_h) || dragging_v) {
+ draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_VSPLIT);
+ } else if (hovering_h || dragging_h) {
+ draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, mid_h + v_grabber->get_height() / 2 + (size_bottom - h_grabber->get_height()) / 2));
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ }
+
+ } break;
+ case VIEW_USE_3_VIEWPORTS_ALT: {
+
+ if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
+ draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_DRAG);
+ } else if ((hovering_v && !dragging_h) || dragging_v) {
+ draw_texture(v_grabber, Vector2((size_left - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_VSPLIT);
+ } else if (hovering_h || dragging_h) {
+ draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ }
+
+ } break;
+ case VIEW_USE_4_VIEWPORTS: {
+
+ Vector2 half(mid_w, mid_h);
+ if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
+ draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0);
+ set_default_cursor_shape(CURSOR_DRAG);
+ } else if ((hovering_v && !dragging_h) || dragging_v) {
+ draw_texture(v_grabber, half - v_grabber->get_size() / 2.0);
+ set_default_cursor_shape(CURSOR_VSPLIT);
+ } else if (hovering_h || dragging_h) {
+ draw_texture(h_grabber, half - h_grabber->get_size() / 2.0);
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ }
+
+ } break;
+ }
+ }
+
+ if (p_what == NOTIFICATION_SORT_CHILDREN) {
+
+ Node3DEditorViewport *viewports[4];
+ int vc = 0;
+ for (int i = 0; i < get_child_count(); i++) {
+ viewports[vc] = Object::cast_to<Node3DEditorViewport>(get_child(i));
+ if (viewports[vc]) {
+ vc++;
+ }
+ }
+
+ ERR_FAIL_COND(vc != 4);
+
+ Size2 size = get_size();
+
+ if (size.x < 10 || size.y < 10) {
+ for (int i = 0; i < 4; i++) {
+ viewports[i]->hide();
+ }
+ return;
+ }
+ int h_sep = get_theme_constant("separation", "HSplitContainer");
+
+ int v_sep = get_theme_constant("separation", "VSplitContainer");
+
+ int mid_w = size.width * ratio_h;
+ int mid_h = size.height * ratio_v;
+
+ int size_left = mid_w - h_sep / 2;
+ int size_right = size.width - mid_w - h_sep / 2;
+
+ int size_top = mid_h - v_sep / 2;
+ int size_bottom = size.height - mid_h - v_sep / 2;
+
+ switch (view) {
+
+ case VIEW_USE_1_VIEWPORT: {
+
+ viewports[0]->show();
+ for (int i = 1; i < 4; i++) {
+
+ viewports[i]->hide();
+ }
+
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), size));
+
+ } break;
+ case VIEW_USE_2_VIEWPORTS: {
+
+ for (int i = 0; i < 4; i++) {
+
+ if (i == 1 || i == 3)
+ viewports[i]->hide();
+ else
+ viewports[i]->show();
+ }
+
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size.width, size_bottom)));
+
+ } break;
+ case VIEW_USE_2_VIEWPORTS_ALT: {
+
+ for (int i = 0; i < 4; i++) {
+
+ if (i == 1 || i == 3)
+ viewports[i]->hide();
+ else
+ viewports[i]->show();
+ }
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
+
+ } break;
+ case VIEW_USE_3_VIEWPORTS: {
+
+ for (int i = 0; i < 4; i++) {
+
+ if (i == 1)
+ viewports[i]->hide();
+ else
+ viewports[i]->show();
+ }
+
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
+ fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
+
+ } break;
+ case VIEW_USE_3_VIEWPORTS_ALT: {
+
+ for (int i = 0; i < 4; i++) {
+
+ if (i == 1)
+ viewports[i]->hide();
+ else
+ viewports[i]->show();
+ }
+
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
+ fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
+
+ } break;
+ case VIEW_USE_4_VIEWPORTS: {
+
+ for (int i = 0; i < 4; i++) {
+
+ viewports[i]->show();
+ }
+
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
+ fit_child_in_rect(viewports[1], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
+ fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
+
+ } break;
+ }
+ }
+}
+
+void Node3DEditorViewportContainer::set_view(View p_view) {
+
+ view = p_view;
+ queue_sort();
+}
+
+Node3DEditorViewportContainer::View Node3DEditorViewportContainer::get_view() {
+
+ return view;
+}
+
+void Node3DEditorViewportContainer::_bind_methods() {
+
+ ClassDB::bind_method("_gui_input", &Node3DEditorViewportContainer::_gui_input);
+}
+
+Node3DEditorViewportContainer::Node3DEditorViewportContainer() {
+
+ set_clip_contents(true);
+ view = VIEW_USE_1_VIEWPORT;
+ mouseover = false;
+ ratio_h = 0.5;
+ ratio_v = 0.5;
+ hovering_v = false;
+ hovering_h = false;
+ dragging_v = false;
+ dragging_h = false;
+}
+
+///////////////////////////////////////////////////////////////////
+
+Node3DEditor *Node3DEditor::singleton = nullptr;
+
+Node3DEditorSelectedItem::~Node3DEditorSelectedItem() {
+
+ if (sbox_instance.is_valid())
+ RenderingServer::get_singleton()->free(sbox_instance);
+}
+
+void Node3DEditor::select_gizmo_highlight_axis(int p_axis) {
+
+ for (int i = 0; i < 3; i++) {
+
+ move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
+ move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
+ rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
+ scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
+ scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
+ }
+}
+
+void Node3DEditor::update_transform_gizmo() {
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ AABB center;
+ bool first = true;
+
+ Basis gizmo_basis;
+ bool local_gizmo_coords = are_local_coords_enabled();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ Transform xf = se->sp->get_global_gizmo_transform();
+
+ if (first) {
+ center.position = xf.origin;
+ first = false;
+ if (local_gizmo_coords) {
+ gizmo_basis = xf.basis;
+ gizmo_basis.orthonormalize();
+ }
+ } else {
+ center.expand_to(xf.origin);
+ gizmo_basis = Basis();
+ }
+ }
+
+ Vector3 pcenter = center.position + center.size * 0.5;
+ gizmo.visible = !first;
+ gizmo.transform.origin = pcenter;
+ gizmo.transform.basis = gizmo_basis;
+
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+ viewports[i]->update_transform_gizmo_view();
+ }
+}
+
+void _update_all_gizmos(Node *p_node) {
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ Node3D *spatial_node = Object::cast_to<Node3D>(p_node->get_child(i));
+ if (spatial_node) {
+ spatial_node->update_gizmo();
+ }
+
+ _update_all_gizmos(p_node->get_child(i));
+ }
+}
+
+void Node3DEditor::update_all_gizmos(Node *p_node) {
+ if (!p_node) {
+ p_node = SceneTree::get_singleton()->get_root();
+ }
+ _update_all_gizmos(p_node);
+}
+
+Object *Node3DEditor::_get_editor_data(Object *p_what) {
+
+ Node3D *sp = Object::cast_to<Node3D>(p_what);
+ if (!sp)
+ return nullptr;
+
+ Node3DEditorSelectedItem *si = memnew(Node3DEditorSelectedItem);
+
+ si->sp = sp;
+ si->sbox_instance = RenderingServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world()->get_scenario());
+ RS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, RS::SHADOW_CASTING_SETTING_OFF);
+
+ return si;
+}
+
+void Node3DEditor::_generate_selection_box() {
+
+ AABB aabb(Vector3(), Vector3(1, 1, 1));
+ aabb.grow_by(aabb.get_longest_axis_size() / 20.0);
+
+ Ref<SurfaceTool> st = memnew(SurfaceTool);
+
+ st->begin(Mesh::PRIMITIVE_LINES);
+ for (int i = 0; i < 12; i++) {
+
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+
+ st->add_color(Color(1.0, 1.0, 0.8, 0.8));
+ st->add_vertex(a);
+ st->add_color(Color(1.0, 1.0, 0.8, 0.4));
+ st->add_vertex(a.linear_interpolate(b, 0.2));
+
+ st->add_color(Color(1.0, 1.0, 0.8, 0.4));
+ st->add_vertex(a.linear_interpolate(b, 0.8));
+ st->add_color(Color(1.0, 1.0, 0.8, 0.8));
+ st->add_vertex(b);
+ }
+
+ Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
+ mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ mat->set_albedo(Color(1, 1, 1));
+ mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ st->set_material(mat);
+ selection_box = st->commit();
+}
+
+Dictionary Node3DEditor::get_state() const {
+
+ Dictionary d;
+
+ d["snap_enabled"] = snap_enabled;
+ d["translate_snap"] = get_translate_snap();
+ d["rotate_snap"] = get_rotate_snap();
+ d["scale_snap"] = get_scale_snap();
+
+ d["local_coords"] = tool_option_button[TOOL_OPT_LOCAL_COORDS]->is_pressed();
+
+ int vc = 0;
+ if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
+ vc = 1;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
+ vc = 2;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
+ vc = 3;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
+ vc = 4;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
+ vc = 5;
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
+ vc = 6;
+
+ d["viewport_mode"] = vc;
+ Array vpdata;
+ for (int i = 0; i < 4; i++) {
+ vpdata.push_back(viewports[i]->get_state());
+ }
+
+ d["viewports"] = vpdata;
+
+ d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID));
+ d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN));
+ d["fov"] = get_fov();
+ d["znear"] = get_znear();
+ d["zfar"] = get_zfar();
+
+ Dictionary gizmos_status;
+ for (int i = 0; i < gizmo_plugins_by_name.size(); i++) {
+ if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
+ int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i));
+ String name = gizmo_plugins_by_name[i]->get_name();
+ gizmos_status[name] = state;
+ }
+
+ d["gizmos_status"] = gizmos_status;
+
+ return d;
+}
+void Node3DEditor::set_state(const Dictionary &p_state) {
+
+ Dictionary d = p_state;
+
+ if (d.has("snap_enabled")) {
+ snap_enabled = d["snap_enabled"];
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(d["snap_enabled"]);
+ }
+
+ if (d.has("translate_snap"))
+ snap_translate_value = d["translate_snap"];
+
+ if (d.has("rotate_snap"))
+ snap_rotate_value = d["rotate_snap"];
+
+ if (d.has("scale_snap"))
+ snap_scale_value = d["scale_snap"];
+
+ _snap_update();
+
+ if (d.has("local_coords")) {
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(d["local_coords"]);
+ update_transform_gizmo();
+ }
+
+ if (d.has("viewport_mode")) {
+ int vc = d["viewport_mode"];
+
+ if (vc == 1)
+ _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
+ else if (vc == 2)
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
+ else if (vc == 3)
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
+ else if (vc == 4)
+ _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
+ else if (vc == 5)
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
+ else if (vc == 6)
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
+ }
+
+ if (d.has("viewports")) {
+ Array vp = d["viewports"];
+ uint32_t vp_size = static_cast<uint32_t>(vp.size());
+ if (vp_size > VIEWPORTS_COUNT) {
+ WARN_PRINT("Ignoring superfluous viewport settings from spatial editor state.");
+ vp_size = VIEWPORTS_COUNT;
+ }
+
+ for (uint32_t i = 0; i < vp_size; i++) {
+ viewports[i]->set_state(vp[i]);
+ }
+ }
+
+ if (d.has("zfar"))
+ settings_zfar->set_value(float(d["zfar"]));
+ if (d.has("znear"))
+ settings_znear->set_value(float(d["znear"]));
+ if (d.has("fov"))
+ settings_fov->set_value(float(d["fov"]));
+ if (d.has("show_grid")) {
+ bool use = d["show_grid"];
+
+ if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) {
+ _menu_item_pressed(MENU_VIEW_GRID);
+ }
+ }
+
+ if (d.has("show_origin")) {
+ bool use = d["show_origin"];
+
+ if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN))) {
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), use);
+ RenderingServer::get_singleton()->instance_set_visible(origin_instance, use);
+ }
+ }
+
+ if (d.has("gizmos_status")) {
+ Dictionary gizmos_status = d["gizmos_status"];
+ List<Variant> keys;
+ gizmos_status.get_key_list(&keys);
+
+ for (int j = 0; j < gizmo_plugins_by_name.size(); ++j) {
+ if (!gizmo_plugins_by_name[j]->can_be_hidden()) continue;
+ int state = EditorNode3DGizmoPlugin::VISIBLE;
+ for (int i = 0; i < keys.size(); i++) {
+ if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) {
+ state = gizmos_status[keys[i]];
+ break;
+ }
+ }
+
+ gizmo_plugins_by_name.write[j]->set_state(state);
+ }
+ _update_gizmos_menu();
+ }
+}
+
+void Node3DEditor::edit(Node3D *p_spatial) {
+
+ if (p_spatial != selected) {
+ if (selected) {
+
+ Ref<EditorNode3DGizmo> seg = selected->get_gizmo();
+ if (seg.is_valid()) {
+ seg->set_selected(false);
+ selected->update_gizmo();
+ }
+ }
+
+ selected = p_spatial;
+ over_gizmo_handle = -1;
+
+ if (selected) {
+
+ Ref<EditorNode3DGizmo> seg = selected->get_gizmo();
+ if (seg.is_valid()) {
+ seg->set_selected(true);
+ selected->update_gizmo();
+ }
+ }
+ }
+}
+
+void Node3DEditor::_snap_changed() {
+
+ snap_translate_value = snap_translate->get_text().to_double();
+ snap_rotate_value = snap_rotate->get_text().to_double();
+ snap_scale_value = snap_scale->get_text().to_double();
+}
+
+void Node3DEditor::_snap_update() {
+
+ snap_translate->set_text(String::num(snap_translate_value));
+ snap_rotate->set_text(String::num(snap_rotate_value));
+ snap_scale->set_text(String::num(snap_scale_value));
+}
+
+void Node3DEditor::_xform_dialog_action() {
+
+ Transform t;
+ //translation
+ Vector3 scale;
+ Vector3 rotate;
+ Vector3 translate;
+
+ for (int i = 0; i < 3; i++) {
+ translate[i] = xform_translate[i]->get_text().to_double();
+ rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_double());
+ scale[i] = xform_scale[i]->get_text().to_double();
+ }
+
+ t.basis.scale(scale);
+ t.basis.rotate(rotate);
+ t.origin = translate;
+
+ undo_redo->create_action(TTR("XForm Dialog"));
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp)
+ continue;
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se)
+ continue;
+
+ bool post = xform_type->get_selected() > 0;
+
+ Transform tr = sp->get_global_gizmo_transform();
+ if (post)
+ tr = tr * t;
+ else {
+
+ tr.basis = t.basis * tr.basis;
+ tr.origin += t.origin;
+ }
+
+ undo_redo->add_do_method(sp, "set_global_transform", tr);
+ undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
+ }
+ undo_redo->commit_action();
+}
+
+void Node3DEditor::_menu_item_toggled(bool pressed, int p_option) {
+
+ switch (p_option) {
+ case MENU_TOOL_LOCAL_COORDS: {
+
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(pressed);
+ update_transform_gizmo();
+ } break;
+
+ case MENU_TOOL_USE_SNAP: {
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
+ snap_enabled = pressed;
+ } break;
+
+ case MENU_TOOL_OVERRIDE_CAMERA: {
+ EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
+
+ using Override = EditorDebuggerNode::CameraOverride;
+ if (pressed) {
+
+ debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
+ } else {
+ debugger->set_camera_override(Override::OVERRIDE_NONE);
+ }
+
+ } break;
+ }
+}
+
+void Node3DEditor::_menu_gizmo_toggled(int p_option) {
+
+ const int idx = gizmos_menu->get_item_index(p_option);
+ gizmos_menu->toggle_item_multistate(idx);
+
+ // Change icon
+ const int state = gizmos_menu->get_item_state(idx);
+ switch (state) {
+ case EditorNode3DGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_theme_icon("visibility_visible"));
+ break;
+ case EditorNode3DGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_theme_icon("visibility_xray"));
+ break;
+ case EditorNode3DGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_theme_icon("visibility_hidden"));
+ break;
+ }
+
+ gizmo_plugins_by_name.write[p_option]->set_state(state);
+
+ update_all_gizmos();
+}
+
+void Node3DEditor::_update_camera_override_button(bool p_game_running) {
+ Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
+
+ if (p_game_running) {
+ button->set_disabled(false);
+ button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
+ } else {
+ button->set_disabled(true);
+ button->set_pressed(false);
+ button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
+ }
+}
+
+void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) {
+ Node3DEditorViewport *current_viewport = Object::cast_to<Node3DEditorViewport>(p_viewport);
+
+ if (!current_viewport)
+ return;
+
+ EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
+
+ camera_override_viewport_id = current_viewport->index;
+ if (debugger->get_camera_override() >= EditorDebuggerNode::OVERRIDE_3D_1) {
+ using Override = EditorDebuggerNode::CameraOverride;
+
+ debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
+ }
+}
+
+void Node3DEditor::_menu_item_pressed(int p_option) {
+
+ switch (p_option) {
+
+ case MENU_TOOL_SELECT:
+ case MENU_TOOL_MOVE:
+ case MENU_TOOL_ROTATE:
+ case MENU_TOOL_SCALE:
+ case MENU_TOOL_LIST_SELECT: {
+
+ for (int i = 0; i < TOOL_MAX; i++)
+ tool_button[i]->set_pressed(i == p_option);
+ tool_mode = (ToolMode)p_option;
+ update_transform_gizmo();
+
+ } break;
+ case MENU_TRANSFORM_CONFIGURE_SNAP: {
+
+ snap_dialog->popup_centered(Size2(200, 180));
+ } break;
+ case MENU_TRANSFORM_DIALOG: {
+
+ for (int i = 0; i < 3; i++) {
+
+ xform_translate[i]->set_text("0");
+ xform_rotate[i]->set_text("0");
+ xform_scale[i]->set_text("1");
+ }
+
+ xform_dialog->popup_centered(Size2(320, 240) * EDSCALE);
+
+ } break;
+ case MENU_VIEW_USE_1_VIEWPORT: {
+
+ viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_1_VIEWPORT);
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
+
+ } break;
+ case MENU_VIEW_USE_2_VIEWPORTS: {
+
+ viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS);
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
+
+ } break;
+ case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
+
+ viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT);
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
+
+ } break;
+ case MENU_VIEW_USE_3_VIEWPORTS: {
+
+ viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS);
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
+
+ } break;
+ case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
+
+ viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT);
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), true);
+
+ } break;
+ case MENU_VIEW_USE_4_VIEWPORTS: {
+
+ viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_4_VIEWPORTS);
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
+
+ } break;
+ case MENU_VIEW_ORIGIN: {
+
+ bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
+
+ origin_enabled = !is_checked;
+ RenderingServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled);
+ // Update the grid since its appearance depends on whether the origin is enabled
+ _finish_grid();
+ _init_grid();
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), origin_enabled);
+ } break;
+ case MENU_VIEW_GRID: {
+
+ bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
+
+ grid_enabled = !is_checked;
+
+ for (int i = 0; i < 3; ++i) {
+ if (grid_enable[i]) {
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
+ grid_visible[i] = grid_enabled;
+ }
+ }
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled);
+
+ } break;
+ case MENU_VIEW_CAMERA_SETTINGS: {
+
+ settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
+ } break;
+ case MENU_SNAP_TO_FLOOR: {
+ snap_selected_nodes_to_floor();
+ } break;
+ case MENU_LOCK_SELECTED: {
+ undo_redo->create_action(TTR("Lock Selected"));
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *spatial = Object::cast_to<Node3D>(E->get());
+ if (!spatial || !spatial->is_visible_in_tree())
+ continue;
+
+ if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
+ continue;
+
+ undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true);
+ undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_");
+ undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
+ }
+
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
+ } break;
+ case MENU_UNLOCK_SELECTED: {
+ undo_redo->create_action(TTR("Unlock Selected"));
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *spatial = Object::cast_to<Node3D>(E->get());
+ if (!spatial || !spatial->is_visible_in_tree())
+ continue;
+
+ if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
+ continue;
+
+ undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_");
+ undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true);
+ undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
+ }
+
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
+ } break;
+ case MENU_GROUP_SELECTED: {
+ undo_redo->create_action(TTR("Group Selected"));
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *spatial = Object::cast_to<Node3D>(E->get());
+ if (!spatial || !spatial->is_visible_in_tree())
+ continue;
+
+ if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
+ continue;
+
+ undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true);
+ undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_");
+ undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
+ }
+
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
+ } break;
+ case MENU_UNGROUP_SELECTED: {
+ undo_redo->create_action(TTR("Ungroup Selected"));
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Node3D *spatial = Object::cast_to<Node3D>(E->get());
+ if (!spatial || !spatial->is_visible_in_tree())
+ continue;
+
+ if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
+ continue;
+
+ undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_");
+ undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true);
+ undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
+ undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
+ }
+
+ undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->commit_action();
+ } break;
+ }
+}
+
+void Node3DEditor::_init_indicators() {
+
+ {
+ origin_enabled = true;
+ grid_enabled = true;
+
+ indicator_mat.instance();
+ indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+
+ Vector<Color> origin_colors;
+ Vector<Vector3> origin_points;
+
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis;
+ axis[i] = 1;
+ Color origin_color;
+ switch (i) {
+ case 0:
+ origin_color = get_theme_color("axis_x_color", "Editor");
+ break;
+ case 1:
+ origin_color = get_theme_color("axis_y_color", "Editor");
+ break;
+ case 2:
+ origin_color = get_theme_color("axis_z_color", "Editor");
+ break;
+ default:
+ origin_color = Color();
+ break;
+ }
+
+ grid_enable[i] = false;
+ grid_visible[i] = false;
+
+ origin_colors.push_back(origin_color);
+ origin_colors.push_back(origin_color);
+ origin_points.push_back(axis * 4096);
+ origin_points.push_back(axis * -4096);
+ }
+
+ grid_enable[1] = true;
+ grid_visible[1] = true;
+
+ _init_grid();
+
+ origin = RenderingServer::get_singleton()->mesh_create();
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+ d[RenderingServer::ARRAY_VERTEX] = origin_points;
+ d[RenderingServer::ARRAY_COLOR] = origin_colors;
+
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin, RenderingServer::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid());
+
+ origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario());
+ RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+
+ RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF);
+ }
+
+ {
+
+ //move gizmo
+
+ for (int i = 0; i < 3; i++) {
+
+ Color col;
+ switch (i) {
+ case 0:
+ col = get_theme_color("axis_x_color", "Editor");
+ break;
+ case 1:
+ col = get_theme_color("axis_y_color", "Editor");
+ break;
+ case 2:
+ col = get_theme_color("axis_z_color", "Editor");
+ break;
+ default:
+ col = Color();
+ break;
+ }
+
+ col.a = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_opacity");
+
+ move_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+
+ Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
+ mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ mat->set_on_top_of_alpha();
+ mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ mat->set_albedo(col);
+ gizmo_color[i] = mat;
+
+ Ref<StandardMaterial3D> mat_hl = mat->duplicate();
+ mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
+ gizmo_color_hl[i] = mat_hl;
+
+ Vector3 ivec;
+ ivec[i] = 1;
+ Vector3 nivec;
+ nivec[(i + 1) % 3] = 1;
+ nivec[(i + 2) % 3] = 1;
+ Vector3 ivec2;
+ ivec2[(i + 1) % 3] = 1;
+ Vector3 ivec3;
+ ivec3[(i + 2) % 3] = 1;
+
+ //translate
+ {
+
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ // Arrow profile
+ const int arrow_points = 5;
+ Vector3 arrow[5] = {
+ nivec * 0.0 + ivec * 0.0,
+ nivec * 0.01 + ivec * 0.0,
+ nivec * 0.01 + ivec * GIZMO_ARROW_OFFSET,
+ nivec * 0.065 + ivec * GIZMO_ARROW_OFFSET,
+ nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
+ };
+
+ int arrow_sides = 16;
+
+ for (int k = 0; k < arrow_sides; k++) {
+
+ Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
+ Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
+
+ for (int j = 0; j < arrow_points - 1; j++) {
+
+ Vector3 points[4] = {
+ ma.xform(arrow[j]),
+ mb.xform(arrow[j]),
+ mb.xform(arrow[j + 1]),
+ ma.xform(arrow[j + 1]),
+ };
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[1]);
+ surftool->add_vertex(points[2]);
+
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[2]);
+ surftool->add_vertex(points[3]);
+ }
+ }
+
+ surftool->set_material(mat);
+ surftool->commit(move_gizmo[i]);
+ }
+
+ // Plane Translation
+ {
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ Vector3 vec = ivec2 - ivec3;
+ Vector3 plane[4] = {
+ vec * GIZMO_PLANE_DST,
+ vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
+ vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
+ vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
+ };
+
+ Basis ma(ivec, Math_PI / 2);
+
+ Vector3 points[4] = {
+ ma.xform(plane[0]),
+ ma.xform(plane[1]),
+ ma.xform(plane[2]),
+ ma.xform(plane[3]),
+ };
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[1]);
+ surftool->add_vertex(points[2]);
+
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[2]);
+ surftool->add_vertex(points[3]);
+
+ Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D);
+ plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ plane_mat->set_on_top_of_alpha();
+ plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
+ plane_mat->set_albedo(col);
+ plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
+ surftool->set_material(plane_mat);
+ surftool->commit(move_plane_gizmo[i]);
+
+ Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
+ plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
+ plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
+ }
+
+ // Rotate
+ {
+
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ Vector3 circle[5] = {
+ ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
+ ivec * -0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
+ ivec * -0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
+ ivec * 0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
+ ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
+ };
+
+ for (int k = 0; k < 64; k++) {
+
+ Basis ma(ivec, Math_PI * 2 * float(k) / 64);
+ Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64);
+
+ for (int j = 0; j < 4; j++) {
+
+ Vector3 points[4] = {
+ ma.xform(circle[j]),
+ mb.xform(circle[j]),
+ mb.xform(circle[j + 1]),
+ ma.xform(circle[j + 1]),
+ };
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[1]);
+ surftool->add_vertex(points[2]);
+
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[2]);
+ surftool->add_vertex(points[3]);
+ }
+ }
+
+ surftool->set_material(mat);
+ surftool->commit(rotate_gizmo[i]);
+ }
+
+ // Scale
+ {
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ // Cube arrow profile
+ const int arrow_points = 6;
+ Vector3 arrow[6] = {
+ nivec * 0.0 + ivec * 0.0,
+ nivec * 0.01 + ivec * 0.0,
+ nivec * 0.01 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
+ nivec * 0.07 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
+ nivec * 0.07 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
+ nivec * 0.0 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
+ };
+
+ int arrow_sides = 4;
+
+ for (int k = 0; k < 4; k++) {
+
+ Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
+ Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
+
+ for (int j = 0; j < arrow_points - 1; j++) {
+
+ Vector3 points[4] = {
+ ma.xform(arrow[j]),
+ mb.xform(arrow[j]),
+ mb.xform(arrow[j + 1]),
+ ma.xform(arrow[j + 1]),
+ };
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[1]);
+ surftool->add_vertex(points[2]);
+
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[2]);
+ surftool->add_vertex(points[3]);
+ }
+ }
+
+ surftool->set_material(mat);
+ surftool->commit(scale_gizmo[i]);
+ }
+
+ // Plane Scale
+ {
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ Vector3 vec = ivec2 - ivec3;
+ Vector3 plane[4] = {
+ vec * GIZMO_PLANE_DST,
+ vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
+ vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
+ vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
+ };
+
+ Basis ma(ivec, Math_PI / 2);
+
+ Vector3 points[4] = {
+ ma.xform(plane[0]),
+ ma.xform(plane[1]),
+ ma.xform(plane[2]),
+ ma.xform(plane[3]),
+ };
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[1]);
+ surftool->add_vertex(points[2]);
+
+ surftool->add_vertex(points[0]);
+ surftool->add_vertex(points[2]);
+ surftool->add_vertex(points[3]);
+
+ Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D);
+ plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ plane_mat->set_on_top_of_alpha();
+ plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
+ plane_mat->set_albedo(col);
+ plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
+ surftool->set_material(plane_mat);
+ surftool->commit(scale_plane_gizmo[i]);
+
+ Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
+ plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
+ plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
+ }
+ }
+ }
+
+ _generate_selection_box();
+}
+
+void Node3DEditor::_update_gizmos_menu() {
+
+ gizmos_menu->clear();
+
+ for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
+ if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
+ String plugin_name = gizmo_plugins_by_name[i]->get_name();
+ const int plugin_state = gizmo_plugins_by_name[i]->get_state();
+ gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i);
+ const int idx = gizmos_menu->get_item_index(i);
+ switch (plugin_state) {
+ case EditorNode3DGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_visible"));
+ break;
+ case EditorNode3DGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_xray"));
+ break;
+ case EditorNode3DGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_hidden"));
+ break;
+ }
+ }
+}
+
+void Node3DEditor::_update_gizmos_menu_theme() {
+ for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
+ if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
+ const int plugin_state = gizmo_plugins_by_name[i]->get_state();
+ const int idx = gizmos_menu->get_item_index(i);
+ switch (plugin_state) {
+ case EditorNode3DGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_visible"));
+ break;
+ case EditorNode3DGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_xray"));
+ break;
+ case EditorNode3DGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_hidden"));
+ break;
+ }
+ }
+}
+
+void Node3DEditor::_init_grid() {
+
+ Vector<Color> grid_colors[3];
+ Vector<Vector3> grid_points[3];
+
+ Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color");
+ Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color");
+ int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size");
+ int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps");
+
+ for (int i = 0; i < 3; i++) {
+ Vector3 axis;
+ axis[i] = 1;
+ Vector3 axis_n1;
+ axis_n1[(i + 1) % 3] = 1;
+ Vector3 axis_n2;
+ axis_n2[(i + 2) % 3] = 1;
+
+ for (int j = -grid_size; j <= grid_size; j++) {
+ Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size;
+ Vector3 p1_dest = p1 * (-axis_n2 + axis_n1);
+ Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size;
+ Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
+
+ Color line_color = secondary_grid_color;
+ if (origin_enabled && j == 0) {
+ // Don't draw the center lines of the grid if the origin is enabled
+ // The origin would overlap the grid lines in this case, causing flickering
+ continue;
+ } else if (j % primary_grid_steps == 0) {
+ line_color = primary_grid_color;
+ }
+
+ grid_points[i].push_back(p1);
+ grid_points[i].push_back(p1_dest);
+ grid_colors[i].push_back(line_color);
+ grid_colors[i].push_back(line_color);
+
+ grid_points[i].push_back(p2);
+ grid_points[i].push_back(p2_dest);
+ grid_colors[i].push_back(line_color);
+ grid_colors[i].push_back(line_color);
+ }
+
+ grid[i] = RenderingServer::get_singleton()->mesh_create();
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+ d[RenderingServer::ARRAY_VERTEX] = grid_points[i];
+ d[RenderingServer::ARRAY_COLOR] = grid_colors[i];
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
+ grid_instance[i] = RenderingServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario());
+
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_visible[i]);
+ RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
+ RS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER);
+ }
+}
+
+void Node3DEditor::_finish_indicators() {
+
+ RenderingServer::get_singleton()->free(origin_instance);
+ RenderingServer::get_singleton()->free(origin);
+
+ _finish_grid();
+}
+
+void Node3DEditor::_finish_grid() {
+ for (int i = 0; i < 3; i++) {
+ RenderingServer::get_singleton()->free(grid_instance[i]);
+ RenderingServer::get_singleton()->free(grid[i]);
+ }
+}
+
+bool Node3DEditor::is_any_freelook_active() const {
+ for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) {
+ if (viewports[i]->is_freelook_active())
+ return true;
+ }
+ return false;
+}
+
+void Node3DEditor::_refresh_menu_icons() {
+
+ bool all_locked = true;
+ bool all_grouped = true;
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ if (selection.empty()) {
+ all_locked = false;
+ all_grouped = false;
+ } else {
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ if (Object::cast_to<Node3D>(E->get()) && !Object::cast_to<Node3D>(E->get())->has_meta("_edit_lock_")) {
+ all_locked = false;
+ break;
+ }
+ }
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ if (Object::cast_to<Node3D>(E->get()) && !Object::cast_to<Node3D>(E->get())->has_meta("_edit_group_")) {
+ all_grouped = false;
+ break;
+ }
+ }
+ }
+
+ tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked);
+ tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.empty());
+ tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked);
+
+ tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped);
+ tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.empty());
+ tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped);
+}
+
+template <typename T>
+Set<T *> _get_child_nodes(Node *parent_node) {
+ Set<T *> nodes = Set<T *>();
+ T *node = Node::cast_to<T>(parent_node);
+ if (node) {
+ nodes.insert(node);
+ }
+
+ for (int i = 0; i < parent_node->get_child_count(); i++) {
+ Node *child_node = parent_node->get_child(i);
+ Set<T *> child_nodes = _get_child_nodes<T>(child_node);
+ for (typename Set<T *>::Element *I = child_nodes.front(); I; I = I->next()) {
+ nodes.insert(I->get());
+ }
+ }
+
+ return nodes;
+}
+
+Set<RID> _get_physics_bodies_rid(Node *node) {
+ Set<RID> rids = Set<RID>();
+ PhysicsBody3D *pb = Node::cast_to<PhysicsBody3D>(node);
+ if (pb) {
+ rids.insert(pb->get_rid());
+ }
+ Set<PhysicsBody3D *> child_nodes = _get_child_nodes<PhysicsBody3D>(node);
+ for (Set<PhysicsBody3D *>::Element *I = child_nodes.front(); I; I = I->next()) {
+ rids.insert(I->get()->get_rid());
+ }
+
+ return rids;
+}
+
+void Node3DEditor::snap_selected_nodes_to_floor() {
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ Dictionary snap_data;
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (sp) {
+ Vector3 from = Vector3();
+ Vector3 position_offset = Vector3();
+
+ // Priorities for snapping to floor are CollisionShapes, VisualInstances and then origin
+ Set<VisualInstance3D *> vi = _get_child_nodes<VisualInstance3D>(sp);
+ Set<CollisionShape3D *> cs = _get_child_nodes<CollisionShape3D>(sp);
+
+ if (cs.size()) {
+ AABB aabb = sp->get_global_transform().xform(cs.front()->get()->get_shape()->get_debug_mesh()->get_aabb());
+ for (Set<CollisionShape3D *>::Element *I = cs.front(); I; I = I->next()) {
+ aabb.merge_with(sp->get_global_transform().xform(I->get()->get_shape()->get_debug_mesh()->get_aabb()));
+ }
+ Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
+ from = aabb.position + size;
+ position_offset.y = from.y - sp->get_global_transform().origin.y;
+ } else if (vi.size()) {
+ AABB aabb = vi.front()->get()->get_transformed_aabb();
+ for (Set<VisualInstance3D *>::Element *I = vi.front(); I; I = I->next()) {
+ aabb.merge_with(I->get()->get_transformed_aabb());
+ }
+ Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
+ from = aabb.position + size;
+ position_offset.y = from.y - sp->get_global_transform().origin.y;
+ } else {
+ from = sp->get_global_transform().origin;
+ }
+
+ // We add a bit of margin to the from position to avoid it from snapping
+ // when the spatial is already on a floor and there's another floor under
+ // it
+ from = from + Vector3(0.0, 0.2, 0.0);
+
+ Dictionary d;
+
+ d["from"] = from;
+ d["position_offset"] = position_offset;
+ snap_data[sp] = d;
+ }
+ }
+
+ PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world()->get_direct_space_state();
+ PhysicsDirectSpaceState3D::RayResult result;
+
+ Array keys = snap_data.keys();
+
+ // The maximum height an object can travel to be snapped
+ const float max_snap_height = 20.0;
+
+ // Will be set to `true` if at least one node from the selection was successfully snapped
+ bool snapped_to_floor = false;
+
+ if (keys.size()) {
+ // For snapping to be performed, there must be solid geometry under at least one of the selected nodes.
+ // We need to check this before snapping to register the undo/redo action only if needed.
+ for (int i = 0; i < keys.size(); i++) {
+ Node *node = keys[i];
+ Node3D *sp = Object::cast_to<Node3D>(node);
+ Dictionary d = snap_data[node];
+ Vector3 from = d["from"];
+ Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
+ Set<RID> excluded = _get_physics_bodies_rid(sp);
+
+ if (ss->intersect_ray(from, to, result, excluded)) {
+ snapped_to_floor = true;
+ }
+ }
+
+ if (snapped_to_floor) {
+ undo_redo->create_action(TTR("Snap Nodes To Floor"));
+
+ // Perform snapping if at least one node can be snapped
+ for (int i = 0; i < keys.size(); i++) {
+ Node *node = keys[i];
+ Node3D *sp = Object::cast_to<Node3D>(node);
+ Dictionary d = snap_data[node];
+ Vector3 from = d["from"];
+ Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
+ Set<RID> excluded = _get_physics_bodies_rid(sp);
+
+ if (ss->intersect_ray(from, to, result, excluded)) {
+ Vector3 position_offset = d["position_offset"];
+ Transform new_transform = sp->get_global_transform();
+
+ new_transform.origin.y = result.position.y;
+ new_transform.origin = new_transform.origin - position_offset;
+
+ undo_redo->add_do_method(sp, "set_global_transform", new_transform);
+ undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
+ }
+ }
+
+ undo_redo->commit_action();
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Couldn't find a solid floor to snap the selection to."));
+ }
+ }
+}
+
+void Node3DEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
+
+ if (!is_visible_in_tree())
+ return;
+
+ snap_key_enabled = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
+}
+void Node3DEditor::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_READY) {
+
+ tool_button[Node3DEditor::TOOL_MODE_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_MOVE]->set_icon(get_theme_icon("ToolMove", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_ROTATE]->set_icon(get_theme_icon("ToolRotate", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_SCALE]->set_icon(get_theme_icon("ToolScale", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon("ListSelect", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_LOCK_SELECTED]->set_icon(get_theme_icon("Lock", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon("Unlock", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_GROUP_SELECTED]->set_icon(get_theme_icon("Group", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon("Ungroup", "EditorIcons"));
+
+ tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon("Object", "EditorIcons"));
+ tool_option_button[Node3DEditor::TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon("Snap", "EditorIcons"));
+ tool_option_button[Node3DEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_theme_icon("Camera3D", "EditorIcons"));
+
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon("Panels1", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon("Panels2", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_theme_icon("Panels2Alt", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_theme_icon("Panels3", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_theme_icon("Panels3Alt", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_theme_icon("Panels4", "EditorIcons"));
+
+ _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
+
+ _refresh_menu_icons();
+
+ get_tree()->connect("node_removed", callable_mp(this, &Node3DEditor::_node_removed));
+ 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));
+ } 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();
+ } else if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ _finish_indicators();
+ } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
+ tool_button[Node3DEditor::TOOL_MODE_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_MOVE]->set_icon(get_theme_icon("ToolMove", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_ROTATE]->set_icon(get_theme_icon("ToolRotate", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_SCALE]->set_icon(get_theme_icon("ToolScale", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon("ListSelect", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_LOCK_SELECTED]->set_icon(get_theme_icon("Lock", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon("Unlock", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_GROUP_SELECTED]->set_icon(get_theme_icon("Group", "EditorIcons"));
+ tool_button[Node3DEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon("Ungroup", "EditorIcons"));
+
+ tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon("Object", "EditorIcons"));
+ tool_option_button[Node3DEditor::TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon("Snap", "EditorIcons"));
+
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon("Panels1", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon("Panels2", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_theme_icon("Panels2Alt", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_theme_icon("Panels3", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_theme_icon("Panels3Alt", "EditorIcons"));
+ view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_theme_icon("Panels4", "EditorIcons"));
+
+ // Update grid color by rebuilding grid.
+ _finish_grid();
+ _init_grid();
+ } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
+ EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
+
+ debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
+ }
+ }
+}
+
+void Node3DEditor::add_control_to_menu_panel(Control *p_control) {
+
+ hbc_menu->add_child(p_control);
+}
+
+void Node3DEditor::remove_control_from_menu_panel(Control *p_control) {
+
+ hbc_menu->remove_child(p_control);
+}
+
+void Node3DEditor::set_can_preview(Camera3D *p_preview) {
+
+ for (int i = 0; i < 4; i++) {
+ viewports[i]->set_can_preview(p_preview);
+ }
+}
+
+VSplitContainer *Node3DEditor::get_shader_split() {
+
+ return shader_split;
+}
+
+HSplitContainer *Node3DEditor::get_palette_split() {
+
+ return palette_split;
+}
+
+void Node3DEditor::_request_gizmo(Object *p_obj) {
+
+ Node3D *sp = Object::cast_to<Node3D>(p_obj);
+ if (!sp)
+ return;
+ if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) {
+
+ Ref<EditorNode3DGizmo> seg;
+
+ for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) {
+ seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp);
+
+ if (seg.is_valid()) {
+ sp->set_gizmo(seg);
+
+ if (sp == selected) {
+ seg->set_selected(true);
+ selected->update_gizmo();
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+void Node3DEditor::_toggle_maximize_view(Object *p_viewport) {
+ if (!p_viewport) return;
+ Node3DEditorViewport *current_viewport = Object::cast_to<Node3DEditorViewport>(p_viewport);
+ if (!current_viewport) return;
+
+ int index = -1;
+ bool maximized = false;
+ for (int i = 0; i < 4; i++) {
+ if (viewports[i] == current_viewport) {
+ index = i;
+ if (current_viewport->get_global_rect() == viewport_base->get_global_rect())
+ maximized = true;
+ break;
+ }
+ }
+ if (index == -1) return;
+
+ if (!maximized) {
+
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+ if (i == (uint32_t)index)
+ viewports[i]->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ else
+ viewports[i]->hide();
+ }
+ } else {
+
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++)
+ viewports[i]->show();
+
+ if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
+ _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
+ else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
+ _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
+ }
+}
+
+void Node3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == selected)
+ selected = nullptr;
+}
+
+void Node3DEditor::_register_all_gizmos() {
+ add_gizmo_plugin(Ref<Camera3DGizmoPlugin>(memnew(Camera3DGizmoPlugin)));
+ 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<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<Skeleton3DGizmoPlugin>(memnew(Skeleton3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<VehicleWheel3DGizmoPlugin>(memnew(VehicleWheel3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<VisibilityNotifier3DGizmoPlugin>(memnew(VisibilityNotifier3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<GPUParticles3DGizmoPlugin>(memnew(GPUParticles3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<CPUParticles3DGizmoPlugin>(memnew(CPUParticles3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
+ add_gizmo_plugin(Ref<DecalGizmoPlugin>(memnew(DecalGizmoPlugin)));
+ add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
+ // add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
+ add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin)));
+}
+
+void Node3DEditor::_bind_methods() {
+
+ ClassDB::bind_method("_unhandled_key_input", &Node3DEditor::_unhandled_key_input);
+ ClassDB::bind_method("_get_editor_data", &Node3DEditor::_get_editor_data);
+ ClassDB::bind_method("_request_gizmo", &Node3DEditor::_request_gizmo);
+
+ ADD_SIGNAL(MethodInfo("transform_key_request"));
+ ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
+ ADD_SIGNAL(MethodInfo("item_group_status_changed"));
+}
+
+void Node3DEditor::clear() {
+
+ settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
+ settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
+ settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0));
+
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+ viewports[i]->reset();
+ }
+
+ RenderingServer::get_singleton()->instance_set_visible(origin_instance, true);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
+ for (int i = 0; i < 3; ++i) {
+ if (grid_enable[i]) {
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], true);
+ grid_visible[i] = true;
+ }
+ }
+
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+
+ viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
+ viewports[i]->viewport->set_as_audio_listener(i == 0);
+ }
+
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
+}
+
+Node3DEditor::Node3DEditor(EditorNode *p_editor) {
+
+ gizmo.visible = true;
+ gizmo.scale = 1.0;
+
+ viewport_environment = Ref<Environment>(memnew(Environment));
+ undo_redo = p_editor->get_undo_redo();
+ VBoxContainer *vbc = this;
+
+ custom_camera = nullptr;
+ singleton = this;
+ editor = p_editor;
+ editor_selection = editor->get_editor_selection();
+ editor_selection->add_editor_plugin(this);
+
+ snap_enabled = false;
+ snap_key_enabled = false;
+ tool_mode = TOOL_MODE_SELECT;
+
+ camera_override_viewport_id = 0;
+
+ hbc_menu = memnew(HBoxContainer);
+ vbc->add_child(hbc_menu);
+
+ Vector<Variant> button_binds;
+ button_binds.resize(1);
+ String sct;
+
+ tool_button[TOOL_MODE_SELECT] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
+ tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
+ tool_button[TOOL_MODE_SELECT]->set_flat(true);
+ tool_button[TOOL_MODE_SELECT]->set_pressed(true);
+ button_binds.write[0] = MENU_TOOL_SELECT;
+ tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q));
+ tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection"));
+
+ hbc_menu->add_child(memnew(VSeparator));
+
+ tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
+ tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
+ tool_button[TOOL_MODE_MOVE]->set_flat(true);
+ button_binds.write[0] = MENU_TOOL_MOVE;
+ tool_button[TOOL_MODE_MOVE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
+
+ tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
+ tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
+ tool_button[TOOL_MODE_ROTATE]->set_flat(true);
+ button_binds.write[0] = MENU_TOOL_ROTATE;
+ tool_button[TOOL_MODE_ROTATE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
+
+ tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
+ tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
+ tool_button[TOOL_MODE_SCALE]->set_flat(true);
+ button_binds.write[0] = MENU_TOOL_SCALE;
+ tool_button[TOOL_MODE_SCALE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
+
+ hbc_menu->add_child(memnew(VSeparator));
+
+ tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
+ tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
+ tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
+ button_binds.write[0] = MENU_TOOL_LIST_SELECT;
+ tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
+
+ tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]);
+ button_binds.write[0] = MENU_LOCK_SELECTED;
+ tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
+
+ tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
+ button_binds.write[0] = MENU_UNLOCK_SELECTED;
+ tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
+
+ tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
+ button_binds.write[0] = MENU_GROUP_SELECTED;
+ tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
+
+ tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton);
+ hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
+ button_binds.write[0] = MENU_UNGROUP_SELECTED;
+ tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
+ tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
+
+ hbc_menu->add_child(memnew(VSeparator));
+
+ tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton);
+ hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true);
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
+ button_binds.write[0] = MENU_TOOL_LOCAL_COORDS;
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds);
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
+
+ tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton);
+ hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true);
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
+ button_binds.write[0] = MENU_TOOL_USE_SNAP;
+ tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds);
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y));
+
+ hbc_menu->add_child(memnew(VSeparator));
+
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
+ hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
+ button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA;
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds);
+ _update_camera_override_button(false);
+
+ hbc_menu->add_child(memnew(VSeparator));
+
+ // Drag and drop support;
+ preview_node = memnew(Node3D);
+ preview_bounds = AABB();
+
+ ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7);
+ ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7);
+ ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KEY_MASK_ALT + KEY_KP_1);
+ ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1);
+ ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT + KEY_KP_3);
+ ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3);
+ ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal View"), KEY_KP_5);
+ ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K);
+ ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O);
+ ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
+ ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M);
+ ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F);
+ ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F);
+
+ PopupMenu *p;
+
+ transform_menu = memnew(MenuButton);
+ transform_menu->set_text(TTR("Transform"));
+ transform_menu->set_switch_on_hover(true);
+ hbc_menu->add_child(transform_menu);
+
+ p = transform_menu->get_popup();
+ p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR);
+ p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG);
+
+ p->add_separator();
+ p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP);
+
+ p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed));
+
+ view_menu = memnew(MenuButton);
+ view_menu->set_text(TTR("View"));
+ view_menu->set_switch_on_hover(true);
+ hbc_menu->add_child(view_menu);
+
+ p = view_menu->get_popup();
+
+ accept = memnew(AcceptDialog);
+ editor->get_gui_base()->add_child(accept);
+
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
+ p->add_separator();
+
+ p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
+
+ p->add_separator();
+ p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
+ p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
+
+ p->add_separator();
+ p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
+
+ p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
+ p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
+
+ p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed));
+
+ gizmos_menu = memnew(PopupMenu);
+ p->add_child(gizmos_menu);
+ gizmos_menu->set_name("GizmosMenu");
+ gizmos_menu->set_hide_on_checkable_item_selection(false);
+ gizmos_menu->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_gizmo_toggled));
+
+ /* REST OF MENU */
+
+ palette_split = memnew(HSplitContainer);
+ palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ vbc->add_child(palette_split);
+
+ shader_split = memnew(VSplitContainer);
+ shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
+ palette_split->add_child(shader_split);
+ viewport_base = memnew(Node3DEditorViewportContainer);
+ shader_split->add_child(viewport_base);
+ viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
+
+ viewports[i] = memnew(Node3DEditorViewport(this, editor, i));
+ viewports[i]->connect("toggle_maximize_view", callable_mp(this, &Node3DEditor::_toggle_maximize_view));
+ viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_update_camera_override_viewport));
+ viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
+ viewport_base->add_child(viewports[i]);
+ }
+
+ /* SNAP DIALOG */
+
+ snap_translate_value = 1;
+ snap_rotate_value = 15;
+ snap_scale_value = 10;
+
+ snap_dialog = memnew(ConfirmationDialog);
+ snap_dialog->set_title(TTR("Snap Settings"));
+ add_child(snap_dialog);
+ snap_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_snap_changed));
+ snap_dialog->get_cancel()->connect("pressed", callable_mp(this, &Node3DEditor::_snap_update));
+
+ VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
+ snap_dialog->add_child(snap_dialog_vbc);
+
+ snap_translate = memnew(LineEdit);
+ snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
+
+ snap_rotate = memnew(LineEdit);
+ snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
+
+ snap_scale = memnew(LineEdit);
+ snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
+
+ _snap_update();
+
+ /* SETTINGS DIALOG */
+
+ settings_dialog = memnew(ConfirmationDialog);
+ settings_dialog->set_title(TTR("Viewport Settings"));
+ add_child(settings_dialog);
+ settings_vbc = memnew(VBoxContainer);
+ settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
+ settings_dialog->add_child(settings_vbc);
+
+ settings_fov = memnew(SpinBox);
+ settings_fov->set_max(MAX_FOV);
+ settings_fov->set_min(MIN_FOV);
+ settings_fov->set_step(0.01);
+ settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
+ settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
+
+ settings_znear = memnew(SpinBox);
+ settings_znear->set_max(MAX_Z);
+ settings_znear->set_min(MIN_Z);
+ settings_znear->set_step(0.01);
+ settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
+ settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
+
+ settings_zfar = memnew(SpinBox);
+ settings_zfar->set_max(MAX_Z);
+ settings_zfar->set_min(MIN_Z);
+ settings_zfar->set_step(0.01);
+ settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500));
+ settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
+
+ for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) {
+ settings_dialog->connect("confirmed", callable_mp(viewports[i], &Node3DEditorViewport::_update_camera), varray(0.0));
+ }
+
+ /* XFORM DIALOG */
+
+ xform_dialog = memnew(ConfirmationDialog);
+ xform_dialog->set_title(TTR("Transform Change"));
+ add_child(xform_dialog);
+
+ VBoxContainer *xform_vbc = memnew(VBoxContainer);
+ xform_dialog->add_child(xform_vbc);
+
+ Label *l = memnew(Label);
+ l->set_text(TTR("Translate:"));
+ xform_vbc->add_child(l);
+
+ HBoxContainer *xform_hbc = memnew(HBoxContainer);
+ xform_vbc->add_child(xform_hbc);
+
+ for (int i = 0; i < 3; i++) {
+
+ xform_translate[i] = memnew(LineEdit);
+ xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_hbc->add_child(xform_translate[i]);
+ }
+
+ l = memnew(Label);
+ l->set_text(TTR("Rotate (deg.):"));
+ xform_vbc->add_child(l);
+
+ xform_hbc = memnew(HBoxContainer);
+ xform_vbc->add_child(xform_hbc);
+
+ for (int i = 0; i < 3; i++) {
+ xform_rotate[i] = memnew(LineEdit);
+ xform_rotate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_hbc->add_child(xform_rotate[i]);
+ }
+
+ l = memnew(Label);
+ l->set_text(TTR("Scale (ratio):"));
+ xform_vbc->add_child(l);
+
+ xform_hbc = memnew(HBoxContainer);
+ xform_vbc->add_child(xform_hbc);
+
+ for (int i = 0; i < 3; i++) {
+ xform_scale[i] = memnew(LineEdit);
+ xform_scale[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_hbc->add_child(xform_scale[i]);
+ }
+
+ l = memnew(Label);
+ l->set_text(TTR("Transform Type"));
+ xform_vbc->add_child(l);
+
+ xform_type = memnew(OptionButton);
+ xform_type->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_type->add_item(TTR("Pre"));
+ xform_type->add_item(TTR("Post"));
+ xform_vbc->add_child(xform_type);
+
+ xform_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_xform_dialog_action));
+
+ scenario_debug = RenderingServer::SCENARIO_DEBUG_DISABLED;
+
+ selected = nullptr;
+
+ set_process_unhandled_key_input(true);
+ add_to_group("_spatial_editor_group");
+
+ EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,1024,1"));
+ EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.4);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::FLOAT, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"));
+ EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
+
+ over_gizmo_handle = -1;
+}
+
+Node3DEditor::~Node3DEditor() {
+ memdelete(preview_node);
+}
+
+void Node3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+
+ spatial_editor->show();
+ spatial_editor->set_process(true);
+
+ } else {
+
+ spatial_editor->hide();
+ spatial_editor->set_process(false);
+ }
+}
+void Node3DEditorPlugin::edit(Object *p_object) {
+
+ spatial_editor->edit(Object::cast_to<Node3D>(p_object));
+}
+
+bool Node3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("Node3D");
+}
+
+Dictionary Node3DEditorPlugin::get_state() const {
+ return spatial_editor->get_state();
+}
+
+void Node3DEditorPlugin::set_state(const Dictionary &p_state) {
+
+ spatial_editor->set_state(p_state);
+}
+
+void Node3DEditor::snap_cursor_to_plane(const Plane &p_plane) {
+
+ //cursor.pos=p_plane.project(cursor.pos);
+}
+
+Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
+ if (is_snap_enabled()) {
+ p_target.x = Math::snap_scalar(0.0, get_translate_snap(), p_target.x);
+ p_target.y = Math::snap_scalar(0.0, get_translate_snap(), p_target.y);
+ p_target.z = Math::snap_scalar(0.0, get_translate_snap(), p_target.z);
+ }
+ return p_target;
+}
+
+float Node3DEditor::get_translate_snap() const {
+ float snap_value;
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ snap_value = snap_translate->get_text().to_double() / 10.0;
+ } else {
+ snap_value = snap_translate->get_text().to_double();
+ }
+
+ return snap_value;
+}
+
+float Node3DEditor::get_rotate_snap() const {
+ float snap_value;
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ snap_value = snap_rotate->get_text().to_double() / 3.0;
+ } else {
+ snap_value = snap_rotate->get_text().to_double();
+ }
+
+ return snap_value;
+}
+
+float Node3DEditor::get_scale_snap() const {
+ float snap_value;
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ snap_value = snap_scale->get_text().to_double() / 2.0;
+ } else {
+ snap_value = snap_scale->get_text().to_double();
+ }
+
+ return snap_value;
+}
+
+void Node3DEditorPlugin::_bind_methods() {
+
+ ClassDB::bind_method("snap_cursor_to_plane", &Node3DEditorPlugin::snap_cursor_to_plane);
+}
+
+void Node3DEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
+
+ spatial_editor->snap_cursor_to_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_priority() > p_b->get_priority();
+ }
+};
+
+struct _GizmoPluginNameComparator {
+
+ bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const {
+ return p_a->get_name() < p_b->get_name();
+ }
+};
+
+void Node3DEditor::add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) {
+ ERR_FAIL_NULL(p_plugin.ptr());
+
+ gizmo_plugins_by_priority.push_back(p_plugin);
+ gizmo_plugins_by_priority.sort_custom<_GizmoPluginPriorityComparator>();
+
+ gizmo_plugins_by_name.push_back(p_plugin);
+ gizmo_plugins_by_name.sort_custom<_GizmoPluginNameComparator>();
+
+ _update_gizmos_menu();
+ Node3DEditor::get_singleton()->update_all_gizmos();
+}
+
+void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) {
+ gizmo_plugins_by_priority.erase(p_plugin);
+ gizmo_plugins_by_name.erase(p_plugin);
+ _update_gizmos_menu();
+}
+
+Node3DEditorPlugin::Node3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ spatial_editor = memnew(Node3DEditor(p_node));
+ spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ editor->get_viewport()->add_child(spatial_editor);
+
+ spatial_editor->hide();
+ spatial_editor->connect_compat("transform_key_request", editor->get_inspector_dock(), "_transform_keyed");
+}
+
+Node3DEditorPlugin::~Node3DEditorPlugin() {
+}
+
+void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
+
+ Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
+
+ Vector<Ref<StandardMaterial3D>> mats;
+
+ for (int i = 0; i < 4; i++) {
+ bool selected = i % 2 == 1;
+ bool instanced = i < 2;
+
+ Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+
+ Color color = instanced ? instanced_color : p_color;
+
+ if (!selected) {
+ color.a *= 0.3;
+ }
+
+ material->set_albedo(color);
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
+
+ if (p_use_vertex_color) {
+ material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ }
+
+ if (p_billboard) {
+ material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
+ }
+
+ if (p_on_top && selected) {
+ material->set_on_top_of_alpha();
+ }
+
+ mats.push_back(material);
+ }
+
+ materials[p_name] = mats;
+}
+
+void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) {
+
+ Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
+
+ Vector<Ref<StandardMaterial3D>> icons;
+
+ for (int i = 0; i < 4; i++) {
+ bool selected = i % 2 == 1;
+ bool instanced = i < 2;
+
+ Ref<StandardMaterial3D> icon = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+
+ Color color = instanced ? instanced_color : p_albedo;
+
+ if (!selected) {
+ color.a *= 0.85;
+ }
+
+ icon->set_albedo(color);
+
+ icon->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ icon->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ icon->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ icon->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
+ icon->set_depth_draw_mode(StandardMaterial3D::DEPTH_DRAW_DISABLED);
+ icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ icon->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, p_texture);
+ icon->set_flag(StandardMaterial3D::FLAG_FIXED_SIZE, true);
+ icon->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
+ icon->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN);
+
+ if (p_on_top && selected) {
+ icon->set_on_top_of_alpha();
+ }
+
+ icons.push_back(icon);
+ }
+
+ materials[p_name] = icons;
+}
+
+void EditorNode3DGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) {
+ Ref<StandardMaterial3D> handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+
+ handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
+ Ref<Texture2D> handle_t = Node3DEditor::get_singleton()->get_theme_icon("Editor3DHandle", "EditorIcons");
+ handle_material->set_point_size(handle_t->get_width());
+ handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle_t);
+ handle_material->set_albedo(Color(1, 1, 1));
+ handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ handle_material->set_on_top_of_alpha();
+ if (p_billboard) {
+ handle_material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
+ handle_material->set_on_top_of_alpha();
+ }
+
+ materials[p_name] = Vector<Ref<StandardMaterial3D>>();
+ materials[p_name].push_back(handle_material);
+}
+
+void EditorNode3DGizmoPlugin::add_material(const String &p_name, Ref<StandardMaterial3D> p_material) {
+ materials[p_name] = Vector<Ref<StandardMaterial3D>>();
+ materials[p_name].push_back(p_material);
+}
+
+Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo) {
+ ERR_FAIL_COND_V(!materials.has(p_name), Ref<StandardMaterial3D>());
+ ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<StandardMaterial3D>());
+
+ if (p_gizmo.is_null() || materials[p_name].size() == 1) return materials[p_name][0];
+
+ int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0);
+
+ Ref<StandardMaterial3D> mat = materials[p_name][index];
+
+ if (current_state == ON_TOP && p_gizmo->is_selected()) {
+ mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
+ } else {
+ mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, false);
+ }
+
+ return mat;
+}
+
+String EditorNode3DGizmoPlugin::get_name() const {
+ if (get_script_instance() && get_script_instance()->has_method("get_name")) {
+ return get_script_instance()->call("get_name");
+ }
+ return TTR("Nameless gizmo");
+}
+
+int EditorNode3DGizmoPlugin::get_priority() const {
+ if (get_script_instance() && get_script_instance()->has_method("get_priority")) {
+ return get_script_instance()->call("get_priority");
+ }
+ return 0;
+}
+
+Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::get_gizmo(Node3D *p_spatial) {
+
+ if (get_script_instance() && get_script_instance()->has_method("get_gizmo")) {
+ return get_script_instance()->call("get_gizmo", p_spatial);
+ }
+
+ Ref<EditorNode3DGizmo> ref = create_gizmo(p_spatial);
+
+ if (ref.is_null()) return ref;
+
+ ref->set_plugin(this);
+ ref->set_spatial_node(p_spatial);
+ ref->set_hidden(current_state == HIDDEN);
+
+ current_gizmos.push_back(ref.ptr());
+ return ref;
+}
+
+void EditorNode3DGizmoPlugin::_bind_methods() {
+#define GIZMO_REF PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "EditorNode3DGizmo")
+
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
+ BIND_VMETHOD(MethodInfo(GIZMO_REF, "create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D")));
+
+ ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorNode3DGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorNode3DGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard"), &EditorNode3DGizmoPlugin::create_handle_material, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorNode3DGizmoPlugin::add_material);
+
+ 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_priority"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden"));
+
+ BIND_VMETHOD(MethodInfo("redraw", GIZMO_REF));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
+
+ MethodInfo hvget(Variant::NIL, "get_handle_value", GIZMO_REF, PropertyInfo(Variant::INT, "index"));
+ hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_VMETHOD(hvget);
+
+ BIND_VMETHOD(MethodInfo("set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point")));
+ MethodInfo cm = MethodInfo("commit_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel"));
+ cm.default_arguments.push_back(false);
+ BIND_VMETHOD(cm);
+
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
+
+#undef GIZMO_REF
+}
+
+bool EditorNode3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ if (get_script_instance() && get_script_instance()->has_method("has_gizmo")) {
+ return get_script_instance()->call("has_gizmo", p_spatial);
+ }
+ return false;
+}
+
+Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
+
+ if (get_script_instance() && get_script_instance()->has_method("create_gizmo")) {
+ return get_script_instance()->call("create_gizmo", p_spatial);
+ }
+
+ Ref<EditorNode3DGizmo> ref;
+ if (has_gizmo(p_spatial)) ref.instance();
+ return ref;
+}
+
+bool EditorNode3DGizmoPlugin::can_be_hidden() const {
+ if (get_script_instance() && get_script_instance()->has_method("can_be_hidden")) {
+ return get_script_instance()->call("can_be_hidden");
+ }
+ return true;
+}
+
+bool EditorNode3DGizmoPlugin::is_selectable_when_hidden() const {
+ if (get_script_instance() && get_script_instance()->has_method("is_selectable_when_hidden")) {
+ return get_script_instance()->call("is_selectable_when_hidden");
+ }
+ return false;
+}
+
+void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ if (get_script_instance() && get_script_instance()->has_method("redraw")) {
+ Ref<EditorNode3DGizmo> ref(p_gizmo);
+ get_script_instance()->call("redraw", ref);
+ }
+}
+
+String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) {
+ return get_script_instance()->call("get_handle_name", p_gizmo, p_idx);
+ }
+ return "";
+}
+
+Variant EditorNode3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) {
+ return get_script_instance()->call("get_handle_value", p_gizmo, p_idx);
+ }
+ return Variant();
+}
+
+void EditorNode3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+ if (get_script_instance() && get_script_instance()->has_method("set_handle")) {
+ get_script_instance()->call("set_handle", p_gizmo, p_idx, p_camera, p_point);
+ }
+}
+
+void EditorNode3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+ if (get_script_instance() && get_script_instance()->has_method("commit_handle")) {
+ get_script_instance()->call("commit_handle", p_gizmo, p_idx, p_restore, p_cancel);
+ }
+}
+
+bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+ if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) {
+ return get_script_instance()->call("is_handle_highlighted", p_gizmo, p_idx);
+ }
+ return false;
+}
+
+void EditorNode3DGizmoPlugin::set_state(int p_state) {
+ current_state = p_state;
+ for (int i = 0; i < current_gizmos.size(); ++i) {
+ current_gizmos[i]->set_hidden(current_state == HIDDEN);
+ }
+}
+
+int EditorNode3DGizmoPlugin::get_state() const {
+ return current_state;
+}
+
+void EditorNode3DGizmoPlugin::unregister_gizmo(EditorNode3DGizmo *p_gizmo) {
+ current_gizmos.erase(p_gizmo);
+}
+
+EditorNode3DGizmoPlugin::EditorNode3DGizmoPlugin() {
+ current_state = VISIBLE;
+}
+
+EditorNode3DGizmoPlugin::~EditorNode3DGizmoPlugin() {
+ for (int i = 0; i < current_gizmos.size(); ++i) {
+ current_gizmos[i]->set_plugin(nullptr);
+ current_gizmos[i]->get_spatial_node()->set_gizmo(nullptr);
+ }
+ if (Node3DEditor::get_singleton()) {
+ Node3DEditor::get_singleton()->update_all_gizmos();
+ }
+}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
new file mode 100644
index 0000000000..2c3b15cfc8
--- /dev/null
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -0,0 +1,892 @@
+/*************************************************************************/
+/* node_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPATIAL_EDITOR_PLUGIN_H
+#define SPATIAL_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "editor/editor_scale.h"
+#include "scene/3d/immediate_geometry_3d.h"
+#include "scene/3d/light_3d.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/gui/panel_container.h"
+
+class Camera3D;
+class Node3DEditor;
+class EditorNode3DGizmoPlugin;
+class Node3DEditorViewport;
+class SubViewportContainer;
+
+class EditorNode3DGizmo : public Node3DGizmo {
+
+ GDCLASS(EditorNode3DGizmo, Node3DGizmo);
+
+ bool selected;
+ bool instanced;
+
+public:
+ void set_selected(bool p_selected) { selected = p_selected; }
+ bool is_selected() const { return selected; }
+
+ struct Instance {
+
+ RID instance;
+ Ref<ArrayMesh> mesh;
+ Ref<Material> material;
+ Ref<SkinReference> skin_reference;
+ RID skeleton;
+ bool billboard;
+ bool unscaled;
+ bool can_intersect;
+ bool extra_margin;
+ Instance() {
+
+ billboard = false;
+ unscaled = false;
+ can_intersect = false;
+ extra_margin = false;
+ }
+
+ void create_instance(Node3D *p_base, bool p_hidden = false);
+ };
+
+ Vector<Vector3> collision_segments;
+ Ref<TriangleMesh> collision_mesh;
+
+ struct Handle {
+ Vector3 pos;
+ bool billboard;
+ };
+
+ Vector<Vector3> handles;
+ Vector<Vector3> secondary_handles;
+ float selectable_icon_size;
+ bool billboard_handle;
+
+ bool valid;
+ bool hidden;
+ Node3D *base;
+ Vector<Instance> instances;
+ Node3D *spatial_node;
+ EditorNode3DGizmoPlugin *gizmo_plugin;
+
+ void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Node3D>(p_node)); }
+
+protected:
+ static void _bind_methods();
+
+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_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);
+ void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1, const Color &p_modulate = Color(1, 1, 1));
+ void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard = false, bool p_secondary = false);
+ void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3());
+
+ virtual bool is_handle_highlighted(int p_idx) const;
+ virtual String get_handle_name(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx);
+ virtual void set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ void set_spatial_node(Node3D *p_node);
+ Node3D *get_spatial_node() const { return spatial_node; }
+ Ref<EditorNode3DGizmoPlugin> get_plugin() const { return gizmo_plugin; }
+ Vector3 get_handle_pos(int p_idx) const;
+ bool intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum);
+ bool intersect_ray(Camera3D *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = nullptr, bool p_sec_first = false);
+
+ virtual void clear();
+ virtual void create();
+ virtual void transform();
+ virtual void redraw();
+ virtual void free();
+
+ virtual bool is_editable() const;
+
+ void set_hidden(bool p_hidden);
+ void set_plugin(EditorNode3DGizmoPlugin *p_plugin);
+
+ EditorNode3DGizmo();
+ ~EditorNode3DGizmo();
+};
+
+class ViewportRotationControl : public Control {
+ GDCLASS(ViewportRotationControl, Control);
+
+ struct Axis2D {
+ Vector2i screen_point;
+ float z_axis = -99.0;
+ int axis = -1;
+ };
+
+ struct Axis2DCompare {
+ _FORCE_INLINE_ bool operator()(const Axis2D &l, const Axis2D &r) const {
+ return l.z_axis < r.z_axis;
+ }
+ };
+
+ Node3DEditorViewport *viewport = nullptr;
+ Vector<Color> axis_colors;
+ Vector<int> axis_menu_options;
+ bool orbiting = false;
+ int focused_axis = -2;
+
+ const float AXIS_CIRCLE_RADIUS = 8.0f * EDSCALE;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+ void _gui_input(Ref<InputEvent> p_event);
+ void _draw();
+ void _draw_axis(const Axis2D &p_axis);
+ void _get_sorted_axis(Vector<Axis2D> &r_axis);
+ void _update_focus();
+ void _on_mouse_exited();
+
+public:
+ void set_viewport(Node3DEditorViewport *p_viewport);
+};
+
+class Node3DEditorViewport : public Control {
+
+ GDCLASS(Node3DEditorViewport, Control);
+ friend class Node3DEditor;
+ friend class ViewportRotationControl;
+ enum {
+
+ VIEW_TOP,
+ VIEW_BOTTOM,
+ VIEW_LEFT,
+ VIEW_RIGHT,
+ VIEW_FRONT,
+ VIEW_REAR,
+ VIEW_CENTER_TO_ORIGIN,
+ VIEW_CENTER_TO_SELECTION,
+ VIEW_ALIGN_TRANSFORM_WITH_VIEW,
+ VIEW_ALIGN_ROTATION_WITH_VIEW,
+ VIEW_PERSPECTIVE,
+ VIEW_ENVIRONMENT,
+ VIEW_ORTHOGONAL,
+ VIEW_HALF_RESOLUTION,
+ VIEW_AUDIO_LISTENER,
+ VIEW_AUDIO_DOPPLER,
+ VIEW_GIZMOS,
+ VIEW_INFORMATION,
+ VIEW_FRAME_TIME,
+ VIEW_DISPLAY_NORMAL,
+ VIEW_DISPLAY_WIREFRAME,
+ VIEW_DISPLAY_OVERDRAW,
+ VIEW_DISPLAY_SHADELESS,
+ VIEW_DISPLAY_LIGHTING,
+ VIEW_DISPLAY_ADVANCED,
+ VIEW_DISPLAY_NORMAL_BUFFER,
+ VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
+ VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
+ VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO,
+ VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING,
+ VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
+ VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
+ VIEW_DISPLAY_DEBUG_SSAO,
+ VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
+ VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
+ VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
+ VIEW_LOCK_ROTATION,
+ VIEW_CINEMATIC_PREVIEW,
+ VIEW_AUTO_ORTHOGONAL,
+ VIEW_MAX
+ };
+
+public:
+ enum {
+ GIZMO_BASE_LAYER = 27,
+ GIZMO_EDIT_LAYER = 26,
+ GIZMO_GRID_LAYER = 25,
+
+ FRAME_TIME_HISTORY = 20,
+ };
+
+ enum NavigationScheme {
+ NAVIGATION_GODOT,
+ NAVIGATION_MAYA,
+ NAVIGATION_MODO,
+ };
+
+private:
+ float cpu_time_history[FRAME_TIME_HISTORY];
+ int cpu_time_history_index;
+ float gpu_time_history[FRAME_TIME_HISTORY];
+ int gpu_time_history_index;
+
+ int index;
+ String name;
+ void _menu_option(int p_option);
+ void _set_auto_orthogonal();
+ Node3D *preview_node;
+ AABB *preview_bounds;
+ Vector<String> selected_files;
+ AcceptDialog *accept;
+
+ Node *target_node;
+ Point2 drop_pos;
+
+ EditorNode *editor;
+ EditorData *editor_data;
+ EditorSelection *editor_selection;
+ UndoRedo *undo_redo;
+
+ CheckBox *preview_camera;
+ SubViewportContainer *subviewport_container;
+
+ MenuButton *view_menu;
+ PopupMenu *display_submenu;
+
+ Control *surface;
+ SubViewport *viewport;
+ Camera3D *camera;
+ bool transforming;
+ bool orthogonal;
+ bool auto_orthogonal;
+ bool lock_rotation;
+ float gizmo_scale;
+
+ bool freelook_active;
+ real_t freelook_speed;
+
+ TextureRect *crosshair;
+ Label *info_label;
+ Label *cinema_label;
+ Label *locked_label;
+
+ VBoxContainer *top_right_vbox;
+ ViewportRotationControl *rotation_control;
+ Label *fps_label;
+
+ struct _RayResult {
+
+ Node3D *item;
+ float depth;
+ int handle;
+ _FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; }
+ };
+
+ void _update_name();
+ void _compute_edit(const Point2 &p_point);
+ void _clear_selected();
+ void _select_clicked(bool p_append, bool p_single, bool p_allow_locked = false);
+ void _select(Node *p_node, bool p_append, bool p_single);
+ ObjectID _select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle = nullptr, bool p_alt_select = false);
+ void _find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select = false);
+ Vector3 _get_ray_pos(const Vector2 &p_pos) const;
+ Vector3 _get_ray(const Vector2 &p_pos) const;
+ Point2 _point_to_screen(const Vector3 &p_point);
+ Transform _get_camera_transform() const;
+ int get_selected_count() const;
+
+ Vector3 _get_camera_position() const;
+ Vector3 _get_camera_normal() const;
+ Vector3 _get_screen_to_space(const Vector3 &p_vector3);
+
+ void _select_region();
+ bool _gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only = false);
+
+ void _nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
+ void _nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
+ void _nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
+ void _nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
+
+ float get_znear() const;
+ float get_zfar() const;
+ float get_fov() const;
+
+ ObjectID clicked;
+ Vector<_RayResult> selection_results;
+ bool clicked_includes_current;
+ bool clicked_wants_append;
+
+ PopupMenu *selection_menu;
+
+ enum NavigationZoomStyle {
+ NAVIGATION_ZOOM_VERTICAL,
+ NAVIGATION_ZOOM_HORIZONTAL
+ };
+
+ enum NavigationMode {
+ NAVIGATION_NONE,
+ NAVIGATION_PAN,
+ NAVIGATION_ZOOM,
+ NAVIGATION_ORBIT,
+ NAVIGATION_LOOK
+ };
+ enum TransformMode {
+ TRANSFORM_NONE,
+ TRANSFORM_ROTATE,
+ TRANSFORM_TRANSLATE,
+ TRANSFORM_SCALE
+
+ };
+ enum TransformPlane {
+ TRANSFORM_VIEW,
+ TRANSFORM_X_AXIS,
+ TRANSFORM_Y_AXIS,
+ TRANSFORM_Z_AXIS,
+ TRANSFORM_YZ,
+ TRANSFORM_XZ,
+ TRANSFORM_XY,
+ };
+
+ struct EditData {
+ TransformMode mode;
+ TransformPlane plane;
+ Transform original;
+ Vector3 click_ray;
+ Vector3 click_ray_pos;
+ Vector3 center;
+ Vector3 orig_gizmo_pos;
+ int edited_gizmo;
+ Point2 mouse_pos;
+ bool snap;
+ Ref<EditorNode3DGizmo> gizmo;
+ int gizmo_handle;
+ Variant gizmo_initial_value;
+ Vector3 gizmo_initial_pos;
+ } _edit;
+
+ struct Cursor {
+
+ Vector3 pos;
+ float x_rot, y_rot, distance;
+ Vector3 eye_pos; // Used in freelook mode
+ bool region_select;
+ Point2 region_begin, region_end;
+
+ Cursor() {
+ x_rot = y_rot = 0.5;
+ distance = 4;
+ region_select = false;
+ }
+ };
+ // Viewport camera supports movement smoothing,
+ // so one cursor is the real cursor, while the other can be an interpolated version.
+ Cursor cursor; // Immediate cursor
+ Cursor camera_cursor; // That one may be interpolated (don't modify this one except for smoothing purposes)
+
+ void scale_cursor_distance(real_t scale);
+
+ void set_freelook_active(bool active_now);
+ void scale_freelook_speed(real_t scale);
+
+ real_t zoom_indicator_delay;
+
+ RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
+
+ String last_message;
+ String message;
+ float message_time;
+
+ void set_message(String p_message, float p_time = 5);
+
+ //
+ void _update_camera(float p_interp_delta);
+ Transform to_camera_transform(const Cursor &p_cursor) const;
+ void _draw();
+
+ void _surface_mouse_enter();
+ void _surface_mouse_exit();
+ void _surface_focus_enter();
+ void _surface_focus_exit();
+
+ void _sinput(const Ref<InputEvent> &p_event);
+ void _update_freelook(real_t delta);
+ Node3DEditor *spatial_editor;
+
+ Camera3D *previewing;
+ Camera3D *preview;
+
+ bool previewing_cinema;
+ bool _is_node_locked(const Node *p_node);
+ void _preview_exited_scene();
+ void _toggle_camera_preview(bool);
+ void _toggle_cinema_preview(bool);
+ void _init_gizmo_instance(int p_idx);
+ void _finish_gizmo_instances();
+ void _selection_result_pressed(int);
+ void _selection_menu_hide();
+ void _list_select(Ref<InputEventMouseButton> b);
+ Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const;
+
+ Vector3 _get_instance_position(const Point2 &p_pos) const;
+ static AABB _calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_toplevel_transform = true);
+ void _create_preview(const Vector<String> &files) const;
+ void _remove_preview();
+ bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node);
+ bool _create_instance(Node *parent, String &path, const Point2 &p_point);
+ void _perform_drop_data();
+
+ 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:
+ void update_surface() { surface->update(); }
+ void update_transform_gizmo_view();
+
+ void set_can_preview(Camera3D *p_preview);
+ void set_state(const Dictionary &p_state);
+ Dictionary get_state() const;
+ void reset();
+ bool is_freelook_active() const { return freelook_active; }
+
+ void focus_selection();
+
+ void assign_pending_data_pointers(
+ Node3D *p_preview_node,
+ AABB *p_preview_bounds,
+ AcceptDialog *p_accept);
+
+ SubViewport *get_viewport_node() { return viewport; }
+ Camera3D *get_camera() { return camera; } // return the default camera object.
+
+ Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index);
+};
+
+class Node3DEditorSelectedItem : public Object {
+
+ GDCLASS(Node3DEditorSelectedItem, Object);
+
+public:
+ AABB aabb;
+ Transform original; // original location when moving
+ Transform original_local;
+ Transform last_xform; // last transform
+ bool last_xform_dirty;
+ Node3D *sp;
+ RID sbox_instance;
+
+ Node3DEditorSelectedItem() {
+ sp = nullptr;
+ last_xform_dirty = true;
+ }
+ ~Node3DEditorSelectedItem();
+};
+
+class Node3DEditorViewportContainer : public Container {
+
+ GDCLASS(Node3DEditorViewportContainer, Container);
+
+public:
+ enum View {
+ VIEW_USE_1_VIEWPORT,
+ VIEW_USE_2_VIEWPORTS,
+ VIEW_USE_2_VIEWPORTS_ALT,
+ VIEW_USE_3_VIEWPORTS,
+ VIEW_USE_3_VIEWPORTS_ALT,
+ VIEW_USE_4_VIEWPORTS,
+ };
+
+private:
+ View view;
+ bool mouseover;
+ float ratio_h;
+ float ratio_v;
+
+ bool hovering_v;
+ bool hovering_h;
+
+ bool dragging_v;
+ bool dragging_h;
+ Vector2 drag_begin_pos;
+ Vector2 drag_begin_ratio;
+
+ void _gui_input(const Ref<InputEvent> &p_event);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_view(View p_view);
+ View get_view();
+
+ Node3DEditorViewportContainer();
+};
+
+class Node3DEditor : public VBoxContainer {
+
+ GDCLASS(Node3DEditor, VBoxContainer);
+
+public:
+ static const unsigned int VIEWPORTS_COUNT = 4;
+
+ enum ToolMode {
+
+ TOOL_MODE_SELECT,
+ TOOL_MODE_MOVE,
+ TOOL_MODE_ROTATE,
+ TOOL_MODE_SCALE,
+ TOOL_MODE_LIST_SELECT,
+ TOOL_LOCK_SELECTED,
+ TOOL_UNLOCK_SELECTED,
+ TOOL_GROUP_SELECTED,
+ TOOL_UNGROUP_SELECTED,
+ TOOL_MAX
+ };
+
+ enum ToolOptions {
+
+ TOOL_OPT_LOCAL_COORDS,
+ TOOL_OPT_USE_SNAP,
+ TOOL_OPT_OVERRIDE_CAMERA,
+ TOOL_OPT_MAX
+
+ };
+
+private:
+ EditorNode *editor;
+ EditorSelection *editor_selection;
+
+ Node3DEditorViewportContainer *viewport_base;
+ Node3DEditorViewport *viewports[VIEWPORTS_COUNT];
+ VSplitContainer *shader_split;
+ HSplitContainer *palette_split;
+
+ /////
+
+ ToolMode tool_mode;
+ bool orthogonal;
+
+ RenderingServer::ScenarioDebugMode scenario_debug;
+
+ RID origin;
+ RID origin_instance;
+ bool origin_enabled;
+ RID grid[3];
+ RID grid_instance[3];
+ bool grid_visible[3]; //currently visible
+ bool grid_enable[3]; //should be always visible if true
+ bool grid_enabled;
+
+ Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3];
+ Ref<StandardMaterial3D> gizmo_color[3];
+ Ref<StandardMaterial3D> plane_gizmo_color[3];
+ Ref<StandardMaterial3D> gizmo_color_hl[3];
+ Ref<StandardMaterial3D> plane_gizmo_color_hl[3];
+
+ int over_gizmo_handle;
+ float snap_translate_value;
+ float snap_rotate_value;
+ float snap_scale_value;
+
+ Ref<ArrayMesh> selection_box;
+ RID indicators;
+ RID indicators_instance;
+ RID cursor_mesh;
+ RID cursor_instance;
+ Ref<StandardMaterial3D> indicator_mat;
+ Ref<StandardMaterial3D> cursor_material;
+
+ // Scene drag and drop support
+ Node3D *preview_node;
+ AABB preview_bounds;
+
+ struct Gizmo {
+
+ bool visible;
+ float scale;
+ Transform transform;
+ } gizmo;
+
+ enum MenuOption {
+
+ MENU_TOOL_SELECT,
+ MENU_TOOL_MOVE,
+ MENU_TOOL_ROTATE,
+ MENU_TOOL_SCALE,
+ MENU_TOOL_LIST_SELECT,
+ MENU_TOOL_LOCAL_COORDS,
+ MENU_TOOL_USE_SNAP,
+ MENU_TOOL_OVERRIDE_CAMERA,
+ MENU_TRANSFORM_CONFIGURE_SNAP,
+ MENU_TRANSFORM_DIALOG,
+ MENU_VIEW_USE_1_VIEWPORT,
+ MENU_VIEW_USE_2_VIEWPORTS,
+ MENU_VIEW_USE_2_VIEWPORTS_ALT,
+ MENU_VIEW_USE_3_VIEWPORTS,
+ MENU_VIEW_USE_3_VIEWPORTS_ALT,
+ MENU_VIEW_USE_4_VIEWPORTS,
+ MENU_VIEW_ORIGIN,
+ MENU_VIEW_GRID,
+ MENU_VIEW_GIZMOS_3D_ICONS,
+ MENU_VIEW_CAMERA_SETTINGS,
+ MENU_LOCK_SELECTED,
+ MENU_UNLOCK_SELECTED,
+ MENU_GROUP_SELECTED,
+ MENU_UNGROUP_SELECTED,
+ MENU_SNAP_TO_FLOOR
+ };
+
+ Button *tool_button[TOOL_MAX];
+ Button *tool_option_button[TOOL_OPT_MAX];
+
+ MenuButton *transform_menu;
+ PopupMenu *gizmos_menu;
+ MenuButton *view_menu;
+
+ AcceptDialog *accept;
+
+ ConfirmationDialog *snap_dialog;
+ ConfirmationDialog *xform_dialog;
+ ConfirmationDialog *settings_dialog;
+
+ bool snap_enabled;
+ bool snap_key_enabled;
+ LineEdit *snap_translate;
+ LineEdit *snap_rotate;
+ LineEdit *snap_scale;
+ PanelContainer *menu_panel;
+
+ LineEdit *xform_translate[3];
+ LineEdit *xform_rotate[3];
+ LineEdit *xform_scale[3];
+ OptionButton *xform_type;
+
+ VBoxContainer *settings_vbc;
+ SpinBox *settings_fov;
+ SpinBox *settings_znear;
+ SpinBox *settings_zfar;
+
+ void _snap_changed();
+ void _snap_update();
+ void _xform_dialog_action();
+ void _menu_item_pressed(int p_option);
+ void _menu_item_toggled(bool pressed, int p_option);
+ void _menu_gizmo_toggled(int p_option);
+ void _update_camera_override_button(bool p_game_running);
+ void _update_camera_override_viewport(Object *p_viewport);
+
+ HBoxContainer *hbc_menu;
+
+ void _generate_selection_box();
+ UndoRedo *undo_redo;
+
+ int camera_override_viewport_id;
+
+ void _init_indicators();
+ void _update_gizmos_menu();
+ void _update_gizmos_menu_theme();
+ void _init_grid();
+ void _finish_indicators();
+ void _finish_grid();
+
+ void _toggle_maximize_view(Object *p_viewport);
+
+ Node *custom_camera;
+
+ Object *_get_editor_data(Object *p_what);
+
+ Ref<Environment> viewport_environment;
+
+ Node3D *selected;
+
+ void _request_gizmo(Object *p_obj);
+
+ static Node3DEditor *singleton;
+
+ void _node_removed(Node *p_node);
+ Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_priority;
+ Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_name;
+
+ void _register_all_gizmos();
+
+ Node3DEditor();
+
+ bool is_any_freelook_active() const;
+
+ void _refresh_menu_icons();
+
+protected:
+ void _notification(int p_what);
+ //void _gui_input(InputEvent p_event);
+ void _unhandled_key_input(Ref<InputEvent> p_event);
+
+ static void _bind_methods();
+
+public:
+ static Node3DEditor *get_singleton() { return singleton; }
+ void snap_cursor_to_plane(const Plane &p_plane);
+
+ Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const;
+
+ float get_znear() const { return settings_znear->get_value(); }
+ float get_zfar() const { return settings_zfar->get_value(); }
+ float get_fov() const { return settings_fov->get_value(); }
+
+ Transform get_gizmo_transform() const { return gizmo.transform; }
+ bool is_gizmo_visible() const { return gizmo.visible; }
+
+ ToolMode get_tool_mode() const { return tool_mode; }
+ bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
+ bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
+ float get_translate_snap() const;
+ float get_rotate_snap() const;
+ float get_scale_snap() const;
+
+ Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
+ Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
+ Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; }
+ Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
+ Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; }
+
+ void update_transform_gizmo();
+ void update_all_gizmos(Node *p_node = nullptr);
+ void snap_selected_nodes_to_floor();
+ void select_gizmo_highlight_axis(int p_axis);
+ void set_custom_camera(Node *p_camera) { custom_camera = p_camera; }
+
+ void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ Dictionary get_state() const;
+ void set_state(const Dictionary &p_state);
+
+ Ref<Environment> get_viewport_environment() { return viewport_environment; }
+
+ UndoRedo *get_undo_redo() { return undo_redo; }
+
+ void add_control_to_menu_panel(Control *p_control);
+ void remove_control_from_menu_panel(Control *p_control);
+
+ VSplitContainer *get_shader_split();
+ HSplitContainer *get_palette_split();
+
+ Node3D *get_selected() { return selected; }
+
+ int get_over_gizmo_handle() const { return over_gizmo_handle; }
+ void set_over_gizmo_handle(int idx) { over_gizmo_handle = idx; }
+
+ void set_can_preview(Camera3D *p_preview);
+
+ Node3DEditorViewport *get_editor_viewport(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), nullptr);
+ return viewports[p_idx];
+ }
+
+ void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
+ void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
+
+ void edit(Node3D *p_spatial);
+ void clear();
+
+ Node3DEditor(EditorNode *p_editor);
+ ~Node3DEditor();
+};
+
+class Node3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(Node3DEditorPlugin, EditorPlugin);
+
+ Node3DEditor *spatial_editor;
+ EditorNode *editor;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void snap_cursor_to_plane(const Plane &p_plane);
+
+ Node3DEditor *get_spatial_editor() { return spatial_editor; }
+ virtual String get_name() const { return "3D"; }
+ bool has_main_screen() const { return true; }
+ virtual void make_visible(bool p_visible);
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+
+ virtual Dictionary get_state() const;
+ virtual void set_state(const Dictionary &p_state);
+ virtual void clear() { spatial_editor->clear(); }
+
+ virtual void edited_scene_changed();
+
+ Node3DEditorPlugin(EditorNode *p_node);
+ ~Node3DEditorPlugin();
+};
+
+class EditorNode3DGizmoPlugin : public Resource {
+
+ GDCLASS(EditorNode3DGizmoPlugin, Resource);
+
+public:
+ static const int VISIBLE = 0;
+ static const int HIDDEN = 1;
+ static const int ON_TOP = 2;
+
+private:
+ int current_state;
+ List<EditorNode3DGizmo *> current_gizmos;
+ HashMap<String, Vector<Ref<StandardMaterial3D>>> materials;
+
+protected:
+ static void _bind_methods();
+ virtual bool has_gizmo(Node3D *p_spatial);
+ virtual Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial);
+
+public:
+ void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false);
+ void create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1));
+ void create_handle_material(const String &p_name, bool p_billboard = false);
+ void add_material(const String &p_name, Ref<StandardMaterial3D> p_material);
+
+ Ref<StandardMaterial3D> get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo = Ref<EditorNode3DGizmo>());
+
+ virtual String get_name() const;
+ virtual int get_priority() const;
+ virtual bool can_be_hidden() const;
+ virtual bool is_selectable_when_hidden() const;
+
+ virtual void redraw(EditorNode3DGizmo *p_gizmo);
+ virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ virtual Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ virtual void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ virtual void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
+ virtual bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+
+ Ref<EditorNode3DGizmo> get_gizmo(Node3D *p_spatial);
+ void set_state(int p_state);
+ int get_state() const;
+ void unregister_gizmo(EditorNode3DGizmo *p_gizmo);
+
+ EditorNode3DGizmoPlugin();
+ virtual ~EditorNode3DGizmoPlugin();
+};
+
+#endif
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
deleted file mode 100644
index 812144742f..0000000000
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ /dev/null
@@ -1,435 +0,0 @@
-/*************************************************************************/
-/* particles_2d_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "particles_2d_editor_plugin.h"
-
-#include "canvas_item_editor_plugin.h"
-#include "core/io/image_loader.h"
-#include "scene/2d/cpu_particles_2d.h"
-#include "scene/gui/separator.h"
-#include "scene/resources/particles_material.h"
-
-void Particles2DEditorPlugin::edit(Object *p_object) {
-
- particles = Object::cast_to<Particles2D>(p_object);
-}
-
-bool Particles2DEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Particles2D");
-}
-
-void Particles2DEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
-
- toolbar->show();
- } else {
-
- toolbar->hide();
- }
-}
-
-void Particles2DEditorPlugin::_file_selected(const String &p_file) {
-
- source_emission_file = p_file;
- emission_mask->popup_centered_minsize();
-}
-
-void Particles2DEditorPlugin::_menu_callback(int p_idx) {
-
- switch (p_idx) {
- case MENU_GENERATE_VISIBILITY_RECT: {
- float gen_time = particles->get_lifetime();
- if (gen_time < 1.0)
- generate_seconds->set_value(1.0);
- else
- generate_seconds->set_value(trunc(gen_time) + 1.0);
- generate_visibility_rect->popup_centered_minsize();
- } break;
- case MENU_LOAD_EMISSION_MASK: {
-
- file->popup_centered_ratio();
-
- } break;
- case MENU_CLEAR_EMISSION_MASK: {
-
- emission_mask->popup_centered_minsize();
- } break;
- case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
-
- CPUParticles2D *cpu_particles = memnew(CPUParticles2D);
- cpu_particles->convert_from_particles(particles);
- 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_z_index(particles->get_z_index());
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Convert to CPUParticles"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", particles, cpu_particles, true, false);
- ur->add_do_reference(cpu_particles);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, particles, false, false);
- ur->add_undo_reference(particles);
- ur->commit_action();
-
- } break;
- case MENU_RESTART: {
-
- particles->restart();
- }
- }
-}
-
-void Particles2DEditorPlugin::_generate_visibility_rect() {
-
- float time = generate_seconds->get_value();
-
- float running = 0.0;
-
- EditorProgress ep("gen_vrect", TTR("Generating Visibility Rect"), int(time));
-
- bool was_emitting = particles->is_emitting();
- if (!was_emitting) {
- particles->set_emitting(true);
- OS::get_singleton()->delay_usec(1000);
- }
-
- Rect2 rect;
- while (running < time) {
-
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- ep.step("Generating...", int(running), true);
- OS::get_singleton()->delay_usec(1000);
-
- Rect2 capture = particles->capture_rect();
- if (rect == Rect2())
- rect = capture;
- else
- rect = rect.merge(capture);
-
- running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
- }
-
- if (!was_emitting) {
- particles->set_emitting(false);
- }
-
- undo_redo->create_action(TTR("Generate Visibility Rect"));
- undo_redo->add_do_method(particles, "set_visibility_rect", rect);
- undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect());
- undo_redo->commit_action();
-}
-
-void Particles2DEditorPlugin::_generate_emission_mask() {
-
- Ref<ParticlesMaterial> pm = particles->get_process_material();
- if (!pm.is_valid()) {
- EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material"));
- return;
- }
-
- Ref<Image> img;
- img.instance();
- Error err = ImageLoader::load_image(source_emission_file, img);
- ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'.");
-
- if (img->is_compressed()) {
- img->decompress();
- }
- img->convert(Image::FORMAT_RGBA8);
- ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
- Size2i s = Size2(img->get_width(), img->get_height());
- ERR_FAIL_COND(s.width == 0 || s.height == 0);
-
- Vector<Point2> valid_positions;
- Vector<Point2> valid_normals;
- Vector<uint8_t> valid_colors;
-
- valid_positions.resize(s.width * s.height);
-
- EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected();
-
- if (emode == EMISSION_MODE_BORDER_DIRECTED) {
- valid_normals.resize(s.width * s.height);
- }
-
- bool capture_colors = emission_colors->is_pressed();
-
- if (capture_colors) {
- valid_colors.resize(s.width * s.height * 4);
- }
-
- int vpc = 0;
-
- {
- Vector<uint8_t> data = img->get_data();
- const uint8_t *r = data.ptr();
-
- for (int i = 0; i < s.width; i++) {
- for (int j = 0; j < s.height; j++) {
-
- uint8_t a = r[(j * s.width + i) * 4 + 3];
-
- if (a > 128) {
-
- if (emode == EMISSION_MODE_SOLID) {
-
- if (capture_colors) {
- valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
- valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
- valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
- valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
- }
- valid_positions.write[vpc++] = Point2(i, j);
-
- } else {
-
- bool on_border = false;
- for (int x = i - 1; x <= i + 1; x++) {
- for (int y = j - 1; y <= j + 1; y++) {
-
- if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
- on_border = true;
- break;
- }
- }
-
- if (on_border)
- break;
- }
-
- if (on_border) {
- valid_positions.write[vpc] = Point2(i, j);
-
- if (emode == EMISSION_MODE_BORDER_DIRECTED) {
- Vector2 normal;
- for (int x = i - 2; x <= i + 2; x++) {
- for (int y = j - 2; y <= j + 2; y++) {
-
- if (x == i && y == j)
- continue;
-
- if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
- normal += Vector2(x - i, y - j).normalized();
- }
- }
- }
-
- normal.normalize();
- valid_normals.write[vpc] = normal;
- }
-
- if (capture_colors) {
- valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
- valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
- valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
- valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
- }
-
- vpc++;
- }
- }
- }
- }
- }
- }
-
- valid_positions.resize(vpc);
- if (valid_normals.size()) {
- valid_normals.resize(vpc);
- }
-
- ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image...");
-
- Vector<uint8_t> texdata;
-
- int w = 2048;
- int h = (vpc / 2048) + 1;
-
- texdata.resize(w * h * 2 * sizeof(float));
-
- {
- uint8_t *tw = texdata.ptrw();
- float *twf = (float *)tw;
- for (int i = 0; i < vpc; i++) {
-
- twf[i * 2 + 0] = valid_positions[i].x;
- twf[i * 2 + 1] = valid_positions[i].y;
- }
- }
-
- img.instance();
- img->create(w, h, false, Image::FORMAT_RGF, texdata);
-
- Ref<ImageTexture> imgt;
- imgt.instance();
- imgt->create_from_image(img);
-
- pm->set_emission_point_texture(imgt);
- pm->set_emission_point_count(vpc);
-
- if (capture_colors) {
-
- Vector<uint8_t> colordata;
- colordata.resize(w * h * 4); //use RG texture
-
- {
- uint8_t *tw = colordata.ptrw();
- for (int i = 0; i < vpc * 4; i++) {
-
- tw[i] = valid_colors[i];
- }
- }
-
- img.instance();
- img->create(w, h, false, Image::FORMAT_RGBA8, colordata);
-
- imgt.instance();
- imgt->create_from_image(img);
- pm->set_emission_color_texture(imgt);
- }
-
- if (valid_normals.size()) {
- pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
-
- Vector<uint8_t> normdata;
- normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
-
- {
- uint8_t *tw = normdata.ptrw();
- float *twf = (float *)tw;
- for (int i = 0; i < vpc; i++) {
- twf[i * 2 + 0] = valid_normals[i].x;
- twf[i * 2 + 1] = valid_normals[i].y;
- }
- }
-
- img.instance();
- img->create(w, h, false, Image::FORMAT_RGF, normdata);
-
- imgt.instance();
- imgt->create_from_image(img);
- pm->set_emission_normal_texture(imgt);
-
- } else {
- pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
- }
-}
-
-void Particles2DEditorPlugin::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- menu->get_popup()->connect("id_pressed", callable_mp(this, &Particles2DEditorPlugin::_menu_callback));
- menu->set_icon(menu->get_popup()->get_icon("Particles2D", "EditorIcons"));
- file->connect("file_selected", callable_mp(this, &Particles2DEditorPlugin::_file_selected));
- }
-}
-
-void Particles2DEditorPlugin::_bind_methods() {
-}
-
-Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
-
- particles = NULL;
- editor = p_node;
- undo_redo = editor->get_undo_redo();
-
- toolbar = memnew(HBoxContainer);
- add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
- toolbar->hide();
-
- toolbar->add_child(memnew(VSeparator));
-
- menu = memnew(MenuButton);
- menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT);
- menu->get_popup()->add_separator();
- menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
- // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
- menu->get_popup()->add_separator();
- menu->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
- menu->get_popup()->add_separator();
- menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART);
- menu->set_text(TTR("Particles"));
- menu->set_switch_on_hover(true);
- toolbar->add_child(menu);
-
- file = memnew(EditorFileDialog);
- List<String> ext;
- ImageLoader::get_recognized_extensions(&ext);
- for (List<String>::Element *E = ext.front(); E; E = E->next()) {
- file->add_filter("*." + E->get() + "; " + E->get().to_upper());
- }
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
- toolbar->add_child(file);
-
- epoints = memnew(SpinBox);
- epoints->set_min(1);
- epoints->set_max(8192);
- epoints->set_step(1);
- epoints->set_value(512);
- file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints);
-
- generate_visibility_rect = memnew(ConfirmationDialog);
- generate_visibility_rect->set_title(TTR("Generate Visibility Rect"));
- VBoxContainer *genvb = memnew(VBoxContainer);
- generate_visibility_rect->add_child(genvb);
- generate_seconds = memnew(SpinBox);
- genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
- generate_seconds->set_min(0.1);
- generate_seconds->set_max(25);
- generate_seconds->set_value(2);
-
- toolbar->add_child(generate_visibility_rect);
-
- generate_visibility_rect->connect("confirmed", callable_mp(this, &Particles2DEditorPlugin::_generate_visibility_rect));
-
- emission_mask = memnew(ConfirmationDialog);
- emission_mask->set_title(TTR("Load Emission Mask"));
- VBoxContainer *emvb = memnew(VBoxContainer);
- emission_mask->add_child(emvb);
- emission_mask_mode = memnew(OptionButton);
- emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode);
- emission_mask_mode->add_item(TTR("Solid Pixels"), EMISSION_MODE_SOLID);
- emission_mask_mode->add_item(TTR("Border Pixels"), EMISSION_MODE_BORDER);
- emission_mask_mode->add_item(TTR("Directed Border Pixels"), EMISSION_MODE_BORDER_DIRECTED);
- emission_colors = memnew(CheckBox);
- emission_colors->set_text(TTR("Capture from Pixel"));
- emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
-
- toolbar->add_child(emission_mask);
-
- emission_mask->connect("confirmed", callable_mp(this, &Particles2DEditorPlugin::_generate_emission_mask));
-}
-
-Particles2DEditorPlugin::~Particles2DEditorPlugin() {
-}
diff --git a/editor/plugins/particles_2d_editor_plugin.h b/editor/plugins/particles_2d_editor_plugin.h
deleted file mode 100644
index 29652a1826..0000000000
--- a/editor/plugins/particles_2d_editor_plugin.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*************************************************************************/
-/* particles_2d_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PARTICLES_2D_EDITOR_PLUGIN_H
-#define PARTICLES_2D_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/2d/collision_polygon_2d.h"
-#include "scene/2d/particles_2d.h"
-#include "scene/gui/box_container.h"
-#include "scene/gui/file_dialog.h"
-
-class Particles2DEditorPlugin : public EditorPlugin {
-
- GDCLASS(Particles2DEditorPlugin, EditorPlugin);
-
- enum {
-
- MENU_GENERATE_VISIBILITY_RECT,
- MENU_LOAD_EMISSION_MASK,
- MENU_CLEAR_EMISSION_MASK,
- MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
- MENU_RESTART
- };
-
- enum EmissionMode {
- EMISSION_MODE_SOLID,
- EMISSION_MODE_BORDER,
- EMISSION_MODE_BORDER_DIRECTED
- };
-
- Particles2D *particles;
-
- EditorFileDialog *file;
- EditorNode *editor;
-
- HBoxContainer *toolbar;
- MenuButton *menu;
-
- SpinBox *epoints;
-
- ConfirmationDialog *generate_visibility_rect;
- SpinBox *generate_seconds;
-
- ConfirmationDialog *emission_mask;
- OptionButton *emission_mask_mode;
- CheckBox *emission_colors;
-
- String source_emission_file;
-
- UndoRedo *undo_redo;
- void _file_selected(const String &p_file);
- void _menu_callback(int p_idx);
- void _generate_visibility_rect();
- void _generate_emission_mask();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- virtual String get_name() const { return "Particles2D"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- Particles2DEditorPlugin(EditorNode *p_node);
- ~Particles2DEditorPlugin();
-};
-
-#endif // PARTICLES_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
deleted file mode 100644
index a4d704c6e1..0000000000
--- a/editor/plugins/particles_editor_plugin.cpp
+++ /dev/null
@@ -1,493 +0,0 @@
-/*************************************************************************/
-/* particles_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "particles_editor_plugin.h"
-
-#include "core/io/resource_loader.h"
-#include "editor/plugins/spatial_editor_plugin.h"
-#include "scene/3d/cpu_particles.h"
-#include "scene/resources/particles_material.h"
-
-bool ParticlesEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) {
-
- bool use_normals = emission_fill->get_selected() == 1;
-
- if (emission_fill->get_selected() < 2) {
-
- float area_accum = 0;
- Map<float, int> triangle_area_map;
-
- for (int i = 0; i < geometry.size(); i++) {
-
- float area = geometry[i].get_area();
- if (area < CMP_EPSILON)
- continue;
- triangle_area_map[area_accum] = i;
- area_accum += area;
- }
-
- if (!triangle_area_map.size() || area_accum == 0) {
-
- EditorNode::get_singleton()->show_warning(TTR("The geometry's faces don't contain any area."));
- return false;
- }
-
- int emissor_count = emission_amount->get_value();
-
- for (int i = 0; i < emissor_count; i++) {
-
- float areapos = Math::random(0.0f, area_accum);
-
- Map<float, int>::Element *E = triangle_area_map.find_closest(areapos);
- ERR_FAIL_COND_V(!E, false);
- int index = E->get();
- ERR_FAIL_INDEX_V(index, geometry.size(), false);
-
- // ok FINALLY get face
- Face3 face = geometry[index];
- //now compute some position inside the face...
-
- Vector3 pos = face.get_random_point_inside();
-
- points.push_back(pos);
-
- if (use_normals) {
- Vector3 normal = face.get_plane().normal;
- normals.push_back(normal);
- }
- }
- } else {
-
- int gcount = geometry.size();
-
- if (gcount == 0) {
-
- EditorNode::get_singleton()->show_warning(TTR("The geometry doesn't contain any faces."));
- return false;
- }
-
- const Face3 *r = geometry.ptr();
-
- AABB aabb;
-
- for (int i = 0; i < gcount; i++) {
-
- for (int j = 0; j < 3; j++) {
-
- if (i == 0 && j == 0)
- aabb.position = r[i].vertex[j];
- else
- aabb.expand_to(r[i].vertex[j]);
- }
- }
-
- int emissor_count = emission_amount->get_value();
-
- for (int i = 0; i < emissor_count; i++) {
-
- int attempts = 5;
-
- for (int j = 0; j < attempts; j++) {
-
- Vector3 dir;
- dir[Math::rand() % 3] = 1.0;
- Vector3 ofs = (Vector3(1, 1, 1) - dir) * Vector3(Math::randf(), Math::randf(), Math::randf()) * aabb.size + aabb.position;
-
- Vector3 ofsv = ofs + aabb.size * dir;
-
- //space it a little
- ofs -= dir;
- ofsv += dir;
-
- float max = -1e7, min = 1e7;
-
- for (int k = 0; k < gcount; k++) {
-
- const Face3 &f3 = r[k];
-
- Vector3 res;
- if (f3.intersects_segment(ofs, ofsv, &res)) {
-
- res -= ofs;
- float d = dir.dot(res);
-
- if (d < min)
- min = d;
- if (d > max)
- max = d;
- }
- }
-
- if (max < min)
- continue; //lost attempt
-
- float val = min + (max - min) * Math::randf();
-
- Vector3 point = ofs + dir * val;
-
- points.push_back(point);
- break;
- }
- }
- }
-
- return true;
-}
-
-void ParticlesEditorBase::_node_selected(const NodePath &p_path) {
-
- Node *sel = get_node(p_path);
- if (!sel)
- return;
-
- if (!sel->is_class("Spatial")) {
-
- EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't inherit from Spatial."), sel->get_name()));
- return;
- }
-
- VisualInstance *vi = Object::cast_to<VisualInstance>(sel);
- if (!vi) {
-
- EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain geometry."), sel->get_name()));
- return;
- }
-
- geometry = vi->get_faces(VisualInstance::FACES_SOLID);
-
- if (geometry.size() == 0) {
-
- EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain face geometry."), sel->get_name()));
- return;
- }
-
- Transform geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform();
-
- int gc = geometry.size();
- Face3 *w = geometry.ptrw();
-
- for (int i = 0; i < gc; i++) {
- for (int j = 0; j < 3; j++) {
- w[i].vertex[j] = geom_xform.xform(w[i].vertex[j]);
- }
- }
-
- emission_dialog->popup_centered(Size2(300, 130));
-}
-
-void ParticlesEditorBase::_bind_methods() {
-}
-
-ParticlesEditorBase::ParticlesEditorBase() {
-
- emission_dialog = memnew(ConfirmationDialog);
- emission_dialog->set_title(TTR("Create Emitter"));
- add_child(emission_dialog);
- VBoxContainer *emd_vb = memnew(VBoxContainer);
- emission_dialog->add_child(emd_vb);
-
- emission_amount = memnew(SpinBox);
- emission_amount->set_min(1);
- emission_amount->set_max(100000);
- emission_amount->set_value(512);
- emd_vb->add_margin_child(TTR("Emission Points:"), emission_amount);
-
- emission_fill = memnew(OptionButton);
- emission_fill->add_item(TTR("Surface Points"));
- emission_fill->add_item(TTR("Surface Points+Normal (Directed)"));
- emission_fill->add_item(TTR("Volume"));
- emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill);
-
- emission_dialog->get_ok()->set_text(TTR("Create"));
- emission_dialog->connect("confirmed", callable_mp(this, &ParticlesEditorBase::_generate_emission_points));
-
- emission_tree_dialog = memnew(SceneTreeDialog);
- add_child(emission_tree_dialog);
- emission_tree_dialog->connect("selected", callable_mp(this, &ParticlesEditorBase::_node_selected));
-}
-
-void ParticlesEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- hide();
- }
-}
-
-void ParticlesEditor::_notification(int p_notification) {
-
- if (p_notification == NOTIFICATION_ENTER_TREE) {
- options->set_icon(options->get_popup()->get_icon("Particles", "EditorIcons"));
- get_tree()->connect("node_removed", callable_mp(this, &ParticlesEditor::_node_removed));
- }
-}
-
-void ParticlesEditor::_menu_option(int p_option) {
-
- switch (p_option) {
-
- case MENU_OPTION_GENERATE_AABB: {
- float gen_time = node->get_lifetime();
-
- if (gen_time < 1.0)
- generate_seconds->set_value(1.0);
- else
- generate_seconds->set_value(trunc(gen_time) + 1.0);
- generate_aabb->popup_centered_minsize();
- } break;
- case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
- Ref<ParticlesMaterial> material = node->get_process_material();
- if (material.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
- return;
- }
-
- emission_tree_dialog->popup_centered_ratio();
-
- } break;
- case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
-
- CPUParticles *cpu_particles = memnew(CPUParticles);
- cpu_particles->convert_from_particles(node);
- 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());
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Convert to CPUParticles"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, cpu_particles, true, false);
- ur->add_do_reference(cpu_particles);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, node, false, false);
- ur->add_undo_reference(node);
- ur->commit_action();
-
- } break;
- case MENU_OPTION_RESTART: {
-
- node->restart();
-
- } break;
- }
-}
-
-void ParticlesEditor::_generate_aabb() {
-
- float time = generate_seconds->get_value();
-
- float running = 0.0;
-
- EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
-
- bool was_emitting = node->is_emitting();
- if (!was_emitting) {
- node->set_emitting(true);
- OS::get_singleton()->delay_usec(1000);
- }
-
- AABB rect;
-
- while (running < time) {
-
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- ep.step("Generating...", int(running), true);
- OS::get_singleton()->delay_usec(1000);
-
- AABB capture = node->capture_aabb();
- if (rect == AABB())
- rect = capture;
- else
- rect.merge_with(capture);
-
- running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
- }
-
- if (!was_emitting) {
- node->set_emitting(false);
- }
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Generate Visibility AABB"));
- ur->add_do_method(node, "set_visibility_aabb", rect);
- ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
- ur->commit_action();
-}
-
-void ParticlesEditor::edit(Particles *p_particles) {
-
- base_node = p_particles;
- node = p_particles;
-}
-
-void ParticlesEditor::_generate_emission_points() {
-
- /// hacer codigo aca
- Vector<Vector3> points;
- Vector<Vector3> normals;
-
- if (!_generate(points, normals)) {
- return;
- }
-
- int point_count = points.size();
-
- int w = 2048;
- int h = (point_count / 2048) + 1;
-
- Vector<uint8_t> point_img;
- point_img.resize(w * h * 3 * sizeof(float));
-
- {
- uint8_t *iw = point_img.ptrw();
- zeromem(iw, w * h * 3 * sizeof(float));
- const Vector3 *r = points.ptr();
- float *wf = (float *)iw;
- for (int i = 0; i < point_count; i++) {
- wf[i * 3 + 0] = r[i].x;
- wf[i * 3 + 1] = r[i].y;
- wf[i * 3 + 2] = r[i].z;
- }
- }
-
- Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
-
- Ref<ImageTexture> tex;
- tex.instance();
-
- Ref<ParticlesMaterial> material = node->get_process_material();
- ERR_FAIL_COND(material.is_null());
-
- if (normals.size() > 0) {
-
- material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
- material->set_emission_point_count(point_count);
- material->set_emission_point_texture(tex);
-
- Vector<uint8_t> point_img2;
- point_img2.resize(w * h * 3 * sizeof(float));
-
- {
- uint8_t *iw = point_img2.ptrw();
- zeromem(iw, w * h * 3 * sizeof(float));
- const Vector3 *r = normals.ptr();
- float *wf = (float *)iw;
- for (int i = 0; i < point_count; i++) {
- wf[i * 3 + 0] = r[i].x;
- wf[i * 3 + 1] = r[i].y;
- wf[i * 3 + 2] = r[i].z;
- }
- }
-
- Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
-
- Ref<ImageTexture> tex2;
- tex2.instance();
-
- material->set_emission_normal_texture(tex2);
- } else {
-
- material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
- material->set_emission_point_count(point_count);
- material->set_emission_point_texture(tex);
- }
-}
-
-void ParticlesEditor::_bind_methods() {
-}
-
-ParticlesEditor::ParticlesEditor() {
-
- node = NULL;
- particles_editor_hb = memnew(HBoxContainer);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
- options = memnew(MenuButton);
- options->set_switch_on_hover(true);
- particles_editor_hb->add_child(options);
- particles_editor_hb->hide();
-
- options->set_text(TTR("Particles"));
- options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB);
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
- options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART);
-
- options->get_popup()->connect("id_pressed", callable_mp(this, &ParticlesEditor::_menu_option));
-
- generate_aabb = memnew(ConfirmationDialog);
- generate_aabb->set_title(TTR("Generate Visibility AABB"));
- VBoxContainer *genvb = memnew(VBoxContainer);
- generate_aabb->add_child(genvb);
- generate_seconds = memnew(SpinBox);
- genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
- generate_seconds->set_min(0.1);
- generate_seconds->set_max(25);
- generate_seconds->set_value(2);
-
- add_child(generate_aabb);
-
- generate_aabb->connect("confirmed", callable_mp(this, &ParticlesEditor::_generate_aabb));
-}
-
-void ParticlesEditorPlugin::edit(Object *p_object) {
-
- particles_editor->edit(Object::cast_to<Particles>(p_object));
-}
-
-bool ParticlesEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Particles");
-}
-
-void ParticlesEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- particles_editor->show();
- particles_editor->particles_editor_hb->show();
- } else {
- particles_editor->particles_editor_hb->hide();
- particles_editor->hide();
- particles_editor->edit(NULL);
- }
-}
-
-ParticlesEditorPlugin::ParticlesEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- particles_editor = memnew(ParticlesEditor);
- editor->get_viewport()->add_child(particles_editor);
-
- particles_editor->hide();
-}
-
-ParticlesEditorPlugin::~ParticlesEditorPlugin() {
-}
diff --git a/editor/plugins/particles_editor_plugin.h b/editor/plugins/particles_editor_plugin.h
deleted file mode 100644
index fb5ce17560..0000000000
--- a/editor/plugins/particles_editor_plugin.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*************************************************************************/
-/* particles_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PARTICLES_EDITOR_PLUGIN_H
-#define PARTICLES_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/3d/particles.h"
-#include "scene/gui/spin_box.h"
-
-class ParticlesEditorBase : public Control {
-
- GDCLASS(ParticlesEditorBase, Control);
-
-protected:
- Spatial *base_node;
- Panel *panel;
- MenuButton *options;
- HBoxContainer *particles_editor_hb;
-
- SceneTreeDialog *emission_tree_dialog;
-
- ConfirmationDialog *emission_dialog;
- SpinBox *emission_amount;
- OptionButton *emission_fill;
-
- Vector<Face3> geometry;
-
- bool _generate(Vector<Vector3> &points, Vector<Vector3> &normals);
- virtual void _generate_emission_points() = 0;
- void _node_selected(const NodePath &p_path);
-
- static void _bind_methods();
-
-public:
- ParticlesEditorBase();
-};
-
-class ParticlesEditor : public ParticlesEditorBase {
-
- GDCLASS(ParticlesEditor, ParticlesEditorBase);
-
- ConfirmationDialog *generate_aabb;
- SpinBox *generate_seconds;
- Particles *node;
-
- enum Menu {
-
- MENU_OPTION_GENERATE_AABB,
- MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
- MENU_OPTION_CLEAR_EMISSION_VOLUME,
- MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
- MENU_OPTION_RESTART,
-
- };
-
- void _generate_aabb();
-
- void _menu_option(int);
-
- friend class ParticlesEditorPlugin;
-
- virtual void _generate_emission_points();
-
-protected:
- void _notification(int p_notification);
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
-public:
- void edit(Particles *p_particles);
- ParticlesEditor();
-};
-
-class ParticlesEditorPlugin : public EditorPlugin {
-
- GDCLASS(ParticlesEditorPlugin, EditorPlugin);
-
- ParticlesEditor *particles_editor;
- EditorNode *editor;
-
-public:
- virtual String get_name() const { return "Particles"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- ParticlesEditorPlugin(EditorNode *p_node);
- ~ParticlesEditorPlugin();
-};
-
-#endif // PARTICLES_EDITOR_PLUGIN_H
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 165df6b500..4516b7035b 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -56,7 +56,7 @@ void Path2DEditor::_notification(int p_what) {
void Path2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
- node = NULL;
+ node = nullptr;
hide();
}
}
@@ -288,7 +288,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Vector2 gpoint = mm->get_position();
Ref<Curve2D> curve = node->get_curve();
- if (curve == NULL) return true;
+ if (curve == nullptr) return true;
if (curve->get_point_count() < 2) return true;
// Find edge
@@ -373,12 +373,12 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- const Ref<Texture2D> path_sharp_handle = get_icon("EditorPathSharpHandle", "EditorIcons");
- const Ref<Texture2D> path_smooth_handle = get_icon("EditorPathSmoothHandle", "EditorIcons");
+ const Ref<Texture2D> path_sharp_handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons");
+ const Ref<Texture2D> path_smooth_handle = get_theme_icon("EditorPathSmoothHandle", "EditorIcons");
// Both handle icons must be of the same size
const Size2 handle_size = path_sharp_handle->get_size();
- const Ref<Texture2D> curve_handle = get_icon("EditorCurveHandle", "EditorIcons");
+ const Ref<Texture2D> curve_handle = get_theme_icon("EditorCurveHandle", "EditorIcons");
const Size2 curve_handle_size = curve_handle->get_size();
Ref<Curve2D> curve = node->get_curve();
@@ -420,7 +420,7 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
if (on_edge) {
- Ref<Texture2D> add_handle = get_icon("EditorHandleAdd", "EditorIcons");
+ Ref<Texture2D> add_handle = get_theme_icon("EditorHandleAdd", "EditorIcons");
p_overlay->draw_texture(add_handle, edge_point - add_handle->get_size() * 0.5);
}
}
@@ -449,7 +449,7 @@ void Path2DEditor::edit(Node *p_path2d) {
// node may have been deleted at this point
if (node && node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed)))
node->disconnect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed));
- node = NULL;
+ node = nullptr;
}
}
@@ -532,7 +532,7 @@ void Path2DEditor::_handle_option_pressed(int p_option) {
Path2DEditor::Path2DEditor(EditorNode *p_editor) {
- canvas_item_editor = NULL;
+ canvas_item_editor = nullptr;
editor = p_editor;
undo_redo = editor->get_undo_redo();
mirror_handle_angle = true;
@@ -548,35 +548,35 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
sep = memnew(VSeparator);
base_hb->add_child(sep);
curve_edit = memnew(ToolButton);
- curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
+ curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons"));
curve_edit->set_toggle_mode(true);
curve_edit->set_focus_mode(Control::FOCUS_NONE);
curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT));
base_hb->add_child(curve_edit);
curve_edit_curve = memnew(ToolButton);
- curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCurve", "EditorIcons"));
+ curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCurve", "EditorIcons"));
curve_edit_curve->set_toggle_mode(true);
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)"));
curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT_CURVE));
base_hb->add_child(curve_edit_curve);
curve_create = memnew(ToolButton);
- curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
+ curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons"));
curve_create->set_toggle_mode(true);
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip(TTR("Add Point (in empty space)"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_CREATE));
base_hb->add_child(curve_create);
curve_del = memnew(ToolButton);
- curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons"));
+ curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons"));
curve_del->set_toggle_mode(true);
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip(TTR("Delete Point"));
curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_DELETE));
base_hb->add_child(curve_del);
curve_close = memnew(ToolButton);
- curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveClose", "EditorIcons"));
+ curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveClose", "EditorIcons"));
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip(TTR("Close Curve"));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(ACTION_CLOSE));
@@ -620,7 +620,7 @@ void Path2DEditorPlugin::make_visible(bool p_visible) {
path2d_editor->hide();
path2d_editor->base_hb->hide();
- path2d_editor->edit(NULL);
+ path2d_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..d3ece9556d
--- /dev/null
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -0,0 +1,653 @@
+/*************************************************************************/
+/* path_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "path_3d_editor_plugin.h"
+
+#include "core/os/keyboard.h"
+#include "node_3d_editor_plugin.h"
+#include "scene/resources/curve.h"
+
+String Path3DGizmo::get_handle_name(int p_idx) const {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return "";
+
+ if (p_idx < c->get_point_count()) {
+
+ return TTR("Curve Point #") + itos(p_idx);
+ }
+
+ p_idx = p_idx - c->get_point_count() + 1;
+
+ int idx = p_idx / 2;
+ int t = p_idx % 2;
+ String n = TTR("Curve Point #") + itos(idx);
+ if (t == 0)
+ n += " In";
+ else
+ n += " Out";
+
+ return n;
+}
+Variant Path3DGizmo::get_handle_value(int p_idx) {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return Variant();
+
+ if (p_idx < c->get_point_count()) {
+
+ original = c->get_point_position(p_idx);
+ return original;
+ }
+
+ p_idx = p_idx - c->get_point_count() + 1;
+
+ int idx = p_idx / 2;
+ int t = p_idx % 2;
+
+ Vector3 ofs;
+ if (t == 0)
+ ofs = c->get_point_in(idx);
+ else
+ ofs = c->get_point_out(idx);
+
+ original = ofs + c->get_point_position(idx);
+
+ return ofs;
+}
+void Path3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+
+ Transform gt = path->get_global_transform();
+ Transform gi = gt.affine_inverse();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ // Setting curve point positions
+ if (p_idx < c->get_point_count()) {
+
+ Plane p(gt.xform(original), p_camera->get_transform().basis.get_axis(2));
+
+ Vector3 inters;
+
+ if (p.intersects_ray(ray_from, ray_dir, &inters)) {
+
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ float snap = Node3DEditor::get_singleton()->get_translate_snap();
+ inters.snap(Vector3(snap, snap, snap));
+ }
+
+ Vector3 local = gi.xform(inters);
+ c->set_point_position(p_idx, local);
+ }
+
+ return;
+ }
+
+ p_idx = p_idx - c->get_point_count() + 1;
+
+ int idx = p_idx / 2;
+ int t = p_idx % 2;
+
+ Vector3 base = c->get_point_position(idx);
+
+ Plane p(gt.xform(original), p_camera->get_transform().basis.get_axis(2));
+
+ Vector3 inters;
+
+ // Setting curve in/out positions
+ if (p.intersects_ray(ray_from, ray_dir, &inters)) {
+
+ if (!Path3DEditorPlugin::singleton->is_handle_clicked()) {
+ orig_in_length = c->get_point_in(idx).length();
+ orig_out_length = c->get_point_out(idx).length();
+ Path3DEditorPlugin::singleton->set_handle_clicked(true);
+ }
+
+ Vector3 local = gi.xform(inters) - base;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ float snap = Node3DEditor::get_singleton()->get_translate_snap();
+ local.snap(Vector3(snap, snap, snap));
+ }
+
+ if (t == 0) {
+ c->set_point_in(idx, local);
+ if (Path3DEditorPlugin::singleton->mirror_angle_enabled())
+ c->set_point_out(idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length));
+ } else {
+ c->set_point_out(idx, local);
+ if (Path3DEditorPlugin::singleton->mirror_angle_enabled())
+ c->set_point_in(idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_in_length));
+ }
+ }
+}
+
+void Path3DGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+
+ if (p_idx < c->get_point_count()) {
+
+ if (p_cancel) {
+
+ c->set_point_position(p_idx, p_restore);
+ return;
+ }
+ ur->create_action(TTR("Set Curve Point Position"));
+ ur->add_do_method(c.ptr(), "set_point_position", p_idx, c->get_point_position(p_idx));
+ ur->add_undo_method(c.ptr(), "set_point_position", p_idx, p_restore);
+ ur->commit_action();
+
+ return;
+ }
+
+ p_idx = p_idx - c->get_point_count() + 1;
+
+ int idx = p_idx / 2;
+ int t = p_idx % 2;
+
+ if (t == 0) {
+ if (p_cancel) {
+ c->set_point_in(p_idx, p_restore);
+ return;
+ }
+
+ ur->create_action(TTR("Set Curve In Position"));
+ ur->add_do_method(c.ptr(), "set_point_in", idx, c->get_point_in(idx));
+ ur->add_undo_method(c.ptr(), "set_point_in", idx, p_restore);
+
+ if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) {
+ ur->add_do_method(c.ptr(), "set_point_out", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_in(idx) : (-c->get_point_in(idx).normalized() * orig_out_length));
+ ur->add_undo_method(c.ptr(), "set_point_out", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_out_length));
+ }
+ ur->commit_action();
+
+ } else {
+ if (p_cancel) {
+ c->set_point_out(idx, p_restore);
+
+ return;
+ }
+
+ ur->create_action(TTR("Set Curve Out Position"));
+ ur->add_do_method(c.ptr(), "set_point_out", idx, c->get_point_out(idx));
+ ur->add_undo_method(c.ptr(), "set_point_out", idx, p_restore);
+
+ if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) {
+ ur->add_do_method(c.ptr(), "set_point_in", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_out(idx) : (-c->get_point_out(idx).normalized() * orig_in_length));
+ ur->add_undo_method(c.ptr(), "set_point_in", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_in_length));
+ }
+ ur->commit_action();
+ }
+}
+
+void Path3DGizmo::redraw() {
+
+ clear();
+
+ Ref<StandardMaterial3D> path_material = gizmo_plugin->get_material("path_material", this);
+ Ref<StandardMaterial3D> path_thin_material = gizmo_plugin->get_material("path_thin_material", this);
+ Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles");
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+
+ Vector<Vector3> v3a = c->tessellate();
+ //Vector<Vector3> v3a=c->get_baked_points();
+
+ int v3s = v3a.size();
+ if (v3s == 0)
+ return;
+ Vector<Vector3> v3p;
+ const Vector3 *r = v3a.ptr();
+
+ // BUG: the following won't work when v3s, avoid drawing as a temporary workaround.
+ for (int i = 0; i < v3s - 1; i++) {
+
+ v3p.push_back(r[i]);
+ v3p.push_back(r[i + 1]);
+ //v3p.push_back(r[i]);
+ //v3p.push_back(r[i]+Vector3(0,0.2,0));
+ }
+
+ if (v3p.size() > 1) {
+ add_lines(v3p, path_material);
+ add_collision_segments(v3p);
+ }
+
+ if (Path3DEditorPlugin::singleton->get_edited_path() == path) {
+ v3p.clear();
+ Vector<Vector3> handles;
+ Vector<Vector3> sec_handles;
+
+ for (int i = 0; i < c->get_point_count(); i++) {
+
+ Vector3 p = c->get_point_position(i);
+ handles.push_back(p);
+ if (i > 0) {
+ v3p.push_back(p);
+ v3p.push_back(p + c->get_point_in(i));
+ sec_handles.push_back(p + c->get_point_in(i));
+ }
+
+ if (i < c->get_point_count() - 1) {
+ v3p.push_back(p);
+ v3p.push_back(p + c->get_point_out(i));
+ sec_handles.push_back(p + c->get_point_out(i));
+ }
+ }
+
+ if (v3p.size() > 1) {
+ add_lines(v3p, path_thin_material);
+ }
+ if (handles.size()) {
+ add_handles(handles, handles_material);
+ }
+ if (sec_handles.size()) {
+ add_handles(sec_handles, handles_material, false, true);
+ }
+ }
+}
+
+Path3DGizmo::Path3DGizmo(Path3D *p_path) {
+
+ path = p_path;
+ set_spatial_node(p_path);
+}
+
+bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+
+ if (!path)
+ return false;
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return false;
+ Transform gt = path->get_global_transform();
+ Transform it = gt.affine_inverse();
+
+ static const int click_dist = 10; //should make global
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+
+ Point2 mbpos(mb->get_position().x, mb->get_position().y);
+
+ if (!mb->is_pressed())
+ 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()))) {
+ //click into curve, break it down
+ Vector<Vector3> v3a = c->tessellate();
+ int idx = 0;
+ int rc = v3a.size();
+ int closest_seg = -1;
+ Vector3 closest_seg_point;
+ float closest_d = 1e20;
+
+ if (rc >= 2) {
+ const Vector3 *r = v3a.ptr();
+
+ if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist)
+ return false; //nope, existing
+
+ for (int i = 0; i < c->get_point_count() - 1; i++) {
+ //find the offset and point index of the place to break up
+ int j = idx;
+ if (p_camera->unproject_position(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist)
+ return false; //nope, existing
+
+ while (j < rc && c->get_point_position(i + 1) != r[j]) {
+
+ Vector3 from = r[j];
+ Vector3 to = r[j + 1];
+ real_t cdist = from.distance_to(to);
+ from = gt.xform(from);
+ to = gt.xform(to);
+ if (cdist > 0) {
+ Vector2 s[2];
+ s[0] = p_camera->unproject_position(from);
+ s[1] = p_camera->unproject_position(to);
+ Vector2 inters = Geometry::get_closest_point_to_segment_2d(mbpos, s);
+ float d = inters.distance_to(mbpos);
+
+ if (d < 10 && d < closest_d) {
+
+ closest_d = d;
+ closest_seg = i;
+ Vector3 ray_from = p_camera->project_ray_origin(mbpos);
+ Vector3 ray_dir = p_camera->project_ray_normal(mbpos);
+
+ Vector3 ra, rb;
+ Geometry::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb);
+
+ closest_seg_point = it.xform(rb);
+ }
+ }
+ j++;
+ }
+ if (idx == j)
+ idx++; //force next
+ else
+ idx = j; //swap
+
+ if (j == rc)
+ break;
+ }
+ }
+
+ UndoRedo *ur = editor->get_undo_redo();
+ if (closest_seg != -1) {
+ //subdivide
+
+ ur->create_action(TTR("Split Path"));
+ ur->add_do_method(c.ptr(), "add_point", closest_seg_point, Vector3(), Vector3(), closest_seg + 1);
+ ur->add_undo_method(c.ptr(), "remove_point", closest_seg + 1);
+ ur->commit_action();
+ return true;
+
+ } else {
+
+ Vector3 org;
+ if (c->get_point_count() == 0)
+ org = path->get_transform().get_origin();
+ else
+ org = gt.xform(c->get_point_position(c->get_point_count() - 1));
+ Plane p(org, p_camera->get_transform().basis.get_axis(2));
+ Vector3 ray_from = p_camera->project_ray_origin(mbpos);
+ Vector3 ray_dir = p_camera->project_ray_normal(mbpos);
+
+ Vector3 inters;
+ if (p.intersects_ray(ray_from, ray_dir, &inters)) {
+
+ ur->create_action(TTR("Add Point to Curve"));
+ ur->add_do_method(c.ptr(), "add_point", it.xform(inters), Vector3(), Vector3(), -1);
+ ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
+ ur->commit_action();
+ return true;
+ }
+
+ //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()))) {
+
+ 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);
+ real_t dist_to_p_in = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_in(i))).distance_to(mbpos);
+
+ // Find the offset and point index of the place to break up.
+ // Also check for the control points.
+ if (dist_to_p < click_dist) {
+
+ UndoRedo *ur = editor->get_undo_redo();
+ ur->create_action(TTR("Remove Path Point"));
+ ur->add_do_method(c.ptr(), "remove_point", i);
+ ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
+ ur->commit_action();
+ return true;
+ } else if (dist_to_p_out < click_dist) {
+
+ UndoRedo *ur = editor->get_undo_redo();
+ ur->create_action(TTR("Remove Out-Control Point"));
+ ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
+ ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
+ ur->commit_action();
+ return true;
+ } else if (dist_to_p_in < click_dist) {
+
+ UndoRedo *ur = editor->get_undo_redo();
+ ur->create_action(TTR("Remove In-Control Point"));
+ ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
+ ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
+ ur->commit_action();
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void Path3DEditorPlugin::edit(Object *p_object) {
+
+ if (p_object) {
+ path = Object::cast_to<Path3D>(p_object);
+ if (path) {
+
+ if (path->get_curve().is_valid()) {
+ path->get_curve()->emit_signal("changed");
+ }
+ }
+ } else {
+ Path3D *pre = path;
+ path = nullptr;
+ if (pre) {
+ pre->get_curve()->emit_signal("changed");
+ }
+ }
+ //collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
+}
+
+bool Path3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("Path3D");
+}
+
+void Path3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+
+ curve_create->show();
+ curve_edit->show();
+ curve_del->show();
+ curve_close->show();
+ handle_menu->show();
+ sep->show();
+ } else {
+
+ curve_create->hide();
+ curve_edit->hide();
+ curve_del->hide();
+ curve_close->hide();
+ handle_menu->hide();
+ sep->hide();
+
+ {
+ Path3D *pre = path;
+ path = nullptr;
+ if (pre && pre->get_curve().is_valid()) {
+ pre->get_curve()->emit_signal("changed");
+ }
+ }
+ }
+}
+
+void Path3DEditorPlugin::_mode_changed(int p_idx) {
+
+ curve_create->set_pressed(p_idx == 0);
+ curve_edit->set_pressed(p_idx == 1);
+ curve_del->set_pressed(p_idx == 2);
+}
+
+void Path3DEditorPlugin::_close_curve() {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+ if (c->get_point_count() < 2)
+ return;
+ c->add_point(c->get_point_position(0), c->get_point_in(0), c->get_point_out(0));
+}
+
+void Path3DEditorPlugin::_handle_option_pressed(int p_option) {
+
+ PopupMenu *pm;
+ pm = handle_menu->get_popup();
+
+ switch (p_option) {
+ case HANDLE_OPTION_ANGLE: {
+ bool is_checked = pm->is_item_checked(HANDLE_OPTION_ANGLE);
+ mirror_handle_angle = !is_checked;
+ pm->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
+ pm->set_item_disabled(HANDLE_OPTION_LENGTH, !mirror_handle_angle);
+ } break;
+ case HANDLE_OPTION_LENGTH: {
+ bool is_checked = pm->is_item_checked(HANDLE_OPTION_LENGTH);
+ mirror_handle_length = !is_checked;
+ pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
+ } break;
+ }
+}
+
+void Path3DEditorPlugin::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ curve_create->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(0));
+ curve_edit->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(1));
+ curve_del->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(2));
+ curve_close->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_close_curve));
+ }
+}
+
+void Path3DEditorPlugin::_bind_methods() {
+}
+
+Path3DEditorPlugin *Path3DEditorPlugin::singleton = nullptr;
+
+Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) {
+
+ path = nullptr;
+ editor = p_node;
+ singleton = this;
+ mirror_handle_angle = true;
+ mirror_handle_length = true;
+
+ Ref<Path3DGizmoPlugin> gizmo_plugin;
+ gizmo_plugin.instance();
+ Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
+
+ sep = memnew(VSeparator);
+ sep->hide();
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(sep);
+ curve_edit = memnew(ToolButton);
+ curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons"));
+ curve_edit->set_toggle_mode(true);
+ curve_edit->hide();
+ curve_edit->set_focus_mode(Control::FOCUS_NONE);
+ curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
+ curve_create = memnew(ToolButton);
+ curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons"));
+ curve_create->set_toggle_mode(true);
+ curve_create->hide();
+ curve_create->set_focus_mode(Control::FOCUS_NONE);
+ curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create);
+ curve_del = memnew(ToolButton);
+ curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons"));
+ curve_del->set_toggle_mode(true);
+ curve_del->hide();
+ curve_del->set_focus_mode(Control::FOCUS_NONE);
+ curve_del->set_tooltip(TTR("Delete Point"));
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del);
+ curve_close = memnew(ToolButton);
+ curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveClose", "EditorIcons"));
+ curve_close->hide();
+ curve_close->set_focus_mode(Control::FOCUS_NONE);
+ curve_close->set_tooltip(TTR("Close Curve"));
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_close);
+
+ PopupMenu *menu;
+
+ handle_menu = memnew(MenuButton);
+ handle_menu->set_text(TTR("Options"));
+ handle_menu->hide();
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(handle_menu);
+
+ menu = handle_menu->get_popup();
+ menu->add_check_item(TTR("Mirror Handle Angles"));
+ menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
+ menu->add_check_item(TTR("Mirror Handle Lengths"));
+ menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
+ menu->connect("id_pressed", callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed));
+
+ curve_edit->set_pressed(true);
+ /*
+ collision_polygon_editor = memnew( PathEditor(p_node) );
+ editor->get_viewport()->add_child(collision_polygon_editor);
+ collision_polygon_editor->set_margin(MARGIN_LEFT,200);
+ collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
+ collision_polygon_editor->set_margin(MARGIN_TOP,0);
+ collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
+ collision_polygon_editor->hide();
+ */
+}
+
+Path3DEditorPlugin::~Path3DEditorPlugin() {
+}
+
+Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
+ Ref<Path3DGizmo> ref;
+
+ Path3D *path = Object::cast_to<Path3D>(p_spatial);
+ if (path) ref = Ref<Path3DGizmo>(memnew(Path3DGizmo(path)));
+
+ return ref;
+}
+
+String Path3DGizmoPlugin::get_name() const {
+ return "Path3D";
+}
+
+int Path3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+Path3DGizmoPlugin::Path3DGizmoPlugin() {
+
+ Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
+ create_material("path_material", path_color);
+ create_material("path_thin_material", Color(0.5, 0.5, 0.5));
+ create_handle_material("handles");
+}
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
new file mode 100644
index 0000000000..3f18cadacd
--- /dev/null
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -0,0 +1,121 @@
+/*************************************************************************/
+/* path_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PATH_EDITOR_PLUGIN_H
+#define PATH_EDITOR_PLUGIN_H
+
+#include "editor/node_3d_editor_gizmos.h"
+#include "scene/3d/path_3d.h"
+
+class Path3DGizmo : public EditorNode3DGizmo {
+
+ GDCLASS(Path3DGizmo, EditorNode3DGizmo);
+
+ Path3D *path;
+ mutable Vector3 original;
+ mutable float orig_in_length;
+ mutable float orig_out_length;
+
+public:
+ virtual String get_handle_name(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx);
+ virtual void set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
+
+ virtual void redraw();
+ Path3DGizmo(Path3D *p_path = nullptr);
+};
+
+class Path3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+
+ GDCLASS(Path3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+protected:
+ Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial);
+
+public:
+ String get_name() const;
+ int get_priority() const;
+ Path3DGizmoPlugin();
+};
+
+class Path3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(Path3DEditorPlugin, EditorPlugin);
+
+ Separator *sep;
+ ToolButton *curve_create;
+ ToolButton *curve_edit;
+ ToolButton *curve_del;
+ ToolButton *curve_close;
+ MenuButton *handle_menu;
+
+ EditorNode *editor;
+
+ Path3D *path;
+
+ void _mode_changed(int p_idx);
+ void _close_curve();
+ void _handle_option_pressed(int p_option);
+ bool handle_clicked;
+ bool mirror_handle_angle;
+ bool mirror_handle_length;
+
+ enum HandleOption {
+ HANDLE_OPTION_ANGLE,
+ HANDLE_OPTION_LENGTH
+ };
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ Path3D *get_edited_path() { return path; }
+
+ static Path3DEditorPlugin *singleton;
+ virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
+
+ virtual String get_name() const { return "Path3D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ bool mirror_angle_enabled() { return mirror_handle_angle; }
+ bool mirror_length_enabled() { return mirror_handle_length; }
+ bool is_handle_clicked() { return handle_clicked; }
+ void set_handle_clicked(bool clicked) { handle_clicked = clicked; }
+
+ Path3DEditorPlugin(EditorNode *p_node);
+ ~Path3DEditorPlugin();
+};
+
+#endif // PATH_EDITOR_PLUGIN_H
diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp
deleted file mode 100644
index 42b1045666..0000000000
--- a/editor/plugins/path_editor_plugin.cpp
+++ /dev/null
@@ -1,653 +0,0 @@
-/*************************************************************************/
-/* path_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "path_editor_plugin.h"
-
-#include "core/os/keyboard.h"
-#include "scene/resources/curve.h"
-#include "spatial_editor_plugin.h"
-
-String PathSpatialGizmo::get_handle_name(int p_idx) const {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return "";
-
- if (p_idx < c->get_point_count()) {
-
- return TTR("Curve Point #") + itos(p_idx);
- }
-
- p_idx = p_idx - c->get_point_count() + 1;
-
- int idx = p_idx / 2;
- int t = p_idx % 2;
- String n = TTR("Curve Point #") + itos(idx);
- if (t == 0)
- n += " In";
- else
- n += " Out";
-
- return n;
-}
-Variant PathSpatialGizmo::get_handle_value(int p_idx) {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return Variant();
-
- if (p_idx < c->get_point_count()) {
-
- original = c->get_point_position(p_idx);
- return original;
- }
-
- p_idx = p_idx - c->get_point_count() + 1;
-
- int idx = p_idx / 2;
- int t = p_idx % 2;
-
- Vector3 ofs;
- if (t == 0)
- ofs = c->get_point_in(idx);
- else
- ofs = c->get_point_out(idx);
-
- original = ofs + c->get_point_position(idx);
-
- return ofs;
-}
-void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
-
- Transform gt = path->get_global_transform();
- Transform gi = gt.affine_inverse();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- // Setting curve point positions
- if (p_idx < c->get_point_count()) {
-
- Plane p(gt.xform(original), p_camera->get_transform().basis.get_axis(2));
-
- Vector3 inters;
-
- if (p.intersects_ray(ray_from, ray_dir, &inters)) {
-
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- float snap = SpatialEditor::get_singleton()->get_translate_snap();
- inters.snap(Vector3(snap, snap, snap));
- }
-
- Vector3 local = gi.xform(inters);
- c->set_point_position(p_idx, local);
- }
-
- return;
- }
-
- p_idx = p_idx - c->get_point_count() + 1;
-
- int idx = p_idx / 2;
- int t = p_idx % 2;
-
- Vector3 base = c->get_point_position(idx);
-
- Plane p(gt.xform(original), p_camera->get_transform().basis.get_axis(2));
-
- Vector3 inters;
-
- // Setting curve in/out positions
- if (p.intersects_ray(ray_from, ray_dir, &inters)) {
-
- if (!PathEditorPlugin::singleton->is_handle_clicked()) {
- orig_in_length = c->get_point_in(idx).length();
- orig_out_length = c->get_point_out(idx).length();
- PathEditorPlugin::singleton->set_handle_clicked(true);
- }
-
- Vector3 local = gi.xform(inters) - base;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- float snap = SpatialEditor::get_singleton()->get_translate_snap();
- local.snap(Vector3(snap, snap, snap));
- }
-
- if (t == 0) {
- c->set_point_in(idx, local);
- if (PathEditorPlugin::singleton->mirror_angle_enabled())
- c->set_point_out(idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length));
- } else {
- c->set_point_out(idx, local);
- if (PathEditorPlugin::singleton->mirror_angle_enabled())
- c->set_point_in(idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_in_length));
- }
- }
-}
-
-void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
-
- if (p_idx < c->get_point_count()) {
-
- if (p_cancel) {
-
- c->set_point_position(p_idx, p_restore);
- return;
- }
- ur->create_action(TTR("Set Curve Point Position"));
- ur->add_do_method(c.ptr(), "set_point_position", p_idx, c->get_point_position(p_idx));
- ur->add_undo_method(c.ptr(), "set_point_position", p_idx, p_restore);
- ur->commit_action();
-
- return;
- }
-
- p_idx = p_idx - c->get_point_count() + 1;
-
- int idx = p_idx / 2;
- int t = p_idx % 2;
-
- if (t == 0) {
- if (p_cancel) {
- c->set_point_in(p_idx, p_restore);
- return;
- }
-
- ur->create_action(TTR("Set Curve In Position"));
- ur->add_do_method(c.ptr(), "set_point_in", idx, c->get_point_in(idx));
- ur->add_undo_method(c.ptr(), "set_point_in", idx, p_restore);
-
- if (PathEditorPlugin::singleton->mirror_angle_enabled()) {
- ur->add_do_method(c.ptr(), "set_point_out", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_in(idx) : (-c->get_point_in(idx).normalized() * orig_out_length));
- ur->add_undo_method(c.ptr(), "set_point_out", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_out_length));
- }
- ur->commit_action();
-
- } else {
- if (p_cancel) {
- c->set_point_out(idx, p_restore);
-
- return;
- }
-
- ur->create_action(TTR("Set Curve Out Position"));
- ur->add_do_method(c.ptr(), "set_point_out", idx, c->get_point_out(idx));
- ur->add_undo_method(c.ptr(), "set_point_out", idx, p_restore);
-
- if (PathEditorPlugin::singleton->mirror_angle_enabled()) {
- ur->add_do_method(c.ptr(), "set_point_in", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_out(idx) : (-c->get_point_out(idx).normalized() * orig_in_length));
- ur->add_undo_method(c.ptr(), "set_point_in", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_in_length));
- }
- ur->commit_action();
- }
-}
-
-void PathSpatialGizmo::redraw() {
-
- clear();
-
- Ref<StandardMaterial3D> path_material = gizmo_plugin->get_material("path_material", this);
- Ref<StandardMaterial3D> path_thin_material = gizmo_plugin->get_material("path_thin_material", this);
- Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles");
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
-
- Vector<Vector3> v3a = c->tessellate();
- //Vector<Vector3> v3a=c->get_baked_points();
-
- int v3s = v3a.size();
- if (v3s == 0)
- return;
- Vector<Vector3> v3p;
- const Vector3 *r = v3a.ptr();
-
- // BUG: the following won't work when v3s, avoid drawing as a temporary workaround.
- for (int i = 0; i < v3s - 1; i++) {
-
- v3p.push_back(r[i]);
- v3p.push_back(r[i + 1]);
- //v3p.push_back(r[i]);
- //v3p.push_back(r[i]+Vector3(0,0.2,0));
- }
-
- if (v3p.size() > 1) {
- add_lines(v3p, path_material);
- add_collision_segments(v3p);
- }
-
- if (PathEditorPlugin::singleton->get_edited_path() == path) {
- v3p.clear();
- Vector<Vector3> handles;
- Vector<Vector3> sec_handles;
-
- for (int i = 0; i < c->get_point_count(); i++) {
-
- Vector3 p = c->get_point_position(i);
- handles.push_back(p);
- if (i > 0) {
- v3p.push_back(p);
- v3p.push_back(p + c->get_point_in(i));
- sec_handles.push_back(p + c->get_point_in(i));
- }
-
- if (i < c->get_point_count() - 1) {
- v3p.push_back(p);
- v3p.push_back(p + c->get_point_out(i));
- sec_handles.push_back(p + c->get_point_out(i));
- }
- }
-
- if (v3p.size() > 1) {
- add_lines(v3p, path_thin_material);
- }
- if (handles.size()) {
- add_handles(handles, handles_material);
- }
- if (sec_handles.size()) {
- add_handles(sec_handles, handles_material, false, true);
- }
- }
-}
-
-PathSpatialGizmo::PathSpatialGizmo(Path *p_path) {
-
- path = p_path;
- set_spatial_node(p_path);
-}
-
-bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
-
- if (!path)
- return false;
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return false;
- Transform gt = path->get_global_transform();
- Transform it = gt.affine_inverse();
-
- static const int click_dist = 10; //should make global
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
-
- Point2 mbpos(mb->get_position().x, mb->get_position().y);
-
- if (!mb->is_pressed())
- 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()))) {
- //click into curve, break it down
- Vector<Vector3> v3a = c->tessellate();
- int idx = 0;
- int rc = v3a.size();
- int closest_seg = -1;
- Vector3 closest_seg_point;
- float closest_d = 1e20;
-
- if (rc >= 2) {
- const Vector3 *r = v3a.ptr();
-
- if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist)
- return false; //nope, existing
-
- for (int i = 0; i < c->get_point_count() - 1; i++) {
- //find the offset and point index of the place to break up
- int j = idx;
- if (p_camera->unproject_position(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist)
- return false; //nope, existing
-
- while (j < rc && c->get_point_position(i + 1) != r[j]) {
-
- Vector3 from = r[j];
- Vector3 to = r[j + 1];
- real_t cdist = from.distance_to(to);
- from = gt.xform(from);
- to = gt.xform(to);
- if (cdist > 0) {
- Vector2 s[2];
- s[0] = p_camera->unproject_position(from);
- s[1] = p_camera->unproject_position(to);
- Vector2 inters = Geometry::get_closest_point_to_segment_2d(mbpos, s);
- float d = inters.distance_to(mbpos);
-
- if (d < 10 && d < closest_d) {
-
- closest_d = d;
- closest_seg = i;
- Vector3 ray_from = p_camera->project_ray_origin(mbpos);
- Vector3 ray_dir = p_camera->project_ray_normal(mbpos);
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb);
-
- closest_seg_point = it.xform(rb);
- }
- }
- j++;
- }
- if (idx == j)
- idx++; //force next
- else
- idx = j; //swap
-
- if (j == rc)
- break;
- }
- }
-
- UndoRedo *ur = editor->get_undo_redo();
- if (closest_seg != -1) {
- //subdivide
-
- ur->create_action(TTR("Split Path"));
- ur->add_do_method(c.ptr(), "add_point", closest_seg_point, Vector3(), Vector3(), closest_seg + 1);
- ur->add_undo_method(c.ptr(), "remove_point", closest_seg + 1);
- ur->commit_action();
- return true;
-
- } else {
-
- Vector3 org;
- if (c->get_point_count() == 0)
- org = path->get_transform().get_origin();
- else
- org = gt.xform(c->get_point_position(c->get_point_count() - 1));
- Plane p(org, p_camera->get_transform().basis.get_axis(2));
- Vector3 ray_from = p_camera->project_ray_origin(mbpos);
- Vector3 ray_dir = p_camera->project_ray_normal(mbpos);
-
- Vector3 inters;
- if (p.intersects_ray(ray_from, ray_dir, &inters)) {
-
- ur->create_action(TTR("Add Point to Curve"));
- ur->add_do_method(c.ptr(), "add_point", it.xform(inters), Vector3(), Vector3(), -1);
- ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
- ur->commit_action();
- return true;
- }
-
- //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()))) {
-
- 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);
- real_t dist_to_p_in = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_in(i))).distance_to(mbpos);
-
- // Find the offset and point index of the place to break up.
- // Also check for the control points.
- if (dist_to_p < click_dist) {
-
- UndoRedo *ur = editor->get_undo_redo();
- ur->create_action(TTR("Remove Path Point"));
- ur->add_do_method(c.ptr(), "remove_point", i);
- ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
- ur->commit_action();
- return true;
- } else if (dist_to_p_out < click_dist) {
-
- UndoRedo *ur = editor->get_undo_redo();
- ur->create_action(TTR("Remove Out-Control Point"));
- ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
- ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
- ur->commit_action();
- return true;
- } else if (dist_to_p_in < click_dist) {
-
- UndoRedo *ur = editor->get_undo_redo();
- ur->create_action(TTR("Remove In-Control Point"));
- ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
- ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
- ur->commit_action();
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-void PathEditorPlugin::edit(Object *p_object) {
-
- if (p_object) {
- path = Object::cast_to<Path>(p_object);
- if (path) {
-
- if (path->get_curve().is_valid()) {
- path->get_curve()->emit_signal("changed");
- }
- }
- } else {
- Path *pre = path;
- path = NULL;
- if (pre) {
- pre->get_curve()->emit_signal("changed");
- }
- }
- //collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
-}
-
-bool PathEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Path");
-}
-
-void PathEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
-
- curve_create->show();
- curve_edit->show();
- curve_del->show();
- curve_close->show();
- handle_menu->show();
- sep->show();
- } else {
-
- curve_create->hide();
- curve_edit->hide();
- curve_del->hide();
- curve_close->hide();
- handle_menu->hide();
- sep->hide();
-
- {
- Path *pre = path;
- path = NULL;
- if (pre && pre->get_curve().is_valid()) {
- pre->get_curve()->emit_signal("changed");
- }
- }
- }
-}
-
-void PathEditorPlugin::_mode_changed(int p_idx) {
-
- curve_create->set_pressed(p_idx == 0);
- curve_edit->set_pressed(p_idx == 1);
- curve_del->set_pressed(p_idx == 2);
-}
-
-void PathEditorPlugin::_close_curve() {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
- if (c->get_point_count() < 2)
- return;
- c->add_point(c->get_point_position(0), c->get_point_in(0), c->get_point_out(0));
-}
-
-void PathEditorPlugin::_handle_option_pressed(int p_option) {
-
- PopupMenu *pm;
- pm = handle_menu->get_popup();
-
- switch (p_option) {
- case HANDLE_OPTION_ANGLE: {
- bool is_checked = pm->is_item_checked(HANDLE_OPTION_ANGLE);
- mirror_handle_angle = !is_checked;
- pm->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
- pm->set_item_disabled(HANDLE_OPTION_LENGTH, !mirror_handle_angle);
- } break;
- case HANDLE_OPTION_LENGTH: {
- bool is_checked = pm->is_item_checked(HANDLE_OPTION_LENGTH);
- mirror_handle_length = !is_checked;
- pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
- } break;
- }
-}
-
-void PathEditorPlugin::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- curve_create->connect("pressed", callable_mp(this, &PathEditorPlugin::_mode_changed), make_binds(0));
- curve_edit->connect("pressed", callable_mp(this, &PathEditorPlugin::_mode_changed), make_binds(1));
- curve_del->connect("pressed", callable_mp(this, &PathEditorPlugin::_mode_changed), make_binds(2));
- curve_close->connect("pressed", callable_mp(this, &PathEditorPlugin::_close_curve));
- }
-}
-
-void PathEditorPlugin::_bind_methods() {
-}
-
-PathEditorPlugin *PathEditorPlugin::singleton = NULL;
-
-PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) {
-
- path = NULL;
- editor = p_node;
- singleton = this;
- mirror_handle_angle = true;
- mirror_handle_length = true;
-
- Ref<PathSpatialGizmoPlugin> gizmo_plugin;
- gizmo_plugin.instance();
- SpatialEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
-
- sep = memnew(VSeparator);
- sep->hide();
- SpatialEditor::get_singleton()->add_control_to_menu_panel(sep);
- curve_edit = memnew(ToolButton);
- curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
- curve_edit->set_toggle_mode(true);
- curve_edit->hide();
- curve_edit->set_focus_mode(Control::FOCUS_NONE);
- curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
- curve_create = memnew(ToolButton);
- curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
- curve_create->set_toggle_mode(true);
- curve_create->hide();
- curve_create->set_focus_mode(Control::FOCUS_NONE);
- curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_create);
- curve_del = memnew(ToolButton);
- curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons"));
- curve_del->set_toggle_mode(true);
- curve_del->hide();
- curve_del->set_focus_mode(Control::FOCUS_NONE);
- curve_del->set_tooltip(TTR("Delete Point"));
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_del);
- curve_close = memnew(ToolButton);
- curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveClose", "EditorIcons"));
- curve_close->hide();
- curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip(TTR("Close Curve"));
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_close);
-
- PopupMenu *menu;
-
- handle_menu = memnew(MenuButton);
- handle_menu->set_text(TTR("Options"));
- handle_menu->hide();
- SpatialEditor::get_singleton()->add_control_to_menu_panel(handle_menu);
-
- menu = handle_menu->get_popup();
- menu->add_check_item(TTR("Mirror Handle Angles"));
- menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle);
- menu->add_check_item(TTR("Mirror Handle Lengths"));
- menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
- menu->connect("id_pressed", callable_mp(this, &PathEditorPlugin::_handle_option_pressed));
-
- curve_edit->set_pressed(true);
- /*
- collision_polygon_editor = memnew( PathEditor(p_node) );
- editor->get_viewport()->add_child(collision_polygon_editor);
- collision_polygon_editor->set_margin(MARGIN_LEFT,200);
- collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
- collision_polygon_editor->set_margin(MARGIN_TOP,0);
- collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
- collision_polygon_editor->hide();
- */
-}
-
-PathEditorPlugin::~PathEditorPlugin() {
-}
-
-Ref<EditorSpatialGizmo> PathSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) {
- Ref<PathSpatialGizmo> ref;
-
- Path *path = Object::cast_to<Path>(p_spatial);
- if (path) ref = Ref<PathSpatialGizmo>(memnew(PathSpatialGizmo(path)));
-
- return ref;
-}
-
-String PathSpatialGizmoPlugin::get_name() const {
- return "Path";
-}
-
-int PathSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() {
-
- Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
- create_material("path_material", path_color);
- create_material("path_thin_material", Color(0.5, 0.5, 0.5));
- create_handle_material("handles");
-}
diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h
deleted file mode 100644
index 8ff83911f8..0000000000
--- a/editor/plugins/path_editor_plugin.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*************************************************************************/
-/* path_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PATH_EDITOR_PLUGIN_H
-#define PATH_EDITOR_PLUGIN_H
-
-#include "editor/spatial_editor_gizmos.h"
-#include "scene/3d/path.h"
-
-class PathSpatialGizmo : public EditorSpatialGizmo {
-
- GDCLASS(PathSpatialGizmo, EditorSpatialGizmo);
-
- Path *path;
- mutable Vector3 original;
- mutable float orig_in_length;
- mutable float orig_out_length;
-
-public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx);
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- virtual void redraw();
- PathSpatialGizmo(Path *p_path = NULL);
-};
-
-class PathSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(PathSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-protected:
- Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial);
-
-public:
- String get_name() const;
- int get_priority() const;
- PathSpatialGizmoPlugin();
-};
-
-class PathEditorPlugin : public EditorPlugin {
-
- GDCLASS(PathEditorPlugin, EditorPlugin);
-
- Separator *sep;
- ToolButton *curve_create;
- ToolButton *curve_edit;
- ToolButton *curve_del;
- ToolButton *curve_close;
- MenuButton *handle_menu;
-
- EditorNode *editor;
-
- Path *path;
-
- void _mode_changed(int p_idx);
- void _close_curve();
- void _handle_option_pressed(int p_option);
- bool handle_clicked;
- bool mirror_handle_angle;
- bool mirror_handle_length;
-
- enum HandleOption {
- HANDLE_OPTION_ANGLE,
- HANDLE_OPTION_LENGTH
- };
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- Path *get_edited_path() { return path; }
-
- static PathEditorPlugin *singleton;
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
-
- //virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); }
- //virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
- virtual String get_name() const { return "Path"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- bool mirror_angle_enabled() { return mirror_handle_angle; }
- bool mirror_length_enabled() { return mirror_handle_length; }
- bool is_handle_clicked() { return handle_clicked; }
- void set_handle_clicked(bool clicked) { handle_clicked = clicked; }
-
- PathEditorPlugin(EditorNode *p_node);
- ~PathEditorPlugin();
-};
-
-#endif // PATH_EDITOR_PLUGIN_H
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..6d38f7f318
--- /dev/null
+++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp
@@ -0,0 +1,113 @@
+/*************************************************************************/
+/* physical_bone_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "physical_bone_3d_editor_plugin.h"
+
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/physics_body_3d.h"
+
+void PhysicalBone3DEditor::_bind_methods() {
+}
+
+void PhysicalBone3DEditor::_on_toggle_button_transform_joint(bool p_is_pressed) {
+
+ _set_move_joint();
+}
+
+void PhysicalBone3DEditor::_set_move_joint() {
+ if (selected) {
+ selected->_set_gizmo_move_joint(button_transform_joint->is_pressed());
+ }
+}
+
+PhysicalBone3DEditor::PhysicalBone3DEditor(EditorNode *p_editor) :
+ editor(p_editor),
+ selected(nullptr) {
+
+ spatial_editor_hb = memnew(HBoxContainer);
+ spatial_editor_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ spatial_editor_hb->set_alignment(BoxContainer::ALIGN_BEGIN);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
+
+ spatial_editor_hb->add_child(memnew(VSeparator));
+
+ button_transform_joint = memnew(ToolButton);
+ spatial_editor_hb->add_child(button_transform_joint);
+
+ button_transform_joint->set_text(TTR("Move Joint"));
+ button_transform_joint->set_icon(Node3DEditor::get_singleton()->get_theme_icon("PhysicalBone3D", "EditorIcons"));
+ button_transform_joint->set_toggle_mode(true);
+ button_transform_joint->connect("toggled", callable_mp(this, &PhysicalBone3DEditor::_on_toggle_button_transform_joint));
+
+ hide();
+}
+
+PhysicalBone3DEditor::~PhysicalBone3DEditor() {}
+
+void PhysicalBone3DEditor::set_selected(PhysicalBone3D *p_pb) {
+
+ button_transform_joint->set_pressed(false);
+
+ _set_move_joint();
+ selected = p_pb;
+ _set_move_joint();
+}
+
+void PhysicalBone3DEditor::hide() {
+ spatial_editor_hb->hide();
+}
+
+void PhysicalBone3DEditor::show() {
+ spatial_editor_hb->show();
+}
+
+PhysicalBone3DEditorPlugin::PhysicalBone3DEditorPlugin(EditorNode *p_editor) :
+ editor(p_editor),
+ selected(nullptr),
+ physical_bone_editor(editor) {}
+
+void PhysicalBone3DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+
+ physical_bone_editor.show();
+ } else {
+
+ physical_bone_editor.hide();
+ physical_bone_editor.set_selected(nullptr);
+ selected = nullptr;
+ }
+}
+
+void PhysicalBone3DEditorPlugin::edit(Object *p_node) {
+ selected = static_cast<PhysicalBone3D *>(p_node); // Trust it
+ ERR_FAIL_COND(!selected);
+
+ physical_bone_editor.set_selected(selected);
+}
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.h b/editor/plugins/physical_bone_3d_editor_plugin.h
new file mode 100644
index 0000000000..74932710d6
--- /dev/null
+++ b/editor/plugins/physical_bone_3d_editor_plugin.h
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* physical_bone_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICAL_BONE_PLUGIN_H
+#define PHYSICAL_BONE_PLUGIN_H
+
+#include "editor/editor_node.h"
+
+class PhysicalBone3DEditor : public Object {
+ GDCLASS(PhysicalBone3DEditor, Object);
+
+ EditorNode *editor;
+ HBoxContainer *spatial_editor_hb;
+ ToolButton *button_transform_joint;
+
+ PhysicalBone3D *selected;
+
+protected:
+ static void _bind_methods();
+
+private:
+ void _on_toggle_button_transform_joint(bool p_is_pressed);
+ void _set_move_joint();
+
+public:
+ PhysicalBone3DEditor(EditorNode *p_editor);
+ ~PhysicalBone3DEditor();
+
+ void set_selected(PhysicalBone3D *p_pb);
+
+ void hide();
+ void show();
+};
+
+class PhysicalBone3DEditorPlugin : public EditorPlugin {
+ GDCLASS(PhysicalBone3DEditorPlugin, EditorPlugin);
+
+ EditorNode *editor;
+ PhysicalBone3D *selected;
+ PhysicalBone3DEditor physical_bone_editor;
+
+public:
+ virtual String get_name() const { return "PhysicalBone3D"; }
+ virtual bool handles(Object *p_object) const { return p_object->is_class("PhysicalBone3D"); }
+ virtual void make_visible(bool p_visible);
+ virtual void edit(Object *p_node);
+
+ PhysicalBone3DEditorPlugin(EditorNode *p_editor);
+};
+
+#endif
diff --git a/editor/plugins/physical_bone_plugin.cpp b/editor/plugins/physical_bone_plugin.cpp
deleted file mode 100644
index e0d48afeef..0000000000
--- a/editor/plugins/physical_bone_plugin.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*************************************************************************/
-/* physical_bone_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "physical_bone_plugin.h"
-#include "editor/plugins/spatial_editor_plugin.h"
-#include "scene/3d/physics_body.h"
-
-void PhysicalBoneEditor::_bind_methods() {
-}
-
-void PhysicalBoneEditor::_on_toggle_button_transform_joint(bool p_is_pressed) {
-
- _set_move_joint();
-}
-
-void PhysicalBoneEditor::_set_move_joint() {
- if (selected) {
- selected->_set_gizmo_move_joint(button_transform_joint->is_pressed());
- }
-}
-
-PhysicalBoneEditor::PhysicalBoneEditor(EditorNode *p_editor) :
- editor(p_editor),
- selected(NULL) {
-
- spatial_editor_hb = memnew(HBoxContainer);
- spatial_editor_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- spatial_editor_hb->set_alignment(BoxContainer::ALIGN_BEGIN);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
-
- spatial_editor_hb->add_child(memnew(VSeparator));
-
- button_transform_joint = memnew(ToolButton);
- spatial_editor_hb->add_child(button_transform_joint);
-
- button_transform_joint->set_text(TTR("Move Joint"));
- button_transform_joint->set_icon(SpatialEditor::get_singleton()->get_icon("PhysicalBone", "EditorIcons"));
- button_transform_joint->set_toggle_mode(true);
- button_transform_joint->connect("toggled", callable_mp(this, &PhysicalBoneEditor::_on_toggle_button_transform_joint));
-
- hide();
-}
-
-PhysicalBoneEditor::~PhysicalBoneEditor() {}
-
-void PhysicalBoneEditor::set_selected(PhysicalBone *p_pb) {
-
- button_transform_joint->set_pressed(false);
-
- _set_move_joint();
- selected = p_pb;
- _set_move_joint();
-}
-
-void PhysicalBoneEditor::hide() {
- spatial_editor_hb->hide();
-}
-
-void PhysicalBoneEditor::show() {
- spatial_editor_hb->show();
-}
-
-PhysicalBonePlugin::PhysicalBonePlugin(EditorNode *p_editor) :
- editor(p_editor),
- selected(NULL),
- physical_bone_editor(editor) {}
-
-void PhysicalBonePlugin::make_visible(bool p_visible) {
- if (p_visible) {
-
- physical_bone_editor.show();
- } else {
-
- physical_bone_editor.hide();
- physical_bone_editor.set_selected(NULL);
- selected = NULL;
- }
-}
-
-void PhysicalBonePlugin::edit(Object *p_node) {
- selected = static_cast<PhysicalBone *>(p_node); // Trust it
- ERR_FAIL_COND(!selected);
-
- physical_bone_editor.set_selected(selected);
-}
diff --git a/editor/plugins/physical_bone_plugin.h b/editor/plugins/physical_bone_plugin.h
deleted file mode 100644
index 459a67db05..0000000000
--- a/editor/plugins/physical_bone_plugin.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* physical_bone_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICAL_BONE_PLUGIN_H
-#define PHYSICAL_BONE_PLUGIN_H
-
-#include "editor/editor_node.h"
-
-class PhysicalBoneEditor : public Object {
- GDCLASS(PhysicalBoneEditor, Object);
-
- EditorNode *editor;
- HBoxContainer *spatial_editor_hb;
- ToolButton *button_transform_joint;
-
- PhysicalBone *selected;
-
-protected:
- static void _bind_methods();
-
-private:
- void _on_toggle_button_transform_joint(bool p_is_pressed);
- void _set_move_joint();
-
-public:
- PhysicalBoneEditor(EditorNode *p_editor);
- ~PhysicalBoneEditor();
-
- void set_selected(PhysicalBone *p_pb);
-
- void hide();
- void show();
-};
-
-class PhysicalBonePlugin : public EditorPlugin {
- GDCLASS(PhysicalBonePlugin, EditorPlugin);
-
- EditorNode *editor;
- PhysicalBone *selected;
- PhysicalBoneEditor physical_bone_editor;
-
-public:
- virtual String get_name() const { return "PhysicalBone"; }
- virtual bool handles(Object *p_object) const { return p_object->is_class("PhysicalBone"); }
- virtual void make_visible(bool p_visible);
- virtual void edit(Object *p_node);
-
- PhysicalBonePlugin(EditorNode *p_editor);
-};
-
-#endif
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 8c115586a4..1f7a5b9968 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -31,8 +31,8 @@
#include "polygon_2d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/os/file_access.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -70,28 +70,28 @@ void Polygon2DEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- uv_edit_draw->add_style_override("panel", get_stylebox("bg", "Tree"));
- bone_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
+ uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ bone_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
} break;
case NOTIFICATION_READY: {
- button_uv->set_icon(get_icon("Uv", "EditorIcons"));
+ button_uv->set_icon(get_theme_icon("Uv", "EditorIcons"));
- uv_button[UV_MODE_CREATE]->set_icon(get_icon("Edit", "EditorIcons"));
- uv_button[UV_MODE_CREATE_INTERNAL]->set_icon(get_icon("EditInternal", "EditorIcons"));
- uv_button[UV_MODE_REMOVE_INTERNAL]->set_icon(get_icon("RemoveInternal", "EditorIcons"));
- uv_button[UV_MODE_EDIT_POINT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
- uv_button[UV_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
- uv_button[UV_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
- uv_button[UV_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
- uv_button[UV_MODE_ADD_POLYGON]->set_icon(get_icon("Edit", "EditorIcons"));
- uv_button[UV_MODE_REMOVE_POLYGON]->set_icon(get_icon("Close", "EditorIcons"));
- uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_icon("PaintVertex", "EditorIcons"));
- uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_icon("UnpaintVertex", "EditorIcons"));
+ uv_button[UV_MODE_CREATE]->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ uv_button[UV_MODE_CREATE_INTERNAL]->set_icon(get_theme_icon("EditInternal", "EditorIcons"));
+ uv_button[UV_MODE_REMOVE_INTERNAL]->set_icon(get_theme_icon("RemoveInternal", "EditorIcons"));
+ uv_button[UV_MODE_EDIT_POINT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ uv_button[UV_MODE_MOVE]->set_icon(get_theme_icon("ToolMove", "EditorIcons"));
+ uv_button[UV_MODE_ROTATE]->set_icon(get_theme_icon("ToolRotate", "EditorIcons"));
+ uv_button[UV_MODE_SCALE]->set_icon(get_theme_icon("ToolScale", "EditorIcons"));
+ uv_button[UV_MODE_ADD_POLYGON]->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ uv_button[UV_MODE_REMOVE_POLYGON]->set_icon(get_theme_icon("Close", "EditorIcons"));
+ uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_theme_icon("PaintVertex", "EditorIcons"));
+ uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_theme_icon("UnpaintVertex", "EditorIcons"));
- b_snap_grid->set_icon(get_icon("Grid", "EditorIcons"));
- b_snap_enable->set_icon(get_icon("SnapGrid", "EditorIcons"));
- uv_icon_zoom->set_texture(get_icon("Zoom", "EditorIcons"));
+ b_snap_grid->set_icon(get_theme_icon("Grid", "EditorIcons"));
+ b_snap_enable->set_icon(get_theme_icon("SnapGrid", "EditorIcons"));
+ uv_icon_zoom->set_texture(get_theme_icon("Zoom", "EditorIcons"));
uv_vscroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE);
uv_hscroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE);
@@ -107,10 +107,10 @@ void Polygon2DEditor::_notification(int p_what) {
void Polygon2DEditor::_sync_bones() {
- Skeleton2D *skeleton = NULL;
+ Skeleton2D *skeleton = nullptr;
if (!node->has_node(node->get_skeleton())) {
error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node"));
- error->popup_centered_minsize();
+ error->popup_centered();
} else {
Node *sn = node->get_node(node->get_skeleton());
skeleton = Object::cast_to<Skeleton2D>(sn);
@@ -121,7 +121,7 @@ void Polygon2DEditor::_sync_bones() {
if (!skeleton) {
error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node"));
- error->popup_centered_minsize();
+ error->popup_centered();
} else {
for (int i = 0; i < skeleton->get_bone_count(); i++) {
NodePath path = skeleton->get_path_to(skeleton->get_bone(i));
@@ -275,7 +275,7 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
void Polygon2DEditor::_uv_edit_popup_hide() {
- EditorSettings::get_singleton()->set("interface/dialogs/uv_editor_bounds", uv_edit->get_rect());
+ EditorSettings::get_singleton()->set("interface/dialogs/uv_editor_bounds", Rect2(uv_edit->get_position(), uv_edit->get_size()));
_cancel_editing();
}
@@ -289,7 +289,7 @@ void Polygon2DEditor::_menu_option(int p_option) {
if (node->get_texture().is_null()) {
error->set_text(TTR("No texture in this polygon.\nSet a texture to be able to edit UV."));
- error->popup_centered_minsize();
+ error->popup_centered();
return;
}
@@ -351,7 +351,7 @@ void Polygon2DEditor::_menu_option(int p_option) {
} break;
case UVEDIT_GRID_SETTINGS: {
- grid_settings->popup_centered_minsize();
+ grid_settings->popup_centered();
} break;
default: {
@@ -683,7 +683,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
//close
if (polygon_create.size() < 3) {
error->set_text(TTR("Invalid Polygon (need 3 different vertices)"));
- error->popup_centered_minsize();
+ error->popup_centered();
} else {
Array polygons = node->get_polygons();
polygons = polygons.duplicate(); //copy because its a reference
@@ -810,7 +810,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &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() & BUTTON_MASK_MIDDLE) || InputFilter::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);
@@ -990,9 +990,9 @@ void Polygon2DEditor::_uv_draw() {
mtx.elements[2] = -uv_draw_ofs;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
- VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx);
+ RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx);
uv_edit_draw->draw_texture(base_tex, Point2());
- VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
+ RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D());
if (snap_show_grid) {
Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
@@ -1031,7 +1031,7 @@ void Polygon2DEditor::_uv_draw() {
uvs = node->get_polygon();
}
- const float *weight_r;
+ const float *weight_r = nullptr;
if (uv_edit_mode[3]->is_pressed()) {
int bone_selected = -1;
@@ -1044,13 +1044,12 @@ void Polygon2DEditor::_uv_draw() {
}
if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == uvs.size()) {
-
weight_r = node->get_bone_weights(bone_selected).ptr();
}
}
// All UV points are sharp, so use the sharp handle icon
- Ref<Texture2D> handle = get_icon("EditorPathSharpHandle", "EditorIcons");
+ Ref<Texture2D> handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons");
Color poly_line_color = Color(0.9, 0.5, 0.5);
if (polygons.size() || polygon_create.size()) {
@@ -1250,7 +1249,7 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
AbstractPolygon2DEditor(p_editor) {
- node = NULL;
+ node = nullptr;
snap_offset = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_offset", Vector2());
snap_step = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_step", Vector2(10, 10));
use_snap = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_enabled", false);
@@ -1265,8 +1264,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_edit = memnew(AcceptDialog);
add_child(uv_edit);
uv_edit->set_title(TTR("Polygon 2D UV Editor"));
- uv_edit->set_resizable(true);
- uv_edit->connect("popup_hide", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
+ uv_edit->connect("cancelled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
VBoxContainer *uv_main_vb = memnew(VBoxContainer);
uv_edit->add_child(uv_main_vb);
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index feef505acc..852feeb675 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -41,7 +41,7 @@ void ResourcePreloaderEditor::_gui_input(Ref<InputEvent> p_event) {
void ResourcePreloaderEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- load->set_icon(get_icon("Folder", "EditorIcons"));
+ load->set_icon(get_theme_icon("Folder", "EditorIcons"));
}
if (p_what == NOTIFICATION_READY) {
@@ -67,7 +67,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths)
dialog->set_title(TTR("Error!"));
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text(TTR("Close"));
- dialog->popup_centered_minsize();
+ dialog->popup_centered();
return; ///beh should show an error i guess
}
@@ -98,7 +98,7 @@ void ResourcePreloaderEditor::_load_pressed() {
for (int i = 0; i < extensions.size(); i++)
file->add_filter("*." + extensions[i]);
- file->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
file->popup_centered_ratio();
}
@@ -152,7 +152,7 @@ void ResourcePreloaderEditor::_paste_pressed() {
dialog->set_text(TTR("Resource clipboard is empty!"));
dialog->set_title(TTR("Error!"));
dialog->get_ok()->set_text(TTR("Close"));
- dialog->popup_centered_minsize();
+ dialog->popup_centered();
return; ///beh should show an error i guess
}
@@ -181,7 +181,7 @@ void ResourcePreloaderEditor::_update_library() {
tree->clear();
tree->set_hide_root(true);
- TreeItem *root = tree->create_item(NULL);
+ TreeItem *root = tree->create_item(nullptr);
List<StringName> rnames;
preloader->get_resource_list(&rnames);
@@ -215,11 +215,11 @@ void ResourcePreloaderEditor::_update_library() {
ti->set_selectable(1, false);
if (type == "PackedScene") {
- ti->add_button(1, get_icon("InstanceOptions", "EditorIcons"), BUTTON_OPEN_SCENE, false, TTR("Open in Editor"));
+ ti->add_button(1, get_theme_icon("InstanceOptions", "EditorIcons"), BUTTON_OPEN_SCENE, false, TTR("Open in Editor"));
} else {
- ti->add_button(1, get_icon("Load", "EditorIcons"), BUTTON_EDIT_RESOURCE, false, TTR("Open in Editor"));
+ ti->add_button(1, get_theme_icon("Load", "EditorIcons"), BUTTON_EDIT_RESOURCE, false, TTR("Open in Editor"));
}
- ti->add_button(1, get_icon("Remove", "EditorIcons"), BUTTON_REMOVE, false, TTR("Remove"));
+ ti->add_button(1, get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE, false, TTR("Remove"));
}
//player->add_resource("default",resource);
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index d932305c63..67e836082d 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -30,7 +30,7 @@
#include "root_motion_editor_plugin.h"
#include "editor/editor_node.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void EditorPropertyRootMotion::_confirmed() {
@@ -88,7 +88,7 @@ void EditorPropertyRootMotion::_node_assign() {
for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
NodePath path = E->get();
- TreeItem *ti = NULL;
+ TreeItem *ti = nullptr;
String accum;
for (int i = 0; i < path.get_name_count(); i++) {
String name = path.get_name(i);
@@ -117,7 +117,7 @@ void EditorPropertyRootMotion::_node_assign() {
}
}
- Node *node = NULL;
+ Node *node = nullptr;
if (base->has_node(accum)) {
node = base->get_node(accum);
}
@@ -128,7 +128,7 @@ void EditorPropertyRootMotion::_node_assign() {
String concat = path.get_concatenated_subnames();
- Skeleton *skeleton = Object::cast_to<Skeleton>(node);
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
if (skeleton && skeleton->find_bone(concat) != -1) {
//path in skeleton
const String &bone = concat;
@@ -152,7 +152,7 @@ void EditorPropertyRootMotion::_node_assign() {
ti->set_text(0, F->get());
ti->set_selectable(0, true);
ti->set_editable(0, false);
- ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons"));
+ ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons"));
ti->set_metadata(0, accum);
} else {
ti = parenthood[accum];
@@ -161,7 +161,7 @@ void EditorPropertyRootMotion::_node_assign() {
ti->set_selectable(0, true);
ti->set_text(0, concat);
- ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons"));
+ ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons"));
ti->set_metadata(0, path);
if (path == current) {
ti->select(0);
@@ -212,7 +212,7 @@ void EditorPropertyRootMotion::update_property() {
}
assign->set_flat(true);
- Node *base_node = NULL;
+ Node *base_node = nullptr;
if (base_hint != NodePath()) {
if (get_tree()->get_root()->has_node(base_hint)) {
base_node = get_tree()->get_root()->get_node(base_hint);
@@ -242,7 +242,7 @@ void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) {
void EditorPropertyRootMotion::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Ref<Texture2D> t = get_icon("Clear", "EditorIcons");
+ Ref<Texture2D> t = get_theme_icon("Clear", "EditorIcons");
clear->set_icon(t);
}
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 72a9e399f2..2c831979de 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -30,9 +30,9 @@
#include "script_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
#include "core/os/file_access.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/project_settings.h"
@@ -45,9 +45,10 @@
#include "editor/find_in_files.h"
#include "editor/node_dock.h"
#include "editor/plugins/shader_editor_plugin.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#include "script_text_editor.h"
+#include "servers/display_server.h"
#include "text_editor.h"
/*** SCRIPT EDITOR ****/
@@ -192,7 +193,7 @@ void ScriptEditorQuickOpen::_update_search() {
}
}
- get_ok()->set_disabled(root->get_children() == NULL);
+ get_ok()->set_disabled(root->get_children() == nullptr);
}
void ScriptEditorQuickOpen::_confirmed() {
@@ -215,8 +216,8 @@ void ScriptEditorQuickOpen::_notification(int p_what) {
search_box->set_clear_button_enabled(true);
[[fallthrough]];
}
- case NOTIFICATION_THEME_CHANGED: {
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons"));
} break;
case NOTIFICATION_EXIT_TREE: {
disconnect("confirmed", callable_mp(this, &ScriptEditorQuickOpen::_confirmed));
@@ -246,12 +247,12 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() {
search_options->connect("item_activated", callable_mp(this, &ScriptEditorQuickOpen::_confirmed));
search_options->set_hide_root(true);
search_options->set_hide_folding(true);
- search_options->add_constant_override("draw_guides", 1);
+ search_options->add_theme_constant_override("draw_guides", 1);
}
/////////////////////////////////
-ScriptEditor *ScriptEditor::script_editor = NULL;
+ScriptEditor *ScriptEditor::script_editor = nullptr;
/*** SCRIPT EDITOR ******/
@@ -320,7 +321,7 @@ void ScriptEditor::_set_execution(REF p_script, int p_line) {
if (!se)
continue;
- if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
+ if ((script != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
se->set_executing_line(p_line);
}
}
@@ -336,7 +337,7 @@ void ScriptEditor::_clear_execution(REF p_script) {
if (!se)
continue;
- if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
+ if ((script != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
se->clear_executing_line();
}
}
@@ -347,7 +348,7 @@ ScriptEditorBase *ScriptEditor::_get_current_editor() const {
int selected = tab_container->get_current_tab();
if (selected < 0 || selected >= tab_container->get_child_count())
- return NULL;
+ return nullptr;
return Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
}
@@ -428,12 +429,12 @@ void ScriptEditor::_go_to_tab(int p_idx) {
if (Object::cast_to<ScriptEditorBase>(c)) {
script_name_label->set_text(Object::cast_to<ScriptEditorBase>(c)->get_name());
- script_icon->set_texture(Object::cast_to<ScriptEditorBase>(c)->get_icon());
+ script_icon->set_texture(Object::cast_to<ScriptEditorBase>(c)->get_theme_icon());
if (is_visible_in_tree())
Object::cast_to<ScriptEditorBase>(c)->ensure_focus();
Ref<Script> script = Object::cast_to<ScriptEditorBase>(c)->get_edited_resource();
- if (script != NULL) {
+ if (script != nullptr) {
notify_script_changed(script);
}
@@ -442,7 +443,7 @@ void ScriptEditor::_go_to_tab(int p_idx) {
if (Object::cast_to<EditorHelp>(c)) {
script_name_label->set_text(Object::cast_to<EditorHelp>(c)->get_class());
- script_icon->set_texture(get_icon("Help", "EditorIcons"));
+ script_icon->set_texture(get_theme_icon("Help", "EditorIcons"));
if (is_visible_in_tree())
Object::cast_to<EditorHelp>(c)->set_focused();
}
@@ -556,7 +557,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
void ScriptEditor::_show_error_dialog(String p_path) {
error_dialog->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_path));
- error_dialog->popup_centered_minsize();
+ error_dialog->popup_centered();
}
void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
@@ -574,7 +575,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
}
Ref<Script> script = current->get_edited_resource();
- if (script != NULL) {
+ if (script != nullptr) {
previous_scripts.push_back(script->get_path());
notify_script_close(script);
}
@@ -651,7 +652,7 @@ void ScriptEditor::_close_docs_tab() {
void ScriptEditor::_copy_script_path() {
ScriptEditorBase *se = _get_current_editor();
RES script = se->get_edited_resource();
- OS::get_singleton()->set_clipboard(script->get_path());
+ DisplayServer::get_singleton()->clipboard_set(script->get_path());
}
void ScriptEditor::_close_other_tabs() {
@@ -703,7 +704,7 @@ void ScriptEditor::_close_all_tabs() {
void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) {
erase_tab_confirm->set_text(TTR("Close and save changes?") + "\n\"" + current->get_name() + "\"");
- erase_tab_confirm->popup_centered_minsize();
+ erase_tab_confirm->popup_centered();
}
void ScriptEditor::_resave_scripts(const String &p_str) {
@@ -736,7 +737,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
}
Ref<TextFile> text_file = script;
- if (text_file != NULL) {
+ if (text_file != nullptr) {
se->apply_code();
_save_text_file(text_file, text_file->get_path());
break;
@@ -774,7 +775,7 @@ void ScriptEditor::_reload_scripts() {
}
Ref<Script> script = edited_res;
- if (script != NULL) {
+ if (script != nullptr) {
Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true);
ERR_CONTINUE(!rel_script.is_valid());
script->set_source_code(rel_script->get_source_code());
@@ -783,7 +784,7 @@ void ScriptEditor::_reload_scripts() {
}
Ref<TextFile> text_file = edited_res;
- if (text_file != NULL) {
+ if (text_file != nullptr) {
Error err;
Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
ERR_CONTINUE(!rel_text_file.is_valid());
@@ -960,16 +961,16 @@ Ref<Script> ScriptEditor::_get_current_script() {
if (current) {
Ref<Script> script = current->get_edited_resource();
- return script != NULL ? script : NULL;
+ return script != nullptr ? script : nullptr;
} else {
- return NULL;
+ return nullptr;
}
}
Array ScriptEditor::_get_open_scripts() const {
Array ret;
- Vector<Ref<Script> > scripts = get_open_scripts();
+ Vector<Ref<Script>> scripts = get_open_scripts();
int scrits_amount = scripts.size();
for (int idx_script = 0; idx_script < scrits_amount; idx_script++) {
ret.push_back(scripts[idx_script]);
@@ -995,7 +996,7 @@ void ScriptEditor::_menu_option(int p_option) {
script_create_dialog->popup_centered();
} break;
case FILE_NEW_TEXTFILE: {
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_dialog_option = FILE_NEW_TEXTFILE;
@@ -1004,7 +1005,7 @@ void ScriptEditor::_menu_option(int p_option) {
file_dialog->set_title(TTR("New Text File..."));
} break;
case FILE_OPEN: {
- file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_dialog_option = FILE_OPEN;
@@ -1092,11 +1093,6 @@ void ScriptEditor::_menu_option(int p_option) {
OS::get_singleton()->shell_open("https://docs.godotengine.org/");
} break;
- case REQUEST_DOCS: {
-
- OS::get_singleton()->shell_open("https://github.com/godotengine/godot-docs/issues/new");
- } break;
-
case WINDOW_NEXT: {
_history_forward();
@@ -1144,7 +1140,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
Ref<TextFile> text_file = current->get_edited_resource();
- if (text_file != NULL) {
+ if (text_file != nullptr) {
current->apply_code();
_save_text_file(text_file, text_file->get_path());
break;
@@ -1168,8 +1164,8 @@ void ScriptEditor::_menu_option(int p_option) {
}
Ref<TextFile> text_file = current->get_edited_resource();
- if (text_file != NULL) {
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ if (text_file != nullptr) {
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_dialog_option = FILE_SAVE_AS;
@@ -1197,7 +1193,7 @@ void ScriptEditor::_menu_option(int p_option) {
case FILE_RUN: {
Ref<Script> scr = current->get_edited_resource();
- if (scr == NULL || scr.is_null()) {
+ if (scr == nullptr || scr.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("Can't obtain the script for running."));
break;
}
@@ -1247,7 +1243,7 @@ void ScriptEditor::_menu_option(int p_option) {
file_system_dock->navigate_to_path(path);
// Ensure that the FileSystem dock is visible.
TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(file_system_dock->get_position_in_parent());
+ tab_container->set_current_tab(file_system_dock->get_index());
}
} break;
case CLOSE_DOCS: {
@@ -1335,7 +1331,7 @@ void ScriptEditor::_menu_option(int p_option) {
void ScriptEditor::_theme_option(int p_option) {
switch (p_option) {
case THEME_IMPORT: {
- file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_dialog_option = THEME_IMPORT;
file_dialog->clear_filters();
@@ -1360,7 +1356,7 @@ void ScriptEditor::_theme_option(int p_option) {
}
void ScriptEditor::_show_save_theme_as_dialog() {
- file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_dialog_option = THEME_SAVE_AS;
file_dialog->clear_filters();
@@ -1395,19 +1391,18 @@ void ScriptEditor::_notification(int p_what) {
}
case NOTIFICATION_THEME_CHANGED: {
- help_search->set_icon(get_icon("HelpSearch", "EditorIcons"));
- site_search->set_icon(get_icon("Instance", "EditorIcons"));
- request_docs->set_icon(get_icon("Issue", "EditorIcons"));
+ help_search->set_icon(get_theme_icon("HelpSearch", "EditorIcons"));
+ site_search->set_icon(get_theme_icon("Instance", "EditorIcons"));
- script_forward->set_icon(get_icon("Forward", "EditorIcons"));
- script_back->set_icon(get_icon("Back", "EditorIcons"));
+ script_forward->set_icon(get_theme_icon("Forward", "EditorIcons"));
+ script_back->set_icon(get_theme_icon("Back", "EditorIcons"));
- members_overview_alphabeta_sort_button->set_icon(get_icon("Sort", "EditorIcons"));
+ members_overview_alphabeta_sort_button->set_icon(get_theme_icon("Sort", "EditorIcons"));
- filter_scripts->set_right_icon(get_icon("Search", "EditorIcons"));
- filter_methods->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter_scripts->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ filter_methods->set_right_icon(get_theme_icon("Search", "EditorIcons"));
- filename->add_style_override("normal", editor->get_gui_base()->get_stylebox("normal", "LineEdit"));
+ filename->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("normal", "LineEdit"));
recent_scripts->set_as_minsize();
} break;
@@ -1424,7 +1419,7 @@ void ScriptEditor::_notification(int p_what) {
editor->disconnect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_FOCUS_IN: {
_test_script_times_on_disk();
_update_modified_scripts_for_external_editor();
@@ -1466,7 +1461,7 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) {
if (se) {
Ref<Script> script = se->get_edited_resource();
- if (script == NULL || !script.is_valid())
+ if (script == nullptr || !script.is_valid())
continue;
if (script->get_path().find("::") != -1 && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed
@@ -1499,7 +1494,7 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
continue;
Ref<Script> script = se->get_edited_resource();
- if (script == NULL) {
+ if (script == nullptr) {
continue;
}
@@ -1550,7 +1545,7 @@ void ScriptEditor::_help_overview_selected(int p_idx) {
void ScriptEditor::_script_selected(int p_idx) {
- grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing
+ grab_focus_block = !InputFilter::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing
_go_to_tab(script_list->get_item_metadata(p_idx));
grab_focus_block = false;
@@ -1571,7 +1566,7 @@ void ScriptEditor::ensure_select_current() {
_update_selected_editor_menu();
}
-void ScriptEditor::_find_scripts(Node *p_base, Node *p_current, Set<Ref<Script> > &used) {
+void ScriptEditor::_find_scripts(Node *p_base, Node *p_current, Set<Ref<Script>> &used) {
if (p_current != p_base && p_current->get_owner() != p_base)
return;
@@ -1704,7 +1699,7 @@ void ScriptEditor::_update_help_overview() {
return;
}
- Vector<Pair<String, int> > sections = se->get_sections();
+ Vector<Pair<String, int>> sections = se->get_sections();
for (int i = 0; i < sections.size(); i++) {
help_overview->add_item(sections[i].first);
help_overview->set_item_metadata(i, sections[i].second);
@@ -1717,8 +1712,8 @@ void ScriptEditor::_update_script_colors() {
bool highlight_current = EditorSettings::get_singleton()->get("text_editor/script_list/highlight_current_script");
int hist_size = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_history_size");
- Color hot_color = get_color("accent_color", "Editor");
- Color cold_color = get_color("font_color", "Editor");
+ Color hot_color = get_theme_color("accent_color", "Editor");
+ Color cold_color = get_theme_color("font_color", "Editor");
for (int i = 0; i < script_list->get_item_count(); i++) {
@@ -1757,7 +1752,7 @@ void ScriptEditor::_update_script_names() {
if (restoring_layout)
return;
- Set<Ref<Script> > used;
+ Set<Ref<Script>> used;
Node *edited = EditorNode::get_singleton()->get_edited_scene();
if (edited) {
_find_scripts(edited, edited, used);
@@ -1775,7 +1770,7 @@ void ScriptEditor::_update_script_names() {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
if (se) {
- Ref<Texture2D> icon = se->get_icon();
+ Ref<Texture2D> icon = se->get_theme_icon();
String path = se->get_edited_resource()->get_path();
bool built_in = !path.is_resource_file();
String name;
@@ -1838,7 +1833,7 @@ void ScriptEditor::_update_script_names() {
if (eh) {
String name = eh->get_class();
- Ref<Texture2D> icon = get_icon("Help", "EditorIcons");
+ Ref<Texture2D> icon = get_theme_icon("Help", "EditorIcons");
String tooltip = vformat(TTR("%s Class Reference"), name);
_ScriptEditorItemData sd;
@@ -1993,7 +1988,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
const bool should_open = open_dominant || !EditorNode::get_singleton()->is_changing_scene();
- if (script != NULL && script->get_language()->overrides_external_editor()) {
+ if (script != nullptr && script->get_language()->overrides_external_editor()) {
if (should_open) {
Error err = script->get_language()->open_in_external_editor(script, p_line >= 0 ? p_line : 0, p_col);
if (err != OK)
@@ -2071,7 +2066,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
if (!se)
continue;
- if ((script != NULL && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) {
+ if ((script != nullptr && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) {
if (should_open) {
if (tab_container->get_current_tab() != i) {
@@ -2093,7 +2088,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
// doesn't have it, make a new one
- ScriptEditorBase *se = NULL;
+ ScriptEditorBase *se = nullptr;
for (int i = script_editor_func_count - 1; i >= 0; i--) {
se = script_editor_funcs[i](p_resource);
@@ -2108,7 +2103,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
SyntaxHighlighter *highlighter = syntax_highlighters_funcs[i]();
se->add_syntax_highlighter(highlighter);
- if (script != NULL && !highlighter_set) {
+ if (script != nullptr && !highlighter_set) {
List<String> languages = highlighter->get_supported_languages();
if (languages.find(script->get_language()->get_name())) {
se->set_syntax_highlighter(highlighter);
@@ -2189,7 +2184,7 @@ void ScriptEditor::save_all_scripts() {
if (edited_res->get_path() != "" && edited_res->get_path().find("local://") == -1 && edited_res->get_path().find("::") == -1) {
Ref<TextFile> text_file = edited_res;
- if (text_file != NULL) {
+ if (text_file != nullptr) {
_save_text_file(text_file, text_file->get_path());
continue;
}
@@ -2348,12 +2343,12 @@ Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(cur_node);
if (se) {
preview_name = se->get_name();
- preview_icon = se->get_icon();
+ preview_icon = se->get_theme_icon();
}
EditorHelp *eh = Object::cast_to<EditorHelp>(cur_node);
if (eh) {
preview_name = eh->get_class();
- preview_icon = get_icon("Help", "EditorIcons");
+ preview_icon = get_theme_icon("Help", "EditorIcons");
}
if (!preview_icon.is_null()) {
@@ -2575,7 +2570,7 @@ void ScriptEditor::_make_script_list_context_menu() {
context_menu->add_separator();
if (se) {
Ref<Script> scr = se->get_edited_resource();
- if (scr != NULL) {
+ if (scr != nullptr) {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT);
if (!scr.is_null() && scr->is_tool()) {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN);
@@ -2832,7 +2827,7 @@ void ScriptEditor::_update_history_pos(int p_new_pos) {
Object::cast_to<ScriptEditorBase>(n)->ensure_focus();
Ref<Script> script = Object::cast_to<ScriptEditorBase>(n)->get_edited_resource();
- if (script != NULL) {
+ if (script != nullptr) {
notify_script_changed(script);
}
}
@@ -2863,9 +2858,9 @@ void ScriptEditor::_history_back() {
}
}
-Vector<Ref<Script> > ScriptEditor::get_open_scripts() const {
+Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
- Vector<Ref<Script> > out_scripts = Vector<Ref<Script> >();
+ Vector<Ref<Script>> out_scripts = Vector<Ref<Script>>();
for (int i = 0; i < tab_container->get_child_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
@@ -2873,7 +2868,7 @@ Vector<Ref<Script> > ScriptEditor::get_open_scripts() const {
continue;
Ref<Script> script = se->get_edited_resource();
- if (script != NULL) {
+ if (script != nullptr) {
out_scripts.push_back(script);
}
}
@@ -2954,7 +2949,7 @@ void ScriptEditor::_on_find_in_files_requested(String text) {
find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::SEARCH_MODE);
find_in_files_dialog->set_search_text(text);
- find_in_files_dialog->popup_centered_minsize();
+ find_in_files_dialog->popup_centered();
}
void ScriptEditor::_on_replace_in_files_requested(String text) {
@@ -2962,7 +2957,7 @@ void ScriptEditor::_on_replace_in_files_requested(String text) {
find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::REPLACE_MODE);
find_in_files_dialog->set_search_text(text);
find_in_files_dialog->set_replace_text("");
- find_in_files_dialog->popup_centered_minsize();
+ find_in_files_dialog->popup_centered();
}
void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) {
@@ -3113,7 +3108,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
context_menu = memnew(PopupMenu);
add_child(context_menu);
context_menu->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option));
- context_menu->set_hide_on_window_lose_focus(true);
overview_vbox = memnew(VBoxContainer);
overview_vbox->set_custom_minimum_size(Size2(0, 90));
@@ -3126,7 +3120,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
filename = memnew(Label);
filename->set_clip_text(true);
filename->set_h_size_flags(SIZE_EXPAND_FILL);
- filename->add_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_stylebox("normal", "LineEdit"));
+ filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("normal", "LineEdit"));
buttons_hbox->add_child(filename);
members_overview_alphabeta_sort_button = memnew(ToolButton);
@@ -3174,7 +3168,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_child(file_menu);
file_menu->set_text(TTR("File"));
file_menu->set_switch_on_hover(true);
- file_menu->get_popup()->set_hide_on_window_lose_focus(true);
+
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script...")), FILE_NEW);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File...")), FILE_NEW_TEXTFILE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN);
@@ -3231,7 +3225,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_child(script_search_menu);
script_search_menu->set_text(TTR("Search"));
script_search_menu->set_switch_on_hover(true);
- script_search_menu->get_popup()->set_hide_on_window_lose_focus(true);
script_search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option));
MenuButton *debug_menu = memnew(MenuButton);
@@ -3263,12 +3256,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_child(site_search);
site_search->set_tooltip(TTR("Open Godot online documentation."));
- request_docs = memnew(ToolButton);
- request_docs->set_text(TTR("Request Docs"));
- request_docs->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option), varray(REQUEST_DOCS));
- menu_hb->add_child(request_docs);
- request_docs->set_tooltip(TTR("Help improve the Godot documentation by giving feedback."));
-
help_search = memnew(ToolButton);
help_search->set_text(TTR("Search Help"));
help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option), varray(SEARCH_HELP));
@@ -3293,7 +3280,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
erase_tab_confirm = memnew(ConfirmationDialog);
erase_tab_confirm->get_ok()->set_text(TTR("Save"));
- erase_tab_confirm->add_button(TTR("Discard"), OS::get_singleton()->get_swap_ok_cancel(), "discard");
+ erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "discard");
erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab));
erase_tab_confirm->connect("custom_action", callable_mp(this, &ScriptEditor::_close_discard_current_tab));
add_child(erase_tab_confirm);
@@ -3327,7 +3314,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts));
disk_changed->get_ok()->set_text(TTR("Reload"));
- disk_changed->add_button(TTR("Resave"), !OS::get_singleton()->get_swap_ok_cancel(), "resave");
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ScriptEditor::_resave_scripts));
}
@@ -3368,8 +3355,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
ScriptServer::edit_request_func = _open_script_request;
- add_style_override("panel", editor->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles"));
- tab_container->add_style_override("panel", editor->get_gui_base()->get_stylebox("ScriptEditor", "EditorStyles"));
+ add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("ScriptEditorPanel", "EditorStyles"));
+ tab_container->add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("ScriptEditor", "EditorStyles"));
}
ScriptEditor::~ScriptEditor() {
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index b4b4f33fc5..e895867268 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -92,7 +92,7 @@ public:
virtual void set_edited_resource(const RES &p_res) = 0;
virtual void reload_text() = 0;
virtual String get_name() = 0;
- virtual Ref<Texture2D> get_icon() = 0;
+ virtual Ref<Texture2D> get_theme_icon() = 0;
virtual bool is_unsaved() = 0;
virtual Variant get_edit_state() = 0;
virtual void set_edit_state(const Variant &p_state) = 0;
@@ -159,7 +159,6 @@ class ScriptEditor : public PanelContainer {
REPLACE_IN_FILES,
SEARCH_HELP,
SEARCH_WEBSITE,
- REQUEST_DOCS,
HELP_SEARCH_FIND,
HELP_SEARCH_FIND_NEXT,
HELP_SEARCH_FIND_PREVIOUS,
@@ -204,7 +203,6 @@ class ScriptEditor : public PanelContainer {
Button *help_search;
Button *site_search;
- Button *request_docs;
EditorHelpSearch *help_search_dialog;
ItemList *script_list;
@@ -351,7 +349,7 @@ class ScriptEditor : public PanelContainer {
void _update_help_overview();
void _help_overview_selected(int p_idx);
- void _find_scripts(Node *p_base, Node *p_current, Set<Ref<Script> > &used);
+ void _find_scripts(Node *p_base, Node *p_current, Set<Ref<Script>> &used);
void _tree_changed();
@@ -429,7 +427,7 @@ public:
void get_window_layout(Ref<ConfigFile> p_layout);
void set_scene_root_script(Ref<Script> p_script);
- Vector<Ref<Script> > get_open_scripts() const;
+ Vector<Ref<Script>> get_open_scripts() const;
bool script_goto_method(Ref<Script> p_script, const String &p_method);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 02168a4c97..4b8383e1e5 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -65,7 +65,8 @@ void ConnectionInfoDialog::popup_connections(String p_method, Vector<Node *> p_n
node_item->set_editable(0, false);
node_item->set_text(1, connection.signal.get_name());
- node_item->set_icon(1, get_parent_control()->get_icon("Slot", "EditorIcons"));
+ Control *p = Object::cast_to<Control>(get_parent());
+ node_item->set_icon(1, p->get_theme_icon("Slot", "EditorIcons"));
node_item->set_selectable(1, false);
node_item->set_editable(1, false);
@@ -83,10 +84,10 @@ ConnectionInfoDialog::ConnectionInfoDialog() {
set_title(TTR("Connections to method:"));
VBoxContainer *vbc = memnew(VBoxContainer);
- vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -8 * EDSCALE);
- vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE);
+ vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE);
add_child(vbc);
method = memnew(Label);
@@ -101,7 +102,7 @@ ConnectionInfoDialog::ConnectionInfoDialog() {
tree->set_column_title(1, TTR("Signal"));
tree->set_column_title(2, TTR("Target"));
vbc->add_child(tree);
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->set_allow_rmb_select(true);
}
@@ -229,36 +230,36 @@ void ScriptTextEditor::_load_theme_settings() {
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color string_color = EDITOR_GET("text_editor/highlighting/string_color");
- text_edit->add_color_override("background_color", background_color);
- text_edit->add_color_override("completion_background_color", completion_background_color);
- text_edit->add_color_override("completion_selected_color", completion_selected_color);
- text_edit->add_color_override("completion_existing_color", completion_existing_color);
- text_edit->add_color_override("completion_scroll_color", completion_scroll_color);
- text_edit->add_color_override("completion_font_color", completion_font_color);
- text_edit->add_color_override("font_color", text_color);
- text_edit->add_color_override("line_number_color", line_number_color);
- text_edit->add_color_override("safe_line_number_color", safe_line_number_color);
- text_edit->add_color_override("caret_color", caret_color);
- text_edit->add_color_override("caret_background_color", caret_background_color);
- text_edit->add_color_override("font_color_selected", text_selected_color);
- text_edit->add_color_override("selection_color", selection_color);
- text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color);
- text_edit->add_color_override("current_line_color", current_line_color);
- text_edit->add_color_override("line_length_guideline_color", line_length_guideline_color);
- text_edit->add_color_override("word_highlighted_color", word_highlighted_color);
- text_edit->add_color_override("number_color", number_color);
- text_edit->add_color_override("function_color", function_color);
- text_edit->add_color_override("member_variable_color", member_variable_color);
- text_edit->add_color_override("bookmark_color", bookmark_color);
- text_edit->add_color_override("breakpoint_color", breakpoint_color);
- text_edit->add_color_override("executing_line_color", executing_line_color);
- text_edit->add_color_override("mark_color", mark_color);
- text_edit->add_color_override("code_folding_color", code_folding_color);
- text_edit->add_color_override("search_result_color", search_result_color);
- text_edit->add_color_override("search_result_border_color", search_result_border_color);
- text_edit->add_color_override("symbol_color", symbol_color);
-
- text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
+ text_edit->add_theme_color_override("background_color", background_color);
+ text_edit->add_theme_color_override("completion_background_color", completion_background_color);
+ text_edit->add_theme_color_override("completion_selected_color", completion_selected_color);
+ text_edit->add_theme_color_override("completion_existing_color", completion_existing_color);
+ text_edit->add_theme_color_override("completion_scroll_color", completion_scroll_color);
+ text_edit->add_theme_color_override("completion_font_color", completion_font_color);
+ text_edit->add_theme_color_override("font_color", text_color);
+ text_edit->add_theme_color_override("line_number_color", line_number_color);
+ text_edit->add_theme_color_override("safe_line_number_color", safe_line_number_color);
+ text_edit->add_theme_color_override("caret_color", caret_color);
+ text_edit->add_theme_color_override("caret_background_color", caret_background_color);
+ text_edit->add_theme_color_override("font_color_selected", text_selected_color);
+ text_edit->add_theme_color_override("selection_color", selection_color);
+ text_edit->add_theme_color_override("brace_mismatch_color", brace_mismatch_color);
+ text_edit->add_theme_color_override("current_line_color", current_line_color);
+ text_edit->add_theme_color_override("line_length_guideline_color", line_length_guideline_color);
+ text_edit->add_theme_color_override("word_highlighted_color", word_highlighted_color);
+ text_edit->add_theme_color_override("number_color", number_color);
+ text_edit->add_theme_color_override("function_color", function_color);
+ text_edit->add_theme_color_override("member_variable_color", member_variable_color);
+ text_edit->add_theme_color_override("bookmark_color", bookmark_color);
+ text_edit->add_theme_color_override("breakpoint_color", breakpoint_color);
+ text_edit->add_theme_color_override("executing_line_color", executing_line_color);
+ text_edit->add_theme_color_override("mark_color", mark_color);
+ text_edit->add_theme_color_override("code_folding_color", code_folding_color);
+ text_edit->add_theme_color_override("search_result_color", search_result_color);
+ text_edit->add_theme_color_override("search_result_border_color", search_result_border_color);
+ text_edit->add_theme_color_override("symbol_color", symbol_color);
+
+ text_edit->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
colors_cache.symbol_color = symbol_color;
colors_cache.keyword_color = keyword_color;
@@ -555,10 +556,10 @@ String ScriptTextEditor::get_name() {
return name;
}
-Ref<Texture2D> ScriptTextEditor::get_icon() {
+Ref<Texture2D> ScriptTextEditor::get_theme_icon() {
- if (get_parent_control() && get_parent_control()->has_icon(script->get_class(), "EditorIcons")) {
- return get_parent_control()->get_icon(script->get_class(), "EditorIcons");
+ if (get_parent_control() && get_parent_control()->has_theme_icon(script->get_class(), "EditorIcons")) {
+ return get_parent_control()->get_theme_icon(script->get_class(), "EditorIcons");
}
return Ref<Texture2D>();
@@ -614,7 +615,7 @@ void ScriptTextEditor::_validate_script() {
String target_path = base == connection.callable.get_object() ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.callable.get_object()));
warnings_panel->push_cell();
- warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor"));
+ warnings_panel->push_color(warnings_panel->get_theme_color("warning_color", "Editor"));
warnings_panel->add_text(vformat(TTR("Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."), connection.callable.get_method(), connection.signal.get_name(), source_path, target_path));
warnings_panel->pop(); // Color.
warnings_panel->pop(); // Cell.
@@ -634,7 +635,7 @@ void ScriptTextEditor::_validate_script() {
warnings_panel->push_cell();
warnings_panel->push_meta(w.line - 1);
- warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor"));
+ warnings_panel->push_color(warnings_panel->get_theme_color("warning_color", "Editor"));
warnings_panel->add_text(TTR("Line") + " " + itos(w.line));
warnings_panel->add_text(" (" + w.string_code + "):");
warnings_panel->pop(); // Color.
@@ -746,7 +747,7 @@ static Vector<Node *> _find_all_node_for_script(Node *p_base, Node *p_current, c
static Node *_find_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) {
if (p_current->get_owner() != p_base && p_base != p_current)
- return NULL;
+ return nullptr;
Ref<Script> c = p_current->get_script();
if (c == p_script)
return p_current;
@@ -756,10 +757,10 @@ static Node *_find_node_for_script(Node *p_base, Node *p_current, const Ref<Scri
return found;
}
- return NULL;
+ return nullptr;
}
-static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_current, Set<Ref<Script> > &r_scripts) {
+static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_current, Set<Ref<Script>> &r_scripts) {
if (p_current->get_owner() != p_base && p_base != p_current)
return;
@@ -780,14 +781,14 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
ERR_FAIL_COND(!get_tree());
- Set<Ref<Script> > scripts;
+ Set<Ref<Script>> scripts;
Node *base = get_tree()->get_edited_scene_root();
if (base) {
_find_changed_scripts_for_external_editor(base, base, scripts);
}
- for (Set<Ref<Script> >::Element *E = scripts.front(); E; E = E->next()) {
+ for (Set<Ref<Script>>::Element *E = scripts.front(); E; E = E->next()) {
Ref<Script> script = E->get();
@@ -821,7 +822,7 @@ void ScriptTextEditor::_code_complete_scripts(void *p_ud, const String &p_code,
void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) {
- if (color_panel->is_visible_in_tree()) return;
+ if (color_panel->is_visible()) return;
Node *base = get_tree()->get_edited_scene_root();
if (base) {
base = _find_node_for_script(base, base, script);
@@ -980,8 +981,25 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
}
}
+void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
+
+ TextEdit *text_edit = code_editor->get_text_edit();
+
+ Node *base = get_tree()->get_edited_scene_root();
+ if (base) {
+ base = _find_node_for_script(base, base, script);
+ }
+
+ ScriptLanguage::LookupResult result;
+ if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK) {
+ text_edit->set_highlighted_word(p_symbol);
+ } else {
+ text_edit->set_highlighted_word(String());
+ }
+}
+
void ScriptTextEditor::update_toggle_scripts_button() {
- if (code_editor != NULL) {
+ if (code_editor != nullptr) {
code_editor->update_toggle_scripts_button();
}
}
@@ -1029,7 +1047,7 @@ void ScriptTextEditor::_update_connected_methods() {
String name = functions[j].get_slice(":", 0);
if (name == connection.callable.get_method()) {
line = functions[j].get_slice(":", 1).to_int();
- text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.callable.get_method());
+ text_edit->set_line_info_icon(line - 1, get_parent_control()->get_theme_icon("Slot", "EditorIcons"), connection.callable.get_method());
methods_found.insert(connection.callable.get_method());
break;
}
@@ -1418,7 +1436,7 @@ void ScriptTextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter)
void ScriptTextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
TextEdit *te = code_editor->get_text_edit();
te->_set_syntax_highlighting(p_highlighter);
- if (p_highlighter != NULL)
+ if (p_highlighter != nullptr)
highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true);
else
highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(TTR("Standard")), true);
@@ -1426,7 +1444,7 @@ void ScriptTextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter)
void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
Map<String, SyntaxHighlighter *>::Element *el = highlighters.front();
- while (el != NULL) {
+ while (el != nullptr) {
highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false);
el = el->next();
}
@@ -1499,7 +1517,7 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene)
- return NULL;
+ return nullptr;
Ref<Script> scr = p_current_node->get_script();
@@ -1512,7 +1530,7 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return n;
}
- return NULL;
+ return nullptr;
}
void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
@@ -1762,13 +1780,14 @@ ScriptTextEditor::ScriptTextEditor() {
code_editor = memnew(CodeTextEditor);
editor_box->add_child(code_editor);
- code_editor->add_constant_override("separation", 2);
+ code_editor->add_theme_constant_override("separation", 2);
code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE);
code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script));
code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings));
code_editor->set_code_complete_func(_code_complete_scripts, this);
code_editor->get_text_edit()->connect("breakpoint_toggled", callable_mp(this, &ScriptTextEditor::_breakpoint_toggled));
code_editor->get_text_edit()->connect("symbol_lookup", callable_mp(this, &ScriptTextEditor::_lookup_symbol));
+ code_editor->get_text_edit()->connect("symbol_validate", callable_mp(this, &ScriptTextEditor::_validate_symbol));
code_editor->get_text_edit()->connect("info_clicked", callable_mp(this, &ScriptTextEditor::_lookup_connections));
code_editor->set_v_size_flags(SIZE_EXPAND_FILL);
code_editor->show_toggle_scripts_button();
@@ -1799,7 +1818,6 @@ ScriptTextEditor::ScriptTextEditor() {
context_menu = memnew(PopupMenu);
add_child(context_menu);
context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
- context_menu->set_hide_on_window_lose_focus(true);
color_panel = memnew(PopupPanel);
add_child(color_panel);
@@ -1820,7 +1838,7 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu = memnew(MenuButton);
edit_menu->set_text(TTR("Edit"));
edit_menu->set_switch_on_hover(true);
- edit_menu->get_popup()->set_hide_on_window_lose_focus(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_separator();
@@ -1859,7 +1877,7 @@ ScriptTextEditor::ScriptTextEditor() {
convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F6), EDIT_CAPITALIZE);
convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
- highlighters[TTR("Standard")] = NULL;
+ highlighters[TTR("Standard")] = nullptr;
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("highlighter_menu");
edit_menu->get_popup()->add_child(highlighter_menu);
@@ -1871,7 +1889,7 @@ ScriptTextEditor::ScriptTextEditor() {
edit_hb->add_child(search_menu);
search_menu->set_text(TTR("Search"));
search_menu->set_switch_on_hover(true);
- search_menu->get_popup()->set_hide_on_window_lose_focus(true);
+
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
@@ -1900,7 +1918,7 @@ ScriptTextEditor::ScriptTextEditor() {
goto_menu->get_popup()->add_child(bookmarks_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks");
_update_bookmark_list();
- bookmarks_menu->connect("about_to_show", callable_mp(this, &ScriptTextEditor::_update_bookmark_list));
+ bookmarks_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list));
bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed));
breakpoints_menu = memnew(PopupMenu);
@@ -1908,7 +1926,7 @@ ScriptTextEditor::ScriptTextEditor() {
goto_menu->get_popup()->add_child(breakpoints_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "Breakpoints");
_update_breakpoint_list();
- breakpoints_menu->connect("about_to_show", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list));
+ breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list));
breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed));
quick_open = memnew(ScriptEditorQuickOpen);
@@ -1926,7 +1944,7 @@ ScriptTextEditor::ScriptTextEditor() {
ScriptTextEditor::~ScriptTextEditor() {
for (const Map<String, SyntaxHighlighter *>::Element *E = highlighters.front(); E; E = E->next()) {
- if (E->get() != NULL) {
+ if (E->get() != nullptr) {
memdelete(E->get());
}
}
@@ -1938,7 +1956,7 @@ static ScriptEditorBase *create_editor(const RES &p_resource) {
if (Object::cast_to<Script>(*p_resource)) {
return memnew(ScriptTextEditor);
}
- return NULL;
+ return nullptr;
}
void ScriptTextEditor::register_editor() {
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index e23160d029..51ce30c831 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -178,6 +178,7 @@ protected:
void _goto_line(int p_line) { goto_line(p_line); }
void _lookup_symbol(const String &p_symbol, int p_row, int p_column);
+ void _validate_symbol(const String &p_symbol);
void _lookup_connections(int p_row, String p_method);
@@ -200,7 +201,7 @@ public:
virtual Vector<String> get_functions();
virtual void reload_text();
virtual String get_name();
- virtual Ref<Texture2D> get_icon();
+ virtual Ref<Texture2D> get_theme_icon();
virtual bool is_unsaved();
virtual Variant get_edit_state();
virtual void set_edit_state(const Variant &p_state);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 01b1e21153..2a36700105 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -38,7 +38,8 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/property_editor.h"
-#include "servers/visual/shader_types.h"
+#include "servers/display_server.h"
+#include "servers/rendering/shader_types.h"
/*** SHADER SCRIPT EDITOR ****/
@@ -116,49 +117,49 @@ void ShaderTextEditor::_load_theme_settings() {
Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
- get_text_edit()->add_color_override("background_color", background_color);
- get_text_edit()->add_color_override("completion_background_color", completion_background_color);
- get_text_edit()->add_color_override("completion_selected_color", completion_selected_color);
- get_text_edit()->add_color_override("completion_existing_color", completion_existing_color);
- get_text_edit()->add_color_override("completion_scroll_color", completion_scroll_color);
- get_text_edit()->add_color_override("completion_font_color", completion_font_color);
- get_text_edit()->add_color_override("font_color", text_color);
- get_text_edit()->add_color_override("line_number_color", line_number_color);
- get_text_edit()->add_color_override("caret_color", caret_color);
- get_text_edit()->add_color_override("caret_background_color", caret_background_color);
- get_text_edit()->add_color_override("font_color_selected", text_selected_color);
- get_text_edit()->add_color_override("selection_color", selection_color);
- get_text_edit()->add_color_override("brace_mismatch_color", brace_mismatch_color);
- get_text_edit()->add_color_override("current_line_color", current_line_color);
- get_text_edit()->add_color_override("line_length_guideline_color", line_length_guideline_color);
- get_text_edit()->add_color_override("word_highlighted_color", word_highlighted_color);
- get_text_edit()->add_color_override("number_color", number_color);
- get_text_edit()->add_color_override("function_color", function_color);
- get_text_edit()->add_color_override("member_variable_color", member_variable_color);
- get_text_edit()->add_color_override("mark_color", mark_color);
- get_text_edit()->add_color_override("bookmark_color", bookmark_color);
- get_text_edit()->add_color_override("breakpoint_color", breakpoint_color);
- get_text_edit()->add_color_override("executing_line_color", executing_line_color);
- get_text_edit()->add_color_override("code_folding_color", code_folding_color);
- get_text_edit()->add_color_override("search_result_color", search_result_color);
- get_text_edit()->add_color_override("search_result_border_color", search_result_border_color);
- get_text_edit()->add_color_override("symbol_color", symbol_color);
+ get_text_edit()->add_theme_color_override("background_color", background_color);
+ get_text_edit()->add_theme_color_override("completion_background_color", completion_background_color);
+ get_text_edit()->add_theme_color_override("completion_selected_color", completion_selected_color);
+ get_text_edit()->add_theme_color_override("completion_existing_color", completion_existing_color);
+ get_text_edit()->add_theme_color_override("completion_scroll_color", completion_scroll_color);
+ get_text_edit()->add_theme_color_override("completion_font_color", completion_font_color);
+ get_text_edit()->add_theme_color_override("font_color", text_color);
+ get_text_edit()->add_theme_color_override("line_number_color", line_number_color);
+ get_text_edit()->add_theme_color_override("caret_color", caret_color);
+ get_text_edit()->add_theme_color_override("caret_background_color", caret_background_color);
+ get_text_edit()->add_theme_color_override("font_color_selected", text_selected_color);
+ get_text_edit()->add_theme_color_override("selection_color", selection_color);
+ get_text_edit()->add_theme_color_override("brace_mismatch_color", brace_mismatch_color);
+ get_text_edit()->add_theme_color_override("current_line_color", current_line_color);
+ get_text_edit()->add_theme_color_override("line_length_guideline_color", line_length_guideline_color);
+ get_text_edit()->add_theme_color_override("word_highlighted_color", word_highlighted_color);
+ get_text_edit()->add_theme_color_override("number_color", number_color);
+ get_text_edit()->add_theme_color_override("function_color", function_color);
+ get_text_edit()->add_theme_color_override("member_variable_color", member_variable_color);
+ get_text_edit()->add_theme_color_override("mark_color", mark_color);
+ get_text_edit()->add_theme_color_override("bookmark_color", bookmark_color);
+ get_text_edit()->add_theme_color_override("breakpoint_color", breakpoint_color);
+ get_text_edit()->add_theme_color_override("executing_line_color", executing_line_color);
+ get_text_edit()->add_theme_color_override("code_folding_color", code_folding_color);
+ get_text_edit()->add_theme_color_override("search_result_color", search_result_color);
+ get_text_edit()->add_theme_color_override("search_result_border_color", search_result_border_color);
+ get_text_edit()->add_theme_color_override("symbol_color", symbol_color);
List<String> keywords;
ShaderLanguage::get_keyword_list(&keywords);
if (shader.is_valid()) {
- for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) {
+ for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) {
for (const Map<StringName, ShaderLanguage::BuiltInInfo>::Element *F = E->get().built_ins.front(); F; F = F->next()) {
keywords.push_back(F->key());
}
}
- for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())).size(); i++) {
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) {
- keywords.push_back(ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode()))[i]);
+ keywords.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]);
}
}
@@ -199,7 +200,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(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), 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())), ShaderTypes::get_singleton()->get_types(), r_options, calltip);
get_text_edit()->set_code_hint(calltip);
}
@@ -214,7 +215,7 @@ void ShaderTextEditor::_validate_script() {
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types());
+ 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());
if (err != OK) {
String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();
@@ -351,7 +352,7 @@ void ShaderEditor::_menu_option(int p_option) {
void ShaderEditor::_notification(int p_what) {
- if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) {
+ if (p_what == NOTIFICATION_WM_FOCUS_IN) {
_check_for_external_edit();
}
}
@@ -376,7 +377,7 @@ void ShaderEditor::_editor_settings_changed() {
shader_editor->get_text_edit()->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line"));
shader_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink"));
shader_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed"));
- shader_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/theme/line_spacing"));
+ shader_editor->get_text_edit()->add_theme_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/theme/line_spacing"));
shader_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret"));
shader_editor->get_text_edit()->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/navigation/smooth_scrolling"));
shader_editor->get_text_edit()->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/navigation/v_scroll_speed"));
@@ -595,7 +596,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
shader_editor = memnew(ShaderTextEditor);
shader_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- shader_editor->add_constant_override("separation", 0);
+ shader_editor->add_theme_constant_override("separation", 0);
shader_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE);
shader_editor->connect("script_changed", callable_mp(this, &ShaderEditor::apply_shaders));
@@ -614,7 +615,6 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
context_menu = memnew(PopupMenu);
add_child(context_menu);
context_menu->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option));
- context_menu->set_hide_on_window_lose_focus(true);
VBoxContainer *main_container = memnew(VBoxContainer);
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -622,7 +622,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
edit_menu = memnew(MenuButton);
edit_menu->set_text(TTR("Edit"));
edit_menu->set_switch_on_hover(true);
- edit_menu->get_popup()->set_hide_on_window_lose_focus(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_separator();
@@ -646,7 +646,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
search_menu = memnew(MenuButton);
search_menu->set_text(TTR("Search"));
search_menu->set_switch_on_hover(true);
- search_menu->get_popup()->set_hide_on_window_lose_focus(true);
+
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
@@ -666,13 +666,13 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
goto_menu->get_popup()->add_child(bookmarks_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks");
_update_bookmark_list();
- bookmarks_menu->connect("about_to_show", callable_mp(this, &ShaderEditor::_update_bookmark_list));
+ bookmarks_menu->connect("about_to_popup", callable_mp(this, &ShaderEditor::_update_bookmark_list));
bookmarks_menu->connect("index_pressed", callable_mp(this, &ShaderEditor::_bookmark_item_pressed));
help_menu = memnew(MenuButton);
help_menu->set_text(TTR("Help"));
help_menu->set_switch_on_hover(true);
- help_menu->get_popup()->add_icon_item(p_node->get_gui_base()->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS);
+ help_menu->get_popup()->add_icon_item(p_node->get_gui_base()->get_theme_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS);
help_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option));
add_child(main_container);
@@ -681,7 +681,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
hbc->add_child(edit_menu);
hbc->add_child(goto_menu);
hbc->add_child(help_menu);
- hbc->add_style_override("panel", p_node->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles"));
+ hbc->add_theme_style_override("panel", p_node->get_gui_base()->get_theme_stylebox("ScriptEditorPanel", "EditorStyles"));
main_container->add_child(shader_editor);
goto_line_dialog = memnew(GotoLineDialog);
@@ -699,7 +699,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
disk_changed->connect("confirmed", callable_mp(this, &ShaderEditor::_reload_shader_from_disk));
disk_changed->get_ok()->set_text(TTR("Reload"));
- disk_changed->add_button(TTR("Resave"), !OS::get_singleton()->get_swap_ok_cancel(), "resave");
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ShaderEditor::save_external_data));
add_child(disk_changed);
@@ -716,7 +716,7 @@ void ShaderEditorPlugin::edit(Object *p_object) {
bool ShaderEditorPlugin::handles(Object *p_object) const {
Shader *shader = Object::cast_to<Shader>(p_object);
- return shader != NULL && shader->is_text_shader();
+ return shader != nullptr && shader->is_text_shader();
}
void ShaderEditorPlugin::make_visible(bool p_visible) {
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 900b40bd7a..f02ed590fc 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -39,7 +39,7 @@
#include "scene/gui/text_edit.h"
#include "scene/main/timer.h"
#include "scene/resources/shader.h"
-#include "servers/visual/shader_language.h"
+#include "servers/rendering/shader_language.h"
class ShaderTextEditor : public CodeTextEditor {
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 0b77b987bf..c81d3f787e 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -38,7 +38,7 @@
void Skeleton2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
- node = NULL;
+ node = nullptr;
options->hide();
}
}
@@ -59,7 +59,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
if (node->get_bone_count() == 0) {
err_dialog->set_text(TTR("This skeleton has no bones, create some children Bone2D nodes."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
@@ -75,7 +75,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
case MENU_OPTION_SET_REST: {
if (node->get_bone_count() == 0) {
err_dialog->set_text(TTR("This skeleton has no bones, create some children Bone2D nodes."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
@@ -101,7 +101,7 @@ Skeleton2DEditor::Skeleton2DEditor() {
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text(TTR("Skeleton2D"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton2D", "EditorIcons"));
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Skeleton2D", "EditorIcons"));
options->get_popup()->add_item(TTR("Make Rest Pose (From Bones)"), MENU_OPTION_MAKE_REST);
options->get_popup()->add_separator();
@@ -131,7 +131,7 @@ void Skeleton2DEditorPlugin::make_visible(bool p_visible) {
} else {
sprite_editor->options->hide();
- sprite_editor->edit(NULL);
+ sprite_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..fac4cb19d8
--- /dev/null
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -0,0 +1,195 @@
+/*************************************************************************/
+/* skeleton_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "skeleton_3d_editor_plugin.h"
+
+#include "node_3d_editor_plugin.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/3d/physics_joint_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/sphere_shape_3d.h"
+
+void Skeleton3DEditor::_on_click_option(int p_option) {
+ if (!skeleton) {
+ return;
+ }
+
+ switch (p_option) {
+ case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
+ create_physical_skeleton();
+ } break;
+ }
+}
+
+void Skeleton3DEditor::create_physical_skeleton() {
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();
+
+ const int bc = skeleton->get_bone_count();
+
+ if (!bc) {
+ return;
+ }
+
+ Vector<BoneInfo> bones_infos;
+ bones_infos.resize(bc);
+
+ for (int bone_id = 0; bc > bone_id; ++bone_id) {
+
+ const int parent = skeleton->get_bone_parent(bone_id);
+
+ if (parent < 0) {
+
+ bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
+
+ } else {
+
+ const int parent_parent = skeleton->get_bone_parent(parent);
+
+ bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
+
+ /// create physical bone on parent
+ if (!bones_infos[parent].physical_bone) {
+
+ bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);
+
+ ur->create_action(TTR("Create physical bones"));
+ ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
+ ur->add_do_reference(bones_infos[parent].physical_bone);
+ ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
+ ur->commit_action();
+
+ bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent));
+ bones_infos[parent].physical_bone->set_owner(owner);
+ bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner
+
+ /// Create joint between parent of parent
+ if (-1 != parent_parent) {
+
+ bones_infos[parent].physical_bone->set_joint_type(PhysicalBone3D::JOINT_TYPE_PIN);
+ }
+ }
+ }
+ }
+}
+
+PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {
+
+ const Transform child_rest = skeleton->get_bone_rest(bone_child_id);
+
+ const real_t half_height(child_rest.origin.length() * 0.5);
+ const real_t radius(half_height * 0.2);
+
+ CapsuleShape3D *bone_shape_capsule = memnew(CapsuleShape3D);
+ bone_shape_capsule->set_height((half_height - radius) * 2);
+ bone_shape_capsule->set_radius(radius);
+
+ CollisionShape3D *bone_shape = memnew(CollisionShape3D);
+ bone_shape->set_shape(bone_shape_capsule);
+
+ Transform body_transform;
+ body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin, Vector3(0, 1, 0));
+ body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height));
+
+ Transform joint_transform;
+ joint_transform.origin = Vector3(0, 0, half_height);
+
+ PhysicalBone3D *physical_bone = memnew(PhysicalBone3D);
+ physical_bone->add_child(bone_shape);
+ physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id));
+ physical_bone->set_body_offset(body_transform);
+ physical_bone->set_joint_offset(joint_transform);
+ return physical_bone;
+}
+
+void Skeleton3DEditor::edit(Skeleton3D *p_node) {
+
+ skeleton = p_node;
+}
+
+void Skeleton3DEditor::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed));
+ }
+}
+
+void Skeleton3DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == skeleton) {
+ skeleton = nullptr;
+ options->hide();
+ }
+}
+
+void Skeleton3DEditor::_bind_methods() {
+}
+
+Skeleton3DEditor::Skeleton3DEditor() {
+ skeleton = nullptr;
+ options = memnew(MenuButton);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
+
+ options->set_text(TTR("Skeleton3D"));
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Skeleton3D", "EditorIcons"));
+
+ options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);
+
+ options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_option));
+ options->hide();
+}
+
+Skeleton3DEditor::~Skeleton3DEditor() {}
+
+void Skeleton3DEditorPlugin::edit(Object *p_object) {
+ skeleton_editor->edit(Object::cast_to<Skeleton3D>(p_object));
+}
+
+bool Skeleton3DEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("Skeleton3D");
+}
+
+void Skeleton3DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ skeleton_editor->options->show();
+ } else {
+
+ skeleton_editor->options->hide();
+ skeleton_editor->edit(nullptr);
+ }
+}
+
+Skeleton3DEditorPlugin::Skeleton3DEditorPlugin(EditorNode *p_node) {
+ editor = p_node;
+ skeleton_editor = memnew(Skeleton3DEditor);
+ editor->get_viewport()->add_child(skeleton_editor);
+}
+
+Skeleton3DEditorPlugin::~Skeleton3DEditorPlugin() {}
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
new file mode 100644
index 0000000000..2ba5a817bc
--- /dev/null
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* skeleton_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SKELETON_3D_EDITOR_PLUGIN_H
+#define SKELETON_3D_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/skeleton_3d.h"
+
+class PhysicalBone3D;
+class Joint3D;
+
+class Skeleton3DEditor : public Node {
+ GDCLASS(Skeleton3DEditor, Node);
+
+ enum Menu {
+ MENU_OPTION_CREATE_PHYSICAL_SKELETON
+ };
+
+ struct BoneInfo {
+ PhysicalBone3D *physical_bone;
+ Transform relative_rest; // Relative to skeleton node
+ BoneInfo() :
+ physical_bone(nullptr) {}
+ };
+
+ Skeleton3D *skeleton;
+
+ MenuButton *options;
+
+ void _on_click_option(int p_option);
+
+ friend class Skeleton3DEditorPlugin;
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+ void create_physical_skeleton();
+ PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
+
+public:
+ void edit(Skeleton3D *p_node);
+
+ Skeleton3DEditor();
+ ~Skeleton3DEditor();
+};
+
+class Skeleton3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(Skeleton3DEditorPlugin, EditorPlugin);
+
+ EditorNode *editor;
+ Skeleton3DEditor *skeleton_editor;
+
+public:
+ virtual String get_name() const { return "Skeleton3D"; }
+ virtual bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ Skeleton3DEditorPlugin(EditorNode *p_node);
+ ~Skeleton3DEditorPlugin();
+};
+
+#endif // SKELETON_3D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp
deleted file mode 100644
index 07bd6a0e41..0000000000
--- a/editor/plugins/skeleton_editor_plugin.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*************************************************************************/
-/* skeleton_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "skeleton_editor_plugin.h"
-
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/physics_body.h"
-#include "scene/3d/physics_joint.h"
-#include "scene/resources/capsule_shape.h"
-#include "scene/resources/sphere_shape.h"
-#include "spatial_editor_plugin.h"
-
-void SkeletonEditor::_on_click_option(int p_option) {
- if (!skeleton) {
- return;
- }
-
- switch (p_option) {
- case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
- create_physical_skeleton();
- } break;
- }
-}
-
-void SkeletonEditor::create_physical_skeleton() {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();
-
- const int bc = skeleton->get_bone_count();
-
- if (!bc) {
- return;
- }
-
- Vector<BoneInfo> bones_infos;
- bones_infos.resize(bc);
-
- for (int bone_id = 0; bc > bone_id; ++bone_id) {
-
- const int parent = skeleton->get_bone_parent(bone_id);
-
- if (parent < 0) {
-
- bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
-
- } else {
-
- const int parent_parent = skeleton->get_bone_parent(parent);
-
- bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
-
- /// create physical bone on parent
- if (!bones_infos[parent].physical_bone) {
-
- bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);
-
- ur->create_action(TTR("Create physical bones"));
- ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
- ur->add_do_reference(bones_infos[parent].physical_bone);
- ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
- ur->commit_action();
-
- bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent));
- bones_infos[parent].physical_bone->set_owner(owner);
- bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner
-
- /// Create joint between parent of parent
- if (-1 != parent_parent) {
-
- bones_infos[parent].physical_bone->set_joint_type(PhysicalBone::JOINT_TYPE_PIN);
- }
- }
- }
- }
-}
-
-PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {
-
- const Transform child_rest = skeleton->get_bone_rest(bone_child_id);
-
- const real_t half_height(child_rest.origin.length() * 0.5);
- const real_t radius(half_height * 0.2);
-
- CapsuleShape *bone_shape_capsule = memnew(CapsuleShape);
- bone_shape_capsule->set_height((half_height - radius) * 2);
- bone_shape_capsule->set_radius(radius);
-
- CollisionShape *bone_shape = memnew(CollisionShape);
- bone_shape->set_shape(bone_shape_capsule);
-
- Transform body_transform;
- body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin, Vector3(0, 1, 0));
- body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height));
-
- Transform joint_transform;
- joint_transform.origin = Vector3(0, 0, half_height);
-
- PhysicalBone *physical_bone = memnew(PhysicalBone);
- physical_bone->add_child(bone_shape);
- physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id));
- physical_bone->set_body_offset(body_transform);
- physical_bone->set_joint_offset(joint_transform);
- return physical_bone;
-}
-
-void SkeletonEditor::edit(Skeleton *p_node) {
-
- skeleton = p_node;
-}
-
-void SkeletonEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- get_tree()->connect("node_removed", callable_mp(this, &SkeletonEditor::_node_removed));
- }
-}
-
-void SkeletonEditor::_node_removed(Node *p_node) {
-
- if (p_node == skeleton) {
- skeleton = NULL;
- options->hide();
- }
-}
-
-void SkeletonEditor::_bind_methods() {
-}
-
-SkeletonEditor::SkeletonEditor() {
- skeleton = NULL;
- options = memnew(MenuButton);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
-
- options->set_text(TTR("Skeleton"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons"));
-
- options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);
-
- options->get_popup()->connect("id_pressed", callable_mp(this, &SkeletonEditor::_on_click_option));
- options->hide();
-}
-
-SkeletonEditor::~SkeletonEditor() {}
-
-void SkeletonEditorPlugin::edit(Object *p_object) {
- skeleton_editor->edit(Object::cast_to<Skeleton>(p_object));
-}
-
-bool SkeletonEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("Skeleton");
-}
-
-void SkeletonEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- skeleton_editor->options->show();
- } else {
-
- skeleton_editor->options->hide();
- skeleton_editor->edit(NULL);
- }
-}
-
-SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- skeleton_editor = memnew(SkeletonEditor);
- editor->get_viewport()->add_child(skeleton_editor);
-}
-
-SkeletonEditorPlugin::~SkeletonEditorPlugin() {}
diff --git a/editor/plugins/skeleton_editor_plugin.h b/editor/plugins/skeleton_editor_plugin.h
deleted file mode 100644
index 1dce6d12ed..0000000000
--- a/editor/plugins/skeleton_editor_plugin.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************************************/
-/* skeleton_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SKELETON_EDITOR_PLUGIN_H
-#define SKELETON_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/3d/skeleton.h"
-
-class PhysicalBone;
-class Joint;
-
-class SkeletonEditor : public Node {
- GDCLASS(SkeletonEditor, Node);
-
- enum Menu {
- MENU_OPTION_CREATE_PHYSICAL_SKELETON
- };
-
- struct BoneInfo {
- PhysicalBone *physical_bone;
- Transform relative_rest; // Relative to skeleton node
- BoneInfo() :
- physical_bone(NULL) {}
- };
-
- Skeleton *skeleton;
-
- MenuButton *options;
-
- void _on_click_option(int p_option);
-
- friend class SkeletonEditorPlugin;
-
-protected:
- void _notification(int p_what);
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
- void create_physical_skeleton();
- PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
-
-public:
- void edit(Skeleton *p_node);
-
- SkeletonEditor();
- ~SkeletonEditor();
-};
-
-class SkeletonEditorPlugin : public EditorPlugin {
-
- GDCLASS(SkeletonEditorPlugin, EditorPlugin);
-
- EditorNode *editor;
- SkeletonEditor *skeleton_editor;
-
-public:
- virtual String get_name() const { return "Skeleton"; }
- virtual bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- SkeletonEditorPlugin(EditorNode *p_node);
- ~SkeletonEditorPlugin();
-};
-
-#endif // SKELETON_EDITOR_PLUGIN_H
diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
new file mode 100644
index 0000000000..a22534eac0
--- /dev/null
+++ b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* skeleton_ik_3d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "skeleton_ik_3d_editor_plugin.h"
+
+#include "scene/3d/skeleton_ik_3d.h"
+
+void SkeletonIK3DEditorPlugin::_play() {
+
+ if (!skeleton_ik)
+ return;
+
+ if (!skeleton_ik->get_parent_skeleton())
+ return;
+
+ if (play_btn->is_pressed()) {
+ skeleton_ik->start();
+ } else {
+ skeleton_ik->stop();
+ skeleton_ik->get_parent_skeleton()->clear_bones_global_pose_override();
+ }
+}
+
+void SkeletonIK3DEditorPlugin::edit(Object *p_object) {
+
+ if (p_object != skeleton_ik) {
+ if (skeleton_ik) {
+ play_btn->set_pressed(false);
+ _play();
+ }
+ }
+
+ SkeletonIK3D *s = Object::cast_to<SkeletonIK3D>(p_object);
+ if (!s)
+ return;
+
+ skeleton_ik = s;
+}
+
+bool SkeletonIK3DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("SkeletonIK3D");
+}
+
+void SkeletonIK3DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible)
+ play_btn->show();
+ else
+ play_btn->hide();
+}
+
+void SkeletonIK3DEditorPlugin::_bind_methods() {
+}
+
+SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ play_btn = memnew(Button);
+ play_btn->set_icon(editor->get_gui_base()->get_theme_icon("Play", "EditorIcons"));
+ play_btn->set_text(TTR("Play IK"));
+ play_btn->set_toggle_mode(true);
+ play_btn->hide();
+ play_btn->connect("pressed", callable_mp(this, &SkeletonIK3DEditorPlugin::_play));
+ add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, play_btn);
+ skeleton_ik = nullptr;
+}
+
+SkeletonIK3DEditorPlugin::~SkeletonIK3DEditorPlugin() {}
diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.h b/editor/plugins/skeleton_ik_3d_editor_plugin.h
new file mode 100644
index 0000000000..88472a2963
--- /dev/null
+++ b/editor/plugins/skeleton_ik_3d_editor_plugin.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* skeleton_ik_3d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SKELETON_IK_3D_EDITOR_PLUGIN_H
+#define SKELETON_IK_3D_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+
+class SkeletonIK3D;
+
+class SkeletonIK3DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(SkeletonIK3DEditorPlugin, EditorPlugin);
+
+ SkeletonIK3D *skeleton_ik;
+
+ Button *play_btn;
+ EditorNode *editor;
+
+ void _play();
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_name() const { return "SkeletonIK3D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ SkeletonIK3DEditorPlugin(EditorNode *p_node);
+ ~SkeletonIK3DEditorPlugin();
+};
+
+#endif // SKELETON_IK_3D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/skeleton_ik_editor_plugin.cpp b/editor/plugins/skeleton_ik_editor_plugin.cpp
deleted file mode 100644
index b031bd71d3..0000000000
--- a/editor/plugins/skeleton_ik_editor_plugin.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*************************************************************************/
-/* skeleton_ik_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "skeleton_ik_editor_plugin.h"
-
-#include "scene/animation/skeleton_ik.h"
-
-void SkeletonIKEditorPlugin::_play() {
-
- if (!skeleton_ik)
- return;
-
- if (!skeleton_ik->get_parent_skeleton())
- return;
-
- if (play_btn->is_pressed()) {
- skeleton_ik->start();
- } else {
- skeleton_ik->stop();
-
- for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) {
- skeleton_ik->get_parent_skeleton()->set_bone_global_pose_override(i, Transform(), 0);
- }
- }
-}
-
-void SkeletonIKEditorPlugin::edit(Object *p_object) {
-
- if (p_object != skeleton_ik) {
- if (skeleton_ik) {
- play_btn->set_pressed(false);
- _play();
- }
- }
-
- SkeletonIK *s = Object::cast_to<SkeletonIK>(p_object);
- if (!s)
- return;
-
- skeleton_ik = s;
-}
-
-bool SkeletonIKEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("SkeletonIK");
-}
-
-void SkeletonIKEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible)
- play_btn->show();
- else
- play_btn->hide();
-}
-
-void SkeletonIKEditorPlugin::_bind_methods() {
-}
-
-SkeletonIKEditorPlugin::SkeletonIKEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- play_btn = memnew(Button);
- play_btn->set_icon(editor->get_gui_base()->get_icon("Play", "EditorIcons"));
- play_btn->set_text(TTR("Play IK"));
- play_btn->set_toggle_mode(true);
- play_btn->hide();
- play_btn->connect("pressed", callable_mp(this, &SkeletonIKEditorPlugin::_play));
- add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, play_btn);
- skeleton_ik = NULL;
-}
-
-SkeletonIKEditorPlugin::~SkeletonIKEditorPlugin() {}
diff --git a/editor/plugins/skeleton_ik_editor_plugin.h b/editor/plugins/skeleton_ik_editor_plugin.h
deleted file mode 100644
index 814eb8ff5b..0000000000
--- a/editor/plugins/skeleton_ik_editor_plugin.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*************************************************************************/
-/* skeleton_ik_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SKELETON_IK_EDITOR_PLUGIN_H
-#define SKELETON_IK_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-
-class SkeletonIK;
-
-class SkeletonIKEditorPlugin : public EditorPlugin {
-
- GDCLASS(SkeletonIKEditorPlugin, EditorPlugin);
-
- SkeletonIK *skeleton_ik;
-
- Button *play_btn;
- EditorNode *editor;
-
- void _play();
-
-protected:
- static void _bind_methods();
-
-public:
- virtual String get_name() const { return "SkeletonIK"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- SkeletonIKEditorPlugin(EditorNode *p_node);
- ~SkeletonIKEditorPlugin();
-};
-
-#endif // SKELETON_IK_EDITOR_PLUGIN_H
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
deleted file mode 100644
index a71cb50db4..0000000000
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ /dev/null
@@ -1,6761 +0,0 @@
-/*************************************************************************/
-/* spatial_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "spatial_editor_plugin.h"
-
-#include "core/math/camera_matrix.h"
-#include "core/os/input.h"
-#include "core/os/keyboard.h"
-#include "core/print_string.h"
-#include "core/project_settings.h"
-#include "core/sort_array.h"
-#include "editor/debugger/editor_debugger_node.h"
-#include "editor/editor_node.h"
-#include "editor/editor_scale.h"
-#include "editor/editor_settings.h"
-#include "editor/plugins/animation_player_editor_plugin.h"
-#include "editor/plugins/script_editor_plugin.h"
-#include "editor/spatial_editor_gizmos.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/physics_body.h"
-#include "scene/3d/visual_instance.h"
-#include "scene/gui/viewport_container.h"
-#include "scene/resources/packed_scene.h"
-#include "scene/resources/surface_tool.h"
-
-#define DISTANCE_DEFAULT 4
-
-#define GIZMO_ARROW_SIZE 0.35
-#define GIZMO_RING_HALF_WIDTH 0.1
-#define GIZMO_SCALE_DEFAULT 0.15
-#define GIZMO_PLANE_SIZE 0.2
-#define GIZMO_PLANE_DST 0.3
-#define GIZMO_CIRCLE_SIZE 1.1
-#define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
-#define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
-
-#define ZOOM_MIN_DISTANCE 0.001
-#define ZOOM_MULTIPLIER 1.08
-#define ZOOM_INDICATOR_DELAY_S 1.5
-
-#define FREELOOK_MIN_SPEED 0.01
-#define FREELOOK_SPEED_MULTIPLIER 1.08
-
-#define MIN_Z 0.01
-#define MAX_Z 1000000.0
-
-#define MIN_FOV 0.01
-#define MAX_FOV 179
-
-void ViewportRotationControl::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
- axis_menu_options.clear();
- axis_menu_options.push_back(SpatialEditorViewport::VIEW_RIGHT);
- axis_menu_options.push_back(SpatialEditorViewport::VIEW_TOP);
- axis_menu_options.push_back(SpatialEditorViewport::VIEW_FRONT);
- axis_menu_options.push_back(SpatialEditorViewport::VIEW_LEFT);
- axis_menu_options.push_back(SpatialEditorViewport::VIEW_BOTTOM);
- axis_menu_options.push_back(SpatialEditorViewport::VIEW_REAR);
-
- axis_colors.clear();
- axis_colors.push_back(get_color("axis_x_color", "Editor"));
- axis_colors.push_back(get_color("axis_y_color", "Editor"));
- axis_colors.push_back(get_color("axis_z_color", "Editor"));
- update();
-
- if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) {
- connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited));
- }
- }
-
- if (p_what == NOTIFICATION_DRAW && viewport != nullptr) {
- _draw();
- }
-}
-
-void ViewportRotationControl::_draw() {
- Vector2i center = get_size() / 2.0;
- float radius = get_size().x / 2.0;
-
- if (focused_axis > -2 || orbiting) {
- draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25));
- }
-
- Vector<Axis2D> axis_to_draw;
- _get_sorted_axis(axis_to_draw);
- for (int i = 0; i < axis_to_draw.size(); ++i) {
- _draw_axis(axis_to_draw[i]);
- }
-}
-
-void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) {
- bool focused = focused_axis == p_axis.axis;
- bool positive = p_axis.axis < 3;
- bool front = (Math::abs(p_axis.z_axis) <= 0.001 && positive) || p_axis.z_axis > 0.001;
- int direction = p_axis.axis % 3;
-
- Color axis_color = axis_colors[direction];
-
- if (!front) {
- axis_color = axis_color.darkened(0.4);
- }
- Color c = focused ? Color(0.9, 0.9, 0.9) : axis_color;
-
- if (positive) {
- Vector2i center = get_size() / 2.0;
- draw_line(center, p_axis.screen_point, c, 1.5 * EDSCALE);
- }
-
- if (front) {
- String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z");
- draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c);
- draw_char(get_font("rotation_control", "EditorFonts"), p_axis.screen_point + Vector2i(-4, 5) * EDSCALE, axis_name, "", Color(0.3, 0.3, 0.3));
- } else {
- draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS * (0.55 + (0.2 * (1.0 + p_axis.z_axis))), c);
- }
-}
-
-void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
- Vector2i center = get_size() / 2.0;
- float radius = get_size().x / 2.0;
-
- float axis_radius = radius - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE;
- Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse();
-
- for (int i = 0; i < 3; ++i) {
- Vector3 axis_3d = camera_basis.get_axis(i);
- Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * axis_radius;
-
- if (Math::abs(axis_3d.z) < 1.0) {
- Axis2D pos_axis;
- pos_axis.axis = i;
- pos_axis.screen_point = center + axis_vector;
- pos_axis.z_axis = axis_3d.z;
- r_axis.push_back(pos_axis);
-
- Axis2D neg_axis;
- neg_axis.axis = i + 3;
- neg_axis.screen_point = center - axis_vector;
- neg_axis.z_axis = -axis_3d.z;
- r_axis.push_back(neg_axis);
- } else {
- // Special case when the camera is aligned with one axis
- Axis2D axis;
- axis.axis = i + (axis_3d.z < 0 ? 0 : 3);
- axis.screen_point = center;
- axis.z_axis = 1.0;
- r_axis.push_back(axis);
- }
- }
-
- r_axis.sort_custom<Axis2DCompare>();
-}
-
-void ViewportRotationControl::_gui_input(Ref<InputEvent> p_event) {
- const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
- Vector2 pos = mb->get_position();
- if (mb->is_pressed()) {
- if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
- orbiting = true;
- }
- } else {
- if (focused_axis > -1) {
- viewport->_menu_option(axis_menu_options[focused_axis]);
- _update_focus();
- }
- orbiting = false;
- }
- }
-
- const Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
- if (orbiting) {
- viewport->_nav_orbit(mm, viewport->_get_warped_mouse_motion(mm));
- focused_axis = -1;
- } else {
- _update_focus();
- }
- }
-}
-
-void ViewportRotationControl::_update_focus() {
- int original_focus = focused_axis;
- focused_axis = -2;
- Vector2 mouse_pos = get_local_mouse_position();
-
- if (mouse_pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
- focused_axis = -1;
- }
-
- Vector<Axis2D> axes;
- _get_sorted_axis(axes);
-
- for (int i = 0; i < axes.size(); i++) {
- const Axis2D &axis = axes[i];
- if (mouse_pos.distance_to(axis.screen_point) < AXIS_CIRCLE_RADIUS) {
- focused_axis = axis.axis;
- }
- }
-
- if (focused_axis != original_focus) {
- update();
- }
-}
-
-void ViewportRotationControl::_on_mouse_exited() {
- focused_axis = -2;
- update();
-}
-
-void ViewportRotationControl::set_viewport(SpatialEditorViewport *p_viewport) {
- viewport = p_viewport;
-}
-
-void ViewportRotationControl::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &ViewportRotationControl::_gui_input);
-}
-
-void SpatialEditorViewport::_update_camera(float p_interp_delta) {
-
- bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
-
- Cursor old_camera_cursor = camera_cursor;
- camera_cursor = cursor;
-
- if (p_interp_delta > 0) {
-
- //-------
- // Perform smoothing
-
- if (is_freelook_active()) {
-
- // Higher inertia should increase "lag" (lerp with factor between 0 and 1)
- // Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1.
- real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
- inertia = MAX(0.001, inertia);
- real_t factor = (1.0 / inertia) * p_interp_delta;
-
- // We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
- camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1));
-
- float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- orbit_inertia = MAX(0.0001, orbit_inertia);
- camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
- camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
-
- if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) {
- camera_cursor.x_rot = cursor.x_rot;
- }
-
- if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) {
- camera_cursor.y_rot = cursor.y_rot;
- }
-
- Vector3 forward = to_camera_transform(camera_cursor).basis.xform(Vector3(0, 0, -1));
- camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance;
-
- } else {
-
- //when not being manipulated, move softly
- float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
- //when being manipulated, move more quickly
- float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
- float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
-
- float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
-
- //determine if being manipulated
- bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_CONTROL);
-
- float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
- float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
- zoom_inertia = MAX(0.0001, zoom_inertia);
-
- camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
- camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
-
- if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) {
- camera_cursor.x_rot = cursor.x_rot;
- }
-
- if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) {
- camera_cursor.y_rot = cursor.y_rot;
- }
-
- camera_cursor.pos = old_camera_cursor.pos.linear_interpolate(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia)));
- camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia)));
- }
- }
-
- //-------
- // Apply camera transform
-
- float tolerance = 0.001;
- bool equal = true;
- if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) {
- equal = false;
- }
-
- if (equal && old_camera_cursor.pos.distance_squared_to(camera_cursor.pos) > tolerance * tolerance) {
- equal = false;
- }
-
- if (equal && Math::abs(old_camera_cursor.distance - camera_cursor.distance) > tolerance) {
- equal = false;
- }
-
- if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) {
-
- camera->set_global_transform(to_camera_transform(camera_cursor));
-
- if (orthogonal) {
- float half_fov = Math::deg2rad(get_fov()) / 2.0;
- float height = 2.0 * cursor.distance * Math::tan(half_fov);
- camera->set_orthogonal(height, 0.1, 8192);
- } else {
- camera->set_perspective(get_fov(), get_znear(), get_zfar());
- }
-
- update_transform_gizmo_view();
- rotation_control->update();
- }
-}
-
-Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
- Transform camera_transform;
- camera_transform.translate(p_cursor.pos);
- camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot);
- camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot);
-
- if (orthogonal)
- camera_transform.translate(0, 0, 4096);
- else
- camera_transform.translate(0, 0, p_cursor.distance);
-
- return camera_transform;
-}
-
-int SpatialEditorViewport::get_selected_count() const {
-
- Map<Node *, Object *> &selection = editor_selection->get_selection();
-
- int count = 0;
-
- for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->key());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- count++;
- }
-
- return count;
-}
-
-float SpatialEditorViewport::get_znear() const {
-
- return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z);
-}
-float SpatialEditorViewport::get_zfar() const {
-
- return CLAMP(spatial_editor->get_zfar(), MIN_Z, MAX_Z);
-}
-float SpatialEditorViewport::get_fov() const {
-
- return CLAMP(spatial_editor->get_fov(), MIN_FOV, MAX_FOV);
-}
-
-Transform SpatialEditorViewport::_get_camera_transform() const {
-
- return camera->get_global_transform();
-}
-
-Vector3 SpatialEditorViewport::_get_camera_position() const {
-
- return _get_camera_transform().origin;
-}
-
-Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) {
-
- return camera->unproject_position(p_point) * viewport_container->get_stretch_shrink();
-}
-
-Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
-
- return camera->project_ray_origin(p_pos / viewport_container->get_stretch_shrink());
-}
-
-Vector3 SpatialEditorViewport::_get_camera_normal() const {
-
- return -_get_camera_transform().basis.get_axis(2);
-}
-
-Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) const {
-
- return camera->project_ray_normal(p_pos / viewport_container->get_stretch_shrink());
-}
-
-void SpatialEditorViewport::_clear_selected() {
-
- editor_selection->clear();
-}
-
-void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single, bool p_allow_locked) {
-
- if (clicked.is_null())
- return;
-
- Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked));
- Spatial *selected = Object::cast_to<Spatial>(node);
- if (!selected)
- return;
-
- if (!p_allow_locked) {
- // Replace the node by the group if grouped
- while (node && node != editor->get_edited_scene()->get_parent()) {
- Spatial *selected_tmp = Object::cast_to<Spatial>(node);
- if (selected_tmp && node->has_meta("_edit_group_")) {
- selected = selected_tmp;
- }
- node = node->get_parent();
- }
- }
-
- if (p_allow_locked || !_is_node_locked(selected)) {
- _select(selected, clicked_wants_append, true);
- }
-}
-
-void SpatialEditorViewport::_select(Node *p_node, bool p_append, bool p_single) {
-
- if (!p_append) {
- editor_selection->clear();
- }
-
- if (editor_selection->is_selected(p_node)) {
- //erase
- editor_selection->remove_node(p_node);
- } else {
-
- editor_selection->add_node(p_node);
- }
-
- if (p_single) {
- if (Engine::get_singleton()->is_editor_hint())
- editor->call("edit_node", p_node);
- }
-}
-
-ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) {
-
- if (r_gizmo_handle)
- *r_gizmo_handle = -1;
-
- Vector3 ray = _get_ray(p_pos);
- Vector3 pos = _get_ray_pos(p_pos);
- Vector2 shrinked_pos = p_pos / viewport_container->get_stretch_shrink();
-
- Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
- Set<Ref<EditorSpatialGizmo> > found_gizmos;
-
- Node *edited_scene = get_tree()->get_edited_scene_root();
- ObjectID closest;
- Node *item = NULL;
- float closest_dist = 1e20;
- int selected_handle = -1;
-
- for (int i = 0; i < instances.size(); i++) {
-
- Spatial *spat = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i]));
-
- if (!spat)
- continue;
-
- Ref<EditorSpatialGizmo> seg = spat->get_gizmo();
-
- if ((!seg.is_valid()) || found_gizmos.has(seg)) {
- continue;
- }
-
- found_gizmos.insert(seg);
- Vector3 point;
- Vector3 normal;
-
- int handle = -1;
- bool inters = seg->intersect_ray(camera, shrinked_pos, point, normal, &handle, p_alt_select);
-
- if (!inters)
- continue;
-
- float dist = pos.distance_to(point);
-
- if (dist < 0)
- continue;
-
- 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();
- }
-
- closest = item->get_instance_id();
- closest_dist = dist;
- selected_handle = handle;
- }
- }
-
- if (!item)
- return ObjectID();
-
- if (!editor_selection->is_selected(item) || (r_gizmo_handle && selected_handle >= 0)) {
-
- if (r_gizmo_handle)
- *r_gizmo_handle = selected_handle;
- }
-
- return closest;
-}
-
-void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) {
-
- Vector3 ray = _get_ray(p_pos);
- Vector3 pos = _get_ray_pos(p_pos);
-
- Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
- Set<Ref<EditorSpatialGizmo> > found_gizmos;
-
- r_includes_current = false;
-
- for (int i = 0; i < instances.size(); i++) {
-
- Spatial *spat = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i]));
-
- if (!spat)
- continue;
-
- Ref<EditorSpatialGizmo> seg = spat->get_gizmo();
-
- if (!seg.is_valid())
- continue;
-
- if (found_gizmos.has(seg))
- continue;
-
- found_gizmos.insert(seg);
- Vector3 point;
- Vector3 normal;
-
- int handle = -1;
- bool inters = seg->intersect_ray(camera, p_pos, point, normal, NULL, p_alt_select);
-
- if (!inters)
- continue;
-
- float dist = pos.distance_to(point);
-
- if (dist < 0)
- continue;
-
- if (editor_selection->is_selected(spat))
- r_includes_current = true;
-
- _RayResult res;
- res.item = spat;
- res.depth = dist;
- res.handle = handle;
- results.push_back(res);
- }
-
- if (results.empty())
- return;
-
- results.sort();
-}
-
-Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
-
- CameraMatrix cm;
- if (orthogonal) {
- cm.set_orthogonal(camera->get_size(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
- } else {
- cm.set_perspective(get_fov(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
- }
- Vector2 screen_he = cm.get_viewport_half_extents();
-
- Transform camera_transform;
- camera_transform.translate(cursor.pos);
- camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
- camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
- camera_transform.translate(0, 0, cursor.distance);
-
- return camera_transform.xform(Vector3(((p_vector3.x / get_size().width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / get_size().height)) * 2.0 - 1.0) * screen_he.y, -(get_znear() + p_vector3.z)));
-}
-
-void SpatialEditorViewport::_select_region() {
-
- if (cursor.region_begin == cursor.region_end)
- return; //nothing really
-
- float z_offset = MAX(0.0, 5.0 - get_znear());
-
- Vector3 box[4] = {
- Vector3(
- MIN(cursor.region_begin.x, cursor.region_end.x),
- MIN(cursor.region_begin.y, cursor.region_end.y),
- z_offset),
- Vector3(
- MAX(cursor.region_begin.x, cursor.region_end.x),
- MIN(cursor.region_begin.y, cursor.region_end.y),
- z_offset),
- Vector3(
- MAX(cursor.region_begin.x, cursor.region_end.x),
- MAX(cursor.region_begin.y, cursor.region_end.y),
- z_offset),
- Vector3(
- MIN(cursor.region_begin.x, cursor.region_end.x),
- MAX(cursor.region_begin.y, cursor.region_end.y),
- z_offset)
- };
-
- Vector<Plane> frustum;
-
- Vector3 cam_pos = _get_camera_position();
-
- for (int i = 0; i < 4; i++) {
-
- Vector3 a = _get_screen_to_space(box[i]);
- Vector3 b = _get_screen_to_space(box[(i + 1) % 4]);
- if (orthogonal) {
- frustum.push_back(Plane(a, (a - b).normalized()));
- } else {
- frustum.push_back(Plane(a, b, cam_pos));
- }
- }
-
- if (!orthogonal) {
- Plane near(cam_pos, -_get_camera_normal());
- near.d -= get_znear();
-
- frustum.push_back(near);
-
- Plane far = -near;
- far.d += get_zfar();
-
- frustum.push_back(far);
- }
-
- Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
- Vector<Node *> selected;
-
- Node *edited_scene = get_tree()->get_edited_scene_root();
-
- for (int i = 0; i < instances.size(); i++) {
-
- Spatial *sp = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i]));
- if (!sp || _is_node_locked(sp))
- continue;
-
- 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();
- }
-
- // Replace the node by the group if grouped
- if (item->is_class("Spatial")) {
- Spatial *sel = Object::cast_to<Spatial>(item);
- while (item && item != editor->get_edited_scene()->get_parent()) {
- Spatial *selected_tmp = Object::cast_to<Spatial>(item);
- if (selected_tmp && item->has_meta("_edit_group_")) {
- sel = selected_tmp;
- }
- item = item->get_parent();
- }
- item = sel;
- }
-
- if (selected.find(item) != -1) continue;
-
- if (_is_node_locked(item)) continue;
-
- Ref<EditorSpatialGizmo> seg = sp->get_gizmo();
-
- if (!seg.is_valid())
- continue;
-
- if (seg->intersect_frustum(camera, frustum)) {
- selected.push_back(item);
- }
- }
-
- bool single = selected.size() == 1;
- for (int i = 0; i < selected.size(); i++) {
- _select(selected[i], true, single);
- }
-}
-
-void SpatialEditorViewport::_update_name() {
-
- String view_mode = orthogonal ? TTR("Orthogonal") : TTR("Perspective");
-
- if (auto_orthogonal) {
- view_mode += " [auto]";
- }
-
- if (name != "")
- view_menu->set_text(name + " " + view_mode);
- else
- view_menu->set_text(view_mode);
-
- view_menu->set_size(Vector2(0, 0)); // resets the button size
-}
-
-void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
-
- _edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y));
- _edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y));
- _edit.plane = TRANSFORM_VIEW;
- spatial_editor->update_transform_gizmo();
- _edit.center = spatial_editor->get_gizmo_transform().origin;
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- se->original = se->sp->get_global_gizmo_transform();
- se->original_local = se->sp->get_local_gizmo_transform();
- }
-}
-
-static int _get_key_modifier_setting(const String &p_property) {
-
- switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
-
- case 0: return 0;
- case 1: return KEY_SHIFT;
- case 2: return KEY_ALT;
- case 3: return KEY_META;
- case 4: return KEY_CONTROL;
- }
- return 0;
-}
-
-static int _get_key_modifier(Ref<InputEventWithModifiers> e) {
- if (e->get_shift())
- return KEY_SHIFT;
- if (e->get_alt())
- return KEY_ALT;
- if (e->get_control())
- return KEY_CONTROL;
- if (e->get_metakey())
- return KEY_META;
- return 0;
-}
-
-bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) {
-
- if (!spatial_editor->is_gizmo_visible())
- return false;
- if (get_selected_count() == 0) {
- if (p_highlight_only)
- spatial_editor->select_gizmo_highlight_axis(-1);
- return false;
- }
-
- Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
- Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
-
- Transform gt = spatial_editor->get_gizmo_transform();
- float gs = gizmo_scale;
-
- if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) {
-
- int col_axis = -1;
- float col_d = 1e20;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
- float grabber_radius = gs * GIZMO_ARROW_SIZE;
-
- Vector3 r;
-
- if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
- float d = r.distance_to(ray_pos);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
- }
- }
- }
-
- bool is_plane_translate = false;
- // plane select
- if (col_axis == -1) {
- col_d = 1e20;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
- Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
-
- Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
-
- Vector3 r;
- Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
-
- if (plane.intersects_ray(ray_pos, ray, &r)) {
-
- float dist = r.distance_to(grabber_pos);
- if (dist < (gs * GIZMO_PLANE_SIZE)) {
-
- float d = ray_pos.distance_to(r);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
-
- is_plane_translate = true;
- }
- }
- }
- }
- }
-
- if (col_axis != -1) {
-
- if (p_highlight_only) {
-
- spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_translate ? 6 : 0));
-
- } else {
- //handle plane translate
- _edit.mode = TRANSFORM_TRANSLATE;
- _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
- _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_translate ? 3 : 0));
- }
- return true;
- }
- }
-
- if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
-
- int col_axis = -1;
- float col_d = 1e20;
-
- for (int i = 0; i < 3; i++) {
-
- Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
- Vector3 r;
- if (!plane.intersects_ray(ray_pos, ray, &r))
- continue;
-
- float dist = r.distance_to(gt.origin);
-
- if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
-
- float d = ray_pos.distance_to(r);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
- }
- }
- }
-
- if (col_axis != -1) {
-
- if (p_highlight_only) {
-
- spatial_editor->select_gizmo_highlight_axis(col_axis + 3);
- } else {
- //handle rotate
- _edit.mode = TRANSFORM_ROTATE;
- _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
- _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
- }
- return true;
- }
- }
-
- if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) {
-
- int col_axis = -1;
- float col_d = 1e20;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET;
- float grabber_radius = gs * GIZMO_ARROW_SIZE;
-
- Vector3 r;
-
- if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
- float d = r.distance_to(ray_pos);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
- }
- }
- }
-
- bool is_plane_scale = false;
- // plane select
- if (col_axis == -1) {
- col_d = 1e20;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
- Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
-
- Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
-
- Vector3 r;
- Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
-
- if (plane.intersects_ray(ray_pos, ray, &r)) {
-
- float dist = r.distance_to(grabber_pos);
- if (dist < (gs * GIZMO_PLANE_SIZE)) {
-
- float d = ray_pos.distance_to(r);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
-
- is_plane_scale = true;
- }
- }
- }
- }
- }
-
- if (col_axis != -1) {
-
- if (p_highlight_only) {
-
- spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9));
-
- } else {
- //handle scale
- _edit.mode = TRANSFORM_SCALE;
- _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
- _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0));
- }
- return true;
- }
- }
-
- if (p_highlight_only)
- spatial_editor->select_gizmo_highlight_axis(-1);
-
- return false;
-}
-
-void SpatialEditorViewport::_surface_mouse_enter() {
-
- if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
- surface->grab_focus();
-}
-
-void SpatialEditorViewport::_surface_mouse_exit() {
-
- _remove_preview();
-}
-
-void SpatialEditorViewport::_surface_focus_enter() {
-
- view_menu->set_disable_shortcuts(false);
-}
-
-void SpatialEditorViewport::_surface_focus_exit() {
-
- view_menu->set_disable_shortcuts(true);
-}
-bool SpatialEditorViewport ::_is_node_locked(const Node *p_node) {
- return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
-}
-void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
-
- _find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift());
-
- Node *scene = editor->get_edited_scene();
-
- for (int i = 0; i < selection_results.size(); i++) {
- Spatial *item = selection_results[i].item;
- if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
- //invalid result
- selection_results.remove(i);
- i--;
- }
- }
-
- clicked_wants_append = b->get_shift();
-
- if (selection_results.size() == 1) {
-
- clicked = selection_results[0].item->get_instance_id();
- selection_results.clear();
-
- if (clicked.is_valid()) {
- _select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != SpatialEditor::TOOL_MODE_LIST_SELECT);
- clicked = ObjectID();
- }
-
- } else if (!selection_results.empty()) {
-
- NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
- StringName root_name = root_path.get_name(root_path.get_name_count() - 1);
-
- for (int i = 0; i < selection_results.size(); i++) {
-
- Spatial *spat = selection_results[i].item;
-
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node");
-
- String node_path = "/" + root_name + "/" + root_path.rel_path_to(spat->get_path());
-
- int locked = 0;
- if (_is_node_locked(spat)) {
- locked = 1;
- } else {
- Node *ed_scene = editor->get_edited_scene();
- Node *node = spat;
-
- while (node && node != ed_scene->get_parent()) {
- Spatial *selected_tmp = Object::cast_to<Spatial>(node);
- if (selected_tmp && node->has_meta("_edit_group_")) {
- locked = 2;
- }
- node = node->get_parent();
- }
- }
-
- String suffix = String();
- if (locked == 1) {
- suffix = " (" + TTR("Locked") + ")";
- } else if (locked == 2) {
- suffix = " (" + TTR("Grouped") + ")";
- }
- selection_menu->add_item((String)spat->get_name() + suffix);
- selection_menu->set_item_icon(i, icon);
- selection_menu->set_item_metadata(i, node_path);
- selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path);
- }
-
- selection_menu->set_global_position(b->get_global_position());
- selection_menu->popup();
- }
-}
-
-void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
-
- if (previewing)
- return; //do NONE
-
- {
- EditorNode *en = editor;
- EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
- if (!force_input_forwarding_list->empty()) {
- bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
- if (discard)
- return;
- }
- }
- {
- EditorNode *en = editor;
- EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
- if (!over_plugin_list->empty()) {
- bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
- if (discard)
- return;
- }
- }
-
- Ref<InputEventMouseButton> b = p_event;
-
- if (b.is_valid()) {
- emit_signal("clicked", this);
-
- float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor();
- switch (b->get_button_index()) {
-
- case 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: {
- if (is_freelook_active())
- scale_freelook_speed(1.0 / zoom_factor);
- else
- scale_cursor_distance(zoom_factor);
- } break;
-
- case 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()) {
- //restore
- _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true);
- _edit.gizmo = Ref<EditorSpatialGizmo>();
- }
-
- if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) {
-
- if (b->get_alt()) {
-
- if (nav_scheme == NAVIGATION_MAYA)
- break;
-
- _list_select(b);
- return;
- }
- }
-
- if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) {
- //cancel motion
- _edit.mode = TRANSFORM_NONE;
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- sp->set_global_transform(se->original);
- }
- surface->update();
- set_message(TTR("Transform Aborted."), 3);
- }
-
- if (b->is_pressed()) {
- const int mod = _get_key_modifier(b);
- if (!orthogonal) {
- if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
- set_freelook_active(true);
- }
- }
- } else {
- set_freelook_active(false);
- }
-
- if (freelook_active && !surface->has_focus()) {
- // Focus usually doesn't trigger on right-click, but in case of freelook it should,
- // otherwise using keyboard navigation would misbehave
- surface->grab_focus();
- }
-
- } break;
- case BUTTON_MIDDLE: {
-
- if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) {
-
- switch (_edit.plane) {
-
- case TRANSFORM_VIEW: {
-
- _edit.plane = TRANSFORM_X_AXIS;
- set_message(TTR("X-Axis Transform."), 2);
- name = "";
- _update_name();
- } break;
- case TRANSFORM_X_AXIS: {
-
- _edit.plane = TRANSFORM_Y_AXIS;
- set_message(TTR("Y-Axis Transform."), 2);
-
- } break;
- case TRANSFORM_Y_AXIS: {
-
- _edit.plane = TRANSFORM_Z_AXIS;
- set_message(TTR("Z-Axis Transform."), 2);
-
- } break;
- case TRANSFORM_Z_AXIS: {
-
- _edit.plane = TRANSFORM_VIEW;
- set_message(TTR("View Plane Transform."), 2);
-
- } break;
- case TRANSFORM_YZ:
- case TRANSFORM_XZ:
- case TRANSFORM_XY: {
- } break;
- }
- }
- } break;
- case 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()) {
- break;
- }
-
- if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_LIST_SELECT) {
- _list_select(b);
- break;
- }
-
- _edit.mouse_pos = b->get_position();
- _edit.snap = spatial_editor->is_snap_enabled();
- _edit.mode = TRANSFORM_NONE;
-
- //gizmo has priority over everything
-
- bool can_select_gizmos = true;
-
- {
- int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
- can_select_gizmos = view_menu->get_popup()->is_item_checked(idx);
- }
-
- if (can_select_gizmos && spatial_editor->get_selected()) {
-
- Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo();
- if (seg.is_valid()) {
- int handle = -1;
- Vector3 point;
- Vector3 normal;
- bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b->get_shift());
- if (inters && handle != -1) {
-
- _edit.gizmo = seg;
- _edit.gizmo_handle = handle;
- _edit.gizmo_initial_value = seg->get_handle_value(handle);
- break;
- }
- }
- }
-
- if (_gizmo_select(_edit.mouse_pos))
- break;
-
- clicked = ObjectID();
- clicked_includes_current = false;
-
- if ((spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
-
- /* HANDLE ROTATION */
- if (get_selected_count() == 0)
- break; //bye
- //handle rotate
- _edit.mode = TRANSFORM_ROTATE;
- _compute_edit(b->get_position());
- break;
- }
-
- if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) {
-
- if (get_selected_count() == 0)
- break; //bye
- //handle translate
- _edit.mode = TRANSFORM_TRANSLATE;
- _compute_edit(b->get_position());
- break;
- }
-
- if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) {
-
- if (get_selected_count() == 0)
- break; //bye
- //handle scale
- _edit.mode = TRANSFORM_SCALE;
- _compute_edit(b->get_position());
- break;
- }
-
- // todo scale
-
- int gizmo_handle = -1;
-
- clicked = _select_ray(b->get_position(), b->get_shift(), clicked_includes_current, &gizmo_handle, b->get_shift());
-
- //clicking is always deferred to either move or release
-
- clicked_wants_append = b->get_shift();
-
- if (clicked.is_null()) {
-
- if (!clicked_wants_append)
- _clear_selected();
-
- //default to regionselect
- cursor.region_select = true;
- cursor.region_begin = b->get_position();
- cursor.region_end = b->get_position();
- }
-
- if (clicked.is_valid() && gizmo_handle >= 0) {
-
- Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked));
- if (spa) {
-
- Ref<EditorSpatialGizmo> seg = spa->get_gizmo();
- if (seg.is_valid()) {
-
- _edit.gizmo = seg;
- _edit.gizmo_handle = gizmo_handle;
- _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle);
- break;
- }
- }
- }
-
- surface->update();
- } else {
-
- if (_edit.gizmo.is_valid()) {
-
- _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false);
- _edit.gizmo = Ref<EditorSpatialGizmo>();
- break;
- }
- if (clicked.is_valid()) {
- _select_clicked(clicked_wants_append, true);
- // Processing was deferred.
- clicked = ObjectID();
- }
-
- if (cursor.region_select) {
-
- if (!clicked_wants_append) _clear_selected();
-
- _select_region();
- cursor.region_select = false;
- surface->update();
- }
-
- if (_edit.mode != TRANSFORM_NONE) {
-
- static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" };
- undo_redo->create_action(_transform_name[_edit.mode]);
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
- undo_redo->add_undo_method(sp, "set_global_transform", se->original);
- }
- undo_redo->commit_action();
- _edit.mode = TRANSFORM_NONE;
- set_message("");
- }
-
- surface->update();
- }
-
- } break;
- }
- }
-
- Ref<InputEventMouseMotion> m = p_event;
-
- if (m.is_valid()) {
-
- _edit.mouse_pos = m->get_position();
-
- if (spatial_editor->get_selected()) {
-
- Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo();
- if (seg.is_valid()) {
-
- int selected_handle = -1;
-
- int handle = -1;
- Vector3 point;
- Vector3 normal;
- bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, false);
- if (inters && handle != -1) {
-
- selected_handle = handle;
- }
-
- if (selected_handle != spatial_editor->get_over_gizmo_handle()) {
- spatial_editor->set_over_gizmo_handle(selected_handle);
- spatial_editor->get_selected()->update_gizmo();
- if (selected_handle != -1)
- spatial_editor->select_gizmo_highlight_axis(-1);
- }
- }
- }
-
- if (spatial_editor->get_over_gizmo_handle() == -1 && !(m->get_button_mask() & 1) && !_edit.gizmo.is_valid()) {
-
- _gizmo_select(_edit.mouse_pos, true);
- }
-
- NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
- NavigationMode nav_mode = NAVIGATION_NONE;
-
- if (_edit.gizmo.is_valid()) {
-
- _edit.gizmo->set_handle(_edit.gizmo_handle, camera, m->get_position());
- Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle);
- String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
- set_message(n + ": " + String(v));
-
- } else if (m->get_button_mask() & 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()) {
- nav_mode = NAVIGATION_PAN;
- } else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_control()) {
- nav_mode = NAVIGATION_ZOOM;
- } else if (nav_scheme == NAVIGATION_MODO && m->get_alt()) {
- nav_mode = NAVIGATION_ORBIT;
- } else {
- if (clicked.is_valid()) {
-
- if (!clicked_includes_current) {
-
- _select_clicked(clicked_wants_append, true);
- // Processing was deferred.
- }
-
- _compute_edit(_edit.mouse_pos);
- clicked = ObjectID();
-
- _edit.mode = TRANSFORM_TRANSLATE;
- }
-
- if (cursor.region_select) {
- cursor.region_end = m->get_position();
- surface->update();
- return;
- }
-
- if (_edit.mode == TRANSFORM_NONE)
- return;
-
- 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");
- int snap_step_decimals = Math::range_step_decimals(snap);
-
- switch (_edit.mode) {
-
- case TRANSFORM_SCALE: {
-
- Vector3 motion_mask;
- Plane plane;
- bool plane_mv = false;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- motion_mask = Vector3(0, 0, 0);
- plane = Plane(_edit.center, _get_camera_normal());
- break;
- case TRANSFORM_X_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
- break;
- case TRANSFORM_Y_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
- break;
- case TRANSFORM_Z_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
- break;
- case TRANSFORM_YZ:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
- plane_mv = true;
- break;
- case TRANSFORM_XZ:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0);
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
- plane_mv = true;
- break;
- case TRANSFORM_XY:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
- plane_mv = true;
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection))
- break;
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
- break;
-
- Vector3 motion = intersection - click;
- if (_edit.plane != TRANSFORM_VIEW) {
-
- if (!plane_mv) {
-
- motion = motion_mask.dot(motion) * motion_mask;
-
- } else {
-
- // Alternative planar scaling mode
- if (_get_key_modifier(m) != KEY_SHIFT) {
- motion = motion_mask.dot(motion) * motion_mask;
- }
- }
-
- } else {
- float center_click_dist = click.distance_to(_edit.center);
- float center_inters_dist = intersection.distance_to(_edit.center);
- if (center_click_dist == 0)
- break;
-
- float scale = center_inters_dist - center_click_dist;
- motion = Vector3(scale, scale, scale);
- }
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- // Disable local transformation for TRANSFORM_VIEW
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_scale_snap() / 100;
- }
- Vector3 motion_snapped = motion;
- motion_snapped.snap(Vector3(snap, snap, snap));
- // This might not be necessary anymore after issue #288 is solved (in 4.0?).
- set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp) {
- continue;
- }
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- Transform original = se->original;
- Transform original_local = se->original_local;
- Transform base = Transform(Basis(), _edit.center);
- Transform t;
- Vector3 local_scale;
-
- if (local_coords) {
-
- Basis g = original.basis.orthonormalized();
- Vector3 local_motion = g.inverse().xform(motion);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- local_motion.snap(Vector3(snap, snap, snap));
- }
-
- local_scale = original_local.basis.get_scale() * (local_motion + Vector3(1, 1, 1));
-
- // Prevent scaling to 0 it would break the gizmo
- Basis check = original_local.basis;
- check.scale(local_scale);
- if (check.determinant() != 0) {
-
- // Apply scale
- sp->set_scale(local_scale);
- }
-
- } else {
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- motion.snap(Vector3(snap, snap, snap));
- }
-
- Transform r;
- r.basis.scale(motion + Vector3(1, 1, 1));
- t = base * (r * (base.inverse() * original));
-
- // Apply scale
- sp->set_global_transform(t);
- }
- }
-
- surface->update();
-
- } break;
-
- case TRANSFORM_TRANSLATE: {
-
- Vector3 motion_mask;
- Plane plane;
- bool plane_mv = false;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- plane = Plane(_edit.center, _get_camera_normal());
- break;
- case TRANSFORM_X_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
- break;
- case TRANSFORM_Y_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
- break;
- case TRANSFORM_Z_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
- break;
- case TRANSFORM_YZ:
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
- plane_mv = true;
- break;
- case TRANSFORM_XZ:
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
- plane_mv = true;
- break;
- case TRANSFORM_XY:
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
- plane_mv = true;
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection))
- break;
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
- break;
-
- Vector3 motion = intersection - click;
- if (_edit.plane != TRANSFORM_VIEW) {
- if (!plane_mv) {
- motion = motion_mask.dot(motion) * motion_mask;
- }
- }
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- // Disable local transformation for TRANSFORM_VIEW
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_translate_snap();
- }
- Vector3 motion_snapped = motion;
- motion_snapped.snap(Vector3(snap, snap, snap));
- set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp) {
- continue;
- }
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- Transform original = se->original;
- Transform t;
-
- if (local_coords) {
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- Basis g = original.basis.orthonormalized();
- Vector3 local_motion = g.inverse().xform(motion);
- local_motion.snap(Vector3(snap, snap, snap));
-
- motion = g.xform(local_motion);
- }
-
- } else {
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- motion.snap(Vector3(snap, snap, snap));
- }
- }
-
- // Apply translation
- t = original;
- t.origin += motion;
- sp->set_global_transform(t);
- }
-
- surface->update();
-
- } break;
-
- case TRANSFORM_ROTATE: {
-
- Plane plane;
- Vector3 axis;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- plane = Plane(_edit.center, _get_camera_normal());
- break;
- case TRANSFORM_X_AXIS:
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
- axis = Vector3(1, 0, 0);
- break;
- case TRANSFORM_Y_AXIS:
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
- axis = Vector3(0, 1, 0);
- break;
- case TRANSFORM_Z_AXIS:
- plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
- axis = Vector3(0, 0, 1);
- break;
- case TRANSFORM_YZ:
- case TRANSFORM_XZ:
- case TRANSFORM_XY:
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection))
- break;
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
- break;
-
- 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));
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_rotate_snap();
- }
- angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
- angle -= Math::fmod(angle, snap);
- set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
- angle = Math::deg2rad(angle);
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- Transform t;
-
- if (local_coords) {
-
- Transform original_local = se->original_local;
- Basis rot = Basis(axis, angle);
-
- t.basis = original_local.get_basis().orthonormalized() * rot;
- t.origin = original_local.origin;
-
- // Apply rotation
- sp->set_transform(t);
- sp->set_scale(original_local.basis.get_scale()); // re-apply original scale
-
- } else {
-
- Transform original = se->original;
- Transform r;
- Transform base = Transform(Basis(), _edit.center);
-
- r.basis.rotate(plane.normal, angle);
- t = base * r * base.inverse() * original;
-
- // Apply rotation
- sp->set_global_transform(t);
- }
- }
-
- surface->update();
-
- } break;
- default: {
- }
- }
- }
-
- } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) {
-
- if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
- nav_mode = NAVIGATION_ZOOM;
- } else if (freelook_active) {
- nav_mode = NAVIGATION_LOOK;
- } else if (orthogonal) {
- nav_mode = NAVIGATION_PAN;
- }
-
- } else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
-
- 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")) {
- nav_mode = NAVIGATION_ZOOM;
- } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
- // 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())
- 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);
-
- if (mod) {
- 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")) {
- nav_mode = NAVIGATION_ZOOM;
- } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
- // Always allow Alt as a modifier to better support graphic tablets.
- nav_mode = NAVIGATION_ORBIT;
- }
- }
- }
-
- switch (nav_mode) {
- case NAVIGATION_PAN: {
- _nav_pan(m, _get_warped_mouse_motion(m));
-
- } break;
-
- case NAVIGATION_ZOOM: {
- _nav_zoom(m, m->get_relative());
-
- } break;
-
- case NAVIGATION_ORBIT: {
- _nav_orbit(m, _get_warped_mouse_motion(m));
-
- } break;
-
- case NAVIGATION_LOOK: {
- _nav_look(m, _get_warped_mouse_motion(m));
-
- } break;
-
- default: {
- }
- }
- }
-
- Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
- if (magnify_gesture.is_valid()) {
-
- if (is_freelook_active())
- scale_freelook_speed(magnify_gesture->get_factor());
- else
- scale_cursor_distance(1.0 / magnify_gesture->get_factor());
- }
-
- Ref<InputEventPanGesture> pan_gesture = p_event;
- if (pan_gesture.is_valid()) {
-
- NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
- NavigationMode nav_mode = NAVIGATION_NONE;
-
- if (nav_scheme == NAVIGATION_GODOT) {
-
- const int mod = _get_key_modifier(pan_gesture);
-
- 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")) {
- nav_mode = NAVIGATION_ZOOM;
- } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
- // Always allow Alt as a modifier to better support graphic tablets.
- nav_mode = NAVIGATION_ORBIT;
- }
-
- } else if (nav_scheme == NAVIGATION_MAYA) {
- if (pan_gesture->get_alt())
- nav_mode = NAVIGATION_PAN;
- }
-
- switch (nav_mode) {
- case NAVIGATION_PAN: {
- _nav_pan(m, pan_gesture->get_delta());
-
- } break;
-
- case NAVIGATION_ZOOM: {
- _nav_zoom(m, pan_gesture->get_delta());
-
- } break;
-
- case NAVIGATION_ORBIT: {
- _nav_orbit(m, pan_gesture->get_delta());
-
- } break;
-
- case NAVIGATION_LOOK: {
- _nav_look(m, pan_gesture->get_delta());
-
- } break;
-
- default: {
- }
- }
- }
-
- Ref<InputEventKey> k = p_event;
-
- if (k.is_valid()) {
- if (!k->is_pressed())
- return;
-
- if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
- if (_edit.mode != TRANSFORM_NONE) {
- _edit.snap = !_edit.snap;
- }
- }
- if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
- _menu_option(VIEW_BOTTOM);
- }
- if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) {
- _menu_option(VIEW_TOP);
- }
- if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) {
- _menu_option(VIEW_REAR);
- }
- if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) {
- _menu_option(VIEW_FRONT);
- }
- if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) {
- _menu_option(VIEW_LEFT);
- }
- if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) {
- _menu_option(VIEW_RIGHT);
- }
- if (ED_IS_SHORTCUT("spatial_editor/focus_origin", p_event)) {
- _menu_option(VIEW_CENTER_TO_ORIGIN);
- }
- if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) {
- _menu_option(VIEW_CENTER_TO_SELECTION);
- }
- // Orthgonal mode doesn't work in freelook.
- if (!freelook_active && ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
- _menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
- _update_name();
- }
- if (ED_IS_SHORTCUT("spatial_editor/align_transform_with_view", p_event)) {
- _menu_option(VIEW_ALIGN_TRANSFORM_WITH_VIEW);
- }
- if (ED_IS_SHORTCUT("spatial_editor/align_rotation_with_view", p_event)) {
- _menu_option(VIEW_ALIGN_ROTATION_WITH_VIEW);
- }
- if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) {
- if (!get_selected_count() || _edit.mode != TRANSFORM_NONE)
- return;
-
- if (!AnimationPlayerEditor::singleton->get_track_editor()->has_keying()) {
- set_message(TTR("Keying is disabled (no key inserted)."));
- return;
- }
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- spatial_editor->emit_signal("transform_key_request", sp, "", sp->get_transform());
- }
-
- set_message(TTR("Animation Key Inserted."));
- }
-
- // Freelook doesn't work in orthogonal mode.
- if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
- set_freelook_active(!is_freelook_active());
-
- } else if (k->get_keycode() == KEY_ESCAPE) {
- set_freelook_active(false);
- }
-
- if (k->get_keycode() == KEY_SPACE) {
- if (!k->is_pressed()) emit_signal("toggle_maximize_view", this);
- }
- }
-
- // freelook uses most of the useful shortcuts, like save, so its ok
- // to consider freelook active as end of the line for future events.
- if (freelook_active)
- accept_event();
-}
-
-void SpatialEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
-
- const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
-
- real_t pan_speed = 1 / 150.0;
- int pan_speed_modifier = 10;
- if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
- pan_speed *= pan_speed_modifier;
-
- Transform camera_transform;
-
- camera_transform.translate(cursor.pos);
- camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
- camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
- Vector3 translation(-p_relative.x * pan_speed, p_relative.y * pan_speed, 0);
- translation *= cursor.distance / DISTANCE_DEFAULT;
- camera_transform.translate(translation);
- cursor.pos = camera_transform.origin;
-}
-
-void SpatialEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
-
- const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
-
- real_t zoom_speed = 1 / 80.0;
- int zoom_speed_modifier = 10;
- if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
- zoom_speed *= zoom_speed_modifier;
-
- NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
- if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
- if (p_relative.x > 0)
- scale_cursor_distance(1 - p_relative.x * zoom_speed);
- else if (p_relative.x < 0)
- scale_cursor_distance(1.0 / (1 + p_relative.x * zoom_speed));
- } else {
- if (p_relative.y > 0)
- scale_cursor_distance(1 + p_relative.y * zoom_speed);
- else if (p_relative.y < 0)
- scale_cursor_distance(1.0 / (1 - p_relative.y * zoom_speed));
- }
-}
-
-void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
-
- if (lock_rotation) {
- _nav_pan(p_event, p_relative);
- return;
- }
-
- if (orthogonal && auto_orthogonal) {
- _menu_option(VIEW_PERSPECTIVE);
- }
-
- real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
- bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
-
- if (invert_y_axis) {
- cursor.x_rot -= p_relative.y * radians_per_pixel;
- } else {
- cursor.x_rot += p_relative.y * radians_per_pixel;
- }
- cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0)
- cursor.x_rot = Math_PI / 2.0;
- if (cursor.x_rot < -Math_PI / 2.0)
- cursor.x_rot = -Math_PI / 2.0;
- name = "";
- _update_name();
-}
-
-void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
-
- if (orthogonal) {
- _nav_pan(p_event, p_relative);
- return;
- }
-
- if (orthogonal && auto_orthogonal) {
- _menu_option(VIEW_PERSPECTIVE);
- }
-
- real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
- bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
-
- // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
- Transform prev_camera_transform = to_camera_transform(cursor);
-
- if (invert_y_axis) {
- cursor.x_rot -= p_relative.y * radians_per_pixel;
- } else {
- cursor.x_rot += p_relative.y * radians_per_pixel;
- }
- cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0)
- cursor.x_rot = Math_PI / 2.0;
- if (cursor.x_rot < -Math_PI / 2.0)
- cursor.x_rot = -Math_PI / 2.0;
-
- // Look is like the opposite of Orbit: the focus point rotates around the camera
- Transform camera_transform = to_camera_transform(cursor);
- Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
- Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
- Vector3 diff = prev_pos - pos;
- cursor.pos += diff;
-
- name = "";
- _update_name();
-}
-
-void SpatialEditorViewport::set_freelook_active(bool active_now) {
-
- if (!freelook_active && active_now) {
- // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
- cursor = camera_cursor;
-
- // Make sure eye_pos is synced, because freelook referential is eye pos rather than orbit pos
- Vector3 forward = to_camera_transform(cursor).basis.xform(Vector3(0, 0, -1));
- cursor.eye_pos = cursor.pos - cursor.distance * forward;
- // Also sync the camera cursor, otherwise switching to freelook will be trippy if inertia is active
- camera_cursor.eye_pos = cursor.eye_pos;
-
- if (EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_speed_zoom_link")) {
- // Re-adjust freelook speed from the current zoom level
- real_t base_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
- freelook_speed = base_speed * cursor.distance;
- }
-
- // Hide mouse like in an FPS (warping doesn't work)
- OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_CAPTURED);
-
- } else if (freelook_active && !active_now) {
- // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
- cursor = camera_cursor;
-
- // Restore mouse
- OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_VISIBLE);
- }
-
- freelook_active = active_now;
-}
-
-void SpatialEditorViewport::scale_cursor_distance(real_t scale) {
-
- // Prevents zero distance which would short-circuit any scaling
- if (cursor.distance < ZOOM_MIN_DISTANCE)
- cursor.distance = ZOOM_MIN_DISTANCE;
-
- cursor.distance *= scale;
-
- if (cursor.distance < ZOOM_MIN_DISTANCE)
- cursor.distance = ZOOM_MIN_DISTANCE;
-
- zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
- surface->update();
-}
-
-void SpatialEditorViewport::scale_freelook_speed(real_t scale) {
-
- // Prevents zero distance which would short-circuit any scaling
- if (freelook_speed < FREELOOK_MIN_SPEED)
- freelook_speed = FREELOOK_MIN_SPEED;
-
- freelook_speed *= scale;
-
- if (freelook_speed < FREELOOK_MIN_SPEED)
- freelook_speed = FREELOOK_MIN_SPEED;
-
- zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
- surface->update();
-}
-
-Point2i SpatialEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const {
- Point2i relative;
- if (bool(EDITOR_DEF("editors/3d/navigation/warped_mouse_panning", false))) {
- relative = Input::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect());
- } else {
- relative = p_ev_mouse_motion->get_relative();
- }
- return relative;
-}
-
-static bool is_shortcut_pressed(const String &p_path) {
- Ref<ShortCut> shortcut = ED_GET_SHORTCUT(p_path);
- if (shortcut.is_null()) {
- return false;
- }
- InputEventKey *k = Object::cast_to<InputEventKey>(shortcut->get_shortcut().ptr());
- if (k == NULL) {
- return false;
- }
- const Input &input = *Input::get_singleton();
- int keycode = k->get_keycode();
- return input.is_key_pressed(keycode);
-}
-
-void SpatialEditorViewport::_update_freelook(real_t delta) {
-
- if (!is_freelook_active()) {
- return;
- }
-
- const Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1));
- const Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0));
- const Vector3 up = camera->get_transform().basis.xform(Vector3(0, 1, 0));
-
- Vector3 direction;
-
- if (is_shortcut_pressed("spatial_editor/freelook_left")) {
- direction -= right;
- }
- if (is_shortcut_pressed("spatial_editor/freelook_right")) {
- direction += right;
- }
- if (is_shortcut_pressed("spatial_editor/freelook_forward")) {
- direction += forward;
- }
- if (is_shortcut_pressed("spatial_editor/freelook_backwards")) {
- direction -= forward;
- }
- if (is_shortcut_pressed("spatial_editor/freelook_up")) {
- direction += up;
- }
- if (is_shortcut_pressed("spatial_editor/freelook_down")) {
- direction -= up;
- }
-
- real_t speed = freelook_speed;
-
- if (is_shortcut_pressed("spatial_editor/freelook_speed_modifier")) {
- speed *= 3.0;
- }
- if (is_shortcut_pressed("spatial_editor/freelook_slow_modifier")) {
- speed *= 0.333333;
- }
-
- const Vector3 motion = direction * speed * delta;
- cursor.pos += motion;
- cursor.eye_pos += motion;
-}
-
-void SpatialEditorViewport::set_message(String p_message, float p_time) {
-
- message = p_message;
- message_time = p_time;
-}
-
-void SpatialEditorPlugin::edited_scene_changed() {
- for (uint32_t i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) {
- SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(i);
- if (viewport->is_visible()) {
- viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED);
- }
- }
-}
-
-void SpatialEditorViewport::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
-
- bool visible = is_visible_in_tree();
-
- set_process(visible);
-
- if (visible) {
- orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
- _update_name();
- _update_camera(0);
- } else {
- set_freelook_active(false);
- }
- call_deferred("update_transform_gizmo_view");
- rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo"));
- }
-
- if (p_what == NOTIFICATION_RESIZED) {
-
- call_deferred("update_transform_gizmo_view");
- }
-
- if (p_what == NOTIFICATION_READY) {
- // The crosshair icon doesn't depend on the editor theme.
- crosshair->set_texture(get_icon("Crosshair", "EditorIcons"));
- // Set the anchors and margins after changing the icon to ensure it's centered correctly.
- crosshair->set_anchors_and_margins_preset(PRESET_CENTER);
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
-
- real_t delta = get_process_delta_time();
-
- if (zoom_indicator_delay > 0) {
- zoom_indicator_delay -= delta;
- if (zoom_indicator_delay <= 0) {
- surface->update();
- }
- }
-
- _update_freelook(delta);
-
- Node *scene_root = editor->get_scene_tree_dock()->get_editor_data()->get_edited_scene_root();
- if (previewing_cinema && scene_root != NULL) {
- Camera *cam = scene_root->get_viewport()->get_camera();
- if (cam != NULL && cam != previewing) {
- //then switch the viewport's camera to the scene's viewport camera
- if (previewing != NULL) {
- previewing->disconnect("tree_exited", callable_mp(this, &SpatialEditorViewport::_preview_exited_scene));
- }
- previewing = cam;
- previewing->connect("tree_exited", callable_mp(this, &SpatialEditorViewport::_preview_exited_scene));
- VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera());
- surface->update();
- }
- }
-
- _update_camera(delta);
-
- Map<Node *, Object *> &selection = editor_selection->get_selection();
-
- bool changed = false;
- bool exist = false;
-
- for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->key());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- Transform t = sp->get_global_gizmo_transform();
-
- exist = true;
- if (se->last_xform == t)
- continue;
- changed = true;
- se->last_xform = t;
-
- VisualInstance *vi = Object::cast_to<VisualInstance>(sp);
-
- se->aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
-
- t.translate(se->aabb.position);
-
- // apply AABB scaling before item's global transform
- Basis aabb_s;
- aabb_s.scale(se->aabb.size);
- t.basis = t.basis * aabb_s;
-
- VisualServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
- }
-
- if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
- spatial_editor->update_transform_gizmo();
- }
-
- if (message_time > 0) {
-
- if (message != last_message) {
- surface->update();
- last_message = message;
- }
-
- message_time -= get_physics_process_delta_time();
- if (message_time < 0)
- surface->update();
- }
-
- //update shadow atlas if changed
-
- int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size");
- 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_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 != (viewport_container->get_stretch_shrink() > 1)) {
- viewport_container->set_stretch_shrink(shrink ? 2 : 1);
- }
-
- //update msaa if changed
-
- int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa");
- viewport->set_msaa(Viewport::MSAA(msaa_mode));
-
- bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
- info_label->set_visible(show_info);
-
- Camera *current_camera;
-
- if (previewing) {
- current_camera = previewing;
- } else {
- current_camera = camera;
- }
-
- // Display the crosshair only while freelooking. Hide it otherwise,
- // as the crosshair can be distracting.
- crosshair->set_visible(freelook_active);
-
- if (show_info) {
- String text;
- text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n";
- text += "Y: " + rtos(current_camera->get_translation().y).pad_decimals(1) + "\n";
- text += "Z: " + rtos(current_camera->get_translation().z).pad_decimals(1) + "\n";
- text += TTR("Pitch") + ": " + itos(Math::round(current_camera->get_rotation_degrees().x)) + "\n";
- text += TTR("Yaw") + ": " + itos(Math::round(current_camera->get_rotation_degrees().y)) + "\n\n";
- text += TTR("Objects Drawn") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_OBJECTS_IN_FRAME)) + "\n";
- text += TTR("Material Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_MATERIAL_CHANGES_IN_FRAME)) + "\n";
- text += TTR("Shader Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SHADER_CHANGES_IN_FRAME)) + "\n";
- text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n";
- text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n";
- text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME));
- info_label->set_text(text);
- }
-
- // FPS Counter.
- bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
- fps_label->set_visible(show_fps);
-
- if (show_fps) {
- String text;
- const float temp_fps = Engine::get_singleton()->get_frames_per_second();
- text += TTR(vformat("FPS: %d (%s ms)", temp_fps, String::num(1000.0f / temp_fps, 2)));
- fps_label->set_text(text);
- }
-
- bool show_cinema = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
- cinema_label->set_visible(show_cinema);
- if (show_cinema) {
- float cinema_half_width = cinema_label->get_size().width / 2.0f;
- cinema_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -cinema_half_width);
- }
-
- if (lock_rotation) {
- float locked_half_width = locked_label->get_size().width / 2.0f;
- locked_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -locked_half_width);
- }
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- surface->connect("draw", callable_mp(this, &SpatialEditorViewport::_draw));
- surface->connect("gui_input", callable_mp(this, &SpatialEditorViewport::_sinput));
- surface->connect("mouse_entered", callable_mp(this, &SpatialEditorViewport::_surface_mouse_enter));
- surface->connect("mouse_exited", callable_mp(this, &SpatialEditorViewport::_surface_mouse_exit));
- surface->connect("focus_entered", callable_mp(this, &SpatialEditorViewport::_surface_focus_enter));
- surface->connect("focus_exited", callable_mp(this, &SpatialEditorViewport::_surface_focus_exit));
-
- _init_gizmo_instance(index);
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
-
- _finish_gizmo_instances();
- }
-
- if (p_what == NOTIFICATION_THEME_CHANGED) {
-
- view_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
- preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
-
- view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
-
- preview_camera->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- preview_camera->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- preview_camera->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- preview_camera->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
-
- info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- }
-}
-
-static void draw_indicator_bar(Control &surface, real_t fill, Ref<Texture2D> icon) {
-
- // Adjust bar size from control height
- Vector2 surface_size = surface.get_size();
- real_t h = surface_size.y / 2.0;
- real_t y = (surface_size.y - h) / 2.0;
-
- Rect2 r(10, y, 6, h);
- real_t sy = r.size.y * fill;
-
- // Note: because this bar appears over the viewport, it has to stay readable for any background color
- // Draw both neutral dark and bright colors to account this
- surface.draw_rect(r, Color(1, 1, 1, 0.2));
- surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6));
- surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE));
-
- Vector2 icon_size = icon->get_size();
- Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2);
- surface.draw_texture(icon, icon_pos);
-}
-
-void SpatialEditorViewport::_draw() {
-
- EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over();
- if (!over_plugin_list->empty()) {
- over_plugin_list->forward_spatial_draw_over_viewport(surface);
- }
-
- EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
- if (!force_over_plugin_list->empty()) {
- force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface);
- }
-
- if (surface->has_focus()) {
- Size2 size = surface->get_size();
- Rect2 r = Rect2(Point2(), size);
- get_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r);
- }
-
- if (cursor.region_select) {
- const Rect2 selection_rect = Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin);
-
- surface->draw_rect(
- selection_rect,
- get_color("box_selection_fill_color", "Editor"));
-
- surface->draw_rect(
- selection_rect,
- get_color("box_selection_stroke_color", "Editor"),
- false,
- Math::round(EDSCALE));
- }
-
- RID ci = surface->get_canvas_item();
-
- if (message_time > 0) {
- Ref<Font> font = get_font("font", "Label");
- Point2 msgpos = Point2(5, get_size().y - 20);
- font->draw(ci, msgpos + Point2(1, 1), message, Color(0, 0, 0, 0.8));
- font->draw(ci, msgpos + Point2(-1, -1), message, Color(0, 0, 0, 0.8));
- font->draw(ci, msgpos, message, Color(1, 1, 1, 1));
- }
-
- if (_edit.mode == TRANSFORM_ROTATE) {
-
- Point2 center = _point_to_screen(_edit.center);
- VisualServer::get_singleton()->canvas_item_add_line(
- ci,
- _edit.mouse_pos,
- center,
- get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
- Math::round(2 * EDSCALE));
- }
- if (previewing) {
-
- Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
- float aspect = ss.aspect();
- Size2 s = get_size();
-
- Rect2 draw_rect;
-
- switch (previewing->get_keep_aspect_mode()) {
- case Camera::KEEP_WIDTH: {
-
- draw_rect.size = Size2(s.width, s.width / aspect);
- draw_rect.position.x = 0;
- draw_rect.position.y = (s.height - draw_rect.size.y) * 0.5;
-
- } break;
- case Camera::KEEP_HEIGHT: {
-
- draw_rect.size = Size2(s.height * aspect, s.height);
- draw_rect.position.y = 0;
- draw_rect.position.x = (s.width - draw_rect.size.x) * 0.5;
-
- } break;
- }
-
- draw_rect = Rect2(Vector2(), s).clip(draw_rect);
-
- surface->draw_rect(draw_rect, Color(0.6, 0.6, 0.1, 0.5), false, Math::round(2 * EDSCALE));
-
- } else {
-
- if (zoom_indicator_delay > 0.0) {
-
- if (is_freelook_active()) {
- // Show speed
-
- real_t min_speed = FREELOOK_MIN_SPEED;
- real_t max_speed = camera->get_zfar();
- real_t scale_length = (max_speed - min_speed);
-
- if (!Math::is_zero_approx(scale_length)) {
- real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
-
- // There is no real maximum speed so that factor can become negative,
- // Let's make it look asymptotic instead (will decrease slower and slower).
- if (logscale_t < 0.25)
- logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
-
- draw_indicator_bar(*surface, 1.0 - logscale_t, get_icon("ViewportSpeed", "EditorIcons"));
- }
-
- } else {
- // Show zoom
-
- real_t min_distance = ZOOM_MIN_DISTANCE; // TODO Why not pick znear to limit zoom?
- real_t max_distance = camera->get_zfar();
- real_t scale_length = (max_distance - min_distance);
-
- if (!Math::is_zero_approx(scale_length)) {
- real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
-
- // There is no real maximum distance so that factor can become negative,
- // Let's make it look asymptotic instead (will decrease slower and slower).
- if (logscale_t < 0.25)
- logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
-
- draw_indicator_bar(*surface, logscale_t, get_icon("ViewportZoom", "EditorIcons"));
- }
- }
- }
- }
-}
-
-void SpatialEditorViewport::_menu_option(int p_option) {
-
- switch (p_option) {
-
- case VIEW_TOP: {
-
- cursor.y_rot = 0;
- cursor.x_rot = Math_PI / 2.0;
- set_message(TTR("Top View."), 2);
- name = TTR("Top");
- _set_auto_orthogonal();
- _update_name();
-
- } break;
- case VIEW_BOTTOM: {
-
- cursor.y_rot = 0;
- cursor.x_rot = -Math_PI / 2.0;
- set_message(TTR("Bottom View."), 2);
- name = TTR("Bottom");
- _set_auto_orthogonal();
- _update_name();
-
- } break;
- case VIEW_LEFT: {
-
- cursor.x_rot = 0;
- cursor.y_rot = Math_PI / 2.0;
- set_message(TTR("Left View."), 2);
- name = TTR("Left");
- _set_auto_orthogonal();
- _update_name();
-
- } break;
- case VIEW_RIGHT: {
-
- cursor.x_rot = 0;
- cursor.y_rot = -Math_PI / 2.0;
- set_message(TTR("Right View."), 2);
- name = TTR("Right");
- _set_auto_orthogonal();
- _update_name();
-
- } break;
- case VIEW_FRONT: {
-
- cursor.x_rot = 0;
- cursor.y_rot = 0;
- set_message(TTR("Front View."), 2);
- name = TTR("Front");
- _set_auto_orthogonal();
- _update_name();
-
- } break;
- case VIEW_REAR: {
-
- cursor.x_rot = 0;
- cursor.y_rot = Math_PI;
- set_message(TTR("Rear View."), 2);
- name = TTR("Rear");
- _set_auto_orthogonal();
- _update_name();
-
- } break;
- case VIEW_CENTER_TO_ORIGIN: {
-
- cursor.pos = Vector3(0, 0, 0);
-
- } break;
- case VIEW_CENTER_TO_SELECTION: {
-
- focus_selection();
-
- } break;
- case VIEW_ALIGN_TRANSFORM_WITH_VIEW: {
-
- if (!get_selected_count())
- break;
-
- Transform camera_transform = camera->get_global_transform();
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- undo_redo->create_action(TTR("Align Transform with View"));
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- Transform xform;
- if (orthogonal) {
- xform = sp->get_global_transform();
- xform.basis.set_euler(camera_transform.basis.get_euler());
- } else {
- xform = camera_transform;
- xform.scale_basis(sp->get_scale());
- }
-
- undo_redo->add_do_method(sp, "set_global_transform", xform);
- undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
- }
- undo_redo->commit_action();
- focus_selection();
-
- } break;
- case VIEW_ALIGN_ROTATION_WITH_VIEW: {
-
- if (!get_selected_count())
- break;
-
- Transform camera_transform = camera->get_global_transform();
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- undo_redo->create_action(TTR("Align Rotation with View"));
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_rotation());
- undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation());
- }
- undo_redo->commit_action();
-
- } break;
- case VIEW_ENVIRONMENT: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- if (current) {
-
- camera->set_environment(RES());
- } else {
-
- camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
- }
-
- view_menu->get_popup()->set_item_checked(idx, current);
-
- } break;
- case VIEW_PERSPECTIVE: {
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false);
- orthogonal = false;
- auto_orthogonal = false;
- call_deferred("update_transform_gizmo_view");
- _update_name();
-
- } break;
- case VIEW_ORTHOGONAL: {
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true);
- orthogonal = true;
- auto_orthogonal = false;
- call_deferred("update_transform_gizmo_view");
- _update_name();
-
- } break;
- case VIEW_AUTO_ORTHOGONAL: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- view_menu->get_popup()->set_item_checked(idx, current);
- if (auto_orthogonal) {
- auto_orthogonal = false;
- _update_name();
- }
- } break;
- case VIEW_LOCK_ROTATION: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- lock_rotation = !current;
- view_menu->get_popup()->set_item_checked(idx, !current);
- if (lock_rotation) {
- locked_label->show();
- } else {
- locked_label->hide();
- }
-
- } break;
- case VIEW_AUDIO_LISTENER: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- viewport->set_as_audio_listener(current);
- view_menu->get_popup()->set_item_checked(idx, current);
-
- } break;
- case VIEW_AUDIO_DOPPLER: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- camera->set_doppler_tracking(current ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED);
- view_menu->get_popup()->set_item_checked(idx, current);
-
- } break;
- case VIEW_CINEMATIC_PREVIEW: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- view_menu->get_popup()->set_item_checked(idx, current);
- previewing_cinema = true;
- _toggle_cinema_preview(current);
-
- if (current) {
- preview_camera->hide();
- } else {
- if (previewing != NULL)
- preview_camera->show();
- }
- } break;
- case VIEW_GIZMOS: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- if (current)
- camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
- else
- camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_GRID_LAYER));
- view_menu->get_popup()->set_item_checked(idx, current);
-
- } break;
- case VIEW_HALF_RESOLUTION: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- current = !current;
- view_menu->get_popup()->set_item_checked(idx, current);
- } break;
- case VIEW_INFORMATION: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- view_menu->get_popup()->set_item_checked(idx, !current);
-
- } break;
- case VIEW_FPS: {
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
- bool current = view_menu->get_popup()->is_item_checked(idx);
- view_menu->get_popup()->set_item_checked(idx, !current);
-
- } break;
- case VIEW_DISPLAY_NORMAL:
- case VIEW_DISPLAY_WIREFRAME:
- case VIEW_DISPLAY_OVERDRAW:
- case VIEW_DISPLAY_SHADELESS:
- case VIEW_DISPLAY_LIGHTING:
- case VIEW_DISPLAY_NORMAL_BUFFER:
- case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS:
- case VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS:
- case VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO:
- case VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING:
- case VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION:
- case VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE:
- case VIEW_DISPLAY_DEBUG_SSAO:
- case VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER: {
-
- static const int display_options[] = {
- VIEW_DISPLAY_NORMAL,
- VIEW_DISPLAY_WIREFRAME,
- VIEW_DISPLAY_OVERDRAW,
- VIEW_DISPLAY_SHADELESS,
- VIEW_DISPLAY_LIGHTING,
- VIEW_DISPLAY_NORMAL_BUFFER,
- VIEW_DISPLAY_WIREFRAME,
- VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
- VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
- VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO,
- VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING,
- VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
- VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
- VIEW_DISPLAY_DEBUG_SSAO,
- VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
- VIEW_MAX
- };
- static const Viewport::DebugDraw debug_draw_modes[] = {
- Viewport::DEBUG_DRAW_DISABLED,
- Viewport::DEBUG_DRAW_WIREFRAME,
- Viewport::DEBUG_DRAW_OVERDRAW,
- Viewport::DEBUG_DRAW_UNSHADED,
- Viewport::DEBUG_DRAW_LIGHTING,
- Viewport::DEBUG_DRAW_NORMAL_BUFFER,
- Viewport::DEBUG_DRAW_WIREFRAME,
- Viewport::DEBUG_DRAW_SHADOW_ATLAS,
- Viewport::DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
- Viewport::DEBUG_DRAW_GI_PROBE_ALBEDO,
- Viewport::DEBUG_DRAW_GI_PROBE_LIGHTING,
- Viewport::DEBUG_DRAW_GI_PROBE_EMISSION,
- Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
- Viewport::DEBUG_DRAW_SSAO,
- Viewport::DEBUG_DRAW_ROUGHNESS_LIMITER,
- };
-
- int idx = 0;
-
- while (display_options[idx] != VIEW_MAX) {
-
- int id = display_options[idx];
- int item_idx = view_menu->get_popup()->get_item_index(id);
- if (item_idx != -1) {
- view_menu->get_popup()->set_item_checked(item_idx, id == p_option);
- }
- item_idx = display_submenu->get_item_index(id);
- if (item_idx != -1) {
- display_submenu->set_item_checked(item_idx, id == p_option);
- }
-
- if (id == p_option) {
- viewport->set_debug_draw(debug_draw_modes[idx]);
- }
- idx++;
- }
- } break;
- }
-}
-
-void SpatialEditorViewport::_set_auto_orthogonal() {
- if (!orthogonal && view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL))) {
- _menu_option(VIEW_ORTHOGONAL);
- auto_orthogonal = true;
- }
-}
-
-void SpatialEditorViewport::_preview_exited_scene() {
-
- preview_camera->disconnect("toggled", callable_mp(this, &SpatialEditorViewport::_toggle_camera_preview));
- preview_camera->set_pressed(false);
- _toggle_camera_preview(false);
- preview_camera->connect("toggled", callable_mp(this, &SpatialEditorViewport::_toggle_camera_preview));
- view_menu->show();
-}
-
-void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
-
- uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx);
-
- for (int i = 0; i < 3; i++) {
- move_gizmo_instance[i] = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
- VS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer);
-
- move_plane_gizmo_instance[i] = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
- VS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer);
-
- rotate_gizmo_instance[i] = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
- VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
-
- scale_gizmo_instance[i] = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
- VS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer);
-
- scale_plane_gizmo_instance[i] = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid());
- VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
- VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
- }
-}
-
-void SpatialEditorViewport::_finish_gizmo_instances() {
-
- for (int i = 0; i < 3; i++) {
- VS::get_singleton()->free(move_gizmo_instance[i]);
- VS::get_singleton()->free(move_plane_gizmo_instance[i]);
- VS::get_singleton()->free(rotate_gizmo_instance[i]);
- VS::get_singleton()->free(scale_gizmo_instance[i]);
- VS::get_singleton()->free(scale_plane_gizmo_instance[i]);
- }
-}
-void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
-
- ERR_FAIL_COND(p_activate && !preview);
- ERR_FAIL_COND(!p_activate && !previewing);
-
- if (!p_activate) {
-
- previewing->disconnect("tree_exiting", callable_mp(this, &SpatialEditorViewport::_preview_exited_scene));
- previewing = NULL;
- VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
- if (!preview)
- preview_camera->hide();
- view_menu->set_disabled(false);
- surface->update();
-
- } else {
-
- previewing = preview;
- previewing->connect("tree_exiting", callable_mp(this, &SpatialEditorViewport::_preview_exited_scene));
- VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
- view_menu->set_disabled(true);
- surface->update();
- }
-}
-
-void SpatialEditorViewport::_toggle_cinema_preview(bool p_activate) {
- previewing_cinema = p_activate;
- if (!previewing_cinema) {
- if (previewing != NULL)
- previewing->disconnect("tree_exited", callable_mp(this, &SpatialEditorViewport::_preview_exited_scene));
-
- previewing = NULL;
- VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
- preview_camera->set_pressed(false);
- if (!preview) {
- preview_camera->hide();
- } else {
- preview_camera->show();
- }
- view_menu->show();
- surface->update();
- }
-}
-
-void SpatialEditorViewport::_selection_result_pressed(int p_result) {
-
- if (selection_results.size() <= p_result)
- return;
-
- clicked = selection_results[p_result].item->get_instance_id();
-
- if (clicked.is_valid()) {
- _select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != SpatialEditor::TOOL_MODE_LIST_SELECT);
- clicked = ObjectID();
- }
-}
-
-void SpatialEditorViewport::_selection_menu_hide() {
-
- selection_results.clear();
- selection_menu->clear();
- selection_menu->set_size(Vector2(0, 0));
-}
-
-void SpatialEditorViewport::set_can_preview(Camera *p_preview) {
-
- preview = p_preview;
-
- if (!preview_camera->is_pressed() && !previewing_cinema)
- preview_camera->set_visible(p_preview);
-}
-
-void SpatialEditorViewport::update_transform_gizmo_view() {
-
- if (!is_visible_in_tree())
- return;
-
- Transform xform = spatial_editor->get_gizmo_transform();
-
- Transform camera_xform = camera->get_transform();
-
- if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) {
- for (int i = 0; i < 3; i++) {
- VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
- VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
- VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
- VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
- VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
- }
- return;
- }
-
- Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
- Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
- Plane p(camera_xform.origin, camz);
- float gizmo_d = Math::abs(p.distance_to(xform.origin));
- float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
- float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
- float dd = Math::abs(d0 - d1);
- if (dd == 0)
- dd = 0.0001;
-
- float gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
- // At low viewport heights, multiply the gizmo scale based on the viewport height.
- // This prevents the gizmo from growing very large and going outside the viewport.
- const int viewport_base_height = 400 * MAX(1, EDSCALE);
- gizmo_scale =
- (gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) *
- MIN(viewport_base_height, viewport_container->get_size().height) / viewport_base_height /
- viewport_container->get_stretch_shrink();
- Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
-
- xform.basis.scale(scale);
-
- for (int i = 0; i < 3; i++) {
- VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
- VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
- VisualServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
- VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
- VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
- VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE));
- VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
- VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
- VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
- VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
- }
-}
-
-void SpatialEditorViewport::set_state(const Dictionary &p_state) {
-
- if (p_state.has("position"))
- cursor.pos = p_state["position"];
- if (p_state.has("x_rotation"))
- cursor.x_rot = p_state["x_rotation"];
- if (p_state.has("y_rotation"))
- cursor.y_rot = p_state["y_rotation"];
- if (p_state.has("distance"))
- cursor.distance = p_state["distance"];
-
- if (p_state.has("use_orthogonal")) {
- bool orth = p_state["use_orthogonal"];
-
- if (orth)
- _menu_option(VIEW_ORTHOGONAL);
- else
- _menu_option(VIEW_PERSPECTIVE);
- }
- if (p_state.has("view_name")) {
- name = p_state["view_name"];
- _update_name();
- }
- if (p_state.has("auto_orthogonal")) {
- auto_orthogonal = p_state["auto_orthogonal"];
- _update_name();
- }
- if (p_state.has("auto_orthogonal_enabled")) {
- bool enabled = p_state["auto_orthogonal_enabled"];
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), enabled);
- }
- if (p_state.has("display_mode")) {
- int display = p_state["display_mode"];
-
- int idx = view_menu->get_popup()->get_item_index(display);
- if (!view_menu->get_popup()->is_item_checked(idx))
- _menu_option(display);
- }
- if (p_state.has("lock_rotation")) {
- lock_rotation = p_state["lock_rotation"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION);
- view_menu->get_popup()->set_item_checked(idx, lock_rotation);
- }
- if (p_state.has("use_environment")) {
- bool env = p_state["use_environment"];
-
- if (env != camera->get_environment().is_valid())
- _menu_option(VIEW_ENVIRONMENT);
- }
- if (p_state.has("listener")) {
- bool listener = p_state["listener"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
- viewport->set_as_audio_listener(listener);
- view_menu->get_popup()->set_item_checked(idx, listener);
- }
- if (p_state.has("doppler")) {
- bool doppler = p_state["doppler"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER);
- camera->set_doppler_tracking(doppler ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED);
- view_menu->get_popup()->set_item_checked(idx, doppler);
- }
- if (p_state.has("gizmos")) {
- bool gizmos = p_state["gizmos"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
- if (view_menu->get_popup()->is_item_checked(idx) != gizmos)
- _menu_option(VIEW_GIZMOS);
- }
- if (p_state.has("information")) {
- bool information = p_state["information"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
- if (view_menu->get_popup()->is_item_checked(idx) != information)
- _menu_option(VIEW_INFORMATION);
- }
- if (p_state.has("fps")) {
- bool fps = p_state["fps"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
- if (view_menu->get_popup()->is_item_checked(idx) != fps)
- _menu_option(VIEW_FPS);
- }
- if (p_state.has("half_res")) {
- bool half_res = p_state["half_res"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
- view_menu->get_popup()->set_item_checked(idx, half_res);
- }
- if (p_state.has("cinematic_preview")) {
- previewing_cinema = p_state["cinematic_preview"];
-
- int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW);
- view_menu->get_popup()->set_item_checked(idx, previewing_cinema);
- }
-
- if (preview_camera->is_connected("toggled", callable_mp(this, &SpatialEditorViewport::_toggle_camera_preview))) {
- preview_camera->disconnect("toggled", callable_mp(this, &SpatialEditorViewport::_toggle_camera_preview));
- }
- if (p_state.has("previewing")) {
- Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
- if (Object::cast_to<Camera>(pv)) {
- previewing = Object::cast_to<Camera>(pv);
- previewing->connect("tree_exiting", callable_mp(this, &SpatialEditorViewport::_preview_exited_scene));
- VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
- view_menu->set_disabled(true);
- surface->update();
- preview_camera->set_pressed(true);
- preview_camera->show();
- }
- }
- preview_camera->connect("toggled", callable_mp(this, &SpatialEditorViewport::_toggle_camera_preview));
-}
-
-Dictionary SpatialEditorViewport::get_state() const {
-
- Dictionary d;
- d["position"] = cursor.pos;
- d["x_rotation"] = cursor.x_rot;
- d["y_rotation"] = cursor.y_rot;
- d["distance"] = cursor.distance;
- d["use_environment"] = camera->get_environment().is_valid();
- d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
- d["view_name"] = name;
- d["auto_orthogonal"] = auto_orthogonal;
- d["auto_orthogonal_enabled"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL));
- if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL)))
- d["display_mode"] = VIEW_DISPLAY_NORMAL;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME)))
- d["display_mode"] = VIEW_DISPLAY_WIREFRAME;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW)))
- d["display_mode"] = VIEW_DISPLAY_OVERDRAW;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS)))
- d["display_mode"] = VIEW_DISPLAY_SHADELESS;
- d["listener"] = viewport->is_audio_listener();
- d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
- d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
- d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
- d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
- d["half_res"] = viewport_container->get_stretch_shrink() > 1;
- d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
- if (previewing)
- d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
- if (lock_rotation)
- d["lock_rotation"] = lock_rotation;
-
- return d;
-}
-
-void SpatialEditorViewport::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &SpatialEditorViewport::update_transform_gizmo_view); // Used by call_deferred.
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpatialEditorViewport::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw);
-
- ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
- ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
-}
-
-void SpatialEditorViewport::reset() {
-
- orthogonal = false;
- auto_orthogonal = false;
- lock_rotation = false;
- message_time = 0;
- message = "";
- last_message = "";
- name = "";
-
- cursor.x_rot = 0.5;
- cursor.y_rot = 0.5;
- cursor.distance = 4;
- cursor.region_select = false;
- cursor.pos = Vector3();
- _update_name();
-}
-
-void SpatialEditorViewport::focus_selection() {
- if (!get_selected_count())
- return;
-
- Vector3 center;
- int count = 0;
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- center += sp->get_global_gizmo_transform().origin;
- count++;
- }
-
- if (count != 0) {
- center /= float(count);
- }
-
- cursor.pos = center;
-}
-
-void SpatialEditorViewport::assign_pending_data_pointers(Spatial *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept) {
- preview_node = p_preview_node;
- preview_bounds = p_preview_bounds;
- accept = p_accept;
-}
-
-Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const {
- const float MAX_DISTANCE = 10;
-
- Vector3 world_ray = _get_ray(p_pos);
- Vector3 world_pos = _get_ray_pos(p_pos);
-
- Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario());
- Set<Ref<EditorSpatialGizmo> > found_gizmos;
-
- float closest_dist = MAX_DISTANCE;
-
- Vector3 point = world_pos + world_ray * MAX_DISTANCE;
- Vector3 normal = Vector3(0.0, 0.0, 0.0);
-
- for (int i = 0; i < instances.size(); i++) {
-
- MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(ObjectDB::get_instance(instances[i]));
-
- if (!mesh_instance)
- continue;
-
- Ref<EditorSpatialGizmo> seg = mesh_instance->get_gizmo();
-
- if ((!seg.is_valid()) || found_gizmos.has(seg)) {
- continue;
- }
-
- found_gizmos.insert(seg);
-
- Vector3 hit_point;
- Vector3 hit_normal;
- bool inters = seg->intersect_ray(camera, p_pos, hit_point, hit_normal, NULL, false);
-
- if (!inters)
- continue;
-
- float dist = world_pos.distance_to(hit_point);
-
- if (dist < 0)
- continue;
-
- if (dist < closest_dist) {
- closest_dist = dist;
- point = hit_point;
- normal = hit_normal;
- }
- }
- Vector3 offset = Vector3();
- for (int i = 0; i < 3; i++) {
- if (normal[i] > 0.0)
- offset[i] = (preview_bounds->get_size()[i] - (preview_bounds->get_size()[i] + preview_bounds->get_position()[i]));
- else if (normal[i] < 0.0)
- offset[i] = -(preview_bounds->get_size()[i] + preview_bounds->get_position()[i]);
- }
- return point + offset;
-}
-
-AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform) {
- AABB bounds;
-
- const MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_parent);
- if (mesh_instance) {
- bounds = mesh_instance->get_aabb();
- }
-
- for (int i = 0; i < p_parent->get_child_count(); i++) {
- Spatial *child = Object::cast_to<Spatial>(p_parent->get_child(i));
- if (child) {
- AABB child_bounds = _calculate_spatial_bounds(child, false);
-
- if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Spatial")) {
- bounds = child_bounds;
- } else {
- bounds.merge_with(child_bounds);
- }
- }
- }
-
- if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Spatial")) {
- bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
- }
-
- if (!p_exclude_toplevel_transform) {
- bounds = p_parent->get_transform().xform(bounds);
- }
-
- return bounds;
-}
-
-void SpatialEditorViewport::_create_preview(const Vector<String> &files) const {
- for (int i = 0; i < files.size(); i++) {
- String path = files[i];
- RES res = ResourceLoader::load(path);
- ERR_CONTINUE(res.is_null());
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
- if (mesh != NULL || scene != NULL) {
- if (mesh != NULL) {
- MeshInstance *mesh_instance = memnew(MeshInstance);
- mesh_instance->set_mesh(mesh);
- preview_node->add_child(mesh_instance);
- } else {
- if (scene.is_valid()) {
- Node *instance = scene->instance();
- if (instance) {
- preview_node->add_child(instance);
- }
- }
- }
- editor->get_scene_root()->add_child(preview_node);
- }
- }
- *preview_bounds = _calculate_spatial_bounds(preview_node);
-}
-
-void SpatialEditorViewport::_remove_preview() {
- if (preview_node->get_parent()) {
- for (int i = preview_node->get_child_count() - 1; i >= 0; i--) {
- Node *node = preview_node->get_child(i);
- node->queue_delete();
- preview_node->remove_child(node);
- }
- editor->get_scene_root()->remove_child(preview_node);
- }
-}
-
-bool SpatialEditorViewport::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) {
- if (p_desired_node->get_filename() == p_target_scene_path) {
- return true;
- }
-
- int childCount = p_desired_node->get_child_count();
- for (int i = 0; i < childCount; i++) {
- Node *child = p_desired_node->get_child(i);
- if (_cyclical_dependency_exists(p_target_scene_path, child)) {
- return true;
- }
- }
- return false;
-}
-
-bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
- RES res = ResourceLoader::load(path);
- ERR_FAIL_COND_V(res.is_null(), false);
-
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
-
- Node *instanced_scene = NULL;
-
- if (mesh != NULL || scene != NULL) {
- if (mesh != NULL) {
- MeshInstance *mesh_instance = memnew(MeshInstance);
- mesh_instance->set_mesh(mesh);
- mesh_instance->set_name(path.get_file().get_basename());
- instanced_scene = mesh_instance;
- } else {
- if (!scene.is_valid()) { // invalid scene
- return false;
- } else {
- instanced_scene = scene->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
- }
- }
- }
-
- if (instanced_scene == NULL) {
- return false;
- }
-
- if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing
- if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) {
- memdelete(instanced_scene);
- return false;
- }
- }
-
- if (scene != NULL) {
- instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
- }
-
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
- editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(instanced_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene);
-
- String new_name = parent->validate_child_name(instanced_scene);
- EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
-
- Transform global_transform;
- Spatial *parent_spatial = Object::cast_to<Spatial>(parent);
- if (parent_spatial)
- global_transform = parent_spatial->get_global_gizmo_transform();
-
- global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
-
- editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform);
-
- return true;
-}
-
-void SpatialEditorViewport::_perform_drop_data() {
- _remove_preview();
-
- Vector<String> error_files;
-
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
-
- for (int i = 0; i < selected_files.size(); i++) {
- String path = selected_files[i];
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
- continue;
- }
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
- if (mesh != NULL || scene != NULL) {
- bool success = _create_instance(target_node, path, drop_pos);
- if (!success) {
- error_files.push_back(path);
- }
- }
- }
-
- editor_data->get_undo_redo().commit_action();
-
- if (error_files.size() > 0) {
- String files_str;
- for (int i = 0; i < error_files.size(); i++) {
- files_str += error_files[i].get_file().get_basename() + ",";
- }
- files_str = files_str.substr(0, files_str.length() - 1);
- accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
- accept->popup_centered_minsize();
- }
-}
-
-bool SpatialEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
-
- bool can_instance = false;
-
- if (!preview_node->is_inside_tree()) {
- Dictionary d = p_data;
- if (d.has("type") && (String(d["type"]) == "files")) {
- Vector<String> files = d["files"];
-
- List<String> scene_extensions;
- ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
- List<String> mesh_extensions;
- ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions);
-
- for (int i = 0; i < files.size(); i++) {
- if (mesh_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
- RES res = ResourceLoader::load(files[i]);
- if (res.is_null()) {
- continue;
- }
-
- String type = res->get_class();
- if (type == "PackedScene") {
- Ref<PackedScene> sdata = ResourceLoader::load(files[i]);
- Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instanced_scene) {
- continue;
- }
- memdelete(instanced_scene);
- } else if (type == "Mesh" || type == "ArrayMesh" || type == "PrimitiveMesh") {
- Ref<Mesh> mesh = ResourceLoader::load(files[i]);
- if (!mesh.is_valid()) {
- continue;
- }
- } else {
- continue;
- }
- can_instance = true;
- break;
- }
- }
- if (can_instance) {
- _create_preview(files);
- }
- }
- } else {
- can_instance = true;
- }
-
- if (can_instance) {
- Transform global_transform = Transform(Basis(), _get_instance_position(p_point));
- preview_node->set_global_transform(global_transform);
- }
-
- return can_instance;
-}
-
-void SpatialEditorViewport::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;
-
- bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
-
- selected_files.clear();
- Dictionary d = p_data;
- if (d.has("type") && String(d["type"]) == "files") {
- selected_files = d["files"];
- }
-
- List<Node *> list = editor->get_editor_selection()->get_selected_node_list();
- if (list.size() == 0) {
- Node *root_node = editor->get_edited_scene();
- if (root_node) {
- list.push_back(root_node);
- } else {
- accept->set_text(TTR("No parent to instance a child at."));
- accept->popup_centered_minsize();
- _remove_preview();
- return;
- }
- }
- if (list.size() != 1) {
- accept->set_text(TTR("This operation requires a single selected node."));
- accept->popup_centered_minsize();
- _remove_preview();
- return;
- }
-
- target_node = list[0];
- if (is_shift && target_node != editor->get_edited_scene()) {
- target_node = target_node->get_parent();
- }
- drop_pos = p_point;
-
- _perform_drop_data();
-}
-
-SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
-
- _edit.mode = TRANSFORM_NONE;
- _edit.plane = TRANSFORM_VIEW;
- _edit.edited_gizmo = 0;
- _edit.snap = 1;
- _edit.gizmo_handle = 0;
-
- index = p_index;
- editor = p_editor;
- editor_data = editor->get_scene_tree_dock()->get_editor_data();
- editor_selection = editor->get_editor_selection();
- undo_redo = editor->get_undo_redo();
-
- clicked_includes_current = false;
- orthogonal = false;
- auto_orthogonal = false;
- lock_rotation = false;
- message_time = 0;
- zoom_indicator_delay = 0.0;
-
- spatial_editor = p_spatial_editor;
- ViewportContainer *c = memnew(ViewportContainer);
- viewport_container = c;
- c->set_stretch(true);
- add_child(c);
- c->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- viewport = memnew(Viewport);
- viewport->set_disable_input(true);
-
- c->add_child(viewport);
- surface = memnew(Control);
- surface->set_drag_forwarding(this);
- add_child(surface);
- surface->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- surface->set_clip_contents(true);
- camera = memnew(Camera);
- camera->set_disable_gizmo(true);
- camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
- viewport->add_child(camera);
- camera->make_current();
- surface->set_focus_mode(FOCUS_ALL);
-
- crosshair = memnew(TextureRect);
- crosshair->set_mouse_filter(MOUSE_FILTER_IGNORE);
- surface->add_child(crosshair);
-
- VBoxContainer *vbox = memnew(VBoxContainer);
- surface->add_child(vbox);
- vbox->set_position(Point2(10, 10) * EDSCALE);
-
- view_menu = memnew(MenuButton);
- view_menu->set_flat(false);
- vbox->add_child(view_menu);
- view_menu->set_h_size_flags(0);
-
- display_submenu = memnew(PopupMenu);
- view_menu->get_popup()->add_child(display_submenu);
-
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/right_view"), VIEW_RIGHT);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR);
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_radio_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
- view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
- view_menu->get_popup()->add_check_item(TTR("Auto Orthogonal Enabled"), VIEW_AUTO_ORTHOGONAL);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), true);
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_lock_rotation", TTR("Lock View Rotation")), VIEW_LOCK_ROTATION);
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL);
- view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME);
- view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
- view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_lighting", TTR("Display Lighting")), VIEW_DISPLAY_LIGHTING);
- view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
- display_submenu->add_radio_check_item(TTR("Normal Buffer"), VIEW_DISPLAY_NORMAL_BUFFER);
- display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Shadow Atlas"), VIEW_DISPLAY_DEBUG_SHADOW_ATLAS);
- display_submenu->add_radio_check_item(TTR("Directional Shadow"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
- display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("GIProbe Lighting"), VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING);
- display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO);
- display_submenu->add_radio_check_item(TTR("GIProbe Emission"), VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION);
- display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Scene Luminance"), VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE);
- display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
- display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Roughness Limiter"), VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER);
- display_submenu->set_name("display_advanced");
- view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true);
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Enable Doppler")), VIEW_AUDIO_DOPPLER);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
-
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_cinematic_preview", TTR("Cinematic Preview")), VIEW_CINEMATIC_PREVIEW);
-
- view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_origin"), VIEW_CENTER_TO_ORIGIN);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_transform_with_view"), VIEW_ALIGN_TRANSFORM_WITH_VIEW);
- view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_rotation_with_view"), VIEW_ALIGN_ROTATION_WITH_VIEW);
- view_menu->get_popup()->connect("id_pressed", callable_mp(this, &SpatialEditorViewport::_menu_option));
- display_submenu->connect("id_pressed", callable_mp(this, &SpatialEditorViewport::_menu_option));
- view_menu->set_disable_shortcuts(true);
-
- if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
- // Alternate display modes only work when using the Vulkan renderer; make this explicit.
- const int normal_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL);
- const int wireframe_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME);
- const int overdraw_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW);
- const int shadeless_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS);
- const String unsupported_tooltip = TTR("Not available when using the GLES2 renderer.");
-
- view_menu->get_popup()->set_item_disabled(normal_idx, true);
- view_menu->get_popup()->set_item_tooltip(normal_idx, unsupported_tooltip);
- view_menu->get_popup()->set_item_disabled(wireframe_idx, true);
- view_menu->get_popup()->set_item_tooltip(wireframe_idx, unsupported_tooltip);
- view_menu->get_popup()->set_item_disabled(overdraw_idx, true);
- view_menu->get_popup()->set_item_tooltip(overdraw_idx, unsupported_tooltip);
- view_menu->get_popup()->set_item_disabled(shadeless_idx, true);
- view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip);
- }
-
- ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A);
- ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D);
- ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W);
- ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S);
- ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_E);
- ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_Q);
- ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT);
- ED_SHORTCUT("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), KEY_ALT);
-
- preview_camera = memnew(CheckBox);
- preview_camera->set_text(TTR("Preview"));
- vbox->add_child(preview_camera);
- preview_camera->set_h_size_flags(0);
- preview_camera->hide();
- preview_camera->connect("toggled", callable_mp(this, &SpatialEditorViewport::_toggle_camera_preview));
- previewing = NULL;
- gizmo_scale = 1.0;
-
- preview_node = NULL;
-
- info_label = memnew(Label);
- info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
- info_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -90 * EDSCALE);
- info_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
- info_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
- info_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
- info_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
- surface->add_child(info_label);
- info_label->hide();
-
- fps_label = memnew(Label);
- fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
- fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
- fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
- fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance."));
- fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show.
- surface->add_child(fps_label);
- fps_label->hide();
-
- cinema_label = memnew(Label);
- cinema_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- cinema_label->set_h_grow_direction(GROW_DIRECTION_END);
- cinema_label->set_align(Label::ALIGN_CENTER);
- surface->add_child(cinema_label);
- cinema_label->set_text(TTR("Cinematic Preview"));
- cinema_label->hide();
- previewing_cinema = false;
-
- locked_label = memnew(Label);
- locked_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE);
- locked_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
- locked_label->set_h_grow_direction(GROW_DIRECTION_END);
- locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
- locked_label->set_align(Label::ALIGN_CENTER);
- surface->add_child(locked_label);
- locked_label->set_text(TTR("View Rotation Locked"));
- locked_label->hide();
-
- top_right_vbox = memnew(VBoxContainer);
- top_right_vbox->set_anchors_and_margins_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 2.0 * EDSCALE);
- top_right_vbox->set_h_grow_direction(GROW_DIRECTION_BEGIN);
-
- rotation_control = memnew(ViewportRotationControl);
- rotation_control->set_custom_minimum_size(Size2(80, 80) * EDSCALE);
- rotation_control->set_h_size_flags(SIZE_SHRINK_END);
- rotation_control->set_viewport(this);
- top_right_vbox->add_child(rotation_control);
-
- fps_label = memnew(Label);
- fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
- fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
- fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
- fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance."));
- fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show.
- top_right_vbox->add_child(fps_label);
- fps_label->hide();
-
- surface->add_child(top_right_vbox);
-
- accept = NULL;
-
- freelook_active = false;
- freelook_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
-
- selection_menu = memnew(PopupMenu);
- add_child(selection_menu);
- selection_menu->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
- selection_menu->connect("id_pressed", callable_mp(this, &SpatialEditorViewport::_selection_result_pressed));
- selection_menu->connect("popup_hide", callable_mp(this, &SpatialEditorViewport::_selection_menu_hide));
-
- if (p_index == 0) {
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER), true);
- viewport->set_as_audio_listener(true);
- }
-
- name = "";
- _update_name();
-
- EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &SpatialEditorViewport::update_transform_gizmo_view));
-}
-
-//////////////////////////////////////////////////////////////
-
-void SpatialEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) {
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
-
- if (mb->is_pressed()) {
- Vector2 size = get_size();
-
- int h_sep = get_constant("separation", "HSplitContainer");
- int v_sep = get_constant("separation", "VSplitContainer");
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- dragging_h = mb->get_position().x > (mid_w - h_sep / 2) && mb->get_position().x < (mid_w + h_sep / 2);
- dragging_v = mb->get_position().y > (mid_h - v_sep / 2) && mb->get_position().y < (mid_h + v_sep / 2);
-
- drag_begin_pos = mb->get_position();
- drag_begin_ratio.x = ratio_h;
- drag_begin_ratio.y = ratio_v;
-
- switch (view) {
- case VIEW_USE_1_VIEWPORT: {
-
- dragging_h = false;
- dragging_v = false;
-
- } break;
- case VIEW_USE_2_VIEWPORTS: {
-
- dragging_h = false;
-
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
-
- dragging_v = false;
-
- } break;
- case VIEW_USE_3_VIEWPORTS:
- case VIEW_USE_3_VIEWPORTS_ALT:
- case VIEW_USE_4_VIEWPORTS: {
-
- // Do nothing.
-
- } break;
- }
- } else {
- dragging_h = false;
- dragging_v = false;
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
-
- if (view == VIEW_USE_3_VIEWPORTS || view == VIEW_USE_3_VIEWPORTS_ALT || view == VIEW_USE_4_VIEWPORTS) {
- Vector2 size = get_size();
-
- int h_sep = get_constant("separation", "HSplitContainer");
- int v_sep = get_constant("separation", "VSplitContainer");
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- bool was_hovering_h = hovering_h;
- bool was_hovering_v = hovering_v;
- hovering_h = mm->get_position().x > (mid_w - h_sep / 2) && mm->get_position().x < (mid_w + h_sep / 2);
- hovering_v = mm->get_position().y > (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2);
-
- if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) {
- update();
- }
- }
-
- if (dragging_h) {
- float new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width;
- new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
- ratio_h = new_ratio;
- queue_sort();
- update();
- }
- if (dragging_v) {
- float new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
- new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
- ratio_v = new_ratio;
- queue_sort();
- update();
- }
- }
-}
-
-void SpatialEditorViewportContainer::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_MOUSE_ENTER || p_what == NOTIFICATION_MOUSE_EXIT) {
-
- mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
- update();
- }
-
- if (p_what == NOTIFICATION_DRAW && mouseover) {
-
- Ref<Texture2D> h_grabber = get_icon("grabber", "HSplitContainer");
- Ref<Texture2D> v_grabber = get_icon("grabber", "VSplitContainer");
-
- Ref<Texture2D> hdiag_grabber = get_icon("GuiViewportHdiagsplitter", "EditorIcons");
- Ref<Texture2D> vdiag_grabber = get_icon("GuiViewportVdiagsplitter", "EditorIcons");
- Ref<Texture2D> vh_grabber = get_icon("GuiViewportVhsplitter", "EditorIcons");
-
- Vector2 size = get_size();
-
- int h_sep = get_constant("separation", "HSplitContainer");
-
- int v_sep = get_constant("separation", "VSplitContainer");
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- int size_left = mid_w - h_sep / 2;
- int size_bottom = size.height - mid_h - v_sep / 2;
-
- switch (view) {
-
- case VIEW_USE_1_VIEWPORT: {
-
- // Nothing to show.
-
- } break;
- case VIEW_USE_2_VIEWPORTS: {
-
- draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
-
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
-
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
-
- } break;
- case VIEW_USE_3_VIEWPORTS: {
-
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4));
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, mid_h + v_grabber->get_height() / 2 + (size_bottom - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
-
- } break;
- case VIEW_USE_3_VIEWPORTS_ALT: {
-
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, Vector2((size_left - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
-
- } break;
- case VIEW_USE_4_VIEWPORTS: {
-
- Vector2 half(mid_w, mid_h);
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, half - v_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, half - h_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
-
- } break;
- }
- }
-
- if (p_what == NOTIFICATION_SORT_CHILDREN) {
-
- SpatialEditorViewport *viewports[4];
- int vc = 0;
- for (int i = 0; i < get_child_count(); i++) {
- viewports[vc] = Object::cast_to<SpatialEditorViewport>(get_child(i));
- if (viewports[vc]) {
- vc++;
- }
- }
-
- ERR_FAIL_COND(vc != 4);
-
- Size2 size = get_size();
-
- if (size.x < 10 || size.y < 10) {
- for (int i = 0; i < 4; i++) {
- viewports[i]->hide();
- }
- return;
- }
- int h_sep = get_constant("separation", "HSplitContainer");
-
- int v_sep = get_constant("separation", "VSplitContainer");
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- int size_left = mid_w - h_sep / 2;
- int size_right = size.width - mid_w - h_sep / 2;
-
- int size_top = mid_h - v_sep / 2;
- int size_bottom = size.height - mid_h - v_sep / 2;
-
- switch (view) {
-
- case VIEW_USE_1_VIEWPORT: {
-
- viewports[0]->show();
- for (int i = 1; i < 4; i++) {
-
- viewports[i]->hide();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), size));
-
- } break;
- case VIEW_USE_2_VIEWPORTS: {
-
- for (int i = 0; i < 4; i++) {
-
- if (i == 1 || i == 3)
- viewports[i]->hide();
- else
- viewports[i]->show();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size.width, size_bottom)));
-
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
-
- for (int i = 0; i < 4; i++) {
-
- if (i == 1 || i == 3)
- viewports[i]->hide();
- else
- viewports[i]->show();
- }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
-
- } break;
- case VIEW_USE_3_VIEWPORTS: {
-
- for (int i = 0; i < 4; i++) {
-
- if (i == 1)
- viewports[i]->hide();
- else
- viewports[i]->show();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
-
- } break;
- case VIEW_USE_3_VIEWPORTS_ALT: {
-
- for (int i = 0; i < 4; i++) {
-
- if (i == 1)
- viewports[i]->hide();
- else
- viewports[i]->show();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
-
- } break;
- case VIEW_USE_4_VIEWPORTS: {
-
- for (int i = 0; i < 4; i++) {
-
- viewports[i]->show();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
- fit_child_in_rect(viewports[1], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
-
- } break;
- }
- }
-}
-
-void SpatialEditorViewportContainer::set_view(View p_view) {
-
- view = p_view;
- queue_sort();
-}
-
-SpatialEditorViewportContainer::View SpatialEditorViewportContainer::get_view() {
-
- return view;
-}
-
-void SpatialEditorViewportContainer::_bind_methods() {
-
- ClassDB::bind_method("_gui_input", &SpatialEditorViewportContainer::_gui_input);
-}
-
-SpatialEditorViewportContainer::SpatialEditorViewportContainer() {
-
- set_clip_contents(true);
- view = VIEW_USE_1_VIEWPORT;
- mouseover = false;
- ratio_h = 0.5;
- ratio_v = 0.5;
- hovering_v = false;
- hovering_h = false;
- dragging_v = false;
- dragging_h = false;
-}
-
-///////////////////////////////////////////////////////////////////
-
-SpatialEditor *SpatialEditor::singleton = NULL;
-
-SpatialEditorSelectedItem::~SpatialEditorSelectedItem() {
-
- if (sbox_instance.is_valid())
- VisualServer::get_singleton()->free(sbox_instance);
-}
-
-void SpatialEditor::select_gizmo_highlight_axis(int p_axis) {
-
- for (int i = 0; i < 3; i++) {
-
- move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
- move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
- rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
- scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
- scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
- }
-}
-
-void SpatialEditor::update_transform_gizmo() {
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- AABB center;
- bool first = true;
-
- Basis gizmo_basis;
- bool local_gizmo_coords = are_local_coords_enabled();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- Transform xf = se->sp->get_global_gizmo_transform();
-
- if (first) {
- center.position = xf.origin;
- first = false;
- if (local_gizmo_coords) {
- gizmo_basis = xf.basis;
- gizmo_basis.orthonormalize();
- }
- } else {
- center.expand_to(xf.origin);
- gizmo_basis = Basis();
- }
- }
-
- Vector3 pcenter = center.position + center.size * 0.5;
- gizmo.visible = !first;
- gizmo.transform.origin = pcenter;
- gizmo.transform.basis = gizmo_basis;
-
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
- viewports[i]->update_transform_gizmo_view();
- }
-}
-
-void _update_all_gizmos(Node *p_node) {
- for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
- Spatial *spatial_node = Object::cast_to<Spatial>(p_node->get_child(i));
- if (spatial_node) {
- spatial_node->update_gizmo();
- }
-
- _update_all_gizmos(p_node->get_child(i));
- }
-}
-
-void SpatialEditor::update_all_gizmos(Node *p_node) {
- if (!p_node) {
- p_node = SceneTree::get_singleton()->get_root();
- }
- _update_all_gizmos(p_node);
-}
-
-Object *SpatialEditor::_get_editor_data(Object *p_what) {
-
- Spatial *sp = Object::cast_to<Spatial>(p_what);
- if (!sp)
- return NULL;
-
- SpatialEditorSelectedItem *si = memnew(SpatialEditorSelectedItem);
-
- si->sp = sp;
- si->sbox_instance = VisualServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world()->get_scenario());
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, VS::SHADOW_CASTING_SETTING_OFF);
-
- return si;
-}
-
-void SpatialEditor::_generate_selection_box() {
-
- AABB aabb(Vector3(), Vector3(1, 1, 1));
- aabb.grow_by(aabb.get_longest_axis_size() / 20.0);
-
- Ref<SurfaceTool> st = memnew(SurfaceTool);
-
- st->begin(Mesh::PRIMITIVE_LINES);
- for (int i = 0; i < 12; i++) {
-
- Vector3 a, b;
- aabb.get_edge(i, a, b);
-
- st->add_color(Color(1.0, 1.0, 0.8, 0.8));
- st->add_vertex(a);
- st->add_color(Color(1.0, 1.0, 0.8, 0.4));
- st->add_vertex(a.linear_interpolate(b, 0.2));
-
- st->add_color(Color(1.0, 1.0, 0.8, 0.4));
- st->add_vertex(a.linear_interpolate(b, 0.8));
- st->add_color(Color(1.0, 1.0, 0.8, 0.8));
- st->add_vertex(b);
- }
-
- Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
- mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- mat->set_albedo(Color(1, 1, 1));
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- st->set_material(mat);
- selection_box = st->commit();
-}
-
-Dictionary SpatialEditor::get_state() const {
-
- Dictionary d;
-
- d["snap_enabled"] = snap_enabled;
- d["translate_snap"] = get_translate_snap();
- d["rotate_snap"] = get_rotate_snap();
- d["scale_snap"] = get_scale_snap();
-
- d["local_coords"] = tool_option_button[TOOL_OPT_LOCAL_COORDS]->is_pressed();
-
- int vc = 0;
- if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
- vc = 1;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
- vc = 2;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
- vc = 3;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
- vc = 4;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
- vc = 5;
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
- vc = 6;
-
- d["viewport_mode"] = vc;
- Array vpdata;
- for (int i = 0; i < 4; i++) {
- vpdata.push_back(viewports[i]->get_state());
- }
-
- d["viewports"] = vpdata;
-
- d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID));
- d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN));
- d["fov"] = get_fov();
- d["znear"] = get_znear();
- d["zfar"] = get_zfar();
-
- Dictionary gizmos_status;
- for (int i = 0; i < gizmo_plugins_by_name.size(); i++) {
- if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
- int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i));
- String name = gizmo_plugins_by_name[i]->get_name();
- gizmos_status[name] = state;
- }
-
- d["gizmos_status"] = gizmos_status;
-
- return d;
-}
-void SpatialEditor::set_state(const Dictionary &p_state) {
-
- Dictionary d = p_state;
-
- if (d.has("snap_enabled")) {
- snap_enabled = d["snap_enabled"];
- tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(d["snap_enabled"]);
- }
-
- if (d.has("translate_snap"))
- snap_translate_value = d["translate_snap"];
-
- if (d.has("rotate_snap"))
- snap_rotate_value = d["rotate_snap"];
-
- if (d.has("scale_snap"))
- snap_scale_value = d["scale_snap"];
-
- _snap_update();
-
- if (d.has("local_coords")) {
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(d["local_coords"]);
- update_transform_gizmo();
- }
-
- if (d.has("viewport_mode")) {
- int vc = d["viewport_mode"];
-
- if (vc == 1)
- _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
- else if (vc == 2)
- _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
- else if (vc == 3)
- _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
- else if (vc == 4)
- _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
- else if (vc == 5)
- _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
- else if (vc == 6)
- _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
- }
-
- if (d.has("viewports")) {
- Array vp = d["viewports"];
- uint32_t vp_size = static_cast<uint32_t>(vp.size());
- if (vp_size > VIEWPORTS_COUNT) {
- WARN_PRINT("Ignoring superfluous viewport settings from spatial editor state.");
- vp_size = VIEWPORTS_COUNT;
- }
-
- for (uint32_t i = 0; i < vp_size; i++) {
- viewports[i]->set_state(vp[i]);
- }
- }
-
- if (d.has("zfar"))
- settings_zfar->set_value(float(d["zfar"]));
- if (d.has("znear"))
- settings_znear->set_value(float(d["znear"]));
- if (d.has("fov"))
- settings_fov->set_value(float(d["fov"]));
- if (d.has("show_grid")) {
- bool use = d["show_grid"];
-
- if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) {
- _menu_item_pressed(MENU_VIEW_GRID);
- }
- }
-
- if (d.has("show_origin")) {
- bool use = d["show_origin"];
-
- if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN))) {
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), use);
- VisualServer::get_singleton()->instance_set_visible(origin_instance, use);
- }
- }
-
- if (d.has("gizmos_status")) {
- Dictionary gizmos_status = d["gizmos_status"];
- List<Variant> keys;
- gizmos_status.get_key_list(&keys);
-
- for (int j = 0; j < gizmo_plugins_by_name.size(); ++j) {
- if (!gizmo_plugins_by_name[j]->can_be_hidden()) continue;
- int state = EditorSpatialGizmoPlugin::VISIBLE;
- for (int i = 0; i < keys.size(); i++) {
- if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) {
- state = gizmos_status[keys[i]];
- break;
- }
- }
-
- gizmo_plugins_by_name.write[j]->set_state(state);
- }
- _update_gizmos_menu();
- }
-}
-
-void SpatialEditor::edit(Spatial *p_spatial) {
-
- if (p_spatial != selected) {
- if (selected) {
-
- Ref<EditorSpatialGizmo> seg = selected->get_gizmo();
- if (seg.is_valid()) {
- seg->set_selected(false);
- selected->update_gizmo();
- }
- }
-
- selected = p_spatial;
- over_gizmo_handle = -1;
-
- if (selected) {
-
- Ref<EditorSpatialGizmo> seg = selected->get_gizmo();
- if (seg.is_valid()) {
- seg->set_selected(true);
- selected->update_gizmo();
- }
- }
- }
-}
-
-void SpatialEditor::_snap_changed() {
-
- snap_translate_value = snap_translate->get_text().to_double();
- snap_rotate_value = snap_rotate->get_text().to_double();
- snap_scale_value = snap_scale->get_text().to_double();
-}
-
-void SpatialEditor::_snap_update() {
-
- snap_translate->set_text(String::num(snap_translate_value));
- snap_rotate->set_text(String::num(snap_rotate_value));
- snap_scale->set_text(String::num(snap_scale_value));
-}
-
-void SpatialEditor::_xform_dialog_action() {
-
- Transform t;
- //translation
- Vector3 scale;
- Vector3 rotate;
- Vector3 translate;
-
- for (int i = 0; i < 3; i++) {
- translate[i] = xform_translate[i]->get_text().to_double();
- rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_double());
- scale[i] = xform_scale[i]->get_text().to_double();
- }
-
- t.basis.scale(scale);
- t.basis.rotate(rotate);
- t.origin = translate;
-
- undo_redo->create_action(TTR("XForm Dialog"));
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (!sp)
- continue;
-
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
- if (!se)
- continue;
-
- bool post = xform_type->get_selected() > 0;
-
- Transform tr = sp->get_global_gizmo_transform();
- if (post)
- tr = tr * t;
- else {
-
- tr.basis = t.basis * tr.basis;
- tr.origin += t.origin;
- }
-
- undo_redo->add_do_method(sp, "set_global_transform", tr);
- undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
- }
- undo_redo->commit_action();
-}
-
-void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) {
-
- switch (p_option) {
- case MENU_TOOL_LOCAL_COORDS: {
-
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(pressed);
- update_transform_gizmo();
- } break;
-
- case MENU_TOOL_USE_SNAP: {
- tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
- snap_enabled = pressed;
- } break;
-
- case MENU_TOOL_OVERRIDE_CAMERA: {
- EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
-
- using Override = EditorDebuggerNode::CameraOverride;
- if (pressed) {
-
- debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
- } else {
- debugger->set_camera_override(Override::OVERRIDE_NONE);
- }
-
- } break;
- }
-}
-
-void SpatialEditor::_menu_gizmo_toggled(int p_option) {
-
- const int idx = gizmos_menu->get_item_index(p_option);
- gizmos_menu->toggle_item_multistate(idx);
-
- // Change icon
- const int state = gizmos_menu->get_item_state(idx);
- switch (state) {
- case EditorSpatialGizmoPlugin::VISIBLE:
- gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible"));
- break;
- case EditorSpatialGizmoPlugin::ON_TOP:
- gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray"));
- break;
- case EditorSpatialGizmoPlugin::HIDDEN:
- gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden"));
- break;
- }
-
- gizmo_plugins_by_name.write[p_option]->set_state(state);
-
- update_all_gizmos();
-}
-
-void SpatialEditor::_update_camera_override_button(bool p_game_running) {
- Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
-
- if (p_game_running) {
- button->set_disabled(false);
- button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
- } else {
- button->set_disabled(true);
- button->set_pressed(false);
- button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
- }
-}
-
-void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) {
- SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport);
-
- if (!current_viewport)
- return;
-
- EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
-
- camera_override_viewport_id = current_viewport->index;
- if (debugger->get_camera_override() >= EditorDebuggerNode::OVERRIDE_3D_1) {
- using Override = EditorDebuggerNode::CameraOverride;
-
- debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
- }
-}
-
-void SpatialEditor::_menu_item_pressed(int p_option) {
-
- switch (p_option) {
-
- case MENU_TOOL_SELECT:
- case MENU_TOOL_MOVE:
- case MENU_TOOL_ROTATE:
- case MENU_TOOL_SCALE:
- case MENU_TOOL_LIST_SELECT: {
-
- for (int i = 0; i < TOOL_MAX; i++)
- tool_button[i]->set_pressed(i == p_option);
- tool_mode = (ToolMode)p_option;
- update_transform_gizmo();
-
- } break;
- case MENU_TRANSFORM_CONFIGURE_SNAP: {
-
- snap_dialog->popup_centered(Size2(200, 180));
- } break;
- case MENU_TRANSFORM_DIALOG: {
-
- for (int i = 0; i < 3; i++) {
-
- xform_translate[i]->set_text("0");
- xform_rotate[i]->set_text("0");
- xform_scale[i]->set_text("1");
- }
-
- xform_dialog->popup_centered(Size2(320, 240) * EDSCALE);
-
- } break;
- case MENU_VIEW_USE_1_VIEWPORT: {
-
- viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_1_VIEWPORT);
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
-
- } break;
- case MENU_VIEW_USE_2_VIEWPORTS: {
-
- viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_2_VIEWPORTS);
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
-
- } break;
- case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
-
- viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT);
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
-
- } break;
- case MENU_VIEW_USE_3_VIEWPORTS: {
-
- viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_3_VIEWPORTS);
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
-
- } break;
- case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
-
- viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT);
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), true);
-
- } break;
- case MENU_VIEW_USE_4_VIEWPORTS: {
-
- viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_4_VIEWPORTS);
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
-
- } break;
- case MENU_VIEW_ORIGIN: {
-
- bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
-
- origin_enabled = !is_checked;
- VisualServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled);
- // Update the grid since its appearance depends on whether the origin is enabled
- _finish_grid();
- _init_grid();
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), origin_enabled);
- } break;
- case MENU_VIEW_GRID: {
-
- bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
-
- grid_enabled = !is_checked;
-
- for (int i = 0; i < 3; ++i) {
- if (grid_enable[i]) {
- VisualServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
- grid_visible[i] = grid_enabled;
- }
- }
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled);
-
- } break;
- case MENU_VIEW_CAMERA_SETTINGS: {
-
- settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
- } break;
- case MENU_SNAP_TO_FLOOR: {
- snap_selected_nodes_to_floor();
- } break;
- case MENU_LOCK_SELECTED: {
- undo_redo->create_action(TTR("Lock Selected"));
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *spatial = Object::cast_to<Spatial>(E->get());
- if (!spatial || !spatial->is_visible_in_tree())
- continue;
-
- if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
- continue;
-
- undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true);
- undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_");
- undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
- undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
- }
-
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
- undo_redo->commit_action();
- } break;
- case MENU_UNLOCK_SELECTED: {
- undo_redo->create_action(TTR("Unlock Selected"));
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *spatial = Object::cast_to<Spatial>(E->get());
- if (!spatial || !spatial->is_visible_in_tree())
- continue;
-
- if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
- continue;
-
- undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_");
- undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true);
- undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
- undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
- }
-
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
- undo_redo->commit_action();
- } break;
- case MENU_GROUP_SELECTED: {
- undo_redo->create_action(TTR("Group Selected"));
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *spatial = Object::cast_to<Spatial>(E->get());
- if (!spatial || !spatial->is_visible_in_tree())
- continue;
-
- if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
- continue;
-
- undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true);
- undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_");
- undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
- undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
- }
-
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
- undo_redo->commit_action();
- } break;
- case MENU_UNGROUP_SELECTED: {
- undo_redo->create_action(TTR("Ungroup Selected"));
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
-
- Spatial *spatial = Object::cast_to<Spatial>(E->get());
- if (!spatial || !spatial->is_visible_in_tree())
- continue;
-
- if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
- continue;
-
- undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_");
- undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true);
- undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
- undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
- }
-
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
- undo_redo->commit_action();
- } break;
- }
-}
-
-void SpatialEditor::_init_indicators() {
-
- {
- origin_enabled = true;
- grid_enabled = true;
-
- indicator_mat.instance();
- indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
-
- Vector<Color> origin_colors;
- Vector<Vector3> origin_points;
-
- for (int i = 0; i < 3; i++) {
- Vector3 axis;
- axis[i] = 1;
- Color origin_color;
- switch (i) {
- case 0:
- origin_color = get_color("axis_x_color", "Editor");
- break;
- case 1:
- origin_color = get_color("axis_y_color", "Editor");
- break;
- case 2:
- origin_color = get_color("axis_z_color", "Editor");
- break;
- default:
- origin_color = Color();
- break;
- }
-
- grid_enable[i] = false;
- grid_visible[i] = false;
-
- origin_colors.push_back(origin_color);
- origin_colors.push_back(origin_color);
- origin_points.push_back(axis * 4096);
- origin_points.push_back(axis * -4096);
- }
-
- grid_enable[1] = true;
- grid_visible[1] = true;
-
- _init_grid();
-
- origin = VisualServer::get_singleton()->mesh_create();
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[VisualServer::ARRAY_VERTEX] = origin_points;
- d[VisualServer::ARRAY_COLOR] = origin_colors;
-
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin, VisualServer::PRIMITIVE_LINES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid());
-
- origin_instance = VisualServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario());
- VS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
-
- VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, VS::SHADOW_CASTING_SETTING_OFF);
- }
-
- {
-
- //move gizmo
-
- for (int i = 0; i < 3; i++) {
-
- Color col;
- switch (i) {
- case 0:
- col = get_color("axis_x_color", "Editor");
- break;
- case 1:
- col = get_color("axis_y_color", "Editor");
- break;
- case 2:
- col = get_color("axis_z_color", "Editor");
- break;
- default:
- col = Color();
- break;
- }
-
- col.a = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_opacity");
-
- move_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
-
- Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
- mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- mat->set_on_top_of_alpha();
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- mat->set_albedo(col);
- gizmo_color[i] = mat;
-
- Ref<StandardMaterial3D> mat_hl = mat->duplicate();
- mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
- gizmo_color_hl[i] = mat_hl;
-
- Vector3 ivec;
- ivec[i] = 1;
- Vector3 nivec;
- nivec[(i + 1) % 3] = 1;
- nivec[(i + 2) % 3] = 1;
- Vector3 ivec2;
- ivec2[(i + 1) % 3] = 1;
- Vector3 ivec3;
- ivec3[(i + 2) % 3] = 1;
-
- //translate
- {
-
- Ref<SurfaceTool> surftool = memnew(SurfaceTool);
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- // Arrow profile
- const int arrow_points = 5;
- Vector3 arrow[5] = {
- nivec * 0.0 + ivec * 0.0,
- nivec * 0.01 + ivec * 0.0,
- nivec * 0.01 + ivec * GIZMO_ARROW_OFFSET,
- nivec * 0.065 + ivec * GIZMO_ARROW_OFFSET,
- nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
- };
-
- int arrow_sides = 16;
-
- for (int k = 0; k < arrow_sides; k++) {
-
- Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
- Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
-
- for (int j = 0; j < arrow_points - 1; j++) {
-
- Vector3 points[4] = {
- ma.xform(arrow[j]),
- mb.xform(arrow[j]),
- mb.xform(arrow[j + 1]),
- ma.xform(arrow[j + 1]),
- };
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[1]);
- surftool->add_vertex(points[2]);
-
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[2]);
- surftool->add_vertex(points[3]);
- }
- }
-
- surftool->set_material(mat);
- surftool->commit(move_gizmo[i]);
- }
-
- // Plane Translation
- {
- Ref<SurfaceTool> surftool = memnew(SurfaceTool);
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- Vector3 vec = ivec2 - ivec3;
- Vector3 plane[4] = {
- vec * GIZMO_PLANE_DST,
- vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
- vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
- vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
- };
-
- Basis ma(ivec, Math_PI / 2);
-
- Vector3 points[4] = {
- ma.xform(plane[0]),
- ma.xform(plane[1]),
- ma.xform(plane[2]),
- ma.xform(plane[3]),
- };
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[1]);
- surftool->add_vertex(points[2]);
-
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[2]);
- surftool->add_vertex(points[3]);
-
- Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D);
- plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- plane_mat->set_on_top_of_alpha();
- plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
- plane_mat->set_albedo(col);
- plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
- surftool->set_material(plane_mat);
- surftool->commit(move_plane_gizmo[i]);
-
- Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
- plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
- plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
- }
-
- // Rotate
- {
-
- Ref<SurfaceTool> surftool = memnew(SurfaceTool);
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- Vector3 circle[5] = {
- ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * -0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * -0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * 0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
- };
-
- for (int k = 0; k < 64; k++) {
-
- Basis ma(ivec, Math_PI * 2 * float(k) / 64);
- Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64);
-
- for (int j = 0; j < 4; j++) {
-
- Vector3 points[4] = {
- ma.xform(circle[j]),
- mb.xform(circle[j]),
- mb.xform(circle[j + 1]),
- ma.xform(circle[j + 1]),
- };
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[1]);
- surftool->add_vertex(points[2]);
-
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[2]);
- surftool->add_vertex(points[3]);
- }
- }
-
- surftool->set_material(mat);
- surftool->commit(rotate_gizmo[i]);
- }
-
- // Scale
- {
- Ref<SurfaceTool> surftool = memnew(SurfaceTool);
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- // Cube arrow profile
- const int arrow_points = 6;
- Vector3 arrow[6] = {
- nivec * 0.0 + ivec * 0.0,
- nivec * 0.01 + ivec * 0.0,
- nivec * 0.01 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
- nivec * 0.07 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
- nivec * 0.07 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
- nivec * 0.0 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
- };
-
- int arrow_sides = 4;
-
- for (int k = 0; k < 4; k++) {
-
- Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
- Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
-
- for (int j = 0; j < arrow_points - 1; j++) {
-
- Vector3 points[4] = {
- ma.xform(arrow[j]),
- mb.xform(arrow[j]),
- mb.xform(arrow[j + 1]),
- ma.xform(arrow[j + 1]),
- };
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[1]);
- surftool->add_vertex(points[2]);
-
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[2]);
- surftool->add_vertex(points[3]);
- }
- }
-
- surftool->set_material(mat);
- surftool->commit(scale_gizmo[i]);
- }
-
- // Plane Scale
- {
- Ref<SurfaceTool> surftool = memnew(SurfaceTool);
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
-
- Vector3 vec = ivec2 - ivec3;
- Vector3 plane[4] = {
- vec * GIZMO_PLANE_DST,
- vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
- vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
- vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
- };
-
- Basis ma(ivec, Math_PI / 2);
-
- Vector3 points[4] = {
- ma.xform(plane[0]),
- ma.xform(plane[1]),
- ma.xform(plane[2]),
- ma.xform(plane[3]),
- };
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[1]);
- surftool->add_vertex(points[2]);
-
- surftool->add_vertex(points[0]);
- surftool->add_vertex(points[2]);
- surftool->add_vertex(points[3]);
-
- Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D);
- plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- plane_mat->set_on_top_of_alpha();
- plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
- plane_mat->set_albedo(col);
- plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
- surftool->set_material(plane_mat);
- surftool->commit(scale_plane_gizmo[i]);
-
- Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate();
- plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
- plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
- }
- }
- }
-
- _generate_selection_box();
-}
-
-void SpatialEditor::_update_gizmos_menu() {
-
- gizmos_menu->clear();
-
- for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
- if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
- String plugin_name = gizmo_plugins_by_name[i]->get_name();
- const int plugin_state = gizmo_plugins_by_name[i]->get_state();
- gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i);
- const int idx = gizmos_menu->get_item_index(i);
- switch (plugin_state) {
- case EditorSpatialGizmoPlugin::VISIBLE:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
- break;
- case EditorSpatialGizmoPlugin::ON_TOP:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
- break;
- case EditorSpatialGizmoPlugin::HIDDEN:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
- break;
- }
- }
-}
-
-void SpatialEditor::_update_gizmos_menu_theme() {
- for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
- if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
- const int plugin_state = gizmo_plugins_by_name[i]->get_state();
- const int idx = gizmos_menu->get_item_index(i);
- switch (plugin_state) {
- case EditorSpatialGizmoPlugin::VISIBLE:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
- break;
- case EditorSpatialGizmoPlugin::ON_TOP:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
- break;
- case EditorSpatialGizmoPlugin::HIDDEN:
- gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
- break;
- }
- }
-}
-
-void SpatialEditor::_init_grid() {
-
- Vector<Color> grid_colors[3];
- Vector<Vector3> grid_points[3];
-
- Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color");
- Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color");
- int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size");
- int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps");
-
- for (int i = 0; i < 3; i++) {
- Vector3 axis;
- axis[i] = 1;
- Vector3 axis_n1;
- axis_n1[(i + 1) % 3] = 1;
- Vector3 axis_n2;
- axis_n2[(i + 2) % 3] = 1;
-
- for (int j = -grid_size; j <= grid_size; j++) {
- Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size;
- Vector3 p1_dest = p1 * (-axis_n2 + axis_n1);
- Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size;
- Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
-
- Color line_color = secondary_grid_color;
- if (origin_enabled && j == 0) {
- // Don't draw the center lines of the grid if the origin is enabled
- // The origin would overlap the grid lines in this case, causing flickering
- continue;
- } else if (j % primary_grid_steps == 0) {
- line_color = primary_grid_color;
- }
-
- grid_points[i].push_back(p1);
- grid_points[i].push_back(p1_dest);
- grid_colors[i].push_back(line_color);
- grid_colors[i].push_back(line_color);
-
- grid_points[i].push_back(p2);
- grid_points[i].push_back(p2_dest);
- grid_colors[i].push_back(line_color);
- grid_colors[i].push_back(line_color);
- }
-
- grid[i] = VisualServer::get_singleton()->mesh_create();
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[VisualServer::ARRAY_VERTEX] = grid_points[i];
- d[VisualServer::ARRAY_COLOR] = grid_colors[i];
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], VisualServer::PRIMITIVE_LINES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
- grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario());
-
- VisualServer::get_singleton()->instance_set_visible(grid_instance[i], grid_visible[i]);
- VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
- VS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
- }
-}
-
-void SpatialEditor::_finish_indicators() {
-
- VisualServer::get_singleton()->free(origin_instance);
- VisualServer::get_singleton()->free(origin);
-
- _finish_grid();
-}
-
-void SpatialEditor::_finish_grid() {
- for (int i = 0; i < 3; i++) {
- VisualServer::get_singleton()->free(grid_instance[i]);
- VisualServer::get_singleton()->free(grid[i]);
- }
-}
-
-bool SpatialEditor::is_any_freelook_active() const {
- for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) {
- if (viewports[i]->is_freelook_active())
- return true;
- }
- return false;
-}
-
-void SpatialEditor::_refresh_menu_icons() {
-
- bool all_locked = true;
- bool all_grouped = true;
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- if (selection.empty()) {
- all_locked = false;
- all_grouped = false;
- } else {
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_lock_")) {
- all_locked = false;
- break;
- }
- }
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_group_")) {
- all_grouped = false;
- break;
- }
- }
- }
-
- tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked);
- tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.empty());
- tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked);
-
- tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped);
- tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.empty());
- tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped);
-}
-
-template <typename T>
-Set<T *> _get_child_nodes(Node *parent_node) {
- Set<T *> nodes = Set<T *>();
- T *node = Node::cast_to<T>(parent_node);
- if (node) {
- nodes.insert(node);
- }
-
- for (int i = 0; i < parent_node->get_child_count(); i++) {
- Node *child_node = parent_node->get_child(i);
- Set<T *> child_nodes = _get_child_nodes<T>(child_node);
- for (typename Set<T *>::Element *I = child_nodes.front(); I; I = I->next()) {
- nodes.insert(I->get());
- }
- }
-
- return nodes;
-}
-
-Set<RID> _get_physics_bodies_rid(Node *node) {
- Set<RID> rids = Set<RID>();
- PhysicsBody *pb = Node::cast_to<PhysicsBody>(node);
- if (pb) {
- rids.insert(pb->get_rid());
- }
- Set<PhysicsBody *> child_nodes = _get_child_nodes<PhysicsBody>(node);
- for (Set<PhysicsBody *>::Element *I = child_nodes.front(); I; I = I->next()) {
- rids.insert(I->get()->get_rid());
- }
-
- return rids;
-}
-
-void SpatialEditor::snap_selected_nodes_to_floor() {
- List<Node *> &selection = editor_selection->get_selected_node_list();
- Dictionary snap_data;
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- Spatial *sp = Object::cast_to<Spatial>(E->get());
- if (sp) {
- Vector3 from = Vector3();
- Vector3 position_offset = Vector3();
-
- // Priorities for snapping to floor are CollisionShapes, VisualInstances and then origin
- Set<VisualInstance *> vi = _get_child_nodes<VisualInstance>(sp);
- Set<CollisionShape *> cs = _get_child_nodes<CollisionShape>(sp);
-
- if (cs.size()) {
- AABB aabb = sp->get_global_transform().xform(cs.front()->get()->get_shape()->get_debug_mesh()->get_aabb());
- for (Set<CollisionShape *>::Element *I = cs.front(); I; I = I->next()) {
- aabb.merge_with(sp->get_global_transform().xform(I->get()->get_shape()->get_debug_mesh()->get_aabb()));
- }
- Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
- from = aabb.position + size;
- position_offset.y = from.y - sp->get_global_transform().origin.y;
- } else if (vi.size()) {
- AABB aabb = vi.front()->get()->get_transformed_aabb();
- for (Set<VisualInstance *>::Element *I = vi.front(); I; I = I->next()) {
- aabb.merge_with(I->get()->get_transformed_aabb());
- }
- Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
- from = aabb.position + size;
- position_offset.y = from.y - sp->get_global_transform().origin.y;
- } else {
- from = sp->get_global_transform().origin;
- }
-
- // We add a bit of margin to the from position to avoid it from snapping
- // when the spatial is already on a floor and there's another floor under
- // it
- from = from + Vector3(0.0, 0.2, 0.0);
-
- Dictionary d;
-
- d["from"] = from;
- d["position_offset"] = position_offset;
- snap_data[sp] = d;
- }
- }
-
- PhysicsDirectSpaceState *ss = get_tree()->get_root()->get_world()->get_direct_space_state();
- PhysicsDirectSpaceState::RayResult result;
-
- Array keys = snap_data.keys();
-
- // The maximum height an object can travel to be snapped
- const float max_snap_height = 20.0;
-
- // Will be set to `true` if at least one node from the selection was successfully snapped
- bool snapped_to_floor = false;
-
- if (keys.size()) {
- // For snapping to be performed, there must be solid geometry under at least one of the selected nodes.
- // We need to check this before snapping to register the undo/redo action only if needed.
- for (int i = 0; i < keys.size(); i++) {
- Node *node = keys[i];
- Spatial *sp = Object::cast_to<Spatial>(node);
- Dictionary d = snap_data[node];
- Vector3 from = d["from"];
- Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
- Set<RID> excluded = _get_physics_bodies_rid(sp);
-
- if (ss->intersect_ray(from, to, result, excluded)) {
- snapped_to_floor = true;
- }
- }
-
- if (snapped_to_floor) {
- undo_redo->create_action(TTR("Snap Nodes To Floor"));
-
- // Perform snapping if at least one node can be snapped
- for (int i = 0; i < keys.size(); i++) {
- Node *node = keys[i];
- Spatial *sp = Object::cast_to<Spatial>(node);
- Dictionary d = snap_data[node];
- Vector3 from = d["from"];
- Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
- Set<RID> excluded = _get_physics_bodies_rid(sp);
-
- if (ss->intersect_ray(from, to, result, excluded)) {
- Vector3 position_offset = d["position_offset"];
- Transform new_transform = sp->get_global_transform();
-
- new_transform.origin.y = result.position.y;
- new_transform.origin = new_transform.origin - position_offset;
-
- undo_redo->add_do_method(sp, "set_global_transform", new_transform);
- undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
- }
- }
-
- undo_redo->commit_action();
- } else {
- EditorNode::get_singleton()->show_warning(TTR("Couldn't find a solid floor to snap the selection to."));
- }
- }
-}
-
-void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
-
- if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
- return;
-
- snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
-}
-void SpatialEditor::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_READY) {
-
- tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons"));
-
- tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
- tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
- tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "EditorIcons"));
-
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons"));
-
- _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
-
- _refresh_menu_icons();
-
- get_tree()->connect("node_removed", callable_mp(this, &SpatialEditor::_node_removed));
- EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", callable_mp(this, &SpatialEditor::_refresh_menu_icons));
- editor_selection->connect("selection_changed", callable_mp(this, &SpatialEditor::_refresh_menu_icons));
-
- editor->connect("stop_pressed", callable_mp(this, &SpatialEditor::_update_camera_override_button), make_binds(false));
- editor->connect("play_pressed", callable_mp(this, &SpatialEditor::_update_camera_override_button), make_binds(true));
- } 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();
- } else if (p_what == NOTIFICATION_EXIT_TREE) {
-
- _finish_indicators();
- } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons"));
- tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons"));
-
- tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
- tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
-
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons"));
-
- // Update grid color by rebuilding grid.
- _finish_grid();
- _init_grid();
- } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
- EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
-
- debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
- }
- }
-}
-
-void SpatialEditor::add_control_to_menu_panel(Control *p_control) {
-
- hbc_menu->add_child(p_control);
-}
-
-void SpatialEditor::remove_control_from_menu_panel(Control *p_control) {
-
- hbc_menu->remove_child(p_control);
-}
-
-void SpatialEditor::set_can_preview(Camera *p_preview) {
-
- for (int i = 0; i < 4; i++) {
- viewports[i]->set_can_preview(p_preview);
- }
-}
-
-VSplitContainer *SpatialEditor::get_shader_split() {
-
- return shader_split;
-}
-
-HSplitContainer *SpatialEditor::get_palette_split() {
-
- return palette_split;
-}
-
-void SpatialEditor::_request_gizmo(Object *p_obj) {
-
- Spatial *sp = Object::cast_to<Spatial>(p_obj);
- if (!sp)
- return;
- if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) {
-
- Ref<EditorSpatialGizmo> seg;
-
- for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) {
- seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp);
-
- if (seg.is_valid()) {
- sp->set_gizmo(seg);
-
- if (sp == selected) {
- seg->set_selected(true);
- selected->update_gizmo();
- }
-
- break;
- }
- }
- }
-}
-
-void SpatialEditor::_toggle_maximize_view(Object *p_viewport) {
- if (!p_viewport) return;
- SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport);
- if (!current_viewport) return;
-
- int index = -1;
- bool maximized = false;
- for (int i = 0; i < 4; i++) {
- if (viewports[i] == current_viewport) {
- index = i;
- if (current_viewport->get_global_rect() == viewport_base->get_global_rect())
- maximized = true;
- break;
- }
- }
- if (index == -1) return;
-
- if (!maximized) {
-
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
- if (i == (uint32_t)index)
- viewports[i]->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- else
- viewports[i]->hide();
- }
- } else {
-
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++)
- viewports[i]->show();
-
- if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
- _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
- _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
- _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
- _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
- _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
- else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
- _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
- }
-}
-
-void SpatialEditor::_node_removed(Node *p_node) {
-
- if (p_node == selected)
- selected = NULL;
-}
-
-void SpatialEditor::_register_all_gizmos() {
- add_gizmo_plugin(Ref<CameraSpatialGizmoPlugin>(memnew(CameraSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<LightSpatialGizmoPlugin>(memnew(LightSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<AudioStreamPlayer3DSpatialGizmoPlugin>(memnew(AudioStreamPlayer3DSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<SpringArmSpatialGizmoPlugin>(memnew(SpringArmSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
- add_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin)));
- add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin)));
- add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
- add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
- // add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
- add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<JointSpatialGizmoPlugin>(memnew(JointSpatialGizmoPlugin)));
- add_gizmo_plugin(Ref<PhysicalBoneSpatialGizmoPlugin>(memnew(PhysicalBoneSpatialGizmoPlugin)));
-}
-
-void SpatialEditor::_bind_methods() {
-
- ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input);
- ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data);
- ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
-
- ADD_SIGNAL(MethodInfo("transform_key_request"));
- ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
- ADD_SIGNAL(MethodInfo("item_group_status_changed"));
-}
-
-void SpatialEditor::clear() {
-
- settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
- settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
- settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0));
-
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
- viewports[i]->reset();
- }
-
- VisualServer::get_singleton()->instance_set_visible(origin_instance, true);
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
- for (int i = 0; i < 3; ++i) {
- if (grid_enable[i]) {
- VisualServer::get_singleton()->instance_set_visible(grid_instance[i], true);
- grid_visible[i] = true;
- }
- }
-
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
-
- viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
- viewports[i]->viewport->set_as_audio_listener(i == 0);
- }
-
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
-}
-
-SpatialEditor::SpatialEditor(EditorNode *p_editor) {
-
- gizmo.visible = true;
- gizmo.scale = 1.0;
-
- viewport_environment = Ref<Environment>(memnew(Environment));
- undo_redo = p_editor->get_undo_redo();
- VBoxContainer *vbc = this;
-
- custom_camera = NULL;
- singleton = this;
- editor = p_editor;
- editor_selection = editor->get_editor_selection();
- editor_selection->add_editor_plugin(this);
-
- snap_enabled = false;
- snap_key_enabled = false;
- tool_mode = TOOL_MODE_SELECT;
-
- camera_override_viewport_id = 0;
-
- hbc_menu = memnew(HBoxContainer);
- vbc->add_child(hbc_menu);
-
- Vector<Variant> button_binds;
- button_binds.resize(1);
- String sct;
-
- tool_button[TOOL_MODE_SELECT] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
- tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
- tool_button[TOOL_MODE_SELECT]->set_flat(true);
- tool_button[TOOL_MODE_SELECT]->set_pressed(true);
- button_binds.write[0] = MENU_TOOL_SELECT;
- tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q));
- tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection"));
-
- hbc_menu->add_child(memnew(VSeparator));
-
- tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
- tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
- tool_button[TOOL_MODE_MOVE]->set_flat(true);
- button_binds.write[0] = MENU_TOOL_MOVE;
- tool_button[TOOL_MODE_MOVE]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
-
- tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
- tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
- tool_button[TOOL_MODE_ROTATE]->set_flat(true);
- button_binds.write[0] = MENU_TOOL_ROTATE;
- tool_button[TOOL_MODE_ROTATE]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
-
- tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
- tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
- tool_button[TOOL_MODE_SCALE]->set_flat(true);
- button_binds.write[0] = MENU_TOOL_SCALE;
- tool_button[TOOL_MODE_SCALE]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
-
- hbc_menu->add_child(memnew(VSeparator));
-
- tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
- tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
- tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
- button_binds.write[0] = MENU_TOOL_LIST_SELECT;
- tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
-
- tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]);
- button_binds.write[0] = MENU_LOCK_SELECTED;
- tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
-
- tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
- button_binds.write[0] = MENU_UNLOCK_SELECTED;
- tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
-
- tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
- button_binds.write[0] = MENU_GROUP_SELECTED;
- tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
-
- tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton);
- hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
- button_binds.write[0] = MENU_UNGROUP_SELECTED;
- tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
-
- hbc_menu->add_child(memnew(VSeparator));
-
- tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton);
- hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true);
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
- button_binds.write[0] = MENU_TOOL_LOCAL_COORDS;
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", callable_mp(this, &SpatialEditor::_menu_item_toggled), button_binds);
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
-
- tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton);
- hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
- tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true);
- tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
- button_binds.write[0] = MENU_TOOL_USE_SNAP;
- tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", callable_mp(this, &SpatialEditor::_menu_item_toggled), button_binds);
- tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y));
-
- hbc_menu->add_child(memnew(VSeparator));
-
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
- hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
- button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA;
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", callable_mp(this, &SpatialEditor::_menu_item_toggled), button_binds);
- _update_camera_override_button(false);
-
- hbc_menu->add_child(memnew(VSeparator));
-
- // Drag and drop support;
- preview_node = memnew(Spatial);
- preview_bounds = AABB();
-
- ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7);
- ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7);
- ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KEY_MASK_ALT + KEY_KP_1);
- ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1);
- ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT + KEY_KP_3);
- ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3);
- ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal View"), KEY_KP_5);
- ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K);
- ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O);
- ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
- ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M);
- ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F);
- ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F);
-
- PopupMenu *p;
-
- transform_menu = memnew(MenuButton);
- transform_menu->set_text(TTR("Transform"));
- transform_menu->set_switch_on_hover(true);
- hbc_menu->add_child(transform_menu);
-
- p = transform_menu->get_popup();
- p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR);
- p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG);
-
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP);
-
- p->connect("id_pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed));
-
- view_menu = memnew(MenuButton);
- view_menu->set_text(TTR("View"));
- view_menu->set_switch_on_hover(true);
- hbc_menu->add_child(view_menu);
-
- p = view_menu->get_popup();
-
- accept = memnew(AcceptDialog);
- editor->get_gui_base()->add_child(accept);
-
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
- p->add_separator();
-
- p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
-
- p->add_separator();
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
-
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
-
- p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
- p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
-
- p->connect("id_pressed", callable_mp(this, &SpatialEditor::_menu_item_pressed));
-
- gizmos_menu = memnew(PopupMenu);
- p->add_child(gizmos_menu);
- gizmos_menu->set_name("GizmosMenu");
- gizmos_menu->set_hide_on_checkable_item_selection(false);
- gizmos_menu->connect("id_pressed", callable_mp(this, &SpatialEditor::_menu_gizmo_toggled));
-
- /* REST OF MENU */
-
- palette_split = memnew(HSplitContainer);
- palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
- vbc->add_child(palette_split);
-
- shader_split = memnew(VSplitContainer);
- shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
- palette_split->add_child(shader_split);
- viewport_base = memnew(SpatialEditorViewportContainer);
- shader_split->add_child(viewport_base);
- viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
-
- viewports[i] = memnew(SpatialEditorViewport(this, editor, i));
- viewports[i]->connect("toggle_maximize_view", callable_mp(this, &SpatialEditor::_toggle_maximize_view));
- viewports[i]->connect("clicked", callable_mp(this, &SpatialEditor::_update_camera_override_viewport));
- viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
- viewport_base->add_child(viewports[i]);
- }
-
- /* SNAP DIALOG */
-
- snap_translate_value = 1;
- snap_rotate_value = 15;
- snap_scale_value = 10;
-
- snap_dialog = memnew(ConfirmationDialog);
- snap_dialog->set_title(TTR("Snap Settings"));
- add_child(snap_dialog);
- snap_dialog->connect("confirmed", callable_mp(this, &SpatialEditor::_snap_changed));
- snap_dialog->get_cancel()->connect("pressed", callable_mp(this, &SpatialEditor::_snap_update));
-
- VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
- snap_dialog->add_child(snap_dialog_vbc);
-
- snap_translate = memnew(LineEdit);
- snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
-
- snap_rotate = memnew(LineEdit);
- snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
-
- snap_scale = memnew(LineEdit);
- snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
-
- _snap_update();
-
- /* SETTINGS DIALOG */
-
- settings_dialog = memnew(ConfirmationDialog);
- settings_dialog->set_title(TTR("Viewport Settings"));
- add_child(settings_dialog);
- settings_vbc = memnew(VBoxContainer);
- settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
- settings_dialog->add_child(settings_vbc);
-
- settings_fov = memnew(SpinBox);
- settings_fov->set_max(MAX_FOV);
- settings_fov->set_min(MIN_FOV);
- settings_fov->set_step(0.01);
- settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
- settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
-
- settings_znear = memnew(SpinBox);
- settings_znear->set_max(MAX_Z);
- settings_znear->set_min(MIN_Z);
- settings_znear->set_step(0.01);
- settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
- settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
-
- settings_zfar = memnew(SpinBox);
- settings_zfar->set_max(MAX_Z);
- settings_zfar->set_min(MIN_Z);
- settings_zfar->set_step(0.01);
- settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500));
- settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
-
- /* XFORM DIALOG */
-
- xform_dialog = memnew(ConfirmationDialog);
- xform_dialog->set_title(TTR("Transform Change"));
- add_child(xform_dialog);
-
- VBoxContainer *xform_vbc = memnew(VBoxContainer);
- xform_dialog->add_child(xform_vbc);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Translate:"));
- xform_vbc->add_child(l);
-
- HBoxContainer *xform_hbc = memnew(HBoxContainer);
- xform_vbc->add_child(xform_hbc);
-
- for (int i = 0; i < 3; i++) {
-
- xform_translate[i] = memnew(LineEdit);
- xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
- xform_hbc->add_child(xform_translate[i]);
- }
-
- l = memnew(Label);
- l->set_text(TTR("Rotate (deg.):"));
- xform_vbc->add_child(l);
-
- xform_hbc = memnew(HBoxContainer);
- xform_vbc->add_child(xform_hbc);
-
- for (int i = 0; i < 3; i++) {
- xform_rotate[i] = memnew(LineEdit);
- xform_rotate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
- xform_hbc->add_child(xform_rotate[i]);
- }
-
- l = memnew(Label);
- l->set_text(TTR("Scale (ratio):"));
- xform_vbc->add_child(l);
-
- xform_hbc = memnew(HBoxContainer);
- xform_vbc->add_child(xform_hbc);
-
- for (int i = 0; i < 3; i++) {
- xform_scale[i] = memnew(LineEdit);
- xform_scale[i]->set_h_size_flags(SIZE_EXPAND_FILL);
- xform_hbc->add_child(xform_scale[i]);
- }
-
- l = memnew(Label);
- l->set_text(TTR("Transform Type"));
- xform_vbc->add_child(l);
-
- xform_type = memnew(OptionButton);
- xform_type->set_h_size_flags(SIZE_EXPAND_FILL);
- xform_type->add_item(TTR("Pre"));
- xform_type->add_item(TTR("Post"));
- xform_vbc->add_child(xform_type);
-
- xform_dialog->connect("confirmed", callable_mp(this, &SpatialEditor::_xform_dialog_action));
-
- scenario_debug = VisualServer::SCENARIO_DEBUG_DISABLED;
-
- selected = NULL;
-
- set_process_unhandled_key_input(true);
- add_to_group("_spatial_editor_group");
-
- EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,1024,1"));
- EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.4);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::FLOAT, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"));
- EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
-
- over_gizmo_handle = -1;
-}
-
-SpatialEditor::~SpatialEditor() {
- memdelete(preview_node);
-}
-
-void SpatialEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
-
- spatial_editor->show();
- spatial_editor->set_process(true);
-
- } else {
-
- spatial_editor->hide();
- spatial_editor->set_process(false);
- }
-}
-void SpatialEditorPlugin::edit(Object *p_object) {
-
- spatial_editor->edit(Object::cast_to<Spatial>(p_object));
-}
-
-bool SpatialEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Spatial");
-}
-
-Dictionary SpatialEditorPlugin::get_state() const {
- return spatial_editor->get_state();
-}
-
-void SpatialEditorPlugin::set_state(const Dictionary &p_state) {
-
- spatial_editor->set_state(p_state);
-}
-
-void SpatialEditor::snap_cursor_to_plane(const Plane &p_plane) {
-
- //cursor.pos=p_plane.project(cursor.pos);
-}
-
-Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
- if (is_snap_enabled()) {
- p_target.x = Math::snap_scalar(0.0, get_translate_snap(), p_target.x);
- p_target.y = Math::snap_scalar(0.0, get_translate_snap(), p_target.y);
- p_target.z = Math::snap_scalar(0.0, get_translate_snap(), p_target.z);
- }
- return p_target;
-}
-
-float SpatialEditor::get_translate_snap() const {
- float snap_value;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
- snap_value = snap_translate->get_text().to_double() / 10.0;
- } else {
- snap_value = snap_translate->get_text().to_double();
- }
-
- return snap_value;
-}
-
-float SpatialEditor::get_rotate_snap() const {
- float snap_value;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
- snap_value = snap_rotate->get_text().to_double() / 3.0;
- } else {
- snap_value = snap_rotate->get_text().to_double();
- }
-
- return snap_value;
-}
-
-float SpatialEditor::get_scale_snap() const {
- float snap_value;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
- snap_value = snap_scale->get_text().to_double() / 2.0;
- } else {
- snap_value = snap_scale->get_text().to_double();
- }
-
- return snap_value;
-}
-
-void SpatialEditorPlugin::_bind_methods() {
-
- ClassDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane);
-}
-
-void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
-
- spatial_editor->snap_cursor_to_plane(p_plane);
-}
-
-struct _GizmoPluginPriorityComparator {
-
- bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &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_priority() > p_b->get_priority();
- }
-};
-
-struct _GizmoPluginNameComparator {
-
- bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
- return p_a->get_name() < p_b->get_name();
- }
-};
-
-void SpatialEditor::add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) {
- ERR_FAIL_NULL(p_plugin.ptr());
-
- gizmo_plugins_by_priority.push_back(p_plugin);
- gizmo_plugins_by_priority.sort_custom<_GizmoPluginPriorityComparator>();
-
- gizmo_plugins_by_name.push_back(p_plugin);
- gizmo_plugins_by_name.sort_custom<_GizmoPluginNameComparator>();
-
- _update_gizmos_menu();
- SpatialEditor::get_singleton()->update_all_gizmos();
-}
-
-void SpatialEditor::remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) {
- gizmo_plugins_by_priority.erase(p_plugin);
- gizmo_plugins_by_name.erase(p_plugin);
- _update_gizmos_menu();
-}
-
-SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- spatial_editor = memnew(SpatialEditor(p_node));
- spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- editor->get_viewport()->add_child(spatial_editor);
-
- spatial_editor->hide();
- spatial_editor->connect_compat("transform_key_request", editor->get_inspector_dock(), "_transform_keyed");
-}
-
-SpatialEditorPlugin::~SpatialEditorPlugin() {
-}
-
-void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
-
- Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
-
- Vector<Ref<StandardMaterial3D> > mats;
-
- for (int i = 0; i < 4; i++) {
- bool selected = i % 2 == 1;
- bool instanced = i < 2;
-
- Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
-
- Color color = instanced ? instanced_color : p_color;
-
- if (!selected) {
- color.a *= 0.3;
- }
-
- material->set_albedo(color);
- material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
-
- if (p_use_vertex_color) {
- material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- }
-
- if (p_billboard) {
- material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
- }
-
- if (p_on_top && selected) {
- material->set_on_top_of_alpha();
- }
-
- mats.push_back(material);
- }
-
- materials[p_name] = mats;
-}
-
-void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) {
-
- Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
-
- Vector<Ref<StandardMaterial3D> > icons;
-
- for (int i = 0; i < 4; i++) {
- bool selected = i % 2 == 1;
- bool instanced = i < 2;
-
- Ref<StandardMaterial3D> icon = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
-
- Color color = instanced ? instanced_color : p_albedo;
-
- if (!selected) {
- color.a *= 0.85;
- }
-
- icon->set_albedo(color);
-
- icon->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- icon->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- icon->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- icon->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
- icon->set_depth_draw_mode(StandardMaterial3D::DEPTH_DRAW_DISABLED);
- icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- icon->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, p_texture);
- icon->set_flag(StandardMaterial3D::FLAG_FIXED_SIZE, true);
- icon->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
- icon->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN);
-
- if (p_on_top && selected) {
- icon->set_on_top_of_alpha();
- }
-
- icons.push_back(icon);
- }
-
- materials[p_name] = icons;
-}
-
-void EditorSpatialGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) {
- Ref<StandardMaterial3D> handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
-
- handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
- Ref<Texture2D> handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons");
- handle_material->set_point_size(handle_t->get_width());
- handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle_t);
- handle_material->set_albedo(Color(1, 1, 1));
- handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- handle_material->set_on_top_of_alpha();
- if (p_billboard) {
- handle_material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
- handle_material->set_on_top_of_alpha();
- }
-
- materials[p_name] = Vector<Ref<StandardMaterial3D> >();
- materials[p_name].push_back(handle_material);
-}
-
-void EditorSpatialGizmoPlugin::add_material(const String &p_name, Ref<StandardMaterial3D> p_material) {
- materials[p_name] = Vector<Ref<StandardMaterial3D> >();
- materials[p_name].push_back(p_material);
-}
-
-Ref<StandardMaterial3D> EditorSpatialGizmoPlugin::get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo) {
- ERR_FAIL_COND_V(!materials.has(p_name), Ref<StandardMaterial3D>());
- ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<StandardMaterial3D>());
-
- if (p_gizmo.is_null() || materials[p_name].size() == 1) return materials[p_name][0];
-
- int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0);
-
- Ref<StandardMaterial3D> mat = materials[p_name][index];
-
- if (current_state == ON_TOP && p_gizmo->is_selected()) {
- mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
- } else {
- mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, false);
- }
-
- return mat;
-}
-
-String EditorSpatialGizmoPlugin::get_name() const {
- if (get_script_instance() && get_script_instance()->has_method("get_name")) {
- return get_script_instance()->call("get_name");
- }
- return TTR("Nameless gizmo");
-}
-
-int EditorSpatialGizmoPlugin::get_priority() const {
- if (get_script_instance() && get_script_instance()->has_method("get_priority")) {
- return get_script_instance()->call("get_priority");
- }
- return 0;
-}
-
-Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) {
-
- if (get_script_instance() && get_script_instance()->has_method("get_gizmo")) {
- return get_script_instance()->call("get_gizmo", p_spatial);
- }
-
- Ref<EditorSpatialGizmo> ref = create_gizmo(p_spatial);
-
- if (ref.is_null()) return ref;
-
- ref->set_plugin(this);
- ref->set_spatial_node(p_spatial);
- ref->set_hidden(current_state == HIDDEN);
-
- current_gizmos.push_back(ref.ptr());
- return ref;
-}
-
-void EditorSpatialGizmoPlugin::_bind_methods() {
-#define GIZMO_REF PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "EditorSpatialGizmo")
-
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial")));
- BIND_VMETHOD(MethodInfo(GIZMO_REF, "create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial")));
-
- ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorSpatialGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorSpatialGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1)));
- ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard"), &EditorSpatialGizmoPlugin::create_handle_material, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorSpatialGizmoPlugin::add_material);
-
- ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorSpatialGizmoPlugin::get_material); //, DEFVAL(Ref<EditorSpatialGizmo>()));
-
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_priority"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden"));
-
- BIND_VMETHOD(MethodInfo("redraw", GIZMO_REF));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
-
- MethodInfo hvget(Variant::NIL, "get_handle_value", GIZMO_REF, PropertyInfo(Variant::INT, "index"));
- hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(hvget);
-
- BIND_VMETHOD(MethodInfo("set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::VECTOR2, "point")));
- MethodInfo cm = MethodInfo("commit_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel"));
- cm.default_arguments.push_back(false);
- BIND_VMETHOD(cm);
-
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
-
-#undef GIZMO_REF
-}
-
-bool EditorSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- if (get_script_instance() && get_script_instance()->has_method("has_gizmo")) {
- return get_script_instance()->call("has_gizmo", p_spatial);
- }
- return false;
-}
-
-Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) {
-
- if (get_script_instance() && get_script_instance()->has_method("create_gizmo")) {
- return get_script_instance()->call("create_gizmo", p_spatial);
- }
-
- Ref<EditorSpatialGizmo> ref;
- if (has_gizmo(p_spatial)) ref.instance();
- return ref;
-}
-
-bool EditorSpatialGizmoPlugin::can_be_hidden() const {
- if (get_script_instance() && get_script_instance()->has_method("can_be_hidden")) {
- return get_script_instance()->call("can_be_hidden");
- }
- return true;
-}
-
-bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const {
- if (get_script_instance() && get_script_instance()->has_method("is_selectable_when_hidden")) {
- return get_script_instance()->call("is_selectable_when_hidden");
- }
- return false;
-}
-
-void EditorSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- if (get_script_instance() && get_script_instance()->has_method("redraw")) {
- Ref<EditorSpatialGizmo> ref(p_gizmo);
- get_script_instance()->call("redraw", ref);
- }
-}
-
-String EditorSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
- if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) {
- return get_script_instance()->call("get_handle_name", p_gizmo, p_idx);
- }
- return "";
-}
-
-Variant EditorSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
- if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) {
- return get_script_instance()->call("get_handle_value", p_gizmo, p_idx);
- }
- return Variant();
-}
-
-void EditorSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
- if (get_script_instance() && get_script_instance()->has_method("set_handle")) {
- get_script_instance()->call("set_handle", p_gizmo, p_idx, p_camera, p_point);
- }
-}
-
-void EditorSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
- if (get_script_instance() && get_script_instance()->has_method("commit_handle")) {
- get_script_instance()->call("commit_handle", p_gizmo, p_idx, p_restore, p_cancel);
- }
-}
-
-bool EditorSpatialGizmoPlugin::is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
- if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) {
- return get_script_instance()->call("is_handle_highlighted", p_gizmo, p_idx);
- }
- return false;
-}
-
-void EditorSpatialGizmoPlugin::set_state(int p_state) {
- current_state = p_state;
- for (int i = 0; i < current_gizmos.size(); ++i) {
- current_gizmos[i]->set_hidden(current_state == HIDDEN);
- }
-}
-
-int EditorSpatialGizmoPlugin::get_state() const {
- return current_state;
-}
-
-void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) {
- current_gizmos.erase(p_gizmo);
-}
-
-EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() {
- current_state = VISIBLE;
-}
-
-EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() {
- for (int i = 0; i < current_gizmos.size(); ++i) {
- current_gizmos[i]->set_plugin(NULL);
- current_gizmos[i]->get_spatial_node()->set_gizmo(NULL);
- }
- if (SpatialEditor::get_singleton()) {
- SpatialEditor::get_singleton()->update_all_gizmos();
- }
-}
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
deleted file mode 100644
index 489bce1e15..0000000000
--- a/editor/plugins/spatial_editor_plugin.h
+++ /dev/null
@@ -1,879 +0,0 @@
-/*************************************************************************/
-/* spatial_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPATIAL_EDITOR_PLUGIN_H
-#define SPATIAL_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "editor/editor_scale.h"
-#include "scene/3d/immediate_geometry.h"
-#include "scene/3d/light.h"
-#include "scene/3d/visual_instance.h"
-#include "scene/gui/panel_container.h"
-
-class Camera;
-class SpatialEditor;
-class EditorSpatialGizmoPlugin;
-class SpatialEditorViewport;
-class ViewportContainer;
-
-class EditorSpatialGizmo : public SpatialGizmo {
-
- GDCLASS(EditorSpatialGizmo, SpatialGizmo);
-
- bool selected;
- bool instanced;
-
-public:
- void set_selected(bool p_selected) { selected = p_selected; }
- bool is_selected() const { return selected; }
-
- struct Instance {
-
- RID instance;
- Ref<ArrayMesh> mesh;
- Ref<Material> material;
- Ref<SkinReference> skin_reference;
- RID skeleton;
- bool billboard;
- bool unscaled;
- bool can_intersect;
- bool extra_margin;
- Instance() {
-
- billboard = false;
- unscaled = false;
- can_intersect = false;
- extra_margin = false;
- }
-
- void create_instance(Spatial *p_base, bool p_hidden = false);
- };
-
- Vector<Vector3> collision_segments;
- Ref<TriangleMesh> collision_mesh;
-
- struct Handle {
- Vector3 pos;
- bool billboard;
- };
-
- Vector<Vector3> handles;
- Vector<Vector3> secondary_handles;
- float selectable_icon_size;
- bool billboard_handle;
-
- bool valid;
- bool hidden;
- Spatial *base;
- Vector<Instance> instances;
- Spatial *spatial_node;
- EditorSpatialGizmoPlugin *gizmo_plugin;
-
- void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); }
-
-protected:
- static void _bind_methods();
-
-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_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);
- void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1, const Color &p_modulate = Color(1, 1, 1));
- void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard = false, bool p_secondary = false);
- void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3());
-
- virtual bool is_handle_highlighted(int p_idx) const;
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx);
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- void set_spatial_node(Spatial *p_node);
- Spatial *get_spatial_node() const { return spatial_node; }
- Ref<EditorSpatialGizmoPlugin> get_plugin() const { return gizmo_plugin; }
- Vector3 get_handle_pos(int p_idx) const;
- bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum);
- bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false);
-
- virtual void clear();
- virtual void create();
- virtual void transform();
- virtual void redraw();
- virtual void free();
-
- virtual bool is_editable() const;
-
- void set_hidden(bool p_hidden);
- void set_plugin(EditorSpatialGizmoPlugin *p_plugin);
-
- EditorSpatialGizmo();
- ~EditorSpatialGizmo();
-};
-
-class ViewportRotationControl : public Control {
- GDCLASS(ViewportRotationControl, Control);
-
- struct Axis2D {
- Vector2i screen_point;
- float z_axis = -99.0;
- int axis = -1;
- };
-
- struct Axis2DCompare {
- _FORCE_INLINE_ bool operator()(const Axis2D &l, const Axis2D &r) const {
- return l.z_axis < r.z_axis;
- }
- };
-
- SpatialEditorViewport *viewport = nullptr;
- Vector<Color> axis_colors;
- Vector<int> axis_menu_options;
- bool orbiting = false;
- int focused_axis = -2;
-
- const float AXIS_CIRCLE_RADIUS = 8.0f * EDSCALE;
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
- void _gui_input(Ref<InputEvent> p_event);
- void _draw();
- void _draw_axis(const Axis2D &p_axis);
- void _get_sorted_axis(Vector<Axis2D> &r_axis);
- void _update_focus();
- void _on_mouse_exited();
-
-public:
- void set_viewport(SpatialEditorViewport *p_viewport);
-};
-
-class SpatialEditorViewport : public Control {
-
- GDCLASS(SpatialEditorViewport, Control);
- friend class SpatialEditor;
- friend class ViewportRotationControl;
- enum {
-
- VIEW_TOP,
- VIEW_BOTTOM,
- VIEW_LEFT,
- VIEW_RIGHT,
- VIEW_FRONT,
- VIEW_REAR,
- VIEW_CENTER_TO_ORIGIN,
- VIEW_CENTER_TO_SELECTION,
- VIEW_ALIGN_TRANSFORM_WITH_VIEW,
- VIEW_ALIGN_ROTATION_WITH_VIEW,
- VIEW_PERSPECTIVE,
- VIEW_ENVIRONMENT,
- VIEW_ORTHOGONAL,
- VIEW_HALF_RESOLUTION,
- VIEW_AUDIO_LISTENER,
- VIEW_AUDIO_DOPPLER,
- VIEW_GIZMOS,
- VIEW_INFORMATION,
- VIEW_FPS,
- VIEW_DISPLAY_NORMAL,
- VIEW_DISPLAY_WIREFRAME,
- VIEW_DISPLAY_OVERDRAW,
- VIEW_DISPLAY_SHADELESS,
- VIEW_DISPLAY_LIGHTING,
- VIEW_DISPLAY_ADVANCED,
- VIEW_DISPLAY_NORMAL_BUFFER,
- VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
- VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
- VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO,
- VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING,
- VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
- VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
- VIEW_DISPLAY_DEBUG_SSAO,
- VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
- VIEW_LOCK_ROTATION,
- VIEW_CINEMATIC_PREVIEW,
- VIEW_AUTO_ORTHOGONAL,
- VIEW_MAX
- };
-
-public:
- enum {
- GIZMO_BASE_LAYER = 27,
- GIZMO_EDIT_LAYER = 26,
- GIZMO_GRID_LAYER = 25
- };
-
- enum NavigationScheme {
- NAVIGATION_GODOT,
- NAVIGATION_MAYA,
- NAVIGATION_MODO,
- };
-
-private:
- int index;
- String name;
- void _menu_option(int p_option);
- void _set_auto_orthogonal();
- Spatial *preview_node;
- AABB *preview_bounds;
- Vector<String> selected_files;
- AcceptDialog *accept;
-
- Node *target_node;
- Point2 drop_pos;
-
- EditorNode *editor;
- EditorData *editor_data;
- EditorSelection *editor_selection;
- UndoRedo *undo_redo;
-
- CheckBox *preview_camera;
- ViewportContainer *viewport_container;
-
- MenuButton *view_menu;
- PopupMenu *display_submenu;
-
- Control *surface;
- Viewport *viewport;
- Camera *camera;
- bool transforming;
- bool orthogonal;
- bool auto_orthogonal;
- bool lock_rotation;
- float gizmo_scale;
-
- bool freelook_active;
- real_t freelook_speed;
-
- TextureRect *crosshair;
- Label *info_label;
- Label *cinema_label;
- Label *locked_label;
-
- VBoxContainer *top_right_vbox;
- ViewportRotationControl *rotation_control;
- Label *fps_label;
-
- struct _RayResult {
-
- Spatial *item;
- float depth;
- int handle;
- _FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; }
- };
-
- void _update_name();
- void _compute_edit(const Point2 &p_point);
- void _clear_selected();
- void _select_clicked(bool p_append, bool p_single, bool p_allow_locked = false);
- void _select(Node *p_node, bool p_append, bool p_single);
- ObjectID _select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle = NULL, bool p_alt_select = false);
- void _find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select = false);
- Vector3 _get_ray_pos(const Vector2 &p_pos) const;
- Vector3 _get_ray(const Vector2 &p_pos) const;
- Point2 _point_to_screen(const Vector3 &p_point);
- Transform _get_camera_transform() const;
- int get_selected_count() const;
-
- Vector3 _get_camera_position() const;
- Vector3 _get_camera_normal() const;
- Vector3 _get_screen_to_space(const Vector3 &p_vector3);
-
- void _select_region();
- bool _gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only = false);
-
- void _nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
- void _nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
- void _nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
- void _nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative);
-
- float get_znear() const;
- float get_zfar() const;
- float get_fov() const;
-
- ObjectID clicked;
- Vector<_RayResult> selection_results;
- bool clicked_includes_current;
- bool clicked_wants_append;
-
- PopupMenu *selection_menu;
-
- enum NavigationZoomStyle {
- NAVIGATION_ZOOM_VERTICAL,
- NAVIGATION_ZOOM_HORIZONTAL
- };
-
- enum NavigationMode {
- NAVIGATION_NONE,
- NAVIGATION_PAN,
- NAVIGATION_ZOOM,
- NAVIGATION_ORBIT,
- NAVIGATION_LOOK
- };
- enum TransformMode {
- TRANSFORM_NONE,
- TRANSFORM_ROTATE,
- TRANSFORM_TRANSLATE,
- TRANSFORM_SCALE
-
- };
- enum TransformPlane {
- TRANSFORM_VIEW,
- TRANSFORM_X_AXIS,
- TRANSFORM_Y_AXIS,
- TRANSFORM_Z_AXIS,
- TRANSFORM_YZ,
- TRANSFORM_XZ,
- TRANSFORM_XY,
- };
-
- struct EditData {
- TransformMode mode;
- TransformPlane plane;
- Transform original;
- Vector3 click_ray;
- Vector3 click_ray_pos;
- Vector3 center;
- Vector3 orig_gizmo_pos;
- int edited_gizmo;
- Point2 mouse_pos;
- bool snap;
- Ref<EditorSpatialGizmo> gizmo;
- int gizmo_handle;
- Variant gizmo_initial_value;
- Vector3 gizmo_initial_pos;
- } _edit;
-
- struct Cursor {
-
- Vector3 pos;
- float x_rot, y_rot, distance;
- Vector3 eye_pos; // Used in freelook mode
- bool region_select;
- Point2 region_begin, region_end;
-
- Cursor() {
- x_rot = y_rot = 0.5;
- distance = 4;
- region_select = false;
- }
- };
- // Viewport camera supports movement smoothing,
- // so one cursor is the real cursor, while the other can be an interpolated version.
- Cursor cursor; // Immediate cursor
- Cursor camera_cursor; // That one may be interpolated (don't modify this one except for smoothing purposes)
-
- void scale_cursor_distance(real_t scale);
-
- void set_freelook_active(bool active_now);
- void scale_freelook_speed(real_t scale);
-
- real_t zoom_indicator_delay;
-
- RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
-
- String last_message;
- String message;
- float message_time;
-
- void set_message(String p_message, float p_time = 5);
-
- //
- void _update_camera(float p_interp_delta);
- Transform to_camera_transform(const Cursor &p_cursor) const;
- void _draw();
-
- void _surface_mouse_enter();
- void _surface_mouse_exit();
- void _surface_focus_enter();
- void _surface_focus_exit();
-
- void _sinput(const Ref<InputEvent> &p_event);
- void _update_freelook(real_t delta);
- SpatialEditor *spatial_editor;
-
- Camera *previewing;
- Camera *preview;
-
- bool previewing_cinema;
- bool _is_node_locked(const Node *p_node);
- void _preview_exited_scene();
- void _toggle_camera_preview(bool);
- void _toggle_cinema_preview(bool);
- void _init_gizmo_instance(int p_idx);
- void _finish_gizmo_instances();
- void _selection_result_pressed(int);
- void _selection_menu_hide();
- void _list_select(Ref<InputEventMouseButton> b);
- Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const;
-
- Vector3 _get_instance_position(const Point2 &p_pos) const;
- static AABB _calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform = true);
- void _create_preview(const Vector<String> &files) const;
- void _remove_preview();
- bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node);
- bool _create_instance(Node *parent, String &path, const Point2 &p_point);
- void _perform_drop_data();
-
- 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:
- void update_surface() { surface->update(); }
- void update_transform_gizmo_view();
-
- void set_can_preview(Camera *p_preview);
- void set_state(const Dictionary &p_state);
- Dictionary get_state() const;
- void reset();
- bool is_freelook_active() const { return freelook_active; }
-
- void focus_selection();
-
- void assign_pending_data_pointers(
- Spatial *p_preview_node,
- AABB *p_preview_bounds,
- AcceptDialog *p_accept);
-
- Viewport *get_viewport_node() { return viewport; }
- Camera *get_camera() { return camera; } // return the default camera object.
-
- SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index);
-};
-
-class SpatialEditorSelectedItem : public Object {
-
- GDCLASS(SpatialEditorSelectedItem, Object);
-
-public:
- AABB aabb;
- Transform original; // original location when moving
- Transform original_local;
- Transform last_xform; // last transform
- Spatial *sp;
- RID sbox_instance;
-
- SpatialEditorSelectedItem() { sp = NULL; }
- ~SpatialEditorSelectedItem();
-};
-
-class SpatialEditorViewportContainer : public Container {
-
- GDCLASS(SpatialEditorViewportContainer, Container);
-
-public:
- enum View {
- VIEW_USE_1_VIEWPORT,
- VIEW_USE_2_VIEWPORTS,
- VIEW_USE_2_VIEWPORTS_ALT,
- VIEW_USE_3_VIEWPORTS,
- VIEW_USE_3_VIEWPORTS_ALT,
- VIEW_USE_4_VIEWPORTS,
- };
-
-private:
- View view;
- bool mouseover;
- float ratio_h;
- float ratio_v;
-
- bool hovering_v;
- bool hovering_h;
-
- bool dragging_v;
- bool dragging_h;
- Vector2 drag_begin_pos;
- Vector2 drag_begin_ratio;
-
- void _gui_input(const Ref<InputEvent> &p_event);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_view(View p_view);
- View get_view();
-
- SpatialEditorViewportContainer();
-};
-
-class SpatialEditor : public VBoxContainer {
-
- GDCLASS(SpatialEditor, VBoxContainer);
-
-public:
- static const unsigned int VIEWPORTS_COUNT = 4;
-
- enum ToolMode {
-
- TOOL_MODE_SELECT,
- TOOL_MODE_MOVE,
- TOOL_MODE_ROTATE,
- TOOL_MODE_SCALE,
- TOOL_MODE_LIST_SELECT,
- TOOL_LOCK_SELECTED,
- TOOL_UNLOCK_SELECTED,
- TOOL_GROUP_SELECTED,
- TOOL_UNGROUP_SELECTED,
- TOOL_MAX
- };
-
- enum ToolOptions {
-
- TOOL_OPT_LOCAL_COORDS,
- TOOL_OPT_USE_SNAP,
- TOOL_OPT_OVERRIDE_CAMERA,
- TOOL_OPT_MAX
-
- };
-
-private:
- EditorNode *editor;
- EditorSelection *editor_selection;
-
- SpatialEditorViewportContainer *viewport_base;
- SpatialEditorViewport *viewports[VIEWPORTS_COUNT];
- VSplitContainer *shader_split;
- HSplitContainer *palette_split;
-
- /////
-
- ToolMode tool_mode;
- bool orthogonal;
-
- VisualServer::ScenarioDebugMode scenario_debug;
-
- RID origin;
- RID origin_instance;
- bool origin_enabled;
- RID grid[3];
- RID grid_instance[3];
- bool grid_visible[3]; //currently visible
- bool grid_enable[3]; //should be always visible if true
- bool grid_enabled;
-
- Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3];
- Ref<StandardMaterial3D> gizmo_color[3];
- Ref<StandardMaterial3D> plane_gizmo_color[3];
- Ref<StandardMaterial3D> gizmo_color_hl[3];
- Ref<StandardMaterial3D> plane_gizmo_color_hl[3];
-
- int over_gizmo_handle;
- float snap_translate_value;
- float snap_rotate_value;
- float snap_scale_value;
-
- Ref<ArrayMesh> selection_box;
- RID indicators;
- RID indicators_instance;
- RID cursor_mesh;
- RID cursor_instance;
- Ref<StandardMaterial3D> indicator_mat;
- Ref<StandardMaterial3D> cursor_material;
-
- // Scene drag and drop support
- Spatial *preview_node;
- AABB preview_bounds;
-
- struct Gizmo {
-
- bool visible;
- float scale;
- Transform transform;
- } gizmo;
-
- enum MenuOption {
-
- MENU_TOOL_SELECT,
- MENU_TOOL_MOVE,
- MENU_TOOL_ROTATE,
- MENU_TOOL_SCALE,
- MENU_TOOL_LIST_SELECT,
- MENU_TOOL_LOCAL_COORDS,
- MENU_TOOL_USE_SNAP,
- MENU_TOOL_OVERRIDE_CAMERA,
- MENU_TRANSFORM_CONFIGURE_SNAP,
- MENU_TRANSFORM_DIALOG,
- MENU_VIEW_USE_1_VIEWPORT,
- MENU_VIEW_USE_2_VIEWPORTS,
- MENU_VIEW_USE_2_VIEWPORTS_ALT,
- MENU_VIEW_USE_3_VIEWPORTS,
- MENU_VIEW_USE_3_VIEWPORTS_ALT,
- MENU_VIEW_USE_4_VIEWPORTS,
- MENU_VIEW_ORIGIN,
- MENU_VIEW_GRID,
- MENU_VIEW_GIZMOS_3D_ICONS,
- MENU_VIEW_CAMERA_SETTINGS,
- MENU_LOCK_SELECTED,
- MENU_UNLOCK_SELECTED,
- MENU_GROUP_SELECTED,
- MENU_UNGROUP_SELECTED,
- MENU_SNAP_TO_FLOOR
- };
-
- Button *tool_button[TOOL_MAX];
- Button *tool_option_button[TOOL_OPT_MAX];
-
- MenuButton *transform_menu;
- PopupMenu *gizmos_menu;
- MenuButton *view_menu;
-
- AcceptDialog *accept;
-
- ConfirmationDialog *snap_dialog;
- ConfirmationDialog *xform_dialog;
- ConfirmationDialog *settings_dialog;
-
- bool snap_enabled;
- bool snap_key_enabled;
- LineEdit *snap_translate;
- LineEdit *snap_rotate;
- LineEdit *snap_scale;
- PanelContainer *menu_panel;
-
- LineEdit *xform_translate[3];
- LineEdit *xform_rotate[3];
- LineEdit *xform_scale[3];
- OptionButton *xform_type;
-
- VBoxContainer *settings_vbc;
- SpinBox *settings_fov;
- SpinBox *settings_znear;
- SpinBox *settings_zfar;
-
- void _snap_changed();
- void _snap_update();
- void _xform_dialog_action();
- void _menu_item_pressed(int p_option);
- void _menu_item_toggled(bool pressed, int p_option);
- void _menu_gizmo_toggled(int p_option);
- void _update_camera_override_button(bool p_game_running);
- void _update_camera_override_viewport(Object *p_viewport);
-
- HBoxContainer *hbc_menu;
-
- void _generate_selection_box();
- UndoRedo *undo_redo;
-
- int camera_override_viewport_id;
-
- void _init_indicators();
- void _update_gizmos_menu();
- void _update_gizmos_menu_theme();
- void _init_grid();
- void _finish_indicators();
- void _finish_grid();
-
- void _toggle_maximize_view(Object *p_viewport);
-
- Node *custom_camera;
-
- Object *_get_editor_data(Object *p_what);
-
- Ref<Environment> viewport_environment;
-
- Spatial *selected;
-
- void _request_gizmo(Object *p_obj);
-
- static SpatialEditor *singleton;
-
- void _node_removed(Node *p_node);
- Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_priority;
- Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_name;
-
- void _register_all_gizmos();
-
- SpatialEditor();
-
- bool is_any_freelook_active() const;
-
- void _refresh_menu_icons();
-
-protected:
- void _notification(int p_what);
- //void _gui_input(InputEvent p_event);
- void _unhandled_key_input(Ref<InputEvent> p_event);
-
- static void _bind_methods();
-
-public:
- static SpatialEditor *get_singleton() { return singleton; }
- void snap_cursor_to_plane(const Plane &p_plane);
-
- Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const;
-
- float get_znear() const { return settings_znear->get_value(); }
- float get_zfar() const { return settings_zfar->get_value(); }
- float get_fov() const { return settings_fov->get_value(); }
-
- Transform get_gizmo_transform() const { return gizmo.transform; }
- bool is_gizmo_visible() const { return gizmo.visible; }
-
- ToolMode get_tool_mode() const { return tool_mode; }
- bool are_local_coords_enabled() const { return tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
- bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
- float get_translate_snap() const;
- float get_rotate_snap() const;
- float get_scale_snap() const;
-
- Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
- Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
- Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; }
- Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
- Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; }
-
- void update_transform_gizmo();
- void update_all_gizmos(Node *p_node = NULL);
- void snap_selected_nodes_to_floor();
- void select_gizmo_highlight_axis(int p_axis);
- void set_custom_camera(Node *p_camera) { custom_camera = p_camera; }
-
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
- Dictionary get_state() const;
- void set_state(const Dictionary &p_state);
-
- Ref<Environment> get_viewport_environment() { return viewport_environment; }
-
- UndoRedo *get_undo_redo() { return undo_redo; }
-
- void add_control_to_menu_panel(Control *p_control);
- void remove_control_from_menu_panel(Control *p_control);
-
- VSplitContainer *get_shader_split();
- HSplitContainer *get_palette_split();
-
- Spatial *get_selected() { return selected; }
-
- int get_over_gizmo_handle() const { return over_gizmo_handle; }
- void set_over_gizmo_handle(int idx) { over_gizmo_handle = idx; }
-
- void set_can_preview(Camera *p_preview);
-
- SpatialEditorViewport *get_editor_viewport(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), NULL);
- return viewports[p_idx];
- }
-
- void add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin);
- void remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin);
-
- void edit(Spatial *p_spatial);
- void clear();
-
- SpatialEditor(EditorNode *p_editor);
- ~SpatialEditor();
-};
-
-class SpatialEditorPlugin : public EditorPlugin {
-
- GDCLASS(SpatialEditorPlugin, EditorPlugin);
-
- SpatialEditor *spatial_editor;
- EditorNode *editor;
-
-protected:
- static void _bind_methods();
-
-public:
- void snap_cursor_to_plane(const Plane &p_plane);
-
- SpatialEditor *get_spatial_editor() { return spatial_editor; }
- virtual String get_name() const { return "3D"; }
- bool has_main_screen() const { return true; }
- virtual void make_visible(bool p_visible);
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
-
- virtual Dictionary get_state() const;
- virtual void set_state(const Dictionary &p_state);
- virtual void clear() { spatial_editor->clear(); }
-
- virtual void edited_scene_changed();
-
- SpatialEditorPlugin(EditorNode *p_node);
- ~SpatialEditorPlugin();
-};
-
-class EditorSpatialGizmoPlugin : public Resource {
-
- GDCLASS(EditorSpatialGizmoPlugin, Resource);
-
-public:
- static const int VISIBLE = 0;
- static const int HIDDEN = 1;
- static const int ON_TOP = 2;
-
-private:
- int current_state;
- List<EditorSpatialGizmo *> current_gizmos;
- HashMap<String, Vector<Ref<StandardMaterial3D> > > materials;
-
-protected:
- static void _bind_methods();
- virtual bool has_gizmo(Spatial *p_spatial);
- virtual Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial);
-
-public:
- void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false);
- void create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1));
- void create_handle_material(const String &p_name, bool p_billboard = false);
- void add_material(const String &p_name, Ref<StandardMaterial3D> p_material);
-
- Ref<StandardMaterial3D> get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo = Ref<EditorSpatialGizmo>());
-
- virtual String get_name() const;
- virtual int get_priority() const;
- virtual bool can_be_hidden() const;
- virtual bool is_selectable_when_hidden() const;
-
- virtual void redraw(EditorSpatialGizmo *p_gizmo);
- virtual String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- virtual Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- virtual void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
- virtual bool is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
-
- Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial);
- void set_state(int p_state);
- int get_state() const;
- void unregister_gizmo(EditorSpatialGizmo *p_gizmo);
-
- EditorSpatialGizmoPlugin();
- virtual ~EditorSpatialGizmoPlugin();
-};
-
-#endif
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..ab0f15d3d0
--- /dev/null
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -0,0 +1,611 @@
+/*************************************************************************/
+/* sprite_2d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "editor/editor_scale.h"
+#include "scene/2d/collision_polygon_2d.h"
+#include "scene/2d/light_occluder_2d.h"
+#include "scene/2d/mesh_instance_2d.h"
+#include "scene/2d/polygon_2d.h"
+#include "scene/gui/box_container.h"
+#include "thirdparty/misc/clipper.hpp"
+
+void Sprite2DEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ options->hide();
+ }
+}
+
+void Sprite2DEditor::edit(Sprite2D *p_sprite) {
+
+ node = p_sprite;
+}
+
+#define PRECISION 10.0
+
+Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float epsilon = 2.0) {
+ int size = points.size();
+ ERR_FAIL_COND_V(size < 2, Vector<Vector2>());
+
+ ClipperLib::Path subj;
+ ClipperLib::PolyTree solution;
+ ClipperLib::PolyTree out;
+
+ for (int i = 0; i < points.size(); i++) {
+
+ subj << ClipperLib::IntPoint(points[i].x * PRECISION, points[i].y * PRECISION);
+ }
+ ClipperLib::ClipperOffset co;
+ co.AddPath(subj, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
+ co.Execute(solution, epsilon * PRECISION);
+
+ ClipperLib::PolyNode *p = solution.GetFirst();
+
+ ERR_FAIL_COND_V(!p, points);
+
+ while (p->IsHole()) {
+ p = p->GetNext();
+ }
+
+ //turn the result into simply polygon (AKA, fix overlap)
+
+ //clamp into the specified rect
+ ClipperLib::Clipper cl;
+ cl.StrictlySimple(true);
+ cl.AddPath(p->Contour, ClipperLib::ptSubject, true);
+ //create the clipping rect
+ ClipperLib::Path clamp;
+ clamp.push_back(ClipperLib::IntPoint(0, 0));
+ clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, 0));
+ clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, rect.size.height * PRECISION));
+ clamp.push_back(ClipperLib::IntPoint(0, rect.size.height * PRECISION));
+ cl.AddPath(clamp, ClipperLib::ptClip, true);
+ cl.Execute(ClipperLib::ctIntersection, out);
+
+ Vector<Vector2> outPoints;
+ ClipperLib::PolyNode *p2 = out.GetFirst();
+ ERR_FAIL_COND_V(!p2, points);
+
+ while (p2->IsHole()) {
+ p2 = p2->GetNext();
+ }
+
+ int lasti = p2->Contour.size() - 1;
+ Vector2 prev = Vector2(p2->Contour[lasti].X / PRECISION, p2->Contour[lasti].Y / PRECISION);
+ for (uint64_t i = 0; i < p2->Contour.size(); i++) {
+
+ Vector2 cur = Vector2(p2->Contour[i].X / PRECISION, p2->Contour[i].Y / PRECISION);
+ if (cur.distance_to(prev) > 0.5) {
+ outPoints.push_back(cur);
+ prev = cur;
+ }
+ }
+ return outPoints;
+}
+
+void Sprite2DEditor::_menu_option(int p_option) {
+
+ if (!node) {
+ return;
+ }
+
+ selected_menu_item = (Menu)p_option;
+
+ switch (p_option) {
+ case MENU_OPTION_CONVERT_TO_MESH_2D: {
+
+ debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
+ debug_uv_dialog->set_title(TTR("Mesh2D Preview"));
+
+ _update_mesh_data();
+ debug_uv_dialog->popup_centered();
+ debug_uv->update();
+
+ } break;
+ case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
+
+ debug_uv_dialog->get_ok()->set_text(TTR("Create Polygon2D"));
+ debug_uv_dialog->set_title(TTR("Polygon2D Preview"));
+
+ _update_mesh_data();
+ debug_uv_dialog->popup_centered();
+ debug_uv->update();
+ } break;
+ case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
+
+ debug_uv_dialog->get_ok()->set_text(TTR("Create CollisionPolygon2D"));
+ debug_uv_dialog->set_title(TTR("CollisionPolygon2D Preview"));
+
+ _update_mesh_data();
+ debug_uv_dialog->popup_centered();
+ debug_uv->update();
+
+ } break;
+ case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
+
+ debug_uv_dialog->get_ok()->set_text(TTR("Create LightOccluder2D"));
+ debug_uv_dialog->set_title(TTR("LightOccluder2D Preview"));
+
+ _update_mesh_data();
+ debug_uv_dialog->popup_centered();
+ debug_uv->update();
+
+ } break;
+ }
+}
+
+void Sprite2DEditor::_update_mesh_data() {
+
+ Ref<Texture2D> texture = node->get_texture();
+ if (texture.is_null()) {
+ err_dialog->set_text(TTR("Sprite2D is empty!"));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ if (node->get_hframes() > 1 || node->get_vframes() > 1) {
+ err_dialog->set_text(TTR("Can't convert a sprite using animation frames to mesh."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Ref<Image> image = texture->get_data();
+ ERR_FAIL_COND(image.is_null());
+ Rect2 rect;
+ if (node->is_region())
+ rect = node->get_region_rect();
+ else
+ rect.size = Size2(image->get_width(), image->get_height());
+
+ Ref<BitMap> bm;
+ bm.instance();
+ bm->create_from_image_alpha(image);
+
+ int shrink = shrink_pixels->get_value();
+ if (shrink > 0) {
+ bm->shrink_mask(shrink, rect);
+ }
+
+ int grow = grow_pixels->get_value();
+ if (grow > 0) {
+ bm->grow_mask(grow, rect);
+ }
+
+ float epsilon = simplification->get_value();
+
+ Vector<Vector<Vector2>> lines = bm->clip_opaque_to_polygons(rect, epsilon);
+
+ uv_lines.clear();
+
+ computed_vertices.clear();
+ computed_uv.clear();
+ computed_indices.clear();
+
+ Size2 img_size = Vector2(image->get_width(), image->get_height());
+ for (int i = 0; i < lines.size(); i++) {
+ lines.write[i] = expand(lines[i], rect, epsilon);
+ }
+
+ if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D) {
+
+ for (int j = 0; j < lines.size(); j++) {
+ int index_ofs = computed_vertices.size();
+
+ for (int i = 0; i < lines[j].size(); i++) {
+ Vector2 vtx = lines[j][i];
+ computed_uv.push_back(vtx / img_size);
+
+ vtx -= rect.position; //offset by rect position
+
+ //flip if flipped
+ if (node->is_flipped_h())
+ vtx.x = rect.size.x - vtx.x - 1.0;
+ if (node->is_flipped_v())
+ vtx.y = rect.size.y - vtx.y - 1.0;
+
+ if (node->is_centered())
+ vtx -= rect.size / 2.0;
+
+ computed_vertices.push_back(vtx);
+ }
+
+ Vector<int> poly = Geometry::triangulate_polygon(lines[j]);
+
+ for (int i = 0; i < poly.size(); i += 3) {
+ for (int k = 0; k < 3; k++) {
+ int idx = i + k;
+ int idxn = i + (k + 1) % 3;
+ uv_lines.push_back(lines[j][poly[idx]]);
+ uv_lines.push_back(lines[j][poly[idxn]]);
+
+ computed_indices.push_back(poly[idx] + index_ofs);
+ }
+ }
+ }
+ }
+
+ outline_lines.clear();
+ computed_outline_lines.clear();
+
+ if (selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) {
+ outline_lines.resize(lines.size());
+ computed_outline_lines.resize(lines.size());
+ for (int pi = 0; pi < lines.size(); pi++) {
+
+ Vector<Vector2> ol;
+ Vector<Vector2> col;
+
+ ol.resize(lines[pi].size());
+ col.resize(lines[pi].size());
+
+ for (int i = 0; i < lines[pi].size(); i++) {
+ Vector2 vtx = lines[pi][i];
+
+ ol.write[i] = vtx;
+
+ vtx -= rect.position; //offset by rect position
+
+ //flip if flipped
+ if (node->is_flipped_h())
+ vtx.x = rect.size.x - vtx.x - 1.0;
+ if (node->is_flipped_v())
+ vtx.y = rect.size.y - vtx.y - 1.0;
+
+ if (node->is_centered())
+ vtx -= rect.size / 2.0;
+
+ col.write[i] = vtx;
+ }
+
+ outline_lines.write[pi] = ol;
+ computed_outline_lines.write[pi] = col;
+ }
+ }
+
+ debug_uv->update();
+}
+
+void Sprite2DEditor::_create_node() {
+ switch (selected_menu_item) {
+ case MENU_OPTION_CONVERT_TO_MESH_2D: {
+ _convert_to_mesh_2d_node();
+ } break;
+ case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
+ _convert_to_polygon_2d_node();
+ } break;
+ case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
+ _create_collision_polygon_2d_node();
+ } break;
+ case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
+ _create_light_occluder_2d_node();
+ } break;
+ }
+}
+
+void Sprite2DEditor::_convert_to_mesh_2d_node() {
+
+ if (computed_vertices.size() < 3) {
+ err_dialog->set_text(TTR("Invalid geometry, can't replace by mesh."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Ref<ArrayMesh> mesh;
+ mesh.instance();
+
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = computed_vertices;
+ a[Mesh::ARRAY_TEX_UV] = computed_uv;
+ a[Mesh::ARRAY_INDEX] = computed_indices;
+
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
+
+ MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
+ mesh_instance->set_mesh(mesh);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Convert to Mesh2D"));
+ ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, mesh_instance, true, false);
+ ur->add_do_reference(mesh_instance);
+ ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", mesh_instance, node, false, false);
+ ur->add_undo_reference(node);
+ ur->commit_action();
+}
+
+void Sprite2DEditor::_convert_to_polygon_2d_node() {
+
+ if (computed_outline_lines.empty()) {
+ err_dialog->set_text(TTR("Invalid geometry, can't create polygon."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ Polygon2D *polygon_2d_instance = memnew(Polygon2D);
+
+ int total_point_count = 0;
+ for (int i = 0; i < computed_outline_lines.size(); i++)
+ total_point_count += computed_outline_lines[i].size();
+
+ PackedVector2Array polygon;
+ polygon.resize(total_point_count);
+ Vector2 *polygon_write = polygon.ptrw();
+
+ PackedVector2Array uvs;
+ uvs.resize(total_point_count);
+ Vector2 *uvs_write = uvs.ptrw();
+
+ int current_point_index = 0;
+
+ Array polys;
+ polys.resize(computed_outline_lines.size());
+
+ for (int i = 0; i < computed_outline_lines.size(); i++) {
+
+ Vector<Vector2> outline = computed_outline_lines[i];
+ Vector<Vector2> uv_outline = outline_lines[i];
+
+ PackedInt32Array pia;
+ pia.resize(outline.size());
+ int *pia_write = pia.ptrw();
+
+ for (int pi = 0; pi < outline.size(); pi++) {
+ polygon_write[current_point_index] = outline[pi];
+ uvs_write[current_point_index] = uv_outline[pi];
+ pia_write[pi] = current_point_index;
+ current_point_index++;
+ }
+
+ polys[i] = pia;
+ }
+
+ polygon_2d_instance->set_uv(uvs);
+ polygon_2d_instance->set_polygon(polygon);
+ polygon_2d_instance->set_polygons(polys);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Convert to Polygon2D"));
+ ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, polygon_2d_instance, true, false);
+ ur->add_do_reference(polygon_2d_instance);
+ ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", polygon_2d_instance, node, false, false);
+ ur->add_undo_reference(node);
+ ur->commit_action();
+}
+
+void Sprite2DEditor::_create_collision_polygon_2d_node() {
+
+ if (computed_outline_lines.empty()) {
+ err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ for (int i = 0; i < computed_outline_lines.size(); i++) {
+
+ Vector<Vector2> outline = computed_outline_lines[i];
+
+ CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
+ collision_polygon_2d_instance->set_polygon(outline);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
+ ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
+ ur->add_do_reference(collision_polygon_2d_instance);
+ ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", collision_polygon_2d_instance);
+ ur->commit_action();
+ }
+}
+
+void Sprite2DEditor::_create_light_occluder_2d_node() {
+
+ if (computed_outline_lines.empty()) {
+ err_dialog->set_text(TTR("Invalid geometry, can't create light occluder."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ for (int i = 0; i < computed_outline_lines.size(); i++) {
+
+ Vector<Vector2> outline = computed_outline_lines[i];
+
+ Ref<OccluderPolygon2D> polygon;
+ polygon.instance();
+
+ PackedVector2Array a;
+ a.resize(outline.size());
+ Vector2 *aw = a.ptrw();
+ for (int io = 0; io < outline.size(); io++) {
+ aw[io] = outline[io];
+ }
+ polygon->set_polygon(a);
+
+ LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
+ light_occluder_2d_instance->set_occluder_polygon(polygon);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create LightOccluder2D Sibling"));
+ ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
+ ur->add_do_reference(light_occluder_2d_instance);
+ ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", light_occluder_2d_instance);
+ ur->commit_action();
+ }
+}
+
+void Sprite2DEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) {
+ // Can't make sibling if own node is scene root
+ if (p_own_node != this->get_tree()->get_edited_scene_root()) {
+ p_own_node->get_parent()->add_child(p_new_node, true);
+ Object::cast_to<Node2D>(p_new_node)->set_transform(Object::cast_to<Node2D>(p_own_node)->get_transform());
+ } else {
+ p_own_node->add_child(p_new_node, true);
+ }
+
+ p_new_node->set_owner(this->get_tree()->get_edited_scene_root());
+}
+
+void Sprite2DEditor::_debug_uv_draw() {
+
+ Ref<Texture2D> tex = node->get_texture();
+ ERR_FAIL_COND(!tex.is_valid());
+
+ Point2 draw_pos_offset = Point2(1.0, 1.0);
+ Size2 draw_size_offset = Size2(2.0, 2.0);
+
+ debug_uv->set_clip_contents(true);
+ debug_uv->draw_texture(tex, draw_pos_offset);
+ debug_uv->set_custom_minimum_size(tex->get_size() + draw_size_offset);
+ debug_uv->draw_set_transform(draw_pos_offset, 0, Size2(1.0, 1.0));
+
+ Color color = Color(1.0, 0.8, 0.7);
+
+ if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D && uv_lines.size() > 0) {
+ debug_uv->draw_multiline(uv_lines, color);
+
+ } else if ((selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) && outline_lines.size() > 0) {
+ for (int i = 0; i < outline_lines.size(); i++) {
+ Vector<Vector2> outline = outline_lines[i];
+
+ debug_uv->draw_polyline(outline, color);
+ debug_uv->draw_line(outline[0], outline[outline.size() - 1], color);
+ }
+ }
+}
+
+void Sprite2DEditor::_bind_methods() {
+
+ ClassDB::bind_method("_add_as_sibling_or_child", &Sprite2DEditor::_add_as_sibling_or_child);
+}
+
+Sprite2DEditor::Sprite2DEditor() {
+
+ options = memnew(MenuButton);
+
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
+
+ options->set_text(TTR("Sprite2D"));
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Sprite2D", "EditorIcons"));
+
+ options->get_popup()->add_item(TTR("Convert to Mesh2D"), MENU_OPTION_CONVERT_TO_MESH_2D);
+ options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D);
+ options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D);
+ options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D);
+ options->set_switch_on_hover(true);
+
+ options->get_popup()->connect("id_pressed", callable_mp(this, &Sprite2DEditor::_menu_option));
+
+ err_dialog = memnew(AcceptDialog);
+ add_child(err_dialog);
+
+ debug_uv_dialog = memnew(ConfirmationDialog);
+ debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
+ debug_uv_dialog->set_title("Mesh 2D Preview");
+ VBoxContainer *vb = memnew(VBoxContainer);
+ debug_uv_dialog->add_child(vb);
+ ScrollContainer *scroll = memnew(ScrollContainer);
+ scroll->set_custom_minimum_size(Size2(800, 500) * EDSCALE);
+ scroll->set_enable_h_scroll(true);
+ scroll->set_enable_v_scroll(true);
+ vb->add_margin_child(TTR("Preview:"), scroll, true);
+ debug_uv = memnew(Control);
+ debug_uv->connect("draw", callable_mp(this, &Sprite2DEditor::_debug_uv_draw));
+ scroll->add_child(debug_uv);
+ debug_uv_dialog->connect("confirmed", callable_mp(this, &Sprite2DEditor::_create_node));
+
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->add_child(memnew(Label(TTR("Simplification: "))));
+ simplification = memnew(SpinBox);
+ simplification->set_min(0.01);
+ simplification->set_max(10.00);
+ simplification->set_step(0.01);
+ simplification->set_value(2);
+ hb->add_child(simplification);
+ hb->add_spacer();
+ hb->add_child(memnew(Label(TTR("Shrink (Pixels): "))));
+ shrink_pixels = memnew(SpinBox);
+ shrink_pixels->set_min(0);
+ shrink_pixels->set_max(10);
+ shrink_pixels->set_step(1);
+ shrink_pixels->set_value(0);
+ hb->add_child(shrink_pixels);
+ hb->add_spacer();
+ hb->add_child(memnew(Label(TTR("Grow (Pixels): "))));
+ grow_pixels = memnew(SpinBox);
+ grow_pixels->set_min(0);
+ grow_pixels->set_max(10);
+ grow_pixels->set_step(1);
+ grow_pixels->set_value(2);
+ hb->add_child(grow_pixels);
+ hb->add_spacer();
+ update_preview = memnew(Button);
+ update_preview->set_text(TTR("Update Preview"));
+ update_preview->connect("pressed", callable_mp(this, &Sprite2DEditor::_update_mesh_data));
+ hb->add_child(update_preview);
+ vb->add_margin_child(TTR("Settings:"), hb);
+
+ add_child(debug_uv_dialog);
+}
+
+void Sprite2DEditorPlugin::edit(Object *p_object) {
+
+ sprite_editor->edit(Object::cast_to<Sprite2D>(p_object));
+}
+
+bool Sprite2DEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("Sprite2D");
+}
+
+void Sprite2DEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ sprite_editor->options->show();
+ } else {
+
+ sprite_editor->options->hide();
+ sprite_editor->edit(nullptr);
+ }
+}
+
+Sprite2DEditorPlugin::Sprite2DEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ sprite_editor = memnew(Sprite2DEditor);
+ editor->get_viewport()->add_child(sprite_editor);
+ make_visible(false);
+
+ //sprite_editor->options->hide();
+}
+
+Sprite2DEditorPlugin::~Sprite2DEditorPlugin() {
+}
diff --git a/editor/plugins/sprite_2d_editor_plugin.h b/editor/plugins/sprite_2d_editor_plugin.h
new file mode 100644
index 0000000000..0add77843b
--- /dev/null
+++ b/editor/plugins/sprite_2d_editor_plugin.h
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* sprite_2d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPRITE_EDITOR_PLUGIN_H
+#define SPRITE_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/2d/sprite_2d.h"
+#include "scene/gui/spin_box.h"
+
+class Sprite2DEditor : public Control {
+
+ GDCLASS(Sprite2DEditor, Control);
+
+ enum Menu {
+ MENU_OPTION_CONVERT_TO_MESH_2D,
+ MENU_OPTION_CONVERT_TO_POLYGON_2D,
+ MENU_OPTION_CREATE_COLLISION_POLY_2D,
+ MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D
+ };
+
+ Menu selected_menu_item;
+
+ Sprite2D *node;
+
+ MenuButton *options;
+
+ ConfirmationDialog *outline_dialog;
+
+ AcceptDialog *err_dialog;
+
+ ConfirmationDialog *debug_uv_dialog;
+ Control *debug_uv;
+ Vector<Vector2> uv_lines;
+ Vector<Vector<Vector2>> outline_lines;
+ Vector<Vector<Vector2>> computed_outline_lines;
+ Vector<Vector2> computed_vertices;
+ Vector<Vector2> computed_uv;
+ Vector<int> computed_indices;
+
+ SpinBox *simplification;
+ SpinBox *grow_pixels;
+ SpinBox *shrink_pixels;
+ Button *update_preview;
+
+ void _menu_option(int p_option);
+
+ //void _create_uv_lines();
+ friend class Sprite2DEditorPlugin;
+
+ void _debug_uv_draw();
+ void _update_mesh_data();
+
+ void _create_node();
+ void _convert_to_mesh_2d_node();
+ void _convert_to_polygon_2d_node();
+ void _create_collision_polygon_2d_node();
+ void _create_light_occluder_2d_node();
+
+ void _add_as_sibling_or_child(Node *p_own_node, Node *p_new_node);
+
+protected:
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+public:
+ void edit(Sprite2D *p_sprite);
+ Sprite2DEditor();
+};
+
+class Sprite2DEditorPlugin : public EditorPlugin {
+
+ GDCLASS(Sprite2DEditorPlugin, EditorPlugin);
+
+ Sprite2DEditor *sprite_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const { return "Sprite2D"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ Sprite2DEditorPlugin(EditorNode *p_node);
+ ~Sprite2DEditorPlugin();
+};
+
+#endif // SPRITE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp
deleted file mode 100644
index 135807e88c..0000000000
--- a/editor/plugins/sprite_editor_plugin.cpp
+++ /dev/null
@@ -1,611 +0,0 @@
-/*************************************************************************/
-/* sprite_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_editor_plugin.h"
-
-#include "canvas_item_editor_plugin.h"
-#include "editor/editor_scale.h"
-#include "scene/2d/collision_polygon_2d.h"
-#include "scene/2d/light_occluder_2d.h"
-#include "scene/2d/mesh_instance_2d.h"
-#include "scene/2d/polygon_2d.h"
-#include "scene/gui/box_container.h"
-#include "thirdparty/misc/clipper.hpp"
-
-void SpriteEditor::_node_removed(Node *p_node) {
-
- if (p_node == node) {
- node = NULL;
- options->hide();
- }
-}
-
-void SpriteEditor::edit(Sprite *p_sprite) {
-
- node = p_sprite;
-}
-
-#define PRECISION 10.0
-
-Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float epsilon = 2.0) {
- int size = points.size();
- ERR_FAIL_COND_V(size < 2, Vector<Vector2>());
-
- ClipperLib::Path subj;
- ClipperLib::PolyTree solution;
- ClipperLib::PolyTree out;
-
- for (int i = 0; i < points.size(); i++) {
-
- subj << ClipperLib::IntPoint(points[i].x * PRECISION, points[i].y * PRECISION);
- }
- ClipperLib::ClipperOffset co;
- co.AddPath(subj, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
- co.Execute(solution, epsilon * PRECISION);
-
- ClipperLib::PolyNode *p = solution.GetFirst();
-
- ERR_FAIL_COND_V(!p, points);
-
- while (p->IsHole()) {
- p = p->GetNext();
- }
-
- //turn the result into simply polygon (AKA, fix overlap)
-
- //clamp into the specified rect
- ClipperLib::Clipper cl;
- cl.StrictlySimple(true);
- cl.AddPath(p->Contour, ClipperLib::ptSubject, true);
- //create the clipping rect
- ClipperLib::Path clamp;
- clamp.push_back(ClipperLib::IntPoint(0, 0));
- clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, 0));
- clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, rect.size.height * PRECISION));
- clamp.push_back(ClipperLib::IntPoint(0, rect.size.height * PRECISION));
- cl.AddPath(clamp, ClipperLib::ptClip, true);
- cl.Execute(ClipperLib::ctIntersection, out);
-
- Vector<Vector2> outPoints;
- ClipperLib::PolyNode *p2 = out.GetFirst();
- ERR_FAIL_COND_V(!p2, points);
-
- while (p2->IsHole()) {
- p2 = p2->GetNext();
- }
-
- int lasti = p2->Contour.size() - 1;
- Vector2 prev = Vector2(p2->Contour[lasti].X / PRECISION, p2->Contour[lasti].Y / PRECISION);
- for (uint64_t i = 0; i < p2->Contour.size(); i++) {
-
- Vector2 cur = Vector2(p2->Contour[i].X / PRECISION, p2->Contour[i].Y / PRECISION);
- if (cur.distance_to(prev) > 0.5) {
- outPoints.push_back(cur);
- prev = cur;
- }
- }
- return outPoints;
-}
-
-void SpriteEditor::_menu_option(int p_option) {
-
- if (!node) {
- return;
- }
-
- selected_menu_item = (Menu)p_option;
-
- switch (p_option) {
- case MENU_OPTION_CONVERT_TO_MESH_2D: {
-
- debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
- debug_uv_dialog->set_title(TTR("Mesh2D Preview"));
-
- _update_mesh_data();
- debug_uv_dialog->popup_centered();
- debug_uv->update();
-
- } break;
- case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
-
- debug_uv_dialog->get_ok()->set_text(TTR("Create Polygon2D"));
- debug_uv_dialog->set_title(TTR("Polygon2D Preview"));
-
- _update_mesh_data();
- debug_uv_dialog->popup_centered();
- debug_uv->update();
- } break;
- case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
-
- debug_uv_dialog->get_ok()->set_text(TTR("Create CollisionPolygon2D"));
- debug_uv_dialog->set_title(TTR("CollisionPolygon2D Preview"));
-
- _update_mesh_data();
- debug_uv_dialog->popup_centered();
- debug_uv->update();
-
- } break;
- case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
-
- debug_uv_dialog->get_ok()->set_text(TTR("Create LightOccluder2D"));
- debug_uv_dialog->set_title(TTR("LightOccluder2D Preview"));
-
- _update_mesh_data();
- debug_uv_dialog->popup_centered();
- debug_uv->update();
-
- } break;
- }
-}
-
-void SpriteEditor::_update_mesh_data() {
-
- Ref<Texture2D> texture = node->get_texture();
- if (texture.is_null()) {
- err_dialog->set_text(TTR("Sprite is empty!"));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- if (node->get_hframes() > 1 || node->get_vframes() > 1) {
- err_dialog->set_text(TTR("Can't convert a sprite using animation frames to mesh."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Ref<Image> image = texture->get_data();
- ERR_FAIL_COND(image.is_null());
- Rect2 rect;
- if (node->is_region())
- rect = node->get_region_rect();
- else
- rect.size = Size2(image->get_width(), image->get_height());
-
- Ref<BitMap> bm;
- bm.instance();
- bm->create_from_image_alpha(image);
-
- int shrink = shrink_pixels->get_value();
- if (shrink > 0) {
- bm->shrink_mask(shrink, rect);
- }
-
- int grow = grow_pixels->get_value();
- if (grow > 0) {
- bm->grow_mask(grow, rect);
- }
-
- float epsilon = simplification->get_value();
-
- Vector<Vector<Vector2> > lines = bm->clip_opaque_to_polygons(rect, epsilon);
-
- uv_lines.clear();
-
- computed_vertices.clear();
- computed_uv.clear();
- computed_indices.clear();
-
- Size2 img_size = Vector2(image->get_width(), image->get_height());
- for (int i = 0; i < lines.size(); i++) {
- lines.write[i] = expand(lines[i], rect, epsilon);
- }
-
- if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D) {
-
- for (int j = 0; j < lines.size(); j++) {
- int index_ofs = computed_vertices.size();
-
- for (int i = 0; i < lines[j].size(); i++) {
- Vector2 vtx = lines[j][i];
- computed_uv.push_back(vtx / img_size);
-
- vtx -= rect.position; //offset by rect position
-
- //flip if flipped
- if (node->is_flipped_h())
- vtx.x = rect.size.x - vtx.x - 1.0;
- if (node->is_flipped_v())
- vtx.y = rect.size.y - vtx.y - 1.0;
-
- if (node->is_centered())
- vtx -= rect.size / 2.0;
-
- computed_vertices.push_back(vtx);
- }
-
- Vector<int> poly = Geometry::triangulate_polygon(lines[j]);
-
- for (int i = 0; i < poly.size(); i += 3) {
- for (int k = 0; k < 3; k++) {
- int idx = i + k;
- int idxn = i + (k + 1) % 3;
- uv_lines.push_back(lines[j][poly[idx]]);
- uv_lines.push_back(lines[j][poly[idxn]]);
-
- computed_indices.push_back(poly[idx] + index_ofs);
- }
- }
- }
- }
-
- outline_lines.clear();
- computed_outline_lines.clear();
-
- if (selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) {
- outline_lines.resize(lines.size());
- computed_outline_lines.resize(lines.size());
- for (int pi = 0; pi < lines.size(); pi++) {
-
- Vector<Vector2> ol;
- Vector<Vector2> col;
-
- ol.resize(lines[pi].size());
- col.resize(lines[pi].size());
-
- for (int i = 0; i < lines[pi].size(); i++) {
- Vector2 vtx = lines[pi][i];
-
- ol.write[i] = vtx;
-
- vtx -= rect.position; //offset by rect position
-
- //flip if flipped
- if (node->is_flipped_h())
- vtx.x = rect.size.x - vtx.x - 1.0;
- if (node->is_flipped_v())
- vtx.y = rect.size.y - vtx.y - 1.0;
-
- if (node->is_centered())
- vtx -= rect.size / 2.0;
-
- col.write[i] = vtx;
- }
-
- outline_lines.write[pi] = ol;
- computed_outline_lines.write[pi] = col;
- }
- }
-
- debug_uv->update();
-}
-
-void SpriteEditor::_create_node() {
- switch (selected_menu_item) {
- case MENU_OPTION_CONVERT_TO_MESH_2D: {
- _convert_to_mesh_2d_node();
- } break;
- case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
- _convert_to_polygon_2d_node();
- } break;
- case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
- _create_collision_polygon_2d_node();
- } break;
- case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
- _create_light_occluder_2d_node();
- } break;
- }
-}
-
-void SpriteEditor::_convert_to_mesh_2d_node() {
-
- if (computed_vertices.size() < 3) {
- err_dialog->set_text(TTR("Invalid geometry, can't replace by mesh."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Ref<ArrayMesh> mesh;
- mesh.instance();
-
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = computed_vertices;
- a[Mesh::ARRAY_TEX_UV] = computed_uv;
- a[Mesh::ARRAY_INDEX] = computed_indices;
-
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
-
- MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
- mesh_instance->set_mesh(mesh);
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Convert to Mesh2D"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, mesh_instance, true, false);
- ur->add_do_reference(mesh_instance);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", mesh_instance, node, false, false);
- ur->add_undo_reference(node);
- ur->commit_action();
-}
-
-void SpriteEditor::_convert_to_polygon_2d_node() {
-
- if (computed_outline_lines.empty()) {
- err_dialog->set_text(TTR("Invalid geometry, can't create polygon."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- Polygon2D *polygon_2d_instance = memnew(Polygon2D);
-
- int total_point_count = 0;
- for (int i = 0; i < computed_outline_lines.size(); i++)
- total_point_count += computed_outline_lines[i].size();
-
- PackedVector2Array polygon;
- polygon.resize(total_point_count);
- Vector2 *polygon_write = polygon.ptrw();
-
- PackedVector2Array uvs;
- uvs.resize(total_point_count);
- Vector2 *uvs_write = uvs.ptrw();
-
- int current_point_index = 0;
-
- Array polys;
- polys.resize(computed_outline_lines.size());
-
- for (int i = 0; i < computed_outline_lines.size(); i++) {
-
- Vector<Vector2> outline = computed_outline_lines[i];
- Vector<Vector2> uv_outline = outline_lines[i];
-
- PackedInt32Array pia;
- pia.resize(outline.size());
- int *pia_write = pia.ptrw();
-
- for (int pi = 0; pi < outline.size(); pi++) {
- polygon_write[current_point_index] = outline[pi];
- uvs_write[current_point_index] = uv_outline[pi];
- pia_write[pi] = current_point_index;
- current_point_index++;
- }
-
- polys[i] = pia;
- }
-
- polygon_2d_instance->set_uv(uvs);
- polygon_2d_instance->set_polygon(polygon);
- polygon_2d_instance->set_polygons(polys);
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Convert to Polygon2D"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, polygon_2d_instance, true, false);
- ur->add_do_reference(polygon_2d_instance);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", polygon_2d_instance, node, false, false);
- ur->add_undo_reference(node);
- ur->commit_action();
-}
-
-void SpriteEditor::_create_collision_polygon_2d_node() {
-
- if (computed_outline_lines.empty()) {
- err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- for (int i = 0; i < computed_outline_lines.size(); i++) {
-
- Vector<Vector2> outline = computed_outline_lines[i];
-
- CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
- collision_polygon_2d_instance->set_polygon(outline);
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
- ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
- ur->add_do_reference(collision_polygon_2d_instance);
- ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", collision_polygon_2d_instance);
- ur->commit_action();
- }
-}
-
-void SpriteEditor::_create_light_occluder_2d_node() {
-
- if (computed_outline_lines.empty()) {
- err_dialog->set_text(TTR("Invalid geometry, can't create light occluder."));
- err_dialog->popup_centered_minsize();
- return;
- }
-
- for (int i = 0; i < computed_outline_lines.size(); i++) {
-
- Vector<Vector2> outline = computed_outline_lines[i];
-
- Ref<OccluderPolygon2D> polygon;
- polygon.instance();
-
- PackedVector2Array a;
- a.resize(outline.size());
- Vector2 *aw = a.ptrw();
- for (int io = 0; io < outline.size(); io++) {
- aw[io] = outline[io];
- }
- polygon->set_polygon(a);
-
- LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
- light_occluder_2d_instance->set_occluder_polygon(polygon);
-
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Create LightOccluder2D Sibling"));
- ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
- ur->add_do_reference(light_occluder_2d_instance);
- ur->add_undo_method(node != this->get_tree()->get_edited_scene_root() ? node->get_parent() : this->get_tree()->get_edited_scene_root(), "remove_child", light_occluder_2d_instance);
- ur->commit_action();
- }
-}
-
-void SpriteEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) {
- // Can't make sibling if own node is scene root
- if (p_own_node != this->get_tree()->get_edited_scene_root()) {
- p_own_node->get_parent()->add_child(p_new_node, true);
- Object::cast_to<Node2D>(p_new_node)->set_transform(Object::cast_to<Node2D>(p_own_node)->get_transform());
- } else {
- p_own_node->add_child(p_new_node, true);
- }
-
- p_new_node->set_owner(this->get_tree()->get_edited_scene_root());
-}
-
-void SpriteEditor::_debug_uv_draw() {
-
- Ref<Texture2D> tex = node->get_texture();
- ERR_FAIL_COND(!tex.is_valid());
-
- Point2 draw_pos_offset = Point2(1.0, 1.0);
- Size2 draw_size_offset = Size2(2.0, 2.0);
-
- debug_uv->set_clip_contents(true);
- debug_uv->draw_texture(tex, draw_pos_offset);
- debug_uv->set_custom_minimum_size(tex->get_size() + draw_size_offset);
- debug_uv->draw_set_transform(draw_pos_offset, 0, Size2(1.0, 1.0));
-
- Color color = Color(1.0, 0.8, 0.7);
-
- if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D && uv_lines.size() > 0) {
- debug_uv->draw_multiline(uv_lines, color);
-
- } else if ((selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) && outline_lines.size() > 0) {
- for (int i = 0; i < outline_lines.size(); i++) {
- Vector<Vector2> outline = outline_lines[i];
-
- debug_uv->draw_polyline(outline, color);
- debug_uv->draw_line(outline[0], outline[outline.size() - 1], color);
- }
- }
-}
-
-void SpriteEditor::_bind_methods() {
-
- ClassDB::bind_method("_add_as_sibling_or_child", &SpriteEditor::_add_as_sibling_or_child);
-}
-
-SpriteEditor::SpriteEditor() {
-
- options = memnew(MenuButton);
-
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
-
- options->set_text(TTR("Sprite"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Sprite", "EditorIcons"));
-
- options->get_popup()->add_item(TTR("Convert to Mesh2D"), MENU_OPTION_CONVERT_TO_MESH_2D);
- options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D);
- options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D);
- options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D);
- options->set_switch_on_hover(true);
-
- options->get_popup()->connect("id_pressed", callable_mp(this, &SpriteEditor::_menu_option));
-
- err_dialog = memnew(AcceptDialog);
- add_child(err_dialog);
-
- debug_uv_dialog = memnew(ConfirmationDialog);
- debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D"));
- debug_uv_dialog->set_title("Mesh 2D Preview");
- VBoxContainer *vb = memnew(VBoxContainer);
- debug_uv_dialog->add_child(vb);
- ScrollContainer *scroll = memnew(ScrollContainer);
- scroll->set_custom_minimum_size(Size2(800, 500) * EDSCALE);
- scroll->set_enable_h_scroll(true);
- scroll->set_enable_v_scroll(true);
- vb->add_margin_child(TTR("Preview:"), scroll, true);
- debug_uv = memnew(Control);
- debug_uv->connect("draw", callable_mp(this, &SpriteEditor::_debug_uv_draw));
- scroll->add_child(debug_uv);
- debug_uv_dialog->connect("confirmed", callable_mp(this, &SpriteEditor::_create_node));
-
- HBoxContainer *hb = memnew(HBoxContainer);
- hb->add_child(memnew(Label(TTR("Simplification: "))));
- simplification = memnew(SpinBox);
- simplification->set_min(0.01);
- simplification->set_max(10.00);
- simplification->set_step(0.01);
- simplification->set_value(2);
- hb->add_child(simplification);
- hb->add_spacer();
- hb->add_child(memnew(Label(TTR("Shrink (Pixels): "))));
- shrink_pixels = memnew(SpinBox);
- shrink_pixels->set_min(0);
- shrink_pixels->set_max(10);
- shrink_pixels->set_step(1);
- shrink_pixels->set_value(0);
- hb->add_child(shrink_pixels);
- hb->add_spacer();
- hb->add_child(memnew(Label(TTR("Grow (Pixels): "))));
- grow_pixels = memnew(SpinBox);
- grow_pixels->set_min(0);
- grow_pixels->set_max(10);
- grow_pixels->set_step(1);
- grow_pixels->set_value(2);
- hb->add_child(grow_pixels);
- hb->add_spacer();
- update_preview = memnew(Button);
- update_preview->set_text(TTR("Update Preview"));
- update_preview->connect("pressed", callable_mp(this, &SpriteEditor::_update_mesh_data));
- hb->add_child(update_preview);
- vb->add_margin_child(TTR("Settings:"), hb);
-
- add_child(debug_uv_dialog);
-}
-
-void SpriteEditorPlugin::edit(Object *p_object) {
-
- sprite_editor->edit(Object::cast_to<Sprite>(p_object));
-}
-
-bool SpriteEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("Sprite");
-}
-
-void SpriteEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- sprite_editor->options->show();
- } else {
-
- sprite_editor->options->hide();
- sprite_editor->edit(NULL);
- }
-}
-
-SpriteEditorPlugin::SpriteEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- sprite_editor = memnew(SpriteEditor);
- editor->get_viewport()->add_child(sprite_editor);
- make_visible(false);
-
- //sprite_editor->options->hide();
-}
-
-SpriteEditorPlugin::~SpriteEditorPlugin() {
-}
diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h
deleted file mode 100644
index 13177c9142..0000000000
--- a/editor/plugins/sprite_editor_plugin.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*************************************************************************/
-/* sprite_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPRITE_EDITOR_PLUGIN_H
-#define SPRITE_EDITOR_PLUGIN_H
-
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/2d/sprite.h"
-#include "scene/gui/spin_box.h"
-
-class SpriteEditor : public Control {
-
- GDCLASS(SpriteEditor, Control);
-
- enum Menu {
- MENU_OPTION_CONVERT_TO_MESH_2D,
- MENU_OPTION_CONVERT_TO_POLYGON_2D,
- MENU_OPTION_CREATE_COLLISION_POLY_2D,
- MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D
- };
-
- Menu selected_menu_item;
-
- Sprite *node;
-
- MenuButton *options;
-
- ConfirmationDialog *outline_dialog;
-
- AcceptDialog *err_dialog;
-
- ConfirmationDialog *debug_uv_dialog;
- Control *debug_uv;
- Vector<Vector2> uv_lines;
- Vector<Vector<Vector2> > outline_lines;
- Vector<Vector<Vector2> > computed_outline_lines;
- Vector<Vector2> computed_vertices;
- Vector<Vector2> computed_uv;
- Vector<int> computed_indices;
-
- SpinBox *simplification;
- SpinBox *grow_pixels;
- SpinBox *shrink_pixels;
- Button *update_preview;
-
- void _menu_option(int p_option);
-
- //void _create_uv_lines();
- friend class SpriteEditorPlugin;
-
- void _debug_uv_draw();
- void _update_mesh_data();
-
- void _create_node();
- void _convert_to_mesh_2d_node();
- void _convert_to_polygon_2d_node();
- void _create_collision_polygon_2d_node();
- void _create_light_occluder_2d_node();
-
- void _add_as_sibling_or_child(Node *p_own_node, Node *p_new_node);
-
-protected:
- void _node_removed(Node *p_node);
- static void _bind_methods();
-
-public:
- void edit(Sprite *p_sprite);
- SpriteEditor();
-};
-
-class SpriteEditorPlugin : public EditorPlugin {
-
- GDCLASS(SpriteEditorPlugin, EditorPlugin);
-
- SpriteEditor *sprite_editor;
- EditorNode *editor;
-
-public:
- virtual String get_name() const { return "Sprite"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- SpriteEditorPlugin(EditorNode *p_node);
- ~SpriteEditorPlugin();
-};
-
-#endif // SPRITE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 5d615c7553..76e60bb014 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -81,7 +81,7 @@ void SpriteFramesEditor::_sheet_preview_draw() {
return;
}
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
int idx = E->get();
@@ -223,24 +223,24 @@ void SpriteFramesEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- load->set_icon(get_icon("Load", "EditorIcons"));
- load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons"));
- copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
- paste->set_icon(get_icon("ActionPaste", "EditorIcons"));
- empty->set_icon(get_icon("InsertBefore", "EditorIcons"));
- empty2->set_icon(get_icon("InsertAfter", "EditorIcons"));
- move_up->set_icon(get_icon("MoveLeft", "EditorIcons"));
- move_down->set_icon(get_icon("MoveRight", "EditorIcons"));
- _delete->set_icon(get_icon("Remove", "EditorIcons"));
- new_anim->set_icon(get_icon("New", "EditorIcons"));
- remove_anim->set_icon(get_icon("Remove", "EditorIcons"));
+ load->set_icon(get_theme_icon("Load", "EditorIcons"));
+ load_sheet->set_icon(get_theme_icon("SpriteSheet", "EditorIcons"));
+ copy->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
+ paste->set_icon(get_theme_icon("ActionPaste", "EditorIcons"));
+ empty->set_icon(get_theme_icon("InsertBefore", "EditorIcons"));
+ empty2->set_icon(get_theme_icon("InsertAfter", "EditorIcons"));
+ move_up->set_icon(get_theme_icon("MoveLeft", "EditorIcons"));
+ move_down->set_icon(get_theme_icon("MoveRight", "EditorIcons"));
+ _delete->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ new_anim->set_icon(get_theme_icon("New", "EditorIcons"));
+ remove_anim->set_icon(get_theme_icon("Remove", "EditorIcons"));
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
- splite_sheet_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
+ splite_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
} break;
case NOTIFICATION_READY: {
- add_constant_override("autohide", 1); // Fixes the dragger always showing up.
+ add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up.
} break;
}
}
@@ -249,7 +249,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
ERR_FAIL_COND(!frames->has_animation(edited_anim));
- List<Ref<Texture2D> > resources;
+ List<Ref<Texture2D>> resources;
for (int i = 0; i < p_path.size(); i++) {
@@ -262,7 +262,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text(TTR("Close"));
- dialog->popup_centered_minsize();
+ dialog->popup_centered();
return; ///beh should show an error i guess
}
@@ -278,7 +278,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
int count = 0;
- for (List<Ref<Texture2D> >::Element *E = resources.front(); E; E = E->next()) {
+ for (List<Ref<Texture2D>>::Element *E = resources.front(); E; E = E->next()) {
undo_redo->add_do_method(frames, "add_frame", edited_anim, E->get(), p_at_pos == -1 ? -1 : p_at_pos + count);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, p_at_pos == -1 ? fc : p_at_pos);
@@ -301,7 +301,7 @@ void SpriteFramesEditor::_load_pressed() {
for (int i = 0; i < extensions.size(); i++)
file->add_filter("*." + extensions[i]);
- file->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
file->popup_centered_ratio();
}
@@ -316,7 +316,7 @@ void SpriteFramesEditor::_paste_pressed() {
dialog->set_title(TTR("Error!"));
//dialog->get_cancel()->set_text("Close");
dialog->get_ok()->set_text(TTR("Close"));
- dialog->popup_centered_minsize();
+ dialog->popup_centered();
return; ///beh should show an error i guess
}
@@ -485,7 +485,7 @@ static void _find_anim_sprites(Node *p_node, List<Node *> *r_nodes, Ref<SpriteFr
return;
{
- AnimatedSprite *as = Object::cast_to<AnimatedSprite>(p_node);
+ AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
if (as && as->get_sprite_frames() == p_sfames) {
r_nodes->push_back(p_node);
}
@@ -591,7 +591,7 @@ void SpriteFramesEditor::_animation_remove() {
return;
delete_dialog->set_text(TTR("Delete Animation?"));
- delete_dialog->popup_centered_minsize();
+ delete_dialog->popup_centered();
}
void SpriteFramesEditor::_animation_remove_confirmed() {
@@ -1058,7 +1058,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
file_split_sheet = memnew(EditorFileDialog);
file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet"));
- file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_split_sheet->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
add_child(file_split_sheet);
file_split_sheet->connect("file_selected", callable_mp(this, &SpriteFramesEditor::_prepare_sprite_sheet));
}
@@ -1068,11 +1068,17 @@ void SpriteFramesEditorPlugin::edit(Object *p_object) {
frames_editor->set_undo_redo(&get_undo_redo());
SpriteFrames *s;
- AnimatedSprite *animated_sprite = Object::cast_to<AnimatedSprite>(p_object);
+ AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object);
if (animated_sprite) {
s = *animated_sprite->get_sprite_frames();
} else {
- s = Object::cast_to<SpriteFrames>(p_object);
+ AnimatedSprite3D *animated_sprite_3d = Object::cast_to<AnimatedSprite3D>(p_object);
+ if (animated_sprite_3d) {
+ s = *animated_sprite_3d->get_sprite_frames();
+ } else {
+
+ s = Object::cast_to<SpriteFrames>(p_object);
+ }
}
frames_editor->edit(s);
@@ -1080,9 +1086,12 @@ void SpriteFramesEditorPlugin::edit(Object *p_object) {
bool SpriteFramesEditorPlugin::handles(Object *p_object) const {
- AnimatedSprite *animated_sprite = Object::cast_to<AnimatedSprite>(p_object);
+ AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object);
+ AnimatedSprite3D *animated_sprite_3d = Object::cast_to<AnimatedSprite3D>(p_object);
if (animated_sprite && *animated_sprite->get_sprite_frames()) {
return true;
+ } else if (animated_sprite_3d && *animated_sprite_3d->get_sprite_frames()) {
+ return true;
} else {
return p_object->is_class("SpriteFrames");
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 1fa93b5c47..89d9bc6fd3 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -33,7 +33,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/2d/animated_sprite.h"
+#include "scene/2d/animated_sprite_2d.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/split_container.h"
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index a92194da17..fbb6616dea 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -34,7 +34,7 @@
bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) {
- return Object::cast_to<StyleBox>(p_object) != NULL;
+ return Object::cast_to<StyleBox>(p_object) != nullptr;
}
void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) {
@@ -57,7 +57,7 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
stylebox->disconnect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed));
stylebox = p_stylebox;
if (p_stylebox.is_valid()) {
- preview->add_style_override("panel", stylebox);
+ preview->add_theme_style_override("panel", stylebox);
stylebox->connect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed));
}
_sb_changed();
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 35f23ccf1d..2786a568ea 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -41,7 +41,7 @@ void TextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
void TextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
TextEdit *te = code_editor->get_text_edit();
te->_set_syntax_highlighting(p_highlighter);
- if (p_highlighter != NULL) {
+ if (p_highlighter != nullptr) {
highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true);
} else {
highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text("Standard"), true);
@@ -49,12 +49,12 @@ void TextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
// little work around. GDScript highlighter goes through text_edit for colours,
// so to remove all colours we need to set and unset them here.
- if (p_highlighter == NULL) { // standard
+ if (p_highlighter == nullptr) { // standard
TextEdit *text_edit = code_editor->get_text_edit();
- text_edit->add_color_override("number_color", colors_cache.font_color);
- text_edit->add_color_override("function_color", colors_cache.font_color);
- text_edit->add_color_override("number_color", colors_cache.font_color);
- text_edit->add_color_override("member_variable_color", colors_cache.font_color);
+ text_edit->add_theme_color_override("number_color", colors_cache.font_color);
+ text_edit->add_theme_color_override("function_color", colors_cache.font_color);
+ text_edit->add_theme_color_override("number_color", colors_cache.font_color);
+ text_edit->add_theme_color_override("member_variable_color", colors_cache.font_color);
} else {
_load_theme_settings();
}
@@ -62,7 +62,7 @@ void TextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
void TextEditor::_change_syntax_highlighter(int p_idx) {
Map<String, SyntaxHighlighter *>::Element *el = highlighters.front();
- while (el != NULL) {
+ while (el != nullptr) {
highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false);
el = el->next();
}
@@ -107,35 +107,35 @@ void TextEditor::_load_theme_settings() {
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color string_color = EDITOR_GET("text_editor/highlighting/string_color");
- text_edit->add_color_override("background_color", background_color);
- text_edit->add_color_override("completion_background_color", completion_background_color);
- text_edit->add_color_override("completion_selected_color", completion_selected_color);
- text_edit->add_color_override("completion_existing_color", completion_existing_color);
- text_edit->add_color_override("completion_scroll_color", completion_scroll_color);
- text_edit->add_color_override("completion_font_color", completion_font_color);
- text_edit->add_color_override("font_color", text_color);
- text_edit->add_color_override("line_number_color", line_number_color);
- text_edit->add_color_override("caret_color", caret_color);
- text_edit->add_color_override("caret_background_color", caret_background_color);
- text_edit->add_color_override("font_color_selected", text_selected_color);
- text_edit->add_color_override("selection_color", selection_color);
- text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color);
- text_edit->add_color_override("current_line_color", current_line_color);
- text_edit->add_color_override("line_length_guideline_color", line_length_guideline_color);
- text_edit->add_color_override("word_highlighted_color", word_highlighted_color);
- text_edit->add_color_override("number_color", number_color);
- text_edit->add_color_override("function_color", function_color);
- text_edit->add_color_override("member_variable_color", member_variable_color);
- text_edit->add_color_override("breakpoint_color", breakpoint_color);
- text_edit->add_color_override("executing_line_color", executing_line_color);
- text_edit->add_color_override("mark_color", mark_color);
- text_edit->add_color_override("bookmark_color", bookmark_color);
- text_edit->add_color_override("code_folding_color", code_folding_color);
- text_edit->add_color_override("search_result_color", search_result_color);
- text_edit->add_color_override("search_result_border_color", search_result_border_color);
- text_edit->add_color_override("symbol_color", symbol_color);
-
- text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
+ text_edit->add_theme_color_override("background_color", background_color);
+ text_edit->add_theme_color_override("completion_background_color", completion_background_color);
+ text_edit->add_theme_color_override("completion_selected_color", completion_selected_color);
+ text_edit->add_theme_color_override("completion_existing_color", completion_existing_color);
+ text_edit->add_theme_color_override("completion_scroll_color", completion_scroll_color);
+ text_edit->add_theme_color_override("completion_font_color", completion_font_color);
+ text_edit->add_theme_color_override("font_color", text_color);
+ text_edit->add_theme_color_override("line_number_color", line_number_color);
+ text_edit->add_theme_color_override("caret_color", caret_color);
+ text_edit->add_theme_color_override("caret_background_color", caret_background_color);
+ text_edit->add_theme_color_override("font_color_selected", text_selected_color);
+ text_edit->add_theme_color_override("selection_color", selection_color);
+ text_edit->add_theme_color_override("brace_mismatch_color", brace_mismatch_color);
+ text_edit->add_theme_color_override("current_line_color", current_line_color);
+ text_edit->add_theme_color_override("line_length_guideline_color", line_length_guideline_color);
+ text_edit->add_theme_color_override("word_highlighted_color", word_highlighted_color);
+ text_edit->add_theme_color_override("number_color", number_color);
+ text_edit->add_theme_color_override("function_color", function_color);
+ text_edit->add_theme_color_override("member_variable_color", member_variable_color);
+ text_edit->add_theme_color_override("breakpoint_color", breakpoint_color);
+ text_edit->add_theme_color_override("executing_line_color", executing_line_color);
+ text_edit->add_theme_color_override("mark_color", mark_color);
+ text_edit->add_theme_color_override("bookmark_color", bookmark_color);
+ text_edit->add_theme_color_override("code_folding_color", code_folding_color);
+ text_edit->add_theme_color_override("search_result_color", search_result_color);
+ text_edit->add_theme_color_override("search_result_border_color", search_result_border_color);
+ text_edit->add_theme_color_override("symbol_color", symbol_color);
+
+ text_edit->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6));
colors_cache.font_color = text_color;
colors_cache.symbol_color = symbol_color;
@@ -163,7 +163,7 @@ String TextEditor::get_name() {
return name;
}
-Ref<Texture2D> TextEditor::get_icon() {
+Ref<Texture2D> TextEditor::get_theme_icon() {
return EditorNode::get_singleton()->get_object_icon(text_file.operator->(), "");
}
@@ -533,7 +533,7 @@ static ScriptEditorBase *create_editor(const RES &p_resource) {
if (Object::cast_to<TextFile>(*p_resource)) {
return memnew(TextEditor);
}
- return NULL;
+ return nullptr;
}
void TextEditor::register_editor() {
@@ -624,7 +624,7 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is
TextEditor::TextEditor() {
code_editor = memnew(CodeTextEditor);
add_child(code_editor);
- code_editor->add_constant_override("separation", 0);
+ code_editor->add_theme_constant_override("separation", 0);
code_editor->connect("load_theme_settings", callable_mp(this, &TextEditor::_load_theme_settings));
code_editor->connect("validate_script", callable_mp(this, &TextEditor::_validate_script));
code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE);
@@ -694,7 +694,7 @@ TextEditor::TextEditor() {
convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE);
convert_case->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
- highlighters["Standard"] = NULL;
+ highlighters["Standard"] = nullptr;
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("highlighter_menu");
edit_menu->get_popup()->add_child(highlighter_menu);
@@ -716,7 +716,7 @@ TextEditor::TextEditor() {
goto_menu->get_popup()->add_child(bookmarks_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks");
_update_bookmark_list();
- bookmarks_menu->connect("about_to_show", callable_mp(this, &TextEditor::_update_bookmark_list));
+ bookmarks_menu->connect("about_to_popup", callable_mp(this, &TextEditor::_update_bookmark_list));
bookmarks_menu->connect("index_pressed", callable_mp(this, &TextEditor::_bookmark_item_pressed));
goto_line_dialog = memnew(GotoLineDialog);
@@ -727,7 +727,7 @@ TextEditor::TextEditor() {
TextEditor::~TextEditor() {
for (const Map<String, SyntaxHighlighter *>::Element *E = highlighters.front(); E; E = E->next()) {
- if (E->get() != NULL) {
+ if (E->get() != nullptr) {
memdelete(E->get());
}
}
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index c80052e7ba..b41e11c3aa 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -121,7 +121,7 @@ public:
virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter);
virtual String get_name();
- virtual Ref<Texture2D> get_icon();
+ virtual Ref<Texture2D> get_theme_icon();
virtual RES get_edited_resource() const;
virtual void set_edited_resource(const RES &p_res);
void set_edited_file(const Ref<TextFile> &p_file);
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 60f9bb5dc1..c1184c1c89 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -46,7 +46,7 @@ void TextureEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<Texture2D> checkerboard = get_icon("Checkerboard", "EditorIcons");
+ Ref<Texture2D> checkerboard = get_theme_icon("Checkerboard", "EditorIcons");
Size2 size = get_size();
draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
@@ -79,7 +79,7 @@ void TextureEditor::_notification(int p_what) {
draw_texture_rect(texture, Rect2(ofs_x, ofs_y, tex_width, tex_height));
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
String format;
if (Object::cast_to<ImageTexture>(*texture)) {
@@ -144,7 +144,7 @@ TextureEditor::~TextureEditor() {
//
bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
- return Object::cast_to<ImageTexture>(p_object) != NULL || Object::cast_to<AtlasTexture>(p_object) != NULL || Object::cast_to<StreamTexture>(p_object) != NULL || Object::cast_to<LargeTexture>(p_object) != NULL || Object::cast_to<AnimatedTexture>(p_object) != NULL;
+ return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture>(p_object) != nullptr || Object::cast_to<LargeTexture>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
}
void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 2262e12f5d..8892d13f51 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -31,7 +31,7 @@
#include "texture_region_editor_plugin.h"
#include "core/core_string_names.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "scene/gui/check_box.h"
@@ -43,13 +43,13 @@
void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) {
Vector2 line = (to - from).normalized() * 10;
while ((to - from).length_squared() > 200) {
- edit_draw->draw_line(from, from + line, EditorNode::get_singleton()->get_theme_base()->get_color("mono_color", "Editor"), 2);
+ edit_draw->draw_line(from, from + line, EditorNode::get_singleton()->get_theme_base()->get_theme_color("mono_color", "Editor"), 2);
from += line * 2;
}
}
void TextureRegionEditor::_region_draw() {
- Ref<Texture2D> base_tex = NULL;
+ Ref<Texture2D> base_tex = nullptr;
if (node_sprite)
base_tex = node_sprite->get_texture();
else if (node_sprite_3d)
@@ -68,9 +68,9 @@ void TextureRegionEditor::_region_draw() {
mtx.elements[2] = -draw_ofs * draw_zoom;
mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
- VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx);
+ RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx);
edit_draw->draw_texture(base_tex, Point2());
- VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
+ RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
if (snap_mode == SNAP_GRID) {
Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
@@ -134,7 +134,7 @@ void TextureRegionEditor::_region_draw() {
}
}
- Ref<Texture2D> select_handle = get_icon("EditorHandle", "EditorIcons");
+ Ref<Texture2D> select_handle = get_theme_icon("EditorHandle", "EditorIcons");
Rect2 scroll_rect(Point2(), base_tex->get_size());
@@ -150,7 +150,7 @@ void TextureRegionEditor::_region_draw() {
mtx.basis_xform(raw_endpoints[2]),
mtx.basis_xform(raw_endpoints[3])
};
- Color color = get_color("mono_color", "Editor");
+ Color color = get_theme_color("mono_color", "Editor");
for (int i = 0; i < 4; i++) {
int prev = (i + 3) % 4;
@@ -307,7 +307,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
if (E->get().has_point(point)) {
rect = E->get();
- if (Input::get_singleton()->is_key_pressed(KEY_CONTROL) && !(Input::get_singleton()->is_key_pressed(KEY_SHIFT | KEY_ALT))) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL) && !(InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT | KEY_ALT))) {
Rect2 r;
if (node_sprite)
r = node_sprite->get_region_rect();
@@ -449,7 +449,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &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() & BUTTON_MASK_MIDDLE || InputFilter::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);
@@ -672,7 +672,7 @@ void TextureRegionEditor::_update_autoslice() {
autoslice_is_dirty = false;
autoslice_cache.clear();
- Ref<Texture2D> texture = NULL;
+ Ref<Texture2D> texture = nullptr;
if (node_sprite)
texture = node_sprite->get_texture();
else if (node_sprite_3d)
@@ -741,12 +741,12 @@ void TextureRegionEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- edit_draw->add_style_override("panel", get_stylebox("bg", "Tree"));
+ edit_draw->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
} break;
case NOTIFICATION_READY: {
- zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
- zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
- zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons"));
+ zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
+ zoom_reset->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
+ zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
vscroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE);
hscroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE);
@@ -756,7 +756,7 @@ void TextureRegionEditor::_notification(int p_what) {
_update_autoslice();
}
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_FOCUS_IN: {
// This happens when the user leaves the Editor and returns,
// they could have changed the textures, so the cache is cleared.
cache_map.clear();
@@ -767,11 +767,11 @@ void TextureRegionEditor::_notification(int p_what) {
void TextureRegionEditor::_node_removed(Object *p_obj) {
if (p_obj == node_sprite || p_obj == node_sprite_3d || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) {
- node_sprite = NULL;
- node_sprite_3d = NULL;
- node_ninepatch = NULL;
- obj_styleBox = Ref<StyleBox>(NULL);
- atlas_tex = Ref<AtlasTexture>(NULL);
+ node_sprite = nullptr;
+ node_sprite_3d = nullptr;
+ node_ninepatch = nullptr;
+ obj_styleBox = Ref<StyleBox>(nullptr);
+ atlas_tex = Ref<AtlasTexture>(nullptr);
hide();
}
}
@@ -793,14 +793,14 @@ bool TextureRegionEditor::is_atlas_texture() {
}
bool TextureRegionEditor::is_ninepatch() {
- return node_ninepatch != NULL;
+ return node_ninepatch != nullptr;
}
Sprite3D *TextureRegionEditor::get_sprite_3d() {
return node_sprite_3d;
}
-Sprite *TextureRegionEditor::get_sprite() {
+Sprite2D *TextureRegionEditor::get_sprite() {
return node_sprite;
}
@@ -816,7 +816,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
if (atlas_tex.is_valid())
atlas_tex->remove_change_receptor(this);
if (p_obj) {
- node_sprite = Object::cast_to<Sprite>(p_obj);
+ node_sprite = Object::cast_to<Sprite2D>(p_obj);
node_sprite_3d = Object::cast_to<Sprite3D>(p_obj);
node_ninepatch = Object::cast_to<NinePatchRect>(p_obj);
if (Object::cast_to<StyleBoxTexture>(p_obj))
@@ -826,11 +826,11 @@ void TextureRegionEditor::edit(Object *p_obj) {
p_obj->add_change_receptor(this);
_edit_region();
} else {
- node_sprite = NULL;
- node_sprite_3d = NULL;
- node_ninepatch = NULL;
- obj_styleBox = Ref<StyleBoxTexture>(NULL);
- atlas_tex = Ref<AtlasTexture>(NULL);
+ node_sprite = nullptr;
+ node_sprite_3d = nullptr;
+ node_ninepatch = nullptr;
+ obj_styleBox = Ref<StyleBoxTexture>(nullptr);
+ atlas_tex = Ref<AtlasTexture>(nullptr);
}
edit_draw->update();
if ((node_sprite && !node_sprite->is_region()) || (node_sprite_3d && !node_sprite_3d->is_region())) {
@@ -850,7 +850,7 @@ void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_pro
}
void TextureRegionEditor::_edit_region() {
- Ref<Texture2D> texture = NULL;
+ Ref<Texture2D> texture = nullptr;
if (node_sprite)
texture = node_sprite->get_texture();
else if (node_sprite_3d)
@@ -896,11 +896,11 @@ Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
}
TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
- node_sprite = NULL;
- node_sprite_3d = NULL;
- node_ninepatch = NULL;
- obj_styleBox = Ref<StyleBoxTexture>(NULL);
- atlas_tex = Ref<AtlasTexture>(NULL);
+ node_sprite = nullptr;
+ node_sprite_3d = nullptr;
+ node_ninepatch = nullptr;
+ obj_styleBox = Ref<StyleBoxTexture>(nullptr);
+ atlas_tex = Ref<AtlasTexture>(nullptr);
editor = p_editor;
undo_redo = editor->get_undo_redo();
@@ -1030,6 +1030,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
hscroll->connect("value_changed", callable_mp(this, &TextureRegionEditor::_scroll_changed));
updating_scroll = false;
+ autoslice_is_dirty = true;
}
void TextureRegionEditorPlugin::edit(Object *p_object) {
@@ -1037,7 +1038,7 @@ void TextureRegionEditorPlugin::edit(Object *p_object) {
}
bool TextureRegionEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("Sprite") || p_object->is_class("Sprite3D") || p_object->is_class("NinePatchRect") || p_object->is_class("StyleBoxTexture") || p_object->is_class("AtlasTexture");
+ return p_object->is_class("Sprite2D") || p_object->is_class("Sprite3D") || p_object->is_class("NinePatchRect") || p_object->is_class("StyleBoxTexture") || p_object->is_class("AtlasTexture");
}
void TextureRegionEditorPlugin::_editor_visiblity_changed() {
@@ -1057,7 +1058,7 @@ void TextureRegionEditorPlugin::make_visible(bool p_visible) {
manually_hidden = false;
}
texture_region_button->hide();
- region_editor->edit(NULL);
+ region_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index d877cf9436..c6cd648842 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -34,7 +34,7 @@
#include "canvas_item_editor_plugin.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/sprite_2d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/gui/nine_patch_rect.h"
#include "scene/resources/style_box.h"
@@ -84,7 +84,7 @@ class TextureRegionEditor : public VBoxContainer {
Vector2 snap_step;
Vector2 snap_separation;
- Sprite *node_sprite;
+ Sprite2D *node_sprite;
Sprite3D *node_sprite_3d;
NinePatchRect *node_ninepatch;
Ref<StyleBoxTexture> obj_styleBox;
@@ -94,7 +94,7 @@ class TextureRegionEditor : public VBoxContainer {
Rect2 rect_prev;
float prev_margin;
int edited_margin;
- Map<RID, List<Rect2> > cache_map;
+ Map<RID, List<Rect2>> cache_map;
List<Rect2> autoslice_cache;
bool autoslice_is_dirty;
@@ -136,7 +136,7 @@ public:
bool is_atlas_texture();
bool is_ninepatch();
Sprite3D *get_sprite_3d();
- Sprite *get_sprite();
+ Sprite2D *get_sprite();
void edit(Object *p_obj);
TextureRegionEditor(EditorNode *p_editor);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index d5b52e9711..b246b611fd 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -120,12 +120,12 @@ struct _TECategory {
bool operator<(const Item<T> &p) const { return name < p.name; }
};
- Set<RefItem<StyleBox> > stylebox_items;
- Set<RefItem<Font> > font_items;
- Set<RefItem<Texture2D> > icon_items;
+ Set<RefItem<StyleBox>> stylebox_items;
+ Set<RefItem<Font>> font_items;
+ Set<RefItem<Texture2D>> icon_items;
- Set<Item<Color> > color_items;
- Set<Item<int> > constant_items;
+ Set<Item<Color>> color_items;
+ Set<Item<int>> constant_items;
};
void ThemeEditor::_save_template_cbk(String fname) {
@@ -275,7 +275,7 @@ void ThemeEditor::_save_template_cbk(String fname) {
if (tc.stylebox_items.size())
file->store_line("\n; StyleBox Items:\n");
- for (Set<_TECategory::RefItem<StyleBox> >::Element *F = tc.stylebox_items.front(); F; F = F->next()) {
+ for (Set<_TECategory::RefItem<StyleBox>>::Element *F = tc.stylebox_items.front(); F; F = F->next()) {
file->store_line(E->key() + "." + F->get().name + " = default");
}
@@ -283,7 +283,7 @@ void ThemeEditor::_save_template_cbk(String fname) {
if (tc.font_items.size())
file->store_line("\n; Font Items:\n");
- for (Set<_TECategory::RefItem<Font> >::Element *F = tc.font_items.front(); F; F = F->next()) {
+ for (Set<_TECategory::RefItem<Font>>::Element *F = tc.font_items.front(); F; F = F->next()) {
file->store_line(E->key() + "." + F->get().name + " = default");
}
@@ -291,7 +291,7 @@ void ThemeEditor::_save_template_cbk(String fname) {
if (tc.icon_items.size())
file->store_line("\n; Icon Items:\n");
- for (Set<_TECategory::RefItem<Texture2D> >::Element *F = tc.icon_items.front(); F; F = F->next()) {
+ for (Set<_TECategory::RefItem<Texture2D>>::Element *F = tc.icon_items.front(); F; F = F->next()) {
file->store_line(E->key() + "." + F->get().name + " = default");
}
@@ -299,7 +299,7 @@ void ThemeEditor::_save_template_cbk(String fname) {
if (tc.color_items.size())
file->store_line("\n; Color Items:\n");
- for (Set<_TECategory::Item<Color> >::Element *F = tc.color_items.front(); F; F = F->next()) {
+ for (Set<_TECategory::Item<Color>>::Element *F = tc.color_items.front(); F; F = F->next()) {
file->store_line(E->key() + "." + F->get().name + " = default");
}
@@ -307,7 +307,7 @@ void ThemeEditor::_save_template_cbk(String fname) {
if (tc.constant_items.size())
file->store_line("\n; Constant Items:\n");
- for (Set<_TECategory::Item<int> >::Element *F = tc.constant_items.front(); F; F = F->next()) {
+ for (Set<_TECategory::Item<int>>::Element *F = tc.constant_items.front(); F; F = F->next()) {
file->store_line(E->key() + "." + F->get().name + " = default");
}
@@ -592,7 +592,7 @@ void ThemeEditor::_notification(int p_what) {
}
} break;
case NOTIFICATION_THEME_CHANGED: {
- theme_menu->set_icon(get_icon("Theme", "EditorIcons"));
+ theme_menu->set_icon(get_theme_icon("Theme", "EditorIcons"));
} break;
}
}
@@ -645,10 +645,10 @@ ThemeEditor::ThemeEditor() {
main_container = memnew(MarginContainer);
root_container->add_child(main_container);
- main_container->add_constant_override("margin_right", 4 * EDSCALE);
- main_container->add_constant_override("margin_top", 4 * EDSCALE);
- main_container->add_constant_override("margin_left", 4 * EDSCALE);
- main_container->add_constant_override("margin_bottom", 4 * EDSCALE);
+ main_container->add_theme_constant_override("margin_right", 4 * EDSCALE);
+ main_container->add_theme_constant_override("margin_top", 4 * EDSCALE);
+ main_container->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ main_container->add_theme_constant_override("margin_bottom", 4 * EDSCALE);
HBoxContainer *main_hb = memnew(HBoxContainer);
main_container->add_child(main_hb);
@@ -656,7 +656,7 @@ ThemeEditor::ThemeEditor() {
VBoxContainer *first_vb = memnew(VBoxContainer);
main_hb->add_child(first_vb);
first_vb->set_h_size_flags(SIZE_EXPAND_FILL);
- first_vb->add_constant_override("separation", 10 * EDSCALE);
+ first_vb->add_theme_constant_override("separation", 10 * EDSCALE);
first_vb->add_child(memnew(Label("Label")));
@@ -716,7 +716,7 @@ ThemeEditor::ThemeEditor() {
VBoxContainer *second_vb = memnew(VBoxContainer);
second_vb->set_h_size_flags(SIZE_EXPAND_FILL);
main_hb->add_child(second_vb);
- second_vb->add_constant_override("separation", 10 * EDSCALE);
+ second_vb->add_theme_constant_override("separation", 10 * EDSCALE);
LineEdit *le = memnew(LineEdit);
le->set_text("LineEdit");
second_vb->add_child(le);
@@ -756,7 +756,7 @@ ThemeEditor::ThemeEditor() {
VBoxContainer *third_vb = memnew(VBoxContainer);
third_vb->set_h_size_flags(SIZE_EXPAND_FILL);
- third_vb->add_constant_override("separation", 10 * EDSCALE);
+ third_vb->add_theme_constant_override("separation", 10 * EDSCALE);
main_hb->add_child(third_vb);
TabContainer *tc = memnew(TabContainer);
@@ -776,7 +776,7 @@ ThemeEditor::ThemeEditor() {
Tree *test_tree = memnew(Tree);
third_vb->add_child(test_tree);
test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE);
- test_tree->add_constant_override("draw_relationship_lines", 1);
+ test_tree->add_theme_constant_override("draw_relationship_lines", 1);
TreeItem *item = test_tree->create_item();
item->set_text(0, "Tree");
@@ -802,7 +802,7 @@ ThemeEditor::ThemeEditor() {
item->set_text(0, TTR("Has,Many,Options"));
item->set_range(0, 2);
- main_hb->add_constant_override("separation", 20 * EDSCALE);
+ main_hb->add_theme_constant_override("separation", 20 * EDSCALE);
////////
@@ -846,7 +846,7 @@ ThemeEditor::ThemeEditor() {
name_menu->set_text("..");
name_hbc->add_child(name_menu);
- name_menu->get_popup()->connect("about_to_show", callable_mp(this, &ThemeEditor::_name_menu_about_to_show));
+ 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);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 017f986469..ce421ac0a5 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -31,13 +31,20 @@
#include "tile_map_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/math/math_funcs.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "scene/gui/split_container.h"
+void TileMapEditor::_node_removed(Node *p_node) {
+
+ if (p_node == node) {
+ node = nullptr;
+ }
+}
+
void TileMapEditor::_notification(int p_what) {
switch (p_what) {
@@ -60,25 +67,30 @@ void TileMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
- paint_button->set_icon(get_icon("Edit", "EditorIcons"));
- bucket_fill_button->set_icon(get_icon("Bucket", "EditorIcons"));
- picker_button->set_icon(get_icon("ColorPick", "EditorIcons"));
- select_button->set_icon(get_icon("ActionCopy", "EditorIcons"));
+ get_tree()->connect("node_removed", callable_mp(this, &TileMapEditor::_node_removed));
+ paint_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ bucket_fill_button->set_icon(get_theme_icon("Bucket", "EditorIcons"));
+ picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
+ select_button->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
- rotate_left_button->set_icon(get_icon("RotateLeft", "EditorIcons"));
- rotate_right_button->set_icon(get_icon("RotateRight", "EditorIcons"));
- flip_horizontal_button->set_icon(get_icon("MirrorX", "EditorIcons"));
- flip_vertical_button->set_icon(get_icon("MirrorY", "EditorIcons"));
- clear_transform_button->set_icon(get_icon("Clear", "EditorIcons"));
+ rotate_left_button->set_icon(get_theme_icon("RotateLeft", "EditorIcons"));
+ rotate_right_button->set_icon(get_theme_icon("RotateRight", "EditorIcons"));
+ flip_horizontal_button->set_icon(get_theme_icon("MirrorX", "EditorIcons"));
+ flip_vertical_button->set_icon(get_theme_icon("MirrorY", "EditorIcons"));
+ clear_transform_button->set_icon(get_theme_icon("Clear", "EditorIcons"));
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
PopupMenu *p = options->get_popup();
- p->set_item_icon(p->get_item_index(OPTION_CUT), get_icon("ActionCut", "EditorIcons"));
- p->set_item_icon(p->get_item_index(OPTION_COPY), get_icon("Duplicate", "EditorIcons"));
- p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_icon("Remove", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_CUT), get_theme_icon("ActionCut", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_COPY), get_theme_icon("Duplicate", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_theme_icon("Remove", "EditorIcons"));
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &TileMapEditor::_node_removed));
} break;
}
}
@@ -421,7 +433,7 @@ void TileMapEditor::_update_palette() {
bool show_tile_ids = bool(EDITOR_DEF("editors/tile_map/show_tile_ids", false));
bool sort_by_name = bool(EDITOR_DEF("editors/tile_map/sort_tiles_by_name", true));
- palette->add_constant_override("hseparation", hseparation * EDSCALE);
+ palette->add_theme_constant_override("hseparation", hseparation * EDSCALE);
palette->set_fixed_icon_size(Size2(min_size, min_size));
palette->set_fixed_column_width(min_size * MAX(size_slider->get_value(), 1));
@@ -627,7 +639,7 @@ Vector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase,
if (r != bucket_cache_rect)
_clear_bucket_cache();
// Cache grid is not initialized
- if (bucket_cache_visited == NULL) {
+ if (bucket_cache_visited == nullptr) {
bucket_cache_visited = new bool[area];
invalidate_cache = true;
}
@@ -894,7 +906,7 @@ void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Po
void TileMapEditor::_clear_bucket_cache() {
if (bucket_cache_visited) {
delete[] bucket_cache_visited;
- bucket_cache_visited = NULL;
+ bucket_cache_visited = nullptr;
}
}
@@ -984,7 +996,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mb->is_pressed()) {
- if (Input::get_singleton()->is_key_pressed(KEY_SPACE))
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SPACE))
return false; // Drag.
if (tool == TOOL_NONE) {
@@ -1365,7 +1377,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 && InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
_pick_tile(over_tile);
@@ -1773,7 +1785,7 @@ void TileMapEditor::edit(Node *p_tile_map) {
_update_palette();
} else {
- node = NULL;
+ node = nullptr;
if (canvas_item_editor_viewport->is_connected("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter)))
canvas_item_editor_viewport->disconnect("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter));
@@ -1889,11 +1901,11 @@ void TileMapEditor::_clear_transform() {
TileMapEditor::TileMapEditor(EditorNode *p_editor) {
- node = NULL;
+ node = nullptr;
manual_autotile = false;
priority_atlastile = false;
manual_position = Vector2(0, 0);
- canvas_item_editor_viewport = NULL;
+ canvas_item_editor_viewport = nullptr;
editor = p_editor;
undo_redo = EditorNode::get_undo_redo();
@@ -1906,7 +1918,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
transpose = false;
bucket_cache_tile = -1;
- bucket_cache_visited = NULL;
+ bucket_cache_visited = nullptr;
invalid_cell.resize(1);
invalid_cell.write[0] = TileMap::INVALID_CELL;
@@ -1960,7 +1972,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
palette->set_icon_mode(ItemList::ICON_MODE_TOP);
palette->set_max_text_lines(2);
palette->set_select_mode(ItemList::SELECT_MULTI);
- palette->add_constant_override("vseparation", 8 * EDSCALE);
+ palette->add_theme_constant_override("vseparation", 8 * EDSCALE);
palette->connect("item_selected", callable_mp(this, &TileMapEditor::_palette_selected));
palette->connect("multi_selected", callable_mp(this, &TileMapEditor::_palette_multi_selected));
palette_container->add_child(palette);
@@ -2031,7 +2043,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
tile_info = memnew(Label);
tile_info->set_modulate(Color(1, 1, 1, 0.8));
tile_info->set_mouse_filter(MOUSE_FILTER_IGNORE);
- tile_info->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts"));
+ tile_info->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts"));
// The tile info is only displayed after a tile has been hovered.
tile_info->hide();
CanvasItemEditor::get_singleton()->add_control_to_info_overlay(tile_info);
@@ -2039,7 +2051,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
// Menu.
options = memnew(MenuButton);
options->set_text("TileMap");
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("TileMap", "EditorIcons"));
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("TileMap", "EditorIcons"));
options->set_process_unhandled_key_input(false);
toolbar_right->add_child(options);
@@ -2142,7 +2154,7 @@ void TileMapEditorPlugin::make_visible(bool p_visible) {
tile_map_editor->get_toolbar()->hide();
tile_map_editor->get_toolbar_right()->hide();
tile_map_editor->get_tile_info()->hide();
- tile_map_editor->edit(NULL);
+ tile_map_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 74969d3e64..f43e5bb5cb 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -211,6 +211,7 @@ class TileMapEditor : public VBoxContainer {
protected:
void _notification(int p_what);
+ void _node_removed(Node *p_node);
static void _bind_methods();
CellOp _get_op_from_cell(const Point2i &p_pos);
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index d23b037ed4..d1dda68c1d 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -30,12 +30,12 @@
#include "tile_set_editor_plugin.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/physics_body_2d.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/sprite_2d.h"
void TileSetEditor::edit(const Ref<TileSet> &p_tileset) {
@@ -53,7 +53,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
Node *child = p_node->get_child(i);
- if (!Object::cast_to<Sprite>(child)) {
+ if (!Object::cast_to<Sprite2D>(child)) {
if (child->get_child_count() > 0) {
_import_node(child, p_library);
}
@@ -61,7 +61,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
continue;
}
- Sprite *mi = Object::cast_to<Sprite>(child);
+ Sprite2D *mi = Object::cast_to<Sprite2D>(child);
Ref<Texture2D> texture = mi->get_texture();
Ref<Texture2D> normal_map = mi->get_normal_map();
Ref<ShaderMaterial> material = mi->get_material();
@@ -284,47 +284,47 @@ void TileSetEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- add_constant_override("autohide", 1); // Fixes the dragger always showing up.
+ add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up.
} break;
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_icon("ToolAddNode", "EditorIcons"));
- tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_icon("Remove", "EditorIcons"));
- tileset_toolbar_tools->set_icon(get_icon("Tools", "EditorIcons"));
-
- tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_icon("Edit", "EditorIcons"));
- tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_icon("AddSingleTile", "EditorIcons"));
- tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_icon("AddAutotile", "EditorIcons"));
- tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_icon("AddAtlasTile", "EditorIcons"));
-
- tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
- tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons"));
- tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons"));
- tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons"));
- tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons"));
- tools[SHAPE_NEW_RECTANGLE]->set_icon(get_icon("CollisionShape2D", "EditorIcons"));
- tools[SELECT_PREVIOUS]->set_icon(get_icon("ArrowLeft", "EditorIcons"));
- tools[SELECT_NEXT]->set_icon(get_icon("ArrowRight", "EditorIcons"));
- tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons"));
- tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons"));
- tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons"));
- tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons"));
- tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons"));
- tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons"));
- tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons"));
+ tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_theme_icon("ToolAddNode", "EditorIcons"));
+ tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ tileset_toolbar_tools->set_icon(get_theme_icon("Tools", "EditorIcons"));
+
+ tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_theme_icon("AddSingleTile", "EditorIcons"));
+ tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_theme_icon("AddAutotile", "EditorIcons"));
+ tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_theme_icon("AddAtlasTile", "EditorIcons"));
+
+ tools[TOOL_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons"));
+ tools[BITMASK_COPY]->set_icon(get_theme_icon("Duplicate", "EditorIcons"));
+ tools[BITMASK_PASTE]->set_icon(get_theme_icon("Override", "EditorIcons"));
+ tools[BITMASK_CLEAR]->set_icon(get_theme_icon("Clear", "EditorIcons"));
+ tools[SHAPE_NEW_POLYGON]->set_icon(get_theme_icon("CollisionPolygon2D", "EditorIcons"));
+ tools[SHAPE_NEW_RECTANGLE]->set_icon(get_theme_icon("CollisionShape2D", "EditorIcons"));
+ tools[SELECT_PREVIOUS]->set_icon(get_theme_icon("ArrowLeft", "EditorIcons"));
+ tools[SELECT_NEXT]->set_icon(get_theme_icon("ArrowRight", "EditorIcons"));
+ tools[SHAPE_DELETE]->set_icon(get_theme_icon("Remove", "EditorIcons"));
+ tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_theme_icon("Snap", "EditorIcons"));
+ tools[TOOL_GRID_SNAP]->set_icon(get_theme_icon("SnapGrid", "EditorIcons"));
+ tools[ZOOM_OUT]->set_icon(get_theme_icon("ZoomLess", "EditorIcons"));
+ tools[ZOOM_1]->set_icon(get_theme_icon("ZoomReset", "EditorIcons"));
+ tools[ZOOM_IN]->set_icon(get_theme_icon("ZoomMore", "EditorIcons"));
+ tools[VISIBLE_INFO]->set_icon(get_theme_icon("InformationSign", "EditorIcons"));
_update_toggle_shape_button();
- tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons"));
- tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons"));
- tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_icon("LightOccluder2D", "EditorIcons"));
- tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_icon("Navigation2D", "EditorIcons"));
- tool_editmode[EDITMODE_BITMASK]->set_icon(get_icon("PackedDataContainer", "EditorIcons"));
- tool_editmode[EDITMODE_PRIORITY]->set_icon(get_icon("MaterialPreviewLight1", "EditorIcons"));
- tool_editmode[EDITMODE_ICON]->set_icon(get_icon("LargeTexture", "EditorIcons"));
- tool_editmode[EDITMODE_Z_INDEX]->set_icon(get_icon("Sort", "EditorIcons"));
+ tool_editmode[EDITMODE_REGION]->set_icon(get_theme_icon("RegionEdit", "EditorIcons"));
+ tool_editmode[EDITMODE_COLLISION]->set_icon(get_theme_icon("StaticBody2D", "EditorIcons"));
+ tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_theme_icon("LightOccluder2D", "EditorIcons"));
+ 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_Z_INDEX]->set_icon(get_theme_icon("Sort", "EditorIcons"));
- scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
+ scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
} break;
}
}
@@ -528,8 +528,8 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
toolbar->add_child(spin_priority);
spin_z_index = memnew(SpinBox);
- spin_z_index->set_min(VS::CANVAS_ITEM_Z_MIN);
- spin_z_index->set_max(VS::CANVAS_ITEM_Z_MAX);
+ spin_z_index->set_min(RS::CANVAS_ITEM_Z_MIN);
+ spin_z_index->set_max(RS::CANVAS_ITEM_Z_MAX);
spin_z_index->set_step(1);
spin_z_index->set_custom_minimum_size(Size2(100, 0));
spin_z_index->connect("value_changed", callable_mp(this, &TileSetEditor::_on_z_index_changed));
@@ -601,7 +601,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
workspace->set_draw_behind_parent(true);
workspace_overlay->add_child(workspace);
- preview = memnew(Sprite);
+ preview = memnew(Sprite2D);
workspace->add_child(preview);
preview->set_centered(false);
preview->set_draw_behind_parent(true);
@@ -619,7 +619,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
//---------------
texture_dialog = memnew(EditorFileDialog);
texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
- texture_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILES);
+ texture_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
texture_dialog->clear_filters();
List<String> extensions;
@@ -725,7 +725,7 @@ void TileSetEditor::_on_texture_list_selected(int p_index) {
update_workspace_minsize();
} else {
current_item_index = -1;
- preview->set_texture(NULL);
+ preview->set_texture(nullptr);
workspace->set_custom_minimum_size(Size2i());
update_workspace_tile_mode();
}
@@ -1113,7 +1113,7 @@ void TileSetEditor::_on_workspace_draw() {
void TileSetEditor::_on_workspace_process() {
- if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) {
if (!tile_names_visible) {
tile_names_visible = true;
workspace_overlay->update();
@@ -1153,7 +1153,7 @@ void TileSetEditor::_on_workspace_overlay_draw() {
else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE)
c = COLOR_ATLAS;
String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id);
- Ref<Font> font = get_font("font", "Label");
+ Ref<Font> font = get_theme_font("font", "Label");
region.set_size(font->get_string_size(tile_id_name));
workspace_overlay->draw_rect(region, c);
region.position.y += region.size.y - 2;
@@ -1167,7 +1167,7 @@ void TileSetEditor::_on_workspace_overlay_draw() {
if (t_id < 0)
return;
- Ref<Texture2D> handle = get_icon("EditorHandle", "EditorIcons");
+ Ref<Texture2D> handle = get_theme_icon("EditorHandle", "EditorIcons");
if (draw_handles) {
for (int i = 0; i < current_shape.size(); i++) {
workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5);
@@ -1395,7 +1395,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
dragging = true;
erasing = (mb->get_button_index() == BUTTON_RIGHT);
- alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ alternative = InputFilter::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));
pos = mb->get_position() - (pos + current_tile_region.position);
@@ -2019,10 +2019,10 @@ void TileSetEditor::_update_toggle_shape_button() {
separator_shape_toggle->hide();
tools[SHAPE_TOGGLE_TYPE]->hide();
} else if (concave.is_valid()) {
- tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConvexPolygonShape2D", "EditorIcons"));
+ tools[SHAPE_TOGGLE_TYPE]->set_icon(get_theme_icon("ConvexPolygonShape2D", "EditorIcons"));
tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Convex"));
} else if (convex.is_valid()) {
- tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons"));
+ tools[SHAPE_TOGGLE_TYPE]->set_icon(get_theme_icon("ConcavePolygonShape2D", "EditorIcons"));
tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Concave"));
} else {
// Shouldn't happen
@@ -2350,12 +2350,12 @@ void TileSetEditor::_undo_tile_removal(int p_id) {
undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", p_id, tileset->tile_get_light_occluder(p_id));
undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", p_id, tileset->tile_get_navigation_polygon(p_id));
} else {
- Map<Vector2, Ref<OccluderPolygon2D> > oclusion_map = tileset->autotile_get_light_oclusion_map(p_id);
- for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = oclusion_map.front(); E; E = E->next()) {
+ Map<Vector2, Ref<OccluderPolygon2D>> oclusion_map = tileset->autotile_get_light_oclusion_map(p_id);
+ for (Map<Vector2, Ref<OccluderPolygon2D>>::Element *E = oclusion_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", p_id, E->value(), E->key());
}
- Map<Vector2, Ref<NavigationPolygon> > navigation_map = tileset->autotile_get_navigation_map(p_id);
- for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = navigation_map.front(); E; E = E->next()) {
+ Map<Vector2, Ref<NavigationPolygon>> navigation_map = tileset->autotile_get_navigation_map(p_id);
+ for (Map<Vector2, Ref<NavigationPolygon>>::Element *E = navigation_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", p_id, E->value(), E->key());
}
Map<Vector2, uint32_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
@@ -2693,8 +2693,8 @@ void TileSetEditor::draw_polygon_shapes() {
}
}
} else {
- Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id);
- for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) {
+ Map<Vector2, Ref<OccluderPolygon2D>> map = tileset->autotile_get_light_oclusion_map(t_id);
+ for (Map<Vector2, Ref<OccluderPolygon2D>>::Element *E = map.front(); E; E = E->next()) {
Vector2 coord = E->key();
Vector2 anchor = tileset->autotile_get_size(t_id);
anchor.x += tileset->autotile_get_spacing(t_id);
@@ -2781,8 +2781,8 @@ void TileSetEditor::draw_polygon_shapes() {
}
}
} else {
- Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id);
- for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) {
+ Map<Vector2, Ref<NavigationPolygon>> map = tileset->autotile_get_navigation_map(t_id);
+ for (Map<Vector2, Ref<NavigationPolygon>>::Element *E = map.front(); E; E = E->next()) {
Vector2 coord = E->key();
Vector2 anchor = tileset->autotile_get_size(t_id);
anchor.x += tileset->autotile_get_spacing(t_id);
@@ -3003,7 +3003,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) {
}
}
if (!found_collision_shape)
- _set_edited_collision_shape(Ref<ConvexPolygonShape2D>(NULL));
+ _set_edited_collision_shape(Ref<ConvexPolygonShape2D>(nullptr));
if (edited_occlusion_shape != tileset->autotile_get_light_occluder(get_current_tile(), coord))
edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), coord);
if (edited_navigation_shape != tileset->autotile_get_navigation_polygon(get_current_tile(), coord))
@@ -3485,7 +3485,7 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const
p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_navigation_offset"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
- p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"));
}
if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) {
p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class()));
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 7b49e2ece2..53f8e8c4d6 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -32,7 +32,7 @@
#define TILE_SET_EDITOR_PLUGIN_H
#include "editor/editor_node.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/sprite_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/tile_set.h"
@@ -114,7 +114,7 @@ class TileSetEditor : public HSplitContainer {
int option;
ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX];
MenuButton *tileset_toolbar_tools;
- Map<RID, Ref<Texture2D> > texture_map;
+ Map<RID, Ref<Texture2D>> texture_map;
bool creating_shape;
int dragging_point;
@@ -136,7 +136,7 @@ class TileSetEditor : public HSplitContainer {
Ref<NavigationPolygon> edited_navigation_shape;
int current_item_index;
- Sprite *preview;
+ Sprite2D *preview;
ScrollContainer *scroll;
Label *empty_message;
Control *workspace_container;
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index da80eee253..fe8392593b 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -35,7 +35,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
-VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = NULL;
+VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;
void VersionControlEditorPlugin::_bind_methods() {
@@ -171,7 +171,7 @@ void VersionControlEditorPlugin::_refresh_stage_area() {
for (int i = 0; i < modified_file_paths.size(); i++) {
file_path = modified_file_paths.get_key_at_index(i);
- TreeItem *found = stage_files->search_item_text(file_path, 0, true);
+ TreeItem *found = stage_files->search_item_text(file_path, nullptr, true);
if (!found) {
ChangeType change_index = (ChangeType)(int)modified_file_paths.get_value_at_index(i);
@@ -217,12 +217,12 @@ void VersionControlEditorPlugin::_stage_selected() {
if (file_entry->is_checked(0)) {
EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor"));
+ file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"));
staged_files_count++;
} else {
EditorVCSInterface::get_singleton()->unstage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
}
file_entry = file_entry->get_next();
@@ -248,7 +248,7 @@ void VersionControlEditorPlugin::_stage_all() {
while (file_entry) {
EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor"));
+ file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"));
file_entry->set_checked(0, true);
staged_files_count++;
@@ -275,20 +275,20 @@ void VersionControlEditorPlugin::_display_file_diff(String p_file_path) {
diff_file_name->set_text(p_file_path);
diff->clear();
- diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts"));
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font("source", "EditorFonts"));
for (int i = 0; i < diff_content.size(); i++) {
Dictionary line_result = diff_content[i];
if (line_result["status"] == "+") {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor"));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"));
} else if (line_result["status"] == "-") {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
} else {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_color("font_color", "Label"));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color("font_color", "Label"));
}
diff->add_text((String)line_result["content"]);
@@ -385,7 +385,7 @@ void VersionControlEditorPlugin::shut_down() {
}
EditorVCSInterface::get_singleton()->shut_down();
memdelete(EditorVCSInterface::get_singleton());
- EditorVCSInterface::set_singleton(NULL);
+ EditorVCSInterface::set_singleton(nullptr);
EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock);
EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock);
@@ -408,11 +408,10 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
staged_files_count = 0;
version_control_actions = memnew(PopupMenu);
- version_control_actions->set_v_size_flags(BoxContainer::SIZE_SHRINK_CENTER);
set_up_dialog = memnew(AcceptDialog);
set_up_dialog->set_title(TTR("Set Up Version Control"));
- set_up_dialog->set_custom_minimum_size(Size2(400, 100));
+ set_up_dialog->set_min_size(Size2(400, 100));
version_control_actions->add_child(set_up_dialog);
set_up_ok_button = set_up_dialog->get_ok();
@@ -439,16 +438,13 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
set_up_choice->connect("item_selected", callable_mp(this, &VersionControlEditorPlugin::_selected_a_vcs));
set_up_hbc->add_child(set_up_choice);
- set_up_init_settings = NULL;
+ set_up_init_settings = nullptr;
set_up_init_button = memnew(Button);
set_up_init_button->set_text(TTR("Initialize"));
set_up_init_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_initialize_vcs));
set_up_vbc->add_child(set_up_init_button);
- version_control_actions->set_v_size_flags(PopupMenu::SIZE_EXPAND_FILL);
- version_control_actions->set_h_size_flags(PopupMenu::SIZE_EXPAND_FILL);
-
version_commit_dock = memnew(VBoxContainer);
version_commit_dock->set_visible(false);
@@ -470,7 +466,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
refresh_button = memnew(Button);
refresh_button->set_tooltip(TTR("Detect new changes"));
refresh_button->set_text(TTR("Refresh"));
- refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Reload", "EditorIcons"));
+ refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Reload", "EditorIcons"));
refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
stage_tools->add_child(refresh_button);
@@ -495,11 +491,11 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
change_type_to_strings[CHANGE_TYPE_DELETED] = TTR("Deleted");
change_type_to_strings[CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");
- change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor");
- change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor");
- change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_color("disabled_font_color", "Editor");
- change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor");
- change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_color("font_color", "Editor");
+ change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor");
+ change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor");
+ change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("disabled_font_color", "Editor");
+ change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor");
+ change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("font_color", "Editor");
stage_buttons = memnew(HSplitContainer);
stage_buttons->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED);
@@ -562,7 +558,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
diff_refresh_button = memnew(Button);
diff_refresh_button->set_tooltip(TTR("Detect changes in file diff"));
- diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Reload", "EditorIcons"));
+ diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Reload", "EditorIcons"));
diff_refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_file_diff));
diff_hbc->add_child(diff_refresh_button);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 9100e28352..294ce2c4cd 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -30,9 +30,9 @@
#include "visual_shader_editor_plugin.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_loader.h"
#include "core/math/math_defs.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "core/version.h"
@@ -42,16 +42,17 @@
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/visual_shader_nodes.h"
-#include "servers/visual/shader_types.h"
+#include "servers/display_server.h"
+#include "servers/rendering/shader_types.h"
Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
if (get_script_instance()) {
return get_script_instance()->call("create_editor", p_parent_resource, p_node);
}
- return NULL;
+ return nullptr;
}
void VisualShaderNodePlugin::_bind_methods() {
@@ -312,8 +313,8 @@ void VisualShaderEditor::_update_options_menu() {
bool is_first_item = true;
- Color unsupported_color = get_color("error_color", "Editor");
- Color supported_color = get_color("warning_color", "Editor");
+ 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";
@@ -351,7 +352,7 @@ void VisualShaderEditor::_update_options_menu() {
for (int i = 0; i < options.size(); i++) {
String path = options[i].category;
Vector<String> subfolders = path.split("/");
- TreeItem *category = NULL;
+ TreeItem *category = nullptr;
if (!folders.has(path)) {
category = root;
@@ -385,22 +386,22 @@ void VisualShaderEditor::_update_options_menu() {
}
switch (options[i].return_type) {
case VisualShaderNode::PORT_TYPE_SCALAR:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("int", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_VECTOR:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_TRANSFORM:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_SAMPLER:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"));
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"));
break;
default:
break;
@@ -420,7 +421,7 @@ void VisualShaderEditor::_draw_color_over_button(Object *obj, Color p_color) {
if (!button)
return;
- Ref<StyleBox> normal = get_stylebox("normal", "Button");
+ Ref<StyleBox> normal = get_theme_stylebox("normal", "Button");
button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);
}
@@ -436,7 +437,7 @@ static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_
void VisualShaderEditor::_update_created_node(GraphNode *node) {
if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode");
+ Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
Color c = sb->get_border_color();
Color ic;
Color mono_color;
@@ -450,10 +451,10 @@ void VisualShaderEditor::_update_created_node(GraphNode *node) {
mono_color.a = 0.85;
c = mono_color;
- node->add_color_override("title_color", c);
+ node->add_theme_color_override("title_color", c);
c.a = 0.7;
- node->add_color_override("close_color", c);
- node->add_color_override("resizer_color", ic);
+ node->add_theme_color_override("close_color", c);
+ node->add_theme_color_override("resizer_color", ic);
}
}
@@ -535,7 +536,7 @@ void VisualShaderEditor::_update_graph() {
node->connect("dragged", callable_mp(this, &VisualShaderEditor::_node_dragged), varray(nodes[n_i]));
- Control *custom_editor = NULL;
+ Control *custom_editor = nullptr;
int port_offset = 0;
if (is_group) {
@@ -555,6 +556,17 @@ void VisualShaderEditor::_update_graph() {
uniform_name->connect("text_entered", callable_mp(this, &VisualShaderEditor::_line_edit_changed), varray(uniform_name, nodes[n_i]));
uniform_name->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_line_edit_focus_out), varray(uniform_name, nodes[n_i]));
+ String error = vsnode->get_warning(visual_shader->get_mode(), type);
+ if (error != String()) {
+ offset = memnew(Control);
+ offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
+ node->add_child(offset);
+ Label *error_label = memnew(Label);
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
+ error_label->set_text(error);
+ node->add_child(error_label);
+ }
+
if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
//shortcut
VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0);
@@ -583,7 +595,7 @@ void VisualShaderEditor::_update_graph() {
custom_editor->call_deferred("_show_prop_names", true);
continue;
}
- custom_editor = NULL;
+ custom_editor = nullptr;
}
if (is_group) {
@@ -641,7 +653,7 @@ void VisualShaderEditor::_update_graph() {
}
HBoxContainer *hb = memnew(HBoxContainer);
- hb->add_constant_override("separation", 7 * EDSCALE);
+ hb->add_theme_constant_override("separation", 7 * EDSCALE);
Variant default_value;
@@ -705,7 +717,7 @@ void VisualShaderEditor::_update_graph() {
name_box->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_port_name_focus_out), varray(name_box, nodes[n_i], i, false));
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
+ remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(this, &VisualShaderEditor::_remove_input_port), varray(nodes[n_i], i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -713,15 +725,15 @@ void VisualShaderEditor::_update_graph() {
Label *label = memnew(Label);
label->set_text(name_left);
- label->add_style_override("normal", label_style); //more compact
+ label->add_theme_style_override("normal", label_style); //more compact
hb->add_child(label);
if (vsnode->get_input_port_default_hint(i) != "" && !port_left_used) {
Label *hint_label = memnew(Label);
hint_label->set_text("[" + vsnode->get_input_port_default_hint(i) + "]");
- hint_label->add_color_override("font_color", get_color("font_color_readonly", "TextEdit"));
- hint_label->add_style_override("normal", label_style);
+ hint_label->add_theme_color_override("font_color", get_theme_color("font_color_readonly", "TextEdit"));
+ hint_label->add_theme_style_override("normal", label_style);
hb->add_child(hint_label);
}
}
@@ -734,7 +746,7 @@ void VisualShaderEditor::_update_graph() {
if (valid_right) {
if (is_group) {
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
+ remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(this, &VisualShaderEditor::_remove_output_port), varray(nodes[n_i], i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -760,7 +772,7 @@ void VisualShaderEditor::_update_graph() {
} else {
Label *label = memnew(Label);
label->set_text(name_right);
- label->add_style_override("normal", label_style); //more compact
+ label->add_theme_style_override("normal", label_style); //more compact
hb->add_child(label);
}
}
@@ -769,8 +781,8 @@ void VisualShaderEditor::_update_graph() {
if (valid_right && edit_type->get_selected() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) {
TextureButton *preview = memnew(TextureButton);
preview->set_toggle_mode(true);
- preview->set_normal_texture(get_icon("GuiVisibilityHidden", "EditorIcons"));
- preview->set_pressed_texture(get_icon("GuiVisibilityVisible", "EditorIcons"));
+ preview->set_normal_texture(get_theme_icon("GuiVisibilityHidden", "EditorIcons"));
+ preview->set_pressed_texture(get_theme_icon("GuiVisibilityVisible", "EditorIcons"));
preview->set_v_size_flags(SIZE_SHRINK_CENTER);
if (vsnode->get_output_port_for_preview() == i) {
@@ -815,7 +827,7 @@ void VisualShaderEditor::_update_graph() {
String error = vsnode->get_warning(visual_shader->get_mode(), type);
if (error != String()) {
Label *error_label = memnew(Label);
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
error_label->set_text(error);
node->add_child(error_label);
}
@@ -833,16 +845,16 @@ void VisualShaderEditor::_update_graph() {
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
expression_box->set_syntax_coloring(true);
- expression_box->add_color_override("background_color", background_color);
+ expression_box->add_theme_color_override("background_color", background_color);
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
expression_box->add_keyword_color(E->get(), keyword_color);
}
- expression_box->add_font_override("font", get_font("expression", "EditorFonts"));
- expression_box->add_color_override("font_color", text_color);
- expression_box->add_color_override("symbol_color", symbol_color);
+ expression_box->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
+ expression_box->add_theme_color_override("font_color", text_color);
+ expression_box->add_theme_color_override("symbol_color", symbol_color);
expression_box->add_color_region("/*", "*/", comment_color, false);
expression_box->add_color_region("//", "", comment_color, false);
@@ -1086,7 +1098,7 @@ void VisualShaderEditor::_expression_focus_out(Object *text_edit, int p_node) {
}
void VisualShaderEditor::_rebuild() {
- if (visual_shader != NULL) {
+ if (visual_shader != nullptr) {
EditorNode::get_singleton()->get_log()->clear();
visual_shader->rebuild();
}
@@ -1110,7 +1122,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
group_node->set_size(size);
- GraphNode *gn = NULL;
+ GraphNode *gn = nullptr;
if (edit_type->get_selected() == p_type) { // check - otherwise the error will be emitted
Node *node2 = graph->get_node(itos(p_node));
gn = Object::cast_to<GraphNode>(node2);
@@ -1125,7 +1137,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
if (!expression_node.is_null()) {
Control *text_box = expression_node->get_control(0);
Size2 box_size = size;
- if (gn != NULL) {
+ if (gn != nullptr) {
if (box_size.x < 150 * EDSCALE || box_size.y < 0) {
box_size.x = gn->get_size().x;
}
@@ -1272,8 +1284,8 @@ void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node,
Button *button = Object::cast_to<Button>(p_button);
ERR_FAIL_COND(!button);
Variant value = vsn->get_input_port_default_value(p_port);
- property_editor->set_global_position(button->get_global_position() + Vector2(0, button->get_size().height));
- property_editor->edit(NULL, "", value.get_type(), value, 0, "");
+ property_editor->set_position(button->get_screen_position() + Vector2(0, button->get_size().height));
+ property_editor->edit(nullptr, "", value.get_type(), value, 0, "");
property_editor->popup();
editing_node = p_node;
editing_port = p_port;
@@ -1303,7 +1315,7 @@ void VisualShaderEditor::_add_texture_node(const String &p_path) {
VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
- ERR_FAIL_INDEX_V(p_idx, add_options.size(), NULL);
+ ERR_FAIL_INDEX_V(p_idx, add_options.size(), nullptr);
Ref<VisualShaderNode> vsnode;
@@ -1311,7 +1323,7 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
if (!is_custom && add_options[p_idx].type != String()) {
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type));
- ERR_FAIL_COND_V(!vsn, NULL);
+ ERR_FAIL_COND_V(!vsn, nullptr);
VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn);
@@ -1409,10 +1421,10 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
vsnode = Ref<VisualShaderNode>(vsn);
} else {
- ERR_FAIL_COND_V(add_options[p_idx].script.is_null(), NULL);
+ ERR_FAIL_COND_V(add_options[p_idx].script.is_null(), nullptr);
String base_type = add_options[p_idx].script->get_instance_base_type();
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(base_type));
- ERR_FAIL_COND_V(!vsn, NULL);
+ ERR_FAIL_COND_V(!vsn, nullptr);
vsnode = Ref<VisualShaderNode>(vsn);
vsnode->set_script(add_options[p_idx].script);
}
@@ -1623,7 +1635,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.empty());
popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.empty());
menu_point = graph->get_local_mouse_position();
- Point2 gpos = Input::get_singleton()->get_mouse_position();
+ Point2 gpos = InputFilter::get_singleton()->get_mouse_position();
popup_menu->set_position(gpos);
popup_menu->popup();
}
@@ -1636,7 +1648,7 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) {
saved_node_pos_dirty = true;
saved_node_pos = graph->get_local_mouse_position();
- Point2 gpos = Input::get_singleton()->get_mouse_position();
+ Point2 gpos = InputFilter::get_singleton()->get_mouse_position();
members_dialog->popup();
members_dialog->set_position(gpos);
} else {
@@ -1646,8 +1658,8 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) {
}
// keep dialog within window bounds
- Size2 window_size = OS::get_singleton()->get_window_size();
- Rect2 dialog_rect = members_dialog->get_global_rect();
+ Size2 window_size = DisplayServer::get_singleton()->window_get_size();
+ Rect2 dialog_rect = Rect2(members_dialog->get_position(), members_dialog->get_size());
if (dialog_rect.position.y + dialog_rect.size.y > window_size.y) {
int difference = dialog_rect.position.y + dialog_rect.size.y - window_size.y;
members_dialog->set_position(members_dialog->get_position() - Point2(0, difference));
@@ -1703,14 +1715,14 @@ void VisualShaderEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- highend_label->set_modulate(get_color("vulkan_color", "Editor"));
+ highend_label->set_modulate(get_theme_color("vulkan_color", "Editor"));
- error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
- node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
+ node_filter->set_right_icon(Control::get_theme_icon("Search", "EditorIcons"));
- preview_shader->set_icon(Control::get_icon("Shader", "EditorIcons"));
+ preview_shader->set_icon(Control::get_theme_icon("Shader", "EditorIcons"));
{
Color background_color = EDITOR_GET("text_editor/highlighting/background_color");
@@ -1719,24 +1731,24 @@ void VisualShaderEditor::_notification(int p_what) {
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
- preview_text->add_color_override("background_color", background_color);
+ preview_text->add_theme_color_override("background_color", background_color);
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
preview_text->add_keyword_color(E->get(), keyword_color);
}
- preview_text->add_font_override("font", get_font("expression", "EditorFonts"));
- preview_text->add_color_override("font_color", text_color);
- preview_text->add_color_override("symbol_color", symbol_color);
+ preview_text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
+ preview_text->add_theme_color_override("font_color", text_color);
+ preview_text->add_theme_color_override("symbol_color", symbol_color);
preview_text->add_color_region("/*", "*/", comment_color, false);
preview_text->add_color_region("//", "", comment_color, false);
- error_text->add_font_override("font", get_font("status_source", "EditorFonts"));
- error_text->add_color_override("font_color", get_color("error_color", "Editor"));
+ error_text->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts"));
+ error_text->add_theme_color_override("font_color", get_theme_color("error_color", "Editor"));
}
- tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons"));
+ tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Tools", "EditorIcons"));
if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())
_update_graph();
@@ -2067,7 +2079,7 @@ void VisualShaderEditor::_member_filter_changed(const String &p_text) {
void VisualShaderEditor::_member_selected() {
TreeItem *item = members->get_selected();
- if (item != NULL && item->has_meta("id")) {
+ if (item != nullptr && item->has_meta("id")) {
members_dialog->get_ok()->set_disabled(false);
highend_label->set_visible(add_options[item->get_meta("id")].highend);
node_desc->set_text(_get_description(item->get_meta("id")));
@@ -2083,7 +2095,7 @@ void VisualShaderEditor::_member_unselected() {
void VisualShaderEditor::_member_create() {
TreeItem *item = members->get_selected();
- if (item != NULL && item->has_meta("id")) {
+ if (item != nullptr && item->has_meta("id")) {
int idx = members->get_selected()->get_meta("id");
_add_node(idx, add_options[idx].sub_func);
members_dialog->hide();
@@ -2262,7 +2274,7 @@ void VisualShaderEditor::_update_preview() {
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_types());
+ 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());
for (int i = 0; i < preview_text->get_line_count(); i++) {
preview_text->set_line_as_marked(i, false);
@@ -2297,7 +2309,7 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
}
-VisualShaderEditor *VisualShaderEditor::singleton = NULL;
+VisualShaderEditor *VisualShaderEditor::singleton = nullptr;
VisualShaderEditor::VisualShaderEditor() {
@@ -2489,13 +2501,10 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog->get_ok()->set_text(TTR("Create"));
members_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
members_dialog->get_ok()->set_disabled(true);
- members_dialog->set_resizable(true);
- members_dialog->set_as_minsize();
- members_dialog->connect("hide", callable_mp(this, &VisualShaderEditor::_member_cancel));
+ members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel));
add_child(members_dialog);
alert = memnew(AcceptDialog);
- alert->set_as_minsize();
alert->get_label()->set_autowrap(true);
alert->get_label()->set_align(Label::ALIGN_CENTER);
alert->get_label()->set_valign(Label::VALIGN_CENTER);
@@ -2669,6 +2678,38 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Transform", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("Velocity", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
+ // 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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_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, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
+
// SCALAR
add_options.push_back(AddOption("FloatFunc", "Scalar", "Common", "VisualShaderNodeFloatFunc", TTR("Float function."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
@@ -2950,12 +2991,12 @@ public:
void setup(const Ref<VisualShaderNodeInput> &p_input) {
input = p_input;
Ref<Texture2D> type_icon[6] = {
- EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"),
- EditorNode::get_singleton()->get_gui_base()->get_icon("int", "EditorIcons"),
- EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"),
- EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"),
- EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"),
- EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"),
};
add_item("[None]");
@@ -3099,7 +3140,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
Vector<StringName> properties = p_node->get_editable_properties();
if (properties.size() == 0) {
- return NULL;
+ return nullptr;
}
List<PropertyInfo> props;
@@ -3117,7 +3158,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
}
if (pinfo.size() == 0)
- return NULL;
+ return nullptr;
properties.clear();
@@ -3128,7 +3169,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
EditorProperty *prop = EditorInspector::instantiate_property_editor(node.ptr(), pinfo[i].type, pinfo[i].name, pinfo[i].hint, pinfo[i].hint_string, pinfo[i].usage);
if (!prop)
- return NULL;
+ return nullptr;
if (Object::cast_to<EditorPropertyResource>(prop)) {
Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 8756fe9fe9..473c1bb070 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -228,7 +228,7 @@ class VisualShaderEditor : public VBoxContainer {
void _copy_nodes();
void _paste_nodes(bool p_use_custom_position = false, const Vector2 &p_custom_position = Vector2());
- Vector<Ref<VisualShaderNodePlugin> > plugins;
+ Vector<Ref<VisualShaderNodePlugin>> plugins;
void _mode_selected(int p_id);
void _rebuild();
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index cdc5255edd..86df069b8b 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -34,6 +34,7 @@
#include "core/os/os.h"
#include "editor_scale.h"
#include "main/main.h"
+#include "servers/display_server.h"
void BackgroundProgress::_add_task(const String &p_task, const String &p_label, int p_steps) {
@@ -134,19 +135,9 @@ void BackgroundProgress::end_task(const String &p_task) {
////////////////////////////////////////////////
-ProgressDialog *ProgressDialog::singleton = NULL;
+ProgressDialog *ProgressDialog::singleton = nullptr;
void ProgressDialog::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_DRAW: {
-
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
- draw_style_box(style, Rect2(Point2(), get_size()));
-
- } break;
- }
}
void ProgressDialog::_popup() {
@@ -154,14 +145,14 @@ void ProgressDialog::_popup() {
Size2 ms = main->get_combined_minimum_size();
ms.width = MAX(500 * EDSCALE, ms.width);
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
+ Ref<StyleBox> style = main->get_theme_stylebox("panel", "PopupMenu");
ms += style->get_minimum_size();
main->set_margin(MARGIN_LEFT, style->get_margin(MARGIN_LEFT));
main->set_margin(MARGIN_RIGHT, -style->get_margin(MARGIN_RIGHT));
main->set_margin(MARGIN_TOP, style->get_margin(MARGIN_TOP));
main->set_margin(MARGIN_BOTTOM, -style->get_margin(MARGIN_BOTTOM));
- raise();
+ //raise();
popup_centered(ms);
}
@@ -219,7 +210,7 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int
t.state->set_text(p_state);
last_progress_tick = OS::get_singleton()->get_ticks_usec();
if (cancel_hb->is_visible()) {
- OS::get_singleton()->force_process_input();
+ DisplayServer::get_singleton()->process_events();
}
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h
index e01c7d802b..82f479ae9d 100644
--- a/editor/progress_dialog.h
+++ b/editor/progress_dialog.h
@@ -68,9 +68,9 @@ public:
BackgroundProgress() {}
};
-class ProgressDialog : public Popup {
+class ProgressDialog : public PopupPanel {
- GDCLASS(ProgressDialog, Popup);
+ GDCLASS(ProgressDialog, PopupPanel);
struct Task {
String task;
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 37b959c78a..04ec5ae043 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -46,25 +46,28 @@
#include "scene/gui/margin_container.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/tab_container.h"
-
+#include "servers/display_server.h"
+
+void ProjectExportDialog::_theme_changed() {
+ duplicate_preset->set_icon(presets->get_theme_icon("Duplicate", "EditorIcons"));
+ delete_preset->set_icon(presets->get_theme_icon("Remove", "EditorIcons"));
+ Control *panel = custom_feature_display->get_parent_control();
+ if (panel)
+ panel->add_theme_style_override("panel", patches->get_theme_stylebox("bg", "Tree"));
+}
void ProjectExportDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible()) {
+ EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "export", Rect2(get_position(), get_size()));
+ }
+ } break;
case NOTIFICATION_READY: {
- duplicate_preset->set_icon(get_icon("Duplicate", "EditorIcons"));
- delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
+ duplicate_preset->set_icon(presets->get_theme_icon("Duplicate", "EditorIcons"));
+ delete_preset->set_icon(presets->get_theme_icon("Remove", "EditorIcons"));
connect("confirmed", callable_mp(this, &ProjectExportDialog::_export_pck_zip));
- custom_feature_display->get_parent_control()->add_style_override("panel", get_stylebox("bg", "Tree"));
- } break;
- case NOTIFICATION_POPUP_HIDE: {
- EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "export", get_rect());
- } break;
- case NOTIFICATION_THEME_CHANGED: {
- duplicate_preset->set_icon(get_icon("Duplicate", "EditorIcons"));
- delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
- Control *panel = custom_feature_display->get_parent_control();
- if (panel)
- panel->add_style_override("panel", get_stylebox("bg", "Tree"));
+ custom_feature_display->get_parent_control()->add_theme_style_override("panel", patches->get_theme_stylebox("bg", "Tree"));
} break;
}
}
@@ -193,7 +196,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
name->set_editable(false);
export_path->hide();
runnable->set_disabled(true);
- parameters->edit(NULL);
+ parameters->edit(nullptr);
presets->unselect_all();
duplicate_preset->set_disabled(true);
delete_preset->set_disabled(true);
@@ -247,8 +250,8 @@ void ProjectExportDialog::_edit_preset(int p_index) {
patch->set_checked(0, true);
patch->set_tooltip(0, patchlist[i]);
patch->set_metadata(0, i);
- patch->add_button(0, get_icon("Remove", "EditorIcons"), 0);
- patch->add_button(0, get_icon("folder", "FileDialog"), 1);
+ patch->add_button(0, presets->get_theme_icon("Remove", "EditorIcons"), 0);
+ patch->add_button(0, presets->get_theme_icon("folder", "FileDialog"), 1);
}
TreeItem *patch_add = patches->create_item(patch_root);
@@ -258,7 +261,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
else
patch_add->set_text(0, TTR("Add previous patches..."));
- patch_add->add_button(0, get_icon("folder", "FileDialog"), 1);
+ patch_add->add_button(0, presets->get_theme_icon("folder", "FileDialog"), 1);
_fill_resource_tree();
@@ -299,7 +302,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
custom_features->set_text(current->get_custom_features());
_update_feature_list();
_update_export_all();
- minimum_size_changed();
+ child_controls_changed();
int script_export_mode = current->get_script_export_mode();
script_mode->select(script_export_mode);
@@ -388,7 +391,7 @@ void ProjectExportDialog::_patch_button_pressed(Object *p_item, int p_column, in
Vector<String> patches = current->get_patches();
ERR_FAIL_INDEX(patch_index, patches.size());
patch_erase->set_text(vformat(TTR("Delete patch '%s' from list?"), patches[patch_index].get_file()));
- patch_erase->popup_centered_minsize();
+ patch_erase->popup_centered();
} else {
patch_dialog->popup_centered_ratio();
}
@@ -618,7 +621,7 @@ void ProjectExportDialog::_delete_preset() {
return;
delete_confirm->set_text(vformat(TTR("Delete preset '%s'?"), current->get_name()));
- delete_confirm->popup_centered_minsize();
+ delete_confirm->popup_centered();
}
void ProjectExportDialog::_delete_preset_confirm() {
@@ -649,7 +652,7 @@ Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_
label->set_text(presets->get_item_text(pos));
drag->add_child(label);
- set_drag_preview(drag);
+ presets->set_drag_preview(drag);
return d;
}
@@ -666,7 +669,7 @@ Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_
Label *label = memnew(Label);
label->set_text(item->get_text(0));
- set_drag_preview(label);
+ patches->set_drag_preview(label);
return d;
}
@@ -816,7 +819,7 @@ void ProjectExportDialog::_fill_resource_tree() {
bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref<EditorExportPreset> &current, bool p_only_scenes) {
- p_item->set_icon(0, get_icon("folder", "FileDialog"));
+ p_item->set_icon(0, presets->get_theme_icon("folder", "FileDialog"));
p_item->set_text(0, p_dir->get_name() + "/");
bool used = false;
@@ -954,7 +957,7 @@ void ProjectExportDialog::_export_project() {
export_project->get_line_edit()->connect_compat("text_entered", export_project, "_file_entered");
}
- export_project->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
export_project->popup_centered_ratio();
}
@@ -979,14 +982,14 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
ERR_PRINT(vformat("Failed to export the project for platform '%s'.", platform->get_name()));
error_dialog->show();
- error_dialog->popup_centered_minsize(Size2(300, 80));
+ error_dialog->popup_centered(Size2(300, 80));
}
}
void ProjectExportDialog::_export_all_dialog() {
export_all_dialog->show();
- export_all_dialog->popup_centered_minsize(Size2(300, 80));
+ export_all_dialog->popup_centered(Size2(300, 80));
}
void ProjectExportDialog::_export_all_dialog_action(const String &p_str) {
@@ -1017,7 +1020,7 @@ void ProjectExportDialog::_export_all(bool p_debug) {
error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name());
}
error_dialog->show();
- error_dialog->popup_centered_minsize(Size2(300, 80));
+ error_dialog->popup_centered(Size2(300, 80));
ERR_PRINT("Failed to export project");
}
}
@@ -1039,13 +1042,13 @@ void ProjectExportDialog::_bind_methods() {
ProjectExportDialog::ProjectExportDialog() {
set_title(TTR("Export"));
- set_resizable(true);
VBoxContainer *main_vb = memnew(VBoxContainer);
+ main_vb->connect("theme_changed", callable_mp(this, &ProjectExportDialog::_theme_changed));
add_child(main_vb);
HSplitContainer *hbox = memnew(HSplitContainer);
main_vb->add_child(hbox);
- hbox->set_v_size_flags(SIZE_EXPAND_FILL);
+ hbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
// Presets list.
@@ -1064,9 +1067,12 @@ ProjectExportDialog::ProjectExportDialog() {
preset_hb->add_child(add_preset);
MarginContainer *mc = memnew(MarginContainer);
preset_vb->add_child(mc);
- mc->set_v_size_flags(SIZE_EXPAND_FILL);
+ mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
presets = memnew(ItemList);
- presets->set_drag_forwarding(this);
+#ifndef _MSC_VER
+#warning must reimplement drag forward
+#endif
+ //presets->set_drag_forwarding(this);
mc->add_child(presets);
presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
duplicate_preset = memnew(ToolButton);
@@ -1104,14 +1110,14 @@ ProjectExportDialog::ProjectExportDialog() {
sections->set_tab_align(TabContainer::ALIGN_LEFT);
sections->set_use_hidden_tabs_for_min_size(true);
settings_vb->add_child(sections);
- sections->set_v_size_flags(SIZE_EXPAND_FILL);
+ sections->set_v_size_flags(Control::SIZE_EXPAND_FILL);
// Main preset parameters.
parameters = memnew(EditorInspector);
sections->add_child(parameters);
parameters->set_name(TTR("Options"));
- parameters->set_v_size_flags(SIZE_EXPAND_FILL);
+ parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL);
parameters->connect("property_edited", callable_mp(this, &ProjectExportDialog::_update_parameters));
// Resources export parameters.
@@ -1131,7 +1137,7 @@ ProjectExportDialog::ProjectExportDialog() {
include_label->set_text(TTR("Resources to export:"));
resources_vb->add_child(include_label);
include_margin = memnew(MarginContainer);
- include_margin->set_v_size_flags(SIZE_EXPAND_FILL);
+ include_margin->set_v_size_flags(Control::SIZE_EXPAND_FILL);
resources_vb->add_child(include_margin);
include_files = memnew(Tree);
@@ -1163,11 +1169,14 @@ ProjectExportDialog::ProjectExportDialog() {
patches = memnew(Tree);
patch_vb->add_child(patches);
- patches->set_v_size_flags(SIZE_EXPAND_FILL);
+ patches->set_v_size_flags(Control::SIZE_EXPAND_FILL);
patches->set_hide_root(true);
patches->connect("button_pressed", callable_mp(this, &ProjectExportDialog::_patch_button_pressed));
patches->connect("item_edited", callable_mp(this, &ProjectExportDialog::_patch_edited));
- patches->set_drag_forwarding(this);
+#ifndef _MSC_VER
+#warning must reimplement drag forward
+#endif
+ //patches->set_drag_forwarding(this);
patches->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
HBoxContainer *patches_hb = memnew(HBoxContainer);
@@ -1180,7 +1189,7 @@ ProjectExportDialog::ProjectExportDialog() {
patch_dialog = memnew(EditorFileDialog);
patch_dialog->add_filter("*.pck ; " + TTR("Pack File"));
- patch_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ patch_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
patch_dialog->connect("file_selected", callable_mp(this, &ProjectExportDialog::_patch_selected));
add_child(patch_dialog);
@@ -1196,12 +1205,9 @@ ProjectExportDialog::ProjectExportDialog() {
custom_features = memnew(LineEdit);
custom_features->connect("text_changed", callable_mp(this, &ProjectExportDialog::_custom_features_changed));
feature_vb->add_margin_child(TTR("Custom (comma-separated):"), custom_features);
- Panel *features_panel = memnew(Panel);
custom_feature_display = memnew(RichTextLabel);
- features_panel->add_child(custom_feature_display);
- custom_feature_display->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 10 * EDSCALE);
- custom_feature_display->set_v_size_flags(SIZE_EXPAND_FILL);
- feature_vb->add_margin_child(TTR("Feature List:"), features_panel, true);
+ custom_feature_display->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ feature_vb->add_margin_child(TTR("Feature List:"), custom_feature_display, true);
sections->add_child(feature_vb);
// Script export parameters.
@@ -1220,7 +1226,7 @@ ProjectExportDialog::ProjectExportDialog() {
script_key->connect("text_changed", callable_mp(this, &ProjectExportDialog::_script_encryption_key_changed));
script_key_error = memnew(Label);
script_key_error->set_text("- " + TTR("Invalid Encryption Key (must be 64 characters long)"));
- script_key_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ script_key_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
script_vb->add_margin_child(TTR("Script Encryption Key (256-bits as hex):"), script_key);
script_vb->add_child(script_key_error);
sections->add_child(script_vb);
@@ -1235,7 +1241,7 @@ ProjectExportDialog::ProjectExportDialog() {
delete_preset->set_disabled(true);
script_key_error->hide();
sections->hide();
- parameters->edit(NULL);
+ parameters->edit(nullptr);
// Deletion dialog.
@@ -1250,7 +1256,7 @@ ProjectExportDialog::ProjectExportDialog() {
get_cancel()->set_text(TTR("Close"));
get_ok()->set_text(TTR("Export PCK/Zip"));
- export_button = add_button(TTR("Export Project"), !OS::get_singleton()->get_swap_ok_cancel(), "export");
+ export_button = add_button(TTR("Export Project"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "export");
export_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_project));
// Disable initially before we select a valid preset
export_button->set_disabled(true);
@@ -1265,7 +1271,7 @@ ProjectExportDialog::ProjectExportDialog() {
export_all_dialog->add_button(TTR("Release"), true, "release");
export_all_dialog->connect("custom_action", callable_mp(this, &ProjectExportDialog::_export_all_dialog_action));
- export_all_button = add_button(TTR("Export All"), !OS::get_singleton()->get_swap_ok_cancel(), "export");
+ export_all_button = add_button(TTR("Export All"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "export");
export_all_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_all_dialog));
export_all_button->set_disabled(true);
@@ -1273,14 +1279,14 @@ ProjectExportDialog::ProjectExportDialog() {
export_pck_zip->add_filter("*.zip ; " + TTR("ZIP File"));
export_pck_zip->add_filter("*.pck ; " + TTR("Godot Game Pack"));
export_pck_zip->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- export_pck_zip->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ export_pck_zip->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
add_child(export_pck_zip);
export_pck_zip->connect("file_selected", callable_mp(this, &ProjectExportDialog::_export_pck_zip_selected));
export_error = memnew(Label);
main_vb->add_child(export_error);
export_error->hide();
- export_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ export_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
export_templates_error = memnew(HBoxContainer);
main_vb->add_child(export_templates_error);
@@ -1288,7 +1294,7 @@ ProjectExportDialog::ProjectExportDialog() {
Label *export_error2 = memnew(Label);
export_templates_error->add_child(export_error2);
- export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ export_error2->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
error_dialog = memnew(AcceptDialog);
@@ -1299,7 +1305,7 @@ ProjectExportDialog::ProjectExportDialog() {
LinkButton *download_templates = memnew(LinkButton);
download_templates->set_text(TTR("Manage Export Templates"));
- download_templates->set_v_size_flags(SIZE_SHRINK_CENTER);
+ download_templates->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
export_templates_error->add_child(download_templates);
download_templates->connect("pressed", callable_mp(this, &ProjectExportDialog::_open_export_template_manager));
diff --git a/editor/project_export.h b/editor/project_export.h
index 00e6dfd6e3..2e311eb3b3 100644
--- a/editor/project_export.h
+++ b/editor/project_export.h
@@ -167,6 +167,7 @@ private:
void _tab_changed(int);
protected:
+ void _theme_changed();
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 94f9bf2767..0ca540a33f 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -51,6 +51,8 @@
#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h"
+#include "scene/main/window.h"
+#include "servers/display_server.h"
static inline String get_project_key_from_path(const String &dir) {
return dir.replace("/", "::");
@@ -115,22 +117,22 @@ private:
case MESSAGE_ERROR: {
- msg->add_color_override("font_color", get_color("error_color", "Editor"));
+ msg->add_theme_color_override("font_color", msg->get_theme_color("error_color", "Editor"));
msg->set_modulate(Color(1, 1, 1, 1));
- new_icon = get_icon("StatusError", "EditorIcons");
+ new_icon = msg->get_theme_icon("StatusError", "EditorIcons");
} break;
case MESSAGE_WARNING: {
- msg->add_color_override("font_color", get_color("warning_color", "Editor"));
+ msg->add_theme_color_override("font_color", msg->get_theme_color("warning_color", "Editor"));
msg->set_modulate(Color(1, 1, 1, 1));
- new_icon = get_icon("StatusWarning", "EditorIcons");
+ new_icon = msg->get_theme_icon("StatusWarning", "EditorIcons");
} break;
case MESSAGE_SUCCESS: {
msg->set_modulate(Color(1, 1, 1, 0));
- new_icon = get_icon("StatusSuccess", "EditorIcons");
+ new_icon = msg->get_theme_icon("StatusSuccess", "EditorIcons");
} break;
}
@@ -141,7 +143,7 @@ private:
install_status_rect->set_texture(new_icon);
}
- set_size(Size2(500, 0) * EDSCALE);
+ set_size(Size2i(500, 0) * EDSCALE);
}
String _test_path() {
@@ -189,7 +191,7 @@ private:
if (valid_path != "" && !d->file_exists("project.godot")) {
if (valid_path.ends_with(".zip")) {
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(valid_path.utf8().get_data(), &io);
@@ -206,7 +208,7 @@ private:
while (ret == UNZ_OK) {
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
if (String(fname).ends_with("project.godot")) {
break;
@@ -377,19 +379,19 @@ private:
if (mode == MODE_IMPORT) {
- fdialog->set_mode(FileDialog::MODE_OPEN_FILE);
+ fdialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
fdialog->clear_filters();
fdialog->add_filter(vformat("project.godot ; %s %s", VERSION_NAME, TTR("Project")));
fdialog->add_filter("*.zip ; " + TTR("ZIP File"));
} else {
- fdialog->set_mode(FileDialog::MODE_OPEN_DIR);
+ fdialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
}
fdialog->popup_centered_ratio();
}
void _browse_install_path() {
fdialog_install->set_current_dir(install_path->get_text());
- fdialog_install->set_mode(FileDialog::MODE_OPEN_DIR);
+ fdialog_install->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
fdialog_install->popup_centered_ratio();
}
@@ -416,12 +418,12 @@ private:
} else {
dialog_error->set_text(TTR("Couldn't create folder."));
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
}
} else {
dialog_error->set_text(TTR("There is already a folder in this path with the specified name."));
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
}
}
@@ -498,14 +500,14 @@ private:
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"), get_icon("DefaultProjectIcon", "EditorIcons"));
+ ResourceSaver::save(dir.plus_file("icon.png"), msg->get_theme_icon("DefaultProjectIcon", "EditorIcons"));
FileAccess *f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
if (!f) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=2]");
- f->store_line("[sub_resource type=\"ProceduralSky\" id=1]");
+ f->store_line("[sub_resource type=\"Sky\" id=1]");
f->store_line("[resource]");
f->store_line("background_mode = 2");
f->store_line("background_sky = SubResource( 1 )");
@@ -520,14 +522,14 @@ private:
zip_path = project_path->get_text();
}
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(zip_path.utf8().get_data(), &io);
if (!pkg) {
dialog_error->set_text(TTR("Error opening package file, not in ZIP format."));
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
return;
}
@@ -541,7 +543,7 @@ private:
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String path = fname;
@@ -605,11 +607,11 @@ private:
}
dialog_error->set_text(msg);
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
} else if (!project_path->get_text().ends_with(".zip")) {
dialog_error->set_text(TTR("Package installed successfully!"));
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
}
}
}
@@ -647,16 +649,16 @@ private:
project_name->clear();
_text_changed("");
- if (status_rect->get_texture() == get_icon("StatusError", "EditorIcons"))
+ if (status_rect->get_texture() == msg->get_theme_icon("StatusError", "EditorIcons"))
msg->show();
- if (install_status_rect->get_texture() == get_icon("StatusError", "EditorIcons"))
+ if (install_status_rect->get_texture() == msg->get_theme_icon("StatusError", "EditorIcons"))
msg->show();
}
void _notification(int p_what) {
- if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST)
+ if (p_what == NOTIFICATION_WM_CLOSE_REQUEST)
_remove_created_folder();
}
@@ -786,7 +788,7 @@ public:
_test_path();
}
- popup_centered_minsize(Size2(500, 0) * EDSCALE);
+ popup_centered(Size2i(500, 0) * EDSCALE);
}
ProjectDialog() {
@@ -805,7 +807,7 @@ public:
name_container->add_child(pnhb);
project_name = memnew(LineEdit);
- project_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ project_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
pnhb->add_child(project_name);
create_dir = memnew(Button);
@@ -824,7 +826,7 @@ public:
path_container->add_child(pphb);
project_path = memnew(LineEdit);
- project_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ project_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
pphb->add_child(project_path);
install_path_container = memnew(VBoxContainer);
@@ -838,7 +840,7 @@ public:
install_path_container->add_child(iphb);
install_path = memnew(LineEdit);
- install_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ install_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
iphb->add_child(install_path);
// status icon
@@ -876,7 +878,7 @@ public:
rasterizer_button_group.instance();
Container *rvb = memnew(VBoxContainer);
- rvb->set_h_size_flags(SIZE_EXPAND_FILL);
+ rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
rshb->add_child(rvb);
Button *rs_button = memnew(CheckBox);
rs_button->set_button_group(rasterizer_button_group);
@@ -895,7 +897,7 @@ public:
TTR("The GLES2 renderer is currently unavailable, as it needs to be reworked for Godot 4.0.\nUse Godot 3.2 if you need GLES2 support.");
rvb = memnew(VBoxContainer);
- rvb->set_h_size_flags(SIZE_EXPAND_FILL);
+ rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
rshb->add_child(rvb);
rs_button = memnew(CheckBox);
rs_button->set_button_group(rasterizer_button_group);
@@ -910,7 +912,7 @@ public:
// Also set the tooltip on the label so it appears when hovering either the checkbox or label.
l->set_tooltip(gles2_unsupported_tooltip);
// Required for the tooltip to show.
- l->set_mouse_filter(MOUSE_FILTER_STOP);
+ l->set_mouse_filter(Control::MOUSE_FILTER_STOP);
rvb->add_child(l);
l = memnew(Label);
@@ -953,8 +955,8 @@ public:
bool hover;
ProjectListItemControl() {
- favorite_button = NULL;
- icon = NULL;
+ favorite_button = nullptr;
+ icon = nullptr;
icon_needs_reload = true;
hover = false;
}
@@ -975,7 +977,7 @@ public:
} break;
case NOTIFICATION_DRAW: {
if (hover) {
- draw_style_box(get_stylebox("hover", "Tree"), Rect2(Point2(), get_size() - Size2(10, 0) * EDSCALE));
+ draw_style_box(get_theme_stylebox("hover", "Tree"), Rect2(Point2(), get_size() - Size2(10, 0) * EDSCALE));
}
} break;
}
@@ -1034,7 +1036,7 @@ public:
grayed = p_grayed;
missing = p_missing;
version = p_version;
- control = NULL;
+ control = nullptr;
}
_FORCE_INLINE_ bool operator==(const Item &l) const {
@@ -1045,6 +1047,9 @@ public:
ProjectList();
~ProjectList();
+ void _global_menu_new_window(const Variant &p_tag);
+ void _global_menu_open_project(const Variant &p_tag);
+
void update_dock_menu();
void load_projects();
void set_search_term(String p_search_term);
@@ -1116,7 +1121,7 @@ ProjectList::ProjectList() {
_order_option = ProjectListFilter::FILTER_EDIT_DATE;
_scroll_children = memnew(VBoxContainer);
- _scroll_children->set_h_size_flags(SIZE_EXPAND_FILL);
+ _scroll_children->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_child(_scroll_children);
_icon_load_index = 0;
@@ -1150,7 +1155,7 @@ void ProjectList::_notification(int p_what) {
void ProjectList::load_project_icon(int p_index) {
Item &item = _projects.write[p_index];
- Ref<Texture2D> default_icon = get_icon("DefaultProjectIcon", "EditorIcons");
+ Ref<Texture2D> default_icon = get_theme_icon("DefaultProjectIcon", "EditorIcons");
Ref<Texture2D> icon;
if (item.icon != "") {
Ref<Image> img;
@@ -1231,7 +1236,7 @@ void ProjectList::load_projects() {
// Clear whole list
for (int i = 0; i < _projects.size(); ++i) {
Item &project = _projects.write[i];
- CRASH_COND(project.control == NULL);
+ CRASH_COND(project.control == nullptr);
memdelete(project.control); // Why not queue_free()?
}
_projects.clear();
@@ -1284,7 +1289,11 @@ void ProjectList::load_projects() {
}
void ProjectList::update_dock_menu() {
- OS::get_singleton()->global_menu_clear("_dock");
+
+ if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
+ return;
+ }
+ DisplayServer::get_singleton()->global_menu_clear("_dock");
int favs_added = 0;
int total_added = 0;
@@ -1294,18 +1303,41 @@ void ProjectList::update_dock_menu() {
favs_added++;
} else {
if (favs_added != 0) {
- OS::get_singleton()->global_menu_add_separator("_dock");
+ DisplayServer::get_singleton()->global_menu_add_separator("_dock");
}
favs_added = 0;
}
- OS::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", GLOBAL_OPEN_PROJECT, Variant(_projects[i].path.plus_file("project.godot")));
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), i);
total_added++;
}
}
if (total_added != 0) {
- OS::get_singleton()->global_menu_add_separator("_dock");
+ DisplayServer::get_singleton()->global_menu_add_separator("_dock");
+ }
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", TTR("New Window"), callable_mp(this, &ProjectList::_global_menu_new_window));
+}
+
+void ProjectList::_global_menu_new_window(const Variant &p_tag) {
+ List<String> args;
+ args.push_back("-p");
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+}
+
+void ProjectList::_global_menu_open_project(const Variant &p_tag) {
+ int idx = (int)p_tag;
+
+ if (idx >= 0 && idx < _projects.size()) {
+ String conf = _projects[idx].path.plus_file("project.godot");
+ List<String> args;
+ args.push_back(conf);
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
}
- OS::get_singleton()->global_menu_add_item("_dock", TTR("New Window"), GLOBAL_NEW_WINDOW, Variant());
}
void ProjectList::create_project_item_control(int p_index) {
@@ -1314,15 +1346,15 @@ void ProjectList::create_project_item_control(int p_index) {
ERR_FAIL_COND(p_index != _scroll_children->get_child_count());
Item &item = _projects.write[p_index];
- ERR_FAIL_COND(item.control != NULL); // Already created
+ ERR_FAIL_COND(item.control != nullptr); // Already created
- Ref<Texture2D> favorite_icon = get_icon("Favorites", "EditorIcons");
- Color font_color = get_color("font_color", "Tree");
+ Ref<Texture2D> favorite_icon = get_theme_icon("Favorites", "EditorIcons");
+ Color font_color = get_theme_color("font_color", "Tree");
ProjectListItemControl *hb = memnew(ProjectListItemControl);
hb->connect("draw", callable_mp(this, &ProjectList::_panel_draw), varray(hb));
hb->connect("gui_input", callable_mp(this, &ProjectList::_panel_input), varray(hb));
- hb->add_constant_override("separation", 10 * EDSCALE);
+ hb->add_theme_constant_override("separation", 10 * EDSCALE);
hb->set_tooltip(item.description);
VBoxContainer *favorite_box = memnew(VBoxContainer);
@@ -1342,7 +1374,7 @@ void ProjectList::create_project_item_control(int p_index) {
TextureRect *tf = memnew(TextureRect);
// The project icon may not be loaded by the time the control is displayed,
// so use a loading placeholder.
- tf->set_texture(get_icon("ProjectIconLoading", "EditorIcons"));
+ tf->set_texture(get_theme_icon("ProjectIconLoading", "EditorIcons"));
tf->set_v_size_flags(SIZE_SHRINK_CENTER);
if (item.missing) {
tf->set_modulate(Color(1, 1, 1, 0.5));
@@ -1353,25 +1385,25 @@ void ProjectList::create_project_item_control(int p_index) {
VBoxContainer *vb = memnew(VBoxContainer);
if (item.grayed)
vb->set_modulate(Color(1, 1, 1, 0.5));
- vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(vb);
Control *ec = memnew(Control);
ec->set_custom_minimum_size(Size2(0, 1));
ec->set_mouse_filter(MOUSE_FILTER_PASS);
vb->add_child(ec);
Label *title = memnew(Label(!item.missing ? item.project_name : TTR("Missing Project")));
- title->add_font_override("font", get_font("title", "EditorFonts"));
- title->add_color_override("font_color", font_color);
+ title->add_theme_font_override("font", get_theme_font("title", "EditorFonts"));
+ title->add_theme_color_override("font_color", font_color);
title->set_clip_text(true);
vb->add_child(title);
HBoxContainer *path_hb = memnew(HBoxContainer);
- path_hb->set_h_size_flags(SIZE_EXPAND_FILL);
+ path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
vb->add_child(path_hb);
Button *show = memnew(Button);
// Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't
- show->set_icon(get_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons"));
+ show->set_icon(get_theme_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons"));
show->set_flat(true);
if (!item.grayed) {
// Don't make the icon less prominent if the parent is already grayed out
@@ -1388,9 +1420,9 @@ void ProjectList::create_project_item_control(int p_index) {
Label *fpath = memnew(Label(item.path));
path_hb->add_child(fpath);
- fpath->set_h_size_flags(SIZE_EXPAND_FILL);
+ fpath->set_h_size_flags(Control::SIZE_EXPAND_FILL);
fpath->set_modulate(Color(1, 1, 1, 0.5));
- fpath->add_color_override("font_color", font_color);
+ fpath->add_theme_color_override("font_color", font_color);
fpath->set_clip_text(true);
_scroll_children->add_child(hb);
@@ -1722,12 +1754,12 @@ void ProjectList::erase_selected_projects() {
void ProjectList::_panel_draw(Node *p_hb) {
Control *hb = Object::cast_to<Control>(p_hb);
- hb->draw_line(Point2(0, hb->get_size().y + 1), Point2(hb->get_size().x - 10, hb->get_size().y + 1), get_color("guide_color", "Tree"));
+ hb->draw_line(Point2(0, hb->get_size().y + 1), Point2(hb->get_size().x - 10, hb->get_size().y + 1), get_theme_color("guide_color", "Tree"));
String key = _projects[p_hb->get_index()].project_key;
if (_selected_project_keys.has(key)) {
- hb->draw_style_box(get_stylebox("selected", "Tree"), Rect2(Point2(), hb->get_size() - Size2(10, 0) * EDSCALE));
+ hb->draw_style_box(get_theme_stylebox("selected", "Tree"), Rect2(Point2(), hb->get_size() - Size2(10, 0) * EDSCALE));
}
}
@@ -1827,13 +1859,13 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
if (open_templates->is_visible()) {
- open_templates->popup_centered_minsize();
+ open_templates->popup_centered();
}
} break;
case NOTIFICATION_READY: {
if (_project_list->get_project_count() == 0 && StreamPeerSSL::is_available())
- open_templates->popup_centered_minsize();
+ open_templates->popup_centered();
if (_project_list->get_project_count() >= 1) {
// Focus on the search box immediately to allow the user
@@ -1845,7 +1877,7 @@ void ProjectManager::_notification(int p_what) {
set_process_unhandled_input(is_visible_in_tree());
} break;
- case NOTIFICATION_WM_QUIT_REQUEST: {
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
_dim_window();
} break;
@@ -2018,30 +2050,6 @@ void ProjectManager::_confirm_update_settings() {
_open_selected_projects();
}
-void ProjectManager::_global_menu_action(const Variant &p_id, const Variant &p_meta) {
-
- int id = (int)p_id;
- if (id == ProjectList::GLOBAL_NEW_WINDOW) {
- List<String> args;
- args.push_back("-p");
- String exec = OS::get_singleton()->get_executable_path();
-
- OS::ProcessID pid = 0;
- OS::get_singleton()->execute(exec, args, false, &pid);
- } else if (id == ProjectList::GLOBAL_OPEN_PROJECT) {
- String conf = (String)p_meta;
-
- if (conf != String()) {
- List<String> args;
- args.push_back(conf);
- String exec = OS::get_singleton()->get_executable_path();
-
- OS::ProcessID pid = 0;
- OS::get_singleton()->execute(exec, args, false, &pid);
- }
- }
-}
-
void ProjectManager::_open_selected_projects() {
const Set<String> &selected_list = _project_list->get_selected_project_keys();
@@ -2053,7 +2061,7 @@ void ProjectManager::_open_selected_projects() {
if (!FileAccess::exists(conf)) {
dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path));
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
return;
}
@@ -2091,7 +2099,7 @@ void ProjectManager::_open_selected_projects_ask() {
if (selected_list.size() > 1) {
multi_open_ask->set_text(TTR("Are you sure to open more than one project?"));
- multi_open_ask->popup_centered_minsize();
+ multi_open_ask->popup_centered();
return;
}
@@ -2107,19 +2115,19 @@ void ProjectManager::_open_selected_projects_ask() {
// Check if the config_version property was empty or 0
if (config_version == 0) {
ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->popup_centered_minsize();
+ ask_update_settings->popup_centered();
return;
}
// Check if we need to convert project settings from an earlier engine version
if (config_version < ProjectSettings::CONFIG_VERSION) {
ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it?\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->popup_centered_minsize();
+ ask_update_settings->popup_centered();
return;
}
// Check if the file was generated by a newer, incompatible engine version
if (config_version > ProjectSettings::CONFIG_VERSION) {
dialog_error->set_text(vformat(TTR("Can't open project at '%s'.") + "\n" + TTR("The project settings were created by a newer engine version, whose settings are not compatible with this version."), project.path));
- dialog_error->popup_centered_minsize();
+ dialog_error->popup_centered();
return;
}
@@ -2179,7 +2187,7 @@ void ProjectManager::_run_project() {
if (selected_list.size() > 1) {
multi_run_ask->set_text(vformat(TTR("Are you sure to run %d projects at once?"), selected_list.size()));
- multi_run_ask->popup_centered_minsize();
+ multi_run_ask->popup_centered();
} else {
_run_project_confirm();
}
@@ -2276,13 +2284,13 @@ void ProjectManager::_erase_project() {
}
erase_ask->set_text(confirm_message);
- erase_ask->popup_centered_minsize();
+ erase_ask->popup_centered();
}
void ProjectManager::_erase_missing_projects() {
erase_missing_ask->set_text(TTR("Remove all missing projects from the list?\nThe project folders' contents won't be modified."));
- erase_missing_ask->popup_centered_minsize();
+ erase_missing_ask->popup_centered();
}
void ProjectManager::_language_selected(int p_id) {
@@ -2290,7 +2298,7 @@ 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);
language_btn->set_text(lang);
- language_btn->set_icon(get_icon("Environment", "EditorIcons"));
+ language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
language_restart_ask->set_text(TTR("Language changed.\nThe interface will update after restarting the editor or project manager."));
language_restart_ask->popup_centered();
@@ -2357,7 +2365,7 @@ void ProjectManager::_files_dropped(PackedStringArray p_files, int p_screen) {
multi_scan_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders), varray(folders));
multi_scan_ask->set_text(
vformat(TTR("Are you sure to scan %s folders for existing Godot projects?\nThis could take a while."), folders.size()));
- multi_scan_ask->popup_centered_minsize();
+ multi_scan_ask->popup_centered();
} else {
_scan_multiple_folders(folders);
}
@@ -2413,8 +2421,12 @@ ProjectManager::ProjectManager() {
switch (display_scale) {
case 0: {
// Try applying a suitable display scale automatically
- const int screen = OS::get_singleton()->get_current_screen();
- editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+ const int screen = DisplayServer::get_singleton()->window_get_current_screen();
+#ifdef OSX_ENABLED
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_scale(screen));
+#else
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000 ? 2.0 : 1.0);
+#endif
} break;
case 1: editor_set_scale(0.75); break;
@@ -2430,12 +2442,12 @@ ProjectManager::ProjectManager() {
}
// Define a minimum window size to prevent UI elements from overlapping or being cut off
- OS::get_singleton()->set_min_window_size(Size2(750, 420) * EDSCALE);
+ DisplayServer::get_singleton()->window_set_min_size(Size2(750, 420) * EDSCALE);
#ifndef OSX_ENABLED
// The macOS platform implementation uses its own hiDPI window resizing code
// TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
- OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE));
+ DisplayServer::get_singleton()->window_set_size(DisplayServer::get_singleton()->window_get_size() * MAX(1, EDSCALE));
#endif
}
@@ -2451,7 +2463,7 @@ ProjectManager::ProjectManager() {
Panel *panel = memnew(Panel);
gui_base->add_child(panel);
panel->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- panel->add_style_override("panel", gui_base->get_stylebox("Background", "EditorStyles"));
+ panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("Background", "EditorStyles"));
VBoxContainer *vb = memnew(VBoxContainer);
panel->add_child(vb);
@@ -2459,10 +2471,10 @@ ProjectManager::ProjectManager() {
String cp;
cp += 0xA9;
- OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2020 Juan Linietsky, Ariel Manzur & Godot Contributors");
+ DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2020 Juan Linietsky, Ariel Manzur & Godot Contributors");
Control *center_box = memnew(Control);
- center_box->set_v_size_flags(SIZE_EXPAND_FILL);
+ center_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vb->add_child(center_box);
tabs = memnew(TabContainer);
@@ -2479,7 +2491,7 @@ ProjectManager::ProjectManager() {
VBoxContainer *search_tree_vb = memnew(VBoxContainer);
tree_hb->add_child(search_tree_vb);
- search_tree_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ search_tree_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
HBoxContainer *sort_filters = memnew(HBoxContainer);
Label *sort_label = memnew(Label);
@@ -2511,9 +2523,9 @@ ProjectManager::ProjectManager() {
search_tree_vb->add_child(sort_filters);
PanelContainer *pc = memnew(PanelContainer);
- pc->add_style_override("panel", gui_base->get_stylebox("bg", "Tree"));
+ pc->add_theme_style_override("panel", gui_base->get_theme_stylebox("bg", "Tree"));
search_tree_vb->add_child(pc);
- pc->set_v_size_flags(SIZE_EXPAND_FILL);
+ pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
_project_list = memnew(ProjectList);
_project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
@@ -2547,7 +2559,7 @@ ProjectManager::ProjectManager() {
scan_dir = memnew(FileDialog);
scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM);
- scan_dir->set_mode(FileDialog::MODE_OPEN_DIR);
+ scan_dir->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"));
gui_base->add_child(scan_dir);
@@ -2631,7 +2643,7 @@ ProjectManager::ProjectManager() {
language_btn->set_text(lang);
}
}
- language_btn->set_icon(get_icon("Environment", "EditorIcons"));
+ language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
settings_hb->add_child(language_btn);
language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected));
@@ -2689,8 +2701,7 @@ ProjectManager::ProjectManager() {
_scan_begin(EditorSettings::get_singleton()->get("filesystem/directories/autoscan_project_path"));
}
- SceneTree::get_singleton()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped));
- SceneTree::get_singleton()->connect("global_menu_action", callable_mp(this, &ProjectManager::_global_menu_action));
+ SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped));
run_error_diag = memnew(AcceptDialog);
gui_base->add_child(run_error_diag);
@@ -2748,7 +2759,7 @@ void ProjectListFilter::_filter_option_selected(int p_idx) {
void ProjectListFilter::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE && has_search_box) {
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
}
}
@@ -2769,7 +2780,7 @@ void ProjectListFilter::add_search_box() {
search_box = memnew(LineEdit);
search_box->set_placeholder(TTR("Search"));
search_box->connect("text_changed", callable_mp(this, &ProjectListFilter::_search_text_changed));
- search_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_child(search_box);
has_search_box = true;
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 8b9c769c59..6385000821 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -97,7 +97,6 @@ class ProjectManager : public Control {
void _restart_confirm();
void _exit_dialog();
void _scan_begin(const String &p_base);
- void _global_menu_action(const Variant &p_id, const Variant &p_meta);
void _confirm_update_settings();
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 7d8a4a733d..42493191a8 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -31,7 +31,7 @@
#include "project_settings_editor.h"
#include "core/global_constants.h"
-#include "core/input_map.h"
+#include "core/input/input_map.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "core/translation.h"
@@ -41,7 +41,7 @@
#include "scene/gui/margin_container.h"
#include "scene/gui/tab_container.h"
-ProjectSettingsEditor *ProjectSettingsEditor::singleton = NULL;
+ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr;
static const char *_button_names[JOY_BUTTON_MAX] = {
"DualShock Cross, Xbox A, Nintendo B",
@@ -80,7 +80,7 @@ void ProjectSettingsEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventKey> k = p_event;
- if (k.is_valid() && is_window_modal_on_top() && k->is_pressed()) {
+ if (k.is_valid() && k->is_pressed()) {
if (k->get_keycode_with_modifiers() == (KEY_MASK_CMD | KEY_F)) {
if (search_button->is_pressed()) {
@@ -91,7 +91,7 @@ void ProjectSettingsEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
search_button->set_pressed(true);
}
- accept_event();
+ set_input_as_handled();
}
}
}
@@ -99,22 +99,28 @@ void ProjectSettingsEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
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()));
+ set_process_unhandled_input(false);
+ }
+ } break;
case NOTIFICATION_ENTER_TREE: {
globals_editor->edit(ProjectSettings::get_singleton());
- search_button->set_icon(get_icon("Search", "EditorIcons"));
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_button->set_icon(input_editor->get_theme_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(input_editor->get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
- action_add_error->add_color_override("font_color", get_color("error_color", "Editor"));
+ action_add_error->add_theme_color_override("font_color", input_editor->get_theme_color("error_color", "Editor"));
translation_list->connect("button_pressed", callable_mp(this, &ProjectSettingsEditor::_translation_delete));
_update_actions();
- popup_add->add_icon_item(get_icon("Keyboard", "EditorIcons"), TTR("Key"), INPUT_KEY); //"Key " - because the word 'key' has already been used as a key animation
- popup_add->add_icon_item(get_icon("KeyboardPhysical", "EditorIcons"), TTR("Physical Key"), INPUT_KEY_PHYSICAL);
- popup_add->add_icon_item(get_icon("JoyButton", "EditorIcons"), TTR("Joy Button"), INPUT_JOY_BUTTON);
- popup_add->add_icon_item(get_icon("JoyAxis", "EditorIcons"), TTR("Joy Axis"), INPUT_JOY_MOTION);
- popup_add->add_icon_item(get_icon("Mouse", "EditorIcons"), TTR("Mouse Button"), INPUT_MOUSE_BUTTON);
+ 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);
List<String> tfn;
ResourceLoader::get_recognized_extensions_for_type("Translation", &tfn);
@@ -131,26 +137,22 @@ void ProjectSettingsEditor::_notification(int p_what) {
translation_res_option_file_open->add_filter("*." + E->get());
}
- restart_close_button->set_icon(get_icon("Close", "EditorIcons"));
- restart_container->add_style_override("panel", get_stylebox("bg", "Tree"));
- restart_icon->set_texture(get_icon("StatusWarning", "EditorIcons"));
- restart_label->add_color_override("font_color", get_color("warning_color", "Editor"));
+ restart_close_button->set_icon(input_editor->get_theme_icon("Close", "EditorIcons"));
+ restart_container->add_theme_style_override("panel", input_editor->get_theme_stylebox("bg", "Tree"));
+ restart_icon->set_texture(input_editor->get_theme_icon("StatusWarning", "EditorIcons"));
+ restart_label->add_theme_color_override("font_color", input_editor->get_theme_color("warning_color", "Editor"));
} break;
- case NOTIFICATION_POPUP_HIDE: {
- EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", get_rect());
- set_process_unhandled_input(false);
- } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- search_button->set_icon(get_icon("Search", "EditorIcons"));
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_button->set_icon(input_editor->get_theme_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(input_editor->get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
- action_add_error->add_color_override("font_color", get_color("error_color", "Editor"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY_PHYSICAL), get_icon("KeyboardPhysical", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_MOTION), get_icon("JoyAxis", "EditorIcons"));
- popup_add->set_item_icon(popup_add->get_item_index(INPUT_MOUSE_BUTTON), get_icon("Mouse", "EditorIcons"));
+ 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;
}
@@ -462,7 +464,7 @@ void ProjectSettingsEditor::_wait_for_key(const Ref<InputEvent> &p_event) {
press_a_key_label->set_text(str);
press_a_key->get_ok()->set_disabled(false);
- press_a_key->accept_event();
+ press_a_key->set_input_as_handled();
}
}
@@ -479,7 +481,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
press_a_key->get_ok()->set_disabled(true);
last_wait_for_key = Ref<InputEvent>();
press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
- press_a_key->grab_focus();
+ //press_a_key->grab_focus();
} break;
case INPUT_KEY_PHYSICAL: {
@@ -505,7 +507,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
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_minsize(Size2(350, 95) * EDSCALE);
+ device_input->popup_centered(Size2(350, 95) * EDSCALE);
Ref<InputEventMouseButton> mb = p_exiting_event;
if (mb.is_valid()) {
@@ -527,7 +529,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
String desc = _axis_names[i];
device_index->add_item(TTR("Axis") + " " + itos(i / 2) + " " + ((i & 1) ? "+" : "-") + desc);
}
- device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE);
+ device_input->popup_centered(Size2(350, 95) * EDSCALE);
Ref<InputEventJoypadMotion> jm = p_exiting_event;
if (jm.is_valid()) {
@@ -549,7 +551,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even
device_index->add_item(itos(i) + ": " + String(_button_names[i]));
}
- device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE);
+ device_input->popup_centered(Size2(350, 95) * EDSCALE);
Ref<InputEventJoypadButton> jb = p_exiting_event;
if (jb.is_valid()) {
@@ -738,7 +740,7 @@ void ProjectSettingsEditor::_update_actions() {
TreeItem *item = input_editor->create_item(root);
item->set_text(0, name);
- item->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
+ item->set_custom_bg_color(0, input_editor->get_theme_color("prop_subsection", "Editor"));
if (collapsed.has(name))
item->set_collapsed(collapsed[name]);
@@ -746,12 +748,12 @@ void ProjectSettingsEditor::_update_actions() {
item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
item->set_range_config(1, 0.0, 1.0, 0.01);
item->set_range(1, action["deadzone"]);
- item->set_custom_bg_color(1, get_color("prop_subsection", "Editor"));
+ 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(pi.name) != NULL;
+ const bool is_builtin_input = ProjectSettings::get_singleton()->get_input_presets().find(pi.name) != nullptr;
const String tooltip = is_builtin_input ? TTR("Built-in actions can't be removed as they're used for UI navigation.") : TTR("Remove");
- item->add_button(2, get_icon("Add", "EditorIcons"), 1, false, TTR("Add Event"));
- item->add_button(2, get_icon("Remove", "EditorIcons"), 2, false, tooltip);
+ 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);
if (is_builtin_input) {
// Built-in action (like `ui_up`). Make the action not removable,
@@ -778,9 +780,9 @@ void ProjectSettingsEditor::_update_actions() {
action2->set_text(0, str);
if ((k->get_keycode() != 0)) {
- action2->set_icon(0, get_icon("Keyboard", "EditorIcons"));
+ action2->set_icon(0, input_editor->get_theme_icon("Keyboard", "EditorIcons"));
} else {
- action2->set_icon(0, get_icon("KeyboardPhysical", "EditorIcons"));
+ action2->set_icon(0, input_editor->get_theme_icon("KeyboardPhysical", "EditorIcons"));
}
}
@@ -794,7 +796,7 @@ void ProjectSettingsEditor::_update_actions() {
}
action2->set_text(0, str);
- action2->set_icon(0, get_icon("JoyButton", "EditorIcons"));
+ action2->set_icon(0, input_editor->get_theme_icon("JoyButton", "EditorIcons"));
}
Ref<InputEventMouseButton> mb = event;
@@ -811,7 +813,7 @@ void ProjectSettingsEditor::_update_actions() {
}
action2->set_text(0, str);
- action2->set_icon(0, get_icon("Mouse", "EditorIcons"));
+ action2->set_icon(0, input_editor->get_theme_icon("Mouse", "EditorIcons"));
}
Ref<InputEventJoypadMotion> jm = event;
@@ -823,13 +825,13 @@ void ProjectSettingsEditor::_update_actions() {
String desc = _axis_names[n];
String str = _get_device_string(jm->get_device()) + ", " + TTR("Axis") + " " + itos(ax) + " " + (jm->get_axis_value() < 0 ? "-" : "+") + desc;
action2->set_text(0, str);
- action2->set_icon(0, get_icon("JoyAxis", "EditorIcons"));
+ 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, get_icon("Edit", "EditorIcons"), 3, false, TTR("Edit"));
- action2->add_button(2, get_icon("Remove", "EditorIcons"), 2, false, TTR("Remove"));
+ 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));
@@ -881,7 +883,7 @@ void ProjectSettingsEditor::_item_add() {
// 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;
- const Variant value = Variant::construct(Variant::Type(type->get_selected() + 1), NULL, 0, ce);
+ const Variant value = Variant::construct(Variant::Type(type->get_selected() + 1), nullptr, 0, ce);
String catname = category->get_text().strip_edges();
String propname = property->get_text().strip_edges();
@@ -1112,7 +1114,7 @@ Variant ProjectSettingsEditor::get_drag_data_fw(const Point2 &p_point, Control *
hb->set_modulate(Color(1, 1, 1, 1.0f));
hb->add_child(label);
vb->add_child(hb);
- set_drag_preview(vb);
+ input_editor->set_drag_preview(vb);
Dictionary drag_data;
drag_data["type"] = "nodes";
@@ -1535,7 +1537,7 @@ void ProjectSettingsEditor::_update_translations() {
updating_translations = true;
translation_list->clear();
- TreeItem *root = translation_list->create_item(NULL);
+ TreeItem *root = translation_list->create_item(nullptr);
translation_list->set_hide_root(true);
if (ProjectSettings::get_singleton()->has_setting("locale/translations")) {
@@ -1547,7 +1549,7 @@ void ProjectSettingsEditor::_update_translations() {
t->set_text(0, translations[i].replace_first("res://", ""));
t->set_tooltip(0, translations[i]);
t->set_metadata(0, i);
- t->add_button(0, get_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
+ t->add_button(0, input_editor->get_theme_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
}
}
@@ -1587,7 +1589,7 @@ void ProjectSettingsEditor::_update_translations() {
translation_locales_list_created = true;
translation_filter->clear();
- root = translation_filter->create_item(NULL);
+ root = translation_filter->create_item(nullptr);
translation_filter->set_hide_root(true);
translation_filter_treeitems.clear();
for (int i = 0; i < s; i++) {
@@ -1620,8 +1622,8 @@ void ProjectSettingsEditor::_update_translations() {
translation_remap->clear();
translation_remap_options->clear();
- root = translation_remap->create_item(NULL);
- TreeItem *root2 = translation_remap_options->create_item(NULL);
+ root = translation_remap->create_item(nullptr);
+ TreeItem *root2 = translation_remap_options->create_item(nullptr);
translation_remap->set_hide_root(true);
translation_remap_options->set_hide_root(true);
translation_res_option_add_button->set_disabled(true);
@@ -1670,7 +1672,7 @@ void ProjectSettingsEditor::_update_translations() {
t->set_text(0, keys[i].replace_first("res://", ""));
t->set_tooltip(0, keys[i]);
t->set_metadata(0, keys[i]);
- t->add_button(0, get_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
+ t->add_button(0, input_editor->get_theme_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
if (keys[i] == remap_selected) {
t->select(0);
translation_res_option_add_button->set_disabled(false);
@@ -1688,7 +1690,7 @@ void ProjectSettingsEditor::_update_translations() {
t2->set_text(0, path.replace_first("res://", ""));
t2->set_tooltip(0, path);
t2->set_metadata(0, j);
- t2->add_button(0, get_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
+ t2->add_button(0, input_editor->get_theme_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
t2->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
t2->set_text(1, langnames);
t2->set_editable(1, true);
@@ -1774,7 +1776,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
singleton = this;
set_title(TTR("Project Settings (project.godot)"));
- set_resizable(true);
+
undo_redo = &p_data->get_undo_redo();
data = p_data;
@@ -1873,7 +1875,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
add_prop_bar->add_child(popup_copy_to_feature);
popup_copy_to_feature->get_popup()->connect("id_pressed", callable_mp(this, &ProjectSettingsEditor::_copy_to_platform));
- popup_copy_to_feature->get_popup()->connect("about_to_show", callable_mp(this, &ProjectSettingsEditor::_copy_to_platform_about_to_show));
+ popup_copy_to_feature->get_popup()->connect("about_to_popup", callable_mp(this, &ProjectSettingsEditor::_copy_to_platform_about_to_show));
get_ok()->set_text(TTR("Close"));
set_hide_on_ok(true);
@@ -1883,7 +1885,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
HBoxContainer *restart_hb = memnew(HBoxContainer);
restart_container->add_child(restart_hb);
restart_icon = memnew(TextureRect);
- restart_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
+ restart_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
restart_hb->add_child(restart_icon);
restart_label = memnew(Label);
restart_label->set_text(TTR("The editor must be restarted for changes to take effect."));
@@ -1907,10 +1909,10 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
VBoxContainer *vbc = memnew(VBoxContainer);
input_base->add_child(vbc);
- vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0);
- vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0);
- vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0);
- vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
+ vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 0);
+ vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, 0);
+ vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 0);
+ vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, 0);
hbc = memnew(HBoxContainer);
vbc->add_child(hbc);
@@ -1920,7 +1922,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
l->set_text(TTR("Action:"));
action_name = memnew(LineEdit);
- action_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ action_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(action_name);
action_name->connect("text_entered", callable_mp(this, &ProjectSettingsEditor::_action_adds));
action_name->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_action_check));
@@ -1938,7 +1940,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
input_editor = memnew(Tree);
vbc->add_child(input_editor);
- input_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ 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"));
@@ -1951,7 +1953,10 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
input_editor->connect("item_activated", callable_mp(this, &ProjectSettingsEditor::_action_activated));
input_editor->connect("cell_selected", callable_mp(this, &ProjectSettingsEditor::_action_selected));
input_editor->connect("button_pressed", callable_mp(this, &ProjectSettingsEditor::_action_button_pressed));
- input_editor->set_drag_forwarding(this);
+#ifndef _MSC_VER
+#warning need to make drag data forwarding to non controls happen
+#endif
+ //input_editor->set_drag_forwarding(this);
popup_add = memnew(PopupMenu);
add_child(popup_add);
@@ -1960,7 +1965,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
press_a_key_physical = false;
press_a_key = memnew(ConfirmationDialog);
- press_a_key->set_focus_mode(FOCUS_ALL);
+ //press_a_key->set_focus_mode(Control::FOCUS_ALL);
add_child(press_a_key);
l = memnew(Label);
@@ -1968,11 +1973,11 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
l->set_anchors_and_margins_preset(Control::PRESET_WIDE);
l->set_align(Label::ALIGN_CENTER);
l->set_margin(MARGIN_TOP, 20);
- l->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_BEGIN, 30);
+ l->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_BEGIN, 30);
press_a_key->get_ok()->set_disabled(true);
press_a_key_label = l;
press_a_key->add_child(l);
- press_a_key->connect("gui_input", callable_mp(this, &ProjectSettingsEditor::_wait_for_key));
+ press_a_key->connect("window_input", callable_mp(this, &ProjectSettingsEditor::_wait_for_key));
press_a_key->connect("confirmed", callable_mp(this, &ProjectSettingsEditor::_press_a_key_confirm));
device_input = memnew(ConfirmationDialog);
@@ -1998,7 +2003,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
VBoxContainer *vbc_right = memnew(VBoxContainer);
hbc->add_child(vbc_right);
- vbc_right->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_right->set_h_size_flags(Control::SIZE_EXPAND_FILL);
l = memnew(Label);
l->set_text(TTR("Index:"));
@@ -2006,6 +2011,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
device_index_label = l;
device_index = memnew(OptionButton);
+ device_index->set_clip_text(true);
+
vbc_right->add_child(device_index);
setting = false;
@@ -2033,14 +2040,14 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
thb->add_child(addtr);
VBoxContainer *tmc = memnew(VBoxContainer);
tvb->add_child(tmc);
- tmc->set_v_size_flags(SIZE_EXPAND_FILL);
+ tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
translation_list = memnew(Tree);
- translation_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ translation_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tmc->add_child(translation_list);
translation_file_open = memnew(EditorFileDialog);
add_child(translation_file_open);
- translation_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ translation_file_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
translation_file_open->connect("file_selected", callable_mp(this, &ProjectSettingsEditor::_translation_add));
}
@@ -2057,16 +2064,16 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
thb->add_child(addtr);
VBoxContainer *tmc = memnew(VBoxContainer);
tvb->add_child(tmc);
- tmc->set_v_size_flags(SIZE_EXPAND_FILL);
+ tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
translation_remap = memnew(Tree);
- translation_remap->set_v_size_flags(SIZE_EXPAND_FILL);
+ translation_remap->set_v_size_flags(Control::SIZE_EXPAND_FILL);
translation_remap->connect("cell_selected", callable_mp(this, &ProjectSettingsEditor::_translation_res_select));
tmc->add_child(translation_remap);
translation_remap->connect("button_pressed", callable_mp(this, &ProjectSettingsEditor::_translation_res_delete));
translation_res_file_open = memnew(EditorFileDialog);
add_child(translation_res_file_open);
- translation_res_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ translation_res_file_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
translation_res_file_open->connect("file_selected", callable_mp(this, &ProjectSettingsEditor::_translation_res_add));
thb = memnew(HBoxContainer);
@@ -2079,9 +2086,9 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
thb->add_child(addtr);
tmc = memnew(VBoxContainer);
tvb->add_child(tmc);
- tmc->set_v_size_flags(SIZE_EXPAND_FILL);
+ tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
translation_remap_options = memnew(Tree);
- translation_remap_options->set_v_size_flags(SIZE_EXPAND_FILL);
+ translation_remap_options->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tmc->add_child(translation_remap_options);
translation_remap_options->set_columns(2);
@@ -2096,7 +2103,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
translation_res_option_file_open = memnew(EditorFileDialog);
add_child(translation_res_option_file_open);
- translation_res_option_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ translation_res_option_file_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
translation_res_option_file_open->connect("file_selected", callable_mp(this, &ProjectSettingsEditor::_translation_res_option_add));
}
@@ -2105,7 +2112,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
translations->add_child(tvb);
tvb->set_name(TTR("Locales Filter"));
VBoxContainer *tmc = memnew(VBoxContainer);
- tmc->set_v_size_flags(SIZE_EXPAND_FILL);
+ tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tvb->add_child(tmc);
translation_locale_filter_mode = memnew(OptionButton);
@@ -2116,7 +2123,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
translation_locale_filter_mode->connect("item_selected", callable_mp(this, &ProjectSettingsEditor::_translation_filter_mode_changed));
translation_filter = memnew(Tree);
- translation_filter->set_v_size_flags(SIZE_EXPAND_FILL);
+ translation_filter->set_v_size_flags(Control::SIZE_EXPAND_FILL);
translation_filter->set_columns(1);
tmc->add_child(memnew(Label(TTR("Locales:"))));
tmc->add_child(translation_filter);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 52e7612acd..2cecb13198 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PROJECT_SETTINGS_H
-#define PROJECT_SETTINGS_H
+#ifndef PROJECT_SETTINGS_EDITOR_H
+#define PROJECT_SETTINGS_EDITOR_H
#include "core/undo_redo.h"
#include "editor/editor_autoload_settings.h"
@@ -204,4 +204,4 @@ public:
ProjectSettingsEditor(EditorData *p_data);
};
-#endif // PROJECT_SETTINGS_H
+#endif // PROJECT_SETTINGS_EDITOR_H
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index f4af50eb81..978c95b9c8 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -31,11 +31,11 @@
#include "property_editor.h"
#include "core/class_db.h"
+#include "core/input/input_filter.h"
#include "core/io/image_loader.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/math/expression.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/pair.h"
#include "core/print_string.h"
@@ -53,7 +53,7 @@
#include "editor/multi_node_edit.h"
#include "editor/property_selector.h"
#include "scene/gui/label.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/font.h"
#include "scene/resources/packed_scene.h"
#include "scene/scene_string_names.h"
@@ -103,12 +103,7 @@ Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_res
void CustomPropertyEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
-
- RID ci = get_canvas_item();
- get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size()));
- }
- if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) {
+ if (p_what == NOTIFICATION_WM_CLOSE_REQUEST) {
hide();
}
}
@@ -151,7 +146,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
switch (p_which) {
case OBJ_MENU_LOAD: {
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
List<String> extensions;
@@ -199,7 +194,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
List<PropertyInfo> property_list;
res_orig->get_property_list(&property_list);
- List<Pair<String, Variant> > propvalues;
+ List<Pair<String, Variant>> propvalues;
for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
@@ -222,7 +217,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
ERR_FAIL_COND(res.is_null());
- for (List<Pair<String, Variant> >::Element *E = propvalues.front(); E; E = E->next()) {
+ for (List<Pair<String, Variant>>::Element *E = propvalues.front(); E; E = E->next()) {
Pair<String, Variant> &p = E->get();
res->set(p.first, p.second);
@@ -262,7 +257,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
file_system_dock->navigate_to_path(r->get_path());
// Ensure that the FileSystem dock is visible.
TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(file_system_dock->get_position_in_parent());
+ tab_container->set_current_tab(file_system_dock->get_index());
} break;
default: {
@@ -270,7 +265,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
int to_type = p_which - CONVERT_BASE_ID;
- Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(RES(v));
+ Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(RES(v));
ERR_FAIL_INDEX(to_type, conversions.size());
@@ -493,14 +488,14 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_EXP_EASING) {
- easing_draw->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5 * EDSCALE);
- easing_draw->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5 * EDSCALE);
- easing_draw->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 5 * EDSCALE);
- easing_draw->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -30 * EDSCALE);
- type_button->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 3 * EDSCALE);
- type_button->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -3 * EDSCALE);
- type_button->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -25 * EDSCALE);
- type_button->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -7 * EDSCALE);
+ easing_draw->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 5 * EDSCALE);
+ easing_draw->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -5 * EDSCALE);
+ easing_draw->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 5 * EDSCALE);
+ easing_draw->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -30 * EDSCALE);
+ type_button->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 3 * EDSCALE);
+ type_button->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -3 * EDSCALE);
+ type_button->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_END, -25 * EDSCALE);
+ type_button->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -7 * EDSCALE);
type_button->set_text(TTR("Preset..."));
type_button->get_popup()->clear();
type_button->get_popup()->add_item(TTR("Linear"), EASING_LINEAR);
@@ -573,13 +568,13 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
text_edit->set_text(v);
text_edit->deselect();
- int button_margin = get_constant("button_margin", "Dialogs");
- int margin = get_constant("margin", "Dialogs");
+ int button_margin = text_edit->get_theme_constant("button_margin", "Dialogs");
+ int margin = text_edit->get_theme_constant("margin", "Dialogs");
- action_buttons[0]->set_anchor(MARGIN_LEFT, ANCHOR_END);
- action_buttons[0]->set_anchor(MARGIN_TOP, ANCHOR_END);
- action_buttons[0]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- action_buttons[0]->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
+ action_buttons[0]->set_anchor(MARGIN_LEFT, Control::ANCHOR_END);
+ action_buttons[0]->set_anchor(MARGIN_TOP, Control::ANCHOR_END);
+ action_buttons[0]->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END);
+ action_buttons[0]->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END);
action_buttons[0]->set_begin(Point2(-70 * EDSCALE, -button_margin + 5 * EDSCALE));
action_buttons[0]->set_end(Point2(-margin, -margin));
action_buttons[0]->set_text(TTR("Close"));
@@ -900,7 +895,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
break;
if (p_name == "script" && hint_text == "Script" && Object::cast_to<Node>(owner)) {
- menu->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
+ menu->add_item(TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
menu->add_separator();
} else if (hint_text != "") {
int idx = 0;
@@ -953,17 +948,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
int id = TYPE_BASE_ID + idx;
- if (!icon.is_valid() && has_icon(t, "EditorIcons")) {
- icon = get_icon(t, "EditorIcons");
- }
-
- if (icon.is_valid()) {
-
- menu->add_icon_item(icon, vformat(TTR("New %s"), t), id);
- } else {
-
- menu->add_item(vformat(TTR("New %s"), t), id);
- }
+ menu->add_item(vformat(TTR("New %s"), t), id);
idx++;
}
@@ -973,13 +958,14 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
menu->add_separator();
}
- menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD);
+ menu->add_item(TTR("Load"), OBJ_MENU_LOAD);
if (!RES(v).is_null()) {
- menu->add_icon_item(get_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT);
- menu->add_icon_item(get_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR);
- menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
+ menu->add_item(TTR("Edit"), OBJ_MENU_EDIT);
+ menu->add_item(TTR("Clear"), OBJ_MENU_CLEAR);
+ menu->add_item(TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
+
RES r = v;
if (r.is_valid() && r->get_path().is_resource_file()) {
menu->add_separator();
@@ -1016,22 +1002,13 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
if (!RES(v).is_null()) {
- Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(RES(v));
+ Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(RES(v));
if (conversions.size()) {
menu->add_separator();
}
for (int i = 0; i < conversions.size(); i++) {
String what = conversions[i]->converts_to();
- Ref<Texture2D> icon;
- if (has_icon(what, "EditorIcons")) {
-
- icon = get_icon(what, "EditorIcons");
- } else {
-
- icon = get_icon(what, "Resource");
- }
-
- menu->add_icon_item(icon, vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i);
+ menu->add_item(vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i);
}
}
@@ -1105,7 +1082,7 @@ void CustomPropertyEditor::_file_selected(String p_file) {
RES res = ResourceLoader::load(p_file, type);
if (res.is_null()) {
error->set_text(TTR("Error loading file: Not a resource!"));
- error->popup_centered_minsize();
+ error->popup_centered();
break;
}
v = res;
@@ -1217,7 +1194,7 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
} else if (owner) {
- Node *node = NULL;
+ Node *node = nullptr;
if (owner->is_class("Node"))
node = Object::cast_to<Node>(owner);
@@ -1282,7 +1259,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
else
file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file->clear_filters();
file->clear_filters();
@@ -1316,7 +1293,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
file->set_access(EditorFileDialog::ACCESS_RESOURCES);
else
file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- file->set_mode(EditorFileDialog::MODE_OPEN_DIR);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
file->clear_filters();
file->popup_centered_ratio();
} else {
@@ -1385,7 +1362,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
} else if (p_which == 1) {
file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
List<String> extensions;
String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
@@ -1421,7 +1398,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
List<PropertyInfo> property_list;
res_orig->get_property_list(&property_list);
- List<Pair<String, Variant> > propvalues;
+ List<Pair<String, Variant>> propvalues;
for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
@@ -1440,7 +1417,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
ERR_FAIL_COND(res.is_null());
- for (List<Pair<String, Variant> >::Element *E = propvalues.front(); E; E = E->next()) {
+ for (List<Pair<String, Variant>>::Element *E = propvalues.front(); E; E = E->next()) {
Pair<String, Variant> &p = E->get();
res->set(p.first, p.second);
@@ -1500,7 +1477,7 @@ void CustomPropertyEditor::_draw_easing() {
Size2 s = easing_draw->get_size();
Rect2 r(Point2(), s);
r = r.grow(3);
- get_stylebox("normal", "LineEdit")->draw(ci, r);
+ easing_draw->get_theme_stylebox("normal", "LineEdit")->draw(ci, r);
int points = 48;
@@ -1508,8 +1485,8 @@ void CustomPropertyEditor::_draw_easing() {
float exp = v;
bool flip = hint_text == "attenuation";
- Ref<Font> f = get_font("font", "Label");
- Color color = get_color("font_color", "Label");
+ Ref<Font> f = easing_draw->get_theme_font("font", "Label");
+ Color color = easing_draw->get_theme_color("font_color", "Label");
for (int i = 1; i <= points; i++) {
@@ -1523,7 +1500,7 @@ void CustomPropertyEditor::_draw_easing() {
iflp = 1.0 - iflp;
}
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color);
prev = h;
}
@@ -1564,7 +1541,7 @@ void CustomPropertyEditor::_modified(String p_string) {
v = value_editor[0]->get_text().to_int();
return;
} else {
- v = expr->execute(Array(), NULL, false);
+ v = expr->execute(Array(), nullptr, false);
}
emit_signal("variant_changed");
@@ -1736,14 +1713,14 @@ real_t CustomPropertyEditor::_parse_real_expression(String text) {
if (err != OK) {
out = value_editor[0]->get_text().to_double();
} else {
- out = expr->execute(Array(), NULL, false);
+ out = expr->execute(Array(), nullptr, false);
}
return out;
}
void CustomPropertyEditor::_emit_changed_whole_or_field() {
- if (!Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (!InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
emit_signal("variant_changed");
} else {
emit_signal("variant_field_changed", field_names[focused_value_editor]);
@@ -1805,7 +1782,7 @@ void CustomPropertyEditor::_focus_exit() {
void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) {
- Ref<StyleBox> sb = get_stylebox("panel");
+ Ref<StyleBox> sb = action_buttons[0]->get_theme_stylebox("panel");
int margin_top = sb->get_margin(MARGIN_TOP);
int margin_left = sb->get_margin(MARGIN_LEFT);
int margin_bottom = sb->get_margin(MARGIN_BOTTOM);
@@ -1921,7 +1898,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
checks20[i] = memnew(CheckBox);
checks20[i]->set_toggle_mode(true);
- checks20[i]->set_focus_mode(FOCUS_NONE);
+ checks20[i]->set_focus_mode(Control::FOCUS_NONE);
checks20gc->add_child(checks20[i]);
checks20[i]->hide();
checks20[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed), make_binds(i));
@@ -1947,9 +1924,8 @@ CustomPropertyEditor::CustomPropertyEditor() {
action_buttons[i]->set_flat(true);
}
- color_picker = NULL;
+ color_picker = nullptr;
- set_as_toplevel(true);
file = memnew(EditorFileDialog);
add_child(file);
file->hide();
@@ -1983,11 +1959,11 @@ CustomPropertyEditor::CustomPropertyEditor() {
type_button->get_popup()->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_type_create_selected));
menu = memnew(PopupMenu);
- menu->set_pass_on_modal_close_click(false);
+ // menu->set_pass_on_modal_close_click(false);
add_child(menu);
menu->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_menu_option));
- evaluator = NULL;
+ evaluator = nullptr;
spinbox = memnew(SpinBox);
add_child(spinbox);
@@ -1999,6 +1975,6 @@ CustomPropertyEditor::CustomPropertyEditor() {
slider->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5);
slider->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified));
- create_dialog = NULL;
- property_select = NULL;
+ create_dialog = nullptr;
+ property_select = nullptr;
}
diff --git a/editor/property_editor.h b/editor/property_editor.h
index bc2a222714..45466eaa42 100644
--- a/editor/property_editor.h
+++ b/editor/property_editor.h
@@ -63,9 +63,9 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const;
};
-class CustomPropertyEditor : public Popup {
+class CustomPropertyEditor : public PopupPanel {
- GDCLASS(CustomPropertyEditor, Popup);
+ GDCLASS(CustomPropertyEditor, PopupPanel);
enum {
MAX_VALUE_EDITORS = 12,
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index ede7b860d6..1960ecc604 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -96,7 +96,7 @@ void PropertySelector::_update_search() {
} else if (type != Variant::NIL) {
Variant v;
Callable::CallError ce;
- v = Variant::construct(type, NULL, 0, ce);
+ v = Variant::construct(type, nullptr, 0, ce);
v.get_property_list(&props);
} else {
@@ -116,43 +116,43 @@ void PropertySelector::_update_search() {
}
}
- TreeItem *category = NULL;
+ TreeItem *category = nullptr;
bool found = false;
Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {
- Control::get_icon("Variant", "EditorIcons"),
- Control::get_icon("bool", "EditorIcons"),
- Control::get_icon("int", "EditorIcons"),
- Control::get_icon("float", "EditorIcons"),
- Control::get_icon("String", "EditorIcons"),
- Control::get_icon("Vector2", "EditorIcons"),
- Control::get_icon("Rect2", "EditorIcons"),
- Control::get_icon("Vector3", "EditorIcons"),
- Control::get_icon("Transform2D", "EditorIcons"),
- Control::get_icon("Plane", "EditorIcons"),
- Control::get_icon("Quat", "EditorIcons"),
- Control::get_icon("AABB", "EditorIcons"),
- Control::get_icon("Basis", "EditorIcons"),
- Control::get_icon("Transform", "EditorIcons"),
- Control::get_icon("Color", "EditorIcons"),
- Control::get_icon("Path", "EditorIcons"),
- Control::get_icon("RID", "EditorIcons"),
- Control::get_icon("Object", "EditorIcons"),
- Control::get_icon("Dictionary", "EditorIcons"),
- Control::get_icon("Array", "EditorIcons"),
- Control::get_icon("PackedByteArray", "EditorIcons"),
- Control::get_icon("PackedInt32Array", "EditorIcons"),
- Control::get_icon("PackedFloat32Array", "EditorIcons"),
- Control::get_icon("PackedStringArray", "EditorIcons"),
- Control::get_icon("PackedVector2Array", "EditorIcons"),
- Control::get_icon("PackedVector3Array", "EditorIcons"),
- Control::get_icon("PackedColorArray", "EditorIcons")
+ search_options->get_theme_icon("Variant", "EditorIcons"),
+ search_options->get_theme_icon("bool", "EditorIcons"),
+ search_options->get_theme_icon("int", "EditorIcons"),
+ search_options->get_theme_icon("float", "EditorIcons"),
+ search_options->get_theme_icon("String", "EditorIcons"),
+ search_options->get_theme_icon("Vector2", "EditorIcons"),
+ search_options->get_theme_icon("Rect2", "EditorIcons"),
+ search_options->get_theme_icon("Vector3", "EditorIcons"),
+ search_options->get_theme_icon("Transform2D", "EditorIcons"),
+ search_options->get_theme_icon("Plane", "EditorIcons"),
+ search_options->get_theme_icon("Quat", "EditorIcons"),
+ search_options->get_theme_icon("AABB", "EditorIcons"),
+ search_options->get_theme_icon("Basis", "EditorIcons"),
+ search_options->get_theme_icon("Transform", "EditorIcons"),
+ search_options->get_theme_icon("Color", "EditorIcons"),
+ search_options->get_theme_icon("Path", "EditorIcons"),
+ search_options->get_theme_icon("RID", "EditorIcons"),
+ search_options->get_theme_icon("Object", "EditorIcons"),
+ search_options->get_theme_icon("Dictionary", "EditorIcons"),
+ search_options->get_theme_icon("Array", "EditorIcons"),
+ search_options->get_theme_icon("PackedByteArray", "EditorIcons"),
+ search_options->get_theme_icon("PackedInt32Array", "EditorIcons"),
+ search_options->get_theme_icon("PackedFloat32Array", "EditorIcons"),
+ search_options->get_theme_icon("PackedStringArray", "EditorIcons"),
+ search_options->get_theme_icon("PackedVector2Array", "EditorIcons"),
+ search_options->get_theme_icon("PackedVector3Array", "EditorIcons"),
+ search_options->get_theme_icon("PackedColorArray", "EditorIcons")
};
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
if (E->get().usage == PROPERTY_USAGE_CATEGORY) {
- if (category && category->get_children() == NULL) {
+ if (category && category->get_children() == nullptr) {
memdelete(category); //old category was unused
}
category = search_options->create_item(root);
@@ -161,7 +161,7 @@ void PropertySelector::_update_search() {
Ref<Texture2D> icon;
if (E->get().name == "Script Variables") {
- icon = get_icon("Script", "EditorIcons");
+ icon = search_options->get_theme_icon("Script", "EditorIcons");
} else {
icon = EditorNode::get_singleton()->get_class_icon(E->get().name);
}
@@ -191,7 +191,7 @@ void PropertySelector::_update_search() {
item->set_selectable(0, true);
}
- if (category && category->get_children() == NULL) {
+ if (category && category->get_children() == nullptr) {
memdelete(category); //old category was unused
}
} else {
@@ -201,7 +201,7 @@ void PropertySelector::_update_search() {
if (type != Variant::NIL) {
Variant v;
Callable::CallError ce;
- v = Variant::construct(type, NULL, 0, ce);
+ v = Variant::construct(type, nullptr, 0, ce);
v.get_method_list(&methods);
} else {
@@ -220,14 +220,14 @@ void PropertySelector::_update_search() {
}
}
- TreeItem *category = NULL;
+ TreeItem *category = nullptr;
bool found = false;
bool script_methods = false;
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
if (E->get().name.begins_with("*")) {
- if (category && category->get_children() == NULL) {
+ if (category && category->get_children() == nullptr) {
memdelete(category); //old category was unused
}
category = search_options->create_item(root);
@@ -238,7 +238,7 @@ void PropertySelector::_update_search() {
script_methods = false;
String rep = E->get().name.replace("*", "");
if (E->get().name == "*Script Methods") {
- icon = get_icon("Script", "EditorIcons");
+ icon = search_options->get_theme_icon("Script", "EditorIcons");
script_methods = true;
} else {
icon = EditorNode::get_singleton()->get_class_icon(rep);
@@ -310,12 +310,12 @@ void PropertySelector::_update_search() {
}
}
- if (category && category->get_children() == NULL) {
+ if (category && category->get_children() == nullptr) {
memdelete(category); //old category was unused
}
}
- get_ok()->set_disabled(root->get_children() == NULL);
+ get_ok()->set_disabled(root->get_children() == nullptr);
}
void PropertySelector::_confirmed() {
@@ -390,7 +390,7 @@ void PropertySelector::_item_selected() {
}
void PropertySelector::_hide_requested() {
- _closed(); // From WindowDialog.
+ _cancel_pressed(); // From AcceptDialog.
}
void PropertySelector::_notification(int p_what) {
@@ -410,7 +410,7 @@ void PropertySelector::select_method_from_base_type(const String &p_base, const
type = Variant::NIL;
script = ObjectID();
properties = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = p_virtuals_only;
popup_centered_ratio(0.6);
@@ -427,7 +427,7 @@ void PropertySelector::select_method_from_script(const Ref<Script> &p_script, co
type = Variant::NIL;
script = p_script->get_instance_id();
properties = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
popup_centered_ratio(0.6);
@@ -443,7 +443,7 @@ void PropertySelector::select_method_from_basic_type(Variant::Type p_type, const
type = p_type;
script = ObjectID();
properties = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
popup_centered_ratio(0.6);
@@ -464,7 +464,7 @@ void PropertySelector::select_method_from_instance(Object *p_instance, const Str
script = scr->get_instance_id();
}
properties = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
popup_centered_ratio(0.6);
@@ -480,7 +480,7 @@ void PropertySelector::select_property_from_base_type(const String &p_base, cons
type = Variant::NIL;
script = ObjectID();
properties = true;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
popup_centered_ratio(0.6);
@@ -498,7 +498,7 @@ void PropertySelector::select_property_from_script(const Ref<Script> &p_script,
type = Variant::NIL;
script = p_script->get_instance_id();
properties = true;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
popup_centered_ratio(0.6);
@@ -515,7 +515,7 @@ void PropertySelector::select_property_from_basic_type(Variant::Type p_type, con
type = p_type;
script = ObjectID();
properties = true;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
popup_centered_ratio(0.6);
diff --git a/editor/pvrtc_compress.cpp b/editor/pvrtc_compress.cpp
index f9efe6a50d..1363fe2942 100644
--- a/editor/pvrtc_compress.cpp
+++ b/editor/pvrtc_compress.cpp
@@ -38,8 +38,8 @@
#include "editor_settings.h"
#include "scene/resources/texture.h"
-static void (*_base_image_compress_pvrtc2_func)(Image *) = NULL;
-static void (*_base_image_compress_pvrtc4_func)(Image *) = NULL;
+static void (*_base_image_compress_pvrtc2_func)(Image *) = nullptr;
+static void (*_base_image_compress_pvrtc4_func)(Image *) = nullptr;
static void _compress_image(Image::CompressMode p_mode, Image *p_image) {
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index 8a5fad269f..1b4439f0a8 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -122,7 +122,7 @@ float EditorQuickOpen::_path_cmp(String search, String path) const {
return path.to_lower().similarity(search.to_lower());
}
-void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D> > > &list) {
+void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D>>> &list) {
if (!add_directories) {
for (int i = 0; i < efsd->get_subdir_count(); i++) {
@@ -140,9 +140,9 @@ void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<Str
if (path != "res://") {
path = path.substr(6, path.length());
if (search_text.is_subsequence_ofi(path)) {
- Pair<String, Ref<Texture2D> > pair;
+ Pair<String, Ref<Texture2D>> pair;
pair.first = path;
- pair.second = get_icon("folder", "FileDialog");
+ pair.second = search_options->get_theme_icon("folder", "FileDialog");
if (search_text != String() && list.size() > 0) {
@@ -169,9 +169,9 @@ void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<Str
file = file.substr(6, file.length());
if (ClassDB::is_parent_class(efsd->get_file_type(i), base_type) && (search_text.is_subsequence_ofi(file))) {
- Pair<String, Ref<Texture2D> > pair;
+ Pair<String, Ref<Texture2D>> pair;
pair.first = file;
- pair.second = get_icon((has_icon(efsd->get_file_type(i), ei) ? efsd->get_file_type(i) : ot), ei);
+ pair.second = search_options->get_theme_icon((search_options->has_theme_icon(efsd->get_file_type(i), ei) ? efsd->get_file_type(i) : ot), ei);
list.push_back(pair);
}
}
@@ -184,10 +184,10 @@ void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<Str
}
}
-Vector<Pair<String, Ref<Texture2D> > > EditorQuickOpen::_sort_fs(Vector<Pair<String, Ref<Texture2D> > > &list) {
+Vector<Pair<String, Ref<Texture2D>>> EditorQuickOpen::_sort_fs(Vector<Pair<String, Ref<Texture2D>>> &list) {
String search_text = search_box->get_text();
- Vector<Pair<String, Ref<Texture2D> > > sorted_list;
+ Vector<Pair<String, Ref<Texture2D>>> sorted_list;
if (search_text == String() || list.size() == 0)
return list;
@@ -223,7 +223,7 @@ void EditorQuickOpen::_update_search() {
search_options->clear();
TreeItem *root = search_options->create_item();
EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem();
- Vector<Pair<String, Ref<Texture2D> > > list;
+ Vector<Pair<String, Ref<Texture2D>>> list;
_parse_fs(efsd, list);
list = _sort_fs(list);
@@ -241,7 +241,7 @@ void EditorQuickOpen::_update_search() {
ti->set_as_cursor(0);
}
- get_ok()->set_disabled(root->get_children() == NULL);
+ get_ok()->set_disabled(root->get_children() == nullptr);
}
void EditorQuickOpen::_confirmed() {
@@ -253,6 +253,11 @@ void EditorQuickOpen::_confirmed() {
hide();
}
+void EditorQuickOpen::_theme_changed() {
+
+ search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons"));
+}
+
void EditorQuickOpen::_notification(int p_what) {
switch (p_what) {
@@ -260,10 +265,6 @@ void EditorQuickOpen::_notification(int p_what) {
connect("confirmed", callable_mp(this, &EditorQuickOpen::_confirmed));
search_box->set_clear_button_enabled(true);
- [[fallthrough]];
- }
- case NOTIFICATION_THEME_CHANGED: {
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
} break;
case NOTIFICATION_EXIT_TREE: {
disconnect("confirmed", callable_mp(this, &EditorQuickOpen::_confirmed));
@@ -284,6 +285,8 @@ void EditorQuickOpen::_bind_methods() {
EditorQuickOpen::EditorQuickOpen() {
VBoxContainer *vbc = memnew(VBoxContainer);
+ vbc->connect("theme_changed", callable_mp(this, &EditorQuickOpen::_theme_changed));
+
add_child(vbc);
search_box = memnew(LineEdit);
vbc->add_margin_child(TTR("Search:"), search_box);
@@ -298,7 +301,7 @@ EditorQuickOpen::EditorQuickOpen() {
search_options->connect("item_activated", callable_mp(this, &EditorQuickOpen::_confirmed));
search_options->set_hide_root(true);
search_options->set_hide_folding(true);
- search_options->add_constant_override("draw_guides", 1);
+ search_options->add_theme_constant_override("draw_guides", 1);
ei = "EditorIcons";
ot = "Object";
add_directories = false;
diff --git a/editor/quick_open.h b/editor/quick_open.h
index 4814e5f310..c0e2cb85d8 100644
--- a/editor/quick_open.h
+++ b/editor/quick_open.h
@@ -49,13 +49,15 @@ class EditorQuickOpen : public ConfirmationDialog {
void _update_search();
void _sbox_input(const Ref<InputEvent> &p_ie);
- void _parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D> > > &list);
- Vector<Pair<String, Ref<Texture2D> > > _sort_fs(Vector<Pair<String, Ref<Texture2D> > > &list);
+ void _parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D>>> &list);
+ Vector<Pair<String, Ref<Texture2D>>> _sort_fs(Vector<Pair<String, Ref<Texture2D>>> &list);
float _path_cmp(String search, String path) const;
void _confirmed();
void _text_changed(const String &p_newtext);
+ void _theme_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 2d7b7027c8..0266ef6a2b 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -45,7 +45,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
scene_tree_editor = p_scene_tree_editor;
undo_redo = p_undo_redo;
- preview_node = NULL;
+ preview_node = nullptr;
set_title(TTR("Batch Rename"));
@@ -56,7 +56,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
GridContainer *grd_main = memnew(GridContainer);
grd_main->set_columns(2);
- grd_main->set_v_size_flags(SIZE_EXPAND_FILL);
+ grd_main->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbc->add_child(grd_main);
// ---- 1st & 2nd row
@@ -67,7 +67,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
lne_search = memnew(LineEdit);
lne_search->set_placeholder(TTR("Search"));
lne_search->set_name("lne_search");
- lne_search->set_h_size_flags(SIZE_EXPAND_FILL);
+ lne_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *lbl_replace = memnew(Label);
lbl_replace->set_text(TTR("Replace"));
@@ -75,7 +75,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
lne_replace = memnew(LineEdit);
lne_replace->set_placeholder(TTR("Replace"));
lne_replace->set_name("lne_replace");
- lne_replace->set_h_size_flags(SIZE_EXPAND_FILL);
+ lne_replace->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_main->add_child(lbl_search);
grd_main->add_child(lbl_replace);
@@ -90,7 +90,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
lne_prefix = memnew(LineEdit);
lne_prefix->set_placeholder(TTR("Prefix"));
lne_prefix->set_name("lne_prefix");
- lne_prefix->set_h_size_flags(SIZE_EXPAND_FILL);
+ lne_prefix->set_h_size_flags(Control::SIZE_EXPAND_FILL);
Label *lbl_suffix = memnew(Label);
lbl_suffix->set_text(TTR("Suffix"));
@@ -98,7 +98,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
lne_suffix = memnew(LineEdit);
lne_suffix->set_placeholder(TTR("Suffix"));
lne_suffix->set_name("lne_suffix");
- lne_suffix->set_h_size_flags(SIZE_EXPAND_FILL);
+ lne_suffix->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_main->add_child(lbl_prefix);
grd_main->add_child(lbl_suffix);
@@ -124,7 +124,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
// ---- Tab Substitute
VBoxContainer *vbc_substitute = memnew(VBoxContainer);
- vbc_substitute->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_substitute->set_h_size_flags(Control::SIZE_EXPAND_FILL);
vbc_substitute->set_custom_minimum_size(Size2(0, feature_min_height));
vbc_substitute->set_name(TTR("Substitute"));
@@ -143,9 +143,9 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_name = memnew(Button);
but_insert_name->set_text("NAME");
but_insert_name->set_tooltip(String("${NAME}\n") + TTR("Node name"));
- but_insert_name->set_focus_mode(FOCUS_NONE);
+ but_insert_name->set_focus_mode(Control::FOCUS_NONE);
but_insert_name->connect("pressed", callable_mp(this, &RenameDialog::_insert_text), make_binds("${NAME}"));
- but_insert_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ but_insert_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_substitute->add_child(but_insert_name);
// Parent
@@ -153,9 +153,9 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_parent = memnew(Button);
but_insert_parent->set_text("PARENT");
but_insert_parent->set_tooltip(String("${PARENT}\n") + TTR("Node's parent name, if available"));
- but_insert_parent->set_focus_mode(FOCUS_NONE);
+ but_insert_parent->set_focus_mode(Control::FOCUS_NONE);
but_insert_parent->connect("pressed", callable_mp(this, &RenameDialog::_insert_text), make_binds("${PARENT}"));
- but_insert_parent->set_h_size_flags(SIZE_EXPAND_FILL);
+ but_insert_parent->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_substitute->add_child(but_insert_parent);
// Type
@@ -163,9 +163,9 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_type = memnew(Button);
but_insert_type->set_text("TYPE");
but_insert_type->set_tooltip(String("${TYPE}\n") + TTR("Node type"));
- but_insert_type->set_focus_mode(FOCUS_NONE);
+ but_insert_type->set_focus_mode(Control::FOCUS_NONE);
but_insert_type->connect("pressed", callable_mp(this, &RenameDialog::_insert_text), make_binds("${TYPE}"));
- but_insert_type->set_h_size_flags(SIZE_EXPAND_FILL);
+ but_insert_type->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_substitute->add_child(but_insert_type);
// Scene
@@ -173,9 +173,9 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_scene = memnew(Button);
but_insert_scene->set_text("SCENE");
but_insert_scene->set_tooltip(String("${SCENE}\n") + TTR("Current scene name"));
- but_insert_scene->set_focus_mode(FOCUS_NONE);
+ but_insert_scene->set_focus_mode(Control::FOCUS_NONE);
but_insert_scene->connect("pressed", callable_mp(this, &RenameDialog::_insert_text), make_binds("${SCENE}"));
- but_insert_scene->set_h_size_flags(SIZE_EXPAND_FILL);
+ but_insert_scene->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_substitute->add_child(but_insert_scene);
// Root
@@ -183,9 +183,9 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_root = memnew(Button);
but_insert_root->set_text("ROOT");
but_insert_root->set_tooltip(String("${ROOT}\n") + TTR("Root node name"));
- but_insert_root->set_focus_mode(FOCUS_NONE);
+ but_insert_root->set_focus_mode(Control::FOCUS_NONE);
but_insert_root->connect("pressed", callable_mp(this, &RenameDialog::_insert_text), make_binds("${ROOT}"));
- but_insert_root->set_h_size_flags(SIZE_EXPAND_FILL);
+ but_insert_root->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_substitute->add_child(but_insert_root);
// Count
@@ -193,9 +193,9 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_count = memnew(Button);
but_insert_count->set_text("COUNTER");
but_insert_count->set_tooltip(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options."));
- but_insert_count->set_focus_mode(FOCUS_NONE);
+ but_insert_count->set_focus_mode(Control::FOCUS_NONE);
but_insert_count->connect("pressed", callable_mp(this, &RenameDialog::_insert_text), make_binds("${COUNTER}"));
- but_insert_count->set_h_size_flags(SIZE_EXPAND_FILL);
+ but_insert_count->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grd_substitute->add_child(but_insert_count);
chk_per_level_counter = memnew(CheckBox);
@@ -240,7 +240,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
// ---- Tab Process
VBoxContainer *vbc_process = memnew(VBoxContainer);
- vbc_process->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc_process->set_h_size_flags(Control::SIZE_EXPAND_FILL);
vbc_process->set_name(TTR("Post-Process"));
vbc_process->set_custom_minimum_size(Size2(0, feature_min_height));
tabc_features->add_child(vbc_process);
@@ -291,13 +291,13 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
lbl_preview = memnew(Label);
lbl_preview->set_text("");
- lbl_preview->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
vbc->add_child(lbl_preview);
// ---- Dialog related
- set_custom_minimum_size(Size2(383, 0));
- set_as_toplevel(true);
+ set_min_size(Size2(383, 0));
+ //set_as_toplevel(true);
get_ok()->set_text(TTR("Rename"));
Button *but_reset = add_button(TTR("Reset"));
@@ -347,7 +347,7 @@ void RenameDialog::_bind_methods() {
void RenameDialog::_update_substitute() {
- LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(get_focus_owner());
+ LineEdit *focus_owner_line_edit = Object::cast_to<LineEdit>(scene_tree_editor->get_focus_owner());
bool is_main_field = _is_main_field(focus_owner_line_edit);
but_insert_name->set_disabled(!is_main_field);
@@ -358,18 +358,18 @@ void RenameDialog::_update_substitute() {
but_insert_count->set_disabled(!is_main_field);
// The focus mode seems to be reset when disabling/re-enabling
- but_insert_name->set_focus_mode(FOCUS_NONE);
- but_insert_parent->set_focus_mode(FOCUS_NONE);
- but_insert_type->set_focus_mode(FOCUS_NONE);
- but_insert_scene->set_focus_mode(FOCUS_NONE);
- but_insert_root->set_focus_mode(FOCUS_NONE);
- but_insert_count->set_focus_mode(FOCUS_NONE);
+ but_insert_name->set_focus_mode(Control::FOCUS_NONE);
+ but_insert_parent->set_focus_mode(Control::FOCUS_NONE);
+ but_insert_type->set_focus_mode(Control::FOCUS_NONE);
+ but_insert_scene->set_focus_mode(Control::FOCUS_NONE);
+ but_insert_root->set_focus_mode(Control::FOCUS_NONE);
+ but_insert_count->set_focus_mode(Control::FOCUS_NONE);
}
void RenameDialog::_post_popup() {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- preview_node = NULL;
+ preview_node = nullptr;
Array selected_node_list = editor_selection->get_selected_nodes();
ERR_FAIL_COND(selected_node_list.size() == 0);
@@ -386,7 +386,7 @@ void RenameDialog::_update_preview_int(int new_value) {
void RenameDialog::_update_preview(String new_text) {
- if (lock_preview_update || preview_node == NULL)
+ if (lock_preview_update || preview_node == nullptr)
return;
has_errors = false;
@@ -401,11 +401,11 @@ void RenameDialog::_update_preview(String new_text) {
if (new_name == preview_node->get_name()) {
// New name is identical to the old one. Don't color it as much to avoid distracting the user.
- const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_color("accent_color", "Editor");
- const Color text_color = EditorNode::get_singleton()->get_gui_base()->get_color("default_color", "RichTextLabel");
- lbl_preview->add_color_override("font_color", accent_color.linear_interpolate(text_color, 0.5));
+ const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor");
+ const Color text_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("default_color", "RichTextLabel");
+ lbl_preview->add_theme_color_override("font_color", accent_color.linear_interpolate(text_color, 0.5));
} else {
- lbl_preview->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor"));
+ lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"));
}
}
@@ -491,7 +491,7 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *
self->has_errors = true;
self->lbl_preview_title->set_text(TTR("Regular Expression Error"));
- self->lbl_preview->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
+ self->lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"));
self->lbl_preview->set_text(vformat(TTR("At character %s"), err_str));
}
@@ -652,7 +652,7 @@ bool RenameDialog::_is_main_field(LineEdit *line_edit) {
void RenameDialog::_insert_text(String text) {
- LineEdit *focus_owner = Object::cast_to<LineEdit>(get_focus_owner());
+ LineEdit *focus_owner = Object::cast_to<LineEdit>(scene_tree_editor->get_focus_owner());
if (_is_main_field(focus_owner)) {
focus_owner->selection_delete();
diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h
index 2825cb2cd2..194dd57648 100644
--- a/editor/rename_dialog.h
+++ b/editor/rename_dialog.h
@@ -96,14 +96,13 @@ class RenameDialog : public ConfirmationDialog {
Label *lbl_preview_title;
Label *lbl_preview;
- List<Pair<NodePath, String> > to_rename;
+ List<Pair<NodePath, String>> to_rename;
Node *preview_node;
bool lock_preview_update;
ErrorHandlerList eh;
bool has_errors;
protected:
- void _notification(int p_what){};
static void _bind_methods();
virtual void _post_popup();
@@ -111,7 +110,7 @@ public:
void reset();
void rename();
- RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo = NULL);
+ RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo = nullptr);
~RenameDialog(){};
};
diff --git a/editor/reparent_dialog.cpp b/editor/reparent_dialog.cpp
index 551d20eddb..b71c2bd078 100644
--- a/editor/reparent_dialog.cpp
+++ b/editor/reparent_dialog.cpp
@@ -45,12 +45,6 @@ void ReparentDialog::_notification(int p_what) {
disconnect("confirmed", callable_mp(this, &ReparentDialog::_reparent));
}
-
- if (p_what == NOTIFICATION_DRAW) {
-
- //RID ci = get_canvas_item();
- //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
- }
}
void ReparentDialog::_cancel() {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index c5ebf40482..a729f62123 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -30,8 +30,8 @@
#include "scene_tree_dock.h"
+#include "core/input/input_filter.h"
#include "core/io/resource_saver.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "editor/debugger/editor_debugger_node.h"
@@ -42,10 +42,12 @@
#include "editor/multi_node_edit.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
-#include "editor/plugins/spatial_editor_plugin.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
+#include "servers/display_server.h"
+#include "servers/rendering_server.h"
void SceneTreeDock::_nodes_drag_begin() {
@@ -73,9 +75,6 @@ void SceneTreeDock::_input(Ref<InputEvent> p_event) {
void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) {
- if (get_viewport()->get_modal_stack_top())
- return; //ignore because of modal window
-
if (get_focus_owner() && get_focus_owner()->is_text_field())
return;
@@ -131,7 +130,7 @@ void SceneTreeDock::instance(const String &p_file) {
current_option = -1;
accept->set_text(TTR("No parent to instance a child at."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
};
@@ -153,7 +152,7 @@ void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_paren
if (!parent || !edited_scene) {
accept->set_text(TTR("No parent to instance the scenes at."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
};
@@ -174,7 +173,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
if (!sdata.is_valid()) {
current_option = -1;
accept->set_text(vformat(TTR("Error loading scene from %s"), p_files[i]));
- accept->popup_centered_minsize();
+ accept->popup_centered();
error = true;
break;
}
@@ -183,7 +182,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
if (!instanced_scene) {
current_option = -1;
accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i]));
- accept->popup_centered_minsize();
+ accept->popup_centered();
error = true;
break;
}
@@ -193,7 +192,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node
if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
accept->set_text(vformat(TTR("Cannot instance the scene '%s' because the current scene exists within one of its nodes."), p_files[i]));
- accept->popup_centered_minsize();
+ accept->popup_centered();
error = true;
break;
}
@@ -240,14 +239,14 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
if (!sdata.is_valid()) {
accept->set_text(vformat(TTR("Error loading scene from %s"), p_file));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instanced_scene) {
accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
@@ -368,8 +367,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (ClassDB::is_parent_class(current_edited_scene_root->get_class_name(), "Node2D"))
preferred = "Node2D";
- else if (ClassDB::is_parent_class(current_edited_scene_root->get_class_name(), "Spatial"))
- preferred = "Spatial";
+ else if (ClassDB::is_parent_class(current_edited_scene_root->get_class_name(), "Node3D"))
+ preferred = "Node3D";
}
create_dialog->set_preferred_search_result_type(preferred);
create_dialog->popup_create(true);
@@ -439,7 +438,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
editor_data->get_undo_redo().create_action(TTR("Clear Script"));
- editor_data->get_undo_redo().add_do_method(editor, "push_item", (Script *)NULL);
+ editor_data->get_undo_redo().add_do_method(editor, "push_item", (Script *)nullptr);
for (int i = 0; i < selection.size(); i++) {
@@ -471,7 +470,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
current_option = -1;
accept->set_text(TTR("This operation can't be done on the tree root."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
break;
}
@@ -496,7 +495,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (index < lowest_id) lowest_id = index;
if (E->get()->get_parent() != common_parent)
- common_parent = NULL;
+ common_parent = nullptr;
}
if (!common_parent || (MOVING_DOWN && highest_id >= common_parent->get_child_count() - MOVING_DOWN) || (MOVING_UP && lowest_id == 0))
@@ -535,7 +534,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
current_option = -1;
accept->set_text(TTR("This operation can't be done on the tree root."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
break;
}
@@ -549,7 +548,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().create_action(TTR("Duplicate Node(s)"));
editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
- Node *dupsingle = NULL;
+ Node *dupsingle = nullptr;
List<Node *> editable_children;
selection.sort_custom<Node::Comparator>();
@@ -618,7 +617,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
current_option = -1;
accept->set_text(TTR("This operation can't be done on the tree root."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
break;
}
@@ -654,19 +653,19 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (root->get_scene_inherited_state().is_valid()) {
accept->set_text(TTR("Can't reparent nodes in inherited scenes, order of nodes can't change."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
if (node->get_owner() != root) {
accept->set_text(TTR("Node must belong to the edited scene to become root."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
if (node->get_filename() != String()) {
accept->set_text(TTR("Instantiated scenes can't become root"));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
@@ -676,7 +675,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_do_method(node, "add_child", root);
editor_data->get_undo_redo().add_do_method(node, "set_filename", root->get_filename());
editor_data->get_undo_redo().add_do_method(root, "set_filename", String());
- editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)NULL);
+ editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)nullptr);
editor_data->get_undo_redo().add_do_method(root, "set_owner", node);
_node_replace_owner(root, root, node, MODE_DO);
@@ -686,7 +685,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", root);
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node);
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, node->get_index());
- editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)NULL);
+ editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)nullptr);
editor_data->get_undo_redo().add_undo_method(node, "set_owner", root);
_node_replace_owner(root, root, root, MODE_UNDO);
@@ -745,7 +744,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// This prevents the dialog from being too wide after displaying
// a deletion confirmation for a node with a long name.
delete_dialog->set_size(Size2());
- delete_dialog->popup_centered_minsize();
+ delete_dialog->popup_centered();
}
} break;
@@ -767,7 +766,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!scene) {
accept->set_text(TTR("This operation can't be done without a scene."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
break;
}
@@ -775,7 +774,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (selection.size() != 1) {
accept->set_text(TTR("This operation requires a single selected node."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
break;
}
@@ -783,17 +782,17 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (tocopy == scene) {
accept->set_text(TTR("Can not perform with the root node."));
- accept->popup_centered_minsize();
+ 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->popup_centered_minsize();
+ accept->popup_centered();
break;
}
- new_scene_from_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ new_scene_from_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
List<String> extensions;
Ref<PackedScene> sd = memnew(PackedScene);
@@ -822,7 +821,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (node) {
Node *root = EditorNode::get_singleton()->get_edited_scene();
NodePath path = root->get_path().rel_path_to(node->get_path());
- OS::get_singleton()->set_clipboard(path);
+ DisplayServer::get_singleton()->clipboard_set(path);
}
}
} break;
@@ -848,7 +847,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (editable) {
editable_instance_remove_dialog->set_text(TTR("Disabling \"editable_instance\" will cause all properties of the node to be reverted to their default."));
- editable_instance_remove_dialog->popup_centered_minsize();
+ editable_instance_remove_dialog->popup_centered();
break;
}
_toggle_editable_children(node);
@@ -872,7 +871,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// Fire confirmation dialog when children are editable.
if (editable && !placeholder) {
placeholder_editable_instance_remove_dialog->set_text(TTR("Enabling \"Load As Placeholder\" will disable \"Editable Children\" and cause all properties of the node to be reverted to their default."));
- placeholder_editable_instance_remove_dialog->popup_centered_minsize();
+ placeholder_editable_instance_remove_dialog->popup_centered();
break;
}
@@ -929,7 +928,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- clear_inherit_confirm->popup_centered_minsize();
+ clear_inherit_confirm->popup_centered();
} break;
case TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM: {
if (!profile_allow_editing) {
@@ -963,7 +962,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
case TOOL_CREATE_USER_INTERFACE:
case TOOL_CREATE_FAVORITE: {
- Node *new_node = NULL;
+ Node *new_node = nullptr;
if (TOOL_CREATE_FAVORITE == p_tool) {
String name = selected_favorite_root.get_slicec(' ', 0);
@@ -985,7 +984,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} else {
switch (p_tool) {
case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break;
- case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break;
+ case TOOL_CREATE_3D_SCENE: new_node = memnew(Node3D); break;
case TOOL_CREATE_USER_INTERFACE: {
Control *node = memnew(Control);
node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs.
@@ -999,7 +998,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", new_node);
editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
editor_data->get_undo_redo().add_do_reference(new_node);
- editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
+ editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr);
editor_data->get_undo_redo().commit_action();
editor->edit_node(new_node);
@@ -1031,7 +1030,7 @@ void SceneTreeDock::_node_collapsed(Object *p_obj) {
if (!ti)
return;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
_set_collapsed_recursive(ti, ti->is_collapsed());
}
}
@@ -1054,16 +1053,16 @@ void SceneTreeDock::_notification(int p_what) {
scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::update));
}
- SpatialEditorPlugin *spatial_editor_plugin = Object::cast_to<SpatialEditorPlugin>(editor_data->get_editor("3D"));
+ Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D"));
spatial_editor_plugin->get_spatial_editor()->connect_compat("item_lock_status_changed", scene_tree, "_update_tree");
spatial_editor_plugin->get_spatial_editor()->connect_compat("item_group_status_changed", scene_tree, "_update_tree");
- button_add->set_icon(get_icon("Add", "EditorIcons"));
- button_instance->set_icon(get_icon("Instance", "EditorIcons"));
- button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons"));
- button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons"));
+ button_add->set_icon(get_theme_icon("Add", "EditorIcons"));
+ button_instance->set_icon(get_theme_icon("Instance", "EditorIcons"));
+ button_create_script->set_icon(get_theme_icon("ScriptCreate", "EditorIcons"));
+ button_clear_script->set_icon(get_theme_icon("ScriptRemove", "EditorIcons"));
- filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_right_icon(get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
@@ -1078,7 +1077,7 @@ void SceneTreeDock::_notification(int p_what) {
ToolButton *node_shortcuts_toggle = memnew(ToolButton);
node_shortcuts_toggle->set_name("NodeShortcutsToggle");
- node_shortcuts_toggle->set_icon(get_icon("Favorites", "EditorIcons"));
+ node_shortcuts_toggle->set_icon(get_theme_icon("Favorites", "EditorIcons"));
node_shortcuts_toggle->set_toggle_mode(true);
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
node_shortcuts_toggle->set_anchors_and_margins_preset(Control::PRESET_CENTER_RIGHT);
@@ -1097,18 +1096,19 @@ void SceneTreeDock::_notification(int p_what) {
Button *button_2d = memnew(Button);
beginner_node_shortcuts->add_child(button_2d);
button_2d->set_text(TTR("2D Scene"));
- button_2d->set_icon(get_icon("Node2D", "EditorIcons"));
+ button_2d->set_icon(get_theme_icon("Node2D", "EditorIcons"));
button_2d->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_CREATE_2D_SCENE, false));
+
button_3d = memnew(Button);
beginner_node_shortcuts->add_child(button_3d);
button_3d->set_text(TTR("3D Scene"));
- button_3d->set_icon(get_icon("Spatial", "EditorIcons"));
+ button_3d->set_icon(get_theme_icon("Node3D", "EditorIcons"));
button_3d->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_CREATE_3D_SCENE, false));
Button *button_ui = memnew(Button);
beginner_node_shortcuts->add_child(button_ui);
button_ui->set_text(TTR("User Interface"));
- button_ui->set_icon(get_icon("Control", "EditorIcons"));
+ button_ui->set_icon(get_theme_icon("Control", "EditorIcons"));
button_ui->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_CREATE_USER_INTERFACE, false));
VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer);
@@ -1118,7 +1118,7 @@ void SceneTreeDock::_notification(int p_what) {
Button *button_custom = memnew(Button);
node_shortcuts->add_child(button_custom);
button_custom->set_text(TTR("Other Node"));
- button_custom->set_icon(get_icon("Add", "EditorIcons"));
+ button_custom->set_icon(get_theme_icon("Add", "EditorIcons"));
button_custom->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_NEW, false));
node_shortcuts->add_spacer();
@@ -1134,17 +1134,17 @@ void SceneTreeDock::_notification(int p_what) {
clear_inherit_confirm->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_tool_selected));
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- button_add->set_icon(get_icon("Add", "EditorIcons"));
- button_instance->set_icon(get_icon("Instance", "EditorIcons"));
- button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons"));
- button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons"));
+ button_add->set_icon(get_theme_icon("Add", "EditorIcons"));
+ button_instance->set_icon(get_theme_icon("Instance", "EditorIcons"));
+ button_create_script->set_icon(get_theme_icon("ScriptCreate", "EditorIcons"));
+ button_clear_script->set_icon(get_theme_icon("ScriptRemove", "EditorIcons"));
- filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_right_icon(get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
} break;
case NOTIFICATION_PROCESS: {
- bool show_create_root = bool(EDITOR_GET("interface/editors/show_scene_tree_root_selection")) && get_tree()->get_edited_scene_root() == NULL;
+ bool show_create_root = bool(EDITOR_GET("interface/editors/show_scene_tree_root_selection")) && get_tree()->get_edited_scene_root() == nullptr;
if (show_create_root != create_root_dialog->is_visible_in_tree() && !remote_tree->is_visible()) {
if (show_create_root) {
@@ -1202,7 +1202,7 @@ void SceneTreeDock::_node_selected() {
if (!node) {
- editor->push_item(NULL);
+ editor->push_item(nullptr);
return;
}
@@ -1229,7 +1229,7 @@ void SceneTreeDock::_set_owners(Node *p_owner, const Array &p_nodes) {
}
}
-void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, List<Pair<NodePath, NodePath> > *p_renames) {
+void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, List<Pair<NodePath, NodePath>> *p_renames) {
base_path.push_back(p_node->get_name());
if (new_base_path.size())
@@ -1252,7 +1252,7 @@ void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<Stri
}
}
-void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath> > *p_renames) {
+void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath>> *p_renames) {
if (!bool(EDITOR_DEF("editors/animation/autorename_animation_tracks", true)))
return;
@@ -1279,9 +1279,9 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
_fill_path_renames(base_path, new_base_path, p_node, p_renames);
}
-void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath> > *p_renames, Map<Ref<Animation>, Set<int> > *r_rem_anims) {
+void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims) {
- Map<Ref<Animation>, Set<int> > rem_anims;
+ Map<Ref<Animation>, Set<int>> rem_anims;
if (!r_rem_anims)
r_rem_anims = &rem_anims;
@@ -1311,7 +1311,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
if (p.get_type() == Variant::NODE_PATH) {
// Goes through all paths to check if its matching
- for (List<Pair<NodePath, NodePath> >::Element *F = p_renames->front(); F; F = F->next()) {
+ for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
NodePath root_path = p_base->get_path();
@@ -1353,7 +1353,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
NodePath root_path = root->get_path();
NodePath new_root_path = root_path;
- for (List<Pair<NodePath, NodePath> >::Element *E = p_renames->front(); E; E = E->next()) {
+ for (List<Pair<NodePath, NodePath>>::Element *E = p_renames->front(); E; E = E->next()) {
if (E->get().first == root_path) {
new_root_path = E->get().second;
@@ -1392,7 +1392,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
if (!ran.has(i))
continue; //channel was removed
- for (List<Pair<NodePath, NodePath> >::Element *F = p_renames->front(); F; F = F->next()) {
+ for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) {
if (F->get().first == old_np) {
@@ -1443,7 +1443,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) {
- List<Pair<NodePath, NodePath> > path_renames;
+ List<Pair<NodePath, NodePath>> path_renames;
Vector<StringName> base_path;
Node *n = p_node->get_parent();
@@ -1466,7 +1466,7 @@ void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) {
for (int i = 0; i < p_node->get_child_count(); i++)
_fill_path_renames(base_path, new_base_path, p_node->get_child(i), &path_renames);
- perform_node_renames(NULL, &path_renames);
+ perform_node_renames(nullptr, &path_renames);
}
bool SceneTreeDock::_validate_no_foreign() {
@@ -1478,7 +1478,7 @@ bool SceneTreeDock::_validate_no_foreign() {
if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) {
accept->set_text(TTR("Can't operate on nodes from a foreign scene!"));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return false;
}
@@ -1492,7 +1492,7 @@ bool SceneTreeDock::_validate_no_foreign() {
if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) {
accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return false;
}
}
@@ -1535,7 +1535,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
if (p_nodes[ni] == p_new_parent)
return; // Attempt to reparent to itself.
- if (p_nodes[ni]->get_parent() != p_new_parent || p_position_in_parent + ni != p_nodes[ni]->get_position_in_parent())
+ if (p_nodes[ni]->get_parent() != p_new_parent || p_position_in_parent + ni != p_nodes[ni]->get_index())
no_change = false;
}
@@ -1554,7 +1554,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo().create_action(TTR("Reparent Node"));
- List<Pair<NodePath, NodePath> > path_renames;
+ List<Pair<NodePath, NodePath>> path_renames;
Vector<StringName> former_names;
int inc = 0;
@@ -1614,8 +1614,8 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
if (p_keep_global_xform) {
if (Object::cast_to<Node2D>(node))
editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform());
- if (Object::cast_to<Spatial>(node))
- editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Spatial>(node)->get_global_transform());
+ if (Object::cast_to<Node3D>(node))
+ editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform());
if (Object::cast_to<Control>(node))
editor_data->get_undo_redo().add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position());
}
@@ -1644,7 +1644,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
owners.push_back(E->get());
}
- int child_pos = node->get_position_in_parent();
+ int child_pos = node->get_index();
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node);
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, child_pos);
@@ -1655,14 +1655,14 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
if (p_keep_global_xform) {
if (Object::cast_to<Node2D>(node))
editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform());
- if (Object::cast_to<Spatial>(node))
- editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Spatial>(node)->get_transform());
+ if (Object::cast_to<Node3D>(node))
+ editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
if (Object::cast_to<Control>(node))
editor_data->get_undo_redo().add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
}
}
- perform_node_renames(NULL, &path_renames);
+ perform_node_renames(nullptr, &path_renames);
editor_data->get_undo_redo().commit_action();
}
@@ -1777,7 +1777,7 @@ void SceneTreeDock::_toggle_editable_children(Node *p_node) {
if (editable)
p_node->set_scene_instance_load_placeholder(false);
- SpatialEditor::get_singleton()->update_all_gizmos(p_node);
+ Node3DEditor::get_singleton()->update_all_gizmos(p_node);
scene_tree->update_tree();
}
@@ -1805,7 +1805,7 @@ void SceneTreeDock::_delete_confirm() {
if (entire_scene) {
- editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", (Object *)NULL);
+ editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", (Object *)nullptr);
editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", edited_scene);
editor_data->get_undo_redo().add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree");
@@ -1814,7 +1814,7 @@ void SceneTreeDock::_delete_confirm() {
} else {
remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions
- List<Pair<NodePath, NodePath> > path_renames;
+ List<Pair<NodePath, NodePath>> path_renames;
//delete from animation
for (List<Node *>::Element *E = remove_list.front(); E; E = E->next()) {
@@ -1822,10 +1822,10 @@ void SceneTreeDock::_delete_confirm() {
if (!n->is_inside_tree() || !n->get_parent())
continue;
- fill_path_renames(n, NULL, &path_renames);
+ fill_path_renames(n, nullptr, &path_renames);
}
- perform_node_renames(NULL, &path_renames);
+ perform_node_renames(nullptr, &path_renames);
//delete for read
for (List<Node *>::Element *E = remove_list.front(); E; E = E->next()) {
Node *n = E->get();
@@ -1859,7 +1859,7 @@ void SceneTreeDock::_delete_confirm() {
if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton())
editor->get_viewport_control()->update();
- editor->push_item(NULL);
+ editor->push_item(nullptr);
// Fixes the EditorHistory from still offering deleted notes
EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history();
@@ -1908,7 +1908,7 @@ void SceneTreeDock::_selection_changed() {
} else if (selection_size == 1) {
editor->push_item(EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list()[0]);
} else {
- editor->push_item(NULL);
+ editor->push_item(nullptr);
}
_update_script_button();
}
@@ -1918,7 +1918,7 @@ Node *SceneTreeDock::_get_selection_group_tail(Node *p_node, List<Node *> p_list
Node *tail = p_node;
Node *parent = tail->get_parent();
- for (int i = p_node->get_position_in_parent(); i < parent->get_child_count(); i++) {
+ for (int i = p_node->get_index(); i < parent->get_child_count(); i++) {
Node *sibling = parent->get_child(i);
if (p_list.find(sibling))
@@ -1958,7 +1958,7 @@ void SceneTreeDock::_do_create(Node *p_parent) {
editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
+ editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr);
}
editor_data->get_undo_redo().commit_action();
@@ -1982,7 +1982,7 @@ void SceneTreeDock::_create() {
if (current_option == TOOL_NEW) {
- Node *parent = NULL;
+ Node *parent = nullptr;
if (edited_scene) {
// If root exists in edited scene
@@ -2052,7 +2052,7 @@ void SceneTreeDock::_create() {
}
}
- Node *parent = NULL;
+ Node *parent = nullptr;
if (only_one_top_node)
parent = top_node->get_parent();
else
@@ -2096,7 +2096,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
memdelete(default_oldnode);
}
- editor->push_item(NULL);
+ editor->push_item(nullptr);
//reconnect signals
List<MethodInfo> sl;
@@ -2120,7 +2120,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
List<Node *> to_erase;
for (int i = 0; i < n->get_child_count(); i++) {
- if (n->get_child(i)->get_owner() == NULL && n->is_owned_by_parent()) {
+ if (n->get_child(i)->get_owner() == nullptr && n->is_owned_by_parent()) {
to_erase.push_back(n->get_child(i));
}
}
@@ -2187,13 +2187,13 @@ void SceneTreeDock::_new_scene_from(String p_file) {
if (selection.size() != 1) {
accept->set_text(TTR("This operation requires a single selected node."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
if (EditorNode::get_singleton()->is_scene_open(p_file)) {
accept->set_text(TTR("Can't overwrite scene that is still open!"));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
@@ -2210,7 +2210,7 @@ void SceneTreeDock::_new_scene_from(String p_file) {
if (err != OK) {
accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
@@ -2221,13 +2221,13 @@ void SceneTreeDock::_new_scene_from(String p_file) {
err = ResourceSaver::save(p_file, sdata, flg);
if (err != OK) {
accept->set_text(TTR("Error saving scene."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
_replace_with_branch_scene(p_file, base);
} else {
accept->set_text(TTR("Error duplicating scene to save it."));
- accept->popup_centered_minsize();
+ accept->popup_centered();
return;
}
}
@@ -2267,7 +2267,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
if (p_type == -1) {
//drop at above selected node
if (to_node == EditorNode::get_singleton()->get_edited_scene()) {
- to_node = NULL;
+ to_node = nullptr;
ERR_FAIL_MSG("Cannot perform drop above the root node!");
}
@@ -2282,7 +2282,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
return;
}
- Node *lower_sibling = NULL;
+ Node *lower_sibling = nullptr;
if (_has_visible_children(to_node)) {
to_pos = 0;
@@ -2346,7 +2346,7 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) {
int to_pos = -1;
_normalize_drop(to_node, to_pos, p_type);
- _do_reparent(to_node, to_pos, nodes, !Input::get_singleton()->is_key_pressed(KEY_SHIFT));
+ _do_reparent(to_node, to_pos, nodes, !InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT));
}
void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
@@ -2390,8 +2390,8 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->clear();
if (profile_allow_editing) {
- menu->add_icon_shortcut(get_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
- menu->add_icon_shortcut(get_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE);
+ menu->add_icon_shortcut(get_theme_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
+ menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE);
}
menu->set_size(Size2(1, 1));
@@ -2422,10 +2422,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (menu->get_item_count() > 0)
menu->add_separator();
- menu->add_icon_shortcut(get_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
- menu->add_icon_shortcut(get_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE);
+ menu->add_icon_shortcut(get_theme_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
+ menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE);
}
- menu->add_icon_shortcut(get_icon("Collapse", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE);
+ menu->add_icon_shortcut(get_theme_icon("Collapse", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE);
menu->add_separator();
existing_script = selected->get_script();
@@ -2440,14 +2440,14 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (full_selection.size() == 1) {
add_separator = true;
- menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ menu->add_icon_shortcut(get_theme_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
if (existing_script.is_valid()) {
- menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT);
+ menu->add_icon_shortcut(get_theme_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT);
}
}
if (existing_script.is_valid() && existing_script_removable) {
add_separator = true;
- menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
+ menu->add_icon_shortcut(get_theme_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
} else if (full_selection.size() > 1) {
bool script_exists = false;
for (List<Node *>::Element *E = full_selection.front(); E; E = E->next()) {
@@ -2459,7 +2459,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (script_exists) {
add_separator = true;
- menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
+ menu->add_icon_shortcut(get_theme_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
}
}
@@ -2470,19 +2470,19 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (profile_allow_editing) {
if (full_selection.size() == 1) {
- menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME);
+ menu->add_icon_shortcut(get_theme_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME);
}
- menu->add_icon_shortcut(get_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_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();
- menu->add_icon_shortcut(get_icon("MoveUp", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP);
- menu->add_icon_shortcut(get_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN);
- menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE);
- menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT);
- menu->add_icon_shortcut(get_icon("ReparentToNewNode", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE);
+ menu->add_icon_shortcut(get_theme_icon("MoveUp", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP);
+ menu->add_icon_shortcut(get_theme_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN);
+ menu->add_icon_shortcut(get_theme_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE);
+ menu->add_icon_shortcut(get_theme_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT);
+ menu->add_icon_shortcut(get_theme_icon("ReparentToNewNode", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE);
if (selection.size() == 1) {
- menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT);
+ menu->add_icon_shortcut(get_theme_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT);
}
}
}
@@ -2490,24 +2490,24 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (profile_allow_editing) {
menu->add_separator();
- menu->add_icon_shortcut(get_icon("Blend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/merge_from_scene"), TOOL_MERGE_FROM_SCENE);
- menu->add_icon_shortcut(get_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM);
+ 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) {
menu->add_separator();
- menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH);
+ menu->add_icon_shortcut(get_theme_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH);
}
bool is_external = (selection[0]->get_filename() != "");
if (is_external) {
- bool is_inherited = selection[0]->get_scene_inherited_state() != NULL;
- bool is_top_level = selection[0]->get_owner() == NULL;
+ bool is_inherited = selection[0]->get_scene_inherited_state() != nullptr;
+ bool is_top_level = selection[0]->get_owner() == nullptr;
if (is_inherited && is_top_level) {
menu->add_separator();
if (profile_allow_editing) {
menu->add_item(TTR("Clear Inheritance"), TOOL_SCENE_CLEAR_INHERITANCE);
}
- menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED);
+ menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED);
} else if (!is_top_level) {
menu->add_separator();
bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(selection[0]);
@@ -2517,7 +2517,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER);
menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL);
}
- menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN);
+ menu->add_icon_item(get_theme_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN);
if (profile_allow_editing) {
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable);
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder);
@@ -2529,14 +2529,14 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (profile_allow_editing && selection.size() > 1) {
//this is not a commonly used action, it makes no sense for it to be where it was nor always present.
menu->add_separator();
- menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME);
+ menu->add_icon_shortcut(get_theme_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME);
}
menu->add_separator();
- menu->add_icon_item(get_icon("Help", "EditorIcons"), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION);
+ menu->add_icon_item(get_theme_icon("Help", "EditorIcons"), TTR("Open Documentation"), TOOL_OPEN_DOCUMENTATION);
if (profile_allow_editing) {
menu->add_separator();
- menu->add_icon_shortcut(get_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE);
+ menu->add_icon_shortcut(get_theme_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE);
}
menu->set_size(Size2(1, 1));
menu->set_position(p_menu_pos);
@@ -2568,7 +2568,7 @@ void SceneTreeDock::_focus_node() {
CanvasItemEditorPlugin *editor = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor("2D"));
editor->get_canvas_item_editor()->focus_selection();
} else {
- SpatialEditorPlugin *editor = Object::cast_to<SpatialEditorPlugin>(editor_data->get_editor("3D"));
+ Node3DEditorPlugin *editor = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D"));
editor->get_spatial_editor()->get_editor_viewport(0)->focus_selection();
}
}
@@ -2634,7 +2634,7 @@ void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) {
}
void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {
- ERR_FAIL_COND(remote_tree != NULL);
+ ERR_FAIL_COND(remote_tree != nullptr);
add_child(p_remote);
remote_tree = p_remote;
remote_tree->hide();
@@ -2787,7 +2787,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
set_name("Scene");
editor = p_editor;
- edited_scene = NULL;
+ edited_scene = nullptr;
editor_data = &p_editor_data;
editor_selection = p_editor_selection;
scene_root = p_scene_root;
@@ -2795,7 +2795,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
VBoxContainer *vbc = this;
HBoxContainer *filter_hbc = memnew(HBoxContainer);
- filter_hbc->add_constant_override("separate", 0);
+ filter_hbc->add_theme_constant_override("separate", 0);
ED_SHORTCUT("scene_tree/rename", TTR("Rename"));
ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_CMD | KEY_F2);
@@ -2835,7 +2835,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_constant_override("minimum_spaces", 0);
+ filter->add_theme_constant_override("minimum_spaces", 0);
filter->connect("text_changed", callable_mp(this, &SceneTreeDock::_filter_changed));
button_create_script = memnew(ToolButton);
@@ -2869,7 +2869,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
edit_local->set_toggle_mode(true);
edit_local->connect("pressed", callable_mp(this, &SceneTreeDock::_local_tree_selected));
- remote_tree = NULL;
+ remote_tree = nullptr;
button_hb->hide();
create_root_dialog = memnew(VBoxContainer);
@@ -2939,14 +2939,14 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
import_subscene_dialog->connect("subscene_selected", callable_mp(this, &SceneTreeDock::_import_subscene));
new_scene_from_dialog = memnew(EditorFileDialog);
- new_scene_from_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ new_scene_from_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
add_child(new_scene_from_dialog);
new_scene_from_dialog->connect("file_selected", callable_mp(this, &SceneTreeDock::_new_scene_from));
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(false));
- menu->set_hide_on_window_lose_focus(true);
+
menu_subresources = memnew(PopupMenu);
menu_subresources->set_name("Sub-Resources");
menu_subresources->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(false));
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index c6ddbc3dfe..31ef1ce7d0 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -205,7 +205,7 @@ class SceneTreeDock : public VBoxContainer {
void _update_script_button();
Node *_get_selection_group_tail(Node *p_node, List<Node *> p_list);
- void _fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, List<Pair<NodePath, NodePath> > *p_renames);
+ void _fill_path_renames(Vector<StringName> base_path, Vector<StringName> new_base_path, Node *p_node, List<Pair<NodePath, NodePath>> *p_renames);
void _normalize_drop(Node *&to_node, int &to_pos, int p_type);
@@ -247,10 +247,10 @@ public:
void import_subscene();
void set_edited_scene(Node *p_scene);
void instance(const String &p_file);
- void instance_scenes(const Vector<String> &p_files, Node *p_parent = NULL);
+ void instance_scenes(const Vector<String> &p_files, Node *p_parent = nullptr);
void set_selected(Node *p_node, bool p_emit_selected = false);
- void fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath> > *p_renames);
- void perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath> > *p_renames, Map<Ref<Animation>, Set<int> > *r_rem_anims = NULL);
+ void fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath>> *p_renames);
+ void perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims = nullptr);
SceneTreeEditor *get_tree_editor() { return scene_tree; }
EditorData *get_editor_data() { return editor_data; }
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index e4e642e368..251c911038 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -37,12 +37,12 @@
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/gui/label.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
Node *SceneTreeEditor::get_scene_node() {
- ERR_FAIL_COND_V(!is_inside_tree(), NULL);
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
return get_tree()->get_edited_scene_root();
}
@@ -78,7 +78,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
undo_redo->create_action(TTR("Toggle Visible"));
_toggle_visible(n);
List<Node *> selection = editor_selection->get_selected_node_list();
- if (selection.size() > 1 && selection.find(n) != NULL) {
+ if (selection.size() > 1 && selection.find(n) != nullptr) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node *nv = E->get();
ERR_FAIL_COND(!nv);
@@ -92,7 +92,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
} else if (p_id == BUTTON_LOCK) {
undo_redo->create_action(TTR("Unlock Node"));
- if (n->is_class("CanvasItem") || n->is_class("Spatial")) {
+ if (n->is_class("CanvasItem") || n->is_class("Node3D")) {
undo_redo->add_do_method(n, "remove_meta", "_edit_lock_");
undo_redo->add_undo_method(n, "set_meta", "_edit_lock_", true);
@@ -112,7 +112,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
} else if (p_id == BUTTON_GROUP) {
undo_redo->create_action(TTR("Button Group"));
- if (n->is_class("CanvasItem") || n->is_class("Spatial")) {
+ if (n->is_class("CanvasItem") || n->is_class("Node3D")) {
undo_redo->add_do_method(n, "remove_meta", "_edit_group_");
undo_redo->add_undo_method(n, "set_meta", "_edit_group_", true);
@@ -129,7 +129,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
return;
config_err = config_err.word_wrap(80);
warning->set_text(config_err);
- warning->popup_centered_minsize();
+ warning->popup_centered();
} else if (p_id == BUTTON_SIGNALS) {
@@ -201,19 +201,19 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->set_metadata(0, p_node->get_path());
if (connect_to_script_mode) {
- Color accent = get_color("accent_color", "Editor");
+ Color accent = get_theme_color("accent_color", "Editor");
Ref<Script> script = p_node->get_script();
if (!script.is_null() && EditorNode::get_singleton()->get_object_custom_type_base(p_node) != script) {
//has script
- item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
+ item->add_button(0, get_theme_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
} else {
//has no script (or script is a custom type)
- item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
+ item->set_custom_color(0, get_theme_color("disabled_font_color", "Editor"));
item->set_selectable(0, false);
if (!script.is_null()) { // make sure to mark the script if a custom type
- item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
+ item->add_button(0, get_theme_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
item->set_button_disabled(0, item->get_button_count(0) - 1, true);
}
@@ -231,7 +231,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
} else if (part_of_subscene) {
if (valid_types.size() == 0) {
- item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
+ item->set_custom_color(0, get_theme_color("disabled_font_color", "Editor"));
}
} else if (marked.has(p_node)) {
@@ -241,14 +241,14 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
item->set_text(0, node_name);
item->set_selectable(0, marked_selectable);
- item->set_custom_color(0, get_color("accent_color", "Editor"));
+ item->set_custom_color(0, get_theme_color("accent_color", "Editor"));
} else if (!marked_selectable && !marked_children_selectable) {
Node *node = p_node;
while (node) {
if (marked.has(node)) {
item->set_selectable(0, false);
- item->set_custom_color(0, get_color("error_color", "Editor"));
+ item->set_custom_color(0, get_theme_color("error_color", "Editor"));
break;
}
node = node->get_parent();
@@ -259,7 +259,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
String warning = p_node->get_configuration_warning();
if (warning != String()) {
- item->add_button(0, get_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" + p_node->get_configuration_warning());
}
int num_connections = p_node->get_persistent_signal_connection_count();
@@ -268,21 +268,21 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
if (num_connections >= 1 && num_groups >= 1) {
item->add_button(
0,
- get_icon("SignalsAndGroups", "EditorIcons"),
+ get_theme_icon("SignalsAndGroups", "EditorIcons"),
BUTTON_SIGNALS,
false,
vformat(TTR("Node has %s connection(s) and %s group(s).\nClick to show signals dock."), num_connections, num_groups));
} else if (num_connections >= 1) {
item->add_button(
0,
- get_icon("Signals", "EditorIcons"),
+ get_theme_icon("Signals", "EditorIcons"),
BUTTON_SIGNALS,
false,
vformat(TTR("Node has %s connection(s).\nClick to show signals dock."), num_connections));
} else if (num_groups >= 1) {
item->add_button(
0,
- get_icon("Groups", "EditorIcons"),
+ get_theme_icon("Groups", "EditorIcons"),
BUTTON_GROUPS,
false,
vformat(TTR("Node is in %s group(s).\nClick to show groups dock."), num_groups));
@@ -290,7 +290,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
- item->add_button(0, get_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
+ item->add_button(0, get_theme_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
String tooltip = TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path() + "\n" + TTR("Type:") + " " + p_node->get_class();
if (p_node->get_editor_description() != String()) {
@@ -299,7 +299,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->set_tooltip(0, tooltip);
} else if (p_node != get_scene_node() && p_node->get_filename() != "" && can_open_instance) {
- item->add_button(0, get_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
+ item->add_button(0, get_theme_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
String tooltip = TTR("Instance:") + " " + p_node->get_filename() + "\n" + TTR("Type:") + " " + p_node->get_class();
if (p_node->get_editor_description() != String()) {
@@ -328,7 +328,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
Ref<Script> script = p_node->get_script();
if (!script.is_null()) {
- item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path());
+ item->add_button(0, get_theme_icon("Script", "EditorIcons"), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path());
if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) {
item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5));
}
@@ -338,37 +338,37 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
bool is_locked = p_node->has_meta("_edit_lock_"); //_edit_group_
if (is_locked)
- item->add_button(0, get_icon("Lock", "EditorIcons"), BUTTON_LOCK, false, TTR("Node is locked.\nClick to unlock it."));
+ item->add_button(0, get_theme_icon("Lock", "EditorIcons"), BUTTON_LOCK, false, TTR("Node is locked.\nClick to unlock it."));
bool is_grouped = p_node->has_meta("_edit_group_");
if (is_grouped)
- item->add_button(0, get_icon("Group", "EditorIcons"), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+ item->add_button(0, get_theme_icon("Group", "EditorIcons"), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
bool v = p_node->call("is_visible");
if (v)
- item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
+ item->add_button(0, get_theme_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
else
- item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
+ item->add_button(0, get_theme_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
if (!p_node->is_connected("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed)))
p_node->connect("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed), varray(p_node));
_update_visibility_color(p_node, item);
- } else if (p_node->is_class("Spatial")) {
+ } else if (p_node->is_class("Node3D")) {
bool is_locked = p_node->has_meta("_edit_lock_");
if (is_locked)
- item->add_button(0, get_icon("Lock", "EditorIcons"), BUTTON_LOCK, false, TTR("Node is locked.\nClick to unlock it."));
+ item->add_button(0, get_theme_icon("Lock", "EditorIcons"), BUTTON_LOCK, false, TTR("Node is locked.\nClick to unlock it."));
bool is_grouped = p_node->has_meta("_edit_group_");
if (is_grouped)
- item->add_button(0, get_icon("Group", "EditorIcons"), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+ item->add_button(0, get_theme_icon("Group", "EditorIcons"), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
bool v = p_node->call("is_visible");
if (v)
- item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
+ item->add_button(0, get_theme_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
else
- item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
+ item->add_button(0, get_theme_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
if (!p_node->is_connected("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed)))
p_node->connect("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed), varray(p_node));
@@ -379,7 +379,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
bool is_pinned = AnimationPlayerEditor::singleton->get_player() == p_node && AnimationPlayerEditor::singleton->is_pinned();
if (is_pinned) {
- item->add_button(0, get_icon("Pin", "EditorIcons"), BUTTON_PIN, false, TTR("AnimationPlayer is pinned.\nClick to unpin."));
+ item->add_button(0, get_theme_icon("Pin", "EditorIcons"), BUTTON_PIN, false, TTR("AnimationPlayer is pinned.\nClick to unpin."));
}
}
}
@@ -417,7 +417,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
if (!valid) {
//item->set_selectable(0,marked_selectable);
- item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
+ item->set_custom_color(0, get_theme_color("disabled_font_color", "Editor"));
item->set_selectable(0, false);
}
}
@@ -457,20 +457,20 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
if (p_node->is_class("CanvasItem")) {
visible = p_node->call("is_visible");
CanvasItemEditor::get_singleton()->get_viewport_control()->update();
- } else if (p_node->is_class("Spatial")) {
+ } else if (p_node->is_class("Node3D")) {
visible = p_node->call("is_visible");
}
if (visible)
- item->set_button(0, idx, get_icon("GuiVisibilityVisible", "EditorIcons"));
+ item->set_button(0, idx, get_theme_icon("GuiVisibilityVisible", "EditorIcons"));
else
- item->set_button(0, idx, get_icon("GuiVisibilityHidden", "EditorIcons"));
+ item->set_button(0, idx, get_theme_icon("GuiVisibilityHidden", "EditorIcons"));
_update_visibility_color(p_node, item);
}
void SceneTreeEditor::_update_visibility_color(Node *p_node, TreeItem *p_item) {
- if (p_node->is_class("CanvasItem") || p_node->is_class("Spatial")) {
+ if (p_node->is_class("CanvasItem") || p_node->is_class("Node3D")) {
Color color(1, 1, 1, 1);
bool visible_on_screen = p_node->call("is_visible_in_tree");
if (!visible_on_screen) {
@@ -498,13 +498,13 @@ void SceneTreeEditor::_node_removed(Node *p_node) {
if (p_node->is_connected("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed)))
p_node->disconnect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed));
- if (p_node->is_class("Spatial") || p_node->is_class("CanvasItem")) {
+ if (p_node->is_class("Node3D") || p_node->is_class("CanvasItem")) {
if (p_node->is_connected("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed)))
p_node->disconnect("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed));
}
if (p_node == selected) {
- selected = NULL;
+ selected = nullptr;
emit_signal("node_selected");
}
}
@@ -529,7 +529,7 @@ void SceneTreeEditor::_update_tree() {
updating_tree = true;
tree->clear();
if (get_scene_node()) {
- _add_nodes(get_scene_node(), NULL);
+ _add_nodes(get_scene_node(), nullptr);
last_hash = hash_djb2_one_64(0);
_compute_hash(get_scene_node(), last_hash);
}
@@ -667,7 +667,7 @@ void SceneTreeEditor::_notification(int p_what) {
TreeItem *SceneTreeEditor::_find(TreeItem *p_node, const NodePath &p_path) {
if (!p_node)
- return NULL;
+ return nullptr;
NodePath np = p_node->get_metadata(0);
if (np == p_path)
@@ -682,7 +682,7 @@ TreeItem *SceneTreeEditor::_find(TreeItem *p_node, const NodePath &p_path) {
children = children->get_next();
}
- return NULL;
+ return nullptr;
}
void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
@@ -697,7 +697,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
if (selected == p_node)
return;
- TreeItem *item = p_node ? _find(tree->get_root(), p_node->get_path()) : NULL;
+ TreeItem *item = p_node ? _find(tree->get_root(), p_node->get_path()) : nullptr;
if (item) {
// make visible when it's collapsed
@@ -713,7 +713,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
} else {
if (!p_node)
- selected = NULL;
+ selected = nullptr;
_update_tree();
selected = p_node;
}
@@ -757,7 +757,7 @@ void SceneTreeEditor::_renamed() {
if (!Node::_validate_node_name(new_name)) {
error->set_text(TTR("Invalid node name, the following characters are not allowed:") + "\n" + Node::invalid_character);
- error->popup_centered_minsize();
+ error->popup_centered();
if (new_name.empty()) {
which->set_text(0, n->get_name());
@@ -905,8 +905,8 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
return Variant(); //not editable tree
Vector<Node *> selected;
- Vector<Ref<Texture2D> > icons;
- TreeItem *next = tree->get_next_selected(NULL);
+ Vector<Ref<Texture2D>> icons;
+ TreeItem *next = tree->get_next_selected(nullptr);
while (next) {
NodePath np = next->get_metadata(0);
@@ -1117,16 +1117,16 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
connect_to_script_mode = false;
connecting_signal = false;
- undo_redo = NULL;
+ undo_redo = nullptr;
tree_dirty = true;
- selected = NULL;
+ selected = nullptr;
marked_selectable = false;
marked_children_selectable = false;
can_rename = p_can_rename;
can_open_instance = p_can_open_instance;
display_foreign = false;
- editor_selection = NULL;
+ editor_selection = nullptr;
if (p_label) {
Label *label = memnew(Label);
@@ -1141,7 +1141,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
tree->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
tree->set_begin(Point2(0, p_label ? 18 : 0));
tree->set_end(Point2(0, 0));
- tree->add_constant_override("button_margin", 0);
+ tree->add_theme_constant_override("button_margin", 0);
add_child(tree);
@@ -1193,18 +1193,19 @@ SceneTreeEditor::~SceneTreeEditor() {
void SceneTreeDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ if (is_visible())
+ tree->update_tree();
+ } break;
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", callable_mp(this, &SceneTreeDialog::_select));
- filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_right_icon(tree->get_theme_icon("Search", "EditorIcons"));
filter->set_clear_button_enabled(true);
} break;
case NOTIFICATION_EXIT_TREE: {
disconnect("confirmed", callable_mp(this, &SceneTreeDialog::_select));
} break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible_in_tree())
- tree->update_tree();
- } break;
}
}
@@ -1239,14 +1240,14 @@ SceneTreeDialog::SceneTreeDialog() {
add_child(vbc);
filter = memnew(LineEdit);
- filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->set_placeholder(TTR("Filter nodes"));
- filter->add_constant_override("minimum_spaces", 0);
+ filter->add_theme_constant_override("minimum_spaces", 0);
filter->connect("text_changed", callable_mp(this, &SceneTreeDialog::_filter_changed));
vbc->add_child(filter);
tree = memnew(SceneTreeEditor(false, false, true));
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->get_scene_tree()->connect("item_activated", callable_mp(this, &SceneTreeDialog::_select));
vbc->add_child(tree);
}
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index eb133abcd5..12b21d871b 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -40,36 +40,38 @@
#include "editor/editor_scale.h"
#include "editor_file_system.h"
-void ScriptCreateDialog::_notification(int p_what) {
+void ScriptCreateDialog::_theme_changed() {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ String lang = ScriptServer::get_language(i)->get_type();
+ Ref<Texture2D> lang_icon = gc->get_theme_icon(lang, "EditorIcons");
+ if (lang_icon.is_valid()) {
+ language_menu->set_item_icon(i, lang_icon);
+ }
+ }
- switch (p_what) {
- case NOTIFICATION_THEME_CHANGED:
- case NOTIFICATION_ENTER_TREE: {
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- String lang = ScriptServer::get_language(i)->get_type();
- Ref<Texture2D> lang_icon = get_icon(lang, "EditorIcons");
- if (lang_icon.is_valid()) {
- language_menu->set_item_icon(i, lang_icon);
- }
+ String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", "");
+ if (!last_lang.empty()) {
+ for (int i = 0; i < language_menu->get_item_count(); i++) {
+ if (language_menu->get_item_text(i) == last_lang) {
+ language_menu->select(i);
+ current_language = i;
+ break;
}
+ }
+ } else {
+ language_menu->select(default_language);
+ }
- String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", "");
- if (!last_lang.empty()) {
- for (int i = 0; i < language_menu->get_item_count(); i++) {
- if (language_menu->get_item_text(i) == last_lang) {
- language_menu->select(i);
- current_language = i;
- break;
- }
- }
- } else {
- language_menu->select(default_language);
- }
+ path_button->set_icon(gc->get_theme_icon("Folder", "EditorIcons"));
+ parent_browse_button->set_icon(gc->get_theme_icon("Folder", "EditorIcons"));
+ parent_search_button->set_icon(gc->get_theme_icon("ClassList", "EditorIcons"));
+ status_panel->add_theme_style_override("panel", gc->get_theme_stylebox("bg", "Tree"));
+}
+void ScriptCreateDialog::_notification(int p_what) {
- path_button->set_icon(get_icon("Folder", "EditorIcons"));
- parent_browse_button->set_icon(get_icon("Folder", "EditorIcons"));
- parent_search_button->set_icon(get_icon("ClassList", "EditorIcons"));
- status_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _theme_changed();
} break;
}
}
@@ -419,7 +421,7 @@ void ScriptCreateDialog::_lang_changed(int l) {
templates[i].id = new_id;
}
// Disable overridden
- for (Map<String, Vector<int> >::Element *E = template_overrides.front(); E; E = E->next()) {
+ for (Map<String, Vector<int>>::Element *E = template_overrides.front(); E; E = E->next()) {
const Vector<int> &overrides = E->get();
if (overrides.size() == 1) {
@@ -442,7 +444,7 @@ void ScriptCreateDialog::_lang_changed(int l) {
override_info += ", ";
}
}
- template_menu->set_item_icon(extended.id, get_icon("Override", "EditorIcons"));
+ template_menu->set_item_icon(extended.id, gc->get_theme_icon("Override", "EditorIcons"));
template_menu->get_popup()->set_item_tooltip(extended.id, override_info.as_string());
}
// Reselect last selected template
@@ -517,11 +519,11 @@ void ScriptCreateDialog::_browse_path(bool browse_parent, bool p_save) {
is_browsing_parent = browse_parent;
if (p_save) {
- file_browse->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_browse->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_browse->set_title(TTR("Open Script / Choose Location"));
file_browse->get_ok()->set_text(TTR("Open"));
} else {
- file_browse->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_browse->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_browse->set_title(TTR("Open Script"));
}
@@ -607,9 +609,9 @@ void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) {
error_label->set_text("- " + TTR(p_msg));
if (valid) {
- error_label->add_color_override("font_color", get_color("success_color", "Editor"));
+ error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor"));
} else {
- error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor"));
}
}
@@ -617,9 +619,9 @@ void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) {
path_error_label->set_text("- " + TTR(p_msg));
if (valid) {
- path_error_label->add_color_override("font_color", get_color("success_color", "Editor"));
+ path_error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor"));
} else {
- path_error_label->add_color_override("font_color", get_color("error_color", "Editor"));
+ path_error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor"));
}
}
@@ -687,6 +689,8 @@ void ScriptCreateDialog::_update_dialog() {
// Is Script created or loaded from existing file?
+ builtin_warning_label->set_visible(is_built_in);
+
if (is_built_in) {
get_ok()->set_text(TTR("Create"));
parent_name->set_editable(true);
@@ -739,9 +743,11 @@ ScriptCreateDialog::ScriptCreateDialog() {
/* Main Controls */
- GridContainer *gc = memnew(GridContainer);
+ gc = memnew(GridContainer);
gc->set_columns(2);
+ gc->connect("theme_changed", callable_mp(this, &ScriptCreateDialog::_theme_changed));
+
/* Error Messages Field */
VBoxContainer *vb = memnew(VBoxContainer);
@@ -752,6 +758,13 @@ ScriptCreateDialog::ScriptCreateDialog() {
path_error_label = memnew(Label);
vb->add_child(path_error_label);
+ builtin_warning_label = memnew(Label);
+ builtin_warning_label->set_text(
+ TTR("Note: Built-in scripts have some limitations and can't be edited using an external editor."));
+ vb->add_child(builtin_warning_label);
+ builtin_warning_label->set_autowrap(true);
+ builtin_warning_label->hide();
+
status_panel = memnew(PanelContainer);
status_panel->set_h_size_flags(Control::SIZE_FILL);
status_panel->add_child(vb);
@@ -774,7 +787,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
language_menu = memnew(OptionButton);
language_menu->set_custom_minimum_size(Size2(250, 0) * EDSCALE);
- language_menu->set_h_size_flags(SIZE_EXPAND_FILL);
+ language_menu->set_h_size_flags(Control::SIZE_EXPAND_FILL);
gc->add_child(memnew(Label(TTR("Language:"))));
gc->add_child(language_menu);
@@ -798,10 +811,10 @@ ScriptCreateDialog::ScriptCreateDialog() {
base_type = "Object";
hb = memnew(HBoxContainer);
- hb->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
parent_name = memnew(LineEdit);
parent_name->connect("text_changed", callable_mp(this, &ScriptCreateDialog::_parent_name_changed));
- parent_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ parent_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(parent_name);
parent_search_button = memnew(Button);
parent_search_button->set_flat(true);
@@ -819,7 +832,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
class_name = memnew(LineEdit);
class_name->connect("text_changed", callable_mp(this, &ScriptCreateDialog::_class_name_changed));
- class_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ class_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
gc->add_child(memnew(Label(TTR("Class Name:"))));
gc->add_child(class_name);
@@ -845,7 +858,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
file_path = memnew(LineEdit);
file_path->connect("text_changed", callable_mp(this, &ScriptCreateDialog::_path_changed));
file_path->connect("text_entered", callable_mp(this, &ScriptCreateDialog::_path_entered));
- file_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ file_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(file_path);
path_button = memnew(Button);
path_button->set_flat(true);
@@ -863,18 +876,16 @@ ScriptCreateDialog::ScriptCreateDialog() {
file_browse = memnew(EditorFileDialog);
file_browse->connect("file_selected", callable_mp(this, &ScriptCreateDialog::_file_selected));
- file_browse->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_browse->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
add_child(file_browse);
get_ok()->set_text(TTR("Create"));
alert = memnew(AcceptDialog);
- alert->set_as_minsize();
alert->get_label()->set_autowrap(true);
alert->get_label()->set_align(Label::ALIGN_CENTER);
alert->get_label()->set_valign(Label::VALIGN_CENTER);
alert->get_label()->set_custom_minimum_size(Size2(325, 60) * EDSCALE);
add_child(alert);
- set_as_minsize();
set_hide_on_ok(false);
set_title(TTR("Attach Node Script"));
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index 00f642fcf7..63a30eba88 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -45,9 +45,11 @@ class CreateDialog;
class ScriptCreateDialog : public ConfirmationDialog {
GDCLASS(ScriptCreateDialog, ConfirmationDialog);
+ GridContainer *gc;
LineEdit *class_name;
Label *error_label;
Label *path_error_label;
+ Label *builtin_warning_label;
PanelContainer *status_panel;
LineEdit *parent_name;
Button *parent_browse_button;
@@ -93,7 +95,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
String script_template;
Vector<ScriptTemplateInfo> template_list;
- Map<String, Vector<int> > template_overrides; // name : indices
+ Map<String, Vector<int>> template_overrides; // name : indices
void _update_script_templates(const String &p_extension);
@@ -123,6 +125,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
void _update_dialog();
protected:
+ void _theme_changed();
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index cf93fab9a8..8910e8ec3a 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -118,18 +118,20 @@ void EditorSettingsDialog::_undo_redo_callback(void *p_self, const String &p_nam
void EditorSettingsDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible()) {
+ EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "editor_settings", Rect2(get_position(), get_size()));
+ set_process_unhandled_input(false);
+ }
+ } break;
case NOTIFICATION_READY: {
- undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, NULL);
- undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, NULL);
+ undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
+ undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
} break;
case NOTIFICATION_ENTER_TREE: {
_update_icons();
} break;
- case NOTIFICATION_POPUP_HIDE: {
- EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "editor_settings", get_rect());
- set_process_unhandled_input(false);
- } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
_update_icons();
// Update theme colors.
@@ -143,7 +145,7 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventKey> k = p_event;
- if (k.is_valid() && is_window_modal_on_top() && k->is_pressed()) {
+ if (k.is_valid() && k->is_pressed()) {
bool handled = false;
@@ -169,22 +171,22 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
}
if (handled) {
- accept_event();
+ set_input_as_handled();
}
}
}
void EditorSettingsDialog::_update_icons() {
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(shortcuts->get_theme_icon("Search", "EditorIcons"));
search_box->set_clear_button_enabled(true);
- shortcut_search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ shortcut_search_box->set_right_icon(shortcuts->get_theme_icon("Search", "EditorIcons"));
shortcut_search_box->set_clear_button_enabled(true);
- restart_close_button->set_icon(get_icon("Close", "EditorIcons"));
- restart_container->add_style_override("panel", get_stylebox("bg", "Tree"));
- restart_icon->set_texture(get_icon("StatusWarning", "EditorIcons"));
- restart_label->add_color_override("font_color", get_color("warning_color", "Editor"));
+ restart_close_button->set_icon(shortcuts->get_theme_icon("Close", "EditorIcons"));
+ restart_container->add_theme_style_override("panel", shortcuts->get_theme_stylebox("bg", "Tree"));
+ restart_icon->set_texture(shortcuts->get_theme_icon("StatusWarning", "EditorIcons"));
+ restart_label->add_theme_color_override("font_color", shortcuts->get_theme_color("warning_color", "Editor"));
}
void EditorSettingsDialog::_update_shortcuts() {
@@ -230,8 +232,8 @@ void EditorSettingsDialog::_update_shortcuts() {
}
sections[section_name] = section;
- section->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
- section->set_custom_bg_color(1, get_color("prop_subsection", "Editor"));
+ section->set_custom_bg_color(0, shortcuts->get_theme_color("prop_subsection", "Editor"));
+ section->set_custom_bg_color(1, shortcuts->get_theme_color("prop_subsection", "Editor"));
}
// Don't match unassigned shortcuts when searching for assigned keys in search results.
@@ -243,16 +245,16 @@ void EditorSettingsDialog::_update_shortcuts() {
item->set_text(1, sc->get_as_text());
if (!sc->is_shortcut(original) && !(sc->get_shortcut().is_null() && original.is_null())) {
- item->add_button(1, get_icon("Reload", "EditorIcons"), 2);
+ item->add_button(1, shortcuts->get_theme_icon("Reload", "EditorIcons"), 2);
}
if (sc->get_as_text() == "None") {
// Fade out unassigned shortcut labels for easier visual grepping.
- item->set_custom_color(1, get_color("font_color", "Label") * Color(1, 1, 1, 0.5));
+ item->set_custom_color(1, shortcuts->get_theme_color("font_color", "Label") * Color(1, 1, 1, 0.5));
}
- item->add_button(1, get_icon("Edit", "EditorIcons"), 0);
- item->add_button(1, get_icon("Close", "EditorIcons"), 1);
+ 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, E->get());
item->set_metadata(0, E->get());
}
@@ -261,7 +263,7 @@ void EditorSettingsDialog::_update_shortcuts() {
// remove sections with no shortcuts
for (Map<String, TreeItem *>::Element *E = sections.front(); E; E = E->next()) {
TreeItem *section = E->get();
- if (section->get_children() == NULL) {
+ if (section->get_children() == nullptr) {
root->remove_child(section);
}
}
@@ -279,9 +281,9 @@ void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column
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()->set_focus_mode(FOCUS_NONE);
- press_a_key->get_cancel()->set_focus_mode(FOCUS_NONE);
+ //press_a_key->grab_focus();
+ press_a_key->get_ok()->set_focus_mode(Control::FOCUS_NONE);
+ press_a_key->get_cancel()->set_focus_mode(Control::FOCUS_NONE);
shortcut_configured = item;
} else if (p_idx == 1) { //erase
@@ -323,7 +325,7 @@ void EditorSettingsDialog::_wait_for_key(const Ref<InputEvent> &p_event) {
const String str = keycode_get_string(k->get_keycode_with_modifiers());
press_a_key_label->set_text(str);
- press_a_key->accept_event();
+ press_a_key->set_input_as_handled();
}
}
@@ -360,7 +362,7 @@ void EditorSettingsDialog::_tabs_tab_changed(int p_tab) {
void EditorSettingsDialog::_focus_current_search_box() {
Control *tab = tabs->get_current_tab_control();
- LineEdit *current_search_box = NULL;
+ LineEdit *current_search_box = nullptr;
if (tab == tab_general)
current_search_box = search_box;
else if (tab == tab_shortcuts)
@@ -394,7 +396,7 @@ void EditorSettingsDialog::_bind_methods() {
EditorSettingsDialog::EditorSettingsDialog() {
set_title(TTR("Editor Settings"));
- set_resizable(true);
+
undo_redo = memnew(UndoRedo);
tabs = memnew(TabContainer);
@@ -430,7 +432,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
HBoxContainer *restart_hb = memnew(HBoxContainer);
restart_container->add_child(restart_hb);
restart_icon = memnew(TextureRect);
- restart_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
+ restart_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
restart_hb->add_child(restart_icon);
restart_label = memnew(Label);
restart_label->set_text(TTR("The editor must be restarted for changes to take effect."));
@@ -462,7 +464,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcuts = memnew(Tree);
tab_shortcuts->add_child(shortcuts, true);
- shortcuts->set_v_size_flags(SIZE_EXPAND_FILL);
+ shortcuts->set_v_size_flags(Control::SIZE_EXPAND_FILL);
shortcuts->set_columns(2);
shortcuts->set_hide_root(true);
shortcuts->set_column_titles_visible(true);
@@ -471,7 +473,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcuts->connect("button_pressed", callable_mp(this, &EditorSettingsDialog::_shortcut_button_pressed));
press_a_key = memnew(ConfirmationDialog);
- press_a_key->set_focus_mode(FOCUS_ALL);
+ //press_a_key->set_focus_mode(Control::FOCUS_ALL);
add_child(press_a_key);
Label *l = memnew(Label);
@@ -479,10 +481,10 @@ EditorSettingsDialog::EditorSettingsDialog() {
l->set_anchors_and_margins_preset(Control::PRESET_WIDE);
l->set_align(Label::ALIGN_CENTER);
l->set_margin(MARGIN_TOP, 20);
- l->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_BEGIN, 30);
+ l->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_BEGIN, 30);
press_a_key_label = l;
press_a_key->add_child(l);
- press_a_key->connect("gui_input", callable_mp(this, &EditorSettingsDialog::_wait_for_key));
+ 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));
set_hide_on_ok(true);
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
deleted file mode 100644
index d6e443ec14..0000000000
--- a/editor/spatial_editor_gizmos.cpp
+++ /dev/null
@@ -1,4510 +0,0 @@
-/*************************************************************************/
-/* spatial_editor_gizmos.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "spatial_editor_gizmos.h"
-
-#include "core/math/geometry.h"
-#include "core/math/quick_hull.h"
-#include "scene/3d/audio_stream_player_3d.h"
-#include "scene/3d/baked_lightmap.h"
-#include "scene/3d/collision_polygon.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/cpu_particles.h"
-#include "scene/3d/gi_probe.h"
-#include "scene/3d/light.h"
-#include "scene/3d/listener.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/navigation_region.h"
-#include "scene/3d/particles.h"
-#include "scene/3d/physics_joint.h"
-#include "scene/3d/position_3d.h"
-#include "scene/3d/ray_cast.h"
-#include "scene/3d/reflection_probe.h"
-#include "scene/3d/soft_body.h"
-#include "scene/3d/spring_arm.h"
-#include "scene/3d/sprite_3d.h"
-#include "scene/3d/vehicle_body.h"
-#include "scene/3d/visibility_notifier.h"
-#include "scene/resources/box_shape.h"
-#include "scene/resources/capsule_shape.h"
-#include "scene/resources/concave_polygon_shape.h"
-#include "scene/resources/convex_polygon_shape.h"
-#include "scene/resources/cylinder_shape.h"
-#include "scene/resources/height_map_shape.h"
-#include "scene/resources/primitive_meshes.h"
-#include "scene/resources/ray_shape.h"
-#include "scene/resources/sphere_shape.h"
-#include "scene/resources/surface_tool.h"
-#include "scene/resources/world_margin_shape.h"
-
-#define HANDLE_HALF_SIZE 9.5
-
-bool EditorSpatialGizmo::is_editable() const {
-
- ERR_FAIL_COND_V(!spatial_node, false);
- Node *edited_root = spatial_node->get_tree()->get_edited_scene_root();
- if (spatial_node == edited_root)
- return true;
- if (spatial_node->get_owner() == edited_root)
- return true;
-
- if (edited_root->is_editable_instance(spatial_node->get_owner()))
- return true;
-
- return false;
-}
-
-void EditorSpatialGizmo::clear() {
-
- for (int i = 0; i < instances.size(); i++) {
-
- if (instances[i].instance.is_valid())
- VS::get_singleton()->free(instances[i].instance);
- }
-
- billboard_handle = false;
- collision_segments.clear();
- collision_mesh = Ref<TriangleMesh>();
- instances.clear();
- handles.clear();
- secondary_handles.clear();
-}
-
-void EditorSpatialGizmo::redraw() {
-
- if (get_script_instance() && get_script_instance()->has_method("redraw")) {
- get_script_instance()->call("redraw");
- return;
- }
-
- ERR_FAIL_COND(!gizmo_plugin);
- gizmo_plugin->redraw(this);
-}
-
-String EditorSpatialGizmo::get_handle_name(int p_idx) const {
-
- if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) {
- return get_script_instance()->call("get_handle_name", p_idx);
- }
-
- ERR_FAIL_COND_V(!gizmo_plugin, "");
- return gizmo_plugin->get_handle_name(this, p_idx);
-}
-
-bool EditorSpatialGizmo::is_handle_highlighted(int p_idx) const {
-
- if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) {
- return get_script_instance()->call("is_handle_highlighted", p_idx);
- }
-
- ERR_FAIL_COND_V(!gizmo_plugin, false);
- return gizmo_plugin->is_handle_highlighted(this, p_idx);
-}
-
-Variant EditorSpatialGizmo::get_handle_value(int p_idx) {
-
- if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) {
- return get_script_instance()->call("get_handle_value", p_idx);
- }
-
- ERR_FAIL_COND_V(!gizmo_plugin, Variant());
- return gizmo_plugin->get_handle_value(this, p_idx);
-}
-
-void EditorSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- if (get_script_instance() && get_script_instance()->has_method("set_handle")) {
- get_script_instance()->call("set_handle", p_idx, p_camera, p_point);
- return;
- }
-
- ERR_FAIL_COND(!gizmo_plugin);
- gizmo_plugin->set_handle(this, p_idx, p_camera, p_point);
-}
-
-void EditorSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
-
- if (get_script_instance() && get_script_instance()->has_method("commit_handle")) {
- get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel);
- return;
- }
-
- ERR_FAIL_COND(!gizmo_plugin);
- gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel);
-}
-
-void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) {
-
- ERR_FAIL_NULL(p_node);
- spatial_node = p_node;
-}
-
-void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base, bool p_hidden) {
-
- instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario());
- VS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id());
- if (skin_reference.is_valid()) {
- VS::get_singleton()->instance_attach_skeleton(instance, skin_reference->get_skeleton());
- }
- if (extra_margin)
- VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1);
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF);
- int layer = p_hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER;
- VS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26
-}
-
-void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const Ref<SkinReference> &p_skin_reference, const Ref<Material> &p_material) {
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
- ins.billboard = p_billboard;
- ins.mesh = p_mesh;
- ins.skin_reference = p_skin_reference;
- ins.material = p_material;
- if (valid) {
- ins.create_instance(spatial_node, hidden);
- VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
- if (ins.material.is_valid()) {
- VS::get_singleton()->instance_geometry_set_material_override(ins.instance, p_material->get_rid());
- }
- }
-
- instances.push_back(ins);
-}
-
-void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) {
- if (p_lines.empty()) {
- return;
- }
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
- Array a;
- a.resize(Mesh::ARRAY_MAX);
-
- a[Mesh::ARRAY_VERTEX] = p_lines;
-
- Vector<Color> color;
- color.resize(p_lines.size());
- {
- Color *w = color.ptrw();
- for (int i = 0; i < p_lines.size(); i++) {
- if (is_selected())
- w[i] = Color(1, 1, 1, 0.8) * p_modulate;
- else
- w[i] = Color(1, 1, 1, 0.2) * p_modulate;
- }
- }
-
- a[Mesh::ARRAY_COLOR] = color;
-
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, 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());
- }
- if (md) {
- mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
- }
- }
-
- ins.billboard = p_billboard;
- ins.mesh = mesh;
- if (valid) {
- ins.create_instance(spatial_node, hidden);
- VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
- }
-
- instances.push_back(ins);
-}
-
-void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material, float p_scale, const Color &p_modulate) {
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
- Vector<Vector3> vs;
- Vector<Vector2> uv;
- Vector<Color> colors;
-
- vs.push_back(Vector3(-p_scale, p_scale, 0));
- vs.push_back(Vector3(p_scale, p_scale, 0));
- vs.push_back(Vector3(p_scale, -p_scale, 0));
- vs.push_back(Vector3(-p_scale, -p_scale, 0));
-
- uv.push_back(Vector2(0, 0));
- uv.push_back(Vector2(1, 0));
- uv.push_back(Vector2(1, 1));
- uv.push_back(Vector2(0, 1));
-
- colors.push_back(p_modulate);
- colors.push_back(p_modulate);
- colors.push_back(p_modulate);
- colors.push_back(p_modulate);
-
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = vs;
- a[Mesh::ARRAY_TEX_UV] = uv;
- Vector<int> indices;
- indices.push_back(0);
- indices.push_back(1);
- indices.push_back(2);
- indices.push_back(0);
- indices.push_back(2);
- indices.push_back(3);
- a[Mesh::ARRAY_INDEX] = indices;
- a[Mesh::ARRAY_COLOR] = colors;
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
- mesh->surface_set_material(0, p_material);
-
- float md = 0;
- for (int i = 0; i < vs.size(); i++) {
-
- md = MAX(0, vs[i].length());
- }
- if (md) {
- mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
- }
-
- selectable_icon_size = p_scale;
- mesh->set_custom_aabb(AABB(Vector3(-selectable_icon_size, -selectable_icon_size, -selectable_icon_size) * 100.0f, Vector3(selectable_icon_size, selectable_icon_size, selectable_icon_size) * 200.0f));
-
- ins.mesh = mesh;
- ins.unscaled = true;
- ins.billboard = true;
- if (valid) {
- ins.create_instance(spatial_node, hidden);
- VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
- }
-
- selectable_icon_size = p_scale;
-
- instances.push_back(ins);
-}
-
-void EditorSpatialGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh) {
- collision_mesh = p_tmesh;
-}
-
-void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) {
-
- int from = collision_segments.size();
- collision_segments.resize(from + p_lines.size());
- for (int i = 0; i < p_lines.size(); i++) {
-
- collision_segments.write[from + i] = p_lines[i];
- }
-}
-
-void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard, bool p_secondary) {
-
- billboard_handle = p_billboard;
-
- if (!is_selected() || !is_editable())
- return;
-
- ERR_FAIL_COND(!spatial_node);
-
- Instance ins;
-
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
-
- Array a;
- a.resize(VS::ARRAY_MAX);
- a[VS::ARRAY_VERTEX] = p_handles;
- Vector<Color> colors;
- {
- colors.resize(p_handles.size());
- Color *w = colors.ptrw();
- for (int i = 0; i < p_handles.size(); i++) {
-
- Color col(1, 1, 1, 1);
- if (is_handle_highlighted(i))
- col = Color(0, 0, 1, 0.9);
-
- if (SpatialEditor::get_singleton()->get_over_gizmo_handle() != i)
- col.a = 0.8;
-
- w[i] = col;
- }
- }
- a[VS::ARRAY_COLOR] = colors;
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
- mesh->surface_set_material(0, p_material);
-
- if (p_billboard) {
- float md = 0;
- for (int i = 0; i < p_handles.size(); i++) {
-
- md = MAX(0, p_handles[i].length());
- }
- if (md) {
- mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
- }
- }
-
- ins.mesh = mesh;
- ins.billboard = p_billboard;
- ins.extra_margin = true;
- if (valid) {
- ins.create_instance(spatial_node, hidden);
- VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
- }
- instances.push_back(ins);
- if (!p_secondary) {
- int chs = handles.size();
- handles.resize(chs + p_handles.size());
- for (int i = 0; i < p_handles.size(); i++) {
- handles.write[i + chs] = p_handles[i];
- }
- } else {
-
- int chs = secondary_handles.size();
- secondary_handles.resize(chs + p_handles.size());
- for (int i = 0; i < p_handles.size(); i++) {
- secondary_handles.write[i + chs] = p_handles[i];
- }
- }
-}
-
-void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position) {
- ERR_FAIL_COND(!spatial_node);
-
- CubeMesh cubem;
- cubem.set_size(p_size);
-
- Array arrays = cubem.surface_get_arrays(0);
- PackedVector3Array vertex = arrays[VS::ARRAY_VERTEX];
- Vector3 *w = vertex.ptrw();
-
- for (int i = 0; i < vertex.size(); ++i) {
- w[i] += p_position;
- }
-
- arrays[VS::ARRAY_VERTEX] = vertex;
-
- Ref<ArrayMesh> m = memnew(ArrayMesh);
- m->add_surface_from_arrays(cubem.surface_get_primitive_type(0), arrays);
- m->surface_set_material(0, p_material);
- add_mesh(m);
-}
-
-bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) {
-
- ERR_FAIL_COND_V(!spatial_node, false);
- ERR_FAIL_COND_V(!valid, false);
-
- if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false;
-
- if (selectable_icon_size > 0.0f) {
- Vector3 origin = spatial_node->get_global_transform().get_origin();
-
- const Plane *p = p_frustum.ptr();
- int fc = p_frustum.size();
-
- bool any_out = false;
-
- for (int j = 0; j < fc; j++) {
-
- if (p[j].is_point_over(origin)) {
- any_out = true;
- break;
- }
- }
-
- return !any_out;
- }
-
- if (collision_segments.size()) {
-
- const Plane *p = p_frustum.ptr();
- int fc = p_frustum.size();
-
- int vc = collision_segments.size();
- const Vector3 *vptr = collision_segments.ptr();
- Transform t = spatial_node->get_global_transform();
-
- bool any_out = false;
- for (int j = 0; j < fc; j++) {
- for (int i = 0; i < vc; i++) {
- Vector3 v = t.xform(vptr[i]);
- if (p[j].is_point_over(v)) {
- any_out = true;
- break;
- }
- }
- if (any_out) break;
- }
-
- if (!any_out) return true;
- }
-
- if (collision_mesh.is_valid()) {
- Transform t = spatial_node->get_global_transform();
-
- Vector3 mesh_scale = t.get_basis().get_scale();
- t.orthonormalize();
-
- Transform it = t.affine_inverse();
-
- Vector<Plane> transformed_frustum;
-
- for (int i = 0; i < 4; i++) {
- transformed_frustum.push_back(it.xform(p_frustum[i]));
- }
-
- if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), mesh_scale)) {
- return true;
- }
- }
-
- return false;
-}
-
-bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
-
- ERR_FAIL_COND_V(!spatial_node, false);
- ERR_FAIL_COND_V(!valid, false);
-
- if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false;
-
- if (r_gizmo_handle && !hidden) {
-
- Transform t = spatial_node->get_global_transform();
- if (billboard_handle) {
- t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
- }
-
- float min_d = 1e20;
- int idx = -1;
-
- for (int i = 0; i < secondary_handles.size(); i++) {
-
- Vector3 hpos = t.xform(secondary_handles[i]);
- Vector2 p = p_camera->unproject_position(hpos);
-
- if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
-
- real_t dp = p_camera->get_transform().origin.distance_to(hpos);
- if (dp < min_d) {
-
- r_pos = t.xform(hpos);
- r_normal = p_camera->get_transform().basis.get_axis(2);
- min_d = dp;
- idx = i + handles.size();
- }
- }
- }
-
- if (p_sec_first && idx != -1) {
-
- *r_gizmo_handle = idx;
- return true;
- }
-
- min_d = 1e20;
-
- for (int i = 0; i < handles.size(); i++) {
-
- Vector3 hpos = t.xform(handles[i]);
- Vector2 p = p_camera->unproject_position(hpos);
-
- if (p.distance_to(p_point) < HANDLE_HALF_SIZE) {
-
- real_t dp = p_camera->get_transform().origin.distance_to(hpos);
- if (dp < min_d) {
-
- r_pos = t.xform(hpos);
- r_normal = p_camera->get_transform().basis.get_axis(2);
- min_d = dp;
- idx = i;
- }
- }
- }
-
- if (idx >= 0) {
- *r_gizmo_handle = idx;
- return true;
- }
- }
-
- if (selectable_icon_size > 0.0f) {
-
- 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));
- }
-
- float scale = t.origin.distance_to(p_camera->get_camera_transform().origin);
-
- if (p_camera->get_projection() == Camera::PROJECTION_ORTHOGONAL) {
- float aspect = p_camera->get_viewport()->get_visible_rect().size.aspect();
- float size = p_camera->get_size();
- scale = size / aspect;
- }
-
- Point2 center = p_camera->unproject_position(t.origin);
-
- Transform orig_camera_transform = p_camera->get_camera_transform();
-
- 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));
- }
-
- Vector3 c0 = t.xform(Vector3(selectable_icon_size, selectable_icon_size, 0) * scale);
- Vector3 c1 = t.xform(Vector3(-selectable_icon_size, -selectable_icon_size, 0) * scale);
-
- Point2 p0 = p_camera->unproject_position(c0);
- Point2 p1 = p_camera->unproject_position(c1);
-
- p_camera->set_global_transform(orig_camera_transform);
-
- Rect2 rect(p0, (p1 - p0).abs());
-
- rect.set_position(center - rect.get_size() / 2.0);
-
- if (rect.has_point(p_point)) {
- r_pos = t.origin;
- r_normal = -p_camera->project_ray_normal(p_point);
- return true;
- }
-
- return false;
- }
-
- if (collision_segments.size()) {
-
- Plane camp(p_camera->get_transform().origin, (-p_camera->get_transform().basis.get_axis(2)).normalized());
-
- int vc = collision_segments.size();
- const Vector3 *vptr = collision_segments.ptr();
- Transform t = spatial_node->get_global_transform();
- if (billboard_handle) {
- t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
- }
-
- Vector3 cp;
- float cpd = 1e20;
-
- for (int i = 0; i < vc / 2; i++) {
-
- Vector3 a = t.xform(vptr[i * 2 + 0]);
- Vector3 b = t.xform(vptr[i * 2 + 1]);
- Vector2 s[2];
- s[0] = p_camera->unproject_position(a);
- s[1] = p_camera->unproject_position(b);
-
- Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s);
-
- float pd = p.distance_to(p_point);
-
- if (pd < cpd) {
-
- float d = s[0].distance_to(s[1]);
- Vector3 tcp;
- if (d > 0) {
-
- float d2 = s[0].distance_to(p) / d;
- tcp = a + (b - a) * d2;
-
- } else {
- tcp = a;
- }
-
- if (camp.distance_to(tcp) < p_camera->get_znear())
- continue;
- cp = tcp;
- cpd = pd;
- }
- }
-
- if (cpd < 8) {
-
- r_pos = cp;
- r_normal = -p_camera->project_ray_normal(p_point);
- return true;
- }
-
- return false;
- }
-
- if (collision_mesh.is_valid()) {
- Transform gt = spatial_node->get_global_transform();
-
- if (billboard_handle) {
- gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
- }
-
- Transform ai = gt.affine_inverse();
- Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point));
- Vector3 ray_dir = ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
- Vector3 rpos, rnorm;
-
- if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm)) {
-
- r_pos = gt.xform(rpos);
- r_normal = gt.basis.xform(rnorm).normalized();
- return true;
- }
- }
-
- return false;
-}
-
-void EditorSpatialGizmo::create() {
-
- ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(valid);
- valid = true;
-
- for (int i = 0; i < instances.size(); i++) {
-
- instances.write[i].create_instance(spatial_node, hidden);
- }
-
- transform();
-}
-
-void EditorSpatialGizmo::transform() {
-
- ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(!valid);
- for (int i = 0; i < instances.size(); i++) {
- VS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform());
- }
-}
-
-void EditorSpatialGizmo::free() {
-
- ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(!valid);
-
- for (int i = 0; i < instances.size(); i++) {
-
- if (instances[i].instance.is_valid())
- VS::get_singleton()->free(instances[i].instance);
- instances.write[i].instance = RID();
- }
-
- clear();
-
- valid = false;
-}
-
-void EditorSpatialGizmo::set_hidden(bool p_hidden) {
- hidden = p_hidden;
- int layer = hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER;
- for (int i = 0; i < instances.size(); ++i) {
- VS::get_singleton()->instance_set_layer_mask(instances[i].instance, layer);
- }
-}
-
-void EditorSpatialGizmo::set_plugin(EditorSpatialGizmoPlugin *p_plugin) {
- gizmo_plugin = p_plugin;
-}
-
-void EditorSpatialGizmo::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("add_lines", "lines", "material", "billboard", "modulate"), &EditorSpatialGizmo::add_lines, DEFVAL(false), DEFVAL(Color(1, 1, 1)));
- ClassDB::bind_method(D_METHOD("add_mesh", "mesh", "billboard", "skeleton", "material"), &EditorSpatialGizmo::add_mesh, DEFVAL(false), DEFVAL(Ref<SkinReference>()), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorSpatialGizmo::add_collision_segments);
- ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorSpatialGizmo::add_collision_triangles);
- ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale", "modulate"), &EditorSpatialGizmo::add_unscaled_billboard, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
- ClassDB::bind_method(D_METHOD("add_handles", "handles", "material", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node);
- ClassDB::bind_method(D_METHOD("get_spatial_node"), &EditorSpatialGizmo::get_spatial_node);
- ClassDB::bind_method(D_METHOD("get_plugin"), &EditorSpatialGizmo::get_plugin);
- ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear);
- ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorSpatialGizmo::set_hidden);
-
- BIND_VMETHOD(MethodInfo("redraw"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index")));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", PropertyInfo(Variant::INT, "index")));
-
- MethodInfo hvget(Variant::NIL, "get_handle_value", PropertyInfo(Variant::INT, "index"));
- hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(hvget);
-
- BIND_VMETHOD(MethodInfo("set_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::VECTOR2, "point")));
- MethodInfo cm = MethodInfo("commit_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel"));
- cm.default_arguments.push_back(false);
- BIND_VMETHOD(cm);
-}
-
-EditorSpatialGizmo::EditorSpatialGizmo() {
- valid = false;
- billboard_handle = false;
- hidden = false;
- base = NULL;
- selected = false;
- instanced = false;
- spatial_node = NULL;
- gizmo_plugin = NULL;
- selectable_icon_size = -1.0f;
-}
-
-EditorSpatialGizmo::~EditorSpatialGizmo() {
-
- if (gizmo_plugin != NULL) gizmo_plugin->unregister_gizmo(this);
- clear();
-}
-
-Vector3 EditorSpatialGizmo::get_handle_pos(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx, handles.size(), Vector3());
-
- return handles[p_idx];
-}
-
-//// light gizmo
-
-LightSpatialGizmoPlugin::LightSpatialGizmoPlugin() {
-
- // Enable vertex colors for the materials below as the gizmo color depends on the light color.
- create_material("lines_primary", Color(1, 1, 1), false, false, true);
- create_material("lines_secondary", Color(1, 1, 1, 0.35), false, false, true);
- create_material("lines_billboard", Color(1, 1, 1), true, false, true);
-
- create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
- create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
- create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons"));
-
- create_handle_material("handles");
- create_handle_material("handles_billboard", true);
-}
-
-bool LightSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Light>(p_spatial) != NULL;
-}
-
-String LightSpatialGizmoPlugin::get_name() const {
- return "Lights";
-}
-
-int LightSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String LightSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- if (p_idx == 0)
- return "Radius";
- else
- return "Aperture";
-}
-
-Variant LightSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
- if (p_idx == 0)
- return light->get_param(Light::PARAM_RANGE);
- if (p_idx == 1)
- return light->get_param(Light::PARAM_SPOT_ANGLE);
-
- return Variant();
-}
-
-static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform &p_arc_xform) {
-
- //bleh, discrete is simpler
- static const int arc_test_points = 64;
- float min_d = 1e20;
- Vector3 min_p;
-
- for (int i = 0; i < arc_test_points; i++) {
-
- float a = i * Math_PI * 0.5 / arc_test_points;
- float an = (i + 1) * Math_PI * 0.5 / arc_test_points;
- Vector3 p = Vector3(Math::cos(a), 0, -Math::sin(a)) * p_arc_radius;
- Vector3 n = Vector3(Math::cos(an), 0, -Math::sin(an)) * p_arc_radius;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(p, n, p_from, p_to, ra, rb);
-
- float d = ra.distance_to(rb);
- if (d < min_d) {
- min_d = d;
- min_p = ra;
- }
- }
-
- //min_p = p_arc_xform.affine_inverse().xform(min_p);
- float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle();
- return a * 180.0 / Math_PI;
-}
-
-void LightSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
- Transform gt = light->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
- if (p_idx == 0) {
-
- if (Object::cast_to<SpotLight>(light)) {
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), Vector3(0, 0, -4096), s[0], s[1], ra, rb);
-
- float d = -ra.z;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d <= 0) // Equal is here for negative zero.
- d = 0;
-
- light->set_param(Light::PARAM_RANGE, d);
- } else if (Object::cast_to<OmniLight>(light)) {
-
- Plane cp = Plane(gt.origin, p_camera->get_transform().basis.get_axis(2));
-
- Vector3 inters;
- if (cp.intersects_ray(ray_from, ray_dir, &inters)) {
-
- float r = inters.distance_to(gt.origin);
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- r = Math::stepify(r, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- light->set_param(Light::PARAM_RANGE, r);
- }
- }
-
- } else if (p_idx == 1) {
-
- float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], light->get_param(Light::PARAM_RANGE), gt);
- light->set_param(Light::PARAM_SPOT_ANGLE, CLAMP(a, 0.01, 89.99));
- }
-}
-
-void LightSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
- if (p_cancel) {
-
- light->set_param(p_idx == 0 ? Light::PARAM_RANGE : Light::PARAM_SPOT_ANGLE, p_restore);
-
- } else if (p_idx == 0) {
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Light Radius"));
- ur->add_do_method(light, "set_param", Light::PARAM_RANGE, light->get_param(Light::PARAM_RANGE));
- ur->add_undo_method(light, "set_param", Light::PARAM_RANGE, p_restore);
- ur->commit_action();
- } else if (p_idx == 1) {
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Light Radius"));
- ur->add_do_method(light, "set_param", Light::PARAM_SPOT_ANGLE, light->get_param(Light::PARAM_SPOT_ANGLE));
- ur->add_undo_method(light, "set_param", Light::PARAM_SPOT_ANGLE, p_restore);
- ur->commit_action();
- }
-}
-
-void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node());
-
- Color color = light->get_color();
- // Make the gizmo color as bright as possible for better visibility
- color.set_hsv(color.get_h(), color.get_s(), 1);
-
- p_gizmo->clear();
-
- if (Object::cast_to<DirectionalLight>(light)) {
-
- Ref<Material> material = get_material("lines_primary", p_gizmo);
- Ref<Material> icon = get_material("light_directional_icon", p_gizmo);
-
- const int arrow_points = 7;
- const float arrow_length = 1.5;
-
- Vector3 arrow[arrow_points] = {
- Vector3(0, 0, -1),
- Vector3(0, 0.8, 0),
- Vector3(0, 0.3, 0),
- Vector3(0, 0.3, arrow_length),
- Vector3(0, -0.3, arrow_length),
- Vector3(0, -0.3, 0),
- Vector3(0, -0.8, 0)
- };
-
- int arrow_sides = 2;
-
- Vector<Vector3> lines;
-
- for (int i = 0; i < arrow_sides; i++) {
- for (int j = 0; j < arrow_points; j++) {
- Basis ma(Vector3(0, 0, 1), Math_PI * i / arrow_sides);
-
- Vector3 v1 = arrow[j] - Vector3(0, 0, arrow_length);
- Vector3 v2 = arrow[(j + 1) % arrow_points] - Vector3(0, 0, arrow_length);
-
- lines.push_back(ma.xform(v1));
- lines.push_back(ma.xform(v2));
- }
- }
-
- p_gizmo->add_lines(lines, material, false, color);
- p_gizmo->add_unscaled_billboard(icon, 0.05, color);
- }
-
- if (Object::cast_to<OmniLight>(light)) {
-
- // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation
- const Ref<Material> lines_material = get_material("lines_secondary", p_gizmo);
- const Ref<Material> lines_billboard_material = get_material("lines_billboard", p_gizmo);
- const Ref<Material> icon = get_material("light_omni_icon", p_gizmo);
-
- OmniLight *on = Object::cast_to<OmniLight>(light);
- const float r = on->get_param(Light::PARAM_RANGE);
- Vector<Vector3> points;
- Vector<Vector3> points_billboard;
-
- for (int i = 0; i < 120; i++) {
-
- // Create a circle
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
- const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- // Draw axis-aligned circles
- points.push_back(Vector3(a.x, 0, a.y));
- points.push_back(Vector3(b.x, 0, b.y));
- points.push_back(Vector3(0, a.x, a.y));
- points.push_back(Vector3(0, b.x, b.y));
- points.push_back(Vector3(a.x, a.y, 0));
- points.push_back(Vector3(b.x, b.y, 0));
-
- // Draw a billboarded circle
- points_billboard.push_back(Vector3(a.x, a.y, 0));
- points_billboard.push_back(Vector3(b.x, b.y, 0));
- }
-
- p_gizmo->add_lines(points, lines_material, true, color);
- p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
- p_gizmo->add_unscaled_billboard(icon, 0.05, color);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(r, 0, 0));
- p_gizmo->add_handles(handles, get_material("handles_billboard"), true);
- }
-
- if (Object::cast_to<SpotLight>(light)) {
-
- const Ref<Material> material_primary = get_material("lines_primary", p_gizmo);
- const Ref<Material> material_secondary = get_material("lines_secondary", p_gizmo);
- const Ref<Material> icon = get_material("light_spot_icon", p_gizmo);
-
- Vector<Vector3> points_primary;
- Vector<Vector3> points_secondary;
- SpotLight *sl = Object::cast_to<SpotLight>(light);
-
- float r = sl->get_param(Light::PARAM_RANGE);
- float w = r * Math::sin(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE)));
- float d = r * Math::cos(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE)));
-
- for (int i = 0; i < 120; i++) {
-
- // Draw a circle
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
- const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
- const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
-
- points_primary.push_back(Vector3(a.x, a.y, -d));
- points_primary.push_back(Vector3(b.x, b.y, -d));
-
- if (i % 15 == 0) {
- // Draw 8 lines from the cone origin to the sides of the circle
- points_secondary.push_back(Vector3(a.x, a.y, -d));
- points_secondary.push_back(Vector3());
- }
- }
-
- points_primary.push_back(Vector3(0, 0, -r));
- points_primary.push_back(Vector3());
-
- p_gizmo->add_lines(points_primary, material_primary, false, color);
- p_gizmo->add_lines(points_secondary, material_secondary, false, color);
-
- const float ra = 16 * Math_PI * 2.0 / 64.0;
- const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(0, 0, -r));
- handles.push_back(Vector3(a.x, a.y, -d));
-
- p_gizmo->add_handles(handles, get_material("handles"));
- p_gizmo->add_unscaled_billboard(icon, 0.05, color);
- }
-}
-
-//////
-
-//// player gizmo
-AudioStreamPlayer3DSpatialGizmoPlugin::AudioStreamPlayer3DSpatialGizmoPlugin() {
-
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
-
- create_icon_material("stream_player_3d_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons"));
- create_material("stream_player_3d_material_primary", gizmo_color);
- create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35));
- create_handle_material("handles");
-}
-
-bool AudioStreamPlayer3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<AudioStreamPlayer3D>(p_spatial) != NULL;
-}
-
-String AudioStreamPlayer3DSpatialGizmoPlugin::get_name() const {
- return "AudioStreamPlayer3D";
-}
-
-int AudioStreamPlayer3DSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- return "Emission Radius";
-}
-
-Variant AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
- AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
- return player->get_emission_angle();
-}
-
-void AudioStreamPlayer3DSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
-
- Transform gt = player->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
- Vector3 ray_to = ray_from + ray_dir * 4096;
-
- ray_from = gi.xform(ray_from);
- ray_to = gi.xform(ray_to);
-
- float closest_dist = 1e20;
- float closest_angle = 1e20;
-
- for (int i = 0; i < 180; i++) {
-
- float a = i * Math_PI / 180.0;
- float an = (i + 1) * Math_PI / 180.0;
-
- Vector3 from(Math::sin(a), 0, -Math::cos(a));
- Vector3 to(Math::sin(an), 0, -Math::cos(an));
-
- Vector3 r1, r2;
- Geometry::get_closest_points_between_segments(from, to, ray_from, ray_to, r1, r2);
- float d = r1.distance_to(r2);
- if (d < closest_dist) {
- closest_dist = d;
- closest_angle = i;
- }
- }
-
- if (closest_angle < 91) {
- player->set_emission_angle(closest_angle);
- }
-}
-
-void AudioStreamPlayer3DSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
-
- if (p_cancel) {
-
- player->set_emission_angle(p_restore);
-
- } else {
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle"));
- ur->add_do_method(player, "set_emission_angle", player->get_emission_angle());
- ur->add_undo_method(player, "set_emission_angle", p_restore);
- ur->commit_action();
- }
-}
-
-void AudioStreamPlayer3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- const AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- const Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
-
- if (player->is_emission_angle_enabled()) {
-
- const float pc = player->get_emission_angle();
- const float ofs = -Math::cos(Math::deg2rad(pc));
- const float radius = Math::sin(Math::deg2rad(pc));
-
- Vector<Vector3> points_primary;
- points_primary.resize(200);
-
- for (int i = 0; i < 100; i++) {
-
- const float a = i * 2.0 * Math_PI / 100.0;
- const float an = (i + 1) * 2.0 * Math_PI / 100.0;
-
- const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
- const Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs);
-
- points_primary.write[i * 2 + 0] = from;
- points_primary.write[i * 2 + 1] = to;
- }
-
- const Ref<Material> material_primary = get_material("stream_player_3d_material_primary", p_gizmo);
- p_gizmo->add_lines(points_primary, material_primary);
-
- Vector<Vector3> points_secondary;
- points_secondary.resize(16);
-
- for (int i = 0; i < 8; i++) {
-
- const float a = i * 2.0 * Math_PI / 8.0;
- const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
-
- points_secondary.write[i * 2 + 0] = from;
- points_secondary.write[i * 2 + 1] = Vector3();
- }
-
- const Ref<Material> material_secondary = get_material("stream_player_3d_material_secondary", p_gizmo);
- p_gizmo->add_lines(points_secondary, material_secondary);
-
- Vector<Vector3> handles;
- const float ha = Math::deg2rad(player->get_emission_angle());
- handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
- p_gizmo->add_handles(handles, get_material("handles"));
- }
-
- p_gizmo->add_unscaled_billboard(icon, 0.05);
-}
-
-//////
-
-CameraSpatialGizmoPlugin::CameraSpatialGizmoPlugin() {
-
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
-
- create_material("camera_material", gizmo_color);
- create_handle_material("handles");
-}
-
-bool CameraSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Camera>(p_spatial) != NULL;
-}
-
-String CameraSpatialGizmoPlugin::get_name() const {
- return "Camera";
-}
-
-int CameraSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String CameraSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
-
- if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
- return "FOV";
- } else {
- return "Size";
- }
-}
-
-Variant CameraSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
-
- if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
- return camera->get_fov();
- } else {
-
- return camera->get_size();
- }
-}
-
-void CameraSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
-
- Transform gt = camera->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
-
- if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
- Transform gt2 = camera->get_global_transform();
- float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt2);
- camera->set("fov", CLAMP(a * 2.0, 1, 179));
- } else {
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb);
- float d = ra.x * 2.0;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- d = CLAMP(d, 0.1, 16384);
-
- camera->set("size", d);
- }
-}
-
-void CameraSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
-
- if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
-
- if (p_cancel) {
-
- camera->set("fov", p_restore);
- } else {
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Camera FOV"));
- ur->add_do_property(camera, "fov", camera->get_fov());
- ur->add_undo_property(camera, "fov", p_restore);
- ur->commit_action();
- }
-
- } else {
-
- if (p_cancel) {
-
- camera->set("size", p_restore);
- } else {
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Camera Size"));
- ur->add_do_property(camera, "size", camera->get_size());
- ur->add_undo_property(camera, "size", p_restore);
- ur->commit_action();
- }
- }
-}
-
-void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
- Vector<Vector3> handles;
-
- Ref<Material> material = get_material("camera_material", p_gizmo);
-
-#define ADD_TRIANGLE(m_a, m_b, m_c) \
- { \
- lines.push_back(m_a); \
- lines.push_back(m_b); \
- lines.push_back(m_b); \
- lines.push_back(m_c); \
- lines.push_back(m_c); \
- lines.push_back(m_a); \
- }
-
-#define ADD_QUAD(m_a, m_b, m_c, m_d) \
- { \
- lines.push_back(m_a); \
- lines.push_back(m_b); \
- lines.push_back(m_b); \
- lines.push_back(m_c); \
- lines.push_back(m_c); \
- lines.push_back(m_d); \
- lines.push_back(m_d); \
- lines.push_back(m_a); \
- }
-
- switch (camera->get_projection()) {
-
- case Camera::PROJECTION_PERSPECTIVE: {
-
- // The real FOV is halved for accurate representation
- float fov = camera->get_fov() / 2.0;
-
- Vector3 side = Vector3(Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)));
- Vector3 nside = side;
- nside.x = -nside.x;
- Vector3 up = Vector3(0, side.x, 0);
-
- ADD_TRIANGLE(Vector3(), side + up, side - up);
- ADD_TRIANGLE(Vector3(), nside + up, nside - up);
- ADD_TRIANGLE(Vector3(), side + up, nside + up);
- ADD_TRIANGLE(Vector3(), side - up, nside - up);
-
- handles.push_back(side);
- side.x *= 0.25;
- nside.x *= 0.25;
- Vector3 tup(0, up.y * 3 / 2, side.z);
- ADD_TRIANGLE(tup, side + up, nside + up);
-
- } break;
- case Camera::PROJECTION_ORTHOGONAL: {
-
- float size = camera->get_size();
-
- float hsize = size * 0.5;
- Vector3 right(hsize, 0, 0);
- Vector3 up(0, hsize, 0);
- Vector3 back(0, 0, -1.0);
- Vector3 front(0, 0, 0);
-
- ADD_QUAD(-up - right, -up + right, up + right, up - right);
- ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back);
- ADD_QUAD(up + right, up + right + back, up - right + back, up - right);
- ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right);
-
- handles.push_back(right + back);
-
- right.x *= 0.25;
- Vector3 tup(0, up.y * 3 / 2, back.z);
- ADD_TRIANGLE(tup, right + up + back, -right + up + back);
-
- } break;
- case Camera::PROJECTION_FRUSTUM: {
- float hsize = camera->get_size() / 2.0;
-
- Vector3 side = Vector3(hsize, 0, -camera->get_znear()).normalized();
- Vector3 nside = side;
- nside.x = -nside.x;
- Vector3 up = Vector3(0, side.x, 0);
- Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0);
-
- ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset);
- ADD_TRIANGLE(Vector3(), nside + up + offset, nside - up + offset);
- ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset);
- ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset);
-
- side.x *= 0.25;
- nside.x *= 0.25;
- Vector3 tup(0, up.y * 3 / 2, side.z);
- ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset);
- }
- }
-
-#undef ADD_TRIANGLE
-#undef ADD_QUAD
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_handles(handles, get_material("handles"));
-
- ClippedCamera *clipcam = Object::cast_to<ClippedCamera>(camera);
- if (clipcam) {
- Spatial *parent = Object::cast_to<Spatial>(camera->get_parent());
- if (!parent) {
- return;
- }
- Vector3 cam_normal = -camera->get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
- Vector3 cam_x = camera->get_global_transform().basis.get_axis(Vector3::AXIS_X).normalized();
- Vector3 cam_y = camera->get_global_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
- Vector3 cam_pos = camera->get_global_transform().origin;
- Vector3 parent_pos = parent->get_global_transform().origin;
-
- Plane parent_plane(parent_pos, cam_normal);
- Vector3 ray_from = parent_plane.project(cam_pos);
-
- lines.clear();
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
-
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
-
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
-
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
-
- if (parent_plane.distance_to(cam_pos) < 0) {
- lines.push_back(ray_from);
- lines.push_back(cam_pos);
- }
-
- Transform local = camera->get_global_transform().affine_inverse();
- for (int i = 0; i < lines.size(); i++) {
- lines.write[i] = local.xform(lines[i]);
- }
-
- p_gizmo->add_lines(lines, material);
- }
-}
-
-//////
-
-MeshInstanceSpatialGizmoPlugin::MeshInstanceSpatialGizmoPlugin() {
-}
-
-bool MeshInstanceSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<MeshInstance>(p_spatial) != NULL && Object::cast_to<SoftBody>(p_spatial) == NULL;
-}
-
-String MeshInstanceSpatialGizmoPlugin::get_name() const {
- return "MeshInstance";
-}
-
-int MeshInstanceSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-bool MeshInstanceSpatialGizmoPlugin::can_be_hidden() const {
- return false;
-}
-
-void MeshInstanceSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- MeshInstance *mesh = Object::cast_to<MeshInstance>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Ref<Mesh> m = mesh->get_mesh();
-
- if (!m.is_valid())
- return; //none
-
- Ref<TriangleMesh> tm = m->generate_triangle_mesh();
- if (tm.is_valid()) {
- p_gizmo->add_collision_triangles(tm);
- }
-}
-
-/////
-Sprite3DSpatialGizmoPlugin::Sprite3DSpatialGizmoPlugin() {
-}
-
-bool Sprite3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Sprite3D>(p_spatial) != NULL;
-}
-
-String Sprite3DSpatialGizmoPlugin::get_name() const {
- return "Sprite3D";
-}
-
-int Sprite3DSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-bool Sprite3DSpatialGizmoPlugin::can_be_hidden() const {
- return false;
-}
-
-void Sprite3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Ref<TriangleMesh> tm = sprite->generate_triangle_mesh();
- if (tm.is_valid()) {
- p_gizmo->add_collision_triangles(tm);
- }
-}
-
-///
-
-Position3DSpatialGizmoPlugin::Position3DSpatialGizmoPlugin() {
- pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
- cursor_points = Vector<Vector3>();
-
- Vector<Color> cursor_colors;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs, 0, 0));
- cursor_points.push_back(Vector3(-cs, 0, 0));
- cursor_points.push_back(Vector3(0, +cs, 0));
- cursor_points.push_back(Vector3(0, -cs, 0));
- cursor_points.push_back(Vector3(0, 0, +cs));
- cursor_points.push_back(Vector3(0, 0, -cs));
- cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_color("axis_x_color", "Editor"));
- cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_color("axis_x_color", "Editor"));
- cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_color("axis_y_color", "Editor"));
- cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_color("axis_y_color", "Editor"));
- cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_color("axis_z_color", "Editor"));
- cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_color("axis_z_color", "Editor"));
-
- Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
- mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
-
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[Mesh::ARRAY_VERTEX] = cursor_points;
- d[Mesh::ARRAY_COLOR] = cursor_colors;
- pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d);
- pos3d_mesh->surface_set_material(0, mat);
-}
-
-bool Position3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Position3D>(p_spatial) != NULL;
-}
-
-String Position3DSpatialGizmoPlugin::get_name() const {
- return "Position3D";
-}
-
-int Position3DSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void Position3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- p_gizmo->clear();
- p_gizmo->add_mesh(pos3d_mesh);
- p_gizmo->add_collision_segments(cursor_points);
-}
-
-/////
-
-SkeletonSpatialGizmoPlugin::SkeletonSpatialGizmoPlugin() {
-
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
- create_material("skeleton_material", gizmo_color);
-}
-
-bool SkeletonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Skeleton>(p_spatial) != NULL;
-}
-
-String SkeletonSpatialGizmoPlugin::get_name() const {
- return "Skeleton";
-}
-
-int SkeletonSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- Skeleton *skel = Object::cast_to<Skeleton>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Ref<Material> material = get_material("skeleton_material", p_gizmo);
-
- Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(material);
- Vector<Transform> grests;
- grests.resize(skel->get_bone_count());
-
- Vector<int> bones;
- Vector<float> weights;
- bones.resize(4);
- weights.resize(4);
-
- for (int i = 0; i < 4; i++) {
- bones.write[i] = 0;
- weights.write[i] = 0;
- }
-
- weights.write[0] = 1;
-
- AABB aabb;
-
- Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
- Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
-
- for (int i_bone = 0; i_bone < skel->get_bone_count(); i_bone++) {
-
- int i = skel->get_process_order(i_bone);
-
- int parent = skel->get_bone_parent(i);
-
- if (parent >= 0) {
- grests.write[i] = grests[parent] * skel->get_bone_rest(i);
-
- Vector3 v0 = grests[parent].origin;
- Vector3 v1 = grests[i].origin;
- Vector3 d = (v1 - v0).normalized();
- float dist = v0.distance_to(v1);
-
- //find closest axis
- int closest = -1;
- float closest_d = 0.0;
-
- for (int j = 0; j < 3; j++) {
- float dp = Math::abs(grests[parent].basis[j].normalized().dot(d));
- if (j == 0 || dp > closest_d)
- closest = j;
- }
-
- //find closest other
- Vector3 first;
- Vector3 points[4];
- int pointidx = 0;
- for (int j = 0; j < 3; j++) {
-
- bones.write[0] = parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(rootcolor);
- surface_tool->add_vertex(v0 - grests[parent].basis[j].normalized() * dist * 0.05);
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(rootcolor);
- surface_tool->add_vertex(v0 + grests[parent].basis[j].normalized() * dist * 0.05);
-
- if (j == closest)
- continue;
-
- Vector3 axis;
- if (first == Vector3()) {
- axis = d.cross(d.cross(grests[parent].basis[j])).normalized();
- first = axis;
- } else {
- axis = d.cross(first).normalized();
- }
-
- for (int k = 0; k < 2; k++) {
-
- if (k == 1)
- axis = -axis;
- Vector3 point = v0 + d * dist * 0.2;
- point += axis * dist * 0.1;
-
- bones.write[0] = parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(v0);
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(point);
-
- bones.write[0] = parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(point);
- bones.write[0] = i;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(v1);
- points[pointidx++] = point;
- }
- }
-
- SWAP(points[1], points[2]);
- for (int j = 0; j < 4; j++) {
-
- bones.write[0] = parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(points[j]);
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(points[(j + 1) % 4]);
- }
-
- /*
- bones[0]=parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(0.4,1,0.4,0.4));
- surface_tool->add_vertex(v0);
- bones[0]=i;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(0.4,1,0.4,0.4));
- surface_tool->add_vertex(v1);
-*/
- } else {
-
- grests.write[i] = skel->get_bone_rest(i);
- bones.write[0] = i;
- }
- /*
- Transform t = grests[i];
- t.orthonormalize();
-
- for (int i=0;i<6;i++) {
-
-
- Vector3 face_points[4];
-
- for (int j=0;j<4;j++) {
-
- float v[3];
- v[0]=1.0;
- v[1]=1-2*((j>>1)&1);
- v[2]=v[1]*(1-2*(j&1));
-
- for (int k=0;k<3;k++) {
-
- if (i<3)
- face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
- else
- face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
- }
- }
-
- for(int j=0;j<4;j++) {
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
- surface_tool->add_vertex(t.xform(face_points[j]*0.04));
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
- surface_tool->add_vertex(t.xform(face_points[(j+1)%4]*0.04));
- }
-
- }
- */
- }
-
- Ref<ArrayMesh> m = surface_tool->commit();
- p_gizmo->add_mesh(m, false, skel->register_skin(Ref<Skin>()));
-}
-
-////
-
-PhysicalBoneSpatialGizmoPlugin::PhysicalBoneSpatialGizmoPlugin() {
- create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
-}
-
-bool PhysicalBoneSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<PhysicalBone>(p_spatial) != NULL;
-}
-
-String PhysicalBoneSpatialGizmoPlugin::get_name() const {
- return "PhysicalBones";
-}
-
-int PhysicalBoneSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- p_gizmo->clear();
-
- PhysicalBone *physical_bone = Object::cast_to<PhysicalBone>(p_gizmo->get_spatial_node());
-
- if (!physical_bone)
- return;
-
- Skeleton *sk(physical_bone->find_skeleton_parent());
- if (!sk)
- return;
-
- PhysicalBone *pb(sk->get_physical_bone(physical_bone->get_bone_id()));
- if (!pb)
- return;
-
- PhysicalBone *pbp(sk->get_physical_bone_parent(physical_bone->get_bone_id()));
- if (!pbp)
- return;
-
- Vector<Vector3> points;
-
- switch (physical_bone->get_joint_type()) {
- case PhysicalBone::JOINT_TYPE_PIN: {
-
- JointSpatialGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points);
- } break;
- case PhysicalBone::JOINT_TYPE_CONE: {
-
- const PhysicalBone::ConeJointData *cjd(static_cast<const PhysicalBone::ConeJointData *>(physical_bone->get_joint_data()));
- JointSpatialGizmoPlugin::CreateConeTwistJointGizmo(
- physical_bone->get_joint_offset(),
- physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
- pb->get_global_transform(),
- pbp->get_global_transform(),
- cjd->swing_span,
- cjd->twist_span,
- &points,
- &points);
- } break;
- case PhysicalBone::JOINT_TYPE_HINGE: {
-
- const PhysicalBone::HingeJointData *hjd(static_cast<const PhysicalBone::HingeJointData *>(physical_bone->get_joint_data()));
- JointSpatialGizmoPlugin::CreateHingeJointGizmo(
- physical_bone->get_joint_offset(),
- physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
- pb->get_global_transform(),
- pbp->get_global_transform(),
- hjd->angular_limit_lower,
- hjd->angular_limit_upper,
- hjd->angular_limit_enabled,
- points,
- &points,
- &points);
- } break;
- case PhysicalBone::JOINT_TYPE_SLIDER: {
-
- const PhysicalBone::SliderJointData *sjd(static_cast<const PhysicalBone::SliderJointData *>(physical_bone->get_joint_data()));
- JointSpatialGizmoPlugin::CreateSliderJointGizmo(
- physical_bone->get_joint_offset(),
- physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
- pb->get_global_transform(),
- pbp->get_global_transform(),
- sjd->angular_limit_lower,
- sjd->angular_limit_upper,
- sjd->linear_limit_lower,
- sjd->linear_limit_upper,
- points,
- &points,
- &points);
- } break;
- case PhysicalBone::JOINT_TYPE_6DOF: {
-
- const PhysicalBone::SixDOFJointData *sdofjd(static_cast<const PhysicalBone::SixDOFJointData *>(physical_bone->get_joint_data()));
- JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo(
- physical_bone->get_joint_offset(),
-
- physical_bone->get_global_transform() * physical_bone->get_joint_offset(),
- pb->get_global_transform(),
- pbp->get_global_transform(),
-
- sdofjd->axis_data[0].angular_limit_lower,
- sdofjd->axis_data[0].angular_limit_upper,
- sdofjd->axis_data[0].linear_limit_lower,
- sdofjd->axis_data[0].linear_limit_upper,
- sdofjd->axis_data[0].angular_limit_enabled,
- sdofjd->axis_data[0].linear_limit_enabled,
-
- sdofjd->axis_data[1].angular_limit_lower,
- sdofjd->axis_data[1].angular_limit_upper,
- sdofjd->axis_data[1].linear_limit_lower,
- sdofjd->axis_data[1].linear_limit_upper,
- sdofjd->axis_data[1].angular_limit_enabled,
- sdofjd->axis_data[1].linear_limit_enabled,
-
- sdofjd->axis_data[2].angular_limit_lower,
- sdofjd->axis_data[2].angular_limit_upper,
- sdofjd->axis_data[2].linear_limit_lower,
- sdofjd->axis_data[2].linear_limit_upper,
- sdofjd->axis_data[2].angular_limit_enabled,
- sdofjd->axis_data[2].linear_limit_enabled,
-
- points,
- &points,
- &points);
- } break;
- default:
- return;
- }
-
- Ref<Material> material = get_material("joint_material", p_gizmo);
-
- p_gizmo->add_collision_segments(points);
- p_gizmo->add_lines(points, material);
-}
-
-/////
-
-RayCastSpatialGizmoPlugin::RayCastSpatialGizmoPlugin() {
-
- 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 RayCastSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<RayCast>(p_spatial) != NULL;
-}
-
-String RayCastSpatialGizmoPlugin::get_name() const {
- return "RayCast";
-}
-
-int RayCastSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void RayCastSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- RayCast *raycast = Object::cast_to<RayCast>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
-
- lines.push_back(Vector3());
- lines.push_back(raycast->get_cast_to());
-
- const Ref<StandardMaterial3D> material =
- get_material(raycast->is_enabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_collision_segments(lines);
-}
-
-/////
-
-void SpringArmSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- SpringArm *spring_arm = Object::cast_to<SpringArm>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
-
- lines.push_back(Vector3());
- lines.push_back(Vector3(0, 0, 1.0) * spring_arm->get_length());
-
- Ref<StandardMaterial3D> material = get_material("shape_material", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_collision_segments(lines);
-}
-
-SpringArmSpatialGizmoPlugin::SpringArmSpatialGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
- create_material("shape_material", gizmo_color);
-}
-
-bool SpringArmSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<SpringArm>(p_spatial) != NULL;
-}
-
-String SpringArmSpatialGizmoPlugin::get_name() const {
- return "SpringArm";
-}
-
-int SpringArmSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-/////
-
-VehicleWheelSpatialGizmoPlugin::VehicleWheelSpatialGizmoPlugin() {
-
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
- create_material("shape_material", gizmo_color);
-}
-
-bool VehicleWheelSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<VehicleWheel>(p_spatial) != NULL;
-}
-
-String VehicleWheelSpatialGizmoPlugin::get_name() const {
- return "VehicleWheel";
-}
-
-int VehicleWheelSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void VehicleWheelSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- VehicleWheel *car_wheel = Object::cast_to<VehicleWheel>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> points;
-
- float r = car_wheel->get_radius();
- const int skip = 10;
- for (int i = 0; i <= 360; i += skip) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + skip);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- points.push_back(Vector3(0, a.x, a.y));
- points.push_back(Vector3(0, b.x, b.y));
-
- const int springsec = 4;
-
- for (int j = 0; j < springsec; j++) {
- float t = car_wheel->get_suspension_rest_length() * 5;
- points.push_back(Vector3(a.x, i / 360.0 * t / springsec + j * (t / springsec), a.y) * 0.2);
- points.push_back(Vector3(b.x, (i + skip) / 360.0 * t / springsec + j * (t / springsec), b.y) * 0.2);
- }
- }
-
- //travel
- points.push_back(Vector3(0, 0, 0));
- points.push_back(Vector3(0, car_wheel->get_suspension_rest_length(), 0));
-
- //axis
- points.push_back(Vector3(r * 0.2, car_wheel->get_suspension_rest_length(), 0));
- points.push_back(Vector3(-r * 0.2, car_wheel->get_suspension_rest_length(), 0));
- //axis
- points.push_back(Vector3(r * 0.2, 0, 0));
- points.push_back(Vector3(-r * 0.2, 0, 0));
-
- //forward line
- points.push_back(Vector3(0, -r, 0));
- points.push_back(Vector3(0, -r, r * 2));
- points.push_back(Vector3(0, -r, r * 2));
- points.push_back(Vector3(r * 2 * 0.2, -r, r * 2 * 0.8));
- points.push_back(Vector3(0, -r, r * 2));
- points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8));
-
- Ref<Material> material = get_material("shape_material", p_gizmo);
-
- p_gizmo->add_lines(points, material);
- p_gizmo->add_collision_segments(points);
-}
-
-///////////
-
-SoftBodySpatialGizmoPlugin::SoftBodySpatialGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
- create_material("shape_material", gizmo_color);
- create_handle_material("handles");
-}
-
-bool SoftBodySpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<SoftBody>(p_spatial) != NULL;
-}
-
-String SoftBodySpatialGizmoPlugin::get_name() const {
- return "SoftBody";
-}
-
-int SoftBodySpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-bool SoftBodySpatialGizmoPlugin::is_selectable_when_hidden() const {
- return true;
-}
-
-void SoftBodySpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- if (!soft_body || soft_body->get_mesh().is_null()) {
- return;
- }
-
- // find mesh
-
- Vector<Vector3> lines;
-
- soft_body->get_mesh()->generate_debug_mesh_lines(lines);
-
- if (!lines.size()) {
- return;
- }
-
- Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh();
-
- Vector<Vector3> points;
- soft_body->get_mesh()->generate_debug_mesh_indices(points);
-
- Ref<Material> material = get_material("shape_material", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_handles(points, get_material("handles"));
- p_gizmo->add_collision_triangles(tm);
-}
-
-String SoftBodySpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
- return "SoftBody pin point";
-}
-
-Variant SoftBodySpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
- SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
- return Variant(soft_body->is_point_pinned(p_idx));
-}
-
-void SoftBodySpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
- SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
- soft_body->pin_point_toggle(p_idx);
-}
-
-bool SoftBodySpatialGizmoPlugin::is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const {
- SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node());
- return soft_body->is_point_pinned(idx);
-}
-
-///////////
-
-VisibilityNotifierGizmoPlugin::VisibilityNotifierGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7));
- create_material("visibility_notifier_material", gizmo_color);
- gizmo_color.a = 0.1;
- create_material("visibility_notifier_solid_material", gizmo_color);
- create_handle_material("handles");
-}
-
-bool VisibilityNotifierGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<VisibilityNotifier>(p_spatial) != NULL;
-}
-
-String VisibilityNotifierGizmoPlugin::get_name() const {
- return "VisibilityNotifier";
-}
-
-int VisibilityNotifierGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String VisibilityNotifierGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Size X";
- case 1: return "Size Y";
- case 2: return "Size Z";
- case 3: return "Pos X";
- case 4: return "Pos Y";
- case 5: return "Pos Z";
- }
-
- return "";
-}
-
-Variant VisibilityNotifierGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
- return notifier->get_aabb();
-}
-void VisibilityNotifierGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
-
- Transform gt = notifier->get_global_transform();
-
- Transform gi = gt.affine_inverse();
-
- bool move = p_idx >= 3;
- p_idx = p_idx % 3;
-
- AABB aabb = notifier->get_aabb();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
-
- Vector3 ofs = aabb.position + aabb.size * 0.5;
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- if (move) {
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
-
- float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
- notifier->set_aabb(aabb);
-
- } else {
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
-
- float d = ra[p_idx] - ofs[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
- //resize
- aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
- aabb.size[p_idx] = d * 2;
- notifier->set_aabb(aabb);
- }
-}
-
-void VisibilityNotifierGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
-
- if (p_cancel) {
- notifier->set_aabb(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Notifier AABB"));
- ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
- ur->add_undo_method(notifier, "set_aabb", p_restore);
- ur->commit_action();
-}
-
-void VisibilityNotifierGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
- AABB aabb = notifier->get_aabb();
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
- ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
- handles.push_back(ax);
- }
-
- Vector3 center = aabb.position + aabb.size * 0.5;
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = 1.0;
- handles.push_back(center + ax);
- lines.push_back(center);
- lines.push_back(center + ax);
- }
-
- Ref<Material> material = get_material("visibility_notifier_material", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_collision_segments(lines);
-
- if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
- }
-
- p_gizmo->add_handles(handles, get_material("handles"));
-}
-
-////
-
-CPUParticlesGizmoPlugin::CPUParticlesGizmoPlugin() {
- create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoCPUParticles", "EditorIcons"));
-}
-
-bool CPUParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<CPUParticles>(p_spatial) != NULL;
-}
-
-String CPUParticlesGizmoPlugin::get_name() const {
- return "CPUParticles";
-}
-
-int CPUParticlesGizmoPlugin::get_priority() const {
- return -1;
-}
-
-bool CPUParticlesGizmoPlugin::is_selectable_when_hidden() const {
- return true;
-}
-
-void CPUParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- Ref<Material> icon = get_material("particles_icon", p_gizmo);
- p_gizmo->add_unscaled_billboard(icon, 0.05);
-}
-
-////
-
-ParticlesGizmoPlugin::ParticlesGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
- create_material("particles_material", gizmo_color);
- gizmo_color.a = 0.1;
- create_material("particles_solid_material", gizmo_color);
- create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons"));
- create_handle_material("handles");
-}
-
-bool ParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Particles>(p_spatial) != NULL;
-}
-
-String ParticlesGizmoPlugin::get_name() const {
- return "Particles";
-}
-
-int ParticlesGizmoPlugin::get_priority() const {
- return -1;
-}
-
-bool ParticlesGizmoPlugin::is_selectable_when_hidden() const {
- return true;
-}
-
-String ParticlesGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Size X";
- case 1: return "Size Y";
- case 2: return "Size Z";
- case 3: return "Pos X";
- case 4: return "Pos Y";
- case 5: return "Pos Z";
- }
-
- return "";
-}
-Variant ParticlesGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
- return particles->get_visibility_aabb();
-}
-void ParticlesGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
-
- Transform gt = particles->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- bool move = p_idx >= 3;
- p_idx = p_idx % 3;
-
- AABB aabb = particles->get_visibility_aabb();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
-
- Vector3 ofs = aabb.position + aabb.size * 0.5;
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- if (move) {
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
-
- float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5;
- particles->set_visibility_aabb(aabb);
-
- } else {
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
-
- float d = ra[p_idx] - ofs[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
- //resize
- aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d;
- aabb.size[p_idx] = d * 2;
- particles->set_visibility_aabb(aabb);
- }
-}
-
-void ParticlesGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
-
- if (p_cancel) {
- particles->set_visibility_aabb(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Particles AABB"));
- ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
- ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
- ur->commit_action();
-}
-
-void ParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
- AABB aabb = particles->get_visibility_aabb();
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
- ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
- handles.push_back(ax);
- }
-
- Vector3 center = aabb.position + aabb.size * 0.5;
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = 1.0;
- handles.push_back(center + ax);
- lines.push_back(center);
- lines.push_back(center + ax);
- }
-
- Ref<Material> material = get_material("particles_material", p_gizmo);
- Ref<Material> icon = get_material("particles_icon", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
-
- if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
- }
-
- p_gizmo->add_handles(handles, get_material("handles"));
- p_gizmo->add_unscaled_billboard(icon, 0.05);
-}
-////
-
-ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
-
- create_material("reflection_probe_material", gizmo_color);
-
- gizmo_color.a = 0.5;
- create_material("reflection_internal_material", gizmo_color);
-
- gizmo_color.a = 0.1;
- create_material("reflection_probe_solid_material", gizmo_color);
-
- create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons"));
- create_handle_material("handles");
-}
-
-bool ReflectionProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<ReflectionProbe>(p_spatial) != NULL;
-}
-
-String ReflectionProbeGizmoPlugin::get_name() const {
- return "ReflectionProbe";
-}
-
-int ReflectionProbeGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String ReflectionProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Extents X";
- case 1: return "Extents Y";
- case 2: return "Extents Z";
- case 3: return "Origin X";
- case 4: return "Origin Y";
- case 5: return "Origin Z";
- }
-
- return "";
-}
-Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
- return AABB(probe->get_extents(), probe->get_origin_offset());
-}
-void ReflectionProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
- Transform gt = probe->get_global_transform();
-
- Transform gi = gt.affine_inverse();
-
- if (p_idx < 3) {
- Vector3 extents = probe->get_extents();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- extents[p_idx] = d;
- probe->set_extents(extents);
- } else {
-
- p_idx -= 3;
-
- Vector3 origin = probe->get_origin_offset();
- origin[p_idx] = 0;
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb);
- // Adjust the actual position to account for the gizmo handle position
- float d = ra[p_idx] + 0.25;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- origin[p_idx] = d;
- probe->set_origin_offset(origin);
- }
-}
-
-void ReflectionProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
-
- AABB restore = p_restore;
-
- if (p_cancel) {
- probe->set_extents(restore.position);
- probe->set_origin_offset(restore.size);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(probe, "set_extents", probe->get_extents());
- ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
- ur->add_undo_method(probe, "set_extents", restore.position);
- ur->add_undo_method(probe, "set_origin_offset", restore.size);
- ur->commit_action();
-}
-
-void ReflectionProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
- Vector<Vector3> internal_lines;
- Vector3 extents = probe->get_extents();
-
- AABB aabb;
- aabb.position = -extents;
- aabb.size = extents * 2;
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- for (int i = 0; i < 8; i++) {
- Vector3 ep = aabb.get_endpoint(i);
- internal_lines.push_back(probe->get_origin_offset());
- internal_lines.push_back(ep);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 orig_handle = probe->get_origin_offset();
- orig_handle[i] -= 0.25;
- lines.push_back(orig_handle);
- handles.push_back(orig_handle);
-
- orig_handle[i] += 0.5;
- lines.push_back(orig_handle);
- }
-
- Ref<Material> material = get_material("reflection_probe_material", p_gizmo);
- Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo);
- Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_lines(internal_lines, material_internal);
-
- if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, probe->get_extents() * 2.0);
- }
-
- p_gizmo->add_unscaled_billboard(icon, 0.05);
- p_gizmo->add_handles(handles, get_material("handles"));
-}
-
-GIProbeGizmoPlugin::GIProbeGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6));
-
- create_material("gi_probe_material", gizmo_color);
-
- // This gizmo draws a lot of lines. Use a low opacity to make it not too intrusive.
- gizmo_color.a = 0.1;
- create_material("gi_probe_internal_material", gizmo_color);
-
- gizmo_color.a = 0.05;
- create_material("gi_probe_solid_material", gizmo_color);
-
- create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons"));
- create_handle_material("handles");
-}
-
-bool GIProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<GIProbe>(p_spatial) != NULL;
-}
-
-String GIProbeGizmoPlugin::get_name() const {
- return "GIProbe";
-}
-
-int GIProbeGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String GIProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Extents X";
- case 1: return "Extents Y";
- case 2: return "Extents Z";
- }
-
- return "";
-}
-Variant GIProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
- return probe->get_extents();
-}
-void GIProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
-
- Transform gt = probe->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- Vector3 extents = probe->get_extents();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- extents[p_idx] = d;
- probe->set_extents(extents);
-}
-
-void GIProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
-
- Vector3 restore = p_restore;
-
- if (p_cancel) {
- probe->set_extents(restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(probe, "set_extents", probe->get_extents());
- ur->add_undo_method(probe, "set_extents", restore);
- ur->commit_action();
-}
-
-void GIProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node());
-
- Ref<Material> material = get_material("gi_probe_material", p_gizmo);
- Ref<Material> icon = get_material("gi_probe_icon", p_gizmo);
- Ref<Material> material_internal = get_material("gi_probe_internal_material", p_gizmo);
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
- Vector3 extents = probe->get_extents();
-
- static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 };
-
- AABB aabb = AABB(-extents, extents * 2);
- int subdiv = subdivs[probe->get_subdiv()];
- float cell_size = aabb.get_longest_axis_size() / subdiv;
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- p_gizmo->add_lines(lines, material);
-
- lines.clear();
-
- for (int i = 1; i < subdiv; i++) {
-
- for (int j = 0; j < 3; j++) {
-
- if (cell_size * i > aabb.size[j]) {
- continue;
- }
-
- Vector2 dir;
- dir[j] = 1.0;
- Vector2 ta, tb;
- int j_n1 = (j + 1) % 3;
- int j_n2 = (j + 2) % 3;
- ta[j_n1] = 1.0;
- tb[j_n2] = 1.0;
-
- for (int k = 0; k < 4; k++) {
-
- Vector3 from = aabb.position, to = aabb.position;
- from[j] += cell_size * i;
- to[j] += cell_size * i;
-
- if (k & 1) {
- to[j_n1] += aabb.size[j_n1];
- } else {
-
- to[j_n2] += aabb.size[j_n2];
- }
-
- if (k & 2) {
- from[j_n1] += aabb.size[j_n1];
- from[j_n2] += aabb.size[j_n2];
- }
-
- lines.push_back(from);
- lines.push_back(to);
- }
- }
- }
-
- p_gizmo->add_lines(lines, material_internal);
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, aabb.get_size());
- }
-
- p_gizmo->add_unscaled_billboard(icon, 0.05);
- p_gizmo->add_handles(handles, get_material("handles"));
-}
-
-////
-#if 0
-BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
-
- create_material("baked_indirect_light_material", gizmo_color);
-
- gizmo_color.a = 0.1;
- create_material("baked_indirect_light_internal_material", gizmo_color);
-
- create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons"));
- create_handle_material("handles");
-}
-
-String BakedIndirectLightGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- switch (p_idx) {
- case 0: return "Extents X";
- case 1: return "Extents Y";
- case 2: return "Extents Z";
- }
-
- return "";
-}
-Variant BakedIndirectLightGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
- return baker->get_extents();
-}
-void BakedIndirectLightGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
-
- Transform gt = baker->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- Vector3 extents = baker->get_extents();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_idx] = 1.0;
-
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- extents[p_idx] = d;
- baker->set_extents(extents);
-}
-
-void BakedIndirectLightGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
-
- Vector3 restore = p_restore;
-
- if (p_cancel) {
- baker->set_extents(restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(baker, "set_extents", baker->get_extents());
- ur->add_undo_method(baker, "set_extents", restore);
- ur->commit_action();
-}
-
-bool BakedIndirectLightGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<BakedLightmap>(p_spatial) != NULL;
-}
-
-String BakedIndirectLightGizmoPlugin::get_name() const {
- return "BakedLightmap";
-}
-
-int BakedIndirectLightGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node());
-
- Ref<Material> material = get_material("baked_indirect_light_material", p_gizmo);
- Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo);
- Ref<Material> material_internal = get_material("baked_indirect_light_internal_material", p_gizmo);
-
- p_gizmo->clear();
-
- Vector<Vector3> lines;
- Vector3 extents = baker->get_extents();
-
- AABB aabb = AABB(-extents, extents * 2);
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- p_gizmo->add_lines(lines, material);
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
- if (p_gizmo->is_selected()) {
- p_gizmo->add_solid_box(material_internal, aabb.get_size());
- }
-
- p_gizmo->add_unscaled_billboard(icon, 0.05);
- p_gizmo->add_handles(handles, get_material("handles"));
-}
-#endif
-////
-
-CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() {
- 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);
- create_handle_material("handles");
-}
-
-bool CollisionShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<CollisionShape>(p_spatial) != NULL;
-}
-
-String CollisionShapeSpatialGizmoPlugin::get_name() const {
- return "CollisionShape";
-}
-
-int CollisionShapeSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-String CollisionShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- const CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return "";
-
- if (Object::cast_to<SphereShape>(*s)) {
-
- return "Radius";
- }
-
- if (Object::cast_to<BoxShape>(*s)) {
-
- return "Extents";
- }
-
- if (Object::cast_to<CapsuleShape>(*s)) {
-
- return p_idx == 0 ? "Radius" : "Height";
- }
-
- if (Object::cast_to<CylinderShape>(*s)) {
-
- return p_idx == 0 ? "Radius" : "Height";
- }
-
- if (Object::cast_to<RayShape>(*s)) {
-
- return "Length";
- }
-
- return "";
-}
-
-Variant CollisionShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
-
- CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return Variant();
-
- if (Object::cast_to<SphereShape>(*s)) {
-
- Ref<SphereShape> ss = s;
- return ss->get_radius();
- }
-
- if (Object::cast_to<BoxShape>(*s)) {
-
- Ref<BoxShape> bs = s;
- return bs->get_extents();
- }
-
- if (Object::cast_to<CapsuleShape>(*s)) {
-
- Ref<CapsuleShape> cs2 = s;
- return p_idx == 0 ? cs2->get_radius() : cs2->get_height();
- }
-
- if (Object::cast_to<CylinderShape>(*s)) {
-
- Ref<CylinderShape> cs2 = s;
- return p_idx == 0 ? cs2->get_radius() : cs2->get_height();
- }
-
- if (Object::cast_to<RayShape>(*s)) {
-
- Ref<RayShape> cs2 = s;
- return cs2->get_length();
- }
-
- return Variant();
-}
-void CollisionShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
-
- CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return;
-
- Transform gt = cs->get_global_transform();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
-
- if (Object::cast_to<SphereShape>(*s)) {
-
- Ref<SphereShape> ss = s;
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
- float d = ra.x;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- ss->set_radius(d);
- }
-
- if (Object::cast_to<RayShape>(*s)) {
-
- Ref<RayShape> rs = s;
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb);
- float d = ra.z;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- rs->set_length(d);
- }
-
- if (Object::cast_to<BoxShape>(*s)) {
-
- Vector3 axis;
- axis[p_idx] = 1.0;
- Ref<BoxShape> bs = s;
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- Vector3 he = bs->get_extents();
- he[p_idx] = d;
- bs->set_extents(he);
- }
-
- if (Object::cast_to<CapsuleShape>(*s)) {
-
- Vector3 axis;
- axis[p_idx == 0 ? 0 : 2] = 1.0;
- Ref<CapsuleShape> cs2 = s;
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = axis.dot(ra);
- if (p_idx == 1)
- d -= cs2->get_radius();
-
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- if (p_idx == 0)
- cs2->set_radius(d);
- else if (p_idx == 1)
- cs2->set_height(d * 2.0);
- }
-
- if (Object::cast_to<CylinderShape>(*s)) {
-
- Vector3 axis;
- axis[p_idx == 0 ? 0 : 1] = 1.0;
- Ref<CylinderShape> cs2 = s;
- Vector3 ra, rb;
- Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = axis.dot(ra);
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001)
- d = 0.001;
-
- if (p_idx == 0)
- cs2->set_radius(d);
- else if (p_idx == 1)
- cs2->set_height(d * 2.0);
- }
-}
-void CollisionShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
-
- CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return;
-
- if (Object::cast_to<SphereShape>(*s)) {
-
- Ref<SphereShape> ss = s;
- if (p_cancel) {
- ss->set_radius(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Sphere Shape Radius"));
- ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
- ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
- ur->commit_action();
- }
-
- if (Object::cast_to<BoxShape>(*s)) {
-
- Ref<BoxShape> ss = s;
- if (p_cancel) {
- ss->set_extents(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Box Shape Extents"));
- ur->add_do_method(ss.ptr(), "set_extents", ss->get_extents());
- ur->add_undo_method(ss.ptr(), "set_extents", p_restore);
- ur->commit_action();
- }
-
- if (Object::cast_to<CapsuleShape>(*s)) {
-
- Ref<CapsuleShape> ss = s;
- if (p_cancel) {
- if (p_idx == 0)
- ss->set_radius(p_restore);
- else
- ss->set_height(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- if (p_idx == 0) {
- ur->create_action(TTR("Change Capsule Shape Radius"));
- ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
- ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
- } else {
- ur->create_action(TTR("Change Capsule Shape Height"));
- ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
- ur->add_undo_method(ss.ptr(), "set_height", p_restore);
- }
-
- ur->commit_action();
- }
-
- if (Object::cast_to<CylinderShape>(*s)) {
-
- Ref<CylinderShape> ss = s;
- if (p_cancel) {
- if (p_idx == 0)
- ss->set_radius(p_restore);
- else
- ss->set_height(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- if (p_idx == 0) {
- ur->create_action(TTR("Change Cylinder Shape Radius"));
- ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
- ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
- } else {
- ur->create_action(
- ///
-
- ////////
- TTR("Change Cylinder Shape Height"));
- ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
- ur->add_undo_method(ss.ptr(), "set_height", p_restore);
- }
-
- ur->commit_action();
- }
-
- if (Object::cast_to<RayShape>(*s)) {
-
- Ref<RayShape> ss = s;
- if (p_cancel) {
- ss->set_length(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Ray Shape Length"));
- ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
- ur->add_undo_method(ss.ptr(), "set_length", p_restore);
- ur->commit_action();
- }
-}
-void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return;
-
- const Ref<Material> material =
- get_material(!cs->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
- Ref<Material> handles_material = get_material("handles");
-
- if (Object::cast_to<SphereShape>(*s)) {
-
- Ref<SphereShape> sp = s;
- float r = sp->get_radius();
-
- Vector<Vector3> points;
-
- for (int i = 0; i <= 360; i++) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- points.push_back(Vector3(a.x, 0, a.y));
- points.push_back(Vector3(b.x, 0, b.y));
- points.push_back(Vector3(0, a.x, a.y));
- points.push_back(Vector3(0, b.x, b.y));
- points.push_back(Vector3(a.x, a.y, 0));
- points.push_back(Vector3(b.x, b.y, 0));
- }
-
- Vector<Vector3> collision_segments;
-
- for (int i = 0; i < 64; i++) {
-
- float ra = i * Math_PI * 2.0 / 64.0;
- float rb = (i + 1) * Math_PI * 2.0 / 64.0;
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- collision_segments.push_back(Vector3(a.x, 0, a.y));
- collision_segments.push_back(Vector3(b.x, 0, b.y));
- collision_segments.push_back(Vector3(0, a.x, a.y));
- collision_segments.push_back(Vector3(0, b.x, b.y));
- collision_segments.push_back(Vector3(a.x, a.y, 0));
- collision_segments.push_back(Vector3(b.x, b.y, 0));
- }
-
- p_gizmo->add_lines(points, material);
- p_gizmo->add_collision_segments(collision_segments);
- Vector<Vector3> handles;
- handles.push_back(Vector3(r, 0, 0));
- p_gizmo->add_handles(handles, handles_material);
- }
-
- if (Object::cast_to<BoxShape>(*s)) {
-
- Ref<BoxShape> bs = s;
- Vector<Vector3> lines;
- AABB aabb;
- aabb.position = -bs->get_extents();
- aabb.size = aabb.position * -2;
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 ax;
- ax[i] = bs->get_extents()[i];
- handles.push_back(ax);
- }
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_collision_segments(lines);
- p_gizmo->add_handles(handles, handles_material);
- }
-
- if (Object::cast_to<CapsuleShape>(*s)) {
-
- Ref<CapsuleShape> cs2 = s;
- float radius = cs2->get_radius();
- float height = cs2->get_height();
-
- Vector<Vector3> points;
-
- Vector3 d(0, height * 0.5, 0);
- for (int i = 0; i < 360; i++) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(b.x, 0, b.y) + d);
-
- points.push_back(Vector3(a.x, 0, a.y) - d);
- points.push_back(Vector3(b.x, 0, b.y) - d);
-
- if (i % 90 == 0) {
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(a.x, 0, a.y) - d);
- }
-
- Vector3 dud = i < 180 ? d : -d;
-
- points.push_back(Vector3(0, a.x, a.y) + dud);
- points.push_back(Vector3(0, b.x, b.y) + dud);
- points.push_back(Vector3(a.y, a.x, 0) + dud);
- points.push_back(Vector3(b.y, b.x, 0) + dud);
- }
-
- p_gizmo->add_lines(points, material);
-
- Vector<Vector3> collision_segments;
-
- for (int i = 0; i < 64; i++) {
-
- float ra = i * Math_PI * 2.0 / 64.0;
- float rb = (i + 1) * Math_PI * 2.0 / 64.0;
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
-
- collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
- collision_segments.push_back(Vector3(b.x, 0, b.y) + d);
-
- collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
- collision_segments.push_back(Vector3(b.x, 0, b.y) - d);
-
- if (i % 16 == 0) {
-
- collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
- collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
- }
-
- Vector3 dud = i < 32 ? d : -d;
-
- collision_segments.push_back(Vector3(0, a.x, a.y) + dud);
- collision_segments.push_back(Vector3(0, b.x, b.y) + dud);
- collision_segments.push_back(Vector3(a.y, a.x, 0) + dud);
- collision_segments.push_back(Vector3(b.y, b.x, 0) + dud);
- }
-
- p_gizmo->add_collision_segments(collision_segments);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(cs2->get_radius(), 0, 0));
- handles.push_back(Vector3(0, cs2->get_height() * 0.5 + cs2->get_radius(), 0));
- p_gizmo->add_handles(handles, handles_material);
- }
-
- if (Object::cast_to<CylinderShape>(*s)) {
-
- Ref<CylinderShape> cs2 = s;
- float radius = cs2->get_radius();
- float height = cs2->get_height();
-
- Vector<Vector3> points;
-
- Vector3 d(0, height * 0.5, 0);
- for (int i = 0; i < 360; i++) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(b.x, 0, b.y) + d);
-
- points.push_back(Vector3(a.x, 0, a.y) - d);
- points.push_back(Vector3(b.x, 0, b.y) - d);
-
- if (i % 90 == 0) {
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(a.x, 0, a.y) - d);
- }
- }
-
- p_gizmo->add_lines(points, material);
-
- Vector<Vector3> collision_segments;
-
- for (int i = 0; i < 64; i++) {
-
- float ra = i * Math_PI * 2.0 / 64.0;
- float rb = (i + 1) * Math_PI * 2.0 / 64.0;
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
-
- collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
- collision_segments.push_back(Vector3(b.x, 0, b.y) + d);
-
- collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
- collision_segments.push_back(Vector3(b.x, 0, b.y) - d);
-
- if (i % 16 == 0) {
-
- collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
- collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
- }
- }
-
- p_gizmo->add_collision_segments(collision_segments);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(cs2->get_radius(), 0, 0));
- handles.push_back(Vector3(0, cs2->get_height() * 0.5, 0));
- p_gizmo->add_handles(handles, handles_material);
- }
-
- if (Object::cast_to<WorldMarginShape>(*s)) {
-
- Ref<WorldMarginShape> ps = s;
- Plane p = ps->get_plane();
- Vector<Vector3> points;
-
- Vector3 n1 = p.get_any_perpendicular_normal();
- Vector3 n2 = p.normal.cross(n1).normalized();
-
- Vector3 pface[4] = {
- p.normal * p.d + n1 * 10.0 + n2 * 10.0,
- p.normal * p.d + n1 * 10.0 + n2 * -10.0,
- p.normal * p.d + n1 * -10.0 + n2 * -10.0,
- p.normal * p.d + n1 * -10.0 + n2 * 10.0,
- };
-
- points.push_back(pface[0]);
- points.push_back(pface[1]);
- points.push_back(pface[1]);
- points.push_back(pface[2]);
- points.push_back(pface[2]);
- points.push_back(pface[3]);
- points.push_back(pface[3]);
- points.push_back(pface[0]);
- points.push_back(p.normal * p.d);
- points.push_back(p.normal * p.d + p.normal * 3);
-
- p_gizmo->add_lines(points, material);
- p_gizmo->add_collision_segments(points);
- }
-
- if (Object::cast_to<ConvexPolygonShape>(*s)) {
-
- Vector<Vector3> points = Object::cast_to<ConvexPolygonShape>(*s)->get_points();
-
- if (points.size() > 3) {
-
- Vector<Vector3> varr = Variant(points);
- Geometry::MeshData md;
- Error err = QuickHull::build(varr, md);
- if (err == OK) {
- Vector<Vector3> points2;
- points2.resize(md.edges.size() * 2);
- for (int i = 0; i < md.edges.size(); i++) {
- points2.write[i * 2 + 0] = md.vertices[md.edges[i].a];
- points2.write[i * 2 + 1] = md.vertices[md.edges[i].b];
- }
-
- p_gizmo->add_lines(points2, material);
- p_gizmo->add_collision_segments(points2);
- }
- }
- }
-
- if (Object::cast_to<ConcavePolygonShape>(*s)) {
-
- Ref<ConcavePolygonShape> cs2 = s;
- Ref<ArrayMesh> mesh = cs2->get_debug_mesh();
- p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), material);
- p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines());
- }
-
- if (Object::cast_to<RayShape>(*s)) {
-
- Ref<RayShape> rs = s;
-
- Vector<Vector3> points;
- points.push_back(Vector3());
- points.push_back(Vector3(0, 0, rs->get_length()));
- p_gizmo->add_lines(points, material);
- p_gizmo->add_collision_segments(points);
- Vector<Vector3> handles;
- handles.push_back(Vector3(0, 0, rs->get_length()));
- p_gizmo->add_handles(handles, handles_material);
- }
-
- if (Object::cast_to<HeightMapShape>(*s)) {
-
- Ref<HeightMapShape> hms = s;
-
- Ref<ArrayMesh> mesh = hms->get_debug_mesh();
- p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), material);
- }
-}
-
-/////
-
-CollisionPolygonSpatialGizmoPlugin::CollisionPolygonSpatialGizmoPlugin() {
- 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 CollisionPolygonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<CollisionPolygon>(p_spatial) != NULL;
-}
-
-String CollisionPolygonSpatialGizmoPlugin::get_name() const {
- return "CollisionPolygon";
-}
-
-int CollisionPolygonSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void CollisionPolygonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- CollisionPolygon *polygon = Object::cast_to<CollisionPolygon>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Vector<Vector2> points = polygon->get_polygon();
- float depth = polygon->get_depth() * 0.5;
-
- Vector<Vector3> lines;
- for (int i = 0; i < points.size(); i++) {
-
- int n = (i + 1) % points.size();
- lines.push_back(Vector3(points[i].x, points[i].y, depth));
- lines.push_back(Vector3(points[n].x, points[n].y, depth));
- lines.push_back(Vector3(points[i].x, points[i].y, -depth));
- lines.push_back(Vector3(points[n].x, points[n].y, -depth));
- lines.push_back(Vector3(points[i].x, points[i].y, depth));
- lines.push_back(Vector3(points[i].x, points[i].y, -depth));
- }
-
- const Ref<Material> material =
- get_material(!polygon->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
-
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_collision_segments(lines);
-}
-
-////
-
-NavigationMeshSpatialGizmoPlugin::NavigationMeshSpatialGizmoPlugin() {
- create_material("navigation_edge_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)));
- create_material("navigation_edge_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)));
- create_material("navigation_solid_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)));
- create_material("navigation_solid_material_disabled", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4)));
-}
-
-bool NavigationMeshSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<NavigationRegion>(p_spatial) != NULL;
-}
-
-String NavigationMeshSpatialGizmoPlugin::get_name() const {
- return "NavigationRegion";
-}
-
-int NavigationMeshSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void NavigationMeshSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
-
- NavigationRegion *navmesh = Object::cast_to<NavigationRegion>(p_gizmo->get_spatial_node());
-
- Ref<Material> edge_material = get_material("navigation_edge_material", p_gizmo);
- Ref<Material> edge_material_disabled = get_material("navigation_edge_material_disabled", p_gizmo);
- Ref<Material> solid_material = get_material("navigation_solid_material", p_gizmo);
- Ref<Material> solid_material_disabled = get_material("navigation_solid_material_disabled", p_gizmo);
-
- p_gizmo->clear();
- Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
- if (navmeshie.is_null())
- return;
-
- Vector<Vector3> vertices = navmeshie->get_vertices();
- const Vector3 *vr = vertices.ptr();
- List<Face3> faces;
- for (int i = 0; i < navmeshie->get_polygon_count(); i++) {
- Vector<int> p = navmeshie->get_polygon(i);
-
- for (int j = 2; j < p.size(); j++) {
- Face3 f;
- f.vertex[0] = vr[p[0]];
- f.vertex[1] = vr[p[j - 1]];
- f.vertex[2] = vr[p[j]];
-
- faces.push_back(f);
- }
- }
-
- if (faces.empty())
- return;
-
- Map<_EdgeKey, bool> edge_map;
- Vector<Vector3> tmeshfaces;
- tmeshfaces.resize(faces.size() * 3);
-
- {
- Vector3 *tw = tmeshfaces.ptrw();
- int tidx = 0;
-
- for (List<Face3>::Element *E = faces.front(); E; E = E->next()) {
-
- const Face3 &f = E->get();
-
- for (int j = 0; j < 3; j++) {
-
- tw[tidx++] = f.vertex[j];
- _EdgeKey ek;
- ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- if (ek.from < ek.to)
- SWAP(ek.from, ek.to);
-
- Map<_EdgeKey, bool>::Element *F = edge_map.find(ek);
-
- if (F) {
-
- F->get() = false;
-
- } else {
-
- edge_map[ek] = true;
- }
- }
- }
- }
- Vector<Vector3> lines;
-
- for (Map<_EdgeKey, bool>::Element *E = edge_map.front(); E; E = E->next()) {
-
- if (E->get()) {
- lines.push_back(E->key().from);
- lines.push_back(E->key().to);
- }
- }
-
- Ref<TriangleMesh> tmesh = memnew(TriangleMesh);
- tmesh->create(tmeshfaces);
-
- if (lines.size())
- p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled);
- p_gizmo->add_collision_triangles(tmesh);
- Ref<ArrayMesh> m = memnew(ArrayMesh);
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[0] = tmeshfaces;
- m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
- m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled);
- p_gizmo->add_mesh(m);
- p_gizmo->add_collision_segments(lines);
-}
-
-//////
-
-#define BODY_A_RADIUS 0.25
-#define BODY_B_RADIUS 0.27
-
-Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Transform &p_body_transform) {
- const Vector3 &p_eye(p_joint_transform.origin);
- const Vector3 &p_target(p_body_transform.origin);
-
- Vector3 v_x, v_y, v_z;
-
- // Look the body with X
- v_x = p_target - p_eye;
- v_x.normalize();
-
- v_z = v_x.cross(Vector3(0, 1, 0));
- v_z.normalize();
-
- v_y = v_z.cross(v_x);
- v_y.normalize();
-
- Basis base;
- base.set(v_x, v_y, v_z);
-
- // Absorb current joint transform
- base = p_joint_transform.basis.inverse() * base;
-
- return base;
-}
-
-Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform) {
-
- switch (p_axis) {
- case Vector3::AXIS_X:
- return look_body_toward_x(joint_transform, body_transform);
- case Vector3::AXIS_Y:
- return look_body_toward_y(joint_transform, body_transform);
- case Vector3::AXIS_Z:
- return look_body_toward_z(joint_transform, body_transform);
- default:
- return Basis();
- }
-}
-
-Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform) {
-
- const Vector3 &p_eye(p_joint_transform.origin);
- const Vector3 &p_target(p_body_transform.origin);
-
- const Vector3 p_front(p_joint_transform.basis.get_axis(0));
-
- Vector3 v_x, v_y, v_z;
-
- // Look the body with X
- v_x = p_target - p_eye;
- v_x.normalize();
-
- v_y = p_front.cross(v_x);
- v_y.normalize();
-
- v_z = v_y.cross(p_front);
- v_z.normalize();
-
- // Clamp X to FRONT axis
- v_x = p_front;
- v_x.normalize();
-
- Basis base;
- base.set(v_x, v_y, v_z);
-
- // Absorb current joint transform
- base = p_joint_transform.basis.inverse() * base;
-
- return base;
-}
-
-Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform) {
-
- const Vector3 &p_eye(p_joint_transform.origin);
- const Vector3 &p_target(p_body_transform.origin);
-
- const Vector3 p_up(p_joint_transform.basis.get_axis(1));
-
- Vector3 v_x, v_y, v_z;
-
- // Look the body with X
- v_x = p_target - p_eye;
- v_x.normalize();
-
- v_z = v_x.cross(p_up);
- v_z.normalize();
-
- v_x = p_up.cross(v_z);
- v_x.normalize();
-
- // Clamp Y to UP axis
- v_y = p_up;
- v_y.normalize();
-
- Basis base;
- base.set(v_x, v_y, v_z);
-
- // Absorb current joint transform
- base = p_joint_transform.basis.inverse() * base;
-
- return base;
-}
-
-Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform) {
-
- const Vector3 &p_eye(p_joint_transform.origin);
- const Vector3 &p_target(p_body_transform.origin);
-
- const Vector3 p_lateral(p_joint_transform.basis.get_axis(2));
-
- Vector3 v_x, v_y, v_z;
-
- // Look the body with X
- v_x = p_target - p_eye;
- v_x.normalize();
-
- v_z = p_lateral;
- v_z.normalize();
-
- v_y = v_z.cross(v_x);
- v_y.normalize();
-
- // Clamp X to Z axis
- v_x = v_y.cross(v_z);
- v_x.normalize();
-
- Basis base;
- base.set(v_x, v_y, v_z);
-
- // Absorb current joint transform
- base = p_joint_transform.basis.inverse() * base;
-
- return base;
-}
-
-void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) {
-
- if (p_limit_lower == p_limit_upper) {
-
- r_points.push_back(p_offset.translated(Vector3()).origin);
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(0.5, 0, 0))).origin);
-
- } else {
-
- if (p_limit_lower > p_limit_upper) {
- p_limit_lower = -Math_PI;
- p_limit_upper = Math_PI;
- }
-
- const int points = 32;
-
- for (int i = 0; i < points; i++) {
-
- real_t s = p_limit_lower + i * (p_limit_upper - p_limit_lower) / points;
- real_t n = p_limit_lower + (i + 1) * (p_limit_upper - p_limit_lower) / points;
-
- Vector3 from;
- Vector3 to;
- switch (p_axis) {
- case Vector3::AXIS_X:
- if (p_inverse) {
- from = p_base.xform(Vector3(0, Math::sin(s), Math::cos(s))) * p_radius;
- to = p_base.xform(Vector3(0, Math::sin(n), Math::cos(n))) * p_radius;
- } else {
- from = p_base.xform(Vector3(0, -Math::sin(s), Math::cos(s))) * p_radius;
- to = p_base.xform(Vector3(0, -Math::sin(n), Math::cos(n))) * p_radius;
- }
- break;
- case Vector3::AXIS_Y:
- if (p_inverse) {
- from = p_base.xform(Vector3(Math::cos(s), 0, -Math::sin(s))) * p_radius;
- to = p_base.xform(Vector3(Math::cos(n), 0, -Math::sin(n))) * p_radius;
- } else {
- from = p_base.xform(Vector3(Math::cos(s), 0, Math::sin(s))) * p_radius;
- to = p_base.xform(Vector3(Math::cos(n), 0, Math::sin(n))) * p_radius;
- }
- break;
- case Vector3::AXIS_Z:
- from = p_base.xform(Vector3(Math::cos(s), Math::sin(s), 0)) * p_radius;
- to = p_base.xform(Vector3(Math::cos(n), Math::sin(n), 0)) * p_radius;
- break;
- }
-
- if (i == points - 1) {
- r_points.push_back(p_offset.translated(to).origin);
- r_points.push_back(p_offset.translated(Vector3()).origin);
- }
- if (i == 0) {
- r_points.push_back(p_offset.translated(from).origin);
- r_points.push_back(p_offset.translated(Vector3()).origin);
- }
-
- r_points.push_back(p_offset.translated(from).origin);
- r_points.push_back(p_offset.translated(to).origin);
- }
-
- r_points.push_back(p_offset.translated(Vector3(0, p_radius * 1.5, 0)).origin);
- r_points.push_back(p_offset.translated(Vector3()).origin);
- }
-}
-
-void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) {
-
- float r = 1.0;
- float w = r * Math::sin(p_swing);
- float d = r * Math::cos(p_swing);
-
- //swing
- for (int i = 0; i < 360; i += 10) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 10);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
-
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin);
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, b.x, b.y))).origin);
-
- if (i % 90 == 0) {
-
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(d, a.x, a.y))).origin);
- r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin);
- }
- }
-
- r_points.push_back(p_offset.translated(p_base.xform(Vector3())).origin);
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(1, 0, 0))).origin);
-
- /// Twist
- float ts = Math::rad2deg(p_twist);
- ts = MIN(ts, 720);
-
- for (int i = 0; i < int(ts); i += 5) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 5);
- float c = i / 720.0;
- float cn = (i + 5) / 720.0;
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn;
-
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(c, a.x, a.y))).origin);
- r_points.push_back(p_offset.translated(p_base.xform(Vector3(cn, b.x, b.y))).origin);
- }
-}
-
-////
-
-JointSpatialGizmoPlugin::JointSpatialGizmoPlugin() {
- create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
- create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)));
- create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)));
-}
-
-bool JointSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<Joint>(p_spatial) != NULL;
-}
-
-String JointSpatialGizmoPlugin::get_name() const {
- return "Joints";
-}
-
-int JointSpatialGizmoPlugin::get_priority() const {
- return -1;
-}
-
-void JointSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
- Joint *joint = Object::cast_to<Joint>(p_gizmo->get_spatial_node());
-
- p_gizmo->clear();
-
- Spatial *node_body_a = NULL;
- if (!joint->get_node_a().is_empty()) {
- node_body_a = Object::cast_to<Spatial>(joint->get_node(joint->get_node_a()));
- }
-
- Spatial *node_body_b = NULL;
- if (!joint->get_node_b().is_empty()) {
- node_body_b = Object::cast_to<Spatial>(joint->get_node(joint->get_node_b()));
- }
-
- if (!node_body_a && !node_body_b) {
- return;
- }
-
- Ref<Material> common_material = get_material("joint_material", p_gizmo);
- Ref<Material> body_a_material = get_material("joint_body_a_material", p_gizmo);
- Ref<Material> body_b_material = get_material("joint_body_b_material", p_gizmo);
-
- Vector<Vector3> points;
- Vector<Vector3> body_a_points;
- Vector<Vector3> body_b_points;
-
- if (Object::cast_to<PinJoint>(joint)) {
- CreatePinJointGizmo(Transform(), points);
- p_gizmo->add_collision_segments(points);
- p_gizmo->add_lines(points, common_material);
- }
-
- HingeJoint *hinge = Object::cast_to<HingeJoint>(joint);
- if (hinge) {
-
- CreateHingeJointGizmo(
- Transform(),
- hinge->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
- hinge->get_param(HingeJoint::PARAM_LIMIT_LOWER),
- hinge->get_param(HingeJoint::PARAM_LIMIT_UPPER),
- hinge->get_flag(HingeJoint::FLAG_USE_LIMIT),
- points,
- node_body_a ? &body_a_points : NULL,
- node_body_b ? &body_b_points : NULL);
-
- p_gizmo->add_collision_segments(points);
- p_gizmo->add_collision_segments(body_a_points);
- p_gizmo->add_collision_segments(body_b_points);
-
- p_gizmo->add_lines(points, common_material);
- p_gizmo->add_lines(body_a_points, body_a_material);
- p_gizmo->add_lines(body_b_points, body_b_material);
- }
-
- SliderJoint *slider = Object::cast_to<SliderJoint>(joint);
- if (slider) {
-
- CreateSliderJointGizmo(
- Transform(),
- slider->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
- slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER),
- slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER),
- slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER),
- slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER),
- points,
- node_body_a ? &body_a_points : NULL,
- node_body_b ? &body_b_points : NULL);
-
- p_gizmo->add_collision_segments(points);
- p_gizmo->add_collision_segments(body_a_points);
- p_gizmo->add_collision_segments(body_b_points);
-
- p_gizmo->add_lines(points, common_material);
- p_gizmo->add_lines(body_a_points, body_a_material);
- p_gizmo->add_lines(body_b_points, body_b_material);
- }
-
- ConeTwistJoint *cone = Object::cast_to<ConeTwistJoint>(joint);
- if (cone) {
-
- CreateConeTwistJointGizmo(
- Transform(),
- cone->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
- cone->get_param(ConeTwistJoint::PARAM_SWING_SPAN),
- cone->get_param(ConeTwistJoint::PARAM_TWIST_SPAN),
- node_body_a ? &body_a_points : NULL,
- node_body_b ? &body_b_points : NULL);
-
- p_gizmo->add_collision_segments(body_a_points);
- p_gizmo->add_collision_segments(body_b_points);
-
- p_gizmo->add_lines(body_a_points, body_a_material);
- p_gizmo->add_lines(body_b_points, body_b_material);
- }
-
- Generic6DOFJoint *gen = Object::cast_to<Generic6DOFJoint>(joint);
- if (gen) {
-
- CreateGeneric6DOFJointGizmo(
- Transform(),
- gen->get_global_transform(),
- node_body_a ? node_body_a->get_global_transform() : Transform(),
- node_body_b ? node_body_b->get_global_transform() : Transform(),
-
- gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
- gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
- gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
- gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
- gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
- gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
-
- gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
- gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
- gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
- gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
- gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
- gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
-
- gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT),
- gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT),
- gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT),
- gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT),
- gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT),
- gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT),
-
- points,
- node_body_a ? &body_a_points : NULL,
- node_body_a ? &body_b_points : NULL);
-
- p_gizmo->add_collision_segments(points);
- p_gizmo->add_collision_segments(body_a_points);
- p_gizmo->add_collision_segments(body_b_points);
-
- p_gizmo->add_lines(points, common_material);
- p_gizmo->add_lines(body_a_points, body_a_material);
- p_gizmo->add_lines(body_b_points, body_b_material);
- }
-}
-
-void JointSpatialGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) {
- float cs = 0.25;
-
- r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin);
- r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin);
-}
-
-void JointSpatialGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
-
- r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
- r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
-
- if (!p_use_limit) {
- p_limit_upper = -1;
- p_limit_lower = 0;
- }
-
- if (r_body_a_points) {
-
- JointGizmosDrawer::draw_circle(Vector3::AXIS_Z,
- BODY_A_RADIUS,
- p_offset,
- JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_a),
- p_limit_lower,
- p_limit_upper,
- *r_body_a_points);
- }
-
- if (r_body_b_points) {
- JointGizmosDrawer::draw_circle(Vector3::AXIS_Z,
- BODY_B_RADIUS,
- p_offset,
- JointGizmosDrawer::look_body_toward_z(p_trs_joint, p_trs_body_b),
- p_limit_lower,
- p_limit_upper,
- *r_body_b_points);
- }
-}
-
-void JointSpatialGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
-
- p_linear_limit_lower = -p_linear_limit_lower;
- p_linear_limit_upper = -p_linear_limit_upper;
-
- float cs = 0.25;
- r_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin);
- r_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin);
-
- if (p_linear_limit_lower >= p_linear_limit_upper) {
-
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, 0, 0)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, 0, 0)).origin);
-
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, cs, -cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_upper, -cs, -cs)).origin);
-
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, cs, -cs)).origin);
- r_points.push_back(p_offset.translated(Vector3(p_linear_limit_lower, -cs, -cs)).origin);
-
- } else {
-
- r_points.push_back(p_offset.translated(Vector3(+cs * 2, 0, 0)).origin);
- r_points.push_back(p_offset.translated(Vector3(-cs * 2, 0, 0)).origin);
- }
-
- if (r_body_a_points)
- JointGizmosDrawer::draw_circle(
- Vector3::AXIS_X,
- BODY_A_RADIUS,
- p_offset,
- JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_a),
- p_angular_limit_lower,
- p_angular_limit_upper,
- *r_body_a_points);
-
- if (r_body_b_points)
- JointGizmosDrawer::draw_circle(
- Vector3::AXIS_X,
- BODY_B_RADIUS,
- p_offset,
- JointGizmosDrawer::look_body_toward(Vector3::AXIS_X, p_trs_joint, p_trs_body_b),
- p_angular_limit_lower,
- p_angular_limit_upper,
- *r_body_b_points,
- true);
-}
-
-void JointSpatialGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) {
-
- if (r_body_a_points)
- JointGizmosDrawer::draw_cone(
- p_offset,
- JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_a),
- p_swing,
- p_twist,
- *r_body_a_points);
-
- if (r_body_b_points)
- JointGizmosDrawer::draw_cone(
- p_offset,
- JointGizmosDrawer::look_body(p_trs_joint, p_trs_body_b),
- p_swing,
- p_twist,
- *r_body_b_points);
-}
-
-void JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo(
- const Transform &p_offset,
- const Transform &p_trs_joint,
- const Transform &p_trs_body_a,
- const Transform &p_trs_body_b,
- real_t p_angular_limit_lower_x,
- real_t p_angular_limit_upper_x,
- real_t p_linear_limit_lower_x,
- real_t p_linear_limit_upper_x,
- bool p_enable_angular_limit_x,
- bool p_enable_linear_limit_x,
- real_t p_angular_limit_lower_y,
- real_t p_angular_limit_upper_y,
- real_t p_linear_limit_lower_y,
- real_t p_linear_limit_upper_y,
- bool p_enable_angular_limit_y,
- bool p_enable_linear_limit_y,
- real_t p_angular_limit_lower_z,
- real_t p_angular_limit_upper_z,
- real_t p_linear_limit_lower_z,
- real_t p_linear_limit_upper_z,
- bool p_enable_angular_limit_z,
- bool p_enable_linear_limit_z,
- Vector<Vector3> &r_points,
- Vector<Vector3> *r_body_a_points,
- Vector<Vector3> *r_body_b_points) {
-
- float cs = 0.25;
-
- for (int ax = 0; ax < 3; ax++) {
- float ll = 0;
- float ul = 0;
- float lll = 0;
- float lul = 0;
-
- int a1 = 0;
- int a2 = 0;
- int a3 = 0;
- bool enable_ang = false;
- bool enable_lin = false;
-
- switch (ax) {
- case 0:
- ll = p_angular_limit_lower_x;
- ul = p_angular_limit_upper_x;
- lll = -p_linear_limit_lower_x;
- lul = -p_linear_limit_upper_x;
- enable_ang = p_enable_angular_limit_x;
- enable_lin = p_enable_linear_limit_x;
- a1 = 0;
- a2 = 1;
- a3 = 2;
- break;
- case 1:
- ll = p_angular_limit_lower_y;
- ul = p_angular_limit_upper_y;
- lll = -p_linear_limit_lower_y;
- lul = -p_linear_limit_upper_y;
- enable_ang = p_enable_angular_limit_y;
- enable_lin = p_enable_linear_limit_y;
- a1 = 1;
- a2 = 2;
- a3 = 0;
- break;
- case 2:
- ll = p_angular_limit_lower_z;
- ul = p_angular_limit_upper_z;
- lll = -p_linear_limit_lower_z;
- lul = -p_linear_limit_upper_z;
- enable_ang = p_enable_angular_limit_z;
- enable_lin = p_enable_linear_limit_z;
- a1 = 2;
- a2 = 0;
- a3 = 1;
- break;
- }
-
-#define ADD_VTX(x, y, z) \
- { \
- Vector3 v; \
- v[a1] = (x); \
- v[a2] = (y); \
- v[a3] = (z); \
- r_points.push_back(p_offset.translated(v).origin); \
- }
-
- if (enable_lin && lll >= lul) {
-
- ADD_VTX(lul, 0, 0);
- ADD_VTX(lll, 0, 0);
-
- ADD_VTX(lul, -cs, -cs);
- ADD_VTX(lul, -cs, cs);
- ADD_VTX(lul, -cs, cs);
- ADD_VTX(lul, cs, cs);
- ADD_VTX(lul, cs, cs);
- ADD_VTX(lul, cs, -cs);
- ADD_VTX(lul, cs, -cs);
- ADD_VTX(lul, -cs, -cs);
-
- ADD_VTX(lll, -cs, -cs);
- ADD_VTX(lll, -cs, cs);
- ADD_VTX(lll, -cs, cs);
- ADD_VTX(lll, cs, cs);
- ADD_VTX(lll, cs, cs);
- ADD_VTX(lll, cs, -cs);
- ADD_VTX(lll, cs, -cs);
- ADD_VTX(lll, -cs, -cs);
-
- } else {
-
- ADD_VTX(+cs * 2, 0, 0);
- ADD_VTX(-cs * 2, 0, 0);
- }
-
- if (!enable_ang) {
- ll = 0;
- ul = -1;
- }
-
- if (r_body_a_points)
- JointGizmosDrawer::draw_circle(
- static_cast<Vector3::Axis>(ax),
- BODY_A_RADIUS,
- p_offset,
- JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_a),
- ll,
- ul,
- *r_body_a_points,
- true);
-
- if (r_body_b_points)
- JointGizmosDrawer::draw_circle(
- static_cast<Vector3::Axis>(ax),
- BODY_B_RADIUS,
- p_offset,
- JointGizmosDrawer::look_body_toward(static_cast<Vector3::Axis>(ax), p_trs_joint, p_trs_body_b),
- ll,
- ul,
- *r_body_b_points);
- }
-
-#undef ADD_VTX
-}
diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h
deleted file mode 100644
index b786aa2b50..0000000000
--- a/editor/spatial_editor_gizmos.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/*************************************************************************/
-/* spatial_editor_gizmos.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPATIAL_EDITOR_GIZMOS_H
-#define SPATIAL_EDITOR_GIZMOS_H
-
-#include "editor/plugins/spatial_editor_plugin.h"
-#include "scene/3d/camera.h"
-
-class Camera;
-
-class LightSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(LightSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- LightSpatialGizmoPlugin();
-};
-
-class AudioStreamPlayer3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(AudioStreamPlayer3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- AudioStreamPlayer3DSpatialGizmoPlugin();
-};
-
-class CameraSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(CameraSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- CameraSpatialGizmoPlugin();
-};
-
-class MeshInstanceSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(MeshInstanceSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- bool can_be_hidden() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- MeshInstanceSpatialGizmoPlugin();
-};
-
-class Sprite3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(Sprite3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- bool can_be_hidden() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- Sprite3DSpatialGizmoPlugin();
-};
-
-class Position3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(Position3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
- Ref<ArrayMesh> pos3d_mesh;
- Vector<Vector3> cursor_points;
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- Position3DSpatialGizmoPlugin();
-};
-
-class SkeletonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(SkeletonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- SkeletonSpatialGizmoPlugin();
-};
-
-class PhysicalBoneSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(PhysicalBoneSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- PhysicalBoneSpatialGizmoPlugin();
-};
-
-class RayCastSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(RayCastSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- RayCastSpatialGizmoPlugin();
-};
-
-class SpringArmSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(SpringArmSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- SpringArmSpatialGizmoPlugin();
-};
-
-class VehicleWheelSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(VehicleWheelSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- VehicleWheelSpatialGizmoPlugin();
-};
-
-class SoftBodySpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(SoftBodySpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- bool is_selectable_when_hidden() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
- bool is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const;
-
- SoftBodySpatialGizmoPlugin();
-};
-
-class VisibilityNotifierGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(VisibilityNotifierGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- VisibilityNotifierGizmoPlugin();
-};
-
-class CPUParticlesGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(CPUParticlesGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- bool is_selectable_when_hidden() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
- CPUParticlesGizmoPlugin();
-};
-
-class ParticlesGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(ParticlesGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- bool is_selectable_when_hidden() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- ParticlesGizmoPlugin();
-};
-
-class ReflectionProbeGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(ReflectionProbeGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- ReflectionProbeGizmoPlugin();
-};
-
-class GIProbeGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(GIProbeGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- GIProbeGizmoPlugin();
-};
-
-#if 0
-class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(BakedIndirectLightGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- BakedIndirectLightGizmoPlugin();
-};
-#endif
-class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false);
-
- CollisionShapeSpatialGizmoPlugin();
-};
-
-class CollisionPolygonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(CollisionPolygonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
- CollisionPolygonSpatialGizmoPlugin();
-};
-
-class NavigationMeshSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(NavigationMeshSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
- struct _EdgeKey {
-
- Vector3 from;
- Vector3 to;
-
- bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; }
- };
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- NavigationMeshSpatialGizmoPlugin();
-};
-
-class JointGizmosDrawer {
-public:
- static Basis look_body(const Transform &p_joint_transform, const Transform &p_body_transform);
- static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform);
- static Basis look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform);
- static Basis look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform);
- /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis
- /// with axis X and Y that are looking toward the body and oriented toward up
- static Basis look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform);
-
- // Draw circle around p_axis
- static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse = false);
- static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points);
-};
-
-class JointSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
- GDCLASS(JointSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
-
-public:
- bool has_gizmo(Spatial *p_spatial);
- String get_name() const;
- int get_priority() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
-
- static void CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points);
- static void CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
- static void CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
- static void CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points);
- static void CreateGeneric6DOFJointGizmo(
- const Transform &p_offset,
- const Transform &p_trs_joint,
- const Transform &p_trs_body_a,
- const Transform &p_trs_body_b,
- real_t p_angular_limit_lower_x,
- real_t p_angular_limit_upper_x,
- real_t p_linear_limit_lower_x,
- real_t p_linear_limit_upper_x,
- bool p_enable_angular_limit_x,
- bool p_enable_linear_limit_x,
- real_t p_angular_limit_lower_y,
- real_t p_angular_limit_upper_y,
- real_t p_linear_limit_lower_y,
- real_t p_linear_limit_upper_y,
- bool p_enable_angular_limit_y,
- bool p_enable_linear_limit_y,
- real_t p_angular_limit_lower_z,
- real_t p_angular_limit_upper_z,
- real_t p_linear_limit_lower_z,
- real_t p_linear_limit_upper_z,
- bool p_enable_angular_limit_z,
- bool p_enable_linear_limit_z,
- Vector<Vector3> &r_points,
- Vector<Vector3> *r_body_a_points,
- Vector<Vector3> *r_body_b_points);
-
- JointSpatialGizmoPlugin();
-};
-
-#endif // SPATIAL_EDITOR_GIZMOS_H
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index 15d4265ef4..304fa8905b 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -11,12 +11,13 @@
# Adolfo Jayme Barrientos <fitojb@ubuntu.com>, 2020.
# Xavier Gomez <hiulit@gmail.com>, 2020.
# Aina <ainasoga@gmail.com>, 2020.
+# Alex Mancha <codingstain@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-02-07 10:32+0000\n"
-"Last-Translator: Roger Blanco Ribera <roger.blancoribera@gmail.com>\n"
+"PO-Revision-Date: 2020-03-11 12:20+0000\n"
+"Last-Translator: Alex Mancha <codingstain@gmail.com>\n"
"Language-Team: Catalan <https://hosted.weblate.org/projects/godot-engine/"
"godot/ca/>\n"
"Language: ca\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 3.11-dev\n"
+"X-Generator: Weblate 4.0-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -694,9 +695,8 @@ msgid "Line Number:"
msgstr "Línia:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Substitueix..."
+msgstr "%d reemplaçat."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
@@ -2756,7 +2756,6 @@ msgid "Set Up Version Control"
msgstr "Configurar Control de Versions"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Shut Down Version Control"
msgstr "Desactivar el control de versions"
@@ -5974,7 +5973,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create a single convex collision shape."
-msgstr ""
+msgstr "No s'ha pogut crear una capa de col·lisió convexa."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index f3ae992410..595db1837f 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -22,7 +22,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-01 05:50+0000\n"
+"PO-Revision-Date: 2020-03-12 23:33+0000\n"
"Last-Translator: Vojtěch Šamla <auzkok@seznam.cz>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
@@ -1117,7 +1117,7 @@ msgstr "Děkujeme za komunitu Godotu!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr "Přispívající do Godot Enginu"
+msgstr "Přispěvatelé do Godot Enginu"
#: editor/editor_about.cpp
msgid "Project Founders"
@@ -9907,7 +9907,6 @@ msgid "Can't run project"
msgstr "Nelze spustit projekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"You currently don't have any projects.\n"
"Would you like to explore official example projects in the Asset Library?"
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 14d9926ecb..1520c3aa2a 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -53,8 +53,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-08 22:32+0000\n"
-"Last-Translator: PagDev <pag.develop@gmail.com>\n"
+"PO-Revision-Date: 2020-03-14 15:05+0000\n"
+"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -6029,9 +6029,8 @@ msgstr ""
"Dies ist die präziseste (aber langsamste) Methode für Kollisionsberechnungen."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
-msgstr "Ein einzelnes konvexes Kollisionsunterelement erzeugen"
+msgstr "Ein einzelnes konvexes Kollisionsnachbarelement erzeugen"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -12483,7 +12482,7 @@ msgstr ""
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
-msgstr ""
+msgstr "ConcavePolygonShape unterstützt RigidBody nur im Modus Statisch."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/es.po b/editor/translations/es.po
index ed82e80658..3bbe96bcb3 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -47,7 +47,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-02-27 07:01+0000\n"
+"PO-Revision-Date: 2020-03-11 12:20+0000\n"
"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
@@ -6027,9 +6027,8 @@ msgstr ""
"Es la opción más precisa (pero la más lenta) para la detección de colisiones."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
-msgstr "Crear una Única Colisión Convexa Hermana"
+msgstr "Crear Colisión Convexa Única Hermana"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -12481,6 +12480,7 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape no soporta RigidBody de otro modo que no sea estático."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index dce0d89b7e..7781d59f34 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -18,7 +18,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-02-27 07:01+0000\n"
+"PO-Revision-Date: 2020-03-11 12:20+0000\n"
"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
@@ -5991,9 +5991,8 @@ msgstr ""
"Esta es la opción mas exacta (pero más lenta) de detección de colisiones."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
-msgstr "Crear Colisión Convexa Unica como Nodo Hermano"
+msgstr "Crear Colisión Convexa Única Hermana"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -12435,6 +12434,7 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape no soporta RigidBody de otro modo que no sea estático."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/extract.py b/editor/translations/extract.py
index e7ebda32df..749bad5fff 100755
--- a/editor/translations/extract.py
+++ b/editor/translations/extract.py
@@ -10,23 +10,23 @@ import sys
line_nb = False
for arg in sys.argv[1:]:
- if (arg == "--with-line-nb"):
+ if arg == "--with-line-nb":
print("Enabling line numbers in the context locations.")
line_nb = True
else:
os.sys.exit("Non supported argument '" + arg + "'. Aborting.")
-if (not os.path.exists("editor")):
+if not os.path.exists("editor"):
os.sys.exit("ERROR: This script should be started from the root of the git repo.")
matches = []
-for root, dirnames, filenames in os.walk('.'):
+for root, dirnames, filenames in os.walk("."):
dirnames[:] = [d for d in dirnames if d not in ["thirdparty"]]
- for filename in fnmatch.filter(filenames, '*.cpp'):
+ for filename in fnmatch.filter(filenames, "*.cpp"):
matches.append(os.path.join(root, filename))
- for filename in fnmatch.filter(filenames, '*.h'):
+ for filename in fnmatch.filter(filenames, "*.h"):
matches.append(os.path.join(root, filename))
matches.sort()
@@ -34,7 +34,7 @@ matches.sort()
unique_str = []
unique_loc = {}
main_po = """
-# LANGUAGE translation of the Godot Engine editor
+# LANGUAGE translation of the Godot Engine editor.
# Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.
# Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).
# This file is distributed under the same license as the Godot source code.
@@ -45,56 +45,60 @@ main_po = """
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\\n"
+"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\\n"
+"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8-bit\\n"
"""
+
def process_file(f, fname):
global main_po, unique_str, unique_loc
l = f.readline()
lc = 1
- while (l):
+ while l:
- patterns = ['RTR(\"', 'TTR(\"', 'TTRC(\"']
+ patterns = ['RTR("', 'TTR("', 'TTRC("']
idx = 0
pos = 0
- while (pos >= 0):
+ while pos >= 0:
pos = l.find(patterns[idx], pos)
- if (pos == -1):
- if (idx < len(patterns) - 1):
+ if pos == -1:
+ if idx < len(patterns) - 1:
idx += 1
pos = 0
continue
pos += len(patterns[idx])
msg = ""
- while (pos < len(l) and (l[pos] != '"' or l[pos - 1] == '\\')):
+ while pos < len(l) and (l[pos] != '"' or l[pos - 1] == "\\"):
msg += l[pos]
pos += 1
- location = os.path.relpath(fname).replace('\\', '/')
- if (line_nb):
+ location = os.path.relpath(fname).replace("\\", "/")
+ if line_nb:
location += ":" + str(lc)
- if (not msg in unique_str):
+ if not msg in unique_str:
main_po += "\n#: " + location + "\n"
main_po += 'msgid "' + msg + '"\n'
main_po += 'msgstr ""\n'
unique_str.append(msg)
unique_loc[msg] = [location]
- elif (not location in unique_loc[msg]):
+ elif not location in unique_loc[msg]:
# Add additional location to previous occurrence too
msg_pos = main_po.find('\nmsgid "' + msg + '"')
- if (msg_pos == -1):
+ if msg_pos == -1:
print("Someone apparently thought writing Python was as easy as GDScript. Ping Akien.")
- main_po = main_po[:msg_pos] + ' ' + location + main_po[msg_pos:]
+ main_po = main_po[:msg_pos] + " " + location + main_po[msg_pos:]
unique_loc[msg].append(location)
l = f.readline()
lc += 1
+
print("Updating the editor.pot template...")
for fname in matches:
@@ -104,7 +108,7 @@ for fname in matches:
with open("editor.pot", "w") as f:
f.write(main_po)
-if (os.name == "posix"):
+if os.name == "posix":
print("Wrapping template at 79 characters for compatibility with Weblate.")
os.system("msgmerge -w79 editor.pot editor.pot > editor.pot.wrap")
shutil.move("editor.pot.wrap", "editor.pot")
@@ -112,7 +116,7 @@ if (os.name == "posix"):
shutil.move("editor.pot", "editor/translations/editor.pot")
# TODO: Make that in a portable way, if we care; if not, kudos to Unix users
-if (os.name == "posix"):
+if os.name == "posix":
added = subprocess.check_output(r"git diff editor/translations/editor.pot | grep \+msgid | wc -l", shell=True)
removed = subprocess.check_output(r"git diff editor/translations/editor.pot | grep \\\-msgid | wc -l", shell=True)
print("\n# Template changes compared to the staged status:")
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index d590546571..2798d56d28 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-02-21 23:33+0000\n"
+"PO-Revision-Date: 2020-03-14 15:05+0000\n"
"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
@@ -23,7 +23,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 3.11.1\n"
+"X-Generator: Weblate 4.0-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -5945,9 +5945,8 @@ msgstr ""
"Tämä on tarkin (mutta hitain) vaihtoehto törmäystunnistukselle."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
-msgstr "Luo yksittäisen konveksin törmäysmuodon sisaret"
+msgstr "Luo yksittäisen konveksin törmäyksen sisar"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -12362,6 +12361,7 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape ei tue RigidBody solmua muussa kuin staattisessa tilassa."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index 3c14b17b53..0bb76f1261 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -35,7 +35,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-05 08:33+0000\n"
+"PO-Revision-Date: 2020-03-16 09:43+0000\n"
"Last-Translator: Akihiro Ogoshi <technical@palsystem-game.com>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
@@ -908,7 +908,7 @@ msgstr "切断"
#: editor/connections_dialog.cpp
msgid "Connect a Signal to a Method"
-msgstr "メソッドにシグナルを接続する"
+msgstr "メソッドにシグナルを接続"
#: editor/connections_dialog.cpp
msgid "Edit Connection:"
@@ -5834,7 +5834,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"
@@ -5854,7 +5854,7 @@ msgstr "メッシュがありません!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create a Trimesh collision shape."
-msgstr "トライメッシュコリジョンシェイプを作成できませんでした。"
+msgstr "三角形メッシュ コリジョンシェイプを作成できませんでした。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Static Trimesh Body"
@@ -5954,7 +5954,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Collision Sibling"
-msgstr "三角形メッシュ兄弟コリジョンを生成"
+msgstr "三角形メッシュ コリジョンの兄弟を作成"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -5965,7 +5965,6 @@ msgstr ""
"これは、衝突検出の最も正確な(ただし最も遅い)オプションです。"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
msgstr "単一の凸型コリジョンの兄弟を作成"
@@ -5979,7 +5978,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
-msgstr "複数の凸型コリジョンの兄弟を作成する"
+msgstr "複数の凸型コリジョンの兄弟を作成"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -7654,7 +7653,7 @@ msgstr "ジオメトリが無効です。衝突ポリゴンを作成できませ
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create CollisionPolygon2D Sibling"
-msgstr "CollisionPolygon2Dの兄弟を作成する"
+msgstr "CollisionPolygon2Dの兄弟を作成"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create light occluder."
@@ -7662,7 +7661,7 @@ msgstr "ジオメトリが無効です。ライトオクールダーを作成で
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create LightOccluder2D Sibling"
-msgstr "LightOccluder2Dの兄弟を作成する"
+msgstr "LightOccluder2Dの兄弟を作成"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
@@ -11936,9 +11935,9 @@ msgid ""
" Godot Version: %s\n"
"Please reinstall Android build template from 'Project' menu."
msgstr ""
-"Androidビルドバージョンの不一致:\n"
-"インストールされたテンプレート:%s\n"
-"ゴドーバージョン:%s\n"
+"Androidビルド バージョンの不一致:\n"
+" インストールされたテンプレート: %s\n"
+" Godot バージョン: %s\n"
"「プロジェクト 」メニューからAndroidビルドテンプレートを再インストールしてく"
"ださい。"
@@ -11952,7 +11951,7 @@ msgid ""
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
"Androidプロジェクトのビルドに失敗しました。エラーの出力を確認してください。\n"
-"あるいは、Androidビルドドキュメントについてはdocs.godotengine.orgをご覧くださ"
+"また、Androidビルドについてのドキュメントは docs.godotengine.org をご覧くださ"
"い。"
#: platform/android/export/export.cpp
@@ -12372,6 +12371,8 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape は、Static 以外のモードの RigidBody をサポートしていませ"
+"ん。"
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index 37c950097b..ec33599440 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-05 08:33+0000\n"
+"PO-Revision-Date: 2020-03-14 00:33+0000\n"
"Last-Translator: Ch. <ccwpc@hanmail.net>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
@@ -12271,6 +12271,8 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape는 static 외의 모드가 설정된 RigidBody를 지원하지 않습니"
+"다."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index dc0a5aa151..14dfdff801 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -4,12 +4,13 @@
# This file is distributed under the same license as the Godot source code.
# Gustavs Porietis (pg829-) <porietisgustavs@gmail.com>, 2018.
# Martch Zagorski <martchzagorski@gmail.com>, 2018.
+# Jānis Ondzuls <janisond@inbox.lv>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2018-12-13 14:41+0100\n"
-"Last-Translator: Martch Zagorski <martchzagorski@gmail.com>\n"
+"PO-Revision-Date: 2020-03-11 12:20+0000\n"
+"Last-Translator: Jānis Ondzuls <janisond@inbox.lv>\n"
"Language-Team: Latvian <https://hosted.weblate.org/projects/godot-engine/"
"godot/lv/>\n"
"Language: lv\n"
@@ -18,7 +19,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n % 10 == 0 || n % 100 >= 11 && n % 100 <= "
"19) ? 0 : ((n % 10 == 1 && n % 100 != 11) ? 1 : 2);\n"
-"X-Generator: Poedit 2.2\n"
+"X-Generator: Weblate 4.0-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -65,31 +66,31 @@ msgstr ""
#: core/ustring.cpp
msgid "B"
-msgstr ""
+msgstr "B"
#: core/ustring.cpp
msgid "KiB"
-msgstr ""
+msgstr "KiB"
#: core/ustring.cpp
msgid "MiB"
-msgstr ""
+msgstr "MiB"
#: core/ustring.cpp
msgid "GiB"
-msgstr ""
+msgstr "GiB"
#: core/ustring.cpp
msgid "TiB"
-msgstr ""
+msgstr "TiB"
#: core/ustring.cpp
msgid "PiB"
-msgstr ""
+msgstr "PiB"
#: core/ustring.cpp
msgid "EiB"
-msgstr ""
+msgstr "EiB"
#: editor/animation_bezier_editor.cpp
msgid "Free"
@@ -101,29 +102,27 @@ msgstr "Balancēts"
#: editor/animation_bezier_editor.cpp
msgid "Mirror"
-msgstr ""
+msgstr "Spogulis"
#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
msgid "Time:"
-msgstr ""
+msgstr "Laiks:"
#: editor/animation_bezier_editor.cpp
msgid "Value:"
-msgstr ""
+msgstr "Vērtība:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
-msgstr ""
+msgstr "Ievadiet vērtību šeit"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Duplicate Selected Key(s)"
-msgstr "Dublikāta Izvēle"
+msgstr "Dublikāta Vērtības"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Delete Selected Key(s)"
-msgstr "Izdzēst izvēlētos failus?"
+msgstr "Izdzēst izvēlēto(ās) vērtību(as)?"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
@@ -682,7 +681,7 @@ msgstr ""
#: editor/array_property_edit.cpp
msgid "Change Array Value"
-msgstr ""
+msgstr "Izmainīt masīva vērtību"
#: editor/code_editor.cpp
msgid "Go to Line"
@@ -690,20 +689,19 @@ msgstr "Doties uz Rindu"
#: editor/code_editor.cpp
msgid "Line Number:"
-msgstr ""
+msgstr "Rindas Numurs:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Aizvietot"
+msgstr "%d aizvietots."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
-msgstr ""
+msgstr "%d sakritība."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d matches."
-msgstr ""
+msgstr "%d sakritības."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -719,16 +717,16 @@ msgstr "Aizvietot"
#: editor/code_editor.cpp
msgid "Replace All"
-msgstr ""
+msgstr "Aizvietot visu"
#: editor/code_editor.cpp
msgid "Selection Only"
-msgstr ""
+msgstr "Tikai izvēlētais"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
msgid "Standard"
-msgstr ""
+msgstr "Standarts"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 458ff0b5b8..a729ea6119 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -44,7 +44,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-08 22:33+0000\n"
+"PO-Revision-Date: 2020-03-16 09:43+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"
@@ -12434,7 +12434,7 @@ msgstr ""
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
-msgstr ""
+msgstr "ConcavePolygonShape ondersteunt RigidBody alleen in statische modus."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 14bbb799aa..de1d6d5375 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -42,7 +42,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-08 22:33+0000\n"
+"PO-Revision-Date: 2020-03-16 09:43+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
@@ -5981,7 +5981,6 @@ msgstr ""
"To jest najdokładniejsza (ale najwolniejsza) opcja do detekcji kolizji."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
msgstr "Utwórz pojedynczego wypukłego sąsiada kolizji"
@@ -12400,6 +12399,8 @@ msgstr ""
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape nie obsługuje węzła RigidBody w innym trybie niż "
+"statyczny."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/pt_PT.po b/editor/translations/pt_PT.po
index 60009b3171..d7532e38d4 100644
--- a/editor/translations/pt_PT.po
+++ b/editor/translations/pt_PT.po
@@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-02-18 15:09+0000\n"
+"PO-Revision-Date: 2020-03-16 09:43+0000\n"
"Last-Translator: João Lopes <linux-man@hotmail.com>\n"
"Language-Team: Portuguese (Portugal) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_PT/>\n"
@@ -28,7 +28,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 3.11\n"
+"X-Generator: Weblate 4.0-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -5958,7 +5958,6 @@ msgstr ""
"Esta é a mais precisa (mas mais lenta) opção para deteção de colisão."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Collision Sibling"
msgstr "Criar Irmãos Únicos de Colisão Convexa"
@@ -12362,7 +12361,7 @@ msgstr ""
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
-msgstr ""
+msgstr "ConcavePolygonShape apenas suporta RigidBody no modo estático."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index b05077637a..d3402fd63e 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -66,12 +66,13 @@
# Artur Tretiak <stikyt@protonmail.com>, 2020.
# Smadjavul <o1985af@gmail.com>, 2020.
# anonymous <noreply@weblate.org>, 2020.
+# Vinsent Insaider_red <vinsent.in7aider@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-03-07 21:18+0000\n"
-"Last-Translator: Smadjavul <o1985af@gmail.com>\n"
+"PO-Revision-Date: 2020-03-11 12:20+0000\n"
+"Last-Translator: Vinsent Insaider_red <vinsent.in7aider@gmail.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
"Language: ru\n"
@@ -98,9 +99,8 @@ msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr "Недостаточно байтов для декодирования байтов или неверный формат."
#: core/math/expression.cpp
-#, fuzzy
msgid "Invalid input %i (not passed) in expression"
-msgstr "Некорректный ввод %i (не был передан) в выражении"
+msgstr "Некорректный ввод %i (не подходит) в выражении"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index c73724c7b7..83eb878d8c 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -42,12 +42,13 @@
# Muhammet Mustafa Tozlu <m.mustafatozlu@gmail.com>, 2019.
# HALİL ATAŞ <halillatass@gmail.com>, 2019.
# Zsosu Ktosu <zktosu@gmail.com>, 2020.
+# Mesut Aslan <kontinyu@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-01-30 03:56+0000\n"
-"Last-Translator: Zsosu Ktosu <zktosu@gmail.com>\n"
+"PO-Revision-Date: 2020-03-11 12:20+0000\n"
+"Last-Translator: Mesut Aslan <kontinyu@gmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -55,7 +56,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 3.11-dev\n"
+"X-Generator: Weblate 4.0-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -726,9 +727,8 @@ msgid "Line Number:"
msgstr "Satır Numarası:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Değiştir..."
+msgstr "%d değiştirildi."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
@@ -3989,9 +3989,8 @@ msgid "Saving..."
msgstr "Kaydediliyor..."
#: editor/import_dock.cpp
-#, fuzzy
msgid "%d Files"
-msgstr " Dosyalar"
+msgstr "%d Dosya"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
@@ -5870,9 +5869,8 @@ msgid "Mesh is empty!"
msgstr "Örüntü boş!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Couldn't create a Trimesh collision shape."
-msgstr "Üçlü Örüntü Çarpışma Kardeşi Oluştur"
+msgstr "Trimesh çarpışma şekli oluşturulamadı."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Static Trimesh Body"
@@ -5888,25 +5886,23 @@ msgstr "Üçlü Örüntü Yüzeyi Oluştur"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Can't create a single convex collision shape for the scene root."
-msgstr ""
+msgstr "Sahne kökü için tek bir dışbükey çarpışma şekli oluşturulamaz."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create a single convex collision shape."
-msgstr ""
+msgstr "Tek dışbükey çarpışma şekli oluşturulamadı."
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Create Single Convex Shape"
-msgstr "Dışbükey Şekil[ler] Oluştur"
+msgstr "Tekil Dışbükey Şekil Oluştur"
#: 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
-#, fuzzy
msgid "Couldn't create any collision shapes."
-msgstr "Klasör oluşturulamadı."
+msgstr "Herhangi bir çarpışma şekli oluşturulamadı."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -5977,6 +5973,8 @@ msgid ""
"Creates a polygon-based collision shape.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Poligon bazlı bir çarpışma şekli oluştur.\n"
+"Bu en hassas (fakat en yavaş) çarpışma algılama seçeneğidir."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
diff --git a/gles_builders.py b/gles_builders.py
index 92cf9357cf..6ff2f4248b 100644
--- a/gles_builders.py
+++ b/gles_builders.py
@@ -7,7 +7,6 @@ from platform_methods import subprocess_main
class LegacyGLHeaderStruct:
-
def __init__(self):
self.vertex_lines = []
self.fragment_lines = []
@@ -73,7 +72,7 @@ def include_file_in_legacygl_header(filename, header_data, depth):
ifdefline = line.replace("#ifdef ", "").strip()
if line.find("_EN_") != -1:
- enumbase = ifdefline[:ifdefline.find("_EN_")]
+ enumbase = ifdefline[: ifdefline.find("_EN_")]
ifdefline = ifdefline.replace("_EN_", "_")
line = line.replace("_EN_", "_")
if enumbase not in header_data.enums:
@@ -86,12 +85,12 @@ def include_file_in_legacygl_header(filename, header_data, depth):
if line.find("uniform") != -1 and line.lower().find("texunit:") != -1:
# texture unit
- texunitstr = line[line.find(":") + 1:].strip()
+ texunitstr = line[line.find(":") + 1 :].strip()
if texunitstr == "auto":
texunit = "-1"
else:
texunit = str(int(texunitstr))
- uline = line[:line.lower().find("//")]
+ uline = line[: line.lower().find("//")]
uline = uline.replace("uniform", "")
uline = uline.replace("highp", "")
uline = uline.replace(";", "")
@@ -99,10 +98,10 @@ def include_file_in_legacygl_header(filename, header_data, depth):
for x in lines:
x = x.strip()
- x = x[x.rfind(" ") + 1:]
+ x = x[x.rfind(" ") + 1 :]
if x.find("[") != -1:
# unfiorm array
- x = x[:x.find("[")]
+ x = x[: x.find("[")]
if not x in header_data.texunit_names:
header_data.texunits += [(x, texunit)]
@@ -110,10 +109,10 @@ def include_file_in_legacygl_header(filename, header_data, depth):
elif line.find("uniform") != -1 and line.lower().find("ubo:") != -1:
# uniform buffer object
- ubostr = line[line.find(":") + 1:].strip()
+ ubostr = line[line.find(":") + 1 :].strip()
ubo = str(int(ubostr))
- uline = line[:line.lower().find("//")]
- uline = uline[uline.find("uniform") + len("uniform"):]
+ uline = line[: line.lower().find("//")]
+ uline = uline[uline.find("uniform") + len("uniform") :]
uline = uline.replace("highp", "")
uline = uline.replace(";", "")
uline = uline.replace("{", "").strip()
@@ -121,10 +120,10 @@ def include_file_in_legacygl_header(filename, header_data, depth):
for x in lines:
x = x.strip()
- x = x[x.rfind(" ") + 1:]
+ x = x[x.rfind(" ") + 1 :]
if x.find("[") != -1:
# unfiorm array
- x = x[:x.find("[")]
+ x = x[: x.find("[")]
if not x in header_data.ubo_names:
header_data.ubos += [(x, ubo)]
@@ -137,10 +136,10 @@ def include_file_in_legacygl_header(filename, header_data, depth):
for x in lines:
x = x.strip()
- x = x[x.rfind(" ") + 1:]
+ x = x[x.rfind(" ") + 1 :]
if x.find("[") != -1:
# unfiorm array
- x = x[:x.find("[")]
+ x = x[: x.find("[")]
if not x in header_data.uniforms:
header_data.uniforms += [x]
@@ -150,7 +149,7 @@ def include_file_in_legacygl_header(filename, header_data, depth):
uline = uline.replace("attribute ", "")
uline = uline.replace("highp ", "")
uline = uline.replace(";", "")
- uline = uline[uline.find(" "):].strip()
+ uline = uline[uline.find(" ") :].strip()
if uline.find("//") != -1:
name, bind = uline.split("//")
@@ -163,7 +162,7 @@ def include_file_in_legacygl_header(filename, header_data, depth):
uline = line.replace("out ", "")
uline = uline.replace("highp ", "")
uline = uline.replace(";", "")
- uline = uline[uline.find(" "):].strip()
+ uline = uline[uline.find(" ") :].strip()
if uline.find("//") != -1:
name, bind = uline.split("//")
@@ -200,17 +199,19 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
out_file_base = out_file
- out_file_base = out_file_base[out_file_base.rfind("/") + 1:]
- out_file_base = out_file_base[out_file_base.rfind("\\") + 1:]
+ out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
+ out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
out_file_ifdef = out_file_base.replace(".", "_").upper()
fd.write("#ifndef " + out_file_ifdef + class_suffix + "_120\n")
fd.write("#define " + out_file_ifdef + class_suffix + "_120\n")
- out_file_class = out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "Shader" + class_suffix
+ out_file_class = (
+ out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "Shader" + class_suffix
+ )
fd.write("\n\n")
- fd.write("#include \"" + include + "\"\n\n\n")
+ fd.write('#include "' + include + '"\n\n\n')
fd.write("class " + out_file_class + " : public Shader" + class_suffix + " {\n\n")
- fd.write("\t virtual String get_shader_name() const { return \"" + out_file_class + "\"; }\n")
+ fd.write('\t virtual String get_shader_name() const { return "' + out_file_class + '"; }\n')
fd.write("public:\n\n")
@@ -228,29 +229,64 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n")
if header_data.conditionals:
- fd.write("\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n")
+ fd.write(
+ "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n"
+ )
fd.write("\t#ifdef DEBUG_ENABLED\n ")
- fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n ")
+ fd.write(
+ "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n "
+ )
fd.write("\t#else\n ")
fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; \n\n ")
fd.write("\t#endif\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n")
- fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n")
-
- fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform& p_transform) { _FU
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n"
+ )
+ fd.write(
+ "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n"
+ )
+
+ fd.write(
+ """\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform& p_transform) { _FU
const Transform &tr = p_transform;
@@ -276,9 +312,11 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
- """)
+ """
+ )
- fd.write("""_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU
+ fd.write(
+ """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU
const Transform2D &tr = p_transform;
@@ -304,9 +342,11 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
- """)
+ """
+ )
- fd.write("""_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU
+ fd.write(
+ """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU
GLfloat matrix[16];
@@ -320,7 +360,8 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
- """)
+ """
+ )
fd.write("\n\n#undef _FU\n\n\n")
@@ -340,21 +381,25 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
x = header_data.enums[xv]
bits = 1
amt = len(x)
- while (2 ** bits < amt):
+ while 2 ** bits < amt:
bits += 1
strs = "{"
for i in range(amt):
- strs += "\"#define " + x[i] + "\\n\","
+ strs += '"#define ' + x[i] + '\\n",'
c = {}
c["set_mask"] = "uint64_t(" + str(i) + ")<<" + str(bitofs)
- c["clear_mask"] = "((uint64_t(1)<<40)-1) ^ (((uint64_t(1)<<" + str(bits) + ") - 1)<<" + str(bitofs) + ")"
+ c["clear_mask"] = (
+ "((uint64_t(1)<<40)-1) ^ (((uint64_t(1)<<" + str(bits) + ") - 1)<<" + str(bitofs) + ")"
+ )
enum_vals.append(c)
enum_constants.append(x[i])
- strs += "NULL}"
+ strs += "nullptr}"
- fd.write("\t\t\t{(uint64_t(1<<" + str(bits) + ")-1)<<" + str(bitofs) + "," + str(bitofs) + "," + strs + "},\n")
+ fd.write(
+ "\t\t\t{(uint64_t(1<<" + str(bits) + ")-1)<<" + str(bitofs) + "," + str(bitofs) + "," + strs + "},\n"
+ )
bitofs += bits
fd.write("\t\t};\n\n")
@@ -373,31 +418,31 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
fd.write("\t\tstatic const char* _conditional_strings[]={\n")
if header_data.conditionals:
for x in header_data.conditionals:
- fd.write("\t\t\t\"#define " + x + "\\n\",\n")
+ fd.write('\t\t\t"#define ' + x + '\\n",\n')
conditionals_found.append(x)
fd.write("\t\t};\n\n")
else:
- fd.write("\t\tstatic const char **_conditional_strings=NULL;\n")
+ fd.write("\t\tstatic const char **_conditional_strings=nullptr;\n")
if header_data.uniforms:
fd.write("\t\tstatic const char* _uniform_strings[]={\n")
if header_data.uniforms:
for x in header_data.uniforms:
- fd.write("\t\t\t\"" + x + "\",\n")
+ fd.write('\t\t\t"' + x + '",\n')
fd.write("\t\t};\n\n")
else:
- fd.write("\t\tstatic const char **_uniform_strings=NULL;\n")
+ fd.write("\t\tstatic const char **_uniform_strings=nullptr;\n")
if output_attribs:
if header_data.attributes:
fd.write("\t\tstatic AttributePair _attribute_pairs[]={\n")
for x in header_data.attributes:
- fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
+ fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
- fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n")
+ fd.write("\t\tstatic AttributePair *_attribute_pairs=nullptr;\n")
feedback_count = 0
@@ -408,9 +453,9 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
name = x[0]
cond = x[1]
if cond in conditionals_found:
- fd.write("\t\t\t{\"" + name + "\"," + str(conditionals_found.index(cond)) + "},\n")
+ fd.write('\t\t\t{"' + name + '",' + str(conditionals_found.index(cond)) + "},\n")
else:
- fd.write("\t\t\t{\"" + name + "\",-1},\n")
+ fd.write('\t\t\t{"' + name + '",-1},\n')
feedback_count += 1
@@ -419,33 +464,33 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
if gles2:
pass
else:
- fd.write("\t\tstatic const Feedback* _feedbacks=NULL;\n")
+ fd.write("\t\tstatic const Feedback* _feedbacks=nullptr;\n")
if header_data.texunits:
fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n")
for x in header_data.texunits:
- fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
+ fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
- fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n")
+ fd.write("\t\tstatic TexUnitPair *_texunit_pairs=nullptr;\n")
if not gles2 and header_data.ubos:
fd.write("\t\tstatic UBOPair _ubo_pairs[]={\n")
for x in header_data.ubos:
- fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
+ fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
if gles2:
pass
else:
- fd.write("\t\tstatic UBOPair *_ubo_pairs=NULL;\n")
+ fd.write("\t\tstatic UBOPair *_ubo_pairs=nullptr;\n")
fd.write("\t\tstatic const char _vertex_code[]={\n")
for x in header_data.vertex_lines:
for c in x:
fd.write(str(ord(c)) + ",")
- fd.write(str(ord('\n')) + ",")
+ fd.write(str(ord("\n")) + ",")
fd.write("\t\t0};\n\n")
fd.write("\t\tstatic const int _vertex_code_start=" + str(header_data.vertex_offset) + ";\n")
@@ -455,28 +500,73 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
for c in x:
fd.write(str(ord(c)) + ",")
- fd.write(str(ord('\n')) + ",")
+ fd.write(str(ord("\n")) + ",")
fd.write("\t\t0};\n\n")
fd.write("\t\tstatic const int _fragment_code_start=" + str(header_data.fragment_offset) + ";\n")
if output_attribs:
if gles2:
- fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_attribute_pairs," + str(
- len(header_data.attributes)) + ", _texunit_pairs," + str(len(header_data.texunits)) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
+ fd.write(
+ "\t\tsetup(_conditional_strings,"
+ + str(len(header_data.conditionals))
+ + ",_uniform_strings,"
+ + str(len(header_data.uniforms))
+ + ",_attribute_pairs,"
+ + str(len(header_data.attributes))
+ + ", _texunit_pairs,"
+ + str(len(header_data.texunits))
+ + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
+ )
else:
- fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_attribute_pairs," + str(
- len(header_data.attributes)) + ", _texunit_pairs," + str(len(header_data.texunits)) + ",_ubo_pairs," + str(len(header_data.ubos)) + ",_feedbacks," + str(
- feedback_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
+ fd.write(
+ "\t\tsetup(_conditional_strings,"
+ + str(len(header_data.conditionals))
+ + ",_uniform_strings,"
+ + str(len(header_data.uniforms))
+ + ",_attribute_pairs,"
+ + str(len(header_data.attributes))
+ + ", _texunit_pairs,"
+ + str(len(header_data.texunits))
+ + ",_ubo_pairs,"
+ + str(len(header_data.ubos))
+ + ",_feedbacks,"
+ + str(feedback_count)
+ + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
+ )
else:
if gles2:
- fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_texunit_pairs," + str(
- len(header_data.texunits)) + ",_enums," + str(len(header_data.enums)) + ",_enum_values," + str(
- enum_value_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
+ fd.write(
+ "\t\tsetup(_conditional_strings,"
+ + str(len(header_data.conditionals))
+ + ",_uniform_strings,"
+ + str(len(header_data.uniforms))
+ + ",_texunit_pairs,"
+ + str(len(header_data.texunits))
+ + ",_enums,"
+ + str(len(header_data.enums))
+ + ",_enum_values,"
+ + str(enum_value_count)
+ + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
+ )
else:
- fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_texunit_pairs," + str(
- len(header_data.texunits)) + ",_enums," + str(len(header_data.enums)) + ",_enum_values," + str(enum_value_count) + ",_ubo_pairs," + str(len(header_data.ubos)) + ",_feedbacks," + str(
- feedback_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
+ fd.write(
+ "\t\tsetup(_conditional_strings,"
+ + str(len(header_data.conditionals))
+ + ",_uniform_strings,"
+ + str(len(header_data.uniforms))
+ + ",_texunit_pairs,"
+ + str(len(header_data.texunits))
+ + ",_enums,"
+ + str(len(header_data.enums))
+ + ",_enum_values,"
+ + str(enum_value_count)
+ + ",_ubo_pairs,"
+ + str(len(header_data.ubos))
+ + ",_feedbacks,"
+ + str(feedback_count)
+ + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n"
+ )
fd.write("\t}\n\n")
@@ -495,12 +585,12 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2
def build_gles2_headers(target, source, env):
for x in source:
- build_legacygl_header(str(x), include="drivers/gles2/shader_gles2.h", class_suffix="GLES2", output_attribs=True, gles2=True)
-
+ build_legacygl_header(
+ str(x), include="drivers/gles2/shader_gles2.h", class_suffix="GLES2", output_attribs=True, gles2=True
+ )
class RDHeaderStruct:
-
def __init__(self):
self.vertex_lines = []
self.fragment_lines = []
@@ -594,30 +684,30 @@ def build_rd_header(filename):
fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
out_file_base = out_file
- out_file_base = out_file_base[out_file_base.rfind("/") + 1:]
- out_file_base = out_file_base[out_file_base.rfind("\\") + 1:]
+ out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
+ out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
out_file_ifdef = out_file_base.replace(".", "_").upper()
fd.write("#ifndef " + out_file_ifdef + "_RD\n")
fd.write("#define " + out_file_ifdef + "_RD\n")
out_file_class = out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "ShaderRD"
fd.write("\n")
- fd.write("#include \"servers/visual/rasterizer_rd/shader_rd.h\"\n\n")
+ fd.write('#include "servers/rendering/rasterizer_rd/shader_rd.h"\n\n')
fd.write("class " + out_file_class + " : public ShaderRD {\n\n")
fd.write("public:\n\n")
fd.write("\t" + out_file_class + "() {\n\n")
- if (len(header_data.compute_lines)):
+ if len(header_data.compute_lines):
fd.write("\t\tstatic const char _compute_code[] = {\n")
for x in header_data.compute_lines:
for c in x:
fd.write(str(ord(c)) + ",")
- fd.write(str(ord('\n')) + ",")
+ fd.write(str(ord("\n")) + ",")
fd.write("\t\t0};\n\n")
- fd.write("\t\tsetup(nullptr, nullptr, _compute_code, \"" + out_file_class + "\");\n")
+ fd.write('\t\tsetup(nullptr, nullptr, _compute_code, "' + out_file_class + '");\n')
fd.write("\t}\n")
else:
@@ -626,17 +716,17 @@ def build_rd_header(filename):
for x in header_data.vertex_lines:
for c in x:
fd.write(str(ord(c)) + ",")
- fd.write(str(ord('\n')) + ",")
+ fd.write(str(ord("\n")) + ",")
fd.write("\t\t0};\n\n")
-
+
fd.write("\t\tstatic const char _fragment_code[]={\n")
for x in header_data.fragment_lines:
for c in x:
fd.write(str(ord(c)) + ",")
- fd.write(str(ord('\n')) + ",")
+ fd.write(str(ord("\n")) + ",")
fd.write("\t\t0};\n\n")
- fd.write("\t\tsetup(_vertex_code, _fragment_code, nullptr, \"" + out_file_class + "\");\n")
+ fd.write('\t\tsetup(_vertex_code, _fragment_code, nullptr, "' + out_file_class + '");\n')
fd.write("\t}\n")
fd.write("};\n\n")
@@ -650,5 +740,5 @@ def build_rd_headers(target, source, env):
build_rd_header(str(x))
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/main/SCsub b/main/SCsub
index e1efc7e6ed..7a301b82bc 100644
--- a/main/SCsub
+++ b/main/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
from platform_methods import run_in_subprocess
import main_builders
@@ -9,27 +9,20 @@ env.main_sources = []
env.add_source_files(env.main_sources, "*.cpp")
-# Order matters here. Higher index controller database files write on top of lower index database files.
-controller_databases = ["#main/gamecontrollerdb_204.txt", "#main/gamecontrollerdb_205.txt", "#main/gamecontrollerdb.txt", "#main/godotcontrollerdb.txt"]
-
-env.Depends("#main/default_controller_mappings.gen.cpp", controller_databases)
-env.CommandNoCache("#main/default_controller_mappings.gen.cpp", controller_databases, run_in_subprocess(main_builders.make_default_controller_mappings))
-
-# Don't warn about duplicate entry here, we need it registered manually for first build,
-# even if later builds will pick it up twice due to above *.cpp globbing.
-env.add_source_files(env.main_sources, "#main/default_controller_mappings.gen.cpp", warn_duplicates=False)
env.Depends("#main/splash.gen.h", "#main/splash.png")
env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash))
env.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png")
-env.CommandNoCache("#main/splash_editor.gen.h", "#main/splash_editor.png", run_in_subprocess(main_builders.make_splash_editor))
+env.CommandNoCache(
+ "#main/splash_editor.gen.h", "#main/splash_editor.png", run_in_subprocess(main_builders.make_splash_editor)
+)
env.Depends("#main/app_icon.gen.h", "#main/app_icon.png")
env.CommandNoCache("#main/app_icon.gen.h", "#main/app_icon.png", run_in_subprocess(main_builders.make_app_icon))
if env["tools"]:
- SConscript('tests/SCsub')
+ SConscript("tests/SCsub")
lib = env.add_library("main", env.main_sources)
env.Prepend(LIBS=[lib])
diff --git a/main/input_default.cpp b/main/input_default.cpp
deleted file mode 100644
index aa9e772a38..0000000000
--- a/main/input_default.cpp
+++ /dev/null
@@ -1,1197 +0,0 @@
-/*************************************************************************/
-/* input_default.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_default.h"
-
-#include "core/input_map.h"
-#include "core/os/os.h"
-#include "main/default_controller_mappings.h"
-#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
-
-void InputDefault::SpeedTrack::update(const Vector2 &p_delta_p) {
-
- uint64_t tick = OS::get_singleton()->get_ticks_usec();
- uint32_t tdiff = tick - last_tick;
- float delta_t = tdiff / 1000000.0;
- last_tick = tick;
-
- accum += p_delta_p;
- accum_t += delta_t;
-
- if (accum_t > max_ref_frame * 10)
- accum_t = max_ref_frame * 10;
-
- while (accum_t >= min_ref_frame) {
-
- float slice_t = min_ref_frame / accum_t;
- Vector2 slice = accum * slice_t;
- accum = accum - slice;
- accum_t -= min_ref_frame;
-
- speed = (slice / min_ref_frame).linear_interpolate(speed, min_ref_frame / max_ref_frame);
- }
-}
-
-void InputDefault::SpeedTrack::reset() {
- last_tick = OS::get_singleton()->get_ticks_usec();
- speed = Vector2();
- accum_t = 0;
-}
-
-InputDefault::SpeedTrack::SpeedTrack() {
-
- min_ref_frame = 0.1;
- max_ref_frame = 0.3;
- reset();
-}
-
-bool InputDefault::is_key_pressed(int p_keycode) const {
-
- _THREAD_SAFE_METHOD_
- return keys_pressed.has(p_keycode);
-}
-
-bool InputDefault::is_mouse_button_pressed(int p_button) const {
-
- _THREAD_SAFE_METHOD_
- return (mouse_button_mask & (1 << (p_button - 1))) != 0;
-}
-
-static int _combine_device(int p_value, int p_device) {
-
- return p_value | (p_device << 20);
-}
-
-bool InputDefault::is_joy_button_pressed(int p_device, int p_button) const {
-
- _THREAD_SAFE_METHOD_
- return joy_buttons_pressed.has(_combine_device(p_button, p_device));
-}
-
-bool InputDefault::is_action_pressed(const StringName &p_action) const {
-
- return action_state.has(p_action) && action_state[p_action].pressed;
-}
-
-bool InputDefault::is_action_just_pressed(const StringName &p_action) const {
-
- const Map<StringName, Action>::Element *E = action_state.find(p_action);
- if (!E)
- 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 {
- return E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames();
- }
-}
-
-bool InputDefault::is_action_just_released(const StringName &p_action) const {
-
- const Map<StringName, Action>::Element *E = action_state.find(p_action);
- if (!E)
- 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 {
- return !E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames();
- }
-}
-
-float InputDefault::get_action_strength(const StringName &p_action) const {
- const Map<StringName, Action>::Element *E = action_state.find(p_action);
- if (!E)
- return 0.0f;
-
- return E->get().strength;
-}
-
-float InputDefault::get_joy_axis(int p_device, int p_axis) const {
-
- _THREAD_SAFE_METHOD_
- int c = _combine_device(p_axis, p_device);
- if (_joy_axis.has(c)) {
- return _joy_axis[c];
- } else {
- return 0;
- }
-}
-
-String InputDefault::get_joy_name(int p_idx) {
-
- _THREAD_SAFE_METHOD_
- return joy_names[p_idx].name;
-};
-
-Vector2 InputDefault::get_joy_vibration_strength(int p_device) {
- if (joy_vibration.has(p_device)) {
- return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
- } else {
- return Vector2(0, 0);
- }
-}
-
-uint64_t InputDefault::get_joy_vibration_timestamp(int p_device) {
- if (joy_vibration.has(p_device)) {
- return joy_vibration[p_device].timestamp;
- } else {
- return 0;
- }
-}
-
-float InputDefault::get_joy_vibration_duration(int p_device) {
- if (joy_vibration.has(p_device)) {
- return joy_vibration[p_device].duration;
- } else {
- return 0.f;
- }
-}
-
-static String _hex_str(uint8_t p_byte) {
-
- static const char *dict = "0123456789abcdef";
- char ret[3];
- ret[2] = 0;
-
- ret[0] = dict[p_byte >> 4];
- ret[1] = dict[p_byte & 0xf];
-
- return ret;
-};
-
-void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
-
- _THREAD_SAFE_METHOD_
- Joypad js;
- js.name = p_connected ? p_name : "";
- js.uid = p_connected ? p_guid : "";
-
- if (p_connected) {
-
- String uidname = p_guid;
- if (p_guid == "") {
- int uidlen = MIN(p_name.length(), 16);
- for (int i = 0; i < uidlen; i++) {
- uidname = uidname + _hex_str(p_name[i]);
- };
- };
- js.uid = uidname;
- js.connected = true;
- int mapping = fallback_mapping;
- for (int i = 0; i < map_db.size(); i++) {
- if (js.uid == map_db[i].uid) {
- mapping = i;
- js.name = map_db[i].name;
- };
- };
- js.mapping = mapping;
- } else {
- js.connected = false;
- for (int i = 0; i < JOY_BUTTON_MAX; i++) {
-
- if (i < JOY_AXIS_MAX)
- set_joy_axis(p_idx, i, 0.0f);
-
- int c = _combine_device(i, p_idx);
- joy_buttons_pressed.erase(c);
- };
- };
- joy_names[p_idx] = js;
-
- emit_signal("joy_connection_changed", p_idx, p_connected);
-};
-
-Vector3 InputDefault::get_gravity() const {
-
- _THREAD_SAFE_METHOD_
- return gravity;
-}
-
-Vector3 InputDefault::get_accelerometer() const {
-
- _THREAD_SAFE_METHOD_
- return accelerometer;
-}
-
-Vector3 InputDefault::get_magnetometer() const {
-
- _THREAD_SAFE_METHOD_
- return magnetometer;
-}
-
-Vector3 InputDefault::get_gyroscope() const {
-
- _THREAD_SAFE_METHOD_
- return gyroscope;
-}
-
-void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
-
- _parse_input_event_impl(p_event, false);
-}
-
-void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
-
- // Notes on mouse-touch emulation:
- // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
- // as true mouse events. The only difference is the situation is flagged as emulated so they are not
- // emulated back to touch events in an endless loop.
- // - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
- // require additional handling by this class.
-
- _THREAD_SAFE_METHOD_
-
- Ref<InputEventKey> k = p_event;
- if (k.is_valid() && !k->is_echo() && k->get_keycode() != 0) {
- if (k->is_pressed())
- keys_pressed.insert(k->get_keycode());
- else
- keys_pressed.erase(k->get_keycode());
- }
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
-
- if (mb->is_pressed()) {
- mouse_button_mask |= (1 << (mb->get_button_index() - 1));
- } else {
- mouse_button_mask &= ~(1 << (mb->get_button_index() - 1));
- }
-
- Point2 pos = mb->get_global_position();
- if (mouse_pos != pos) {
- set_mouse_position(pos);
- }
-
- if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) {
- Ref<InputEventScreenTouch> touch_event;
- touch_event.instance();
- touch_event->set_pressed(mb->is_pressed());
- touch_event->set_position(mb->get_position());
- main_loop->input_event(touch_event);
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
-
- Point2 pos = mm->get_global_position();
- if (mouse_pos != pos) {
- set_mouse_position(pos);
- }
-
- if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) {
- Ref<InputEventScreenDrag> drag_event;
- drag_event.instance();
-
- drag_event->set_position(mm->get_position());
- drag_event->set_relative(mm->get_relative());
- drag_event->set_speed(mm->get_speed());
-
- main_loop->input_event(drag_event);
- }
- }
-
- Ref<InputEventScreenTouch> st = p_event;
-
- if (st.is_valid()) {
-
- if (st->is_pressed()) {
- SpeedTrack &track = touch_speed_track[st->get_index()];
- track.reset();
- } else {
- // Since a pointer index may not occur again (OSs may or may not reuse them),
- // imperatively remove it from the map to keep no fossil entries in it
- touch_speed_track.erase(st->get_index());
- }
-
- if (emulate_mouse_from_touch) {
-
- bool translate = false;
- if (st->is_pressed()) {
- if (mouse_from_touch_index == -1) {
- translate = true;
- mouse_from_touch_index = st->get_index();
- }
- } else {
- if (st->get_index() == mouse_from_touch_index) {
- translate = true;
- mouse_from_touch_index = -1;
- }
- }
-
- if (translate) {
- Ref<InputEventMouseButton> button_event;
- button_event.instance();
-
- button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
- 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);
- if (st->is_pressed()) {
- button_event->set_button_mask(mouse_button_mask | (1 << (BUTTON_LEFT - 1)));
- } else {
- button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1)));
- }
-
- _parse_input_event_impl(button_event, true);
- }
- }
- }
-
- Ref<InputEventScreenDrag> sd = p_event;
-
- if (sd.is_valid()) {
-
- SpeedTrack &track = touch_speed_track[sd->get_index()];
- track.update(sd->get_relative());
- sd->set_speed(track.speed);
-
- if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) {
-
- Ref<InputEventMouseMotion> motion_event;
- motion_event.instance();
-
- motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
- motion_event->set_position(sd->get_position());
- motion_event->set_global_position(sd->get_position());
- motion_event->set_relative(sd->get_relative());
- motion_event->set_speed(sd->get_speed());
- motion_event->set_button_mask(mouse_button_mask);
-
- _parse_input_event_impl(motion_event, true);
- }
- }
-
- Ref<InputEventJoypadButton> jb = p_event;
-
- if (jb.is_valid()) {
-
- int c = _combine_device(jb->get_button_index(), jb->get_device());
-
- if (jb->is_pressed())
- joy_buttons_pressed.insert(c);
- else
- joy_buttons_pressed.erase(c);
- }
-
- Ref<InputEventJoypadMotion> jm = p_event;
-
- if (jm.is_valid()) {
- set_joy_axis(jm->get_device(), jm->get_axis(), jm->get_axis_value());
- }
-
- Ref<InputEventGesture> ge = p_event;
-
- if (ge.is_valid()) {
-
- if (main_loop) {
- main_loop->input_event(ge);
- }
- }
-
- 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())) {
- Action action;
- action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.idle_frame = Engine::get_singleton()->get_idle_frames();
- action.pressed = p_event->is_action_pressed(E->key());
- action.strength = 0.f;
- action_state[E->key()] = action;
- }
- action_state[E->key()].strength = p_event->get_action_strength(E->key());
- }
- }
-
- if (main_loop)
- main_loop->input_event(p_event);
-}
-
-void InputDefault::set_joy_axis(int p_device, int p_axis, float p_value) {
-
- _THREAD_SAFE_METHOD_
- int c = _combine_device(p_axis, p_device);
- _joy_axis[c] = p_value;
-}
-
-void InputDefault::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
- _THREAD_SAFE_METHOD_
- if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
- return;
- }
- VibrationInfo vibration;
- vibration.weak_magnitude = p_weak_magnitude;
- vibration.strong_magnitude = p_strong_magnitude;
- vibration.duration = p_duration;
- vibration.timestamp = OS::get_singleton()->get_ticks_usec();
- joy_vibration[p_device] = vibration;
-}
-
-void InputDefault::stop_joy_vibration(int p_device) {
- _THREAD_SAFE_METHOD_
- VibrationInfo vibration;
- vibration.weak_magnitude = 0;
- vibration.strong_magnitude = 0;
- vibration.duration = 0;
- vibration.timestamp = OS::get_singleton()->get_ticks_usec();
- joy_vibration[p_device] = vibration;
-}
-
-void InputDefault::vibrate_handheld(int p_duration_ms) {
- OS::get_singleton()->vibrate_handheld(p_duration_ms);
-}
-
-void InputDefault::set_gravity(const Vector3 &p_gravity) {
-
- _THREAD_SAFE_METHOD_
-
- gravity = p_gravity;
-}
-
-void InputDefault::set_accelerometer(const Vector3 &p_accel) {
-
- _THREAD_SAFE_METHOD_
-
- accelerometer = p_accel;
-}
-
-void InputDefault::set_magnetometer(const Vector3 &p_magnetometer) {
-
- _THREAD_SAFE_METHOD_
-
- magnetometer = p_magnetometer;
-}
-
-void InputDefault::set_gyroscope(const Vector3 &p_gyroscope) {
-
- _THREAD_SAFE_METHOD_
-
- gyroscope = p_gyroscope;
-}
-
-void InputDefault::set_main_loop(MainLoop *p_main_loop) {
- main_loop = p_main_loop;
-}
-
-void InputDefault::set_mouse_position(const Point2 &p_posf) {
-
- mouse_speed_track.update(p_posf - mouse_pos);
- mouse_pos = p_posf;
-}
-
-Point2 InputDefault::get_mouse_position() const {
-
- return mouse_pos;
-}
-Point2 InputDefault::get_last_mouse_speed() const {
-
- return mouse_speed_track.speed;
-}
-
-int InputDefault::get_mouse_button_mask() const {
-
- return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
-}
-
-void InputDefault::warp_mouse_position(const Vector2 &p_to) {
-
- OS::get_singleton()->warp_mouse_position(p_to);
-}
-
-Point2i InputDefault::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()
- // 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.
- // And due to this mouse warping mechanism being stateless, we need to apply some heuristics to
- // detect the warp: if the relative distance is greater than the half of the size of the relevant rect
- // (checked per each axis), it will be considered as the consequence of a former pointer warp.
-
- const Point2i rel_sgn(p_motion->get_relative().x >= 0.0f ? 1 : -1, p_motion->get_relative().y >= 0.0 ? 1 : -1);
- const Size2i warp_margin = p_rect.size * 0.5f;
- const Point2i rel_warped(
- Math::fmod(p_motion->get_relative().x + rel_sgn.x * warp_margin.x, p_rect.size.x) - rel_sgn.x * warp_margin.x,
- Math::fmod(p_motion->get_relative().y + rel_sgn.y * warp_margin.y, p_rect.size.y) - rel_sgn.y * warp_margin.y);
-
- const Point2i pos_local = p_motion->get_global_position() - p_rect.position;
- const Point2i pos_warped(Math::fposmod(pos_local.x, p_rect.size.x), Math::fposmod(pos_local.y, p_rect.size.y));
- if (pos_warped != pos_local) {
- OS::get_singleton()->warp_mouse_position(pos_warped + p_rect.position);
- }
-
- return rel_warped;
-}
-
-void InputDefault::iteration(float p_step) {
-}
-
-void InputDefault::action_press(const StringName &p_action, float p_strength) {
-
- Action action;
-
- action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.idle_frame = Engine::get_singleton()->get_idle_frames();
- action.pressed = true;
- action.strength = p_strength;
-
- action_state[p_action] = action;
-}
-
-void InputDefault::action_release(const StringName &p_action) {
-
- Action action;
-
- action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.idle_frame = Engine::get_singleton()->get_idle_frames();
- action.pressed = false;
- action.strength = 0.f;
-
- action_state[p_action] = action;
-}
-
-void InputDefault::set_emulate_touch_from_mouse(bool p_emulate) {
-
- emulate_touch_from_mouse = p_emulate;
-}
-
-bool InputDefault::is_emulating_touch_from_mouse() const {
-
- return emulate_touch_from_mouse;
-}
-
-// Calling this whenever the game window is focused helps unstucking the "touch mouse"
-// if the OS or its abstraction class hasn't properly reported that touch pointers raised
-void InputDefault::ensure_touch_mouse_raised() {
-
- if (mouse_from_touch_index != -1) {
- mouse_from_touch_index = -1;
-
- Ref<InputEventMouseButton> button_event;
- button_event.instance();
-
- button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE);
- 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)));
-
- _parse_input_event_impl(button_event, true);
- }
-}
-
-void InputDefault::set_emulate_mouse_from_touch(bool p_emulate) {
-
- emulate_mouse_from_touch = p_emulate;
-}
-
-bool InputDefault::is_emulating_mouse_from_touch() const {
-
- return emulate_mouse_from_touch;
-}
-
-Input::CursorShape InputDefault::get_default_cursor_shape() const {
-
- return default_shape;
-}
-
-void InputDefault::set_default_cursor_shape(CursorShape p_shape) {
-
- if (default_shape == p_shape)
- return;
-
- default_shape = p_shape;
- // The default shape is set in Viewport::_gui_input_event. To instantly
- // see the shape in the viewport we need to trigger a mouse motion event.
- Ref<InputEventMouseMotion> mm;
- mm.instance();
- mm->set_position(mouse_pos);
- mm->set_global_position(mouse_pos);
- parse_input_event(mm);
-}
-
-Input::CursorShape InputDefault::get_current_cursor_shape() const {
-
- return (Input::CursorShape)OS::get_singleton()->get_cursor_shape();
-}
-
-void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
- if (Engine::get_singleton()->is_editor_hint())
- return;
-
- OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
-}
-
-void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND(p_event.is_null());
-
- if (!use_accumulated_input) {
- parse_input_event(p_event);
- return;
- }
- if (!accumulated_events.empty() && accumulated_events.back()->get()->accumulate(p_event)) {
- return; //event was accumulated, exit
- }
-
- accumulated_events.push_back(p_event);
-}
-void InputDefault::flush_accumulated_events() {
-
- while (accumulated_events.front()) {
- parse_input_event(accumulated_events.front()->get());
- accumulated_events.pop_front();
- }
-}
-
-void InputDefault::set_use_accumulated_input(bool p_enable) {
-
- use_accumulated_input = p_enable;
-}
-
-void InputDefault::release_pressed_events() {
-
- flush_accumulated_events(); // this is needed to release actions strengths
-
- keys_pressed.clear();
- joy_buttons_pressed.clear();
- _joy_axis.clear();
-
- for (Map<StringName, InputDefault::Action>::Element *E = action_state.front(); E; E = E->next()) {
- if (E->get().pressed)
- action_release(E->key());
- }
-}
-
-InputDefault::InputDefault() {
-
- use_accumulated_input = true;
- mouse_button_mask = 0;
- emulate_touch_from_mouse = false;
- emulate_mouse_from_touch = false;
- mouse_from_touch_index = -1;
- main_loop = NULL;
- default_shape = CURSOR_ARROW;
-
- hat_map_default[HAT_UP].type = TYPE_BUTTON;
- hat_map_default[HAT_UP].index = JOY_DPAD_UP;
- hat_map_default[HAT_UP].value = 0;
-
- hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
- hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
- hat_map_default[HAT_RIGHT].value = 0;
-
- hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
- hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
- hat_map_default[HAT_DOWN].value = 0;
-
- hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
- hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
- hat_map_default[HAT_LEFT].value = 0;
-
- fallback_mapping = -1;
-
- // Parse default mappings.
- {
- int i = 0;
- while (DefaultControllerMappings::mappings[i]) {
- parse_mapping(DefaultControllerMappings::mappings[i++]);
- }
- }
-
- // If defined, parse SDL_GAMECONTROLLERCONFIG for possible new mappings/overrides.
- String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
- if (env_mapping != "") {
- Vector<String> entries = env_mapping.split("\n");
- for (int i = 0; i < entries.size(); i++) {
- if (entries[i] == "")
- continue;
- parse_mapping(entries[i]);
- }
- }
-}
-
-void InputDefault::joy_button(int p_device, int p_button, bool p_pressed) {
-
- _THREAD_SAFE_METHOD_;
- Joypad &joy = joy_names[p_device];
- //printf("got button %i, mapping is %i\n", p_button, joy.mapping);
- if (joy.last_buttons[p_button] == p_pressed) {
- return;
- }
- joy.last_buttons[p_button] = p_pressed;
- if (joy.mapping == -1) {
- _button_event(p_device, p_button, p_pressed);
- return;
- }
-
- const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].buttons.find(p_button);
- if (!el) {
- //don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis
- //return _button_event(p_last_id, p_device, p_button, p_pressed);
- return;
- }
-
- JoyEvent map = el->get();
- if (map.type == TYPE_BUTTON) {
- //fake additional axis event for triggers
- if (map.index == JOY_L2 || map.index == JOY_R2) {
- float value = p_pressed ? 1.0f : 0.0f;
- int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
- _axis_event(p_device, axis, value);
- }
- _button_event(p_device, map.index, p_pressed);
- return;
- }
-
- if (map.type == TYPE_AXIS) {
- _axis_event(p_device, map.index, p_pressed ? 1.0 : 0.0);
- }
- // no event?
-}
-
-void InputDefault::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
-
- _THREAD_SAFE_METHOD_;
-
- ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX);
-
- Joypad &joy = joy_names[p_device];
-
- if (joy.last_axis[p_axis] == p_value.value) {
- return;
- }
-
- if (p_value.value > joy.last_axis[p_axis]) {
-
- if (p_value.value < joy.last_axis[p_axis] + joy.filter) {
-
- return;
- }
- } else if (p_value.value > joy.last_axis[p_axis] - joy.filter) {
-
- return;
- }
-
- //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;
- 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;
- jx.min = p_value.min;
- jx.value = p_value.value < 0 ? 0.1 : -0.1;
- joy_axis(p_device, p_axis, jx);
- }
-
- joy.last_axis[p_axis] = p_value.value;
- float val = p_value.min == 0 ? -1.0f + 2.0f * p_value.value : p_value.value;
-
- if (joy.mapping == -1) {
- _axis_event(p_device, p_axis, val);
- return;
- };
-
- const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].axis.find(p_axis);
- if (!el) {
- //return _axis_event(p_last_id, p_device, p_axis, p_value);
- return;
- };
-
- JoyEvent map = el->get();
-
- if (map.type == TYPE_BUTTON) {
- //send axis event for triggers
- if (map.index == JOY_L2 || map.index == JOY_R2) {
- float value = p_value.min == 0 ? p_value.value : 0.5f + p_value.value / 2.0f;
- int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
- _axis_event(p_device, axis, value);
- }
-
- if (map.index == JOY_DPAD_UP || map.index == JOY_DPAD_DOWN) {
- bool pressed = p_value.value != 0.0f;
- int button = p_value.value < 0 ? JOY_DPAD_UP : JOY_DPAD_DOWN;
-
- if (!pressed) {
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_UP, p_device))) {
- _button_event(p_device, JOY_DPAD_UP, false);
- }
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_DOWN, p_device))) {
- _button_event(p_device, JOY_DPAD_DOWN, false);
- }
- }
- if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
- return;
- }
- _button_event(p_device, button, true);
- return;
- }
- if (map.index == JOY_DPAD_LEFT || map.index == JOY_DPAD_RIGHT) {
- bool pressed = p_value.value != 0.0f;
- int button = p_value.value < 0 ? JOY_DPAD_LEFT : JOY_DPAD_RIGHT;
-
- if (!pressed) {
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_LEFT, p_device))) {
- _button_event(p_device, JOY_DPAD_LEFT, false);
- }
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_RIGHT, p_device))) {
- _button_event(p_device, JOY_DPAD_RIGHT, false);
- }
- }
- if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
- return;
- }
- _button_event(p_device, button, true);
- return;
- }
- float deadzone = p_value.min == 0 ? 0.5f : 0.0f;
- bool pressed = p_value.value > deadzone;
- if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) {
- // button already pressed or released, this is an axis bounce value
- return;
- }
- _button_event(p_device, map.index, pressed);
- return;
- }
-
- if (map.type == TYPE_AXIS) {
-
- _axis_event(p_device, map.index, val);
- return;
- }
- //printf("invalid mapping\n");
-}
-
-void InputDefault::joy_hat(int p_device, int p_val) {
-
- _THREAD_SAFE_METHOD_;
- const Joypad &joy = joy_names[p_device];
-
- const JoyEvent *map;
-
- if (joy.mapping == -1) {
- map = hat_map_default;
- } else {
- map = map_db[joy.mapping].hat;
- };
-
- int cur_val = joy_names[p_device].hat_current;
-
- if ((p_val & HAT_MASK_UP) != (cur_val & HAT_MASK_UP)) {
- _button_event(p_device, map[HAT_UP].index, p_val & HAT_MASK_UP);
- }
-
- if ((p_val & HAT_MASK_RIGHT) != (cur_val & HAT_MASK_RIGHT)) {
- _button_event(p_device, map[HAT_RIGHT].index, p_val & HAT_MASK_RIGHT);
- }
- if ((p_val & HAT_MASK_DOWN) != (cur_val & HAT_MASK_DOWN)) {
- _button_event(p_device, map[HAT_DOWN].index, p_val & HAT_MASK_DOWN);
- }
- if ((p_val & HAT_MASK_LEFT) != (cur_val & HAT_MASK_LEFT)) {
- _button_event(p_device, map[HAT_LEFT].index, p_val & HAT_MASK_LEFT);
- }
-
- joy_names[p_device].hat_current = p_val;
-}
-
-void InputDefault::_button_event(int p_device, int p_index, bool p_pressed) {
-
- Ref<InputEventJoypadButton> ievent;
- ievent.instance();
- ievent->set_device(p_device);
- ievent->set_button_index(p_index);
- ievent->set_pressed(p_pressed);
-
- parse_input_event(ievent);
-}
-
-void InputDefault::_axis_event(int p_device, int p_axis, float p_value) {
-
- Ref<InputEventJoypadMotion> ievent;
- ievent.instance();
- ievent->set_device(p_device);
- ievent->set_axis(p_axis);
- ievent->set_axis_value(p_value);
-
- parse_input_event(ievent);
-};
-
-InputDefault::JoyEvent InputDefault::_find_to_event(String p_to) {
-
- // string names of the SDL buttons in the same order as input_event.h godot buttons
- static const char *buttons[] = { "a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", NULL };
-
- static const char *axis[] = { "leftx", "lefty", "rightx", "righty", NULL };
-
- JoyEvent ret;
- ret.type = -1;
- ret.index = 0;
-
- int i = 0;
- while (buttons[i]) {
-
- if (p_to == buttons[i]) {
- ret.type = TYPE_BUTTON;
- ret.index = i;
- ret.value = 0;
- return ret;
- };
- ++i;
- };
-
- i = 0;
- while (axis[i]) {
-
- if (p_to == axis[i]) {
- ret.type = TYPE_AXIS;
- ret.index = i;
- ret.value = 0;
- return ret;
- };
- ++i;
- };
-
- return ret;
-};
-
-void InputDefault::parse_mapping(String p_mapping) {
-
- _THREAD_SAFE_METHOD_;
- JoyDeviceMapping mapping;
- for (int i = 0; i < HAT_MAX; ++i)
- mapping.hat[i].index = 1024 + i;
-
- Vector<String> entry = p_mapping.split(",");
- if (entry.size() < 2) {
- return;
- }
-
- CharString uid;
- uid.resize(17);
-
- mapping.uid = entry[0];
- mapping.name = entry[1];
-
- int idx = 1;
- while (++idx < entry.size()) {
-
- if (entry[idx] == "")
- continue;
-
- String from = entry[idx].get_slice(":", 1).replace(" ", "");
- String to = entry[idx].get_slice(":", 0).replace(" ", "");
-
- JoyEvent to_event = _find_to_event(to);
- if (to_event.type == -1)
- continue;
-
- String etype = from.substr(0, 1);
- if (etype == "a") {
-
- int aid = from.substr(1, from.length() - 1).to_int();
- mapping.axis[aid] = to_event;
-
- } else if (etype == "b") {
-
- int bid = from.substr(1, from.length() - 1).to_int();
- mapping.buttons[bid] = to_event;
-
- } else if (etype == "h") {
-
- int hat_value = from.get_slice(".", 1).to_int();
- switch (hat_value) {
- case 1:
- mapping.hat[HAT_UP] = to_event;
- break;
- case 2:
- mapping.hat[HAT_RIGHT] = to_event;
- break;
- case 4:
- mapping.hat[HAT_DOWN] = to_event;
- break;
- case 8:
- mapping.hat[HAT_LEFT] = to_event;
- break;
- };
- };
- };
- map_db.push_back(mapping);
- //printf("added mapping with uuid %ls\n", mapping.uid.c_str());
-};
-
-void InputDefault::add_joy_mapping(String p_mapping, bool p_update_existing) {
- parse_mapping(p_mapping);
- 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;
- }
- }
- }
-}
-
-void InputDefault::remove_joy_mapping(String p_guid) {
- for (int i = map_db.size() - 1; i >= 0; i--) {
- if (p_guid == map_db[i].uid) {
- 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;
- }
- }
-}
-
-void InputDefault::set_fallback_mapping(String p_guid) {
-
- for (int i = 0; i < map_db.size(); i++) {
- if (map_db[i].uid == p_guid) {
- fallback_mapping = i;
- return;
- }
- }
-}
-
-//Defaults to simple implementation for platforms with a fixed gamepad layout, like consoles.
-bool InputDefault::is_joy_known(int p_device) {
-
- return OS::get_singleton()->is_joy_known(p_device);
-}
-
-String InputDefault::get_joy_guid(int p_device) const {
- return OS::get_singleton()->get_joy_guid(p_device);
-}
-
-//platforms that use the remapping system can override and call to these ones
-bool InputDefault::is_joy_mapped(int p_device) {
- int mapping = joy_names[p_device].mapping;
- return mapping != -1 ? (mapping != fallback_mapping) : false;
-}
-
-String InputDefault::get_joy_guid_remapped(int p_device) const {
- ERR_FAIL_COND_V(!joy_names.has(p_device), "");
- return joy_names[p_device].uid;
-}
-
-Array InputDefault::get_connected_joypads() {
- Array ret;
- Map<int, Joypad>::Element *elem = joy_names.front();
- while (elem) {
- if (elem->get().connected) {
- ret.push_back(elem->key());
- }
- elem = elem->next();
- }
- return ret;
-}
-
-static const char *_buttons[JOY_BUTTON_MAX] = {
- "Face Button Bottom",
- "Face Button Right",
- "Face Button Left",
- "Face Button Top",
- "L",
- "R",
- "L2",
- "R2",
- "L3",
- "R3",
- "Select",
- "Start",
- "DPAD Up",
- "DPAD Down",
- "DPAD Left",
- "DPAD Right"
-};
-
-static const char *_axes[JOY_AXIS_MAX] = {
- "Left Stick X",
- "Left Stick Y",
- "Right Stick X",
- "Right Stick Y",
- "",
- "",
- "L2",
- "R2",
- "",
- ""
-};
-
-String InputDefault::get_joy_button_string(int p_button) {
- ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "");
- return _buttons[p_button];
-}
-
-int InputDefault::get_joy_button_index_from_string(String p_button) {
- for (int i = 0; i < JOY_BUTTON_MAX; i++) {
- if (p_button == _buttons[i]) {
- return i;
- }
- }
- ERR_FAIL_V(-1);
-}
-
-int InputDefault::get_unused_joy_id() {
- for (int i = 0; i < JOYPADS_MAX; i++) {
- if (!joy_names.has(i) || !joy_names[i].connected) {
- return i;
- }
- }
- return -1;
-}
-
-String InputDefault::get_joy_axis_string(int p_axis) {
- ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "");
- return _axes[p_axis];
-}
-
-int InputDefault::get_joy_axis_index_from_string(String p_axis) {
- for (int i = 0; i < JOY_AXIS_MAX; i++) {
- if (p_axis == _axes[i]) {
- return i;
- }
- }
- ERR_FAIL_V(-1);
-}
diff --git a/main/input_default.h b/main/input_default.h
deleted file mode 100644
index 549093955d..0000000000
--- a/main/input_default.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/*************************************************************************/
-/* input_default.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 INPUT_DEFAULT_H
-#define INPUT_DEFAULT_H
-
-#include "core/os/input.h"
-
-class InputDefault : public Input {
-
- GDCLASS(InputDefault, Input);
- _THREAD_SAFE_CLASS_
-
- int mouse_button_mask;
-
- Set<int> keys_pressed;
- Set<int> joy_buttons_pressed;
- Map<int, float> _joy_axis;
- //Map<StringName,int> custom_action_press;
- Vector3 gravity;
- Vector3 accelerometer;
- Vector3 magnetometer;
- Vector3 gyroscope;
- Vector2 mouse_pos;
- MainLoop *main_loop;
-
- struct Action {
- uint64_t physics_frame;
- uint64_t idle_frame;
- bool pressed;
- float strength;
- };
-
- Map<StringName, Action> action_state;
-
- bool emulate_touch_from_mouse;
- bool emulate_mouse_from_touch;
-
- int mouse_from_touch_index;
-
- struct VibrationInfo {
- float weak_magnitude;
- float strong_magnitude;
- float duration; // Duration in seconds
- uint64_t timestamp;
- };
-
- Map<int, VibrationInfo> joy_vibration;
-
- struct SpeedTrack {
-
- uint64_t last_tick;
- Vector2 speed;
- Vector2 accum;
- float accum_t;
- float min_ref_frame;
- float max_ref_frame;
-
- void update(const Vector2 &p_delta_p);
- void reset();
- SpeedTrack();
- };
-
- struct Joypad {
- StringName name;
- StringName uid;
- bool connected;
- bool last_buttons[JOY_BUTTON_MAX + 19]; //apparently SDL specifies 35 possible buttons on android
- float last_axis[JOY_AXIS_MAX];
- float filter;
- int last_hat;
- int mapping;
- int hat_current;
-
- Joypad() {
- for (int i = 0; i < JOY_AXIS_MAX; i++) {
-
- last_axis[i] = 0.0f;
- }
- for (int i = 0; i < JOY_BUTTON_MAX + 19; i++) {
-
- last_buttons[i] = false;
- }
- connected = false;
- last_hat = HAT_MASK_CENTER;
- filter = 0.01f;
- mapping = -1;
- hat_current = 0;
- }
- };
-
- SpeedTrack mouse_speed_track;
- Map<int, SpeedTrack> touch_speed_track;
- Map<int, Joypad> joy_names;
- int fallback_mapping;
-
- CursorShape default_shape;
-
-public:
- enum HatMask {
- HAT_MASK_CENTER = 0,
- HAT_MASK_UP = 1,
- HAT_MASK_RIGHT = 2,
- HAT_MASK_DOWN = 4,
- HAT_MASK_LEFT = 8,
- };
-
- enum HatDir {
- HAT_UP,
- HAT_RIGHT,
- HAT_DOWN,
- HAT_LEFT,
- HAT_MAX,
- };
-
- enum {
- JOYPADS_MAX = 16,
- };
-
- struct JoyAxis {
- int min;
- float value;
- };
-
-private:
- enum JoyType {
- TYPE_BUTTON,
- TYPE_AXIS,
- TYPE_HAT,
- TYPE_MAX,
- };
-
- struct JoyEvent {
- int type;
- int index;
- int value;
- };
-
- struct JoyDeviceMapping {
-
- String uid;
- String name;
- Map<int, JoyEvent> buttons;
- Map<int, JoyEvent> axis;
- JoyEvent hat[HAT_MAX];
- };
-
- JoyEvent hat_map_default[HAT_MAX];
-
- Vector<JoyDeviceMapping> map_db;
-
- JoyEvent _find_to_event(String p_to);
- void _button_event(int p_device, int p_index, bool p_pressed);
- void _axis_event(int p_device, int p_axis, float p_value);
- float _handle_deadzone(int p_device, int p_axis, float p_value);
-
- void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
-
- List<Ref<InputEvent> > accumulated_events;
- bool use_accumulated_input;
-
-public:
- virtual bool is_key_pressed(int p_keycode) const;
- virtual bool is_mouse_button_pressed(int p_button) const;
- virtual bool is_joy_button_pressed(int p_device, int p_button) const;
- virtual bool is_action_pressed(const StringName &p_action) const;
- virtual bool is_action_just_pressed(const StringName &p_action) const;
- virtual bool is_action_just_released(const StringName &p_action) const;
- virtual float get_action_strength(const StringName &p_action) const;
-
- virtual float get_joy_axis(int p_device, int p_axis) const;
- String get_joy_name(int p_idx);
- virtual Array get_connected_joypads();
- virtual Vector2 get_joy_vibration_strength(int p_device);
- virtual float get_joy_vibration_duration(int p_device);
- virtual uint64_t get_joy_vibration_timestamp(int p_device);
- void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
- void parse_joypad_mapping(String p_mapping, bool p_update_existing);
-
- virtual Vector3 get_gravity() const;
- virtual Vector3 get_accelerometer() const;
- virtual Vector3 get_magnetometer() const;
- virtual Vector3 get_gyroscope() const;
-
- virtual Point2 get_mouse_position() const;
- virtual Point2 get_last_mouse_speed() const;
- virtual int get_mouse_button_mask() const;
-
- virtual void warp_mouse_position(const Vector2 &p_to);
- virtual Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
-
- virtual void parse_input_event(const Ref<InputEvent> &p_event);
-
- void set_gravity(const Vector3 &p_gravity);
- void set_accelerometer(const Vector3 &p_accel);
- void set_magnetometer(const Vector3 &p_magnetometer);
- void set_gyroscope(const Vector3 &p_gyroscope);
- void set_joy_axis(int p_device, int p_axis, float p_value);
-
- virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
- virtual void stop_joy_vibration(int p_device);
- virtual void vibrate_handheld(int p_duration_ms = 500);
-
- void set_main_loop(MainLoop *p_main_loop);
- void set_mouse_position(const Point2 &p_posf);
-
- void action_press(const StringName &p_action, float p_strength = 1.f);
- void action_release(const StringName &p_action);
-
- void iteration(float p_step);
-
- void set_emulate_touch_from_mouse(bool p_emulate);
- virtual bool is_emulating_touch_from_mouse() const;
- void ensure_touch_mouse_raised();
-
- void set_emulate_mouse_from_touch(bool p_emulate);
- virtual bool is_emulating_mouse_from_touch() const;
-
- virtual CursorShape get_default_cursor_shape() const;
- virtual void set_default_cursor_shape(CursorShape p_shape);
- virtual CursorShape get_current_cursor_shape() const;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
-
- 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_hat(int p_device, int p_val);
-
- virtual void add_joy_mapping(String p_mapping, bool p_update_existing = false);
- virtual void remove_joy_mapping(String p_guid);
- virtual bool is_joy_known(int p_device);
- virtual String get_joy_guid(int p_device) const;
-
- virtual String get_joy_button_string(int p_button);
- virtual String get_joy_axis_string(int p_axis);
- virtual int get_joy_axis_index_from_string(String p_axis);
- virtual int get_joy_button_index_from_string(String p_button);
-
- int get_unused_joy_id();
-
- bool is_joy_mapped(int p_device);
- String get_joy_guid_remapped(int p_device) const;
- void set_fallback_mapping(String p_guid);
-
- virtual void accumulate_input_event(const Ref<InputEvent> &p_event);
- virtual void flush_accumulated_events();
- virtual void set_use_accumulated_input(bool p_enable);
-
- virtual void release_pressed_events();
- InputDefault();
-};
-
-#endif // INPUT_DEFAULT_H
diff --git a/main/main.cpp b/main/main.cpp
index 887d423d52..fb42f71a75 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -32,7 +32,8 @@
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
-#include "core/input_map.h"
+#include "core/input/input_filter.h"
+#include "core/input/input_map.h"
#include "core/io/file_access_network.h"
#include "core/io/file_access_pack.h"
#include "core/io/file_access_zip.h"
@@ -49,7 +50,6 @@
#include "core/version_hash.gen.h"
#include "drivers/register_driver_types.h"
#include "main/app_icon.gen.h"
-#include "main/input_default.h"
#include "main/main_timer_sync.h"
#include "main/performance.h"
#include "main/splash.gen.h"
@@ -58,21 +58,24 @@
#include "modules/register_module_types.h"
#include "platform/register_platform_apis.h"
#include "scene/main/scene_tree.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/register_scene_types.h"
#include "scene/resources/packed_scene.h"
-#include "servers/arvr_server.h"
#include "servers/audio_server.h"
#include "servers/camera_server.h"
-#include "servers/navigation_2d_server.h"
-#include "servers/navigation_server.h"
-#include "servers/physics_2d_server.h"
-#include "servers/physics_server.h"
+#include "servers/display_server.h"
+#include "servers/navigation_server_2d.h"
+#include "servers/navigation_server_3d.h"
+#include "servers/physics_server_2d.h"
+#include "servers/physics_server_3d.h"
#include "servers/register_server_types.h"
+#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_wrap_mt.h"
+#include "servers/xr_server.h"
#ifdef TOOLS_ENABLED
-#include "editor/doc/doc_data.h"
-#include "editor/doc/doc_data_class_path.gen.h"
+#include "editor/doc_data.h"
+#include "editor/doc_data_class_path.gen.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/progress_dialog.h"
@@ -84,36 +87,40 @@
// Singletons
// Initialized in setup()
-static Engine *engine = NULL;
-static ProjectSettings *globals = NULL;
-static InputMap *input_map = NULL;
-static TranslationServer *translation_server = NULL;
-static Performance *performance = NULL;
-static PackedData *packed_data = NULL;
+static Engine *engine = nullptr;
+static ProjectSettings *globals = nullptr;
+static InputFilter *input = nullptr;
+static InputMap *input_map = nullptr;
+static TranslationServer *translation_server = nullptr;
+static Performance *performance = nullptr;
+static PackedData *packed_data = nullptr;
#ifdef MINIZIP_ENABLED
-static ZipArchive *zip_packed_data = NULL;
+static ZipArchive *zip_packed_data = nullptr;
#endif
-static FileAccessNetworkClient *file_access_network_client = NULL;
-static MessageQueue *message_queue = NULL;
+static FileAccessNetworkClient *file_access_network_client = nullptr;
+static MessageQueue *message_queue = nullptr;
// Initialized in setup2()
-static AudioServer *audio_server = NULL;
-static CameraServer *camera_server = NULL;
-static ARVRServer *arvr_server = NULL;
-static PhysicsServer *physics_server = NULL;
-static Physics2DServer *physics_2d_server = NULL;
-static NavigationServer *navigation_server = NULL;
-static Navigation2DServer *navigation_2d_server = NULL;
+static AudioServer *audio_server = nullptr;
+static DisplayServer *display_server = nullptr;
+static RenderingServer *rendering_server = nullptr;
+static CameraServer *camera_server = nullptr;
+static XRServer *xr_server = nullptr;
+static PhysicsServer3D *physics_server = nullptr;
+static PhysicsServer2D *physics_2d_server = nullptr;
+static NavigationServer3D *navigation_server = nullptr;
+static NavigationServer2D *navigation_2d_server = nullptr;
// We error out if setup2() doesn't turn this true
static bool _start_success = false;
// Drivers
-static int video_driver_idx = -1;
+static int display_driver_idx = -1;
static int audio_driver_idx = -1;
// Engine config/tools
+static bool single_window = false;
static bool editor = false;
static bool project_manager = false;
static String locale;
@@ -126,7 +133,12 @@ static bool auto_build_solutions = false;
// Display
-static OS::VideoMode video_mode;
+static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOWED;
+static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
+static uint32_t window_flags = 0;
+static Size2i window_size = Size2i(1024, 600);
+static bool window_vsync_via_compositor = false;
+
static int init_screen = -1;
static bool init_fullscreen = false;
static bool init_maximized = false;
@@ -168,29 +180,30 @@ static String get_full_version_string() {
return String(VERSION_FULL_BUILD) + hash;
}
-// FIXME: Could maybe be moved to PhysicsServerManager and Physics2DServerManager directly
+// FIXME: Could maybe be moved to PhysicsServer3DManager and PhysicsServer2DManager directly
// to have less code in main.cpp.
void initialize_physics() {
/// 3D Physics Server
- physics_server = PhysicsServerManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServerManager::setting_property_name));
+ physics_server = PhysicsServer3DManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
if (!physics_server) {
// Physics server not found, Use the default physics
- physics_server = PhysicsServerManager::new_default_server();
+ physics_server = PhysicsServer3DManager::new_default_server();
}
ERR_FAIL_COND(!physics_server);
physics_server->init();
/// 2D Physics server
- physics_2d_server = Physics2DServerManager::new_server(ProjectSettings::get_singleton()->get(Physics2DServerManager::setting_property_name));
+ physics_2d_server = PhysicsServer2DManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name));
if (!physics_2d_server) {
// Physics server not found, Use the default physics
- physics_2d_server = Physics2DServerManager::new_default_server();
+ physics_2d_server = PhysicsServer2DManager::new_default_server();
}
ERR_FAIL_COND(!physics_2d_server);
physics_2d_server->init();
}
void finalize_physics() {
+
physics_server->finish();
memdelete(physics_server);
@@ -198,19 +211,27 @@ void finalize_physics() {
memdelete(physics_2d_server);
}
+void finalize_display() {
+
+ rendering_server->finish();
+ memdelete(rendering_server);
+
+ memdelete(display_server);
+}
+
void initialize_navigation_server() {
- ERR_FAIL_COND(navigation_server != NULL);
+ ERR_FAIL_COND(navigation_server != nullptr);
- navigation_server = NavigationServerManager::new_default_server();
- navigation_2d_server = memnew(Navigation2DServer);
+ navigation_server = NavigationServer3DManager::new_default_server();
+ navigation_2d_server = memnew(NavigationServer2D);
}
void finalize_navigation_server() {
memdelete(navigation_server);
- navigation_server = NULL;
+ navigation_server = nullptr;
memdelete(navigation_2d_server);
- navigation_2d_server = NULL;
+ navigation_2d_server = nullptr;
}
//#define DEBUG_INIT
@@ -250,20 +271,33 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --render-thread <mode> Render thread mode ('unsafe', 'safe', 'separate').\n");
OS::get_singleton()->print(" --remote-fs <address> Remote filesystem (<host/IP>[:<port>] address).\n");
OS::get_singleton()->print(" --remote-fs-password <password> Password for remote filesystem.\n");
- OS::get_singleton()->print(" --audio-driver <driver> Audio driver (");
- for (int i = 0; i < OS::get_singleton()->get_audio_driver_count(); i++) {
- if (i != 0)
+
+ OS::get_singleton()->print(" --audio-driver <driver> Audio driver [");
+ for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
+ if (i > 0) {
OS::get_singleton()->print(", ");
- OS::get_singleton()->print("'%s'", OS::get_singleton()->get_audio_driver_name(i));
+ }
+ OS::get_singleton()->print("'%s'", AudioDriverManager::get_driver(i)->get_name());
}
- OS::get_singleton()->print(").\n");
- OS::get_singleton()->print(" --video-driver <driver> Video driver (");
- for (int i = 0; i < OS::get_singleton()->get_video_driver_count(); i++) {
- if (i != 0)
+ OS::get_singleton()->print("].\n");
+
+ OS::get_singleton()->print(" --display-driver <driver> Display driver (and rendering driver) [");
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ if (i > 0) {
OS::get_singleton()->print(", ");
- OS::get_singleton()->print("'%s'", OS::get_singleton()->get_video_driver_name(i));
+ }
+ OS::get_singleton()->print("'%s' (", DisplayServer::get_create_function_name(i));
+ Vector<String> rd = DisplayServer::get_create_function_rendering_drivers(i);
+ for (int j = 0; j < rd.size(); j++) {
+ if (j > 0) {
+ OS::get_singleton()->print(", ");
+ }
+ OS::get_singleton()->print("'%s'", rd[j].utf8().get_data());
+ }
+ OS::get_singleton()->print(")");
}
- OS::get_singleton()->print(").\n");
+ OS::get_singleton()->print("].\n");
+ OS::get_singleton()->print(" --rendering-driver <driver> Rendering driver (depends on display driver).\n");
OS::get_singleton()->print("\n");
#ifndef SERVER_ENABLED
@@ -278,6 +312,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --no-window Disable window creation (Windows only). Useful together with --script.\n");
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("\n");
#endif
@@ -313,7 +348,7 @@ void Main::print_help(const char *p_binary) {
#ifdef DEBUG_METHODS_ENABLED
OS::get_singleton()->print(" --gdnative-generate-json-api Generate JSON dump of the Godot API for GDNative bindings.\n");
#endif
- OS::get_singleton()->print(" --test <test> Run a unit test (");
+ OS::get_singleton()->print(" --test <test> Run a unit test [");
const char **test_names = tests_get_names();
const char *comma = "";
while (*test_names) {
@@ -321,7 +356,7 @@ void Main::print_help(const char *p_binary) {
test_names++;
comma = ", ";
}
- OS::get_singleton()->print(").\n");
+ OS::get_singleton()->print("].\n");
#endif
}
@@ -353,7 +388,7 @@ void Main::print_help(const char *p_binary) {
Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) {
- OS::get_singleton()->initialize_core();
+ OS::get_singleton()->initialize();
engine = memnew(Engine);
@@ -403,7 +438,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
I = args.front();
- String video_driver = "";
+ String display_driver = "";
String audio_driver = "";
String project_path = ".";
bool upwards = false;
@@ -423,6 +458,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef TOOLS_ENABLED
bool found_project = false;
#endif
+ bool use_vsync = false;
packed_data = PackedData::get_singleton();
if (!packed_data)
@@ -442,6 +478,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
I = args.front();
while (I) {
+#ifdef OSX_ENABLED
+ // Ignore the process serial number argument passed by macOS Gatekeeper.
+ // Otherwise, Godot would try to open a non-existent project on the first start and abort.
+ if (I->get().begins_with("-psn_")) {
+ I = I->next();
+ continue;
+ }
+#endif
List<String>::Element *N = I->next();
@@ -469,8 +513,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
audio_driver = I->next()->get();
bool found = false;
- for (int i = 0; i < OS::get_singleton()->get_audio_driver_count(); i++) {
- if (audio_driver == OS::get_singleton()->get_audio_driver_name(i)) {
+ for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
+ if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) {
found = true;
}
}
@@ -478,14 +522,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (!found) {
OS::get_singleton()->print("Unknown audio driver '%s', aborting.\nValid options are ", audio_driver.utf8().get_data());
- for (int i = 0; i < OS::get_singleton()->get_audio_driver_count(); i++) {
- if (i == OS::get_singleton()->get_audio_driver_count() - 1) {
+ for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
+ if (i == AudioDriverManager::get_driver_count() - 1) {
OS::get_singleton()->print(" and ");
} else if (i != 0) {
OS::get_singleton()->print(", ");
}
- OS::get_singleton()->print("'%s'", OS::get_singleton()->get_audio_driver_name(i));
+ OS::get_singleton()->print("'%s'", AudioDriverManager::get_driver(i)->get_name());
}
OS::get_singleton()->print(".\n");
@@ -499,30 +543,30 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
goto error;
}
- } else if (I->get() == "--video-driver") { // force video driver
+ } else if (I->get() == "--display-driver") { // force video driver
if (I->next()) {
- video_driver = I->next()->get();
+ display_driver = I->next()->get();
bool found = false;
- for (int i = 0; i < OS::get_singleton()->get_video_driver_count(); i++) {
- if (video_driver == OS::get_singleton()->get_video_driver_name(i)) {
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ if (display_driver == DisplayServer::get_create_function_name(i)) {
found = true;
}
}
if (!found) {
- OS::get_singleton()->print("Unknown video driver '%s', aborting.\nValid options are ", video_driver.utf8().get_data());
+ OS::get_singleton()->print("Unknown display driver '%s', aborting.\nValid options are ", display_driver.utf8().get_data());
- for (int i = 0; i < OS::get_singleton()->get_video_driver_count(); i++) {
- if (i == OS::get_singleton()->get_video_driver_count() - 1) {
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ if (i == DisplayServer::get_create_function_count() - 1) {
OS::get_singleton()->print(" and ");
} else if (i != 0) {
OS::get_singleton()->print(", ");
}
- OS::get_singleton()->print("'%s'", OS::get_singleton()->get_video_driver_name(i));
+ OS::get_singleton()->print("'%s'", DisplayServer::get_create_function_name(i));
}
OS::get_singleton()->print(".\n");
@@ -542,7 +586,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "-m" || I->get() == "--maximized") { // force maximized window
init_maximized = true;
- video_mode.maximized = true;
+ window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
} else if (I->get() == "-w" || I->get() == "--windowed") { // force windowed window
@@ -550,6 +594,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--gpu-abort") { // force windowed window
Engine::singleton->abort_on_gpu_errors = true;
+ } else if (I->get() == "--single-window") { // force single window
+
+ single_window = true;
} else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window
init_always_on_top = true;
@@ -574,8 +621,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
goto error;
}
- video_mode.width = w;
- video_mode.height = h;
+ window_size.width = w;
+ window_size.height = h;
force_res = true;
N = I->next()->next();
@@ -616,11 +663,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->set_no_window_mode(true);
} else if (I->get() == "--enable-vsync-via-compositor") {
- video_mode.vsync_via_compositor = true;
+ window_vsync_via_compositor = true;
saw_vsync_via_compositor_override = true;
} else if (I->get() == "--disable-vsync-via-compositor") {
- video_mode.vsync_via_compositor = false;
+ window_vsync_via_compositor = false;
saw_vsync_via_compositor_override = true;
#endif
} else if (I->get() == "--profiling") { // enable profiling
@@ -874,7 +921,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#else
const String error_msg = "Error: Couldn't load project data at path \"" + project_path + "\". Is the .pck file missing?\nIf you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension).\n";
OS::get_singleton()->print("%s", error_msg.ascii().get_data());
- OS::get_singleton()->alert(error_msg);
+ DisplayServer::get_singleton()->alert(error_msg);
goto error;
#endif
@@ -917,7 +964,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
main_args.push_back("--editor");
if (!init_windowed) {
init_maximized = true;
- video_mode.maximized = true;
+ window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
}
}
@@ -960,8 +1007,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("rendering/quality/driver/driver_name", "Vulkan");
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_name", PropertyInfo(Variant::STRING, "rendering/quality/driver/driver_name", PROPERTY_HINT_ENUM, "Vulkan,GLES2"));
- if (video_driver == "") {
- video_driver = GLOBAL_GET("rendering/quality/driver/driver_name");
+ if (display_driver == "") {
+ display_driver = GLOBAL_GET("rendering/quality/driver/driver_name");
}
// Assigning here even though it's GLES2-specific, to be sure that it appears in docs
@@ -983,48 +1030,58 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (use_custom_res) {
if (!force_res) {
- video_mode.width = GLOBAL_GET("display/window/size/width");
- video_mode.height = GLOBAL_GET("display/window/size/height");
+ window_size.width = GLOBAL_GET("display/window/size/width");
+ window_size.height = GLOBAL_GET("display/window/size/height");
if (globals->has_setting("display/window/size/test_width") && globals->has_setting("display/window/size/test_height")) {
int tw = globals->get("display/window/size/test_width");
if (tw > 0) {
- video_mode.width = tw;
+ window_size.width = tw;
}
int th = globals->get("display/window/size/test_height");
if (th > 0) {
- video_mode.height = th;
+ window_size.height = th;
}
}
}
- video_mode.resizable = GLOBAL_GET("display/window/size/resizable");
- video_mode.borderless_window = GLOBAL_GET("display/window/size/borderless");
- video_mode.fullscreen = GLOBAL_GET("display/window/size/fullscreen");
- video_mode.always_on_top = GLOBAL_GET("display/window/size/always_on_top");
+ if (!bool(GLOBAL_GET("display/window/size/resizable"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_RESIZE_DISABLED_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/borderless"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
+ }
+ if (bool(GLOBAL_GET("display/window/size/fullscreen"))) {
+ window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
+ }
+
+ if (bool(GLOBAL_GET("display/window/size/always_on_top"))) {
+ window_flags |= DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP;
+ }
}
if (!force_lowdpi) {
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
}
- video_mode.use_vsync = GLOBAL_DEF_RST("display/window/vsync/use_vsync", true);
- OS::get_singleton()->_use_vsync = video_mode.use_vsync;
+ use_vsync = GLOBAL_DEF_RST("display/window/vsync/use_vsync", true);
+ OS::get_singleton()->_use_vsync = use_vsync;
if (!saw_vsync_via_compositor_override) {
// If one of the command line options to enable/disable vsync via the
// window compositor ("--enable-vsync-via-compositor" or
// "--disable-vsync-via-compositor") was present then it overrides the
// project setting.
- video_mode.vsync_via_compositor = GLOBAL_DEF("display/window/vsync/vsync_via_compositor", false);
+ window_vsync_via_compositor = GLOBAL_DEF("display/window/vsync/vsync_via_compositor", false);
}
- OS::get_singleton()->_vsync_via_compositor = video_mode.vsync_via_compositor;
+ OS::get_singleton()->_vsync_via_compositor = window_vsync_via_compositor;
+ /* 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);
@@ -1049,26 +1106,26 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
/* Determine audio and video drivers */
- for (int i = 0; i < OS::get_singleton()->get_video_driver_count(); i++) {
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
- if (video_driver == OS::get_singleton()->get_video_driver_name(i)) {
+ if (display_driver == DisplayServer::get_create_function_name(i)) {
- video_driver_idx = i;
+ display_driver_idx = i;
break;
}
}
- if (video_driver_idx < 0) {
- video_driver_idx = 0;
+ if (display_driver_idx < 0) {
+ display_driver_idx = 0;
}
if (audio_driver == "") { // specified in project.godot
- audio_driver = GLOBAL_DEF_RST("audio/driver", OS::get_singleton()->get_audio_driver_name(0));
+ audio_driver = GLOBAL_DEF_RST("audio/driver", AudioDriverManager::get_driver(0)->get_name());
}
- for (int i = 0; i < OS::get_singleton()->get_audio_driver_count(); i++) {
+ for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
- if (audio_driver == OS::get_singleton()->get_audio_driver_name(i)) {
+ if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) {
audio_driver_idx = i;
break;
@@ -1083,19 +1140,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
String orientation = GLOBAL_DEF("display/window/handheld/orientation", "landscape");
if (orientation == "portrait")
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_PORTRAIT);
+ window_orientation = DisplayServer::SCREEN_PORTRAIT;
else if (orientation == "reverse_landscape")
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_REVERSE_LANDSCAPE);
+ window_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE;
else if (orientation == "reverse_portrait")
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_REVERSE_PORTRAIT);
+ window_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT;
else if (orientation == "sensor_landscape")
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_SENSOR_LANDSCAPE);
+ window_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE;
else if (orientation == "sensor_portrait")
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_SENSOR_PORTRAIT);
+ window_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT;
else if (orientation == "sensor")
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_SENSOR);
+ window_orientation = DisplayServer::SCREEN_SENSOR;
else
- OS::get_singleton()->set_screen_orientation(OS::SCREEN_LANDSCAPE);
+ window_orientation = DisplayServer::SCREEN_LANDSCAPE;
}
Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60));
@@ -1131,7 +1188,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
error:
- video_driver = "";
+ display_driver = "";
audio_driver = "";
project_path = "";
@@ -1183,15 +1240,64 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
Thread::_main_thread_id = p_main_tid_override;
}
- Error err = OS::get_singleton()->initialize(video_mode, video_driver_idx, audio_driver_idx);
- if (err != OK) {
- return err;
+ /* Initialize user data dir */
+
+ OS::get_singleton()->ensure_user_data_dir();
+
+ /* Initialize Input */
+
+ input = memnew(InputFilter);
+
+ /* Iniitalize Display Server */
+
+ {
+
+ String rendering_driver; // temp broken
+
+ Error err;
+ display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags, window_size, err);
+ if (err != OK) {
+ //ok i guess we can't use this display server, try other ones
+ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
+ if (i == display_driver_idx) {
+ continue; //don't try the same twice
+ }
+ display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags, window_size, err);
+ if (err == OK) {
+ break;
+ }
+ }
+ }
+
+ if (!display_server) {
+ ERR_PRINT("Unable to create DisplayServer, all display drivers failed.");
+ return err;
+ }
+ }
+
+ if (display_server->has_feature(DisplayServer::FEATURE_ORIENTATION)) {
+ display_server->screen_set_orientation(window_orientation);
}
+ /* Initialize Visual Server */
+
+ rendering_server = memnew(RenderingServerRaster);
+ 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));
+ }
+
+ rendering_server->init();
+
+ OS::get_singleton()->initialize_joypads();
+
+ /* Initialize Audio Driver */
+
+ AudioDriverManager::initialize(audio_driver_idx);
+
print_line(" "); //add a blank line for readability
if (init_use_custom_pos) {
- OS::get_singleton()->set_window_position(init_custom_pos);
+ display_server->window_set_position(init_custom_pos);
}
// right moment to create and initialize the audio server
@@ -1199,8 +1305,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
audio_server = memnew(AudioServer);
audio_server->init();
- // also init our arvr_server from here
- arvr_server = memnew(ARVRServer);
+ // also init our xr_server from here
+ xr_server = memnew(XRServer);
register_core_singletons();
@@ -1213,21 +1319,21 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#endif
if (init_screen != -1) {
- OS::get_singleton()->set_current_screen(init_screen);
+ DisplayServer::get_singleton()->window_set_current_screen(init_screen);
}
if (init_windowed) {
//do none..
} else if (init_maximized) {
- OS::get_singleton()->set_window_maximized(true);
+ DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_MAXIMIZED);
} else if (init_fullscreen) {
- OS::get_singleton()->set_window_fullscreen(true);
+ DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_FULLSCREEN);
}
if (init_always_on_top) {
- OS::get_singleton()->set_window_always_on_top(true);
+ DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, true);
}
if (allow_focus_steal_pid) {
- OS::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid);
+ DisplayServer::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid);
}
register_server_types();
@@ -1235,7 +1341,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Load Remaps");
Color clear = GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3));
- VisualServer::get_singleton()->set_default_clear_color(clear);
+ RenderingServer::get_singleton()->set_default_clear_color(clear);
if (show_logo) { //boot logo!
String boot_logo_path = GLOBAL_DEF("application/boot_splash/image", String());
@@ -1257,7 +1363,7 @@ 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 (boot_logo.is_valid()) {
OS::get_singleton()->_msec_splash = OS::get_singleton()->get_ticks_msec();
- VisualServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale, boot_logo_filter);
+ RenderingServer::get_singleton()->set_boot_image(boot_logo, boot_bg_color, boot_logo_scale, boot_logo_filter);
} else {
#ifndef NO_DEFAULT_BOOT_LOGO
@@ -1269,20 +1375,20 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#endif
MAIN_PRINT("Main: ClearColor");
- VisualServer::get_singleton()->set_default_clear_color(boot_bg_color);
+ RenderingServer::get_singleton()->set_default_clear_color(boot_bg_color);
MAIN_PRINT("Main: Image");
- VisualServer::get_singleton()->set_boot_image(splash, boot_bg_color, false);
+ RenderingServer::get_singleton()->set_boot_image(splash, boot_bg_color, false);
#endif
}
#ifdef TOOLS_ENABLED
Ref<Image> icon = memnew(Image(app_icon_png));
- OS::get_singleton()->set_icon(icon);
+ DisplayServer::get_singleton()->set_icon(icon);
#endif
}
MAIN_PRINT("Main: DCC");
- VisualServer::get_singleton()->set_default_clear_color(GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3)));
+ RenderingServer::get_singleton()->set_default_clear_color(GLOBAL_DEF("rendering/environment/default_clear_color", Color(0.3, 0.3, 0.3)));
MAIN_PRINT("Main: END");
GLOBAL_DEF("application/config/icon", String());
@@ -1294,10 +1400,17 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
GLOBAL_DEF("application/config/windows_native_icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/windows_native_icon", PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"));
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ InputFilter *id = InputFilter::get_singleton();
if (id) {
if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
- if (!OS::get_singleton()->has_touchscreen_ui_hint()) {
+
+ bool found_touchscreen = false;
+ for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
+ if (DisplayServer::get_singleton()->screen_is_touchscreen(i)) {
+ found_touchscreen = true;
+ }
+ }
+ if (!found_touchscreen) {
//only if no touchscreen ui hint, set emulation
id->set_emulate_touch_from_mouse(true);
}
@@ -1322,7 +1435,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
Ref<Texture2D> cursor = ResourceLoader::load(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"));
if (cursor.is_valid()) {
Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
- Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
+ InputFilter::get_singleton()->set_custom_mouse_cursor(cursor, InputFilter::CURSOR_ARROW, hotspot);
}
}
#ifdef TOOLS_ENABLED
@@ -1537,7 +1650,7 @@ bool Main::start() {
game_path = GLOBAL_DEF("application/run/main_scene", "");
}
- MainLoop *main_loop = NULL;
+ MainLoop *main_loop = nullptr;
if (editor) {
main_loop = memnew(SceneTree);
};
@@ -1589,7 +1702,7 @@ bool Main::start() {
if (!main_loop) {
if (!ClassDB::class_exists(main_loop_type)) {
- OS::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type);
+ DisplayServer::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type);
return false;
} else {
@@ -1618,6 +1731,11 @@ bool Main::start() {
}
#endif
+ bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", false);
+
+ if (single_window || (!project_manager && !editor && embed_subwindows)) {
+ sml->get_root()->set_embed_subwindows_hint(true);
+ }
ResourceLoader::add_custom_loaders();
ResourceSaver::add_custom_savers();
@@ -1664,7 +1782,7 @@ bool Main::start() {
RES res = ResourceLoader::load(path);
ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + path);
- Node *n = NULL;
+ Node *n = nullptr;
if (res->is_class("PackedScene")) {
Ref<PackedScene> ps = res;
n = ps->instance();
@@ -1676,7 +1794,7 @@ bool Main::start() {
Object *obj = ClassDB::instance(ibt);
- ERR_CONTINUE_MSG(obj == NULL, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(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);
@@ -1703,7 +1821,7 @@ bool Main::start() {
}
#ifdef TOOLS_ENABLED
- EditorNode *editor_node = NULL;
+ EditorNode *editor_node = nullptr;
if (editor) {
editor_node = memnew(EditorNode);
sml->get_root()->add_child(editor_node);
@@ -1718,7 +1836,7 @@ bool Main::start() {
{
int directional_atlas_size = GLOBAL_GET("rendering/quality/directional_shadow/size");
- VisualServer::get_singleton()->directional_shadow_atlas_set_size(directional_atlas_size);
+ RenderingServer::get_singleton()->directional_shadow_atlas_set_size(directional_atlas_size);
}
if (!editor && !project_manager) {
@@ -1727,31 +1845,32 @@ bool Main::start() {
String stretch_mode = GLOBAL_DEF("display/window/stretch/mode", "disabled");
String stretch_aspect = GLOBAL_DEF("display/window/stretch/aspect", "ignore");
Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0));
- real_t stretch_shrink = GLOBAL_DEF("display/window/stretch/shrink", 1.0);
- SceneTree::StretchMode sml_sm = SceneTree::STRETCH_MODE_DISABLED;
- if (stretch_mode == "2d")
- sml_sm = SceneTree::STRETCH_MODE_2D;
- else if (stretch_mode == "viewport")
- sml_sm = SceneTree::STRETCH_MODE_VIEWPORT;
+ Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED;
+ if (stretch_mode == "objects")
+ cs_sm = Window::CONTENT_SCALE_MODE_OBJECTS;
+ else if (stretch_mode == "pixels")
+ cs_sm = Window::CONTENT_SCALE_MODE_PIXELS;
- SceneTree::StretchAspect sml_aspect = SceneTree::STRETCH_ASPECT_IGNORE;
+ Window::ContentScaleAspect cs_aspect = Window::CONTENT_SCALE_ASPECT_IGNORE;
if (stretch_aspect == "keep")
- sml_aspect = SceneTree::STRETCH_ASPECT_KEEP;
+ cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP;
else if (stretch_aspect == "keep_width")
- sml_aspect = SceneTree::STRETCH_ASPECT_KEEP_WIDTH;
+ cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP_WIDTH;
else if (stretch_aspect == "keep_height")
- sml_aspect = SceneTree::STRETCH_ASPECT_KEEP_HEIGHT;
+ cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP_HEIGHT;
else if (stretch_aspect == "expand")
- sml_aspect = SceneTree::STRETCH_ASPECT_EXPAND;
+ cs_aspect = Window::CONTENT_SCALE_ASPECT_EXPAND;
- sml->set_screen_stretch(sml_sm, sml_aspect, stretch_size, stretch_shrink);
+ sml->get_root()->set_content_scale_mode(cs_sm);
+ sml->get_root()->set_content_scale_aspect(cs_aspect);
+ sml->get_root()->set_content_scale_size(stretch_size);
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));
String appname = ProjectSettings::get_singleton()->get("application/config/name");
appname = TranslationServer::get_singleton()->translate(appname);
- OS::get_singleton()->set_window_title(appname);
+ DisplayServer::get_singleton()->window_set_title(appname);
int shadow_atlas_size = GLOBAL_GET("rendering/quality/shadow_atlas/size");
int shadow_atlas_q0_subdiv = GLOBAL_GET("rendering/quality/shadow_atlas/quadrant_0_subdiv");
@@ -1769,7 +1888,7 @@ bool Main::start() {
sml->get_root()->set_snap_controls_to_pixels(snap_controls);
bool font_oversampling = GLOBAL_DEF("rendering/quality/dynamic_fonts/use_oversampling", true);
- sml->set_use_font_oversampling(font_oversampling);
+ 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);
@@ -1833,16 +1952,22 @@ bool Main::start() {
#ifdef TOOLS_ENABLED
if (editor) {
+ bool editor_embed_subwindows = EditorSettings::get_singleton()->get_setting("interface/editor/single_window_mode");
+
+ if (editor_embed_subwindows) {
+ sml->get_root()->set_embed_subwindows_hint(true);
+ }
+
if (game_path != GLOBAL_GET("application/run/main_scene") || !editor_node->has_scenes_in_session()) {
Error serr = editor_node->load_scene(local_game_path);
if (serr != OK)
ERR_PRINT("Failed to load scene");
}
- OS::get_singleton()->set_context(OS::CONTEXT_EDITOR);
+ DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_EDITOR);
}
#endif
if (!editor) {
- OS::get_singleton()->set_context(OS::CONTEXT_ENGINE);
+ DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_ENGINE);
}
}
@@ -1852,7 +1977,7 @@ bool Main::start() {
Crypto::load_default_certificates(GLOBAL_DEF("network/ssl/certificates", ""));
if (game_path != "") {
- Node *scene = NULL;
+ Node *scene = nullptr;
Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path);
if (scenedata.is_valid())
scene = scenedata->instance();
@@ -1863,7 +1988,7 @@ bool Main::start() {
#ifdef OSX_ENABLED
String mac_iconpath = GLOBAL_DEF("application/config/macos_native_icon", "Variant()");
if (mac_iconpath != "") {
- OS::get_singleton()->set_native_icon(mac_iconpath);
+ DisplayServer::get_singleton()->set_native_icon(mac_iconpath);
hasicon = true;
}
#endif
@@ -1871,7 +1996,7 @@ bool Main::start() {
#ifdef WINDOWS_ENABLED
String win_iconpath = GLOBAL_DEF("application/config/windows_native_icon", "Variant()");
if (win_iconpath != "") {
- OS::get_singleton()->set_native_icon(win_iconpath);
+ DisplayServer::get_singleton()->set_native_icon(win_iconpath);
hasicon = true;
}
#endif
@@ -1881,7 +2006,7 @@ bool Main::start() {
Ref<Image> icon;
icon.instance();
if (ImageLoader::load_image(iconpath, icon) == OK) {
- OS::get_singleton()->set_icon(icon);
+ DisplayServer::get_singleton()->set_icon(icon);
hasicon = true;
}
}
@@ -1896,14 +2021,14 @@ bool Main::start() {
ProgressDialog *progress_dialog = memnew(ProgressDialog);
pmanager->add_child(progress_dialog);
sml->get_root()->add_child(pmanager);
- OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN);
+ DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN);
project_manager = true;
}
if (project_manager || editor) {
// Hide console window if requested (Windows-only).
bool hide_console = EditorSettings::get_singleton()->get_setting("interface/editor/hide_console_window");
- OS::get_singleton()->set_console_visible(!hide_console);
+ DisplayServer::get_singleton()->console_set_visible(!hide_console);
// Load SSL Certificates from Editor Settings (or builtin)
Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String());
@@ -1913,7 +2038,7 @@ bool Main::start() {
if (!hasicon) {
Ref<Image> icon = memnew(Image(app_icon_png));
- OS::get_singleton()->set_icon(icon);
+ DisplayServer::get_singleton()->set_icon(icon);
}
OS::get_singleton()->set_main_loop(main_loop);
@@ -1992,25 +2117,25 @@ bool Main::iteration() {
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
- PhysicsServer::get_singleton()->sync();
- PhysicsServer::get_singleton()->flush_queries();
+ PhysicsServer3D::get_singleton()->sync();
+ PhysicsServer3D::get_singleton()->flush_queries();
- Physics2DServer::get_singleton()->sync();
- Physics2DServer::get_singleton()->flush_queries();
+ PhysicsServer2D::get_singleton()->sync();
+ PhysicsServer2D::get_singleton()->flush_queries();
if (OS::get_singleton()->get_main_loop()->iteration(frame_slice * time_scale)) {
exit = true;
break;
}
- NavigationServer::get_singleton_mut()->process(frame_slice * time_scale);
+ NavigationServer3D::get_singleton_mut()->process(frame_slice * time_scale);
message_queue->flush();
- PhysicsServer::get_singleton()->step(frame_slice * time_scale);
+ PhysicsServer3D::get_singleton()->step(frame_slice * time_scale);
- Physics2DServer::get_singleton()->end_sync();
- Physics2DServer::get_singleton()->step(frame_slice * time_scale);
+ PhysicsServer2D::get_singleton()->end_sync();
+ PhysicsServer2D::get_singleton()->step(frame_slice * time_scale);
message_queue->flush();
@@ -2028,17 +2153,17 @@ bool Main::iteration() {
}
message_queue->flush();
- VisualServer::get_singleton()->sync(); //sync if still drawing from previous frames.
+ RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
- if (OS::get_singleton()->can_draw() && !disable_render_loop) {
+ if (DisplayServer::get_singleton()->can_any_window_draw() && !disable_render_loop) {
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
- if (VisualServer::get_singleton()->has_changed()) {
- VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands
+ if (RenderingServer::get_singleton()->has_changed()) {
+ RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
}
} else {
- VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands
+ RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
force_redraw_requested = false;
}
@@ -2085,7 +2210,7 @@ bool Main::iteration() {
if (fixed_fps != -1)
return exit;
- if (OS::get_singleton()->is_in_low_processor_usage_mode() || !OS::get_singleton()->can_draw())
+ if (OS::get_singleton()->is_in_low_processor_usage_mode() || !DisplayServer::get_singleton()->can_any_window_draw())
OS::get_singleton()->delay_usec(OS::get_singleton()->get_low_processor_usage_mode_sleep_usec()); //apply some delay to force idle time
else {
uint32_t frame_delay = Engine::get_singleton()->get_frame_delay();
@@ -2153,15 +2278,15 @@ void Main::cleanup() {
ScriptServer::finish_languages();
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
- VisualServer::get_singleton()->sync();
+ RenderingServer::get_singleton()->sync();
#ifdef TOOLS_ENABLED
EditorNode::unregister_editor_types();
#endif
- if (arvr_server) {
+ if (xr_server) {
// cleanup now before we pull the rug from underneath...
- memdelete(arvr_server);
+ memdelete(xr_server);
}
ImageLoader::cleanup();
@@ -2182,8 +2307,14 @@ void Main::cleanup() {
}
OS::get_singleton()->finalize();
+
finalize_physics();
finalize_navigation_server();
+ finalize_display();
+
+ if (input) {
+ memdelete(input);
+ }
if (packed_data)
memdelete(packed_data);
diff --git a/main/main_builders.py b/main/main_builders.py
index c48aaaa572..2ea774e3b4 100644
--- a/main/main_builders.py
+++ b/main/main_builders.py
@@ -4,7 +4,6 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki
"""
from platform_methods import subprocess_main
-from compat import byte_to_str
from collections import OrderedDict
@@ -19,10 +18,10 @@ 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")
- g.write('static const Color boot_splash_bg_color = Color(0.14, 0.14, 0.14);\n')
+ 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)):
- g.write(byte_to_str(buf[i]) + ",\n")
+ g.write(str(buf[i]) + ",\n")
g.write("};\n")
g.write("#endif")
@@ -38,10 +37,10 @@ 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')
+ g.write("static const Color boot_splash_editor_bg_color = Color(0.14, 0.14, 0.14);\n")
g.write("static const unsigned char boot_splash_editor_png[] = {\n")
for i in range(len(buf)):
- g.write(byte_to_str(buf[i]) + ",\n")
+ g.write(str(buf[i]) + ",\n")
g.write("};\n")
g.write("#endif")
@@ -59,72 +58,10 @@ def make_app_icon(target, source, env):
g.write("#define APP_ICON_H\n")
g.write("static const unsigned char app_icon_png[] = {\n")
for i in range(len(buf)):
- g.write(byte_to_str(buf[i]) + ",\n")
+ g.write(str(buf[i]) + ",\n")
g.write("};\n")
g.write("#endif")
-def make_default_controller_mappings(target, source, env):
- dst = target[0]
- g = open(dst, "w")
-
- g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- g.write("#include \"core/typedefs.h\"\n")
- g.write("#include \"main/default_controller_mappings.h\"\n")
-
- # ensure mappings have a consistent order
- platform_mappings = OrderedDict()
- for src_path in source:
- with open(src_path, "r") as f:
- # read mapping file and skip header
- mapping_file_lines = f.readlines()[2:]
-
- current_platform = None
- for line in mapping_file_lines:
- if not line:
- continue
- line = line.strip()
- if len(line) == 0:
- continue
- if line[0] == "#":
- current_platform = line[1:].strip()
- if current_platform not in platform_mappings:
- platform_mappings[current_platform] = {}
- elif current_platform:
- line_parts = line.split(",")
- guid = line_parts[0]
- if guid in platform_mappings[current_platform]:
- g.write("// WARNING - DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(src_path, current_platform, platform_mappings[current_platform][guid]))
- valid_mapping = True
- for input_map in line_parts[2:]:
- if "+" in input_map or "-" in input_map or "~" in input_map:
- g.write("// WARNING - DISCARDED UNSUPPORTED MAPPING TYPE FROM DATABASE {}: {} {}\n".format(src_path, current_platform, line))
- valid_mapping = False
- break
- if valid_mapping:
- platform_mappings[current_platform][guid] = line
-
- platform_variables = {
- "Linux": "#if X11_ENABLED",
- "Windows": "#ifdef WINDOWS_ENABLED",
- "Mac OS X": "#ifdef OSX_ENABLED",
- "Android": "#if defined(__ANDROID__)",
- "iOS": "#ifdef IPHONE_ENABLED",
- "Javascript": "#ifdef JAVASCRIPT_ENABLED",
- "UWP": "#ifdef UWP_ENABLED",
- }
-
- g.write("const char* DefaultControllerMappings::mappings[] = {\n")
- for platform, mappings in platform_mappings.items():
- variable = platform_variables[platform]
- g.write("{}\n".format(variable))
- for mapping in mappings.values():
- g.write("\t\"{}\",\n".format(mapping))
- g.write("#endif\n")
-
- g.write("\tNULL\n};\n")
- g.close()
-
-
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/main/performance.cpp b/main/performance.cpp
index c7e3a41aa6..3ca7d7bed8 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -35,11 +35,11 @@
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "servers/audio_server.h"
-#include "servers/physics_2d_server.h"
-#include "servers/physics_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/physics_server_3d.h"
+#include "servers/rendering_server.h"
-Performance *Performance::singleton = NULL;
+Performance *Performance::singleton = nullptr;
void Performance::_bind_methods() {
@@ -135,22 +135,22 @@ float Performance::get_monitor(Monitor p_monitor) const {
case OBJECT_RESOURCE_COUNT: return ResourceCache::get_cached_resource_count();
case OBJECT_NODE_COUNT: return _get_node_count();
case OBJECT_ORPHAN_NODE_COUNT: return Node::orphan_node_count;
- case RENDER_OBJECTS_IN_FRAME: return VS::get_singleton()->get_render_info(VS::INFO_OBJECTS_IN_FRAME);
- case RENDER_VERTICES_IN_FRAME: return VS::get_singleton()->get_render_info(VS::INFO_VERTICES_IN_FRAME);
- case RENDER_MATERIAL_CHANGES_IN_FRAME: return VS::get_singleton()->get_render_info(VS::INFO_MATERIAL_CHANGES_IN_FRAME);
- case RENDER_SHADER_CHANGES_IN_FRAME: return VS::get_singleton()->get_render_info(VS::INFO_SHADER_CHANGES_IN_FRAME);
- case RENDER_SURFACE_CHANGES_IN_FRAME: return VS::get_singleton()->get_render_info(VS::INFO_SURFACE_CHANGES_IN_FRAME);
- case RENDER_DRAW_CALLS_IN_FRAME: return VS::get_singleton()->get_render_info(VS::INFO_DRAW_CALLS_IN_FRAME);
- case RENDER_VIDEO_MEM_USED: return VS::get_singleton()->get_render_info(VS::INFO_VIDEO_MEM_USED);
- case RENDER_TEXTURE_MEM_USED: return VS::get_singleton()->get_render_info(VS::INFO_TEXTURE_MEM_USED);
- case RENDER_VERTEX_MEM_USED: return VS::get_singleton()->get_render_info(VS::INFO_VERTEX_MEM_USED);
- case RENDER_USAGE_VIDEO_MEM_TOTAL: return VS::get_singleton()->get_render_info(VS::INFO_USAGE_VIDEO_MEM_TOTAL);
- case PHYSICS_2D_ACTIVE_OBJECTS: return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_ACTIVE_OBJECTS);
- case PHYSICS_2D_COLLISION_PAIRS: return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_COLLISION_PAIRS);
- case PHYSICS_2D_ISLAND_COUNT: return Physics2DServer::get_singleton()->get_process_info(Physics2DServer::INFO_ISLAND_COUNT);
- case PHYSICS_3D_ACTIVE_OBJECTS: return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_ACTIVE_OBJECTS);
- case PHYSICS_3D_COLLISION_PAIRS: return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_COLLISION_PAIRS);
- case PHYSICS_3D_ISLAND_COUNT: return PhysicsServer::get_singleton()->get_process_info(PhysicsServer::INFO_ISLAND_COUNT);
+ case RENDER_OBJECTS_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_OBJECTS_IN_FRAME);
+ case RENDER_VERTICES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_VERTICES_IN_FRAME);
+ case RENDER_MATERIAL_CHANGES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME);
+ case RENDER_SHADER_CHANGES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME);
+ case RENDER_SURFACE_CHANGES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME);
+ case RENDER_DRAW_CALLS_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_DRAW_CALLS_IN_FRAME);
+ case RENDER_VIDEO_MEM_USED: return RS::get_singleton()->get_render_info(RS::INFO_VIDEO_MEM_USED);
+ case RENDER_TEXTURE_MEM_USED: return RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED);
+ case RENDER_VERTEX_MEM_USED: return RS::get_singleton()->get_render_info(RS::INFO_VERTEX_MEM_USED);
+ case RENDER_USAGE_VIDEO_MEM_TOTAL: return RS::get_singleton()->get_render_info(RS::INFO_USAGE_VIDEO_MEM_TOTAL);
+ case PHYSICS_2D_ACTIVE_OBJECTS: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ACTIVE_OBJECTS);
+ case PHYSICS_2D_COLLISION_PAIRS: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_COLLISION_PAIRS);
+ case PHYSICS_2D_ISLAND_COUNT: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ISLAND_COUNT);
+ case PHYSICS_3D_ACTIVE_OBJECTS: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ACTIVE_OBJECTS);
+ case PHYSICS_3D_COLLISION_PAIRS: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_COLLISION_PAIRS);
+ case PHYSICS_3D_ISLAND_COUNT: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ISLAND_COUNT);
case AUDIO_OUTPUT_LATENCY: return AudioServer::get_singleton()->get_output_latency();
default: {
diff --git a/main/tests/SCsub b/main/tests/SCsub
index 437d9ed777..cb1d35b12f 100644
--- a/main/tests/SCsub
+++ b/main/tests/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/python
-Import('env')
+Import("env")
env.tests_sources = []
env.add_source_files(env.tests_sources, "*.cpp")
diff --git a/main/tests/test_astar.cpp b/main/tests/test_astar.cpp
index e82d885af2..e0b4a7f2c8 100644
--- a/main/tests/test_astar.cpp
+++ b/main/tests/test_astar.cpp
@@ -351,7 +351,7 @@ TestFunc test_funcs[] = {
test_abcx,
test_add_remove,
test_solutions,
- NULL
+ nullptr
};
MainLoop *test() {
@@ -370,7 +370,7 @@ MainLoop *test() {
}
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
- return NULL;
+ return nullptr;
}
} // namespace TestAStar
diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp
index 0e7c45f603..971460c655 100644
--- a/main/tests/test_gdscript.cpp
+++ b/main/tests/test_gdscript.cpp
@@ -396,7 +396,7 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i
}
}
-static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = NULL) {
+static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = nullptr) {
String txt;
if (p_func->_static)
@@ -947,17 +947,17 @@ MainLoop *test(TestType p_type) {
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
if (cmdlargs.empty()) {
- return NULL;
+ return nullptr;
}
String test = cmdlargs.back()->get();
if (!test.ends_with(".gd") && !test.ends_with(".gdc")) {
print_line("This test expects a path to a GDScript file as its last parameter. Got: " + test);
- return NULL;
+ return nullptr;
}
FileAccess *fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test);
+ ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -1030,11 +1030,11 @@ MainLoop *test(TestType p_type) {
if (err) {
print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
memdelete(fa);
- return NULL;
+ return nullptr;
}
const GDScriptParser::Node *root = parser.get_parse_tree();
- ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, NULL);
+ ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, nullptr);
const GDScriptParser::ClassNode *cnode = static_cast<const GDScriptParser::ClassNode *>(root);
_parser_show_class(cnode, 0, lines);
@@ -1048,7 +1048,7 @@ MainLoop *test(TestType p_type) {
if (err) {
print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error());
memdelete(fa);
- return NULL;
+ return nullptr;
}
Ref<GDScript> gds;
@@ -1059,7 +1059,7 @@ MainLoop *test(TestType p_type) {
if (err) {
print_line("Compile Error:\n" + itos(gdc.get_error_line()) + ":" + itos(gdc.get_error_column()) + ":" + gdc.get_error());
- return NULL;
+ return nullptr;
}
Ref<GDScript> current = gds;
@@ -1083,7 +1083,7 @@ MainLoop *test(TestType p_type) {
memdelete(fa);
- return NULL;
+ return nullptr;
}
} // namespace TestGDScript
@@ -1093,7 +1093,7 @@ namespace TestGDScript {
MainLoop *test(TestType p_type) {
ERR_PRINT("The GDScript module is disabled, therefore GDScript tests cannot be used.");
- return NULL;
+ return nullptr;
}
} // namespace TestGDScript
diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp
index f0b00aeeae..c5c8917a51 100644
--- a/main/tests/test_gui.cpp
+++ b/main/tests/test_gui.cpp
@@ -35,7 +35,7 @@
#include "core/io/image_loader.h"
#include "core/os/os.h"
#include "core/print_string.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/sprite_2d.h"
#include "scene/gui/button.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
@@ -53,8 +53,8 @@
#include "scene/gui/tree.h"
#include "scene/main/scene_tree.h"
-#include "scene/3d/camera.h"
-#include "scene/main/viewport.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/main/window.h"
namespace TestGUI {
@@ -220,7 +220,7 @@ public:
richtext->add_text("faeries.\n");
richtext->pop();
richtext->add_text("In this new episode, we will attempt to ");
- richtext->push_font(richtext->get_font("mono_font", "Fonts"));
+ richtext->push_font(richtext->get_theme_font("mono_font", "Fonts"));
richtext->push_color(Color(0.7, 0.5, 1.0));
richtext->add_text("deliver something nice");
richtext->pop();
diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp
index 2c2e6e8b45..922a55b88e 100644
--- a/main/tests/test_main.cpp
+++ b/main/tests/test_main.cpp
@@ -28,8 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "test_main.h"
+
#include "core/list.h"
-#include "core/os/main_loop.h"
#ifdef DEBUG_ENABLED
@@ -39,8 +40,8 @@
#include "test_math.h"
#include "test_oa_hash_map.h"
#include "test_ordered_hash_map.h"
-#include "test_physics.h"
#include "test_physics_2d.h"
+#include "test_physics_3d.h"
#include "test_render.h"
#include "test_shader_lang.h"
#include "test_string.h"
@@ -50,8 +51,8 @@ const char **tests_get_names() {
static const char *test_names[] = {
"string",
"math",
- "physics",
"physics_2d",
+ "physics_3d",
"render",
"oa_hash_map",
"gui",
@@ -62,7 +63,7 @@ const char **tests_get_names() {
"gd_bytecode",
"ordered_hash_map",
"astar",
- NULL
+ nullptr
};
return test_names;
@@ -80,14 +81,14 @@ MainLoop *test_main(String p_test, const List<String> &p_args) {
return TestMath::test();
}
- if (p_test == "physics") {
+ if (p_test == "physics_2d") {
- return TestPhysics::test();
+ return TestPhysics2D::test();
}
- if (p_test == "physics_2d") {
+ if (p_test == "physics_3d") {
- return TestPhysics2D::test();
+ return TestPhysics3D::test();
}
if (p_test == "render") {
@@ -143,7 +144,7 @@ MainLoop *test_main(String p_test, const List<String> &p_args) {
}
print_line("Unknown test: " + p_test);
- return NULL;
+ return nullptr;
}
#else
@@ -151,7 +152,7 @@ MainLoop *test_main(String p_test, const List<String> &p_args) {
const char **tests_get_names() {
static const char *test_names[] = {
- NULL
+ nullptr
};
return test_names;
@@ -159,7 +160,7 @@ const char **tests_get_names() {
MainLoop *test_main(String p_test, const List<String> &p_args) {
- return NULL;
+ return nullptr;
}
#endif
diff --git a/main/tests/test_main.h b/main/tests/test_main.h
index 56db3ea2a5..bdb1668d21 100644
--- a/main/tests/test_main.h
+++ b/main/tests/test_main.h
@@ -32,9 +32,10 @@
#define TEST_MAIN_H
#include "core/list.h"
+#include "core/os/main_loop.h"
#include "core/ustring.h"
const char **tests_get_names();
MainLoop *test_main(String p_test, const List<String> &p_args);
-#endif
+#endif // TEST_MAIN_H
diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp
index d91503501d..38f7371802 100644
--- a/main/tests/test_math.cpp
+++ b/main/tests/test_math.cpp
@@ -43,7 +43,7 @@
#include "core/vmap.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
-#include "servers/visual/shader_language.h"
+#include "servers/rendering/shader_language.h"
#include "core/method_ptrcall.h"
@@ -475,18 +475,18 @@ MainLoop *test() {
if (cmdlargs.empty()) {
//try editor!
- return NULL;
+ return nullptr;
}
String test = cmdlargs.back()->get();
if (test == "math") {
// Not a file name but the test name, abort.
// FIXME: This test is ugly as heck, needs fixing :)
- return NULL;
+ return nullptr;
}
FileAccess *fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test);
+ ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -580,7 +580,7 @@ MainLoop *test() {
List<String> args;
args.push_back("-l");
- Error err = OS::get_singleton()->execute("/bin/ls", args, true, NULL, &ret);
+ Error err = OS::get_singleton()->execute("/bin/ls", args, true, nullptr, &ret);
print_line("error: " + itos(err));
print_line(ret);
@@ -660,6 +660,6 @@ MainLoop *test() {
print_line("scalar /=: " + v);
}
- return NULL;
+ return nullptr;
}
} // namespace TestMath
diff --git a/main/tests/test_oa_hash_map.cpp b/main/tests/test_oa_hash_map.cpp
index edb57f2a9f..cffec7fa77 100644
--- a/main/tests/test_oa_hash_map.cpp
+++ b/main/tests/test_oa_hash_map.cpp
@@ -30,9 +30,8 @@
#include "test_oa_hash_map.h"
-#include "core/os/os.h"
-
#include "core/oa_hash_map.h"
+#include "core/os/os.h"
namespace TestOAHashMap {
@@ -153,6 +152,6 @@ MainLoop *test() {
map.set(5, 1);
}
- return NULL;
+ return nullptr;
}
} // namespace TestOAHashMap
diff --git a/main/tests/test_oa_hash_map.h b/main/tests/test_oa_hash_map.h
index 60cde961c5..eb2b3d1e99 100644
--- a/main/tests/test_oa_hash_map.h
+++ b/main/tests/test_oa_hash_map.h
@@ -37,4 +37,5 @@ namespace TestOAHashMap {
MainLoop *test();
}
+
#endif // TEST_OA_HASH_MAP_H
diff --git a/main/tests/test_ordered_hash_map.cpp b/main/tests/test_ordered_hash_map.cpp
index 4a74ad5898..0720eebaf9 100644
--- a/main/tests/test_ordered_hash_map.cpp
+++ b/main/tests/test_ordered_hash_map.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "test_ordered_hash_map.h"
+
#include "core/ordered_hash_map.h"
#include "core/os/os.h"
#include "core/pair.h"
@@ -84,7 +86,7 @@ bool test_iteration() {
map.insert(123485, 1238888);
map.insert(123, 111111);
- Vector<Pair<int, int> > expected;
+ Vector<Pair<int, int>> expected;
expected.push_back(Pair<int, int>(42, 84));
expected.push_back(Pair<int, int>(123, 111111));
expected.push_back(Pair<int, int>(0, 12934));
@@ -101,7 +103,7 @@ bool test_iteration() {
}
bool test_const_iteration(const OrderedHashMap<int, int> &map) {
- Vector<Pair<int, int> > expected;
+ Vector<Pair<int, int>> expected;
expected.push_back(Pair<int, int>(42, 84));
expected.push_back(Pair<int, int>(123, 111111));
expected.push_back(Pair<int, int>(0, 12934));
@@ -139,7 +141,7 @@ TestFunc test_funcs[] = {
test_size,
test_iteration,
test_const_iteration,
- 0
+ nullptr
};
@@ -166,6 +168,6 @@ MainLoop *test() {
OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
- return NULL;
+ return nullptr;
}
} // namespace TestOrderedHashMap
diff --git a/main/tests/test_ordered_hash_map.h b/main/tests/test_ordered_hash_map.h
index 03e559107e..f251da0ba2 100644
--- a/main/tests/test_ordered_hash_map.h
+++ b/main/tests/test_ordered_hash_map.h
@@ -31,9 +31,11 @@
#ifndef TEST_ORDERED_HASH_MAP_H
#define TEST_ORDERED_HASH_MAP_H
+#include "core/os/main_loop.h"
+
namespace TestOrderedHashMap {
MainLoop *test();
}
-#endif
+#endif // TEST_ORDERED_HASH_MAP_H
diff --git a/main/tests/test_physics.cpp b/main/tests/test_physics.cpp
deleted file mode 100644
index 0304e8f6dd..0000000000
--- a/main/tests/test_physics.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-/*************************************************************************/
-/* test_physics.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "test_physics.h"
-
-#include "core/map.h"
-#include "core/math/math_funcs.h"
-#include "core/math/quick_hull.h"
-#include "core/os/main_loop.h"
-#include "core/os/os.h"
-#include "core/print_string.h"
-#include "servers/physics_server.h"
-#include "servers/visual_server.h"
-
-class TestPhysicsMainLoop : public MainLoop {
-
- GDCLASS(TestPhysicsMainLoop, MainLoop);
-
- enum {
- LINK_COUNT = 20,
- };
-
- RID test_cube;
-
- RID plane;
- RID sphere;
- RID light;
- RID camera;
- RID mover;
- RID scenario;
- RID space;
-
- RID character;
-
- float ofs_x, ofs_y;
-
- Point2 joy_direction;
-
- List<RID> bodies;
- Map<PhysicsServer::ShapeType, RID> type_shape_map;
- Map<PhysicsServer::ShapeType, RID> type_mesh_map;
-
- void body_changed_transform(Object *p_state, RID p_visual_instance) {
-
- PhysicsDirectBodyState *state = (PhysicsDirectBodyState *)p_state;
- VisualServer *vs = VisualServer::get_singleton();
- Transform t = state->get_transform();
- vs->instance_set_transform(p_visual_instance, t);
- }
-
- bool quit;
-
-protected:
- static void _bind_methods() {
-
- ClassDB::bind_method("body_changed_transform", &TestPhysicsMainLoop::body_changed_transform);
- }
-
- RID create_body(PhysicsServer::ShapeType p_shape, PhysicsServer::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) {
-
- VisualServer *vs = VisualServer::get_singleton();
- PhysicsServer *ps = PhysicsServer::get_singleton();
-
- RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape], scenario);
- RID body = ps->body_create(p_body, !p_active_default);
- ps->body_set_space(body, space);
- ps->body_set_param(body, PhysicsServer::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_state(body, PhysicsServer::BODY_STATE_TRANSFORM, p_location);
- bodies.push_back(body);
-
- if (p_body == PhysicsServer::BODY_MODE_STATIC) {
-
- vs->instance_set_transform(mesh_instance, p_location);
- }
- return body;
- }
-
- RID create_static_plane(const Plane &p_plane) {
-
- PhysicsServer *ps = PhysicsServer::get_singleton();
-
- RID world_margin_shape = ps->shape_create(PhysicsServer::SHAPE_PLANE);
- ps->shape_set_data(world_margin_shape, p_plane);
-
- RID b = ps->body_create(PhysicsServer::BODY_MODE_STATIC);
- ps->body_set_space(b, space);
- //todo set space
- ps->body_add_shape(b, world_margin_shape);
- return b;
- }
-
- void configure_body(RID p_body, float p_mass, float p_friction, float p_bounce) {
-
- PhysicsServer *ps = PhysicsServer::get_singleton();
- ps->body_set_param(p_body, PhysicsServer::BODY_PARAM_MASS, p_mass);
- ps->body_set_param(p_body, PhysicsServer::BODY_PARAM_FRICTION, p_friction);
- ps->body_set_param(p_body, PhysicsServer::BODY_PARAM_BOUNCE, p_bounce);
- }
-
- void init_shapes() {
-
- VisualServer *vs = VisualServer::get_singleton();
- PhysicsServer *ps = PhysicsServer::get_singleton();
-
- /* SPHERE SHAPE */
- RID sphere_mesh = vs->make_sphere_mesh(10, 20, 0.5);
- type_mesh_map[PhysicsServer::SHAPE_SPHERE] = sphere_mesh;
-
- RID sphere_shape = ps->shape_create(PhysicsServer::SHAPE_SPHERE);
- ps->shape_set_data(sphere_shape, 0.5);
- type_shape_map[PhysicsServer::SHAPE_SPHERE] = sphere_shape;
-
- /* BOX SHAPE */
-
- Vector<Plane> box_planes = Geometry::build_box_planes(Vector3(0.5, 0.5, 0.5));
- RID box_mesh = vs->mesh_create();
- Geometry::MeshData box_data = Geometry::build_convex_mesh(box_planes);
- vs->mesh_add_surface_from_mesh_data(box_mesh, box_data);
- type_mesh_map[PhysicsServer::SHAPE_BOX] = box_mesh;
-
- RID box_shape = ps->shape_create(PhysicsServer::SHAPE_BOX);
- ps->shape_set_data(box_shape, Vector3(0.5, 0.5, 0.5));
- type_shape_map[PhysicsServer::SHAPE_BOX] = box_shape;
-
- /* CAPSULE SHAPE */
-
- Vector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5, 0.7, 12, Vector3::AXIS_Z);
-
- RID capsule_mesh = vs->mesh_create();
- Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
- vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data);
-
- type_mesh_map[PhysicsServer::SHAPE_CAPSULE] = capsule_mesh;
-
- RID capsule_shape = ps->shape_create(PhysicsServer::SHAPE_CAPSULE);
- Dictionary capsule_params;
- capsule_params["radius"] = 0.5;
- capsule_params["height"] = 1.4;
- ps->shape_set_data(capsule_shape, capsule_params);
- type_shape_map[PhysicsServer::SHAPE_CAPSULE] = capsule_shape;
-
- /* CONVEX SHAPE */
-
- Vector<Plane> convex_planes = Geometry::build_cylinder_planes(0.5, 0.7, 5, Vector3::AXIS_Z);
-
- RID convex_mesh = vs->mesh_create();
- Geometry::MeshData convex_data = Geometry::build_convex_mesh(convex_planes);
- QuickHull::build(convex_data.vertices, convex_data);
- vs->mesh_add_surface_from_mesh_data(convex_mesh, convex_data);
-
- type_mesh_map[PhysicsServer::SHAPE_CONVEX_POLYGON] = convex_mesh;
-
- RID convex_shape = ps->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON);
- ps->shape_set_data(convex_shape, convex_data.vertices);
- type_shape_map[PhysicsServer::SHAPE_CONVEX_POLYGON] = convex_shape;
- }
-
- void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) {
-
- VisualServer *vs = VisualServer::get_singleton();
- PhysicsServer *ps = PhysicsServer::get_singleton();
- RID trimesh_shape = ps->shape_create(PhysicsServer::SHAPE_CONCAVE_POLYGON);
- ps->shape_set_data(trimesh_shape, p_faces);
- p_faces = ps->shape_get_data(trimesh_shape); // optimized one
- 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]);
- normals.push_back(p.normal);
- normals.push_back(p.normal);
- normals.push_back(p.normal);
- }
-
- RID trimesh_mesh = vs->mesh_create();
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[VS::ARRAY_VERTEX] = p_faces;
- d[VS::ARRAY_NORMAL] = normals;
- vs->mesh_add_surface_from_arrays(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, d);
-
- RID triins = vs->instance_create2(trimesh_mesh, scenario);
-
- RID tribody = ps->body_create(PhysicsServer::BODY_MODE_STATIC);
- ps->body_set_space(tribody, space);
- //todo set space
- ps->body_add_shape(tribody, trimesh_shape);
- Transform tritrans = p_xform;
- ps->body_set_state(tribody, PhysicsServer::BODY_STATE_TRANSFORM, tritrans);
- vs->instance_set_transform(triins, tritrans);
- }
-
- void make_grid(int p_width, int p_height, float p_cellsize, float p_cellheight, const Transform &p_xform = Transform()) {
-
- Vector<Vector<float> > grid;
-
- grid.resize(p_width);
-
- for (int i = 0; i < p_width; i++) {
-
- grid.write[i].resize(p_height);
-
- for (int j = 0; j < p_height; j++) {
-
- grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight);
- }
- }
-
- Vector<Vector3> faces;
-
- for (int i = 1; i < p_width; i++) {
-
- for (int j = 1; j < p_height; j++) {
-
-#define MAKE_VERTEX(m_x, m_z) \
- faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize))
-
- MAKE_VERTEX(i, j - 1);
- MAKE_VERTEX(i, j);
- MAKE_VERTEX(i - 1, j);
-
- MAKE_VERTEX(i - 1, j - 1);
- MAKE_VERTEX(i, j - 1);
- MAKE_VERTEX(i - 1, j);
- }
- }
-
- make_trimesh(faces, p_xform);
- }
-
-public:
- virtual void input_event(const Ref<InputEvent> &p_event) {
-
- Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & 4) {
-
- ofs_y -= mm->get_relative().y / 200.0;
- ofs_x += mm->get_relative().x / 200.0;
- }
-
- if (mm.is_valid() && mm->get_button_mask() & 1) {
-
- float y = -mm->get_relative().y / 20.0;
- float x = mm->get_relative().x / 20.0;
-
- if (mover.is_valid()) {
-
- PhysicsServer *ps = PhysicsServer::get_singleton();
- Transform t = ps->body_get_state(mover, PhysicsServer::BODY_STATE_TRANSFORM);
- t.origin += Vector3(x, y, 0);
-
- ps->body_set_state(mover, PhysicsServer::BODY_STATE_TRANSFORM, t);
- }
- }
- }
-
- virtual void request_quit() {
-
- quit = true;
- }
- virtual void init() {
-
- ofs_x = ofs_y = 0;
- init_shapes();
-
- PhysicsServer *ps = PhysicsServer::get_singleton();
- space = ps->space_create();
- ps->space_set_active(space, true);
-
- VisualServer *vs = VisualServer::get_singleton();
-
- /* LIGHT */
- RID lightaux = vs->directional_light_create();
- scenario = vs->scenario_create();
- vs->light_set_shadow(lightaux, true);
- light = vs->instance_create2(lightaux, scenario);
- Transform t;
- t.rotate(Vector3(1.0, 0, 0), 0.6);
- vs->instance_set_transform(light, t);
-
- /* CAMERA */
-
- camera = vs->camera_create();
-
- RID viewport = vs->viewport_create();
- Size2i screen_size = OS::get_singleton()->get_window_size();
- vs->viewport_set_size(viewport, screen_size.x, screen_size.y);
- vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size));
- vs->viewport_set_active(viewport, true);
- vs->viewport_attach_camera(viewport, camera);
- vs->viewport_set_scenario(viewport, scenario);
-
- vs->camera_set_perspective(camera, 60, 0.1, 40.0);
- vs->camera_set_transform(camera, Transform(Basis(), Vector3(0, 9, 12)));
-
- Transform gxf;
- gxf.basis.scale(Vector3(1.4, 0.4, 1.4));
- gxf.origin = Vector3(-2, 1, -2);
- make_grid(5, 5, 2.5, 1, gxf);
- test_fall();
- quit = false;
- }
- virtual bool iteration(float p_time) {
-
- if (mover.is_valid()) {
- static float joy_speed = 10;
- PhysicsServer *ps = PhysicsServer::get_singleton();
- Transform t = ps->body_get_state(mover, PhysicsServer::BODY_STATE_TRANSFORM);
- t.origin += Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time, 0);
- ps->body_set_state(mover, PhysicsServer::BODY_STATE_TRANSFORM, t);
- };
-
- Transform cameratr;
- cameratr.rotate(Vector3(0, 1, 0), ofs_x);
- cameratr.rotate(Vector3(1, 0, 0), -ofs_y);
- cameratr.translate(Vector3(0, 2, 8));
- VisualServer *vs = VisualServer::get_singleton();
- vs->camera_set_transform(camera, cameratr);
-
- return quit;
- }
- virtual void finish() {
- }
-
- void test_joint() {
- }
-
- void test_hinge() {
- }
-
- void test_character() {
-
- VisualServer *vs = VisualServer::get_singleton();
- PhysicsServer *ps = PhysicsServer::get_singleton();
-
- Vector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5, 1, 12, 5, Vector3::AXIS_Y);
-
- RID capsule_mesh = vs->mesh_create();
- Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
- vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data);
- type_mesh_map[PhysicsServer::SHAPE_CAPSULE] = capsule_mesh;
-
- RID capsule_shape = ps->shape_create(PhysicsServer::SHAPE_CAPSULE);
- Dictionary capsule_params;
- capsule_params["radius"] = 0.5;
- capsule_params["height"] = 1;
- Transform shape_xform;
- shape_xform.rotate(Vector3(1, 0, 0), Math_PI / 2.0);
- //shape_xform.origin=Vector3(1,1,1);
- ps->shape_set_data(capsule_shape, capsule_params);
-
- RID mesh_instance = vs->instance_create2(capsule_mesh, scenario);
- character = ps->body_create(PhysicsServer::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_state(character, PhysicsServer::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2)));
- bodies.push_back(character);
- }
-
- void test_fall() {
-
- for (int i = 0; i < 35; i++) {
-
- static const PhysicsServer::ShapeType shape_idx[] = {
- PhysicsServer::SHAPE_CAPSULE,
- PhysicsServer::SHAPE_BOX,
- PhysicsServer::SHAPE_SPHERE,
- PhysicsServer::SHAPE_CONVEX_POLYGON
- };
-
- PhysicsServer::ShapeType type = shape_idx[i % 4];
-
- Transform t;
-
- t.origin = Vector3(0.0 * i, 3.5 + 1.1 * i, 0.7 + 0.0 * i);
- t.basis.rotate(Vector3(0.2, -1, 0), Math_PI / 2 * 0.6);
-
- create_body(type, PhysicsServer::BODY_MODE_RIGID, t);
- }
-
- create_static_plane(Plane(Vector3(0, 1, 0), -1));
- }
-
- void test_activate() {
-
- create_body(PhysicsServer::SHAPE_BOX, PhysicsServer::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true);
- create_static_plane(Plane(Vector3(0, 1, 0), -1));
- }
-
- virtual bool idle(float p_time) {
- return false;
- }
-
- TestPhysicsMainLoop() {
- }
-};
-
-namespace TestPhysics {
-
-MainLoop *test() {
-
- return memnew(TestPhysicsMainLoop);
-}
-} // namespace TestPhysics
diff --git a/main/tests/test_physics.h b/main/tests/test_physics.h
deleted file mode 100644
index fbbc59bba9..0000000000
--- a/main/tests/test_physics.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*************************************************************************/
-/* test_physics.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_PHYSICS_H
-#define TEST_PHYSICS_H
-
-#include "core/os/main_loop.h"
-
-namespace TestPhysics {
-
-MainLoop *test();
-}
-
-#endif
diff --git a/main/tests/test_physics_2d.cpp b/main/tests/test_physics_2d.cpp
index 160c25f43a..6feff3b0a9 100644
--- a/main/tests/test_physics_2d.cpp
+++ b/main/tests/test_physics_2d.cpp
@@ -35,8 +35,9 @@
#include "core/os/os.h"
#include "core/print_string.h"
#include "scene/resources/texture.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/display_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
static const unsigned char convex_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0xaa, 0x69, 0x71, 0xde, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x43, 0xbb, 0x7f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0x6, 0xa, 0x3, 0x13, 0x31, 0x66, 0xa7, 0xac, 0x79, 0x0, 0x0, 0x4, 0xef, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x9b, 0xdd, 0x4e, 0x2a, 0x57, 0x14, 0xc7, 0xf7, 0x1e, 0xc0, 0x19, 0x38, 0x32, 0x80, 0xa, 0x6a, 0xda, 0x18, 0xa3, 0xc6, 0x47, 0x50, 0x7b, 0xa1, 0xd9, 0x36, 0x27, 0x7e, 0x44, 0xed, 0x45, 0x4d, 0x93, 0x3e, 0x40, 0x1f, 0x64, 0x90, 0xf4, 0x1, 0xbc, 0xf0, 0xc2, 0x9c, 0x57, 0x30, 0x4d, 0xbc, 0xa8, 0x6d, 0xc, 0x69, 0x26, 0xb5, 0x68, 0x8b, 0x35, 0x7e, 0x20, 0xb4, 0xf5, 0x14, 0xbf, 0x51, 0x3c, 0x52, 0xe, 0xc, 0xe, 0xc8, 0xf0, 0xb1, 0x7a, 0x51, 0x3d, 0xb1, 0x9e, 0x19, 0x1c, 0x54, 0x70, 0x1c, 0xdc, 0x9, 0x17, 0x64, 0x8, 0xc9, 0xff, 0xb7, 0xd6, 0x7f, 0xcd, 0x3f, 0x2b, 0xd9, 0x8, 0xbd, 0x9c, 0xda, 0x3e, 0xf8, 0x31, 0xff, 0xc, 0x0, 0x8, 0x42, 0x88, 0x9c, 0x9f, 0x9f, 0xbf, 0xa, 0x87, 0xc3, 0xad, 0x7d, 0x7d, 0x7d, 0x7f, 0x23, 0x84, 0x78, 0x8c, 0x31, 0xaf, 0x55, 0x0, 0xc6, 0xc7, 0x14, 0x1e, 0x8f, 0xc7, 0xbf, 0x38, 0x3c, 0x3c, 0x6c, 0x9b, 0x9f, 0x9f, 0x6f, 0xb8, 0x82, 0x9b, 0xee, 0xe8, 0xe8, 0xf8, 0x12, 0x0, 0xbe, 0xd3, 0x2a, 0x8, 0xfc, 0x50, 0xd1, 0xf9, 0x7c, 0x9e, 0x8a, 0x46, 0xa3, 0x5f, 0x9d, 0x9e, 0x9e, 0x7e, 0xb2, 0xb0, 0xb0, 0x60, 0xe5, 0x79, 0x1e, 0xf1, 0xfc, 0x7f, 0x3a, 0x9, 0x21, 0x88, 0x10, 0x82, 0x26, 0x26, 0x26, 0xde, 0x77, 0x75, 0x75, 0x85, 0x59, 0x96, 0xfd, 0x5e, 0x6b, 0x20, 0xf0, 0x7d, 0x85, 0x4b, 0x92, 0xf4, 0xfa, 0xe0, 0xe0, 0xe0, 0xd3, 0xb9, 0xb9, 0xb9, 0x46, 0x49, 0x92, 0xea, 0x6f, 0xa, 0xbf, 0x7d, 0x8, 0x21, 0x68, 0x70, 0x70, 0xb0, 0x38, 0x39, 0x39, 0x79, 0xd6, 0xd9, 0xd9, 0xb9, 0xcf, 0x30, 0xcc, 0xa2, 0xd6, 0xad, 0x21, 0x2b, 0x1c, 0x0, 0x38, 0x41, 0x10, 0xfc, 0xdb, 0xdb, 0xdb, 0x27, 0x1e, 0x8f, 0x27, 0x4b, 0x8, 0x1, 0x84, 0x90, 0xea, 0xf, 0x21, 0x4, 0x3c, 0x1e, 0x4f, 0x76, 0x67, 0x67, 0x67, 0x3f, 0x9f, 0xcf, 0xff, 0x7c, 0x5, 0xf3, 0xd9, 0x0, 0xe0, 0x2, 0x81, 0xc0, 0xa9, 0xdb, 0xed, 0x2e, 0x94, 0x2b, 0x5c, 0xe, 0xc4, 0xca, 0xca, 0x8a, 0x18, 0x8d, 0x46, 0x3, 0x0, 0xc0, 0x69, 0x1e, 0x4, 0x0, 0x90, 0x48, 0x24, 0x12, 0xe4, 0x38, 0xee, 0x41, 0xc2, 0x6f, 0x43, 0xe0, 0x38, 0xe, 0xfc, 0x7e, 0xbf, 0x10, 0x8b, 0xc5, 0xd6, 0x35, 0xd, 0x22, 0x9b, 0xcd, 0x7a, 0x96, 0x97, 0x97, 0x33, 0xf, 0xad, 0x7c, 0x29, 0x10, 0x9b, 0x9b, 0x9b, 0xef, 0x2e, 0x2e, 0x2e, 0x7e, 0xd5, 0x1c, 0x8, 0x0, 0x20, 0xe1, 0x70, 0x38, 0xfc, 0x98, 0xd5, 0x57, 0x2, 0xe1, 0x76, 0xbb, 0xf3, 0xa1, 0x50, 0xe8, 0x38, 0x9b, 0xcd, 0xfe, 0xa2, 0x9, 0x8, 0x0, 0x40, 0x2e, 0x2f, 0x2f, 0x7d, 0x4b, 0x4b, 0x4b, 0xb9, 0x4a, 0x54, 0x5f, 0x9, 0xc4, 0xd2, 0xd2, 0x92, 0xb4, 0xb7, 0xb7, 0xf7, 0x36, 0x97, 0xcb, 0x4d, 0x3d, 0x29, 0x8, 0x0, 0xe0, 0x42, 0xa1, 0xd0, 0x71, 0xb5, 0xc4, 0xdf, 0xb6, 0xc5, 0x93, 0xe, 0x4a, 0x0, 0x20, 0xa9, 0x54, 0xea, 0x37, 0xb7, 0xdb, 0x5d, 0xa8, 0xa6, 0x78, 0x39, 0x10, 0x6b, 0x6b, 0x6b, 0xf1, 0x64, 0x32, 0xb9, 0x5a, 0x55, 0x10, 0x0, 0xc0, 0x6d, 0x6c, 0x6c, 0x9c, 0x57, 0xbb, 0xfa, 0x25, 0x40, 0x14, 0x3, 0x81, 0x40, 0x34, 0x93, 0xc9, 0x2c, 0x57, 0x1c, 0x4, 0x0, 0x90, 0x58, 0x2c, 0xb6, 0x5e, 0xe9, 0xc1, 0x77, 0x1f, 0x10, 0x53, 0x53, 0x53, 0x52, 0xc5, 0x83, 0x14, 0x0, 0x70, 0x7e, 0xbf, 0x5f, 0xd0, 0x42, 0xf5, 0x95, 0x40, 0xf8, 0x7c, 0xbe, 0xcb, 0xa3, 0xa3, 0xa3, 0x3f, 0x1e, 0xbd, 0x1b, 0x0, 0x80, 0x1c, 0x1f, 0x1f, 0x87, 0xb4, 0x56, 0xfd, 0xaa, 0x5, 0x29, 0x51, 0x14, 0xbf, 0xf5, 0xf9, 0x7c, 0x97, 0x5a, 0xad, 0xbe, 0x12, 0x88, 0xf5, 0xf5, 0xf5, 0xd8, 0x83, 0x83, 0x54, 0xb5, 0x42, 0x8f, 0x66, 0x83, 0x94, 0xd6, 0xbd, 0x5f, 0xce, 0x7c, 0x38, 0x3c, 0x3c, 0xfc, 0xb3, 0x50, 0x28, 0xb8, 0xcb, 0x2, 0x1, 0x0, 0xdc, 0xf4, 0xf4, 0xf4, 0xfe, 0x73, 0x15, 0x2f, 0x17, 0xa4, 0x22, 0x91, 0x48, 0x50, 0xb5, 0x2d, 0x0, 0x80, 0x9b, 0x99, 0x99, 0x79, 0xfb, 0xdc, 0x1, 0xc8, 0x5, 0xa9, 0x44, 0x22, 0xf1, 0xfb, 0x9d, 0x10, 0x0, 0x80, 0x9b, 0x9d, 0x9d, 0xd, 0xea, 0x5, 0xc0, 0xad, 0xfd, 0x43, 0x1a, 0x0, 0xb8, 0xdb, 0x9a, 0xa9, 0x8f, 0xb6, 0xa4, 0x46, 0xa3, 0xa4, 0xb7, 0xd5, 0x37, 0xcf, 0xf3, 0x68, 0x75, 0x75, 0xf5, 0x4c, 0xee, 0x99, 0x1c, 0x80, 0x9c, 0x1e, 0xf7, 0xff, 0x16, 0x8b, 0x45, 0x50, 0x5, 0xa0, 0xb7, 0xb7, 0xb7, 0x85, 0x10, 0xa2, 0x2b, 0xf1, 0x84, 0x10, 0xd4, 0xdf, 0xdf, 0x6f, 0x57, 0x3, 0x80, 0x37, 0x18, 0xc, 0x5, 0x3d, 0x2, 0xa0, 0x69, 0x3a, 0x8b, 0x10, 0xe2, 0x4b, 0x2, 0xc0, 0x18, 0xf3, 0xc1, 0x60, 0x70, 0x47, 0x8f, 0x16, 0x38, 0x3a, 0x3a, 0x5a, 0x93, 0x5b, 0xc3, 0x7f, 0x64, 0x81, 0xba, 0xba, 0x3a, 0x49, 0x8f, 0x0, 0x1a, 0x1a, 0x1a, 0xd4, 0xcd, 0x0, 0x93, 0xc9, 0xa4, 0xcb, 0x21, 0xe8, 0x74, 0x3a, 0xd5, 0x1, 0xa0, 0x69, 0x5a, 0x77, 0x1d, 0x80, 0x31, 0x2e, 0x38, 0x9d, 0x4e, 0xb1, 0x66, 0x1, 0x30, 0xc, 0x23, 0x28, 0x3d, 0x93, 0x9b, 0x1, 0xb9, 0x9a, 0x6, 0x60, 0x36, 0x9b, 0x75, 0xd7, 0x1, 0x4a, 0x21, 0xa8, 0x26, 0x0, 0x94, 0xa, 0x41, 0xb2, 0x0, 0x18, 0x86, 0xc9, 0xe9, 0xd, 0x80, 0x52, 0x8, 0x92, 0x5, 0x60, 0xb1, 0x58, 0x74, 0x67, 0x1, 0xa5, 0x10, 0xa4, 0x4, 0x40, 0x77, 0x43, 0xd0, 0xe1, 0x70, 0xa8, 0x9f, 0x1, 0x14, 0x45, 0x1, 0x45, 0x51, 0x79, 0x3d, 0x1, 0x68, 0x6e, 0x6e, 0x4e, 0xaa, 0x6, 0x80, 0x10, 0x42, 0x6, 0x83, 0x41, 0x37, 0x36, 0x28, 0x15, 0x82, 0x6a, 0x2, 0x0, 0x4d, 0xd3, 0xa9, 0x52, 0xcf, 0x95, 0x0, 0xe8, 0x66, 0xe, 0x98, 0xcd, 0x66, 0xa1, 0x6c, 0x0, 0x7a, 0x5a, 0x8b, 0x59, 0x2c, 0x96, 0x64, 0xcd, 0x2, 0xb8, 0x2b, 0x4, 0xe9, 0xde, 0x2, 0x77, 0x85, 0xa0, 0x9a, 0xb0, 0x40, 0xa9, 0x10, 0xa4, 0x8, 0xc0, 0x64, 0x32, 0xe9, 0x6, 0x40, 0xa9, 0x10, 0x54, 0xaa, 0x3, 0x74, 0xf3, 0x16, 0x70, 0xb9, 0x5c, 0xe5, 0x3, 0xe8, 0xe9, 0xe9, 0x69, 0xd5, 0xc3, 0x66, 0x18, 0x63, 0x5c, 0x68, 0x6a, 0x6a, 0x12, 0xcb, 0x5, 0xa0, 0x9b, 0xd5, 0x38, 0x4d, 0xd3, 0x29, 0x8a, 0xa2, 0xa0, 0x2c, 0x0, 0x18, 0x63, 0x3e, 0x14, 0xa, 0xfd, 0x55, 0xb, 0x21, 0x48, 0xd1, 0x2, 0x7a, 0x59, 0x8d, 0xdf, 0x1b, 0x80, 0x1e, 0x56, 0xe3, 0x84, 0x10, 0x34, 0x30, 0x30, 0x60, 0xbb, 0xeb, 0x77, 0x46, 0x5, 0xef, 0x48, 0xcf, 0x4d, 0xec, 0x8d, 0x99, 0x5, 0xf5, 0xf5, 0xf5, 0xef, 0x46, 0x47, 0x47, 0xb, 0x2e, 0x97, 0xeb, 0xbc, 0x54, 0x8, 0x52, 0x4, 0xc0, 0x30, 0x8c, 0xf4, 0x5c, 0x4, 0x9b, 0x4c, 0xa6, 0xf4, 0xf8, 0xf8, 0xb8, 0xc8, 0xb2, 0x6c, 0x32, 0x9d, 0x4e, 0xff, 0xd4, 0xdd, 0xdd, 0x7d, 0x66, 0x34, 0x1a, 0x8b, 0xd7, 0x3, 0xfd, 0xae, 0x5b, 0x29, 0xb2, 0x57, 0x66, 0xb6, 0xb6, 0xb6, 0xde, 0xc4, 0xe3, 0xf1, 0x6f, 0xae, 0xaf, 0xc1, 0x28, 0x5d, 0x85, 0x79, 0x2, 0xc1, 0x60, 0xb5, 0x5a, 0xa3, 0xa3, 0xa3, 0xa3, 0x45, 0xab, 0xd5, 0x9a, 0x2a, 0x16, 0x8b, 0x8b, 0x6d, 0x6d, 0x6d, 0xef, 0xd5, 0x8a, 0x55, 0xd, 0x20, 0x91, 0x48, 0xbc, 0x3e, 0x38, 0x38, 0xf8, 0xda, 0x6e, 0xb7, 0xf7, 0x5f, 0x5c, 0x5c, 0xd4, 0x7b, 0xbd, 0xde, 0xbc, 0x20, 0x8, 0xcd, 0x85, 0x42, 0x81, 0xfe, 0xf0, 0xae, 0xac, 0x10, 0x98, 0x9b, 0xd5, 0xc5, 0x18, 0x17, 0x59, 0x96, 0x3d, 0x1d, 0x19, 0x19, 0x1, 0x96, 0x65, 0x5, 0x8a, 0xa2, 0x7e, 0x6c, 0x69, 0x69, 0x49, 0x3d, 0x44, 0xb0, 0x2a, 0x0, 0x1f, 0xcc, 0x74, 0x75, 0x41, 0xea, 0xfa, 0x7b, 0x32, 0x99, 0x64, 0x76, 0x77, 0x77, 0x5d, 0xe, 0x87, 0xa3, 0x5f, 0x14, 0xc5, 0x57, 0x57, 0x60, 0x5a, 0x8b, 0xc5, 0xa2, 0xf1, 0xbe, 0x50, 0x6e, 0xa, 0x66, 0x18, 0x26, 0x31, 0x36, 0x36, 0x96, 0x65, 0x59, 0x36, 0x29, 0x49, 0x92, 0xb7, 0xbd, 0xbd, 0xfd, 0x9f, 0x72, 0xda, 0xf9, 0xd1, 0x1, 0xa8, 0x1, 0x93, 0xcf, 0xe7, 0xa9, 0x93, 0x93, 0x13, 0x1b, 0x4d, 0xd3, 0x9f, 0xb, 0x82, 0x60, 0xf5, 0x7a, 0xbd, 0xd9, 0x54, 0x2a, 0xe5, 0xcc, 0x64, 0x32, 0xe, 0xb9, 0x6e, 0xb9, 0x16, 0x8c, 0x31, 0x2e, 0xda, 0x6c, 0xb6, 0xc8, 0xd0, 0xd0, 0x10, 0x65, 0xb3, 0xd9, 0x92, 0x95, 0xa8, 0x6e, 0xc5, 0x0, 0xa8, 0xe9, 0x96, 0x68, 0x34, 0x6a, 0xdd, 0xdf, 0xdf, 0x6f, 0x76, 0xb9, 0x5c, 0x9f, 0x89, 0xa2, 0x58, 0xbf, 0xb8, 0xb8, 0x8, 0x26, 0x93, 0x29, 0x3b, 0x3c, 0x3c, 0x8c, 0xed, 0x76, 0x7b, 0xd2, 0x68, 0x34, 0xfe, 0xd0, 0xd8, 0xd8, 0x98, 0xae, 0xb6, 0xe0, 0x8a, 0x1, 0x50, 0xb, 0xe6, 0xa9, 0x5, 0xbf, 0x9c, 0x97, 0xf3, 0xff, 0xf3, 0x2f, 0x6a, 0x82, 0x7f, 0xf6, 0x4e, 0xca, 0x1b, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
@@ -65,8 +66,8 @@ class TestPhysics2DMainLoop : public MainLoop {
BodyShapeData body_shape_data[8];
void _create_body_shape_data() {
- VisualServer *vs = VisualServer::get_singleton();
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
// SEGMENT
@@ -85,13 +86,13 @@ class TestPhysics2DMainLoop : public MainLoop {
Ref<Image> image = memnew(Image(32, 2, 0, Image::FORMAT_LA8, pixels));
- body_shape_data[Physics2DServer::SHAPE_SEGMENT].image = vs->texture_2d_create(image);
+ body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].image = vs->texture_2d_create(image);
RID segment_shape = ps->segment_shape_create();
Rect2 sg(Point2(-16, 0), Point2(16, 0));
ps->shape_set_data(segment_shape, sg);
- body_shape_data[Physics2DServer::SHAPE_SEGMENT].shape = segment_shape;
+ body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].shape = segment_shape;
}
// CIRCLE
@@ -112,12 +113,12 @@ class TestPhysics2DMainLoop : public MainLoop {
Ref<Image> image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels));
- body_shape_data[Physics2DServer::SHAPE_CIRCLE].image = vs->texture_2d_create(image);
+ body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].image = vs->texture_2d_create(image);
RID circle_shape = ps->circle_shape_create();
ps->shape_set_data(circle_shape, 16);
- body_shape_data[Physics2DServer::SHAPE_CIRCLE].shape = circle_shape;
+ body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].shape = circle_shape;
}
// BOX
@@ -139,12 +140,12 @@ class TestPhysics2DMainLoop : public MainLoop {
Ref<Image> image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels));
- body_shape_data[Physics2DServer::SHAPE_RECTANGLE].image = vs->texture_2d_create(image);
+ body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].image = vs->texture_2d_create(image);
RID rectangle_shape = ps->rectangle_shape_create();
ps->shape_set_data(rectangle_shape, Vector2(16, 16));
- body_shape_data[Physics2DServer::SHAPE_RECTANGLE].shape = rectangle_shape;
+ body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].shape = rectangle_shape;
}
// CAPSULE
@@ -167,12 +168,12 @@ class TestPhysics2DMainLoop : public MainLoop {
Ref<Image> image = memnew(Image(32, 64, 0, Image::FORMAT_LA8, pixels));
- body_shape_data[Physics2DServer::SHAPE_CAPSULE].image = vs->texture_2d_create(image);
+ body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].image = vs->texture_2d_create(image);
RID capsule_shape = ps->capsule_shape_create();
ps->shape_set_data(capsule_shape, Vector2(16, 32));
- body_shape_data[Physics2DServer::SHAPE_CAPSULE].shape = capsule_shape;
+ body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].shape = capsule_shape;
}
// CONVEX
@@ -181,7 +182,7 @@ class TestPhysics2DMainLoop : public MainLoop {
Ref<Image> image = memnew(Image(convex_png));
- body_shape_data[Physics2DServer::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image);
+ body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image);
RID convex_polygon_shape = ps->convex_polygon_shape_create();
@@ -196,14 +197,14 @@ class TestPhysics2DMainLoop : public MainLoop {
arr.push_back(Point2(11, 7) - sb);
ps->shape_set_data(convex_polygon_shape, arr);
- body_shape_data[Physics2DServer::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape;
+ body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape;
}
}
void _do_ray_query() {
/*
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
ps->query_intersection_segment(ray_query,ray_from,ray_to);
*/
}
@@ -245,16 +246,16 @@ protected:
}
}
- RID _add_body(Physics2DServer::ShapeType p_shape, const Transform2D &p_xform) {
+ RID _add_body(PhysicsServer2D::ShapeType p_shape, const Transform2D &p_xform) {
- VisualServer *vs = VisualServer::get_singleton();
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
RID body = ps->body_create();
ps->body_add_shape(body, body_shape_data[p_shape].shape);
ps->body_set_space(body, space);
- ps->body_set_continuous_collision_detection_mode(body, Physics2DServer::CCD_MODE_CAST_SHAPE);
- ps->body_set_state(body, Physics2DServer::BODY_STATE_TRANSFORM, p_xform);
+ ps->body_set_continuous_collision_detection_mode(body, PhysicsServer2D::CCD_MODE_CAST_SHAPE);
+ ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform);
//print_line("add body with xform: "+p_xform);
RID sprite = vs->canvas_item_create();
@@ -272,7 +273,7 @@ protected:
void _add_plane(const Vector2 &p_normal, real_t p_d) {
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
Array arr;
arr.push_back(p_normal);
@@ -282,23 +283,23 @@ protected:
ps->shape_set_data(plane, arr);
RID plane_body = ps->body_create();
- ps->body_set_mode(plane_body, Physics2DServer::BODY_MODE_STATIC);
+ ps->body_set_mode(plane_body, PhysicsServer2D::BODY_MODE_STATIC);
ps->body_set_space(plane_body, space);
ps->body_add_shape(plane_body, plane);
}
void _add_concave(const Vector<Vector2> &p_points, const Transform2D &p_xform = Transform2D()) {
- Physics2DServer *ps = Physics2DServer::get_singleton();
- VisualServer *vs = VisualServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
RID concave = ps->concave_polygon_shape_create();
ps->shape_set_data(concave, p_points);
RID body = ps->body_create();
- ps->body_set_mode(body, Physics2DServer::BODY_MODE_STATIC);
+ ps->body_set_mode(body, PhysicsServer2D::BODY_MODE_STATIC);
ps->body_set_space(body, space);
ps->body_add_shape(body, concave);
- ps->body_set_state(body, Physics2DServer::BODY_STATE_TRANSFORM, p_xform);
+ ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform);
RID sprite = vs->canvas_item_create();
vs->canvas_item_set_parent(sprite, canvas);
@@ -309,8 +310,8 @@ protected:
}
void _body_moved(Object *p_state, RID p_sprite) {
- Physics2DDirectBodyState *state = (Physics2DDirectBodyState *)p_state;
- VisualServer::get_singleton()->canvas_item_set_transform(p_sprite, state->get_transform());
+ PhysicsDirectBodyState2D *state = (PhysicsDirectBodyState2D *)p_state;
+ RenderingServer::get_singleton()->canvas_item_set_transform(p_sprite, state->get_transform());
}
void _ray_query_callback(const RID &p_rid, ObjectID p_id, int p_shape, const Vector2 &p_point, const Vector2 &p_normal) {
@@ -323,7 +324,7 @@ protected:
ray_end = ray_to;
}
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
vs->canvas_item_clear(ray);
vs->canvas_item_add_line(ray, ray_from, ray_end, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2);
@@ -340,21 +341,21 @@ protected:
public:
virtual void init() {
- VisualServer *vs = VisualServer::get_singleton();
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
space = ps->space_create();
ps->space_set_active(space, true);
ps->set_active(true);
- ps->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1));
- ps->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY, 98);
+ ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1));
+ ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 98);
{
RID vp = vs->viewport_create();
canvas = vs->canvas_create();
- Size2i screen_size = OS::get_singleton()->get_window_size();
+ Size2i screen_size = DisplayServer::get_singleton()->window_get_size();
vs->viewport_attach_canvas(vp, canvas);
vs->viewport_set_size(vp, screen_size.x, screen_size.y);
vs->viewport_attach_to_screen(vp, Rect2(Vector2(), screen_size));
@@ -377,25 +378,25 @@ public:
for (int i = 0; i < 32; i++) {
- Physics2DServer::ShapeType types[4] = {
- Physics2DServer::SHAPE_CIRCLE,
- Physics2DServer::SHAPE_CAPSULE,
- Physics2DServer::SHAPE_RECTANGLE,
- Physics2DServer::SHAPE_CONVEX_POLYGON,
+ PhysicsServer2D::ShapeType types[4] = {
+ PhysicsServer2D::SHAPE_CIRCLE,
+ PhysicsServer2D::SHAPE_CAPSULE,
+ PhysicsServer2D::SHAPE_RECTANGLE,
+ PhysicsServer2D::SHAPE_CONVEX_POLYGON,
};
- Physics2DServer::ShapeType type = types[i % 4];
- //type=Physics2DServer::SHAPE_SEGMENT;
+ PhysicsServer2D::ShapeType type = types[i % 4];
+ //type=PhysicsServer2D::SHAPE_SEGMENT;
_add_body(type, Transform2D(i * 0.8, Point2(152 + i * 40, 100 - 40 * i)));
/*
if (i==0)
- ps->body_set_mode(b,Physics2DServer::BODY_MODE_STATIC);
+ ps->body_set_mode(b,PhysicsServer2D::BODY_MODE_STATIC);
*/
}
- //RID b= _add_body(Physics2DServer::SHAPE_CIRCLE,Transform2D(0,Point2(101,140)));
- //ps->body_set_mode(b,Physics2DServer::BODY_MODE_STATIC);
+ //RID b= _add_body(PhysicsServer2D::SHAPE_CIRCLE,Transform2D(0,Point2(101,140)));
+ //ps->body_set_mode(b,PhysicsServer2D::BODY_MODE_STATIC);
Point2 prev;
diff --git a/main/tests/test_physics_3d.cpp b/main/tests/test_physics_3d.cpp
new file mode 100644
index 0000000000..2d208ee317
--- /dev/null
+++ b/main/tests/test_physics_3d.cpp
@@ -0,0 +1,439 @@
+/*************************************************************************/
+/* test_physics_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "test_physics_3d.h"
+
+#include "core/map.h"
+#include "core/math/math_funcs.h"
+#include "core/math/quick_hull.h"
+#include "core/os/main_loop.h"
+#include "core/os/os.h"
+#include "core/print_string.h"
+#include "servers/display_server.h"
+#include "servers/physics_server_3d.h"
+#include "servers/rendering_server.h"
+
+class TestPhysics3DMainLoop : public MainLoop {
+
+ GDCLASS(TestPhysics3DMainLoop, MainLoop);
+
+ enum {
+ LINK_COUNT = 20,
+ };
+
+ RID test_cube;
+
+ RID plane;
+ RID sphere;
+ RID light;
+ RID camera;
+ RID mover;
+ RID scenario;
+ RID space;
+
+ RID character;
+
+ float ofs_x, ofs_y;
+
+ Point2 joy_direction;
+
+ List<RID> bodies;
+ Map<PhysicsServer3D::ShapeType, RID> type_shape_map;
+ Map<PhysicsServer3D::ShapeType, RID> type_mesh_map;
+
+ void body_changed_transform(Object *p_state, RID p_visual_instance) {
+
+ PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state;
+ RenderingServer *vs = RenderingServer::get_singleton();
+ Transform t = state->get_transform();
+ vs->instance_set_transform(p_visual_instance, t);
+ }
+
+ 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);
+ 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_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location);
+ bodies.push_back(body);
+
+ if (p_body == PhysicsServer3D::BODY_MODE_STATIC) {
+
+ vs->instance_set_transform(mesh_instance, p_location);
+ }
+ return body;
+ }
+
+ RID create_static_plane(const Plane &p_plane) {
+
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+
+ 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);
+ ps->body_set_space(b, space);
+ //todo set space
+ ps->body_add_shape(b, world_margin_shape);
+ return b;
+ }
+
+ void configure_body(RID p_body, float p_mass, float p_friction, float p_bounce) {
+
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+ ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_MASS, p_mass);
+ ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_FRICTION, p_friction);
+ ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_BOUNCE, p_bounce);
+ }
+
+ void init_shapes() {
+
+ RenderingServer *vs = RenderingServer::get_singleton();
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+
+ /* SPHERE SHAPE */
+ RID sphere_mesh = vs->make_sphere_mesh(10, 20, 0.5);
+ type_mesh_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_mesh;
+
+ RID sphere_shape = ps->shape_create(PhysicsServer3D::SHAPE_SPHERE);
+ ps->shape_set_data(sphere_shape, 0.5);
+ type_shape_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_shape;
+
+ /* BOX SHAPE */
+
+ Vector<Plane> box_planes = Geometry::build_box_planes(Vector3(0.5, 0.5, 0.5));
+ RID box_mesh = vs->mesh_create();
+ Geometry::MeshData box_data = Geometry::build_convex_mesh(box_planes);
+ vs->mesh_add_surface_from_mesh_data(box_mesh, box_data);
+ type_mesh_map[PhysicsServer3D::SHAPE_BOX] = box_mesh;
+
+ RID box_shape = ps->shape_create(PhysicsServer3D::SHAPE_BOX);
+ ps->shape_set_data(box_shape, Vector3(0.5, 0.5, 0.5));
+ type_shape_map[PhysicsServer3D::SHAPE_BOX] = box_shape;
+
+ /* CAPSULE SHAPE */
+
+ Vector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5, 0.7, 12, Vector3::AXIS_Z);
+
+ RID capsule_mesh = vs->mesh_create();
+ Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
+ vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data);
+
+ type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh;
+
+ RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE);
+ Dictionary capsule_params;
+ capsule_params["radius"] = 0.5;
+ capsule_params["height"] = 1.4;
+ ps->shape_set_data(capsule_shape, capsule_params);
+ type_shape_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_shape;
+
+ /* CONVEX SHAPE */
+
+ Vector<Plane> convex_planes = Geometry::build_cylinder_planes(0.5, 0.7, 5, Vector3::AXIS_Z);
+
+ RID convex_mesh = vs->mesh_create();
+ Geometry::MeshData convex_data = Geometry::build_convex_mesh(convex_planes);
+ QuickHull::build(convex_data.vertices, convex_data);
+ vs->mesh_add_surface_from_mesh_data(convex_mesh, convex_data);
+
+ type_mesh_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_mesh;
+
+ RID convex_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON);
+ ps->shape_set_data(convex_shape, convex_data.vertices);
+ type_shape_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_shape;
+ }
+
+ void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) {
+
+ 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
+ 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]);
+ normals.push_back(p.normal);
+ normals.push_back(p.normal);
+ normals.push_back(p.normal);
+ }
+
+ RID trimesh_mesh = vs->mesh_create();
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+ d[RS::ARRAY_VERTEX] = p_faces;
+ d[RS::ARRAY_NORMAL] = normals;
+ vs->mesh_add_surface_from_arrays(trimesh_mesh, RS::PRIMITIVE_TRIANGLES, d);
+
+ RID triins = vs->instance_create2(trimesh_mesh, scenario);
+
+ RID tribody = ps->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ ps->body_set_space(tribody, space);
+ //todo set space
+ ps->body_add_shape(tribody, trimesh_shape);
+ Transform tritrans = p_xform;
+ ps->body_set_state(tribody, PhysicsServer3D::BODY_STATE_TRANSFORM, tritrans);
+ vs->instance_set_transform(triins, tritrans);
+ }
+
+ void make_grid(int p_width, int p_height, float p_cellsize, float p_cellheight, const Transform &p_xform = Transform()) {
+
+ Vector<Vector<float>> grid;
+
+ grid.resize(p_width);
+
+ for (int i = 0; i < p_width; i++) {
+
+ grid.write[i].resize(p_height);
+
+ for (int j = 0; j < p_height; j++) {
+
+ grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight);
+ }
+ }
+
+ Vector<Vector3> faces;
+
+ for (int i = 1; i < p_width; i++) {
+
+ for (int j = 1; j < p_height; j++) {
+
+#define MAKE_VERTEX(m_x, m_z) \
+ faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize))
+
+ MAKE_VERTEX(i, j - 1);
+ MAKE_VERTEX(i, j);
+ MAKE_VERTEX(i - 1, j);
+
+ MAKE_VERTEX(i - 1, j - 1);
+ MAKE_VERTEX(i, j - 1);
+ MAKE_VERTEX(i - 1, j);
+ }
+ }
+
+ make_trimesh(faces, p_xform);
+ }
+
+public:
+ virtual void input_event(const Ref<InputEvent> &p_event) {
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && mm->get_button_mask() & 4) {
+
+ ofs_y -= mm->get_relative().y / 200.0;
+ ofs_x += mm->get_relative().x / 200.0;
+ }
+
+ if (mm.is_valid() && mm->get_button_mask() & 1) {
+
+ float y = -mm->get_relative().y / 20.0;
+ float x = mm->get_relative().x / 20.0;
+
+ if (mover.is_valid()) {
+
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+ Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM);
+ t.origin += Vector3(x, y, 0);
+
+ ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t);
+ }
+ }
+ }
+
+ virtual void request_quit() {
+
+ quit = true;
+ }
+ virtual void init() {
+
+ ofs_x = ofs_y = 0;
+ init_shapes();
+
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+ space = ps->space_create();
+ ps->space_set_active(space, true);
+
+ RenderingServer *vs = RenderingServer::get_singleton();
+
+ /* LIGHT */
+ RID lightaux = vs->directional_light_create();
+ scenario = vs->scenario_create();
+ vs->light_set_shadow(lightaux, true);
+ light = vs->instance_create2(lightaux, scenario);
+ Transform t;
+ t.rotate(Vector3(1.0, 0, 0), 0.6);
+ vs->instance_set_transform(light, t);
+
+ /* CAMERA */
+
+ camera = vs->camera_create();
+
+ RID viewport = vs->viewport_create();
+ Size2i screen_size = DisplayServer::get_singleton()->window_get_size();
+ vs->viewport_set_size(viewport, screen_size.x, screen_size.y);
+ vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size));
+ vs->viewport_set_active(viewport, true);
+ vs->viewport_attach_camera(viewport, camera);
+ vs->viewport_set_scenario(viewport, scenario);
+
+ vs->camera_set_perspective(camera, 60, 0.1, 40.0);
+ vs->camera_set_transform(camera, Transform(Basis(), Vector3(0, 9, 12)));
+
+ Transform gxf;
+ gxf.basis.scale(Vector3(1.4, 0.4, 1.4));
+ gxf.origin = Vector3(-2, 1, -2);
+ make_grid(5, 5, 2.5, 1, gxf);
+ test_fall();
+ quit = false;
+ }
+ virtual bool iteration(float p_time) {
+
+ if (mover.is_valid()) {
+ static float joy_speed = 10;
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+ Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM);
+ t.origin += Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time, 0);
+ ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t);
+ };
+
+ Transform cameratr;
+ cameratr.rotate(Vector3(0, 1, 0), ofs_x);
+ cameratr.rotate(Vector3(1, 0, 0), -ofs_y);
+ cameratr.translate(Vector3(0, 2, 8));
+ RenderingServer *vs = RenderingServer::get_singleton();
+ vs->camera_set_transform(camera, cameratr);
+
+ return quit;
+ }
+ virtual void finish() {
+ }
+
+ void test_joint() {
+ }
+
+ void test_hinge() {
+ }
+
+ void test_character() {
+
+ RenderingServer *vs = RenderingServer::get_singleton();
+ PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
+
+ Vector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5, 1, 12, 5, Vector3::AXIS_Y);
+
+ RID capsule_mesh = vs->mesh_create();
+ Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
+ vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data);
+ type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh;
+
+ RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE);
+ Dictionary capsule_params;
+ capsule_params["radius"] = 0.5;
+ capsule_params["height"] = 1;
+ Transform shape_xform;
+ shape_xform.rotate(Vector3(1, 0, 0), Math_PI / 2.0);
+ //shape_xform.origin=Vector3(1,1,1);
+ 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);
+ 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_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2)));
+ bodies.push_back(character);
+ }
+
+ void test_fall() {
+
+ for (int i = 0; i < 35; i++) {
+
+ static const PhysicsServer3D::ShapeType shape_idx[] = {
+ PhysicsServer3D::SHAPE_CAPSULE,
+ PhysicsServer3D::SHAPE_BOX,
+ PhysicsServer3D::SHAPE_SPHERE,
+ PhysicsServer3D::SHAPE_CONVEX_POLYGON
+ };
+
+ PhysicsServer3D::ShapeType type = shape_idx[i % 4];
+
+ Transform t;
+
+ t.origin = Vector3(0.0 * i, 3.5 + 1.1 * i, 0.7 + 0.0 * i);
+ t.basis.rotate(Vector3(0.2, -1, 0), Math_PI / 2 * 0.6);
+
+ create_body(type, PhysicsServer3D::BODY_MODE_RIGID, t);
+ }
+
+ create_static_plane(Plane(Vector3(0, 1, 0), -1));
+ }
+
+ void test_activate() {
+
+ create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true);
+ create_static_plane(Plane(Vector3(0, 1, 0), -1));
+ }
+
+ virtual bool idle(float p_time) {
+ return false;
+ }
+
+ TestPhysics3DMainLoop() {
+ }
+};
+
+namespace TestPhysics3D {
+
+MainLoop *test() {
+
+ return memnew(TestPhysics3DMainLoop);
+}
+} // namespace TestPhysics3D
diff --git a/main/tests/test_physics_3d.h b/main/tests/test_physics_3d.h
new file mode 100644
index 0000000000..d03f2c6573
--- /dev/null
+++ b/main/tests/test_physics_3d.h
@@ -0,0 +1,41 @@
+/*************************************************************************/
+/* test_physics_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_PHYSICS_H
+#define TEST_PHYSICS_H
+
+#include "core/os/main_loop.h"
+
+namespace TestPhysics3D {
+
+MainLoop *test();
+}
+
+#endif
diff --git a/main/tests/test_render.cpp b/main/tests/test_render.cpp
index 62239a5cb5..bcfcf61e25 100644
--- a/main/tests/test_render.cpp
+++ b/main/tests/test_render.cpp
@@ -36,7 +36,8 @@
#include "core/os/main_loop.h"
#include "core/os/os.h"
#include "core/print_string.h"
-#include "servers/visual_server.h"
+#include "servers/display_server.h"
+#include "servers/rendering_server.h"
#define OBJECT_COUNT 50
@@ -74,7 +75,7 @@ public:
virtual void init() {
print_line("INITIALIZING TEST RENDER");
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
test_cube = vs->get_test_cube();
scenario = vs->scenario_create();
@@ -125,7 +126,7 @@ public:
print_line("ERR: " + itos(err));
test_cube = vs->mesh_create();
vs->mesh_add_surface_from_mesh_data(test_cube, md);
- //vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME);
+ //vs->scenario_set_debug(scenario,RS::SCENARIO_DEBUG_WIREFRAME);
/*
RID sm = vs->shader_create();
@@ -163,7 +164,7 @@ public:
// vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
viewport = vs->viewport_create();
- Size2i screen_size = OS::get_singleton()->get_window_size();
+ Size2i screen_size = DisplayServer::get_singleton()->window_get_size();
vs->viewport_set_size(viewport, screen_size.x, screen_size.y);
vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size));
vs->viewport_set_active(viewport, true);
@@ -173,16 +174,16 @@ public:
vs->camera_set_perspective(camera, 60, 0.1, 1000);
/*
- RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
- vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 );
- vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 );
- vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 );
+ RID lightaux = vs->light_create( RenderingServer::LIGHT_OMNI );
+ vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_RADIUS, 80 );
+ vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ATTENUATION, 1 );
+ vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ENERGY, 1.5 );
light = vs->instance_create( lightaux );
*/
RID lightaux;
lightaux = vs->directional_light_create();
- //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
+ //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
vs->light_set_color(lightaux, Color(1.0, 1.0, 1.0));
//vs->light_set_shadow( lightaux, true );
light = vs->instance_create2(lightaux, scenario);
@@ -193,10 +194,10 @@ public:
vs->instance_set_transform(light, lla);
lightaux = vs->omni_light_create();
- //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) );
+ //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) );
vs->light_set_color(lightaux, Color(1.0, 1.0, 0.0));
- vs->light_set_param(lightaux, VisualServer::LIGHT_PARAM_RANGE, 4);
- vs->light_set_param(lightaux, VisualServer::LIGHT_PARAM_ENERGY, 8);
+ vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_RANGE, 4);
+ vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_ENERGY, 8);
//vs->light_set_shadow( lightaux, true );
//light = vs->instance_create( lightaux );
@@ -205,7 +206,7 @@ public:
}
virtual bool iteration(float p_time) {
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
//Transform t;
//t.rotate(Vector3(0, 1, 0), ofs);
//t.translate(Vector3(0,0,20 ));
diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp
index 941a6771bf..1e85f7f1d2 100644
--- a/main/tests/test_shader_lang.cpp
+++ b/main/tests/test_shader_lang.cpp
@@ -37,7 +37,7 @@
#include "core/print_string.h"
#include "scene/gui/control.h"
#include "scene/gui/text_edit.h"
-#include "servers/visual/shader_language.h"
+#include "servers/rendering/shader_language.h"
typedef ShaderLanguage SL;
@@ -310,7 +310,7 @@ MainLoop *test() {
if (cmdlargs.empty()) {
//try editor!
print_line("usage: godot -test shader_lang <shader>");
- return NULL;
+ return nullptr;
}
String test = cmdlargs.back()->get();
@@ -318,7 +318,7 @@ MainLoop *test() {
FileAccess *fa = FileAccess::open(test, FileAccess::READ);
if (!fa) {
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
String code;
@@ -347,13 +347,13 @@ MainLoop *test() {
if (err) {
print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text());
- return NULL;
+ return nullptr;
} else {
String code2;
recreate_code(&code2, sl.get_shader());
print_line("code:\n\n" + code2);
}
- return NULL;
+ return nullptr;
}
} // namespace TestShaderLang
diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp
index 84731746fa..7438e2bae9 100644
--- a/main/tests/test_string.cpp
+++ b/main/tests/test_string.cpp
@@ -1071,7 +1071,7 @@ bool test_33() {
OS::get_singleton()->print("\n\nTest 33: parse_utf8(null, -1)\n");
String empty;
- return empty.parse_utf8(NULL, -1);
+ return empty.parse_utf8(nullptr, -1);
}
bool test_34() {
@@ -1164,7 +1164,7 @@ TestFunc test_funcs[] = {
test_33,
test_34,
test_35,
- 0
+ nullptr
};
@@ -1195,6 +1195,6 @@ MainLoop *test() {
OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
- return NULL;
+ return nullptr;
}
} // namespace TestString
diff --git a/methods.py b/methods.py
index 28c6d0c097..805ae256c3 100644
--- a/methods.py
+++ b/methods.py
@@ -2,20 +2,19 @@ import os
import re
import glob
import subprocess
-from compat import iteritems, isbasestring, decode_utf8
def add_source_files(self, sources, files, warn_duplicates=True):
# Convert string to list of absolute paths (including expanding wildcard)
- if isbasestring(files):
+ if isinstance(files, (str, bytes)):
# Keep SCons project-absolute path as they are (no wildcard support)
- if files.startswith('#'):
- if '*' in files:
+ if files.startswith("#"):
+ if "*" in files:
print("ERROR: Wildcards can't be expanded in SCons project-absolute path: '{}'".format(files))
return
files = [files]
else:
- dir_path = self.Dir('.').abspath
+ dir_path = self.Dir(".").abspath
files = sorted(glob.glob(dir_path + "/" + files))
# Add each path as compiled Object following environment (self) configuration
@@ -23,7 +22,7 @@ def add_source_files(self, sources, files, warn_duplicates=True):
obj = self.Object(path)
if obj in sources:
if warn_duplicates:
- print("WARNING: Object \"{}\" already included in environment sources.".format(obj))
+ print('WARNING: Object "{}" already included in environment sources.'.format(obj))
else:
continue
sources.append(obj)
@@ -34,20 +33,20 @@ def disable_warnings(self):
if self.msvc:
# We have to remove existing warning level defines before appending /w,
# otherwise we get: "warning D9025 : overriding '/W3' with '/w'"
- warn_flags = ['/Wall', '/W4', '/W3', '/W2', '/W1', '/WX']
- self.Append(CCFLAGS=['/w'])
- self.Append(CFLAGS=['/w'])
- self.Append(CXXFLAGS=['/w'])
- self['CCFLAGS'] = [x for x in self['CCFLAGS'] if not x in warn_flags]
- self['CFLAGS'] = [x for x in self['CFLAGS'] if not x in warn_flags]
- self['CXXFLAGS'] = [x for x in self['CXXFLAGS'] if not x in warn_flags]
+ warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"]
+ self.Append(CCFLAGS=["/w"])
+ self.Append(CFLAGS=["/w"])
+ self.Append(CXXFLAGS=["/w"])
+ self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags]
+ self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags]
+ self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags]
else:
- self.Append(CCFLAGS=['-w'])
- self.Append(CFLAGS=['-w'])
- self.Append(CXXFLAGS=['-w'])
+ self.Append(CCFLAGS=["-w"])
+ self.Append(CFLAGS=["-w"])
+ self.Append(CXXFLAGS=["-w"])
-def add_module_version_string(self,s):
+def add_module_version_string(self, s):
self.module_version_string += "." + s
@@ -62,20 +61,27 @@ def update_version(module_version_string=""):
# NOTE: It is safe to generate this file here, since this is still executed serially
f = open("core/version_generated.gen.h", "w")
- f.write("#define VERSION_SHORT_NAME \"" + str(version.short_name) + "\"\n")
- f.write("#define VERSION_NAME \"" + str(version.name) + "\"\n")
+ f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ f.write("#ifndef VERSION_GENERATED_GEN_H\n")
+ f.write("#define VERSION_GENERATED_GEN_H\n")
+ f.write('#define VERSION_SHORT_NAME "' + str(version.short_name) + '"\n')
+ f.write('#define VERSION_NAME "' + str(version.name) + '"\n')
f.write("#define VERSION_MAJOR " + str(version.major) + "\n")
f.write("#define VERSION_MINOR " + str(version.minor) + "\n")
f.write("#define VERSION_PATCH " + str(version.patch) + "\n")
- f.write("#define VERSION_STATUS \"" + str(version.status) + "\"\n")
- f.write("#define VERSION_BUILD \"" + str(build_name) + "\"\n")
- f.write("#define VERSION_MODULE_CONFIG \"" + str(version.module_config) + module_version_string + "\"\n")
+ f.write('#define VERSION_STATUS "' + str(version.status) + '"\n')
+ f.write('#define VERSION_BUILD "' + str(build_name) + '"\n')
+ f.write('#define VERSION_MODULE_CONFIG "' + str(version.module_config) + module_version_string + '"\n')
f.write("#define VERSION_YEAR " + str(version.year) + "\n")
- f.write("#define VERSION_WEBSITE \"" + str(version.website) + "\"\n")
+ f.write('#define VERSION_WEBSITE "' + str(version.website) + '"\n')
+ f.write("#endif // VERSION_GENERATED_GEN_H\n")
f.close()
# NOTE: It is safe to generate this file here, since this is still executed serially
fhash = open("core/version_hash.gen.h", "w")
+ fhash.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ fhash.write("#ifndef VERSION_HASH_GEN_H\n")
+ fhash.write("#define VERSION_HASH_GEN_H\n")
githash = ""
gitfolder = ".git"
@@ -93,7 +99,8 @@ def update_version(module_version_string=""):
else:
githash = head
- fhash.write("#define VERSION_HASH \"" + githash + "\"")
+ fhash.write('#define VERSION_HASH "' + githash + '"\n')
+ fhash.write("#endif // VERSION_HASH_GEN_H\n")
fhash.close()
@@ -151,17 +158,17 @@ def detect_modules():
try:
with open("modules/" + x + "/register_types.h"):
includes_cpp += '#include "modules/' + x + '/register_types.h"\n'
- register_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
- register_cpp += '\tregister_' + x + '_types();\n'
- register_cpp += '#endif\n'
- preregister_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
- preregister_cpp += '#ifdef MODULE_' + x.upper() + '_HAS_PREREGISTER\n'
- preregister_cpp += '\tpreregister_' + x + '_types();\n'
- preregister_cpp += '#endif\n'
- preregister_cpp += '#endif\n'
- unregister_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
- unregister_cpp += '\tunregister_' + x + '_types();\n'
- unregister_cpp += '#endif\n'
+ register_cpp += "#ifdef MODULE_" + x.upper() + "_ENABLED\n"
+ register_cpp += "\tregister_" + x + "_types();\n"
+ register_cpp += "#endif\n"
+ preregister_cpp += "#ifdef MODULE_" + x.upper() + "_ENABLED\n"
+ preregister_cpp += "#ifdef MODULE_" + x.upper() + "_HAS_PREREGISTER\n"
+ preregister_cpp += "\tpreregister_" + x + "_types();\n"
+ preregister_cpp += "#endif\n"
+ preregister_cpp += "#endif\n"
+ unregister_cpp += "#ifdef MODULE_" + x.upper() + "_ENABLED\n"
+ unregister_cpp += "\tunregister_" + x + "_types();\n"
+ unregister_cpp += "#endif\n"
except IOError:
pass
@@ -184,7 +191,12 @@ void register_module_types() {
void unregister_module_types() {
%s
}
-""" % (includes_cpp, preregister_cpp, register_cpp, unregister_cpp)
+""" % (
+ includes_cpp,
+ preregister_cpp,
+ register_cpp,
+ unregister_cpp,
+ )
# NOTE: It is safe to generate this file here, since this is still executed serially
with open("modules/register_module_types.gen.cpp", "w") as f:
@@ -193,32 +205,13 @@ void unregister_module_types() {
return module_list
-def win32_spawn(sh, escape, cmd, args, env):
- import subprocess
- newargs = ' '.join(args[1:])
- cmdline = cmd + " " + newargs
- startupinfo = subprocess.STARTUPINFO()
- for e in env:
- if type(env[e]) != type(""):
- env[e] = str(env[e])
- proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env)
- _, err = proc.communicate()
- rv = proc.wait()
- if rv:
- print("=====")
- print(err)
- print("=====")
- return rv
-
-
def disable_module(self):
self.disabled_modules.append(self.current_module)
def use_windows_spawn_fix(self, platform=None):
- if (os.name != "nt"):
+ if os.name != "nt":
return # not needed, only for windows
# On Windows, due to the limited command line length, when creating a static library
@@ -229,14 +222,21 @@ def use_windows_spawn_fix(self, platform=None):
# got built correctly regardless the invocation strategy.
# Furthermore, since SCons will rebuild the library from scratch when an object file
# changes, no multiple versions of the same object file will be present.
- self.Replace(ARFLAGS='q')
+ self.Replace(ARFLAGS="q")
def mySubProcess(cmdline, env):
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env)
+ proc = subprocess.Popen(
+ cmdline,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ startupinfo=startupinfo,
+ shell=False,
+ env=env,
+ )
_, err = proc.communicate()
rv = proc.wait()
if rv:
@@ -247,11 +247,11 @@ def use_windows_spawn_fix(self, platform=None):
def mySpawn(sh, escape, cmd, args, env):
- newargs = ' '.join(args[1:])
+ newargs = " ".join(args[1:])
cmdline = cmd + " " + newargs
rv = 0
- env = {str(key): str(value) for key, value in iteritems(env)}
+ env = {str(key): str(value) for key, value in iter(env.items())}
if len(cmdline) > 32000 and cmd.endswith("ar"):
cmdline = cmd + " " + args[1] + " " + args[2] + " "
for i in range(3, len(args)):
@@ -263,15 +263,15 @@ def use_windows_spawn_fix(self, platform=None):
return rv
- self['SPAWN'] = mySpawn
+ self["SPAWN"] = mySpawn
def save_active_platforms(apnames, ap):
for x in ap:
- names = ['logo']
+ names = ["logo"]
if os.path.isfile(x + "/run_icon.png"):
- names.append('run_icon')
+ names.append("run_icon")
for name in names:
pngf = open(x + "/" + name + ".png", "rb")
@@ -281,7 +281,7 @@ def save_active_platforms(apnames, ap):
while len(b) == 1:
str += hex(ord(b))
b = pngf.read(1)
- if (len(b) == 1):
+ if len(b) == 1:
str += ","
str += "};\n"
@@ -301,30 +301,46 @@ def no_verbose(sys, env):
# Colors are disabled in non-TTY environments such as pipes. This means
# that if output is redirected to a file, it will not contain color codes
if sys.stdout.isatty():
- colors['cyan'] = '\033[96m'
- colors['purple'] = '\033[95m'
- colors['blue'] = '\033[94m'
- colors['green'] = '\033[92m'
- colors['yellow'] = '\033[93m'
- colors['red'] = '\033[91m'
- colors['end'] = '\033[0m'
+ colors["cyan"] = "\033[96m"
+ colors["purple"] = "\033[95m"
+ colors["blue"] = "\033[94m"
+ colors["green"] = "\033[92m"
+ colors["yellow"] = "\033[93m"
+ colors["red"] = "\033[91m"
+ colors["end"] = "\033[0m"
else:
- colors['cyan'] = ''
- colors['purple'] = ''
- colors['blue'] = ''
- colors['green'] = ''
- colors['yellow'] = ''
- colors['red'] = ''
- colors['end'] = ''
-
- compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
- java_compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
- compile_shared_source_message = '%sCompiling shared %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
- link_program_message = '%sLinking Program %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
- link_library_message = '%sLinking Static Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
- ranlib_library_message = '%sRanlib Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
- link_shared_library_message = '%sLinking Shared Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
- java_library_message = '%sCreating Java Archive %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+ colors["cyan"] = ""
+ colors["purple"] = ""
+ colors["blue"] = ""
+ colors["green"] = ""
+ colors["yellow"] = ""
+ colors["red"] = ""
+ colors["end"] = ""
+
+ compile_source_message = "{}Compiling {}==> {}$SOURCE{}".format(
+ colors["blue"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ java_compile_source_message = "{}Compiling {}==> {}$SOURCE{}".format(
+ colors["blue"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ compile_shared_source_message = "{}Compiling shared {}==> {}$SOURCE{}".format(
+ colors["blue"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ link_program_message = "{}Linking Program {}==> {}$TARGET{}".format(
+ colors["red"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ link_library_message = "{}Linking Static Library {}==> {}$TARGET{}".format(
+ colors["red"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ ranlib_library_message = "{}Ranlib Library {}==> {}$TARGET{}".format(
+ colors["red"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ link_shared_library_message = "{}Linking Shared Library {}==> {}$TARGET{}".format(
+ colors["red"], colors["purple"], colors["yellow"], colors["end"]
+ )
+ java_library_message = "{}Creating Java Archive {}==> {}$TARGET{}".format(
+ colors["red"], colors["purple"], colors["yellow"], colors["end"]
+ )
env.Append(CXXCOMSTR=[compile_source_message])
env.Append(CCCOMSTR=[compile_source_message])
@@ -365,70 +381,79 @@ def detect_visual_c_compiler_version(tools_env):
vc_chosen_compiler_str = ""
# Start with Pre VS 2017 checks which uses VCINSTALLDIR:
- if 'VCINSTALLDIR' in tools_env:
+ if "VCINSTALLDIR" in tools_env:
# print("Checking VCINSTALLDIR")
# find() works with -1 so big ifs below are needed... the simplest solution, in fact
# First test if amd64 and amd64_x86 compilers are present in the path
vc_amd64_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN\\amd64;")
- if(vc_amd64_compiler_detection_index > -1):
+ if vc_amd64_compiler_detection_index > -1:
vc_chosen_compiler_index = vc_amd64_compiler_detection_index
vc_chosen_compiler_str = "amd64"
vc_amd64_x86_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN\\amd64_x86;")
- if(vc_amd64_x86_compiler_detection_index > -1
- and (vc_chosen_compiler_index == -1
- or vc_chosen_compiler_index > vc_amd64_x86_compiler_detection_index)):
+ if vc_amd64_x86_compiler_detection_index > -1 and (
+ vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_amd64_x86_compiler_detection_index
+ ):
vc_chosen_compiler_index = vc_amd64_x86_compiler_detection_index
vc_chosen_compiler_str = "amd64_x86"
# Now check the 32 bit compilers
vc_x86_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN;")
- if(vc_x86_compiler_detection_index > -1
- and (vc_chosen_compiler_index == -1
- or vc_chosen_compiler_index > vc_x86_compiler_detection_index)):
+ if vc_x86_compiler_detection_index > -1 and (
+ vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_x86_compiler_detection_index
+ ):
vc_chosen_compiler_index = vc_x86_compiler_detection_index
vc_chosen_compiler_str = "x86"
- vc_x86_amd64_compiler_detection_index = tools_env["PATH"].find(tools_env['VCINSTALLDIR'] + "BIN\\x86_amd64;")
- if(vc_x86_amd64_compiler_detection_index > -1
- and (vc_chosen_compiler_index == -1
- or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index)):
+ vc_x86_amd64_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN\\x86_amd64;")
+ if vc_x86_amd64_compiler_detection_index > -1 and (
+ vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index
+ ):
vc_chosen_compiler_index = vc_x86_amd64_compiler_detection_index
vc_chosen_compiler_str = "x86_amd64"
# and for VS 2017 and newer we check VCTOOLSINSTALLDIR:
- if 'VCTOOLSINSTALLDIR' in tools_env:
+ if "VCTOOLSINSTALLDIR" in tools_env:
# Newer versions have a different path available
- vc_amd64_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX64\\X64;")
- if(vc_amd64_compiler_detection_index > -1):
+ vc_amd64_compiler_detection_index = (
+ tools_env["PATH"].upper().find(tools_env["VCTOOLSINSTALLDIR"].upper() + "BIN\\HOSTX64\\X64;")
+ )
+ if vc_amd64_compiler_detection_index > -1:
vc_chosen_compiler_index = vc_amd64_compiler_detection_index
vc_chosen_compiler_str = "amd64"
- vc_amd64_x86_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX64\\X86;")
- if(vc_amd64_x86_compiler_detection_index > -1
- and (vc_chosen_compiler_index == -1
- or vc_chosen_compiler_index > vc_amd64_x86_compiler_detection_index)):
+ vc_amd64_x86_compiler_detection_index = (
+ tools_env["PATH"].upper().find(tools_env["VCTOOLSINSTALLDIR"].upper() + "BIN\\HOSTX64\\X86;")
+ )
+ if vc_amd64_x86_compiler_detection_index > -1 and (
+ vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_amd64_x86_compiler_detection_index
+ ):
vc_chosen_compiler_index = vc_amd64_x86_compiler_detection_index
vc_chosen_compiler_str = "amd64_x86"
- vc_x86_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX86\\X86;")
- if(vc_x86_compiler_detection_index > -1
- and (vc_chosen_compiler_index == -1
- or vc_chosen_compiler_index > vc_x86_compiler_detection_index)):
+ vc_x86_compiler_detection_index = (
+ tools_env["PATH"].upper().find(tools_env["VCTOOLSINSTALLDIR"].upper() + "BIN\\HOSTX86\\X86;")
+ )
+ if vc_x86_compiler_detection_index > -1 and (
+ vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_x86_compiler_detection_index
+ ):
vc_chosen_compiler_index = vc_x86_compiler_detection_index
vc_chosen_compiler_str = "x86"
- vc_x86_amd64_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX86\\X64;")
- if(vc_x86_amd64_compiler_detection_index > -1
- and (vc_chosen_compiler_index == -1
- or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index)):
+ vc_x86_amd64_compiler_detection_index = (
+ tools_env["PATH"].upper().find(tools_env["VCTOOLSINSTALLDIR"].upper() + "BIN\\HOSTX86\\X64;")
+ )
+ if vc_x86_amd64_compiler_detection_index > -1 and (
+ vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index
+ ):
vc_chosen_compiler_index = vc_x86_amd64_compiler_detection_index
vc_chosen_compiler_str = "x86_amd64"
return vc_chosen_compiler_str
+
def find_visual_c_batch_file(env):
from SCons.Tool.MSCommon.vc import get_default_version, get_host_target, find_batch_file
@@ -436,6 +461,7 @@ def find_visual_c_batch_file(env):
(host_platform, target_platform, _) = get_host_target(env)
return find_batch_file(env, version, host_platform, target_platform)[0]
+
def generate_cpp_hint_file(filename):
if os.path.isfile(filename):
# Don't overwrite an existing hint file since the user may have customized it.
@@ -447,15 +473,19 @@ def generate_cpp_hint_file(filename):
except IOError:
print("Could not write cpp.hint file.")
+
def generate_vs_project(env, num_jobs):
batch_file = find_visual_c_batch_file(env)
if batch_file:
+
def build_commandline(commands):
- common_build_prefix = ['cmd /V /C set "plat=$(PlatformTarget)"',
- '(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))',
- 'set "tools=yes"',
- '(if "$(Configuration)"=="release" (set "tools=no"))',
- 'call "' + batch_file + '" !plat!']
+ common_build_prefix = [
+ 'cmd /V /C set "plat=$(PlatformTarget)"',
+ '(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))',
+ 'set "tools=yes"',
+ '(if "$(Configuration)"=="release" (set "tools=no"))',
+ 'call "' + batch_file + '" !plat!',
+ ]
result = " ^& ".join(common_build_prefix + [commands])
return result
@@ -471,87 +501,108 @@ def generate_vs_project(env, num_jobs):
# 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
- env['MSVSBUILDCOM'] = build_commandline('scons --directory="$(ProjectDir.TrimEnd(\'\\\'))" platform=windows progress=no target=$(Configuration) tools=!tools! -j' + str(num_jobs))
- env['MSVSREBUILDCOM'] = build_commandline('scons --directory="$(ProjectDir.TrimEnd(\'\\\'))" platform=windows progress=no target=$(Configuration) tools=!tools! vsproj=yes -j' + str(num_jobs))
- env['MSVSCLEANCOM'] = build_commandline('scons --directory="$(ProjectDir.TrimEnd(\'\\\'))" --clean platform=windows progress=no target=$(Configuration) tools=!tools! -j' + str(num_jobs))
+ env["MSVSBUILDCOM"] = build_commandline(
+ "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration) tools=!tools! -j"
+ + str(num_jobs)
+ )
+ env["MSVSREBUILDCOM"] = build_commandline(
+ "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration) tools=!tools! vsproj=yes -j"
+ + str(num_jobs)
+ )
+ env["MSVSCLEANCOM"] = build_commandline(
+ "scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" --clean platform=windows progress=no target=$(Configuration) tools=!tools! -j"
+ + str(num_jobs)
+ )
# This version information (Win32, x64, Debug, Release, Release_Debug seems to be
# required for Visual Studio to understand that it needs to generate an NMAKE
# project. Do not modify without knowing what you are doing.
- debug_variants = ['debug|Win32'] + ['debug|x64']
- release_variants = ['release|Win32'] + ['release|x64']
- release_debug_variants = ['release_debug|Win32'] + ['release_debug|x64']
+ debug_variants = ["debug|Win32"] + ["debug|x64"]
+ release_variants = ["release|Win32"] + ["release|x64"]
+ release_debug_variants = ["release_debug|Win32"] + ["release_debug|x64"]
variants = debug_variants + release_variants + release_debug_variants
- debug_targets = ['bin\\godot.windows.tools.32.exe'] + ['bin\\godot.windows.tools.64.exe']
- release_targets = ['bin\\godot.windows.opt.32.exe'] + ['bin\\godot.windows.opt.64.exe']
- release_debug_targets = ['bin\\godot.windows.opt.tools.32.exe'] + ['bin\\godot.windows.opt.tools.64.exe']
+ debug_targets = ["bin\\godot.windows.tools.32.exe"] + ["bin\\godot.windows.tools.64.exe"]
+ release_targets = ["bin\\godot.windows.opt.32.exe"] + ["bin\\godot.windows.opt.64.exe"]
+ release_debug_targets = ["bin\\godot.windows.opt.tools.32.exe"] + ["bin\\godot.windows.opt.tools.64.exe"]
targets = debug_targets + release_targets + release_debug_targets
- if not env.get('MSVS'):
- env['MSVS']['PROJECTSUFFIX'] = '.vcxproj'
- env['MSVS']['SOLUTIONSUFFIX'] = '.sln'
+ if not env.get("MSVS"):
+ env["MSVS"]["PROJECTSUFFIX"] = ".vcxproj"
+ env["MSVS"]["SOLUTIONSUFFIX"] = ".sln"
env.MSVSProject(
- target=['#godot' + env['MSVSPROJECTSUFFIX']],
+ target=["#godot" + env["MSVSPROJECTSUFFIX"]],
incs=env.vs_incs,
srcs=env.vs_srcs,
runfile=targets,
buildtarget=targets,
auto_build_solution=1,
- variant=variants)
+ variant=variants,
+ )
else:
- print("Could not locate Visual Studio batch file for setting up the build environment. Not generating VS project.")
+ print("Could not locate Visual Studio batch file to set up the build environment. Not generating VS project.")
+
def precious_program(env, program, sources, **args):
program = env.ProgramOriginal(program, sources, **args)
env.Precious(program)
return program
+
def add_shared_library(env, name, sources, **args):
library = env.SharedLibrary(name, sources, **args)
env.NoCache(library)
return library
+
def add_library(env, name, sources, **args):
library = env.Library(name, sources, **args)
env.NoCache(library)
return library
+
def add_program(env, name, sources, **args):
program = env.Program(name, sources, **args)
env.NoCache(program)
return program
+
def CommandNoCache(env, target, sources, command, **args):
result = env.Command(target, sources, command, **args)
env.NoCache(result)
return result
+
def detect_darwin_sdk_path(platform, env):
- sdk_name = ''
- if platform == 'osx':
- sdk_name = 'macosx'
- var_name = 'MACOS_SDK_PATH'
- elif platform == 'iphone':
- sdk_name = 'iphoneos'
- var_name = 'IPHONESDK'
- elif platform == 'iphonesimulator':
- sdk_name = 'iphonesimulator'
- var_name = 'IPHONESDK'
+ sdk_name = ""
+ if platform == "osx":
+ sdk_name = "macosx"
+ var_name = "MACOS_SDK_PATH"
+ elif platform == "iphone":
+ sdk_name = "iphoneos"
+ var_name = "IPHONESDK"
+ elif platform == "iphonesimulator":
+ sdk_name = "iphonesimulator"
+ var_name = "IPHONESDK"
else:
raise Exception("Invalid platform argument passed to detect_darwin_sdk_path")
if not env[var_name]:
try:
- sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip())
+ sdk_path = subprocess.check_output(["xcrun", "--sdk", sdk_name, "--show-sdk-path"]).strip().decode("utf-8")
if sdk_path:
env[var_name] = sdk_path
except (subprocess.CalledProcessError, OSError):
print("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
raise
+
def is_vanilla_clang(env):
if not using_clang(env):
return False
- version = decode_utf8(subprocess.check_output([env['CXX'], '--version']).strip())
+ try:
+ version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8")
+ except (subprocess.CalledProcessError, OSError):
+ print("Couldn't parse CXX environment variable to infer compiler version.")
+ return False
return not version.startswith("Apple")
@@ -564,20 +615,22 @@ def get_compiler_version(env):
# Not using -dumpversion as some GCC distros only return major, and
# Clang used to return hardcoded 4.2.1: # https://reviews.llvm.org/D56803
try:
- version = decode_utf8(subprocess.check_output([env.subst(env['CXX']), '--version']).strip())
+ version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8")
except (subprocess.CalledProcessError, OSError):
print("Couldn't parse CXX environment variable to infer compiler version.")
return None
else: # TODO: Implement for MSVC
return None
- match = re.search('[0-9]+\.[0-9.]+', version)
+ match = re.search("[0-9]+\.[0-9.]+", version)
if match is not None:
- return list(map(int, match.group().split('.')))
+ return list(map(int, match.group().split(".")))
else:
return None
+
def using_gcc(env):
- return 'gcc' in os.path.basename(env["CC"])
+ return "gcc" in os.path.basename(env["CC"])
+
def using_clang(env):
- return 'clang' in os.path.basename(env["CC"])
+ return "clang" in os.path.basename(env["CC"])
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 0b8a508d2f..4b2870b67a 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -50,10 +50,10 @@
1FF4C1841F584E3F00A41E41 /* GameKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System/Library/Frameworks/GameKit.framework; sourceTree = SDKROOT; };
1FF4C1861F584E5600A41E41 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
1FF4C1881F584E7600A41E41 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
- 1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = $binary.entitlements; sourceTree = "<group>"; };
+ 1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "$binary.entitlements"; sourceTree = "<group>"; };
1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dummy.cpp; sourceTree = "<group>"; };
D07CD44D1C5D589C00B7FB28 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
- D0BCFE3418AEBDA2004A7AAE /* $binary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = $binary.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ D0BCFE3418AEBDA2004A7AAE /* $binary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "$binary.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D0BCFE3718AEBDA2004A7AAE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D0BCFE3918AEBDA2004A7AAE /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
E360193621F32F37009258C1 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
@@ -62,7 +62,7 @@
D0BCFE3F18AEBDA2004A7AAE /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
D0BCFE4318AEBDA2004A7AAE /* $binary-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "$binary-Info.plist"; sourceTree = "<group>"; };
D0BCFE4518AEBDA2004A7AAE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
- D0BCFE7718AEBFEB004A7AAE /* $binary.pck */ = {isa = PBXFileReference; lastKnownFileType = file; path = $binary.pck; sourceTree = "<group>"; };
+ D0BCFE7718AEBFEB004A7AAE /* $binary.pck */ = {isa = PBXFileReference; lastKnownFileType = file; path = "$binary.pck"; sourceTree = "<group>"; };
/* End PBXFileReference section */
$additional_pbx_files
@@ -155,7 +155,7 @@
D0BCFE4218AEBDA2004A7AAE /* Supporting Files */,
1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */,
);
- path = $binary;
+ path = "$binary";
sourceTree = "<group>";
};
D0BCFE4218AEBDA2004A7AAE /* Supporting Files */ = {
@@ -422,7 +422,7 @@
ARCHS = "$godot_archs";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- CODE_SIGN_ENTITLEMENTS = $binary/$binary.entitlements;
+ CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements";
CODE_SIGN_IDENTITY = "$code_sign_identity_debug";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug";
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
@@ -448,7 +448,7 @@
ARCHS = "$godot_archs";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- CODE_SIGN_ENTITLEMENTS = $binary/$binary.entitlements;
+ CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements";
CODE_SIGN_IDENTITY = "$code_sign_identity_release";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release";
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
diff --git a/misc/dist/ios_xcode/godot_ios/dylibs/empty b/misc/dist/ios_xcode/godot_ios/dylibs/empty
index 4b5614362b..bd3e894333 100644
--- a/misc/dist/ios_xcode/godot_ios/dylibs/empty
+++ b/misc/dist/ios_xcode/godot_ios/dylibs/empty
@@ -1 +1 @@
-Dummy file to make dylibs folder exported \ No newline at end of file
+Dummy file to make dylibs folder exported
diff --git a/misc/hooks/README.md b/misc/hooks/README.md
index b18ba7df38..5661c239ed 100644
--- a/misc/hooks/README.md
+++ b/misc/hooks/README.md
@@ -5,16 +5,33 @@ contributors to make sure they comply with our requirements.
## List of hooks
-- Pre-commit hook for clang-format: Applies clang-format to the staged files
- before accepting a commit; blocks the commit and generates a patch if the
- style is not respected.
- Should work on Linux and macOS. You may need to edit the file if your
- clang-format binary is not in the `$PATH`, or if you want to enable colored
- output with pygmentize.
-- Pre-commit hook for makerst: Checks the class reference syntax using `makerst.py`.
- Should work on Linux and macOS.
+- Pre-commit hook for `clang-format`: Applies `clang-format` to the staged
+ files before accepting a commit; blocks the commit and generates a patch if
+ the style is not respected.
+ You may need to edit the file if your `clang-format` binary is not in the
+ `PATH`, or if you want to enable colored output with `pygmentize`.
+- Pre-commit hook for `black`: Applies `black` to the staged Python files
+ before accepting a commit.
+- Pre-commit hook for `makerst`: Checks the class reference syntax using
+ `makerst.py`.
## Installation
-Copy all the files from this folder into your `.git/hooks` folder, and make sure
-the hooks and helper scripts are executable.
+Copy all the files from this folder into your `.git/hooks` folder, and make
+sure the hooks and helper scripts are executable.
+
+#### Linux/MacOS
+
+The hooks rely on bash scripts and tools which should be in the system `PATH`,
+so they should work out of the box on Linux/macOS.
+
+#### Windows
+
+##### clang-format
+- Download LLVM for Windows (version 8 or later) from
+ <https://releases.llvm.org/download.html>
+- Make sure LLVM is added to the `PATH` during installation
+
+##### black
+- Python installation: make sure Python is added to the `PATH`
+- Install `black` - in any console: `pip3 install black`
diff --git a/misc/hooks/pre-commit b/misc/hooks/pre-commit
index 36e9935785..40cb00253b 100755
--- a/misc/hooks/pre-commit
+++ b/misc/hooks/pre-commit
@@ -14,7 +14,7 @@
# as this script. Hooks should return 0 if successful and nonzero to cancel the
# commit. They are executed in the order in which they are listed.
#HOOKS="pre-commit-compile pre-commit-uncrustify"
-HOOKS="pre-commit-clang-format pre-commit-makerst"
+HOOKS="pre-commit-clang-format pre-commit-black pre-commit-makerst"
###########################################################
# There should be no need to change anything below this line.
diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black
new file mode 100755
index 0000000000..2dcc2e8cf1
--- /dev/null
+++ b/misc/hooks/pre-commit-black
@@ -0,0 +1,132 @@
+#!/usr/bin/env bash
+
+# git pre-commit hook that runs a black stylecheck.
+# Based on pre-commit-clang-format.
+
+##################################################################
+# SETTINGS
+# Set path to black binary.
+BLACK=`which black`
+BLACK_OPTIONS="-l 120"
+
+# Remove any older patches from previous commits. Set to true or false.
+DELETE_OLD_PATCHES=false
+
+# File types to parse.
+FILE_NAMES="SConstruct SCsub"
+FILE_EXTS="py"
+
+# Use pygmentize instead of cat to parse diff with highlighting.
+# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
+PYGMENTIZE=`which pygmentize`
+if [ ! -z "$PYGMENTIZE" ]; then
+ READER="pygmentize -l diff"
+else
+ READER=cat
+fi
+
+##################################################################
+# There should be no need to change anything below this line.
+
+. "$(dirname -- "$0")/canonicalize_filename.sh"
+
+# exit on error
+set -e
+
+# check whether the given file matches any of the set extensions
+matches_name_or_extension() {
+ local filename=$(basename "$1")
+ local extension=".${filename##*.}"
+
+ for name in $FILE_NAMES; do [[ "$name" == "$filename" ]] && return 0; done
+ for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
+
+ return 1
+}
+
+# necessary check for initial commit
+if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+if [ ! -x "$BLACK" ] ; then
+ printf "Error: black executable not found.\n"
+ printf "Set the correct path in $(canonicalize_filename "$0").\n"
+ exit 1
+fi
+
+# create a random filename to store our generated patch
+prefix="pre-commit-black"
+suffix="$(date +%s)"
+patch="/tmp/$prefix-$suffix.patch"
+
+# clean up any older black patches
+$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
+
+# create one patch containing all changes to the files
+git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
+do
+ # ignore thirdparty files
+ if grep -q "thirdparty" <<< $file; then
+ continue;
+ fi
+
+ # ignore file if not one of the names or extensions we handle
+ if ! matches_name_or_extension "$file"; then
+ continue;
+ fi
+
+ # format our file with black, create a patch with diff and append it to our $patch
+ # The sed call is necessary to transform the patch from
+ # --- $file timestamp
+ # +++ $file timestamp
+ # to both lines working on the same file and having a/ and b/ prefix.
+ # Else it can not be applied with 'git apply'.
+ "$BLACK" "$BLACK_OPTIONS" --diff "$file" | \
+ sed -e "1s|--- |--- a/|" -e "2s|+++ |+++ b/|" >> "$patch"
+done
+
+# if no patch has been generated all is ok, clean up the file stub and exit
+if [ ! -s "$patch" ] ; then
+ printf "Files in this commit comply with the black formatter rules.\n"
+ rm -f "$patch"
+ exit 0
+fi
+
+# a patch has been created, notify the user and exit
+printf "\nThe following differences were found between the code to commit "
+printf "and the black formatter rules:\n\n"
+$READER "$patch"
+printf "\n"
+
+# Allows us to read user input below, assigns stdin to keyboard
+exec < /dev/tty
+
+while true; do
+ read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn
+ case $yn in
+ [Yy] ) git apply $patch;
+ printf "The patch was applied. You can now stage the changes and commit again.\n\n";
+ break
+ ;;
+ [Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n";
+ printf "(may need to be called from the root directory of your repository)\n";
+ printf "Aborting commit. Apply changes and commit again or skip checking with";
+ printf " --no-verify (not recommended).\n\n";
+ break
+ ;;
+ [Ss] ) git apply $patch;
+ git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
+ do git add $file;
+ done
+ printf "The patch was applied and the changed files staged. You can now commit.\n\n";
+ break
+ ;;
+ * ) echo "Please answer yes or no."
+ ;;
+ esac
+done
+exit 1 # we don't commit in any case
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index e309233a8b..c5cf4ecbb1 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -15,28 +15,28 @@
##################################################################
# SETTINGS
-# Set path to clang-format binary
-# CLANG_FORMAT="/usr/bin/clang-format"
+# Set path to clang-format binary.
CLANG_FORMAT=`which clang-format`
# Remove any older patches from previous commits. Set to true or false.
-# DELETE_OLD_PATCHES=false
DELETE_OLD_PATCHES=false
# Only parse files with the extensions in FILE_EXTS. Set to true or false.
# If false every changed file in the commit will be parsed with clang-format.
# If true only files matching one of the extensions are parsed with clang-format.
-# PARSE_EXTS=true
PARSE_EXTS=true
# File types to parse. Only effective when PARSE_EXTS is true.
-# FILE_EXTS=".c .h .cpp .hpp"
FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl"
# Use pygmentize instead of cat to parse diff with highlighting.
# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
-# READER="pygmentize -l diff"
-READER=cat
+PYGMENTIZE=`which pygmentize`
+if [ ! -z "$PYGMENTIZE" ]; then
+ READER="pygmentize -l diff"
+else
+ READER=cat
+fi
##################################################################
# There should be no need to change anything below this line.
diff --git a/misc/hooks/pre-commit-makerst b/misc/hooks/pre-commit-makerst
index d9b684e73b..b990788b99 100755
--- a/misc/hooks/pre-commit-makerst
+++ b/misc/hooks/pre-commit-makerst
@@ -2,4 +2,11 @@
# Git pre-commit hook that checks the class reference syntax using makerst.py.
-doc/tools/makerst.py doc/classes modules --dry-run
+# Workaround because we can't execute the .py file directly on windows
+PYTHON=python
+py_ver=$($PYTHON -c "import sys; print(sys.version_info.major)")
+if [[ "$py_ver" != "3" ]]; then
+ PYTHON+=3
+fi
+
+$PYTHON doc/tools/makerst.py doc/classes modules --dry-run
diff --git a/misc/scripts/fix_headers.py b/misc/scripts/fix_headers.py
index f0038a8351..7af97eec4b 100755
--- a/misc/scripts/fix_headers.py
+++ b/misc/scripts/fix_headers.py
@@ -37,24 +37,24 @@ files = open("files", "r")
fname = files.readline()
-while (fname != ""):
+while fname != "":
# Handle replacing $filename with actual filename and keep alignment
fsingle = fname.strip()
- if (fsingle.find("/") != -1):
- fsingle = fsingle[fsingle.rfind("/") + 1:]
+ if fsingle.find("/") != -1:
+ fsingle = fsingle[fsingle.rfind("/") + 1 :]
rep_fl = "$filename"
rep_fi = fsingle
len_fl = len(rep_fl)
len_fi = len(rep_fi)
# Pad with spaces to keep alignment
- if (len_fi < len_fl):
+ if len_fi < len_fl:
for x in range(len_fl - len_fi):
rep_fi += " "
- elif (len_fl < len_fi):
+ elif len_fl < len_fi:
for x in range(len_fi - len_fl):
rep_fl += " "
- if (header.find(rep_fl) != -1):
+ if header.find(rep_fl) != -1:
text = header.replace(rep_fl, rep_fi)
else:
text = header.replace("$filename", fsingle)
@@ -71,21 +71,21 @@ while (fname != ""):
line = fileread.readline()
header_done = False
- while (line.strip() == ""): # Skip empty lines at the top
+ while line.strip() == "": # Skip empty lines at the top
line = fileread.readline()
- if (line.find("/**********") == -1): # Godot header starts this way
+ if line.find("/**********") == -1: # Godot header starts this way
# Maybe starting with a non-Godot comment, abort header magic
header_done = True
- while (not header_done): # Handle header now
- if (line.find("/*") != 0): # No more starting with a comment
+ while not header_done: # Handle header now
+ if line.find("/*") != 0: # No more starting with a comment
header_done = True
- if (line.strip() != ""):
+ if line.strip() != "":
text += line
line = fileread.readline()
- while (line != ""): # Dump everything until EOF
+ while line != "": # Dump everything until EOF
text += line
line = fileread.readline()
diff --git a/misc/scripts/fix_style.sh b/misc/scripts/fix_style.sh
index b33cb0a7b4..2eee61a459 100755
--- a/misc/scripts/fix_style.sh
+++ b/misc/scripts/fix_style.sh
@@ -1,9 +1,10 @@
#!/usr/bin/env bash
# Command line arguments
+run_black=false
run_clang_format=false
run_fix_headers=false
-usage="Invalid argument. Usage:\n$0 <option>\n\t--clang-format|-c\n\t--headers|-h\n\t--all|-a"
+usage="Invalid argument. Usage:\n$0 <option>\n\t--black|-b\n\t--clang-format|-c\n\t--headers|-h\n\t--all|-a"
if [ -z "$1" ]; then
echo -e $usage
@@ -12,6 +13,9 @@ fi
while [ $# -gt 0 ]; do
case "$1" in
+ --black|-b)
+ run_black=true
+ ;;
--clang-format|-c)
run_clang_format=true
;;
@@ -19,6 +23,7 @@ while [ $# -gt 0 ]; do
run_fix_headers=true
;;
--all|-a)
+ run_black=true
run_clang_format=true
run_fix_headers=true
;;
@@ -32,6 +37,19 @@ done
echo "Removing generated files, some have binary data and make clang-format freeze."
find -name "*.gen.*" -delete
+# Apply black
+if $run_black; then
+ echo -e "Formatting Python files..."
+ PY_FILES=$(find \( -path "./.git" \
+ -o -path "./thirdparty" \
+ \) -prune \
+ -o \( -name "SConstruct" \
+ -o -name "SCsub" \
+ -o -name "*.py" \
+ \) -print)
+ black -l 120 $PY_FILES
+fi
+
# Apply clang-format
if $run_clang_format; then
# Sync list with pre-commit hook
diff --git a/misc/travis/android-tools-linux.sh b/misc/travis/android-tools-linux.sh
index d0c123ee6c..6114551861 100755
--- a/misc/travis/android-tools-linux.sh
+++ b/misc/travis/android-tools-linux.sh
@@ -24,12 +24,12 @@ ANDROID_SDK_URL=$ANDROID_BASE_URL/$ANDROID_SDK_FILENAME
ANDROID_SDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_SDK_DIR
ANDROID_SDK_SHA256=92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9
-ANDROID_NDK_RELEASE=r20
+ANDROID_NDK_RELEASE=r21
ANDROID_NDK_DIR=android-ndk
ANDROID_NDK_FILENAME=android-ndk-$ANDROID_NDK_RELEASE-linux-x86_64.zip
ANDROID_NDK_URL=$ANDROID_BASE_URL/$ANDROID_NDK_FILENAME
ANDROID_NDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_NDK_DIR
-ANDROID_NDK_SHA1=8665fc84a1b1f0d6ab3b5fdd1e30200cc7b9adff
+ANDROID_NDK_SHA1=afc9c0b9faad222898ac8168c78ad4ccac8a1b5c
echo
echo "Download and install Android development tools ..."
@@ -76,7 +76,7 @@ yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager --licenses > /dev/null
echo "Installing: Android Build and Platform Tools ..."
yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager 'tools' > /dev/null
yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager 'platform-tools' > /dev/null
-yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager 'build-tools;28.0.3' > /dev/null
+yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager 'build-tools;29.0.3' > /dev/null
echo
EXPORT_VAL="export ANDROID_HOME=$ANDROID_SDK_PATH"
diff --git a/misc/travis/black-format.sh b/misc/travis/black-format.sh
new file mode 100755
index 0000000000..75b153f6bb
--- /dev/null
+++ b/misc/travis/black-format.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+BLACK=black
+BLACK_OPTIONS="-l 120"
+
+if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
+ # Travis only clones the PR branch and uses its HEAD commit as detached HEAD,
+ # so it's problematic when we want an exact commit range for format checks.
+ # We fetch upstream to ensure that we have the proper references to resolve.
+ # Ideally we would use $TRAVIS_COMMIT_RANGE but it doesn't play well with PR
+ # updates, as it only includes changes since the previous state of the PR.
+ if [ -z "$(git remote | grep upstream)" ]; then
+ git remote add upstream https://github.com/godotengine/godot \
+ --no-tags -f -t $TRAVIS_BRANCH
+ fi
+ RANGE="upstream/$TRAVIS_BRANCH HEAD"
+else
+ # Test only the last commit, since $TRAVIS_COMMIT_RANGE wouldn't support
+ # force pushes.
+ RANGE=HEAD
+fi
+
+FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/| grep -E "(SConstruct|SCsub|\.py)$")
+echo "Checking files:\n$FILES"
+
+# create a random filename to store our generated patch
+prefix="static-check-black"
+suffix="$(date +%s)"
+patch="/tmp/$prefix-$suffix.patch"
+
+for file in $FILES; do
+ "$BLACK" "$BLACK_OPTIONS" --diff "$file" | \
+ sed -e "1s|--- |--- a/|" -e "2s|+++ |+++ b/|" >> "$patch"
+done
+
+# if no patch has been generated all is ok, clean up the file stub and exit
+if [ ! -s "$patch" ] ; then
+ printf "Files in this commit comply with the black formatting rules.\n"
+ rm -f "$patch"
+ exit 0
+fi
+
+# a patch has been created, notify the user and exit
+printf "\n*** The following differences were found between the code to commit "
+printf "and the black formatting rules:\n\n"
+pygmentize -l diff "$patch"
+printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
+exit 1
diff --git a/misc/travis/clang-format.sh b/misc/travis/clang-format.sh
index a6585578e1..c917744ece 100755
--- a/misc/travis/clang-format.sh
+++ b/misc/travis/clang-format.sh
@@ -8,8 +8,10 @@ if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
# We fetch upstream to ensure that we have the proper references to resolve.
# Ideally we would use $TRAVIS_COMMIT_RANGE but it doesn't play well with PR
# updates, as it only includes changes since the previous state of the PR.
- git remote add upstream https://github.com/godotengine/godot \
- --no-tags -f -t $TRAVIS_BRANCH
+ if [ -z "$(git remote | grep upstream)" ]; then
+ git remote add upstream https://github.com/godotengine/godot \
+ --no-tags -f -t $TRAVIS_BRANCH
+ fi
RANGE="upstream/$TRAVIS_BRANCH HEAD"
else
# Test only the last commit, since $TRAVIS_COMMIT_RANGE wouldn't support
@@ -41,6 +43,6 @@ fi
# a patch has been created, notify the user and exit
printf "\n*** The following differences were found between the code to commit "
printf "and the clang-format rules:\n\n"
-cat "$patch"
+pygmentize -l diff "$patch"
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
exit 1
diff --git a/modules/SCsub b/modules/SCsub
index 5b39b18334..fb46c5f877 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -1,16 +1,17 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
import modules_builders
env_modules = env.Clone()
-Export('env_modules')
+Export("env_modules")
# Header with MODULE_*_ENABLED defines.
env.CommandNoCache("modules_enabled.gen.h", Value(env.module_list), modules_builders.generate_modules_enabled)
+vs_sources = []
# libmodule_<name>.a for each active module.
for module in env.module_list:
env.modules_sources = []
@@ -23,6 +24,8 @@ for module in env.module_list:
lib = env_modules.add_library("module_%s" % module, env.modules_sources)
env.Prepend(LIBS=[lib])
+ if env["vsproj"]:
+ vs_sources += env.modules_sources
# libmodules.a with only register_module_types.
# Must be last so that all libmodule_<name>.a libraries are on the right side
@@ -31,3 +34,5 @@ env.modules_sources = []
env_modules.add_source_files(env.modules_sources, "register_module_types.gen.cpp")
lib = env_modules.add_library("modules", env.modules_sources)
env.Prepend(LIBS=[lib])
+if env["vsproj"]:
+ env.modules_sources += vs_sources
diff --git a/modules/arkit/SCsub b/modules/arkit/SCsub
index e605703a72..61c0a8248c 100644
--- a/modules/arkit/SCsub
+++ b/modules/arkit/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_arkit = env_modules.Clone()
@@ -9,4 +9,4 @@ env_arkit = env_modules.Clone()
modules_sources = []
env_arkit.add_source_files(modules_sources, "*.cpp")
env_arkit.add_source_files(modules_sources, "*.mm")
-mod_lib = env_modules.add_library('#bin/libgodot_arkit_module' + env['LIBSUFFIX'], modules_sources) \ No newline at end of file
+mod_lib = env_modules.add_library("#bin/libgodot_arkit_module" + env["LIBSUFFIX"], modules_sources)
diff --git a/modules/arkit/arkit_interface.h b/modules/arkit/arkit_interface.h
index 4f8f726816..1044f3cf6f 100644
--- a/modules/arkit/arkit_interface.h
+++ b/modules/arkit/arkit_interface.h
@@ -31,9 +31,9 @@
#ifndef ARKIT_INTERFACE_H
#define ARKIT_INTERFACE_H
-#include "servers/arvr/arvr_interface.h"
-#include "servers/arvr/arvr_positional_tracker.h"
#include "servers/camera/camera_feed.h"
+#include "servers/xr/xr_interface.h"
+#include "servers/xr/xr_positional_tracker.h"
/**
@author Bastiaan Olij <mux213@gmail.com>
@@ -44,8 +44,8 @@
// forward declaration for some needed objects
class ARKitShader;
-class ARKitInterface : public ARVRInterface {
- GDCLASS(ARKitInterface, ARVRInterface);
+class ARKitInterface : public XRInterface {
+ GDCLASS(ARKitInterface, XRInterface);
private:
bool initialized;
@@ -65,7 +65,7 @@ private:
Vector<uint8_t> img_data[2];
struct anchor_map {
- ARVRPositionalTracker *tracker;
+ XRPositionalTracker *tracker;
unsigned char uuid[16];
};
@@ -73,7 +73,7 @@ private:
unsigned int num_anchors;
unsigned int max_anchors;
anchor_map *anchors;
- ARVRPositionalTracker *get_anchor_for_uuid(const unsigned char *p_uuid);
+ XRPositionalTracker *get_anchor_for_uuid(const unsigned char *p_uuid);
void remove_anchor_for_uuid(const unsigned char *p_uuid);
void remove_all_anchors();
@@ -108,9 +108,9 @@ public:
virtual Size2 get_render_targetsize();
virtual bool is_stereo();
- virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
- virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
- virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
+ virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform);
+ virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+ virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
virtual void process();
diff --git a/modules/arkit/arkit_interface.mm b/modules/arkit/arkit_interface.mm
index 39447e8dab..79f09e2a7e 100644
--- a/modules/arkit/arkit_interface.mm
+++ b/modules/arkit/arkit_interface.mm
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
#include "scene/resources/surface_tool.h"
-#include "servers/visual/visual_server_globals.h"
+#include "servers/rendering/rendering_server_globals.h"
#import <ARKit/ARKit.h>
#import <UIKit/UIKit.h>
@@ -158,7 +158,7 @@ StringName ARKitInterface::get_name() const {
}
int ARKitInterface::get_capabilities() const {
- return ARKitInterface::ARVR_MONO + ARKitInterface::ARVR_AR;
+ return ARKitInterface::XR_MONO + ARKitInterface::XR_AR;
}
Array ARKitInterface::raycast(Vector2 p_screen_coord) {
@@ -218,8 +218,8 @@ bool ARKitInterface::is_initialized() const {
}
bool ARKitInterface::initialize() {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, false);
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, false);
if (!initialized) {
print_line("initializing ARKit");
@@ -244,7 +244,7 @@ bool ARKitInterface::initialize() {
transform = Transform();
// make this our primary interface
- arvr_server->set_primary_interface(this);
+ xr_server->set_primary_interface(this);
// make sure we have our feed setup
if (feed.is_null()) {
@@ -270,10 +270,10 @@ bool ARKitInterface::initialize() {
void ARKitInterface::uninitialize() {
if (initialized) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- if (arvr_server != NULL) {
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server != NULL) {
// no longer our primary interface
- arvr_server->clear_primary_interface_if(this);
+ xr_server->clear_primary_interface_if(this);
}
if (feed.is_valid()) {
@@ -303,22 +303,22 @@ Size2 ARKitInterface::get_render_targetsize() {
return target_size;
}
-Transform ARKitInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+Transform ARKitInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
_THREAD_SAFE_METHOD_
Transform transform_for_eye;
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, transform_for_eye);
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, transform_for_eye);
if (initialized) {
- float world_scale = arvr_server->get_world_scale();
+ float world_scale = xr_server->get_world_scale();
// just scale our origin point of our transform, note that we really shouldn't be using world_scale in ARKit but....
transform_for_eye = transform;
transform_for_eye.origin *= world_scale;
- transform_for_eye = p_cam_transform * arvr_server->get_reference_frame() * transform_for_eye;
+ transform_for_eye = p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
} else {
// huh? well just return what we got....
transform_for_eye = p_cam_transform;
@@ -327,7 +327,7 @@ Transform ARKitInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, const
return transform_for_eye;
}
-CameraMatrix ARKitInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+CameraMatrix ARKitInterface::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
// Remember our near and far, it will be used in process when we obtain our projection from our ARKit session.
z_near = p_z_near;
z_far = p_z_far;
@@ -335,7 +335,7 @@ CameraMatrix ARKitInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye, r
return projection;
}
-void ARKitInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+void ARKitInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
_THREAD_SAFE_METHOD_
// We must have a valid render target
@@ -356,7 +356,7 @@ void ARKitInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_targ
VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0);
}
-ARVRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *p_uuid) {
+XRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *p_uuid) {
if (anchors == NULL) {
num_anchors = 0;
max_anchors = 10;
@@ -377,8 +377,8 @@ ARVRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *
ERR_FAIL_NULL_V(anchors, NULL);
}
- ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
- new_tracker->set_type(ARVRServer::TRACKER_ANCHOR);
+ XRPositionalTracker *new_tracker = memnew(XRPositionalTracker);
+ new_tracker->set_type(XRServer::TRACKER_ANCHOR);
char tracker_name[256];
sprintf(tracker_name, "Anchor %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p_uuid[0], p_uuid[1], p_uuid[2], p_uuid[3], p_uuid[4], p_uuid[5], p_uuid[6], p_uuid[7], p_uuid[8], p_uuid[9], p_uuid[10], p_uuid[11], p_uuid[12], p_uuid[13], p_uuid[14], p_uuid[15]);
@@ -388,7 +388,7 @@ ARVRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *
new_tracker->set_name(name);
// add our tracker
- ARVRServer::get_singleton()->add_tracker(new_tracker);
+ XRServer::get_singleton()->add_tracker(new_tracker);
anchors[num_anchors].tracker = new_tracker;
memcpy(anchors[num_anchors].uuid, p_uuid, 16);
num_anchors++;
@@ -401,7 +401,7 @@ void ARKitInterface::remove_anchor_for_uuid(const unsigned char *p_uuid) {
for (unsigned int i = 0; i < num_anchors; i++) {
if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
// remove our tracker
- ARVRServer::get_singleton()->remove_tracker(anchors[i].tracker);
+ XRServer::get_singleton()->remove_tracker(anchors[i].tracker);
memdelete(anchors[i].tracker);
// bring remaining forward
@@ -421,7 +421,7 @@ void ARKitInterface::remove_all_anchors() {
if (anchors != NULL) {
for (unsigned int i = 0; i < num_anchors; i++) {
// remove our tracker
- ARVRServer::get_singleton()->remove_tracker(anchors[i].tracker);
+ XRServer::get_singleton()->remove_tracker(anchors[i].tracker);
memdelete(anchors[i].tracker);
};
@@ -582,16 +582,16 @@ void ARKitInterface::process() {
// strangely enough we have to states, rolling them up into one
if (camera.trackingState == ARTrackingStateNotAvailable) {
// no tracking, would be good if we black out the screen or something...
- tracking_state = ARVRInterface::ARVR_NOT_TRACKING;
+ tracking_state = XRInterface::XR_NOT_TRACKING;
} else {
if (camera.trackingState == ARTrackingStateNormal) {
- tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
+ tracking_state = XRInterface::XR_NORMAL_TRACKING;
} else if (camera.trackingStateReason == ARTrackingStateReasonExcessiveMotion) {
- tracking_state = ARVRInterface::ARVR_EXCESSIVE_MOTION;
+ tracking_state = XRInterface::XR_EXCESSIVE_MOTION;
} else if (camera.trackingStateReason == ARTrackingStateReasonInsufficientFeatures) {
- tracking_state = ARVRInterface::ARVR_INSUFFICIENT_FEATURES;
+ tracking_state = XRInterface::XR_INSUFFICIENT_FEATURES;
} else {
- tracking_state = ARVRInterface::ARVR_UNKNOWN_TRACKING;
+ tracking_state = XRInterface::XR_UNKNOWN_TRACKING;
}
// copy our current frame transform
@@ -665,7 +665,7 @@ void ARKitInterface::_add_or_update_anchor(void *p_anchor) {
unsigned char uuid[16];
[anchor.identifier getUUIDBytes:uuid];
- ARVRPositionalTracker *tracker = get_anchor_for_uuid(uuid);
+ XRPositionalTracker *tracker = get_anchor_for_uuid(uuid);
if (tracker != NULL) {
// lets update our mesh! (using Arjens code as is for now)
// we should also probably limit how often we do this...
@@ -695,7 +695,7 @@ void ARKitInterface::_add_or_update_anchor(void *p_anchor) {
}
// Note, this also contains a scale factor which gives us an idea of the size of the anchor
- // We may extract that in our ARVRAnchor class
+ // We may extract that in our XRAnchor class
Basis b;
matrix_float4x4 m44 = anchor.transform;
b.elements[0].x = m44.columns[0][0];
diff --git a/modules/arkit/arkit_session_delegate.mm b/modules/arkit/arkit_session_delegate.mm
index d3c12ad582..f44f46b7b7 100644
--- a/modules/arkit/arkit_session_delegate.mm
+++ b/modules/arkit/arkit_session_delegate.mm
@@ -53,4 +53,4 @@
}
}
-@end \ No newline at end of file
+@end
diff --git a/modules/arkit/config.py b/modules/arkit/config.py
index 96e41826c5..e68603fc93 100644
--- a/modules/arkit/config.py
+++ b/modules/arkit/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return platform == 'iphone'
+ return platform == "iphone"
+
def configure(env):
pass
diff --git a/modules/arkit/register_types.cpp b/modules/arkit/register_types.cpp
index c78b35529b..91069ab364 100644
--- a/modules/arkit/register_types.cpp
+++ b/modules/arkit/register_types.cpp
@@ -37,7 +37,7 @@ void register_arkit_types() {
Ref<ARKitInterface> arkit_interface;
arkit_interface.instance();
- ARVRServer::get_singleton()->add_interface(arkit_interface);
+ XRServer::get_singleton()->add_interface(arkit_interface);
}
void unregister_arkit_types() {
diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub
index 90cdd7f5fc..f1d0c742b4 100644
--- a/modules/assimp/SCsub
+++ b/modules/assimp/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_assimp = env_modules.Clone()
@@ -10,85 +10,85 @@ env_assimp = env_modules.Clone()
if True: # env['builtin_assimp']:
thirdparty_dir = "#thirdparty/assimp"
- env_assimp.Prepend(CPPPATH=['#thirdparty/assimp'])
- env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/code'])
- env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/include'])
+ env_assimp.Prepend(CPPPATH=["#thirdparty/assimp"])
+ env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/code"])
+ env_assimp.Prepend(CPPPATH=["#thirdparty/assimp/include"])
- #env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_SINGLETHREADED'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_BOOST_WORKAROUND'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OWN_ZLIB'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_EXPORT'])
+ # env_assimp.Append(CPPDEFINES=['ASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_SINGLETHREADED"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_BOOST_WORKAROUND"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OWN_ZLIB"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_EXPORT"])
# Importers we don't need
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3DS_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3MF_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_AC_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_AMF_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_ASE_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_ASSBIN_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_B3D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_BLEND_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_BVH_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_C4D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_COB_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_COLLADA_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_CSM_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_DXF_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_GLTF2_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_GLTF_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_HMP_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IFC_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IRR_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IRRMESH_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_LWO_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_LWS_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_M3D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD2_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD3_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD5_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MD5_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MDC_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MDL_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MMD_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_MS3D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_NDO_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_NFF_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OBJ_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OFF_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OGRE_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_OPENGEX_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_PLY_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_Q3BSP_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_Q3D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_RAW_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_SIB_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_SMD_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_STEP_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_STL_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_TERRAGEN_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_X3D_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_XGL_IMPORTER'])
- env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_X_IMPORTER'])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3DS_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_3MF_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AC_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_AMF_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASE_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_ASSBIN_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_B3D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BLEND_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_BVH_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_C4D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COB_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_COLLADA_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_CSM_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_DXF_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF2_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_GLTF_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_HMP_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IFC_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRR_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_IRRMESH_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWO_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_LWS_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_M3D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD2_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD3_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MD5_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDC_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MDL_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MMD_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_MS3D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NDO_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_NFF_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OBJ_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OFF_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OGRE_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_OPENGEX_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_PLY_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3BSP_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_Q3D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_RAW_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SIB_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_SMD_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STEP_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_STL_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_TERRAGEN_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X3D_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_XGL_IMPORTER"])
+ env_assimp.Append(CPPDEFINES=["ASSIMP_BUILD_NO_X_IMPORTER"])
+
+ if env["platform"] == "windows":
+ env_assimp.Append(CPPDEFINES=["PLATFORM_WINDOWS"])
+ env_assimp.Append(CPPDEFINES=[("PLATFORM", "WINDOWS")])
+ elif env["platform"] == "linuxbsd":
+ env_assimp.Append(CPPDEFINES=["PLATFORM_LINUX"])
+ env_assimp.Append(CPPDEFINES=[("PLATFORM", "LINUX")])
+ elif env["platform"] == "osx":
+ env_assimp.Append(CPPDEFINES=["PLATFORM_DARWIN"])
+ env_assimp.Append(CPPDEFINES=[("PLATFORM", "DARWIN")])
- if(env['platform'] == 'windows'):
- env_assimp.Append(CPPDEFINES=['PLATFORM_WINDOWS'])
- env_assimp.Append(CPPDEFINES=[('PLATFORM', 'WINDOWS')])
- elif(env['platform'] == 'x11'):
- env_assimp.Append(CPPDEFINES=['PLATFORM_LINUX'])
- env_assimp.Append(CPPDEFINES=[('PLATFORM', 'LINUX')])
- elif(env['platform'] == 'osx'):
- env_assimp.Append(CPPDEFINES=['PLATFORM_DARWIN'])
- env_assimp.Append(CPPDEFINES=[('PLATFORM', 'DARWIN')])
-
env_thirdparty = env_assimp.Clone()
env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/CApi/*.cpp'))
- env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/Common/*.cpp'))
- env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/PostProcessing/*.cpp'))
- env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/Material/*.cpp'))
- env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/FBX/*.cpp'))
+ env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/CApi/*.cpp"))
+ env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Common/*.cpp"))
+ env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/PostProcessing/*.cpp"))
+ env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/Material/*.cpp"))
+ env_thirdparty.add_source_files(env.modules_sources, Glob("#thirdparty/assimp/code/FBX/*.cpp"))
# Godot's own source files
env_assimp.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/assimp/config.py b/modules/assimp/config.py
index 098f1eafa9..53b8f2f2e3 100644
--- a/modules/assimp/config.py
+++ b/modules/assimp/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return env['tools']
+ return env["tools"]
+
def configure(env):
pass
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
index 1881d0db33..cc74674eff 100644
--- a/modules/assimp/editor_scene_importer_assimp.cpp
+++ b/modules/assimp/editor_scene_importer_assimp.cpp
@@ -32,9 +32,9 @@
#include "core/io/image_loader.h"
#include "editor/import/resource_importer_scene.h"
#include "import_utils.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/light.h"
-#include "scene/3d/mesh_instance.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"
#include "scene/resources/surface_tool.h"
@@ -62,7 +62,7 @@ aiBone *get_bone_by_name(const aiScene *scene, aiString bone_name) {
}
}
- return NULL;
+ return nullptr;
}
void EditorSceneImporterAssimp::get_extensions(List<String> *r_extensions) const {
@@ -149,7 +149,7 @@ Node *EditorSceneImporterAssimp::import_scene(const String &p_path, uint32_t p_f
0;
aiScene *scene = (aiScene *)importer.ReadFile(s_path.c_str(), post_process_Steps);
- ERR_FAIL_COND_V_MSG(scene == NULL, NULL, String("Open Asset Import failed to open: ") + String(importer.GetErrorString()));
+ ERR_FAIL_COND_V_MSG(scene == nullptr, nullptr, String("Open Asset Import failed to open: ") + String(importer.GetErrorString()));
return _generate_scene(p_path, scene, p_flags, p_bake_fps, max_bone_weights);
}
@@ -284,7 +284,7 @@ T EditorSceneImporterAssimp::_interpolate_track(const Vector<float> &p_times, co
aiBone *EditorSceneImporterAssimp::get_bone_from_stack(ImportState &state, aiString name) {
List<aiBone *>::Element *iter;
- aiBone *bone = NULL;
+ aiBone *bone = nullptr;
for (iter = state.bone_stack.front(); iter; iter = iter->next()) {
bone = (aiBone *)iter->get();
@@ -294,32 +294,32 @@ aiBone *EditorSceneImporterAssimp::get_bone_from_stack(ImportState &state, aiStr
}
}
- return NULL;
+ return nullptr;
}
-Spatial *
+Node3D *
EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps,
const int32_t p_max_bone_weights) {
- ERR_FAIL_COND_V(scene == NULL, NULL);
+ ERR_FAIL_COND_V(scene == nullptr, nullptr);
ImportState state;
state.path = p_path;
state.assimp_scene = scene;
state.max_bone_weights = p_max_bone_weights;
- state.animation_player = NULL;
+ state.animation_player = nullptr;
// populate light map
for (unsigned int l = 0; l < scene->mNumLights; l++) {
aiLight *ai_light = scene->mLights[l];
- ERR_CONTINUE(ai_light == NULL);
+ ERR_CONTINUE(ai_light == nullptr);
state.light_cache[AssimpUtils::get_assimp_string(ai_light->mName)] = l;
}
// fill camera cache
for (unsigned int c = 0; c < scene->mNumCameras; c++) {
aiCamera *ai_camera = scene->mCameras[c];
- ERR_CONTINUE(ai_camera == NULL);
+ ERR_CONTINUE(ai_camera == nullptr);
state.camera_cache[AssimpUtils::get_assimp_string(ai_camera->mName)] = c;
}
@@ -333,7 +333,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
RegenerateBoneStack(state);
- Node *last_valid_parent = NULL;
+ Node *last_valid_parent = nullptr;
List<const aiNode *>::Element *iter;
for (iter = state.nodes.front(); iter; iter = iter->next()) {
@@ -343,7 +343,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
String node_name = AssimpUtils::get_assimp_string(element_assimp_node->mName);
//print_verbose("node: " + node_name);
- Spatial *spatial = NULL;
+ Node3D *spatial = nullptr;
Transform transform = AssimpUtils::assimp_matrix_transform(element_assimp_node->mTransformation);
// retrieve this node bone
@@ -356,18 +356,18 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
} else if (state.armature_nodes.find(element_assimp_node)) {
// create skeleton
print_verbose("Making skeleton: " + node_name);
- Skeleton *skeleton = memnew(Skeleton);
+ Skeleton3D *skeleton = memnew(Skeleton3D);
spatial = skeleton;
if (!state.armature_skeletons.has(element_assimp_node)) {
state.armature_skeletons.insert(element_assimp_node, skeleton);
}
- } else if (bone != NULL) {
+ } else if (bone != nullptr) {
continue;
} else {
- spatial = memnew(Spatial);
+ spatial = memnew(Node3D);
}
- ERR_CONTINUE_MSG(spatial == NULL, "FBX Import - are we out of ram?");
+ ERR_CONTINUE_MSG(spatial == nullptr, "FBX Import - are we out of ram?");
// we on purpose set the transform and name after creating the node.
spatial->set_name(node_name);
@@ -381,13 +381,13 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
// flat node map parent lookup tool
state.flat_node_map.insert(element_assimp_node, spatial);
- Map<const aiNode *, Spatial *>::Element *parent_lookup = state.flat_node_map.find(parent_assimp_node);
+ Map<const aiNode *, Node3D *>::Element *parent_lookup = state.flat_node_map.find(parent_assimp_node);
// note: this always fails on the root node :) keep that in mind this is by design
if (parent_lookup) {
- Spatial *parent_node = parent_lookup->value();
+ Node3D *parent_node = parent_lookup->value();
- ERR_FAIL_COND_V_MSG(parent_node == NULL, state.root,
+ ERR_FAIL_COND_V_MSG(parent_node == nullptr, state.root,
"Parent node invalid even though lookup successful, out of ram?");
if (spatial != state.root) {
@@ -434,8 +434,8 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
aiNode *parent_node = bone_node->mParent;
String bone_name = AssimpUtils::get_anim_string_from_assimp(bone->mName);
- ERR_CONTINUE_MSG(armature_for_bone == NULL, "Armature for bone invalid: " + bone_name);
- Skeleton *skeleton = state.armature_skeletons[armature_for_bone];
+ ERR_CONTINUE_MSG(armature_for_bone == nullptr, "Armature for bone invalid: " + bone_name);
+ Skeleton3D *skeleton = state.armature_skeletons[armature_for_bone];
state.skeleton_bone_map[bone] = skeleton;
@@ -454,7 +454,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
skeleton->set_bone_rest(boneIdx, pform);
skeleton->set_bone_pose(boneIdx, pform);
- if (parent_node != NULL) {
+ if (parent_node != nullptr) {
int parent_bone_id = skeleton->find_bone(AssimpUtils::get_anim_string_from_assimp(parent_node->mName));
int current_bone_id = boneIdx;
skeleton->set_bone_parent(current_bone_id, parent_bone_id);
@@ -464,14 +464,14 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
print_verbose("generating mesh phase from skeletal mesh");
- List<Spatial *> cleanup_template_nodes;
+ List<Node3D *> cleanup_template_nodes;
- for (Map<const aiNode *, Spatial *>::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) {
+ for (Map<const aiNode *, Node3D *>::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) {
const aiNode *assimp_node = key_value_pair->key();
- Spatial *mesh_template = key_value_pair->value();
+ Node3D *mesh_template = key_value_pair->value();
- ERR_CONTINUE(assimp_node == NULL);
- ERR_CONTINUE(mesh_template == NULL);
+ ERR_CONTINUE(assimp_node == nullptr);
+ ERR_CONTINUE(mesh_template == nullptr);
Node *parent_node = mesh_template->get_parent();
@@ -479,7 +479,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
continue;
}
- if (parent_node == NULL) {
+ if (parent_node == nullptr) {
print_error("Found invalid parent node!");
continue; // root node
}
@@ -488,7 +488,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
Transform node_transform = AssimpUtils::assimp_matrix_transform(assimp_node->mTransformation);
if (assimp_node->mNumMeshes > 0) {
- MeshInstance *mesh = create_mesh(state, assimp_node, node_name, parent_node, node_transform);
+ MeshInstance3D *mesh = create_mesh(state, assimp_node, node_name, parent_node, node_transform);
if (mesh) {
parent_node->remove_child(mesh_template);
@@ -522,7 +522,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
}
}
- for (List<Spatial *>::Element *element = cleanup_template_nodes.front(); element; element = element->next()) {
+ for (List<Node3D *>::Element *element = cleanup_template_nodes.front(); element; element = element->next()) {
if (element->get()) {
memdelete(element->get());
}
@@ -559,7 +559,7 @@ EditorSceneImporterAssimp::_generate_scene(const String &p_path, aiScene *scene,
void EditorSceneImporterAssimp::_insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id,
int anim_fps, Ref<Animation> animation, float ticks_per_second,
- Skeleton *skeleton, const NodePath &node_path,
+ Skeleton3D *skeleton, const NodePath &node_path,
const String &node_name, aiBone *track_bone) {
const aiNodeAnim *assimp_track = assimp_anim->mChannels[track_id];
//make transform track
@@ -652,16 +652,16 @@ void EditorSceneImporterAssimp::_insert_animation_track(ImportState &scene, cons
// I really do not like this but need to figure out a better way of removing it later.
Node *EditorSceneImporterAssimp::get_node_by_name(ImportState &state, String name) {
- for (Map<const aiNode *, Spatial *>::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) {
+ for (Map<const aiNode *, Node3D *>::Element *key_value_pair = state.flat_node_map.front(); key_value_pair; key_value_pair = key_value_pair->next()) {
const aiNode *assimp_node = key_value_pair->key();
- Spatial *node = key_value_pair->value();
+ Node3D *node = key_value_pair->value();
String node_name = AssimpUtils::get_assimp_string(assimp_node->mName);
if (name == node_name && node) {
return node;
}
}
- return NULL;
+ return nullptr;
}
/* Bone stack is a fifo handler for multiple armatures since armatures aren't a thing in assimp (yet) */
@@ -691,7 +691,7 @@ void EditorSceneImporterAssimp::RegenerateBoneStack(ImportState &state, aiMesh *
// iterate over all the bones on the mesh for this node only!
for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; boneIndex++) {
aiBone *bone = mesh->mBones[boneIndex];
- if (state.bone_stack.find(bone) == NULL) {
+ if (state.bone_stack.find(bone) == nullptr) {
state.bone_stack.push_back(bone);
}
}
@@ -711,7 +711,7 @@ void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_anim
print_verbose("import animation: " + name);
float ticks_per_second = anim->mTicksPerSecond;
- if (state.assimp_scene->mMetaData != NULL && Math::is_equal_approx(ticks_per_second, 0.0f)) {
+ if (state.assimp_scene->mMetaData != nullptr && Math::is_equal_approx(ticks_per_second, 0.0f)) {
int32_t time_mode = 0;
state.assimp_scene->mMetaData->Get("TimeMode", time_mode);
ticks_per_second = AssimpUtils::get_fbx_fps(time_mode, state.assimp_scene);
@@ -747,9 +747,9 @@ void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_anim
continue; //do not bother
}
- Skeleton *skeleton = NULL;
+ Skeleton3D *skeleton = nullptr;
NodePath node_path;
- aiBone *bone = NULL;
+ aiBone *bone = nullptr;
// Import skeleton bone animation for this track
// Any bone will do, no point in processing more than just what is in the skeleton
@@ -805,8 +805,8 @@ void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_anim
Node *item = get_node_by_name(state, mesh_name);
ERR_CONTINUE_MSG(!item, "failed to look up node by name");
- const MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(item);
- ERR_CONTINUE(mesh_instance == NULL);
+ const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(item);
+ ERR_CONTINUE(mesh_instance == nullptr);
String base_path = state.root->get_path_to(mesh_instance);
@@ -842,7 +842,7 @@ void EditorSceneImporterAssimp::_import_animation(ImportState &state, int p_anim
Ref<Mesh>
EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
const aiNode *assimp_node, Ref<Skin> &skin,
- Skeleton *&skeleton_assigned) {
+ Skeleton3D *&skeleton_assigned) {
Ref<ArrayMesh> mesh;
mesh.instance();
@@ -872,7 +872,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
const unsigned int mesh_idx = p_surface_indices[i];
const aiMesh *ai_mesh = state.assimp_scene->mMeshes[mesh_idx];
- Map<uint32_t, Vector<BoneInfo> > vertex_weights;
+ Map<uint32_t, Vector<BoneInfo>> vertex_weights;
if (ai_mesh->mNumBones > 0) {
for (size_t b = 0; b < ai_mesh->mNumBones; b++) {
@@ -940,7 +940,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
}
// Work out normal calculations? - this needs work it doesn't work properly on huestos
- if (ai_mesh->mNormals != NULL) {
+ if (ai_mesh->mNormals != nullptr) {
const aiVector3D normals = ai_mesh->mNormals[j];
const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
st->add_normal(godot_normal);
@@ -1208,9 +1208,9 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
}
Array array_copy;
- array_copy.resize(VisualServer::ARRAY_MAX);
+ array_copy.resize(RenderingServer::ARRAY_MAX);
- for (int l = 0; l < VisualServer::ARRAY_MAX; l++) {
+ for (int l = 0; l < RenderingServer::ARRAY_MAX; l++) {
array_copy[l] = array_mesh[l].duplicate(true);
}
@@ -1224,13 +1224,13 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
Vector3 position = Vector3(ai_pos.x, ai_pos.y, ai_pos.z);
vertices.ptrw()[l] = position;
}
- PackedVector3Array new_vertices = array_copy[VisualServer::ARRAY_VERTEX].duplicate(true);
+ PackedVector3Array new_vertices = array_copy[RenderingServer::ARRAY_VERTEX].duplicate(true);
ERR_CONTINUE(vertices.size() != new_vertices.size());
for (int32_t l = 0; l < new_vertices.size(); l++) {
Vector3 *w = new_vertices.ptrw();
w[l] = vertices[l];
}
- array_copy[VisualServer::ARRAY_VERTEX] = new_vertices;
+ array_copy[RenderingServer::ARRAY_VERTEX] = new_vertices;
}
int32_t color_set = 0;
@@ -1242,13 +1242,13 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
Color color = Color(ai_color.r, ai_color.g, ai_color.b, ai_color.a);
colors.ptrw()[l] = color;
}
- PackedColorArray new_colors = array_copy[VisualServer::ARRAY_COLOR].duplicate(true);
+ PackedColorArray new_colors = array_copy[RenderingServer::ARRAY_COLOR].duplicate(true);
ERR_CONTINUE(colors.size() != new_colors.size());
for (int32_t l = 0; l < colors.size(); l++) {
Color *w = new_colors.ptrw();
w[l] = colors[l];
}
- array_copy[VisualServer::ARRAY_COLOR] = new_colors;
+ array_copy[RenderingServer::ARRAY_COLOR] = new_colors;
}
if (ai_mesh->mAnimMeshes[j]->HasNormals()) {
@@ -1259,13 +1259,13 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
Vector3 normal = Vector3(ai_normal.x, ai_normal.y, ai_normal.z);
normals.ptrw()[l] = normal;
}
- PackedVector3Array new_normals = array_copy[VisualServer::ARRAY_NORMAL].duplicate(true);
+ PackedVector3Array new_normals = array_copy[RenderingServer::ARRAY_NORMAL].duplicate(true);
ERR_CONTINUE(normals.size() != new_normals.size());
for (int l = 0; l < normals.size(); l++) {
Vector3 *w = new_normals.ptrw();
w[l] = normals[l];
}
- array_copy[VisualServer::ARRAY_NORMAL] = new_normals;
+ array_copy[RenderingServer::ARRAY_NORMAL] = new_normals;
}
if (ai_mesh->mAnimMeshes[j]->HasTangentsAndBitangents()) {
@@ -1275,7 +1275,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
for (size_t l = 0; l < num_vertices; l++) {
AssimpUtils::calc_tangent_from_mesh(ai_mesh, j, l, l, w);
}
- PackedFloat32Array new_tangents = array_copy[VisualServer::ARRAY_TANGENT].duplicate(true);
+ PackedFloat32Array new_tangents = array_copy[RenderingServer::ARRAY_TANGENT].duplicate(true);
ERR_CONTINUE(new_tangents.size() != tangents.size() * 4);
for (int32_t l = 0; l < tangents.size(); l++) {
new_tangents.ptrw()[l + 0] = tangents[l].r;
@@ -1283,7 +1283,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
new_tangents.ptrw()[l + 2] = tangents[l].b;
new_tangents.ptrw()[l + 3] = tangents[l].a;
}
- array_copy[VisualServer::ARRAY_TANGENT] = new_tangents;
+ array_copy[RenderingServer::ARRAY_TANGENT] = new_tangents;
}
morphs[j] = array_copy;
@@ -1299,7 +1299,7 @@ EditorSceneImporterAssimp::_generate_mesh_from_surface_indices(ImportState &stat
/**
* Create a new mesh for the node supplied
*/
-MeshInstance *
+MeshInstance3D *
EditorSceneImporterAssimp::create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform) {
/* MESH NODE */
Ref<Mesh> mesh;
@@ -1325,15 +1325,15 @@ EditorSceneImporterAssimp::create_mesh(ImportState &state, const aiNode *assimp_
mesh_key += itos(surface_indices[i]);
}
- Skeleton *skeleton = NULL;
- aiNode *armature = NULL;
+ Skeleton3D *skeleton = nullptr;
+ aiNode *armature = nullptr;
if (!state.mesh_cache.has(mesh_key)) {
mesh = _generate_mesh_from_surface_indices(state, surface_indices, assimp_node, skin, skeleton);
state.mesh_cache[mesh_key] = mesh;
}
- MeshInstance *mesh_node = memnew(MeshInstance);
+ MeshInstance3D *mesh_node = memnew(MeshInstance3D);
mesh = state.mesh_cache[mesh_key];
mesh_node->set_mesh(mesh);
@@ -1407,22 +1407,22 @@ EditorSceneImporterAssimp::create_mesh(ImportState &state, const aiNode *assimp_
* Create a light for the scene
* Automatically caches lights for lookup later
*/
-Spatial *EditorSceneImporterAssimp::create_light(
+Node3D *EditorSceneImporterAssimp::create_light(
ImportState &state,
const String &node_name,
Transform &look_at_transform) {
- Light *light = NULL;
+ Light3D *light = nullptr;
aiLight *assimp_light = state.assimp_scene->mLights[state.light_cache[node_name]];
- ERR_FAIL_COND_V(!assimp_light, NULL);
+ ERR_FAIL_COND_V(!assimp_light, nullptr);
if (assimp_light->mType == aiLightSource_DIRECTIONAL) {
- light = memnew(DirectionalLight);
+ light = memnew(DirectionalLight3D);
} else if (assimp_light->mType == aiLightSource_POINT) {
- light = memnew(OmniLight);
+ light = memnew(OmniLight3D);
} else if (assimp_light->mType == aiLightSource_SPOT) {
- light = memnew(SpotLight);
+ light = memnew(SpotLight3D);
}
- ERR_FAIL_COND_V(light == NULL, NULL);
+ ERR_FAIL_COND_V(light == nullptr, nullptr);
if (assimp_light->mType != aiLightSource_POINT) {
Vector3 pos = Vector3(
@@ -1453,15 +1453,15 @@ Spatial *EditorSceneImporterAssimp::create_light(
/**
* Create camera for the scene
*/
-Spatial *EditorSceneImporterAssimp::create_camera(
+Node3D *EditorSceneImporterAssimp::create_camera(
ImportState &state,
const String &node_name,
Transform &look_at_transform) {
aiCamera *camera = state.assimp_scene->mCameras[state.camera_cache[node_name]];
- ERR_FAIL_COND_V(!camera, NULL);
+ ERR_FAIL_COND_V(!camera, nullptr);
- Camera *camera_node = memnew(Camera);
- ERR_FAIL_COND_V(!camera_node, NULL);
+ Camera3D *camera_node = memnew(Camera3D);
+ ERR_FAIL_COND_V(!camera_node, nullptr);
float near = camera->mClipPlaneNear;
if (Math::is_equal_approx(near, 0.0f)) {
near = 0.1f;
@@ -1483,7 +1483,7 @@ void EditorSceneImporterAssimp::_generate_node(
ImportState &state,
const aiNode *assimp_node) {
- ERR_FAIL_COND(assimp_node == NULL);
+ ERR_FAIL_COND(assimp_node == nullptr);
state.nodes.push_back(assimp_node);
String parent_name = AssimpUtils::get_assimp_string(assimp_node->mParent->mName);
@@ -1498,7 +1498,7 @@ void EditorSceneImporterAssimp::_generate_node(
// is this an armature
// parent null
// and this is the first bone :)
- if (parent_bone == NULL && current_bone) {
+ if (parent_bone == nullptr && current_bone) {
state.armature_nodes.push_back(assimp_node->mParent);
print_verbose("found valid armature: " + parent_name);
}
diff --git a/modules/assimp/editor_scene_importer_assimp.h b/modules/assimp/editor_scene_importer_assimp.h
index 4cd50e7681..ab00a6c3aa 100644
--- a/modules/assimp/editor_scene_importer_assimp.h
+++ b/modules/assimp/editor_scene_importer_assimp.h
@@ -37,9 +37,9 @@
#include "core/vector.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/project_settings_editor.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/surface_tool.h"
@@ -90,29 +90,29 @@ private:
Ref<Mesh> _generate_mesh_from_surface_indices(ImportState &state, const Vector<int> &p_surface_indices,
const aiNode *assimp_node, Ref<Skin> &skin,
- Skeleton *&skeleton_assigned);
+ Skeleton3D *&skeleton_assigned);
// simple object creation functions
- Spatial *create_light(ImportState &state,
+ Node3D *create_light(ImportState &state,
const String &node_name,
Transform &look_at_transform);
- Spatial *create_camera(
+ Node3D *create_camera(
ImportState &state,
const String &node_name,
Transform &look_at_transform);
// non recursive - linear so must not use recursive arguments
- MeshInstance *create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform);
+ MeshInstance3D *create_mesh(ImportState &state, const aiNode *assimp_node, const String &node_name, Node *active_node, Transform node_transform);
// recursive node generator
void _generate_node(ImportState &state, const aiNode *assimp_node);
void _insert_animation_track(ImportState &scene, const aiAnimation *assimp_anim, int track_id,
int anim_fps, Ref<Animation> animation, float ticks_per_second,
- Skeleton *skeleton, const NodePath &node_path,
+ Skeleton3D *skeleton, const NodePath &node_path,
const String &node_name, aiBone *track_bone);
void _import_animation(ImportState &state, int p_animation_index, int p_bake_fps);
Node *get_node_by_name(ImportState &state, String name);
aiBone *get_bone_from_stack(ImportState &state, aiString name);
- Spatial *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
+ Node3D *_generate_scene(const String &p_path, aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
template <class T>
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
@@ -138,7 +138,7 @@ public:
virtual void get_extensions(List<String> *r_extensions) const;
virtual uint32_t get_import_flags() const;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path);
static void RegenerateBoneStack(ImportState &state);
diff --git a/modules/assimp/import_state.h b/modules/assimp/import_state.h
index 26aad423cd..cda1a854f0 100644
--- a/modules/assimp/import_state.h
+++ b/modules/assimp/import_state.h
@@ -36,9 +36,9 @@
#include "core/vector.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/project_settings_editor.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/surface_tool.h"
@@ -57,32 +57,32 @@ namespace AssimpImporter {
struct ImportState {
String path;
- Spatial *root;
+ Node3D *root;
const aiScene *assimp_scene;
uint32_t max_bone_weights;
- Map<String, Ref<Mesh> > mesh_cache;
- Map<int, Ref<Material> > material_cache;
+ Map<String, Ref<Mesh>> mesh_cache;
+ Map<int, Ref<Material>> material_cache;
Map<String, int> light_cache;
Map<String, int> camera_cache;
// very useful for when you need to ask assimp for the bone mesh
Map<const aiNode *, Node *> assimp_node_map;
- Map<String, Ref<Image> > path_to_image_cache;
+ Map<String, Ref<Image>> path_to_image_cache;
// Generation 3 - determinisitic iteration
// to lower potential recursion errors
List<const aiNode *> nodes;
- Map<const aiNode *, Spatial *> flat_node_map;
+ Map<const aiNode *, Node3D *> flat_node_map;
AnimationPlayer *animation_player;
// Generation 3 - deterministic armatures
// list of armature nodes - flat and simple to parse
// assimp node, node in godot
List<aiNode *> armature_nodes;
- Map<const aiNode *, Skeleton *> armature_skeletons;
- Map<aiBone *, Skeleton *> skeleton_bone_map;
+ Map<const aiNode *, Skeleton3D *> armature_skeletons;
+ Map<aiBone *, Skeleton3D *> skeleton_bone_map;
// Generation 3 - deterministic bone handling
// bones from the stack are popped when found
// this means we can detect
@@ -103,8 +103,8 @@ struct RecursiveState {
RecursiveState() {} // do not construct :)
RecursiveState(
Transform &_node_transform,
- Skeleton *_skeleton,
- Spatial *_new_node,
+ Skeleton3D *_skeleton,
+ Node3D *_new_node,
String &_node_name,
aiNode *_assimp_node,
Node *_parent_node,
@@ -118,12 +118,12 @@ struct RecursiveState {
bone(_bone) {}
Transform node_transform;
- Skeleton *skeleton = NULL;
- Spatial *new_node = NULL;
+ Skeleton3D *skeleton = nullptr;
+ Node3D *new_node = nullptr;
String node_name;
- aiNode *assimp_node = NULL;
- Node *parent_node = NULL;
- aiBone *bone = NULL;
+ aiNode *assimp_node = nullptr;
+ Node *parent_node = nullptr;
+ aiBone *bone = nullptr;
};
} // namespace AssimpImporter
diff --git a/modules/assimp/import_utils.h b/modules/assimp/import_utils.h
index 80b67b5453..f78931add3 100644
--- a/modules/assimp/import_utils.h
+++ b/modules/assimp/import_utils.h
@@ -233,7 +233,7 @@ public:
static Transform _get_global_assimp_node_transform(const aiNode *p_current_node) {
aiNode const *current_node = p_current_node;
Transform xform;
- while (current_node != NULL) {
+ while (current_node != nullptr) {
xform = assimp_matrix_transform(current_node->mTransformation) * xform;
current_node = current_node->mParent;
}
@@ -319,7 +319,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);
// FIXME: Commented out during Vulkan port.
/*
aiTextureMapMode tex_mode = map_mode[0];
@@ -341,7 +341,7 @@ public:
*/
static Ref<Image> load_image(ImportState &state, const aiScene *p_scene, String p_path) {
- Map<String, Ref<Image> >::Element *match = state.path_to_image_cache.find(p_path);
+ Map<String, Ref<Image>>::Element *match = state.path_to_image_cache.find(p_path);
// if our cache contains this image then don't bother
if (match) {
@@ -358,13 +358,13 @@ public:
print_verbose("Open Asset Import: Loading embedded texture " + filename);
if (tex->mHeight == 0) {
if (tex->CheckFormat("png")) {
- ERR_FAIL_COND_V(Image::_png_mem_loader_func == NULL, Ref<Image>());
+ ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, Ref<Image>());
Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
state.path_to_image_cache.insert(p_path, img);
return img;
} else if (tex->CheckFormat("jpg")) {
- ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == NULL, Ref<Image>());
+ ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, Ref<Image>());
Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
ERR_FAIL_COND_V(img.is_null(), Ref<Image>());
state.path_to_image_cache.insert(p_path, img);
@@ -440,7 +440,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/assimp/register_types.h b/modules/assimp/register_types.h
index f363744c0a..f399a7acc6 100644
--- a/modules/assimp/register_types.h
+++ b/modules/assimp/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef ASSIMP_REGISTER_TYPES_H
+#define ASSIMP_REGISTER_TYPES_H
+
void register_assimp_types();
void unregister_assimp_types();
+
+#endif // ASSIMP_REGISTER_TYPES_H
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub
index 63324e920b..dc7b176d24 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_basisu = env_modules.Clone()
@@ -9,36 +9,38 @@ env_basisu = env_modules.Clone()
# Not unbundled so far since not widespread as shared library
thirdparty_dir = "#thirdparty/basis_universal/"
tool_sources = [
- "basisu_astc_decomp.cpp",
- "basisu_backend.cpp",
- "basisu_basis_file.cpp",
- "basisu_comp.cpp",
- "basisu_enc.cpp",
- "basisu_etc.cpp",
- "basisu_frontend.cpp",
- "basisu_global_selector_palette_helpers.cpp",
- "basisu_gpu_texture.cpp",
- "basisu_pvrtc1_4.cpp",
- "basisu_resample_filters.cpp",
- "basisu_resampler.cpp",
- "basisu_ssim.cpp",
- "lodepng.cpp",
+ "basisu_astc_decomp.cpp",
+ "basisu_backend.cpp",
+ "basisu_basis_file.cpp",
+ "basisu_comp.cpp",
+ "basisu_enc.cpp",
+ "basisu_etc.cpp",
+ "basisu_frontend.cpp",
+ "basisu_global_selector_palette_helpers.cpp",
+ "basisu_gpu_texture.cpp",
+ "basisu_pvrtc1_4.cpp",
+ "basisu_resample_filters.cpp",
+ "basisu_resampler.cpp",
+ "basisu_ssim.cpp",
+ "lodepng.cpp",
]
tool_sources = [thirdparty_dir + file for file in tool_sources]
transcoder_sources = [thirdparty_dir + "transcoder/basisu_transcoder.cpp"]
# Treat Basis headers as system headers to avoid raising warnings. Not supported on MSVC.
if not env.msvc:
- env_basisu.Append(CPPFLAGS=['-isystem', Dir(thirdparty_dir).path, '-isystem', Dir(thirdparty_dir + "transcoder").path])
+ env_basisu.Append(
+ CPPFLAGS=["-isystem", Dir(thirdparty_dir).path, "-isystem", Dir(thirdparty_dir + "transcoder").path]
+ )
else:
env_basisu.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "transcoder"])
-if env['target'] == "debug":
- env_basisu.Append(CPPFLAGS=["-DBASISU_DEVEL_MESSAGES=1", "-DBASISD_ENABLE_DEBUG_FLAGS=1"])
+if env["target"] == "debug":
+ env_basisu.Append(CPPFLAGS=["-DBASISU_DEVEL_MESSAGES=1", "-DBASISD_ENABLE_DEBUG_FLAGS=1"])
env_thirdparty = env_basisu.Clone()
env_thirdparty.disable_warnings()
-if env['tools']:
+if env["tools"]:
env_thirdparty.add_source_files(env.modules_sources, tool_sources)
env_thirdparty.add_source_files(env.modules_sources, transcoder_sources)
diff --git a/modules/basis_universal/config.py b/modules/basis_universal/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/basis_universal/config.py
+++ b/modules/basis_universal/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index 062b5b59f8..f31c889a6d 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -31,7 +31,7 @@
#include "register_types.h"
#include "core/os/os.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
#include "texture_basisu.h"
#ifdef TOOLS_ENABLED
@@ -98,7 +98,7 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::
params.m_mip_gen = false; //sorry, please some day support provided mipmaps.
params.m_source_images.push_back(buimg);
- BasisDecompressFormat decompress_format;
+ BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_RG;
params.m_check_for_alpha = false;
switch (p_channels) {
@@ -158,33 +158,34 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
const uint8_t *ptr = r;
int size = p_buffer.size();
- basist::transcoder_texture_format format;
- Image::Format imgfmt;
+ basist::transcoder_texture_format format = basist::transcoder_texture_format::cTFTotalTextureFormats;
+ Image::Format imgfmt = Image::FORMAT_MAX;
switch (*(uint32_t *)(ptr)) {
case BASIS_DECOMPRESS_RG: {
- if (VS::get_singleton()->has_os_feature("rgtc")) {
+ if (RS::get_singleton()->has_os_feature("rgtc")) {
format = basist::transcoder_texture_format::cTFBC5; // get this from renderer
imgfmt = Image::FORMAT_RGTC_RG;
- } else if (VS::get_singleton()->has_os_feature("etc2")) {
+ } else if (RS::get_singleton()->has_os_feature("etc2")) {
//unfortunately, basis universal does not support
//
ERR_FAIL_V(image); //unimplemented here
//format = basist::transcoder_texture_format::cTFETC1; // get this from renderer
//imgfmt = Image::FORMAT_RGTC_RG;
} else {
- //decompress
+ // FIXME: There wasn't anything here, but then imgformat is used uninitialized.
+ ERR_FAIL_V(image);
}
} break;
case BASIS_DECOMPRESS_RGB: {
- if (VS::get_singleton()->has_os_feature("bptc")) {
+ if (RS::get_singleton()->has_os_feature("bptc")) {
format = basist::transcoder_texture_format::cTFBC7_M6_OPAQUE_ONLY; // get this from renderer
imgfmt = Image::FORMAT_BPTC_RGBA;
- } else if (VS::get_singleton()->has_os_feature("s3tc")) {
+ } else if (RS::get_singleton()->has_os_feature("s3tc")) {
format = basist::transcoder_texture_format::cTFBC1; // get this from renderer
imgfmt = Image::FORMAT_DXT1;
- } else if (VS::get_singleton()->has_os_feature("etc")) {
+ } else if (RS::get_singleton()->has_os_feature("etc")) {
format = basist::transcoder_texture_format::cTFETC1; // get this from renderer
imgfmt = Image::FORMAT_ETC;
@@ -195,13 +196,13 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
} break;
case BASIS_DECOMPRESS_RGBA: {
- if (VS::get_singleton()->has_os_feature("bptc")) {
+ if (RS::get_singleton()->has_os_feature("bptc")) {
format = basist::transcoder_texture_format::cTFBC7_M5; // get this from renderer
imgfmt = Image::FORMAT_BPTC_RGBA;
- } else if (VS::get_singleton()->has_os_feature("s3tc")) {
+ } else if (RS::get_singleton()->has_os_feature("s3tc")) {
format = basist::transcoder_texture_format::cTFBC3; // get this from renderer
imgfmt = Image::FORMAT_DXT5;
- } else if (VS::get_singleton()->has_os_feature("etc2")) {
+ } else if (RS::get_singleton()->has_os_feature("etc2")) {
format = basist::transcoder_texture_format::cTFETC2; // get this from renderer
imgfmt = Image::FORMAT_ETC2_RGBA8;
} else {
@@ -211,10 +212,10 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
}
} break;
case BASIS_DECOMPRESS_RG_AS_RA: {
- if (VS::get_singleton()->has_os_feature("s3tc")) {
+ if (RS::get_singleton()->has_os_feature("s3tc")) {
format = basist::transcoder_texture_format::cTFBC3; // get this from renderer
imgfmt = Image::FORMAT_DXT5_RA_AS_RG;
- } else if (VS::get_singleton()->has_os_feature("etc2")) {
+ } else if (RS::get_singleton()->has_os_feature("etc2")) {
format = basist::transcoder_texture_format::cTFETC2; // get this from renderer
imgfmt = Image::FORMAT_ETC2_RGBA8;
} else {
@@ -228,7 +229,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
ptr += 4;
size -= 4;
- basist::basisu_transcoder tr(NULL);
+ basist::basisu_transcoder tr(nullptr);
ERR_FAIL_COND_V(!tr.validate_header(ptr, size), image);
@@ -281,7 +282,7 @@ void unregister_basis_universal_types() {
#ifdef TOOLS_ENABLED
delete sel_codebook;
- Image::basis_universal_packer = NULL;
+ Image::basis_universal_packer = nullptr;
#endif
- Image::basis_universal_unpacker = NULL;
+ Image::basis_universal_unpacker = nullptr;
}
diff --git a/modules/basis_universal/register_types.h b/modules/basis_universal/register_types.h
index 977374fbfc..5053dc27ce 100644
--- a/modules/basis_universal/register_types.h
+++ b/modules/basis_universal/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef BASIS_UNIVERSAL_REGISTER_TYPES_H
+#define BASIS_UNIVERSAL_REGISTER_TYPES_H
+
void register_basis_universal_types();
void unregister_basis_universal_types();
+
+#endif // BASIS_UNIVERSAL_REGISTER_TYPES_H
diff --git a/modules/basis_universal/texture_basisu.cpp b/modules/basis_universal/texture_basisu.cpp
index 12f3241c98..2ed0340927 100644
--- a/modules/basis_universal/texture_basisu.cpp
+++ b/modules/basis_universal/texture_basisu.cpp
@@ -72,7 +72,7 @@ bool TextureBasisU::has_alpha() const {
void TextureBasisU::set_flags(uint32_t p_flags) {
flags = p_flags;
- VisualServer::get_singleton()->texture_set_flags(texture, p_flags);
+ RenderingServer::get_singleton()->texture_set_flags(texture, p_flags);
};
uint32_t TextureBasisU::get_flags() const {
@@ -105,7 +105,7 @@ void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) {
imgfmt = Image::FORMAT_ETC2_RGBA8;
};
- basist::basisu_transcoder tr(NULL);
+ basist::basisu_transcoder tr(nullptr);
ERR_FAIL_COND(!tr.validate_header(ptr, size));
@@ -144,8 +144,8 @@ void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) {
img.instance();
img->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata);
- VisualServer::get_singleton()->texture_allocate(texture, tex_size.x, tex_size.y, 0, img->get_format(), VS::TEXTURE_TYPE_2D, flags);
- VisualServer::get_singleton()->texture_set_data(texture, img);
+ RenderingServer::get_singleton()->texture_allocate(texture, tex_size.x, tex_size.y, 0, img->get_format(), RS::TEXTURE_TYPE_2D, flags);
+ RenderingServer::get_singleton()->texture_set_data(texture, img);
};
Error TextureBasisU::import(const Ref<Image>& p_img) {
@@ -221,13 +221,13 @@ Vector<uint8_t> TextureBasisU::get_basisu_data() const {
TextureBasisU::TextureBasisU() {
flags = FLAGS_DEFAULT;
- texture = VisualServer::get_singleton()->texture_create();
+ texture = RenderingServer::get_singleton()->texture_create();
};
TextureBasisU::~TextureBasisU() {
- VisualServer::get_singleton()->free(texture);
+ RenderingServer::get_singleton()->free(texture);
};
#endif
diff --git a/modules/bmp/SCsub b/modules/bmp/SCsub
index e7da7cf108..4f3405ff28 100644
--- a/modules/bmp/SCsub
+++ b/modules/bmp/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_bmp = env_modules.Clone()
diff --git a/modules/bmp/config.py b/modules/bmp/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/bmp/config.py
+++ b/modules/bmp/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index 71e5076e78..ea2b2b548f 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -38,7 +38,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
Error err = OK;
- if (p_buffer == NULL)
+ if (p_buffer == nullptr)
err = FAILED;
if (err == OK) {
@@ -151,7 +151,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
line -= line_width;
}
- if (p_color_buffer == NULL || color_table_size == 0) { // regular pixels
+ if (p_color_buffer == nullptr || color_table_size == 0) { // regular pixels
p_image->create(width, height, 0, Image::FORMAT_RGBA8, data);
diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp
index d5cc6c5eb3..6220e956d6 100644
--- a/modules/bmp/register_types.cpp
+++ b/modules/bmp/register_types.cpp
@@ -32,7 +32,7 @@
#include "image_loader_bmp.h"
-static ImageLoaderBMP *image_loader_bmp = NULL;
+static ImageLoaderBMP *image_loader_bmp = nullptr;
void register_bmp_types() {
image_loader_bmp = memnew(ImageLoaderBMP);
diff --git a/modules/bmp/register_types.h b/modules/bmp/register_types.h
index 398716eaa1..e7561dc32d 100644
--- a/modules/bmp/register_types.h
+++ b/modules/bmp/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef BMP_REGISTER_TYPES_H
+#define BMP_REGISTER_TYPES_H
+
void register_bmp_types();
void unregister_bmp_types();
+
+#endif // BMP_REGISTER_TYPES_H
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index 02d0a31a69..692c749886 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -1,208 +1,203 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_bullet = env_modules.Clone()
# Thirdparty source files
-if env['builtin_bullet']:
+if env["builtin_bullet"]:
# Build only version 2 for now (as of 2.89)
# Sync file list with relevant upstream CMakeLists.txt for each folder.
thirdparty_dir = "#thirdparty/bullet/"
bullet2_src = [
# BulletCollision
- "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp"
- , "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp"
- , "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp"
- , "BulletCollision/BroadphaseCollision/btDbvt.cpp"
- , "BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp"
- , "BulletCollision/BroadphaseCollision/btDispatcher.cpp"
- , "BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp"
- , "BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp"
- , "BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp"
- , "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp"
- , "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp"
- , "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp"
- , "BulletCollision/CollisionDispatch/btCollisionObject.cpp"
- , "BulletCollision/CollisionDispatch/btCollisionWorld.cpp"
- , "BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp"
- , "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp"
- , "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btGhostObject.cpp"
- , "BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp"
- , "BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp"
- , "BulletCollision/CollisionDispatch/btManifoldResult.cpp"
- , "BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp"
- , "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp"
- , "BulletCollision/CollisionDispatch/btUnionFind.cpp"
- , "BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp"
- , "BulletCollision/CollisionShapes/btBoxShape.cpp"
- , "BulletCollision/CollisionShapes/btBox2dShape.cpp"
- , "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp"
- , "BulletCollision/CollisionShapes/btCapsuleShape.cpp"
- , "BulletCollision/CollisionShapes/btCollisionShape.cpp"
- , "BulletCollision/CollisionShapes/btCompoundShape.cpp"
- , "BulletCollision/CollisionShapes/btConcaveShape.cpp"
- , "BulletCollision/CollisionShapes/btConeShape.cpp"
- , "BulletCollision/CollisionShapes/btConvexHullShape.cpp"
- , "BulletCollision/CollisionShapes/btConvexInternalShape.cpp"
- , "BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp"
- , "BulletCollision/CollisionShapes/btConvexPolyhedron.cpp"
- , "BulletCollision/CollisionShapes/btConvexShape.cpp"
- , "BulletCollision/CollisionShapes/btConvex2dShape.cpp"
- , "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp"
- , "BulletCollision/CollisionShapes/btCylinderShape.cpp"
- , "BulletCollision/CollisionShapes/btEmptyShape.cpp"
- , "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp"
- , "BulletCollision/CollisionShapes/btMiniSDF.cpp"
- , "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp"
- , "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp"
- , "BulletCollision/CollisionShapes/btMultiSphereShape.cpp"
- , "BulletCollision/CollisionShapes/btOptimizedBvh.cpp"
- , "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp"
- , "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp"
- , "BulletCollision/CollisionShapes/btSdfCollisionShape.cpp"
- , "BulletCollision/CollisionShapes/btShapeHull.cpp"
- , "BulletCollision/CollisionShapes/btSphereShape.cpp"
- , "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp"
- , "BulletCollision/CollisionShapes/btStridingMeshInterface.cpp"
- , "BulletCollision/CollisionShapes/btTetrahedronShape.cpp"
- , "BulletCollision/CollisionShapes/btTriangleBuffer.cpp"
- , "BulletCollision/CollisionShapes/btTriangleCallback.cpp"
- , "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp"
- , "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp"
- , "BulletCollision/CollisionShapes/btTriangleMesh.cpp"
- , "BulletCollision/CollisionShapes/btTriangleMeshShape.cpp"
- , "BulletCollision/CollisionShapes/btUniformScalingShape.cpp"
- , "BulletCollision/Gimpact/btContactProcessing.cpp"
- , "BulletCollision/Gimpact/btGenericPoolAllocator.cpp"
- , "BulletCollision/Gimpact/btGImpactBvh.cpp"
- , "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp"
- , "BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp"
- , "BulletCollision/Gimpact/btGImpactShape.cpp"
- , "BulletCollision/Gimpact/btTriangleShapeEx.cpp"
- , "BulletCollision/Gimpact/gim_box_set.cpp"
- , "BulletCollision/Gimpact/gim_contact.cpp"
- , "BulletCollision/Gimpact/gim_memory.cpp"
- , "BulletCollision/Gimpact/gim_tri_collision.cpp"
- , "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp"
- , "BulletCollision/NarrowPhaseCollision/btConvexCast.cpp"
- , "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp"
- , "BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp"
- , "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp"
- , "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp"
- , "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp"
- , "BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp"
- , "BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp"
- , "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp"
- , "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp"
- , "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp"
-
+ "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp",
+ "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp",
+ "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp",
+ "BulletCollision/BroadphaseCollision/btDbvt.cpp",
+ "BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp",
+ "BulletCollision/BroadphaseCollision/btDispatcher.cpp",
+ "BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp",
+ "BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp",
+ "BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp",
+ "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp",
+ "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp",
+ "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp",
+ "BulletCollision/CollisionDispatch/btCollisionObject.cpp",
+ "BulletCollision/CollisionDispatch/btCollisionWorld.cpp",
+ "BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp",
+ "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp",
+ "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btGhostObject.cpp",
+ "BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp",
+ "BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp",
+ "BulletCollision/CollisionDispatch/btManifoldResult.cpp",
+ "BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp",
+ "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp",
+ "BulletCollision/CollisionDispatch/btUnionFind.cpp",
+ "BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp",
+ "BulletCollision/CollisionShapes/btBoxShape.cpp",
+ "BulletCollision/CollisionShapes/btBox2dShape.cpp",
+ "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp",
+ "BulletCollision/CollisionShapes/btCapsuleShape.cpp",
+ "BulletCollision/CollisionShapes/btCollisionShape.cpp",
+ "BulletCollision/CollisionShapes/btCompoundShape.cpp",
+ "BulletCollision/CollisionShapes/btConcaveShape.cpp",
+ "BulletCollision/CollisionShapes/btConeShape.cpp",
+ "BulletCollision/CollisionShapes/btConvexHullShape.cpp",
+ "BulletCollision/CollisionShapes/btConvexInternalShape.cpp",
+ "BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp",
+ "BulletCollision/CollisionShapes/btConvexPolyhedron.cpp",
+ "BulletCollision/CollisionShapes/btConvexShape.cpp",
+ "BulletCollision/CollisionShapes/btConvex2dShape.cpp",
+ "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp",
+ "BulletCollision/CollisionShapes/btCylinderShape.cpp",
+ "BulletCollision/CollisionShapes/btEmptyShape.cpp",
+ "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp",
+ "BulletCollision/CollisionShapes/btMiniSDF.cpp",
+ "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp",
+ "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp",
+ "BulletCollision/CollisionShapes/btMultiSphereShape.cpp",
+ "BulletCollision/CollisionShapes/btOptimizedBvh.cpp",
+ "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp",
+ "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp",
+ "BulletCollision/CollisionShapes/btSdfCollisionShape.cpp",
+ "BulletCollision/CollisionShapes/btShapeHull.cpp",
+ "BulletCollision/CollisionShapes/btSphereShape.cpp",
+ "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp",
+ "BulletCollision/CollisionShapes/btStridingMeshInterface.cpp",
+ "BulletCollision/CollisionShapes/btTetrahedronShape.cpp",
+ "BulletCollision/CollisionShapes/btTriangleBuffer.cpp",
+ "BulletCollision/CollisionShapes/btTriangleCallback.cpp",
+ "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp",
+ "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp",
+ "BulletCollision/CollisionShapes/btTriangleMesh.cpp",
+ "BulletCollision/CollisionShapes/btTriangleMeshShape.cpp",
+ "BulletCollision/CollisionShapes/btUniformScalingShape.cpp",
+ "BulletCollision/Gimpact/btContactProcessing.cpp",
+ "BulletCollision/Gimpact/btGenericPoolAllocator.cpp",
+ "BulletCollision/Gimpact/btGImpactBvh.cpp",
+ "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp",
+ "BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp",
+ "BulletCollision/Gimpact/btGImpactShape.cpp",
+ "BulletCollision/Gimpact/btTriangleShapeEx.cpp",
+ "BulletCollision/Gimpact/gim_box_set.cpp",
+ "BulletCollision/Gimpact/gim_contact.cpp",
+ "BulletCollision/Gimpact/gim_memory.cpp",
+ "BulletCollision/Gimpact/gim_tri_collision.cpp",
+ "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp",
+ "BulletCollision/NarrowPhaseCollision/btConvexCast.cpp",
+ "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp",
+ "BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp",
+ "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp",
+ "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp",
+ "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp",
+ "BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp",
+ "BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp",
+ "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp",
+ "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp",
+ "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp",
# BulletDynamics
- , "BulletDynamics/Character/btKinematicCharacterController.cpp"
- , "BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btContactConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btFixedConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btGearConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp"
- , "BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp"
- , "BulletDynamics/ConstraintSolver/btHingeConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp"
- , "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp"
- , "BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp"
- , "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp"
- , "BulletDynamics/ConstraintSolver/btSliderConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btTypedConstraint.cpp"
- , "BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp"
- , "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp"
- , "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp"
- , "BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp"
- , "BulletDynamics/Dynamics/btRigidBody.cpp"
- , "BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp"
- #, "BulletDynamics/Dynamics/Bullet-C-API.cpp"
- , "BulletDynamics/Vehicle/btRaycastVehicle.cpp"
- , "BulletDynamics/Vehicle/btWheelInfo.cpp"
- , "BulletDynamics/Featherstone/btMultiBody.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyConstraint.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp"
- , "BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp"
- , "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp"
- , "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp"
- , "BulletDynamics/MLCPSolvers/btDantzigLCP.cpp"
- , "BulletDynamics/MLCPSolvers/btMLCPSolver.cpp"
- , "BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp"
-
+ "BulletDynamics/Character/btKinematicCharacterController.cpp",
+ "BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btContactConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btFixedConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btGearConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp",
+ "BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp",
+ "BulletDynamics/ConstraintSolver/btHingeConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp",
+ "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.cpp",
+ "BulletDynamics/ConstraintSolver/btBatchedConstraints.cpp",
+ "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp",
+ "BulletDynamics/ConstraintSolver/btSliderConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btTypedConstraint.cpp",
+ "BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp",
+ "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp",
+ "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp",
+ "BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp",
+ "BulletDynamics/Dynamics/btRigidBody.cpp",
+ "BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp",
+ # "BulletDynamics/Dynamics/Bullet-C-API.cpp",
+ "BulletDynamics/Vehicle/btRaycastVehicle.cpp",
+ "BulletDynamics/Vehicle/btWheelInfo.cpp",
+ "BulletDynamics/Featherstone/btMultiBody.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyConstraint.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.cpp",
+ "BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp",
+ "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp",
+ "BulletDynamics/Featherstone/btMultiBodySphericalJointMotor.cpp",
+ "BulletDynamics/MLCPSolvers/btDantzigLCP.cpp",
+ "BulletDynamics/MLCPSolvers/btMLCPSolver.cpp",
+ "BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp",
# BulletInverseDynamics
- , "BulletInverseDynamics/IDMath.cpp"
- , "BulletInverseDynamics/MultiBodyTree.cpp"
- , "BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp"
- , "BulletInverseDynamics/details/MultiBodyTreeImpl.cpp"
-
+ "BulletInverseDynamics/IDMath.cpp",
+ "BulletInverseDynamics/MultiBodyTree.cpp",
+ "BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp",
+ "BulletInverseDynamics/details/MultiBodyTreeImpl.cpp",
# BulletSoftBody
- , "BulletSoftBody/btSoftBody.cpp"
- , "BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp"
- , "BulletSoftBody/btSoftBodyHelpers.cpp"
- , "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp"
- , "BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp"
- , "BulletSoftBody/btSoftRigidDynamicsWorld.cpp"
- , "BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp"
- , "BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp"
- , "BulletSoftBody/btDefaultSoftBodySolver.cpp"
- , "BulletSoftBody/btDeformableBackwardEulerObjective.cpp"
- , "BulletSoftBody/btDeformableBodySolver.cpp"
- , "BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp"
- , "BulletSoftBody/btDeformableContactProjection.cpp"
- , "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp"
- , "BulletSoftBody/btDeformableContactConstraint.cpp"
-
+ "BulletSoftBody/btSoftBody.cpp",
+ "BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp",
+ "BulletSoftBody/btSoftBodyHelpers.cpp",
+ "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp",
+ "BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp",
+ "BulletSoftBody/btSoftRigidDynamicsWorld.cpp",
+ "BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp",
+ "BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp",
+ "BulletSoftBody/btDefaultSoftBodySolver.cpp",
+ "BulletSoftBody/btDeformableBackwardEulerObjective.cpp",
+ "BulletSoftBody/btDeformableBodySolver.cpp",
+ "BulletSoftBody/btDeformableMultiBodyConstraintSolver.cpp",
+ "BulletSoftBody/btDeformableContactProjection.cpp",
+ "BulletSoftBody/btDeformableMultiBodyDynamicsWorld.cpp",
+ "BulletSoftBody/btDeformableContactConstraint.cpp",
# clew
- , "clew/clew.c"
-
+ "clew/clew.c",
# LinearMath
- , "LinearMath/btAlignedAllocator.cpp"
- , "LinearMath/btConvexHull.cpp"
- , "LinearMath/btConvexHullComputer.cpp"
- , "LinearMath/btGeometryUtil.cpp"
- , "LinearMath/btPolarDecomposition.cpp"
- , "LinearMath/btQuickprof.cpp"
- , "LinearMath/btSerializer.cpp"
- , "LinearMath/btSerializer64.cpp"
- , "LinearMath/btThreads.cpp"
- , "LinearMath/btVector3.cpp"
- , "LinearMath/TaskScheduler/btTaskScheduler.cpp"
- , "LinearMath/TaskScheduler/btThreadSupportPosix.cpp"
- , "LinearMath/TaskScheduler/btThreadSupportWin32.cpp"
+ "LinearMath/btAlignedAllocator.cpp",
+ "LinearMath/btConvexHull.cpp",
+ "LinearMath/btConvexHullComputer.cpp",
+ "LinearMath/btGeometryUtil.cpp",
+ "LinearMath/btPolarDecomposition.cpp",
+ "LinearMath/btQuickprof.cpp",
+ "LinearMath/btSerializer.cpp",
+ "LinearMath/btSerializer64.cpp",
+ "LinearMath/btThreads.cpp",
+ "LinearMath/btVector3.cpp",
+ "LinearMath/TaskScheduler/btTaskScheduler.cpp",
+ "LinearMath/TaskScheduler/btThreadSupportPosix.cpp",
+ "LinearMath/TaskScheduler/btThreadSupportWin32.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in bullet2_src]
# Treat Bullet headers as system headers to avoid raising warnings. Not supported on MSVC.
if not env.msvc:
- env_bullet.Append(CPPFLAGS=['-isystem', Dir(thirdparty_dir).path])
+ env_bullet.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
else:
env_bullet.Prepend(CPPPATH=[thirdparty_dir])
# if env['target'] == "debug" or env['target'] == "release_debug":
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index e8a5c1475a..4d727529ef 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -46,7 +46,7 @@
AreaBullet::AreaBullet() :
RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA),
monitorable(true),
- spOv_mode(PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED),
+ spOv_mode(PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED),
spOv_gravityPoint(false),
spOv_gravityPointDistanceScale(0),
spOv_gravityPointAttenuation(1),
@@ -86,11 +86,11 @@ void AreaBullet::dispatch_callbacks() {
switch (otherObj.state) {
case OVERLAP_STATE_ENTER:
otherObj.state = OVERLAP_STATE_INSIDE;
- call_event(otherObj.object, PhysicsServer::AREA_BODY_ADDED);
+ call_event(otherObj.object, PhysicsServer3D::AREA_BODY_ADDED);
otherObj.object->on_enter_area(this);
break;
case OVERLAP_STATE_EXIT:
- call_event(otherObj.object, PhysicsServer::AREA_BODY_REMOVED);
+ call_event(otherObj.object, PhysicsServer3D::AREA_BODY_REMOVED);
otherObj.object->on_exit_area(this);
overlappingObjects.remove(i); // Remove after callback
break;
@@ -101,7 +101,7 @@ void AreaBullet::dispatch_callbacks() {
}
}
-void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer::AreaBodyStatus p_status) {
+void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status) {
InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())];
Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id);
@@ -130,7 +130,7 @@ void AreaBullet::scratch() {
void AreaBullet::clear_overlaps(bool p_notify) {
for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
if (p_notify)
- call_event(overlappingObjects[i].object, PhysicsServer::AREA_BODY_REMOVED);
+ call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
overlappingObjects[i].object->on_exit_area(this);
}
overlappingObjects.clear();
@@ -140,7 +140,7 @@ void AreaBullet::remove_overlap(CollisionObjectBullet *p_object, bool p_notify)
for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
if (overlappingObjects[i].object == p_object) {
if (p_notify)
- call_event(overlappingObjects[i].object, PhysicsServer::AREA_BODY_REMOVED);
+ call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED);
overlappingObjects[i].object->on_exit_area(this);
overlappingObjects.remove(i);
break;
@@ -218,30 +218,30 @@ void AreaBullet::put_overlap_as_inside(int p_index) {
}
}
-void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) {
+void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
switch (p_param) {
- case PhysicsServer::AREA_PARAM_GRAVITY:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY:
set_spOv_gravityMag(p_value);
break;
- case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
set_spOv_gravityVec(p_value);
break;
- case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
set_spOv_linearDump(p_value);
break;
- case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
set_spOv_angularDump(p_value);
break;
- case PhysicsServer::AREA_PARAM_PRIORITY:
+ case PhysicsServer3D::AREA_PARAM_PRIORITY:
set_spOv_priority(p_value);
break;
- case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
set_spOv_gravityPoint(p_value);
break;
- case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
set_spOv_gravityPointDistanceScale(p_value);
break;
- case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
set_spOv_gravityPointAttenuation(p_value);
break;
default:
@@ -249,23 +249,23 @@ void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &
}
}
-Variant AreaBullet::get_param(PhysicsServer::AreaParameter p_param) const {
+Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const {
switch (p_param) {
- case PhysicsServer::AREA_PARAM_GRAVITY:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY:
return spOv_gravityMag;
- case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
return spOv_gravityVec;
- case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
return spOv_linearDump;
- case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
return spOv_angularDump;
- case PhysicsServer::AREA_PARAM_PRIORITY:
+ case PhysicsServer3D::AREA_PARAM_PRIORITY:
return spOv_priority;
- case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
return spOv_gravityPoint;
- case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
return spOv_gravityPointDistanceScale;
- case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
return spOv_gravityPointAttenuation;
default:
WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h
index 18888c6725..0272350510 100644
--- a/modules/bullet/area_bullet.h
+++ b/modules/bullet/area_bullet.h
@@ -33,7 +33,7 @@
#include "collision_object_bullet.h"
#include "core/vector.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#include "space_bullet.h"
/**
@@ -65,7 +65,7 @@ public:
OverlapState state;
OverlappingObjectData() :
- object(NULL),
+ object(nullptr),
state(OVERLAP_STATE_ENTER) {}
OverlappingObjectData(CollisionObjectBullet *p_object, OverlapState p_state) :
object(p_object),
@@ -88,7 +88,7 @@ private:
Vector<OverlappingObjectData> overlappingObjects;
bool monitorable;
- PhysicsServer::AreaSpaceOverrideMode spOv_mode;
+ PhysicsServer3D::AreaSpaceOverrideMode spOv_mode;
bool spOv_gravityPoint;
real_t spOv_gravityPointDistanceScale;
real_t spOv_gravityPointAttenuation;
@@ -114,8 +114,8 @@ public:
bool is_monitoring() const;
- _FORCE_INLINE_ void set_spOv_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) { spOv_mode = p_mode; }
- _FORCE_INLINE_ PhysicsServer::AreaSpaceOverrideMode get_spOv_mode() { return spOv_mode; }
+ _FORCE_INLINE_ void set_spOv_mode(PhysicsServer3D::AreaSpaceOverrideMode p_mode) { spOv_mode = p_mode; }
+ _FORCE_INLINE_ PhysicsServer3D::AreaSpaceOverrideMode get_spOv_mode() { return spOv_mode; }
_FORCE_INLINE_ void set_spOv_gravityPoint(bool p_isGP) { spOv_gravityPoint = p_isGP; }
_FORCE_INLINE_ bool is_spOv_gravityPoint() { return spOv_gravityPoint; }
@@ -146,7 +146,7 @@ public:
virtual void set_space(SpaceBullet *p_space);
virtual void dispatch_callbacks();
- void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer::AreaBodyStatus p_status);
+ void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status);
void set_on_state_change(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
void scratch();
@@ -162,8 +162,8 @@ public:
void put_overlap_as_exit(int p_index);
void put_overlap_as_inside(int p_index);
- void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value);
- Variant get_param(PhysicsServer::AreaParameter p_param) const;
+ void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer3D::AreaParameter p_param) const;
void set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method);
bool has_event_callback(Type p_callbackObjectType);
diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp
index 4071723a3e..0f54f848dc 100644
--- a/modules/bullet/btRayShape.cpp
+++ b/modules/bullet/btRayShape.cpp
@@ -43,6 +43,7 @@ btRayShape::btRayShape(btScalar length) :
m_shapeAxis(0, 0, 1) {
m_shapeType = CUSTOM_CONVEX_SHAPE_TYPE;
setLength(length);
+ slipsOnSlope = false;
}
btRayShape::~btRayShape() {
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 89868babc6..2705c749a2 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -74,19 +74,19 @@
body->get_space()->add_constraint(joint, joint->is_disabled_collisions_between_bodies());
// <--------------- Joint creation asserts
-void BulletPhysicsServer::_bind_methods() {
- //ClassDB::bind_method(D_METHOD("DoTest"), &BulletPhysicsServer::DoTest);
+void BulletPhysicsServer3D::_bind_methods() {
+ //ClassDB::bind_method(D_METHOD("DoTest"), &BulletPhysicsServer3D::DoTest);
}
-BulletPhysicsServer::BulletPhysicsServer() :
- PhysicsServer(),
+BulletPhysicsServer3D::BulletPhysicsServer3D() :
+ PhysicsServer3D(),
active(true),
active_spaces_count(0) {}
-BulletPhysicsServer::~BulletPhysicsServer() {}
+BulletPhysicsServer3D::~BulletPhysicsServer3D() {}
-RID BulletPhysicsServer::shape_create(ShapeType p_shape) {
- ShapeBullet *shape = NULL;
+RID BulletPhysicsServer3D::shape_create(ShapeType p_shape) {
+ ShapeBullet *shape = nullptr;
switch (p_shape) {
case SHAPE_PLANE: {
@@ -133,51 +133,51 @@ RID BulletPhysicsServer::shape_create(ShapeType p_shape) {
CreateThenReturnRID(shape_owner, shape)
}
-void BulletPhysicsServer::shape_set_data(RID p_shape, const Variant &p_data) {
+void BulletPhysicsServer3D::shape_set_data(RID p_shape, const Variant &p_data) {
ShapeBullet *shape = shape_owner.getornull(p_shape);
ERR_FAIL_COND(!shape);
shape->set_data(p_data);
}
-void BulletPhysicsServer::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
+void BulletPhysicsServer3D::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
//WARN_PRINT("Bias not supported by Bullet physics engine");
}
-PhysicsServer::ShapeType BulletPhysicsServer::shape_get_type(RID p_shape) const {
+PhysicsServer3D::ShapeType BulletPhysicsServer3D::shape_get_type(RID p_shape) const {
ShapeBullet *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, PhysicsServer::SHAPE_CUSTOM);
+ ERR_FAIL_COND_V(!shape, PhysicsServer3D::SHAPE_CUSTOM);
return shape->get_type();
}
-Variant BulletPhysicsServer::shape_get_data(RID p_shape) const {
+Variant BulletPhysicsServer3D::shape_get_data(RID p_shape) const {
ShapeBullet *shape = shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, Variant());
return shape->get_data();
}
-void BulletPhysicsServer::shape_set_margin(RID p_shape, real_t p_margin) {
+void BulletPhysicsServer3D::shape_set_margin(RID p_shape, real_t p_margin) {
ShapeBullet *shape = shape_owner.getornull(p_shape);
ERR_FAIL_COND(!shape);
shape->set_margin(p_margin);
}
-real_t BulletPhysicsServer::shape_get_margin(RID p_shape) const {
+real_t BulletPhysicsServer3D::shape_get_margin(RID p_shape) const {
ShapeBullet *shape = shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0.0);
return shape->get_margin();
}
-real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const {
+real_t BulletPhysicsServer3D::shape_get_custom_solver_bias(RID p_shape) const {
//WARN_PRINT("Bias not supported by Bullet physics engine");
return 0.;
}
-RID BulletPhysicsServer::space_create() {
+RID BulletPhysicsServer3D::space_create() {
SpaceBullet *space = bulletnew(SpaceBullet);
CreateThenReturnRID(space_owner, space);
}
-void BulletPhysicsServer::space_set_active(RID p_space, bool p_active) {
+void BulletPhysicsServer3D::space_set_active(RID p_space, bool p_active) {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND(!space);
@@ -195,64 +195,64 @@ void BulletPhysicsServer::space_set_active(RID p_space, bool p_active) {
}
}
-bool BulletPhysicsServer::space_is_active(RID p_space) const {
+bool BulletPhysicsServer3D::space_is_active(RID p_space) const {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND_V(!space, false);
return -1 != active_spaces.find(space);
}
-void BulletPhysicsServer::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
+void BulletPhysicsServer3D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND(!space);
space->set_param(p_param, p_value);
}
-real_t BulletPhysicsServer::space_get_param(RID p_space, SpaceParameter p_param) const {
+real_t BulletPhysicsServer3D::space_get_param(RID p_space, SpaceParameter p_param) const {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND_V(!space, 0);
return space->get_param(p_param);
}
-PhysicsDirectSpaceState *BulletPhysicsServer::space_get_direct_state(RID p_space) {
+PhysicsDirectSpaceState3D *BulletPhysicsServer3D::space_get_direct_state(RID p_space) {
SpaceBullet *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, NULL);
+ ERR_FAIL_COND_V(!space, nullptr);
return space->get_direct_state();
}
-void BulletPhysicsServer::space_set_debug_contacts(RID p_space, int p_max_contacts) {
+void BulletPhysicsServer3D::space_set_debug_contacts(RID p_space, int p_max_contacts) {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND(!space);
space->set_debug_contacts(p_max_contacts);
}
-Vector<Vector3> BulletPhysicsServer::space_get_contacts(RID p_space) const {
+Vector<Vector3> BulletPhysicsServer3D::space_get_contacts(RID p_space) const {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND_V(!space, Vector<Vector3>());
return space->get_debug_contacts();
}
-int BulletPhysicsServer::space_get_contact_count(RID p_space) const {
+int BulletPhysicsServer3D::space_get_contact_count(RID p_space) const {
SpaceBullet *space = space_owner.getornull(p_space);
ERR_FAIL_COND_V(!space, 0);
return space->get_debug_contact_count();
}
-RID BulletPhysicsServer::area_create() {
+RID BulletPhysicsServer3D::area_create() {
AreaBullet *area = bulletnew(AreaBullet);
area->set_collision_layer(1);
area->set_collision_mask(1);
CreateThenReturnRID(area_owner, area)
}
-void BulletPhysicsServer::area_set_space(RID p_area, RID p_space) {
+void BulletPhysicsServer3D::area_set_space(RID p_area, RID p_space) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
- SpaceBullet *space = NULL;
+ SpaceBullet *space = nullptr;
if (p_space.is_valid()) {
space = space_owner.getornull(p_space);
ERR_FAIL_COND(!space);
@@ -260,26 +260,26 @@ void BulletPhysicsServer::area_set_space(RID p_area, RID p_space) {
area->set_space(space);
}
-RID BulletPhysicsServer::area_get_space(RID p_area) const {
+RID BulletPhysicsServer3D::area_get_space(RID p_area) const {
AreaBullet *area = area_owner.getornull(p_area);
return area->get_space()->get_self();
}
-void BulletPhysicsServer::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
+void BulletPhysicsServer3D::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_spOv_mode(p_mode);
}
-PhysicsServer::AreaSpaceOverrideMode BulletPhysicsServer::area_get_space_override_mode(RID p_area) const {
+PhysicsServer3D::AreaSpaceOverrideMode BulletPhysicsServer3D::area_get_space_override_mode(RID p_area) const {
AreaBullet *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED);
+ ERR_FAIL_COND_V(!area, PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED);
return area->get_spOv_mode();
}
-void BulletPhysicsServer::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
+void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -289,7 +289,7 @@ void BulletPhysicsServer::area_add_shape(RID p_area, RID p_shape, const Transfor
area->add_shape(shape, p_transform, p_disabled);
}
-void BulletPhysicsServer::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
+void BulletPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -299,41 +299,41 @@ void BulletPhysicsServer::area_set_shape(RID p_area, int p_shape_idx, RID p_shap
area->set_shape(p_shape_idx, shape);
}
-void BulletPhysicsServer::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) {
+void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_shape_transform(p_shape_idx, p_transform);
}
-int BulletPhysicsServer::area_get_shape_count(RID p_area) const {
+int BulletPhysicsServer3D::area_get_shape_count(RID p_area) const {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND_V(!area, 0);
return area->get_shape_count();
}
-RID BulletPhysicsServer::area_get_shape(RID p_area, int p_shape_idx) const {
+RID BulletPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND_V(!area, RID());
return area->get_shape(p_shape_idx)->get_self();
}
-Transform BulletPhysicsServer::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+Transform BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND_V(!area, Transform());
return area->get_shape_transform(p_shape_idx);
}
-void BulletPhysicsServer::area_remove_shape(RID p_area, int p_shape_idx) {
+void BulletPhysicsServer3D::area_remove_shape(RID p_area, int p_shape_idx) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
return area->remove_shape_full(p_shape_idx);
}
-void BulletPhysicsServer::area_clear_shapes(RID p_area) {
+void BulletPhysicsServer3D::area_clear_shapes(RID p_area) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
@@ -341,14 +341,14 @@ void BulletPhysicsServer::area_clear_shapes(RID p_area) {
area->remove_shape_full(0);
}
-void BulletPhysicsServer::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) {
+void BulletPhysicsServer3D::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_shape_disabled(p_shape_idx, p_disabled);
}
-void BulletPhysicsServer::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
+void BulletPhysicsServer3D::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
if (space_owner.owns(p_area)) {
return;
}
@@ -357,7 +357,7 @@ void BulletPhysicsServer::area_attach_object_instance_id(RID p_area, ObjectID p_
area->set_instance_id(p_id);
}
-ObjectID BulletPhysicsServer::area_get_object_instance_id(RID p_area) const {
+ObjectID BulletPhysicsServer3D::area_get_object_instance_id(RID p_area) const {
if (space_owner.owns(p_area)) {
return ObjectID();
}
@@ -366,7 +366,7 @@ ObjectID BulletPhysicsServer::area_get_object_instance_id(RID p_area) const {
return area->get_instance_id();
}
-void BulletPhysicsServer::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
+void BulletPhysicsServer3D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
if (space_owner.owns(p_area)) {
SpaceBullet *space = space_owner.getornull(p_area);
if (space) {
@@ -381,7 +381,7 @@ void BulletPhysicsServer::area_set_param(RID p_area, AreaParameter p_param, cons
}
}
-Variant BulletPhysicsServer::area_get_param(RID p_area, AreaParameter p_param) const {
+Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param) const {
if (space_owner.owns(p_area)) {
SpaceBullet *space = space_owner.getornull(p_area);
return space->get_param(p_param);
@@ -393,64 +393,64 @@ Variant BulletPhysicsServer::area_get_param(RID p_area, AreaParameter p_param) c
}
}
-void BulletPhysicsServer::area_set_transform(RID p_area, const Transform &p_transform) {
+void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform &p_transform) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_transform(p_transform);
}
-Transform BulletPhysicsServer::area_get_transform(RID p_area) const {
+Transform BulletPhysicsServer3D::area_get_transform(RID p_area) const {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND_V(!area, Transform());
return area->get_transform();
}
-void BulletPhysicsServer::area_set_collision_mask(RID p_area, uint32_t p_mask) {
+void BulletPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_collision_mask(p_mask);
}
-void BulletPhysicsServer::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+void BulletPhysicsServer3D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_collision_layer(p_layer);
}
-void BulletPhysicsServer::area_set_monitorable(RID p_area, bool p_monitorable) {
+void BulletPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_monitorable(p_monitorable);
}
-void BulletPhysicsServer::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+void BulletPhysicsServer3D::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
-void BulletPhysicsServer::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+void BulletPhysicsServer3D::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
-void BulletPhysicsServer::area_set_ray_pickable(RID p_area, bool p_enable) {
+void BulletPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) {
AreaBullet *area = area_owner.getornull(p_area);
ERR_FAIL_COND(!area);
area->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer::area_is_ray_pickable(RID p_area) const {
+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 BulletPhysicsServer::body_create(BodyMode p_mode, bool p_init_sleeping) {
+RID BulletPhysicsServer3D::body_create(BodyMode p_mode, bool p_init_sleeping) {
RigidBodyBullet *body = bulletnew(RigidBodyBullet);
body->set_mode(p_mode);
body->set_collision_layer(1);
@@ -460,10 +460,10 @@ RID BulletPhysicsServer::body_create(BodyMode p_mode, bool p_init_sleeping) {
CreateThenReturnRID(rigid_body_owner, body);
}
-void BulletPhysicsServer::body_set_space(RID p_body, RID p_space) {
+void BulletPhysicsServer3D::body_set_space(RID p_body, RID p_space) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- SpaceBullet *space = NULL;
+ SpaceBullet *space = nullptr;
if (p_space.is_valid()) {
space = space_owner.getornull(p_space);
@@ -476,7 +476,7 @@ void BulletPhysicsServer::body_set_space(RID p_body, RID p_space) {
body->set_space(space);
}
-RID BulletPhysicsServer::body_get_space(RID p_body) const {
+RID BulletPhysicsServer3D::body_get_space(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, RID());
@@ -486,19 +486,19 @@ RID BulletPhysicsServer::body_get_space(RID p_body) const {
return space->get_self();
}
-void BulletPhysicsServer::body_set_mode(RID p_body, PhysicsServer::BodyMode p_mode) {
+void BulletPhysicsServer3D::body_set_mode(RID p_body, PhysicsServer3D::BodyMode p_mode) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_mode(p_mode);
}
-PhysicsServer::BodyMode BulletPhysicsServer::body_get_mode(RID p_body) const {
+PhysicsServer3D::BodyMode BulletPhysicsServer3D::body_get_mode(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
return body->get_mode();
}
-void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
+void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -509,7 +509,7 @@ void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transfor
body->add_shape(shape, p_transform, p_disabled);
}
-void BulletPhysicsServer::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
+void BulletPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -519,20 +519,20 @@ void BulletPhysicsServer::body_set_shape(RID p_body, int p_shape_idx, RID p_shap
body->set_shape(p_shape_idx, shape);
}
-void BulletPhysicsServer::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) {
+void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_shape_transform(p_shape_idx, p_transform);
}
-int BulletPhysicsServer::body_get_shape_count(RID p_body) const {
+int BulletPhysicsServer3D::body_get_shape_count(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_shape_count();
}
-RID BulletPhysicsServer::body_get_shape(RID p_body, int p_shape_idx) const {
+RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, RID());
@@ -542,113 +542,113 @@ RID BulletPhysicsServer::body_get_shape(RID p_body, int p_shape_idx) const {
return shape->get_self();
}
-Transform BulletPhysicsServer::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+Transform BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Transform());
return body->get_shape_transform(p_shape_idx);
}
-void BulletPhysicsServer::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
+void BulletPhysicsServer3D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_shape_disabled(p_shape_idx, p_disabled);
}
-void BulletPhysicsServer::body_remove_shape(RID p_body, int p_shape_idx) {
+void BulletPhysicsServer3D::body_remove_shape(RID p_body, int p_shape_idx) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->remove_shape_full(p_shape_idx);
}
-void BulletPhysicsServer::body_clear_shapes(RID p_body) {
+void BulletPhysicsServer3D::body_clear_shapes(RID p_body) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->remove_all_shapes();
}
-void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
+void BulletPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
CollisionObjectBullet *body = get_collisin_object(p_body);
ERR_FAIL_COND(!body);
body->set_instance_id(p_id);
}
-ObjectID BulletPhysicsServer::body_get_object_instance_id(RID p_body) const {
+ObjectID BulletPhysicsServer3D::body_get_object_instance_id(RID p_body) const {
CollisionObjectBullet *body = get_collisin_object(p_body);
ERR_FAIL_COND_V(!body, ObjectID());
return body->get_instance_id();
}
-void BulletPhysicsServer::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) {
+void BulletPhysicsServer3D::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_continuous_collision_detection(p_enable);
}
-bool BulletPhysicsServer::body_is_continuous_collision_detection_enabled(RID p_body) const {
+bool BulletPhysicsServer3D::body_is_continuous_collision_detection_enabled(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
return body->is_continuous_collision_detection_enabled();
}
-void BulletPhysicsServer::body_set_collision_layer(RID p_body, uint32_t p_layer) {
+void BulletPhysicsServer3D::body_set_collision_layer(RID p_body, uint32_t p_layer) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_collision_layer(p_layer);
}
-uint32_t BulletPhysicsServer::body_get_collision_layer(RID p_body) const {
+uint32_t BulletPhysicsServer3D::body_get_collision_layer(RID p_body) const {
const RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_layer();
}
-void BulletPhysicsServer::body_set_collision_mask(RID p_body, uint32_t p_mask) {
+void BulletPhysicsServer3D::body_set_collision_mask(RID p_body, uint32_t p_mask) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_collision_mask(p_mask);
}
-uint32_t BulletPhysicsServer::body_get_collision_mask(RID p_body) const {
+uint32_t BulletPhysicsServer3D::body_get_collision_mask(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_mask();
}
-void BulletPhysicsServer::body_set_user_flags(RID p_body, uint32_t p_flags) {
+void BulletPhysicsServer3D::body_set_user_flags(RID p_body, uint32_t p_flags) {
// This function si not currently supported
}
-uint32_t BulletPhysicsServer::body_get_user_flags(RID p_body) const {
+uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const {
// This function si not currently supported
return 0;
}
-void BulletPhysicsServer::body_set_param(RID p_body, BodyParameter p_param, float p_value) {
+void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, float p_value) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_param(p_param, p_value);
}
-float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) const {
+float BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_param(p_param);
}
-void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
+void BulletPhysicsServer3D::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -658,7 +658,7 @@ void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_ma
}
}
-real_t BulletPhysicsServer::body_get_kinematic_safe_margin(RID p_body) const {
+real_t BulletPhysicsServer3D::body_get_kinematic_safe_margin(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
@@ -670,90 +670,90 @@ real_t BulletPhysicsServer::body_get_kinematic_safe_margin(RID p_body) const {
return 0;
}
-void BulletPhysicsServer::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+void BulletPhysicsServer3D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_state(p_state, p_variant);
}
-Variant BulletPhysicsServer::body_get_state(RID p_body, BodyState p_state) const {
+Variant BulletPhysicsServer3D::body_get_state(RID p_body, BodyState p_state) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Variant());
return body->get_state(p_state);
}
-void BulletPhysicsServer::body_set_applied_force(RID p_body, const Vector3 &p_force) {
+void BulletPhysicsServer3D::body_set_applied_force(RID p_body, const Vector3 &p_force) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_applied_force(p_force);
}
-Vector3 BulletPhysicsServer::body_get_applied_force(RID p_body) const {
+Vector3 BulletPhysicsServer3D::body_get_applied_force(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Vector3());
return body->get_applied_force();
}
-void BulletPhysicsServer::body_set_applied_torque(RID p_body, const Vector3 &p_torque) {
+void BulletPhysicsServer3D::body_set_applied_torque(RID p_body, const Vector3 &p_torque) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_applied_torque(p_torque);
}
-Vector3 BulletPhysicsServer::body_get_applied_torque(RID p_body) const {
+Vector3 BulletPhysicsServer3D::body_get_applied_torque(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Vector3());
return body->get_applied_torque();
}
-void BulletPhysicsServer::body_add_central_force(RID p_body, const Vector3 &p_force) {
+void BulletPhysicsServer3D::body_add_central_force(RID p_body, const Vector3 &p_force) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->apply_central_force(p_force);
}
-void BulletPhysicsServer::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) {
+void BulletPhysicsServer3D::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->apply_force(p_force, p_pos);
}
-void BulletPhysicsServer::body_add_torque(RID p_body, const Vector3 &p_torque) {
+void BulletPhysicsServer3D::body_add_torque(RID p_body, const Vector3 &p_torque) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->apply_torque(p_torque);
}
-void BulletPhysicsServer::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) {
+void BulletPhysicsServer3D::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->apply_central_impulse(p_impulse);
}
-void BulletPhysicsServer::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) {
+void BulletPhysicsServer3D::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->apply_impulse(p_pos, p_impulse);
}
-void BulletPhysicsServer::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
+void BulletPhysicsServer3D::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->apply_torque_impulse(p_impulse);
}
-void BulletPhysicsServer::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) {
+void BulletPhysicsServer3D::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -764,19 +764,19 @@ void BulletPhysicsServer::body_set_axis_velocity(RID p_body, const Vector3 &p_ax
body->set_linear_velocity(v);
}
-void BulletPhysicsServer::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) {
+void BulletPhysicsServer3D::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_axis_lock(p_axis, p_lock);
}
-bool BulletPhysicsServer::body_is_axis_locked(RID p_body, BodyAxis p_axis) const {
+bool BulletPhysicsServer3D::body_is_axis_locked(RID p_body, BodyAxis p_axis) const {
const RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->is_axis_locked(p_axis);
}
-void BulletPhysicsServer::body_add_collision_exception(RID p_body, RID p_body_b) {
+void BulletPhysicsServer3D::body_add_collision_exception(RID p_body, RID p_body_b) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -786,7 +786,7 @@ void BulletPhysicsServer::body_add_collision_exception(RID p_body, RID p_body_b)
body->add_collision_exception(other_body);
}
-void BulletPhysicsServer::body_remove_collision_exception(RID p_body, RID p_body_b) {
+void BulletPhysicsServer3D::body_remove_collision_exception(RID p_body, RID p_body_b) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -796,7 +796,7 @@ void BulletPhysicsServer::body_remove_collision_exception(RID p_body, RID p_body
body->remove_collision_exception(other_body);
}
-void BulletPhysicsServer::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+void BulletPhysicsServer3D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
for (int i = 0; i < body->get_exceptions().size(); i++) {
@@ -804,68 +804,68 @@ void BulletPhysicsServer::body_get_collision_exceptions(RID p_body, List<RID> *p
}
}
-void BulletPhysicsServer::body_set_max_contacts_reported(RID p_body, int p_contacts) {
+void BulletPhysicsServer3D::body_set_max_contacts_reported(RID p_body, int p_contacts) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_max_collisions_detection(p_contacts);
}
-int BulletPhysicsServer::body_get_max_contacts_reported(RID p_body) const {
+int BulletPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_max_collisions_detection();
}
-void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) {
+void BulletPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) {
// Not supported by bullet and even Godot
}
-float BulletPhysicsServer::body_get_contacts_reported_depth_threshold(RID p_body) const {
+float BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const {
// Not supported by bullet and even Godot
return 0.;
}
-void BulletPhysicsServer::body_set_omit_force_integration(RID p_body, bool p_omit) {
+void BulletPhysicsServer3D::body_set_omit_force_integration(RID p_body, bool p_omit) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_omit_forces_integration(p_omit);
}
-bool BulletPhysicsServer::body_is_omitting_force_integration(RID p_body) const {
+bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
return body->get_omit_forces_integration();
}
-void BulletPhysicsServer::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, Object *p_receiver, const StringName &p_method, 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);
}
-void BulletPhysicsServer::body_set_ray_pickable(RID p_body, bool p_enable) {
+void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_ray_pickable(p_enable);
}
-bool BulletPhysicsServer::body_is_ray_pickable(RID p_body) const {
+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();
}
-PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) {
+PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_body) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, NULL);
- return BulletPhysicsDirectBodyState::get_singleton(body);
+ ERR_FAIL_COND_V(!body, nullptr);
+ return BulletPhysicsDirectBodyState3D::get_singleton(body);
}
-bool BulletPhysicsServer::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) {
+bool BulletPhysicsServer3D::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) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@@ -873,7 +873,7 @@ bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from,
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
}
-int BulletPhysicsServer::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, float p_margin) {
+int BulletPhysicsServer3D::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, float p_margin) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
ERR_FAIL_COND_V(!body->get_space(), 0);
@@ -881,7 +881,7 @@ int BulletPhysicsServer::body_test_ray_separation(RID p_body, const Transform &p
return body->get_space()->test_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
}
-RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) {
+RID BulletPhysicsServer3D::soft_body_create(bool p_init_sleeping) {
SoftBodyBullet *body = bulletnew(SoftBodyBullet);
body->set_collision_layer(1);
body->set_collision_mask(1);
@@ -890,17 +890,17 @@ RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) {
CreateThenReturnRID(soft_body_owner, body);
}
-void BulletPhysicsServer::soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) {
+void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->update_visual_server(p_visual_server_handler);
+ body->update_rendering_server(p_rendering_server_handler);
}
-void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) {
+void BulletPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- SpaceBullet *space = NULL;
+ SpaceBullet *space = nullptr;
if (p_space.is_valid()) {
space = space_owner.getornull(p_space);
@@ -913,7 +913,7 @@ void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) {
body->set_space(space);
}
-RID BulletPhysicsServer::soft_body_get_space(RID p_body) const {
+RID BulletPhysicsServer3D::soft_body_get_space(RID p_body) const {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, RID());
@@ -923,42 +923,42 @@ RID BulletPhysicsServer::soft_body_get_space(RID p_body) const {
return space->get_self();
}
-void BulletPhysicsServer::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
+void BulletPhysicsServer3D::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_soft_mesh(p_mesh);
}
-void BulletPhysicsServer::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
+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);
body->set_collision_layer(p_layer);
}
-uint32_t BulletPhysicsServer::soft_body_get_collision_layer(RID p_body) const {
+uint32_t BulletPhysicsServer3D::soft_body_get_collision_layer(RID p_body) const {
const SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_layer();
}
-void BulletPhysicsServer::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
+void BulletPhysicsServer3D::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_collision_mask(p_mask);
}
-uint32_t BulletPhysicsServer::soft_body_get_collision_mask(RID p_body) const {
+uint32_t BulletPhysicsServer3D::soft_body_get_collision_mask(RID p_body) const {
const SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_mask();
}
-void BulletPhysicsServer::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
+void BulletPhysicsServer3D::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -971,7 +971,7 @@ void BulletPhysicsServer::soft_body_add_collision_exception(RID p_body, RID p_bo
body->add_collision_exception(other_body);
}
-void BulletPhysicsServer::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
+void BulletPhysicsServer3D::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
@@ -984,7 +984,7 @@ void BulletPhysicsServer::soft_body_remove_collision_exception(RID p_body, RID p
body->remove_collision_exception(other_body);
}
-void BulletPhysicsServer::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+void BulletPhysicsServer3D::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
for (int i = 0; i < body->get_exceptions().size(); i++) {
@@ -992,25 +992,25 @@ void BulletPhysicsServer::soft_body_get_collision_exceptions(RID p_body, List<RI
}
}
-void BulletPhysicsServer::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+void BulletPhysicsServer3D::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
// FIXME: Must be implemented.
WARN_PRINT("soft_body_state is not implemented yet in Bullet backend.");
}
-Variant BulletPhysicsServer::soft_body_get_state(RID p_body, BodyState p_state) const {
+Variant BulletPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state) const {
// FIXME: Must be implemented.
WARN_PRINT("soft_body_state is not implemented yet in Bullet backend.");
return Variant();
}
-void BulletPhysicsServer::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform &p_transform) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_soft_transform(p_transform);
}
-Vector3 BulletPhysicsServer::soft_body_get_vertex_position(RID p_body, int vertex_index) const {
+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);
@@ -1019,133 +1019,133 @@ Vector3 BulletPhysicsServer::soft_body_get_vertex_position(RID p_body, int verte
return pos;
}
-void BulletPhysicsServer::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
+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 BulletPhysicsServer::soft_body_is_ray_pickable(RID p_body) const {
+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 BulletPhysicsServer::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
+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 BulletPhysicsServer::soft_body_get_simulation_precision(RID p_body) {
+int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_simulation_precision();
}
-void BulletPhysicsServer::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
+void BulletPhysicsServer3D::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_total_mass(p_total_mass);
}
-real_t BulletPhysicsServer::soft_body_get_total_mass(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_total_mass();
}
-void BulletPhysicsServer::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) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_linear_stiffness(p_stiffness);
}
-real_t BulletPhysicsServer::soft_body_get_linear_stiffness(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_linear_stiffness(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_linear_stiffness();
}
-void BulletPhysicsServer::soft_body_set_areaAngular_stiffness(RID p_body, real_t p_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 BulletPhysicsServer::soft_body_get_areaAngular_stiffness(RID p_body) {
+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 BulletPhysicsServer::soft_body_set_volume_stiffness(RID p_body, real_t p_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 BulletPhysicsServer::soft_body_get_volume_stiffness(RID p_body) {
+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 BulletPhysicsServer::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
+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 BulletPhysicsServer::soft_body_get_pressure_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_pressure_coefficient();
}
-void BulletPhysicsServer::soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_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 BulletPhysicsServer::soft_body_get_pose_matching_coefficient(RID p_body) {
+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 BulletPhysicsServer::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_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 BulletPhysicsServer::soft_body_get_damping_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_damping_coefficient();
}
-void BulletPhysicsServer::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
+void BulletPhysicsServer3D::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_drag_coefficient(p_drag_coefficient);
}
-real_t BulletPhysicsServer::soft_body_get_drag_coefficient(RID p_body) {
+real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_drag_coefficient();
}
-void BulletPhysicsServer::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
+void BulletPhysicsServer3D::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_node_position(p_point_index, p_global_position);
}
-Vector3 BulletPhysicsServer::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) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.));
Vector3 pos;
@@ -1153,7 +1153,7 @@ Vector3 BulletPhysicsServer::soft_body_get_point_global_position(RID p_body, int
return pos;
}
-Vector3 BulletPhysicsServer::soft_body_get_point_offset(RID p_body, int p_point_index) const {
+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;
@@ -1161,60 +1161,60 @@ Vector3 BulletPhysicsServer::soft_body_get_point_offset(RID p_body, int p_point_
return res;
}
-void BulletPhysicsServer::soft_body_remove_all_pinned_points(RID p_body) {
+void BulletPhysicsServer3D::soft_body_remove_all_pinned_points(RID p_body) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->reset_all_node_mass();
}
-void BulletPhysicsServer::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
+void BulletPhysicsServer3D::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
body->set_node_mass(p_point_index, p_pin ? 0 : 1);
}
-bool BulletPhysicsServer::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) {
SoftBodyBullet *body = soft_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_node_mass(p_point_index);
}
-PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const {
+PhysicsServer3D::JointType BulletPhysicsServer3D::joint_get_type(RID p_joint) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, JOINT_PIN);
return joint->get_type();
}
-void BulletPhysicsServer::joint_set_solver_priority(RID p_joint, int p_priority) {
+void BulletPhysicsServer3D::joint_set_solver_priority(RID p_joint, int p_priority) {
// Joint priority not supported by bullet
}
-int BulletPhysicsServer::joint_get_solver_priority(RID p_joint) const {
+int BulletPhysicsServer3D::joint_get_solver_priority(RID p_joint) const {
// Joint priority not supported by bullet
return 0;
}
-void BulletPhysicsServer::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
+void BulletPhysicsServer3D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
joint->disable_collisions_between_bodies(p_disable);
}
-bool BulletPhysicsServer::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
+bool BulletPhysicsServer3D::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
JointBullet *joint(joint_owner.getornull(p_joint));
ERR_FAIL_COND_V(!joint, false);
return joint->is_disabled_collisions_between_bodies();
}
-RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
+RID BulletPhysicsServer3D::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
- RigidBodyBullet *body_B = NULL;
+ RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
body_B = rigid_body_owner.getornull(p_body_B);
JointAssertSpace(body_B, "B", RID());
@@ -1229,7 +1229,7 @@ RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer::pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
@@ -1237,7 +1237,7 @@ void BulletPhysicsServer::pin_joint_set_param(RID p_joint, PinJointParam p_param
pin_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
+float BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0);
@@ -1245,7 +1245,7 @@ float BulletPhysicsServer::pin_joint_get_param(RID p_joint, PinJointParam p_para
return pin_joint->get_param(p_param);
}
-void BulletPhysicsServer::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
+void BulletPhysicsServer3D::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
@@ -1253,7 +1253,7 @@ void BulletPhysicsServer::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A)
pin_joint->setPivotInA(p_A);
}
-Vector3 BulletPhysicsServer::pin_joint_get_local_a(RID p_joint) const {
+Vector3 BulletPhysicsServer3D::pin_joint_get_local_a(RID p_joint) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, Vector3());
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
@@ -1261,7 +1261,7 @@ Vector3 BulletPhysicsServer::pin_joint_get_local_a(RID p_joint) const {
return pin_joint->getPivotInA();
}
-void BulletPhysicsServer::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
+void BulletPhysicsServer3D::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
@@ -1269,7 +1269,7 @@ void BulletPhysicsServer::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B)
pin_joint->setPivotInB(p_B);
}
-Vector3 BulletPhysicsServer::pin_joint_get_local_b(RID p_joint) const {
+Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, Vector3());
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
@@ -1277,12 +1277,12 @@ Vector3 BulletPhysicsServer::pin_joint_get_local_b(RID p_joint) const {
return pin_joint->getPivotInB();
}
-RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) {
+RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) {
RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
- RigidBodyBullet *body_B = NULL;
+ RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
body_B = rigid_body_owner.getornull(p_body_B);
JointAssertSpace(body_B, "B", RID());
@@ -1297,12 +1297,12 @@ RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hin
CreateThenReturnRID(joint_owner, joint);
}
-RID BulletPhysicsServer::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) {
+RID BulletPhysicsServer3D::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) {
RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
- RigidBodyBullet *body_B = NULL;
+ RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
body_B = rigid_body_owner.getornull(p_body_B);
JointAssertSpace(body_B, "B", RID());
@@ -1317,7 +1317,7 @@ RID BulletPhysicsServer::joint_create_hinge_simple(RID p_body_A, const Vector3 &
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
@@ -1325,7 +1325,7 @@ void BulletPhysicsServer::hinge_joint_set_param(RID p_joint, HingeJointParam p_p
hinge_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
+float BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0);
@@ -1333,7 +1333,7 @@ float BulletPhysicsServer::hinge_joint_get_param(RID p_joint, HingeJointParam p_
return hinge_joint->get_param(p_param);
}
-void BulletPhysicsServer::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) {
+void BulletPhysicsServer3D::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
@@ -1341,7 +1341,7 @@ void BulletPhysicsServer::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_fla
hinge_joint->set_flag(p_flag, p_value);
}
-bool BulletPhysicsServer::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const {
+bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, false);
ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false);
@@ -1349,12 +1349,12 @@ bool BulletPhysicsServer::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_fla
return hinge_joint->get_flag(p_flag);
}
-RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
- RigidBodyBullet *body_B = NULL;
+ RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
body_B = rigid_body_owner.getornull(p_body_B);
JointAssertSpace(body_B, "B", RID());
@@ -1369,7 +1369,7 @@ RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_lo
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer::slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER);
@@ -1377,7 +1377,7 @@ void BulletPhysicsServer::slider_joint_set_param(RID p_joint, SliderJointParam p
slider_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
+float BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0);
@@ -1385,12 +1385,12 @@ float BulletPhysicsServer::slider_joint_get_param(RID p_joint, SliderJointParam
return slider_joint->get_param(p_param);
}
-RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
- RigidBodyBullet *body_B = NULL;
+ RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
body_B = rigid_body_owner.getornull(p_body_B);
JointAssertSpace(body_B, "B", RID());
@@ -1403,7 +1403,7 @@ RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform &
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) {
+void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST);
@@ -1411,7 +1411,7 @@ void BulletPhysicsServer::cone_twist_joint_set_param(RID p_joint, ConeTwistJoint
coneTwist_joint->set_param(p_param, p_value);
}
-float BulletPhysicsServer::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
+float BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0.);
ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.);
@@ -1419,12 +1419,12 @@ float BulletPhysicsServer::cone_twist_joint_get_param(RID p_joint, ConeTwistJoin
return coneTwist_joint->get_param(p_param);
}
-RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
- RigidBodyBullet *body_B = NULL;
+ RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
body_B = rigid_body_owner.getornull(p_body_B);
JointAssertSpace(body_B, "B", RID());
@@ -1439,7 +1439,7 @@ RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform
CreateThenReturnRID(joint_owner, joint);
}
-void BulletPhysicsServer::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) {
+void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
@@ -1447,7 +1447,7 @@ void BulletPhysicsServer::generic_6dof_joint_set_param(RID p_joint, Vector3::Axi
generic_6dof_joint->set_param(p_axis, p_param, p_value);
}
-float BulletPhysicsServer::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
+float BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
@@ -1455,7 +1455,7 @@ float BulletPhysicsServer::generic_6dof_joint_get_param(RID p_joint, Vector3::Ax
return generic_6dof_joint->get_param(p_axis, p_param);
}
-void BulletPhysicsServer::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) {
+void BulletPhysicsServer3D::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
@@ -1463,7 +1463,7 @@ void BulletPhysicsServer::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis
generic_6dof_joint->set_flag(p_axis, p_flag, p_enable);
}
-bool BulletPhysicsServer::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) {
+bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, false);
ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false);
@@ -1471,7 +1471,7 @@ bool BulletPhysicsServer::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis
return generic_6dof_joint->get_flag(p_axis, p_flag);
}
-void BulletPhysicsServer::generic_6dof_joint_set_precision(RID p_joint, int p_precision) {
+void BulletPhysicsServer3D::generic_6dof_joint_set_precision(RID p_joint, int p_precision) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
@@ -1479,7 +1479,7 @@ void BulletPhysicsServer::generic_6dof_joint_set_precision(RID p_joint, int p_pr
generic_6dof_joint->set_precision(p_precision);
}
-int BulletPhysicsServer::generic_6dof_joint_get_precision(RID p_joint) {
+int BulletPhysicsServer3D::generic_6dof_joint_get_precision(RID p_joint) {
JointBullet *joint = joint_owner.getornull(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
@@ -1487,7 +1487,7 @@ int BulletPhysicsServer::generic_6dof_joint_get_precision(RID p_joint) {
return generic_6dof_joint->get_precision();
}
-void BulletPhysicsServer::free(RID p_rid) {
+void BulletPhysicsServer3D::free(RID p_rid) {
if (shape_owner.owns(p_rid)) {
ShapeBullet *shape = shape_owner.getornull(p_rid);
@@ -1503,7 +1503,7 @@ void BulletPhysicsServer::free(RID p_rid) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_rid);
- body->set_space(NULL);
+ body->set_space(nullptr);
body->remove_all_shapes(true, true);
@@ -1514,7 +1514,7 @@ void BulletPhysicsServer::free(RID p_rid) {
SoftBodyBullet *body = soft_body_owner.getornull(p_rid);
- body->set_space(NULL);
+ body->set_space(nullptr);
soft_body_owner.free(p_rid);
bulletdelete(body);
@@ -1523,7 +1523,7 @@ void BulletPhysicsServer::free(RID p_rid) {
AreaBullet *area = area_owner.getornull(p_rid);
- area->set_space(NULL);
+ area->set_space(nullptr);
area->remove_all_shapes(true, true);
@@ -1552,15 +1552,15 @@ void BulletPhysicsServer::free(RID p_rid) {
}
}
-void BulletPhysicsServer::init() {
- BulletPhysicsDirectBodyState::initSingleton();
+void BulletPhysicsServer3D::init() {
+ BulletPhysicsDirectBodyState3D::initSingleton();
}
-void BulletPhysicsServer::step(float p_deltaTime) {
+void BulletPhysicsServer3D::step(float p_deltaTime) {
if (!active)
return;
- BulletPhysicsDirectBodyState::singleton_setDeltaTime(p_deltaTime);
+ BulletPhysicsDirectBodyState3D::singleton_setDeltaTime(p_deltaTime);
for (int i = 0; i < active_spaces_count; ++i) {
@@ -1568,21 +1568,21 @@ void BulletPhysicsServer::step(float p_deltaTime) {
}
}
-void BulletPhysicsServer::sync() {
+void BulletPhysicsServer3D::sync() {
}
-void BulletPhysicsServer::flush_queries() {
+void BulletPhysicsServer3D::flush_queries() {
}
-void BulletPhysicsServer::finish() {
- BulletPhysicsDirectBodyState::destroySingleton();
+void BulletPhysicsServer3D::finish() {
+ BulletPhysicsDirectBodyState3D::destroySingleton();
}
-int BulletPhysicsServer::get_process_info(ProcessInfo p_info) {
+int BulletPhysicsServer3D::get_process_info(ProcessInfo p_info) {
return 0;
}
-CollisionObjectBullet *BulletPhysicsServer::get_collisin_object(RID p_object) const {
+CollisionObjectBullet *BulletPhysicsServer3D::get_collisin_object(RID p_object) const {
if (rigid_body_owner.owns(p_object)) {
return rigid_body_owner.getornull(p_object);
}
@@ -1592,15 +1592,15 @@ CollisionObjectBullet *BulletPhysicsServer::get_collisin_object(RID p_object) co
if (soft_body_owner.owns(p_object)) {
return soft_body_owner.getornull(p_object);
}
- return NULL;
+ return nullptr;
}
-RigidCollisionObjectBullet *BulletPhysicsServer::get_rigid_collisin_object(RID p_object) const {
+RigidCollisionObjectBullet *BulletPhysicsServer3D::get_rigid_collisin_object(RID p_object) const {
if (rigid_body_owner.owns(p_object)) {
return rigid_body_owner.getornull(p_object);
}
if (area_owner.owns(p_object)) {
return area_owner.getornull(p_object);
}
- return NULL;
+ return nullptr;
}
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 6ea9a7a974..ea9c5e589e 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -36,7 +36,7 @@
#include "core/rid_owner.h"
#include "joint_bullet.h"
#include "rigid_body_bullet.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#include "shape_bullet.h"
#include "soft_body_bullet.h"
#include "space_bullet.h"
@@ -44,8 +44,8 @@
@author AndreaCatania
*/
-class BulletPhysicsServer : public PhysicsServer {
- GDCLASS(BulletPhysicsServer, PhysicsServer);
+class BulletPhysicsServer3D : public PhysicsServer3D {
+ GDCLASS(BulletPhysicsServer3D, PhysicsServer3D);
friend class BulletPhysicsDirectSpaceState;
@@ -64,8 +64,8 @@ protected:
static void _bind_methods();
public:
- BulletPhysicsServer();
- ~BulletPhysicsServer();
+ BulletPhysicsServer3D();
+ ~BulletPhysicsServer3D();
_FORCE_INLINE_ RID_PtrOwner<SpaceBullet> *get_space_owner() {
return &space_owner;
@@ -111,7 +111,7 @@ public:
/// Not supported
virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const;
- virtual PhysicsDirectSpaceState *space_get_direct_state(RID p_space);
+ virtual PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space);
virtual void space_set_debug_contacts(RID p_space, int p_max_contacts);
virtual Vector<Vector3> space_get_contacts(RID p_space) const;
@@ -252,16 +252,16 @@ public:
virtual bool body_is_ray_pickable(RID p_body) const;
// this function only works on physics process, errors and returns null otherwise
- virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body);
+ virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body);
- virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true);
+ 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);
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, float p_margin = 0.001);
/* SOFT BODY API */
virtual RID soft_body_create(bool p_init_sleeping = false);
- virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler);
+ virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler);
virtual void soft_body_set_space(RID p_body, RID p_space);
virtual RID soft_body_get_space(RID p_body) const;
@@ -387,7 +387,7 @@ public:
}
static bool singleton_isActive() {
- return static_cast<BulletPhysicsServer *>(get_singleton())->active;
+ return static_cast<BulletPhysicsServer3D *>(get_singleton())->active;
}
bool isActive() {
diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h
index 968cb38ba2..a5e33d9829 100644
--- a/modules/bullet/bullet_utilities.h
+++ b/modules/bullet/bullet_utilities.h
@@ -41,6 +41,6 @@
#define bulletdelete(cl) \
{ \
delete cl; \
- cl = NULL; \
+ cl = nullptr; \
}
#endif
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index 5b7e7281e4..1b72c2f577 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -60,7 +60,7 @@ void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_tra
}
btTransform CollisionObjectBullet::ShapeWrapper::get_adjusted_transform() const {
- if (shape->get_type() == PhysicsServer::SHAPE_HEIGHTMAP) {
+ if (shape->get_type() == PhysicsServer3D::SHAPE_HEIGHTMAP) {
const HeightMapShapeBullet *hm_shape = (const HeightMapShapeBullet *)shape; // should be safe to cast now
btTransform adjusted_transform;
@@ -96,10 +96,10 @@ CollisionObjectBullet::CollisionObjectBullet(Type p_type) :
collisionsEnabled(true),
m_isStatic(false),
ray_pickable(false),
- bt_collision_object(NULL),
+ bt_collision_object(nullptr),
body_scale(1., 1., 1.),
force_shape_reset(false),
- space(NULL),
+ space(nullptr),
isTransformChanged(false) {}
CollisionObjectBullet::~CollisionObjectBullet() {
@@ -227,7 +227,7 @@ void CollisionObjectBullet::notify_transform_changed() {
RigidCollisionObjectBullet::RigidCollisionObjectBullet(Type p_type) :
CollisionObjectBullet(p_type),
- mainShape(NULL) {
+ mainShape(nullptr) {
}
RigidCollisionObjectBullet::~RigidCollisionObjectBullet() {
@@ -332,7 +332,7 @@ bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) {
void RigidCollisionObjectBullet::shape_changed(int p_shape_index) {
ShapeWrapper &shp = shapes.write[p_shape_index];
if (shp.bt_shape == mainShape) {
- mainShape = NULL;
+ mainShape = nullptr;
}
bulletdelete(shp.bt_shape);
reload_shapes();
@@ -345,7 +345,7 @@ void RigidCollisionObjectBullet::reload_shapes() {
bulletdelete(mainShape);
}
- mainShape = NULL;
+ mainShape = nullptr;
ShapeWrapper *shpWrapper;
const int shape_count = shapes.size();
@@ -398,7 +398,7 @@ void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_perm
ShapeWrapper &shp = shapes.write[p_index];
shp.shape->remove_owner(this, p_permanentlyFromThisBody);
if (shp.bt_shape == mainShape) {
- mainShape = NULL;
+ mainShape = nullptr;
}
bulletdelete(shp.bt_shape);
}
diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h
index 42ba4aa907..25176458a7 100644
--- a/modules/bullet/collision_object_bullet.h
+++ b/modules/bullet/collision_object_bullet.h
@@ -76,20 +76,20 @@ public:
bool active;
ShapeWrapper() :
- shape(NULL),
- bt_shape(NULL),
+ shape(nullptr),
+ bt_shape(nullptr),
active(true) {}
ShapeWrapper(ShapeBullet *p_shape, const btTransform &p_transform, bool p_active) :
shape(p_shape),
- bt_shape(NULL),
+ bt_shape(nullptr),
active(p_active) {
set_transform(p_transform);
}
ShapeWrapper(ShapeBullet *p_shape, const Transform &p_transform, bool p_active) :
shape(p_shape),
- bt_shape(NULL),
+ bt_shape(nullptr),
active(p_active) {
set_transform(p_transform);
}
diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp
index 23eb39fe7e..aac51034b8 100644
--- a/modules/bullet/cone_twist_joint_bullet.cpp
+++ b/modules/bullet/cone_twist_joint_bullet.cpp
@@ -64,43 +64,43 @@ ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet
setup(coneConstraint);
}
-void ConeTwistJointBullet::set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value) {
+void ConeTwistJointBullet::set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value) {
switch (p_param) {
- case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN:
+ case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN:
coneConstraint->setLimit(5, p_value);
coneConstraint->setLimit(4, p_value);
break;
- case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN:
+ case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN:
coneConstraint->setLimit(3, p_value);
break;
- case PhysicsServer::CONE_TWIST_JOINT_BIAS:
+ case PhysicsServer3D::CONE_TWIST_JOINT_BIAS:
coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), p_value, coneConstraint->getRelaxationFactor());
break;
- case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS:
+ case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS:
coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), p_value, coneConstraint->getBiasFactor(), coneConstraint->getRelaxationFactor());
break;
- case PhysicsServer::CONE_TWIST_JOINT_RELAXATION:
+ case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION:
coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), coneConstraint->getBiasFactor(), p_value);
break;
- case PhysicsServer::CONE_TWIST_MAX:
+ case PhysicsServer3D::CONE_TWIST_MAX:
// Internal size value, nothing to do.
break;
}
}
-real_t ConeTwistJointBullet::get_param(PhysicsServer::ConeTwistJointParam p_param) const {
+real_t ConeTwistJointBullet::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const {
switch (p_param) {
- case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN:
+ case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN:
return coneConstraint->getSwingSpan1();
- case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN:
+ case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN:
return coneConstraint->getTwistSpan();
- case PhysicsServer::CONE_TWIST_JOINT_BIAS:
+ case PhysicsServer3D::CONE_TWIST_JOINT_BIAS:
return coneConstraint->getBiasFactor();
- case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS:
+ case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS:
return coneConstraint->getLimitSoftness();
- case PhysicsServer::CONE_TWIST_JOINT_RELAXATION:
+ case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION:
return coneConstraint->getRelaxationFactor();
- case PhysicsServer::CONE_TWIST_MAX:
+ case PhysicsServer3D::CONE_TWIST_MAX:
// Internal size value, nothing to do.
return 0;
}
diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h
index 134706f8bb..ed4baa9d1b 100644
--- a/modules/bullet/cone_twist_joint_bullet.h
+++ b/modules/bullet/cone_twist_joint_bullet.h
@@ -45,9 +45,9 @@ class ConeTwistJointBullet : public JointBullet {
public:
ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; }
- void set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::ConeTwistJointParam p_param) const;
+ void set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::ConeTwistJointParam p_param) const;
};
#endif
diff --git a/modules/bullet/config.py b/modules/bullet/config.py
index 92dbcf5cb0..e8ca273f61 100644
--- a/modules/bullet/config.py
+++ b/modules/bullet/config.py
@@ -1,14 +1,17 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
- "BulletPhysicsDirectBodyState",
- "BulletPhysicsServer",
+ "BulletPhysicsDirectBodyState3D",
+ "BulletPhysicsServer3D",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp
index 7e90e2b488..469b58521e 100644
--- a/modules/bullet/constraint_bullet.cpp
+++ b/modules/bullet/constraint_bullet.cpp
@@ -38,8 +38,8 @@
*/
ConstraintBullet::ConstraintBullet() :
- space(NULL),
- constraint(NULL),
+ space(nullptr),
+ constraint(nullptr),
disabled_collisions_between_bodies(true) {}
void ConstraintBullet::setup(btTypedConstraint *p_constraint) {
diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h
index 89ad150257..1946807bad 100644
--- a/modules/bullet/constraint_bullet.h
+++ b/modules/bullet/constraint_bullet.h
@@ -64,7 +64,7 @@ public:
public:
virtual ~ConstraintBullet() {
bulletdelete(constraint);
- constraint = NULL;
+ constraint = nullptr;
}
_FORCE_INLINE_ btTypedConstraint *get_bt_constraint() { return constraint; }
diff --git a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
deleted file mode 100644
index 5ea1b810a1..0000000000
--- a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState3D.xml b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState3D.xml
new file mode 100644
index 0000000000..1c0181bd9c
--- /dev/null
+++ b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState3D.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="BulletPhysicsDirectBodyState3D" inherits="PhysicsDirectBodyState3D" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/bullet/doc_classes/BulletPhysicsServer.xml b/modules/bullet/doc_classes/BulletPhysicsServer.xml
deleted file mode 100644
index af8fb3c02c..0000000000
--- a/modules/bullet/doc_classes/BulletPhysicsServer.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BulletPhysicsServer" inherits="PhysicsServer" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/modules/bullet/doc_classes/BulletPhysicsServer3D.xml b/modules/bullet/doc_classes/BulletPhysicsServer3D.xml
new file mode 100644
index 0000000000..b20595b4f6
--- /dev/null
+++ b/modules/bullet/doc_classes/BulletPhysicsServer3D.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="BulletPhysicsServer3D" inherits="PhysicsServer3D" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index 45ab3d3bb2..638944df76 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -43,6 +43,12 @@
Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) :
JointBullet() {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < PhysicsServer3D::G6DOF_JOINT_FLAG_MAX; j++) {
+ flags[i][j] = false;
+ }
+ }
+
Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale()));
scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis);
@@ -118,62 +124,62 @@ void Generic6DOFJointBullet::set_angular_upper_limit(const Vector3 &angularUpper
sixDOFConstraint->setAngularUpperLimit(btVec);
}
-void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value) {
+void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value) {
ERR_FAIL_INDEX(p_axis, 3);
switch (p_param) {
- case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
limits_lower[0][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter
+ set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter
break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
limits_upper[0][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter
+ set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter
break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY:
sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis] = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis] = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING:
sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis] = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS:
sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis] = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT:
sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis] = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
limits_lower[1][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
+ set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
limits_upper[1][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
+ set_flag(p_axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_MAX:
+ case PhysicsServer3D::G6DOF_JOINT_MAX:
// Internal size value, nothing to do.
break;
default:
@@ -182,42 +188,42 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
}
}
-real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const {
+real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const {
ERR_FAIL_INDEX_V(p_axis, 3, 0.);
switch (p_param) {
- case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
return limits_lower[0][p_axis];
- case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
return limits_upper[0][p_axis];
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY:
return sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis];
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
return sixDOFConstraint->getTranslationalLimitMotor()->m_maxMotorForce.m_floats[p_axis];
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING:
return sixDOFConstraint->getTranslationalLimitMotor()->m_springDamping.m_floats[p_axis];
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS:
return sixDOFConstraint->getTranslationalLimitMotor()->m_springStiffness.m_floats[p_axis];
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT:
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT:
return sixDOFConstraint->getTranslationalLimitMotor()->m_equilibriumPoint.m_floats[p_axis];
- case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
return limits_lower[1][p_axis];
- case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
return limits_upper[1][p_axis];
- case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springStiffness;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_springDamping;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT:
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT:
return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_equilibriumPoint;
- case PhysicsServer::G6DOF_JOINT_MAX:
+ case PhysicsServer3D::G6DOF_JOINT_MAX:
// Internal size value, nothing to do.
return 0;
default:
@@ -226,45 +232,45 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6
}
}
-void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value) {
+void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value) {
ERR_FAIL_INDEX(p_axis, 3);
flags[p_axis][p_flag] = p_value;
switch (p_flag) {
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT:
if (flags[p_axis][p_flag]) {
sixDOFConstraint->setLimit(p_axis, limits_lower[0][p_axis], limits_upper[0][p_axis]);
} else {
sixDOFConstraint->setLimit(p_axis, 0, -1); // Free
}
break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT:
if (flags[p_axis][p_flag]) {
sixDOFConstraint->setLimit(p_axis + 3, limits_lower[1][p_axis], limits_upper[1][p_axis]);
} else {
sixDOFConstraint->setLimit(p_axis + 3, 0, -1); // Free
}
break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableSpring = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING:
sixDOFConstraint->getTranslationalLimitMotor()->m_enableSpring[p_axis] = p_value;
break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor = flags[p_axis][p_flag];
break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR:
sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = flags[p_axis][p_flag];
break;
- case PhysicsServer::G6DOF_JOINT_FLAG_MAX:
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX:
// Internal size value, nothing to do.
break;
}
}
-bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const {
+bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const {
ERR_FAIL_INDEX_V(p_axis, 3, false);
return flags[p_axis][p_flag];
}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index 75c8005811..316708bb11 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -45,12 +45,12 @@ class Generic6DOFJointBullet : public JointBullet {
// First is linear second is angular
Vector3 limits_lower[2];
Vector3 limits_upper[2];
- bool flags[3][PhysicsServer::G6DOF_JOINT_FLAG_MAX];
+ bool flags[3][PhysicsServer3D::G6DOF_JOINT_FLAG_MAX];
public:
Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB);
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; }
Transform getFrameOffsetA() const;
Transform getFrameOffsetB() const;
@@ -63,11 +63,11 @@ public:
void set_angular_lower_limit(const Vector3 &angularLower);
void set_angular_upper_limit(const Vector3 &angularUpper);
- void set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value);
- real_t get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const;
+ void set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value);
+ real_t get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const;
- void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value);
- bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const;
+ void set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value);
+ bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const;
void set_precision(int p_precision);
int get_precision() const;
diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp
index f3e3a01a52..8e29845a36 100644
--- a/modules/bullet/godot_collision_configuration.cpp
+++ b/modules/bullet/godot_collision_configuration.cpp
@@ -42,7 +42,7 @@
GodotCollisionConfiguration::GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) :
btDefaultCollisionConfiguration(constructionInfo) {
- void *mem = NULL;
+ void *mem = nullptr;
mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16);
m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world);
@@ -98,7 +98,7 @@ btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getClosestPointsAlg
GodotSoftCollisionConfiguration::GodotSoftCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo) :
btSoftBodyRigidBodyCollisionConfiguration(constructionInfo) {
- void *mem = NULL;
+ void *mem = nullptr;
mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16);
m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world);
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 20467e3ef3..ad20a7e451 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -107,12 +107,12 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer());
- PhysicsDirectSpaceState::ShapeResult &result = m_results[count];
+ 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.rid = gObj->get_self();
result.collider_id = gObj->get_instance_id();
- result.collider = result.collider_id.is_null() ? NULL : ObjectDB::get_instance(result.collider_id);
+ result.collider = result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(result.collider_id);
++count;
return 1; // not used by bullet
@@ -207,7 +207,7 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con
if (cp.getDistance() <= 0) {
- PhysicsDirectSpaceState::ShapeResult &result = m_results[m_count];
+ PhysicsDirectSpaceState3D::ShapeResult &result = m_results[m_count];
// Penetrated
CollisionObjectBullet *colObj;
@@ -220,7 +220,7 @@ btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, con
}
result.collider_id = colObj->get_instance_id();
- result.collider = result.collider_id.is_null() ? NULL : ObjectDB::get_instance(result.collider_id);
+ result.collider = result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(result.collider_id);
result.rid = colObj->get_self();
++m_count;
}
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index 4f634ed6f0..7e74a2b22e 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -31,7 +31,7 @@
#ifndef GODOT_RESULT_CALLBACKS_H
#define GODOT_RESULT_CALLBACKS_H
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h>
#include <btBulletDynamicsCommon.h>
@@ -85,12 +85,12 @@ public:
// store all colliding object
struct GodotAllConvexResultCallback : public btCollisionWorld::ConvexResultCallback {
public:
- PhysicsDirectSpaceState::ShapeResult *m_results;
+ PhysicsDirectSpaceState3D::ShapeResult *m_results;
int m_resultMax;
const Set<RID> *m_exclude;
int count;
- GodotAllConvexResultCallback(PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) :
+ GodotAllConvexResultCallback(PhysicsDirectSpaceState3D::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude) :
m_results(p_results),
m_resultMax(p_resultMax),
m_exclude(p_exclude),
@@ -137,7 +137,7 @@ public:
struct GodotAllContactResultCallback : public btCollisionWorld::ContactResultCallback {
public:
const btCollisionObject *m_self_object;
- PhysicsDirectSpaceState::ShapeResult *m_results;
+ PhysicsDirectSpaceState3D::ShapeResult *m_results;
int m_resultMax;
const Set<RID> *m_exclude;
int m_count;
@@ -145,7 +145,7 @@ public:
bool collide_with_bodies;
bool collide_with_areas;
- GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
+ GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState3D::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
m_self_object(p_self_object),
m_results(p_results),
m_resultMax(p_resultMax),
@@ -188,7 +188,7 @@ public:
struct GodotRestInfoContactResultCallback : public btCollisionWorld::ContactResultCallback {
public:
const btCollisionObject *m_self_object;
- PhysicsDirectSpaceState::ShapeRestInfo *m_result;
+ PhysicsDirectSpaceState3D::ShapeRestInfo *m_result;
const Set<RID> *m_exclude;
bool m_collided;
real_t m_min_distance;
@@ -197,7 +197,7 @@ public:
bool collide_with_bodies;
bool collide_with_areas;
- GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
+ GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState3D::ShapeRestInfo *p_result, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
m_self_object(p_self_object),
m_result(p_result),
m_exclude(p_exclude),
diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp
index 970732688a..4bea9f87c0 100644
--- a/modules/bullet/hinge_joint_bullet.cpp
+++ b/modules/bullet/hinge_joint_bullet.cpp
@@ -93,58 +93,58 @@ real_t HingeJointBullet::get_hinge_angle() {
return hingeConstraint->getHingeAngle();
}
-void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) {
+void HingeJointBullet::set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value) {
switch (p_param) {
- case PhysicsServer::HINGE_JOINT_BIAS:
- WARN_DEPRECATED_MSG("The HingeJoint parameter \"bias\" is deprecated.");
+ case PhysicsServer3D::HINGE_JOINT_BIAS:
+ WARN_DEPRECATED_MSG("The HingeJoint3D parameter \"bias\" is deprecated.");
break;
- case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER:
hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), p_value, hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor());
break;
- case PhysicsServer::HINGE_JOINT_LIMIT_LOWER:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER:
hingeConstraint->setLimit(p_value, hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor());
break;
- case PhysicsServer::HINGE_JOINT_LIMIT_BIAS:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS:
hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), p_value, hingeConstraint->getLimitRelaxationFactor());
break;
- case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS:
hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), p_value, hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor());
break;
- case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION:
hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), p_value);
break;
- case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
hingeConstraint->setMotorTargetVelocity(p_value);
break;
- case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE:
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE:
hingeConstraint->setMaxMotorImpulse(p_value);
break;
- case PhysicsServer::HINGE_JOINT_MAX:
+ case PhysicsServer3D::HINGE_JOINT_MAX:
// Internal size value, nothing to do.
break;
}
}
-real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const {
+real_t HingeJointBullet::get_param(PhysicsServer3D::HingeJointParam p_param) const {
switch (p_param) {
- case PhysicsServer::HINGE_JOINT_BIAS:
- WARN_DEPRECATED_MSG("The HingeJoint parameter \"bias\" is deprecated.");
+ case PhysicsServer3D::HINGE_JOINT_BIAS:
+ WARN_DEPRECATED_MSG("The HingeJoint3D parameter \"bias\" is deprecated.");
return 0;
- case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER:
return hingeConstraint->getUpperLimit();
- case PhysicsServer::HINGE_JOINT_LIMIT_LOWER:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER:
return hingeConstraint->getLowerLimit();
- case PhysicsServer::HINGE_JOINT_LIMIT_BIAS:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS:
return hingeConstraint->getLimitBiasFactor();
- case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS:
return hingeConstraint->getLimitSoftness();
- case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION:
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION:
return hingeConstraint->getLimitRelaxationFactor();
- case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
return hingeConstraint->getMotorTargetVelocity();
- case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE:
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE:
return hingeConstraint->getMaxMotorImpulse();
- case PhysicsServer::HINGE_JOINT_MAX:
+ case PhysicsServer3D::HINGE_JOINT_MAX:
// Internal size value, nothing to do.
return 0;
}
@@ -152,25 +152,25 @@ real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const
return 0;
}
-void HingeJointBullet::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value) {
+void HingeJointBullet::set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value) {
switch (p_flag) {
- case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
+ case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT:
if (!p_value) {
hingeConstraint->setLimit(-Math_PI, Math_PI);
}
break;
- case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:
+ case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR:
hingeConstraint->enableMotor(p_value);
break;
- case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
+ case PhysicsServer3D::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
}
}
-bool HingeJointBullet::get_flag(PhysicsServer::HingeJointFlag p_flag) const {
+bool HingeJointBullet::get_flag(PhysicsServer3D::HingeJointFlag p_flag) const {
switch (p_flag) {
- case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
+ case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT:
return true;
- case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:
+ case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR:
return hingeConstraint->getEnableAngularMotor();
default:
return false;
diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h
index d1061fe52f..120c40e5c0 100644
--- a/modules/bullet/hinge_joint_bullet.h
+++ b/modules/bullet/hinge_joint_bullet.h
@@ -44,14 +44,14 @@ public:
HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB);
HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_HINGE; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; }
real_t get_hinge_angle();
- void set_param(PhysicsServer::HingeJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::HingeJointParam p_param) const;
+ void set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::HingeJointParam p_param) const;
- void set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value);
- bool get_flag(PhysicsServer::HingeJointFlag p_flag) const;
+ void set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value);
+ bool get_flag(PhysicsServer3D::HingeJointFlag p_flag) const;
};
#endif
diff --git a/modules/bullet/joint_bullet.h b/modules/bullet/joint_bullet.h
index c840eb8f14..9cb8aab276 100644
--- a/modules/bullet/joint_bullet.h
+++ b/modules/bullet/joint_bullet.h
@@ -32,7 +32,7 @@
#define JOINT_BULLET_H
#include "constraint_bullet.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
/**
@author AndreaCatania
@@ -47,6 +47,6 @@ public:
JointBullet();
virtual ~JointBullet();
- virtual PhysicsServer::JointType get_type() const = 0;
+ virtual PhysicsServer3D::JointType get_type() const = 0;
};
#endif
diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp
index 8d109f1866..68b40d7405 100644
--- a/modules/bullet/pin_joint_bullet.cpp
+++ b/modules/bullet/pin_joint_bullet.cpp
@@ -62,27 +62,27 @@ PinJointBullet::PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a
PinJointBullet::~PinJointBullet() {}
-void PinJointBullet::set_param(PhysicsServer::PinJointParam p_param, real_t p_value) {
+void PinJointBullet::set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value) {
switch (p_param) {
- case PhysicsServer::PIN_JOINT_BIAS:
+ case PhysicsServer3D::PIN_JOINT_BIAS:
p2pConstraint->m_setting.m_tau = p_value;
break;
- case PhysicsServer::PIN_JOINT_DAMPING:
+ case PhysicsServer3D::PIN_JOINT_DAMPING:
p2pConstraint->m_setting.m_damping = p_value;
break;
- case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP:
+ case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP:
p2pConstraint->m_setting.m_impulseClamp = p_value;
break;
}
}
-real_t PinJointBullet::get_param(PhysicsServer::PinJointParam p_param) const {
+real_t PinJointBullet::get_param(PhysicsServer3D::PinJointParam p_param) const {
switch (p_param) {
- case PhysicsServer::PIN_JOINT_BIAS:
+ case PhysicsServer3D::PIN_JOINT_BIAS:
return p2pConstraint->m_setting.m_tau;
- case PhysicsServer::PIN_JOINT_DAMPING:
+ case PhysicsServer3D::PIN_JOINT_DAMPING:
return p2pConstraint->m_setting.m_damping;
- case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP:
+ case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP:
return p2pConstraint->m_setting.m_impulseClamp;
}
// Compiler doesn't seem to notice that all code paths are fulfilled...
diff --git a/modules/bullet/pin_joint_bullet.h b/modules/bullet/pin_joint_bullet.h
index d6e7a945b5..e7d05f34d4 100644
--- a/modules/bullet/pin_joint_bullet.h
+++ b/modules/bullet/pin_joint_bullet.h
@@ -46,10 +46,10 @@ public:
PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b);
~PinJointBullet();
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_PIN; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_PIN; }
- void set_param(PhysicsServer::PinJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::PinJointParam p_param) const;
+ void set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::PinJointParam p_param) const;
void setPivotInA(const Vector3 &p_pos);
void setPivotInB(const Vector3 &p_pos);
diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp
index 7819b67cad..009d0dff63 100644
--- a/modules/bullet/register_types.cpp
+++ b/modules/bullet/register_types.cpp
@@ -39,15 +39,15 @@
*/
#ifndef _3D_DISABLED
-PhysicsServer *_createBulletPhysicsCallback() {
- return memnew(BulletPhysicsServer);
+PhysicsServer3D *_createBulletPhysicsCallback() {
+ return memnew(BulletPhysicsServer3D);
}
#endif
void register_bullet_types() {
#ifndef _3D_DISABLED
- PhysicsServerManager::register_server("Bullet", &_createBulletPhysicsCallback);
- PhysicsServerManager::set_default_server("Bullet", 1);
+ PhysicsServer3DManager::register_server("Bullet", &_createBulletPhysicsCallback);
+ PhysicsServer3DManager::set_default_server("Bullet", 1);
GLOBAL_DEF("physics/3d/active_soft_world", true);
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/active_soft_world", PropertyInfo(Variant::BOOL, "physics/3d/active_soft_world"));
diff --git a/modules/bullet/rid_bullet.h b/modules/bullet/rid_bullet.h
index b76641ca54..3551ca05f9 100644
--- a/modules/bullet/rid_bullet.h
+++ b/modules/bullet/rid_bullet.h
@@ -37,17 +37,17 @@
@author AndreaCatania
*/
-class BulletPhysicsServer;
+class BulletPhysicsServer3D;
class RIDBullet {
RID self;
- BulletPhysicsServer *physicsServer;
+ BulletPhysicsServer3D *physicsServer;
public:
_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
_FORCE_INLINE_ RID get_self() const { return self; }
- _FORCE_INLINE_ void _set_physics_server(BulletPhysicsServer *p_physicsServer) { physicsServer = p_physicsServer; }
- _FORCE_INLINE_ BulletPhysicsServer *get_physics_server() const { return physicsServer; }
+ _FORCE_INLINE_ void _set_physics_server(BulletPhysicsServer3D *p_physicsServer) { physicsServer = p_physicsServer; }
+ _FORCE_INLINE_ BulletPhysicsServer3D *get_physics_server() const { return physicsServer; }
};
#endif
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 80f42c8441..a4f9affa95 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -48,141 +48,141 @@
@author AndreaCatania
*/
-BulletPhysicsDirectBodyState *BulletPhysicsDirectBodyState::singleton = NULL;
+BulletPhysicsDirectBodyState3D *BulletPhysicsDirectBodyState3D::singleton = nullptr;
-Vector3 BulletPhysicsDirectBodyState::get_total_gravity() const {
+Vector3 BulletPhysicsDirectBodyState3D::get_total_gravity() const {
Vector3 gVec;
B_TO_G(body->btBody->getGravity(), gVec);
return gVec;
}
-float BulletPhysicsDirectBodyState::get_total_angular_damp() const {
+float BulletPhysicsDirectBodyState3D::get_total_angular_damp() const {
return body->btBody->getAngularDamping();
}
-float BulletPhysicsDirectBodyState::get_total_linear_damp() const {
+float BulletPhysicsDirectBodyState3D::get_total_linear_damp() const {
return body->btBody->getLinearDamping();
}
-Vector3 BulletPhysicsDirectBodyState::get_center_of_mass() const {
+Vector3 BulletPhysicsDirectBodyState3D::get_center_of_mass() const {
Vector3 gVec;
B_TO_G(body->btBody->getCenterOfMassPosition(), gVec);
return gVec;
}
-Basis BulletPhysicsDirectBodyState::get_principal_inertia_axes() const {
+Basis BulletPhysicsDirectBodyState3D::get_principal_inertia_axes() const {
return Basis();
}
-float BulletPhysicsDirectBodyState::get_inverse_mass() const {
+float BulletPhysicsDirectBodyState3D::get_inverse_mass() const {
return body->btBody->getInvMass();
}
-Vector3 BulletPhysicsDirectBodyState::get_inverse_inertia() const {
+Vector3 BulletPhysicsDirectBodyState3D::get_inverse_inertia() const {
Vector3 gVec;
B_TO_G(body->btBody->getInvInertiaDiagLocal(), gVec);
return gVec;
}
-Basis BulletPhysicsDirectBodyState::get_inverse_inertia_tensor() const {
+Basis BulletPhysicsDirectBodyState3D::get_inverse_inertia_tensor() const {
Basis gInertia;
B_TO_G(body->btBody->getInvInertiaTensorWorld(), gInertia);
return gInertia;
}
-void BulletPhysicsDirectBodyState::set_linear_velocity(const Vector3 &p_velocity) {
+void BulletPhysicsDirectBodyState3D::set_linear_velocity(const Vector3 &p_velocity) {
body->set_linear_velocity(p_velocity);
}
-Vector3 BulletPhysicsDirectBodyState::get_linear_velocity() const {
+Vector3 BulletPhysicsDirectBodyState3D::get_linear_velocity() const {
return body->get_linear_velocity();
}
-void BulletPhysicsDirectBodyState::set_angular_velocity(const Vector3 &p_velocity) {
+void BulletPhysicsDirectBodyState3D::set_angular_velocity(const Vector3 &p_velocity) {
body->set_angular_velocity(p_velocity);
}
-Vector3 BulletPhysicsDirectBodyState::get_angular_velocity() const {
+Vector3 BulletPhysicsDirectBodyState3D::get_angular_velocity() const {
return body->get_angular_velocity();
}
-void BulletPhysicsDirectBodyState::set_transform(const Transform &p_transform) {
+void BulletPhysicsDirectBodyState3D::set_transform(const Transform &p_transform) {
body->set_transform(p_transform);
}
-Transform BulletPhysicsDirectBodyState::get_transform() const {
+Transform BulletPhysicsDirectBodyState3D::get_transform() const {
return body->get_transform();
}
-void BulletPhysicsDirectBodyState::add_central_force(const Vector3 &p_force) {
+void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) {
body->apply_central_force(p_force);
}
-void BulletPhysicsDirectBodyState::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
+void BulletPhysicsDirectBodyState3D::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
body->apply_force(p_force, p_pos);
}
-void BulletPhysicsDirectBodyState::add_torque(const Vector3 &p_torque) {
+void BulletPhysicsDirectBodyState3D::add_torque(const Vector3 &p_torque) {
body->apply_torque(p_torque);
}
-void BulletPhysicsDirectBodyState::apply_central_impulse(const Vector3 &p_impulse) {
+void BulletPhysicsDirectBodyState3D::apply_central_impulse(const Vector3 &p_impulse) {
body->apply_central_impulse(p_impulse);
}
-void BulletPhysicsDirectBodyState::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
+void BulletPhysicsDirectBodyState3D::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
body->apply_impulse(p_pos, p_impulse);
}
-void BulletPhysicsDirectBodyState::apply_torque_impulse(const Vector3 &p_impulse) {
+void BulletPhysicsDirectBodyState3D::apply_torque_impulse(const Vector3 &p_impulse) {
body->apply_torque_impulse(p_impulse);
}
-void BulletPhysicsDirectBodyState::set_sleep_state(bool p_enable) {
- body->set_activation_state(p_enable);
+void BulletPhysicsDirectBodyState3D::set_sleep_state(bool p_sleep) {
+ body->set_activation_state(!p_sleep);
}
-bool BulletPhysicsDirectBodyState::is_sleeping() const {
+bool BulletPhysicsDirectBodyState3D::is_sleeping() const {
return !body->is_active();
}
-int BulletPhysicsDirectBodyState::get_contact_count() const {
+int BulletPhysicsDirectBodyState3D::get_contact_count() const {
return body->collisionsCount;
}
-Vector3 BulletPhysicsDirectBodyState::get_contact_local_position(int p_contact_idx) const {
+Vector3 BulletPhysicsDirectBodyState3D::get_contact_local_position(int p_contact_idx) const {
return body->collisions[p_contact_idx].hitLocalLocation;
}
-Vector3 BulletPhysicsDirectBodyState::get_contact_local_normal(int p_contact_idx) const {
+Vector3 BulletPhysicsDirectBodyState3D::get_contact_local_normal(int p_contact_idx) const {
return body->collisions[p_contact_idx].hitNormal;
}
-float BulletPhysicsDirectBodyState::get_contact_impulse(int p_contact_idx) const {
+float BulletPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const {
return body->collisions[p_contact_idx].appliedImpulse;
}
-int BulletPhysicsDirectBodyState::get_contact_local_shape(int p_contact_idx) const {
+int BulletPhysicsDirectBodyState3D::get_contact_local_shape(int p_contact_idx) const {
return body->collisions[p_contact_idx].local_shape;
}
-RID BulletPhysicsDirectBodyState::get_contact_collider(int p_contact_idx) const {
+RID BulletPhysicsDirectBodyState3D::get_contact_collider(int p_contact_idx) const {
return body->collisions[p_contact_idx].otherObject->get_self();
}
-Vector3 BulletPhysicsDirectBodyState::get_contact_collider_position(int p_contact_idx) const {
+Vector3 BulletPhysicsDirectBodyState3D::get_contact_collider_position(int p_contact_idx) const {
return body->collisions[p_contact_idx].hitWorldLocation;
}
-ObjectID BulletPhysicsDirectBodyState::get_contact_collider_id(int p_contact_idx) const {
+ObjectID BulletPhysicsDirectBodyState3D::get_contact_collider_id(int p_contact_idx) const {
return body->collisions[p_contact_idx].otherObject->get_instance_id();
}
-int BulletPhysicsDirectBodyState::get_contact_collider_shape(int p_contact_idx) const {
+int BulletPhysicsDirectBodyState3D::get_contact_collider_shape(int p_contact_idx) const {
return body->collisions[p_contact_idx].other_object_shape;
}
-Vector3 BulletPhysicsDirectBodyState::get_contact_collider_velocity_at_position(int p_contact_idx) const {
+Vector3 BulletPhysicsDirectBodyState3D::get_contact_collider_velocity_at_position(int p_contact_idx) const {
RigidBodyBullet::CollisionData &colDat = body->collisions.write[p_contact_idx];
btVector3 hitLocation;
@@ -194,7 +194,7 @@ Vector3 BulletPhysicsDirectBodyState::get_contact_collider_velocity_at_position(
return velocityAtPoint;
}
-PhysicsDirectSpaceState *BulletPhysicsDirectBodyState::get_space_state() {
+PhysicsDirectSpaceState3D *BulletPhysicsDirectBodyState3D::get_space_state() {
return body->get_space()->get_direct_state();
}
@@ -231,17 +231,17 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() {
shapes.write[i].transform = shape_wrapper->transform;
shapes.write[i].transform.getOrigin() *= owner_scale;
switch (shape_wrapper->shape->get_type()) {
- case PhysicsServer::SHAPE_SPHERE:
- case PhysicsServer::SHAPE_BOX:
- case PhysicsServer::SHAPE_CAPSULE:
- case PhysicsServer::SHAPE_CYLINDER:
- case PhysicsServer::SHAPE_CONVEX_POLYGON:
- case PhysicsServer::SHAPE_RAY: {
+ case PhysicsServer3D::SHAPE_SPHERE:
+ case PhysicsServer3D::SHAPE_BOX:
+ case PhysicsServer3D::SHAPE_CAPSULE:
+ case PhysicsServer3D::SHAPE_CYLINDER:
+ case PhysicsServer3D::SHAPE_CONVEX_POLYGON:
+ case PhysicsServer3D::SHAPE_RAY: {
shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin));
} break;
default:
WARN_PRINT("This shape is not supported for kinematic collision.");
- shapes.write[i].shape = NULL;
+ shapes.write[i].shape = nullptr;
}
}
}
@@ -257,7 +257,7 @@ void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) {
RigidBodyBullet::RigidBodyBullet() :
RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_RIGID_BODY),
- kinematic_utilities(NULL),
+ kinematic_utilities(nullptr),
locked_axis(0),
mass(1),
gravity_scale(1),
@@ -274,24 +274,24 @@ RigidBodyBullet::RigidBodyBullet() :
countGravityPointSpaces(0),
isScratchedSpaceOverrideModificator(false),
previousActiveState(true),
- force_integration_callback(NULL) {
+ force_integration_callback(nullptr) {
godotMotionState = bulletnew(GodotMotionState(this));
// Initial properties
const btVector3 localInertia(0, 0, 0);
- btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, NULL, localInertia);
+ btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, nullptr, localInertia);
btBody = bulletnew(btRigidBody(cInfo));
reload_shapes();
setupBulletCollisionObject(btBody);
- set_mode(PhysicsServer::BODY_MODE_RIGID);
+ set_mode(PhysicsServer3D::BODY_MODE_RIGID);
reload_axis_lock();
areasWhereIam.resize(maxAreasWhereIam);
for (int i = areasWhereIam.size() - 1; 0 <= i; --i) {
- areasWhereIam.write[i] = NULL;
+ areasWhereIam.write[i] = nullptr;
}
btBody->setSleepingThresholds(0.2, 0.2);
@@ -315,7 +315,7 @@ void RigidBodyBullet::init_kinematic_utilities() {
void RigidBodyBullet::destroy_kinematic_utilities() {
if (kinematic_utilities) {
memdelete(kinematic_utilities);
- kinematic_utilities = NULL;
+ kinematic_utilities = nullptr;
}
}
@@ -359,7 +359,7 @@ void RigidBodyBullet::dispatch_callbacks() {
if (omit_forces_integration)
btBody->clearForces();
- BulletPhysicsDirectBodyState *bodyDirect = BulletPhysicsDirectBodyState::get_singleton(this);
+ BulletPhysicsDirectBodyState3D *bodyDirect = BulletPhysicsDirectBodyState3D::get_singleton(this);
Variant variantBodyDirect = bodyDirect;
@@ -392,7 +392,7 @@ void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const String
if (force_integration_callback) {
memdelete(force_integration_callback);
- force_integration_callback = NULL;
+ force_integration_callback = nullptr;
}
if (p_id.is_valid()) {
@@ -487,29 +487,29 @@ void RigidBodyBullet::set_omit_forces_integration(bool p_omit) {
omit_forces_integration = p_omit;
}
-void RigidBodyBullet::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) {
+void RigidBodyBullet::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) {
switch (p_param) {
- case PhysicsServer::BODY_PARAM_BOUNCE:
+ case PhysicsServer3D::BODY_PARAM_BOUNCE:
btBody->setRestitution(p_value);
break;
- case PhysicsServer::BODY_PARAM_FRICTION:
+ case PhysicsServer3D::BODY_PARAM_FRICTION:
btBody->setFriction(p_value);
break;
- case PhysicsServer::BODY_PARAM_MASS: {
+ case PhysicsServer3D::BODY_PARAM_MASS: {
ERR_FAIL_COND(p_value < 0);
mass = p_value;
_internal_set_mass(p_value);
break;
}
- case PhysicsServer::BODY_PARAM_LINEAR_DAMP:
+ case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP:
linearDamp = p_value;
btBody->setDamping(linearDamp, angularDamp);
break;
- case PhysicsServer::BODY_PARAM_ANGULAR_DAMP:
+ case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP:
angularDamp = p_value;
btBody->setDamping(linearDamp, angularDamp);
break;
- case PhysicsServer::BODY_PARAM_GRAVITY_SCALE:
+ case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE:
gravity_scale = p_value;
/// The Bullet gravity will be is set by reload_space_override_modificator
scratch_space_override_modificator();
@@ -519,21 +519,21 @@ void RigidBodyBullet::set_param(PhysicsServer::BodyParameter p_param, real_t p_v
}
}
-real_t RigidBodyBullet::get_param(PhysicsServer::BodyParameter p_param) const {
+real_t RigidBodyBullet::get_param(PhysicsServer3D::BodyParameter p_param) const {
switch (p_param) {
- case PhysicsServer::BODY_PARAM_BOUNCE:
+ case PhysicsServer3D::BODY_PARAM_BOUNCE:
return btBody->getRestitution();
- case PhysicsServer::BODY_PARAM_FRICTION:
+ case PhysicsServer3D::BODY_PARAM_FRICTION:
return btBody->getFriction();
- case PhysicsServer::BODY_PARAM_MASS: {
+ case PhysicsServer3D::BODY_PARAM_MASS: {
const btScalar invMass = btBody->getInvMass();
return 0 == invMass ? 0 : 1 / invMass;
}
- case PhysicsServer::BODY_PARAM_LINEAR_DAMP:
+ case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP:
return linearDamp;
- case PhysicsServer::BODY_PARAM_ANGULAR_DAMP:
+ case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP:
return angularDamp;
- case PhysicsServer::BODY_PARAM_GRAVITY_SCALE:
+ case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE:
return gravity_scale;
default:
WARN_PRINT("Parameter " + itos(p_param) + " not supported by bullet");
@@ -541,31 +541,31 @@ real_t RigidBodyBullet::get_param(PhysicsServer::BodyParameter p_param) const {
}
}
-void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) {
+void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) {
// This is necessary to block force_integration untile next move
can_integrate_forces = false;
destroy_kinematic_utilities();
// The mode change is relevant to its mass
switch (p_mode) {
- case PhysicsServer::BODY_MODE_KINEMATIC:
- mode = PhysicsServer::BODY_MODE_KINEMATIC;
+ case PhysicsServer3D::BODY_MODE_KINEMATIC:
+ mode = PhysicsServer3D::BODY_MODE_KINEMATIC;
reload_axis_lock();
_internal_set_mass(0);
init_kinematic_utilities();
break;
- case PhysicsServer::BODY_MODE_STATIC:
- mode = PhysicsServer::BODY_MODE_STATIC;
+ case PhysicsServer3D::BODY_MODE_STATIC:
+ mode = PhysicsServer3D::BODY_MODE_STATIC;
reload_axis_lock();
_internal_set_mass(0);
break;
- case PhysicsServer::BODY_MODE_RIGID:
- mode = PhysicsServer::BODY_MODE_RIGID;
+ case PhysicsServer3D::BODY_MODE_RIGID:
+ mode = PhysicsServer3D::BODY_MODE_RIGID;
reload_axis_lock();
_internal_set_mass(0 == mass ? 1 : mass);
scratch_space_override_modificator();
break;
- case PhysicsServer::BODY_MODE_CHARACTER:
- mode = PhysicsServer::BODY_MODE_CHARACTER;
+ case PhysicsServer3D::BODY_MODE_CHARACTER:
+ mode = PhysicsServer3D::BODY_MODE_CHARACTER;
reload_axis_lock();
_internal_set_mass(0 == mass ? 1 : mass);
scratch_space_override_modificator();
@@ -575,26 +575,26 @@ void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) {
btBody->setAngularVelocity(btVector3(0, 0, 0));
btBody->setLinearVelocity(btVector3(0, 0, 0));
}
-PhysicsServer::BodyMode RigidBodyBullet::get_mode() const {
+PhysicsServer3D::BodyMode RigidBodyBullet::get_mode() const {
return mode;
}
-void RigidBodyBullet::set_state(PhysicsServer::BodyState p_state, const Variant &p_variant) {
+void RigidBodyBullet::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
switch (p_state) {
- case PhysicsServer::BODY_STATE_TRANSFORM:
+ case PhysicsServer3D::BODY_STATE_TRANSFORM:
set_transform(p_variant);
break;
- case PhysicsServer::BODY_STATE_LINEAR_VELOCITY:
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY:
set_linear_velocity(p_variant);
break;
- case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY:
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY:
set_angular_velocity(p_variant);
break;
- case PhysicsServer::BODY_STATE_SLEEPING:
+ case PhysicsServer3D::BODY_STATE_SLEEPING:
set_activation_state(!bool(p_variant));
break;
- case PhysicsServer::BODY_STATE_CAN_SLEEP:
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP:
can_sleep = bool(p_variant);
if (!can_sleep) {
// Can't sleep
@@ -606,17 +606,17 @@ void RigidBodyBullet::set_state(PhysicsServer::BodyState p_state, const Variant
}
}
-Variant RigidBodyBullet::get_state(PhysicsServer::BodyState p_state) const {
+Variant RigidBodyBullet::get_state(PhysicsServer3D::BodyState p_state) const {
switch (p_state) {
- case PhysicsServer::BODY_STATE_TRANSFORM:
+ case PhysicsServer3D::BODY_STATE_TRANSFORM:
return get_transform();
- case PhysicsServer::BODY_STATE_LINEAR_VELOCITY:
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY:
return get_linear_velocity();
- case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY:
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY:
return get_angular_velocity();
- case PhysicsServer::BODY_STATE_SLEEPING:
+ case PhysicsServer3D::BODY_STATE_SLEEPING:
return !is_active();
- case PhysicsServer::BODY_STATE_CAN_SLEEP:
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP:
return can_sleep;
default:
WARN_PRINT("This state " + itos(p_state) + " is not supported by Bullet");
@@ -714,7 +714,7 @@ Vector3 RigidBodyBullet::get_applied_torque() const {
return gTotTorq;
}
-void RigidBodyBullet::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
+void RigidBodyBullet::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) {
if (lock) {
locked_axis |= p_axis;
} else {
@@ -724,18 +724,18 @@ void RigidBodyBullet::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
reload_axis_lock();
}
-bool RigidBodyBullet::is_axis_locked(PhysicsServer::BodyAxis p_axis) const {
+bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
return locked_axis & p_axis;
}
void RigidBodyBullet::reload_axis_lock() {
- btBody->setLinearFactor(btVector3(float(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_X)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_Y)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_Z))));
- if (PhysicsServer::BODY_MODE_CHARACTER == mode) {
+ btBody->setLinearFactor(btVector3(float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z))));
+ if (PhysicsServer3D::BODY_MODE_CHARACTER == mode) {
/// When character angular is always locked
btBody->setAngularFactor(btVector3(0., 0., 0.));
} else {
- btBody->setAngularFactor(btVector3(float(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_X)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_Y)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_Z))));
+ btBody->setAngularFactor(btVector3(float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z))));
}
}
@@ -794,7 +794,7 @@ Vector3 RigidBodyBullet::get_angular_velocity() const {
}
void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) {
- if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
+ if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
if (space && space->get_delta_time() != 0)
btBody->setLinearVelocity((p_global_transform.getOrigin() - btBody->getWorldTransform().getOrigin()) / space->get_delta_time());
// The kinematic use MotionState class
@@ -847,7 +847,7 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) {
}
for (int i = 0; i < areaWhereIamCount; ++i) {
- if (NULL == areasWhereIam[i]) {
+ if (nullptr == areasWhereIam[i]) {
// This area has the highest priority
areasWhereIam.write[i] = p_area;
break;
@@ -862,7 +862,7 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) {
}
}
}
- if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) {
+ if (PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) {
scratch_space_override_modificator();
}
@@ -894,8 +894,8 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
}
--areaWhereIamCount;
- areasWhereIam.write[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe
- if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) {
+ areasWhereIam.write[areaWhereIamCount] = nullptr; // Even if this is not required, I clear the last element to be safe
+ if (PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) {
scratch_space_override_modificator();
}
}
@@ -904,7 +904,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
void RigidBodyBullet::reload_space_override_modificator() {
// Make sure that kinematic bodies have their total gravity calculated
- if (!is_active() && PhysicsServer::BODY_MODE_KINEMATIC != mode)
+ if (!is_active() && PhysicsServer3D::BODY_MODE_KINEMATIC != mode)
return;
Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude());
@@ -920,7 +920,7 @@ void RigidBodyBullet::reload_space_override_modificator() {
currentArea = areasWhereIam[i];
- if (!currentArea || PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) {
+ if (!currentArea || PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) {
continue;
}
@@ -954,11 +954,11 @@ void RigidBodyBullet::reload_space_override_modificator() {
}
switch (currentArea->get_spOv_mode()) {
- case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED:
/// This area does not affect gravity/damp. These are generally areas
/// that exist only to detect collisions, and objects entering or exiting them.
break;
- case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
/// This area adds its gravity/damp values to whatever has been
/// calculated so far. This way, many overlapping areas can combine
/// their physics to make interesting
@@ -967,7 +967,7 @@ void RigidBodyBullet::reload_space_override_modificator() {
newAngularDamp += currentArea->get_spOv_angularDamp();
++countCombined;
break;
- case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE:
/// This area adds its gravity/damp values to whatever has been calculated
/// so far. Then stops taking into account the rest of the areas, even the
/// default one.
@@ -976,7 +976,7 @@ void RigidBodyBullet::reload_space_override_modificator() {
newAngularDamp += currentArea->get_spOv_angularDamp();
++countCombined;
goto endAreasCycle;
- case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
/// This area replaces any gravity/damp, even the default one, and
/// stops taking into account the rest of the areas.
newGravity = support_gravity;
@@ -984,7 +984,7 @@ void RigidBodyBullet::reload_space_override_modificator() {
newAngularDamp = currentArea->get_spOv_angularDamp();
countCombined = 1;
goto endAreasCycle;
- case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE:
/// This area replaces any gravity/damp calculated so far, but keeps
/// calculating the rest of the areas, down to the default one.
newGravity = support_gravity;
@@ -1032,14 +1032,14 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
const bool isDynamic = p_mass != 0.f;
if (isDynamic) {
- if (PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode)
+ if (PhysicsServer3D::BODY_MODE_RIGID != mode && PhysicsServer3D::BODY_MODE_CHARACTER != mode)
return;
m_isStatic = false;
if (mainShape)
mainShape->calculateLocalInertia(p_mass, localInertia);
- if (PhysicsServer::BODY_MODE_RIGID == mode) {
+ if (PhysicsServer3D::BODY_MODE_RIGID == mode) {
btBody->setCollisionFlags(clearedCurrentFlags); // Just set the flags without Kin and Static
} else {
@@ -1054,11 +1054,11 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
}
} else {
- if (PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode)
+ if (PhysicsServer3D::BODY_MODE_STATIC != mode && PhysicsServer3D::BODY_MODE_KINEMATIC != mode)
return;
m_isStatic = true;
- if (PhysicsServer::BODY_MODE_STATIC == mode) {
+ if (PhysicsServer3D::BODY_MODE_STATIC == mode) {
btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_STATIC_OBJECT);
} else {
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index ca599f7a77..420b5cc443 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -45,37 +45,37 @@ class AreaBullet;
class SpaceBullet;
class btRigidBody;
class GodotMotionState;
-class BulletPhysicsDirectBodyState;
+class BulletPhysicsDirectBodyState3D;
/// This class could be used in multi thread with few changes but currently
/// is set to be only in one single thread.
///
/// In the system there is only one object at a time that manage all bodies and is
-/// created by BulletPhysicsServer and is held by the "singleton" variable of this class
+/// created by BulletPhysicsServer3D and is held by the "singleton" variable of this class
/// Each time something require it, the body must be set again.
-class BulletPhysicsDirectBodyState : public PhysicsDirectBodyState {
- GDCLASS(BulletPhysicsDirectBodyState, PhysicsDirectBodyState);
+class BulletPhysicsDirectBodyState3D : public PhysicsDirectBodyState3D {
+ GDCLASS(BulletPhysicsDirectBodyState3D, PhysicsDirectBodyState3D);
- static BulletPhysicsDirectBodyState *singleton;
+ static BulletPhysicsDirectBodyState3D *singleton;
public:
/// This class avoid the creation of more object of this class
static void initSingleton() {
if (!singleton) {
- singleton = memnew(BulletPhysicsDirectBodyState);
+ singleton = memnew(BulletPhysicsDirectBodyState3D);
}
}
static void destroySingleton() {
memdelete(singleton);
- singleton = NULL;
+ singleton = nullptr;
}
static void singleton_setDeltaTime(real_t p_deltaTime) {
singleton->deltaTime = p_deltaTime;
}
- static BulletPhysicsDirectBodyState *get_singleton(RigidBodyBullet *p_body) {
+ static BulletPhysicsDirectBodyState3D *get_singleton(RigidBodyBullet *p_body) {
singleton->body = p_body;
return singleton;
}
@@ -85,7 +85,7 @@ public:
real_t deltaTime;
private:
- BulletPhysicsDirectBodyState() {}
+ BulletPhysicsDirectBodyState3D() {}
public:
virtual Vector3 get_total_gravity() const;
@@ -117,7 +117,7 @@ public:
virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
virtual void apply_torque_impulse(const Vector3 &p_impulse);
- virtual void set_sleep_state(bool p_enable);
+ virtual void set_sleep_state(bool p_sleep);
virtual bool is_sleeping() const;
virtual int get_contact_count() const;
@@ -138,7 +138,7 @@ public:
// Skip the execution of this function
}
- virtual PhysicsDirectSpaceState *get_space_state();
+ virtual PhysicsDirectSpaceState3D *get_space_state();
};
class RigidBodyBullet : public RigidCollisionObjectBullet {
@@ -166,7 +166,7 @@ public:
btTransform transform;
KinematicShape() :
- shape(NULL) {}
+ shape(nullptr) {}
bool is_active() const { return shape; }
};
@@ -187,12 +187,12 @@ public:
};
private:
- friend class BulletPhysicsDirectBodyState;
+ friend class BulletPhysicsDirectBodyState3D;
// This is required only for Kinematic movement
KinematicUtilities *kinematic_utilities;
- PhysicsServer::BodyMode mode;
+ PhysicsServer3D::BodyMode mode;
GodotMotionState *godotMotionState;
btRigidBody *btBody;
uint16_t locked_axis;
@@ -278,14 +278,14 @@ public:
void set_omit_forces_integration(bool p_omit);
_FORCE_INLINE_ bool get_omit_forces_integration() const { return omit_forces_integration; }
- void set_param(PhysicsServer::BodyParameter p_param, real_t);
- real_t get_param(PhysicsServer::BodyParameter p_param) const;
+ void set_param(PhysicsServer3D::BodyParameter p_param, real_t);
+ real_t get_param(PhysicsServer3D::BodyParameter p_param) const;
- void set_mode(PhysicsServer::BodyMode p_mode);
- PhysicsServer::BodyMode get_mode() const;
+ void set_mode(PhysicsServer3D::BodyMode p_mode);
+ PhysicsServer3D::BodyMode get_mode() const;
- void set_state(PhysicsServer::BodyState p_state, const Variant &p_variant);
- Variant get_state(PhysicsServer::BodyState p_state) const;
+ void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer3D::BodyState p_state) const;
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
void apply_central_impulse(const Vector3 &p_impulse);
@@ -300,8 +300,8 @@ public:
void set_applied_torque(const Vector3 &p_torque);
Vector3 get_applied_torque() const;
- void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock);
- bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const;
+ void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock);
+ bool is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const;
void reload_axis_lock();
/// Doc:
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 6780f89d9e..8ac26a0fdb 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -138,7 +138,7 @@ btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMes
if (p_mesh_shape) {
return bulletnew(btScaledBvhTriangleMeshShape(p_mesh_shape, p_local_scaling));
} else {
- return NULL;
+ return nullptr;
}
}
@@ -150,7 +150,7 @@ btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<real_t>
btHeightfieldTerrainShape *heightfield = bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, p_min_height, p_max_height, YAxis, PHY_FLOAT, flipQuadEdges));
- // The shape can be created without params when you do PhysicsServer.shape_create(PhysicsServer.SHAPE_HEIGHTMAP)
+ // The shape can be created without params when you do PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_HEIGHTMAP)
if (heightsPtr)
heightfield->buildAccelerator(16);
@@ -176,8 +176,8 @@ Variant PlaneShapeBullet::get_data() const {
return plane;
}
-PhysicsServer::ShapeType PlaneShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_PLANE;
+PhysicsServer3D::ShapeType PlaneShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_PLANE;
}
void PlaneShapeBullet::setup(const Plane &p_plane) {
@@ -204,8 +204,8 @@ Variant SphereShapeBullet::get_data() const {
return radius;
}
-PhysicsServer::ShapeType SphereShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_SPHERE;
+PhysicsServer3D::ShapeType SphereShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_SPHERE;
}
void SphereShapeBullet::setup(real_t p_radius) {
@@ -231,8 +231,8 @@ Variant BoxShapeBullet::get_data() const {
return g_half_extents;
}
-PhysicsServer::ShapeType BoxShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_BOX;
+PhysicsServer3D::ShapeType BoxShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_BOX;
}
void BoxShapeBullet::setup(const Vector3 &p_half_extents) {
@@ -263,8 +263,8 @@ Variant CapsuleShapeBullet::get_data() const {
return d;
}
-PhysicsServer::ShapeType CapsuleShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_CAPSULE;
+PhysicsServer3D::ShapeType CapsuleShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_CAPSULE;
}
void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) {
@@ -296,8 +296,8 @@ Variant CylinderShapeBullet::get_data() const {
return d;
}
-PhysicsServer::ShapeType CylinderShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_CYLINDER;
+PhysicsServer3D::ShapeType CylinderShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_CYLINDER;
}
void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) {
@@ -334,8 +334,8 @@ Variant ConvexPolygonShapeBullet::get_data() const {
return out_vertices;
}
-PhysicsServer::ShapeType ConvexPolygonShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_CONVEX_POLYGON;
+PhysicsServer3D::ShapeType ConvexPolygonShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_CONVEX_POLYGON;
}
void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) {
@@ -362,7 +362,7 @@ btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_i
ConcavePolygonShapeBullet::ConcavePolygonShapeBullet() :
ShapeBullet(),
- meshShape(NULL) {}
+ meshShape(nullptr) {}
ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() {
if (meshShape) {
@@ -381,8 +381,8 @@ Variant ConcavePolygonShapeBullet::get_data() const {
return faces;
}
-PhysicsServer::ShapeType ConcavePolygonShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_CONCAVE_POLYGON;
+PhysicsServer3D::ShapeType ConcavePolygonShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_CONCAVE_POLYGON;
}
void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) {
@@ -425,7 +425,7 @@ void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) {
btGenerateInternalEdgeInfo(meshShape, triangleInfoMap);
}
} else {
- meshShape = NULL;
+ meshShape = nullptr;
ERR_PRINT("The faces count are 0, the mesh shape cannot be created");
}
notifyShapeChanged();
@@ -434,7 +434,7 @@ void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) {
btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape);
if (!cs)
- // This is necessary since if 0 faces the creation of concave return NULL
+ // This is necessary since if 0 faces the creation of concave return null
cs = ShapeBullet::create_shape_empty();
cs->setLocalScaling(p_implicit_scale);
prepare(cs);
@@ -536,8 +536,8 @@ Variant HeightMapShapeBullet::get_data() const {
ERR_FAIL_V(Variant());
}
-PhysicsServer::ShapeType HeightMapShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_HEIGHTMAP;
+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) {
@@ -580,8 +580,8 @@ Variant RayShapeBullet::get_data() const {
return d;
}
-PhysicsServer::ShapeType RayShapeBullet::get_type() const {
- return PhysicsServer::SHAPE_RAY;
+PhysicsServer3D::ShapeType RayShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_RAY;
}
void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) {
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index c8b5ca102a..0dbc616fe5 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -34,7 +34,7 @@
#include "core/math/geometry.h"
#include "core/variant.h"
#include "rid_bullet.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#include <LinearMath/btAlignedObjectArray.h>
#include <LinearMath/btScalar.h>
@@ -78,7 +78,7 @@ public:
virtual void set_data(const Variant &p_data) = 0;
virtual Variant get_data() const = 0;
- virtual PhysicsServer::ShapeType get_type() const = 0;
+ virtual PhysicsServer3D::ShapeType get_type() const = 0;
public:
static class btEmptyShape *create_shape_empty();
@@ -103,7 +103,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -120,7 +120,7 @@ public:
_FORCE_INLINE_ real_t get_radius() { return radius; }
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -137,7 +137,7 @@ public:
_FORCE_INLINE_ const btVector3 &get_half_extents() { return half_extents; }
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -156,7 +156,7 @@ public:
_FORCE_INLINE_ real_t get_radius() { return radius; }
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -175,7 +175,7 @@ public:
_FORCE_INLINE_ real_t get_radius() { return radius; }
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
@@ -192,7 +192,7 @@ public:
virtual void set_data(const Variant &p_data);
void get_vertices(Vector<Vector3> &out_vertices);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -210,7 +210,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -230,7 +230,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
@@ -247,7 +247,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
- virtual PhysicsServer::ShapeType get_type() const;
+ virtual PhysicsServer3D::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp
index d9ebb9d580..f193daef39 100644
--- a/modules/bullet/slider_joint_bullet.cpp
+++ b/modules/bullet/slider_joint_bullet.cpp
@@ -342,58 +342,58 @@ real_t SliderJointBullet::getLinearPos() {
;
}
-void SliderJointBullet::set_param(PhysicsServer::SliderJointParam p_param, real_t p_value) {
+void SliderJointBullet::set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value) {
switch (p_param) {
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: setUpperLinLimit(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: setLowerLinLimit(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: setSoftnessLimLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: setRestitutionLimLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: setDampingLimLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: setSoftnessDirLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: setRestitutionDirLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: setDampingDirLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: setDampingOrthoLin(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: setUpperAngLimit(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: setLowerAngLimit(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: setSoftnessLimAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: setRestitutionLimAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: setDampingLimAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: setSoftnessDirAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: setRestitutionDirAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: setDampingDirAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: setDampingOrthoAng(p_value); break;
- case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: setUpperLinLimit(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: setLowerLinLimit(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: setSoftnessLimLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: setRestitutionLimLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: setDampingLimLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: setSoftnessDirLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: setRestitutionDirLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: setDampingDirLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: setDampingOrthoLin(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: setUpperAngLimit(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: setLowerAngLimit(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: setSoftnessLimAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: setRestitutionLimAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: setDampingLimAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: setSoftnessDirAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: setRestitutionDirAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: setDampingDirAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: setDampingOrthoAng(p_value); break;
+ case PhysicsServer3D::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning
}
}
-real_t SliderJointBullet::get_param(PhysicsServer::SliderJointParam p_param) const {
+real_t SliderJointBullet::get_param(PhysicsServer3D::SliderJointParam p_param) const {
switch (p_param) {
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return getUpperLinLimit();
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return getLowerLinLimit();
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return getSoftnessLimLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return getRestitutionLimLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return getDampingLimLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return getSoftnessDirLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return getRestitutionDirLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return getDampingDirLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoLin();
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return getDampingOrthoLin();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return getUpperAngLimit();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return getLowerAngLimit();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return getSoftnessLimAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return getRestitutionLimAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return getDampingLimAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return getSoftnessDirAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return getRestitutionDirAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return getDampingDirAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoAng();
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return getDampingOrthoAng();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return getUpperLinLimit();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return getLowerLinLimit();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return getSoftnessLimLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return getRestitutionLimLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return getDampingLimLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return getSoftnessDirLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return getRestitutionDirLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return getDampingDirLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoLin();
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return getDampingOrthoLin();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return getUpperAngLimit();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return getLowerAngLimit();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return getSoftnessLimAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return getRestitutionLimAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return getDampingLimAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return getSoftnessDirAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return getRestitutionDirAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return getDampingDirAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoAng();
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return getDampingOrthoAng();
default:
return 0;
}
diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h
index d98a1b8c95..6410b952ed 100644
--- a/modules/bullet/slider_joint_bullet.h
+++ b/modules/bullet/slider_joint_bullet.h
@@ -46,7 +46,7 @@ public:
/// Reference frame is A
SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB);
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_SLIDER; }
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; }
const RigidBodyBullet *getRigidBodyA() const;
const RigidBodyBullet *getRigidBodyB() const;
@@ -115,7 +115,7 @@ public:
real_t getMaxAngMotorForce();
real_t getLinearPos();
- void set_param(PhysicsServer::SliderJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::SliderJointParam p_param) const;
+ void set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::SliderJointParam p_param) const;
};
#endif
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index f21206dd0d..236bdc7c8a 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -32,12 +32,12 @@
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
-#include "scene/3d/soft_body.h"
+#include "scene/3d/soft_body_3d.h"
#include "space_bullet.h"
SoftBodyBullet::SoftBodyBullet() :
CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY),
- bt_soft_body(NULL),
+ bt_soft_body(nullptr),
isScratched(false),
simulation_precision(5),
total_mass(1.),
@@ -76,7 +76,7 @@ void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {}
void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {}
-void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_server_handler) {
+void SoftBodyBullet::update_rendering_server(SoftBodyRenderingServerHandler *p_rendering_server_handler) {
if (!bt_soft_body)
return;
@@ -96,8 +96,8 @@ void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_
const int vs_indices_size(vs_indices->size());
for (int x = 0; x < vs_indices_size; ++x) {
- p_visual_server_handler->set_vertex((*vs_indices)[x], vertex_position);
- p_visual_server_handler->set_normal((*vs_indices)[x], vertex_normal);
+ p_rendering_server_handler->set_vertex((*vs_indices)[x], vertex_position);
+ p_rendering_server_handler->set_normal((*vs_indices)[x], vertex_normal);
}
}
@@ -112,7 +112,7 @@ void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_
B_TO_G(aabb_min, aabb.position);
B_TO_G(size, aabb.size);
- p_visual_server_handler->set_aabb(aabb);
+ p_rendering_server_handler->set_aabb(aabb);
}
void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) {
@@ -129,8 +129,8 @@ void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) {
}
Array arrays = soft_mesh->surface_get_arrays(0);
- ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & VS::ARRAY_FORMAT_INDEX));
- set_trimesh_body_shape(arrays[VS::ARRAY_INDEX], arrays[VS::ARRAY_VERTEX]);
+ ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & RS::ARRAY_FORMAT_INDEX));
+ set_trimesh_body_shape(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
}
void SoftBodyBullet::destroy_soft_body() {
@@ -144,7 +144,7 @@ void SoftBodyBullet::destroy_soft_body() {
}
destroyBulletCollisionObject();
- bt_soft_body = NULL;
+ bt_soft_body = nullptr;
}
void SoftBodyBullet::set_soft_transform(const Transform &p_transform) {
@@ -184,7 +184,7 @@ void SoftBodyBullet::get_node_offset(int p_node_index, Vector3 &r_offset) const
return;
Array arrays = soft_mesh->surface_get_arrays(0);
- Vector<Vector3> vertices(arrays[VS::ARRAY_VERTEX]);
+ Vector<Vector3> vertices(arrays[RS::ARRAY_VERTEX]);
if (0 <= p_node_index && vertices.size() > p_node_index) {
r_offset = vertices[p_node_index];
@@ -230,7 +230,7 @@ void SoftBodyBullet::reset_all_node_positions() {
return;
Array arrays = soft_mesh->surface_get_arrays(0);
- Vector<Vector3> vs_vertices(arrays[VS::ARRAY_VERTEX]);
+ Vector<Vector3> vs_vertices(arrays[RS::ARRAY_VERTEX]);
const Vector3 *vs_vertices_read = vs_vertices.ptr();
for (int vertex_index = bt_soft_body->m_nodes.size() - 1; 0 <= vertex_index; --vertex_index) {
@@ -404,7 +404,7 @@ void SoftBodyBullet::setup_soft_body() {
// Soft body setup
setupBulletCollisionObject(bt_soft_body);
- bt_soft_body->m_worldInfo = NULL; // Remove fake world info
+ bt_soft_body->m_worldInfo = nullptr; // Remove fake world info
bt_soft_body->getCollisionShape()->setMargin(0.01);
bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT)));
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
index 2df8ce074f..3c6871e0d6 100644
--- a/modules/bullet/soft_body_bullet.h
+++ b/modules/bullet/soft_body_bullet.h
@@ -43,7 +43,7 @@
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "collision_object_bullet.h"
#include "scene/resources/mesh.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#ifdef x11_None
/// This is required to re add the macro None defined by x11 compiler
@@ -59,7 +59,7 @@ class SoftBodyBullet : public CollisionObjectBullet {
private:
btSoftBody *bt_soft_body;
- Vector<Vector<int> > indices_table;
+ Vector<Vector<int>> indices_table;
btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody
bool isScratched;
@@ -100,7 +100,7 @@ public:
_FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; }
- void update_visual_server(class SoftBodyVisualServerHandler *p_visual_server_handler);
+ void update_rendering_server(class SoftBodyRenderingServerHandler *p_rendering_server_handler);
void set_soft_mesh(const Ref<Mesh> &p_mesh);
void destroy_soft_body();
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index f6df97f11d..1659664ff9 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -39,7 +39,7 @@
#include "godot_collision_configuration.h"
#include "godot_collision_dispatcher.h"
#include "rigid_body_bullet.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#include "soft_body_bullet.h"
#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h>
@@ -59,7 +59,7 @@
*/
BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_space) :
- PhysicsDirectSpaceState(),
+ PhysicsDirectSpaceState3D(),
space(p_space) {}
int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
@@ -108,7 +108,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
r_result.shape = btResult.m_shapeId;
r_result.rid = gObj->get_self();
r_result.collider_id = gObj->get_instance_id();
- r_result.collider = r_result.collider_id.is_null() ? NULL : ObjectDB::get_instance(r_result.collider_id);
+ r_result.collider = r_result.collider_id.is_null() ? nullptr : ObjectDB::get_instance(r_result.collider_id);
} else {
WARN_PRINT("The raycast performed has hit a collision object that is not part of Godot scene, please check it.");
}
@@ -309,7 +309,7 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_
btPointCollector result;
btGjkPairDetector gjk_pair_detector(&point_shape, convex_shape, space->gjk_simplex_solver, space->gjk_epa_pen_solver);
- gjk_pair_detector.getClosestPoints(input, result, 0);
+ gjk_pair_detector.getClosestPoints(input, result, nullptr);
if (out_distance > result.m_distance) {
out_distance = result.m_distance;
@@ -332,14 +332,14 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_
}
SpaceBullet::SpaceBullet() :
- broadphase(NULL),
- collisionConfiguration(NULL),
- dispatcher(NULL),
- solver(NULL),
- dynamicsWorld(NULL),
- soft_body_world_info(NULL),
- ghostPairCallback(NULL),
- godotFilterCallback(NULL),
+ broadphase(nullptr),
+ collisionConfiguration(nullptr),
+ dispatcher(nullptr),
+ solver(nullptr),
+ dynamicsWorld(nullptr),
+ soft_body_world_info(nullptr),
+ ghostPairCallback(nullptr),
+ godotFilterCallback(nullptr),
gravityDirection(0, -1, 0),
gravityMagnitude(10),
contactDebugCount(0),
@@ -366,27 +366,27 @@ void SpaceBullet::step(real_t p_delta_time) {
dynamicsWorld->stepSimulation(p_delta_time, 0, 0);
}
-void SpaceBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) {
+void SpaceBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
assert(dynamicsWorld);
switch (p_param) {
- case PhysicsServer::AREA_PARAM_GRAVITY:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY:
gravityMagnitude = p_value;
update_gravity();
break;
- case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
gravityDirection = p_value;
update_gravity();
break;
- case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
- case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
break; // No damp
- case PhysicsServer::AREA_PARAM_PRIORITY:
+ case PhysicsServer3D::AREA_PARAM_PRIORITY:
// Priority is always 0, the lower
break;
- case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
- case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
- case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
break;
default:
WARN_PRINT("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it.");
@@ -394,22 +394,22 @@ void SpaceBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant
}
}
-Variant SpaceBullet::get_param(PhysicsServer::AreaParameter p_param) {
+Variant SpaceBullet::get_param(PhysicsServer3D::AreaParameter p_param) {
switch (p_param) {
- case PhysicsServer::AREA_PARAM_GRAVITY:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY:
return gravityMagnitude;
- case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR:
return gravityDirection;
- case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
- case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP:
+ case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP:
return 0; // No damp
- case PhysicsServer::AREA_PARAM_PRIORITY:
+ case PhysicsServer3D::AREA_PARAM_PRIORITY:
return 0; // Priority is always 0, the lower
- case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT:
return false;
- case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
return 0;
- case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
return 0;
default:
WARN_PRINT("This get parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it.");
@@ -417,32 +417,32 @@ Variant SpaceBullet::get_param(PhysicsServer::AreaParameter p_param) {
}
}
-void SpaceBullet::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) {
+void SpaceBullet::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value) {
switch (p_param) {
- case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
- case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION:
- case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
- case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
- case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP:
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
- case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
+ case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
+ case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
+ case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
default:
WARN_PRINT("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it.");
break;
}
}
-real_t SpaceBullet::get_param(PhysicsServer::SpaceParameter p_param) {
+real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) {
switch (p_param) {
- case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
- case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION:
- case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
- case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
- case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP:
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
- case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION:
+ case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
+ case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP:
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
+ case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
default:
WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned.");
return 0.f;
@@ -511,7 +511,7 @@ void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) {
if (is_using_soft_world()) {
if (p_body->get_bt_soft_body()) {
static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body());
- p_body->get_bt_soft_body()->m_worldInfo = NULL;
+ p_body->get_bt_soft_body()->m_worldInfo = nullptr;
}
}
}
@@ -539,7 +539,7 @@ void SpaceBullet::remove_all_collision_objects() {
for (int i = dynamicsWorld->getNumCollisionObjects() - 1; 0 <= i; --i) {
btCollisionObject *btObj = dynamicsWorld->getCollisionObjectArray()[i];
CollisionObjectBullet *colObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
- colObj->set_space(NULL);
+ colObj->set_space(nullptr);
}
}
@@ -636,8 +636,8 @@ void SpaceBullet::destroy_world() {
/// The world elements (like: Collision Objects, Constraints, Shapes) are managed by godot
- dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(NULL);
- dynamicsWorld->getPairCache()->setOverlapFilterCallback(NULL);
+ dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(nullptr);
+ dynamicsWorld->getPairCache()->setOverlapFilterCallback(nullptr);
bulletdelete(ghostPairCallback);
bulletdelete(godotFilterCallback);
@@ -645,7 +645,7 @@ void SpaceBullet::destroy_world() {
// Deallocate world
dynamicsWorld->~btDiscreteDynamicsWorld();
free(dynamicsWorld);
- dynamicsWorld = NULL;
+ dynamicsWorld = nullptr;
bulletdelete(solver);
bulletdelete(broadphase);
@@ -741,7 +741,7 @@ void SpaceBullet::check_ghost_overlaps() {
static_cast<btConvexShape *>(other_body_shape),
gjk_simplex_solver,
gjk_epa_pen_solver);
- gjk_pair_detector.getClosestPoints(gjk_input, result, 0);
+ gjk_pair_detector.getClosestPoints(gjk_input, result, nullptr);
if (0 >= result.m_distance) {
hasOverlap = true;
@@ -750,10 +750,10 @@ void SpaceBullet::check_ghost_overlaps() {
} else {
- btCollisionObjectWrapper obA(NULL, area_shape, area->get_bt_ghost(), gjk_input.m_transformA, -1, y);
- btCollisionObjectWrapper obB(NULL, other_body_shape, otherObject->get_bt_collision_object(), gjk_input.m_transformB, -1, z);
+ btCollisionObjectWrapper obA(nullptr, area_shape, area->get_bt_ghost(), gjk_input.m_transformA, -1, y);
+ btCollisionObjectWrapper obB(nullptr, other_body_shape, otherObject->get_bt_collision_object(), gjk_input.m_transformB, -1, z);
- btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS);
+ btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, nullptr, BT_CONTACT_POINT_ALGORITHMS);
if (!algorithm)
continue;
@@ -885,20 +885,20 @@ void SpaceBullet::update_gravity() {
#include "scene/3d/immediate_geometry.h"
-static ImmediateGeometry *motionVec(NULL);
-static ImmediateGeometry *normalLine(NULL);
+static ImmediateGeometry3D *motionVec(nullptr);
+static ImmediateGeometry3D *normalLine(nullptr);
static Ref<StandardMaterial3D> red_mat;
static Ref<StandardMaterial3D> blue_mat;
#endif
-bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
#if debug_test_motion
/// Yes I know this is not good, but I've used it as fast debugging hack.
/// I'm leaving it here just for speedup the other eventual debugs
if (!normalLine) {
- motionVec = memnew(ImmediateGeometry);
- normalLine = memnew(ImmediateGeometry);
+ motionVec = memnew(ImmediateGeometry3D);
+ normalLine = memnew(ImmediateGeometry3D);
SceneTree::get_singleton()->get_current_scene()->add_child(motionVec);
SceneTree::get_singleton()->get_current_scene()->add_child(normalLine);
@@ -951,7 +951,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
Vector3 sup_line;
B_TO_G(body_safe_position.getOrigin(), sup_line);
motionVec->clear();
- motionVec->begin(Mesh::PRIMITIVE_LINES, NULL);
+ motionVec->begin(Mesh::PRIMITIVE_LINES, nullptr);
motionVec->add_vertex(sup_line);
motionVec->add_vertex(sup_line + p_motion * 10);
motionVec->end();
@@ -1028,7 +1028,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
Vector3 sup_line2;
B_TO_G(motion, sup_line2);
normalLine->clear();
- normalLine->begin(Mesh::PRIMITIVE_LINES, NULL);
+ normalLine->begin(Mesh::PRIMITIVE_LINES, nullptr);
normalLine->add_vertex(r_result->collision_point);
normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10);
normalLine->end();
@@ -1042,7 +1042,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
return has_penetration;
}
-int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin) {
+int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, float p_margin) {
btTransform body_transform;
G_TO_B(p_transform, body_transform);
@@ -1054,7 +1054,7 @@ int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p
int rays_found_this_round = 0;
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
- PhysicsServer::SeparationResult *next_results = &r_results[rays_found];
+ PhysicsServer3D::SeparationResult *next_results = &r_results[rays_found];
rays_found_this_round = recover_from_penetration_ray(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, p_result_max - rays_found, recover_motion, next_results);
rays_found += rays_found_this_round;
@@ -1124,7 +1124,7 @@ public:
if (cs->getNumChildShapes() > 1) {
const btDbvt *tree = cs->getDynamicAabbTree();
- ERR_FAIL_COND_V(tree == NULL, true);
+ ERR_FAIL_COND_V(tree == nullptr, true);
// Transform bounds into compound shape local space
const btTransform other_in_compound_space = co->getWorldTransform().inverse();
@@ -1275,7 +1275,7 @@ bool SpaceBullet::RFP_convex_convex_test(const btConvexShape *p_shapeA, const bt
// Perform GJK test
btPointCollector result;
btGjkPairDetector gjk_pair_detector(p_shapeA, p_shapeB, gjk_simplex_solver, gjk_epa_pen_solver);
- gjk_pair_detector.getClosestPoints(gjk_input, result, 0);
+ gjk_pair_detector.getClosestPoints(gjk_input, result, nullptr);
if (0 > result.m_distance) {
// Has penetration
r_delta_recover_movement += result.m_normalOnBInWorld * (result.m_distance * -1 * p_recover_movement_scale);
@@ -1302,10 +1302,10 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC
btTransform tA(p_transformA);
- btCollisionObjectWrapper obA(NULL, p_shapeA, p_objectA, tA, -1, p_shapeId_A);
- btCollisionObjectWrapper obB(NULL, p_shapeB, p_objectB, p_transformB, -1, p_shapeId_B);
+ btCollisionObjectWrapper obA(nullptr, p_shapeA, p_objectA, tA, -1, p_shapeId_A);
+ btCollisionObjectWrapper obB(nullptr, p_shapeB, p_objectB, p_transformB, -1, p_shapeId_B);
- btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS);
+ btCollisionAlgorithm *algorithm = dispatcher->findAlgorithm(&obA, &obB, nullptr, BT_CONTACT_POINT_ALGORITHMS);
if (algorithm) {
GodotDeepPenetrationContactResultCallback contactPointResult(&obA, &obB);
//discrete collision detection query
@@ -1333,7 +1333,7 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC
return false;
}
-int SpaceBullet::add_separation_result(PhysicsServer::SeparationResult *r_result, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const {
+int SpaceBullet::add_separation_result(PhysicsServer3D::SeparationResult *r_result, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const {
// optimize results (ignore non-colliding)
if (p_recover_result.penetration_distance < 0.0) {
@@ -1355,7 +1355,7 @@ int SpaceBullet::add_separation_result(PhysicsServer::SeparationResult *r_result
}
}
-int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results) {
+int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer3D::SeparationResult *r_results) {
// Calculate the cumulative AABB of all shapes of the kinematic body
btVector3 aabb_min, aabb_max;
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 32372f1630..f9a8c063fd 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -35,7 +35,7 @@
#include "core/vector.h"
#include "godot_result_callbacks.h"
#include "rid_bullet.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
#include <BulletCollision/BroadphaseCollision/btBroadphaseProxy.h>
#include <BulletCollision/BroadphaseCollision/btOverlappingPairCache.h>
@@ -67,8 +67,8 @@ class btGjkEpaPenetrationDepthSolver;
extern ContactAddedCallback gContactAddedCallback;
-class BulletPhysicsDirectSpaceState : public PhysicsDirectSpaceState {
- GDCLASS(BulletPhysicsDirectSpaceState, PhysicsDirectSpaceState);
+class BulletPhysicsDirectSpaceState : public PhysicsDirectSpaceState3D {
+ GDCLASS(BulletPhysicsDirectSpaceState, PhysicsDirectSpaceState3D);
private:
SpaceBullet *space;
@@ -79,7 +79,7 @@ public:
virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false);
virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = NULL);
+ virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr);
/// Returns the list of contacts pairs in this order: Local contact, other body contact
virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
@@ -131,15 +131,15 @@ public:
/// @param p_param:
/// AREA_PARAM_GRAVITY to set the gravity magnitude of entire world
/// AREA_PARAM_GRAVITY_VECTOR to set the gravity direction of entire world
- void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value);
+ void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value);
/// Used to get some parameters to Bullet world
/// @param p_param:
/// AREA_PARAM_GRAVITY to get the gravity magnitude of entire world
/// AREA_PARAM_GRAVITY_VECTOR to get the gravity direction of entire world
- Variant get_param(PhysicsServer::AreaParameter p_param);
+ Variant get_param(PhysicsServer3D::AreaParameter p_param);
- void set_param(PhysicsServer::SpaceParameter p_param, real_t p_value);
- real_t get_param(PhysicsServer::SpaceParameter p_param);
+ void set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::SpaceParameter p_param);
void add_area(AreaBullet *p_area);
void remove_area(AreaBullet *p_area);
@@ -177,8 +177,8 @@ public:
void update_gravity();
- bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes);
- int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
+ int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, float p_margin);
private:
void create_empty_world(bool p_create_soft_world);
@@ -201,19 +201,19 @@ private:
pointWorld(0, 0, 0),
penetration_distance(1e20),
other_compound_shape_index(0),
- other_collision_object(NULL),
+ other_collision_object(nullptr),
local_shape_most_recovered(0) {}
};
- bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+ bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
/// This is an API that recover a kinematic object from penetration
/// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions
- bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+ bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
/// This is an API that recover a kinematic object from penetration
/// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm
- bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+ bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
- int add_separation_result(PhysicsServer::SeparationResult *r_results, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const;
- int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results);
+ int add_separation_result(PhysicsServer3D::SeparationResult *r_results, const SpaceBullet::RecoverResult &p_recover_result, int p_shape_id, const btCollisionObject *p_other_object) const;
+ int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer3D::SeparationResult *r_results);
};
#endif
diff --git a/modules/camera/SCsub b/modules/camera/SCsub
index 23f031f06e..63c4e9fbab 100644
--- a/modules/camera/SCsub
+++ b/modules/camera/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_camera = env_modules.Clone()
@@ -10,7 +10,7 @@ if env["platform"] == "iphone":
modules_sources = []
env_camera.add_source_files(modules_sources, "register_types.cpp")
env_camera.add_source_files(modules_sources, "camera_ios.mm")
- mod_lib = env_modules.add_library('#bin/libgodot_camera_module' + env['LIBSUFFIX'], modules_sources)
+ mod_lib = env_modules.add_library("#bin/libgodot_camera_module" + env["LIBSUFFIX"], modules_sources)
elif env["platform"] == "windows":
env_camera.add_source_files(env.modules_sources, "register_types.cpp")
@@ -19,4 +19,3 @@ elif env["platform"] == "windows":
elif env["platform"] == "osx":
env_camera.add_source_files(env.modules_sources, "register_types.cpp")
env_camera.add_source_files(env.modules_sources, "camera_osx.mm")
-
diff --git a/modules/camera/camera_ios.h b/modules/camera/camera_ios.h
index 89620f788b..7da43e4851 100644
--- a/modules/camera/camera_ios.h
+++ b/modules/camera/camera_ios.h
@@ -42,4 +42,4 @@ public:
void update_feeds();
};
-#endif /* CAMERAIOS_H */ \ No newline at end of file
+#endif /* CAMERAIOS_H */
diff --git a/modules/camera/config.py b/modules/camera/config.py
index d308c04195..87d7542741 100644
--- a/modules/camera/config.py
+++ b/modules/camera/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return platform == 'iphone' or platform == 'osx' or platform == 'windows'
+ return platform == "iphone" or platform == "osx" or platform == "windows"
+
def configure(env):
pass
diff --git a/modules/csg/SCsub b/modules/csg/SCsub
index 57c504efd8..641a42c187 100644
--- a/modules/csg/SCsub
+++ b/modules/csg/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_csg = env_modules.Clone()
diff --git a/modules/csg/config.py b/modules/csg/config.py
index 38ccc66d91..9106cbceca 100644
--- a/modules/csg/config.py
+++ b/modules/csg/config.py
@@ -1,21 +1,24 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
- "CSGBox",
- "CSGCombiner",
- "CSGCylinder",
- "CSGMesh",
- "CSGPolygon",
- "CSGPrimitive",
- "CSGShape",
- "CSGSphere",
- "CSGTorus",
+ "CSGBox3D",
+ "CSGCombiner3D",
+ "CSGCylinder3D",
+ "CSGMesh3D",
+ "CSGPolygon3D",
+ "CSGPrimitive3D",
+ "CSGShape3D",
+ "CSGSphere3D",
+ "CSGTorus3D",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 4e39cce4a5..3f61e2852f 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -179,7 +179,7 @@ void CSGBrush::_regen_face_aabbs() {
}
}
-void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material> > &p_materials, const Vector<bool> &p_invert_faces) {
+void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces) {
faces.clear();
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index bb83c84cb5..d389cbc283 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -55,12 +55,12 @@ struct CSGBrush {
};
Vector<Face> faces;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
inline void _regen_face_aabbs();
// Create a brush from faces.
- void build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material> > &p_materials, const Vector<bool> &p_invert_faces);
+ void build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces);
void copy_from(const CSGBrush &p_brush, const Transform &p_xform);
};
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index 1b63bccb06..fa176cb94e 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -32,7 +32,7 @@
///////////
-CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() {
+CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15));
create_material("shape_union_material", gizmo_color);
@@ -49,46 +49,46 @@ CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() {
create_handle_material("handles");
}
-String CSGShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
- CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
- if (Object::cast_to<CSGSphere>(cs)) {
+ if (Object::cast_to<CSGSphere3D>(cs)) {
return "Radius";
}
- if (Object::cast_to<CSGBox>(cs)) {
+ if (Object::cast_to<CSGBox3D>(cs)) {
static const char *hname[3] = { "Width", "Height", "Depth" };
return hname[p_idx];
}
- if (Object::cast_to<CSGCylinder>(cs)) {
+ if (Object::cast_to<CSGCylinder3D>(cs)) {
return p_idx == 0 ? "Radius" : "Height";
}
- if (Object::cast_to<CSGTorus>(cs)) {
+ if (Object::cast_to<CSGTorus3D>(cs)) {
return p_idx == 0 ? "InnerRadius" : "OuterRadius";
}
return "";
}
-Variant CSGShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
- CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
- if (Object::cast_to<CSGSphere>(cs)) {
+ if (Object::cast_to<CSGSphere3D>(cs)) {
- CSGSphere *s = Object::cast_to<CSGSphere>(cs);
+ CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
return s->get_radius();
}
- if (Object::cast_to<CSGBox>(cs)) {
+ if (Object::cast_to<CSGBox3D>(cs)) {
- CSGBox *s = Object::cast_to<CSGBox>(cs);
+ CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
switch (p_idx) {
case 0: return s->get_width();
case 1: return s->get_height();
@@ -96,23 +96,23 @@ Variant CSGShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo
}
}
- if (Object::cast_to<CSGCylinder>(cs)) {
+ if (Object::cast_to<CSGCylinder3D>(cs)) {
- CSGCylinder *s = Object::cast_to<CSGCylinder>(cs);
+ CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
return p_idx == 0 ? s->get_radius() : s->get_height();
}
- if (Object::cast_to<CSGTorus>(cs)) {
+ if (Object::cast_to<CSGTorus3D>(cs)) {
- CSGTorus *s = Object::cast_to<CSGTorus>(cs);
+ CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs);
return p_idx == 0 ? s->get_inner_radius() : s->get_outer_radius();
}
return Variant();
}
-void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
- CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
Transform gt = cs->get_global_transform();
//gt.orthonormalize();
@@ -123,15 +123,15 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
- if (Object::cast_to<CSGSphere>(cs)) {
+ if (Object::cast_to<CSGSphere3D>(cs)) {
- CSGSphere *s = Object::cast_to<CSGSphere>(cs);
+ CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
float d = ra.x;
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001)
@@ -140,17 +140,17 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
s->set_radius(d);
}
- if (Object::cast_to<CSGBox>(cs)) {
+ if (Object::cast_to<CSGBox3D>(cs)) {
- CSGBox *s = Object::cast_to<CSGBox>(cs);
+ CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
Vector3 axis;
axis[p_idx] = 1.0;
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_idx];
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001)
@@ -163,17 +163,17 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
}
}
- if (Object::cast_to<CSGCylinder>(cs)) {
+ if (Object::cast_to<CSGCylinder3D>(cs)) {
- CSGCylinder *s = Object::cast_to<CSGCylinder>(cs);
+ CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
Vector3 axis;
axis[p_idx == 0 ? 0 : 1] = 1.0;
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001)
@@ -185,17 +185,17 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
s->set_height(d * 2.0);
}
- if (Object::cast_to<CSGTorus>(cs)) {
+ if (Object::cast_to<CSGTorus3D>(cs)) {
- CSGTorus *s = Object::cast_to<CSGTorus>(cs);
+ CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs);
Vector3 axis;
axis[0] = 1.0;
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
- if (SpatialEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001)
@@ -207,26 +207,26 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i
s->set_outer_radius(d);
}
}
-void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
- CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
- if (Object::cast_to<CSGSphere>(cs)) {
- CSGSphere *s = Object::cast_to<CSGSphere>(cs);
+ if (Object::cast_to<CSGSphere3D>(cs)) {
+ CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
if (p_cancel) {
s->set_radius(p_restore);
return;
}
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
ur->add_undo_method(s, "set_radius", p_restore);
ur->commit_action();
}
- if (Object::cast_to<CSGBox>(cs)) {
- CSGBox *s = Object::cast_to<CSGBox>(cs);
+ if (Object::cast_to<CSGBox3D>(cs)) {
+ CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
if (p_cancel) {
switch (p_idx) {
case 0: s->set_width(p_restore); break;
@@ -236,7 +236,7 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Box Shape Extents"));
static const char *method[3] = { "set_width", "set_height", "set_depth" };
float current = 0;
@@ -251,8 +251,8 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int
ur->commit_action();
}
- if (Object::cast_to<CSGCylinder>(cs)) {
- CSGCylinder *s = Object::cast_to<CSGCylinder>(cs);
+ if (Object::cast_to<CSGCylinder3D>(cs)) {
+ CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
if (p_cancel) {
if (p_idx == 0)
s->set_radius(p_restore);
@@ -261,7 +261,7 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
if (p_idx == 0) {
ur->create_action(TTR("Change Cylinder Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
@@ -275,8 +275,8 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int
ur->commit_action();
}
- if (Object::cast_to<CSGTorus>(cs)) {
- CSGTorus *s = Object::cast_to<CSGTorus>(cs);
+ if (Object::cast_to<CSGTorus3D>(cs)) {
+ CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs);
if (p_cancel) {
if (p_idx == 0)
s->set_inner_radius(p_restore);
@@ -285,7 +285,7 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
if (p_idx == 0) {
ur->create_action(TTR("Change Torus Inner Radius"));
ur->add_do_method(s, "set_inner_radius", s->get_inner_radius());
@@ -299,37 +299,37 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int
ur->commit_action();
}
}
-bool CSGShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
- return Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial);
+bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial);
}
-String CSGShapeSpatialGizmoPlugin::get_name() const {
- return "CSGShapes";
+String CSGShape3DGizmoPlugin::get_name() const {
+ return "CSGShape3D";
}
-int CSGShapeSpatialGizmoPlugin::get_priority() const {
+int CSGShape3DGizmoPlugin::get_priority() const {
return -1;
}
-bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const {
+bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
-void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
p_gizmo->clear();
Ref<Material> material;
switch (cs->get_operation()) {
- case CSGShape::OPERATION_UNION:
+ case CSGShape3D::OPERATION_UNION:
material = get_material("shape_union_material", p_gizmo);
break;
- case CSGShape::OPERATION_INTERSECTION:
+ case CSGShape3D::OPERATION_INTERSECTION:
material = get_material("shape_intersection_material", p_gizmo);
break;
- case CSGShape::OPERATION_SUBTRACTION:
+ case CSGShape3D::OPERATION_SUBTRACTION:
material = get_material("shape_subtraction_material", p_gizmo);
break;
}
@@ -366,13 +366,13 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
Ref<Material> solid_material;
switch (cs->get_operation()) {
- case CSGShape::OPERATION_UNION:
+ case CSGShape3D::OPERATION_UNION:
solid_material = get_material("shape_union_solid_material", p_gizmo);
break;
- case CSGShape::OPERATION_INTERSECTION:
+ case CSGShape3D::OPERATION_INTERSECTION:
solid_material = get_material("shape_intersection_solid_material", p_gizmo);
break;
- case CSGShape::OPERATION_SUBTRACTION:
+ case CSGShape3D::OPERATION_SUBTRACTION:
solid_material = get_material("shape_subtraction_solid_material", p_gizmo);
break;
}
@@ -380,8 +380,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), solid_material);
}
- if (Object::cast_to<CSGSphere>(cs)) {
- CSGSphere *s = Object::cast_to<CSGSphere>(cs);
+ if (Object::cast_to<CSGSphere3D>(cs)) {
+ CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
float r = s->get_radius();
Vector<Vector3> handles;
@@ -389,8 +389,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
p_gizmo->add_handles(handles, handles_material);
}
- if (Object::cast_to<CSGBox>(cs)) {
- CSGBox *s = Object::cast_to<CSGBox>(cs);
+ if (Object::cast_to<CSGBox3D>(cs)) {
+ CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_width() * 0.5, 0, 0));
@@ -399,8 +399,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
p_gizmo->add_handles(handles, handles_material);
}
- if (Object::cast_to<CSGCylinder>(cs)) {
- CSGCylinder *s = Object::cast_to<CSGCylinder>(cs);
+ if (Object::cast_to<CSGCylinder3D>(cs)) {
+ CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_radius(), 0, 0));
@@ -408,8 +408,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
p_gizmo->add_handles(handles, handles_material);
}
- if (Object::cast_to<CSGTorus>(cs)) {
- CSGTorus *s = Object::cast_to<CSGTorus>(cs);
+ if (Object::cast_to<CSGTorus3D>(cs)) {
+ CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs);
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_inner_radius(), 0, 0));
@@ -419,6 +419,6 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
}
EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) {
- Ref<CSGShapeSpatialGizmoPlugin> gizmo_plugin = Ref<CSGShapeSpatialGizmoPlugin>(memnew(CSGShapeSpatialGizmoPlugin));
- SpatialEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
+ Ref<CSGShape3DGizmoPlugin> gizmo_plugin = Ref<CSGShape3DGizmoPlugin>(memnew(CSGShape3DGizmoPlugin));
+ Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
}
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 966b654802..7763989b2a 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -33,25 +33,25 @@
#include "csg_shape.h"
#include "editor/editor_plugin.h"
-#include "editor/spatial_editor_gizmos.h"
+#include "editor/node_3d_editor_gizmos.h"
-class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
+class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(CSGShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
+ GDCLASS(CSGShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
- bool has_gizmo(Spatial *p_spatial);
+ bool has_gizmo(Node3D *p_spatial);
String get_name() const;
int get_priority() const;
bool is_selectable_when_hidden() const;
- void redraw(EditorSpatialGizmo *p_gizmo);
+ void redraw(EditorNode3DGizmo *p_gizmo);
- String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
- Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
- void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
- void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point);
+ void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
- CSGShapeSpatialGizmoPlugin();
+ CSGShape3DGizmoPlugin();
};
class EditorPluginCSG : public EditorPlugin {
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index a227d49892..5557da3014 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -29,9 +29,9 @@
/*************************************************************************/
#include "csg_shape.h"
-#include "scene/3d/path.h"
+#include "scene/3d/path_3d.h"
-void CSGShape::set_use_collision(bool p_enable) {
+void CSGShape3D::set_use_collision(bool p_enable) {
if (use_collision == p_enable)
return;
@@ -43,52 +43,52 @@ void CSGShape::set_use_collision(bool p_enable) {
if (use_collision) {
root_collision_shape.instance();
- root_collision_instance = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC);
- PhysicsServer::get_singleton()->body_set_state(root_collision_instance, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
- PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
- PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space());
- PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
+ root_collision_instance = PhysicsServer3D::get_singleton()->body_create(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()->get_space());
+ PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
_make_dirty(); //force update
} else {
- PhysicsServer::get_singleton()->free(root_collision_instance);
+ PhysicsServer3D::get_singleton()->free(root_collision_instance);
root_collision_instance = RID();
root_collision_shape.unref();
}
_change_notify();
}
-bool CSGShape::is_using_collision() const {
+bool CSGShape3D::is_using_collision() const {
return use_collision;
}
-void CSGShape::set_collision_layer(uint32_t p_layer) {
+void CSGShape3D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
if (root_collision_instance.is_valid()) {
- PhysicsServer::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer);
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer);
}
}
-uint32_t CSGShape::get_collision_layer() const {
+uint32_t CSGShape3D::get_collision_layer() const {
return collision_layer;
}
-void CSGShape::set_collision_mask(uint32_t p_mask) {
+void CSGShape3D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
if (root_collision_instance.is_valid()) {
- PhysicsServer::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask);
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask);
}
}
-uint32_t CSGShape::get_collision_mask() const {
+uint32_t CSGShape3D::get_collision_mask() const {
return collision_mask;
}
-void CSGShape::set_collision_mask_bit(int p_bit, bool p_value) {
+void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
uint32_t mask = get_collision_mask();
if (p_value)
@@ -98,12 +98,12 @@ void CSGShape::set_collision_mask_bit(int p_bit, bool p_value) {
set_collision_mask(mask);
}
-bool CSGShape::get_collision_mask_bit(int p_bit) const {
+bool CSGShape3D::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit);
}
-void CSGShape::set_collision_layer_bit(int p_bit, bool p_value) {
+void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) {
uint32_t mask = get_collision_layer();
if (p_value)
@@ -113,25 +113,25 @@ void CSGShape::set_collision_layer_bit(int p_bit, bool p_value) {
set_collision_layer(mask);
}
-bool CSGShape::get_collision_layer_bit(int p_bit) const {
+bool CSGShape3D::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
-bool CSGShape::is_root_shape() const {
+bool CSGShape3D::is_root_shape() const {
return !parent;
}
-void CSGShape::set_snap(float p_snap) {
+void CSGShape3D::set_snap(float p_snap) {
snap = p_snap;
}
-float CSGShape::get_snap() const {
+float CSGShape3D::get_snap() const {
return snap;
}
-void CSGShape::_make_dirty() {
+void CSGShape3D::_make_dirty() {
if (!is_inside_tree())
return;
@@ -150,19 +150,19 @@ void CSGShape::_make_dirty() {
}
}
-CSGBrush *CSGShape::_get_brush() {
+CSGBrush *CSGShape3D::_get_brush() {
if (dirty) {
if (brush) {
memdelete(brush);
}
- brush = NULL;
+ brush = nullptr;
CSGBrush *n = _build_brush();
for (int i = 0; i < get_child_count(); i++) {
- CSGShape *child = Object::cast_to<CSGShape>(get_child(i));
+ CSGShape3D *child = Object::cast_to<CSGShape3D>(get_child(i));
if (!child)
continue;
if (!child->is_visible_in_tree())
@@ -185,9 +185,9 @@ CSGBrush *CSGShape::_get_brush() {
CSGBrushOperation bop;
switch (child->get_operation()) {
- case CSGShape::OPERATION_UNION: bop.merge_brushes(CSGBrushOperation::OPERATION_UNION, *n, *nn2, *nn, snap); break;
- case CSGShape::OPERATION_INTERSECTION: bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); break;
- case CSGShape::OPERATION_SUBTRACTION: bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); break;
+ case CSGShape3D::OPERATION_UNION: bop.merge_brushes(CSGBrushOperation::OPERATION_UNION, *n, *nn2, *nn, snap); break;
+ case CSGShape3D::OPERATION_INTERSECTION: bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); break;
+ case CSGShape3D::OPERATION_SUBTRACTION: bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); break;
}
memdelete(n);
memdelete(nn2);
@@ -218,18 +218,18 @@ CSGBrush *CSGShape::_get_brush() {
return brush;
}
-int CSGShape::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
+int CSGShape3D::mikktGetNumFaces(const SMikkTSpaceContext *pContext) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
return surface.vertices.size() / 3;
}
-int CSGShape::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) {
+int CSGShape3D::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) {
// always 3
return 3;
}
-void CSGShape::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
+void CSGShape3D::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
Vector3 v = surface.verticesw[iFace * 3 + iVert];
@@ -238,7 +238,7 @@ void CSGShape::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosO
fvPosOut[2] = v.z;
}
-void CSGShape::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
+void CSGShape3D::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
Vector3 n = surface.normalsw[iFace * 3 + iVert];
@@ -247,7 +247,7 @@ void CSGShape::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOu
fvNormOut[2] = n.z;
}
-void CSGShape::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
+void CSGShape3D::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
Vector2 t = surface.uvsw[iFace * 3 + iVert];
@@ -255,7 +255,7 @@ void CSGShape::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexc
fvTexcOut[1] = t.y;
}
-void CSGShape::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
+void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT,
const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData);
@@ -273,7 +273,7 @@ void CSGShape::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const f
surface.tansw[i++] = d < 0 ? -1 : 1;
}
-void CSGShape::_update_shape() {
+void CSGShape3D::_update_shape() {
if (parent)
return;
@@ -427,7 +427,7 @@ void CSGShape::_update_shape() {
mkif.m_getPosition = mikktGetPosition;
mkif.m_getTexCoord = mikktGetTexCoord;
mkif.m_setTSpace = mikktSetTSpaceDefault;
- mkif.m_setTSpaceBasic = NULL;
+ mkif.m_setTSpaceBasic = nullptr;
SMikkTSpaceContext msc;
msc.m_pInterface = &mkif;
@@ -460,11 +460,11 @@ void CSGShape::_update_shape() {
set_base(root_mesh->get_rid());
}
-AABB CSGShape::get_aabb() const {
+AABB CSGShape3D::get_aabb() const {
return node_aabb;
}
-Vector<Vector3> CSGShape::get_brush_faces() {
+Vector<Vector3> CSGShape3D::get_brush_faces() {
ERR_FAIL_COND_V(!is_inside_tree(), Vector<Vector3>());
CSGBrush *b = _get_brush();
if (!b) {
@@ -486,18 +486,18 @@ Vector<Vector3> CSGShape::get_brush_faces() {
return faces;
}
-Vector<Face3> CSGShape::get_faces(uint32_t p_usage_flags) const {
+Vector<Face3> CSGShape3D::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-void CSGShape::_notification(int p_what) {
+void CSGShape3D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
Node *parentn = get_parent();
if (parentn) {
- parent = Object::cast_to<CSGShape>(parentn);
+ parent = Object::cast_to<CSGShape3D>(parentn);
if (parent) {
set_base(RID());
root_mesh.unref();
@@ -506,11 +506,11 @@ void CSGShape::_notification(int p_what) {
if (use_collision && is_root_shape()) {
root_collision_shape.instance();
- root_collision_instance = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC);
- PhysicsServer::get_singleton()->body_set_state(root_collision_instance, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
- PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
- PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space());
- PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
+ root_collision_instance = PhysicsServer3D::get_singleton()->body_create(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()->get_space());
+ PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
}
@@ -536,10 +536,10 @@ void CSGShape::_notification(int p_what) {
if (parent)
parent->_make_dirty();
- parent = NULL;
+ parent = nullptr;
if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
- PhysicsServer::get_singleton()->free(root_collision_instance);
+ PhysicsServer3D::get_singleton()->free(root_collision_instance);
root_collision_instance = RID();
root_collision_shape.unref();
}
@@ -547,27 +547,27 @@ void CSGShape::_notification(int p_what) {
}
}
-void CSGShape::set_operation(Operation p_operation) {
+void CSGShape3D::set_operation(Operation p_operation) {
operation = p_operation;
_make_dirty();
update_gizmo();
}
-CSGShape::Operation CSGShape::get_operation() const {
+CSGShape3D::Operation CSGShape3D::get_operation() const {
return operation;
}
-void CSGShape::set_calculate_tangents(bool p_calculate_tangents) {
+void CSGShape3D::set_calculate_tangents(bool p_calculate_tangents) {
calculate_tangents = p_calculate_tangents;
_make_dirty();
}
-bool CSGShape::is_calculating_tangents() const {
+bool CSGShape3D::is_calculating_tangents() const {
return calculate_tangents;
}
-void CSGShape::_validate_property(PropertyInfo &property) const {
+void CSGShape3D::_validate_property(PropertyInfo &property) const {
bool is_collision_prefixed = property.name.begins_with("collision_");
if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
//hide collision if not root
@@ -577,7 +577,7 @@ void CSGShape::_validate_property(PropertyInfo &property) const {
}
}
-Array CSGShape::get_meshes() const {
+Array CSGShape3D::get_meshes() const {
if (root_mesh.is_valid()) {
Array arr;
@@ -589,36 +589,36 @@ Array CSGShape::get_meshes() const {
return Array();
}
-void CSGShape::_bind_methods() {
+void CSGShape3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape::_update_shape);
- ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape::is_root_shape);
+ ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape3D::_update_shape);
+ ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape3D::is_root_shape);
- ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape::set_operation);
- ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape::get_operation);
+ ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape3D::set_operation);
+ ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape3D::get_operation);
- ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
- ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
+ ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape3D::set_snap);
+ ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape3D::get_snap);
- ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape::set_use_collision);
- ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape::is_using_collision);
+ ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape3D::set_use_collision);
+ ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape3D::is_using_collision);
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CSGShape::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &CSGShape::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CSGShape3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &CSGShape3D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape3D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape3D::get_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape3D::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape3D::get_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape::set_calculate_tangents);
- ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape::is_calculating_tangents);
+ ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents);
+ ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents);
- ClassDB::bind_method(D_METHOD("get_meshes"), &CSGShape::get_meshes);
+ ClassDB::bind_method(D_METHOD("get_meshes"), &CSGShape3D::get_meshes);
ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
@@ -634,10 +634,10 @@ void CSGShape::_bind_methods() {
BIND_ENUM_CONSTANT(OPERATION_SUBTRACTION);
}
-CSGShape::CSGShape() {
+CSGShape3D::CSGShape3D() {
operation = OPERATION_UNION;
- parent = NULL;
- brush = NULL;
+ parent = nullptr;
+ brush = nullptr;
dirty = false;
snap = 0.001;
use_collision = false;
@@ -647,25 +647,25 @@ CSGShape::CSGShape() {
set_notify_local_transform(true);
}
-CSGShape::~CSGShape() {
+CSGShape3D::~CSGShape3D() {
if (brush) {
memdelete(brush);
- brush = NULL;
+ brush = nullptr;
}
}
//////////////////////////////////
-CSGBrush *CSGCombiner::_build_brush() {
+CSGBrush *CSGCombiner3D::_build_brush() {
- return NULL; //does not build anything
+ return nullptr; //does not build anything
}
-CSGCombiner::CSGCombiner() {
+CSGCombiner3D::CSGCombiner3D() {
}
/////////////////////
-CSGBrush *CSGPrimitive::_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material> > &p_materials) {
+CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials) {
CSGBrush *brush = memnew(CSGBrush);
@@ -683,15 +683,15 @@ CSGBrush *CSGPrimitive::_create_brush_from_arrays(const Vector<Vector3> &p_verti
return brush;
}
-void CSGPrimitive::_bind_methods() {
+void CSGPrimitive3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive::set_invert_faces);
- ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive::is_inverting_faces);
+ ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive3D::set_invert_faces);
+ ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive3D::is_inverting_faces);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_faces"), "set_invert_faces", "is_inverting_faces");
}
-void CSGPrimitive::set_invert_faces(bool p_invert) {
+void CSGPrimitive3D::set_invert_faces(bool p_invert) {
if (invert_faces == p_invert)
return;
@@ -700,24 +700,24 @@ void CSGPrimitive::set_invert_faces(bool p_invert) {
_make_dirty();
}
-bool CSGPrimitive::is_inverting_faces() {
+bool CSGPrimitive3D::is_inverting_faces() {
return invert_faces;
}
-CSGPrimitive::CSGPrimitive() {
+CSGPrimitive3D::CSGPrimitive3D() {
invert_faces = false;
}
/////////////////////
-CSGBrush *CSGMesh::_build_brush() {
+CSGBrush *CSGMesh3D::_build_brush() {
if (!mesh.is_valid())
- return NULL;
+ return nullptr;
Vector<Vector3> vertices;
Vector<bool> smooth;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
Vector<Vector2> uvs;
Ref<Material> material = get_material();
@@ -731,7 +731,7 @@ CSGBrush *CSGMesh::_build_brush() {
if (arrays.size() == 0) {
_make_dirty();
- ERR_FAIL_COND_V(arrays.size() == 0, NULL);
+ ERR_FAIL_COND_V(arrays.size() == 0, nullptr);
}
Vector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX];
@@ -741,19 +741,15 @@ CSGBrush *CSGMesh::_build_brush() {
const Vector3 *vr = avertices.ptr();
Vector<Vector3> anormals = arrays[Mesh::ARRAY_NORMAL];
- const Vector3 *nr;
- bool nr_used = false;
+ const Vector3 *nr = nullptr;
if (anormals.size()) {
nr = anormals.ptr();
- nr_used = true;
}
Vector<Vector2> auvs = arrays[Mesh::ARRAY_TEX_UV];
- const Vector2 *uvr;
- bool uvr_used = false;
+ const Vector2 *uvr = nullptr;
if (auvs.size()) {
uvr = auvs.ptr();
- uvr_used = true;
}
Ref<Material> mat;
@@ -789,10 +785,10 @@ CSGBrush *CSGMesh::_build_brush() {
for (int k = 0; k < 3; k++) {
int idx = ir[j + k];
vertex[k] = vr[idx];
- if (nr_used) {
+ if (nr) {
normal[k] = nr[idx];
}
- if (uvr_used) {
+ if (uvr) {
uv[k] = uvr[idx];
}
}
@@ -832,10 +828,10 @@ CSGBrush *CSGMesh::_build_brush() {
for (int k = 0; k < 3; k++) {
vertex[k] = vr[j + k];
- if (nr_used) {
+ if (nr) {
normal[k] = nr[j + k];
}
- if (uvr_used) {
+ if (uvr) {
uv[k] = uvr[j + k];
}
}
@@ -857,63 +853,63 @@ CSGBrush *CSGMesh::_build_brush() {
}
if (vertices.size() == 0)
- return NULL;
+ return nullptr;
return _create_brush_from_arrays(vertices, uvs, smooth, materials);
}
-void CSGMesh::_mesh_changed() {
+void CSGMesh3D::_mesh_changed() {
_make_dirty();
update_gizmo();
}
-void CSGMesh::set_material(const Ref<Material> &p_material) {
+void CSGMesh3D::set_material(const Ref<Material> &p_material) {
if (material == p_material)
return;
material = p_material;
_make_dirty();
}
-Ref<Material> CSGMesh::get_material() const {
+Ref<Material> CSGMesh3D::get_material() const {
return material;
}
-void CSGMesh::_bind_methods() {
+void CSGMesh3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CSGMesh::set_mesh);
- ClassDB::bind_method(D_METHOD("get_mesh"), &CSGMesh::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CSGMesh3D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &CSGMesh3D::get_mesh);
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGMesh::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CSGMesh::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGMesh3D::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CSGMesh3D::get_material);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGMesh::set_mesh(const Ref<Mesh> &p_mesh) {
+void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) {
if (mesh == p_mesh)
return;
if (mesh.is_valid()) {
- mesh->disconnect("changed", callable_mp(this, &CSGMesh::_mesh_changed));
+ mesh->disconnect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
}
mesh = p_mesh;
if (mesh.is_valid()) {
- mesh->connect("changed", callable_mp(this, &CSGMesh::_mesh_changed));
+ mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
}
_make_dirty();
}
-Ref<Mesh> CSGMesh::get_mesh() {
+Ref<Mesh> CSGMesh3D::get_mesh() {
return mesh;
}
////////////////////////////////
-CSGBrush *CSGSphere::_build_brush() {
+CSGBrush *CSGSphere3D::_build_brush() {
// set our bounding box
@@ -927,7 +923,7 @@ CSGBrush *CSGSphere::_build_brush() {
Vector<Vector3> faces;
Vector<Vector2> uvs;
Vector<bool> smooth;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
Vector<bool> invert;
faces.resize(face_count * 3);
@@ -1032,20 +1028,20 @@ CSGBrush *CSGSphere::_build_brush() {
return brush;
}
-void CSGSphere::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGSphere::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &CSGSphere::get_radius);
+void CSGSphere3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGSphere3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &CSGSphere3D::get_radius);
- ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &CSGSphere::set_radial_segments);
- ClassDB::bind_method(D_METHOD("get_radial_segments"), &CSGSphere::get_radial_segments);
- ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CSGSphere::set_rings);
- ClassDB::bind_method(D_METHOD("get_rings"), &CSGSphere::get_rings);
+ ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &CSGSphere3D::set_radial_segments);
+ ClassDB::bind_method(D_METHOD("get_radial_segments"), &CSGSphere3D::get_radial_segments);
+ ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CSGSphere3D::set_rings);
+ ClassDB::bind_method(D_METHOD("get_rings"), &CSGSphere3D::get_rings);
- ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGSphere::set_smooth_faces);
- ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGSphere::get_smooth_faces);
+ ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGSphere3D::set_smooth_faces);
+ ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGSphere3D::get_smooth_faces);
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGSphere::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CSGSphere::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGSphere3D::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CSGSphere3D::get_material);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments");
@@ -1054,7 +1050,7 @@ void CSGSphere::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGSphere::set_radius(const float p_radius) {
+void CSGSphere3D::set_radius(const float p_radius) {
ERR_FAIL_COND(p_radius <= 0);
radius = p_radius;
_make_dirty();
@@ -1062,51 +1058,51 @@ void CSGSphere::set_radius(const float p_radius) {
_change_notify("radius");
}
-float CSGSphere::get_radius() const {
+float CSGSphere3D::get_radius() const {
return radius;
}
-void CSGSphere::set_radial_segments(const int p_radial_segments) {
+void CSGSphere3D::set_radial_segments(const int p_radial_segments) {
radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
_make_dirty();
update_gizmo();
}
-int CSGSphere::get_radial_segments() const {
+int CSGSphere3D::get_radial_segments() const {
return radial_segments;
}
-void CSGSphere::set_rings(const int p_rings) {
+void CSGSphere3D::set_rings(const int p_rings) {
rings = p_rings > 1 ? p_rings : 1;
_make_dirty();
update_gizmo();
}
-int CSGSphere::get_rings() const {
+int CSGSphere3D::get_rings() const {
return rings;
}
-void CSGSphere::set_smooth_faces(const bool p_smooth_faces) {
+void CSGSphere3D::set_smooth_faces(const bool p_smooth_faces) {
smooth_faces = p_smooth_faces;
_make_dirty();
}
-bool CSGSphere::get_smooth_faces() const {
+bool CSGSphere3D::get_smooth_faces() const {
return smooth_faces;
}
-void CSGSphere::set_material(const Ref<Material> &p_material) {
+void CSGSphere3D::set_material(const Ref<Material> &p_material) {
material = p_material;
_make_dirty();
}
-Ref<Material> CSGSphere::get_material() const {
+Ref<Material> CSGSphere3D::get_material() const {
return material;
}
-CSGSphere::CSGSphere() {
+CSGSphere3D::CSGSphere3D() {
// defaults
radius = 1.0;
radial_segments = 12;
@@ -1116,7 +1112,7 @@ CSGSphere::CSGSphere() {
///////////////
-CSGBrush *CSGBox::_build_brush() {
+CSGBrush *CSGBox3D::_build_brush() {
// set our bounding box
@@ -1130,7 +1126,7 @@ CSGBrush *CSGBox::_build_brush() {
Vector<Vector3> faces;
Vector<Vector2> uvs;
Vector<bool> smooth;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
Vector<bool> invert;
faces.resize(face_count * 3);
@@ -1221,18 +1217,18 @@ CSGBrush *CSGBox::_build_brush() {
return brush;
}
-void CSGBox::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_width", "width"), &CSGBox::set_width);
- ClassDB::bind_method(D_METHOD("get_width"), &CSGBox::get_width);
+void CSGBox3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &CSGBox3D::set_width);
+ ClassDB::bind_method(D_METHOD("get_width"), &CSGBox3D::get_width);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGBox::set_height);
- ClassDB::bind_method(D_METHOD("get_height"), &CSGBox::get_height);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGBox3D::set_height);
+ ClassDB::bind_method(D_METHOD("get_height"), &CSGBox3D::get_height);
- ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGBox::set_depth);
- ClassDB::bind_method(D_METHOD("get_depth"), &CSGBox::get_depth);
+ ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGBox3D::set_depth);
+ ClassDB::bind_method(D_METHOD("get_depth"), &CSGBox3D::get_depth);
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CSGBox::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox3D::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height");
@@ -1240,52 +1236,52 @@ void CSGBox::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGBox::set_width(const float p_width) {
+void CSGBox3D::set_width(const float p_width) {
width = p_width;
_make_dirty();
update_gizmo();
_change_notify("width");
}
-float CSGBox::get_width() const {
+float CSGBox3D::get_width() const {
return width;
}
-void CSGBox::set_height(const float p_height) {
+void CSGBox3D::set_height(const float p_height) {
height = p_height;
_make_dirty();
update_gizmo();
_change_notify("height");
}
-float CSGBox::get_height() const {
+float CSGBox3D::get_height() const {
return height;
}
-void CSGBox::set_depth(const float p_depth) {
+void CSGBox3D::set_depth(const float p_depth) {
depth = p_depth;
_make_dirty();
update_gizmo();
_change_notify("depth");
}
-float CSGBox::get_depth() const {
+float CSGBox3D::get_depth() const {
return depth;
}
-void CSGBox::set_material(const Ref<Material> &p_material) {
+void CSGBox3D::set_material(const Ref<Material> &p_material) {
material = p_material;
_make_dirty();
update_gizmo();
}
-Ref<Material> CSGBox::get_material() const {
+Ref<Material> CSGBox3D::get_material() const {
return material;
}
-CSGBox::CSGBox() {
+CSGBox3D::CSGBox3D() {
// defaults
width = 2.0;
height = 2.0;
@@ -1294,7 +1290,7 @@ CSGBox::CSGBox() {
///////////////
-CSGBrush *CSGCylinder::_build_brush() {
+CSGBrush *CSGCylinder3D::_build_brush() {
// set our bounding box
@@ -1308,7 +1304,7 @@ CSGBrush *CSGCylinder::_build_brush() {
Vector<Vector3> faces;
Vector<Vector2> uvs;
Vector<bool> smooth;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
Vector<bool> invert;
faces.resize(face_count * 3);
@@ -1430,24 +1426,24 @@ CSGBrush *CSGCylinder::_build_brush() {
return brush;
}
-void CSGCylinder::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGCylinder::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &CSGCylinder::get_radius);
+void CSGCylinder3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGCylinder3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &CSGCylinder3D::get_radius);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGCylinder::set_height);
- ClassDB::bind_method(D_METHOD("get_height"), &CSGCylinder::get_height);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGCylinder3D::set_height);
+ ClassDB::bind_method(D_METHOD("get_height"), &CSGCylinder3D::get_height);
- ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGCylinder::set_sides);
- ClassDB::bind_method(D_METHOD("get_sides"), &CSGCylinder::get_sides);
+ ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGCylinder3D::set_sides);
+ ClassDB::bind_method(D_METHOD("get_sides"), &CSGCylinder3D::get_sides);
- ClassDB::bind_method(D_METHOD("set_cone", "cone"), &CSGCylinder::set_cone);
- ClassDB::bind_method(D_METHOD("is_cone"), &CSGCylinder::is_cone);
+ ClassDB::bind_method(D_METHOD("set_cone", "cone"), &CSGCylinder3D::set_cone);
+ ClassDB::bind_method(D_METHOD("is_cone"), &CSGCylinder3D::is_cone);
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGCylinder::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CSGCylinder::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGCylinder3D::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CSGCylinder3D::get_material);
- ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder::set_smooth_faces);
- ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder::get_smooth_faces);
+ ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder3D::set_smooth_faces);
+ ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder3D::get_smooth_faces);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height");
@@ -1457,70 +1453,70 @@ void CSGCylinder::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGCylinder::set_radius(const float p_radius) {
+void CSGCylinder3D::set_radius(const float p_radius) {
radius = p_radius;
_make_dirty();
update_gizmo();
_change_notify("radius");
}
-float CSGCylinder::get_radius() const {
+float CSGCylinder3D::get_radius() const {
return radius;
}
-void CSGCylinder::set_height(const float p_height) {
+void CSGCylinder3D::set_height(const float p_height) {
height = p_height;
_make_dirty();
update_gizmo();
_change_notify("height");
}
-float CSGCylinder::get_height() const {
+float CSGCylinder3D::get_height() const {
return height;
}
-void CSGCylinder::set_sides(const int p_sides) {
+void CSGCylinder3D::set_sides(const int p_sides) {
ERR_FAIL_COND(p_sides < 3);
sides = p_sides;
_make_dirty();
update_gizmo();
}
-int CSGCylinder::get_sides() const {
+int CSGCylinder3D::get_sides() const {
return sides;
}
-void CSGCylinder::set_cone(const bool p_cone) {
+void CSGCylinder3D::set_cone(const bool p_cone) {
cone = p_cone;
_make_dirty();
update_gizmo();
}
-bool CSGCylinder::is_cone() const {
+bool CSGCylinder3D::is_cone() const {
return cone;
}
-void CSGCylinder::set_smooth_faces(const bool p_smooth_faces) {
+void CSGCylinder3D::set_smooth_faces(const bool p_smooth_faces) {
smooth_faces = p_smooth_faces;
_make_dirty();
}
-bool CSGCylinder::get_smooth_faces() const {
+bool CSGCylinder3D::get_smooth_faces() const {
return smooth_faces;
}
-void CSGCylinder::set_material(const Ref<Material> &p_material) {
+void CSGCylinder3D::set_material(const Ref<Material> &p_material) {
material = p_material;
_make_dirty();
}
-Ref<Material> CSGCylinder::get_material() const {
+Ref<Material> CSGCylinder3D::get_material() const {
return material;
}
-CSGCylinder::CSGCylinder() {
+CSGCylinder3D::CSGCylinder3D() {
// defaults
radius = 1.0;
height = 1.0;
@@ -1531,7 +1527,7 @@ CSGCylinder::CSGCylinder() {
///////////////
-CSGBrush *CSGTorus::_build_brush() {
+CSGBrush *CSGTorus3D::_build_brush() {
// set our bounding box
@@ -1539,7 +1535,7 @@ CSGBrush *CSGTorus::_build_brush() {
float max_radius = outer_radius;
if (min_radius == max_radius)
- return NULL; //sorry, can't
+ return nullptr; //sorry, can't
if (min_radius > max_radius) {
SWAP(min_radius, max_radius);
@@ -1557,7 +1553,7 @@ CSGBrush *CSGTorus::_build_brush() {
Vector<Vector3> faces;
Vector<Vector2> uvs;
Vector<bool> smooth;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
Vector<bool> invert;
faces.resize(face_count * 3);
@@ -1657,24 +1653,24 @@ CSGBrush *CSGTorus::_build_brush() {
return brush;
}
-void CSGTorus::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &CSGTorus::set_inner_radius);
- ClassDB::bind_method(D_METHOD("get_inner_radius"), &CSGTorus::get_inner_radius);
+void CSGTorus3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &CSGTorus3D::set_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_inner_radius"), &CSGTorus3D::get_inner_radius);
- ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &CSGTorus::set_outer_radius);
- ClassDB::bind_method(D_METHOD("get_outer_radius"), &CSGTorus::get_outer_radius);
+ ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &CSGTorus3D::set_outer_radius);
+ ClassDB::bind_method(D_METHOD("get_outer_radius"), &CSGTorus3D::get_outer_radius);
- ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGTorus::set_sides);
- ClassDB::bind_method(D_METHOD("get_sides"), &CSGTorus::get_sides);
+ ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGTorus3D::set_sides);
+ ClassDB::bind_method(D_METHOD("get_sides"), &CSGTorus3D::get_sides);
- ClassDB::bind_method(D_METHOD("set_ring_sides", "sides"), &CSGTorus::set_ring_sides);
- ClassDB::bind_method(D_METHOD("get_ring_sides"), &CSGTorus::get_ring_sides);
+ ClassDB::bind_method(D_METHOD("set_ring_sides", "sides"), &CSGTorus3D::set_ring_sides);
+ ClassDB::bind_method(D_METHOD("get_ring_sides"), &CSGTorus3D::get_ring_sides);
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGTorus::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CSGTorus::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGTorus3D::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CSGTorus3D::get_material);
- ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus::set_smooth_faces);
- ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus::get_smooth_faces);
+ ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus3D::set_smooth_faces);
+ ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus3D::get_smooth_faces);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_outer_radius", "get_outer_radius");
@@ -1684,71 +1680,71 @@ void CSGTorus::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGTorus::set_inner_radius(const float p_inner_radius) {
+void CSGTorus3D::set_inner_radius(const float p_inner_radius) {
inner_radius = p_inner_radius;
_make_dirty();
update_gizmo();
_change_notify("inner_radius");
}
-float CSGTorus::get_inner_radius() const {
+float CSGTorus3D::get_inner_radius() const {
return inner_radius;
}
-void CSGTorus::set_outer_radius(const float p_outer_radius) {
+void CSGTorus3D::set_outer_radius(const float p_outer_radius) {
outer_radius = p_outer_radius;
_make_dirty();
update_gizmo();
_change_notify("outer_radius");
}
-float CSGTorus::get_outer_radius() const {
+float CSGTorus3D::get_outer_radius() const {
return outer_radius;
}
-void CSGTorus::set_sides(const int p_sides) {
+void CSGTorus3D::set_sides(const int p_sides) {
ERR_FAIL_COND(p_sides < 3);
sides = p_sides;
_make_dirty();
update_gizmo();
}
-int CSGTorus::get_sides() const {
+int CSGTorus3D::get_sides() const {
return sides;
}
-void CSGTorus::set_ring_sides(const int p_ring_sides) {
+void CSGTorus3D::set_ring_sides(const int p_ring_sides) {
ERR_FAIL_COND(p_ring_sides < 3);
ring_sides = p_ring_sides;
_make_dirty();
update_gizmo();
}
-int CSGTorus::get_ring_sides() const {
+int CSGTorus3D::get_ring_sides() const {
return ring_sides;
}
-void CSGTorus::set_smooth_faces(const bool p_smooth_faces) {
+void CSGTorus3D::set_smooth_faces(const bool p_smooth_faces) {
smooth_faces = p_smooth_faces;
_make_dirty();
}
-bool CSGTorus::get_smooth_faces() const {
+bool CSGTorus3D::get_smooth_faces() const {
return smooth_faces;
}
-void CSGTorus::set_material(const Ref<Material> &p_material) {
+void CSGTorus3D::set_material(const Ref<Material> &p_material) {
material = p_material;
_make_dirty();
}
-Ref<Material> CSGTorus::get_material() const {
+Ref<Material> CSGTorus3D::get_material() const {
return material;
}
-CSGTorus::CSGTorus() {
+CSGTorus3D::CSGTorus3D() {
// defaults
inner_radius = 2.0;
outer_radius = 3.0;
@@ -1759,12 +1755,12 @@ CSGTorus::CSGTorus() {
///////////////
-CSGBrush *CSGPolygon::_build_brush() {
+CSGBrush *CSGPolygon3D::_build_brush() {
// set our bounding box
if (polygon.size() < 3)
- return NULL;
+ return nullptr;
Vector<Point2> final_polygon = polygon;
@@ -1775,9 +1771,9 @@ CSGBrush *CSGPolygon::_build_brush() {
Vector<int> triangles = Geometry::triangulate_polygon(final_polygon);
if (triangles.size() < 3)
- return NULL;
+ return nullptr;
- Path *path = NULL;
+ Path3D *path = nullptr;
Ref<Curve3D> curve;
// get bounds for our polygon
@@ -1800,32 +1796,32 @@ CSGBrush *CSGPolygon::_build_brush() {
if (mode == MODE_PATH) {
if (!has_node(path_node))
- return NULL;
+ return nullptr;
Node *n = get_node(path_node);
if (!n)
- return NULL;
- path = Object::cast_to<Path>(n);
+ return nullptr;
+ path = Object::cast_to<Path3D>(n);
if (!path)
- return NULL;
+ return nullptr;
if (path != path_cache) {
if (path_cache) {
- path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon::_path_exited));
- path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon::_path_changed));
- path_cache = NULL;
+ path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
+ path_cache = nullptr;
}
path_cache = path;
- path_cache->connect("tree_exited", callable_mp(this, &CSGPolygon::_path_exited));
- path_cache->connect("curve_changed", callable_mp(this, &CSGPolygon::_path_changed));
- path_cache = NULL;
+ 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())
- return NULL;
+ return nullptr;
if (curve->get_baked_length() <= 0)
- return NULL;
+ return nullptr;
}
CSGBrush *brush = memnew(CSGBrush);
@@ -1851,7 +1847,7 @@ CSGBrush *CSGPolygon::_build_brush() {
Vector<Vector3> faces;
Vector<Vector2> uvs;
Vector<bool> smooth;
- Vector<Ref<Material> > materials;
+ Vector<Ref<Material>> materials;
Vector<bool> invert;
faces.resize(face_count * 3);
@@ -2231,17 +2227,17 @@ CSGBrush *CSGPolygon::_build_brush() {
return brush;
}
-void CSGPolygon::_notification(int p_what) {
+void CSGPolygon3D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
if (path_cache) {
- path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon::_path_exited));
- path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon::_path_changed));
- path_cache = NULL;
+ path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
+ path_cache = nullptr;
}
}
}
-void CSGPolygon::_validate_property(PropertyInfo &property) const {
+void CSGPolygon3D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("spin") && mode != MODE_SPIN) {
property.usage = 0;
}
@@ -2252,60 +2248,60 @@ void CSGPolygon::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- CSGShape::_validate_property(property);
+ CSGShape3D::_validate_property(property);
}
-void CSGPolygon::_path_changed() {
+void CSGPolygon3D::_path_changed() {
_make_dirty();
update_gizmo();
}
-void CSGPolygon::_path_exited() {
- path_cache = NULL;
+void CSGPolygon3D::_path_exited() {
+ path_cache = nullptr;
}
-void CSGPolygon::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CSGPolygon::set_polygon);
- ClassDB::bind_method(D_METHOD("get_polygon"), &CSGPolygon::get_polygon);
+void CSGPolygon3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CSGPolygon3D::set_polygon);
+ ClassDB::bind_method(D_METHOD("get_polygon"), &CSGPolygon3D::get_polygon);
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &CSGPolygon::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &CSGPolygon::get_mode);
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &CSGPolygon3D::set_mode);
+ ClassDB::bind_method(D_METHOD("get_mode"), &CSGPolygon3D::get_mode);
- ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGPolygon::set_depth);
- ClassDB::bind_method(D_METHOD("get_depth"), &CSGPolygon::get_depth);
+ ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGPolygon3D::set_depth);
+ ClassDB::bind_method(D_METHOD("get_depth"), &CSGPolygon3D::get_depth);
- ClassDB::bind_method(D_METHOD("set_spin_degrees", "degrees"), &CSGPolygon::set_spin_degrees);
- ClassDB::bind_method(D_METHOD("get_spin_degrees"), &CSGPolygon::get_spin_degrees);
+ ClassDB::bind_method(D_METHOD("set_spin_degrees", "degrees"), &CSGPolygon3D::set_spin_degrees);
+ ClassDB::bind_method(D_METHOD("get_spin_degrees"), &CSGPolygon3D::get_spin_degrees);
- ClassDB::bind_method(D_METHOD("set_spin_sides", "spin_sides"), &CSGPolygon::set_spin_sides);
- ClassDB::bind_method(D_METHOD("get_spin_sides"), &CSGPolygon::get_spin_sides);
+ ClassDB::bind_method(D_METHOD("set_spin_sides", "spin_sides"), &CSGPolygon3D::set_spin_sides);
+ ClassDB::bind_method(D_METHOD("get_spin_sides"), &CSGPolygon3D::get_spin_sides);
- ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon::set_path_node);
- ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon::get_path_node);
+ ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon3D::set_path_node);
+ ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon3D::get_path_node);
- ClassDB::bind_method(D_METHOD("set_path_interval", "distance"), &CSGPolygon::set_path_interval);
- ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon::get_path_interval);
+ ClassDB::bind_method(D_METHOD("set_path_interval", "distance"), &CSGPolygon3D::set_path_interval);
+ ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon3D::get_path_interval);
- ClassDB::bind_method(D_METHOD("set_path_rotation", "mode"), &CSGPolygon::set_path_rotation);
- ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon::get_path_rotation);
+ ClassDB::bind_method(D_METHOD("set_path_rotation", "mode"), &CSGPolygon3D::set_path_rotation);
+ ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon3D::get_path_rotation);
- ClassDB::bind_method(D_METHOD("set_path_local", "enable"), &CSGPolygon::set_path_local);
- ClassDB::bind_method(D_METHOD("is_path_local"), &CSGPolygon::is_path_local);
+ ClassDB::bind_method(D_METHOD("set_path_local", "enable"), &CSGPolygon3D::set_path_local);
+ ClassDB::bind_method(D_METHOD("is_path_local"), &CSGPolygon3D::is_path_local);
- ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon::set_path_continuous_u);
- ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon::is_path_continuous_u);
+ ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon3D::set_path_continuous_u);
+ ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon3D::is_path_continuous_u);
- ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon::set_path_joined);
- ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon::is_path_joined);
+ ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon3D::set_path_joined);
+ ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon3D::is_path_joined);
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGPolygon::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CSGPolygon::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGPolygon3D::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CSGPolygon3D::get_material);
- ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGPolygon::set_smooth_faces);
- ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGPolygon::get_smooth_faces);
+ ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGPolygon3D::set_smooth_faces);
+ ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGPolygon3D::get_smooth_faces);
- ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CSGPolygon::_is_editable_3d_polygon);
- ClassDB::bind_method(D_METHOD("_has_editable_3d_polygon_no_depth"), &CSGPolygon::_has_editable_3d_polygon_no_depth);
+ ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CSGPolygon3D::_is_editable_3d_polygon);
+ ClassDB::bind_method(D_METHOD("_has_editable_3d_polygon_no_depth"), &CSGPolygon3D::_has_editable_3d_polygon_no_depth);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode");
@@ -2330,148 +2326,148 @@ void CSGPolygon::_bind_methods() {
BIND_ENUM_CONSTANT(PATH_ROTATION_PATH_FOLLOW);
}
-void CSGPolygon::set_polygon(const Vector<Vector2> &p_polygon) {
+void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) {
polygon = p_polygon;
_make_dirty();
update_gizmo();
}
-Vector<Vector2> CSGPolygon::get_polygon() const {
+Vector<Vector2> CSGPolygon3D::get_polygon() const {
return polygon;
}
-void CSGPolygon::set_mode(Mode p_mode) {
+void CSGPolygon3D::set_mode(Mode p_mode) {
mode = p_mode;
_make_dirty();
update_gizmo();
_change_notify();
}
-CSGPolygon::Mode CSGPolygon::get_mode() const {
+CSGPolygon3D::Mode CSGPolygon3D::get_mode() const {
return mode;
}
-void CSGPolygon::set_depth(const float p_depth) {
+void CSGPolygon3D::set_depth(const float p_depth) {
ERR_FAIL_COND(p_depth < 0.001);
depth = p_depth;
_make_dirty();
update_gizmo();
}
-float CSGPolygon::get_depth() const {
+float CSGPolygon3D::get_depth() const {
return depth;
}
-void CSGPolygon::set_path_continuous_u(bool p_enable) {
+void CSGPolygon3D::set_path_continuous_u(bool p_enable) {
path_continuous_u = p_enable;
_make_dirty();
}
-bool CSGPolygon::is_path_continuous_u() const {
+bool CSGPolygon3D::is_path_continuous_u() const {
return path_continuous_u;
}
-void CSGPolygon::set_spin_degrees(const float p_spin_degrees) {
+void CSGPolygon3D::set_spin_degrees(const float p_spin_degrees) {
ERR_FAIL_COND(p_spin_degrees < 0.01 || p_spin_degrees > 360);
spin_degrees = p_spin_degrees;
_make_dirty();
update_gizmo();
}
-float CSGPolygon::get_spin_degrees() const {
+float CSGPolygon3D::get_spin_degrees() const {
return spin_degrees;
}
-void CSGPolygon::set_spin_sides(const int p_spin_sides) {
+void CSGPolygon3D::set_spin_sides(const int p_spin_sides) {
ERR_FAIL_COND(p_spin_sides < 3);
spin_sides = p_spin_sides;
_make_dirty();
update_gizmo();
}
-int CSGPolygon::get_spin_sides() const {
+int CSGPolygon3D::get_spin_sides() const {
return spin_sides;
}
-void CSGPolygon::set_path_node(const NodePath &p_path) {
+void CSGPolygon3D::set_path_node(const NodePath &p_path) {
path_node = p_path;
_make_dirty();
update_gizmo();
}
-NodePath CSGPolygon::get_path_node() const {
+NodePath CSGPolygon3D::get_path_node() const {
return path_node;
}
-void CSGPolygon::set_path_interval(float p_interval) {
+void CSGPolygon3D::set_path_interval(float p_interval) {
ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001.");
path_interval = p_interval;
_make_dirty();
update_gizmo();
}
-float CSGPolygon::get_path_interval() const {
+float CSGPolygon3D::get_path_interval() const {
return path_interval;
}
-void CSGPolygon::set_path_rotation(PathRotation p_rotation) {
+void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) {
path_rotation = p_rotation;
_make_dirty();
update_gizmo();
}
-CSGPolygon::PathRotation CSGPolygon::get_path_rotation() const {
+CSGPolygon3D::PathRotation CSGPolygon3D::get_path_rotation() const {
return path_rotation;
}
-void CSGPolygon::set_path_local(bool p_enable) {
+void CSGPolygon3D::set_path_local(bool p_enable) {
path_local = p_enable;
_make_dirty();
update_gizmo();
}
-bool CSGPolygon::is_path_local() const {
+bool CSGPolygon3D::is_path_local() const {
return path_local;
}
-void CSGPolygon::set_path_joined(bool p_enable) {
+void CSGPolygon3D::set_path_joined(bool p_enable) {
path_joined = p_enable;
_make_dirty();
update_gizmo();
}
-bool CSGPolygon::is_path_joined() const {
+bool CSGPolygon3D::is_path_joined() const {
return path_joined;
}
-void CSGPolygon::set_smooth_faces(const bool p_smooth_faces) {
+void CSGPolygon3D::set_smooth_faces(const bool p_smooth_faces) {
smooth_faces = p_smooth_faces;
_make_dirty();
}
-bool CSGPolygon::get_smooth_faces() const {
+bool CSGPolygon3D::get_smooth_faces() const {
return smooth_faces;
}
-void CSGPolygon::set_material(const Ref<Material> &p_material) {
+void CSGPolygon3D::set_material(const Ref<Material> &p_material) {
material = p_material;
_make_dirty();
}
-Ref<Material> CSGPolygon::get_material() const {
+Ref<Material> CSGPolygon3D::get_material() const {
return material;
}
-bool CSGPolygon::_is_editable_3d_polygon() const {
+bool CSGPolygon3D::_is_editable_3d_polygon() const {
return true;
}
-bool CSGPolygon::_has_editable_3d_polygon_no_depth() const {
+bool CSGPolygon3D::_has_editable_3d_polygon_no_depth() const {
return true;
}
-CSGPolygon::CSGPolygon() {
+CSGPolygon3D::CSGPolygon3D() {
// defaults
mode = MODE_DEPTH;
polygon.push_back(Vector2(0, 0));
@@ -2487,5 +2483,5 @@ CSGPolygon::CSGPolygon() {
path_local = false;
path_continuous_u = false;
path_joined = false;
- path_cache = NULL;
+ path_cache = nullptr;
}
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 909437e39b..abab1ded20 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -34,12 +34,12 @@
#define CSGJS_HEADER_ONLY
#include "csg.h"
-#include "scene/3d/visual_instance.h"
-#include "scene/resources/concave_polygon_shape.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
#include "thirdparty/misc/mikktspace.h"
-class CSGShape : public GeometryInstance {
- GDCLASS(CSGShape, GeometryInstance);
+class CSGShape3D : public GeometryInstance3D {
+ GDCLASS(CSGShape3D, GeometryInstance3D);
public:
enum Operation {
@@ -51,7 +51,7 @@ public:
private:
Operation operation;
- CSGShape *parent;
+ CSGShape3D *parent;
CSGBrush *brush;
@@ -63,7 +63,7 @@ private:
bool use_collision;
uint32_t collision_layer;
uint32_t collision_mask;
- Ref<ConcavePolygonShape> root_collision_shape;
+ Ref<ConcavePolygonShape3D> root_collision_shape;
RID root_collision_instance;
bool calculate_tangents;
@@ -111,7 +111,7 @@ protected:
static void _bind_methods();
- friend class CSGCombiner;
+ friend class CSGCombiner3D;
CSGBrush *_get_brush();
virtual void _validate_property(PropertyInfo &property) const;
@@ -149,41 +149,41 @@ public:
bool is_calculating_tangents() const;
bool is_root_shape() const;
- CSGShape();
- ~CSGShape();
+ CSGShape3D();
+ ~CSGShape3D();
};
-VARIANT_ENUM_CAST(CSGShape::Operation)
+VARIANT_ENUM_CAST(CSGShape3D::Operation)
-class CSGCombiner : public CSGShape {
- GDCLASS(CSGCombiner, CSGShape);
+class CSGCombiner3D : public CSGShape3D {
+ GDCLASS(CSGCombiner3D, CSGShape3D);
private:
virtual CSGBrush *_build_brush();
public:
- CSGCombiner();
+ CSGCombiner3D();
};
-class CSGPrimitive : public CSGShape {
- GDCLASS(CSGPrimitive, CSGShape);
+class CSGPrimitive3D : public CSGShape3D {
+ GDCLASS(CSGPrimitive3D, CSGShape3D);
private:
bool invert_faces;
protected:
- CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material> > &p_materials);
+ CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials);
static void _bind_methods();
public:
void set_invert_faces(bool p_invert);
bool is_inverting_faces();
- CSGPrimitive();
+ CSGPrimitive3D();
};
-class CSGMesh : public CSGPrimitive {
- GDCLASS(CSGMesh, CSGPrimitive);
+class CSGMesh3D : public CSGPrimitive3D {
+ GDCLASS(CSGMesh3D, CSGPrimitive3D);
virtual CSGBrush *_build_brush();
@@ -203,9 +203,9 @@ public:
Ref<Material> get_material() const;
};
-class CSGSphere : public CSGPrimitive {
+class CSGSphere3D : public CSGPrimitive3D {
- GDCLASS(CSGSphere, CSGPrimitive);
+ GDCLASS(CSGSphere3D, CSGPrimitive3D);
virtual CSGBrush *_build_brush();
Ref<Material> material;
@@ -233,12 +233,12 @@ public:
void set_smooth_faces(bool p_smooth_faces);
bool get_smooth_faces() const;
- CSGSphere();
+ CSGSphere3D();
};
-class CSGBox : public CSGPrimitive {
+class CSGBox3D : public CSGPrimitive3D {
- GDCLASS(CSGBox, CSGPrimitive);
+ GDCLASS(CSGBox3D, CSGPrimitive3D);
virtual CSGBrush *_build_brush();
Ref<Material> material;
@@ -262,12 +262,12 @@ public:
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
- CSGBox();
+ CSGBox3D();
};
-class CSGCylinder : public CSGPrimitive {
+class CSGCylinder3D : public CSGPrimitive3D {
- GDCLASS(CSGCylinder, CSGPrimitive);
+ GDCLASS(CSGCylinder3D, CSGPrimitive3D);
virtual CSGBrush *_build_brush();
Ref<Material> material;
@@ -299,12 +299,12 @@ public:
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
- CSGCylinder();
+ CSGCylinder3D();
};
-class CSGTorus : public CSGPrimitive {
+class CSGTorus3D : public CSGPrimitive3D {
- GDCLASS(CSGTorus, CSGPrimitive);
+ GDCLASS(CSGTorus3D, CSGPrimitive3D);
virtual CSGBrush *_build_brush();
Ref<Material> material;
@@ -336,12 +336,12 @@ public:
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
- CSGTorus();
+ CSGTorus3D();
};
-class CSGPolygon : public CSGPrimitive {
+class CSGPolygon3D : public CSGPrimitive3D {
- GDCLASS(CSGPolygon, CSGPrimitive);
+ GDCLASS(CSGPolygon3D, CSGPrimitive3D);
public:
enum Mode {
@@ -431,10 +431,10 @@ public:
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
- CSGPolygon();
+ CSGPolygon3D();
};
-VARIANT_ENUM_CAST(CSGPolygon::Mode)
-VARIANT_ENUM_CAST(CSGPolygon::PathRotation)
+VARIANT_ENUM_CAST(CSGPolygon3D::Mode)
+VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation)
#endif // CSG_SHAPE_H
diff --git a/modules/csg/doc_classes/CSGBox.xml b/modules/csg/doc_classes/CSGBox.xml
deleted file mode 100644
index e2f0f8488a..0000000000
--- a/modules/csg/doc_classes/CSGBox.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGBox" inherits="CSGPrimitive" version="4.0">
- <brief_description>
- A CSG Box shape.
- </brief_description>
- <description>
- This node allows you to create a box for use with the CSG system.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth" default="2.0">
- Depth of the box measured from the center of the box.
- </member>
- <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
- Height of the box measured from the center of the box.
- </member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
- The material used to render the box.
- </member>
- <member name="width" type="float" setter="set_width" getter="get_width" default="2.0">
- Width of the box measured from the center of the box.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml
new file mode 100644
index 0000000000..492bf68c44
--- /dev/null
+++ b/modules/csg/doc_classes/CSGBox3D.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.0">
+ <brief_description>
+ A CSG Box shape.
+ </brief_description>
+ <description>
+ This node allows you to create a box for use with the CSG system.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="2.0">
+ Depth of the box measured from the center of the box.
+ </member>
+ <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
+ Height of the box measured from the center of the box.
+ </member>
+ <member name="material" type="Material" setter="set_material" getter="get_material">
+ The material used to render the box.
+ </member>
+ <member name="width" type="float" setter="set_width" getter="get_width" default="2.0">
+ Width of the box measured from the center of the box.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGCombiner.xml b/modules/csg/doc_classes/CSGCombiner.xml
deleted file mode 100644
index ab95d3c3ee..0000000000
--- a/modules/csg/doc_classes/CSGCombiner.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCombiner" inherits="CSGShape" version="4.0">
- <brief_description>
- A CSG node that allows you to combine other CSG modifiers.
- </brief_description>
- <description>
- For complex arrangements of shapes, it is sometimes needed to add structure to your CSG nodes. The CSGCombiner node allows you to create this structure. The node encapsulates the result of the CSG operations of its children. In this way, it is possible to do operations on one set of shapes that are children of one CSGCombiner node, and a set of separate operations on a second set of shapes that are children of a second CSGCombiner node, and then do an operation that takes the two end results as its input to create the final shape.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml
new file mode 100644
index 0000000000..b55111eee4
--- /dev/null
+++ b/modules/csg/doc_classes/CSGCombiner3D.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.0">
+ <brief_description>
+ A CSG node that allows you to combine other CSG modifiers.
+ </brief_description>
+ <description>
+ For complex arrangements of shapes, it is sometimes needed to add structure to your CSG nodes. The CSGCombiner3D node allows you to create this structure. The node encapsulates the result of the CSG operations of its children. In this way, it is possible to do operations on one set of shapes that are children of one CSGCombiner3D node, and a set of separate operations on a second set of shapes that are children of a second CSGCombiner3D node, and then do an operation that takes the two end results as its input to create the final shape.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGCylinder.xml b/modules/csg/doc_classes/CSGCylinder.xml
deleted file mode 100644
index 2dd8c6a8d0..0000000000
--- a/modules/csg/doc_classes/CSGCylinder.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCylinder" inherits="CSGPrimitive" version="4.0">
- <brief_description>
- A CSG Cylinder shape.
- </brief_description>
- <description>
- This node allows you to create a cylinder (or cone) for use with the CSG system.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="cone" type="bool" setter="set_cone" getter="is_cone" default="false">
- If [code]true[/code] a cone is created, the [member radius] will only apply to one side.
- </member>
- <member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
- The height of the cylinder.
- </member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
- The material used to render the cylinder.
- </member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- The radius of the cylinder.
- </member>
- <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
- The number of sides of the cylinder, the higher this number the more detail there will be in the cylinder.
- </member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
- If [code]true[/code] the normals of the cylinder are set to give a smooth effect making the cylinder seem rounded. If [code]false[/code] the cylinder will have a flat shaded look.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGCylinder3D.xml b/modules/csg/doc_classes/CSGCylinder3D.xml
new file mode 100644
index 0000000000..bfd2a5d5f2
--- /dev/null
+++ b/modules/csg/doc_classes/CSGCylinder3D.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.0">
+ <brief_description>
+ A CSG Cylinder shape.
+ </brief_description>
+ <description>
+ This node allows you to create a cylinder (or cone) for use with the CSG system.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="cone" type="bool" setter="set_cone" getter="is_cone" default="false">
+ If [code]true[/code] a cone is created, the [member radius] will only apply to one side.
+ </member>
+ <member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
+ The height of the cylinder.
+ </member>
+ <member name="material" type="Material" setter="set_material" getter="get_material">
+ The material used to render the cylinder.
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ The radius of the cylinder.
+ </member>
+ <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
+ The number of sides of the cylinder, the higher this number the more detail there will be in the cylinder.
+ </member>
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
+ If [code]true[/code] the normals of the cylinder are set to give a smooth effect making the cylinder seem rounded. If [code]false[/code] the cylinder will have a flat shaded look.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh.xml
deleted file mode 100644
index f1fe2c286b..0000000000
--- a/modules/csg/doc_classes/CSGMesh.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGMesh" inherits="CSGPrimitive" version="4.0">
- <brief_description>
- 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.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="material" type="Material" setter="set_material" getter="get_material">
- The [Material] used in drawing the CSG shape.
- </member>
- <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
- The [Mesh] resource to use as a CSG shape.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
new file mode 100644
index 0000000000..1bab8f4ee9
--- /dev/null
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.0">
+ <brief_description>
+ 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.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="material" type="Material" setter="set_material" getter="get_material">
+ The [Material] used in drawing the CSG shape.
+ </member>
+ <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
+ The [Mesh] resource to use as a CSG shape.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon.xml
deleted file mode 100644
index 02b2e8b03f..0000000000
--- a/modules/csg/doc_classes/CSGPolygon.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPolygon" inherits="CSGPrimitive" version="4.0">
- <brief_description>
- Extrudes a 2D polygon shape to create a 3D mesh.
- </brief_description>
- <description>
- This node takes a 2D polygon shape and extrudes it to create a 3D mesh.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
- Extrusion depth when [member mode] is [constant MODE_DEPTH].
- </member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
- Material to use for the resulting mesh.
- </member>
- <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon.Mode" default="0">
- Extrusion mode.
- </member>
- <member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u">
- If [code]true[/code] the u component of our uv will continuously increase in unison with the distance traveled along our path when [member mode] is [constant MODE_PATH].
- </member>
- <member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval">
- Interval at which a new extrusion slice is added along the path when [member mode] is [constant MODE_PATH].
- </member>
- <member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined">
- If [code]true[/code] the start and end of our path are joined together ensuring there is no seam when [member mode] is [constant MODE_PATH].
- </member>
- <member name="path_local" type="bool" setter="set_path_local" getter="is_path_local">
- If [code]false[/code] we extrude centered on our path, if [code]true[/code] we extrude in relation to the position of our CSGPolygon when [member mode] is [constant MODE_PATH].
- </member>
- <member name="path_node" type="NodePath" setter="set_path_node" getter="get_path_node">
- The [Shape] object containing the path along which we extrude when [member mode] is [constant MODE_PATH].
- </member>
- <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon.PathRotation">
- The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH].
- </member>
- <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )">
- Point array that defines the shape that we'll extrude.
- </member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
- Generates smooth normals so smooth shading is applied to our mesh.
- </member>
- <member name="spin_degrees" type="float" setter="set_spin_degrees" getter="get_spin_degrees">
- Degrees to rotate our extrusion for each slice when [member mode] is [constant MODE_SPIN].
- </member>
- <member name="spin_sides" type="int" setter="set_spin_sides" getter="get_spin_sides">
- Number of extrusion when [member mode] is [constant MODE_SPIN].
- </member>
- </members>
- <constants>
- <constant name="MODE_DEPTH" value="0" enum="Mode">
- Shape is extruded to [member depth].
- </constant>
- <constant name="MODE_SPIN" value="1" enum="Mode">
- Shape is extruded by rotating it around an axis.
- </constant>
- <constant name="MODE_PATH" value="2" enum="Mode">
- Shape is extruded along a path set by a [Shape] set in [member path_node].
- </constant>
- <constant name="PATH_ROTATION_POLYGON" value="0" enum="PathRotation">
- Slice is not rotated.
- </constant>
- <constant name="PATH_ROTATION_PATH" value="1" enum="PathRotation">
- Slice is rotated around the up vector of the path.
- </constant>
- <constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation">
- Slice is rotate to match the path exactly.
- </constant>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml
new file mode 100644
index 0000000000..c55fa0983e
--- /dev/null
+++ b/modules/csg/doc_classes/CSGPolygon3D.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.0">
+ <brief_description>
+ Extrudes a 2D polygon shape to create a 3D mesh.
+ </brief_description>
+ <description>
+ This node takes a 2D polygon shape and extrudes it to create a 3D mesh.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
+ Extrusion depth when [member mode] is [constant MODE_DEPTH].
+ </member>
+ <member name="material" type="Material" setter="set_material" getter="get_material">
+ Material to use for the resulting mesh.
+ </member>
+ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon3D.Mode" default="0">
+ Extrusion mode.
+ </member>
+ <member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u">
+ If [code]true[/code] the u component of our uv will continuously increase in unison with the distance traveled along our path when [member mode] is [constant MODE_PATH].
+ </member>
+ <member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval">
+ Interval at which a new extrusion slice is added along the path when [member mode] is [constant MODE_PATH].
+ </member>
+ <member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined">
+ If [code]true[/code] the start and end of our path are joined together ensuring there is no seam when [member mode] is [constant MODE_PATH].
+ </member>
+ <member name="path_local" type="bool" setter="set_path_local" getter="is_path_local">
+ If [code]false[/code] we extrude centered on our path, if [code]true[/code] we extrude in relation to the position of our CSGPolygon3D when [member mode] is [constant MODE_PATH].
+ </member>
+ <member name="path_node" type="NodePath" setter="set_path_node" getter="get_path_node">
+ The [Shape3D] object containing the path along which we extrude when [member mode] is [constant MODE_PATH].
+ </member>
+ <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation">
+ The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH].
+ </member>
+ <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )">
+ Point array that defines the shape that we'll extrude.
+ </member>
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
+ Generates smooth normals so smooth shading is applied to our mesh.
+ </member>
+ <member name="spin_degrees" type="float" setter="set_spin_degrees" getter="get_spin_degrees">
+ Degrees to rotate our extrusion for each slice when [member mode] is [constant MODE_SPIN].
+ </member>
+ <member name="spin_sides" type="int" setter="set_spin_sides" getter="get_spin_sides">
+ Number of extrusion when [member mode] is [constant MODE_SPIN].
+ </member>
+ </members>
+ <constants>
+ <constant name="MODE_DEPTH" value="0" enum="Mode">
+ Shape3D is extruded to [member depth].
+ </constant>
+ <constant name="MODE_SPIN" value="1" enum="Mode">
+ Shape3D is extruded by rotating it around an axis.
+ </constant>
+ <constant name="MODE_PATH" value="2" enum="Mode">
+ Shape3D is extruded along a path set by a [Shape3D] set in [member path_node].
+ </constant>
+ <constant name="PATH_ROTATION_POLYGON" value="0" enum="PathRotation">
+ Slice is not rotated.
+ </constant>
+ <constant name="PATH_ROTATION_PATH" value="1" enum="PathRotation">
+ Slice is rotated around the up vector of the path.
+ </constant>
+ <constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation">
+ Slice is rotate to match the path exactly.
+ </constant>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGPrimitive.xml b/modules/csg/doc_classes/CSGPrimitive.xml
deleted file mode 100644
index ba395b7edd..0000000000
--- a/modules/csg/doc_classes/CSGPrimitive.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPrimitive" inherits="CSGShape" version="4.0">
- <brief_description>
- Base class for CSG primitives.
- </brief_description>
- <description>
- Parent class for various CSG primitives. It contains code and functionality that is common between them. It cannot be used directly. Instead use one of the various classes that inherit from it.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
- Invert the faces of the mesh.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml
new file mode 100644
index 0000000000..31b7360fac
--- /dev/null
+++ b/modules/csg/doc_classes/CSGPrimitive3D.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.0">
+ <brief_description>
+ Base class for CSG primitives.
+ </brief_description>
+ <description>
+ Parent class for various CSG primitives. It contains code and functionality that is common between them. It cannot be used directly. Instead use one of the various classes that inherit from it.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
+ Invert the faces of the mesh.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml
deleted file mode 100644
index 64a2fb1840..0000000000
--- a/modules/csg/doc_classes/CSGShape.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGShape" inherits="GeometryInstance" version="4.0">
- <brief_description>
- The CSG base class.
- </brief_description>
- <description>
- This is the CSG base class that provides CSG operation support to the various CSG nodes in Godot.
- </description>
- <tutorials>
- </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 collision 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_meshes" qualifiers="const">
- <return type="Array">
- </return>
- <description>
- Returns an [Array] with two elements, the first is the [Transform] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape.
- </description>
- </method>
- <method name="is_root_shape" qualifiers="const">
- <return type="bool">
- </return>
- <description>
- Returns [code]true[/code] if this is a root shape and is thus the object that is rendered.
- </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 layer mask. 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 collision mask. Use this if you only need to change one layer's value.
- </description>
- </method>
- </methods>
- <members>
- <member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents" default="true">
- Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child.
- </member>
- <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 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.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this CSG shape scans for collisions.
- </member>
- <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation" default="0">
- The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
- </member>
- <member name="snap" type="float" setter="set_snap" getter="get_snap" default="0.001">
- Snap makes the mesh snap to a given distance so that the faces of two meshes can be perfectly aligned. A lower value results in greater precision but may be harder to adjust.
- </member>
- <member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision" default="false">
- Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden.
- </member>
- </members>
- <constants>
- <constant name="OPERATION_UNION" value="0" enum="Operation">
- Geometry of both primitives is merged, intersecting geometry is removed.
- </constant>
- <constant name="OPERATION_INTERSECTION" value="1" enum="Operation">
- Only intersecting geometry remains, the rest is removed.
- </constant>
- <constant name="OPERATION_SUBTRACTION" value="2" enum="Operation">
- The second shape is subtracted from the first, leaving a dent with its shape.
- </constant>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
new file mode 100644
index 0000000000..43ce988c30
--- /dev/null
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.0">
+ <brief_description>
+ The CSG base class.
+ </brief_description>
+ <description>
+ This is the CSG base class that provides CSG operation support to the various CSG nodes in Godot.
+ </description>
+ <tutorials>
+ </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 collision 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_meshes" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Returns an [Array] with two elements, the first is the [Transform] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape.
+ </description>
+ </method>
+ <method name="is_root_shape" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if this is a root shape and is thus the object that is rendered.
+ </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 layer mask. 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 collision mask. Use this if you only need to change one layer's value.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="calculate_tangents" type="bool" setter="set_calculate_tangents" getter="is_calculating_tangents" default="true">
+ Calculate tangents for the CSG shape which allows the use of normal maps. This is only applied on the root shape, this setting is ignored on any child.
+ </member>
+ <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 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.
+ </member>
+ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The physics layers this CSG shape scans for collisions.
+ </member>
+ <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
+ The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
+ </member>
+ <member name="snap" type="float" setter="set_snap" getter="get_snap" default="0.001">
+ Snap makes the mesh snap to a given distance so that the faces of two meshes can be perfectly aligned. A lower value results in greater precision but may be harder to adjust.
+ </member>
+ <member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision" default="false">
+ Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden.
+ </member>
+ </members>
+ <constants>
+ <constant name="OPERATION_UNION" value="0" enum="Operation">
+ Geometry of both primitives is merged, intersecting geometry is removed.
+ </constant>
+ <constant name="OPERATION_INTERSECTION" value="1" enum="Operation">
+ Only intersecting geometry remains, the rest is removed.
+ </constant>
+ <constant name="OPERATION_SUBTRACTION" value="2" enum="Operation">
+ The second shape is subtracted from the first, leaving a dent with its shape.
+ </constant>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGSphere.xml b/modules/csg/doc_classes/CSGSphere.xml
deleted file mode 100644
index 847cc63586..0000000000
--- a/modules/csg/doc_classes/CSGSphere.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGSphere" inherits="CSGPrimitive" version="4.0">
- <brief_description>
- A CSG Sphere shape.
- </brief_description>
- <description>
- This node allows you to create a sphere for use with the CSG system.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="material" type="Material" setter="set_material" getter="get_material">
- The material used to render the sphere.
- </member>
- <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12">
- Number of vertical slices for the sphere.
- </member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- Radius of the sphere.
- </member>
- <member name="rings" type="int" setter="set_rings" getter="get_rings" default="6">
- Number of horizontal slices for the sphere.
- </member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
- If [code]true[/code] the normals of the sphere are set to give a smooth effect making the sphere seem rounded. If [code]false[/code] the sphere will have a flat shaded look.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
new file mode 100644
index 0000000000..4d5b3be099
--- /dev/null
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.0">
+ <brief_description>
+ A CSG Sphere shape.
+ </brief_description>
+ <description>
+ This node allows you to create a sphere for use with the CSG system.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="material" type="Material" setter="set_material" getter="get_material">
+ The material used to render the sphere.
+ </member>
+ <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12">
+ Number of vertical slices for the sphere.
+ </member>
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ Radius of the sphere.
+ </member>
+ <member name="rings" type="int" setter="set_rings" getter="get_rings" default="6">
+ Number of horizontal slices for the sphere.
+ </member>
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
+ If [code]true[/code] the normals of the sphere are set to give a smooth effect making the sphere seem rounded. If [code]false[/code] the sphere will have a flat shaded look.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/doc_classes/CSGTorus.xml b/modules/csg/doc_classes/CSGTorus.xml
deleted file mode 100644
index 84a08edaf5..0000000000
--- a/modules/csg/doc_classes/CSGTorus.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGTorus" inherits="CSGPrimitive" version="4.0">
- <brief_description>
- A CSG Torus shape.
- </brief_description>
- <description>
- This node allows you to create a torus for use with the CSG system.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0">
- The inner radius of the torus.
- </member>
- <member name="material" type="Material" setter="set_material" getter="get_material">
- The material used to render the torus.
- </member>
- <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="3.0">
- The outer radius of the torus.
- </member>
- <member name="ring_sides" type="int" setter="set_ring_sides" getter="get_ring_sides" default="6">
- The number of edges each ring of the torus is constructed of.
- </member>
- <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
- The number of slices the torus is constructed of.
- </member>
- <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
- If [code]true[/code] the normals of the torus are set to give a smooth effect making the torus seem rounded. If [code]false[/code] the torus will have a flat shaded look.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/csg/doc_classes/CSGTorus3D.xml b/modules/csg/doc_classes/CSGTorus3D.xml
new file mode 100644
index 0000000000..abe3eab913
--- /dev/null
+++ b/modules/csg/doc_classes/CSGTorus3D.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.0">
+ <brief_description>
+ A CSG Torus shape.
+ </brief_description>
+ <description>
+ This node allows you to create a torus for use with the CSG system.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0">
+ The inner radius of the torus.
+ </member>
+ <member name="material" type="Material" setter="set_material" getter="get_material">
+ The material used to render the torus.
+ </member>
+ <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="3.0">
+ The outer radius of the torus.
+ </member>
+ <member name="ring_sides" type="int" setter="set_ring_sides" getter="get_ring_sides" default="6">
+ The number of edges each ring of the torus is constructed of.
+ </member>
+ <member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
+ The number of slices the torus is constructed of.
+ </member>
+ <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="true">
+ If [code]true[/code] the normals of the torus are set to give a smooth effect making the torus seem rounded. If [code]false[/code] the torus will have a flat shaded look.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/csg/icons/CSGBox.svg b/modules/csg/icons/CSGBox3D.svg
index 67e34df444..67e34df444 100644
--- a/modules/csg/icons/CSGBox.svg
+++ b/modules/csg/icons/CSGBox3D.svg
diff --git a/modules/csg/icons/CSGCapsule.svg b/modules/csg/icons/CSGCapsule3D.svg
index 92a7b5a870..92a7b5a870 100644
--- a/modules/csg/icons/CSGCapsule.svg
+++ b/modules/csg/icons/CSGCapsule3D.svg
diff --git a/modules/csg/icons/CSGCombiner.svg b/modules/csg/icons/CSGCombiner3D.svg
index cce2902e24..cce2902e24 100644
--- a/modules/csg/icons/CSGCombiner.svg
+++ b/modules/csg/icons/CSGCombiner3D.svg
diff --git a/modules/csg/icons/CSGCylinder.svg b/modules/csg/icons/CSGCylinder3D.svg
index 645a74c79b..645a74c79b 100644
--- a/modules/csg/icons/CSGCylinder.svg
+++ b/modules/csg/icons/CSGCylinder3D.svg
diff --git a/modules/csg/icons/CSGMesh.svg b/modules/csg/icons/CSGMesh3D.svg
index 6e940a4aa5..6e940a4aa5 100644
--- a/modules/csg/icons/CSGMesh.svg
+++ b/modules/csg/icons/CSGMesh3D.svg
diff --git a/modules/csg/icons/CSGPolygon.svg b/modules/csg/icons/CSGPolygon3D.svg
index 71b03cb8e6..71b03cb8e6 100644
--- a/modules/csg/icons/CSGPolygon.svg
+++ b/modules/csg/icons/CSGPolygon3D.svg
diff --git a/modules/csg/icons/CSGSphere.svg b/modules/csg/icons/CSGSphere3D.svg
index f81b566993..f81b566993 100644
--- a/modules/csg/icons/CSGSphere.svg
+++ b/modules/csg/icons/CSGSphere3D.svg
diff --git a/modules/csg/icons/CSGTorus.svg b/modules/csg/icons/CSGTorus3D.svg
index 3d30aa47b2..3d30aa47b2 100644
--- a/modules/csg/icons/CSGTorus.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp
index 677a20df38..40eef84b1b 100644
--- a/modules/csg/register_types.cpp
+++ b/modules/csg/register_types.cpp
@@ -37,15 +37,15 @@ void register_csg_types() {
#ifndef _3D_DISABLED
- ClassDB::register_virtual_class<CSGShape>();
- ClassDB::register_virtual_class<CSGPrimitive>();
- ClassDB::register_class<CSGMesh>();
- ClassDB::register_class<CSGSphere>();
- ClassDB::register_class<CSGBox>();
- ClassDB::register_class<CSGCylinder>();
- ClassDB::register_class<CSGTorus>();
- ClassDB::register_class<CSGPolygon>();
- ClassDB::register_class<CSGCombiner>();
+ ClassDB::register_virtual_class<CSGShape3D>();
+ ClassDB::register_virtual_class<CSGPrimitive3D>();
+ ClassDB::register_class<CSGMesh3D>();
+ ClassDB::register_class<CSGSphere3D>();
+ ClassDB::register_class<CSGBox3D>();
+ ClassDB::register_class<CSGCylinder3D>();
+ ClassDB::register_class<CSGTorus3D>();
+ ClassDB::register_class<CSGPolygon3D>();
+ ClassDB::register_class<CSGCombiner3D>();
#ifdef TOOLS_ENABLED
EditorPlugins::add_by_type<EditorPluginCSG>();
diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h
index 4eadeea254..926e598561 100644
--- a/modules/csg/register_types.h
+++ b/modules/csg/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef CSG_REGISTER_TYPES_H
+#define CSG_REGISTER_TYPES_H
+
void register_csg_types();
void unregister_csg_types();
+
+#endif // CSG_REGISTER_TYPES_H
diff --git a/modules/cvtt/SCsub b/modules/cvtt/SCsub
index 746b23ca28..5438f7ebac 100644
--- a/modules/cvtt/SCsub
+++ b/modules/cvtt/SCsub
@@ -1,14 +1,14 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_cvtt = env_modules.Clone()
# Thirdparty source files
thirdparty_dir = "#thirdparty/cvtt/"
thirdparty_sources = [
- "ConvectionKernels.cpp"
+ "ConvectionKernels.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/modules/cvtt/config.py b/modules/cvtt/config.py
index 098f1eafa9..53b8f2f2e3 100644
--- a/modules/cvtt/config.py
+++ b/modules/cvtt/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return env['tools']
+ return env["tools"]
+
def configure(env):
pass
diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h
index 93f684cdd1..8472980c6a 100644
--- a/modules/cvtt/register_types.h
+++ b/modules/cvtt/register_types.h
@@ -29,6 +29,13 @@
/*************************************************************************/
#ifdef TOOLS_ENABLED
+
+#ifndef CVTT_REGISTER_TYPES_H
+#define CVTT_REGISTER_TYPES_H
+
void register_cvtt_types();
void unregister_cvtt_types();
-#endif
+
+#endif // CVTT_REGISTER_TYPES_H
+
+#endif // TOOLS_ENABLED
diff --git a/modules/dds/SCsub b/modules/dds/SCsub
index 3d92ff02d6..06980bd670 100644
--- a/modules/dds/SCsub
+++ b/modules/dds/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_dds = env_modules.Clone()
diff --git a/modules/dds/config.py b/modules/dds/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/dds/config.py
+++ b/modules/dds/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/dds/register_types.h b/modules/dds/register_types.h
index 1808a4af36..3cb7b5c2a6 100644
--- a/modules/dds/register_types.h
+++ b/modules/dds/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef DDS_REGISTER_TYPES_H
+#define DDS_REGISTER_TYPES_H
+
void register_dds_types();
void unregister_dds_types();
+
+#endif // DDS_REGISTER_TYPES_H
diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h
index de8088af90..5b89f16277 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 = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/SCsub b/modules/enet/SCsub
index 485c33b1a8..c8f4b3885e 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -1,13 +1,13 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_enet = env_modules.Clone()
# Thirdparty source files
-if env['builtin_enet']:
+if env["builtin_enet"]:
thirdparty_dir = "#thirdparty/enet/"
thirdparty_sources = [
"godot.cpp",
diff --git a/modules/enet/config.py b/modules/enet/config.py
index 3e30bbe778..5fd343c75d 100644
--- a/modules/enet/config.py
+++ b/modules/enet/config.py
@@ -1,13 +1,16 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"NetworkedMultiplayerENet",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 406eb467f0..444ffae713 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -154,7 +154,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por
p_in_bandwidth /* limit incoming bandwidth if > 0 */,
p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
} else {
- host = enet_host_create(NULL /* create a client host */,
+ 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 */,
@@ -197,7 +197,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por
// Initiate connection, allocating enough channels
ENetPeer *peer = enet_host_connect(host, &address, channel_count, unique_id);
- if (peer == NULL) {
+ if (peer == nullptr) {
enet_host_destroy(host);
ERR_FAIL_COND_V_MSG(!peer, ERR_CANT_CREATE, "Couldn't connect to the ENet multiplayer server.");
}
@@ -276,12 +276,12 @@ void NetworkedMultiplayerENet::poll() {
if (E->key() == *new_id)
continue;
// Send existing peers to new peer
- ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
+ ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]);
encode_uint32(E->key(), &packet->data[4]);
enet_peer_send(event.peer, SYSCH_CONFIG, packet);
// Send the new peer to existing peers
- packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
+ packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]);
encode_uint32(*new_id, &packet->data[4]);
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
@@ -320,7 +320,7 @@ void NetworkedMultiplayerENet::poll() {
if (E->key() == *id)
continue;
- ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
+ ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
encode_uint32(*id, &packet->data[4]);
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
@@ -346,7 +346,7 @@ void NetworkedMultiplayerENet::poll() {
switch (msg) {
case SYSMSG_ADD_PEER: {
- peer_map[id] = NULL;
+ peer_map[id] = nullptr;
emit_signal("peer_connected", id);
} break;
@@ -502,7 +502,7 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) {
continue;
}
- ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
+ ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
encode_uint32(p_peer, &packet->data[4]);
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
@@ -568,7 +568,7 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer
if (transfer_channel > SYSCH_CONFIG)
channel = transfer_channel;
- Map<int, ENetPeer *>::Element *E = NULL;
+ Map<int, ENetPeer *>::Element *E = nullptr;
if (target_peer != 0) {
@@ -576,7 +576,7 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer
ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer));
}
- ENetPacket *packet = enet_packet_create(NULL, p_buffer_size + 8, packet_flags);
+ 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);
@@ -625,7 +625,7 @@ void NetworkedMultiplayerENet::_pop_current_packet() {
if (current_packet.packet) {
enet_packet_destroy(current_packet.packet);
- current_packet.packet = NULL;
+ current_packet.packet = nullptr;
current_packet.from = 0;
current_packet.channel = -1;
}
@@ -771,7 +771,7 @@ void NetworkedMultiplayerENet::_setup_compressor() {
case COMPRESS_NONE: {
- enet_host_compress(host, NULL);
+ enet_host_compress(host, nullptr);
} break;
case COMPRESS_RANGE_CODER: {
enet_host_compress_with_range_coder(host);
@@ -794,7 +794,7 @@ IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const {
ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IP_Address(), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IP_Address(), "Can't get the address of peers other than the server (ID -1) when acting as a client.");
- ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == NULL, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
+ ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
IP_Address out;
#ifdef GODOT_ENET
@@ -810,7 +810,7 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const {
ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), 0, vformat("Peer ID %d not found in the list of peers.", p_peer_id));
ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, 0, "Can't get the address of peers other than the server (ID -1) when acting as a client.");
- ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == NULL, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
+ ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
#ifdef GODOT_ENET
return peer_map[p_peer_id]->address.port;
#else
@@ -910,7 +910,7 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() {
server_relay = true;
unique_id = 0;
target_peer = 0;
- current_packet.packet = NULL;
+ current_packet.packet = nullptr;
transfer_mode = TRANSFER_MODE_RELIABLE;
channel_count = SYSCH_MAX;
transfer_channel = -1;
diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h
index 19f8c5a352..cac0a4f7ee 100644
--- a/modules/enet/register_types.h
+++ b/modules/enet/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef ENET_REGISTER_TYPES_H
+#define ENET_REGISTER_TYPES_H
+
void register_enet_types();
void unregister_enet_types();
+
+#endif // ENET_REGISTER_TYPES_H
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
index 1742d3534f..383bbf83c3 100644
--- a/modules/etc/SCsub
+++ b/modules/etc/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_etc = env_modules.Clone()
@@ -9,21 +9,21 @@ env_etc = env_modules.Clone()
# 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",
+ "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]
diff --git a/modules/etc/config.py b/modules/etc/config.py
index 098f1eafa9..53b8f2f2e3 100644
--- a/modules/etc/config.py
+++ b/modules/etc/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return env['tools']
+ return env["tools"]
+
def configure(env):
pass
diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp
index b3f7b1d94f..223830f445 100644
--- a/modules/etc/image_etc.cpp
+++ b/modules/etc/image_etc.cpp
@@ -192,7 +192,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
src_rgba_f[j] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]);
}
- unsigned char *etc_data = NULL;
+ 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);
diff --git a/modules/etc/register_types.h b/modules/etc/register_types.h
index fac83e7d17..247c7213af 100644
--- a/modules/etc/register_types.h
+++ b/modules/etc/register_types.h
@@ -28,5 +28,10 @@
/* 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
diff --git a/modules/etc/texture_loader_pkm.h b/modules/etc/texture_loader_pkm.h
index d6011993e3..989e203994 100644
--- a/modules/etc/texture_loader_pkm.h
+++ b/modules/etc/texture_loader_pkm.h
@@ -36,7 +36,7 @@
class ResourceFormatPKM : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/freetype/SCsub b/modules/freetype/SCsub
index 7b66aa1c76..bfc1658bb4 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -1,14 +1,12 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
-
-from compat import isbasestring
+Import("env")
+Import("env_modules")
env_freetype = env_modules.Clone()
# Thirdparty source files
-if env['builtin_freetype']:
+if env["builtin_freetype"]:
thirdparty_dir = "#thirdparty/freetype/"
thirdparty_sources = [
"src/autofit/autofit.c",
@@ -55,31 +53,31 @@ if env['builtin_freetype']:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- if env['platform'] == 'uwp':
+ if env["platform"] == "uwp":
# Include header for UWP to fix build issues
- env_freetype.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"'])
+ env_freetype.Append(CCFLAGS=["/FI", '"modules/freetype/uwpdef.h"'])
# Globally too, as freetype is used in scene (see bottom)
- env.Append(CCFLAGS=['/FI', '"modules/freetype/uwpdef.h"'])
+ env.Append(CCFLAGS=["/FI", '"modules/freetype/uwpdef.h"'])
env_freetype.Prepend(CPPPATH=[thirdparty_dir + "/include"])
# Also needed in main env for scene/
env.Prepend(CPPPATH=[thirdparty_dir + "/include"])
- env_freetype.Append(CPPDEFINES=['FT2_BUILD_LIBRARY', 'FT_CONFIG_OPTION_USE_PNG'])
- if (env['target'] == 'debug'):
- env_freetype.Append(CPPDEFINES=['ZLIB_DEBUG'])
+ env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG"])
+ if env["target"] == "debug":
+ env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"])
# Also requires libpng headers
- if env['builtin_libpng']:
+ if env["builtin_libpng"]:
env_freetype.Prepend(CPPPATH=["#thirdparty/libpng"])
- sfnt = thirdparty_dir + 'src/sfnt/sfnt.c'
+ sfnt = thirdparty_dir + "src/sfnt/sfnt.c"
# Must be done after all CPPDEFINES are being set so we can copy them.
- if env['platform'] == 'javascript':
+ if env["platform"] == "javascript":
# Forcibly undefine this macro so SIMD is not used in this file,
# since currently unsupported in WASM
tmp_env = env_freetype.Clone()
- tmp_env.Append(CPPFLAGS=['-U__OPTIMIZE__'])
+ tmp_env.Append(CPPFLAGS=["-U__OPTIMIZE__"])
sfnt = tmp_env.Object(sfnt)
thirdparty_sources += [sfnt]
@@ -93,7 +91,7 @@ if env['builtin_freetype']:
# and then plain strings for system library. We insert between the two.
inserted = False
for idx, linklib in enumerate(env["LIBS"]):
- if isbasestring(linklib): # first system lib such as "X11", otherwise SCons lib object
+ if isinstance(linklib, (str, bytes)): # first system lib such as "X11", otherwise SCons lib object
env["LIBS"].insert(idx, lib)
inserted = True
break
diff --git a/modules/freetype/config.py b/modules/freetype/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/freetype/config.py
+++ b/modules/freetype/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/freetype/register_types.h b/modules/freetype/register_types.h
index 336969d079..aa8088d2e8 100644
--- a/modules/freetype/register_types.h
+++ b/modules/freetype/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef FREETYPE_REGISTER_TYPES_H
+#define FREETYPE_REGISTER_TYPES_H
+
void register_freetype_types();
void unregister_freetype_types();
+
+#endif // FREETYPE_REGISTER_TYPES_H
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index a18c75fa27..cab05549d2 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_gdnative = env_modules.Clone()
env_gdnative.add_source_files(env.modules_sources, "gdnative.cpp")
@@ -12,12 +12,12 @@ env_gdnative.add_source_files(env.modules_sources, "nativescript/*.cpp")
env_gdnative.add_source_files(env.modules_sources, "gdnative_library_singleton_editor.cpp")
env_gdnative.add_source_files(env.modules_sources, "gdnative_library_editor_plugin.cpp")
-env_gdnative.Prepend(CPPPATH=['#modules/gdnative/include/'])
+env_gdnative.Prepend(CPPPATH=["#modules/gdnative/include/"])
-Export('env_gdnative')
+Export("env_gdnative")
SConscript("net/SCsub")
-SConscript("arvr/SCsub")
+SConscript("xr/SCsub")
SConscript("pluginscript/SCsub")
SConscript("videodecoder/SCsub")
@@ -25,8 +25,11 @@ SConscript("videodecoder/SCsub")
from platform_methods import run_in_subprocess
import gdnative_builders
-_, gensource = env_gdnative.CommandNoCache(['include/gdnative_api_struct.gen.h', 'gdnative_api_struct.gen.cpp'],
- 'gdnative_api.json', run_in_subprocess(gdnative_builders.build_gdnative_api_struct))
+_, gensource = env_gdnative.CommandNoCache(
+ ["include/gdnative_api_struct.gen.h", "gdnative_api_struct.gen.cpp"],
+ "gdnative_api.json",
+ run_in_subprocess(gdnative_builders.build_gdnative_api_struct),
+)
env_gdnative.add_source_files(env.modules_sources, [gensource])
env.use_ptrcall = True
diff --git a/modules/gdnative/android/android_gdn.cpp b/modules/gdnative/android/android_gdn.cpp
index 4be489cd46..bc39be1813 100644
--- a/modules/gdnative/android/android_gdn.cpp
+++ b/modules/gdnative/android/android_gdn.cpp
@@ -50,7 +50,7 @@ JNIEnv *GDAPI godot_android_get_env() {
#ifdef __ANDROID__
return ThreadAndroid::get_env();
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -59,7 +59,7 @@ jobject GDAPI godot_android_get_activity() {
OS_Android *os_android = (OS_Android *)OS::get_singleton();
return os_android->get_godot_java()->get_activity();
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -68,7 +68,7 @@ jobject GDAPI godot_android_get_surface() {
OS_Android *os_android = (OS_Android *)OS::get_singleton();
return os_android->get_godot_java()->get_surface();
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -83,4 +83,4 @@ bool GDAPI godot_android_is_activity_resumed() {
#ifdef __cplusplus
}
-#endif \ No newline at end of file
+#endif
diff --git a/modules/gdnative/arvr/SCsub b/modules/gdnative/arvr/SCsub
deleted file mode 100644
index 20eaa99592..0000000000
--- a/modules/gdnative/arvr/SCsub
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-Import('env_gdnative')
-
-env_gdnative.add_source_files(env.modules_sources, '*.cpp')
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
deleted file mode 100644
index a033c2b7f9..0000000000
--- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/*************************************************************************/
-/* arvr_interface_gdnative.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "arvr_interface_gdnative.h"
-#include "main/input_default.h"
-#include "servers/arvr/arvr_positional_tracker.h"
-#include "servers/visual/visual_server_globals.h"
-
-void ARVRInterfaceGDNative::_bind_methods() {
- ADD_PROPERTY_DEFAULT("interface_is_initialized", false);
- ADD_PROPERTY_DEFAULT("ar_is_anchor_detection_enabled", false);
-}
-
-ARVRInterfaceGDNative::ARVRInterfaceGDNative() {
- print_verbose("Construct gdnative interface\n");
-
- // we won't have our data pointer until our library gets set
- data = NULL;
-
- interface = NULL;
-}
-
-ARVRInterfaceGDNative::~ARVRInterfaceGDNative() {
- print_verbose("Destruct gdnative interface\n");
-
- if (interface != NULL && is_initialized()) {
- uninitialize();
- };
-
- // cleanup after ourselves
- cleanup();
-}
-
-void ARVRInterfaceGDNative::cleanup() {
- if (interface != NULL) {
- interface->destructor(data);
- data = NULL;
- interface = NULL;
- }
-}
-
-void ARVRInterfaceGDNative::set_interface(const godot_arvr_interface_gdnative *p_interface) {
- // this should only be called once, just being paranoid..
- if (interface) {
- cleanup();
- }
-
- // bind to our interface
- interface = p_interface;
-
- // Now we do our constructing...
- data = interface->constructor((godot_object *)this);
-}
-
-StringName ARVRInterfaceGDNative::get_name() const {
-
- ERR_FAIL_COND_V(interface == NULL, StringName());
-
- godot_string result = interface->get_name(data);
-
- StringName name = *(String *)&result;
-
- godot_string_destroy(&result);
-
- return name;
-}
-
-int ARVRInterfaceGDNative::get_capabilities() const {
- int capabilities;
-
- ERR_FAIL_COND_V(interface == NULL, 0); // 0 = None
-
- capabilities = interface->get_capabilities(data);
-
- return capabilities;
-}
-
-bool ARVRInterfaceGDNative::get_anchor_detection_is_enabled() const {
-
- ERR_FAIL_COND_V(interface == NULL, false);
-
- return interface->get_anchor_detection_is_enabled(data);
-}
-
-void ARVRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
-
- ERR_FAIL_COND(interface == NULL);
-
- interface->set_anchor_detection_is_enabled(data, p_enable);
-}
-
-int ARVRInterfaceGDNative::get_camera_feed_id() {
-
- ERR_FAIL_COND_V(interface == NULL, 0);
-
- if ((interface->version.major > 1) || ((interface->version.major) == 1 && (interface->version.minor >= 1))) {
- return (unsigned int)interface->get_camera_feed_id(data);
- } else {
- return 0;
- }
-}
-
-bool ARVRInterfaceGDNative::is_stereo() {
- bool stereo;
-
- ERR_FAIL_COND_V(interface == NULL, false);
-
- stereo = interface->is_stereo(data);
-
- return stereo;
-}
-
-bool ARVRInterfaceGDNative::is_initialized() const {
-
- ERR_FAIL_COND_V(interface == NULL, false);
-
- return interface->is_initialized(data);
-}
-
-bool ARVRInterfaceGDNative::initialize() {
- ERR_FAIL_COND_V(interface == NULL, false);
-
- bool initialized = interface->initialize(data);
-
- if (initialized) {
- // if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
-
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- if ((arvr_server != NULL) && (arvr_server->get_primary_interface() == NULL)) {
- arvr_server->set_primary_interface(this);
- };
- };
-
- return initialized;
-}
-
-void ARVRInterfaceGDNative::uninitialize() {
- ERR_FAIL_COND(interface == NULL);
-
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- if (arvr_server != NULL) {
- // Whatever happens, make sure this is no longer our primary interface
- arvr_server->clear_primary_interface_if(this);
- }
-
- interface->uninitialize(data);
-}
-
-Size2 ARVRInterfaceGDNative::get_render_targetsize() {
-
- ERR_FAIL_COND_V(interface == NULL, Size2());
-
- godot_vector2 result = interface->get_render_targetsize(data);
- Vector2 *vec = (Vector2 *)&result;
-
- return *vec;
-}
-
-Transform ARVRInterfaceGDNative::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
- Transform *ret;
-
- ERR_FAIL_COND_V(interface == NULL, Transform());
-
- godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform);
-
- ret = (Transform *)&t;
-
- return *ret;
-}
-
-CameraMatrix ARVRInterfaceGDNative::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
- CameraMatrix cm;
-
- ERR_FAIL_COND_V(interface == NULL, CameraMatrix());
-
- interface->fill_projection_for_eye(data, (godot_real *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
-
- return cm;
-}
-
-unsigned int ARVRInterfaceGDNative::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) {
-
- ERR_FAIL_COND_V(interface == NULL, 0);
-
- if ((interface->version.major > 1) || ((interface->version.major) == 1 && (interface->version.minor >= 1))) {
- return (unsigned int)interface->get_external_texture_for_eye(data, (godot_int)p_eye);
- } else {
- return 0;
- }
-}
-
-void ARVRInterfaceGDNative::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
-
- ERR_FAIL_COND(interface == NULL);
-
- interface->commit_for_eye(data, (godot_int)p_eye, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
-}
-
-void ARVRInterfaceGDNative::process() {
- ERR_FAIL_COND(interface == NULL);
-
- interface->process(data);
-}
-
-void ARVRInterfaceGDNative::notification(int p_what) {
- ERR_FAIL_COND(interface == NULL);
-
- // this is only available in interfaces that implement 1.1 or later
- if ((interface->version.major > 1) || ((interface->version.major == 1) && (interface->version.minor > 0))) {
- interface->notification(data, p_what);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// some helper callbacks
-
-extern "C" {
-
-void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface) {
- // If our major version is 0 or bigger then 10, we're likely looking at our constructor pointer from an older plugin
- ERR_FAIL_COND_MSG((p_interface->version.major == 0) || (p_interface->version.major > 10), "GDNative ARVR interfaces build for Godot 3.0 are not supported.");
-
- Ref<ARVRInterfaceGDNative> new_interface;
- new_interface.instance();
- new_interface->set_interface((const godot_arvr_interface_gdnative *)p_interface);
- ARVRServer::get_singleton()->add_interface(new_interface);
-}
-
-godot_real GDAPI godot_arvr_get_worldscale() {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, 1.0);
-
- return arvr_server->get_world_scale();
-}
-
-godot_transform GDAPI godot_arvr_get_reference_frame() {
- godot_transform reference_frame;
- Transform *reference_frame_ptr = (Transform *)&reference_frame;
-
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- if (arvr_server != NULL) {
- *reference_frame_ptr = arvr_server->get_reference_frame();
- } else {
- godot_transform_new_identity(&reference_frame);
- }
-
- return reference_frame;
-}
-
-void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) {
- // blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD
- ARVRInterface::Eyes eye = (ARVRInterface::Eyes)p_eye;
-#if 0
- RID *render_target = (RID *)p_render_target;
-#endif
- Rect2 screen_rect = *(Rect2 *)p_rect;
-
- if (eye == ARVRInterface::EYE_LEFT) {
- screen_rect.size.x /= 2.0;
- } else if (p_eye == ARVRInterface::EYE_RIGHT) {
- screen_rect.size.x /= 2.0;
- screen_rect.position.x += screen_rect.size.x;
- }
-#ifndef _MSC_VER
-#warning this needs to be redone
-#endif
-#if 0
- VSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0);
-#endif
-}
-
-godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target) {
- // In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID
- // This is a handy function to expose that.
-#if 0
- RID *render_target = (RID *)p_render_target;
-
- RID eye_texture = VSG::storage->render_target_get_texture(*render_target);
-#endif
-
-#ifndef _MSC_VER
-#warning need to obtain this ID again
-#endif
- uint32_t texid = 0; //VS::get_singleton()->texture_get_texid(eye_texture);
-
- return texid;
-}
-
-godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, 0);
-
- InputDefault *input = (InputDefault *)Input::get_singleton();
- ERR_FAIL_NULL_V(input, 0);
-
- ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
- new_tracker->set_name(p_device_name);
- new_tracker->set_type(ARVRServer::TRACKER_CONTROLLER);
- if (p_hand == 1) {
- new_tracker->set_hand(ARVRPositionalTracker::TRACKER_LEFT_HAND);
- } else if (p_hand == 2) {
- new_tracker->set_hand(ARVRPositionalTracker::TRACKER_RIGHT_HAND);
- }
-
- // also register as joystick...
- int joyid = input->get_unused_joy_id();
- if (joyid != -1) {
- new_tracker->set_joy_id(joyid);
- input->joy_connection_changed(joyid, true, p_device_name, "");
- }
-
- if (p_tracks_orientation) {
- Basis orientation;
- new_tracker->set_orientation(orientation);
- }
- if (p_tracks_position) {
- Vector3 position;
- new_tracker->set_position(position);
- }
-
- // add our tracker to our server and remember its pointer
- arvr_server->add_tracker(new_tracker);
-
- // note, this ID is only unique within controllers!
- return new_tracker->get_tracker_id();
-}
-
-void GDAPI godot_arvr_remove_controller(godot_int p_controller_id) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- InputDefault *input = (InputDefault *)Input::get_singleton();
- ERR_FAIL_NULL(input);
-
- ARVRPositionalTracker *remove_tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
- if (remove_tracker != NULL) {
- // unset our joystick if applicable
- int joyid = remove_tracker->get_joy_id();
- if (joyid != -1) {
- input->joy_connection_changed(joyid, false, "", "");
- remove_tracker->set_joy_id(-1);
- }
-
- // remove our tracker from our server
- arvr_server->remove_tracker(remove_tracker);
- memdelete(remove_tracker);
- }
-}
-
-void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != NULL) {
- Transform *transform = (Transform *)p_transform;
- if (p_tracks_orientation) {
- tracker->set_orientation(transform->basis);
- }
- if (p_tracks_position) {
- tracker->set_rw_position(transform->origin);
- }
- }
-}
-
-void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- InputDefault *input = (InputDefault *)Input::get_singleton();
- ERR_FAIL_NULL(input);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != NULL) {
- int joyid = tracker->get_joy_id();
- if (joyid != -1) {
- input->joy_button(joyid, p_button, p_is_pressed);
- }
- }
-}
-
-void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- InputDefault *input = (InputDefault *)Input::get_singleton();
- ERR_FAIL_NULL(input);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != NULL) {
- int joyid = tracker->get_joy_id();
- if (joyid != -1) {
- InputDefault::JoyAxis jx;
- jx.min = p_can_be_negative ? -1 : 0;
- jx.value = p_value;
- input->joy_axis(joyid, p_axis, jx);
- }
- }
-}
-
-godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, 0.0);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != NULL) {
- return tracker->get_rumble();
- }
-
- return 0.0;
-}
-}
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h
deleted file mode 100644
index e38eb435c6..0000000000
--- a/modules/gdnative/arvr/arvr_interface_gdnative.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*************************************************************************/
-/* arvr_interface_gdnative.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 ARVR_INTERFACE_GDNATIVE_H
-#define ARVR_INTERFACE_GDNATIVE_H
-
-#include "modules/gdnative/gdnative.h"
-#include "servers/arvr/arvr_interface.h"
-
-/**
- @authors Hinsbart & Karroffel & Mux213
-
- This subclass of our AR/VR interface forms a bridge to GDNative.
-*/
-
-class ARVRInterfaceGDNative : public ARVRInterface {
- GDCLASS(ARVRInterfaceGDNative, ARVRInterface);
-
- void cleanup();
-
-protected:
- const godot_arvr_interface_gdnative *interface;
- void *data;
-
- static void _bind_methods();
-
-public:
- /** general interface information **/
- ARVRInterfaceGDNative();
- ~ARVRInterfaceGDNative();
-
- void set_interface(const godot_arvr_interface_gdnative *p_interface);
-
- virtual StringName get_name() const;
- virtual int get_capabilities() const;
-
- virtual bool is_initialized() const;
- virtual bool initialize();
- virtual void uninitialize();
-
- /** specific to AR **/
- virtual bool get_anchor_detection_is_enabled() const;
- virtual void set_anchor_detection_is_enabled(bool p_enable);
- virtual int get_camera_feed_id();
-
- /** rendering and internal **/
- virtual Size2 get_render_targetsize();
- virtual bool is_stereo();
- virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
-
- // we expose a Vector<float> version of this function to GDNative
- Vector<float> _get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
-
- // and a CameraMatrix version to ARVRServer
- virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
-
- virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye);
- virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
-
- virtual void process();
- virtual void notification(int p_what);
-};
-
-#endif // ARVR_INTERFACE_GDNATIVE_H
diff --git a/modules/gdnative/arvr/config.py b/modules/gdnative/arvr/config.py
deleted file mode 100644
index 53bc827027..0000000000
--- a/modules/gdnative/arvr/config.py
+++ /dev/null
@@ -1,5 +0,0 @@
-def can_build(env, platform):
- return True
-
-def configure(env):
- pass
diff --git a/modules/gdnative/arvr/register_types.cpp b/modules/gdnative/arvr/register_types.cpp
deleted file mode 100644
index 0f6e2bca1a..0000000000
--- a/modules/gdnative/arvr/register_types.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "arvr_interface_gdnative.h"
-
-void register_arvr_types() {
- ClassDB::register_class<ARVRInterfaceGDNative>();
-}
-
-void unregister_arvr_types() {
-}
diff --git a/modules/gdnative/arvr/register_types.h b/modules/gdnative/arvr/register_types.h
deleted file mode 100644
index 815f112fbf..0000000000
--- a/modules/gdnative/arvr/register_types.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-void register_arvr_types();
-void unregister_arvr_types();
diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py
index b9e5afcdf3..4b997e4bfe 100644
--- a/modules/gdnative/config.py
+++ b/modules/gdnative/config.py
@@ -1,13 +1,15 @@
def can_build(env, platform):
return True
+
def configure(env):
env.use_ptrcall = True
+
def get_doc_classes():
return [
"@NativeScript",
- "ARVRInterfaceGDNative",
+ "XRInterfaceGDNative",
"GDNative",
"GDNativeLibrary",
"MultiplayerPeerGDNative",
@@ -20,5 +22,6 @@ def get_doc_classes():
"WebRTCDataChannelGDNative",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
deleted file mode 100644
index e8405b64a3..0000000000
--- a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" version="4.0">
- <brief_description>
- GDNative wrapper for an ARVR interface.
- </brief_description>
- <description>
- This is a wrapper class for GDNative implementations of the ARVR interface. To use a GDNative ARVR interface, simply instantiate this object and set your GDNative library containing the ARVR interface implementation.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 601e132d42..1aab864102 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -4,7 +4,7 @@
An external library containing functions or script classes to use in Godot.
</brief_description>
<description>
- A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [ARVRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on.
+ A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [XRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>
diff --git a/modules/gdnative/doc_classes/XRInterfaceGDNative.xml b/modules/gdnative/doc_classes/XRInterfaceGDNative.xml
new file mode 100644
index 0000000000..13de815793
--- /dev/null
+++ b/modules/gdnative/doc_classes/XRInterfaceGDNative.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="XRInterfaceGDNative" inherits="XRInterface" version="4.0">
+ <brief_description>
+ GDNative wrapper for an XR interface.
+ </brief_description>
+ <description>
+ This is a wrapper class for GDNative implementations of the XR interface. To use a GDNative XR interface, simply instantiate this object and set your GDNative library containing the XR interface implementation.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 33b734f672..d3426044ec 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -48,7 +48,7 @@ static const bool default_reloadable = true;
// Defined in gdnative_api_struct.gen.cpp
extern const godot_gdnative_core_api_struct api_struct;
-Map<String, Vector<Ref<GDNative> > > GDNativeLibrary::loaded_libraries;
+Map<String, Vector<Ref<GDNative>>> GDNativeLibrary::loaded_libraries;
GDNativeLibrary::GDNativeLibrary() {
config_file.instance();
@@ -248,7 +248,7 @@ void GDNativeLibrary::_bind_methods() {
}
GDNative::GDNative() {
- native_handle = NULL;
+ native_handle = nullptr;
initialized = false;
}
@@ -338,7 +338,7 @@ bool GDNative::initialize() {
if (err || !library_init) {
OS::get_singleton()->close_dynamic_library(native_handle);
- native_handle = NULL;
+ native_handle = nullptr;
ERR_PRINT("Failed to obtain " + library->get_symbol_prefix() + "gdnative_init symbol");
return false;
}
@@ -373,7 +373,7 @@ bool GDNative::initialize() {
initialized = true;
if (library->should_load_once() && !GDNativeLibrary::loaded_libraries.has(lib_path)) {
- Vector<Ref<GDNative> > gdnatives;
+ Vector<Ref<GDNative>> gdnatives;
gdnatives.resize(1);
gdnatives.write[0] = Ref<GDNative>(this);
GDNativeLibrary::loaded_libraries.insert(lib_path, gdnatives);
@@ -390,7 +390,7 @@ bool GDNative::terminate() {
}
if (library->should_load_once()) {
- Vector<Ref<GDNative> > *gdnatives = &GDNativeLibrary::loaded_libraries[library->get_current_library_path()];
+ Vector<Ref<GDNative>> *gdnatives = &GDNativeLibrary::loaded_libraries[library->get_current_library_path()];
if (gdnatives->size() > 1) {
// there are other GDNative's still using this library, so we actually don't terminate
gdnatives->erase(Ref<GDNative>(this));
@@ -408,7 +408,7 @@ bool GDNative::terminate() {
Error error = get_symbol(library->get_symbol_prefix() + terminate_symbol, library_terminate);
if (error || !library_terminate) {
OS::get_singleton()->close_dynamic_library(native_handle);
- native_handle = NULL;
+ native_handle = nullptr;
initialized = false;
return true;
}
@@ -426,7 +426,7 @@ bool GDNative::terminate() {
// GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path);
OS::get_singleton()->close_dynamic_library(native_handle);
- native_handle = NULL;
+ native_handle = nullptr;
return true;
}
@@ -466,7 +466,7 @@ Variant GDNative::call_native(StringName p_native_call_type, StringName p_proced
p_procedure_name,
procedure_handle);
- if (err != OK || procedure_handle == NULL) {
+ if (err != OK || procedure_handle == nullptr) {
return Variant();
}
@@ -544,11 +544,11 @@ Error GDNativeLibraryResourceSaver::save(const String &p_path, const RES &p_reso
}
bool GDNativeLibraryResourceSaver::recognize(const RES &p_resource) const {
- return Object::cast_to<GDNativeLibrary>(*p_resource) != NULL;
+ return Object::cast_to<GDNativeLibrary>(*p_resource) != nullptr;
}
void GDNativeLibraryResourceSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
- if (Object::cast_to<GDNativeLibrary>(*p_resource) != NULL) {
+ if (Object::cast_to<GDNativeLibrary>(*p_resource) != nullptr) {
p_extensions->push_back("gdnlib");
}
}
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index b4c5ec9d00..9ef9c706d1 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -47,7 +47,7 @@ class GDNative;
class GDNativeLibrary : public Resource {
GDCLASS(GDNativeLibrary, Resource);
- static Map<String, Vector<Ref<GDNative> > > loaded_libraries;
+ static Map<String, Vector<Ref<GDNative>>> loaded_libraries;
friend class GDNativeLibraryResourceLoader;
friend class GDNative;
diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp
index d996b006a5..3175340448 100644
--- a/modules/gdnative/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative/gdnative.cpp
@@ -95,7 +95,7 @@ godot_class_constructor GDAPI godot_get_class_constructor(const char *p_classnam
ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname));
if (class_info)
return (godot_class_constructor)class_info->creation_func;
- return NULL;
+ return nullptr;
}
godot_dictionary GDAPI godot_get_global_constants() {
@@ -173,14 +173,14 @@ godot_object GDAPI *godot_instance_from_id(godot_int p_instance_id) {
void *godot_get_class_tag(const godot_string_name *p_class) {
StringName class_name = *(StringName *)p_class;
ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name);
- return class_info ? class_info->class_ptr : NULL;
+ return class_info ? class_info->class_ptr : nullptr;
}
godot_object *godot_object_cast_to(const godot_object *p_object, void *p_class_tag) {
- if (!p_object) return NULL;
+ if (!p_object) return nullptr;
Object *o = (Object *)p_object;
- return o->is_class_ptr(p_class_tag) ? (godot_object *)o : NULL;
+ return o->is_class_ptr(p_class_tag) ? (godot_object *)o : nullptr;
}
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index e1d6c0c867..9473a3d419 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -5935,8 +5935,8 @@
]
},
{
- "name": "arvr",
- "type": "ARVR",
+ "name": "xr",
+ "type": "XR",
"version": {
"major": 1,
"minor": 1
@@ -5944,24 +5944,24 @@
"next": null,
"api": [
{
- "name": "godot_arvr_register_interface",
+ "name": "godot_xr_register_interface",
"return_type": "void",
"arguments": [
- ["const godot_arvr_interface_gdnative *", "p_interface"]
+ ["const godot_xr_interface_gdnative *", "p_interface"]
]
},
{
- "name": "godot_arvr_get_worldscale",
+ "name": "godot_xr_get_worldscale",
"return_type": "godot_real",
"arguments": []
},
{
- "name": "godot_arvr_get_reference_frame",
+ "name": "godot_xr_get_reference_frame",
"return_type": "godot_transform",
"arguments": []
},
{
- "name": "godot_arvr_blit",
+ "name": "godot_xr_blit",
"return_type": "void",
"arguments": [
["godot_int", "p_eye"],
@@ -5970,14 +5970,14 @@
]
},
{
- "name": "godot_arvr_get_texid",
+ "name": "godot_xr_get_texid",
"return_type": "godot_int",
"arguments": [
["godot_rid *", "p_render_target"]
]
},
{
- "name": "godot_arvr_add_controller",
+ "name": "godot_xr_add_controller",
"return_type": "godot_int",
"arguments": [
["char *", "p_device_name"],
@@ -5987,14 +5987,14 @@
]
},
{
- "name": "godot_arvr_remove_controller",
+ "name": "godot_xr_remove_controller",
"return_type": "void",
"arguments": [
["godot_int", "p_controller_id"]
]
},
{
- "name": "godot_arvr_set_controller_transform",
+ "name": "godot_xr_set_controller_transform",
"return_type": "void",
"arguments": [
["godot_int", "p_controller_id"],
@@ -6004,7 +6004,7 @@
]
},
{
- "name": "godot_arvr_set_controller_button",
+ "name": "godot_xr_set_controller_button",
"return_type": "void",
"arguments": [
["godot_int", "p_controller_id"],
@@ -6013,7 +6013,7 @@
]
},
{
- "name": "godot_arvr_set_controller_axis",
+ "name": "godot_xr_set_controller_axis",
"return_type": "void",
"arguments": [
["godot_int", "p_controller_id"],
@@ -6023,7 +6023,7 @@
]
},
{
- "name": "godot_arvr_get_controller_rumble",
+ "name": "godot_xr_get_controller_rumble",
"return_type": "godot_real",
"arguments": [
["godot_int", "p_controller_id"]
diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py
index 0d95a65b7e..620935795f 100644
--- a/modules/gdnative/gdnative_builders.py
+++ b/modules/gdnative/gdnative_builders.py
@@ -8,209 +8,249 @@ from platform_methods import subprocess_main
def _spaced(e):
- return e if e[-1] == '*' else e + ' '
+ return e if e[-1] == "*" else e + " "
def _build_gdnative_api_struct_header(api):
out = [
- '/* THIS FILE IS GENERATED DO NOT EDIT */',
- '#ifndef GODOT_GDNATIVE_API_STRUCT_H',
- '#define GODOT_GDNATIVE_API_STRUCT_H',
- '',
- '#include <gdnative/gdnative.h>',
- '#include <android/godot_android.h>',
- '#include <arvr/godot_arvr.h>',
- '#include <nativescript/godot_nativescript.h>',
- '#include <net/godot_net.h>',
- '#include <pluginscript/godot_pluginscript.h>',
- '#include <videodecoder/godot_videodecoder.h>',
- '',
- '#ifdef __cplusplus',
+ "/* THIS FILE IS GENERATED DO NOT EDIT */",
+ "#ifndef GODOT_GDNATIVE_API_STRUCT_H",
+ "#define GODOT_GDNATIVE_API_STRUCT_H",
+ "",
+ "#include <gdnative/gdnative.h>",
+ "#include <android/godot_android.h>",
+ "#include <xr/godot_xr.h>",
+ "#include <nativescript/godot_nativescript.h>",
+ "#include <net/godot_net.h>",
+ "#include <pluginscript/godot_pluginscript.h>",
+ "#include <videodecoder/godot_videodecoder.h>",
+ "",
+ "#ifdef __cplusplus",
'extern "C" {',
- '#endif',
- '',
- 'enum GDNATIVE_API_TYPES {',
- '\tGDNATIVE_' + api['core']['type'] + ','
+ "#endif",
+ "",
+ "enum GDNATIVE_API_TYPES {",
+ "\tGDNATIVE_" + api["core"]["type"] + ",",
]
- for ext in api['extensions']:
- out += ['\tGDNATIVE_EXT_' + ext['type'] + ',']
+ for ext in api["extensions"]:
+ out += ["\tGDNATIVE_EXT_" + ext["type"] + ","]
- out += ['};', '']
+ out += ["};", ""]
def generate_extension_struct(name, ext, include_version=True):
ret_val = []
- if ext['next']:
- ret_val += generate_extension_struct(name, ext['next'])
+ if ext["next"]:
+ ret_val += generate_extension_struct(name, ext["next"])
ret_val += [
- 'typedef struct godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct {',
- '\tunsigned int type;',
- '\tgodot_gdnative_api_version version;',
- '\tconst godot_gdnative_api_struct *next;'
+ "typedef struct godot_gdnative_ext_"
+ + name
+ + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"])))
+ + "_api_struct {",
+ "\tunsigned int type;",
+ "\tgodot_gdnative_api_version version;",
+ "\tconst godot_gdnative_api_struct *next;",
]
- for funcdef in ext['api']:
- args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']])
- ret_val.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+ for funcdef in ext["api"]:
+ args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]])
+ ret_val.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args))
- ret_val += ['} godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct;', '']
+ ret_val += [
+ "} godot_gdnative_ext_"
+ + name
+ + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"])))
+ + "_api_struct;",
+ "",
+ ]
return ret_val
-
def generate_core_extension_struct(core):
ret_val = []
- if core['next']:
- ret_val += generate_core_extension_struct(core['next'])
+ if core["next"]:
+ ret_val += generate_core_extension_struct(core["next"])
ret_val += [
- 'typedef struct godot_gdnative_core_' + ('{0}_{1}'.format(core['version']['major'], core['version']['minor'])) + '_api_struct {',
- '\tunsigned int type;',
- '\tgodot_gdnative_api_version version;',
- '\tconst godot_gdnative_api_struct *next;',
+ "typedef struct godot_gdnative_core_"
+ + ("{0}_{1}".format(core["version"]["major"], core["version"]["minor"]))
+ + "_api_struct {",
+ "\tunsigned int type;",
+ "\tgodot_gdnative_api_version version;",
+ "\tconst godot_gdnative_api_struct *next;",
]
- for funcdef in core['api']:
- args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']])
- ret_val.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+ for funcdef in core["api"]:
+ args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]])
+ ret_val.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args))
- ret_val += ['} godot_gdnative_core_' + '{0}_{1}'.format(core['version']['major'], core['version']['minor']) + '_api_struct;', '']
+ ret_val += [
+ "} godot_gdnative_core_"
+ + "{0}_{1}".format(core["version"]["major"], core["version"]["minor"])
+ + "_api_struct;",
+ "",
+ ]
return ret_val
-
- for ext in api['extensions']:
- name = ext['name']
+ for ext in api["extensions"]:
+ name = ext["name"]
out += generate_extension_struct(name, ext, False)
- if api['core']['next']:
- out += generate_core_extension_struct(api['core']['next'])
+ if api["core"]["next"]:
+ out += generate_core_extension_struct(api["core"]["next"])
out += [
- 'typedef struct godot_gdnative_core_api_struct {',
- '\tunsigned int type;',
- '\tgodot_gdnative_api_version version;',
- '\tconst godot_gdnative_api_struct *next;',
- '\tunsigned int num_extensions;',
- '\tconst godot_gdnative_api_struct **extensions;',
+ "typedef struct godot_gdnative_core_api_struct {",
+ "\tunsigned int type;",
+ "\tgodot_gdnative_api_version version;",
+ "\tconst godot_gdnative_api_struct *next;",
+ "\tunsigned int num_extensions;",
+ "\tconst godot_gdnative_api_struct **extensions;",
]
- for funcdef in api['core']['api']:
- args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']])
- out.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+ for funcdef in api["core"]["api"]:
+ args = ", ".join(["%s%s" % (_spaced(t), n) for t, n in funcdef["arguments"]])
+ out.append("\t%s(*%s)(%s);" % (_spaced(funcdef["return_type"]), funcdef["name"], args))
out += [
- '} godot_gdnative_core_api_struct;',
- '',
- '#ifdef __cplusplus',
- '}',
- '#endif',
- '',
- '#endif // GODOT_GDNATIVE_API_STRUCT_H',
- ''
+ "} godot_gdnative_core_api_struct;",
+ "",
+ "#ifdef __cplusplus",
+ "}",
+ "#endif",
+ "",
+ "#endif // GODOT_GDNATIVE_API_STRUCT_H",
+ "",
]
- return '\n'.join(out)
+ return "\n".join(out)
def _build_gdnative_api_struct_source(api):
- out = [
- '/* THIS FILE IS GENERATED DO NOT EDIT */',
- '',
- '#include <gdnative_api_struct.gen.h>',
- ''
- ]
+ out = ["/* THIS FILE IS GENERATED DO NOT EDIT */", "", "#include <gdnative_api_struct.gen.h>", ""]
def get_extension_struct_name(name, ext, include_version=True):
- return 'godot_gdnative_ext_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_api_struct'
+ return (
+ "godot_gdnative_ext_"
+ + name
+ + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"])))
+ + "_api_struct"
+ )
def get_extension_struct_instance_name(name, ext, include_version=True):
- return 'api_extension_' + name + ('' if not include_version else ('_{0}_{1}'.format(ext['version']['major'], ext['version']['minor']))) + '_struct'
+ return (
+ "api_extension_"
+ + name
+ + ("" if not include_version else ("_{0}_{1}".format(ext["version"]["major"], ext["version"]["minor"])))
+ + "_struct"
+ )
def get_extension_struct_definition(name, ext, include_version=True):
ret_val = []
- if ext['next']:
- ret_val += get_extension_struct_definition(name, ext['next'])
+ if ext["next"]:
+ ret_val += get_extension_struct_definition(name, ext["next"])
ret_val += [
- 'extern const ' + get_extension_struct_name(name, ext, include_version) + ' ' + get_extension_struct_instance_name(name, ext, include_version) + ' = {',
- '\tGDNATIVE_EXT_' + ext['type'] + ',',
- '\t{' + str(ext['version']['major']) + ', ' + str(ext['version']['minor']) + '},',
- '\t' + ('NULL' if not ext['next'] else ('(const godot_gdnative_api_struct *)&' + get_extension_struct_instance_name(name, ext['next']))) + ','
+ "extern const "
+ + get_extension_struct_name(name, ext, include_version)
+ + " "
+ + get_extension_struct_instance_name(name, ext, include_version)
+ + " = {",
+ "\tGDNATIVE_EXT_" + ext["type"] + ",",
+ "\t{" + str(ext["version"]["major"]) + ", " + str(ext["version"]["minor"]) + "},",
+ "\t"
+ + (
+ "nullptr"
+ if not ext["next"]
+ else ("(const godot_gdnative_api_struct *)&" + get_extension_struct_instance_name(name, ext["next"]))
+ )
+ + ",",
]
- for funcdef in ext['api']:
- ret_val.append('\t%s,' % funcdef['name'])
+ for funcdef in ext["api"]:
+ ret_val.append("\t%s," % funcdef["name"])
- ret_val += ['};\n']
+ ret_val += ["};\n"]
return ret_val
-
def get_core_struct_definition(core):
ret_val = []
- if core['next']:
- ret_val += get_core_struct_definition(core['next'])
+ if core["next"]:
+ ret_val += get_core_struct_definition(core["next"])
ret_val += [
- 'extern const godot_gdnative_core_' + ('{0}_{1}_api_struct api_{0}_{1}'.format(core['version']['major'], core['version']['minor'])) + ' = {',
- '\tGDNATIVE_' + core['type'] + ',',
- '\t{' + str(core['version']['major']) + ', ' + str(core['version']['minor']) + '},',
- '\t' + ('NULL' if not core['next'] else ('(const godot_gdnative_api_struct *)& api_{0}_{1}'.format(core['next']['version']['major'], core['next']['version']['minor']))) + ','
+ "extern const godot_gdnative_core_"
+ + ("{0}_{1}_api_struct api_{0}_{1}".format(core["version"]["major"], core["version"]["minor"]))
+ + " = {",
+ "\tGDNATIVE_" + core["type"] + ",",
+ "\t{" + str(core["version"]["major"]) + ", " + str(core["version"]["minor"]) + "},",
+ "\t"
+ + (
+ "nullptr"
+ if not core["next"]
+ else (
+ "(const godot_gdnative_api_struct *)& api_{0}_{1}".format(
+ core["next"]["version"]["major"], core["next"]["version"]["minor"]
+ )
+ )
+ )
+ + ",",
]
- for funcdef in core['api']:
- ret_val.append('\t%s,' % funcdef['name'])
+ for funcdef in core["api"]:
+ ret_val.append("\t%s," % funcdef["name"])
- ret_val += ['};\n']
+ ret_val += ["};\n"]
return ret_val
- for ext in api['extensions']:
- name = ext['name']
+ for ext in api["extensions"]:
+ name = ext["name"]
out += get_extension_struct_definition(name, ext, False)
- out += ['', 'const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {']
+ out += ["", "const godot_gdnative_api_struct *gdnative_extensions_pointers[] = {"]
- for ext in api['extensions']:
- name = ext['name']
- out += ['\t(godot_gdnative_api_struct *)&api_extension_' + name + '_struct,']
+ for ext in api["extensions"]:
+ name = ext["name"]
+ out += ["\t(godot_gdnative_api_struct *)&api_extension_" + name + "_struct,"]
- out += ['};\n']
+ out += ["};\n"]
- if api['core']['next']:
- out += get_core_struct_definition(api['core']['next'])
+ if api["core"]["next"]:
+ out += get_core_struct_definition(api["core"]["next"])
out += [
- 'extern const godot_gdnative_core_api_struct api_struct = {',
- '\tGDNATIVE_' + api['core']['type'] + ',',
- '\t{' + str(api['core']['version']['major']) + ', ' + str(api['core']['version']['minor']) + '},',
- '\t(const godot_gdnative_api_struct *)&api_1_1,',
- '\t' + str(len(api['extensions'])) + ',',
- '\tgdnative_extensions_pointers,',
+ "extern const godot_gdnative_core_api_struct api_struct = {",
+ "\tGDNATIVE_" + api["core"]["type"] + ",",
+ "\t{" + str(api["core"]["version"]["major"]) + ", " + str(api["core"]["version"]["minor"]) + "},",
+ "\t(const godot_gdnative_api_struct *)&api_1_1,",
+ "\t" + str(len(api["extensions"])) + ",",
+ "\tgdnative_extensions_pointers,",
]
- for funcdef in api['core']['api']:
- out.append('\t%s,' % funcdef['name'])
- out.append('};\n')
+ for funcdef in api["core"]["api"]:
+ out.append("\t%s," % funcdef["name"])
+ out.append("};\n")
- return '\n'.join(out)
+ return "\n".join(out)
def build_gdnative_api_struct(target, source, env):
- with open(source[0], 'r') as fd:
+ with open(source[0], "r") as fd:
api = json.load(fd)
header, source = target
- with open(header, 'w') as fd:
+ with open(header, "w") as fd:
fd.write(_build_gdnative_api_struct_header(api))
- with open(source, 'w') as fd:
+ with open(source, "w") as fd:
fd.write(_build_gdnative_api_struct_source(api))
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index db90199e63..10ddd79d3a 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -77,9 +77,9 @@ void GDNativeLibraryEditor::_update_tree() {
platform->set_text(0, E->get().name);
platform->set_metadata(0, E->get().library_extension);
- platform->set_custom_bg_color(0, get_color("prop_category", "Editor"));
- platform->set_custom_bg_color(1, get_color("prop_category", "Editor"));
- platform->set_custom_bg_color(2, get_color("prop_category", "Editor"));
+ platform->set_custom_bg_color(0, get_theme_color("prop_category", "Editor"));
+ platform->set_custom_bg_color(1, get_theme_color("prop_category", "Editor"));
+ platform->set_custom_bg_color(2, get_theme_color("prop_category", "Editor"));
platform->set_selectable(0, false);
platform->set_expand_right(0, true);
@@ -91,35 +91,35 @@ void GDNativeLibraryEditor::_update_tree() {
bit->set_text(0, it->get());
bit->set_metadata(0, target);
bit->set_selectable(0, false);
- bit->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
+ bit->set_custom_bg_color(0, get_theme_color("prop_subsection", "Editor"));
- bit->add_button(1, get_icon("Folder", "EditorIcons"), BUTTON_SELECT_LIBRARY, false, TTR("Select the dynamic library for this entry"));
+ bit->add_button(1, get_theme_icon("Folder", "EditorIcons"), BUTTON_SELECT_LIBRARY, false, TTR("Select the dynamic library for this entry"));
String file = entry_configs[target].library;
if (!file.empty()) {
- bit->add_button(1, get_icon("Clear", "EditorIcons"), BUTTON_CLEAR_LIBRARY, false, TTR("Clear"));
+ bit->add_button(1, get_theme_icon("Clear", "EditorIcons"), BUTTON_CLEAR_LIBRARY, false, TTR("Clear"));
}
bit->set_text(1, file);
- bit->add_button(2, get_icon("Folder", "EditorIcons"), BUTTON_SELECT_DEPENDENCES, false, TTR("Select dependencies of the library for this entry"));
+ bit->add_button(2, get_theme_icon("Folder", "EditorIcons"), BUTTON_SELECT_DEPENDENCES, false, TTR("Select dependencies of the library for this entry"));
Array files = entry_configs[target].dependencies;
if (files.size()) {
- bit->add_button(2, get_icon("Clear", "EditorIcons"), BUTTON_CLEAR_DEPENDENCES, false, TTR("Clear"));
+ bit->add_button(2, get_theme_icon("Clear", "EditorIcons"), BUTTON_CLEAR_DEPENDENCES, false, TTR("Clear"));
}
bit->set_text(2, Variant(files));
- bit->add_button(3, get_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP, false, TTR("Move Up"));
- bit->add_button(3, get_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN, false, TTR("Move Down"));
- bit->add_button(3, get_icon("Remove", "EditorIcons"), BUTTON_ERASE_ENTRY, false, TTR("Remove current entry"));
+ bit->add_button(3, get_theme_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP, false, TTR("Move Up"));
+ bit->add_button(3, get_theme_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN, false, TTR("Move Down"));
+ bit->add_button(3, get_theme_icon("Remove", "EditorIcons"), BUTTON_ERASE_ENTRY, false, TTR("Remove current entry"));
}
TreeItem *new_arch = tree->create_item(platform);
new_arch->set_text(0, TTR("Double click to create a new entry"));
new_arch->set_text_align(0, TreeItem::ALIGN_CENTER);
- new_arch->set_custom_color(0, get_color("accent_color", "Editor"));
+ new_arch->set_custom_color(0, get_theme_color("accent_color", "Editor"));
new_arch->set_expand_right(0, true);
new_arch->set_metadata(1, E->key());
- platform->set_collapsed(collapsed_items.find(E->get().name) != NULL);
+ platform->set_collapsed(collapsed_items.find(E->get().name) != nullptr);
}
filter->set_text(text);
}
@@ -133,15 +133,15 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
if (id == BUTTON_SELECT_LIBRARY || id == BUTTON_SELECT_DEPENDENCES) {
- EditorFileDialog::Mode mode = EditorFileDialog::MODE_OPEN_FILE;
+ EditorFileDialog::FileMode mode = EditorFileDialog::FILE_MODE_OPEN_FILE;
if (id == BUTTON_SELECT_DEPENDENCES)
- mode = EditorFileDialog::MODE_OPEN_FILES;
+ mode = EditorFileDialog::FILE_MODE_OPEN_FILES;
file_dialog->set_meta("target", target);
file_dialog->set_meta("section", section);
file_dialog->clear_filters();
file_dialog->add_filter(Object::cast_to<TreeItem>(item)->get_parent()->get_metadata(0));
- file_dialog->set_mode(mode);
+ file_dialog->set_file_mode(mode);
file_dialog->popup_centered_ratio();
} else if (id == BUTTON_CLEAR_LIBRARY) {
@@ -372,7 +372,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
file_dialog = memnew(EditorFileDialog);
file_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES);
- file_dialog->set_resizable(true);
+ //file_dialog->set_resizable(true);
add_child(file_dialog);
file_dialog->connect("file_selected", callable_mp(this, &GDNativeLibraryEditor::_on_library_selected));
file_dialog->connect("files_selected", callable_mp(this, &GDNativeLibraryEditor::_on_dependencies_selected));
@@ -382,7 +382,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
new_architecture_dialog->set_title(TTR("Add an architecture entry"));
new_architecture_input = memnew(LineEdit);
new_architecture_dialog->add_child(new_architecture_input);
- new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE);
+ // new_architecture_dialog->set_custom_minimum_size(Vector2(300, 80) * EDSCALE);
new_architecture_input->set_anchors_and_margins_preset(PRESET_HCENTER_WIDE, PRESET_MODE_MINSIZE, 5 * EDSCALE);
new_architecture_dialog->get_ok()->connect("pressed", callable_mp(this, &GDNativeLibraryEditor::_on_create_new_entry));
}
diff --git a/modules/gdnative/include/arvr/godot_arvr.h b/modules/gdnative/include/arvr/godot_arvr.h
deleted file mode 100644
index aaef31a855..0000000000
--- a/modules/gdnative/include/arvr/godot_arvr.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*************************************************************************/
-/* godot_arvr.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 GODOT_NATIVEARVR_H
-#define GODOT_NATIVEARVR_H
-
-#include <gdnative/gdnative.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// For future versions of the API we should only add new functions at the end of the structure and use the
-// version info to detect whether a call is available
-
-// Use these to populate version in your plugin
-#define GODOTVR_API_MAJOR 1
-#define GODOTVR_API_MINOR 1
-
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
- void *(*constructor)(godot_object *);
- void (*destructor)(void *);
- godot_string (*get_name)(const void *);
- godot_int (*get_capabilities)(const void *);
- godot_bool (*get_anchor_detection_is_enabled)(const void *);
- void (*set_anchor_detection_is_enabled)(void *, godot_bool);
- godot_bool (*is_stereo)(const void *);
- godot_bool (*is_initialized)(const void *);
- godot_bool (*initialize)(void *);
- void (*uninitialize)(void *);
- godot_vector2 (*get_render_targetsize)(const void *);
- godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *);
- void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real);
- void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
- void (*process)(void *);
- // only in 1.1 onwards
- godot_int (*get_external_texture_for_eye)(void *, godot_int);
- void (*notification)(void *, godot_int);
- godot_int (*get_camera_feed_id)(void *);
-} godot_arvr_interface_gdnative;
-
-void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface);
-
-// helper functions to access ARVRServer data
-godot_real GDAPI godot_arvr_get_worldscale();
-godot_transform GDAPI godot_arvr_get_reference_frame();
-
-// helper functions for rendering
-void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect);
-godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target);
-
-// helper functions for updating ARVR controllers
-godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
-void GDAPI godot_arvr_remove_controller(godot_int p_controller_id);
-void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
-void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed);
-void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative);
-godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !GODOT_NATIVEARVR_H */
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index 1b131c8cf0..dcf2ddb9ca 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -54,7 +54,6 @@ typedef enum {
GODOT_PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
GODOT_PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease)
GODOT_PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
- GODOT_PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat
GODOT_PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
GODOT_PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
GODOT_PROPERTY_HINT_LAYERS_2D_RENDER,
@@ -96,8 +95,6 @@ typedef enum {
GODOT_PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings
GODOT_PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor
GODOT_PROPERTY_USAGE_CATEGORY = 256,
- GODOT_PROPERTY_USAGE_STORE_IF_NONZERO = 512, // FIXME: Obsolete: drop whenever we can break compat
- GODOT_PROPERTY_USAGE_STORE_IF_NONONE = 1024, // FIXME: Obsolete: drop whenever we can break compat
GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE = 2048,
GODOT_PROPERTY_USAGE_RESTART_IF_CHANGED = 4096,
GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE = 8192,
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index 341e7f9e2b..406c3ba663 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -60,7 +60,7 @@ typedef struct {
//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
//depends entirely from the script.
- // Note: You can set those function pointer to NULL if not needed.
+ // Note: You can set those function pointer to nullptr if not needed.
void (*refcount_incremented)(godot_pluginscript_instance_data *p_data);
bool (*refcount_decremented)(godot_pluginscript_instance_data *p_data); // return true if it can die
} godot_pluginscript_instance_desc;
@@ -119,18 +119,18 @@ typedef struct {
const char *name;
const char *type;
const char *extension;
- const char **recognized_extensions; // NULL terminated array
+ const char **recognized_extensions; // nullptr terminated array
godot_pluginscript_language_data *(*init)();
void (*finish)(godot_pluginscript_language_data *p_data);
- const char **reserved_words; // NULL terminated array
- const char **comment_delimiters; // NULL terminated array
- const char **string_delimiters; // NULL terminated array
+ const char **reserved_words; // nullptr terminated array
+ const char **comment_delimiters; // nullptr terminated array
+ const char **string_delimiters; // nullptr terminated array
godot_bool has_named_classes;
godot_bool supports_builtin_mode;
godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name);
godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions);
- int (*find_function)(godot_pluginscript_language_data *p_data, const godot_string *p_function, const godot_string *p_code); // Can be NULL
+ int (*find_function)(godot_pluginscript_language_data *p_data, const godot_string *p_function, const godot_string *p_code); // Can be nullptr
godot_string (*make_function)(godot_pluginscript_language_data *p_data, const godot_string *p_class, const godot_string *p_name, const godot_packed_string_array *p_args);
godot_error (*complete_code)(godot_pluginscript_language_data *p_data, const godot_string *p_code, const godot_string *p_path, godot_object *p_owner, godot_array *r_options, godot_bool *r_force, godot_string *r_call_hint);
void (*auto_indent_code)(godot_pluginscript_language_data *p_data, godot_string *p_code, int p_from_line, int p_to_line);
diff --git a/modules/gdnative/include/xr/godot_xr.h b/modules/gdnative/include/xr/godot_xr.h
new file mode 100644
index 0000000000..22f7f021c4
--- /dev/null
+++ b/modules/gdnative/include/xr/godot_xr.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* godot_xr.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 GODOT_NATIVEXR_H
+#define GODOT_NATIVEXR_H
+
+#include <gdnative/gdnative.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// For future versions of the API we should only add new functions at the end of the structure and use the
+// version info to detect whether a call is available
+
+// Use these to populate version in your plugin
+#define GODOTVR_API_MAJOR 1
+#define GODOTVR_API_MINOR 1
+
+typedef struct {
+ godot_gdnative_api_version version; /* version of our API */
+ void *(*constructor)(godot_object *);
+ void (*destructor)(void *);
+ godot_string (*get_name)(const void *);
+ godot_int (*get_capabilities)(const void *);
+ godot_bool (*get_anchor_detection_is_enabled)(const void *);
+ void (*set_anchor_detection_is_enabled)(void *, godot_bool);
+ godot_bool (*is_stereo)(const void *);
+ godot_bool (*is_initialized)(const void *);
+ godot_bool (*initialize)(void *);
+ void (*uninitialize)(void *);
+ godot_vector2 (*get_render_targetsize)(const void *);
+ godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *);
+ void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real);
+ void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
+ void (*process)(void *);
+ godot_int (*get_external_texture_for_eye)(void *, godot_int);
+ void (*notification)(void *, godot_int);
+ godot_int (*get_camera_feed_id)(void *);
+} godot_xr_interface_gdnative;
+
+void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface);
+
+// helper functions to access XRServer data
+godot_real GDAPI godot_xr_get_worldscale();
+godot_transform GDAPI godot_xr_get_reference_frame();
+
+// helper functions for rendering
+void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect);
+godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target);
+
+// helper functions for updating XR controllers
+godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
+void GDAPI godot_xr_remove_controller(godot_int p_controller_id);
+void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
+void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed);
+void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative);
+godot_real GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !GODOT_NATIVEXR_H */
diff --git a/modules/gdnative/nativescript/SCsub b/modules/gdnative/nativescript/SCsub
index 92c9d6630d..4212e87a87 100644
--- a/modules/gdnative/nativescript/SCsub
+++ b/modules/gdnative/nativescript/SCsub
@@ -1,9 +1,9 @@
#!/usr/bin/env python
-Import('env')
-Import('env_gdnative')
+Import("env")
+Import("env_gdnative")
-env_gdnative.add_source_files(env.modules_sources, '*.cpp')
+env_gdnative.add_source_files(env.modules_sources, "*.cpp")
-if "platform" in env and env["platform"] in ["x11", "iphone"]:
+if "platform" in env and env["platform"] in ["linuxbsd", "iphone"]:
env.Append(LINKFLAGS=["-rdynamic"])
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 850871579b..3c0cfd0484 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -46,7 +46,7 @@ static Error save_file(const String &p_path, const List<String> &p_content) {
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
- for (const List<String>::Element *e = p_content.front(); e != NULL; e = e->next()) {
+ for (const List<String>::Element *e = p_content.front(); e != nullptr; e = e->next()) {
file->store_string(e->get());
}
@@ -98,7 +98,7 @@ struct SignalAPI {
struct EnumAPI {
String name;
- List<Pair<int, String> > values;
+ List<Pair<int, String>> values;
};
struct ClassAPI {
@@ -197,7 +197,7 @@ List<ClassAPI> generate_c_api_classes() {
api.push_back(global_constants_api);
}
- for (List<StringName>::Element *e = classes.front(); e != NULL; e = e->next()) {
+ for (List<StringName>::Element *e = classes.front(); e != nullptr; e = e->next()) {
StringName class_name = e->get();
ClassAPI class_api;
@@ -229,7 +229,7 @@ List<ClassAPI> generate_c_api_classes() {
List<String> constant;
ClassDB::get_integer_constant_list(class_name, &constant, true);
constant.sort_custom<NoCaseComparator>();
- for (List<String>::Element *c = constant.front(); c != NULL; c = c->next()) {
+ for (List<String>::Element *c = constant.front(); c != nullptr; c = c->next()) {
ConstantAPI constant_api;
constant_api.constant_name = c->get();
constant_api.constant_value = ClassDB::get_integer_constant(class_name, c->get());
@@ -284,7 +284,7 @@ List<ClassAPI> generate_c_api_classes() {
ClassDB::get_property_list(class_name, &properties, true);
properties.sort_custom<PropertyInfoComparator>();
- for (List<PropertyInfo>::Element *p = properties.front(); p != NULL; p = p->next()) {
+ for (List<PropertyInfo>::Element *p = properties.front(); p != nullptr; p = p->next()) {
PropertyAPI property_api;
property_api.name = p->get().name;
@@ -312,7 +312,7 @@ List<ClassAPI> generate_c_api_classes() {
ClassDB::get_method_list(class_name, &methods, true);
methods.sort_custom<MethodInfoComparator>();
- for (List<MethodInfo>::Element *m = methods.front(); m != NULL; m = m->next()) {
+ for (List<MethodInfo>::Element *m = methods.front(); m != nullptr; m = m->next()) {
MethodAPI method_api;
MethodBind *method_bind = ClassDB::get_method(class_name, m->get().name);
MethodInfo &method_info = m->get();
@@ -392,10 +392,10 @@ List<ClassAPI> generate_c_api_classes() {
enum_api.name = E->get();
ClassDB::get_enum_constants(class_name, E->get(), &value_names, true);
for (List<StringName>::Element *val_e = value_names.front(); val_e; val_e = val_e->next()) {
- int int_val = ClassDB::get_integer_constant(class_name, val_e->get(), NULL);
+ int int_val = ClassDB::get_integer_constant(class_name, val_e->get(), nullptr);
enum_api.values.push_back(Pair<int, String>(int_val, val_e->get()));
}
- enum_api.values.sort_custom<PairSort<int, String> >();
+ enum_api.values.sort_custom<PairSort<int, String>>();
class_api.enums.push_back(enum_api);
}
}
@@ -417,7 +417,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back("[\n");
- for (const List<ClassAPI>::Element *c = p_api.front(); c != NULL; c = c->next()) {
+ for (const List<ClassAPI>::Element *c = p_api.front(); c != nullptr; c = c->next()) {
ClassAPI api = c->get();
source.push_back("\t{\n");
@@ -497,7 +497,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back("\t\t\t{\n");
source.push_back("\t\t\t\t\"name\": \"" + e->get().name + "\",\n");
source.push_back("\t\t\t\t\"values\": {\n");
- for (List<Pair<int, String> >::Element *val_e = e->get().values.front(); val_e; val_e = val_e->next()) {
+ for (List<Pair<int, String>>::Element *val_e = e->get().values.front(); val_e; val_e = val_e->next()) {
source.push_back("\t\t\t\t\t\"" + val_e->get().second + "\": " + itos(val_e->get().first));
source.push_back(String((val_e->next() ? "," : "")) + "\n");
}
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index f953206a34..0502458b4f 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -77,7 +77,7 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char
}
} else {
- desc.base_data = NULL;
+ desc.base_data = nullptr;
desc.base_native_type = p_base;
}
@@ -111,7 +111,7 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const
}
} else {
- desc.base_data = NULL;
+ desc.base_data = nullptr;
desc.base_native_type = p_base;
}
@@ -210,11 +210,11 @@ void GDAPI godot_nativescript_register_signal(void *p_gdnative_handle, const cha
void GDAPI *godot_nativescript_get_userdata(godot_object *p_instance) {
Object *instance = (Object *)p_instance;
if (!instance)
- return NULL;
+ return nullptr;
if (instance->get_script_instance() && instance->get_script_instance()->get_language() == NativeScriptLanguage::get_singleton()) {
return ((NativeScriptInstance *)instance->get_script_instance())->userdata;
}
- return NULL;
+ return nullptr;
}
/*
@@ -319,18 +319,18 @@ const void GDAPI *godot_nativescript_get_type_tag(const godot_object *p_object)
const Object *o = (Object *)p_object;
if (!o->get_script_instance()) {
- return NULL;
+ return nullptr;
} else {
NativeScript *script = Object::cast_to<NativeScript>(o->get_script_instance()->get_script().ptr());
if (!script) {
- return NULL;
+ return nullptr;
}
if (script->get_script_desc())
return script->get_script_desc()->type_tag;
}
- return NULL;
+ return nullptr;
}
int GDAPI godot_nativescript_register_instance_binding_data_functions(godot_instance_binding_functions p_binding_functions) {
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index d0e196b3e6..bf458c15ee 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -204,7 +204,7 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) {
NativeScriptDesc *script_data = get_script_desc();
if (!script_data) {
- return NULL;
+ return nullptr;
}
NativeScriptInstance *nsi = memnew(NativeScriptInstance);
@@ -214,7 +214,7 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) {
#ifndef TOOLS_ENABLED
if (!ScriptServer::is_scripting_enabled()) {
- nsi->userdata = NULL;
+ nsi->userdata = nullptr;
} else {
nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data);
}
@@ -240,7 +240,7 @@ PlaceHolderScriptInstance *NativeScript::placeholder_instance_create(Object *p_t
return sins;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -738,7 +738,7 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
r_error.error = Callable::CallError::CALL_OK;
REF ref;
- Object *owner = NULL;
+ Object *owner = nullptr;
if (!(script_data->base_native_type == "")) {
owner = ClassDB::instance(script_data->base_native_type);
@@ -886,7 +886,7 @@ void NativeScriptInstance::get_property_list(List<PropertyInfo> *p_properties) c
E->get().method.method_data,
userdata,
0,
- NULL);
+ nullptr);
Variant res = *(Variant *)&result;
godot_variant_destroy(&result);
@@ -1007,7 +1007,7 @@ void NativeScriptInstance::notification(int p_notification) {
String NativeScriptInstance::to_string(bool *r_valid) {
if (has_method(CoreStringNames::get_singleton()->_to_string)) {
Callable::CallError ce;
- Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
+ Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
if (r_valid)
@@ -1026,7 +1026,7 @@ String NativeScriptInstance::to_string(bool *r_valid) {
void NativeScriptInstance::refcount_incremented() {
Callable::CallError err;
- call("_refcount_incremented", NULL, 0, err);
+ call("_refcount_incremented", nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK && err.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) {
ERR_PRINT("Failed to invoke _refcount_incremented - should not happen");
}
@@ -1034,7 +1034,7 @@ void NativeScriptInstance::refcount_incremented() {
bool NativeScriptInstance::refcount_decremented() {
Callable::CallError err;
- Variant ret = call("_refcount_decremented", NULL, 0, err);
+ Variant ret = call("_refcount_decremented", nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK && err.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) {
ERR_PRINT("Failed to invoke _refcount_decremented - should not happen");
return true; // assume we can destroy the object
@@ -1139,16 +1139,16 @@ NativeScriptLanguage *NativeScriptLanguage::singleton;
void NativeScriptLanguage::_unload_stuff(bool p_reload) {
- Map<String, Ref<GDNative> > erase_and_unload;
+ Map<String, Ref<GDNative>> erase_and_unload;
- for (Map<String, Map<StringName, NativeScriptDesc> >::Element *L = library_classes.front(); L; L = L->next()) {
+ for (Map<String, Map<StringName, NativeScriptDesc>>::Element *L = library_classes.front(); L; L = L->next()) {
String lib_path = L->key();
Map<StringName, NativeScriptDesc> classes = L->get();
if (p_reload) {
- Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path);
Ref<GDNative> gdn;
if (E) {
@@ -1169,7 +1169,7 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) {
}
}
- Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path);
Ref<GDNative> gdn;
if (E) {
@@ -1204,7 +1204,7 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) {
erase_and_unload.insert(lib_path, gdn);
}
- for (Map<String, Ref<GDNative> >::Element *E = erase_and_unload.front(); E; E = E->next()) {
+ for (Map<String, Ref<GDNative>>::Element *E = erase_and_unload.front(); E; E = E->next()) {
String lib_path = E->key();
Ref<GDNative> gdn = E->get();
@@ -1247,7 +1247,7 @@ NativeScriptLanguage::NativeScriptLanguage() {
NativeScriptLanguage::~NativeScriptLanguage() {
- for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
+ for (Map<String, Ref<GDNative>>::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
Ref<GDNative> lib = L->get();
// only shut down valid libs, duh!
@@ -1385,7 +1385,7 @@ void NativeScriptLanguage::get_recognized_extensions(List<String> *p_extensions)
void NativeScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
}
-void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
+void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const {
}
void NativeScriptLanguage::profiling_start() {
@@ -1525,14 +1525,14 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) {
}
void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) {
- ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), NULL);
+ ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), nullptr);
- ERR_FAIL_COND_V_MSG(!binding_functions[p_idx].first, NULL, "Tried to get binding data for a nativescript binding that does not exist.");
+ ERR_FAIL_COND_V_MSG(!binding_functions[p_idx].first, nullptr, "Tried to get binding data for a nativescript binding that does not exist.");
Vector<void *> *binding_data = (Vector<void *> *)p_object->get_script_instance_binding(lang_idx);
if (!binding_data)
- return NULL; // should never happen.
+ return nullptr; // should never happen.
if (binding_data->size() <= p_idx) {
// okay, add new elements here.
@@ -1541,7 +1541,7 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec
binding_data->resize(p_idx + 1);
for (int i = old_size; i <= p_idx; i++) {
- (*binding_data).write[i] = NULL;
+ (*binding_data).write[i] = nullptr;
}
}
@@ -1563,7 +1563,7 @@ void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) {
binding_data->resize(binding_functions.size());
for (int i = 0; i < binding_functions.size(); i++) {
- (*binding_data).write[i] = NULL;
+ (*binding_data).write[i] = nullptr;
}
binding_instances.insert(binding_data);
@@ -1652,12 +1652,12 @@ void NativeScriptLanguage::set_global_type_tag(int p_idx, StringName p_class_nam
const void *NativeScriptLanguage::get_global_type_tag(int p_idx, StringName p_class_name) const {
if (!global_type_tags.has(p_idx))
- return NULL;
+ return nullptr;
const HashMap<StringName, const void *> &tags = global_type_tags[p_idx];
if (!tags.has(p_class_name))
- return NULL;
+ return nullptr;
const void *tag = tags.get(p_class_name);
@@ -1679,7 +1679,7 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) {
// See if this library was "registered" already.
const String &lib_path = lib->get_current_library_path();
ERR_FAIL_COND_MSG(lib_path.length() == 0, lib->get_name() + " does not have a library for the current platform.");
- Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path);
+ Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path);
if (!E) {
Ref<GDNative> gdn;
@@ -1719,7 +1719,7 @@ void NativeScriptLanguage::register_script(NativeScript *script) {
void NativeScriptLanguage::unregister_script(NativeScript *script) {
MutexLock lock(mutex);
- Map<String, Set<NativeScript *> >::Element *S = library_script_users.find(script->lib_path);
+ Map<String, Set<NativeScript *>>::Element *S = library_script_users.find(script->lib_path);
if (S) {
S->get().erase(script);
if (S->get().size() == 0) {
@@ -1733,7 +1733,7 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
// library_gdnatives is modified only from the main thread, so it's safe not to use mutex here
- for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) {
+ for (Map<String, Ref<GDNative>>::Element *L = library_gdnatives.front(); L; L = L->next()) {
if (L->get().is_null()) {
continue;
@@ -1755,7 +1755,7 @@ void NativeScriptLanguage::frame() {
#ifndef NO_THREADS
if (has_objects_to_register) {
MutexLock lock(mutex);
- for (Set<Ref<GDNativeLibrary> >::Element *L = libs_to_init.front(); L; L = L->next()) {
+ for (Set<Ref<GDNativeLibrary>>::Element *L = libs_to_init.front(); L; L = L->next()) {
init_library(L->get());
}
libs_to_init.clear();
@@ -1827,14 +1827,14 @@ void NativeReloadNode::_notification(int p_what) {
#ifdef TOOLS_ENABLED
switch (p_what) {
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_WM_FOCUS_OUT: {
if (unloaded)
break;
MutexLock lock(NSL->mutex);
NSL->_unload_stuff(true);
- for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
+ for (Map<String, Ref<GDNative>>::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
Ref<GDNative> gdn = L->get();
@@ -1862,14 +1862,14 @@ void NativeReloadNode::_notification(int p_what) {
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_FOCUS_IN: {
if (!unloaded)
break;
MutexLock lock(NSL->mutex);
Set<StringName> libs_to_remove;
- for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
+ for (Map<String, Ref<GDNative>>::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
Ref<GDNative> gdn = L->get();
@@ -1904,7 +1904,7 @@ void NativeReloadNode::_notification(int p_what) {
((void (*)(void *))proc_ptr)((void *)&L->key());
}
- for (Map<String, Set<NativeScript *> >::Element *U = NSL->library_script_users.front(); U; U = U->next()) {
+ for (Map<String, Set<NativeScript *>>::Element *U = NSL->library_script_users.front(); U; U = U->next()) {
for (Set<NativeScript *>::Element *S = U->get().front(); S; S = S->next()) {
NativeScript *script = S->get();
@@ -1956,7 +1956,7 @@ Error ResourceFormatSaverNativeScript::save(const String &p_path, const RES &p_r
}
bool ResourceFormatSaverNativeScript::recognize(const RES &p_resource) const {
- return Object::cast_to<NativeScript>(*p_resource) != NULL;
+ return Object::cast_to<NativeScript>(*p_resource) != nullptr;
}
void ResourceFormatSaverNativeScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 90542c96b7..75bbb42664 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -95,7 +95,7 @@ struct NativeScriptDesc {
base(),
base_native_type(),
documentation(),
- type_tag(NULL) {
+ type_tag(nullptr) {
zeromem(&create_func, sizeof(godot_instance_create_func));
zeromem(&destroy_func, sizeof(godot_instance_destroy_func));
}
@@ -263,7 +263,7 @@ private:
Mutex mutex;
#ifndef NO_THREADS
- Set<Ref<GDNativeLibrary> > libs_to_init;
+ Set<Ref<GDNativeLibrary>> libs_to_init;
Set<NativeScript *> scripts_to_register;
volatile bool 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);
@@ -275,10 +275,10 @@ private:
void call_libraries_cb(const StringName &name);
- Vector<Pair<bool, godot_instance_binding_functions> > binding_functions;
+ Vector<Pair<bool, godot_instance_binding_functions>> binding_functions;
Set<Vector<void *> *> binding_instances;
- Map<int, HashMap<StringName, const void *> > global_type_tags;
+ Map<int, HashMap<StringName, const void *>> global_type_tags;
struct ProfileData {
StringName signature;
@@ -298,10 +298,10 @@ private:
public:
// These two maps must only be touched on the main thread
- Map<String, Map<StringName, NativeScriptDesc> > library_classes;
- Map<String, Ref<GDNative> > library_gdnatives;
+ Map<String, Map<StringName, NativeScriptDesc>> library_classes;
+ Map<String, Ref<GDNative>> library_gdnatives;
- Map<String, Set<NativeScript *> > library_script_users;
+ Map<String, Set<NativeScript *>> library_script_users;
StringName _init_call_type;
StringName _init_call_name;
@@ -341,7 +341,7 @@ public:
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -362,7 +362,7 @@ public:
virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_public_functions(List<MethodInfo> *p_functions) const;
- virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const;
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const;
virtual void profiling_start();
virtual void profiling_stop();
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max);
@@ -389,7 +389,7 @@ public:
inline NativeScriptDesc *NativeScript::get_script_desc() const {
Map<StringName, NativeScriptDesc>::Element *E = NativeScriptLanguage::singleton->library_classes[lib_path].find(class_name);
- return E ? &E->get() : NULL;
+ return E ? &E->get() : nullptr;
}
class NativeReloadNode : public Node {
@@ -406,7 +406,7 @@ public:
class ResourceFormatLoaderNativeScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/nativescript/register_types.h b/modules/gdnative/nativescript/register_types.h
index 8fcecb9836..088bf38dd5 100644
--- a/modules/gdnative/nativescript/register_types.h
+++ b/modules/gdnative/nativescript/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef NATIVESCRIPT_REGISTER_TYPES_H
+#define NATIVESCRIPT_REGISTER_TYPES_H
+
void register_nativescript_types();
void unregister_nativescript_types();
+
+#endif // NATIVESCRIPT_REGISTER_TYPES_H
diff --git a/modules/gdnative/net/SCsub b/modules/gdnative/net/SCsub
index 18ab9986b0..b76500c003 100644
--- a/modules/gdnative/net/SCsub
+++ b/modules/gdnative/net/SCsub
@@ -1,13 +1,12 @@
#!/usr/bin/env python
-Import('env')
-Import('env_gdnative')
+Import("env")
+Import("env_gdnative")
env_net = env_gdnative.Clone()
has_webrtc = env_net["module_webrtc_enabled"]
if has_webrtc:
- env_net.Append(CPPDEFINES=['WEBRTC_GDNATIVE_ENABLED'])
-
-env_net.add_source_files(env.modules_sources, '*.cpp')
+ env_net.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"])
+env_net.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
index 8c43a79cc5..a95697ea65 100644
--- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp
+++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
@@ -31,7 +31,7 @@
#include "multiplayer_peer_gdnative.h"
MultiplayerPeerGDNative::MultiplayerPeerGDNative() {
- interface = NULL;
+ interface = nullptr;
}
MultiplayerPeerGDNative::~MultiplayerPeerGDNative() {
@@ -42,73 +42,73 @@ void MultiplayerPeerGDNative::set_native_multiplayer_peer(const godot_net_multip
}
Error MultiplayerPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size);
}
Error MultiplayerPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size);
}
int MultiplayerPeerGDNative::get_max_packet_size() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_max_packet_size(interface->data);
}
int MultiplayerPeerGDNative::get_available_packet_count() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_available_packet_count(interface->data);
}
/* NetworkedMultiplayerPeer */
void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->set_transfer_mode(interface->data, (godot_int)p_mode);
}
NetworkedMultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const {
- ERR_FAIL_COND_V(interface == NULL, TRANSFER_MODE_UNRELIABLE);
+ ERR_FAIL_COND_V(interface == nullptr, TRANSFER_MODE_UNRELIABLE);
return (TransferMode)interface->get_transfer_mode(interface->data);
}
void MultiplayerPeerGDNative::set_target_peer(int p_peer_id) {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->set_target_peer(interface->data, p_peer_id);
}
int MultiplayerPeerGDNative::get_packet_peer() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_packet_peer(interface->data);
}
bool MultiplayerPeerGDNative::is_server() const {
- ERR_FAIL_COND_V(interface == NULL, false);
+ ERR_FAIL_COND_V(interface == nullptr, false);
return interface->is_server(interface->data);
}
void MultiplayerPeerGDNative::poll() {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->poll(interface->data);
}
int MultiplayerPeerGDNative::get_unique_id() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_unique_id(interface->data);
}
void MultiplayerPeerGDNative::set_refuse_new_connections(bool p_enable) {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->set_refuse_new_connections(interface->data, p_enable);
}
bool MultiplayerPeerGDNative::is_refusing_new_connections() const {
- ERR_FAIL_COND_V(interface == NULL, true);
+ ERR_FAIL_COND_V(interface == nullptr, true);
return interface->is_refusing_new_connections(interface->data);
}
NetworkedMultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const {
- ERR_FAIL_COND_V(interface == NULL, CONNECTION_DISCONNECTED);
+ ERR_FAIL_COND_V(interface == nullptr, CONNECTION_DISCONNECTED);
return (ConnectionStatus)interface->get_connection_status(interface->data);
}
diff --git a/modules/gdnative/net/packet_peer_gdnative.cpp b/modules/gdnative/net/packet_peer_gdnative.cpp
index 75e1e0b824..28135df3b6 100644
--- a/modules/gdnative/net/packet_peer_gdnative.cpp
+++ b/modules/gdnative/net/packet_peer_gdnative.cpp
@@ -31,7 +31,7 @@
#include "packet_peer_gdnative.h"
PacketPeerGDNative::PacketPeerGDNative() {
- interface = NULL;
+ interface = nullptr;
}
PacketPeerGDNative::~PacketPeerGDNative() {
@@ -45,22 +45,22 @@ void PacketPeerGDNative::_bind_methods() {
}
Error PacketPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size);
}
Error PacketPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size);
}
int PacketPeerGDNative::get_max_packet_size() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_max_packet_size(interface->data);
}
int PacketPeerGDNative::get_available_packet_count() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_available_packet_count(interface->data);
}
diff --git a/modules/gdnative/net/register_types.h b/modules/gdnative/net/register_types.h
index 526bc49deb..70b266f9b9 100644
--- a/modules/gdnative/net/register_types.h
+++ b/modules/gdnative/net/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef NET_REGISTER_TYPES_H
+#define NET_REGISTER_TYPES_H
+
void register_net_types();
void unregister_net_types();
+
+#endif // NET_REGISTER_TYPES_H
diff --git a/modules/gdnative/net/stream_peer_gdnative.cpp b/modules/gdnative/net/stream_peer_gdnative.cpp
index 22634daf5f..9dcb184115 100644
--- a/modules/gdnative/net/stream_peer_gdnative.cpp
+++ b/modules/gdnative/net/stream_peer_gdnative.cpp
@@ -31,7 +31,7 @@
#include "stream_peer_gdnative.h"
StreamPeerGDNative::StreamPeerGDNative() {
- interface = NULL;
+ interface = nullptr;
}
StreamPeerGDNative::~StreamPeerGDNative() {
@@ -45,27 +45,27 @@ void StreamPeerGDNative::_bind_methods() {
}
Error StreamPeerGDNative::put_data(const uint8_t *p_data, int p_bytes) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)(interface->put_data(interface->data, p_data, p_bytes));
}
Error StreamPeerGDNative::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)(interface->put_partial_data(interface->data, p_data, p_bytes, &r_sent));
}
Error StreamPeerGDNative::get_data(uint8_t *p_buffer, int p_bytes) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)(interface->get_data(interface->data, p_buffer, p_bytes));
}
Error StreamPeerGDNative::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)(interface->get_partial_data(interface->data, p_buffer, p_bytes, &r_received));
}
int StreamPeerGDNative::get_available_bytes() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_available_bytes(interface->data);
}
diff --git a/modules/gdnative/pluginscript/SCsub b/modules/gdnative/pluginscript/SCsub
index 20eaa99592..0b2db3b504 100644
--- a/modules/gdnative/pluginscript/SCsub
+++ b/modules/gdnative/pluginscript/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
-Import('env_gdnative')
+Import("env")
+Import("env_gdnative")
-env_gdnative.add_source_files(env.modules_sources, '*.cpp')
+env_gdnative.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 22e8372130..7d17a7d5ab 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -156,7 +156,7 @@ bool PluginScriptInstance::init(PluginScript *p_script, Object *p_owner) {
_script = Ref<PluginScript>(p_script);
_desc = &p_script->_desc->instance_desc;
_data = _desc->init(p_script->_data, (godot_object *)p_owner);
- ERR_FAIL_COND_V(_data == NULL, false);
+ ERR_FAIL_COND_V(_data == nullptr, false);
p_owner->set_script_instance(this);
return true;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index c91ad643a7..6309b6fde3 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -55,7 +55,7 @@ public:
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index a40b59bb2e..bccbe95033 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -210,7 +210,7 @@ void PluginScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) c
}
}
-void PluginScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
+void PluginScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const {
// TODO: provide this statically in `godot_pluginscript_language_desc` ?
if (_desc.get_public_constants) {
Dictionary constants;
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index 3f0d2b8d3d..dd6758713f 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -74,7 +74,7 @@ public:
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -112,7 +112,7 @@ public:
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_public_functions(List<MethodInfo> *p_functions) const;
- virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const;
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const;
virtual void profiling_start();
virtual void profiling_stop();
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp
index 46db20b6c2..3fb22b3f8d 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp
@@ -109,5 +109,5 @@ void ResourceFormatSaverPluginScript::get_recognized_extensions(const RES &p_res
bool ResourceFormatSaverPluginScript::recognize(const RES &p_resource) const {
- return Object::cast_to<PluginScript>(*p_resource) != NULL;
+ return Object::cast_to<PluginScript>(*p_resource) != nullptr;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h
index a039072fdc..c929be53bd 100644
--- a/modules/gdnative/pluginscript/pluginscript_loader.h
+++ b/modules/gdnative/pluginscript/pluginscript_loader.h
@@ -44,7 +44,7 @@ class ResourceFormatLoaderPluginScript : public ResourceFormatLoader {
public:
ResourceFormatLoaderPluginScript(PluginScriptLanguage *language);
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index b7cbedc51a..a4c84dc0ca 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -69,7 +69,7 @@ PluginScriptInstance *PluginScript::_create_instance(const Variant **p_args, int
} else {
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
memdelete(instance);
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
// Construct
@@ -93,7 +93,7 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
}
REF ref;
- Object *owner = NULL;
+ Object *owner = nullptr;
if (get_instance_base_type() == "") {
owner = memnew(Reference);
@@ -175,7 +175,7 @@ void PluginScript::update_exports() {
// TODO: rename p_this "p_owner" ?
ScriptInstance *PluginScript::instance_create(Object *p_this) {
- ASSERT_SCRIPT_VALID_V(NULL);
+ ASSERT_SCRIPT_VALID_V(nullptr);
// TODO check script validity ?
if (!_tool && !ScriptServer::is_scripting_enabled()) {
#ifdef TOOLS_ENABLED
@@ -185,7 +185,7 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) {
update_exports();
return si;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -197,12 +197,12 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) {
// if (EngineDebugger::is_active()) {
// _language->debug_break_parse(get_path(), 0, msg);
// }
- ERR_FAIL_V_MSG(NULL, msg);
+ ERR_FAIL_V_MSG(nullptr, msg);
}
}
Callable::CallError unchecked_error;
- return _create_instance(NULL, 0, p_this, unchecked_error);
+ return _create_instance(nullptr, 0, p_this, unchecked_error);
}
bool PluginScript::instance_has(const Object *p_this) const {
@@ -296,7 +296,7 @@ Error PluginScript::reload(bool p_keep_state) {
_tool = manifest.is_tool;
Dictionary *members = (Dictionary *)&manifest.member_lines;
- for (const Variant *key = members->next(); key != NULL; key = members->next(key)) {
+ for (const Variant *key = members->next(); key != nullptr; key = members->next(key)) {
_member_lines[*key] = (*members)[*key];
}
Array *methods = (Array *)&manifest.methods;
@@ -366,14 +366,14 @@ Error PluginScript::reload(bool p_keep_state) {
void PluginScript::get_script_method_list(List<MethodInfo> *r_methods) const {
ASSERT_SCRIPT_VALID();
- for (Map<StringName, MethodInfo>::Element *e = _methods_info.front(); e != NULL; e = e->next()) {
+ for (Map<StringName, MethodInfo>::Element *e = _methods_info.front(); e != nullptr; e = e->next()) {
r_methods->push_back(e->get());
}
}
void PluginScript::get_script_property_list(List<PropertyInfo> *r_properties) const {
ASSERT_SCRIPT_VALID();
- for (Map<StringName, PropertyInfo>::Element *e = _properties_info.front(); e != NULL; e = e->next()) {
+ for (Map<StringName, PropertyInfo>::Element *e = _properties_info.front(); e != nullptr; e = e->next()) {
r_properties->push_back(e->get());
}
}
@@ -386,7 +386,7 @@ bool PluginScript::has_method(const StringName &p_method) const {
MethodInfo PluginScript::get_method_info(const StringName &p_method) const {
ASSERT_SCRIPT_VALID_V(MethodInfo());
const Map<StringName, MethodInfo>::Element *e = _methods_info.find(p_method);
- if (e != NULL) {
+ if (e != nullptr) {
return e->get();
} else {
return MethodInfo();
@@ -401,7 +401,7 @@ bool PluginScript::has_property(const StringName &p_method) const {
PropertyInfo PluginScript::get_property_info(const StringName &p_property) const {
ASSERT_SCRIPT_VALID_V(PropertyInfo());
const Map<StringName, PropertyInfo>::Element *e = _properties_info.find(p_property);
- if (e != NULL) {
+ if (e != nullptr) {
return e->get();
} else {
return PropertyInfo();
@@ -412,7 +412,7 @@ bool PluginScript::get_property_default_value(const StringName &p_property, Vari
ASSERT_SCRIPT_VALID_V(false);
#ifdef TOOLS_ENABLED
const Map<StringName, Variant>::Element *e = _properties_default_values.find(p_property);
- if (e != NULL) {
+ if (e != nullptr) {
r_value = e->get();
return true;
} else {
@@ -462,7 +462,7 @@ bool PluginScript::has_script_signal(const StringName &p_signal) const {
void PluginScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
ASSERT_SCRIPT_VALID();
- for (Map<StringName, MethodInfo>::Element *e = _signals_info.front(); e != NULL; e = e->next()) {
+ for (Map<StringName, MethodInfo>::Element *e = _signals_info.front(); e != nullptr; e = e->next()) {
r_signals->push_back(e->get());
}
}
@@ -543,9 +543,9 @@ MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable
}
PluginScript::PluginScript() :
- _data(NULL),
- _desc(NULL),
- _language(NULL),
+ _data(nullptr),
+ _desc(nullptr),
+ _language(nullptr),
_tool(false),
_valid(false),
_script_list(this) {
diff --git a/modules/gdnative/pluginscript/register_types.h b/modules/gdnative/pluginscript/register_types.h
index a4f7284b54..c6a64b4f40 100644
--- a/modules/gdnative/pluginscript/register_types.h
+++ b/modules/gdnative/pluginscript/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef PLUGINSCRIPT_REGISTER_TYPES_H
+#define PLUGINSCRIPT_REGISTER_TYPES_H
+
void register_pluginscript_types();
void unregister_pluginscript_types();
+
+#endif // PLUGINSCRIPT_REGISTER_TYPES_H
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index e5d688afd4..67a286ee2e 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -34,11 +34,11 @@
#include "gdnative.h"
-#include "arvr/register_types.h"
#include "nativescript/register_types.h"
#include "net/register_types.h"
#include "pluginscript/register_types.h"
#include "videodecoder/register_types.h"
+#include "xr/register_types.h"
#include "core/engine.h"
#include "core/io/resource_loader.h"
@@ -214,7 +214,7 @@ static godot_variant cb_standard_varcall(void *p_procedure_handle, godot_array *
GDNativeCallRegistry *GDNativeCallRegistry::singleton;
-Vector<Ref<GDNative> > singleton_gdnatives;
+Vector<Ref<GDNative>> singleton_gdnatives;
Ref<GDNativeLibraryResourceLoader> resource_loader_gdnlib;
Ref<GDNativeLibraryResourceSaver> resource_saver_gdnlib;
@@ -240,7 +240,7 @@ void register_gdnative_types() {
GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);
register_net_types();
- register_arvr_types();
+ register_xr_types();
register_nativescript_types();
register_pluginscript_types();
register_videodecoder_types();
@@ -305,7 +305,7 @@ void unregister_gdnative_types() {
unregister_videodecoder_types();
unregister_pluginscript_types();
unregister_nativescript_types();
- unregister_arvr_types();
+ unregister_xr_types();
unregister_net_types();
memdelete(GDNativeCallRegistry::singleton);
diff --git a/modules/gdnative/register_types.h b/modules/gdnative/register_types.h
index 0091ef3f96..b5c182f8b7 100644
--- a/modules/gdnative/register_types.h
+++ b/modules/gdnative/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GDNATIVE_REGISTER_TYPES_H
+#define GDNATIVE_REGISTER_TYPES_H
+
void register_gdnative_types();
void unregister_gdnative_types();
+
+#endif // GDNATIVE_REGISTER_TYPES_H
diff --git a/modules/gdnative/videodecoder/SCsub b/modules/gdnative/videodecoder/SCsub
index 04cc8ed604..5948b9a3dd 100644
--- a/modules/gdnative/videodecoder/SCsub
+++ b/modules/gdnative/videodecoder/SCsub
@@ -1,9 +1,9 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_vsdecoder_gdnative = env_modules.Clone()
-env_vsdecoder_gdnative.Prepend(CPPPATH=['#modules/gdnative/include/'])
-env_vsdecoder_gdnative.add_source_files(env.modules_sources, '*.cpp')
+env_vsdecoder_gdnative.Prepend(CPPPATH=["#modules/gdnative/include/"])
+env_vsdecoder_gdnative.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/videodecoder/register_types.h b/modules/gdnative/videodecoder/register_types.h
index d81d5c497b..b1a83d4071 100644
--- a/modules/gdnative/videodecoder/register_types.h
+++ b/modules/gdnative/videodecoder/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef VIDEODECODER_REGISTER_TYPES_H
+#define VIDEODECODER_REGISTER_TYPES_H
+
void register_videodecoder_types();
void unregister_videodecoder_types();
+
+#endif // VIDEODECODER_REGISTER_TYPES_H
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
index f6e2bad739..fa9f6be5c1 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
@@ -33,7 +33,7 @@
#include "core/project_settings.h"
#include "servers/audio_server.h"
-VideoDecoderServer *VideoDecoderServer::instance = NULL;
+VideoDecoderServer *VideoDecoderServer::instance = nullptr;
static VideoDecoderServer decoder_server;
@@ -113,7 +113,7 @@ void GDAPI godot_videodecoder_register_decoder(const godot_videodecoder_interfac
// VideoStreamPlaybackGDNative starts here.
bool VideoStreamPlaybackGDNative::open_file(const String &p_file) {
- ERR_FAIL_COND_V(interface == NULL, false);
+ ERR_FAIL_COND_V(interface == nullptr, false);
file = FileAccess::open(p_file, FileAccess::READ);
bool file_opened = interface->open_file(data_struct, file);
@@ -150,7 +150,7 @@ void VideoStreamPlaybackGDNative::update(float p_delta) {
return;
}
time += p_delta;
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->update(data_struct, p_delta);
// Don't mix if there's no audio (num_channels == 0).
@@ -189,7 +189,7 @@ void VideoStreamPlaybackGDNative::update(float p_delta) {
void VideoStreamPlaybackGDNative::update_texture() {
PackedByteArray *pba = (PackedByteArray *)interface->get_videoframe(data_struct);
- if (pba == NULL) {
+ if (pba == nullptr) {
playing = false;
return;
}
@@ -205,19 +205,19 @@ VideoStreamPlaybackGDNative::VideoStreamPlaybackGDNative() :
texture(Ref<ImageTexture>(memnew(ImageTexture))),
playing(false),
paused(false),
- mix_udata(NULL),
- mix_callback(NULL),
+ mix_udata(nullptr),
+ mix_callback(nullptr),
num_channels(-1),
time(0),
seek_backward(false),
mix_rate(0),
delay_compensation(0),
- pcm(NULL),
+ pcm(nullptr),
pcm_write_idx(0),
samples_decoded(0),
- file(NULL),
- interface(NULL),
- data_struct(NULL) {}
+ file(nullptr),
+ interface(nullptr),
+ data_struct(nullptr) {}
VideoStreamPlaybackGDNative::~VideoStreamPlaybackGDNative() {
cleanup();
@@ -228,16 +228,16 @@ void VideoStreamPlaybackGDNative::cleanup() {
interface->destructor(data_struct);
if (pcm)
memfree(pcm);
- pcm = NULL;
+ pcm = nullptr;
time = 0;
num_channels = -1;
- interface = NULL;
- data_struct = NULL;
+ interface = nullptr;
+ data_struct = nullptr;
}
void VideoStreamPlaybackGDNative::set_interface(const godot_videodecoder_interface_gdnative *p_interface) {
- ERR_FAIL_COND(p_interface == NULL);
- if (interface != NULL) {
+ ERR_FAIL_COND(p_interface == nullptr);
+ if (interface != nullptr) {
cleanup();
}
interface = p_interface;
@@ -272,7 +272,7 @@ void VideoStreamPlaybackGDNative::stop() {
}
void VideoStreamPlaybackGDNative::seek(float p_time) {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->seek(data_struct, p_time);
if (p_time < time)
seek_backward = true;
@@ -292,13 +292,13 @@ Ref<Texture2D> VideoStreamPlaybackGDNative::get_texture() const {
}
float VideoStreamPlaybackGDNative::get_length() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_length(data_struct);
}
float VideoStreamPlaybackGDNative::get_playback_position() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_playback_position(data_struct);
}
@@ -312,7 +312,7 @@ void VideoStreamPlaybackGDNative::set_loop(bool p_enable) {
}
void VideoStreamPlaybackGDNative::set_audio_track(int p_idx) {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->set_audio_track(data_struct, p_idx);
}
@@ -323,13 +323,13 @@ void VideoStreamPlaybackGDNative::set_mix_callback(AudioMixCallback p_callback,
}
int VideoStreamPlaybackGDNative::get_channels() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return (num_channels > 0) ? num_channels : 0;
}
int VideoStreamPlaybackGDNative::get_mix_rate() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return mix_rate;
}
@@ -339,13 +339,13 @@ int VideoStreamPlaybackGDNative::get_mix_rate() const {
Ref<VideoStreamPlayback> VideoStreamGDNative::instance_playback() {
Ref<VideoStreamPlaybackGDNative> pb = memnew(VideoStreamPlaybackGDNative);
VideoDecoderGDNative *decoder = decoder_server.get_decoder(file.get_extension().to_lower());
- if (decoder == NULL)
- return NULL;
+ if (decoder == nullptr)
+ return nullptr;
pb->set_interface(decoder->interface);
pb->set_audio_track(audio_track);
if (pb->open_file(file))
return pb;
- return NULL;
+ return nullptr;
}
void VideoStreamGDNative::set_file(const String &p_file) {
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h
index 21b5245a16..fbc0d4016f 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.h
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.h
@@ -42,7 +42,7 @@ struct VideoDecoderGDNative {
Vector<String> supported_extensions;
VideoDecoderGDNative() :
- interface(NULL),
+ interface(nullptr),
plugin_name("none") {}
VideoDecoderGDNative(const godot_videodecoder_interface_gdnative *p_interface) :
@@ -89,7 +89,7 @@ public:
VideoDecoderGDNative *get_decoder(const String &extension) {
if (extensions.size() == 0 || !extensions.has(extension))
- return NULL;
+ return nullptr;
return decoders[extensions[extension]];
}
@@ -102,7 +102,7 @@ public:
memdelete(decoders[i]);
}
decoders.clear();
- instance = NULL;
+ instance = nullptr;
}
};
@@ -194,12 +194,12 @@ public:
virtual void set_audio_track(int p_track);
virtual Ref<VideoStreamPlayback> instance_playback();
- VideoStreamGDNative() {}
+ VideoStreamGDNative() { audio_track = 0; }
};
class ResourceFormatLoaderVideoStreamGDNative : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/SCsub b/modules/gdnative/xr/SCsub
new file mode 100644
index 0000000000..0b2db3b504
--- /dev/null
+++ b/modules/gdnative/xr/SCsub
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_gdnative")
+
+env_gdnative.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/xr/config.py b/modules/gdnative/xr/config.py
new file mode 100644
index 0000000000..d22f9454ed
--- /dev/null
+++ b/modules/gdnative/xr/config.py
@@ -0,0 +1,6 @@
+def can_build(env, platform):
+ return True
+
+
+def configure(env):
+ pass
diff --git a/modules/gdnative/xr/register_types.cpp b/modules/gdnative/xr/register_types.cpp
new file mode 100644
index 0000000000..da3a7dc4b8
--- /dev/null
+++ b/modules/gdnative/xr/register_types.cpp
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "xr_interface_gdnative.h"
+
+void register_xr_types() {
+ ClassDB::register_class<XRInterfaceGDNative>();
+ ClassDB::add_compatibility_class("ARVRInterfaceGDNative", "XRInterfaceGDNative");
+}
+
+void unregister_xr_types() {
+}
diff --git a/modules/gdnative/xr/register_types.h b/modules/gdnative/xr/register_types.h
new file mode 100644
index 0000000000..2501d28651
--- /dev/null
+++ b/modules/gdnative/xr/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 XR_REGISTER_TYPES_H
+#define XR_REGISTER_TYPES_H
+
+void register_xr_types();
+void unregister_xr_types();
+
+#endif // XR_REGISTER_TYPES_H
diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp
new file mode 100644
index 0000000000..0451945139
--- /dev/null
+++ b/modules/gdnative/xr/xr_interface_gdnative.cpp
@@ -0,0 +1,428 @@
+/*************************************************************************/
+/* xr_interface_gdnative.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "xr_interface_gdnative.h"
+#include "core/input/input_filter.h"
+#include "servers/rendering/rendering_server_globals.h"
+#include "servers/xr/xr_positional_tracker.h"
+
+void XRInterfaceGDNative::_bind_methods() {
+ ADD_PROPERTY_DEFAULT("interface_is_initialized", false);
+ ADD_PROPERTY_DEFAULT("ar_is_anchor_detection_enabled", false);
+}
+
+XRInterfaceGDNative::XRInterfaceGDNative() {
+ print_verbose("Construct gdnative interface\n");
+
+ // we won't have our data pointer until our library gets set
+ data = nullptr;
+
+ interface = nullptr;
+}
+
+XRInterfaceGDNative::~XRInterfaceGDNative() {
+ print_verbose("Destruct gdnative interface\n");
+
+ if (interface != nullptr && is_initialized()) {
+ uninitialize();
+ };
+
+ // cleanup after ourselves
+ cleanup();
+}
+
+void XRInterfaceGDNative::cleanup() {
+ if (interface != nullptr) {
+ interface->destructor(data);
+ data = nullptr;
+ interface = nullptr;
+ }
+}
+
+void XRInterfaceGDNative::set_interface(const godot_xr_interface_gdnative *p_interface) {
+ // this should only be called once, just being paranoid..
+ if (interface) {
+ cleanup();
+ }
+
+ // bind to our interface
+ interface = p_interface;
+
+ // Now we do our constructing...
+ data = interface->constructor((godot_object *)this);
+}
+
+StringName XRInterfaceGDNative::get_name() const {
+
+ ERR_FAIL_COND_V(interface == nullptr, StringName());
+
+ godot_string result = interface->get_name(data);
+
+ StringName name = *(String *)&result;
+
+ godot_string_destroy(&result);
+
+ return name;
+}
+
+int XRInterfaceGDNative::get_capabilities() const {
+ int capabilities;
+
+ ERR_FAIL_COND_V(interface == nullptr, 0); // 0 = None
+
+ capabilities = interface->get_capabilities(data);
+
+ return capabilities;
+}
+
+bool XRInterfaceGDNative::get_anchor_detection_is_enabled() const {
+
+ ERR_FAIL_COND_V(interface == nullptr, false);
+
+ return interface->get_anchor_detection_is_enabled(data);
+}
+
+void XRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
+
+ ERR_FAIL_COND(interface == nullptr);
+
+ interface->set_anchor_detection_is_enabled(data, p_enable);
+}
+
+int XRInterfaceGDNative::get_camera_feed_id() {
+
+ ERR_FAIL_COND_V(interface == nullptr, 0);
+
+ return (unsigned int)interface->get_camera_feed_id(data);
+}
+
+bool XRInterfaceGDNative::is_stereo() {
+ bool stereo;
+
+ ERR_FAIL_COND_V(interface == nullptr, false);
+
+ stereo = interface->is_stereo(data);
+
+ return stereo;
+}
+
+bool XRInterfaceGDNative::is_initialized() const {
+
+ ERR_FAIL_COND_V(interface == nullptr, false);
+
+ return interface->is_initialized(data);
+}
+
+bool XRInterfaceGDNative::initialize() {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+
+ bool initialized = interface->initialize(data);
+
+ if (initialized) {
+ // if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
+
+ XRServer *xr_server = XRServer::get_singleton();
+ if ((xr_server != nullptr) && (xr_server->get_primary_interface() == nullptr)) {
+ xr_server->set_primary_interface(this);
+ };
+ };
+
+ return initialized;
+}
+
+void XRInterfaceGDNative::uninitialize() {
+ ERR_FAIL_COND(interface == nullptr);
+
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server != nullptr) {
+ // Whatever happens, make sure this is no longer our primary interface
+ xr_server->clear_primary_interface_if(this);
+ }
+
+ interface->uninitialize(data);
+}
+
+Size2 XRInterfaceGDNative::get_render_targetsize() {
+
+ ERR_FAIL_COND_V(interface == nullptr, Size2());
+
+ godot_vector2 result = interface->get_render_targetsize(data);
+ Vector2 *vec = (Vector2 *)&result;
+
+ return *vec;
+}
+
+Transform XRInterfaceGDNative::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+ Transform *ret;
+
+ ERR_FAIL_COND_V(interface == nullptr, Transform());
+
+ godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform);
+
+ ret = (Transform *)&t;
+
+ return *ret;
+}
+
+CameraMatrix XRInterfaceGDNative::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+ CameraMatrix cm;
+
+ ERR_FAIL_COND_V(interface == nullptr, CameraMatrix());
+
+ interface->fill_projection_for_eye(data, (godot_real *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
+
+ return cm;
+}
+
+unsigned int XRInterfaceGDNative::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
+
+ ERR_FAIL_COND_V(interface == nullptr, 0);
+
+ return (unsigned int)interface->get_external_texture_for_eye(data, (godot_int)p_eye);
+}
+
+void XRInterfaceGDNative::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+
+ ERR_FAIL_COND(interface == nullptr);
+
+ interface->commit_for_eye(data, (godot_int)p_eye, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
+}
+
+void XRInterfaceGDNative::process() {
+ ERR_FAIL_COND(interface == nullptr);
+
+ interface->process(data);
+}
+
+void XRInterfaceGDNative::notification(int p_what) {
+ ERR_FAIL_COND(interface == nullptr);
+
+ interface->notification(data, p_what);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// some helper callbacks
+
+extern "C" {
+
+void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface) {
+ // Must be on a version 4 plugin
+ ERR_FAIL_COND_MSG(p_interface->version.major < 4, "GDNative XR interfaces build for Godot 3.x are not supported.");
+
+ Ref<XRInterfaceGDNative> new_interface;
+ new_interface.instance();
+ new_interface->set_interface((const godot_xr_interface_gdnative *)p_interface);
+ XRServer::get_singleton()->add_interface(new_interface);
+}
+
+godot_real GDAPI godot_xr_get_worldscale() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, 1.0);
+
+ return xr_server->get_world_scale();
+}
+
+godot_transform GDAPI godot_xr_get_reference_frame() {
+ godot_transform reference_frame;
+ Transform *reference_frame_ptr = (Transform *)&reference_frame;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server != nullptr) {
+ *reference_frame_ptr = xr_server->get_reference_frame();
+ } else {
+ godot_transform_new_identity(&reference_frame);
+ }
+
+ return reference_frame;
+}
+
+void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) {
+ // blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD
+ XRInterface::Eyes eye = (XRInterface::Eyes)p_eye;
+#if 0
+ RID *render_target = (RID *)p_render_target;
+#endif
+ Rect2 screen_rect = *(Rect2 *)p_rect;
+
+ if (eye == XRInterface::EYE_LEFT) {
+ screen_rect.size.x /= 2.0;
+ } else if (p_eye == XRInterface::EYE_RIGHT) {
+ screen_rect.size.x /= 2.0;
+ screen_rect.position.x += screen_rect.size.x;
+ }
+#ifndef _MSC_VER
+#warning this needs to be redone
+#endif
+#if 0
+ RSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0);
+#endif
+}
+
+godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target) {
+ // In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID
+ // This is a handy function to expose that.
+#if 0
+ RID *render_target = (RID *)p_render_target;
+
+ RID eye_texture = RSG::storage->render_target_get_texture(*render_target);
+#endif
+
+#ifndef _MSC_VER
+#warning need to obtain this ID again
+#endif
+ uint32_t texid = 0; //RS::get_singleton()->texture_get_texid(eye_texture);
+
+ return texid;
+}
+
+godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, 0);
+
+ InputFilter *input = InputFilter::get_singleton();
+ ERR_FAIL_NULL_V(input, 0);
+
+ XRPositionalTracker *new_tracker = memnew(XRPositionalTracker);
+ new_tracker->set_name(p_device_name);
+ new_tracker->set_type(XRServer::TRACKER_CONTROLLER);
+ if (p_hand == 1) {
+ new_tracker->set_hand(XRPositionalTracker::TRACKER_LEFT_HAND);
+ } else if (p_hand == 2) {
+ new_tracker->set_hand(XRPositionalTracker::TRACKER_RIGHT_HAND);
+ }
+
+ // also register as joystick...
+ int joyid = input->get_unused_joy_id();
+ if (joyid != -1) {
+ new_tracker->set_joy_id(joyid);
+ input->joy_connection_changed(joyid, true, p_device_name, "");
+ }
+
+ if (p_tracks_orientation) {
+ Basis orientation;
+ new_tracker->set_orientation(orientation);
+ }
+ if (p_tracks_position) {
+ Vector3 position;
+ new_tracker->set_position(position);
+ }
+
+ // add our tracker to our server and remember its pointer
+ xr_server->add_tracker(new_tracker);
+
+ // note, this ID is only unique within controllers!
+ return new_tracker->get_tracker_id();
+}
+
+void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ InputFilter *input = InputFilter::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) {
+ // unset our joystick if applicable
+ int joyid = remove_tracker->get_joy_id();
+ if (joyid != -1) {
+ input->joy_connection_changed(joyid, false, "", "");
+ remove_tracker->set_joy_id(-1);
+ }
+
+ // remove our tracker from our server
+ xr_server->remove_tracker(remove_tracker);
+ memdelete(remove_tracker);
+ }
+}
+
+void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
+ 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) {
+ Transform *transform = (Transform *)p_transform;
+ if (p_tracks_orientation) {
+ tracker->set_orientation(transform->basis);
+ }
+ if (p_tracks_position) {
+ tracker->set_rw_position(transform->origin);
+ }
+ }
+}
+
+void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ InputFilter *input = InputFilter::get_singleton();
+ ERR_FAIL_NULL(input);
+
+ XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != nullptr) {
+ int joyid = tracker->get_joy_id();
+ if (joyid != -1) {
+ input->joy_button(joyid, p_button, p_is_pressed);
+ }
+ }
+}
+
+void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ InputFilter *input = InputFilter::get_singleton();
+ ERR_FAIL_NULL(input);
+
+ XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != nullptr) {
+ int joyid = tracker->get_joy_id();
+ if (joyid != -1) {
+ InputFilter::JoyAxis jx;
+ jx.min = p_can_be_negative ? -1 : 0;
+ jx.value = p_value;
+ input->joy_axis(joyid, p_axis, jx);
+ }
+ }
+}
+
+godot_real 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) {
+ return tracker->get_rumble();
+ }
+
+ return 0.0;
+}
+}
diff --git a/modules/gdnative/xr/xr_interface_gdnative.h b/modules/gdnative/xr/xr_interface_gdnative.h
new file mode 100644
index 0000000000..64f1282a7e
--- /dev/null
+++ b/modules/gdnative/xr/xr_interface_gdnative.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* xr_interface_gdnative.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 XR_INTERFACE_GDNATIVE_H
+#define XR_INTERFACE_GDNATIVE_H
+
+#include "modules/gdnative/gdnative.h"
+#include "servers/xr/xr_interface.h"
+
+/**
+ @authors Hinsbart & Karroffel & Mux213
+
+ This subclass of our AR/VR interface forms a bridge to GDNative.
+*/
+
+class XRInterfaceGDNative : public XRInterface {
+ GDCLASS(XRInterfaceGDNative, XRInterface);
+
+ void cleanup();
+
+protected:
+ const godot_xr_interface_gdnative *interface;
+ void *data;
+
+ static void _bind_methods();
+
+public:
+ /** general interface information **/
+ XRInterfaceGDNative();
+ ~XRInterfaceGDNative();
+
+ void set_interface(const godot_xr_interface_gdnative *p_interface);
+
+ virtual StringName get_name() const;
+ virtual int get_capabilities() const;
+
+ virtual bool is_initialized() const;
+ virtual bool initialize();
+ virtual void uninitialize();
+
+ /** specific to AR **/
+ virtual bool get_anchor_detection_is_enabled() const;
+ virtual void set_anchor_detection_is_enabled(bool p_enable);
+ virtual int get_camera_feed_id();
+
+ /** rendering and internal **/
+ virtual Size2 get_render_targetsize();
+ virtual bool is_stereo();
+ virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform);
+
+ // we expose a Vector<float> version of this function to GDNative
+ Vector<float> _get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+
+ // and a CameraMatrix version to XRServer
+ virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+
+ virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye);
+ virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
+
+ virtual void process();
+ virtual void notification(int p_what);
+};
+
+#endif // XR_INTERFACE_GDNATIVE_H
diff --git a/modules/gdnavigation/SCsub b/modules/gdnavigation/SCsub
index 9d462f92a7..877d601c6a 100644
--- a/modules/gdnavigation/SCsub
+++ b/modules/gdnavigation/SCsub
@@ -1,25 +1,25 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_navigation = env_modules.Clone()
# Recast Thirdparty source files
-if env['builtin_recast']:
+if env["builtin_recast"]:
thirdparty_dir = "#thirdparty/recastnavigation/Recast/"
thirdparty_sources = [
- "Source/Recast.cpp",
- "Source/RecastAlloc.cpp",
- "Source/RecastArea.cpp",
- "Source/RecastAssert.cpp",
- "Source/RecastContour.cpp",
- "Source/RecastFilter.cpp",
- "Source/RecastLayers.cpp",
- "Source/RecastMesh.cpp",
- "Source/RecastMeshDetail.cpp",
- "Source/RecastRasterization.cpp",
- "Source/RecastRegion.cpp",
+ "Source/Recast.cpp",
+ "Source/RecastAlloc.cpp",
+ "Source/RecastArea.cpp",
+ "Source/RecastAssert.cpp",
+ "Source/RecastContour.cpp",
+ "Source/RecastFilter.cpp",
+ "Source/RecastLayers.cpp",
+ "Source/RecastMesh.cpp",
+ "Source/RecastMeshDetail.cpp",
+ "Source/RecastRasterization.cpp",
+ "Source/RecastRegion.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -31,11 +31,11 @@ if env['builtin_recast']:
# RVO Thirdparty source files
-if env['builtin_rvo2']:
+if env["builtin_rvo2"]:
thirdparty_dir = "#thirdparty/rvo2"
thirdparty_sources = [
- "/src/Agent.cpp",
- "/src/KdTree.cpp",
+ "/src/Agent.cpp",
+ "/src/KdTree.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/modules/gdnavigation/config.py b/modules/gdnavigation/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/gdnavigation/config.py
+++ b/modules/gdnavigation/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/gdnavigation/gd_navigation_server.cpp
index a1f6ddfedc..278c27ae22 100644
--- a/modules/gdnavigation/gd_navigation_server.cpp
+++ b/modules/gdnavigation/gd_navigation_server.cpp
@@ -114,7 +114,7 @@
void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3)
GdNavigationServer::GdNavigationServer() :
- NavigationServer(),
+ NavigationServer3D(),
active(true) {
}
@@ -141,7 +141,7 @@ RID GdNavigationServer::map_create() const {
COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND(map == NULL);
+ ERR_FAIL_COND(map == nullptr);
if (p_active) {
if (!map_is_active(p_map)) {
@@ -154,84 +154,84 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
bool GdNavigationServer::map_is_active(RID p_map) const {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, false);
+ ERR_FAIL_COND_V(map == nullptr, false);
return active_maps.find(map) >= 0;
}
COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND(map == NULL);
+ ERR_FAIL_COND(map == nullptr);
map->set_up(p_up);
}
Vector3 GdNavigationServer::map_get_up(RID p_map) const {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, Vector3());
+ ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_up();
}
COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND(map == NULL);
+ ERR_FAIL_COND(map == nullptr);
map->set_cell_size(p_cell_size);
}
real_t GdNavigationServer::map_get_cell_size(RID p_map) const {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, 0);
+ ERR_FAIL_COND_V(map == nullptr, 0);
return map->get_cell_size();
}
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin) {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND(map == NULL);
+ ERR_FAIL_COND(map == nullptr);
map->set_edge_connection_margin(p_connection_margin);
}
real_t GdNavigationServer::map_get_edge_connection_margin(RID p_map) const {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, 0);
+ ERR_FAIL_COND_V(map == nullptr, 0);
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 {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, Vector<Vector3>());
+ ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
return map->get_path(p_origin, p_destination, p_optimize);
}
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 {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, Vector3());
+ ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_closest_point_to_segment(p_from, p_to, p_use_collision);
}
Vector3 GdNavigationServer::map_get_closest_point(RID p_map, const Vector3 &p_point) const {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, Vector3());
+ ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_closest_point(p_point);
}
Vector3 GdNavigationServer::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, Vector3());
+ ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_closest_point_normal(p_point);
}
RID GdNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const {
const NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND_V(map == NULL, RID());
+ ERR_FAIL_COND_V(map == nullptr, RID());
return map->get_closest_point_owner(p_point);
}
@@ -247,20 +247,20 @@ RID GdNavigationServer::region_create() const {
COMMAND_2(region_set_map, RID, p_region, RID, p_map) {
NavRegion *region = region_owner.getornull(p_region);
- ERR_FAIL_COND(region == NULL);
+ ERR_FAIL_COND(region == nullptr);
- if (region->get_map() != NULL) {
+ if (region->get_map() != nullptr) {
if (region->get_map()->get_self() == p_map)
return; // Pointless
region->get_map()->remove_region(region);
- region->set_map(NULL);
+ region->set_map(nullptr);
}
if (p_map.is_valid()) {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND(map == NULL);
+ ERR_FAIL_COND(map == nullptr);
map->add_region(region);
region->set_map(map);
@@ -269,21 +269,21 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) {
COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform) {
NavRegion *region = region_owner.getornull(p_region);
- ERR_FAIL_COND(region == NULL);
+ ERR_FAIL_COND(region == nullptr);
region->set_transform(p_transform);
}
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) {
NavRegion *region = region_owner.getornull(p_region);
- ERR_FAIL_COND(region == NULL);
+ ERR_FAIL_COND(region == nullptr);
region->set_mesh(p_nav_mesh);
}
void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const {
ERR_FAIL_COND(r_mesh.is_null());
- ERR_FAIL_COND(p_node == NULL);
+ ERR_FAIL_COND(p_node == nullptr);
#ifndef _3D_DISABLED
NavigationMeshGenerator::get_singleton()->clear(r_mesh);
@@ -302,7 +302,7 @@ RID GdNavigationServer::agent_create() const {
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
if (agent->get_map()) {
if (agent->get_map()->get_self() == p_map)
@@ -311,11 +311,11 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
agent->get_map()->remove_agent(agent);
}
- agent->set_map(NULL);
+ agent->set_map(nullptr);
if (p_map.is_valid()) {
NavMap *map = map_owner.getornull(p_map);
- ERR_FAIL_COND(map == NULL);
+ ERR_FAIL_COND(map == nullptr);
agent->set_map(map);
map->add_agent(agent);
@@ -328,82 +328,82 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->neighborDist_ = p_dist;
}
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->maxNeighbors_ = p_count;
}
COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->timeHorizon_ = p_time;
}
COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->radius_ = p_radius;
}
COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->maxSpeed_ = p_max_speed;
}
COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->velocity_ = RVO::Vector3(p_velocity.x, p_velocity.y, p_velocity.z);
}
COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->prefVelocity_ = RVO::Vector3(p_velocity.x, p_velocity.y, p_velocity.z);
}
COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->position_ = RVO::Vector3(p_position.x, p_position.y, p_position.z);
}
COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->ignore_y_ = p_ignore;
}
bool GdNavigationServer::agent_is_map_changed(RID p_agent) const {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND_V(agent == NULL, false);
+ ERR_FAIL_COND_V(agent == nullptr, false);
return agent->is_map_changed();
}
COMMAND_4(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata) {
RvoAgent *agent = agent_owner.getornull(p_agent);
- ERR_FAIL_COND(agent == NULL);
+ ERR_FAIL_COND(agent == nullptr);
- agent->set_callback(p_receiver == NULL ? ObjectID() : p_receiver->get_instance_id(), p_method, p_udata);
+ agent->set_callback(p_receiver == nullptr ? ObjectID() : p_receiver->get_instance_id(), p_method, p_udata);
if (agent->get_map()) {
- if (p_receiver == NULL) {
+ if (p_receiver == nullptr) {
agent->get_map()->remove_agent_as_controlled(agent);
} else {
agent->get_map()->set_agent_as_controlled(agent);
@@ -419,14 +419,14 @@ COMMAND_1(free, RID, p_object) {
std::vector<NavRegion *> regions = map->get_regions();
for (size_t i(0); i < regions.size(); i++) {
map->remove_region(regions[i]);
- regions[i]->set_map(NULL);
+ regions[i]->set_map(nullptr);
}
// Remove any assigned agent
std::vector<RvoAgent *> agents = map->get_agents();
for (size_t i(0); i < agents.size(); i++) {
map->remove_agent(agents[i]);
- agents[i]->set_map(NULL);
+ agents[i]->set_map(nullptr);
}
active_maps.erase(map);
@@ -437,9 +437,9 @@ COMMAND_1(free, RID, p_object) {
NavRegion *region = region_owner.getornull(p_object);
// Removes this region from the map if assigned
- if (region->get_map() != NULL) {
+ if (region->get_map() != nullptr) {
region->get_map()->remove_region(region);
- region->set_map(NULL);
+ region->set_map(nullptr);
}
region_owner.free(p_object);
@@ -449,9 +449,9 @@ COMMAND_1(free, RID, p_object) {
RvoAgent *agent = agent_owner.getornull(p_object);
// Removes this agent from the map if assigned
- if (agent->get_map() != NULL) {
+ if (agent->get_map() != nullptr) {
agent->get_map()->remove_agent(agent);
- agent->set_map(NULL);
+ agent->set_map(nullptr);
}
agent_owner.free(p_object);
diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/gdnavigation/gd_navigation_server.h
index e9f5c1ffe6..01d1a4fba9 100644
--- a/modules/gdnavigation/gd_navigation_server.h
+++ b/modules/gdnavigation/gd_navigation_server.h
@@ -33,7 +33,7 @@
#include "core/rid.h"
#include "core/rid_owner.h"
-#include "servers/navigation_server.h"
+#include "servers/navigation_server_3d.h"
#include "nav_map.h"
#include "nav_region.h"
@@ -67,7 +67,7 @@ struct SetCommand {
virtual void exec(GdNavigationServer *server) = 0;
};
-class GdNavigationServer : public NavigationServer {
+class GdNavigationServer : public NavigationServer3D {
Mutex commands_mutex;
/// Mutex used to make any operation threadsafe.
Mutex operations_mutex;
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 338e49eb9f..7e6a3f7a26 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -81,8 +81,8 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize) const {
- const gd::Polygon *begin_poly = NULL;
- const gd::Polygon *end_poly = NULL;
+ const gd::Polygon *begin_poly = nullptr;
+ const gd::Polygon *end_poly = nullptr;
Vector3 begin_point;
Vector3 end_point;
float begin_d = 1e20;
@@ -146,7 +146,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
open_list.push_back(0);
- const gd::Polygon *reachable_end = NULL;
+ const gd::Polygon *reachable_end = nullptr;
float reachable_d = 1e30;
bool is_reachable = true;
@@ -215,7 +215,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// so 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 == NULL) {
+ if (reachable_end == nullptr) {
// The path is not found and there is not a way out.
break;
}
@@ -240,7 +240,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
open_list.clear();
open_list.push_back(0);
- reachable_end = NULL;
+ reachable_end = nullptr;
continue;
}
@@ -249,7 +249,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
least_cost_id = -1;
float least_cost = 1e30;
- for (auto element = open_list.front(); element != NULL; element = element->next()) {
+ for (auto element = open_list.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
float cost = np->traveled_distance;
#ifdef USE_ENTRY_POINT
@@ -366,7 +366,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
p = &navigation_polys[p->prev_navigation_poly_id];
else
// The end
- p = NULL;
+ p = nullptr;
}
if (path[path.size() - 1] != begin_point)
@@ -637,12 +637,12 @@ void NavMap::sync() {
gd::Connection c;
c.A = &poly;
c.A_edge = p;
- c.B = NULL;
+ c.B = nullptr;
c.B_edge = -1;
connections[ek] = c;
- } else if (connection->get().B == NULL) {
- CRASH_COND(connection->get().A == NULL); // Unreachable
+ } else if (connection->get().B == nullptr) {
+ CRASH_COND(connection->get().A == nullptr); // Unreachable
// Connect the two Polygons by this edge
connection->get().B = &poly;
@@ -657,7 +657,7 @@ void NavMap::sync() {
connection->get().B->edges[connection->get().B_edge].other_edge = connection->get().A_edge;
} 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 Navigation'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 Navigation3D's `cell_size` is different from the one used to generate the navigation mesh. This will cause navigation problem.");
}
}
}
@@ -667,8 +667,8 @@ void NavMap::sync() {
free_edges.reserve(connections.size());
for (auto connection_element = connections.front(); connection_element; connection_element = connection_element->next()) {
- if (connection_element->get().B == NULL) {
- CRASH_COND(connection_element->get().A == NULL); // Unreachable
+ 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
diff --git a/modules/gdnavigation/nav_region.cpp b/modules/gdnavigation/nav_region.cpp
index 0215821305..b91376f761 100644
--- a/modules/gdnavigation/nav_region.cpp
+++ b/modules/gdnavigation/nav_region.cpp
@@ -37,7 +37,7 @@
*/
NavRegion::NavRegion() :
- map(NULL),
+ map(nullptr),
polygons_dirty(true) {
}
@@ -71,7 +71,7 @@ void NavRegion::update_polygons() {
polygons.clear();
polygons_dirty = false;
- if (map == NULL) {
+ if (map == nullptr) {
return;
}
diff --git a/modules/gdnavigation/nav_region.h b/modules/gdnavigation/nav_region.h
index d99254d1ad..f35ee4bea0 100644
--- a/modules/gdnavigation/nav_region.h
+++ b/modules/gdnavigation/nav_region.h
@@ -34,7 +34,7 @@
#include "nav_rid.h"
#include "nav_utils.h"
-#include "scene/3d/navigation.h"
+#include "scene/3d/navigation_3d.h"
#include <vector>
/**
diff --git a/modules/gdnavigation/nav_utils.h b/modules/gdnavigation/nav_utils.h
index bdf9eb34a8..3401284c31 100644
--- a/modules/gdnavigation/nav_utils.h
+++ b/modules/gdnavigation/nav_utils.h
@@ -90,7 +90,7 @@ struct Edge {
Edge() {
this_edge = -1;
- other_polygon = NULL;
+ other_polygon = nullptr;
other_edge = -1;
}
};
@@ -119,8 +119,8 @@ struct Connection {
int B_edge;
Connection() {
- A = NULL;
- B = NULL;
+ A = nullptr;
+ B = nullptr;
A_edge = -1;
B_edge = -1;
}
diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp b/modules/gdnavigation/navigation_mesh_editor_plugin.cpp
index e6ff7a7afa..abaf73ba6a 100644
--- a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp
+++ b/modules/gdnavigation/navigation_mesh_editor_plugin.cpp
@@ -34,13 +34,13 @@
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "navigation_mesh_generator.h"
-#include "scene/3d/mesh_instance.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/box_container.h"
void NavigationMeshEditor::_node_removed(Node *p_node) {
if (p_node == node) {
- node = NULL;
+ node = nullptr;
hide();
}
@@ -50,8 +50,8 @@ void NavigationMeshEditor::_notification(int p_option) {
if (p_option == NOTIFICATION_ENTER_TREE) {
- button_bake->set_icon(get_icon("Bake", "EditorIcons"));
- button_reset->set_icon(get_icon("Reload", "EditorIcons"));
+ button_bake->set_icon(get_theme_icon("Bake", "EditorIcons"));
+ button_reset->set_icon(get_theme_icon("Reload", "EditorIcons"));
}
}
@@ -61,7 +61,7 @@ void NavigationMeshEditor::_bake_pressed() {
ERR_FAIL_COND(!node);
if (!node->get_navigation_mesh().is_valid()) {
err_dialog->set_text(TTR("A NavigationMesh resource must be set or created for this node to work."));
- err_dialog->popup_centered_minsize();
+ err_dialog->popup_centered();
return;
}
@@ -84,9 +84,9 @@ void NavigationMeshEditor::_clear_pressed() {
}
}
-void NavigationMeshEditor::edit(NavigationRegion *p_nav_region) {
+void NavigationMeshEditor::edit(NavigationRegion3D *p_nav_region) {
- if (p_nav_region == NULL || node == p_nav_region) {
+ if (p_nav_region == nullptr || node == p_nav_region) {
return;
}
@@ -117,7 +117,7 @@ NavigationMeshEditor::NavigationMeshEditor() {
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
- node = NULL;
+ node = nullptr;
}
NavigationMeshEditor::~NavigationMeshEditor() {
@@ -125,12 +125,12 @@ NavigationMeshEditor::~NavigationMeshEditor() {
void NavigationMeshEditorPlugin::edit(Object *p_object) {
- navigation_mesh_editor->edit(Object::cast_to<NavigationRegion>(p_object));
+ navigation_mesh_editor->edit(Object::cast_to<NavigationRegion3D>(p_object));
}
bool NavigationMeshEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("NavigationRegion");
+ return p_object->is_class("NavigationRegion3D");
}
void NavigationMeshEditorPlugin::make_visible(bool p_visible) {
@@ -142,7 +142,7 @@ void NavigationMeshEditorPlugin::make_visible(bool p_visible) {
navigation_mesh_editor->hide();
navigation_mesh_editor->bake_hbox->hide();
- navigation_mesh_editor->edit(NULL);
+ navigation_mesh_editor->edit(nullptr);
}
}
diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.h b/modules/gdnavigation/navigation_mesh_editor_plugin.h
index 847ad4f63d..434981c9e0 100644
--- a/modules/gdnavigation/navigation_mesh_editor_plugin.h
+++ b/modules/gdnavigation/navigation_mesh_editor_plugin.h
@@ -36,7 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-class NavigationRegion;
+class NavigationRegion3D;
class NavigationMeshEditor : public Control {
friend class NavigationMeshEditorPlugin;
@@ -50,7 +50,7 @@ class NavigationMeshEditor : public Control {
ToolButton *button_reset;
Label *bake_info;
- NavigationRegion *node;
+ NavigationRegion3D *node;
void _bake_pressed();
void _clear_pressed();
@@ -61,7 +61,7 @@ protected:
void _notification(int p_option);
public:
- void edit(NavigationRegion *p_nav_region);
+ void edit(NavigationRegion3D *p_nav_region);
NavigationMeshEditor();
~NavigationMeshEditor();
};
diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/gdnavigation/navigation_mesh_generator.cpp
index e7038b38a2..acb4f0461f 100644
--- a/modules/gdnavigation/navigation_mesh_generator.cpp
+++ b/modules/gdnavigation/navigation_mesh_generator.cpp
@@ -34,18 +34,18 @@
#include "core/math/quick_hull.h"
#include "core/os/thread.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/physics_body.h"
-#include "scene/resources/box_shape.h"
-#include "scene/resources/capsule_shape.h"
-#include "scene/resources/concave_polygon_shape.h"
-#include "scene/resources/convex_polygon_shape.h"
-#include "scene/resources/cylinder_shape.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
+#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/primitive_meshes.h"
-#include "scene/resources/shape.h"
-#include "scene/resources/sphere_shape.h"
-#include "scene/resources/world_margin_shape.h"
+#include "scene/resources/shape_3d.h"
+#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/world_margin_shape_3d.h"
#include "modules/modules_enabled.gen.h"
#ifdef TOOLS_ENABLED
@@ -60,7 +60,7 @@
#include "modules/gridmap/grid_map.h"
#endif
-NavigationMeshGenerator *NavigationMeshGenerator::singleton = NULL;
+NavigationMeshGenerator *NavigationMeshGenerator::singleton = nullptr;
void NavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies) {
p_verticies.push_back(p_vec3.x);
@@ -140,9 +140,9 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons
void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
- if (Object::cast_to<MeshInstance>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
+ if (Object::cast_to<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
- MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_node);
+ MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mesh_instance->get_mesh();
if (mesh.is_valid()) {
_add_mesh(mesh, p_accumulated_transform * mesh_instance->get_transform(), p_verticies, p_indices);
@@ -150,9 +150,9 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
}
#ifdef MODULE_CSG_ENABLED
- if (Object::cast_to<CSGShape>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
+ if (Object::cast_to<CSGShape3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
- CSGShape *csg_shape = Object::cast_to<CSGShape>(p_node);
+ CSGShape3D *csg_shape = Object::cast_to<CSGShape3D>(p_node);
Array meshes = csg_shape->get_meshes();
if (!meshes.empty()) {
Ref<Mesh> mesh = meshes[1];
@@ -163,22 +163,22 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
}
#endif
- if (Object::cast_to<StaticBody>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES) {
- StaticBody *static_body = Object::cast_to<StaticBody>(p_node);
+ if (Object::cast_to<StaticBody3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_MESH_INSTANCES) {
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(p_node);
if (static_body->get_collision_layer() & p_collision_mask) {
for (int i = 0; i < p_node->get_child_count(); ++i) {
Node *child = p_node->get_child(i);
- if (Object::cast_to<CollisionShape>(child)) {
- CollisionShape *col_shape = Object::cast_to<CollisionShape>(child);
+ if (Object::cast_to<CollisionShape3D>(child)) {
+ CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child);
Transform transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform();
Ref<Mesh> mesh;
- Ref<Shape> s = col_shape->get_shape();
+ Ref<Shape3D> s = col_shape->get_shape();
- BoxShape *box = Object::cast_to<BoxShape>(*s);
+ BoxShape3D *box = Object::cast_to<BoxShape3D>(*s);
if (box) {
Ref<CubeMesh> cube_mesh;
cube_mesh.instance();
@@ -186,7 +186,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
mesh = cube_mesh;
}
- CapsuleShape *capsule = Object::cast_to<CapsuleShape>(*s);
+ CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s);
if (capsule) {
Ref<CapsuleMesh> capsule_mesh;
capsule_mesh.instance();
@@ -195,7 +195,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
mesh = capsule_mesh;
}
- CylinderShape *cylinder = Object::cast_to<CylinderShape>(*s);
+ CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s);
if (cylinder) {
Ref<CylinderMesh> cylinder_mesh;
cylinder_mesh.instance();
@@ -205,7 +205,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
mesh = cylinder_mesh;
}
- SphereShape *sphere = Object::cast_to<SphereShape>(*s);
+ SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s);
if (sphere) {
Ref<SphereMesh> sphere_mesh;
sphere_mesh.instance();
@@ -214,12 +214,12 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
mesh = sphere_mesh;
}
- ConcavePolygonShape *concave_polygon = Object::cast_to<ConcavePolygonShape>(*s);
+ ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s);
if (concave_polygon) {
_add_faces(concave_polygon->get_faces(), transform, p_verticies, p_indices);
}
- ConvexPolygonShape *convex_polygon = Object::cast_to<ConvexPolygonShape>(*s);
+ ConvexPolygonShape3D *convex_polygon = Object::cast_to<ConvexPolygonShape3D>(*s);
if (convex_polygon) {
Vector<Vector3> varr = Variant(convex_polygon->get_points());
Geometry::MeshData md;
@@ -265,8 +265,8 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform,
}
#endif
- if (Object::cast_to<Spatial>(p_node)) {
- Spatial *spatial = Object::cast_to<Spatial>(p_node);
+ if (Object::cast_to<Node3D>(p_node)) {
+ Node3D *spatial = Object::cast_to<Node3D>(p_node);
p_accumulated_transform = p_accumulated_transform * spatial->get_transform();
}
@@ -405,7 +405,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
ERR_FAIL_COND(!rcBuildCompactHeightfield(&ctx, cfg.walkableHeight, cfg.walkableClimb, *hf, *chf));
rcFreeHeightField(hf);
- hf = 0;
+ hf = nullptr;
#ifdef TOOLS_ENABLED
if (ep)
@@ -452,9 +452,9 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
ERR_FAIL_COND(!rcBuildPolyMeshDetail(&ctx, *poly_mesh, *chf, cfg.detailSampleDist, cfg.detailSampleMaxError, *detail_mesh));
rcFreeCompactHeightfield(chf);
- chf = 0;
+ chf = nullptr;
rcFreeContourSet(cset);
- cset = 0;
+ cset = nullptr;
#ifdef TOOLS_ENABLED
if (ep)
@@ -464,9 +464,9 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
_convert_detail_mesh_to_native_navigation_mesh(detail_mesh, p_nav_mesh);
rcFreePolyMesh(poly_mesh);
- poly_mesh = 0;
+ poly_mesh = nullptr;
rcFreePolyMeshDetail(detail_mesh);
- detail_mesh = 0;
+ detail_mesh = nullptr;
}
NavigationMeshGenerator *NavigationMeshGenerator::get_singleton() {
@@ -485,7 +485,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
ERR_FAIL_COND(!p_nav_mesh.is_valid());
#ifdef TOOLS_ENABLED
- EditorProgress *ep(NULL);
+ EditorProgress *ep(nullptr);
if (Engine::get_singleton()->is_editor_hint()) {
ep = memnew(EditorProgress("bake", TTR("Navigation Mesh Generator Setup:"), 11));
}
@@ -505,7 +505,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes);
}
- Transform navmesh_xform = Object::cast_to<Spatial>(p_node)->get_transform().affine_inverse();
+ Transform navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse();
for (const List<Node *>::Element *E = parse_nodes.front(); E; E = E->next()) {
int geometry_type = p_nav_mesh->get_parsed_geometry_type();
uint32_t collision_mask = p_nav_mesh->get_collision_mask();
@@ -515,11 +515,11 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
if (vertices.size() > 0 && indices.size() > 0) {
- rcHeightfield *hf = NULL;
- rcCompactHeightfield *chf = NULL;
- rcContourSet *cset = NULL;
- rcPolyMesh *poly_mesh = NULL;
- rcPolyMeshDetail *detail_mesh = NULL;
+ rcHeightfield *hf = nullptr;
+ rcCompactHeightfield *chf = nullptr;
+ rcContourSet *cset = nullptr;
+ rcPolyMesh *poly_mesh = nullptr;
+ rcPolyMeshDetail *detail_mesh = nullptr;
_build_recast_navigation_mesh(
p_nav_mesh,
@@ -535,19 +535,19 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
indices);
rcFreeHeightField(hf);
- hf = 0;
+ hf = nullptr;
rcFreeCompactHeightfield(chf);
- chf = 0;
+ chf = nullptr;
rcFreeContourSet(cset);
- cset = 0;
+ cset = nullptr;
rcFreePolyMesh(poly_mesh);
- poly_mesh = 0;
+ poly_mesh = nullptr;
rcFreePolyMeshDetail(detail_mesh);
- detail_mesh = 0;
+ detail_mesh = nullptr;
}
#ifdef TOOLS_ENABLED
diff --git a/modules/gdnavigation/navigation_mesh_generator.h b/modules/gdnavigation/navigation_mesh_generator.h
index d1f2e4b56f..c5f7b2ab81 100644
--- a/modules/gdnavigation/navigation_mesh_generator.h
+++ b/modules/gdnavigation/navigation_mesh_generator.h
@@ -33,7 +33,7 @@
#ifndef _3D_DISABLED
-#include "scene/3d/navigation_region.h"
+#include "scene/3d/navigation_region_3d.h"
#include <Recast.h>
diff --git a/modules/gdnavigation/register_types.cpp b/modules/gdnavigation/register_types.cpp
index d717733787..088b26bf17 100644
--- a/modules/gdnavigation/register_types.cpp
+++ b/modules/gdnavigation/register_types.cpp
@@ -32,7 +32,7 @@
#include "core/engine.h"
#include "gd_navigation_server.h"
-#include "servers/navigation_server.h"
+#include "servers/navigation_server_3d.h"
#ifndef _3D_DISABLED
#include "navigation_mesh_generator.h"
@@ -47,15 +47,15 @@
*/
#ifndef _3D_DISABLED
-NavigationMeshGenerator *_nav_mesh_generator = NULL;
+NavigationMeshGenerator *_nav_mesh_generator = nullptr;
#endif
-NavigationServer *new_server() {
+NavigationServer3D *new_server() {
return memnew(GdNavigationServer);
}
void register_gdnavigation_types() {
- NavigationServerManager::set_default_server(new_server);
+ NavigationServer3DManager::set_default_server(new_server);
#ifndef _3D_DISABLED
_nav_mesh_generator = memnew(NavigationMeshGenerator);
diff --git a/modules/gdnavigation/register_types.h b/modules/gdnavigation/register_types.h
index bd15eaaada..cdbff1b937 100644
--- a/modules/gdnavigation/register_types.h
+++ b/modules/gdnavigation/register_types.h
@@ -32,5 +32,10 @@
@author AndreaCatania
*/
+#ifndef GDNAVIGATION_REGISTER_TYPES_H
+#define GDNAVIGATION_REGISTER_TYPES_H
+
void register_gdnavigation_types();
void unregister_gdnavigation_types();
+
+#endif // GDNAVIGATION_REGISTER_TYPES_H
diff --git a/modules/gdnavigation/rvo_agent.cpp b/modules/gdnavigation/rvo_agent.cpp
index 677e525bbf..3c39f02c26 100644
--- a/modules/gdnavigation/rvo_agent.cpp
+++ b/modules/gdnavigation/rvo_agent.cpp
@@ -37,7 +37,7 @@
*/
RvoAgent::RvoAgent() :
- map(NULL) {
+ map(nullptr) {
callback.id = ObjectID();
}
@@ -70,7 +70,7 @@ void RvoAgent::dispatch_callback() {
return;
}
Object *obj = ObjectDB::get_instance(callback.id);
- if (obj == NULL) {
+ if (obj == nullptr) {
callback.id = ObjectID();
}
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index 74e653ce43..e58a1d8edc 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -1,19 +1,19 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_gdscript = env_modules.Clone()
env_gdscript.add_source_files(env.modules_sources, "*.cpp")
-if env['tools']:
+if env["tools"]:
env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp")
# Those two modules are required for the language server protocol
- if env['module_jsonrpc_enabled'] and env['module_websocket_enabled']:
+ if env["module_jsonrpc_enabled"] and env["module_websocket_enabled"]:
env_gdscript.add_source_files(env.modules_sources, "./language_server/*.cpp")
else:
# Using a define in the disabled case, to avoid having an extra define
# in regular builds where all modules are enabled.
- env_gdscript.Append(CPPDEFINES=['GDSCRIPT_NO_LSP'])
+ env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"])
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py
index a525eedaaa..185a10bcb2 100644
--- a/modules/gdscript/config.py
+++ b/modules/gdscript/config.py
@@ -1,9 +1,11 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"@GDScript",
@@ -12,5 +14,6 @@ def get_doc_classes():
"GDScriptNativeClass",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 2f6f9f30a4..9324691df5 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -90,14 +90,18 @@
</return>
<argument index="0" name="condition" type="bool">
</argument>
+ <argument index="1" name="message" type="String" default="&quot;&quot;">
+ </argument>
<description>
- Asserts that the [code]condition[/code] is [code]true[/code] . If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development.
+ Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development.
+ The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed.
[codeblock]
# Imagine we always want speed to be between 0 and 20
speed = -10
assert(speed &lt; 20) # True, the program will continue
assert(speed &gt;= 0) # False, the program will stop
assert(speed &gt;= 0 &amp;&amp; speed &lt; 20) # You can also combine the two conditional statements in one check
+ assert(speed &lt; 20, "speed = %f, but the speed limit is 20" % speed) # Show a message with clarifying details
[/codeblock]
</description>
</method>
@@ -1216,7 +1220,7 @@
<description>
Returns whether the given class exists in [ClassDB].
[codeblock]
- type_exists("Sprite") # Returns true
+ type_exists("Sprite2D") # Returns true
type_exists("Variant") # Returns false
[/codeblock]
</description>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 687e1785be..0aca4dbc5e 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -358,11 +358,11 @@ List<String> GDScriptSyntaxHighlighter::get_supported_languages() {
}
void GDScriptSyntaxHighlighter::_update_cache() {
- font_color = text_editor->get_color("font_color");
- symbol_color = text_editor->get_color("symbol_color");
- function_color = text_editor->get_color("function_color");
- number_color = text_editor->get_color("number_color");
- member_color = text_editor->get_color("member_variable_color");
+ font_color = text_editor->get_theme_color("font_color");
+ symbol_color = text_editor->get_theme_color("symbol_color");
+ function_color = text_editor->get_theme_color("function_color");
+ number_color = text_editor->get_theme_color("number_color");
+ member_color = text_editor->get_theme_color("member_variable_color");
const String text_editor_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
const bool default_theme = text_editor_color_theme == "Default";
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index d31823d632..9a4fa5cc86 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -114,13 +114,13 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
if (r_error.error != Callable::CallError::CALL_OK) {
instance->script = Ref<GDScript>();
- instance->owner->set_script_instance(NULL);
+ instance->owner->set_script_instance(nullptr);
{
MutexLock lock(GDScriptLanguage::singleton->lock);
instances.erase(p_owner);
}
- ERR_FAIL_COND_V(r_error.error != Callable::CallError::CALL_OK, NULL); //error constructing
+ ERR_FAIL_COND_V(r_error.error != Callable::CallError::CALL_OK, nullptr); //error constructing
}
//@TODO make thread safe
@@ -138,7 +138,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
r_error.error = Callable::CallError::CALL_OK;
REF ref;
- Object *owner = NULL;
+ Object *owner = nullptr;
GDScript *_baseptr = this;
while (_baseptr->_base) {
@@ -158,7 +158,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
ref = REF(r);
}
- GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error);
+ GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
if (!instance) {
if (ref.is_null()) {
memdelete(owner); //no owner, sorry
@@ -318,12 +318,12 @@ ScriptInstance *GDScript::instance_create(Object *p_this) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
}
- ERR_FAIL_V_MSG(NULL, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + ".");
+ ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + ".");
}
}
Callable::CallError unchecked_error;
- return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
+ return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error);
}
PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) {
@@ -333,7 +333,7 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this)
_update_exports();
return si;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -522,7 +522,7 @@ void GDScript::update_exports() {
void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
p_sc->path = p_path;
- for (Map<StringName, Ref<GDScript> >::Element *E = p_sc->subclasses.front(); E; E = E->next()) {
+ for (Map<StringName, Ref<GDScript>>::Element *E = p_sc->subclasses.front(); E; E = E->next()) {
_set_subclass_path(E->get(), p_path);
}
@@ -592,57 +592,12 @@ Error GDScript::reload(bool p_keep_state) {
valid = true;
- for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
+ for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
_set_subclass_path(E->get(), path);
}
- // Copy the base rpc methods so we don't mask their IDs.
- rpc_functions.clear();
- rpc_variables.clear();
- if (base.is_valid()) {
- rpc_functions = base->rpc_functions;
- rpc_variables = base->rpc_variables;
- }
-
- GDScript *cscript = this;
- Map<StringName, Ref<GDScript> >::Element *sub_E = subclasses.front();
- while (cscript) {
- // RPC Methods
- for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) {
- if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
- ScriptNetData nd;
- nd.name = E->key();
- nd.mode = E->get()->get_rpc_mode();
- if (-1 == rpc_functions.find(nd)) {
- rpc_functions.push_back(nd);
- }
- }
- }
- // RSet
- for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) {
- if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
- ScriptNetData nd;
- nd.name = E->key();
- nd.mode = E->get().rpc_mode;
- if (-1 == rpc_variables.find(nd)) {
- rpc_variables.push_back(nd);
- }
- }
- }
-
- if (cscript != this)
- sub_E = sub_E->next();
-
- if (sub_E)
- cscript = sub_E->get().ptr();
- else
- cscript = NULL;
- }
-
- // Sort so we are 100% that they are always the same.
- rpc_functions.sort_custom<SortNetData>();
- rpc_variables.sort_custom<SortNetData>();
+ _init_rpc_methods_properties();
return OK;
}
@@ -715,8 +670,8 @@ StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const {
}
MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
- ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
- return rpc_functions[p_rset_member_id].mode;
+ ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED);
+ return rpc_variables[p_rset_member_id].mode;
}
MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const {
@@ -733,7 +688,7 @@ Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p
ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
- return E->get()->call(NULL, p_args, p_argcount, r_error);
+ return E->get()->call(nullptr, p_args, p_argcount, r_error);
}
top = top->_base;
}
@@ -760,7 +715,7 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
}
{
- const Map<StringName, Ref<GDScript> >::Element *E = subclasses.find(p_name);
+ const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name);
if (E) {
r_ret = E->get();
@@ -876,11 +831,13 @@ Error GDScript::load_byte_code(const String &p_path) {
valid = true;
- for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
+ for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
_set_subclass_path(E->get(), path);
}
+ _init_rpc_methods_properties();
+
return OK;
}
@@ -953,7 +910,7 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
}
void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const Map<StringName, Vector<StringName> >::Element *E = _signals.front(); E; E = E->next()) {
+ for (const Map<StringName, Vector<StringName>>::Element *E = _signals.front(); E; E = E->next()) {
MethodInfo mi;
mi.name = E->key();
@@ -981,9 +938,9 @@ GDScript::GDScript() :
valid = false;
subclass_count = 0;
- initializer = NULL;
- _base = NULL;
- _owner = NULL;
+ initializer = nullptr;
+ _base = nullptr;
+ _owner = nullptr;
tool = false;
#ifdef TOOLS_ENABLED
source_changed_cache = false;
@@ -1006,8 +963,8 @@ void GDScript::_save_orphaned_subclasses() {
};
Vector<ClassRefWithName> weak_subclasses;
// collect subclasses ObjectID and name
- for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
- E->get()->_owner = NULL; //bye, you are no longer owned cause I died
+ for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
+ E->get()->_owner = nullptr; //bye, you are no longer owned cause I died
ClassRefWithName subclass;
subclass.id = E->get()->get_instance_id();
subclass.fully_qualified_name = E->get()->fully_qualified_name;
@@ -1030,6 +987,55 @@ void GDScript::_save_orphaned_subclasses() {
}
}
+void GDScript::_init_rpc_methods_properties() {
+ // Copy the base rpc methods so we don't mask their IDs.
+ rpc_functions.clear();
+ rpc_variables.clear();
+ if (base.is_valid()) {
+ rpc_functions = base->rpc_functions;
+ rpc_variables = base->rpc_variables;
+ }
+
+ GDScript *cscript = this;
+ Map<StringName, Ref<GDScript>>::Element *sub_E = subclasses.front();
+ while (cscript) {
+ // RPC Methods
+ for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) {
+ if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
+ ScriptNetData nd;
+ nd.name = E->key();
+ nd.mode = E->get()->get_rpc_mode();
+ if (-1 == rpc_functions.find(nd)) {
+ rpc_functions.push_back(nd);
+ }
+ }
+ }
+ // RSet
+ for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) {
+ if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) {
+ ScriptNetData nd;
+ nd.name = E->key();
+ nd.mode = E->get().rpc_mode;
+ if (-1 == rpc_variables.find(nd)) {
+ rpc_variables.push_back(nd);
+ }
+ }
+ }
+
+ if (cscript != this)
+ sub_E = sub_E->next();
+
+ if (sub_E)
+ cscript = sub_E->get().ptr();
+ else
+ cscript = nullptr;
+ }
+
+ // Sort so we are 100% that they are always the same.
+ rpc_functions.sort_custom<SortNetData>();
+ rpc_variables.sort_custom<SortNetData>();
+}
+
GDScript::~GDScript() {
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
memdelete(E->get());
@@ -1114,7 +1120,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
if (E) {
if (E->get().getter) {
Callable::CallError err;
- r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, NULL, 0, err);
+ r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
return true;
}
@@ -1188,7 +1194,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
if (E) {
Callable::CallError err;
- Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), NULL, 0, err);
+ Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
@@ -1345,7 +1351,7 @@ void GDScriptInstance::notification(int p_notification) {
String GDScriptInstance::to_string(bool *r_valid) {
if (has_method(CoreStringNames::get_singleton()->_to_string)) {
Callable::CallError ce;
- Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
+ Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
if (r_valid)
@@ -1444,7 +1450,7 @@ void GDScriptInstance::reload_members() {
}
GDScriptInstance::GDScriptInstance() {
- owner = NULL;
+ owner = nullptr;
base_ref = false;
}
@@ -1458,7 +1464,7 @@ GDScriptInstance::~GDScriptInstance() {
/************* SCRIPT LANGUAGE **************/
-GDScriptLanguage *GDScriptLanguage::singleton = NULL;
+GDScriptLanguage *GDScriptLanguage::singleton = nullptr;
String GDScriptLanguage::get_name() const {
@@ -1655,7 +1661,7 @@ void GDScriptLanguage::reload_all_scripts() {
#ifdef DEBUG_ENABLED
print_verbose("GDScript: Reloading all scripts");
- List<Ref<GDScript> > scripts;
+ List<Ref<GDScript>> scripts;
{
MutexLock lock(this->lock);
@@ -1673,7 +1679,7 @@ void GDScriptLanguage::reload_all_scripts() {
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
- for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
+ for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) {
print_verbose("GDScript: Reloading: " + E->get()->get_path());
E->get()->load_source_code(E->get()->get_path());
@@ -1686,7 +1692,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
#ifdef DEBUG_ENABLED
- List<Ref<GDScript> > scripts;
+ List<Ref<GDScript>> scripts;
{
MutexLock lock(this->lock);
@@ -1702,30 +1708,30 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//when someone asks you why dynamically typed languages are easier to write....
- Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
+ Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> to_reload;
//as scripts are going to be reloaded, must proceed without locking here
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
- for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
+ for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) {
bool reload = E->get() == p_script || to_reload.has(E->get()->get_base());
if (!reload)
continue;
- to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant> > >());
+ to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant>>>());
if (!p_soft_reload) {
//save state and remove script from instances
- Map<ObjectID, List<Pair<StringName, Variant> > > &map = to_reload[E->get()];
+ Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[E->get()];
while (E->get()->instances.front()) {
Object *obj = E->get()->instances.front()->get();
//save instance info
- List<Pair<StringName, Variant> > state;
+ List<Pair<StringName, Variant>> state;
if (obj->get_script_instance()) {
obj->get_script_instance()->get_property_state(state);
@@ -1743,8 +1749,8 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//save instance info
if (obj->get_script_instance()) {
- map.insert(obj->get_instance_id(), List<Pair<StringName, Variant> >());
- List<Pair<StringName, Variant> > &state = map[obj->get_instance_id()];
+ map.insert(obj->get_instance_id(), List<Pair<StringName, Variant>>());
+ List<Pair<StringName, Variant>> &state = map[obj->get_instance_id()];
obj->get_script_instance()->get_property_state(state);
obj->set_script(Variant());
} else {
@@ -1755,21 +1761,21 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
#endif
- for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) {
+ for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) {
map[F->key()] = F->get(); //pending to reload, use this one instead
}
}
}
- for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
+ for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>>::Element *E = to_reload.front(); E; E = E->next()) {
Ref<GDScript> scr = E->key();
scr->reload(p_soft_reload);
//restore state if saved
- for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) {
+ for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get().front(); F; F = F->next()) {
- List<Pair<StringName, Variant> > &saved_state = F->get();
+ List<Pair<StringName, Variant>> &saved_state = F->get();
Object *obj = ObjectDB::get_instance(F->key());
if (!obj)
@@ -1793,11 +1799,11 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
if (script_instance->is_placeholder() && scr->is_placeholder_fallback_enabled()) {
PlaceHolderScriptInstance *placeholder = static_cast<PlaceHolderScriptInstance *>(script_instance);
- for (List<Pair<StringName, Variant> >::Element *G = saved_state.front(); G; G = G->next()) {
+ for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) {
placeholder->property_set_fallback(G->get().first, G->get().second);
}
} else {
- for (List<Pair<StringName, Variant> >::Element *G = saved_state.front(); G; G = G->next()) {
+ for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) {
script_instance->set(G->get().first, G->get().second);
}
}
@@ -1894,7 +1900,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"remotesync",
"mastersync",
"puppetsync",
- 0
+ nullptr
};
const char **w = _reserved_words;
@@ -1927,7 +1933,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
String source = f->get_as_utf8_string();
GDScriptParser parser;
- parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true);
+ parser.parse(source, p_path.get_base_dir(), true, p_path, false, nullptr, true);
if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) {
@@ -1948,7 +1954,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (subclass->extends_file) {
if (subclass->extends_class.size() == 0) {
get_global_class_name(subclass->extends_file, r_base_type);
- subclass = NULL;
+ subclass = nullptr;
break;
} else {
Vector<StringName> extend_classes = subclass->extends_class;
@@ -1967,7 +1973,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
subpath = path.get_base_dir().plus_file(subpath).simplify_path();
}
- if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, NULL, true)) {
+ if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, nullptr, true)) {
break;
}
path = subpath;
@@ -1988,20 +1994,20 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
}
if (!found) {
- subclass = NULL;
+ subclass = nullptr;
break;
}
}
}
} else if (subclass->extends_class.size() == 1) {
*r_base_type = subclass->extends_class[0];
- subclass = NULL;
+ subclass = nullptr;
} else {
break;
}
} else {
*r_base_type = "Reference";
- subclass = NULL;
+ subclass = nullptr;
}
}
}
@@ -2162,7 +2168,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"UNSAFE_CALL_ARGUMENT",
"DEPRECATED_KEYWORD",
"STANDALONE_TERNARY",
- NULL
+ nullptr
};
return names[(int)p_code];
@@ -2209,7 +2215,7 @@ GDScriptLanguage::GDScriptLanguage() {
} else {
_debug_max_call_stack = 0;
- _call_stack = NULL;
+ _call_stack = nullptr;
}
#ifdef DEBUG_ENABLED
@@ -2230,7 +2236,7 @@ GDScriptLanguage::~GDScriptLanguage() {
if (_call_stack) {
memdelete_arr(_call_stack);
}
- singleton = NULL;
+ singleton = nullptr;
}
void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
@@ -2313,7 +2319,7 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
}
GDScriptParser parser;
- if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true)) {
+ if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, nullptr, true)) {
return;
}
@@ -2357,5 +2363,5 @@ void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resourc
}
bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
- return Object::cast_to<GDScript>(*p_resource) != NULL;
+ return Object::cast_to<GDScript>(*p_resource) != nullptr;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 456cd88fe6..2c5876372b 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -84,8 +84,8 @@ class GDScript : public Script {
Map<StringName, Variant> constants;
Map<StringName, GDScriptFunction *> member_functions;
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
- Map<StringName, Ref<GDScript> > subclasses;
- Map<StringName, Vector<StringName> > _signals;
+ Map<StringName, Ref<GDScript>> subclasses;
+ Map<StringName, Vector<StringName>> _signals;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
@@ -129,13 +129,14 @@ class GDScript : public Script {
#ifdef DEBUG_ENABLED
- Map<ObjectID, List<Pair<StringName, Variant> > > pending_reload_state;
+ Map<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state;
#endif
bool _update_exports();
void _save_orphaned_subclasses();
+ void _init_rpc_methods_properties();
protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -150,7 +151,7 @@ protected:
public:
virtual bool is_valid() const { return valid; }
- const Map<StringName, Ref<GDScript> > &get_subclasses() const { return subclasses; }
+ const Map<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; }
const Map<StringName, Variant> &get_constants() const { return constants; }
const Set<StringName> &get_members() const { return members; }
const GDScriptDataType &get_member_type(const StringName &p_member) const {
@@ -259,7 +260,7 @@ public:
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
@@ -482,7 +483,7 @@ public:
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool is_using_templates();
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -518,7 +519,7 @@ public:
virtual void frame();
virtual void get_public_functions(List<MethodInfo> *p_functions) const;
- virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const;
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const;
virtual void profiling_start();
virtual void profiling_stop();
@@ -533,7 +534,7 @@ public:
/* GLOBAL CLASSES */
virtual bool handles_global_class_type(const String &p_type) const;
- virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const;
void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);
@@ -544,7 +545,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 42efdeffbb..2bbec29043 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -46,7 +46,7 @@ bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringN
bool GDScriptCompiler::_is_class_member_property(GDScript *owner, const StringName &p_name) {
GDScript *scr = owner;
- GDScriptNativeClass *nc = NULL;
+ GDScriptNativeClass *nc = nullptr;
while (scr) {
if (scr->native.is_valid())
@@ -265,7 +265,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
while (owner) {
GDScript *scr = owner;
- GDScriptNativeClass *nc = NULL;
+ GDScriptNativeClass *nc = nullptr;
while (scr) {
if (scr->constants.has(identifier)) {
@@ -1700,14 +1700,14 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
gdfunc->_constant_count = codegen.constant_map.size();
gdfunc->constants.resize(codegen.constant_map.size());
gdfunc->_constants_ptr = gdfunc->constants.ptrw();
- const Variant *K = NULL;
+ const Variant *K = nullptr;
while ((K = codegen.constant_map.next(K))) {
int idx = codegen.constant_map[*K];
gdfunc->constants.write[idx] = *K;
}
} else {
- gdfunc->_constants_ptr = NULL;
+ gdfunc->_constants_ptr = nullptr;
gdfunc->_constant_count = 0;
}
//global names
@@ -1722,7 +1722,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
gdfunc->_global_names_count = gdfunc->global_names.size();
} else {
- gdfunc->_global_names_ptr = NULL;
+ gdfunc->_global_names_ptr = nullptr;
gdfunc->_global_names_count = 0;
}
@@ -1746,7 +1746,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
} else {
- gdfunc->_code_ptr = NULL;
+ gdfunc->_code_ptr = nullptr;
gdfunc->_code_size = 0;
}
@@ -1757,7 +1757,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
gdfunc->_default_arg_ptr = &gdfunc->default_arguments[0];
} else {
gdfunc->_default_arg_count = 0;
- gdfunc->_default_arg_ptr = NULL;
+ gdfunc->_default_arg_ptr = nullptr;
}
gdfunc->_argument_count = p_func ? p_func->arguments.size() : 0;
@@ -1838,7 +1838,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->native = Ref<GDScriptNativeClass>();
p_script->base = Ref<GDScript>();
- p_script->_base = NULL;
+ p_script->_base = nullptr;
p_script->members.clear();
p_script->constants.clear();
for (Map<StringName, GDScriptFunction *>::Element *E = p_script->member_functions.front(); E; E = E->next()) {
@@ -1848,7 +1848,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->member_indices.clear();
p_script->member_info.clear();
p_script->_signals.clear();
- p_script->initializer = NULL;
+ p_script->initializer = nullptr;
p_script->tool = p_class->tool;
p_script->name = p_class->name;
@@ -1962,7 +1962,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
if (c->base.is_valid()) {
c = c->base.ptr();
} else {
- c = NULL;
+ c = nullptr;
}
}
@@ -2032,14 +2032,14 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_initializer) {
//create a constructor
- Error err = _parse_function(p_script, p_class, NULL);
+ Error err = _parse_function(p_script, p_class, nullptr);
if (err)
return err;
}
if (!has_ready && p_class->ready->statements.size()) {
//create a constructor
- Error err = _parse_function(p_script, p_class, NULL, true);
+ Error err = _parse_function(p_script, p_class, nullptr, true);
if (err)
return err;
}
@@ -2077,7 +2077,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
/* STEP 2, INITIALIZE AND CONSTRUCT */
Callable::CallError ce;
- p_script->initializer->call(instance, NULL, 0, ce);
+ p_script->initializer->call(instance, nullptr, 0, ce);
if (ce.error != Callable::CallError::CALL_OK) {
//well, tough luck, not goinna do anything here
@@ -2111,7 +2111,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
- Map<StringName, Ref<GDScript> > old_subclasses;
+ Map<StringName, Ref<GDScript>> old_subclasses;
if (p_keep_state) {
old_subclasses = p_script->subclasses;
@@ -2162,7 +2162,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
// Create scripts for subclasses beforehand so they can be referenced
_make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
- p_script->_owner = NULL;
+ p_script->_owner = nullptr;
Error err = _parse_class_level(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
if (err)
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 7d5234a023..34b066b5c7 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -48,11 +48,11 @@ class GDScriptCompiler {
const GDScriptParser::FunctionNode *function_node;
bool debug_stack;
- List<Map<StringName, int> > stack_id_stack;
+ List<Map<StringName, int>> stack_id_stack;
Map<StringName, int> stack_identifiers;
List<GDScriptFunction::StackDebug> stack_debug;
- List<Map<StringName, int> > block_identifier_stack;
+ List<Map<StringName, int>> block_identifier_stack;
Map<StringName, int> block_identifiers;
void add_stack_identifier(const StringName &p_id, int p_stackpos) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 966a3db840..2ec3352e70 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -299,10 +299,10 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p
GDScriptFunction *f = _call_stack[l].function;
- List<Pair<StringName, int> > locals;
+ List<Pair<StringName, int>> locals;
f->debug_get_stack_member_state(*_call_stack[l].line, &locals);
- for (List<Pair<StringName, int> >::Element *E = locals.front(); E; E = E->next()) {
+ for (List<Pair<StringName, int>>::Element *E = locals.front(); E; E = E->next()) {
p_locals->push_back(E->get().first);
p_values->push_back(_call_stack[l].stack[E->get().second]);
@@ -336,9 +336,9 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
if (_debug_parse_err_line >= 0)
- return NULL;
+ return nullptr;
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, NULL);
+ ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, nullptr);
int l = _debug_call_stack_pos - p_level - 1;
ScriptInstance *instance = _call_stack[l].instance;
@@ -351,7 +351,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array();
- List<Pair<String, Variant> > cinfo;
+ List<Pair<String, Variant>> cinfo;
get_public_constants(&cinfo);
for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) {
@@ -360,7 +360,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
continue;
bool is_script_constant = false;
- for (List<Pair<String, Variant> >::Element *CE = cinfo.front(); CE; CE = CE->next()) {
+ for (List<Pair<String, Variant>>::Element *CE = cinfo.front(); CE; CE = CE->next()) {
if (CE->get().first == E->key()) {
is_script_constant = true;
break;
@@ -430,11 +430,13 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const
mi.name = "assert";
mi.return_val.type = Variant::NIL;
mi.arguments.push_back(PropertyInfo(Variant::BOOL, "condition"));
+ mi.arguments.push_back(PropertyInfo(Variant::STRING, "message"));
+ mi.default_arguments.push_back(String());
p_functions->push_back(mi);
}
}
-void GDScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
+void GDScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const {
Pair<String, Variant> pi;
pi.first = "PI";
@@ -499,10 +501,10 @@ struct GDScriptCompletionContext {
uint32_t depth;
GDScriptCompletionContext() :
- _class(NULL),
- function(NULL),
- block(NULL),
- base(NULL),
+ _class(nullptr),
+ function(nullptr),
+ block(nullptr),
+ base(nullptr),
line(0),
depth(0) {}
};
@@ -514,7 +516,7 @@ struct GDScriptCompletionIdentifier {
const GDScriptParser::Node *assigned_expression;
GDScriptCompletionIdentifier() :
- assigned_expression(NULL) {}
+ assigned_expression(nullptr) {}
};
static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) {
@@ -909,7 +911,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G
Variant ret = mb->call(baseptr, (const Variant **)argptr.ptr(), argptr.size(), ce);
if (ce.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
- if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != NULL) {
+ if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != nullptr) {
r_type = _type_from_variant(ret);
found = true;
}
@@ -963,7 +965,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G
break;
}
- const GDScriptParser::DictionaryNode *dn = NULL;
+ const GDScriptParser::DictionaryNode *dn = nullptr;
if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) {
dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]);
} else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) {
@@ -1017,7 +1019,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G
}
// Look if it is a dictionary node
- const GDScriptParser::DictionaryNode *dn = NULL;
+ const GDScriptParser::DictionaryNode *dn = nullptr;
if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) {
dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]);
} else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) {
@@ -1041,7 +1043,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G
// Look if it is an array node
if (!found && index.value.is_num()) {
int idx = index.value;
- const GDScriptParser::ArrayNode *an = NULL;
+ const GDScriptParser::ArrayNode *an = nullptr;
if (op->arguments[0]->type == GDScriptParser::Node::TYPE_ARRAY) {
an = static_cast<const GDScriptParser::ArrayNode *>(op->arguments[0]);
} else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_ARRAY) {
@@ -1061,7 +1063,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G
found = _guess_identifier_type_from_base(c, base, id, r_type);
} else if (!found && index.type.kind == GDScriptParser::DataType::BUILTIN) {
Callable::CallError err;
- Variant base_val = Variant::construct(base.type.builtin_type, NULL, 0, err);
+ Variant base_val = Variant::construct(base.type.builtin_type, nullptr, 0, err);
bool valid = false;
Variant res = base_val.get(index.value, &valid);
if (valid) {
@@ -1116,9 +1118,9 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G
Callable::CallError ce;
bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT;
- Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, NULL, 0, ce);
+ Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, nullptr, 0, ce);
bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT;
- Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, NULL, 0, ce);
+ Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, nullptr, 0, ce);
// avoid potential invalid ops
if ((vop == Variant::OP_DIVIDE || vop == Variant::OP_MODULE) && v2.get_type() == Variant::INT) {
v2 = 1;
@@ -1173,7 +1175,7 @@ static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const S
// Look in blocks first
const GDScriptParser::BlockNode *blk = p_context.block;
int last_assign_line = -1;
- const GDScriptParser::Node *last_assigned_expression = NULL;
+ const GDScriptParser::Node *last_assigned_expression = nullptr;
GDScriptParser::DataType var_type;
while (blk) {
if (blk->variables.has(p_identifier)) {
@@ -1227,7 +1229,7 @@ static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const S
r_type.type.is_meta_type = false; // Right-hand of `is` will be a meta type, but the left-hand value is not
// Not an assignment, it shouldn't carry any value
r_type.value = Variant();
- r_type.assigned_expression = NULL;
+ r_type.assigned_expression = nullptr;
return true;
}
@@ -1271,8 +1273,8 @@ static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const S
return false;
}
GDScriptCompletionContext c = p_context;
- c.function = NULL;
- c.block = NULL;
+ c.function = nullptr;
+ c.block = nullptr;
return _guess_expression_type(c, op->arguments[1], r_type);
}
}
@@ -1534,7 +1536,7 @@ static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_contex
} break;
case GDScriptParser::DataType::BUILTIN: {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return false;
@@ -1612,7 +1614,7 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con
for (int i = 0; i < base_type.class_type->static_functions.size(); i++) {
if (base_type.class_type->static_functions[i]->name == p_method) {
int last_return_line = -1;
- const GDScriptParser::Node *last_returned_value = NULL;
+ const GDScriptParser::Node *last_returned_value = nullptr;
GDScriptCompletionContext c = p_context;
c._class = base_type.class_type;
c.function = base_type.class_type->static_functions[i];
@@ -1629,7 +1631,7 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con
for (int i = 0; i < base_type.class_type->functions.size(); i++) {
if (base_type.class_type->functions[i]->name == p_method) {
int last_return_line = -1;
- const GDScriptParser::Node *last_returned_value = NULL;
+ const GDScriptParser::Node *last_returned_value = nullptr;
GDScriptCompletionContext c = p_context;
c._class = base_type.class_type;
c.function = base_type.class_type->functions[i];
@@ -1704,7 +1706,7 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con
} break;
case GDScriptParser::DataType::BUILTIN: {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return false;
}
@@ -1911,8 +1913,8 @@ static void _find_identifiers_in_class(const GDScriptCompletionContext &p_contex
base_type.value = p_context.base;
GDScriptCompletionContext c = p_context;
- c.block = NULL;
- c.function = NULL;
+ c.block = nullptr;
+ c.function = nullptr;
_find_identifiers_in_base(c, base_type, p_only_functions, r_result);
}
@@ -1932,8 +1934,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
case GDScriptParser::DataType::CLASS: {
GDScriptCompletionContext c = p_context;
c._class = base_type.class_type;
- c.block = NULL;
- c.function = NULL;
+ c.block = nullptr;
+ c.function = nullptr;
_find_identifiers_in_class(c, _static, p_only_functions, false, r_result);
base_type = base_type.class_type->base_type;
} break;
@@ -1972,7 +1974,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
}
}
if (!p_only_functions) {
- for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) {
+ for (const Map<StringName, Ref<GDScript>>::Element *E = script->get_subclasses().front(); E; E = E->next()) {
ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
r_result.insert(option.display, option);
}
@@ -2089,7 +2091,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
} break;
case GDScriptParser::DataType::BUILTIN: {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return;
}
@@ -2153,8 +2155,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
while (clss) {
GDScriptCompletionContext c = p_context;
c._class = clss;
- c.block = NULL;
- c.function = NULL;
+ c.block = nullptr;
+ c.function = nullptr;
_find_identifiers_in_class(c, _static, p_only_functions, false, r_result);
_static = true;
clss = clss->owner;
@@ -2188,7 +2190,7 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p
"const", "enum", "export", "onready", "static", "var", "break", "continue", "if", "elif",
"else", "for", "pass", "return", "match", "while", "remote", "master", "puppet",
"remotesync", "mastersync", "puppetsync",
- 0
+ nullptr
};
const char **kw = _keywords;
@@ -2234,6 +2236,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
+#define IS_METHOD_SIGNAL(m_method) (m_method == "connect" || m_method == "disconnect" || m_method == "is_connected" || m_method == "emit_signal")
+
while (base_type.has_type) {
switch (base_type.kind) {
case GDScriptParser::DataType::CLASS: {
@@ -2250,7 +2254,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
}
}
- if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) {
+ if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) {
for (int i = 0; i < base_type.class_type->_signals.size(); i++) {
ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL);
option.insert_text = quote_style + option.display + quote_style;
@@ -2263,7 +2267,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
case GDScriptParser::DataType::GDSCRIPT: {
Ref<GDScript> gds = base_type.script_type;
if (gds.is_valid()) {
- if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) {
+ if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) {
List<MethodInfo> signals;
gds->get_script_signal_list(&signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
@@ -2325,7 +2329,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
}
}
- if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) {
+ if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) {
List<MethodInfo> signals;
ClassDB::get_signal_list(class_name, &signals);
for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) {
@@ -2334,6 +2338,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
r_result.insert(option.display, option);
}
}
+#undef IS_METHOD_SIGNAL
if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) {
// Get autoloads
@@ -2373,7 +2378,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con
case GDScriptParser::DataType::BUILTIN: {
if (base.get_type() == Variant::NIL) {
Callable::CallError err;
- base = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ base = Variant::construct(base_type.builtin_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
return;
}
@@ -2542,7 +2547,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
context.function = parser.get_completion_function();
context.line = parser.get_completion_line();
- if (!context._class || context._class->owner == NULL) {
+ if (!context._class || context._class->owner == nullptr) {
context.base = p_owner;
context.base_path = p_path.get_base_dir();
}
@@ -2626,13 +2631,13 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
}
GDScriptCompletionContext c = context;
- c.function = NULL;
- c.block = NULL;
- c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : NULL;
+ c.function = nullptr;
+ c.block = nullptr;
+ c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : nullptr;
if (base.type.kind == GDScriptParser::DataType::CLASS) {
c._class = base.type.class_type;
} else {
- c._class = NULL;
+ c._class = nullptr;
}
_find_identifiers_in_base(c, base, is_function, options);
@@ -2818,8 +2823,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = clss->constant_expressions.front(); E; E = E->next()) {
GDScriptCompletionIdentifier constant;
GDScriptCompletionContext c = context;
- c.function = NULL;
- c.block = NULL;
+ c.function = nullptr;
+ c.block = nullptr;
c.line = E->value().expression->line;
if (_guess_expression_type(c, E->value().expression, constant)) {
if (constant.type.has_type && constant.type.is_meta_type) {
@@ -2887,9 +2892,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
}
GDScriptCompletionContext c = context;
- c._class = NULL;
- c.function = NULL;
- c.block = NULL;
+ c._class = nullptr;
+ c.function = nullptr;
+ c.block = nullptr;
bool finding = true;
index = index.right(index.find(".") + 1);
while (index.find(".") != -1) {
@@ -2917,8 +2922,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
GDScriptCompletionIdentifier constant;
GDScriptCompletionContext c2 = context;
c2._class = base_type.class_type;
- c2.function = NULL;
- c2.block = NULL;
+ c2.function = nullptr;
+ c2.block = nullptr;
c2.line = E->value().expression->line;
if (_guess_expression_type(c2, E->value().expression, constant)) {
if (constant.type.has_type && constant.type.is_meta_type) {
@@ -3220,7 +3225,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
v = v_ref;
} else {
Callable::CallError err;
- v = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ v = Variant::construct(base_type.builtin_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
break;
}
@@ -3440,7 +3445,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 3f73654a1e..ca4d6f6de9 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -45,7 +45,7 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
#ifdef DEBUG_ENABLED
if (unlikely(!p_instance)) {
r_error = "Cannot access self without instance.";
- return NULL;
+ return nullptr;
}
#endif
return &self;
@@ -58,7 +58,7 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
#ifdef DEBUG_ENABLED
if (unlikely(!p_instance)) {
r_error = "Cannot access member without instance.";
- return NULL;
+ return nullptr;
}
#endif
//member indexing is O(1)
@@ -69,7 +69,7 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
//todo change to index!
GDScript *s = p_script;
#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, NULL);
+ ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
#endif
const StringName *sn = &_global_names_ptr[address];
@@ -86,31 +86,31 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
s = s->_base;
}
- ERR_FAIL_V_MSG(NULL, "GDScriptCompiler bug.");
+ ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
} break;
case ADDR_TYPE_LOCAL_CONSTANT: {
#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _constant_count, NULL);
+ 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, NULL);
+ 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(), NULL);
+ 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, _named_globals_count, NULL);
+ ERR_FAIL_INDEX_V(address, _named_globals_count, nullptr);
#endif
StringName id = _named_globals_ptr[address];
@@ -118,7 +118,7 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
} else {
r_error = "Autoload singleton '" + String(id) + "' has been removed.";
- return NULL;
+ return nullptr;
}
} break;
#endif
@@ -127,8 +127,8 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
} break;
}
- ERR_FAIL_V_MSG(NULL, "Bad code! (unknown addressing mode).");
- return NULL;
+ ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
+ return nullptr;
}
#ifdef DEBUG_ENABLED
@@ -272,7 +272,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Variant self;
Variant static_ref;
Variant retvalue;
- Variant *stack = NULL;
+ Variant *stack = nullptr;
Variant **call_args;
int defarg = 0;
@@ -358,7 +358,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&stack[i], Variant);
}
} else {
- stack = NULL;
+ stack = nullptr;
}
if (_call_size) {
@@ -366,12 +366,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
- call_args = NULL;
+ call_args = nullptr;
}
} else {
- stack = NULL;
- call_args = NULL;
+ stack = nullptr;
+ call_args = nullptr;
}
if (p_instance) {
@@ -490,7 +490,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, 3);
#ifdef DEBUG_ENABLED
- if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) {
+ if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) {
err_text = "Right operand of 'is' is not a class.";
OPCODE_BREAK;
@@ -498,7 +498,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
bool extends_ok = false;
- if (a->get_type() == Variant::OBJECT && a->operator Object *() != NULL) {
+ if (a->get_type() == Variant::OBJECT && a->operator Object *() != nullptr) {
#ifdef DEBUG_ENABLED
bool was_freed;
@@ -855,7 +855,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_BREAK;
}
- if (src->get_type() != Variant::NIL && src->operator Object *() != NULL) {
+ if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
if (!scr_inst) {
@@ -960,7 +960,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
bool valid = false;
- if (src->get_type() != Variant::NIL && src->operator Object *() != NULL) {
+ if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) {
ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
@@ -1099,7 +1099,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
base->call_ptr(*methodname, (const Variant **)argptrs, argc, ret, err);
} else {
- base->call_ptr(*methodname, (const Variant **)argptrs, argc, NULL, err);
+ base->call_ptr(*methodname, (const Variant **)argptrs, argc, nullptr, err);
}
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
@@ -1137,7 +1137,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
#endif
- //_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
+ //_call_func(nullptr,base,*methodname,ip,argc,p_instance,stack);
ip += argc + 1;
}
DISPATCH_OPCODE;
@@ -1216,7 +1216,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
const GDScript *gds = _script;
- const Map<StringName, GDScriptFunction *>::Element *E = NULL;
+ const Map<StringName, GDScriptFunction *>::Element *E = nullptr;
while (gds->base.ptr()) {
gds = gds->base.ptr();
E = gds->member_functions.find(*methodname);
@@ -1707,7 +1707,7 @@ struct _GDFKCS {
}
};
-void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int> > *r_stackvars) const {
+void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const {
int oc = 0;
Map<StringName, _GDFKC> sdmap;
@@ -1767,7 +1767,7 @@ GDScriptFunction::GDScriptFunction() :
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
name = "<anonymous>";
#ifdef DEBUG_ENABLED
- _func_cname = NULL;
+ _func_cname = nullptr;
{
MutexLock lock(GDScriptLanguage::get_singleton()->lock);
@@ -1834,7 +1834,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar
bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
- if (function == NULL)
+ if (function == nullptr)
return false;
if (p_extended_check) {
@@ -1859,7 +1859,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
state.result = p_arg;
Callable::CallError err;
- Variant ret = function->call(NULL, NULL, 0, err, &state);
+ Variant ret = function->call(nullptr, nullptr, 0, err, &state);
bool completed = true;
@@ -1873,7 +1873,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
}
}
- function = NULL; //cleaned up;
+ function = nullptr; //cleaned up;
state.result = Variant();
if (completed) {
@@ -1909,12 +1909,12 @@ void GDScriptFunctionState::_bind_methods() {
GDScriptFunctionState::GDScriptFunctionState() {
- function = NULL;
+ function = nullptr;
}
GDScriptFunctionState::~GDScriptFunctionState() {
- if (function != NULL) {
+ if (function != nullptr) {
//never called, deinitialize stack
for (int i = 0; i < state.stack_size; i++) {
Variant *v = (Variant *)&state.stack[sizeof(Variant) * i];
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 34019e563d..acfc0a95b4 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -105,7 +105,7 @@ struct GDScriptDataType {
return false;
}
- Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : NULL;
+ Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : nullptr;
bool valid = false;
while (base.is_valid()) {
if (base == script_type) {
@@ -321,7 +321,7 @@ public:
GDScript *get_script() const { return _script; }
StringName get_source() const { return source; }
- void debug_get_stack_member_state(int p_line, List<Pair<StringName, int> > *r_stackvars) const;
+ void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const;
_FORCE_INLINE_ bool is_empty() const { return _code_size == 0; }
@@ -339,7 +339,7 @@ public:
return default_arguments[p_idx];
}
- Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = NULL);
+ Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr);
_FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; }
GDScriptFunction();
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index aaa308f40f..9154d6eb89 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -858,7 +858,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
PackedByteArray barr;
int len;
- Error err = encode_variant(*p_args[0], NULL, len, full_objects);
+ Error err = encode_variant(*p_args[0], nullptr, len, full_objects);
if (err) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -908,7 +908,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
Variant ret;
{
const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), NULL, allow_objects);
+ Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
if (err != OK) {
r_ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
@@ -1198,7 +1198,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
}
}
- r_ret = gdscr->_new(NULL, 0, r_error);
+ r_ret = gdscr->_new(nullptr, 0, r_error);
GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(r_ret)->get_script_instance());
Ref<GDScript> gd_ref = ins->get_script();
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index b42fcba7d3..8d34ce5c70 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -242,7 +242,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
Vector<Expression> expression;
- Node *expr = NULL;
+ Node *expr = nullptr;
int op_line = tokenizer->get_token_line(); // when operators are created at the bottom, the line might have been changed (\n found)
@@ -276,12 +276,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
Node *subexpr = _parse_expression(p_parent, p_static, p_allow_assign, p_parsing_constant);
parenthesis--;
if (!subexpr)
- return NULL;
+ return nullptr;
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')' in expression");
- return NULL;
+ return nullptr;
}
tokenizer->advance();
@@ -318,7 +318,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (tokenizer->get_token_constant().get_type() != Variant::STRING) {
_set_error("Expected string constant or identifier after '$' or '/'.");
- return NULL;
+ return nullptr;
}
path += String(tokenizer->get_token_constant());
@@ -355,7 +355,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (path == "") {
_set_error("Path expected after $.");
- return NULL;
+ return nullptr;
}
OperatorNode *op = alloc_node<OperatorNode>();
@@ -427,7 +427,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
tokenizer->advance();
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
_set_error("Expected '(' after 'preload'");
- return NULL;
+ return nullptr;
}
tokenizer->advance();
@@ -476,7 +476,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (!valid) {
_set_error("expected string constant as 'preload' argument.");
- return NULL;
+ return nullptr;
}
if (!path.is_abs_path() && base_path != "")
@@ -485,7 +485,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (path == self_path) {
_set_error("Can't preload itself (use 'get_script()').");
- return NULL;
+ return nullptr;
}
Ref<Resource> res;
@@ -503,26 +503,26 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (!FileAccess::exists(path)) {
_set_error("Can't preload resource at path: " + path);
- return NULL;
+ return nullptr;
} else if (ScriptCodeCompletionCache::get_singleton()) {
res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path);
}
}
if (!res.is_valid()) {
_set_error("Can't preload resource at path: " + path);
- return NULL;
+ return nullptr;
}
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')' after 'preload' path");
- return NULL;
+ return nullptr;
}
Ref<GDScript> gds = res;
if (gds.is_valid() && !gds->is_valid()) {
_set_error("Couldn't fully preload the script, possible cyclic reference or compilation error. Use \"load()\" instead if a cyclic reference is intended.");
- return NULL;
+ return nullptr;
}
tokenizer->advance();
@@ -536,7 +536,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (!current_function) {
_set_error("\"yield()\" can only be used inside function blocks.");
- return NULL;
+ return nullptr;
}
current_function->has_yield = true;
@@ -544,7 +544,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
tokenizer->advance();
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
_set_error("Expected \"(\" after \"yield\".");
- return NULL;
+ return nullptr;
}
tokenizer->advance();
@@ -565,12 +565,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
Node *object = _parse_and_reduce_expression(p_parent, p_static);
if (!object)
- return NULL;
+ return nullptr;
yield->arguments.push_back(object);
if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) {
_set_error("Expected \",\" after the first argument of \"yield\".");
- return NULL;
+ return nullptr;
}
tokenizer->advance();
@@ -591,12 +591,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
Node *signal = _parse_and_reduce_expression(p_parent, p_static);
if (!signal)
- return NULL;
+ return nullptr;
yield->arguments.push_back(signal);
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
_set_error("Expected \")\" after the second argument of \"yield\".");
- return NULL;
+ return nullptr;
}
parenthesis--;
@@ -610,7 +610,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (p_static) {
_set_error("\"self\" isn't allowed in a static function or constant expression.");
- return NULL;
+ return nullptr;
}
//constant defined by tokenizer
SelfNode *self = alloc_node<SelfNode>();
@@ -631,7 +631,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (identifier == StringName()) {
_set_error("Built-in type constant or static function expected after \".\".");
- return NULL;
+ return nullptr;
}
if (!Variant::has_constant(bi_type, identifier)) {
@@ -657,7 +657,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
op->arguments.push_back(id);
if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant))
- return NULL;
+ return nullptr;
expr = op;
} else {
@@ -674,7 +674,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
if (!valid) {
_set_error("Static constant '" + identifier.operator String() + "' not present in built-in type " + Variant::get_type_name(bi_type) + ".");
- return NULL;
+ return nullptr;
}
}
} else {
@@ -749,7 +749,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
if (!replaced) {
if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant))
- return NULL;
+ return nullptr;
expr = op;
}
} else if (tokenizer->is_token_literal(0, true)) {
@@ -789,7 +789,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (lv->assignments == 0) {
if (!lv->datatype.has_type) {
_set_error("Using assignment with operation on a variable that was never assigned.");
- return NULL;
+ return nullptr;
}
_add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String());
}
@@ -912,7 +912,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (e.op != OperatorNode::OP_NOT && tokenizer->get_token() == GDScriptTokenizer::TK_OP_NOT) {
_set_error("Misplaced 'not'.");
- return NULL;
+ return nullptr;
}
expression.push_back(e);
@@ -921,7 +921,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
/*
Node *subexpr=_parse_expression(op,p_static);
if (!subexpr)
- return NULL;
+ return nullptr;
op->arguments.push_back(subexpr);
expr=op;*/
@@ -929,7 +929,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
// 'is' operator with built-in type
if (!expr) {
_set_error("Expected identifier before 'is' operator");
- return NULL;
+ return nullptr;
}
OperatorNode *op = alloc_node<OperatorNode>();
op->op = OperatorNode::OP_IS_BUILTIN;
@@ -955,7 +955,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (tokenizer->get_token() == GDScriptTokenizer::TK_EOF) {
_set_error("Unterminated array");
- return NULL;
+ return nullptr;
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_BRACKET_CLOSE) {
tokenizer->advance();
@@ -966,7 +966,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
if (!expecting_comma) {
_set_error("expression or ']' expected");
- return NULL;
+ return nullptr;
}
expecting_comma = false;
@@ -975,11 +975,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
//parse expression
if (expecting_comma) {
_set_error("',' or ']' expected");
- return NULL;
+ return nullptr;
}
Node *n = _parse_expression(arr, p_static, p_allow_assign, p_parsing_constant);
if (!n)
- return NULL;
+ return nullptr;
arr->elements.push_back(n);
expecting_comma = true;
}
@@ -1001,7 +1001,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
};
- Node *key = NULL;
+ Node *key = nullptr;
Set<Variant> keys;
DictExpect expecting = DICT_EXPECT_KEY;
@@ -1011,17 +1011,17 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (tokenizer->get_token() == GDScriptTokenizer::TK_EOF) {
_set_error("Unterminated dictionary");
- return NULL;
+ return nullptr;
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_CURLY_BRACKET_CLOSE) {
if (expecting == DICT_EXPECT_COLON) {
_set_error("':' expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_VALUE) {
_set_error("value expected");
- return NULL;
+ return nullptr;
}
tokenizer->advance();
break;
@@ -1032,15 +1032,15 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expecting == DICT_EXPECT_KEY) {
_set_error("key or '}' expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_VALUE) {
_set_error("value expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_COLON) {
_set_error("':' expected");
- return NULL;
+ return nullptr;
}
expecting = DICT_EXPECT_KEY;
@@ -1050,15 +1050,15 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expecting == DICT_EXPECT_KEY) {
_set_error("key or '}' expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_VALUE) {
_set_error("value expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_COMMA) {
_set_error("',' or '}' expected");
- return NULL;
+ return nullptr;
}
expecting = DICT_EXPECT_VALUE;
@@ -1067,11 +1067,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expecting == DICT_EXPECT_COMMA) {
_set_error("',' or '}' expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_COLON) {
_set_error("':' expected");
- return NULL;
+ return nullptr;
}
if (expecting == DICT_EXPECT_KEY) {
@@ -1089,7 +1089,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
//python/js style more flexible
key = _parse_expression(dict, p_static, p_allow_assign, p_parsing_constant);
if (!key)
- return NULL;
+ return nullptr;
expecting = DICT_EXPECT_COLON;
}
}
@@ -1097,7 +1097,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expecting == DICT_EXPECT_VALUE) {
Node *value = _parse_expression(dict, p_static, p_allow_assign, p_parsing_constant);
if (!value)
- return NULL;
+ return nullptr;
expecting = DICT_EXPECT_COMMA;
if (key->type == GDScriptParser::Node::TYPE_CONSTANT) {
@@ -1105,7 +1105,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (keys.has(keyName)) {
_set_error("Duplicate key found in Dictionary literal");
- return NULL;
+ return nullptr;
}
keys.insert(keyName);
}
@@ -1114,7 +1114,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
pair.key = key;
pair.value = value;
dict->elements.push_back(pair);
- key = NULL;
+ key = nullptr;
}
}
}
@@ -1142,12 +1142,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
if (!is_completion) {
_set_error("Expected '(' for parent function call.");
- return NULL;
+ return nullptr;
}
} else {
tokenizer->advance();
if (!_parse_arguments(op, op->arguments, p_static, false, p_parsing_constant)) {
- return NULL;
+ return nullptr;
}
}
@@ -1166,10 +1166,10 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
//find list [ or find dictionary {
_set_error("Error parsing expression, misplaced: " + String(tokenizer->get_token_name(tokenizer->get_token())));
- return NULL; //nothing
+ return nullptr; //nothing
}
- ERR_FAIL_COND_V_MSG(!expr, NULL, "GDScriptParser bug, couldn't figure out what expression is.");
+ ERR_FAIL_COND_V_MSG(!expr, nullptr, "GDScriptParser bug, couldn't figure out what expression is.");
/******************/
/* Parse Indexing */
@@ -1186,7 +1186,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (tokenizer->get_token(1) != GDScriptTokenizer::TK_CURSOR && !tokenizer->is_token_literal(1)) {
// We check with is_token_literal, as this allows us to use match/sync/etc. as a name
_set_error("Expected identifier as member");
- return NULL;
+ return nullptr;
} else if (tokenizer->get_token(2) == GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
//call!!
OperatorNode *op = alloc_node<OperatorNode>();
@@ -1212,7 +1212,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
completion_node = op;
}
if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant))
- return NULL;
+ return nullptr;
expr = op;
} else {
@@ -1251,12 +1251,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
Node *subexpr = _parse_expression(op, p_static, p_allow_assign, p_parsing_constant);
if (!subexpr) {
- return NULL;
+ return nullptr;
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_BRACKET_CLOSE) {
_set_error("Expected ']'");
- return NULL;
+ return nullptr;
}
op->arguments.push_back(expr);
@@ -1276,12 +1276,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_AS) {
if (has_casting) {
_set_error("Unexpected 'as'.");
- return NULL;
+ return nullptr;
}
CastNode *cn = alloc_node<CastNode>();
if (!_parse_type(cn->cast_type)) {
_set_error("Expected type after 'as'.");
- return NULL;
+ return nullptr;
}
has_casting = true;
cn->source_node = expr;
@@ -1313,7 +1313,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
#define _VALIDATE_ASSIGN \
if (!p_allow_assign || has_casting) { \
_set_error("Unexpected assign."); \
- return NULL; \
+ return nullptr; \
} \
p_allow_assign = false;
@@ -1479,7 +1479,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
default: {
_set_error("GDScriptParser bug, invalid operator in expression: " + itos(expression[i].op));
- return NULL;
+ return nullptr;
}
}
@@ -1488,7 +1488,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
// <= is used for right to left
if (error) {
_set_error("Unexpected operator");
- return NULL;
+ return nullptr;
}
next_op = i;
min_priority = priority;
@@ -1500,7 +1500,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (next_op == -1) {
_set_error("Yet another parser bug....");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
// OK! create operator..
@@ -1513,7 +1513,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expr_pos == expression.size()) {
//can happen..
_set_error("Unexpected end of expression...");
- return NULL;
+ return nullptr;
}
}
@@ -1532,16 +1532,16 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
} else if (is_ternary) {
if (next_op < 1 || next_op >= (expression.size() - 1)) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
if (next_op >= (expression.size() - 2) || expression[next_op + 2].op != OperatorNode::OP_TERNARY_ELSE) {
_set_error("Expected else after ternary if.");
- return NULL;
+ return nullptr;
}
if (next_op >= (expression.size() - 3)) {
_set_error("Expected value after ternary else.");
- return NULL;
+ return nullptr;
}
OperatorNode *op = alloc_node<OperatorNode>();
@@ -1551,7 +1551,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expression[next_op - 1].is_op) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
if (expression[next_op + 1].is_op) {
@@ -1561,7 +1561,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
// due to how precedence works, unaries will always disappear first
_set_error("Unexpected two consecutive operators after ternary if.");
- return NULL;
+ return nullptr;
}
if (expression[next_op + 3].is_op) {
@@ -1571,7 +1571,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
// due to how precedence works, unaries will always disappear first
_set_error("Unexpected two consecutive operators after ternary else.");
- return NULL;
+ return nullptr;
}
op->arguments.push_back(expression[next_op + 1].node); //next expression goes as first
@@ -1588,7 +1588,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (next_op < 1 || next_op >= (expression.size() - 1)) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
OperatorNode *op = alloc_node<OperatorNode>();
@@ -1598,7 +1598,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (expression[next_op - 1].is_op) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
if (expression[next_op + 1].is_op) {
@@ -1608,7 +1608,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
// due to how precedence works, unaries will always disappear first
_set_error("Unexpected two consecutive operators.");
- return NULL;
+ return nullptr;
}
op->arguments.push_back(expression[next_op - 1].node); //expression goes as left
@@ -1725,7 +1725,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to
if ((op->arguments[0]->type == Node::TYPE_TYPE || (op->arguments[0]->type == Node::TYPE_BUILT_IN_FUNCTION && GDScriptFunctions::is_deterministic(static_cast<BuiltInFunctionNode *>(op->arguments[0])->function))) && last_not_constant == 0) {
//native type constructor or intrinsic function
- const Variant **vptr = NULL;
+ const Variant **vptr = nullptr;
Vector<Variant *> ptrs;
if (op->arguments.size() > 1) {
@@ -2015,10 +2015,10 @@ GDScriptParser::Node *GDScriptParser::_parse_and_reduce_expression(Node *p_paren
Node *expr = _parse_expression(p_parent, p_static, p_allow_assign, p_reduce_const);
if (!expr || error_set)
- return NULL;
+ return nullptr;
expr = _reduce_expression(expr, p_reduce_const);
if (!expr || error_set)
- return NULL;
+ return nullptr;
return expr;
}
@@ -2046,10 +2046,10 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
GDScriptTokenizer::Token token = tokenizer->get_token();
if (error_set)
- return NULL;
+ return nullptr;
if (token == GDScriptTokenizer::TK_EOF) {
- return NULL;
+ return nullptr;
}
switch (token) {
@@ -2078,13 +2078,13 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
break;
} else {
_set_error("'..' pattern only allowed at the end of an array pattern");
- return NULL;
+ return nullptr;
}
}
PatternNode *sub_pattern = _parse_pattern(p_static);
if (!sub_pattern) {
- return NULL;
+ return nullptr;
}
pattern->array.push_back(sub_pattern);
@@ -2097,7 +2097,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
break;
} else {
_set_error("Not a valid pattern");
- return NULL;
+ return nullptr;
}
}
} break;
@@ -2106,7 +2106,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
tokenizer->advance();
if (!tokenizer->is_token_literal()) {
_set_error("Expected identifier for binding variable name.");
- return NULL;
+ return nullptr;
}
pattern->pt_type = GDScriptParser::PatternNode::PT_BIND;
pattern->bind = tokenizer->get_token_literal();
@@ -2115,7 +2115,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
while (bl) {
if (bl->variables.has(pattern->bind)) {
_set_error("Binding name of '" + pattern->bind.operator String() + "' is already declared in this scope.");
- return NULL;
+ return nullptr;
}
bl = bl->parent_block;
}
@@ -2150,19 +2150,19 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
break;
} else {
_set_error("'..' pattern only allowed at the end of a dictionary pattern");
- return NULL;
+ return nullptr;
}
}
Node *key = _parse_and_reduce_expression(pattern, p_static);
if (!key) {
_set_error("Not a valid key in pattern");
- return NULL;
+ return nullptr;
}
if (key->type != GDScriptParser::Node::TYPE_CONSTANT) {
_set_error("Not a constant expression as key");
- return NULL;
+ return nullptr;
}
if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
@@ -2171,12 +2171,12 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
PatternNode *value = _parse_pattern(p_static);
if (!value) {
_set_error("Expected pattern in dictionary value");
- return NULL;
+ return nullptr;
}
pattern->dictionary.insert(static_cast<ConstantNode *>(key), value);
} else {
- pattern->dictionary.insert(static_cast<ConstantNode *>(key), NULL);
+ pattern->dictionary.insert(static_cast<ConstantNode *>(key), nullptr);
}
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -2187,7 +2187,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
break;
} else {
_set_error("Not a valid pattern");
- return NULL;
+ return nullptr;
}
}
} break;
@@ -2200,7 +2200,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
Node *value = _parse_and_reduce_expression(pattern, p_static);
if (!value) {
_set_error("Expect constant expression or variables in a pattern");
- return NULL;
+ return nullptr;
}
if (value->type == Node::TYPE_OPERATOR) {
@@ -2212,19 +2212,19 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
if (op_node->op != OperatorNode::OP_INDEX_NAMED) {
_set_error("Invalid operator in pattern. Only index (`A.B`) is allowed");
- return NULL;
+ return nullptr;
}
current_value = op_node->arguments[0];
}
if (current_value->type != Node::TYPE_IDENTIFIER) {
_set_error("Only constant expression or variables allowed in a pattern");
- return NULL;
+ return nullptr;
}
} else if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) {
_set_error("Only constant expressions or variables allowed in a pattern");
- return NULL;
+ return nullptr;
}
pattern->pt_type = PatternNode::PT_CONSTANT;
@@ -2332,7 +2332,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m
return;
}
- OperatorNode *type_comp = NULL;
+ OperatorNode *type_comp = nullptr;
// static type check if possible
if (pattern_type.has_type && to_match_type.has_type) {
@@ -2402,7 +2402,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m
// typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() == length
{
- OperatorNode *type_comp = NULL;
+ OperatorNode *type_comp = nullptr;
// static type check if possible
if (to_match_type.has_type) {
// must be an array
@@ -2461,7 +2461,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m
for (int i = 0; i < p_pattern->array.size(); i++) {
PatternNode *pattern = p_pattern->array[i];
- Node *condition = NULL;
+ Node *condition = nullptr;
ConstantNode *index = alloc_node<ConstantNode>();
index->value = Variant(i);
@@ -2495,7 +2495,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m
// typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() == length
{
- OperatorNode *type_comp = NULL;
+ OperatorNode *type_comp = nullptr;
// static type check if possible
if (to_match_type.has_type) {
// must be an dictionary
@@ -2553,7 +2553,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m
for (Map<ConstantNode *, PatternNode *>::Element *e = p_pattern->dictionary.front(); e; e = e->next()) {
- Node *condition = NULL;
+ Node *condition = nullptr;
// check for has, then for pattern
@@ -2629,7 +2629,7 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) {
PatternBranchNode *branch = p_match_statement->branches[i];
MatchNode::CompiledPatternBranch compiled_branch;
- compiled_branch.compiled_pattern = NULL;
+ compiled_branch.compiled_pattern = nullptr;
Map<StringName, Node *> binding;
@@ -2638,7 +2638,7 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) {
_mark_line_as_safe(pattern->line);
Map<StringName, Node *> bindings;
- Node *resulting_node = NULL;
+ Node *resulting_node = nullptr;
_generate_pattern(pattern, id, resulting_node, bindings);
if (!resulting_node) {
@@ -2838,7 +2838,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
lv->line = var_line;
p_block->statements.push_back(lv);
- Node *assigned = NULL;
+ Node *assigned = nullptr;
if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) {
@@ -3113,7 +3113,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
}
} else {
constant = false;
- break;
}
}
@@ -3935,7 +3934,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_function = function;
Node *arg = _parse_and_reduce_expression(p_class, _static);
- current_function = NULL;
+ current_function = nullptr;
cparent->arguments.push_back(arg);
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -3990,7 +3989,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
function->body = block;
current_block = block;
_parse_block(block, _static);
- current_block = NULL;
+ current_block = nullptr;
//arguments
} break;
@@ -4736,7 +4735,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
member.identifier = tokenizer->get_token_literal();
- member.expression = NULL;
+ member.expression = nullptr;
member._export.name = member.identifier;
member.line = tokenizer->get_token_line();
member.usages = 0;
@@ -4816,7 +4815,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
#ifdef TOOLS_ENABLED
Callable::CallError ce;
- member.default_value = Variant::construct(member._export.type, NULL, 0, ce);
+ member.default_value = Variant::construct(member._export.type, nullptr, 0, ce);
#endif
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
@@ -4869,7 +4868,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (cn->value.get_type() == Variant::OBJECT) {
Object *obj = cn->value;
Resource *res = Object::cast_to<Resource>(obj);
- if (res == NULL) {
+ if (res == nullptr) {
_set_error("The exported constant isn't a type or resource.");
return;
}
@@ -5257,7 +5256,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive
Ref<GDScript> script;
StringName native;
- ClassNode *base_class = NULL;
+ ClassNode *base_class = nullptr;
if (path != "") {
//path (and optionally subclasses)
@@ -5319,7 +5318,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive
_set_error("The class \"" + base + "\" couldn't be fully loaded (script error or cyclic dependency).", p_class->line);
return;
}
- p = NULL;
+ p = nullptr;
} else {
List<PropertyInfo> props;
ProjectSettings::get_singleton()->get_property_list(&props);
@@ -5342,7 +5341,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive
_set_error("Class '" + base + "' could not be fully loaded (script error or cyclic inheritance).", p_class->line);
return;
}
- p = NULL;
+ p = nullptr;
}
}
}
@@ -5662,7 +5661,7 @@ GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source,
StringName id = full_name[name_part];
DataType base_type = result;
- ClassNode *p = NULL;
+ ClassNode *p = nullptr;
if (name_part == 0) {
if (ScriptServer::is_global_class(id)) {
String script_path = ScriptServer::get_global_class_path(id);
@@ -5944,7 +5943,7 @@ GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Oper
a = a_ref;
} else {
Callable::CallError err;
- a = Variant::construct(a_type, NULL, 0, err);
+ a = Variant::construct(a_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
r_valid = false;
return DataType();
@@ -5957,7 +5956,7 @@ GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Oper
b = b_ref;
} else {
Callable::CallError err;
- b = Variant::construct(b_type, NULL, 0, err);
+ b = Variant::construct(b_type, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
r_valid = false;
return DataType();
@@ -6118,7 +6117,7 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data
StringName expr_native;
Ref<Script> expr_script;
- ClassNode *expr_class = NULL;
+ ClassNode *expr_class = nullptr;
switch (p_expression.kind) {
case DataType::NATIVE: {
@@ -6229,7 +6228,7 @@ GDScriptParser::Node *GDScriptParser::_get_default_value_for_type(const DataType
} else {
ConstantNode *c = alloc_node<ConstantNode>();
Callable::CallError err;
- c->value = Variant::construct(p_type.builtin_type, NULL, 0, err);
+ c->value = Variant::construct(p_type.builtin_type, nullptr, 0, err);
result = c;
}
} else {
@@ -6308,7 +6307,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
int idx = current_function->arguments.find(id->name);
node_type = current_function->argument_types[idx];
} else {
- node_type = _reduce_identifier_type(NULL, id->name, id->line, false);
+ node_type = _reduce_identifier_type(nullptr, id->name, id->line, false);
}
} break;
case Node::TYPE_CAST: {
@@ -6542,7 +6541,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
} break;
default: {
Callable::CallError err;
- Variant temp = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant temp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
bool valid = false;
Variant res = temp.get(member_id->name.operator String(), &valid);
@@ -6671,7 +6670,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
}
default: {
Callable::CallError err;
- Variant temp = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant temp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
bool valid = false;
Variant res = temp.get(cn->value, &valid);
@@ -6778,8 +6777,8 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String
r_default_arg_count = 0;
DataType original_type = p_base_type;
- ClassNode *base = NULL;
- FunctionNode *callee = NULL;
+ ClassNode *base = nullptr;
+ FunctionNode *callee = nullptr;
if (p_base_type.kind == DataType::CLASS) {
base = p_base_type.class_type;
@@ -7112,7 +7111,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
if (base_type.kind == DataType::BUILTIN) {
Callable::CallError err;
- Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err);
+ Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err);
if (check_types) {
if (!tmp.has_method(callee_name)) {
@@ -7276,7 +7275,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
DataType base_type = p_base_type;
// Check classes in current file
- ClassNode *base = NULL;
+ ClassNode *base = nullptr;
if (base_type.kind == DataType::CLASS) {
base = base_type.class_type;
}
@@ -7365,6 +7364,8 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
}
}
+#define IS_USAGE_MEMBER(m_usage) (!(m_usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)))
+
// Check other script types
while (scr.is_valid()) {
Map<StringName, Variant> constants;
@@ -7377,7 +7378,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
List<PropertyInfo> properties;
scr->get_script_property_list(&properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().name == p_member) {
+ if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) {
r_member_type = _type_from_property(E->get());
return true;
}
@@ -7419,7 +7420,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
List<PropertyInfo> properties;
ClassDB::get_property_list(native, &properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().name == p_member) {
+ if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) {
// Check if a getter exists
StringName getter_name = ClassDB::get_property_getter(native, p_member);
if (getter_name != StringName()) {
@@ -7459,7 +7460,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
List<PropertyInfo> properties;
ClassDB::get_property_list(native, &properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().name == p_member) {
+ if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) {
// Check if a getter exists
StringName getter_name = ClassDB::get_property_getter(native, p_member);
if (getter_name != StringName()) {
@@ -7481,6 +7482,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
}
}
}
+#undef IS_USAGE_MEMBER
return false;
}
@@ -7994,8 +7996,8 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
current_block = current_function->body;
_mark_line_as_safe(current_function->line);
_check_block_types(current_block);
- current_block = NULL;
- current_function = NULL;
+ current_block = nullptr;
+ current_function = nullptr;
if (error_set) return;
}
@@ -8004,8 +8006,8 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
current_block = current_function->body;
_mark_line_as_safe(current_function->line);
_check_block_types(current_block);
- current_block = NULL;
- current_function = NULL;
+ current_block = nullptr;
+ current_function = nullptr;
if (error_set) return;
}
@@ -8054,7 +8056,7 @@ static String _find_function_name(const GDScriptParser::OperatorNode *p_call) {
void GDScriptParser::_check_block_types(BlockNode *p_block) {
- Node *last_var_assign = NULL;
+ Node *last_var_assign = nullptr;
// Check each statement
for (List<Node *>::Element *E = p_block->statements.front(); E; E = E->next()) {
@@ -8445,7 +8447,7 @@ void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &
warn.symbols = p_symbols;
warn.line = p_line == -1 ? tokenizer->get_token_line() : p_line;
- List<GDScriptWarning>::Element *before = NULL;
+ List<GDScriptWarning>::Element *before = nullptr;
for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
if (E->get().line > warn.line) {
break;
@@ -8512,8 +8514,8 @@ Error GDScriptParser::_parse(const String &p_base_path) {
}
current_class = main_class;
- current_function = NULL;
- current_block = NULL;
+ current_function = nullptr;
+ current_block = nullptr;
if (for_completion) check_types = false;
@@ -8534,7 +8536,7 @@ Error GDScriptParser::_parse(const String &p_base_path) {
#ifdef DEBUG_ENABLED
// Resolve warning ignores
- Vector<Pair<int, String> > warning_skips = tokenizer->get_warning_skips();
+ Vector<Pair<int, String>> warning_skips = tokenizer->get_warning_skips();
bool warning_is_error = GLOBAL_GET("debug/gdscript/warnings/treat_warnings_as_errors").booleanize();
for (List<GDScriptWarning>::Element *E = warnings.front(); E;) {
GDScriptWarning &w = E->get();
@@ -8576,7 +8578,7 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St
tokenizer = tb;
Error ret = _parse(p_base_path);
memdelete(tb);
- tokenizer = NULL;
+ tokenizer = nullptr;
return ret;
}
@@ -8597,7 +8599,7 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo
tokenizer = tt;
Error ret = _parse(p_base_path);
memdelete(tt);
- tokenizer = NULL;
+ tokenizer = nullptr;
return ret;
}
@@ -8620,21 +8622,21 @@ void GDScriptParser::clear() {
memdelete(l);
}
- head = NULL;
- list = NULL;
+ head = nullptr;
+ list = nullptr;
completion_type = COMPLETION_NONE;
- completion_node = NULL;
- completion_class = NULL;
- completion_function = NULL;
- completion_block = NULL;
- current_block = NULL;
- current_class = NULL;
+ completion_node = nullptr;
+ completion_class = nullptr;
+ completion_function = nullptr;
+ completion_block = nullptr;
+ current_block = nullptr;
+ current_class = nullptr;
completion_found = false;
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
- current_function = NULL;
+ current_function = nullptr;
validating = false;
for_completion = false;
@@ -8651,7 +8653,7 @@ void GDScriptParser::clear() {
dependencies.clear();
error = "";
#ifdef DEBUG_ENABLED
- safe_lines = NULL;
+ safe_lines = nullptr;
#endif // DEBUG_ENABLED
}
@@ -8707,9 +8709,9 @@ int GDScriptParser::get_completion_identifier_is_function() {
GDScriptParser::GDScriptParser() {
- head = NULL;
- list = NULL;
- tokenizer = NULL;
+ head = nullptr;
+ list = nullptr;
+ tokenizer = nullptr;
pending_newline = -1;
clear();
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index c74d7dd856..eca5f83f7a 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -102,7 +102,7 @@ public:
infer_type(false),
may_yield(false),
builtin_type(Variant::NIL),
- class_type(NULL) {}
+ class_type(nullptr) {}
};
struct Node {
@@ -201,7 +201,7 @@ public:
extends_used = false;
classname_used = false;
end_line = -1;
- owner = NULL;
+ owner = nullptr;
}
};
@@ -248,11 +248,11 @@ public:
List<BlockNode *> sub_blocks;
int end_line;
BlockNode() {
- if_condition = NULL;
+ if_condition = nullptr;
type = TYPE_BLOCK;
end_line = -1;
- parent_block = NULL;
- parent_class = NULL;
+ parent_block = nullptr;
+ parent_class = nullptr;
has_return = false;
}
};
@@ -276,7 +276,7 @@ public:
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
IdentifierNode() {
type = TYPE_IDENTIFIER;
- declared_block = NULL;
+ declared_block = nullptr;
}
};
@@ -292,8 +292,8 @@ public:
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
LocalVarNode() {
type = TYPE_LOCAL_VAR;
- assign = NULL;
- assign_op = NULL;
+ assign = nullptr;
+ assign_op = nullptr;
assignments = 0;
usages = 0;
}
@@ -465,8 +465,8 @@ public:
ControlFlowNode() {
type = TYPE_CONTROL_FLOW;
cf_type = CF_IF;
- body = NULL;
- body_else = NULL;
+ body = nullptr;
+ body_else = nullptr;
}
};
@@ -608,7 +608,7 @@ private:
bool _recover_from_completion();
bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false, bool p_parsing_constant = false);
- bool _enter_indent_block(BlockNode *p_block = NULL);
+ bool _enter_indent_block(BlockNode *p_block = nullptr);
bool _parse_newline();
Node *_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign = false, bool p_parsing_constant = false);
Node *_reduce_expression(Node *p_node, bool p_to_const = false);
@@ -665,7 +665,7 @@ public:
#ifdef DEBUG_ENABLED
const List<GDScriptWarning> &get_warnings() const { return warnings; }
#endif // DEBUG_ENABLED
- Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL, bool p_dependencies_only = false);
+ Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = nullptr, bool p_dependencies_only = false);
Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = "");
bool is_tool_script() const;
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 9064998d32..d42ca52731 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -178,7 +178,7 @@ static const _bit _type_list[] = {
{ Variant::PACKED_VECTOR2_ARRAY, "PackedVector2Array" },
{ Variant::PACKED_VECTOR3_ARRAY, "PackedVector3Array" },
{ Variant::PACKED_COLOR_ARRAY, "PackedColorArray" },
- { Variant::VARIANT_MAX, NULL },
+ { Variant::VARIANT_MAX, nullptr },
};
struct _kws {
@@ -236,7 +236,7 @@ static const _kws _keyword_list[] = {
{ GDScriptTokenizer::TK_WILDCARD, "_" },
{ GDScriptTokenizer::TK_CONST_INF, "INF" },
{ GDScriptTokenizer::TK_CONST_NAN, "NAN" },
- { GDScriptTokenizer::TK_ERROR, NULL }
+ { GDScriptTokenizer::TK_ERROR, nullptr }
};
const char *GDScriptTokenizer::get_token_name(Token p_token) {
@@ -1075,7 +1075,7 @@ void GDScriptTokenizerText::set_code(const String &p_code) {
if (len) {
_code = &code[0];
} else {
- _code = NULL;
+ _code = nullptr;
}
code_pos = 0;
line = 1; //it is stand-ar-ized that lines begin in 1 in code..
@@ -1358,7 +1358,7 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code)
}
Map<int, Variant> rev_constant_map;
- const Variant *K = NULL;
+ const Variant *K = nullptr;
while ((K = constant_map.next(K))) {
rev_constant_map[constant_map[*K]] = *K;
}
@@ -1407,7 +1407,7 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code)
int len;
// Objects cannot be constant, never encode objects
- Error err = encode_variant(E->get(), NULL, len, false);
+ Error err = encode_variant(E->get(), nullptr, len, false);
ERR_FAIL_COND_V_MSG(err != OK, Vector<uint8_t>(), "Error when trying to encode Variant.");
int pos = buf.size();
buf.resize(pos + len);
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 3694825d80..180ec3c77e 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -32,6 +32,7 @@
#define GDSCRIPT_TOKENIZER_H
#include "core/pair.h"
+#include "core/set.h"
#include "core/string_name.h"
#include "core/ustring.h"
#include "core/variant.h"
@@ -170,7 +171,7 @@ public:
virtual String get_token_error(int p_offset = 0) const = 0;
virtual void advance(int p_amount = 1) = 0;
#ifdef DEBUG_ENABLED
- virtual const Vector<Pair<int, String> > &get_warning_skips() const = 0;
+ virtual const Vector<Pair<int, String>> &get_warning_skips() const = 0;
virtual const Set<String> &get_warning_global_skips() const = 0;
virtual bool is_ignoring_warnings() const = 0;
#endif // DEBUG_ENABLED
@@ -223,7 +224,7 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
bool error_flag;
#ifdef DEBUG_ENABLED
- Vector<Pair<int, String> > warning_skips;
+ Vector<Pair<int, String>> warning_skips;
Set<String> warning_global_skips;
bool ignore_warnings;
#endif // DEBUG_ENABLED
@@ -244,7 +245,7 @@ public:
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
#ifdef DEBUG_ENABLED
- virtual const Vector<Pair<int, String> > &get_warning_skips() const { return warning_skips; }
+ virtual const Vector<Pair<int, String>> &get_warning_skips() const { return warning_skips; }
virtual const Set<String> &get_warning_global_skips() const { return warning_global_skips; }
virtual bool is_ignoring_warnings() const { return ignore_warnings; }
#endif // DEBUG_ENABLED
@@ -283,8 +284,8 @@ public:
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
#ifdef DEBUG_ENABLED
- virtual const Vector<Pair<int, String> > &get_warning_skips() const {
- static Vector<Pair<int, String> > v;
+ virtual const Vector<Pair<int, String>> &get_warning_skips() const {
+ static Vector<Pair<int, String>> v;
return v;
}
virtual const Set<String> &get_warning_global_skips() const {
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 0f6f13944b..b2c6b0e1ab 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -327,7 +327,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size());
if (default_value_idx >= 0) {
const GDScriptParser::ConstantNode *const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(p_func->default_values[default_value_idx]);
- if (const_node == NULL) {
+ if (const_node == nullptr) {
const GDScriptParser::OperatorNode *operator_node = dynamic_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[default_value_idx]);
if (operator_node) {
const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(operator_node->next);
@@ -507,7 +507,7 @@ String ExtendGDScriptParser::get_uri() const {
}
const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const {
- const lsp::DocumentSymbol *ret = NULL;
+ const lsp::DocumentSymbol *ret = nullptr;
if (p_line < p_parent.range.start.line) {
return ret;
} else if (p_parent.range.start.line == p_line) {
@@ -591,7 +591,7 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String
}
}
- return NULL;
+ return nullptr;
}
const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const {
@@ -602,7 +602,7 @@ const Array &ExtendGDScriptParser::get_member_completions() {
if (member_completions.empty()) {
- const String *name = members.next(NULL);
+ const String *name = members.next(nullptr);
while (name) {
const lsp::DocumentSymbol *symbol = members.get(*name);
@@ -613,11 +613,11 @@ const Array &ExtendGDScriptParser::get_member_completions() {
name = members.next(name);
}
- const String *_class = inner_classes.next(NULL);
+ const String *_class = inner_classes.next(nullptr);
while (_class) {
const ClassMembers *inner_class = inner_classes.getptr(*_class);
- const String *member_name = inner_class->next(NULL);
+ const String *member_name = inner_class->next(nullptr);
while (member_name) {
const lsp::DocumentSymbol *symbol = inner_class->get(*member_name);
lsp::CompletionItem item = symbol->make_completion_item();
@@ -648,7 +648,7 @@ Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::Functio
int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size());
if (default_value_idx >= 0) {
const GDScriptParser::ConstantNode *const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(p_func->default_values[default_value_idx]);
- if (const_node == NULL) {
+ if (const_node == nullptr) {
const GDScriptParser::OperatorNode *operator_node = dynamic_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[default_value_idx]);
if (operator_node) {
const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(operator_node->next);
@@ -778,7 +778,7 @@ Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) {
path = p_path;
lines = p_code.split("\n");
- Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, NULL, false);
+ Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, nullptr, false);
update_diagnostics();
update_symbols();
update_document_links(p_code);
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 2243a7b81d..69662e96f7 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -35,7 +35,7 @@
#include "editor/editor_log.h"
#include "editor/editor_node.h"
-GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = NULL;
+GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = nullptr;
Error GDScriptLanguageProtocol::LSPeer::handle_data() {
int read = 0;
@@ -191,7 +191,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
Dictionary request = make_notification("gdscrip_client/changeWorkspace", params);
Ref<LSPeer> peer = clients.get(latest_client_id);
- if (peer != NULL) {
+ if (peer != nullptr) {
String msg = JSON::print(request);
msg = format_output(msg);
(*peer)->res_queue.push_back(msg.utf8());
@@ -230,26 +230,26 @@ void GDScriptLanguageProtocol::poll() {
if (server->is_connection_available()) {
on_client_connected();
}
- const int *id = NULL;
+ const int *id = nullptr;
while ((id = clients.next(id))) {
Ref<LSPeer> peer = clients.get(*id);
StreamPeerTCP::Status status = peer->connection->get_status();
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
on_client_disconnected(*id);
- id = NULL;
+ id = nullptr;
} else {
if (peer->connection->get_available_bytes() > 0) {
latest_client_id = *id;
Error err = peer->handle_data();
if (err != OK && err != ERR_BUSY) {
on_client_disconnected(*id);
- id = NULL;
+ id = nullptr;
}
}
Error err = peer->send_data();
if (err != OK && err != ERR_BUSY) {
on_client_disconnected(*id);
- id = NULL;
+ id = nullptr;
}
}
}
@@ -260,7 +260,7 @@ Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) {
}
void GDScriptLanguageProtocol::stop() {
- const int *id = NULL;
+ const int *id = nullptr;
while ((id = clients.next(id))) {
Ref<LSPeer> peer = clients.get(*id);
peer->connection->disconnect_from_host();
@@ -274,7 +274,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia
p_client_id = latest_client_id;
}
Ref<LSPeer> peer = clients.get(p_client_id);
- ERR_FAIL_COND(peer == NULL);
+ ERR_FAIL_COND(peer == nullptr);
Dictionary message = make_notification(p_method, p_params);
String msg = JSON::print(message);
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index 3f0ae36af2..d929fd255d 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -68,7 +68,7 @@ private:
static GDScriptLanguageProtocol *singleton;
- HashMap<int, Ref<LSPeer> > clients;
+ HashMap<int, Ref<LSPeer>> clients;
Ref<TCP_Server> server;
int latest_client_id;
int next_client_id;
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 7170c63058..e1d86ecdd4 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -35,7 +35,7 @@
#include "editor/editor_node.h"
GDScriptLanguageServer::GDScriptLanguageServer() {
- thread = NULL;
+ thread = nullptr;
thread_running = false;
started = false;
@@ -87,7 +87,7 @@ void GDScriptLanguageServer::start() {
if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
- ERR_FAIL_COND(thread != NULL);
+ ERR_FAIL_COND(thread != nullptr);
thread_running = true;
thread = Thread::create(GDScriptLanguageServer::thread_main, this);
}
@@ -98,11 +98,11 @@ void GDScriptLanguageServer::start() {
void GDScriptLanguageServer::stop() {
if (use_thread) {
- ERR_FAIL_COND(NULL == thread);
+ ERR_FAIL_COND(nullptr == thread);
thread_running = false;
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
protocol.stop();
started = false;
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index d5723fd20f..f065b33570 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -35,6 +35,7 @@
#include "editor/plugins/script_text_editor.h"
#include "gdscript_extend_parser.h"
#include "gdscript_language_protocol.h"
+#include "servers/display_server.h"
void GDScriptTextDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
@@ -89,12 +90,12 @@ void GDScriptTextDocument::initialize() {
const HashMap<StringName, ClassMembers> &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members;
- const StringName *class_ptr = native_members.next(NULL);
+ const StringName *class_ptr = native_members.next(nullptr);
while (class_ptr) {
const ClassMembers &members = native_members.get(*class_ptr);
- const String *name = members.next(NULL);
+ const String *name = members.next(nullptr);
while (name) {
const lsp::DocumentSymbol *symbol = members.get(*name);
@@ -226,7 +227,7 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
lsp::CompletionParams params;
Variant data = p_params["data"];
- const lsp::DocumentSymbol *symbol = NULL;
+ const lsp::DocumentSymbol *symbol = nullptr;
if (data.get_type() == Variant::DICTIONARY) {
@@ -419,7 +420,8 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
ScriptEditor::get_singleton()->call_deferred("_help_class_goto", p_symbol_id);
- OS::get_singleton()->move_window_to_foreground();
+
+ DisplayServer::get_singleton()->window_move_to_foreground();
}
Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &p_location, List<const lsp::DocumentSymbol *> &r_list) {
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 205257b8f2..32fc8f36f0 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -93,7 +93,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_
class_name = ClassDB::get_parent_class(class_name);
}
- return NULL;
+ return nullptr;
}
const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_path) const {
@@ -101,7 +101,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_
if (S) {
return &(S->get()->get_symbols());
}
- return NULL;
+ return nullptr;
}
void GDScriptWorkspace::reload_all_workspace_scripts() {
@@ -152,7 +152,7 @@ ExtendGDScriptParser *GDScriptWorkspace::get_parse_successed_script(const String
if (S) {
return S->get();
}
- return NULL;
+ return nullptr;
}
ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path) {
@@ -164,7 +164,7 @@ ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path)
if (S) {
return S->get();
}
- return NULL;
+ return nullptr;
}
Array GDScriptWorkspace::symbol(const Dictionary &p_params) {
@@ -402,7 +402,7 @@ void GDScriptWorkspace::_get_owners(EditorFileSystemDirectory *efsd, String p_pa
}
Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {
- Node *owner_scene_node = NULL;
+ Node *owner_scene_node = nullptr;
List<String> owners;
_get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners);
@@ -438,7 +438,7 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S
const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name, bool p_func_requred) {
- const lsp::DocumentSymbol *symbol = NULL;
+ const lsp::DocumentSymbol *symbol = nullptr;
String path = get_file_path(p_doc_pos.textDocument.uri);
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
@@ -466,7 +466,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
} else {
ScriptLanguage::LookupResult ret;
- if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_requred), symbol_identifier, path, NULL, ret)) {
+ if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_requred), symbol_identifier, path, nullptr, ret)) {
if (ret.type == ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION) {
@@ -506,7 +506,7 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
Vector2i offset;
symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset);
- const StringName *class_ptr = native_members.next(NULL);
+ const StringName *class_ptr = native_members.next(nullptr);
while (class_ptr) {
const ClassMembers &members = native_members.get(*class_ptr);
if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
@@ -523,7 +523,7 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
}
const HashMap<String, ClassMembers> &inner_classes = script->get_inner_classes();
- const String *_class = inner_classes.next(NULL);
+ const String *_class = inner_classes.next(nullptr);
while (_class) {
const ClassMembers *inner_class = inner_classes.getptr(*_class);
@@ -552,7 +552,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::N
}
}
- return NULL;
+ return nullptr;
}
void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) {
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index a2dcc48820..124fcbfed8 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -33,7 +33,7 @@
#include "core/class_db.h"
#include "core/list.h"
-#include "editor/doc/doc_data.h"
+#include "editor/doc_data.h"
namespace lsp {
@@ -156,7 +156,7 @@ struct LocationLink {
* Used as the underlined span for mouse interaction. Defaults to the word range at
* the mouse position.
*/
- Range *originSelectionRange = NULL;
+ Range *originSelectionRange = nullptr;
/**
* The target resource identifier of this link.
@@ -1686,8 +1686,8 @@ struct InitializeResult {
struct GodotNativeClassInfo {
String name;
- const DocData::ClassDoc *class_doc = NULL;
- const ClassDB::ClassInfo *class_info = NULL;
+ const DocData::ClassDoc *class_doc = nullptr;
+ const ClassDB::ClassInfo *class_info = nullptr;
Dictionary to_json() {
Dictionary dict;
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index b5eb09d6ba..62b9d94d6c 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -37,7 +37,7 @@
#include "gdscript.h"
#include "gdscript_tokenizer.h"
-GDScriptLanguage *script_language_gd = NULL;
+GDScriptLanguage *script_language_gd = nullptr;
Ref<ResourceFormatLoaderGDScript> resource_loader_gd;
Ref<ResourceFormatSaverGDScript> resource_saver_gd;
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index 55920e8b97..18e57c1211 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GDSCRIPT_REGISTER_TYPES_H
+#define GDSCRIPT_REGISTER_TYPES_H
+
void register_gdscript_types();
void unregister_gdscript_types();
+
+#endif // GDSCRIPT_REGISTER_TYPES_H
diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub
index ae102238f2..c1d23a138b 100644
--- a/modules/glslang/SCsub
+++ b/modules/glslang/SCsub
@@ -1,12 +1,12 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_glslang = env_modules.Clone()
# Thirdparty source files
-if env['builtin_glslang']:
+if env["builtin_glslang"]:
thirdparty_dir = "#thirdparty/glslang/"
thirdparty_sources = [
"glslang/MachineIndependent/RemoveTree.cpp",
@@ -48,10 +48,10 @@ if env['builtin_glslang']:
"SPIRV/doc.cpp",
"SPIRV/SPVRemapper.cpp",
"SPIRV/SpvPostProcess.cpp",
- "SPIRV/Logger.cpp"
+ "SPIRV/Logger.cpp",
]
- if (env["platform"]=="windows"):
+ if env["platform"] == "windows":
thirdparty_sources.append("glslang/OSDependent/Windows/ossource.cpp")
else:
thirdparty_sources.append("glslang/OSDependent/Unix/ossource.cpp")
@@ -60,7 +60,7 @@ if env['builtin_glslang']:
# Treat glslang headers as system headers to avoid raising warnings. Not supported on MSVC.
if not env.msvc:
- env_glslang.Append(CPPFLAGS=['-isystem', Dir(thirdparty_dir).path])
+ env_glslang.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
else:
env_glslang.Prepend(CPPPATH=[thirdparty_dir])
diff --git a/modules/glslang/config.py b/modules/glslang/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/glslang/config.py
+++ b/modules/glslang/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index d2b4a18fc7..2540ba476c 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -30,7 +30,7 @@
#include "register_types.h"
-#include "servers/visual/rendering_device.h"
+#include "servers/rendering/rendering_device.h"
#include <SPIRV/GlslangToSpv.h>
#include <glslang/Include/Types.h>
diff --git a/modules/glslang/register_types.h b/modules/glslang/register_types.h
index 37a1ef67f2..2437e2b27a 100644
--- a/modules/glslang/register_types.h
+++ b/modules/glslang/register_types.h
@@ -28,7 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GLSLANG_REGISTER_TYPES_H
+#define GLSLANG_REGISTER_TYPES_H
+
#define MODULE_GLSLANG_HAS_PREREGISTER
+
void preregister_glslang_types();
void register_glslang_types();
void unregister_glslang_types();
+
+#endif // GLSLANG_REGISTER_TYPES_H
diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub
index 62b8a0ff93..970ce534f0 100644
--- a/modules/gridmap/SCsub
+++ b/modules/gridmap/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_gridmap = env_modules.Clone()
diff --git a/modules/gridmap/config.py b/modules/gridmap/config.py
index 5022116c9b..a6319fe1ea 100644
--- a/modules/gridmap/config.py
+++ b/modules/gridmap/config.py
@@ -1,13 +1,16 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"GridMap",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 37ebb3e5d5..a213069e19 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GridMap" inherits="Spatial" version="4.0">
+<class name="GridMap" inherits="Node3D" version="4.0">
<brief_description>
Node for 3D tile-based maps.
</brief_description>
diff --git a/modules/gridmap/doc_classes/README.md b/modules/gridmap/doc_classes/README.md
index b1ec9058c8..37ad93b6d3 100644
--- a/modules/gridmap/doc_classes/README.md
+++ b/modules/gridmap/doc_classes/README.md
@@ -1 +1 @@
-Doc classes will appear here when generating \ No newline at end of file
+Doc classes will appear here when generating
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 84075f76fd..df7c2f397f 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -32,12 +32,12 @@
#include "core/io/marshalls.h"
#include "core/message_queue.h"
-#include "scene/3d/light.h"
+#include "scene/3d/light_3d.h"
#include "scene/resources/mesh_library.h"
#include "scene/resources/surface_tool.h"
#include "scene/scene_string_names.h"
-#include "servers/navigation_server.h"
-#include "servers/visual_server.h"
+#include "servers/navigation_server_3d.h"
+#include "servers/rendering_server.h"
bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
@@ -76,12 +76,12 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) {
BakedMesh bm;
bm.mesh = meshes[i];
ERR_CONTINUE(!bm.mesh.is_valid());
- bm.instance = VS::get_singleton()->instance_create();
- VS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
- VS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
+ bm.instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
+ RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
if (is_inside_tree()) {
- VS::get_singleton()->instance_set_scenario(bm.instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
+ RS::get_singleton()->instance_set_scenario(bm.instance, get_world()->get_scenario());
+ RS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
}
baked_meshes.push_back(bm);
}
@@ -306,17 +306,17 @@ void GridMap::set_cell_item(int p_x, int p_y, int p_z, int p_item, int p_rot) {
//create octant because it does not exist
Octant *g = memnew(Octant);
g->dirty = true;
- g->static_body = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC);
- PhysicsServer::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id());
- PhysicsServer::get_singleton()->body_set_collision_layer(g->static_body, collision_layer);
- PhysicsServer::get_singleton()->body_set_collision_mask(g->static_body, collision_mask);
+ g->static_body = PhysicsServer3D::get_singleton()->body_create(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);
SceneTree *st = SceneTree::get_singleton();
if (st && st->is_debugging_collisions_hint()) {
- g->collision_debug = VisualServer::get_singleton()->mesh_create();
- g->collision_debug_instance = VisualServer::get_singleton()->instance_create();
- VisualServer::get_singleton()->instance_set_base(g->collision_debug_instance, g->collision_debug);
+ g->collision_debug = RenderingServer::get_singleton()->mesh_create();
+ g->collision_debug_instance = RenderingServer::get_singleton()->instance_create();
+ RenderingServer::get_singleton()->instance_set_base(g->collision_debug_instance, g->collision_debug);
}
octant_map[octantkey] = g;
@@ -392,14 +392,14 @@ void GridMap::_octant_transform(const OctantKey &p_key) {
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
- PhysicsServer::get_singleton()->body_set_state(g.static_body, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
+ PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
if (g.collision_debug_instance.is_valid()) {
- VS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
+ RS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
}
for (int i = 0; i < g.multimesh_instances.size(); i++) {
- VS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
+ RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
}
}
@@ -410,17 +410,17 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
return false;
//erase body shapes
- PhysicsServer::get_singleton()->body_clear_shapes(g.static_body);
+ PhysicsServer3D::get_singleton()->body_clear_shapes(g.static_body);
//erase body shapes debug
if (g.collision_debug.is_valid()) {
- VS::get_singleton()->mesh_clear(g.collision_debug);
+ RS::get_singleton()->mesh_clear(g.collision_debug);
}
//erase navigation
for (Map<IndexKey, Octant::NavMesh>::Element *E = g.navmesh_ids.front(); E; E = E->next()) {
- NavigationServer::get_singleton()->free(E->get().region);
+ NavigationServer3D::get_singleton()->free(E->get().region);
}
g.navmesh_ids.clear();
@@ -428,8 +428,8 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
for (int i = 0; i < g.multimesh_instances.size(); i++) {
- VS::get_singleton()->free(g.multimesh_instances[i].instance);
- VS::get_singleton()->free(g.multimesh_instances[i].multimesh);
+ RS::get_singleton()->free(g.multimesh_instances[i].instance);
+ RS::get_singleton()->free(g.multimesh_instances[i].multimesh);
}
g.multimesh_instances.clear();
@@ -447,7 +447,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
* and set said multimesh bounding box to one containing all cells which have this item
*/
- Map<int, List<Pair<Transform, IndexKey> > > multimesh_items;
+ Map<int, List<Pair<Transform, IndexKey>>> multimesh_items;
for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) {
@@ -468,7 +468,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
if (baked_meshes.size() == 0) {
if (mesh_library->get_item_mesh(c.item).is_valid()) {
if (!multimesh_items.has(c.item)) {
- multimesh_items[c.item] = List<Pair<Transform, IndexKey> >();
+ multimesh_items[c.item] = List<Pair<Transform, IndexKey>>();
}
Pair<Transform, IndexKey> p;
@@ -484,7 +484,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
// add the item's shape
if (!shapes[i].shape.is_valid())
continue;
- PhysicsServer::get_singleton()->body_add_shape(g.static_body, shapes[i].shape->get_rid(), xform * shapes[i].local_transform);
+ PhysicsServer3D::get_singleton()->body_add_shape(g.static_body, shapes[i].shape->get_rid(), xform * shapes[i].local_transform);
if (g.collision_debug.is_valid()) {
shapes.write[i].shape->add_vertices_to_array(col_debug, xform * shapes[i].local_transform);
}
@@ -497,10 +497,10 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
nm.xform = xform * mesh_library->get_item_navmesh_transform(c.item);
if (navigation) {
- RID region = NavigationServer::get_singleton()->region_create();
- NavigationServer::get_singleton()->region_set_navmesh(region, navmesh);
- NavigationServer::get_singleton()->region_set_transform(region, navigation->get_global_transform() * nm.xform);
- NavigationServer::get_singleton()->region_set_map(region, navigation->get_rid());
+ RID region = NavigationServer3D::get_singleton()->region_create();
+ 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());
nm.region = region;
}
g.navmesh_ids[E->get()] = nm;
@@ -510,16 +510,16 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
//update multimeshes, only if not baked
if (baked_meshes.size() == 0) {
- for (Map<int, List<Pair<Transform, IndexKey> > >::Element *E = multimesh_items.front(); E; E = E->next()) {
+ for (Map<int, List<Pair<Transform, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) {
Octant::MultimeshInstance mmi;
- RID mm = VS::get_singleton()->multimesh_create();
- VS::get_singleton()->multimesh_allocate(mm, E->get().size(), VS::MULTIMESH_TRANSFORM_3D);
- VS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid());
+ RID mm = RS::get_singleton()->multimesh_create();
+ RS::get_singleton()->multimesh_allocate(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;
- for (List<Pair<Transform, IndexKey> >::Element *F = E->get().front(); F; F = F->next()) {
- VS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first);
+ for (List<Pair<Transform, IndexKey>>::Element *F = E->get().front(); F; F = F->next()) {
+ RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first);
#ifdef TOOLS_ENABLED
Octant::MultimeshInstance::Item it;
@@ -532,12 +532,12 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
idx++;
}
- RID instance = VS::get_singleton()->instance_create();
- VS::get_singleton()->instance_set_base(instance, mm);
+ RID instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(instance, mm);
if (is_inside_tree()) {
- VS::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(instance, get_global_transform());
+ RS::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
+ RS::get_singleton()->instance_set_transform(instance, get_global_transform());
}
mmi.multimesh = mm;
@@ -550,13 +550,13 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
if (col_debug.size()) {
Array arr;
- arr.resize(VS::ARRAY_MAX);
- arr[VS::ARRAY_VERTEX] = col_debug;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = col_debug;
- VS::get_singleton()->mesh_add_surface_from_arrays(g.collision_debug, VS::PRIMITIVE_LINES, arr);
+ RS::get_singleton()->mesh_add_surface_from_arrays(g.collision_debug, RS::PRIMITIVE_LINES, arr);
SceneTree *st = SceneTree::get_singleton();
if (st) {
- VS::get_singleton()->mesh_surface_set_material(g.collision_debug, 0, st->get_debug_collision_material()->get_rid());
+ RS::get_singleton()->mesh_surface_set_material(g.collision_debug, 0, st->get_debug_collision_material()->get_rid());
}
}
@@ -567,8 +567,8 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
void GridMap::_reset_physic_bodies_collision_filters() {
for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- PhysicsServer::get_singleton()->body_set_collision_layer(E->get()->static_body, collision_layer);
- PhysicsServer::get_singleton()->body_set_collision_mask(E->get()->static_body, collision_mask);
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(E->get()->static_body, collision_layer);
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(E->get()->static_body, collision_mask);
}
}
@@ -576,17 +576,17 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
- PhysicsServer::get_singleton()->body_set_state(g.static_body, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
- PhysicsServer::get_singleton()->body_set_space(g.static_body, get_world()->get_space());
+ PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+ PhysicsServer3D::get_singleton()->body_set_space(g.static_body, get_world()->get_space());
if (g.collision_debug_instance.is_valid()) {
- VS::get_singleton()->instance_set_scenario(g.collision_debug_instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
+ RS::get_singleton()->instance_set_scenario(g.collision_debug_instance, get_world()->get_scenario());
+ RS::get_singleton()->instance_set_transform(g.collision_debug_instance, get_global_transform());
}
for (int i = 0; i < g.multimesh_instances.size(); i++) {
- VS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
+ RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, get_world()->get_scenario());
+ RS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
}
if (navigation && mesh_library.is_valid()) {
@@ -595,10 +595,10 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
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 = NavigationServer::get_singleton()->region_create();
- NavigationServer::get_singleton()->region_set_navmesh(region, nm);
- NavigationServer::get_singleton()->region_set_transform(region, navigation->get_global_transform() * F->get().xform);
- NavigationServer::get_singleton()->region_set_map(region, navigation->get_rid());
+ RID region = NavigationServer3D::get_singleton()->region_create();
+ 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());
F->get().region = region;
}
}
@@ -610,23 +610,23 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
ERR_FAIL_COND(!octant_map.has(p_key));
Octant &g = *octant_map[p_key];
- PhysicsServer::get_singleton()->body_set_state(g.static_body, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
- PhysicsServer::get_singleton()->body_set_space(g.static_body, RID());
+ PhysicsServer3D::get_singleton()->body_set_state(g.static_body, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+ PhysicsServer3D::get_singleton()->body_set_space(g.static_body, RID());
if (g.collision_debug_instance.is_valid()) {
- VS::get_singleton()->instance_set_scenario(g.collision_debug_instance, RID());
+ RS::get_singleton()->instance_set_scenario(g.collision_debug_instance, RID());
}
for (int i = 0; i < g.multimesh_instances.size(); i++) {
- VS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID());
+ 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()) {
- NavigationServer::get_singleton()->free(F->get().region);
+ NavigationServer3D::get_singleton()->free(F->get().region);
F->get().region = RID();
}
}
@@ -639,15 +639,15 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
Octant &g = *octant_map[p_key];
if (g.collision_debug.is_valid())
- VS::get_singleton()->free(g.collision_debug);
+ RS::get_singleton()->free(g.collision_debug);
if (g.collision_debug_instance.is_valid())
- VS::get_singleton()->free(g.collision_debug_instance);
+ RS::get_singleton()->free(g.collision_debug_instance);
- PhysicsServer::get_singleton()->free(g.static_body);
+ PhysicsServer3D::get_singleton()->free(g.static_body);
// Erase navigation
for (Map<IndexKey, Octant::NavMesh>::Element *E = g.navmesh_ids.front(); E; E = E->next()) {
- NavigationServer::get_singleton()->free(E->get().region);
+ NavigationServer3D::get_singleton()->free(E->get().region);
}
g.navmesh_ids.clear();
@@ -655,8 +655,8 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
for (int i = 0; i < g.multimesh_instances.size(); i++) {
- VS::get_singleton()->free(g.multimesh_instances[i].instance);
- VS::get_singleton()->free(g.multimesh_instances[i].multimesh);
+ RS::get_singleton()->free(g.multimesh_instances[i].instance);
+ RS::get_singleton()->free(g.multimesh_instances[i].multimesh);
}
g.multimesh_instances.clear();
}
@@ -667,14 +667,14 @@ void GridMap::_notification(int p_what) {
case NOTIFICATION_ENTER_WORLD: {
- Spatial *c = this;
+ Node3D *c = this;
while (c) {
- navigation = Object::cast_to<Navigation>(c);
+ navigation = Object::cast_to<Navigation3D>(c);
if (navigation) {
break;
}
- c = Object::cast_to<Spatial>(c->get_parent());
+ c = Object::cast_to<Node3D>(c->get_parent());
}
last_transform = get_global_transform();
@@ -684,8 +684,8 @@ void GridMap::_notification(int p_what) {
}
for (int i = 0; i < baked_meshes.size(); i++) {
- VS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
+ RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, get_world()->get_scenario());
+ RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
}
} break;
@@ -702,7 +702,7 @@ void GridMap::_notification(int p_what) {
last_transform = new_xform;
for (int i = 0; i < baked_meshes.size(); i++) {
- VS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
+ RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform());
}
} break;
@@ -712,13 +712,13 @@ void GridMap::_notification(int p_what) {
_octant_exit_world(E->key());
}
- navigation = NULL;
+ navigation = nullptr;
//_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
//_update_octants_callback();
//_update_area_instances();
for (int i = 0; i < baked_meshes.size(); i++) {
- VS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID());
+ RS::get_singleton()->instance_set_scenario(baked_meshes[i].instance, RID());
}
} break;
@@ -738,7 +738,7 @@ void GridMap::_update_visibility() {
Octant *octant = e->value();
for (int i = 0; i < octant->multimesh_instances.size(); i++) {
const Octant::MultimeshInstance &mi = octant->multimesh_instances[i];
- VS::get_singleton()->instance_set_visible(mi.instance, is_visible());
+ RS::get_singleton()->instance_set_visible(mi.instance, is_visible());
}
}
}
@@ -975,7 +975,7 @@ Vector3 GridMap::_get_offset() const {
void GridMap::clear_baked_meshes() {
for (int i = 0; i < baked_meshes.size(); i++) {
- VS::get_singleton()->free(baked_meshes[i].instance);
+ RS::get_singleton()->free(baked_meshes[i].instance);
}
baked_meshes.clear();
@@ -988,7 +988,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
return;
//generate
- Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool> > > surface_map;
+ Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>> surface_map;
for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
@@ -1017,10 +1017,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
ok.z = key.z / octant_size;
if (!surface_map.has(ok)) {
- surface_map[ok] = Map<Ref<Material>, Ref<SurfaceTool> >();
+ surface_map[ok] = Map<Ref<Material>, Ref<SurfaceTool>>();
}
- Map<Ref<Material>, Ref<SurfaceTool> > &mat_map = surface_map[ok];
+ Map<Ref<Material>, Ref<SurfaceTool>> &mat_map = surface_map[ok];
for (int i = 0; i < mesh->get_surface_count(); i++) {
@@ -1040,22 +1040,22 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
}
}
- for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool> > >::Element *E = surface_map.front(); E; E = E->next()) {
+ for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>>::Element *E = surface_map.front(); E; E = E->next()) {
Ref<ArrayMesh> mesh;
mesh.instance();
- for (Map<Ref<Material>, Ref<SurfaceTool> >::Element *F = E->get().front(); F; F = F->next()) {
+ for (Map<Ref<Material>, Ref<SurfaceTool>>::Element *F = E->get().front(); F; F = F->next()) {
F->get()->commit(mesh);
}
BakedMesh bm;
bm.mesh = mesh;
- bm.instance = VS::get_singleton()->instance_create();
- VS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
- VS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
+ bm.instance = RS::get_singleton()->instance_create();
+ RS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid());
+ RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id());
if (is_inside_tree()) {
- VS::get_singleton()->instance_set_scenario(bm.instance, get_world()->get_scenario());
- VS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
+ RS::get_singleton()->instance_set_scenario(bm.instance, get_world()->get_scenario());
+ RS::get_singleton()->instance_set_transform(bm.instance, get_global_transform());
}
if (p_gen_lightmap_uv) {
@@ -1107,7 +1107,7 @@ GridMap::GridMap() {
clip_above = true;
cell_scale = 1.0;
- navigation = NULL;
+ navigation = nullptr;
set_notify_transform(true);
recreating_octants = false;
}
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index cc1c8c2923..3f3da09fe9 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -31,17 +31,17 @@
#ifndef GRID_MAP_H
#define GRID_MAP_H
-#include "scene/3d/navigation.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/navigation_3d.h"
+#include "scene/3d/node_3d.h"
#include "scene/resources/mesh_library.h"
#include "scene/resources/multimesh.h"
//heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done..
//should scale better with hardware that supports instancing
-class GridMap : public Spatial {
+class GridMap : public Node3D {
- GDCLASS(GridMap, Spatial);
+ GDCLASS(GridMap, Node3D);
enum {
MAP_DIRTY_TRANSFORMS = 1,
@@ -147,7 +147,7 @@ class GridMap : public Spatial {
int octant_size;
bool center_x, center_y, center_z;
float cell_scale;
- Navigation *navigation;
+ Navigation3D *navigation;
bool clip;
bool clip_above;
@@ -166,10 +166,10 @@ class GridMap : public Spatial {
struct BakeLight {
- VS::LightType type;
+ RS::LightType type;
Vector3 pos;
Vector3 dir;
- float param[VS::LIGHT_PARAM_MAX];
+ float param[RS::LIGHT_PARAM_MAX];
};
_FORCE_INLINE_ Vector3 _octant_get_offset(const OctantKey &p_key) const {
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index a656ee8b63..eb8feb5bc7 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -29,19 +29,20 @@
/*************************************************************************/
#include "grid_map_editor_plugin.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
-#include "editor/plugins/spatial_editor_plugin.h"
-#include "scene/3d/camera.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
#include "core/math/geometry.h"
#include "core/os/keyboard.h"
+#include "scene/main/window.h"
void GridMapEditor::_node_removed(Node *p_node) {
if (p_node == node)
- node = NULL;
+ node = nullptr;
}
void GridMapEditor::_configure() {
@@ -280,8 +281,8 @@ void GridMapEditor::_update_cursor_transform() {
cursor_transform = node->get_global_transform() * cursor_transform;
if (cursor_instance.is_valid()) {
- VisualServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
- VisualServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);
+ RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
+ RenderingServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);
}
}
@@ -291,9 +292,9 @@ void GridMapEditor::_update_selection_transform() {
if (!selection.active) {
- VisualServer::get_singleton()->instance_set_transform(selection_instance, xf_zero);
+ RenderingServer::get_singleton()->instance_set_transform(selection_instance, xf_zero);
for (int i = 0; i < 3; i++) {
- VisualServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);
+ RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);
}
return;
}
@@ -302,11 +303,11 @@ void GridMapEditor::_update_selection_transform() {
xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size());
xf.origin = selection.begin * node->get_cell_size();
- VisualServer::get_singleton()->instance_set_transform(selection_instance, node->get_global_transform() * xf);
+ RenderingServer::get_singleton()->instance_set_transform(selection_instance, node->get_global_transform() * xf);
for (int i = 0; i < 3; i++) {
if (i != edit_axis || (edit_floor[edit_axis] < selection.begin[edit_axis]) || (edit_floor[edit_axis] > selection.end[edit_axis] + 1)) {
- VisualServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);
+ RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf_zero);
} else {
Vector3 scale = (selection.end - selection.begin + Vector3(1, 1, 1));
@@ -321,7 +322,7 @@ void GridMapEditor::_update_selection_transform() {
xf2.basis.scale(scale);
xf2.origin = pos;
- VisualServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf2);
+ RenderingServer::get_singleton()->instance_set_transform(selection_level_instance[i], xf2);
}
}
}
@@ -361,7 +362,7 @@ void GridMapEditor::_set_selection(bool p_active, const Vector3 &p_begin, const
options->get_popup()->set_item_disabled(options->get_popup()->get_item_index(MENU_OPTION_SELECTION_FILL), !selection.active);
}
-bool GridMapEditor::do_input_action(Camera *p_camera, const Point2 &p_point, bool p_click) {
+bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click) {
if (!spatial_editor)
return false;
@@ -374,7 +375,7 @@ bool GridMapEditor::do_input_action(Camera *p_camera, const Point2 &p_point, boo
if (input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE && !mesh_library->has_item(selected_palette))
return false;
- Camera *camera = p_camera;
+ Camera3D *camera = p_camera;
Vector3 from = camera->project_ray_origin(p_point);
Vector3 normal = camera->project_ray_normal(p_point);
Transform local_xform = node->get_global_transform().affine_inverse();
@@ -415,7 +416,7 @@ bool GridMapEditor::do_input_action(Camera *p_camera, const Point2 &p_point, boo
}
}
- VS::get_singleton()->instance_set_transform(grid_instance[edit_axis], node->get_global_transform() * edit_grid_xform);
+ RS::get_singleton()->instance_set_transform(grid_instance[edit_axis], node->get_global_transform() * edit_grid_xform);
if (cursor_instance.is_valid()) {
@@ -527,7 +528,7 @@ void GridMapEditor::_clear_clipboard_data() {
for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) {
- VisualServer::get_singleton()->free(E->get().instance);
+ RenderingServer::get_singleton()->free(E->get().instance);
}
clipboard_items.clear();
@@ -555,7 +556,7 @@ void GridMapEditor::_set_clipboard_data() {
item.cell_item = itm;
item.grid_offset = Vector3(i, j, k) - selection.begin;
item.orientation = node->get_cell_item_orientation(i, j, k);
- item.instance = VisualServer::get_singleton()->instance_create2(mesh->get_rid(), get_tree()->get_root()->get_world()->get_scenario());
+ item.instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), get_tree()->get_root()->get_world()->get_scenario());
clipboard_items.push_back(item);
}
@@ -569,7 +570,7 @@ void GridMapEditor::_update_paste_indicator() {
Transform xf;
xf.basis.set_zero();
- VisualServer::get_singleton()->instance_set_transform(paste_instance, xf);
+ RenderingServer::get_singleton()->instance_set_transform(paste_instance, xf);
return;
}
@@ -583,7 +584,7 @@ void GridMapEditor::_update_paste_indicator() {
xf.basis = rot * xf.basis;
xf.translate((-center * node->get_cell_size()) / scale);
- VisualServer::get_singleton()->instance_set_transform(paste_instance, node->get_global_transform() * xf);
+ RenderingServer::get_singleton()->instance_set_transform(paste_instance, node->get_global_transform() * xf);
for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) {
@@ -598,7 +599,7 @@ void GridMapEditor::_update_paste_indicator() {
item_rot.set_orthogonal_index(item.orientation);
xf.basis = item_rot * xf.basis * node->get_cell_scale();
- VisualServer::get_singleton()->instance_set_transform(item.instance, node->get_global_transform() * xf);
+ RenderingServer::get_singleton()->instance_set_transform(item.instance, node->get_global_transform() * xf);
}
}
@@ -638,7 +639,7 @@ void GridMapEditor::_do_paste() {
_clear_clipboard_data();
}
-bool GridMapEditor::forward_spatial_input_event(Camera *p_camera, const Ref<InputEvent> &p_event) {
+bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!node) {
return false;
}
@@ -659,8 +660,8 @@ bool GridMapEditor::forward_spatial_input_event(Camera *p_camera, const Ref<Inpu
}
if (mb->is_pressed()) {
- SpatialEditorViewport::NavigationScheme nav_scheme = (SpatialEditorViewport::NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
- if ((nav_scheme == SpatialEditorViewport::NAVIGATION_MAYA || nav_scheme == SpatialEditorViewport::NAVIGATION_MODO) && mb->get_alt()) {
+ 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) {
@@ -895,7 +896,7 @@ void GridMapEditor::update_palette() {
Ref<MeshLibrary> mesh_library = node->get_mesh_library();
if (mesh_library.is_null()) {
- last_mesh_library = NULL;
+ last_mesh_library = nullptr;
search_box->set_text("");
search_box->set_editable(false);
info_message->show();
@@ -963,16 +964,16 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
_update_selection_transform();
_update_paste_indicator();
- spatial_editor = Object::cast_to<SpatialEditorPlugin>(editor->get_editor_plugin_screen());
+ spatial_editor = Object::cast_to<Node3DEditorPlugin>(editor->get_editor_plugin_screen());
if (!node) {
set_process(false);
for (int i = 0; i < 3; i++) {
- VisualServer::get_singleton()->instance_set_visible(grid_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], false);
}
if (cursor_instance.is_valid()) {
- VisualServer::get_singleton()->instance_set_visible(cursor_instance, false);
+ RenderingServer::get_singleton()->instance_set_visible(cursor_instance, false);
}
return;
@@ -1010,7 +1011,7 @@ void GridMapEditor::update_grid() {
edit_grid_xform.basis = Basis();
for (int i = 0; i < 3; i++) {
- VisualServer::get_singleton()->instance_set_visible(grid_instance[i], i == edit_axis);
+ RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], i == edit_axis);
}
updating = true;
@@ -1022,7 +1023,7 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) {
Vector3 edited_floor = node->has_meta("_editor_floor_") ? node->get_meta("_editor_floor_") : Variant();
for (int i = 0; i < 3; i++) {
- VS::get_singleton()->mesh_clear(grid[i]);
+ RS::get_singleton()->mesh_clear(grid[i]);
edit_floor[i] = edited_floor[i];
}
@@ -1064,11 +1065,11 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) {
}
Array d;
- d.resize(VS::ARRAY_MAX);
- d[VS::ARRAY_VERTEX] = grid_points[i];
- d[VS::ARRAY_COLOR] = grid_colors[i];
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], VisualServer::PRIMITIVE_LINES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
+ d.resize(RS::ARRAY_MAX);
+ d[RS::ARRAY_VERTEX] = grid_points[i];
+ d[RS::ARRAY_COLOR] = grid_colors[i];
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], RenderingServer::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
}
}
@@ -1081,13 +1082,13 @@ void GridMapEditor::_notification(int p_what) {
mesh_library_palette->connect("item_selected", callable_mp(this, &GridMapEditor::_item_selected_cbk));
for (int i = 0; i < 3; i++) {
- grid[i] = VS::get_singleton()->mesh_create();
- grid_instance[i] = VS::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario());
- selection_level_instance[i] = VisualServer::get_singleton()->instance_create2(selection_level_mesh[i], get_tree()->get_root()->get_world()->get_scenario());
+ grid[i] = RS::get_singleton()->mesh_create();
+ grid_instance[i] = RS::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario());
+ selection_level_instance[i] = RenderingServer::get_singleton()->instance_create2(selection_level_mesh[i], get_tree()->get_root()->get_world()->get_scenario());
}
- selection_instance = VisualServer::get_singleton()->instance_create2(selection_mesh, get_tree()->get_root()->get_world()->get_scenario());
- paste_instance = VisualServer::get_singleton()->instance_create2(paste_mesh, get_tree()->get_root()->get_world()->get_scenario());
+ selection_instance = RenderingServer::get_singleton()->instance_create2(selection_mesh, get_tree()->get_root()->get_world()->get_scenario());
+ paste_instance = RenderingServer::get_singleton()->instance_create2(paste_mesh, get_tree()->get_root()->get_world()->get_scenario());
_update_selection_transform();
_update_paste_indicator();
@@ -1099,15 +1100,15 @@ void GridMapEditor::_notification(int p_what) {
for (int i = 0; i < 3; i++) {
- VS::get_singleton()->free(grid_instance[i]);
- VS::get_singleton()->free(grid[i]);
+ RS::get_singleton()->free(grid_instance[i]);
+ RS::get_singleton()->free(grid[i]);
grid_instance[i] = RID();
grid[i] = RID();
- VisualServer::get_singleton()->free(selection_level_instance[i]);
+ RenderingServer::get_singleton()->free(selection_level_instance[i]);
}
- VisualServer::get_singleton()->free(selection_instance);
- VisualServer::get_singleton()->free(paste_instance);
+ RenderingServer::get_singleton()->free(selection_instance);
+ RenderingServer::get_singleton()->free(paste_instance);
selection_instance = RID();
paste_instance = RID();
} break;
@@ -1122,7 +1123,7 @@ void GridMapEditor::_notification(int p_what) {
if (xf != grid_xform) {
for (int i = 0; i < 3; i++) {
- VS::get_singleton()->instance_set_transform(grid_instance[i], xf * edit_grid_xform);
+ RS::get_singleton()->instance_set_transform(grid_instance[i], xf * edit_grid_xform);
}
grid_xform = xf;
}
@@ -1139,15 +1140,15 @@ void GridMapEditor::_notification(int p_what) {
p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis];
p = node->get_transform().xform(p); // plane to snap
- SpatialEditorPlugin *sep = Object::cast_to<SpatialEditorPlugin>(editor->get_editor_plugin_screen());
+ Node3DEditorPlugin *sep = Object::cast_to<Node3DEditorPlugin>(editor->get_editor_plugin_screen());
if (sep)
sep->snap_cursor_to_plane(p);
}
} break;
case NOTIFICATION_THEME_CHANGED: {
- options->set_icon(get_icon("GridMap", "EditorIcons"));
- search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ options->set_icon(get_theme_icon("GridMap", "EditorIcons"));
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
} break;
}
}
@@ -1158,7 +1159,7 @@ void GridMapEditor::_update_cursor_instance() {
}
if (cursor_instance.is_valid())
- VisualServer::get_singleton()->free(cursor_instance);
+ RenderingServer::get_singleton()->free(cursor_instance);
cursor_instance = RID();
if (selected_palette >= 0) {
@@ -1167,8 +1168,8 @@ void GridMapEditor::_update_cursor_instance() {
Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);
if (!mesh.is_null() && mesh->get_rid().is_valid()) {
- cursor_instance = VisualServer::get_singleton()->instance_create2(mesh->get_rid(), get_tree()->get_root()->get_world()->get_scenario());
- VisualServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
+ cursor_instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), get_tree()->get_root()->get_world()->get_scenario());
+ RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
}
}
}
@@ -1216,7 +1217,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
spatial_editor_hb = memnew(HBoxContainer);
spatial_editor_hb->set_h_size_flags(SIZE_EXPAND_FILL);
spatial_editor_hb->set_alignment(BoxContainer::ALIGN_END);
- SpatialEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
spin_box_label = memnew(Label);
spin_box_label->set_text(TTR("Floor:"));
@@ -1226,7 +1227,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
floor->set_min(-32767);
floor->set_max(32767);
floor->set_step(1);
- floor->get_line_edit()->add_constant_override("minimum_spaces", 16);
+ floor->get_line_edit()->add_theme_constant_override("minimum_spaces", 16);
spatial_editor_hb->add_child(floor);
floor->connect("value_changed", callable_mp(this, &GridMapEditor::_floor_changed));
@@ -1304,14 +1305,14 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
mode_thumbnail = memnew(ToolButton);
mode_thumbnail->set_toggle_mode(true);
mode_thumbnail->set_pressed(true);
- mode_thumbnail->set_icon(p_editor->get_gui_base()->get_icon("FileThumbnail", "EditorIcons"));
+ mode_thumbnail->set_icon(p_editor->get_gui_base()->get_theme_icon("FileThumbnail", "EditorIcons"));
hb->add_child(mode_thumbnail);
mode_thumbnail->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode), varray(DISPLAY_THUMBNAIL));
mode_list = memnew(ToolButton);
mode_list->set_toggle_mode(true);
mode_list->set_pressed(false);
- mode_list->set_icon(p_editor->get_gui_base()->get_icon("FileList", "EditorIcons"));
+ mode_list->set_icon(p_editor->get_gui_base()->get_theme_icon("FileList", "EditorIcons"));
hb->add_child(mode_list);
mode_list->connect("pressed", callable_mp(this, &GridMapEditor::_set_display_mode), varray(DISPLAY_LIST));
@@ -1352,8 +1353,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
lock_view = false;
cursor_rot = 0;
- selection_mesh = VisualServer::get_singleton()->mesh_create();
- paste_mesh = VisualServer::get_singleton()->mesh_create();
+ selection_mesh = RenderingServer::get_singleton()->mesh_create();
+ paste_mesh = RenderingServer::get_singleton()->mesh_create();
{
// Selection mesh create.
@@ -1430,16 +1431,16 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
}
Array d;
- d.resize(VS::ARRAY_MAX);
+ d.resize(RS::ARRAY_MAX);
inner_mat.instance();
inner_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.2));
inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- d[VS::ARRAY_VERTEX] = triangles;
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, VS::PRIMITIVE_TRIANGLES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid());
+ d[RS::ARRAY_VERTEX] = triangles;
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_TRIANGLES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid());
outer_mat.instance();
outer_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.8));
@@ -1453,23 +1454,23 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
selection_floor_mat->set_on_top_of_alpha();
selection_floor_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- d[VS::ARRAY_VERTEX] = lines;
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, VS::PRIMITIVE_LINES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_mesh, 1, outer_mat->get_rid());
+ d[RS::ARRAY_VERTEX] = lines;
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 1, outer_mat->get_rid());
- d[VS::ARRAY_VERTEX] = triangles;
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, VS::PRIMITIVE_TRIANGLES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(paste_mesh, 0, inner_mat->get_rid());
+ d[RS::ARRAY_VERTEX] = triangles;
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_TRIANGLES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 0, inner_mat->get_rid());
- d[VS::ARRAY_VERTEX] = lines;
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, VS::PRIMITIVE_LINES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(paste_mesh, 1, outer_mat->get_rid());
+ d[RS::ARRAY_VERTEX] = lines;
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(paste_mesh, RS::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(paste_mesh, 1, outer_mat->get_rid());
for (int i = 0; i < 3; i++) {
- d[VS::ARRAY_VERTEX] = square[i];
- selection_level_mesh[i] = VS::get_singleton()->mesh_create();
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(selection_level_mesh[i], VS::PRIMITIVE_LINES, d);
- VisualServer::get_singleton()->mesh_surface_set_material(selection_level_mesh[i], 0, selection_floor_mat->get_rid());
+ d[RS::ARRAY_VERTEX] = square[i];
+ selection_level_mesh[i] = RS::get_singleton()->mesh_create();
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_level_mesh[i], RS::PRIMITIVE_LINES, d);
+ RenderingServer::get_singleton()->mesh_surface_set_material(selection_level_mesh[i], 0, selection_floor_mat->get_rid());
}
}
@@ -1492,24 +1493,24 @@ GridMapEditor::~GridMapEditor() {
for (int i = 0; i < 3; i++) {
if (grid[i].is_valid())
- VisualServer::get_singleton()->free(grid[i]);
+ RenderingServer::get_singleton()->free(grid[i]);
if (grid_instance[i].is_valid())
- VisualServer::get_singleton()->free(grid_instance[i]);
+ RenderingServer::get_singleton()->free(grid_instance[i]);
if (cursor_instance.is_valid())
- VisualServer::get_singleton()->free(cursor_instance);
+ RenderingServer::get_singleton()->free(cursor_instance);
if (selection_level_instance[i].is_valid())
- VisualServer::get_singleton()->free(selection_level_instance[i]);
+ RenderingServer::get_singleton()->free(selection_level_instance[i]);
if (selection_level_mesh[i].is_valid())
- VisualServer::get_singleton()->free(selection_level_mesh[i]);
+ RenderingServer::get_singleton()->free(selection_level_mesh[i]);
}
- VisualServer::get_singleton()->free(selection_mesh);
+ RenderingServer::get_singleton()->free(selection_mesh);
if (selection_instance.is_valid())
- VisualServer::get_singleton()->free(selection_instance);
+ RenderingServer::get_singleton()->free(selection_instance);
- VisualServer::get_singleton()->free(paste_mesh);
+ RenderingServer::get_singleton()->free(paste_mesh);
if (paste_instance.is_valid())
- VisualServer::get_singleton()->free(paste_instance);
+ RenderingServer::get_singleton()->free(paste_instance);
}
void GridMapEditorPlugin::_notification(int p_what) {
@@ -1518,10 +1519,10 @@ void GridMapEditorPlugin::_notification(int p_what) {
switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) {
case 0: { // Left.
- SpatialEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 0);
+ Node3DEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 0);
} break;
case 1: { // Right.
- SpatialEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 1);
+ Node3DEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 1);
} break;
}
}
@@ -1547,7 +1548,7 @@ void GridMapEditorPlugin::make_visible(bool p_visible) {
grid_map_editor->spatial_editor_hb->hide();
grid_map_editor->hide();
- grid_map_editor->edit(NULL);
+ grid_map_editor->edit(nullptr);
grid_map_editor->set_process(false);
}
}
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index d6459cee0a..fd880e8b7b 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -36,7 +36,7 @@
#include "editor/pane_drag.h"
#include "grid_map.h"
-class SpatialEditorPlugin;
+class Node3DEditorPlugin;
class GridMapEditor : public VBoxContainer {
GDCLASS(GridMapEditor, VBoxContainer);
@@ -188,7 +188,7 @@ class GridMapEditor : public VBoxContainer {
};
- SpatialEditorPlugin *spatial_editor;
+ Node3DEditorPlugin *spatial_editor;
struct AreaDisplay {
@@ -232,7 +232,7 @@ class GridMapEditor : public VBoxContainer {
void _delete_selection();
void _fill_selection();
- bool do_input_action(Camera *p_camera, const Point2 &p_point, bool p_click);
+ bool do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click);
friend class GridMapEditorPlugin;
@@ -242,7 +242,7 @@ protected:
static void _bind_methods();
public:
- bool forward_spatial_input_event(Camera *p_camera, const Ref<InputEvent> &p_event);
+ bool forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event);
void edit(GridMap *p_gridmap);
GridMapEditor() {}
@@ -261,7 +261,7 @@ protected:
void _notification(int p_what);
public:
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
+ virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual String get_name() const { return "GridMap"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index bc720f460c..c0e3c39ca8 100644
--- a/modules/gridmap/register_types.h
+++ b/modules/gridmap/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef GRIDMAP_REGISTER_TYPES_H
+#define GRIDMAP_REGISTER_TYPES_H
+
void register_gridmap_types();
void unregister_gridmap_types();
+
+#endif // GRIDMAP_REGISTER_TYPES_H
diff --git a/modules/hdr/SCsub b/modules/hdr/SCsub
index c960e8126b..a709397c9a 100644
--- a/modules/hdr/SCsub
+++ b/modules/hdr/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_hdr = env_modules.Clone()
diff --git a/modules/hdr/config.py b/modules/hdr/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/hdr/config.py
+++ b/modules/hdr/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp
index 2ef6b7cd07..5f2d1578c5 100644
--- a/modules/hdr/register_types.cpp
+++ b/modules/hdr/register_types.cpp
@@ -32,7 +32,7 @@
#include "image_loader_hdr.h"
-static ImageLoaderHDR *image_loader_hdr = NULL;
+static ImageLoaderHDR *image_loader_hdr = nullptr;
void register_hdr_types() {
diff --git a/modules/hdr/register_types.h b/modules/hdr/register_types.h
index c1c69a1e27..02441516ec 100644
--- a/modules/hdr/register_types.h
+++ b/modules/hdr/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef HDR_REGISTER_TYPES_H
+#define HDR_REGISTER_TYPES_H
+
void register_hdr_types();
void unregister_hdr_types();
+
+#endif // HDR_REGISTER_TYPES_H
diff --git a/modules/jpg/SCsub b/modules/jpg/SCsub
index 96e8e704dd..8ee8e6dd6e 100644
--- a/modules/jpg/SCsub
+++ b/modules/jpg/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_jpg = env_modules.Clone()
diff --git a/modules/jpg/config.py b/modules/jpg/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/jpg/config.py
+++ b/modules/jpg/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp
index f6077d5c68..61375fef10 100644
--- a/modules/jpg/register_types.cpp
+++ b/modules/jpg/register_types.cpp
@@ -32,7 +32,7 @@
#include "image_loader_jpegd.h"
-static ImageLoaderJPG *image_loader_jpg = NULL;
+static ImageLoaderJPG *image_loader_jpg = nullptr;
void register_jpg_types() {
diff --git a/modules/jpg/register_types.h b/modules/jpg/register_types.h
index 291098fae2..52cd378b3a 100644
--- a/modules/jpg/register_types.h
+++ b/modules/jpg/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef JPG_REGISTER_TYPES_H
+#define JPG_REGISTER_TYPES_H
+
void register_jpg_types();
void unregister_jpg_types();
+
+#endif // JPG_REGISTER_TYPES_H
diff --git a/modules/jsonrpc/SCsub b/modules/jsonrpc/SCsub
index 13c9ffb253..fe5312670a 100644
--- a/modules/jsonrpc/SCsub
+++ b/modules/jsonrpc/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_jsonrpc = env_modules.Clone()
env_jsonrpc.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/jsonrpc/config.py b/modules/jsonrpc/config.py
index 53bc827027..d22f9454ed 100644
--- a/modules/jsonrpc/config.py
+++ b/modules/jsonrpc/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return True
+ return True
+
def configure(env):
- pass
+ pass
diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp
index 014b65e3e2..393269d422 100644
--- a/modules/jsonrpc/jsonrpc.cpp
+++ b/modules/jsonrpc/jsonrpc.cpp
@@ -119,7 +119,7 @@ Variant JSONRPC::process_action(const Variant &p_action, bool p_process_arr_elem
id = dict["id"];
}
- if (object == NULL || !object->has_method(method)) {
+ if (object == nullptr || !object->has_method(method)) {
ret = make_response_error(JSONRPC::METHOD_NOT_FOUND, "Method not found", id);
} else {
Variant call_ret = object->callv(method, args);
diff --git a/modules/jsonrpc/register_types.h b/modules/jsonrpc/register_types.h
index 958f16344a..854d73a21f 100644
--- a/modules/jsonrpc/register_types.h
+++ b/modules/jsonrpc/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef JSONRPC_REGISTER_TYPES_H
+#define JSONRPC_REGISTER_TYPES_H
+
void register_jsonrpc_types();
void unregister_jsonrpc_types();
+
+#endif // JSONRPC_REGISTER_TYPES_H
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
index 0c6c703e16..5f5d25a3ee 100755
--- a/modules/mbedtls/SCsub
+++ b/modules/mbedtls/SCsub
@@ -1,11 +1,11 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_mbed_tls = env_modules.Clone()
-if env['builtin_mbedtls']:
+if env["builtin_mbedtls"]:
# Thirdparty source files
thirdparty_sources = [
"aes.c",
@@ -86,7 +86,7 @@ if env['builtin_mbedtls']:
"x509_csr.c",
"x509write_crt.c",
"x509write_csr.c",
- "xtea.c"
+ "xtea.c",
]
thirdparty_dir = "#thirdparty/mbedtls/library/"
diff --git a/modules/mbedtls/config.py b/modules/mbedtls/config.py
index 1c8cd12a2d..d22f9454ed 100755
--- a/modules/mbedtls/config.py
+++ b/modules/mbedtls/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index ee3c78aeb3..a47a4503a5 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -66,7 +66,7 @@ Error CryptoKeyMbedTLS::load(String p_path) {
}
memdelete(f);
- int ret = mbedtls_pk_parse_key(&pkey, out.ptr(), out.size(), NULL, 0);
+ int ret = mbedtls_pk_parse_key(&pkey, out.ptr(), out.size(), nullptr, 0);
// We MUST zeroize the memory for safety!
mbedtls_platform_zeroize(out.ptrw(), out.size());
ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing private key '" + itos(ret) + "'.");
@@ -167,11 +167,11 @@ void CryptoMbedTLS::initialize_crypto() {
}
void CryptoMbedTLS::finalize_crypto() {
- Crypto::_create = NULL;
- Crypto::_load_default_certificates = NULL;
+ Crypto::_create = nullptr;
+ Crypto::_load_default_certificates = nullptr;
if (default_certs) {
memdelete(default_certs);
- default_certs = NULL;
+ default_certs = nullptr;
}
X509CertificateMbedTLS::finalize();
CryptoKeyMbedTLS::finalize();
@@ -180,7 +180,7 @@ void CryptoMbedTLS::finalize_crypto() {
CryptoMbedTLS::CryptoMbedTLS() {
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
- int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+ int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);
if (ret != 0) {
ERR_PRINT(" failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
}
@@ -191,17 +191,17 @@ CryptoMbedTLS::~CryptoMbedTLS() {
mbedtls_entropy_free(&entropy);
}
-X509CertificateMbedTLS *CryptoMbedTLS::default_certs = NULL;
+X509CertificateMbedTLS *CryptoMbedTLS::default_certs = nullptr;
X509CertificateMbedTLS *CryptoMbedTLS::get_default_certificates() {
return default_certs;
}
void CryptoMbedTLS::load_default_certificates(String p_path) {
- ERR_FAIL_COND(default_certs != NULL);
+ ERR_FAIL_COND(default_certs != nullptr);
default_certs = memnew(X509CertificateMbedTLS);
- ERR_FAIL_COND(default_certs == NULL);
+ ERR_FAIL_COND(default_certs == nullptr);
if (p_path != "") {
// Use certs defined in project settings.
@@ -227,15 +227,15 @@ Ref<CryptoKey> CryptoMbedTLS::generate_rsa(int p_bytes) {
Ref<CryptoKeyMbedTLS> out;
out.instance();
int ret = mbedtls_pk_setup(&(out->pkey), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
- ERR_FAIL_COND_V(ret != 0, NULL);
+ ERR_FAIL_COND_V(ret != 0, nullptr);
ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(out->pkey), mbedtls_ctr_drbg_random, &ctr_drbg, p_bytes, 65537);
- ERR_FAIL_COND_V(ret != 0, NULL);
+ ERR_FAIL_COND_V(ret != 0, nullptr);
return out;
}
Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoKey> p_key, String p_issuer_name, String p_not_before, String p_not_after) {
- Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS> >(p_key);
- ERR_FAIL_COND_V_MSG(key.is_null(), NULL, "Invalid private key argument.");
+ Ref<CryptoKeyMbedTLS> key = static_cast<Ref<CryptoKeyMbedTLS>>(p_key);
+ ERR_FAIL_COND_V_MSG(key.is_null(), nullptr, "Invalid private key argument.");
mbedtls_x509write_cert crt;
mbedtls_x509write_crt_init(&crt);
@@ -250,7 +250,7 @@ Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoK
mbedtls_mpi_init(&serial);
uint8_t rand_serial[20];
mbedtls_ctr_drbg_random(&ctr_drbg, rand_serial, 20);
- ERR_FAIL_COND_V(mbedtls_mpi_read_binary(&serial, rand_serial, 20), NULL);
+ ERR_FAIL_COND_V(mbedtls_mpi_read_binary(&serial, rand_serial, 20), nullptr);
mbedtls_x509write_crt_set_serial(&crt, &serial);
mbedtls_x509write_crt_set_validity(&crt, p_not_before.utf8().get_data(), p_not_after.utf8().get_data());
@@ -268,7 +268,7 @@ Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoK
mbedtls_mpi_free(&serial);
mbedtls_x509write_crt_free(&crt);
ERR_PRINT("Generated invalid certificate: " + itos(err));
- return NULL;
+ return nullptr;
}
mbedtls_mpi_free(&serial);
diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h
index 6c1c0e255d..db3d00a5e3 100644
--- a/modules/mbedtls/crypto_mbedtls.h
+++ b/modules/mbedtls/crypto_mbedtls.h
@@ -49,7 +49,7 @@ private:
public:
static CryptoKey *create();
static void make_default() { CryptoKey::_create = create; }
- static void finalize() { CryptoKey::_create = NULL; }
+ static void finalize() { CryptoKey::_create = nullptr; }
virtual Error load(String p_path);
virtual Error save(String p_path);
@@ -78,7 +78,7 @@ private:
public:
static X509Certificate *create();
static void make_default() { X509Certificate::_create = create; }
- static void finalize() { X509Certificate::_create = NULL; }
+ static void finalize() { X509Certificate::_create = nullptr; }
virtual Error load(String p_path);
virtual Error load_from_memory(const uint8_t *p_buffer, int p_len);
diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp
index 215b511758..f31f067f4e 100644
--- a/modules/mbedtls/dtls_server_mbedtls.cpp
+++ b/modules/mbedtls/dtls_server_mbedtls.cpp
@@ -65,7 +65,7 @@ void DTLSServerMbedTLS::initialize() {
}
void DTLSServerMbedTLS::finalize() {
- _create = NULL;
+ _create = nullptr;
available = false;
}
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index bdf36ad1b1..b2aa5f5827 100755
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -36,11 +36,11 @@
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
- if (buf == NULL || len <= 0) return 0;
+ if (buf == nullptr || len <= 0) return 0;
PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
- ERR_FAIL_COND_V(sp == NULL, 0);
+ ERR_FAIL_COND_V(sp == nullptr, 0);
Error err = sp->base->put_packet((const uint8_t *)buf, len);
if (err == ERR_BUSY) {
@@ -53,11 +53,11 @@ int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len
int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
- if (buf == NULL || len <= 0) return 0;
+ if (buf == nullptr || len <= 0) return 0;
PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
- ERR_FAIL_COND_V(sp == NULL, 0);
+ ERR_FAIL_COND_V(sp == nullptr, 0);
int pc = sp->base->get_available_packet_count();
if (pc == 0) {
@@ -125,7 +125,7 @@ Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_vali
ERR_FAIL_COND_V(err != OK, err);
mbedtls_ssl_set_hostname(ssl_ctx->get_context(), p_for_hostname.utf8().get_data());
- mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, NULL);
+ mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, nullptr);
mbedtls_ssl_set_timer_cb(ssl_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
status = STATUS_HANDSHAKING;
@@ -154,7 +154,7 @@ Error PacketPeerMbedDTLS::accept_peer(Ref<PacketPeerUDP> p_base, Ref<CryptoKey>
ERR_FAIL_V_MSG(FAILED, "Error setting DTLS client cookie");
}
- mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, NULL);
+ mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, nullptr);
mbedtls_ssl_set_timer_cb(ssl_ctx->get_context(), &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
status = STATUS_HANDSHAKING;
@@ -223,7 +223,7 @@ void PacketPeerMbedDTLS::poll() {
ERR_FAIL_COND(!base.is_valid());
- int ret = mbedtls_ssl_read(ssl_ctx->get_context(), NULL, 0);
+ int ret = mbedtls_ssl_read(ssl_ctx->get_context(), nullptr, 0);
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
@@ -292,6 +292,6 @@ void PacketPeerMbedDTLS::initialize_dtls() {
}
void PacketPeerMbedDTLS::finalize_dtls() {
- _create = NULL;
+ _create = nullptr;
available = false;
}
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.h b/modules/mbedtls/packet_peer_mbed_dtls.h
index 26c4543785..b958fa3b95 100755
--- a/modules/mbedtls/packet_peer_mbed_dtls.h
+++ b/modules/mbedtls/packet_peer_mbed_dtls.h
@@ -67,7 +67,7 @@ protected:
public:
virtual void poll();
virtual Error accept_peer(Ref<PacketPeerUDP> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert = Ref<X509Certificate>(), Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>(), Ref<CookieContextMbedTLS> p_cookies = Ref<CookieContextMbedTLS>());
- virtual Error connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_ca_certs = Ref<X509Certificate>());
+ virtual Error connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs = true, const String &p_for_hostname = String(), Ref<X509Certificate> p_ca_certs = Ref<X509Certificate>());
virtual Status get_status() const;
virtual void disconnect_from_peer();
diff --git a/modules/mbedtls/register_types.h b/modules/mbedtls/register_types.h
index f179d39438..90c81b1682 100755
--- a/modules/mbedtls/register_types.h
+++ b/modules/mbedtls/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef MBEDTLS_REGISTER_TYPES_H
+#define MBEDTLS_REGISTER_TYPES_H
+
void register_mbedtls_types();
void unregister_mbedtls_types();
+
+#endif // MBEDTLS_REGISTER_TYPES_H
diff --git a/modules/mbedtls/ssl_context_mbedtls.cpp b/modules/mbedtls/ssl_context_mbedtls.cpp
index 52630bd98c..1ffb9bda05 100644
--- a/modules/mbedtls/ssl_context_mbedtls.cpp
+++ b/modules/mbedtls/ssl_context_mbedtls.cpp
@@ -53,7 +53,7 @@ Error CookieContextMbedTLS::setup() {
mbedtls_ssl_cookie_init(&cookie_ctx);
inited = true;
- int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+ int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);
if (ret != 0) {
clear(); // Never leave unusable resources around.
ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error " + itos(ret));
@@ -94,7 +94,7 @@ Error SSLContextMbedTLS::_setup(int p_endpoint, int p_transport, int p_authmode)
mbedtls_entropy_init(&entropy);
inited = true;
- int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+ int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);
if (ret != 0) {
clear(); // Never leave unusable resources around.
ERR_FAIL_V_MSG(FAILED, "mbedtls_ctr_drbg_seed returned an error " + itos(ret));
@@ -134,7 +134,7 @@ Error SSLContextMbedTLS::init_server(int p_transport, int p_authmode, Ref<Crypto
}
// Adding CA chain if available.
if (certs->cert.next) {
- mbedtls_ssl_conf_ca_chain(&conf, certs->cert.next, NULL);
+ mbedtls_ssl_conf_ca_chain(&conf, certs->cert.next, nullptr);
}
// DTLS Cookies
if (p_transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
@@ -153,7 +153,7 @@ Error SSLContextMbedTLS::init_client(int p_transport, int p_authmode, Ref<X509Ce
Error err = _setup(MBEDTLS_SSL_IS_CLIENT, p_transport, p_authmode);
ERR_FAIL_COND_V(err != OK, err);
- X509CertificateMbedTLS *cas = NULL;
+ X509CertificateMbedTLS *cas = nullptr;
if (p_valid_cas.is_valid()) {
// Locking CA certificates
@@ -163,14 +163,14 @@ Error SSLContextMbedTLS::init_client(int p_transport, int p_authmode, Ref<X509Ce
} else {
// Fall back to default certificates (no need to lock those).
cas = CryptoMbedTLS::get_default_certificates();
- if (cas == NULL) {
+ if (cas == nullptr) {
clear();
ERR_FAIL_V_MSG(ERR_UNCONFIGURED, "SSL module failed to initialize!");
}
}
// Set valid CAs
- mbedtls_ssl_conf_ca_chain(&conf, &(cas->cert), NULL);
+ mbedtls_ssl_conf_ca_chain(&conf, &(cas->cert), nullptr);
mbedtls_ssl_setup(&ssl, &conf);
return OK;
}
@@ -195,7 +195,7 @@ void SSLContextMbedTLS::clear() {
}
mbedtls_ssl_context *SSLContextMbedTLS::get_context() {
- ERR_FAIL_COND_V(!inited, NULL);
+ ERR_FAIL_COND_V(!inited, nullptr);
return &ssl;
}
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index 03c5922267..983095c536 100755
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -35,11 +35,11 @@
int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
- if (buf == NULL || len <= 0) return 0;
+ if (buf == nullptr || len <= 0) return 0;
StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
- ERR_FAIL_COND_V(sp == NULL, 0);
+ ERR_FAIL_COND_V(sp == nullptr, 0);
int sent;
Error err = sp->base->put_partial_data((const uint8_t *)buf, len, sent);
@@ -54,11 +54,11 @@ int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len)
int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
- if (buf == NULL || len <= 0) return 0;
+ if (buf == nullptr || len <= 0) return 0;
StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
- ERR_FAIL_COND_V(sp == NULL, 0);
+ ERR_FAIL_COND_V(sp == nullptr, 0);
int got;
Error err = sp->base->get_partial_data((uint8_t *)buf, len, got);
@@ -112,7 +112,7 @@ Error StreamPeerMbedTLS::connect_to_stream(Ref<StreamPeer> p_base, bool p_valida
ERR_FAIL_COND_V(err != OK, err);
mbedtls_ssl_set_hostname(ssl_ctx->get_context(), p_for_hostname.utf8().get_data());
- mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, NULL);
+ mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, nullptr);
status = STATUS_HANDSHAKING;
@@ -133,7 +133,7 @@ Error StreamPeerMbedTLS::accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_
base = p_base;
- mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, NULL);
+ mbedtls_ssl_set_bio(ssl_ctx->get_context(), this, bio_send, bio_recv, nullptr);
status = STATUS_HANDSHAKING;
@@ -320,5 +320,5 @@ void StreamPeerMbedTLS::initialize_ssl() {
void StreamPeerMbedTLS::finalize_ssl() {
available = false;
- _create = NULL;
+ _create = nullptr;
}
diff --git a/modules/mobile_vr/SCsub b/modules/mobile_vr/SCsub
index 4bd184f025..e6c43228b4 100644
--- a/modules/mobile_vr/SCsub
+++ b/modules/mobile_vr/SCsub
@@ -1,8 +1,8 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_mobile_vr = env_modules.Clone()
-env_mobile_vr.add_source_files(env.modules_sources, '*.cpp')
+env_mobile_vr.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/mobile_vr/config.py b/modules/mobile_vr/config.py
index e85fa631dd..ee401c1a2a 100644
--- a/modules/mobile_vr/config.py
+++ b/modules/mobile_vr/config.py
@@ -1,13 +1,16 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"MobileVRInterface",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index 7552abe61d..120535bd41 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MobileVRInterface" inherits="ARVRInterface" version="4.0">
+<class name="MobileVRInterface" inherits="XRInterface" version="4.0">
<brief_description>
Generic mobile VR implementation.
</brief_description>
@@ -8,9 +8,9 @@
Note that even though there is no positional tracking, the camera will assume the headset is at a height of 1.85 meters. You can change this by setting [member eye_height].
You can initialise this interface as follows:
[codeblock]
- var interface = ARVRServer.find_interface("Native mobile")
+ var interface = XRServer.find_interface("Native mobile")
if interface and interface.initialize():
- get_viewport().arvr = true
+ get_viewport().xr = true
[/codeblock]
</description>
<tutorials>
@@ -25,7 +25,7 @@
The width of the display in centimeters.
</member>
<member name="eye_height" type="float" setter="set_eye_height" getter="get_eye_height" default="1.85">
- The height at which the camera is placed in relation to the ground (i.e. [ARVROrigin] node).
+ The height at which the camera is placed in relation to the ground (i.e. [XROrigin3D] node).
</member>
<member name="iod" type="float" setter="set_iod" getter="get_iod" default="6.0">
The interocular distance, also known as the interpupillary distance. The distance between the pupils of the left and right eye.
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 2f1d95cd42..2f0a15f20b 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -29,16 +29,17 @@
/*************************************************************************/
#include "mobile_vr_interface.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
-#include "servers/visual/visual_server_globals.h"
+#include "servers/display_server.h"
+#include "servers/rendering/rendering_server_globals.h"
StringName MobileVRInterface::get_name() const {
return "Native mobile";
};
int MobileVRInterface::get_capabilities() const {
- return ARVRInterface::ARVR_STEREO;
+ return XRInterface::XR_STEREO;
};
Vector3 MobileVRInterface::scale_magneto(const Vector3 &p_magnetometer) {
@@ -117,7 +118,7 @@ void MobileVRInterface::set_position_from_sensors() {
float delta_time = (double)ticks_elapsed / 1000000.0;
// few things we need
- Input *input = Input::get_singleton();
+ InputFilter *input = InputFilter::get_singleton();
Vector3 down(0.0, -1.0, 0.0); // Down is Y negative
Vector3 north(0.0, 0.0, 1.0); // North is Z positive
@@ -164,7 +165,7 @@ void MobileVRInterface::set_position_from_sensors() {
rotate.rotate(orientation.get_axis(2), gyro.z * delta_time);
orientation = rotate * orientation;
- tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
+ 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)
@@ -176,7 +177,7 @@ void MobileVRInterface::set_position_from_sensors() {
transform_quat = transform_quat.slerp(acc_mag_quat, 0.1);
orientation = Basis(transform_quat);
- tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
+ tracking_state = XRInterface::XR_NORMAL_TRACKING;
} else if (has_grav) {
// use gravity vector to make sure down is down...
// transform gravity into our world space
@@ -296,8 +297,8 @@ bool MobileVRInterface::is_initialized() const {
};
bool MobileVRInterface::initialize() {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, false);
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, false);
if (!initialized) {
// reset our sensor data and orientation
@@ -313,7 +314,7 @@ bool MobileVRInterface::initialize() {
orientation = Basis();
// make this our primary interface
- arvr_server->set_primary_interface(this);
+ xr_server->set_primary_interface(this);
last_ticks = OS::get_singleton()->get_ticks_usec();
@@ -325,10 +326,10 @@ bool MobileVRInterface::initialize() {
void MobileVRInterface::uninitialize() {
if (initialized) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- if (arvr_server != NULL) {
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server != nullptr) {
// no longer our primary interface
- arvr_server->clear_primary_interface_if(this);
+ xr_server->clear_primary_interface_if(this);
}
initialized = false;
@@ -339,7 +340,7 @@ Size2 MobileVRInterface::get_render_targetsize() {
_THREAD_SAFE_METHOD_
// we use half our window size
- Size2 target_size = OS::get_singleton()->get_window_size();
+ Size2 target_size = DisplayServer::get_singleton()->window_get_size();
target_size.x *= 0.5 * oversample;
target_size.y *= oversample;
@@ -347,22 +348,22 @@ Size2 MobileVRInterface::get_render_targetsize() {
return target_size;
};
-Transform MobileVRInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) {
_THREAD_SAFE_METHOD_
Transform transform_for_eye;
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, transform_for_eye);
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, transform_for_eye);
if (initialized) {
- float world_scale = arvr_server->get_world_scale();
+ 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...
// note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction...
- if (p_eye == ARVRInterface::EYE_LEFT) {
+ if (p_eye == XRInterface::EYE_LEFT) {
transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale);
- } else if (p_eye == ARVRInterface::EYE_RIGHT) {
+ } else if (p_eye == XRInterface::EYE_RIGHT) {
transform_for_eye.origin.x = intraocular_dist * 0.01 * 0.5 * world_scale;
} else {
// for mono we don't reposition, we want our center position.
@@ -373,7 +374,7 @@ Transform MobileVRInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, co
hmd_transform.basis = orientation;
hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0);
- transform_for_eye = p_cam_transform * (arvr_server->get_reference_frame()) * hmd_transform * transform_for_eye;
+ transform_for_eye = p_cam_transform * (xr_server->get_reference_frame()) * hmd_transform * transform_for_eye;
} else {
// huh? well just return what we got....
transform_for_eye = p_cam_transform;
@@ -382,12 +383,12 @@ Transform MobileVRInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, co
return transform_for_eye;
};
-CameraMatrix MobileVRInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+CameraMatrix MobileVRInterface::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
_THREAD_SAFE_METHOD_
CameraMatrix eye;
- if (p_eye == ARVRInterface::EYE_MONO) {
+ 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
// 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
@@ -395,13 +396,13 @@ CameraMatrix MobileVRInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye
// This will make more sense when we implement ARkit on iOS (probably a separate interface).
eye.set_perspective(60.0, p_aspect, p_z_near, p_z_far, false);
} else {
- eye.set_for_hmd(p_eye == ARVRInterface::EYE_LEFT ? 1 : 2, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far);
+ eye.set_for_hmd(p_eye == XRInterface::EYE_LEFT ? 1 : 2, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far);
};
return eye;
};
-void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+void MobileVRInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
_THREAD_SAFE_METHOD_
// We must have a valid render target
@@ -416,9 +417,9 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t
// we output half a screen
dest.size.x *= 0.5;
- if (p_eye == ARVRInterface::EYE_LEFT) {
+ if (p_eye == XRInterface::EYE_LEFT) {
eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0);
- } else if (p_eye == ARVRInterface::EYE_RIGHT) {
+ } else if (p_eye == XRInterface::EYE_RIGHT) {
dest.position.x = dest.size.x;
eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0);
}
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index c762c9b799..3a9ed1314a 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -31,8 +31,8 @@
#ifndef MOBILE_VR_INTERFACE_H
#define MOBILE_VR_INTERFACE_H
-#include "servers/arvr/arvr_interface.h"
-#include "servers/arvr/arvr_positional_tracker.h"
+#include "servers/xr/xr_interface.h"
+#include "servers/xr/xr_positional_tracker.h"
/**
@author Bastiaan Olij <mux213@gmail.com>
@@ -47,8 +47,8 @@
more advanced interfaces.
*/
-class MobileVRInterface : public ARVRInterface {
- GDCLASS(MobileVRInterface, ARVRInterface);
+class MobileVRInterface : public XRInterface {
+ GDCLASS(MobileVRInterface, XRInterface);
private:
bool initialized;
@@ -137,9 +137,9 @@ public:
virtual Size2 get_render_targetsize();
virtual bool is_stereo();
- virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
- virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
- virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
+ virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform);
+ virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+ virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
virtual void process();
virtual void notification(int p_what);
diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp
index faf6c3b151..75638d47c4 100644
--- a/modules/mobile_vr/register_types.cpp
+++ b/modules/mobile_vr/register_types.cpp
@@ -37,7 +37,7 @@ void register_mobile_vr_types() {
Ref<MobileVRInterface> mobile_vr;
mobile_vr.instance();
- ARVRServer::get_singleton()->add_interface(mobile_vr);
+ XRServer::get_singleton()->add_interface(mobile_vr);
}
void unregister_mobile_vr_types() {
diff --git a/modules/mobile_vr/register_types.h b/modules/mobile_vr/register_types.h
index 602fae1f4e..33f608b6ed 100644
--- a/modules/mobile_vr/register_types.h
+++ b/modules/mobile_vr/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef MOBILE_VR_REGISTER_TYPES_H
+#define MOBILE_VR_REGISTER_TYPES_H
+
void register_mobile_vr_types();
void unregister_mobile_vr_types();
+
+#endif // MOBILE_VR_REGISTER_TYPES_H
diff --git a/modules/modules_builders.py b/modules/modules_builders.py
index 0e9cba2b0b..e7be6380d1 100644
--- a/modules/modules_builders.py
+++ b/modules/modules_builders.py
@@ -7,10 +7,10 @@ from platform_methods import subprocess_main
def generate_modules_enabled(target, source, env):
- with open(target[0].path, 'w') as f:
+ with open(target[0].path, "w") as f:
for module in env.module_list:
- f.write('#define %s\n' % ("MODULE_" + module.upper() + "_ENABLED"))
+ f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED"))
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index 41be367f2f..c723b210cb 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -1,54 +1,57 @@
#!/usr/bin/env python
-import build_scripts.tls_configure as tls_configure
import build_scripts.mono_configure as mono_configure
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_mono = env_modules.Clone()
-if env_mono['tools']:
+if env_mono["tools"]:
# NOTE: It is safe to generate this file here, since this is still executed serially
import build_scripts.gen_cs_glue_version as gen_cs_glue_version
- gen_cs_glue_version.generate_header('glue/GodotSharp', 'glue/cs_glue_version.gen.h')
+
+ gen_cs_glue_version.generate_header("glue/GodotSharp", "glue/cs_glue_version.gen.h")
# Glue sources
-if env_mono['mono_glue']:
- env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
+if env_mono["mono_glue"]:
+ env_mono.Append(CPPDEFINES=["MONO_GLUE_ENABLED"])
import os.path
- if not os.path.isfile('glue/mono_glue.gen.cpp'):
- raise RuntimeError("Mono glue sources not found. Did you forget to run '--generate-mono-glue'?")
-if env_mono['tools'] or env_mono['target'] != 'release':
- env_mono.Append(CPPDEFINES=['GD_MONO_HOT_RELOAD'])
-
-# Configure Thread Local Storage
+ if not os.path.isfile("glue/mono_glue.gen.cpp"):
+ raise RuntimeError("Mono glue sources not found. Did you forget to run '--generate-mono-glue'?")
-conf = Configure(env_mono)
-tls_configure.configure(conf)
-env_mono = conf.Finish()
+if env_mono["tools"] or env_mono["target"] != "release":
+ env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
# Configure Mono
mono_configure.configure(env, env_mono)
-if env_mono['tools'] and env_mono['mono_glue']:
+if env_mono["tools"] and env_mono["mono_glue"]:
# Build Godot API solution
import build_scripts.api_solution_build as api_solution_build
+
api_sln_cmd = api_solution_build.build(env_mono)
# Build GodotTools
import build_scripts.godot_tools_build as godot_tools_build
+
godot_tools_build.build(env_mono, api_sln_cmd)
# Add sources
-env_mono.add_source_files(env.modules_sources, '*.cpp')
-env_mono.add_source_files(env.modules_sources, 'glue/*.cpp')
-env_mono.add_source_files(env.modules_sources, 'mono_gd/*.cpp')
-env_mono.add_source_files(env.modules_sources, 'utils/*.cpp')
+env_mono.add_source_files(env.modules_sources, "*.cpp")
+env_mono.add_source_files(env.modules_sources, "glue/*.cpp")
+env_mono.add_source_files(env.modules_sources, "mono_gd/*.cpp")
+env_mono.add_source_files(env.modules_sources, "utils/*.cpp")
+
+env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.cpp")
+
+if env["platform"] in ["osx", "iphone"]:
+ env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.mm")
+ env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.m")
-if env['tools']:
- env_mono.add_source_files(env.modules_sources, 'editor/*.cpp')
+if env["tools"]:
+ env_mono.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/mono/build_scripts/api_solution_build.py b/modules/mono/build_scripts/api_solution_build.py
index 639197c285..9abac22df6 100644
--- a/modules/mono/build_scripts/api_solution_build.py
+++ b/modules/mono/build_scripts/api_solution_build.py
@@ -8,21 +8,22 @@ from SCons.Script import Dir
def build_api_solution(source, target, env):
# source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
- module_dir = env['module_dir']
+ module_dir = env["module_dir"]
- solution_path = os.path.join(module_dir, 'glue/GodotSharp/GodotSharp.sln')
+ solution_path = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
- build_config = env['solution_build_config']
+ build_config = env["solution_build_config"]
- extra_msbuild_args = ['/p:NoWarn=1591'] # Ignore missing documentation warnings
+ extra_msbuild_args = ["/p:NoWarn=1591"] # Ignore missing documentation warnings
from .solution_builder import build_solution
+
build_solution(env, solution_path, build_config, extra_msbuild_args=extra_msbuild_args)
# Copy targets
- core_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, 'GodotSharp', 'bin', build_config))
- editor_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, 'GodotSharpEditor', 'bin', build_config))
+ core_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharp", "bin", build_config))
+ editor_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharpEditor", "bin", build_config))
dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
@@ -32,6 +33,7 @@ def build_api_solution(source, target, env):
def copy_target(target_path):
from shutil import copy
+
filename = os.path.basename(target_path)
src_path = os.path.join(core_src_dir, filename)
@@ -45,23 +47,28 @@ def build_api_solution(source, target, env):
def build(env_mono):
- assert env_mono['tools']
+ assert env_mono["tools"]
target_filenames = [
- 'GodotSharp.dll', 'GodotSharp.pdb', 'GodotSharp.xml',
- 'GodotSharpEditor.dll', 'GodotSharpEditor.pdb', 'GodotSharpEditor.xml'
+ "GodotSharp.dll",
+ "GodotSharp.pdb",
+ "GodotSharp.xml",
+ "GodotSharpEditor.dll",
+ "GodotSharpEditor.pdb",
+ "GodotSharpEditor.xml",
]
depend_cmd = []
- for build_config in ['Debug', 'Release']:
- output_dir = Dir('#bin').abspath
- editor_api_dir = os.path.join(output_dir, 'GodotSharp', 'Api', build_config)
+ for build_config in ["Debug", "Release"]:
+ output_dir = Dir("#bin").abspath
+ editor_api_dir = os.path.join(output_dir, "GodotSharp", "Api", build_config)
targets = [os.path.join(editor_api_dir, filename) for filename in target_filenames]
- cmd = env_mono.CommandNoCache(targets, depend_cmd, build_api_solution,
- module_dir=os.getcwd(), solution_build_config=build_config)
+ cmd = env_mono.CommandNoCache(
+ targets, depend_cmd, build_api_solution, module_dir=os.getcwd(), solution_build_config=build_config
+ )
env_mono.AlwaysBuild(cmd)
# Make the Release build of the API solution depend on the Debug build.
diff --git a/modules/mono/build_scripts/gen_cs_glue_version.py b/modules/mono/build_scripts/gen_cs_glue_version.py
index 5d1056c2fc..98bbb4d9be 100644
--- a/modules/mono/build_scripts/gen_cs_glue_version.py
+++ b/modules/mono/build_scripts/gen_cs_glue_version.py
@@ -1,20 +1,20 @@
-
def generate_header(solution_dir, version_header_dst):
import os
+
latest_mtime = 0
for root, dirs, files in os.walk(solution_dir, topdown=True):
- dirs[:] = [d for d in dirs if d not in ['Generated']] # Ignored generated files
- files = [f for f in files if f.endswith('.cs')]
+ dirs[:] = [d for d in dirs if d not in ["Generated"]] # Ignored generated files
+ files = [f for f in files if f.endswith(".cs")]
for file in files:
filepath = os.path.join(root, file)
mtime = os.path.getmtime(filepath)
latest_mtime = mtime if mtime > latest_mtime else latest_mtime
- glue_version = int(latest_mtime) # The latest modified time will do for now
+ glue_version = int(latest_mtime) # The latest modified time will do for now
- with open(version_header_dst, 'w') as version_header:
- version_header.write('/* THIS FILE IS GENERATED DO NOT EDIT */\n')
- version_header.write('#ifndef CS_GLUE_VERSION_H\n')
- version_header.write('#define CS_GLUE_VERSION_H\n\n')
- version_header.write('#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
- version_header.write('\n#endif // CS_GLUE_VERSION_H\n')
+ with open(version_header_dst, "w") as version_header:
+ version_header.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ version_header.write("#ifndef CS_GLUE_VERSION_H\n")
+ version_header.write("#define CS_GLUE_VERSION_H\n\n")
+ version_header.write("#define CS_GLUE_VERSION UINT32_C(" + str(glue_version) + ")\n")
+ version_header.write("\n#endif // CS_GLUE_VERSION_H\n")
diff --git a/modules/mono/build_scripts/godot_tools_build.py b/modules/mono/build_scripts/godot_tools_build.py
index 99341c631e..cffacf2577 100644
--- a/modules/mono/build_scripts/godot_tools_build.py
+++ b/modules/mono/build_scripts/godot_tools_build.py
@@ -8,30 +8,31 @@ from SCons.Script import Dir
def build_godot_tools(source, target, env):
# source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
- module_dir = env['module_dir']
+ module_dir = env["module_dir"]
- solution_path = os.path.join(module_dir, 'editor/GodotTools/GodotTools.sln')
- build_config = 'Debug' if env['target'] == 'debug' else 'Release'
+ solution_path = os.path.join(module_dir, "editor/GodotTools/GodotTools.sln")
+ build_config = "Debug" if env["target"] == "debug" else "Release"
# Custom build target to make sure output is always copied to the data dir.
- extra_build_args = ['/Target:Build;GodotTools:BuildAlwaysCopyToDataDir']
+ extra_build_args = ["/Target:Build;GodotTools:BuildAlwaysCopyToDataDir"]
+
+ from .solution_builder import build_solution, nuget_restore
- from . solution_builder import build_solution, nuget_restore
nuget_restore(env, solution_path)
build_solution(env, solution_path, build_config, extra_build_args)
# No need to copy targets. The GodotTools csproj takes care of copying them.
def build(env_mono, api_sln_cmd):
- assert env_mono['tools']
+ assert env_mono["tools"]
- output_dir = Dir('#bin').abspath
- editor_tools_dir = os.path.join(output_dir, 'GodotSharp', 'Tools')
+ output_dir = Dir("#bin").abspath
+ editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools")
- target_filenames = ['GodotTools.dll']
+ target_filenames = ["GodotTools.dll"]
- if env_mono['target'] == 'debug':
- target_filenames += ['GodotTools.pdb']
+ if env_mono["target"] == "debug":
+ target_filenames += ["GodotTools.pdb"]
targets = [os.path.join(editor_tools_dir, filename) for filename in target_filenames]
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
index 0afd939c57..d276d7d886 100644
--- a/modules/mono/build_scripts/make_android_mono_config.py
+++ b/modules/mono/build_scripts/make_android_mono_config.py
@@ -1,24 +1,24 @@
-
def generate_compressed_config(config_src, output_dir):
import os.path
- from compat import byte_to_str
# Source file
- with open(os.path.join(output_dir, 'android_mono_config.gen.cpp'), 'w') as cpp:
- with open(config_src, 'rb') as f:
+ with open(os.path.join(output_dir, "android_mono_config.gen.cpp"), "w") as cpp:
+ with open(config_src, "rb") as f:
buf = f.read()
decompr_size = len(buf)
import zlib
+
buf = zlib.compress(buf)
compr_size = len(buf)
- bytes_seq_str = ''
+ bytes_seq_str = ""
for i, buf_idx in enumerate(range(compr_size)):
if i > 0:
- bytes_seq_str += ', '
- bytes_seq_str += byte_to_str(buf[buf_idx])
+ bytes_seq_str += ", "
+ bytes_seq_str += str(buf[buf_idx])
- cpp.write('''/* THIS FILE IS GENERATED DO NOT EDIT */
+ cpp.write(
+ """/* THIS FILE IS GENERATED DO NOT EDIT */
#include "android_mono_config.h"
#ifdef ANDROID_ENABLED
@@ -49,4 +49,6 @@ String get_godot_android_mono_config() {
}
#endif // ANDROID_ENABLED
-''' % (compr_size, decompr_size, bytes_seq_str))
+"""
+ % (compr_size, decompr_size, bytes_seq_str)
+ )
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index 9a6198f13a..23f01b3cca 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -5,178 +5,230 @@ import subprocess
from SCons.Script import Dir, Environment
-if os.name == 'nt':
+if os.name == "nt":
from . import mono_reg_utils as monoreg
android_arch_dirs = {
- 'armv7': 'armeabi-v7a',
- 'arm64v8': 'arm64-v8a',
- 'x86': 'x86',
- 'x86_64': 'x86_64'
+ "armv7": "armeabi-v7a",
+ "arm64v8": "arm64-v8a",
+ "x86": "x86",
+ "x86_64": "x86_64",
}
def get_android_out_dir(env):
- return os.path.join(Dir('#platform/android/java/lib/libs').abspath,
- 'release' if env['target'] == 'release' else 'debug',
- android_arch_dirs[env['android_arch']])
-
-
-def find_file_in_dir(directory, files, prefix='', extension=''):
- if not extension.startswith('.'):
- extension = '.' + extension
- for curfile in files:
- if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
- return curfile
- return ''
-
-
-def copy_file(src_dir, dst_dir, name):
+ return os.path.join(
+ Dir("#platform/android/java/lib/libs").abspath,
+ "release" if env["target"] == "release" else "debug",
+ android_arch_dirs[env["android_arch"]],
+ )
+
+
+def find_name_in_dir_files(directory, names, prefixes=[""], extensions=[""]):
+ for extension in extensions:
+ if extension and not extension.startswith("."):
+ extension = "." + extension
+ for prefix in prefixes:
+ for curname in names:
+ if os.path.isfile(os.path.join(directory, prefix + curname + extension)):
+ return curname
+ return ""
+
+
+def find_file_in_dir(directory, names, prefixes=[""], extensions=[""]):
+ for extension in extensions:
+ if extension and not extension.startswith("."):
+ extension = "." + extension
+ for prefix in prefixes:
+ for curname in names:
+ filename = prefix + curname + extension
+ if os.path.isfile(os.path.join(directory, filename)):
+ return filename
+ return ""
+
+
+def copy_file(src_dir, dst_dir, src_name, dst_name=""):
from shutil import copy
- src_path = os.path.join(Dir(src_dir).abspath, name)
+ src_path = os.path.join(Dir(src_dir).abspath, src_name)
dst_dir = Dir(dst_dir).abspath
if not os.path.isdir(dst_dir):
os.makedirs(dst_dir)
- copy(src_path, dst_dir)
+ if dst_name:
+ copy(src_path, os.path.join(dst_dir, dst_name))
+ else:
+ copy(src_path, dst_dir)
def is_desktop(platform):
- return platform in ['windows', 'osx', 'x11', 'server', 'uwp', 'haiku']
+ return platform in ["windows", "osx", "linuxbsd", "server", "uwp", "haiku"]
def is_unix_like(platform):
- return platform in ['osx', 'x11', 'server', 'android', 'haiku']
+ return platform in ["osx", "linuxbsd", "server", "android", "haiku", "iphone"]
def module_supports_tools_on(platform):
- return platform not in ['android', 'javascript']
+ return platform not in ["android", "javascript", "iphone"]
def find_wasm_src_dir(mono_root):
hint_dirs = [
- os.path.join(mono_root, 'src'),
- os.path.join(mono_root, '../src'),
+ os.path.join(mono_root, "src"),
+ os.path.join(mono_root, "../src"),
]
for hint_dir in hint_dirs:
- if os.path.isfile(os.path.join(hint_dir, 'driver.c')):
+ if os.path.isfile(os.path.join(hint_dir, "driver.c")):
return hint_dir
- return ''
+ return ""
def configure(env, env_mono):
- bits = env['bits']
- is_android = env['platform'] == 'android'
- is_javascript = env['platform'] == 'javascript'
+ bits = env["bits"]
+ is_android = env["platform"] == "android"
+ is_javascript = env["platform"] == "javascript"
+ is_ios = env["platform"] == "iphone"
+ is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"]
- tools_enabled = env['tools']
- mono_static = env['mono_static']
- copy_mono_root = env['copy_mono_root']
+ tools_enabled = env["tools"]
+ mono_static = env["mono_static"]
+ copy_mono_root = env["copy_mono_root"]
- mono_prefix = env['mono_prefix']
+ mono_prefix = env["mono_prefix"]
- mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
+ mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"]
- is_travis = os.environ.get('TRAVIS') == 'true'
+ is_travis = os.environ.get("TRAVIS") == "true"
if is_travis:
# Travis CI may have a Mono version lower than 5.12
- env_mono.Append(CPPDEFINES=['NO_PENDING_EXCEPTIONS'])
+ env_mono.Append(CPPDEFINES=["NO_PENDING_EXCEPTIONS"])
- if is_android and not env['android_arch'] in android_arch_dirs:
- raise RuntimeError('This module does not support the specified \'android_arch\': ' + env['android_arch'])
+ if is_android and not env["android_arch"] in android_arch_dirs:
+ raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"])
- if tools_enabled and not module_supports_tools_on(env['platform']):
+ if tools_enabled and not module_supports_tools_on(env["platform"]):
# TODO:
# Android: We have to add the data directory to the apk, concretely the Api and Tools folders.
- raise RuntimeError('This module does not currently support building for this platform with tools enabled')
+ raise RuntimeError("This module does not currently support building for this platform with tools enabled")
if is_android and mono_static:
- # Android: When static linking and doing something that requires libmono-native, we get a dlopen error as libmono-native seems to depend on libmonosgen-2.0
- raise RuntimeError('Statically linking Mono is not currently supported on this platform')
+ # FIXME: When static linking and doing something that requires libmono-native, we get a dlopen error as 'libmono-native'
+ # seems to depend on 'libmonosgen-2.0'. Could be fixed by re-directing to '__Internal' with a dllmap or in the dlopen hook.
+ raise RuntimeError("Statically linking Mono is not currently supported for this platform")
+
+ if not mono_static and (is_javascript or is_ios):
+ raise RuntimeError("Dynamically linking Mono is not currently supported for this platform")
+
+ if not mono_prefix and (os.getenv("MONO32_PREFIX") or os.getenv("MONO64_PREFIX")):
+ print(
+ "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead"
+ )
+
+ # Although we don't support building with tools for any platform where we currently use static AOT,
+ # if these are supported in the future, we won't be using static AOT for them as that would be
+ # too restrictive for the editor. These builds would probably be made to only use the interpreter.
+ mono_aot_static = (is_ios and not is_ios_sim) and not env["tools"]
- if is_javascript:
- mono_static = True
+ # Static AOT is only supported on the root domain
+ mono_single_appdomain = mono_aot_static
- if not mono_prefix and (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')):
- print("WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead")
+ if mono_single_appdomain:
+ env_mono.Append(CPPDEFINES=["GD_MONO_SINGLE_APPDOMAIN"])
- if env['platform'] == 'windows':
+ if (env["tools"] or env["target"] != "release") and not mono_single_appdomain:
+ env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
+
+ if env["platform"] == "windows":
mono_root = mono_prefix
- if not mono_root and os.name == 'nt':
+ if not mono_root and os.name == "nt":
mono_root = monoreg.find_mono_root_dir(bits)
if not mono_root:
- raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter")
+ raise RuntimeError(
+ "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter"
+ )
- print('Found Mono root directory: ' + mono_root)
+ print("Found Mono root directory: " + mono_root)
- mono_lib_path = os.path.join(mono_root, 'lib')
+ mono_lib_path = os.path.join(mono_root, "lib")
env.Append(LIBPATH=mono_lib_path)
- env_mono.Prepend(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
+ env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0"))
+
+ lib_suffixes = [".lib"]
- lib_suffix = Environment()['LIBSUFFIX']
+ if not env.msvc:
+ # MingW supports both '.a' and '.lib'
+ lib_suffixes.insert(0, ".a")
if mono_static:
if env.msvc:
- mono_static_lib_name = 'libmono-static-sgen'
+ mono_static_lib_name = "libmono-static-sgen"
else:
- mono_static_lib_name = 'libmonosgen-2.0'
+ mono_static_lib_name = "libmonosgen-2.0"
- if not os.path.isfile(os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix)):
- raise RuntimeError('Could not find static mono library in: ' + mono_lib_path)
+ mono_static_lib_file = find_file_in_dir(mono_lib_path, [mono_static_lib_name], extensions=lib_suffixes)
+
+ if not mono_static_lib_file:
+ raise RuntimeError("Could not find static mono library in: " + mono_lib_path)
if env.msvc:
- env.Append(LINKFLAGS=mono_static_lib_name + lib_suffix)
+ env.Append(LINKFLAGS=mono_static_lib_file)
- env.Append(LINKFLAGS='Mincore' + lib_suffix)
- env.Append(LINKFLAGS='msvcrt' + lib_suffix)
- env.Append(LINKFLAGS='LIBCMT' + lib_suffix)
- env.Append(LINKFLAGS='Psapi' + lib_suffix)
+ env.Append(LINKFLAGS="Mincore.lib")
+ env.Append(LINKFLAGS="msvcrt.lib")
+ env.Append(LINKFLAGS="LIBCMT.lib")
+ env.Append(LINKFLAGS="Psapi.lib")
else:
- env.Append(LINKFLAGS=os.path.join(mono_lib_path, mono_static_lib_name + lib_suffix))
+ mono_static_lib_file_path = os.path.join(mono_lib_path, mono_static_lib_file)
+ env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_static_lib_file_path, "-Wl,-no-whole-archive"])
- env.Append(LIBS=['psapi'])
- env.Append(LIBS=['version'])
+ env.Append(LIBS=["psapi"])
+ env.Append(LIBS=["version"])
else:
- mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension=lib_suffix)
+ mono_lib_name = find_name_in_dir_files(
+ mono_lib_path, mono_lib_names, prefixes=["", "lib"], extensions=lib_suffixes
+ )
if not mono_lib_name:
- raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
+ raise RuntimeError("Could not find mono library in: " + mono_lib_path)
if env.msvc:
- env.Append(LINKFLAGS=mono_lib_name + lib_suffix)
+ env.Append(LINKFLAGS=mono_lib_name + ".lib")
else:
env.Append(LIBS=[mono_lib_name])
- mono_bin_path = os.path.join(mono_root, 'bin')
+ mono_bin_path = os.path.join(mono_root, "bin")
- mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
+ mono_dll_file = find_file_in_dir(mono_bin_path, mono_lib_names, prefixes=["", "lib"], extensions=[".dll"])
- if not mono_dll_name:
- raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
+ if not mono_dll_file:
+ raise RuntimeError("Could not find mono shared library in: " + mono_bin_path)
- copy_file(mono_bin_path, '#bin', mono_dll_name + '.dll')
+ copy_file(mono_bin_path, "#bin", mono_dll_file)
else:
- is_apple = env['platform'] in ['osx', 'iphone']
+ is_apple = env["platform"] in ["osx", "iphone"]
+ is_macos = is_apple and not is_ios
- sharedlib_ext = '.dylib' if is_apple else '.so'
+ sharedlib_ext = ".dylib" if is_apple else ".so"
mono_root = mono_prefix
- mono_lib_path = ''
- mono_so_name = ''
+ mono_lib_path = ""
+ mono_so_file = ""
- if not mono_root and (is_android or is_javascript):
- raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter")
+ if not mono_root and (is_android or is_javascript or is_ios):
+ raise RuntimeError(
+ "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter"
+ )
- if not mono_root and is_apple:
+ if not mono_root and is_macos:
# Try with some known directories under OSX
- hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current', '/usr/local/var/homebrew/linked/mono']
+ hint_dirs = ["/Library/Frameworks/Mono.framework/Versions/Current", "/usr/local/var/homebrew/linked/mono"]
for hint_dir in hint_dirs:
if os.path.isdir(hint_dir):
mono_root = hint_dir
@@ -187,126 +239,165 @@ def configure(env, env_mono):
if not mono_root and mono_static:
mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
if not mono_root:
- raise RuntimeError("Building with mono_static=yes, but failed to find the mono prefix with pkg-config; " + \
- "specify one manually with the 'mono_prefix' SCons parameter")
+ raise RuntimeError(
+ "Building with mono_static=yes, but failed to find the mono prefix with pkg-config; "
+ + "specify one manually with the 'mono_prefix' SCons parameter"
+ )
+
+ if is_ios and not is_ios_sim:
+ env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
if mono_root:
- print('Found Mono root directory: ' + mono_root)
+ print("Found Mono root directory: " + mono_root)
- mono_lib_path = os.path.join(mono_root, 'lib')
+ mono_lib_path = os.path.join(mono_root, "lib")
env.Append(LIBPATH=[mono_lib_path])
- env_mono.Prepend(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
+ env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0"))
- mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
+ mono_lib = find_name_in_dir_files(mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[".a"])
if not mono_lib:
- raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
+ raise RuntimeError("Could not find mono library in: " + mono_lib_path)
- env_mono.Append(CPPDEFINES=['_REENTRANT'])
+ env_mono.Append(CPPDEFINES=["_REENTRANT"])
if mono_static:
- env.Append(LINKFLAGS=['-rdynamic'])
+ env.Append(LINKFLAGS=["-rdynamic"])
- mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
+ mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a")
if is_apple:
- env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
+ if is_macos:
+ env.Append(LINKFLAGS=["-Wl,-force_load," + mono_lib_file])
+ else:
+ arch = env["arch"]
+
+ def copy_mono_lib(libname_wo_ext):
+ copy_file(
+ mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.iphone.%s.a" % (libname_wo_ext, arch)
+ )
+
+ # Copy Mono libraries to the output folder. These are meant to be bundled with
+ # the export templates and added to the Xcode project when exporting a game.
+ copy_mono_lib("lib" + mono_lib)
+ copy_mono_lib("libmono-native")
+ copy_mono_lib("libmono-profiler-log")
+
+ if not is_ios_sim:
+ copy_mono_lib("libmono-ee-interp")
+ copy_mono_lib("libmono-icall-table")
+ copy_mono_lib("libmono-ilgen")
else:
- assert is_desktop(env['platform']) or is_android or is_javascript
- env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
+ assert is_desktop(env["platform"]) or is_android or is_javascript
+ env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_lib_file, "-Wl,-no-whole-archive"])
if is_javascript:
- env.Append(LIBS=['mono-icall-table', 'mono-native', 'mono-ilgen', 'mono-ee-interp'])
+ env.Append(LIBS=["mono-icall-table", "mono-native", "mono-ilgen", "mono-ee-interp"])
- wasm_src_dir = os.path.join(mono_root, 'src')
+ wasm_src_dir = os.path.join(mono_root, "src")
if not os.path.isdir(wasm_src_dir):
- raise RuntimeError('Could not find mono wasm src directory')
+ raise RuntimeError("Could not find mono wasm src directory")
# Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours
- env_mono.Append(CPPDEFINES=['CORE_BINDINGS'])
-
- env_mono.add_source_files(env.modules_sources, [
- os.path.join(wasm_src_dir, 'driver.c'),
- os.path.join(wasm_src_dir, 'zlib-helper.c'),
- os.path.join(wasm_src_dir, 'corebindings.c')
- ])
-
- env.Append(LINKFLAGS=[
- '--js-library', os.path.join(wasm_src_dir, 'library_mono.js'),
- '--js-library', os.path.join(wasm_src_dir, 'binding_support.js'),
- '--js-library', os.path.join(wasm_src_dir, 'dotnet_support.js')
- ])
+ env_mono.Append(CPPDEFINES=["CORE_BINDINGS"])
+
+ env_mono.add_source_files(
+ env.modules_sources,
+ [
+ os.path.join(wasm_src_dir, "driver.c"),
+ os.path.join(wasm_src_dir, "zlib-helper.c"),
+ os.path.join(wasm_src_dir, "corebindings.c"),
+ ],
+ )
+
+ env.Append(
+ LINKFLAGS=[
+ "--js-library",
+ os.path.join(wasm_src_dir, "library_mono.js"),
+ "--js-library",
+ os.path.join(wasm_src_dir, "binding_support.js"),
+ "--js-library",
+ os.path.join(wasm_src_dir, "dotnet_support.js"),
+ ]
+ )
else:
env.Append(LIBS=[mono_lib])
- if is_apple:
- env.Append(LIBS=['iconv', 'pthread'])
+ if is_macos:
+ env.Append(LIBS=["iconv", "pthread"])
elif is_android:
- pass # Nothing
+ pass # Nothing
+ elif is_ios:
+ pass # Nothing, linking is delegated to the exported Xcode project
elif is_javascript:
- env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
+ env.Append(LIBS=["m", "rt", "dl", "pthread"])
else:
- env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
+ env.Append(LIBS=["m", "rt", "dl", "pthread"])
if not mono_static:
- mono_so_name = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+ mono_so_file = find_file_in_dir(
+ mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]
+ )
- if not mono_so_name:
- raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
-
- copy_file(mono_lib_path, '#bin', 'lib' + mono_so_name + sharedlib_ext)
+ if not mono_so_file:
+ raise RuntimeError("Could not find mono shared library in: " + mono_lib_path)
else:
assert not mono_static
# TODO: Add option to force using pkg-config
- print('Mono root directory not found. Using pkg-config instead')
+ print("Mono root directory not found. Using pkg-config instead")
- env.ParseConfig('pkg-config monosgen-2 --libs')
- env_mono.ParseConfig('pkg-config monosgen-2 --cflags')
+ env.ParseConfig("pkg-config monosgen-2 --libs")
+ env_mono.ParseConfig("pkg-config monosgen-2 --cflags")
tmpenv = Environment()
- tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
- tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
+ tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
+ tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L")
- for hint_dir in tmpenv['LIBPATH']:
- name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
- if name_found:
+ for hint_dir in tmpenv["LIBPATH"]:
+ file_found = find_file_in_dir(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext])
+ if file_found:
mono_lib_path = hint_dir
- mono_so_name = name_found
+ mono_so_file = file_found
break
- if not mono_so_name:
- raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
+ if not mono_so_file:
+ raise RuntimeError("Could not find mono shared library in: " + str(tmpenv["LIBPATH"]))
if not mono_static:
- libs_output_dir = get_android_out_dir(env) if is_android else '#bin'
- copy_file(mono_lib_path, libs_output_dir, 'lib' + mono_so_name + sharedlib_ext)
+ libs_output_dir = get_android_out_dir(env) if is_android else "#bin"
+ copy_file(mono_lib_path, libs_output_dir, mono_so_file)
if not tools_enabled:
- if is_desktop(env['platform']):
+ if is_desktop(env["platform"]):
if not mono_root:
- mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
+ mono_root = (
+ subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip()
+ )
make_template_dir(env, mono_root)
elif is_android:
# Compress Android Mono Config
from . import make_android_mono_config
+
module_dir = os.getcwd()
- config_file_path = os.path.join(module_dir, 'build_scripts', 'mono_android_config.xml')
- make_android_mono_config.generate_compressed_config(config_file_path, 'mono_gd/')
+ config_file_path = os.path.join(module_dir, "build_scripts", "mono_android_config.xml")
+ make_android_mono_config.generate_compressed_config(config_file_path, "mono_gd/")
# Copy the required shared libraries
copy_mono_shared_libs(env, mono_root, None)
elif is_javascript:
- pass # No data directory for this platform
+ pass # No data directory for this platform
+ elif is_ios:
+ pass # No data directory for this platform
if copy_mono_root:
if not mono_root:
- mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
+ mono_root = subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip()
if tools_enabled:
- copy_mono_root_files(env, mono_root)
+ copy_mono_root_files(env, mono_root)
else:
print("Ignoring option: 'copy_mono_root'; only available for builds with 'tools' enabled.")
@@ -314,26 +405,26 @@ def configure(env, env_mono):
def make_template_dir(env, mono_root):
from shutil import rmtree
- platform = env['platform']
- target = env['target']
+ platform = env["platform"]
+ target = env["target"]
- template_dir_name = ''
+ template_dir_name = ""
assert is_desktop(platform)
- template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
+ template_dir_name = "data.mono.%s.%s.%s" % (platform, env["bits"], target)
- output_dir = Dir('#bin').abspath
+ output_dir = Dir("#bin").abspath
template_dir = os.path.join(output_dir, template_dir_name)
- template_mono_root_dir = os.path.join(template_dir, 'Mono')
+ template_mono_root_dir = os.path.join(template_dir, "Mono")
if os.path.isdir(template_mono_root_dir):
- rmtree(template_mono_root_dir) # Clean first
+ rmtree(template_mono_root_dir) # Clean first
# Copy etc/mono/
- template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
+ template_mono_config_dir = os.path.join(template_mono_root_dir, "etc", "mono")
copy_mono_etc_dir(mono_root, template_mono_config_dir, platform)
# Copy the required shared libraries
@@ -347,18 +438,18 @@ def copy_mono_root_files(env, mono_root):
from shutil import rmtree
if not mono_root:
- raise RuntimeError('Mono installation directory not found')
+ raise RuntimeError("Mono installation directory not found")
- output_dir = Dir('#bin').abspath
- editor_mono_root_dir = os.path.join(output_dir, 'GodotSharp', 'Mono')
+ output_dir = Dir("#bin").abspath
+ editor_mono_root_dir = os.path.join(output_dir, "GodotSharp", "Mono")
if os.path.isdir(editor_mono_root_dir):
- rmtree(editor_mono_root_dir) # Clean first
+ rmtree(editor_mono_root_dir) # Clean first
# Copy etc/mono/
- editor_mono_config_dir = os.path.join(editor_mono_root_dir, 'etc', 'mono')
- copy_mono_etc_dir(mono_root, editor_mono_config_dir, env['platform'])
+ editor_mono_config_dir = os.path.join(editor_mono_root_dir, "etc", "mono")
+ copy_mono_etc_dir(mono_root, editor_mono_config_dir, env["platform"])
# Copy the required shared libraries
@@ -366,20 +457,20 @@ def copy_mono_root_files(env, mono_root):
# Copy framework assemblies
- mono_framework_dir = os.path.join(mono_root, 'lib', 'mono', '4.5')
- mono_framework_facades_dir = os.path.join(mono_framework_dir, 'Facades')
+ mono_framework_dir = os.path.join(mono_root, "lib", "mono", "4.5")
+ mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades")
- editor_mono_framework_dir = os.path.join(editor_mono_root_dir, 'lib', 'mono', '4.5')
- editor_mono_framework_facades_dir = os.path.join(editor_mono_framework_dir, 'Facades')
+ editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5")
+ editor_mono_framework_facades_dir = os.path.join(editor_mono_framework_dir, "Facades")
if not os.path.isdir(editor_mono_framework_dir):
os.makedirs(editor_mono_framework_dir)
if not os.path.isdir(editor_mono_framework_facades_dir):
os.makedirs(editor_mono_framework_facades_dir)
- for assembly in glob(os.path.join(mono_framework_dir, '*.dll')):
+ for assembly in glob(os.path.join(mono_framework_dir, "*.dll")):
copy(assembly, editor_mono_framework_dir)
- for assembly in glob(os.path.join(mono_framework_facades_dir, '*.dll')):
+ for assembly in glob(os.path.join(mono_framework_facades_dir, "*.dll")):
copy(assembly, editor_mono_framework_facades_dir)
@@ -391,28 +482,28 @@ def copy_mono_etc_dir(mono_root, target_mono_config_dir, platform):
if not os.path.isdir(target_mono_config_dir):
os.makedirs(target_mono_config_dir)
- mono_etc_dir = os.path.join(mono_root, 'etc', 'mono')
+ mono_etc_dir = os.path.join(mono_root, "etc", "mono")
if not os.path.isdir(mono_etc_dir):
- mono_etc_dir = ''
+ mono_etc_dir = ""
etc_hint_dirs = []
- if platform != 'windows':
- etc_hint_dirs += ['/etc/mono', '/usr/local/etc/mono']
- if 'MONO_CFG_DIR' in os.environ:
- etc_hint_dirs += [os.path.join(os.environ['MONO_CFG_DIR'], 'mono')]
+ if platform != "windows":
+ etc_hint_dirs += ["/etc/mono", "/usr/local/etc/mono"]
+ if "MONO_CFG_DIR" in os.environ:
+ etc_hint_dirs += [os.path.join(os.environ["MONO_CFG_DIR"], "mono")]
for etc_hint_dir in etc_hint_dirs:
if os.path.isdir(etc_hint_dir):
mono_etc_dir = etc_hint_dir
break
if not mono_etc_dir:
- raise RuntimeError('Mono installation etc directory not found')
+ raise RuntimeError("Mono installation etc directory not found")
- copy_tree(os.path.join(mono_etc_dir, '2.0'), os.path.join(target_mono_config_dir, '2.0'))
- copy_tree(os.path.join(mono_etc_dir, '4.0'), os.path.join(target_mono_config_dir, '4.0'))
- copy_tree(os.path.join(mono_etc_dir, '4.5'), os.path.join(target_mono_config_dir, '4.5'))
- if os.path.isdir(os.path.join(mono_etc_dir, 'mconfig')):
- copy_tree(os.path.join(mono_etc_dir, 'mconfig'), os.path.join(target_mono_config_dir, 'mconfig'))
+ copy_tree(os.path.join(mono_etc_dir, "2.0"), os.path.join(target_mono_config_dir, "2.0"))
+ copy_tree(os.path.join(mono_etc_dir, "4.0"), os.path.join(target_mono_config_dir, "4.0"))
+ copy_tree(os.path.join(mono_etc_dir, "4.5"), os.path.join(target_mono_config_dir, "4.5"))
+ if os.path.isdir(os.path.join(mono_etc_dir, "mconfig")):
+ copy_tree(os.path.join(mono_etc_dir, "mconfig"), os.path.join(target_mono_config_dir, "mconfig"))
- for file in glob(os.path.join(mono_etc_dir, '*')):
+ for file in glob(os.path.join(mono_etc_dir, "*")):
if os.path.isfile(file):
copy(file, target_mono_config_dir)
@@ -424,48 +515,66 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir):
if os.path.isfile(src):
copy(src, dst)
- platform = env['platform']
+ platform = env["platform"]
- if platform == 'windows':
- src_mono_bin_dir = os.path.join(mono_root, 'bin')
- target_mono_bin_dir = os.path.join(target_mono_root_dir, 'bin')
+ if platform == "windows":
+ src_mono_bin_dir = os.path.join(mono_root, "bin")
+ target_mono_bin_dir = os.path.join(target_mono_root_dir, "bin")
if not os.path.isdir(target_mono_bin_dir):
os.makedirs(target_mono_bin_dir)
- mono_posix_helper_name = find_file_in_dir(src_mono_bin_dir, ['MonoPosixHelper', 'libMonoPosixHelper'], extension='.dll')
- copy(os.path.join(src_mono_bin_dir, mono_posix_helper_name + '.dll'), os.path.join(target_mono_bin_dir, 'MonoPosixHelper.dll'))
+ mono_posix_helper_file = find_file_in_dir(
+ src_mono_bin_dir, ["MonoPosixHelper"], prefixes=["", "lib"], extensions=[".dll"]
+ )
+ copy(
+ os.path.join(src_mono_bin_dir, mono_posix_helper_file),
+ os.path.join(target_mono_bin_dir, "MonoPosixHelper.dll"),
+ )
# For newer versions
- btls_dll_path = os.path.join(src_mono_bin_dir, 'libmono-btls-shared.dll')
+ btls_dll_path = os.path.join(src_mono_bin_dir, "libmono-btls-shared.dll")
if os.path.isfile(btls_dll_path):
copy(btls_dll_path, target_mono_bin_dir)
else:
- target_mono_lib_dir = get_android_out_dir(env) if platform == 'android' else os.path.join(target_mono_root_dir, 'lib')
+ target_mono_lib_dir = (
+ get_android_out_dir(env) if platform == "android" else os.path.join(target_mono_root_dir, "lib")
+ )
if not os.path.isdir(target_mono_lib_dir):
os.makedirs(target_mono_lib_dir)
lib_file_names = []
- if platform == 'osx':
- lib_file_names = [lib_name + '.dylib' for lib_name in [
- 'libmono-btls-shared', 'libmono-native-compat', 'libMonoPosixHelper'
- ]]
+ if platform == "osx":
+ lib_file_names = [
+ lib_name + ".dylib"
+ for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"]
+ ]
elif is_unix_like(platform):
- lib_file_names = [lib_name + '.so' for lib_name in [
- 'libmono-btls-shared', 'libmono-ee-interp', 'libmono-native', 'libMonoPosixHelper',
- 'libmono-profiler-aot', 'libmono-profiler-coverage', 'libmono-profiler-log', 'libMonoSupportW'
- ]]
+ lib_file_names = [
+ lib_name + ".so"
+ for lib_name in [
+ "libmono-btls-shared",
+ "libmono-ee-interp",
+ "libmono-native",
+ "libMonoPosixHelper",
+ "libmono-profiler-aot",
+ "libmono-profiler-coverage",
+ "libmono-profiler-log",
+ "libMonoSupportW",
+ ]
+ ]
for lib_file_name in lib_file_names:
- copy_if_exists(os.path.join(mono_root, 'lib', lib_file_name), target_mono_lib_dir)
+ copy_if_exists(os.path.join(mono_root, "lib", lib_file_name), target_mono_lib_dir)
+
def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
tmpenv = Environment()
- tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
- tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
- for hint_dir in tmpenv['LIBPATH']:
- name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
- if name_found and os.path.isdir(os.path.join(hint_dir, '..', 'include', 'mono-2.0')):
- return os.path.join(hint_dir, '..')
- return ''
+ tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
+ tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L")
+ for hint_dir in tmpenv["LIBPATH"]:
+ name_found = find_name_in_dir_files(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext])
+ if name_found and os.path.isdir(os.path.join(hint_dir, "..", "include", "mono-2.0")):
+ return os.path.join(hint_dir, "..")
+ return ""
diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py
index b2c48f0a61..3090a4759a 100644
--- a/modules/mono/build_scripts/mono_reg_utils.py
+++ b/modules/mono/build_scripts/mono_reg_utils.py
@@ -1,21 +1,16 @@
import os
import platform
-from compat import decode_utf8
-
-if os.name == 'nt':
+if os.name == "nt":
import sys
- if sys.version_info < (3,):
- import _winreg as winreg
- else:
- import winreg
+ import winreg
def _reg_open_key(key, subkey):
try:
return winreg.OpenKey(key, subkey)
except (WindowsError, OSError):
- if platform.architecture()[0] == '32bit':
+ if platform.architecture()[0] == "32bit":
bitness_sam = winreg.KEY_WOW64_64KEY
else:
bitness_sam = winreg.KEY_WOW64_32KEY
@@ -25,12 +20,12 @@ def _reg_open_key(key, subkey):
def _reg_open_key_bits(key, subkey, bits):
sam = winreg.KEY_READ
- if platform.architecture()[0] == '32bit':
- if bits == '64':
+ if platform.architecture()[0] == "32bit":
+ if bits == "64":
# Force 32bit process to search in 64bit registry
sam |= winreg.KEY_WOW64_64KEY
else:
- if bits == '32':
+ if bits == "32":
# Force 64bit process to search in 32bit registry
sam |= winreg.KEY_WOW64_32KEY
@@ -40,7 +35,7 @@ def _reg_open_key_bits(key, subkey, bits):
def _find_mono_in_reg(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- value = winreg.QueryValueEx(hKey, 'SdkInstallRoot')[0]
+ value = winreg.QueryValueEx(hKey, "SdkInstallRoot")[0]
return value
except (WindowsError, OSError):
return None
@@ -49,70 +44,70 @@ def _find_mono_in_reg(subkey, bits):
def _find_mono_in_reg_old(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- default_clr = winreg.QueryValueEx(hKey, 'DefaultCLR')[0]
+ default_clr = winreg.QueryValueEx(hKey, "DefaultCLR")[0]
if default_clr:
- return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
+ return _find_mono_in_reg(subkey + "\\" + default_clr, bits)
return None
except (WindowsError, EnvironmentError):
return None
def find_mono_root_dir(bits):
- root_dir = _find_mono_in_reg(r'SOFTWARE\Mono', bits)
+ root_dir = _find_mono_in_reg(r"SOFTWARE\Mono", bits)
if root_dir is not None:
return str(root_dir)
- root_dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono', bits)
+ root_dir = _find_mono_in_reg_old(r"SOFTWARE\Novell\Mono", bits)
if root_dir is not None:
return str(root_dir)
- return ''
+ return ""
def find_msbuild_tools_path_reg():
import subprocess
- vswhere = os.getenv('PROGRAMFILES(X86)')
+ vswhere = os.getenv("PROGRAMFILES(X86)")
if not vswhere:
- vswhere = os.getenv('PROGRAMFILES')
- vswhere += r'\Microsoft Visual Studio\Installer\vswhere.exe'
+ vswhere = os.getenv("PROGRAMFILES")
+ vswhere += r"\Microsoft Visual Studio\Installer\vswhere.exe"
- vswhere_args = ['-latest', '-products', '*', '-requires', 'Microsoft.Component.MSBuild']
+ vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"]
try:
lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
for line in lines:
- parts = decode_utf8(line).split(':', 1)
+ parts = line.decode("utf-8").split(":", 1)
- if len(parts) < 2 or parts[0] != 'installationPath':
+ if len(parts) < 2 or parts[0] != "installationPath":
continue
val = parts[1].strip()
if not val:
- raise ValueError('Value of `installationPath` entry is empty')
+ raise ValueError("Value of `installationPath` entry is empty")
# Since VS2019, the directory is simply named "Current"
- msbuild_dir = os.path.join(val, 'MSBuild\\Current\\Bin')
+ msbuild_dir = os.path.join(val, "MSBuild\\Current\\Bin")
if os.path.isdir(msbuild_dir):
return msbuild_dir
# Directory name "15.0" is used in VS 2017
- return os.path.join(val, 'MSBuild\\15.0\\Bin')
+ return os.path.join(val, "MSBuild\\15.0\\Bin")
- raise ValueError('Cannot find `installationPath` entry')
+ raise ValueError("Cannot find `installationPath` entry")
except ValueError as e:
- print('Error reading output from vswhere: ' + e.message)
+ print("Error reading output from vswhere: " + e.message)
except WindowsError:
- pass # Fine, vswhere not found
+ pass # Fine, vswhere not found
except (subprocess.CalledProcessError, OSError):
pass
# Try to find 14.0 in the Registry
try:
- subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
+ subkey = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0"
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
- value = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')[0]
+ value = winreg.QueryValueEx(hKey, "MSBuildToolsPath")[0]
return value
except (WindowsError, OSError):
- return ''
+ return ""
diff --git a/modules/mono/build_scripts/solution_builder.py b/modules/mono/build_scripts/solution_builder.py
index d1529a64d2..db6b4ff7aa 100644
--- a/modules/mono/build_scripts/solution_builder.py
+++ b/modules/mono/build_scripts/solution_builder.py
@@ -1,4 +1,3 @@
-
import os
@@ -8,35 +7,38 @@ verbose = False
def find_nuget_unix():
import os
- if 'NUGET_PATH' in os.environ:
- hint_path = os.environ['NUGET_PATH']
+ if "NUGET_PATH" in os.environ:
+ hint_path = os.environ["NUGET_PATH"]
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- hint_path = os.path.join(hint_path, 'nuget')
+ hint_path = os.path.join(hint_path, "nuget")
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
import os.path
import sys
- hint_dirs = ['/opt/novell/mono/bin']
- if sys.platform == 'darwin':
- hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
+ hint_dirs = ["/opt/novell/mono/bin"]
+ if sys.platform == "darwin":
+ hint_dirs = [
+ "/Library/Frameworks/Mono.framework/Versions/Current/bin",
+ "/usr/local/var/homebrew/linked/mono/bin",
+ ] + hint_dirs
for hint_dir in hint_dirs:
- hint_path = os.path.join(hint_dir, 'nuget')
+ hint_path = os.path.join(hint_dir, "nuget")
if os.path.isfile(hint_path):
return hint_path
- elif os.path.isfile(hint_path + '.exe'):
- return hint_path + '.exe'
+ elif os.path.isfile(hint_path + ".exe"):
+ return hint_path + ".exe"
- for hint_dir in os.environ['PATH'].split(os.pathsep):
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, 'nuget')
+ hint_path = os.path.join(hint_dir, "nuget")
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
- return hint_path + '.exe'
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
return None
@@ -44,30 +46,30 @@ def find_nuget_unix():
def find_nuget_windows(env):
import os
- if 'NUGET_PATH' in os.environ:
- hint_path = os.environ['NUGET_PATH']
+ if "NUGET_PATH" in os.environ:
+ hint_path = os.environ["NUGET_PATH"]
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- hint_path = os.path.join(hint_path, 'nuget.exe')
+ hint_path = os.path.join(hint_path, "nuget.exe")
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- from . mono_reg_utils import find_mono_root_dir
+ from .mono_reg_utils import find_mono_root_dir
- mono_root = env['mono_prefix'] or find_mono_root_dir(env['bits'])
+ mono_root = env["mono_prefix"] or find_mono_root_dir(env["bits"])
if mono_root:
- mono_bin_dir = os.path.join(mono_root, 'bin')
- nuget_mono = os.path.join(mono_bin_dir, 'nuget.bat')
+ mono_bin_dir = os.path.join(mono_root, "bin")
+ nuget_mono = os.path.join(mono_bin_dir, "nuget.bat")
if os.path.isfile(nuget_mono):
return nuget_mono
# Standalone NuGet
- for hint_dir in os.environ['PATH'].split(os.pathsep):
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, 'nuget.exe')
+ hint_path = os.path.join(hint_dir, "nuget.exe")
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
@@ -78,52 +80,55 @@ def find_msbuild_unix(filename):
import os.path
import sys
- hint_dirs = ['/opt/novell/mono/bin']
- if sys.platform == 'darwin':
- hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin', '/usr/local/var/homebrew/linked/mono/bin'] + hint_dirs
+ hint_dirs = ["/opt/novell/mono/bin"]
+ if sys.platform == "darwin":
+ hint_dirs = [
+ "/Library/Frameworks/Mono.framework/Versions/Current/bin",
+ "/usr/local/var/homebrew/linked/mono/bin",
+ ] + hint_dirs
for hint_dir in hint_dirs:
hint_path = os.path.join(hint_dir, filename)
if os.path.isfile(hint_path):
return hint_path
- elif os.path.isfile(hint_path + '.exe'):
- return hint_path + '.exe'
+ elif os.path.isfile(hint_path + ".exe"):
+ return hint_path + ".exe"
- for hint_dir in os.environ['PATH'].split(os.pathsep):
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
hint_dir = hint_dir.strip('"')
hint_path = os.path.join(hint_dir, filename)
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- if os.path.isfile(hint_path + '.exe') and os.access(hint_path + '.exe', os.X_OK):
- return hint_path + '.exe'
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
return None
def find_msbuild_windows(env):
- from . mono_reg_utils import find_mono_root_dir, find_msbuild_tools_path_reg
+ from .mono_reg_utils import find_mono_root_dir, find_msbuild_tools_path_reg
- mono_root = env['mono_prefix'] or find_mono_root_dir(env['bits'])
+ mono_root = env["mono_prefix"] or find_mono_root_dir(env["bits"])
if not mono_root:
- raise RuntimeError('Cannot find mono root directory')
+ raise RuntimeError("Cannot find mono root directory")
- mono_bin_dir = os.path.join(mono_root, 'bin')
- msbuild_mono = os.path.join(mono_bin_dir, 'msbuild.bat')
+ mono_bin_dir = os.path.join(mono_root, "bin")
+ msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat")
msbuild_tools_path = find_msbuild_tools_path_reg()
if msbuild_tools_path:
- return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), {})
+ return (os.path.join(msbuild_tools_path, "MSBuild.exe"), {})
if os.path.isfile(msbuild_mono):
# The (Csc/Vbc/Fsc)ToolExe environment variables are required when
# building with Mono's MSBuild. They must point to the batch files
# in Mono's bin directory to make sure they are executed with Mono.
mono_msbuild_env = {
- 'CscToolExe': os.path.join(mono_bin_dir, 'csc.bat'),
- 'VbcToolExe': os.path.join(mono_bin_dir, 'vbc.bat'),
- 'FscToolExe': os.path.join(mono_bin_dir, 'fsharpc.bat')
+ "CscToolExe": os.path.join(mono_bin_dir, "csc.bat"),
+ "VbcToolExe": os.path.join(mono_bin_dir, "vbc.bat"),
+ "FscToolExe": os.path.join(mono_bin_dir, "fsharpc.bat"),
}
return (msbuild_mono, mono_msbuild_env)
@@ -132,7 +137,7 @@ def find_msbuild_windows(env):
def run_command(command, args, env_override=None, name=None):
def cmd_args_to_str(cmd_args):
- return ' '.join([arg if not ' ' in arg else '"%s"' % arg for arg in cmd_args])
+ return " ".join([arg if not " " in arg else '"%s"' % arg for arg in cmd_args])
args = [command] + args
@@ -143,6 +148,7 @@ def run_command(command, args, env_override=None, name=None):
print("Running '%s': %s" % (name, cmd_args_to_str(args)))
import subprocess
+
try:
if env_override is None:
subprocess.check_call(args)
@@ -154,61 +160,61 @@ def run_command(command, args, env_override=None, name=None):
def nuget_restore(env, *args):
global verbose
- verbose = env['verbose']
+ verbose = env["verbose"]
# Find NuGet
- nuget_path = find_nuget_windows(env) if os.name == 'nt' else find_nuget_unix()
+ nuget_path = find_nuget_windows(env) if os.name == "nt" else find_nuget_unix()
if nuget_path is None:
- raise RuntimeError('Cannot find NuGet executable')
+ raise RuntimeError("Cannot find NuGet executable")
- print('NuGet path: ' + nuget_path)
+ print("NuGet path: " + nuget_path)
# Do NuGet restore
- run_command(nuget_path, ['restore'] + list(args), name='nuget restore')
+ run_command(nuget_path, ["restore"] + list(args), name="nuget restore")
def build_solution(env, solution_path, build_config, extra_msbuild_args=[]):
global verbose
- verbose = env['verbose']
+ verbose = env["verbose"]
msbuild_env = os.environ.copy()
# Needed when running from Developer Command Prompt for VS
- if 'PLATFORM' in msbuild_env:
- del msbuild_env['PLATFORM']
+ if "PLATFORM" in msbuild_env:
+ del msbuild_env["PLATFORM"]
# Find MSBuild
- if os.name == 'nt':
+ if os.name == "nt":
msbuild_info = find_msbuild_windows(env)
if msbuild_info is None:
- raise RuntimeError('Cannot find MSBuild executable')
+ raise RuntimeError("Cannot find MSBuild executable")
msbuild_path = msbuild_info[0]
msbuild_env.update(msbuild_info[1])
else:
- msbuild_path = find_msbuild_unix('msbuild')
+ msbuild_path = find_msbuild_unix("msbuild")
if msbuild_path is None:
- xbuild_fallback = env['xbuild_fallback']
+ xbuild_fallback = env["xbuild_fallback"]
- if xbuild_fallback and os.name == 'nt':
- print('Option \'xbuild_fallback\' not supported on Windows')
+ if xbuild_fallback and os.name == "nt":
+ print("Option 'xbuild_fallback' not supported on Windows")
xbuild_fallback = False
if xbuild_fallback:
- print('Cannot find MSBuild executable, trying with xbuild')
- print('Warning: xbuild is deprecated')
+ print("Cannot find MSBuild executable, trying with xbuild")
+ print("Warning: xbuild is deprecated")
- msbuild_path = find_msbuild_unix('xbuild')
+ msbuild_path = find_msbuild_unix("xbuild")
if msbuild_path is None:
- raise RuntimeError('Cannot find xbuild executable')
+ raise RuntimeError("Cannot find xbuild executable")
else:
- raise RuntimeError('Cannot find MSBuild executable')
+ raise RuntimeError("Cannot find MSBuild executable")
- print('MSBuild path: ' + msbuild_path)
+ print("MSBuild path: " + msbuild_path)
# Build solution
- msbuild_args = [solution_path, '/p:Configuration=' + build_config]
+ msbuild_args = [solution_path, "/p:Configuration=" + build_config]
msbuild_args += extra_msbuild_args
- run_command(msbuild_path, msbuild_args, env_override=msbuild_env, name='msbuild')
+ run_command(msbuild_path, msbuild_args, env_override=msbuild_env, name="msbuild")
diff --git a/modules/mono/build_scripts/tls_configure.py b/modules/mono/build_scripts/tls_configure.py
deleted file mode 100644
index 622280b00b..0000000000
--- a/modules/mono/build_scripts/tls_configure.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from __future__ import print_function
-
-def supported(result):
- return 'supported' if result else 'not supported'
-
-
-def check_cxx11_thread_local(conf):
- print('Checking for `thread_local` support...', end=" ")
- result = conf.TryCompile('thread_local int foo = 0; int main() { return foo; }', '.cpp')
- print(supported(result))
- return bool(result)
-
-
-def check_declspec_thread(conf):
- print('Checking for `__declspec(thread)` support...', end=" ")
- result = conf.TryCompile('__declspec(thread) int foo = 0; int main() { return foo; }', '.cpp')
- print(supported(result))
- return bool(result)
-
-
-def check_gcc___thread(conf):
- print('Checking for `__thread` support...', end=" ")
- result = conf.TryCompile('__thread int foo = 0; int main() { return foo; }', '.cpp')
- print(supported(result))
- return bool(result)
-
-
-def configure(conf):
- if check_cxx11_thread_local(conf):
- conf.env.Append(CPPDEFINES=['HAVE_CXX11_THREAD_LOCAL'])
- else:
- if conf.env.msvc:
- if check_declspec_thread(conf):
- conf.env.Append(CPPDEFINES=['HAVE_DECLSPEC_THREAD'])
- elif check_gcc___thread(conf):
- conf.env.Append(CPPDEFINES=['HAVE_GCC___THREAD'])
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index b04e53bd81..384685d04b 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -42,7 +42,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> names;
- const StringName *k = NULL;
+ const StringName *k = nullptr;
while ((k = ClassDB::classes.next(k))) {
@@ -67,7 +67,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->method_map.next(k))) {
@@ -132,7 +132,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->constant_map.next(k))) {
@@ -160,7 +160,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->signal_map.next(k))) {
@@ -196,7 +196,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = NULL;
+ k = nullptr;
while ((k = t->property_setget.next(k))) {
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 70cb464c7a..106ca6e028 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,42 +1,70 @@
+supported_platforms = ["windows", "osx", "linuxbsd", "server", "android", "haiku", "javascript", "iphone"]
+
+
def can_build(env, platform):
return True
def configure(env):
- if env['platform'] not in ['windows', 'osx', 'x11', 'server', 'android', 'haiku', 'javascript']:
- raise RuntimeError('This module does not currently support building for this platform')
+ platform = env["platform"]
+
+ if platform not in supported_platforms:
+ raise RuntimeError("This module does not currently support building for this platform")
env.use_ptrcall = True
- env.add_module_version_string('mono')
+ env.add_module_version_string("mono")
- from SCons.Script import BoolVariable, PathVariable, Variables
+ from SCons.Script import BoolVariable, PathVariable, Variables, Help
+
+ default_mono_static = platform in ["iphone", "javascript"]
+ default_mono_bundles_zlib = platform in ["javascript"]
envvars = Variables()
- envvars.Add(PathVariable('mono_prefix', 'Path to the mono installation directory for the target platform and architecture', '', PathVariable.PathAccept))
- envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
- envvars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
- envvars.Add(BoolVariable('copy_mono_root', 'Make a copy of the mono installation directory to bundle with the editor', False))
- envvars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
+ envvars.Add(
+ PathVariable(
+ "mono_prefix",
+ "Path to the mono installation directory for the target platform and architecture",
+ "",
+ PathVariable.PathAccept,
+ )
+ )
+ envvars.Add(BoolVariable("mono_static", "Statically link mono", default_mono_static))
+ envvars.Add(BoolVariable("mono_glue", "Build with the mono glue sources", True))
+ envvars.Add(
+ BoolVariable(
+ "copy_mono_root", "Make a copy of the mono installation directory to bundle with the editor", False
+ )
+ )
+ envvars.Add(BoolVariable("xbuild_fallback", "If MSBuild is not found, fallback to xbuild", False))
+
+ # TODO: It would be great if this could be detected automatically instead
+ envvars.Add(
+ BoolVariable(
+ "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib
+ )
+ )
+
envvars.Update(env)
+ Help(envvars.GenerateHelpText(env))
- if env['platform'] == 'javascript':
- # Mono wasm already has zlib builtin, so we need this workaround to avoid symbol collisions
- print('Compiling with Mono wasm disables \'builtin_zlib\'')
- env['builtin_zlib'] = False
+ if env["mono_bundles_zlib"]:
+ # Mono may come with zlib bundled for WASM or on newer version when built with MinGW.
+ print("This Mono runtime comes with zlib bundled. Disabling 'builtin_zlib'...")
+ env["builtin_zlib"] = False
thirdparty_zlib_dir = "#thirdparty/zlib/"
env.Prepend(CPPPATH=[thirdparty_zlib_dir])
def get_doc_classes():
return [
- '@C#',
- 'CSharpScript',
- 'GodotSharp',
+ "@C#",
+ "CSharpScript",
+ "GodotSharp",
]
def get_doc_path():
- return 'doc_classes'
+ return "doc_classes"
def is_enabled():
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 02ff6bcf13..0b5d3c8dbc 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -62,7 +62,6 @@
#include "signal_awaiter_utils.h"
#include "utils/macros.h"
#include "utils/string_utils.h"
-#include "utils/thread_local.h"
#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var)
@@ -75,7 +74,7 @@ static bool _create_project_solution_if_needed() {
if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
// A solution does not yet exist, create a new one
- CRASH_COND(CSharpLanguage::get_singleton()->get_godotsharp_editor() == NULL);
+ CRASH_COND(CSharpLanguage::get_singleton()->get_godotsharp_editor() == nullptr);
return CSharpLanguage::get_singleton()->get_godotsharp_editor()->call("CreateProjectSolution");
}
@@ -83,7 +82,7 @@ static bool _create_project_solution_if_needed() {
}
#endif
-CSharpLanguage *CSharpLanguage::singleton = NULL;
+CSharpLanguage *CSharpLanguage::singleton = nullptr;
String CSharpLanguage::get_name() const {
@@ -142,21 +141,24 @@ void CSharpLanguage::init() {
void CSharpLanguage::finish() {
+ if (finalized)
+ return;
+
finalizing = true;
// Make sure all script binding gchandles are released before finalizing GDMono
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value();
- if (script_binding.gchandle.is_valid()) {
- script_binding.gchandle->release();
+ if (!script_binding.gchandle.is_released()) {
+ script_binding.gchandle.release();
script_binding.inited = false;
}
}
if (gdmono) {
memdelete(gdmono);
- gdmono = NULL;
+ gdmono = nullptr;
}
// Clear here, after finalizing all domains to make sure there is nothing else referencing the elements.
@@ -175,7 +177,10 @@ void CSharpLanguage::finish() {
}
#endif
+ memdelete(managed_callable_middleman);
+
finalizing = false;
+ finalized = true;
}
void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
@@ -311,7 +316,8 @@ void CSharpLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("' '"); // character literal
p_delimiters->push_back("\" \""); // regular string literal
- p_delimiters->push_back("@\" \""); // verbatim string literal
+ // Verbatim string literals (`@" "`) don't render correctly, so don't highlight them.
+ // Generic string highlighting suffices as a workaround for now.
}
static String get_base_class_name(const String &p_base_class_name, const String p_class_name) {
@@ -434,13 +440,12 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
return "byte[]";
if (p_var_type_name == Variant::get_type_name(Variant::PACKED_INT32_ARRAY))
return "int[]";
- if (p_var_type_name == Variant::get_type_name(Variant::PACKED_FLOAT32_ARRAY)) {
-#ifdef REAL_T_IS_DOUBLE
- return "double[]";
-#else
+ if (p_var_type_name == Variant::get_type_name(Variant::PACKED_INT64_ARRAY))
+ return "long[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::PACKED_FLOAT32_ARRAY))
return "float[]";
-#endif
- }
+ if (p_var_type_name == Variant::get_type_name(Variant::PACKED_FLOAT64_ARRAY))
+ return "double[]";
if (p_var_type_name == Variant::get_type_name(Variant::PACKED_STRING_ARRAY))
return "string[]";
if (p_var_type_name == Variant::get_type_name(Variant::PACKED_VECTOR2_ARRAY))
@@ -450,12 +455,18 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
if (p_var_type_name == Variant::get_type_name(Variant::PACKED_COLOR_ARRAY))
return "Color[]";
+ if (p_var_type_name == Variant::get_type_name(Variant::SIGNAL))
+ return "SignalInfo";
+
Variant::Type var_types[] = {
Variant::BOOL,
Variant::INT,
Variant::VECTOR2,
+ Variant::VECTOR2I,
Variant::RECT2,
+ Variant::RECT2I,
Variant::VECTOR3,
+ Variant::VECTOR3I,
Variant::TRANSFORM2D,
Variant::PLANE,
Variant::QUAT,
@@ -463,8 +474,10 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
Variant::BASIS,
Variant::TRANSFORM,
Variant::COLOR,
+ Variant::STRING_NAME,
Variant::NODE_PATH,
- Variant::_RID
+ Variant::_RID,
+ Variant::CALLABLE
};
for (unsigned int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) {
@@ -561,7 +574,13 @@ String CSharpLanguage::debug_get_stack_level_source(int p_level) const {
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
#ifdef DEBUG_ENABLED
- _TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
+ // Printing an error here will result in endless recursion, so we must be careful
+ static thread_local bool _recursion_flag_ = false;
+ if (_recursion_flag_)
+ return Vector<StackInfo>();
+ _recursion_flag_ = true;
+ SCOPE_EXIT { _recursion_flag_ = false; };
+
GD_MONO_SCOPE_THREAD_ATTACH;
if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated)
@@ -586,10 +605,16 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
#ifdef DEBUG_ENABLED
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
- _TLS_RECURSION_GUARD_V_(Vector<StackInfo>());
+ // Printing an error here will result in endless recursion, so we must be careful
+ static thread_local bool _recursion_flag_ = false;
+ if (_recursion_flag_)
+ return Vector<StackInfo>();
+ _recursion_flag_ = true;
+ SCOPE_EXIT { _recursion_flag_ = false; };
+
GD_MONO_SCOPE_THREAD_ATTACH;
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoArray *frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames).invoke(p_stack_trace, &exc);
@@ -654,14 +679,14 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
void CSharpLanguage::frame() {
- if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) {
- const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoCache::cached_data.task_scheduler_handle;
+ if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != nullptr) {
+ const Ref<MonoGCHandleRef> &task_scheduler_handle = GDMonoCache::cached_data.task_scheduler_handle;
if (task_scheduler_handle.is_valid()) {
MonoObject *task_scheduler = task_scheduler_handle->get_target();
if (task_scheduler) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
CACHED_METHOD_THUNK(GodotTaskScheduler, Activate).invoke(task_scheduler, &exc);
if (exc) {
@@ -739,7 +764,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
if (proj_assembly) {
String proj_asm_path = proj_assembly->get_path();
- if (!FileAccess::exists(proj_assembly->get_path())) {
+ if (!FileAccess::exists(proj_asm_path)) {
// Maybe it wasn't loaded from the default path, so check this as well
proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe);
if (!FileAccess::exists(proj_asm_path))
@@ -763,7 +788,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// There is no soft reloading with Mono. It's always hard reloading.
- List<Ref<CSharpScript> > scripts;
+ List<Ref<CSharpScript>> scripts;
{
MutexLock lock(script_instances_mutex);
@@ -774,10 +799,40 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
}
- List<Ref<CSharpScript> > to_reload;
+ scripts.sort_custom<CSharpScriptDepSort>(); // Update in inheritance dependency order
+
+ // Serialize managed callables
+ {
+ MutexLock lock(ManagedCallable::instances_mutex);
+
+ for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) {
+ ManagedCallable *managed_callable = elem->self();
+
+ MonoDelegate *delegate = (MonoDelegate *)managed_callable->delegate_handle.get_target();
+
+ Array serialized_data;
+ MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
+
+ MonoException *exc = nullptr;
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate).invoke(delegate, managed_serialized_data, &exc);
+
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ continue;
+ }
+
+ if (success) {
+ ManagedCallable::instances_pending_reload.insert(managed_callable, serialized_data);
+ } else if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Failed to serialize delegate\n");
+ }
+ }
+ }
+
+ List<Ref<CSharpScript>> to_reload;
// We need to keep reference instances alive during reloading
- List<Ref<Reference> > ref_instances;
+ List<Ref<Reference>> ref_instances;
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value();
@@ -789,9 +844,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// As scripts are going to be reloaded, must proceed without locking here
- scripts.sort_custom<CSharpScriptDepSort>(); // Update in inheritance dependency order
-
- for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
+ for (List<Ref<CSharpScript>>::Element *E = scripts.front(); E; E = E->next()) {
Ref<CSharpScript> &script = E->get();
to_reload.push_back(script);
@@ -845,13 +898,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// TODO: Proper state backup (Not only variants, serialize managed state of scripts)
csi->get_properties_state_for_reloading(state.properties);
+ csi->get_event_signals_state_for_reloading(state.event_signals);
owners_map[obj->get_instance_id()] = state;
}
}
// After the state of all instances is saved, clear scripts and script instances
- for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
+ for (List<Ref<CSharpScript>>::Element *E = scripts.front(); E; E = E->next()) {
Ref<CSharpScript> &script = E->get();
while (script->instances.front()) {
@@ -866,7 +920,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
if (gdmono->reload_scripts_domain() != OK) {
// Failed to reload the scripts domain
// Make sure to add the scripts back to their owners before returning
- for (List<Ref<CSharpScript> >::Element *E = to_reload.front(); E; E = E->next()) {
+ for (List<Ref<CSharpScript>>::Element *E = to_reload.front(); E; E = E->next()) {
Ref<CSharpScript> scr = E->get();
for (const Map<ObjectID, CSharpScript::StateBackup>::Element *F = scr->pending_reload_state.front(); F; F = F->next()) {
@@ -891,8 +945,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#endif
// Restore Variant properties state, it will be kept by the placeholder until the next script reloading
- for (List<Pair<StringName, Variant> >::Element *G = scr->pending_reload_state[obj_id].properties.front(); G; G = G->next()) {
- placeholder->property_set_fallback(G->get().first, G->get().second, NULL);
+ for (List<Pair<StringName, Variant>>::Element *G = scr->pending_reload_state[obj_id].properties.front(); G; G = G->next()) {
+ placeholder->property_set_fallback(G->get().first, G->get().second, nullptr);
}
scr->pending_reload_state.erase(obj_id);
@@ -902,9 +956,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
return;
}
- List<Ref<CSharpScript> > to_reload_state;
+ List<Ref<CSharpScript>> to_reload_state;
- for (List<Ref<CSharpScript> >::Element *E = to_reload.front(); E; E = E->next()) {
+ for (List<Ref<CSharpScript>>::Element *E = to_reload.front(); E; E = E->next()) {
Ref<CSharpScript> script = E->get();
if (!script->get_path().empty()) {
@@ -926,12 +980,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
GDMonoAssembly *project_assembly = gdmono->get_project_assembly();
// Search in project and tools assemblies first as those are the most likely to have the class
- GDMonoClass *script_class = (project_assembly ? project_assembly->get_class(class_namespace, class_name) : NULL);
+ GDMonoClass *script_class = (project_assembly ? project_assembly->get_class(class_namespace, class_name) : nullptr);
#ifdef TOOLS_ENABLED
if (!script_class) {
GDMonoAssembly *tools_assembly = gdmono->get_tools_assembly();
- script_class = (tools_assembly ? tools_assembly->get_class(class_namespace, class_name) : NULL);
+ script_class = (tools_assembly ? tools_assembly->get_class(class_namespace, class_name) : nullptr);
}
#endif
@@ -957,7 +1011,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
CSharpScript::initialize_for_managed_type(script, script_class, native);
}
- String native_name = NATIVE_GDMONOCLASS_NAME(script->native);
+ StringName native_name = NATIVE_GDMONOCLASS_NAME(script->native);
{
for (Set<ObjectID>::Element *F = script->pending_reload_instances.front(); F; F = F->next()) {
@@ -1002,7 +1056,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
continue;
}
#else
- CRASH_COND(si != NULL);
+ CRASH_COND(si != nullptr);
#endif
// Re-create script instance
obj->set_script(script); // will create the script instance as well
@@ -1012,7 +1066,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
to_reload_state.push_back(script);
}
- for (List<Ref<CSharpScript> >::Element *E = to_reload_state.front(); E; E = E->next()) {
+ for (List<Ref<CSharpScript>>::Element *E = to_reload_state.front(); E; E = E->next()) {
Ref<CSharpScript> script = E->get();
for (Set<ObjectID>::Element *F = script->pending_reload_instances.front(); F; F = F->next()) {
@@ -1030,19 +1084,84 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id];
- for (List<Pair<StringName, Variant> >::Element *G = state_backup.properties.front(); G; G = G->next()) {
+ for (List<Pair<StringName, Variant>>::Element *G = state_backup.properties.front(); G; G = G->next()) {
obj->get_script_instance()->set(G->get().first, G->get().second);
}
- // Call OnAfterDeserialization
CSharpInstance *csi = CAST_CSHARP_INSTANCE(obj->get_script_instance());
- if (csi && csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener)))
- obj->get_script_instance()->call_multilevel(string_names.on_after_deserialize);
+
+ if (csi) {
+ for (List<Pair<StringName, Array>>::Element *G = state_backup.event_signals.front(); G; G = G->next()) {
+ const StringName &name = G->get().first;
+ const Array &serialized_data = G->get().second;
+
+ Map<StringName, CSharpScript::EventSignal>::Element *match = script->event_signals.find(name);
+
+ if (!match) {
+ // The event or its signal attribute were removed
+ continue;
+ }
+
+ const CSharpScript::EventSignal &event_signal = match->value();
+
+ MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
+ MonoDelegate *delegate = nullptr;
+
+ MonoException *exc = nullptr;
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegate).invoke(managed_serialized_data, &delegate, &exc);
+
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ continue;
+ }
+
+ if (success) {
+ ERR_CONTINUE(delegate == nullptr);
+ event_signal.field->set_value(csi->get_mono_object(), (MonoObject *)delegate);
+ } else if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Failed to deserialize event signal delegate\n");
+ }
+ }
+
+ // Call OnAfterDeserialization
+ if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener)))
+ obj->get_script_instance()->call_multilevel(string_names.on_after_deserialize);
+ }
}
script->pending_reload_instances.clear();
}
+ // Deserialize managed callables
+ {
+ MutexLock lock(ManagedCallable::instances_mutex);
+
+ for (Map<ManagedCallable *, Array>::Element *elem = ManagedCallable::instances_pending_reload.front(); elem; elem = elem->next()) {
+ ManagedCallable *managed_callable = elem->key();
+ const Array &serialized_data = elem->value();
+
+ MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
+ MonoDelegate *delegate = nullptr;
+
+ MonoException *exc = nullptr;
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegate).invoke(managed_serialized_data, &delegate, &exc);
+
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ continue;
+ }
+
+ if (success) {
+ ERR_CONTINUE(delegate == nullptr);
+ managed_callable->set_delegate(delegate);
+ } else if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Failed to deserialize delegate\n");
+ }
+ }
+
+ ManagedCallable::instances_pending_reload.clear();
+ }
+
#ifdef TOOLS_ENABLED
// FIXME: Hack to refresh editor in order to display new properties and signals. See if there is a better alternative.
if (Engine::get_singleton()->is_editor_hint()) {
@@ -1163,9 +1282,20 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
void CSharpLanguage::_on_scripts_domain_unloaded() {
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
CSharpScriptBinding &script_binding = E->value();
+ script_binding.gchandle.release();
script_binding.inited = false;
}
+ {
+ MutexLock lock(ManagedCallable::instances_mutex);
+
+ for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) {
+ ManagedCallable *managed_callable = elem->self();
+ managed_callable->delegate_handle.release();
+ managed_callable->delegate_invoke = nullptr;
+ }
+ }
+
scripts_metadata_invalidated = true;
}
@@ -1177,17 +1307,17 @@ void CSharpLanguage::_editor_init_callback() {
// Initialize GodotSharpEditor
GDMonoClass *editor_klass = GDMono::get_singleton()->get_tools_assembly()->get_class("GodotTools", "GodotSharpEditor");
- CRASH_COND(editor_klass == NULL);
+ CRASH_COND(editor_klass == nullptr);
MonoObject *mono_object = mono_object_new(mono_domain_get(), editor_klass->get_mono_ptr());
- CRASH_COND(mono_object == NULL);
+ CRASH_COND(mono_object == nullptr);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::runtime_object_init(mono_object, editor_klass, &exc);
UNHANDLED_EXCEPTION(exc);
EditorPlugin *godotsharp_editor = Object::cast_to<EditorPlugin>(GDMonoMarshal::mono_object_to_variant(mono_object));
- CRASH_COND(godotsharp_editor == NULL);
+ CRASH_COND(godotsharp_editor == nullptr);
// Enable it as a plugin
EditorNode::add_editor_plugin(godotsharp_editor);
@@ -1203,57 +1333,45 @@ void CSharpLanguage::set_language_index(int p_idx) {
lang_idx = p_idx;
}
-void CSharpLanguage::release_script_gchandle(Ref<MonoGCHandle> &p_gchandle) {
+void CSharpLanguage::release_script_gchandle(MonoGCHandleData &p_gchandle) {
- if (!p_gchandle->is_released()) { // Do not lock unnecessarily
+ if (!p_gchandle.is_released()) { // Do not lock unnecessarily
MutexLock lock(get_singleton()->script_gchandle_release_mutex);
- p_gchandle->release();
+ p_gchandle.release();
}
}
-void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, Ref<MonoGCHandle> &p_gchandle) {
+void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, MonoGCHandleData &p_gchandle) {
- uint32_t pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(p_expected_obj); // We might lock after this, so pin it
+ uint32_t pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(p_expected_obj); // We might lock after this, so pin it
- if (!p_gchandle->is_released()) { // Do not lock unnecessarily
+ if (!p_gchandle.is_released()) { // Do not lock unnecessarily
MutexLock lock(get_singleton()->script_gchandle_release_mutex);
- MonoObject *target = p_gchandle->get_target();
+ MonoObject *target = p_gchandle.get_target();
// We release the gchandle if it points to the MonoObject* we expect (otherwise it was
// already released and could have been replaced) or if we can't get its target MonoObject*
// (which doesn't necessarily mean it was released, and we want it released in order to
// avoid locking other threads unnecessarily).
- if (target == p_expected_obj || target == NULL) {
- p_gchandle->release();
+ if (target == p_expected_obj || target == nullptr) {
+ p_gchandle.release();
}
}
- MonoGCHandle::free_handle(pinned_gchandle);
+ GDMonoUtils::free_gchandle(pinned_gchandle);
}
CSharpLanguage::CSharpLanguage() {
ERR_FAIL_COND_MSG(singleton, "C# singleton already exist.");
singleton = this;
-
- finalizing = false;
-
- gdmono = NULL;
-
- lang_idx = -1;
-
- scripts_metadata_invalidated = true;
-
-#ifdef TOOLS_ENABLED
- godotsharp_editor = NULL;
-#endif
}
CSharpLanguage::~CSharpLanguage() {
finish();
- singleton = NULL;
+ singleton = nullptr;
}
bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object) {
@@ -1262,7 +1380,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
// I don't trust you
if (p_object->get_script_instance()) {
CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
- CRASH_COND(csharp_instance != NULL && !csharp_instance->is_destructing_script_instance());
+ CRASH_COND(csharp_instance != nullptr && !csharp_instance->is_destructing_script_instance());
}
#endif
@@ -1286,7 +1404,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
r_script_binding.inited = true;
r_script_binding.type_name = type_name;
r_script_binding.wrapper_class = type_class; // cache
- r_script_binding.gchandle = MonoGCHandle::create_strong(mono_object);
+ r_script_binding.gchandle = MonoGCHandleData::new_strong_handle(mono_object);
r_script_binding.owner = p_object;
// Tie managed to unmanaged
@@ -1316,7 +1434,7 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
CSharpScriptBinding script_binding;
if (!setup_csharp_script_binding(script_binding, p_object))
- return NULL;
+ return nullptr;
return (void *)insert_script_binding(p_object, script_binding);
}
@@ -1328,7 +1446,7 @@ Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_bindi
void CSharpLanguage::free_instance_binding_data(void *p_data) {
- if (GDMono::get_singleton() == NULL) {
+ if (GDMono::get_singleton() == nullptr) {
#ifdef DEBUG_ENABLED
CRASH_COND(!script_bindings.empty());
#endif
@@ -1351,10 +1469,11 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
if (script_binding.inited) {
// Set the native instance field to IntPtr.Zero, if not yet garbage collected.
// This is done to avoid trying to dispose the native instance from Dispose(bool).
- MonoObject *mono_object = script_binding.gchandle->get_target();
+ MonoObject *mono_object = script_binding.gchandle.get_target();
if (mono_object) {
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, NULL);
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, nullptr);
}
+ script_binding.gchandle.release();
}
script_bindings.erase(data);
@@ -1374,26 +1493,26 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
CRASH_COND(!data);
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+ MonoGCHandleData &gchandle = script_binding.gchandle;
if (!script_binding.inited)
return;
- if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
GD_MONO_SCOPE_THREAD_ATTACH;
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
- MonoObject *target = gchandle->get_target();
+ MonoObject *target = gchandle.get_target();
if (!target)
return; // Called after the managed side was collected, so nothing to do here
// Release the current weak handle and replace it with a strong handle.
- uint32_t strong_gchandle = MonoGCHandle::new_strong_handle(target);
- gchandle->release();
- gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE);
+ MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
+ gchandle.release();
+ gchandle = strong_gchandle;
}
}
@@ -1410,27 +1529,27 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
CRASH_COND(!data);
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
+ MonoGCHandleData &gchandle = script_binding.gchandle;
int refcount = ref_owner->reference_get_count();
if (!script_binding.inited)
return refcount == 0;
- if (refcount == 1 && gchandle.is_valid() && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
GD_MONO_SCOPE_THREAD_ATTACH;
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
- MonoObject *target = gchandle->get_target();
+ MonoObject *target = gchandle.get_target();
if (!target)
return refcount == 0; // Called after the managed side was collected, so nothing to do here
// Release the current strong handle and replace it with a weak handle.
- uint32_t weak_gchandle = MonoGCHandle::new_weak_handle(target);
- gchandle->release();
- gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE);
+ MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
+ gchandle.release();
+ gchandle = weak_gchandle;
return false;
}
@@ -1438,14 +1557,13 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
return refcount == 0;
}
-CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle) {
+CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
- CSharpInstance *instance = memnew(CSharpInstance);
+ CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script)));
Reference *ref = Object::cast_to<Reference>(p_owner);
- instance->base_ref = ref != NULL;
- instance->script = Ref<CSharpScript>(p_script);
+ instance->base_ref = ref != nullptr;
instance->owner = p_owner;
instance->gchandle = p_gchandle;
@@ -1459,8 +1577,8 @@ CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpS
MonoObject *CSharpInstance::get_mono_object() const {
- ERR_FAIL_COND_V(gchandle.is_null(), NULL);
- return gchandle->get_target();
+ ERR_FAIL_COND_V(gchandle.is_released(), nullptr);
+ return gchandle.get_target();
}
Object *CSharpInstance::get_owner() {
@@ -1544,7 +1662,7 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
GDMonoProperty *property = top->get_property(p_name);
if (property) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoObject *value = property->get_value(mono_object, &exc);
if (exc) {
r_ret = Variant();
@@ -1585,7 +1703,7 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
return false;
}
-void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Variant> > &r_state) {
+void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state) {
List<PropertyInfo> pinfo;
get_property_list(&pinfo);
@@ -1610,6 +1728,37 @@ void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Va
}
}
+void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state) {
+
+ MonoObject *owner_managed = get_mono_object();
+ ERR_FAIL_NULL(owner_managed);
+
+ for (const Map<StringName, CSharpScript::EventSignal>::Element *E = script->event_signals.front(); E; E = E->next()) {
+ const CSharpScript::EventSignal &event_signal = E->value();
+
+ MonoDelegate *delegate_field_value = (MonoDelegate *)event_signal.field->get_value(owner_managed);
+ if (!delegate_field_value)
+ continue; // Empty
+
+ Array serialized_data;
+ MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
+
+ MonoException *exc = nullptr;
+ bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate).invoke(delegate_field_value, managed_serialized_data, &exc);
+
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ continue;
+ }
+
+ if (success) {
+ r_state.push_back(Pair<StringName, Array>(event_signal.field->get_name(), serialized_data));
+ } else if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Failed to serialize event signal delegate\n");
+ }
+ }
+}
+
void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
for (Map<StringName, PropertyInfo>::Element *E = script->member_info.front(); E; E = E->next()) {
@@ -1761,7 +1910,7 @@ bool CSharpInstance::_reference_owner_unsafe() {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
- CRASH_COND(owner == NULL);
+ CRASH_COND(owner == nullptr);
CRASH_COND(unsafe_referenced); // already referenced
#endif
@@ -1783,7 +1932,7 @@ bool CSharpInstance::_unreference_owner_unsafe() {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
- CRASH_COND(owner == NULL);
+ CRASH_COND(owner == nullptr);
#endif
if (!unsafe_referenced)
@@ -1802,19 +1951,15 @@ bool CSharpInstance::_unreference_owner_unsafe() {
}
MonoObject *CSharpInstance::_internal_new_managed() {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!gchandle.is_valid());
-#endif
-
// Search the constructor first, to fail with an error if it's not found before allocating anything else.
GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
- ERR_FAIL_NULL_V_MSG(ctor, NULL,
+ ERR_FAIL_NULL_V_MSG(ctor, nullptr,
"Cannot create script instance because the class does not define a parameterless constructor: '" + script->get_path() + "'.");
CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
- ERR_FAIL_NULL_V(owner, NULL);
- ERR_FAIL_COND_V(script.is_null(), NULL);
+ ERR_FAIL_NULL_V(owner, nullptr);
+ ERR_FAIL_COND_V(script.is_null(), nullptr);
MonoObject *mono_object = mono_object_new(mono_domain_get(), script->script_class->get_mono_ptr());
@@ -1826,13 +1971,13 @@ MonoObject *CSharpInstance::_internal_new_managed() {
// Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
CRASH_COND(die == true);
- owner = NULL;
+ owner = nullptr;
- ERR_FAIL_V_MSG(NULL, "Failed to allocate memory for the object.");
+ ERR_FAIL_V_MSG(nullptr, "Failed to allocate memory for the object.");
}
// Tie managed to unmanaged
- gchandle = MonoGCHandle::create_strong(mono_object);
+ gchandle = MonoGCHandleData::new_strong_handle(mono_object);
if (base_ref)
_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
@@ -1840,16 +1985,18 @@ MonoObject *CSharpInstance::_internal_new_managed() {
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner);
// Construct
- ctor->invoke_raw(mono_object, NULL);
+ ctor->invoke_raw(mono_object, nullptr);
return mono_object;
}
void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
+ disconnect_event_signals();
+
#ifdef DEBUG_ENABLED
CRASH_COND(base_ref);
- CRASH_COND(gchandle.is_null());
+ CRASH_COND(gchandle.is_released());
#endif
CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
}
@@ -1858,7 +2005,7 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
- CRASH_COND(gchandle.is_null());
+ CRASH_COND(gchandle.is_released());
#endif
r_remove_script_instance = false;
@@ -1888,16 +2035,43 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
}
}
+void CSharpInstance::connect_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: Use pooling for ManagedCallable instances.
+ auto event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
+
+ owner->connect(signal_name, Callable(event_signal_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));
+ }
+}
+
void CSharpInstance::refcount_incremented() {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
- CRASH_COND(owner == NULL);
+ CRASH_COND(owner == nullptr);
#endif
Reference *ref_owner = Object::cast_to<Reference>(owner);
- if (ref_owner->reference_get_count() > 1 && gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
GD_MONO_SCOPE_THREAD_ATTACH;
// The reference count was increased after the managed side was the only one referencing our owner.
@@ -1905,9 +2079,9 @@ void CSharpInstance::refcount_incremented() {
// so the owner must hold the managed side alive again to avoid it from being GCed.
// Release the current weak handle and replace it with a strong handle.
- uint32_t strong_gchandle = MonoGCHandle::new_strong_handle(gchandle->get_target());
- gchandle->release();
- gchandle->set_handle(strong_gchandle, MonoGCHandle::STRONG_HANDLE);
+ MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(gchandle.get_target());
+ gchandle.release();
+ gchandle = strong_gchandle;
}
}
@@ -1915,23 +2089,23 @@ bool CSharpInstance::refcount_decremented() {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref);
- CRASH_COND(owner == NULL);
+ CRASH_COND(owner == nullptr);
#endif
Reference *ref_owner = Object::cast_to<Reference>(owner);
int refcount = ref_owner->reference_get_count();
- if (refcount == 1 && !gchandle->is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
+ if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
GD_MONO_SCOPE_THREAD_ATTACH;
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
// Release the current strong handle and replace it with a weak handle.
- uint32_t weak_gchandle = MonoGCHandle::new_weak_handle(gchandle->get_target());
- gchandle->release();
- gchandle->set_handle(weak_gchandle, MonoGCHandle::WEAK_HANDLE);
+ MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(gchandle.get_target());
+ gchandle.release();
+ gchandle = weak_gchandle;
return false;
}
@@ -2007,7 +2181,7 @@ void CSharpInstance::notification(int p_notification) {
MonoObject *mono_object = get_mono_object();
ERR_FAIL_NULL(mono_object);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::dispose(mono_object, &exc);
if (exc) {
@@ -2052,13 +2226,13 @@ String CSharpInstance::to_string(bool *r_valid) {
MonoObject *mono_object = get_mono_object();
- if (mono_object == NULL) {
+ if (mono_object == nullptr) {
if (r_valid)
*r_valid = false;
return String();
}
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoString *result = GDMonoUtils::object_to_string(mono_object, &exc);
if (exc) {
@@ -2068,7 +2242,7 @@ String CSharpInstance::to_string(bool *r_valid) {
return String();
}
- if (result == NULL) {
+ if (result == nullptr) {
if (r_valid)
*r_valid = false;
return String();
@@ -2087,13 +2261,8 @@ ScriptLanguage *CSharpInstance::get_language() {
return CSharpLanguage::get_singleton();
}
-CSharpInstance::CSharpInstance() :
- owner(NULL),
- base_ref(false),
- ref_dying(false),
- unsafe_referenced(false),
- predelete_notified(false),
- destructing_script_instance(false) {
+CSharpInstance::CSharpInstance(const Ref<CSharpScript> &p_script) :
+ script(p_script) {
}
CSharpInstance::~CSharpInstance() {
@@ -2102,18 +2271,18 @@ CSharpInstance::~CSharpInstance() {
destructing_script_instance = true;
- if (gchandle.is_valid()) {
+ if (!gchandle.is_released()) {
if (!predelete_notified && !ref_dying) {
// This destructor is not called from the owners destructor.
// This could be being called from the owner's set_script_instance method,
// meaning this script is being replaced with another one. If this is the case,
- // we must call Dispose here, because Dispose calls owner->set_script_instance(NULL)
+ // we must call Dispose here, because Dispose calls owner->set_script_instance(nullptr)
// and that would mess up with the new script instance if called later.
- MonoObject *mono_object = gchandle->get_target();
+ MonoObject *mono_object = gchandle.get_target();
if (mono_object) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::dispose(mono_object, &exc);
if (exc) {
@@ -2122,7 +2291,7 @@ CSharpInstance::~CSharpInstance() {
}
}
- gchandle->release(); // Make sure the gchandle is released
+ gchandle.release(); // Make sure the gchandle is released
}
// If not being called from the owner's destructor, and we still hold a reference to the owner
@@ -2143,7 +2312,7 @@ CSharpInstance::~CSharpInstance() {
CRASH_COND(die == true); // `owner_keep_alive` holds a reference, so it can't die
void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
- CRASH_COND(data == NULL);
+ CRASH_COND(data == nullptr);
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
@@ -2282,23 +2451,23 @@ bool CSharpScript::_update_exports() {
return false;
}
- uint32_t tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed)
+ uint32_t tmp_pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(tmp_object); // pin it (not sure if needed)
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
- ERR_FAIL_NULL_V_MSG(ctor, NULL,
+ ERR_FAIL_NULL_V_MSG(ctor, false,
"Cannot construct temporary MonoObject because the class does not define a parameterless constructor: '" + get_path() + "'.");
- MonoException *ctor_exc = NULL;
- ctor->invoke(tmp_object, NULL, &ctor_exc);
+ MonoException *ctor_exc = nullptr;
+ ctor->invoke(tmp_object, nullptr, &ctor_exc);
Object *tmp_native = GDMonoMarshal::unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(tmp_object));
if (ctor_exc) {
// TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
- MonoGCHandle::free_handle(tmp_pinned_gchandle);
- tmp_object = NULL;
+ GDMonoUtils::free_gchandle(tmp_pinned_gchandle);
+ tmp_object = nullptr;
ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
GDMonoUtils::debug_print_unhandled_exception(ctor_exc);
@@ -2345,7 +2514,7 @@ bool CSharpScript::_update_exports() {
exported_members_cache.push_front(prop_info);
if (tmp_object) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoObject *ret = property->get_value(tmp_object, &exc);
if (exc) {
exported_members_defval_cache[member_name] = Variant();
@@ -2364,11 +2533,11 @@ bool CSharpScript::_update_exports() {
}
// Need to check this here, before disposal
- bool base_ref = Object::cast_to<Reference>(tmp_native) != NULL;
+ bool base_ref = Object::cast_to<Reference>(tmp_native) != nullptr;
// Dispose the temporary managed instance
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::dispose(tmp_object, &exc);
if (exc) {
@@ -2376,8 +2545,8 @@ bool CSharpScript::_update_exports() {
GDMonoUtils::debug_print_unhandled_exception(exc);
}
- MonoGCHandle::free_handle(tmp_pinned_gchandle);
- tmp_object = NULL;
+ GDMonoUtils::free_gchandle(tmp_pinned_gchandle);
+ tmp_object = nullptr;
if (tmp_native && !base_ref) {
Node *node = Object::cast_to<Node>(tmp_native);
@@ -2416,6 +2585,7 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
// make sure this classes signals are empty when loading for the first time
_signals.clear();
+ event_signals.clear();
GD_MONO_SCOPE_THREAD_ATTACH;
@@ -2423,56 +2593,90 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati
while (top && top != p_native_class) {
const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
for (int i = delegates.size() - 1; i >= 0; --i) {
- Vector<Argument> parameters;
-
GDMonoClass *delegate = delegates[i];
- if (_get_signal(top, delegate, parameters)) {
+ if (!delegate->has_attribute(CACHED_CLASS(SignalAttribute)))
+ continue;
+
+ // Arguments are accessibles as arguments of .Invoke method
+ GDMonoMethod *invoke_method = delegate->get_method(mono_get_delegate_invoke(delegate->get_mono_ptr()));
+
+ Vector<SignalParameter> parameters;
+ if (_get_signal(top, invoke_method, parameters)) {
_signals[delegate->get_name()] = parameters;
}
}
+ List<StringName> found_event_signals;
+
+ void *iter = nullptr;
+ MonoEvent *raw_event = nullptr;
+ while ((raw_event = mono_class_get_events(top->get_mono_ptr(), &iter)) != nullptr) {
+ MonoCustomAttrInfo *event_attrs = mono_custom_attrs_from_event(top->get_mono_ptr(), raw_event);
+ if (event_attrs) {
+ if (mono_custom_attrs_has_attr(event_attrs, CACHED_CLASS(SignalAttribute)->get_mono_ptr())) {
+ const char *event_name = mono_event_get_name(raw_event);
+ found_event_signals.push_back(StringName(event_name));
+ }
+
+ mono_custom_attrs_free(event_attrs);
+ }
+ }
+
+ const Vector<GDMonoField *> &fields = top->get_all_fields();
+ for (int i = 0; i < fields.size(); i++) {
+ GDMonoField *field = fields[i];
+
+ GDMonoClass *field_class = field->get_type().type_class;
+
+ if (!mono_class_is_delegate(field_class->get_mono_ptr()))
+ continue;
+
+ if (!found_event_signals.find(field->get_name()))
+ continue;
+
+ GDMonoMethod *invoke_method = field_class->get_method(mono_get_delegate_invoke(field_class->get_mono_ptr()));
+
+ Vector<SignalParameter> parameters;
+ if (_get_signal(top, invoke_method, parameters)) {
+ event_signals[field->get_name()] = { field, invoke_method, parameters };
+ }
+ }
+
top = top->get_parent_class();
}
signals_invalidated = false;
}
-bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params) {
+bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params) {
GD_MONO_ASSERT_THREAD_ATTACHED;
- if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
- MonoType *raw_type = p_delegate->get_mono_type();
+ Vector<StringName> names;
+ Vector<ManagedType> types;
+ p_delegate_invoke->get_parameter_names(names);
+ p_delegate_invoke->get_parameter_types(types);
- if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) {
- // Arguments are accessibles as arguments of .Invoke method
- GDMonoMethod *invoke = p_delegate->get_method("Invoke", -1);
-
- Vector<StringName> names;
- Vector<ManagedType> types;
- invoke->get_parameter_names(names);
- invoke->get_parameter_types(types);
-
- if (names.size() == types.size()) {
- for (int i = 0; i < names.size(); ++i) {
- Argument arg;
- arg.name = names[i];
- arg.type = GDMonoMarshal::managed_to_variant_type(types[i]);
-
- if (arg.type == Variant::NIL) {
- ERR_PRINT("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
- return false;
- }
+ for (int i = 0; i < names.size(); ++i) {
+ SignalParameter arg;
+ arg.name = names[i];
- params.push_back(arg);
- }
+ bool nil_is_variant = false;
+ arg.type = GDMonoMarshal::managed_to_variant_type(types[i], &nil_is_variant);
- return true;
+ if (arg.type == Variant::NIL) {
+ if (nil_is_variant) {
+ arg.nil_is_variant = true;
+ } else {
+ ERR_PRINT("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
+ return false;
}
}
+
+ params.push_back(arg);
}
- return false;
+ return true;
}
#ifdef TOOLS_ENABLED
@@ -2523,7 +2727,8 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
}
}
- Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type);
+ bool nil_is_variant = false;
+ Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &nil_is_variant);
if (!p_inspect_export || !exported) {
r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
@@ -2536,7 +2741,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
PropertyHint hint = PROPERTY_HINT_NONE;
String hint_string;
- if (variant_type == Variant::NIL) {
+ if (variant_type == Variant::NIL && !nil_is_variant) {
ERR_PRINT("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
return false;
}
@@ -2552,7 +2757,14 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
}
- r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
+ uint32_t prop_usage = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE;
+
+ if (variant_type == Variant::NIL) {
+ // System.Object (Variant)
+ prop_usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+
+ r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, prop_usage);
r_exported = true;
return true;
@@ -2562,6 +2774,11 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) {
+ if (p_variant_type == Variant::NIL) {
+ // System.Object (Variant)
+ return 1;
+ }
+
GD_MONO_ASSERT_THREAD_ATTACHED;
if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
@@ -2594,7 +2811,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
// Instead of using mono_field_get_value_object, we can do this without boxing. Check the
// internal mono functions: ves_icall_System_Enum_GetEnumValuesAndNames and the get_enum_field.
- MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, NULL);
+ MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, nullptr);
ERR_FAIL_NULL_V_MSG(val_obj, -1, "Failed to get '" + enum_field_name + "' constant enum value.");
@@ -2618,10 +2835,10 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
}
} else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(GodotResource)->is_assignable_from(p_type.type_class)) {
GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class);
- CRASH_COND(field_native_class == NULL);
+ CRASH_COND(field_native_class == nullptr);
r_hint = PROPERTY_HINT_RESOURCE_TYPE;
- r_hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class);
+ r_hint_string = String(NATIVE_GDMONOCLASS_NAME(field_native_class));
} else if (p_allow_generics && p_variant_type == Variant::ARRAY) {
// Nested arrays are not supported in the inspector
@@ -2660,14 +2877,14 @@ void CSharpScript::_clear() {
tool = false;
valid = false;
- base = NULL;
- native = NULL;
- script_class = NULL;
+ base = nullptr;
+ native = nullptr;
+ script_class = nullptr;
}
Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (unlikely(GDMono::get_singleton() == NULL)) {
+ if (unlikely(GDMono::get_singleton() == nullptr)) {
// Probably not the best error but eh.
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return Variant();
@@ -2681,7 +2898,7 @@ Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, i
GDMonoMethod *method = top->get_method(p_method, p_argcount);
if (method && method->is_static()) {
- MonoObject *result = method->invoke(NULL, p_args);
+ MonoObject *result = method->invoke(nullptr, p_args);
if (result) {
return GDMonoMarshal::mono_object_to_variant(result);
@@ -2743,7 +2960,7 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD
// This method should not fail, only assertions allowed
- CRASH_COND(p_class == NULL);
+ CRASH_COND(p_class == nullptr);
// TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
Ref<CSharpScript> script = memnew(CSharpScript);
@@ -2757,13 +2974,13 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon
// This method should not fail, only assertions allowed
- CRASH_COND(p_class == NULL);
+ CRASH_COND(p_class == nullptr);
p_script->name = p_class->get_name();
p_script->script_class = p_class;
p_script->native = p_native;
- CRASH_COND(p_script->native == NULL);
+ CRASH_COND(p_script->native == nullptr);
GDMonoClass *base = p_script->script_class->get_parent_class();
@@ -2820,22 +3037,6 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon
bool CSharpScript::can_instance() const {
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
-
- // Hack to lower the risk of attached scripts not being added to the C# project
- if (!get_path().empty() && get_path().find("::") == -1) { // Ignore if built-in script. Can happen if the file is deleted...
- if (_create_project_solution_if_needed()) {
- CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(),
- "Compile",
- ProjectSettings::get_singleton()->globalize_path(get_path()));
- } else {
- ERR_PRINT("C# project could not be created; cannot add file: '" + get_path() + "'.");
- }
- }
- }
-#endif
-
-#ifdef TOOLS_ENABLED
bool extra_cond = tool || ScriptServer::is_scripting_enabled();
#else
bool extra_cond = true;
@@ -2845,12 +3046,12 @@ bool CSharpScript::can_instance() const {
// For tool scripts, this will never fire if the class is not found. That's because we
// don't know if it's a tool script if we can't find the class to access the attributes.
if (extra_cond && !script_class) {
- if (GDMono::get_singleton()->get_project_assembly() == NULL) {
+ if (GDMono::get_singleton()->get_project_assembly() == nullptr) {
// The project assembly is not loaded
- ERR_FAIL_V_MSG(NULL, "Cannot instance script because the project assembly is not loaded. Script: '" + get_path() + "'.");
+ ERR_FAIL_V_MSG(false, "Cannot instance script because the project assembly is not loaded. Script: '" + get_path() + "'.");
} else {
// The project assembly is loaded, but the class could not found
- ERR_FAIL_V_MSG(NULL, "Cannot instance script because the class '" + name + "' could not be found. Script: '" + get_path() + "'.");
+ ERR_FAIL_V_MSG(false, "Cannot instance script because the class '" + name + "' could not be found. Script: '" + get_path() + "'.");
}
}
@@ -2873,13 +3074,13 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
// Search the constructor first, to fail with an error if it's not found before allocating anything else.
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
- if (ctor == NULL) {
- ERR_FAIL_COND_V_MSG(p_argcount == 0, NULL,
+ if (ctor == nullptr) {
+ ERR_FAIL_COND_V_MSG(p_argcount == 0, nullptr,
"Cannot create script instance. The class '" + script_class->get_full_name() +
"' does not define a parameterless constructor." +
(get_path().empty() ? String() : " Path: '" + get_path() + "'."));
- ERR_FAIL_V_MSG(NULL, "Constructor not found.");
+ ERR_FAIL_V_MSG(nullptr, "Constructor not found.");
}
Ref<Reference> ref;
@@ -2891,13 +3092,13 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
// If the object had a script instance binding, dispose it before adding the CSharpInstance
if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) {
void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
- CRASH_COND(data == NULL);
+ CRASH_COND(data == nullptr);
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
- if (script_binding.inited && script_binding.gchandle.is_valid()) {
- MonoObject *mono_object = script_binding.gchandle->get_target();
+ if (script_binding.inited && !script_binding.gchandle.is_released()) {
+ MonoObject *mono_object = script_binding.gchandle.get_target();
if (mono_object) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::dispose(mono_object, &exc);
if (exc) {
@@ -2905,13 +3106,13 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
}
}
+ script_binding.gchandle.release(); // Just in case
script_binding.inited = false;
}
}
- CSharpInstance *instance = memnew(CSharpInstance);
+ CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this)));
instance->base_ref = p_isref;
- instance->script = Ref<CSharpScript>(this);
instance->owner = p_owner;
instance->owner->set_script_instance(instance);
@@ -2922,19 +3123,19 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
if (!mono_object) {
// Important to clear this before destroying the script instance here
instance->script = Ref<CSharpScript>();
- instance->owner = NULL;
+ instance->owner = nullptr;
bool die = instance->_unreference_owner_unsafe();
// Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
CRASH_COND(die == true);
- p_owner->set_script_instance(NULL);
+ p_owner->set_script_instance(nullptr);
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- ERR_FAIL_V_MSG(NULL, "Failed to allocate memory for the object.");
+ ERR_FAIL_V_MSG(nullptr, "Failed to allocate memory for the object.");
}
// Tie managed to unmanaged
- instance->gchandle = MonoGCHandle::create_strong(mono_object);
+ instance->gchandle = MonoGCHandleData::new_strong_handle(mono_object);
if (instance->base_ref)
instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
@@ -2976,7 +3177,7 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
ref = REF(r);
}
- CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error);
+ CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
if (!instance) {
if (ref.is_null()) {
memdelete(owner); //no owner, sorry
@@ -2998,20 +3199,22 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
#endif
if (native) {
- String native_name = NATIVE_GDMONOCLASS_NAME(native);
+ StringName native_name = NATIVE_GDMONOCLASS_NAME(native);
if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
if (EngineDebugger::is_active()) {
- CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + native_name + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
+ CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0,
+ "Script inherits from native type '" + String(native_name) +
+ "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
}
- ERR_FAIL_V_MSG(NULL, "Script inherits from native type '" + native_name +
- "', so it can't be instanced in object of type: '" + p_this->get_class() + "'.");
+ ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) +
+ "', so it can't be instanced in object of type: '" + p_this->get_class() + "'.");
}
}
GD_MONO_SCOPE_THREAD_ATTACH;
Callable::CallError unchecked_error;
- return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
+ return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error);
}
PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) {
@@ -3022,7 +3225,7 @@ PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_t
_update_exports();
return si;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -3130,7 +3333,7 @@ Error CSharpScript::reload(bool p_keep_state) {
script_class = project_assembly->get_object_derived_class(name);
}
- valid = script_class != NULL;
+ valid = script_class != nullptr;
if (script_class) {
#ifdef DEBUG_ENABLED
@@ -3152,7 +3355,7 @@ Error CSharpScript::reload(bool p_keep_state) {
native = GDMonoUtils::get_class_native_base(script_class);
- CRASH_COND(native == NULL);
+ CRASH_COND(native == nullptr);
GDMonoClass *base_class = script_class->get_parent_class();
@@ -3290,19 +3493,45 @@ void CSharpScript::update_exports() {
}
bool CSharpScript::has_script_signal(const StringName &p_signal) const {
- return _signals.has(p_signal);
+ return event_signals.has(p_signal) || _signals.has(p_signal);
}
void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const Map<StringName, Vector<Argument> >::Element *E = _signals.front(); E; E = E->next()) {
+
+ for (const Map<StringName, Vector<SignalParameter>>::Element *E = _signals.front(); E; E = E->next()) {
MethodInfo mi;
+ mi.name = E->key();
+
+ const Vector<SignalParameter> &params = E->value();
+ for (int i = 0; i < params.size(); i++) {
+ const SignalParameter &param = params[i];
+
+ PropertyInfo arg_info = PropertyInfo(param.type, param.name);
+ if (param.type == Variant::NIL && param.nil_is_variant)
+ arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+
+ mi.arguments.push_back(arg_info);
+ }
+
+ r_signals->push_back(mi);
+ }
+ for (const Map<StringName, EventSignal>::Element *E = event_signals.front(); E; E = E->next()) {
+ MethodInfo mi;
mi.name = E->key();
- for (int i = 0; i < E->get().size(); i++) {
- PropertyInfo arg;
- arg.name = E->get()[i].name;
- mi.arguments.push_back(arg);
+
+ const EventSignal &event_signal = E->value();
+ const Vector<SignalParameter> &params = event_signal.parameters;
+ for (int i = 0; i < params.size(); i++) {
+ const SignalParameter &param = params[i];
+
+ PropertyInfo arg_info = PropertyInfo(param.type, param.name);
+ if (param.type == Variant::NIL && param.nil_is_variant)
+ arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+
+ mi.arguments.push_back(arg_info);
}
+
r_signals->push_back(mi);
}
}
@@ -3420,19 +3649,10 @@ StringName CSharpScript::get_script_name() const {
return name;
}
-CSharpScript::CSharpScript() :
- script_list(this) {
+CSharpScript::CSharpScript() {
_clear();
-#ifdef TOOLS_ENABLED
- source_changed_cache = false;
- placeholder_fallback_enabled = false;
- exports_invalidated = true;
-#endif
-
- signals_invalidated = true;
-
_resource_path_changed();
#ifdef DEBUG_ENABLED
@@ -3547,7 +3767,7 @@ void ResourceFormatSaverCSharpScript::get_recognized_extensions(const RES &p_res
bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const {
- return Object::cast_to<CSharpScript>(p_resource.ptr()) != NULL;
+ return Object::cast_to<CSharpScript>(p_resource.ptr()) != nullptr;
}
CSharpLanguage::StringNameCache::StringNameCache() {
@@ -3561,4 +3781,5 @@ CSharpLanguage::StringNameCache::StringNameCache() {
on_before_serialize = StaticCString::create("OnBeforeSerialize");
on_after_deserialize = StaticCString::create("OnAfterDeserialize");
dotctor = StaticCString::create(".ctor");
+ delegate_invoke_method_name = StaticCString::create("Invoke");
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 18c53aab52..29c33b50bb 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -53,8 +53,8 @@ class CSharpLanguage;
template <typename TScriptInstance, typename TScriptLanguage>
TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
if (!p_inst)
- return NULL;
- return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : NULL;
+ return nullptr;
+ return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : nullptr;
}
#else
template <typename TScriptInstance, typename TScriptLanguage>
@@ -69,18 +69,32 @@ class CSharpScript : public Script {
GDCLASS(CSharpScript, Script);
+public:
+ struct SignalParameter {
+ String name;
+ Variant::Type type;
+ bool nil_is_variant = false;
+ };
+
+ struct EventSignal {
+ GDMonoField *field = nullptr;
+ GDMonoMethod *invoke_method = nullptr;
+ Vector<SignalParameter> parameters;
+ };
+
+private:
friend class CSharpInstance;
friend class CSharpLanguage;
friend struct CSharpScriptDepSort;
- bool tool;
- bool valid;
+ bool tool = false;
+ bool valid = false;
bool builtin;
- GDMonoClass *base;
- GDMonoClass *native;
- GDMonoClass *script_class;
+ GDMonoClass *base = nullptr;
+ GDMonoClass *native = nullptr;
+ GDMonoClass *script_class = nullptr;
Ref<CSharpScript> base_cache; // TODO what's this for?
@@ -91,7 +105,8 @@ class CSharpScript : public Script {
// TODO
// Replace with buffer containing the serialized state of managed scripts.
// Keep variant state backup to use only with script instance placeholders.
- List<Pair<StringName, Variant> > properties;
+ List<Pair<StringName, Variant>> properties;
+ List<Pair<StringName, Array>> event_signals;
};
Set<ObjectID> pending_reload_instances;
@@ -103,15 +118,11 @@ class CSharpScript : public Script {
String source;
StringName name;
- SelfList<CSharpScript> script_list;
-
- struct Argument {
- String name;
- Variant::Type type;
- };
+ SelfList<CSharpScript> script_list = this;
- Map<StringName, Vector<Argument> > _signals;
- bool signals_invalidated;
+ Map<StringName, Vector<SignalParameter>> _signals;
+ Map<StringName, EventSignal> event_signals;
+ bool signals_invalidated = true;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
@@ -120,9 +131,9 @@ class CSharpScript : public Script {
List<PropertyInfo> exported_members_cache; // members_cache
Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
Set<PlaceHolderScriptInstance *> placeholders;
- bool source_changed_cache;
- bool placeholder_fallback_enabled;
- bool exports_invalidated;
+ bool source_changed_cache = false;
+ bool placeholder_fallback_enabled = false;
+ bool exports_invalidated = true;
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
void _update_member_info_no_exports();
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
@@ -133,7 +144,7 @@ class CSharpScript : public Script {
void _clear();
void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class);
- bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> &params);
+ bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params);
bool _update_exports();
#ifdef TOOLS_ENABLED
@@ -221,15 +232,17 @@ class CSharpInstance : public ScriptInstance {
friend class CSharpScript;
friend class CSharpLanguage;
- Object *owner;
- bool base_ref;
- bool ref_dying;
- bool unsafe_referenced;
- bool predelete_notified;
- bool destructing_script_instance;
+ Object *owner = nullptr;
+ bool base_ref = false;
+ bool ref_dying = false;
+ bool unsafe_referenced = false;
+ bool predelete_notified = false;
+ bool destructing_script_instance = false;
Ref<CSharpScript> script;
- Ref<MonoGCHandle> gchandle;
+ MonoGCHandleData gchandle;
+
+ Vector<Callable> event_signal_callables;
bool _reference_owner_unsafe();
@@ -239,17 +252,18 @@ class CSharpInstance : public ScriptInstance {
bool _unreference_owner_unsafe();
/*
- * If NULL is returned, the caller must destroy the script instance by removing it from its owner.
+ * If nullptr is returned, the caller must destroy the script instance by removing it from its owner.
*/
MonoObject *_internal_new_managed();
// Do not use unless you know what you are doing
friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
- static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle);
+ static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle);
void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount);
- void get_properties_state_for_reloading(List<Pair<StringName, Variant> > &r_state);
+ void get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state);
+ void get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state);
public:
MonoObject *get_mono_object() const;
@@ -272,11 +286,14 @@ public:
void mono_object_disposed(MonoObject *p_obj);
/*
- * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if
+ * If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, ifevent_signal
* 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner.
*/
void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
+ void connect_event_signals();
+ void disconnect_event_signals();
+
virtual void refcount_incremented();
virtual bool refcount_decremented();
@@ -301,7 +318,7 @@ public:
virtual ScriptLanguage *get_language();
- CSharpInstance();
+ CSharpInstance(const Ref<CSharpScript> &p_script);
~CSharpInstance();
};
@@ -309,8 +326,18 @@ struct CSharpScriptBinding {
bool inited;
StringName type_name;
GDMonoClass *wrapper_class;
- Ref<MonoGCHandle> gchandle;
+ MonoGCHandleData gchandle;
Object *owner;
+
+ CSharpScriptBinding() :
+ inited(false),
+ wrapper_class(nullptr),
+ owner(nullptr) {
+ }
+};
+
+class ManagedCallableMiddleman : public Object {
+ GDCLASS(ManagedCallableMiddleman, Object);
};
class CSharpLanguage : public ScriptLanguage {
@@ -320,9 +347,10 @@ class CSharpLanguage : public ScriptLanguage {
static CSharpLanguage *singleton;
- bool finalizing;
+ bool finalizing = false;
+ bool finalized = false;
- GDMono *gdmono;
+ GDMono *gdmono = nullptr;
SelfList<CSharpScript>::List script_list;
Mutex script_instances_mutex;
@@ -337,6 +365,8 @@ class CSharpLanguage : public ScriptLanguage {
Mutex unsafe_object_references_lock;
#endif
+ ManagedCallableMiddleman *managed_callable_middleman = memnew(ManagedCallableMiddleman);
+
struct StringNameCache {
StringName _signal_callback;
@@ -348,17 +378,18 @@ class CSharpLanguage : public ScriptLanguage {
StringName dotctor; // .ctor
StringName on_before_serialize; // OnBeforeSerialize
StringName on_after_deserialize; // OnAfterDeserialize
+ StringName delegate_invoke_method_name;
StringNameCache();
};
- int lang_idx;
+ int lang_idx = -1;
Dictionary scripts_metadata;
- bool scripts_metadata_invalidated;
+ bool scripts_metadata_invalidated = true;
// For debug_break and debug_break_parse
- int _debug_parse_err_line;
+ int _debug_parse_err_line = -1;
String _debug_parse_err_file;
String _debug_error;
@@ -368,7 +399,7 @@ class CSharpLanguage : public ScriptLanguage {
void _on_scripts_domain_unloaded();
#ifdef TOOLS_ENABLED
- EditorPlugin *godotsharp_editor;
+ EditorPlugin *godotsharp_editor = nullptr;
static void _editor_init_callback();
#endif
@@ -389,8 +420,8 @@ public:
_FORCE_INLINE_ EditorPlugin *get_godotsharp_editor() const { return godotsharp_editor; }
#endif
- static void release_script_gchandle(Ref<MonoGCHandle> &p_gchandle);
- static void release_script_gchandle(MonoObject *p_expected_obj, Ref<MonoGCHandle> &p_gchandle);
+ static void release_script_gchandle(MonoGCHandleData &p_gchandle);
+ static void release_script_gchandle(MonoObject *p_expected_obj, MonoGCHandleData &p_gchandle);
bool debug_break(const String &p_error, bool p_allow_continue = true);
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
@@ -410,6 +441,8 @@ public:
return scripts_metadata;
}
+ _FORCE_INLINE_ ManagedCallableMiddleman *get_managed_callable_middleman() const { return managed_callable_middleman; }
+
virtual String get_name() const;
/* LANGUAGE FUNCTIONS */
@@ -426,7 +459,7 @@ public:
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool is_using_templates();
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
- /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const { return true; }
+ /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const { return true; }
virtual String validate_path(const String &p_path) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
@@ -458,7 +491,7 @@ public:
virtual void frame();
/* TODO? */ virtual void get_public_functions(List<MethodInfo> *p_functions) const {}
- /* TODO? */ virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const {}
+ /* TODO? */ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const {}
virtual void reload_all_scripts();
virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
@@ -497,7 +530,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs
index 8717c4901e..4374f21cfa 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-using System.Reflection;
+using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
index b531b6aeee..326c49f096 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
@@ -30,7 +30,7 @@ namespace GodotTools.Core
path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim();
- return rooted ? Path.DirectorySeparatorChar.ToString() + path : path;
+ return rooted ? Path.DirectorySeparatorChar + path : path;
}
private static readonly string driveRoot = Path.GetPathRoot(Environment.CurrentDirectory);
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeConnection/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools.IdeConnection/Properties/AssemblyInfo.cs
index c7c00e66a2..0806d02ca0 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeConnection/Properties/AssemblyInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeConnection/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-using System.Reflection;
+using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs
index 76cb249acf..9afd9adeb1 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs
@@ -1,6 +1,8 @@
using GodotTools.Core;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
namespace GodotTools.ProjectEditor
{
@@ -118,5 +120,40 @@ EndProject";
const string ProjectPlatformsConfig =
@" {{{0}}}.{1}|Any CPU.ActiveCfg = {1}|Any CPU
{{{0}}}.{1}|Any CPU.Build.0 = {1}|Any CPU";
+
+ public static void MigrateFromOldConfigNames(string slnPath)
+ {
+ if (!File.Exists(slnPath))
+ return;
+
+ var input = File.ReadAllText(slnPath);
+
+ if (!Regex.IsMatch(input, Regex.Escape("Tools|Any CPU")))
+ return;
+
+ // This method renames old configurations in solutions to the new ones.
+ //
+ // This is the order configs appear in the solution and what we want to rename them to:
+ // Debug|Any CPU = Debug|Any CPU -> ExportDebug|Any CPU = ExportDebug|Any CPU
+ // Tools|Any CPU = Tools|Any CPU -> Debug|Any CPU = Debug|Any CPU
+ //
+ // But we want to move Tools (now Debug) to the top, so it's easier to rename like this:
+ // Debug|Any CPU = Debug|Any CPU -> Debug|Any CPU = Debug|Any CPU
+ // Release|Any CPU = Release|Any CPU -> ExportDebug|Any CPU = ExportDebug|Any CPU
+ // Tools|Any CPU = Tools|Any CPU -> ExportRelease|Any CPU = ExportRelease|Any CPU
+
+ var dict = new Dictionary<string, string>
+ {
+ {"Debug|Any CPU", "Debug|Any CPU"},
+ {"Release|Any CPU", "ExportDebug|Any CPU"},
+ {"Tools|Any CPU", "ExportRelease|Any CPU"}
+ };
+
+ var regex = new Regex(string.Join("|",dict.Keys.Select(Regex.Escape)));
+ var result = regex.Replace(input,m => dict[m.Value]);
+
+ if (result != input)
+ File.WriteAllText(slnPath, result);
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs
index 36961eb45e..f0e0d1b33d 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectExtensions.cs
@@ -1,5 +1,7 @@
using GodotTools.Core;
using System;
+using System.Collections.Generic;
+using System.IO;
using DotNet.Globbing;
using Microsoft.Build.Construction;
@@ -7,16 +9,15 @@ namespace GodotTools.ProjectEditor
{
public static class ProjectExtensions
{
- public static bool HasItem(this ProjectRootElement root, string itemType, string include)
+ public static ProjectItemElement FindItemOrNull(this ProjectRootElement root, string itemType, string include, bool noCondition = false)
{
- GlobOptions globOptions = new GlobOptions();
- globOptions.Evaluation.CaseInsensitive = false;
+ GlobOptions globOptions = new GlobOptions {Evaluation = {CaseInsensitive = false}};
string normalizedInclude = include.NormalizePath();
foreach (var itemGroup in root.ItemGroups)
{
- if (itemGroup.Condition.Length != 0)
+ if (noCondition && itemGroup.Condition.Length != 0)
continue;
foreach (var item in itemGroup.Items)
@@ -27,18 +28,65 @@ namespace GodotTools.ProjectEditor
var glob = Glob.Parse(item.Include.NormalizePath(), globOptions);
if (glob.IsMatch(normalizedInclude))
- {
- return true;
- }
+ return item;
}
}
- return false;
+ return null;
+ }
+ public static ProjectItemElement FindItemOrNullAbs(this ProjectRootElement root, string itemType, string include, bool noCondition = false)
+ {
+ GlobOptions globOptions = new GlobOptions {Evaluation = {CaseInsensitive = false}};
+
+ string normalizedInclude = Path.GetFullPath(include).NormalizePath();
+
+ foreach (var itemGroup in root.ItemGroups)
+ {
+ if (noCondition && itemGroup.Condition.Length != 0)
+ continue;
+
+ foreach (var item in itemGroup.Items)
+ {
+ if (item.ItemType != itemType)
+ continue;
+
+ var glob = Glob.Parse(Path.GetFullPath(item.Include).NormalizePath(), globOptions);
+
+ if (glob.IsMatch(normalizedInclude))
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ public static IEnumerable<ProjectItemElement> FindAllItemsInFolder(this ProjectRootElement root, string itemType, string folder)
+ {
+ string absFolderNormalizedWithSep = Path.GetFullPath(folder).NormalizePath() + Path.DirectorySeparatorChar;
+
+ foreach (var itemGroup in root.ItemGroups)
+ {
+ foreach (var item in itemGroup.Items)
+ {
+ if (item.ItemType != itemType)
+ continue;
+
+ string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath();
+
+ if (absPathNormalized.StartsWith(absFolderNormalizedWithSep))
+ yield return item;
+ }
+ }
+ }
+
+ public static bool HasItem(this ProjectRootElement root, string itemType, string include, bool noCondition = false)
+ {
+ return root.FindItemOrNull(itemType, include, noCondition) != null;
}
public static bool AddItemChecked(this ProjectRootElement root, string itemType, string include)
{
- if (!root.HasItem(itemType, include))
+ if (!root.HasItem(itemType, include, noCondition: true))
{
root.AddItem(itemType, include);
return true;
@@ -47,6 +95,18 @@ namespace GodotTools.ProjectEditor
return false;
}
+ public static bool RemoveItemChecked(this ProjectRootElement root, string itemType, string include)
+ {
+ var item = root.FindItemOrNullAbs(itemType, include);
+ if (item != null)
+ {
+ item.Parent.RemoveChild(item);
+ return true;
+ }
+
+ return false;
+ }
+
public static Guid GetGuid(this ProjectRootElement root)
{
foreach (var property in root.Properties)
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index 28b7832f90..cbe3afaedd 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -17,30 +17,30 @@ namespace GodotTools.ProjectEditor
string path = Path.Combine(dir, name + ".csproj");
ProjectPropertyGroupElement mainGroup;
- var root = CreateLibraryProject(name, "Tools", out mainGroup);
+ var root = CreateLibraryProject(name, "Debug", out mainGroup);
mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
- mainGroup.SetProperty("ApiConfiguration", "Debug").Condition = " '$(Configuration)' != 'Release' ";
- mainGroup.SetProperty("ApiConfiguration", "Release").Condition = " '$(Configuration)' == 'Release' ";
-
- var toolsGroup = root.AddPropertyGroup();
- toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' ";
- toolsGroup.AddProperty("DebugSymbols", "true");
- toolsGroup.AddProperty("DebugType", "portable");
- toolsGroup.AddProperty("Optimize", "false");
- toolsGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;TOOLS;");
- toolsGroup.AddProperty("ErrorReport", "prompt");
- toolsGroup.AddProperty("WarningLevel", "4");
- toolsGroup.AddProperty("ConsolePause", "false");
+ mainGroup.SetProperty("ApiConfiguration", "Debug").Condition = " '$(Configuration)' != 'ExportRelease' ";
+ mainGroup.SetProperty("ApiConfiguration", "Release").Condition = " '$(Configuration)' == 'ExportRelease' ";
+
+ var debugGroup = root.AddPropertyGroup();
+ debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ";
+ debugGroup.AddProperty("DebugSymbols", "true");
+ debugGroup.AddProperty("DebugType", "portable");
+ debugGroup.AddProperty("Optimize", "false");
+ debugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;TOOLS;");
+ debugGroup.AddProperty("ErrorReport", "prompt");
+ debugGroup.AddProperty("WarningLevel", "4");
+ debugGroup.AddProperty("ConsolePause", "false");
var coreApiRef = root.AddItem("Reference", CoreApiProjectName);
coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", CoreApiProjectName + ".dll"));
coreApiRef.AddMetadata("Private", "False");
var editorApiRef = root.AddItem("Reference", EditorApiProjectName);
- editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
+ editorApiRef.Condition = " '$(Configuration)' == 'Debug' ";
editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", EditorApiProjectName + ".dll"));
editorApiRef.AddMetadata("Private", "False");
@@ -103,24 +103,24 @@ namespace GodotTools.ProjectEditor
mainGroup.AddProperty("TargetFrameworkVersion", "v4.7");
mainGroup.AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
- var debugGroup = root.AddPropertyGroup();
- debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ";
- debugGroup.AddProperty("DebugSymbols", "true");
- debugGroup.AddProperty("DebugType", "portable");
- debugGroup.AddProperty("Optimize", "false");
- debugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;");
- debugGroup.AddProperty("ErrorReport", "prompt");
- debugGroup.AddProperty("WarningLevel", "4");
- debugGroup.AddProperty("ConsolePause", "false");
-
- var releaseGroup = root.AddPropertyGroup();
- releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ";
- releaseGroup.AddProperty("DebugType", "portable");
- releaseGroup.AddProperty("Optimize", "true");
- releaseGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;");
- releaseGroup.AddProperty("ErrorReport", "prompt");
- releaseGroup.AddProperty("WarningLevel", "4");
- releaseGroup.AddProperty("ConsolePause", "false");
+ var exportDebugGroup = root.AddPropertyGroup();
+ exportDebugGroup.Condition = " '$(Configuration)|$(Platform)' == 'ExportDebug|AnyCPU' ";
+ exportDebugGroup.AddProperty("DebugSymbols", "true");
+ exportDebugGroup.AddProperty("DebugType", "portable");
+ exportDebugGroup.AddProperty("Optimize", "false");
+ exportDebugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;");
+ exportDebugGroup.AddProperty("ErrorReport", "prompt");
+ exportDebugGroup.AddProperty("WarningLevel", "4");
+ exportDebugGroup.AddProperty("ConsolePause", "false");
+
+ var exportReleaseGroup = root.AddPropertyGroup();
+ exportReleaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'ExportRelease|AnyCPU' ";
+ exportReleaseGroup.AddProperty("DebugType", "portable");
+ exportReleaseGroup.AddProperty("Optimize", "true");
+ exportReleaseGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;");
+ exportReleaseGroup.AddProperty("ErrorReport", "prompt");
+ exportReleaseGroup.AddProperty("WarningLevel", "4");
+ exportReleaseGroup.AddProperty("ConsolePause", "false");
// References
var referenceGroup = root.AddItemGroup();
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index 233aab45b3..1776b46e6a 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Reflection;
using DotNet.Globbing;
using Microsoft.Build.Construction;
@@ -22,6 +23,79 @@ namespace GodotTools.ProjectEditor
root.Save();
}
+ public static void RenameItemInProjectChecked(string projectPath, string itemType, string oldInclude, string newInclude)
+ {
+ var dir = Directory.GetParent(projectPath).FullName;
+ var root = ProjectRootElement.Open(projectPath);
+ Debug.Assert(root != null);
+
+ var normalizedOldInclude = oldInclude.NormalizePath();
+ var normalizedNewInclude = newInclude.NormalizePath();
+
+ var item = root.FindItemOrNullAbs(itemType, normalizedOldInclude);
+
+ if (item == null)
+ return;
+
+ item.Include = normalizedNewInclude.RelativeToPath(dir).Replace("/", "\\");
+ root.Save();
+ }
+
+ public static void RemoveItemFromProjectChecked(string projectPath, string itemType, string include)
+ {
+ var dir = Directory.GetParent(projectPath).FullName;
+ var root = ProjectRootElement.Open(projectPath);
+ Debug.Assert(root != null);
+
+ var normalizedInclude = include.NormalizePath();
+
+ if (root.RemoveItemChecked(itemType, normalizedInclude))
+ root.Save();
+ }
+
+ public static void RenameItemsToNewFolderInProjectChecked(string projectPath, string itemType, string oldFolder, string newFolder)
+ {
+ var dir = Directory.GetParent(projectPath).FullName;
+ var root = ProjectRootElement.Open(projectPath);
+ Debug.Assert(root != null);
+
+ bool dirty = false;
+
+ var oldFolderNormalized = oldFolder.NormalizePath();
+ var newFolderNormalized = newFolder.NormalizePath();
+ string absOldFolderNormalized = Path.GetFullPath(oldFolderNormalized).NormalizePath();
+ string absNewFolderNormalized = Path.GetFullPath(newFolderNormalized).NormalizePath();
+
+ foreach (var item in root.FindAllItemsInFolder(itemType, oldFolderNormalized))
+ {
+ string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath();
+ string absNewIncludeNormalized = absNewFolderNormalized + absPathNormalized.Substring(absOldFolderNormalized.Length);
+ item.Include = absNewIncludeNormalized.RelativeToPath(dir).Replace("/", "\\");
+ dirty = true;
+ }
+
+ if (dirty)
+ root.Save();
+ }
+
+ public static void RemoveItemsInFolderFromProjectChecked(string projectPath, string itemType, string folder)
+ {
+ var root = ProjectRootElement.Open(projectPath);
+ Debug.Assert(root != null);
+
+ var folderNormalized = folder.NormalizePath();
+
+ var itemsToRemove = root.FindAllItemsInFolder(itemType, folderNormalized).ToList();
+
+ if (itemsToRemove.Count > 0)
+ {
+ foreach (var item in itemsToRemove)
+ item.Parent.RemoveChild(item);
+
+ root.Save();
+ }
+ }
+
private static string[] GetAllFilesRecursive(string rootDirectory, string mask)
{
string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories);
@@ -44,6 +118,7 @@ namespace GodotTools.ProjectEditor
globOptions.Evaluation.CaseInsensitive = false;
var root = ProjectRootElement.Open(projectPath);
+ Debug.Assert(root != null);
foreach (var itemGroup in root.ItemGroups)
{
@@ -85,35 +160,35 @@ namespace GodotTools.ProjectEditor
void AddPropertyIfNotPresent(string name, string condition, string value)
{
if (root.PropertyGroups
- .Any(g => (g.Condition == string.Empty || g.Condition == condition) &&
+ .Any(g => (g.Condition == string.Empty || g.Condition.Trim() == condition) &&
g.Properties
.Any(p => p.Name == name &&
p.Value == value &&
- (p.Condition == condition || g.Condition == condition))))
+ (p.Condition.Trim() == condition || g.Condition.Trim() == condition))))
{
return;
}
- root.AddProperty(name, value).Condition = condition;
+ root.AddProperty(name, value).Condition = " " + condition + " ";
dirty = true;
}
AddPropertyIfNotPresent(name: "ApiConfiguration",
- condition: " '$(Configuration)' != 'Release' ",
+ condition: "'$(Configuration)' != 'ExportRelease'",
value: "Debug");
AddPropertyIfNotPresent(name: "ApiConfiguration",
- condition: " '$(Configuration)' == 'Release' ",
+ condition: "'$(Configuration)' == 'ExportRelease'",
value: "Release");
void SetReferenceHintPath(string referenceName, string condition, string hintPath)
{
foreach (var itemGroup in root.ItemGroups.Where(g =>
- g.Condition == string.Empty || g.Condition == condition))
+ g.Condition.Trim() == string.Empty || g.Condition.Trim() == condition))
{
var references = itemGroup.Items.Where(item =>
item.ItemType == "Reference" &&
item.Include == referenceName &&
- (item.Condition == condition || itemGroup.Condition == condition));
+ (item.Condition.Trim() == condition || itemGroup.Condition.Trim() == condition));
var referencesWithHintPath = references.Where(reference =>
reference.Metadata.Any(m => m.Name == "HintPath"));
@@ -152,7 +227,7 @@ namespace GodotTools.ProjectEditor
}
// Found no Reference item at all. Add it.
- root.AddItem("Reference", referenceName).Condition = condition;
+ root.AddItem("Reference", referenceName).Condition = " " + condition + " ";
dirty = true;
}
@@ -160,7 +235,7 @@ namespace GodotTools.ProjectEditor
const string editorProjectName = "GodotSharpEditor";
const string coreCondition = "";
- const string editorCondition = " '$(Configuration)' == 'Tools' ";
+ const string editorCondition = "'$(Configuration)' == 'Debug'";
var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll";
var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll";
@@ -171,5 +246,104 @@ namespace GodotTools.ProjectEditor
if (dirty)
root.Save();
}
+
+ public static void MigrateFromOldConfigNames(string projectPath)
+ {
+ var root = ProjectRootElement.Open(projectPath);
+ Debug.Assert(root != null);
+
+ bool dirty = false;
+
+ bool hasGodotProjectGeneratorVersion = false;
+ bool foundOldConfiguration = false;
+
+ foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition == string.Empty))
+ {
+ if (!hasGodotProjectGeneratorVersion && propertyGroup.Properties.Any(p => p.Name == "GodotProjectGeneratorVersion"))
+ hasGodotProjectGeneratorVersion = true;
+
+ foreach (var configItem in propertyGroup.Properties
+ .Where(p => p.Condition.Trim() == "'$(Configuration)' == ''" && p.Value == "Tools"))
+ {
+ configItem.Value = "Debug";
+ foundOldConfiguration = true;
+ dirty = true;
+ }
+ }
+
+ if (!hasGodotProjectGeneratorVersion)
+ {
+ root.PropertyGroups.First(g => g.Condition == string.Empty)?
+ .AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
+ dirty = true;
+ }
+
+ if (!foundOldConfiguration)
+ {
+ var toolsConditions = new[]
+ {
+ "'$(Configuration)|$(Platform)' == 'Tools|AnyCPU'",
+ "'$(Configuration)|$(Platform)' != 'Tools|AnyCPU'",
+ "'$(Configuration)' == 'Tools'",
+ "'$(Configuration)' != 'Tools'"
+ };
+
+ foundOldConfiguration = root.PropertyGroups
+ .Any(g => toolsConditions.Any(c => c == g.Condition.Trim()));
+ }
+
+ if (foundOldConfiguration)
+ {
+ void MigrateConfigurationConditions(string oldConfiguration, string newConfiguration)
+ {
+ void MigrateConditions(string oldCondition, string newCondition)
+ {
+ foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition))
+ {
+ propertyGroup.Condition = " " + newCondition + " ";
+ dirty = true;
+ }
+
+ foreach (var propertyGroup in root.PropertyGroups)
+ {
+ foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition))
+ {
+ prop.Condition = " " + newCondition + " ";
+ dirty = true;
+ }
+ }
+
+ foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition))
+ {
+ itemGroup.Condition = " " + newCondition + " ";
+ dirty = true;
+ }
+
+ foreach (var itemGroup in root.ItemGroups)
+ {
+ foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition))
+ {
+ item.Condition = " " + newCondition + " ";
+ dirty = true;
+ }
+ }
+ }
+
+ foreach (var op in new[] {"==", "!="})
+ {
+ MigrateConditions($"'$(Configuration)|$(Platform)' {op} '{oldConfiguration}|AnyCPU'", $"'$(Configuration)|$(Platform)' {op} '{newConfiguration}|AnyCPU'");
+ MigrateConditions($"'$(Configuration)' {op} '{oldConfiguration}'", $"'$(Configuration)' {op} '{newConfiguration}'");
+ }
+ }
+
+ MigrateConfigurationConditions("Debug", "ExportDebug");
+ MigrateConfigurationConditions("Release", "ExportRelease");
+ MigrateConfigurationConditions("Tools", "Debug"); // Must be last
+ }
+
+
+ if (dirty)
+ root.Save();
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs
index 09333850fc..3a0464c9bc 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-using System.Reflection;
+using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
diff --git a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs
index bd7eb59913..3cf495f025 100644
--- a/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/BottomPanel.cs
@@ -166,7 +166,7 @@ namespace GodotTools
Internal.GodotIs32Bits() ? "32" : "64"
};
- bool buildSuccess = BuildManager.BuildProjectBlocking("Tools", godotDefines);
+ bool buildSuccess = BuildManager.BuildProjectBlocking("Debug", godotDefines);
if (!buildSuccess)
return;
@@ -205,9 +205,9 @@ namespace GodotTools
if (what == EditorSettings.NotificationEditorSettingsChanged)
{
var editorBaseControl = editorInterface.GetBaseControl();
- panelTabs.AddStyleboxOverride("panel", editorBaseControl.GetStylebox("DebuggerPanel", "EditorStyles"));
- panelTabs.AddStyleboxOverride("tab_fg", editorBaseControl.GetStylebox("DebuggerTabFG", "EditorStyles"));
- panelTabs.AddStyleboxOverride("tab_bg", editorBaseControl.GetStylebox("DebuggerTabBG", "EditorStyles"));
+ panelTabs.AddThemeStyleboxOverride("panel", editorBaseControl.GetThemeStylebox("DebuggerPanel", "EditorStyles"));
+ panelTabs.AddThemeStyleboxOverride("tab_fg", editorBaseControl.GetThemeStylebox("DebuggerTabFG", "EditorStyles"));
+ panelTabs.AddThemeStyleboxOverride("tab_bg", editorBaseControl.GetThemeStylebox("DebuggerTabBG", "EditorStyles"));
}
}
@@ -258,9 +258,9 @@ namespace GodotTools
RectMinSize = new Vector2(0, 228) * EditorScale,
SizeFlagsVertical = (int)SizeFlags.ExpandFill
};
- panelTabs.AddStyleboxOverride("panel", editorBaseControl.GetStylebox("DebuggerPanel", "EditorStyles"));
- panelTabs.AddStyleboxOverride("tab_fg", editorBaseControl.GetStylebox("DebuggerTabFG", "EditorStyles"));
- panelTabs.AddStyleboxOverride("tab_bg", editorBaseControl.GetStylebox("DebuggerTabBG", "EditorStyles"));
+ panelTabs.AddThemeStyleboxOverride("panel", editorBaseControl.GetThemeStylebox("DebuggerPanel", "EditorStyles"));
+ panelTabs.AddThemeStyleboxOverride("tab_fg", editorBaseControl.GetThemeStylebox("DebuggerTabFG", "EditorStyles"));
+ panelTabs.AddThemeStyleboxOverride("tab_bg", editorBaseControl.GetThemeStylebox("DebuggerTabBG", "EditorStyles"));
AddChild(panelTabs);
{
@@ -280,7 +280,7 @@ namespace GodotTools
Text = "Build Project".TTR(),
FocusMode = FocusModeEnum.None
};
- buildProjectBtn.Connect("pressed", this, nameof(BuildProjectPressed));
+ buildProjectBtn.PressedSignal += BuildProjectPressed;
toolBarHBox.AddChild(buildProjectBtn);
toolBarHBox.AddSpacer(begin: false);
@@ -293,7 +293,7 @@ namespace GodotTools
Visible = false,
FocusMode = FocusModeEnum.None
};
- warningsBtn.Connect("toggled", this, nameof(_WarningsToggled));
+ warningsBtn.Toggled += _WarningsToggled;
toolBarHBox.AddChild(warningsBtn);
errorsBtn = new ToolButton
@@ -304,7 +304,7 @@ namespace GodotTools
Visible = false,
FocusMode = FocusModeEnum.None
};
- errorsBtn.Connect("toggled", this, nameof(_ErrorsToggled));
+ errorsBtn.Toggled += _ErrorsToggled;
toolBarHBox.AddChild(errorsBtn);
toolBarHBox.AddSpacer(begin: false);
@@ -315,7 +315,7 @@ namespace GodotTools
FocusMode = FocusModeEnum.None,
Visible = false
};
- viewLogBtn.Connect("pressed", this, nameof(_ViewLogPressed));
+ viewLogBtn.PressedSignal += _ViewLogPressed;
toolBarHBox.AddChild(viewLogBtn);
var hsc = new HSplitContainer
@@ -326,8 +326,8 @@ namespace GodotTools
panelBuildsTab.AddChild(hsc);
buildTabsList = new ItemList { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill };
- buildTabsList.Connect("item_selected", this, nameof(_BuildTabsItemSelected));
- buildTabsList.Connect("nothing_selected", this, nameof(_BuildTabsNothingSelected));
+ buildTabsList.ItemSelected += _BuildTabsItemSelected;
+ buildTabsList.NothingSelected += _BuildTabsNothingSelected;
hsc.AddChild(buildTabsList);
buildTabs = new TabContainer
diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
index 69a8c9cf4a..520e665595 100644
--- a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
@@ -166,7 +166,7 @@ namespace GodotTools
// Make sure the API assemblies are up to date before building the project.
// We may not have had the chance to update the release API assemblies, and the debug ones
// may have been deleted by the user at some point after they were loaded by the Godot editor.
- string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "Release" ? "Release" : "Debug");
+ string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "ExportRelease" ? "Release" : "Debug");
if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
{
@@ -242,7 +242,7 @@ namespace GodotTools
Internal.GodotIs32Bits() ? "32" : "64"
};
- return BuildProjectBlocking("Tools", godotDefines);
+ return BuildProjectBlocking("Debug", godotDefines);
}
public static void Initialize()
@@ -251,12 +251,12 @@ namespace GodotTools
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
var msbuild = BuildTool.MsBuildMono;
if (OS.IsWindows)
- msbuild = RiderPathManager.IsRider((string) editorSettings.GetSetting(RiderPathManager.EditorPathSettingName))
+ msbuild = RiderPathManager.IsExternalEditorSetToRider(editorSettings)
? BuildTool.JetBrainsMsBuild
: BuildTool.MsBuildVs;
EditorDef("mono/builds/build_tool", msbuild);
-
+
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
{
["type"] = Godot.Variant.Type.Int,
diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs b/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs
index f75fe239e3..938c3d8be1 100644
--- a/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/BuildTab.cs
@@ -46,12 +46,12 @@ namespace GodotTools
get
{
if (!BuildExited)
- return GetIcon("Stop", "EditorIcons");
+ return GetThemeIcon("Stop", "EditorIcons");
if (BuildResult == BuildResults.Error)
- return GetIcon("StatusError", "EditorIcons");
+ return GetThemeIcon("StatusError", "EditorIcons");
- return GetIcon("StatusSuccess", "EditorIcons");
+ return GetThemeIcon("StatusSuccess", "EditorIcons");
}
}
@@ -145,8 +145,8 @@ namespace GodotTools
{
issuesList.Clear();
- using (var warningIcon = GetIcon("Warning", "EditorIcons"))
- using (var errorIcon = GetIcon("Error", "EditorIcons"))
+ using (var warningIcon = GetThemeIcon("Warning", "EditorIcons"))
+ using (var errorIcon = GetThemeIcon("Error", "EditorIcons"))
{
for (int i = 0; i < issues.Count; i++)
{
@@ -251,7 +251,7 @@ namespace GodotTools
base._Ready();
issuesList = new ItemList { SizeFlagsVertical = (int)SizeFlags.ExpandFill };
- issuesList.Connect("item_activated", this, nameof(_IssueActivated));
+ issuesList.ItemActivated += _IssueActivated;
AddChild(issuesList);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
index 9abfda4538..421729cc11 100644
--- a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
@@ -32,18 +32,6 @@ namespace GodotTools
ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include);
}
- public static void FixApiHintPath(string projectPath)
- {
- try
- {
- ProjectUtils.FixApiHintPath(projectPath);
- }
- catch (Exception e)
- {
- GD.PushError(e.ToString());
- }
- }
-
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private static ulong ConvertToTimestamp(this DateTime value)
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
new file mode 100755
index 0000000000..f1765f7e19
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
@@ -0,0 +1,618 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using GodotTools.Internals;
+using Directory = GodotTools.Utils.Directory;
+using File = GodotTools.Utils.File;
+using OS = GodotTools.Utils.OS;
+using Path = System.IO.Path;
+
+namespace GodotTools.Export
+{
+ public struct AotOptions
+ {
+ public bool EnableLLVM;
+ public bool LLVMOnly;
+ public string LLVMPath;
+ public string LLVMOutputPath;
+
+ public bool FullAot;
+
+ private bool _useInterpreter;
+ public bool UseInterpreter { get => _useInterpreter && !LLVMOnly; set => _useInterpreter = value; }
+
+ public string[] ExtraAotOptions;
+ public string[] ExtraOptimizerOptions;
+
+ public string ToolchainPath;
+ }
+
+ public static class AotBuilder
+ {
+ public static void CompileAssemblies(ExportPlugin exporter, AotOptions aotOpts, string[] features, string platform, bool isDebug, string bclDir, string outputDir, string outputDataDir, IDictionary<string, string> assemblies)
+ {
+ // TODO: WASM
+
+ string aotTempDir = Path.Combine(Path.GetTempPath(), $"godot-aot-{Process.GetCurrentProcess().Id}");
+
+ if (!Directory.Exists(aotTempDir))
+ Directory.CreateDirectory(aotTempDir);
+
+ var assembliesPrepared = new Dictionary<string, string>();
+
+ foreach (var dependency in assemblies)
+ {
+ string assemblyName = dependency.Key;
+ string assemblyPath = dependency.Value;
+
+ string assemblyPathInBcl = Path.Combine(bclDir, assemblyName + ".dll");
+
+ if (File.Exists(assemblyPathInBcl))
+ {
+ // Don't create teporaries for assemblies from the BCL
+ assembliesPrepared.Add(assemblyName, assemblyPathInBcl);
+ }
+ else
+ {
+ string tempAssemblyPath = Path.Combine(aotTempDir, assemblyName + ".dll");
+ File.Copy(assemblyPath, tempAssemblyPath);
+ assembliesPrepared.Add(assemblyName, tempAssemblyPath);
+ }
+ }
+
+ if (platform == OS.Platforms.iOS)
+ {
+ var architectures = GetEnablediOSArchs(features).ToArray();
+ CompileAssembliesForiOS(exporter, isDebug, architectures, aotOpts, aotTempDir, assembliesPrepared, bclDir);
+ }
+ else if (platform == OS.Platforms.Android)
+ {
+ var abis = GetEnabledAndroidAbis(features).ToArray();
+ CompileAssembliesForAndroid(exporter, isDebug, abis, aotOpts, aotTempDir, assembliesPrepared, bclDir);
+ }
+ else
+ {
+ string bits = features.Contains("64") ? "64" : features.Contains("32") ? "32" : null;
+ CompileAssembliesForDesktop(exporter, platform, isDebug, bits, aotOpts, aotTempDir, outputDataDir, assembliesPrepared, bclDir);
+ }
+ }
+
+ public static void CompileAssembliesForAndroid(ExportPlugin exporter, bool isDebug, string[] abis, AotOptions aotOpts, string aotTempDir, IDictionary<string, string> assemblies, string bclDir)
+ {
+
+ foreach (var assembly in assemblies)
+ {
+ string assemblyName = assembly.Key;
+ string assemblyPath = assembly.Value;
+
+ // Not sure if the 'lib' prefix is an Android thing or just Godot being picky,
+ // but we use '-aot-' as well just in case to avoid conflicts with other libs.
+ string outputFileName = "lib-aot-" + assemblyName + ".dll.so";
+
+ foreach (string abi in abis)
+ {
+ string aotAbiTempDir = Path.Combine(aotTempDir, abi);
+ string soFilePath = Path.Combine(aotAbiTempDir, outputFileName);
+
+ var compilerArgs = GetAotCompilerArgs(OS.Platforms.Android, isDebug, abi, aotOpts, assemblyPath, soFilePath);
+
+ // Make sure the output directory exists
+ Directory.CreateDirectory(aotAbiTempDir);
+
+ string compilerDirPath = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "aot-compilers", $"{OS.Platforms.Android}-{abi}");
+
+ ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir);
+
+ // The Godot exporter expects us to pass the abi in the tags parameter
+ exporter.AddSharedObject(soFilePath, tags: new[] { abi });
+ }
+ }
+ }
+
+ public static void CompileAssembliesForDesktop(ExportPlugin exporter, string platform, bool isDebug, string bits, AotOptions aotOpts, string aotTempDir, string outputDataDir, IDictionary<string, string> assemblies, string bclDir)
+ {
+ foreach (var assembly in assemblies)
+ {
+ string assemblyName = assembly.Key;
+ string assemblyPath = assembly.Value;
+
+ string outputFileExtension = platform == OS.Platforms.Windows ? ".dll" :
+ platform == OS.Platforms.OSX ? ".dylib" :
+ ".so";
+
+ string outputFileName = assemblyName + ".dll" + outputFileExtension;
+ string tempOutputFilePath = Path.Combine(aotTempDir, outputFileName);
+
+ var compilerArgs = GetAotCompilerArgs(platform, isDebug, bits, aotOpts, assemblyPath, tempOutputFilePath);
+
+ string compilerDirPath = GetMonoCrossDesktopDirName(platform, bits);
+
+ ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir);
+
+ if (platform == OS.Platforms.OSX)
+ {
+ exporter.AddSharedObject(tempOutputFilePath, tags: null);
+ }
+ else
+ {
+ string outputDataLibDir = Path.Combine(outputDataDir, "Mono", platform == OS.Platforms.Windows ? "bin" : "lib");
+ File.Copy(tempOutputFilePath, Path.Combine(outputDataLibDir, outputFileName));
+ }
+ }
+ }
+
+ public static void CompileAssembliesForiOS(ExportPlugin exporter, bool isDebug, string[] architectures, AotOptions aotOpts, string aotTempDir, IDictionary<string, string> assemblies, string bclDir)
+ {
+ var cppCode = new StringBuilder();
+ var aotModuleInfoSymbols = new List<string>(assemblies.Count);
+
+ // {arch: paths}
+ var objFilePathsForiOSArch = architectures.ToDictionary(arch => arch, arch => new List<string>(assemblies.Count));
+
+ foreach (var assembly in assemblies)
+ {
+ string assemblyName = assembly.Key;
+ string assemblyPath = assembly.Value;
+
+ string asmFileName = assemblyName + ".dll.S";
+ string objFileName = assemblyName + ".dll.o";
+
+ foreach (string arch in architectures)
+ {
+ string aotArchTempDir = Path.Combine(aotTempDir, arch);
+ string asmFilePath = Path.Combine(aotArchTempDir, asmFileName);
+
+ var compilerArgs = GetAotCompilerArgs(OS.Platforms.iOS, isDebug, arch, aotOpts, assemblyPath, asmFilePath);
+
+ // Make sure the output directory exists
+ Directory.CreateDirectory(aotArchTempDir);
+
+ string compilerDirPath = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "aot-compilers", $"{OS.Platforms.iOS}-{arch}");
+
+ ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir);
+
+ // Assembling
+ bool isSim = arch == "i386" || arch == "x86_64"; // Shouldn't really happen as we don't do AOT for the simulator
+ string versionMinName = isSim ? "iphonesimulator" : "iphoneos";
+ string iOSPlatformName = isSim ? "iPhoneSimulator" : "iPhoneOS";
+ const string versionMin = "10.0"; // TODO: Turn this hard-coded version into an exporter setting
+ string iOSSdkPath = Path.Combine(XcodeHelper.XcodePath,
+ $"Contents/Developer/Platforms/{iOSPlatformName}.platform/Developer/SDKs/{iOSPlatformName}.sdk");
+
+ string objFilePath = Path.Combine(aotArchTempDir, objFileName);
+
+ var clangArgs = new List<string>()
+ {
+ "-isysroot", iOSSdkPath,
+ "-Qunused-arguments",
+ $"-m{versionMinName}-version-min={versionMin}",
+ "-arch", arch,
+ "-c",
+ "-o", objFilePath,
+ "-x", "assembler"
+ };
+
+ if (isDebug)
+ clangArgs.Add("-DDEBUG");
+
+ clangArgs.Add(asmFilePath);
+
+ int clangExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("clang"), clangArgs);
+ if (clangExitCode != 0)
+ throw new Exception($"Command 'clang' exited with code: {clangExitCode}");
+
+ objFilePathsForiOSArch[arch].Add(objFilePath);
+ }
+
+ aotModuleInfoSymbols.Add($"mono_aot_module_{AssemblyNameToAotSymbol(assemblyName)}_info");
+ }
+
+ // Generate driver code
+ cppCode.AppendLine("#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)");
+ cppCode.AppendLine("#define IOS_DEVICE");
+ cppCode.AppendLine("#endif");
+
+ cppCode.AppendLine("#ifdef IOS_DEVICE");
+ cppCode.AppendLine("extern \"C\" {");
+ cppCode.AppendLine("// Mono API");
+ cppCode.AppendLine(@"
+typedef enum {
+MONO_AOT_MODE_NONE,
+MONO_AOT_MODE_NORMAL,
+MONO_AOT_MODE_HYBRID,
+MONO_AOT_MODE_FULL,
+MONO_AOT_MODE_LLVMONLY,
+MONO_AOT_MODE_INTERP,
+MONO_AOT_MODE_INTERP_LLVMONLY,
+MONO_AOT_MODE_LLVMONLY_INTERP,
+MONO_AOT_MODE_LAST = 1000,
+} MonoAotMode;");
+ cppCode.AppendLine("void mono_jit_set_aot_mode(MonoAotMode);");
+ cppCode.AppendLine("void mono_aot_register_module(void *);");
+
+ if (aotOpts.UseInterpreter)
+ {
+ cppCode.AppendLine("void mono_ee_interp_init(const char *);");
+ cppCode.AppendLine("void mono_icall_table_init();");
+ cppCode.AppendLine("void mono_marshal_ilgen_init();");
+ cppCode.AppendLine("void mono_method_builder_ilgen_init();");
+ cppCode.AppendLine("void mono_sgen_mono_ilgen_init();");
+ }
+
+ foreach (string symbol in aotModuleInfoSymbols)
+ cppCode.AppendLine($"extern void *{symbol};");
+
+ cppCode.AppendLine("void gd_mono_setup_aot() {");
+
+ foreach (string symbol in aotModuleInfoSymbols)
+ cppCode.AppendLine($"\tmono_aot_register_module({symbol});");
+
+ if (aotOpts.UseInterpreter)
+ {
+ cppCode.AppendLine("\tmono_icall_table_init();");
+ cppCode.AppendLine("\tmono_marshal_ilgen_init();");
+ cppCode.AppendLine("\tmono_method_builder_ilgen_init();");
+ cppCode.AppendLine("\tmono_sgen_mono_ilgen_init();");
+ cppCode.AppendLine("\tmono_ee_interp_init(0);");
+ }
+
+ string aotModeStr = null;
+
+ if (aotOpts.LLVMOnly)
+ {
+ aotModeStr = "MONO_AOT_MODE_LLVMONLY"; // --aot=llvmonly
+ }
+ else
+ {
+ if (aotOpts.UseInterpreter)
+ aotModeStr = "MONO_AOT_MODE_INTERP"; // --aot=interp or --aot=interp,full
+ else if (aotOpts.FullAot)
+ aotModeStr = "MONO_AOT_MODE_FULL"; // --aot=full
+ }
+
+ // One of the options above is always set for iOS
+ Debug.Assert(aotModeStr != null);
+
+ cppCode.AppendLine($"\tmono_jit_set_aot_mode({aotModeStr});");
+
+ cppCode.AppendLine("} // gd_mono_setup_aot");
+ cppCode.AppendLine("} // extern \"C\"");
+ cppCode.AppendLine("#endif // IOS_DEVICE");
+
+ // Add the driver code to the Xcode project
+ exporter.AddIosCppCode(cppCode.ToString());
+
+ // Archive the AOT object files into a static library
+
+ var arFilePathsForAllArchs = new List<string>();
+ string projectAssemblyName = GodotSharpEditor.ProjectAssemblyName;
+
+ foreach (var archPathsPair in objFilePathsForiOSArch)
+ {
+ string arch = archPathsPair.Key;
+ var objFilePaths = archPathsPair.Value;
+
+ string arOutputFilePath = Path.Combine(aotTempDir, $"lib-aot-{projectAssemblyName}.{arch}.a");
+
+ var arArgs = new List<string>()
+ {
+ "cr",
+ arOutputFilePath
+ };
+
+ foreach (string objFilePath in objFilePaths)
+ arArgs.Add(objFilePath);
+
+ int arExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("ar"), arArgs);
+ if (arExitCode != 0)
+ throw new Exception($"Command 'ar' exited with code: {arExitCode}");
+
+ arFilePathsForAllArchs.Add(arOutputFilePath);
+ }
+
+ // It's lipo time
+
+ string fatOutputFileName = $"lib-aot-{projectAssemblyName}.fat.a";
+ string fatOutputFilePath = Path.Combine(aotTempDir, fatOutputFileName);
+
+ var lipoArgs = new List<string>();
+ lipoArgs.Add("-create");
+ lipoArgs.AddRange(arFilePathsForAllArchs);
+ lipoArgs.Add("-output");
+ lipoArgs.Add(fatOutputFilePath);
+
+ int lipoExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("lipo"), lipoArgs);
+ if (lipoExitCode != 0)
+ throw new Exception($"Command 'lipo' exited with code: {lipoExitCode}");
+
+ // TODO: Add the AOT lib and interpreter libs as device only to supress warnings when targeting the simulator
+
+ // Add the fat AOT static library to the Xcode project
+ exporter.AddIosProjectStaticLib(fatOutputFilePath);
+
+ // Add the required Mono libraries to the Xcode project
+
+ string MonoLibFile(string libFileName) => libFileName + ".iphone.fat.a";
+
+ string MonoLibFromTemplate(string libFileName) =>
+ Path.Combine(Internal.FullTemplatesDir, "iphone-mono-libs", MonoLibFile(libFileName));
+
+ exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmonosgen-2.0"));
+
+ exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-native"));
+
+ if (aotOpts.UseInterpreter)
+ {
+ exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-ee-interp"));
+ exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-icall-table"));
+ exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-ilgen"));
+ }
+
+ // TODO: Turn into an exporter option
+ bool enableProfiling = false;
+ if (enableProfiling)
+ exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-profiler-log"));
+
+ // Add frameworks required by Mono to the Xcode project
+ exporter.AddIosFramework("libiconv.tbd");
+ exporter.AddIosFramework("GSS.framework");
+ exporter.AddIosFramework("CFNetwork.framework");
+
+ // Force load and export dynamic are needed for the linker to not strip required symbols.
+ // In theory we shouldn't be relying on this for P/Invoked functions (as is the case with
+ // functions in System.Native/libmono-native). Instead, we should use cecil to search for
+ // DllImports in assemblies and pass them to 'ld' as '-u/--undefined {pinvoke_symbol}'.
+ exporter.AddIosLinkerFlags("-rdynamic");
+ exporter.AddIosLinkerFlags($"-force_load \"$(SRCROOT)/{MonoLibFile("libmono-native")}\"");
+ }
+
+ /// Converts an assembly name to a valid symbol name in the same way the AOT compiler does
+ private static string AssemblyNameToAotSymbol(string assemblyName)
+ {
+ var builder = new StringBuilder();
+
+ foreach (var charByte in Encoding.UTF8.GetBytes(assemblyName))
+ {
+ char @char = (char)charByte;
+ builder.Append(Char.IsLetterOrDigit(@char) || @char == '_' ? @char : '_');
+ }
+
+ return builder.ToString();
+ }
+
+ private static IEnumerable<string> GetAotCompilerArgs(string platform, bool isDebug, string target, AotOptions aotOpts, string assemblyPath, string outputFilePath)
+ {
+ // TODO: LLVM
+
+ bool aotSoftDebug = isDebug && !aotOpts.EnableLLVM;
+ bool aotDwarfDebug = platform == OS.Platforms.iOS;
+
+ var aotOptions = new List<string>();
+ var optimizerOptions = new List<string>();
+
+ if (aotOpts.LLVMOnly)
+ {
+ aotOptions.Add("llvmonly");
+ }
+ else
+ {
+ // Can be both 'interp' and 'full'
+ if (aotOpts.UseInterpreter)
+ aotOptions.Add("interp");
+ if (aotOpts.FullAot)
+ aotOptions.Add("full");
+ }
+
+ aotOptions.Add(aotSoftDebug ? "soft-debug" : "nodebug");
+
+ if (aotDwarfDebug)
+ aotOptions.Add("dwarfdebug");
+
+ if (platform == OS.Platforms.Android)
+ {
+ string abi = target;
+
+ string androidToolchain = aotOpts.ToolchainPath;
+
+ if (string.IsNullOrEmpty(androidToolchain))
+ {
+ androidToolchain = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "android-toolchains", $"{abi}"); // TODO: $"{abi}-{apiLevel}{(clang?"clang":"")}"
+
+ if (!Directory.Exists(androidToolchain))
+ throw new FileNotFoundException("Missing android toolchain. Specify one in the AOT export settings.");
+ }
+ else if (!Directory.Exists(androidToolchain))
+ {
+ throw new FileNotFoundException("Android toolchain not found: " + androidToolchain);
+ }
+
+ var androidToolPrefixes = new Dictionary<string, string>
+ {
+ ["armeabi-v7a"] = "arm-linux-androideabi-",
+ ["arm64-v8a"] = "aarch64-linux-android-",
+ ["x86"] = "i686-linux-android-",
+ ["x86_64"] = "x86_64-linux-android-"
+ };
+
+ aotOptions.Add("tool-prefix=" + Path.Combine(androidToolchain, "bin", androidToolPrefixes[abi]));
+
+ string triple = GetAndroidTriple(abi);
+ aotOptions.Add($"mtriple={triple}");
+ }
+ else if (platform == OS.Platforms.iOS)
+ {
+ if (!aotOpts.LLVMOnly && !aotOpts.UseInterpreter)
+ optimizerOptions.Add("gsharedvt");
+
+ aotOptions.Add("static");
+
+ // I couldn't get the Mono cross-compiler to do assembling, so we'll have to do it ourselves
+ aotOptions.Add("asmonly");
+
+ aotOptions.Add("direct-icalls");
+
+ if (aotSoftDebug)
+ aotOptions.Add("no-direct-calls");
+
+ if (aotOpts.LLVMOnly || !aotOpts.UseInterpreter)
+ aotOptions.Add("direct-pinvoke");
+
+ string arch = target;
+ aotOptions.Add($"mtriple={arch}-ios");
+ }
+
+ aotOptions.Add($"outfile={outputFilePath}");
+
+ if (aotOpts.EnableLLVM)
+ {
+ aotOptions.Add($"llvm-path={aotOpts.LLVMPath}");
+ aotOptions.Add($"llvm-outfile={aotOpts.LLVMOutputPath}");
+ }
+
+ if (aotOpts.ExtraAotOptions.Length > 0)
+ aotOptions.AddRange(aotOpts.ExtraAotOptions);
+
+ if (aotOpts.ExtraOptimizerOptions.Length > 0)
+ optimizerOptions.AddRange(aotOpts.ExtraOptimizerOptions);
+
+ string EscapeOption(string option) => option.Contains(',') ? $"\"{option}\"" : option;
+ string OptionsToString(IEnumerable<string> options) => string.Join(",", options.Select(EscapeOption));
+
+ var runtimeArgs = new List<string>();
+
+ // The '--debug' runtime option is required when using the 'soft-debug' and 'dwarfdebug' AOT options
+ if (aotSoftDebug || aotDwarfDebug)
+ runtimeArgs.Add("--debug");
+
+ if (aotOpts.EnableLLVM)
+ runtimeArgs.Add("--llvm");
+
+ runtimeArgs.Add(aotOptions.Count > 0 ? $"--aot={OptionsToString(aotOptions)}" : "--aot");
+
+ if (optimizerOptions.Count > 0)
+ runtimeArgs.Add($"-O={OptionsToString(optimizerOptions)}");
+
+ runtimeArgs.Add(assemblyPath);
+
+ return runtimeArgs;
+ }
+
+ private static void ExecuteCompiler(string compiler, IEnumerable<string> compilerArgs, string bclDir)
+ {
+ // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
+ string CmdLineArgsToString(IEnumerable<string> args)
+ {
+ // Not perfect, but as long as we are careful...
+ return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
+ }
+
+ using (var process = new Process())
+ {
+ process.StartInfo = new ProcessStartInfo(compiler, CmdLineArgsToString(compilerArgs))
+ {
+ UseShellExecute = false
+ };
+
+ process.StartInfo.EnvironmentVariables.Remove("MONO_ENV_OPTIONS");
+ process.StartInfo.EnvironmentVariables.Remove("MONO_THREADS_SUSPEND");
+ process.StartInfo.EnvironmentVariables.Add("MONO_PATH", bclDir);
+
+ Console.WriteLine($"Running: \"{process.StartInfo.FileName}\" {process.StartInfo.Arguments}");
+
+ if (!process.Start())
+ throw new Exception("Failed to start process for Mono AOT compiler");
+
+ process.WaitForExit();
+
+ if (process.ExitCode != 0)
+ throw new Exception($"Mono AOT compiler exited with code: {process.ExitCode}");
+ }
+ }
+
+ private static IEnumerable<string> GetEnablediOSArchs(string[] features)
+ {
+ var iosArchs = new[]
+ {
+ "armv7",
+ "arm64"
+ };
+
+ return iosArchs.Where(features.Contains);
+ }
+
+ private static IEnumerable<string> GetEnabledAndroidAbis(string[] features)
+ {
+ var androidAbis = new[]
+ {
+ "armeabi-v7a",
+ "arm64-v8a",
+ "x86",
+ "x86_64"
+ };
+
+ return androidAbis.Where(features.Contains);
+ }
+
+ private static string GetAndroidTriple(string abi)
+ {
+ var abiArchs = new Dictionary<string, string>
+ {
+ ["armeabi-v7a"] = "armv7",
+ ["arm64-v8a"] = "aarch64-v8a",
+ ["x86"] = "i686",
+ ["x86_64"] = "x86_64"
+ };
+
+ string arch = abiArchs[abi];
+
+ return $"{arch}-linux-android";
+ }
+
+ private static string GetMonoCrossDesktopDirName(string platform, string bits)
+ {
+ switch (platform)
+ {
+ case OS.Platforms.Windows:
+ case OS.Platforms.UWP:
+ {
+ string arch = bits == "64" ? "x86_64" : "i686";
+ return $"windows-{arch}";
+ }
+ case OS.Platforms.OSX:
+ {
+ Debug.Assert(bits == null || bits == "64");
+ string arch = "x86_64";
+ return $"{platform}-{arch}";
+ }
+ case OS.Platforms.X11:
+ case OS.Platforms.Server:
+ {
+ string arch = bits == "64" ? "x86_64" : "i686";
+ return $"linux-{arch}";
+ }
+ case OS.Platforms.Haiku:
+ {
+ string arch = bits == "64" ? "x86_64" : "i686";
+ return $"{platform}-{arch}";
+ }
+ default:
+ throw new NotSupportedException($"Platform not supported: {platform}");
+ }
+ }
+
+ // TODO: Replace this for a specific path for each platform
+ private static string FindCrossCompiler(string monoCrossBin)
+ {
+ string exeExt = OS.IsWindows ? ".exe" : string.Empty;
+
+ var files = new DirectoryInfo(monoCrossBin).GetFiles($"*mono-sgen{exeExt}", SearchOption.TopDirectoryOnly);
+ if (files.Length > 0)
+ return Path.Combine(monoCrossBin, files[0].Name);
+
+ throw new FileNotFoundException($"Cannot find the mono runtime executable in {monoCrossBin}");
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 3e2a8c22a9..d782d4e61b 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -29,15 +29,13 @@ namespace GodotTools.Export
All = CJK | MidEast | Other | Rare | West
}
- private void AddI18NAssemblies(Godot.Collections.Dictionary<string, string> assemblies, string platform)
+ private void AddI18NAssemblies(Godot.Collections.Dictionary<string, string> assemblies, string bclDir)
{
- var codesets = (I18NCodesets) ProjectSettings.GetSetting("mono/export/i18n_codesets");
+ var codesets = (I18NCodesets)ProjectSettings.GetSetting("mono/export/i18n_codesets");
if (codesets == I18NCodesets.None)
return;
- string bclDir = DeterminePlatformBclDir(platform) ?? typeof(object).Assembly.Location.GetBaseDir();
-
void AddI18NAssembly(string name) => assemblies.Add(name, Path.Combine(bclDir, $"{name}.dll"));
AddI18NAssembly("I18N");
@@ -73,6 +71,7 @@ namespace GodotTools.Export
GlobalDef("mono/export/aot/enabled", false);
GlobalDef("mono/export/aot/full_aot", false);
+ GlobalDef("mono/export/aot/use_interpreter", true);
// --aot or --aot=opt1,opt2 (use 'mono --aot=help AuxAssembly.dll' to list AOT options)
GlobalDef("mono/export/aot/extra_aot_options", new string[] { });
@@ -86,9 +85,11 @@ namespace GodotTools.Export
private void AddFile(string srcPath, string dstPath, bool remap = false)
{
+ // Add file to the PCK
AddFile(dstPath.Replace("\\", "/"), File.ReadAllBytes(srcPath), remap);
}
+ // With this method we can override how a file is exported in the PCK
public override void _ExportFile(string path, string type, string[] features)
{
base._ExportFile(path, type, features);
@@ -96,7 +97,7 @@ namespace GodotTools.Export
if (type != Internal.CSharpLanguageType)
return;
- if (Path.GetExtension(path) != $".{Internal.CSharpLanguageExtension}")
+ if (Path.GetExtension(path) != Internal.CSharpLanguageExtension)
throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path));
// TODO What if the source file is not part of the game's C# project
@@ -110,6 +111,8 @@ namespace GodotTools.Export
// Sadly, Godot prints errors when adding an empty file (nothing goes wrong, it's just noise).
// Because of this, we add a file which contains a line break.
AddFile(path, System.Text.Encoding.UTF8.GetBytes("\n"), remap: false);
+
+ // Tell the Godot exporter that we already took care of the file
Skip();
}
}
@@ -150,7 +153,7 @@ namespace GodotTools.Export
string outputDir = new FileInfo(path).Directory?.FullName ??
throw new FileNotFoundException("Base directory not found");
- string buildConfig = isDebug ? "Debug" : "Release";
+ string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
@@ -167,12 +170,7 @@ namespace GodotTools.Export
var dependencies = new Godot.Collections.Dictionary<string, string>();
- var projectDllName = (string)ProjectSettings.GetSetting("application/config/name");
- if (projectDllName.Empty())
- {
- projectDllName = "UnnamedProject";
- }
-
+ string projectDllName = GodotSharpEditor.ProjectAssemblyName;
string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig);
string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll");
@@ -189,10 +187,12 @@ namespace GodotTools.Export
dependencies["Mono.Android"] = monoAndroidAssemblyPath;
}
+ string bclDir = DeterminePlatformBclDir(platform);
+
var initialDependencies = dependencies.Duplicate();
- internal_GetExportedAssemblyDependencies(initialDependencies, buildConfig, DeterminePlatformBclDir(platform), dependencies);
+ internal_GetExportedAssemblyDependencies(initialDependencies, buildConfig, bclDir, dependencies);
- AddI18NAssemblies(dependencies, platform);
+ AddI18NAssemblies(dependencies, bclDir);
string outputDataDir = null;
@@ -227,11 +227,34 @@ namespace GodotTools.Export
}
}
- // AOT
+ // AOT compilation
+ bool aotEnabled = platform == OS.Platforms.iOS || (bool)ProjectSettings.GetSetting("mono/export/aot/enabled");
- if ((bool)ProjectSettings.GetSetting("mono/export/aot/enabled"))
+ if (aotEnabled)
{
- AotCompileDependencies(features, platform, isDebug, outputDir, outputDataDir, dependencies);
+ string aotToolchainPath = null;
+
+ if (platform == OS.Platforms.Android)
+ aotToolchainPath = (string)ProjectSettings.GetSetting("mono/export/aot/android_toolchain_path");
+
+ if (aotToolchainPath == string.Empty)
+ aotToolchainPath = null; // Don't risk it being used as current working dir
+
+ // TODO: LLVM settings are hard-coded and disabled for now
+ var aotOpts = new AotOptions
+ {
+ EnableLLVM = false,
+ LLVMOnly = false,
+ LLVMPath = "",
+ LLVMOutputPath = "",
+ FullAot = platform == OS.Platforms.iOS || (bool)(ProjectSettings.GetSetting("mono/export/aot/full_aot") ?? false),
+ UseInterpreter = (bool)ProjectSettings.GetSetting("mono/export/aot/use_interpreter"),
+ ExtraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options") ?? new string[] { },
+ ExtraOptimizerOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options") ?? new string[] { },
+ ToolchainPath = aotToolchainPath
+ };
+
+ AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, dependencies);
}
}
@@ -258,7 +281,8 @@ namespace GodotTools.Export
{
string target = isDebug ? "release_debug" : "release";
- // NOTE: Bits is ok for now as all platforms with a data directory have it, but that may change in the future.
+ // NOTE: Bits is ok for now as all platforms with a data directory only have one or two architectures.
+ // However, this may change in the future if we add arm linux or windows desktop templates.
string bits = features.Contains("64") ? "64" : "32";
string TemplateDirName() => $"data.mono.{platform}.{bits}.{target}";
@@ -284,7 +308,7 @@ namespace GodotTools.Export
if (!validTemplatePathFound)
throw new FileNotFoundException("Data template directory not found", templateDirPath);
- string outputDataDir = Path.Combine(outputDir, DataDirName);
+ string outputDataDir = Path.Combine(outputDir, DetermineDataDirNameForProject());
if (Directory.Exists(outputDataDir))
Directory.Delete(outputDataDir, recursive: true); // Clean first
@@ -304,333 +328,10 @@ namespace GodotTools.Export
return outputDataDir;
}
- private void AotCompileDependencies(string[] features, string platform, bool isDebug, string outputDir, string outputDataDir, IDictionary<string, string> dependencies)
- {
- // TODO: WASM
-
- string bclDir = DeterminePlatformBclDir(platform) ?? typeof(object).Assembly.Location.GetBaseDir();
-
- string aotTempDir = Path.Combine(Path.GetTempPath(), $"godot-aot-{Process.GetCurrentProcess().Id}");
-
- if (!Directory.Exists(aotTempDir))
- Directory.CreateDirectory(aotTempDir);
-
- var assemblies = new Dictionary<string, string>();
-
- foreach (var dependency in dependencies)
- {
- string assemblyName = dependency.Key;
- string assemblyPath = dependency.Value;
-
- string assemblyPathInBcl = Path.Combine(bclDir, assemblyName + ".dll");
-
- if (File.Exists(assemblyPathInBcl))
- {
- // Don't create teporaries for assemblies from the BCL
- assemblies.Add(assemblyName, assemblyPathInBcl);
- }
- else
- {
- string tempAssemblyPath = Path.Combine(aotTempDir, assemblyName + ".dll");
- File.Copy(assemblyPath, tempAssemblyPath);
- assemblies.Add(assemblyName, tempAssemblyPath);
- }
- }
-
- foreach (var assembly in assemblies)
- {
- string assemblyName = assembly.Key;
- string assemblyPath = assembly.Value;
-
- string sharedLibExtension = platform == OS.Platforms.Windows ? ".dll" :
- platform == OS.Platforms.OSX ? ".dylib" :
- platform == OS.Platforms.HTML5 ? ".wasm" :
- ".so";
-
- string outputFileName = assemblyName + ".dll" + sharedLibExtension;
-
- if (platform == OS.Platforms.Android)
- {
- // Not sure if the 'lib' prefix is an Android thing or just Godot being picky,
- // but we use '-aot-' as well just in case to avoid conflicts with other libs.
- outputFileName = "lib-aot-" + outputFileName;
- }
-
- string outputFilePath = null;
- string tempOutputFilePath;
-
- switch (platform)
- {
- case OS.Platforms.OSX:
- tempOutputFilePath = Path.Combine(aotTempDir, outputFileName);
- break;
- case OS.Platforms.Android:
- tempOutputFilePath = Path.Combine(aotTempDir, "%%ANDROID_ABI%%", outputFileName);
- break;
- case OS.Platforms.HTML5:
- tempOutputFilePath = Path.Combine(aotTempDir, outputFileName);
- outputFilePath = Path.Combine(outputDir, outputFileName);
- break;
- default:
- tempOutputFilePath = Path.Combine(aotTempDir, outputFileName);
- outputFilePath = Path.Combine(outputDataDir, "Mono", platform == OS.Platforms.Windows ? "bin" : "lib", outputFileName);
- break;
- }
-
- var data = new Dictionary<string, string>();
- var enabledAndroidAbis = platform == OS.Platforms.Android ? GetEnabledAndroidAbis(features).ToArray() : null;
-
- if (platform == OS.Platforms.Android)
- {
- Debug.Assert(enabledAndroidAbis != null);
-
- foreach (var abi in enabledAndroidAbis)
- {
- data["abi"] = abi;
- var outputFilePathForThisAbi = tempOutputFilePath.Replace("%%ANDROID_ABI%%", abi);
-
- AotCompileAssembly(platform, isDebug, data, assemblyPath, outputFilePathForThisAbi);
-
- AddSharedObject(outputFilePathForThisAbi, tags: new[] { abi });
- }
- }
- else
- {
- string bits = features.Contains("64") ? "64" : features.Contains("64") ? "32" : null;
-
- if (bits != null)
- data["bits"] = bits;
-
- AotCompileAssembly(platform, isDebug, data, assemblyPath, tempOutputFilePath);
-
- if (platform == OS.Platforms.OSX)
- {
- AddSharedObject(tempOutputFilePath, tags: null);
- }
- else
- {
- Debug.Assert(outputFilePath != null);
- File.Copy(tempOutputFilePath, outputFilePath);
- }
- }
- }
- }
-
- private static void AotCompileAssembly(string platform, bool isDebug, Dictionary<string, string> data, string assemblyPath, string outputFilePath)
- {
- // Make sure the output directory exists
- Directory.CreateDirectory(outputFilePath.GetBaseDir());
-
- string exeExt = OS.IsWindows ? ".exe" : string.Empty;
-
- string monoCrossDirName = DetermineMonoCrossDirName(platform, data);
- string monoCrossRoot = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "aot-compilers", monoCrossDirName);
- string monoCrossBin = Path.Combine(monoCrossRoot, "bin");
-
- string toolPrefix = DetermineToolPrefix(monoCrossBin);
- string monoExeName = System.IO.File.Exists(Path.Combine(monoCrossBin, $"{toolPrefix}mono{exeExt}")) ? "mono" : "mono-sgen";
-
- string compilerCommand = Path.Combine(monoCrossBin, $"{toolPrefix}{monoExeName}{exeExt}");
-
- bool fullAot = (bool)ProjectSettings.GetSetting("mono/export/aot/full_aot");
-
- string EscapeOption(string option) => option.Contains(',') ? $"\"{option}\"" : option;
- string OptionsToString(IEnumerable<string> options) => string.Join(",", options.Select(EscapeOption));
-
- var aotOptions = new List<string>();
- var optimizerOptions = new List<string>();
-
- if (fullAot)
- aotOptions.Add("full");
-
- aotOptions.Add(isDebug ? "soft-debug" : "nodebug");
-
- if (platform == OS.Platforms.Android)
- {
- string abi = data["abi"];
-
- string androidToolchain = (string)ProjectSettings.GetSetting("mono/export/aot/android_toolchain_path");
-
- if (string.IsNullOrEmpty(androidToolchain))
- {
- androidToolchain = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "android-toolchains", $"{abi}"); // TODO: $"{abi}-{apiLevel}{(clang?"clang":"")}"
-
- if (!Directory.Exists(androidToolchain))
- throw new FileNotFoundException("Missing android toolchain. Specify one in the AOT export settings.");
- }
- else if (!Directory.Exists(androidToolchain))
- {
- throw new FileNotFoundException("Android toolchain not found: " + androidToolchain);
- }
-
- var androidToolPrefixes = new Dictionary<string, string>
- {
- ["armeabi-v7a"] = "arm-linux-androideabi-",
- ["arm64-v8a"] = "aarch64-linux-android-",
- ["x86"] = "i686-linux-android-",
- ["x86_64"] = "x86_64-linux-android-"
- };
-
- aotOptions.Add("tool-prefix=" + Path.Combine(androidToolchain, "bin", androidToolPrefixes[abi]));
-
- string triple = GetAndroidTriple(abi);
- aotOptions.Add($"mtriple={triple}");
- }
-
- aotOptions.Add($"outfile={outputFilePath}");
-
- var extraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options");
- var extraOptimizerOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options");
-
- if (extraAotOptions.Length > 0)
- aotOptions.AddRange(extraAotOptions);
-
- if (extraOptimizerOptions.Length > 0)
- optimizerOptions.AddRange(extraOptimizerOptions);
-
- var compilerArgs = new List<string>();
-
- if (isDebug)
- compilerArgs.Add("--debug"); // Required for --aot=soft-debug
-
- compilerArgs.Add(aotOptions.Count > 0 ? $"--aot={OptionsToString(aotOptions)}" : "--aot");
-
- if (optimizerOptions.Count > 0)
- compilerArgs.Add($"-O={OptionsToString(optimizerOptions)}");
-
- compilerArgs.Add(ProjectSettings.GlobalizePath(assemblyPath));
-
- // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
- string CmdLineArgsToString(IEnumerable<string> args)
- {
- // Not perfect, but as long as we are careful...
- return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
- }
-
- using (var process = new Process())
- {
- process.StartInfo = new ProcessStartInfo(compilerCommand, CmdLineArgsToString(compilerArgs))
- {
- UseShellExecute = false
- };
-
- string platformBclDir = DeterminePlatformBclDir(platform);
- process.StartInfo.EnvironmentVariables.Add("MONO_PATH", string.IsNullOrEmpty(platformBclDir) ?
- typeof(object).Assembly.Location.GetBaseDir() :
- platformBclDir);
-
- Console.WriteLine($"Running: \"{process.StartInfo.FileName}\" {process.StartInfo.Arguments}");
-
- if (!process.Start())
- throw new Exception("Failed to start process for Mono AOT compiler");
-
- process.WaitForExit();
-
- if (process.ExitCode != 0)
- throw new Exception($"Mono AOT compiler exited with error code: {process.ExitCode}");
-
- if (!System.IO.File.Exists(outputFilePath))
- throw new Exception("Mono AOT compiler finished successfully but the output file is missing");
- }
- }
-
- private static string DetermineMonoCrossDirName(string platform, IReadOnlyDictionary<string, string> data)
- {
- switch (platform)
- {
- case OS.Platforms.Windows:
- case OS.Platforms.UWP:
- {
- string arch = data["bits"] == "64" ? "x86_64" : "i686";
- return $"windows-{arch}";
- }
- case OS.Platforms.OSX:
- {
- string arch = "x86_64";
- return $"{platform}-{arch}";
- }
- case OS.Platforms.X11:
- case OS.Platforms.Server:
- {
- string arch = data["bits"] == "64" ? "x86_64" : "i686";
- return $"linux-{arch}";
- }
- case OS.Platforms.Haiku:
- {
- string arch = data["bits"] == "64" ? "x86_64" : "i686";
- return $"{platform}-{arch}";
- }
- case OS.Platforms.Android:
- {
- string abi = data["abi"];
- return $"{platform}-{abi}";
- }
- case OS.Platforms.HTML5:
- return "wasm-wasm32";
- default:
- throw new NotSupportedException($"Platform not supported: {platform}");
- }
- }
-
- private static string DetermineToolPrefix(string monoCrossBin)
- {
- string exeExt = OS.IsWindows ? ".exe" : string.Empty;
-
- if (System.IO.File.Exists(Path.Combine(monoCrossBin, $"mono{exeExt}")))
- return string.Empty;
-
- if (System.IO.File.Exists(Path.Combine(monoCrossBin, $"mono-sgen{exeExt}" + exeExt)))
- return string.Empty;
-
- var files = new DirectoryInfo(monoCrossBin).GetFiles($"*mono{exeExt}" + exeExt, SearchOption.TopDirectoryOnly);
- if (files.Length > 0)
- {
- string fileName = files[0].Name;
- return fileName.Substring(0, fileName.Length - $"mono{exeExt}".Length);
- }
-
- files = new DirectoryInfo(monoCrossBin).GetFiles($"*mono-sgen{exeExt}" + exeExt, SearchOption.TopDirectoryOnly);
- if (files.Length > 0)
- {
- string fileName = files[0].Name;
- return fileName.Substring(0, fileName.Length - $"mono-sgen{exeExt}".Length);
- }
-
- throw new FileNotFoundException($"Cannot find the mono runtime executable in {monoCrossBin}");
- }
-
- private static IEnumerable<string> GetEnabledAndroidAbis(string[] features)
- {
- var androidAbis = new[]
- {
- "armeabi-v7a",
- "arm64-v8a",
- "x86",
- "x86_64"
- };
-
- return androidAbis.Where(features.Contains);
- }
-
- private static string GetAndroidTriple(string abi)
- {
- var abiArchs = new Dictionary<string, string>
- {
- ["armeabi-v7a"] = "armv7",
- ["arm64-v8a"] = "aarch64-v8a",
- ["x86"] = "i686",
- ["x86_64"] = "x86_64"
- };
-
- string arch = abiArchs[abi];
-
- return $"{arch}-linux-android";
- }
-
private static bool PlatformHasTemplateDir(string platform)
{
// OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest.
- return !new[] { OS.Platforms.OSX, OS.Platforms.Android, OS.Platforms.HTML5 }.Contains(platform);
+ return !new[] { OS.Platforms.OSX, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform);
}
private static string DeterminePlatformFromFeatures(IEnumerable<string> features)
@@ -665,7 +366,7 @@ namespace GodotTools.Export
if (PlatformRequiresCustomBcl(platform))
throw new FileNotFoundException($"Missing BCL (Base Class Library) for platform: {platform}");
- platformBclDir = null; // Use the one we're running on
+ platformBclDir = typeof(object).Assembly.Location; // Use the one we're running on
}
}
@@ -678,7 +379,7 @@ namespace GodotTools.Export
/// </summary>
private static bool PlatformRequiresCustomBcl(string platform)
{
- if (new[] { OS.Platforms.Android, OS.Platforms.HTML5 }.Contains(platform))
+ if (new[] { OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform))
return true;
// The 'net_4_x' BCL is not compatible between Windows and the other platforms.
@@ -707,6 +408,8 @@ namespace GodotTools.Export
return "net_4_x";
case OS.Platforms.Android:
return "monodroid";
+ case OS.Platforms.iOS:
+ return "monotouch";
case OS.Platforms.HTML5:
return "wasm";
default:
@@ -714,14 +417,11 @@ namespace GodotTools.Export
}
}
- private static string DataDirName
+ private static string DetermineDataDirNameForProject()
{
- get
- {
- var appName = (string)ProjectSettings.GetSetting("application/config/name");
- string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false);
- return $"data_{appNameSafe}";
- }
+ var appName = (string)ProjectSettings.GetSetting("application/config/name");
+ string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false);
+ return $"data_{appNameSafe}";
}
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs b/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
new file mode 100755
index 0000000000..219b7a698a
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
@@ -0,0 +1,93 @@
+using System;
+using System.IO;
+
+namespace GodotTools.Export
+{
+ public static class XcodeHelper
+ {
+ private static string _XcodePath = null;
+
+ public static string XcodePath
+ {
+ get
+ {
+ if (_XcodePath == null)
+ {
+ _XcodePath = FindXcode();
+
+ if (_XcodePath == null)
+ throw new Exception("Could not find Xcode");
+ }
+
+ return _XcodePath;
+ }
+ }
+
+ private static string FindSelectedXcode()
+ {
+ var outputWrapper = new Godot.Collections.Array();
+
+ int exitCode = Godot.OS.Execute("xcode-select", new string[] { "--print-path" }, blocking: true, output: outputWrapper);
+
+ if (exitCode == 0)
+ {
+ string output = (string)outputWrapper[0];
+ return output.Trim();
+ }
+
+ Console.Error.WriteLine($"'xcode-select --print-path' exited with code: {exitCode}");
+
+ return null;
+ }
+
+ public static string FindXcode()
+ {
+ string selectedXcode = FindSelectedXcode();
+ if (selectedXcode != null)
+ {
+ if (Directory.Exists(Path.Combine(selectedXcode, "Contents", "Developer")))
+ return selectedXcode;
+
+ // The path already pointed to Contents/Developer
+ var dirInfo = new DirectoryInfo(selectedXcode);
+ if (dirInfo.Name != "Developer" || dirInfo.Parent.Name != "Contents")
+ {
+ Console.WriteLine(Path.GetDirectoryName(selectedXcode));
+ Console.WriteLine(System.IO.Directory.GetParent(selectedXcode).Name);
+ Console.Error.WriteLine("Unrecognized path for selected Xcode");
+ }
+ else
+ {
+ return System.IO.Path.GetFullPath($"{selectedXcode}/../..");
+ }
+ }
+ else
+ {
+ Console.Error.WriteLine("Could not find the selected Xcode; trying with a hint path");
+ }
+
+ const string XcodeHintPath = "/Applications/Xcode.app";
+
+ if (Directory.Exists(XcodeHintPath))
+ {
+ if (Directory.Exists(Path.Combine(XcodeHintPath, "Contents", "Developer")))
+ return XcodeHintPath;
+
+ Console.Error.WriteLine($"Found Xcode at '{XcodeHintPath}' but it's missing the 'Contents/Developer' sub-directory");
+ }
+
+ return null;
+ }
+
+ public static string FindXcodeTool(string toolName)
+ {
+ string XcodeDefaultToolchain = Path.Combine(XcodePath, "Contents", "Developer", "Toolchains", "XcodeDefault.xctoolchain");
+
+ string path = Path.Combine(XcodeDefaultToolchain, "usr", "bin", toolName);
+ if (File.Exists(path))
+ return path;
+
+ throw new FileNotFoundException($"Cannot find Xcode tool: {toolName}");
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 147bc95bb8..c9d7dd26f8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -13,6 +13,7 @@ using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
using OS = GodotTools.Utils.OS;
+using Path = System.IO.Path;
namespace GodotTools
{
@@ -35,6 +36,17 @@ namespace GodotTools
public BottomPanel BottomPanel { get; private set; }
+ public static string ProjectAssemblyName
+ {
+ get
+ {
+ var projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name");
+ if (string.IsNullOrEmpty(projectAssemblyName))
+ projectAssemblyName = "UnnamedProject";
+ return projectAssemblyName;
+ }
+ }
+
private bool CreateProjectSolution()
{
using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 3))
@@ -44,9 +56,7 @@ namespace GodotTools
string resourceDir = ProjectSettings.GlobalizePath("res://");
string path = resourceDir;
- string name = (string)ProjectSettings.GetSetting("application/config/name");
- if (name.Empty())
- name = "UnnamedProject";
+ string name = ProjectAssemblyName;
string guid = CsProjOperations.GenerateGameProject(path, name);
@@ -61,7 +71,7 @@ namespace GodotTools
{
Guid = guid,
PathRelativeToSolution = name + ".csproj",
- Configs = new List<string> { "Debug", "Release", "Tools" }
+ Configs = new List<string> {"Debug", "ExportDebug", "ExportRelease"}
};
solution.AddNewProject(name, projectInfo);
@@ -118,19 +128,12 @@ namespace GodotTools
{
bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
aboutDialogCheckBox.Pressed = showOnStart;
- aboutDialog.PopupCenteredMinsize();
- }
-
- private void _ToggleAboutDialogOnStart(bool enabled)
- {
- bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
- if (showOnStart != enabled)
- editorSettings.SetSetting("mono/editor/show_info_on_start", enabled);
+ aboutDialog.PopupCentered();
}
- private void _MenuOptionPressed(MenuOptions id)
+ private void _MenuOptionPressed(int id)
{
- switch (id)
+ switch ((MenuOptions)id)
{
case MenuOptions.CreateSln:
CreateProjectSolution();
@@ -163,11 +166,41 @@ namespace GodotTools
bool showInfoDialog = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
if (showInfoDialog)
{
- aboutDialog.PopupExclusive = true;
+ aboutDialog.Exclusive = true;
_ShowAboutDialog();
// Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on.
- aboutDialog.PopupExclusive = false;
+ aboutDialog.Exclusive = false;
}
+
+ var fileSystemDock = GetEditorInterface().GetFileSystemDock();
+
+ fileSystemDock.FilesMoved += (file, newFile) =>
+ {
+ if (Path.GetExtension(file) == Internal.CSharpLanguageExtension)
+ {
+ ProjectUtils.RenameItemInProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile",
+ ProjectSettings.GlobalizePath(file), ProjectSettings.GlobalizePath(newFile));
+ }
+ };
+
+ fileSystemDock.FileRemoved += file =>
+ {
+ if (Path.GetExtension(file) == Internal.CSharpLanguageExtension)
+ ProjectUtils.RemoveItemFromProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile",
+ ProjectSettings.GlobalizePath(file));
+ };
+
+ fileSystemDock.FolderMoved += (oldFolder, newFolder) =>
+ {
+ ProjectUtils.RenameItemsToNewFolderInProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile",
+ ProjectSettings.GlobalizePath(oldFolder), ProjectSettings.GlobalizePath(newFolder));
+ };
+
+ fileSystemDock.FolderRemoved += oldFolder =>
+ {
+ ProjectUtils.RemoveItemsInFolderFromProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile",
+ ProjectSettings.GlobalizePath(oldFolder));
+ };
}
}
@@ -179,9 +212,9 @@ namespace GodotTools
public void ShowErrorDialog(string message, string title = "Error")
{
- errorDialog.WindowTitle = title;
+ errorDialog.Title = title;
errorDialog.DialogText = message;
- errorDialog.PopupCenteredMinsize();
+ errorDialog.PopupCentered();
}
private static string _vsCodePath = string.Empty;
@@ -210,7 +243,7 @@ namespace GodotTools
string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
RiderPathManager.OpenFile(GodotSharpDirs.ProjectSlnPath, scriptPath, line);
return Error.Ok;
- }
+ }
case ExternalEditorId.MonoDevelop:
{
string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
@@ -346,11 +379,10 @@ namespace GodotTools
bottomPanelBtn = AddControlToBottomPanel(BottomPanel, "Mono".TTR());
- AddChild(new HotReloadAssemblyWatcher { Name = "HotReloadAssemblyWatcher" });
+ AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"});
menuPopup = new PopupMenu();
menuPopup.Hide();
- menuPopup.SetAsToplevel(true);
AddToolSubmenuItem("Mono", menuPopup);
@@ -359,7 +391,7 @@ namespace GodotTools
menuPopup.AddItem("About C# support".TTR(), (int)MenuOptions.AboutCSharp);
aboutDialog = new AcceptDialog();
editorBaseControl.AddChild(aboutDialog);
- aboutDialog.WindowTitle = "Important: C# support is not feature-complete";
+ aboutDialog.Title = "Important: C# support is not feature-complete";
// We don't use DialogText as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox
// we'll add. Instead we add containers and a new autowrapped Label inside.
@@ -373,7 +405,7 @@ namespace GodotTools
aboutVBox.AddChild(aboutHBox);
var aboutIcon = new TextureRect();
- aboutIcon.Texture = aboutIcon.GetIcon("NodeWarning", "EditorIcons");
+ aboutIcon.Texture = aboutIcon.GetThemeIcon("NodeWarning", "EditorIcons");
aboutHBox.AddChild(aboutIcon);
var aboutLabel = new Label();
@@ -394,15 +426,34 @@ namespace GodotTools
EditorDef("mono/editor/show_info_on_start", true);
// CheckBox in main container
- aboutDialogCheckBox = new CheckBox { Text = "Show this warning when starting the editor" };
- aboutDialogCheckBox.Connect("toggled", this, nameof(_ToggleAboutDialogOnStart));
+ aboutDialogCheckBox = new CheckBox {Text = "Show this warning when starting the editor"};
+ aboutDialogCheckBox.Toggled += enabled =>
+ {
+ bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
+ if (showOnStart != enabled)
+ editorSettings.SetSetting("mono/editor/show_info_on_start", enabled);
+ };
aboutVBox.AddChild(aboutDialogCheckBox);
}
if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
{
- // Make sure the existing project has Api assembly references configured correctly
- CsProjOperations.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
+ try
+ {
+ // Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease
+ DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath);
+ // Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease
+ ProjectUtils.MigrateFromOldConfigNames(GodotSharpDirs.ProjectCsProjPath);
+
+ // Apply the other fixes after configurations are migrated
+
+ // Make sure the existing project has Api assembly references configured correctly
+ ProjectUtils.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
+ }
+ catch (Exception e)
+ {
+ GD.PushError(e.ToString());
+ }
}
else
{
@@ -410,7 +461,7 @@ namespace GodotTools
menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln);
}
- menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed));
+ menuPopup.IdPressed += _MenuOptionPressed;
var buildButton = new ToolButton
{
@@ -418,7 +469,7 @@ namespace GodotTools
HintTooltip = "Build solution",
FocusMode = Control.FocusModeEnum.None
};
- buildButton.Connect("pressed", this, nameof(_BuildSolutionPressed));
+ buildButton.PressedSignal += _BuildSolutionPressed;
AddControlToContainer(CustomControlContainer.Toolbar, buildButton);
// External editor settings
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index 379dfd9f7d..ac9379adf8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -51,7 +51,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Build\MsBuildFinder.cs" />
+ <Compile Include="Export\AotBuilder.cs" />
<Compile Include="Export\ExportPlugin.cs" />
+ <Compile Include="Export\XcodeHelper.cs" />
<Compile Include="ExternalEditorId.cs" />
<Compile Include="Ides\GodotIdeManager.cs" />
<Compile Include="Ides\GodotIdeServer.cs" />
diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
index 0ed567afd1..ae05710f4f 100644
--- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
@@ -10,7 +10,7 @@ namespace GodotTools
public override void _Notification(int what)
{
- if (what == MainLoop.NotificationWmFocusIn)
+ if (what == Node.NotificationWmFocusIn)
{
RestartTimer();
@@ -40,7 +40,7 @@ namespace GodotTools
OneShot = false,
WaitTime = (float)EditorDef("mono/assembly_watch_interval_sec", 0.5)
};
- watchTimer.Connect("timeout", this, nameof(TimerTimeout));
+ watchTimer.Timeout += TimerTimeout;
AddChild(watchTimer);
watchTimer.Start();
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
index 77740f0e53..e3a4fa7b45 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
@@ -162,7 +162,7 @@ namespace GodotTools.Ides.Rider
private static string GetToolboxRiderRootPath(string localAppData)
{
- var toolboxPath = Path.Combine(localAppData, @"JetBrains\Toolbox");
+ var toolboxPath = Path.Combine(localAppData, @"JetBrains/Toolbox");
var settingsJson = Path.Combine(toolboxPath, ".settings.json");
if (File.Exists(settingsJson))
@@ -172,7 +172,7 @@ namespace GodotTools.Ides.Rider
toolboxPath = path;
}
- var toolboxRiderRootPath = Path.Combine(toolboxPath, @"apps\Rider");
+ var toolboxRiderRootPath = Path.Combine(toolboxPath, @"apps/Rider");
return toolboxRiderRootPath;
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index ee5677a6a8..16f91a0925 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -55,6 +55,11 @@ namespace GodotTools.Ides.Rider
}
}
+ public static bool IsExternalEditorSetToRider(EditorSettings editorSettings)
+ {
+ return editorSettings.HasSetting(EditorPathSettingName) && IsRider((string) editorSettings.GetSetting(EditorPathSettingName));
+ }
+
public static bool IsRider(string path)
{
if (string.IsNullOrEmpty(path))
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 2e121ba879..026a7db89c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -8,7 +8,7 @@ namespace GodotTools.Internals
public static class Internal
{
public const string CSharpLanguageType = "CSharpScript";
- public const string CSharpLanguageExtension = "cs";
+ public const string CSharpLanguageExtension = ".cs";
public static string UpdateApiAssembliesFromPrebuilt(string config) =>
internal_UpdateApiAssembliesFromPrebuilt(config);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 279e67b3eb..b057ac12c6 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
+using JetBrains.Annotations;
namespace GodotTools.Utils
{
@@ -26,6 +27,7 @@ namespace GodotTools.Utils
public const string UWP = "UWP";
public const string Haiku = "Haiku";
public const string Android = "Android";
+ public const string iOS = "iOS";
public const string HTML5 = "HTML5";
}
@@ -33,11 +35,12 @@ namespace GodotTools.Utils
{
public const string Windows = "windows";
public const string OSX = "osx";
- public const string X11 = "x11";
+ public const string X11 = "linuxbsd";
public const string Server = "server";
public const string UWP = "uwp";
public const string Haiku = "haiku";
public const string Android = "android";
+ public const string iOS = "iphone";
public const string HTML5 = "javascript";
}
@@ -50,6 +53,7 @@ namespace GodotTools.Utils
[Names.UWP] = Platforms.UWP,
[Names.Haiku] = Platforms.Haiku,
[Names.Android] = Platforms.Android,
+ [Names.iOS] = Platforms.iOS,
[Names.HTML5] = Platforms.HTML5
};
@@ -65,6 +69,7 @@ namespace GodotTools.Utils
private static readonly Lazy<bool> _isUWP = new Lazy<bool>(() => IsOS(Names.UWP));
private static readonly Lazy<bool> _isHaiku = new Lazy<bool>(() => IsOS(Names.Haiku));
private static readonly Lazy<bool> _isAndroid = new Lazy<bool>(() => IsOS(Names.Android));
+ private static readonly Lazy<bool> _isiOS = new Lazy<bool>(() => IsOS(Names.iOS));
private static readonly Lazy<bool> _isHTML5 = new Lazy<bool>(() => IsOS(Names.HTML5));
public static bool IsWindows => _isWindows.Value || IsUWP;
@@ -74,10 +79,11 @@ namespace GodotTools.Utils
public static bool IsUWP => _isUWP.Value;
public static bool IsHaiku => _isHaiku.Value;
public static bool IsAndroid => _isAndroid.Value;
+ public static bool IsiOS => _isiOS.Value;
public static bool IsHTML5 => _isHTML5.Value;
private static bool? _isUnixCache;
- private static readonly string[] UnixLikePlatforms = { Names.OSX, Names.X11, Names.Server, Names.Haiku, Names.Android };
+ private static readonly string[] UnixLikePlatforms = { Names.OSX, Names.X11, Names.Server, Names.Haiku, Names.Android, Names.iOS };
public static bool IsUnixLike()
{
@@ -91,12 +97,12 @@ namespace GodotTools.Utils
public static char PathSep => IsWindows ? ';' : ':';
- public static string PathWhich(string name)
+ public static string PathWhich([NotNull] string name)
{
return IsWindows ? PathWhichWindows(name) : PathWhichUnix(name);
}
- private static string PathWhichWindows(string name)
+ private static string PathWhichWindows([NotNull] string name)
{
string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? new string[] { };
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
@@ -121,7 +127,7 @@ namespace GodotTools.Utils
select path + ext).FirstOrDefault(File.Exists);
}
- private static string PathWhichUnix(string name)
+ private static string PathWhichUnix([NotNull] string name)
{
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
@@ -163,5 +169,33 @@ namespace GodotTools.Utils
User32Dll.AllowSetForegroundWindow(process.Id); // allows application to focus itself
}
}
+
+ public static int ExecuteCommand(string command, IEnumerable<string> arguments)
+ {
+ // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
+ string CmdLineArgsToString(IEnumerable<string> args)
+ {
+ // Not perfect, but as long as we are careful...
+ return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
+ }
+
+ var startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments));
+
+ Console.WriteLine($"Executing: \"{startInfo.FileName}\" {startInfo.Arguments}");
+
+ // Print the output
+ startInfo.RedirectStandardOutput = false;
+ startInfo.RedirectStandardError = false;
+
+ startInfo.UseShellExecute = false;
+
+ using (var process = new Process { StartInfo = startInfo })
+ {
+ process.Start();
+ process.WaitForExit();
+
+ return process.ExitCode;
+ }
+ }
}
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 908c72c591..71bb8ff851 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -76,7 +76,7 @@
#define GLUE_HEADER_FILE "glue_header.h"
#define ICALL_PREFIX "godot_icall_"
#define SINGLETON_ICALL_SUFFIX "_get_singleton"
-#define ICALL_GET_METHODBIND ICALL_PREFIX "Object_ClassDB_get_method"
+#define ICALL_GET_METHODBIND "__ClassDB_get_method"
#define C_LOCAL_RET "ret"
#define C_LOCAL_VARARG_RET "vararg_ret"
@@ -95,6 +95,10 @@
#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
+#define C_METHOD_MANAGED_TO_CALLABLE C_NS_MONOMARSHAL "::managed_to_callable"
+#define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL "::callable_to_managed"
+#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
+#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
#define BINDINGS_GENERATOR_VERSION UINT32_C(11)
@@ -407,7 +411,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append("\"/>");
} else {
// Try to find as global enum constant
- const EnumInterface *target_ienum = NULL;
+ const EnumInterface *target_ienum = nullptr;
for (const List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) {
target_ienum = &E->get();
@@ -445,7 +449,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append("\"/>");
} else {
// Try to find as enum constant in the current class
- const EnumInterface *target_ienum = NULL;
+ const EnumInterface *target_ienum = nullptr;
for (const List<EnumInterface>::Element *E = target_itype->enums.front(); E; E = E->next()) {
target_ienum = &E->get();
@@ -504,23 +508,23 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append(tag);
xml_output.append("</c>");
} else if (tag == "PackedByteArray") {
- xml_output.append("<see cref=\"byte\"/>");
+ xml_output.append("<see cref=\"T:byte[]\"/>");
} else if (tag == "PackedInt32Array") {
- xml_output.append("<see cref=\"int\"/>");
+ xml_output.append("<see cref=\"T:int[]\"/>");
+ } else if (tag == "PackedInt64Array") {
+ xml_output.append("<see cref=\"T:long[]\"/>");
} else if (tag == "PackedFloat32Array") {
-#ifdef REAL_T_IS_DOUBLE
- xml_output.append("<see cref=\"double\"/>");
-#else
- xml_output.append("<see cref=\"float\"/>");
-#endif
+ xml_output.append("<see cref=\"T:float[]\"/>");
+ } else if (tag == "PackedFloat64Array") {
+ xml_output.append("<see cref=\"T:double[]\"/>");
} else if (tag == "PackedStringArray") {
- xml_output.append("<see cref=\"string\"/>");
+ xml_output.append("<see cref=\"T:string[]\"/>");
} else if (tag == "PackedVector2Array") {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>");
+ xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector2[]\"/>");
} else if (tag == "PackedVector3Array") {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>");
+ xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector3[]\"/>");
} else if (tag == "PackedColorArray") {
- xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>");
+ xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Color[]\"/>");
} else {
const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
@@ -778,7 +782,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
const ConstantInterface &iconstant = E->get();
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
- String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
+ String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), nullptr);
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
if (summary_lines.size()) {
@@ -839,7 +843,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
const ConstantInterface &iconstant = F->get();
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
- String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
+ String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), nullptr);
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
if (summary_lines.size()) {
@@ -932,7 +936,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
"using System.Runtime.CompilerServices;\n"
"\n");
cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
+ cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 "{");
cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
@@ -944,7 +948,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
#define ADD_INTERNAL_CALL(m_icall) \
if (!m_icall.editor_only) { \
cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.append(INDENT2 "internal extern static "); \
+ cs_icalls_content.append(INDENT2 "internal static extern "); \
cs_icalls_content.append(m_icall.im_type_out + " "); \
cs_icalls_content.append(m_icall.name + "("); \
cs_icalls_content.append(m_icall.im_sig + ");\n"); \
@@ -1046,7 +1050,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
#define ADD_INTERNAL_CALL(m_icall) \
if (m_icall.editor_only) { \
cs_icalls_content.append(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.append(INDENT2 "internal extern static "); \
+ cs_icalls_content.append(INDENT2 "internal static extern "); \
cs_icalls_content.append(m_icall.im_type_out + " "); \
cs_icalls_content.append(m_icall.name + "("); \
cs_icalls_content.append(m_icall.im_sig + ");\n"); \
@@ -1312,7 +1316,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(itype.proxy_name);
output.append(").Name);\n" INDENT4 "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n");
- output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
@@ -1324,7 +1328,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
} else if (is_derived_type) {
// Add member fields
- output.append(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
@@ -1363,6 +1367,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
}
+ for (const List<SignalInterface>::Element *E = itype.signals_.front(); E; E = E->next()) {
+ const SignalInterface &isignal = E->get();
+ Error method_err = _generate_cs_signal(itype, isignal, output);
+ ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
+ "Failed to generate signal '" + isignal.name + "' for class '" + itype.name + "'.");
+ }
+
if (itype.is_singleton) {
InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr");
@@ -1395,7 +1406,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
const TypeInterface *current_type = &p_itype;
while (!setter && current_type->base_name != StringName()) {
OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
- ERR_FAIL_COND_V(!base_match, ERR_BUG);
+ ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
current_type = &base_match.get();
setter = current_type->find_method_by_name(p_iprop.setter);
}
@@ -1406,7 +1417,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
current_type = &p_itype;
while (!getter && current_type->base_name != StringName()) {
OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
- ERR_FAIL_COND_V(!base_match, ERR_BUG);
+ ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
current_type = &base_match.get();
getter = current_type->find_method_by_name(p_iprop.getter);
}
@@ -1424,7 +1435,16 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
}
if (getter && setter) {
- ERR_FAIL_COND_V(getter->return_type.cname != setter->arguments.back()->get().type.cname, ERR_BUG);
+ const ArgumentInterface &setter_first_arg = setter->arguments.back()->get();
+ if (getter->return_type.cname != setter_first_arg.type.cname) {
+ // Special case for Node::set_name
+ bool whitelisted = getter->return_type.cname == name_cache.type_StringName &&
+ setter_first_arg.type.cname == name_cache.type_String;
+
+ ERR_FAIL_COND_V_MSG(!whitelisted, ERR_BUG,
+ "Return type from getter doesn't match first argument of setter for property: '" +
+ p_itype.name + "." + String(p_iprop.cname) + "'.");
+ }
}
const TypeReference &proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
@@ -1474,7 +1494,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
if (idx_arg.type.cname != name_cache.type_int) {
// Assume the index parameter is an enum
const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type);
- CRASH_COND(idx_arg_type == NULL);
+ CRASH_COND(idx_arg_type == nullptr);
p_output.append("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index));
} else {
p_output.append(itos(p_iprop.index));
@@ -1502,7 +1522,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
if (idx_arg.type.cname != name_cache.type_int) {
// Assume the index parameter is an enum
const TypeInterface *idx_arg_type = _get_type_or_null(idx_arg.type);
- CRASH_COND(idx_arg_type == NULL);
+ CRASH_COND(idx_arg_type == nullptr);
p_output.append("(" + idx_arg_type->proxy_name + ")" + itos(p_iprop.index) + ", ");
} else {
p_output.append(itos(p_iprop.index) + ", ");
@@ -1525,7 +1545,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
- String method_bind_field = "method_bind_" + itos(p_method_bind_count);
+ String method_bind_field = "__method_bind_" + itos(p_method_bind_count);
String arguments_sig;
String cs_in_statements;
@@ -1611,8 +1631,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Generate method
{
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr ");
- p_output.append(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
+ p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static readonly IntPtr ");
+ p_output.append(method_bind_field);
+ p_output.append(" = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
p_output.append(p_imethod.name);
p_output.append("\");\n");
}
@@ -1726,6 +1747,106 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
return OK;
}
+Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output) {
+ String arguments_sig;
+
+ // Retrieve information from the arguments
+ for (const List<ArgumentInterface>::Element *F = p_isignal.arguments.front(); F; F = F->next()) {
+ const ArgumentInterface &iarg = F->get();
+ const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+
+ // Add the current arguments to the signature
+
+ if (F != p_isignal.arguments.front())
+ arguments_sig += ", ";
+
+ arguments_sig += arg_type->cs_type;
+ arguments_sig += " ";
+ arguments_sig += iarg.name;
+ }
+
+ // Generate signal
+ {
+ if (p_isignal.method_doc && p_isignal.method_doc->description.size()) {
+ String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype);
+ Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
+
+ if (summary_lines.size()) {
+ p_output.append(MEMBER_BEGIN "/// <summary>\n");
+
+ for (int i = 0; i < summary_lines.size(); i++) {
+ p_output.append(INDENT2 "/// ");
+ p_output.append(summary_lines[i]);
+ p_output.append("\n");
+ }
+
+ p_output.append(INDENT2 "/// </summary>");
+ }
+ }
+
+ if (p_isignal.is_deprecated) {
+ if (p_isignal.deprecation_message.empty())
+ WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
+
+ p_output.append(MEMBER_BEGIN "[Obsolete(\"");
+ p_output.append(p_isignal.deprecation_message);
+ p_output.append("\")]");
+ }
+
+ String delegate_name = p_isignal.proxy_name;
+ delegate_name += "Handler"; // Delegate name is [SignalName]Handler
+
+ // Generate delegate
+ p_output.append(MEMBER_BEGIN "public delegate void ");
+ p_output.append(delegate_name);
+ p_output.append("(");
+ p_output.append(arguments_sig);
+ p_output.append(");\n");
+
+ // TODO:
+ // Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded?
+ // If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here.
+
+ // Cached signal name (StringName)
+ p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static StringName __signal_name_");
+ p_output.append(p_isignal.name);
+ p_output.append(" = \"");
+ p_output.append(p_isignal.name);
+ p_output.append("\";\n");
+
+ // Generate event
+ p_output.append(MEMBER_BEGIN "[Signal]" MEMBER_BEGIN "public ");
+
+ if (p_itype.is_singleton)
+ p_output.append("static ");
+
+ p_output.append("event ");
+ p_output.append(delegate_name);
+ p_output.append(" ");
+ p_output.append(p_isignal.proxy_name);
+ p_output.append("\n" OPEN_BLOCK_L2);
+
+ if (p_itype.is_singleton)
+ p_output.append("add => Singleton.Connect(__signal_name_");
+ else
+ p_output.append("add => Connect(__signal_name_");
+
+ p_output.append(p_isignal.name);
+ p_output.append(", new Callable(value));\n");
+
+ if (p_itype.is_singleton)
+ p_output.append(INDENT3 "remove => Singleton.Disconnect(__signal_name_");
+ else
+ p_output.append(INDENT3 "remove => Disconnect(__signal_name_");
+
+ p_output.append(p_isignal.name);
+ p_output.append(", new Callable(value));\n");
+ p_output.append(CLOSE_BLOCK_L2);
+ }
+
+ return OK;
+}
+
Error BindingsGenerator::generate_glue(const String &p_output_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
@@ -2000,7 +2121,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
if (return_type->is_object_type) {
ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type;
- initialization = return_type->is_reference ? "" : " = NULL";
+ initialization = return_type->is_reference ? "" : " = nullptr";
} else {
ptrcall_return_type = return_type->c_type;
}
@@ -2009,10 +2130,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
p_output.append(" " C_LOCAL_RET);
p_output.append(initialization + ";\n");
- String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "NULL" : return_type->c_type_out + "()";
+ String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "nullptr" : return_type->c_type_out + "()";
if (return_type->ret_as_byref_arg) {
- p_output.append("\tif (" CS_PARAM_INSTANCE " == NULL) { *arg_ret = ");
+ p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
p_output.append(fail_ret);
p_output.append("; ERR_FAIL_MSG(\"Parameter ' arg_ret ' is null.\"); }\n");
} else {
@@ -2066,7 +2187,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
p_output.append(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
- p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
+ p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "nullptr");
p_output.append(", total_length, vcall_error);\n");
if (!ret_void) {
@@ -2077,8 +2198,8 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
} else {
p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
- p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
- p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "NULL);\n");
+ p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "nullptr, ");
+ p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "nullptr);\n");
}
if (!ret_void) {
@@ -2120,11 +2241,11 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(con
// Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead.
const Map<StringName, TypeInterface>::Element *int_match = builtin_types.find(name_cache.type_int);
- ERR_FAIL_NULL_V(int_match, NULL);
+ ERR_FAIL_NULL_V(int_match, nullptr);
return &int_match->get();
}
- return NULL;
+ return nullptr;
}
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placeholder(const TypeReference &p_typeref) {
@@ -2291,7 +2412,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
iprop.proxy_name = iprop.proxy_name.replace("/", "__"); // Some members have a slash...
- iprop.prop_doc = NULL;
+ iprop.prop_doc = nullptr;
for (int i = 0; i < itype.class_doc->properties.size(); i++) {
const DocData::PropertyDoc &prop_doc = itype.class_doc->properties[i];
@@ -2336,7 +2457,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
PropertyInfo return_info = method_info.return_val;
- MethodBind *m = imethod.is_virtual ? NULL : ClassDB::get_method(type_cname, method_info.name);
+ MethodBind *m = imethod.is_virtual ? nullptr : ClassDB::get_method(type_cname, method_info.name);
imethod.is_vararg = m && m->is_vararg();
@@ -2479,13 +2600,92 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
}
}
+ // Populate signals
+
+ const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map;
+ const StringName *k = nullptr;
+
+ while ((k = signal_map.next(k))) {
+ SignalInterface isignal;
+
+ const MethodInfo &method_info = signal_map.get(*k);
+
+ isignal.name = method_info.name;
+ isignal.cname = method_info.name;
+
+ int argc = method_info.arguments.size();
+
+ for (int i = 0; i < argc; i++) {
+ PropertyInfo arginfo = method_info.arguments[i];
+
+ String orig_arg_name = arginfo.name;
+
+ ArgumentInterface iarg;
+ iarg.name = orig_arg_name;
+
+ if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ iarg.type.cname = arginfo.class_name;
+ iarg.type.is_enum = true;
+ } else if (arginfo.class_name != StringName()) {
+ iarg.type.cname = arginfo.class_name;
+ } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ iarg.type.cname = arginfo.hint_string;
+ } else if (arginfo.type == Variant::NIL) {
+ iarg.type.cname = name_cache.type_Variant;
+ } else {
+ if (arginfo.type == Variant::INT) {
+ iarg.type.cname = _get_int_type_name_from_meta(GodotTypeInfo::METADATA_NONE);
+ } else if (arginfo.type == Variant::FLOAT) {
+ iarg.type.cname = _get_float_type_name_from_meta(GodotTypeInfo::METADATA_NONE);
+ } else {
+ iarg.type.cname = Variant::get_type_name(arginfo.type);
+ }
+ }
+
+ iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
+
+ isignal.add_argument(iarg);
+ }
+
+ isignal.proxy_name = escape_csharp_keyword(snake_to_pascal_case(isignal.name));
+
+ // Prevent the signal and its enclosing type from sharing the same name
+ if (isignal.proxy_name == itype.proxy_name) {
+ _log("Name of signal '%s' is ambiguous with the name of its enclosing class '%s'. Renaming signal to '%s_'\n",
+ isignal.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), isignal.proxy_name.utf8().get_data());
+
+ isignal.proxy_name += "_";
+ }
+
+ if (itype.find_property_by_proxy_name(isignal.proxy_name) || itype.find_method_by_proxy_name(isignal.proxy_name)) {
+ // ClassDB allows signal names that conflict with method or property names.
+ // While registering a signal with a conflicting name is considered wrong,
+ // it may still happen and it may take some time until someone fixes the name.
+ // We can't allow the bindings to be in a broken state while we wait for a fix;
+ // that's why we must handle this possibility by renaming the signal.
+ isignal.proxy_name += "Signal";
+ }
+
+ if (itype.class_doc) {
+ for (int i = 0; i < itype.class_doc->signals.size(); i++) {
+ const DocData::MethodDoc &signal_doc = itype.class_doc->signals[i];
+ if (signal_doc.name == isignal.name) {
+ isignal.method_doc = &signal_doc;
+ break;
+ }
+ }
+ }
+
+ itype.signals_.push_back(isignal);
+ }
+
// Populate enums and constants
List<String> constants;
ClassDB::get_integer_constant_list(type_cname, &constants, true);
- const HashMap<StringName, List<StringName> > &enum_map = class_info->enum_map;
- const StringName *k = NULL;
+ const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map;
+ k = nullptr;
while ((k = enum_map.next(k))) {
StringName enum_proxy_cname = *k;
@@ -2507,7 +2707,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
- iconstant.const_doc = NULL;
+ iconstant.const_doc = nullptr;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
const DocData::ConstantDoc &const_doc = itype.class_doc->constants[i];
@@ -2542,7 +2742,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
- iconstant.const_doc = NULL;
+ iconstant.const_doc = nullptr;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
const DocData::ConstantDoc &const_doc = itype.class_doc->constants[i];
@@ -2587,8 +2787,15 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
#endif
break;
case Variant::STRING:
+ case Variant::STRING_NAME:
case Variant::NODE_PATH:
- r_iarg.default_argument = "\"" + r_iarg.default_argument + "\"";
+ if (r_iarg.type.cname == name_cache.type_StringName || r_iarg.type.cname == name_cache.type_NodePath) {
+ r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\"";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ } else {
+ CRASH_COND(r_iarg.type.cname != name_cache.type_String);
+ r_iarg.default_argument = "\"" + r_iarg.default_argument + "\"";
+ }
break;
case Variant::TRANSFORM:
if (p_val.operator Transform() == Transform())
@@ -2603,8 +2810,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
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;
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
break;
@@ -2630,8 +2840,8 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
case Variant::ARRAY:
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
- case Variant::PACKED_FLOAT32_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:
@@ -2646,8 +2856,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = Variant::get_type_name(p_val.get_type()) + ".Identity";
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
break;
- default: {
- }
+ case Variant::CALLABLE:
+ case Variant::SIGNAL:
+ CRASH_NOW_MSG("Parameter of type '" + String(r_iarg.type.cname) + "' cannot have a default value.");
+ break;
+ default:
+ CRASH_NOW_MSG("Unexpected Variant type: " + itos(p_val.get_type()));
+ break;
}
if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "null")
@@ -2672,16 +2887,19 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = "GDMonoMarshal::M_" #m_type; \
itype.cs_in = "ref %s"; \
/* in cs_out, im_type_out (%3) includes the 'out ' part */ \
- itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; \
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;"; \
itype.im_type_out = "out " + itype.cs_type; \
itype.ret_as_byref_arg = true; \
builtin_types.insert(itype.cname, itype); \
}
INSERT_STRUCT_TYPE(Vector2)
+ INSERT_STRUCT_TYPE(Vector2i)
INSERT_STRUCT_TYPE(Rect2)
+ INSERT_STRUCT_TYPE(Rect2i)
INSERT_STRUCT_TYPE(Transform2D)
INSERT_STRUCT_TYPE(Vector3)
+ INSERT_STRUCT_TYPE(Vector3i)
INSERT_STRUCT_TYPE(Basis)
INSERT_STRUCT_TYPE(Quat)
INSERT_STRUCT_TYPE(Transform)
@@ -2749,7 +2967,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = "out " + itype.name;
itype.cs_in = "ref %0";
/* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;";
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;";
itype.ret_as_byref_arg = true;
builtin_types.insert(itype.cname, itype);
@@ -2766,7 +2984,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = "out " + itype.name;
itype.cs_in = "ref %0";
/* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;";
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;";
itype.ret_as_byref_arg = true;
builtin_types.insert(itype.cname, itype);
}
@@ -2792,7 +3010,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = "out " + itype.proxy_name;
itype.cs_in = "ref %0";
/* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;";
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;";
itype.ret_as_byref_arg = true;
builtin_types.insert(itype.cname, itype);
@@ -2814,7 +3032,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = "out " + itype.proxy_name;
itype.cs_in = "ref %0";
/* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;";
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;";
itype.ret_as_byref_arg = true;
builtin_types.insert(itype.cname, itype);
}
@@ -2835,6 +3053,24 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
+ // StringName
+ itype = TypeInterface();
+ itype.name = "StringName";
+ itype.cname = itype.name;
+ itype.proxy_name = "StringName";
+ itype.c_in = "\t%0 %1_in = %1 ? *%1 : StringName();\n";
+ itype.c_out = "\treturn memnew(StringName(%1));\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = itype.name;
+ itype.c_type_in = itype.c_type + "*";
+ itype.c_type_out = itype.c_type + "*";
+ itype.cs_type = itype.proxy_name;
+ itype.cs_in = "StringName." CS_SMETHOD_GETINSTANCE "(%0)";
+ itype.cs_out = "return new %2(%0(%1));";
+ itype.im_type_in = "IntPtr";
+ itype.im_type_out = "IntPtr";
+ builtin_types.insert(itype.cname, itype);
+
// NodePath
itype = TypeInterface();
itype.name = "NodePath";
@@ -2883,6 +3119,40 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
+ // Callable
+ itype = TypeInterface::create_value_type(String("Callable"));
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(*%1);\n";
+ itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_CALLABLE "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type_in = "GDMonoMarshal::M_Callable*";
+ itype.c_type_out = "GDMonoMarshal::M_Callable";
+ itype.cs_in = "ref %s";
+ /* in cs_out, im_type_out (%3) includes the 'out ' part */
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;";
+ itype.im_type_out = "out " + itype.cs_type;
+ itype.ret_as_byref_arg = true;
+ builtin_types.insert(itype.cname, itype);
+
+ // Signal
+ itype = TypeInterface();
+ itype.name = "Signal";
+ itype.cname = itype.name;
+ itype.proxy_name = "SignalInfo";
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(*%1);\n";
+ itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_SIGNAL "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = itype.name;
+ itype.c_type_in = "GDMonoMarshal::M_SignalInfo*";
+ itype.c_type_out = "GDMonoMarshal::M_SignalInfo";
+ itype.cs_in = "ref %s";
+ /* in cs_out, im_type_out (%3) includes the 'out ' part */
+ itype.cs_out = "%0(%1, %3 argRet); return argRet;";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = "ref " + itype.cs_type;
+ itype.im_type_out = "out " + itype.cs_type;
+ itype.ret_as_byref_arg = true;
+ builtin_types.insert(itype.cname, itype);
+
// VarArg (fictitious type to represent variable arguments)
itype = TypeInterface();
itype.name = "VarArg";
@@ -2917,13 +3187,11 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
#define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
INSERT_ARRAY(PackedInt32Array, int);
+ INSERT_ARRAY(PackedInt64Array, long);
INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, byte);
-#ifdef REAL_T_IS_DOUBLE
- INSERT_ARRAY(PackedFloat32Array, double);
-#else
INSERT_ARRAY(PackedFloat32Array, float);
-#endif
+ INSERT_ARRAY(PackedFloat64Array, double);
INSERT_ARRAY(PackedStringArray, string);
@@ -2994,7 +3262,7 @@ void BindingsGenerator::_populate_global_constants() {
String constant_name = GlobalConstants::get_global_constant_name(i);
- const DocData::ConstantDoc *const_doc = NULL;
+ const DocData::ConstantDoc *const_doc = nullptr;
for (int j = 0; j < global_scope_doc.constants.size(); j++) {
const DocData::ConstantDoc &curr_const_doc = global_scope_doc.constants[j];
@@ -3052,7 +3320,10 @@ void BindingsGenerator::_populate_global_constants() {
// HARDCODED
List<StringName> hardcoded_enums;
+ hardcoded_enums.push_back("Vector2.Axis");
+ hardcoded_enums.push_back("Vector2i.Axis");
hardcoded_enums.push_back("Vector3.Axis");
+ hardcoded_enums.push_back("Vector3i.Axis");
for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) {
// These enums are not generated and must be written manually (e.g.: Vector3.Axis)
// Here, we assume core types do not begin with underscore
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index d3a8937313..7c87c688db 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -33,7 +33,7 @@
#include "core/class_db.h"
#include "core/string_builder.h"
-#include "editor/doc/doc_data.h"
+#include "editor/doc_data.h"
#include "editor/editor_help.h"
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
@@ -107,9 +107,15 @@ class BindingsGenerator {
TypeReference type;
String name;
- String default_argument;
DefaultParamMode def_param_mode;
+ /**
+ * Determines the expression for the parameter default value.
+ * Formatting elements:
+ * %0 or %s: [cs_type] of the argument type
+ */
+ String default_argument;
+
ArgumentInterface() {
def_param_mode = CONSTANT;
}
@@ -170,7 +176,33 @@ class BindingsGenerator {
is_virtual = false;
requires_object_call = false;
is_internal = false;
- method_doc = NULL;
+ method_doc = nullptr;
+ is_deprecated = false;
+ }
+ };
+
+ struct SignalInterface {
+ String name;
+ StringName cname;
+
+ /**
+ * Name of the C# method
+ */
+ String proxy_name;
+
+ List<ArgumentInterface> arguments;
+
+ const DocData::MethodDoc *method_doc;
+
+ bool is_deprecated;
+ String deprecation_message;
+
+ void add_argument(const ArgumentInterface &argument) {
+ arguments.push_back(argument);
+ }
+
+ SignalInterface() {
+ method_doc = nullptr;
is_deprecated = false;
}
};
@@ -336,6 +368,7 @@ class BindingsGenerator {
List<EnumInterface> enums;
List<PropertyInterface> properties;
List<MethodInterface> methods;
+ List<SignalInterface> signals_;
const MethodInterface *find_method_by_name(const StringName &p_cname) const {
for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) {
@@ -343,7 +376,7 @@ class BindingsGenerator {
return &E->get();
}
- return NULL;
+ return nullptr;
}
const PropertyInterface *find_property_by_name(const StringName &p_cname) const {
@@ -352,7 +385,7 @@ class BindingsGenerator {
return &E->get();
}
- return NULL;
+ return nullptr;
}
const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const {
@@ -361,7 +394,16 @@ class BindingsGenerator {
return &E->get();
}
- return NULL;
+ return nullptr;
+ }
+
+ const MethodInterface *find_method_by_proxy_name(const String &p_proxy_name) const {
+ for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) {
+ if (E->get().proxy_name == p_proxy_name)
+ return &E->get();
+ }
+
+ return nullptr;
}
private:
@@ -456,7 +498,7 @@ class BindingsGenerator {
c_arg_in = "%s";
- class_doc = NULL;
+ class_doc = nullptr;
}
};
@@ -510,7 +552,7 @@ class BindingsGenerator {
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
- Map<StringName, List<StringName> > blacklisted_methods;
+ Map<StringName, List<StringName>> blacklisted_methods;
void _initialize_blacklisted_methods();
@@ -524,6 +566,8 @@ class BindingsGenerator {
StringName type_Reference;
StringName type_RID;
StringName type_String;
+ StringName type_StringName;
+ StringName type_NodePath;
StringName type_at_GlobalScope;
StringName enum_Error;
@@ -548,6 +592,8 @@ class BindingsGenerator {
type_Reference = StaticCString::create("Reference");
type_RID = StaticCString::create("RID");
type_String = StaticCString::create("String");
+ type_StringName = StaticCString::create("StringName");
+ type_NodePath = StaticCString::create("NodePath");
type_at_GlobalScope = StaticCString::create("@GlobalScope");
enum_Error = StaticCString::create("Error");
@@ -576,7 +622,7 @@ class BindingsGenerator {
if (it->get().name == p_name) return it;
it = it->next();
}
- return NULL;
+ return nullptr;
}
const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const {
@@ -585,7 +631,7 @@ class BindingsGenerator {
return &E->get();
}
- return NULL;
+ return nullptr;
}
inline String get_unique_sig(const TypeInterface &p_type) {
@@ -623,6 +669,7 @@ class BindingsGenerator {
Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output);
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_global_constants(StringBuilder &p_output);
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index 872f45ba91..e5c2d023d3 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -57,8 +57,8 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
Variant item_type = p_item_type;
Variant include = p_include;
const Variant *args[3] = { &project_path, &item_type, &include };
- MonoException *exc = NULL;
- klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &exc);
+ MonoException *exc = nullptr;
+ klass->get_method("AddItemToProjectChecked", 3)->invoke(nullptr, args, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 31996a03d0..283d4beb8e 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -95,7 +95,7 @@ MonoString *godot_icall_GodotSharpDirs_MonoSolutionsDir() {
#ifdef TOOLS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_solutions_dir());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -103,7 +103,7 @@ MonoString *godot_icall_GodotSharpDirs_BuildLogsDirs() {
#ifdef TOOLS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_build_logs_dir());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -111,7 +111,7 @@ MonoString *godot_icall_GodotSharpDirs_ProjectSlnPath() {
#ifdef TOOLS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_sln_path());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -119,7 +119,7 @@ MonoString *godot_icall_GodotSharpDirs_ProjectCsProjPath() {
#ifdef TOOLS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_csproj_path());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -127,7 +127,7 @@ MonoString *godot_icall_GodotSharpDirs_DataEditorToolsDir() {
#ifdef TOOLS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_tools_dir());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -135,7 +135,7 @@ MonoString *godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir() {
#ifdef TOOLS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_prebuilt_api_dir());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -151,7 +151,7 @@ MonoString *godot_icall_GodotSharpDirs_DataMonoBinDir() {
#ifdef WINDOWS_ENABLED
return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_bin_dir());
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -202,7 +202,7 @@ uint32_t godot_icall_BindingsGenerator_CsGlueVersion() {
}
int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObject *p_classes, MonoString **r_error_str) {
- *r_error_str = NULL;
+ *r_error_str = nullptr;
String filepath = GDMonoMarshal::mono_string_to_godot(p_filepath);
@@ -335,7 +335,7 @@ MonoString *godot_icall_Internal_MonoWindowsInstallRoot() {
String install_root_dir = GDMono::get_singleton()->get_mono_reg_info().install_root_dir;
return GDMonoMarshal::mono_string_from_godot(install_root_dir);
#else
- return NULL;
+ return nullptr;
#endif
}
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index ce0b6ad0e6..324013e5e2 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -59,7 +59,7 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>
if (r_dependencies.has(ref_name))
continue;
- GDMonoAssembly *ref_assembly = NULL;
+ GDMonoAssembly *ref_assembly = nullptr;
String path;
bool has_extension = ref_name.ends_with(".dll") || ref_name.ends_with(".exe");
@@ -70,21 +70,21 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>
path = search_dir.plus_file(ref_name);
if (FileAccess::exists(path)) {
GDMono::get_singleton()->load_assembly_from(ref_name.get_basename(), path, &ref_assembly, true);
- if (ref_assembly != NULL)
+ if (ref_assembly != nullptr)
break;
}
} else {
path = search_dir.plus_file(ref_name + ".dll");
if (FileAccess::exists(path)) {
GDMono::get_singleton()->load_assembly_from(ref_name, path, &ref_assembly, true);
- if (ref_assembly != NULL)
+ if (ref_assembly != nullptr)
break;
}
path = search_dir.plus_file(ref_name + ".exe");
if (FileAccess::exists(path)) {
GDMono::get_singleton()->load_assembly_from(ref_name, path, &ref_assembly, true);
- if (ref_assembly != NULL)
+ if (ref_assembly != nullptr)
break;
}
}
@@ -92,7 +92,8 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>
ERR_FAIL_COND_V_MSG(!ref_assembly, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
- r_dependencies[ref_name] = ref_assembly->get_path();
+ // Use the path we got from the search. Don't try to get the path from the loaded assembly as we can't trust it will be from the selected BCL dir.
+ r_dependencies[ref_name] = path;
Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'.");
@@ -116,7 +117,7 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencie
String assembly_name = *key;
String assembly_path = p_initial_dependencies[*key];
- GDMonoAssembly *assembly = NULL;
+ GDMonoAssembly *assembly = nullptr;
bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly, /* refonly: */ true);
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'.");
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln b/modules/mono/glue/GodotSharp/GodotSharp.sln
index a496e36da3..4896d0a07d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp.sln
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln
@@ -8,8 +8,6 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
index 3957387be9..39d5782db8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
@@ -2,7 +2,7 @@ using System;
namespace Godot
{
- [AttributeUsage(AttributeTargets.Delegate)]
+ [AttributeUsage(AttributeTargets.Delegate | AttributeTargets.Event)]
public class SignalAttribute : Attribute
{
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
new file mode 100644
index 0000000000..c85cc1884c
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Godot
+{
+ public struct Callable
+ {
+ private readonly Object _target;
+ private readonly StringName _method;
+ private readonly Delegate _delegate;
+
+ public Object Target => _target;
+ public StringName Method => _method;
+ public Delegate Delegate => _delegate;
+
+ public static implicit operator Callable(Delegate @delegate) => new Callable(@delegate);
+
+ public Callable(Object target, StringName method)
+ {
+ _target = target;
+ _method = method;
+ _delegate = null;
+ }
+
+ public Callable(Delegate @delegate)
+ {
+ _target = null;
+ _method = null;
+ _delegate = @delegate;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
new file mode 100644
index 0000000000..785e87a043
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -0,0 +1,395 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ internal static class DelegateUtils
+ {
+ private enum TargetKind : uint
+ {
+ Static,
+ GodotObject,
+ CompilerGenerated
+ }
+
+ internal static bool TrySerializeDelegate(Delegate @delegate, Collections.Array serializedData)
+ {
+ if (@delegate is MulticastDelegate multicastDelegate)
+ {
+ bool someDelegatesSerialized = false;
+
+ Delegate[] invocationList = multicastDelegate.GetInvocationList();
+
+ if (invocationList.Length > 1)
+ {
+ var multiCastData = new Collections.Array();
+
+ foreach (Delegate oneDelegate in invocationList)
+ someDelegatesSerialized |= TrySerializeDelegate(oneDelegate, multiCastData);
+
+ if (!someDelegatesSerialized)
+ return false;
+
+ serializedData.Add(multiCastData);
+ return true;
+ }
+ }
+
+ if (TrySerializeSingleDelegate(@delegate, out byte[] buffer))
+ {
+ serializedData.Add(buffer);
+ return true;
+ }
+
+ return false;
+ }
+
+ private static bool TrySerializeSingleDelegate(Delegate @delegate, out byte[] buffer)
+ {
+ buffer = null;
+
+ object target = @delegate.Target;
+
+ switch (target)
+ {
+ case null:
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ writer.Write((ulong) TargetKind.Static);
+
+ SerializeType(writer, @delegate.GetType());
+
+ if (!TrySerializeMethodInfo(writer, @delegate.Method))
+ return false;
+
+ buffer = stream.ToArray();
+ return true;
+ }
+ }
+ case Godot.Object godotObject:
+ {
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ writer.Write((ulong) TargetKind.GodotObject);
+ writer.Write((ulong) godotObject.GetInstanceId());
+
+ SerializeType(writer, @delegate.GetType());
+
+ if (!TrySerializeMethodInfo(writer, @delegate.Method))
+ return false;
+
+ buffer = stream.ToArray();
+ return true;
+ }
+ }
+ default:
+ {
+ Type targetType = target.GetType();
+
+ if (targetType.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) != null)
+ {
+ // Compiler generated. Probably a closure. Try to serialize it.
+
+ using (var stream = new MemoryStream())
+ using (var writer = new BinaryWriter(stream))
+ {
+ writer.Write((ulong) TargetKind.CompilerGenerated);
+ SerializeType(writer, targetType);
+
+ SerializeType(writer, @delegate.GetType());
+
+ if (!TrySerializeMethodInfo(writer, @delegate.Method))
+ return false;
+
+ FieldInfo[] fields = targetType.GetFields(BindingFlags.Instance | BindingFlags.Public);
+
+ writer.Write(fields.Length);
+
+ foreach (FieldInfo field in fields)
+ {
+ Type fieldType = field.GetType();
+
+ Variant.Type variantType = GD.TypeToVariantType(fieldType);
+
+ if (variantType == Variant.Type.Nil)
+ return false;
+
+ writer.Write(field.Name);
+ byte[] valueBuffer = GD.Var2Bytes(field.GetValue(target));
+ writer.Write(valueBuffer.Length);
+ writer.Write(valueBuffer);
+ }
+
+ buffer = stream.ToArray();
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ private static bool TrySerializeMethodInfo(BinaryWriter writer, MethodInfo methodInfo)
+ {
+ if (methodInfo == null)
+ return false;
+
+ SerializeType(writer, methodInfo.DeclaringType);
+
+ writer.Write(methodInfo.Name);
+
+ int flags = 0;
+
+ if (methodInfo.IsPublic)
+ flags |= (int) BindingFlags.Public;
+ else
+ flags |= (int) BindingFlags.NonPublic;
+
+ if (methodInfo.IsStatic)
+ flags |= (int) BindingFlags.Static;
+ else
+ flags |= (int) BindingFlags.Instance;
+
+ writer.Write(flags);
+
+ Type returnType = methodInfo.ReturnType;
+ bool hasReturn = methodInfo.ReturnType != typeof(void);
+
+ writer.Write(hasReturn);
+ if (hasReturn)
+ SerializeType(writer, returnType);
+
+ ParameterInfo[] parameters = methodInfo.GetParameters();
+
+ writer.Write(parameters.Length);
+
+ if (parameters.Length > 0)
+ {
+ for (int i = 0; i < parameters.Length; i++)
+ SerializeType(writer, parameters[i].ParameterType);
+ }
+
+ return true;
+ }
+
+ private static void SerializeType(BinaryWriter writer, Type type)
+ {
+ if (type == null)
+ {
+ int genericArgumentsCount = -1;
+ writer.Write(genericArgumentsCount);
+ }
+ else if (type.IsGenericType)
+ {
+ Type genericTypeDef = type.GetGenericTypeDefinition();
+ Type[] genericArgs = type.GetGenericArguments();
+
+ int genericArgumentsCount = genericArgs.Length;
+ writer.Write(genericArgumentsCount);
+
+ string assemblyQualifiedName = genericTypeDef.AssemblyQualifiedName;
+ Debug.Assert(assemblyQualifiedName != null);
+ writer.Write(assemblyQualifiedName);
+
+ for (int i = 0; i < genericArgs.Length; i++)
+ SerializeType(writer, genericArgs[i]);
+ }
+ else
+ {
+ int genericArgumentsCount = 0;
+ writer.Write(genericArgumentsCount);
+
+ string assemblyQualifiedName = type.AssemblyQualifiedName;
+ Debug.Assert(assemblyQualifiedName != null);
+ writer.Write(assemblyQualifiedName);
+ }
+ }
+
+ private static bool TryDeserializeDelegate(Collections.Array serializedData, out Delegate @delegate)
+ {
+ if (serializedData.Count == 1)
+ {
+ object elem = serializedData[0];
+
+ if (elem is Collections.Array multiCastData)
+ return TryDeserializeDelegate(multiCastData, out @delegate);
+
+ return TryDeserializeSingleDelegate((byte[])elem, out @delegate);
+ }
+
+ @delegate = null;
+
+ var delegates = new List<Delegate>(serializedData.Count);
+
+ foreach (object elem in serializedData)
+ {
+ if (elem is Collections.Array multiCastData)
+ {
+ if (TryDeserializeDelegate(multiCastData, out Delegate oneDelegate))
+ delegates.Add(oneDelegate);
+ }
+ else
+ {
+ if (TryDeserializeSingleDelegate((byte[]) elem, out Delegate oneDelegate))
+ delegates.Add(oneDelegate);
+ }
+ }
+
+ if (delegates.Count <= 0)
+ return false;
+
+ @delegate = delegates.Count == 1 ? delegates[0] : Delegate.Combine(delegates.ToArray());
+ return true;
+ }
+
+ private static bool TryDeserializeSingleDelegate(byte[] buffer, out Delegate @delegate)
+ {
+ @delegate = null;
+
+ using (var stream = new MemoryStream(buffer, writable: false))
+ using (var reader = new BinaryReader(stream))
+ {
+ var targetKind = (TargetKind) reader.ReadUInt64();
+
+ switch (targetKind)
+ {
+ case TargetKind.Static:
+ {
+ Type delegateType = DeserializeType(reader);
+ if (delegateType == null)
+ return false;
+
+ if (!TryDeserializeMethodInfo(reader, out MethodInfo methodInfo))
+ return false;
+
+ @delegate = Delegate.CreateDelegate(delegateType, null, methodInfo);
+ return true;
+ }
+ case TargetKind.GodotObject:
+ {
+ ulong objectId = reader.ReadUInt64();
+ Godot.Object godotObject = GD.InstanceFromId(objectId);
+ if (godotObject == null)
+ return false;
+
+ Type delegateType = DeserializeType(reader);
+ if (delegateType == null)
+ return false;
+
+ if (!TryDeserializeMethodInfo(reader, out MethodInfo methodInfo))
+ return false;
+
+ @delegate = Delegate.CreateDelegate(delegateType, godotObject, methodInfo);
+ return true;
+ }
+ case TargetKind.CompilerGenerated:
+ {
+ Type targetType = DeserializeType(reader);
+ if (targetType == null)
+ return false;
+
+ Type delegateType = DeserializeType(reader);
+ if (delegateType == null)
+ return false;
+
+ if (!TryDeserializeMethodInfo(reader, out MethodInfo methodInfo))
+ return false;
+
+ int fieldCount = reader.ReadInt32();
+
+ object recreatedTarget = Activator.CreateInstance(targetType);
+
+ for (int i = 0; i < fieldCount; i++)
+ {
+ string name = reader.ReadString();
+ int valueBufferLength = reader.ReadInt32();
+ byte[] valueBuffer = reader.ReadBytes(valueBufferLength);
+
+ FieldInfo fieldInfo = targetType.GetField(name, BindingFlags.Instance | BindingFlags.Public);
+ fieldInfo?.SetValue(recreatedTarget, GD.Bytes2Var(valueBuffer));
+ }
+
+ @delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo);
+ return true;
+ }
+ default:
+ return false;
+ }
+ }
+ }
+
+ private static bool TryDeserializeMethodInfo(BinaryReader reader, out MethodInfo methodInfo)
+ {
+ methodInfo = null;
+
+ Type declaringType = DeserializeType(reader);
+
+ string methodName = reader.ReadString();
+
+ int flags = reader.ReadInt32();
+
+ bool hasReturn = reader.ReadBoolean();
+ Type returnType = hasReturn ? DeserializeType(reader) : typeof(void);
+
+ int parametersCount = reader.ReadInt32();
+
+ if (parametersCount > 0)
+ {
+ var parameterTypes = new Type[parametersCount];
+
+ for (int i = 0; i < parametersCount; i++)
+ {
+ Type parameterType = DeserializeType(reader);
+ if (parameterType == null)
+ return false;
+ parameterTypes[i] = parameterType;
+ }
+
+ methodInfo = declaringType.GetMethod(methodName, (BindingFlags) flags, null, parameterTypes, null);
+ return methodInfo != null && methodInfo.ReturnType == returnType;
+ }
+
+ methodInfo = declaringType.GetMethod(methodName, (BindingFlags) flags);
+ return methodInfo != null && methodInfo.ReturnType == returnType;
+ }
+
+ private static Type DeserializeType(BinaryReader reader)
+ {
+ int genericArgumentsCount = reader.ReadInt32();
+
+ if (genericArgumentsCount == -1)
+ return null;
+
+ string assemblyQualifiedName = reader.ReadString();
+ var type = Type.GetType(assemblyQualifiedName);
+
+ if (type == null)
+ return null; // Type not found
+
+ if (genericArgumentsCount != 0)
+ {
+ var genericArgumentTypes = new Type[genericArgumentsCount];
+
+ for (int i = 0; i < genericArgumentsCount; i++)
+ {
+ Type genericArgumentType = DeserializeType(reader);
+ if (genericArgumentType == null)
+ return null;
+ genericArgumentTypes[i] = genericArgumentType;
+ }
+
+ type = type.MakeGenericType(genericArgumentTypes);
+ }
+
+ return type;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
index a0f105d55e..c4c911b863 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
@@ -23,7 +23,7 @@ namespace Godot
/// <example>
/// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>.
/// <code>
- /// dynamic sprite = GetNode("Sprite").DynamicGodotObject;
+ /// dynamic sprite = GetNode("Sprite2D").DynamicGodotObject;
/// sprite.add_child(this);
///
/// if ((sprite.hframes * sprite.vframes) &gt; 0)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index 2a9c2d73b1..9384da0e48 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -5,6 +5,7 @@ using System.Runtime.CompilerServices;
using real_t = System.Double;
#else
using real_t = System.Single;
+
#endif
// TODO: Add comments describing what this class does. It is not obvious.
@@ -13,9 +14,9 @@ namespace Godot
{
public static partial class GD
{
- public static object Bytes2Var(byte[] bytes, bool allow_objects = false)
+ public static object Bytes2Var(byte[] bytes, bool allowObjects = false)
{
- return godot_icall_GD_bytes2var(bytes, allow_objects);
+ return godot_icall_GD_bytes2var(bytes, allowObjects);
}
public static object Convert(object what, Variant.Type type)
@@ -25,7 +26,7 @@ namespace Godot
public static real_t Db2Linear(real_t db)
{
- return (real_t)Math.Exp(db * 0.11512925464970228420089957273422);
+ return (real_t) Math.Exp(db * 0.11512925464970228420089957273422);
}
public static real_t DecTime(real_t value, real_t amount, real_t step)
@@ -38,11 +39,11 @@ namespace Godot
return val * sgn;
}
- public static FuncRef FuncRef(Object instance, string funcname)
+ public static FuncRef FuncRef(Object instance, StringName funcName)
{
var ret = new FuncRef();
ret.SetInstance(instance);
- ret.SetFunction(funcname);
+ ret.SetFunction(funcName);
return ret;
}
@@ -58,7 +59,7 @@ namespace Godot
public static real_t Linear2Db(real_t linear)
{
- return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321);
+ return (real_t) (Math.Log(linear) * 8.6858896380650365530225783783321);
}
public static Resource Load(string path)
@@ -181,14 +182,14 @@ namespace Godot
return godot_icall_GD_str2var(str);
}
- public static bool TypeExists(string type)
+ public static bool TypeExists(StringName type)
{
- return godot_icall_GD_type_exists(type);
+ return godot_icall_GD_type_exists(StringName.GetPtr(type));
}
- public static byte[] Var2Bytes(object var, bool full_objects = false)
+ public static byte[] Var2Bytes(object var, bool fullObjects = false)
{
- return godot_icall_GD_var2bytes(var, full_objects);
+ return godot_icall_GD_var2bytes(var, fullObjects);
}
public static string Var2Str(object var)
@@ -196,8 +197,13 @@ namespace Godot
return godot_icall_GD_var2str(var);
}
+ public static Variant.Type TypeToVariantType(Type type)
+ {
+ return godot_icall_TypeToVariantType(type);
+ }
+
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allow_objects);
+ internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allowObjects);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static object godot_icall_GD_convert(object what, Variant.Type type);
@@ -206,7 +212,7 @@ namespace Godot
internal extern static int godot_icall_GD_hash(object var);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static Object godot_icall_GD_instance_from_id(ulong instance_id);
+ internal extern static Object godot_icall_GD_instance_from_id(ulong instanceId);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_print(object[] what);
@@ -249,10 +255,10 @@ namespace Godot
internal extern static object godot_icall_GD_str2var(string str);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static bool godot_icall_GD_type_exists(string type);
+ internal extern static bool godot_icall_GD_type_exists(IntPtr type);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static byte[] godot_icall_GD_var2bytes(object what, bool full_objects);
+ internal extern static byte[] godot_icall_GD_var2bytes(object what, bool fullObjects);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_var2str(object var);
@@ -262,5 +268,8 @@ namespace Godot
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_GD_pushwarning(string type);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern Variant.Type godot_icall_TypeToVariantType(Type type);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
index 8c5872ba5a..4ecc55f94e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -7,7 +7,7 @@ namespace Godot
{
private bool disposed = false;
- internal IntPtr ptr;
+ private IntPtr ptr;
internal static IntPtr GetPtr(NodePath instance)
{
@@ -50,104 +50,93 @@ namespace Godot
this.ptr = ptr;
}
- public IntPtr NativeInstance
- {
- get { return ptr; }
- }
-
public NodePath() : this(string.Empty) {}
public NodePath(string path)
{
- this.ptr = godot_icall_NodePath_Ctor(path);
+ ptr = godot_icall_NodePath_Ctor(path);
}
- public static implicit operator NodePath(string from)
- {
- return new NodePath(from);
- }
+ public static implicit operator NodePath(string from) => new NodePath(from);
- public static implicit operator string(NodePath from)
- {
- return godot_icall_NodePath_operator_String(NodePath.GetPtr(from));
- }
+ public static implicit operator string(NodePath from) => from.ToString();
public override string ToString()
{
- return (string)this;
+ return godot_icall_NodePath_operator_String(GetPtr(this));
}
public NodePath GetAsPropertyPath()
{
- return new NodePath(godot_icall_NodePath_get_as_property_path(NodePath.GetPtr(this)));
+ return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this)));
}
public string GetConcatenatedSubnames()
{
- return godot_icall_NodePath_get_concatenated_subnames(NodePath.GetPtr(this));
+ return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this));
}
public string GetName(int idx)
{
- return godot_icall_NodePath_get_name(NodePath.GetPtr(this), idx);
+ return godot_icall_NodePath_get_name(GetPtr(this), idx);
}
public int GetNameCount()
{
- return godot_icall_NodePath_get_name_count(NodePath.GetPtr(this));
+ return godot_icall_NodePath_get_name_count(GetPtr(this));
}
public string GetSubname(int idx)
{
- return godot_icall_NodePath_get_subname(NodePath.GetPtr(this), idx);
+ return godot_icall_NodePath_get_subname(GetPtr(this), idx);
}
public int GetSubnameCount()
{
- return godot_icall_NodePath_get_subname_count(NodePath.GetPtr(this));
+ return godot_icall_NodePath_get_subname_count(GetPtr(this));
}
public bool IsAbsolute()
{
- return godot_icall_NodePath_is_absolute(NodePath.GetPtr(this));
+ return godot_icall_NodePath_is_absolute(GetPtr(this));
}
public bool IsEmpty()
{
- return godot_icall_NodePath_is_empty(NodePath.GetPtr(this));
+ return godot_icall_NodePath_is_empty(GetPtr(this));
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static IntPtr godot_icall_NodePath_Ctor(string path);
+ private static extern IntPtr godot_icall_NodePath_Ctor(string path);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_NodePath_Dtor(IntPtr ptr);
+ private static extern void godot_icall_NodePath_Dtor(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static string godot_icall_NodePath_operator_String(IntPtr ptr);
+ private static extern string godot_icall_NodePath_operator_String(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
+ private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
+ private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
+ private static extern string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static int godot_icall_NodePath_get_name_count(IntPtr ptr);
+ private static extern int godot_icall_NodePath_get_name_count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
+ private static extern string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static int godot_icall_NodePath_get_subname_count(IntPtr ptr);
+ private static extern int godot_icall_NodePath_get_subname_count(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static bool godot_icall_NodePath_is_absolute(IntPtr ptr);
+ private static extern bool godot_icall_NodePath_is_absolute(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static bool godot_icall_NodePath_is_empty(IntPtr ptr);
+ private static extern bool godot_icall_NodePath_is_empty(IntPtr ptr);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index de80f7fddc..42610c5ef7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -7,7 +7,7 @@ namespace Godot
{
private bool disposed = false;
- private const string nativeName = "Object";
+ private static StringName nativeName = "Object";
internal IntPtr ptr;
internal bool memoryOwn;
@@ -15,7 +15,14 @@ namespace Godot
public Object() : this(false)
{
if (ptr == IntPtr.Zero)
+ {
ptr = godot_icall_Object_Ctor(this);
+ }
+ else
+ {
+ // This is called inside godot_icall_Object_Ctor, so we must call it as well in this case.
+ godot_icall_Object_ConnectEventSignals(ptr);
+ }
}
internal Object(bool memoryOwn)
@@ -101,7 +108,7 @@ namespace Godot
/// }
/// </code>
/// </example>
- public SignalAwaiter ToSignal(Object source, string signal)
+ public SignalAwaiter ToSignal(Object source, StringName signal)
{
return new SignalAwaiter(source, signal, this);
}
@@ -111,20 +118,28 @@ namespace Godot
/// </summary>
public dynamic DynamicObject => new DynamicGodotObject(this);
+ internal static IntPtr __ClassDB_get_method(StringName type, string method)
+ {
+ return godot_icall_Object_ClassDB_get_method(StringName.GetPtr(type), method);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal static extern IntPtr godot_icall_Object_Ctor(Object obj);
+
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static IntPtr godot_icall_Object_Ctor(Object obj);
+ internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
+ internal static extern void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
+ internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static string godot_icall_Object_ToString(IntPtr ptr);
+ internal static extern string godot_icall_Object_ToString(IntPtr ptr);
// Used by the generated API
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static IntPtr godot_icall_Object_ClassDB_get_method(string type, string method);
+ internal static extern IntPtr godot_icall_Object_ClassDB_get_method(IntPtr type, string method);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
new file mode 100644
index 0000000000..bc2cad8713
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -0,0 +1,262 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Rect2i : IEquatable<Rect2i>
+ {
+ private Vector2i _position;
+ private Vector2i _size;
+
+ public Vector2i Position
+ {
+ get { return _position; }
+ set { _position = value; }
+ }
+
+ public Vector2i Size
+ {
+ get { return _size; }
+ set { _size = value; }
+ }
+
+ public Vector2i End
+ {
+ get { return _position + _size; }
+ set { _size = value - _position; }
+ }
+
+ public int Area
+ {
+ get { return GetArea(); }
+ }
+
+ public Rect2i Abs()
+ {
+ Vector2i end = End;
+ Vector2i topLeft = new Vector2i(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y));
+ return new Rect2i(topLeft, _size.Abs());
+ }
+
+ public Rect2i Clip(Rect2i b)
+ {
+ var newRect = b;
+
+ if (!Intersects(newRect))
+ return new Rect2i();
+
+ newRect._position.x = Mathf.Max(b._position.x, _position.x);
+ newRect._position.y = Mathf.Max(b._position.y, _position.y);
+
+ Vector2i bEnd = b._position + b._size;
+ Vector2i end = _position + _size;
+
+ newRect._size.x = Mathf.Min(bEnd.x, end.x) - newRect._position.x;
+ newRect._size.y = Mathf.Min(bEnd.y, end.y) - newRect._position.y;
+
+ return newRect;
+ }
+
+ public bool Encloses(Rect2i b)
+ {
+ return b._position.x >= _position.x && b._position.y >= _position.y &&
+ b._position.x + b._size.x < _position.x + _size.x &&
+ b._position.y + b._size.y < _position.y + _size.y;
+ }
+
+ public Rect2i Expand(Vector2i to)
+ {
+ var expanded = this;
+
+ Vector2i begin = expanded._position;
+ Vector2i end = expanded._position + expanded._size;
+
+ if (to.x < begin.x)
+ begin.x = to.x;
+ if (to.y < begin.y)
+ begin.y = to.y;
+
+ if (to.x > end.x)
+ end.x = to.x;
+ if (to.y > end.y)
+ end.y = to.y;
+
+ expanded._position = begin;
+ expanded._size = end - begin;
+
+ return expanded;
+ }
+
+ public int GetArea()
+ {
+ return _size.x * _size.y;
+ }
+
+ public Rect2i Grow(int by)
+ {
+ var g = this;
+
+ g._position.x -= by;
+ g._position.y -= by;
+ g._size.x += by * 2;
+ g._size.y += by * 2;
+
+ return g;
+ }
+
+ public Rect2i GrowIndividual(int left, int top, int right, int bottom)
+ {
+ var g = this;
+
+ g._position.x -= left;
+ g._position.y -= top;
+ g._size.x += left + right;
+ g._size.y += top + bottom;
+
+ return g;
+ }
+
+ public Rect2i GrowMargin(Margin margin, int by)
+ {
+ var g = this;
+
+ g.GrowIndividual(Margin.Left == margin ? by : 0,
+ Margin.Top == margin ? by : 0,
+ Margin.Right == margin ? by : 0,
+ Margin.Bottom == margin ? by : 0);
+
+ return g;
+ }
+
+ public bool HasNoArea()
+ {
+ return _size.x <= 0 || _size.y <= 0;
+ }
+
+ public bool HasPoint(Vector2i point)
+ {
+ if (point.x < _position.x)
+ return false;
+ if (point.y < _position.y)
+ return false;
+
+ if (point.x >= _position.x + _size.x)
+ return false;
+ if (point.y >= _position.y + _size.y)
+ return false;
+
+ return true;
+ }
+
+ public bool Intersects(Rect2i b)
+ {
+ if (_position.x >= b._position.x + b._size.x)
+ return false;
+ if (_position.x + _size.x <= b._position.x)
+ return false;
+ if (_position.y >= b._position.y + b._size.y)
+ return false;
+ if (_position.y + _size.y <= b._position.y)
+ return false;
+
+ return true;
+ }
+
+ public Rect2i Merge(Rect2i b)
+ {
+ Rect2i newRect;
+
+ newRect._position.x = Mathf.Min(b._position.x, _position.x);
+ newRect._position.y = Mathf.Min(b._position.y, _position.y);
+
+ newRect._size.x = Mathf.Max(b._position.x + b._size.x, _position.x + _size.x);
+ newRect._size.y = Mathf.Max(b._position.y + b._size.y, _position.y + _size.y);
+
+ newRect._size = newRect._size - newRect._position; // Make relative again
+
+ return newRect;
+ }
+
+ // Constructors
+ public Rect2i(Vector2i position, Vector2i size)
+ {
+ _position = position;
+ _size = size;
+ }
+ public Rect2i(Vector2i position, int width, int height)
+ {
+ _position = position;
+ _size = new Vector2i(width, height);
+ }
+ public Rect2i(int x, int y, Vector2i size)
+ {
+ _position = new Vector2i(x, y);
+ _size = size;
+ }
+ public Rect2i(int x, int y, int width, int height)
+ {
+ _position = new Vector2i(x, y);
+ _size = new Vector2i(width, height);
+ }
+
+ public static bool operator ==(Rect2i left, Rect2i right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Rect2i left, Rect2i right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static implicit operator Rect2(Rect2i value)
+ {
+ return new Rect2(value._position, value._size);
+ }
+
+ public static explicit operator Rect2i(Rect2 value)
+ {
+ return new Rect2i((Vector2i)value.Position, (Vector2i)value.Size);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Rect2i)
+ {
+ return Equals((Rect2i)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Rect2i other)
+ {
+ return _position.Equals(other._position) && _size.Equals(other._size);
+ }
+
+ public override int GetHashCode()
+ {
+ return _position.GetHashCode() ^ _size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0}, {1}", new object[]
+ {
+ _position.ToString(),
+ _size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0}, {1}", new object[]
+ {
+ _position.ToString(format),
+ _size.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
index 9483b6ffb4..4dc630238b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -9,13 +9,13 @@ namespace Godot
private object[] result;
private Action action;
- public SignalAwaiter(Object source, string signal, Object target)
+ public SignalAwaiter(Object source, StringName signal, Object target)
{
- godot_icall_SignalAwaiter_connect(Object.GetPtr(source), signal, Object.GetPtr(target), this);
+ godot_icall_SignalAwaiter_connect(Object.GetPtr(source), StringName.GetPtr(signal), Object.GetPtr(target), this);
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static Error godot_icall_SignalAwaiter_connect(IntPtr source, string signal, IntPtr target, SignalAwaiter awaiter);
+ internal extern static Error godot_icall_SignalAwaiter_connect(IntPtr source, IntPtr signal, IntPtr target, SignalAwaiter awaiter);
public bool IsCompleted
{
@@ -50,11 +50,5 @@ namespace Godot
action();
}
}
-
- internal void FailureCallback()
- {
- action = null;
- completed = true;
- }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
new file mode 100644
index 0000000000..dc92de7a61
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
@@ -0,0 +1,17 @@
+namespace Godot
+{
+ public struct SignalInfo
+ {
+ private readonly Object _owner;
+ private readonly StringName _signalName;
+
+ public Object Owner => _owner;
+ public StringName Name => _signalName;
+
+ public SignalInfo(Object owner, StringName name)
+ {
+ _owner = owner;
+ _signalName = name;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
new file mode 100644
index 0000000000..7700b6d4ed
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public sealed partial class StringName : IDisposable
+ {
+ private IntPtr ptr;
+
+ internal static IntPtr GetPtr(StringName instance)
+ {
+ if (instance == null)
+ throw new NullReferenceException($"The instance of type {nameof(StringName)} is null.");
+
+ if (instance.ptr == IntPtr.Zero)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
+ }
+
+ ~StringName()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (ptr != IntPtr.Zero)
+ {
+ godot_icall_StringName_Dtor(ptr);
+ ptr = IntPtr.Zero;
+ }
+ }
+
+ internal StringName(IntPtr ptr)
+ {
+ this.ptr = ptr;
+ }
+
+ public StringName()
+ {
+ ptr = IntPtr.Zero;
+ }
+
+ public StringName(string path)
+ {
+ ptr = path == null ? IntPtr.Zero : godot_icall_StringName_Ctor(path);
+ }
+
+ public static implicit operator StringName(string from) => new StringName(from);
+
+ public static implicit operator string(StringName from) => from.ToString();
+
+ public override string ToString()
+ {
+ return ptr == IntPtr.Zero ? string.Empty : godot_icall_StringName_operator_String(GetPtr(this));
+ }
+
+ public bool IsEmpty()
+ {
+ return ptr == IntPtr.Zero || godot_icall_StringName_is_empty(GetPtr(this));
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern IntPtr godot_icall_StringName_Ctor(string path);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void godot_icall_StringName_Dtor(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern string godot_icall_StringName_operator_String(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern bool godot_icall_StringName_is_empty(IntPtr ptr);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 385bfed122..f7b13198f8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -76,11 +76,6 @@ namespace Godot
}
}
- public real_t Cross(Vector2 b)
- {
- return x * b.y - y * b.x;
- }
-
public Vector2 Abs()
{
return new Vector2(Mathf.Abs(x), Mathf.Abs(y));
@@ -130,6 +125,11 @@ namespace Godot
return v;
}
+ public real_t Cross(Vector2 b)
+ {
+ return x * b.y - y * b.x;
+ }
+
public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t)
{
var p0 = preA;
@@ -234,7 +234,7 @@ namespace Godot
public Vector2 Reflect(Vector2 n)
{
- return 2.0f * n * Dot(n) - this;
+ return 2 * Dot(n) * n - this;
}
public Vector2 Rotated(real_t phi)
@@ -352,18 +352,18 @@ namespace Godot
return left;
}
- public static Vector2 operator /(Vector2 vec, real_t scale)
+ public static Vector2 operator /(Vector2 vec, real_t divisor)
{
- vec.x /= scale;
- vec.y /= scale;
+ vec.x /= divisor;
+ vec.y /= divisor;
return vec;
}
- public static Vector2 operator /(Vector2 left, Vector2 right)
+ public static Vector2 operator /(Vector2 vec, Vector2 divisorv)
{
- left.x /= right.x;
- left.y /= right.y;
- return left;
+ vec.x /= divisorv.x;
+ vec.y /= divisorv.y;
+ return vec;
}
public static Vector2 operator %(Vector2 vec, real_t divisor)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
new file mode 100644
index 0000000000..7dc22d7918
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -0,0 +1,380 @@
+using System;
+using System.Runtime.InteropServices;
+
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ /// <summary>
+ /// 2-element structure that can be used to represent 2D grid coordinates or pairs of integers.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector2i : IEquatable<Vector2i>
+ {
+ public enum Axis
+ {
+ X = 0,
+ Y
+ }
+
+ public int x;
+ public int y;
+
+ public int this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Vector2i Abs()
+ {
+ return new Vector2i(Mathf.Abs(x), Mathf.Abs(y));
+ }
+
+ public real_t Angle()
+ {
+ return Mathf.Atan2(y, x);
+ }
+
+ public real_t AngleTo(Vector2i to)
+ {
+ return Mathf.Atan2(Cross(to), Dot(to));
+ }
+
+ public real_t AngleToPoint(Vector2i to)
+ {
+ return Mathf.Atan2(y - to.y, x - to.x);
+ }
+
+ public real_t Aspect()
+ {
+ return x / (real_t)y;
+ }
+
+ public Vector2i Bounce(Vector2i n)
+ {
+ return -Reflect(n);
+ }
+
+ public int Cross(Vector2i b)
+ {
+ return x * b.y - y * b.x;
+ }
+
+ public int DistanceSquaredTo(Vector2i b)
+ {
+ return (b - this).LengthSquared();
+ }
+
+ public real_t DistanceTo(Vector2i b)
+ {
+ return (b - this).Length();
+ }
+
+ public int Dot(Vector2i b)
+ {
+ return x * b.x + y * b.y;
+ }
+
+ public real_t Length()
+ {
+ int x2 = x * x;
+ int y2 = y * y;
+
+ return Mathf.Sqrt(x2 + y2);
+ }
+
+ public int LengthSquared()
+ {
+ int x2 = x * x;
+ int y2 = y * y;
+
+ return x2 + y2;
+ }
+
+ public Axis MaxAxis()
+ {
+ return x < y ? Axis.Y : Axis.X;
+ }
+
+ public Axis MinAxis()
+ {
+ return x > y ? Axis.Y : Axis.X;
+ }
+
+ public Vector2i PosMod(int mod)
+ {
+ Vector2i v = this;
+ v.x = Mathf.PosMod(v.x, mod);
+ v.y = Mathf.PosMod(v.y, mod);
+ return v;
+ }
+
+ public Vector2i PosMod(Vector2i modv)
+ {
+ Vector2i v = this;
+ v.x = Mathf.PosMod(v.x, modv.x);
+ v.y = Mathf.PosMod(v.y, modv.y);
+ return v;
+ }
+
+ public Vector2i Reflect(Vector2i n)
+ {
+ return 2 * Dot(n) * n - this;
+ }
+
+ public Vector2i Sign()
+ {
+ Vector2i v = this;
+ v.x = Mathf.Sign(v.x);
+ v.y = Mathf.Sign(v.y);
+ return v;
+ }
+
+ public Vector2i Tangent()
+ {
+ return new Vector2i(y, -x);
+ }
+
+ // Constants
+ private static readonly Vector2i _zero = new Vector2i(0, 0);
+ private static readonly Vector2i _one = new Vector2i(1, 1);
+
+ private static readonly Vector2i _up = new Vector2i(0, -1);
+ private static readonly Vector2i _down = new Vector2i(0, 1);
+ private static readonly Vector2i _right = new Vector2i(1, 0);
+ private static readonly Vector2i _left = new Vector2i(-1, 0);
+
+ public static Vector2i Zero { get { return _zero; } }
+ public static Vector2i One { get { return _one; } }
+
+ public static Vector2i Up { get { return _up; } }
+ public static Vector2i Down { get { return _down; } }
+ public static Vector2i Right { get { return _right; } }
+ public static Vector2i Left { get { return _left; } }
+
+ // Constructors
+ public Vector2i(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+ public Vector2i(Vector2i vi)
+ {
+ this.x = vi.x;
+ this.y = vi.y;
+ }
+ public Vector2i(Vector2 v)
+ {
+ this.x = Mathf.RoundToInt(v.x);
+ this.y = Mathf.RoundToInt(v.y);
+ }
+
+ public static Vector2i operator +(Vector2i left, Vector2i right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ return left;
+ }
+
+ public static Vector2i operator -(Vector2i left, Vector2i right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ return left;
+ }
+
+ public static Vector2i operator -(Vector2i vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ return vec;
+ }
+
+ public static Vector2i operator *(Vector2i vec, int scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2i operator *(int scale, Vector2i vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2i operator *(Vector2i left, Vector2i right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ return left;
+ }
+
+ public static Vector2i operator /(Vector2i vec, int divisor)
+ {
+ vec.x /= divisor;
+ vec.y /= divisor;
+ return vec;
+ }
+
+ public static Vector2i operator /(Vector2i vec, Vector2i divisorv)
+ {
+ vec.x /= divisorv.x;
+ vec.y /= divisorv.y;
+ return vec;
+ }
+
+ public static Vector2i operator %(Vector2i vec, int divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ return vec;
+ }
+
+ public static Vector2i operator %(Vector2i vec, Vector2i divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ return vec;
+ }
+
+ public static Vector2i operator &(Vector2i vec, int and)
+ {
+ vec.x &= and;
+ vec.y &= and;
+ return vec;
+ }
+
+ public static Vector2i operator &(Vector2i vec, Vector2i andv)
+ {
+ vec.x &= andv.x;
+ vec.y &= andv.y;
+ return vec;
+ }
+
+ public static bool operator ==(Vector2i left, Vector2i right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector2i left, Vector2i right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector2i left, Vector2i right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y < right.y;
+ }
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector2i left, Vector2i right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y > right.y;
+ }
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector2i left, Vector2i right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y <= right.y;
+ }
+ return left.x <= right.x;
+ }
+
+ public static bool operator >=(Vector2i left, Vector2i right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y >= right.y;
+ }
+ return left.x >= right.x;
+ }
+
+ public static implicit operator Vector2(Vector2i value)
+ {
+ return new Vector2(value.x, value.y);
+ }
+
+ public static explicit operator Vector2i(Vector2 value)
+ {
+ return new Vector2i(value);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector2i)
+ {
+ return Equals((Vector2i)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector2i other)
+ {
+ return x == other.x && y == other.y;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 390036c654..a43836e985 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -400,20 +400,20 @@ namespace Godot
return left;
}
- public static Vector3 operator /(Vector3 vec, real_t scale)
+ public static Vector3 operator /(Vector3 vec, real_t divisor)
{
- vec.x /= scale;
- vec.y /= scale;
- vec.z /= scale;
+ vec.x /= divisor;
+ vec.y /= divisor;
+ vec.z /= divisor;
return vec;
}
- public static Vector3 operator /(Vector3 left, Vector3 right)
+ public static Vector3 operator /(Vector3 vec, Vector3 divisorv)
{
- left.x /= right.x;
- left.y /= right.y;
- left.z /= right.z;
- return left;
+ vec.x /= divisorv.x;
+ vec.y /= divisorv.y;
+ vec.z /= divisorv.z;
+ return vec;
}
public static Vector3 operator %(Vector3 vec, real_t divisor)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
new file mode 100644
index 0000000000..c17f900131
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Runtime.InteropServices;
+
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ /// <summary>
+ /// 3-element structure that can be used to represent 3D grid coordinates or sets of integers.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector3i : IEquatable<Vector3i>
+ {
+ public enum Axis
+ {
+ X = 0,
+ Y,
+ Z
+ }
+
+ public int x;
+ public int y;
+ public int z;
+
+ public int this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Vector3i Abs()
+ {
+ Vector3i v = this;
+ if (v.x < 0)
+ {
+ v.x = -v.x;
+ }
+ if (v.y < 0)
+ {
+ v.y = -v.y;
+ }
+ if (v.z < 0)
+ {
+ v.z = -v.z;
+ }
+ return v;
+ }
+
+ public int DistanceSquaredTo(Vector3i b)
+ {
+ return (b - this).LengthSquared();
+ }
+
+ public real_t DistanceTo(Vector3i b)
+ {
+ return (b - this).Length();
+ }
+
+ public int Dot(Vector3i b)
+ {
+ return x * b.x + y * b.y + z * b.z;
+ }
+
+ public real_t Length()
+ {
+ int x2 = x * x;
+ int y2 = y * y;
+ int z2 = z * z;
+
+ return Mathf.Sqrt(x2 + y2 + z2);
+ }
+
+ public int LengthSquared()
+ {
+ int x2 = x * x;
+ int y2 = y * y;
+ int z2 = z * z;
+
+ return x2 + y2 + z2;
+ }
+
+ public Axis MaxAxis()
+ {
+ return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
+ }
+
+ public Axis MinAxis()
+ {
+ return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
+ }
+
+ public Vector3i PosMod(int mod)
+ {
+ Vector3i v = this;
+ v.x = Mathf.PosMod(v.x, mod);
+ v.y = Mathf.PosMod(v.y, mod);
+ v.z = Mathf.PosMod(v.z, mod);
+ return v;
+ }
+
+ public Vector3i PosMod(Vector3i modv)
+ {
+ Vector3i v = this;
+ v.x = Mathf.PosMod(v.x, modv.x);
+ v.y = Mathf.PosMod(v.y, modv.y);
+ v.z = Mathf.PosMod(v.z, modv.z);
+ return v;
+ }
+
+ public Vector3i Sign()
+ {
+ Vector3i v = this;
+ v.x = Mathf.Sign(v.x);
+ v.y = Mathf.Sign(v.y);
+ v.z = Mathf.Sign(v.z);
+ return v;
+ }
+
+ // Constants
+ private static readonly Vector3i _zero = new Vector3i(0, 0, 0);
+ private static readonly Vector3i _one = new Vector3i(1, 1, 1);
+
+ private static readonly Vector3i _up = new Vector3i(0, 1, 0);
+ private static readonly Vector3i _down = new Vector3i(0, -1, 0);
+ private static readonly Vector3i _right = new Vector3i(1, 0, 0);
+ private static readonly Vector3i _left = new Vector3i(-1, 0, 0);
+ private static readonly Vector3i _forward = new Vector3i(0, 0, -1);
+ private static readonly Vector3i _back = new Vector3i(0, 0, 1);
+
+ public static Vector3i Zero { get { return _zero; } }
+ public static Vector3i One { get { return _one; } }
+
+ public static Vector3i Up { get { return _up; } }
+ public static Vector3i Down { get { return _down; } }
+ public static Vector3i Right { get { return _right; } }
+ public static Vector3i Left { get { return _left; } }
+ public static Vector3i Forward { get { return _forward; } }
+ public static Vector3i Back { get { return _back; } }
+
+ // Constructors
+ public Vector3i(int x, int y, int z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+ public Vector3i(Vector3i vi)
+ {
+ this.x = vi.x;
+ this.y = vi.y;
+ this.z = vi.z;
+ }
+ public Vector3i(Vector3 v)
+ {
+ this.x = Mathf.RoundToInt(v.x);
+ this.y = Mathf.RoundToInt(v.y);
+ this.z = Mathf.RoundToInt(v.z);
+ }
+
+ public static Vector3i operator +(Vector3i left, Vector3i right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ left.z += right.z;
+ return left;
+ }
+
+ public static Vector3i operator -(Vector3i left, Vector3i right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ left.z -= right.z;
+ return left;
+ }
+
+ public static Vector3i operator -(Vector3i vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ vec.z = -vec.z;
+ return vec;
+ }
+
+ public static Vector3i operator *(Vector3i vec, int scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3i operator *(int scale, Vector3i vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3i operator *(Vector3i left, Vector3i right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ left.z *= right.z;
+ return left;
+ }
+
+ public static Vector3i operator /(Vector3i vec, int divisor)
+ {
+ vec.x /= divisor;
+ vec.y /= divisor;
+ vec.z /= divisor;
+ return vec;
+ }
+
+ public static Vector3i operator /(Vector3i vec, Vector3i divisorv)
+ {
+ vec.x /= divisorv.x;
+ vec.y /= divisorv.y;
+ vec.z /= divisorv.z;
+ return vec;
+ }
+
+ public static Vector3i operator %(Vector3i vec, int divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ vec.z %= divisor;
+ return vec;
+ }
+
+ public static Vector3i operator %(Vector3i vec, Vector3i divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ vec.z %= divisorv.z;
+ return vec;
+ }
+
+ public static Vector3i operator &(Vector3i vec, int and)
+ {
+ vec.x &= and;
+ vec.y &= and;
+ vec.z &= and;
+ return vec;
+ }
+
+ public static Vector3i operator &(Vector3i vec, Vector3i andv)
+ {
+ vec.x &= andv.x;
+ vec.y &= andv.y;
+ vec.z &= andv.z;
+ return vec;
+ }
+
+ public static bool operator ==(Vector3i left, Vector3i right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector3i left, Vector3i right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector3i left, Vector3i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z < right.z;
+ else
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector3i left, Vector3i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z > right.z;
+ else
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector3i left, Vector3i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z <= right.z;
+ else
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >=(Vector3i left, Vector3i right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z >= right.z;
+ else
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static implicit operator Vector3(Vector3i value)
+ {
+ return new Vector3(value.x, value.y, value.z);
+ }
+
+ public static explicit operator Vector3i(Vector3 value)
+ {
+ return new Vector3i(value);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector3i)
+ {
+ return Equals((Vector3i)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector3i other)
+ {
+ return x == other.x && y == other.y && z == other.z;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 5419cd06e6..ba0bbd7630 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -41,9 +41,11 @@
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />
<Compile Include="Core\Basis.cs" />
+ <Compile Include="Core\Callable.cs" />
<Compile Include="Core\Color.cs" />
<Compile Include="Core\Colors.cs" />
<Compile Include="Core\DebuggingUtils.cs" />
+ <Compile Include="Core\DelegateUtils.cs" />
<Compile Include="Core\Dictionary.cs" />
<Compile Include="Core\Dispatcher.cs" />
<Compile Include="Core\DynamicObject.cs" />
@@ -65,13 +67,18 @@
<Compile Include="Core\Plane.cs" />
<Compile Include="Core\Quat.cs" />
<Compile Include="Core\Rect2.cs" />
+ <Compile Include="Core\Rect2i.cs" />
<Compile Include="Core\RID.cs" />
+ <Compile Include="Core\SignalInfo.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
<Compile Include="Core\StringExtensions.cs" />
+ <Compile Include="Core\StringName.cs" />
<Compile Include="Core\Transform.cs" />
<Compile Include="Core\Transform2D.cs" />
<Compile Include="Core\Vector2.cs" />
+ <Compile Include="Core\Vector2i.cs" />
<Compile Include="Core\Vector3.cs" />
+ <Compile Include="Core\Vector3i.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<!--
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 8c77220b85..f370883320 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -51,7 +51,7 @@ Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_ptr == NULL);
+ CRASH_COND(p_ptr == nullptr);
#endif
if (p_ptr->get_script_instance()) {
@@ -59,7 +59,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
if (cs_instance) {
if (!cs_instance->is_destructing_script_instance()) {
cs_instance->mono_object_disposed(p_obj);
- p_ptr->set_script_instance(NULL);
+ p_ptr->set_script_instance(nullptr);
}
return;
}
@@ -70,8 +70,8 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
if (data) {
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
- if (gchandle.is_valid()) {
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+ if (!gchandle.is_released()) {
CSharpLanguage::release_script_gchandle(p_obj, gchandle);
}
}
@@ -80,7 +80,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_ptr == NULL);
+ CRASH_COND(p_ptr == nullptr);
// This is only called with Reference derived classes
CRASH_COND(!Object::cast_to<Reference>(p_ptr));
#endif
@@ -99,7 +99,7 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea
if (delete_owner) {
memdelete(ref);
} else if (remove_script_instance) {
- ref->set_script_instance(NULL);
+ ref->set_script_instance(nullptr);
}
}
return;
@@ -117,8 +117,8 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea
if (data) {
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
- if (gchandle.is_valid()) {
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+ if (!gchandle.is_released()) {
CSharpLanguage::release_script_gchandle(p_obj, gchandle);
}
}
@@ -126,37 +126,44 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea
}
}
-MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method) {
- StringName type(GDMonoMarshal::mono_string_to_godot(p_type));
+void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
+ CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
+ if (csharp_instance) {
+ csharp_instance->connect_event_signals();
+ }
+}
+
+MethodBind *godot_icall_Object_ClassDB_get_method(StringName *p_type, MonoString *p_method) {
+ StringName type = p_type ? *p_type : StringName();
StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
return ClassDB::get_method(type, method);
}
-MonoObject *godot_icall_Object_weakref(Object *p_obj) {
- if (!p_obj)
- return NULL;
+MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
+ if (!p_ptr)
+ return nullptr;
Ref<WeakRef> wref;
- Reference *ref = Object::cast_to<Reference>(p_obj);
+ Reference *ref = Object::cast_to<Reference>(p_ptr);
if (ref) {
REF r = ref;
if (!r.is_valid())
- return NULL;
+ return nullptr;
wref.instance();
wref->set_ref(r);
} else {
wref.instance();
- wref->set_obj(p_obj);
+ wref->set_obj(p_ptr);
}
return GDMonoUtils::unmanaged_get_managed(wref.ptr());
}
-Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) {
- String signal = GDMonoMarshal::mono_string_to_godot(p_signal);
- return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
+Error godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
+ StringName signal = p_signal ? *p_signal : StringName();
+ return gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
}
MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
@@ -223,10 +230,10 @@ MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *
MonoString *godot_icall_Object_ToString(Object *p_ptr) {
#ifdef DEBUG_ENABLED
// Cannot happen in C#; would get an ObjectDisposedException instead.
- CRASH_COND(p_ptr == NULL);
+ CRASH_COND(p_ptr == nullptr);
#endif
-
- String result = p_ptr->to_string();
+ // Can't call 'Object::to_string()' here, as that can end up calling 'ToString' again resulting in an endless circular loop.
+ String result = "[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]";
return GDMonoMarshal::mono_string_from_godot(result);
}
diff --git a/modules/mono/glue/base_object_glue.h b/modules/mono/glue/base_object_glue.h
index 22532dcff9..67769f3061 100644
--- a/modules/mono/glue/base_object_glue.h
+++ b/modules/mono/glue/base_object_glue.h
@@ -44,11 +44,13 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr);
void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer);
-MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method);
+void godot_icall_Object_ConnectEventSignals(Object *p_ptr);
-MonoObject *godot_icall_Object_weakref(Object *p_obj);
+MethodBind *godot_icall_Object_ClassDB_get_method(StringName *p_type, MonoString *p_method);
-Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter);
+MonoObject *godot_icall_Object_weakref(Object *p_ptr);
+
+Error godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter);
// DynamicGodotObject
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index b7fa7fcab2..4e3dc9c4ea 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -49,7 +49,7 @@ void godot_icall_Array_Dtor(Array *ptr) {
MonoObject *godot_icall_Array_At(Array *ptr, int index) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return NULL;
+ return nullptr;
}
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
}
@@ -57,7 +57,7 @@ MonoObject *godot_icall_Array_At(Array *ptr, int index) {
MonoObject *godot_icall_Array_At_Generic(Array *ptr, int index, uint32_t type_encoding, GDMonoClass *type_class) {
if (index < 0 || index >= ptr->size()) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return NULL;
+ return nullptr;
}
return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
}
@@ -162,28 +162,28 @@ void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == NULL) {
+ if (ret == nullptr) {
MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
#ifdef DEBUG_ENABLED
CRASH_COND(!exc);
#endif
GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
GDMonoUtils::set_pending_exception((MonoException *)exc);
- return NULL;
+ return nullptr;
}
return GDMonoMarshal::variant_to_mono_object(ret);
}
MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == NULL) {
+ if (ret == nullptr) {
MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
#ifdef DEBUG_ENABLED
CRASH_COND(!exc);
#endif
GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
GDMonoUtils::set_pending_exception((MonoException *)exc);
- return NULL;
+ return nullptr;
}
return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
}
@@ -207,7 +207,7 @@ int godot_icall_Dictionary_Count(Dictionary *ptr) {
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
Variant *ret = ptr->getptr(varKey);
- if (ret != NULL) {
+ if (ret != nullptr) {
GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists"));
return;
}
@@ -221,7 +221,7 @@ void godot_icall_Dictionary_Clear(Dictionary *ptr) {
MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
// no dupes
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value);
+ return ret != nullptr && *ret == GDMonoMarshal::mono_object_to_variant(value);
}
MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
@@ -241,7 +241,7 @@ MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, Mono
// no dupes
Variant *ret = ptr->getptr(varKey);
- if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
+ if (ret != nullptr && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
ptr->erase(varKey);
return true;
}
@@ -251,8 +251,8 @@ MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, Mono
MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == NULL) {
- *value = NULL;
+ if (ret == nullptr) {
+ *value = nullptr;
return false;
}
*value = GDMonoMarshal::variant_to_mono_object(ret);
@@ -261,8 +261,8 @@ MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key,
MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == NULL) {
- *value = NULL;
+ if (ret == nullptr) {
+ *value = nullptr;
return false;
}
*value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index cdacd90538..2da39a916a 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -45,7 +45,7 @@
MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
Variant ret;
PackedByteArray varr = GDMonoMarshal::mono_array_to_PackedByteArray(p_bytes);
- Error err = decode_variant(ret, varr.ptr(), varr.size(), NULL, p_allow_objects);
+ Error err = decode_variant(ret, varr.ptr(), varr.size(), nullptr, p_allow_objects);
if (err != OK) {
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
}
@@ -57,7 +57,7 @@ MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type) {
const Variant *args[1] = { &what };
Callable::CallError ce;
Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
- ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, NULL);
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
return GDMonoMarshal::variant_to_mono_object(ret);
}
@@ -76,7 +76,7 @@ void godot_icall_GD_print(MonoArray *p_what) {
for (int i = 0; i < length; i++) {
MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
if (exc) {
@@ -98,7 +98,7 @@ void godot_icall_GD_printerr(MonoArray *p_what) {
for (int i = 0; i < length; i++) {
MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
if (exc) {
@@ -119,7 +119,7 @@ void godot_icall_GD_printraw(MonoArray *p_what) {
for (int i = 0; i < length; i++) {
MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
if (exc) {
@@ -140,7 +140,7 @@ void godot_icall_GD_prints(MonoArray *p_what) {
for (int i = 0; i < length; i++) {
MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
if (exc) {
@@ -164,7 +164,7 @@ void godot_icall_GD_printt(MonoArray *p_what) {
for (int i = 0; i < length; i++) {
MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
if (exc) {
@@ -241,8 +241,9 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
return GDMonoMarshal::variant_to_mono_object(ret);
}
-MonoBoolean godot_icall_GD_type_exists(MonoString *p_type) {
- return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
+MonoBoolean godot_icall_GD_type_exists(StringName *p_type) {
+ StringName type = p_type ? *p_type : StringName();
+ return ClassDB::class_exists(type);
}
void godot_icall_GD_pusherror(MonoString *p_str) {
@@ -258,8 +259,8 @@ MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_object
PackedByteArray barr;
int len;
- Error err = encode_variant(var, NULL, len, p_full_objects);
- ERR_FAIL_COND_V_MSG(err != OK, NULL, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
+ Error err = encode_variant(var, nullptr, len, p_full_objects);
+ ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
barr.resize(len);
encode_variant(var, barr.ptrw(), len, p_full_objects);
@@ -273,6 +274,10 @@ MonoString *godot_icall_GD_var2str(MonoObject *p_var) {
return GDMonoMarshal::mono_string_from_godot(vars);
}
+uint32_t godot_icall_TypeToVariantType(MonoReflectionType *p_refl_type) {
+ return (uint32_t)GDMonoMarshal::managed_to_variant_type(ManagedType::from_reftype(p_refl_type));
+}
+
MonoObject *godot_icall_DefaultGodotTaskScheduler() {
return GDMonoCache::cached_data.task_scheduler_handle->get_target();
}
@@ -300,6 +305,7 @@ void godot_register_gd_icalls() {
mono_add_internal_call("Godot.GD::godot_icall_GD_type_exists", (void *)godot_icall_GD_type_exists);
mono_add_internal_call("Godot.GD::godot_icall_GD_var2bytes", (void *)godot_icall_GD_var2bytes);
mono_add_internal_call("Godot.GD::godot_icall_GD_var2str", (void *)godot_icall_GD_var2str);
+ mono_add_internal_call("Godot.GD::godot_icall_TypeToVariantType", (void *)godot_icall_TypeToVariantType);
// Dispatcher
mono_add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", (void *)godot_icall_DefaultGodotTaskScheduler);
diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h
index f00e2efc5d..3ad6058205 100644
--- a/modules/mono/glue/gd_glue.h
+++ b/modules/mono/glue/gd_glue.h
@@ -69,7 +69,7 @@ MonoString *godot_icall_GD_str(MonoArray *p_what);
MonoObject *godot_icall_GD_str2var(MonoString *p_str);
-MonoBoolean godot_icall_GD_type_exists(MonoString *p_type);
+MonoBoolean godot_icall_GD_type_exists(StringName *p_type);
MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects);
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index 758b71f719..ee99a300b9 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -36,6 +36,7 @@
#include "nodepath_glue.h"
#include "rid_glue.h"
#include "string_glue.h"
+#include "string_name_glue.h"
/**
* Registers internal calls that were not generated. This function is called
@@ -44,6 +45,7 @@
void godot_register_glue_header_icalls() {
godot_register_collections_icalls();
godot_register_gd_icalls();
+ godot_register_string_name_icalls();
godot_register_nodepath_icalls();
godot_register_object_icalls();
godot_register_rid_icalls();
@@ -68,7 +70,7 @@ void godot_register_glue_header_icalls() {
#include "../mono_gd/gd_mono_utils.h"
#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \
- static ClassDB::ClassInfo *ci = NULL; \
+ static ClassDB::ClassInfo *ci = nullptr; \
if (!ci) { \
ci = ClassDB::classes.getptr(m_type); \
} \
diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp
new file mode 100644
index 0000000000..81006e5849
--- /dev/null
+++ b/modules/mono/glue/string_name_glue.cpp
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* string_name_glue.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "string_name_glue.h"
+
+#ifdef MONO_GLUE_ENABLED
+
+#include "core/ustring.h"
+
+StringName *godot_icall_StringName_Ctor(MonoString *p_path) {
+ return memnew(StringName(GDMonoMarshal::mono_string_to_godot(p_path)));
+}
+
+void godot_icall_StringName_Dtor(StringName *p_ptr) {
+ ERR_FAIL_NULL(p_ptr);
+ memdelete(p_ptr);
+}
+
+MonoString *godot_icall_StringName_operator_String(StringName *p_np) {
+ return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
+}
+
+MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) {
+ return (MonoBoolean)(p_ptr == StringName());
+}
+
+void godot_register_string_name_icalls() {
+ mono_add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", (void *)godot_icall_StringName_Ctor);
+ mono_add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", (void *)godot_icall_StringName_Dtor);
+ mono_add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", (void *)godot_icall_StringName_operator_String);
+ mono_add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", (void *)godot_icall_StringName_is_empty);
+}
+
+#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_name_glue.h b/modules/mono/glue/string_name_glue.h
new file mode 100644
index 0000000000..88354ddd84
--- /dev/null
+++ b/modules/mono/glue/string_name_glue.h
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* string_name_glue.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 STRING_NAME_GLUE_H
+#define STRING_NAME_GLUE_H
+
+#ifdef MONO_GLUE_ENABLED
+
+#include "core/string_name.h"
+
+#include "../mono_gd/gd_mono_marshal.h"
+
+StringName *godot_icall_StringName_Ctor(MonoString *p_path);
+
+void godot_icall_StringName_Dtor(StringName *p_ptr);
+
+MonoString *godot_icall_StringName_operator_String(StringName *p_np);
+
+MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr);
+
+// Register internal calls
+
+void godot_register_string_name_icalls();
+
+#endif // MONO_GLUE_ENABLED
+
+#endif // STRING_NAME_GLUE_H
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 47eb432490..fe8b925257 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -40,7 +40,7 @@
#endif
#ifdef ANDROID_ENABLED
-#include "mono_gd/gd_mono_android.h"
+#include "mono_gd/support/mono-support.h"
#endif
#include "mono_gd/gd_mono.h"
@@ -49,13 +49,13 @@ namespace GodotSharpDirs {
String _get_expected_build_config() {
#ifdef TOOLS_ENABLED
- return "Tools";
+ return "Debug";
#else
#ifdef DEBUG_ENABLED
- return "Debug";
+ return "ExportDebug";
#else
- return "Release";
+ return "ExportRelease";
#endif
#endif
@@ -169,7 +169,7 @@ private:
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
#ifdef ANDROID_ENABLED
- data_mono_lib_dir = GDMonoAndroid::get_app_native_lib_dir();
+ data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
#else
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
#endif
@@ -206,7 +206,7 @@ private:
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
#ifdef ANDROID_ENABLED
- data_mono_lib_dir = GDMonoAndroid::get_app_native_lib_dir();
+ data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
#else
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
data_game_assemblies_dir = data_dir_root.plus_file("Assemblies");
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
new file mode 100644
index 0000000000..dfd78a8244
--- /dev/null
+++ b/modules/mono/managed_callable.cpp
@@ -0,0 +1,145 @@
+/*************************************************************************/
+/* managed_callable.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "managed_callable.h"
+
+#include "csharp_script.h"
+#include "mono_gd/gd_mono_marshal.h"
+#include "mono_gd/gd_mono_utils.h"
+
+#ifdef GD_MONO_HOT_RELOAD
+SelfList<ManagedCallable>::List ManagedCallable::instances;
+Map<ManagedCallable *, Array> ManagedCallable::instances_pending_reload;
+Mutex ManagedCallable::instances_mutex;
+#endif
+
+bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const ManagedCallable *a = static_cast<const ManagedCallable *>(p_a);
+ const ManagedCallable *b = static_cast<const ManagedCallable *>(p_b);
+
+ MonoDelegate *delegate_a = (MonoDelegate *)a->delegate_handle.get_target();
+ MonoDelegate *delegate_b = (MonoDelegate *)b->delegate_handle.get_target();
+
+ if (!delegate_a || !delegate_b) {
+ if (!delegate_a && !delegate_b)
+ return true;
+ return false;
+ }
+
+ // Call Delegate's 'Equals'
+ return GDMonoUtils::mono_delegate_equal(delegate_a, delegate_b);
+}
+
+bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ if (compare_equal(p_a, p_b))
+ return false;
+ return p_a < p_b;
+}
+
+uint32_t ManagedCallable::hash() const {
+ // hmm
+ uint32_t hash = delegate_invoke->get_name().hash();
+ return hash_djb2_one_64(delegate_handle.handle, hash);
+}
+
+String ManagedCallable::get_as_text() const {
+ return "Delegate::Invoke";
+}
+
+CallableCustom::CompareEqualFunc ManagedCallable::get_compare_equal_func() const {
+ return compare_equal_func_ptr;
+}
+
+CallableCustom::CompareLessFunc ManagedCallable::get_compare_less_func() const {
+ return compare_less_func_ptr;
+}
+
+ObjectID ManagedCallable::get_object() const {
+ return CSharpLanguage::get_singleton()->get_managed_callable_middleman()->get_instance_id();
+}
+
+void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
+ r_return_value = Variant();
+
+#ifdef GD_MONO_HOT_RELOAD
+ // Lost during hot-reload
+ ERR_FAIL_NULL(delegate_invoke);
+ ERR_FAIL_COND(delegate_handle.is_released());
+#endif
+
+ ERR_FAIL_COND(delegate_invoke->get_parameters_count() < p_argcount);
+
+ MonoObject *delegate = delegate_handle.get_target();
+
+ MonoException *exc = nullptr;
+ MonoObject *ret = delegate_invoke->invoke(delegate, p_arguments, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ } else {
+ r_return_value = GDMonoMarshal::mono_object_to_variant(ret);
+ r_call_error.error = Callable::CallError::CALL_OK;
+ }
+}
+
+void ManagedCallable::set_delegate(MonoDelegate *p_delegate) {
+ delegate_handle = MonoGCHandleData::new_strong_handle((MonoObject *)p_delegate);
+ MonoMethod *delegate_invoke_raw = mono_get_delegate_invoke(mono_object_get_class((MonoObject *)p_delegate));
+ const StringName &delegate_invoke_name = CSharpLanguage::get_singleton()->get_string_names().delegate_invoke_method_name;
+ delegate_invoke = memnew(GDMonoMethod(delegate_invoke_name, delegate_invoke_raw)); // TODO: Use pooling for this GDMonoMethod instances
+}
+
+ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_delegate == nullptr);
+#endif
+
+ set_delegate(p_delegate);
+
+#ifdef GD_MONO_HOT_RELOAD
+ {
+ MutexLock lock(instances_mutex);
+ instances.add(&self_instance);
+ }
+#endif
+}
+
+ManagedCallable::~ManagedCallable() {
+#ifdef GD_MONO_HOT_RELOAD
+ {
+ MutexLock lock(instances_mutex);
+ instances.remove(&self_instance);
+ instances_pending_reload.erase(this);
+ }
+#endif
+
+ delegate_handle.release();
+}
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
new file mode 100644
index 0000000000..4f71e14a2f
--- /dev/null
+++ b/modules/mono/managed_callable.h
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* managed_callable.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 MANAGED_CALLABLE_H
+#define MANAGED_CALLABLE_H
+
+#include <mono/metadata/object.h>
+
+#include "core/callable.h"
+#include "core/os/mutex.h"
+#include "core/self_list.h"
+
+#include "mono_gc_handle.h"
+#include "mono_gd/gd_mono_method.h"
+
+class ManagedCallable : public CallableCustom {
+ friend class CSharpLanguage;
+ MonoGCHandleData delegate_handle;
+ GDMonoMethod *delegate_invoke;
+
+#ifdef GD_MONO_HOT_RELOAD
+ SelfList<ManagedCallable> self_instance = this;
+ static SelfList<ManagedCallable>::List instances;
+ static Map<ManagedCallable *, Array> instances_pending_reload;
+ static Mutex instances_mutex;
+#endif
+
+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;
+
+ _FORCE_INLINE_ MonoDelegate *get_delegate() { return (MonoDelegate *)delegate_handle.get_target(); }
+
+ void set_delegate(MonoDelegate *p_delegate);
+
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
+
+ static constexpr CompareEqualFunc compare_equal_func_ptr = &ManagedCallable::compare_equal;
+ static constexpr CompareEqualFunc compare_less_func_ptr = &ManagedCallable::compare_less;
+
+ ManagedCallable(MonoDelegate *p_delegate);
+ ~ManagedCallable();
+};
+
+#endif // MANAGED_CALLABLE_H
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index feeea848ee..e362d5affb 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -32,56 +32,35 @@
#include "mono_gd/gd_mono.h"
-uint32_t MonoGCHandle::new_strong_handle(MonoObject *p_object) {
-
- return mono_gchandle_new(p_object, /* pinned: */ false);
-}
-
-uint32_t MonoGCHandle::new_strong_handle_pinned(MonoObject *p_object) {
-
- return mono_gchandle_new(p_object, /* pinned: */ true);
-}
-
-uint32_t MonoGCHandle::new_weak_handle(MonoObject *p_object) {
-
- return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false);
-}
-
-void MonoGCHandle::free_handle(uint32_t p_gchandle) {
+void MonoGCHandleData::release() {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(handle && GDMono::get_singleton() == nullptr);
+#endif
- mono_gchandle_free(p_gchandle);
+ if (handle && GDMono::get_singleton()->is_runtime_initialized()) {
+ GDMonoUtils::free_gchandle(handle);
+ handle = 0;
+ }
}
-Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
-
- return memnew(MonoGCHandle(new_strong_handle(p_object), STRONG_HANDLE));
+MonoGCHandleData MonoGCHandleData::new_strong_handle(MonoObject *p_object) {
+ return MonoGCHandleData(GDMonoUtils::new_strong_gchandle(p_object), gdmono::GCHandleType::STRONG_HANDLE);
}
-Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
-
- return memnew(MonoGCHandle(new_weak_handle(p_object), WEAK_HANDLE));
+MonoGCHandleData MonoGCHandleData::new_strong_handle_pinned(MonoObject *p_object) {
+ return MonoGCHandleData(GDMonoUtils::new_strong_gchandle_pinned(p_object), gdmono::GCHandleType::STRONG_HANDLE);
}
-void MonoGCHandle::release() {
-
-#ifdef DEBUG_ENABLED
- CRASH_COND(!released && GDMono::get_singleton() == NULL);
-#endif
-
- if (!released && GDMono::get_singleton()->is_runtime_initialized()) {
- free_handle(handle);
- released = true;
- }
+MonoGCHandleData MonoGCHandleData::new_weak_handle(MonoObject *p_object) {
+ return MonoGCHandleData(GDMonoUtils::new_weak_gchandle(p_object), gdmono::GCHandleType::WEAK_HANDLE);
}
-MonoGCHandle::MonoGCHandle(uint32_t p_handle, HandleType p_handle_type) {
+Ref<MonoGCHandleRef> MonoGCHandleRef::create_strong(MonoObject *p_object) {
- released = false;
- weak = p_handle_type == WEAK_HANDLE;
- handle = p_handle;
+ return memnew(MonoGCHandleRef(MonoGCHandleData::new_strong_handle(p_object)));
}
-MonoGCHandle::~MonoGCHandle() {
+Ref<MonoGCHandleRef> MonoGCHandleRef::create_weak(MonoObject *p_object) {
- release();
+ return memnew(MonoGCHandleRef(MonoGCHandleData::new_weak_handle(p_object)));
}
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index 37fc7d8a17..fbcb405b0d 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -35,42 +35,79 @@
#include "core/reference.h"
-class MonoGCHandle : public Reference {
+namespace gdmono {
- GDCLASS(MonoGCHandle, Reference);
+enum class GCHandleType : char {
+ NIL,
+ STRONG_HANDLE,
+ WEAK_HANDLE
+};
+
+}
- bool released;
- bool weak;
+// Manual release of the GC handle must be done when using this struct
+struct MonoGCHandleData {
uint32_t handle;
+ gdmono::GCHandleType type;
-public:
- enum HandleType {
- STRONG_HANDLE,
- WEAK_HANDLE
- };
+ _FORCE_INLINE_ bool is_released() const { return !handle; }
+ _FORCE_INLINE_ bool is_weak() const { return type == gdmono::GCHandleType::WEAK_HANDLE; }
- static uint32_t new_strong_handle(MonoObject *p_object);
- static uint32_t new_strong_handle_pinned(MonoObject *p_object);
- static uint32_t new_weak_handle(MonoObject *p_object);
- static void free_handle(uint32_t p_gchandle);
+ _FORCE_INLINE_ MonoObject *get_target() const { return handle ? mono_gchandle_get_target(handle) : nullptr; }
- static Ref<MonoGCHandle> create_strong(MonoObject *p_object);
- static Ref<MonoGCHandle> create_weak(MonoObject *p_object);
+ void release();
- _FORCE_INLINE_ bool is_released() { return released; }
- _FORCE_INLINE_ bool is_weak() { return weak; }
+ MonoGCHandleData &operator=(const MonoGCHandleData &p_other) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!is_released());
+#endif
+ handle = p_other.handle;
+ type = p_other.type;
+ return *this;
+ }
- _FORCE_INLINE_ MonoObject *get_target() const { return released ? NULL : mono_gchandle_get_target(handle); }
+ MonoGCHandleData(const MonoGCHandleData &) = default;
- _FORCE_INLINE_ void set_handle(uint32_t p_handle, HandleType p_handle_type) {
- released = false;
- weak = p_handle_type == WEAK_HANDLE;
- handle = p_handle;
+ MonoGCHandleData() :
+ handle(0),
+ type(gdmono::GCHandleType::NIL) {
}
- void release();
- MonoGCHandle(uint32_t p_handle, HandleType p_handle_type);
- ~MonoGCHandle();
+ MonoGCHandleData(uint32_t p_handle, gdmono::GCHandleType p_type) :
+ handle(p_handle),
+ type(p_type) {
+ }
+
+ static MonoGCHandleData new_strong_handle(MonoObject *p_object);
+ static MonoGCHandleData new_strong_handle_pinned(MonoObject *p_object);
+ static MonoGCHandleData new_weak_handle(MonoObject *p_object);
+};
+
+class MonoGCHandleRef : public Reference {
+
+ GDCLASS(MonoGCHandleRef, Reference);
+
+ MonoGCHandleData data;
+
+public:
+ static Ref<MonoGCHandleRef> create_strong(MonoObject *p_object);
+ static Ref<MonoGCHandleRef> create_weak(MonoObject *p_object);
+
+ _FORCE_INLINE_ bool is_released() const { return data.is_released(); }
+ _FORCE_INLINE_ bool is_weak() const { return data.is_weak(); }
+
+ _FORCE_INLINE_ MonoObject *get_target() const { return data.get_target(); }
+
+ void release() { data.release(); }
+
+ _FORCE_INLINE_ void set_handle(uint32_t p_handle, gdmono::GCHandleType p_handle_type) {
+ data = MonoGCHandleData(p_handle, p_handle_type);
+ }
+
+ MonoGCHandleRef(const MonoGCHandleData &p_gc_handle_data) :
+ data(p_gc_handle_data) {
+ }
+ ~MonoGCHandleRef() { release(); }
};
#endif // CSHARP_GC_HANDLE_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index eb4c263745..306a1997ab 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -58,14 +58,25 @@
#ifdef ANDROID_ENABLED
#include "android_mono_config.h"
-#include "gd_mono_android.h"
+#include "support/android_support.h"
+#elif defined(IPHONE_ENABLED)
+#include "support/ios_support.h"
+#endif
+
+#if defined(TOOL_ENABLED) && defined(GD_MONO_SINGLE_APPDOMAIN)
+// This will no longer be the case if we replace appdomains with AssemblyLoadContext
+#error "Editor build requires support for multiple appdomains"
+#endif
+
+#if defined(GD_MONO_HOT_RELOAD) && defined(GD_MONO_SINGLE_APPDOMAIN)
+#error "Hot reloading requires multiple appdomains"
#endif
// TODO:
// This has turn into a gigantic mess. There's too much going on here. Too much #ifdef as well.
// It's just painful to read... It needs to be re-structured. Please, clean this up, future me.
-GDMono *GDMono::singleton = NULL;
+GDMono *GDMono::singleton = nullptr;
namespace {
@@ -178,7 +189,14 @@ MonoDomain *gd_initialize_mono_runtime() {
gd_mono_debug_init();
#endif
- return mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
+#if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED)
+ // I don't know whether this actually matters or not
+ const char *runtime_version = "mobile";
+#else
+ const char *runtime_version = "v4.0.30319";
+#endif
+
+ return mono_jit_init_version("GodotEngine.RootDomain", runtime_version);
}
#endif
@@ -314,14 +332,22 @@ void GDMono::initialize() {
determine_mono_dirs(assembly_rootdir, config_dir);
// Leak if we call mono_set_dirs more than once
- mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL,
- config_dir.length() ? config_dir.utf8().get_data() : NULL);
+ mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : nullptr,
+ config_dir.length() ? config_dir.utf8().get_data() : nullptr);
add_mono_shared_libs_dir_to_path();
#endif
+#ifdef ANDROID_ENABLED
+ mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
+#else
+ mono_config_parse(nullptr);
+#endif
+
#if defined(ANDROID_ENABLED)
- GDMonoAndroid::initialize();
+ gdmono::android::support::initialize();
+#elif defined(IPHONE_ENABLED)
+ gdmono::ios::support::initialize();
#endif
GDMonoAssembly::initialize();
@@ -330,13 +356,7 @@ void GDMono::initialize() {
gd_mono_profiler_init();
#endif
-#ifdef ANDROID_ENABLED
- mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
-#else
- mono_config_parse(NULL);
-#endif
-
- mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
+ mono_install_unhandled_exception_hook(&unhandled_exception_hook, nullptr);
#ifndef TOOLS_ENABLED
// Exported games that don't use C# must still work. They likely don't ship with mscorlib.
@@ -355,7 +375,7 @@ void GDMono::initialize() {
#endif
// NOTE: Internal calls must be registered after the Mono runtime initialization.
- // Otherwise registration fails with the error: 'assertion 'hash != NULL' failed'.
+ // Otherwise registration fails with the error: 'assertion 'hash != nullptr' failed'.
root_domain = gd_initialize_mono_runtime();
ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime.");
@@ -371,15 +391,19 @@ void GDMono::initialize() {
print_verbose("Mono: Runtime initialized");
#if defined(ANDROID_ENABLED)
- GDMonoAndroid::register_internal_calls();
+ gdmono::android::support::register_internal_calls();
#endif
// mscorlib assembly MUST be present at initialization
bool corlib_loaded = _load_corlib_assembly();
ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly.");
+#ifndef GD_MONO_SINGLE_APPDOMAIN
Error domain_load_err = _load_scripts_domain();
ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
+#else
+ scripts_domain = root_domain;
+#endif
_register_internal_calls();
@@ -491,11 +515,15 @@ void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
}
-GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
+GDMonoAssembly *GDMono::get_loaded_assembly(const String &p_name) {
+
+ if (p_name == "mscorlib")
+ return get_corlib_assembly();
MonoDomain *domain = mono_domain_get();
uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
- return assemblies[domain_id].getptr(p_name);
+ GDMonoAssembly **result = assemblies[domain_id].getptr(p_name);
+ return result ? *result : nullptr;
}
bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
@@ -517,7 +545,7 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo
print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
MonoImageOpenStatus status = MONO_IMAGE_OK;
- MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);
+ MonoAssembly *assembly = mono_assembly_load_full(p_aname, nullptr, &status, p_refonly);
if (!assembly)
return false;
@@ -528,7 +556,7 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo
GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
- ERR_FAIL_COND_V(stored_assembly == NULL, false);
+ ERR_FAIL_COND_V(stored_assembly == nullptr, false);
ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
*r_assembly = *stored_assembly;
@@ -549,14 +577,6 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo
if (!assembly)
return false;
-#ifdef DEBUG_ENABLED
- uint32_t domain_id = mono_domain_get_id(mono_domain_get());
- GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
-
- ERR_FAIL_COND_V(stored_assembly == NULL, false);
- ERR_FAIL_COND_V(*stored_assembly != assembly, false);
-#endif
-
*r_assembly = assembly;
print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
@@ -576,15 +596,15 @@ ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMo
if (nativecalls_klass) {
GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash");
if (api_hash_field)
- api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(NULL));
+ api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(nullptr));
GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version");
if (binds_ver_field)
- api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(NULL));
+ api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(nullptr));
GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version");
if (cs_glue_ver_field)
- api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(NULL));
+ api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(nullptr));
}
return api_assembly_version;
@@ -715,7 +735,7 @@ bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config
GDMono::LoadedApiAssembly temp_editor_api_assembly;
if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly,
- p_config, /* refonly: */ true, /* loaded_callback: */ NULL)) {
+ p_config, /* refonly: */ true, /* loaded_callback: */ nullptr)) {
return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync;
}
@@ -894,8 +914,8 @@ void GDMono::_load_api_assemblies() {
bool api_assemblies_loaded = _try_load_api_assemblies_preset();
+#if defined(TOOLS_ENABLED) && !defined(GD_MONO_SINGLE_APPDOMAIN)
if (!api_assemblies_loaded) {
-#ifdef TOOLS_ENABLED
// The API assemblies are out of sync or some other error happened. Fine, try one more time, but
// this time update them from the prebuilt assemblies directory before trying to load them again.
@@ -916,8 +936,8 @@ void GDMono::_load_api_assemblies() {
// 4. Try loading the updated assemblies
api_assemblies_loaded = _try_load_api_assemblies_preset();
-#endif
}
+#endif
if (!api_assemblies_loaded) {
// welp... too bad
@@ -982,8 +1002,8 @@ void GDMono::_install_trace_listener() {
GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener");
- MonoException *exc = NULL;
- install_func->invoke_raw(NULL, NULL, &exc);
+ MonoException *exc = nullptr;
+ install_func->invoke_raw(nullptr, nullptr, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
@@ -991,9 +1011,10 @@ void GDMono::_install_trace_listener() {
#endif
}
+#ifndef GD_MONO_SINGLE_APPDOMAIN
Error GDMono::_load_scripts_domain() {
- ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG);
+ ERR_FAIL_COND_V(scripts_domain != nullptr, ERR_BUG);
print_verbose("Mono: Loading scripts domain...");
@@ -1010,7 +1031,7 @@ Error GDMono::_unload_scripts_domain() {
ERR_FAIL_NULL_V(scripts_domain, ERR_BUG);
- print_verbose("Mono: Unloading scripts domain...");
+ print_verbose("Mono: Finalizing scripts domain...");
if (mono_domain_get() != root_domain)
mono_domain_set(root_domain, true);
@@ -1029,21 +1050,23 @@ Error GDMono::_unload_scripts_domain() {
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
- core_api_assembly.assembly = NULL;
+ core_api_assembly.assembly = nullptr;
#ifdef TOOLS_ENABLED
- editor_api_assembly.assembly = NULL;
+ editor_api_assembly.assembly = nullptr;
#endif
- project_assembly = NULL;
+ project_assembly = nullptr;
#ifdef TOOLS_ENABLED
- tools_assembly = NULL;
- tools_project_editor_assembly = NULL;
+ tools_assembly = nullptr;
+ tools_project_editor_assembly = nullptr;
#endif
MonoDomain *domain = scripts_domain;
- scripts_domain = NULL;
+ scripts_domain = nullptr;
+
+ print_verbose("Mono: Unloading scripts domain...");
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
mono_domain_try_unload(domain, (MonoObject **)&exc);
if (exc) {
@@ -1054,6 +1077,7 @@ Error GDMono::_unload_scripts_domain() {
return OK;
}
+#endif
#ifdef GD_MONO_HOT_RELOAD
Error GDMono::reload_scripts_domain() {
@@ -1092,9 +1116,10 @@ Error GDMono::reload_scripts_domain() {
}
#endif
+#ifndef GD_MONO_SINGLE_APPDOMAIN
Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
- CRASH_COND(p_domain == NULL);
+ CRASH_COND(p_domain == nullptr);
CRASH_COND(p_domain == GDMono::get_singleton()->get_scripts_domain()); // Should use _unload_scripts_domain() instead
String domain_name = mono_domain_get_friendly_name(p_domain);
@@ -1112,7 +1137,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
_domain_assemblies_cleanup(mono_domain_get_id(p_domain));
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
mono_domain_try_unload(p_domain, (MonoObject **)&exc);
if (exc) {
@@ -1123,6 +1148,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
return OK;
}
+#endif
GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
@@ -1134,7 +1160,7 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
- const String *k = NULL;
+ const String *k = nullptr;
while ((k = domain_assemblies.next(k))) {
GDMonoAssembly *assembly = domain_assemblies.get(*k);
if (assembly->get_image() == image) {
@@ -1145,30 +1171,34 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
}
}
- return NULL;
+ return nullptr;
}
GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) {
+ GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name);
+ if (klass)
+ return klass;
+
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
- const String *k = NULL;
+ const String *k = nullptr;
while ((k = domain_assemblies.next(k))) {
GDMonoAssembly *assembly = domain_assemblies.get(*k);
- GDMonoClass *klass = assembly->get_class(p_namespace, p_name);
+ klass = assembly->get_class(p_namespace, p_name);
if (klass)
return klass;
}
- return NULL;
+ return nullptr;
}
void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
- const String *k = NULL;
+ const String *k = nullptr;
while ((k = domain_assemblies.next(k))) {
memdelete(domain_assemblies.get(*k));
}
@@ -1202,14 +1232,14 @@ GDMono::GDMono() {
runtime_initialized = false;
finalizing_scripts_domain = false;
- root_domain = NULL;
- scripts_domain = NULL;
+ root_domain = nullptr;
+ scripts_domain = nullptr;
- corlib_assembly = NULL;
- project_assembly = NULL;
+ corlib_assembly = nullptr;
+ project_assembly = nullptr;
#ifdef TOOLS_ENABLED
- tools_assembly = NULL;
- tools_project_editor_assembly = NULL;
+ tools_assembly = nullptr;
+ tools_project_editor_assembly = nullptr;
#endif
api_core_hash = 0;
@@ -1223,18 +1253,50 @@ GDMono::GDMono() {
GDMono::~GDMono() {
if (is_runtime_initialized()) {
+#ifndef GD_MONO_SINGLE_APPDOMAIN
if (scripts_domain) {
Error err = _unload_scripts_domain();
if (err != OK) {
ERR_PRINT("Mono: Failed to unload scripts domain.");
}
}
+#else
+ CRASH_COND(scripts_domain != root_domain);
+
+ print_verbose("Mono: Finalizing scripts domain...");
+
+ if (mono_domain_get() != root_domain)
+ mono_domain_set(root_domain, true);
+
+ finalizing_scripts_domain = true;
+
+ if (!mono_domain_finalize(root_domain, 2000)) {
+ ERR_PRINT("Mono: Domain finalization timeout.");
+ }
+
+ finalizing_scripts_domain = false;
- const uint32_t *k = NULL;
+ mono_gc_collect(mono_gc_max_generation());
+
+ GDMonoCache::clear_godot_api_cache();
+
+ _domain_assemblies_cleanup(mono_domain_get_id(root_domain));
+
+ core_api_assembly.assembly = nullptr;
+
+ project_assembly = nullptr;
+
+ root_domain = nullptr;
+ scripts_domain = nullptr;
+
+ // Leave the rest to 'mono_jit_cleanup'
+#endif
+
+ const uint32_t *k = nullptr;
while ((k = assemblies.next(k))) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
- const String *kk = NULL;
+ const String *kk = nullptr;
while ((kk = domain_assemblies.next(kk))) {
memdelete(domain_assemblies.get(*kk));
}
@@ -1245,22 +1307,22 @@ GDMono::~GDMono() {
mono_jit_cleanup(root_domain);
-#if defined(ANDROID_ENABLED)
- GDMonoAndroid::cleanup();
-#endif
-
print_verbose("Mono: Finalized");
runtime_initialized = false;
}
+#if defined(ANDROID_ENABLED)
+ gdmono::android::support::cleanup();
+#endif
+
if (gdmono_log)
memdelete(gdmono_log);
- singleton = NULL;
+ singleton = nullptr;
}
-_GodotSharp *_GodotSharp::singleton = NULL;
+_GodotSharp *_GodotSharp::singleton = nullptr;
void _GodotSharp::attach_thread() {
@@ -1288,7 +1350,7 @@ int32_t _GodotSharp::get_scripts_domain_id() {
bool _GodotSharp::is_scripts_domain_loaded() {
- return GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != NULL;
+ return GDMono::get_singleton()->is_runtime_initialized() && GDMono::get_singleton()->get_scripts_domain() != nullptr;
}
bool _GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
@@ -1353,5 +1415,5 @@ _GodotSharp::_GodotSharp() {
_GodotSharp::~_GodotSharp() {
- singleton = NULL;
+ singleton = nullptr;
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 306fa15f12..4898833e8e 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -91,7 +91,7 @@ public:
bool out_of_sync;
LoadedApiAssembly() :
- assembly(NULL),
+ assembly(nullptr),
out_of_sync(false) {
}
};
@@ -105,7 +105,7 @@ private:
MonoDomain *root_domain;
MonoDomain *scripts_domain;
- HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
+ HashMap<uint32_t, HashMap<String, GDMonoAssembly *>> assemblies;
GDMonoAssembly *corlib_assembly;
GDMonoAssembly *project_assembly;
@@ -144,8 +144,10 @@ private:
void _register_internal_calls();
+#ifndef GD_MONO_SINGLE_APPDOMAIN
Error _load_scripts_domain();
Error _unload_scripts_domain();
+#endif
void _domain_assemblies_cleanup(uint32_t p_domain_id);
@@ -198,18 +200,18 @@ public:
#ifdef TOOLS_ENABLED
bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config);
- String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = NULL, const bool *p_editor_api_out_of_sync = NULL);
+ String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = nullptr, const bool *p_editor_api_out_of_sync = nullptr);
#endif
static GDMono *get_singleton() { return singleton; }
- GD_NORETURN static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
+ [[noreturn]] static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
UnhandledExceptionPolicy get_unhandled_exception_policy() const { return unhandled_exception_policy; }
// Do not use these, unless you know what you're doing
void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
- GDMonoAssembly **get_loaded_assembly(const String &p_name);
+ GDMonoAssembly *get_loaded_assembly(const String &p_name);
_FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; }
@@ -263,7 +265,7 @@ public:
this->prev_domain = prev_domain;
mono_domain_set(p_domain, false);
} else {
- this->prev_domain = NULL;
+ this->prev_domain = nullptr;
}
}
diff --git a/modules/mono/mono_gd/gd_mono_android.cpp b/modules/mono/mono_gd/gd_mono_android.cpp
deleted file mode 100644
index 761368878f..0000000000
--- a/modules/mono/mono_gd/gd_mono_android.cpp
+++ /dev/null
@@ -1,686 +0,0 @@
-/*************************************************************************/
-/* gd_mono_android.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "gd_mono_android.h"
-
-#if defined(ANDROID_ENABLED)
-
-#include <dlfcn.h> // dlopen, dlsym
-#include <mono/utils/mono-dl-fallback.h>
-#include <sys/system_properties.h>
-#include <cstddef>
-
-#if __ANDROID_API__ < 24
-#include "thirdparty/misc/ifaddrs-android.h"
-#else
-#include <ifaddrs.h>
-#endif
-
-#include "core/os/os.h"
-#include "core/ustring.h"
-#include "platform/android/java_godot_wrapper.h"
-#include "platform/android/os_android.h"
-#include "platform/android/thread_jandroid.h"
-
-#include "../utils/path_utils.h"
-#include "../utils/string_utils.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_marshal.h"
-
-// Warning: JNI boilerplate ahead... continue at your own risk
-
-namespace GDMonoAndroid {
-
-template <typename T>
-struct ScopedLocalRef {
- JNIEnv *env;
- T local_ref;
-
- _FORCE_INLINE_ T get() const { return local_ref; }
- _FORCE_INLINE_ operator T() const { return local_ref; }
- _FORCE_INLINE_ operator jvalue() const { return (jvalue)local_ref; }
-
- _FORCE_INLINE_ operator bool() const { return local_ref != NULL; }
-
- _FORCE_INLINE_ bool operator==(std::nullptr_t) const {
- return local_ref == nullptr;
- }
-
- _FORCE_INLINE_ bool operator!=(std::nullptr_t) const {
- return local_ref != nullptr;
- }
-
- ScopedLocalRef(const ScopedLocalRef &) = delete;
- ScopedLocalRef &operator=(const ScopedLocalRef &) = delete;
-
- ScopedLocalRef(JNIEnv *p_env, T p_local_ref) :
- env(p_env),
- local_ref(p_local_ref) {
- }
-
- ~ScopedLocalRef() {
- if (local_ref) {
- env->DeleteLocalRef(local_ref);
- }
- }
-};
-
-bool jni_exception_check(JNIEnv *p_env) {
- if (p_env->ExceptionCheck()) {
- // Print the exception to logcat
- p_env->ExceptionDescribe();
-
- p_env->ExceptionClear();
- return true;
- }
-
- return false;
-}
-
-String app_native_lib_dir_cache;
-
-String determine_app_native_lib_dir() {
- JNIEnv *env = ThreadAndroid::get_env();
-
- ScopedLocalRef<jclass> activityThreadClass(env, env->FindClass("android/app/ActivityThread"));
- jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;");
- ScopedLocalRef<jobject> activityThread(env, env->CallStaticObjectMethod(activityThreadClass, currentActivityThread));
- jmethodID getApplication = env->GetMethodID(activityThreadClass, "getApplication", "()Landroid/app/Application;");
- ScopedLocalRef<jobject> ctx(env, env->CallObjectMethod(activityThread, getApplication));
-
- jmethodID getApplicationInfo = env->GetMethodID(env->GetObjectClass(ctx), "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
- ScopedLocalRef<jobject> applicationInfo(env, env->CallObjectMethod(ctx, getApplicationInfo));
- jfieldID nativeLibraryDirField = env->GetFieldID(env->GetObjectClass(applicationInfo), "nativeLibraryDir", "Ljava/lang/String;");
- ScopedLocalRef<jstring> nativeLibraryDir(env, (jstring)env->GetObjectField(applicationInfo, nativeLibraryDirField));
-
- String result;
-
- const char *const nativeLibraryDirUtf8 = env->GetStringUTFChars(nativeLibraryDir, NULL);
- if (nativeLibraryDirUtf8) {
- result.parse_utf8(nativeLibraryDirUtf8);
- env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDirUtf8);
- }
-
- return result;
-}
-
-String get_app_native_lib_dir() {
- if (app_native_lib_dir_cache.empty())
- app_native_lib_dir_cache = determine_app_native_lib_dir();
- return app_native_lib_dir_cache;
-}
-
-int gd_mono_convert_dl_flags(int flags) {
- // from mono's runtime-bootstrap.c
-
- int lflags = flags & MONO_DL_LOCAL ? 0 : RTLD_GLOBAL;
-
- if (flags & MONO_DL_LAZY)
- lflags |= RTLD_LAZY;
- else
- lflags |= RTLD_NOW;
-
- return lflags;
-}
-
-#ifndef GD_MONO_ANDROID_SO_NAME
-#define GD_MONO_ANDROID_SO_NAME "libmonosgen-2.0.so"
-#endif
-
-const char *mono_so_name = GD_MONO_ANDROID_SO_NAME;
-const char *godot_so_name = "libgodot_android.so";
-
-void *mono_dl_handle = NULL;
-void *godot_dl_handle = NULL;
-
-void *try_dlopen(const String &p_so_path, int p_flags) {
- if (!FileAccess::exists(p_so_path)) {
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data());
- return NULL;
- }
-
- int lflags = gd_mono_convert_dl_flags(p_flags);
-
- void *handle = dlopen(p_so_path.utf8().get_data(), lflags);
-
- if (!handle) {
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror());
- return NULL;
- }
-
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data());
-
- return handle;
-}
-
-void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void *p_user_data) {
- if (p_name == NULL) {
- // __Internal
-
- if (!mono_dl_handle) {
- String app_native_lib_dir = get_app_native_lib_dir();
- String so_path = path::join(app_native_lib_dir, mono_so_name);
-
- mono_dl_handle = try_dlopen(so_path, p_flags);
- }
-
- return mono_dl_handle;
- }
-
- String name = String::utf8(p_name);
-
- if (name.ends_with(".dll.so") || name.ends_with(".exe.so")) {
- String app_native_lib_dir = get_app_native_lib_dir();
-
- String orig_so_name = name.get_file();
- String so_name = "lib-aot-" + orig_so_name;
- String so_path = path::join(app_native_lib_dir, so_name);
-
- return try_dlopen(so_path, p_flags);
- }
-
- return NULL;
-}
-
-void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, void *p_user_data) {
- void *sym_addr = dlsym(p_handle, p_name);
-
- if (sym_addr)
- return sym_addr;
-
- if (p_handle == mono_dl_handle && godot_dl_handle) {
- // Looking up for '__Internal' P/Invoke. We want to search in both the Mono and Godot shared libraries.
- // This is needed to resolve the monodroid P/Invoke functions that are defined at the bottom of the file.
- sym_addr = dlsym(godot_dl_handle, p_name);
-
- if (sym_addr)
- return sym_addr;
- }
-
- if (r_err)
- *r_err = str_format_new("%s\n", dlerror());
-
- return NULL;
-}
-
-void *gd_mono_android_dlclose(void *p_handle, void *p_user_data) {
- dlclose(p_handle);
-
- // Not sure if this ever happens. Does Mono close the handle for the main module?
- if (p_handle == mono_dl_handle)
- mono_dl_handle = NULL;
-
- return NULL;
-}
-
-int32_t build_version_sdk_int = 0;
-
-int32_t get_build_version_sdk_int() {
- // The JNI code is the equivalent of:
- //
- // android.os.Build.VERSION.SDK_INT
-
- if (build_version_sdk_int == 0) {
- JNIEnv *env = ThreadAndroid::get_env();
-
- jclass versionClass = env->FindClass("android/os/Build$VERSION");
- ERR_FAIL_NULL_V(versionClass, 0);
-
- jfieldID sdkIntField = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
- ERR_FAIL_NULL_V(sdkIntField, 0);
-
- build_version_sdk_int = (int32_t)env->GetStaticIntField(versionClass, sdkIntField);
- }
-
- return build_version_sdk_int;
-}
-
-jobject certStore = NULL; // KeyStore
-
-MonoBoolean _gd_mono_init_cert_store() {
- // The JNI code is the equivalent of:
- //
- // try {
- // certStoreLocal = KeyStore.getInstance("AndroidCAStore");
- // certStoreLocal.load(null);
- // certStore = certStoreLocal;
- // return true;
- // } catch (Exception e) {
- // return false;
- // }
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore"));
-
- jmethodID getInstance = env->GetStaticMethodID(keyStoreClass, "getInstance", "(Ljava/lang/String;)Ljava/security/KeyStore;");
- jmethodID load = env->GetMethodID(keyStoreClass, "load", "(Ljava/security/KeyStore$LoadStoreParameter;)V");
-
- ScopedLocalRef<jstring> androidCAStoreString(env, env->NewStringUTF("AndroidCAStore"));
-
- ScopedLocalRef<jobject> certStoreLocal(env, env->CallStaticObjectMethod(keyStoreClass, getInstance, androidCAStoreString.get()));
-
- if (jni_exception_check(env))
- return 0;
-
- env->CallVoidMethod(certStoreLocal, load, NULL);
-
- if (jni_exception_check(env))
- return 0;
-
- certStore = env->NewGlobalRef(certStoreLocal);
-
- return 1;
-}
-
-MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
- // The JNI code is the equivalent of:
- //
- // Certificate certificate = certStore.getCertificate(alias);
- // if (certificate == null)
- // return null;
- // return certificate.getEncoded();
-
- MonoError mono_error;
- char *alias_utf8 = mono_string_to_utf8_checked(p_alias, &mono_error);
-
- if (!mono_error_ok(&mono_error)) {
- ERR_PRINT(String() + "Failed to convert MonoString* to UTF-8: '" + mono_error_get_message(&mono_error) + "'.");
- mono_error_cleanup(&mono_error);
- return NULL;
- }
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- ScopedLocalRef<jstring> js_alias(env, env->NewStringUTF(alias_utf8));
- mono_free(alias_utf8);
-
- ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore"));
- ERR_FAIL_NULL_V(keyStoreClass, NULL);
- ScopedLocalRef<jclass> certificateClass(env, env->FindClass("java/security/cert/Certificate"));
- ERR_FAIL_NULL_V(certificateClass, NULL);
-
- jmethodID getCertificate = env->GetMethodID(keyStoreClass, "getCertificate", "(Ljava/lang/String;)Ljava/security/cert/Certificate;");
- ERR_FAIL_NULL_V(getCertificate, NULL);
-
- jmethodID getEncoded = env->GetMethodID(certificateClass, "getEncoded", "()[B");
- ERR_FAIL_NULL_V(getEncoded, NULL);
-
- ScopedLocalRef<jobject> certificate(env, env->CallObjectMethod(certStore, getCertificate, js_alias.get()));
-
- if (!certificate)
- return NULL;
-
- ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded));
- jsize encodedLength = env->GetArrayLength(encoded);
-
- MonoArray *encoded_ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), encodedLength);
- uint8_t *dest = (uint8_t *)mono_array_addr(encoded_ret, uint8_t, 0);
-
- env->GetByteArrayRegion(encoded, 0, encodedLength, reinterpret_cast<jbyte *>(dest));
-
- return encoded_ret;
-}
-
-void initialize() {
- // We need to set this environment variable to make the monodroid BCL use btls instead of legacy as the default provider
- OS::get_singleton()->set_environment("XA_TLS_PROVIDER", "btls");
-
- mono_dl_fallback_register(gd_mono_android_dlopen, gd_mono_android_dlsym, gd_mono_android_dlclose, NULL);
-
- String app_native_lib_dir = get_app_native_lib_dir();
- String so_path = path::join(app_native_lib_dir, godot_so_name);
-
- godot_dl_handle = try_dlopen(so_path, gd_mono_convert_dl_flags(MONO_DL_LAZY));
-}
-
-void register_internal_calls() {
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store);
- mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup);
-}
-
-void cleanup() {
- // This is called after shutting down the Mono runtime
-
- if (mono_dl_handle)
- gd_mono_android_dlclose(mono_dl_handle, NULL);
-
- if (godot_dl_handle)
- gd_mono_android_dlclose(godot_dl_handle, NULL);
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- if (certStore) {
- env->DeleteGlobalRef(certStore);
- certStore = NULL;
- }
-}
-
-} // namespace GDMonoAndroid
-
-using namespace GDMonoAndroid;
-
-// The following are P/Invoke functions required by the monodroid profile of the BCL.
-// These are P/Invoke functions and not internal calls, hence why they use
-// 'mono_bool' and 'const char*' instead of 'MonoBoolean' and 'MonoString*'.
-
-#define GD_PINVOKE_EXPORT extern "C" __attribute__((visibility("default")))
-
-GD_PINVOKE_EXPORT int32_t _monodroid_get_android_api_level() {
- return get_build_version_sdk_int();
-}
-
-GD_PINVOKE_EXPORT void monodroid_free(void *ptr) {
- free(ptr);
-}
-
-GD_PINVOKE_EXPORT int32_t monodroid_get_system_property(const char *p_name, char **r_value) {
- char prop_value_str[PROP_VALUE_MAX + 1] = { 0 };
-
- int len = __system_property_get(p_name, prop_value_str);
-
- if (r_value) {
- if (len >= 0) {
- *r_value = (char *)malloc(len + 1);
- if (!*r_value)
- return -1;
- memcpy(*r_value, prop_value_str, len);
- (*r_value)[len] = '\0';
- } else {
- *r_value = NULL;
- }
- }
-
- return len;
-}
-
-GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char *p_ifname, mono_bool *r_is_up) {
- // The JNI code is the equivalent of:
- //
- // NetworkInterface.getByName(p_ifname).isUp()
-
- if (!r_is_up || !p_ifname || strlen(p_ifname) == 0)
- return 0;
-
- *r_is_up = 0;
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface");
- ERR_FAIL_NULL_V(networkInterfaceClass, 0);
-
- jmethodID getByName = env->GetStaticMethodID(networkInterfaceClass, "getByName", "(Ljava/lang/String;)Ljava/net/NetworkInterface;");
- ERR_FAIL_NULL_V(getByName, 0);
-
- jmethodID isUp = env->GetMethodID(networkInterfaceClass, "isUp", "()Z");
- ERR_FAIL_NULL_V(isUp, 0);
-
- ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname));
- ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get()));
-
- if (!networkInterface)
- return 0;
-
- *r_is_up = (mono_bool)env->CallBooleanMethod(networkInterface, isUp);
-
- return 1;
-}
-
-GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast(const char *p_ifname, mono_bool *r_supports_multicast) {
- // The JNI code is the equivalent of:
- //
- // NetworkInterface.getByName(p_ifname).supportsMulticast()
-
- if (!r_supports_multicast || !p_ifname || strlen(p_ifname) == 0)
- return 0;
-
- *r_supports_multicast = 0;
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface");
- ERR_FAIL_NULL_V(networkInterfaceClass, 0);
-
- jmethodID getByName = env->GetStaticMethodID(networkInterfaceClass, "getByName", "(Ljava/lang/String;)Ljava/net/NetworkInterface;");
- ERR_FAIL_NULL_V(getByName, 0);
-
- jmethodID supportsMulticast = env->GetMethodID(networkInterfaceClass, "supportsMulticast", "()Z");
- ERR_FAIL_NULL_V(supportsMulticast, 0);
-
- ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname));
- ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get()));
-
- if (!networkInterface)
- return 0;
-
- *r_supports_multicast = (mono_bool)env->CallBooleanMethod(networkInterface, supportsMulticast);
-
- return 1;
-}
-
-static const int dns_servers_len = 8;
-
-static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dns_servers_count) {
- // The JNI code is the equivalent of:
- //
- // ConnectivityManager connectivityManager = (ConnectivityManager)getApplicationContext()
- // .getSystemService(Context.CONNECTIVITY_SERVICE);
- // Network activeNerwork = connectivityManager.getActiveNetwork();
- // LinkProperties linkProperties = connectivityManager.getLinkProperties(activeNerwork);
- // List<String> dnsServers = linkProperties.getDnsServers().stream()
- // .map(inetAddress -> inetAddress.getHostAddress()).collect(Collectors.toList());
-
-#ifdef DEBUG_ENABLED
- CRASH_COND(get_build_version_sdk_int() < 23);
-#endif
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- GodotJavaWrapper *godot_java = ((OS_Android *)OS::get_singleton())->get_godot_java();
- jobject activity = godot_java->get_activity();
-
- ScopedLocalRef<jclass> activityClass(env, env->GetObjectClass(activity));
- ERR_FAIL_NULL(activityClass);
-
- jmethodID getApplicationContext = env->GetMethodID(activityClass, "getApplicationContext", "()Landroid/content/Context;");
-
- ScopedLocalRef<jobject> applicationContext(env, env->CallObjectMethod(activity, getApplicationContext));
-
- ScopedLocalRef<jclass> contextClass(env, env->FindClass("android/content/Context"));
- ERR_FAIL_NULL(contextClass);
-
- jfieldID connectivityServiceField = env->GetStaticFieldID(contextClass, "CONNECTIVITY_SERVICE", "Ljava/lang/String;");
- ScopedLocalRef<jstring> connectivityServiceString(env, (jstring)env->GetStaticObjectField(contextClass, connectivityServiceField));
-
- jmethodID getSystemService = env->GetMethodID(contextClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
-
- ScopedLocalRef<jobject> connectivityManager(env, env->CallObjectMethod(applicationContext, getSystemService, connectivityServiceString.get()));
-
- if (!connectivityManager)
- return;
-
- ScopedLocalRef<jclass> connectivityManagerClass(env, env->FindClass("android/net/ConnectivityManager"));
- ERR_FAIL_NULL(connectivityManagerClass);
-
- jmethodID getActiveNetwork = env->GetMethodID(connectivityManagerClass, "getActiveNetwork", "()Landroid/net/Network;");
- ERR_FAIL_NULL(getActiveNetwork);
-
- ScopedLocalRef<jobject> activeNetwork(env, env->CallObjectMethod(connectivityManager, getActiveNetwork));
-
- if (!activeNetwork)
- return;
-
- jmethodID getLinkProperties = env->GetMethodID(connectivityManagerClass,
- "getLinkProperties", "(Landroid/net/Network;)Landroid/net/LinkProperties;");
- ERR_FAIL_NULL(getLinkProperties);
-
- ScopedLocalRef<jobject> linkProperties(env, env->CallObjectMethod(connectivityManager, getLinkProperties, activeNetwork.get()));
-
- if (!linkProperties)
- return;
-
- ScopedLocalRef<jclass> linkPropertiesClass(env, env->FindClass("android/net/LinkProperties"));
- ERR_FAIL_NULL(linkPropertiesClass);
-
- jmethodID getDnsServers = env->GetMethodID(linkPropertiesClass, "getDnsServers", "()Ljava/util/List;");
- ERR_FAIL_NULL(getDnsServers);
-
- ScopedLocalRef<jobject> dnsServers(env, env->CallObjectMethod(linkProperties, getDnsServers));
-
- if (!dnsServers)
- return;
-
- ScopedLocalRef<jclass> listClass(env, env->FindClass("java/util/List"));
- ERR_FAIL_NULL(listClass);
-
- jmethodID listSize = env->GetMethodID(listClass, "size", "()I");
- ERR_FAIL_NULL(listSize);
-
- int dnsServersCount = env->CallIntMethod(dnsServers, listSize);
-
- if (dnsServersCount > dns_servers_len)
- dnsServersCount = dns_servers_len;
-
- if (dnsServersCount <= 0)
- return;
-
- jmethodID listGet = env->GetMethodID(listClass, "get", "(I)Ljava/lang/Object;");
- ERR_FAIL_NULL(listGet);
-
- ScopedLocalRef<jclass> inetAddressClass(env, env->FindClass("java/net/InetAddress"));
- ERR_FAIL_NULL(inetAddressClass);
-
- jmethodID getHostAddress = env->GetMethodID(inetAddressClass, "getHostAddress", "()Ljava/lang/String;");
- ERR_FAIL_NULL(getHostAddress);
-
- for (int i = 0; i < dnsServersCount; i++) {
- ScopedLocalRef<jobject> dnsServer(env, env->CallObjectMethod(dnsServers, listGet, (jint)i));
- if (!dnsServer)
- continue;
-
- ScopedLocalRef<jstring> hostAddress(env, (jstring)env->CallObjectMethod(dnsServer, getHostAddress));
- const char *host_address = env->GetStringUTFChars(hostAddress, 0);
-
- r_dns_servers[i] = strdup(host_address); // freed by the BCL
- (*dns_servers_count)++;
-
- env->ReleaseStringUTFChars(hostAddress, host_address);
- }
-
- // jesus...
-}
-
-GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array) {
- if (!r_dns_servers_array)
- return -1;
-
- *r_dns_servers_array = NULL;
-
- char *dns_servers[dns_servers_len];
- int dns_servers_count = 0;
-
- if (_monodroid_get_android_api_level() < 26) {
- // The 'net.dns*' system properties are no longer available in Android 8.0 (API level 26) and greater:
- // https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri
-
- char prop_name[] = "net.dns*";
-
- for (int i = 0; i < dns_servers_len; i++) {
- prop_name[7] = (char)(i + 0x31);
- char *prop_value;
- int32_t len = monodroid_get_system_property(prop_name, &prop_value);
-
- if (len > 0) {
- dns_servers[dns_servers_count] = strndup(prop_value, (size_t)len); // freed by the BCL
- dns_servers_count++;
- free(prop_value);
- }
- }
- } else {
- // Alternative for Oreo and greater
- interop_get_active_network_dns_servers(dns_servers, &dns_servers_count);
- }
-
- 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
- memcpy(*r_dns_servers_array, dns_servers, ret_size);
- }
-
- return dns_servers_count;
-}
-
-GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() {
- // The JNI code is the equivalent of:
- //
- // TimeZone.getDefault().getID()
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- ScopedLocalRef<jclass> timeZoneClass(env, env->FindClass("java/util/TimeZone"));
- ERR_FAIL_NULL_V(timeZoneClass, NULL);
-
- jmethodID getDefault = env->GetStaticMethodID(timeZoneClass, "getDefault", "()Ljava/util/TimeZone;");
- ERR_FAIL_NULL_V(getDefault, NULL);
-
- jmethodID getID = env->GetMethodID(timeZoneClass, "getID", "()Ljava/lang/String;");
- ERR_FAIL_NULL_V(getID, NULL);
-
- ScopedLocalRef<jobject> defaultTimeZone(env, env->CallStaticObjectMethod(timeZoneClass, getDefault));
-
- if (!defaultTimeZone)
- return NULL;
-
- ScopedLocalRef<jstring> defaultTimeZoneID(env, (jstring)env->CallObjectMethod(defaultTimeZone, getID));
-
- if (!defaultTimeZoneID)
- return NULL;
-
- const char *default_time_zone_id = env->GetStringUTFChars(defaultTimeZoneID, 0);
-
- char *result = strdup(default_time_zone_id); // freed by the BCL
-
- env->ReleaseStringUTFChars(defaultTimeZoneID, default_time_zone_id);
-
- return result;
-}
-
-GD_PINVOKE_EXPORT int32_t _monodroid_getifaddrs(struct ifaddrs **p_ifap) {
- return getifaddrs(p_ifap);
-}
-
-GD_PINVOKE_EXPORT void _monodroid_freeifaddrs(struct ifaddrs *p_ifap) {
- freeifaddrs(p_ifap);
-}
-
-#endif
diff --git a/modules/mono/mono_gd/gd_mono_android.h b/modules/mono/mono_gd/gd_mono_android.h
deleted file mode 100644
index 0e04847924..0000000000
--- a/modules/mono/mono_gd/gd_mono_android.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* gd_mono_android.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 GD_MONO_ANDROID_H
-#define GD_MONO_ANDROID_H
-
-#if defined(ANDROID_ENABLED)
-
-#include "core/ustring.h"
-
-namespace GDMonoAndroid {
-
-String get_app_native_lib_dir();
-
-void initialize();
-
-void register_internal_calls();
-
-void cleanup();
-
-} // namespace GDMonoAndroid
-
-#endif // ANDROID_ENABLED
-
-#endif // GD_MONO_ANDROID_H
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 6cf5377e2c..8439769d84 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -42,9 +42,6 @@
#include "gd_mono_cache.h"
#include "gd_mono_class.h"
-bool GDMonoAssembly::no_search = false;
-bool GDMonoAssembly::in_preload = false;
-
Vector<String> GDMonoAssembly::search_dirs;
void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) {
@@ -78,7 +75,7 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
if (p_custom_config.empty()) {
r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
} else {
- String api_config = p_custom_config == "Release" ? "Release" : "Debug";
+ String api_config = p_custom_config == "ExportRelease" ? "Release" : "Debug";
r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir().plus_file(api_config));
}
@@ -94,19 +91,30 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
#endif
}
+// This is how these assembly loading hooks work:
+//
+// - The 'search' hook checks if the assembly has already been loaded, to avoid loading again.
+// - The 'preload' hook does the actual loading and is only called if the
+// 'search' hook didn't find the assembly in the list of loaded assemblies.
+// - The 'load' hook is called after the assembly has been loaded. Its job is to add the
+// assembly to the list of loaded assemblies so that the 'search' hook can look it up.
+
void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, void *user_data) {
- if (no_search)
- return;
-
- // If our search and preload hooks fail to load the assembly themselves, the mono runtime still might.
- // Just do Assembly.LoadFrom("/Full/Path/On/Disk.dll");
- // In this case, we wouldn't have the assembly known in GDMono, which causes crashes
- // if any class inside the assembly is looked up by Godot.
- // And causing a lookup like that is as easy as throwing an exception defined in it...
- // No, we can't make the assembly load hooks smart enough because they get passed a MonoAssemblyName* only,
- // not the disk path passed to say Assembly.LoadFrom().
- _wrap_mono_assembly(assembly);
+ String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly)));
+
+ MonoImage *image = mono_assembly_get_image(assembly);
+
+ GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, image, assembly));
+
+#ifdef GD_MONO_HOT_RELOAD
+ const char *path = mono_image_get_filename(image);
+ if (FileAccess::exists(path))
+ gdassembly->modified_time = FileAccess::get_modified_time(path);
+#endif
+
+ MonoDomain *domain = mono_domain_get();
+ GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly);
}
MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) {
@@ -132,71 +140,24 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
String name = String::utf8(mono_assembly_name_get_name(aname));
bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
- if (no_search)
- return NULL;
-
- GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
+ GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
if (loaded_asm)
- return (*loaded_asm)->get_assembly();
-
- no_search = true; // Avoid the recursion madness
-
- GDMonoAssembly *res = _load_assembly_search(name, search_dirs, refonly);
-
- no_search = false;
+ return loaded_asm->get_assembly();
- return res ? res->get_assembly() : NULL;
+ return nullptr;
}
-static _THREAD_LOCAL_(MonoImage *) image_corlib_loading = NULL;
-
MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, void *user_data, bool refonly) {
(void)user_data; // UNUSED
- {
- // If we find the assembly here, we load it with 'mono_assembly_load_from_full',
- // which in turn invokes load hooks before returning the MonoAssembly to us.
- // One of the load hooks is 'load_aot_module'. This hook can end up calling preload hooks
- // again for the same assembly in certain in certain circumstances (the 'do_load_image' part).
- // If this is the case and we return NULL due to the no_search condition below,
- // it will result in an internal crash later on. Therefore we need to return the assembly we didn't
- // get yet from 'mono_assembly_load_from_full'. Luckily we have the image, which already got it.
- // This must be done here. If done in search hooks, it would cause 'mono_assembly_load_from_full'
- // to think another MonoAssembly for this assembly was already loaded, making it delete its own,
- // when in fact both pointers were the same... This hooks thing is confusing.
- if (image_corlib_loading) {
- return mono_image_get_assembly(image_corlib_loading);
- }
- }
-
- if (no_search)
- return NULL;
-
- no_search = true;
- in_preload = true;
-
String name = String::utf8(mono_assembly_name_get_name(aname));
- bool has_extension = name.ends_with(".dll");
-
- GDMonoAssembly *res = NULL;
- if (has_extension ? name == "mscorlib.dll" : name == "mscorlib") {
- GDMonoAssembly **stored_assembly = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
- if (stored_assembly)
- return (*stored_assembly)->get_assembly();
-
- res = _load_assembly_search("mscorlib.dll", search_dirs, refonly);
- }
-
- no_search = false;
- in_preload = false;
-
- return res ? res->get_assembly() : NULL;
+ return _load_assembly_search(name, search_dirs, refonly);
}
-GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) {
+MonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) {
- GDMonoAssembly *res = NULL;
+ MonoAssembly *res = nullptr;
String path;
bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
@@ -207,28 +168,28 @@ GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, cons
if (has_extension) {
path = search_dir.plus_file(p_name);
if (FileAccess::exists(path)) {
- res = _load_assembly_from(p_name.get_basename(), path, p_refonly);
- if (res != NULL)
+ res = _real_load_assembly_from(path, p_refonly);
+ if (res != nullptr)
return res;
}
} else {
path = search_dir.plus_file(p_name + ".dll");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(p_name, path, p_refonly);
- if (res != NULL)
+ res = _real_load_assembly_from(path, p_refonly);
+ if (res != nullptr)
return res;
}
path = search_dir.plus_file(p_name + ".exe");
if (FileAccess::exists(path)) {
- res = _load_assembly_from(p_name, path, p_refonly);
- if (res != NULL)
+ res = _real_load_assembly_from(path, p_refonly);
+ if (res != nullptr)
return res;
}
}
}
- return NULL;
+ return nullptr;
}
String GDMonoAssembly::find_assembly(const String &p_name) {
@@ -258,91 +219,50 @@ String GDMonoAssembly::find_assembly(const String &p_name) {
return String();
}
-GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {
-
- GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
-
- Error err = assembly->load(p_refonly);
-
- if (err != OK) {
- memdelete(assembly);
- ERR_FAIL_V(NULL);
- }
-
- MonoDomain *domain = mono_domain_get();
- GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly);
-
- return assembly;
-}
-
-void GDMonoAssembly::_wrap_mono_assembly(MonoAssembly *assembly) {
- String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly)));
-
- MonoImage *image = mono_assembly_get_image(assembly);
-
- GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, mono_image_get_filename(image)));
- Error err = gdassembly->wrapper_for_image(image);
-
- if (err != OK) {
- memdelete(gdassembly);
- ERR_FAIL();
- }
-
- MonoDomain *domain = mono_domain_get();
- GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly);
-}
-
void GDMonoAssembly::initialize() {
fill_search_dirs(search_dirs);
- mono_install_assembly_search_hook(&assembly_search_hook, NULL);
- mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL);
- mono_install_assembly_preload_hook(&assembly_preload_hook, NULL);
- mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, NULL);
- mono_install_assembly_load_hook(&assembly_load_hook, NULL);
+ mono_install_assembly_search_hook(&assembly_search_hook, nullptr);
+ mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, nullptr);
+ mono_install_assembly_preload_hook(&assembly_preload_hook, nullptr);
+ mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, nullptr);
+ mono_install_assembly_load_hook(&assembly_load_hook, nullptr);
}
-Error GDMonoAssembly::load(bool p_refonly) {
-
- ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
-
- refonly = p_refonly;
+MonoAssembly *GDMonoAssembly::_real_load_assembly_from(const String &p_path, bool p_refonly) {
- uint64_t last_modified_time = FileAccess::get_modified_time(path);
-
- Vector<uint8_t> data = FileAccess::get_file_as_array(path);
- ERR_FAIL_COND_V(data.empty(), ERR_FILE_CANT_READ);
+ Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
+ ERR_FAIL_COND_V_MSG(data.empty(), nullptr, "Could read the assembly in the specified location");
String image_filename;
#ifdef ANDROID_ENABLED
- if (path.begins_with("res://")) {
- image_filename = path.substr(6, path.length());
+ if (p_path.begins_with("res://")) {
+ image_filename = p_path.substr(6, p_path.length());
} else {
- image_filename = ProjectSettings::get_singleton()->globalize_path(path);
+ image_filename = ProjectSettings::get_singleton()->globalize_path(p_path);
}
#else
// FIXME: globalize_path does not work on exported games
- image_filename = ProjectSettings::get_singleton()->globalize_path(path);
+ image_filename = ProjectSettings::get_singleton()->globalize_path(p_path);
#endif
MonoImageOpenStatus status = MONO_IMAGE_OK;
- image = mono_image_open_from_data_with_name(
+ MonoImage *image = mono_image_open_from_data_with_name(
(char *)&data[0], data.size(),
- true, &status, refonly,
- image_filename.utf8().get_data());
+ true, &status, p_refonly,
+ image_filename.utf8());
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK, ERR_FILE_CANT_OPEN);
- ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !image, nullptr, "Failed to open assembly image from the loaded data");
#ifdef DEBUG_ENABLED
Vector<uint8_t> pdb_data;
- String pdb_path(path + ".pdb");
+ String pdb_path(p_path + ".pdb");
if (!FileAccess::exists(pdb_path)) {
- pdb_path = path.get_basename() + ".pdb"; // without .dll
+ pdb_path = p_path.get_basename() + ".pdb"; // without .dll
if (!FileAccess::exists(pdb_path))
goto no_pdb;
@@ -357,44 +277,21 @@ no_pdb:
#endif
- bool is_corlib_preload = in_preload && name == "mscorlib";
-
- if (is_corlib_preload)
- image_corlib_loading = image;
+ status = MONO_IMAGE_OK;
- assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly);
+ MonoAssembly *assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, p_refonly);
- if (is_corlib_preload)
- image_corlib_loading = NULL;
-
- ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !assembly, nullptr, "Failed to load assembly for image");
// Decrement refcount which was previously incremented by mono_image_open_from_data_with_name
mono_image_close(image);
- loaded = true;
- modified_time = last_modified_time;
-
- return OK;
-}
-
-Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) {
-
- ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
-
- assembly = mono_image_get_assembly(p_image);
- ERR_FAIL_NULL_V(assembly, FAILED);
-
- image = p_image;
-
- loaded = true;
-
- return OK;
+ return assembly;
}
void GDMonoAssembly::unload() {
- ERR_FAIL_COND(!loaded);
+ ERR_FAIL_NULL(image); // Should not be called if already unloaded
for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) {
memdelete(E->value());
@@ -403,14 +300,17 @@ void GDMonoAssembly::unload() {
cached_classes.clear();
cached_raw.clear();
- assembly = NULL;
- image = NULL;
- loaded = false;
+ assembly = nullptr;
+ image = nullptr;
+}
+
+String GDMonoAssembly::get_path() const {
+ return String::utf8(mono_image_get_filename(image));
}
GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
- ERR_FAIL_COND_V(!loaded, NULL);
+ ERR_FAIL_NULL_V(image, nullptr);
ClassKey key(p_namespace, p_name);
@@ -422,7 +322,7 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri
MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8());
if (!mono_class)
- return NULL;
+ return nullptr;
GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this));
@@ -434,7 +334,7 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri
GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
- ERR_FAIL_COND_V(!loaded, NULL);
+ ERR_FAIL_NULL_V(image, nullptr);
Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class);
@@ -454,7 +354,7 @@ GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) {
- GDMonoClass *match = NULL;
+ GDMonoClass *match = nullptr;
if (gdobject_class_cache_updated) {
Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class);
@@ -486,7 +386,7 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
GDMonoClass *current_nested = nested_classes.front()->get();
nested_classes.pop_back();
- void *iter = NULL;
+ void *iter = nullptr;
while (true) {
MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_mono_ptr(), &iter);
@@ -514,32 +414,38 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) {
- GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
- if (loaded_asm)
- return *loaded_asm;
-#ifdef DEBUG_ENABLED
- CRASH_COND(!FileAccess::exists(p_path));
-#endif
- no_search = true;
- GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly);
- no_search = false;
- return res;
-}
+ if (p_name == "mscorlib" || p_name == "mscorlib.dll")
+ return GDMono::get_singleton()->get_corlib_assembly();
-GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
+ // We need to manually call the search hook in this case, as it won't be called in the next step
+ MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
+ MonoAssembly *assembly = mono_assembly_invoke_search_hook(aname);
+ mono_assembly_name_free(aname);
+ mono_free(aname);
+
+ if (!assembly) {
+ assembly = _real_load_assembly_from(p_path, p_refonly);
+ ERR_FAIL_NULL_V(assembly, nullptr);
+ }
- loaded = false;
- gdobject_class_cache_updated = false;
- name = p_name;
- path = p_path;
- refonly = false;
- modified_time = 0;
- assembly = NULL;
- image = NULL;
+ GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
+ ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?");
+
+ return loaded_asm;
+}
+
+GDMonoAssembly::GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly) :
+ name(p_name),
+ image(p_image),
+ assembly(p_assembly),
+#ifdef GD_MONO_HOT_RELOAD
+ modified_time(0),
+#endif
+ gdobject_class_cache_updated(false) {
}
GDMonoAssembly::~GDMonoAssembly() {
- if (loaded)
+ if (image)
unload();
}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 4740e10339..43c8225b74 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -68,24 +68,20 @@ class GDMonoAssembly {
StringName class_name;
};
- MonoAssembly *assembly;
+ String name;
MonoImage *image;
+ MonoAssembly *assembly;
- bool refonly;
- bool loaded;
-
- String name;
- String path;
+#ifdef GD_MONO_HOT_RELOAD
uint64_t modified_time;
-
- HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
- Map<MonoClass *, GDMonoClass *> cached_raw;
+#endif
bool gdobject_class_cache_updated;
Map<StringName, GDMonoClass *> gdobject_class_cache;
- static bool no_search;
- static bool in_preload;
+ HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
+ Map<MonoClass *, GDMonoClass *> cached_raw;
+
static Vector<String> search_dirs;
static void assembly_load_hook(MonoAssembly *assembly, void *user_data);
@@ -97,25 +93,24 @@ class GDMonoAssembly {
static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly);
static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly);
- static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly);
- static GDMonoAssembly *_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly);
- static void _wrap_mono_assembly(MonoAssembly *assembly);
+ static MonoAssembly *_real_load_assembly_from(const String &p_path, bool p_refonly);
+ static MonoAssembly *_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly);
friend class GDMono;
static void initialize();
public:
- Error load(bool p_refonly);
- Error wrapper_for_image(MonoImage *p_image);
void unload();
- _FORCE_INLINE_ bool is_refonly() const { return refonly; }
- _FORCE_INLINE_ bool is_loaded() const { return loaded; }
_FORCE_INLINE_ MonoImage *get_image() const { return image; }
_FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; }
_FORCE_INLINE_ String get_name() const { return name; }
- _FORCE_INLINE_ String get_path() const { return path; }
+
+#ifdef GD_MONO_HOT_RELOAD
_FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; }
+#endif
+
+ String get_path() const;
GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
GDMonoClass *get_class(MonoClass *p_mono_class);
@@ -128,7 +123,7 @@ public:
static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
- GDMonoAssembly(const String &p_name, const String &p_path = String());
+ GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly);
~GDMonoAssembly();
};
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 0ad90a510e..facc0da780 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -40,11 +40,11 @@ namespace GDMonoCache {
CachedData cached_data;
-#define CACHE_AND_CHECK(m_var, m_val) \
- { \
- CRASH_COND(m_var != NULL); \
- m_var = m_val; \
- ERR_FAIL_COND_MSG(m_var == NULL, "Mono Cache: Member " #m_var " is null."); \
+#define CACHE_AND_CHECK(m_var, m_val) \
+ { \
+ CRASH_COND(m_var != nullptr); \
+ m_var = m_val; \
+ ERR_FAIL_COND_MSG(m_var == nullptr, "Mono Cache: Member " #m_var " is null."); \
}
#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val)
@@ -54,12 +54,12 @@ CachedData cached_data;
#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val)
#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val)
-#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
- { \
- CRASH_COND(!m_var.is_null()); \
- ERR_FAIL_COND_MSG(m_val == NULL, "Mono Cache: Method for member " #m_var " is null."); \
- m_var.set_from_method(m_val); \
- ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \
+#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
+ { \
+ CRASH_COND(!m_var.is_null()); \
+ ERR_FAIL_COND_MSG(m_val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \
+ m_var.set_from_method(m_val); \
+ ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \
}
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val)
@@ -68,94 +68,105 @@ void CachedData::clear_corlib_cache() {
corlib_cache_updated = false;
- class_MonoObject = NULL;
- class_bool = NULL;
- class_int8_t = NULL;
- class_int16_t = NULL;
- class_int32_t = NULL;
- class_int64_t = NULL;
- class_uint8_t = NULL;
- class_uint16_t = NULL;
- class_uint32_t = NULL;
- class_uint64_t = NULL;
- class_float = NULL;
- class_double = NULL;
- class_String = NULL;
- class_IntPtr = NULL;
-
- class_System_Collections_IEnumerable = NULL;
- class_System_Collections_IDictionary = NULL;
+ class_MonoObject = nullptr;
+ class_bool = nullptr;
+ class_int8_t = nullptr;
+ class_int16_t = nullptr;
+ class_int32_t = nullptr;
+ class_int64_t = nullptr;
+ class_uint8_t = nullptr;
+ class_uint16_t = nullptr;
+ class_uint32_t = nullptr;
+ class_uint64_t = nullptr;
+ class_float = nullptr;
+ class_double = nullptr;
+ class_String = nullptr;
+ class_IntPtr = nullptr;
+
+ class_System_Collections_IEnumerable = nullptr;
+ class_System_Collections_IDictionary = nullptr;
#ifdef DEBUG_ENABLED
- class_System_Diagnostics_StackTrace = NULL;
+ class_System_Diagnostics_StackTrace = nullptr;
methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify();
- method_System_Diagnostics_StackTrace_ctor_bool = NULL;
- method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL;
+ method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
+ method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
#endif
- class_KeyNotFoundException = NULL;
+ class_KeyNotFoundException = nullptr;
}
void CachedData::clear_godot_api_cache() {
godot_api_cache_updated = false;
- rawclass_Dictionary = NULL;
-
- class_Vector2 = NULL;
- class_Rect2 = NULL;
- class_Transform2D = NULL;
- class_Vector3 = NULL;
- class_Basis = NULL;
- class_Quat = NULL;
- class_Transform = NULL;
- class_AABB = NULL;
- class_Color = NULL;
- class_Plane = NULL;
- class_NodePath = NULL;
- class_RID = NULL;
- class_GodotObject = NULL;
- class_GodotResource = NULL;
- class_Node = NULL;
- class_Control = NULL;
- class_Spatial = NULL;
- class_WeakRef = NULL;
- class_Array = NULL;
- class_Dictionary = NULL;
- class_MarshalUtils = NULL;
- class_ISerializationListener = NULL;
+ rawclass_Dictionary = nullptr;
+
+ class_Vector2 = nullptr;
+ class_Vector2i = nullptr;
+ class_Rect2 = nullptr;
+ class_Rect2i = nullptr;
+ class_Transform2D = nullptr;
+ class_Vector3 = nullptr;
+ class_Vector3i = nullptr;
+ class_Basis = nullptr;
+ class_Quat = nullptr;
+ class_Transform = nullptr;
+ class_AABB = nullptr;
+ class_Color = nullptr;
+ class_Plane = nullptr;
+ class_StringName = nullptr;
+ class_NodePath = nullptr;
+ class_RID = nullptr;
+ class_GodotObject = nullptr;
+ class_GodotResource = nullptr;
+ class_Node = nullptr;
+ class_Control = nullptr;
+ class_Node3D = nullptr;
+ class_WeakRef = nullptr;
+ class_Callable = nullptr;
+ class_SignalInfo = nullptr;
+ class_Array = nullptr;
+ class_Dictionary = nullptr;
+ class_MarshalUtils = nullptr;
+ class_ISerializationListener = nullptr;
#ifdef DEBUG_ENABLED
- class_DebuggingUtils = NULL;
+ class_DebuggingUtils = nullptr;
methodthunk_DebuggingUtils_GetStackFrameInfo.nullify();
#endif
- class_ExportAttribute = NULL;
- field_ExportAttribute_hint = NULL;
- field_ExportAttribute_hintString = NULL;
- class_SignalAttribute = NULL;
- class_ToolAttribute = NULL;
- class_RemoteAttribute = NULL;
- class_MasterAttribute = NULL;
- class_PuppetAttribute = NULL;
- class_RemoteSyncAttribute = NULL;
- class_MasterSyncAttribute = NULL;
- class_PuppetSyncAttribute = NULL;
- class_GodotMethodAttribute = NULL;
- field_GodotMethodAttribute_methodName = NULL;
-
- field_GodotObject_ptr = NULL;
- field_NodePath_ptr = NULL;
- field_Image_ptr = NULL;
- field_RID_ptr = NULL;
+ class_ExportAttribute = nullptr;
+ field_ExportAttribute_hint = nullptr;
+ field_ExportAttribute_hintString = nullptr;
+ class_SignalAttribute = nullptr;
+ class_ToolAttribute = nullptr;
+ class_RemoteAttribute = nullptr;
+ class_MasterAttribute = nullptr;
+ class_PuppetAttribute = nullptr;
+ class_RemoteSyncAttribute = nullptr;
+ class_MasterSyncAttribute = nullptr;
+ class_PuppetSyncAttribute = nullptr;
+ class_GodotMethodAttribute = nullptr;
+ field_GodotMethodAttribute_methodName = nullptr;
+
+ field_GodotObject_ptr = nullptr;
+ field_StringName_ptr = nullptr;
+ field_NodePath_ptr = nullptr;
+ field_Image_ptr = nullptr;
+ field_RID_ptr = nullptr;
methodthunk_GodotObject_Dispose.nullify();
methodthunk_Array_GetPtr.nullify();
methodthunk_Dictionary_GetPtr.nullify();
methodthunk_SignalAwaiter_SignalCallback.nullify();
- methodthunk_SignalAwaiter_FailureCallback.nullify();
methodthunk_GodotTaskScheduler_Activate.nullify();
+ methodthunk_Delegate_Equals.nullify();
+
+ methodthunk_DelegateUtils_TrySerializeDelegate.nullify();
+ methodthunk_DelegateUtils_TryDeserializeDelegate.nullify();
+
// Start of MarshalUtils methods
methodthunk_MarshalUtils_TypeIsGenericArray.nullify();
@@ -178,7 +189,7 @@ void CachedData::clear_godot_api_cache() {
// End of MarshalUtils methods
- task_scheduler_handle = Ref<MonoGCHandle>();
+ task_scheduler_handle = Ref<MonoGCHandleRef>();
}
#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
@@ -211,6 +222,8 @@ void update_corlib_cache() {
CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
#endif
+ CACHE_METHOD_THUNK_AND_CHECK(Delegate, Equals, GDMono::get_singleton()->get_corlib_assembly()->get_class("System", "Delegate")->get_method_with_desc("System.Delegate:Equals(object)", 1));
+
CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
cached_data.corlib_cache_updated = true;
@@ -219,23 +232,29 @@ void update_corlib_cache() {
void update_godot_api_cache() {
CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
+ CACHE_CLASS_AND_CHECK(Vector2i, GODOT_API_CLASS(Vector2i));
CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
+ CACHE_CLASS_AND_CHECK(Rect2i, GODOT_API_CLASS(Rect2i));
CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
+ CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i));
CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat));
CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform));
CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB));
CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
+ CACHE_CLASS_AND_CHECK(StringName, GODOT_API_CLASS(StringName));
CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
- CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
+ CACHE_CLASS_AND_CHECK(Node3D, GODOT_API_CLASS(Node3D));
CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
+ CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable));
+ CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo));
CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array));
CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary));
CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
@@ -261,6 +280,7 @@ void update_godot_api_cache() {
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
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));
CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
@@ -268,9 +288,11 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method("GetPtr", 0));
CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method("GetPtr", 0));
CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1));
- CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0));
CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegate", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegate", 2));
+
// Start of MarshalUtils methods
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1));
@@ -300,7 +322,7 @@ void update_godot_api_cache() {
// TODO Move to CSharpLanguage::init() and do handle disposal
MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler));
- cached_data.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
+ cached_data.task_scheduler_handle = MonoGCHandleRef::create_strong(task_scheduler);
cached_data.godot_api_cache_updated = true;
}
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 0458e91240..21c8ed4efe 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -73,23 +73,29 @@ struct CachedData {
// -----------------------------------------------
GDMonoClass *class_Vector2;
+ GDMonoClass *class_Vector2i;
GDMonoClass *class_Rect2;
+ GDMonoClass *class_Rect2i;
GDMonoClass *class_Transform2D;
GDMonoClass *class_Vector3;
+ GDMonoClass *class_Vector3i;
GDMonoClass *class_Basis;
GDMonoClass *class_Quat;
GDMonoClass *class_Transform;
GDMonoClass *class_AABB;
GDMonoClass *class_Color;
GDMonoClass *class_Plane;
+ GDMonoClass *class_StringName;
GDMonoClass *class_NodePath;
GDMonoClass *class_RID;
GDMonoClass *class_GodotObject;
GDMonoClass *class_GodotResource;
GDMonoClass *class_Node;
GDMonoClass *class_Control;
- GDMonoClass *class_Spatial;
+ GDMonoClass *class_Node3D;
GDMonoClass *class_WeakRef;
+ GDMonoClass *class_Callable;
+ GDMonoClass *class_SignalInfo;
GDMonoClass *class_Array;
GDMonoClass *class_Dictionary;
GDMonoClass *class_MarshalUtils;
@@ -115,6 +121,7 @@ struct CachedData {
GDMonoField *field_GodotMethodAttribute_methodName;
GDMonoField *field_GodotObject_ptr;
+ GDMonoField *field_StringName_ptr;
GDMonoField *field_NodePath_ptr;
GDMonoField *field_Image_ptr;
GDMonoField *field_RID_ptr;
@@ -123,9 +130,13 @@ struct CachedData {
GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
GDMonoMethodThunkR<Dictionary *, MonoObject *> methodthunk_Dictionary_GetPtr;
GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback;
- GDMonoMethodThunk<MonoObject *> methodthunk_SignalAwaiter_FailureCallback;
GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate;
+ GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoObject *> methodthunk_Delegate_Equals;
+
+ GDMonoMethodThunkR<MonoBoolean, MonoDelegate *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegate;
+ GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoDelegate **> methodthunk_DelegateUtils_TryDeserializeDelegate;
+
// Start of MarshalUtils methods
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray;
@@ -148,7 +159,7 @@ struct CachedData {
// End of MarshalUtils methods
- Ref<MonoGCHandle> task_scheduler_handle;
+ Ref<MonoGCHandleRef> task_scheduler_handle;
bool corlib_cache_updated;
bool godot_api_cache_updated;
@@ -193,10 +204,4 @@ _FORCE_INLINE_ bool tools_godot_api_check() {
#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method)
#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property)
-#ifdef REAL_T_IS_DOUBLE
-#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
-#else
-#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
-#endif
-
#endif // GD_MONO_CACHE_H
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 648f5f6c6b..ede4203e35 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -40,7 +40,7 @@ String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
// mono_type_get_full_name is not exposed to embedders, but this seems to do the job
MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class));
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoString *str = GDMonoUtils::object_to_string((MonoObject *)type_obj, &exc);
UNHANDLED_EXCEPTION(exc);
@@ -76,12 +76,12 @@ bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
GDMonoClass *GDMonoClass::get_parent_class() {
MonoClass *parent_mono_class = mono_class_get_parent(mono_class);
- return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : NULL;
+ return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : nullptr;
}
GDMonoClass *GDMonoClass::get_nesting_class() {
MonoClass *nesting_type = mono_class_get_nesting_type(mono_class);
- return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : NULL;
+ return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : nullptr;
}
#ifdef TOOLS_ENABLED
@@ -92,9 +92,9 @@ Vector<MonoClassField *> GDMonoClass::get_enum_fields() {
Vector<MonoClassField *> enum_fields;
- void *iter = NULL;
- MonoClassField *raw_field = NULL;
- while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != NULL) {
+ void *iter = nullptr;
+ MonoClassField *raw_field = nullptr;
+ while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != nullptr) {
uint32_t field_flags = mono_field_get_flags(raw_field);
// Enums have an instance field named value__ which holds the value of the enum.
@@ -126,21 +126,21 @@ bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) {
MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, NULL);
+ ERR_FAIL_NULL_V(p_attr_class, nullptr);
#endif
if (!attrs_fetched)
fetch_attributes();
if (!attributes)
- return NULL;
+ return nullptr;
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
}
void GDMonoClass::fetch_attributes() {
- ERR_FAIL_COND(attributes != NULL);
+ ERR_FAIL_COND(attributes != nullptr);
attributes = mono_custom_attrs_from_class(get_mono_ptr());
attrs_fetched = true;
@@ -153,9 +153,9 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
if (methods_fetched)
return;
- void *iter = NULL;
- MonoMethod *raw_method = NULL;
- while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) {
+ void *iter = nullptr;
+ MonoMethod *raw_method = nullptr;
+ while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
StringName name = mono_method_get_name(raw_method);
// get_method implicitly fetches methods and adds them to this->methods
@@ -198,7 +198,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
}
#endif
- uint32_t flags = mono_method_get_flags(method->mono_method, NULL);
+ uint32_t flags = mono_method_get_flags(method->mono_method, nullptr);
if (!(flags & MONO_METHOD_ATTR_VIRTUAL))
continue;
@@ -242,21 +242,21 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) {
- ERR_FAIL_COND_V(!methods_fetched, NULL);
+ ERR_FAIL_COND_V(!methods_fetched, nullptr);
- const MethodKey *k = NULL;
+ const MethodKey *k = nullptr;
while ((k = methods.next(k))) {
if (k->name == p_name)
return methods.get(*k);
}
- return NULL;
+ return nullptr;
}
bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
- return get_fetched_method_unknown_params(p_name) != NULL;
+ return get_fetched_method_unknown_params(p_name) != nullptr;
}
bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
@@ -274,7 +274,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_cou
return *match;
if (methods_fetched)
- return NULL;
+ return nullptr;
MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count);
@@ -285,7 +285,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_cou
return method;
}
- return NULL;
+ return nullptr;
}
GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) {
@@ -307,7 +307,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName
GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count) {
- ERR_FAIL_NULL_V(p_raw_method, NULL);
+ ERR_FAIL_NULL_V(p_raw_method, nullptr);
MethodKey key = MethodKey(p_name, p_params_count);
@@ -328,7 +328,7 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo
MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
mono_method_desc_free(desc);
- ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, NULL);
+ ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, nullptr);
return get_method(method);
}
@@ -341,7 +341,7 @@ GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
return result->value();
if (fields_fetched)
- return NULL;
+ return nullptr;
MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data());
@@ -352,7 +352,7 @@ GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
return field;
}
- return NULL;
+ return nullptr;
}
const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
@@ -360,9 +360,9 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
if (fields_fetched)
return fields_list;
- void *iter = NULL;
- MonoClassField *raw_field = NULL;
- while ((raw_field = mono_class_get_fields(mono_class, &iter)) != NULL) {
+ void *iter = nullptr;
+ MonoClassField *raw_field = nullptr;
+ while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) {
StringName name = mono_field_get_name(raw_field);
Map<StringName, GDMonoField *>::Element *match = fields.find(name);
@@ -389,7 +389,7 @@ GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
return result->value();
if (properties_fetched)
- return NULL;
+ return nullptr;
MonoProperty *raw_property = mono_class_get_property_from_name(mono_class, String(p_name).utf8().get_data());
@@ -400,7 +400,7 @@ GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
return property;
}
- return NULL;
+ return nullptr;
}
const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
@@ -408,9 +408,9 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
if (properties_fetched)
return properties_list;
- void *iter = NULL;
- MonoProperty *raw_property = NULL;
- while ((raw_property = mono_class_get_properties(mono_class, &iter)) != NULL) {
+ void *iter = nullptr;
+ MonoProperty *raw_property = nullptr;
+ while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) {
StringName name = mono_property_get_name(raw_property);
Map<StringName, GDMonoProperty *>::Element *match = properties.find(name);
@@ -433,9 +433,9 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
if (delegates_fetched)
return delegates_list;
- void *iter = NULL;
- MonoClass *raw_class = NULL;
- while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != NULL) {
+ void *iter = nullptr;
+ MonoClass *raw_class = nullptr;
+ while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != nullptr) {
if (mono_class_is_delegate(raw_class)) {
StringName name = mono_class_get_name(raw_class);
@@ -459,9 +459,9 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() {
if (!method_list_fetched) {
- void *iter = NULL;
- MonoMethod *raw_method = NULL;
- while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) {
+ void *iter = nullptr;
+ MonoMethod *raw_method = nullptr;
+ while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
method_list.push_back(memnew(GDMonoMethod(mono_method_get_name(raw_method), raw_method)));
}
@@ -479,7 +479,7 @@ GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name
assembly = p_assembly;
attrs_fetched = false;
- attributes = NULL;
+ attributes = nullptr;
methods_fetched = false;
method_list_fetched = false;
@@ -512,7 +512,7 @@ GDMonoClass::~GDMonoClass() {
Vector<GDMonoMethod *> deleted_methods;
deleted_methods.resize(methods.size());
- const MethodKey *k = NULL;
+ const MethodKey *k = nullptr;
while ((k = methods.next(k))) {
GDMonoMethod *method = methods.get(*k);
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index 03b56c9949..3f4e5fe5ac 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -37,6 +37,10 @@
#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
+void GDMonoField::set_value(MonoObject *p_object, MonoObject *p_value) {
+ mono_field_set_value(p_object, mono_field, p_value);
+}
+
void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
mono_field_set_value(p_object, mono_field, &p_ptr);
}
@@ -112,7 +116,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_STRING: {
if (p_value.get_type() == Variant::NIL) {
// Otherwise, Variant -> String would return the string "Null"
- MonoString *mono_string = NULL;
+ MonoString *mono_string = nullptr;
mono_field_set_value(p_object, mono_field, mono_string);
} else {
MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
@@ -128,11 +132,21 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (tclass == CACHED_CLASS(Vector2i)) {
+ SET_FROM_STRUCT(Vector2i);
+ break;
+ }
+
if (tclass == CACHED_CLASS(Rect2)) {
SET_FROM_STRUCT(Rect2);
break;
}
+ if (tclass == CACHED_CLASS(Rect2i)) {
+ SET_FROM_STRUCT(Rect2i);
+ break;
+ }
+
if (tclass == CACHED_CLASS(Transform2D)) {
SET_FROM_STRUCT(Transform2D);
break;
@@ -143,6 +157,11 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (tclass == CACHED_CLASS(Vector3i)) {
+ SET_FROM_STRUCT(Vector3i);
+ break;
+ }
+
if (tclass == CACHED_CLASS(Basis)) {
SET_FROM_STRUCT(Basis);
break;
@@ -173,6 +192,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (tclass == CACHED_CLASS(Callable)) {
+ GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable());
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+
+ if (tclass == CACHED_CLASS(SignalInfo)) {
+ GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal());
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+
if (mono_class_is_enum(tclass->get_mono_ptr())) {
MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
switch (mono_type_get_type(enum_basetype)) {
@@ -256,11 +287,21 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
- if (array_type->eklass == REAL_T_MONOCLASS) {
+ if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
+ SET_FROM_ARRAY(PackedInt64Array);
+ break;
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(float)) {
SET_FROM_ARRAY(PackedFloat32Array);
break;
}
+ if (array_type->eklass == CACHED_CLASS_RAW(double)) {
+ SET_FROM_ARRAY(PackedFloat64Array);
+ break;
+ }
+
if (array_type->eklass == CACHED_CLASS_RAW(String)) {
SET_FROM_ARRAY(PackedStringArray);
break;
@@ -294,6 +335,12 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
break;
}
+ if (CACHED_CLASS(StringName) == type_class) {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+
if (CACHED_CLASS(NodePath) == type_class) {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
mono_field_set_value(p_object, mono_field, managed);
@@ -386,12 +433,21 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case Variant::VECTOR2: {
SET_FROM_STRUCT(Vector2);
} break;
+ case Variant::VECTOR2I: {
+ SET_FROM_STRUCT(Vector2i);
+ } break;
case Variant::RECT2: {
SET_FROM_STRUCT(Rect2);
} break;
+ case Variant::RECT2I: {
+ SET_FROM_STRUCT(Rect2i);
+ } break;
case Variant::VECTOR3: {
SET_FROM_STRUCT(Vector3);
} break;
+ case Variant::VECTOR3I: {
+ SET_FROM_STRUCT(Vector3i);
+ } break;
case Variant::TRANSFORM2D: {
SET_FROM_STRUCT(Transform2D);
} break;
@@ -413,6 +469,10 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case Variant::COLOR: {
SET_FROM_STRUCT(Color);
} break;
+ case Variant::STRING_NAME: {
+ MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
+ mono_field_set_value(p_object, mono_field, managed);
+ } break;
case Variant::NODE_PATH: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
mono_field_set_value(p_object, mono_field, managed);
@@ -424,8 +484,15 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case Variant::OBJECT: {
MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
mono_field_set_value(p_object, mono_field, managed);
- break;
- }
+ } break;
+ case Variant::CALLABLE: {
+ GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable());
+ mono_field_set_value(p_object, mono_field, &val);
+ } break;
+ case Variant::SIGNAL: {
+ GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal());
+ mono_field_set_value(p_object, mono_field, &val);
+ } break;
case Variant::DICTIONARY: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
mono_field_set_value(p_object, mono_field, managed);
@@ -440,9 +507,15 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case Variant::PACKED_INT32_ARRAY: {
SET_FROM_ARRAY(PackedInt32Array);
} break;
+ case Variant::PACKED_INT64_ARRAY: {
+ SET_FROM_ARRAY(PackedInt64Array);
+ } break;
case Variant::PACKED_FLOAT32_ARRAY: {
SET_FROM_ARRAY(PackedFloat32Array);
} break;
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ SET_FROM_ARRAY(PackedFloat64Array);
+ } break;
case Variant::PACKED_STRING_ARRAY: {
SET_FROM_ARRAY(PackedStringArray);
} break;
@@ -550,19 +623,19 @@ bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
}
MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, NULL);
+ ERR_FAIL_NULL_V(p_attr_class, nullptr);
if (!attrs_fetched)
fetch_attributes();
if (!attributes)
- return NULL;
+ return nullptr;
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
}
void GDMonoField::fetch_attributes() {
- ERR_FAIL_COND(attributes != NULL);
+ ERR_FAIL_COND(attributes != nullptr);
attributes = mono_custom_attrs_from_field(owner->get_mono_ptr(), mono_field);
attrs_fetched = true;
}
@@ -598,7 +671,7 @@ GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) {
type.type_class = GDMono::get_singleton()->get_class(field_type_class);
attrs_fetched = false;
- attributes = NULL;
+ attributes = nullptr;
}
GDMonoField::~GDMonoField() {
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index 76ee0963c4..61f2c8f071 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -47,21 +47,22 @@ class GDMonoField : public IMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; }
+ virtual GDMonoClass *get_enclosing_class() const final { return owner; }
- virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_FIELD; }
+ virtual MemberType get_member_type() const final { return MEMBER_TYPE_FIELD; }
- virtual StringName get_name() const GD_FINAL { return name; }
+ virtual StringName get_name() const final { return name; }
- virtual bool is_static() GD_FINAL;
- virtual Visibility get_visibility() GD_FINAL;
+ virtual bool is_static() final;
+ virtual Visibility get_visibility() final;
- virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual bool has_attribute(GDMonoClass *p_attr_class) final;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
void fetch_attributes();
_FORCE_INLINE_ ManagedType get_type() const { return type; }
+ void set_value(MonoObject *p_object, MonoObject *p_value);
void set_value_raw(MonoObject *p_object, void *p_ptr);
void set_value_from_variant(MonoObject *p_object, const Variant &p_value);
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index b179b484f3..1898785699 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -33,7 +33,6 @@
#include "../csharp_script.h"
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
-#include "../utils/thread_local.h"
#include "gd_mono_class.h"
#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
@@ -62,7 +61,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
GDMonoClass *native = GDMonoUtils::get_class_native_base(klass);
- CRASH_COND(native == NULL);
+ CRASH_COND(native == nullptr);
if (native == klass) {
// If it's just a wrapper Godot class and not a custom inheriting class, then attach a
@@ -76,7 +75,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
script_binding.inited = true;
script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass);
script_binding.wrapper_class = klass;
- script_binding.gchandle = ref ? MonoGCHandle::create_weak(managed) : MonoGCHandle::create_strong(managed);
+ script_binding.gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
script_binding.owner = unmanaged;
if (ref) {
@@ -102,15 +101,17 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
return;
}
- Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) : MonoGCHandle::create_strong(managed);
+ MonoGCHandleData gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native);
CRASH_COND(script.is_null());
- ScriptInstance *si = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
+ CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
- unmanaged->set_script_and_instance(script, si);
+ unmanaged->set_script_and_instance(script, csharp_instance);
+
+ csharp_instance->connect_event_signals();
}
void unhandled_exception(MonoException *p_exc) {
@@ -118,7 +119,7 @@ void unhandled_exception(MonoException *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
- GDMono::unhandled_exception_hook((MonoObject *)p_exc, NULL);
+ GDMono::unhandled_exception_hook((MonoObject *)p_exc, nullptr);
GD_UNREACHABLE();
} else {
#ifdef DEBUG_ENABLED
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index 76828a66e0..ca16c2b76a 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -46,13 +46,13 @@ static CharString get_default_log_level() {
#endif
}
-GDMonoLog *GDMonoLog::singleton = NULL;
+GDMonoLog *GDMonoLog::singleton = nullptr;
-#if !defined(JAVASCRIPT_ENABLED)
+#ifdef GD_MONO_LOG_ENABLED
static int get_log_level_id(const char *p_log_level) {
- const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL };
+ const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", nullptr };
int i = 0;
while (valid_log_levels[i]) {
@@ -191,7 +191,7 @@ GDMonoLog::GDMonoLog() {
GDMonoLog::~GDMonoLog() {
- singleton = NULL;
+ singleton = nullptr;
if (log_file) {
log_file->close();
@@ -213,7 +213,7 @@ GDMonoLog::GDMonoLog() {
GDMonoLog::~GDMonoLog() {
- singleton = NULL;
+ singleton = nullptr;
}
#endif // !defined(JAVASCRIPT_ENABLED)
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index ecf4c78b1a..1fc21f7df5 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -35,13 +35,18 @@
#include "core/typedefs.h"
-#if !defined(JAVASCRIPT_ENABLED)
+#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED)
+// We have custom mono log callbacks for WASM and iOS
+#define GD_MONO_LOG_ENABLED
+#endif
+
+#ifdef GD_MONO_LOG_ENABLED
#include "core/os/file_access.h"
#endif
class GDMonoLog {
-#if !defined(JAVASCRIPT_ENABLED)
+#ifdef GD_MONO_LOG_ENABLED
int log_level_id;
FileAccess *log_file;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 695be64d6e..1878038f44 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -30,13 +30,14 @@
#include "gd_mono_marshal.h"
+#include "../signal_awaiter_utils.h"
#include "gd_mono.h"
#include "gd_mono_cache.h"
#include "gd_mono_class.h"
namespace GDMonoMarshal {
-Variant::Type managed_to_variant_type(const ManagedType &p_type) {
+Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return Variant::BOOL;
@@ -74,15 +75,24 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (vtclass == CACHED_CLASS(Vector2))
return Variant::VECTOR2;
+ if (vtclass == CACHED_CLASS(Vector2i))
+ return Variant::VECTOR2I;
+
if (vtclass == CACHED_CLASS(Rect2))
return Variant::RECT2;
+ if (vtclass == CACHED_CLASS(Rect2i))
+ return Variant::RECT2I;
+
if (vtclass == CACHED_CLASS(Transform2D))
return Variant::TRANSFORM2D;
if (vtclass == CACHED_CLASS(Vector3))
return Variant::VECTOR3;
+ if (vtclass == CACHED_CLASS(Vector3i))
+ return Variant::VECTOR3I;
+
if (vtclass == CACHED_CLASS(Basis))
return Variant::BASIS;
@@ -101,6 +111,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (vtclass == CACHED_CLASS(Plane))
return Variant::PLANE;
+ if (vtclass == CACHED_CLASS(Callable))
+ return Variant::CALLABLE;
+
+ if (vtclass == CACHED_CLASS(SignalInfo))
+ return Variant::SIGNAL;
+
if (mono_class_is_enum(vtclass->get_mono_ptr()))
return Variant::INT;
} break;
@@ -118,9 +134,15 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
return Variant::PACKED_INT32_ARRAY;
- if (array_type->eklass == REAL_T_MONOCLASS)
+ if (array_type->eklass == CACHED_CLASS_RAW(int64_t))
+ return Variant::PACKED_INT64_ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(float))
return Variant::PACKED_FLOAT32_ARRAY;
+ if (array_type->eklass == CACHED_CLASS_RAW(double))
+ return Variant::PACKED_FLOAT64_ARRAY;
+
if (array_type->eklass == CACHED_CLASS_RAW(String))
return Variant::PACKED_STRING_ARRAY;
@@ -142,6 +164,10 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
return Variant::OBJECT;
}
+ if (CACHED_CLASS(StringName) == type_class) {
+ return Variant::STRING_NAME;
+ }
+
if (CACHED_CLASS(NodePath) == type_class) {
return Variant::NODE_PATH;
}
@@ -179,6 +205,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
}
} break;
+ case MONO_TYPE_OBJECT: {
+ if (r_nil_is_variant)
+ *r_nil_is_variant = true;
+ return Variant::NIL;
+ } break;
+
case MONO_TYPE_GENERICINST: {
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
@@ -211,6 +243,9 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
} break;
}
+ if (r_nil_is_variant)
+ *r_nil_is_variant = false;
+
// Unknown
return Variant::NIL;
}
@@ -375,7 +410,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
case MONO_TYPE_STRING: {
if (p_var->get_type() == Variant::NIL)
- return NULL; // Otherwise, Variant -> String would return the string "Null"
+ return nullptr; // Otherwise, Variant -> String would return the string "Null"
return (MonoObject *)mono_string_from_godot(p_var->operator String());
} break;
@@ -387,11 +422,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
}
+ if (vtclass == CACHED_CLASS(Vector2i)) {
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
+ }
+
if (vtclass == CACHED_CLASS(Rect2)) {
GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
}
+ if (vtclass == CACHED_CLASS(Rect2i)) {
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
+ }
+
if (vtclass == CACHED_CLASS(Transform2D)) {
GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
@@ -402,6 +447,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
}
+ if (vtclass == CACHED_CLASS(Vector3i)) {
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
+ }
+
if (vtclass == CACHED_CLASS(Basis)) {
GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
@@ -432,6 +482,16 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
}
+ if (vtclass == CACHED_CLASS(Callable)) {
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
+ }
+
+ if (vtclass == CACHED_CLASS(SignalInfo)) {
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
+ }
+
if (mono_class_is_enum(vtclass->get_mono_ptr())) {
MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
@@ -477,7 +537,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return BOX_ENUM(enum_baseclass, val);
}
default: {
- ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
}
}
}
@@ -496,9 +556,15 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array());
- if (array_type->eklass == REAL_T_MONOCLASS)
+ if (array_type->eklass == CACHED_CLASS_RAW(int64_t))
+ return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(float))
return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array());
+ if (array_type->eklass == CACHED_CLASS_RAW(double))
+ return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array());
+
if (array_type->eklass == CACHED_CLASS_RAW(String))
return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray());
@@ -511,7 +577,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
if (array_type->eklass == CACHED_CLASS_RAW(Color))
return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray());
- ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed array of unmarshallable element type.");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to a managed array of unmarshallable element type.");
} break;
case MONO_TYPE_CLASS: {
@@ -522,6 +588,10 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
}
+ if (CACHED_CLASS(StringName) == type_class) {
+ return GDMonoUtils::create_managed_from(p_var->operator StringName());
+ }
+
if (CACHED_CLASS(NodePath) == type_class) {
return GDMonoUtils::create_managed_from(p_var->operator NodePath());
}
@@ -592,14 +662,26 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
}
+ case Variant::VECTOR2I: {
+ GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var->operator ::Vector2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
+ }
case Variant::RECT2: {
GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
}
+ case Variant::RECT2I: {
+ GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var->operator ::Rect2i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
+ }
case Variant::VECTOR3: {
GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
}
+ case Variant::VECTOR3I: {
+ GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var->operator ::Vector3i());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
+ }
case Variant::TRANSFORM2D: {
GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
@@ -628,12 +710,22 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
}
+ case Variant::STRING_NAME:
+ return GDMonoUtils::create_managed_from(p_var->operator StringName());
case Variant::NODE_PATH:
return GDMonoUtils::create_managed_from(p_var->operator NodePath());
case Variant::_RID:
return GDMonoUtils::create_managed_from(p_var->operator RID());
case Variant::OBJECT:
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
+ case Variant::CALLABLE: {
+ GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var->operator Callable());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
+ }
+ case Variant::SIGNAL: {
+ GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var->operator Signal());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
+ }
case Variant::DICTIONARY:
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
case Variant::ARRAY:
@@ -642,8 +734,12 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return (MonoObject *)PackedByteArray_to_mono_array(p_var->operator PackedByteArray());
case Variant::PACKED_INT32_ARRAY:
return (MonoObject *)PackedInt32Array_to_mono_array(p_var->operator PackedInt32Array());
+ case Variant::PACKED_INT64_ARRAY:
+ return (MonoObject *)PackedInt64Array_to_mono_array(p_var->operator PackedInt64Array());
case Variant::PACKED_FLOAT32_ARRAY:
return (MonoObject *)PackedFloat32Array_to_mono_array(p_var->operator PackedFloat32Array());
+ case Variant::PACKED_FLOAT64_ARRAY:
+ return (MonoObject *)PackedFloat64Array_to_mono_array(p_var->operator PackedFloat64Array());
case Variant::PACKED_STRING_ARRAY:
return (MonoObject *)PackedStringArray_to_mono_array(p_var->operator PackedStringArray());
case Variant::PACKED_VECTOR2_ARRAY:
@@ -653,7 +749,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
case Variant::PACKED_COLOR_ARRAY:
return (MonoObject *)PackedColorArray_to_mono_array(p_var->operator PackedColorArray());
default:
- return NULL;
+ return nullptr;
}
break;
case MONO_TYPE_GENERICINST: {
@@ -696,8 +792,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
} break;
}
- ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to an unmarshallable managed type. Name: '" +
- p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to an unmarshallable managed type. Name: '" +
+ p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
}
Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
@@ -735,7 +831,7 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return unbox<double>(p_obj);
case MONO_TYPE_STRING: {
- if (p_obj == NULL)
+ if (p_obj == nullptr)
return Variant(); // NIL
return mono_string_to_godot_not_null((MonoString *)p_obj);
} break;
@@ -744,34 +840,49 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
GDMonoClass *vtclass = p_type.type_class;
if (vtclass == CACHED_CLASS(Vector2))
- return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Vector2, unbox_addr<GDMonoMarshal::M_Vector2>(p_obj));
+
+ if (vtclass == CACHED_CLASS(Vector2i))
+ return MARSHALLED_IN(Vector2i, unbox_addr<GDMonoMarshal::M_Vector2i>(p_obj));
if (vtclass == CACHED_CLASS(Rect2))
- return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Rect2, unbox_addr<GDMonoMarshal::M_Rect2>(p_obj));
+
+ if (vtclass == CACHED_CLASS(Rect2i))
+ return MARSHALLED_IN(Rect2i, unbox_addr<GDMonoMarshal::M_Rect2i>(p_obj));
if (vtclass == CACHED_CLASS(Transform2D))
- return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Transform2D, unbox_addr<GDMonoMarshal::M_Transform2D>(p_obj));
if (vtclass == CACHED_CLASS(Vector3))
- return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Vector3, unbox_addr<GDMonoMarshal::M_Vector3>(p_obj));
+
+ if (vtclass == CACHED_CLASS(Vector3i))
+ return MARSHALLED_IN(Vector3i, unbox_addr<GDMonoMarshal::M_Vector3i>(p_obj));
if (vtclass == CACHED_CLASS(Basis))
- return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj));
if (vtclass == CACHED_CLASS(Quat))
- return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Quat, unbox_addr<GDMonoMarshal::M_Quat>(p_obj));
if (vtclass == CACHED_CLASS(Transform))
- return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Transform, unbox_addr<GDMonoMarshal::M_Transform>(p_obj));
if (vtclass == CACHED_CLASS(AABB))
- return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(AABB, unbox_addr<GDMonoMarshal::M_AABB>(p_obj));
if (vtclass == CACHED_CLASS(Color))
- return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Color, unbox_addr<GDMonoMarshal::M_Color>(p_obj));
if (vtclass == CACHED_CLASS(Plane))
- return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj));
+ return MARSHALLED_IN(Plane, unbox_addr<GDMonoMarshal::M_Plane>(p_obj));
+
+ if (vtclass == CACHED_CLASS(Callable))
+ return managed_to_callable(unbox<GDMonoMarshal::M_Callable>(p_obj));
+
+ if (vtclass == CACHED_CLASS(SignalInfo))
+ return managed_to_signal_info(unbox<GDMonoMarshal::M_SignalInfo>(p_obj));
if (mono_class_is_enum(vtclass->get_mono_ptr()))
return unbox<int32_t>(p_obj);
@@ -790,9 +901,15 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
return mono_array_to_PackedInt32Array((MonoArray *)p_obj);
- if (array_type->eklass == REAL_T_MONOCLASS)
+ if (array_type->eklass == CACHED_CLASS_RAW(int64_t))
+ return mono_array_to_PackedInt64Array((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(float))
return mono_array_to_PackedFloat32Array((MonoArray *)p_obj);
+ if (array_type->eklass == CACHED_CLASS_RAW(double))
+ return mono_array_to_PackedFloat64Array((MonoArray *)p_obj);
+
if (array_type->eklass == CACHED_CLASS_RAW(String))
return mono_array_to_PackedStringArray((MonoArray *)p_obj);
@@ -818,13 +935,18 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- if (ptr != NULL) {
+ if (ptr != nullptr) {
Reference *ref = Object::cast_to<Reference>(ptr);
return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr);
}
return Variant();
}
+ if (CACHED_CLASS(StringName) == type_class) {
+ StringName *ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_obj));
+ return ptr ? Variant(*ptr) : Variant();
+ }
+
if (CACHED_CLASS(NodePath) == type_class) {
NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
return ptr ? Variant(*ptr) : Variant();
@@ -836,14 +958,14 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
}
if (CACHED_CLASS(Array) == type_class) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc);
UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
}
if (CACHED_CLASS(Dictionary) == type_class) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc);
UNHANDLED_EXCEPTION(exc);
return ptr ? Variant(*ptr) : Variant();
@@ -874,14 +996,14 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNHANDLED_EXCEPTION(exc);
return *unbox<Dictionary *>(ret);
}
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
@@ -942,9 +1064,9 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
- if (var.get_type() == Variant::NIL && p_obj != NULL) {
+ if (var.get_type() == Variant::NIL && p_obj != nullptr) {
// Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc);
if (exc) {
@@ -960,9 +1082,10 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
}
MonoArray *Array_to_mono_array(const Array &p_array) {
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_array.size());
+ int length = p_array.size();
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length);
- for (int i = 0; i < p_array.size(); i++) {
+ for (int i = 0; i < length; i++) {
MonoObject *boxed = variant_to_mono_object(p_array[i]);
mono_array_setref(ret, i, boxed);
}
@@ -985,16 +1108,14 @@ Array mono_array_to_Array(MonoArray *p_array) {
return ret;
}
-// TODO: Use memcpy where possible
-
MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array) {
- const int *r = p_array.ptr();
+ const int32_t *src = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), length);
- for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, int32_t, i, r[i]);
- }
+ int32_t *dst = (int32_t *)mono_array_addr(ret, int32_t, 0);
+ memcpy(dst, src, length);
return ret;
}
@@ -1005,23 +1126,48 @@ PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
- int *w = ret.ptrw();
+ int32_t *dst = ret.ptrw();
- for (int i = 0; i < length; i++) {
- w[i] = mono_array_get(p_array, int32_t, i);
- }
+ const int32_t *src = (const int32_t *)mono_array_addr(p_array, int32_t, 0);
+ memcpy(dst, src, length);
+
+ return ret;
+}
+
+MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array) {
+ const int64_t *src = p_array.ptr();
+ int length = p_array.size();
+
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int64_t), length);
+
+ int64_t *dst = (int64_t *)mono_array_addr(ret, int64_t, 0);
+ memcpy(dst, src, length);
+
+ return ret;
+}
+
+PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array) {
+ PackedInt64Array ret;
+ if (!p_array)
+ return ret;
+ int length = mono_array_length(p_array);
+ ret.resize(length);
+ int64_t *dst = ret.ptrw();
+
+ const int64_t *src = (const int64_t *)mono_array_addr(p_array, int64_t, 0);
+ memcpy(dst, src, length);
return ret;
}
MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array) {
- const uint8_t *r = p_array.ptr();
+ const uint8_t *src = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), length);
- for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, uint8_t, i, r[i]);
- }
+ uint8_t *dst = (uint8_t *)mono_array_addr(ret, uint8_t, 0);
+ memcpy(dst, src, length);
return ret;
}
@@ -1032,23 +1178,22 @@ PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
- uint8_t *w = ret.ptrw();
+ uint8_t *dst = ret.ptrw();
- for (int i = 0; i < length; i++) {
- w[i] = mono_array_get(p_array, uint8_t, i);
- }
+ const uint8_t *src = (const uint8_t *)mono_array_addr(p_array, uint8_t, 0);
+ memcpy(dst, src, length);
return ret;
}
MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array) {
- const real_t *r = p_array.ptr();
+ const float *src = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), REAL_T_MONOCLASS, p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(float), length);
- for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, real_t, i, r[i]);
- }
+ float *dst = (float *)mono_array_addr(ret, float, 0);
+ memcpy(dst, src, length);
return ret;
}
@@ -1059,21 +1204,47 @@ PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
- real_t *w = ret.ptrw();
+ float *dst = ret.ptrw();
- for (int i = 0; i < length; i++) {
- w[i] = mono_array_get(p_array, real_t, i);
- }
+ const float *src = (const float *)mono_array_addr(p_array, float, 0);
+ memcpy(dst, src, length);
+
+ return ret;
+}
+
+MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array) {
+ const double *src = p_array.ptr();
+ int length = p_array.size();
+
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(double), length);
+
+ double *dst = (double *)mono_array_addr(ret, double, 0);
+ memcpy(dst, src, length);
+
+ return ret;
+}
+
+PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array) {
+ PackedFloat64Array ret;
+ if (!p_array)
+ return ret;
+ int length = mono_array_length(p_array);
+ ret.resize(length);
+ double *dst = ret.ptrw();
+
+ const double *src = (const double *)mono_array_addr(p_array, double, 0);
+ memcpy(dst, src, length);
return ret;
}
MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) {
const String *r = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), length);
- for (int i = 0; i < p_array.size(); i++) {
+ for (int i = 0; i < length; i++) {
MonoString *boxed = mono_string_from_godot(r[i]);
mono_array_setref(ret, i, boxed);
}
@@ -1098,13 +1269,19 @@ PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array) {
}
MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array) {
- const Color *r = p_array.ptr();
+ const Color *src = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), length);
- for (int i = 0; i < p_array.size(); i++) {
- M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
- *raw = MARSHALLED_OUT(Color, r[i]);
+ if constexpr (InteropLayout::MATCHES_Color) {
+ Color *dst = (Color *)mono_array_addr(ret, Color, 0);
+ memcpy(dst, src, length);
+ } else {
+ for (int i = 0; i < length; i++) {
+ M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
+ *raw = MARSHALLED_OUT(Color, src[i]);
+ }
}
return ret;
@@ -1116,23 +1293,34 @@ PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
- Color *w = ret.ptrw();
+ Color *dst = ret.ptrw();
- for (int i = 0; i < length; i++) {
- w[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
+ if constexpr (InteropLayout::MATCHES_Color) {
+ const Color *src = (const Color *)mono_array_addr(p_array, Color, 0);
+ memcpy(dst, src, length);
+ } else {
+ for (int i = 0; i < length; i++) {
+ dst[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
+ }
}
return ret;
}
MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array) {
- const Vector2 *r = p_array.ptr();
+ const Vector2 *src = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), length);
- for (int i = 0; i < p_array.size(); i++) {
- M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
- *raw = MARSHALLED_OUT(Vector2, r[i]);
+ if constexpr (InteropLayout::MATCHES_Vector2) {
+ Vector2 *dst = (Vector2 *)mono_array_addr(ret, Vector2, 0);
+ memcpy(dst, src, length);
+ } else {
+ for (int i = 0; i < length; i++) {
+ M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
+ *raw = MARSHALLED_OUT(Vector2, src[i]);
+ }
}
return ret;
@@ -1144,23 +1332,34 @@ PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
- Vector2 *w = ret.ptrw();
+ Vector2 *dst = ret.ptrw();
- for (int i = 0; i < length; i++) {
- w[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
+ if constexpr (InteropLayout::MATCHES_Vector2) {
+ const Vector2 *src = (const Vector2 *)mono_array_addr(p_array, Vector2, 0);
+ memcpy(dst, src, length);
+ } else {
+ for (int i = 0; i < length; i++) {
+ dst[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
+ }
}
return ret;
}
MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array) {
- const Vector3 *r = p_array.ptr();
+ const Vector3 *src = p_array.ptr();
+ int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), p_array.size());
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), length);
- for (int i = 0; i < p_array.size(); i++) {
- M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
- *raw = MARSHALLED_OUT(Vector3, r[i]);
+ if constexpr (InteropLayout::MATCHES_Vector3) {
+ Vector3 *dst = (Vector3 *)mono_array_addr(ret, Vector3, 0);
+ memcpy(dst, src, length);
+ } else {
+ for (int i = 0; i < length; i++) {
+ M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
+ *raw = MARSHALLED_OUT(Vector3, src[i]);
+ }
}
return ret;
@@ -1172,13 +1371,85 @@ PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
- Vector3 *w = ret.ptrw();
+ Vector3 *dst = ret.ptrw();
- for (int i = 0; i < length; i++) {
- w[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
+ if constexpr (InteropLayout::MATCHES_Vector3) {
+ const Vector3 *src = (const Vector3 *)mono_array_addr(p_array, Vector3, 0);
+ memcpy(dst, src, length);
+ } else {
+ for (int i = 0; i < length; i++) {
+ dst[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
+ }
}
return ret;
}
+Callable managed_to_callable(const M_Callable &p_managed_callable) {
+ if (p_managed_callable.delegate) {
+ // TODO: Use pooling for ManagedCallable instances.
+ CallableCustom *managed_callable = memnew(ManagedCallable(p_managed_callable.delegate));
+ return Callable(managed_callable);
+ } else {
+ Object *target = p_managed_callable.target ?
+ unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target)) :
+ nullptr;
+ StringName *method_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name));
+ StringName method = method_ptr ? *method_ptr : StringName();
+ return Callable(target, method);
+ }
+}
+
+M_Callable callable_to_managed(const Callable &p_callable) {
+ if (p_callable.is_custom()) {
+ CallableCustom *custom = p_callable.get_custom();
+ CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
+
+ if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
+ ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
+ return {
+ nullptr, nullptr,
+ managed_callable->get_delegate()
+ };
+ } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
+ SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
+ return {
+ GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(signal_awaiter_callable->get_object())),
+ GDMonoUtils::create_managed_from(signal_awaiter_callable->get_signal()),
+ nullptr
+ };
+ } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
+ EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
+ return {
+ GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(event_signal_callable->get_object())),
+ GDMonoUtils::create_managed_from(event_signal_callable->get_signal()),
+ nullptr
+ };
+ }
+
+ // Some other CallableCustom. We only support ManagedCallable.
+ return { nullptr, nullptr, nullptr };
+ } else {
+ MonoObject *target_managed = GDMonoUtils::unmanaged_get_managed(p_callable.get_object());
+ MonoObject *method_string_name_managed = GDMonoUtils::create_managed_from(p_callable.get_method());
+ return { target_managed, method_string_name_managed, nullptr };
+ }
+}
+
+Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) {
+ Object *owner = p_managed_signal.owner ?
+ unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner)) :
+ nullptr;
+ StringName *name_ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name));
+ StringName name = name_ptr ? *name_ptr : StringName();
+ return Signal(owner, name);
+}
+
+M_SignalInfo signal_info_to_managed(const Signal &p_signal) {
+ Object *owner = p_signal.get_object();
+ MonoObject *owner_managed = GDMonoUtils::unmanaged_get_managed(owner);
+ MonoObject *name_string_name_managed = GDMonoUtils::create_managed_from(p_signal.get_name());
+ return { owner_managed, name_string_name_managed };
+}
+
} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 5db59522ce..8b405291a7 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -33,6 +33,7 @@
#include "core/variant.h"
+#include "../managed_callable.h"
#include "gd_mono.h"
#include "gd_mono_utils.h"
@@ -62,7 +63,7 @@ T *unbox_addr(MonoObject *p_obj) {
#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
-Variant::Type managed_to_variant_type(const ManagedType &p_type);
+Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = nullptr);
bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type);
bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, ManagedType &r_key_type, ManagedType &r_value_type);
@@ -80,7 +81,7 @@ _FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) {
}
_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
- if (p_mono_string == NULL)
+ if (p_mono_string == nullptr)
return String();
return mono_string_to_godot_not_null(p_mono_string);
@@ -132,6 +133,11 @@ Array mono_array_to_Array(MonoArray *p_array);
MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array);
PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array);
+// PackedInt64Array
+
+MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array);
+PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array);
+
// PackedByteArray
MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array);
@@ -142,6 +148,11 @@ PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array);
MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array);
PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array);
+// PackedFloat64Array
+
+MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array);
+PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array);
+
// PackedStringArray
MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array);
@@ -162,11 +173,36 @@ PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array);
MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array);
PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array);
+#pragma pack(push, 1)
+
+struct M_Callable {
+ MonoObject *target;
+ MonoObject *method_string_name;
+ MonoDelegate *delegate;
+};
+
+struct M_SignalInfo {
+ MonoObject *owner;
+ MonoObject *name_string_name;
+};
+
+#pragma pack(pop)
+
+// Callable
+Callable managed_to_callable(const M_Callable &p_managed_callable);
+M_Callable callable_to_managed(const Callable &p_callable);
+
+// SignalInfo
+Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal);
+M_SignalInfo signal_info_to_managed(const Signal &p_signal);
+
// Structures
namespace InteropLayout {
enum {
+ MATCHES_int = (sizeof(int32_t) == sizeof(uint32_t)),
+
MATCHES_float = (sizeof(float) == sizeof(uint32_t)),
MATCHES_double = (sizeof(double) == sizeof(uint64_t)),
@@ -181,10 +217,18 @@ enum {
offsetof(Vector2, x) == (sizeof(real_t) * 0) &&
offsetof(Vector2, y) == (sizeof(real_t) * 1)),
+ MATCHES_Vector2i = (MATCHES_int && (sizeof(Vector2i) == (sizeof(int32_t) * 2)) &&
+ offsetof(Vector2i, x) == (sizeof(int32_t) * 0) &&
+ offsetof(Vector2i, y) == (sizeof(int32_t) * 1)),
+
MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) &&
offsetof(Rect2, position) == (sizeof(Vector2) * 0) &&
offsetof(Rect2, size) == (sizeof(Vector2) * 1)),
+ MATCHES_Rect2i = (MATCHES_Vector2i && (sizeof(Rect2i) == (sizeof(Vector2i) * 2)) &&
+ offsetof(Rect2i, position) == (sizeof(Vector2i) * 0) &&
+ offsetof(Rect2i, size) == (sizeof(Vector2i) * 1)),
+
MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array
MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) &&
@@ -192,6 +236,11 @@ enum {
offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
offsetof(Vector3, z) == (sizeof(real_t) * 2)),
+ MATCHES_Vector3i = (MATCHES_int && (sizeof(Vector3i) == (sizeof(int32_t) * 3)) &&
+ offsetof(Vector3i, x) == (sizeof(int32_t) * 0) &&
+ offsetof(Vector3i, y) == (sizeof(int32_t) * 1) &&
+ offsetof(Vector3i, z) == (sizeof(int32_t) * 2)),
+
MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array
MATCHES_Quat = (MATCHES_real_t && (sizeof(Quat) == (sizeof(real_t) * 4)) &&
@@ -222,8 +271,9 @@ enum {
// In the future we may force this if we want to ref return these structs
#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
/* clang-format off */
-GD_STATIC_ASSERT(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 &&
- MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color &&MATCHES_Plane);
+static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 &&
+ MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color &&
+ MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i);
/* clang-format on */
#endif
@@ -244,6 +294,19 @@ struct M_Vector2 {
}
};
+struct M_Vector2i {
+ int32_t x, y;
+
+ static _FORCE_INLINE_ Vector2i convert_to(const M_Vector2i &p_from) {
+ return Vector2i(p_from.x, p_from.y);
+ }
+
+ static _FORCE_INLINE_ M_Vector2i convert_from(const Vector2i &p_from) {
+ M_Vector2i ret = { p_from.x, p_from.y };
+ return ret;
+ }
+};
+
struct M_Rect2 {
M_Vector2 position;
M_Vector2 size;
@@ -259,6 +322,21 @@ struct M_Rect2 {
}
};
+struct M_Rect2i {
+ M_Vector2i position;
+ M_Vector2i size;
+
+ static _FORCE_INLINE_ Rect2i convert_to(const M_Rect2i &p_from) {
+ return Rect2i(M_Vector2i::convert_to(p_from.position),
+ M_Vector2i::convert_to(p_from.size));
+ }
+
+ static _FORCE_INLINE_ M_Rect2i convert_from(const Rect2i &p_from) {
+ M_Rect2i ret = { M_Vector2i::convert_from(p_from.position), M_Vector2i::convert_from(p_from.size) };
+ return ret;
+ }
+};
+
struct M_Transform2D {
M_Vector2 elements[3];
@@ -291,6 +369,19 @@ struct M_Vector3 {
}
};
+struct M_Vector3i {
+ int32_t x, y, z;
+
+ static _FORCE_INLINE_ Vector3i convert_to(const M_Vector3i &p_from) {
+ return Vector3i(p_from.x, p_from.y, p_from.z);
+ }
+
+ static _FORCE_INLINE_ M_Vector3i convert_from(const Vector3i &p_from) {
+ M_Vector3i ret = { p_from.x, p_from.y, p_from.z };
+ return ret;
+ }
+};
+
struct M_Basis {
M_Vector3 elements[3];
@@ -416,9 +507,12 @@ struct M_Plane {
}
DECL_TYPE_MARSHAL_TEMPLATES(Vector2)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector2i)
DECL_TYPE_MARSHAL_TEMPLATES(Rect2)
+DECL_TYPE_MARSHAL_TEMPLATES(Rect2i)
DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector3i)
DECL_TYPE_MARSHAL_TEMPLATES(Basis)
DECL_TYPE_MARSHAL_TEMPLATES(Quat)
DECL_TYPE_MARSHAL_TEMPLATES(Transform)
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index 971c5ac737..c8cc5247c6 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -58,9 +58,9 @@ void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
}
}
- void *iter = NULL;
+ void *iter = nullptr;
MonoType *param_raw_type;
- while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != NULL) {
+ while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != nullptr) {
ManagedType param_type;
param_type.type_encoding = mono_type_get_type(param_raw_type);
@@ -81,11 +81,11 @@ GDMonoClass *GDMonoMethod::get_enclosing_class() const {
}
bool GDMonoMethod::is_static() {
- return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC;
+ return mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
}
IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
- switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
+ switch (mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) {
case MONO_METHOD_ATTR_PRIVATE:
return IMonoClassMember::PRIVATE;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
@@ -101,55 +101,46 @@ IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
}
}
-MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) {
- if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) {
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
+MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) const {
+ MonoException *exc = nullptr;
+ MonoObject *ret;
+
+ if (params_count > 0) {
+ MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), params_count);
for (int i = 0; i < params_count; i++) {
MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]);
mono_array_setref(params, i, boxed_param);
}
- MonoException *exc = NULL;
- MonoObject *ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc);
-
- if (exc) {
- ret = NULL;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
+ ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc);
} else {
- MonoException *exc = NULL;
- GDMonoUtils::runtime_invoke(mono_method, p_object, NULL, &exc);
-
- if (exc) {
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
+ ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc);
+ }
- return NULL;
+ if (exc) {
+ ret = nullptr;
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ GDMonoUtils::set_pending_exception(exc);
+ }
}
+
+ return ret;
}
-MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) {
- ERR_FAIL_COND_V(get_parameters_count() > 0, NULL);
- return invoke_raw(p_object, NULL, r_exc);
+MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) const {
+ ERR_FAIL_COND_V(get_parameters_count() > 0, nullptr);
+ return invoke_raw(p_object, nullptr, r_exc);
}
-MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) {
- MonoException *exc = NULL;
+MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) const {
+ MonoException *exc = nullptr;
MonoObject *ret = GDMonoUtils::runtime_invoke(mono_method, p_object, p_params, &exc);
if (exc) {
- ret = NULL;
+ ret = nullptr;
if (r_exc) {
*r_exc = exc;
} else {
@@ -173,19 +164,19 @@ bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
}
MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, NULL);
+ ERR_FAIL_NULL_V(p_attr_class, nullptr);
if (!attrs_fetched)
fetch_attributes();
if (!attributes)
- return NULL;
+ return nullptr;
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
}
void GDMonoMethod::fetch_attributes() {
- ERR_FAIL_COND(attributes != NULL);
+ ERR_FAIL_COND(attributes != nullptr);
attributes = mono_custom_attrs_from_method(mono_method);
attrs_fetched = true;
}
@@ -247,7 +238,7 @@ void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const {
}
void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const {
- for (int i = 0; i < param_types.size(); ++i) {
+ for (int i = 0; i < params_count; ++i) {
types.push_back(param_types[i]);
}
}
@@ -256,13 +247,22 @@ const MethodInfo &GDMonoMethod::get_method_info() {
if (!method_info_fetched) {
method_info.name = name;
- method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type), "");
+
+ bool nil_is_variant = false;
+ method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type, &nil_is_variant), "");
+ if (method_info.return_val.type == Variant::NIL && nil_is_variant)
+ method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
Vector<StringName> names;
get_parameter_names(names);
for (int i = 0; i < params_count; ++i) {
- method_info.arguments.push_back(PropertyInfo(GDMonoMarshal::managed_to_variant_type(param_types[i]), names[i]));
+ nil_is_variant = false;
+ PropertyInfo arg_info = PropertyInfo(GDMonoMarshal::managed_to_variant_type(param_types[i], &nil_is_variant), names[i]);
+ if (arg_info.type == Variant::NIL && nil_is_variant)
+ arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+
+ method_info.arguments.push_back(arg_info);
}
// TODO: default arguments
@@ -281,7 +281,7 @@ GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
method_info_fetched = false;
attrs_fetched = false;
- attributes = NULL;
+ attributes = nullptr;
_update_signature();
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index b47e42dec2..54b2eba3e8 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -57,28 +57,28 @@ class GDMonoMethod : public IMonoClassMember {
MonoMethod *mono_method;
public:
- virtual GDMonoClass *get_enclosing_class() const GD_FINAL;
+ virtual GDMonoClass *get_enclosing_class() const final;
- virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_METHOD; }
+ virtual MemberType get_member_type() const final { return MEMBER_TYPE_METHOD; }
- virtual StringName get_name() const GD_FINAL { return name; }
+ virtual StringName get_name() const final { return name; }
- virtual bool is_static() GD_FINAL;
+ virtual bool is_static() final;
- virtual Visibility get_visibility() GD_FINAL;
+ virtual Visibility get_visibility() final;
- virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual bool has_attribute(GDMonoClass *p_attr_class) final;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
void fetch_attributes();
- _FORCE_INLINE_ MonoMethod *get_mono_ptr() { return mono_method; }
+ _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; }
- _FORCE_INLINE_ int get_parameters_count() { return params_count; }
- _FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
+ _FORCE_INLINE_ int get_parameters_count() const { return params_count; }
+ _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; }
- MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL);
- MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL);
- MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);
+ MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const;
+ MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = nullptr) const;
+ MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr) const;
String get_full_name(bool p_signature = false) const;
String get_full_name_no_class() const;
diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h
index d8c9a5eb02..0e05e974e9 100644
--- a/modules/mono/mono_gd/gd_mono_method_thunk.h
+++ b/modules/mono/mono_gd/gd_mono_method_thunk.h
@@ -39,7 +39,7 @@
#include "gd_mono_method.h"
#include "gd_mono_utils.h"
-#if !defined(JAVASCRIPT_ENABLED)
+#if !defined(JAVASCRIPT_ENABLED) && !defined(IPHONE_ENABLED)
#define HAVE_METHOD_THUNKS
#endif
@@ -60,16 +60,16 @@ public:
}
_FORCE_INLINE_ bool is_null() {
- return mono_method_thunk == NULL;
+ return mono_method_thunk == nullptr;
}
_FORCE_INLINE_ void nullify() {
- mono_method_thunk = NULL;
+ mono_method_thunk = nullptr;
}
_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == NULL);
+ CRASH_COND(p_mono_method == nullptr);
CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
if (p_mono_method->is_static()) {
@@ -82,7 +82,7 @@ public:
}
GDMonoMethodThunk() :
- mono_method_thunk(NULL) {
+ mono_method_thunk(nullptr) {
}
explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
@@ -106,16 +106,16 @@ public:
}
_FORCE_INLINE_ bool is_null() {
- return mono_method_thunk == NULL;
+ return mono_method_thunk == nullptr;
}
_FORCE_INLINE_ void nullify() {
- mono_method_thunk = NULL;
+ mono_method_thunk = nullptr;
}
_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == NULL);
+ CRASH_COND(p_mono_method == nullptr);
CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
if (p_mono_method->is_static()) {
@@ -128,12 +128,12 @@ public:
}
GDMonoMethodThunkR() :
- mono_method_thunk(NULL) {
+ mono_method_thunk(nullptr) {
}
explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == NULL);
+ CRASH_COND(p_mono_method == nullptr);
#endif
mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
}
@@ -146,7 +146,7 @@ struct VariadicInvokeMonoMethodImpl {
static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
if (p_mono_method->is_static()) {
void *args[ThunkParamCount] = { p_arg1, p_args... };
- p_mono_method->invoke_raw(NULL, args, r_exc);
+ p_mono_method->invoke_raw(nullptr, args, r_exc);
} else {
void *args[ThunkParamCount] = { p_args... };
p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
@@ -167,7 +167,7 @@ struct VariadicInvokeMonoMethod<0> {
#ifdef DEBUG_ENABLED
CRASH_COND(!p_mono_method->is_static());
#endif
- p_mono_method->invoke_raw(NULL, NULL, r_exc);
+ p_mono_method->invoke_raw(nullptr, nullptr, r_exc);
}
};
@@ -176,9 +176,9 @@ struct VariadicInvokeMonoMethod<1, P1> {
static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
if (p_mono_method->is_static()) {
void *args[1] = { p_arg1 };
- p_mono_method->invoke_raw(NULL, args, r_exc);
+ p_mono_method->invoke_raw(nullptr, args, r_exc);
} else {
- p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc);
+ p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc);
}
}
};
@@ -203,7 +203,7 @@ struct VariadicInvokeMonoMethodRImpl {
static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
if (p_mono_method->is_static()) {
void *args[ThunkParamCount] = { p_arg1, p_args... };
- MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc);
+ MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc);
return unbox_if_needed<R>(r, p_mono_method->get_return_type());
} else {
void *args[ThunkParamCount] = { p_args... };
@@ -226,7 +226,7 @@ struct VariadicInvokeMonoMethodR<0, R> {
#ifdef DEBUG_ENABLED
CRASH_COND(!p_mono_method->is_static());
#endif
- MonoObject *r = p_mono_method->invoke_raw(NULL, NULL, r_exc);
+ MonoObject *r = p_mono_method->invoke_raw(nullptr, nullptr, r_exc);
return unbox_if_needed<R>(r, p_mono_method->get_return_type());
}
};
@@ -236,10 +236,10 @@ struct VariadicInvokeMonoMethodR<1, R, P1> {
static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
if (p_mono_method->is_static()) {
void *args[1] = { p_arg1 };
- MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc);
+ MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc);
return unbox_if_needed<R>(r, p_mono_method->get_return_type());
} else {
- MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc);
+ MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc);
return unbox_if_needed<R>(r, p_mono_method->get_return_type());
}
}
@@ -256,16 +256,16 @@ public:
}
_FORCE_INLINE_ bool is_null() {
- return mono_method == NULL;
+ return mono_method == nullptr;
}
_FORCE_INLINE_ void nullify() {
- mono_method = NULL;
+ mono_method = nullptr;
}
_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == NULL);
+ CRASH_COND(p_mono_method == nullptr);
CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
if (p_mono_method->is_static()) {
@@ -278,7 +278,7 @@ public:
}
GDMonoMethodThunk() :
- mono_method(NULL) {
+ mono_method(nullptr) {
}
explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
@@ -297,16 +297,16 @@ public:
}
_FORCE_INLINE_ bool is_null() {
- return mono_method == NULL;
+ return mono_method == nullptr;
}
_FORCE_INLINE_ void nullify() {
- mono_method = NULL;
+ mono_method = nullptr;
}
_FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == NULL);
+ CRASH_COND(p_mono_method == nullptr);
CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
if (p_mono_method->is_static()) {
@@ -319,7 +319,7 @@ public:
}
GDMonoMethodThunkR() :
- mono_method(NULL) {
+ mono_method(nullptr) {
}
explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index 3b5ce58d80..c3e7598f2d 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -57,7 +57,7 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own
MonoMethodSignature *setter_sig = mono_method_signature(prop_method);
- void *iter = NULL;
+ void *iter = nullptr;
MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter);
type.type_encoding = mono_type_get_type(param_raw_type);
@@ -66,7 +66,7 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own
}
attrs_fetched = false;
- attributes = NULL;
+ attributes = nullptr;
}
GDMonoProperty::~GDMonoProperty() {
@@ -77,17 +77,17 @@ GDMonoProperty::~GDMonoProperty() {
bool GDMonoProperty::is_static() {
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
- if (prop_method == NULL)
+ if (prop_method == nullptr)
prop_method = mono_property_get_set_method(mono_property);
- return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC;
+ return mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_STATIC;
}
IMonoClassMember::Visibility GDMonoProperty::get_visibility() {
MonoMethod *prop_method = mono_property_get_get_method(mono_property);
- if (prop_method == NULL)
+ if (prop_method == nullptr)
prop_method = mono_property_get_set_method(mono_property);
- switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
+ switch (mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) {
case MONO_METHOD_ATTR_PRIVATE:
return IMonoClassMember::PRIVATE;
case MONO_METHOD_ATTR_FAM_AND_ASSEM:
@@ -116,36 +116,36 @@ bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) {
}
MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, NULL);
+ ERR_FAIL_NULL_V(p_attr_class, nullptr);
if (!attrs_fetched)
fetch_attributes();
if (!attributes)
- return NULL;
+ return nullptr;
return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
}
void GDMonoProperty::fetch_attributes() {
- ERR_FAIL_COND(attributes != NULL);
+ ERR_FAIL_COND(attributes != nullptr);
attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property);
attrs_fetched = true;
}
bool GDMonoProperty::has_getter() {
- return mono_property_get_get_method(mono_property) != NULL;
+ return mono_property_get_get_method(mono_property) != nullptr;
}
bool GDMonoProperty::has_setter() {
- return mono_property_get_set_method(mono_property) != NULL;
+ return mono_property_get_set_method(mono_property) != nullptr;
}
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
mono_array_setref(params, 0, p_value);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc);
if (exc) {
if (r_exc) {
@@ -157,7 +157,7 @@ void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoEx
}
void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::property_set_value(mono_property, p_object, p_params, &exc);
if (exc) {
@@ -170,11 +170,11 @@ void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoExcept
}
MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) {
- MonoException *exc = NULL;
- MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, NULL, &exc);
+ MonoException *exc = nullptr;
+ MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, nullptr, &exc);
if (exc) {
- ret = NULL;
+ ret = nullptr;
if (r_exc) {
*r_exc = exc;
} else {
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 692037f76a..4653758a86 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -47,17 +47,17 @@ class GDMonoProperty : public IMonoClassMember {
MonoCustomAttrInfo *attributes;
public:
- virtual GDMonoClass *get_enclosing_class() const GD_FINAL { return owner; }
+ virtual GDMonoClass *get_enclosing_class() const final { return owner; }
- virtual MemberType get_member_type() const GD_FINAL { return MEMBER_TYPE_PROPERTY; }
+ virtual MemberType get_member_type() const final { return MEMBER_TYPE_PROPERTY; }
- virtual StringName get_name() const GD_FINAL { return name; }
+ virtual StringName get_name() const final { return name; }
- virtual bool is_static() GD_FINAL;
- virtual Visibility get_visibility() GD_FINAL;
+ virtual bool is_static() final;
+ virtual Visibility get_visibility() final;
- virtual bool has_attribute(GDMonoClass *p_attr_class) GD_FINAL;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL;
+ virtual bool has_attribute(GDMonoClass *p_attr_class) final;
+ virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
void fetch_attributes();
bool has_getter();
@@ -65,9 +65,9 @@ public:
_FORCE_INLINE_ ManagedType get_type() const { return type; }
- void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = NULL);
- void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL);
- MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = NULL);
+ void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = nullptr);
+ void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr);
+ MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = nullptr);
bool get_bool_value(MonoObject *p_object);
int get_int_value(MonoObject *p_object);
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index bc290f3a7f..00119ced88 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -57,7 +57,7 @@ namespace GDMonoUtils {
MonoObject *unmanaged_get_managed(Object *unmanaged) {
if (!unmanaged)
- return NULL;
+ return nullptr;
if (unmanaged->get_script_instance()) {
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
@@ -71,7 +71,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
- ERR_FAIL_NULL_V(data, NULL);
+ ERR_FAIL_NULL_V(data, nullptr);
CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
@@ -82,14 +82,13 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
// Already had a binding that needs to be setup
CSharpLanguage::get_singleton()->setup_csharp_script_binding(script_binding, unmanaged);
- ERR_FAIL_COND_V(!script_binding.inited, NULL);
+ ERR_FAIL_COND_V(!script_binding.inited, nullptr);
}
}
- Ref<MonoGCHandle> &gchandle = script_binding.gchandle;
- ERR_FAIL_COND_V(gchandle.is_null(), NULL);
+ MonoGCHandleData &gchandle = script_binding.gchandle;
- MonoObject *target = gchandle->get_target();
+ MonoObject *target = gchandle.get_target();
if (target)
return target;
@@ -100,13 +99,13 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
#ifdef DEBUG_ENABLED
CRASH_COND(script_binding.type_name == StringName());
- CRASH_COND(script_binding.wrapper_class == NULL);
+ CRASH_COND(script_binding.wrapper_class == nullptr);
#endif
MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
- ERR_FAIL_NULL_V(mono_object, NULL);
+ ERR_FAIL_NULL_V(mono_object, nullptr);
- gchandle->set_handle(MonoGCHandle::new_strong_handle(mono_object), MonoGCHandle::STRONG_HANDLE);
+ gchandle = MonoGCHandleData::new_strong_handle(mono_object);
// Tie managed to unmanaged
Reference *ref = Object::cast_to<Reference>(unmanaged);
@@ -128,10 +127,15 @@ void set_main_thread(MonoThread *p_thread) {
}
MonoThread *attach_current_thread() {
- ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), NULL);
+ ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), nullptr);
MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain();
+#ifndef GD_MONO_SINGLE_APPDOMAIN
MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain());
- ERR_FAIL_NULL_V(mono_thread, NULL);
+#else
+ // The scripts domain is the root domain
+ MonoThread *mono_thread = mono_thread_attach(scripts_domain);
+#endif
+ ERR_FAIL_NULL_V(mono_thread, nullptr);
return mono_thread;
}
@@ -153,13 +157,36 @@ MonoThread *get_current_thread() {
}
bool is_thread_attached() {
- return mono_domain_get() != NULL;
+ return mono_domain_get() != nullptr;
+}
+
+uint32_t new_strong_gchandle(MonoObject *p_object) {
+ return mono_gchandle_new(p_object, /* pinned: */ false);
+}
+
+uint32_t new_strong_gchandle_pinned(MonoObject *p_object) {
+ return mono_gchandle_new(p_object, /* pinned: */ true);
+}
+
+uint32_t new_weak_gchandle(MonoObject *p_object) {
+ return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false);
+}
+
+void free_gchandle(uint32_t p_gchandle) {
+ mono_gchandle_free(p_gchandle);
}
void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) {
GDMonoMethod *ctor = p_class->get_method(".ctor", 0);
ERR_FAIL_NULL(ctor);
- ctor->invoke_raw(p_this_obj, NULL, r_exc);
+ ctor->invoke_raw(p_this_obj, nullptr, r_exc);
+}
+
+bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b) {
+ MonoException *exc = nullptr;
+ MonoBoolean res = CACHED_METHOD_THUNK(Delegate, Equals).invoke((MonoObject *)p_a, (MonoObject *)p_b, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ return (bool)res;
}
GDMonoClass *get_object_class(MonoObject *p_object) {
@@ -199,18 +226,18 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
if (assembly == GDMono::get_singleton()->get_editor_api_assembly())
return klass;
#endif
- } while ((klass = klass->get_parent_class()) != NULL);
+ } while ((klass = klass->get_parent_class()) != nullptr);
- return NULL;
+ return nullptr;
}
MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native);
- ERR_FAIL_COND_V_MSG(!parent_is_object_class, NULL,
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr,
"Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'.");
MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, NULL);
+ ERR_FAIL_NULL_V(mono_object, nullptr);
CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
@@ -220,9 +247,21 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa
return mono_object;
}
+MonoObject *create_managed_from(const StringName &p_from) {
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(StringName));
+ ERR_FAIL_NULL_V(mono_object, nullptr);
+
+ // Construct
+ GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(StringName));
+
+ CACHED_FIELD(StringName, ptr)->set_value_raw(mono_object, memnew(StringName(p_from)));
+
+ return mono_object;
+}
+
MonoObject *create_managed_from(const NodePath &p_from) {
MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath));
- ERR_FAIL_NULL_V(mono_object, NULL);
+ ERR_FAIL_NULL_V(mono_object, nullptr);
// Construct
GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath));
@@ -234,7 +273,7 @@ MonoObject *create_managed_from(const NodePath &p_from) {
MonoObject *create_managed_from(const RID &p_from) {
MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID));
- ERR_FAIL_NULL_V(mono_object, NULL);
+ ERR_FAIL_NULL_V(mono_object, nullptr);
// Construct
GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID));
@@ -246,15 +285,15 @@ MonoObject *create_managed_from(const RID &p_from) {
MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, NULL);
+ ERR_FAIL_NULL_V(mono_object, nullptr);
// Search constructor that takes a pointer as parameter
MonoMethod *m;
- void *iter = NULL;
+ void *iter = nullptr;
while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
MonoMethodSignature *sig = mono_method_signature(m);
- void *front = NULL;
+ void *front = nullptr;
if (mono_signature_get_param_count(sig) == 1 &&
mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
break;
@@ -262,12 +301,12 @@ MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
}
}
- CRASH_COND(m == NULL);
+ CRASH_COND(m == nullptr);
Array *new_array = memnew(Array(p_from));
void *args[1] = { &new_array };
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
UNHANDLED_EXCEPTION(exc);
@@ -276,15 +315,15 @@ MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, NULL);
+ ERR_FAIL_NULL_V(mono_object, nullptr);
// Search constructor that takes a pointer as parameter
MonoMethod *m;
- void *iter = NULL;
+ void *iter = nullptr;
while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
MonoMethodSignature *sig = mono_method_signature(m);
- void *front = NULL;
+ void *front = nullptr;
if (mono_signature_get_param_count(sig) == 1 &&
mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
break;
@@ -292,12 +331,12 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class)
}
}
- CRASH_COND(m == NULL);
+ CRASH_COND(m == nullptr);
Dictionary *new_dict = memnew(Dictionary(p_from));
void *args[1] = { &new_dict };
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
UNHANDLED_EXCEPTION(exc);
@@ -307,7 +346,7 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class)
MonoDomain *create_domain(const String &p_friendly_name) {
print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
- MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
+ MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), nullptr);
if (domain) {
// Workaround to avoid this exception:
@@ -332,7 +371,7 @@ String get_exception_name_and_message(MonoException *p_exc) {
res += ": ";
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
- MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, NULL, NULL);
+ MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, nullptr, nullptr);
res += GDMonoMarshal::mono_string_to_godot(msg);
return res;
@@ -343,7 +382,7 @@ void set_exception_message(MonoException *p_exc, String message) {
MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
MonoString *msg = GDMonoMarshal::mono_string_from_godot(message);
void *params[1] = { msg };
- property_set_value(prop, (MonoObject *)p_exc, params, NULL);
+ property_set_value(prop, (MonoObject *)p_exc, params, nullptr);
}
void debug_print_unhandled_exception(MonoException *p_exc) {
@@ -362,7 +401,11 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
return;
}
- _TLS_RECURSION_GUARD_;
+ static thread_local bool _recursion_flag_ = false;
+ if (_recursion_flag_)
+ return;
+ _recursion_flag_ = true;
+ SCOPE_EXIT { _recursion_flag_ = false; };
ScriptLanguage::StackInfo separator;
separator.file = String();
@@ -372,14 +415,14 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
Vector<ScriptLanguage::StackInfo> si;
String exc_msg;
- while (p_exc != NULL) {
+ while (p_exc != nullptr) {
GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr());
MonoBoolean need_file_info = true;
void *ctor_args[2] = { p_exc, &need_file_info };
- MonoException *unexpected_exc = NULL;
+ MonoException *unexpected_exc = nullptr;
CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
if (unexpected_exc) {
@@ -388,7 +431,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
}
Vector<ScriptLanguage::StackInfo> _si;
- if (stack_trace != NULL) {
+ if (stack_trace != nullptr) {
_si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
for (int i = _si.size() - 1; i >= 0; i--)
si.insert(0, _si[i]);
@@ -398,10 +441,10 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class());
GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException");
- CRASH_COND(inner_exc_prop == NULL);
+ CRASH_COND(inner_exc_prop == nullptr);
MonoObject *inner_exc = inner_exc_prop->get_value((MonoObject *)p_exc);
- if (inner_exc != NULL)
+ if (inner_exc != nullptr)
si.insert(0, separator);
p_exc = (MonoException *)inner_exc;
@@ -439,8 +482,7 @@ void set_pending_exception(MonoException *p_exc) {
#endif
}
-_THREAD_LOCAL_(int)
-current_invoke_count = 0;
+thread_local int current_invoke_count = 0;
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
@@ -528,7 +570,7 @@ namespace Marshal {
bool type_is_generic_array(MonoReflectionType *p_reftype) {
NO_GLUE_RET(false);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return (bool)res;
@@ -536,27 +578,27 @@ bool type_is_generic_array(MonoReflectionType *p_reftype) {
bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
NO_GLUE_RET(false);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return (bool)res;
}
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
}
void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
}
bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
NO_GLUE_RET(false);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType).invoke(p_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return (bool)res;
@@ -564,7 +606,7 @@ bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
NO_GLUE_RET(false);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType).invoke(p_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return (bool)res;
@@ -572,7 +614,7 @@ bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
NO_GLUE_RET(false);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info).invoke(p_reftype, r_elem_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return (bool)res;
@@ -580,7 +622,7 @@ bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoR
bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
NO_GLUE_RET(false);
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info).invoke(p_reftype, r_key_reftype, r_value_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return (bool)res;
@@ -589,7 +631,7 @@ bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoR
Array enumerable_to_array(MonoObject *p_enumerable) {
NO_GLUE_RET(Array());
Array result;
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray).invoke(p_enumerable, &result, &exc);
UNHANDLED_EXCEPTION(exc);
return result;
@@ -598,7 +640,7 @@ Array enumerable_to_array(MonoObject *p_enumerable) {
Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
NO_GLUE_RET(Dictionary());
Dictionary result;
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary).invoke(p_idictionary, &result, &exc);
UNHANDLED_EXCEPTION(exc);
return result;
@@ -607,23 +649,23 @@ Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) {
NO_GLUE_RET(Dictionary());
Dictionary result;
- MonoException *exc = NULL;
+ MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary).invoke(p_generic_idictionary, &result, &exc);
UNHANDLED_EXCEPTION(exc);
return result;
}
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
- NO_GLUE_RET(NULL);
- MonoException *exc = NULL;
+ NO_GLUE_RET(nullptr);
+ MonoException *exc = nullptr;
MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
}
GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- NO_GLUE_RET(NULL);
- MonoException *exc = NULL;
+ NO_GLUE_RET(nullptr);
+ MonoException *exc = nullptr;
MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
@@ -632,7 +674,7 @@ GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, Mon
} // namespace Marshal
ScopeThreadAttach::ScopeThreadAttach() :
- mono_thread(NULL) {
+ mono_thread(nullptr) {
if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) {
mono_thread = GDMonoUtils::attach_current_thread();
}
@@ -644,6 +686,10 @@ ScopeThreadAttach::~ScopeThreadAttach() {
}
}
-// namespace Marshal
+StringName get_native_godot_class_name(GDMonoClass *p_class) {
+ MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(nullptr);
+ StringName *ptr = GDMonoMarshal::unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(native_name_obj));
+ return ptr ? *ptr : StringName();
+}
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index db9f99bfdc..b850e1be9b 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -35,14 +35,13 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
-#include "../utils/thread_local.h"
#include "gd_mono_header.h"
#include "core/object.h"
#include "core/reference.h"
#define UNHANDLED_EXCEPTION(m_exc) \
- if (unlikely(m_exc != NULL)) { \
+ if (unlikely(m_exc != nullptr)) { \
GDMonoUtils::debug_unhandled_exception(m_exc); \
GD_UNREACHABLE(); \
}
@@ -78,7 +77,7 @@ _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash)
/**
* If the object has a csharp script, returns the target of the gchandle stored in the script instance
* Otherwise returns a newly constructed MonoObject* which is attached to the object
- * Returns NULL on error
+ * Returns nullptr on error
*/
MonoObject *unmanaged_get_managed(Object *unmanaged);
@@ -90,10 +89,17 @@ MonoThread *get_current_thread();
bool is_thread_attached();
_FORCE_INLINE_ bool is_main_thread() {
- return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
+ return mono_domain_get() != nullptr && mono_thread_get_main() == mono_thread_current();
}
-void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = NULL);
+uint32_t new_strong_gchandle(MonoObject *p_object);
+uint32_t new_strong_gchandle_pinned(MonoObject *p_object);
+uint32_t new_weak_gchandle(MonoObject *p_object);
+void free_gchandle(uint32_t p_gchandle);
+
+void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = nullptr);
+
+bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b);
GDMonoClass *get_object_class(MonoObject *p_object);
GDMonoClass *type_get_proxy_class(const StringName &p_type);
@@ -101,6 +107,7 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class);
MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object);
+MonoObject *create_managed_from(const StringName &p_from);
MonoObject *create_managed_from(const NodePath &p_from);
MonoObject *create_managed_from(const RID &p_from);
MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class);
@@ -123,7 +130,7 @@ void print_unhandled_exception(MonoException *p_exc);
*/
void set_pending_exception(MonoException *p_exc);
-extern _THREAD_LOCAL_(int) current_invoke_count;
+extern thread_local int current_invoke_count;
_FORCE_INLINE_ int get_runtime_invoke_count() {
return current_invoke_count;
@@ -152,9 +159,11 @@ private:
MonoThread *mono_thread;
};
+StringName get_native_godot_class_name(GDMonoClass *p_class);
+
} // namespace GDMonoUtils
-#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL)))
+#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class))
#define GD_MONO_BEGIN_RUNTIME_INVOKE \
int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h
index 11b832d0cc..84d1837853 100644
--- a/modules/mono/mono_gd/managed_type.h
+++ b/modules/mono/mono_gd/managed_type.h
@@ -46,7 +46,7 @@ struct ManagedType {
ManagedType() :
type_encoding(0),
- type_class(NULL) {
+ type_class(nullptr) {
}
ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
new file mode 100755
index 0000000000..8bcdeec9dd
--- /dev/null
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -0,0 +1,690 @@
+/*************************************************************************/
+/* android_support.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "android_support.h"
+
+#if defined(ANDROID_ENABLED)
+
+#include <dlfcn.h> // dlopen, dlsym
+#include <mono/utils/mono-dl-fallback.h>
+#include <sys/system_properties.h>
+#include <cstddef>
+
+#if __ANDROID_API__ < 24
+#include "thirdparty/misc/ifaddrs-android.h"
+#else
+#include <ifaddrs.h>
+#endif
+
+#include "core/os/os.h"
+#include "core/ustring.h"
+#include "platform/android/java_godot_wrapper.h"
+#include "platform/android/os_android.h"
+#include "platform/android/thread_jandroid.h"
+
+#include "../../utils/path_utils.h"
+#include "../../utils/string_utils.h"
+#include "../gd_mono_cache.h"
+#include "../gd_mono_marshal.h"
+
+// Warning: JNI boilerplate ahead... continue at your own risk
+
+namespace gdmono {
+namespace android {
+namespace support {
+
+template <typename T>
+struct ScopedLocalRef {
+ JNIEnv *env;
+ T local_ref;
+
+ _FORCE_INLINE_ T get() const { return local_ref; }
+ _FORCE_INLINE_ operator T() const { return local_ref; }
+ _FORCE_INLINE_ operator jvalue() const { return (jvalue)local_ref; }
+
+ _FORCE_INLINE_ operator bool() const { return local_ref != nullptr; }
+
+ _FORCE_INLINE_ bool operator==(std::nullptr_t) const {
+ return local_ref == nullptr;
+ }
+
+ _FORCE_INLINE_ bool operator!=(std::nullptr_t) const {
+ return local_ref != nullptr;
+ }
+
+ ScopedLocalRef(const ScopedLocalRef &) = delete;
+ ScopedLocalRef &operator=(const ScopedLocalRef &) = delete;
+
+ ScopedLocalRef(JNIEnv *p_env, T p_local_ref) :
+ env(p_env),
+ local_ref(p_local_ref) {
+ }
+
+ ~ScopedLocalRef() {
+ if (local_ref) {
+ env->DeleteLocalRef(local_ref);
+ }
+ }
+};
+
+bool jni_exception_check(JNIEnv *p_env) {
+ if (p_env->ExceptionCheck()) {
+ // Print the exception to logcat
+ p_env->ExceptionDescribe();
+
+ p_env->ExceptionClear();
+ return true;
+ }
+
+ return false;
+}
+
+String app_native_lib_dir_cache;
+
+String determine_app_native_lib_dir() {
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ ScopedLocalRef<jclass> activityThreadClass(env, env->FindClass("android/app/ActivityThread"));
+ jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;");
+ ScopedLocalRef<jobject> activityThread(env, env->CallStaticObjectMethod(activityThreadClass, currentActivityThread));
+ jmethodID getApplication = env->GetMethodID(activityThreadClass, "getApplication", "()Landroid/app/Application;");
+ ScopedLocalRef<jobject> ctx(env, env->CallObjectMethod(activityThread, getApplication));
+
+ jmethodID getApplicationInfo = env->GetMethodID(env->GetObjectClass(ctx), "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
+ ScopedLocalRef<jobject> applicationInfo(env, env->CallObjectMethod(ctx, getApplicationInfo));
+ jfieldID nativeLibraryDirField = env->GetFieldID(env->GetObjectClass(applicationInfo), "nativeLibraryDir", "Ljava/lang/String;");
+ ScopedLocalRef<jstring> nativeLibraryDir(env, (jstring)env->GetObjectField(applicationInfo, nativeLibraryDirField));
+
+ String result;
+
+ const char *const nativeLibraryDirUtf8 = env->GetStringUTFChars(nativeLibraryDir, nullptr);
+ if (nativeLibraryDirUtf8) {
+ result.parse_utf8(nativeLibraryDirUtf8);
+ env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDirUtf8);
+ }
+
+ return result;
+}
+
+String get_app_native_lib_dir() {
+ if (app_native_lib_dir_cache.empty())
+ app_native_lib_dir_cache = determine_app_native_lib_dir();
+ return app_native_lib_dir_cache;
+}
+
+int gd_mono_convert_dl_flags(int flags) {
+ // from mono's runtime-bootstrap.c
+
+ int lflags = flags & MONO_DL_LOCAL ? 0 : RTLD_GLOBAL;
+
+ if (flags & MONO_DL_LAZY)
+ lflags |= RTLD_LAZY;
+ else
+ lflags |= RTLD_NOW;
+
+ return lflags;
+}
+
+#ifndef GD_MONO_SO_NAME
+#define GD_MONO_SO_NAME "libmonosgen-2.0.so"
+#endif
+
+const char *mono_so_name = GD_MONO_SO_NAME;
+const char *godot_so_name = "libgodot_android.so";
+
+void *mono_dl_handle = nullptr;
+void *godot_dl_handle = nullptr;
+
+void *try_dlopen(const String &p_so_path, int p_flags) {
+ if (!FileAccess::exists(p_so_path)) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Cannot find shared library: '%s'\n", p_so_path.utf8().get_data());
+ return nullptr;
+ }
+
+ int lflags = gd_mono_convert_dl_flags(p_flags);
+
+ void *handle = dlopen(p_so_path.utf8().get_data(), lflags);
+
+ if (!handle) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", p_so_path.utf8().get_data(), dlerror());
+ return nullptr;
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Successfully loaded shared library: '%s'\n", p_so_path.utf8().get_data());
+
+ return handle;
+}
+
+void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void *p_user_data) {
+ if (p_name == nullptr) {
+ // __Internal
+
+ if (!mono_dl_handle) {
+ String app_native_lib_dir = get_app_native_lib_dir();
+ String so_path = path::join(app_native_lib_dir, mono_so_name);
+
+ mono_dl_handle = try_dlopen(so_path, p_flags);
+ }
+
+ return mono_dl_handle;
+ }
+
+ String name = String::utf8(p_name);
+
+ if (name.ends_with(".dll.so") || name.ends_with(".exe.so")) {
+ String app_native_lib_dir = get_app_native_lib_dir();
+
+ String orig_so_name = name.get_file();
+ String so_name = "lib-aot-" + orig_so_name;
+ String so_path = path::join(app_native_lib_dir, so_name);
+
+ return try_dlopen(so_path, p_flags);
+ }
+
+ return nullptr;
+}
+
+void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, void *p_user_data) {
+ void *sym_addr = dlsym(p_handle, p_name);
+
+ if (sym_addr)
+ return sym_addr;
+
+ if (p_handle == mono_dl_handle && godot_dl_handle) {
+ // Looking up for '__Internal' P/Invoke. We want to search in both the Mono and Godot shared libraries.
+ // This is needed to resolve the monodroid P/Invoke functions that are defined at the bottom of the file.
+ sym_addr = dlsym(godot_dl_handle, p_name);
+
+ if (sym_addr)
+ return sym_addr;
+ }
+
+ if (r_err)
+ *r_err = str_format_new("%s\n", dlerror());
+
+ return nullptr;
+}
+
+void *gd_mono_android_dlclose(void *p_handle, void *p_user_data) {
+ dlclose(p_handle);
+
+ // Not sure if this ever happens. Does Mono close the handle for the main module?
+ if (p_handle == mono_dl_handle)
+ mono_dl_handle = nullptr;
+
+ return nullptr;
+}
+
+int32_t build_version_sdk_int = 0;
+
+int32_t get_build_version_sdk_int() {
+ // The JNI code is the equivalent of:
+ //
+ // android.os.Build.VERSION.SDK_INT
+
+ if (build_version_sdk_int == 0) {
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass versionClass = env->FindClass("android/os/Build$VERSION");
+ ERR_FAIL_NULL_V(versionClass, 0);
+
+ jfieldID sdkIntField = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
+ ERR_FAIL_NULL_V(sdkIntField, 0);
+
+ build_version_sdk_int = (int32_t)env->GetStaticIntField(versionClass, sdkIntField);
+ }
+
+ return build_version_sdk_int;
+}
+
+jobject certStore = nullptr; // KeyStore
+
+MonoBoolean _gd_mono_init_cert_store() {
+ // The JNI code is the equivalent of:
+ //
+ // try {
+ // certStoreLocal = KeyStore.getInstance("AndroidCAStore");
+ // certStoreLocal.load(null);
+ // certStore = certStoreLocal;
+ // return true;
+ // } catch (Exception e) {
+ // return false;
+ // }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore"));
+
+ jmethodID getInstance = env->GetStaticMethodID(keyStoreClass, "getInstance", "(Ljava/lang/String;)Ljava/security/KeyStore;");
+ jmethodID load = env->GetMethodID(keyStoreClass, "load", "(Ljava/security/KeyStore$LoadStoreParameter;)V");
+
+ ScopedLocalRef<jstring> androidCAStoreString(env, env->NewStringUTF("AndroidCAStore"));
+
+ ScopedLocalRef<jobject> certStoreLocal(env, env->CallStaticObjectMethod(keyStoreClass, getInstance, androidCAStoreString.get()));
+
+ if (jni_exception_check(env))
+ return 0;
+
+ env->CallVoidMethod(certStoreLocal, load, nullptr);
+
+ if (jni_exception_check(env))
+ return 0;
+
+ certStore = env->NewGlobalRef(certStoreLocal);
+
+ return 1;
+}
+
+MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
+ // The JNI code is the equivalent of:
+ //
+ // Certificate certificate = certStore.getCertificate(alias);
+ // if (certificate == null)
+ // return null;
+ // return certificate.getEncoded();
+
+ MonoError mono_error;
+ char *alias_utf8 = mono_string_to_utf8_checked(p_alias, &mono_error);
+
+ if (!mono_error_ok(&mono_error)) {
+ ERR_PRINT(String() + "Failed to convert MonoString* to UTF-8: '" + mono_error_get_message(&mono_error) + "'.");
+ mono_error_cleanup(&mono_error);
+ return nullptr;
+ }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ ScopedLocalRef<jstring> js_alias(env, env->NewStringUTF(alias_utf8));
+ mono_free(alias_utf8);
+
+ ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore"));
+ ERR_FAIL_NULL_V(keyStoreClass, nullptr);
+ ScopedLocalRef<jclass> certificateClass(env, env->FindClass("java/security/cert/Certificate"));
+ ERR_FAIL_NULL_V(certificateClass, nullptr);
+
+ jmethodID getCertificate = env->GetMethodID(keyStoreClass, "getCertificate", "(Ljava/lang/String;)Ljava/security/cert/Certificate;");
+ ERR_FAIL_NULL_V(getCertificate, nullptr);
+
+ jmethodID getEncoded = env->GetMethodID(certificateClass, "getEncoded", "()[B");
+ ERR_FAIL_NULL_V(getEncoded, nullptr);
+
+ ScopedLocalRef<jobject> certificate(env, env->CallObjectMethod(certStore, getCertificate, js_alias.get()));
+
+ if (!certificate)
+ return nullptr;
+
+ ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded));
+ jsize encodedLength = env->GetArrayLength(encoded);
+
+ MonoArray *encoded_ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), encodedLength);
+ uint8_t *dest = (uint8_t *)mono_array_addr(encoded_ret, uint8_t, 0);
+
+ env->GetByteArrayRegion(encoded, 0, encodedLength, reinterpret_cast<jbyte *>(dest));
+
+ return encoded_ret;
+}
+
+void register_internal_calls() {
+ mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_init_cert_store", (void *)_gd_mono_init_cert_store);
+ mono_add_internal_call("Android.Runtime.AndroidEnvironment::_gd_mono_android_cert_store_lookup", (void *)_gd_mono_android_cert_store_lookup);
+}
+
+void initialize() {
+ // We need to set this environment variable to make the monodroid BCL use btls instead of legacy as the default provider
+ OS::get_singleton()->set_environment("XA_TLS_PROVIDER", "btls");
+
+ mono_dl_fallback_register(gd_mono_android_dlopen, gd_mono_android_dlsym, gd_mono_android_dlclose, nullptr);
+
+ String app_native_lib_dir = get_app_native_lib_dir();
+ String so_path = path::join(app_native_lib_dir, godot_so_name);
+
+ godot_dl_handle = try_dlopen(so_path, gd_mono_convert_dl_flags(MONO_DL_LAZY));
+}
+
+void cleanup() {
+ // This is called after shutting down the Mono runtime
+
+ if (mono_dl_handle)
+ gd_mono_android_dlclose(mono_dl_handle, nullptr);
+
+ if (godot_dl_handle)
+ gd_mono_android_dlclose(godot_dl_handle, nullptr);
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ if (certStore) {
+ env->DeleteGlobalRef(certStore);
+ certStore = nullptr;
+ }
+}
+
+} // namespace support
+} // namespace android
+} // namespace gdmono
+
+using namespace gdmono::android::support;
+
+// The following are P/Invoke functions required by the monodroid profile of the BCL.
+// These are P/Invoke functions and not internal calls, hence why they use
+// 'mono_bool' and 'const char*' instead of 'MonoBoolean' and 'MonoString*'.
+
+#define GD_PINVOKE_EXPORT extern "C" __attribute__((visibility("default")))
+
+GD_PINVOKE_EXPORT int32_t _monodroid_get_android_api_level() {
+ return get_build_version_sdk_int();
+}
+
+GD_PINVOKE_EXPORT void monodroid_free(void *ptr) {
+ free(ptr);
+}
+
+GD_PINVOKE_EXPORT int32_t monodroid_get_system_property(const char *p_name, char **r_value) {
+ char prop_value_str[PROP_VALUE_MAX + 1] = { 0 };
+
+ int len = __system_property_get(p_name, prop_value_str);
+
+ if (r_value) {
+ if (len >= 0) {
+ *r_value = (char *)malloc(len + 1);
+ if (!*r_value)
+ return -1;
+ memcpy(*r_value, prop_value_str, len);
+ (*r_value)[len] = '\0';
+ } else {
+ *r_value = nullptr;
+ }
+ }
+
+ return len;
+}
+
+GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char *p_ifname, mono_bool *r_is_up) {
+ // The JNI code is the equivalent of:
+ //
+ // NetworkInterface.getByName(p_ifname).isUp()
+
+ if (!r_is_up || !p_ifname || strlen(p_ifname) == 0)
+ return 0;
+
+ *r_is_up = 0;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface");
+ ERR_FAIL_NULL_V(networkInterfaceClass, 0);
+
+ jmethodID getByName = env->GetStaticMethodID(networkInterfaceClass, "getByName", "(Ljava/lang/String;)Ljava/net/NetworkInterface;");
+ ERR_FAIL_NULL_V(getByName, 0);
+
+ jmethodID isUp = env->GetMethodID(networkInterfaceClass, "isUp", "()Z");
+ ERR_FAIL_NULL_V(isUp, 0);
+
+ ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname));
+ ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get()));
+
+ if (!networkInterface)
+ return 0;
+
+ *r_is_up = (mono_bool)env->CallBooleanMethod(networkInterface, isUp);
+
+ return 1;
+}
+
+GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast(const char *p_ifname, mono_bool *r_supports_multicast) {
+ // The JNI code is the equivalent of:
+ //
+ // NetworkInterface.getByName(p_ifname).supportsMulticast()
+
+ if (!r_supports_multicast || !p_ifname || strlen(p_ifname) == 0)
+ return 0;
+
+ *r_supports_multicast = 0;
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface");
+ ERR_FAIL_NULL_V(networkInterfaceClass, 0);
+
+ jmethodID getByName = env->GetStaticMethodID(networkInterfaceClass, "getByName", "(Ljava/lang/String;)Ljava/net/NetworkInterface;");
+ ERR_FAIL_NULL_V(getByName, 0);
+
+ jmethodID supportsMulticast = env->GetMethodID(networkInterfaceClass, "supportsMulticast", "()Z");
+ ERR_FAIL_NULL_V(supportsMulticast, 0);
+
+ ScopedLocalRef<jstring> js_ifname(env, env->NewStringUTF(p_ifname));
+ ScopedLocalRef<jobject> networkInterface(env, env->CallStaticObjectMethod(networkInterfaceClass, getByName, js_ifname.get()));
+
+ if (!networkInterface)
+ return 0;
+
+ *r_supports_multicast = (mono_bool)env->CallBooleanMethod(networkInterface, supportsMulticast);
+
+ return 1;
+}
+
+static const int dns_servers_len = 8;
+
+static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dns_servers_count) {
+ // The JNI code is the equivalent of:
+ //
+ // ConnectivityManager connectivityManager = (ConnectivityManager)getApplicationContext()
+ // .getSystemService(Context.CONNECTIVITY_SERVICE);
+ // Network activeNerwork = connectivityManager.getActiveNetwork();
+ // LinkProperties linkProperties = connectivityManager.getLinkProperties(activeNerwork);
+ // List<String> dnsServers = linkProperties.getDnsServers().stream()
+ // .map(inetAddress -> inetAddress.getHostAddress()).collect(Collectors.toList());
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(get_build_version_sdk_int() < 23);
+#endif
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ GodotJavaWrapper *godot_java = ((OS_Android *)OS::get_singleton())->get_godot_java();
+ jobject activity = godot_java->get_activity();
+
+ ScopedLocalRef<jclass> activityClass(env, env->GetObjectClass(activity));
+ ERR_FAIL_NULL(activityClass);
+
+ jmethodID getApplicationContext = env->GetMethodID(activityClass, "getApplicationContext", "()Landroid/content/Context;");
+
+ ScopedLocalRef<jobject> applicationContext(env, env->CallObjectMethod(activity, getApplicationContext));
+
+ ScopedLocalRef<jclass> contextClass(env, env->FindClass("android/content/Context"));
+ ERR_FAIL_NULL(contextClass);
+
+ jfieldID connectivityServiceField = env->GetStaticFieldID(contextClass, "CONNECTIVITY_SERVICE", "Ljava/lang/String;");
+ ScopedLocalRef<jstring> connectivityServiceString(env, (jstring)env->GetStaticObjectField(contextClass, connectivityServiceField));
+
+ jmethodID getSystemService = env->GetMethodID(contextClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+
+ ScopedLocalRef<jobject> connectivityManager(env, env->CallObjectMethod(applicationContext, getSystemService, connectivityServiceString.get()));
+
+ if (!connectivityManager)
+ return;
+
+ ScopedLocalRef<jclass> connectivityManagerClass(env, env->FindClass("android/net/ConnectivityManager"));
+ ERR_FAIL_NULL(connectivityManagerClass);
+
+ jmethodID getActiveNetwork = env->GetMethodID(connectivityManagerClass, "getActiveNetwork", "()Landroid/net/Network;");
+ ERR_FAIL_NULL(getActiveNetwork);
+
+ ScopedLocalRef<jobject> activeNetwork(env, env->CallObjectMethod(connectivityManager, getActiveNetwork));
+
+ if (!activeNetwork)
+ return;
+
+ jmethodID getLinkProperties = env->GetMethodID(connectivityManagerClass,
+ "getLinkProperties", "(Landroid/net/Network;)Landroid/net/LinkProperties;");
+ ERR_FAIL_NULL(getLinkProperties);
+
+ ScopedLocalRef<jobject> linkProperties(env, env->CallObjectMethod(connectivityManager, getLinkProperties, activeNetwork.get()));
+
+ if (!linkProperties)
+ return;
+
+ ScopedLocalRef<jclass> linkPropertiesClass(env, env->FindClass("android/net/LinkProperties"));
+ ERR_FAIL_NULL(linkPropertiesClass);
+
+ jmethodID getDnsServers = env->GetMethodID(linkPropertiesClass, "getDnsServers", "()Ljava/util/List;");
+ ERR_FAIL_NULL(getDnsServers);
+
+ ScopedLocalRef<jobject> dnsServers(env, env->CallObjectMethod(linkProperties, getDnsServers));
+
+ if (!dnsServers)
+ return;
+
+ ScopedLocalRef<jclass> listClass(env, env->FindClass("java/util/List"));
+ ERR_FAIL_NULL(listClass);
+
+ jmethodID listSize = env->GetMethodID(listClass, "size", "()I");
+ ERR_FAIL_NULL(listSize);
+
+ int dnsServersCount = env->CallIntMethod(dnsServers, listSize);
+
+ if (dnsServersCount > dns_servers_len)
+ dnsServersCount = dns_servers_len;
+
+ if (dnsServersCount <= 0)
+ return;
+
+ jmethodID listGet = env->GetMethodID(listClass, "get", "(I)Ljava/lang/Object;");
+ ERR_FAIL_NULL(listGet);
+
+ ScopedLocalRef<jclass> inetAddressClass(env, env->FindClass("java/net/InetAddress"));
+ ERR_FAIL_NULL(inetAddressClass);
+
+ jmethodID getHostAddress = env->GetMethodID(inetAddressClass, "getHostAddress", "()Ljava/lang/String;");
+ ERR_FAIL_NULL(getHostAddress);
+
+ for (int i = 0; i < dnsServersCount; i++) {
+ ScopedLocalRef<jobject> dnsServer(env, env->CallObjectMethod(dnsServers, listGet, (jint)i));
+ if (!dnsServer)
+ continue;
+
+ ScopedLocalRef<jstring> hostAddress(env, (jstring)env->CallObjectMethod(dnsServer, getHostAddress));
+ const char *host_address = env->GetStringUTFChars(hostAddress, 0);
+
+ r_dns_servers[i] = strdup(host_address); // freed by the BCL
+ (*dns_servers_count)++;
+
+ env->ReleaseStringUTFChars(hostAddress, host_address);
+ }
+
+ // jesus...
+}
+
+GD_PINVOKE_EXPORT int32_t _monodroid_get_dns_servers(void **r_dns_servers_array) {
+ if (!r_dns_servers_array)
+ return -1;
+
+ *r_dns_servers_array = nullptr;
+
+ char *dns_servers[dns_servers_len];
+ int dns_servers_count = 0;
+
+ if (_monodroid_get_android_api_level() < 26) {
+ // The 'net.dns*' system properties are no longer available in Android 8.0 (API level 26) and greater:
+ // https://developer.android.com/about/versions/oreo/android-8.0-changes.html#o-pri
+
+ char prop_name[] = "net.dns*";
+
+ for (int i = 0; i < dns_servers_len; i++) {
+ prop_name[7] = (char)(i + 0x31);
+ char *prop_value;
+ int32_t len = monodroid_get_system_property(prop_name, &prop_value);
+
+ if (len > 0) {
+ dns_servers[dns_servers_count] = strndup(prop_value, (size_t)len); // freed by the BCL
+ dns_servers_count++;
+ free(prop_value);
+ }
+ }
+ } else {
+ // Alternative for Oreo and greater
+ interop_get_active_network_dns_servers(dns_servers, &dns_servers_count);
+ }
+
+ 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
+ memcpy(*r_dns_servers_array, dns_servers, ret_size);
+ }
+
+ return dns_servers_count;
+}
+
+GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() {
+ // The JNI code is the equivalent of:
+ //
+ // TimeZone.getDefault().getID()
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ ScopedLocalRef<jclass> timeZoneClass(env, env->FindClass("java/util/TimeZone"));
+ ERR_FAIL_NULL_V(timeZoneClass, nullptr);
+
+ jmethodID getDefault = env->GetStaticMethodID(timeZoneClass, "getDefault", "()Ljava/util/TimeZone;");
+ ERR_FAIL_NULL_V(getDefault, nullptr);
+
+ jmethodID getID = env->GetMethodID(timeZoneClass, "getID", "()Ljava/lang/String;");
+ ERR_FAIL_NULL_V(getID, nullptr);
+
+ ScopedLocalRef<jobject> defaultTimeZone(env, env->CallStaticObjectMethod(timeZoneClass, getDefault));
+
+ if (!defaultTimeZone)
+ return nullptr;
+
+ ScopedLocalRef<jstring> defaultTimeZoneID(env, (jstring)env->CallObjectMethod(defaultTimeZone, getID));
+
+ if (!defaultTimeZoneID)
+ return nullptr;
+
+ const char *default_time_zone_id = env->GetStringUTFChars(defaultTimeZoneID, 0);
+
+ char *result = strdup(default_time_zone_id); // freed by the BCL
+
+ env->ReleaseStringUTFChars(defaultTimeZoneID, default_time_zone_id);
+
+ return result;
+}
+
+GD_PINVOKE_EXPORT int32_t _monodroid_getifaddrs(struct ifaddrs **p_ifap) {
+ return getifaddrs(p_ifap);
+}
+
+GD_PINVOKE_EXPORT void _monodroid_freeifaddrs(struct ifaddrs *p_ifap) {
+ freeifaddrs(p_ifap);
+}
+
+#endif
diff --git a/modules/mono/mono_gd/support/android_support.h b/modules/mono/mono_gd/support/android_support.h
new file mode 100755
index 0000000000..dc2e6c95ed
--- /dev/null
+++ b/modules/mono/mono_gd/support/android_support.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* android_support.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 ANDROID_SUPPORT_H
+#define ANDROID_SUPPORT_H
+
+#if defined(ANDROID_ENABLED)
+
+#include "core/ustring.h"
+
+namespace gdmono {
+namespace android {
+namespace support {
+
+String get_app_native_lib_dir();
+
+void initialize();
+void cleanup();
+
+void register_internal_calls();
+
+} // namespace support
+} // namespace android
+} // namespace gdmono
+
+#endif // ANDROID_ENABLED
+
+#endif // ANDROID_SUPPORT_H
diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h
new file mode 100755
index 0000000000..e28af120e3
--- /dev/null
+++ b/modules/mono/mono_gd/support/ios_support.h
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* ios_support.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 IOS_SUPPORT_H
+#define IOS_SUPPORT_H
+
+#if defined(IPHONE_ENABLED)
+
+#include "core/ustring.h"
+
+namespace gdmono {
+namespace ios {
+namespace support {
+
+void initialize();
+void cleanup();
+
+} // namespace support
+} // namespace ios
+} // namespace gdmono
+
+#endif // IPHONE_ENABLED
+
+#endif // IOS_SUPPORT_H
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
new file mode 100755
index 0000000000..e3d1a647fd
--- /dev/null
+++ b/modules/mono/mono_gd/support/ios_support.mm
@@ -0,0 +1,151 @@
+/*************************************************************************/
+/* ios_support.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "ios_support.h"
+
+#if defined(IPHONE_ENABLED)
+
+#import <Foundation/Foundation.h>
+#include <os/log.h>
+
+#include "core/ustring.h"
+
+#include "../gd_mono_marshal.h"
+
+// Implemented mostly following: https://github.com/mono/mono/blob/master/sdks/ios/app/runtime.m
+
+// Definition generated by the Godot exporter
+extern "C" void gd_mono_setup_aot();
+
+namespace gdmono {
+namespace ios {
+namespace support {
+
+void ios_mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
+ os_log_info(OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message);
+ if (fatal) {
+ os_log_info(OS_LOG_DEFAULT, "Exit code: %d.", 1);
+ exit(1);
+ }
+}
+
+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);
+
+#ifdef IOS_DEVICE
+ // This function is defined in an auto-generated source file
+ gd_mono_setup_aot();
+#endif
+
+ mono_set_signal_chaining(true);
+ mono_set_crash_chaining(true);
+}
+
+void cleanup() {
+}
+
+} // namespace support
+} // namespace ios
+} // namespace gdmono
+
+// The following are P/Invoke functions required by the monotouch profile of the BCL.
+// These are P/Invoke functions and not internal calls, hence why they use
+// 'mono_bool' and 'const char*' instead of 'MonoBoolean' and 'MonoString*'.
+
+#define GD_PINVOKE_EXPORT extern "C" __attribute__((visibility("default")))
+
+GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() {
+ NSLocale *locale = [NSLocale currentLocale];
+ NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
+ if (countryCode == NULL) {
+ return strdup("US");
+ }
+ return strdup([countryCode UTF8String]);
+}
+
+GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) {
+ int length = 0;
+ const uint16_t *ptr = p_unicode_message;
+ while (*ptr++)
+ length += sizeof(uint16_t);
+ NSString *msg = [[NSString alloc] initWithBytes:p_unicode_message length:length encoding:NSUTF16LittleEndianStringEncoding];
+
+ os_log_info(OS_LOG_DEFAULT, "%{public}@", msg);
+}
+
+GD_PINVOKE_EXPORT const char *xamarin_GetFolderPath(int p_folder) {
+ NSSearchPathDirectory dd = (NSSearchPathDirectory)p_folder;
+ NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:dd inDomains:NSUserDomainMask] lastObject];
+ NSString *path = [url path];
+ return strdup([path UTF8String]);
+}
+
+GD_PINVOKE_EXPORT char *xamarin_timezone_get_local_name() {
+ NSTimeZone *tz = nil;
+ tz = [NSTimeZone localTimeZone];
+ NSString *name = [tz name];
+ return (name != nil) ? strdup([name UTF8String]) : strdup("Local");
+}
+
+GD_PINVOKE_EXPORT char **xamarin_timezone_get_names(uint32_t *p_count) {
+ NSArray *array = [NSTimeZone knownTimeZoneNames];
+ *p_count = array.count;
+ char **result = (char **)malloc(sizeof(char *) * (*p_count));
+ for (uint32_t i = 0; i < *p_count; i++) {
+ NSString *s = [array objectAtIndex:i];
+ result[i] = strdup(s.UTF8String);
+ }
+ return result;
+}
+
+GD_PINVOKE_EXPORT void *xamarin_timezone_get_data(const char *p_name, uint32_t *p_size) { // FIXME: uint32_t since Dec 2019, unsigned long before
+ NSTimeZone *tz = nil;
+ if (p_name) {
+ NSString *n = [[NSString alloc] initWithUTF8String:p_name];
+ tz = [[[NSTimeZone alloc] initWithName:n] autorelease];
+ [n release];
+ } else {
+ tz = [NSTimeZone localTimeZone];
+ }
+ NSData *data = [tz data];
+ *p_size = [data length];
+ void *result = malloc(*p_size);
+ memcpy(result, data.bytes, *p_size);
+ return result;
+}
+
+GD_PINVOKE_EXPORT void xamarin_start_wwan(const char *p_uri) {
+ // FIXME: What's this for? No idea how to implement.
+ os_log_error(OS_LOG_DEFAULT, "Not implemented: 'xamarin_start_wwan'");
+}
+
+#endif // IPHONE_ENABLED
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 4823ba3679..94431e7c30 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -34,11 +34,11 @@
#include "csharp_script.h"
-CSharpLanguage *script_language_cs = NULL;
+CSharpLanguage *script_language_cs = nullptr;
Ref<ResourceFormatLoaderCSharpScript> resource_loader_cs;
Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
-_GodotSharp *_godotsharp = NULL;
+_GodotSharp *_godotsharp = nullptr;
void register_mono_types() {
ClassDB::register_class<CSharpScript>();
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 718bc2bb93..e77a2e98f2 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -36,103 +36,192 @@
#include "mono_gd/gd_mono_marshal.h"
#include "mono_gd/gd_mono_utils.h"
-namespace SignalAwaiterUtils {
-
-Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p_target, MonoObject *p_awaiter) {
-
+Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter) {
ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA);
- Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(p_awaiter));
-#ifdef DEBUG_ENABLED
- sa_con->set_connection_target(p_target);
-#endif
+ // TODO: Use pooling for ManagedCallable instances.
+ SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, p_awaiter, p_signal));
+ Callable callable = Callable(awaiter_callable);
+
+ return p_source->connect(p_signal, callable, Vector<Variant>(), Object::CONNECT_ONESHOT);
+}
+
+bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a);
+ const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b);
- Vector<Variant> binds;
- binds.push_back(sa_con);
+ if (a->target_id != b->target_id)
+ return false;
+
+ if (a->signal != b->signal)
+ return false;
+
+ return true;
+}
+
+bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ if (compare_equal(p_a, p_b))
+ return false;
+ return p_a < p_b;
+}
+
+uint32_t SignalAwaiterCallable::hash() const {
+ uint32_t hash = signal.hash();
+ return hash_djb2_one_64(target_id, hash);
+}
- Error err = p_source->connect_compat(p_signal, sa_con.ptr(),
- CSharpLanguage::get_singleton()->get_string_names()._signal_callback,
- binds, Object::CONNECT_ONESHOT);
+String SignalAwaiterCallable::get_as_text() const {
+ Object *base = ObjectDB::get_instance(target_id);
+ if (base) {
+ String class_name = base->get_class();
+ Ref<Script> script = base->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
- if (err != OK) {
- // Set it as completed to prevent it from calling the failure callback when released.
- // The awaiter will be aware of the failure by checking the returned error.
- sa_con->set_completed(true);
+ class_name += "(" + script->get_path().get_file() + ")";
+ }
+ return class_name + "::SignalAwaiterMiddleman::" + String(signal);
+ } else {
+ return "null::SignalAwaiterMiddleman::" + String(signal);
}
+}
- return err;
+CallableCustom::CompareEqualFunc SignalAwaiterCallable::get_compare_equal_func() const {
+ return compare_equal_func_ptr;
}
-} // namespace SignalAwaiterUtils
-Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+CallableCustom::CompareLessFunc SignalAwaiterCallable::get_compare_less_func() const {
+ return compare_less_func_ptr;
+}
+
+ObjectID SignalAwaiterCallable::get_object() const {
+ return target_id;
+}
+
+void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
+ r_return_value = Variant();
#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(conn_target_id.is_valid() && !ObjectDB::get_instance(conn_target_id), Variant(),
+ ERR_FAIL_COND_MSG(target_id.is_valid() && !ObjectDB::get_instance(target_id),
"Resumed after await, but class instance is gone.");
#endif
- if (p_argcount < 1) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- return Variant();
- }
+ MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
- Ref<SignalAwaiterHandle> self = *p_args[p_argcount - 1];
-
- if (self.is_null()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = p_argcount - 1;
- r_error.expected = Variant::OBJECT;
- return Variant();
+ for (int i = 0; i < p_argcount; i++) {
+ MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
+ mono_array_setref(signal_args, i, boxed);
}
- set_completed(true);
-
- int signal_argc = p_argcount - 1;
- MonoArray *signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), signal_argc);
+ MonoObject *awaiter = awaiter_handle.get_target();
- for (int i = 0; i < signal_argc; i++) {
- MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]);
- mono_array_setref(signal_args, i, boxed);
+ if (!awaiter) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
}
- MonoException *exc = NULL;
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback).invoke(get_target(), signal_args, &exc);
- GD_MONO_END_RUNTIME_INVOKE;
+ MonoException *exc = nullptr;
+ CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback).invoke(awaiter, signal_args, &exc);
if (exc) {
GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL_V(Variant());
+ ERR_FAIL();
+ } else {
+ r_call_error.error = Callable::CallError::CALL_OK;
}
+}
- return Variant();
+SignalAwaiterCallable::SignalAwaiterCallable(Object *p_target, MonoObject *p_awaiter, const StringName &p_signal) :
+ target_id(p_target->get_instance_id()),
+ awaiter_handle(MonoGCHandleData::new_strong_handle(p_awaiter)),
+ signal(p_signal) {
}
-void SignalAwaiterHandle::_bind_methods() {
+SignalAwaiterCallable::~SignalAwaiterCallable() {
+ awaiter_handle.release();
+}
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &SignalAwaiterHandle::_signal_callback, MethodInfo("_signal_callback"));
+bool EventSignalCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const EventSignalCallable *a = static_cast<const EventSignalCallable *>(p_a);
+ const EventSignalCallable *b = static_cast<const EventSignalCallable *>(p_b);
+
+ if (a->owner != b->owner)
+ return false;
+
+ if (a->event_signal != b->event_signal)
+ return false;
+
+ return true;
}
-SignalAwaiterHandle::SignalAwaiterHandle(MonoObject *p_managed) :
- MonoGCHandle(MonoGCHandle::new_strong_handle(p_managed), STRONG_HANDLE) {}
+bool EventSignalCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ if (compare_equal(p_a, p_b))
+ return false;
+ return p_a < p_b;
+}
-SignalAwaiterHandle::~SignalAwaiterHandle() {
+uint32_t EventSignalCallable::hash() const {
+ uint32_t hash = event_signal->field->get_name().hash();
+ return hash_djb2_one_64(owner->get_instance_id(), hash);
+}
- if (!completed) {
- MonoObject *awaiter = get_target();
+String EventSignalCallable::get_as_text() const {
+ String class_name = owner->get_class();
+ Ref<Script> script = owner->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
+ class_name += "(" + script->get_path().get_file() + ")";
+ }
+ StringName signal = event_signal->field->get_name();
+ return class_name + "::EventSignalMiddleman::" + String(signal);
+}
- if (awaiter) {
- MonoException *exc = NULL;
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback).invoke(awaiter, &exc);
- GD_MONO_END_RUNTIME_INVOKE;
+CallableCustom::CompareEqualFunc EventSignalCallable::get_compare_equal_func() const {
+ return compare_equal_func_ptr;
+}
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL();
- }
- }
+CallableCustom::CompareLessFunc EventSignalCallable::get_compare_less_func() const {
+ return compare_less_func_ptr;
+}
+
+ObjectID EventSignalCallable::get_object() const {
+ return owner->get_instance_id();
+}
+
+StringName EventSignalCallable::get_signal() const {
+ return event_signal->field->get_name();
+}
+
+void EventSignalCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
+ r_return_value = Variant();
+
+ ERR_FAIL_COND(p_argcount < event_signal->invoke_method->get_parameters_count());
+
+ CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(owner->get_script_instance());
+ ERR_FAIL_NULL(csharp_instance);
+
+ MonoObject *owner_managed = csharp_instance->get_mono_object();
+ ERR_FAIL_NULL(owner_managed);
+
+ MonoObject *delegate_field_value = event_signal->field->get_value(owner_managed);
+ if (!delegate_field_value) {
+ r_call_error.error = Callable::CallError::CALL_OK;
+ return;
}
+
+ MonoException *exc = nullptr;
+ event_signal->invoke_method->invoke(delegate_field_value, p_arguments, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ ERR_FAIL();
+ } else {
+ r_call_error.error = Callable::CallError::CALL_OK;
+ }
+}
+
+EventSignalCallable::EventSignalCallable(Object *p_owner, const CSharpScript::EventSignal *p_event_signal) :
+ owner(p_owner),
+ event_signal(p_event_signal) {
}
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 012f6e5bb3..c550315a23 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -32,40 +32,66 @@
#define SIGNAL_AWAITER_UTILS_H
#include "core/reference.h"
+
+#include "csharp_script.h"
#include "mono_gc_handle.h"
-namespace SignalAwaiterUtils {
+Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter);
+
+class SignalAwaiterCallable : public CallableCustom {
+ ObjectID target_id;
+ MonoGCHandleData awaiter_handle;
+ StringName signal;
+
+public:
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
-Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p_target, MonoObject *p_awaiter);
-}
+ static constexpr CompareEqualFunc compare_equal_func_ptr = &SignalAwaiterCallable::compare_equal;
+ static constexpr CompareEqualFunc compare_less_func_ptr = &SignalAwaiterCallable::compare_less;
-class SignalAwaiterHandle : public MonoGCHandle {
+ uint32_t hash() const override;
- GDCLASS(SignalAwaiterHandle, MonoGCHandle);
+ String get_as_text() const override;
- bool completed;
+ CompareEqualFunc get_compare_equal_func() const override;
+ CompareLessFunc get_compare_less_func() const override;
-#ifdef DEBUG_ENABLED
- ObjectID conn_target_id;
-#endif
+ ObjectID get_object() const override;
- Variant _signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ _FORCE_INLINE_ StringName get_signal() const { return signal; }
+
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+
+ SignalAwaiterCallable(Object *p_target, MonoObject *p_awaiter, const StringName &p_signal);
+ ~SignalAwaiterCallable();
+};
-protected:
- static void _bind_methods();
+class EventSignalCallable : public CallableCustom {
+ Object *owner;
+ const CSharpScript::EventSignal *event_signal;
public:
- _FORCE_INLINE_ bool is_completed() { return completed; }
- _FORCE_INLINE_ void set_completed(bool p_completed) { completed = p_completed; }
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
+
+ static constexpr CompareEqualFunc compare_equal_func_ptr = &EventSignalCallable::compare_equal;
+ static constexpr CompareEqualFunc compare_less_func_ptr = &EventSignalCallable::compare_less;
+
+ 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;
+
+ StringName get_signal() const;
-#ifdef DEBUG_ENABLED
- _FORCE_INLINE_ void set_connection_target(Object *p_target) {
- conn_target_id = p_target->get_instance_id();
- }
-#endif
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- SignalAwaiterHandle(MonoObject *p_managed);
- ~SignalAwaiterHandle();
+ EventSignalCallable(Object *p_owner, const CSharpScript::EventSignal *p_event_signal);
};
#endif // SIGNAL_AWAITER_UTILS_H
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index 754000dc14..8650d6cc09 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -36,38 +36,6 @@
#define _GD_VARNAME_CONCAT_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c)
#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT_(m_name, _, __COUNTER__)
-// static assert
-// TODO: Get rid of this macro once we upgrade to C++11
-
-#ifdef __cpp_static_assert
-#define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed")
-#else
-#define GD_STATIC_ASSERT(m_cond) typedef int GD_UNIQUE_NAME(godot_static_assert)[((m_cond) ? 1 : -1)]
-#endif
-
-// final
-// TODO: Get rid of this macro once we upgrade to C++11
-
-#if (__cplusplus >= 201103L)
-#define GD_FINAL final
-#else
-#define GD_FINAL
-#endif
-
-// noreturn
-// TODO: Get rid of this macro once we upgrade to C++11
-
-#if (__cplusplus >= 201103L)
-#define GD_NORETURN [[noreturn]]
-#elif defined(__GNUC__)
-#define GD_NORETURN __attribute__((noreturn))
-#elif defined(_MSC_VER)
-#define GD_NORETURN __declspec(noreturn)
-#else
-#define GD_NORETURN
-#pragma message "Macro GD_NORETURN will have no effect"
-#endif
-
// unreachable
#if defined(_MSC_VER)
@@ -81,4 +49,25 @@
} while (true);
#endif
+namespace gdmono {
+
+template <typename F>
+struct ScopeExit {
+ ScopeExit(F p_exit_func) :
+ exit_func(p_exit_func) {}
+ ~ScopeExit() { exit_func(); }
+ F exit_func;
+};
+
+class ScopeExitAux {
+public:
+ template <typename F>
+ ScopeExit<F> operator+(F p_exit_func) { return ScopeExit<F>(p_exit_func); }
+};
+
+} // namespace gdmono
+
+#define SCOPE_EXIT \
+ auto GD_UNIQUE_NAME(gd_scope_exit) = gdmono::ScopeExitAux() + [=]()
+
#endif // UTIL_MACROS_H
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index c1cd5f1db4..8f0ad8ba5e 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -73,13 +73,13 @@ LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value)
buffer.resize(512);
DWORD dwBufferSize = buffer.size();
- LONG res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, NULL, (LPBYTE)buffer.ptr(), &dwBufferSize);
+ LONG res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
if (res == ERROR_MORE_DATA) {
// dwBufferSize now contains the actual size
Vector<WCHAR> buffer;
buffer.resize(dwBufferSize);
- res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, NULL, (LPBYTE)buffer.ptr(), &dwBufferSize);
+ res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
}
if (res == ERROR_SUCCESS) {
@@ -180,7 +180,7 @@ String find_msbuild_tools_path() {
String output;
int exit_code;
- OS::get_singleton()->execute(vswhere_path, vswhere_args, true, NULL, &output, &exit_code);
+ OS::get_singleton()->execute(vswhere_path, vswhere_args, true, nullptr, &output, &exit_code);
if (exit_code == 0) {
Vector<String> lines = output.split("\n");
diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp
index 432b306414..8fadf3c109 100644
--- a/modules/mono/utils/osx_utils.cpp
+++ b/modules/mono/utils/osx_utils.cpp
@@ -39,9 +39,9 @@
bool osx_is_app_bundle_installed(const String &p_bundle_id) {
- CFURLRef app_url = NULL;
- CFStringRef bundle_id = CFStringCreateWithCString(NULL, p_bundle_id.utf8(), kCFStringEncodingUTF8);
- OSStatus result = LSFindApplicationForInfo(kLSUnknownCreator, bundle_id, NULL, NULL, &app_url);
+ CFURLRef app_url = nullptr;
+ CFStringRef bundle_id = CFStringCreateWithCString(nullptr, p_bundle_id.utf8(), kCFStringEncodingUTF8);
+ OSStatus result = LSFindApplicationForInfo(kLSUnknownCreator, bundle_id, nullptr, nullptr, &app_url);
CFRelease(bundle_id);
if (app_url)
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index 545da6c79e..973375a471 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -80,7 +80,7 @@ String find_executable(const String &p_name) {
String cwd() {
#ifdef WINDOWS_ENABLED
- const DWORD expected_size = ::GetCurrentDirectoryW(0, NULL);
+ const DWORD expected_size = ::GetCurrentDirectoryW(0, nullptr);
String buffer;
buffer.resize((int)expected_size);
@@ -90,7 +90,7 @@ String cwd() {
return buffer.simplify_path();
#else
char buffer[PATH_MAX];
- if (::getcwd(buffer, sizeof(buffer)) == NULL)
+ if (::getcwd(buffer, sizeof(buffer)) == nullptr)
return ".";
String result;
@@ -114,12 +114,12 @@ String realpath(const String &p_path) {
// Open file without read/write access
HANDLE hFile = ::CreateFileW(p_path.c_str(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE)
return p_path;
- const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, NULL, 0, FILE_NAME_NORMALIZED);
+ const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, FILE_NAME_NORMALIZED);
if (expected_size == 0) {
::CloseHandle(hFile);
@@ -133,7 +133,7 @@ String realpath(const String &p_path) {
::CloseHandle(hFile);
return buffer.simplify_path();
#elif UNIX_ENABLED
- char *resolved_path = ::realpath(p_path.utf8().get_data(), NULL);
+ char *resolved_path = ::realpath(p_path.utf8().get_data(), nullptr);
if (!resolved_path)
return p_path;
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 49c4fb3f73..907811355f 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -212,7 +212,7 @@ String str_format(const char *p_format, ...) {
#define gd_vscprintf(m_format, m_args_copy) _vscprintf(m_format, m_args_copy)
#else
#define gd_vsnprintf(m_buffer, m_count, m_format, m_args_copy) vsnprintf(m_buffer, m_count, m_format, m_args_copy)
-#define gd_vscprintf(m_format, m_args_copy) vsnprintf(NULL, 0, p_format, m_args_copy)
+#define gd_vscprintf(m_format, m_args_copy) vsnprintf(nullptr, 0, p_format, m_args_copy)
#endif
String str_format(const char *p_format, va_list p_list) {
diff --git a/modules/mono/utils/thread_local.cpp b/modules/mono/utils/thread_local.cpp
deleted file mode 100644
index 4f10e3fb85..0000000000
--- a/modules/mono/utils/thread_local.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*************************************************************************/
-/* thread_local.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "thread_local.h"
-
-#ifdef WINDOWS_ENABLED
-#include <windows.h>
-#else
-#include <pthread.h>
-#endif
-
-#include "core/os/memory.h"
-#include "core/print_string.h"
-
-struct ThreadLocalStorage::Impl {
-
-#ifdef WINDOWS_ENABLED
- DWORD dwFlsIndex;
-#else
- pthread_key_t key;
-#endif
-
- void *get_value() const {
-#ifdef WINDOWS_ENABLED
- return FlsGetValue(dwFlsIndex);
-#else
- return pthread_getspecific(key);
-#endif
- }
-
- void set_value(void *p_value) const {
-#ifdef WINDOWS_ENABLED
- FlsSetValue(dwFlsIndex, p_value);
-#else
- pthread_setspecific(key, p_value);
-#endif
- }
-
-#ifdef WINDOWS_ENABLED
-#define _CALLBACK_FUNC_ __stdcall
-#else
-#define _CALLBACK_FUNC_
-#endif
-
- Impl(void(_CALLBACK_FUNC_ *p_destr_callback_func)(void *)) {
-#ifdef WINDOWS_ENABLED
- dwFlsIndex = FlsAlloc(p_destr_callback_func);
- ERR_FAIL_COND(dwFlsIndex == FLS_OUT_OF_INDEXES);
-#else
- pthread_key_create(&key, p_destr_callback_func);
-#endif
- }
-
- ~Impl() {
-#ifdef WINDOWS_ENABLED
- FlsFree(dwFlsIndex);
-#else
- pthread_key_delete(key);
-#endif
- }
-};
-
-void *ThreadLocalStorage::get_value() const {
- return pimpl->get_value();
-}
-
-void ThreadLocalStorage::set_value(void *p_value) const {
- pimpl->set_value(p_value);
-}
-
-void ThreadLocalStorage::alloc(void(_CALLBACK_FUNC_ *p_destr_callback)(void *)) {
- pimpl = memnew(ThreadLocalStorage::Impl(p_destr_callback));
-}
-
-#undef _CALLBACK_FUNC_
-
-void ThreadLocalStorage::free() {
- memdelete(pimpl);
- pimpl = NULL;
-}
diff --git a/modules/mono/utils/thread_local.h b/modules/mono/utils/thread_local.h
deleted file mode 100644
index b1cc2e37ea..0000000000
--- a/modules/mono/utils/thread_local.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*************************************************************************/
-/* thread_local.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 THREAD_LOCAL_H
-#define THREAD_LOCAL_H
-
-#ifdef HAVE_CXX11_THREAD_LOCAL
-#define _THREAD_LOCAL_(m_t) thread_local m_t
-#else
-
-#if !defined(__GNUC__) && !defined(_MSC_VER)
-#error Platform or compiler not supported
-#endif
-
-#if defined(__GNUC__)
-
-#ifdef HAVE_GCC___THREAD
-#define _THREAD_LOCAL_(m_t) __thread m_t
-#else
-#define USE_CUSTOM_THREAD_LOCAL
-#endif
-
-#elif defined(_MSC_VER)
-
-#ifdef HAVE_DECLSPEC_THREAD
-#define _THREAD_LOCAL_(m_t) __declspec(thread) m_t
-#else
-#define USE_CUSTOM_THREAD_LOCAL
-#endif
-
-#endif // __GNUC__ _MSC_VER
-
-#endif // HAVE_CXX11_THREAD_LOCAL
-
-#ifdef USE_CUSTOM_THREAD_LOCAL
-#define _THREAD_LOCAL_(m_t) ThreadLocal<m_t>
-#endif
-
-#include "core/typedefs.h"
-
-#ifdef WINDOWS_ENABLED
-#define _CALLBACK_FUNC_ __stdcall
-#else
-#define _CALLBACK_FUNC_
-#endif
-
-struct ThreadLocalStorage {
-
- void *get_value() const;
- void set_value(void *p_value) const;
-
- void alloc(void(_CALLBACK_FUNC_ *p_destr_callback)(void *));
- void free();
-
-private:
- struct Impl;
- Impl *pimpl;
-};
-
-template <typename T>
-class ThreadLocal {
-
- ThreadLocalStorage storage;
-
- T init_val;
-
- static void _CALLBACK_FUNC_ destr_callback(void *tls_data) {
- memdelete(static_cast<T *>(tls_data));
- }
-
- T *_tls_get_value() const {
- void *tls_data = storage.get_value();
-
- if (tls_data)
- return static_cast<T *>(tls_data);
-
- T *data = memnew(T(init_val));
-
- storage.set_value(data);
-
- return data;
- }
-
- void _initialize(const T &p_init_val) {
- init_val = p_init_val;
- storage.alloc(&destr_callback);
- }
-
-public:
- ThreadLocal() {
- _initialize(T());
- }
-
- ThreadLocal(const T &p_init_val) {
- _initialize(p_init_val);
- }
-
- ThreadLocal(const ThreadLocal &other) {
- _initialize(*other._tls_get_value());
- }
-
- ~ThreadLocal() {
- storage.free();
- }
-
- _FORCE_INLINE_ T *operator&() const {
- return _tls_get_value();
- }
-
- _FORCE_INLINE_ operator T &() const {
- return *_tls_get_value();
- }
-
- _FORCE_INLINE_ ThreadLocal &operator=(const T &val) {
- T *ptr = _tls_get_value();
- *ptr = val;
- return *this;
- }
-};
-
-struct FlagScopeGuard {
-
- FlagScopeGuard(bool &p_flag) :
- flag(p_flag) {
- flag = !flag;
- }
-
- ~FlagScopeGuard() {
- flag = !flag;
- }
-
-private:
- bool &flag;
-};
-
-#undef _CALLBACK_FUNC_
-
-#define _TLS_RECURSION_GUARD_V_(m_ret) \
- static _THREAD_LOCAL_(bool) _recursion_flag_ = false; \
- if (_recursion_flag_) \
- return m_ret; \
- FlagScopeGuard _recursion_guard_(_recursion_flag_);
-
-#define _TLS_RECURSION_GUARD_ \
- static _THREAD_LOCAL_(bool) _recursion_flag_ = false; \
- if (_recursion_flag_) \
- return; \
- FlagScopeGuard _recursion_guard_(_recursion_flag_);
-
-#endif // THREAD_LOCAL_H
diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub
index 6a72a519fe..e768fb4ae8 100644
--- a/modules/ogg/SCsub
+++ b/modules/ogg/SCsub
@@ -1,12 +1,15 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
+
+# Only kept to build the thirdparty library used by the theora and webm
+# modules.
env_ogg = env_modules.Clone()
# Thirdparty source files
-if env['builtin_libogg']:
+if env["builtin_libogg"]:
thirdparty_dir = "#thirdparty/libogg/"
thirdparty_sources = [
"bitwise.c",
diff --git a/modules/ogg/config.py b/modules/ogg/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/ogg/config.py
+++ b/modules/ogg/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/ogg/register_types.h b/modules/ogg/register_types.h
index 09095c9b62..849d27bb06 100644
--- a/modules/ogg/register_types.h
+++ b/modules/ogg/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef OGG_REGISTER_TYPES_H
+#define OGG_REGISTER_TYPES_H
+
void register_ogg_types();
void unregister_ogg_types();
+
+#endif // OGG_REGISTER_TYPES_H
diff --git a/modules/opensimplex/SCsub b/modules/opensimplex/SCsub
index 311d33b047..52d8b145ef 100644
--- a/modules/opensimplex/SCsub
+++ b/modules/opensimplex/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_opensimplex = env_modules.Clone()
diff --git a/modules/opensimplex/config.py b/modules/opensimplex/config.py
index c1010ad433..90b85dbd70 100644
--- a/modules/opensimplex/config.py
+++ b/modules/opensimplex/config.py
@@ -1,14 +1,17 @@
def can_build(env, platform):
- return True
+ return True
+
def configure(env):
- pass
+ pass
+
def get_doc_classes():
return [
"NoiseTexture",
- "OpenSimplexNoise"
+ "OpenSimplexNoise",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp
index 8e5b04f995..2018f90e9f 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -34,7 +34,7 @@
NoiseTexture::NoiseTexture() {
update_queued = false;
- noise_thread = NULL;
+ noise_thread = nullptr;
regen_queued = false;
first_time = true;
@@ -50,7 +50,7 @@ NoiseTexture::NoiseTexture() {
NoiseTexture::~NoiseTexture() {
if (texture.is_valid()) {
- VS::get_singleton()->free(texture);
+ RS::get_singleton()->free(texture);
}
if (noise_thread) {
Thread::wait_to_finish(noise_thread);
@@ -100,10 +100,10 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) {
data = p_image;
if (data.is_valid()) {
if (texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_create(p_image);
- VS::get_singleton()->texture_replace(texture, new_texture);
+ RID new_texture = RS::get_singleton()->texture_2d_create(p_image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
} else {
- texture = VS::get_singleton()->texture_2d_create(p_image);
+ texture = RS::get_singleton()->texture_2d_create(p_image);
}
}
emit_changed();
@@ -114,7 +114,7 @@ void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
_set_texture_data(p_image);
Thread::wait_to_finish(noise_thread);
memdelete(noise_thread);
- noise_thread = NULL;
+ noise_thread = nullptr;
if (regen_queued) {
noise_thread = Thread::create(_thread_function, this);
regen_queued = false;
@@ -137,14 +137,19 @@ void NoiseTexture::_queue_update() {
Ref<Image> NoiseTexture::_generate_texture() {
- if (noise.is_null()) return Ref<Image>();
+ // Prevent memdelete due to unref() on other thread.
+ Ref<OpenSimplexNoise> ref_noise = noise;
+
+ if (ref_noise.is_null()) {
+ return Ref<Image>();
+ }
Ref<Image> image;
if (seamless) {
- image = noise->get_seamless_image(size.x);
+ image = ref_noise->get_seamless_image(size.x);
} else {
- image = noise->get_image(size.x, size.y);
+ image = ref_noise->get_image(size.x, size.y);
}
if (as_normalmap) {
@@ -254,7 +259,7 @@ int NoiseTexture::get_height() const {
RID NoiseTexture::get_rid() const {
if (!texture.is_valid()) {
- texture = VS::get_singleton()->texture_2d_placeholder_create();
+ texture = RS::get_singleton()->texture_2d_placeholder_create();
}
return texture;
diff --git a/modules/opensimplex/register_types.h b/modules/opensimplex/register_types.h
index 56e128f09e..51c6815eae 100644
--- a/modules/opensimplex/register_types.h
+++ b/modules/opensimplex/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef OPENSIMPLEX_REGISTER_TYPES_H
+#define OPENSIMPLEX_REGISTER_TYPES_H
+
void register_opensimplex_types();
void unregister_opensimplex_types();
+
+#endif // OPENSIMPLEX_REGISTER_TYPES_H
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index 1db5b0987e..e51590d808 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -1,18 +1,19 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
-stub = True
+# Only kept to build the thirdparty library used by the webm module.
+# AudioStreamOpus was dropped in 3.0 due to incompatibility with the new audio
+# engine. If you want to port it, fetch it from the Git history.
env_opus = env_modules.Clone()
# Thirdparty source files
-if env['builtin_opus']:
+if env["builtin_opus"]:
thirdparty_dir = "#thirdparty/opus/"
thirdparty_sources = [
-
# Sync with opus_sources.mk
"opus.c",
"opus_decoder.c",
@@ -21,17 +22,14 @@ if env['builtin_opus']:
"opus_multistream_encoder.c",
"opus_multistream_decoder.c",
"repacketizer.c",
-
"analysis.c",
"mlp.c",
"mlp_data.c",
-
# Sync with libopusfile Makefile.am
"info.c",
"internal.c",
"opusfile.c",
"stream.c",
-
# Sync with celt_sources.mk
"celt/bands.c",
"celt/celt.c",
@@ -51,12 +49,11 @@ if env['builtin_opus']:
"celt/quant_bands.c",
"celt/rate.c",
"celt/vq.c",
- #"celt/arm/arm_celt_map.c",
- #"celt/arm/armcpu.c",
- #"celt/arm/celt_ne10_fft.c",
- #"celt/arm/celt_ne10_mdct.c",
- #"celt/arm/celt_neon_intr.c",
-
+ # "celt/arm/arm_celt_map.c",
+ # "celt/arm/armcpu.c",
+ # "celt/arm/celt_ne10_fft.c",
+ # "celt/arm/celt_ne10_mdct.c",
+ # "celt/arm/celt_neon_intr.c",
# Sync with silk_sources.mk
"silk/CNG.c",
"silk/code_signs.c",
@@ -205,7 +202,7 @@ if env['builtin_opus']:
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources + opus_sources_silk]
# also requires libogg
- if env['builtin_libogg']:
+ if env["builtin_libogg"]:
env_opus.Prepend(CPPPATH=["#thirdparty/libogg"])
env_opus.Append(CPPDEFINES=["HAVE_CONFIG_H"])
@@ -221,23 +218,19 @@ if env['builtin_opus']:
env_opus.Prepend(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths])
if env["platform"] == "android":
- if ("android_arch" in env and env["android_arch"] == "armv7"):
+ if "android_arch" in env and env["android_arch"] == "armv7":
env_opus.Append(CPPDEFINES=["OPUS_ARM_OPT"])
- elif ("android_arch" in env and env["android_arch"] == "arm64v8"):
+ elif "android_arch" in env and env["android_arch"] == "arm64v8":
env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
elif env["platform"] == "iphone":
- if ("arch" in env and env["arch"] == "arm"):
+ if "arch" in env and env["arch"] == "arm":
env_opus.Append(CPPDEFINES=["OPUS_ARM_OPT"])
- elif ("arch" in env and env["arch"] == "arm64"):
+ elif "arch" in env and env["arch"] == "arm64":
env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
env_thirdparty = env_opus.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
-if not stub:
- # Module files
- env_opus.add_source_files(env.modules_sources, "*.cpp")
-else:
- # Module files
- env_opus.add_source_files(env.modules_sources, "stub/register_types.cpp")
+# Module files
+env_opus.add_source_files(env.modules_sources, "register_types.cpp")
diff --git a/modules/opus/audio_stream_opus.cpp b/modules/opus/audio_stream_opus.cpp
deleted file mode 100644
index a983edee91..0000000000
--- a/modules/opus/audio_stream_opus.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/*************************************************************************/
-/* audio_stream_opus.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "audio_stream_opus.h"
-
-/**
- @author George Marques <george@gmarqu.es>
-*/
-
-const float AudioStreamPlaybackOpus::osrate = 48000.0f;
-
-int AudioStreamPlaybackOpus::_op_read_func(void *_stream, unsigned char *_ptr, int _nbytes) {
- FileAccess *fa = (FileAccess *)_stream;
-
- if (fa->eof_reached())
- return 0;
-
- uint8_t *dst = (uint8_t *)_ptr;
-
- int read = fa->get_buffer(dst, _nbytes);
-
- return read;
-}
-
-int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, int _whence) {
-
-#ifdef SEEK_SET
- FileAccess *fa = (FileAccess *)_stream;
-
- switch (_whence) {
- case SEEK_SET: {
- fa->seek(_offset);
- } break;
- case SEEK_CUR: {
- fa->seek(fa->get_position() + _offset);
- } break;
- case SEEK_END: {
- fa->seek_end(_offset);
- } break;
- default: {
- ERR_PRINT("Opus seek function failure: Unexpected value in _whence\n");
- }
- }
- int ret = fa->eof_reached() ? -1 : 0;
- return ret;
-#else
- return -1; // no seeking
-#endif
-}
-
-int AudioStreamPlaybackOpus::_op_close_func(void *_stream) {
- if (!_stream)
- return 0;
- FileAccess *fa = (FileAccess *)_stream;
- if (fa->is_open())
- fa->close();
- return 0;
-}
-
-opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) {
- FileAccess *_fa = (FileAccess *)_stream;
- return (opus_int64)_fa->get_position();
-}
-
-void AudioStreamPlaybackOpus::_clear_stream() {
- if (!stream_loaded)
- return;
-
- op_free(opus_file);
- _close_file();
-
- stream_loaded = false;
- stream_channels = 1;
- playing = false;
-}
-
-void AudioStreamPlaybackOpus::_close_file() {
- if (f) {
- memdelete(f);
- f = NULL;
- }
-}
-
-Error AudioStreamPlaybackOpus::_load_stream() {
-
- ERR_FAIL_COND_V(!stream_valid, ERR_UNCONFIGURED);
-
- _clear_stream();
- if (file == "")
- return ERR_INVALID_DATA;
-
- Error err;
- f = FileAccess::open(file, FileAccess::READ, &err);
-
- ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + file + "'.");
-
- int _err = 0;
-
- opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &_err);
-
- switch (_err) {
- case OP_EREAD: { // - Can't read the file.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CANT_READ);
- } break;
- case OP_EVERSION: // - Unrecognized version number.
- case OP_ENOTFORMAT: // - Stream is not Opus data.
- case OP_EIMPL: { // - Stream used non-implemented feature.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
- } break;
- case OP_EBADLINK: // - Failed to find old data after seeking.
- case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
- case OP_EBADHEADER: { // - Invalid or missing Opus bitstream header.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- } break;
- case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_BUG);
- } break;
- }
- repeats = 0;
- stream_loaded = true;
-
- return OK;
-}
-
-AudioStreamPlaybackOpus::AudioStreamPlaybackOpus() {
- loops = false;
- playing = false;
- f = NULL;
- stream_loaded = false;
- stream_valid = false;
- repeats = 0;
- paused = true;
- stream_channels = 0;
- current_section = 0;
- length = 0;
- loop_restart_time = 0;
- pre_skip = 0;
-
- _op_callbacks.read = _op_read_func;
- _op_callbacks.seek = _op_seek_func;
- _op_callbacks.tell = _op_tell_func;
- _op_callbacks.close = _op_close_func;
-}
-
-Error AudioStreamPlaybackOpus::set_file(const String &p_file) {
- file = p_file;
- stream_valid = false;
- Error err;
- f = FileAccess::open(file, FileAccess::READ, &err);
-
- ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + file + "'.");
-
- int _err;
-
- opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &_err);
-
- switch (_err) {
- case OP_EREAD: { // - Can't read the file.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CANT_READ);
- } break;
- case OP_EVERSION: // - Unrecognized version number.
- case OP_ENOTFORMAT: // - Stream is not Opus data.
- case OP_EIMPL: { // - Stream used non-implemented feature.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
- } break;
- case OP_EBADLINK: // - Failed to find old data after seeking.
- case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
- case OP_EBADHEADER: { // - Invalid or missing Opus bitstream header.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- } break;
- case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_BUG);
- } break;
- }
-
- const OpusHead *oinfo = op_head(opus_file, -1);
-
- stream_channels = oinfo->channel_count;
- pre_skip = oinfo->pre_skip;
- frames_mixed = pre_skip;
- ogg_int64_t len = op_pcm_total(opus_file, -1);
- if (len < 0) {
- length = 0;
- } else {
- length = (len / osrate);
- }
-
- op_free(opus_file);
- memdelete(f);
- f = NULL;
- stream_valid = true;
-
- return OK;
-}
-
-void AudioStreamPlaybackOpus::play(float p_from) {
- if (playing)
- stop();
-
- if (_load_stream() != OK)
- return;
-
- frames_mixed = pre_skip;
- playing = true;
- if (p_from > 0) {
- seek(p_from);
- }
-}
-
-void AudioStreamPlaybackOpus::stop() {
- _clear_stream();
- playing = false;
-}
-
-void AudioStreamPlaybackOpus::seek(float p_time) {
- if (!playing) return;
- ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate);
- bool ok = op_pcm_seek(opus_file, pcm_offset) == 0;
- if (!ok) {
- ERR_PRINT("Seek time over stream size.");
- return;
- }
- frames_mixed = osrate * p_time;
-}
-
-int AudioStreamPlaybackOpus::mix(int16_t *p_buffer, int p_frames) {
- if (!playing)
- return 0;
-
- int total = p_frames;
-
- while (true) {
-
- int todo = p_frames;
-
- if (todo < MIN_MIX) {
- break;
- }
-
- int ret = op_read(opus_file, (opus_int16 *)p_buffer, todo * stream_channels, &current_section);
- if (ret < 0) {
- playing = false;
- ERR_BREAK_MSG(ret < 0, "Error reading Opus file: " + file + ".");
- } else if (ret == 0) { // end of song, reload?
- op_free(opus_file);
-
- _close_file();
-
- f = FileAccess::open(file, FileAccess::READ);
-
- int errv = 0;
- opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &errv);
- if (errv != 0) {
- playing = false;
- break; // :(
- }
-
- if (!has_loop()) {
- playing = false;
- repeats = 1;
- break;
- }
-
- if (loop_restart_time) {
- bool ok = op_pcm_seek(opus_file, (loop_restart_time * osrate) + pre_skip) == 0;
- if (!ok) {
- playing = false;
- ERR_PRINT("Loop restart time rejected");
- }
-
- frames_mixed = (loop_restart_time * osrate) + pre_skip;
- } else {
- frames_mixed = pre_skip;
- }
- repeats++;
- continue;
- }
-
- stream_channels = op_head(opus_file, current_section)->channel_count;
-
- frames_mixed += ret;
-
- p_buffer += ret * stream_channels;
- p_frames -= ret;
- }
-
- return total - p_frames;
-}
-
-float AudioStreamPlaybackOpus::get_length() const {
- if (!stream_loaded) {
- if (const_cast<AudioStreamPlaybackOpus *>(this)->_load_stream() != OK)
- return 0;
- }
- return length;
-}
-
-float AudioStreamPlaybackOpus::get_playback_position() const {
-
- int32_t frames = int32_t(frames_mixed);
- if (frames < 0)
- frames = 0;
- return double(frames) / osrate;
-}
-
-int AudioStreamPlaybackOpus::get_minimum_buffer_size() const {
- return MIN_MIX;
-}
-
-AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() {
- _clear_stream();
-}
-
-RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
- if (r_error)
- *r_error = OK;
-
- AudioStreamOpus *opus_stream = memnew(AudioStreamOpus);
- opus_stream->set_file(p_path);
- return Ref<AudioStreamOpus>(opus_stream);
-}
-
-void ResourceFormatLoaderAudioStreamOpus::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("opus");
-}
-String ResourceFormatLoaderAudioStreamOpus::get_resource_type(const String &p_path) const {
-
- if (p_path.get_extension().to_lower() == "opus")
- return "AudioStreamOpus";
- return "";
-}
-
-bool ResourceFormatLoaderAudioStreamOpus::handles_type(const String &p_type) const {
- return (p_type == "AudioStream" || p_type == "AudioStreamOpus");
-}
diff --git a/modules/opus/audio_stream_opus.h b/modules/opus/audio_stream_opus.h
deleted file mode 100644
index 343cbc6b83..0000000000
--- a/modules/opus/audio_stream_opus.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*************************************************************************/
-/* audio_stream_opus.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 AUDIO_STREAM_OPUS_H
-#define AUDIO_STREAM_OPUS_H
-
-#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
-#include "scene/resources/audio_stream.h"
-
-#include <opus/opusfile.h>
-
-/**
- @author George Marques <george@gmarqu.es>
-*/
-
-class AudioStreamPlaybackOpus : public AudioStreamPlayback {
-
- GDCLASS(AudioStreamPlaybackOpus, AudioStreamPlayback);
-
- enum {
- MIN_MIX = 1024
- };
-
- FileAccess *f;
-
- OpusFileCallbacks _op_callbacks;
- float length;
- static int _op_read_func(void *_stream, unsigned char *_ptr, int _nbytes);
- static int _op_seek_func(void *_stream, opus_int64 _offset, int _whence);
- static int _op_close_func(void *_stream);
- static opus_int64 _op_tell_func(void *_stream);
- static const float osrate;
-
- String file;
- int64_t frames_mixed;
-
- bool stream_loaded;
- volatile bool playing;
- OggOpusFile *opus_file;
- int stream_channels;
- int current_section;
- int pre_skip;
-
- bool paused;
- bool loops;
- int repeats;
-
- Error _load_stream();
- void _clear_stream();
- void _close_file();
-
- bool stream_valid;
- float loop_restart_time;
-
-public:
- Error set_file(const String &p_file);
-
- virtual void play(float p_from = 0);
- virtual void stop();
- virtual bool is_playing() const { return playing; }
-
- virtual void set_loop_restart_time(float p_time) { loop_restart_time = p_time; }
-
- virtual void set_paused(bool p_paused) { paused = p_paused; }
- virtual bool is_paused() const { return paused; }
-
- virtual void set_loop(bool p_enable) { loops = p_enable; }
- virtual bool has_loop() const { return loops; }
-
- virtual float get_length() const;
-
- virtual String get_stream_name() const { return ""; }
-
- virtual int get_loop_count() const { return repeats; }
-
- virtual float get_playback_position() const;
- virtual void seek(float p_time);
-
- virtual int get_channels() const { return stream_channels; }
- virtual int get_mix_rate() const { return osrate; }
-
- virtual int get_minimum_buffer_size() const;
-
- virtual int mix(int16_t *p_buffer, int p_frames);
-
- AudioStreamPlaybackOpus();
- ~AudioStreamPlaybackOpus();
-};
-
-class AudioStreamOpus : public AudioStream {
-
- GDCLASS(AudioStreamOpus, AudioStream);
-
- String file;
-
-public:
- Ref<AudioStreamPlayback> instance_playback() {
- Ref<AudioStreamPlaybackOpus> pb = memnew(AudioStreamPlaybackOpus);
- pb->set_file(file);
- return pb;
- }
-
- void set_file(const String &p_file) { file = p_file; }
-};
-
-class ResourceFormatLoaderAudioStreamOpus : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
-#endif // AUDIO_STREAM_OPUS_H
diff --git a/modules/opus/config.py b/modules/opus/config.py
index a1cde10ea0..d22f9454ed 100644
--- a/modules/opus/config.py
+++ b/modules/opus/config.py
@@ -1,13 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
-
-def get_doc_classes():
- return [
- "AudioStreamOpus",
- ]
-
-def get_doc_path():
- return "doc_classes"
diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp
index dff309b49c..a4329e142c 100644
--- a/modules/opus/register_types.cpp
+++ b/modules/opus/register_types.cpp
@@ -30,23 +30,8 @@
#include "register_types.h"
-#include "audio_stream_opus.h"
+// Dummy module as libvorbis is needed by other modules (theora ...)
-static Ref<ResourceFormatLoaderAudioStreamOpus> opus_stream_loader;
+void register_opus_types() {}
-void register_opus_types() {
- // Sorry guys, do not enable this unless you can figure out a way
- // to get Opus to not do any memory allocation or system calls
- // in the audio thread.
- // Currently the implementation even reads files from the audio thread,
- // and this is not how audio programming works.
-
- //opus_stream_loader = memnew(ResourceFormatLoaderAudioStreamOpus);
- //ResourceLoader::add_resource_format_loader(opus_stream_loader);
- //ClassDB::register_class<AudioStreamOpus>();
-}
-
-void unregister_opus_types() {
-
- //memdelete(opus_stream_loader);
-}
+void unregister_opus_types() {}
diff --git a/modules/opus/register_types.h b/modules/opus/register_types.h
index 445be4e166..ad6e083c82 100644
--- a/modules/opus/register_types.h
+++ b/modules/opus/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef OPUS_REGISTER_TYPES_H
+#define OPUS_REGISTER_TYPES_H
+
void register_opus_types();
void unregister_opus_types();
+
+#endif // OPUS_REGISTER_TYPES_H
diff --git a/modules/opus/stub/register_types.cpp b/modules/opus/stub/register_types.cpp
deleted file mode 100644
index a4329e142c..0000000000
--- a/modules/opus/stub/register_types.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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"
-
-// Dummy module as libvorbis is needed by other modules (theora ...)
-
-void register_opus_types() {}
-
-void unregister_opus_types() {}
diff --git a/modules/opus/stub/register_types.h b/modules/opus/stub/register_types.h
deleted file mode 100644
index 445be4e166..0000000000
--- a/modules/opus/stub/register_types.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-void register_opus_types();
-void unregister_opus_types();
diff --git a/modules/pvr/SCsub b/modules/pvr/SCsub
index 18da38fbbd..e0baf851f1 100644
--- a/modules/pvr/SCsub
+++ b/modules/pvr/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_pvr = env_modules.Clone()
diff --git a/modules/pvr/config.py b/modules/pvr/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/pvr/config.py
+++ b/modules/pvr/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/pvr/register_types.h b/modules/pvr/register_types.h
index 06c54f50b1..8318996a46 100644
--- a/modules/pvr/register_types.h
+++ b/modules/pvr/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef PVR_REGISTER_TYPES_H
+#define PVR_REGISTER_TYPES_H
+
void register_pvr_types();
void unregister_pvr_types();
+
+#endif // PVR_REGISTER_TYPES_H
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 179c6f692b..10d4d71f5e 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -534,7 +534,7 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int
// local neighbourhood of blocks
PVRTCBlock *p_blocks[2][2];
- PVRTCBlock *prev[2][2] = { { NULL, NULL }, { NULL, NULL } };
+ PVRTCBlock *prev[2][2] = { { nullptr, nullptr }, { nullptr, nullptr } };
struct
{
diff --git a/modules/pvr/texture_loader_pvr.h b/modules/pvr/texture_loader_pvr.h
index c990c3612b..642323db35 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 = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/regex/SCsub b/modules/regex/SCsub
index 6238cd3d9f..753650adcb 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -1,16 +1,16 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_regex = env_modules.Clone()
-if env['builtin_pcre2']:
- thirdparty_dir = '#thirdparty/pcre2/src/'
- thirdparty_flags = ['PCRE2_STATIC', 'HAVE_CONFIG_H']
+if env["builtin_pcre2"]:
+ thirdparty_dir = "#thirdparty/pcre2/src/"
+ thirdparty_flags = ["PCRE2_STATIC", "HAVE_CONFIG_H"]
- if env['builtin_pcre2_with_jit']:
- thirdparty_flags.append('SUPPORT_JIT')
+ if env["builtin_pcre2_with_jit"]:
+ thirdparty_flags.append("SUPPORT_JIT")
thirdparty_sources = [
"pcre2_auto_possess.c",
@@ -24,7 +24,7 @@ if env['builtin_pcre2']:
"pcre2_extuni.c",
"pcre2_find_bracket.c",
"pcre2_jit_compile.c",
- #"pcre2_jit_match.c", "pcre2_jit_misc.c", # these files are included in pcre2_jit_compile.c.
+ # "pcre2_jit_match.c", "pcre2_jit_misc.c", # these files are included in pcre2_jit_compile.c.
"pcre2_maketables.c",
"pcre2_match.c",
"pcre2_match_data.c",
diff --git a/modules/regex/config.py b/modules/regex/config.py
index 42cfe3b43c..df9f44cb95 100644
--- a/modules/regex/config.py
+++ b/modules/regex/config.py
@@ -1,14 +1,17 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"RegEx",
"RegExMatch",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 53d1a1dd65..25cc580591 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -80,7 +80,7 @@ Dictionary RegExMatch::get_names() const {
Dictionary result;
- for (const Map<String, int>::Element *i = names.front(); i != NULL; i = i->next()) {
+ for (const Map<String, int>::Element *i = names.front(); i != nullptr; i = i->next()) {
result[i->key()] = i->value();
}
@@ -180,14 +180,14 @@ void RegEx::clear() {
if (code) {
pcre2_code_free_16((pcre2_code_16 *)code);
- code = NULL;
+ code = nullptr;
}
} else {
if (code) {
pcre2_code_free_32((pcre2_code_32 *)code);
- code = NULL;
+ code = nullptr;
}
}
}
@@ -242,7 +242,7 @@ Error RegEx::compile(const String &p_pattern) {
Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end) const {
- ERR_FAIL_COND_V(!is_valid(), NULL);
+ ERR_FAIL_COND_V(!is_valid(), nullptr);
Ref<RegExMatch> result = memnew(RegExMatch);
@@ -263,7 +263,7 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
if (res < 0) {
pcre2_match_data_free_16(match);
- return NULL;
+ return nullptr;
}
uint32_t size = pcre2_get_ovector_count_16(match);
@@ -295,7 +295,7 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
pcre2_match_data_free_32(match);
pcre2_match_context_free_32(mctx);
- return NULL;
+ return nullptr;
}
uint32_t size = pcre2_get_ovector_count_32(match);
@@ -431,7 +431,7 @@ String RegEx::sub(const String &p_subject, const String &p_replacement, bool p_a
bool RegEx::is_valid() const {
- return (code != NULL);
+ return (code != nullptr);
}
String RegEx::get_pattern() const {
@@ -479,26 +479,26 @@ RegEx::RegEx() {
if (sizeof(CharType) == 2) {
- general_ctx = pcre2_general_context_create_16(&_regex_malloc, &_regex_free, NULL);
+ general_ctx = pcre2_general_context_create_16(&_regex_malloc, &_regex_free, nullptr);
} else {
- general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, NULL);
+ general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr);
}
- code = NULL;
+ code = nullptr;
}
RegEx::RegEx(const String &p_pattern) {
if (sizeof(CharType) == 2) {
- general_ctx = pcre2_general_context_create_16(&_regex_malloc, &_regex_free, NULL);
+ general_ctx = pcre2_general_context_create_16(&_regex_malloc, &_regex_free, nullptr);
} else {
- general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, NULL);
+ general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr);
}
- code = NULL;
+ code = nullptr;
compile(p_pattern);
}
diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h
index 99a6bbeb2c..cf377cdf5f 100644
--- a/modules/regex/register_types.h
+++ b/modules/regex/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef REGEX_REGISTER_TYPES_H
+#define REGEX_REGISTER_TYPES_H
+
void register_regex_types();
void unregister_regex_types();
+
+#endif // REGEX_REGISTER_TYPES_H
diff --git a/modules/squish/SCsub b/modules/squish/SCsub
index 15320bcd0c..b31032403f 100644
--- a/modules/squish/SCsub
+++ b/modules/squish/SCsub
@@ -1,12 +1,12 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_squish = env_modules.Clone()
# Thirdparty source files
-if env['builtin_squish']:
+if env["builtin_squish"]:
thirdparty_dir = "#thirdparty/squish/"
thirdparty_sources = [
"alpha.cpp",
diff --git a/modules/squish/config.py b/modules/squish/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/squish/config.py
+++ b/modules/squish/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h
index 0845e2b500..ab56c54d4a 100644
--- a/modules/squish/register_types.h
+++ b/modules/squish/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SQUISH_REGISTER_TYPES_H
+#define SQUISH_REGISTER_TYPES_H
+
void register_squish_types();
void unregister_squish_types();
+
+#endif // SQUISH_REGISTER_TYPES_H
diff --git a/modules/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub
index d14939a3b1..266c87c802 100644
--- a/modules/stb_vorbis/SCsub
+++ b/modules/stb_vorbis/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_stb_vorbis = env_modules.Clone()
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 42f341cef7..9609c234ec 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -122,7 +122,7 @@ void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
if (ogg_alloc.alloc_buffer) {
stb_vorbis_close(ogg_stream);
- AudioServer::get_singleton()->audio_data_free(ogg_alloc.alloc_buffer);
+ memfree(ogg_alloc.alloc_buffer);
}
}
@@ -130,11 +130,11 @@ Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
Ref<AudioStreamPlaybackOGGVorbis> ovs;
- ERR_FAIL_COND_V(data == NULL, ovs);
+ ERR_FAIL_COND_V(data == nullptr, ovs);
ovs.instance();
ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this);
- ovs->ogg_alloc.alloc_buffer = (char *)AudioServer::get_singleton()->audio_data_alloc(decode_mem_size);
+ ovs->ogg_alloc.alloc_buffer = (char *)memalloc(decode_mem_size);
ovs->ogg_alloc.alloc_buffer_length_in_bytes = decode_mem_size;
ovs->frames_mixed = 0;
ovs->active = false;
@@ -143,8 +143,8 @@ Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
ovs->ogg_stream = stb_vorbis_open_memory((const unsigned char *)data, data_len, &error, &ovs->ogg_alloc);
if (!ovs->ogg_stream) {
- AudioServer::get_singleton()->audio_data_free(ovs->ogg_alloc.alloc_buffer);
- ovs->ogg_alloc.alloc_buffer = NULL;
+ memfree(ovs->ogg_alloc.alloc_buffer);
+ ovs->ogg_alloc.alloc_buffer = nullptr;
ERR_FAIL_COND_V(!ovs->ogg_stream, Ref<AudioStreamPlaybackOGGVorbis>());
}
@@ -158,8 +158,8 @@ String AudioStreamOGGVorbis::get_stream_name() const {
void AudioStreamOGGVorbis::clear_data() {
if (data) {
- AudioServer::get_singleton()->audio_data_free(data);
- data = NULL;
+ memfree(data);
+ data = nullptr;
data_len = 0;
}
}
@@ -172,7 +172,7 @@ void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
uint32_t alloc_try = 1024;
Vector<char> alloc_mem;
char *w;
- stb_vorbis *ogg_stream = NULL;
+ stb_vorbis *ogg_stream = nullptr;
stb_vorbis_alloc ogg_alloc;
while (alloc_try < MAX_TEST_MEM) {
@@ -194,7 +194,7 @@ void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
} else {
ERR_FAIL_COND(alloc_try == MAX_TEST_MEM);
- ERR_FAIL_COND(ogg_stream == NULL);
+ ERR_FAIL_COND(ogg_stream == nullptr);
stb_vorbis_info info = stb_vorbis_get_info(ogg_stream);
@@ -210,7 +210,8 @@ void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
// free any existing data
clear_data();
- data = AudioServer::get_singleton()->audio_data_alloc(src_data_len, src_datar);
+ data = memalloc(src_data_len);
+ copymem(data, src_datar, src_data_len);
data_len = src_data_len;
break;
@@ -273,7 +274,7 @@ void AudioStreamOGGVorbis::_bind_methods() {
AudioStreamOGGVorbis::AudioStreamOGGVorbis() {
- data = NULL;
+ data = nullptr;
data_len = 0;
length = 0;
sample_rate = 1;
diff --git a/modules/stb_vorbis/config.py b/modules/stb_vorbis/config.py
index 200b8dfd50..1eb0a8cf33 100644
--- a/modules/stb_vorbis/config.py
+++ b/modules/stb_vorbis/config.py
@@ -1,13 +1,16 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"AudioStreamOGGVorbis",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/stb_vorbis/register_types.h b/modules/stb_vorbis/register_types.h
index f6147abd01..f5a1dd31bc 100644
--- a/modules/stb_vorbis/register_types.h
+++ b/modules/stb_vorbis/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef STB_VORBIS_REGISTER_TYPES_H
+#define STB_VORBIS_REGISTER_TYPES_H
+
void register_stb_vorbis_types();
void unregister_stb_vorbis_types();
+
+#endif // STB_VORBIS_REGISTER_TYPES_H
diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.h b/modules/stb_vorbis/resource_importer_ogg_vorbis.h
index 43541bcf3c..8d6f71a456 100644
--- a/modules/stb_vorbis/resource_importer_ogg_vorbis.h
+++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.h
@@ -50,7 +50,7 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
- 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 = NULL, Variant *r_metadata = NULL);
+ 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);
ResourceImporterOGGVorbis();
};
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 7961d1f33e..0bfba34fe5 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -1,14 +1,14 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_svg = env_modules.Clone()
# Thirdparty source files
thirdparty_dir = "#thirdparty/nanosvg/"
thirdparty_sources = [
- "nanosvg.cc"
+ "nanosvg.cc",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/modules/svg/config.py b/modules/svg/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/svg/config.py
+++ b/modules/svg/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index e9d30d015a..3c2784f8de 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -65,7 +65,7 @@ inline void change_nsvg_paint_color(NSVGpaint *p_paint, const uint32_t p_old, co
void ImageLoaderSVG::_convert_colors(NSVGimage *p_svg_image) {
- for (NSVGshape *shape = p_svg_image->shapes; shape != NULL; shape = shape->next) {
+ for (NSVGshape *shape = p_svg_image->shapes; shape != nullptr; shape = shape->next) {
for (int i = 0; i < replace_colors.old_colors.size(); i++) {
change_nsvg_paint_color(&(shape->stroke), replace_colors.old_colors[i], replace_colors.new_colors[i]);
@@ -98,7 +98,7 @@ Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const Vector<uint8_t> *p
NSVGimage *svg_image;
const uint8_t *src_r = p_data->ptr();
svg_image = nsvgParse((char *)src_r, "px", 96);
- if (svg_image == NULL) {
+ if (svg_image == nullptr) {
ERR_PRINT("SVG Corrupted");
return ERR_FILE_CORRUPT;
}
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index def2885199..0fa4a0fdf4 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -63,7 +63,7 @@ class ImageLoaderSVG : public ImageFormatLoader {
static Error _create_image(Ref<Image> p_image, const Vector<uint8_t> *p_data, float p_scale, bool upsample, bool convert_colors = false);
public:
- static void set_convert_colors(Dictionary *p_replace_color = NULL);
+ static void set_convert_colors(Dictionary *p_replace_color = nullptr);
static Error create_image_from_string(Ref<Image> p_image, const char *p_svg_str, float p_scale, bool upsample, bool convert_colors = false);
virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp
index b0782dae88..37875313aa 100644
--- a/modules/svg/register_types.cpp
+++ b/modules/svg/register_types.cpp
@@ -32,7 +32,7 @@
#include "image_loader_svg.h"
-static ImageLoaderSVG *image_loader_svg = NULL;
+static ImageLoaderSVG *image_loader_svg = nullptr;
void register_svg_types() {
diff --git a/modules/svg/register_types.h b/modules/svg/register_types.h
index aa50540552..a3d914e0cb 100644
--- a/modules/svg/register_types.h
+++ b/modules/svg/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SVG_REGISTER_TYPES_H
+#define SVG_REGISTER_TYPES_H
+
void register_svg_types();
void unregister_svg_types();
+
+#endif // SVG_REGISTER_TYPES_H
diff --git a/modules/tga/SCsub b/modules/tga/SCsub
index 7e405f405c..067caa6ea0 100644
--- a/modules/tga/SCsub
+++ b/modules/tga/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_tga = env_modules.Clone()
diff --git a/modules/tga/config.py b/modules/tga/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/tga/config.py
+++ b/modules/tga/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 0e904fdd76..fc9d727bb0 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -283,7 +283,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
uint8_t *uncompressed_buffer_w = uncompressed_buffer.ptrw();
const uint8_t *uncompressed_buffer_r;
- const uint8_t *buffer = NULL;
+ const uint8_t *buffer = nullptr;
if (is_encoded) {
diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp
index 359f4d785e..0d9268ebbf 100644
--- a/modules/tga/register_types.cpp
+++ b/modules/tga/register_types.cpp
@@ -32,7 +32,7 @@
#include "image_loader_tga.h"
-static ImageLoaderTGA *image_loader_tga = NULL;
+static ImageLoaderTGA *image_loader_tga = nullptr;
void register_tga_types() {
diff --git a/modules/tga/register_types.h b/modules/tga/register_types.h
index beef05a590..94a77d295e 100644
--- a/modules/tga/register_types.h
+++ b/modules/tga/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef TGA_REGISTER_TYPES_H
+#define TGA_REGISTER_TYPES_H
+
void register_tga_types();
void unregister_tga_types();
+
+#endif // TGA_REGISTER_TYPES_H
diff --git a/modules/theora/SCsub b/modules/theora/SCsub
index ff65d2f8ec..a01e65b4b0 100644
--- a/modules/theora/SCsub
+++ b/modules/theora/SCsub
@@ -1,71 +1,71 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_theora = env_modules.Clone()
# Thirdparty source files
-if env['builtin_libtheora']:
+if env["builtin_libtheora"]:
thirdparty_dir = "#thirdparty/libtheora/"
thirdparty_sources = [
- #"analyze.c",
- #"apiwrapper.c",
+ # "analyze.c",
+ # "apiwrapper.c",
"bitpack.c",
"cpu.c",
- #"decapiwrapper.c",
+ # "decapiwrapper.c",
"decinfo.c",
"decode.c",
"dequant.c",
- #"encapiwrapper.c",
- #"encfrag.c",
- #"encinfo.c",
- #"encode.c",
- #"encoder_disabled.c",
- #"enquant.c",
- #"fdct.c",
+ # "encapiwrapper.c",
+ # "encfrag.c",
+ # "encinfo.c",
+ # "encode.c",
+ # "encoder_disabled.c",
+ # "enquant.c",
+ # "fdct.c",
"fragment.c",
"huffdec.c",
- #"huffenc.c",
+ # "huffenc.c",
"idct.c",
"info.c",
"internal.c",
- #"mathops.c",
- #"mcenc.c",
+ # "mathops.c",
+ # "mcenc.c",
"quant.c",
- #"rate.c",
+ # "rate.c",
"state.c",
- #"tokenize.c",
+ # "tokenize.c",
]
thirdparty_sources_x86 = [
- #"x86/mmxencfrag.c",
- #"x86/mmxfdct.c",
+ # "x86/mmxencfrag.c",
+ # "x86/mmxfdct.c",
"x86/mmxfrag.c",
"x86/mmxidct.c",
"x86/mmxstate.c",
- #"x86/sse2fdct.c",
- #"x86/x86enc.c",
+ # "x86/sse2fdct.c",
+ # "x86/x86enc.c",
"x86/x86state.c",
]
thirdparty_sources_x86_vc = [
- #"x86_vc/mmxencfrag.c",
- #"x86_vc/mmxfdct.c",
+ # "x86_vc/mmxencfrag.c",
+ # "x86_vc/mmxfdct.c",
"x86_vc/mmxfrag.c",
"x86_vc/mmxidct.c",
"x86_vc/mmxstate.c",
- #"x86_vc/x86enc.c",
+ # "x86_vc/x86enc.c",
"x86_vc/x86state.c",
]
- if (env["x86_libtheora_opt_gcc"]):
+ if env["x86_libtheora_opt_gcc"]:
thirdparty_sources += thirdparty_sources_x86
- if (env["x86_libtheora_opt_vc"]):
+ if env["x86_libtheora_opt_vc"]:
thirdparty_sources += thirdparty_sources_x86_vc
- if (env["x86_libtheora_opt_gcc"] or env["x86_libtheora_opt_vc"]):
+ if env["x86_libtheora_opt_gcc"] or env["x86_libtheora_opt_vc"]:
env_theora.Append(CPPDEFINES=["OC_X86_ASM"])
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -73,9 +73,9 @@ if env['builtin_libtheora']:
env_theora.Prepend(CPPPATH=[thirdparty_dir])
# also requires libogg and libvorbis
- if env['builtin_libogg']:
+ if env["builtin_libogg"]:
env_theora.Prepend(CPPPATH=["#thirdparty/libogg"])
- if env['builtin_libvorbis']:
+ if env["builtin_libvorbis"]:
env_theora.Prepend(CPPPATH=["#thirdparty/libvorbis"])
env_thirdparty = env_theora.Clone()
diff --git a/modules/theora/config.py b/modules/theora/config.py
index c7713d7607..413acce2df 100644
--- a/modules/theora/config.py
+++ b/modules/theora/config.py
@@ -1,13 +1,16 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"VideoStreamTheora",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/theora/register_types.h b/modules/theora/register_types.h
index 66eb49aed1..4f0670b2c7 100644
--- a/modules/theora/register_types.h
+++ b/modules/theora/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef THEORA_REGISTER_TYPES_H
+#define THEORA_REGISTER_TYPES_H
+
void register_theora_types();
void unregister_theora_types();
+
+#endif // THEORA_REGISTER_TYPES_H
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index ee44c6bf05..e5fb6f996d 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -144,7 +144,7 @@ void VideoStreamPlaybackTheora::clear() {
thread_sem->post(); //just in case
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
ring_buffer.clear();
#endif
@@ -159,7 +159,7 @@ void VideoStreamPlaybackTheora::clear() {
if (file) {
memdelete(file);
}
- file = NULL;
+ file = nullptr;
playing = false;
};
@@ -167,7 +167,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
ERR_FAIL_COND(playing);
ogg_packet op;
- th_setup_info *ts = NULL;
+ th_setup_info *ts = nullptr;
file_name = p_file;
if (file) {
@@ -674,7 +674,7 @@ void VideoStreamPlaybackTheora::_streaming_thread(void *ud) {
VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() {
- file = NULL;
+ file = nullptr;
theora_p = 0;
vorbis_p = 0;
videobuf_ready = 0;
@@ -685,8 +685,8 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() {
buffering = false;
texture = Ref<ImageTexture>(memnew(ImageTexture));
- mix_callback = NULL;
- mix_udata = NULL;
+ mix_callback = nullptr;
+ mix_udata = nullptr;
audio_track = 0;
delay_compensation = 0;
audio_frames_wrote = 0;
@@ -696,7 +696,7 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() {
ring_buffer.resize(rb_power);
read_buffer.resize(RB_SIZE_KB * 1024);
thread_sem = Semaphore::create();
- thread = NULL;
+ thread = nullptr;
thread_exit = false;
thread_eof = false;
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index da3558ce34..cd7bff7adb 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -187,7 +187,7 @@ public:
class ResourceFormatLoaderTheora : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/tinyexr/SCsub b/modules/tinyexr/SCsub
index 97f9797b58..e7fd44fabd 100644
--- a/modules/tinyexr/SCsub
+++ b/modules/tinyexr/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_tinyexr = env_modules.Clone()
diff --git a/modules/tinyexr/config.py b/modules/tinyexr/config.py
index 098f1eafa9..53b8f2f2e3 100644
--- a/modules/tinyexr/config.py
+++ b/modules/tinyexr/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return env['tools']
+ return env["tools"]
+
def configure(env):
pass
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 41938f5b42..1c0f3cd03e 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -56,7 +56,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
EXRVersion exr_version;
EXRImage exr_image;
EXRHeader exr_header;
- const char *err = NULL;
+ const char *err = nullptr;
InitEXRHeader(&exr_header);
@@ -194,7 +194,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
const float *r_channel_start = reinterpret_cast<const float *>(tile.images[idxR]);
const float *g_channel_start = reinterpret_cast<const float *>(tile.images[idxG]);
const float *b_channel_start = reinterpret_cast<const float *>(tile.images[idxB]);
- const float *a_channel_start = NULL;
+ const float *a_channel_start = nullptr;
if (idxA != -1) {
a_channel_start = reinterpret_cast<const float *>(tile.images[idxA]);
@@ -206,7 +206,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
const float *r_channel = r_channel_start + y * tile_width;
const float *g_channel = g_channel_start + y * tile_width;
const float *b_channel = b_channel_start + y * tile_width;
- const float *a_channel = NULL;
+ const float *a_channel = nullptr;
if (a_channel_start) {
a_channel = a_channel_start + y * tile_width;
diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp
index d8529fd893..af05a411e1 100644
--- a/modules/tinyexr/register_types.cpp
+++ b/modules/tinyexr/register_types.cpp
@@ -33,7 +33,7 @@
#include "image_loader_tinyexr.h"
#include "image_saver_tinyexr.h"
-static ImageLoaderTinyEXR *image_loader_tinyexr = NULL;
+static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr;
void register_tinyexr_types() {
@@ -47,5 +47,5 @@ void unregister_tinyexr_types() {
memdelete(image_loader_tinyexr);
- Image::save_exr_func = NULL;
+ Image::save_exr_func = nullptr;
}
diff --git a/modules/tinyexr/register_types.h b/modules/tinyexr/register_types.h
index 2028cd4a33..9739488312 100644
--- a/modules/tinyexr/register_types.h
+++ b/modules/tinyexr/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef TINYEXR_REGISTER_TYPES_H
+#define TINYEXR_REGISTER_TYPES_H
+
void register_tinyexr_types();
void unregister_tinyexr_types();
+
+#endif // TINYEXR_REGISTER_TYPES_H
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 3f56a69594..2e129e15ca 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -1,13 +1,13 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_upnp = env_modules.Clone()
# Thirdparty source files
-if env['builtin_miniupnpc']:
+if env["builtin_miniupnpc"]:
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
"miniupnpc.c",
diff --git a/modules/upnp/config.py b/modules/upnp/config.py
index 8724ff1a51..3e15b940a1 100644
--- a/modules/upnp/config.py
+++ b/modules/upnp/config.py
@@ -1,14 +1,17 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"UPNP",
- "UPNPDevice"
+ "UPNPDevice",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/upnp/register_types.h b/modules/upnp/register_types.h
index 4d752e4a94..0c71db9ffa 100644
--- a/modules/upnp/register_types.h
+++ b/modules/upnp/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef UPNP_REGISTER_TYPES_H
+#define UPNP_REGISTER_TYPES_H
+
void register_upnp_types();
void unregister_upnp_types();
+
+#endif // UPNP_REGISTER_TYPES_H
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index 5ef7575b0c..988bf3017d 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -44,9 +44,8 @@ bool UPNP::is_common_device(const String &dev) const {
}
int UPNP::discover(int timeout, int ttl, const String &device_filter) {
- ERR_FAIL_COND_V(timeout < 0, UPNP_RESULT_INVALID_PARAM);
- ERR_FAIL_COND_V(ttl < 0, UPNP_RESULT_INVALID_PARAM);
- ERR_FAIL_COND_V(ttl > 255, UPNP_RESULT_INVALID_PARAM);
+ ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative.");
+ ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive).");
devices.clear();
@@ -54,9 +53,9 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) {
struct UPNPDev *devlist;
if (is_common_device(device_filter)) {
- devlist = upnpDiscover(timeout, discover_multicast_if.utf8().get_data(), NULL, discover_local_port, discover_ipv6, ttl, &error);
+ devlist = upnpDiscover(timeout, discover_multicast_if.utf8().get_data(), nullptr, discover_local_port, discover_ipv6, ttl, &error);
} else {
- devlist = upnpDiscoverAll(timeout, discover_multicast_if.utf8().get_data(), NULL, discover_local_port, discover_ipv6, ttl, &error);
+ devlist = upnpDiscoverAll(timeout, discover_multicast_if.utf8().get_data(), nullptr, discover_local_port, discover_ipv6, ttl, &error);
}
if (error != UPNPDISCOVER_SUCCESS) {
@@ -133,7 +132,7 @@ void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
parserootdesc(xml, size, &data);
free(xml);
- xml = 0;
+ xml = nullptr;
GetUPNPUrls(urls, &data, dev->get_description_url().utf8().get_data(), 0);
@@ -235,20 +234,20 @@ int UPNP::get_device_count() const {
}
Ref<UPNPDevice> UPNP::get_device(int index) const {
- ERR_FAIL_INDEX_V(index, devices.size(), NULL);
+ ERR_FAIL_INDEX_V(index, devices.size(), nullptr);
return devices.get(index);
}
void UPNP::add_device(Ref<UPNPDevice> device) {
- ERR_FAIL_COND(device == NULL);
+ ERR_FAIL_COND(device == nullptr);
devices.push_back(device);
}
void UPNP::set_device(int index, Ref<UPNPDevice> device) {
ERR_FAIL_INDEX(index, devices.size());
- ERR_FAIL_COND(device == NULL);
+ ERR_FAIL_COND(device == nullptr);
devices.set(index, device);
}
@@ -264,17 +263,17 @@ void UPNP::clear_devices() {
}
Ref<UPNPDevice> UPNP::get_gateway() const {
- ERR_FAIL_COND_V(devices.size() < 1, NULL);
+ ERR_FAIL_COND_V_MSG(devices.size() < 1, nullptr, "Couldn't find any UPNPDevices.");
for (int i = 0; i < devices.size(); i++) {
Ref<UPNPDevice> dev = get_device(i);
- if (dev != NULL && dev->is_valid_gateway()) {
+ if (dev != nullptr && dev->is_valid_gateway()) {
return dev;
}
}
- return NULL;
+ return nullptr;
}
void UPNP::set_discover_multicast_if(const String &m_if) {
@@ -304,7 +303,7 @@ bool UPNP::is_discover_ipv6() const {
String UPNP::query_external_address() const {
Ref<UPNPDevice> dev = get_gateway();
- if (dev == NULL) {
+ if (dev == nullptr) {
return "";
}
@@ -314,7 +313,7 @@ String UPNP::query_external_address() const {
int UPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
Ref<UPNPDevice> dev = get_gateway();
- if (dev == NULL) {
+ if (dev == nullptr) {
return UPNP_RESULT_NO_GATEWAY;
}
@@ -326,7 +325,7 @@ int UPNP::add_port_mapping(int port, int port_internal, String desc, String prot
int UPNP::delete_port_mapping(int port, String proto) const {
Ref<UPNPDevice> dev = get_gateway();
- if (dev == NULL) {
+ if (dev == nullptr) {
return UPNP_RESULT_NO_GATEWAY;
}
diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h
index d052e155de..46f44e04e5 100644
--- a/modules/upnp/upnp.h
+++ b/modules/upnp/upnp.h
@@ -46,7 +46,7 @@ private:
int discover_local_port;
bool discover_ipv6;
- Vector<Ref<UPNPDevice> > devices;
+ Vector<Ref<UPNPDevice>> devices;
bool is_common_device(const String &dev) const;
void add_device_to_list(UPNPDev *dev, UPNPDev *devlist);
diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp
index 6edfbc2d7d..40eb6106a0 100644
--- a/modules/upnp/upnp_device.cpp
+++ b/modules/upnp/upnp_device.cpp
@@ -35,7 +35,7 @@
#include <miniupnpc/upnpcommands.h>
String UPNPDevice::query_external_address() const {
- ERR_FAIL_COND_V(!is_valid_gateway(), "");
+ ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid.");
char addr[16];
int i = UPNP_GetExternalIPAddress(
@@ -43,17 +43,17 @@ String UPNPDevice::query_external_address() const {
igd_service_type.utf8().get_data(),
(char *)&addr);
- ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, "");
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address.");
return String(addr);
}
int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
- ERR_FAIL_COND_V(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY);
- ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT);
- ERR_FAIL_COND_V(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT); // Needs to allow 0 because 0 signifies "use external port as internal port"
- ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL);
- ERR_FAIL_COND_V(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION);
+ ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid.");
+ ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port"
+ ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
+ ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative.");
if (port_internal < 1) {
port_internal = port;
@@ -65,29 +65,29 @@ int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, Strin
itos(port).utf8().get_data(),
itos(port_internal).utf8().get_data(),
igd_our_addr.utf8().get_data(),
- desc.empty() ? 0 : desc.utf8().get_data(),
+ desc.empty() ? nullptr : desc.utf8().get_data(),
proto.utf8().get_data(),
- NULL, // Remote host, always NULL as IGDs don't support it
- duration > 0 ? itos(duration).utf8().get_data() : 0);
+ nullptr, // Remote host, always nullptr as IGDs don't support it
+ duration > 0 ? itos(duration).utf8().get_data() : nullptr);
- ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i));
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't add port mapping.");
return UPNP::UPNP_RESULT_SUCCESS;
}
int UPNPDevice::delete_port_mapping(int port, String proto) const {
- ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT);
- ERR_FAIL_COND_V(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL);
+ ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
int i = UPNP_DeletePortMapping(
igd_control_url.utf8().get_data(),
igd_service_type.utf8().get_data(),
itos(port).utf8().get_data(),
proto.utf8().get_data(),
- NULL // Remote host, always NULL as IGDs don't support it
+ nullptr // Remote host, always nullptr as IGDs don't support it
);
- ERR_FAIL_COND_V(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i));
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't delete port mapping.");
return UPNP::UPNP_RESULT_SUCCESS;
}
diff --git a/modules/vhacd/SCsub b/modules/vhacd/SCsub
index 685976dc33..ecd432b275 100644
--- a/modules/vhacd/SCsub
+++ b/modules/vhacd/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_vhacd = env_modules.Clone()
@@ -19,7 +19,7 @@ thirdparty_sources = [
"src/btAlignedAllocator.cpp",
"src/vhacdRaycastMesh.cpp",
"src/VHACD.cpp",
- "src/btConvexHullComputer.cpp"
+ "src/btConvexHullComputer.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
diff --git a/modules/vhacd/config.py b/modules/vhacd/config.py
index 9ced70d2fb..d22f9454ed 100644
--- a/modules/vhacd/config.py
+++ b/modules/vhacd/config.py
@@ -1,6 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
-
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 26c6146bab..c006a9deec 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -32,7 +32,7 @@
#include "scene/resources/mesh.h"
#include "thirdparty/vhacd/public/VHACD.h"
-static Vector<Vector<Face3> > convex_decompose(const Vector<Face3> &p_faces) {
+static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces) {
Vector<float> vertices;
vertices.resize(p_faces.size() * 9);
@@ -54,7 +54,7 @@ static Vector<Vector<Face3> > convex_decompose(const Vector<Face3> &p_faces) {
int hull_count = decomposer->GetNConvexHulls();
- Vector<Vector<Face3> > ret;
+ Vector<Vector<Face3>> ret;
for (int i = 0; i < hull_count; i++) {
Vector<Face3> triangles;
@@ -84,5 +84,5 @@ void register_vhacd_types() {
}
void unregister_vhacd_types() {
- Mesh::convex_composition_function = NULL;
+ Mesh::convex_composition_function = nullptr;
}
diff --git a/modules/vhacd/register_types.h b/modules/vhacd/register_types.h
index de56620813..d02a990901 100644
--- a/modules/vhacd/register_types.h
+++ b/modules/vhacd/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef VHACD_REGISTER_TYPES_H
+#define VHACD_REGISTER_TYPES_H
+
void register_vhacd_types();
void unregister_vhacd_types();
+
+#endif // VHACD_REGISTER_TYPES_H
diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub
index 3c3d2caa57..16faea08d7 100644
--- a/modules/visual_script/SCsub
+++ b/modules/visual_script/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_vs = env_modules.Clone()
diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py
index 087a13a200..bd459ca344 100644
--- a/modules/visual_script/config.py
+++ b/modules/visual_script/config.py
@@ -1,9 +1,11 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"@VisualScript",
@@ -56,5 +58,6 @@ def get_doc_classes():
"VisualScriptYield",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index 63bd88ad81..5ea84a32c4 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -41,9 +41,9 @@
#include "visual_script_nodes.h"
#include "visual_script_yield_nodes.h"
-VisualScriptLanguage *visual_script_language = NULL;
+VisualScriptLanguage *visual_script_language = nullptr;
#ifdef TOOLS_ENABLED
-static _VisualScriptEditor *vs_editor_singleton = NULL;
+static _VisualScriptEditor *vs_editor_singleton = nullptr;
#endif
void register_visual_script_types() {
diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h
index 546c2fbff3..c18c2930b1 100644
--- a/modules/visual_script/register_types.h
+++ b/modules/visual_script/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef VISUAL_SCRIPT_REGISTER_TYPES_H
+#define VISUAL_SCRIPT_REGISTER_TYPES_H
+
void register_visual_script_types();
void unregister_visual_script_types();
+
+#endif // VISUAL_SCRIPT_REGISTER_TYPES_H
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 050fdbcb07..7cc52eef36 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -94,7 +94,7 @@ void VisualScriptNode::validate_input_default_values() {
default_input_values[i] = Variant::construct(expected, &existingp, 1, ce, false);
if (ce.error != Callable::CallError::CALL_OK) {
//could not convert? force..
- default_input_values[i] = Variant::construct(expected, NULL, 0, ce, false);
+ default_input_values[i] = Variant::construct(expected, nullptr, 0, ce, false);
}
}
}
@@ -158,8 +158,8 @@ VisualScriptNode::VisualScriptNode() {
VisualScriptNodeInstance::VisualScriptNodeInstance() {
- sequence_outputs = NULL;
- input_ports = NULL;
+ sequence_outputs = nullptr;
+ input_ports = nullptr;
}
VisualScriptNodeInstance::~VisualScriptNodeInstance() {
@@ -727,6 +727,26 @@ void VisualScript::rename_variable(const StringName &p_name, const StringName &p
variables[p_new_name] = variables[p_name];
variables.erase(p_name);
+
+ List<StringName> funcs;
+ get_function_list(&funcs);
+ for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) { // loop through all the functions
+ List<int> ids;
+ get_node_list(F->get(), &ids);
+ for (List<int>::Element *E = ids.front(); E; E = E->next()) {
+ Ref<VisualScriptVariableGet> nodeget = get_node(F->get(), E->get());
+ if (nodeget.is_valid()) {
+ if (nodeget->get_variable() == p_name)
+ nodeget->set_variable(p_new_name);
+ } else {
+ Ref<VisualScriptVariableSet> nodeset = get_node(F->get(), E->get());
+ if (nodeset.is_valid()) {
+ if (nodeset->get_variable() == p_name)
+ nodeset->set_variable(p_new_name);
+ }
+ }
+ }
+ }
}
void VisualScript::add_custom_signal(const StringName &p_name) {
@@ -827,7 +847,7 @@ void VisualScript::rename_custom_signal(const StringName &p_name, const StringNa
void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const {
- for (const Map<StringName, Vector<Argument> >::Element *E = custom_signals.front(); E; E = E->next()) {
+ for (const Map<StringName, Vector<Argument>>::Element *E = custom_signals.front(); E; E = E->next()) {
r_custom_signals->push_back(E->key());
}
@@ -981,7 +1001,7 @@ bool VisualScript::has_script_signal(const StringName &p_signal) const {
void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const Map<StringName, Vector<Argument> >::Element *E = custom_signals.front(); E; E = E->next()) {
+ for (const Map<StringName, Vector<Argument>>::Element *E = custom_signals.front(); E; E = E->next()) {
MethodInfo mi;
mi.name = E->key();
@@ -1148,8 +1168,8 @@ StringName VisualScript::get_rset_property(const uint16_t p_rset_property_id) co
}
MultiplayerAPI::RPCMode VisualScript::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const {
- ERR_FAIL_COND_V(p_rset_variable_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
- return rpc_functions[p_rset_variable_id].mode;
+ ERR_FAIL_COND_V(p_rset_variable_id >= rpc_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED);
+ return rpc_variables[p_rset_variable_id].mode;
}
MultiplayerAPI::RPCMode VisualScript::get_rset_mode(const StringName &p_variable) const {
@@ -1302,7 +1322,7 @@ Dictionary VisualScript::_get_data() const {
d["variables"] = vars;
Array sigs;
- for (const Map<StringName, Vector<Argument> >::Element *E = custom_signals.front(); E; E = E->next()) {
+ for (const Map<StringName, Vector<Argument>>::Element *E = custom_signals.front(); E; E = E->next()) {
Dictionary cs;
cs["name"] = E->key();
@@ -1594,7 +1614,7 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
output_args[i] = &variant_stack[node->output_ports[i]];
}
- Variant *working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)NULL;
+ Variant *working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr;
node->step(input_args, output_args, VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE, working_mem, r_error, error_str);
//ignore return
@@ -1615,8 +1635,8 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
Variant **output_args = (Variant **)(input_args + max_input_args);
int flow_max = f->flow_stack_size;
- int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)NULL;
- int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)NULL;
+ int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)nullptr;
+ int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr;
String error_str;
@@ -1624,7 +1644,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
bool error = false;
int current_node_id = f->node;
Variant return_value;
- Variant *working_mem = NULL;
+ Variant *working_mem = nullptr;
int flow_stack_pos = p_flow_stack_pos;
@@ -1643,7 +1663,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
VSDEBUG("AT STACK POS: " + itos(flow_stack_pos));
//setup working mem
- working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)NULL;
+ working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr;
VSDEBUG("WORKING MEM: " + itos(node->working_mem_idx));
@@ -1817,7 +1837,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
break; //exit function requested, bye
}
- VisualScriptNodeInstance *next = NULL; //next node
+ VisualScriptNodeInstance *next = nullptr; //next node
if ((ret == output || ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) {
//if no exit bit was set, and has sequence outputs, guess next node
@@ -2033,8 +2053,8 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p
const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
Variant **output_args = (Variant **)(input_args + max_input_args);
int flow_max = f->flow_stack_size;
- int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)NULL;
- int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)NULL;
+ int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)nullptr;
+ int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr;
for (int i = 0; i < f->node_count; i++) {
sequence_bits[i] = false; //all starts as false
@@ -2097,7 +2117,7 @@ void VisualScriptInstance::notification(int p_notification) {
String VisualScriptInstance::to_string(bool *r_valid) {
if (has_method(CoreStringNames::get_singleton()->_to_string)) {
Callable::CallError ce;
- Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
+ Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
if (r_valid)
@@ -2237,12 +2257,12 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
instance->id = F->key();
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) {
@@ -2263,7 +2283,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
}
}
@@ -2779,7 +2799,7 @@ void VisualScriptLanguage::get_recognized_extensions(List<String> *p_extensions)
}
void VisualScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
}
-void VisualScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
+void VisualScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const {
}
void VisualScriptLanguage::profiling_start() {
@@ -2797,7 +2817,7 @@ int VisualScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in
return 0;
}
-VisualScriptLanguage *VisualScriptLanguage::singleton = NULL;
+VisualScriptLanguage *VisualScriptLanguage::singleton = nullptr;
void VisualScriptLanguage::add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func) {
@@ -2844,7 +2864,7 @@ VisualScriptLanguage::VisualScriptLanguage() {
} else {
_debug_max_call_stack = 0;
- _call_stack = NULL;
+ _call_stack = nullptr;
}
}
@@ -2853,5 +2873,5 @@ VisualScriptLanguage::~VisualScriptLanguage() {
if (_call_stack) {
memdelete_arr(_call_stack);
}
- singleton = NULL;
+ singleton = nullptr;
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index d1005c025c..29309aa156 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -246,7 +246,7 @@ private:
Map<StringName, Function> functions;
Map<StringName, Variable> variables;
- Map<StringName, Vector<Argument> > custom_signals;
+ Map<StringName, Vector<Argument>> custom_signals;
Vector<ScriptNetData> rpc_functions;
Vector<ScriptNetData> rpc_variables;
@@ -420,7 +420,7 @@ public:
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
@@ -596,7 +596,7 @@ public:
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool is_using_templates();
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -623,7 +623,7 @@ public:
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_public_functions(List<MethodInfo> *p_functions) const;
- virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const;
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const;
virtual void profiling_start();
virtual void profiling_stop();
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 07f152efd4..bb291b1cb6 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -506,10 +506,12 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_CEIL: {
t = Variant::FLOAT;
} break;
- case MATH_POSMOD:
- case MATH_ROUND: {
+ case MATH_POSMOD: {
t = Variant::INT;
} break;
+ case MATH_ROUND: {
+ t = Variant::FLOAT;
+ } break;
case MATH_ABS: {
t = Variant::NIL;
} break;
@@ -1231,7 +1233,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
PackedByteArray barr;
int len;
bool full_objects = *p_inputs[1];
- Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
+ Error err = encode_variant(*p_inputs[0], nullptr, len, full_objects);
if (err) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -1267,7 +1269,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
Variant ret;
{
const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), NULL, allow_objects);
+ Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 8840b9f7cf..59b1bcdd96 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -30,15 +30,15 @@
#include "visual_script_editor.h"
+#include "core/input/input_filter.h"
#include "core/object.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/script_language.h"
#include "core/variant.h"
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "visual_script_expression.h"
#include "visual_script_flow_control.h"
#include "visual_script_func_nodes.h"
@@ -182,7 +182,7 @@ public:
_change_notify();
}
- VisualScriptEditorSignalEdit() { undo_redo = NULL; }
+ VisualScriptEditorSignalEdit() { undo_redo = nullptr; }
};
class VisualScriptEditorVariableEdit : public Object {
@@ -335,7 +335,7 @@ public:
_change_notify();
}
- VisualScriptEditorVariableEdit() { undo_redo = NULL; }
+ VisualScriptEditorVariableEdit() { undo_redo = nullptr; }
};
static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
@@ -350,8 +350,11 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::STRING: color = Color(0.42, 0.65, 0.93); break;
case Variant::VECTOR2: color = Color(0.74, 0.57, 0.95); break;
+ case Variant::VECTOR2I: color = Color(0.74, 0.57, 0.95); break;
case Variant::RECT2: color = Color(0.95, 0.57, 0.65); break;
+ case Variant::RECT2I: color = Color(0.95, 0.57, 0.65); break;
case Variant::VECTOR3: color = Color(0.84, 0.49, 0.93); break;
+ case Variant::VECTOR3I: color = Color(0.84, 0.49, 0.93); break;
case Variant::TRANSFORM2D: color = Color(0.77, 0.93, 0.41); break;
case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break;
case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break;
@@ -389,8 +392,11 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
case Variant::STRING: color = Color(0.27, 0.56, 0.91); break;
case Variant::VECTOR2: color = Color(0.68, 0.46, 0.93); break;
+ case Variant::VECTOR2I: color = Color(0.68, 0.46, 0.93); break;
case Variant::RECT2: color = Color(0.93, 0.46, 0.56); break;
+ case Variant::RECT2I: color = Color(0.93, 0.46, 0.56); break;
case Variant::VECTOR3: color = Color(0.86, 0.42, 0.93); break;
+ case Variant::VECTOR3I: color = Color(0.86, 0.42, 0.93); break;
case Variant::TRANSFORM2D: color = Color(0.59, 0.81, 0.1); break;
case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break;
case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break;
@@ -504,36 +510,41 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
select_func_text->hide();
Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {
- Control::get_icon("Variant", "EditorIcons"),
- Control::get_icon("bool", "EditorIcons"),
- Control::get_icon("int", "EditorIcons"),
- Control::get_icon("float", "EditorIcons"),
- Control::get_icon("String", "EditorIcons"),
- Control::get_icon("Vector2", "EditorIcons"),
- Control::get_icon("Rect2", "EditorIcons"),
- Control::get_icon("Vector3", "EditorIcons"),
- Control::get_icon("Transform2D", "EditorIcons"),
- Control::get_icon("Plane", "EditorIcons"),
- Control::get_icon("Quat", "EditorIcons"),
- Control::get_icon("AABB", "EditorIcons"),
- Control::get_icon("Basis", "EditorIcons"),
- Control::get_icon("Transform", "EditorIcons"),
- Control::get_icon("Color", "EditorIcons"),
- Control::get_icon("NodePath", "EditorIcons"),
- Control::get_icon("RID", "EditorIcons"),
- Control::get_icon("MiniObject", "EditorIcons"),
- Control::get_icon("Dictionary", "EditorIcons"),
- Control::get_icon("Array", "EditorIcons"),
- Control::get_icon("PackedByteArray", "EditorIcons"),
- Control::get_icon("PackedInt32Array", "EditorIcons"),
- Control::get_icon("PackedFloat32Array", "EditorIcons"),
- Control::get_icon("PackedStringArray", "EditorIcons"),
- Control::get_icon("PackedVector2Array", "EditorIcons"),
- Control::get_icon("PackedVector3Array", "EditorIcons"),
- Control::get_icon("PackedColorArray", "EditorIcons")
+ Control::get_theme_icon("Variant", "EditorIcons"),
+ Control::get_theme_icon("bool", "EditorIcons"),
+ Control::get_theme_icon("int", "EditorIcons"),
+ Control::get_theme_icon("float", "EditorIcons"),
+ Control::get_theme_icon("String", "EditorIcons"),
+ Control::get_theme_icon("Vector2", "EditorIcons"),
+ Control::get_theme_icon("Vector2i", "EditorIcons"),
+ Control::get_theme_icon("Rect2", "EditorIcons"),
+ Control::get_theme_icon("Rect2i", "EditorIcons"),
+ Control::get_theme_icon("Vector3", "EditorIcons"),
+ Control::get_theme_icon("Vector3i", "EditorIcons"),
+ Control::get_theme_icon("Transform2D", "EditorIcons"),
+ Control::get_theme_icon("Plane", "EditorIcons"),
+ Control::get_theme_icon("Quat", "EditorIcons"),
+ Control::get_theme_icon("AABB", "EditorIcons"),
+ Control::get_theme_icon("Basis", "EditorIcons"),
+ Control::get_theme_icon("Transform", "EditorIcons"),
+ Control::get_theme_icon("Color", "EditorIcons"),
+ Control::get_theme_icon("NodePath", "EditorIcons"),
+ Control::get_theme_icon("RID", "EditorIcons"),
+ Control::get_theme_icon("MiniObject", "EditorIcons"),
+ Control::get_theme_icon("Callable", "EditorIcons"),
+ Control::get_theme_icon("Signal", "EditorIcons"),
+ Control::get_theme_icon("Dictionary", "EditorIcons"),
+ Control::get_theme_icon("Array", "EditorIcons"),
+ Control::get_theme_icon("PackedByteArray", "EditorIcons"),
+ Control::get_theme_icon("PackedInt32Array", "EditorIcons"),
+ Control::get_theme_icon("PackedFloat32Array", "EditorIcons"),
+ Control::get_theme_icon("PackedStringArray", "EditorIcons"),
+ Control::get_theme_icon("PackedVector2Array", "EditorIcons"),
+ Control::get_theme_icon("PackedVector3Array", "EditorIcons"),
+ Control::get_theme_icon("PackedColorArray", "EditorIcons")
};
- Ref<Texture2D> seq_port = Control::get_icon("VisualShaderPort", "EditorIcons");
+ Ref<Texture2D> seq_port = Control::get_theme_icon("VisualShaderPort", "EditorIcons");
for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) { // loop through all the functions
@@ -596,7 +607,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
LineEdit *line_edit = memnew(LineEdit);
line_edit->set_text(node->get_text());
line_edit->set_expand_to_text_length(true);
- line_edit->add_font_override("font", get_font("source", "EditorFonts"));
+ 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()));
} else {
@@ -637,14 +648,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
mono_color.a = 0.85;
c = mono_color;
}
- gnode->add_color_override("title_color", c);
+ gnode->add_theme_color_override("title_color", c);
c.a = 0.7;
- gnode->add_color_override("close_color", c);
- gnode->add_color_override("resizer_color", ic);
- gnode->add_style_override("frame", sbf);
+ gnode->add_theme_color_override("close_color", c);
+ gnode->add_theme_color_override("resizer_color", ic);
+ gnode->add_theme_style_override("frame", sbf);
}
- const Color mono_color = get_color("mono_color", "Editor");
+ const Color mono_color = get_theme_color("mono_color", "Editor");
int slot_idx = 0;
@@ -750,7 +761,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
}
Button *rmbtn = memnew(Button);
- rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
+ rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
hbc->add_child(rmbtn);
rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port), varray(E->get(), i), CONNECT_DEFERRED);
} else {
@@ -812,7 +823,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
if (is_vslist) {
Button *rmbtn = memnew(Button);
- rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
+ rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
hbc->add_child(rmbtn);
rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port), varray(E->get(), i), CONNECT_DEFERRED);
@@ -856,7 +867,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
gnode->add_child(vbc);
- bool dark_theme = get_constant("dark_theme", "Editor");
+ bool dark_theme = get_theme_constant("dark_theme", "Editor");
if (i < mixed_seq_ports) {
gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture2D>(), seq_port);
} else {
@@ -940,9 +951,9 @@ void VisualScriptEditor::_update_members() {
TreeItem *functions = members->create_item(root);
functions->set_selectable(0, false);
functions->set_text(0, TTR("Functions:"));
- functions->add_button(0, Control::get_icon("Override", "EditorIcons"), 1, false, TTR("Override an existing built-in function."));
- functions->add_button(0, Control::get_icon("Add", "EditorIcons"), 0, false, TTR("Create a new function."));
- functions->set_custom_color(0, Control::get_color("mono_color", "Editor"));
+ functions->add_button(0, Control::get_theme_icon("Override", "EditorIcons"), 1, false, TTR("Override an existing built-in function."));
+ functions->add_button(0, Control::get_theme_icon("Add", "EditorIcons"), 0, false, TTR("Create a new function."));
+ functions->set_custom_color(0, Control::get_theme_color("mono_color", "Editor"));
List<StringName> func_names;
script->get_function_list(&func_names);
@@ -956,7 +967,7 @@ void VisualScriptEditor::_update_members() {
ti->set_text(0, E->get());
ti->set_selectable(0, true);
ti->set_metadata(0, E->get());
- ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0);
+ ti->add_button(0, Control::get_theme_icon("Edit", "EditorIcons"), 0);
if (selected == E->get())
ti->select(0);
}
@@ -964,37 +975,42 @@ void VisualScriptEditor::_update_members() {
TreeItem *variables = members->create_item(root);
variables->set_selectable(0, false);
variables->set_text(0, TTR("Variables:"));
- variables->add_button(0, Control::get_icon("Add", "EditorIcons"), -1, false, TTR("Create a new variable."));
- variables->set_custom_color(0, Control::get_color("mono_color", "Editor"));
+ variables->add_button(0, Control::get_theme_icon("Add", "EditorIcons"), -1, false, TTR("Create a new variable."));
+ variables->set_custom_color(0, Control::get_theme_color("mono_color", "Editor"));
Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {
- Control::get_icon("Variant", "EditorIcons"),
- Control::get_icon("bool", "EditorIcons"),
- Control::get_icon("int", "EditorIcons"),
- Control::get_icon("float", "EditorIcons"),
- Control::get_icon("String", "EditorIcons"),
- Control::get_icon("Vector2", "EditorIcons"),
- Control::get_icon("Rect2", "EditorIcons"),
- Control::get_icon("Vector3", "EditorIcons"),
- Control::get_icon("Transform2D", "EditorIcons"),
- Control::get_icon("Plane", "EditorIcons"),
- Control::get_icon("Quat", "EditorIcons"),
- Control::get_icon("AABB", "EditorIcons"),
- Control::get_icon("Basis", "EditorIcons"),
- Control::get_icon("Transform", "EditorIcons"),
- Control::get_icon("Color", "EditorIcons"),
- Control::get_icon("NodePath", "EditorIcons"),
- Control::get_icon("RID", "EditorIcons"),
- Control::get_icon("MiniObject", "EditorIcons"),
- Control::get_icon("Dictionary", "EditorIcons"),
- Control::get_icon("Array", "EditorIcons"),
- Control::get_icon("PackedByteArray", "EditorIcons"),
- Control::get_icon("PackedInt32Array", "EditorIcons"),
- Control::get_icon("PackedFloat32Array", "EditorIcons"),
- Control::get_icon("PackedStringArray", "EditorIcons"),
- Control::get_icon("PackedVector2Array", "EditorIcons"),
- Control::get_icon("PackedVector3Array", "EditorIcons"),
- Control::get_icon("PackedColorArray", "EditorIcons")
+ Control::get_theme_icon("Variant", "EditorIcons"),
+ Control::get_theme_icon("bool", "EditorIcons"),
+ Control::get_theme_icon("int", "EditorIcons"),
+ Control::get_theme_icon("float", "EditorIcons"),
+ Control::get_theme_icon("String", "EditorIcons"),
+ Control::get_theme_icon("Vector2", "EditorIcons"),
+ Control::get_theme_icon("Vector2i", "EditorIcons"),
+ Control::get_theme_icon("Rect2", "EditorIcons"),
+ Control::get_theme_icon("Rect2i", "EditorIcons"),
+ Control::get_theme_icon("Vector3", "EditorIcons"),
+ Control::get_theme_icon("Vector3i", "EditorIcons"),
+ Control::get_theme_icon("Transform2D", "EditorIcons"),
+ Control::get_theme_icon("Plane", "EditorIcons"),
+ Control::get_theme_icon("Quat", "EditorIcons"),
+ Control::get_theme_icon("AABB", "EditorIcons"),
+ Control::get_theme_icon("Basis", "EditorIcons"),
+ Control::get_theme_icon("Transform", "EditorIcons"),
+ Control::get_theme_icon("Color", "EditorIcons"),
+ Control::get_theme_icon("NodePath", "EditorIcons"),
+ Control::get_theme_icon("RID", "EditorIcons"),
+ Control::get_theme_icon("MiniObject", "EditorIcons"),
+ Control::get_theme_icon("Callable", "EditorIcons"),
+ Control::get_theme_icon("Signal", "EditorIcons"),
+ Control::get_theme_icon("Dictionary", "EditorIcons"),
+ Control::get_theme_icon("Array", "EditorIcons"),
+ Control::get_theme_icon("PackedByteArray", "EditorIcons"),
+ Control::get_theme_icon("PackedInt32Array", "EditorIcons"),
+ Control::get_theme_icon("PackedFloat32Array", "EditorIcons"),
+ Control::get_theme_icon("PackedStringArray", "EditorIcons"),
+ Control::get_theme_icon("PackedVector2Array", "EditorIcons"),
+ Control::get_theme_icon("PackedVector3Array", "EditorIcons"),
+ Control::get_theme_icon("PackedColorArray", "EditorIcons")
};
List<StringName> var_names;
@@ -1017,8 +1033,8 @@ void VisualScriptEditor::_update_members() {
TreeItem *_signals = members->create_item(root);
_signals->set_selectable(0, false);
_signals->set_text(0, TTR("Signals:"));
- _signals->add_button(0, Control::get_icon("Add", "EditorIcons"), -1, false, TTR("Create a new signal."));
- _signals->set_custom_color(0, Control::get_color("mono_color", "Editor"));
+ _signals->add_button(0, Control::get_theme_icon("Add", "EditorIcons"), -1, false, TTR("Create a new signal."));
+ _signals->set_custom_color(0, Control::get_theme_color("mono_color", "Editor"));
List<StringName> signal_names;
script->get_custom_signal_list(&signal_names);
@@ -1034,12 +1050,12 @@ void VisualScriptEditor::_update_members() {
String base_type = script->get_instance_base_type();
String icon_type = base_type;
- if (!Control::has_icon(base_type, "EditorIcons")) {
+ if (!Control::has_theme_icon(base_type, "EditorIcons")) {
icon_type = "Object";
}
base_type_select->set_text(base_type);
- base_type_select->set_icon(Control::get_icon(icon_type, "EditorIcons"));
+ base_type_select->set_icon(Control::get_theme_icon(icon_type, "EditorIcons"));
updating_members = false;
}
@@ -1057,9 +1073,9 @@ void VisualScriptEditor::_member_selected() {
if (ti->get_parent() == members->get_root()->get_children()) {
#ifdef OSX_ENABLED
- bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META);
+ bool held_ctrl = InputFilter::get_singleton()->is_key_pressed(KEY_META);
#else
- bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool held_ctrl = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
#endif
if (held_ctrl) {
ERR_FAIL_COND(!script->has_function(selected));
@@ -1155,6 +1171,8 @@ void VisualScriptEditor::_member_edited() {
undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name);
undo_redo->add_do_method(this, "_update_members");
undo_redo->add_undo_method(this, "_update_members");
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
undo_redo->commit_action();
@@ -1252,7 +1270,7 @@ void VisualScriptEditor::_add_func_input() {
hbox->add_child(type_box);
Button *delete_button = memnew(Button);
- delete_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
+ delete_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons"));
delete_button->set_tooltip(vformat(TTR("Delete input port")));
hbox->add_child(delete_button);
@@ -1262,7 +1280,7 @@ void VisualScriptEditor::_add_func_input() {
}
func_input_vbox->add_child(hbox);
- hbox->set_meta("id", hbox->get_position_in_parent());
+ hbox->set_meta("id", hbox->get_index());
delete_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_func_input), varray(hbox));
@@ -1360,7 +1378,7 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
}
} else if (ti->get_parent() == root->get_children()) {
selected = ti->get_text(0);
- function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));
+ function_name_edit->set_position(InputFilter::get_singleton()->get_mouse_position() - Vector2(60, -10));
function_name_edit->popup();
function_name_box->set_text(selected);
function_name_box->select_all();
@@ -1458,7 +1476,7 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
List<VisualScript::DataConnection> data_connections;
script->get_data_connection_list(func, &data_connections);
- HashMap<int, Set<int> > conn_map;
+ HashMap<int, Set<int>> conn_map;
for (const List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id && E->get().from_port == p_port) {
// push into the connections map
@@ -1722,7 +1740,7 @@ void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> key = p_event;
if (key.is_valid() && !key->is_pressed()) {
- mouse_up_position = Input::get_singleton()->get_mouse_position();
+ mouse_up_position = InputFilter::get_singleton()->get_mouse_position();
}
}
@@ -1732,7 +1750,7 @@ void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (key.is_valid() && key->is_pressed() && key->get_button_mask() == BUTTON_RIGHT) {
saved_position = graph->get_local_mouse_position();
- Point2 gpos = Input::get_singleton()->get_mouse_position();
+ Point2 gpos = InputFilter::get_singleton()->get_mouse_position();
_generic_search(script->get_instance_base_type(), gpos);
}
}
@@ -1932,7 +1950,7 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene)
- return NULL;
+ return nullptr;
Ref<Script> scr = p_current_node->get_script();
@@ -1945,7 +1963,7 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return n;
}
- return NULL;
+ return nullptr;
}
void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
@@ -1986,9 +2004,9 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
if (String(d["type"]) == "visual_script_variable_drag") {
#ifdef OSX_ENABLED
- bool use_set = Input::get_singleton()->is_key_pressed(KEY_META);
+ bool use_set = InputFilter::get_singleton()->is_key_pressed(KEY_META);
#else
- bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool use_set = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
#endif
Vector2 ofs = graph->get_scroll_ofs() + p_point;
if (graph->is_using_snap()) {
@@ -2181,9 +2199,9 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
#ifdef OSX_ENABLED
- bool use_node = Input::get_singleton()->is_key_pressed(KEY_META);
+ bool use_node = InputFilter::get_singleton()->is_key_pressed(KEY_META);
#else
- bool use_node = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool use_node = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
#endif
Array nodes = d["nodes"];
@@ -2245,7 +2263,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
- if (!sn && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (!sn && !InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop properties because script '%s' is not used in this scene.\nDrop holding 'Shift' to just copy the signature."), get_name()));
return;
}
@@ -2265,12 +2283,12 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
ofs /= EDSCALE;
#ifdef OSX_ENABLED
- bool use_get = Input::get_singleton()->is_key_pressed(KEY_META);
+ bool use_get = InputFilter::get_singleton()->is_key_pressed(KEY_META);
#else
- bool use_get = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ bool use_get = InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL);
#endif
- if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (!node || InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT)) {
if (use_get)
undo_redo->create_action(TTR("Add Getter Property"));
@@ -2377,7 +2395,7 @@ void VisualScriptEditor::_draw_color_over_button(Object *obj, Color p_color) {
if (!button)
return;
- Ref<StyleBox> normal = get_stylebox("normal", "Button");
+ Ref<StyleBox> normal = get_theme_stylebox("normal", "Button");
button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);
}
@@ -2459,9 +2477,9 @@ String VisualScriptEditor::get_name() {
return name;
}
-Ref<Texture2D> VisualScriptEditor::get_icon() {
+Ref<Texture2D> VisualScriptEditor::get_theme_icon() {
- return Control::get_icon("VisualScript", "EditorIcons");
+ return Control::get_theme_icon("VisualScript", "EditorIcons");
}
bool VisualScriptEditor::is_unsaved() {
@@ -3078,8 +3096,8 @@ void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_sl
void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from, const StringName &p_func_to, int p_id) {
Set<int> nodes_to_move;
- HashMap<int, Map<int, int> > seqconns_to_move; // from => List(outp, to)
- HashMap<int, Map<int, Pair<int, int> > > dataconns_to_move; // to => List(inp_p => from, outp)
+ HashMap<int, Map<int, int>> seqconns_to_move; // from => List(outp, to)
+ HashMap<int, Map<int, Pair<int, int>>> dataconns_to_move; // to => List(inp_p => from, outp)
nodes_to_move.insert(p_id);
Set<int> sequence_connections;
@@ -3087,7 +3105,7 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
List<VisualScript::SequenceConnection> sequence_conns;
script->get_sequence_connection_list(p_func_from, &sequence_conns);
- HashMap<int, Map<int, int> > seqcons; // from => List(out_p => to)
+ HashMap<int, Map<int, int>> seqcons; // from => List(out_p => to)
for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
int from = E->get().from_node;
@@ -3102,7 +3120,7 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
int conn = p_id;
List<int> stack;
- HashMap<int, Set<int> > seen; // from, outp
+ HashMap<int, Set<int>> seen; // from, outp
while (seqcons.has(conn)) {
for (auto E = seqcons[conn].front(); E; E = E->next()) {
if (seen.has(conn) && seen[conn].has(E->key())) {
@@ -3139,7 +3157,7 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
List<VisualScript::DataConnection> data_connections;
script->get_data_connection_list(p_func_from, &data_connections);
- HashMap<int, Map<int, Pair<int, int> > > connections;
+ HashMap<int, Map<int, Pair<int, int>>> connections;
for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
int from = E->get().from_node;
@@ -3148,14 +3166,14 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
int in_p = E->get().to_port;
if (!connections.has(to))
- connections.set(to, Map<int, Pair<int, int> >());
+ connections.set(to, Map<int, Pair<int, int>>());
connections[to].insert(in_p, Pair<int, int>(from, out_p));
}
// go through the HashMap and do all sorts of crazy ass stuff now...
Set<int> nodes_to_be_added;
for (Set<int>::Element *F = nodes_to_move.front(); F; F = F->next()) {
- HashMap<int, Set<int> > seen;
+ HashMap<int, Set<int>> seen;
List<int> stack;
int id = F->get();
while (connections.has(id)) {
@@ -3190,7 +3208,7 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
seen[id].insert(E->key());
stack.push_back(id);
if (!dataconns_to_move.has(id))
- dataconns_to_move.set(id, Map<int, Pair<int, int> >());
+ dataconns_to_move.set(id, Map<int, Pair<int, int>>());
dataconns_to_move[id].insert(E->key(), Pair<int, int>(E->get().first, E->get().second));
id = E->get().first;
nodes_to_be_added.insert(id);
@@ -3261,7 +3279,7 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
dataconns_to_move.get_key_list(&keys);
for (List<int>::Element *E = keys.front(); E; E = E->next()) {
int to_node = E->get(); // to_node
- for (Map<int, Pair<int, int> >::Element *F = dataconns_to_move[E->get()].front(); F; F = F->next()) {
+ for (Map<int, Pair<int, int>>::Element *F = dataconns_to_move[E->get()].front(); F; F = F->next()) {
int inp_p = F->key();
Pair<int, int> fro = F->get();
@@ -3447,7 +3465,7 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua
undo_redo->create_action(TTR("Connect Node Data"));
VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr());
- if (vnode_return != NULL && vnode_old->get_output_value_port_count() > 0) {
+ if (vnode_return != nullptr && vnode_old->get_output_value_port_count() > 0) {
vnode_return->set_enable_return_value(true);
}
if (vnode_old->get_output_value_port_count() <= 0) {
@@ -3713,11 +3731,11 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) {
VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr());
- if (vnode_operator != NULL && !vnode_operator->has_input_sequence_port()) {
+ if (vnode_operator != nullptr && !vnode_operator->has_input_sequence_port()) {
return;
}
VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr());
- if (vnode_constructor != NULL) {
+ if (vnode_constructor != nullptr) {
return;
}
if (vnode_old->get_output_sequence_port_count() <= 0) {
@@ -3889,7 +3907,7 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
}
}
- if (default_value_edit->edit(NULL, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {
+ if (default_value_edit->edit(nullptr, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {
if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT)
default_value_edit->popup_centered_ratio();
else
@@ -3917,7 +3935,9 @@ void VisualScriptEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));
+ variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED);
signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));
+ signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED);
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
@@ -3925,15 +3945,15 @@ void VisualScriptEditor::_notification(int p_what) {
return;
}
- edit_variable_edit->add_style_override("bg", get_stylebox("bg", "Tree"));
- edit_signal_edit->add_style_override("bg", get_stylebox("bg", "Tree"));
- func_input_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
+ edit_variable_edit->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
+ edit_signal_edit->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
+ func_input_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
bool dark_theme = tm->get_constant("dark_theme", "Editor");
- List<Pair<String, Color> > colors;
+ List<Pair<String, Color>> colors;
if (dark_theme) {
colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96)));
colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51)));
@@ -3950,7 +3970,7 @@ void VisualScriptEditor::_notification(int p_what) {
colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49)));
}
- for (List<Pair<String, Color> >::Element *E = colors.front(); E; E = E->next()) {
+ for (List<Pair<String, Color>>::Element *E = colors.front(); E; E = E->next()) {
Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
if (!sb.is_null()) {
Ref<StyleBoxFlat> frame_style = sb->duplicate();
@@ -4149,7 +4169,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
}
- for (Map<int, Ref<VisualScriptNode> >::Element *E = clipboard->nodes.front(); E; E = E->next()) {
+ for (Map<int, Ref<VisualScriptNode>>::Element *E = clipboard->nodes.front(); E; E = E->next()) {
Ref<VisualScriptNode> node = E->get()->duplicate();
@@ -4196,7 +4216,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
case EDIT_CREATE_FUNCTION: {
StringName function = "";
- Map<int, Ref<VisualScriptNode> > nodes;
+ Map<int, Ref<VisualScriptNode>> nodes;
Set<int> selections;
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
@@ -4252,7 +4272,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
// the user wants to connect the nodes
int top_nd = -1;
Vector2 top;
- for (Map<int, Ref<VisualScriptNode> >::Element *E = nodes.front(); E; E = E->next()) {
+ for (Map<int, Ref<VisualScriptNode>>::Element *E = nodes.front(); E; E = E->next()) {
Ref<VisualScriptNode> nd = script->get_node(function, E->key());
if (nd.is_valid() && nd->has_input_sequence_port()) {
if (top_nd < 0) {
@@ -4316,7 +4336,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
List<Variant::Type> inputs; // input types
- List<Pair<int, int> > input_connections;
+ List<Pair<int, int>> input_connections;
{
List<VisualScript::DataConnection> dats;
script->get_data_connection_list(function, &dats);
@@ -4359,7 +4379,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
// Move the nodes
- for (Map<int, Ref<VisualScriptNode> >::Element *E = nodes.front(); E; E = E->next()) {
+ for (Map<int, Ref<VisualScriptNode>>::Element *E = nodes.front(); E; E = E->next()) {
undo_redo->add_do_method(script.ptr(), "remove_node", function, E->key());
undo_redo->add_do_method(script.ptr(), "add_node", new_fn, E->key(), E->get(), script->get_node_position(function, E->key()));
@@ -4414,7 +4434,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
// * might make the system more intelligent by checking port from info.
int i = 0;
- List<Pair<int, int> >::Element *F = input_connections.front();
+ List<Pair<int, int>>::Element *F = input_connections.front();
for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) {
func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i);
undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, fn_id, i, F->get().first, F->get().second);
@@ -4479,9 +4499,9 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
TreeItem *root = members->get_root();
- Ref<Texture2D> del_icon = Control::get_icon("Remove", "EditorIcons");
+ Ref<Texture2D> del_icon = Control::get_theme_icon("Remove", "EditorIcons");
- Ref<Texture2D> edit_icon = Control::get_icon("Edit", "EditorIcons");
+ Ref<Texture2D> edit_icon = Control::get_theme_icon("Edit", "EditorIcons");
if (ti->get_parent() == root->get_children()) {
@@ -4578,7 +4598,7 @@ void VisualScriptEditor::_member_option(int p_option) {
} else if (p_option == MEMBER_EDIT) {
variable_editor->edit(name);
edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name);
- edit_variable_dialog->popup_centered_minsize(Size2(400, 200) * EDSCALE);
+ edit_variable_dialog->popup_centered(Size2(400, 200) * EDSCALE);
}
} break;
case MEMBER_SIGNAL: {
@@ -4599,7 +4619,7 @@ void VisualScriptEditor::_member_option(int p_option) {
} else if (p_option == MEMBER_EDIT) {
signal_editor->edit(name);
edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name);
- edit_signal_dialog->popup_centered_minsize(Size2(400, 300) * EDSCALE);
+ edit_signal_dialog->popup_centered(Size2(400, 300) * EDSCALE);
}
} break;
}
@@ -4629,6 +4649,7 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_input", &VisualScriptEditor::_input);
ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections);
+ ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);
ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search);
}
@@ -4687,10 +4708,9 @@ VisualScriptEditor::VisualScriptEditor() {
add_child(member_popup);
member_popup->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_member_option));
- function_name_edit = memnew(PopupDialog);
+ function_name_edit = memnew(AcceptDialog);
function_name_box = memnew(LineEdit);
function_name_edit->add_child(function_name_box);
- function_name_edit->set_h_size_flags(SIZE_EXPAND);
function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input));
function_name_box->set_expand_to_text_length(true);
add_child(function_name_edit);
@@ -4770,7 +4790,6 @@ VisualScriptEditor::VisualScriptEditor() {
func_input_scroll->add_child(func_input_vbox);
function_create_dialog = memnew(ConfirmationDialog);
- function_create_dialog->set_v_size_flags(SIZE_EXPAND_FILL);
function_create_dialog->set_title(TTR("Create Function"));
function_create_dialog->add_child(function_vb);
function_create_dialog->get_ok()->set_text(TTR("Create"));
@@ -4859,7 +4878,6 @@ VisualScriptEditor::VisualScriptEditor() {
new_connect_node_select = memnew(VisualScriptPropertySelector);
add_child(new_connect_node_select);
- new_connect_node_select->set_resizable(true);
new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node));
new_connect_node_select->get_cancel()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
@@ -4881,10 +4899,10 @@ static ScriptEditorBase *create_editor(const RES &p_resource) {
return memnew(VisualScriptEditor);
}
- return NULL;
+ return nullptr;
}
-VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard = NULL;
+VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard = nullptr;
void VisualScriptEditor::free_clipboard() {
if (clipboard)
@@ -4920,7 +4938,7 @@ Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_na
return node;
}
-_VisualScriptEditor *_VisualScriptEditor::singleton = NULL;
+_VisualScriptEditor *_VisualScriptEditor::singleton = nullptr;
Map<String, REF> _VisualScriptEditor::custom_nodes;
_VisualScriptEditor::_VisualScriptEditor() {
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 9a2a42b160..d9494e4d04 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -114,7 +114,7 @@ class VisualScriptEditor : public ScriptEditorBase {
UndoRedo *undo_redo;
Tree *members;
- PopupDialog *function_name_edit;
+ AcceptDialog *function_name_edit;
LineEdit *function_name_box;
Label *hint_text;
@@ -133,10 +133,10 @@ class VisualScriptEditor : public ScriptEditorBase {
String name;
Variant::Type ret;
bool ret_variant;
- Vector<Pair<Variant::Type, String> > args;
+ Vector<Pair<Variant::Type, String>> args;
};
- HashMap<StringName, Ref<StyleBox> > node_styles;
+ HashMap<StringName, Ref<StyleBox>> node_styles;
StringName edited_func;
StringName default_func;
@@ -153,7 +153,7 @@ class VisualScriptEditor : public ScriptEditorBase {
struct Clipboard {
- Map<int, Ref<VisualScriptNode> > nodes;
+ Map<int, Ref<VisualScriptNode>> nodes;
Map<int, Vector2> nodes_positions;
Set<VisualScript::SequenceConnection> sequence_connections;
@@ -298,7 +298,7 @@ public:
virtual Vector<String> get_functions();
virtual void reload_text();
virtual String get_name();
- virtual Ref<Texture2D> get_icon();
+ virtual Ref<Texture2D> get_theme_icon();
virtual bool is_unsaved();
virtual Variant get_edit_state();
virtual void set_edit_state(const Variant &p_state);
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index c52315a477..71ed483d65 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -652,12 +652,12 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
while (true) {
//keep appending stuff to expression
- ENode *expr = NULL;
+ ENode *expr = nullptr;
Token tk;
_get_token(tk);
if (error_set)
- return NULL;
+ return nullptr;
switch (tk.type) {
case TK_CURLY_BRACKET_OPEN: {
@@ -675,18 +675,18 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//parse an expression
ENode *expr2 = _parse_expression();
if (!expr2)
- return NULL;
+ return nullptr;
dn->dict.push_back(expr2);
_get_token(tk);
if (tk.type != TK_COLON) {
_set_error("Expected ':'");
- return NULL;
+ return nullptr;
}
expr2 = _parse_expression();
if (!expr2)
- return NULL;
+ return nullptr;
dn->dict.push_back(expr2);
@@ -719,7 +719,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//parse an expression
ENode *expr2 = _parse_expression();
if (!expr2)
- return NULL;
+ return nullptr;
an->array.push_back(expr2);
cofs = str_ofs;
@@ -739,11 +739,11 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//a suexpression
ENode *e = _parse_expression();
if (error_set)
- return NULL;
+ return nullptr;
_get_token(tk);
if (tk.type != TK_PARENTHESIS_CLOSE) {
_set_error("Expected ')'");
- return NULL;
+ return nullptr;
}
expr = e;
@@ -766,7 +766,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
expr = input;
} else {
_set_error("Invalid input identifier '" + what + "'. For script variables, use self (locals are for inputs)." + what);
- return NULL;
+ return nullptr;
}
} break;
case TK_SELF: {
@@ -786,7 +786,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
_get_token(tk);
if (tk.type != TK_PARENTHESIS_OPEN) {
_set_error("Expected '('");
- return NULL;
+ return nullptr;
}
ConstructorNode *constructor = alloc_node<ConstructorNode>();
@@ -803,7 +803,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//parse an expression
ENode *expr2 = _parse_expression();
if (!expr2)
- return NULL;
+ return nullptr;
constructor->arguments.push_back(expr2);
@@ -827,7 +827,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
_get_token(tk);
if (tk.type != TK_PARENTHESIS_OPEN) {
_set_error("Expected '('");
- return NULL;
+ return nullptr;
}
BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
@@ -844,7 +844,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//parse an expression
ENode *expr2 = _parse_expression();
if (!expr2)
- return NULL;
+ return nullptr;
bifunc->arguments.push_back(expr2);
@@ -886,7 +886,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
default: {
_set_error("Expected expression.");
- return NULL;
+ return nullptr;
} break;
}
@@ -896,7 +896,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
int cofs2 = str_ofs;
_get_token(tk);
if (error_set)
- return NULL;
+ return nullptr;
bool done = false;
@@ -909,14 +909,14 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
ENode *what = _parse_expression();
if (!what)
- return NULL;
+ return nullptr;
index->index = what;
_get_token(tk);
if (tk.type != TK_BRACKET_CLOSE) {
_set_error("Expected ']' at end of index.");
- return NULL;
+ return nullptr;
}
expr = index;
@@ -926,7 +926,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
_get_token(tk);
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier after '.'");
- return NULL;
+ return nullptr;
}
StringName identifier = tk.value;
@@ -950,7 +950,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//parse an expression
ENode *expr2 = _parse_expression();
if (!expr2)
- return NULL;
+ return nullptr;
func_call->arguments.push_back(expr2);
@@ -1000,7 +1000,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
int cofs = str_ofs;
_get_token(tk);
if (error_set)
- return NULL;
+ return nullptr;
Variant::Operator op = Variant::OP_MAX;
@@ -1107,7 +1107,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
default: {
_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
- return NULL;
+ return nullptr;
}
}
@@ -1124,7 +1124,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (next_op == -1) {
_set_error("Yet another parser bug....");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
// OK! create operator..
@@ -1137,7 +1137,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (expr_pos == expression.size()) {
//can happen..
_set_error("Unexpected end of expression...");
- return NULL;
+ return nullptr;
}
}
@@ -1147,7 +1147,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
OperatorNode *op = alloc_node<OperatorNode>();
op->op = expression[i].op;
op->nodes[0] = expression[i + 1].node;
- op->nodes[1] = NULL;
+ op->nodes[1] = nullptr;
expression.write[i].is_op = false;
expression.write[i].node = op;
expression.remove(i + 1);
@@ -1157,7 +1157,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (next_op < 1 || next_op >= (expression.size() - 1)) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
OperatorNode *op = alloc_node<OperatorNode>();
@@ -1166,7 +1166,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (expression[next_op - 1].is_op) {
_set_error("Parser bug...");
- ERR_FAIL_V(NULL);
+ ERR_FAIL_V(nullptr);
}
if (expression[next_op + 1].is_op) {
@@ -1176,7 +1176,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
// due to how precedence works, unaries will always disappear first
_set_error("Unexpected two consecutive operators.");
- return NULL;
+ return nullptr;
}
op->nodes[0] = expression[next_op - 1].node; //expression goes as left
@@ -1199,8 +1199,8 @@ bool VisualScriptExpression::_compile_expression() {
if (nodes) {
memdelete(nodes);
- nodes = NULL;
- root = NULL;
+ nodes = nullptr;
+ root = nullptr;
}
error_str = String();
@@ -1210,11 +1210,11 @@ bool VisualScriptExpression::_compile_expression() {
root = _parse_expression();
if (error_set) {
- root = NULL;
+ root = nullptr;
if (nodes) {
memdelete(nodes);
}
- nodes = NULL;
+ nodes = nullptr;
return true;
}
@@ -1478,8 +1478,8 @@ VisualScriptExpression::VisualScriptExpression() {
output_type = Variant::NIL;
expression_dirty = true;
error_set = true;
- root = NULL;
- nodes = NULL;
+ root = nullptr;
+ nodes = nullptr;
sequenced = false;
}
diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h
index d131713ef0..61b50ff99d 100644
--- a/modules/visual_script/visual_script_expression.h
+++ b/modules/visual_script/visual_script_expression.h
@@ -138,7 +138,7 @@ class VisualScriptExpression : public VisualScriptNode {
Type type;
- ENode() { next = NULL; }
+ ENode() { next = nullptr; }
virtual ~ENode() {
if (next) {
memdelete(next);
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 011432ef39..3b6ae369ae 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -58,7 +58,7 @@ bool VisualScriptFunctionCall::has_input_sequence_port() const {
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene)
- return NULL;
+ return nullptr;
Ref<Script> scr = p_current_node->get_script();
@@ -71,7 +71,7 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return n;
}
- return NULL;
+ return nullptr;
}
#endif
@@ -80,33 +80,33 @@ Node *VisualScriptFunctionCall::_get_base_node() const {
#ifdef TOOLS_ENABLED
Ref<Script> script = get_visual_script();
if (!script.is_valid())
- return NULL;
+ return nullptr;
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
if (!scene_tree)
- return NULL;
+ return nullptr;
Node *edited_scene = scene_tree->get_edited_scene_root();
if (!edited_scene)
- return NULL;
+ return nullptr;
Node *script_node = _find_script_node(edited_scene, edited_scene, script);
if (!script_node)
- return NULL;
+ return nullptr;
if (!script_node->has_node(base_path))
- return NULL;
+ return nullptr;
Node *path_to = script_node->get_node(base_path);
return path_to;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -955,34 +955,34 @@ Node *VisualScriptPropertySet::_get_base_node() const {
#ifdef TOOLS_ENABLED
Ref<Script> script = get_visual_script();
if (!script.is_valid())
- return NULL;
+ return nullptr;
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
if (!scene_tree)
- return NULL;
+ return nullptr;
Node *edited_scene = scene_tree->get_edited_scene_root();
if (!edited_scene)
- return NULL;
+ return nullptr;
Node *script_node = _find_script_node(edited_scene, edited_scene, script);
if (!script_node)
- return NULL;
+ return nullptr;
if (!script_node->has_node(base_path))
- return NULL;
+ return nullptr;
Node *path_to = script_node->get_node(base_path);
return path_to;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -1021,7 +1021,7 @@ void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const {
Variant v;
Callable::CallError ce;
- v = Variant::construct(pinfo.type, NULL, 0, ce);
+ v = Variant::construct(pinfo.type, nullptr, 0, ce);
Variant i = v.get(index);
pinfo.type = i.get_type();
}
@@ -1168,7 +1168,7 @@ void VisualScriptPropertySet::_update_cache() {
Variant v;
Callable::CallError ce;
- v = Variant::construct(basic_type, NULL, 0, ce);
+ v = Variant::construct(basic_type, nullptr, 0, ce);
List<PropertyInfo> pinfo;
v.get_property_list(&pinfo);
@@ -1185,7 +1185,7 @@ void VisualScriptPropertySet::_update_cache() {
StringName type;
Ref<Script> script;
- Node *node = NULL;
+ Node *node = nullptr;
if (call_mode == CALL_MODE_NODE_PATH) {
@@ -1410,7 +1410,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
if (property.name == "index") {
Callable::CallError ce;
- Variant v = Variant::construct(type_cache.type, NULL, 0, ce);
+ Variant v = Variant::construct(type_cache.type, nullptr, 0, ce);
List<PropertyInfo> plist;
v.get_property_list(&plist);
String options = "";
@@ -1735,34 +1735,34 @@ Node *VisualScriptPropertyGet::_get_base_node() const {
#ifdef TOOLS_ENABLED
Ref<Script> script = get_visual_script();
if (!script.is_valid())
- return NULL;
+ return nullptr;
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
if (!scene_tree)
- return NULL;
+ return nullptr;
Node *edited_scene = scene_tree->get_edited_scene_root();
if (!edited_scene)
- return NULL;
+ return nullptr;
Node *script_node = _find_script_node(edited_scene, edited_scene, script);
if (!script_node)
- return NULL;
+ return nullptr;
if (!script_node->has_node(base_path))
- return NULL;
+ return nullptr;
Node *path_to = script_node->get_node(base_path);
return path_to;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -1876,7 +1876,7 @@ void VisualScriptPropertyGet::_update_cache() {
Variant v;
Callable::CallError ce;
- v = Variant::construct(basic_type, NULL, 0, ce);
+ v = Variant::construct(basic_type, nullptr, 0, ce);
List<PropertyInfo> pinfo;
v.get_property_list(&pinfo);
@@ -1894,7 +1894,7 @@ void VisualScriptPropertyGet::_update_cache() {
StringName type;
Ref<Script> script;
- Node *node = NULL;
+ Node *node = nullptr;
if (call_mode == CALL_MODE_NODE_PATH) {
@@ -2125,7 +2125,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
if (property.name == "index") {
Callable::CallError ce;
- Variant v = Variant::construct(type_cache, NULL, 0, ce);
+ Variant v = Variant::construct(type_cache, nullptr, 0, ce);
List<PropertyInfo> plist;
v.get_property_list(&plist);
String options = "";
@@ -2501,7 +2501,7 @@ void register_visual_script_func_nodes() {
Variant::Type t = Variant::Type(i);
String type_name = Variant::get_type_name(t);
Callable::CallError ce;
- Variant vt = Variant::construct(t, NULL, 0, ce);
+ Variant vt = Variant::construct(t, nullptr, 0, ce);
List<MethodInfo> ml;
vt.get_method_list(&ml);
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index ea09c82013..c860e08943 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -32,7 +32,7 @@
#include "core/engine.h"
#include "core/global_constants.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "scene/main/node.h"
@@ -1483,7 +1483,7 @@ void VisualScriptConstant::set_constant_type(Variant::Type p_type) {
type = p_type;
Callable::CallError ce;
- value = Variant::construct(type, NULL, 0, ce);
+ value = Variant::construct(type, nullptr, 0, ce);
ports_changed_notify();
_change_notify();
}
@@ -2548,7 +2548,7 @@ VisualScriptNodeInstance *VisualScriptSceneNode::instance(VisualScriptInstance *
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene)
- return NULL;
+ return nullptr;
Ref<Script> scr = p_current_node->get_script();
@@ -2561,7 +2561,7 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return n;
}
- return NULL;
+ return nullptr;
}
#endif
@@ -3519,7 +3519,7 @@ VisualScriptConstructor::VisualScriptConstructor() {
type = Variant::NIL;
}
-static Map<String, Pair<Variant::Type, MethodInfo> > constructor_map;
+static Map<String, Pair<Variant::Type, MethodInfo>> constructor_map;
static Ref<VisualScriptNode> create_constructor_node(const String &p_name) {
@@ -3870,16 +3870,16 @@ public:
switch (mode) {
case VisualScriptInputAction::MODE_PRESSED: {
- *p_outputs[0] = Input::get_singleton()->is_action_pressed(action);
+ *p_outputs[0] = InputFilter::get_singleton()->is_action_pressed(action);
} break;
case VisualScriptInputAction::MODE_RELEASED: {
- *p_outputs[0] = !Input::get_singleton()->is_action_pressed(action);
+ *p_outputs[0] = !InputFilter::get_singleton()->is_action_pressed(action);
} break;
case VisualScriptInputAction::MODE_JUST_PRESSED: {
- *p_outputs[0] = Input::get_singleton()->is_action_just_pressed(action);
+ *p_outputs[0] = InputFilter::get_singleton()->is_action_just_pressed(action);
} break;
case VisualScriptInputAction::MODE_JUST_RELEASED: {
- *p_outputs[0] = Input::get_singleton()->is_action_just_released(action);
+ *p_outputs[0] = InputFilter::get_singleton()->is_action_just_released(action);
} break;
}
@@ -4006,7 +4006,7 @@ void VisualScriptDeconstruct::_update_elements() {
elements.clear();
Variant v;
Callable::CallError ce;
- v = Variant::construct(type, NULL, 0, ce);
+ v = Variant::construct(type, nullptr, 0, ce);
List<PropertyInfo> pinfo;
v.get_property_list(&pinfo);
@@ -4184,9 +4184,12 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2), create_node_deconst_typed<Variant::Type::VECTOR2>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2I), create_node_deconst_typed<Variant::Type::VECTOR2I>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3), create_node_deconst_typed<Variant::Type::VECTOR3>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3I), create_node_deconst_typed<Variant::Type::VECTOR3I>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::COLOR), create_node_deconst_typed<Variant::Type::COLOR>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2), create_node_deconst_typed<Variant::Type::RECT2>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>);
VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUAT), create_node_deconst_typed<Variant::Type::QUAT>);
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index d799f19143..f57853078d 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -39,7 +39,7 @@
#include "modules/visual_script/visual_script_func_nodes.h"
#include "modules/visual_script/visual_script_nodes.h"
#include "scene/main/node.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void VisualScriptPropertySelector::_text_changed(const String &p_newtext) {
_update_search();
@@ -97,37 +97,37 @@ void VisualScriptPropertySelector::_update_search() {
for (List<StringName>::Element *E = base_list.front(); E; E = E->next()) {
List<MethodInfo> methods;
List<PropertyInfo> props;
- TreeItem *category = NULL;
+ TreeItem *category = nullptr;
Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {
- Control::get_icon("Variant", "EditorIcons"),
- Control::get_icon("bool", "EditorIcons"),
- Control::get_icon("int", "EditorIcons"),
- Control::get_icon("float", "EditorIcons"),
- Control::get_icon("String", "EditorIcons"),
- Control::get_icon("Vector2", "EditorIcons"),
- Control::get_icon("Rect2", "EditorIcons"),
- Control::get_icon("Vector3", "EditorIcons"),
- Control::get_icon("Transform2D", "EditorIcons"),
- Control::get_icon("Plane", "EditorIcons"),
- Control::get_icon("Quat", "EditorIcons"),
- Control::get_icon("AABB", "EditorIcons"),
- Control::get_icon("Basis", "EditorIcons"),
- Control::get_icon("Transform", "EditorIcons"),
- Control::get_icon("Color", "EditorIcons"),
- Control::get_icon("Path", "EditorIcons"),
- Control::get_icon("RID", "EditorIcons"),
- Control::get_icon("Object", "EditorIcons"),
- Control::get_icon("Dictionary", "EditorIcons"),
- Control::get_icon("Array", "EditorIcons"),
- Control::get_icon("PackedByteArray", "EditorIcons"),
- Control::get_icon("PackedInt32Array", "EditorIcons"),
- Control::get_icon("PackedFloat32Array", "EditorIcons"),
- Control::get_icon("PackedInt64Array", "EditorIcons"),
- Control::get_icon("PackedFloat64Array", "EditorIcons"),
- Control::get_icon("PackedStringArray", "EditorIcons"),
- Control::get_icon("PackedVector2Array", "EditorIcons"),
- Control::get_icon("PackedVector3Array", "EditorIcons"),
- Control::get_icon("PackedColorArray", "EditorIcons")
+ vbc->get_theme_icon("Variant", "EditorIcons"),
+ vbc->get_theme_icon("bool", "EditorIcons"),
+ vbc->get_theme_icon("int", "EditorIcons"),
+ vbc->get_theme_icon("float", "EditorIcons"),
+ vbc->get_theme_icon("String", "EditorIcons"),
+ vbc->get_theme_icon("Vector2", "EditorIcons"),
+ vbc->get_theme_icon("Rect2", "EditorIcons"),
+ vbc->get_theme_icon("Vector3", "EditorIcons"),
+ vbc->get_theme_icon("Transform2D", "EditorIcons"),
+ vbc->get_theme_icon("Plane", "EditorIcons"),
+ vbc->get_theme_icon("Quat", "EditorIcons"),
+ vbc->get_theme_icon("AABB", "EditorIcons"),
+ vbc->get_theme_icon("Basis", "EditorIcons"),
+ vbc->get_theme_icon("Transform", "EditorIcons"),
+ vbc->get_theme_icon("Color", "EditorIcons"),
+ vbc->get_theme_icon("Path", "EditorIcons"),
+ vbc->get_theme_icon("RID", "EditorIcons"),
+ vbc->get_theme_icon("Object", "EditorIcons"),
+ vbc->get_theme_icon("Dictionary", "EditorIcons"),
+ vbc->get_theme_icon("Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedByteArray", "EditorIcons"),
+ vbc->get_theme_icon("PackedInt32Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedFloat32Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedInt64Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedFloat64Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedStringArray", "EditorIcons"),
+ vbc->get_theme_icon("PackedVector2Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedVector3Array", "EditorIcons"),
+ vbc->get_theme_icon("PackedColorArray", "EditorIcons")
};
{
String b = String(E->get());
@@ -196,7 +196,7 @@ void VisualScriptPropertySelector::_update_search() {
if (type != Variant::NIL) {
Variant v;
Callable::CallError ce;
- v = Variant::construct(type, NULL, 0, ce);
+ v = Variant::construct(type, nullptr, 0, ce);
v.get_method_list(&methods);
} else {
@@ -252,7 +252,7 @@ void VisualScriptPropertySelector::_update_search() {
TreeItem *item = search_options->create_item(category ? category : root);
item->set_text(0, desc);
- item->set_icon(0, get_icon("MemberMethod", "EditorIcons"));
+ item->set_icon(0, vbc->get_theme_icon("MemberMethod", "EditorIcons"));
item->set_metadata(0, name);
item->set_selectable(0, true);
@@ -264,7 +264,7 @@ void VisualScriptPropertySelector::_update_search() {
item->set_metadata(2, connecting);
}
- if (category && category->get_children() == NULL) {
+ if (category && category->get_children() == nullptr) {
memdelete(category); //old category was unused
}
}
@@ -304,19 +304,19 @@ void VisualScriptPropertySelector::_update_search() {
}
TreeItem *selected_item = search_options->search_item_text(search_box->get_text());
- if (!found && selected_item != NULL) {
+ if (!found && selected_item != nullptr) {
selected_item->select(0);
found = true;
}
- get_ok()->set_disabled(root->get_children() == NULL);
+ get_ok()->set_disabled(root->get_children() == nullptr);
}
void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
if (search_input == String() || text.findn(search_input) != -1) {
TreeItem *item = search_options->create_item(root);
item->set_text(0, text);
- item->set_icon(0, get_icon("VisualScript", "EditorIcons"));
+ item->set_icon(0, vbc->get_theme_icon("VisualScript", "EditorIcons"));
item->set_metadata(0, name);
item->set_metadata(1, "action");
item->set_selectable(0, true);
@@ -399,7 +399,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt
}
item->set_text(0, type_name + String("").join(desc));
- item->set_icon(0, get_icon("VisualScript", "EditorIcons"));
+ item->set_icon(0, vbc->get_theme_icon("VisualScript", "EditorIcons"));
item->set_selectable(0, true);
item->set_metadata(0, E->get());
item->set_selectable(0, true);
@@ -416,7 +416,7 @@ void VisualScriptPropertySelector::_confirmed() {
if (!ti)
return;
emit_signal("selected", ti->get_metadata(0), ti->get_metadata(1), ti->get_metadata(2));
- hide();
+ set_visible(false);
}
void VisualScriptPropertySelector::_item_selected() {
@@ -481,7 +481,7 @@ void VisualScriptPropertySelector::_item_selected() {
List<String> *names = memnew(List<String>);
VisualScriptLanguage::singleton->get_registered_node_names(names);
- if (names->find(name) != NULL) {
+ if (names->find(name) != nullptr) {
Ref<VisualScriptOperator> operator_node = VisualScriptLanguage::singleton->create_node_from_name(name);
if (operator_node.is_valid()) {
Map<String, DocData::ClassDoc>::Element *F = dd->class_list.find(operator_node->get_class_name());
@@ -519,7 +519,7 @@ void VisualScriptPropertySelector::_item_selected() {
}
void VisualScriptPropertySelector::_hide_requested() {
- _closed(); // From WindowDialog.
+ _cancel_pressed(); // From AcceptDialog.
}
void VisualScriptPropertySelector::_notification(int p_what) {
@@ -536,7 +536,7 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_
selected = p_current;
type = Variant::NIL;
properties = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = p_virtuals_only;
show_window(.5f);
@@ -561,7 +561,7 @@ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, c
type = Variant::NIL;
properties = true;
visual_script_generic = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = p_virtuals_only;
show_window(.5f);
@@ -585,7 +585,7 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip
script = p_script->get_instance_id();
properties = true;
visual_script_generic = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
show_window(.5f);
@@ -607,7 +607,7 @@ void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type,
type = p_type;
properties = true;
visual_script_generic = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
show_window(.5f);
@@ -628,7 +628,7 @@ void VisualScriptPropertySelector::select_from_action(const String &p_type, cons
type = Variant::NIL;
properties = false;
visual_script_generic = false;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
show_window(.5f);
@@ -670,7 +670,7 @@ void VisualScriptPropertySelector::select_from_visual_script(const String &p_bas
type = Variant::NIL;
properties = true;
visual_script_generic = true;
- instance = NULL;
+ instance = nullptr;
virtuals_only = false;
show_window(.5f);
if (clear_text)
@@ -684,12 +684,8 @@ void VisualScriptPropertySelector::select_from_visual_script(const String &p_bas
}
void VisualScriptPropertySelector::show_window(float p_screen_ratio) {
- Rect2 rect;
- Point2 window_size = get_viewport_rect().size;
- rect.size = (window_size * p_screen_ratio).floor();
- rect.size.x = rect.size.x / 2.2f;
- rect.position = ((window_size - rect.size) / 2.0f).floor();
- popup(rect);
+
+ popup_centered_ratio(p_screen_ratio);
}
void VisualScriptPropertySelector::_bind_methods() {
@@ -699,7 +695,7 @@ void VisualScriptPropertySelector::_bind_methods() {
VisualScriptPropertySelector::VisualScriptPropertySelector() {
- VBoxContainer *vbc = memnew(VBoxContainer);
+ vbc = memnew(VBoxContainer);
add_child(vbc);
//set_child_rect(vbc);
search_box = memnew(LineEdit);
diff --git a/modules/visual_script/visual_script_property_selector.h b/modules/visual_script/visual_script_property_selector.h
index f438ca1f5b..cc49b2863d 100644
--- a/modules/visual_script/visual_script_property_selector.h
+++ b/modules/visual_script/visual_script_property_selector.h
@@ -64,6 +64,7 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
Object *instance;
bool virtuals_only;
bool seq_connect;
+ VBoxContainer *vbc;
Vector<Variant::Type> type_filter;
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index 858074742e..b300aec385 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -228,7 +228,7 @@ bool VisualScriptYieldSignal::has_input_sequence_port() const {
static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene)
- return NULL;
+ return nullptr;
Ref<Script> scr = p_current_node->get_script();
@@ -241,7 +241,7 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return n;
}
- return NULL;
+ return nullptr;
}
#endif
@@ -250,33 +250,33 @@ Node *VisualScriptYieldSignal::_get_base_node() const {
#ifdef TOOLS_ENABLED
Ref<Script> script = get_visual_script();
if (!script.is_valid())
- return NULL;
+ return nullptr;
MainLoop *main_loop = OS::get_singleton()->get_main_loop();
SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
if (!scene_tree)
- return NULL;
+ return nullptr;
Node *edited_scene = scene_tree->get_edited_scene_root();
if (!edited_scene)
- return NULL;
+ return nullptr;
Node *script_node = _find_script_node(edited_scene, edited_scene, script);
if (!script_node)
- return NULL;
+ return nullptr;
if (!script_node->has_node(base_path))
- return NULL;
+ return nullptr;
Node *path_to = script_node->get_node(base_path);
return path_to;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -516,7 +516,7 @@ public:
} else {
//yield
- Object *object = NULL;
+ Object *object = nullptr;
switch (call_mode) {
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index 3824fdd789..05d46757d3 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -1,18 +1,21 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
+
+# Only kept to build the thirdparty library used by the theora and webm
+# modules. We now use stb_vorbis for AudioStreamOGGVorbis.
env_vorbis = env_modules.Clone()
stub = True
# Thirdparty source files
-if env['builtin_libvorbis']:
+if env["builtin_libvorbis"]:
thirdparty_dir = "#thirdparty/libvorbis/"
thirdparty_sources = [
- #"analysis.c",
- #"barkmel.c",
+ # "analysis.c",
+ # "barkmel.c",
"bitrate.c",
"block.c",
"codebook.c",
@@ -26,14 +29,14 @@ if env['builtin_libvorbis']:
"mapping0.c",
"mdct.c",
"psy.c",
- #"psytune.c",
+ # "psytune.c",
"registry.c",
"res0.c",
"sharedbook.c",
"smallft.c",
"synthesis.c",
- #"tone.c",
- #"vorbisenc.c",
+ # "tone.c",
+ # "vorbisenc.c",
"vorbisfile.c",
"window.c",
]
@@ -43,16 +46,12 @@ if env['builtin_libvorbis']:
env_vorbis.Prepend(CPPPATH=[thirdparty_dir])
# also requires libogg
- if env['builtin_libogg']:
+ if env["builtin_libogg"]:
env_vorbis.Prepend(CPPPATH=["#thirdparty/libogg"])
env_thirdparty = env_vorbis.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
-if not stub:
- # Module files
- env_vorbis.add_source_files(env.modules_sources, "*.cpp")
-else:
- # Module files
- env_vorbis.add_source_files(env.modules_sources, "stub/register_types.cpp")
+# Module files
+env_vorbis.add_source_files(env.modules_sources, "register_types.cpp")
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
deleted file mode 100644
index 1e8ee9b17e..0000000000
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-/*************************************************************************/
-/* audio_stream_ogg_vorbis.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "audio_stream_ogg_vorbis.h"
-
-size_t AudioStreamPlaybackOGGVorbis::_ov_read_func(void *p_dst, size_t p_data, size_t p_count, void *_f) {
-
- //printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f);
- FileAccess *fa = (FileAccess *)_f;
- size_t read_total = p_data * p_count;
-
- if (fa->eof_reached())
- return 0;
-
- uint8_t *dst = (uint8_t *)p_dst;
-
- int read = fa->get_buffer(dst, read_total);
-
- return read;
-}
-
-int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f, ogg_int64_t offs, int whence) {
-
- //printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence);
-
-#ifdef SEEK_SET
- //printf("seek set defined\n");
- FileAccess *fa = (FileAccess *)_f;
-
- if (whence == SEEK_SET) {
-
- fa->seek(offs);
- } else if (whence == SEEK_CUR) {
-
- fa->seek(fa->get_position() + offs);
- } else if (whence == SEEK_END) {
-
- fa->seek_end(offs);
- } else {
-
- ERR_PRINT("Vorbis seek function failure: Unexpected value in _whence\n");
- }
- int ret = fa->eof_reached() ? -1 : 0;
- //printf("returning %i\n",ret);
- return ret;
-
-#else
- return -1; // no seeking
-#endif
-}
-int AudioStreamPlaybackOGGVorbis::_ov_close_func(void *_f) {
-
- //printf("close %p\n",_f);
- if (!_f)
- return 0;
- FileAccess *fa = (FileAccess *)_f;
- if (fa->is_open())
- fa->close();
- return 0;
-}
-long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) {
-
- //printf("close %p\n",_f);
-
- FileAccess *fa = (FileAccess *)_f;
- return fa->get_position();
-}
-
-int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_buffer, int p_frames) {
-
- if (!playing)
- return 0;
-
- int total = p_frames;
- while (true) {
-
- int todo = p_frames;
-
- if (todo < MIN_MIX) {
- break;
- }
-
-#ifdef BIG_ENDIAN_ENABLED
- long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, &current_section);
-#else
- long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 0, 2, 1, &current_section);
-#endif
-
- if (ret < 0) {
-
- playing = false;
- ERR_BREAK_MSG(ret < 0, "Error reading OGG Vorbis file: " + file + ".");
- } else if (ret == 0) { // end of song, reload?
-
- ov_clear(&vf);
-
- _close_file();
-
- if (!has_loop()) {
-
- playing = false;
- repeats = 1;
- break;
- }
-
- f = FileAccess::open(file, FileAccess::READ);
-
- int errv = ov_open_callbacks(f, &vf, NULL, 0, _ov_callbacks);
- if (errv != 0) {
- playing = false;
- break; // :(
- }
-
- if (loop_restart_time) {
- bool ok = ov_time_seek(&vf, loop_restart_time) == 0;
- if (!ok) {
- playing = false;
- ERR_PRINT("Loop restart time rejected");
- }
-
- frames_mixed = stream_srate * loop_restart_time;
- } else {
-
- frames_mixed = 0;
- }
- repeats++;
- continue;
- }
-
- ret /= stream_channels;
- ret /= sizeof(int16_t);
-
- frames_mixed += ret;
-
- p_buffer += ret * stream_channels;
- p_frames -= ret;
- }
-
- return total - p_frames;
-}
-
-void AudioStreamPlaybackOGGVorbis::play(float p_from) {
-
- if (playing)
- stop();
-
- if (_load_stream() != OK)
- return;
-
- frames_mixed = 0;
- playing = true;
- if (p_from > 0) {
- seek(p_from);
- }
-}
-
-void AudioStreamPlaybackOGGVorbis::_close_file() {
-
- if (f) {
-
- memdelete(f);
- f = NULL;
- }
-}
-
-bool AudioStreamPlaybackOGGVorbis::is_playing() const {
- return playing;
-}
-void AudioStreamPlaybackOGGVorbis::stop() {
-
- _clear_stream();
- playing = false;
- //_clear();
-}
-
-float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
-
- int32_t frames = int32_t(frames_mixed);
- if (frames < 0)
- frames = 0;
- return double(frames) / stream_srate;
-}
-
-void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
-
- if (!playing)
- return;
- bool ok = ov_time_seek(&vf, p_time) == 0;
- ERR_FAIL_COND(!ok);
- frames_mixed = stream_srate * p_time;
-}
-
-String AudioStreamPlaybackOGGVorbis::get_stream_name() const {
-
- return "";
-}
-
-void AudioStreamPlaybackOGGVorbis::set_loop(bool p_enable) {
-
- loops = p_enable;
-}
-
-bool AudioStreamPlaybackOGGVorbis::has_loop() const {
-
- return loops;
-}
-
-int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
- return repeats;
-}
-
-Error AudioStreamPlaybackOGGVorbis::set_file(const String &p_file) {
-
- file = p_file;
- stream_valid = false;
- Error err;
- f = FileAccess::open(file, FileAccess::READ, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + p_file + "'.");
-
- int errv = ov_open_callbacks(f, &vf, NULL, 0, _ov_callbacks);
- switch (errv) {
-
- case OV_EREAD: { // - A read from media returned an error.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CANT_READ);
- } break;
- case OV_EVERSION: // - Vorbis version mismatch.
- case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
- } break;
- case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- } break;
- case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_BUG);
- } break;
- }
- const vorbis_info *vinfo = ov_info(&vf, -1);
- stream_channels = vinfo->channels;
- stream_srate = vinfo->rate;
- length = ov_time_total(&vf, -1);
- ov_clear(&vf);
- memdelete(f);
- f = NULL;
- stream_valid = true;
-
- return OK;
-}
-
-Error AudioStreamPlaybackOGGVorbis::_load_stream() {
-
- ERR_FAIL_COND_V(!stream_valid, ERR_UNCONFIGURED);
-
- _clear_stream();
- if (file == "")
- return ERR_INVALID_DATA;
-
- Error err;
- f = FileAccess::open(file, FileAccess::READ, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + file + "'.");
-
- int errv = ov_open_callbacks(f, &vf, NULL, 0, _ov_callbacks);
- switch (errv) {
-
- case OV_EREAD: { // - A read from media returned an error.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CANT_READ);
- } break;
- case OV_EVERSION: // - Vorbis version mismatch.
- case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
- } break;
- case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_FILE_CORRUPT);
- } break;
- case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
- memdelete(f);
- f = NULL;
- ERR_FAIL_V(ERR_BUG);
- } break;
- }
- repeats = 0;
- stream_loaded = true;
-
- return OK;
-}
-
-float AudioStreamPlaybackOGGVorbis::get_length() const {
-
- if (!stream_loaded) {
- if (const_cast<AudioStreamPlaybackOGGVorbis *>(this)->_load_stream() != OK)
- return 0;
- }
- return length;
-}
-
-void AudioStreamPlaybackOGGVorbis::_clear_stream() {
-
- if (!stream_loaded)
- return;
-
- ov_clear(&vf);
- _close_file();
-
- stream_loaded = false;
- //stream_channels=1;
- playing = false;
-}
-
-void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) {
-
- paused = p_paused;
-}
-
-bool AudioStreamPlaybackOGGVorbis::is_paused() const {
-
- return paused;
-}
-
-AudioStreamPlaybackOGGVorbis::AudioStreamPlaybackOGGVorbis() {
-
- loops = false;
- playing = false;
- _ov_callbacks.read_func = _ov_read_func;
- _ov_callbacks.seek_func = _ov_seek_func;
- _ov_callbacks.close_func = _ov_close_func;
- _ov_callbacks.tell_func = _ov_tell_func;
- f = NULL;
- stream_loaded = false;
- stream_valid = false;
- repeats = 0;
- paused = true;
- stream_channels = 0;
- stream_srate = 0;
- current_section = 0;
- length = 0;
- loop_restart_time = 0;
-}
-
-AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
-
- _clear_stream();
-}
-
-RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
- if (r_error)
- *r_error = OK;
-
- AudioStreamOGGVorbis *ogg_stream = memnew(AudioStreamOGGVorbis);
- ogg_stream->set_file(p_path);
- return Ref<AudioStreamOGGVorbis>(ogg_stream);
-}
-
-void ResourceFormatLoaderAudioStreamOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("ogg");
-}
-String ResourceFormatLoaderAudioStreamOGGVorbis::get_resource_type(const String &p_path) const {
-
- if (p_path.get_extension().to_lower() == "ogg")
- return "AudioStreamOGGVorbis";
- return "";
-}
-
-bool ResourceFormatLoaderAudioStreamOGGVorbis::handles_type(const String &p_type) const {
- return (p_type == "AudioStream" || p_type == "AudioStreamOGG" || p_type == "AudioStreamOGGVorbis");
-}
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h
deleted file mode 100644
index db621f88d2..0000000000
--- a/modules/vorbis/audio_stream_ogg_vorbis.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*************************************************************************/
-/* audio_stream_ogg_vorbis.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 AUDIO_STREAM_OGG_VORBIS_H
-#define AUDIO_STREAM_OGG_VORBIS_H
-
-#include "core/io/resource_loader.h"
-#include "core/os/file_access.h"
-#include "core/os/thread_safe.h"
-#include "scene/resources/audio_stream.h"
-
-#include <vorbis/vorbisfile.h>
-
-class AudioStreamPlaybackOGGVorbis : public AudioStreamPlayback {
-
- GDCLASS(AudioStreamPlaybackOGGVorbis, AudioStreamPlayback);
-
- enum {
- MIN_MIX = 1024
- };
-
- FileAccess *f;
-
- ov_callbacks _ov_callbacks;
- float length;
- static size_t _ov_read_func(void *p_dst, size_t p_data, size_t p_count, void *_f);
- static int _ov_seek_func(void *_f, ogg_int64_t offs, int whence);
- static int _ov_close_func(void *_f);
- static long _ov_tell_func(void *_f);
-
- String file;
- int64_t frames_mixed;
-
- bool stream_loaded;
- volatile bool playing;
- OggVorbis_File vf;
- int stream_channels;
- int stream_srate;
- int current_section;
-
- bool paused;
- bool loops;
- int repeats;
-
- Error _load_stream();
- void _clear_stream();
- void _close_file();
-
- bool stream_valid;
- float loop_restart_time;
-
-public:
- Error set_file(const String &p_file);
-
- virtual void play(float p_from = 0);
- virtual void stop();
- virtual bool is_playing() const;
-
- virtual void set_loop_restart_time(float p_time) { loop_restart_time = p_time; }
-
- virtual void set_paused(bool p_paused);
- virtual bool is_paused() const;
-
- virtual void set_loop(bool p_enable);
- virtual bool has_loop() const;
-
- virtual float get_length() const;
-
- virtual String get_stream_name() const;
-
- virtual int get_loop_count() const;
-
- virtual float get_playback_position() const;
- virtual void seek(float p_time);
-
- virtual int get_channels() const { return stream_channels; }
- virtual int get_mix_rate() const { return stream_srate; }
-
- virtual int get_minimum_buffer_size() const { return 0; }
- virtual int mix(int16_t *p_buffer, int p_frames);
-
- AudioStreamPlaybackOGGVorbis();
- ~AudioStreamPlaybackOGGVorbis();
-};
-
-class AudioStreamOGGVorbis : public AudioStream {
-
- GDCLASS(AudioStreamOGGVorbis, AudioStream);
-
- String file;
-
-public:
- Ref<AudioStreamPlayback> instance_playback() {
- Ref<AudioStreamPlaybackOGGVorbis> pb = memnew(AudioStreamPlaybackOGGVorbis);
- pb->set_file(file);
- return pb;
- }
-
- void set_file(const String &p_file) { file = p_file; }
-};
-
-class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = nullptr);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
-#endif // AUDIO_STREAM_OGG_H
diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/vorbis/config.py
+++ b/modules/vorbis/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp
index de055551ad..8874b3887b 100644
--- a/modules/vorbis/register_types.cpp
+++ b/modules/vorbis/register_types.cpp
@@ -30,19 +30,8 @@
#include "register_types.h"
-#include "audio_stream_ogg_vorbis.h"
+// Dummy module as libvorbis is needed by other modules (theora ...)
-static Ref<ResourceFormatLoaderAudioStreamOGGVorbis> vorbis_stream_loader;
+void register_vorbis_types() {}
-void register_vorbis_types() {
-
- vorbis_stream_loader.instance();
- ResourceLoader::add_resource_format_loader(vorbis_stream_loader);
- ClassDB::register_class<AudioStreamOGGVorbis>();
-}
-
-void unregister_vorbis_types() {
-
- ResourceLoader::remove_resource_format_loader(vorbis_stream_loader);
- vorbis_stream_loader.unref();
-}
+void unregister_vorbis_types() {}
diff --git a/modules/vorbis/register_types.h b/modules/vorbis/register_types.h
index 83d4904a87..7fa0dfdeef 100644
--- a/modules/vorbis/register_types.h
+++ b/modules/vorbis/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef VORBIS_REGISTER_TYPES_H
+#define VORBIS_REGISTER_TYPES_H
+
void register_vorbis_types();
void unregister_vorbis_types();
+
+#endif // VORBIS_REGISTER_TYPES_H
diff --git a/modules/vorbis/stub/register_types.cpp b/modules/vorbis/stub/register_types.cpp
deleted file mode 100644
index 8874b3887b..0000000000
--- a/modules/vorbis/stub/register_types.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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"
-
-// Dummy module as libvorbis is needed by other modules (theora ...)
-
-void register_vorbis_types() {}
-
-void unregister_vorbis_types() {}
diff --git a/modules/vorbis/stub/register_types.h b/modules/vorbis/stub/register_types.h
deleted file mode 100644
index 83d4904a87..0000000000
--- a/modules/vorbis/stub/register_types.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-void register_vorbis_types();
-void unregister_vorbis_types();
diff --git a/modules/webm/SCsub b/modules/webm/SCsub
index 32e6727656..247b4ead37 100644
--- a/modules/webm/SCsub
+++ b/modules/webm/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_webm = env_modules.Clone()
@@ -18,14 +18,14 @@ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_webm.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "libwebm/"])
# also requires libogg, libvorbis and libopus
-if env['builtin_libogg']:
+if env["builtin_libogg"]:
env_webm.Prepend(CPPPATH=["#thirdparty/libogg"])
-if env['builtin_libvorbis']:
+if env["builtin_libvorbis"]:
env_webm.Prepend(CPPPATH=["#thirdparty/libvorbis"])
-if env['builtin_opus']:
+if env["builtin_opus"]:
env_webm.Prepend(CPPPATH=["#thirdparty/opus"])
-if env['builtin_libvpx']:
+if env["builtin_libvpx"]:
env_webm.Prepend(CPPPATH=["#thirdparty/libvpx"])
SConscript("libvpx/SCsub")
diff --git a/modules/webm/config.py b/modules/webm/config.py
index ba4dcce2f5..93b49d177a 100644
--- a/modules/webm/config.py
+++ b/modules/webm/config.py
@@ -1,13 +1,16 @@
def can_build(env, platform):
- return platform not in ['iphone']
+ return platform not in ["iphone"]
+
def configure(env):
pass
+
def get_doc_classes():
return [
"VideoStreamWebm",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index 14fa6c1268..dd6866ad0e 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
# Thirdparty sources
@@ -9,9 +9,7 @@ libvpx_dir = "#thirdparty/libvpx/"
libvpx_sources = [
"vp8/vp8_dx_iface.c",
-
"vp8/common/generic/systemdependent.c",
-
"vp8/common/alloccommon.c",
"vp8/common/blockd.c",
"vp8/common/copy_c.c",
@@ -37,16 +35,12 @@ libvpx_sources = [
"vp8/common/swapyv12buffer.c",
"vp8/common/treecoder.c",
"vp8/common/vp8_loopfilter.c",
-
"vp8/decoder/dboolhuff.c",
"vp8/decoder/decodeframe.c",
"vp8/decoder/decodemv.c",
"vp8/decoder/detokenize.c",
"vp8/decoder/onyxd_if.c",
-
-
"vp9/vp9_dx_iface.c",
-
"vp9/common/vp9_alloccommon.c",
"vp9/common/vp9_blockd.c",
"vp9/common/vp9_common_data.c",
@@ -69,21 +63,16 @@ libvpx_sources = [
"vp9/common/vp9_seg_common.c",
"vp9/common/vp9_thread_common.c",
"vp9/common/vp9_tile_common.c",
-
"vp9/decoder/vp9_decodeframe.c",
"vp9/decoder/vp9_decodemv.c",
"vp9/decoder/vp9_decoder.c",
"vp9/decoder/vp9_detokenize.c",
"vp9/decoder/vp9_dsubexp.c",
"vp9/decoder/vp9_dthread.c",
-
-
"vpx/src/vpx_codec.c",
"vpx/src/vpx_decoder.c",
"vpx/src/vpx_image.c",
"vpx/src/vpx_psnr.c",
-
-
"vpx_dsp/bitreader.c",
"vpx_dsp/bitreader_buffer.c",
"vpx_dsp/intrapred.c",
@@ -92,18 +81,11 @@ libvpx_sources = [
"vpx_dsp/prob.c",
"vpx_dsp/vpx_convolve.c",
"vpx_dsp/vpx_dsp_rtcd.c",
-
-
"vpx_mem/vpx_mem.c",
-
-
"vpx_scale/vpx_scale_rtcd.c",
-
"vpx_scale/generic/yv12config.c",
"vpx_scale/generic/yv12extend.c",
-
-
- "vpx_util/vpx_thread.c"
+ "vpx_util/vpx_thread.c",
]
libvpx_sources_mt = [
@@ -114,29 +96,23 @@ libvpx_sources_intrin_x86 = [
"vp8/common/x86/filter_x86.c",
"vp8/common/x86/loopfilter_x86.c",
"vp8/common/x86/vp8_asm_stubs.c",
-
-
- "vpx_dsp/x86/vpx_asm_stubs.c"
+ "vpx_dsp/x86/vpx_asm_stubs.c",
]
libvpx_sources_intrin_x86_mmx = [
"vp8/common/x86/idct_blk_mmx.c",
]
libvpx_sources_intrin_x86_sse2 = [
"vp8/common/x86/idct_blk_sse2.c",
-
-
"vp9/common/x86/vp9_idct_intrin_sse2.c",
-
-
"vpx_dsp/x86/inv_txfm_sse2.c",
"vpx_dsp/x86/loopfilter_sse2.c",
]
libvpx_sources_intrin_x86_ssse3 = [
- "vpx_dsp/x86/vpx_subpixel_8t_intrin_ssse3.c"
+ "vpx_dsp/x86/vpx_subpixel_8t_intrin_ssse3.c",
]
libvpx_sources_intrin_x86_avx2 = [
"vpx_dsp/x86/loopfilter_avx2.c",
- "vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c"
+ "vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c",
]
libvpx_sources_x86asm = [
"vp8/common/x86/copy_sse2.asm",
@@ -153,8 +129,6 @@ libvpx_sources_x86asm = [
"vp8/common/x86/subpixel_sse2.asm",
"vp8/common/x86/subpixel_ssse3.asm",
"vp8/common/x86/vp8_loopfilter_mmx.asm",
-
-
"vpx_dsp/x86/intrapred_sse2.asm",
"vpx_dsp/x86/intrapred_ssse3.asm",
"vpx_dsp/x86/inv_wht_sse2.asm",
@@ -163,21 +137,15 @@ libvpx_sources_x86asm = [
"vpx_dsp/x86/vpx_subpixel_8t_ssse3.asm",
"vpx_dsp/x86/vpx_subpixel_bilinear_sse2.asm",
"vpx_dsp/x86/vpx_subpixel_bilinear_ssse3.asm",
-
-
- "vpx_ports/emms.asm"
+ "vpx_ports/emms.asm",
]
libvpx_sources_x86_64asm = [
"vp8/common/x86/loopfilter_block_sse2_x86_64.asm",
-
-
- "vpx_dsp/x86/inv_txfm_ssse3_x86_64.asm"
+ "vpx_dsp/x86/inv_txfm_ssse3_x86_64.asm",
]
libvpx_sources_arm = [
"vpx_ports/arm_cpudetect.c",
-
-
"vp8/common/arm/loopfilter_arm.c",
]
libvpx_sources_arm_neon = [
@@ -196,12 +164,8 @@ libvpx_sources_arm_neon = [
"vp8/common/arm/neon/shortidct4x4llm_neon.c",
"vp8/common/arm/neon/sixtappredict_neon.c",
"vp8/common/arm/neon/vp8_loopfilter_neon.c",
-
-
"vp9/common/arm/neon/vp9_iht4x4_add_neon.c",
"vp9/common/arm/neon/vp9_iht8x8_add_neon.c",
-
-
"vpx_dsp/arm/idct16x16_1_add_neon.c",
"vpx_dsp/arm/idct16x16_add_neon.c",
"vpx_dsp/arm/idct16x16_neon.c",
@@ -220,22 +184,22 @@ libvpx_sources_arm_neon = [
"vpx_dsp/arm/vpx_convolve8_neon.c",
"vpx_dsp/arm/vpx_convolve_avg_neon.c",
"vpx_dsp/arm/vpx_convolve_copy_neon.c",
- "vpx_dsp/arm/vpx_convolve_neon.c"
+ "vpx_dsp/arm/vpx_convolve_neon.c",
]
libvpx_sources_arm_neon_gas = [
"vpx_dsp/arm/gas/intrapred_neon_asm.s",
"vpx_dsp/arm/gas/loopfilter_mb_neon.s",
- "vpx_dsp/arm/gas/save_reg_neon.s"
+ "vpx_dsp/arm/gas/save_reg_neon.s",
]
libvpx_sources_arm_neon_armasm_ms = [
"vpx_dsp/arm/armasm_ms/intrapred_neon_asm.asm",
"vpx_dsp/arm/armasm_ms/loopfilter_mb_neon.asm",
- "vpx_dsp/arm/armasm_ms/save_reg_neon.asm"
+ "vpx_dsp/arm/armasm_ms/save_reg_neon.asm",
]
libvpx_sources_arm_neon_gas_apple = [
"vpx_dsp/arm/gas_apple/intrapred_neon_asm.s",
"vpx_dsp/arm/gas_apple/loopfilter_mb_neon.s",
- "vpx_dsp/arm/gas_apple/save_reg_neon.s"
+ "vpx_dsp/arm/gas_apple/save_reg_neon.s",
]
libvpx_sources = [libvpx_dir + file for file in libvpx_sources]
@@ -258,25 +222,43 @@ env_libvpx = env_modules.Clone()
env_libvpx.disable_warnings()
env_libvpx.Prepend(CPPPATH=[libvpx_dir])
-webm_multithread = env["platform"] != 'javascript'
+webm_multithread = env["platform"] != "javascript"
cpu_bits = env["bits"]
webm_cpu_x86 = False
webm_cpu_arm = False
-if env["platform"] == 'uwp':
- if 'arm' in env["PROGSUFFIX"]:
+if env["platform"] == "uwp":
+ if "arm" in env["PROGSUFFIX"]:
webm_cpu_arm = True
else:
webm_cpu_x86 = True
else:
import platform
- is_x11_or_server_arm = ((env["platform"] == 'x11' or env["platform"] == 'server') and (platform.machine().startswith('arm') or platform.machine().startswith('aarch')))
- is_ios_x86 = (env["platform"] == 'iphone' and ("arch" in env and env["arch"].startswith('x86')))
- is_android_x86 = (env["platform"] == 'android' and env["android_arch"].startswith('x86'))
+
+ is_x11_or_server_arm = (env["platform"] == "linuxbsd" or env["platform"] == "server") and (
+ platform.machine().startswith("arm") or platform.machine().startswith("aarch")
+ )
+ is_ios_x86 = env["platform"] == "iphone" and ("arch" in env and env["arch"].startswith("x86"))
+ is_android_x86 = env["platform"] == "android" and env["android_arch"].startswith("x86")
if is_android_x86:
- cpu_bits = '32' if env["android_arch"] == 'x86' else '64'
- webm_cpu_x86 = not is_x11_or_server_arm and (cpu_bits == '32' or cpu_bits == '64') and (env["platform"] == 'windows' or env["platform"] == 'x11' or env["platform"] == 'osx' or env["platform"] == 'haiku' or is_android_x86 or is_ios_x86)
- webm_cpu_arm = is_x11_or_server_arm or (not is_ios_x86 and env["platform"] == 'iphone') or (not is_android_x86 and env["platform"] == 'android')
+ cpu_bits = "32" if env["android_arch"] == "x86" else "64"
+ webm_cpu_x86 = (
+ not is_x11_or_server_arm
+ and (cpu_bits == "32" or cpu_bits == "64")
+ and (
+ env["platform"] == "windows"
+ or env["platform"] == "linuxbsd"
+ or env["platform"] == "osx"
+ or env["platform"] == "haiku"
+ or is_android_x86
+ or is_ios_x86
+ )
+ )
+ webm_cpu_arm = (
+ is_x11_or_server_arm
+ or (not is_ios_x86 and env["platform"] == "iphone")
+ or (not is_android_x86 and env["platform"] == "android")
+ )
if webm_cpu_x86:
import subprocess
@@ -306,38 +288,43 @@ if webm_cpu_x86:
webm_simd_optimizations = False
if webm_cpu_x86:
- if env["platform"] == 'windows' or env["platform"] == 'uwp':
- env_libvpx["ASFORMAT"] = 'win'
- elif env["platform"] == 'osx' or env["platform"] == "iphone":
- env_libvpx["ASFORMAT"] = 'macho'
+ if env["platform"] == "windows" or env["platform"] == "uwp":
+ env_libvpx["ASFORMAT"] = "win"
+ elif env["platform"] == "osx" or env["platform"] == "iphone":
+ env_libvpx["ASFORMAT"] = "macho"
else:
- env_libvpx["ASFORMAT"] = 'elf'
+ env_libvpx["ASFORMAT"] = "elf"
env_libvpx["ASFORMAT"] += cpu_bits
- env_libvpx["AS"] = 'yasm'
- env_libvpx["ASFLAGS"] = '-I' + libvpx_dir[1:] + ' -f $ASFORMAT -D $ASCPU'
- env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES'
+ env_libvpx["AS"] = "yasm"
+ env_libvpx["ASFLAGS"] = "-I" + libvpx_dir[1:] + " -f $ASFORMAT -D $ASCPU"
+ env_libvpx["ASCOM"] = "$AS $ASFLAGS -o $TARGET $SOURCES"
- if cpu_bits == '32':
- env_libvpx["ASCPU"] = 'X86_32'
- elif cpu_bits == '64':
- env_libvpx["ASCPU"] = 'X86_64'
+ if cpu_bits == "32":
+ env_libvpx["ASCPU"] = "X86_32"
+ elif cpu_bits == "64":
+ env_libvpx["ASCPU"] = "X86_64"
- env_libvpx.Append(CPPDEFINES=['WEBM_X86ASM'])
+ env_libvpx.Append(CPPDEFINES=["WEBM_X86ASM"])
webm_simd_optimizations = True
if webm_cpu_arm:
- if env["platform"] == 'iphone':
- env_libvpx["ASFLAGS"] = '-arch armv7'
- elif env["platform"] == 'android' and env["android_arch"] == 'armv7' or env["platform"] == 'x11' or env["platform"] == 'server':
- env_libvpx["ASFLAGS"] = '-mfpu=neon'
- elif env["platform"] == 'uwp':
- env_libvpx["AS"] = 'armasm'
- env_libvpx["ASFLAGS"] = ''
- env_libvpx["ASCOM"] = '$AS $ASFLAGS -o $TARGET $SOURCES'
-
- env_libvpx.Append(CPPDEFINES=['WEBM_ARMASM'])
+ if env["platform"] == "iphone":
+ env_libvpx["ASFLAGS"] = "-arch armv7"
+ elif (
+ env["platform"] == "android"
+ and env["android_arch"] == "armv7"
+ or env["platform"] == "linuxbsd"
+ or env["platform"] == "server"
+ ):
+ env_libvpx["ASFLAGS"] = "-mfpu=neon"
+ elif env["platform"] == "uwp":
+ env_libvpx["AS"] = "armasm"
+ env_libvpx["ASFLAGS"] = ""
+ env_libvpx["ASCOM"] = "$AS $ASFLAGS -o $TARGET $SOURCES"
+
+ env_libvpx.Append(CPPDEFINES=["WEBM_ARMASM"])
webm_simd_optimizations = True
@@ -350,45 +337,49 @@ if webm_multithread:
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_mt)
if webm_cpu_x86:
- is_clang_or_gcc = ('gcc' in os.path.basename(env["CC"])) or ('clang' in os.path.basename(env["CC"])) or ("osxcross" in env)
+ is_clang_or_gcc = (
+ ("gcc" in os.path.basename(env["CC"])) or ("clang" in os.path.basename(env["CC"])) or ("osxcross" in env)
+ )
env_libvpx_mmx = env_libvpx.Clone()
- if cpu_bits == '32' and is_clang_or_gcc:
- env_libvpx_mmx.Append(CCFLAGS=['-mmmx'])
+ if cpu_bits == "32" and is_clang_or_gcc:
+ env_libvpx_mmx.Append(CCFLAGS=["-mmmx"])
env_libvpx_mmx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_mmx)
env_libvpx_sse2 = env_libvpx.Clone()
- if cpu_bits == '32' and is_clang_or_gcc:
- env_libvpx_sse2.Append(CCFLAGS=['-msse2'])
+ if cpu_bits == "32" and is_clang_or_gcc:
+ env_libvpx_sse2.Append(CCFLAGS=["-msse2"])
env_libvpx_sse2.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_sse2)
env_libvpx_ssse3 = env_libvpx.Clone()
if is_clang_or_gcc:
- env_libvpx_ssse3.Append(CCFLAGS=['-mssse3'])
+ env_libvpx_ssse3.Append(CCFLAGS=["-mssse3"])
env_libvpx_ssse3.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_ssse3)
env_libvpx_avx2 = env_libvpx.Clone()
if is_clang_or_gcc:
- env_libvpx_avx2.Append(CCFLAGS=['-mavx2'])
+ env_libvpx_avx2.Append(CCFLAGS=["-mavx2"])
env_libvpx_avx2.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_avx2)
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86)
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86asm)
- if cpu_bits == '64':
+ if cpu_bits == "64":
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86_64asm)
elif webm_cpu_arm:
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm)
- if env["platform"] == 'android':
+ if env["platform"] == "android":
env_libvpx.Prepend(CPPPATH=[libvpx_dir + "third_party/android"])
env_libvpx.add_source_files(env.modules_sources, [libvpx_dir + "third_party/android/cpu-features.c"])
env_libvpx_neon = env_libvpx.Clone()
env_libvpx_neon.add_source_files(env.modules_sources, libvpx_sources_arm_neon)
- if env["platform"] == 'uwp':
+ if env["platform"] == "uwp":
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_armasm_ms)
- elif env["platform"] == 'iphone':
+ elif env["platform"] == "iphone":
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas_apple)
- elif (is_x11_or_server_arm and cpu_bits == '32') or (env["platform"] == 'android' and not env["android_arch"] == 'arm64v8'):
+ elif (is_x11_or_server_arm and cpu_bits == "32") or (
+ env["platform"] == "android" and not env["android_arch"] == "arm64v8"
+ ):
env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas)
diff --git a/modules/webm/register_types.h b/modules/webm/register_types.h
index 962a0dab4e..6a02e3a87a 100644
--- a/modules/webm/register_types.h
+++ b/modules/webm/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef WEBM_REGISTER_TYPES_H
+#define WEBM_REGISTER_TYPES_H
+
void register_webm_types();
void unregister_webm_types();
+
+#endif // WEBM_REGISTER_TYPES_H
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 265383831e..ca78d664f7 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -96,17 +96,17 @@ private:
VideoStreamPlaybackWebm::VideoStreamPlaybackWebm() :
audio_track(0),
- webm(NULL),
- video(NULL),
- audio(NULL),
- video_frames(NULL),
- audio_frame(NULL),
+ webm(nullptr),
+ video(nullptr),
+ audio(nullptr),
+ video_frames(nullptr),
+ audio_frame(nullptr),
video_frames_pos(0),
video_frames_capacity(0),
num_decoded_samples(0),
samples_offset(-1),
- mix_callback(NULL),
- mix_udata(NULL),
+ mix_callback(nullptr),
+ mix_udata(nullptr),
playing(false),
paused(false),
delay_compensation(0.0),
@@ -114,7 +114,7 @@ VideoStreamPlaybackWebm::VideoStreamPlaybackWebm() :
video_frame_delay(0.0),
video_pos(0.0),
texture(memnew(ImageTexture)),
- pcm(NULL) {}
+ pcm(nullptr) {}
VideoStreamPlaybackWebm::~VideoStreamPlaybackWebm() {
delete_pointers();
@@ -137,7 +137,7 @@ bool VideoStreamPlaybackWebm::open_file(const String &p_file) {
} else {
memdelete(audio);
- audio = NULL;
+ audio = nullptr;
}
frame_data.resize((webm->getWidth() * webm->getHeight()) << 2);
@@ -149,10 +149,10 @@ bool VideoStreamPlaybackWebm::open_file(const String &p_file) {
return true;
}
memdelete(video);
- video = NULL;
+ video = nullptr;
}
memdelete(webm);
- webm = NULL;
+ webm = nullptr;
return false;
}
@@ -162,13 +162,13 @@ void VideoStreamPlaybackWebm::stop() {
delete_pointers();
- pcm = NULL;
+ pcm = nullptr;
- audio_frame = NULL;
- video_frames = NULL;
+ audio_frame = nullptr;
+ video_frames = nullptr;
- video = NULL;
- audio = NULL;
+ video = nullptr;
+ audio = nullptr;
open_file(file_name); //Should not fail here...
@@ -447,7 +447,7 @@ Ref<VideoStreamPlayback> VideoStreamWebm::instance_playback() {
pb->set_audio_track(audio_track);
if (pb->open_file(file))
return pb;
- return NULL;
+ return nullptr;
}
void VideoStreamWebm::set_file(const String &p_file) {
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
index 3feaa1278f..bc209e0057 100644
--- a/modules/webm/video_stream_webm.h
+++ b/modules/webm/video_stream_webm.h
@@ -128,7 +128,7 @@ public:
class ResourceFormatLoaderWebm : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/SCsub b/modules/webp/SCsub
index 666628bb44..58f2bb35e6 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -1,12 +1,12 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_webp = env_modules.Clone()
# Thirdparty source files
-if env['builtin_libwebp']:
+if env["builtin_libwebp"]:
thirdparty_dir = "#thirdparty/libwebp/"
thirdparty_sources = [
"dec/alpha_dec.c",
diff --git a/modules/webp/config.py b/modules/webp/config.py
index 1c8cd12a2d..d22f9454ed 100644
--- a/modules/webp/config.py
+++ b/modules/webp/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index 09a8985472..0998977bb4 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -52,7 +52,7 @@ static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quali
Vector<uint8_t> data = img->get_data();
const uint8_t *r = data.ptr();
- uint8_t *dst_buff = NULL;
+ uint8_t *dst_buff = nullptr;
size_t dst_size = 0;
if (img->get_format() == Image::FORMAT_RGB8) {
@@ -101,9 +101,9 @@ static Ref<Image> _webp_lossy_unpack(const Vector<uint8_t> &p_buffer) {
bool errdec = false;
if (features.has_alpha) {
- errdec = WebPDecodeRGBAInto(&r[4], size, dst_w, datasize, 4 * features.width) == NULL;
+ errdec = WebPDecodeRGBAInto(&r[4], size, dst_w, datasize, 4 * features.width) == nullptr;
} else {
- errdec = WebPDecodeRGBInto(&r[4], size, dst_w, datasize, 3 * features.width) == NULL;
+ errdec = WebPDecodeRGBInto(&r[4], size, dst_w, datasize, 3 * features.width) == nullptr;
}
ERR_FAIL_COND_V_MSG(errdec, Ref<Image>(), "Failed decoding WebP image.");
@@ -128,9 +128,9 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
bool errdec = false;
if (features.has_alpha) {
- errdec = WebPDecodeRGBAInto(p_buffer, p_buffer_len, dst_w, datasize, 4 * features.width) == NULL;
+ errdec = WebPDecodeRGBAInto(p_buffer, p_buffer_len, dst_w, datasize, 4 * features.width) == nullptr;
} else {
- errdec = WebPDecodeRGBInto(p_buffer, p_buffer_len, dst_w, datasize, 3 * features.width) == NULL;
+ errdec = WebPDecodeRGBInto(p_buffer, p_buffer_len, dst_w, datasize, 3 * features.width) == nullptr;
}
ERR_FAIL_COND_V_MSG(errdec, ERR_FILE_CORRUPT, "Failed decoding WebP image.");
diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp
index 12a0c05f44..fe945b01d4 100644
--- a/modules/webp/register_types.cpp
+++ b/modules/webp/register_types.cpp
@@ -32,7 +32,7 @@
#include "image_loader_webp.h"
-static ImageLoaderWEBP *image_loader_webp = NULL;
+static ImageLoaderWEBP *image_loader_webp = nullptr;
void register_webp_types() {
diff --git a/modules/webp/register_types.h b/modules/webp/register_types.h
index 9591b91558..d574d7be1d 100644
--- a/modules/webp/register_types.h
+++ b/modules/webp/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef WEBP_REGISTER_TYPES_H
+#define WEBP_REGISTER_TYPES_H
+
void register_webp_types();
void unregister_webp_types();
+
+#endif // WEBP_REGISTER_TYPES_H
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub
index 868553b879..20b4c8f8d2 100644
--- a/modules/webrtc/SCsub
+++ b/modules/webrtc/SCsub
@@ -1,15 +1,15 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
# Thirdparty source files
env_webrtc = env_modules.Clone()
use_gdnative = env_webrtc["module_gdnative_enabled"]
-if use_gdnative: # GDNative is retained in Javascript for export compatibility
- env_webrtc.Append(CPPDEFINES=['WEBRTC_GDNATIVE_ENABLED'])
+if use_gdnative: # GDNative is retained in Javascript for export compatibility
+ env_webrtc.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"])
env_webrtc.Prepend(CPPPATH=["#modules/gdnative/include/"])
env_webrtc.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py
index 48b4c33c5d..0a075ccef1 100644
--- a/modules/webrtc/config.py
+++ b/modules/webrtc/config.py
@@ -1,15 +1,18 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"WebRTCPeerConnection",
"WebRTCDataChannel",
- "WebRTCMultiplayer"
+ "WebRTCMultiplayer",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h
index e6b50506e5..8f5b9e8452 100644
--- a/modules/webrtc/register_types.h
+++ b/modules/webrtc/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef WEBRTC_REGISTER_TYPES_H
+#define WEBRTC_REGISTER_TYPES_H
+
void register_webrtc_types();
void unregister_webrtc_types();
+
+#endif // WEBRTC_REGISTER_TYPES_H
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp
index b0c4b473fc..67ad2c07ce 100644
--- a/modules/webrtc/webrtc_data_channel_gdnative.cpp
+++ b/modules/webrtc/webrtc_data_channel_gdnative.cpp
@@ -39,94 +39,94 @@ void WebRTCDataChannelGDNative::_bind_methods() {
}
WebRTCDataChannelGDNative::WebRTCDataChannelGDNative() {
- interface = NULL;
+ interface = nullptr;
}
WebRTCDataChannelGDNative::~WebRTCDataChannelGDNative() {
}
Error WebRTCDataChannelGDNative::poll() {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->poll(interface->data);
}
void WebRTCDataChannelGDNative::close() {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->close(interface->data);
}
void WebRTCDataChannelGDNative::set_write_mode(WriteMode p_mode) {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->set_write_mode(interface->data, p_mode);
}
WebRTCDataChannel::WriteMode WebRTCDataChannelGDNative::get_write_mode() const {
- ERR_FAIL_COND_V(interface == NULL, WRITE_MODE_BINARY);
+ ERR_FAIL_COND_V(interface == nullptr, WRITE_MODE_BINARY);
return (WriteMode)interface->get_write_mode(interface->data);
}
bool WebRTCDataChannelGDNative::was_string_packet() const {
- ERR_FAIL_COND_V(interface == NULL, false);
+ ERR_FAIL_COND_V(interface == nullptr, false);
return interface->was_string_packet(interface->data);
}
WebRTCDataChannel::ChannelState WebRTCDataChannelGDNative::get_ready_state() const {
- ERR_FAIL_COND_V(interface == NULL, STATE_CLOSED);
+ ERR_FAIL_COND_V(interface == nullptr, STATE_CLOSED);
return (ChannelState)interface->get_ready_state(interface->data);
}
String WebRTCDataChannelGDNative::get_label() const {
- ERR_FAIL_COND_V(interface == NULL, "");
+ ERR_FAIL_COND_V(interface == nullptr, "");
return String(interface->get_label(interface->data));
}
bool WebRTCDataChannelGDNative::is_ordered() const {
- ERR_FAIL_COND_V(interface == NULL, false);
+ ERR_FAIL_COND_V(interface == nullptr, false);
return interface->is_ordered(interface->data);
}
int WebRTCDataChannelGDNative::get_id() const {
- ERR_FAIL_COND_V(interface == NULL, -1);
+ ERR_FAIL_COND_V(interface == nullptr, -1);
return interface->get_id(interface->data);
}
int WebRTCDataChannelGDNative::get_max_packet_life_time() const {
- ERR_FAIL_COND_V(interface == NULL, -1);
+ ERR_FAIL_COND_V(interface == nullptr, -1);
return interface->get_max_packet_life_time(interface->data);
}
int WebRTCDataChannelGDNative::get_max_retransmits() const {
- ERR_FAIL_COND_V(interface == NULL, -1);
+ ERR_FAIL_COND_V(interface == nullptr, -1);
return interface->get_max_retransmits(interface->data);
}
String WebRTCDataChannelGDNative::get_protocol() const {
- ERR_FAIL_COND_V(interface == NULL, "");
+ ERR_FAIL_COND_V(interface == nullptr, "");
return String(interface->get_protocol(interface->data));
}
bool WebRTCDataChannelGDNative::is_negotiated() const {
- ERR_FAIL_COND_V(interface == NULL, false);
+ ERR_FAIL_COND_V(interface == nullptr, false);
return interface->is_negotiated(interface->data);
}
Error WebRTCDataChannelGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size);
}
Error WebRTCDataChannelGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size);
}
int WebRTCDataChannelGDNative::get_max_packet_size() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_max_packet_size(interface->data);
}
int WebRTCDataChannelGDNative::get_available_packet_count() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
+ ERR_FAIL_COND_V(interface == nullptr, 0);
return interface->get_available_packet_count(interface->data);
}
diff --git a/modules/webrtc/webrtc_data_channel_js.cpp b/modules/webrtc/webrtc_data_channel_js.cpp
index 37203a4ec9..1b360720a2 100644
--- a/modules/webrtc/webrtc_data_channel_js.cpp
+++ b/modules/webrtc/webrtc_data_channel_js.cpp
@@ -334,7 +334,7 @@ WebRTCDataChannelJS::WebRTCDataChannelJS(int js_id) {
stringToUTF8(str, ptr, len+1);
return ptr;
}, js_id);
- if(str != NULL) {
+ if(str != nullptr) {
_label.parse_utf8(str);
EM_ASM({ _free($0) }, str);
}
@@ -347,7 +347,7 @@ WebRTCDataChannelJS::WebRTCDataChannelJS(int js_id) {
stringToUTF8(str, ptr, len+1);
return ptr;
}, js_id);
- if(str != NULL) {
+ if(str != nullptr) {
_protocol.parse_utf8(str);
EM_ASM({ _free($0) }, str);
}
diff --git a/modules/webrtc/webrtc_multiplayer.cpp b/modules/webrtc/webrtc_multiplayer.cpp
index 9df2420bbc..78a4d1e61a 100644
--- a/modules/webrtc/webrtc_multiplayer.cpp
+++ b/modules/webrtc/webrtc_multiplayer.cpp
@@ -70,7 +70,7 @@ void WebRTCMultiplayer::poll() {
List<int> remove;
List<int> add;
- for (Map<int, Ref<ConnectedPeer> >::Element *E = peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
Ref<ConnectedPeer> peer = E->get();
peer->connection->poll();
// Check peer state
@@ -89,7 +89,7 @@ void WebRTCMultiplayer::poll() {
}
// Check channels state
int ready = 0;
- for (List<Ref<WebRTCDataChannel> >::Element *C = peer->channels.front(); C && C->get().is_valid(); C = C->next()) {
+ for (List<Ref<WebRTCDataChannel>>::Element *C = peer->channels.front(); C && C->get().is_valid(); C = C->next()) {
Ref<WebRTCDataChannel> ch = C->get();
switch (ch->get_ready_state()) {
case WebRTCDataChannel::STATE_CONNECTING:
@@ -130,7 +130,7 @@ void WebRTCMultiplayer::poll() {
emit_signal("peer_connected", TARGET_PEER_SERVER);
emit_signal("connection_succeeded");
// Notify of all previously connected peers
- for (Map<int, Ref<ConnectedPeer> >::Element *F = peer_map.front(); F; F = F->next()) {
+ for (Map<int, Ref<ConnectedPeer>>::Element *F = peer_map.front(); F; F = F->next()) {
if (F->key() != 1 && F->get()->connected)
emit_signal("peer_connected", F->key());
}
@@ -143,11 +143,11 @@ void WebRTCMultiplayer::poll() {
}
void WebRTCMultiplayer::_find_next_peer() {
- Map<int, Ref<ConnectedPeer> >::Element *E = peer_map.find(next_packet_peer);
+ Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer);
if (E) E = E->next();
// After last.
while (E) {
- for (List<Ref<WebRTCDataChannel> >::Element *F = E->get()->channels.front(); F; F = F->next()) {
+ for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) {
if (F->get()->get_available_packet_count()) {
next_packet_peer = E->key();
return;
@@ -158,7 +158,7 @@ void WebRTCMultiplayer::_find_next_peer() {
E = peer_map.front();
// Before last
while (E) {
- for (List<Ref<WebRTCDataChannel> >::Element *F = E->get()->channels.front(); F; F = F->next()) {
+ for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) {
if (F->get()->get_available_packet_count()) {
next_packet_peer = E->key();
return;
@@ -204,7 +204,7 @@ int WebRTCMultiplayer::get_unique_id() const {
void WebRTCMultiplayer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) {
Array channels;
- for (List<Ref<WebRTCDataChannel> >::Element *F = p_connected_peer->channels.front(); F; F = F->next()) {
+ for (List<Ref<WebRTCDataChannel>>::Element *F = p_connected_peer->channels.front(); F; F = F->next()) {
channels.push_back(F->get());
}
r_dict["connection"] = p_connected_peer->connection;
@@ -225,7 +225,7 @@ Dictionary WebRTCMultiplayer::get_peer(int p_peer_id) {
Dictionary WebRTCMultiplayer::get_peers() {
Dictionary out;
- for (Map<int, Ref<ConnectedPeer> >::Element *E = peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
Dictionary d;
_peer_to_dict(E->get(), d);
out[E->key()] = d;
@@ -288,7 +288,7 @@ Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size
_find_next_peer();
ERR_FAIL_V(ERR_UNAVAILABLE);
}
- for (List<Ref<WebRTCDataChannel> >::Element *E = peer_map[next_packet_peer]->channels.front(); E; E = E->next()) {
+ for (List<Ref<WebRTCDataChannel>>::Element *E = peer_map[next_packet_peer]->channels.front(); E; E = E->next()) {
if (E->get()->get_available_packet_count()) {
Error err = E->get()->get_packet(r_buffer, r_buffer_size);
_find_next_peer();
@@ -316,7 +316,7 @@ Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size)
break;
}
- Map<int, Ref<ConnectedPeer> >::Element *E = NULL;
+ Map<int, Ref<ConnectedPeer>>::Element *E = nullptr;
if (target_peer > 0) {
@@ -330,7 +330,7 @@ Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size)
} else {
int exclude = -target_peer;
- for (Map<int, Ref<ConnectedPeer> >::Element *F = peer_map.front(); F; F = F->next()) {
+ for (Map<int, Ref<ConnectedPeer>>::Element *F = peer_map.front(); F; F = F->next()) {
// Exclude packet. If target_peer == 0 then don't exclude any packets
if (target_peer != 0 && F->key() == exclude)
@@ -347,8 +347,8 @@ int WebRTCMultiplayer::get_available_packet_count() const {
if (next_packet_peer == 0)
return 0; // To be sure next call to get_packet works if size > 0 .
int size = 0;
- for (Map<int, Ref<ConnectedPeer> >::Element *E = peer_map.front(); E; E = E->next()) {
- for (List<Ref<WebRTCDataChannel> >::Element *F = E->get()->channels.front(); F; F = F->next()) {
+ for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
+ for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) {
size += F->get()->get_available_packet_count();
}
}
@@ -371,6 +371,7 @@ WebRTCMultiplayer::WebRTCMultiplayer() {
unique_id = 0;
next_packet_peer = 0;
target_peer = 0;
+ client_count = 0;
transfer_mode = TRANSFER_MODE_RELIABLE;
refuse_connections = false;
connection_status = CONNECTION_DISCONNECTED;
diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer.h
index 66a3cd0ff5..0e1335b8a8 100644
--- a/modules/webrtc/webrtc_multiplayer.h
+++ b/modules/webrtc/webrtc_multiplayer.h
@@ -53,7 +53,7 @@ private:
public:
Ref<WebRTCPeerConnection> connection;
- List<Ref<WebRTCDataChannel> > channels;
+ List<Ref<WebRTCDataChannel>> channels;
bool connected;
ConnectedPeer() {
@@ -72,7 +72,7 @@ private:
int next_packet_peer;
bool server_compat;
- Map<int, Ref<ConnectedPeer> > peer_map;
+ Map<int, Ref<ConnectedPeer>> peer_map;
void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict);
void _find_next_peer();
diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp
index 90c62e2495..399e4f09ff 100644
--- a/modules/webrtc/webrtc_peer_connection.cpp
+++ b/modules/webrtc/webrtc_peer_connection.cpp
@@ -30,7 +30,7 @@
#include "webrtc_peer_connection.h"
-WebRTCPeerConnection *(*WebRTCPeerConnection::_create)() = NULL;
+WebRTCPeerConnection *(*WebRTCPeerConnection::_create)() = nullptr;
Ref<WebRTCPeerConnection> WebRTCPeerConnection::create_ref() {
@@ -40,7 +40,7 @@ Ref<WebRTCPeerConnection> WebRTCPeerConnection::create_ref() {
WebRTCPeerConnection *WebRTCPeerConnection::create() {
if (!_create)
- return NULL;
+ return nullptr;
return _create();
}
diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.cpp b/modules/webrtc/webrtc_peer_connection_gdnative.cpp
index 411ad50275..f082646629 100644
--- a/modules/webrtc/webrtc_peer_connection_gdnative.cpp
+++ b/modules/webrtc/webrtc_peer_connection_gdnative.cpp
@@ -36,12 +36,12 @@
#include "modules/gdnative/nativescript/nativescript.h"
#include "webrtc_data_channel_gdnative.h"
-const godot_net_webrtc_library *WebRTCPeerConnectionGDNative::default_library = NULL;
+const godot_net_webrtc_library *WebRTCPeerConnectionGDNative::default_library = nullptr;
Error WebRTCPeerConnectionGDNative::set_default_library(const godot_net_webrtc_library *p_lib) {
if (default_library) {
const godot_net_webrtc_library *old = default_library;
- default_library = NULL;
+ default_library = nullptr;
old->unregistered();
}
default_library = p_lib;
@@ -64,54 +64,54 @@ void WebRTCPeerConnectionGDNative::_bind_methods() {
}
WebRTCPeerConnectionGDNative::WebRTCPeerConnectionGDNative() {
- interface = NULL;
+ interface = nullptr;
}
WebRTCPeerConnectionGDNative::~WebRTCPeerConnectionGDNative() {
}
Error WebRTCPeerConnectionGDNative::initialize(Dictionary p_config) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->initialize(interface->data, (const godot_dictionary *)&p_config);
}
Ref<WebRTCDataChannel> WebRTCPeerConnectionGDNative::create_data_channel(String p_label, Dictionary p_options) {
- ERR_FAIL_COND_V(interface == NULL, NULL);
+ ERR_FAIL_COND_V(interface == nullptr, nullptr);
return (WebRTCDataChannel *)interface->create_data_channel(interface->data, p_label.utf8().get_data(), (const godot_dictionary *)&p_options);
}
Error WebRTCPeerConnectionGDNative::create_offer() {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->create_offer(interface->data);
}
Error WebRTCPeerConnectionGDNative::set_local_description(String p_type, String p_sdp) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->set_local_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data());
}
Error WebRTCPeerConnectionGDNative::set_remote_description(String p_type, String p_sdp) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->set_remote_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data());
}
Error WebRTCPeerConnectionGDNative::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->add_ice_candidate(interface->data, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data());
}
Error WebRTCPeerConnectionGDNative::poll() {
- ERR_FAIL_COND_V(interface == NULL, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
return (Error)interface->poll(interface->data);
}
void WebRTCPeerConnectionGDNative::close() {
- ERR_FAIL_COND(interface == NULL);
+ ERR_FAIL_COND(interface == nullptr);
interface->close(interface->data);
}
WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionGDNative::get_connection_state() const {
- ERR_FAIL_COND_V(interface == NULL, STATE_DISCONNECTED);
+ ERR_FAIL_COND_V(interface == nullptr, STATE_DISCONNECTED);
return (ConnectionState)interface->get_connection_state(interface->data);
}
diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp
index a84dabab72..593c3a5162 100644
--- a/modules/webrtc/webrtc_peer_connection_js.cpp
+++ b/modules/webrtc/webrtc_peer_connection_js.cpp
@@ -279,7 +279,7 @@ Ref<WebRTCDataChannel> WebRTCPeerConnectionJS::create_data_channel(String p_chan
}
}, _js_id, p_channel.utf8().get_data(), config.utf8().get_data());
/* clang-format on */
- ERR_FAIL_COND_V(id == 0, NULL);
+ ERR_FAIL_COND_V(id == 0, nullptr);
return memnew(WebRTCDataChannelJS(id));
}
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index 033169411f..af60055855 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -1,13 +1,13 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
# Thirdparty source files
env_ws = env_modules.Clone()
-if env['builtin_wslay'] and not env["platform"] == "javascript": # already builtin for javascript
+if env["builtin_wslay"] and not env["platform"] == "javascript": # already builtin for javascript
wslay_dir = "#thirdparty/wslay/"
wslay_sources = [
"wslay_net.c",
diff --git a/modules/websocket/config.py b/modules/websocket/config.py
index f59ef432b4..9e27a1a0fe 100644
--- a/modules/websocket/config.py
+++ b/modules/websocket/config.py
@@ -1,16 +1,19 @@
def can_build(env, platform):
return True
+
def configure(env):
pass
+
def get_doc_classes():
return [
"WebSocketClient",
"WebSocketMultiplayerPeer",
"WebSocketPeer",
- "WebSocketServer"
+ "WebSocketServer",
]
+
def get_doc_path():
return "doc_classes"
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index e5680ce2e9..bbe4d6dc5b 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -181,7 +181,7 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
if (peer_sock == -1)
return FAILED;
- static_cast<Ref<EMWSPeer> >(_peer)->set_sock(peer_sock, _in_buf_size, _in_pkt_size);
+ static_cast<Ref<EMWSPeer>>(_peer)->set_sock(peer_sock, _in_buf_size, _in_pkt_size);
return OK;
};
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index 8ceefa42b6..95cffb4775 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -50,7 +50,7 @@ bool EMWSServer::has_peer(int p_id) const {
}
Ref<WebSocketPeer> EMWSServer::get_peer(int p_id) const {
- return NULL;
+ return nullptr;
}
Vector<String> EMWSServer::get_protocols() const {
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index ea3658c827..5f5f0e20cd 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -63,7 +63,7 @@ public:
ERR_FAIL_COND_V(p_info && _packets.space_left() < 1, ERR_OUT_OF_MEMORY);
#endif
- // If p_info is NULL, only the payload is written
+ // If p_info is nullptr, only the payload is written
if (p_info) {
_Packet p;
p.size = p_size;
@@ -71,7 +71,7 @@ public:
_packets.write(p);
}
- // If p_payload is NULL, only the packet information is written.
+ // If p_payload is nullptr, only the packet information is written.
if (p_payload) {
_payload.write((const uint8_t *)p_payload, p_size);
}
diff --git a/modules/websocket/register_types.h b/modules/websocket/register_types.h
index b254b9dae8..bb7be57ab3 100644
--- a/modules/websocket/register_types.h
+++ b/modules/websocket/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef WEBSOCKET_REGISTER_TYPES_H
+#define WEBSOCKET_REGISTER_TYPES_H
+
void register_websocket_types();
void unregister_websocket_types();
+
+#endif // WEBSOCKET_REGISTER_TYPES_H
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
index 8aa01a70ed..f7eafcff1f 100644
--- a/modules/websocket/websocket_macros.h
+++ b/modules/websocket/websocket_macros.h
@@ -56,13 +56,13 @@ public:\
static CNAME *create() {\
\
if (!_create)\
- return NULL;\
+ return nullptr;\
return _create();\
}\
protected:\
#define GDCINULL(CNAME) \
-CNAME *(*CNAME::_create)() = NULL;
+CNAME *(*CNAME::_create)() = nullptr;
#define GDCIIMPL(IMPNAME, CNAME) \
public:\
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 5c01d44ede..9b71b32e33 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -42,7 +42,7 @@ WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() {
_current_packet.source = 0;
_current_packet.destination = 0;
_current_packet.size = 0;
- _current_packet.data = NULL;
+ _current_packet.data = nullptr;
}
WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() {
@@ -74,12 +74,12 @@ int WebSocketMultiplayerPeer::_gen_unique_id() const {
void WebSocketMultiplayerPeer::_clear() {
_peer_map.clear();
- if (_current_packet.data != NULL)
+ if (_current_packet.data != nullptr)
memfree(_current_packet.data);
for (List<Packet>::Element *E = _incoming_packets.front(); E; E = E->next()) {
memfree(E->get().data);
- E->get().data = NULL;
+ E->get().data = nullptr;
}
_incoming_packets.clear();
@@ -109,9 +109,9 @@ Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buff
r_buffer_size = 0;
- if (_current_packet.data != NULL) {
+ if (_current_packet.data != nullptr) {
memfree(_current_packet.data);
- _current_packet.data = NULL;
+ _current_packet.data = nullptr;
}
_current_packet = _incoming_packets.front()->get();
@@ -209,7 +209,7 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
// Then send the server peer (which will trigger connection_succeded in client)
_send_sys(get_peer(p_peer_id), SYS_ADD, 1);
- for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ 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)
@@ -222,7 +222,7 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
}
void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) {
- for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
int32_t id = E->key();
if (p_peer_id != id)
_send_sys(get_peer(id), SYS_DEL, p_peer_id);
@@ -247,7 +247,7 @@ Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, cons
} else if (p_to == 0) {
- for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
if (E->key() != p_from)
E->get()->put_packet(p_buffer, p_buffer_size);
}
@@ -255,7 +255,7 @@ Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, cons
} else if (p_to < 0) {
- for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
if (E->key() != p_from && E->key() != -p_to)
E->get()->put_packet(p_buffer, p_buffer_size);
}
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index 579972ada2..c6669c730c 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -63,7 +63,7 @@ protected:
};
List<Packet> _incoming_packets;
- Map<int, Ref<WebSocketPeer> > _peer_map;
+ Map<int, Ref<WebSocketPeer>> _peer_map;
Packet _current_packet;
bool _is_multiplayer;
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index 088f266f18..9f05500eb9 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -253,7 +253,7 @@ void WSLClient::poll() {
}
_connection = ssl;
} else {
- ssl = static_cast<Ref<StreamPeerSSL> >(_connection);
+ ssl = static_cast<Ref<StreamPeerSSL>>(_connection);
ERR_FAIL_COND(ssl.is_null()); // Bug?
ssl->poll();
}
@@ -279,7 +279,7 @@ void WSLClient::poll() {
Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const {
- ERR_FAIL_COND_V(p_peer_id != 1, NULL);
+ ERR_FAIL_COND_V(p_peer_id != 1, nullptr);
return _peer;
}
@@ -298,7 +298,7 @@ NetworkedMultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() co
void WSLClient::disconnect_from_host(int p_code, String p_reason) {
_peer->close(p_code, p_reason);
- _connection = Ref<StreamPeer>(NULL);
+ _connection = Ref<StreamPeer>(nullptr);
_tcp = Ref<StreamPeerTCP>(memnew(StreamPeerTCP));
_key = "";
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index ff32e83dc1..44b71f70f4 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -69,7 +69,7 @@ void WSLPeer::_wsl_destroy(struct PeerData **p_data) {
}
wslay_event_context_free(data->ctx);
memdelete(data);
- *p_data = NULL;
+ *p_data = nullptr;
}
bool WSLPeer::_wsl_poll(struct PeerData *p_data) {
@@ -163,9 +163,9 @@ wslay_event_callbacks wsl_callbacks = {
wsl_recv_callback,
wsl_send_callback,
wsl_genmask_callback,
- NULL, /* on_frame_recv_start_callback */
- NULL, /* on_frame_recv_callback */
- NULL, /* on_frame_recv_end_callback */
+ nullptr, /* on_frame_recv_start_callback */
+ nullptr, /* on_frame_recv_callback */
+ nullptr, /* on_frame_recv_end_callback */
wsl_msg_recv_callback
};
@@ -199,8 +199,8 @@ Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) {
}
void WSLPeer::make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size) {
- ERR_FAIL_COND(_data != NULL);
- ERR_FAIL_COND(p_data == NULL);
+ ERR_FAIL_COND(_data != nullptr);
+ ERR_FAIL_COND(p_data == nullptr);
_in_buffer.resize(p_in_pkt_size, p_in_buf_size);
_packet_buffer.resize((1 << MAX(p_in_buf_size, p_out_buf_size)));
@@ -229,7 +229,7 @@ void WSLPeer::poll() {
return;
if (_wsl_poll(_data)) {
- _data = NULL;
+ _data = nullptr;
}
}
@@ -284,7 +284,7 @@ bool WSLPeer::was_string_packet() const {
bool WSLPeer::is_connected_to_host() const {
- return _data != NULL;
+ return _data != nullptr;
}
void WSLPeer::close_now() {
@@ -330,7 +330,7 @@ void WSLPeer::invalidate() {
}
WSLPeer::WSLPeer() {
- _data = NULL;
+ _data = nullptr;
_is_string = 0;
close_code = -1;
write_mode = WRITE_MODE_BINARY;
@@ -341,7 +341,7 @@ WSLPeer::~WSLPeer() {
close();
invalidate();
_wsl_destroy(&_data);
- _data = NULL;
+ _data = nullptr;
}
#endif // JAVASCRIPT_ENABLED
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index 00549cd9bc..3b0639831a 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -67,10 +67,10 @@ public:
valid = false;
is_server = false;
id = 1;
- ctx = NULL;
- obj = NULL;
+ ctx = nullptr;
+ obj = nullptr;
closing = false;
- peer = NULL;
+ peer = nullptr;
}
};
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index 4db650a0c1..6f155a6ffa 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -103,7 +103,7 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols) {
if (OS::get_singleton()->get_ticks_msec() - time > WSL_SERVER_TIMEOUT)
return ERR_TIMEOUT;
if (use_ssl) {
- Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL> >(connection);
+ Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL>>(connection);
if (ssl.is_null())
return FAILED;
ssl->poll();
@@ -171,7 +171,7 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp
void WSLServer::poll() {
List<int> remove_ids;
- for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
Ref<WSLPeer> peer = (WSLPeer *)E->get().ptr();
peer->poll();
if (!peer->is_connected_to_host()) {
@@ -184,8 +184,8 @@ void WSLServer::poll() {
}
remove_ids.clear();
- List<Ref<PendingPeer> > remove_peers;
- for (List<Ref<PendingPeer> >::Element *E = _pending.front(); E; E = E->next()) {
+ List<Ref<PendingPeer>> remove_peers;
+ for (List<Ref<PendingPeer>>::Element *E = _pending.front(); E; E = E->next()) {
Ref<PendingPeer> ppeer = E->get();
Error err = ppeer->do_handshake(_protocols);
if (err == ERR_BUSY) {
@@ -212,7 +212,7 @@ void WSLServer::poll() {
remove_peers.push_back(ppeer);
_on_connect(id, ppeer->protocol);
}
- for (List<Ref<PendingPeer> >::Element *E = remove_peers.front(); E; E = E->next()) {
+ for (List<Ref<PendingPeer>>::Element *E = remove_peers.front(); E; E = E->next()) {
_pending.erase(E->get());
}
remove_peers.clear();
@@ -251,7 +251,7 @@ int WSLServer::get_max_packet_size() const {
void WSLServer::stop() {
_server->stop();
- for (Map<int, Ref<WebSocketPeer> >::Element *E = _peer_map.front(); E; E = E->next()) {
+ for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
Ref<WSLPeer> peer = (WSLPeer *)E->get().ptr();
peer->close_now();
}
@@ -265,7 +265,7 @@ bool WSLServer::has_peer(int p_id) const {
}
Ref<WebSocketPeer> WSLServer::get_peer(int p_id) const {
- ERR_FAIL_COND_V(!has_peer(p_id), NULL);
+ ERR_FAIL_COND_V(!has_peer(p_id), nullptr);
return _peer_map[p_id];
}
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 649d1adee6..2e893d6727 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -76,7 +76,7 @@ private:
int _out_buf_size;
int _out_pkt_size;
- List<Ref<PendingPeer> > _pending;
+ List<Ref<PendingPeer>> _pending;
Ref<TCP_Server> _server;
Vector<String> _protocols;
diff --git a/modules/xatlas_unwrap/SCsub b/modules/xatlas_unwrap/SCsub
index b242fd4673..c659349d05 100644
--- a/modules/xatlas_unwrap/SCsub
+++ b/modules/xatlas_unwrap/SCsub
@@ -1,12 +1,12 @@
#!/usr/bin/env python
-Import('env')
-Import('env_modules')
+Import("env")
+Import("env_modules")
env_xatlas_unwrap = env_modules.Clone()
# Thirdparty source files
-if env['builtin_xatlas']:
+if env["builtin_xatlas"]:
thirdparty_dir = "#thirdparty/xatlas/"
thirdparty_sources = [
"xatlas.cpp",
diff --git a/modules/xatlas_unwrap/config.py b/modules/xatlas_unwrap/config.py
index bd092bdc16..2e73c51626 100644
--- a/modules/xatlas_unwrap/config.py
+++ b/modules/xatlas_unwrap/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return (env['tools'] and platform not in ["android", "ios"])
+ return env["tools"] and platform not in ["android", "ios"]
+
def configure(env):
pass
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index c69b566525..e293dfd50c 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -52,7 +52,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
input_mesh.vertexPositionStride = sizeof(float) * 3;
input_mesh.vertexNormalData = p_normals;
input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
- input_mesh.vertexUvData = NULL;
+ input_mesh.vertexUvData = nullptr;
input_mesh.vertexUvStride = 0;
xatlas::ChartOptions chart_options;
@@ -68,7 +68,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err));
printf("Generate..\n");
- xatlas::Generate(atlas, chart_options, NULL, pack_options);
+ xatlas::Generate(atlas, chart_options, nullptr, pack_options);
*r_size_hint_x = atlas->width;
*r_size_hint_y = atlas->height;
diff --git a/modules/xatlas_unwrap/register_types.h b/modules/xatlas_unwrap/register_types.h
index 3f2181fa63..fe924bab96 100644
--- a/modules/xatlas_unwrap/register_types.h
+++ b/modules/xatlas_unwrap/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef XATLAS_UNWRAP_REGISTER_TYPES_H
+#define XATLAS_UNWRAP_REGISTER_TYPES_H
+
void register_xatlas_unwrap_types();
void unregister_xatlas_unwrap_types();
+
+#endif // XATLAS_UNWRAP_REGISTER_TYPES_H
diff --git a/platform/SCsub b/platform/SCsub
index 38bab59d74..5194a19518 100644
--- a/platform/SCsub
+++ b/platform/SCsub
@@ -1,32 +1,30 @@
#!/usr/bin/env python
-from compat import open_utf8
-
-Import('env')
+Import("env")
env.platform_sources = []
# Register platform-exclusive APIs
reg_apis_inc = '#include "register_platform_apis.h"\n'
-reg_apis = 'void register_platform_apis() {\n'
-unreg_apis = 'void unregister_platform_apis() {\n'
+reg_apis = "void register_platform_apis() {\n"
+unreg_apis = "void unregister_platform_apis() {\n"
for platform in env.platform_apis:
platform_dir = env.Dir(platform)
- env.add_source_files(env.platform_sources, platform + '/api/api.cpp')
- reg_apis += '\tregister_' + platform + '_api();\n'
- unreg_apis += '\tunregister_' + platform + '_api();\n'
+ env.add_source_files(env.platform_sources, platform + "/api/api.cpp")
+ reg_apis += "\tregister_" + platform + "_api();\n"
+ unreg_apis += "\tunregister_" + platform + "_api();\n"
reg_apis_inc += '#include "' + platform + '/api/api.h"\n'
-reg_apis_inc += '\n'
-reg_apis += '}\n\n'
-unreg_apis += '}\n'
+reg_apis_inc += "\n"
+reg_apis += "}\n\n"
+unreg_apis += "}\n"
# NOTE: It is safe to generate this file here, since this is still execute serially
-with open_utf8('register_platform_apis.gen.cpp', 'w') as f:
+with open("register_platform_apis.gen.cpp", "w", encoding="utf-8") as f:
f.write(reg_apis_inc)
f.write(reg_apis)
f.write(unreg_apis)
-env.add_source_files(env.platform_sources, 'register_platform_apis.gen.cpp')
+env.add_source_files(env.platform_sources, "register_platform_apis.gen.cpp")
-lib = env.add_library('platform', env.platform_sources)
+lib = env.add_library("platform", env.platform_sources)
env.Prepend(LIBS=[lib])
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 46f0703a65..ec42bc42b5 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -1,27 +1,24 @@
#!/usr/bin/env python
-from detect import get_ndk_version
-from distutils.version import LooseVersion
-
-Import('env')
+Import("env")
android_files = [
- 'os_android.cpp',
- 'file_access_android.cpp',
- 'audio_driver_opensl.cpp',
- 'file_access_jandroid.cpp',
- 'dir_access_jandroid.cpp',
- 'thread_jandroid.cpp',
- 'net_socket_android.cpp',
- 'audio_driver_jandroid.cpp',
- 'java_godot_lib_jni.cpp',
- 'java_class_wrapper.cpp',
- 'java_godot_wrapper.cpp',
- 'java_godot_io_wrapper.cpp',
- 'jni_utils.cpp',
- 'android_keys_utils.cpp',
- 'vulkan/vk_renderer_jni.cpp',
- 'plugin/godot_plugin_jni.cpp'
+ "os_android.cpp",
+ "file_access_android.cpp",
+ "audio_driver_opensl.cpp",
+ "file_access_jandroid.cpp",
+ "dir_access_jandroid.cpp",
+ "thread_jandroid.cpp",
+ "net_socket_android.cpp",
+ "audio_driver_jandroid.cpp",
+ "java_godot_lib_jni.cpp",
+ "java_class_wrapper.cpp",
+ "java_godot_wrapper.cpp",
+ "java_godot_io_wrapper.cpp",
+ "jni_utils.cpp",
+ "android_keys_utils.cpp",
+ "display_server_android.cpp",
+ "vulkan/vulkan_context_android.cpp",
]
env_android = env.Clone()
@@ -32,30 +29,34 @@ for x in android_files:
env_thirdparty = env_android.Clone()
env_thirdparty.disable_warnings()
-android_objects.append(env_thirdparty.SharedObject('#thirdparty/misc/ifaddrs-android.cc'))
+android_objects.append(env_thirdparty.SharedObject("#thirdparty/misc/ifaddrs-android.cc"))
lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
-lib_arch_dir = ''
-if env['android_arch'] == 'armv7':
- lib_arch_dir = 'armeabi-v7a'
-elif env['android_arch'] == 'arm64v8':
- lib_arch_dir = 'arm64-v8a'
-elif env['android_arch'] == 'x86':
- lib_arch_dir = 'x86'
-elif env['android_arch'] == 'x86_64':
- lib_arch_dir = 'x86_64'
+lib_arch_dir = ""
+if env["android_arch"] == "armv7":
+ lib_arch_dir = "armeabi-v7a"
+elif env["android_arch"] == "arm64v8":
+ lib_arch_dir = "arm64-v8a"
+elif env["android_arch"] == "x86":
+ lib_arch_dir = "x86"
+elif env["android_arch"] == "x86_64":
+ lib_arch_dir = "x86_64"
else:
- print('WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin')
+ print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin")
-if lib_arch_dir != '':
- if env['target'] == 'release':
- lib_type_dir = 'release'
+if lib_arch_dir != "":
+ if env["target"] == "release":
+ lib_type_dir = "release"
else: # release_debug, debug
- lib_type_dir = 'debug'
+ lib_type_dir = "debug"
- out_dir = '#platform/android/java/lib/libs/' + lib_type_dir + '/' + lib_arch_dir
- env_android.Command(out_dir + '/libgodot_android.so', '#bin/libgodot' + env['SHLIBSUFFIX'], Move("$TARGET", "$SOURCE"))
+ out_dir = "#platform/android/java/lib/libs/" + lib_type_dir + "/" + lib_arch_dir
+ env_android.Command(
+ out_dir + "/libgodot_android.so", "#bin/libgodot" + env["SHLIBSUFFIX"], Move("$TARGET", "$SOURCE")
+ )
- stl_lib_path = str(env['ANDROID_NDK_ROOT']) + '/sources/cxx-stl/llvm-libc++/libs/' + lib_arch_dir + '/libc++_shared.so'
- env_android.Command(out_dir + '/libc++_shared.so', stl_lib_path, Copy("$TARGET", "$SOURCE"))
+ stl_lib_path = (
+ str(env["ANDROID_NDK_ROOT"]) + "/sources/cxx-stl/llvm-libc++/libs/" + lib_arch_dir + "/libc++_shared.so"
+ )
+ env_android.Command(out_dir + "/libc++_shared.so", stl_lib_path, Copy("$TARGET", "$SOURCE"))
diff --git a/platform/android/api/api.cpp b/platform/android/api/api.cpp
index 7efb545524..4fe868d4f0 100644
--- a/platform/android/api/api.cpp
+++ b/platform/android/api/api.cpp
@@ -32,15 +32,20 @@
#include "core/engine.h"
#include "java_class_wrapper.h"
+#include "jni_singleton.h"
#if !defined(ANDROID_ENABLED)
-static JavaClassWrapper *java_class_wrapper = NULL;
+static JavaClassWrapper *java_class_wrapper = nullptr;
#endif
void register_android_api() {
#if !defined(ANDROID_ENABLED)
+ // On Android platforms, the `java_class_wrapper` instantiation and the
+ // `JNISingleton` registration occurs in
+ // `platform/android/java_godot_lib_jni.cpp#Java_org_godotengine_godot_GodotLib_setup`
java_class_wrapper = memnew(JavaClassWrapper); // Dummy
+ ClassDB::register_class<JNISingleton>();
#endif
ClassDB::register_class<JavaClass>();
@@ -73,7 +78,7 @@ Variant JavaObject::call(const StringName &, const Variant **, int, Callable::Ca
return Variant();
}
-JavaClassWrapper *JavaClassWrapper::singleton = NULL;
+JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
Ref<JavaClass> JavaClassWrapper::wrap(const String &) {
return Ref<JavaClass>();
diff --git a/platform/android/api/api.h b/platform/android/api/api.h
index c7296d92a7..5e951b9c88 100644
--- a/platform/android/api/api.h
+++ b/platform/android/api/api.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef ANDROID_API_H
+#define ANDROID_API_H
+
void register_android_api();
void unregister_android_api();
+
+#endif // ANDROID_API_H
diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h
index 48b581958b..59fcd94b4d 100644
--- a/platform/android/api/java_class_wrapper.h
+++ b/platform/android/api/java_class_wrapper.h
@@ -163,7 +163,7 @@ class JavaClass : public Reference {
bool _call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret);
friend class JavaClassWrapper;
- Map<StringName, List<MethodInfo> > methods;
+ Map<StringName, List<MethodInfo>> methods;
jclass _class;
#endif
@@ -198,7 +198,7 @@ class JavaClassWrapper : public Object {
GDCLASS(JavaClassWrapper, Object);
#ifdef ANDROID_ENABLED
- Map<String, Ref<JavaClass> > class_cache;
+ Map<String, Ref<JavaClass>> class_cache;
friend class JavaClass;
jclass activityClass;
jmethodID findClass;
@@ -236,7 +236,7 @@ public:
Ref<JavaClass> wrap(const String &p_class);
#ifdef ANDROID_ENABLED
- JavaClassWrapper(jobject p_activity = NULL);
+ JavaClassWrapper(jobject p_activity = nullptr);
#else
JavaClassWrapper();
#endif
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
new file mode 100644
index 0000000000..917c3f5029
--- /dev/null
+++ b/platform/android/api/jni_singleton.h
@@ -0,0 +1,242 @@
+/*************************************************************************/
+/* jni_singleton.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 JNI_SINGLETON_H
+#define JNI_SINGLETON_H
+
+#include <core/engine.h>
+#include <core/variant.h>
+#ifdef ANDROID_ENABLED
+#include <platform/android/jni_utils.h>
+#endif
+
+class JNISingleton : public Object {
+
+ GDCLASS(JNISingleton, Object);
+
+#ifdef ANDROID_ENABLED
+ struct MethodData {
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName, MethodData> method_map;
+#endif
+
+public:
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+#ifdef ANDROID_ENABLED
+ Map<StringName, MethodData>::Element *E = method_map.find(p_method);
+
+ // Check the method we're looking for is in the JNISingleton map and that
+ // the arguments match.
+ bool call_error = !E || E->get().argtypes.size() != p_argcount;
+ if (!call_error) {
+ for (int i = 0; i < p_argcount; i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
+ call_error = true;
+ break;
+ }
+ }
+ }
+
+ if (call_error) {
+ // The method is not in this map, defaulting to the regular instance calls.
+ return Object::call(p_method, p_args, p_argcount, r_error);
+ }
+
+ ERR_FAIL_COND_V(!instance, Variant());
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ jvalue *v = nullptr;
+
+ if (p_argcount) {
+
+ v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
+ }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ int res = env->PushLocalFrame(16);
+
+ ERR_FAIL_COND_V(res != 0, Variant());
+
+ List<jobject> to_erase;
+ for (int i = 0; i < p_argcount; i++) {
+
+ jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ v[i] = vr.val;
+ if (vr.obj)
+ to_erase.push_back(vr.obj);
+ }
+
+ Variant ret;
+
+ switch (E->get().ret_type) {
+
+ case Variant::NIL: {
+
+ env->CallVoidMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::FLOAT: {
+
+ ret = env->CallFloatMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = jstring_to_string((jstring)o, env);
+ env->DeleteLocalRef(o);
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ ret = _jobject_to_variant(env, arr);
+
+ env->DeleteLocalRef(arr);
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<int> sarr;
+ sarr.resize(fCount);
+
+ int *w = sarr.ptrw();
+ env->GetIntArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<float> sarr;
+ sarr.resize(fCount);
+
+ float *w = sarr.ptrw();
+ env->GetFloatArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
+
+#ifndef _MSC_VER
+#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
+#endif
+ case Variant::DICTIONARY: {
+
+ jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = _jobject_to_variant(env, obj);
+ env->DeleteLocalRef(obj);
+
+ } break;
+ default: {
+
+ env->PopLocalFrame(nullptr);
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ while (to_erase.size()) {
+ env->DeleteLocalRef(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ env->PopLocalFrame(nullptr);
+
+ return ret;
+#else // ANDROID_ENABLED
+
+ // Defaulting to the regular instance calls.
+ return Object::call(p_method, p_args, p_argcount, r_error);
+#endif
+ }
+
+#ifdef ANDROID_ENABLED
+ jobject get_instance() const {
+
+ return instance;
+ }
+
+ void set_instance(jobject p_instance) {
+
+ instance = p_instance;
+ }
+
+ void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method = p_method;
+ md.argtypes = p_args;
+ md.ret_type = p_ret_type;
+ method_map[p_name] = md;
+ }
+
+ void add_signal(const StringName &p_name, const Vector<Variant::Type> &p_args) {
+ if (p_args.size() == 0)
+ ADD_SIGNAL(MethodInfo(p_name));
+ else if (p_args.size() == 1)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1")));
+ else if (p_args.size() == 2)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2")));
+ else if (p_args.size() == 3)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3")));
+ else if (p_args.size() == 4)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4")));
+ else if (p_args.size() == 5)
+ ADD_SIGNAL(MethodInfo(p_name, PropertyInfo(p_args[0], "arg1"), PropertyInfo(p_args[1], "arg2"), PropertyInfo(p_args[2], "arg3"), PropertyInfo(p_args[3], "arg4"), PropertyInfo(p_args[4], "arg5")));
+ }
+
+#endif
+
+ JNISingleton() {
+#ifdef ANDROID_ENABLED
+ instance = nullptr;
+#endif
+ }
+};
+
+#endif // JNI_SINGLETON_H
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index e94dad9ac6..802d85e7be 100644
--- a/platform/android/audio_driver_jandroid.cpp
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -34,7 +34,7 @@
#include "core/project_settings.h"
#include "thread_jandroid.h"
-AudioDriverAndroid *AudioDriverAndroid::s_ad = NULL;
+AudioDriverAndroid *AudioDriverAndroid::s_ad = nullptr;
jobject AudioDriverAndroid::io;
jmethodID AudioDriverAndroid::_init_audio;
@@ -46,10 +46,10 @@ jclass AudioDriverAndroid::cls;
int AudioDriverAndroid::audioBufferFrames = 0;
int AudioDriverAndroid::mix_rate = 44100;
bool AudioDriverAndroid::quit = false;
-jobject AudioDriverAndroid::audioBuffer = NULL;
-void *AudioDriverAndroid::audioBufferPinned = NULL;
+jobject AudioDriverAndroid::audioBuffer = nullptr;
+void *AudioDriverAndroid::audioBufferPinned = nullptr;
Mutex AudioDriverAndroid::mutex;
-int32_t *AudioDriverAndroid::audioBuffer32 = NULL;
+int32_t *AudioDriverAndroid::audioBuffer32 = nullptr;
const char *AudioDriverAndroid::get_name() const {
@@ -83,7 +83,7 @@ Error AudioDriverAndroid::init() {
audioBuffer = env->CallObjectMethod(io, _init_audio, mix_rate, buffer_size);
- ERR_FAIL_COND_V(audioBuffer == NULL, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(audioBuffer == nullptr, ERR_INVALID_PARAMETER);
audioBuffer = env->NewGlobalRef(audioBuffer);
@@ -181,8 +181,8 @@ void AudioDriverAndroid::finish() {
if (audioBuffer) {
env->DeleteGlobalRef(audioBuffer);
- audioBuffer = NULL;
- audioBufferPinned = NULL;
+ audioBuffer = nullptr;
+ audioBufferPinned = nullptr;
}
active = false;
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index 222120f81f..e59850e016 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -83,7 +83,7 @@ void AudioDriverOpenSL::_buffer_callbacks(
ad->_buffer_callback(queueItf);
}
-AudioDriverOpenSL *AudioDriverOpenSL::s_ad = NULL;
+AudioDriverOpenSL *AudioDriverOpenSL::s_ad = nullptr;
const char *AudioDriverOpenSL::get_name() const {
@@ -96,7 +96,7 @@ Error AudioDriverOpenSL::init() {
SLEngineOption EngineOption[] = {
{ (SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE }
};
- res = slCreateEngine(&sl, 1, EngineOption, 0, NULL, NULL);
+ res = slCreateEngine(&sl, 1, EngineOption, 0, nullptr, nullptr);
ERR_FAIL_COND_V_MSG(res != SL_RESULT_SUCCESS, ERR_INVALID_PARAMETER, "Could not initialize OpenSL.");
res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE);
@@ -161,7 +161,7 @@ void AudioDriverOpenSL::start() {
locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
locator_outputmix.outputMix = OutputMix;
audioSink.pLocator = (void *)&locator_outputmix;
- audioSink.pFormat = NULL;
+ audioSink.pFormat = nullptr;
/* Initialize the context for Buffer queue callbacks */
//cntxt.pDataBase = (void*)&pcmData;
//cntxt.pData = cntxt.pDataBase;
@@ -228,9 +228,9 @@ Error AudioDriverOpenSL::capture_init_device() {
SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT,
- NULL
+ nullptr
};
- SLDataSource recSource = { &loc_dev, NULL };
+ SLDataSource recSource = { &loc_dev, nullptr };
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 8f74ae0ef0..6da1e5f3d6 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)
+ return "ANDROID_NDK_ROOT" in os.environ
def get_platform(platform):
@@ -24,33 +24,33 @@ def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
return [
- ('ANDROID_NDK_ROOT', 'Path to the Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
- ('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"),
- EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'arm64v8', 'x86', 'x86_64')),
- BoolVariable('android_neon', 'Enable NEON support (armv7 only)', True),
+ ("ANDROID_NDK_ROOT", "Path to the Android NDK", os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"),
+ EnumVariable("android_arch", "Target architecture", "armv7", ("armv7", "arm64v8", "x86", "x86_64")),
+ BoolVariable("android_neon", "Enable NEON support (armv7 only)", True),
]
def get_flags():
return [
- ('tools', False),
+ ("tools", False),
]
def create(env):
- tools = env['TOOLS']
+ tools = env["TOOLS"]
if "mingw" in tools:
- tools.remove('mingw')
+ tools.remove("mingw")
if "applelink" in tools:
tools.remove("applelink")
- env.Tool('gcc')
+ env.Tool("gcc")
return env.Clone(tools=tools)
def configure(env):
# Workaround for MinGW. See:
# http://www.scons.org/wiki/LongCmdLinesOnWin32
- if (os.name == "nt"):
+ if os.name == "nt":
import subprocess
@@ -58,8 +58,15 @@ def configure(env):
# print("SPAWNED : " + cmdline)
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env)
+ proc = subprocess.Popen(
+ cmdline,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ startupinfo=startupinfo,
+ shell=False,
+ env=env,
+ )
data, err = proc.communicate()
rv = proc.wait()
if rv:
@@ -70,7 +77,7 @@ def configure(env):
def mySpawn(sh, escape, cmd, args, env):
- newargs = ' '.join(args[1:])
+ newargs = " ".join(args[1:])
cmdline = cmd + " " + newargs
rv = 0
@@ -85,50 +92,54 @@ def configure(env):
return rv
- env['SPAWN'] = mySpawn
+ env["SPAWN"] = mySpawn
# Architecture
- if env['android_arch'] not in ['armv7', 'arm64v8', 'x86', 'x86_64']:
- env['android_arch'] = 'armv7'
+ if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]:
+ env["android_arch"] = "armv7"
neon_text = ""
- if env["android_arch"] == "armv7" and env['android_neon']:
+ if env["android_arch"] == "armv7" and env["android_neon"]:
neon_text = " (with NEON)"
- print("Building for Android (" + env['android_arch'] + ")" + neon_text)
+ print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")" + neon_text)
can_vectorize = True
- if env['android_arch'] == 'x86':
- env['ARCH'] = 'arch-x86'
+ if env["android_arch"] == "x86":
+ env["ARCH"] = "arch-x86"
env.extra_suffix = ".x86" + env.extra_suffix
target_subpath = "x86-4.9"
abi_subpath = "i686-linux-android"
arch_subpath = "x86"
env["x86_libtheora_opt_gcc"] = True
- if env['android_arch'] == 'x86_64':
+ if env["android_arch"] == "x86_64":
if get_platform(env["ndk_platform"]) < 21:
- print("WARNING: android_arch=x86_64 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21")
+ print(
+ "WARNING: android_arch=x86_64 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21"
+ )
env["ndk_platform"] = "android-21"
- env['ARCH'] = 'arch-x86_64'
+ env["ARCH"] = "arch-x86_64"
env.extra_suffix = ".x86_64" + env.extra_suffix
target_subpath = "x86_64-4.9"
abi_subpath = "x86_64-linux-android"
arch_subpath = "x86_64"
env["x86_libtheora_opt_gcc"] = True
elif env["android_arch"] == "armv7":
- env['ARCH'] = 'arch-arm'
+ env["ARCH"] = "arch-arm"
target_subpath = "arm-linux-androideabi-4.9"
abi_subpath = "arm-linux-androideabi"
arch_subpath = "armeabi-v7a"
- if env['android_neon']:
+ if env["android_neon"]:
env.extra_suffix = ".armv7.neon" + env.extra_suffix
else:
env.extra_suffix = ".armv7" + env.extra_suffix
elif env["android_arch"] == "arm64v8":
if get_platform(env["ndk_platform"]) < 21:
- print("WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21")
+ print(
+ "WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21"
+ )
env["ndk_platform"] = "android-21"
- env['ARCH'] = 'arch-arm64'
+ env["ARCH"] = "arch-arm64"
target_subpath = "aarch64-linux-android-4.9"
abi_subpath = "aarch64-linux-android"
arch_subpath = "arm64-v8a"
@@ -136,70 +147,65 @@ def configure(env):
# Build type
- if (env["target"].startswith("release")):
- if (env["optimize"] == "speed"): # optimize for speed (default)
- env.Append(LINKFLAGS=['-O2'])
- env.Append(CCFLAGS=['-O2', '-fomit-frame-pointer'])
- env.Append(CPPDEFINES=['NDEBUG'])
+ if env["target"].startswith("release"):
+ 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
- env.Append(CCFLAGS=['-Os'])
- env.Append(CPPDEFINES=['NDEBUG'])
- env.Append(LINKFLAGS=['-Os'])
-
- if (can_vectorize):
- env.Append(CCFLAGS=['-ftree-vectorize'])
- if (env["target"] == "release_debug"):
- env.Append(CPPDEFINES=['DEBUG_ENABLED'])
- elif (env["target"] == "debug"):
- env.Append(LINKFLAGS=['-O0'])
- env.Append(CCFLAGS=['-O0', '-g', '-fno-limit-debug-info'])
- env.Append(CPPDEFINES=['_DEBUG', 'DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
- env.Append(CPPFLAGS=['-UNDEBUG'])
+ env.Append(CCFLAGS=["-Os"])
+ env.Append(CPPDEFINES=["NDEBUG"])
+ env.Append(LINKFLAGS=["-Os"])
+
+ if can_vectorize:
+ env.Append(CCFLAGS=["-ftree-vectorize"])
+ if env["target"] == "release_debug":
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ elif env["target"] == "debug":
+ env.Append(LINKFLAGS=["-O0"])
+ env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"])
+ env.Append(CPPDEFINES=["_DEBUG", "DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
+ env.Append(CPPFLAGS=["-UNDEBUG"])
# Compiler configuration
- env['SHLIBSUFFIX'] = '.so'
+ env["SHLIBSUFFIX"] = ".so"
- if env['PLATFORM'] == 'win32':
- env.Tool('gcc')
+ if env["PLATFORM"] == "win32":
+ env.Tool("gcc")
env.use_windows_spawn_fix()
- mt_link = True
- if (sys.platform.startswith("linux")):
+ if sys.platform.startswith("linux"):
host_subpath = "linux-x86_64"
- elif (sys.platform.startswith("darwin")):
+ elif sys.platform.startswith("darwin"):
host_subpath = "darwin-x86_64"
- elif (sys.platform.startswith('win')):
- if (platform.machine().endswith('64')):
+ elif sys.platform.startswith("win"):
+ if platform.machine().endswith("64"):
host_subpath = "windows-x86_64"
else:
- mt_link = False
host_subpath = "windows"
- if env["android_arch"] == "arm64v8":
- mt_link = False
-
compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin"
gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath
tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin"
# For Clang to find NDK tools in preference of those system-wide
- env.PrependENVPath('PATH', tools_path)
+ env.PrependENVPath("PATH", tools_path)
ccache_path = os.environ.get("CCACHE")
if ccache_path is None:
- env['CC'] = compiler_path + '/clang'
- env['CXX'] = compiler_path + '/clang++'
+ env["CC"] = compiler_path + "/clang"
+ env["CXX"] = compiler_path + "/clang++"
else:
# there aren't any ccache wrappers available for Android,
# to enable caching we need to prepend the path to the ccache binary
- env['CC'] = ccache_path + ' ' + compiler_path + '/clang'
- env['CXX'] = ccache_path + ' ' + compiler_path + '/clang++'
- env['AR'] = tools_path + "/ar"
- env['RANLIB'] = tools_path + "/ranlib"
- env['AS'] = tools_path + "/as"
+ env["CC"] = ccache_path + " " + compiler_path + "/clang"
+ env["CXX"] = ccache_path + " " + compiler_path + "/clang++"
+ env["AR"] = tools_path + "/ar"
+ env["RANLIB"] = tools_path + "/ranlib"
+ env["AS"] = tools_path + "/as"
- common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path]
+ common_opts = ["-fno-integrated-as", "-gcc-toolchain", gcc_toolchain_path]
# Compile flags
@@ -207,14 +213,14 @@ 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']:
- env.Append(CXXFLAGS=['-frtti'])
+ if env["tools"]:
+ env.Append(CXXFLAGS=["-frtti"])
else:
- env.Append(CXXFLAGS=['-fno-rtti', '-fno-exceptions'])
+ env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])
# Don't use dynamic_cast, necessary with no-rtti.
- env.Append(CPPDEFINES=['NO_SAFE_CAST'])
+ env.Append(CPPDEFINES=["NO_SAFE_CAST"])
- lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
+ lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env["ndk_platform"] + "/" + env["ARCH"]
# Using NDK unified headers (NDK r15+)
sysroot = env["ANDROID_NDK_ROOT"] + "/sysroot"
@@ -222,35 +228,37 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath])
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/android/support/include"])
# For unified headers this define has to be set manually
- env.Append(CPPDEFINES=[('__ANDROID_API__', str(get_platform(env['ndk_platform'])))])
+ env.Append(CPPDEFINES=[("__ANDROID_API__", str(get_platform(env["ndk_platform"])))])
- env.Append(CCFLAGS='-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'.split())
- env.Append(CPPDEFINES=['NO_STATVFS', 'GLES_ENABLED'])
+ env.Append(
+ CCFLAGS="-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split()
+ )
+ env.Append(CPPDEFINES=["NO_STATVFS", "GLES_ENABLED"])
- env['neon_enabled'] = False
- if env['android_arch'] == 'x86':
- target_opts = ['-target', 'i686-none-linux-android']
+ env["neon_enabled"] = False
+ if env["android_arch"] == "x86":
+ target_opts = ["-target", "i686-none-linux-android"]
# The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least
- env.Append(CCFLAGS=['-mstackrealign'])
+ env.Append(CCFLAGS=["-mstackrealign"])
- elif env['android_arch'] == 'x86_64':
- target_opts = ['-target', 'x86_64-none-linux-android']
+ elif env["android_arch"] == "x86_64":
+ target_opts = ["-target", "x86_64-none-linux-android"]
elif env["android_arch"] == "armv7":
- target_opts = ['-target', 'armv7-none-linux-androideabi']
- env.Append(CCFLAGS='-march=armv7-a -mfloat-abi=softfp'.split())
- env.Append(CPPDEFINES=['__ARM_ARCH_7__', '__ARM_ARCH_7A__'])
- if env['android_neon']:
- env['neon_enabled'] = True
- env.Append(CCFLAGS=['-mfpu=neon'])
- env.Append(CPPDEFINES=['__ARM_NEON__'])
+ target_opts = ["-target", "armv7-none-linux-androideabi"]
+ env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
+ env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
+ if env["android_neon"]:
+ env["neon_enabled"] = True
+ env.Append(CCFLAGS=["-mfpu=neon"])
+ env.Append(CPPDEFINES=["__ARM_NEON__"])
else:
- env.Append(CCFLAGS=['-mfpu=vfpv3-d16'])
+ env.Append(CCFLAGS=["-mfpu=vfpv3-d16"])
elif env["android_arch"] == "arm64v8":
- target_opts = ['-target', 'aarch64-none-linux-android']
- env.Append(CCFLAGS=['-mfix-cortex-a53-835769'])
- env.Append(CPPDEFINES=['__ARM_ARCH_8A__'])
+ target_opts = ["-target", "aarch64-none-linux-android"]
+ env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
+ env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
env.Append(CCFLAGS=target_opts)
env.Append(CCFLAGS=common_opts)
@@ -259,29 +267,55 @@ def configure(env):
ndk_version = get_ndk_version(env["ANDROID_NDK_ROOT"])
if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("17.1.4828580"):
- env.Append(LINKFLAGS=['-Wl,--exclude-libs,libgcc.a', '-Wl,--exclude-libs,libatomic.a', '-nostdlib++'])
+ env.Append(LINKFLAGS=["-Wl,--exclude-libs,libgcc.a", "-Wl,--exclude-libs,libatomic.a", "-nostdlib++"])
else:
- env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libandroid_support.a"])
- env.Append(LINKFLAGS=['-shared', '--sysroot=' + lib_sysroot, '-Wl,--warn-shared-textrel'])
+ env.Append(
+ LINKFLAGS=[
+ env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libandroid_support.a"
+ ]
+ )
+ env.Append(LINKFLAGS=["-shared", "--sysroot=" + lib_sysroot, "-Wl,--warn-shared-textrel"])
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/"])
- env.Append(LINKFLAGS=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libc++_shared.so"])
+ env.Append(
+ LINKFLAGS=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libc++_shared.so"]
+ )
if env["android_arch"] == "armv7":
- env.Append(LINKFLAGS='-Wl,--fix-cortex-a8'.split())
- env.Append(LINKFLAGS='-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'.split())
- env.Append(LINKFLAGS='-Wl,-soname,libgodot_android.so -Wl,--gc-sections'.split())
+ env.Append(LINKFLAGS="-Wl,--fix-cortex-a8".split())
+ env.Append(LINKFLAGS="-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now".split())
+ env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so -Wl,--gc-sections".split())
env.Append(LINKFLAGS=target_opts)
env.Append(LINKFLAGS=common_opts)
- env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + '/toolchains/' + target_subpath + '/prebuilt/' +
- host_subpath + '/lib/gcc/' + abi_subpath + '/4.9.x'])
- env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] +
- '/toolchains/' + target_subpath + '/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib'])
-
- env.Prepend(CPPPATH=['#platform/android'])
- env.Append(CPPDEFINES=['ANDROID_ENABLED', 'UNIX_ENABLED', 'NO_FCNTL'])
- env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'GLESv2', 'android', 'log', 'z', 'dl'])
+ env.Append(
+ LIBPATH=[
+ env["ANDROID_NDK_ROOT"]
+ + "/toolchains/"
+ + target_subpath
+ + "/prebuilt/"
+ + host_subpath
+ + "/lib/gcc/"
+ + abi_subpath
+ + "/4.9.x"
+ ]
+ )
+ env.Append(
+ LIBPATH=[
+ env["ANDROID_NDK_ROOT"]
+ + "/toolchains/"
+ + target_subpath
+ + "/prebuilt/"
+ + host_subpath
+ + "/"
+ + abi_subpath
+ + "/lib"
+ ]
+ )
+
+ env.Prepend(CPPPATH=["#platform/android"])
+ env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED", "VULKAN_ENABLED", "NO_FCNTL"])
+ env.Append(LIBS=["OpenSLES", "EGL", "GLESv2", "vulkan", "android", "log", "z", "dl"])
# Return NDK version string in source.properties (adapted from the Chromium project).
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index ebcac884db..f8571e6277 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -34,12 +34,12 @@
#include "string_android.h"
#include "thread_jandroid.h"
-jobject DirAccessJAndroid::io = NULL;
-jclass DirAccessJAndroid::cls = NULL;
-jmethodID DirAccessJAndroid::_dir_open = NULL;
-jmethodID DirAccessJAndroid::_dir_next = NULL;
-jmethodID DirAccessJAndroid::_dir_close = NULL;
-jmethodID DirAccessJAndroid::_dir_is_dir = NULL;
+jobject DirAccessJAndroid::io = nullptr;
+jclass DirAccessJAndroid::cls = nullptr;
+jmethodID DirAccessJAndroid::_dir_open = nullptr;
+jmethodID DirAccessJAndroid::_dir_next = nullptr;
+jmethodID DirAccessJAndroid::_dir_close = nullptr;
+jmethodID DirAccessJAndroid::_dir_is_dir = nullptr;
DirAccess *DirAccessJAndroid::create_fs() {
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
new file mode 100644
index 0000000000..9534387d35
--- /dev/null
+++ b/platform/android/display_server_android.cpp
@@ -0,0 +1,655 @@
+/*************************************************************************/
+/* display_server_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "display_server_android.h"
+
+#include "android_keys_utils.h"
+#include "core/project_settings.h"
+#include "java_godot_io_wrapper.h"
+#include "java_godot_wrapper.h"
+#include "os_android.h"
+
+#if defined(OPENGL_ENABLED)
+#include "drivers/gles2/rasterizer_gles2.h"
+#endif
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_device_vulkan.h"
+#include "platform/android/vulkan/vulkan_context_android.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#endif
+
+DisplayServerAndroid *DisplayServerAndroid::get_singleton() {
+ return (DisplayServerAndroid *)DisplayServer::get_singleton();
+}
+
+bool DisplayServerAndroid::has_feature(Feature p_feature) const {
+ switch (p_feature) {
+ //case FEATURE_CONSOLE_WINDOW:
+ //case FEATURE_CURSOR_SHAPE:
+ //case FEATURE_CUSTOM_CURSOR_SHAPE:
+ //case FEATURE_GLOBAL_MENU:
+ //case FEATURE_HIDPI:
+ //case FEATURE_ICON:
+ //case FEATURE_IME:
+ //case FEATURE_MOUSE:
+ //case FEATURE_MOUSE_WARP:
+ //case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_ICON:
+ //case FEATURE_NATIVE_VIDEO:
+ //case FEATURE_WINDOW_TRANSPARENCY:
+ case FEATURE_CLIPBOARD:
+ case FEATURE_KEEP_SCREEN_ON:
+ case FEATURE_ORIENTATION:
+ case FEATURE_TOUCHSCREEN:
+ case FEATURE_VIRTUAL_KEYBOARD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+String DisplayServerAndroid::get_name() const {
+ return "Android";
+}
+
+void DisplayServerAndroid::clipboard_set(const String &p_text) {
+ GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+ ERR_FAIL_COND(!godot_java);
+
+ if (godot_java->has_set_clipboard()) {
+ godot_java->set_clipboard(p_text);
+ } else {
+ DisplayServer::clipboard_set(p_text);
+ }
+}
+
+String DisplayServerAndroid::clipboard_get() const {
+ GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+ ERR_FAIL_COND_V(!godot_java, String());
+
+ if (godot_java->has_get_clipboard()) {
+ return godot_java->get_clipboard();
+ } else {
+ return DisplayServer::clipboard_get();
+ }
+}
+
+void DisplayServerAndroid::screen_set_keep_on(bool p_enable) {
+ GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+ ERR_FAIL_COND(!godot_java);
+
+ godot_java->set_keep_screen_on(p_enable);
+ keep_screen_on = p_enable;
+}
+
+bool DisplayServerAndroid::screen_is_kept_on() const {
+ return keep_screen_on;
+}
+
+void DisplayServerAndroid::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_COND(!godot_io_java);
+
+ godot_io_java->set_screen_orientation(p_orientation);
+}
+
+DisplayServer::ScreenOrientation DisplayServerAndroid::screen_get_orientation(int p_screen) const {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_COND_V(!godot_io_java, SCREEN_LANDSCAPE);
+
+ return (ScreenOrientation)godot_io_java->get_screen_orientation();
+}
+
+int DisplayServerAndroid::get_screen_count() const {
+ return 1;
+}
+
+Point2i DisplayServerAndroid::screen_get_position(int p_screen) const {
+ return Point2i(0, 0);
+}
+
+Size2i DisplayServerAndroid::screen_get_size(int p_screen) const {
+ return OS_Android::get_singleton()->get_display_size();
+}
+
+Rect2i DisplayServerAndroid::screen_get_usable_rect(int p_screen) const {
+ Size2i display_size = OS_Android::get_singleton()->get_display_size();
+ return Rect2i(0, 0, display_size.width, display_size.height);
+}
+
+int DisplayServerAndroid::screen_get_dpi(int p_screen) const {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_COND_V(!godot_io_java, 0);
+
+ return godot_io_java->get_screen_dpi();
+}
+
+bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const {
+ return true;
+}
+
+void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_length) {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_COND(!godot_io_java);
+
+ if (godot_io_java->has_vk()) {
+ godot_io_java->show_vk(p_existing_text, p_max_length);
+ } else {
+ ERR_PRINT("Virtual keyboard not available");
+ }
+}
+
+void DisplayServerAndroid::virtual_keyboard_hide() {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_COND(!godot_io_java);
+
+ if (godot_io_java->has_vk()) {
+ godot_io_java->hide_vk();
+ } else {
+ ERR_PRINT("Virtual keyboard not available");
+ }
+}
+
+int DisplayServerAndroid::virtual_keyboard_get_height() const {
+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+ ERR_FAIL_COND_V(!godot_io_java, 0);
+
+ return godot_io_java->get_vk_height();
+}
+
+void DisplayServerAndroid::window_set_window_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
+ window_event_callback = p_callable;
+}
+
+void DisplayServerAndroid::window_set_input_event_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
+ input_event_callback = p_callable;
+}
+
+void DisplayServerAndroid::window_set_input_text_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
+ input_text_callback = p_callable;
+}
+
+void DisplayServerAndroid::window_set_rect_changed_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+void DisplayServerAndroid::window_set_drop_files_callback(const Callable &p_callable, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Variant &p_arg) const {
+ if (!p_callable.is_null()) {
+ const Variant *argp = &p_arg;
+ Variant ret;
+ Callable::CallError ce;
+ p_callable.call((const Variant **)&argp, 1, ret, ce);
+ }
+}
+
+void DisplayServerAndroid::send_window_event(DisplayServer::WindowEvent p_event) const {
+ _window_callback(window_event_callback, int(p_event));
+}
+
+void DisplayServerAndroid::send_input_event(const Ref<InputEvent> &p_event) const {
+ _window_callback(input_event_callback, p_event);
+}
+
+void DisplayServerAndroid::send_input_text(const String &p_text) const {
+ _window_callback(input_text_callback, p_text);
+}
+
+void DisplayServerAndroid::_dispatch_input_events(const Ref<InputEvent> &p_event) {
+ DisplayServerAndroid::get_singleton()->send_input_event(p_event);
+}
+
+Vector<DisplayServer::WindowID> DisplayServerAndroid::get_window_list() const {
+ Vector<WindowID> ret;
+ ret.push_back(MAIN_WINDOW_ID);
+ return ret;
+}
+
+DisplayServer::WindowID DisplayServerAndroid::get_window_at_screen_position(const Point2i &p_position) const {
+ return MAIN_WINDOW_ID;
+}
+
+void DisplayServerAndroid::window_attach_instance_id(ObjectID p_instance, DisplayServer::WindowID p_window) {
+ window_attached_instance_id = p_instance;
+}
+
+ObjectID DisplayServerAndroid::window_get_attached_instance_id(DisplayServer::WindowID p_window) const {
+ return window_attached_instance_id;
+}
+
+void DisplayServerAndroid::window_set_title(const String &p_title, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+int DisplayServerAndroid::window_get_current_screen(DisplayServer::WindowID p_window) const {
+ return SCREEN_OF_MAIN_WINDOW;
+}
+
+void DisplayServerAndroid::window_set_current_screen(int p_screen, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+Point2i DisplayServerAndroid::window_get_position(DisplayServer::WindowID p_window) const {
+ return Point2i();
+}
+
+void DisplayServerAndroid::window_set_position(const Point2i &p_position, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+void DisplayServerAndroid::window_set_transient(DisplayServer::WindowID p_window, DisplayServer::WindowID p_parent) {
+ // Not supported on Android.
+}
+
+void DisplayServerAndroid::window_set_max_size(const Size2i p_size, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+Size2i DisplayServerAndroid::window_get_max_size(DisplayServer::WindowID p_window) const {
+ return Size2i();
+}
+
+void DisplayServerAndroid::window_set_min_size(const Size2i p_size, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+Size2i DisplayServerAndroid::window_get_min_size(DisplayServer::WindowID p_window) const {
+ return Size2i();
+}
+
+void DisplayServerAndroid::window_set_size(const Size2i p_size, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+Size2i DisplayServerAndroid::window_get_size(DisplayServer::WindowID p_window) const {
+ return OS_Android::get_singleton()->get_display_size();
+}
+
+Size2i DisplayServerAndroid::window_get_real_size(DisplayServer::WindowID p_window) const {
+ return OS_Android::get_singleton()->get_display_size();
+}
+
+void DisplayServerAndroid::window_set_mode(DisplayServer::WindowMode p_mode, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+DisplayServer::WindowMode DisplayServerAndroid::window_get_mode(DisplayServer::WindowID p_window) const {
+ return WINDOW_MODE_FULLSCREEN;
+}
+
+bool DisplayServerAndroid::window_is_maximize_allowed(DisplayServer::WindowID p_window) const {
+ return false;
+}
+
+void DisplayServerAndroid::window_set_flag(DisplayServer::WindowFlags p_flag, bool p_enabled, DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+bool DisplayServerAndroid::window_get_flag(DisplayServer::WindowFlags p_flag, DisplayServer::WindowID p_window) const {
+ return false;
+}
+
+void DisplayServerAndroid::window_request_attention(DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+void DisplayServerAndroid::window_move_to_foreground(DisplayServer::WindowID p_window) {
+ // Not supported on Android.
+}
+
+bool DisplayServerAndroid::window_can_draw(DisplayServer::WindowID p_window) const {
+ return true;
+}
+
+bool DisplayServerAndroid::can_any_window_draw() const {
+ return true;
+}
+
+void DisplayServerAndroid::alert(const String &p_alert, const String &p_title) {
+ GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+ ERR_FAIL_COND(!godot_java);
+
+ godot_java->alert(p_alert, p_title);
+}
+
+void DisplayServerAndroid::process_events() {
+ // Nothing to do
+}
+
+Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
+ Vector<String> drivers;
+
+#ifdef OPENGL_ENABLED
+ drivers.push_back("opengl");
+#endif
+#ifdef VULKAN_ENABLED
+ drivers.push_back("vulkan");
+#endif
+
+ return drivers;
+}
+
+DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+}
+
+void DisplayServerAndroid::register_android_driver() {
+ register_create_function("android", create_func, get_rendering_drivers_func);
+}
+
+DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ rendering_driver = p_rendering_driver;
+
+ // TODO: rendering_driver is broken, change when different drivers are supported again
+ rendering_driver = "vulkan";
+
+ keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on");
+
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl") {
+ bool gl_initialization_error = false;
+
+ if (RasterizerGLES2::is_viable() == OK) {
+ RasterizerGLES2::register_config();
+ RasterizerGLES2::make_current();
+ } else {
+ gl_initialization_error = true;
+ }
+
+ if (gl_initialization_error) {
+ OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n"
+ "Please try updating your Android version.",
+ "Unable to initialize video driver");
+ return;
+ }
+ }
+#endif
+
+#if defined(VULKAN_ENABLED)
+ context_vulkan = nullptr;
+ rendering_device_vulkan = nullptr;
+
+ if (rendering_driver == "vulkan") {
+ ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
+ ERR_FAIL_COND(!native_window);
+
+ context_vulkan = memnew(VulkanContextAndroid);
+ if (context_vulkan->initialize() != OK) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
+ ERR_FAIL_MSG("Failed to initialize Vulkan context");
+ }
+
+ Size2i display_size = OS_Android::get_singleton()->get_display_size();
+ if (context_vulkan->window_create(native_window, display_size.width, display_size.height) == -1) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
+ ERR_FAIL_MSG("Failed to create Vulkan window.");
+ }
+
+ rendering_device_vulkan = memnew(RenderingDeviceVulkan);
+ rendering_device_vulkan->initialize(context_vulkan);
+
+ RasterizerRD::make_current();
+ }
+#endif
+
+ InputFilter::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
+}
+
+DisplayServerAndroid::~DisplayServerAndroid() {
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ if (rendering_device_vulkan) {
+ rendering_device_vulkan->finalize();
+ memdelete(rendering_device_vulkan);
+ }
+
+ if (context_vulkan) {
+ memdelete(context_vulkan);
+ }
+ }
+#endif
+}
+
+void DisplayServerAndroid::process_joy_event(DisplayServerAndroid::JoypadEvent p_event) {
+ switch (p_event.type) {
+ case JOY_EVENT_BUTTON:
+ InputFilter::get_singleton()->joy_button(p_event.device, p_event.index, p_event.pressed);
+ break;
+ case JOY_EVENT_AXIS:
+ InputFilter::JoyAxis value;
+ value.min = -1;
+ value.value = p_event.value;
+ InputFilter::get_singleton()->joy_axis(p_event.device, p_event.index, value);
+ break;
+ case JOY_EVENT_HAT:
+ InputFilter::get_singleton()->joy_hat(p_event.device, p_event.hat);
+ break;
+ default:
+ return;
+ }
+}
+
+void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) {
+ Ref<InputEventKey> ev;
+ ev.instance();
+ int val = p_unicode_char;
+ int keycode = android_get_keysym(p_keycode);
+ int phy_keycode = android_get_keysym(p_scancode);
+ ev->set_keycode(keycode);
+ ev->set_physical_keycode(phy_keycode);
+ ev->set_unicode(val);
+ ev->set_pressed(p_pressed);
+
+ if (val == '\n') {
+ ev->set_keycode(KEY_ENTER);
+ } else if (val == 61448) {
+ ev->set_keycode(KEY_BACKSPACE);
+ ev->set_unicode(KEY_BACKSPACE);
+ } else if (val == 61453) {
+ ev->set_keycode(KEY_ENTER);
+ ev->set_unicode(KEY_ENTER);
+ } else if (p_keycode == 4) {
+ OS_Android::get_singleton()->main_loop_request_go_back();
+ }
+
+ InputFilter::get_singleton()->parse_input_event(ev);
+}
+
+void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector<DisplayServerAndroid::TouchPos> &p_points) {
+ switch (p_what) {
+ case 0: { //gesture begin
+ if (touch.size()) {
+ //end all if exist
+ for (int i = 0; i < touch.size(); i++) {
+
+ Ref<InputEventScreenTouch> ev;
+ ev.instance();
+ ev->set_index(touch[i].id);
+ ev->set_pressed(false);
+ ev->set_position(touch[i].pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ }
+ }
+
+ touch.resize(p_points.size());
+ for (int i = 0; i < p_points.size(); i++) {
+ touch.write[i].id = p_points[i].id;
+ touch.write[i].pos = p_points[i].pos;
+ }
+
+ //send touch
+ for (int i = 0; i < touch.size(); i++) {
+
+ Ref<InputEventScreenTouch> ev;
+ ev.instance();
+ ev->set_index(touch[i].id);
+ ev->set_pressed(true);
+ ev->set_position(touch[i].pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ }
+
+ } break;
+ case 1: { //motion
+ ERR_FAIL_COND(touch.size() != p_points.size());
+
+ for (int i = 0; i < touch.size(); i++) {
+
+ int idx = -1;
+ for (int j = 0; j < p_points.size(); j++) {
+
+ if (touch[i].id == p_points[j].id) {
+ idx = j;
+ break;
+ }
+ }
+
+ ERR_CONTINUE(idx == -1);
+
+ if (touch[i].pos == p_points[idx].pos)
+ continue; //no move unncesearily
+
+ Ref<InputEventScreenDrag> ev;
+ ev.instance();
+ ev->set_index(touch[i].id);
+ ev->set_position(p_points[idx].pos);
+ ev->set_relative(p_points[idx].pos - touch[i].pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ touch.write[i].pos = p_points[idx].pos;
+ }
+
+ } break;
+ case 2: { //release
+ if (touch.size()) {
+ //end all if exist
+ for (int i = 0; i < touch.size(); i++) {
+
+ Ref<InputEventScreenTouch> ev;
+ ev.instance();
+ ev->set_index(touch[i].id);
+ ev->set_pressed(false);
+ ev->set_position(touch[i].pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ }
+ touch.clear();
+ }
+ } break;
+ case 3: { // add touch
+ for (int i = 0; i < p_points.size(); i++) {
+ if (p_points[i].id == p_pointer) {
+ TouchPos tp = p_points[i];
+ touch.push_back(tp);
+
+ Ref<InputEventScreenTouch> ev;
+ ev.instance();
+
+ ev->set_index(tp.id);
+ ev->set_pressed(true);
+ ev->set_position(tp.pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+
+ break;
+ }
+ }
+ } break;
+ case 4: { // remove touch
+ for (int i = 0; i < touch.size(); i++) {
+ if (touch[i].id == p_pointer) {
+
+ Ref<InputEventScreenTouch> ev;
+ ev.instance();
+ ev->set_index(touch[i].id);
+ ev->set_pressed(false);
+ ev->set_position(touch[i].pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ touch.remove(i);
+
+ break;
+ }
+ }
+ } break;
+ }
+}
+
+void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) {
+ // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
+ switch (p_type) {
+ case 7: // hover move
+ case 9: // hover enter
+ case 10: { // hover exit
+ Ref<InputEventMouseMotion> ev;
+ ev.instance();
+ ev->set_position(p_pos);
+ ev->set_global_position(p_pos);
+ ev->set_relative(p_pos - hover_prev_pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ hover_prev_pos = p_pos;
+ } break;
+ }
+}
+
+void DisplayServerAndroid::process_double_tap(Point2 p_pos) {
+ Ref<InputEventMouseButton> ev;
+ ev.instance();
+ ev->set_position(p_pos);
+ ev->set_global_position(p_pos);
+ ev->set_pressed(false);
+ ev->set_doubleclick(true);
+ InputFilter::get_singleton()->parse_input_event(ev);
+}
+
+void DisplayServerAndroid::process_scroll(Point2 p_pos) {
+ Ref<InputEventPanGesture> ev;
+ ev.instance();
+ ev->set_position(p_pos);
+ ev->set_delta(p_pos - scroll_prev_pos);
+ InputFilter::get_singleton()->parse_input_event(ev);
+ scroll_prev_pos = p_pos;
+}
+
+void DisplayServerAndroid::process_accelerometer(const Vector3 &p_accelerometer) {
+ InputFilter::get_singleton()->set_accelerometer(p_accelerometer);
+}
+
+void DisplayServerAndroid::process_gravity(const Vector3 &p_gravity) {
+ InputFilter::get_singleton()->set_gravity(p_gravity);
+}
+
+void DisplayServerAndroid::process_magnetometer(const Vector3 &p_magnetometer) {
+ InputFilter::get_singleton()->set_magnetometer(p_magnetometer);
+}
+
+void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) {
+ InputFilter::get_singleton()->set_gyroscope(p_gyroscope);
+}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
new file mode 100644
index 0000000000..2096ba68f1
--- /dev/null
+++ b/platform/android/display_server_android.h
@@ -0,0 +1,174 @@
+/*************************************************************************/
+/* display_server_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 DISPLAY_SERVER_ANDROID_H
+#define DISPLAY_SERVER_ANDROID_H
+
+#include "servers/display_server.h"
+
+#if defined(VULKAN_ENABLED)
+class VulkanContextAndroid;
+class RenderingDeviceVulkan;
+#endif
+
+class DisplayServerAndroid : public DisplayServer {
+public:
+ struct TouchPos {
+ int id;
+ Point2 pos;
+ };
+
+ enum {
+ JOY_EVENT_BUTTON = 0,
+ JOY_EVENT_AXIS = 1,
+ JOY_EVENT_HAT = 2
+ };
+
+ struct JoypadEvent {
+
+ int device;
+ int type;
+ int index;
+ bool pressed;
+ float value;
+ int hat;
+ };
+
+private:
+ String rendering_driver;
+
+ bool keep_screen_on;
+
+ Vector<TouchPos> touch;
+ Point2 hover_prev_pos; // needed to calculate the relative position on hover events
+ Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events
+
+#if defined(VULKAN_ENABLED)
+ VulkanContextAndroid *context_vulkan;
+ RenderingDeviceVulkan *rendering_device_vulkan;
+#endif
+
+ ObjectID window_attached_instance_id;
+
+ Callable window_event_callback;
+ Callable input_event_callback;
+ Callable input_text_callback;
+
+ void _window_callback(const Callable &p_callable, const Variant &p_arg) const;
+
+ static void _dispatch_input_events(const Ref<InputEvent> &p_event);
+
+public:
+ static DisplayServerAndroid *get_singleton();
+
+ virtual bool has_feature(Feature p_feature) const;
+ virtual String get_name() const;
+
+ virtual void clipboard_set(const String &p_text);
+ virtual String clipboard_get() const;
+
+ virtual void screen_set_keep_on(bool p_enable);
+ virtual bool screen_is_kept_on() const;
+
+ virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW);
+ virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual int get_screen_count() const;
+ virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_length = -1);
+ virtual void virtual_keyboard_hide();
+ virtual int virtual_keyboard_get_height() const;
+
+ virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+
+ void send_window_event(WindowEvent p_event) const;
+ void send_input_event(const Ref<InputEvent> &p_event) const;
+ void send_input_text(const String &p_text) const;
+
+ virtual Vector<WindowID> get_window_list() const;
+ virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
+ virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID);
+ virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+ virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_transient(WindowID p_window, WindowID p_parent);
+ virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
+ virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
+ virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
+ virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual bool can_any_window_draw() const;
+
+ virtual void alert(const String &p_alert, const String &p_title);
+
+ virtual void process_events();
+
+ void process_accelerometer(const Vector3 &p_accelerometer);
+ void process_gravity(const Vector3 &p_gravity);
+ void process_magnetometer(const Vector3 &p_magnetometer);
+ void process_gyroscope(const Vector3 &p_gyroscope);
+ void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points);
+ void process_hover(int p_type, Point2 p_pos);
+ void process_double_tap(Point2 p_pos);
+ void process_scroll(Point2 p_pos);
+ void process_joy_event(JoypadEvent p_event);
+ void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
+
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static Vector<String> get_rendering_drivers_func();
+ static void register_android_driver();
+
+ DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ ~DisplayServerAndroid();
+};
+
+#endif // DISPLAY_SERVER_ANDROID_H
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index e7d4bc6c51..1eb1ee0d29 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -194,7 +194,7 @@ static const char *android_perms[] = {
"WRITE_SOCIAL_STREAM",
"WRITE_SYNC_SETTINGS",
"WRITE_USER_DICTIONARY",
- NULL
+ nullptr
};
struct LauncherIcon {
@@ -274,7 +274,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
List<String> args;
args.push_back("devices");
int ec;
- OS::get_singleton()->execute(adb, args, true, NULL, &devices, &ec);
+ OS::get_singleton()->execute(adb, args, true, nullptr, &devices, &ec);
Vector<String> ds = devices.split("\n");
Vector<String> ldevices;
@@ -332,7 +332,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int ec2;
String dp;
- OS::get_singleton()->execute(adb, args, true, NULL, &dp, &ec2);
+ OS::get_singleton()->execute(adb, args, true, nullptr, &dp, &ec2);
Vector<String> props = dp.split("\n");
String vendor;
@@ -447,7 +447,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
return pname;
}
- bool is_package_name_valid(const String &p_package, String *r_error = NULL) const {
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
String pname = p_package;
@@ -537,7 +537,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
".scn", // Binary scenes are usually already compressed
".stex", // Streamable textures are usually already compressed
// Trailer for easier processing
- NULL
+ nullptr
};
for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
@@ -591,11 +591,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
zipOpenNewFileInZip(ed->apk,
p_path.utf8().get_data(),
&zipfi,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
compression_method,
Z_DEFAULT_COMPRESSION);
@@ -1530,7 +1530,7 @@ public:
args.push_back("uninstall");
args.push_back(get_package_name(package_name));
- err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
+ err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
}
print_line("Installing to device (please wait...): " + devices[p_device].name);
@@ -1545,7 +1545,7 @@ public:
args.push_back("-r");
args.push_back(tmp_export_path);
- err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
+ err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
if (err || rv != 0) {
EditorNode::add_io_error("Could not install to device.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -1563,7 +1563,7 @@ public:
args.push_back(devices[p_device].id);
args.push_back("reverse");
args.push_back("--remove-all");
- OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
+ OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
@@ -1575,7 +1575,7 @@ public:
args.push_back("tcp:" + itos(dbg_port));
args.push_back("tcp:" + itos(dbg_port));
- OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
+ OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
print_line("Reverse result: " + itos(rv));
}
@@ -1590,7 +1590,7 @@ public:
args.push_back("tcp:" + itos(fs_port));
args.push_back("tcp:" + itos(fs_port));
- err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
+ err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
print_line("Reverse result2: " + itos(rv));
}
} else {
@@ -1619,7 +1619,7 @@ public:
args.push_back("-n");
args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
- err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv);
+ err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
if (err || rv != 0) {
EditorNode::add_io_error("Could not execute on device.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -1806,7 +1806,7 @@ public:
/*{ used for debug
int ec;
String pipe;
- OS::get_singleton()->execute(build_command, cmdline, true, NULL, NULL, &ec);
+ OS::get_singleton()->execute(build_command, cmdline, true, nullptr, nullptr, &ec);
print_line("exit code: " + itos(ec));
}
*/
@@ -1851,7 +1851,7 @@ public:
return ERR_FILE_BAD_PATH;
}
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
if (ep.step("Creating APK...", 0)) {
@@ -1868,7 +1868,7 @@ public:
int ret = unzGoToFirstFile(pkg);
zlib_filefunc_def io2 = io;
- FileAccess *dst_f = NULL;
+ FileAccess *dst_f = nullptr;
io2.opaque = &dst_f;
String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk");
@@ -1879,7 +1879,7 @@ public:
return m_err; \
}
- zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+ zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
bool use_32_fb = p_preset->get("graphics/32_bits_framebuffer");
bool immersive = p_preset->get("screen/immersive_mode");
@@ -1932,12 +1932,13 @@ public:
ImageLoader::load_image(path, launcher_adaptive_icon_background_image);
}
+ Vector<String> invalid_abis(enabled_abis);
while (ret == UNZ_OK) {
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
bool skip = false;
@@ -1977,6 +1978,7 @@ public:
bool enabled = false;
for (int i = 0; i < enabled_abis.size(); ++i) {
if (file.begins_with("lib/" + enabled_abis[i] + "/")) {
+ invalid_abis.erase(enabled_abis[i]);
enabled = true;
break;
}
@@ -2001,11 +2003,11 @@ public:
zipOpenNewFileInZip(unaligned_apk,
file.utf8().get_data(),
&zipfi,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
uncompressed ? 0 : Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
@@ -2016,6 +2018,13 @@ public:
ret = unzGoToNextFile(pkg);
}
+ if (!invalid_abis.empty()) {
+ String unsupported_arch = String(", ").join(invalid_abis);
+ EditorNode::add_io_error("Missing libraries in the export template for the selected architectures: " + unsupported_arch + ".\n" +
+ "Please build a template with all required libraries, or uncheck the missing architectures in the export preset.");
+ CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND);
+ }
+
if (ep.step("Adding files...", 1)) {
CLEANUP_AND_RETURN(ERR_SKIP);
}
@@ -2108,11 +2117,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);
@@ -2120,7 +2129,7 @@ public:
zipCloseFileInZip(unaligned_apk);
}
- zipClose(unaligned_apk, NULL);
+ zipClose(unaligned_apk, nullptr);
unzClose(pkg);
if (err != OK) {
@@ -2188,7 +2197,7 @@ public:
args.push_back(tmp_unaligned_path);
args.push_back(user);
int retval;
- OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval);
+ OS::get_singleton()->execute(jarsigner, args, true, nullptr, nullptr, &retval);
if (retval) {
EditorNode::add_io_error("'jarsigner' returned with error #" + itos(retval));
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -2205,7 +2214,7 @@ public:
args.push_back(tmp_unaligned_path);
args.push_back("-verbose");
- OS::get_singleton()->execute(jarsigner, args, true, NULL, NULL, &retval);
+ OS::get_singleton()->execute(jarsigner, args, true, nullptr, nullptr, &retval);
if (retval) {
EditorNode::add_io_error("'jarsigner' verification of APK failed. Make sure to use a jarsigner from OpenJDK 8.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -2230,9 +2239,9 @@ public:
ret = unzGoToFirstFile(tmp_unaligned);
io2 = io;
- dst_f = NULL;
+ dst_f = nullptr;
io2.opaque = &dst_f;
- zipFile final_apk = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+ zipFile final_apk = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
// Take files from the unaligned APK and write them out to the aligned one
// in raw mode, i.e. not uncompressing and recompressing, aligning them as needed,
@@ -2245,7 +2254,7 @@ public:
char fname[16384];
char extra[16384];
- ret = unzGetCurrentFileInfo(tmp_unaligned, &info, fname, 16384, extra, 16384 - ZIP_ALIGNMENT, NULL, 0);
+ ret = unzGetCurrentFileInfo(tmp_unaligned, &info, fname, 16384, extra, 16384 - ZIP_ALIGNMENT, nullptr, 0);
String file = fname;
@@ -2277,9 +2286,9 @@ public:
&zipfi,
extra,
info.size_file_extra + padding,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
method,
level,
1); // raw write
@@ -2291,7 +2300,7 @@ public:
ret = unzGoToNextFile(tmp_unaligned);
}
- zipClose(final_apk, NULL);
+ zipClose(final_apk, nullptr);
unzClose(tmp_unaligned);
CLEANUP_AND_RETURN(OK);
diff --git a/platform/android/export/export.h b/platform/android/export/export.h
index ce786cc8b6..d11ab9f49e 100644
--- a/platform/android/export/export.h
+++ b/platform/android/export/export.h
@@ -28,4 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef ANDROID_EXPORT_H
+#define ANDROID_EXPORT_H
+
void register_android_exporter();
+
+#endif // ANDROID_EXPORT_H
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index 965342b364..fa805ec4f3 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -31,7 +31,7 @@
#include "file_access_android.h"
#include "core/print_string.h"
-AAssetManager *FileAccessAndroid::asset_manager = NULL;
+AAssetManager *FileAccessAndroid::asset_manager = nullptr;
/*void FileAccessAndroid::make_default() {
@@ -68,12 +68,12 @@ void FileAccessAndroid::close() {
if (!a)
return;
AAsset_close(a);
- a = NULL;
+ a = nullptr;
}
bool FileAccessAndroid::is_open() const {
- return a != NULL;
+ return a != nullptr;
}
void FileAccessAndroid::seek(size_t p_position) {
@@ -175,7 +175,7 @@ bool FileAccessAndroid::file_exists(const String &p_path) {
}
FileAccessAndroid::FileAccessAndroid() {
- a = NULL;
+ a = nullptr;
eof = false;
}
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
index db3aa4255e..e088eca8ef 100644
--- a/platform/android/file_access_jandroid.cpp
+++ b/platform/android/file_access_jandroid.cpp
@@ -33,7 +33,7 @@
#include "thread_jandroid.h"
#include <unistd.h>
-jobject FileAccessJAndroid::io = NULL;
+jobject FileAccessJAndroid::io = nullptr;
jclass FileAccessJAndroid::cls;
jmethodID FileAccessJAndroid::_file_open = 0;
jmethodID FileAccessJAndroid::_file_get_size = 0;
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 5e37f538e9..99080eeb3c 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -56,6 +56,11 @@ android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
+ compileOptions {
+ sourceCompatibility 1.8
+ targetCompatibility 1.8
+ }
+
defaultConfig {
// Feel free to modify the application id to your own.
applicationId getExportPackageName()
@@ -71,6 +76,7 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
+ doNotStrip '**/*.so'
}
// Both signing and zip-aligning will be done at export time
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index eaaefcbccb..aa98194a10 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,9 +1,9 @@
ext.versions = [
- androidGradlePlugin: '3.6.0',
+ androidGradlePlugin: '3.5.3',
compileSdk : 29,
minSdk : 18,
targetSdk : 29,
- buildTools : '29.0.1',
+ buildTools : '29.0.3',
supportCoreUtils : '28.0.0',
kotlinVersion : '1.3.61',
v4Support : '28.0.0'
diff --git a/platform/android/java/app/settings.gradle b/platform/android/java/app/settings.gradle
new file mode 100644
index 0000000000..33b863c7bf
--- /dev/null
+++ b/platform/android/java/app/settings.gradle
@@ -0,0 +1,2 @@
+// Empty settings.gradle file to denote this directory as being the root project
+// of the Godot custom build.
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 976a5bda99..865b61956c 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -25,7 +25,7 @@ ext {
sconsExt = org.gradle.internal.os.OperatingSystem.current().isWindows() ? ".bat" : ""
supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
- supportedTargets = ['release': "release", 'debug': "release_debug"]
+ supportedTargets = ["release", "debug"]
// Used by gradle to specify which architecture to build for by default when running `./gradlew build`.
// This command is usually used by Android Studio.
@@ -136,14 +136,14 @@ task zipCustomBuild(type: Zip) {
*/
task generateGodotTemplates(type: GradleBuild) {
// We exclude these gradle tasks so we can run the scons command manually.
- for (String buildType : supportedTargets.keySet()) {
+ for (String buildType : supportedTargets) {
startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType)
}
tasks = ["copyGodotPaymentPluginToAppModule"]
// Only build the apks and aar files for which we have native shared libraries.
- for (String target : supportedTargets.keySet()) {
+ for (String target : supportedTargets) {
File targetLibs = new File("lib/libs/" + target)
if (targetLibs != null
&& targetLibs.isDirectory()
diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml
index b133585f99..fa39bc0f1d 100644
--- a/platform/android/java/lib/AndroidManifest.xml
+++ b/platform/android/java/lib/AndroidManifest.xml
@@ -13,7 +13,7 @@
<instrumentation
android:icon="@mipmap/icon"
android:label="@string/godot_project_name_string"
- android:name=".GodotInstrumentation"
+ android:name="org.godotengine.godot.GodotInstrumentation"
android:targetPackage="org.godotengine.godot" />
</manifest>
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index ca8aaf8af0..6bb438c249 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -1,4 +1,5 @@
apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
dependencies {
implementation libraries.supportCoreUtils
@@ -11,7 +12,6 @@ def pathToRootDir = "../../../../"
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
- useLibrary 'org.apache.http.legacy'
defaultConfig {
minSdkVersion versions.minSdk
@@ -26,6 +26,7 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
+ doNotStrip '**/*.so'
}
sourceSets {
@@ -56,7 +57,7 @@ android {
// files is only setup for editing support.
gradle.startParameter.excludedTaskNames += taskPrefix + "externalNativeBuild" + buildType
- def releaseTarget = supportedTargets[buildType.toLowerCase()]
+ def releaseTarget = buildType.toLowerCase()
if (releaseTarget == null || releaseTarget == "") {
throw new GradleException("Invalid build type: " + buildType)
}
diff --git a/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png
deleted file mode 100644
index f849d8e90d..0000000000
--- a/platform/android/java/lib/res/drawable-hdpi/notify_panel_notification_icon_bg.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png
deleted file mode 100644
index 1dfb28b33a..0000000000
--- a/platform/android/java/lib/res/drawable-mdpi/notify_panel_notification_icon_bg.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.png
deleted file mode 100644
index 372b763ec5..0000000000
--- a/platform/android/java/lib/res/drawable-xhdpi/notify_panel_notification_icon_bg.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png b/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png
deleted file mode 100644
index 302a972049..0000000000
--- a/platform/android/java/lib/res/drawable-xxhdpi/notify_panel_notification_icon_bg.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java
index 1dcc370d83..0700b78a28 100644
--- a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java
+++ b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java
@@ -233,4 +233,4 @@ public class Constants {
*/
public static final long ACTIVE_THREAD_WATCHDOG = 5*1000;
-} \ No newline at end of file
+}
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 7db4aa6597..bf0d1c6273 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -55,8 +55,6 @@ import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
-import android.os.Handler;
-import android.os.Looper;
import android.os.Messenger;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -64,7 +62,6 @@ import android.provider.Settings.Secure;
import android.support.annotation.CallSuper;
import android.support.annotation.Keep;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.view.Display;
import android.view.KeyEvent;
@@ -95,7 +92,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import org.godotengine.godot.input.GodotEditText;
-import org.godotengine.godot.payments.PaymentsManager;
import org.godotengine.godot.plugin.GodotPlugin;
import org.godotengine.godot.plugin.GodotPluginRegistry;
import org.godotengine.godot.utils.GodotNetUtils;
@@ -157,7 +153,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
private String[] command_line;
private boolean use_apk_expansion;
- public GodotView mView;
+ public GodotRenderView mRenderView;
private boolean godot_initialized = false;
private SensorManager mSensorManager;
@@ -174,21 +170,17 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
}
public ResultCallback result_callback;
- private PaymentsManager mPaymentsManager = null;
-
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE) {
- mPaymentsManager.processPurchaseResponse(resultCode, data);
- } else if (result_callback != null) {
+ if (result_callback != null) {
result_callback.callback(requestCode, resultCode, data);
result_callback = null;
- };
+ }
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainActivityResult(requestCode, resultCode, data);
}
- };
+ }
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
@@ -202,12 +194,12 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
};
/**
- * Invoked on the GL thread when the Godot main loop has started.
+ * Invoked on the render thread when the Godot main loop has started.
*/
@CallSuper
- protected void onGLGodotMainLoopStarted() {
+ protected void onGodotMainLoopStarted() {
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onGLGodotMainLoopStarted();
+ plugin.onGodotMainLoopStarted();
}
}
@@ -221,38 +213,45 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
setContentView(layout);
// GodotEditText layout
- GodotEditText edittext = new GodotEditText(this);
- edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+ GodotEditText editText = new GodotEditText(this);
+ editText.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
// ...add to FrameLayout
- layout.addView(edittext);
+ layout.addView(editText);
+
+ GodotLib.setup(command_line);
- mView = new GodotView(this, xrMode, use_32_bits, use_debug_opengl);
- layout.addView(mView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- edittext.setView(mView);
- io.setEdit(edittext);
+ final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name");
+ if (videoDriver.equals("Vulkan")) {
+ mRenderView = new GodotVulkanRenderView(this);
+ } else {
+ mRenderView = new GodotGLRenderView(this, xrMode, use_32_bits, use_debug_opengl);
+ }
+
+ View view = mRenderView.getView();
+ layout.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ editText.setView(mRenderView);
+ io.setEdit(editText);
- mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Point fullSize = new Point();
getWindowManager().getDefaultDisplay().getSize(fullSize);
Rect gameSize = new Rect();
- mView.getWindowVisibleDisplayFrame(gameSize);
+ mRenderView.getView().getWindowVisibleDisplayFrame(gameSize);
final int keyboardHeight = fullSize.y - gameSize.bottom;
GodotLib.setVirtualKeyboardHeight(keyboardHeight);
}
});
- final String[] current_command_line = command_line;
- mView.queueEvent(new Runnable() {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
- GodotLib.setup(current_command_line);
// Must occur after GodotLib.setup has completed.
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- plugin.onGLRegisterPluginWithGodotNative();
+ plugin.onRegisterPluginWithGodotNative();
}
setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
@@ -392,7 +391,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
*/
@Keep
private Surface getSurface() {
- return mView.getHolder().getSurface();
+ return mRenderView.getView().getHolder().getSurface();
}
/**
@@ -445,8 +444,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
result_callback = null;
- mPaymentsManager = PaymentsManager.createManager(this).initService();
-
godot_initialized = true;
}
@@ -603,7 +600,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
@Override
protected void onDestroy() {
- if (mPaymentsManager != null) mPaymentsManager.destroy();
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainDestroy();
}
@@ -628,7 +624,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
}
return;
}
- mView.onPause();
+ mRenderView.onActivityPaused();
mSensorManager.unregisterListener(this);
@@ -666,7 +662,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
return;
}
- mView.onResume();
+ mRenderView.onActivityResumed();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
@@ -732,8 +728,8 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
final float z = adjustedValues[2];
final int typeOfSensor = event.sensor.getType();
- if (mView != null) {
- mView.queueEvent(new Runnable() {
+ if (mRenderView != null) {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) {
@@ -784,8 +780,8 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
}
}
- if (shouldQuit && mView != null) {
- mView.queueEvent(new Runnable() {
+ if (shouldQuit && mRenderView != null) {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
GodotLib.back();
@@ -795,13 +791,13 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
}
/**
- * Queue a runnable to be run on the GL thread.
+ * Queue a runnable to be run on the render thread.
* <p>
- * This must be called after the GL thread has started.
+ * This must be called after the render thread has started.
*/
- public final void runOnGLThread(@NonNull Runnable action) {
- if (mView != null) {
- mView.queueEvent(action);
+ public final void runOnRenderThread(@NonNull Runnable action) {
+ if (mRenderView != null) {
+ mRenderView.queueOnRenderThread(action);
}
}
@@ -858,7 +854,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
if (evcount == 0)
return true;
- if (mView != null) {
+ if (mRenderView != null) {
final int[] arr = new int[event.getPointerCount() * 3];
for (int i = 0; i < event.getPointerCount(); i++) {
@@ -871,7 +867,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
//System.out.printf("gaction: %d\n",event.getAction());
final int action = event.getAction() & MotionEvent.ACTION_MASK;
- mView.queueEvent(new Runnable() {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
switch (action) {
@@ -922,7 +918,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0)
;
if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event);
- mView.queueEvent(new Runnable() {
+ mRenderView.queueOnRenderThread(new Runnable() {
// This method will be called on the rendering thread:
public void run() {
for (int i = 0, n = cc.length; i < n; i++) {
@@ -938,10 +934,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
return true;
}
- public PaymentsManager getPaymentsManager() {
- return mPaymentsManager;
- }
-
public boolean requestPermission(String p_name) {
return PermissionsUtil.requestPermission(p_name, this);
}
@@ -1048,6 +1040,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
progress.mOverallTotal));
}
public void initInputDevices() {
- mView.initInputDevices();
+ mRenderView.initInputDevices();
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
new file mode 100644
index 0000000000..9be93243b8
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -0,0 +1,225 @@
+/*************************************************************************/
+/* GodotGLRenderView.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 android.annotation.SuppressLint;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SurfaceView;
+import org.godotengine.godot.input.GodotGestureHandler;
+import org.godotengine.godot.input.GodotInputHandler;
+import org.godotengine.godot.utils.GLUtils;
+import org.godotengine.godot.xr.XRMode;
+import org.godotengine.godot.xr.ovr.OvrConfigChooser;
+import org.godotengine.godot.xr.ovr.OvrContextFactory;
+import org.godotengine.godot.xr.ovr.OvrWindowSurfaceFactory;
+import org.godotengine.godot.xr.regular.RegularConfigChooser;
+import org.godotengine.godot.xr.regular.RegularContextFactory;
+import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser;
+
+/**
+ * A simple GLSurfaceView sub-class that demonstrate how to perform
+ * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
+ * details:
+ *
+ * - The class must use a custom context factory to enable 2.0 rendering.
+ * See ContextFactory class definition below.
+ *
+ * - The class must use a custom EGLConfigChooser to be able to select
+ * an EGLConfig that supports 2.0. This is done by providing a config
+ * specification to eglChooseConfig() that has the attribute
+ * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
+ * set. See ConfigChooser class definition below.
+ *
+ * - The class must select the surface's format, then choose an EGLConfig
+ * that matches it exactly (with regards to red/green/blue/alpha channels
+ * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
+ */
+public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
+
+ private final Godot activity;
+ private final GodotInputHandler inputHandler;
+ private final GestureDetector detector;
+ private final GodotRenderer godotRenderer;
+
+ public GodotGLRenderView(Godot activity, XRMode xrMode, boolean p_use_32_bits, boolean p_use_debug_opengl) {
+ super(activity);
+ GLUtils.use_32 = p_use_32_bits;
+ GLUtils.use_debug_opengl = p_use_debug_opengl;
+
+ this.activity = activity;
+ this.inputHandler = new GodotInputHandler(this);
+ this.detector = new GestureDetector(activity, new GodotGestureHandler(this));
+ this.godotRenderer = new GodotRenderer();
+ init(xrMode, false, 16, 0);
+ }
+
+ @Override
+ public SurfaceView getView() {
+ return this;
+ }
+
+ @Override
+ public void initInputDevices() {
+ this.inputHandler.initInputDevices();
+ }
+
+ @Override
+ public void queueOnRenderThread(Runnable event) {
+ queueEvent(event);
+ }
+
+ @Override
+ public void onActivityPaused() {
+ onPause();
+ }
+
+ @Override
+ public void onActivityResumed() {
+ onResume();
+ }
+
+ @Override
+ public void onBackPressed() {
+ activity.onBackPressed();
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ this.detector.onTouchEvent(event);
+ return activity.gotTouchEvent(event);
+ }
+
+ @Override
+ public boolean onKeyUp(final int keyCode, KeyEvent event) {
+ return inputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyDown(final int keyCode, KeyEvent event) {
+ return inputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
+ }
+
+ private void init(XRMode xrMode, boolean translucent, int depth, int stencil) {
+
+ setPreserveEGLContextOnPause(true);
+ setFocusableInTouchMode(true);
+ switch (xrMode) {
+
+ case OVR:
+ // Replace the default egl config chooser.
+ setEGLConfigChooser(new OvrConfigChooser());
+
+ // Replace the default context factory.
+ setEGLContextFactory(new OvrContextFactory());
+
+ // Replace the default window surface factory.
+ setEGLWindowSurfaceFactory(new OvrWindowSurfaceFactory());
+ break;
+
+ case REGULAR:
+ default:
+ /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
+ * If we want a translucent one, we should change the surface's
+ * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
+ * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
+ */
+ if (translucent) {
+ this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ /* Setup the context factory for 2.0 rendering.
+ * See ContextFactory class definition below
+ */
+ setEGLContextFactory(new RegularContextFactory());
+
+ /* We need to choose an EGLConfig that matches the format of
+ * our surface exactly. This is going to be done in our
+ * custom config chooser. See ConfigChooser class definition
+ * below.
+ */
+
+ if (GLUtils.use_32) {
+ setEGLConfigChooser(translucent ?
+ new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
+ new RegularConfigChooser(8, 8, 8, 8, 16, stencil)) :
+ new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
+ new RegularConfigChooser(5, 6, 5, 0, 16, stencil)));
+
+ } else {
+ setEGLConfigChooser(translucent ?
+ new RegularConfigChooser(8, 8, 8, 8, 16, stencil) :
+ new RegularConfigChooser(5, 6, 5, 0, 16, stencil));
+ }
+ break;
+ }
+
+ /* Set the renderer responsible for frame rendering */
+ setRenderer(godotRenderer);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ // Resume the renderer
+ godotRenderer.onActivityResumed();
+ GodotLib.focusin();
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.focusout();
+ // Pause the renderer
+ godotRenderer.onActivityPaused();
+ }
+ });
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index 68ce40ba10..016a3a8d18 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -53,8 +53,6 @@ public class GodotIO {
Godot activity;
GodotEditText edit;
- MediaPlayer mediaPlayer;
-
final int SCREEN_LANDSCAPE = 0;
final int SCREEN_PORTRAIT = 1;
final int SCREEN_REVERSE_LANDSCAPE = 2;
@@ -530,44 +528,14 @@ public class GodotIO {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
} break;
}
- };
-
- public void setEdit(GodotEditText _edit) {
- edit = _edit;
- }
-
- public void playVideo(String p_path) {
- Uri filePath = Uri.parse(p_path);
- mediaPlayer = new MediaPlayer();
-
- try {
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setDataSource(activity.getApplicationContext(), filePath);
- mediaPlayer.prepare();
- mediaPlayer.start();
- } catch (IOException e) {
- System.out.println("IOError while playing video");
- }
}
- public boolean isVideoPlaying() {
- if (mediaPlayer != null) {
- return mediaPlayer.isPlaying();
- }
- return false;
+ public int getScreenOrientation() {
+ return activity.getRequestedOrientation();
}
- public void pauseVideo() {
- if (mediaPlayer != null) {
- mediaPlayer.pause();
- }
- }
-
- public void stopVideo() {
- if (mediaPlayer != null) {
- mediaPlayer.release();
- mediaPlayer = null;
- }
+ public void setEdit(GodotEditText _edit) {
+ edit = _edit;
}
public static final int SYSTEM_DIR_DESKTOP = 0;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 89a65aea24..71fe822233 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -32,6 +32,7 @@ package org.godotengine.godot;
import android.app.Activity;
import android.hardware.SensorEvent;
+import android.view.Surface;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@@ -72,11 +73,11 @@ public class GodotLib {
public static native void resize(int width, int height);
/**
- * Invoked on the GL thread when the underlying Android surface is created or recreated.
+ * Invoked on the render thread when the underlying Android surface is created or recreated.
+ * @param p_surface
* @param p_32_bits
- * @see android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig)
*/
- public static native void newcontext(boolean p_32_bits);
+ public static native void newcontext(Surface p_surface, boolean p_32_bits);
/**
* Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
new file mode 100644
index 0000000000..170c433c9c
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* GodotRenderView.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 android.view.SurfaceView;
+
+public interface GodotRenderView {
+
+ abstract public SurfaceView getView();
+
+ abstract public void initInputDevices();
+
+ abstract public void queueOnRenderThread(Runnable event);
+
+ abstract public void onActivityPaused();
+ abstract public void onActivityResumed();
+
+ abstract public void onBackPressed();
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
index ee9a2aee4f..3e5bb4a4c9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
@@ -70,7 +70,7 @@ class GodotRenderer implements GLSurfaceView.Renderer {
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- GodotLib.newcontext(GLUtils.use_32);
+ GodotLib.newcontext(null, GLUtils.use_32);
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onGLSurfaceCreated(gl, config);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotView.java
deleted file mode 100644
index 8d3c2ae319..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*************************************************************************/
-/* GodotView.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 android.annotation.SuppressLint;
-import android.graphics.PixelFormat;
-import android.opengl.GLSurfaceView;
-import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import org.godotengine.godot.input.GodotGestureHandler;
-import org.godotengine.godot.input.GodotInputHandler;
-import org.godotengine.godot.utils.GLUtils;
-import org.godotengine.godot.xr.XRMode;
-import org.godotengine.godot.xr.ovr.OvrConfigChooser;
-import org.godotengine.godot.xr.ovr.OvrContextFactory;
-import org.godotengine.godot.xr.ovr.OvrWindowSurfaceFactory;
-import org.godotengine.godot.xr.regular.RegularConfigChooser;
-import org.godotengine.godot.xr.regular.RegularContextFactory;
-import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser;
-
-/**
- * A simple GLSurfaceView sub-class that demonstrate how to perform
- * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
- * details:
- *
- * - The class must use a custom context factory to enable 2.0 rendering.
- * See ContextFactory class definition below.
- *
- * - The class must use a custom EGLConfigChooser to be able to select
- * an EGLConfig that supports 2.0. This is done by providing a config
- * specification to eglChooseConfig() that has the attribute
- * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
- * set. See ConfigChooser class definition below.
- *
- * - The class must select the surface's format, then choose an EGLConfig
- * that matches it exactly (with regards to red/green/blue/alpha channels
- * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
- */
-public class GodotView extends GLSurfaceView {
-
- private static String TAG = GodotView.class.getSimpleName();
-
- private final Godot activity;
- private final GodotInputHandler inputHandler;
- private final GestureDetector detector;
- private final GodotRenderer godotRenderer;
-
- public GodotView(Godot activity, XRMode xrMode, boolean p_use_32_bits, boolean p_use_debug_opengl) {
- super(activity);
- GLUtils.use_32 = p_use_32_bits;
- GLUtils.use_debug_opengl = p_use_debug_opengl;
-
- this.activity = activity;
- this.inputHandler = new GodotInputHandler(this);
- this.detector = new GestureDetector(activity, new GodotGestureHandler(this));
- this.godotRenderer = new GodotRenderer();
- init(xrMode, false, 16, 0);
- }
-
- public void initInputDevices() {
- this.inputHandler.initInputDevices();
- }
-
- @SuppressLint("ClickableViewAccessibility")
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
- this.detector.onTouchEvent(event);
- return activity.gotTouchEvent(event);
- }
-
- @Override
- public boolean onKeyUp(final int keyCode, KeyEvent event) {
- return inputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
- }
-
- @Override
- public boolean onKeyDown(final int keyCode, KeyEvent event) {
- return inputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onGenericMotionEvent(MotionEvent event) {
- return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
- }
-
- private void init(XRMode xrMode, boolean translucent, int depth, int stencil) {
-
- setPreserveEGLContextOnPause(true);
- setFocusableInTouchMode(true);
- switch (xrMode) {
-
- case OVR:
- // Replace the default egl config chooser.
- setEGLConfigChooser(new OvrConfigChooser());
-
- // Replace the default context factory.
- setEGLContextFactory(new OvrContextFactory());
-
- // Replace the default window surface factory.
- setEGLWindowSurfaceFactory(new OvrWindowSurfaceFactory());
- break;
-
- case REGULAR:
- default:
- /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
- * If we want a translucent one, we should change the surface's
- * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
- * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
- */
- if (translucent) {
- this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
- }
-
- /* Setup the context factory for 2.0 rendering.
- * See ContextFactory class definition below
- */
- setEGLContextFactory(new RegularContextFactory());
-
- /* We need to choose an EGLConfig that matches the format of
- * our surface exactly. This is going to be done in our
- * custom config chooser. See ConfigChooser class definition
- * below.
- */
-
- if (GLUtils.use_32) {
- setEGLConfigChooser(translucent ?
- new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
- new RegularConfigChooser(8, 8, 8, 8, 16, stencil)) :
- new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil,
- new RegularConfigChooser(5, 6, 5, 0, 16, stencil)));
-
- } else {
- setEGLConfigChooser(translucent ?
- new RegularConfigChooser(8, 8, 8, 8, 16, stencil) :
- new RegularConfigChooser(5, 6, 5, 0, 16, stencil));
- }
- break;
- }
-
- /* Set the renderer responsible for frame rendering */
- setRenderer(godotRenderer);
- }
-
- public void onBackPressed() {
- activity.onBackPressed();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- queueEvent(new Runnable() {
- @Override
- public void run() {
- // Resume the renderer
- godotRenderer.onActivityResumed();
- GodotLib.focusin();
- }
- });
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- queueEvent(new Runnable() {
- @Override
- public void run() {
- GodotLib.focusout();
- // Pause the renderer
- godotRenderer.onActivityPaused();
- }
- });
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
new file mode 100644
index 0000000000..30197d5729
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
@@ -0,0 +1,142 @@
+/*************************************************************************/
+/* GodotVulkanRenderView.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 android.annotation.SuppressLint;
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SurfaceView;
+import org.godotengine.godot.input.GodotGestureHandler;
+import org.godotengine.godot.input.GodotInputHandler;
+import org.godotengine.godot.vulkan.VkRenderer;
+import org.godotengine.godot.vulkan.VkSurfaceView;
+
+public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
+
+ private final Godot mActivity;
+ private final GodotInputHandler mInputHandler;
+ private final GestureDetector mGestureDetector;
+ private final VkRenderer mRenderer;
+
+ public GodotVulkanRenderView(Godot activity) {
+ super(activity);
+
+ mActivity = activity;
+ mInputHandler = new GodotInputHandler(this);
+ mGestureDetector = new GestureDetector(mActivity, new GodotGestureHandler(this));
+ mRenderer = new VkRenderer();
+
+ setFocusableInTouchMode(true);
+ startRenderer(mRenderer);
+ }
+
+ @Override
+ public SurfaceView getView() {
+ return this;
+ }
+
+ @Override
+ public void initInputDevices() {
+ mInputHandler.initInputDevices();
+ }
+
+ @Override
+ public void queueOnRenderThread(Runnable event) {
+ queueOnVkThread(event);
+ }
+
+ @Override
+ public void onActivityPaused() {
+ onPause();
+ }
+
+ @Override
+ public void onActivityResumed() {
+ onResume();
+ }
+
+ @Override
+ public void onBackPressed() {
+ mActivity.onBackPressed();
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ mGestureDetector.onTouchEvent(event);
+ return mActivity.gotTouchEvent(event);
+ }
+
+ @Override
+ public boolean onKeyUp(final int keyCode, KeyEvent event) {
+ return mInputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyDown(final int keyCode, KeyEvent event) {
+ return mInputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return mInputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ queueOnVkThread(new Runnable() {
+ @Override
+ public void run() {
+ // Resume the renderer
+ mRenderer.onVkResume();
+ GodotLib.focusin();
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ queueOnVkThread(new Runnable() {
+ @Override
+ public void run() {
+ GodotLib.focusout();
+ // Pause the renderer
+ mRenderer.onVkPause();
+ }
+ });
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index e901b4b36d..92bb118e44 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -51,7 +51,7 @@ public class GodotEditText extends EditText {
// ===========================================================
// Fields
// ===========================================================
- private GodotView mView;
+ private GodotRenderView mRenderView;
private GodotTextInputWrapper mInputWrapper;
private EditHandler sHandler = new EditHandler(this);
private String mOriginText;
@@ -76,22 +76,22 @@ public class GodotEditText extends EditText {
// ===========================================================
public GodotEditText(final Context context) {
super(context);
- this.initView();
+ initView();
}
public GodotEditText(final Context context, final AttributeSet attrs) {
super(context, attrs);
- this.initView();
+ initView();
}
public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
- this.initView();
+ initView();
}
protected void initView() {
- this.setPadding(0, 0, 0, 0);
- this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
+ setPadding(0, 0, 0, 0);
+ setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
}
private void handleMessage(final Message msg) {
@@ -106,7 +106,7 @@ public class GodotEditText extends EditText {
edit.mInputWrapper.setOriginText(text);
edit.addTextChangedListener(edit.mInputWrapper);
setMaxInputLength(edit, msg.arg1);
- final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(edit, 0);
}
} break;
@@ -115,9 +115,9 @@ public class GodotEditText extends EditText {
GodotEditText edit = (GodotEditText)msg.obj;
edit.removeTextChangedListener(mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edit.getWindowToken(), 0);
- edit.mView.requestFocus();
+ edit.mRenderView.getView().requestFocus();
} break;
}
}
@@ -135,12 +135,12 @@ public class GodotEditText extends EditText {
// ===========================================================
// Getter & Setter
// ===========================================================
- public void setView(final GodotView view) {
- this.mView = view;
+ public void setView(final GodotRenderView view) {
+ mRenderView = view;
if (mInputWrapper == null)
- mInputWrapper = new GodotTextInputWrapper(mView, this);
- this.setOnEditorActionListener(mInputWrapper);
- view.requestFocus();
+ mInputWrapper = new GodotTextInputWrapper(mRenderView, this);
+ setOnEditorActionListener(mInputWrapper);
+ view.getView().requestFocus();
}
// ===========================================================
@@ -152,7 +152,7 @@ public class GodotEditText extends EditText {
/* Let GlSurfaceView get focus if back key is input. */
if (keyCode == KeyEvent.KEYCODE_BACK) {
- this.mView.requestFocus();
+ mRenderView.getView().requestFocus();
}
return true;
@@ -162,7 +162,7 @@ public class GodotEditText extends EditText {
// Methods
// ===========================================================
public void showKeyboard(String p_existing_text, int p_max_input_length) {
- this.mOriginText = p_existing_text;
+ mOriginText = p_existing_text;
final Message msg = new Message();
msg.what = HANDLER_OPEN_IME_KEYBOARD;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java
index 1a38a9c3d2..b1e0f66373 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java
@@ -34,22 +34,22 @@ import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.GodotView;
+import org.godotengine.godot.GodotRenderView;
/**
- * Handles gesture input related events for the {@link GodotView} view.
+ * Handles gesture input related events for the {@link GodotRenderView} view.
* https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener
*/
public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener {
- private final GodotView godotView;
+ private final GodotRenderView mRenderView;
- public GodotGestureHandler(GodotView godotView) {
- this.godotView = godotView;
+ public GodotGestureHandler(GodotRenderView godotView) {
+ mRenderView = godotView;
}
private void queueEvent(Runnable task) {
- godotView.queueEvent(task);
+ mRenderView.queueOnRenderThread(task);
}
@Override
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index e00ca86c41..0e4fc65119 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
@@ -42,27 +42,27 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.GodotView;
+import org.godotengine.godot.GodotRenderView;
import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
/**
- * Handles input related events for the {@link GodotView} view.
+ * Handles input related events for the {@link GodotRenderView} view.
*/
public class GodotInputHandler implements InputDeviceListener {
- private final ArrayList<Joystick> joysticksDevices = new ArrayList<Joystick>();
+ private final ArrayList<Joystick> mJoysticksDevices = new ArrayList<Joystick>();
- private final GodotView godotView;
- private final InputManagerCompat inputManager;
+ private final GodotRenderView mRenderView;
+ private final InputManagerCompat mInputManager;
- public GodotInputHandler(GodotView godotView) {
- this.godotView = godotView;
- this.inputManager = InputManagerCompat.Factory.getInputManager(godotView.getContext());
- this.inputManager.registerInputDeviceListener(this, null);
+ public GodotInputHandler(GodotRenderView godotView) {
+ mRenderView = godotView;
+ mInputManager = InputManagerCompat.Factory.getInputManager(mRenderView.getView().getContext());
+ mInputManager.registerInputDeviceListener(this, null);
}
private void queueEvent(Runnable task) {
- godotView.queueEvent(task);
+ mRenderView.queueOnRenderThread(task);
}
private boolean isKeyEvent_GameDevice(int source) {
@@ -113,7 +113,7 @@ public class GodotInputHandler implements InputDeviceListener {
public boolean onKeyDown(final int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
- godotView.onBackPressed();
+ mRenderView.onBackPressed();
// press 'back' button should not terminate program
//normal handle 'back' event in game logic
return true;
@@ -164,7 +164,7 @@ public class GodotInputHandler implements InputDeviceListener {
// Check if the device exists
if (device_id > -1) {
- Joystick joy = joysticksDevices.get(device_id);
+ Joystick joy = mJoysticksDevices.get(device_id);
for (int i = 0; i < joy.axes.size(); i++) {
InputDevice.MotionRange range = joy.axes.get(i);
@@ -208,11 +208,11 @@ public class GodotInputHandler implements InputDeviceListener {
public void initInputDevices() {
/* initially add input devices*/
- int[] deviceIds = inputManager.getInputDeviceIds();
+ int[] deviceIds = mInputManager.getInputDeviceIds();
for (int deviceId : deviceIds) {
- InputDevice device = inputManager.getInputDevice(deviceId);
+ InputDevice device = mInputManager.getInputDevice(deviceId);
if (DEBUG) {
- Log.v("GodotView", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
+ Log.v("GodotInputHandler", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
}
onInputDeviceAdded(deviceId);
}
@@ -224,13 +224,13 @@ public class GodotInputHandler implements InputDeviceListener {
// Check if the device has not been already added
if (id < 0) {
- InputDevice device = inputManager.getInputDevice(deviceId);
+ 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 = joysticksDevices.size();
+ id = mJoysticksDevices.size();
Joystick joy = new Joystick();
joy.device_id = deviceId;
@@ -249,7 +249,7 @@ public class GodotInputHandler implements InputDeviceListener {
}
}
- joysticksDevices.add(joy);
+ mJoysticksDevices.add(joy);
final int device_id = id;
final String name = joy.name;
@@ -270,7 +270,7 @@ public class GodotInputHandler implements InputDeviceListener {
// Check if the evice has not been already removed
if (device_id > -1) {
- joysticksDevices.remove(device_id);
+ mJoysticksDevices.remove(device_id);
queueEvent(new Runnable() {
@Override
@@ -360,8 +360,8 @@ public class GodotInputHandler implements InputDeviceListener {
}
private int findJoystickDevice(int device_id) {
- for (int i = 0; i < joysticksDevices.size(); i++) {
- if (joysticksDevices.get(i).device_id == device_id) {
+ for (int i = 0; i < mJoysticksDevices.size(); i++) {
+ if (mJoysticksDevices.get(i).device_id == device_id) {
return i;
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index 8d9b5461a1..e12ff266bf 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -48,7 +48,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
// ===========================================================
// Fields
// ===========================================================
- private final GodotView mView;
+ private final GodotRenderView mRenderView;
private final GodotEditText mEdit;
private String mOriginText;
@@ -56,9 +56,9 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
// Constructors
// ===========================================================
- public GodotTextInputWrapper(final GodotView view, final GodotEditText edit) {
- this.mView = view;
- this.mEdit = edit;
+ public GodotTextInputWrapper(final GodotRenderView view, final GodotEditText edit) {
+ mRenderView = view;
+ mEdit = edit;
}
// ===========================================================
@@ -66,13 +66,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
// ===========================================================
private boolean isFullScreenEdit() {
- final TextView textField = this.mEdit;
+ final TextView textField = mEdit;
final InputMethodManager imm = (InputMethodManager)textField.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.isFullscreenMode();
}
public void setOriginText(final String originText) {
- this.mOriginText = originText;
+ mOriginText = originText;
}
// ===========================================================
@@ -87,7 +87,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
//Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after);
- mView.queueEvent(new Runnable() {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < count; ++i) {
@@ -106,12 +106,17 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
for (int i = start; i < start + count; ++i) {
newChars[i - start] = pCharSequence.charAt(i);
}
- mView.queueEvent(new Runnable() {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < count; ++i) {
- GodotLib.key(0, 0, newChars[i], true);
- GodotLib.key(0, 0, newChars[i], false);
+ int key = newChars[i];
+ if (key == '\n') {
+ // Return keys are handled through action events
+ continue;
+ }
+ GodotLib.key(0, 0, key, true);
+ GodotLib.key(0, 0, key, false);
}
}
});
@@ -119,10 +124,10 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) {
- if (this.mEdit == pTextView && this.isFullScreenEdit()) {
+ if (mEdit == pTextView && isFullScreenEdit()) {
final String characters = pKeyEvent.getCharacters();
- mView.queueEvent(new Runnable() {
+ mRenderView.queueOnRenderThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < characters.length(); i++) {
@@ -134,8 +139,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
});
}
- if (pActionID == EditorInfo.IME_ACTION_DONE) {
- this.mView.requestFocus();
+ if (pActionID == EditorInfo.IME_NULL) {
+ // Enter key has been pressed
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false);
+
+ mRenderView.getView().requestFocus();
+ return true;
}
return false;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java
deleted file mode 100644
index 95cc48f536..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*************************************************************************/
-/* ConsumeTask.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import com.android.vending.billing.IInAppBillingService;
-import java.lang.ref.WeakReference;
-
-abstract public class ConsumeTask {
-
- private Context context;
- private IInAppBillingService mService;
-
- private String mSku;
- private String mToken;
-
- private static class ConsumeAsyncTask extends AsyncTask<String, String, String> {
-
- private WeakReference<ConsumeTask> mTask;
-
- ConsumeAsyncTask(ConsumeTask consume) {
- mTask = new WeakReference<>(consume);
- }
-
- @Override
- protected String doInBackground(String... strings) {
- ConsumeTask consume = mTask.get();
- if (consume != null) {
- return consume.doInBackground(strings);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(String param) {
- ConsumeTask consume = mTask.get();
- if (consume != null) {
- consume.onPostExecute(param);
- }
- }
- }
-
- public ConsumeTask(IInAppBillingService mService, Context context) {
- this.context = context;
- this.mService = mService;
- }
-
- public void consume(final String sku) {
- mSku = sku;
- PaymentsCache pc = new PaymentsCache(context);
- Boolean isBlocked = pc.getConsumableFlag("block", sku);
- mToken = pc.getConsumableValue("token", sku);
- if (!isBlocked && mToken == null) {
- // Consuming task is processing
- } else if (!isBlocked) {
- return;
- } else if (mToken == null) {
- this.error("No token for sku:" + sku);
- return;
- }
- new ConsumeAsyncTask(this).execute();
- }
-
- private String doInBackground(String... params) {
- try {
- int response = mService.consumePurchase(3, context.getPackageName(), mToken);
- if (response == 0 || response == 8) {
- return null;
- }
- } catch (RemoteException e) {
- return e.getMessage();
- }
- return "Some error";
- }
-
- private void onPostExecute(String param) {
- if (param == null) {
- success(new PaymentsCache(context).getConsumableValue("ticket", mSku));
- } else {
- error(param);
- }
- }
-
- abstract protected void success(String ticket);
- abstract protected void error(String message);
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/GodotPaymentInterface.java b/platform/android/java/lib/src/org/godotengine/godot/payments/GodotPaymentInterface.java
deleted file mode 100644
index 6ac7338b30..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/GodotPaymentInterface.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*************************************************************************/
-/* GodotPaymentInterface.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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.payments;
-
-public interface GodotPaymentInterface {
- void purchase(String sku, String transactionId);
-
- void consumeUnconsumedPurchases();
-
- String getSignature();
-
- void callbackSuccess(String ticket, String signature, String sku);
-
- void callbackSuccessProductMassConsumed(String ticket, String signature, String sku);
-
- void callbackSuccessNoUnconsumedPurchases();
-
- void callbackFailConsume(String message);
-
- void callbackFail(String message);
-
- void callbackCancel();
-
- void callbackAlreadyOwned(String sku);
-
- int getPurchaseCallbackId();
-
- void setPurchaseCallbackId(int purchaseCallbackId);
-
- String getPurchaseValidationUrlPrefix();
-
- void setPurchaseValidationUrlPrefix(String url);
-
- String getAccessToken();
-
- void setAccessToken(String accessToken);
-
- void setTransactionId(String transactionId);
-
- String getTransactionId();
-
- // request purchased items are not consumed
- void requestPurchased();
-
- // callback for requestPurchased()
- void callbackPurchased(String receipt, String signature, String sku);
-
- void callbackDisconnected();
-
- void callbackConnected();
-
- // true if connected, false otherwise
- boolean isConnected();
-
- // consume item automatically after purchase. default is true.
- void setAutoConsume(boolean autoConsume);
-
- // consume a specific item
- void consume(String sku);
-
- // query in app item detail info
- void querySkuDetails(String[] list);
-
- void addSkuDetail(String itemJson);
-
- void completeSkuDetail();
-
- void errorSkuDetail(String errorMessage);
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java
deleted file mode 100644
index 23d693cc8c..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*************************************************************************/
-/* HandlePurchaseTask.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.app.Activity;
-import android.content.Intent;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-abstract public class HandlePurchaseTask {
-
- private Activity context;
-
- public HandlePurchaseTask(Activity context) {
- this.context = context;
- }
-
- public void handlePurchaseRequest(int resultCode, Intent data) {
- //Log.d("XXX", "Handling purchase response");
- if (resultCode == Activity.RESULT_OK) {
- try {
- //int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
- PaymentsCache pc = new PaymentsCache(context);
-
- String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
- //Log.d("XXX", "Purchase data:" + purchaseData);
- String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
- //Log.d("XXX", "Purchase signature:" + dataSignature);
- //Log.d("SARLANGA", purchaseData);
-
- JSONObject jo = new JSONObject(purchaseData);
- //String sku = jo.getString("productId");
- //alert("You have bought the " + sku + ". Excellent choice, aventurer!");
- //String orderId = jo.getString("orderId");
- //String packageName = jo.getString("packageName");
- String productId = jo.getString("productId");
- //Long purchaseTime = jo.getLong("purchaseTime");
- //Integer state = jo.getInt("purchaseState");
- String developerPayload = jo.getString("developerPayload");
- String purchaseToken = jo.getString("purchaseToken");
-
- if (!pc.getConsumableValue("validation_hash", productId).equals(developerPayload)) {
- error("Untrusted callback");
- return;
- }
- //Log.d("XXX", "Este es el product ID:" + productId);
- pc.setConsumableValue("ticket_signautre", productId, dataSignature);
- pc.setConsumableValue("ticket", productId, purchaseData);
- pc.setConsumableFlag("block", productId, true);
- pc.setConsumableValue("token", productId, purchaseToken);
-
- success(productId, dataSignature, purchaseData);
- return;
- } catch (JSONException e) {
- error(e.getMessage());
- }
- } else if (resultCode == Activity.RESULT_CANCELED) {
- canceled();
- }
- }
-
- abstract protected void success(String sku, String signature, String ticket);
- abstract protected void error(String message);
- abstract protected void canceled();
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java b/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java
deleted file mode 100644
index 84a7eda6e0..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*************************************************************************/
-/* PaymentsCache.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-public class PaymentsCache {
-
- public Context context;
-
- public PaymentsCache(Context context) {
- this.context = context;
- }
-
- public void setConsumableFlag(String set, String sku, Boolean flag) {
- SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putBoolean(sku, flag);
- editor.apply();
- }
-
- public boolean getConsumableFlag(String set, String sku) {
- SharedPreferences sharedPref = context.getSharedPreferences(
- "consumables_" + set, Context.MODE_PRIVATE);
- return sharedPref.getBoolean(sku, false);
- }
-
- public void setConsumableValue(String set, String sku, String value) {
- SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putString(sku, value);
- //Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
- editor.apply();
- }
-
- public String getConsumableValue(String set, String sku) {
- SharedPreferences sharedPref = context.getSharedPreferences(
- "consumables_" + set, Context.MODE_PRIVATE);
- //Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
- return sharedPref.getString(sku, null);
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java
deleted file mode 100644
index 9bf6650f84..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java
+++ /dev/null
@@ -1,418 +0,0 @@
-/*************************************************************************/
-/* PaymentsManager.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.vending.billing.IInAppBillingService;
-import java.util.ArrayList;
-import java.util.Arrays;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-public class PaymentsManager {
-
- public static final int BILLING_RESPONSE_RESULT_OK = 0;
- public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001;
- private static boolean auto_consume = true;
-
- private Activity activity;
- IInAppBillingService mService;
-
- public void setActivity(Activity activity) {
- this.activity = activity;
- }
-
- public static PaymentsManager createManager(Activity activity) {
- PaymentsManager manager = new PaymentsManager(activity);
- return manager;
- }
-
- private PaymentsManager(Activity activity) {
- this.activity = activity;
- }
-
- public PaymentsManager initService() {
- Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
- intent.setPackage("com.android.vending");
- activity.bindService(
- intent,
- mServiceConn,
- Context.BIND_AUTO_CREATE);
- return this;
- }
-
- public void destroy() {
- if (mService != null) {
- activity.unbindService(mServiceConn);
- }
- }
-
- ServiceConnection mServiceConn = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
-
- // At this stage, godotPayment might not have been initialized yet.
- if (godotPayment != null) {
- godotPayment.callbackDisconnected();
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = IInAppBillingService.Stub.asInterface(service);
-
- // At this stage, godotPayment might not have been initialized yet.
- if (godotPayment != null) {
- godotPayment.callbackConnected();
- }
- }
- };
-
- public void requestPurchase(final String sku, String transactionId) {
- new PurchaseTask(mService, activity) {
- @Override
- protected void error(String message) {
- godotPayment.callbackFail(message);
- }
-
- @Override
- protected void canceled() {
- godotPayment.callbackCancel();
- }
-
- @Override
- protected void alreadyOwned() {
- godotPayment.callbackAlreadyOwned(sku);
- }
- }
- .purchase(sku, transactionId);
- }
-
- public boolean isConnected() {
- return mService != null;
- }
-
- public void consumeUnconsumedPurchases() {
- new ReleaseAllConsumablesTask(mService, activity) {
- @Override
- protected void success(String sku, String receipt, String signature, String token) {
- godotPayment.callbackSuccessProductMassConsumed(receipt, signature, sku);
- }
-
- @Override
- protected void error(String message) {
- Log.d("godot", "consumeUnconsumedPurchases :" + message);
- godotPayment.callbackFailConsume(message);
- }
-
- @Override
- protected void notRequired() {
- Log.d("godot", "callbackSuccessNoUnconsumedPurchases :");
- godotPayment.callbackSuccessNoUnconsumedPurchases();
- }
- }
- .consumeItAll();
- }
-
- public void requestPurchased() {
- try {
- PaymentsCache pc = new PaymentsCache(activity);
-
- String continueToken = null;
-
- do {
- Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp", continueToken);
-
- if (bundle.getInt("RESPONSE_CODE") == 0) {
-
- final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
- final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
-
- if (myPurchases == null || myPurchases.size() == 0) {
- godotPayment.callbackPurchased("", "", "");
- return;
- }
-
- for (int i = 0; i < myPurchases.size(); i++) {
-
- try {
- String receipt = myPurchases.get(i);
- JSONObject inappPurchaseData = new JSONObject(receipt);
- String sku = inappPurchaseData.getString("productId");
- String token = inappPurchaseData.getString("purchaseToken");
- String signature = mySignatures.get(i);
-
- pc.setConsumableValue("ticket_signautre", sku, signature);
- pc.setConsumableValue("ticket", sku, receipt);
- pc.setConsumableFlag("block", sku, true);
- pc.setConsumableValue("token", sku, token);
-
- godotPayment.callbackPurchased(receipt, signature, sku);
- } catch (JSONException e) {
- }
- }
- }
- continueToken = bundle.getString("INAPP_CONTINUATION_TOKEN");
- Log.d("godot", "continue token = " + continueToken);
- } while (!TextUtils.isEmpty(continueToken));
- } catch (Exception e) {
- Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage());
- }
- }
-
- public void processPurchaseResponse(int resultCode, Intent data) {
- new HandlePurchaseTask(activity) {
- @Override
- protected void success(final String sku, final String signature, final String ticket) {
- godotPayment.callbackSuccess(ticket, signature, sku);
-
- if (auto_consume) {
- new ConsumeTask(mService, activity) {
- @Override
- protected void success(String ticket) {
- }
-
- @Override
- protected void error(String message) {
- godotPayment.callbackFail(message);
- }
- }
- .consume(sku);
- }
- }
-
- @Override
- protected void error(String message) {
- godotPayment.callbackFail(message);
- }
-
- @Override
- protected void canceled() {
- godotPayment.callbackCancel();
- }
- }
- .handlePurchaseRequest(resultCode, data);
- }
-
- public void validatePurchase(String purchaseToken, final String sku) {
-
- new ValidateTask(activity, godotPayment) {
- @Override
- protected void success() {
-
- new ConsumeTask(mService, activity) {
- @Override
- protected void success(String ticket) {
- godotPayment.callbackSuccess(ticket, null, sku);
- }
-
- @Override
- protected void error(String message) {
- godotPayment.callbackFail(message);
- }
- }
- .consume(sku);
- }
-
- @Override
- protected void error(String message) {
- godotPayment.callbackFail(message);
- }
-
- @Override
- protected void canceled() {
- godotPayment.callbackCancel();
- }
- }
- .validatePurchase(sku);
- }
-
- public void setAutoConsume(boolean autoConsume) {
- auto_consume = autoConsume;
- }
-
- public void consume(final String sku) {
- new ConsumeTask(mService, activity) {
- @Override
- protected void success(String ticket) {
- godotPayment.callbackSuccessProductMassConsumed(ticket, "", sku);
- }
-
- @Override
- protected void error(String message) {
- godotPayment.callbackFailConsume(message);
- }
- }
- .consume(sku);
- }
-
- // Workaround to bug where sometimes response codes come as Long instead of Integer
- int getResponseCodeFromBundle(Bundle b) {
- Object o = b.get("RESPONSE_CODE");
- if (o == null) {
- //logDebug("Bundle with null response code, assuming OK (known issue)");
- return BILLING_RESPONSE_RESULT_OK;
- } else if (o instanceof Integer)
- return ((Integer)o).intValue();
- else if (o instanceof Long)
- return (int)((Long)o).longValue();
- else {
- //logError("Unexpected type for bundle response code.");
- //logError(o.getClass().getName());
- throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName());
- }
- }
-
- /**
- * Returns a human-readable description for the given response code.
- *
- * @param code The response code
- * @return A human-readable string explaining the result code.
- * It also includes the result code numerically.
- */
- public static String getResponseDesc(int code) {
- String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/"
- +
- "3:Billing Unavailable/4:Item unavailable/"
- +
- "5:Developer Error/6:Error/7:Item Already Owned/"
- +
- "8:Item not owned")
- .split("/");
- String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/"
- +
- "-1002:Bad response received/"
- +
- "-1003:Purchase signature verification failed/"
- +
- "-1004:Send intent failed/"
- +
- "-1005:User cancelled/"
- +
- "-1006:Unknown purchase response/"
- +
- "-1007:Missing token/"
- +
- "-1008:Unknown error/"
- +
- "-1009:Subscriptions not available/"
- +
- "-1010:Invalid consumption attempt")
- .split("/");
-
- if (code <= -1000) {
- int index = -1000 - code;
- if (index >= 0 && index < iabhelper_msgs.length)
- return iabhelper_msgs[index];
- else
- return String.valueOf(code) + ":Unknown IAB Helper Error";
- } else if (code < 0 || code >= iab_msgs.length)
- return String.valueOf(code) + ":Unknown";
- else
- return iab_msgs[code];
- }
-
- public void querySkuDetails(final String[] list) {
- (new Thread(new Runnable() {
- @Override
- public void run() {
- ArrayList<String> skuList = new ArrayList<String>(Arrays.asList(list));
- if (skuList.size() == 0) {
- return;
- }
- // Split the sku list in blocks of no more than 20 elements.
- ArrayList<ArrayList<String>> packs = new ArrayList<ArrayList<String>>();
- ArrayList<String> tempList;
- int n = skuList.size() / 20;
- int mod = skuList.size() % 20;
- for (int i = 0; i < n; i++) {
- tempList = new ArrayList<String>();
- for (String s : skuList.subList(i * 20, i * 20 + 20)) {
- tempList.add(s);
- }
- packs.add(tempList);
- }
- if (mod != 0) {
- tempList = new ArrayList<String>();
- for (String s : skuList.subList(n * 20, n * 20 + mod)) {
- tempList.add(s);
- }
- packs.add(tempList);
- }
- for (ArrayList<String> skuPartList : packs) {
- Bundle querySkus = new Bundle();
- querySkus.putStringArrayList("ITEM_ID_LIST", skuPartList);
- Bundle skuDetails = null;
- try {
- skuDetails = mService.getSkuDetails(3, activity.getPackageName(), "inapp", querySkus);
- if (!skuDetails.containsKey("DETAILS_LIST")) {
- int response = getResponseCodeFromBundle(skuDetails);
- if (response != BILLING_RESPONSE_RESULT_OK) {
- godotPayment.errorSkuDetail(getResponseDesc(response));
- } else {
- godotPayment.errorSkuDetail("No error but no detail list.");
- }
- return;
- }
-
- ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
-
- for (String thisResponse : responseList) {
- Log.d("godot", "response = " + thisResponse);
- godotPayment.addSkuDetail(thisResponse);
- }
- } catch (RemoteException e) {
- e.printStackTrace();
- godotPayment.errorSkuDetail("RemoteException error!");
- }
- }
- godotPayment.completeSkuDetail();
- }
- }))
- .start();
- }
-
- private GodotPaymentInterface godotPayment;
-
- public void setBaseSingleton(GodotPaymentInterface godotPaymentInterface) {
- this.godotPayment = godotPaymentInterface;
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java
deleted file mode 100644
index 09c9349124..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*************************************************************************/
-/* PurchaseTask.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.content.IntentSender.SendIntentException;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-import com.android.vending.billing.IInAppBillingService;
-
-abstract public class PurchaseTask {
-
- private Activity context;
-
- private IInAppBillingService mService;
- public PurchaseTask(IInAppBillingService mService, Activity context) {
- this.context = context;
- this.mService = mService;
- }
-
- private boolean isLooping = false;
-
- public void purchase(final String sku, final String transactionId) {
- Log.d("XXX", "Starting purchase for: " + sku);
- PaymentsCache pc = new PaymentsCache(context);
- Boolean isBlocked = pc.getConsumableFlag("block", sku);
- /*
- if(isBlocked){
- Log.d("XXX", "Is awaiting payment confirmation");
- error("Awaiting payment confirmation");
- return;
- }
- */
- final String hash = transactionId;
-
- Bundle buyIntentBundle;
- try {
- buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash);
- } catch (RemoteException e) {
- //Log.d("XXX", "Error: " + e.getMessage());
- error(e.getMessage());
- return;
- }
- Object rc = buyIntentBundle.get("RESPONSE_CODE");
- int responseCode = 0;
- if (rc == null) {
- responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK;
- } else if (rc instanceof Integer) {
- responseCode = ((Integer)rc).intValue();
- } else if (rc instanceof Long) {
- responseCode = (int)((Long)rc).longValue();
- }
- //Log.d("XXX", "Buy intent response code: " + responseCode);
- if (responseCode == 1 || responseCode == 3 || responseCode == 4) {
- canceled();
- return;
- }
- if (responseCode == 7) {
- alreadyOwned();
- return;
- }
-
- PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
- pc.setConsumableValue("validation_hash", sku, hash);
- try {
- if (context == null) {
- //Log.d("XXX", "No context!");
- }
- if (pendingIntent == null) {
- //Log.d("XXX", "No pending intent");
- }
- //Log.d("XXX", "Starting activity for purchase!");
- context.startIntentSenderForResult(
- pendingIntent.getIntentSender(),
- PaymentsManager.REQUEST_CODE_FOR_PURCHASE,
- new Intent(),
- Integer.valueOf(0), Integer.valueOf(0),
- Integer.valueOf(0));
- } catch (SendIntentException e) {
- error(e.getMessage());
- }
- }
-
- abstract protected void error(String message);
- abstract protected void canceled();
- abstract protected void alreadyOwned();
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
deleted file mode 100644
index a101780511..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*************************************************************************/
-/* ReleaseAllConsumablesTask.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import com.android.vending.billing.IInAppBillingService;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-abstract public class ReleaseAllConsumablesTask {
-
- private Context context;
- private IInAppBillingService mService;
-
- private static class ReleaseAllConsumablesAsyncTask extends AsyncTask<String, String, String> {
-
- private WeakReference<ReleaseAllConsumablesTask> mTask;
- private String mSku;
- private String mReceipt;
- private String mSignature;
- private String mToken;
-
- ReleaseAllConsumablesAsyncTask(ReleaseAllConsumablesTask task, String sku, String receipt, String signature, String token) {
- mTask = new WeakReference<ReleaseAllConsumablesTask>(task);
-
- mSku = sku;
- mReceipt = receipt;
- mSignature = signature;
- mToken = token;
- }
-
- @Override
- protected String doInBackground(String... params) {
- ReleaseAllConsumablesTask consume = mTask.get();
- if (consume != null) {
- return consume.doInBackground(mToken);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(String param) {
- ReleaseAllConsumablesTask consume = mTask.get();
- if (consume != null) {
- consume.success(mSku, mReceipt, mSignature, mToken);
- }
- }
- }
-
- public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context) {
- this.context = context;
- this.mService = mService;
- }
-
- public void consumeItAll() {
- try {
- //Log.d("godot", "consumeItall for " + context.getPackageName());
- Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp", null);
-
- if (bundle.getInt("RESPONSE_CODE") == 0) {
-
- final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
- final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
-
- if (myPurchases == null || myPurchases.size() == 0) {
- //Log.d("godot", "No purchases!");
- notRequired();
- return;
- }
-
- //Log.d("godot", "# products to be consumed:" + myPurchases.size());
- for (int i = 0; i < myPurchases.size(); i++) {
-
- try {
- String receipt = myPurchases.get(i);
- JSONObject inappPurchaseData = new JSONObject(receipt);
- String sku = inappPurchaseData.getString("productId");
- String token = inappPurchaseData.getString("purchaseToken");
- String signature = mySignatures.get(i);
- //Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt);
- new ReleaseAllConsumablesAsyncTask(this, sku, receipt, signature, token).execute();
- } catch (JSONException e) {
- }
- }
- }
- } catch (Exception e) {
- Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage());
- }
- }
-
- private String doInBackground(String token) {
- try {
- //Log.d("godot", "Requesting to consume an item with token ." + token);
- int response = mService.consumePurchase(3, context.getPackageName(), token);
- //Log.d("godot", "consumePurchase response: " + response);
- if (response == 0 || response == 8) {
- return null;
- }
- } catch (Exception e) {
- Log.d("godot", "Error " + e.getClass().getName() + ":" + e.getMessage());
- }
- return null;
- }
-
- abstract protected void success(String sku, String receipt, String signature, String token);
- abstract protected void error(String message);
- abstract protected void notRequired();
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java
deleted file mode 100644
index 10c314aecf..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*************************************************************************/
-/* ValidateTask.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.payments;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.os.AsyncTask;
-import java.lang.ref.WeakReference;
-import org.godotengine.godot.utils.HttpRequester;
-import org.godotengine.godot.utils.RequestParams;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-abstract public class ValidateTask {
-
- private Activity context;
- private GodotPaymentInterface godotPayments;
- private ProgressDialog dialog;
- private String mSku;
-
- private static class ValidateAsyncTask extends AsyncTask<String, String, String> {
- private WeakReference<ValidateTask> mTask;
-
- ValidateAsyncTask(ValidateTask task) {
- mTask = new WeakReference<>(task);
- }
-
- @Override
- protected void onPreExecute() {
- ValidateTask task = mTask.get();
- if (task != null) {
- task.onPreExecute();
- }
- }
-
- @Override
- protected String doInBackground(String... params) {
- ValidateTask task = mTask.get();
- if (task != null) {
- return task.doInBackground(params);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(String response) {
- ValidateTask task = mTask.get();
- if (task != null) {
- task.onPostExecute(response);
- }
- }
- }
-
- public ValidateTask(Activity context, GodotPaymentInterface godotPayments) {
- this.context = context;
- this.godotPayments = godotPayments;
- }
-
- public void validatePurchase(final String sku) {
- mSku = sku;
- new ValidateAsyncTask(this).execute();
- }
-
- private void onPreExecute() {
- dialog = ProgressDialog.show(context, null, "Please wait...");
- }
-
- private String doInBackground(String... params) {
- PaymentsCache pc = new PaymentsCache(context);
- String url = godotPayments.getPurchaseValidationUrlPrefix();
- RequestParams param = new RequestParams();
- param.setUrl(url);
- param.put("ticket", pc.getConsumableValue("ticket", mSku));
- param.put("purchaseToken", pc.getConsumableValue("token", mSku));
- param.put("sku", mSku);
- //Log.d("XXX", "Haciendo request a " + url);
- //Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku));
- //Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku));
- //Log.d("XXX", "sku: " + sku);
- param.put("package", context.getApplicationContext().getPackageName());
- HttpRequester requester = new HttpRequester();
- String jsonResponse = requester.post(param);
- //Log.d("XXX", "Validation response:\n"+jsonResponse);
- return jsonResponse;
- }
-
- private void onPostExecute(String response) {
- if (dialog != null) {
- dialog.dismiss();
- dialog = null;
- }
- JSONObject j;
- try {
- j = new JSONObject(response);
- if (j.getString("status").equals("OK")) {
- success();
- return;
- } else if (j.getString("status") != null) {
- error(j.getString("message"));
- } else {
- error("Connection error");
- }
- } catch (JSONException e) {
- error(e.getMessage());
- } catch (Exception e) {
- error(e.getMessage());
- }
- }
-
- abstract protected void success();
- abstract protected void error(String message);
- abstract protected void canceled();
-}
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 d5bf4fc70e..a051164d15 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
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 */
@@ -34,14 +34,19 @@ import android.app.Activity;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Surface;
import android.view.View;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import org.godotengine.godot.BuildConfig;
import org.godotengine.godot.Godot;
/**
@@ -69,7 +74,10 @@ import org.godotengine.godot.Godot;
*/
public abstract class GodotPlugin {
+ private static final String TAG = GodotPlugin.class.getSimpleName();
+
private final Godot godot;
+ private final ConcurrentHashMap<String, SignalInfo> registeredSignals = new ConcurrentHashMap<>();
public GodotPlugin(Godot godot) {
this.godot = godot;
@@ -84,8 +92,10 @@ public abstract class GodotPlugin {
/**
* Register the plugin with Godot native code.
+ *
+ * This method is invoked on the render thread.
*/
- public final void onGLRegisterPluginWithGodotNative() {
+ public final void onRegisterPluginWithGodotNative() {
nativeRegisterSingleton(getPluginName());
Class clazz = getClass();
@@ -115,6 +125,13 @@ public abstract class GodotPlugin {
nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt);
}
+ // Register the signals for this plugin.
+ for (SignalInfo signalInfo : getPluginSignals()) {
+ String signalName = signalInfo.getName();
+ nativeRegisterSignal(getPluginName(), signalName, signalInfo.getParamTypesNames());
+ registeredSignals.put(signalName, signalInfo);
+ }
+
// Get the list of gdnative libraries to register.
Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths();
if (!gdnativeLibrariesPaths.isEmpty()) {
@@ -169,9 +186,9 @@ public abstract class GodotPlugin {
public boolean onMainBackPressed() { return false; }
/**
- * Invoked on the GL thread when the Godot main loop has started.
+ * Invoked on the render thread when the Godot main loop has started.
*/
- public void onGLGodotMainLoopStarted() {}
+ public void onGodotMainLoopStarted() {}
/**
* Invoked once per frame on the GL thread after the frame is drawn.
@@ -190,6 +207,22 @@ public abstract class GodotPlugin {
public void onGLSurfaceCreated(GL10 gl, EGLConfig config) {}
/**
+ * Invoked once per frame on the Vulkan thread after the frame is drawn.
+ */
+ public void onVkDrawFrame() {}
+
+ /**
+ * Called on the Vulkan thread after the surface is created and whenever the surface size
+ * changes.
+ */
+ public void onVkSurfaceChanged(Surface surface, int width, int height) {}
+
+ /**
+ * Called on the Vulkan thread when the surface is created or recreated.
+ */
+ public void onVkSurfaceCreated(Surface surface) {}
+
+ /**
* Returns the name of the plugin.
* <p>
* This value must match the one listed in the plugin '<meta-data>' manifest entry.
@@ -201,7 +234,17 @@ public abstract class GodotPlugin {
* Returns the list of methods to be exposed to Godot.
*/
@NonNull
- public abstract List<String> getPluginMethods();
+ public List<String> getPluginMethods() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns the list of signals to be exposed to Godot.
+ */
+ @NonNull
+ public Set<SignalInfo> getPluginSignals() {
+ return Collections.emptySet();
+ }
/**
* Returns the paths for the plugin's gdnative libraries.
@@ -225,12 +268,55 @@ public abstract class GodotPlugin {
}
/**
- * Queue the specified action to be run on the GL thread.
+ * Queue the specified action to be run on the render thread.
*
- * @param action the action to run on the GL thread
+ * @param action the action to run on the render thread
*/
- protected void runOnGLThread(Runnable action) {
- godot.runOnGLThread(action);
+ protected void runOnRenderThread(Runnable action) {
+ godot.runOnRenderThread(action);
+ }
+
+ /**
+ * Emit a registered Godot signal.
+ * @param signalName
+ * @param signalArgs
+ */
+ protected void emitSignal(final String signalName, final Object... signalArgs) {
+ try {
+ // Check that the given signal is among the registered set.
+ SignalInfo signalInfo = registeredSignals.get(signalName);
+ if (signalInfo == null) {
+ throw new IllegalArgumentException(
+ "Signal " + signalName + " is not registered for this plugin.");
+ }
+
+ // Validate the arguments count.
+ Class<?>[] signalParamTypes = signalInfo.getParamTypes();
+ if (signalArgs.length != signalParamTypes.length) {
+ throw new IllegalArgumentException(
+ "Invalid arguments count. Should be " + signalParamTypes.length + " but is " + signalArgs.length);
+ }
+
+ // Validate the argument's types.
+ for (int i = 0; i < signalParamTypes.length; i++) {
+ if (!signalParamTypes[i].isInstance(signalArgs[i])) {
+ throw new IllegalArgumentException(
+ "Invalid type for argument #" + i + ". Should be of type " + signalParamTypes[i].getName());
+ }
+ }
+
+ runOnRenderThread(new Runnable() {
+ @Override
+ public void run() {
+ nativeEmitSignal(getPluginName(), signalName, signalArgs);
+ }
+ });
+ } catch (IllegalArgumentException exception) {
+ Log.w(TAG, exception.getMessage());
+ if (BuildConfig.DEBUG) {
+ throw exception;
+ }
+ }
}
/**
@@ -253,4 +339,20 @@ public abstract class GodotPlugin {
* @param gdnlibPaths Paths to the libraries relative to the 'assets' directory.
*/
private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
+
+ /**
+ * Used to complete registration of the {@link GodotPlugin} instance's methods.
+ * @param pluginName Name of the plugin
+ * @param signalName Name of the signal to register
+ * @param signalParamTypes Signal parameters types
+ */
+ private native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes);
+
+ /**
+ * Used to emit signal by {@link GodotPlugin} instance.
+ * @param pluginName Name of the plugin
+ * @param signalName Name of the signal to emit
+ * @param signalParams Signal parameters
+ */
+ private native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams);
}
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 b6d949b7bf..e13a9c15d8 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
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 */
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java
new file mode 100644
index 0000000000..f907706889
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java
@@ -0,0 +1,98 @@
+/*************************************************************************/
+/* SignalInfo.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 android.support.annotation.NonNull;
+import android.text.TextUtils;
+import java.util.Arrays;
+
+/**
+ * Store information about a {@link GodotPlugin}'s signal.
+ */
+public final class SignalInfo {
+
+ private final String name;
+ private final Class<?>[] paramTypes;
+ private final String[] paramTypesNames;
+
+ public SignalInfo(@NonNull String signalName, Class<?>... paramTypes) {
+ if (TextUtils.isEmpty(signalName)) {
+ throw new IllegalArgumentException("Invalid signal name: " + signalName);
+ }
+
+ this.name = signalName;
+ this.paramTypes = paramTypes == null ? new Class<?>[ 0 ] : paramTypes;
+ this.paramTypesNames = new String[this.paramTypes.length];
+ for (int i = 0; i < this.paramTypes.length; i++) {
+ this.paramTypesNames[i] = this.paramTypes[i].getName();
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ Class<?>[] getParamTypes() {
+ return paramTypes;
+ }
+
+ String[] getParamTypesNames() {
+ return paramTypesNames;
+ }
+
+ @Override
+ public String toString() {
+ return "SignalInfo{"
+ +
+ "name='" + name + '\'' +
+ ", paramsTypes=" + Arrays.toString(paramTypes) +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SignalInfo)) {
+ return false;
+ }
+
+ SignalInfo that = (SignalInfo)o;
+
+ return name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
deleted file mode 100644
index c78e8c1c66..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*************************************************************************/
-/* CustomSSLSocketFactory.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.utils;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManagerFactory;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-
-/**
- *
- * @author Luis Linietsky <luis.linietsky@gmail.com>
- */
-public class CustomSSLSocketFactory extends SSLSocketFactory {
- SSLContext sslContext = SSLContext.getInstance("TLS");
-
- public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- super(truststore);
-
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
- tmf.init(truststore);
-
- sslContext.init(null, tmf.getTrustManagers(), null);
- }
-
- @Override
- public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
- return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
- }
-
- @Override
- public Socket createSocket() throws IOException {
- return sslContext.getSocketFactory().createSocket();
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java b/platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java
deleted file mode 100644
index 68f9a83597..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*************************************************************************/
-/* HttpRequester.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.utils;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.security.KeyStore;
-import java.util.Date;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpVersion;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EntityUtils;
-
-/**
- *
- * @author Luis Linietsky <luis.linietsky@gmail.com>
- */
-public class HttpRequester {
-
- private Context context;
- private static final int TTL = 600000; // 10 minutos
- private long cttl = 0;
-
- public HttpRequester() {
- //Log.d("XXX", "Creando http request sin contexto");
- }
-
- public HttpRequester(Context context) {
- this.context = context;
- //Log.d("XXX", "Creando http request con contexto");
- }
-
- public String post(RequestParams params) {
- HttpPost httppost = new HttpPost(params.getUrl());
- try {
- httppost.setEntity(new UrlEncodedFormEntity(params.toPairsList()));
- return request(httppost);
- } catch (UnsupportedEncodingException e) {
- return null;
- }
- }
-
- public String get(RequestParams params) {
- String response = getResponseFromCache(params.getUrl());
- if (response == null) {
- //Log.d("XXX", "Cache miss!");
- HttpGet httpget = new HttpGet(params.getUrl());
- long timeInit = new Date().getTime();
- response = request(httpget);
- long delay = new Date().getTime() - timeInit;
- Log.d("HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay / 1000.0f) + " seconds");
- if (response == null || response.length() == 0) {
- response = "";
- } else {
- saveResponseIntoCache(params.getUrl(), response);
- }
- }
- Log.d("XXX", "Req: " + params.getUrl());
- Log.d("XXX", "Resp: " + response);
- return response;
- }
-
- private String request(HttpUriRequest request) {
- //Log.d("XXX", "Haciendo request a: " + request.getURI() );
- Log.d("PPP", "Haciendo request a: " + request.getURI());
- long init = new Date().getTime();
- HttpClient httpclient = getNewHttpClient();
- HttpParams httpParameters = httpclient.getParams();
- HttpConnectionParams.setConnectionTimeout(httpParameters, 0);
- HttpConnectionParams.setSoTimeout(httpParameters, 0);
- HttpConnectionParams.setTcpNoDelay(httpParameters, true);
- try {
- HttpResponse response = httpclient.execute(request);
- Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI());
- //Log.d("XXX1", "Status:" + response.getStatusLine().toString());
- if (response.getStatusLine().getStatusCode() == 200) {
- String strResponse = EntityUtils.toString(response.getEntity());
- //Log.d("XXX2", strResponse);
- return strResponse;
- } else {
- Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity()));
- return null;
- }
-
- } catch (ClientProtocolException e) {
- Log.d("XXX3", e.getMessage());
- } catch (IOException e) {
- Log.d("XXX4", e.getMessage());
- }
- return null;
- }
-
- private HttpClient getNewHttpClient() {
- try {
- KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
- trustStore.load(null, null);
-
- SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
- sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
-
- HttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
-
- SchemeRegistry registry = new SchemeRegistry();
- registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- registry.register(new Scheme("https", sf, 443));
-
- ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
-
- return new DefaultHttpClient(ccm, params);
- } catch (Exception e) {
- return new DefaultHttpClient();
- }
- }
-
- private static String convertStreamToString(InputStream is) {
- BufferedReader reader = new BufferedReader(new InputStreamReader(is));
- StringBuilder sb = new StringBuilder();
- String line = null;
- try {
- while ((line = reader.readLine()) != null) {
- sb.append((line + "\n"));
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return sb.toString();
- }
-
- public void saveResponseIntoCache(String request, String response) {
- if (context == null) {
- //Log.d("XXX", "No context, cache failed!");
- return;
- }
- SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putString("request_" + Crypt.md5(request), response);
- editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl());
- editor.apply();
- }
-
- public String getResponseFromCache(String request) {
- if (context == null) {
- Log.d("XXX", "No context, cache miss");
- return null;
- }
- SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE);
- long ttl = getResponseTtl(request);
- if (ttl == 0l || (new Date().getTime() - ttl) > 0l) {
- Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime());
- return null;
- }
- return sharedPref.getString("request_" + Crypt.md5(request), null);
- }
-
- public long getResponseTtl(String request) {
- SharedPreferences sharedPref = context.getSharedPreferences(
- "http_get_cache", Context.MODE_PRIVATE);
- return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l);
- }
-
- public long getTtl() {
- return cttl > 0 ? cttl : TTL;
- }
-
- public void setTtl(long ttl) {
- this.cttl = (ttl * 1000) + new Date().getTime();
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/RequestParams.java b/platform/android/java/lib/src/org/godotengine/godot/utils/RequestParams.java
deleted file mode 100644
index 25fa10647d..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/RequestParams.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*************************************************************************/
-/* RequestParams.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.utils;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import org.apache.http.NameValuePair;
-import org.apache.http.message.BasicNameValuePair;
-
-/**
- *
- * @author Luis Linietsky <luis.linietsky@gmail.com>
- */
-public class RequestParams {
-
- private HashMap<String, String> params;
- private String url;
-
- public RequestParams() {
- params = new HashMap<String, String>();
- }
-
- public void put(String key, String value) {
- params.put(key, value);
- }
-
- public String get(String key) {
- return params.get(key);
- }
-
- public void remove(Object key) {
- params.remove(key);
- }
-
- public boolean has(String key) {
- return params.containsKey(key);
- }
-
- public List<NameValuePair> toPairsList() {
- List<NameValuePair> fields = new ArrayList<NameValuePair>();
-
- for (String key : params.keySet()) {
- fields.add(new BasicNameValuePair(key, this.get(key)));
- }
- return fields;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
index 67faad8ddd..608ad48df9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
@@ -33,6 +33,11 @@ package org.godotengine.godot.vulkan
import android.view.Surface
+import org.godotengine.godot.Godot
+import org.godotengine.godot.GodotLib
+import org.godotengine.godot.plugin.GodotPlugin
+import org.godotengine.godot.plugin.GodotPluginRegistry
+
/**
* Responsible to setting up and driving the Vulkan rendering logic.
*
@@ -48,52 +53,64 @@ import android.view.Surface
*/
internal class VkRenderer {
+ private val pluginRegistry: GodotPluginRegistry = GodotPluginRegistry.getPluginRegistry()
+
/**
* Called when the surface is created and signals the beginning of rendering.
*/
fun onVkSurfaceCreated(surface: Surface) {
- nativeOnVkSurfaceCreated(surface)
+ // TODO: properly implement surface re-creation:
+ // GodotLib.newcontext should be called here once it's done.
+ //GodotLib.newcontext(surface, false)
+
+ for (plugin in pluginRegistry.getAllPlugins()) {
+ plugin.onVkSurfaceCreated(surface)
+ }
}
/**
* Called after the surface is created and whenever its size changes.
*/
fun onVkSurfaceChanged(surface: Surface, width: Int, height: Int) {
- nativeOnVkSurfaceChanged(surface, width, height)
+ GodotLib.resize(width, height)
+
+ // TODO: properly implement surface re-creation:
+ // Update the native renderer instead of restarting the app.
+ // GodotLib.newcontext should not be called here once it's done.
+ GodotLib.newcontext(surface, false)
+
+ for (plugin in pluginRegistry.getAllPlugins()) {
+ plugin.onVkSurfaceChanged(surface, width, height)
+ }
}
/**
* Called to draw the current frame.
*/
fun onVkDrawFrame() {
- nativeOnVkDrawFrame()
+ GodotLib.step()
+ for (plugin in pluginRegistry.getAllPlugins()) {
+ plugin.onVkDrawFrame()
+ }
}
/**
* Called when the rendering thread is resumed.
*/
fun onVkResume() {
- nativeOnVkResume()
+ GodotLib.onRendererResumed()
}
/**
* Called when the rendering thread is paused.
*/
fun onVkPause() {
- nativeOnVkPause()
+ GodotLib.onRendererPaused()
}
/**
* Called when the rendering thread is destroyed and used as signal to tear down the Vulkan logic.
*/
fun onVkDestroy() {
- nativeOnVkDestroy()
}
-
- private external fun nativeOnVkSurfaceCreated(surface: Surface)
- private external fun nativeOnVkSurfaceChanged(surface: Surface, width: Int, height: Int)
- private external fun nativeOnVkResume()
- private external fun nativeOnVkDrawFrame()
- private external fun nativeOnVkPause()
- private external fun nativeOnVkDestroy()
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt
index 1c594f3201..6b0e12b21a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt
@@ -49,7 +49,7 @@ import android.view.SurfaceView
* UI thread.
* </ul>
*/
-internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
+open internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
companion object {
fun checkState(expression: Boolean, errorMessage: Any) {
@@ -100,7 +100,7 @@ internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHo
*
* Must not be called before a [VkRenderer] has been set.
*/
- fun onResume() {
+ open fun onResume() {
vkThread.onResume()
}
@@ -109,7 +109,7 @@ internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHo
*
* Must not be called before a [VkRenderer] has been set.
*/
- fun onPause() {
+ open fun onPause() {
vkThread.onPause()
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt
index 2e332840bf..7557c8aa22 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt
@@ -219,9 +219,9 @@ internal class VkThread(private val vkSurfaceView: VkSurfaceView, private val vk
vkRenderer.onVkDrawFrame()
}
} catch (ex: InterruptedException) {
- Log.i(TAG, ex.message)
+ Log.i(TAG, "InterruptedException", ex)
} catch (ex: IllegalStateException) {
- Log.i(TAG, ex.message)
+ Log.i(TAG, "IllegalStateException", ex)
} finally {
threadExiting()
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
index f2b4c95a2c..31cf696195 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
@@ -51,7 +51,6 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
- String driver_name = GodotLib.getGlobal("rendering/quality/driver/driver_name");
// FIXME: Add support for Vulkan.
Log.w(TAG, "creating OpenGL ES 2.0 context :");
diff --git a/platform/android/java/plugins/godotpayment/build.gradle b/platform/android/java/plugins/godotpayment/build.gradle
index 4f376c4587..ffab86e26e 100644
--- a/platform/android/java/plugins/godotpayment/build.gradle
+++ b/platform/android/java/plugins/godotpayment/build.gradle
@@ -3,6 +3,7 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
+ useLibrary 'org.apache.http.legacy'
defaultConfig {
minSdkVersion versions.minSdk
diff --git a/platform/android/java/lib/aidl/com/android/vending/billing/IInAppBillingService.aidl b/platform/android/java/plugins/godotpayment/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
index 0f2bcae338..0f2bcae338 100644
--- a/platform/android/java/lib/aidl/com/android/vending/billing/IInAppBillingService.aidl
+++ b/platform/android/java/plugins/godotpayment/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java
new file mode 100644
index 0000000000..c15bc232ce
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java
@@ -0,0 +1,116 @@
+/*************************************************************************/
+/* ConsumeTask.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import com.android.vending.billing.IInAppBillingService;
+import java.lang.ref.WeakReference;
+
+abstract public class ConsumeTask {
+
+ private Context context;
+ private IInAppBillingService mService;
+
+ private String mSku;
+ private String mToken;
+
+ private static class ConsumeAsyncTask extends AsyncTask<String, String, String> {
+
+ private WeakReference<ConsumeTask> mTask;
+
+ ConsumeAsyncTask(ConsumeTask consume) {
+ mTask = new WeakReference<>(consume);
+ }
+
+ @Override
+ protected String doInBackground(String... strings) {
+ ConsumeTask consume = mTask.get();
+ if (consume != null) {
+ return consume.doInBackground(strings);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(String param) {
+ ConsumeTask consume = mTask.get();
+ if (consume != null) {
+ consume.onPostExecute(param);
+ }
+ }
+ }
+
+ public ConsumeTask(IInAppBillingService mService, Context context) {
+ this.context = context;
+ this.mService = mService;
+ }
+
+ public void consume(final String sku) {
+ mSku = sku;
+ PaymentsCache pc = new PaymentsCache(context);
+ Boolean isBlocked = pc.getConsumableFlag("block", sku);
+ mToken = pc.getConsumableValue("token", sku);
+ if (!isBlocked && mToken == null) {
+ // Consuming task is processing
+ } else if (!isBlocked) {
+ return;
+ } else if (mToken == null) {
+ this.error("No token for sku:" + sku);
+ return;
+ }
+ new ConsumeAsyncTask(this).execute();
+ }
+
+ private String doInBackground(String... params) {
+ try {
+ int response = mService.consumePurchase(3, context.getPackageName(), mToken);
+ if (response == 0 || response == 8) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ return e.getMessage();
+ }
+ return "Some error";
+ }
+
+ private void onPostExecute(String param) {
+ if (param == null) {
+ success(new PaymentsCache(context).getConsumableValue("ticket", mSku));
+ } else {
+ error(param);
+ }
+ }
+
+ abstract protected void success(String ticket);
+ abstract protected void error(String message);
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
index 4a6b611c4d..c7d0a5de65 100644
--- a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
@@ -30,6 +30,7 @@
package org.godotengine.godot.plugin.payment;
+import android.content.Intent;
import android.support.annotation.NonNull;
import android.util.Log;
import java.util.ArrayList;
@@ -38,28 +39,40 @@ import java.util.List;
import org.godotengine.godot.Dictionary;
import org.godotengine.godot.Godot;
import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.payments.GodotPaymentInterface;
-import org.godotengine.godot.payments.PaymentsManager;
import org.godotengine.godot.plugin.GodotPlugin;
import org.json.JSONException;
import org.json.JSONObject;
-public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
+public class GodotPayment extends GodotPlugin {
private Integer purchaseCallbackId = 0;
private String accessToken;
private String purchaseValidationUrlPrefix;
private String transactionId;
- private PaymentsManager mPaymentManager;
- private Dictionary mSkuDetails = new Dictionary();
+ private final PaymentsManager mPaymentManager;
+ private final Dictionary mSkuDetails = new Dictionary();
public GodotPayment(Godot godot) {
super(godot);
- mPaymentManager = godot.getPaymentsManager();
- mPaymentManager.setBaseSingleton(this);
+ mPaymentManager = new PaymentsManager(godot, this);
+ mPaymentManager.initService();
}
@Override
+ public void onMainActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE) {
+ mPaymentManager.processPurchaseResponse(resultCode, data);
+ }
+ }
+
+ @Override
+ public void onMainDestroy() {
+ super.onMainDestroy();
+ if (mPaymentManager != null) {
+ mPaymentManager.destroy();
+ }
+ }
+
public void purchase(final String sku, final String transactionId) {
runOnUiThread(new Runnable() {
@Override
@@ -69,7 +82,6 @@ public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
});
}
- @Override
public void consumeUnconsumedPurchases() {
runOnUiThread(new Runnable() {
@Override
@@ -81,89 +93,72 @@ public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
private String signature;
- @Override
public String getSignature() {
return this.signature;
}
- @Override
public void callbackSuccess(String ticket, String signature, String sku) {
GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[] { ticket, signature, sku });
}
- @Override
public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku) {
Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > " + ticket + "," + signature + "," + sku);
GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[] { ticket, signature, sku });
}
- @Override
public void callbackSuccessNoUnconsumedPurchases() {
GodotLib.calldeferred(purchaseCallbackId, "consume_not_required", new Object[] {});
}
- @Override
public void callbackFailConsume(String message) {
GodotLib.calldeferred(purchaseCallbackId, "consume_fail", new Object[] { message });
}
- @Override
public void callbackFail(String message) {
GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[] { message });
}
- @Override
public void callbackCancel() {
GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[] {});
}
- @Override
public void callbackAlreadyOwned(String sku) {
GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[] { sku });
}
- @Override
public int getPurchaseCallbackId() {
return purchaseCallbackId;
}
- @Override
public void setPurchaseCallbackId(int purchaseCallbackId) {
this.purchaseCallbackId = purchaseCallbackId;
}
- @Override
public String getPurchaseValidationUrlPrefix() {
return this.purchaseValidationUrlPrefix;
}
- @Override
public void setPurchaseValidationUrlPrefix(String url) {
this.purchaseValidationUrlPrefix = url;
}
- @Override
public String getAccessToken() {
return accessToken;
}
- @Override
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
- @Override
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
- @Override
public String getTransactionId() {
return this.transactionId;
}
// request purchased items are not consumed
- @Override
public void requestPurchased() {
runOnUiThread(new Runnable() {
@Override
@@ -174,41 +169,34 @@ public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
}
// callback for requestPurchased()
- @Override
public void callbackPurchased(String receipt, String signature, String sku) {
GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[] { receipt, signature, sku });
}
- @Override
public void callbackDisconnected() {
GodotLib.calldeferred(purchaseCallbackId, "iap_disconnected", new Object[] {});
}
- @Override
public void callbackConnected() {
GodotLib.calldeferred(purchaseCallbackId, "iap_connected", new Object[] {});
}
// true if connected, false otherwise
- @Override
public boolean isConnected() {
return mPaymentManager.isConnected();
}
// consume item automatically after purchase. default is true.
- @Override
public void setAutoConsume(boolean autoConsume) {
mPaymentManager.setAutoConsume(autoConsume);
}
// consume a specific item
- @Override
public void consume(String sku) {
mPaymentManager.consume(sku);
}
// query in app item detail info
- @Override
public void querySkuDetails(String[] list) {
List<String> nKeys = Arrays.asList(list);
List<String> cKeys = Arrays.asList(mSkuDetails.get_keys());
@@ -225,7 +213,6 @@ public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
}
}
- @Override
public void addSkuDetail(String itemJson) {
JSONObject o = null;
try {
@@ -244,12 +231,10 @@ public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
}
}
- @Override
public void completeSkuDetail() {
GodotLib.calldeferred(purchaseCallbackId, "sku_details_complete", new Object[] { mSkuDetails });
}
- @Override
public void errorSkuDetail(String errorMessage) {
GodotLib.calldeferred(purchaseCallbackId, "sku_details_error", new Object[] { errorMessage });
}
@@ -263,6 +248,8 @@ public class GodotPayment extends GodotPlugin implements GodotPaymentInterface {
@NonNull
@Override
public List<String> getPluginMethods() {
- return Arrays.asList("purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails", "isConnected");
+ return Arrays.asList("purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix",
+ "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased",
+ "setAutoConsume", "consume", "querySkuDetails", "isConnected");
}
}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java
new file mode 100644
index 0000000000..fe5685288b
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java
@@ -0,0 +1,93 @@
+/*************************************************************************/
+/* HandlePurchaseTask.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.app.Activity;
+import android.content.Intent;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+abstract public class HandlePurchaseTask {
+
+ private Activity context;
+
+ public HandlePurchaseTask(Activity context) {
+ this.context = context;
+ }
+
+ public void handlePurchaseRequest(int resultCode, Intent data) {
+ //Log.d("XXX", "Handling purchase response");
+ if (resultCode == Activity.RESULT_OK) {
+ try {
+ //int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
+ PaymentsCache pc = new PaymentsCache(context);
+
+ String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
+ //Log.d("XXX", "Purchase data:" + purchaseData);
+ String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
+ //Log.d("XXX", "Purchase signature:" + dataSignature);
+ //Log.d("SARLANGA", purchaseData);
+
+ JSONObject jo = new JSONObject(purchaseData);
+ //String sku = jo.getString("productId");
+ //alert("You have bought the " + sku + ". Excellent choice, aventurer!");
+ //String orderId = jo.getString("orderId");
+ //String packageName = jo.getString("packageName");
+ String productId = jo.getString("productId");
+ //Long purchaseTime = jo.getLong("purchaseTime");
+ //Integer state = jo.getInt("purchaseState");
+ String developerPayload = jo.getString("developerPayload");
+ String purchaseToken = jo.getString("purchaseToken");
+
+ if (!pc.getConsumableValue("validation_hash", productId).equals(developerPayload)) {
+ error("Untrusted callback");
+ return;
+ }
+ //Log.d("XXX", "Este es el product ID:" + productId);
+ pc.setConsumableValue("ticket_signautre", productId, dataSignature);
+ pc.setConsumableValue("ticket", productId, purchaseData);
+ pc.setConsumableFlag("block", productId, true);
+ pc.setConsumableValue("token", productId, purchaseToken);
+
+ success(productId, dataSignature, purchaseData);
+ return;
+ } catch (JSONException e) {
+ error(e.getMessage());
+ }
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ canceled();
+ }
+ }
+
+ abstract protected void success(String sku, String signature, String ticket);
+ abstract protected void error(String message);
+ abstract protected void canceled();
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java
new file mode 100644
index 0000000000..d5919e3d9d
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* PaymentsCache.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+public class PaymentsCache {
+
+ public Context context;
+
+ public PaymentsCache(Context context) {
+ this.context = context;
+ }
+
+ public void setConsumableFlag(String set, String sku, Boolean flag) {
+ SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putBoolean(sku, flag);
+ editor.apply();
+ }
+
+ public boolean getConsumableFlag(String set, String sku) {
+ SharedPreferences sharedPref = context.getSharedPreferences(
+ "consumables_" + set, Context.MODE_PRIVATE);
+ return sharedPref.getBoolean(sku, false);
+ }
+
+ public void setConsumableValue(String set, String sku, String value) {
+ SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString(sku, value);
+ //Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
+ editor.apply();
+ }
+
+ public String getConsumableValue(String set, String sku) {
+ SharedPreferences sharedPref = context.getSharedPreferences(
+ "consumables_" + set, Context.MODE_PRIVATE);
+ //Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
+ return sharedPref.getString(sku, null);
+ }
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java
new file mode 100644
index 0000000000..bded1f452f
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java
@@ -0,0 +1,405 @@
+/*************************************************************************/
+/* PaymentsManager.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.vending.billing.IInAppBillingService;
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class PaymentsManager {
+
+ public static final int BILLING_RESPONSE_RESULT_OK = 0;
+ public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001;
+ private static boolean auto_consume = true;
+
+ private final Activity activity;
+ private final GodotPayment godotPayment;
+ IInAppBillingService mService;
+
+ PaymentsManager(Activity activity, GodotPayment godotPayment) {
+ this.activity = activity;
+ this.godotPayment = godotPayment;
+ }
+
+ public PaymentsManager initService() {
+ Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+ intent.setPackage("com.android.vending");
+ activity.bindService(
+ intent,
+ mServiceConn,
+ Context.BIND_AUTO_CREATE);
+ return this;
+ }
+
+ public void destroy() {
+ if (mService != null) {
+ activity.unbindService(mServiceConn);
+ }
+ }
+
+ ServiceConnection mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+
+ // At this stage, godotPayment might not have been initialized yet.
+ if (godotPayment != null) {
+ godotPayment.callbackDisconnected();
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = IInAppBillingService.Stub.asInterface(service);
+
+ // At this stage, godotPayment might not have been initialized yet.
+ if (godotPayment != null) {
+ godotPayment.callbackConnected();
+ }
+ }
+ };
+
+ public void requestPurchase(final String sku, String transactionId) {
+ new PurchaseTask(mService, activity) {
+ @Override
+ protected void error(String message) {
+ godotPayment.callbackFail(message);
+ }
+
+ @Override
+ protected void canceled() {
+ godotPayment.callbackCancel();
+ }
+
+ @Override
+ protected void alreadyOwned() {
+ godotPayment.callbackAlreadyOwned(sku);
+ }
+ }
+ .purchase(sku, transactionId);
+ }
+
+ public boolean isConnected() {
+ return mService != null;
+ }
+
+ public void consumeUnconsumedPurchases() {
+ new ReleaseAllConsumablesTask(mService, activity) {
+ @Override
+ protected void success(String sku, String receipt, String signature, String token) {
+ godotPayment.callbackSuccessProductMassConsumed(receipt, signature, sku);
+ }
+
+ @Override
+ protected void error(String message) {
+ Log.d("godot", "consumeUnconsumedPurchases :" + message);
+ godotPayment.callbackFailConsume(message);
+ }
+
+ @Override
+ protected void notRequired() {
+ Log.d("godot", "callbackSuccessNoUnconsumedPurchases :");
+ godotPayment.callbackSuccessNoUnconsumedPurchases();
+ }
+ }
+ .consumeItAll();
+ }
+
+ public void requestPurchased() {
+ try {
+ PaymentsCache pc = new PaymentsCache(activity);
+
+ String continueToken = null;
+
+ do {
+ Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp", continueToken);
+
+ if (bundle.getInt("RESPONSE_CODE") == 0) {
+
+ final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
+ final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
+
+ if (myPurchases == null || myPurchases.size() == 0) {
+ godotPayment.callbackPurchased("", "", "");
+ return;
+ }
+
+ for (int i = 0; i < myPurchases.size(); i++) {
+
+ try {
+ String receipt = myPurchases.get(i);
+ JSONObject inappPurchaseData = new JSONObject(receipt);
+ String sku = inappPurchaseData.getString("productId");
+ String token = inappPurchaseData.getString("purchaseToken");
+ String signature = mySignatures.get(i);
+
+ pc.setConsumableValue("ticket_signautre", sku, signature);
+ pc.setConsumableValue("ticket", sku, receipt);
+ pc.setConsumableFlag("block", sku, true);
+ pc.setConsumableValue("token", sku, token);
+
+ godotPayment.callbackPurchased(receipt, signature, sku);
+ } catch (JSONException e) {
+ }
+ }
+ }
+ continueToken = bundle.getString("INAPP_CONTINUATION_TOKEN");
+ Log.d("godot", "continue token = " + continueToken);
+ } while (!TextUtils.isEmpty(continueToken));
+ } catch (Exception e) {
+ Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage());
+ }
+ }
+
+ public void processPurchaseResponse(int resultCode, Intent data) {
+ new HandlePurchaseTask(activity) {
+ @Override
+ protected void success(final String sku, final String signature, final String ticket) {
+ godotPayment.callbackSuccess(ticket, signature, sku);
+
+ if (auto_consume) {
+ new ConsumeTask(mService, activity) {
+ @Override
+ protected void success(String ticket) {
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPayment.callbackFail(message);
+ }
+ }
+ .consume(sku);
+ }
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPayment.callbackFail(message);
+ }
+
+ @Override
+ protected void canceled() {
+ godotPayment.callbackCancel();
+ }
+ }
+ .handlePurchaseRequest(resultCode, data);
+ }
+
+ public void validatePurchase(String purchaseToken, final String sku) {
+
+ new ValidateTask(activity, godotPayment) {
+ @Override
+ protected void success() {
+
+ new ConsumeTask(mService, activity) {
+ @Override
+ protected void success(String ticket) {
+ godotPayment.callbackSuccess(ticket, null, sku);
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPayment.callbackFail(message);
+ }
+ }
+ .consume(sku);
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPayment.callbackFail(message);
+ }
+
+ @Override
+ protected void canceled() {
+ godotPayment.callbackCancel();
+ }
+ }
+ .validatePurchase(sku);
+ }
+
+ public void setAutoConsume(boolean autoConsume) {
+ auto_consume = autoConsume;
+ }
+
+ public void consume(final String sku) {
+ new ConsumeTask(mService, activity) {
+ @Override
+ protected void success(String ticket) {
+ godotPayment.callbackSuccessProductMassConsumed(ticket, "", sku);
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPayment.callbackFailConsume(message);
+ }
+ }
+ .consume(sku);
+ }
+
+ // Workaround to bug where sometimes response codes come as Long instead of Integer
+ int getResponseCodeFromBundle(Bundle b) {
+ Object o = b.get("RESPONSE_CODE");
+ if (o == null) {
+ //logDebug("Bundle with null response code, assuming OK (known issue)");
+ return BILLING_RESPONSE_RESULT_OK;
+ } else if (o instanceof Integer)
+ return ((Integer)o).intValue();
+ else if (o instanceof Long)
+ return (int)((Long)o).longValue();
+ else {
+ //logError("Unexpected type for bundle response code.");
+ //logError(o.getClass().getName());
+ throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName());
+ }
+ }
+
+ /**
+ * Returns a human-readable description for the given response code.
+ *
+ * @param code The response code
+ * @return A human-readable string explaining the result code.
+ * It also includes the result code numerically.
+ */
+ public static String getResponseDesc(int code) {
+ String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/"
+ +
+ "3:Billing Unavailable/4:Item unavailable/"
+ +
+ "5:Developer Error/6:Error/7:Item Already Owned/"
+ +
+ "8:Item not owned")
+ .split("/");
+ String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/"
+ +
+ "-1002:Bad response received/"
+ +
+ "-1003:Purchase signature verification failed/"
+ +
+ "-1004:Send intent failed/"
+ +
+ "-1005:User cancelled/"
+ +
+ "-1006:Unknown purchase response/"
+ +
+ "-1007:Missing token/"
+ +
+ "-1008:Unknown error/"
+ +
+ "-1009:Subscriptions not available/"
+ +
+ "-1010:Invalid consumption attempt")
+ .split("/");
+
+ if (code <= -1000) {
+ int index = -1000 - code;
+ if (index >= 0 && index < iabhelper_msgs.length)
+ return iabhelper_msgs[index];
+ else
+ return String.valueOf(code) + ":Unknown IAB Helper Error";
+ } else if (code < 0 || code >= iab_msgs.length)
+ return String.valueOf(code) + ":Unknown";
+ else
+ return iab_msgs[code];
+ }
+
+ public void querySkuDetails(final String[] list) {
+ (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ ArrayList<String> skuList = new ArrayList<String>(Arrays.asList(list));
+ if (skuList.size() == 0) {
+ return;
+ }
+ // Split the sku list in blocks of no more than 20 elements.
+ ArrayList<ArrayList<String>> packs = new ArrayList<ArrayList<String>>();
+ ArrayList<String> tempList;
+ int n = skuList.size() / 20;
+ int mod = skuList.size() % 20;
+ for (int i = 0; i < n; i++) {
+ tempList = new ArrayList<String>();
+ for (String s : skuList.subList(i * 20, i * 20 + 20)) {
+ tempList.add(s);
+ }
+ packs.add(tempList);
+ }
+ if (mod != 0) {
+ tempList = new ArrayList<String>();
+ for (String s : skuList.subList(n * 20, n * 20 + mod)) {
+ tempList.add(s);
+ }
+ packs.add(tempList);
+ }
+ for (ArrayList<String> skuPartList : packs) {
+ Bundle querySkus = new Bundle();
+ querySkus.putStringArrayList("ITEM_ID_LIST", skuPartList);
+ Bundle skuDetails = null;
+ try {
+ skuDetails = mService.getSkuDetails(3, activity.getPackageName(), "inapp", querySkus);
+ if (!skuDetails.containsKey("DETAILS_LIST")) {
+ int response = getResponseCodeFromBundle(skuDetails);
+ if (response != BILLING_RESPONSE_RESULT_OK) {
+ godotPayment.errorSkuDetail(getResponseDesc(response));
+ } else {
+ godotPayment.errorSkuDetail("No error but no detail list.");
+ }
+ return;
+ }
+
+ ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
+
+ for (String thisResponse : responseList) {
+ Log.d("godot", "response = " + thisResponse);
+ godotPayment.addSkuDetail(thisResponse);
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ godotPayment.errorSkuDetail("RemoteException error!");
+ }
+ }
+ godotPayment.completeSkuDetail();
+ }
+ }))
+ .start();
+ }
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java
new file mode 100644
index 0000000000..eecd1d2151
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* PurchaseTask.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.vending.billing.IInAppBillingService;
+
+abstract public class PurchaseTask {
+
+ private Activity context;
+
+ private IInAppBillingService mService;
+ public PurchaseTask(IInAppBillingService mService, Activity context) {
+ this.context = context;
+ this.mService = mService;
+ }
+
+ private boolean isLooping = false;
+
+ public void purchase(final String sku, final String transactionId) {
+ Log.d("XXX", "Starting purchase for: " + sku);
+ PaymentsCache pc = new PaymentsCache(context);
+ Boolean isBlocked = pc.getConsumableFlag("block", sku);
+ /*
+ if(isBlocked){
+ Log.d("XXX", "Is awaiting payment confirmation");
+ error("Awaiting payment confirmation");
+ return;
+ }
+ */
+ final String hash = transactionId;
+
+ Bundle buyIntentBundle;
+ try {
+ buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash);
+ } catch (RemoteException e) {
+ //Log.d("XXX", "Error: " + e.getMessage());
+ error(e.getMessage());
+ return;
+ }
+ Object rc = buyIntentBundle.get("RESPONSE_CODE");
+ int responseCode = 0;
+ if (rc == null) {
+ responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK;
+ } else if (rc instanceof Integer) {
+ responseCode = ((Integer)rc).intValue();
+ } else if (rc instanceof Long) {
+ responseCode = (int)((Long)rc).longValue();
+ }
+ //Log.d("XXX", "Buy intent response code: " + responseCode);
+ if (responseCode == 1 || responseCode == 3 || responseCode == 4) {
+ canceled();
+ return;
+ }
+ if (responseCode == 7) {
+ alreadyOwned();
+ return;
+ }
+
+ PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
+ pc.setConsumableValue("validation_hash", sku, hash);
+ try {
+ if (context == null) {
+ //Log.d("XXX", "No context!");
+ }
+ if (pendingIntent == null) {
+ //Log.d("XXX", "No pending intent");
+ }
+ //Log.d("XXX", "Starting activity for purchase!");
+ context.startIntentSenderForResult(
+ pendingIntent.getIntentSender(),
+ PaymentsManager.REQUEST_CODE_FOR_PURCHASE,
+ new Intent(),
+ Integer.valueOf(0), Integer.valueOf(0),
+ Integer.valueOf(0));
+ } catch (SendIntentException e) {
+ error(e.getMessage());
+ }
+ }
+
+ abstract protected void error(String message);
+ abstract protected void canceled();
+ abstract protected void alreadyOwned();
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java
new file mode 100644
index 0000000000..b7bd638feb
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java
@@ -0,0 +1,141 @@
+/*************************************************************************/
+/* ReleaseAllConsumablesTask.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import com.android.vending.billing.IInAppBillingService;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+abstract public class ReleaseAllConsumablesTask {
+
+ private Context context;
+ private IInAppBillingService mService;
+
+ private static class ReleaseAllConsumablesAsyncTask extends AsyncTask<String, String, String> {
+
+ private WeakReference<ReleaseAllConsumablesTask> mTask;
+ private String mSku;
+ private String mReceipt;
+ private String mSignature;
+ private String mToken;
+
+ ReleaseAllConsumablesAsyncTask(ReleaseAllConsumablesTask task, String sku, String receipt, String signature, String token) {
+ mTask = new WeakReference<ReleaseAllConsumablesTask>(task);
+
+ mSku = sku;
+ mReceipt = receipt;
+ mSignature = signature;
+ mToken = token;
+ }
+
+ @Override
+ protected String doInBackground(String... params) {
+ ReleaseAllConsumablesTask consume = mTask.get();
+ if (consume != null) {
+ return consume.doInBackground(mToken);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(String param) {
+ ReleaseAllConsumablesTask consume = mTask.get();
+ if (consume != null) {
+ consume.success(mSku, mReceipt, mSignature, mToken);
+ }
+ }
+ }
+
+ public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context) {
+ this.context = context;
+ this.mService = mService;
+ }
+
+ public void consumeItAll() {
+ try {
+ //Log.d("godot", "consumeItall for " + context.getPackageName());
+ Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp", null);
+
+ if (bundle.getInt("RESPONSE_CODE") == 0) {
+
+ final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
+ final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
+
+ if (myPurchases == null || myPurchases.size() == 0) {
+ //Log.d("godot", "No purchases!");
+ notRequired();
+ return;
+ }
+
+ //Log.d("godot", "# products to be consumed:" + myPurchases.size());
+ for (int i = 0; i < myPurchases.size(); i++) {
+
+ try {
+ String receipt = myPurchases.get(i);
+ JSONObject inappPurchaseData = new JSONObject(receipt);
+ String sku = inappPurchaseData.getString("productId");
+ String token = inappPurchaseData.getString("purchaseToken");
+ String signature = mySignatures.get(i);
+ //Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt);
+ new ReleaseAllConsumablesAsyncTask(this, sku, receipt, signature, token).execute();
+ } catch (JSONException e) {
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage());
+ }
+ }
+
+ private String doInBackground(String token) {
+ try {
+ //Log.d("godot", "Requesting to consume an item with token ." + token);
+ int response = mService.consumePurchase(3, context.getPackageName(), token);
+ //Log.d("godot", "consumePurchase response: " + response);
+ if (response == 0 || response == 8) {
+ return null;
+ }
+ } catch (Exception e) {
+ Log.d("godot", "Error " + e.getClass().getName() + ":" + e.getMessage());
+ }
+ return null;
+ }
+
+ abstract protected void success(String sku, String receipt, String signature, String token);
+ abstract protected void error(String message);
+ abstract protected void notRequired();
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java
new file mode 100644
index 0000000000..d42ded0c9b
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java
@@ -0,0 +1,141 @@
+/*************************************************************************/
+/* ValidateTask.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+import java.lang.ref.WeakReference;
+import org.godotengine.godot.plugin.payment.utils.HttpRequester;
+import org.godotengine.godot.plugin.payment.utils.RequestParams;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+abstract public class ValidateTask {
+
+ private Activity context;
+ private GodotPayment godotPayments;
+ private ProgressDialog dialog;
+ private String mSku;
+
+ private static class ValidateAsyncTask extends AsyncTask<String, String, String> {
+ private WeakReference<ValidateTask> mTask;
+
+ ValidateAsyncTask(ValidateTask task) {
+ mTask = new WeakReference<>(task);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ ValidateTask task = mTask.get();
+ if (task != null) {
+ task.onPreExecute();
+ }
+ }
+
+ @Override
+ protected String doInBackground(String... params) {
+ ValidateTask task = mTask.get();
+ if (task != null) {
+ return task.doInBackground(params);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(String response) {
+ ValidateTask task = mTask.get();
+ if (task != null) {
+ task.onPostExecute(response);
+ }
+ }
+ }
+
+ public ValidateTask(Activity context, GodotPayment godotPayments) {
+ this.context = context;
+ this.godotPayments = godotPayments;
+ }
+
+ public void validatePurchase(final String sku) {
+ mSku = sku;
+ new ValidateAsyncTask(this).execute();
+ }
+
+ private void onPreExecute() {
+ dialog = ProgressDialog.show(context, null, "Please wait...");
+ }
+
+ private String doInBackground(String... params) {
+ PaymentsCache pc = new PaymentsCache(context);
+ String url = godotPayments.getPurchaseValidationUrlPrefix();
+ RequestParams param = new RequestParams();
+ param.setUrl(url);
+ param.put("ticket", pc.getConsumableValue("ticket", mSku));
+ param.put("purchaseToken", pc.getConsumableValue("token", mSku));
+ param.put("sku", mSku);
+ //Log.d("XXX", "Haciendo request a " + url);
+ //Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku));
+ //Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku));
+ //Log.d("XXX", "sku: " + sku);
+ param.put("package", context.getApplicationContext().getPackageName());
+ HttpRequester requester = new HttpRequester();
+ String jsonResponse = requester.post(param);
+ //Log.d("XXX", "Validation response:\n"+jsonResponse);
+ return jsonResponse;
+ }
+
+ private void onPostExecute(String response) {
+ if (dialog != null) {
+ dialog.dismiss();
+ dialog = null;
+ }
+ JSONObject j;
+ try {
+ j = new JSONObject(response);
+ if (j.getString("status").equals("OK")) {
+ success();
+ return;
+ } else if (j.getString("status") != null) {
+ error(j.getString("message"));
+ } else {
+ error("Connection error");
+ }
+ } catch (JSONException e) {
+ error(e.getMessage());
+ } catch (Exception e) {
+ error(e.getMessage());
+ }
+ }
+
+ abstract protected void success();
+ abstract protected void error(String message);
+ abstract protected void canceled();
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/CustomSSLSocketFactory.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/CustomSSLSocketFactory.java
new file mode 100644
index 0000000000..9571769cd3
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/CustomSSLSocketFactory.java
@@ -0,0 +1,70 @@
+/*************************************************************************/
+/* CustomSSLSocketFactory.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment.utils;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+
+/**
+ *
+ * @author Luis Linietsky <luis.linietsky@gmail.com>
+ */
+public class CustomSSLSocketFactory extends SSLSocketFactory {
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+
+ public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(truststore);
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
+ tmf.init(truststore);
+
+ sslContext.init(null, tmf.getTrustManagers(), null);
+ }
+
+ @Override
+ public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
+ return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ return sslContext.getSocketFactory().createSocket();
+ }
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/HttpRequester.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/HttpRequester.java
new file mode 100644
index 0000000000..dcb983201e
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/HttpRequester.java
@@ -0,0 +1,228 @@
+/*************************************************************************/
+/* HttpRequester.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.security.KeyStore;
+import java.util.Date;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.EntityUtils;
+import org.godotengine.godot.utils.Crypt;
+
+/**
+ *
+ * @author Luis Linietsky <luis.linietsky@gmail.com>
+ */
+public class HttpRequester {
+
+ private Context context;
+ private static final int TTL = 600000; // 10 minutos
+ private long cttl = 0;
+
+ public HttpRequester() {
+ //Log.d("XXX", "Creando http request sin contexto");
+ }
+
+ public HttpRequester(Context context) {
+ this.context = context;
+ //Log.d("XXX", "Creando http request con contexto");
+ }
+
+ public String post(RequestParams params) {
+ HttpPost httppost = new HttpPost(params.getUrl());
+ try {
+ httppost.setEntity(new UrlEncodedFormEntity(params.toPairsList()));
+ return request(httppost);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+
+ public String get(RequestParams params) {
+ String response = getResponseFromCache(params.getUrl());
+ if (response == null) {
+ //Log.d("XXX", "Cache miss!");
+ HttpGet httpget = new HttpGet(params.getUrl());
+ long timeInit = new Date().getTime();
+ response = request(httpget);
+ long delay = new Date().getTime() - timeInit;
+ Log.d("HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay / 1000.0f) + " seconds");
+ if (response == null || response.length() == 0) {
+ response = "";
+ } else {
+ saveResponseIntoCache(params.getUrl(), response);
+ }
+ }
+ Log.d("XXX", "Req: " + params.getUrl());
+ Log.d("XXX", "Resp: " + response);
+ return response;
+ }
+
+ private String request(HttpUriRequest request) {
+ //Log.d("XXX", "Haciendo request a: " + request.getURI() );
+ Log.d("PPP", "Haciendo request a: " + request.getURI());
+ long init = new Date().getTime();
+ HttpClient httpclient = getNewHttpClient();
+ HttpParams httpParameters = httpclient.getParams();
+ HttpConnectionParams.setConnectionTimeout(httpParameters, 0);
+ HttpConnectionParams.setSoTimeout(httpParameters, 0);
+ HttpConnectionParams.setTcpNoDelay(httpParameters, true);
+ try {
+ HttpResponse response = httpclient.execute(request);
+ Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI());
+ //Log.d("XXX1", "Status:" + response.getStatusLine().toString());
+ if (response.getStatusLine().getStatusCode() == 200) {
+ String strResponse = EntityUtils.toString(response.getEntity());
+ //Log.d("XXX2", strResponse);
+ return strResponse;
+ } else {
+ Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity()));
+ return null;
+ }
+
+ } catch (ClientProtocolException e) {
+ Log.d("XXX3", e.getMessage());
+ } catch (IOException e) {
+ Log.d("XXX4", e.getMessage());
+ }
+ return null;
+ }
+
+ private HttpClient getNewHttpClient() {
+ try {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ trustStore.load(null, null);
+
+ SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
+ sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+ HttpParams params = new BasicHttpParams();
+ HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+ HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+
+ SchemeRegistry registry = new SchemeRegistry();
+ registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+ registry.register(new Scheme("https", sf, 443));
+
+ ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
+
+ return new DefaultHttpClient(ccm, params);
+ } catch (Exception e) {
+ return new DefaultHttpClient();
+ }
+ }
+
+ private static String convertStreamToString(InputStream is) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ StringBuilder sb = new StringBuilder();
+ String line = null;
+ try {
+ while ((line = reader.readLine()) != null) {
+ sb.append((line + "\n"));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return sb.toString();
+ }
+
+ public void saveResponseIntoCache(String request, String response) {
+ if (context == null) {
+ //Log.d("XXX", "No context, cache failed!");
+ return;
+ }
+ SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString("request_" + Crypt.md5(request), response);
+ editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl());
+ editor.apply();
+ }
+
+ public String getResponseFromCache(String request) {
+ if (context == null) {
+ Log.d("XXX", "No context, cache miss");
+ return null;
+ }
+ SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE);
+ long ttl = getResponseTtl(request);
+ if (ttl == 0l || (new Date().getTime() - ttl) > 0l) {
+ Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime());
+ return null;
+ }
+ return sharedPref.getString("request_" + Crypt.md5(request), null);
+ }
+
+ public long getResponseTtl(String request) {
+ SharedPreferences sharedPref = context.getSharedPreferences(
+ "http_get_cache", Context.MODE_PRIVATE);
+ return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l);
+ }
+
+ public long getTtl() {
+ return cttl > 0 ? cttl : TTL;
+ }
+
+ public void setTtl(long ttl) {
+ this.cttl = (ttl * 1000) + new Date().getTime();
+ }
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/RequestParams.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/RequestParams.java
new file mode 100644
index 0000000000..4be8b37473
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/utils/RequestParams.java
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* RequestParams.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.payment.utils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
+
+/**
+ *
+ * @author Luis Linietsky <luis.linietsky@gmail.com>
+ */
+public class RequestParams {
+
+ private HashMap<String, String> params;
+ private String url;
+
+ public RequestParams() {
+ params = new HashMap<String, String>();
+ }
+
+ public void put(String key, String value) {
+ params.put(key, value);
+ }
+
+ public String get(String key) {
+ return params.get(key);
+ }
+
+ public void remove(Object key) {
+ params.remove(key);
+ }
+
+ public boolean has(String key) {
+ return params.containsKey(key);
+ }
+
+ public List<NameValuePair> toPairsList() {
+ List<NameValuePair> fields = new ArrayList<NameValuePair>();
+
+ for (String key : params.keySet()) {
+ fields.add(new BasicNameValuePair(key, this.get(key)));
+ }
+ return fields;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+}
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index 9e9b17fb99..6b9105b8e5 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -34,13 +34,13 @@
bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret) {
- Map<StringName, List<MethodInfo> >::Element *M = methods.find(p_method);
+ Map<StringName, List<MethodInfo>>::Element *M = methods.find(p_method);
if (!M)
return false;
JNIEnv *env = ThreadAndroid::get_env();
- MethodInfo *method = NULL;
+ MethodInfo *method = nullptr;
for (List<MethodInfo>::Element *E = M->get().front(); E; E = E->next()) {
if (!p_instance && !E->get()._static) {
@@ -160,7 +160,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
r_error.error = Callable::CallError::CALL_OK;
- jvalue *argv = NULL;
+ jvalue *argv = nullptr;
if (method->param_types.size()) {
@@ -173,7 +173,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
switch (method->param_types[i]) {
case ARG_TYPE_VOID: {
//can't happen
- argv[i].l = NULL; //I hope this works
+ argv[i].l = nullptr; //I hope this works
} break;
case ARG_TYPE_BOOLEAN: {
@@ -285,7 +285,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
argv[i].l = jo->instance;
} else {
- argv[i].l = NULL; //I hope this works
+ argv[i].l = nullptr; //I hope this works
}
} break;
@@ -386,7 +386,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
case ARG_ARRAY_BIT | ARG_TYPE_STRING: {
Array arr = *p_args[i];
- jobjectArray a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), NULL);
+ jobjectArray a = env->NewObjectArray(arr.size(), env->FindClass("java/lang/String"), nullptr);
for (int j = 0; j < arr.size(); j++) {
String s = arr[j];
@@ -400,7 +400,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
} break;
case ARG_ARRAY_BIT | ARG_TYPE_CLASS: {
- argv[i].l = NULL;
+ argv[i].l = nullptr;
} break;
}
}
@@ -520,7 +520,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
Variant JavaClass::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
Variant ret;
- bool found = _call_method(NULL, p_method, p_args, p_argcount, r_error, ret);
+ bool found = _call_method(nullptr, p_method, p_args, p_argcount, r_error, ret);
if (found) {
return ret;
}
@@ -1205,7 +1205,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
int mods = env->CallIntMethod(obj, Field_getModifiers);
if ((mods & 0x8) && (mods & 0x10) && (mods & 0x1)) { //static final public!
- jobject objc = env->CallObjectMethod(obj, Field_get, NULL);
+ jobject objc = env->CallObjectMethod(obj, Field_get, nullptr);
if (objc) {
uint32_t sig;
@@ -1236,7 +1236,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
return Ref<JavaClass>();
}
-JavaClassWrapper *JavaClassWrapper::singleton = NULL;
+JavaClassWrapper *JavaClassWrapper::singleton = nullptr;
JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 8d075f8e97..0da0bd6387 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -56,11 +56,8 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;I)V");
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
+ _get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I");
_get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(I)Ljava/lang/String;");
- _play_video = p_env->GetMethodID(cls, "playVideo", "(Ljava/lang/String;)V");
- _is_video_playing = p_env->GetMethodID(cls, "isVideoPlaying", "()Z");
- _pause_video = p_env->GetMethodID(cls, "pauseVideo", "()V");
- _stop_video = p_env->GetMethodID(cls, "stopVideo", "()V");
}
}
@@ -157,40 +154,22 @@ void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
}
}
-String GodotIOJavaWrapper::get_system_dir(int p_dir) {
- if (_get_system_dir) {
+int GodotIOJavaWrapper::get_screen_orientation() {
+ if (_get_screen_orientation) {
JNIEnv *env = ThreadAndroid::get_env();
- jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
- return jstring_to_string(s, env);
+ return env->CallIntMethod(godot_io_instance, _get_screen_orientation);
} else {
- return String(".");
+ return 0;
}
}
-void GodotIOJavaWrapper::play_video(const String &p_path) {
- // Why is this not here?!?!
-}
-
-bool GodotIOJavaWrapper::is_video_playing() {
- if (_is_video_playing) {
+String GodotIOJavaWrapper::get_system_dir(int p_dir) {
+ if (_get_system_dir) {
JNIEnv *env = ThreadAndroid::get_env();
- return env->CallBooleanMethod(godot_io_instance, _is_video_playing);
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
+ return jstring_to_string(s, env);
} else {
- return false;
- }
-}
-
-void GodotIOJavaWrapper::pause_video() {
- if (_pause_video) {
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(godot_io_instance, _pause_video);
- }
-}
-
-void GodotIOJavaWrapper::stop_video() {
- if (_stop_video) {
- JNIEnv *env = ThreadAndroid::get_env();
- env->CallVoidMethod(godot_io_instance, _stop_video);
+ return String(".");
}
}
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index 7dfed52187..dbb3b564f6 100644
--- a/platform/android/java_godot_io_wrapper.h
+++ b/platform/android/java_godot_io_wrapper.h
@@ -54,11 +54,8 @@ private:
jmethodID _show_keyboard = 0;
jmethodID _hide_keyboard = 0;
jmethodID _set_screen_orientation = 0;
+ jmethodID _get_screen_orientation = 0;
jmethodID _get_system_dir = 0;
- jmethodID _play_video = 0;
- jmethodID _is_video_playing = 0;
- jmethodID _pause_video = 0;
- jmethodID _stop_video = 0;
public:
GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instance);
@@ -78,11 +75,8 @@ public:
int get_vk_height();
void set_vk_height(int p_height);
void set_screen_orientation(int p_orient);
+ int get_screen_orientation();
String get_system_dir(int p_dir);
- void play_video(const String &p_path);
- bool is_video_playing();
- void pause_video();
- void stop_video();
};
#endif /* !JAVA_GODOT_IO_WRAPPER_H */
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 0b1d070441..8b38113e09 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -29,31 +29,36 @@
/*************************************************************************/
#include "java_godot_lib_jni.h"
+
#include "java_godot_io_wrapper.h"
#include "java_godot_wrapper.h"
#include "android/asset_manager_jni.h"
-#include "android_keys_utils.h"
#include "api/java_class_wrapper.h"
+#include "api/jni_singleton.h"
#include "audio_driver_jandroid.h"
#include "core/engine.h"
+#include "core/input/input_filter.h"
#include "core/project_settings.h"
#include "dir_access_jandroid.h"
+#include "display_server_android.h"
#include "file_access_android.h"
#include "file_access_jandroid.h"
#include "jni_utils.h"
-#include "main/input_default.h"
#include "main/main.h"
#include "net_socket_android.h"
#include "os_android.h"
#include "string_android.h"
#include "thread_jandroid.h"
+
#include <unistd.h>
-static JavaClassWrapper *java_class_wrapper = NULL;
-static OS_Android *os_android = NULL;
-static GodotJavaWrapper *godot_java = NULL;
-static GodotIOJavaWrapper *godot_io_java = NULL;
+#include <android/native_window_jni.h>
+
+static JavaClassWrapper *java_class_wrapper = nullptr;
+static OS_Android *os_android = nullptr;
+static GodotJavaWrapper *godot_java = nullptr;
+static GodotIOJavaWrapper *godot_io_java = nullptr;
static bool initialized = false;
static int step = 0;
@@ -121,14 +126,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) {
ThreadAndroid::setup_thread();
- const char **cmdline = NULL;
- jstring *j_cmdline = NULL;
+ const char **cmdline = nullptr;
+ jstring *j_cmdline = nullptr;
int cmdlen = 0;
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
cmdline = (const char **)malloc((cmdlen + 1) * sizeof(const char *));
- cmdline[cmdlen] = NULL;
+ cmdline[cmdlen] = nullptr;
j_cmdline = (jstring *)malloc(cmdlen * sizeof(jstring));
for (int i = 0; i < cmdlen; i++) {
@@ -158,22 +163,26 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
}
java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
+ ClassDB::register_class<JNISingleton>();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height) {
if (os_android)
- os_android->set_display_size(Size2(width, height));
+ os_android->set_display_size(Size2i(width, height));
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jboolean p_32_bits) {
-
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits) {
if (os_android) {
if (step == 0) {
// During startup
os_android->set_context_is_16_bits(!p_32_bits);
+ if (p_surface) {
+ ANativeWindow *native_window = ANativeWindow_fromSurface(env, p_surface);
+ os_android->set_native_window(native_window);
+ }
} else {
- // GL context recreated because it was lost; restart app to let it reload everything
+ // Rendering context recreated because it was lost; restart app to let it reload everything
os_android->main_loop_end();
godot_java->restart(env);
step = -1; // Ensure no further steps are attempted
@@ -193,7 +202,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
return;
if (step == 0) {
-
// Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id,
// but for Godot purposes, the main thread is the one running the game loop
Main::setup2(Thread::get_caller_id());
@@ -207,14 +215,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
}
os_android->main_loop_begin();
- godot_java->on_gl_godot_main_loop_started(env);
+ godot_java->on_godot_main_loop_started(env);
++step;
}
- os_android->process_accelerometer(accelerometer);
- os_android->process_gravity(gravity);
- os_android->process_magnetometer(magnetometer);
- os_android->process_gyroscope(gyroscope);
+ DisplayServerAndroid::get_singleton()->process_accelerometer(accelerometer);
+ DisplayServerAndroid::get_singleton()->process_gravity(gravity);
+ DisplayServerAndroid::get_singleton()->process_magnetometer(magnetometer);
+ DisplayServerAndroid::get_singleton()->process_gyroscope(gyroscope);
if (os_android->main_loop_iterate()) {
@@ -227,18 +235,18 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jc
if (step == 0)
return;
- Vector<OS_Android::TouchPos> points;
+ Vector<DisplayServerAndroid::TouchPos> points;
for (int i = 0; i < count; i++) {
jint p[3];
env->GetIntArrayRegion(positions, i * 3, 3, p);
- OS_Android::TouchPos tp;
+ DisplayServerAndroid::TouchPos tp;
tp.pos = Point2(p[1], p[2]);
tp.id = p[0];
points.push_back(tp);
}
- os_android->process_touch(ev, pointer, points);
+ DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
/*
if (os_android)
@@ -250,78 +258,78 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jc
if (step == 0)
return;
- os_android->process_hover(p_type, Point2(p_x, p_y));
+ DisplayServerAndroid::get_singleton()->process_hover(p_type, Point2(p_x, p_y));
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
if (step == 0)
return;
- os_android->process_double_tap(Point2(p_x, p_y));
+ DisplayServerAndroid::get_singleton()->process_double_tap(Point2(p_x, p_y));
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
if (step == 0)
return;
- os_android->process_scroll(Point2(p_x, p_y));
+ DisplayServerAndroid::get_singleton()->process_scroll(Point2(p_x, p_y));
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) {
if (step == 0)
return;
- OS_Android::JoypadEvent jevent;
+ DisplayServerAndroid::JoypadEvent jevent;
jevent.device = p_device;
- jevent.type = OS_Android::JOY_EVENT_BUTTON;
+ jevent.type = DisplayServerAndroid::JOY_EVENT_BUTTON;
jevent.index = p_button;
jevent.pressed = p_pressed;
- os_android->process_joy_event(jevent);
+ DisplayServerAndroid::get_singleton()->process_joy_event(jevent);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value) {
if (step == 0)
return;
- OS_Android::JoypadEvent jevent;
+ DisplayServerAndroid::JoypadEvent jevent;
jevent.device = p_device;
- jevent.type = OS_Android::JOY_EVENT_AXIS;
+ jevent.type = DisplayServerAndroid::JOY_EVENT_AXIS;
jevent.index = p_axis;
jevent.value = p_value;
- os_android->process_joy_event(jevent);
+ DisplayServerAndroid::get_singleton()->process_joy_event(jevent);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y) {
if (step == 0)
return;
- OS_Android::JoypadEvent jevent;
+ DisplayServerAndroid::JoypadEvent jevent;
jevent.device = p_device;
- jevent.type = OS_Android::JOY_EVENT_HAT;
+ jevent.type = DisplayServerAndroid::JOY_EVENT_HAT;
int hat = 0;
if (p_hat_x != 0) {
if (p_hat_x < 0)
- hat |= InputDefault::HAT_MASK_LEFT;
+ hat |= InputFilter::HAT_MASK_LEFT;
else
- hat |= InputDefault::HAT_MASK_RIGHT;
+ hat |= InputFilter::HAT_MASK_RIGHT;
}
if (p_hat_y != 0) {
if (p_hat_y < 0)
- hat |= InputDefault::HAT_MASK_UP;
+ hat |= InputFilter::HAT_MASK_UP;
else
- hat |= InputDefault::HAT_MASK_DOWN;
+ hat |= InputFilter::HAT_MASK_DOWN;
}
jevent.hat = hat;
- os_android->process_joy_event(jevent);
+ DisplayServerAndroid::get_singleton()->process_joy_event(jevent);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name) {
if (os_android) {
String name = jstring_to_string(p_name, env);
- os_android->joy_connection_changed(p_device, p_connected, name);
+ InputFilter::get_singleton()->joy_connection_changed(p_device, p_connected, name);
}
}
@@ -329,29 +337,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jcla
if (step == 0)
return;
- Ref<InputEventKey> ievent;
- ievent.instance();
- int val = p_unicode_char;
- int keycode = android_get_keysym(p_keycode);
- int phy_keycode = android_get_keysym(p_scancode);
- ievent->set_keycode(keycode);
- ievent->set_physical_keycode(phy_keycode);
- ievent->set_unicode(val);
- ievent->set_pressed(p_pressed);
-
- if (val == '\n') {
- ievent->set_keycode(KEY_ENTER);
- } else if (val == 61448) {
- ievent->set_keycode(KEY_BACKSPACE);
- ievent->set_unicode(KEY_BACKSPACE);
- } else if (val == 61453) {
- ievent->set_keycode(KEY_ENTER);
- ievent->set_unicode(KEY_ENTER);
- } else if (p_keycode == 4) {
- os_android->main_loop_request_go_back();
- }
-
- os_android->process_event(ievent);
+ DisplayServerAndroid::get_singleton()->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
@@ -428,7 +414,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
obj->call(str_method, (const Variant **)vptr, count, err);
// something
- env->PopLocalFrame(NULL);
+ env->PopLocalFrame(nullptr);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params) {
@@ -454,7 +440,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
obj->call_deferred(str_method, args[0], args[1], args[2], args[3], args[4]);
// something
- env->PopLocalFrame(NULL);
+ env->PopLocalFrame(nullptr);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index a7a5970440..221d701e2b 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -41,7 +41,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz, jobject activity);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jboolean p_32_bits);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions);
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 7b677c186e..8ef99dfab0 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -66,7 +66,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
_is_activity_resumed = p_env->GetMethodID(cls, "isActivityResumed", "()Z");
_vibrate = p_env->GetMethodID(cls, "vibrate", "(I)V");
_get_input_fallback_mapping = p_env->GetMethodID(cls, "getInputFallbackMapping", "()Ljava/lang/String;");
- _on_gl_godot_main_loop_started = p_env->GetMethodID(cls, "onGLGodotMainLoopStarted", "()V");
+ _on_godot_main_loop_started = p_env->GetMethodID(cls, "onGodotMainLoopStarted", "()V");
}
GodotJavaWrapper::~GodotJavaWrapper() {
@@ -80,13 +80,13 @@ jobject GodotJavaWrapper::get_activity() {
jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env) {
if (cls) {
- if (p_env == NULL)
+ if (p_env == nullptr)
p_env = ThreadAndroid::get_env();
jfieldID fid = p_env->GetStaticFieldID(cls, p_name, p_class);
return p_env->GetStaticObjectField(cls, fid);
} else {
- return NULL;
+ return nullptr;
}
}
@@ -96,30 +96,30 @@ jobject GodotJavaWrapper::get_class_loader() {
jmethodID getClassLoader = env->GetMethodID(cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
return env->CallObjectMethod(godot_instance, getClassLoader);
} else {
- return NULL;
+ return nullptr;
}
}
void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
if (_on_video_init)
- if (p_env == NULL)
+ if (p_env == nullptr)
p_env = ThreadAndroid::get_env();
p_env->CallVoidMethod(godot_instance, _on_video_init);
}
-void GodotJavaWrapper::on_gl_godot_main_loop_started(JNIEnv *p_env) {
- if (_on_gl_godot_main_loop_started) {
- if (p_env == NULL) {
+void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) {
+ if (_on_godot_main_loop_started) {
+ if (p_env == nullptr) {
p_env = ThreadAndroid::get_env();
}
}
- p_env->CallVoidMethod(godot_instance, _on_gl_godot_main_loop_started);
+ p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started);
}
void GodotJavaWrapper::restart(JNIEnv *p_env) {
if (_restart)
- if (p_env == NULL)
+ if (p_env == nullptr)
p_env = ThreadAndroid::get_env();
p_env->CallVoidMethod(godot_instance, _restart);
@@ -127,7 +127,7 @@ void GodotJavaWrapper::restart(JNIEnv *p_env) {
void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
if (_finish)
- if (p_env == NULL)
+ if (p_env == nullptr)
p_env = ThreadAndroid::get_env();
p_env->CallVoidMethod(godot_instance, _finish);
@@ -244,7 +244,7 @@ jobject GodotJavaWrapper::get_surface() {
JNIEnv *env = ThreadAndroid::get_env();
return env->CallObjectMethod(godot_instance, _get_surface);
} else {
- return NULL;
+ return nullptr;
}
}
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index cdab2ecc9c..89d6b6db46 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -61,21 +61,21 @@ private:
jmethodID _is_activity_resumed = 0;
jmethodID _vibrate = 0;
jmethodID _get_input_fallback_mapping = 0;
- jmethodID _on_gl_godot_main_loop_started = 0;
+ jmethodID _on_godot_main_loop_started = 0;
public:
GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
~GodotJavaWrapper();
jobject get_activity();
- jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = NULL);
+ jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = nullptr);
jobject get_class_loader();
- void on_video_init(JNIEnv *p_env = NULL);
- void on_gl_godot_main_loop_started(JNIEnv *p_env = NULL);
- void restart(JNIEnv *p_env = NULL);
- void force_quit(JNIEnv *p_env = NULL);
+ void on_video_init(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);
void set_keep_screen_on(bool p_enabled);
void alert(const String &p_message, const String &p_title);
int get_gles_version_code();
diff --git a/platform/android/jni_utils.cpp b/platform/android/jni_utils.cpp
index 3fa4e80884..ded79a668f 100644
--- a/platform/android/jni_utils.cpp
+++ b/platform/android/jni_utils.cpp
@@ -130,7 +130,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
env->CallVoidMethodA(jdict, set_keys, &val);
env->DeleteLocalRef(jkeys);
- jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
+ jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), nullptr);
for (int j = 0; j < keys.size(); j++) {
Variant var = dict[keys[j]];
@@ -211,7 +211,7 @@ String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
- if (obj == NULL) {
+ if (obj == nullptr) {
return Variant();
}
@@ -384,7 +384,7 @@ Variant::Type get_jni_type(const String &p_type) {
{ "[F", Variant::PACKED_FLOAT32_ARRAY },
{ "[Ljava.lang.String;", Variant::PACKED_STRING_ARRAY },
{ "org.godotengine.godot.Dictionary", Variant::DICTIONARY },
- { NULL, Variant::NIL }
+ { nullptr, Variant::NIL }
};
int idx = 0;
@@ -417,7 +417,7 @@ const char *get_jni_sig(const String &p_type) {
{ "[B", "[B" },
{ "[F", "[F" },
{ "[Ljava.lang.String;", "[Ljava/lang/String;" },
- { NULL, "V" }
+ { nullptr, "V" }
};
int idx = 0;
diff --git a/platform/android/jni_utils.h b/platform/android/jni_utils.h
index 925340a680..c2baa51b4a 100644
--- a/platform/android/jni_utils.h
+++ b/platform/android/jni_utils.h
@@ -40,7 +40,7 @@ struct jvalret {
jobject obj;
jvalue val;
- jvalret() { obj = NULL; }
+ jvalret() { obj = nullptr; }
};
jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_arg, bool force_jobject = false);
@@ -53,190 +53,4 @@ Variant::Type get_jni_type(const String &p_type);
const char *get_jni_sig(const String &p_type);
-class JNISingleton : public Object {
-
- GDCLASS(JNISingleton, Object);
-
- struct MethodData {
-
- jmethodID method;
- Variant::Type ret_type;
- Vector<Variant::Type> argtypes;
- };
-
- jobject instance;
- Map<StringName, MethodData> method_map;
-
-public:
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-
- ERR_FAIL_COND_V(!instance, Variant());
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Map<StringName, MethodData>::Element *E = method_map.find(p_method);
- if (!E) {
-
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
- int ac = E->get().argtypes.size();
- if (ac < p_argcount) {
-
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- if (ac > p_argcount) {
-
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- for (int i = 0; i < p_argcount; i++) {
-
- if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
-
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = i;
- r_error.expected = E->get().argtypes[i];
- }
- }
-
- jvalue *v = NULL;
-
- if (p_argcount) {
-
- v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
- }
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- int res = env->PushLocalFrame(16);
-
- ERR_FAIL_COND_V(res != 0, Variant());
-
- List<jobject> to_erase;
- for (int i = 0; i < p_argcount; i++) {
-
- jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
- v[i] = vr.val;
- if (vr.obj)
- to_erase.push_back(vr.obj);
- }
-
- Variant ret;
-
- switch (E->get().ret_type) {
-
- case Variant::NIL: {
-
- env->CallVoidMethodA(instance, E->get().method, v);
- } break;
- case Variant::BOOL: {
-
- ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
- } break;
- case Variant::INT: {
-
- ret = env->CallIntMethodA(instance, E->get().method, v);
- } break;
- case Variant::FLOAT: {
-
- ret = env->CallFloatMethodA(instance, E->get().method, v);
- } break;
- case Variant::STRING: {
-
- jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- ret = jstring_to_string((jstring)o, env);
- env->DeleteLocalRef(o);
- } break;
- case Variant::PACKED_STRING_ARRAY: {
-
- jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- ret = _jobject_to_variant(env, arr);
-
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_INT32_ARRAY: {
-
- jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<int> sarr;
- sarr.resize(fCount);
-
- int *w = sarr.ptrw();
- env->GetIntArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
-
- jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- Vector<float> sarr;
- sarr.resize(fCount);
-
- float *w = sarr.ptrw();
- env->GetFloatArrayRegion(arr, 0, fCount, w);
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
-
-#ifndef _MSC_VER
-#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
-#endif
- case Variant::DICTIONARY: {
-
- jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
- ret = _jobject_to_variant(env, obj);
- env->DeleteLocalRef(obj);
-
- } break;
- default: {
-
- env->PopLocalFrame(NULL);
- ERR_FAIL_V(Variant());
- } break;
- }
-
- while (to_erase.size()) {
- env->DeleteLocalRef(to_erase.front()->get());
- to_erase.pop_front();
- }
-
- env->PopLocalFrame(NULL);
-
- return ret;
- }
-
- jobject get_instance() const {
-
- return instance;
- }
- void set_instance(jobject p_instance) {
-
- instance = p_instance;
- }
-
- void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
-
- MethodData md;
- md.method = p_method;
- md.argtypes = p_args;
- md.ret_type = p_ret_type;
- method_map[p_name] = md;
- }
-
- JNISingleton() {
- instance = NULL;
- }
-};
-
#endif // JNI_UTILS_H
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 7e2b0d948e..760157595c 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -32,15 +32,11 @@
#include "core/io/file_access_buffered_fa.h"
#include "core/project_settings.h"
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
#include "file_access_android.h"
#include "main/main.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
+#include "platform/android/display_server_android.h"
#include "dir_access_jandroid.h"
#include "file_access_jandroid.h"
@@ -60,29 +56,6 @@ public:
virtual ~AndroidLogger() {}
};
-int OS_Android::get_video_driver_count() const {
-
- return 2;
-}
-
-const char *OS_Android::get_video_driver_name(int p_driver) const {
-
- switch (p_driver) {
- case VIDEO_DRIVER_GLES2:
- return "GLES2";
- }
- ERR_FAIL_V_MSG(NULL, "Invalid video driver index: " + itos(p_driver) + ".");
-}
-int OS_Android::get_audio_driver_count() const {
-
- return 1;
-}
-
-const char *OS_Android::get_audio_driver_name(int p_driver) const {
-
- return "Android";
-}
-
void OS_Android::initialize_core() {
OS_Unix::initialize_core();
@@ -91,7 +64,7 @@ void OS_Android::initialize_core() {
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
else {
#ifdef USE_JAVA_FILE_ACCESS
- FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid> >(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid>>(FileAccess::ACCESS_RESOURCES);
#else
//FileAccess::make_default<FileAccessBufferedFA<FileAccessAndroid> >(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
@@ -110,71 +83,33 @@ void OS_Android::initialize_core() {
NetSocketAndroid::make_default();
}
-void OS_Android::set_opengl_extensions(const char *p_gl_extensions) {
-
- ERR_FAIL_COND(!p_gl_extensions);
- gl_extensions = p_gl_extensions;
-}
-
-int OS_Android::get_current_video_driver() const {
- return video_driver_index;
+void OS_Android::initialize() {
+ initialize_core();
}
-Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
+void OS_Android::initialize_joypads() {
+ InputFilter::get_singleton()->set_fallback_mapping(godot_java->get_input_fallback_mapping());
- // FIXME: Add Vulkan support. Readd fallback code from Vulkan to GLES2?
-
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- bool gl_initialization_error = false;
-
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- } else {
- gl_initialization_error = true;
- }
-
- if (gl_initialization_error) {
- OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n"
- "Please try updating your Android version.",
- "Unable to initialize video driver");
- return ERR_UNAVAILABLE;
- }
- }
-#endif
-
- video_driver_index = p_video_driver;
-
- visual_server = memnew(VisualServerRaster);
- if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, false));
- }
-
- visual_server->init();
-
- AudioDriverManager::initialize(p_audio_driver);
-
- input = memnew(InputDefault);
- input->set_fallback_mapping(godot_java->get_input_fallback_mapping());
-
- return OK;
+ // This queries/updates the currently connected devices/joypads.
+ godot_java->init_input_devices();
}
void OS_Android::set_main_loop(MainLoop *p_main_loop) {
-
main_loop = p_main_loop;
- input->set_main_loop(p_main_loop);
}
void OS_Android::delete_main_loop() {
-
- memdelete(main_loop);
+ if (main_loop) {
+ memdelete(main_loop);
+ main_loop = nullptr;
+ }
}
void OS_Android::finalize() {
+}
- memdelete(input);
+OS_Android *OS_Android::get_singleton() {
+ return (OS_Android *)OS::get_singleton();
}
GodotJavaWrapper *OS_Android::get_godot_java() {
@@ -185,12 +120,6 @@ GodotIOJavaWrapper *OS_Android::get_godot_io_java() {
return godot_io_java;
}
-void OS_Android::alert(const String &p_alert, const String &p_title) {
-
- //print("ALERT: %s\n", p_alert.utf8().get_data());
- godot_java->alert(p_alert, p_title);
-}
-
bool OS_Android::request_permission(const String &p_name) {
return godot_java->request_permission(p_name);
@@ -212,63 +141,6 @@ Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_han
return OK;
}
-void OS_Android::set_mouse_show(bool p_show) {
-
- //android has no mouse...
-}
-
-void OS_Android::set_mouse_grab(bool p_grab) {
-
- //it really has no mouse...!
-}
-
-bool OS_Android::is_mouse_grab_enabled() const {
-
- //*sigh* technology has evolved so much since i was a kid..
- return false;
-}
-
-Point2 OS_Android::get_mouse_position() const {
-
- return Point2();
-}
-
-int OS_Android::get_mouse_button_state() const {
-
- return 0;
-}
-
-void OS_Android::set_window_title(const String &p_title) {
- //This queries/updates the currently connected devices/joypads
- //Set_window_title is called when initializing the main loop (main.cpp)
- //therefore this place is found to be suitable (I found no better).
- godot_java->init_input_devices();
-}
-
-void OS_Android::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
-}
-
-OS::VideoMode OS_Android::get_video_mode(int p_screen) const {
-
- return default_videomode;
-}
-
-void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
-
- p_list->push_back(default_videomode);
-}
-
-void OS_Android::set_keep_screen_on(bool p_enabled) {
- OS::set_keep_screen_on(p_enabled);
-
- godot_java->set_keep_screen_on(p_enabled);
-}
-
-Size2 OS_Android::get_window_size() const {
-
- return Vector2(default_videomode.width, default_videomode.height);
-}
-
String OS_Android::get_name() const {
return "Android";
@@ -279,11 +151,6 @@ MainLoop *OS_Android::get_main_loop() const {
return main_loop;
}
-bool OS_Android::can_draw() const {
-
- return true; //always?
-}
-
void OS_Android::main_loop_begin() {
if (main_loop)
@@ -304,277 +171,17 @@ void OS_Android::main_loop_end() {
}
void OS_Android::main_loop_focusout() {
-
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+ DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
audio_driver_android.set_pause(true);
}
void OS_Android::main_loop_focusin() {
-
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+ DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN);
audio_driver_android.set_pause(false);
}
-void OS_Android::process_joy_event(OS_Android::JoypadEvent p_event) {
-
- switch (p_event.type) {
- case JOY_EVENT_BUTTON:
- input->joy_button(p_event.device, p_event.index, p_event.pressed);
- break;
- case JOY_EVENT_AXIS:
- InputDefault::JoyAxis value;
- value.min = -1;
- value.value = p_event.value;
- input->joy_axis(p_event.device, p_event.index, value);
- break;
- case JOY_EVENT_HAT:
- input->joy_hat(p_event.device, p_event.hat);
- break;
- default:
- return;
- }
-}
-
-void OS_Android::process_event(Ref<InputEvent> p_event) {
-
- input->parse_input_event(p_event);
-}
-
-void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points) {
-
- switch (p_what) {
- case 0: { //gesture begin
-
- if (touch.size()) {
- //end all if exist
- for (int i = 0; i < touch.size(); i++) {
-
- Ref<InputEventScreenTouch> ev;
- ev.instance();
- ev->set_index(touch[i].id);
- ev->set_pressed(false);
- ev->set_position(touch[i].pos);
- input->parse_input_event(ev);
- }
- }
-
- touch.resize(p_points.size());
- for (int i = 0; i < p_points.size(); i++) {
- touch.write[i].id = p_points[i].id;
- touch.write[i].pos = p_points[i].pos;
- }
-
- //send touch
- for (int i = 0; i < touch.size(); i++) {
-
- Ref<InputEventScreenTouch> ev;
- ev.instance();
- ev->set_index(touch[i].id);
- ev->set_pressed(true);
- ev->set_position(touch[i].pos);
- input->parse_input_event(ev);
- }
-
- } break;
- case 1: { //motion
-
- ERR_FAIL_COND(touch.size() != p_points.size());
-
- for (int i = 0; i < touch.size(); i++) {
-
- int idx = -1;
- for (int j = 0; j < p_points.size(); j++) {
-
- if (touch[i].id == p_points[j].id) {
- idx = j;
- break;
- }
- }
-
- ERR_CONTINUE(idx == -1);
-
- if (touch[i].pos == p_points[idx].pos)
- continue; //no move unncesearily
-
- Ref<InputEventScreenDrag> ev;
- ev.instance();
- ev->set_index(touch[i].id);
- ev->set_position(p_points[idx].pos);
- ev->set_relative(p_points[idx].pos - touch[i].pos);
- input->parse_input_event(ev);
- touch.write[i].pos = p_points[idx].pos;
- }
-
- } break;
- case 2: { //release
-
- if (touch.size()) {
- //end all if exist
- for (int i = 0; i < touch.size(); i++) {
-
- Ref<InputEventScreenTouch> ev;
- ev.instance();
- ev->set_index(touch[i].id);
- ev->set_pressed(false);
- ev->set_position(touch[i].pos);
- input->parse_input_event(ev);
- }
- touch.clear();
- }
- } break;
- case 3: { // add touch
-
- for (int i = 0; i < p_points.size(); i++) {
- if (p_points[i].id == p_pointer) {
- TouchPos tp = p_points[i];
- touch.push_back(tp);
-
- Ref<InputEventScreenTouch> ev;
- ev.instance();
-
- ev->set_index(tp.id);
- ev->set_pressed(true);
- ev->set_position(tp.pos);
- input->parse_input_event(ev);
-
- break;
- }
- }
- } break;
- case 4: { // remove touch
-
- for (int i = 0; i < touch.size(); i++) {
- if (touch[i].id == p_pointer) {
-
- Ref<InputEventScreenTouch> ev;
- ev.instance();
- ev->set_index(touch[i].id);
- ev->set_pressed(false);
- ev->set_position(touch[i].pos);
- input->parse_input_event(ev);
- touch.remove(i);
-
- break;
- }
- }
- } break;
- }
-}
-
-void OS_Android::process_hover(int p_type, Point2 p_pos) {
- // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
- switch (p_type) {
- case 7: // hover move
- case 9: // hover enter
- case 10: { // hover exit
- Ref<InputEventMouseMotion> ev;
- ev.instance();
- ev->set_position(p_pos);
- ev->set_global_position(p_pos);
- ev->set_relative(p_pos - hover_prev_pos);
- input->parse_input_event(ev);
- hover_prev_pos = p_pos;
- } break;
- }
-}
-
-void OS_Android::process_double_tap(Point2 p_pos) {
- Ref<InputEventMouseButton> ev;
- ev.instance();
- ev->set_position(p_pos);
- ev->set_global_position(p_pos);
- ev->set_pressed(false);
- ev->set_doubleclick(true);
- input->parse_input_event(ev);
-}
-
-void OS_Android::process_scroll(Point2 p_pos) {
- Ref<InputEventPanGesture> ev;
- ev.instance();
- ev->set_position(p_pos);
- ev->set_delta(p_pos - scroll_prev_pos);
- input->parse_input_event(ev);
- scroll_prev_pos = p_pos;
-}
-
-void OS_Android::process_accelerometer(const Vector3 &p_accelerometer) {
-
- input->set_accelerometer(p_accelerometer);
-}
-
-void OS_Android::process_gravity(const Vector3 &p_gravity) {
-
- input->set_gravity(p_gravity);
-}
-
-void OS_Android::process_magnetometer(const Vector3 &p_magnetometer) {
-
- input->set_magnetometer(p_magnetometer);
-}
-
-void OS_Android::process_gyroscope(const Vector3 &p_gyroscope) {
-
- input->set_gyroscope(p_gyroscope);
-}
-
-bool OS_Android::has_touchscreen_ui_hint() const {
-
- return true;
-}
-
-bool OS_Android::has_virtual_keyboard() const {
-
- return true;
-}
-
-int OS_Android::get_virtual_keyboard_height() const {
- return godot_io_java->get_vk_height();
-
- // ERR_PRINT("Cannot obtain virtual keyboard height.");
- // return 0;
-}
-
-void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) {
-
- if (godot_io_java->has_vk()) {
- godot_io_java->show_vk(p_existing_text, p_max_input_length);
- } else {
-
- ERR_PRINT("Virtual keyboard not available");
- };
-}
-
-void OS_Android::hide_virtual_keyboard() {
-
- if (godot_io_java->has_vk()) {
-
- godot_io_java->hide_vk();
- } else {
-
- ERR_PRINT("Virtual keyboard not available");
- };
-}
-
-void OS_Android::init_video_mode(int p_video_width, int p_video_height) {
-
- default_videomode.width = p_video_width;
- default_videomode.height = p_video_height;
- default_videomode.fullscreen = true;
- default_videomode.resizable = false;
-}
-
void OS_Android::main_loop_request_go_back() {
-
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST);
-}
-
-void OS_Android::set_display_size(Size2 p_size) {
-
- default_videomode.width = p_size.x;
- default_videomode.height = p_size.y;
+ DisplayServerAndroid::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST);
}
Error OS_Android::shell_open(String p_uri) {
@@ -597,26 +204,6 @@ String OS_Android::get_locale() const {
return OS_Unix::get_locale();
}
-void OS_Android::set_clipboard(const String &p_text) {
-
- // DO we really need the fallback to OS_Unix here?!
- if (godot_java->has_set_clipboard()) {
- godot_java->set_clipboard(p_text);
- } else {
- OS_Unix::set_clipboard(p_text);
- }
-}
-
-String OS_Android::get_clipboard() const {
-
- // DO we really need the fallback to OS_Unix here?!
- if (godot_java->has_get_clipboard()) {
- return godot_java->get_clipboard();
- }
-
- return OS_Unix::get_clipboard();
-}
-
String OS_Android::get_model_name() const {
String model = godot_io_java->get_model();
@@ -626,11 +213,6 @@ String OS_Android::get_model_name() const {
return OS_Unix::get_model_name();
}
-int OS_Android::get_screen_dpi(int p_screen) const {
-
- return godot_io_java->get_screen_dpi();
-}
-
String OS_Android::get_user_data_dir() const {
if (data_dir_cache != String())
@@ -662,11 +244,6 @@ String OS_Android::get_user_data_dir() const {
return ".";
}
-void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
-
- godot_io_java->set_screen_orientation(p_orientation);
-}
-
String OS_Android::get_unique_id() const {
String unique_id = godot_io_java->get_unique_id();
@@ -676,50 +253,46 @@ String OS_Android::get_unique_id() const {
return OS::get_unique_id();
}
-Error OS_Android::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
- // FIXME: Add support for volume, audio and subtitle tracks
-
- godot_io_java->play_video(p_path);
- return OK;
-}
-
-bool OS_Android::native_video_is_playing() const {
-
- return godot_io_java->is_video_playing();
-}
-
-void OS_Android::native_video_pause() {
-
- godot_io_java->pause_video();
-}
-
String OS_Android::get_system_dir(SystemDir p_dir) const {
return godot_io_java->get_system_dir(p_dir);
}
-void OS_Android::native_video_stop() {
+void OS_Android::set_display_size(const Size2i &p_size) {
+ display_size = p_size;
+}
- godot_io_java->stop_video();
+Size2i OS_Android::get_display_size() const {
+ return display_size;
}
void OS_Android::set_context_is_16_bits(bool p_is_16) {
-
+#if defined(OPENGL_ENABLED)
//use_16bits_fbo = p_is_16;
//if (rasterizer)
// rasterizer->set_force_16_bits_fbo(p_is_16);
+#endif
}
-void OS_Android::joy_connection_changed(int p_device, bool p_connected, String p_name) {
- return input->joy_connection_changed(p_device, p_connected, p_name, "");
+void OS_Android::set_opengl_extensions(const char *p_gl_extensions) {
+#if defined(OPENGL_ENABLED)
+ ERR_FAIL_COND(!p_gl_extensions);
+ gl_extensions = p_gl_extensions;
+#endif
}
-bool OS_Android::is_joy_known(int p_device) {
- return input->is_joy_mapped(p_device);
+void OS_Android::set_native_window(ANativeWindow *p_native_window) {
+#if defined(VULKAN_ENABLED)
+ native_window = p_native_window;
+#endif
}
-String OS_Android::get_joy_guid(int p_device) const {
- return input->get_joy_guid_remapped(p_device);
+ANativeWindow *OS_Android::get_native_window() const {
+#if defined(VULKAN_ENABLED)
+ return native_window;
+#else
+ return nullptr;
+#endif
}
void OS_Android::vibrate_handheld(int p_duration_ms) {
@@ -747,19 +320,21 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) {
}
OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion) {
+ display_size.width = 800;
+ display_size.height = 600;
use_apk_expansion = p_use_apk_expansion;
- default_videomode.width = 800;
- default_videomode.height = 600;
- default_videomode.fullscreen = true;
- default_videomode.resizable = false;
-
- main_loop = NULL;
- gl_extensions = NULL;
- //rasterizer = NULL;
+
+ main_loop = nullptr;
+
+#if defined(OPENGL_ENABLED)
+ gl_extensions = nullptr;
use_gl2 = false;
+#endif
- visual_server = NULL;
+#if defined(VULKAN_ENABLED)
+ native_window = nullptr;
+#endif
godot_java = p_godot_java;
godot_io_java = p_godot_io_java;
@@ -769,6 +344,8 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god
_set_logger(memnew(CompositeLogger(loggers)));
AudioDriverManager::add_driver(&audio_driver_android);
+
+ DisplayServerAndroid::register_android_driver();
}
OS_Android::~OS_Android() {
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index ec6ffe5438..cac7efaa88 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -33,79 +33,45 @@
#include "audio_driver_jandroid.h"
#include "audio_driver_opensl.h"
-#include "core/os/input.h"
#include "core/os/main_loop.h"
#include "drivers/unix/os_unix.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
class GodotJavaWrapper;
class GodotIOJavaWrapper;
-class OS_Android : public OS_Unix {
-public:
- struct TouchPos {
- int id;
- Point2 pos;
- };
-
- enum {
- JOY_EVENT_BUTTON = 0,
- JOY_EVENT_AXIS = 1,
- JOY_EVENT_HAT = 2
- };
-
- struct JoypadEvent {
-
- int device;
- int type;
- int index;
- bool pressed;
- float value;
- int hat;
- };
+struct ANativeWindow;
+class OS_Android : public OS_Unix {
private:
- Vector<TouchPos> touch;
- Point2 hover_prev_pos; // needed to calculate the relative position on hover events
- Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events
+ Size2i display_size;
- bool use_gl2;
bool use_apk_expansion;
+#if defined(OPENGL_ENABLED)
bool use_16bits_fbo;
+ const char *gl_extensions;
+#endif
- VisualServer *visual_server;
+#if defined(VULKAN_ENABLED)
+ ANativeWindow *native_window;
+#endif
mutable String data_dir_cache;
//AudioDriverAndroid audio_driver_android;
AudioDriverOpenSL audio_driver_android;
- const char *gl_extensions;
-
- InputDefault *input;
- VideoMode default_videomode;
MainLoop *main_loop;
GodotJavaWrapper *godot_java;
GodotIOJavaWrapper *godot_io_java;
- int video_driver_index;
-
public:
- // functions used by main to initialize/deinitialize the OS
- virtual int get_video_driver_count() const;
- virtual const char *get_video_driver_name(int p_driver) const;
-
- virtual int get_audio_driver_count() const;
- virtual const char *get_audio_driver_name(int p_driver) const;
-
- virtual int get_current_video_driver() const;
-
virtual void initialize_core();
- virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
+ virtual void initialize();
+
+ virtual void initialize_joypads();
virtual void set_main_loop(MainLoop *p_main_loop);
virtual void delete_main_loop();
@@ -114,37 +80,19 @@ public:
typedef int64_t ProcessID;
- static OS *get_singleton();
+ static OS_Android *get_singleton();
GodotJavaWrapper *get_godot_java();
GodotIOJavaWrapper *get_godot_io_java();
- virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual bool request_permission(const String &p_name);
virtual bool request_permissions();
virtual Vector<String> get_granted_permissions() const;
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
- virtual void set_mouse_show(bool p_show);
- virtual void set_mouse_grab(bool p_grab);
- virtual bool is_mouse_grab_enabled() const;
- virtual Point2 get_mouse_position() const;
- virtual int get_mouse_button_state() const;
- virtual void set_window_title(const String &p_title);
-
- virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
- virtual VideoMode get_video_mode(int p_screen = 0) const;
- virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
-
- virtual void set_keep_screen_on(bool p_enabled);
-
- virtual Size2 get_window_size() const;
-
virtual String get_name() const;
virtual MainLoop *get_main_loop() const;
- virtual bool can_draw() const;
-
void main_loop_begin();
bool main_loop_iterate();
void main_loop_request_go_back();
@@ -152,53 +100,25 @@ public:
void main_loop_focusout();
void main_loop_focusin();
- virtual bool has_touchscreen_ui_hint() const;
-
- virtual bool has_virtual_keyboard() const;
- virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1);
- virtual void hide_virtual_keyboard();
- virtual int get_virtual_keyboard_height() const;
-
- void set_opengl_extensions(const char *p_gl_extensions);
- void set_display_size(Size2 p_size);
+ void set_display_size(const Size2i &p_size);
+ Size2i get_display_size() const;
void set_context_is_16_bits(bool p_is_16);
+ void set_opengl_extensions(const char *p_gl_extensions);
- virtual void set_screen_orientation(ScreenOrientation p_orientation);
+ void set_native_window(ANativeWindow *p_native_window);
+ ANativeWindow *get_native_window() const;
virtual Error shell_open(String p_uri);
virtual String get_user_data_dir() const;
virtual String get_resource_dir() const;
virtual String get_locale() const;
- virtual void set_clipboard(const String &p_text);
- virtual String get_clipboard() const;
virtual String get_model_name() const;
- virtual int get_screen_dpi(int p_screen = 0) const;
virtual String get_unique_id() const;
virtual String get_system_dir(SystemDir p_dir) const;
- void process_accelerometer(const Vector3 &p_accelerometer);
- void process_gravity(const Vector3 &p_gravity);
- void process_magnetometer(const Vector3 &p_magnetometer);
- void process_gyroscope(const Vector3 &p_gyroscope);
- void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points);
- void process_hover(int p_type, Point2 p_pos);
- void process_double_tap(Point2 p_pos);
- void process_scroll(Point2 p_pos);
- void process_joy_event(JoypadEvent p_event);
- void process_event(Ref<InputEvent> p_event);
- void init_video_mode(int p_video_width, int p_video_height);
-
- virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track);
- virtual bool native_video_is_playing() const;
- virtual void native_video_pause();
- virtual void native_video_stop();
-
- virtual bool is_joy_known(int p_device);
- virtual String get_joy_guid(int p_device) const;
- void joy_connection_changed(int p_device, bool p_connected, String p_name);
void vibrate_handheld(int p_duration_ms);
virtual bool _check_internal_feature_support(const String &p_feature);
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 7413236e5d..c3bfb2f2ed 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -33,6 +33,7 @@
#include <core/engine.h>
#include <core/error_macros.h>
#include <core/project_settings.h>
+#include <platform/android/api/jni_singleton.h>
#include <platform/android/jni_utils.h>
#include <platform/android/string_android.h>
@@ -43,7 +44,7 @@ extern "C" {
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name) {
String singname = jstring_to_string(name, env);
- JNISingleton *s = memnew(JNISingleton);
+ JNISingleton *s = (JNISingleton *)ClassDB::instance("JNISingleton");
s->set_instance(env->NewGlobalRef(obj));
jni_singletons[singname] = s;
@@ -86,6 +87,51 @@ 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) {
+ String singleton_name = jstring_to_string(j_plugin_name, env);
+
+ ERR_FAIL_COND(!jni_singletons.has(singleton_name));
+
+ JNISingleton *singleton = jni_singletons.get(singleton_name);
+
+ String signal_name = jstring_to_string(j_signal_name, env);
+ Vector<Variant::Type> types;
+
+ int stringCount = env->GetArrayLength(j_signal_param_types);
+
+ for (int i = 0; i < stringCount; i++) {
+
+ jstring j_signal_param_type = (jstring)env->GetObjectArrayElement(j_signal_param_types, i);
+ const String signal_param_type = jstring_to_string(j_signal_param_type, env);
+ types.push_back(get_jni_type(signal_param_type));
+ }
+
+ 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) {
+ String singleton_name = jstring_to_string(j_plugin_name, env);
+
+ ERR_FAIL_COND(!jni_singletons.has(singleton_name));
+
+ JNISingleton *singleton = jni_singletons.get(singleton_name);
+
+ String signal_name = jstring_to_string(j_signal_name, env);
+
+ int count = env->GetArrayLength(j_signal_params);
+ const Variant *args[count];
+
+ for (int i = 0; i < count; i++) {
+
+ jobject j_param = env->GetObjectArrayElement(j_signal_params, i);
+ Variant variant = _jobject_to_variant(env, j_param);
+ args[i] = &variant;
+ env->DeleteLocalRef(j_param);
+ };
+
+ singleton->emit_signal(signal_name, args, count);
+}
+
JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths) {
int gdnlib_count = env->GetArrayLength(gdnlib_paths);
if (gdnlib_count == 0) {
diff --git a/platform/android/plugin/godot_plugin_jni.h b/platform/android/plugin/godot_plugin_jni.h
index 0d613d3bfe..80ce332e7c 100644
--- a/platform/android/plugin/godot_plugin_jni.h
+++ b/platform/android/plugin/godot_plugin_jni.h
@@ -37,6 +37,8 @@
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);
}
diff --git a/platform/android/string_android.h b/platform/android/string_android.h
index 51c488c8cc..88ccd3b652 100644
--- a/platform/android/string_android.h
+++ b/platform/android/string_android.h
@@ -40,13 +40,13 @@
* @param env JNI environment instance. If null obtained by ThreadAndroid::get_env().
* @return Godot string instance.
*/
-static inline String jstring_to_string(jstring source, JNIEnv *env = NULL) {
+static inline String jstring_to_string(jstring source, JNIEnv *env = nullptr) {
String result;
if (source) {
if (!env) {
env = ThreadAndroid::get_env();
}
- const char *const source_utf8 = env->GetStringUTFChars(source, NULL);
+ const char *const source_utf8 = env->GetStringUTFChars(source, nullptr);
if (source_utf8) {
result.parse_utf8(source_utf8);
env->ReleaseStringUTFChars(source, source_utf8);
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index 98b61ad755..729327f6f0 100644
--- a/platform/android/thread_jandroid.cpp
+++ b/platform/android/thread_jandroid.cpp
@@ -66,7 +66,7 @@ void *ThreadAndroid::thread_callback(void *userdata) {
pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id)));
t->callback(t->user);
ScriptServer::thread_exit();
- return NULL;
+ return nullptr;
}
Thread *ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
@@ -100,7 +100,7 @@ void ThreadAndroid::wait_to_finish_func_jandroid(Thread *p_thread) {
ERR_FAIL_COND(!tp);
ERR_FAIL_COND(tp->pthread == 0);
- pthread_join(tp->pthread, NULL);
+ pthread_join(tp->pthread, nullptr);
tp->pthread = 0;
}
@@ -108,21 +108,21 @@ void ThreadAndroid::_thread_destroyed(void *value) {
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
JNIEnv *env = (JNIEnv *)value;
- if (env != NULL) {
+ if (env != nullptr) {
java_vm->DetachCurrentThread();
- pthread_setspecific(jvm_key, NULL);
+ pthread_setspecific(jvm_key, nullptr);
}
}
pthread_key_t ThreadAndroid::jvm_key;
-JavaVM *ThreadAndroid::java_vm = NULL;
+JavaVM *ThreadAndroid::java_vm = nullptr;
void ThreadAndroid::setup_thread() {
if (pthread_getspecific(jvm_key))
return; //already setup
JNIEnv *env;
- java_vm->AttachCurrentThread(&env, NULL);
+ java_vm->AttachCurrentThread(&env, nullptr);
pthread_setspecific(jvm_key, (void *)env);
}
@@ -142,8 +142,8 @@ JNIEnv *ThreadAndroid::get_env() {
setup_thread();
}
- JNIEnv *env = NULL;
- java_vm->AttachCurrentThread(&env, NULL);
+ JNIEnv *env = nullptr;
+ java_vm->AttachCurrentThread(&env, nullptr);
return env;
}
diff --git a/platform/android/vulkan/vk_renderer_jni.cpp b/platform/android/vulkan/vk_renderer_jni.cpp
deleted file mode 100644
index 3026e7daad..0000000000
--- a/platform/android/vulkan/vk_renderer_jni.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*************************************************************************/
-/* vk_renderer_jni.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "vk_renderer_jni.h"
-
-extern "C" {
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceCreated(JNIEnv *env, jobject obj, jobject j_surface) {
- // TODO: complete
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceChanged(JNIEnv *env, jobject object, jobject j_surface, jint width, jint height) {
- // TODO: complete
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkResume(JNIEnv *env, jobject obj) {
- // TODO: complete
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDrawFrame(JNIEnv *env, jobject obj) {
- // TODO: complete
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkPause(JNIEnv *env, jobject obj) {
- // TODO: complete
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDestroy(JNIEnv *env, jobject obj) {
- // TODO: complete
-}
-}
diff --git a/platform/android/vulkan/vk_renderer_jni.h b/platform/android/vulkan/vk_renderer_jni.h
deleted file mode 100644
index 017766fea2..0000000000
--- a/platform/android/vulkan/vk_renderer_jni.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*************************************************************************/
-/* vk_renderer_jni.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VK_RENDERER_JNI_H
-#define VK_RENDERER_JNI_H
-
-#include <android/log.h>
-#include <jni.h>
-
-extern "C" {
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceCreated(JNIEnv *env, jobject obj, jobject j_surface);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceChanged(JNIEnv *env, jobject object, jobject j_surface, jint width, jint height);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkResume(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDrawFrame(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkPause(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDestroy(JNIEnv *env, jobject obj);
-}
-
-#endif // VK_RENDERER_JNI_H
diff --git a/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp
new file mode 100644
index 0000000000..5fb7a83da4
--- /dev/null
+++ b/platform/android/vulkan/vulkan_context_android.cpp
@@ -0,0 +1,60 @@
+/*************************************************************************/
+/* vulkan_context_android.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "vulkan_context_android.h"
+#include <vulkan/vulkan_android.h>
+
+const char *VulkanContextAndroid::_get_platform_surface_extension() const {
+ return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
+}
+
+int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, int p_height) {
+ VkAndroidSurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.window = p_window;
+
+ VkSurfaceKHR surface;
+ VkResult err = vkCreateAndroidSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
+ if (err != VK_SUCCESS) {
+ ERR_FAIL_V_MSG(-1, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
+ }
+
+ return _window_create(DisplayServer::MAIN_WINDOW_ID, surface, p_width, p_height);
+}
+
+VulkanContextAndroid::VulkanContextAndroid() {
+ // TODO: fix validation layers
+ use_validation_layers = false;
+}
+
+VulkanContextAndroid::~VulkanContextAndroid() {
+}
diff --git a/platform/android/vulkan/vulkan_context_android.h b/platform/android/vulkan/vulkan_context_android.h
new file mode 100644
index 0000000000..7e698ada4f
--- /dev/null
+++ b/platform/android/vulkan/vulkan_context_android.h
@@ -0,0 +1,49 @@
+/*************************************************************************/
+/* vulkan_context_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VULKAN_CONTEXT_ANDROID_H
+#define VULKAN_CONTEXT_ANDROID_H
+
+#include "drivers/vulkan/vulkan_context.h"
+
+struct ANativeWindow;
+
+class VulkanContextAndroid : public VulkanContext {
+
+ virtual const char *_get_platform_surface_extension() const;
+
+public:
+ int window_create(ANativeWindow *p_window, int p_width, int p_height);
+
+ VulkanContextAndroid();
+ ~VulkanContextAndroid();
+};
+
+#endif // VULKAN_CONTEXT_ANDROID_H
diff --git a/platform/haiku/SCsub b/platform/haiku/SCsub
index 592f56bbbf..dbff6c5ae9 100644
--- a/platform/haiku/SCsub
+++ b/platform/haiku/SCsub
@@ -1,28 +1,25 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
common_haiku = [
- 'os_haiku.cpp',
- 'context_gl_haiku.cpp',
- 'haiku_application.cpp',
- 'haiku_direct_window.cpp',
- 'haiku_gl_view.cpp',
- 'key_mapping_haiku.cpp',
- 'audio_driver_media_kit.cpp'
+ "os_haiku.cpp",
+ "context_gl_haiku.cpp",
+ "haiku_application.cpp",
+ "haiku_direct_window.cpp",
+ "haiku_gl_view.cpp",
+ "key_mapping_haiku.cpp",
+ "audio_driver_media_kit.cpp",
]
-target = env.add_program(
- '#bin/godot',
- ['godot_haiku.cpp'] + common_haiku
-)
+target = env.add_program("#bin/godot", ["godot_haiku.cpp"] + common_haiku)
-command = env.Command('#bin/godot.rsrc', '#platform/haiku/godot.rdef',
- ['rc -o $TARGET $SOURCE'])
+command = env.Command("#bin/godot.rsrc", "#platform/haiku/godot.rdef", ["rc -o $TARGET $SOURCE"])
def addResourcesAction(target=None, source=None, env=None):
- return env.Execute('xres -o ' + File(target)[0].path + ' bin/godot.rsrc')
+ return env.Execute("xres -o " + File(target)[0].path + " bin/godot.rsrc")
+
env.AddPostAction(target, addResourcesAction)
env.Depends(target, command)
diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp
index 0a5df14743..94c9e83368 100644
--- a/platform/haiku/audio_driver_media_kit.cpp
+++ b/platform/haiku/audio_driver_media_kit.cpp
@@ -34,7 +34,7 @@
#include "core/project_settings.h"
-int32_t *AudioDriverMediaKit::samples_in = NULL;
+int32_t *AudioDriverMediaKit::samples_in = nullptr;
Error AudioDriverMediaKit::init() {
active = false;
@@ -59,12 +59,12 @@ Error AudioDriverMediaKit::init() {
&format,
"godot_sound_server",
AudioDriverMediaKit::PlayBuffer,
- NULL,
+ nullptr,
this);
if (player->InitCheck() != B_OK) {
fprintf(stderr, "MediaKit ERR: can not create a BSoundPlayer instance\n");
- ERR_FAIL_COND_V(player == NULL, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V(player == nullptr, ERR_CANT_OPEN);
}
player->Start();
@@ -126,7 +126,7 @@ void AudioDriverMediaKit::finish() {
}
AudioDriverMediaKit::AudioDriverMediaKit() {
- player = NULL;
+ player = nullptr;
}
AudioDriverMediaKit::~AudioDriverMediaKit() {
diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py
index dd72294816..0b84df8f9b 100644
--- a/platform/haiku/detect.py
+++ b/platform/haiku/detect.py
@@ -12,7 +12,7 @@ def get_name():
def can_build():
- if (os.name != "posix" or sys.platform == "darwin"):
+ if os.name != "posix" or sys.platform == "darwin":
return False
return True
@@ -22,41 +22,40 @@ def get_opts():
from SCons.Variables import EnumVariable
return [
- EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
+ EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
]
def get_flags():
- return [
- ]
+ return []
def configure(env):
## Build type
- if (env["target"] == "release"):
- env.Prepend(CCFLAGS=['-O3'])
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
+ if env["target"] == "release":
+ env.Prepend(CCFLAGS=["-O3"])
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
- elif (env["target"] == "release_debug"):
- env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED'])
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
+ elif env["target"] == "release_debug":
+ env.Prepend(CCFLAGS=["-O2", "-DDEBUG_ENABLED"])
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
- elif (env["target"] == "debug"):
- env.Prepend(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ elif env["target"] == "debug":
+ env.Prepend(CCFLAGS=["-g3", "-DDEBUG_ENABLED", "-DDEBUG_MEMORY_ENABLED"])
## Architecture
- is64 = sys.maxsize > 2**32
- if (env["bits"] == "default"):
+ is64 = sys.maxsize > 2 ** 32
+ if env["bits"] == "default":
env["bits"] = "64" if is64 else "32"
## Compiler configuration
@@ -66,89 +65,94 @@ def configure(env):
## Dependencies
- if not env['builtin_libwebp']:
- env.ParseConfig('pkg-config libwebp --cflags --libs')
+ if not env["builtin_libwebp"]:
+ env.ParseConfig("pkg-config libwebp --cflags --libs")
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
- if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']:
- env['builtin_freetype'] = True
- env['builtin_libpng'] = True
- env['builtin_zlib'] = True
+ if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ env["builtin_freetype"] = True
+ env["builtin_libpng"] = True
+ env["builtin_zlib"] = True
- if not env['builtin_freetype']:
- env.ParseConfig('pkg-config freetype2 --cflags --libs')
+ if not env["builtin_freetype"]:
+ env.ParseConfig("pkg-config freetype2 --cflags --libs")
- if not env['builtin_libpng']:
- env.ParseConfig('pkg-config libpng16 --cflags --libs')
+ if not env["builtin_libpng"]:
+ env.ParseConfig("pkg-config libpng16 --cflags --libs")
- if not env['builtin_bullet']:
+ if not env["builtin_bullet"]:
# We need at least version 2.88
import subprocess
- bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
+
+ bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip()
if bullet_version < "2.88":
# Abort as system bullet was requested but too old
- print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88"))
+ print(
+ "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(
+ bullet_version, "2.88"
+ )
+ )
sys.exit(255)
- env.ParseConfig('pkg-config bullet --cflags --libs')
+ env.ParseConfig("pkg-config bullet --cflags --libs")
- if not env['builtin_enet']:
- env.ParseConfig('pkg-config libenet --cflags --libs')
+ if not env["builtin_enet"]:
+ env.ParseConfig("pkg-config libenet --cflags --libs")
- if not env['builtin_squish']:
- env.ParseConfig('pkg-config libsquish --cflags --libs')
+ if not env["builtin_squish"]:
+ env.ParseConfig("pkg-config libsquish --cflags --libs")
- if not env['builtin_zstd']:
- env.ParseConfig('pkg-config libzstd --cflags --libs')
+ if not env["builtin_zstd"]:
+ env.ParseConfig("pkg-config libzstd --cflags --libs")
# Sound and video libraries
# Keep the order as it triggers chained dependencies (ogg needed by others, etc.)
- if not env['builtin_libtheora']:
- env['builtin_libogg'] = False # Needed to link against system libtheora
- env['builtin_libvorbis'] = False # Needed to link against system libtheora
- env.ParseConfig('pkg-config theora theoradec --cflags --libs')
+ if not env["builtin_libtheora"]:
+ env["builtin_libogg"] = False # Needed to link against system libtheora
+ env["builtin_libvorbis"] = False # Needed to link against system libtheora
+ env.ParseConfig("pkg-config theora theoradec --cflags --libs")
- if not env['builtin_libvpx']:
- env.ParseConfig('pkg-config vpx --cflags --libs')
+ if not env["builtin_libvpx"]:
+ env.ParseConfig("pkg-config vpx --cflags --libs")
- if not env['builtin_libvorbis']:
- env['builtin_libogg'] = False # Needed to link against system libvorbis
- env.ParseConfig('pkg-config vorbis vorbisfile --cflags --libs')
+ if not env["builtin_libvorbis"]:
+ env["builtin_libogg"] = False # Needed to link against system libvorbis
+ env.ParseConfig("pkg-config vorbis vorbisfile --cflags --libs")
- if not env['builtin_opus']:
- env['builtin_libogg'] = False # Needed to link against system opus
- env.ParseConfig('pkg-config opus opusfile --cflags --libs')
+ if not env["builtin_opus"]:
+ env["builtin_libogg"] = False # Needed to link against system opus
+ env.ParseConfig("pkg-config opus opusfile --cflags --libs")
- if not env['builtin_libogg']:
- env.ParseConfig('pkg-config ogg --cflags --libs')
+ if not env["builtin_libogg"]:
+ env.ParseConfig("pkg-config ogg --cflags --libs")
- if env['builtin_libtheora']:
- list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
+ if env["builtin_libtheora"]:
+ list_of_x86 = ["x86_64", "x86", "i386", "i586"]
if any(platform.machine() in s for s in list_of_x86):
env["x86_libtheora_opt_gcc"] = True
- if not env['builtin_wslay']:
- env.ParseConfig('pkg-config libwslay --cflags --libs')
+ if not env["builtin_wslay"]:
+ env.ParseConfig("pkg-config libwslay --cflags --libs")
- if not env['builtin_mbedtls']:
+ if not env["builtin_mbedtls"]:
# mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
- env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
+ env.Append(LIBS=["mbedtls", "mbedcrypto", "mbedx509"])
- if not env['builtin_miniupnpc']:
+ if not env["builtin_miniupnpc"]:
# No pkgconfig file so far, hardcode default paths.
env.Prepend(CPPPATH=["/system/develop/headers/x86/miniupnpc"])
env.Append(LIBS=["miniupnpc"])
# On Linux wchar_t should be 32-bits
# 16-bit library shouldn't be required due to compiler optimisations
- if not env['builtin_pcre2']:
- env.ParseConfig('pkg-config libpcre2-32 --cflags --libs')
+ if not env["builtin_pcre2"]:
+ env.ParseConfig("pkg-config libpcre2-32 --cflags --libs")
## Flags
- env.Prepend(CPPPATH=['#platform/haiku'])
- env.Append(CPPDEFINES=['UNIX_ENABLED', 'OPENGL_ENABLED', 'GLES_ENABLED'])
- env.Append(CPPDEFINES=['MEDIA_KIT_ENABLED'])
- env.Append(CPPDEFINES=['PTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np
- env.Append(LIBS=['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL'])
+ env.Prepend(CPPPATH=["#platform/haiku"])
+ env.Append(CPPDEFINES=["UNIX_ENABLED", "OPENGL_ENABLED", "GLES_ENABLED"])
+ env.Append(CPPDEFINES=["MEDIA_KIT_ENABLED"])
+ env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"]) # TODO: enable when we have pthread_setname_np
+ env.Append(LIBS=["be", "game", "media", "network", "bnetapi", "z", "GL"])
diff --git a/platform/haiku/haiku_direct_window.cpp b/platform/haiku/haiku_direct_window.cpp
index 2d7efe6b61..0a40f847f4 100644
--- a/platform/haiku/haiku_direct_window.cpp
+++ b/platform/haiku/haiku_direct_window.cpp
@@ -42,10 +42,10 @@ HaikuDirectWindow::HaikuDirectWindow(BRect p_frame) :
last_button_mask = 0;
last_key_modifier_state = 0;
- view = NULL;
- update_runner = NULL;
- input = NULL;
- main_loop = NULL;
+ view = nullptr;
+ update_runner = nullptr;
+ input = nullptr;
+ main_loop = nullptr;
}
HaikuDirectWindow::~HaikuDirectWindow() {
@@ -74,7 +74,7 @@ void HaikuDirectWindow::SetMainLoop(MainLoop *p_main_loop) {
bool HaikuDirectWindow::QuitRequested() {
StopMessageRunner();
- main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ main_loop->notification(NOTIFICATION_WM_CLOSE_REQUEST);
return false;
}
@@ -278,7 +278,7 @@ void HaikuDirectWindow::HandleKeyboardEvent(BMessage *message) {
event->set_echo(message->HasInt32("be:key_repeat"));
event->set_unicode(0);
- const char *bytes = NULL;
+ const char *bytes = nullptr;
if (message->FindString("bytes", &bytes) == B_OK) {
event->set_unicode(BUnicodeChar::FromUTF8(&bytes));
}
diff --git a/platform/haiku/haiku_direct_window.h b/platform/haiku/haiku_direct_window.h
index ccc9542f0e..925bb9ac5d 100644
--- a/platform/haiku/haiku_direct_window.h
+++ b/platform/haiku/haiku_direct_window.h
@@ -35,8 +35,8 @@
#include <DirectWindow.h>
+#include "core/input/input_filter.h"
#include "core/os/os.h"
-#include "main/input_default.h"
#include "haiku_gl_view.h"
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index a082ba53f9..07cb18d7cd 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -32,9 +32,9 @@
#include "drivers/gles2/rasterizer_gles2.h"
#include "main/main.h"
-#include "servers/physics/physics_server_sw.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/physics_3d/physics_server_3d_sw.h"
+#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_wrap_mt.h"
#include <Screen.h>
@@ -85,7 +85,7 @@ int OS_Haiku::get_current_video_driver() const {
}
Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
- main_loop = NULL;
+ main_loop = nullptr;
current_video_mode = p_desired;
app = new HaikuApplication();
@@ -116,13 +116,13 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p
RasterizerGLES2::make_current();
#endif
- visual_server = memnew(VisualServerRaster);
+ rendering_server = memnew(RenderingServerRaster);
// FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, false));
+ rendering_server = memnew(RenderingServerWrapMT(rendering_server, false));
}
- ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(!rendering_server, ERR_UNAVAILABLE);
video_driver_index = p_video_driver;
@@ -130,7 +130,7 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p
window->SetInput(input);
window->Show();
- visual_server->init();
+ rendering_server->init();
AudioDriverManager::initialize(p_audio_driver);
@@ -142,10 +142,10 @@ void OS_Haiku::finalize() {
memdelete(main_loop);
}
- main_loop = NULL;
+ main_loop = nullptr;
- visual_server->finish();
- memdelete(visual_server);
+ rendering_server->finish();
+ memdelete(rendering_server);
memdelete(input);
@@ -169,8 +169,8 @@ void OS_Haiku::delete_main_loop() {
memdelete(main_loop);
}
- main_loop = NULL;
- window->SetMainLoop(NULL);
+ main_loop = nullptr;
+ window->SetMainLoop(nullptr);
}
void OS_Haiku::release_rendering_thread() {
@@ -267,7 +267,7 @@ void OS_Haiku::set_window_position(const Point2 &p_position) {
void OS_Haiku::set_window_fullscreen(bool p_enabled) {
window->SetFullScreen(p_enabled);
current_video_mode.fullscreen = p_enabled;
- visual_server->init();
+ rendering_server->init();
}
bool OS_Haiku::is_window_fullscreen() const {
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index fc8cb77a91..64f5690dd1 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -33,12 +33,12 @@
#include "audio_driver_media_kit.h"
#include "context_gl_haiku.h"
+#include "core/input/input_filter.h"
#include "drivers/unix/os_unix.h"
#include "haiku_application.h"
#include "haiku_direct_window.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
class OS_Haiku : public OS_Unix {
private:
@@ -46,7 +46,7 @@ private:
HaikuDirectWindow *window;
MainLoop *main_loop;
InputDefault *input;
- VisualServer *visual_server;
+ RenderingServer *rendering_server;
VideoMode current_video_mode;
int video_driver_index;
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index 1f82f51888..a48629f720 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -1,31 +1,35 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
iphone_lib = [
- 'godot_iphone.cpp',
- 'os_iphone.cpp',
- 'semaphore_iphone.cpp',
- 'gl_view.mm',
- 'main.m',
- 'app_delegate.mm',
- 'view_controller.mm',
- 'game_center.mm',
- 'in_app_store.mm',
- 'icloud.mm',
- 'ios.mm',
- 'vulkan_context_iphone.mm',
+ "godot_iphone.cpp",
+ "os_iphone.cpp",
+ "semaphore_iphone.cpp",
+ "gl_view.mm",
+ "main.m",
+ "app_delegate.mm",
+ "view_controller.mm",
+ "game_center.mm",
+ "in_app_store.mm",
+ "icloud.mm",
+ "ios.mm",
+ "vulkan_context_iphone.mm",
]
env_ios = env.Clone()
-ios_lib = env_ios.add_library('iphone', iphone_lib)
+ios_lib = env_ios.add_library("iphone", iphone_lib)
+
def combine_libs(target=None, source=None, env=None):
lib_path = target[0].srcnode().abspath
if "osxcross" in env:
- libtool = '$IPHONEPATH/usr/bin/${ios_triple}libtool'
+ libtool = "$IPHONEPATH/usr/bin/${ios_triple}libtool"
else:
libtool = "$IPHONEPATH/usr/bin/libtool"
- env.Execute(libtool + ' -static -o "' + lib_path + '" ' + ' '.join([('"' + lib.srcnode().abspath + '"') for lib in source]))
+ env.Execute(
+ libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source])
+ )
+
-combine_command = env_ios.Command('#bin/libgodot' + env_ios['LIBSUFFIX'], [ios_lib] + env_ios['LIBS'], combine_libs)
+combine_command = env_ios.Command("#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], combine_libs)
diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h
index 6b3b7ad5bc..27552d781a 100644
--- a/platform/iphone/app_delegate.h
+++ b/platform/iphone/app_delegate.h
@@ -36,9 +36,11 @@
#import <CoreMotion/CoreMotion.h>
-#if defined(OPENGL_ENABLED)
-@interface AppDelegate : NSObject <UIApplicationDelegate, GLViewDelegate> {
-#endif
+// FIXME: Add support for both GLES2 and Vulkan when GLES2 is implemented again,
+// so it can't be done with compilation time branching.
+//#if defined(OPENGL_ENABLED)
+//@interface AppDelegate : NSObject <UIApplicationDelegate, GLViewDelegate> {
+//#endif
#if defined(VULKAN_ENABLED)
@interface AppDelegate : NSObject <UIApplicationDelegate> {
#endif
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index acc3e5d4e0..0ac8bb7a56 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -648,7 +648,6 @@ static int frame_count = 0;
view_controller = [[ViewController alloc] init];
view_controller.view = glView;
-
_set_keep_screen_on(bool(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)) ? YES : NO);
glView.useCADisplayLink =
bool(GLOBAL_DEF("display.iOS/use_cadisplaylink", true)) ? YES : NO;
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index e01950c1db..3e6c2f0ecf 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -2,6 +2,7 @@ import os
import sys
from methods import detect_darwin_sdk_path
+
def is_active():
return True
@@ -12,7 +13,7 @@ def get_name():
def can_build():
- if sys.platform == 'darwin' or ("OSXCROSS_IOS" in os.environ):
+ if sys.platform == "darwin" or ("OSXCROSS_IOS" in os.environ):
return True
return False
@@ -20,22 +21,31 @@ def can_build():
def get_opts():
from SCons.Variables import BoolVariable
+
return [
- ('IPHONEPATH', 'Path to iPhone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
- ('IPHONESDK', 'Path to the iPhone SDK', ''),
- BoolVariable('use_static_mvk', 'Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)', False),
- BoolVariable('game_center', 'Support for game center', True),
- BoolVariable('store_kit', 'Support for in-app store', True),
- BoolVariable('icloud', 'Support for iCloud', True),
- BoolVariable('ios_exceptions', 'Enable exceptions', False),
- ('ios_triple', 'Triple for ios toolchain', ''),
+ (
+ "IPHONEPATH",
+ "Path to iPhone toolchain",
+ "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain",
+ ),
+ ("IPHONESDK", "Path to the iPhone SDK", ""),
+ BoolVariable(
+ "use_static_mvk",
+ "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)",
+ False,
+ ),
+ BoolVariable("game_center", "Support for game center", True),
+ BoolVariable("store_kit", "Support for in-app store", True),
+ BoolVariable("icloud", "Support for iCloud", True),
+ BoolVariable("ios_exceptions", "Enable exceptions", False),
+ ("ios_triple", "Triple for ios toolchain", ""),
]
def get_flags():
return [
- ('tools', False),
+ ("tools", False),
]
@@ -43,32 +53,32 @@ def configure(env):
## Build type
- if (env["target"].startswith("release")):
- env.Append(CPPDEFINES=['NDEBUG', ('NS_BLOCK_ASSERTIONS', 1)])
- 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
- env.Append(CCFLAGS=['-Os', '-ftree-vectorize'])
- env.Append(LINKFLAGS=['-Os'])
+ if env["target"].startswith("release"):
+ env.Append(CPPDEFINES=["NDEBUG", ("NS_BLOCK_ASSERTIONS", 1)])
+ 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
+ env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
+ env.Append(LINKFLAGS=["-Os"])
if env["target"] == "release_debug":
- env.Append(CPPDEFINES=['DEBUG_ENABLED'])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
- elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-gdwarf-2', '-O0'])
- env.Append(CPPDEFINES=['_DEBUG', ('DEBUG', 1), 'DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
+ elif env["target"] == "debug":
+ env.Append(CCFLAGS=["-gdwarf-2", "-O0"])
+ env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1), "DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
- if (env["use_lto"]):
- env.Append(CCFLAGS=['-flto'])
- env.Append(LINKFLAGS=['-flto'])
+ if env["use_lto"]:
+ env.Append(CCFLAGS=["-flto"])
+ env.Append(LINKFLAGS=["-flto"])
## Architecture
if env["arch"] == "x86": # i386
env["bits"] = "32"
elif env["arch"] == "x86_64":
env["bits"] = "64"
- elif (env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32"): # arm
+ elif env["arch"] == "arm" or env["arch"] == "arm32" or env["arch"] == "armv7" or env["bits"] == "32": # arm
env["arch"] = "arm"
env["bits"] = "32"
else: # armv64
@@ -81,108 +91,145 @@ def configure(env):
if "OSXCROSS_IOS" in os.environ:
env["osxcross"] = True
- env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
+ env["ENV"]["PATH"] = env["IPHONEPATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"]
- compiler_path = '$IPHONEPATH/usr/bin/${ios_triple}'
- s_compiler_path = '$IPHONEPATH/Developer/usr/bin/'
+ compiler_path = "$IPHONEPATH/usr/bin/${ios_triple}"
+ s_compiler_path = "$IPHONEPATH/Developer/usr/bin/"
ccache_path = os.environ.get("CCACHE")
if ccache_path is None:
- env['CC'] = compiler_path + 'clang'
- env['CXX'] = compiler_path + 'clang++'
- env['S_compiler'] = s_compiler_path + 'gcc'
+ env["CC"] = compiler_path + "clang"
+ env["CXX"] = compiler_path + "clang++"
+ env["S_compiler"] = s_compiler_path + "gcc"
else:
# there aren't any ccache wrappers available for iOS,
# to enable caching we need to prepend the path to the ccache binary
- env['CC'] = ccache_path + ' ' + compiler_path + 'clang'
- env['CXX'] = ccache_path + ' ' + compiler_path + 'clang++'
- env['S_compiler'] = ccache_path + ' ' + s_compiler_path + 'gcc'
- env['AR'] = compiler_path + 'ar'
- env['RANLIB'] = compiler_path + 'ranlib'
+ env["CC"] = ccache_path + " " + compiler_path + "clang"
+ env["CXX"] = ccache_path + " " + compiler_path + "clang++"
+ env["S_compiler"] = ccache_path + " " + s_compiler_path + "gcc"
+ env["AR"] = compiler_path + "ar"
+ env["RANLIB"] = compiler_path + "ranlib"
## Compile flags
- if (env["arch"] == "x86" or env["arch"] == "x86_64"):
- detect_darwin_sdk_path('iphonesimulator', env)
- env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.9'
+ if env["arch"] == "x86" or env["arch"] == "x86_64":
+ detect_darwin_sdk_path("iphonesimulator", env)
+ env["ENV"]["MACOSX_DEPLOYMENT_TARGET"] = "10.9"
arch_flag = "i386" if env["arch"] == "x86" else env["arch"]
- env.Append(CCFLAGS=('-arch ' + arch_flag + ' -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=10.0').split())
- elif (env["arch"] == "arm"):
- detect_darwin_sdk_path('iphone', env)
- env.Append(CCFLAGS='-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=10.0 -MMD -MT dependencies'.split())
- elif (env["arch"] == "arm64"):
- detect_darwin_sdk_path('iphone', env)
- env.Append(CCFLAGS='-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=10.0 -isysroot $IPHONESDK'.split())
- env.Append(CPPDEFINES=['NEED_LONG_INT'])
- env.Append(CPPDEFINES=['LIBYUV_DISABLE_NEON'])
+ env.Append(
+ CCFLAGS=(
+ "-arch "
+ + arch_flag
+ + " -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=10.0"
+ ).split()
+ )
+ elif env["arch"] == "arm":
+ detect_darwin_sdk_path("iphone", env)
+ env.Append(
+ CCFLAGS='-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=10.0 -MMD -MT dependencies'.split()
+ )
+ elif env["arch"] == "arm64":
+ detect_darwin_sdk_path("iphone", env)
+ env.Append(
+ CCFLAGS="-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=10.0 -isysroot $IPHONESDK".split()
+ )
+ env.Append(CPPDEFINES=["NEED_LONG_INT"])
+ env.Append(CPPDEFINES=["LIBYUV_DISABLE_NEON"])
# Disable exceptions on non-tools (template) builds
- if not env['tools']:
- if env['ios_exceptions']:
- env.Append(CCFLAGS=['-fexceptions'])
+ if not env["tools"]:
+ if env["ios_exceptions"]:
+ env.Append(CCFLAGS=["-fexceptions"])
else:
- env.Append(CCFLAGS=['-fno-exceptions'])
+ env.Append(CCFLAGS=["-fno-exceptions"])
## Link flags
- if (env["arch"] == "x86" or env["arch"] == "x86_64"):
+ if env["arch"] == "x86" or env["arch"] == "x86_64":
arch_flag = "i386" if env["arch"] == "x86" else env["arch"]
- env.Append(LINKFLAGS=['-arch', arch_flag, '-mios-simulator-version-min=10.0',
- '-isysroot', '$IPHONESDK',
- '-Xlinker',
- '-objc_abi_version',
- '-Xlinker', '2',
- '-F$IPHONESDK',
- ])
- elif (env["arch"] == "arm"):
- env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=10.0'])
- if (env["arch"] == "arm64"):
- env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=10.0'])
-
- env.Append(LINKFLAGS=['-isysroot', '$IPHONESDK',
- '-framework', 'AudioToolbox',
- '-framework', 'AVFoundation',
- '-framework', 'CoreAudio',
- '-framework', 'CoreGraphics',
- '-framework', 'CoreMedia',
- '-framework', 'CoreVideo',
- '-framework', 'CoreMotion',
- '-framework', 'Foundation',
- '-framework', 'GameController',
- '-framework', 'MediaPlayer',
- '-framework', 'Metal',
- '-framework', 'QuartzCore',
- '-framework', 'Security',
- '-framework', 'SystemConfiguration',
- '-framework', 'UIKit',
- '-framework', 'ARKit',
- ])
+ env.Append(
+ LINKFLAGS=[
+ "-arch",
+ arch_flag,
+ "-mios-simulator-version-min=10.0",
+ "-isysroot",
+ "$IPHONESDK",
+ "-Xlinker",
+ "-objc_abi_version",
+ "-Xlinker",
+ "2",
+ "-F$IPHONESDK",
+ ]
+ )
+ elif env["arch"] == "arm":
+ env.Append(LINKFLAGS=["-arch", "armv7", "-Wl,-dead_strip", "-miphoneos-version-min=10.0"])
+ if env["arch"] == "arm64":
+ env.Append(LINKFLAGS=["-arch", "arm64", "-Wl,-dead_strip", "-miphoneos-version-min=10.0"])
+
+ env.Append(
+ LINKFLAGS=[
+ "-isysroot",
+ "$IPHONESDK",
+ "-framework",
+ "AudioToolbox",
+ "-framework",
+ "AVFoundation",
+ "-framework",
+ "CoreAudio",
+ "-framework",
+ "CoreGraphics",
+ "-framework",
+ "CoreMedia",
+ "-framework",
+ "CoreVideo",
+ "-framework",
+ "CoreMotion",
+ "-framework",
+ "Foundation",
+ "-framework",
+ "GameController",
+ "-framework",
+ "MediaPlayer",
+ "-framework",
+ "Metal",
+ "-framework",
+ "QuartzCore",
+ "-framework",
+ "Security",
+ "-framework",
+ "SystemConfiguration",
+ "-framework",
+ "UIKit",
+ "-framework",
+ "ARKit",
+ ]
+ )
# Feature options
- if env['game_center']:
- env.Append(CPPDEFINES=['GAME_CENTER_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'GameKit'])
+ if env["game_center"]:
+ env.Append(CPPDEFINES=["GAME_CENTER_ENABLED"])
+ env.Append(LINKFLAGS=["-framework", "GameKit"])
- if env['store_kit']:
- env.Append(CPPDEFINES=['STOREKIT_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'StoreKit'])
+ if env["store_kit"]:
+ env.Append(CPPDEFINES=["STOREKIT_ENABLED"])
+ env.Append(LINKFLAGS=["-framework", "StoreKit"])
- if env['icloud']:
- env.Append(CPPDEFINES=['ICLOUD_ENABLED'])
+ if env["icloud"]:
+ env.Append(CPPDEFINES=["ICLOUD_ENABLED"])
- env.Prepend(CPPPATH=['$IPHONESDK/usr/include',
- '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers',
- ])
+ env.Prepend(
+ CPPPATH=["$IPHONESDK/usr/include", "$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers",]
+ )
- env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
+ env["ENV"]["CODESIGN_ALLOCATE"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate"
- env.Prepend(CPPPATH=['#platform/iphone'])
- env.Append(CPPDEFINES=['IPHONE_ENABLED', 'UNIX_ENABLED', 'COREAUDIO_ENABLED'])
+ env.Prepend(CPPPATH=["#platform/iphone"])
+ env.Append(CPPDEFINES=["IPHONE_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"])
- env.Append(CPPDEFINES=['VULKAN_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'IOSurface'])
- if (env['use_static_mvk']):
- env.Append(LINKFLAGS=['-framework', 'MoltenVK'])
- env['builtin_vulkan'] = False
- elif not env['builtin_vulkan']:
- env.Append(LIBS=['vulkan'])
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ env.Append(LINKFLAGS=["-framework", "IOSurface"])
+ if env["use_static_mvk"]:
+ env.Append(LINKFLAGS=["-framework", "MoltenVK"])
+ env["builtin_vulkan"] = False
+ elif not env["builtin_vulkan"]:
+ env.Append(LIBS=["vulkan"])
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 7cef2351e3..3efe338ac7 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -71,8 +71,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
String modules_buildphase;
String modules_buildgrp;
};
-
struct ExportArchitecture {
+
String name;
bool is_default;
@@ -106,7 +106,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets);
Error _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
- bool is_package_name_valid(const String &p_package, String *r_error = NULL) const {
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
String pname = p_package;
@@ -410,7 +410,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
String EditorExportPlatformIOS::_get_additional_plist_content() {
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
String result;
for (int i = 0; i < export_plugins.size(); ++i) {
result += export_plugins[i]->get_ios_plist_content();
@@ -419,7 +419,7 @@ String EditorExportPlatformIOS::_get_additional_plist_content() {
}
String EditorExportPlatformIOS::_get_linker_flags() {
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
String result;
for (int i = 0; i < export_plugins.size(); ++i) {
String flags = export_plugins[i]->get_ios_linker_flags();
@@ -434,7 +434,7 @@ String EditorExportPlatformIOS::_get_linker_flags() {
}
String EditorExportPlatformIOS::_get_cpp_code() {
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
String result;
for (int i = 0; i < export_plugins.size(); ++i) {
result += export_plugins[i]->get_ios_cpp_code();
@@ -776,7 +776,7 @@ struct ExportLibsData {
};
void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
Vector<String> frameworks;
for (int i = 0; i < export_plugins.size(); ++i) {
Vector<String> plugin_frameworks = export_plugins[i]->get_ios_frameworks();
@@ -795,7 +795,7 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
String pbx_resources_refs;
const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
- "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = $name; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
+ "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
for (int i = 0; i < p_additional_assets.size(); ++i) {
String build_id = (++current_id).str();
String ref_id = (++current_id).str();
@@ -920,11 +920,18 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
}
Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) {
- Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
Vector<String> frameworks = export_plugins[i]->get_ios_frameworks();
Error err = _export_additional_assets(p_out_dir, frameworks, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
+
+ Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
+ for (int j = 0; j < project_static_libs.size(); j++)
+ project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
+ err = _export_additional_assets(p_out_dir, project_static_libs, true, r_exported_assets);
+ ERR_FAIL_COND_V(err, err);
+
Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
err = _export_additional_assets(p_out_dir, ios_bundle_files, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
@@ -1076,7 +1083,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE);
print_line("Unzipping...");
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io);
if (!src_pkg_zip) {
@@ -1098,7 +1105,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0);
String file = fname;
@@ -1202,6 +1209,22 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return ERR_FILE_NOT_FOUND;
}
+ // Copy project static libs to the project
+ Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ for (int i = 0; i < export_plugins.size(); i++) {
+ Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
+ for (int j = 0; j < project_static_libs.size(); j++) {
+ const String &static_lib_path = project_static_libs[j];
+ String dest_lib_file_path = dest_dir + static_lib_path.get_file();
+ Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path);
+ if (lib_copy_err != OK) {
+ ERR_PRINT("Can't copy '" + static_lib_path + "'.");
+ memdelete(tmp_app_path);
+ return lib_copy_err;
+ }
+ }
+ }
+
String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/";
err = OK;
if (!tmp_app_path->dir_exists(iconset_dir)) {
diff --git a/platform/iphone/export/export.h b/platform/iphone/export/export.h
index 77b2a07bd1..043d21f533 100644
--- a/platform/iphone/export/export.h
+++ b/platform/iphone/export/export.h
@@ -28,4 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef IPHONE_EXPORT_H
+#define IPHONE_EXPORT_H
+
void register_iphone_exporter();
+
+#endif // IPHONE_EXPORT_H
diff --git a/platform/iphone/godot_iphone.cpp b/platform/iphone/godot_iphone.cpp
index 8c3eddc5f7..3e67362e16 100644
--- a/platform/iphone/godot_iphone.cpp
+++ b/platform/iphone/godot_iphone.cpp
@@ -36,7 +36,7 @@
#include <string.h>
#include <unistd.h>
-static OSIPhone *os = NULL;
+static OSIPhone *os = nullptr;
extern "C" {
int add_path(int p_argc, char **p_args);
@@ -71,7 +71,7 @@ int iphone_main(int width, int height, int argc, char **argv, String data_dir) {
for (int i = 0; i < argc; i++) {
fargv[i] = argv[i];
};
- fargv[argc] = NULL;
+ fargv[argc] = nullptr;
argc = add_path(argc, fargv);
argc = add_cmdline(argc, fargv);
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index 497f2f747d..3ef521a61a 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -37,13 +37,13 @@
#endif
#if defined(VULKAN_ENABLED)
-#include "servers/visual/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
// #import <QuartzCore/CAMetalLayer.h>
#include <vulkan/vulkan_metal.h>
#endif
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_wrap_mt.h"
#include "main/main.h"
@@ -68,7 +68,7 @@ const char *OSIPhone::get_video_driver_name(int p_driver) const {
case VIDEO_DRIVER_GLES2:
return "GLES2";
}
- ERR_FAIL_V_MSG(NULL, "Invalid video driver index: " + itos(p_driver) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Invalid video driver index: " + itos(p_driver) + ".");
};
OSIPhone *OSIPhone::get_singleton() {
@@ -134,16 +134,16 @@ Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p
RasterizerRD::make_current();
#endif
- visual_server = memnew(VisualServerRaster);
+ rendering_server = memnew(RenderingServerRaster);
// FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, false));
+ rendering_server = memnew(RenderingServerWrapMT(rendering_server, false));
}
- visual_server->init();
- //visual_server->cursor_set_visible(false, 0);
+ rendering_server->init();
+ //rendering_server->cursor_set_visible(false, 0);
#if defined(OPENGL_ENABLED)
- // reset this to what it should be, it will have been set to 0 after visual_server->init() is called
+ // reset this to what it should be, it will have been set to 0 after rendering_server->init() is called
RasterizerStorageGLES2::system_fbo = gl_view_base_fb;
#endif
@@ -339,7 +339,7 @@ void OSIPhone::delete_main_loop() {
memdelete(main_loop);
};
- main_loop = NULL;
+ main_loop = nullptr;
};
void OSIPhone::finalize() {
@@ -361,8 +361,8 @@ void OSIPhone::finalize() {
memdelete(icloud);
#endif
- visual_server->finish();
- memdelete(visual_server);
+ rendering_server->finish();
+ memdelete(rendering_server);
// memdelete(rasterizer);
// Free unhandled events before close
@@ -608,7 +608,7 @@ bool OSIPhone::_check_internal_feature_support(const String &p_feature) {
// so we use this as a hack to ensure certain code is called before
// everything else, but after all units are initialized.
typedef void (*init_callback)();
-static init_callback *ios_init_callbacks = NULL;
+static init_callback *ios_init_callbacks = nullptr;
static int ios_init_callbacks_count = 0;
static int ios_init_callbacks_capacity = 0;
@@ -631,12 +631,12 @@ OSIPhone::OSIPhone(int width, int height, String p_data_dir) {
ios_init_callbacks[i]();
}
free(ios_init_callbacks);
- ios_init_callbacks = NULL;
+ ios_init_callbacks = nullptr;
ios_init_callbacks_count = 0;
ios_init_callbacks_capacity = 0;
- main_loop = NULL;
- visual_server = NULL;
+ main_loop = nullptr;
+ rendering_server = nullptr;
VideoMode vm;
vm.fullscreen = true;
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index f42679e754..96cf041c37 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -33,18 +33,16 @@
#ifndef OS_IPHONE_H
#define OS_IPHONE_H
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "drivers/coreaudio/audio_driver_coreaudio.h"
#include "drivers/unix/os_unix.h"
-
#include "game_center.h"
#include "icloud.h"
#include "in_app_store.h"
#include "ios.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
#if defined(VULKAN_ENABLED)
#include "drivers/vulkan/rendering_device_vulkan.h"
@@ -62,7 +60,7 @@ private:
static HashMap<String, void *> dynamic_symbol_lookup_table;
friend void register_dynamic_symbol(char *name, void *address);
- VisualServer *visual_server;
+ RenderingServer *rendering_server;
AudioDriverCoreAudio audio_driver;
diff --git a/platform/iphone/platform_refcount.h b/platform/iphone/platform_refcount.h
deleted file mode 100644
index 9029418462..0000000000
--- a/platform/iphone/platform_refcount.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* platform_refcount.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "core/safe_refcount.h"
-
-#ifdef IPHONE_ENABLED
-
-#define REFCOUNT_T int
-#define REFCOUNT_GET_T int const volatile &
-
-#include <libkern/OSAtomic.h>
-
-inline int atomic_conditional_increment(volatile int *v) {
- return (*v == 0) ? 0 : OSAtomicIncrement32(v);
-}
-
-inline int atomic_decrement(volatile int *v) {
- return OSAtomicDecrement32(v);
-}
-
-#endif
diff --git a/platform/iphone/vulkan_context_iphone.h b/platform/iphone/vulkan_context_iphone.h
index 200057e14d..625e41f4b9 100644
--- a/platform/iphone/vulkan_context_iphone.h
+++ b/platform/iphone/vulkan_context_iphone.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* vulkan_context_osx.h */
+/* vulkan_context_iphone.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/iphone/vulkan_context_iphone.mm
index f49b85c097..701ac0d9bb 100644
--- a/platform/iphone/vulkan_context_iphone.mm
+++ b/platform/iphone/vulkan_context_iphone.mm
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* vulkan_context_osx.mm */
+/* vulkan_context_iphone.mm */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index d3cd8f76b7..7239648937 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -1,67 +1,63 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
javascript_files = [
- 'audio_driver_javascript.cpp',
- 'http_client_javascript.cpp',
- 'javascript_eval.cpp',
- 'javascript_main.cpp',
- 'os_javascript.cpp',
+ "audio_driver_javascript.cpp",
+ "http_client_javascript.cpp",
+ "javascript_eval.cpp",
+ "javascript_main.cpp",
+ "os_javascript.cpp",
]
-build_targets = ['#bin/godot${PROGSUFFIX}.js', '#bin/godot${PROGSUFFIX}.wasm']
-if env['threads_enabled']:
- build_targets.append('#bin/godot${PROGSUFFIX}.worker.js')
+build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
+if env["threads_enabled"]:
+ build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
build = env.add_program(build_targets, javascript_files)
js_libraries = [
- 'http_request.js',
+ "http_request.js",
]
for lib in js_libraries:
- env.Append(LINKFLAGS=['--js-library', env.File(lib).path])
+ env.Append(LINKFLAGS=["--js-library", env.File(lib).path])
env.Depends(build, js_libraries)
js_modules = [
- 'id_handler.js',
+ "id_handler.js",
]
for module in js_modules:
- env.Append(LINKFLAGS=['--pre-js', env.File(module).path])
+ env.Append(LINKFLAGS=["--pre-js", env.File(module).path])
env.Depends(build, js_modules)
engine = [
- 'engine/preloader.js',
- 'engine/loader.js',
- 'engine/utils.js',
- 'engine/engine.js',
+ "engine/preloader.js",
+ "engine/loader.js",
+ "engine/utils.js",
+ "engine/engine.js",
]
-externs = [
- env.File('#platform/javascript/engine/externs.js')
-]
-js_engine = env.CreateEngineFile('#bin/godot${PROGSUFFIX}.engine.js', engine, externs)
+externs = [env.File("#platform/javascript/engine/externs.js")]
+js_engine = env.CreateEngineFile("#bin/godot${PROGSUFFIX}.engine.js", engine, externs)
env.Depends(js_engine, externs)
wrap_list = [
build[0],
js_engine,
]
-js_wrapped = env.Textfile('#bin/godot', [env.File(f) for f in wrap_list], TEXTFILESUFFIX='${PROGSUFFIX}.wrapped.js')
+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')
-out_files = [
- zip_dir.File('godot.js'),
- zip_dir.File('godot.wasm'),
- zip_dir.File('godot.html')
-]
-in_files = [
- js_wrapped,
- build[1],
- '#misc/dist/html/full-size.html'
-]
-if env['threads_enabled']:
+zip_dir = env.Dir("#bin/.javascript_zip")
+out_files = [zip_dir.File("godot.js"), zip_dir.File("godot.wasm"), zip_dir.File("godot.html")]
+in_files = [js_wrapped, build[1], "#misc/dist/html/full-size.html"]
+if env["threads_enabled"]:
in_files.append(build[2])
- out_files.append(zip_dir.File('godot.worker.js'))
+ out_files.append(zip_dir.File("godot.worker.js"))
zip_files = env.InstallAs(out_files, in_files)
-env.Zip('#bin/godot', zip_files, ZIPROOT=zip_dir, ZIPSUFFIX='${PROGSUFFIX}${ZIPSUFFIX}', ZIPCOMSTR='Archving $SOURCES as $TARGET')
+env.Zip(
+ "#bin/godot",
+ zip_files,
+ ZIPROOT=zip_dir,
+ ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}",
+ ZIPCOMSTR="Archving $SOURCES as $TARGET",
+)
diff --git a/platform/javascript/api/api.cpp b/platform/javascript/api/api.cpp
index 88de13d771..45cb82b351 100644
--- a/platform/javascript/api/api.cpp
+++ b/platform/javascript/api/api.cpp
@@ -46,7 +46,7 @@ void unregister_javascript_api() {
memdelete(javascript_eval);
}
-JavaScript *JavaScript::singleton = NULL;
+JavaScript *JavaScript::singleton = nullptr;
JavaScript *JavaScript::get_singleton() {
@@ -55,7 +55,7 @@ JavaScript *JavaScript::get_singleton() {
JavaScript::JavaScript() {
- ERR_FAIL_COND_MSG(singleton != NULL, "JavaScript singleton already exist.");
+ ERR_FAIL_COND_MSG(singleton != nullptr, "JavaScript singleton already exist.");
singleton = this;
}
diff --git a/platform/javascript/api/api.h b/platform/javascript/api/api.h
index 164d679205..8afe0f33ce 100644
--- a/platform/javascript/api/api.h
+++ b/platform/javascript/api/api.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef JAVASCRIPT_API_H
+#define JAVASCRIPT_API_H
+
void register_javascript_api();
void unregister_javascript_api();
+
+#endif // JAVASCRIPT_API_H
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index d63c6a40a5..8f857478e5 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -32,7 +32,7 @@
#include <emscripten.h>
-AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL;
+AudioDriverJavaScript *AudioDriverJavaScript::singleton = nullptr;
const char *AudioDriverJavaScript::get_name() const {
@@ -200,7 +200,7 @@ void AudioDriverJavaScript::finish() {
if (internal_buffer) {
memdelete_arr(internal_buffer);
- internal_buffer = NULL;
+ internal_buffer = nullptr;
}
_driver_id = 0;
}
@@ -264,7 +264,7 @@ Error AudioDriverJavaScript::capture_stop() {
AudioDriverJavaScript::AudioDriverJavaScript() {
_driver_id = 0;
- internal_buffer = NULL;
+ internal_buffer = nullptr;
buffer_length = 0;
singleton = this;
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index fb02752aa7..9486e10717 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -2,37 +2,39 @@ import os
from emscripten_helpers import parse_config, run_closure_compiler, create_engine_file
+
def is_active():
return True
def get_name():
- return 'JavaScript'
+ return "JavaScript"
def can_build():
- return 'EM_CONFIG' in os.environ or os.path.exists(os.path.expanduser('~/.emscripten'))
+ return "EM_CONFIG" in os.environ or os.path.exists(os.path.expanduser("~/.emscripten"))
def get_opts():
from SCons.Variables import BoolVariable
+
return [
# eval() can be a security concern, so it can be disabled.
- BoolVariable('javascript_eval', 'Enable JavaScript eval interface', True),
- BoolVariable('threads_enabled', 'Enable WebAssembly Threads support (limited browser support)', False),
- BoolVariable('use_closure_compiler', 'Use closure compiler to minimize Javascript code', False),
+ BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
+ BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
+ BoolVariable("use_closure_compiler", "Use closure compiler to minimize Javascript code", False),
]
def get_flags():
return [
- ('tools', False),
- ('builtin_pcre2_with_jit', False),
+ ("tools", False),
+ ("builtin_pcre2_with_jit", False),
# Disabling the mbedtls module reduces file size.
# The module has little use due to the limited networking functionality
# in this platform. For the available networking methods, the browser
# manages TLS.
- ('module_mbedtls_enabled', False),
+ ("module_mbedtls_enabled", False),
]
@@ -40,125 +42,125 @@ def configure(env):
## Build type
- if env['target'] == 'release':
+ if env["target"] == "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'])
+ 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'])
- else: # 'debug'
- env.Append(CPPDEFINES=['DEBUG_ENABLED'])
- env.Append(CCFLAGS=['-O1', '-g'])
- env.Append(LINKFLAGS=['-O1', '-g'])
- env.Append(LINKFLAGS=['-s', 'ASSERTIONS=1'])
-
- if env['tools']:
- if not env['threads_enabled']:
- raise RuntimeError("Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option")
+ env.Append(LINKFLAGS=["--profiling-funcs"])
+ else: # 'debug'
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ env.Append(CCFLAGS=["-O1", "-g"])
+ env.Append(LINKFLAGS=["-O1", "-g"])
+ env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
+
+ if env["tools"]:
+ if not env["threads_enabled"]:
+ raise RuntimeError(
+ "Threads must be enabled to build the editor. Please add the 'threads_enabled=yes' option"
+ )
# Tools need more memory. Initial stack memory in bytes. See `src/settings.js` in emscripten repository (will be renamed to INITIAL_MEMORY).
- env.Append(LINKFLAGS=['-s', 'TOTAL_MEMORY=33554432'])
+ env.Append(LINKFLAGS=["-s", "TOTAL_MEMORY=33554432"])
else:
# Disable exceptions and rtti on non-tools (template) builds
# These flags help keep the file size down.
- env.Append(CCFLAGS=['-fno-exceptions', '-fno-rtti'])
+ env.Append(CCFLAGS=["-fno-exceptions", "-fno-rtti"])
# Don't use dynamic_cast, necessary with no-rtti.
- env.Append(CPPDEFINES=['NO_SAFE_CAST'])
+ env.Append(CPPDEFINES=["NO_SAFE_CAST"])
## Copy env variables.
- env['ENV'] = os.environ
+ env["ENV"] = os.environ
# LTO
- if env['use_lto']:
- env.Append(CCFLAGS=['-s', 'WASM_OBJECT_FILES=0'])
- env.Append(LINKFLAGS=['-s', 'WASM_OBJECT_FILES=0'])
- env.Append(LINKFLAGS=['--llvm-lto', '1'])
+ if env["use_lto"]:
+ env.Append(CCFLAGS=["-s", "WASM_OBJECT_FILES=0"])
+ env.Append(LINKFLAGS=["-s", "WASM_OBJECT_FILES=0"])
+ env.Append(LINKFLAGS=["--llvm-lto", "1"])
# Closure compiler
- if env['use_closure_compiler']:
+ if env["use_closure_compiler"]:
# For emscripten support code.
- env.Append(LINKFLAGS=['--closure', '1'])
+ env.Append(LINKFLAGS=["--closure", "1"])
# Register builder for our Engine files
- jscc = env.Builder(generator=run_closure_compiler, suffix='.cc.js', src_suffix='.js')
- env.Append(BUILDERS = {'BuildJS' : jscc})
+ jscc = env.Builder(generator=run_closure_compiler, suffix=".cc.js", src_suffix=".js")
+ env.Append(BUILDERS={"BuildJS": jscc})
# Add method that joins/compiles our Engine files.
env.AddMethod(create_engine_file, "CreateEngineFile")
# Closure compiler extern and support for ecmascript specs (const, let, etc).
- env['ENV']['EMCC_CLOSURE_ARGS'] = '--language_in ECMASCRIPT6'
+ env["ENV"]["EMCC_CLOSURE_ARGS"] = "--language_in ECMASCRIPT6"
em_config = parse_config()
- env.PrependENVPath('PATH', em_config['EMCC_ROOT'])
+ env.PrependENVPath("PATH", em_config["EMCC_ROOT"])
- env['CC'] = 'emcc'
- env['CXX'] = 'em++'
- env['LINK'] = 'emcc'
+ env["CC"] = "emcc"
+ env["CXX"] = "em++"
+ env["LINK"] = "emcc"
- env['AR'] = 'emar'
- env['RANLIB'] = 'emranlib'
+ env["AR"] = "emar"
+ env["RANLIB"] = "emranlib"
# Use TempFileMunge since some AR invocations are too long for cmd.exe.
# Use POSIX-style paths, required with TempFileMunge.
- env['ARCOM_POSIX'] = env['ARCOM'].replace(
- '$TARGET', '$TARGET.posix').replace(
- '$SOURCES', '$SOURCES.posix')
- env['ARCOM'] = '${TEMPFILE(ARCOM_POSIX)}'
+ env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
+ env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
# All intermediate files are just LLVM bitcode.
- env['OBJPREFIX'] = ''
- env['OBJSUFFIX'] = '.bc'
- env['PROGPREFIX'] = ''
+ env["OBJPREFIX"] = ""
+ env["OBJSUFFIX"] = ".bc"
+ env["PROGPREFIX"] = ""
# Program() output consists of multiple files, so specify suffixes manually at builder.
- env['PROGSUFFIX'] = ''
- env['LIBPREFIX'] = 'lib'
- env['LIBSUFFIX'] = '.bc'
- env['LIBPREFIXES'] = ['$LIBPREFIX']
- env['LIBSUFFIXES'] = ['$LIBSUFFIX']
+ env["PROGSUFFIX"] = ""
+ env["LIBPREFIX"] = "lib"
+ env["LIBSUFFIX"] = ".bc"
+ env["LIBPREFIXES"] = ["$LIBPREFIX"]
+ env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
- env.Prepend(CPPPATH=['#platform/javascript'])
- env.Append(CPPDEFINES=['JAVASCRIPT_ENABLED', 'UNIX_ENABLED'])
+ env.Prepend(CPPPATH=["#platform/javascript"])
+ env.Append(CPPDEFINES=["JAVASCRIPT_ENABLED", "UNIX_ENABLED"])
- if env['javascript_eval']:
- env.Append(CPPDEFINES=['JAVASCRIPT_EVAL_ENABLED'])
+ if env["javascript_eval"]:
+ env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
# Thread support (via SharedArrayBuffer).
- if env['threads_enabled']:
- env.Append(CPPDEFINES=['PTHREAD_NO_RENAME'])
- env.Append(CCFLAGS=['-s', 'USE_PTHREADS=1'])
- env.Append(LINKFLAGS=['-s', 'USE_PTHREADS=1'])
- env.Append(LINKFLAGS=['-s', 'PTHREAD_POOL_SIZE=4'])
- env.Append(LINKFLAGS=['-s', 'WASM_MEM_MAX=2048MB'])
+ if env["threads_enabled"]:
+ env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
+ env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
+ env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
+ env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=4"])
+ env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
else:
- env.Append(CPPDEFINES=['NO_THREADS'])
+ env.Append(CPPDEFINES=["NO_THREADS"])
# Reduce code size by generating less support code (e.g. skip NodeJS support).
- env.Append(LINKFLAGS=['-s', 'ENVIRONMENT=web,worker'])
+ env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
# We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to
# be linked explicitly.
- env.Append(LIBS=['idbfs.js'])
+ env.Append(LIBS=["idbfs.js"])
- env.Append(LINKFLAGS=['-s', 'BINARYEN=1'])
- env.Append(LINKFLAGS=['-s', 'MODULARIZE=1', '-s', 'EXPORT_NAME="Godot"'])
+ env.Append(LINKFLAGS=["-s", "BINARYEN=1"])
+ env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", 'EXPORT_NAME="Godot"'])
# Allow increasing memory buffer size during runtime. This is efficient
# when using WebAssembly (in comparison to asm.js) and works well for
# us since we don't know requirements at compile-time.
- env.Append(LINKFLAGS=['-s', 'ALLOW_MEMORY_GROWTH=1'])
+ env.Append(LINKFLAGS=["-s", "ALLOW_MEMORY_GROWTH=1"])
# This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1.
- env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1'])
+ env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"])
- env.Append(LINKFLAGS=['-s', 'INVOKE_RUN=0'])
+ env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"])
# callMain for manual start, FS for preloading.
- env.Append(LINKFLAGS=['-s', 'EXTRA_EXPORTED_RUNTIME_METHODS=["callMain", "FS"]'])
+ env.Append(LINKFLAGS=["-s", 'EXTRA_EXPORTED_RUNTIME_METHODS=["callMain", "FS"]'])
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index bda5b40a74..a55c9d3f48 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -1,7 +1,8 @@
import os
+
def parse_config():
- em_config_file = os.getenv('EM_CONFIG') or os.path.expanduser('~/.emscripten')
+ em_config_file = os.getenv("EM_CONFIG") or os.path.expanduser("~/.emscripten")
if not os.path.exists(em_config_file):
raise RuntimeError("Emscripten configuration file '%s' does not exist" % em_config_file)
@@ -13,25 +14,25 @@ def parse_config():
exec(f.read(), em_config)
except StandardError as e:
raise RuntimeError("Emscripten configuration file '%s' is invalid:\n%s" % (em_config_file, e))
- normalized['EMCC_ROOT'] = em_config.get('EMSCRIPTEN_ROOT')
- normalized['NODE_JS'] = em_config.get('NODE_JS')
- normalized['CLOSURE_BIN'] = os.path.join(normalized['EMCC_ROOT'], 'node_modules', '.bin', 'google-closure-compiler')
+ normalized["EMCC_ROOT"] = em_config.get("EMSCRIPTEN_ROOT")
+ normalized["NODE_JS"] = em_config.get("NODE_JS")
+ normalized["CLOSURE_BIN"] = os.path.join(normalized["EMCC_ROOT"], "node_modules", ".bin", "google-closure-compiler")
return normalized
def run_closure_compiler(target, source, env, for_signature):
cfg = parse_config()
- cmd = [cfg['NODE_JS'], cfg['CLOSURE_BIN']]
- cmd.extend(['--compilation_level', 'ADVANCED_OPTIMIZATIONS'])
- for f in env['JSEXTERNS']:
- cmd.extend(['--externs', f.get_abspath()])
+ cmd = [cfg["NODE_JS"], cfg["CLOSURE_BIN"]]
+ cmd.extend(["--compilation_level", "ADVANCED_OPTIMIZATIONS"])
+ for f in env["JSEXTERNS"]:
+ cmd.extend(["--externs", f.get_abspath()])
for f in source:
- cmd.extend(['--js', f.get_abspath()])
- cmd.extend(['--js_output_file', target[0].get_abspath()])
- return ' '.join(cmd)
+ cmd.extend(["--js", f.get_abspath()])
+ cmd.extend(["--js_output_file", target[0].get_abspath()])
+ return " ".join(cmd)
def create_engine_file(env, target, source, externs):
- if env['use_closure_compiler']:
+ if env["use_closure_compiler"]:
return env.BuildJS(target, source, JSEXTERNS=externs)
return env.Textfile(target, [env.File(s) for s in source])
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index da61425747..39faae2d17 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -390,7 +390,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return error;
}
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(template_path.utf8().get_data(), &io);
@@ -410,7 +410,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
//get filename
unz_file_info info;
char fname[16384];
- unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
String file = fname;
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
index 472384cf30..863c207896 100644
--- a/platform/javascript/http_client_javascript.cpp
+++ b/platform/javascript/http_client_javascript.cpp
@@ -88,8 +88,8 @@ Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Ve
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.empty() ? NULL : username.utf8().get_data(),
- password.empty() ? NULL : password.utf8().get_data());
+ username.empty() ? nullptr : username.utf8().get_data(),
+ password.empty() ? nullptr : password.utf8().get_data());
for (int i = 0; i < p_headers.size(); i++) {
int header_separator = p_headers[i].find(": ");
diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h
index 57dc4f0d9f..54e98c1927 100644
--- a/platform/javascript/http_request.h
+++ b/platform/javascript/http_request.h
@@ -49,7 +49,7 @@ extern int godot_xhr_new();
extern void godot_xhr_reset(int p_xhr_id);
extern bool 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 = NULL, const char *p_password = NULL);
+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);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 1d7a16db80..ad06aef86e 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -36,7 +36,7 @@
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
#include "main/main.h"
-#include "servers/visual/visual_server_raster.h"
+#include "servers/rendering/rendering_server_raster.h"
#include <emscripten.h>
#include <png.h>
@@ -167,7 +167,7 @@ void OS_JavaScript::set_window_maximized(bool p_enabled) {
strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
- strategy.canvasResizedCallback = NULL;
+ strategy.canvasResizedCallback = nullptr;
emscripten_enter_soft_fullscreen(GODOT_CANVAS_SELECTOR, &strategy);
window_maximized = p_enabled;
}
@@ -196,7 +196,7 @@ void OS_JavaScript::set_window_fullscreen(bool p_enabled) {
strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
- strategy.canvasResizedCallback = NULL;
+ strategy.canvasResizedCallback = nullptr;
EMSCRIPTEN_RESULT result = emscripten_request_fullscreen_strategy(GODOT_CANVAS_SELECTOR, 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.");
@@ -470,7 +470,7 @@ void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_s
if (p_cursor.is_valid()) {
- Map<CursorShape, Vector<Variant> >::Element *cursor_c = cursors_cache.find(p_shape);
+ Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
if (cursor_c) {
if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
@@ -541,10 +541,10 @@ void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_s
PackedByteArray png;
size_t len;
PackedByteArray data = image->get_data();
- ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, NULL));
+ ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, nullptr));
png.resize(len);
- ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, NULL));
+ ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, nullptr));
char *object_url;
/* clang-format off */
@@ -824,7 +824,7 @@ const char *OS_JavaScript::get_video_driver_name(int p_driver) const {
case VIDEO_DRIVER_GLES2:
return "GLES2";
}
- ERR_FAIL_V_MSG(NULL, "Invalid video driver index: " + itos(p_driver) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Invalid video driver index: " + itos(p_driver) + ".");
}
// Audio
@@ -887,7 +887,7 @@ int OS_JavaScript::get_current_video_driver() const {
void OS_JavaScript::initialize_core() {
OS_Unix::initialize_core();
- FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix>>(FileAccess::ACCESS_RESOURCES);
}
Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
@@ -962,18 +962,18 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
setenv("LANG", locale_ptr, true);
AudioDriverManager::initialize(p_audio_driver);
- VisualServer *visual_server = memnew(VisualServerRaster());
+ RenderingServer *rendering_server = memnew(RenderingServerRaster());
input = memnew(InputDefault);
EMSCRIPTEN_RESULT result;
#define EM_CHECK(ev) \
if (result != EMSCRIPTEN_RESULT_SUCCESS) \
ERR_PRINT("Error while setting " #ev " callback: Code " + itos(result));
-#define SET_EM_CALLBACK(target, ev, cb) \
- result = emscripten_set_##ev##_callback(target, NULL, true, &cb); \
+#define SET_EM_CALLBACK(target, ev, cb) \
+ result = emscripten_set_##ev##_callback(target, nullptr, true, &cb); \
EM_CHECK(ev)
-#define SET_EM_CALLBACK_NOTARGET(ev, cb) \
- result = emscripten_set_##ev##_callback(NULL, true, &cb); \
+#define SET_EM_CALLBACK_NOTARGET(ev, cb) \
+ result = emscripten_set_##ev##_callback(nullptr, true, &cb); \
EM_CHECK(ev)
// These callbacks from Emscripten's html5.h suffice to access most
// JavaScript APIs. For APIs that are not (sufficiently) exposed, EM_ASM
@@ -1009,14 +1009,14 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
update_clipboard(evt.clipboardData.getData('text'));
}, true);
},
- MainLoop::NOTIFICATION_WM_MOUSE_ENTER,
- MainLoop::NOTIFICATION_WM_MOUSE_EXIT,
- MainLoop::NOTIFICATION_WM_FOCUS_IN,
- MainLoop::NOTIFICATION_WM_FOCUS_OUT
+ NOTIFICATION_WM_MOUSE_ENTER,
+ NOTIFICATION_WM_MOUSE_EXIT,
+ NOTIFICATION_WM_FOCUS_IN,
+ NOTIFICATION_WM_FOCUS_OUT
);
/* clang-format on */
- visual_server->init();
+ rendering_server->init();
return OK;
}
@@ -1072,7 +1072,7 @@ bool OS_JavaScript::main_loop_iterate() {
strategy.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH;
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;
strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
- strategy.canvasResizedCallback = NULL;
+ strategy.canvasResizedCallback = nullptr;
emscripten_enter_soft_fullscreen(GODOT_CANVAS_SELECTOR, &strategy);
} else {
emscripten_set_canvas_element_size(GODOT_CANVAS_SELECTOR, windowed_size.width, windowed_size.height);
@@ -1121,8 +1121,8 @@ int OS_JavaScript::get_process_id() const {
extern "C" EMSCRIPTEN_KEEPALIVE void send_notification(int p_notification) {
- if (p_notification == MainLoop::NOTIFICATION_WM_MOUSE_ENTER || p_notification == MainLoop::NOTIFICATION_WM_MOUSE_EXIT) {
- cursor_inside_canvas = p_notification == MainLoop::NOTIFICATION_WM_MOUSE_ENTER;
+ if (p_notification == NOTIFICATION_WM_MOUSE_ENTER || p_notification == NOTIFICATION_WM_MOUSE_EXIT) {
+ cursor_inside_canvas = p_notification == NOTIFICATION_WM_MOUSE_ENTER;
}
OS_JavaScript::get_singleton()->get_main_loop()->notification(p_notification);
}
@@ -1182,10 +1182,10 @@ void OS_JavaScript::set_icon(const Ref<Image> &p_icon) {
PackedByteArray png;
size_t len;
PackedByteArray data = icon->get_data();
- ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, NULL));
+ ERR_FAIL_COND(!png_image_write_get_memory_size(png_meta, len, 0, data.ptr(), 0, nullptr));
png.resize(len);
- ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, NULL));
+ ERR_FAIL_COND(!png_image_write_to_memory(&png_meta, png.ptrw(), &len, 0, data.ptr(), 0, nullptr));
/* clang-format off */
EM_ASM_ARGS({
@@ -1284,7 +1284,7 @@ OS_JavaScript::OS_JavaScript(int p_argc, char *p_argv[]) {
just_exited_fullscreen = false;
transparency_enabled = false;
- main_loop = NULL;
+ main_loop = nullptr;
idb_available = false;
sync_wait_time = -1;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 5319ea121c..81fe4cf0cc 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -32,10 +32,10 @@
#define OS_JAVASCRIPT_H
#include "audio_driver_javascript.h"
+#include "core/input/input_filter.h"
#include "drivers/unix/os_unix.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
+#include "servers/rendering/rasterizer.h"
#include <emscripten/html5.h>
@@ -52,7 +52,7 @@ class OS_JavaScript : public OS_Unix {
Ref<InputEventKey> deferred_key_event;
CursorShape cursor_shape;
String cursors[CURSOR_MAX];
- Map<CursorShape, Vector<Variant> > cursors_cache;
+ Map<CursorShape, Vector<Variant>> cursors_cache;
Point2 touches[32];
Point2i last_click_pos;
@@ -145,7 +145,7 @@ public:
void run_async();
bool main_loop_iterate();
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
new file mode 100644
index 0000000000..ae75a75830
--- /dev/null
+++ b/platform/linuxbsd/SCsub
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+Import("env")
+
+from platform_methods import run_in_subprocess
+import platform_linuxbsd_builders
+
+common_x11 = [
+ "crash_handler_linuxbsd.cpp",
+ "os_linuxbsd.cpp",
+ "joypad_linux.cpp",
+ "context_gl_x11.cpp",
+ "detect_prime_x11.cpp",
+ "display_server_x11.cpp",
+ "vulkan_context_x11.cpp",
+ "key_mapping_x11.cpp",
+]
+
+prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_x11)
+
+if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
+ env.AddPostAction(prog, run_in_subprocess(platform_linuxbsd_builders.make_debug_linuxbsd))
diff --git a/platform/linuxbsd/context_gl_x11.cpp b/platform/linuxbsd/context_gl_x11.cpp
new file mode 100644
index 0000000000..308d68521a
--- /dev/null
+++ b/platform/linuxbsd/context_gl_x11.cpp
@@ -0,0 +1,265 @@
+/*************************************************************************/
+/* context_gl_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "context_gl_x11.h"
+
+#ifdef X11_ENABLED
+#if defined(OPENGL_ENABLED)
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <GL/glxext.h>
+
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+
+typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
+
+struct ContextGL_X11_Private {
+
+ ::GLXContext glx_context;
+};
+
+void ContextGL_X11::release_current() {
+
+ glXMakeCurrent(x11_display, None, nullptr);
+}
+
+void ContextGL_X11::make_current() {
+
+ glXMakeCurrent(x11_display, x11_window, p->glx_context);
+}
+
+void ContextGL_X11::swap_buffers() {
+
+ glXSwapBuffers(x11_display, x11_window);
+}
+
+static bool ctxErrorOccurred = false;
+static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
+ ctxErrorOccurred = true;
+ return 0;
+}
+
+static void set_class_hint(Display *p_display, Window p_window) {
+ XClassHint *classHint;
+
+ /* set the name and class hints for the window manager to use */
+ classHint = XAllocClassHint();
+ if (classHint) {
+ classHint->res_name = (char *)"Godot_Engine";
+ classHint->res_class = (char *)"Godot";
+ }
+ XSetClassHint(p_display, p_window, classHint);
+ XFree(classHint);
+}
+
+Error ContextGL_X11::initialize() {
+
+ //const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
+
+ GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
+
+ ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED);
+
+ static int visual_attribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_DOUBLEBUFFER, true,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 24,
+ None
+ };
+
+ static int visual_attribs_layered[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_DOUBLEBUFFER, true,
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, 8,
+ GLX_DEPTH_SIZE, 24,
+ None
+ };
+
+ int fbcount;
+ GLXFBConfig fbconfig = 0;
+ XVisualInfo *vi = nullptr;
+
+ XSetWindowAttributes swa;
+ swa.event_mask = StructureNotifyMask;
+ swa.border_pixel = 0;
+ unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+
+ if (OS::get_singleton()->is_layered_allowed()) {
+ GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
+ ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
+
+ for (int i = 0; i < fbcount; i++) {
+ vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
+ if (!vi)
+ continue;
+
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
+ if (!pict_format) {
+ XFree(vi);
+ vi = nullptr;
+ continue;
+ }
+
+ fbconfig = fbc[i];
+ if (pict_format->direct.alphaMask > 0) {
+ break;
+ }
+ }
+ XFree(fbc);
+ ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
+
+ swa.background_pixmap = None;
+ swa.background_pixel = 0;
+ swa.border_pixmap = None;
+ valuemask |= CWBackPixel;
+
+ } else {
+ GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
+ ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
+
+ vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
+
+ fbconfig = fbc[0];
+ XFree(fbc);
+ }
+
+ int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
+
+ switch (context_type) {
+ case GLES_2_0_COMPATIBLE: {
+
+ p->glx_context = glXCreateNewContext(x11_display, fbconfig, GLX_RGBA_TYPE, 0, true);
+ ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
+ } break;
+ }
+
+ swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
+ x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
+ XStoreName(x11_display, x11_window, "Godot Engine");
+
+ ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
+ set_class_hint(x11_display, x11_window);
+ XMapWindow(x11_display, x11_window);
+
+ XSync(x11_display, False);
+ XSetErrorHandler(oldHandler);
+
+ glXMakeCurrent(x11_display, x11_window, p->glx_context);
+
+ XFree(vi);
+
+ return OK;
+}
+
+int ContextGL_X11::get_window_width() {
+
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, x11_window, &xwa);
+
+ return xwa.width;
+}
+
+int ContextGL_X11::get_window_height() {
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, x11_window, &xwa);
+
+ return xwa.height;
+}
+
+void ContextGL_X11::set_use_vsync(bool p_use) {
+ static bool setup = false;
+ static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr;
+ static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr;
+
+ if (!setup) {
+ setup = true;
+ String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
+ if (extensions.find("GLX_EXT_swap_control") != -1)
+ glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
+ if (extensions.find("GLX_MESA_swap_control") != -1)
+ glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
+ if (extensions.find("GLX_SGI_swap_control") != -1)
+ glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
+ }
+ int val = p_use ? 1 : 0;
+ if (glXSwapIntervalMESA) {
+ glXSwapIntervalMESA(val);
+ } else if (glXSwapIntervalSGI) {
+ glXSwapIntervalSGI(val);
+ } else if (glXSwapIntervalEXT) {
+ GLXDrawable drawable = glXGetCurrentDrawable();
+ glXSwapIntervalEXT(x11_display, drawable, val);
+ } else
+ return;
+ use_vsync = p_use;
+}
+bool ContextGL_X11::is_using_vsync() const {
+
+ return use_vsync;
+}
+
+ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type) :
+ x11_window(p_x11_window) {
+
+ default_video_mode = p_default_video_mode;
+ x11_display = p_x11_display;
+
+ context_type = p_context_type;
+
+ double_buffer = false;
+ direct_render = false;
+ glx_minor = glx_major = 0;
+ p = memnew(ContextGL_X11_Private);
+ p->glx_context = 0;
+ use_vsync = false;
+}
+
+ContextGL_X11::~ContextGL_X11() {
+ release_current();
+ glXDestroyContext(x11_display, p->glx_context);
+ memdelete(p);
+}
+
+#endif
+#endif
diff --git a/platform/x11/context_gl_x11.h b/platform/linuxbsd/context_gl_x11.h
index 2c0643c95a..2c0643c95a 100644
--- a/platform/x11/context_gl_x11.h
+++ b/platform/linuxbsd/context_gl_x11.h
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
new file mode 100644
index 0000000000..dbdb15918e
--- /dev/null
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -0,0 +1,149 @@
+/*************************************************************************/
+/* crash_handler_linuxbsd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "crash_handler_linuxbsd.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+#include "main/main.h"
+
+#ifdef DEBUG_ENABLED
+#define CRASH_HANDLER_ENABLED 1
+#endif
+
+#ifdef CRASH_HANDLER_ENABLED
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void handle_crash(int sig) {
+ if (OS::get_singleton() == nullptr) {
+ abort();
+ }
+
+ void *bt_buffer[256];
+ size_t size = backtrace(bt_buffer, 256);
+ String _execpath = OS::get_singleton()->get_executable_path();
+
+ String msg;
+ const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
+ if (proj_settings) {
+ msg = proj_settings->get("debug/settings/crash_handler/message");
+ }
+
+ // Dump the backtrace to stderr with a message to the user
+ fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
+
+ if (OS::get_singleton()->get_main_loop())
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
+
+ fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ char **strings = backtrace_symbols(bt_buffer, size);
+ if (strings) {
+ for (size_t i = 1; i < size; i++) {
+ char fname[1024];
+ Dl_info info;
+
+ snprintf(fname, 1024, "%s", strings[i]);
+
+ // Try to demangle the function name to provide a more readable one
+ if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
+ if (info.dli_sname[0] == '_') {
+ int status;
+ char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
+
+ if (status == 0 && demangled) {
+ snprintf(fname, 1024, "%s", demangled);
+ }
+
+ if (demangled)
+ free(demangled);
+ }
+ }
+
+ List<String> args;
+
+ char str[1024];
+ snprintf(str, 1024, "%p", bt_buffer[i]);
+ args.push_back(str);
+ args.push_back("-e");
+ args.push_back(_execpath);
+
+ String output = "";
+
+ // Try to get the file/line number using addr2line
+ int ret;
+ Error err = OS::get_singleton()->execute(String("addr2line"), args, true, nullptr, &output, &ret);
+ if (err == OK) {
+ output.erase(output.length() - 1, 1);
+ }
+
+ fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str());
+ }
+
+ free(strings);
+ }
+ fprintf(stderr, "-- END OF BACKTRACE --\n");
+
+ // Abort to pass the error to the OS
+ abort();
+}
+#endif
+
+CrashHandler::CrashHandler() {
+ disabled = false;
+}
+
+CrashHandler::~CrashHandler() {
+ disable();
+}
+
+void CrashHandler::disable() {
+ if (disabled)
+ return;
+
+#ifdef CRASH_HANDLER_ENABLED
+ signal(SIGSEGV, nullptr);
+ signal(SIGFPE, nullptr);
+ signal(SIGILL, nullptr);
+#endif
+
+ disabled = true;
+}
+
+void CrashHandler::initialize() {
+#ifdef CRASH_HANDLER_ENABLED
+ signal(SIGSEGV, handle_crash);
+ signal(SIGFPE, handle_crash);
+ signal(SIGILL, handle_crash);
+#endif
+}
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.h b/platform/linuxbsd/crash_handler_linuxbsd.h
new file mode 100644
index 0000000000..94b4649690
--- /dev/null
+++ b/platform/linuxbsd/crash_handler_linuxbsd.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* crash_handler_linuxbsd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CRASH_HANDLER_X11_H
+#define CRASH_HANDLER_X11_H
+
+class CrashHandler {
+
+ bool disabled;
+
+public:
+ void initialize();
+
+ void disable();
+ bool is_disabled() const { return disabled; };
+
+ CrashHandler();
+ ~CrashHandler();
+};
+
+#endif // CRASH_HANDLER_X11_H
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
new file mode 100644
index 0000000000..5d8b4fba48
--- /dev/null
+++ b/platform/linuxbsd/detect.py
@@ -0,0 +1,377 @@
+import os
+import platform
+import sys
+
+
+def is_active():
+ return True
+
+
+def get_name():
+ return "LinuxBSD"
+
+
+def can_build():
+
+ if os.name != "posix" or sys.platform == "darwin":
+ return False
+
+ # Check the minimal dependencies
+ x11_error = os.system("pkg-config --version > /dev/null")
+ if x11_error:
+ return False
+
+ x11_error = os.system("pkg-config x11 --modversion > /dev/null ")
+ if x11_error:
+ return False
+
+ x11_error = os.system("pkg-config xcursor --modversion > /dev/null ")
+ if x11_error:
+ print("xcursor not found.. x11 disabled.")
+ return False
+
+ x11_error = os.system("pkg-config xinerama --modversion > /dev/null ")
+ if x11_error:
+ print("xinerama not found.. x11 disabled.")
+ return False
+
+ x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
+ if x11_error:
+ print("xrandr not found.. x11 disabled.")
+ return False
+
+ x11_error = os.system("pkg-config xrender --modversion > /dev/null ")
+ if x11_error:
+ print("xrender not found.. x11 disabled.")
+ return False
+
+ x11_error = os.system("pkg-config xi --modversion > /dev/null ")
+ if x11_error:
+ print("xi not found.. Aborting.")
+ return False
+
+ return True
+
+
+def get_opts():
+ from SCons.Variables import BoolVariable, EnumVariable
+
+ return [
+ BoolVariable("use_llvm", "Use the LLVM compiler", False),
+ BoolVariable("use_lld", "Use the LLD linker", False),
+ BoolVariable("use_thinlto", "Use ThinLTO", False),
+ BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", False),
+ 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("pulseaudio", "Detect and use PulseAudio", True),
+ BoolVariable("udev", "Use udev for gamepad connection callbacks", False),
+ EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
+ BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
+ BoolVariable("touch", "Enable touch events", True),
+ BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
+ ]
+
+
+def get_flags():
+
+ return []
+
+
+def configure(env):
+
+ ## Build type
+
+ if env["target"] == "release":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Prepend(CCFLAGS=["-O3"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "release_debug":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Prepend(CCFLAGS=["-O2"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+ env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
+
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "debug":
+ env.Prepend(CCFLAGS=["-g3"])
+ env.Prepend(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
+ env.Append(LINKFLAGS=["-rdynamic"])
+
+ ## Architecture
+
+ is64 = sys.maxsize > 2 ** 32
+ if env["bits"] == "default":
+ env["bits"] = "64" if is64 else "32"
+
+ ## Compiler configuration
+
+ if "CXX" in env and "clang" in os.path.basename(env["CXX"]):
+ # Convenience check to enforce the use_llvm overrides when CXX is clang(++)
+ env["use_llvm"] = True
+
+ if env["use_llvm"]:
+ if "clang++" not in os.path.basename(env["CXX"]):
+ env["CC"] = "clang"
+ env["CXX"] = "clang++"
+ env["LINK"] = "clang++"
+ env.Append(CPPDEFINES=["TYPED_METHOD_BIND"])
+ env.extra_suffix = ".llvm" + env.extra_suffix
+
+ if env["use_lld"]:
+ if env["use_llvm"]:
+ env.Append(LINKFLAGS=["-fuse-ld=lld"])
+ if env["use_thinlto"]:
+ # A convenience so you don't need to write use_lto too when using SCons
+ env["use_lto"] = True
+ else:
+ print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
+ sys.exit(255)
+
+ 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"]:
+ env.extra_suffix += "s"
+
+ if env["use_ubsan"]:
+ env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(LINKFLAGS=["-fsanitize=undefined"])
+
+ if env["use_asan"]:
+ env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(LINKFLAGS=["-fsanitize=address"])
+
+ if env["use_lsan"]:
+ env.Append(CCFLAGS=["-fsanitize=leak"])
+ env.Append(LINKFLAGS=["-fsanitize=leak"])
+
+ if env["use_tsan"]:
+ env.Append(CCFLAGS=["-fsanitize=thread"])
+ env.Append(LINKFLAGS=["-fsanitize=thread"])
+
+ if env["use_lto"]:
+ if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
+ env.Append(CCFLAGS=["-flto"])
+ env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
+ else:
+ if env["use_lld"] and env["use_thinlto"]:
+ env.Append(CCFLAGS=["-flto=thin"])
+ env.Append(LINKFLAGS=["-flto=thin"])
+ else:
+ env.Append(CCFLAGS=["-flto"])
+ env.Append(LINKFLAGS=["-flto"])
+
+ if not env["use_llvm"]:
+ env["RANLIB"] = "gcc-ranlib"
+ env["AR"] = "gcc-ar"
+
+ env.Append(CCFLAGS=["-pipe"])
+ env.Append(LINKFLAGS=["-pipe"])
+
+ # -fpie and -no-pie is supported on GCC 6+ and Clang 4+, both below our
+ # minimal requirements.
+ env.Append(CCFLAGS=["-fpie"])
+ env.Append(LINKFLAGS=["-no-pie"])
+
+ ## Dependencies
+
+ env.ParseConfig("pkg-config x11 --cflags --libs")
+ env.ParseConfig("pkg-config xcursor --cflags --libs")
+ env.ParseConfig("pkg-config xinerama --cflags --libs")
+ env.ParseConfig("pkg-config xrandr --cflags --libs")
+ env.ParseConfig("pkg-config xrender --cflags --libs")
+ env.ParseConfig("pkg-config xi --cflags --libs")
+
+ if env["touch"]:
+ env.Append(CPPDEFINES=["TOUCH_ENABLED"])
+
+ # FIXME: Check for existence of the libs before parsing their flags with pkg-config
+
+ # freetype depends on libpng and zlib, so bundling one of them while keeping others
+ # as shared libraries leads to weird issues
+ if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ env["builtin_freetype"] = True
+ env["builtin_libpng"] = True
+ env["builtin_zlib"] = True
+
+ if not env["builtin_freetype"]:
+ env.ParseConfig("pkg-config freetype2 --cflags --libs")
+
+ if not env["builtin_libpng"]:
+ env.ParseConfig("pkg-config libpng16 --cflags --libs")
+
+ if not env["builtin_bullet"]:
+ # We need at least version 2.89
+ import subprocess
+
+ bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip()
+ if str(bullet_version) < "2.89":
+ # Abort as system bullet was requested but too old
+ print(
+ "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(
+ bullet_version, "2.89"
+ )
+ )
+ sys.exit(255)
+ env.ParseConfig("pkg-config bullet --cflags --libs")
+
+ if False: # not env['builtin_assimp']:
+ # FIXME: Add min version check
+ env.ParseConfig("pkg-config assimp --cflags --libs")
+
+ if not env["builtin_enet"]:
+ env.ParseConfig("pkg-config libenet --cflags --libs")
+
+ if not env["builtin_squish"]:
+ env.ParseConfig("pkg-config libsquish --cflags --libs")
+
+ if not env["builtin_zstd"]:
+ env.ParseConfig("pkg-config libzstd --cflags --libs")
+
+ # Sound and video libraries
+ # Keep the order as it triggers chained dependencies (ogg needed by others, etc.)
+
+ if not env["builtin_libtheora"]:
+ env["builtin_libogg"] = False # Needed to link against system libtheora
+ env["builtin_libvorbis"] = False # Needed to link against system libtheora
+ env.ParseConfig("pkg-config theora theoradec --cflags --libs")
+ else:
+ list_of_x86 = ["x86_64", "x86", "i386", "i586"]
+ if any(platform.machine() in s for s in list_of_x86):
+ env["x86_libtheora_opt_gcc"] = True
+
+ if not env["builtin_libvpx"]:
+ env.ParseConfig("pkg-config vpx --cflags --libs")
+
+ if not env["builtin_libvorbis"]:
+ env["builtin_libogg"] = False # Needed to link against system libvorbis
+ env.ParseConfig("pkg-config vorbis vorbisfile --cflags --libs")
+
+ if not env["builtin_opus"]:
+ env["builtin_libogg"] = False # Needed to link against system opus
+ env.ParseConfig("pkg-config opus opusfile --cflags --libs")
+
+ if not env["builtin_libogg"]:
+ env.ParseConfig("pkg-config ogg --cflags --libs")
+
+ if not env["builtin_libwebp"]:
+ env.ParseConfig("pkg-config libwebp --cflags --libs")
+
+ if not env["builtin_mbedtls"]:
+ # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
+ env.Append(LIBS=["mbedtls", "mbedcrypto", "mbedx509"])
+
+ if not env["builtin_wslay"]:
+ env.ParseConfig("pkg-config libwslay --cflags --libs")
+
+ if not env["builtin_miniupnpc"]:
+ # No pkgconfig file so far, hardcode default paths.
+ env.Prepend(CPPPATH=["/usr/include/miniupnpc"])
+ env.Append(LIBS=["miniupnpc"])
+
+ # On Linux wchar_t should be 32-bits
+ # 16-bit library shouldn't be required due to compiler optimisations
+ if not env["builtin_pcre2"]:
+ env.ParseConfig("pkg-config libpcre2-32 --cflags --libs")
+
+ ## Flags
+
+ if os.system("pkg-config --exists alsa") == 0: # 0 means found
+ print("Enabling ALSA")
+ 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")
+
+ if env["pulseaudio"]:
+ 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")
+ 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")
+
+ # Linkflags below this line should typically stay the last ones
+ if not env["builtin_zlib"]:
+ env.ParseConfig("pkg-config zlib --cflags --libs")
+
+ env.Prepend(CPPPATH=["#platform/linuxbsd"])
+ env.Append(CPPDEFINES=["X11_ENABLED", "UNIX_ENABLED"])
+
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["builtin_vulkan"]:
+ env.ParseConfig("pkg-config vulkan --cflags --libs")
+ if not env["builtin_glslang"]:
+ # No pkgconfig file for glslang so far
+ env.Append(LIBS=["glslang", "SPIRV"])
+
+ # env.Append(CPPDEFINES=['OPENGL_ENABLED'])
+ env.Append(LIBS=["GL"])
+
+ env.Append(LIBS=["pthread"])
+
+ if platform.system() == "Linux":
+ env.Append(LIBS=["dl"])
+
+ if platform.system().find("BSD") >= 0:
+ env["execinfo"] = True
+
+ if env["execinfo"]:
+ env.Append(LIBS=["execinfo"])
+
+ if not env["tools"]:
+ import subprocess
+ import re
+
+ linker_version_str = subprocess.check_output([env.subst(env["LINK"]), "-Wl,--version"]).decode("utf-8")
+ gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE)
+ if not gnu_ld_version:
+ print(
+ "Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld"
+ )
+ else:
+ if float(gnu_ld_version.group(1)) >= 2.30:
+ env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.ld"])
+ else:
+ env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"])
+
+ ## Cross-compilation
+
+ if is64 and env["bits"] == "32":
+ env.Append(CCFLAGS=["-m32"])
+ env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"])
+ elif not is64 and env["bits"] == "64":
+ env.Append(CCFLAGS=["-m64"])
+ env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"])
+
+ # Link those statically for portability
+ if env["use_static_cpp"]:
+ env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp
new file mode 100644
index 0000000000..1bec65ff04
--- /dev/null
+++ b/platform/linuxbsd/detect_prime_x11.cpp
@@ -0,0 +1,238 @@
+/*************************************************************************/
+/* detect_prime_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 X11_ENABLED
+#if defined(OPENGL_ENABLED)
+
+#include "detect_prime.h"
+
+#include "core/print_string.h"
+#include "core/ustring.h"
+
+#include <stdlib.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
+
+typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
+
+struct vendor {
+ const char *glxvendor;
+ int priority;
+};
+
+vendor vendormap[] = {
+ { "Advanced Micro Devices, Inc.", 30 },
+ { "NVIDIA Corporation", 30 },
+ { "X.Org", 30 },
+ { "Intel Open Source Technology Center", 20 },
+ { "Intel", 20 },
+ { "nouveau", 10 },
+ { "Mesa Project", 0 },
+ { nullptr, 0 }
+};
+
+// Runs inside a child. Exiting will not quit the engine.
+void create_context() {
+ Display *x11_display = XOpenDisplay(nullptr);
+ Window x11_window;
+ GLXContext glx_context;
+
+ GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
+
+ static int visual_attribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_DOUBLEBUFFER, true,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DEPTH_SIZE, 24,
+ None
+ };
+
+ int fbcount;
+ GLXFBConfig fbconfig = 0;
+ XVisualInfo *vi = nullptr;
+
+ XSetWindowAttributes swa;
+ swa.event_mask = StructureNotifyMask;
+ swa.border_pixel = 0;
+ unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+
+ GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
+ if (!fbc)
+ exit(1);
+
+ vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
+
+ fbconfig = fbc[0];
+
+ static int context_attribs[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 3,
+ GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+ GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+ None
+ };
+
+ glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs);
+
+ swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
+ x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
+
+ if (!x11_window)
+ exit(1);
+
+ glXMakeCurrent(x11_display, x11_window, glx_context);
+ XFree(vi);
+}
+
+int detect_prime() {
+ pid_t p;
+ int priorities[2];
+ String vendors[2];
+ String renderers[2];
+
+ vendors[0] = "Unknown";
+ vendors[1] = "Unknown";
+ renderers[0] = "Unknown";
+ renderers[1] = "Unknown";
+
+ for (int i = 0; i < 2; ++i) {
+ int fdset[2];
+
+ if (pipe(fdset) == -1) {
+ print_verbose("Failed to pipe(), using default GPU");
+ return 0;
+ }
+
+ // Fork so the driver initialization can crash without taking down the engine.
+ p = fork();
+
+ if (p > 0) {
+ // Main thread
+
+ int stat_loc = 0;
+ char string[201];
+ string[200] = '\0';
+
+ close(fdset[1]);
+
+ waitpid(p, &stat_loc, 0);
+
+ if (!stat_loc) {
+ // No need to do anything complicated here. Anything less than
+ // PIPE_BUF will be delivered in one read() call.
+ // Leave it 'Unknown' otherwise.
+ if (read(fdset[0], string, sizeof(string) - 1) > 0) {
+ vendors[i] = string;
+ renderers[i] = string + strlen(string) + 1;
+ }
+ }
+
+ close(fdset[0]);
+
+ } else {
+ // In child, exit() here will not quit the engine.
+
+ char string[201];
+
+ close(fdset[0]);
+
+ if (i) setenv("DRI_PRIME", "1", 1);
+ create_context();
+
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ const char *renderer = (const char *)glGetString(GL_RENDERER);
+
+ unsigned int vendor_len = strlen(vendor) + 1;
+ unsigned int renderer_len = strlen(renderer) + 1;
+
+ if (vendor_len + renderer_len >= sizeof(string)) {
+ renderer_len = 200 - vendor_len;
+ }
+
+ memcpy(&string, vendor, vendor_len);
+ memcpy(&string[vendor_len], renderer, renderer_len);
+
+ if (write(fdset[1], string, vendor_len + renderer_len) == -1) {
+ print_verbose("Couldn't write vendor/renderer string.");
+ }
+ close(fdset[1]);
+ exit(0);
+ }
+ }
+
+ int preferred = 0;
+ int priority = 0;
+
+ if (vendors[0] == vendors[1]) {
+ print_verbose("Only one GPU found, using default.");
+ return 0;
+ }
+
+ for (int i = 1; i >= 0; --i) {
+ vendor *v = vendormap;
+ while (v->glxvendor) {
+ if (v->glxvendor == vendors[i]) {
+ priorities[i] = v->priority;
+
+ if (v->priority >= priority) {
+ priority = v->priority;
+ preferred = i;
+ }
+ }
+ ++v;
+ }
+ }
+
+ print_verbose("Found renderers:");
+ for (int i = 0; i < 2; ++i) {
+ print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i]));
+ }
+
+ print_verbose("Using renderer: " + renderers[preferred]);
+ return preferred;
+}
+
+#endif
+#endif
diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h
new file mode 100644
index 0000000000..039bdee76b
--- /dev/null
+++ b/platform/linuxbsd/detect_prime_x11.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* detect_prime_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 X11_ENABLED
+#if defined(OPENGL_ENABLED)
+
+int detect_prime();
+
+#endif
+#endif
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
new file mode 100644
index 0000000000..78ddef5ff6
--- /dev/null
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -0,0 +1,3856 @@
+/*************************************************************************/
+/* display_server_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "display_server_x11.h"
+
+#ifdef X11_ENABLED
+
+#include "detect_prime_x11.h"
+
+#include "core/os/dir_access.h"
+#include "core/print_string.h"
+#include "errno.h"
+#include "key_mapping_x11.h"
+
+#if defined(OPENGL_ENABLED)
+#include "drivers/gles2/rasterizer_gles2.h"
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#endif
+
+#include "scene/resources/texture.h"
+
+#ifdef HAVE_MNTENT
+#include <mntent.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "X11/Xutil.h"
+
+#include "X11/Xatom.h"
+#include "X11/extensions/Xinerama.h"
+// ICCCM
+#define WM_NormalState 1L // window normal state
+#define WM_IconicState 3L // window minimized
+// EWMH
+#define _NET_WM_STATE_REMOVE 0L // remove/unset property
+#define _NET_WM_STATE_ADD 1L // add/set property
+#define _NET_WM_STATE_TOGGLE 2L // toggle property
+
+#include "main/main.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+//stupid linux.h
+#ifdef KEY_TAB
+#undef KEY_TAB
+#endif
+
+#include <X11/Xatom.h>
+
+#undef CursorShape
+
+#include <X11/XKBlib.h>
+
+#include "core/project_settings.h"
+
+// 2.2 is the first release with multitouch
+#define XINPUT_CLIENT_VERSION_MAJOR 2
+#define XINPUT_CLIENT_VERSION_MINOR 2
+
+#define VALUATOR_ABSX 0
+#define VALUATOR_ABSY 1
+#define VALUATOR_PRESSURE 2
+#define VALUATOR_TILTX 3
+#define VALUATOR_TILTY 4
+
+static const double abs_resolution_mult = 10000.0;
+static const double abs_resolution_range_mult = 10.0;
+
+bool DisplayServerX11::has_feature(Feature p_feature) const {
+ switch (p_feature) {
+ case FEATURE_SUBWINDOWS:
+#ifdef TOUCH_ENABLED
+ case FEATURE_TOUCHSCREEN:
+#endif
+ case FEATURE_MOUSE:
+ case FEATURE_MOUSE_WARP:
+ case FEATURE_CLIPBOARD:
+ case FEATURE_CURSOR_SHAPE:
+ case FEATURE_CUSTOM_CURSOR_SHAPE:
+ case FEATURE_IME:
+ case FEATURE_WINDOW_TRANSPARENCY:
+ //case FEATURE_HIDPI:
+ case FEATURE_ICON:
+ case FEATURE_NATIVE_ICON:
+ case FEATURE_SWAP_BUFFERS:
+ return true;
+ default: {
+ }
+ }
+
+ return false;
+}
+String DisplayServerX11::get_name() const {
+ return "X11";
+}
+
+void DisplayServerX11::alert(const String &p_alert, const String &p_title) {
+ const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" };
+
+ String path = OS::get_singleton()->get_environment("PATH");
+ Vector<String> path_elems = path.split(":", false);
+ String program;
+
+ for (int i = 0; i < path_elems.size(); i++) {
+ for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
+ String tested_path = path_elems[i].plus_file(message_programs[k]);
+
+ if (FileAccess::exists(tested_path)) {
+ program = tested_path;
+ break;
+ }
+ }
+
+ if (program.length())
+ break;
+ }
+
+ List<String> args;
+
+ if (program.ends_with("zenity")) {
+ args.push_back("--error");
+ args.push_back("--width");
+ args.push_back("500");
+ args.push_back("--title");
+ args.push_back(p_title);
+ args.push_back("--text");
+ args.push_back(p_alert);
+ }
+
+ if (program.ends_with("kdialog")) {
+ args.push_back("--error");
+ args.push_back(p_alert);
+ args.push_back("--title");
+ args.push_back(p_title);
+ }
+
+ if (program.ends_with("Xdialog")) {
+ args.push_back("--title");
+ args.push_back(p_title);
+ args.push_back("--msgbox");
+ args.push_back(p_alert);
+ args.push_back("0");
+ args.push_back("0");
+ }
+
+ if (program.ends_with("xmessage")) {
+ args.push_back("-center");
+ args.push_back("-title");
+ args.push_back(p_title);
+ args.push_back(p_alert);
+ }
+
+ if (program.length()) {
+ OS::get_singleton()->execute(program, args, true);
+ } else {
+ print_line(p_alert);
+ }
+}
+
+void DisplayServerX11::_update_real_mouse_position(const WindowData &wd) {
+ Window root_return, child_return;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask_return;
+
+ Bool xquerypointer_result = XQueryPointer(x11_display, wd.x11_window, &root_return, &child_return, &root_x, &root_y,
+ &win_x, &win_y, &mask_return);
+
+ if (xquerypointer_result) {
+ if (win_x > 0 && win_y > 0 && win_x <= wd.size.width && win_y <= wd.size.height) {
+
+ last_mouse_pos.x = win_x;
+ last_mouse_pos.y = win_y;
+ last_mouse_pos_valid = true;
+ InputFilter::get_singleton()->set_mouse_position(last_mouse_pos);
+ }
+ }
+}
+
+bool DisplayServerX11::_refresh_device_info() {
+ int event_base, error_base;
+
+ print_verbose("XInput: Refreshing devices.");
+
+ if (!XQueryExtension(x11_display, "XInputExtension", &xi.opcode, &event_base, &error_base)) {
+ print_verbose("XInput extension not available. Please upgrade your distribution.");
+ return false;
+ }
+
+ int xi_major_query = XINPUT_CLIENT_VERSION_MAJOR;
+ int xi_minor_query = XINPUT_CLIENT_VERSION_MINOR;
+
+ if (XIQueryVersion(x11_display, &xi_major_query, &xi_minor_query) != Success) {
+ print_verbose(vformat("XInput 2 not available (server supports %d.%d).", xi_major_query, xi_minor_query));
+ xi.opcode = 0;
+ return false;
+ }
+
+ if (xi_major_query < XINPUT_CLIENT_VERSION_MAJOR || (xi_major_query == XINPUT_CLIENT_VERSION_MAJOR && xi_minor_query < XINPUT_CLIENT_VERSION_MINOR)) {
+ print_verbose(vformat("XInput %d.%d not available (server supports %d.%d). Touch input unavailable.",
+ XINPUT_CLIENT_VERSION_MAJOR, XINPUT_CLIENT_VERSION_MINOR, xi_major_query, xi_minor_query));
+ }
+
+ xi.absolute_devices.clear();
+ xi.touch_devices.clear();
+
+ int dev_count;
+ XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
+
+ for (int i = 0; i < dev_count; i++) {
+ XIDeviceInfo *dev = &info[i];
+ if (!dev->enabled)
+ continue;
+ if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave))
+ continue;
+
+ bool direct_touch = false;
+ bool absolute_mode = false;
+ int resolution_x = 0;
+ int resolution_y = 0;
+ double range_min_x = 0;
+ double range_min_y = 0;
+ double range_max_x = 0;
+ double range_max_y = 0;
+ int pressure_resolution = 0;
+ int tilt_resolution_x = 0;
+ int tilt_resolution_y = 0;
+ for (int j = 0; j < dev->num_classes; j++) {
+#ifdef TOUCH_ENABLED
+ if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
+ direct_touch = true;
+ }
+#endif
+ if (dev->classes[j]->type == XIValuatorClass) {
+ XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j];
+
+ if (class_info->number == VALUATOR_ABSX && class_info->mode == XIModeAbsolute) {
+ resolution_x = class_info->resolution;
+ range_min_x = class_info->min;
+ range_max_x = class_info->max;
+ absolute_mode = true;
+ } else if (class_info->number == VALUATOR_ABSY && class_info->mode == XIModeAbsolute) {
+ resolution_y = class_info->resolution;
+ range_min_y = class_info->min;
+ range_max_y = class_info->max;
+ absolute_mode = true;
+ } else if (class_info->number == VALUATOR_PRESSURE && class_info->mode == XIModeAbsolute) {
+ pressure_resolution = (class_info->max - class_info->min);
+ if (pressure_resolution == 0) pressure_resolution = 1;
+ } else if (class_info->number == VALUATOR_TILTX && class_info->mode == XIModeAbsolute) {
+ tilt_resolution_x = (class_info->max - class_info->min);
+ if (tilt_resolution_x == 0) tilt_resolution_x = 1;
+ } else if (class_info->number == VALUATOR_TILTY && class_info->mode == XIModeAbsolute) {
+ tilt_resolution_y = (class_info->max - class_info->min);
+ if (tilt_resolution_y == 0) tilt_resolution_y = 1;
+ }
+ }
+ }
+ if (direct_touch) {
+ xi.touch_devices.push_back(dev->deviceid);
+ print_verbose("XInput: Using touch device: " + String(dev->name));
+ }
+ if (absolute_mode) {
+ // If no resolution was reported, use the min/max ranges.
+ if (resolution_x <= 0) {
+ resolution_x = (range_max_x - range_min_x) * abs_resolution_range_mult;
+ }
+ if (resolution_y <= 0) {
+ resolution_y = (range_max_y - range_min_y) * abs_resolution_range_mult;
+ }
+
+ xi.absolute_devices[dev->deviceid] = Vector2(abs_resolution_mult / resolution_x, abs_resolution_mult / resolution_y);
+ print_verbose("XInput: Absolute pointing device: " + String(dev->name));
+ }
+
+ xi.pressure = 0;
+ xi.pen_devices[dev->deviceid] = Vector3(pressure_resolution, tilt_resolution_x, tilt_resolution_y);
+ }
+
+ XIFreeDeviceInfo(info);
+#ifdef TOUCH_ENABLED
+ if (!xi.touch_devices.size()) {
+ print_verbose("XInput: No touch devices found.");
+ }
+#endif
+
+ return true;
+}
+
+void DisplayServerX11::_flush_mouse_motion() {
+ while (true) {
+ if (XPending(x11_display) > 0) {
+ XEvent event;
+ XPeekEvent(x11_display, &event);
+
+ if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
+ XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+
+ if (event_data->evtype == XI_RawMotion) {
+ XNextEvent(x11_display, &event);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ xi.relative_motion.x = 0;
+ xi.relative_motion.y = 0;
+}
+
+void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (p_mode == mouse_mode)
+ return;
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED)
+ XUngrabPointer(x11_display, CurrentTime);
+
+ // The only modes that show a cursor are VISIBLE and CONFINED
+ bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+
+ if (showCursor) {
+ XDefineCursor(x11_display, E->get().x11_window, cursors[current_cursor]); // show cursor
+ } else {
+ XDefineCursor(x11_display, E->get().x11_window, null_cursor); // hide cursor
+ }
+ }
+ mouse_mode = p_mode;
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
+
+ //flush pending motion events
+ _flush_mouse_motion();
+ WindowData &main_window = windows[MAIN_WINDOW_ID];
+
+ if (XGrabPointer(
+ x11_display, main_window.x11_window, True,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, windows[MAIN_WINDOW_ID].x11_window, None, CurrentTime) != GrabSuccess) {
+ ERR_PRINT("NO GRAB");
+ }
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ center.x = main_window.size.width / 2;
+ center.y = main_window.size.height / 2;
+
+ XWarpPointer(x11_display, None, main_window.x11_window,
+ 0, 0, 0, 0, (int)center.x, (int)center.y);
+
+ InputFilter::get_singleton()->set_mouse_position(center);
+ }
+ } else {
+ do_mouse_warp = false;
+ }
+
+ XFlush(x11_display);
+}
+DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode() const {
+ return mouse_mode;
+}
+
+void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+
+ last_mouse_pos = p_to;
+ } else {
+
+ /*XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display, x11_window, &xwa);
+ printf("%d %d\n", xwa.x, xwa.y); needed? */
+
+ XWarpPointer(x11_display, None, windows[MAIN_WINDOW_ID].x11_window,
+ 0, 0, 0, 0, (int)p_to.x, (int)p_to.y);
+ }
+}
+
+Point2i DisplayServerX11::mouse_get_position() const {
+ return last_mouse_pos;
+}
+
+Point2i DisplayServerX11::mouse_get_absolute_position() const {
+ int number_of_screens = XScreenCount(x11_display);
+ for (int i = 0; i < number_of_screens; i++) {
+ Window root, child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
+ XWindowAttributes root_attrs;
+ XGetWindowAttributes(x11_display, root, &root_attrs);
+
+ return Vector2i(root_attrs.x + root_x, root_attrs.y + root_y);
+ }
+ }
+ return Vector2i();
+}
+
+int DisplayServerX11::mouse_get_button_state() const {
+ return last_button_state;
+}
+
+void DisplayServerX11::clipboard_set(const String &p_text) {
+
+ _THREAD_SAFE_METHOD_
+
+ internal_clipboard = p_text;
+ XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
+ XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
+}
+
+static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) {
+
+ String ret;
+
+ Atom type;
+ Atom selection = XA_PRIMARY;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ unsigned char *data;
+ Window Sown = XGetSelectionOwner(x11_display, p_source);
+
+ if (Sown == x11_window) {
+
+ return p_internal_clipboard;
+ };
+
+ if (Sown != None) {
+ XConvertSelection(x11_display, p_source, target, selection,
+ x11_window, CurrentTime);
+ XFlush(x11_display);
+ while (true) {
+ XEvent event;
+ XNextEvent(x11_display, &event);
+ if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
+ break;
+ };
+ };
+
+ //
+ // Do not get any data, see how much data is there
+ //
+ XGetWindowProperty(x11_display, x11_window,
+ selection, // Tricky..
+ 0, 0, // offset - len
+ 0, // Delete 0==FALSE
+ AnyPropertyType, //flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, //that
+ &data);
+ // DATA is There
+ if (bytes_left > 0) {
+ result = XGetWindowProperty(x11_display, x11_window,
+ selection, 0, bytes_left, 0,
+ AnyPropertyType, &type, &format,
+ &len, &dummy, &data);
+ if (result == Success) {
+ ret.parse_utf8((const char *)data);
+ } else
+ printf("FAIL\n");
+ if (data) {
+ XFree(data);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static String _clipboard_get(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+ String ret;
+ Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
+ if (utf8_atom != None) {
+ ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom);
+ }
+ if (ret == "") {
+ ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING);
+ }
+ return ret;
+}
+
+String DisplayServerX11::clipboard_get() const {
+
+ _THREAD_SAFE_METHOD_
+
+ String ret;
+ ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard);
+
+ if (ret == "") {
+ ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard);
+ };
+
+ return ret;
+}
+
+int DisplayServerX11::get_screen_count() const {
+
+ _THREAD_SAFE_METHOD_
+
+ // Using Xinerama Extension
+ int event_base, error_base;
+ const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+ if (!ext_okay) return 0;
+
+ int count;
+ XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ XFree(xsi);
+ return count;
+}
+Point2i DisplayServerX11::screen_get_position(int p_screen) const {
+
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ // Using Xinerama Extension
+ int event_base, error_base;
+ const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+ if (!ext_okay) {
+ return Point2i(0, 0);
+ }
+
+ int count;
+ XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ if (p_screen >= count) {
+ return Point2i(0, 0);
+ }
+
+ Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
+
+ XFree(xsi);
+
+ return position;
+}
+
+Size2i DisplayServerX11::screen_get_size(int p_screen) const {
+ return screen_get_usable_rect(p_screen).size;
+}
+
+Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ // Using Xinerama Extension
+ int event_base, error_base;
+ const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+ if (!ext_okay) return Rect2i(0, 0, 0, 0);
+
+ int count;
+ XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+ if (p_screen >= count) return 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);
+ return rect;
+}
+
+int DisplayServerX11::screen_get_dpi(int p_screen) const {
+
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ //invalid screen?
+ ERR_FAIL_INDEX_V(p_screen, get_screen_count(), 0);
+
+ //Get physical monitor Dimensions through XRandR and calculate dpi
+ Size2i sc = screen_get_size(p_screen);
+ if (xrandr_ext_ok) {
+ int count = 0;
+ if (xrr_get_monitors) {
+ xrr_monitor_info *monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count);
+ if (p_screen < count) {
+ double xdpi = sc.width / (double)monitors[p_screen].mwidth * 25.4;
+ double ydpi = sc.height / (double)monitors[p_screen].mheight * 25.4;
+ xrr_free_monitors(monitors);
+ return (xdpi + ydpi) / 2;
+ }
+ xrr_free_monitors(monitors);
+ } else if (p_screen == 0) {
+ XRRScreenSize *sizes = XRRSizes(x11_display, 0, &count);
+ if (sizes) {
+ double xdpi = sc.width / (double)sizes[0].mwidth * 25.4;
+ double ydpi = sc.height / (double)sizes[0].mheight * 25.4;
+ return (xdpi + ydpi) / 2;
+ }
+ }
+ }
+
+ int width_mm = DisplayWidthMM(x11_display, p_screen);
+ int height_mm = DisplayHeightMM(x11_display, p_screen);
+ double xdpi = (width_mm ? sc.width / (double)width_mm * 25.4 : 0);
+ double ydpi = (height_mm ? sc.height / (double)height_mm * 25.4 : 0);
+ if (xdpi || ydpi)
+ return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1);
+
+ //could not get dpi
+ return 96;
+}
+bool DisplayServerX11::screen_is_touchscreen(int p_screen) const {
+
+ _THREAD_SAFE_METHOD_
+
+#ifndef _MSC_VER
+#warning Need to get from proper window
+#endif
+
+ return DisplayServer::screen_is_touchscreen(p_screen);
+}
+
+Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
+ _THREAD_SAFE_METHOD_
+
+ Vector<int> ret;
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+
+ _THREAD_SAFE_METHOD_
+
+ WindowID id = _create_window(p_mode, p_flags, p_rect);
+ for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+ if (p_flags & (1 << i)) {
+ window_set_flag(WindowFlags(i), true, id);
+ }
+ }
+
+ return id;
+}
+
+void DisplayServerX11::delete_sub_window(WindowID p_id) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_id));
+ ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted"); //ma
+
+ WindowData &wd = windows[p_id];
+
+ while (wd.transient_children.size()) {
+ window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID);
+ }
+
+ if (wd.transient_parent != INVALID_WINDOW_ID) {
+ window_set_transient(p_id, INVALID_WINDOW_ID);
+ }
+
+#ifdef VULKAN_ENABLED
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_destroy(p_id);
+ }
+#endif
+ XUnmapWindow(x11_display, wd.x11_window);
+ XDestroyWindow(x11_display, wd.x11_window);
+ if (wd.xic) {
+ XDestroyIC(wd.xic);
+ }
+
+ windows.erase(p_id);
+}
+
+void DisplayServerX11::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.instance_id = p_instance;
+}
+
+ObjectID DisplayServerX11::window_get_attached_instance_id(WindowID p_window) const {
+
+ ERR_FAIL_COND_V(!windows.has(p_window), ObjectID());
+ const WindowData &wd = windows[p_window];
+ return wd.instance_id;
+}
+
+DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const Point2i &p_position) const {
+
+ return INVALID_WINDOW_ID;
+}
+
+void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ XStoreName(x11_display, wd.x11_window, p_title.utf8().get_data());
+
+ Atom _net_wm_name = XInternAtom(x11_display, "_NET_WM_NAME", false);
+ Atom utf8_string = XInternAtom(x11_display, "UTF8_STRING", false);
+ XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
+}
+
+void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.rect_changed_callback = p_callable;
+}
+
+void DisplayServerX11::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.event_callback = p_callable;
+}
+
+void DisplayServerX11::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.input_event_callback = p_callable;
+}
+void DisplayServerX11::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.input_text_callback = p_callable;
+}
+
+void DisplayServerX11::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.drop_files_callback = p_callable;
+}
+
+int DisplayServerX11::window_get_current_screen(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), -1);
+ const WindowData &wd = windows[p_window];
+
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+
+ int count = get_screen_count();
+ for (int i = 0; i < count; i++) {
+ Point2i pos = screen_get_position(i);
+ Size2i size = screen_get_size(i);
+ if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height))
+ return i;
+ }
+ return 0;
+}
+void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ int count = get_screen_count();
+ if (p_screen >= count) return;
+
+ if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) {
+ Point2i position = screen_get_position(p_screen);
+ Size2i size = screen_get_size(p_screen);
+
+ XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y);
+ } else {
+ if (p_screen != window_get_current_screen(p_window)) {
+ Point2i position = screen_get_position(p_screen);
+ XMoveWindow(x11_display, wd.x11_window, position.x, position.y);
+ }
+ }
+}
+
+void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(p_window == p_parent);
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd_window = windows[p_window];
+
+ ERR_FAIL_COND(wd_window.transient_parent == p_parent);
+
+ ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
+ if (p_parent == INVALID_WINDOW_ID) {
+ //remove transient
+
+ ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
+ ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
+
+ WindowData &wd_parent = windows[wd_window.transient_parent];
+
+ wd_window.transient_parent = INVALID_WINDOW_ID;
+ wd_parent.transient_children.erase(p_window);
+
+ XSetTransientForHint(x11_display, wd_window.x11_window, None);
+ } else {
+ ERR_FAIL_COND(!windows.has(p_parent));
+ ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
+ WindowData &wd_parent = windows[p_parent];
+
+ wd_window.transient_parent = p_parent;
+ wd_parent.transient_children.insert(p_window);
+
+ XSetTransientForHint(x11_display, wd_window.x11_window, wd_parent.x11_window);
+ }
+}
+
+Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
+ const WindowData &wd = windows[p_window];
+
+ return wd.position;
+}
+
+void DisplayServerX11::window_set_position(const Point2i &p_position, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ int x = 0;
+ int y = 0;
+ if (!window_get_flag(WINDOW_FLAG_BORDERLESS, p_window)) {
+ //exclude window decorations
+ XSync(x11_display, False);
+ Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+ if (prop != None) {
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+ if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ if (format == 32 && len == 4 && data) {
+ long *extents = (long *)data;
+ x = extents[0];
+ y = extents[2];
+ }
+ XFree(data);
+ }
+ }
+ }
+ XMoveWindow(x11_display, wd.x11_window, p_position.x - x, p_position.y - y);
+ _update_real_mouse_position(wd);
+}
+
+void DisplayServerX11::window_set_max_size(const Size2i p_size, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
+ ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
+ return;
+ }
+ wd.max_size = p_size;
+
+ if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ xsh->flags = 0L;
+ if (wd.min_size != Size2i()) {
+ xsh->flags |= PMinSize;
+ xsh->min_width = wd.min_size.x;
+ xsh->min_height = wd.min_size.y;
+ }
+ if (wd.max_size != Size2i()) {
+ xsh->flags |= PMaxSize;
+ xsh->max_width = wd.max_size.x;
+ xsh->max_height = wd.max_size.y;
+ }
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+
+ XFlush(x11_display);
+ }
+}
+Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+
+ return wd.max_size;
+}
+
+void DisplayServerX11::window_set_min_size(const Size2i p_size, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
+ ERR_PRINT("Minimum window size can't be larger than maximum window size!");
+ return;
+ }
+ wd.min_size = p_size;
+
+ if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ xsh->flags = 0L;
+ if (wd.min_size != Size2i()) {
+ xsh->flags |= PMinSize;
+ xsh->min_width = wd.min_size.x;
+ xsh->min_height = wd.min_size.y;
+ }
+ if (wd.max_size != Size2i()) {
+ xsh->flags |= PMaxSize;
+ xsh->max_width = wd.max_size.x;
+ xsh->max_height = wd.max_size.y;
+ }
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+
+ XFlush(x11_display);
+ }
+}
+Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+
+ return wd.min_size;
+}
+
+void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+
+ Size2i size = p_size;
+ size.x = MAX(1, size.x);
+ size.y = MAX(1, size.y);
+
+ WindowData &wd = windows[p_window];
+
+ if (wd.size.width == size.width && wd.size.height == size.height)
+ return;
+
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+ int old_w = xwa.width;
+ int old_h = xwa.height;
+
+ // If window resizable is disabled we need to update the attributes first
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+ xsh->flags = PMinSize | PMaxSize;
+ xsh->min_width = size.x;
+ xsh->max_width = size.x;
+ xsh->min_height = size.y;
+ xsh->max_height = size.y;
+ } else {
+ xsh->flags = 0L;
+ if (wd.min_size != Size2i()) {
+ xsh->flags |= PMinSize;
+ xsh->min_width = wd.min_size.x;
+ xsh->min_height = wd.min_size.y;
+ }
+ if (wd.max_size != Size2i()) {
+ xsh->flags |= PMaxSize;
+ xsh->max_width = wd.max_size.x;
+ xsh->max_height = wd.max_size.y;
+ }
+ }
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+
+ // Resize the window
+ XResizeWindow(x11_display, wd.x11_window, size.x, size.y);
+
+ // Update our videomode width and height
+ wd.size = size;
+
+ for (int timeout = 0; timeout < 50; ++timeout) {
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+
+ if (old_w != xwa.width || old_h != xwa.height)
+ break;
+
+ usleep(10000);
+ }
+}
+Size2i DisplayServerX11::window_get_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+ return wd.size;
+}
+Size2i DisplayServerX11::window_get_real_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+ int w = xwa.width;
+ int h = xwa.height;
+ Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+ if (prop != None) {
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+ if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ if (format == 32 && len == 4 && data) {
+ long *extents = (long *)data;
+ w += extents[0] + extents[1]; // left, right
+ h += extents[2] + extents[3]; // top, bottom
+ }
+ XFree(data);
+ }
+ }
+ return Size2i(w, h);
+}
+
+bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+
+ Atom property = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ wd.x11_window,
+ property,
+ 0,
+ 1024,
+ False,
+ XA_ATOM,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success && data) {
+ Atom *atoms = (Atom *)data;
+ Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
+ Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
+ bool found_wm_act_max_horz = false;
+ bool found_wm_act_max_vert = false;
+
+ for (uint64_t i = 0; i < len; i++) {
+ if (atoms[i] == wm_act_max_horz)
+ found_wm_act_max_horz = true;
+ if (atoms[i] == wm_act_max_vert)
+ found_wm_act_max_vert = true;
+
+ if (found_wm_act_max_horz || found_wm_act_max_vert)
+ return true;
+ }
+ XFree(atoms);
+ }
+
+ return false;
+}
+
+void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ // Using EWMH -- Extended Window Manager Hints
+ XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_max_horz;
+ xev.xclient.data.l[2] = wm_max_vert;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ if (p_enabled && window_is_maximize_allowed(p_window)) {
+ // Wait for effective resizing (so the GLX context is too).
+ // Give up after 0.5s, it's not going to happen on this WM.
+ // https://github.com/godotengine/godot/issues/19978
+ for (int attempt = 0; window_get_mode(p_window) != WINDOW_MODE_MAXIMIZED && attempt < 50; attempt++) {
+ usleep(10000);
+ }
+ }
+}
+
+void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if (p_enabled && !window_get_flag(WINDOW_FLAG_BORDERLESS, p_window)) {
+ // remove decorations if the window is not already borderless
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = 0;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+ }
+
+ if (p_enabled && window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+ // Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
+ XSizeHints *xsh;
+
+ xsh = XAllocSizeHints();
+ xsh->flags = 0L;
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+ }
+
+ // Using EWMH -- Extended Window Manager Hints
+ XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_fullscreen;
+ xev.xclient.data.l[2] = 0;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ // set bypass compositor hint
+ Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
+ unsigned long compositing_disable_on = p_enabled ? 1 : 0;
+ XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
+
+ XFlush(x11_display);
+
+ if (!p_enabled) {
+ // Reset the non-resizable flags if we un-set these before.
+ Size2i size = window_get_size(p_window);
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+ xsh->flags = PMinSize | PMaxSize;
+ xsh->min_width = size.x;
+ xsh->max_width = size.x;
+ xsh->min_height = size.y;
+ xsh->max_height = size.y;
+ } else {
+ xsh->flags = 0L;
+ if (wd.min_size != Size2i()) {
+ xsh->flags |= PMinSize;
+ xsh->min_width = wd.min_size.x;
+ xsh->min_height = wd.min_size.y;
+ }
+ if (wd.max_size != Size2i()) {
+ xsh->flags |= PMaxSize;
+ xsh->max_width = wd.max_size.x;
+ xsh->max_height = wd.max_size.y;
+ }
+ }
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+
+ // put back or remove decorations according to the last set borderless state
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = window_get_flag(WINDOW_FLAG_BORDERLESS, p_window) ? 0 : 1;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+ }
+}
+
+void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ WindowMode old_mode = window_get_mode(p_window);
+ if (old_mode == p_mode) {
+ return; // do nothing
+ }
+ //remove all "extra" modes
+
+ switch (old_mode) {
+ case WINDOW_MODE_WINDOWED: {
+ //do nothing
+ } break;
+ case WINDOW_MODE_MINIMIZED: {
+ //Un-Minimize
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ XEvent xev;
+ Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_change;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = WM_NormalState;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+ xev.xclient.data.l[1] = wm_hidden;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ } break;
+ case WINDOW_MODE_FULLSCREEN: {
+ //Remove full-screen
+ _set_wm_fullscreen(p_window, false);
+
+ //un-maximize required for always on top
+ bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window);
+
+ wd.fullscreen = false;
+
+ window_set_position(wd.last_position_before_fs, p_window);
+
+ if (on_top) {
+ _set_wm_maximized(p_window, false);
+ }
+
+ } break;
+ case WINDOW_MODE_MAXIMIZED: {
+
+ _set_wm_maximized(p_window, false);
+ } break;
+ }
+
+ switch (p_mode) {
+ case WINDOW_MODE_WINDOWED: {
+ //do nothing
+ } break;
+ case WINDOW_MODE_MINIMIZED: {
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ XEvent xev;
+ Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_change;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = WM_IconicState;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+ xev.xclient.data.l[1] = wm_hidden;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ } break;
+ case WINDOW_MODE_FULLSCREEN: {
+ wd.last_position_before_fs = wd.position;
+ if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) {
+ _set_wm_maximized(p_window, true);
+ }
+ _set_wm_fullscreen(p_window, true);
+ wd.fullscreen = true;
+ } break;
+ case WINDOW_MODE_MAXIMIZED: {
+
+ _set_wm_maximized(p_window, true);
+
+ } break;
+ }
+}
+
+DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
+ const WindowData &wd = windows[p_window];
+
+ if (wd.fullscreen) { //if fullscreen, it's not in another mode
+ return WINDOW_MODE_FULLSCREEN;
+ }
+ { //test maximized
+ // Using EWMH -- Extended Window Manager Hints
+ Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+ bool retval = false;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ wd.x11_window,
+ property,
+ 0,
+ 1024,
+ False,
+ XA_ATOM,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success && data) {
+ Atom *atoms = (Atom *)data;
+ Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+ Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+ bool found_wm_max_horz = false;
+ bool found_wm_max_vert = false;
+
+ for (uint64_t i = 0; i < len; i++) {
+ if (atoms[i] == wm_max_horz)
+ found_wm_max_horz = true;
+ if (atoms[i] == wm_max_vert)
+ found_wm_max_vert = true;
+
+ if (found_wm_max_horz && found_wm_max_vert) {
+ retval = true;
+ break;
+ }
+ }
+
+ XFree(data);
+ }
+
+ if (retval) {
+ return WINDOW_MODE_MAXIMIZED;
+ }
+ }
+
+ { // test minimzed
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ Atom property = XInternAtom(x11_display, "WM_STATE", True);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ wd.x11_window,
+ property,
+ 0,
+ 32,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success && data) {
+ long *state = (long *)data;
+ if (state[0] == WM_IconicState) {
+ XFree(data);
+ return WINDOW_MODE_MINIMIZED;
+ }
+ XFree(data);
+ }
+ }
+
+ // all other discarded, return windowed.
+
+ return WINDOW_MODE_WINDOWED;
+}
+
+void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ switch (p_flag) {
+ case WINDOW_FLAG_RESIZE_DISABLED: {
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+ if (p_enabled) {
+ Size2i size = window_get_size(p_window);
+
+ xsh->flags = PMinSize | PMaxSize;
+ xsh->min_width = size.x;
+ xsh->max_width = size.x;
+ xsh->min_height = size.y;
+ xsh->max_height = size.y;
+ } else {
+ xsh->flags = 0L;
+ if (wd.min_size != Size2i()) {
+ xsh->flags |= PMinSize;
+ xsh->min_width = wd.min_size.x;
+ xsh->min_height = wd.min_size.y;
+ }
+ if (wd.max_size != Size2i()) {
+ xsh->flags |= PMaxSize;
+ xsh->max_width = wd.max_size.x;
+ xsh->max_height = wd.max_size.y;
+ }
+ }
+
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+
+ wd.resize_disabled = p_enabled;
+
+ XFlush(x11_display);
+
+ } break;
+ case WINDOW_FLAG_BORDERLESS: {
+
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = p_enabled ? 0 : 1;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+
+ // Preserve window size
+ window_set_size(window_get_size(p_window), p_window);
+
+ wd.borderless = p_enabled;
+ } break;
+ case WINDOW_FLAG_ALWAYS_ON_TOP: {
+
+ ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID, "Can't make a window transient if the 'on top' flag is active.");
+ if (p_enabled && wd.fullscreen) {
+ _set_wm_maximized(p_window, true);
+ }
+
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
+
+ XClientMessageEvent xev;
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.window = wd.x11_window;
+ xev.message_type = wm_state;
+ xev.format = 32;
+ xev.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.data.l[1] = wm_above;
+ xev.data.l[3] = 1;
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
+
+ if (!p_enabled && !wd.fullscreen) {
+ _set_wm_maximized(p_window, false);
+ }
+ wd.on_top = p_enabled;
+
+ } break;
+ case WINDOW_FLAG_TRANSPARENT: {
+ //todo reimplement
+ } break;
+ default: {
+ }
+ }
+}
+bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+
+ switch (p_flag) {
+ case WINDOW_FLAG_RESIZE_DISABLED: {
+
+ return wd.resize_disabled;
+ } break;
+ case WINDOW_FLAG_BORDERLESS: {
+
+ bool borderless = wd.borderless;
+ Atom prop = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ if (prop != None) {
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+ if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, sizeof(Hints), False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ if (data && (format == 32) && (len >= 5)) {
+ borderless = !((Hints *)data)->decorations;
+ }
+ if (data) {
+ XFree(data);
+ }
+ }
+ }
+ return borderless;
+ } break;
+ case WINDOW_FLAG_ALWAYS_ON_TOP: {
+
+ return wd.on_top;
+ } break;
+ case WINDOW_FLAG_TRANSPARENT: {
+ //todo reimplement
+ } break;
+ default: {
+ }
+ }
+
+ return false;
+}
+
+void DisplayServerX11::window_request_attention(WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ // Using EWMH -- Extended Window Manager Hints
+ //
+ // Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE
+ // Will be unset by the window manager after user react on the request for attention
+
+ XEvent xev;
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_attention = XInternAtom(x11_display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+ xev.xclient.data.l[1] = wm_attention;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ XFlush(x11_display);
+}
+
+void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ XEvent xev;
+ Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = net_active_window;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = 1;
+ xev.xclient.data.l[1] = CurrentTime;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ XFlush(x11_display);
+}
+
+bool DisplayServerX11::window_can_draw(WindowID p_window) const {
+
+ //this seems to be all that is provided by X11
+ return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
+}
+bool DisplayServerX11::can_any_window_draw() const {
+
+ _THREAD_SAFE_METHOD_
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (window_get_mode(E->key()) != WINDOW_MODE_MINIMIZED) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.im_active = p_active;
+
+ if (!wd.xic)
+ return;
+
+ if (p_active) {
+ XSetICFocus(wd.xic);
+ window_set_ime_position(wd.im_position, p_window);
+ } else {
+ XUnsetICFocus(wd.xic);
+ }
+}
+void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.im_position = p_pos;
+
+ if (!wd.xic)
+ return;
+
+ ::XPoint spot;
+ spot.x = short(p_pos.x);
+ spot.y = short(p_pos.y);
+ XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, nullptr);
+ XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, nullptr);
+ XFree(preedit_attr);
+}
+
+void DisplayServerX11::cursor_set_shape(CursorShape p_shape) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
+
+ if (p_shape == current_cursor) {
+ return;
+ }
+
+ if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ if (cursors[p_shape] != None) {
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]);
+ }
+ } else if (cursors[CURSOR_ARROW] != None) {
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ XDefineCursor(x11_display, E->get().x11_window, cursors[CURSOR_ARROW]);
+ }
+ }
+ }
+
+ current_cursor = p_shape;
+}
+DisplayServerX11::CursorShape DisplayServerX11::cursor_get_shape() const {
+ return current_cursor;
+}
+void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (p_cursor.is_valid()) {
+
+ Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
+
+ if (cursor_c) {
+ if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
+ cursor_set_shape(p_shape);
+ return;
+ }
+
+ cursors_cache.erase(p_shape);
+ }
+
+ Ref<Texture2D> texture = p_cursor;
+ Ref<AtlasTexture> atlas_texture = p_cursor;
+ Ref<Image> image;
+ Size2i texture_size;
+ Rect2i atlas_rect;
+
+ if (texture.is_valid()) {
+ image = texture->get_data();
+ }
+
+ if (!image.is_valid() && atlas_texture.is_valid()) {
+ texture = atlas_texture->get_atlas();
+
+ atlas_rect.size.width = texture->get_width();
+ atlas_rect.size.height = texture->get_height();
+ atlas_rect.position.x = atlas_texture->get_region().position.x;
+ atlas_rect.position.y = atlas_texture->get_region().position.y;
+
+ texture_size.width = atlas_texture->get_region().size.x;
+ texture_size.height = atlas_texture->get_region().size.y;
+ } else if (image.is_valid()) {
+ texture_size.width = texture->get_width();
+ texture_size.height = texture->get_height();
+ }
+
+ ERR_FAIL_COND(!texture.is_valid());
+ ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
+ 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();
+
+ ERR_FAIL_COND(!image.is_valid());
+
+ // Create the cursor structure
+ XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
+ XcursorUInt image_size = texture_size.width * texture_size.height;
+ XcursorDim size = sizeof(XcursorPixel) * image_size;
+
+ cursor_image->version = 1;
+ cursor_image->size = size;
+ cursor_image->xhot = p_hotspot.x;
+ cursor_image->yhot = p_hotspot.y;
+
+ // allocate memory to contain the whole file
+ cursor_image->pixels = (XcursorPixel *)memalloc(size);
+
+ for (XcursorPixel index = 0; index < image_size; index++) {
+ int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
+ int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
+
+ if (atlas_texture.is_valid()) {
+ column_index = MIN(column_index, atlas_rect.size.width - 1);
+ row_index = MIN(row_index, atlas_rect.size.height - 1);
+ }
+
+ *(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
+ }
+
+ ERR_FAIL_COND(cursor_image->pixels == nullptr);
+
+ // Save it for a further usage
+ cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
+
+ Vector<Variant> params;
+ params.push_back(p_cursor);
+ params.push_back(p_hotspot);
+ cursors_cache.insert(p_shape, params);
+
+ if (p_shape == current_cursor) {
+ if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]);
+ }
+ }
+ }
+
+ memfree(cursor_image->pixels);
+ XcursorImageDestroy(cursor_image);
+ } else {
+ // Reset to default system cursor
+ if (img[p_shape]) {
+ cursors[p_shape] = XcursorImageLoadCursor(x11_display, img[p_shape]);
+ }
+
+ CursorShape c = current_cursor;
+ current_cursor = CURSOR_MAX;
+ cursor_set_shape(c);
+
+ cursors_cache.erase(p_shape);
+ }
+}
+
+DisplayServerX11::LatinKeyboardVariant DisplayServerX11::get_latin_keyboard_variant() const {
+ _THREAD_SAFE_METHOD_
+
+ XkbDescRec *xkbdesc = XkbAllocKeyboard();
+ ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY);
+
+ XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc);
+ ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY);
+ ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY);
+
+ char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols);
+ ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY);
+
+ Vector<String> info = String(layout).split("+");
+ ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY);
+
+ if (info[1].find("colemak") != -1) {
+ return LATIN_KEYBOARD_COLEMAK;
+ } else if (info[1].find("qwertz") != -1) {
+ return LATIN_KEYBOARD_QWERTZ;
+ } else if (info[1].find("azerty") != -1) {
+ return LATIN_KEYBOARD_AZERTY;
+ } else if (info[1].find("qzerty") != -1) {
+ return LATIN_KEYBOARD_QZERTY;
+ } else if (info[1].find("dvorak") != -1) {
+ return LATIN_KEYBOARD_DVORAK;
+ } else if (info[1].find("neo") != -1) {
+ return LATIN_KEYBOARD_NEO;
+ }
+
+ return LATIN_KEYBOARD_QWERTY;
+}
+
+DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) {
+
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *ret = nullptr;
+
+ int read_bytes = 1024;
+
+ //Keep trying to read the property until there are no
+ //bytes unread.
+ do {
+ if (ret != nullptr)
+ XFree(ret);
+
+ XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType,
+ &actual_type, &actual_format, &nitems, &bytes_after,
+ &ret);
+
+ read_bytes *= 2;
+
+ } while (bytes_after != 0);
+
+ Property p = { ret, actual_format, (int)nitems, actual_type };
+
+ return p;
+}
+
+static Atom pick_target_from_list(Display *p_display, Atom *p_list, int p_count) {
+
+ static const char *target_type = "text/uri-list";
+
+ for (int i = 0; i < p_count; i++) {
+
+ Atom atom = p_list[i];
+
+ if (atom != None && String(XGetAtomName(p_display, atom)) == target_type)
+ return atom;
+ }
+ return None;
+}
+
+static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p_t3) {
+
+ static const char *target_type = "text/uri-list";
+ if (p_t1 != None && String(XGetAtomName(p_disp, p_t1)) == target_type)
+ return p_t1;
+
+ if (p_t2 != None && String(XGetAtomName(p_disp, p_t2)) == target_type)
+ return p_t2;
+
+ if (p_t3 != None && String(XGetAtomName(p_disp, p_t3)) == target_type)
+ return p_t3;
+
+ return None;
+}
+
+void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) {
+
+ state->set_shift((p_x11_state & ShiftMask));
+ state->set_control((p_x11_state & ControlMask));
+ state->set_alt((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt
+ state->set_metakey((p_x11_state & Mod4Mask));
+}
+
+unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) {
+
+ unsigned int mask = 1 << (p_x11_button - 1);
+
+ if (p_x11_type == ButtonPress) {
+ last_button_state |= mask;
+ } else {
+ last_button_state &= ~mask;
+ }
+
+ return last_button_state;
+}
+
+void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo) {
+
+ WindowData wd = windows[p_window];
+ // X11 functions don't know what const is
+ XKeyEvent *xkeyevent = p_event;
+
+ // This code was pretty difficult to write.
+ // The docs stink and every toolkit seems to
+ // do it in a different way.
+
+ /* Phase 1, obtain a proper keysym */
+
+ // This was also very difficult to figure out.
+ // You'd expect you could just use Keysym provided by
+ // XKeycodeToKeysym to obtain internationalized
+ // input.. WRONG!!
+ // you must use XLookupString (???) which not only wastes
+ // cycles generating an unnecessary string, but also
+ // still works in half the cases. (won't handle deadkeys)
+ // For more complex input methods (deadkeys and more advanced)
+ // you have to use XmbLookupString (??).
+ // So.. then you have to chosse which of both results
+ // you want to keep.
+ // This is a real bizarreness and cpu waster.
+
+ KeySym keysym_keycode = 0; // keysym used to find a keycode
+ KeySym keysym_unicode = 0; // keysym used to find unicode
+
+ // XLookupString returns keysyms usable as nice keycodes.
+ char str[256 + 1];
+ XKeyEvent xkeyevent_no_mod = *xkeyevent;
+ xkeyevent_no_mod.state &= ~ShiftMask;
+ xkeyevent_no_mod.state &= ~ControlMask;
+ XLookupString(xkeyevent, str, 256, &keysym_unicode, nullptr);
+ XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_keycode, nullptr);
+
+ // Meanwhile, XLookupString returns keysyms useful for unicode.
+
+ if (!xmbstring) {
+ // keep a temporary buffer for the string
+ xmbstring = (char *)memalloc(sizeof(char) * 8);
+ xmblen = 8;
+ }
+
+ if (xkeyevent->type == KeyPress && wd.xic) {
+
+ Status status;
+#ifdef X_HAVE_UTF8_STRING
+ int utf8len = 8;
+ char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
+ int utf8bytes = Xutf8LookupString(wd.xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ if (status == XBufferOverflow) {
+ utf8len = utf8bytes + 1;
+ utf8string = (char *)memrealloc(utf8string, utf8len);
+ utf8bytes = Xutf8LookupString(wd.xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ }
+ utf8string[utf8bytes] = '\0';
+
+ if (status == XLookupChars) {
+ bool keypress = xkeyevent->type == KeyPress;
+ unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+ unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+
+ if (keycode >= 'a' && keycode <= 'z')
+ keycode -= 'a' - 'A';
+
+ String tmp;
+ tmp.parse_utf8(utf8string, utf8bytes);
+ for (int i = 0; i < tmp.length(); i++) {
+ Ref<InputEventKey> k;
+ k.instance();
+ if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) {
+ continue;
+ }
+
+ if (keycode == 0) {
+ keycode = physical_keycode;
+ }
+
+ _get_key_modifier_state(xkeyevent->state, k);
+
+ k->set_window_id(p_window);
+ k->set_unicode(tmp[i]);
+
+ k->set_pressed(keypress);
+
+ k->set_keycode(keycode);
+
+ k->set_physical_keycode(physical_keycode);
+
+ k->set_echo(false);
+
+ if (k->get_keycode() == KEY_BACKTAB) {
+ //make it consistent across platforms.
+ k->set_keycode(KEY_TAB);
+ k->set_physical_keycode(KEY_TAB);
+ k->set_shift(true);
+ }
+
+ InputFilter::get_singleton()->accumulate_input_event(k);
+ }
+ memfree(utf8string);
+ return;
+ }
+ memfree(utf8string);
+#else
+ do {
+
+ int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
+ xmbstring[mnbytes] = '\0';
+
+ if (status == XBufferOverflow) {
+ xmblen = mnbytes + 1;
+ xmbstring = (char *)memrealloc(xmbstring, xmblen);
+ }
+ } while (status == XBufferOverflow);
+#endif
+ }
+
+ /* Phase 2, obtain a Godot keycode from the keysym */
+
+ // KeyMappingX11 just translated the X11 keysym to a PIGUI
+ // keysym, so it works in all platforms the same.
+
+ unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+ unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+
+ /* Phase 3, obtain a unicode character from the keysym */
+
+ // KeyMappingX11 also translates keysym to unicode.
+ // It does a binary search on a table to translate
+ // most properly.
+ unsigned int unicode = keysym_unicode > 0 ? KeyMappingX11::get_unicode_from_keysym(keysym_unicode) : 0;
+
+ /* Phase 4, determine if event must be filtered */
+
+ // This seems to be a side-effect of using XIM.
+ // XEventFilter looks like a core X11 function,
+ // but it's actually just used to see if we must
+ // ignore a deadkey, or events XIM determines
+ // must not reach the actual gui.
+ // Guess it was a design problem of the extension
+
+ bool keypress = xkeyevent->type == KeyPress;
+
+ if (physical_keycode == 0 && keycode == 0 && unicode == 0) {
+ return;
+ }
+
+ if (keycode == 0) {
+ keycode = physical_keycode;
+ }
+
+ /* Phase 5, determine modifier mask */
+
+ // No problems here, except I had no way to
+ // know Mod1 was ALT and Mod4 was META (applekey/winkey)
+ // just tried Mods until i found them.
+
+ //print_verbose("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
+
+ Ref<InputEventKey> k;
+ k.instance();
+ k->set_window_id(p_window);
+
+ _get_key_modifier_state(xkeyevent->state, k);
+
+ /* Phase 6, determine echo character */
+
+ // Echo characters in X11 are a keyrelease and a keypress
+ // one after the other with the (almot) same timestamp.
+ // To detect them, i use XPeekEvent and check that their
+ // difference in time is below a threshold.
+
+ if (xkeyevent->type != KeyPress) {
+
+ p_echo = false;
+
+ // make sure there are events pending,
+ // so this call won't block.
+ if (XPending(x11_display) > 0) {
+ XEvent peek_event;
+ XPeekEvent(x11_display, &peek_event);
+
+ // I'm using a threshold of 5 msecs,
+ // since sometimes there seems to be a little
+ // jitter. I'm still not convinced that all this approach
+ // is correct, but the xorg developers are
+ // not very helpful today.
+
+#define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
+ ::Time threshold = ABSDIFF(peek_event.xkey.time, xkeyevent->time);
+#undef ABSDIFF
+ if (peek_event.type == KeyPress && threshold < 5) {
+ KeySym rk;
+ XLookupString((XKeyEvent *)&peek_event, str, 256, &rk, nullptr);
+ if (rk == keysym_keycode) {
+ XEvent event;
+ XNextEvent(x11_display, &event); //erase next event
+ _handle_key_event(p_window, (XKeyEvent *)&event, true);
+ return; //ignore current, echo next
+ }
+ }
+
+ // use the time from peek_event so it always works
+ }
+
+ // save the time to check for echo when keypress happens
+ }
+
+ /* Phase 7, send event to Window */
+
+ k->set_pressed(keypress);
+
+ if (keycode >= 'a' && keycode <= 'z')
+ keycode -= 'a' - 'A';
+
+ k->set_keycode(keycode);
+ k->set_physical_keycode(physical_keycode);
+ k->set_unicode(unicode);
+ k->set_echo(p_echo);
+
+ if (k->get_keycode() == KEY_BACKTAB) {
+ //make it consistent across platforms.
+ k->set_keycode(KEY_TAB);
+ k->set_physical_keycode(KEY_TAB);
+ k->set_shift(true);
+ }
+
+ //don't set mod state if modifier keys are released by themselves
+ //else event.is_action() will not work correctly here
+ if (!k->is_pressed()) {
+ if (k->get_keycode() == KEY_SHIFT)
+ k->set_shift(false);
+ else if (k->get_keycode() == KEY_CONTROL)
+ k->set_control(false);
+ else if (k->get_keycode() == KEY_ALT)
+ k->set_alt(false);
+ else if (k->get_keycode() == KEY_META)
+ k->set_metakey(false);
+ }
+
+ bool last_is_pressed = InputFilter::get_singleton()->is_key_pressed(k->get_keycode());
+ if (k->is_pressed()) {
+ if (last_is_pressed) {
+ k->set_echo(true);
+ }
+ }
+
+ InputFilter::get_singleton()->accumulate_input_event(k);
+}
+
+void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data) {
+
+ WARN_PRINT("Input method stopped");
+ DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
+ ds->xim = nullptr;
+
+ for (Map<WindowID, WindowData>::Element *E = ds->windows.front(); E; E = E->next()) {
+ E->get().xic = nullptr;
+ }
+}
+
+void DisplayServerX11::_window_changed(XEvent *event) {
+
+ WindowID window_id = MAIN_WINDOW_ID;
+
+ // Assign the event to the relevant window
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (event->xany.window == E->get().x11_window) {
+ window_id = E->key();
+ break;
+ }
+ }
+
+ Rect2i new_rect;
+
+ WindowData &wd = windows[window_id];
+ if (wd.x11_window != event->xany.window) { // Check if the correct window, in case it was not main window or anything else
+ return;
+ }
+
+ {
+ //the position in xconfigure is not useful here, obtain it manually
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+ new_rect.position.x = x;
+ new_rect.position.y = y;
+
+ new_rect.size.width = event->xconfigure.width;
+ new_rect.size.height = event->xconfigure.height;
+ }
+
+ if (new_rect == Rect2i(wd.position, wd.size)) {
+ return;
+ }
+ if (wd.xic) {
+ // Not portable.
+ window_set_ime_position(Point2(0, 1));
+ }
+
+ wd.position = new_rect.position;
+ wd.size = new_rect.size;
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
+ }
+#endif
+
+ print_line("DisplayServer::_window_changed: " + itos(window_id) + " rect: " + new_rect);
+ if (!wd.rect_changed_callback.is_null()) {
+ Rect2i r = new_rect;
+
+ Variant rect = r;
+
+ Variant *rectp = &rect;
+ Variant ret;
+ Callable::CallError ce;
+ wd.rect_changed_callback.call((const Variant **)&rectp, 1, ret, ce);
+ }
+}
+
+void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) {
+ ((DisplayServerX11 *)(get_singleton()))->_dispatch_input_event(p_event);
+}
+
+void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {
+
+ Variant ev = p_event;
+ Variant *evp = &ev;
+ Variant ret;
+ Callable::CallError ce;
+
+ Ref<InputEventFromWindow> event_from_window = p_event;
+ if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
+ //send to a window
+ ERR_FAIL_COND(!windows.has(event_from_window->get_window_id()));
+ Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
+ if (callable.is_null()) {
+ return;
+ }
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ } else {
+ //send to all windows
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ Callable callable = E->get().input_event_callback;
+ if (callable.is_null()) {
+ continue;
+ }
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ }
+}
+
+void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_event) {
+ if (!wd.event_callback.is_null()) {
+ Variant event = int(p_event);
+ Variant *eventp = &event;
+ Variant ret;
+ Callable::CallError ce;
+ wd.event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ }
+}
+void DisplayServerX11::process_events() {
+
+ _THREAD_SAFE_METHOD_
+
+ do_mouse_warp = false;
+
+ // Is the current mouse mode one where it needs to be grabbed.
+ bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED;
+
+ while (XPending(x11_display) > 0) {
+ XEvent event;
+ XNextEvent(x11_display, &event);
+
+ WindowID window_id = MAIN_WINDOW_ID;
+
+ // Assign the event to the relevant window
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (event.xany.window == E->get().x11_window) {
+ window_id = E->key();
+ break;
+ }
+ }
+
+ if (XFilterEvent(&event, None)) {
+ continue;
+ }
+
+ if (XGetEventData(x11_display, &event.xcookie)) {
+
+ if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
+
+ XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+ int index = event_data->detail;
+ Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
+
+ switch (event_data->evtype) {
+ case XI_HierarchyChanged:
+ case XI_DeviceChanged: {
+ _refresh_device_info();
+ } break;
+ case XI_RawMotion: {
+ XIRawEvent *raw_event = (XIRawEvent *)event_data;
+ int device_id = raw_event->deviceid;
+
+ // Determine the axis used (called valuators in XInput for some forsaken reason)
+ // Mask is a bitmask indicating which axes are involved.
+ // We are interested in the values of axes 0 and 1.
+ if (raw_event->valuators.mask_len <= 0) {
+ break;
+ }
+
+ const double *values = raw_event->raw_values;
+
+ double rel_x = 0.0;
+ double rel_y = 0.0;
+ double pressure = 0.0;
+ double tilt_x = 0.0;
+ double tilt_y = 0.0;
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSX)) {
+ rel_x = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSY)) {
+ rel_y = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_PRESSURE)) {
+ pressure = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTX)) {
+ tilt_x = *values;
+ values++;
+ }
+
+ if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTY)) {
+ tilt_y = *values;
+ }
+
+ Map<int, Vector3>::Element *pen_info = xi.pen_devices.find(device_id);
+ if (pen_info) {
+ Vector3 mult = pen_info->value();
+ if (mult.x != 0.0) xi.pressure = pressure / mult.x;
+ if ((mult.y != 0.0) && (mult.z != 0.0)) xi.tilt = Vector2(tilt_x / mult.y, tilt_y / mult.z);
+ }
+
+ // https://bugs.freedesktop.org/show_bug.cgi?id=71609
+ // http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html
+ if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) {
+ break; // Flush duplicate to avoid overly fast motion
+ }
+
+ xi.old_raw_pos.x = xi.raw_pos.x;
+ xi.old_raw_pos.y = xi.raw_pos.y;
+ xi.raw_pos.x = rel_x;
+ xi.raw_pos.y = rel_y;
+
+ Map<int, Vector2>::Element *abs_info = xi.absolute_devices.find(device_id);
+
+ if (abs_info) {
+ // Absolute mode device
+ Vector2 mult = abs_info->value();
+
+ xi.relative_motion.x += (xi.raw_pos.x - xi.old_raw_pos.x) * mult.x;
+ xi.relative_motion.y += (xi.raw_pos.y - xi.old_raw_pos.y) * mult.y;
+ } else {
+ // Relative mode device
+ xi.relative_motion.x = xi.raw_pos.x;
+ xi.relative_motion.y = xi.raw_pos.y;
+ }
+
+ xi.last_relative_time = raw_event->time;
+ } break;
+#ifdef TOUCH_ENABLED
+ case XI_TouchBegin: // Fall-through
+ // Disabled hand-in-hand with the grabbing
+ //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
+
+ case XI_TouchEnd: {
+
+ bool is_begin = event_data->evtype == XI_TouchBegin;
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_window_id(window_id);
+ st->set_index(index);
+ st->set_position(pos);
+ st->set_pressed(is_begin);
+
+ if (is_begin) {
+ if (xi.state.has(index)) // Defensive
+ break;
+ xi.state[index] = pos;
+ if (xi.state.size() == 1) {
+ // X11 may send a motion event when a touch gesture begins, that would result
+ // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
+ xi.mouse_pos_to_filter = pos;
+ }
+ InputFilter::get_singleton()->accumulate_input_event(st);
+ } else {
+ if (!xi.state.has(index)) // Defensive
+ break;
+ xi.state.erase(index);
+ InputFilter::get_singleton()->accumulate_input_event(st);
+ }
+ } break;
+
+ case XI_TouchUpdate: {
+
+ Map<int, Vector2>::Element *curr_pos_elem = xi.state.find(index);
+ if (!curr_pos_elem) { // Defensive
+ break;
+ }
+
+ if (curr_pos_elem->value() != pos) {
+
+ Ref<InputEventScreenDrag> sd;
+ sd.instance();
+ sd->set_window_id(window_id);
+ sd->set_index(index);
+ sd->set_position(pos);
+ sd->set_relative(pos - curr_pos_elem->value());
+ InputFilter::get_singleton()->accumulate_input_event(sd);
+
+ curr_pos_elem->value() = pos;
+ }
+ } break;
+#endif
+ }
+ }
+ }
+ XFreeEventData(x11_display, &event.xcookie);
+
+ switch (event.type) {
+ case Expose:
+ Main::force_redraw();
+ break;
+
+ case NoExpose:
+ minimized = true;
+ break;
+
+ case VisibilityNotify: {
+ XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
+ minimized = (visibility->state == VisibilityFullyObscured);
+ } break;
+ case LeaveNotify: {
+ if (!mouse_mode_grab) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
+
+ } break;
+ case EnterNotify: {
+ if (!mouse_mode_grab) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+ } break;
+ case FocusIn:
+ minimized = false;
+ window_has_focus = true;
+ _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN);
+ window_focused = true;
+
+ if (mouse_mode_grab) {
+ // Show and update the cursor if confined and the window regained focus.
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+
+ if (mouse_mode == MOUSE_MODE_CONFINED)
+ XUndefineCursor(x11_display, E->get().x11_window);
+ else if (mouse_mode == MOUSE_MODE_CAPTURED) // or re-hide it in captured mode
+ XDefineCursor(x11_display, E->get().x11_window, null_cursor);
+
+ XGrabPointer(
+ x11_display, E->get().x11_window, True,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, E->get().x11_window, None, CurrentTime);
+ }
+ }
+#ifdef TOUCH_ENABLED
+ // Grab touch devices to avoid OS gesture interference
+ /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
+ XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
+ }*/
+#endif
+ if (windows[window_id].xic) {
+ XSetICFocus(windows[window_id].xic);
+ }
+ break;
+
+ case FocusOut:
+ window_has_focus = false;
+ InputFilter::get_singleton()->release_pressed_events();
+ _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT);
+ window_focused = false;
+
+ if (mouse_mode_grab) {
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+
+ //dear X11, I try, I really try, but you never work, you do whathever you want.
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ // Show the cursor if we're in captured mode so it doesn't look weird.
+ XUndefineCursor(x11_display, E->get().x11_window);
+ }
+ }
+ XUngrabPointer(x11_display, CurrentTime);
+ }
+#ifdef TOUCH_ENABLED
+ // Ungrab touch devices so input works as usual while we are unfocused
+ /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
+ XIUngrabDevice(x11_display, xi.touch_devices[i], CurrentTime);
+ }*/
+
+ // Release every pointer to avoid sticky points
+ for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) {
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_index(E->key());
+ st->set_window_id(window_id);
+ st->set_position(E->get());
+ InputFilter::get_singleton()->accumulate_input_event(st);
+ }
+ xi.state.clear();
+#endif
+ if (windows[window_id].xic) {
+ XSetICFocus(windows[window_id].xic);
+ }
+ break;
+
+ case ConfigureNotify:
+ _window_changed(&event);
+ break;
+ case ButtonPress:
+ case ButtonRelease: {
+
+ /* exit in case of a mouse button press */
+ last_timestamp = event.xbutton.time;
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ event.xbutton.x = last_mouse_pos.x;
+ event.xbutton.y = last_mouse_pos.y;
+ }
+
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+
+ mb->set_window_id(window_id);
+ _get_key_modifier_state(event.xbutton.state, mb);
+ mb->set_button_index(event.xbutton.button);
+ if (mb->get_button_index() == 2)
+ mb->set_button_index(3);
+ else if (mb->get_button_index() == 3)
+ mb->set_button_index(2);
+ mb->set_button_mask(_get_mouse_button_state(mb->get_button_index(), event.xbutton.type));
+ mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
+ mb->set_global_position(mb->get_position());
+
+ mb->set_pressed((event.type == ButtonPress));
+
+ if (event.type == ButtonPress) {
+
+ uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
+
+ if (mb->get_button_index() == last_click_button_index) {
+
+ if (diff < 400 && Vector2(last_click_pos).distance_to(Vector2(event.xbutton.x, event.xbutton.y)) < 5) {
+
+ last_click_ms = 0;
+ last_click_pos = Point2i(-100, -100);
+ last_click_button_index = -1;
+ mb->set_doubleclick(true);
+ }
+
+ } else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) {
+ last_click_button_index = mb->get_button_index();
+ }
+
+ if (!mb->is_doubleclick()) {
+ last_click_ms += diff;
+ last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
+ }
+ }
+
+ InputFilter::get_singleton()->accumulate_input_event(mb);
+
+ } break;
+ case MotionNotify: {
+
+ // The X11 API requires filtering one-by-one through the motion
+ // notify events, in order to figure out which event is the one
+ // generated by warping the mouse pointer.
+
+ while (true) {
+ if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[MAIN_WINDOW_ID].size.width / 2 && event.xmotion.y == windows[MAIN_WINDOW_ID].size.height / 2) {
+ //this is likely the warp event since it was warped here
+ center = Vector2(event.xmotion.x, event.xmotion.y);
+ break;
+ }
+
+ if (XPending(x11_display) > 0) {
+ XEvent tevent;
+ XPeekEvent(x11_display, &tevent);
+ if (tevent.type == MotionNotify) {
+ XNextEvent(x11_display, &event);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ last_timestamp = event.xmotion.time;
+
+ // Motion is also simple.
+ // A little hack is in order
+ // to be able to send relative motion events.
+ Point2i pos(event.xmotion.x, event.xmotion.y);
+
+ // Avoidance of spurious mouse motion (see handling of touch)
+ bool filter = false;
+ // Adding some tolerance to match better Point2i to Vector2
+ if (xi.state.size() && Vector2(pos).distance_squared_to(xi.mouse_pos_to_filter) < 2) {
+ filter = true;
+ }
+ // Invalidate to avoid filtering a possible legitimate similar event coming later
+ xi.mouse_pos_to_filter = Vector2(1e10, 1e10);
+ if (filter) {
+ break;
+ }
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
+ break;
+ }
+
+ Point2i new_center = pos;
+ pos = last_mouse_pos + xi.relative_motion;
+ center = new_center;
+ do_mouse_warp = window_has_focus; // warp the cursor if we're focused in
+ }
+
+ if (!last_mouse_pos_valid) {
+
+ last_mouse_pos = pos;
+ last_mouse_pos_valid = true;
+ }
+
+ // Hackish but relative mouse motion is already handled in the RawMotion event.
+ // RawMotion does not provide the absolute mouse position (whereas MotionNotify does).
+ // Therefore, RawMotion cannot be the authority on absolute mouse position.
+ // RawMotion provides more precision than MotionNotify, which doesn't sense subpixel motion.
+ // Therefore, MotionNotify cannot be the authority on relative mouse motion.
+ // This means we need to take a combined approach...
+ Point2i rel;
+
+ // Only use raw input if in capture mode. Otherwise use the classic behavior.
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ rel = xi.relative_motion;
+ } else {
+ rel = pos - last_mouse_pos;
+ }
+
+ // Reset to prevent lingering motion
+ xi.relative_motion.x = 0;
+ xi.relative_motion.y = 0;
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ pos = Point2i(windows[MAIN_WINDOW_ID].size.width / 2, windows[MAIN_WINDOW_ID].size.height / 2);
+ }
+
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+
+ mm->set_window_id(window_id);
+ mm->set_pressure(xi.pressure);
+ mm->set_tilt(xi.tilt);
+
+ // Make the absolute position integral so it doesn't look _too_ weird :)
+ Point2i posi(pos);
+
+ _get_key_modifier_state(event.xmotion.state, mm);
+ mm->set_button_mask(mouse_get_button_state());
+ mm->set_position(posi);
+ mm->set_global_position(posi);
+ InputFilter::get_singleton()->set_mouse_position(posi);
+ mm->set_speed(InputFilter::get_singleton()->get_last_mouse_speed());
+
+ mm->set_relative(rel);
+
+ last_mouse_pos = pos;
+
+ // printf("rel: %d,%d\n", rel.x, rel.y );
+ // Don't propagate the motion event unless we have focus
+ // this is so that the relative motion doesn't get messed up
+ // after we regain focus.
+ if (window_has_focus || !mouse_mode_grab)
+ InputFilter::get_singleton()->accumulate_input_event(mm);
+
+ } break;
+ case KeyPress:
+ case KeyRelease: {
+
+ last_timestamp = event.xkey.time;
+
+ // key event is a little complex, so
+ // it will be handled in its own function.
+ _handle_key_event(window_id, (XKeyEvent *)&event);
+ } break;
+ case SelectionRequest: {
+
+ XSelectionRequestEvent *req;
+ XEvent e, respond;
+ e = event;
+
+ req = &(e.xselectionrequest);
+ if (req->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
+ req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ req->target == XInternAtom(x11_display, "TEXT", 0) ||
+ req->target == XA_STRING ||
+ req->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+ req->target == XInternAtom(x11_display, "text/plain", 0)) {
+ CharString clip = clipboard_get().utf8();
+ XChangeProperty(x11_display,
+ req->requestor,
+ req->property,
+ req->target,
+ 8,
+ PropModeReplace,
+ (unsigned char *)clip.get_data(),
+ clip.length());
+ respond.xselection.property = req->property;
+ } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
+
+ Atom data[7];
+ data[0] = XInternAtom(x11_display, "TARGETS", 0);
+ data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
+ data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
+ data[3] = XInternAtom(x11_display, "TEXT", 0);
+ data[4] = XA_STRING;
+ data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
+ data[6] = XInternAtom(x11_display, "text/plain", 0);
+
+ XChangeProperty(x11_display,
+ req->requestor,
+ req->property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *)&data,
+ sizeof(data) / sizeof(data[0]));
+ respond.xselection.property = req->property;
+
+ } else {
+ char *targetname = XGetAtomName(x11_display, req->target);
+ printf("No Target '%s'\n", targetname);
+ if (targetname)
+ XFree(targetname);
+ respond.xselection.property = None;
+ }
+
+ respond.xselection.type = SelectionNotify;
+ respond.xselection.display = req->display;
+ respond.xselection.requestor = req->requestor;
+ respond.xselection.selection = req->selection;
+ respond.xselection.target = req->target;
+ respond.xselection.time = req->time;
+ XSendEvent(x11_display, req->requestor, True, NoEventMask, &respond);
+ XFlush(x11_display);
+ } break;
+
+ case SelectionNotify:
+
+ if (event.xselection.target == requested) {
+
+ Property p = _read_property(x11_display, windows[window_id].x11_window, XInternAtom(x11_display, "PRIMARY", 0));
+
+ Vector<String> files = String((char *)p.data).split("\n", false);
+ for (int i = 0; i < files.size(); i++) {
+ files.write[i] = files[i].replace("file://", "").http_unescape().strip_edges();
+ }
+
+ if (!windows[window_id].drop_files_callback.is_null()) {
+ Variant v = files;
+ Variant *vp = &v;
+ Variant ret;
+ Callable::CallError ce;
+ windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
+ }
+
+ //Reply that all is well.
+ XClientMessageEvent m;
+ memset(&m, 0, sizeof(m));
+ m.type = ClientMessage;
+ m.display = x11_display;
+ m.window = xdnd_source_window;
+ m.message_type = xdnd_finished;
+ m.format = 32;
+ m.data.l[0] = windows[window_id].x11_window;
+ m.data.l[1] = 1;
+ m.data.l[2] = xdnd_action_copy; //We only ever copy.
+
+ XSendEvent(x11_display, xdnd_source_window, False, NoEventMask, (XEvent *)&m);
+ }
+ break;
+
+ case ClientMessage:
+
+ if ((unsigned int)event.xclient.data.l[0] == (unsigned int)wm_delete) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
+ }
+
+ else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_enter) {
+
+ //File(s) have been dragged over the window, check for supported target (text/uri-list)
+ xdnd_version = (event.xclient.data.l[1] >> 24);
+ Window source = event.xclient.data.l[0];
+ bool more_than_3 = event.xclient.data.l[1] & 1;
+ if (more_than_3) {
+ Property p = _read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False));
+ requested = pick_target_from_list(x11_display, (Atom *)p.data, p.nitems);
+ } else
+ requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]);
+ } else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_position) {
+
+ //xdnd position event, reply with an XDND status message
+ //just depending on type of data for now
+ XClientMessageEvent m;
+ memset(&m, 0, sizeof(m));
+ m.type = ClientMessage;
+ m.display = event.xclient.display;
+ m.window = event.xclient.data.l[0];
+ m.message_type = xdnd_status;
+ m.format = 32;
+ m.data.l[0] = windows[window_id].x11_window;
+ m.data.l[1] = (requested != None);
+ m.data.l[2] = 0; //empty rectangle
+ m.data.l[3] = 0;
+ m.data.l[4] = xdnd_action_copy;
+
+ XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
+ XFlush(x11_display);
+ } else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_drop) {
+
+ if (requested != None) {
+ xdnd_source_window = event.xclient.data.l[0];
+ if (xdnd_version >= 1)
+ XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), windows[window_id].x11_window, event.xclient.data.l[2]);
+ else
+ XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), windows[window_id].x11_window, CurrentTime);
+ } else {
+ //Reply that we're not interested.
+ XClientMessageEvent m;
+ memset(&m, 0, sizeof(m));
+ m.type = ClientMessage;
+ m.display = event.xclient.display;
+ m.window = event.xclient.data.l[0];
+ m.message_type = xdnd_finished;
+ m.format = 32;
+ m.data.l[0] = windows[window_id].x11_window;
+ m.data.l[1] = 0;
+ m.data.l[2] = None; //Failed.
+ XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ XFlush(x11_display);
+
+ if (do_mouse_warp) {
+
+ XWarpPointer(x11_display, None, windows[MAIN_WINDOW_ID].x11_window,
+ 0, 0, 0, 0, (int)windows[MAIN_WINDOW_ID].size.width / 2, (int)windows[MAIN_WINDOW_ID].size.height / 2);
+
+ /*
+ Window root, child;
+ int root_x, root_y;
+ int win_x, win_y;
+ unsigned int mask;
+ XQueryPointer( x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );
+
+ printf("Root: %d,%d\n", root_x, root_y);
+ printf("Win: %d,%d\n", win_x, win_y);
+ */
+ }
+
+ InputFilter::get_singleton()->flush_accumulated_events();
+}
+
+void DisplayServerX11::release_rendering_thread() {
+}
+
+void DisplayServerX11::make_rendering_thread() {
+}
+
+void DisplayServerX11::swap_buffers() {
+}
+
+void DisplayServerX11::_update_context(WindowData &wd) {
+ XClassHint *classHint = XAllocClassHint();
+
+ if (classHint) {
+
+ CharString name_str;
+ switch (context) {
+ case CONTEXT_EDITOR:
+ name_str = "Godot_Editor";
+ break;
+ case CONTEXT_PROJECTMAN:
+ name_str = "Godot_ProjectList";
+ break;
+ case CONTEXT_ENGINE:
+ name_str = "Godot_Engine";
+ break;
+ }
+
+ CharString class_str;
+ if (context == CONTEXT_ENGINE) {
+ String config_name = GLOBAL_GET("application/config/name");
+ if (config_name.length() == 0) {
+ class_str = "Godot_Engine";
+ } else {
+ class_str = config_name.utf8();
+ }
+ } else {
+ class_str = "Godot";
+ }
+
+ classHint->res_class = class_str.ptrw();
+ classHint->res_name = name_str.ptrw();
+
+ XSetClassHint(x11_display, wd.x11_window, classHint);
+ XFree(classHint);
+ }
+}
+void DisplayServerX11::set_context(Context p_context) {
+
+ _THREAD_SAFE_METHOD_
+
+ context = p_context;
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ _update_context(E->get());
+ }
+}
+void DisplayServerX11::set_native_icon(const String &p_filename) {
+ WARN_PRINT("Native icon not supported by this display server.");
+}
+
+bool g_set_icon_error = false;
+int set_icon_errorhandler(Display *dpy, XErrorEvent *ev) {
+ g_set_icon_error = true;
+ return 0;
+}
+
+void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
+ _THREAD_SAFE_METHOD_
+
+ WindowData &wd = windows[MAIN_WINDOW_ID];
+
+ int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&set_icon_errorhandler);
+
+ Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
+
+ if (p_icon.is_valid()) {
+ Ref<Image> img = p_icon->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
+
+ while (true) {
+ int w = img->get_width();
+ int h = img->get_height();
+
+ if (g_set_icon_error) {
+ g_set_icon_error = false;
+
+ WARN_PRINT("Icon too large, attempting to resize icon.");
+
+ int new_width, new_height;
+ if (w > h) {
+ new_width = w / 2;
+ new_height = h * new_width / w;
+ } else {
+ new_height = h / 2;
+ new_width = w * new_height / h;
+ }
+
+ w = new_width;
+ h = new_height;
+
+ if (!w || !h) {
+ WARN_PRINT("Unable to set icon.");
+ break;
+ }
+
+ img->resize(w, h, Image::INTERPOLATE_CUBIC);
+ }
+
+ // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
+ Vector<long> pd;
+
+ pd.resize(2 + w * h);
+
+ pd.write[0] = w;
+ pd.write[1] = h;
+
+ const uint8_t *r = img->get_data().ptr();
+
+ long *wr = &pd.write[2];
+ uint8_t const *pr = r;
+
+ for (int i = 0; i < w * h; i++) {
+ long v = 0;
+ // A R G B
+ v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
+ *wr++ = v;
+ pr += 4;
+ }
+
+ XChangeProperty(x11_display, wd.x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size());
+
+ if (!g_set_icon_error)
+ break;
+ }
+ } else {
+ XDeleteProperty(x11_display, wd.x11_window, net_wm_icon);
+ }
+
+ XFlush(x11_display);
+ XSetErrorHandler(oldHandler);
+}
+
+Vector<String> DisplayServerX11::get_rendering_drivers_func() {
+ Vector<String> drivers;
+
+#ifdef VULKAN_ENABLED
+ drivers.push_back("vulkan");
+#endif
+#ifdef OPENGL_ENABLED
+ drivers.push_back("opengl");
+#endif
+
+ return drivers;
+}
+
+DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+
+ return memnew(DisplayServerX11(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+}
+
+DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+
+ //Create window
+
+ long visualMask = VisualScreenMask;
+ int numberOfVisuals;
+ XVisualInfo vInfoTemplate = {};
+ vInfoTemplate.screen = DefaultScreen(x11_display);
+ XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+
+ Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
+
+ XSetWindowAttributes windowAttributes = {};
+ windowAttributes.colormap = colormap;
+ windowAttributes.background_pixel = 0xFFFFFFFF;
+ windowAttributes.border_pixel = 0;
+ windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
+
+ unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+
+ WindowID id;
+ {
+ WindowData wd;
+ wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+
+ XMapWindow(x11_display, wd.x11_window);
+
+ //associate PID
+ // make PID known to X11
+ {
+ const long pid = OS::get_singleton()->get_process_id();
+ Atom net_wm_pid = XInternAtom(x11_display, "_NET_WM_PID", False);
+ XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
+ }
+
+ long im_event_mask = 0;
+
+ {
+ XIEventMask all_event_mask;
+ XSetWindowAttributes new_attr;
+
+ new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
+ ButtonReleaseMask | EnterWindowMask |
+ LeaveWindowMask | PointerMotionMask |
+ Button1MotionMask |
+ Button2MotionMask | Button3MotionMask |
+ Button4MotionMask | Button5MotionMask |
+ ButtonMotionMask | KeymapStateMask |
+ ExposureMask | VisibilityChangeMask |
+ StructureNotifyMask |
+ SubstructureNotifyMask | SubstructureRedirectMask |
+ FocusChangeMask | PropertyChangeMask |
+ ColormapChangeMask | OwnerGrabButtonMask |
+ im_event_mask;
+
+ XChangeWindowAttributes(x11_display, wd.x11_window, CWEventMask, &new_attr);
+
+ static unsigned char all_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+
+ all_event_mask.deviceid = XIAllDevices;
+ all_event_mask.mask_len = sizeof(all_mask_data);
+ all_event_mask.mask = all_mask_data;
+
+ XISetMask(all_event_mask.mask, XI_HierarchyChanged);
+
+#ifdef TOUCH_ENABLED
+ if (xi.touch_devices.size()) {
+ XISetMask(all_event_mask.mask, XI_TouchBegin);
+ XISetMask(all_event_mask.mask, XI_TouchUpdate);
+ XISetMask(all_event_mask.mask, XI_TouchEnd);
+ XISetMask(all_event_mask.mask, XI_TouchOwnership);
+ }
+#endif
+
+ XISelectEvents(x11_display, wd.x11_window, &all_event_mask, 1);
+ }
+
+ /* set the titlebar name */
+ XStoreName(x11_display, wd.x11_window, "Godot");
+ XSetWMProtocols(x11_display, wd.x11_window, &wm_delete, 1);
+ XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1);
+
+ if (xim && xim_style) {
+
+ wd.xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, wd.x11_window, XNFocusWindow, wd.x11_window, (char *)nullptr);
+ if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) {
+ WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
+ XDestroyIC(wd.xic);
+ wd.xic = nullptr;
+ }
+ if (wd.xic) {
+ XUnsetICFocus(wd.xic);
+ } else {
+ WARN_PRINT("XCreateIC couldn't create wd.xic");
+ }
+ } else {
+
+ wd.xic = nullptr;
+ WARN_PRINT("XCreateIC couldn't create wd.xic");
+ }
+
+ _update_context(wd);
+
+ id = window_id_counter++;
+
+ windows[id] = wd;
+
+ {
+
+ if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) {
+
+ XSizeHints *xsh;
+ xsh = XAllocSizeHints();
+
+ xsh->flags = PMinSize | PMaxSize;
+ xsh->min_width = p_rect.size.width;
+ xsh->max_width = p_rect.size.width;
+ xsh->min_height = p_rect.size.height;
+ xsh->max_height = p_rect.size.height;
+
+ XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+ XFree(xsh);
+ }
+
+ bool make_utility = false;
+
+ if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = 0;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+
+ make_utility = true;
+ }
+ if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
+ make_utility = true;
+ }
+
+ if (make_utility) {
+ //this one seems to disable the fade animations for regular windows
+ //but has the drawback that will not get focus by default, so
+ //we need fo force it, unless no focus requested
+
+ Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
+ Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
+
+ XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
+
+ if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
+ //but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested
+ XEvent xev;
+ Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = net_active_window;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = 1;
+ xev.xclient.data.l[1] = CurrentTime;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ }
+ } else {
+ Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
+ Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
+
+ XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
+ }
+ }
+
+ if (id != MAIN_WINDOW_ID) {
+
+ XSizeHints my_hints = XSizeHints();
+
+ my_hints.flags = PPosition | PSize; /* I want to specify position and size */
+ my_hints.x = p_rect.position.x; /* The origin and size coords I want */
+ my_hints.y = p_rect.position.y;
+ my_hints.width = p_rect.size.width;
+ my_hints.height = p_rect.size.height;
+
+ XSetNormalHints(x11_display, wd.x11_window, &my_hints);
+ XMoveWindow(x11_display, wd.x11_window, p_rect.position.x, p_rect.position.y);
+ }
+
+#if defined(VULKAN_ENABLED)
+ if (context_vulkan) {
+ Error err = context_vulkan->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
+ }
+#endif
+
+ //set_class_hint(x11_display, wd.x11_window);
+ XFlush(x11_display);
+
+ XSync(x11_display, False);
+ //XSetErrorHandler(oldHandler);
+
+ XFree(visualInfo);
+ }
+
+ WindowData &wd = windows[id];
+
+ window_set_mode(p_mode, id);
+
+ //sync size
+ {
+ XWindowAttributes xwa;
+
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+
+ wd.position.x = xwa.x;
+ wd.position.y = xwa.y;
+ wd.size.width = xwa.width;
+ wd.size.height = xwa.height;
+
+ print_line("DisplayServer::_create_window " + itos(id) + " want rect: " + p_rect + " got rect " + Rect2i(xwa.x, xwa.y, xwa.width, xwa.height));
+ }
+
+ //set cursor
+ if (cursors[current_cursor] != None) {
+
+ XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]);
+ }
+ return id;
+}
+
+DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+
+ InputFilter::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
+
+ r_error = OK;
+
+ current_cursor = CURSOR_ARROW;
+ mouse_mode = MOUSE_MODE_VISIBLE;
+
+ for (int i = 0; i < CURSOR_MAX; i++) {
+
+ cursors[i] = None;
+ img[i] = nullptr;
+ }
+
+ last_button_state = 0;
+
+ xmbstring = nullptr;
+
+ last_click_ms = 0;
+ last_click_button_index = -1;
+ last_click_pos = Point2i(-100, -100);
+
+ last_timestamp = 0;
+ last_mouse_pos_valid = false;
+ last_keyrelease_time = 0;
+
+ XInitThreads(); //always use threads
+
+ /** XLIB INITIALIZATION **/
+ x11_display = XOpenDisplay(nullptr);
+
+ if (!x11_display) {
+ ERR_PRINT("X11 Display is not available");
+ r_error = ERR_UNAVAILABLE;
+ return;
+ }
+
+ char *modifiers = nullptr;
+ Bool xkb_dar = False;
+ XAutoRepeatOn(x11_display);
+ xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, nullptr);
+
+ // Try to support IME if detectable auto-repeat is supported
+ if (xkb_dar == True) {
+
+#ifdef X_HAVE_UTF8_STRING
+ // Xutf8LookupString will be used later instead of XmbLookupString before
+ // the multibyte sequences can be converted to unicode string.
+ modifiers = XSetLocaleModifiers("");
+#endif
+ }
+
+ if (modifiers == nullptr) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ WARN_PRINT("IME is disabled");
+ }
+ XSetLocaleModifiers("@im=none");
+ WARN_PRINT("Error setting locale modifiers");
+ }
+
+ const char *err;
+ xrr_get_monitors = nullptr;
+ xrr_free_monitors = nullptr;
+ int xrandr_major = 0;
+ int xrandr_minor = 0;
+ int event_base, error_base;
+ xrandr_ext_ok = XRRQueryExtension(x11_display, &event_base, &error_base);
+ xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY);
+ if (!xrandr_handle) {
+ err = dlerror();
+ fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
+ } else {
+ XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
+ if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
+ xrr_get_monitors = (xrr_get_monitors_t)dlsym(xrandr_handle, "XRRGetMonitors");
+ if (!xrr_get_monitors) {
+ err = dlerror();
+ fprintf(stderr, "could not find symbol XRRGetMonitors\nError: %s\n", err);
+ } else {
+ xrr_free_monitors = (xrr_free_monitors_t)dlsym(xrandr_handle, "XRRFreeMonitors");
+ if (!xrr_free_monitors) {
+ err = dlerror();
+ fprintf(stderr, "could not find XRRFreeMonitors\nError: %s\n", err);
+ xrr_get_monitors = nullptr;
+ }
+ }
+ }
+ }
+
+ if (!_refresh_device_info()) {
+ alert("Your system does not support XInput 2.\n"
+ "Please upgrade your distribution.",
+ "Unable to initialize XInput");
+ r_error = ERR_UNAVAILABLE;
+ return;
+ }
+
+ xim = XOpenIM(x11_display, nullptr, nullptr, nullptr);
+
+ if (xim == nullptr) {
+ WARN_PRINT("XOpenIM failed");
+ xim_style = 0L;
+ } else {
+ ::XIMCallback im_destroy_callback;
+ im_destroy_callback.client_data = (::XPointer)(this);
+ im_destroy_callback.callback = (::XIMProc)(_xim_destroy_callback);
+ if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback,
+ nullptr) != nullptr) {
+ WARN_PRINT("Error setting XIM destroy callback");
+ }
+
+ ::XIMStyles *xim_styles = nullptr;
+ xim_style = 0L;
+ char *imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, nullptr);
+ if (imvalret != nullptr || xim_styles == nullptr) {
+ fprintf(stderr, "Input method doesn't support any styles\n");
+ }
+
+ if (xim_styles) {
+ xim_style = 0L;
+ for (int i = 0; i < xim_styles->count_styles; i++) {
+
+ if (xim_styles->supported_styles[i] ==
+ (XIMPreeditNothing | XIMStatusNothing)) {
+
+ xim_style = xim_styles->supported_styles[i];
+ break;
+ }
+ }
+
+ XFree(xim_styles);
+ }
+ XFree(imvalret);
+ }
+
+ /* Atorm internment */
+ wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
+ //Set Xdnd (drag & drop) support
+ xdnd_aware = XInternAtom(x11_display, "XdndAware", False);
+ xdnd_version = 5;
+ xdnd_enter = XInternAtom(x11_display, "XdndEnter", False);
+ xdnd_position = XInternAtom(x11_display, "XdndPosition", False);
+ xdnd_status = XInternAtom(x11_display, "XdndStatus", False);
+ xdnd_action_copy = XInternAtom(x11_display, "XdndActionCopy", False);
+ xdnd_drop = XInternAtom(x11_display, "XdndDrop", False);
+ xdnd_finished = XInternAtom(x11_display, "XdndFinished", False);
+ xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
+ rendering_driver = p_rendering_driver;
+
+#ifndef _MSC_VER
+#warning Forcing vulkan rendering driver because OpenGL not implemented yet
+#endif
+ rendering_driver = "vulkan";
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ context_vulkan = memnew(VulkanContextX11);
+ if (context_vulkan->initialize() != OK) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
+ r_error = ERR_CANT_CREATE;
+ ERR_FAIL_MSG("Could not initialize Vulkan");
+ }
+ }
+#endif
+ // Init context and rendering device
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ if (getenv("DRI_PRIME") == nullptr) {
+ int use_prime = -1;
+
+ if (getenv("PRIMUS_DISPLAY") ||
+ getenv("PRIMUS_libGLd") ||
+ getenv("PRIMUS_libGLa") ||
+ getenv("PRIMUS_libGL") ||
+ getenv("PRIMUS_LOAD_GLOBAL") ||
+ getenv("BUMBLEBEE_SOCKET")) {
+
+ print_verbose("Optirun/primusrun detected. Skipping GPU detection");
+ use_prime = 0;
+ }
+
+ if (getenv("LD_LIBRARY_PATH")) {
+ String ld_library_path(getenv("LD_LIBRARY_PATH"));
+ Vector<String> libraries = ld_library_path.split(":");
+
+ for (int i = 0; i < libraries.size(); ++i) {
+ if (FileAccess::exists(libraries[i] + "/libGL.so.1") ||
+ FileAccess::exists(libraries[i] + "/libGL.so")) {
+
+ print_verbose("Custom libGL override detected. Skipping GPU detection");
+ use_prime = 0;
+ }
+ }
+ }
+
+ if (use_prime == -1) {
+ print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic.");
+ use_prime = detect_prime();
+ }
+
+ if (use_prime) {
+ print_line("Found discrete GPU, setting DRI_PRIME=1 to use it.");
+ print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU.");
+ setenv("DRI_PRIME", "1", 1);
+ }
+ }
+
+ ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
+
+ context_gles2 = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type));
+
+ if (context_gles2->initialize() != OK) {
+ memdelete(context_gles2);
+ context_gles2 = nullptr;
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+
+ context_gles2->set_use_vsync(current_videomode.use_vsync);
+
+ if (RasterizerGLES2::is_viable() == OK) {
+ RasterizerGLES2::register_config();
+ RasterizerGLES2::make_current();
+ } else {
+ memdelete(context_gles2);
+ context_gles2 = nullptr;
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ }
+#endif
+
+ WindowID main_window = _create_window(p_mode, p_flags, Rect2i(Point2(), p_resolution));
+ for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+ if (p_flags & (1 << i)) {
+ window_set_flag(WindowFlags(i), true, main_window);
+ }
+ }
+
+//create RenderingDevice if used
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ //temporary
+ rendering_device_vulkan = memnew(RenderingDeviceVulkan);
+ rendering_device_vulkan->initialize(context_vulkan);
+
+ RasterizerRD::make_current();
+ }
+#endif
+
+ /*
+ rendering_server = memnew(RenderingServerRaster);
+ if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
+ rendering_server = memnew(RenderingServerWrapMT(rendering_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
+ }
+ */
+
+ {
+ //set all event master mask
+ XIEventMask all_master_event_mask;
+ static unsigned char all_master_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+ all_master_event_mask.deviceid = XIAllMasterDevices;
+ all_master_event_mask.mask_len = sizeof(all_master_mask_data);
+ all_master_event_mask.mask = all_master_mask_data;
+ XISetMask(all_master_event_mask.mask, XI_DeviceChanged);
+ XISetMask(all_master_event_mask.mask, XI_RawMotion);
+ XISelectEvents(x11_display, DefaultRootWindow(x11_display), &all_master_event_mask, 1);
+ }
+
+ // Disabled by now since grabbing also blocks mouse events
+ // (they are received as extended events instead of standard events)
+ /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership);
+
+ // Grab touch devices to avoid OS gesture interference
+ for (int i = 0; i < xi.touch_devices.size(); ++i) {
+ XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
+ }*/
+
+ cursor_size = XcursorGetDefaultSize(x11_display);
+ cursor_theme = XcursorGetTheme(x11_display);
+
+ if (!cursor_theme) {
+ print_verbose("XcursorGetTheme could not get cursor theme");
+ cursor_theme = "default";
+ }
+
+ for (int i = 0; i < CURSOR_MAX; i++) {
+
+ static const char *cursor_file[] = {
+ "left_ptr",
+ "xterm",
+ "hand2",
+ "cross",
+ "watch",
+ "left_ptr_watch",
+ "fleur",
+ "dnd-move",
+ "crossed_circle",
+ "v_double_arrow",
+ "h_double_arrow",
+ "size_bdiag",
+ "size_fdiag",
+ "move",
+ "row_resize",
+ "col_resize",
+ "question_arrow"
+ };
+
+ img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size);
+ if (!img[i]) {
+ const char *fallback = nullptr;
+
+ switch (i) {
+ case CURSOR_POINTING_HAND:
+ fallback = "pointer";
+ break;
+ case CURSOR_CROSS:
+ fallback = "crosshair";
+ break;
+ case CURSOR_WAIT:
+ fallback = "wait";
+ break;
+ case CURSOR_BUSY:
+ fallback = "progress";
+ break;
+ case CURSOR_DRAG:
+ fallback = "grabbing";
+ break;
+ case CURSOR_CAN_DROP:
+ fallback = "hand1";
+ break;
+ case CURSOR_FORBIDDEN:
+ fallback = "forbidden";
+ break;
+ case CURSOR_VSIZE:
+ fallback = "ns-resize";
+ break;
+ case CURSOR_HSIZE:
+ fallback = "ew-resize";
+ break;
+ case CURSOR_BDIAGSIZE:
+ fallback = "fd_double_arrow";
+ break;
+ case CURSOR_FDIAGSIZE:
+ fallback = "bd_double_arrow";
+ break;
+ case CURSOR_MOVE:
+ img[i] = img[CURSOR_DRAG];
+ break;
+ case CURSOR_VSPLIT:
+ fallback = "sb_v_double_arrow";
+ break;
+ case CURSOR_HSPLIT:
+ fallback = "sb_h_double_arrow";
+ break;
+ case CURSOR_HELP:
+ fallback = "help";
+ break;
+ }
+ if (fallback != nullptr) {
+ img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size);
+ }
+ }
+ if (img[i]) {
+ cursors[i] = XcursorImageLoadCursor(x11_display, img[i]);
+ } else {
+ print_verbose("Failed loading custom cursor: " + String(cursor_file[i]));
+ }
+ }
+
+ {
+ // Creating an empty/transparent cursor
+
+ // Create 1x1 bitmap
+ Pixmap cursormask = XCreatePixmap(x11_display,
+ RootWindow(x11_display, DefaultScreen(x11_display)), 1, 1, 1);
+
+ // Fill with zero
+ XGCValues xgc;
+ xgc.function = GXclear;
+ GC gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
+ XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
+
+ // Color value doesn't matter. Mask zero means no foreground or background will be drawn
+ XColor col = {};
+
+ Cursor cursor = XCreatePixmapCursor(x11_display,
+ cursormask, // source (using cursor mask as placeholder, since it'll all be ignored)
+ cursormask, // mask
+ &col, &col, 0, 0);
+
+ XFreePixmap(x11_display, cursormask);
+ XFreeGC(x11_display, gc);
+
+ if (cursor == None) {
+ ERR_PRINT("FAILED CREATING CURSOR");
+ }
+
+ null_cursor = cursor;
+ }
+ cursor_set_shape(CURSOR_BUSY);
+
+ requested = None;
+
+ window_has_focus = true; // Set focus to true at init
+
+ /*if (p_desired.layered) {
+ set_window_per_pixel_transparency_enabled(true);
+ }*/
+
+ XEvent xevent;
+ while (XPending(x11_display) > 0) {
+ XNextEvent(x11_display, &xevent);
+ if (xevent.type == ConfigureNotify) {
+ _window_changed(&xevent);
+ }
+ }
+
+ _update_real_mouse_position(windows[MAIN_WINDOW_ID]);
+
+ r_error = OK;
+}
+DisplayServerX11::~DisplayServerX11() {
+
+ //destroy all windows
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+#ifdef VULKAN_ENABLED
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_destroy(E->key());
+ }
+#endif
+
+ if (E->get().xic) {
+ XDestroyIC(E->get().xic);
+ }
+ XUnmapWindow(x11_display, E->get().x11_window);
+ XDestroyWindow(x11_display, E->get().x11_window);
+ }
+
+ //destroy drivers
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ if (rendering_device_vulkan) {
+ rendering_device_vulkan->finalize();
+ memdelete(rendering_device_vulkan);
+ }
+
+ if (context_vulkan)
+ memdelete(context_vulkan);
+ }
+#endif
+
+ if (xrandr_handle)
+ dlclose(xrandr_handle);
+
+ for (int i = 0; i < CURSOR_MAX; i++) {
+ if (cursors[i] != None)
+ XFreeCursor(x11_display, cursors[i]);
+ if (img[i] != nullptr)
+ XcursorImageDestroy(img[i]);
+ };
+
+ if (xim) {
+ XCloseIM(xim);
+ }
+
+ XCloseDisplay(x11_display);
+ if (xmbstring)
+ memfree(xmbstring);
+}
+
+void DisplayServerX11::register_x11_driver() {
+
+ register_create_function("x11", create_func, get_rendering_drivers_func);
+}
+
+#endif // X11 enabled
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
new file mode 100644
index 0000000000..113e504e9b
--- /dev/null
+++ b/platform/linuxbsd/display_server_x11.h
@@ -0,0 +1,351 @@
+/*************************************************************************/
+/* display_server_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 DISPLAY_SERVER_X11_H
+#define DISPLAY_SERVER_X11_H
+
+#ifdef X11_ENABLED
+
+#include "servers/display_server.h"
+
+#include "core/input/input_filter.h"
+
+#include "drivers/alsa/audio_driver_alsa.h"
+#include "drivers/alsamidi/midi_driver_alsamidi.h"
+#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
+#include "drivers/unix/os_unix.h"
+#include "joypad_linux.h"
+#include "servers/audio_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
+
+#if defined(OPENGL_ENABLED)
+#include "context_gl_x11.h"
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_device_vulkan.h"
+#include "platform/linuxbsd/vulkan_context_x11.h"
+#endif
+
+#include <X11/Xcursor/Xcursor.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/keysym.h>
+
+// Hints for X11 fullscreen
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} Hints;
+
+typedef struct _xrr_monitor_info {
+ Atom name;
+ Bool primary;
+ Bool automatic;
+ int noutput;
+ int x;
+ int y;
+ int width;
+ int height;
+ int mwidth;
+ int mheight;
+ RROutput *outputs;
+} xrr_monitor_info;
+
+#undef CursorShape
+
+class DisplayServerX11 : public DisplayServer {
+ //No need to register, it's platform-specific and nothing is added
+ //GDCLASS(DisplayServerX11, DisplayServer)
+
+ _THREAD_SAFE_CLASS_
+
+ Atom wm_delete;
+ Atom xdnd_enter;
+ Atom xdnd_position;
+ Atom xdnd_status;
+ Atom xdnd_action_copy;
+ Atom xdnd_drop;
+ Atom xdnd_finished;
+ Atom xdnd_selection;
+ Atom xdnd_aware;
+ Atom requested;
+ int xdnd_version;
+
+#if defined(OPENGL_ENABLED)
+ ContextGL_X11 *context_gles2;
+#endif
+#if defined(VULKAN_ENABLED)
+ VulkanContextX11 *context_vulkan;
+ RenderingDeviceVulkan *rendering_device_vulkan;
+#endif
+
+ struct WindowData {
+ Window x11_window;
+ ::XIC xic;
+
+ Size2i min_size;
+ Size2i max_size;
+ Point2i position;
+ Size2i size;
+ Point2i im_position;
+ bool im_active = false;
+ Callable rect_changed_callback;
+ Callable event_callback;
+ Callable input_event_callback;
+ Callable input_text_callback;
+ Callable drop_files_callback;
+
+ WindowID transient_parent = INVALID_WINDOW_ID;
+ Set<WindowID> transient_children;
+
+ ObjectID instance_id;
+
+ //better to guess on the fly, given WM can change it
+ //WindowMode mode;
+ bool fullscreen = false; //OS can't exit from this mode
+ bool on_top = false;
+ bool borderless = false;
+ bool resize_disabled = false;
+ Vector2i last_position_before_fs;
+ };
+
+ Map<WindowID, WindowData> windows;
+
+ WindowID window_id_counter = MAIN_WINDOW_ID;
+ WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect);
+
+ String internal_clipboard;
+ Window xdnd_source_window;
+ ::Display *x11_display;
+ char *xmbstring;
+ int xmblen;
+ unsigned long last_timestamp;
+ ::Time last_keyrelease_time;
+ ::XIM xim;
+ ::XIMStyle xim_style;
+ static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data);
+
+ Point2i last_mouse_pos;
+ bool last_mouse_pos_valid;
+ Point2i last_click_pos;
+ uint64_t last_click_ms;
+ int last_click_button_index;
+ uint32_t last_button_state;
+
+ struct {
+ int opcode;
+ Vector<int> touch_devices;
+ Map<int, Vector2> absolute_devices;
+ Map<int, Vector3> pen_devices;
+ XIEventMask all_event_mask;
+ Map<int, Vector2> state;
+ double pressure;
+ Vector2 tilt;
+ Vector2 mouse_pos_to_filter;
+ Vector2 relative_motion;
+ Vector2 raw_pos;
+ Vector2 old_raw_pos;
+ ::Time last_relative_time;
+ } xi;
+
+ bool _refresh_device_info();
+
+ unsigned int _get_mouse_button_state(unsigned int p_x11_button, int p_x11_type);
+ void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
+ void _flush_mouse_motion();
+
+ MouseMode mouse_mode;
+ Point2i center;
+
+ void _handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo = false);
+
+ bool minimized;
+ bool window_has_focus;
+ bool do_mouse_warp;
+
+ const char *cursor_theme;
+ int cursor_size;
+ XcursorImage *img[CURSOR_MAX];
+ Cursor cursors[CURSOR_MAX];
+ Cursor null_cursor;
+ CursorShape current_cursor;
+ Map<CursorShape, Vector<Variant>> cursors_cache;
+
+ bool layered_window;
+
+ String rendering_driver;
+ bool window_focused;
+ //void set_wm_border(bool p_enabled);
+ void set_wm_fullscreen(bool p_enabled);
+ void set_wm_above(bool p_enabled);
+
+ typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
+ typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
+ xrr_get_monitors_t xrr_get_monitors;
+ xrr_free_monitors_t xrr_free_monitors;
+ void *xrandr_handle;
+ Bool xrandr_ext_ok;
+
+ struct Property {
+ unsigned char *data;
+ int format, nitems;
+ Atom type;
+ };
+ static Property _read_property(Display *p_display, Window p_window, Atom p_property);
+
+ void _update_real_mouse_position(const WindowData &wd);
+ void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
+ void _set_wm_maximized(WindowID p_window, bool p_enabled);
+
+ void _update_context(WindowData &wd);
+
+ Context context = CONTEXT_ENGINE;
+
+ void _send_window_event(const WindowData &wd, WindowEvent p_event);
+ static void _dispatch_input_events(const Ref<InputEvent> &p_event);
+ void _dispatch_input_event(const Ref<InputEvent> &p_event);
+
+protected:
+ void _window_changed(XEvent *event);
+
+public:
+ virtual bool has_feature(Feature p_feature) const;
+ virtual String get_name() const;
+
+ virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+
+ virtual void mouse_set_mode(MouseMode p_mode);
+ virtual MouseMode mouse_get_mode() const;
+
+ virtual void mouse_warp_to_position(const Point2i &p_to);
+ virtual Point2i mouse_get_position() const;
+ virtual Point2i mouse_get_absolute_position() const;
+ virtual int mouse_get_button_state() const;
+
+ virtual void clipboard_set(const String &p_text);
+ virtual String clipboard_get() const;
+
+ virtual int get_screen_count() const;
+ virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual Vector<DisplayServer::WindowID> get_window_list() const;
+
+ virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+ virtual void delete_sub_window(WindowID p_id);
+
+ virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
+
+ virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID);
+ virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_transient(WindowID p_window, WindowID p_parent);
+
+ virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
+ virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
+ virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual bool can_any_window_draw() const;
+
+ virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void cursor_set_shape(CursorShape p_shape);
+ virtual CursorShape cursor_get_shape() const;
+ virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
+
+ virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+ virtual void process_events();
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ virtual void set_context(Context p_context);
+
+ virtual void set_native_icon(const String &p_filename);
+ virtual void set_icon(const Ref<Image> &p_icon);
+
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static Vector<String> get_rendering_drivers_func();
+
+ static void register_x11_driver();
+
+ DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ ~DisplayServerX11();
+};
+
+#endif // X11 enabled
+
+#endif // DISPLAY_SERVER_X11_H
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
new file mode 100644
index 0000000000..53e3ce8f85
--- /dev/null
+++ b/platform/linuxbsd/export/export.cpp
@@ -0,0 +1,169 @@
+/*************************************************************************/
+/* export.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "export.h"
+
+#include "core/os/file_access.h"
+#include "editor/editor_export.h"
+#include "platform/linuxbsd/logo.gen.h"
+#include "scene/resources/texture.h"
+
+static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
+
+void register_linuxbsd_exporter() {
+
+ Ref<EditorExportPlatformPC> platform;
+ platform.instance();
+
+ Ref<Image> img = memnew(Image(_linuxbsd_logo));
+ Ref<ImageTexture> logo;
+ logo.instance();
+ logo->create_from_image(img);
+ platform->set_logo(logo);
+ platform->set_name("Linux/X11");
+ platform->set_extension("x86");
+ platform->set_extension("x86_64", "binary_format/64_bits");
+ platform->set_release_32("linux_x11_32_release");
+ platform->set_debug_32("linux_x11_32_debug");
+ platform->set_release_64("linux_x11_64_release");
+ platform->set_debug_64("linux_x11_64_debug");
+ platform->set_os_name("X11");
+ platform->set_chmod_flags(0755);
+ platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
+
+ EditorExport::get_singleton()->add_export_platform(platform);
+}
+
+static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
+
+ // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
+
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
+ if (!f) {
+ return ERR_CANT_OPEN;
+ }
+
+ // Read and check ELF magic number
+ {
+ uint32_t magic = f->get_32();
+ if (magic != 0x464c457f) { // 0x7F + "ELF"
+ f->close();
+ return ERR_FILE_CORRUPT;
+ }
+ }
+
+ // Read program architecture bits from class field
+
+ int bits = f->get_8() * 32;
+
+ if (bits == 32 && p_embedded_size >= 0x100000000) {
+ f->close();
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
+ }
+
+ // Get info about the section header table
+
+ int64_t section_table_pos;
+ int64_t section_header_size;
+ if (bits == 32) {
+ section_header_size = 40;
+ f->seek(0x20);
+ section_table_pos = f->get_32();
+ f->seek(0x30);
+ } else { // 64
+ section_header_size = 64;
+ f->seek(0x28);
+ section_table_pos = f->get_64();
+ f->seek(0x3c);
+ }
+ int num_sections = f->get_16();
+ int string_section_idx = f->get_16();
+
+ // Load the strings table
+ uint8_t *strings;
+ {
+ // Jump to the strings section header
+ f->seek(section_table_pos + string_section_idx * section_header_size);
+
+ // Read strings data size and offset
+ int64_t string_data_pos;
+ int64_t string_data_size;
+ if (bits == 32) {
+ f->seek(f->get_position() + 0x10);
+ string_data_pos = f->get_32();
+ string_data_size = f->get_32();
+ } else { // 64
+ f->seek(f->get_position() + 0x18);
+ string_data_pos = f->get_64();
+ string_data_size = f->get_64();
+ }
+
+ // Read strings data
+ f->seek(string_data_pos);
+ strings = (uint8_t *)memalloc(string_data_size);
+ if (!strings) {
+ f->close();
+ return ERR_OUT_OF_MEMORY;
+ }
+ f->get_buffer(strings, string_data_size);
+ }
+
+ // Search for the "pck" section
+
+ bool found = false;
+ for (int i = 0; i < num_sections; ++i) {
+
+ int64_t section_header_pos = section_table_pos + i * section_header_size;
+ f->seek(section_header_pos);
+
+ uint32_t name_offset = f->get_32();
+ if (strcmp((char *)strings + name_offset, "pck") == 0) {
+ // "pck" section found, let's patch!
+
+ if (bits == 32) {
+ f->seek(section_header_pos + 0x10);
+ f->store_32(p_embedded_start);
+ f->store_32(p_embedded_size);
+ } else { // 64
+ f->seek(section_header_pos + 0x18);
+ f->store_64(p_embedded_start);
+ f->store_64(p_embedded_size);
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ memfree(strings);
+ f->close();
+
+ return found ? OK : ERR_FILE_CORRUPT;
+}
diff --git a/platform/linuxbsd/export/export.h b/platform/linuxbsd/export/export.h
new file mode 100644
index 0000000000..5ee81f485e
--- /dev/null
+++ b/platform/linuxbsd/export/export.h
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* export.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 LINUXBSD_EXPORT_H
+#define LINUXBSD_EXPORT_H
+
+void register_linuxbsd_exporter();
+
+#endif // LINUXBSD_EXPORT_H
diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp
new file mode 100644
index 0000000000..710ba3ca40
--- /dev/null
+++ b/platform/linuxbsd/godot_linuxbsd.cpp
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* godot_linuxbsd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main/main.h"
+#include "os_linuxbsd.h"
+
+int main(int argc, char *argv[]) {
+
+ OS_LinuxBSD os;
+
+ setlocale(LC_CTYPE, "");
+
+ char *cwd = (char *)malloc(PATH_MAX);
+ ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY);
+ char *ret = getcwd(cwd, PATH_MAX);
+
+ Error err = Main::setup(argv[0], argc - 1, &argv[1]);
+ if (err != OK) {
+ free(cwd);
+ return 255;
+ }
+
+ if (Main::start())
+ os.run(); // it is actually the OS that decides how to run
+ Main::cleanup();
+
+ if (ret) { // Previous getcwd was successful
+ if (chdir(cwd) != 0) {
+ ERR_PRINT("Couldn't return to previous working directory.");
+ }
+ }
+ free(cwd);
+
+ return os.get_exit_code();
+}
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
new file mode 100644
index 0000000000..381eb909ba
--- /dev/null
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -0,0 +1,554 @@
+/*************************************************************************/
+/* joypad_linux.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 JOYDEV_ENABLED
+
+#include "joypad_linux.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <unistd.h>
+
+#ifdef UDEV_ENABLED
+#include <libudev.h>
+#endif
+
+#define LONG_BITS (sizeof(long) * 8)
+#define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0)
+#define NBITS(x) ((((x)-1) / LONG_BITS) + 1)
+
+#ifdef UDEV_ENABLED
+static const char *ignore_str = "/dev/input/js";
+#endif
+
+JoypadLinux::Joypad::Joypad() {
+ fd = -1;
+ dpad = 0;
+ devpath = "";
+ for (int i = 0; i < MAX_ABS; i++) {
+ abs_info[i] = nullptr;
+ }
+}
+
+JoypadLinux::Joypad::~Joypad() {
+
+ for (int i = 0; i < MAX_ABS; i++) {
+ if (abs_info[i]) {
+ memdelete(abs_info[i]);
+ }
+ }
+}
+
+void JoypadLinux::Joypad::reset() {
+ dpad = 0;
+ fd = -1;
+
+ InputFilter::JoyAxis jx;
+ jx.min = -1;
+ jx.value = 0.0f;
+ for (int i = 0; i < MAX_ABS; i++) {
+ abs_map[i] = -1;
+ curr_axis[i] = jx;
+ }
+}
+
+JoypadLinux::JoypadLinux(InputFilter *in) {
+ exit_udev = false;
+ input = in;
+ joy_thread = Thread::create(joy_thread_func, this);
+}
+
+JoypadLinux::~JoypadLinux() {
+ exit_udev = true;
+ Thread::wait_to_finish(joy_thread);
+ memdelete(joy_thread);
+ close_joypad();
+}
+
+void JoypadLinux::joy_thread_func(void *p_user) {
+
+ if (p_user) {
+ JoypadLinux *joy = (JoypadLinux *)p_user;
+ joy->run_joypad_thread();
+ }
+}
+
+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);
+#else
+ monitor_joypads();
+#endif
+}
+
+#ifdef UDEV_ENABLED
+void JoypadLinux::enumerate_joypads(udev *p_udev) {
+
+ udev_enumerate *enumerate;
+ udev_list_entry *devices, *dev_list_entry;
+ udev_device *dev;
+
+ enumerate = udev_enumerate_new(p_udev);
+ udev_enumerate_add_match_subsystem(enumerate, "input");
+
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(dev_list_entry, devices) {
+
+ const char *path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(p_udev, path);
+ const char *devnode = udev_device_get_devnode(dev);
+
+ if (devnode) {
+
+ String devnode_str = devnode;
+ if (devnode_str.find(ignore_str) == -1) {
+ MutexLock lock(joy_mutex);
+ open_joypad(devnode);
+ }
+ }
+ udev_device_unref(dev);
+ }
+ udev_enumerate_unref(enumerate);
+}
+
+void JoypadLinux::monitor_joypads(udev *p_udev) {
+
+ udev_device *dev = nullptr;
+ udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev");
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "input", nullptr);
+ udev_monitor_enable_receiving(mon);
+ int fd = udev_monitor_get_fd(mon);
+
+ while (!exit_udev) {
+
+ fd_set fds;
+ struct timeval tv;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ ret = select(fd + 1, &fds, nullptr, nullptr, &tv);
+
+ /* Check if our file descriptor has received data. */
+ if (ret > 0 && FD_ISSET(fd, &fds)) {
+ /* Make the call to receive the device.
+ select() ensured that this will not block. */
+ dev = udev_monitor_receive_device(mon);
+
+ if (dev && udev_device_get_devnode(dev) != 0) {
+
+ 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")
+ open_joypad(devnode);
+ else if (String(action) == "remove")
+ close_joypad(get_joy_from_path(devnode));
+ }
+ }
+
+ udev_device_unref(dev);
+ }
+ }
+ usleep(50000);
+ }
+ udev_monitor_unref(mon);
+}
+#endif
+
+void JoypadLinux::monitor_joypads() {
+
+ while (!exit_udev) {
+ {
+ MutexLock lock(joy_mutex);
+
+ for (int i = 0; i < 32; i++) {
+ char fname[64];
+ sprintf(fname, "/dev/input/event%d", i);
+ if (attached_devices.find(fname) == -1) {
+ open_joypad(fname);
+ }
+ }
+ }
+ usleep(1000000); // 1s
+ }
+}
+
+int JoypadLinux::get_joy_from_path(String p_path) const {
+
+ for (int i = 0; i < JOYPADS_MAX; i++) {
+
+ if (joypads[i].devpath == p_path) {
+ return i;
+ }
+ }
+ return -2;
+}
+
+void JoypadLinux::close_joypad(int p_id) {
+ if (p_id == -1) {
+ for (int i = 0; i < JOYPADS_MAX; i++) {
+
+ close_joypad(i);
+ };
+ return;
+ } else if (p_id < 0)
+ return;
+
+ Joypad &joy = joypads[p_id];
+
+ if (joy.fd != -1) {
+
+ close(joy.fd);
+ joy.fd = -1;
+ attached_devices.remove(attached_devices.find(joy.devpath));
+ input->joy_connection_changed(p_id, false, "");
+ };
+}
+
+static String _hex_str(uint8_t p_byte) {
+
+ static const char *dict = "0123456789abcdef";
+ char ret[3];
+ ret[2] = 0;
+
+ ret[0] = dict[p_byte >> 4];
+ ret[1] = dict[p_byte & 0xF];
+
+ return ret;
+}
+
+void JoypadLinux::setup_joypad_properties(int p_id) {
+
+ Joypad *joy = &joypads[p_id];
+
+ unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
+ unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
+
+ int num_buttons = 0;
+ int num_axes = 0;
+
+ if ((ioctl(joy->fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
+ (ioctl(joy->fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
+ return;
+ }
+ for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
+
+ if (test_bit(i, keybit)) {
+
+ joy->key_map[i] = num_buttons++;
+ }
+ }
+ for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
+
+ if (test_bit(i, keybit)) {
+
+ joy->key_map[i] = num_buttons++;
+ }
+ }
+ for (int i = 0; i < ABS_MISC; ++i) {
+ /* Skip hats */
+ if (i == ABS_HAT0X) {
+ i = ABS_HAT3Y;
+ continue;
+ }
+ if (test_bit(i, absbit)) {
+
+ joy->abs_map[i] = num_axes++;
+ joy->abs_info[i] = memnew(input_absinfo);
+ if (ioctl(joy->fd, EVIOCGABS(i), joy->abs_info[i]) < 0) {
+ memdelete(joy->abs_info[i]);
+ joy->abs_info[i] = nullptr;
+ }
+ }
+ }
+
+ joy->force_feedback = false;
+ joy->ff_effect_timestamp = 0;
+ unsigned long ffbit[NBITS(FF_CNT)];
+ if (ioctl(joy->fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) {
+ if (test_bit(FF_RUMBLE, ffbit)) {
+ joy->force_feedback = true;
+ }
+ }
+}
+
+void JoypadLinux::open_joypad(const char *p_path) {
+
+ int joy_num = input->get_unused_joy_id();
+ int fd = open(p_path, O_RDWR | O_NONBLOCK);
+ if (fd != -1 && joy_num != -1) {
+
+ unsigned long evbit[NBITS(EV_MAX)] = { 0 };
+ unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
+ unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
+
+ // add to attached devices so we don't try to open it again
+ attached_devices.push_back(String(p_path));
+
+ if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
+ (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
+ (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
+ close(fd);
+ return;
+ }
+
+ //check if the device supports basic gamepad events, prevents certain keyboards from
+ //being detected as joypads
+ if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
+ (test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) ||
+ test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) &&
+ (test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) ||
+ test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit))) &&
+ !(test_bit(EV_ABS, evbit) &&
+ test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
+ test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit))) {
+ close(fd);
+ return;
+ }
+
+ char uid[128];
+ char namebuf[128];
+ String name = "";
+ input_id inpid;
+ if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) {
+ name = namebuf;
+ }
+
+ if (ioctl(fd, EVIOCGID, &inpid) < 0) {
+ close(fd);
+ return;
+ }
+
+ joypads[joy_num].reset();
+
+ Joypad &joy = joypads[joy_num];
+ joy.fd = fd;
+ joy.devpath = String(p_path);
+ setup_joypad_properties(joy_num);
+ sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0);
+ if (inpid.vendor && inpid.product && inpid.version) {
+
+ uint16_t vendor = BSWAP16(inpid.vendor);
+ uint16_t product = BSWAP16(inpid.product);
+ uint16_t version = BSWAP16(inpid.version);
+
+ sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0);
+ input->joy_connection_changed(joy_num, true, name, uid);
+ } else {
+ String uidname = uid;
+ int uidlen = MIN(name.length(), 11);
+ for (int i = 0; i < uidlen; i++) {
+
+ uidname = uidname + _hex_str(name[i]);
+ }
+ uidname += "00";
+ input->joy_connection_changed(joy_num, true, name, uidname);
+ }
+ }
+}
+
+void JoypadLinux::joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) {
+ Joypad &joy = joypads[p_id];
+ if (!joy.force_feedback || joy.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
+ return;
+ }
+ if (joy.ff_effect_id != -1) {
+ joypad_vibration_stop(p_id, p_timestamp);
+ }
+
+ struct ff_effect effect;
+ effect.type = FF_RUMBLE;
+ effect.id = -1;
+ effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff);
+ effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff);
+ effect.replay.length = floor(p_duration * 1000);
+ effect.replay.delay = 0;
+
+ if (ioctl(joy.fd, EVIOCSFF, &effect) < 0) {
+ return;
+ }
+
+ struct input_event play;
+ play.type = EV_FF;
+ play.code = effect.id;
+ play.value = 1;
+ if (write(joy.fd, (const void *)&play, sizeof(play)) == -1) {
+ print_verbose("Couldn't write to Joypad device.");
+ }
+
+ joy.ff_effect_id = effect.id;
+ joy.ff_effect_timestamp = p_timestamp;
+}
+
+void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) {
+ Joypad &joy = joypads[p_id];
+ if (!joy.force_feedback || joy.fd == -1 || joy.ff_effect_id == -1) {
+ return;
+ }
+
+ if (ioctl(joy.fd, EVIOCRMFF, joy.ff_effect_id) < 0) {
+ return;
+ }
+
+ joy.ff_effect_id = -1;
+ joy.ff_effect_timestamp = p_timestamp;
+}
+
+InputFilter::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
+
+ int min = p_abs->minimum;
+ int max = p_abs->maximum;
+ InputFilter::JoyAxis jx;
+
+ if (min < 0) {
+ jx.min = -1;
+ if (p_value < 0) {
+ jx.value = (float)-p_value / min;
+ } else {
+ jx.value = (float)p_value / max;
+ }
+ } else if (min == 0) {
+ jx.min = 0;
+ jx.value = 0.0f + (float)p_value / max;
+ }
+ return jx;
+}
+
+void JoypadLinux::process_joypads() {
+
+ if (joy_mutex.try_lock() != OK) {
+ return;
+ }
+ for (int i = 0; i < JOYPADS_MAX; i++) {
+
+ if (joypads[i].fd == -1) continue;
+
+ input_event events[32];
+ Joypad *joy = &joypads[i];
+
+ int len;
+
+ while ((len = read(joy->fd, events, (sizeof events))) > 0) {
+ len /= sizeof(events[0]);
+ for (int j = 0; j < len; j++) {
+
+ input_event &ev = events[j];
+
+ // ev may be tainted and out of MAX_KEY range, which will cause
+ // joy->key_map[ev.code] to crash
+ if (ev.code >= MAX_KEY)
+ return;
+
+ switch (ev.type) {
+ case EV_KEY:
+ input->joy_button(i, joy->key_map[ev.code], ev.value);
+ break;
+
+ case EV_ABS:
+
+ switch (ev.code) {
+ case ABS_HAT0X:
+ if (ev.value != 0) {
+ if (ev.value < 0)
+ joy->dpad |= InputFilter::HAT_MASK_LEFT;
+ else
+ joy->dpad |= InputFilter::HAT_MASK_RIGHT;
+ } else
+ joy->dpad &= ~(InputFilter::HAT_MASK_LEFT | InputFilter::HAT_MASK_RIGHT);
+
+ input->joy_hat(i, joy->dpad);
+ break;
+
+ case ABS_HAT0Y:
+ if (ev.value != 0) {
+ if (ev.value < 0)
+ joy->dpad |= InputFilter::HAT_MASK_UP;
+ else
+ joy->dpad |= InputFilter::HAT_MASK_DOWN;
+ } else
+ joy->dpad &= ~(InputFilter::HAT_MASK_UP | InputFilter::HAT_MASK_DOWN);
+
+ input->joy_hat(i, joy->dpad);
+ break;
+
+ default:
+ if (ev.code >= MAX_ABS)
+ return;
+ if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
+ InputFilter::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
+ joy->curr_axis[joy->abs_map[ev.code]] = value;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ }
+ for (int j = 0; j < MAX_ABS; j++) {
+ int index = joy->abs_map[j];
+ if (index != -1) {
+ input->joy_axis(i, index, joy->curr_axis[index]);
+ }
+ }
+ if (len == 0 || (len < 0 && errno != EAGAIN)) {
+ close_joypad(i);
+ };
+
+ if (joy->force_feedback) {
+ uint64_t timestamp = input->get_joy_vibration_timestamp(i);
+ if (timestamp > joy->ff_effect_timestamp) {
+ Vector2 strength = input->get_joy_vibration_strength(i);
+ float duration = input->get_joy_vibration_duration(i);
+ if (strength.x == 0 && strength.y == 0) {
+ joypad_vibration_stop(i, timestamp);
+ } else {
+ joypad_vibration_start(i, strength.x, strength.y, duration, timestamp);
+ }
+ }
+ }
+ }
+ joy_mutex.unlock();
+}
+#endif
diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h
new file mode 100644
index 0000000000..1d2ed5bbc1
--- /dev/null
+++ b/platform/linuxbsd/joypad_linux.h
@@ -0,0 +1,102 @@
+/*************************************************************************/
+/* joypad_linux.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+//author: Andreas Haas <hondres, liugam3@gmail.com>
+#ifndef JOYPAD_LINUX_H
+#define JOYPAD_LINUX_H
+
+#ifdef JOYDEV_ENABLED
+#include "core/input/input_filter.h"
+#include "core/os/mutex.h"
+#include "core/os/thread.h"
+
+struct input_absinfo;
+
+class JoypadLinux {
+public:
+ JoypadLinux(InputFilter *in);
+ ~JoypadLinux();
+ void process_joypads();
+
+private:
+ enum {
+ JOYPADS_MAX = 16,
+ MAX_ABS = 63,
+ MAX_KEY = 767, // Hack because <linux/input.h> can't be included here
+ };
+
+ struct Joypad {
+ InputFilter::JoyAxis curr_axis[MAX_ABS];
+ int key_map[MAX_KEY];
+ int abs_map[MAX_ABS];
+ int dpad;
+ int fd;
+
+ String devpath;
+ input_absinfo *abs_info[MAX_ABS];
+
+ bool force_feedback;
+ int ff_effect_id;
+ uint64_t ff_effect_timestamp;
+
+ Joypad();
+ ~Joypad();
+ void reset();
+ };
+
+ bool exit_udev;
+ Mutex joy_mutex;
+ Thread *joy_thread;
+ InputFilter *input;
+ Joypad joypads[JOYPADS_MAX];
+ Vector<String> attached_devices;
+
+ static void joy_thread_func(void *p_user);
+
+ int get_joy_from_path(String p_path) const;
+
+ void setup_joypad_properties(int p_id);
+ void close_joypad(int p_id = -1);
+#ifdef UDEV_ENABLED
+ void enumerate_joypads(struct udev *p_udev);
+ void monitor_joypads(struct udev *p_udev);
+#endif
+ void monitor_joypads();
+ void run_joypad_thread();
+ void open_joypad(const char *p_path);
+
+ 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);
+
+ InputFilter::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
+};
+
+#endif
+#endif // JOYPAD_LINUX_H
diff --git a/platform/x11/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp
index 78bd2b71a0..78bd2b71a0 100644
--- a/platform/x11/key_mapping_x11.cpp
+++ b/platform/linuxbsd/key_mapping_x11.cpp
diff --git a/platform/x11/key_mapping_x11.h b/platform/linuxbsd/key_mapping_x11.h
index 10db43bcc4..10db43bcc4 100644
--- a/platform/x11/key_mapping_x11.h
+++ b/platform/linuxbsd/key_mapping_x11.h
diff --git a/platform/x11/logo.png b/platform/linuxbsd/logo.png
index 078654b757..078654b757 100644
--- a/platform/x11/logo.png
+++ b/platform/linuxbsd/logo.png
Binary files differ
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
new file mode 100644
index 0000000000..5b9a25bd8b
--- /dev/null
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -0,0 +1,381 @@
+/*************************************************************************/
+/* os_linuxbsd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "os_linuxbsd.h"
+
+#include "core/os/dir_access.h"
+#include "core/print_string.h"
+#include "errno.h"
+
+#ifdef HAVE_MNTENT
+#include <mntent.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "main/main.h"
+
+#ifdef X11_ENABLED
+#include "display_server_x11.h"
+#endif
+
+void OS_LinuxBSD::initialize() {
+
+ crash_handler.initialize();
+
+ OS_Unix::initialize_core();
+}
+
+void OS_LinuxBSD::initialize_joypads() {
+
+#ifdef JOYDEV_ENABLED
+ joypad = memnew(JoypadLinux(InputFilter::get_singleton()));
+#endif
+}
+
+String OS_LinuxBSD::get_unique_id() const {
+
+ static String machine_id;
+ if (machine_id.empty()) {
+ if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) {
+ while (machine_id.empty() && !f->eof_reached()) {
+ machine_id = f->get_line().strip_edges();
+ }
+ f->close();
+ memdelete(f);
+ }
+ }
+ return machine_id;
+}
+
+void OS_LinuxBSD::finalize() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop = nullptr;
+
+#ifdef ALSAMIDI_ENABLED
+ driver_alsamidi.close();
+#endif
+
+#ifdef JOYDEV_ENABLED
+ memdelete(joypad);
+#endif
+}
+
+MainLoop *OS_LinuxBSD::get_main_loop() const {
+
+ return main_loop;
+}
+
+void OS_LinuxBSD::delete_main_loop() {
+
+ if (main_loop)
+ memdelete(main_loop);
+ main_loop = nullptr;
+}
+
+void OS_LinuxBSD::set_main_loop(MainLoop *p_main_loop) {
+
+ main_loop = p_main_loop;
+}
+
+String OS_LinuxBSD::get_name() const {
+
+#ifdef __linux__
+ return "Linux";
+#elif defined(__FreeBSD__)
+ return "FreeBSD";
+#elif defined(__NetBSD__)
+ return "NetBSD";
+#else
+ return "BSD";
+#endif
+}
+
+Error OS_LinuxBSD::shell_open(String p_uri) {
+
+ Error ok;
+ List<String> args;
+ args.push_back(p_uri);
+ ok = execute("xdg-open", args, false);
+ if (ok == OK)
+ return OK;
+ ok = execute("gnome-open", args, false);
+ if (ok == OK)
+ return OK;
+ ok = execute("kde-open", args, false);
+ return ok;
+}
+
+bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
+
+ return p_feature == "pc";
+}
+
+String OS_LinuxBSD::get_config_path() const {
+
+ if (has_environment("XDG_CONFIG_HOME")) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".config");
+ } else {
+ return ".";
+ }
+}
+
+String OS_LinuxBSD::get_data_path() const {
+
+ if (has_environment("XDG_DATA_HOME")) {
+ return get_environment("XDG_DATA_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".local/share");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_LinuxBSD::get_cache_path() const {
+
+ if (has_environment("XDG_CACHE_HOME")) {
+ return get_environment("XDG_CACHE_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".cache");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_LinuxBSD::get_system_dir(SystemDir p_dir) const {
+
+ String xdgparam;
+
+ switch (p_dir) {
+ case SYSTEM_DIR_DESKTOP: {
+
+ xdgparam = "DESKTOP";
+ } break;
+ case SYSTEM_DIR_DCIM: {
+
+ xdgparam = "PICTURES";
+
+ } break;
+ case SYSTEM_DIR_DOCUMENTS: {
+
+ xdgparam = "DOCUMENTS";
+
+ } break;
+ case SYSTEM_DIR_DOWNLOADS: {
+
+ xdgparam = "DOWNLOAD";
+
+ } break;
+ case SYSTEM_DIR_MOVIES: {
+
+ xdgparam = "VIDEOS";
+
+ } break;
+ case SYSTEM_DIR_MUSIC: {
+
+ xdgparam = "MUSIC";
+
+ } break;
+ case SYSTEM_DIR_PICTURES: {
+
+ xdgparam = "PICTURES";
+
+ } break;
+ case SYSTEM_DIR_RINGTONES: {
+
+ xdgparam = "MUSIC";
+
+ } break;
+ }
+
+ String pipe;
+ List<String> arg;
+ arg.push_back(xdgparam);
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("xdg-user-dir", arg, true, nullptr, &pipe);
+ if (err != OK)
+ return ".";
+ return pipe.strip_edges();
+}
+
+void OS_LinuxBSD::run() {
+
+ force_quit = false;
+
+ if (!main_loop)
+ return;
+
+ main_loop->init();
+
+ //uint64_t last_ticks=get_ticks_usec();
+
+ //int frames=0;
+ //uint64_t frame=0;
+
+ while (!force_quit) {
+
+ DisplayServer::get_singleton()->process_events(); // get rid of pending events
+#ifdef JOYDEV_ENABLED
+ joypad->process_joypads();
+#endif
+ if (Main::iteration())
+ break;
+ };
+
+ main_loop->finish();
+}
+
+void OS_LinuxBSD::disable_crash_handler() {
+ crash_handler.disable();
+}
+
+bool OS_LinuxBSD::is_disable_crash_handler() const {
+ return crash_handler.is_disabled();
+}
+
+static String get_mountpoint(const String &p_path) {
+ struct stat s;
+ if (stat(p_path.utf8().get_data(), &s)) {
+ return "";
+ }
+
+#ifdef HAVE_MNTENT
+ dev_t dev = s.st_dev;
+ FILE *fd = setmntent("/proc/mounts", "r");
+ if (!fd) {
+ return "";
+ }
+
+ struct mntent mnt;
+ char buf[1024];
+ size_t buflen = 1024;
+ while (getmntent_r(fd, &mnt, buf, buflen)) {
+ if (!stat(mnt.mnt_dir, &s) && s.st_dev == dev) {
+ endmntent(fd);
+ return String(mnt.mnt_dir);
+ }
+ }
+
+ endmntent(fd);
+#endif
+ return "";
+}
+
+Error OS_LinuxBSD::move_to_trash(const String &p_path) {
+ String trash_can = "";
+ String mnt = get_mountpoint(p_path);
+
+ // If there is a directory "[Mountpoint]/.Trash-[UID]/files", use it as the trash can.
+ if (mnt != "") {
+ String path(mnt + "/.Trash-" + itos(getuid()) + "/files");
+ struct stat s;
+ if (!stat(path.utf8().get_data(), &s)) {
+ trash_can = path;
+ }
+ }
+
+ // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash/files" as the trash can.
+ if (trash_can == "") {
+ char *dhome = getenv("XDG_DATA_HOME");
+ if (dhome) {
+ trash_can = String(dhome) + "/Trash/files";
+ }
+ }
+
+ // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash/files" as the trash can.
+ if (trash_can == "") {
+ char *home = getenv("HOME");
+ if (home) {
+ trash_can = String(home) + "/.local/share/Trash/files";
+ }
+ }
+
+ // Issue an error if none of the previous locations is appropriate for the trash can.
+ if (trash_can == "") {
+ ERR_PRINT("move_to_trash: Could not determine the trash can location");
+ return FAILED;
+ }
+
+ // Create needed directories for decided trash can location.
+ DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Error err = dir_access->make_dir_recursive(trash_can);
+ memdelete(dir_access);
+
+ // Issue an error if trash can is not created proprely.
+ if (err != OK) {
+ ERR_PRINT("move_to_trash: Could not create the trash can \"" + trash_can + "\"");
+ return err;
+ }
+
+ // The trash can is successfully created, now move the given resource to it.
+ // Do not use DirAccess:rename() because it can't move files across multiple mountpoints.
+ List<String> mv_args;
+ mv_args.push_back(p_path);
+ mv_args.push_back(trash_can);
+ int retval;
+ err = execute("mv", mv_args, true, nullptr, nullptr, &retval);
+
+ // Issue an error if "mv" failed to move the given resource to the trash can.
+ if (err != OK || retval != 0) {
+ ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_can + "\"");
+ return FAILED;
+ }
+
+ return OK;
+}
+
+OS_LinuxBSD::OS_LinuxBSD() {
+
+ main_loop = nullptr;
+ force_quit = false;
+
+#ifdef PULSEAUDIO_ENABLED
+ AudioDriverManager::add_driver(&driver_pulseaudio);
+#endif
+
+#ifdef ALSA_ENABLED
+ AudioDriverManager::add_driver(&driver_alsa);
+#endif
+
+#ifdef X11_ENABLED
+ DisplayServerX11::register_x11_driver();
+#endif
+}
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
new file mode 100644
index 0000000000..100cb53ba3
--- /dev/null
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* os_linuxbsd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 OS_LINUXBSD_H
+#define OS_LINUXBSD_H
+
+#include "core/input/input_filter.h"
+#include "crash_handler_linuxbsd.h"
+#include "drivers/alsa/audio_driver_alsa.h"
+#include "drivers/alsamidi/midi_driver_alsamidi.h"
+#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
+#include "drivers/unix/os_unix.h"
+#include "joypad_linux.h"
+#include "servers/audio_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
+
+class OS_LinuxBSD : public OS_Unix {
+
+ virtual void delete_main_loop();
+
+ bool force_quit;
+
+#ifdef JOYDEV_ENABLED
+ JoypadLinux *joypad;
+#endif
+
+#ifdef ALSA_ENABLED
+ AudioDriverALSA driver_alsa;
+#endif
+
+#ifdef ALSAMIDI_ENABLED
+ MIDIDriverALSAMidi driver_alsamidi;
+#endif
+
+#ifdef PULSEAUDIO_ENABLED
+ AudioDriverPulseAudio driver_pulseaudio;
+#endif
+
+ CrashHandler crash_handler;
+
+ MainLoop *main_loop;
+
+protected:
+ virtual void initialize();
+ virtual void finalize();
+
+ virtual void initialize_joypads();
+
+ virtual void set_main_loop(MainLoop *p_main_loop);
+
+public:
+ virtual String get_name() const;
+
+ virtual MainLoop *get_main_loop() const;
+
+ virtual String get_config_path() const;
+ virtual String get_data_path() const;
+ virtual String get_cache_path() const;
+
+ virtual String get_system_dir(SystemDir p_dir) const;
+
+ virtual Error shell_open(String p_uri);
+
+ virtual String get_unique_id() const;
+
+ virtual bool _check_internal_feature_support(const String &p_feature);
+
+ void run();
+
+ void disable_crash_handler();
+ bool is_disable_crash_handler() const;
+
+ virtual Error move_to_trash(const String &p_path);
+
+ OS_LinuxBSD();
+};
+
+#endif
diff --git a/platform/x11/pck_embed.ld b/platform/linuxbsd/pck_embed.ld
index 57a1994043..57a1994043 100644
--- a/platform/x11/pck_embed.ld
+++ b/platform/linuxbsd/pck_embed.ld
diff --git a/platform/x11/pck_embed.legacy.ld b/platform/linuxbsd/pck_embed.legacy.ld
index a23013ba7a..a23013ba7a 100644
--- a/platform/x11/pck_embed.legacy.ld
+++ b/platform/linuxbsd/pck_embed.legacy.ld
diff --git a/platform/x11/platform_config.h b/platform/linuxbsd/platform_config.h
index ac30519132..ac30519132 100644
--- a/platform/x11/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
diff --git a/platform/linuxbsd/platform_linuxbsd_builders.py b/platform/linuxbsd/platform_linuxbsd_builders.py
new file mode 100644
index 0000000000..58234f3748
--- /dev/null
+++ b/platform/linuxbsd/platform_linuxbsd_builders.py
@@ -0,0 +1,17 @@
+"""Functions used to generate source files during build time
+
+All such functions are invoked in a subprocess on Windows to prevent build flakiness.
+
+"""
+import os
+from platform_methods import subprocess_main
+
+
+def make_debug_linuxbsd(target, source, env):
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ os.system("strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+
+
+if __name__ == "__main__":
+ subprocess_main(globals())
diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/vulkan_context_x11.cpp
new file mode 100644
index 0000000000..1798a7026e
--- /dev/null
+++ b/platform/linuxbsd/vulkan_context_x11.cpp
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* vulkan_context_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "vulkan_context_x11.h"
+#include <vulkan/vulkan_xlib.h>
+
+const char *VulkanContextX11::_get_platform_surface_extension() const {
+ return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
+}
+
+Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
+
+ VkXlibSurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.dpy = p_display;
+ createInfo.window = p_window;
+
+ VkSurfaceKHR surface;
+ VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
+ ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ return _window_create(p_window_id, surface, p_width, p_height);
+}
+
+VulkanContextX11::VulkanContextX11() {
+}
+
+VulkanContextX11::~VulkanContextX11() {
+}
diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h
new file mode 100644
index 0000000000..6e144ab2d9
--- /dev/null
+++ b/platform/linuxbsd/vulkan_context_x11.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* vulkan_context_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VULKAN_DEVICE_X11_H
+#define VULKAN_DEVICE_X11_H
+
+#include "drivers/vulkan/vulkan_context.h"
+#include <X11/Xlib.h>
+
+class VulkanContextX11 : public VulkanContext {
+
+ virtual const char *_get_platform_surface_extension() const;
+
+public:
+ Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height);
+
+ VulkanContextX11();
+ ~VulkanContextX11();
+};
+
+#endif // VULKAN_DEVICE_X11_H
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index 0a4e0a45e1..ad62db358b 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -1,22 +1,22 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
from platform_methods import run_in_subprocess
import platform_osx_builders
files = [
- 'crash_handler_osx.mm',
- 'os_osx.mm',
- 'godot_main_osx.mm',
- 'dir_access_osx.mm',
- 'joypad_osx.cpp',
- 'vulkan_context_osx.mm',
- 'context_gl_osx.mm'
+ "crash_handler_osx.mm",
+ "os_osx.mm",
+ "display_server_osx.mm",
+ "godot_main_osx.mm",
+ "dir_access_osx.mm",
+ "joypad_osx.cpp",
+ "vulkan_context_osx.mm",
+ "context_gl_osx.mm",
]
-prog = env.add_program('#bin/godot', files)
+prog = env.add_program("#bin/godot", files)
if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_osx_builders.make_debug_osx))
-
diff --git a/platform/osx/context_gl_osx.h b/platform/osx/context_gl_osx.h
index 6e73c2203a..7e436c5e36 100644
--- a/platform/osx/context_gl_osx.h
+++ b/platform/osx/context_gl_osx.h
@@ -72,4 +72,4 @@ public:
};
#endif
-#endif \ No newline at end of file
+#endif
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 12ca5c10dc..29aa8ece19 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -14,7 +14,7 @@ def get_name():
def can_build():
- if (sys.platform == "darwin" or ("OSXCROSS_ROOT" in os.environ)):
+ if sys.platform == "darwin" or ("OSXCROSS_ROOT" in os.environ):
return True
return False
@@ -24,52 +24,55 @@ def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
return [
- ('osxcross_sdk', 'OSXCross SDK version', 'darwin14'),
- ('MACOS_SDK_PATH', 'Path to the macOS SDK', ''),
- BoolVariable('use_static_mvk', 'Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)', False),
- EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
- 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),
+ ("osxcross_sdk", "OSXCross SDK version", "darwin14"),
+ ("MACOS_SDK_PATH", "Path to the macOS SDK", ""),
+ BoolVariable(
+ "use_static_mvk",
+ "Link MoltenVK statically as Level-0 driver (better portability) or use Vulkan ICD loader (enables validation layers)",
+ False,
+ ),
+ EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
+ 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),
]
def get_flags():
- return [
- ]
+ return []
def configure(env):
- ## Build type
-
- if (env["target"] == "release"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O3', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os','-ftree-vectorize', '-msse2'])
-
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "release_debug"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O2'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
- env.Prepend(CPPDEFINES=['DEBUG_ENABLED'])
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "debug"):
- env.Prepend(CCFLAGS=['-g3'])
- env.Prepend(CPPDEFINES=['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
+ ## Build type
+
+ if env["target"] == "release":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize", "-msse2"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize", "-msse2"])
+
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "release_debug":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Prepend(CCFLAGS=["-O2"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+ env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "debug":
+ env.Prepend(CCFLAGS=["-g3"])
+ env.Prepend(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
## Architecture
@@ -83,86 +86,109 @@ def configure(env):
if "OSXCROSS_ROOT" in os.environ:
env["osxcross"] = True
- if not "osxcross" in env: # regular native build
- env.Append(CCFLAGS=['-arch', 'x86_64'])
- env.Append(LINKFLAGS=['-arch', 'x86_64'])
- if (env["macports_clang"] != 'no'):
+ if not "osxcross" in env: # regular native build
+ env.Append(CCFLAGS=["-arch", "x86_64"])
+ env.Append(LINKFLAGS=["-arch", "x86_64"])
+ if env["macports_clang"] != "no":
mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local")
mpclangver = env["macports_clang"]
env["CC"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang"
env["LINK"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang++"
env["CXX"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/clang++"
- env['AR'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar"
- env['RANLIB'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib"
- env['AS'] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as"
- env.Append(CPPDEFINES=['__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
+ env["AR"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ar"
+ env["RANLIB"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-ranlib"
+ env["AS"] = mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-as"
+ env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define
else:
- env['CC'] = 'clang'
- env['CXX'] = 'clang++'
+ env["CC"] = "clang"
+ env["CXX"] = "clang++"
- detect_darwin_sdk_path('osx', env)
- env.Append(CCFLAGS=['-isysroot', '$MACOS_SDK_PATH'])
- env.Append(LINKFLAGS=['-isysroot', '$MACOS_SDK_PATH'])
+ detect_darwin_sdk_path("osx", env)
+ env.Append(CCFLAGS=["-isysroot", "$MACOS_SDK_PATH"])
+ env.Append(LINKFLAGS=["-isysroot", "$MACOS_SDK_PATH"])
- else: # osxcross build
+ else: # osxcross build
root = os.environ.get("OSXCROSS_ROOT", 0)
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
ccache_path = os.environ.get("CCACHE")
if ccache_path is None:
- env['CC'] = basecmd + "cc"
- env['CXX'] = basecmd + "c++"
+ env["CC"] = basecmd + "cc"
+ env["CXX"] = basecmd + "c++"
else:
# there aren't any ccache wrappers available for OS X cross-compile,
# to enable caching we need to prepend the path to the ccache binary
- env['CC'] = ccache_path + ' ' + basecmd + "cc"
- env['CXX'] = ccache_path + ' ' + basecmd + "c++"
- env['AR'] = basecmd + "ar"
- env['RANLIB'] = basecmd + "ranlib"
- env['AS'] = basecmd + "as"
- env.Append(CPPDEFINES=['__MACPORTS__']) #hack to fix libvpx MM256_BROADCASTSI128_SI256 define
-
- if (env["CXX"] == "clang++"):
- env.Append(CPPDEFINES=['TYPED_METHOD_BIND'])
+ env["CC"] = ccache_path + " " + basecmd + "cc"
+ env["CXX"] = ccache_path + " " + basecmd + "c++"
+ env["AR"] = basecmd + "ar"
+ env["RANLIB"] = basecmd + "ranlib"
+ env["AS"] = basecmd + "as"
+ env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define
+
+ if env["CXX"] == "clang++":
+ env.Append(CPPDEFINES=["TYPED_METHOD_BIND"])
env["CC"] = "clang"
env["LINK"] = "clang++"
- if env['use_ubsan'] or env['use_asan'] or env['use_tsan']:
+ if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]:
env.extra_suffix += "s"
- if env['use_ubsan']:
- env.Append(CCFLAGS=['-fsanitize=undefined'])
- env.Append(LINKFLAGS=['-fsanitize=undefined'])
+ if env["use_ubsan"]:
+ env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(LINKFLAGS=["-fsanitize=undefined"])
- if env['use_asan']:
- env.Append(CCFLAGS=['-fsanitize=address'])
- env.Append(LINKFLAGS=['-fsanitize=address'])
+ if env["use_asan"]:
+ env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(LINKFLAGS=["-fsanitize=address"])
- if env['use_tsan']:
- env.Append(CCFLAGS=['-fsanitize=thread'])
- env.Append(LINKFLAGS=['-fsanitize=thread'])
+ if env["use_tsan"]:
+ env.Append(CCFLAGS=["-fsanitize=thread"])
+ env.Append(LINKFLAGS=["-fsanitize=thread"])
## Dependencies
- if env['builtin_libtheora']:
+ if env["builtin_libtheora"]:
env["x86_libtheora_opt_gcc"] = True
## Flags
- env.Prepend(CPPPATH=['#platform/osx'])
- env.Append(CPPDEFINES=['OSX_ENABLED', 'UNIX_ENABLED', 'APPLE_STYLE_KEYS', 'COREAUDIO_ENABLED', 'COREMIDI_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-framework', 'IOKit', '-framework', 'ForceFeedback', '-framework', 'CoreVideo', '-framework', 'AVFoundation', '-framework', 'CoreMedia'])
- env.Append(LIBS=['pthread', 'z'])
-
- env.Append(CPPDEFINES=['VULKAN_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'Metal', '-framework', 'QuartzCore', '-framework', 'IOSurface'])
- if (env['use_static_mvk']):
- env.Append(LINKFLAGS=['-framework', 'MoltenVK'])
- env['builtin_vulkan'] = False
- elif not env['builtin_vulkan']:
- env.Append(LIBS=['vulkan'])
-
- #env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED'])
-
- env.Append(CCFLAGS=['-mmacosx-version-min=10.12'])
- env.Append(LINKFLAGS=['-mmacosx-version-min=10.12'])
+ env.Prepend(CPPPATH=["#platform/osx"])
+ env.Append(CPPDEFINES=["OSX_ENABLED", "UNIX_ENABLED", "APPLE_STYLE_KEYS", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"])
+ env.Append(
+ LINKFLAGS=[
+ "-framework",
+ "Cocoa",
+ "-framework",
+ "Carbon",
+ "-framework",
+ "AudioUnit",
+ "-framework",
+ "CoreAudio",
+ "-framework",
+ "CoreMIDI",
+ "-framework",
+ "IOKit",
+ "-framework",
+ "ForceFeedback",
+ "-framework",
+ "CoreVideo",
+ "-framework",
+ "AVFoundation",
+ "-framework",
+ "CoreMedia",
+ ]
+ )
+ env.Append(LIBS=["pthread", "z"])
+
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"])
+ if env["use_static_mvk"]:
+ env.Append(LINKFLAGS=["-framework", "MoltenVK"])
+ env["builtin_vulkan"] = False
+ elif not env["builtin_vulkan"]:
+ env.Append(LIBS=["vulkan"])
+
+ # env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED'])
+
+ env.Append(CCFLAGS=["-mmacosx-version-min=10.12"])
+ env.Append(LINKFLAGS=["-mmacosx-version-min=10.12"])
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
new file mode 100644
index 0000000000..86ceb51763
--- /dev/null
+++ b/platform/osx/display_server_osx.h
@@ -0,0 +1,308 @@
+/*************************************************************************/
+/* display_server_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 DISPLAY_SERVER_OSX_H
+#define DISPLAY_SERVER_OSX_H
+
+#define BitMap _QDBitMap // Suppress deprecated QuickDraw definition.
+
+#include "core/input/input_filter.h"
+#include "servers/display_server.h"
+
+#if defined(OPENGL_ENABLED)
+#include "context_gl_osx.h"
+//TODO - reimplement OpenGLES
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_device_vulkan.h"
+#include "platform/osx/vulkan_context_osx.h"
+#endif
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSCursor.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreVideo/CoreVideo.h>
+
+#undef BitMap
+#undef CursorShape
+
+class DisplayServerOSX : public DisplayServer {
+ GDCLASS(DisplayServerOSX, DisplayServer)
+
+ _THREAD_SAFE_CLASS_
+
+public:
+#if defined(OPENGL_ENABLED)
+ ContextGL_OSX *context_gles2;
+#endif
+#if defined(VULKAN_ENABLED)
+ VulkanContextOSX *context_vulkan;
+ RenderingDeviceVulkan *rendering_device_vulkan;
+#endif
+
+ const NSMenu *_get_menu_root(const String &p_menu_root) const;
+ NSMenu *_get_menu_root(const String &p_menu_root);
+
+ NSMenu *apple_menu = nullptr;
+ NSMenu *dock_menu = nullptr;
+ Map<String, NSMenu *> submenu;
+
+ struct KeyEvent {
+ WindowID window_id;
+ unsigned int osx_state;
+ bool pressed;
+ bool echo;
+ bool raw;
+ uint32_t keycode;
+ uint32_t physical_keycode;
+ uint32_t unicode;
+ };
+
+ Vector<KeyEvent> key_event_buffer;
+ int key_event_pos;
+
+ struct WindowData {
+ id window_delegate;
+ id window_object;
+ id window_view;
+
+#if defined(OPENGL_ENABLED)
+ ContextGL_OSX *context_gles2 = nullptr;
+#endif
+ Point2i mouse_pos;
+
+ Size2i min_size;
+ Size2i max_size;
+ Size2i size;
+
+ bool mouse_down_control = false;
+
+ bool im_active = false;
+ Size2i im_position;
+
+ Callable rect_changed_callback;
+ Callable event_callback;
+ Callable input_event_callback;
+ Callable input_text_callback;
+ Callable drop_files_callback;
+
+ ObjectID instance_id;
+
+ WindowID transient_parent = INVALID_WINDOW_ID;
+ Set<WindowID> transient_children;
+
+ bool layered_window = false;
+ bool fullscreen = false;
+ bool on_top = false;
+ bool borderless = false;
+ bool resize_disabled = false;
+ };
+
+ Point2i im_selection;
+ String im_text;
+
+ Map<WindowID, WindowData> windows;
+
+ WindowID window_id_counter = MAIN_WINDOW_ID;
+
+ WindowID _create_window(WindowMode p_mode, const Rect2i &p_rect);
+ void _update_window(WindowData p_wd);
+ void _send_window_event(const WindowData &wd, WindowEvent p_event);
+ static void _dispatch_input_events(const Ref<InputEvent> &p_event);
+ void _dispatch_input_event(const Ref<InputEvent> &p_event);
+ WindowID _find_window_id(id p_window);
+
+ void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window);
+
+ float _display_scale(id screen) const;
+ Point2i _get_screens_origin() const;
+ Point2i _get_native_screen_position(int p_screen) const;
+
+ void _push_input(const Ref<InputEvent> &p_event);
+ void _process_key_events();
+ void _release_pressed_events();
+
+ String rendering_driver;
+
+ id delegate;
+ id autoreleasePool;
+ CGEventSourceRef eventSource;
+
+ CursorShape cursor_shape;
+ NSCursor *cursors[CURSOR_MAX];
+ Map<CursorShape, Vector<Variant>> cursors_cache;
+
+ MouseMode mouse_mode;
+ Point2i last_mouse_pos;
+ uint32_t last_button_state;
+
+ bool window_focused;
+ bool drop_events;
+ bool in_dispatch_input_event = false;
+
+public:
+ virtual bool has_feature(Feature p_feature) const;
+ virtual String get_name() const;
+
+ virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant());
+ virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant());
+ virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu);
+ virtual void global_menu_add_separator(const String &p_menu_root);
+
+ virtual bool global_menu_is_item_checked(const String &p_menu_root, int p_idx) const;
+ virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const;
+ virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx);
+ virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx);
+ virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx);
+ virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx);
+
+ virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked);
+ virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable);
+ virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback);
+ virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag);
+ virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text);
+ virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu);
+
+ virtual int global_menu_get_item_count(const String &p_menu_root) const;
+
+ virtual void global_menu_remove_item(const String &p_menu_root, int p_idx);
+ virtual void global_menu_clear(const String &p_menu_root);
+
+ virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+ virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback);
+ virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback);
+
+ virtual void mouse_set_mode(MouseMode p_mode);
+ virtual MouseMode mouse_get_mode() const;
+
+ virtual void mouse_warp_to_position(const Point2i &p_to);
+ virtual Point2i mouse_get_position() const;
+ virtual Point2i mouse_get_absolute_position() const;
+ virtual int mouse_get_button_state() const;
+
+ virtual void clipboard_set(const String &p_text);
+ virtual String clipboard_get() const;
+
+ virtual int get_screen_count() const;
+ virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual Vector<int> get_window_list() const;
+
+ virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i & = Rect2i());
+ virtual void delete_sub_window(WindowID p_id);
+
+ virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_transient(WindowID p_window, WindowID p_parent);
+
+ virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
+ virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
+ virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual bool can_any_window_draw() const;
+
+ virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
+
+ virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID);
+ virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual Point2i ime_get_selection() const;
+ virtual String ime_get_text() const;
+
+ virtual void cursor_set_shape(CursorShape p_shape);
+ virtual CursorShape cursor_get_shape() const;
+ virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+
+ virtual bool get_swap_ok_cancel();
+
+ virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+ virtual void process_events();
+ virtual void force_process_and_drop_events();
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ virtual void set_native_icon(const String &p_filename);
+ virtual void set_icon(const Ref<Image> &p_icon);
+
+ virtual void console_set_visible(bool p_enabled);
+ virtual bool is_console_visible() const;
+
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static Vector<String> get_rendering_drivers_func();
+
+ static void register_osx_driver();
+
+ DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ ~DisplayServerOSX();
+};
+
+#endif // DISPLAY_SERVER_OSX_H
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
new file mode 100644
index 0000000000..074fc3be0d
--- /dev/null
+++ b/platform/osx/display_server_osx.mm
@@ -0,0 +1,3595 @@
+/*************************************************************************/
+/* display_server_osx.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "display_server_osx.h"
+
+#include "os_osx.h"
+
+#include "core/io/marshalls.h"
+#include "core/os/keyboard.h"
+#include "main/main.h"
+#include "scene/resources/texture.h"
+
+#include <Carbon/Carbon.h>
+#include <Cocoa/Cocoa.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/hid/IOHIDLib.h>
+
+#if defined(OPENGL_ENABLED)
+#include "drivers/gles2/rasterizer_gles2.h"
+//TODO - reimplement OpenGLES
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+
+#include <QuartzCore/CAMetalLayer.h>
+#endif
+
+#define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton()))
+
+static void _get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) {
+ r_state->set_shift((p_osx_state & NSEventModifierFlagShift));
+ r_state->set_control((p_osx_state & NSEventModifierFlagControl));
+ r_state->set_alt((p_osx_state & NSEventModifierFlagOption));
+ r_state->set_metakey((p_osx_state & NSEventModifierFlagCommand));
+}
+
+static Vector2i _get_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_locationInWindow, CGFloat p_backingScaleFactor) {
+ const NSRect contentRect = [p_wd.window_view frame];
+ const NSPoint p = p_locationInWindow;
+ p_wd.mouse_pos.x = p.x * p_backingScaleFactor;
+ p_wd.mouse_pos.y = (contentRect.size.height - p.y) * p_backingScaleFactor;
+ DS_OSX->last_mouse_pos = p_wd.mouse_pos;
+ InputFilter::get_singleton()->set_mouse_position(p_wd.mouse_pos);
+ return p_wd.mouse_pos;
+}
+
+static void _push_to_key_event_buffer(const DisplayServerOSX::KeyEvent &p_event) {
+ Vector<DisplayServerOSX::KeyEvent> &buffer = DS_OSX->key_event_buffer;
+ if (DS_OSX->key_event_pos >= buffer.size()) {
+ buffer.resize(1 + DS_OSX->key_event_pos);
+ }
+ buffer.write[DS_OSX->key_event_pos++] = p_event;
+}
+
+static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
+ if ([NSCursor respondsToSelector:selector]) {
+ id object = [NSCursor performSelector:selector];
+ if ([object isKindOfClass:[NSCursor class]]) {
+ return object;
+ }
+ }
+ if (fallback) {
+ // Fallback should be a reasonable default, no need to check.
+ return [NSCursor performSelector:fallback];
+ }
+ return [NSCursor arrowCursor];
+}
+
+/*************************************************************************/
+/* GodotApplication */
+/*************************************************************************/
+
+@interface GodotApplication : NSApplication
+@end
+
+@implementation GodotApplication
+
+- (void)sendEvent:(NSEvent *)event {
+ // special case handling of command-period, which is traditionally a special
+ // shortcut in macOS and doesn't arrive at our regular keyDown handler.
+ if ([event type] == NSEventTypeKeyDown) {
+ if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) {
+ Ref<InputEventKey> k;
+ k.instance();
+
+ _get_key_modifier_state([event modifierFlags], k);
+ k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID);
+ k->set_pressed(true);
+ k->set_keycode(KEY_PERIOD);
+ k->set_physical_keycode(KEY_PERIOD);
+ k->set_echo([event isARepeat]);
+
+ InputFilter::get_singleton()->accumulate_input_event(k);
+ }
+ }
+
+ // From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
+ // This works around an AppKit bug, where key up events while holding
+ // down the command key don't get sent to the key window.
+ if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand))
+ [[self keyWindow] sendEvent:event];
+ else
+ [super sendEvent:event];
+}
+
+@end
+
+/*************************************************************************/
+/* GlobalMenuItem */
+/*************************************************************************/
+
+@interface GlobalMenuItem : NSObject {
+@public
+ Callable callback;
+ Variant meta;
+ bool checkable;
+}
+@end
+
+@implementation GlobalMenuItem
+@end
+
+/*************************************************************************/
+/* GodotApplicationDelegate */
+/*************************************************************************/
+
+@interface GodotApplicationDelegate : NSObject
+- (void)forceUnbundledWindowActivationHackStep1;
+- (void)forceUnbundledWindowActivationHackStep2;
+- (void)forceUnbundledWindowActivationHackStep3;
+@end
+
+@implementation GodotApplicationDelegate
+
+- (void)forceUnbundledWindowActivationHackStep1 {
+ // Step1: Switch focus to macOS Dock.
+ // Required to perform step 2, TransformProcessType will fail if app is already the in focus.
+ for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
+ [app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
+ break;
+ }
+ [self performSelector:@selector(forceUnbundledWindowActivationHackStep2) withObject:nil afterDelay:0.02];
+}
+
+- (void)forceUnbundledWindowActivationHackStep2 {
+ // Step 2: Register app as foreground process.
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+ (void)TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ [self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02];
+}
+
+- (void)forceUnbundledWindowActivationHackStep3 {
+ // Step 3: Switch focus back to app window.
+ [[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notice {
+ NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
+ if (nsappname == nil) {
+ // If executable is not a bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
+ [self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
+ }
+}
+
+- (void)globalMenuCallback:(id)sender {
+ if (![sender representedObject])
+ return;
+
+ GlobalMenuItem *value = [sender representedObject];
+
+ if (value) {
+ if (value->checkable) {
+ if ([sender state] == NSControlStateValueOff) {
+ [sender setState:NSControlStateValueOn];
+ } else {
+ [sender setState:NSControlStateValueOff];
+ }
+ }
+
+ if (value->callback != Callable()) {
+ Variant tag = value->meta;
+ Variant *tagp = &tag;
+ Variant ret;
+ Callable::CallError ce;
+ value->callback.call((const Variant **)&tagp, 1, ret, ce);
+ }
+ }
+}
+
+- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
+ return DS_OSX->dock_menu;
+}
+
+- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
+ // Note: may be called called before main loop init!
+ char *utfs = strdup([filename UTF8String]);
+ ((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename.parse_utf8(utfs);
+ free(utfs);
+
+#ifdef TOOLS_ENABLED
+ // Open new instance
+ if (OS_OSX::get_singleton()->get_main_loop()) {
+ List<String> args;
+ args.push_back(((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename);
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+ }
+#endif
+ return YES;
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
+ DS_OSX->_send_window_event(DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ return NSTerminateCancel;
+}
+
+- (void)showAbout:(id)sender {
+ if (OS_OSX::get_singleton()->get_main_loop())
+ OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT);
+}
+
+@end
+
+/*************************************************************************/
+/* GodotWindowDelegate */
+/*************************************************************************/
+
+@interface GodotWindowDelegate : NSObject {
+ DisplayServerOSX::WindowID window_id;
+}
+
+- (void)windowWillClose:(NSNotification *)notification;
+- (void)setWindowID:(DisplayServerOSX::WindowID)wid;
+
+@end
+
+@implementation GodotWindowDelegate
+
+- (void)setWindowID:(DisplayServerOSX::WindowID)wid {
+ window_id = wid;
+}
+
+- (BOOL)windowShouldClose:(id)sender {
+ ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), YES);
+ DS_OSX->_send_window_event(DS_OSX->windows[window_id], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+ return NO;
+}
+
+- (void)windowWillClose:(NSNotification *)notification {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ while (wd.transient_children.size()) {
+ DS_OSX->window_set_transient(wd.transient_children.front()->get(), DisplayServerOSX::INVALID_WINDOW_ID);
+ }
+
+ DS_OSX->windows.erase(window_id);
+
+ if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) {
+ DisplayServerOSX::WindowData &pwd = DS_OSX->windows[wd.transient_parent];
+ [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to parent.
+ DS_OSX->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID);
+ } else if ((window_id != DisplayServerOSX::MAIN_WINDOW_ID) && (DS_OSX->windows.size() == 1)) {
+ DisplayServerOSX::WindowData &pwd = DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID];
+ [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left.
+ }
+
+#ifdef VULKAN_ENABLED
+ if (DS_OSX->rendering_driver == "vulkan") {
+ DS_OSX->context_vulkan->window_destroy(window_id);
+ }
+#endif
+}
+
+- (void)windowDidEnterFullScreen:(NSNotification *)notification {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ wd.fullscreen = true;
+
+ [wd.window_object setContentMinSize:NSMakeSize(0, 0)];
+ [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+}
+
+- (void)windowDidExitFullScreen:(NSNotification *)notification {
+ if (!DS_OSX || !DS_OSX->windows.has(window_id))
+ return;
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ wd.fullscreen = false;
+
+ if (wd.min_size != Size2i()) {
+ Size2i size = wd.min_size / DS_OSX->_display_scale([wd.window_object screen]);
+ [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
+ }
+ if (wd.max_size != Size2i()) {
+ Size2i size = wd.max_size / DS_OSX->_display_scale([wd.window_object screen]);
+ [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
+ }
+
+ if (wd.resize_disabled)
+ [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
+}
+
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
+ if (!DisplayServerOSX::get_singleton())
+ return;
+
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ CGFloat newBackingScaleFactor = [wd.window_object backingScaleFactor];
+ CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
+
+#if defined(OPENGL_ENABLED)
+ if (DS_OSX->rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ if (OS_OSX::get_singleton()->is_hidpi_allowed()) {
+ [wd.window_view setWantsBestResolutionOpenGLSurface:YES];
+ } else {
+ [wd.window_view setWantsBestResolutionOpenGLSurface:NO];
+ }
+ }
+#endif
+
+ if (newBackingScaleFactor != oldBackingScaleFactor) {
+ //Set new display scale and window size
+ float newDisplayScale = OS_OSX::get_singleton()->is_hidpi_allowed() ? newBackingScaleFactor : 1.0;
+
+ const NSRect contentRect = [wd.window_view frame];
+
+ wd.size.width = contentRect.size.width * newDisplayScale;
+ wd.size.height = contentRect.size.height * newDisplayScale;
+
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_DPI_CHANGE);
+
+#if defined(VULKAN_ENABLED)
+ if (DS_OSX->rendering_driver == "vulkan") {
+ CALayer *layer = [wd.window_view layer];
+ layer.contentsScale = DS_OSX->_display_scale([wd.window_object screen]);
+ }
+#endif
+ //Force window resize event
+ [self windowDidResize:notification];
+ }
+}
+
+- (void)windowDidResize:(NSNotification *)notification {
+ if (!DS_OSX || !DS_OSX->windows.has(window_id))
+ return;
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+#if defined(OPENGL_ENABLED)
+ if (DS_OSX->rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ wd.context_gles2->update();
+ }
+#endif
+ const NSRect contentRect = [wd.window_view frame];
+
+ float displayScale = DS_OSX->_display_scale([wd.window_object screen]);
+ wd.size.width = contentRect.size.width * displayScale;
+ wd.size.height = contentRect.size.height * displayScale;
+
+#if defined(VULKAN_ENABLED)
+ if (DS_OSX->rendering_driver == "vulkan") {
+ CALayer *layer = [wd.window_view layer];
+ layer.contentsScale = displayScale;
+ DS_OSX->context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
+ }
+#endif
+
+ if (!wd.rect_changed_callback.is_null()) {
+ Variant size = Rect2i(DS_OSX->window_get_position(window_id), DS_OSX->window_get_size(window_id));
+ Variant *sizep = &size;
+ Variant ret;
+ Callable::CallError ce;
+ wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
+ }
+
+ if (OS_OSX::get_singleton()->get_main_loop()) {
+ Main::force_redraw();
+ //Event retrieval blocks until resize is over. Call Main::iteration() directly.
+ if (!Main::is_iterating()) { //avoid cyclic loop
+ Main::iteration();
+ }
+ }
+}
+
+- (void)windowDidMove:(NSNotification *)notification {
+ DS_OSX->_release_pressed_events();
+}
+
+- (void)windowDidBecomeKey:(NSNotification *)notification {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [wd.window_view backingScaleFactor] : 1.0;
+ _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream], backingScaleFactor);
+ InputFilter::get_singleton()->set_mouse_position(wd.mouse_pos);
+
+ DS_OSX->window_focused = true;
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN);
+}
+
+- (void)windowDidResignKey:(NSNotification *)notification {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ DS_OSX->window_focused = false;
+
+ DS_OSX->_release_pressed_events();
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT);
+}
+
+- (void)windowDidMiniaturize:(NSNotification *)notification {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ DS_OSX->window_focused = false;
+
+ DS_OSX->_release_pressed_events();
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT);
+}
+
+- (void)windowDidDeminiaturize:(NSNotification *)notification {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ DS_OSX->window_focused = true;
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN);
+}
+
+@end
+
+/*************************************************************************/
+/* GodotContentView */
+/*************************************************************************/
+
+@interface GodotContentView : NSView <NSTextInputClient> {
+ DisplayServerOSX::WindowID window_id;
+ NSTrackingArea *trackingArea;
+ NSMutableAttributedString *markedText;
+ bool imeInputEventInProgress;
+}
+
+- (void)cancelComposition;
+- (CALayer *)makeBackingLayer;
+- (BOOL)wantsUpdateLayer;
+- (void)updateLayer;
+- (void)setWindowID:(DisplayServerOSX::WindowID)wid;
+
+@end
+
+@implementation GodotContentView
+
+- (void)setWindowID:(DisplayServerOSX::WindowID)wid {
+ window_id = wid;
+}
+
++ (void)initialize {
+ if (self == [GodotContentView class]) {
+ // nothing left to do here at the moment..
+ }
+}
+
+- (CALayer *)makeBackingLayer {
+#if defined(VULKAN_ENABLED)
+ if (DS_OSX->rendering_driver == "vulkan") {
+ CALayer *layer = [[CAMetalLayer class] layer];
+ return layer;
+ }
+#endif
+ return [super makeBackingLayer];
+}
+
+- (void)updateLayer {
+#if defined(VULKAN_ENABLED)
+ if (DS_OSX->rendering_driver == "vulkan") {
+ [super updateLayer];
+ }
+#endif
+#if defined(OPENGL_ENABLED)
+ if (DS_OSX->rendering_driver == "opengl_es") {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ wd.context_gles2->update();
+ //TODO - reimplement OpenGLES
+ }
+#endif
+}
+
+- (BOOL)wantsUpdateLayer {
+ return YES;
+}
+
+- (id)init {
+ self = [super init];
+ trackingArea = nil;
+ imeInputEventInProgress = false;
+ [self updateTrackingAreas];
+ [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
+ markedText = [[NSMutableAttributedString alloc] init];
+ return self;
+}
+
+- (void)dealloc {
+ [trackingArea release];
+ [markedText release];
+ [super dealloc];
+}
+
+static const NSRange kEmptyRange = { NSNotFound, 0 };
+
+- (BOOL)hasMarkedText {
+ return (markedText.length > 0);
+}
+
+- (NSRange)markedRange {
+ return NSMakeRange(0, markedText.length);
+}
+
+- (NSRange)selectedRange {
+ return kEmptyRange;
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
+ if ([aString isKindOfClass:[NSAttributedString class]]) {
+ [markedText initWithAttributedString:aString];
+ } else {
+ [markedText initWithString:aString];
+ }
+ if (markedText.length == 0) {
+ [self unmarkText];
+ return;
+ }
+
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (wd.im_active) {
+ imeInputEventInProgress = true;
+ DS_OSX->im_text.parse_utf8([[markedText mutableString] UTF8String]);
+ DS_OSX->im_selection = Point2i(selectedRange.location, selectedRange.length);
+
+ OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
+}
+
+- (void)doCommandBySelector:(SEL)aSelector {
+ if ([self respondsToSelector:aSelector])
+ [self performSelector:aSelector];
+}
+
+- (void)unmarkText {
+ imeInputEventInProgress = false;
+ [[markedText mutableString] setString:@""];
+
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (wd.im_active) {
+ DS_OSX->im_text = String();
+ DS_OSX->im_selection = Point2i();
+
+ OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
+}
+
+- (NSArray *)validAttributesForMarkedText {
+ return [NSArray array];
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
+ return nil;
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
+ return 0;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
+ ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), NSMakeRect(0, 0, 0, 0));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ const NSRect contentRect = [wd.window_view frame];
+ float displayScale = DS_OSX->_display_scale([wd.window_object screen]);
+ NSRect pointInWindowRect = NSMakeRect(wd.im_position.x / displayScale, contentRect.size.height - (wd.im_position.y / displayScale) - 1, 0, 0);
+ NSPoint pointOnScreen = [wd.window_object convertRectToScreen:pointInWindowRect].origin;
+
+ return NSMakeRect(pointOnScreen.x, pointOnScreen.y, 0, 0);
+}
+
+- (void)cancelComposition {
+ [self unmarkText];
+ NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext];
+ [currentInputContext discardMarkedText];
+}
+
+- (void)insertText:(id)aString {
+ [self insertText:aString replacementRange:NSMakeRange(0, 0)];
+}
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
+ NSEvent *event = [NSApp currentEvent];
+
+ NSString *characters;
+ if ([aString isKindOfClass:[NSAttributedString class]]) {
+ characters = [aString string];
+ } else {
+ characters = (NSString *)aString;
+ }
+
+ NSUInteger i, length = [characters length];
+
+ NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
+ NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+ if ([characters rangeOfCharacterFromSet:ctrlChars].length && [characters rangeOfCharacterFromSet:wsnlChars].length == 0) {
+ NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext];
+ [currentInputContext discardMarkedText];
+ [self cancelComposition];
+ return;
+ }
+
+ for (i = 0; i < length; i++) {
+ const unichar codepoint = [characters characterAtIndex:i];
+ if ((codepoint & 0xFF00) == 0xF700)
+ continue;
+
+ DisplayServerOSX::KeyEvent ke;
+
+ ke.window_id = window_id;
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = false;
+ ke.raw = false; // IME input event
+ ke.keycode = 0;
+ ke.physical_keycode = 0;
+ ke.unicode = codepoint;
+
+ _push_to_key_event_buffer(ke);
+ }
+ [self cancelComposition];
+}
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
+ return NSDragOperationCopy;
+}
+
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
+ return NSDragOperationCopy;
+}
+
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
+ ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), NO);
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ NSPasteboard *pboard = [sender draggingPasteboard];
+ NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
+
+ Vector<String> files;
+ for (NSUInteger i = 0; i < filenames.count; i++) {
+ NSString *ns = [filenames objectAtIndex:i];
+ char *utfs = strdup([ns UTF8String]);
+ String ret;
+ ret.parse_utf8(utfs);
+ free(utfs);
+ files.push_back(ret);
+ }
+
+ if (!wd.drop_files_callback.is_null()) {
+ Variant v = files;
+ Variant *vp = &v;
+ Variant ret;
+ Callable::CallError ce;
+ wd.drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
+ }
+
+ return NO;
+}
+
+- (BOOL)isOpaque {
+ return YES;
+}
+
+- (BOOL)canBecomeKeyView {
+ return YES;
+}
+
+- (BOOL)acceptsFirstResponder {
+ return YES;
+}
+
+- (void)cursorUpdate:(NSEvent *)event {
+ DisplayServer::CursorShape p_shape = DS_OSX->cursor_shape;
+ DS_OSX->cursor_shape = DisplayServer::CURSOR_MAX;
+ DS_OSX->cursor_set_shape(p_shape);
+}
+
+static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, int index, int mask, bool pressed) {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (pressed) {
+ DS_OSX->last_button_state |= mask;
+ } else {
+ DS_OSX->last_button_state &= ~mask;
+ }
+
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_window_id(window_id);
+ const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0;
+ const Vector2 pos = _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor);
+ _get_key_modifier_state([event modifierFlags], mb);
+ mb->set_button_index(index);
+ mb->set_pressed(pressed);
+ mb->set_position(pos);
+ mb->set_global_position(pos);
+ mb->set_button_mask(DS_OSX->last_button_state);
+ if (index == BUTTON_LEFT && pressed) {
+ mb->set_doubleclick([event clickCount] == 2);
+ }
+
+ InputFilter::get_singleton()->accumulate_input_event(mb);
+}
+
+- (void)mouseDown:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (([event modifierFlags] & NSEventModifierFlagControl)) {
+ wd.mouse_down_control = true;
+ _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+ } else {
+ wd.mouse_down_control = false;
+ _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, true);
+ }
+}
+
+- (void)mouseDragged:(NSEvent *)event {
+ [self mouseMoved:event];
+}
+
+- (void)mouseUp:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (wd.mouse_down_control) {
+ _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+ } else {
+ _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, false);
+ }
+}
+
+- (void)mouseMoved:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+
+ mm->set_window_id(window_id);
+ mm->set_button_mask(DS_OSX->last_button_state);
+ const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0;
+ const Vector2i pos = _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor);
+ mm->set_position(pos);
+ mm->set_pressure([event pressure]);
+ if ([event subtype] == NSEventSubtypeTabletPoint) {
+ const NSPoint p = [event tilt];
+ mm->set_tilt(Vector2(p.x, p.y));
+ }
+ mm->set_global_position(pos);
+ mm->set_speed(InputFilter::get_singleton()->get_last_mouse_speed());
+ Vector2i relativeMotion = Vector2i();
+ relativeMotion.x = [event deltaX] * backingScaleFactor;
+ relativeMotion.y = [event deltaY] * backingScaleFactor;
+ mm->set_relative(relativeMotion);
+ _get_key_modifier_state([event modifierFlags], mm);
+
+ InputFilter::get_singleton()->set_mouse_position(wd.mouse_pos);
+ InputFilter::get_singleton()->accumulate_input_event(mm);
+}
+
+- (void)rightMouseDown:(NSEvent *)event {
+ _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+}
+
+- (void)rightMouseDragged:(NSEvent *)event {
+ [self mouseMoved:event];
+}
+
+- (void)rightMouseUp:(NSEvent *)event {
+ _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+}
+
+- (void)otherMouseDown:(NSEvent *)event {
+ if ((int)[event buttonNumber] == 2) {
+ _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true);
+ } else if ((int)[event buttonNumber] == 3) {
+ _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, true);
+ } else if ((int)[event buttonNumber] == 4) {
+ _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, true);
+ } else {
+ return;
+ }
+}
+
+- (void)otherMouseDragged:(NSEvent *)event {
+ [self mouseMoved:event];
+}
+
+- (void)otherMouseUp:(NSEvent *)event {
+ if ((int)[event buttonNumber] == 2) {
+ _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false);
+ } else if ((int)[event buttonNumber] == 3) {
+ _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, false);
+ } else if ((int)[event buttonNumber] == 4) {
+ _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, false);
+ } else {
+ return;
+ }
+}
+
+- (void)mouseExited:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (DS_OSX->mouse_mode != DisplayServer::MOUSE_MODE_CAPTURED)
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_EXIT);
+}
+
+- (void)mouseEntered:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ if (DS_OSX->mouse_mode != DisplayServer::MOUSE_MODE_CAPTURED)
+ DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_ENTER);
+
+ DisplayServer::CursorShape p_shape = DS_OSX->cursor_shape;
+ DS_OSX->cursor_shape = DisplayServer::CURSOR_MAX;
+ DS_OSX->cursor_set_shape(p_shape);
+}
+
+- (void)magnifyWithEvent:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ Ref<InputEventMagnifyGesture> ev;
+ ev.instance();
+ ev->set_window_id(window_id);
+ _get_key_modifier_state([event modifierFlags], ev);
+ const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0;
+ ev->set_position(_get_mouse_pos(wd, [event locationInWindow], backingScaleFactor));
+ ev->set_factor([event magnification] + 1.0);
+
+ InputFilter::get_singleton()->accumulate_input_event(ev);
+}
+
+- (void)viewDidChangeBackingProperties {
+ // nothing left to do here
+}
+
+- (void)updateTrackingAreas {
+ if (trackingArea != nil) {
+ [self removeTrackingArea:trackingArea];
+ [trackingArea release];
+ }
+
+ NSTrackingAreaOptions options =
+ NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow |
+ NSTrackingCursorUpdate |
+ NSTrackingInVisibleRect;
+
+ trackingArea = [[NSTrackingArea alloc]
+ initWithRect:[self bounds]
+ options:options
+ owner:self
+ userInfo:nil];
+
+ [self addTrackingArea:trackingArea];
+ [super updateTrackingAreas];
+}
+
+static bool isNumpadKey(unsigned int key) {
+
+ static const unsigned int table[] = {
+ 0x41, /* kVK_ANSI_KeypadDecimal */
+ 0x43, /* kVK_ANSI_KeypadMultiply */
+ 0x45, /* kVK_ANSI_KeypadPlus */
+ 0x47, /* kVK_ANSI_KeypadClear */
+ 0x4b, /* kVK_ANSI_KeypadDivide */
+ 0x4c, /* kVK_ANSI_KeypadEnter */
+ 0x4e, /* kVK_ANSI_KeypadMinus */
+ 0x51, /* kVK_ANSI_KeypadEquals */
+ 0x52, /* kVK_ANSI_Keypad0 */
+ 0x53, /* kVK_ANSI_Keypad1 */
+ 0x54, /* kVK_ANSI_Keypad2 */
+ 0x55, /* kVK_ANSI_Keypad3 */
+ 0x56, /* kVK_ANSI_Keypad4 */
+ 0x57, /* kVK_ANSI_Keypad5 */
+ 0x58, /* kVK_ANSI_Keypad6 */
+ 0x59, /* kVK_ANSI_Keypad7 */
+ 0x5b, /* kVK_ANSI_Keypad8 */
+ 0x5c, /* kVK_ANSI_Keypad9 */
+ 0x5f, /* kVK_JIS_KeypadComma */
+ 0x00
+ };
+ for (int i = 0; table[i] != 0; i++) {
+ if (key == table[i])
+ return true;
+ }
+ return false;
+}
+
+// Translates a OS X keycode to a Godot keycode
+//
+static int translateKey(unsigned int key) {
+
+ // Keyboard symbol translation table
+ static const unsigned int table[128] = {
+ /* 00 */ KEY_A,
+ /* 01 */ KEY_S,
+ /* 02 */ KEY_D,
+ /* 03 */ KEY_F,
+ /* 04 */ KEY_H,
+ /* 05 */ KEY_G,
+ /* 06 */ KEY_Z,
+ /* 07 */ KEY_X,
+ /* 08 */ KEY_C,
+ /* 09 */ KEY_V,
+ /* 0a */ KEY_SECTION, /* ISO Section */
+ /* 0b */ KEY_B,
+ /* 0c */ KEY_Q,
+ /* 0d */ KEY_W,
+ /* 0e */ KEY_E,
+ /* 0f */ KEY_R,
+ /* 10 */ KEY_Y,
+ /* 11 */ KEY_T,
+ /* 12 */ KEY_1,
+ /* 13 */ KEY_2,
+ /* 14 */ KEY_3,
+ /* 15 */ KEY_4,
+ /* 16 */ KEY_6,
+ /* 17 */ KEY_5,
+ /* 18 */ KEY_EQUAL,
+ /* 19 */ KEY_9,
+ /* 1a */ KEY_7,
+ /* 1b */ KEY_MINUS,
+ /* 1c */ KEY_8,
+ /* 1d */ KEY_0,
+ /* 1e */ KEY_BRACERIGHT,
+ /* 1f */ KEY_O,
+ /* 20 */ KEY_U,
+ /* 21 */ KEY_BRACELEFT,
+ /* 22 */ KEY_I,
+ /* 23 */ KEY_P,
+ /* 24 */ KEY_ENTER,
+ /* 25 */ KEY_L,
+ /* 26 */ KEY_J,
+ /* 27 */ KEY_APOSTROPHE,
+ /* 28 */ KEY_K,
+ /* 29 */ KEY_SEMICOLON,
+ /* 2a */ KEY_BACKSLASH,
+ /* 2b */ KEY_COMMA,
+ /* 2c */ KEY_SLASH,
+ /* 2d */ KEY_N,
+ /* 2e */ KEY_M,
+ /* 2f */ KEY_PERIOD,
+ /* 30 */ KEY_TAB,
+ /* 31 */ KEY_SPACE,
+ /* 32 */ KEY_QUOTELEFT,
+ /* 33 */ KEY_BACKSPACE,
+ /* 34 */ KEY_UNKNOWN,
+ /* 35 */ KEY_ESCAPE,
+ /* 36 */ KEY_META,
+ /* 37 */ KEY_META,
+ /* 38 */ KEY_SHIFT,
+ /* 39 */ KEY_CAPSLOCK,
+ /* 3a */ KEY_ALT,
+ /* 3b */ KEY_CONTROL,
+ /* 3c */ KEY_SHIFT,
+ /* 3d */ KEY_ALT,
+ /* 3e */ KEY_CONTROL,
+ /* 3f */ KEY_UNKNOWN, /* Function */
+ /* 40 */ KEY_UNKNOWN, /* F17 */
+ /* 41 */ KEY_KP_PERIOD,
+ /* 42 */ KEY_UNKNOWN,
+ /* 43 */ KEY_KP_MULTIPLY,
+ /* 44 */ KEY_UNKNOWN,
+ /* 45 */ KEY_KP_ADD,
+ /* 46 */ KEY_UNKNOWN,
+ /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
+ /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
+ /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
+ /* 4a */ KEY_VOLUMEMUTE, /* Mute */
+ /* 4b */ KEY_KP_DIVIDE,
+ /* 4c */ KEY_KP_ENTER,
+ /* 4d */ KEY_UNKNOWN,
+ /* 4e */ KEY_KP_SUBTRACT,
+ /* 4f */ KEY_UNKNOWN, /* F18 */
+ /* 50 */ KEY_UNKNOWN, /* F19 */
+ /* 51 */ KEY_EQUAL, /* KeypadEqual */
+ /* 52 */ KEY_KP_0,
+ /* 53 */ KEY_KP_1,
+ /* 54 */ KEY_KP_2,
+ /* 55 */ KEY_KP_3,
+ /* 56 */ KEY_KP_4,
+ /* 57 */ KEY_KP_5,
+ /* 58 */ KEY_KP_6,
+ /* 59 */ KEY_KP_7,
+ /* 5a */ KEY_UNKNOWN, /* F20 */
+ /* 5b */ KEY_KP_8,
+ /* 5c */ KEY_KP_9,
+ /* 5d */ KEY_YEN, /* JIS Yen */
+ /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
+ /* 5f */ KEY_COMMA, /* JIS KeypadComma */
+ /* 60 */ KEY_F5,
+ /* 61 */ KEY_F6,
+ /* 62 */ KEY_F7,
+ /* 63 */ KEY_F3,
+ /* 64 */ KEY_F8,
+ /* 65 */ KEY_F9,
+ /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
+ /* 67 */ KEY_F11,
+ /* 68 */ KEY_UNKNOWN, /* JIS Kana */
+ /* 69 */ KEY_F13,
+ /* 6a */ KEY_F16,
+ /* 6b */ KEY_F14,
+ /* 6c */ KEY_UNKNOWN,
+ /* 6d */ KEY_F10,
+ /* 6e */ KEY_MENU,
+ /* 6f */ KEY_F12,
+ /* 70 */ KEY_UNKNOWN,
+ /* 71 */ KEY_F15,
+ /* 72 */ KEY_INSERT, /* Really Help... */
+ /* 73 */ KEY_HOME,
+ /* 74 */ KEY_PAGEUP,
+ /* 75 */ KEY_DELETE,
+ /* 76 */ KEY_F4,
+ /* 77 */ KEY_END,
+ /* 78 */ KEY_F2,
+ /* 79 */ KEY_PAGEDOWN,
+ /* 7a */ KEY_F1,
+ /* 7b */ KEY_LEFT,
+ /* 7c */ KEY_RIGHT,
+ /* 7d */ KEY_DOWN,
+ /* 7e */ KEY_UP,
+ /* 7f */ KEY_UNKNOWN,
+ };
+
+ if (key >= 128)
+ return KEY_UNKNOWN;
+
+ return table[key];
+}
+
+struct _KeyCodeMap {
+ UniChar kchar;
+ int kcode;
+};
+
+static const _KeyCodeMap _keycodes[55] = {
+ { '`', KEY_QUOTELEFT },
+ { '~', KEY_ASCIITILDE },
+ { '0', KEY_0 },
+ { '1', KEY_1 },
+ { '2', KEY_2 },
+ { '3', KEY_3 },
+ { '4', KEY_4 },
+ { '5', KEY_5 },
+ { '6', KEY_6 },
+ { '7', KEY_7 },
+ { '8', KEY_8 },
+ { '9', KEY_9 },
+ { '-', KEY_MINUS },
+ { '_', KEY_UNDERSCORE },
+ { '=', KEY_EQUAL },
+ { '+', KEY_PLUS },
+ { 'q', KEY_Q },
+ { 'w', KEY_W },
+ { 'e', KEY_E },
+ { 'r', KEY_R },
+ { 't', KEY_T },
+ { 'y', KEY_Y },
+ { 'u', KEY_U },
+ { 'i', KEY_I },
+ { 'o', KEY_O },
+ { 'p', KEY_P },
+ { '[', KEY_BRACELEFT },
+ { ']', KEY_BRACERIGHT },
+ { '{', KEY_BRACELEFT },
+ { '}', KEY_BRACERIGHT },
+ { 'a', KEY_A },
+ { 's', KEY_S },
+ { 'd', KEY_D },
+ { 'f', KEY_F },
+ { 'g', KEY_G },
+ { 'h', KEY_H },
+ { 'j', KEY_J },
+ { 'k', KEY_K },
+ { 'l', KEY_L },
+ { ';', KEY_SEMICOLON },
+ { ':', KEY_COLON },
+ { '\'', KEY_APOSTROPHE },
+ { '\"', KEY_QUOTEDBL },
+ { '\\', KEY_BACKSLASH },
+ { '#', KEY_NUMBERSIGN },
+ { 'z', KEY_Z },
+ { 'x', KEY_X },
+ { 'c', KEY_C },
+ { 'v', KEY_V },
+ { 'b', KEY_B },
+ { 'n', KEY_N },
+ { 'm', KEY_M },
+ { ',', KEY_COMMA },
+ { '.', KEY_PERIOD },
+ { '/', KEY_SLASH }
+};
+
+static int remapKey(unsigned int key, unsigned int state) {
+ if (isNumpadKey(key))
+ return translateKey(key);
+
+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+ if (!currentKeyboard)
+ return translateKey(key);
+
+ CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
+ if (!layoutData)
+ return translateKey(key);
+
+ const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+
+ UInt32 keysDown = 0;
+ UniChar chars[4];
+ UniCharCount realLength;
+
+ OSStatus err = UCKeyTranslate(keyboardLayout,
+ key,
+ kUCKeyActionDisplay,
+ (state >> 8) & 0xFF,
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &keysDown,
+ sizeof(chars) / sizeof(chars[0]),
+ &realLength,
+ chars);
+
+ if (err != noErr) {
+ return translateKey(key);
+ }
+
+ for (unsigned int i = 0; i < 55; i++) {
+ if (_keycodes[i].kchar == chars[0]) {
+ return _keycodes[i].kcode;
+ }
+ }
+ return translateKey(key);
+}
+
+- (void)keyDown:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ // Ignore all input if IME input is in progress
+ if (!imeInputEventInProgress) {
+ NSString *characters = [event characters];
+ NSUInteger length = [characters length];
+
+ if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
+ // Fallback unicode character handler used if IME is not active
+ for (NSUInteger i = 0; i < length; i++) {
+ DisplayServerOSX::KeyEvent ke;
+
+ ke.window_id = window_id;
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.keycode = remapKey([event keyCode], [event modifierFlags]);
+ ke.physical_keycode = translateKey([event keyCode]);
+ ke.raw = true;
+ ke.unicode = [characters characterAtIndex:i];
+
+ _push_to_key_event_buffer(ke);
+ }
+ } else {
+ DisplayServerOSX::KeyEvent ke;
+
+ ke.window_id = window_id;
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.keycode = remapKey([event keyCode], [event modifierFlags]);
+ ke.physical_keycode = translateKey([event keyCode]);
+ ke.raw = false;
+ ke.unicode = 0;
+
+ _push_to_key_event_buffer(ke);
+ }
+ }
+
+ // Pass events to IME handler
+ if (wd.im_active)
+ [self interpretKeyEvents:[NSArray arrayWithObject:event]];
+}
+
+- (void)flagsChanged:(NSEvent *)event {
+ // Ignore all input if IME input is in progress
+ if (!imeInputEventInProgress) {
+ DisplayServerOSX::KeyEvent ke;
+
+ ke.window_id = window_id;
+ ke.echo = false;
+ ke.raw = true;
+
+ int key = [event keyCode];
+ int mod = [event modifierFlags];
+
+ if (key == 0x36 || key == 0x37) {
+ if (mod & NSEventModifierFlagCommand) {
+ mod &= ~NSEventModifierFlagCommand;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x38 || key == 0x3c) {
+ if (mod & NSEventModifierFlagShift) {
+ mod &= ~NSEventModifierFlagShift;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x3a || key == 0x3d) {
+ if (mod & NSEventModifierFlagOption) {
+ mod &= ~NSEventModifierFlagOption;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x3b || key == 0x3e) {
+ if (mod & NSEventModifierFlagControl) {
+ mod &= ~NSEventModifierFlagControl;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else {
+ return;
+ }
+
+ ke.osx_state = mod;
+ ke.keycode = remapKey(key, mod);
+ ke.physical_keycode = translateKey(key);
+ ke.unicode = 0;
+
+ _push_to_key_event_buffer(ke);
+ }
+}
+
+- (void)keyUp:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ // Ignore all input if IME input is in progress
+ if (!imeInputEventInProgress) {
+ NSString *characters = [event characters];
+ NSUInteger length = [characters length];
+
+ // Fallback unicode character handler used if IME is not active
+ if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
+ for (NSUInteger i = 0; i < length; i++) {
+ DisplayServerOSX::KeyEvent ke;
+
+ ke.window_id = window_id;
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = false;
+ ke.echo = [event isARepeat];
+ ke.keycode = remapKey([event keyCode], [event modifierFlags]);
+ ke.physical_keycode = translateKey([event keyCode]);
+ ke.raw = true;
+ ke.unicode = [characters characterAtIndex:i];
+
+ _push_to_key_event_buffer(ke);
+ }
+ } else {
+ DisplayServerOSX::KeyEvent ke;
+
+ ke.window_id = window_id;
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = false;
+ ke.echo = [event isARepeat];
+ ke.keycode = remapKey([event keyCode], [event modifierFlags]);
+ ke.physical_keycode = translateKey([event keyCode]);
+ ke.raw = true;
+ ke.unicode = 0;
+
+ _push_to_key_event_buffer(ke);
+ }
+ }
+}
+
+inline void sendScrollEvent(DisplayServer::WindowID window_id, int button, double factor, int modifierFlags) {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ unsigned int mask = 1 << (button - 1);
+
+ Ref<InputEventMouseButton> sc;
+ sc.instance();
+
+ sc->set_window_id(window_id);
+ _get_key_modifier_state(modifierFlags, sc);
+ sc->set_button_index(button);
+ sc->set_factor(factor);
+ sc->set_pressed(true);
+ sc->set_position(wd.mouse_pos);
+ sc->set_global_position(wd.mouse_pos);
+ DS_OSX->last_button_state |= mask;
+ sc->set_button_mask(DS_OSX->last_button_state);
+
+ InputFilter::get_singleton()->accumulate_input_event(sc);
+
+ sc.instance();
+ sc->set_window_id(window_id);
+ sc->set_button_index(button);
+ sc->set_factor(factor);
+ sc->set_pressed(false);
+ sc->set_position(wd.mouse_pos);
+ sc->set_global_position(wd.mouse_pos);
+ DS_OSX->last_button_state &= ~mask;
+ sc->set_button_mask(DS_OSX->last_button_state);
+
+ InputFilter::get_singleton()->accumulate_input_event(sc);
+}
+
+inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy, int modifierFlags) {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ Ref<InputEventPanGesture> pg;
+ pg.instance();
+
+ pg->set_window_id(window_id);
+ _get_key_modifier_state(modifierFlags, pg);
+ pg->set_position(wd.mouse_pos);
+ pg->set_delta(Vector2(-dx, -dy));
+
+ InputFilter::get_singleton()->accumulate_input_event(pg);
+}
+
+- (void)scrollWheel:(NSEvent *)event {
+ ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
+ DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+
+ double deltaX, deltaY;
+
+ const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0;
+ _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor);
+
+ deltaX = [event scrollingDeltaX];
+ deltaY = [event scrollingDeltaY];
+
+ if ([event hasPreciseScrollingDeltas]) {
+ deltaX *= 0.03;
+ deltaY *= 0.03;
+ }
+
+ if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
+ 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]);
+ }
+ if (fabs(deltaY)) {
+ sendScrollEvent(window_id, 0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
+ }
+ }
+}
+
+@end
+
+/*************************************************************************/
+/* GodotWindow */
+/*************************************************************************/
+
+@interface GodotWindow : NSWindow {
+}
+@end
+
+@implementation GodotWindow
+
+- (BOOL)canBecomeKeyWindow {
+ // Required for NSBorderlessWindowMask windows
+ return YES;
+}
+
+@end
+
+/*************************************************************************/
+/* DisplayServerOSX */
+/*************************************************************************/
+
+bool DisplayServerOSX::has_feature(Feature p_feature) const {
+ switch (p_feature) {
+ case FEATURE_GLOBAL_MENU:
+ case FEATURE_SUBWINDOWS:
+ //case FEATURE_TOUCHSCREEN:
+ case FEATURE_MOUSE:
+ case FEATURE_MOUSE_WARP:
+ case FEATURE_CLIPBOARD:
+ case FEATURE_CURSOR_SHAPE:
+ case FEATURE_CUSTOM_CURSOR_SHAPE:
+ case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_CONSOLE_WINDOW:
+ case FEATURE_IME:
+ case FEATURE_WINDOW_TRANSPARENCY:
+ case FEATURE_HIDPI:
+ case FEATURE_ICON:
+ case FEATURE_NATIVE_ICON:
+ case FEATURE_SWAP_BUFFERS:
+ return true;
+ default: {
+ }
+ }
+ return false;
+}
+
+String DisplayServerOSX::get_name() const {
+ return "OSX";
+}
+
+const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const {
+ const NSMenu *menu = NULL;
+ if (p_menu_root == "") {
+ // Main menu.x
+ menu = [NSApp mainMenu];
+ } else if (p_menu_root.to_lower() == "_dock") {
+ // macOS dock menu.
+ menu = dock_menu;
+ } else {
+ // Submenu.
+ if (submenu.has(p_menu_root)) {
+ menu = submenu[p_menu_root];
+ }
+ }
+ if (menu == apple_menu) {
+ // Do not allow to change Apple menu.
+ return NULL;
+ }
+ return menu;
+}
+
+NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
+ NSMenu *menu = NULL;
+ if (p_menu_root == "") {
+ // Main menu.
+ menu = [NSApp mainMenu];
+ } else if (p_menu_root.to_lower() == "_dock") {
+ // macOS dock menu.
+ menu = dock_menu;
+ } else {
+ // Submenu.
+ if (!submenu.has(p_menu_root)) {
+ NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]];
+ submenu[p_menu_root] = n_menu;
+ }
+ menu = submenu[p_menu_root];
+ }
+ if (menu == apple_menu) {
+ // Do not allow to change Apple menu.
+ return NULL;
+ }
+ return menu;
+}
+
+void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
+ GlobalMenuItem *obj = [[[GlobalMenuItem alloc] init] autorelease];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable = false;
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
+ GlobalMenuItem *obj = [[[GlobalMenuItem alloc] init] autorelease];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable = true;
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ NSMenu *sub_menu = _get_menu_root(p_submenu);
+ if (menu && sub_menu) {
+ if (sub_menu == menu) {
+ ERR_PRINT("Can't set submenu to self!");
+ return;
+ }
+ if ([sub_menu supermenu]) {
+ ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
+ return;
+ }
+ NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""];
+ [menu setSubmenu:sub_menu forItem:menu_item];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+}
+
+bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ return ([menu_item state] == NSControlStateValueOn);
+ }
+ }
+ return false;
+}
+
+bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GlobalMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->checkable;
+ }
+ }
+ }
+ return false;
+}
+
+Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GlobalMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->callback;
+ }
+ }
+ }
+ return Callable();
+}
+
+Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, int p_idx) {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GlobalMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->meta;
+ }
+ }
+ }
+ return Variant();
+}
+
+String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, int p_idx) {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ char *utfs = strdup([[menu_item title] UTF8String]);
+ String ret;
+ ret.parse_utf8(utfs);
+ free(utfs);
+ return ret;
+ }
+ }
+ return String();
+}
+
+String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ const NSMenu *sub_menu = [menu_item submenu];
+ if (sub_menu) {
+ for (Map<String, NSMenu *>::Element *E = submenu.front(); E; E = E->next()) {
+ if (E->get() == sub_menu) return E->key();
+ }
+ }
+ }
+ }
+ return String();
+}
+
+void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ if (p_checked) {
+ [menu_item setState:NSControlStateValueOn];
+ } else {
+ [menu_item setState:NSControlStateValueOff];
+ }
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GlobalMenuItem *obj = [menu_item representedObject];
+ obj->checkable = p_checkable;
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GlobalMenuItem *obj = [menu_item representedObject];
+ obj->callback = p_callback;
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GlobalMenuItem *obj = [menu_item representedObject];
+ obj->meta = p_tag;
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ [menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ NSMenu *sub_menu = _get_menu_root(p_submenu);
+ if (menu && sub_menu) {
+ if (sub_menu == menu) {
+ ERR_PRINT("Can't set submenu to self!");
+ return;
+ }
+ if ([sub_menu supermenu]) {
+ ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
+ return;
+ }
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ [menu setSubmenu:sub_menu forItem:menu_item];
+ }
+ }
+}
+
+int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ return [menu numberOfItems];
+ } else {
+ return 0;
+ }
+}
+
+void DisplayServerOSX::global_menu_remove_item(const String &p_menu_root, int p_idx) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not delete Apple menu.
+ return;
+ }
+ [menu removeItemAtIndex:p_idx];
+ }
+}
+
+void DisplayServerOSX::global_menu_clear(const String &p_menu_root) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ [menu removeAllItems];
+ // Restore Apple menu.
+ if (menu == [NSApp mainMenu]) {
+ NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
+ [menu setSubmenu:apple_menu forItem:menu_item];
+ }
+ }
+}
+
+void DisplayServerOSX::alert(const String &p_alert, const String &p_title) {
+ _THREAD_SAFE_METHOD_
+
+ NSAlert *window = [[NSAlert alloc] init];
+ NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
+ NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
+
+ [window addButtonWithTitle:@"OK"];
+ [window setMessageText:ns_title];
+ [window setInformativeText:ns_alert];
+ [window setAlertStyle:NSAlertStyleWarning];
+
+ [window runModal];
+ [window release];
+}
+
+Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ NSAlert *window = [[NSAlert alloc] init];
+ NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
+ NSString *ns_description = [NSString stringWithUTF8String:p_description.utf8().get_data()];
+
+ for (int i = 0; i < p_buttons.size(); i++) {
+ NSString *ns_button = [NSString stringWithUTF8String:p_buttons[i].utf8().get_data()];
+ [window addButtonWithTitle:ns_button];
+ }
+ [window setMessageText:ns_title];
+ [window setInformativeText:ns_description];
+ [window setAlertStyle:NSAlertStyleInformational];
+
+ int button_pressed;
+ NSInteger ret = [window runModal];
+ if (ret == NSAlertFirstButtonReturn) {
+ button_pressed = 0;
+ } else if (ret == NSAlertSecondButtonReturn) {
+ button_pressed = 1;
+ } else if (ret == NSAlertThirdButtonReturn) {
+ button_pressed = 2;
+ } else {
+ button_pressed = 2 + (ret - NSAlertThirdButtonReturn);
+ }
+
+ if (!p_callback.is_null()) {
+ Variant button = button_pressed;
+ Variant *buttonp = &button;
+ Variant ret;
+ Callable::CallError ce;
+ p_callback.call((const Variant **)&buttonp, 1, ret, ce);
+ }
+
+ [window release];
+ return OK;
+}
+
+Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
+ _THREAD_SAFE_METHOD_
+
+ NSAlert *window = [[NSAlert alloc] init];
+ NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
+ NSString *ns_description = [NSString stringWithUTF8String:p_description.utf8().get_data()];
+ NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 30)];
+
+ [window addButtonWithTitle:@"OK"];
+ [window setMessageText:ns_title];
+ [window setInformativeText:ns_description];
+ [window setAlertStyle:NSAlertStyleInformational];
+
+ [input setStringValue:[NSString stringWithUTF8String:p_partial.utf8().get_data()]];
+ [window setAccessoryView:input];
+
+ [window runModal];
+
+ char *utfs = strdup([[input stringValue] UTF8String]);
+ String ret;
+ ret.parse_utf8(utfs);
+ free(utfs);
+
+ if (!p_callback.is_null()) {
+ Variant text = ret;
+ Variant *textp = &text;
+ Variant ret;
+ Callable::CallError ce;
+ p_callback.call((const Variant **)&textp, 1, ret, ce);
+ }
+
+ [window release];
+ return OK;
+}
+
+void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
+ _THREAD_SAFE_METHOD_
+
+ if (p_mode == mouse_mode)
+ return;
+
+ if (p_mode == MOUSE_MODE_CAPTURED) {
+ // Apple Docs state that the display parameter is not used.
+ // "This parameter is not used. By default, you may pass kCGDirectMainDisplay."
+ // https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html
+ CGDisplayHideCursor(kCGDirectMainDisplay);
+ CGAssociateMouseAndMouseCursorPosition(false);
+ } else if (p_mode == MOUSE_MODE_HIDDEN) {
+ CGDisplayHideCursor(kCGDirectMainDisplay);
+ CGAssociateMouseAndMouseCursorPosition(true);
+ } else {
+ CGDisplayShowCursor(kCGDirectMainDisplay);
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
+
+ mouse_mode = p_mode;
+}
+
+DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const {
+ return mouse_mode;
+}
+
+void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
+ _THREAD_SAFE_METHOD_
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ last_mouse_pos = p_to;
+ } else {
+ WindowData &wd = windows[MAIN_WINDOW_ID];
+
+ //local point in window coords
+ const NSRect contentRect = [wd.window_view frame];
+ float displayScale = _display_scale([wd.window_object screen]);
+ NSRect pointInWindowRect = NSMakeRect(p_to.x / displayScale, contentRect.size.height - (p_to.y / displayScale) - 1, 0, 0);
+ NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
+
+ //point in scren coords
+ CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
+
+ //do the warping
+ CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
+ CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
+ CGAssociateMouseAndMouseCursorPosition(false);
+ CGWarpMouseCursorPosition(lMouseWarpPos);
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
+}
+
+Point2i DisplayServerOSX::mouse_get_position() const {
+ return last_mouse_pos;
+}
+
+Point2i DisplayServerOSX::mouse_get_absolute_position() const {
+ _THREAD_SAFE_METHOD_
+
+ const NSPoint mouse_pos = [NSEvent mouseLocation];
+
+ for (NSScreen *screen in [NSScreen screens]) {
+ NSRect frame = [screen frame];
+ if (NSMouseInRect(mouse_pos, frame, NO)) {
+ return Vector2i((int)mouse_pos.x, (int)-mouse_pos.y) + _get_screens_origin();
+ }
+ }
+ return Vector2i();
+}
+
+int DisplayServerOSX::mouse_get_button_state() const {
+ return last_button_state;
+}
+
+void DisplayServerOSX::clipboard_set(const String &p_text) {
+ _THREAD_SAFE_METHOD_
+
+ NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()];
+ NSArray *copiedStringArray = [NSArray arrayWithObject:copiedString];
+
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ [pasteboard clearContents];
+ [pasteboard writeObjects:copiedStringArray];
+}
+
+String DisplayServerOSX::clipboard_get() const {
+ _THREAD_SAFE_METHOD_
+
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
+ NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
+ NSDictionary *options = [NSDictionary dictionary];
+
+ BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
+
+ if (!ok) {
+ return "";
+ }
+
+ NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
+ NSString *string = [objectsToPaste objectAtIndex:0];
+
+ char *utfs = strdup([string UTF8String]);
+ String ret;
+ ret.parse_utf8(utfs);
+ free(utfs);
+
+ return ret;
+}
+
+int DisplayServerOSX::get_screen_count() const {
+ _THREAD_SAFE_METHOD_
+
+ NSArray *screenArray = [NSScreen screens];
+ return [screenArray count];
+}
+
+// Returns the native top-left screen coordinate of the smallest rectangle
+// that encompasses all screens. Needed in get_screen_position(),
+// window_get_position, and window_set_position()
+// to convert between OS X native screen coordinates and the ones expected by Godot
+
+static bool displays_arrangement_dirty = true;
+static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
+ displays_arrangement_dirty = true;
+}
+
+float DisplayServerOSX::_display_scale(id screen) const {
+ if (OS_OSX::get_singleton()->is_hidpi_allowed()) {
+ if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
+ return fmax(1.0, [screen backingScaleFactor]);
+ }
+ }
+ return 1.0;
+}
+
+Point2i DisplayServerOSX::_get_screens_origin() const {
+ static Point2i origin;
+
+ if (displays_arrangement_dirty) {
+ origin = Point2i();
+
+ for (int i = 0; i < get_screen_count(); i++) {
+ Point2i position = _get_native_screen_position(i);
+ if (position.x < origin.x) {
+ origin.x = position.x;
+ }
+ if (position.y > origin.y) {
+ origin.y = position.y;
+ }
+ }
+ displays_arrangement_dirty = false;
+ }
+
+ return origin;
+}
+
+Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const {
+ NSArray *screenArray = [NSScreen screens];
+ if ((NSUInteger)p_screen < [screenArray count]) {
+ float display_scale = _display_scale([screenArray objectAtIndex:p_screen]);
+ NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
+ // Return the top-left corner of the screen, for OS X the y starts at the bottom
+ return Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * display_scale;
+ }
+
+ return Point2i();
+}
+
+Point2i DisplayServerOSX::screen_get_position(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ Point2i position = _get_native_screen_position(p_screen) - _get_screens_origin();
+ // OS X native y-coordinate relative to _get_screens_origin() is negative,
+ // Godot expects a positive value
+ position.y *= -1;
+ return position;
+}
+
+Size2i DisplayServerOSX::screen_get_size(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ NSArray *screenArray = [NSScreen screens];
+ if ((NSUInteger)p_screen < [screenArray count]) {
+ float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
+ // Note: Use frame to get the whole screen size
+ NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
+ return Size2i(nsrect.size.width, nsrect.size.height) * displayScale;
+ }
+
+ return Size2i();
+}
+
+int DisplayServerOSX::screen_get_dpi(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ NSArray *screenArray = [NSScreen screens];
+ if ((NSUInteger)p_screen < [screenArray count]) {
+ float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
+ NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
+ NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
+ CGSize displayPhysicalSize = CGDisplayScreenSize(
+ [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
+
+ return (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale;
+ }
+
+ return 96;
+}
+
+float DisplayServerOSX::screen_get_scale(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+ NSArray *screenArray = [NSScreen screens];
+ if ((NSUInteger)p_screen < [screenArray count]) {
+ return _display_scale([screenArray objectAtIndex:p_screen]);
+ }
+
+ return 1.f;
+}
+
+Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+ p_screen = window_get_current_screen();
+ }
+
+ NSArray *screenArray = [NSScreen screens];
+ if ((NSUInteger)p_screen < [screenArray count]) {
+ float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
+ NSRect nsrect = [[screenArray objectAtIndex:p_screen] visibleFrame];
+
+ Point2i position = Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * displayScale - _get_screens_origin();
+ position.y *= -1;
+ Size2i size = Size2i(nsrect.size.width, nsrect.size.height) / displayScale;
+
+ return Rect2i(position, size);
+ }
+
+ return Rect2i();
+}
+
+Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const {
+ _THREAD_SAFE_METHOD_
+
+ Vector<int> ret;
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+ _THREAD_SAFE_METHOD_
+
+ WindowID id = _create_window(p_mode, p_rect);
+ WindowData &wd = windows[id];
+ for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+ if (p_flags & (1 << i)) {
+ window_set_flag(WindowFlags(i), true, id);
+ }
+ }
+ [wd.window_object makeKeyAndOrderFront:nil];
+ return id;
+}
+
+void DisplayServerOSX::_send_window_event(const WindowData &wd, WindowEvent p_event) {
+ _THREAD_SAFE_METHOD_
+
+ if (!wd.event_callback.is_null()) {
+ Variant event = int(p_event);
+ Variant *eventp = &event;
+ Variant ret;
+ Callable::CallError ce;
+ wd.event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ }
+}
+
+DisplayServerOSX::WindowID DisplayServerOSX::_find_window_id(id p_window) {
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (E->get().window_object == p_window)
+ return E->key();
+ }
+ return INVALID_WINDOW_ID;
+}
+
+void DisplayServerOSX::_update_window(WindowData p_wd) {
+ bool borderless_full = false;
+
+ if (p_wd.borderless) {
+ NSRect frameRect = [p_wd.window_object frame];
+ NSRect screenRect = [[p_wd.window_object screen] frame];
+
+ // Check if our window covers up the screen
+ if (frameRect.origin.x <= screenRect.origin.x && frameRect.origin.y <= frameRect.origin.y &&
+ frameRect.size.width >= screenRect.size.width && frameRect.size.height >= screenRect.size.height) {
+ borderless_full = true;
+ }
+ }
+
+ if (borderless_full) {
+ // If the window covers up the screen set the level to above the main menu and hide on deactivate
+ [p_wd.window_object setLevel:NSMainMenuWindowLevel + 1];
+ [p_wd.window_object setHidesOnDeactivate:YES];
+ } else {
+ // Reset these when our window is not a borderless window that covers up the screen
+ [p_wd.window_object setLevel:NSNormalWindowLevel];
+ [p_wd.window_object setHidesOnDeactivate:NO];
+ }
+}
+
+void DisplayServerOSX::delete_sub_window(WindowID p_id) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_id));
+ ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted");
+
+ WindowData &wd = windows[p_id];
+
+ [wd.window_object setContentView:nil];
+ [wd.window_object close];
+}
+
+void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ [wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
+}
+
+void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.rect_changed_callback = p_callable;
+}
+
+void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.event_callback = p_callable;
+}
+
+void DisplayServerOSX::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.input_event_callback = p_callable;
+}
+
+void DisplayServerOSX::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.input_text_callback = p_callable;
+}
+
+void DisplayServerOSX::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ wd.drop_files_callback = p_callable;
+}
+
+int DisplayServerOSX::window_get_current_screen(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V(!windows.has(p_window), -1);
+ const WindowData &wd = windows[p_window];
+
+ const NSUInteger index = [[NSScreen screens] indexOfObject:[wd.window_object screen]];
+ return (index == NSNotFound) ? 0 : index;
+}
+
+void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+ Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
+ window_set_position(wpos + screen_get_position(p_screen), p_window);
+}
+
+void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) {
+ _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(p_window == p_parent);
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd_window = windows[p_window];
+
+ ERR_FAIL_COND(wd_window.transient_parent == p_parent);
+
+ ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
+ if (p_parent == INVALID_WINDOW_ID) {
+ //remove transient
+ ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
+ ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
+
+ WindowData &wd_parent = windows[wd_window.transient_parent];
+
+ wd_window.transient_parent = INVALID_WINDOW_ID;
+ wd_parent.transient_children.erase(p_window);
+
+ [wd_window.window_object setParentWindow:nil];
+ } else {
+ ERR_FAIL_COND(!windows.has(p_parent));
+ ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
+ WindowData &wd_parent = windows[p_parent];
+
+ wd_window.transient_parent = p_parent;
+ wd_parent.transient_children.insert(p_window);
+
+ [wd_window.window_object setParentWindow:wd_parent.window_object];
+ }
+}
+
+Point2i DisplayServerOSX::window_get_position(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
+ const WindowData &wd = windows[p_window];
+
+ NSRect nsrect = [wd.window_object frame];
+ Point2i pos;
+ float display_scale = _display_scale([wd.window_object screen]);
+
+ // Return the position of the top-left corner, for OS X the y starts at the bottom
+ pos.x = nsrect.origin.x * display_scale;
+ pos.y = (nsrect.origin.y + nsrect.size.height) * display_scale;
+ pos -= _get_screens_origin();
+ // OS X native y-coordinate relative to _get_screens_origin() is negative,
+ // Godot expects a positive value
+ pos.y *= -1;
+ return pos;
+}
+
+void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ Point2i position = p_position;
+ // OS X native y-coordinate relative to _get_screens_origin() is negative,
+ // Godot passes a positive value
+ position.y *= -1;
+ position += _get_screens_origin();
+
+ NSPoint pos;
+ float displayScale = _display_scale([wd.window_object screen]);
+
+ pos.x = position.x / displayScale;
+ pos.y = position.y / displayScale;
+
+ [wd.window_object setFrameTopLeftPoint:pos];
+
+ _update_window(wd);
+ _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream], displayScale);
+}
+
+void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
+ ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
+ return;
+ }
+ wd.max_size = p_size;
+
+ if ((wd.max_size != Size2i()) && !wd.fullscreen) {
+ Size2i size = wd.max_size / _display_scale([wd.window_object screen]);
+ [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
+ } else {
+ [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ }
+}
+
+Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+ return wd.max_size;
+}
+
+void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
+ ERR_PRINT("Minimum window size can't be larger than maximum window size!");
+ return;
+ }
+ wd.min_size = p_size;
+
+ if ((wd.min_size != Size2i()) && !wd.fullscreen) {
+ Size2i size = wd.min_size / _display_scale([wd.window_object screen]);
+ [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
+ } else {
+ [wd.window_object setContentMinSize:NSMakeSize(0, 0)];
+ }
+}
+
+Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+
+ return wd.min_size;
+}
+
+void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ Size2i size = p_size / _display_scale([wd.window_object screen]);
+
+ if (!wd.borderless) {
+ // NSRect used by setFrame includes the title bar, so add it to our size.y
+ CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
+ if (menuBarHeight != 0.f) {
+ size.y += menuBarHeight;
+ }
+ }
+
+ NSRect frame = [wd.window_object frame];
+ [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES];
+
+ _update_window(wd);
+}
+
+Size2i DisplayServerOSX::window_get_size(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+ return wd.size;
+}
+
+Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+ NSRect frame = [wd.window_object frame];
+ return Size2i(frame.size.width, frame.size.height) * _display_scale([wd.window_object screen]);
+}
+
+bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const {
+ return true;
+}
+
+void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if (!OS_OSX::get_singleton()->is_layered_allowed()) return;
+ if (wd.layered_window != p_enabled) {
+ if (p_enabled) {
+ [wd.window_object setBackgroundColor:[NSColor clearColor]];
+ [wd.window_object setOpaque:NO];
+ [wd.window_object setHasShadow:NO];
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ CALayer *layer = [wd.window_view layer];
+ [layer setOpaque:NO];
+ //TODO - implement transparency for Vulkan
+ }
+#endif
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ wd.context_gles2->set_opacity(0);
+ }
+#endif
+ wd.layered_window = true;
+ } else {
+ [wd.window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]];
+ [wd.window_object setOpaque:YES];
+ [wd.window_object setHasShadow:YES];
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ CALayer *layer = [wd.window_view layer];
+ [layer setOpaque:YES];
+ //TODO - implement transparency for Vulkan
+ }
+#endif
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ wd.context_gles2->set_opacity(1);
+ }
+#endif
+ wd.layered_window = false;
+ }
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ wd.context_gles2->update();
+ }
+#endif
+ NSRect frameRect = [wd.window_object frame];
+ [wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:YES];
+ [wd.window_object setFrame:frameRect display:YES];
+ }
+}
+
+void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ WindowMode old_mode = window_get_mode(p_window);
+ if (old_mode == p_mode) {
+ return; // do nothing
+ }
+
+ switch (old_mode) {
+ case WINDOW_MODE_WINDOWED: {
+ //do nothing
+ } break;
+ case WINDOW_MODE_MINIMIZED: {
+ [wd.window_object deminiaturize:nil];
+ } break;
+ case WINDOW_MODE_FULLSCREEN: {
+ if (wd.layered_window)
+ _set_window_per_pixel_transparency_enabled(true, p_window);
+ if (wd.resize_disabled) //restore resize disabled
+ [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
+ if (wd.min_size != Size2i()) {
+ Size2i size = wd.min_size / _display_scale([wd.window_object screen]);
+ [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
+ }
+ if (wd.max_size != Size2i()) {
+ Size2i size = wd.max_size / _display_scale([wd.window_object screen]);
+ [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
+ }
+ [wd.window_object toggleFullScreen:nil];
+ wd.fullscreen = false;
+ } break;
+ case WINDOW_MODE_MAXIMIZED: {
+ if ([wd.window_object isZoomed]) {
+ [wd.window_object zoom:nil];
+ }
+ } break;
+ }
+
+ switch (p_mode) {
+ case WINDOW_MODE_WINDOWED: {
+ //do nothing
+ } break;
+ case WINDOW_MODE_MINIMIZED: {
+ [wd.window_object performMiniaturize:nil];
+ } break;
+ case WINDOW_MODE_FULLSCREEN: {
+ if (wd.layered_window)
+ _set_window_per_pixel_transparency_enabled(false, p_window);
+ if (wd.resize_disabled) //fullscreen window should be resizable to work
+ [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable];
+ [wd.window_object setContentMinSize:NSMakeSize(0, 0)];
+ [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [wd.window_object toggleFullScreen:nil];
+ wd.fullscreen = true;
+ } break;
+ case WINDOW_MODE_MAXIMIZED: {
+ if (![wd.window_object isZoomed]) {
+ [wd.window_object zoom:nil];
+ }
+ } break;
+ }
+}
+
+DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
+ const WindowData &wd = windows[p_window];
+
+ if (wd.fullscreen) { //if fullscreen, it's not in another mode
+ return WINDOW_MODE_FULLSCREEN;
+ }
+ if ([wd.window_object isZoomed] && !wd.resize_disabled) {
+ return WINDOW_MODE_MAXIMIZED;
+ }
+ if ([wd.window_object respondsToSelector:@selector(isMiniaturized)]) {
+ if ([wd.window_object isMiniaturized]) {
+ return WINDOW_MODE_MINIMIZED;
+ }
+ }
+
+ // all other discarded, return windowed.
+ return WINDOW_MODE_WINDOWED;
+}
+
+void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ switch (p_flag) {
+ case WINDOW_FLAG_RESIZE_DISABLED: {
+ wd.resize_disabled = p_enabled;
+ if (wd.fullscreen) //fullscreen window should be resizable, style will be applyed on exiting fs
+ return;
+ if (p_enabled) {
+ [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
+ } else {
+ [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable];
+ }
+ } break;
+ case WINDOW_FLAG_BORDERLESS: {
+ // OrderOut prevents a lose focus bug with the window
+ [wd.window_object orderOut:nil];
+ wd.borderless = p_enabled;
+ if (p_enabled) {
+ [wd.window_object setStyleMask:NSWindowStyleMaskBorderless];
+ } else {
+ if (wd.layered_window)
+ _set_window_per_pixel_transparency_enabled(false, p_window);
+ [wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)];
+ // Force update of the window styles
+ NSRect frameRect = [wd.window_object frame];
+ [wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
+ [wd.window_object setFrame:frameRect display:NO];
+ }
+ _update_window(wd);
+ [wd.window_object makeKeyAndOrderFront:nil];
+ } break;
+ case WINDOW_FLAG_ALWAYS_ON_TOP: {
+ wd.on_top = p_enabled;
+ if (p_enabled) {
+ [wd.window_object setLevel:NSFloatingWindowLevel];
+ } else {
+ [wd.window_object setLevel:NSNormalWindowLevel];
+ }
+ } break;
+ case WINDOW_FLAG_TRANSPARENT: {
+ wd.layered_window = p_enabled;
+ if (p_enabled) {
+ [wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; // force borderless
+ } else if (!wd.borderless) {
+ [wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)];
+ }
+ _set_window_per_pixel_transparency_enabled(p_enabled, p_window);
+
+ } break;
+ default: {
+ }
+ }
+}
+
+bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+
+ switch (p_flag) {
+ case WINDOW_FLAG_RESIZE_DISABLED: {
+ return wd.resize_disabled;
+ } break;
+ case WINDOW_FLAG_BORDERLESS: {
+ return [wd.window_object styleMask] == NSWindowStyleMaskBorderless;
+ } break;
+ case WINDOW_FLAG_ALWAYS_ON_TOP: {
+ return [wd.window_object level] == NSFloatingWindowLevel;
+ } break;
+ case WINDOW_FLAG_TRANSPARENT: {
+ return wd.layered_window;
+ } break;
+ default: {
+ }
+ }
+
+ return false;
+}
+
+void DisplayServerOSX::window_request_attention(WindowID p_window) {
+ // It's app global, ignore window id.
+ [NSApp requestUserAttention:NSCriticalRequest];
+}
+
+void DisplayServerOSX::window_move_to_foreground(WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ const WindowData &wd = windows[p_window];
+
+ [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
+ [wd.window_object makeKeyAndOrderFront:nil];
+}
+
+bool DisplayServerOSX::window_can_draw(WindowID p_window) const {
+ return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
+}
+
+bool DisplayServerOSX::can_any_window_draw() const {
+ _THREAD_SAFE_METHOD_
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (window_get_mode(E->key()) != WINDOW_MODE_MINIMIZED) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.im_active = p_active;
+
+ if (!p_active)
+ [wd.window_view cancelComposition];
+}
+
+void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.im_position = p_pos;
+}
+
+bool DisplayServerOSX::get_swap_ok_cancel() {
+ return true;
+}
+
+void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
+
+ if (cursor_shape == p_shape)
+ return;
+
+ if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
+ cursor_shape = p_shape;
+ return;
+ }
+
+ if (cursors[p_shape] != NULL) {
+ [cursors[p_shape] set];
+ } else {
+ switch (p_shape) {
+ case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
+ case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
+ case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
+ case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
+ case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
+ case CURSOR_FORBIDDEN: [[NSCursor operationNotAllowedCursor] set]; break;
+ case CURSOR_VSIZE: [_cursorFromSelector(@selector(_windowResizeNorthSouthCursor), @selector(resizeUpDownCursor)) set]; break;
+ case CURSOR_HSIZE: [_cursorFromSelector(@selector(_windowResizeEastWestCursor), @selector(resizeLeftRightCursor)) set]; break;
+ case CURSOR_BDIAGSIZE: [_cursorFromSelector(@selector(_windowResizeNorthEastSouthWestCursor)) set]; break;
+ case CURSOR_FDIAGSIZE: [_cursorFromSelector(@selector(_windowResizeNorthWestSouthEastCursor)) set]; break;
+ case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
+ case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
+ case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
+ case CURSOR_HELP: [_cursorFromSelector(@selector(_helpCursor)) set]; break;
+ default: {
+ }
+ }
+ }
+
+ cursor_shape = p_shape;
+}
+
+DisplayServerOSX::CursorShape DisplayServerOSX::cursor_get_shape() const {
+ return cursor_shape;
+}
+
+void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ _THREAD_SAFE_METHOD_
+
+ if (p_cursor.is_valid()) {
+ Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
+
+ if (cursor_c) {
+ if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
+ cursor_set_shape(p_shape);
+ return;
+ }
+ cursors_cache.erase(p_shape);
+ }
+
+ Ref<Texture2D> texture = p_cursor;
+ Ref<AtlasTexture> atlas_texture = p_cursor;
+ Ref<Image> image;
+ Size2 texture_size;
+ Rect2 atlas_rect;
+
+ if (texture.is_valid()) {
+ image = texture->get_data();
+ }
+
+ if (!image.is_valid() && atlas_texture.is_valid()) {
+ texture = atlas_texture->get_atlas();
+
+ atlas_rect.size.width = texture->get_width();
+ atlas_rect.size.height = texture->get_height();
+ atlas_rect.position.x = atlas_texture->get_region().position.x;
+ atlas_rect.position.y = atlas_texture->get_region().position.y;
+
+ texture_size.width = atlas_texture->get_region().size.x;
+ texture_size.height = atlas_texture->get_region().size.y;
+ } else if (image.is_valid()) {
+ texture_size.width = texture->get_width();
+ texture_size.height = texture->get_height();
+ }
+
+ ERR_FAIL_COND(!texture.is_valid());
+ ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
+ 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();
+
+ ERR_FAIL_COND(!image.is_valid());
+
+ NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:NULL
+ pixelsWide:int(texture_size.width)
+ pixelsHigh:int(texture_size.height)
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:int(texture_size.width) * 4
+ bitsPerPixel:32];
+
+ ERR_FAIL_COND(imgrep == nil);
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = int(texture_size.width * texture_size.height);
+
+ for (int i = 0; i < len; i++) {
+ int row_index = floor(i / texture_size.width) + atlas_rect.position.y;
+ int column_index = (i % int(texture_size.width)) + atlas_rect.position.x;
+
+ if (atlas_texture.is_valid()) {
+ column_index = MIN(column_index, atlas_rect.size.width - 1);
+ row_index = MIN(row_index, atlas_rect.size.height - 1);
+ }
+
+ uint32_t color = image->get_pixel(column_index, row_index).to_argb32();
+
+ uint8_t alpha = (color >> 24) & 0xFF;
+ pixels[i * 4 + 0] = ((color >> 16) & 0xFF) * alpha / 255;
+ pixels[i * 4 + 1] = ((color >> 8) & 0xFF) * alpha / 255;
+ pixels[i * 4 + 2] = ((color)&0xFF) * alpha / 255;
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ NSImage *nsimage = [[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)];
+ [nsimage addRepresentation:imgrep];
+
+ NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
+
+ [cursors[p_shape] release];
+ cursors[p_shape] = cursor;
+
+ Vector<Variant> params;
+ params.push_back(p_cursor);
+ params.push_back(p_hotspot);
+ cursors_cache.insert(p_shape, params);
+
+ if (p_shape == cursor_shape) {
+ if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ [cursor set];
+ }
+ }
+
+ [imgrep release];
+ [nsimage release];
+ } else {
+ // Reset to default system cursor
+ if (cursors[p_shape] != NULL) {
+ [cursors[p_shape] release];
+ cursors[p_shape] = NULL;
+ }
+
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ cursor_set_shape(c);
+
+ cursors_cache.erase(p_shape);
+ }
+}
+
+static bool keyboard_layout_dirty = true;
+static void keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) {
+ keyboard_layout_dirty = true;
+}
+
+// Returns string representation of keys, if they are printable.
+static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) {
+ TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+ if (!currentKeyboard)
+ return nil;
+
+ CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
+ if (!layoutData)
+ return nil;
+
+ const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+
+ OSStatus err;
+ CFMutableStringRef output = CFStringCreateMutable(NULL, 0);
+
+ for (int i = 0; i < length; ++i) {
+ UInt32 keysDown = 0;
+ UniChar chars[4];
+ UniCharCount realLength;
+
+ err = UCKeyTranslate(keyboardLayout,
+ keyCode[i],
+ kUCKeyActionDisplay,
+ 0,
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &keysDown,
+ sizeof(chars) / sizeof(chars[0]),
+ &realLength,
+ chars);
+
+ if (err != noErr) {
+ CFRelease(output);
+ return nil;
+ }
+
+ CFStringAppendCharacters(output, chars, 1);
+ }
+
+ return (NSString *)output;
+}
+
+DisplayServerOSX::LatinKeyboardVariant DisplayServerOSX::get_latin_keyboard_variant() const {
+ _THREAD_SAFE_METHOD_
+
+ static LatinKeyboardVariant layout = LATIN_KEYBOARD_QWERTY;
+
+ if (keyboard_layout_dirty) {
+
+ layout = LATIN_KEYBOARD_QWERTY;
+
+ CGKeyCode keys[] = { kVK_ANSI_Q, kVK_ANSI_W, kVK_ANSI_E, kVK_ANSI_R, kVK_ANSI_T, kVK_ANSI_Y };
+ NSString *test = createStringForKeys(keys, 6);
+
+ if ([test isEqualToString:@"qwertz"]) {
+ layout = LATIN_KEYBOARD_QWERTZ;
+ } else if ([test isEqualToString:@"azerty"]) {
+ layout = LATIN_KEYBOARD_AZERTY;
+ } else if ([test isEqualToString:@"qzerty"]) {
+ layout = LATIN_KEYBOARD_QZERTY;
+ } else if ([test isEqualToString:@"',.pyf"]) {
+ layout = LATIN_KEYBOARD_DVORAK;
+ } else if ([test isEqualToString:@"xvlcwk"]) {
+ layout = LATIN_KEYBOARD_NEO;
+ } else if ([test isEqualToString:@"qwfpgj"]) {
+ layout = LATIN_KEYBOARD_COLEMAK;
+ }
+
+ [test release];
+
+ keyboard_layout_dirty = false;
+ return layout;
+ }
+
+ return layout;
+}
+
+void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEvent> ev = p_event;
+ InputFilter::get_singleton()->accumulate_input_event(ev);
+}
+
+void DisplayServerOSX::_release_pressed_events() {
+ _THREAD_SAFE_METHOD_
+ if (InputFilter::get_singleton()) {
+ InputFilter::get_singleton()->release_pressed_events();
+ }
+}
+
+void DisplayServerOSX::_process_key_events() {
+ Ref<InputEventKey> k;
+ for (int i = 0; i < key_event_pos; i++) {
+ const KeyEvent &ke = key_event_buffer[i];
+ if (ke.raw) {
+ // Non IME input - no composite characters, pass events as is
+ k.instance();
+
+ k->set_window_id(ke.window_id);
+ _get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_keycode(ke.keycode);
+ k->set_physical_keycode(ke.physical_keycode);
+ k->set_unicode(ke.unicode);
+
+ _push_input(k);
+ } else {
+ // IME input
+ if ((i == 0 && ke.keycode == 0) || (i > 0 && key_event_buffer[i - 1].keycode == 0)) {
+ k.instance();
+
+ k->set_window_id(ke.window_id);
+ _get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_keycode(0);
+ k->set_physical_keycode(0);
+ k->set_unicode(ke.unicode);
+
+ _push_input(k);
+ }
+ if (ke.keycode != 0) {
+ k.instance();
+
+ k->set_window_id(ke.window_id);
+ _get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_keycode(ke.keycode);
+ k->set_physical_keycode(ke.physical_keycode);
+
+ if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == 0) {
+ k->set_unicode(key_event_buffer[i + 1].unicode);
+ }
+
+ _push_input(k);
+ }
+ }
+ }
+
+ key_event_pos = 0;
+}
+
+void DisplayServerOSX::process_events() {
+ _THREAD_SAFE_METHOD_
+
+ while (true) {
+ NSEvent *event = [NSApp
+ nextEventMatchingMask:NSEventMaskAny
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+
+ if (event == nil)
+ break;
+
+ [NSApp sendEvent:event];
+ }
+
+ if (!drop_events) {
+ _process_key_events();
+ InputFilter::get_singleton()->flush_accumulated_events();
+ }
+
+ [autoreleasePool drain];
+ autoreleasePool = [[NSAutoreleasePool alloc] init];
+}
+
+void DisplayServerOSX::force_process_and_drop_events() {
+ _THREAD_SAFE_METHOD_
+
+ drop_events = true;
+ process_events();
+ drop_events = false;
+}
+
+void DisplayServerOSX::set_native_icon(const String &p_filename) {
+ _THREAD_SAFE_METHOD_
+
+ FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
+ ERR_FAIL_COND(!f);
+
+ Vector<uint8_t> data;
+ uint32_t len = f->get_len();
+ data.resize(len);
+ f->get_buffer((uint8_t *)&data.write[0], len);
+ memdelete(f);
+
+ NSData *icon_data = [[[NSData alloc] initWithBytes:&data.write[0] length:len] autorelease];
+ ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data.");
+
+ NSImage *icon = [[[NSImage alloc] initWithData:icon_data] autorelease];
+ ERR_FAIL_COND_MSG(!icon, "Error loading icon.");
+
+ [NSApp setApplicationIconImage:icon];
+}
+
+void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) {
+ _THREAD_SAFE_METHOD_
+
+ Ref<Image> img = p_icon;
+ img = img->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
+ NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:NULL
+ pixelsWide:img->get_width()
+ pixelsHigh:img->get_height()
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:img->get_width() * 4
+ bitsPerPixel:32];
+ ERR_FAIL_COND(imgrep == nil);
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = img->get_width() * img->get_height();
+ const uint8_t *r = img->get_data().ptr();
+
+ /* Premultiply the alpha channel */
+ for (int i = 0; i < len; i++) {
+ uint8_t alpha = r[i * 4 + 3];
+ pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
+ pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
+ pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
+ ERR_FAIL_COND(nsimg == nil);
+
+ [nsimg addRepresentation:imgrep];
+ [NSApp setApplicationIconImage:nsimg];
+
+ [imgrep release];
+ [nsimg release];
+}
+
+Vector<String> DisplayServerOSX::get_rendering_drivers_func() {
+ Vector<String> drivers;
+
+#ifdef VULKAN_ENABLED
+ drivers.push_back("vulkan");
+#endif
+#ifdef OPENGL_ENABLED
+ drivers.push_back("opengl");
+#endif
+
+ return drivers;
+}
+
+Point2i DisplayServerOSX::ime_get_selection() const {
+ return im_selection;
+}
+
+String DisplayServerOSX::ime_get_text() const {
+ return im_text;
+}
+
+DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Point2i &p_position) const {
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ Rect2i win_rect = Rect2i(window_get_position(E->key()), window_get_size(E->key()));
+ if (win_rect.has_point(p_position)) {
+ return E->key();
+ }
+ }
+ return INVALID_WINDOW_ID;
+}
+
+void DisplayServerOSX::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].instance_id = p_instance;
+}
+
+ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), ObjectID());
+ return windows[p_window].instance_id;
+}
+
+DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+}
+
+DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, const Rect2i &p_rect) {
+ WindowID id;
+ {
+ WindowData wd;
+
+ float displayScale = 1.0;
+ if (OS_OSX::get_singleton()->is_hidpi_allowed()) {
+ // note that mainScreen is not screen #0 but the one with the keyboard focus.
+ NSScreen *screen = [NSScreen mainScreen];
+ if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
+ displayScale = fmax(displayScale, [screen backingScaleFactor]);
+ }
+ }
+
+ wd.window_delegate = [[GodotWindowDelegate alloc] init];
+ ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate");
+ [wd.window_delegate setWindowID:window_id_counter];
+
+ Point2i position = p_rect.position;
+ // OS X native y-coordinate relative to _get_screens_origin() is negative,
+ // Godot passes a positive value
+ position.y *= -1;
+ position += _get_screens_origin();
+
+ // initWithContentRect uses bottom-left corner of the window’s frame as origin.
+ wd.window_object = [[GodotWindow alloc]
+ initWithContentRect:NSMakeRect(position.x / displayScale, (position.y - p_rect.size.height) / displayScale, p_rect.size.width / displayScale, p_rect.size.height / displayScale)
+ styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window");
+
+ wd.window_view = [[GodotContentView alloc] init];
+ ERR_FAIL_COND_V_MSG(wd.window_view == nil, INVALID_WINDOW_ID, "Can't create a window view");
+ [wd.window_view setWindowID:window_id_counter];
+ if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_14) {
+ [wd.window_view setWantsLayer:TRUE];
+ }
+
+ if (displayScale > 1.0) {
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ [wd.window_view setWantsBestResolutionOpenGLSurface:YES];
+ }
+#endif
+ [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ } else {
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ [wd.window_view setWantsBestResolutionOpenGLSurface:NO];
+ }
+#endif
+ }
+
+ [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ [wd.window_object setContentView:wd.window_view];
+ [wd.window_object setDelegate:wd.window_delegate];
+ [wd.window_object setAcceptsMouseMovedEvents:YES];
+ [wd.window_object setRestorable:NO];
+
+ if ([wd.window_object respondsToSelector:@selector(setTabbingMode:)])
+ [wd.window_object setTabbingMode:NSWindowTabbingModeDisallowed];
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ if (context_vulkan) {
+ CALayer *layer = [wd.window_view layer];
+ layer.contentsScale = displayScale;
+ Error err = context_vulkan->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context");
+ }
+ }
+#endif
+#ifdef OPENGL_ENABLED
+ if (rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ wd.context_gles2 = memnew(ContextGL_OSX(wd.window_view, false));
+
+ if (wd.context_gles2->initialize() != OK) {
+ memdelete(wd.context_gles2);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a OpenGL context");
+ }
+
+ //if (RasterizerGLES2::is_viable() == OK) {
+ // RasterizerGLES2::register_config();
+ // RasterizerGLES2::make_current();
+ //}
+ }
+#endif
+ id = window_id_counter++;
+ windows[id] = wd;
+ }
+
+ WindowData &wd = windows[id];
+ window_set_mode(p_mode, id);
+
+ float displayScale = _display_scale([wd.window_object screen]);
+ const NSRect contentRect = [wd.window_view frame];
+ wd.size.width = contentRect.size.width * displayScale;
+ wd.size.height = contentRect.size.height * displayScale;
+
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ if (OS_OSX::singleton->is_hidpi_allowed()) {
+ [wd.window_view setWantsBestResolutionOpenGLSurface:YES];
+ } else {
+ [wd.window_view setWantsBestResolutionOpenGLSurface:NO];
+ }
+ wd.context_gles2->update();
+ }
+#endif
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ CALayer *layer = [wd.window_view layer];
+ layer.contentsScale = displayScale;
+ context_vulkan->window_resize(id, wd.size.width, wd.size.height);
+ }
+#endif
+
+ return id;
+}
+
+void DisplayServerOSX::_dispatch_input_events(const Ref<InputEvent> &p_event) {
+ ((DisplayServerOSX *)(get_singleton()))->_dispatch_input_event(p_event);
+}
+
+void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) {
+ _THREAD_SAFE_METHOD_
+ if (!in_dispatch_input_event) {
+ in_dispatch_input_event = true;
+
+ Variant ev = p_event;
+ Variant *evp = &ev;
+ Variant ret;
+ Callable::CallError ce;
+
+ Ref<InputEventFromWindow> event_from_window = p_event;
+ if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
+ //send to a window
+ if (windows.has(event_from_window->get_window_id())) {
+ Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
+ if (callable.is_null()) {
+ return;
+ }
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ } else {
+ //send to all windows
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ Callable callable = E->get().input_event_callback;
+ if (callable.is_null()) {
+ continue;
+ }
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ }
+
+ in_dispatch_input_event = false;
+ }
+}
+
+void DisplayServerOSX::release_rendering_thread() {
+ //TODO - reimplement OpenGLES
+}
+
+void DisplayServerOSX::make_rendering_thread() {
+ //TODO - reimplement OpenGLES
+}
+
+void DisplayServerOSX::swap_buffers() {
+ //TODO - reimplement OpenGLES
+}
+
+void DisplayServerOSX::console_set_visible(bool p_enabled) {
+ //TODO - open terminal and redirect
+}
+
+bool DisplayServerOSX::is_console_visible() const {
+ return isatty(STDIN_FILENO);
+}
+
+DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ InputFilter::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
+
+ r_error = OK;
+ drop_events = false;
+
+ memset(cursors, 0, sizeof(cursors));
+ cursor_shape = CURSOR_ARROW;
+
+ key_event_pos = 0;
+ mouse_mode = MOUSE_MODE_VISIBLE;
+ last_button_state = 0;
+
+ autoreleasePool = [[NSAutoreleasePool alloc] init];
+
+ eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
+ ERR_FAIL_COND(!eventSource);
+
+ CGEventSourceSetLocalEventsSuppressionInterval(eventSource, 0.0);
+
+ // Implicitly create shared NSApplication instance
+ [GodotApplication sharedApplication];
+
+ // In case we are unbundled, make us a proper UI application
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+
+ keyboard_layout_dirty = true;
+ displays_arrangement_dirty = true;
+
+ // Register to be notified on keyboard layout changes
+ CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
+ NULL, keyboard_layout_changed,
+ kTISNotifySelectedKeyboardInputSourceChanged, NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ // Register to be notified on displays arrangement changes
+ CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
+
+ // Menu bar setup must go between sharedApplication above and
+ // finishLaunching below, in order to properly emulate the behavior
+ // of NSApplicationMain
+ NSMenuItem *menu_item;
+ NSString *title;
+
+ NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
+ if (nsappname == nil)
+ nsappname = [[NSProcessInfo processInfo] processName];
+
+ // Setup Dock menu
+ dock_menu = [[NSMenu alloc] initWithTitle:@"_dock"];
+
+ // Setup Apple menu
+ apple_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+ title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname];
+ [apple_menu addItemWithTitle:title action:@selector(showAbout:) keyEquivalent:@""];
+
+ [apple_menu addItem:[NSMenuItem separatorItem]];
+
+ NSMenu *services = [[NSMenu alloc] initWithTitle:@""];
+ menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""];
+ [apple_menu setSubmenu:services forItem:menu_item];
+ [NSApp setServicesMenu:services];
+ [services release];
+
+ [apple_menu addItem:[NSMenuItem separatorItem]];
+
+ title = [NSString stringWithFormat:NSLocalizedString(@"Hide %@", nil), nsappname];
+ [apple_menu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+ menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+ [menu_item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
+
+ [apple_menu addItemWithTitle:NSLocalizedString(@"Show all", nil) action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+ [apple_menu addItem:[NSMenuItem separatorItem]];
+
+ title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
+ [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+ // Setup menu bar
+ NSMenu *main_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+ menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
+ [main_menu setSubmenu:apple_menu forItem:menu_item];
+ [NSApp setMainMenu:main_menu];
+
+ [NSApp finishLaunching];
+
+ delegate = [[GodotApplicationDelegate alloc] init];
+ ERR_FAIL_COND(!delegate);
+ [NSApp setDelegate:delegate];
+
+ //process application:openFile: event
+ while (true) {
+ NSEvent *event = [NSApp
+ nextEventMatchingMask:NSEventMaskAny
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+
+ if (event == nil)
+ break;
+
+ [NSApp sendEvent:event];
+ }
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
+ rendering_driver = p_rendering_driver;
+
+#ifndef _MSC_VER
+#warning Forcing vulkan rendering driver because OpenGL not implemented yet
+#endif
+ rendering_driver = "vulkan";
+
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver == "opengl_es") {
+ //TODO - reimplement OpenGLES
+ }
+#endif
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ context_vulkan = memnew(VulkanContextOSX);
+ if (context_vulkan->initialize() != OK) {
+ memdelete(context_vulkan);
+ context_vulkan = NULL;
+ r_error = ERR_CANT_CREATE;
+ ERR_FAIL_MSG("Could not initialize Vulkan");
+ }
+ }
+#endif
+
+ WindowID main_window = _create_window(p_mode, Rect2i(Point2i(), p_resolution));
+ for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+ if (p_flags & (1 << i)) {
+ window_set_flag(WindowFlags(i), true, main_window);
+ }
+ }
+ [windows[main_window].window_object makeKeyAndOrderFront:nil];
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ rendering_device_vulkan = memnew(RenderingDeviceVulkan);
+ rendering_device_vulkan->initialize(context_vulkan);
+
+ RasterizerRD::make_current();
+ }
+#endif
+
+ [NSApp activateIgnoringOtherApps:YES];
+
+ /*
+ visual_server = memnew(VisualServerRaster);
+ if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
+ visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
+ }
+ visual_server->init();
+ */
+}
+
+DisplayServerOSX::~DisplayServerOSX() {
+ if (dock_menu) {
+ [dock_menu release];
+ }
+
+ for (Map<String, NSMenu *>::Element *E = submenu.front(); E; E = E->next()) {
+ [E->get() release];
+ }
+
+ //destroy all windows
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ [E->get().window_object setContentView:nil];
+ [E->get().window_object close];
+ }
+
+ //destroy drivers
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ if (rendering_device_vulkan) {
+ rendering_device_vulkan->finalize();
+ memdelete(rendering_device_vulkan);
+ }
+
+ if (context_vulkan)
+ memdelete(context_vulkan);
+ }
+#endif
+
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
+ CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
+
+ cursors_cache.clear();
+
+ //visual_server->finish();
+ //memdelete(visual_server);
+}
+
+void DisplayServerOSX::register_osx_driver() {
+ register_create_function("osx", create_func, get_rendering_drivers_func);
+}
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index dbe52da912..c2df9c7082 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -402,7 +402,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
args.push_back(p_path);
String str;
- Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true);
+ Error err = OS::get_singleton()->execute("codesign", args, true, nullptr, &str, nullptr, true);
ERR_FAIL_COND_V(err != OK, err);
print_line("codesign (" + p_path + "): " + str);
@@ -435,7 +435,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
args.push_back(p_app_path_name);
String str;
- Error err = OS::get_singleton()->execute("hdiutil", args, true, NULL, &str, NULL, true);
+ Error err = OS::get_singleton()->execute("hdiutil", args, true, nullptr, &str, nullptr, true);
ERR_FAIL_COND_V(err != OK, err);
print_line("hdiutil returned: " + str);
@@ -476,7 +476,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
return ERR_FILE_BAD_PATH;
}
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
if (ep.step("Creating app", 0)) {
@@ -507,11 +507,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
Error err = OK;
String tmp_app_path_name = "";
zlib_filefunc_def io2 = io;
- FileAccess *dst_f = NULL;
+ FileAccess *dst_f = nullptr;
io2.opaque = &dst_f;
- zipFile dst_pkg_zip = NULL;
+ zipFile dst_pkg_zip = nullptr;
- DirAccess *tmp_app_path = NULL;
+ DirAccess *tmp_app_path = nullptr;
String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
if (export_format == "dmg") {
// We're on OSX so we can export to DMG, but first we create our application bundle
@@ -539,7 +539,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
} else {
// Open our destination zip file
- dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2);
+ dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2);
if (!dst_pkg_zip) {
err = ERR_CANT_CREATE;
}
@@ -555,7 +555,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
//get filename
unz_file_info info;
char fname[16384];
- ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0);
String file = fname;
@@ -672,11 +672,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
zipOpenNewFileInZip(dst_pkg_zip,
file.utf8().get_data(),
&fi,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
@@ -754,12 +754,12 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (err == OK) {
zipOpenNewFileInZip(dst_pkg_zip,
(pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
@@ -791,12 +791,12 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
zipOpenNewFileInZip(dst_pkg_zip,
(pkg_name + ".app/Contents/Frameworks/").plus_file(shared_objects[i].path.get_file()).utf8().get_data(),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
Z_DEFLATED,
Z_DEFAULT_COMPRESSION);
@@ -811,7 +811,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
if (dst_pkg_zip) {
- zipClose(dst_pkg_zip, NULL);
+ zipClose(dst_pkg_zip, nullptr);
}
return err;
diff --git a/platform/osx/export/export.h b/platform/osx/export/export.h
index 7b8832cb01..4ddcec09fb 100644
--- a/platform/osx/export/export.h
+++ b/platform/osx/export/export.h
@@ -28,4 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef OSX_EXPORT_H
+#define OSX_EXPORT_H
+
void register_osx_exporter();
+
+#endif // OSX_EXPORT_H
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index e9f46fb5a4..643acd8944 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -34,13 +34,13 @@
#define GODOT_JOY_LOOP_RUN_MODE CFSTR("GodotJoypad")
-static JoypadOSX *self = NULL;
+static JoypadOSX *self = nullptr;
joypad::joypad() {
- device_ref = NULL;
- ff_device = NULL;
- ff_axes = NULL;
- ff_directions = NULL;
+ device_ref = nullptr;
+ ff_device = nullptr;
+ ff_axes = nullptr;
+ ff_directions = nullptr;
ffservice = 0;
ff_timestamp = 0;
id = 0;
@@ -53,7 +53,7 @@ joypad::joypad() {
ff_effect.dwTriggerButton = FFEB_NOTRIGGER;
ff_effect.dwStartDelay = 0;
ff_effect.dwTriggerRepeatInterval = 0;
- ff_effect.lpEnvelope = NULL;
+ ff_effect.lpEnvelope = nullptr;
ff_effect.cbTypeSpecificParams = sizeof(FFCONSTANTFORCE);
ff_effect.lpvTypeSpecificParams = &ff_constant_force;
ff_effect.dwSize = sizeof(ff_effect);
@@ -105,7 +105,7 @@ void joypad::add_hid_element(IOHIDElementRef p_element) {
const IOHIDElementCookie cookie = IOHIDElementGetCookie(p_element);
const uint32_t usagePage = IOHIDElementGetUsagePage(p_element);
const uint32_t usage = IOHIDElementGetUsage(p_element);
- Vector<rec_element> *list = NULL;
+ Vector<rec_element> *list = nullptr;
switch (IOHIDElementGetType(p_element)) {
case kIOHIDElementTypeInput_Misc:
@@ -249,7 +249,7 @@ void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) {
if (is_joypad(p_device)) {
configure_joypad(p_device, &new_joypad);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
- if (IOHIDDeviceGetService != NULL) {
+ if (IOHIDDeviceGetService != nullptr) {
#endif
const io_service_t ioservice = IOHIDDeviceGetService(p_device);
if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK) && new_joypad.config_force_feedback(ioservice)) {
@@ -330,7 +330,7 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
input->joy_connection_changed(id, true, name, guid);
}
- CFArrayRef array = IOHIDDeviceCopyMatchingElements(p_device_ref, NULL, kIOHIDOptionsTypeNone);
+ CFArrayRef array = IOHIDDeviceCopyMatchingElements(p_device_ref, nullptr, kIOHIDOptionsTypeNone);
if (array) {
p_joy->add_hid_elements(array);
CFRelease(array);
@@ -395,38 +395,38 @@ bool joypad::check_ff_features() {
static int process_hat_value(int p_min, int p_max, int p_value) {
int range = (p_max - p_min + 1);
int value = p_value - p_min;
- int hat_value = InputDefault::HAT_MASK_CENTER;
+ int hat_value = InputFilter::HAT_MASK_CENTER;
if (range == 4) {
value *= 2;
}
switch (value) {
case 0:
- hat_value = InputDefault::HAT_MASK_UP;
+ hat_value = InputFilter::HAT_MASK_UP;
break;
case 1:
- hat_value = InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT;
+ hat_value = InputFilter::HAT_MASK_UP | InputFilter::HAT_MASK_RIGHT;
break;
case 2:
- hat_value = InputDefault::HAT_MASK_RIGHT;
+ hat_value = InputFilter::HAT_MASK_RIGHT;
break;
case 3:
- hat_value = InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_RIGHT;
+ hat_value = InputFilter::HAT_MASK_DOWN | InputFilter::HAT_MASK_RIGHT;
break;
case 4:
- hat_value = InputDefault::HAT_MASK_DOWN;
+ hat_value = InputFilter::HAT_MASK_DOWN;
break;
case 5:
- hat_value = InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT;
+ hat_value = InputFilter::HAT_MASK_DOWN | InputFilter::HAT_MASK_LEFT;
break;
case 6:
- hat_value = InputDefault::HAT_MASK_LEFT;
+ hat_value = InputFilter::HAT_MASK_LEFT;
break;
case 7:
- hat_value = InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_LEFT;
+ hat_value = InputFilter::HAT_MASK_UP | InputFilter::HAT_MASK_LEFT;
break;
default:
- hat_value = InputDefault::HAT_MASK_CENTER;
+ hat_value = InputFilter::HAT_MASK_CENTER;
break;
}
return hat_value;
@@ -438,8 +438,8 @@ void JoypadOSX::poll_joypads() const {
}
}
-static const InputDefault::JoyAxis axis_correct(int p_value, int p_min, int p_max) {
- InputDefault::JoyAxis jx;
+static const InputFilter::JoyAxis axis_correct(int p_value, int p_min, int p_max) {
+ InputFilter::JoyAxis jx;
if (p_min < 0) {
jx.min = -1;
if (p_value < 0) {
@@ -531,7 +531,7 @@ bool JoypadOSX::have_device(IOHIDDeviceRef p_device) const {
}
static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 usage, int *okay) {
- CFDictionaryRef retval = NULL;
+ CFDictionaryRef retval = nullptr;
CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
const void *keys[2] = { (void *)CFSTR(kIOHIDDeviceUsagePageKey), (void *)CFSTR(kIOHIDDeviceUsageKey) };
@@ -562,8 +562,8 @@ void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const {
ERR_FAIL_COND(ret != kIOReturnSuccess);
IOHIDManagerSetDeviceMatchingMultiple(hid_manager, p_matching_array);
- IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, joypad_added_callback, NULL);
- IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, joypad_removed_callback, NULL);
+ IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, joypad_added_callback, nullptr);
+ IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, joypad_removed_callback, nullptr);
IOHIDManagerScheduleWithRunLoop(hid_manager, runloop, GODOT_JOY_LOOP_RUN_MODE);
while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) {
@@ -571,9 +571,9 @@ void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const {
}
}
-JoypadOSX::JoypadOSX() {
+JoypadOSX::JoypadOSX(InputFilter *in) {
self = this;
- input = (InputDefault *)Input::get_singleton();
+ input = in;
int okay = 1;
const void *vals[] = {
@@ -582,7 +582,7 @@ JoypadOSX::JoypadOSX() {
(void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay),
};
const size_t n_elements = sizeof(vals) / sizeof(vals[0]);
- CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, n_elements, &kCFTypeArrayCallBacks) : NULL;
+ CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, n_elements, &kCFTypeArrayCallBacks) : nullptr;
for (size_t i = 0; i < n_elements; i++) {
if (vals[i]) {
@@ -592,7 +592,7 @@ JoypadOSX::JoypadOSX() {
if (array) {
hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
- if (hid_manager != NULL) {
+ if (hid_manager != nullptr) {
config_hid_manager(array);
}
CFRelease(array);
@@ -608,5 +608,5 @@ JoypadOSX::~JoypadOSX() {
IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE);
IOHIDManagerClose(hid_manager, kIOHIDOptionsTypeNone);
CFRelease(hid_manager);
- hid_manager = NULL;
+ hid_manager = nullptr;
}
diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h
index 2c076b3680..62027c6a30 100644
--- a/platform/osx/joypad_osx.h
+++ b/platform/osx/joypad_osx.h
@@ -40,7 +40,7 @@
#include <ForceFeedback/ForceFeedbackConstants.h>
#include <IOKit/hid/IOHIDLib.h>
-#include "main/input_default.h"
+#include "core/input/input_filter.h"
struct rec_element {
IOHIDElementRef ref;
@@ -94,7 +94,7 @@ class JoypadOSX {
};
private:
- InputDefault *input;
+ InputFilter *input;
IOHIDManagerRef hid_manager;
Vector<joypad> device_list;
@@ -118,7 +118,7 @@ public:
void _device_added(IOReturn p_res, IOHIDDeviceRef p_device);
void _device_removed(IOReturn p_res, IOHIDDeviceRef p_device);
- JoypadOSX();
+ JoypadOSX(InputFilter *in);
~JoypadOSX();
};
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 3140d9bac4..d2c67cff9f 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -31,57 +31,20 @@
#ifndef OS_OSX_H
#define OS_OSX_H
-#define BitMap _QDBitMap // Suppress deprecated QuickDraw definition.
-
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "crash_handler_osx.h"
#include "drivers/coreaudio/audio_driver_coreaudio.h"
#include "drivers/coremidi/midi_driver_coremidi.h"
#include "drivers/unix/os_unix.h"
#include "joypad_osx.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual/visual_server_wrap_mt.h"
-#include "servers/visual_server.h"
-
-#if defined(OPENGL_ENABLED)
-#include "context_gl_osx.h"
-#endif
-
-#if defined(VULKAN_ENABLED)
-#include "drivers/vulkan/rendering_device_vulkan.h"
-#include "platform/osx/vulkan_context_osx.h"
-#endif
-
-#include <AppKit/AppKit.h>
-#include <AppKit/NSCursor.h>
-#include <ApplicationServices/ApplicationServices.h>
-#include <CoreVideo/CoreVideo.h>
-
-#undef BitMap
-#undef CursorShape
class OS_OSX : public OS_Unix {
-public:
- struct KeyEvent {
- unsigned int osx_state;
- bool pressed;
- bool echo;
- bool raw;
- uint32_t keycode;
- uint32_t physical_keycode;
- uint32_t unicode;
- };
-
- Vector<KeyEvent> key_event_buffer;
- int key_event_pos;
+ virtual void delete_main_loop();
bool force_quit;
- VisualServer *visual_server;
- List<String> args;
- MainLoop *main_loop;
+ JoypadOSX *joypad_osx;
#ifdef COREAUDIO_ENABLED
AudioDriverCoreAudio audio_driver;
@@ -90,143 +53,27 @@ public:
MIDIDriverCoreMidi midi_driver;
#endif
- InputDefault *input;
- JoypadOSX *joypad_osx;
-
- /* objc */
-
- CGEventSourceRef eventSource;
-
- void process_events();
- void process_key_events();
-
- // pthread_key_t current;
- bool mouse_grab;
- Point2 mouse_pos;
-
- id delegate;
- id window_delegate;
- id window_object;
- id window_view;
- id autoreleasePool;
- id cursor;
-
-#if defined(OPENGL_ENABLED)
- ContextGL_OSX *context_gles2;
-#endif
-
-#if defined(VULKAN_ENABLED)
- VulkanContextOSX *context_vulkan;
- RenderingDeviceVulkan *rendering_device_vulkan;
-#endif
-
- bool layered_window;
-
- CursorShape cursor_shape;
- NSCursor *cursors[CURSOR_MAX];
- Map<CursorShape, Vector<Variant> > cursors_cache;
- MouseMode mouse_mode;
-
- String title;
- bool minimized;
- bool maximized;
- bool zoomed;
- bool resizable;
- bool window_focused;
-
- Size2 window_size;
- Rect2 restore_rect;
-
- String open_with_filename;
-
- Point2 im_position;
- bool im_active;
- String im_text;
- Point2 im_selection;
-
- Size2 min_size;
- Size2 max_size;
-
CrashHandler crash_handler;
- float _mouse_scale(float p_scale) {
- if (_display_scale() > 1.0)
- return p_scale;
- else
- return 1.0;
- }
-
- float _display_scale() const;
- float _display_scale(id screen) const;
-
- void _update_window();
-
- int video_driver_index;
- virtual int get_current_video_driver() const;
-
- struct GlobalMenuItem {
- String label;
- Variant signal;
- Variant meta;
-
- GlobalMenuItem() {
- //NOP
- }
-
- GlobalMenuItem(const String &p_label, const Variant &p_signal, const Variant &p_meta) {
- label = p_label;
- signal = p_signal;
- meta = p_meta;
- }
- };
-
- Map<String, Vector<GlobalMenuItem> > global_menus;
+ MainLoop *main_loop;
- void _update_global_menu();
+public:
+ String open_with_filename;
protected:
virtual void initialize_core();
- virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
+ virtual void initialize();
virtual void finalize();
+ virtual void initialize_joypads();
+
virtual void set_main_loop(MainLoop *p_main_loop);
- virtual void delete_main_loop();
public:
- static OS_OSX *singleton;
-
- void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta);
- void global_menu_add_separator(const String &p_menu);
- void global_menu_remove_item(const String &p_menu, int p_idx);
- void global_menu_clear(const String &p_menu);
-
- void wm_minimized(bool p_minimized);
-
virtual String get_name() const;
- virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
-
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
- virtual void set_cursor_shape(CursorShape p_shape);
- virtual CursorShape get_cursor_shape() const;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
-
- virtual void set_mouse_show(bool p_show);
- virtual void set_mouse_grab(bool p_grab);
- virtual bool is_mouse_grab_enabled() const;
- virtual void warp_mouse_position(const Point2 &p_to);
- virtual Point2 get_mouse_position() const;
- virtual int get_mouse_button_state() const;
- void update_real_mouse_position();
- virtual void set_window_title(const String &p_title);
-
- virtual Size2 get_window_size() const;
- virtual Size2 get_real_window_size() const;
-
- virtual void set_native_icon(const String &p_filename);
- virtual void set_icon(const Ref<Image> &p_icon);
-
virtual MainLoop *get_main_loop() const;
virtual String get_config_path() const;
@@ -237,95 +84,24 @@ public:
virtual String get_system_dir(SystemDir p_dir) const;
- virtual bool can_draw() const;
-
- virtual void set_clipboard(const String &p_text);
- virtual String get_clipboard() const;
-
- virtual void release_rendering_thread();
- virtual void make_rendering_thread();
- virtual void swap_buffers();
-
Error shell_open(String p_uri);
- void push_input(const Ref<InputEvent> &p_event);
String get_locale() const;
- virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
- virtual VideoMode get_video_mode(int p_screen = 0) const;
- virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
-
virtual String get_executable_path() const;
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
-
- virtual void move_window_to_foreground();
-
- virtual int get_screen_count() const;
- virtual int get_current_screen() const;
- virtual void set_current_screen(int p_screen);
- virtual Point2 get_screen_position(int p_screen = -1) const;
- virtual Size2 get_screen_size(int p_screen = -1) const;
- virtual int get_screen_dpi(int p_screen = -1) const;
-
- virtual Point2 get_window_position() const;
- virtual void set_window_position(const Point2 &p_position);
- virtual Size2 get_max_window_size() const;
- virtual Size2 get_min_window_size() const;
- virtual void set_min_window_size(const Size2 p_size);
- virtual void set_max_window_size(const Size2 p_size);
- virtual void set_window_size(const Size2 p_size);
- virtual void set_window_fullscreen(bool p_enabled);
- virtual bool is_window_fullscreen() const;
- virtual void set_window_resizable(bool p_enabled);
- virtual bool is_window_resizable() const;
- virtual void set_window_minimized(bool p_enabled);
- virtual bool is_window_minimized() const;
- virtual void set_window_maximized(bool p_enabled);
- virtual bool is_window_maximized() const;
- virtual void set_window_always_on_top(bool p_enabled);
- virtual bool is_window_always_on_top() const;
- virtual bool is_window_focused() const;
- virtual void request_attention();
- virtual String get_joy_guid(int p_device) const;
-
- virtual void set_borderless_window(bool p_borderless);
- virtual bool get_borderless_window();
-
- virtual bool get_window_per_pixel_transparency_enabled() const;
- virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
-
- virtual void set_ime_active(const bool p_active);
- virtual void set_ime_position(const Point2 &p_pos);
- virtual Point2 get_ime_selection() const;
- virtual String get_ime_text() const;
-
- virtual String get_unique_id() const;
+ virtual String get_unique_id() const; //++
virtual bool _check_internal_feature_support(const String &p_feature);
- virtual void _set_use_vsync(bool p_enable);
- //virtual bool is_vsync_enabled() const;
-
void run();
- void set_mouse_mode(MouseMode p_mode);
- MouseMode get_mouse_mode() const;
-
void disable_crash_handler();
bool is_disable_crash_handler() const;
virtual Error move_to_trash(const String &p_path);
- void force_process_input();
-
OS_OSX();
-
-private:
- Point2 get_native_screen_position(int p_screen) const;
- Point2 get_native_window_position() const;
- void set_native_window_position(const Point2 &p_position);
- Point2 get_screens_origin() const;
};
#endif
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 4c70beee00..49cb056c9f 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -30,1668 +30,21 @@
#include "os_osx.h"
-#include "core/os/keyboard.h"
-#include "core/print_string.h"
#include "core/version_generated.gen.h"
-#include "dir_access_osx.h"
-
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
-
-#if defined(VULKAN_ENABLED)
-#include "servers/visual/rasterizer_rd/rasterizer_rd.h"
-#endif
+#include "dir_access_osx.h"
+#include "display_server_osx.h"
#include "main/main.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
-
-#include <mach-o/dyld.h>
-
-#include <Carbon/Carbon.h>
-#import <Cocoa/Cocoa.h>
-#include <IOKit/IOCFPlugIn.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/hid/IOHIDKeys.h>
-#include <IOKit/hid/IOHIDLib.h>
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
-#include <os/log.h>
-#endif
-
-#import <QuartzCore/CAMetalLayer.h>
-#include <vulkan/vulkan_metal.h>
#include <dlfcn.h>
-#include <fcntl.h>
#include <libproc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
-#define NSEventMaskAny NSAnyEventMask
-#define NSEventTypeKeyDown NSKeyDown
-#define NSEventTypeKeyUp NSKeyUp
-#define NSEventModifierFlagShift NSShiftKeyMask
-#define NSEventModifierFlagCommand NSCommandKeyMask
-#define NSEventModifierFlagControl NSControlKeyMask
-#define NSEventModifierFlagOption NSAlternateKeyMask
-#define NSWindowStyleMaskTitled NSTitledWindowMask
-#define NSWindowStyleMaskResizable NSResizableWindowMask
-#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
-#define NSWindowStyleMaskClosable NSClosableWindowMask
-#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
-#endif
-
-#ifndef NSAppKitVersionNumber10_12
-#define NSAppKitVersionNumber10_12 1504
-#endif
-#ifndef NSAppKitVersionNumber10_14
-#define NSAppKitVersionNumber10_14 1671
-#endif
-
-static void get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> state) {
-
- state->set_shift((p_osx_state & NSEventModifierFlagShift));
- state->set_control((p_osx_state & NSEventModifierFlagControl));
- state->set_alt((p_osx_state & NSEventModifierFlagOption));
- state->set_metakey((p_osx_state & NSEventModifierFlagCommand));
-}
-
-static void push_to_key_event_buffer(const OS_OSX::KeyEvent &p_event) {
-
- Vector<OS_OSX::KeyEvent> &buffer = OS_OSX::singleton->key_event_buffer;
- if (OS_OSX::singleton->key_event_pos >= buffer.size()) {
- buffer.resize(1 + OS_OSX::singleton->key_event_pos);
- }
- buffer.write[OS_OSX::singleton->key_event_pos++] = p_event;
-}
-
-static int mouse_x = 0;
-static int mouse_y = 0;
-static int button_mask = 0;
-static bool mouse_down_control = false;
-
-static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFactor) {
-
- const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- const NSPoint p = locationInWindow;
- const float s = OS_OSX::singleton->_mouse_scale(backingScaleFactor);
- mouse_x = p.x * s;
- mouse_y = (contentRect.size.height - p.y) * s;
- return Vector2(mouse_x, mouse_y);
-}
-
-static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) {
- if ([NSCursor respondsToSelector:selector]) {
- id object = [NSCursor performSelector:selector];
- if ([object isKindOfClass:[NSCursor class]]) {
- return object;
- }
- }
- if (fallback) {
- // Fallback should be a reasonable default, no need to check.
- return [NSCursor performSelector:fallback];
- }
- return [NSCursor arrowCursor];
-}
-
-@interface GodotApplication : NSApplication
-@end
-
-@implementation GodotApplication
-
-- (void)sendEvent:(NSEvent *)event {
-
- // special case handling of command-period, which is traditionally a special
- // shortcut in macOS and doesn't arrive at our regular keyDown handler.
- if ([event type] == NSEventTypeKeyDown) {
- if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) {
-
- Ref<InputEventKey> k;
- k.instance();
-
- get_key_modifier_state([event modifierFlags], k);
- k->set_pressed(true);
- k->set_keycode(KEY_PERIOD);
- k->set_physical_keycode(KEY_PERIOD);
- k->set_echo([event isARepeat]);
-
- OS_OSX::singleton->push_input(k);
- }
- }
-
- // From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
- // This works around an AppKit bug, where key up events while holding
- // down the command key don't get sent to the key window.
- if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand))
- [[self keyWindow] sendEvent:event];
- else
- [super sendEvent:event];
-}
-
-@end
-
-@interface GodotApplicationDelegate : NSObject
-- (void)forceUnbundledWindowActivationHackStep1;
-- (void)forceUnbundledWindowActivationHackStep2;
-- (void)forceUnbundledWindowActivationHackStep3;
-@end
-
-@implementation GodotApplicationDelegate
-
-- (void)forceUnbundledWindowActivationHackStep1 {
- // Step1: Switch focus to macOS Dock.
- // Required to perform step 2, TransformProcessType will fail if app is already the in focus.
- for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
- [app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
- break;
- }
- [self performSelector:@selector(forceUnbundledWindowActivationHackStep2) withObject:nil afterDelay:0.02];
-}
-
-- (void)forceUnbundledWindowActivationHackStep2 {
- // Step 2: Register app as foreground process.
- ProcessSerialNumber psn = { 0, kCurrentProcess };
- (void)TransformProcessType(&psn, kProcessTransformToForegroundApplication);
-
- [self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02];
-}
-
-- (void)forceUnbundledWindowActivationHackStep3 {
- // Step 3: Switch focus back to app window.
- [[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
-}
-
-- (void)applicationDidFinishLaunching:(NSNotification *)notice {
- NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
- if (nsappname == nil) {
- // If executable is not a bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
- [self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
- }
-}
-
-- (void)globalMenuCallback:(id)sender {
-
- if (![sender representedObject])
- return;
-
- OS_OSX::GlobalMenuItem *item = (OS_OSX::GlobalMenuItem *)[[sender representedObject] pointerValue];
-
- if (!item)
- return;
-
- OS_OSX::singleton->main_loop->global_menu_action(item->signal, item->meta);
-}
-
-- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
-
- NSMenu *menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
-
- Vector<OS_OSX::GlobalMenuItem> &E = OS_OSX::singleton->global_menus["_dock"];
- for (int i = 0; i < E.size(); i++) {
- if (E[i].label == String()) {
- [menu addItem:[NSMenuItem separatorItem]];
- } else {
- NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:E[i].label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
- [menu_item setRepresentedObject:[NSValue valueWithPointer:&(E[i])]];
- }
- }
-
- return menu;
-}
-
-- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
- // Note: may be called called before main loop init!
- char *utfs = strdup([filename UTF8String]);
- OS_OSX::singleton->open_with_filename.parse_utf8(utfs);
- free(utfs);
-
-#ifdef TOOLS_ENABLED
- // Open new instance
- if (OS_OSX::singleton->get_main_loop()) {
- List<String> args;
- args.push_back(OS_OSX::singleton->open_with_filename);
- String exec = OS::get_singleton()->get_executable_path();
-
- OS::ProcessID pid = 0;
- OS::get_singleton()->execute(exec, args, false, &pid);
- }
-#endif
- return YES;
-}
-
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
-
- return NSTerminateCancel;
-}
-
-- (void)showAbout:(id)sender {
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT);
-}
-
-@end
-
-@interface GodotWindowDelegate : NSObject {
- //_Godotwindow* window;
-}
-
-- (void)windowWillClose:(NSNotification *)notification;
-
-@end
-
-@implementation GodotWindowDelegate
-
-- (BOOL)windowShouldClose:(id)sender {
- //_GodotInputWindowCloseRequest(window);
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
-
- return NO;
-}
-
-- (void)windowWillClose:(NSNotification *)notification {
-#if defined(VULKAN_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_VULKAN) {
-
- if (OS_OSX::singleton->rendering_device_vulkan) {
- OS_OSX::singleton->rendering_device_vulkan->finalize();
- memdelete(OS_OSX::singleton->rendering_device_vulkan);
- OS_OSX::singleton->rendering_device_vulkan = NULL;
- }
-
- if (OS_OSX::singleton->context_vulkan) {
- memdelete(OS_OSX::singleton->context_vulkan);
- OS_OSX::singleton->context_vulkan = NULL;
- }
- }
-#endif
-}
-
-- (void)windowDidEnterFullScreen:(NSNotification *)notification {
- OS_OSX::singleton->zoomed = true;
-
- [OS_OSX::singleton->window_object setContentMinSize:NSMakeSize(0, 0)];
- [OS_OSX::singleton->window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
-}
-
-- (void)windowDidExitFullScreen:(NSNotification *)notification {
- OS_OSX::singleton->zoomed = false;
-
- if (OS_OSX::singleton->min_size != Size2()) {
- Size2 size = OS_OSX::singleton->min_size / OS_OSX::singleton->_display_scale();
- [OS_OSX::singleton->window_object setContentMinSize:NSMakeSize(size.x, size.y)];
- }
- if (OS_OSX::singleton->max_size != Size2()) {
- Size2 size = OS_OSX::singleton->max_size / OS_OSX::singleton->_display_scale();
- [OS_OSX::singleton->window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
- }
-
- if (!OS_OSX::singleton->resizable)
- [OS_OSX::singleton->window_object setStyleMask:[OS_OSX::singleton->window_object styleMask] & ~NSWindowStyleMaskResizable];
-}
-
-- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
- if (!OS_OSX::singleton)
- return;
-
- NSWindow *window = (NSWindow *)[notification object];
- CGFloat newBackingScaleFactor = [window backingScaleFactor];
- CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
-
-#if defined(OPENGL_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_GLES2) {
- if (OS_OSX::singleton->is_hidpi_allowed()) {
- [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES];
- } else {
- [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:NO];
- }
- }
-#endif
-
- if (newBackingScaleFactor != oldBackingScaleFactor) {
- //Set new display scale and window size
- float newDisplayScale = OS_OSX::singleton->is_hidpi_allowed() ? newBackingScaleFactor : 1.0;
-
- const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- const NSRect fbRect = contentRect;
-
- OS_OSX::singleton->window_size.width = fbRect.size.width * newDisplayScale;
- OS_OSX::singleton->window_size.height = fbRect.size.height * newDisplayScale;
-
-#if defined(VULKAN_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_VULKAN) {
- CALayer *layer = [OS_OSX::singleton->window_view layer];
- layer.contentsScale = OS_OSX::singleton->_display_scale();
- }
-#endif
- //Update context
- if (OS_OSX::singleton->main_loop) {
- //Force window resize event
- [self windowDidResize:notification];
- }
- }
-}
-
-- (void)windowDidResize:(NSNotification *)notification {
-
-#if defined(OPENGL_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_GLES2) {
- OS_OSX::singleton->context_gles2->update();
- }
-#endif
- const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- const NSRect fbRect = contentRect;
-
- float displayScale = OS_OSX::singleton->_display_scale();
- OS_OSX::singleton->window_size.width = fbRect.size.width * displayScale;
- OS_OSX::singleton->window_size.height = fbRect.size.height * displayScale;
-
-#if defined(VULKAN_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_VULKAN) {
- CALayer *layer = [OS_OSX::singleton->window_view layer];
- layer.contentsScale = OS_OSX::singleton->_display_scale();
- OS_OSX::singleton->context_vulkan->window_resize(0, OS_OSX::singleton->window_size.width, OS_OSX::singleton->window_size.height);
- }
-#endif
-
- if (OS_OSX::singleton->main_loop) {
- Main::force_redraw();
- //Event retrieval blocks until resize is over. Call Main::iteration() directly.
- if (!Main::is_iterating()) { //avoid cyclic loop
- Main::iteration();
- }
- }
-}
-
-- (void)windowDidMove:(NSNotification *)notification {
-
- if (OS_OSX::singleton->get_main_loop()) {
- OS_OSX::singleton->input->release_pressed_events();
- }
-}
-
-- (void)windowDidBecomeKey:(NSNotification *)notification {
- if (OS_OSX::singleton->get_main_loop()) {
- get_mouse_pos(
- [OS_OSX::singleton->window_object mouseLocationOutsideOfEventStream],
- [OS_OSX::singleton->window_view backingScaleFactor]);
- OS_OSX::singleton->input->set_mouse_position(Point2(mouse_x, mouse_y));
-
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
- }
-
- OS_OSX::singleton->window_focused = true;
-}
-
-- (void)windowDidResignKey:(NSNotification *)notification {
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
-
- OS_OSX::singleton->window_focused = false;
-}
-
-- (void)windowDidMiniaturize:(NSNotification *)notification {
- OS_OSX::singleton->wm_minimized(true);
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
-
- OS_OSX::singleton->window_focused = false;
-};
-
-- (void)windowDidDeminiaturize:(NSNotification *)notification {
- OS_OSX::singleton->wm_minimized(false);
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
-
- OS_OSX::singleton->window_focused = true;
-};
-
-@end
-
-@interface GodotContentView : NSView <NSTextInputClient> {
- NSTrackingArea *trackingArea;
- NSMutableAttributedString *markedText;
- bool imeInputEventInProgress;
-}
-- (void)cancelComposition;
-
-- (CALayer *)makeBackingLayer;
-
-- (BOOL)wantsUpdateLayer;
-- (void)updateLayer;
-
-@end
-
-@implementation GodotContentView
-
-+ (void)initialize {
- if (self == [GodotContentView class]) {
- // nothing left to do here at the moment..
- }
-}
-
-- (CALayer *)makeBackingLayer {
-#if defined(VULKAN_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_VULKAN) {
- CALayer *layer = [[CAMetalLayer class] layer];
- layer.contentsScale = OS_OSX::singleton->_display_scale();
- return layer;
- }
-#endif
- return [super makeBackingLayer];
-}
-
-- (void)updateLayer {
-#if defined(VULKAN_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_VULKAN) {
- [super updateLayer];
- }
-#endif
-#if defined(OPENGL_ENABLED)
- if (OS_OSX::singleton->video_driver_index == OS::VIDEO_DRIVER_GLES2) {
- OS_OSX::singleton->context_gles2->update();
- }
-#endif
-}
-
-- (BOOL)wantsUpdateLayer {
- return YES;
-}
-
-- (id)init {
- self = [super init];
- trackingArea = nil;
- imeInputEventInProgress = false;
- [self updateTrackingAreas];
- [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
- markedText = [[NSMutableAttributedString alloc] init];
- return self;
-}
-
-- (void)dealloc {
- [trackingArea release];
- [markedText release];
- [super dealloc];
-}
-
-static const NSRange kEmptyRange = { NSNotFound, 0 };
-
-- (BOOL)hasMarkedText {
- return (markedText.length > 0);
-}
-
-- (NSRange)markedRange {
- return NSMakeRange(0, markedText.length);
-}
-
-- (NSRange)selectedRange {
- return kEmptyRange;
-}
-
-- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
- if ([aString isKindOfClass:[NSAttributedString class]]) {
- [markedText initWithAttributedString:aString];
- } else {
- [markedText initWithString:aString];
- }
- if (markedText.length == 0) {
- [self unmarkText];
- return;
- }
- if (OS_OSX::singleton->im_active) {
- imeInputEventInProgress = true;
- OS_OSX::singleton->im_text.parse_utf8([[markedText mutableString] UTF8String]);
- OS_OSX::singleton->im_selection = Point2(selectedRange.location, selectedRange.length);
-
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
- }
-}
-
-- (void)doCommandBySelector:(SEL)aSelector {
- if ([self respondsToSelector:aSelector])
- [self performSelector:aSelector];
-}
-
-- (void)unmarkText {
- imeInputEventInProgress = false;
- [[markedText mutableString] setString:@""];
- if (OS_OSX::singleton->im_active) {
- OS_OSX::singleton->im_text = String();
- OS_OSX::singleton->im_selection = Point2();
-
- if (OS_OSX::singleton->get_main_loop())
- OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
- }
-}
-
-- (NSArray *)validAttributesForMarkedText {
- return [NSArray array];
-}
-
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
- return nil;
-}
-
-- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
- return 0;
-}
-
-- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
- const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- float displayScale = OS_OSX::singleton->_display_scale();
- NSRect pointInWindowRect = NSMakeRect(OS_OSX::singleton->im_position.x / displayScale, contentRect.size.height - (OS_OSX::singleton->im_position.y / displayScale) - 1, 0, 0);
- NSPoint pointOnScreen = [[OS_OSX::singleton->window_view window] convertRectToScreen:pointInWindowRect].origin;
-
- return NSMakeRect(pointOnScreen.x, pointOnScreen.y, 0, 0);
-}
-
-- (void)cancelComposition {
- [self unmarkText];
- NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext];
- [currentInputContext discardMarkedText];
-}
-
-- (void)insertText:(id)aString {
- [self insertText:aString replacementRange:NSMakeRange(0, 0)];
-}
-
-- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
- NSEvent *event = [NSApp currentEvent];
-
- NSString *characters;
- if ([aString isKindOfClass:[NSAttributedString class]]) {
- characters = [aString string];
- } else {
- characters = (NSString *)aString;
- }
-
- NSUInteger i, length = [characters length];
-
- NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
- NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
- if ([characters rangeOfCharacterFromSet:ctrlChars].length && [characters rangeOfCharacterFromSet:wsnlChars].length == 0) {
- NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext];
- [currentInputContext discardMarkedText];
- [self cancelComposition];
- return;
- }
-
- for (i = 0; i < length; i++) {
- const unichar codepoint = [characters characterAtIndex:i];
- if ((codepoint & 0xFF00) == 0xF700)
- continue;
-
- OS_OSX::KeyEvent ke;
-
- ke.osx_state = [event modifierFlags];
- ke.pressed = true;
- ke.echo = false;
- ke.raw = false; // IME input event
- ke.keycode = 0;
- ke.physical_keycode = 0;
- ke.unicode = codepoint;
-
- push_to_key_event_buffer(ke);
- }
- [self cancelComposition];
-}
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
- return NSDragOperationCopy;
-}
-
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
- return NSDragOperationCopy;
-}
-
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
-
- NSPasteboard *pboard = [sender draggingPasteboard];
- NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
-
- Vector<String> files;
- for (NSUInteger i = 0; i < filenames.count; i++) {
- NSString *ns = [filenames objectAtIndex:i];
- char *utfs = strdup([ns UTF8String]);
- String ret;
- ret.parse_utf8(utfs);
- free(utfs);
- files.push_back(ret);
- }
-
- if (files.size()) {
- OS_OSX::singleton->main_loop->drop_files(files, 0);
- OS_OSX::singleton->move_window_to_foreground();
- }
-
- return NO;
-}
-
-- (BOOL)isOpaque {
- return YES;
-}
-
-- (BOOL)canBecomeKeyView {
- return YES;
-}
-
-- (BOOL)acceptsFirstResponder {
- return YES;
-}
-
-- (void)cursorUpdate:(NSEvent *)event {
- OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape;
- OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
- OS_OSX::singleton->set_cursor_shape(p_shape);
-}
-
-static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
- if (pressed) {
- button_mask |= mask;
- } else {
- button_mask &= ~mask;
- }
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
- const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
- const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
- get_key_modifier_state([event modifierFlags], mb);
- mb->set_button_index(index);
- mb->set_pressed(pressed);
- mb->set_position(pos);
- mb->set_global_position(pos);
- mb->set_button_mask(button_mask);
- if (index == BUTTON_LEFT && pressed) {
- mb->set_doubleclick([event clickCount] == 2);
- }
- OS_OSX::singleton->push_input(mb);
-}
-
-- (void)mouseDown:(NSEvent *)event {
- if (([event modifierFlags] & NSEventModifierFlagControl)) {
- mouse_down_control = true;
- _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
- } else {
- mouse_down_control = false;
- _mouseDownEvent(event, BUTTON_LEFT, BUTTON_MASK_LEFT, true);
- }
-}
-
-- (void)mouseDragged:(NSEvent *)event {
- [self mouseMoved:event];
-}
-
-- (void)mouseUp:(NSEvent *)event {
- if (mouse_down_control) {
- _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
- } else {
- _mouseDownEvent(event, BUTTON_LEFT, BUTTON_MASK_LEFT, false);
- }
-}
-
-- (void)mouseMoved:(NSEvent *)event {
-
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- mm->set_button_mask(button_mask);
- const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
- const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
- mm->set_position(pos);
- mm->set_pressure([event pressure]);
- if ([event subtype] == NSEventSubtypeTabletPoint) {
- const NSPoint p = [event tilt];
- mm->set_tilt(Vector2(p.x, p.y));
- }
- mm->set_global_position(pos);
- mm->set_speed(OS_OSX::singleton->input->get_last_mouse_speed());
- Vector2 relativeMotion = Vector2();
- relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor);
- relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor);
- mm->set_relative(relativeMotion);
- get_key_modifier_state([event modifierFlags], mm);
-
- OS_OSX::singleton->input->set_mouse_position(Point2(mouse_x, mouse_y));
- OS_OSX::singleton->push_input(mm);
-}
-
-- (void)rightMouseDown:(NSEvent *)event {
- _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
-}
-
-- (void)rightMouseDragged:(NSEvent *)event {
- [self mouseMoved:event];
-}
-
-- (void)rightMouseUp:(NSEvent *)event {
- _mouseDownEvent(event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
-}
-
-- (void)otherMouseDown:(NSEvent *)event {
-
- if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true);
-
- } else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, true);
-
- } else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, true);
-
- } else {
- return;
- }
-}
-
-- (void)otherMouseDragged:(NSEvent *)event {
- [self mouseMoved:event];
-}
-
-- (void)otherMouseUp:(NSEvent *)event {
-
- if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false);
-
- } else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, false);
-
- } else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, false);
-
- } else {
- return;
- }
-}
-
-- (void)mouseExited:(NSEvent *)event {
- if (!OS_OSX::singleton)
- return;
-
- if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
- OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
-}
-
-- (void)mouseEntered:(NSEvent *)event {
- if (!OS_OSX::singleton)
- return;
- if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
- OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
-
- OS::CursorShape p_shape = OS_OSX::singleton->cursor_shape;
- OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
- OS_OSX::singleton->set_cursor_shape(p_shape);
-}
-
-- (void)magnifyWithEvent:(NSEvent *)event {
- Ref<InputEventMagnifyGesture> ev;
- ev.instance();
- get_key_modifier_state([event modifierFlags], ev);
- ev->set_position(get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]));
- ev->set_factor([event magnification] + 1.0);
- OS_OSX::singleton->push_input(ev);
-}
-
-- (void)viewDidChangeBackingProperties {
- // nothing left to do here
-}
-
-- (void)updateTrackingAreas {
- if (trackingArea != nil) {
- [self removeTrackingArea:trackingArea];
- [trackingArea release];
- }
-
- NSTrackingAreaOptions options =
- NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInKeyWindow |
- NSTrackingCursorUpdate |
- NSTrackingInVisibleRect;
-
- trackingArea = [[NSTrackingArea alloc]
- initWithRect:[self bounds]
- options:options
- owner:self
- userInfo:nil];
-
- [self addTrackingArea:trackingArea];
- [super updateTrackingAreas];
-}
-
-static bool isNumpadKey(unsigned int key) {
-
- static const unsigned int table[] = {
- 0x41, /* kVK_ANSI_KeypadDecimal */
- 0x43, /* kVK_ANSI_KeypadMultiply */
- 0x45, /* kVK_ANSI_KeypadPlus */
- 0x47, /* kVK_ANSI_KeypadClear */
- 0x4b, /* kVK_ANSI_KeypadDivide */
- 0x4c, /* kVK_ANSI_KeypadEnter */
- 0x4e, /* kVK_ANSI_KeypadMinus */
- 0x51, /* kVK_ANSI_KeypadEquals */
- 0x52, /* kVK_ANSI_Keypad0 */
- 0x53, /* kVK_ANSI_Keypad1 */
- 0x54, /* kVK_ANSI_Keypad2 */
- 0x55, /* kVK_ANSI_Keypad3 */
- 0x56, /* kVK_ANSI_Keypad4 */
- 0x57, /* kVK_ANSI_Keypad5 */
- 0x58, /* kVK_ANSI_Keypad6 */
- 0x59, /* kVK_ANSI_Keypad7 */
- 0x5b, /* kVK_ANSI_Keypad8 */
- 0x5c, /* kVK_ANSI_Keypad9 */
- 0x5f, /* kVK_JIS_KeypadComma */
- 0x00
- };
- for (int i = 0; table[i] != 0; i++) {
- if (key == table[i])
- return true;
- }
- return false;
-}
-
-// Translates a OS X keycode to a Godot keycode
-//
-static int translateKey(unsigned int key) {
-
- // Keyboard symbol translation table
- static const unsigned int table[128] = {
- /* 00 */ KEY_A,
- /* 01 */ KEY_S,
- /* 02 */ KEY_D,
- /* 03 */ KEY_F,
- /* 04 */ KEY_H,
- /* 05 */ KEY_G,
- /* 06 */ KEY_Z,
- /* 07 */ KEY_X,
- /* 08 */ KEY_C,
- /* 09 */ KEY_V,
- /* 0a */ KEY_SECTION, /* ISO Section */
- /* 0b */ KEY_B,
- /* 0c */ KEY_Q,
- /* 0d */ KEY_W,
- /* 0e */ KEY_E,
- /* 0f */ KEY_R,
- /* 10 */ KEY_Y,
- /* 11 */ KEY_T,
- /* 12 */ KEY_1,
- /* 13 */ KEY_2,
- /* 14 */ KEY_3,
- /* 15 */ KEY_4,
- /* 16 */ KEY_6,
- /* 17 */ KEY_5,
- /* 18 */ KEY_EQUAL,
- /* 19 */ KEY_9,
- /* 1a */ KEY_7,
- /* 1b */ KEY_MINUS,
- /* 1c */ KEY_8,
- /* 1d */ KEY_0,
- /* 1e */ KEY_BRACERIGHT,
- /* 1f */ KEY_O,
- /* 20 */ KEY_U,
- /* 21 */ KEY_BRACELEFT,
- /* 22 */ KEY_I,
- /* 23 */ KEY_P,
- /* 24 */ KEY_ENTER,
- /* 25 */ KEY_L,
- /* 26 */ KEY_J,
- /* 27 */ KEY_APOSTROPHE,
- /* 28 */ KEY_K,
- /* 29 */ KEY_SEMICOLON,
- /* 2a */ KEY_BACKSLASH,
- /* 2b */ KEY_COMMA,
- /* 2c */ KEY_SLASH,
- /* 2d */ KEY_N,
- /* 2e */ KEY_M,
- /* 2f */ KEY_PERIOD,
- /* 30 */ KEY_TAB,
- /* 31 */ KEY_SPACE,
- /* 32 */ KEY_QUOTELEFT,
- /* 33 */ KEY_BACKSPACE,
- /* 34 */ KEY_UNKNOWN,
- /* 35 */ KEY_ESCAPE,
- /* 36 */ KEY_META,
- /* 37 */ KEY_META,
- /* 38 */ KEY_SHIFT,
- /* 39 */ KEY_CAPSLOCK,
- /* 3a */ KEY_ALT,
- /* 3b */ KEY_CONTROL,
- /* 3c */ KEY_SHIFT,
- /* 3d */ KEY_ALT,
- /* 3e */ KEY_CONTROL,
- /* 3f */ KEY_UNKNOWN, /* Function */
- /* 40 */ KEY_UNKNOWN, /* F17 */
- /* 41 */ KEY_KP_PERIOD,
- /* 42 */ KEY_UNKNOWN,
- /* 43 */ KEY_KP_MULTIPLY,
- /* 44 */ KEY_UNKNOWN,
- /* 45 */ KEY_KP_ADD,
- /* 46 */ KEY_UNKNOWN,
- /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
- /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
- /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
- /* 4a */ KEY_VOLUMEMUTE, /* Mute */
- /* 4b */ KEY_KP_DIVIDE,
- /* 4c */ KEY_KP_ENTER,
- /* 4d */ KEY_UNKNOWN,
- /* 4e */ KEY_KP_SUBTRACT,
- /* 4f */ KEY_UNKNOWN, /* F18 */
- /* 50 */ KEY_UNKNOWN, /* F19 */
- /* 51 */ KEY_EQUAL, /* KeypadEqual */
- /* 52 */ KEY_KP_0,
- /* 53 */ KEY_KP_1,
- /* 54 */ KEY_KP_2,
- /* 55 */ KEY_KP_3,
- /* 56 */ KEY_KP_4,
- /* 57 */ KEY_KP_5,
- /* 58 */ KEY_KP_6,
- /* 59 */ KEY_KP_7,
- /* 5a */ KEY_UNKNOWN, /* F20 */
- /* 5b */ KEY_KP_8,
- /* 5c */ KEY_KP_9,
- /* 5d */ KEY_YEN, /* JIS Yen */
- /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
- /* 5f */ KEY_COMMA, /* JIS KeypadComma */
- /* 60 */ KEY_F5,
- /* 61 */ KEY_F6,
- /* 62 */ KEY_F7,
- /* 63 */ KEY_F3,
- /* 64 */ KEY_F8,
- /* 65 */ KEY_F9,
- /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
- /* 67 */ KEY_F11,
- /* 68 */ KEY_UNKNOWN, /* JIS Kana */
- /* 69 */ KEY_F13,
- /* 6a */ KEY_F16,
- /* 6b */ KEY_F14,
- /* 6c */ KEY_UNKNOWN,
- /* 6d */ KEY_F10,
- /* 6e */ KEY_MENU,
- /* 6f */ KEY_F12,
- /* 70 */ KEY_UNKNOWN,
- /* 71 */ KEY_F15,
- /* 72 */ KEY_INSERT, /* Really Help... */
- /* 73 */ KEY_HOME,
- /* 74 */ KEY_PAGEUP,
- /* 75 */ KEY_DELETE,
- /* 76 */ KEY_F4,
- /* 77 */ KEY_END,
- /* 78 */ KEY_F2,
- /* 79 */ KEY_PAGEDOWN,
- /* 7a */ KEY_F1,
- /* 7b */ KEY_LEFT,
- /* 7c */ KEY_RIGHT,
- /* 7d */ KEY_DOWN,
- /* 7e */ KEY_UP,
- /* 7f */ KEY_UNKNOWN,
- };
-
- if (key >= 128)
- return KEY_UNKNOWN;
-
- return table[key];
-}
-
-struct _KeyCodeMap {
- UniChar kchar;
- int kcode;
-};
-
-static const _KeyCodeMap _keycodes[55] = {
- { '`', KEY_QUOTELEFT },
- { '~', KEY_ASCIITILDE },
- { '0', KEY_0 },
- { '1', KEY_1 },
- { '2', KEY_2 },
- { '3', KEY_3 },
- { '4', KEY_4 },
- { '5', KEY_5 },
- { '6', KEY_6 },
- { '7', KEY_7 },
- { '8', KEY_8 },
- { '9', KEY_9 },
- { '-', KEY_MINUS },
- { '_', KEY_UNDERSCORE },
- { '=', KEY_EQUAL },
- { '+', KEY_PLUS },
- { 'q', KEY_Q },
- { 'w', KEY_W },
- { 'e', KEY_E },
- { 'r', KEY_R },
- { 't', KEY_T },
- { 'y', KEY_Y },
- { 'u', KEY_U },
- { 'i', KEY_I },
- { 'o', KEY_O },
- { 'p', KEY_P },
- { '[', KEY_BRACELEFT },
- { ']', KEY_BRACERIGHT },
- { '{', KEY_BRACELEFT },
- { '}', KEY_BRACERIGHT },
- { 'a', KEY_A },
- { 's', KEY_S },
- { 'd', KEY_D },
- { 'f', KEY_F },
- { 'g', KEY_G },
- { 'h', KEY_H },
- { 'j', KEY_J },
- { 'k', KEY_K },
- { 'l', KEY_L },
- { ';', KEY_SEMICOLON },
- { ':', KEY_COLON },
- { '\'', KEY_APOSTROPHE },
- { '\"', KEY_QUOTEDBL },
- { '\\', KEY_BACKSLASH },
- { '#', KEY_NUMBERSIGN },
- { 'z', KEY_Z },
- { 'x', KEY_X },
- { 'c', KEY_C },
- { 'v', KEY_V },
- { 'b', KEY_B },
- { 'n', KEY_N },
- { 'm', KEY_M },
- { ',', KEY_COMMA },
- { '.', KEY_PERIOD },
- { '/', KEY_SLASH }
-};
-
-static int remapKey(unsigned int key, unsigned int state) {
-
- if (isNumpadKey(key))
- return translateKey(key);
-
- TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
- if (!currentKeyboard)
- return translateKey(key);
-
- CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
- if (!layoutData)
- return translateKey(key);
-
- const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
-
- UInt32 keysDown = 0;
- UniChar chars[4];
- UniCharCount realLength;
-
- OSStatus err = UCKeyTranslate(keyboardLayout,
- key,
- kUCKeyActionDisplay,
- (state >> 8) & 0xFF,
- LMGetKbdType(),
- kUCKeyTranslateNoDeadKeysBit,
- &keysDown,
- sizeof(chars) / sizeof(chars[0]),
- &realLength,
- chars);
-
- if (err != noErr) {
- return translateKey(key);
- }
-
- for (unsigned int i = 0; i < 55; i++) {
- if (_keycodes[i].kchar == chars[0]) {
- return _keycodes[i].kcode;
- }
- }
- return translateKey(key);
-}
-
-- (void)keyDown:(NSEvent *)event {
-
- // Ignore all input if IME input is in progress
- if (!imeInputEventInProgress) {
- NSString *characters = [event characters];
- NSUInteger length = [characters length];
-
- if (!OS_OSX::singleton->im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
- // Fallback unicode character handler used if IME is not active
- for (NSUInteger i = 0; i < length; i++) {
- OS_OSX::KeyEvent ke;
-
- ke.osx_state = [event modifierFlags];
- ke.pressed = true;
- ke.echo = [event isARepeat];
- ke.keycode = remapKey([event keyCode], [event modifierFlags]);
- ke.physical_keycode = translateKey([event keyCode]);
- ke.raw = true;
- ke.unicode = [characters characterAtIndex:i];
-
- push_to_key_event_buffer(ke);
- }
- } else {
- OS_OSX::KeyEvent ke;
-
- ke.osx_state = [event modifierFlags];
- ke.pressed = true;
- ke.echo = [event isARepeat];
- ke.keycode = remapKey([event keyCode], [event modifierFlags]);
- ke.physical_keycode = translateKey([event keyCode]);
- ke.raw = false;
- ke.unicode = 0;
-
- push_to_key_event_buffer(ke);
- }
- }
-
- // Pass events to IME handler
- if (OS_OSX::singleton->im_active)
- [self interpretKeyEvents:[NSArray arrayWithObject:event]];
-}
-
-- (void)flagsChanged:(NSEvent *)event {
-
- // Ignore all input if IME input is in progress
- if (!imeInputEventInProgress) {
- OS_OSX::KeyEvent ke;
-
- ke.echo = false;
- ke.raw = true;
-
- int key = [event keyCode];
- int mod = [event modifierFlags];
-
- if (key == 0x36 || key == 0x37) {
- if (mod & NSEventModifierFlagCommand) {
- mod &= ~NSEventModifierFlagCommand;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else if (key == 0x38 || key == 0x3c) {
- if (mod & NSEventModifierFlagShift) {
- mod &= ~NSEventModifierFlagShift;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else if (key == 0x3a || key == 0x3d) {
- if (mod & NSEventModifierFlagOption) {
- mod &= ~NSEventModifierFlagOption;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else if (key == 0x3b || key == 0x3e) {
- if (mod & NSEventModifierFlagControl) {
- mod &= ~NSEventModifierFlagControl;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else {
- return;
- }
-
- ke.osx_state = mod;
- ke.keycode = remapKey(key, mod);
- ke.physical_keycode = translateKey(key);
- ke.unicode = 0;
-
- push_to_key_event_buffer(ke);
- }
-}
-
-- (void)keyUp:(NSEvent *)event {
-
- // Ignore all input if IME input is in progress
- if (!imeInputEventInProgress) {
- NSString *characters = [event characters];
- NSUInteger length = [characters length];
-
- // Fallback unicode character handler used if IME is not active
- if (!OS_OSX::singleton->im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
- for (NSUInteger i = 0; i < length; i++) {
- OS_OSX::KeyEvent ke;
-
- ke.osx_state = [event modifierFlags];
- ke.pressed = false;
- ke.echo = [event isARepeat];
- ke.keycode = remapKey([event keyCode], [event modifierFlags]);
- ke.physical_keycode = translateKey([event keyCode]);
- ke.raw = true;
- ke.unicode = [characters characterAtIndex:i];
-
- push_to_key_event_buffer(ke);
- }
- } else {
- OS_OSX::KeyEvent ke;
-
- ke.osx_state = [event modifierFlags];
- ke.pressed = false;
- ke.echo = [event isARepeat];
- ke.keycode = remapKey([event keyCode], [event modifierFlags]);
- ke.physical_keycode = translateKey([event keyCode]);
- ke.raw = true;
- ke.unicode = 0;
-
- push_to_key_event_buffer(ke);
- }
- }
-}
-
-inline void sendScrollEvent(int button, double factor, int modifierFlags) {
-
- unsigned int mask = 1 << (button - 1);
- Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
-
- Ref<InputEventMouseButton> sc;
- sc.instance();
-
- get_key_modifier_state(modifierFlags, sc);
- sc->set_button_index(button);
- sc->set_factor(factor);
- sc->set_pressed(true);
- sc->set_position(mouse_pos);
- sc->set_global_position(mouse_pos);
- button_mask |= mask;
- sc->set_button_mask(button_mask);
- OS_OSX::singleton->push_input(sc);
-
- sc.instance();
- sc->set_button_index(button);
- sc->set_factor(factor);
- sc->set_pressed(false);
- sc->set_position(mouse_pos);
- sc->set_global_position(mouse_pos);
- button_mask &= ~mask;
- sc->set_button_mask(button_mask);
- OS_OSX::singleton->push_input(sc);
-}
-
-inline void sendPanEvent(double dx, double dy, int modifierFlags) {
-
- Ref<InputEventPanGesture> pg;
- pg.instance();
-
- get_key_modifier_state(modifierFlags, pg);
- Vector2 mouse_pos = Vector2(mouse_x, mouse_y);
- pg->set_position(mouse_pos);
- pg->set_delta(Vector2(-dx, -dy));
- OS_OSX::singleton->push_input(pg);
-}
-
-- (void)scrollWheel:(NSEvent *)event {
- double deltaX, deltaY;
-
- get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]);
-
- deltaX = [event scrollingDeltaX];
- deltaY = [event scrollingDeltaY];
-
- if ([event hasPreciseScrollingDeltas]) {
- deltaX *= 0.03;
- deltaY *= 0.03;
- }
-
- if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
- sendPanEvent(deltaX, deltaY, [event modifierFlags]);
- } else {
- if (fabs(deltaX)) {
- sendScrollEvent(0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
- }
- if (fabs(deltaY)) {
- sendScrollEvent(0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
- }
- }
-}
-
-@end
-
-@interface GodotWindow : NSWindow {
-}
-@end
-
-@implementation GodotWindow
-
-- (BOOL)canBecomeKeyWindow {
- // Required for NSBorderlessWindowMask windows
- return YES;
-}
-
-@end
-
-void OS_OSX::_update_global_menu() {
-
- NSMenu *main_menu = [NSApp mainMenu];
-
- for (int i = 1; i < [main_menu numberOfItems]; i++) {
- [main_menu removeItemAtIndex:i];
- }
- for (Map<String, Vector<GlobalMenuItem> >::Element *E = global_menus.front(); E; E = E->next()) {
- if (E->key() != "_dock") {
- NSMenu *menu = [[[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:E->key().utf8().get_data()]] autorelease];
- for (int i = 0; i < E->get().size(); i++) {
- if (E->get()[i].label == String()) {
- [menu addItem:[NSMenuItem separatorItem]];
- } else {
- NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:E->get()[i].label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
- [menu_item setRepresentedObject:[NSValue valueWithPointer:&(E->get()[i])]];
- }
- }
- NSMenuItem *menu_item = [main_menu addItemWithTitle:[NSString stringWithUTF8String:E->key().utf8().get_data()] action:nil keyEquivalent:@""];
- [main_menu setSubmenu:menu forItem:menu_item];
- }
- }
-}
-
-void OS_OSX::global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta) {
-
- global_menus[p_menu].push_back(GlobalMenuItem(p_label, p_signal, p_meta));
- _update_global_menu();
-}
-
-void OS_OSX::global_menu_add_separator(const String &p_menu) {
-
- global_menus[p_menu].push_back(GlobalMenuItem());
- _update_global_menu();
-}
-
-void OS_OSX::global_menu_remove_item(const String &p_menu, int p_idx) {
-
- ERR_FAIL_INDEX(p_idx, global_menus[p_menu].size());
-
- global_menus[p_menu].remove(p_idx);
- _update_global_menu();
-}
-
-void OS_OSX::global_menu_clear(const String &p_menu) {
-
- global_menus[p_menu].clear();
- _update_global_menu();
-}
-
-Point2 OS_OSX::get_ime_selection() const {
-
- return im_selection;
-}
-
-String OS_OSX::get_ime_text() const {
-
- return im_text;
-}
-
-String OS_OSX::get_unique_id() const {
-
- static String serial_number;
-
- if (serial_number.empty()) {
- io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
- CFStringRef serialNumberAsCFString = NULL;
- if (platformExpert) {
- serialNumberAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
- IOObjectRelease(platformExpert);
- }
-
- NSString *serialNumberAsNSString = nil;
- if (serialNumberAsCFString) {
- serialNumberAsNSString = [NSString stringWithString:(NSString *)serialNumberAsCFString];
- CFRelease(serialNumberAsCFString);
- }
-
- serial_number = [serialNumberAsNSString UTF8String];
- }
-
- return serial_number;
-}
-
-void OS_OSX::set_ime_active(const bool p_active) {
-
- im_active = p_active;
- if (!im_active)
- [window_view cancelComposition];
-}
-
-void OS_OSX::set_ime_position(const Point2 &p_pos) {
-
- im_position = p_pos;
-}
-
-void OS_OSX::initialize_core() {
-
- crash_handler.initialize();
-
- OS_Unix::initialize_core();
-
- DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES);
- DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_USERDATA);
- DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_FILESYSTEM);
-}
-
-static bool keyboard_layout_dirty = true;
-static void keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) {
- keyboard_layout_dirty = true;
-}
-
-static bool displays_arrangement_dirty = true;
-static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
- displays_arrangement_dirty = true;
-}
-
-int OS_OSX::get_current_video_driver() const {
- return video_driver_index;
-}
-
-Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
-
- /*** OSX INITIALIZATION ***/
- /*** OSX INITIALIZATION ***/
- /*** OSX INITIALIZATION ***/
-
- keyboard_layout_dirty = true;
- displays_arrangement_dirty = true;
-
- // Register to be notified on keyboard layout changes
- CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
- NULL, keyboard_layout_changed,
- kTISNotifySelectedKeyboardInputSourceChanged, NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
-
- // Register to be notified on displays arrangement changes
- CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
-
- //!!!!!!!!!!!!!!!!!!!!!!!!!!
- //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
- video_driver_index = p_video_driver;
- print_verbose("Driver: " + String(get_video_driver_name(video_driver_index)) + " [" + itos(video_driver_index) + "]");
- //!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- //Create window
-
- window_delegate = [[GodotWindowDelegate alloc] init];
-
- // Don't use accumulation buffer support; it's not accelerated
- // Aux buffers probably aren't accelerated either
-
- unsigned int styleMask;
-
- if (p_desired.borderless_window) {
- styleMask = NSWindowStyleMaskBorderless;
- } else {
- resizable = p_desired.resizable;
- styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (p_desired.resizable ? NSWindowStyleMaskResizable : 0);
- }
-
- window_object = [[GodotWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, p_desired.width, p_desired.height)
- styleMask:styleMask
- backing:NSBackingStoreBuffered
- defer:NO];
-
- ERR_FAIL_COND_V(window_object == nil, ERR_UNAVAILABLE);
-
- window_view = [[GodotContentView alloc] init];
- if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_14) {
- [window_view setWantsLayer:TRUE];
- }
-
- float displayScale = 1.0;
- if (is_hidpi_allowed()) {
- // note that mainScreen is not screen #0 but the one with the keyboard focus.
- NSScreen *screen = [NSScreen mainScreen];
- if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
- displayScale = fmax(displayScale, [screen backingScaleFactor]);
- }
- }
-
- window_size.width = p_desired.width * displayScale;
- window_size.height = p_desired.height * displayScale;
-
- if (displayScale > 1.0) {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- [window_view setWantsBestResolutionOpenGLSurface:YES];
- }
-#endif
- [window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
- } else {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- [window_view setWantsBestResolutionOpenGLSurface:NO];
- }
-#endif
- }
-
- [window_object setContentView:window_view];
- [window_object setDelegate:window_delegate];
- [window_object setAcceptsMouseMovedEvents:YES];
- [(NSWindow *)window_object center];
-
- [window_object setRestorable:NO];
-
- // Init context and rendering device
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
-
- context_gles2 = memnew(ContextGL_OSX(window_view, false));
-
- if (context_gles2->initialize() != OK) {
- memdelete(context_gles2);
- context_gles2 = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
-
- context_gles2->set_use_vsync(p_desired.use_vsync);
-
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- } else {
- memdelete(context_gles2);
- context_gles2 = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
-
- context_vulkan = memnew(VulkanContextOSX);
- if (context_vulkan->initialize() != OK) {
- memdelete(context_vulkan);
- context_vulkan = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- if (context_vulkan->window_create(window_view, get_video_mode().width, get_video_mode().height) == -1) {
- memdelete(context_vulkan);
- context_vulkan = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
-
- rendering_device_vulkan = memnew(RenderingDeviceVulkan);
- rendering_device_vulkan->initialize(context_vulkan);
-
- RasterizerRD::make_current();
- }
-#endif
-
- [NSApp activateIgnoringOtherApps:YES];
-
- _update_window();
-
- [window_object makeKeyAndOrderFront:nil];
-
- if (p_desired.fullscreen)
- zoomed = true;
-
- visual_server = memnew(VisualServerRaster);
- if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
- }
-
- visual_server->init();
- AudioDriverManager::initialize(p_audio_driver);
-
- input = memnew(InputDefault);
- joypad_osx = memnew(JoypadOSX);
-
- _ensure_user_data_dir();
-
- restore_rect = Rect2(get_window_position(), get_window_size());
-
- if (p_desired.layered) {
- set_window_per_pixel_transparency_enabled(true);
- }
-
- update_real_mouse_position();
-
- return OK;
-}
-
-void OS_OSX::finalize() {
-
-#ifdef COREMIDI_ENABLED
- midi_driver.close();
-#endif
-
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
-
- if (context_gles2)
- memdelete(context_gles2);
- }
-#endif
-
- CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
- CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
-
- delete_main_loop();
-
- memdelete(joypad_osx);
- memdelete(input);
-
- cursors_cache.clear();
- visual_server->finish();
- memdelete(visual_server);
-}
-
-void OS_OSX::set_main_loop(MainLoop *p_main_loop) {
-
- main_loop = p_main_loop;
- input->set_main_loop(p_main_loop);
-}
-
-void OS_OSX::delete_main_loop() {
-
- if (!main_loop)
- return;
- memdelete(main_loop);
- main_loop = NULL;
-}
-
-String OS_OSX::get_name() const {
+#include <mach-o/dyld.h>
+#include <os/log.h>
- return "OSX";
-}
+/*************************************************************************/
+/* OSXTerminalLogger */
+/*************************************************************************/
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
class OSXTerminalLogger : public StdLogger {
public:
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) {
@@ -1747,333 +100,101 @@ public:
}
};
-#else
-
-typedef UnixTerminalLogger OSXTerminalLogger;
-#endif
-
-void OS_OSX::alert(const String &p_alert, const String &p_title) {
- // Set OS X-compliant variables
- NSAlert *window = [[NSAlert alloc] init];
- NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
- NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
-
- [window addButtonWithTitle:@"OK"];
- [window setMessageText:ns_title];
- [window setInformativeText:ns_alert];
- [window setAlertStyle:NSAlertStyleWarning];
-
- // Display it, then release
- [window runModal];
- [window release];
-}
+/*************************************************************************/
+/* OS_OSX */
+/*************************************************************************/
-Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+String OS_OSX::get_unique_id() const {
+ static String serial_number;
- String path = p_path;
+ if (serial_number.empty()) {
+ io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
+ CFStringRef serialNumberAsCFString = NULL;
+ if (platformExpert) {
+ serialNumberAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
+ IOObjectRelease(platformExpert);
+ }
- if (!FileAccess::exists(path)) {
- //this code exists so gdnative can load .dylib files from within the executable path
- path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
- }
+ NSString *serialNumberAsNSString = nil;
+ if (serialNumberAsCFString) {
+ serialNumberAsNSString = [NSString stringWithString:(NSString *)serialNumberAsCFString];
+ CFRelease(serialNumberAsCFString);
+ }
- if (!FileAccess::exists(path)) {
- //this code exists so gdnative can load .dylib files from a standard macOS location
- path = get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file());
+ serial_number = [serialNumberAsNSString UTF8String];
}
- p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
- return OK;
+ return serial_number;
}
-void OS_OSX::set_cursor_shape(CursorShape p_shape) {
-
- if (cursor_shape == p_shape)
- return;
-
- if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
- cursor_shape = p_shape;
- return;
- }
-
- if (cursors[p_shape] != NULL) {
- [cursors[p_shape] set];
- } else {
- switch (p_shape) {
- case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
- case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
- case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
- case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
- case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
- case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
- case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
- case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
- case CURSOR_FORBIDDEN: [[NSCursor operationNotAllowedCursor] set]; break;
- case CURSOR_VSIZE: [cursorFromSelector(@selector(_windowResizeNorthSouthCursor), @selector(resizeUpDownCursor)) set]; break;
- case CURSOR_HSIZE: [cursorFromSelector(@selector(_windowResizeEastWestCursor), @selector(resizeLeftRightCursor)) set]; break;
- case CURSOR_BDIAGSIZE: [cursorFromSelector(@selector(_windowResizeNorthEastSouthWestCursor)) set]; break;
- case CURSOR_FDIAGSIZE: [cursorFromSelector(@selector(_windowResizeNorthWestSouthEastCursor)) set]; break;
- case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
- case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
- case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
- case CURSOR_HELP: [cursorFromSelector(@selector(_helpCursor)) set]; break;
- default: {
- };
- }
- }
+void OS_OSX::initialize_core() {
+ OS_Unix::initialize_core();
- cursor_shape = p_shape;
+ DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_FILESYSTEM);
}
-OS::CursorShape OS_OSX::get_cursor_shape() const {
-
- return cursor_shape;
+void OS_OSX::initialize_joypads() {
+ joypad_osx = memnew(JoypadOSX(InputFilter::get_singleton()));
}
-void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-
- if (p_cursor.is_valid()) {
-
- Map<CursorShape, Vector<Variant> >::Element *cursor_c = cursors_cache.find(p_shape);
-
- if (cursor_c) {
- if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
- set_cursor_shape(p_shape);
- return;
- }
-
- cursors_cache.erase(p_shape);
- }
-
- Ref<Texture2D> texture = p_cursor;
- Ref<AtlasTexture> atlas_texture = p_cursor;
- Ref<Image> image;
- Size2 texture_size;
- Rect2 atlas_rect;
-
- if (texture.is_valid()) {
- image = texture->get_data();
- }
-
- if (!image.is_valid() && atlas_texture.is_valid()) {
- texture = atlas_texture->get_atlas();
-
- atlas_rect.size.width = texture->get_width();
- atlas_rect.size.height = texture->get_height();
- atlas_rect.position.x = atlas_texture->get_region().position.x;
- atlas_rect.position.y = atlas_texture->get_region().position.y;
-
- texture_size.width = atlas_texture->get_region().size.x;
- texture_size.height = atlas_texture->get_region().size.y;
- } else if (image.is_valid()) {
- texture_size.width = texture->get_width();
- texture_size.height = texture->get_height();
- }
-
- ERR_FAIL_COND(!texture.is_valid());
- ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
- 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();
-
- ERR_FAIL_COND(!image.is_valid());
-
- NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:NULL
- pixelsWide:int(texture_size.width)
- pixelsHigh:int(texture_size.height)
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:int(texture_size.width) * 4
- bitsPerPixel:32];
-
- ERR_FAIL_COND(imgrep == nil);
- uint8_t *pixels = [imgrep bitmapData];
-
- int len = int(texture_size.width * texture_size.height);
-
- for (int i = 0; i < len; i++) {
- int row_index = floor(i / texture_size.width) + atlas_rect.position.y;
- int column_index = (i % int(texture_size.width)) + atlas_rect.position.x;
-
- if (atlas_texture.is_valid()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
-
- uint32_t color = image->get_pixel(column_index, row_index).to_argb32();
-
- uint8_t alpha = (color >> 24) & 0xFF;
- pixels[i * 4 + 0] = ((color >> 16) & 0xFF) * alpha / 255;
- pixels[i * 4 + 1] = ((color >> 8) & 0xFF) * alpha / 255;
- pixels[i * 4 + 2] = ((color)&0xFF) * alpha / 255;
- pixels[i * 4 + 3] = alpha;
- }
-
- NSImage *nsimage = [[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)];
- [nsimage addRepresentation:imgrep];
-
- NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
-
- [cursors[p_shape] release];
- cursors[p_shape] = cursor;
-
- Vector<Variant> params;
- params.push_back(p_cursor);
- params.push_back(p_hotspot);
- cursors_cache.insert(p_shape, params);
-
- if (p_shape == cursor_shape) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
- [cursor set];
- }
- }
-
- [imgrep release];
- [nsimage release];
- } else {
- // Reset to default system cursor
- if (cursors[p_shape] != NULL) {
- [cursors[p_shape] release];
- cursors[p_shape] = NULL;
- }
-
- CursorShape c = cursor_shape;
- cursor_shape = CURSOR_MAX;
- set_cursor_shape(c);
-
- cursors_cache.erase(p_shape);
- }
-}
-
-void OS_OSX::set_mouse_show(bool p_show) {
-}
+void OS_OSX::initialize() {
+ crash_handler.initialize();
-void OS_OSX::set_mouse_grab(bool p_grab) {
+ initialize_core();
+ //ensure_user_data_dir();
}
-bool OS_OSX::is_mouse_grab_enabled() const {
-
- return mouse_grab;
-}
+void OS_OSX::finalize() {
-void OS_OSX::warp_mouse_position(const Point2 &p_to) {
-
- //copied from windows impl with osx native calls
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- mouse_x = p_to.x;
- mouse_y = p_to.y;
- } else { //set OS position
-
- //local point in window coords
- const NSRect contentRect = [window_view frame];
- float displayScale = _display_scale();
- NSRect pointInWindowRect = NSMakeRect(p_to.x / displayScale, contentRect.size.height - (p_to.y / displayScale) - 1, 0, 0);
- NSPoint pointOnScreen = [[window_view window] convertRectToScreen:pointInWindowRect].origin;
-
- //point in scren coords
- CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
-
- //do the warping
- CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
- CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
- CGAssociateMouseAndMouseCursorPosition(false);
- CGWarpMouseCursorPosition(lMouseWarpPos);
- CGAssociateMouseAndMouseCursorPosition(true);
- }
-}
+#ifdef COREMIDI_ENABLED
+ midi_driver.close();
+#endif
-void OS_OSX::update_real_mouse_position() {
+ delete_main_loop();
- get_mouse_pos([window_object mouseLocationOutsideOfEventStream], [window_view backingScaleFactor]);
- input->set_mouse_position(Point2(mouse_x, mouse_y));
+ memdelete(joypad_osx);
}
-Point2 OS_OSX::get_mouse_position() const {
-
- return Vector2(mouse_x, mouse_y);
+void OS_OSX::set_main_loop(MainLoop *p_main_loop) {
+ main_loop = p_main_loop;
}
-int OS_OSX::get_mouse_button_state() const {
- return button_mask;
+void OS_OSX::delete_main_loop() {
+ if (!main_loop)
+ return;
+ memdelete(main_loop);
+ main_loop = NULL;
}
-void OS_OSX::set_window_title(const String &p_title) {
- title = p_title;
-
- [window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
+String OS_OSX::get_name() const {
+ return "macOS";
}
-void OS_OSX::set_native_icon(const String &p_filename) {
-
- FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
- ERR_FAIL_COND(!f);
-
- Vector<uint8_t> data;
- uint32_t len = f->get_len();
- data.resize(len);
- f->get_buffer((uint8_t *)&data.write[0], len);
- memdelete(f);
-
- NSData *icon_data = [[[NSData alloc] initWithBytes:&data.write[0] length:len] autorelease];
- ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data.");
-
- NSImage *icon = [[[NSImage alloc] initWithData:icon_data] autorelease];
- ERR_FAIL_COND_MSG(!icon, "Error loading icon.");
-
- [NSApp setApplicationIconImage:icon];
-}
+Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+ String path = p_path;
-void OS_OSX::set_icon(const Ref<Image> &p_icon) {
-
- Ref<Image> img = p_icon;
- img = img->duplicate();
- img->convert(Image::FORMAT_RGBA8);
- NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:NULL
- pixelsWide:img->get_width()
- pixelsHigh:img->get_height()
- bitsPerSample:8
- samplesPerPixel:4
- hasAlpha:YES
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:img->get_width() * 4
- bitsPerPixel:32] autorelease];
- ERR_FAIL_COND(imgrep == nil);
- uint8_t *pixels = [imgrep bitmapData];
-
- int len = img->get_width() * img->get_height();
- const uint8_t *r = img->get_data().ptr();
-
- /* Premultiply the alpha channel */
- for (int i = 0; i < len; i++) {
- uint8_t alpha = r[i * 4 + 3];
- pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
- pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
- pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
- pixels[i * 4 + 3] = alpha;
+ if (!FileAccess::exists(path)) {
+ //this code exists so gdnative can load .dylib files from within the executable path
+ path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
}
- NSImage *nsimg = [[[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())] autorelease];
- ERR_FAIL_COND(nsimg == nil);
- [nsimg addRepresentation:imgrep];
+ if (!FileAccess::exists(path)) {
+ //this code exists so gdnative can load .dylib files from a standard macOS location
+ path = get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file());
+ }
- [NSApp setApplicationIconImage:nsimg];
+ p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
+ ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
+ return OK;
}
MainLoop *OS_OSX::get_main_loop() const {
-
return main_loop;
}
String OS_OSX::get_config_path() const {
-
if (has_environment("XDG_CONFIG_HOME")) {
return get_environment("XDG_CONFIG_HOME");
} else if (has_environment("HOME")) {
@@ -2084,7 +205,6 @@ String OS_OSX::get_config_path() const {
}
String OS_OSX::get_data_path() const {
-
if (has_environment("XDG_DATA_HOME")) {
return get_environment("XDG_DATA_HOME");
} else {
@@ -2093,7 +213,6 @@ String OS_OSX::get_data_path() const {
}
String OS_OSX::get_cache_path() const {
-
if (has_environment("XDG_CACHE_HOME")) {
return get_environment("XDG_CACHE_HOME");
} else if (has_environment("HOME")) {
@@ -2104,7 +223,6 @@ String OS_OSX::get_cache_path() const {
}
String OS_OSX::get_bundle_resource_dir() const {
-
NSBundle *main = [NSBundle mainBundle];
NSString *resourcePath = [main resourcePath];
@@ -2118,12 +236,10 @@ String OS_OSX::get_bundle_resource_dir() const {
// Get properly capitalized engine name for system paths
String OS_OSX::get_godot_dir_name() const {
-
return String(VERSION_SHORT_NAME).capitalize();
}
String OS_OSX::get_system_dir(SystemDir p_dir) const {
-
NSSearchPathDirectory id;
bool found = true;
@@ -2166,62 +282,7 @@ String OS_OSX::get_system_dir(SystemDir p_dir) const {
return ret;
}
-bool OS_OSX::can_draw() const {
-
- return true;
-}
-
-void OS_OSX::set_clipboard(const String &p_text) {
-
- NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()];
- NSArray *copiedStringArray = [NSArray arrayWithObject:copiedString];
-
- NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
- [pasteboard clearContents];
- [pasteboard writeObjects:copiedStringArray];
-}
-
-String OS_OSX::get_clipboard() const {
-
- NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
- NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
- NSDictionary *options = [NSDictionary dictionary];
-
- BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
-
- if (!ok) {
- return "";
- }
-
- NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
- NSString *string = [objectsToPaste objectAtIndex:0];
-
- char *utfs = strdup([string UTF8String]);
- String ret;
- ret.parse_utf8(utfs);
- free(utfs);
-
- return ret;
-}
-
-void OS_OSX::release_rendering_thread() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->release_current();
- }
-#endif
-}
-
-void OS_OSX::make_rendering_thread() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->make_current();
- }
-#endif
-}
-
Error OS_OSX::shell_open(String p_uri) {
-
[[NSWorkspace sharedWorkspace] openURL:[[NSURL alloc] initWithString:[[NSString stringWithUTF8String:p_uri.utf8().get_data()] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]];
return OK;
}
@@ -2231,491 +292,7 @@ String OS_OSX::get_locale() const {
return [locale_code UTF8String];
}
-void OS_OSX::swap_buffers() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->swap_buffers();
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
- context_vulkan->swap_buffers();
- }
-#endif
-}
-
-void OS_OSX::wm_minimized(bool p_minimized) {
-
- minimized = p_minimized;
-};
-
-void OS_OSX::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
-}
-
-OS::VideoMode OS_OSX::get_video_mode(int p_screen) const {
-
- VideoMode vm;
- vm.width = window_size.width;
- vm.height = window_size.height;
-
- return vm;
-}
-
-void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
-}
-
-int OS_OSX::get_screen_count() const {
- NSArray *screenArray = [NSScreen screens];
- return [screenArray count];
-};
-
-// Returns the native top-left screen coordinate of the smallest rectangle
-// that encompasses all screens. Needed in get_screen_position(),
-// get_window_position, and set_window_position()
-// to convert between OS X native screen coordinates and the ones expected by Godot
-Point2 OS_OSX::get_screens_origin() const {
- static Point2 origin;
-
- if (displays_arrangement_dirty) {
- origin = Point2();
-
- for (int i = 0; i < get_screen_count(); i++) {
- Point2 position = get_native_screen_position(i);
- if (position.x < origin.x) {
- origin.x = position.x;
- }
- if (position.y > origin.y) {
- origin.y = position.y;
- }
- }
-
- displays_arrangement_dirty = false;
- }
-
- return origin;
-}
-
-static int get_screen_index(NSScreen *screen) {
- const NSUInteger index = [[NSScreen screens] indexOfObject:screen];
- return index == NSNotFound ? 0 : index;
-}
-
-int OS_OSX::get_current_screen() const {
- if (window_object) {
- return get_screen_index([window_object screen]);
- } else {
- return get_screen_index([NSScreen mainScreen]);
- }
-};
-
-void OS_OSX::set_current_screen(int p_screen) {
- Vector2 wpos = get_window_position() - get_screen_position(get_current_screen());
- set_window_position(wpos + get_screen_position(p_screen));
-};
-
-Point2 OS_OSX::get_native_screen_position(int p_screen) const {
- if (p_screen < 0) {
- p_screen = get_current_screen();
- }
-
- NSArray *screenArray = [NSScreen screens];
- if ((NSUInteger)p_screen < [screenArray count]) {
- float display_scale = _display_scale([screenArray objectAtIndex:p_screen]);
- NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
- // Return the top-left corner of the screen, for OS X the y starts at the bottom
- return Point2(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * display_scale;
- }
-
- return Point2();
-}
-
-Point2 OS_OSX::get_screen_position(int p_screen) const {
- Point2 position = get_native_screen_position(p_screen) - get_screens_origin();
- // OS X native y-coordinate relative to get_screens_origin() is negative,
- // Godot expects a positive value
- position.y *= -1;
- return position;
-}
-
-int OS_OSX::get_screen_dpi(int p_screen) const {
- if (p_screen < 0) {
- p_screen = get_current_screen();
- }
-
- NSArray *screenArray = [NSScreen screens];
- if ((NSUInteger)p_screen < [screenArray count]) {
- float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
- NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
- NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
- CGSize displayPhysicalSize = CGDisplayScreenSize(
- [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
-
- return (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale;
- }
-
- return 72;
-}
-
-Size2 OS_OSX::get_screen_size(int p_screen) const {
- if (p_screen < 0) {
- p_screen = get_current_screen();
- }
-
- NSArray *screenArray = [NSScreen screens];
- if ((NSUInteger)p_screen < [screenArray count]) {
- float displayScale = _display_scale([screenArray objectAtIndex:p_screen]);
- // Note: Use frame to get the whole screen size
- NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
- return Size2(nsrect.size.width, nsrect.size.height) * displayScale;
- }
-
- return Size2();
-}
-
-void OS_OSX::_update_window() {
- bool borderless_full = false;
-
- if (get_borderless_window()) {
- NSRect frameRect = [window_object frame];
- NSRect screenRect = [[window_object screen] frame];
-
- // Check if our window covers up the screen
- if (frameRect.origin.x <= screenRect.origin.x && frameRect.origin.y <= frameRect.origin.y &&
- frameRect.size.width >= screenRect.size.width && frameRect.size.height >= screenRect.size.height) {
- borderless_full = true;
- }
- }
-
- if (borderless_full) {
- // If the window covers up the screen set the level to above the main menu and hide on deactivate
- [window_object setLevel:NSMainMenuWindowLevel + 1];
- [window_object setHidesOnDeactivate:YES];
- } else {
- // Reset these when our window is not a borderless window that covers up the screen
- [window_object setLevel:NSNormalWindowLevel];
- [window_object setHidesOnDeactivate:NO];
- }
-}
-
-float OS_OSX::_display_scale() const {
- if (window_object) {
- return _display_scale([window_object screen]);
- } else {
- return _display_scale([NSScreen mainScreen]);
- }
-}
-
-float OS_OSX::_display_scale(id screen) const {
- if (is_hidpi_allowed()) {
- if ([screen respondsToSelector:@selector(backingScaleFactor)]) {
- return fmax(1.0, [screen backingScaleFactor]);
- }
- }
- return 1.0;
-}
-
-Point2 OS_OSX::get_native_window_position() const {
-
- NSRect nsrect = [window_object frame];
- Point2 pos;
- float display_scale = _display_scale();
-
- // Return the position of the top-left corner, for OS X the y starts at the bottom
- pos.x = nsrect.origin.x * display_scale;
- pos.y = (nsrect.origin.y + nsrect.size.height) * display_scale;
-
- return pos;
-};
-
-Point2 OS_OSX::get_window_position() const {
- Point2 position = get_native_window_position() - get_screens_origin();
- // OS X native y-coordinate relative to get_screens_origin() is negative,
- // Godot expects a positive value
- position.y *= -1;
- return position;
-}
-
-void OS_OSX::set_native_window_position(const Point2 &p_position) {
-
- NSPoint pos;
- float displayScale = _display_scale();
-
- pos.x = p_position.x / displayScale;
- pos.y = p_position.y / displayScale;
-
- [window_object setFrameTopLeftPoint:pos];
-
- _update_window();
-};
-
-void OS_OSX::set_window_position(const Point2 &p_position) {
- Point2 position = p_position;
- // OS X native y-coordinate relative to get_screens_origin() is negative,
- // Godot passes a positive value
- position.y *= -1;
- set_native_window_position(get_screens_origin() + position);
-
- update_real_mouse_position();
-};
-
-Size2 OS_OSX::get_window_size() const {
-
- return window_size;
-};
-
-Size2 OS_OSX::get_real_window_size() const {
-
- NSRect frame = [window_object frame];
- return Size2(frame.size.width, frame.size.height) * _display_scale();
-}
-
-Size2 OS_OSX::get_max_window_size() const {
- return max_size;
-}
-
-Size2 OS_OSX::get_min_window_size() const {
- return min_size;
-}
-
-void OS_OSX::set_min_window_size(const Size2 p_size) {
-
- if ((p_size != Size2()) && (max_size != Size2()) && ((p_size.x > max_size.x) || (p_size.y > max_size.y))) {
- ERR_PRINT("Minimum window size can't be larger than maximum window size!");
- return;
- }
- min_size = p_size;
-
- if ((min_size != Size2()) && !zoomed) {
- Size2 size = min_size / _display_scale();
- [window_object setContentMinSize:NSMakeSize(size.x, size.y)];
- } else {
- [window_object setContentMinSize:NSMakeSize(0, 0)];
- }
-}
-
-void OS_OSX::set_max_window_size(const Size2 p_size) {
-
- if ((p_size != Size2()) && ((p_size.x < min_size.x) || (p_size.y < min_size.y))) {
- ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
- return;
- }
- max_size = p_size;
-
- if ((max_size != Size2()) && !zoomed) {
- Size2 size = max_size / _display_scale();
- [window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
- } else {
- [window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- }
-}
-
-void OS_OSX::set_window_size(const Size2 p_size) {
-
- Size2 size = p_size / _display_scale();
-
- if (get_borderless_window() == false) {
- // NSRect used by setFrame includes the title bar, so add it to our size.y
- CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
- if (menuBarHeight != 0.f) {
- size.y += menuBarHeight;
- } else {
- if (floor(NSAppKitVersionNumber) < NSAppKitVersionNumber10_12) {
- size.y += [[NSStatusBar systemStatusBar] thickness];
- }
- }
- }
-
- NSRect frame = [window_object frame];
- [window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES];
-
- _update_window();
-};
-
-void OS_OSX::set_window_fullscreen(bool p_enabled) {
-
- if (zoomed != p_enabled) {
- if (layered_window)
- set_window_per_pixel_transparency_enabled(false);
- if (!resizable)
- [window_object setStyleMask:[window_object styleMask] | NSWindowStyleMaskResizable];
- if (p_enabled) {
- [window_object setContentMinSize:NSMakeSize(0, 0)];
- [window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- } else {
- if (min_size != Size2()) {
- Size2 size = min_size / _display_scale();
- [window_object setContentMinSize:NSMakeSize(size.x, size.y)];
- }
- if (max_size != Size2()) {
- Size2 size = max_size / _display_scale();
- [window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
- }
- }
- [window_object toggleFullScreen:nil];
- }
- zoomed = p_enabled;
-};
-
-bool OS_OSX::is_window_fullscreen() const {
-
- return zoomed;
-};
-
-void OS_OSX::set_window_resizable(bool p_enabled) {
-
- if (p_enabled)
- [window_object setStyleMask:[window_object styleMask] | NSWindowStyleMaskResizable];
- else if (!zoomed)
- [window_object setStyleMask:[window_object styleMask] & ~NSWindowStyleMaskResizable];
-
- resizable = p_enabled;
-};
-
-bool OS_OSX::is_window_resizable() const {
-
- return [window_object styleMask] & NSWindowStyleMaskResizable;
-};
-
-void OS_OSX::set_window_minimized(bool p_enabled) {
-
- if (p_enabled)
- [window_object performMiniaturize:nil];
- else
- [window_object deminiaturize:nil];
-};
-
-bool OS_OSX::is_window_minimized() const {
-
- if ([window_object respondsToSelector:@selector(isMiniaturized)])
- return [window_object isMiniaturized];
-
- return minimized;
-};
-
-void OS_OSX::set_window_maximized(bool p_enabled) {
-
- if (p_enabled) {
- restore_rect = Rect2(get_window_position(), get_window_size());
- [window_object setFrame:[[[NSScreen screens] objectAtIndex:get_current_screen()] visibleFrame] display:YES];
- } else {
- set_window_size(restore_rect.size);
- set_window_position(restore_rect.position);
- };
- maximized = p_enabled;
-};
-
-bool OS_OSX::is_window_maximized() const {
-
- // don't know
- return maximized;
-};
-
-void OS_OSX::move_window_to_foreground() {
-
- [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
- [window_object makeKeyAndOrderFront:nil];
-}
-
-void OS_OSX::set_window_always_on_top(bool p_enabled) {
- if (is_window_always_on_top() == p_enabled)
- return;
-
- if (p_enabled)
- [window_object setLevel:NSFloatingWindowLevel];
- else
- [window_object setLevel:NSNormalWindowLevel];
-}
-
-bool OS_OSX::is_window_always_on_top() const {
- return [window_object level] == NSFloatingWindowLevel;
-}
-
-bool OS_OSX::is_window_focused() const {
- return window_focused;
-}
-
-void OS_OSX::request_attention() {
-
- [NSApp requestUserAttention:NSCriticalRequest];
-}
-
-bool OS_OSX::get_window_per_pixel_transparency_enabled() const {
-
- if (!is_layered_allowed()) return false;
- return layered_window;
-}
-
-void OS_OSX::set_window_per_pixel_transparency_enabled(bool p_enabled) {
-
- if (!is_layered_allowed()) return;
- if (layered_window != p_enabled) {
- if (p_enabled) {
- set_borderless_window(true);
- [window_object setBackgroundColor:[NSColor clearColor]];
- [window_object setOpaque:NO];
- [window_object setHasShadow:NO];
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->set_opacity(0);
- }
-#endif
- layered_window = true;
- } else {
- [window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]];
- [window_object setOpaque:YES];
- [window_object setHasShadow:YES];
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->set_opacity(1);
- }
-#endif
- layered_window = false;
- }
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->update();
- }
-#endif
- NSRect frame = [window_object frame];
- [window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, 1, 1) display:YES];
- [window_object setFrame:frame display:YES];
- }
-}
-
-void OS_OSX::set_borderless_window(bool p_borderless) {
-
- // OrderOut prevents a lose focus bug with the window
- [window_object orderOut:nil];
-
- if (p_borderless) {
- [window_object setStyleMask:NSWindowStyleMaskBorderless];
- } else {
- if (layered_window)
- set_window_per_pixel_transparency_enabled(false);
-
- [window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (resizable ? NSWindowStyleMaskResizable : 0)];
-
- // Force update of the window styles
- NSRect frameRect = [window_object frame];
- [window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
- [window_object setFrame:frameRect display:NO];
-
- // Restore the window title
- [window_object setTitle:[NSString stringWithUTF8String:title.utf8().get_data()]];
- }
-
- _update_window();
-
- [window_object makeKeyAndOrderFront:nil];
-}
-
-bool OS_OSX::get_borderless_window() {
-
- return [window_object styleMask] == NSWindowStyleMaskBorderless;
-}
-
String OS_OSX::get_executable_path() const {
-
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
@@ -2732,177 +309,7 @@ String OS_OSX::get_executable_path() const {
}
}
-// Returns string representation of keys, if they are printable.
-//
-static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) {
-
- TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
- if (!currentKeyboard)
- return nil;
-
- CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
- if (!layoutData)
- return nil;
-
- const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
-
- OSStatus err;
- CFMutableStringRef output = CFStringCreateMutable(NULL, 0);
-
- for (int i = 0; i < length; ++i) {
-
- UInt32 keysDown = 0;
- UniChar chars[4];
- UniCharCount realLength;
-
- err = UCKeyTranslate(keyboardLayout,
- keyCode[i],
- kUCKeyActionDisplay,
- 0,
- LMGetKbdType(),
- kUCKeyTranslateNoDeadKeysBit,
- &keysDown,
- sizeof(chars) / sizeof(chars[0]),
- &realLength,
- chars);
-
- if (err != noErr) {
- CFRelease(output);
- return nil;
- }
-
- CFStringAppendCharacters(output, chars, 1);
- }
-
- //CFStringUppercase(output, NULL);
-
- return (NSString *)output;
-}
-
-OS::LatinKeyboardVariant OS_OSX::get_latin_keyboard_variant() const {
-
- static LatinKeyboardVariant layout = LATIN_KEYBOARD_QWERTY;
-
- if (keyboard_layout_dirty) {
-
- layout = LATIN_KEYBOARD_QWERTY;
-
- CGKeyCode keys[] = { kVK_ANSI_Q, kVK_ANSI_W, kVK_ANSI_E, kVK_ANSI_R, kVK_ANSI_T, kVK_ANSI_Y };
- NSString *test = createStringForKeys(keys, 6);
-
- if ([test isEqualToString:@"qwertz"]) {
- layout = LATIN_KEYBOARD_QWERTZ;
- } else if ([test isEqualToString:@"azerty"]) {
- layout = LATIN_KEYBOARD_AZERTY;
- } else if ([test isEqualToString:@"qzerty"]) {
- layout = LATIN_KEYBOARD_QZERTY;
- } else if ([test isEqualToString:@"',.pyf"]) {
- layout = LATIN_KEYBOARD_DVORAK;
- } else if ([test isEqualToString:@"xvlcwk"]) {
- layout = LATIN_KEYBOARD_NEO;
- } else if ([test isEqualToString:@"qwfpgj"]) {
- layout = LATIN_KEYBOARD_COLEMAK;
- }
-
- [test release];
-
- keyboard_layout_dirty = false;
- return layout;
- }
-
- return layout;
-}
-
-void OS_OSX::process_events() {
-
- while (true) {
- NSEvent *event = [NSApp
- nextEventMatchingMask:NSEventMaskAny
- untilDate:[NSDate distantPast]
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
-
- if (event == nil)
- break;
-
- [NSApp sendEvent:event];
- }
- process_key_events();
-
- [autoreleasePool drain];
- autoreleasePool = [[NSAutoreleasePool alloc] init];
-
- input->flush_accumulated_events();
-}
-
-void OS_OSX::process_key_events() {
-
- Ref<InputEventKey> k;
- for (int i = 0; i < key_event_pos; i++) {
-
- const KeyEvent &ke = key_event_buffer[i];
-
- if (ke.raw) {
- // Non IME input - no composite characters, pass events as is
- k.instance();
-
- get_key_modifier_state(ke.osx_state, k);
- k->set_pressed(ke.pressed);
- k->set_echo(ke.echo);
- k->set_keycode(ke.keycode);
- k->set_physical_keycode(ke.physical_keycode);
- k->set_unicode(ke.unicode);
-
- push_input(k);
- } else {
- // IME input
- if ((i == 0 && ke.keycode == 0) || (i > 0 && key_event_buffer[i - 1].keycode == 0)) {
- k.instance();
-
- get_key_modifier_state(ke.osx_state, k);
- k->set_pressed(ke.pressed);
- k->set_echo(ke.echo);
- k->set_keycode(0);
- k->set_physical_keycode(0);
- k->set_unicode(ke.unicode);
-
- push_input(k);
- }
- if (ke.keycode != 0) {
- k.instance();
-
- get_key_modifier_state(ke.osx_state, k);
- k->set_pressed(ke.pressed);
- k->set_echo(ke.echo);
- k->set_keycode(ke.keycode);
- k->set_physical_keycode(ke.physical_keycode);
-
- if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == 0) {
- k->set_unicode(key_event_buffer[i + 1].unicode);
- }
-
- push_input(k);
- }
- }
- }
-
- key_event_pos = 0;
-}
-
-void OS_OSX::push_input(const Ref<InputEvent> &p_event) {
-
- Ref<InputEvent> ev = p_event;
- input->accumulate_input_event(ev);
-}
-
-void OS_OSX::force_process_input() {
-
- process_events(); // get rid of pending events
- joypad_osx->process_joypads();
-}
-
void OS_OSX::run() {
-
force_quit = false;
if (!main_loop)
@@ -2910,23 +317,12 @@ void OS_OSX::run() {
main_loop->init();
- if (zoomed) {
- zoomed = false;
- set_window_fullscreen(true);
- }
-
- //uint64_t last_ticks=get_ticks_usec();
-
- //int frames=0;
- //uint64_t frame=0;
-
bool quit = false;
-
while (!force_quit && !quit) {
-
@try {
-
- process_events(); // get rid of pending events
+ if (DisplayServer::get_singleton()) {
+ DisplayServer::get_singleton()->process_events(); // get rid of pending events
+ }
joypad_osx->process_joypads();
if (Main::iteration() == true) {
@@ -2936,41 +332,9 @@ void OS_OSX::run() {
ERR_PRINT("NSException: " + String([exception reason].UTF8String));
}
};
-
main_loop->finish();
}
-void OS_OSX::set_mouse_mode(MouseMode p_mode) {
-
- if (p_mode == mouse_mode)
- return;
-
- if (p_mode == MOUSE_MODE_CAPTURED) {
- // Apple Docs state that the display parameter is not used.
- // "This parameter is not used. By default, you may pass kCGDirectMainDisplay."
- // https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html
- CGDisplayHideCursor(kCGDirectMainDisplay);
- CGAssociateMouseAndMouseCursorPosition(false);
- } else if (p_mode == MOUSE_MODE_HIDDEN) {
- CGDisplayHideCursor(kCGDirectMainDisplay);
- CGAssociateMouseAndMouseCursorPosition(true);
- } else {
- CGDisplayShowCursor(kCGDirectMainDisplay);
- CGAssociateMouseAndMouseCursorPosition(true);
- }
-
- mouse_mode = p_mode;
-}
-
-OS::MouseMode OS_OSX::get_mouse_mode() const {
-
- return mouse_mode;
-}
-
-String OS_OSX::get_joy_guid(int p_device) const {
- return input->get_joy_guid_remapped(p_device);
-}
-
Error OS_OSX::move_to_trash(const String &p_path) {
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
@@ -2984,123 +348,19 @@ Error OS_OSX::move_to_trash(const String &p_path) {
return OK;
}
-void OS_OSX::_set_use_vsync(bool p_enable) {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- if (context_gles2)
- context_gles2->set_use_vsync(p_enable);
- }
-#endif
-}
-
-OS_OSX *OS_OSX::singleton = NULL;
-
OS_OSX::OS_OSX() {
-
- memset(cursors, 0, sizeof(cursors));
- key_event_pos = 0;
- mouse_mode = OS::MOUSE_MODE_VISIBLE;
main_loop = NULL;
- singleton = this;
- im_active = false;
- im_position = Point2();
- layered_window = false;
- autoreleasePool = [[NSAutoreleasePool alloc] init];
-
- eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
- ERR_FAIL_COND(!eventSource);
-
- CGEventSourceSetLocalEventsSuppressionInterval(eventSource, 0.0);
-
- // Implicitly create shared NSApplication instance
- [GodotApplication sharedApplication];
-
- // In case we are unbundled, make us a proper UI application
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
-
- // Menu bar setup must go between sharedApplication above and
- // finishLaunching below, in order to properly emulate the behavior
- // of NSApplicationMain
- NSMenuItem *menu_item;
- NSString *title;
-
- NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
- if (nsappname == nil)
- nsappname = [[NSProcessInfo processInfo] processName];
-
- // Setup Apple menu
- NSMenu *apple_menu = [[NSMenu alloc] initWithTitle:@""];
- title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname];
- [apple_menu addItemWithTitle:title action:@selector(showAbout:) keyEquivalent:@""];
-
- [apple_menu addItem:[NSMenuItem separatorItem]];
-
- NSMenu *services = [[NSMenu alloc] initWithTitle:@""];
- menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""];
- [apple_menu setSubmenu:services forItem:menu_item];
- [NSApp setServicesMenu:services];
- [services release];
-
- [apple_menu addItem:[NSMenuItem separatorItem]];
-
- title = [NSString stringWithFormat:NSLocalizedString(@"Hide %@", nil), nsappname];
- [apple_menu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
-
- menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
- [menu_item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
-
- [apple_menu addItemWithTitle:NSLocalizedString(@"Show all", nil) action:@selector(unhideAllApplications:) keyEquivalent:@""];
-
- [apple_menu addItem:[NSMenuItem separatorItem]];
-
- title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
- [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
- // Setup menu bar
- NSMenu *main_menu = [[NSMenu alloc] initWithTitle:@""];
- menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
- [main_menu setSubmenu:apple_menu forItem:menu_item];
- [NSApp setMainMenu:main_menu];
-
- [main_menu release];
- [apple_menu release];
-
- [NSApp finishLaunching];
-
- delegate = [[GodotApplicationDelegate alloc] init];
- ERR_FAIL_COND(!delegate);
- [NSApp setDelegate:delegate];
-
- cursor_shape = CURSOR_ARROW;
-
- maximized = false;
- minimized = false;
- window_size = Vector2(1024, 600);
- zoomed = false;
- resizable = false;
- window_focused = true;
+ force_quit = false;
Vector<Logger *> loggers;
loggers.push_back(memnew(OSXTerminalLogger));
_set_logger(memnew(CompositeLogger(loggers)));
- //process application:openFile: event
- while (true) {
- NSEvent *event = [NSApp
- nextEventMatchingMask:NSEventMaskAny
- untilDate:[NSDate distantPast]
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
-
- if (event == nil)
- break;
-
- [NSApp sendEvent:event];
- }
-
#ifdef COREAUDIO_ENABLED
AudioDriverManager::add_driver(&audio_driver);
#endif
+
+ DisplayServerOSX::register_osx_driver();
}
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
diff --git a/platform/osx/platform_osx_builders.py b/platform/osx/platform_osx_builders.py
index 81997f674b..953ed479db 100644
--- a/platform/osx/platform_osx_builders.py
+++ b/platform/osx/platform_osx_builders.py
@@ -8,14 +8,14 @@ from platform_methods import subprocess_main
def make_debug_osx(target, source, env):
- if (env["macports_clang"] != 'no'):
+ if env["macports_clang"] != "no":
mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local")
mpclangver = env["macports_clang"]
- os.system(mpprefix + '/libexec/llvm-' + mpclangver + '/bin/llvm-dsymutil {0} -o {0}.dSYM'.format(target[0]))
+ os.system(mpprefix + "/libexec/llvm-" + mpclangver + "/bin/llvm-dsymutil {0} -o {0}.dSYM".format(target[0]))
else:
- os.system('dsymutil {0} -o {0}.dSYM'.format(target[0]))
- os.system('strip -u -r {0}'.format(target[0]))
+ os.system("dsymutil {0} -o {0}.dSYM".format(target[0]))
+ os.system("strip -u -r {0}".format(target[0]))
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/platform/osx/vulkan_context_osx.h b/platform/osx/vulkan_context_osx.h
index 619e91d1f6..09a5494ae8 100644
--- a/platform/osx/vulkan_context_osx.h
+++ b/platform/osx/vulkan_context_osx.h
@@ -39,7 +39,7 @@ class VulkanContextOSX : public VulkanContext {
virtual const char *_get_platform_surface_extension() const;
public:
- int window_create(id p_window, int p_width, int p_height);
+ Error window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height);
VulkanContextOSX();
~VulkanContextOSX();
diff --git a/platform/osx/vulkan_context_osx.mm b/platform/osx/vulkan_context_osx.mm
index c132bd334a..320401cdcb 100644
--- a/platform/osx/vulkan_context_osx.mm
+++ b/platform/osx/vulkan_context_osx.mm
@@ -35,7 +35,7 @@ const char *VulkanContextOSX::_get_platform_surface_extension() const {
return VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
}
-int VulkanContextOSX::window_create(id p_window, int p_width, int p_height) {
+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;
@@ -45,8 +45,8 @@ int VulkanContextOSX::window_create(id p_window, int p_width, int p_height) {
VkSurfaceKHR surface;
VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, NULL, &surface);
- ERR_FAIL_COND_V(err, -1);
- return _window_create(surface, p_width, p_height);
+ ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ return _window_create(p_window_id, surface, p_width, p_height);
}
VulkanContextOSX::VulkanContextOSX() {
diff --git a/platform/server/SCsub b/platform/server/SCsub
index 8364164114..15b9af4d25 100644
--- a/platform/server/SCsub
+++ b/platform/server/SCsub
@@ -2,15 +2,15 @@
import sys
-Import('env')
+Import("env")
-common_server = [\
- "os_server.cpp",\
+common_server = [
+ "os_server.cpp",
]
if sys.platform == "darwin":
- common_server.append("#platform/osx/crash_handler_osx.mm")
+ common_server.append("#platform/osx/crash_handler_osx.mm")
else:
- common_server.append("#platform/x11/crash_handler_x11.cpp")
+ common_server.append("#platform/x11/crash_handler_x11.cpp")
-prog = env.add_program('#bin/godot_server', ['godot_server.cpp'] + common_server)
+prog = env.add_program("#bin/godot_server", ["godot_server.cpp"] + common_server)
diff --git a/platform/server/detect.py b/platform/server/detect.py
index db9ba8d036..a73810cdf4 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -5,6 +5,7 @@ import sys
# This file is mostly based on platform/x11/detect.py.
# If editing this file, make sure to apply relevant changes here too.
+
def is_active():
return True
@@ -14,14 +15,14 @@ def get_name():
def get_program_suffix():
- if (sys.platform == "darwin"):
+ if sys.platform == "darwin":
return "osx"
- return "x11"
+ return "linuxbsd"
def can_build():
- if (os.name != "posix"):
+ if os.name != "posix":
return False
return True
@@ -29,17 +30,18 @@ def can_build():
def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
+
return [
- BoolVariable('use_llvm', 'Use the LLVM compiler', False),
- BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
- 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),
- EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
- BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
- BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False),
+ BoolVariable("use_llvm", "Use the LLVM compiler", False),
+ BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", False),
+ 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),
+ EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
+ BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
+ BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
]
@@ -52,89 +54,89 @@ def configure(env):
## Build type
- if (env["target"] == "release"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O3'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
-
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "release_debug"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O2'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
- env.Prepend(CPPDEFINES=['DEBUG_ENABLED'])
-
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "debug"):
- env.Prepend(CCFLAGS=['-g3'])
- env.Prepend(CPPDEFINES=['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
- env.Append(LINKFLAGS=['-rdynamic'])
+ if env["target"] == "release":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Prepend(CCFLAGS=["-O3"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "release_debug":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Prepend(CCFLAGS=["-O2"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+ env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
+
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "debug":
+ env.Prepend(CCFLAGS=["-g3"])
+ env.Prepend(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
+ env.Append(LINKFLAGS=["-rdynamic"])
## Architecture
- is64 = sys.maxsize > 2**32
- if (env["bits"] == "default"):
+ is64 = sys.maxsize > 2 ** 32
+ if env["bits"] == "default":
env["bits"] = "64" if is64 else "32"
## Compiler configuration
- if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
+ if "CXX" in env and "clang" in os.path.basename(env["CXX"]):
# Convenience check to enforce the use_llvm overrides when CXX is clang(++)
- env['use_llvm'] = True
+ env["use_llvm"] = True
- if env['use_llvm']:
- if ('clang++' not in os.path.basename(env['CXX'])):
+ if env["use_llvm"]:
+ if "clang++" not in os.path.basename(env["CXX"]):
env["CC"] = "clang"
env["CXX"] = "clang++"
env["LINK"] = "clang++"
- env.Append(CPPDEFINES=['TYPED_METHOD_BIND'])
+ env.Append(CPPDEFINES=["TYPED_METHOD_BIND"])
env.extra_suffix = ".llvm" + env.extra_suffix
- if env['use_coverage']:
- env.Append(CCFLAGS=['-ftest-coverage', '-fprofile-arcs'])
- env.Append(LINKFLAGS=['-ftest-coverage', '-fprofile-arcs'])
+ 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"]:
env.extra_suffix += "s"
- if env['use_ubsan']:
- env.Append(CCFLAGS=['-fsanitize=undefined'])
- env.Append(LINKFLAGS=['-fsanitize=undefined'])
+ if env["use_ubsan"]:
+ env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(LINKFLAGS=["-fsanitize=undefined"])
- if env['use_asan']:
- env.Append(CCFLAGS=['-fsanitize=address'])
- env.Append(LINKFLAGS=['-fsanitize=address'])
+ if env["use_asan"]:
+ env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(LINKFLAGS=["-fsanitize=address"])
- if env['use_lsan']:
- env.Append(CCFLAGS=['-fsanitize=leak'])
- env.Append(LINKFLAGS=['-fsanitize=leak'])
+ if env["use_lsan"]:
+ env.Append(CCFLAGS=["-fsanitize=leak"])
+ env.Append(LINKFLAGS=["-fsanitize=leak"])
- if env['use_tsan']:
- env.Append(CCFLAGS=['-fsanitize=thread'])
- env.Append(LINKFLAGS=['-fsanitize=thread'])
+ if env["use_tsan"]:
+ env.Append(CCFLAGS=["-fsanitize=thread"])
+ env.Append(LINKFLAGS=["-fsanitize=thread"])
- if env['use_lto']:
- env.Append(CCFLAGS=['-flto'])
- if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
- env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
+ if env["use_lto"]:
+ env.Append(CCFLAGS=["-flto"])
+ if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
+ env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
else:
- env.Append(LINKFLAGS=['-flto'])
- if not env['use_llvm']:
- env['RANLIB'] = 'gcc-ranlib'
- env['AR'] = 'gcc-ar'
+ env.Append(LINKFLAGS=["-flto"])
+ if not env["use_llvm"]:
+ env["RANLIB"] = "gcc-ranlib"
+ env["AR"] = "gcc-ar"
- env.Append(CCFLAGS=['-pipe'])
- env.Append(LINKFLAGS=['-pipe'])
+ env.Append(CCFLAGS=["-pipe"])
+ env.Append(LINKFLAGS=["-pipe"])
## Dependencies
@@ -142,109 +144,114 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
- if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']:
- env['builtin_freetype'] = True
- env['builtin_libpng'] = True
- env['builtin_zlib'] = True
+ if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ env["builtin_freetype"] = True
+ env["builtin_libpng"] = True
+ env["builtin_zlib"] = True
- if not env['builtin_freetype']:
- env.ParseConfig('pkg-config freetype2 --cflags --libs')
+ if not env["builtin_freetype"]:
+ env.ParseConfig("pkg-config freetype2 --cflags --libs")
- if not env['builtin_libpng']:
- env.ParseConfig('pkg-config libpng16 --cflags --libs')
+ if not env["builtin_libpng"]:
+ env.ParseConfig("pkg-config libpng16 --cflags --libs")
- if not env['builtin_bullet']:
+ if not env["builtin_bullet"]:
# We need at least version 2.89
import subprocess
- bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
+
+ bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip()
if str(bullet_version) < "2.89":
# Abort as system bullet was requested but too old
- print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.89"))
+ print(
+ "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(
+ bullet_version, "2.89"
+ )
+ )
sys.exit(255)
- env.ParseConfig('pkg-config bullet --cflags --libs')
+ env.ParseConfig("pkg-config bullet --cflags --libs")
if False: # not env['builtin_assimp']:
# FIXME: Add min version check
- env.ParseConfig('pkg-config assimp --cflags --libs')
+ env.ParseConfig("pkg-config assimp --cflags --libs")
- if not env['builtin_enet']:
- env.ParseConfig('pkg-config libenet --cflags --libs')
+ if not env["builtin_enet"]:
+ env.ParseConfig("pkg-config libenet --cflags --libs")
- if not env['builtin_squish']:
- env.ParseConfig('pkg-config libsquish --cflags --libs')
+ if not env["builtin_squish"]:
+ env.ParseConfig("pkg-config libsquish --cflags --libs")
- if not env['builtin_zstd']:
- env.ParseConfig('pkg-config libzstd --cflags --libs')
+ if not env["builtin_zstd"]:
+ env.ParseConfig("pkg-config libzstd --cflags --libs")
# Sound and video libraries
# Keep the order as it triggers chained dependencies (ogg needed by others, etc.)
- if not env['builtin_libtheora']:
- env['builtin_libogg'] = False # Needed to link against system libtheora
- env['builtin_libvorbis'] = False # Needed to link against system libtheora
- env.ParseConfig('pkg-config theora theoradec --cflags --libs')
+ if not env["builtin_libtheora"]:
+ env["builtin_libogg"] = False # Needed to link against system libtheora
+ env["builtin_libvorbis"] = False # Needed to link against system libtheora
+ env.ParseConfig("pkg-config theora theoradec --cflags --libs")
else:
- list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
+ list_of_x86 = ["x86_64", "x86", "i386", "i586"]
if any(platform.machine() in s for s in list_of_x86):
env["x86_libtheora_opt_gcc"] = True
- if not env['builtin_libvpx']:
- env.ParseConfig('pkg-config vpx --cflags --libs')
+ if not env["builtin_libvpx"]:
+ env.ParseConfig("pkg-config vpx --cflags --libs")
- if not env['builtin_libvorbis']:
- env['builtin_libogg'] = False # Needed to link against system libvorbis
- env.ParseConfig('pkg-config vorbis vorbisfile --cflags --libs')
+ if not env["builtin_libvorbis"]:
+ env["builtin_libogg"] = False # Needed to link against system libvorbis
+ env.ParseConfig("pkg-config vorbis vorbisfile --cflags --libs")
- if not env['builtin_opus']:
- env['builtin_libogg'] = False # Needed to link against system opus
- env.ParseConfig('pkg-config opus opusfile --cflags --libs')
+ if not env["builtin_opus"]:
+ env["builtin_libogg"] = False # Needed to link against system opus
+ env.ParseConfig("pkg-config opus opusfile --cflags --libs")
- if not env['builtin_libogg']:
- env.ParseConfig('pkg-config ogg --cflags --libs')
+ if not env["builtin_libogg"]:
+ env.ParseConfig("pkg-config ogg --cflags --libs")
- if not env['builtin_libwebp']:
- env.ParseConfig('pkg-config libwebp --cflags --libs')
+ if not env["builtin_libwebp"]:
+ env.ParseConfig("pkg-config libwebp --cflags --libs")
- if not env['builtin_mbedtls']:
+ if not env["builtin_mbedtls"]:
# mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
- env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
+ env.Append(LIBS=["mbedtls", "mbedcrypto", "mbedx509"])
- if not env['builtin_wslay']:
- env.ParseConfig('pkg-config libwslay --cflags --libs')
+ if not env["builtin_wslay"]:
+ env.ParseConfig("pkg-config libwslay --cflags --libs")
- if not env['builtin_miniupnpc']:
+ if not env["builtin_miniupnpc"]:
# No pkgconfig file so far, hardcode default paths.
env.Prepend(CPPPATH=["/usr/include/miniupnpc"])
env.Append(LIBS=["miniupnpc"])
# On Linux wchar_t should be 32-bits
# 16-bit library shouldn't be required due to compiler optimisations
- if not env['builtin_pcre2']:
- env.ParseConfig('pkg-config libpcre2-32 --cflags --libs')
+ if not env["builtin_pcre2"]:
+ env.ParseConfig("pkg-config libpcre2-32 --cflags --libs")
## Flags
# Linkflags below this line should typically stay the last ones
- if not env['builtin_zlib']:
- env.ParseConfig('pkg-config zlib --cflags --libs')
+ if not env["builtin_zlib"]:
+ env.ParseConfig("pkg-config zlib --cflags --libs")
- env.Prepend(CPPPATH=['#platform/server'])
- env.Append(CPPDEFINES=['SERVER_ENABLED', 'UNIX_ENABLED'])
+ env.Prepend(CPPPATH=["#platform/server"])
+ env.Append(CPPDEFINES=["SERVER_ENABLED", "UNIX_ENABLED"])
- if (platform.system() == "Darwin"):
- env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-lz', '-framework', 'IOKit'])
+ if platform.system() == "Darwin":
+ env.Append(LINKFLAGS=["-framework", "Cocoa", "-framework", "Carbon", "-lz", "-framework", "IOKit"])
- env.Append(LIBS=['pthread'])
+ env.Append(LIBS=["pthread"])
- if (platform.system() == "Linux"):
- env.Append(LIBS=['dl'])
+ if platform.system() == "Linux":
+ env.Append(LIBS=["dl"])
- if (platform.system().find("BSD") >= 0):
+ if platform.system().find("BSD") >= 0:
env["execinfo"] = True
if env["execinfo"]:
- env.Append(LIBS=['execinfo'])
+ env.Append(LIBS=["execinfo"])
# Link those statically for portability
- if env['use_static_cpp']:
- env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])
+ if env["use_static_cpp"]:
+ env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 3257ec261c..0fda0663a2 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -33,7 +33,7 @@
#include "core/print_string.h"
#include "drivers/dummy/rasterizer_dummy.h"
#include "drivers/dummy/texture_loader_dummy.h"
-#include "servers/visual/visual_server_raster.h"
+#include "servers/rendering/rendering_server_raster.h"
#include "main/main.h"
@@ -74,14 +74,14 @@ Error OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int
args = OS::get_singleton()->get_cmdline_args();
current_videomode = p_desired;
- main_loop = NULL;
+ main_loop = nullptr;
RasterizerDummy::make_current();
video_driver_index = p_video_driver; // unused in server platform, but should still be initialized
- visual_server = memnew(VisualServerRaster);
- visual_server->init();
+ rendering_server = memnew(RenderingServerRaster);
+ rendering_server->init();
AudioDriverManager::initialize(p_audio_driver);
@@ -99,10 +99,10 @@ void OS_Server::finalize() {
if (main_loop)
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
- visual_server->finish();
- memdelete(visual_server);
+ rendering_server->finish();
+ memdelete(rendering_server);
memdelete(input);
@@ -163,7 +163,7 @@ void OS_Server::delete_main_loop() {
if (main_loop)
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
}
void OS_Server::set_main_loop(MainLoop *p_main_loop) {
@@ -289,7 +289,7 @@ String OS_Server::get_system_dir(SystemDir p_dir) const {
String pipe;
List<String> arg;
arg.push_back(xdgparam);
- Error err = const_cast<OS_Server *>(this)->execute("xdg-user-dir", arg, true, NULL, &pipe);
+ Error err = const_cast<OS_Server *>(this)->execute("xdg-user-dir", arg, true, nullptr, &pipe);
if (err != OK)
return ".";
return pipe.strip_edges();
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index 7584293722..62028b26e4 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -31,24 +31,24 @@
#ifndef OS_SERVER_H
#define OS_SERVER_H
+#include "core/input/input_filter.h"
#include "drivers/dummy/texture_loader_dummy.h"
#include "drivers/unix/os_unix.h"
-#include "main/input_default.h"
#ifdef __APPLE__
#include "platform/osx/crash_handler_osx.h"
#include "platform/osx/semaphore_osx.h"
#else
-#include "platform/x11/crash_handler_x11.h"
+#include "platform/x11/crash_handler_linuxbsd.h"
#endif
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
#undef CursorShape
class OS_Server : public OS_Unix {
- VisualServer *visual_server;
+ RenderingServer *rendering_server;
VideoMode current_videomode;
List<String> args;
MainLoop *main_loop;
diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub
index 620d8c3c3a..4358b0eead 100644
--- a/platform/uwp/SCsub
+++ b/platform/uwp/SCsub
@@ -1,21 +1,21 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
files = [
- 'thread_uwp.cpp',
- '#platform/windows/key_mapping_windows.cpp',
- '#platform/windows/windows_terminal_logger.cpp',
- 'joypad_uwp.cpp',
- 'context_egl_uwp.cpp',
- 'app.cpp',
- 'os_uwp.cpp',
+ "thread_uwp.cpp",
+ "#platform/windows/key_mapping_windows.cpp",
+ "#platform/windows/windows_terminal_logger.cpp",
+ "joypad_uwp.cpp",
+ "context_egl_uwp.cpp",
+ "app.cpp",
+ "os_uwp.cpp",
]
if "build_angle" in env and env["build_angle"]:
- cmd = env.AlwaysBuild(env.ANGLE('libANGLE.lib', None))
+ cmd = env.AlwaysBuild(env.ANGLE("libANGLE.lib", None))
-prog = env.add_program('#bin/godot', files)
+prog = env.add_program("#bin/godot", files)
if "build_angle" in env and env["build_angle"]:
env.Depends(prog, [cmd])
diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp
index ccb4b43373..d3870b0b6c 100644
--- a/platform/uwp/app.cpp
+++ b/platform/uwp/app.cpp
@@ -507,12 +507,12 @@ void App::UpdateWindowSize(Size size) {
char **App::get_command_line(unsigned int *out_argc) {
- static char *fail_cl[] = { "--path", "game", NULL };
+ static char *fail_cl[] = { "--path", "game", nullptr };
*out_argc = 2;
FILE *f = _wfopen(L"__cl__.cl", L"rb");
- if (f == NULL) {
+ if (f == nullptr) {
wprintf(L"Couldn't open command line file.\n");
return fail_cl;
@@ -558,7 +558,7 @@ char **App::get_command_line(unsigned int *out_argc) {
if (r == strlen) {
- int warg_size = MultiByteToWideChar(CP_UTF8, 0, arg, -1, NULL, 0);
+ int warg_size = MultiByteToWideChar(CP_UTF8, 0, arg, -1, nullptr, 0);
wchar_t *warg = new wchar_t[warg_size];
MultiByteToWideChar(CP_UTF8, 0, arg, -1, warg, warg_size);
@@ -583,14 +583,14 @@ char **App::get_command_line(unsigned int *out_argc) {
for (int i = 0; i < cl.Size; i++) {
- int arg_size = WideCharToMultiByte(CP_UTF8, 0, cl.GetAt(i)->Data(), -1, NULL, 0, NULL, NULL);
+ int arg_size = WideCharToMultiByte(CP_UTF8, 0, cl.GetAt(i)->Data(), -1, nullptr, 0, nullptr, nullptr);
char *arg = new char[arg_size];
- WideCharToMultiByte(CP_UTF8, 0, cl.GetAt(i)->Data(), -1, arg, arg_size, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, cl.GetAt(i)->Data(), -1, arg, arg_size, nullptr, nullptr);
ret[i] = arg;
}
- ret[cl.Size] = NULL;
+ ret[cl.Size] = nullptr;
*out_argc = cl.Size;
return ret;
diff --git a/platform/uwp/context_egl_uwp.cpp b/platform/uwp/context_egl_uwp.cpp
index 7ac9489bb4..bc8ca2e36c 100644
--- a/platform/uwp/context_egl_uwp.cpp
+++ b/platform/uwp/context_egl_uwp.cpp
@@ -155,7 +155,7 @@ Error ContextEGL_UWP::initialize() {
throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL");
}
- if (eglGetConfigs(display, NULL, 0, &numConfigs) == EGL_FALSE) {
+ if (eglGetConfigs(display, nullptr, 0, &numConfigs) == EGL_FALSE) {
throw Exception::CreateException(E_FAIL, L"Failed to get EGLConfig count");
}
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index 000bd18e7d..669bfe6814 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -12,11 +12,11 @@ def get_name():
def can_build():
- if (os.name == "nt"):
+ if os.name == "nt":
# building natively on windows!
- if (os.getenv("VSINSTALLDIR")):
+ if os.getenv("VSINSTALLDIR"):
- if (os.getenv("ANGLE_SRC_PATH") is None):
+ if os.getenv("ANGLE_SRC_PATH") is None:
return False
return True
@@ -25,16 +25,16 @@ def can_build():
def get_opts():
return [
- ('msvc_version', 'MSVC version to use (ignored if the VCINSTALLDIR environment variable is set)', None),
+ ("msvc_version", "MSVC version to use (ignored if the VCINSTALLDIR environment variable is set)", None),
]
def get_flags():
return [
- ('tools', False),
- ('xaudio2', True),
- ('builtin_pcre2_with_jit', False),
+ ("tools", False),
+ ("xaudio2", True),
+ ("builtin_pcre2_with_jit", False),
]
@@ -42,45 +42,53 @@ def configure(env):
env.msvc = True
- if (env["bits"] != "default"):
+ if env["bits"] != "default":
print("Error: bits argument is disabled for MSVC")
- print("""
+ print(
+ """
Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console
(or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits
argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
- """)
+ """
+ )
sys.exit()
## Build type
- if (env["target"] == "release"):
- env.Append(CCFLAGS=['/O2', '/GL'])
- env.Append(CCFLAGS=['/MD'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS', '/LTCG'])
+ if env["target"] == "release":
+ env.Append(CCFLAGS=["/O2", "/GL"])
+ env.Append(CCFLAGS=["/MD"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS", "/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'])
+ elif env["target"] == "release_debug":
+ env.Append(CCFLAGS=["/O2", "/Zi"])
+ env.Append(CCFLAGS=["/MD"])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
- elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['/Zi'])
- env.Append(CCFLAGS=['/MDd'])
- env.Append(CPPDEFINES=['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG'])
+ elif env["target"] == "debug":
+ env.Append(CCFLAGS=["/Zi"])
+ env.Append(CCFLAGS=["/MDd"])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
+ env.Append(LINKFLAGS=["/DEBUG"])
## Compiler configuration
- env['ENV'] = os.environ
- vc_base_path = os.environ['VCTOOLSINSTALLDIR'] if "VCTOOLSINSTALLDIR" in os.environ else os.environ['VCINSTALLDIR']
+ env["ENV"] = os.environ
+ vc_base_path = os.environ["VCTOOLSINSTALLDIR"] if "VCTOOLSINSTALLDIR" in os.environ else os.environ["VCINSTALLDIR"]
# ANGLE
angle_root = os.getenv("ANGLE_SRC_PATH")
- env.Prepend(CPPPATH=[angle_root + '/include'])
+ env.Prepend(CPPPATH=[angle_root + "/include"])
jobs = str(env.GetOption("num_jobs"))
- angle_build_cmd = "msbuild.exe " + angle_root + "/winrt/10/src/angle.sln /nologo /v:m /m:" + jobs + " /p:Configuration=Release /p:Platform="
+ angle_build_cmd = (
+ "msbuild.exe "
+ + angle_root
+ + "/winrt/10/src/angle.sln /nologo /v:m /m:"
+ + jobs
+ + " /p:Configuration=Release /p:Platform="
+ )
if os.path.isfile(str(os.getenv("ANGLE_SRC_PATH")) + "/winrt/10/src/angle.sln"):
env["build_angle"] = True
@@ -88,49 +96,51 @@ def configure(env):
## Architecture
arch = ""
- if str(os.getenv('Platform')).lower() == "arm":
+ if str(os.getenv("Platform")).lower() == "arm":
print("Compiled program architecture will be an ARM executable. (forcing bits=32).")
arch = "arm"
env["bits"] = "32"
- env.Append(LINKFLAGS=['/MACHINE:ARM'])
- env.Append(LIBPATH=[vc_base_path + 'lib/store/arm'])
+ env.Append(LINKFLAGS=["/MACHINE:ARM"])
+ env.Append(LIBPATH=[vc_base_path + "lib/store/arm"])
angle_build_cmd += "ARM"
- env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_ARM/lib'])
+ env.Append(LIBPATH=[angle_root + "/winrt/10/src/Release_ARM/lib"])
else:
- compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV'])
+ compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"])
- if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"):
+ if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64":
env["bits"] = "64"
print("Compiled program architecture will be a x64 executable (forcing bits=64).")
- elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"):
+ elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86":
env["bits"] = "32"
print("Compiled program architecture will be a x86 executable. (forcing bits=32).")
else:
- print("Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup.")
+ print(
+ "Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup."
+ )
env["bits"] = "32"
- if (env["bits"] == "32"):
+ if env["bits"] == "32":
arch = "x86"
angle_build_cmd += "Win32"
- env.Append(LINKFLAGS=['/MACHINE:X86'])
- env.Append(LIBPATH=[vc_base_path + 'lib/store'])
- env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_Win32/lib'])
+ env.Append(LINKFLAGS=["/MACHINE:X86"])
+ env.Append(LIBPATH=[vc_base_path + "lib/store"])
+ env.Append(LIBPATH=[angle_root + "/winrt/10/src/Release_Win32/lib"])
else:
arch = "x64"
angle_build_cmd += "x64"
- env.Append(LINKFLAGS=['/MACHINE:X64'])
- env.Append(LIBPATH=[os.environ['VCINSTALLDIR'] + 'lib/store/amd64'])
- env.Append(LIBPATH=[angle_root + '/winrt/10/src/Release_x64/lib'])
+ env.Append(LINKFLAGS=["/MACHINE:X64"])
+ env.Append(LIBPATH=[os.environ["VCINSTALLDIR"] + "lib/store/amd64"])
+ env.Append(LIBPATH=[angle_root + "/winrt/10/src/Release_x64/lib"])
env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"]
env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"]
@@ -138,39 +148,61 @@ def configure(env):
## Compile flags
- env.Prepend(CPPPATH=['#platform/uwp', '#drivers/windows'])
- env.Append(CPPDEFINES=['UWP_ENABLED', 'WINDOWS_ENABLED', 'TYPED_METHOD_BIND'])
- env.Append(CPPDEFINES=['GLES_ENABLED', 'GL_GLEXT_PROTOTYPES', 'EGL_EGLEXT_PROTOTYPES', 'ANGLE_ENABLED'])
- winver = "0x0602" # Windows 8 is the minimum target for UWP build
- env.Append(CPPDEFINES=[('WINVER', winver), ('_WIN32_WINNT', winver), 'WIN32'])
-
- env.Append(CPPDEFINES=['__WRL_NO_DEFAULT_LIB__', ('PNG_ABORT', 'abort')])
-
- env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/store/references'])
- env.Append(CPPFLAGS=['/AI', vc_base_path + 'lib/x86/store/references'])
-
- env.Append(CCFLAGS='/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo'.split())
- env.Append(CPPDEFINES=['_UNICODE', 'UNICODE', ('WINAPI_FAMILY', 'WINAPI_FAMILY_APP')])
- env.Append(CXXFLAGS=['/ZW'])
- env.Append(CCFLAGS=['/AI', vc_base_path + '\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR'] + '\\References\\CommonConfiguration\\Neutral'])
+ env.Prepend(CPPPATH=["#platform/uwp", "#drivers/windows"])
+ env.Append(CPPDEFINES=["UWP_ENABLED", "WINDOWS_ENABLED", "TYPED_METHOD_BIND"])
+ env.Append(CPPDEFINES=["GLES_ENABLED", "GL_GLEXT_PROTOTYPES", "EGL_EGLEXT_PROTOTYPES", "ANGLE_ENABLED"])
+ winver = "0x0602" # Windows 8 is the minimum target for UWP build
+ env.Append(CPPDEFINES=[("WINVER", winver), ("_WIN32_WINNT", winver), "WIN32"])
+
+ env.Append(CPPDEFINES=["__WRL_NO_DEFAULT_LIB__", ("PNG_ABORT", "abort")])
+
+ env.Append(CPPFLAGS=["/AI", vc_base_path + "lib/store/references"])
+ env.Append(CPPFLAGS=["/AI", vc_base_path + "lib/x86/store/references"])
+
+ env.Append(
+ CCFLAGS='/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /errorReport:prompt /WX- /Zc:forScope /Gd /EHsc /nologo'.split()
+ )
+ env.Append(CPPDEFINES=["_UNICODE", "UNICODE", ("WINAPI_FAMILY", "WINAPI_FAMILY_APP")])
+ env.Append(CXXFLAGS=["/ZW"])
+ env.Append(
+ CCFLAGS=[
+ "/AI",
+ vc_base_path + "\\vcpackages",
+ "/AI",
+ os.environ["WINDOWSSDKDIR"] + "\\References\\CommonConfiguration\\Neutral",
+ ]
+ )
## Link flags
- env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', '/WINMD', '/APPCONTAINER', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1', '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"'])
+ env.Append(
+ LINKFLAGS=[
+ "/MANIFEST:NO",
+ "/NXCOMPAT",
+ "/DYNAMICBASE",
+ "/WINMD",
+ "/APPCONTAINER",
+ "/ERRORREPORT:PROMPT",
+ "/NOLOGO",
+ "/TLBID:1",
+ '/NODEFAULTLIB:"kernel32.lib"',
+ '/NODEFAULTLIB:"ole32.lib"',
+ ]
+ )
LIBS = [
- 'WindowsApp',
- 'mincore',
- 'ws2_32',
- 'libANGLE',
- 'libEGL',
- 'libGLESv2',
- 'bcrypt',
+ "WindowsApp",
+ "mincore",
+ "ws2_32",
+ "libANGLE",
+ "libEGL",
+ "libGLESv2",
+ "bcrypt",
]
env.Append(LINKFLAGS=[p + ".lib" for p in LIBS])
# Incremental linking fix
- env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program']
- env['BUILDERS']['Program'] = methods.precious_program
+ env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
+ env["BUILDERS"]["Program"] = methods.precious_program
- env.Append(BUILDERS={'ANGLE': env.Builder(action=angle_build_cmd)})
+ env.Append(BUILDERS={"ANGLE": env.Builder(action=angle_build_cmd)})
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index 533293387d..06bf738dc1 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -54,7 +54,7 @@ static const char *uwp_capabilities[] = {
"internetClient",
"internetClientServer",
"privateNetworkClientServer",
- NULL
+ nullptr
};
static const char *uwp_uap_capabilities[] = {
"appointments",
@@ -71,7 +71,7 @@ static const char *uwp_uap_capabilities[] = {
"userAccountInformation",
"videosLibrary",
"voipCall",
- NULL
+ nullptr
};
static const char *uwp_device_capabilities[] = {
"bluetooth",
@@ -79,7 +79,7 @@ static const char *uwp_device_capabilities[] = {
"microphone",
"proximity",
"webcam",
- NULL
+ nullptr
};
class AppxPackager {
@@ -478,7 +478,7 @@ Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t
// Data for compression
z_stream strm;
- FileAccess *strm_f = NULL;
+ FileAccess *strm_f = nullptr;
Vector<uint8_t> strm_in;
strm_in.resize(BLOCK_SIZE);
Vector<uint8_t> strm_out;
@@ -641,7 +641,7 @@ void AppxPackager::finish() {
package->close();
memdelete(package);
- package = NULL;
+ package = nullptr;
}
AppxPackager::AppxPackager() {}
@@ -670,7 +670,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
static const char *invalid_names[] = {
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
"COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
- NULL
+ nullptr
};
const char **t = invalid_names;
@@ -726,7 +726,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
"snow", "springGreen", "steelBlue", "tan", "teal", "thistle",
"tomato", "transparent", "turquoise", "violet", "wheat", "white",
"whiteSmoke", "yellow", "yellowGreen",
- NULL
+ nullptr
};
const char **color = valid_colors;
@@ -876,22 +876,22 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
Vector<uint8_t> data;
- StreamTexture *image = NULL;
+ StreamTexture *image = nullptr;
if (p_path.find("StoreLogo") != -1) {
- image = p_preset->get("images/store_logo").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/store_logo")));
+ image = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/store_logo")));
} else if (p_path.find("Square44x44Logo") != -1) {
- image = p_preset->get("images/square44x44_logo").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square44x44_logo")));
+ image = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square44x44_logo")));
} else if (p_path.find("Square71x71Logo") != -1) {
- image = p_preset->get("images/square71x71_logo").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square71x71_logo")));
+ image = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square71x71_logo")));
} else if (p_path.find("Square150x150Logo") != -1) {
- image = p_preset->get("images/square150x150_logo").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square150x150_logo")));
+ image = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square150x150_logo")));
} else if (p_path.find("Square310x310Logo") != -1) {
- image = p_preset->get("images/square310x310_logo").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square310x310_logo")));
+ image = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/square310x310_logo")));
} else if (p_path.find("Wide310x150Logo") != -1) {
- image = p_preset->get("images/wide310x150_logo").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/wide310x150_logo")));
+ image = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/wide310x150_logo")));
} else if (p_path.find("SplashScreen") != -1) {
- image = p_preset->get("images/splash_screen").is_zero() ? NULL : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/splash_screen")));
+ image = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture>(((Object *)p_preset->get("images/splash_screen")));
} else {
ERR_PRINT("Unable to load logo");
}
@@ -961,7 +961,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
".scn", // Binary scenes are usually already compressed
".stex", // Streamable textures are usually already compressed
// Trailer for easier processing
- NULL
+ nullptr
};
for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
@@ -1251,7 +1251,7 @@ public:
AppxPackager packager;
packager.init(fa_pack);
- FileAccess *src_f = NULL;
+ FileAccess *src_f = nullptr;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
if (ep.step("Creating package...", 0)) {
@@ -1283,7 +1283,7 @@ public:
// get file name
unz_file_info info;
char fname[16834];
- ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, NULL, 0, NULL, 0);
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, nullptr, 0, nullptr, 0);
String path = fname;
diff --git a/platform/uwp/export/export.h b/platform/uwp/export/export.h
index ce03bc0aeb..1a1555d8ee 100644
--- a/platform/uwp/export/export.h
+++ b/platform/uwp/export/export.h
@@ -28,4 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef UWP_EXPORT_H
+#define UWP_EXPORT_H
+
void register_uwp_exporter();
+
+#endif // UWP_EXPORT_H
diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h
index f2a721f3dd..054b67ddc8 100644
--- a/platform/uwp/joypad_uwp.h
+++ b/platform/uwp/joypad_uwp.h
@@ -31,7 +31,7 @@
#ifndef JOYPAD_UWP_H
#define JOYPAD_UWP_H
-#include "main/input_default.h"
+#include "core/input/input_filter.h"
ref class JoypadUWP sealed {
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 4ddb5463d0..f5e989b370 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -45,8 +45,8 @@
#include "main/main.h"
#include "platform/windows/windows_terminal_logger.h"
#include "servers/audio_server.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_wrap_mt.h"
#include "thread_uwp.h"
#include <ppltasks.h>
@@ -180,7 +180,7 @@ void OS_UWP::screen_size_changed() {
Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
- main_loop = NULL;
+ main_loop = nullptr;
outside = true;
// FIXME: Hardcoded for now, add Vulkan support.
@@ -193,7 +193,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
if (gl_context->initialize() != OK) {
memdelete(gl_context);
- gl_context = NULL;
+ gl_context = nullptr;
gl_initialization_error = true;
}
@@ -254,13 +254,13 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
set_video_mode(vm);
- visual_server = memnew(VisualServerRaster);
+ rendering_server = memnew(RenderingServerRaster);
// FIXME: Reimplement threaded rendering
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, false));
+ rendering_server = memnew(RenderingServerWrapMT(rendering_server, false));
}
- visual_server->init();
+ rendering_server->init();
input = memnew(InputDefault);
@@ -333,7 +333,7 @@ void OS_UWP::delete_main_loop() {
if (main_loop)
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
}
void OS_UWP::set_main_loop(MainLoop *p_main_loop) {
@@ -347,10 +347,10 @@ void OS_UWP::finalize() {
if (main_loop)
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
- visual_server->finish();
- memdelete(visual_server);
+ rendering_server->finish();
+ memdelete(rendering_server);
#ifdef OPENGL_ENABLED
if (gl_context)
memdelete(gl_context);
@@ -773,9 +773,9 @@ void OS_UWP::hide_virtual_keyboard() {
static String format_error_message(DWORD id) {
- LPWSTR messageBuffer = NULL;
+ LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
+ nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
@@ -869,14 +869,14 @@ OS_UWP::OS_UWP() {
stdo = fopen("stdout.txt", "wb");
#endif
- gl_context = NULL;
+ gl_context = nullptr;
display_request = ref new Windows::System::Display::DisplayRequest();
managed_object = ref new ManagedType;
managed_object->os = this;
- mouse_mode_changed = CreateEvent(NULL, TRUE, FALSE, L"os_mouse_mode_changed");
+ mouse_mode_changed = CreateEvent(nullptr, TRUE, FALSE, L"os_mouse_mode_changed");
AudioDriverManager::add_driver(&audio_driver);
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index ac6e0f3dd5..ad0efa1d03 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -32,16 +32,15 @@
#define OS_UWP_H
#include "context_egl_uwp.h"
+#include "core/input/input_filter.h"
#include "core/math/transform_2d.h"
-#include "core/os/input.h"
#include "core/os/os.h"
#include "core/ustring.h"
#include "drivers/xaudio2/audio_driver_xaudio2.h"
#include "joypad_uwp.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
#include <fcntl.h>
#include <io.h>
@@ -89,7 +88,7 @@ private:
bool outside;
int old_x, old_y;
Point2i center;
- VisualServer *visual_server;
+ RenderingServer *rendering_server;
int pressrc;
ContextEGL_UWP *gl_context;
@@ -203,7 +202,7 @@ public:
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
virtual Error kill(const ProcessID &p_pid);
virtual bool has_environment(const String &p_var) const;
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 8e94c7b35d..daffe59f34 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
import os
from platform_methods import run_in_subprocess
@@ -10,21 +10,22 @@ common_win = [
"godot_windows.cpp",
"crash_handler_windows.cpp",
"os_windows.cpp",
+ "display_server_windows.cpp",
"key_mapping_windows.cpp",
"joypad_windows.cpp",
"windows_terminal_logger.cpp",
"vulkan_context_win.cpp",
- "context_gl_windows.cpp"
+ "context_gl_windows.cpp",
]
-res_file = 'godot_res.rc'
+res_file = "godot_res.rc"
res_target = "godot_res" + env["OBJSUFFIX"]
res_obj = env.RES(res_target, res_file)
-prog = env.add_program('#bin/godot', common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"])
+prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGSUFFIX"])
# Microsoft Visual Studio Project Generation
-if env['vsproj']:
+if env["vsproj"]:
env.vs_srcs = env.vs_srcs + ["platform/windows/" + res_file]
env.vs_srcs = env.vs_srcs + ["platform/windows/godot.natvis"]
for x in common_win:
diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp
index ad62e3a306..5a36b5546d 100644
--- a/platform/windows/context_gl_windows.cpp
+++ b/platform/windows/context_gl_windows.cpp
@@ -52,7 +52,7 @@ typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int
void ContextGL_Windows::release_current() {
- wglMakeCurrent(hDC, NULL);
+ wglMakeCurrent(hDC, nullptr);
}
void ContextGL_Windows::make_current() {
@@ -185,10 +185,10 @@ Error ContextGL_Windows::initialize() {
0
}; //zero indicates the end of the array
- PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; //pointer to the method
+ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
- if (wglCreateContextAttribsARB == NULL) //OpenGL 3.0 is not supported
+ if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported
{
wglDeleteContext(hRC);
return ERR_CANT_CREATE;
@@ -199,7 +199,7 @@ Error ContextGL_Windows::initialize() {
wglDeleteContext(hRC);
return ERR_CANT_CREATE; // Return false
}
- wglMakeCurrent(hDC, NULL);
+ wglMakeCurrent(hDC, nullptr);
wglDeleteContext(hRC);
hRC = new_hRC;
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 6145751e00..1d9eba22d8 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -121,7 +121,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);
- if (OS::get_singleton() == NULL || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) {
+ if (OS::get_singleton() == nullptr || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) {
return EXCEPTION_CONTINUE_SEARCH;
}
@@ -131,7 +131,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
// Load the symbols:
- if (!SymInitialize(process, NULL, false))
+ if (!SymInitialize(process, nullptr, false))
return EXCEPTION_CONTINUE_SEARCH;
SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
@@ -193,7 +193,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
n++;
}
- if (!StackWalk64(image_type, process, hThread, &frame, context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
+ if (!StackWalk64(image_type, process, hThread, &frame, context, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
break;
} while (frame.AddrReturn.Offset != 0 && n < 256);
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 3ab0d38a6a..9f79e92dcb 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,6 +1,9 @@
import methods
import os
+# To match other platforms
+STACK_SIZE = 8388608
+
def is_active():
return True
@@ -11,10 +14,10 @@ def get_name():
def can_build():
- if (os.name == "nt"):
+ if os.name == "nt":
# Building natively on Windows
# If VCINSTALLDIR is set in the OS environ, use traditional Godot logic to set up MSVC
- if (os.getenv("VCINSTALLDIR")): # MSVC, manual setup
+ if os.getenv("VCINSTALLDIR"): # MSVC, manual setup
return True
# Otherwise, let SCons find MSVC if installed, or else Mingw.
@@ -23,18 +26,18 @@ def can_build():
# null compiler.
return True
- if (os.name == "posix"):
+ if os.name == "posix":
# Cross-compiling with MinGW-w64 (old MinGW32 is not supported)
mingw32 = "i686-w64-mingw32-"
mingw64 = "x86_64-w64-mingw32-"
- if (os.getenv("MINGW32_PREFIX")):
+ if os.getenv("MINGW32_PREFIX"):
mingw32 = os.getenv("MINGW32_PREFIX")
- if (os.getenv("MINGW64_PREFIX")):
+ if os.getenv("MINGW64_PREFIX"):
mingw64 = os.getenv("MINGW64_PREFIX")
test = "gcc --version > /dev/null 2>&1"
- if (os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0):
+ if os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0:
return True
return False
@@ -45,47 +48,47 @@ def get_opts():
mingw32 = ""
mingw64 = ""
- if (os.name == "posix"):
+ if os.name == "posix":
mingw32 = "i686-w64-mingw32-"
mingw64 = "x86_64-w64-mingw32-"
- if (os.getenv("MINGW32_PREFIX")):
+ if os.getenv("MINGW32_PREFIX"):
mingw32 = os.getenv("MINGW32_PREFIX")
- if (os.getenv("MINGW64_PREFIX")):
+ if os.getenv("MINGW64_PREFIX"):
mingw64 = os.getenv("MINGW64_PREFIX")
return [
- ('mingw_prefix_32', 'MinGW prefix (Win32)', mingw32),
- ('mingw_prefix_64', 'MinGW prefix (Win64)', mingw64),
+ ("mingw_prefix_32", "MinGW prefix (Win32)", mingw32),
+ ("mingw_prefix_64", "MinGW prefix (Win64)", mingw64),
# Targeted Windows version: 7 (and later), minimum supported version
# XP support dropped after EOL due to missing API for IPv6 and other issues
# Vista support dropped after EOL due to GH-10243
- ('target_win_version', 'Targeted Windows version, >= 0x0601 (Windows 7)', '0x0601'),
- EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
- BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
- ('msvc_version', 'MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.', None),
- BoolVariable('use_mingw', 'Use the Mingw compiler, even if MSVC is installed. Only used on Windows.', False),
- BoolVariable('use_llvm', 'Use the LLVM compiler', False),
- BoolVariable('use_thinlto', 'Use ThinLTO', False),
+ ("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"),
+ EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
+ BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
+ ("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None),
+ BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed. Only used on Windows.", False),
+ BoolVariable("use_llvm", "Use the LLVM compiler", False),
+ BoolVariable("use_thinlto", "Use ThinLTO", False),
]
def get_flags():
- return [
- ]
+ return []
def build_res_file(target, source, env):
- if (env["bits"] == "32"):
- cmdbase = env['mingw_prefix_32']
+ if env["bits"] == "32":
+ cmdbase = env["mingw_prefix_32"]
else:
- cmdbase = env['mingw_prefix_64']
- cmdbase = cmdbase + 'windres --include-dir . '
+ cmdbase = env["mingw_prefix_64"]
+ cmdbase = cmdbase + "windres --include-dir . "
import subprocess
+
for x in range(len(source)):
- cmd = cmdbase + '-i ' + str(source[x]) + ' -o ' + str(target[x])
+ cmd = cmdbase + "-i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
@@ -97,12 +100,14 @@ def build_res_file(target, source, env):
def setup_msvc_manual(env):
"""Set up env to use MSVC manually, using VCINSTALLDIR"""
- if (env["bits"] != "default"):
- print("""
+ if env["bits"] != "default":
+ print(
+ """
Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console
(or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits
argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
- """)
+ """
+ )
raise SCons.Errors.UserError("Bits argument should not be used when using VCINSTALLDIR")
# Force bits arg
@@ -111,18 +116,21 @@ def setup_msvc_manual(env):
env["x86_libtheora_opt_vc"] = True
# find compiler manually
- compiler_version_str = methods.detect_visual_c_compiler_version(env['ENV'])
+ compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"])
print("Found MSVC compiler: " + compiler_version_str)
# If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm
- if(compiler_version_str == "amd64" or compiler_version_str == "x86_amd64"):
+ if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64":
env["bits"] = "64"
env["x86_libtheora_opt_vc"] = False
print("Compiled program architecture will be a 64 bit executable (forcing bits=64).")
- elif (compiler_version_str == "x86" or compiler_version_str == "amd64_x86"):
+ elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86":
print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).")
else:
- print("Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR.")
+ print(
+ "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR."
+ )
+
def setup_msvc_auto(env):
"""Set up MSVC using SCons's auto-detection logic"""
@@ -135,103 +143,127 @@ def setup_msvc_auto(env):
# (Ideally we'd decide on the tool config before configuring any
# environment, and just set the env up once, but this function runs
# on an existing env so this is the simplest way.)
- env['MSVC_SETUP_RUN'] = False # Need to set this to re-run the tool
- env['MSVS_VERSION'] = None
- env['MSVC_VERSION'] = None
- env['TARGET_ARCH'] = None
- if env['bits'] != 'default':
- env['TARGET_ARCH'] = {'32': 'x86', '64': 'x86_64'}[env['bits']]
- if env.has_key('msvc_version'):
- env['MSVC_VERSION'] = env['msvc_version']
- env.Tool('msvc')
- env.Tool('mssdk') # we want the MS SDK
+ env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool
+ env["MSVS_VERSION"] = None
+ env["MSVC_VERSION"] = None
+ env["TARGET_ARCH"] = None
+ if env["bits"] != "default":
+ env["TARGET_ARCH"] = {"32": "x86", "64": "x86_64"}[env["bits"]]
+ if env.has_key("msvc_version"):
+ env["MSVC_VERSION"] = env["msvc_version"]
+ env.Tool("msvc")
+ env.Tool("mssdk") # we want the MS SDK
# Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015
# Get actual target arch into bits (it may be "default" at this point):
- if env['TARGET_ARCH'] in ('amd64', 'x86_64'):
- env['bits'] = '64'
+ if env["TARGET_ARCH"] in ("amd64", "x86_64"):
+ env["bits"] = "64"
else:
- env['bits'] = '32'
- print("Found MSVC version %s, arch %s, bits=%s" % (env['MSVC_VERSION'], env['TARGET_ARCH'], env['bits']))
- if env['TARGET_ARCH'] in ('amd64', 'x86_64'):
+ env["bits"] = "32"
+ print("Found MSVC version %s, arch %s, bits=%s" % (env["MSVC_VERSION"], env["TARGET_ARCH"], env["bits"]))
+ if env["TARGET_ARCH"] in ("amd64", "x86_64"):
env["x86_libtheora_opt_vc"] = False
+
def setup_mingw(env):
"""Set up env for use with mingw"""
# Nothing to do here
print("Using MinGW")
pass
+
def configure_msvc(env, manual_msvc_config):
"""Configure env to work with MSVC"""
# Build type
- if (env["target"] == "release"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Append(CCFLAGS=['/O2'])
- else: # optimize for size
- env.Append(CCFLAGS=['/O1'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
- 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(CCFLAGS=['/O1'])
- env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/OPT:REF'])
-
- elif (env["target"] == "debug"):
- env.AppendUnique(CCFLAGS=['/Z7', '/Od', '/EHsc'])
- env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED',
- 'D3D_DEBUG_INFO'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG'])
-
- if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes"):
- env.AppendUnique(CCFLAGS=['/Z7'])
- env.AppendUnique(LINKFLAGS=['/DEBUG'])
+ if env["target"] == "release":
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Append(CCFLAGS=["/O2"])
+ else: # optimize for size
+ env.Append(CCFLAGS=["/O1"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
+ 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(CCFLAGS=["/O1"])
+ env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
+ env.Append(LINKFLAGS=["/OPT:REF"])
+
+ elif env["target"] == "debug":
+ env.AppendUnique(CCFLAGS=["/Z7", "/Od", "/EHsc"])
+ env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED", "D3D_DEBUG_INFO"])
+ env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
+ env.Append(LINKFLAGS=["/DEBUG"])
+
+ if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
+ env.AppendUnique(CCFLAGS=["/Z7"])
+ env.AppendUnique(LINKFLAGS=["/DEBUG"])
## Compile/link flags
- env.AppendUnique(CCFLAGS=['/MT', '/Gd', '/GR', '/nologo'])
- if int(env['MSVC_VERSION'].split('.')[0]) >= 14: #vs2015 and later
- env.AppendUnique(CCFLAGS=['/utf-8'])
- env.AppendUnique(CXXFLAGS=['/TP']) # assume all sources are C++
- if manual_msvc_config: # should be automatic if SCons found it
+ env.AppendUnique(CCFLAGS=["/MT", "/Gd", "/GR", "/nologo"])
+ if int(env["MSVC_VERSION"].split(".")[0]) >= 14: # vs2015 and later
+ env.AppendUnique(CCFLAGS=["/utf-8"])
+ env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
+ if manual_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
env.Prepend(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"])
else:
print("Missing environment variable: WindowsSdkDir")
- env.AppendUnique(CPPDEFINES = ['WINDOWS_ENABLED',
- 'WASAPI_ENABLED', 'WINMIDI_ENABLED',
- 'TYPED_METHOD_BIND',
- 'WIN32', 'MSVC',
- 'WINVER=%s' % env["target_win_version"],
- '_WIN32_WINNT=%s' % env["target_win_version"]])
- env.AppendUnique(CPPDEFINES=['NOMINMAX']) # disable bogus min/max WinDef.h macros
+ env.AppendUnique(
+ CPPDEFINES=[
+ "WINDOWS_ENABLED",
+ "WASAPI_ENABLED",
+ "WINMIDI_ENABLED",
+ "TYPED_METHOD_BIND",
+ "WIN32",
+ "MSVC",
+ "WINVER=%s" % env["target_win_version"],
+ "_WIN32_WINNT=%s" % env["target_win_version"],
+ ]
+ )
+ env.AppendUnique(CPPDEFINES=["NOMINMAX"]) # disable bogus min/max WinDef.h macros
if env["bits"] == "64":
- env.AppendUnique(CPPDEFINES=['_WIN64'])
+ env.AppendUnique(CPPDEFINES=["_WIN64"])
## Libs
- LIBS = ['winmm', 'dsound', 'kernel32', 'ole32', 'oleaut32',
- 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32',
- 'shell32', 'advapi32', 'dinput8', 'dxguid', 'imm32', 'bcrypt', 'Avrt',
- 'dwmapi']
+ LIBS = [
+ "winmm",
+ "dsound",
+ "kernel32",
+ "ole32",
+ "oleaut32",
+ "user32",
+ "gdi32",
+ "IPHLPAPI",
+ "Shlwapi",
+ "wsock32",
+ "Ws2_32",
+ "shell32",
+ "advapi32",
+ "dinput8",
+ "dxguid",
+ "imm32",
+ "bcrypt",
+ "Avrt",
+ "dwmapi",
+ ]
- env.AppendUnique(CPPDEFINES=['VULKAN_ENABLED'])
- if not env['builtin_vulkan']:
- LIBS += ['vulkan']
+ env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["builtin_vulkan"]:
+ LIBS += ["vulkan"]
else:
- LIBS += ['cfgmgr32']
+ LIBS += ["cfgmgr32"]
- #env.AppendUnique(CPPDEFINES = ['OPENGL_ENABLED'])
- LIBS += ['opengl32']
+ # env.AppendUnique(CPPDEFINES = ['OPENGL_ENABLED'])
+ LIBS += ["opengl32"]
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
@@ -243,21 +275,24 @@ def configure_msvc(env, manual_msvc_config):
## LTO
- if (env["use_lto"]):
- env.AppendUnique(CCFLAGS=['/GL'])
- env.AppendUnique(ARFLAGS=['/LTCG'])
+ if env["use_lto"]:
+ env.AppendUnique(CCFLAGS=["/GL"])
+ env.AppendUnique(ARFLAGS=["/LTCG"])
if env["progress"]:
- env.AppendUnique(LINKFLAGS=['/LTCG:STATUS'])
+ env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"])
else:
- env.AppendUnique(LINKFLAGS=['/LTCG'])
+ env.AppendUnique(LINKFLAGS=["/LTCG"])
if 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(";")])
# Incremental linking fix
- env['BUILDERS']['ProgramOriginal'] = env['BUILDERS']['Program']
- env['BUILDERS']['Program'] = methods.precious_program
+ env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
+ env["BUILDERS"]["Program"] = methods.precious_program
+
+ env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
+
def configure_mingw(env):
# Workaround for MinGW. See:
@@ -266,124 +301,148 @@ def configure_mingw(env):
## Build type
- if (env["target"] == "release"):
- env.Append(CCFLAGS=['-msse2'])
+ if env["target"] == "release":
+ env.Append(CCFLAGS=["-msse2"])
- if (env["optimize"] == "speed"): #optimize for speed (default)
- if (env["bits"] == "64"):
- env.Append(CCFLAGS=['-O3'])
+ if env["optimize"] == "speed": # optimize for speed (default)
+ if env["bits"] == "64":
+ env.Append(CCFLAGS=["-O3"])
else:
- env.Append(CCFLAGS=['-O2'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
-
-
- env.Append(LINKFLAGS=['-Wl,--subsystem,windows'])
-
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "release_debug"):
- env.Append(CCFLAGS=['-O2'])
- env.Append(CPPDEFINES=['DEBUG_ENABLED'])
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Append(CCFLAGS=['-O2'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
-
- elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['-g3'])
- env.Append(CPPDEFINES=['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
+ env.Append(CCFLAGS=["-O2"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+
+ env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
+
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+
+ elif env["target"] == "release_debug":
+ env.Append(CCFLAGS=["-O2"])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED"])
+ if env["debug_symbols"] == "yes":
+ env.Prepend(CCFLAGS=["-g1"])
+ if env["debug_symbols"] == "full":
+ env.Prepend(CCFLAGS=["-g2"])
+ if env["optimize"] == "speed": # optimize for speed (default)
+ env.Append(CCFLAGS=["-O2"])
+ else: # optimize for size
+ env.Prepend(CCFLAGS=["-Os"])
+
+ elif env["target"] == "debug":
+ env.Append(CCFLAGS=["-g3"])
+ env.Append(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_MEMORY_ENABLED"])
## Compiler configuration
if os.name != "nt":
env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation
- if (env["bits"] == "default"):
- if (os.name == "nt"):
+ if env["bits"] == "default":
+ if os.name == "nt":
env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32"
- else: # default to 64-bit on Linux
+ else: # default to 64-bit on Linux
env["bits"] = "64"
mingw_prefix = ""
- if (env["bits"] == "32"):
- env.Append(LINKFLAGS=['-static'])
- env.Append(LINKFLAGS=['-static-libgcc'])
- env.Append(LINKFLAGS=['-static-libstdc++'])
+ if env["bits"] == "32":
+ env.Append(LINKFLAGS=["-static"])
+ env.Append(LINKFLAGS=["-static-libgcc"])
+ env.Append(LINKFLAGS=["-static-libstdc++"])
mingw_prefix = env["mingw_prefix_32"]
else:
- env.Append(LINKFLAGS=['-static'])
+ env.Append(LINKFLAGS=["-static"])
mingw_prefix = env["mingw_prefix_64"]
- if env['use_llvm']:
+ if env["use_llvm"]:
env["CC"] = mingw_prefix + "clang"
- env['AS'] = mingw_prefix + "as"
+ env["AS"] = mingw_prefix + "as"
env["CXX"] = mingw_prefix + "clang++"
- env['AR'] = mingw_prefix + "ar"
- env['RANLIB'] = mingw_prefix + "ranlib"
+ env["AR"] = mingw_prefix + "ar"
+ env["RANLIB"] = mingw_prefix + "ranlib"
env["LINK"] = mingw_prefix + "clang++"
else:
env["CC"] = mingw_prefix + "gcc"
- env['AS'] = mingw_prefix + "as"
- env['CXX'] = mingw_prefix + "g++"
- env['AR'] = mingw_prefix + "gcc-ar"
- env['RANLIB'] = mingw_prefix + "gcc-ranlib"
- env['LINK'] = mingw_prefix + "g++"
+ env["AS"] = mingw_prefix + "as"
+ env["CXX"] = mingw_prefix + "g++"
+ env["AR"] = mingw_prefix + "gcc-ar"
+ env["RANLIB"] = mingw_prefix + "gcc-ranlib"
+ env["LINK"] = mingw_prefix + "g++"
env["x86_libtheora_opt_gcc"] = True
- if env['use_lto']:
- if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
- env.Append(CCFLAGS=['-flto'])
- env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
+ if env["use_lto"]:
+ if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
+ env.Append(CCFLAGS=["-flto"])
+ env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
else:
- if env['use_thinlto']:
- env.Append(CCFLAGS=['-flto=thin'])
- env.Append(LINKFLAGS=['-flto=thin'])
+ if env["use_thinlto"]:
+ env.Append(CCFLAGS=["-flto=thin"])
+ env.Append(LINKFLAGS=["-flto=thin"])
else:
- env.Append(CCFLAGS=['-flto'])
- env.Append(LINKFLAGS=['-flto'])
+ env.Append(CCFLAGS=["-flto"])
+ env.Append(LINKFLAGS=["-flto"])
+ env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)])
## Compile flags
- env.Append(CCFLAGS=['-mwindows'])
-
- env.Append(CPPDEFINES=['WINDOWS_ENABLED', 'WASAPI_ENABLED', 'WINMIDI_ENABLED'])
- env.Append(CPPDEFINES=[('WINVER', env['target_win_version']), ('_WIN32_WINNT', env['target_win_version'])])
- env.Append(LIBS=['mingw32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'imm32', 'bcrypt', 'avrt', 'uuid', 'dwmapi'])
-
- env.Append(CPPDEFINES=['VULKAN_ENABLED'])
- if not env['builtin_vulkan']:
- env.Append(LIBS=['vulkan'])
+ env.Append(CCFLAGS=["-mwindows"])
+
+ env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"])
+ env.Append(CPPDEFINES=[("WINVER", env["target_win_version"]), ("_WIN32_WINNT", env["target_win_version"])])
+ env.Append(
+ LIBS=[
+ "mingw32",
+ "dsound",
+ "ole32",
+ "d3d9",
+ "winmm",
+ "gdi32",
+ "iphlpapi",
+ "shlwapi",
+ "wsock32",
+ "ws2_32",
+ "kernel32",
+ "oleaut32",
+ "dinput8",
+ "dxguid",
+ "ksuser",
+ "imm32",
+ "bcrypt",
+ "avrt",
+ "uuid",
+ "dwmapi",
+ ]
+ )
+
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["builtin_vulkan"]:
+ env.Append(LIBS=["vulkan"])
else:
- env.Append(LIBS=['cfgmgr32'])
+ env.Append(LIBS=["cfgmgr32"])
## TODO !!! Reenable when OpenGLES Rendering Device is implemented !!!
- #env.Append(CPPDEFINES=['OPENGL_ENABLED'])
- env.Append(LIBS=['opengl32'])
+ # env.Append(CPPDEFINES=['OPENGL_ENABLED'])
+ env.Append(LIBS=["opengl32"])
- env.Append(CPPDEFINES=['MINGW_ENABLED', ('MINGW_HAS_SECURE_API', 1)])
+ env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
# resrc
- env.Append(BUILDERS={'RES': env.Builder(action=build_res_file, suffix='.o', src_suffix='.rc')})
+ env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")})
+
def configure(env):
# At this point the env has been set up with basic tools/compilers.
- env.Prepend(CPPPATH=['#platform/windows'])
+ env.Prepend(CPPPATH=["#platform/windows"])
- print("Configuring for Windows: target=%s, bits=%s" % (env['target'], env['bits']))
+ print("Configuring for Windows: target=%s, bits=%s" % (env["target"], env["bits"]))
- if (os.name == "nt"):
- env['ENV'] = os.environ # this makes build less repeatable, but simplifies some things
- env['ENV']['TMP'] = os.environ['TMP']
+ if os.name == "nt":
+ env["ENV"] = os.environ # this makes build less repeatable, but simplifies some things
+ env["ENV"]["TMP"] = os.environ["TMP"]
# First figure out which compiler, version, and target arch we're using
if os.getenv("VCINSTALLDIR") and not env["use_mingw"]:
@@ -391,7 +450,7 @@ def configure(env):
setup_msvc_manual(env)
env.msvc = True
manual_msvc_config = True
- elif env.get('MSVC_VERSION', '') and not env["use_mingw"]:
+ elif env.get("MSVC_VERSION", "") and not env["use_mingw"]:
setup_msvc_auto(env)
env.msvc = True
manual_msvc_config = False
@@ -403,5 +462,5 @@ def configure(env):
if env.msvc:
configure_msvc(env, manual_msvc_config)
- else: # MinGW
+ else: # MinGW
configure_mingw(env)
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
new file mode 100644
index 0000000000..ebe9a7d27a
--- /dev/null
+++ b/platform/windows/display_server_windows.cpp
@@ -0,0 +1,3007 @@
+/*************************************************************************/
+/* display_server_windows.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "display_server_windows.h"
+#include "core/io/marshalls.h"
+#include "main/main.h"
+#include "os_windows.h"
+#include "scene/resources/texture.h"
+
+#include <avrt.h>
+
+#ifndef WM_POINTERUPDATE
+#define WM_POINTERUPDATE 0x0245
+#endif
+
+#ifdef DEBUG_ENABLED
+static String format_error_message(DWORD id) {
+
+ LPWSTR messageBuffer = nullptr;
+ size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
+
+ String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
+
+ LocalFree(messageBuffer);
+
+ return msg;
+}
+#endif // DEBUG_ENABLED
+
+bool DisplayServerWindows::has_feature(Feature p_feature) const {
+ switch (p_feature) {
+ case FEATURE_SUBWINDOWS:
+ case FEATURE_TOUCHSCREEN:
+ case FEATURE_MOUSE:
+ case FEATURE_MOUSE_WARP:
+ case FEATURE_CLIPBOARD:
+ case FEATURE_CURSOR_SHAPE:
+ case FEATURE_CUSTOM_CURSOR_SHAPE:
+ case FEATURE_CONSOLE_WINDOW:
+ case FEATURE_IME:
+ case FEATURE_WINDOW_TRANSPARENCY:
+ case FEATURE_HIDPI:
+ case FEATURE_ICON:
+ case FEATURE_NATIVE_ICON:
+ case FEATURE_SWAP_BUFFERS:
+ case FEATURE_KEEP_SCREEN_ON:
+ return true;
+ default:
+ return false;
+ }
+}
+
+String DisplayServerWindows::get_name() const {
+ return "Windows";
+}
+
+void DisplayServerWindows::alert(const String &p_alert, const String &p_title) {
+ MessageBoxW(nullptr, p_alert.c_str(), p_title.c_str(), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
+}
+
+void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
+
+ if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED) {
+ WindowData &wd = windows[MAIN_WINDOW_ID];
+
+ RECT clipRect;
+ GetClientRect(wd.hWnd, &clipRect);
+ ClientToScreen(wd.hWnd, (POINT *)&clipRect.left);
+ ClientToScreen(wd.hWnd, (POINT *)&clipRect.right);
+ ClipCursor(&clipRect);
+ if (p_mode == MOUSE_MODE_CAPTURED) {
+
+ center = window_get_size() / 2;
+ POINT pos = { (int)center.x, (int)center.y };
+ ClientToScreen(wd.hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+ SetCapture(wd.hWnd);
+ }
+ } else {
+ ReleaseCapture();
+ ClipCursor(nullptr);
+ }
+
+ if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_HIDDEN) {
+ hCursor = SetCursor(nullptr);
+ } else {
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ cursor_set_shape(c);
+ }
+}
+void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (mouse_mode == p_mode)
+ return;
+
+ _set_mouse_mode_impl(p_mode);
+
+ mouse_mode = p_mode;
+}
+DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const {
+ return mouse_mode;
+}
+
+void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (!windows.has(last_focused_window)) {
+ return; //no window focused?
+ }
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+
+ old_x = p_to.x;
+ old_y = p_to.y;
+ } else {
+
+ POINT p;
+ p.x = p_to.x;
+ p.y = p_to.y;
+ ClientToScreen(windows[last_focused_window].hWnd, &p);
+
+ SetCursorPos(p.x, p.y);
+ }
+}
+Point2i DisplayServerWindows::mouse_get_position() const {
+ POINT p;
+ GetCursorPos(&p);
+ return Point2i(p.x, p.y);
+ //return Point2(old_x, old_y);
+}
+int DisplayServerWindows::mouse_get_button_state() const {
+ return last_button_state;
+}
+
+void DisplayServerWindows::clipboard_set(const String &p_text) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (!windows.has(last_focused_window)) {
+ return; //no window focused?
+ }
+
+ // Convert LF line endings to CRLF in clipboard content
+ // Otherwise, line endings won't be visible when pasted in other software
+ String text = p_text.replace("\n", "\r\n");
+
+ if (!OpenClipboard(windows[last_focused_window].hWnd)) {
+ ERR_FAIL_MSG("Unable to open clipboard.");
+ }
+ EmptyClipboard();
+
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType));
+ ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
+
+ LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
+ memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType));
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_UNICODETEXT, mem);
+
+ // set the CF_TEXT version (not needed?)
+ CharString utf8 = text.utf8();
+ mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
+ ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
+
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ memcpy(ptr, utf8.get_data(), utf8.length());
+ ptr[utf8.length()] = 0;
+ GlobalUnlock(mem);
+
+ SetClipboardData(CF_TEXT, mem);
+
+ CloseClipboard();
+}
+String DisplayServerWindows::clipboard_get() const {
+
+ _THREAD_SAFE_METHOD_
+
+ if (!windows.has(last_focused_window)) {
+ return String(); //no window focused?
+ }
+
+ String ret;
+ if (!OpenClipboard(windows[last_focused_window].hWnd)) {
+ ERR_FAIL_V_MSG("", "Unable to open clipboard.");
+ };
+
+ if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != nullptr) {
+
+ LPWSTR ptr = (LPWSTR)GlobalLock(mem);
+ if (ptr != nullptr) {
+
+ ret = String((CharType *)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+
+ } else if (IsClipboardFormatAvailable(CF_TEXT)) {
+
+ HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+ if (mem != nullptr) {
+
+ LPTSTR ptr = (LPTSTR)GlobalLock(mem);
+ if (ptr != nullptr) {
+
+ ret.parse_utf8((const char *)ptr);
+ GlobalUnlock(mem);
+ };
+ };
+ };
+
+ CloseClipboard();
+
+ return ret;
+}
+
+typedef struct {
+ int count;
+ int screen;
+ HMONITOR monitor;
+} EnumScreenData;
+
+static BOOL CALLBACK _MonitorEnumProcScreen(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+
+ EnumScreenData *data = (EnumScreenData *)dwData;
+ if (data->monitor == hMonitor) {
+ data->screen = data->count;
+ }
+
+ data->count++;
+ return TRUE;
+}
+
+static BOOL CALLBACK _MonitorEnumProcCount(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+
+ int *data = (int *)dwData;
+ (*data)++;
+ return TRUE;
+}
+
+int DisplayServerWindows::get_screen_count() const {
+ _THREAD_SAFE_METHOD_
+
+ int data = 0;
+ EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcCount, (LPARAM)&data);
+ return data;
+}
+
+typedef struct {
+ int count;
+ int screen;
+ Point2 pos;
+} EnumPosData;
+
+static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+
+ EnumPosData *data = (EnumPosData *)dwData;
+ if (data->count == data->screen) {
+ data->pos.x = lprcMonitor->left;
+ data->pos.y = lprcMonitor->top;
+ }
+
+ data->count++;
+ return TRUE;
+}
+Point2i DisplayServerWindows::screen_get_position(int p_screen) const {
+
+ _THREAD_SAFE_METHOD_
+
+ EnumPosData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Point2() };
+ EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPos, (LPARAM)&data);
+ return data.pos;
+}
+
+typedef struct {
+ int count;
+ int screen;
+ Size2 size;
+} EnumSizeData;
+
+typedef struct {
+ int count;
+ int screen;
+ Rect2i rect;
+} EnumRectData;
+
+static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+
+ EnumSizeData *data = (EnumSizeData *)dwData;
+ if (data->count == data->screen) {
+ data->size.x = lprcMonitor->right - lprcMonitor->left;
+ data->size.y = lprcMonitor->bottom - lprcMonitor->top;
+ }
+
+ data->count++;
+ return TRUE;
+}
+
+Size2i DisplayServerWindows::screen_get_size(int p_screen) const {
+
+ _THREAD_SAFE_METHOD_
+
+ EnumSizeData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Size2() };
+ EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcSize, (LPARAM)&data);
+ return data.size;
+}
+
+static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+
+ EnumRectData *data = (EnumRectData *)dwData;
+ if (data->count == data->screen) {
+ MONITORINFO minfo;
+ zeromem(&minfo, sizeof(MONITORINFO));
+ minfo.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfoA(hMonitor, &minfo);
+
+ data->rect.position.x = minfo.rcWork.left;
+ data->rect.position.y = minfo.rcWork.top;
+ data->rect.size.x = minfo.rcWork.right - minfo.rcWork.left;
+ data->rect.size.y = minfo.rcWork.bottom - minfo.rcWork.top;
+ }
+
+ data->count++;
+ return TRUE;
+}
+
+Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const {
+
+ _THREAD_SAFE_METHOD_
+
+ EnumRectData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Rect2i() };
+ EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcUsableSize, (LPARAM)&data);
+ return data.rect;
+}
+
+typedef struct {
+ int count;
+ int screen;
+ int dpi;
+} EnumDpiData;
+
+enum _MonitorDpiType {
+ MDT_Effective_DPI = 0,
+ MDT_Angular_DPI = 1,
+ MDT_Raw_DPI = 2,
+ MDT_Default = MDT_Effective_DPI
+};
+
+static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Default) {
+
+ int dpiX = 96, dpiY = 96;
+
+ static HMODULE Shcore = nullptr;
+ typedef HRESULT(WINAPI * GetDPIForMonitor_t)(HMONITOR hmonitor, _MonitorDpiType dpiType, UINT * dpiX, UINT * dpiY);
+ static GetDPIForMonitor_t getDPIForMonitor = nullptr;
+
+ if (Shcore == nullptr) {
+ Shcore = LoadLibraryW(L"Shcore.dll");
+ getDPIForMonitor = Shcore ? (GetDPIForMonitor_t)GetProcAddress(Shcore, "GetDpiForMonitor") : nullptr;
+
+ if ((Shcore == nullptr) || (getDPIForMonitor == nullptr)) {
+ if (Shcore)
+ FreeLibrary(Shcore);
+ Shcore = (HMODULE)INVALID_HANDLE_VALUE;
+ }
+ }
+
+ UINT x = 0, y = 0;
+ HRESULT hr = E_FAIL;
+ if (hmon && (Shcore != (HMODULE)INVALID_HANDLE_VALUE)) {
+ hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y);
+ if (SUCCEEDED(hr) && (x > 0) && (y > 0)) {
+
+ dpiX = (int)x;
+ dpiY = (int)y;
+ }
+ } else {
+ static int overallX = 0, overallY = 0;
+ if (overallX <= 0 || overallY <= 0) {
+ HDC hdc = GetDC(nullptr);
+ if (hdc) {
+ overallX = GetDeviceCaps(hdc, LOGPIXELSX);
+ overallY = GetDeviceCaps(hdc, LOGPIXELSY);
+ ReleaseDC(nullptr, hdc);
+ }
+ }
+ if (overallX > 0 && overallY > 0) {
+ dpiX = overallX;
+ dpiY = overallY;
+ }
+ }
+
+ return (dpiX + dpiY) / 2;
+}
+
+static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+
+ EnumDpiData *data = (EnumDpiData *)dwData;
+ if (data->count == data->screen) {
+ data->dpi = QueryDpiForMonitor(hMonitor);
+ }
+
+ data->count++;
+ return TRUE;
+}
+
+int DisplayServerWindows::screen_get_dpi(int p_screen) const {
+ _THREAD_SAFE_METHOD_
+
+ EnumDpiData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, 72 };
+ EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data);
+ return data.dpi;
+}
+bool DisplayServerWindows::screen_is_touchscreen(int p_screen) const {
+#ifndef _MSC_VER
+#warning touchscreen not working
+#endif
+ return false;
+}
+
+void DisplayServerWindows::screen_set_orientation(ScreenOrientation p_orientation, int p_screen) {
+}
+DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(int p_screen) const {
+ return SCREEN_LANDSCAPE;
+}
+
+void DisplayServerWindows::screen_set_keep_on(bool p_enable) {
+}
+bool DisplayServerWindows::screen_is_kept_on() const {
+ return false;
+}
+
+Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const {
+
+ _THREAD_SAFE_METHOD_
+
+ Vector<DisplayServer::WindowID> ret;
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+ return ret;
+}
+
+DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(const Point2i &p_position) const {
+
+ POINT p;
+ p.x = p_position.x;
+ p.y = p_position.y;
+ HWND hwnd = WindowFromPoint(p);
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (E->get().hWnd == hwnd) {
+ return E->key();
+ }
+ }
+
+ return INVALID_WINDOW_ID;
+}
+
+DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+
+ _THREAD_SAFE_METHOD_
+
+ WindowID window_id = _create_window(p_mode, p_flags, p_rect);
+
+ WindowData &wd = windows[window_id];
+
+ if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) {
+ wd.resizable = false;
+ }
+ if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
+ wd.borderless = true;
+ }
+ if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN) {
+ wd.always_on_top = true;
+ }
+ if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
+ wd.no_focus = true;
+ }
+
+ _update_window_style(window_id);
+
+ ShowWindow(wd.hWnd, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
+ if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
+ SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
+ SetFocus(wd.hWnd); // Sets Keyboard Focus To
+ }
+
+ return window_id;
+}
+void DisplayServerWindows::delete_sub_window(WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window cannot be deleted.");
+
+ WindowData &wd = windows[p_window];
+
+ while (wd.transient_children.size()) {
+ window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID);
+ }
+
+ if (wd.transient_parent != INVALID_WINDOW_ID) {
+ window_set_transient(p_window, INVALID_WINDOW_ID);
+ }
+
+#ifdef VULKAN_ENABLED
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_destroy(p_window);
+ }
+#endif
+
+ DestroyWindow(windows[p_window].hWnd);
+ windows.erase(p_window);
+}
+
+void DisplayServerWindows::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].instance_id = p_instance;
+}
+
+ObjectID DisplayServerWindows::window_get_attached_instance_id(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), ObjectID());
+ return windows[p_window].instance_id;
+}
+
+void DisplayServerWindows::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].rect_changed_callback = p_callable;
+}
+
+void DisplayServerWindows::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].event_callback = p_callable;
+}
+void DisplayServerWindows::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].input_event_callback = p_callable;
+}
+void DisplayServerWindows::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].input_text_callback = p_callable;
+}
+
+void DisplayServerWindows::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].drop_files_callback = p_callable;
+}
+
+void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ SetWindowTextW(windows[p_window].hWnd, p_title.c_str());
+}
+
+int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), -1);
+
+ EnumScreenData data = { 0, 0, MonitorFromWindow(windows[p_window].hWnd, MONITOR_DEFAULTTONEAREST) };
+ EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcScreen, (LPARAM)&data);
+ return data.screen;
+}
+void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ ERR_FAIL_INDEX(p_screen, get_screen_count());
+
+ Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
+ window_set_position(ofs + screen_get_position(p_screen), p_window);
+}
+
+Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
+ const WindowData &wd = windows[p_window];
+
+ if (wd.minimized) {
+ return wd.last_pos;
+ }
+
+ POINT point;
+ point.x = 0;
+ point.y = 0;
+
+ ClientToScreen(wd.hWnd, &point);
+
+ return Point2i(point.x, point.y);
+
+#if 0
+ //do not use this method, as it includes windows decorations
+ RECT r;
+ GetWindowRect(wd.hWnd, &r);
+ return Point2(r.left, r.top);
+#endif
+}
+void DisplayServerWindows::_update_real_mouse_position(WindowID p_window) {
+
+ POINT mouse_pos;
+ if (GetCursorPos(&mouse_pos) && ScreenToClient(windows[p_window].hWnd, &mouse_pos)) {
+ if (mouse_pos.x > 0 && mouse_pos.y > 0 && mouse_pos.x <= windows[p_window].width && mouse_pos.y <= windows[p_window].height) {
+ old_x = mouse_pos.x;
+ old_y = mouse_pos.y;
+ old_invalid = false;
+ InputFilter::get_singleton()->set_mouse_position(Point2i(mouse_pos.x, mouse_pos.y));
+ }
+ }
+}
+void DisplayServerWindows::window_set_position(const Point2i &p_position, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if (wd.fullscreen) return;
+#if 0
+ //wrong needs to account properly for decorations
+ RECT r;
+ GetWindowRect(wd.hWnd, &r);
+ MoveWindow(wd.hWnd, p_position.x, p_position.y, r.right - r.left, r.bottom - r.top, TRUE);
+#else
+
+ RECT rc;
+ rc.left = p_position.x;
+ rc.right = p_position.x + wd.width;
+ rc.bottom = p_position.y + wd.height;
+ rc.top = p_position.y;
+
+ const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE);
+ const DWORD exStyle = GetWindowLongPtr(wd.hWnd, GWL_EXSTYLE);
+
+ AdjustWindowRectEx(&rc, style, false, exStyle);
+ MoveWindow(wd.hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+#endif
+ // Don't let the mouse leave the window when moved
+ if (mouse_mode == MOUSE_MODE_CONFINED) {
+ RECT rect;
+ GetClientRect(wd.hWnd, &rect);
+ ClientToScreen(wd.hWnd, (POINT *)&rect.left);
+ ClientToScreen(wd.hWnd, (POINT *)&rect.right);
+ ClipCursor(&rect);
+ }
+
+ wd.last_pos = p_position;
+ _update_real_mouse_position(p_window);
+}
+
+void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_parent) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(p_window == p_parent);
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd_window = windows[p_window];
+
+ ERR_FAIL_COND(wd_window.transient_parent == p_parent);
+
+ ERR_FAIL_COND_MSG(wd_window.always_on_top, "Windows with the 'on top' can't become transient.");
+
+ if (p_parent == INVALID_WINDOW_ID) {
+ //remove transient
+
+ ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
+ ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
+
+ WindowData &wd_parent = windows[wd_window.transient_parent];
+
+ wd_window.transient_parent = INVALID_WINDOW_ID;
+ wd_parent.transient_children.erase(p_window);
+
+ SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr);
+ } else {
+ ERR_FAIL_COND(!windows.has(p_parent));
+ ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
+ WindowData &wd_parent = windows[p_parent];
+
+ wd_window.transient_parent = p_parent;
+ wd_parent.transient_children.insert(p_window);
+
+ SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd);
+ }
+}
+
+void DisplayServerWindows::window_set_max_size(const Size2i p_size, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if ((p_size != Size2()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
+ ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
+ return;
+ }
+ wd.max_size = p_size;
+}
+Size2i DisplayServerWindows::window_get_max_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+ return wd.max_size;
+}
+
+void DisplayServerWindows::window_set_min_size(const Size2i p_size, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if ((p_size != Size2()) && (wd.max_size != Size2()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
+ ERR_PRINT("Minimum window size can't be larger than maximum window size!");
+ return;
+ }
+ wd.min_size = p_size;
+}
+Size2i DisplayServerWindows::window_get_min_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+ return wd.min_size;
+}
+
+void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ int w = p_size.width;
+ int h = p_size.height;
+
+ wd.width = w;
+ wd.height = h;
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_resize(p_window, w, h);
+ }
+#endif
+
+ if (wd.fullscreen) {
+ return;
+ }
+
+ RECT rect;
+ GetWindowRect(wd.hWnd, &rect);
+
+ if (!wd.borderless) {
+ RECT crect;
+ GetClientRect(wd.hWnd, &crect);
+
+ w += (rect.right - rect.left) - (crect.right - crect.left);
+ h += (rect.bottom - rect.top) - (crect.bottom - crect.top);
+ }
+
+ MoveWindow(wd.hWnd, rect.left, rect.top, w, h, TRUE);
+
+ // Don't let the mouse leave the window when resizing to a smaller resolution
+ if (mouse_mode == MOUSE_MODE_CONFINED) {
+ RECT crect;
+ GetClientRect(wd.hWnd, &crect);
+ ClientToScreen(wd.hWnd, (POINT *)&crect.left);
+ ClientToScreen(wd.hWnd, (POINT *)&crect.right);
+ ClipCursor(&crect);
+ }
+}
+Size2i DisplayServerWindows::window_get_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+
+ if (wd.minimized) {
+ return Size2(wd.width, wd.height);
+ }
+
+ RECT r;
+ if (GetClientRect(wd.hWnd, &r)) { // Only area inside of window border
+ return Size2(r.right - r.left, r.bottom - r.top);
+ }
+ return Size2();
+}
+Size2i DisplayServerWindows::window_get_real_size(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
+ const WindowData &wd = windows[p_window];
+
+ RECT r;
+ if (GetWindowRect(wd.hWnd, &r)) { // Includes area of the window border
+ return Size2(r.right - r.left, r.bottom - r.top);
+ }
+ return Size2();
+}
+
+void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
+
+ r_style = 0;
+ r_style_ex = WS_EX_WINDOWEDGE;
+ if (p_main_window) {
+ r_style_ex |= WS_EX_APPWINDOW;
+ }
+
+ if (p_fullscreen || p_borderless) {
+ r_style |= WS_POPUP;
+ //if (p_borderless) {
+ // r_style_ex |= WS_EX_TOOLWINDOW;
+ //}
+ } else {
+
+ if (p_resizable) {
+ if (p_maximized) {
+ r_style = WS_OVERLAPPEDWINDOW | WS_MAXIMIZE;
+ } else {
+ r_style = WS_OVERLAPPEDWINDOW;
+ }
+ } else {
+ r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
+ }
+ }
+
+ if (p_no_activate_focus) {
+ r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;
+ }
+ r_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+}
+
+void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repaint, bool p_maximized) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ DWORD style = 0;
+ DWORD style_ex = 0;
+
+ _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex);
+
+ SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
+ SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
+
+ SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | (wd.no_focus ? SWP_NOACTIVATE : 0));
+
+ if (p_repaint) {
+ RECT rect;
+ GetWindowRect(wd.hWnd, &rect);
+ MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
+ }
+}
+
+void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if (wd.fullscreen && p_mode != WINDOW_MODE_FULLSCREEN) {
+
+ RECT rect;
+
+ wd.fullscreen = false;
+
+ if (wd.pre_fs_valid) {
+ rect = wd.pre_fs_rect;
+ } else {
+ rect.left = 0;
+ rect.right = wd.width;
+ rect.top = 0;
+ rect.bottom = wd.height;
+ }
+
+ _update_window_style(p_window, false, wd.was_maximized);
+
+ MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
+
+ wd.pre_fs_valid = true;
+ }
+
+ if (p_mode == WINDOW_MODE_MAXIMIZED) {
+
+ ShowWindow(wd.hWnd, SW_MAXIMIZE);
+ wd.maximized = true;
+ wd.minimized = false;
+ }
+
+ if (p_mode == WINDOW_MODE_WINDOWED) {
+
+ ShowWindow(wd.hWnd, SW_RESTORE);
+ wd.maximized = false;
+ wd.minimized = false;
+ }
+
+ if (p_mode == WINDOW_MODE_MINIMIZED) {
+
+ ShowWindow(wd.hWnd, SW_MINIMIZE);
+ wd.maximized = false;
+ wd.minimized = true;
+ }
+
+ if (p_mode == WINDOW_MODE_FULLSCREEN && !wd.fullscreen) {
+ if (wd.minimized) {
+ ShowWindow(wd.hWnd, SW_RESTORE);
+ }
+ wd.was_maximized = wd.maximized;
+
+ if (wd.pre_fs_valid) {
+ GetWindowRect(wd.hWnd, &wd.pre_fs_rect);
+ }
+
+ int cs = window_get_current_screen(p_window);
+ Point2 pos = screen_get_position(cs);
+ Size2 size = screen_get_size(cs);
+
+ wd.fullscreen = true;
+ wd.maximized = false;
+ wd.minimized = false;
+
+ _update_window_style(false);
+
+ MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
+ }
+}
+DisplayServer::WindowMode DisplayServerWindows::window_get_mode(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
+ const WindowData &wd = windows[p_window];
+
+ if (wd.fullscreen) {
+ return WINDOW_MODE_FULLSCREEN;
+ } else if (wd.minimized) {
+ return WINDOW_MODE_MINIMIZED;
+ } else if (wd.maximized) {
+ return WINDOW_MODE_MAXIMIZED;
+ } else {
+ return WINDOW_MODE_WINDOWED;
+ }
+}
+
+bool DisplayServerWindows::window_is_maximize_allowed(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+
+ // FIXME: Implement this, or confirm that it should always be true.
+
+ return true; //no idea
+}
+
+void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+ switch (p_flag) {
+ case WINDOW_FLAG_RESIZE_DISABLED: {
+
+ wd.resizable = !p_enabled;
+ _update_window_style(p_window);
+ } break;
+ case WINDOW_FLAG_BORDERLESS: {
+
+ wd.borderless = p_enabled;
+ _update_window_style(p_window);
+ } break;
+ case WINDOW_FLAG_ALWAYS_ON_TOP: {
+
+ ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top");
+ wd.always_on_top = p_enabled;
+ _update_window_style(p_window);
+ } break;
+ case WINDOW_FLAG_TRANSPARENT: {
+
+ // FIXME: Implement.
+ } break;
+ case WINDOW_FLAG_NO_FOCUS: {
+
+ wd.no_focus = p_enabled;
+ _update_window_style(p_window);
+ } break;
+ case WINDOW_FLAG_MAX: break;
+ }
+}
+
+bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+ switch (p_flag) {
+ case WINDOW_FLAG_RESIZE_DISABLED: {
+
+ return !wd.resizable;
+ } break;
+ case WINDOW_FLAG_BORDERLESS: {
+
+ return wd.borderless;
+ } break;
+ case WINDOW_FLAG_ALWAYS_ON_TOP: {
+
+ return wd.always_on_top;
+ } break;
+ case WINDOW_FLAG_TRANSPARENT: {
+
+ // FIXME: Implement.
+ } break;
+ case WINDOW_FLAG_NO_FOCUS: {
+
+ return wd.no_focus;
+ } break;
+ case WINDOW_FLAG_MAX: break;
+ }
+
+ return false;
+}
+
+void DisplayServerWindows::window_request_attention(WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ FLASHWINFO info;
+ info.cbSize = sizeof(FLASHWINFO);
+ info.hwnd = wd.hWnd;
+ info.dwFlags = FLASHW_TRAY;
+ info.dwTimeout = 0;
+ info.uCount = 2;
+ FlashWindowEx(&info);
+}
+void DisplayServerWindows::window_move_to_foreground(WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ SetForegroundWindow(wd.hWnd);
+}
+
+bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+ const WindowData &wd = windows[p_window];
+ return wd.minimized;
+}
+
+bool DisplayServerWindows::can_any_window_draw() const {
+
+ _THREAD_SAFE_METHOD_
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (!E->get().minimized) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ if (p_active) {
+ ImmAssociateContext(wd.hWnd, wd.im_himc);
+
+ window_set_ime_position(wd.im_position, p_window);
+ } else {
+ ImmAssociateContext(wd.hWnd, (HIMC)0);
+ }
+}
+void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.im_position = p_pos;
+
+ HIMC himc = ImmGetContext(wd.hWnd);
+ if (himc == (HIMC)0)
+ return;
+
+ COMPOSITIONFORM cps;
+ cps.dwStyle = CFS_FORCE_POSITION;
+ cps.ptCurrentPos.x = wd.im_position.x;
+ cps.ptCurrentPos.y = wd.im_position.y;
+ ImmSetCompositionWindow(himc, &cps);
+ ImmReleaseContext(wd.hWnd, himc);
+}
+
+void DisplayServerWindows::console_set_visible(bool p_enabled) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (console_visible == p_enabled)
+ return;
+ ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
+ console_visible = p_enabled;
+}
+bool DisplayServerWindows::is_console_visible() const {
+ return console_visible;
+}
+
+void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
+
+ if (cursor_shape == p_shape)
+ return;
+
+ if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
+ cursor_shape = p_shape;
+ return;
+ }
+
+ static const LPCTSTR win_cursors[CURSOR_MAX] = {
+ IDC_ARROW,
+ IDC_IBEAM,
+ IDC_HAND, //finger
+ IDC_CROSS,
+ IDC_WAIT,
+ IDC_APPSTARTING,
+ IDC_ARROW,
+ IDC_ARROW,
+ IDC_NO,
+ IDC_SIZENS,
+ IDC_SIZEWE,
+ IDC_SIZENESW,
+ IDC_SIZENWSE,
+ IDC_SIZEALL,
+ IDC_SIZENS,
+ IDC_SIZEWE,
+ IDC_HELP
+ };
+
+ if (cursors[p_shape] != nullptr) {
+ SetCursor(cursors[p_shape]);
+ } else {
+ SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
+ }
+
+ cursor_shape = p_shape;
+}
+DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
+ return cursor_shape;
+}
+
+void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
+
+ // Get the system display DC
+ HDC hDC = GetDC(nullptr);
+
+ // Create helper DC
+ HDC hMainDC = CreateCompatibleDC(hDC);
+ HDC hAndMaskDC = CreateCompatibleDC(hDC);
+ HDC hXorMaskDC = CreateCompatibleDC(hDC);
+
+ // Get the dimensions of the source bitmap
+ BITMAP bm;
+ GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
+
+ // Create the mask bitmaps
+ hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
+ hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
+
+ // Release the system display DC
+ ReleaseDC(nullptr, hDC);
+
+ // Select the bitmaps to helper DC
+ HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
+ 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
+ // 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
+ // with 'clrTransparent' will be black and rest the pixels same as corresponding
+ // pixels of the source bitmap
+ SetBkColor(hXorMaskDC, RGB(0, 0, 0));
+ SetTextColor(hXorMaskDC, RGB(255, 255, 255));
+ BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
+ BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
+
+ // Deselect bitmaps from the helper DC
+ SelectObject(hMainDC, hOldMainBitmap);
+ SelectObject(hAndMaskDC, hOldAndMaskBitmap);
+ SelectObject(hXorMaskDC, hOldXorMaskBitmap);
+
+ // Delete the helper DC
+ DeleteDC(hXorMaskDC);
+ DeleteDC(hAndMaskDC);
+ DeleteDC(hMainDC);
+}
+
+void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+
+ _THREAD_SAFE_METHOD_
+
+ if (p_cursor.is_valid()) {
+
+ Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
+
+ if (cursor_c) {
+ if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
+ cursor_set_shape(p_shape);
+ return;
+ }
+
+ cursors_cache.erase(p_shape);
+ }
+
+ Ref<Texture2D> texture = p_cursor;
+ Ref<AtlasTexture> atlas_texture = p_cursor;
+ Ref<Image> image;
+ Size2 texture_size;
+ Rect2 atlas_rect;
+
+ if (texture.is_valid()) {
+ image = texture->get_data();
+ }
+
+ if (!image.is_valid() && atlas_texture.is_valid()) {
+ texture = atlas_texture->get_atlas();
+
+ atlas_rect.size.width = texture->get_width();
+ atlas_rect.size.height = texture->get_height();
+ atlas_rect.position.x = atlas_texture->get_region().position.x;
+ atlas_rect.position.y = atlas_texture->get_region().position.y;
+
+ texture_size.width = atlas_texture->get_region().size.x;
+ texture_size.height = atlas_texture->get_region().size.y;
+ } else if (image.is_valid()) {
+ texture_size.width = texture->get_width();
+ texture_size.height = texture->get_height();
+ }
+
+ ERR_FAIL_COND(!texture.is_valid());
+ ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
+ 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();
+
+ ERR_FAIL_COND(!image.is_valid());
+
+ UINT image_size = texture_size.width * texture_size.height;
+
+ // Create the BITMAP with alpha channel
+ COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
+
+ for (UINT index = 0; index < image_size; index++) {
+ int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
+ int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
+
+ if (atlas_texture.is_valid()) {
+ column_index = MIN(column_index, atlas_rect.size.width - 1);
+ row_index = MIN(row_index, atlas_rect.size.height - 1);
+ }
+
+ *(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
+ }
+
+ // Using 4 channels, so 4 * 8 bits
+ HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
+ COLORREF clrTransparent = -1;
+
+ // Create the AND and XOR masks for the bitmap
+ HBITMAP hAndMask = nullptr;
+ HBITMAP hXorMask = nullptr;
+
+ GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
+
+ if (nullptr == hAndMask || nullptr == hXorMask) {
+ memfree(buffer);
+ DeleteObject(bitmap);
+ return;
+ }
+
+ // Finally, create the icon
+ ICONINFO iconinfo;
+ iconinfo.fIcon = FALSE;
+ iconinfo.xHotspot = p_hotspot.x;
+ iconinfo.yHotspot = p_hotspot.y;
+ iconinfo.hbmMask = hAndMask;
+ iconinfo.hbmColor = hXorMask;
+
+ if (cursors[p_shape])
+ DestroyIcon(cursors[p_shape]);
+
+ cursors[p_shape] = CreateIconIndirect(&iconinfo);
+
+ Vector<Variant> params;
+ params.push_back(p_cursor);
+ params.push_back(p_hotspot);
+ cursors_cache.insert(p_shape, params);
+
+ if (p_shape == cursor_shape) {
+ if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+ SetCursor(cursors[p_shape]);
+ }
+ }
+
+ if (hAndMask != nullptr) {
+ DeleteObject(hAndMask);
+ }
+
+ if (hXorMask != nullptr) {
+ DeleteObject(hXorMask);
+ }
+
+ memfree(buffer);
+ DeleteObject(bitmap);
+ } else {
+ // Reset to default system cursor
+ if (cursors[p_shape]) {
+ DestroyIcon(cursors[p_shape]);
+ cursors[p_shape] = nullptr;
+ }
+
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ cursor_set_shape(c);
+
+ cursors_cache.erase(p_shape);
+ }
+}
+
+bool DisplayServerWindows::get_swap_ok_cancel() {
+ return true;
+}
+
+void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) {
+ _THREAD_SAFE_METHOD_
+
+ AllowSetForegroundWindow(pid);
+}
+
+DisplayServer::LatinKeyboardVariant DisplayServerWindows::get_latin_keyboard_variant() const {
+
+ _THREAD_SAFE_METHOD_
+
+ unsigned long azerty[] = {
+ 0x00020401, // Arabic (102) AZERTY
+ 0x0001080c, // Belgian (Comma)
+ 0x0000080c, // Belgian French
+ 0x0000040c, // French
+ 0 // <--- STOP MARK
+ };
+ unsigned long qwertz[] = {
+ 0x0000041a, // Croation
+ 0x00000405, // Czech
+ 0x00000407, // German
+ 0x00010407, // German (IBM)
+ 0x0000040e, // Hungarian
+ 0x0000046e, // Luxembourgish
+ 0x00010415, // Polish (214)
+ 0x00000418, // Romanian (Legacy)
+ 0x0000081a, // Serbian (Latin)
+ 0x0000041b, // Slovak
+ 0x00000424, // Slovenian
+ 0x0001042e, // Sorbian Extended
+ 0x0002042e, // Sorbian Standard
+ 0x0000042e, // Sorbian Standard (Legacy)
+ 0x0000100c, // Swiss French
+ 0x00000807, // Swiss German
+ 0 // <--- STOP MARK
+ };
+ unsigned long dvorak[] = {
+ 0x00010409, // US-Dvorak
+ 0x00030409, // US-Dvorak for left hand
+ 0x00040409, // US-Dvorak for right hand
+ 0 // <--- STOP MARK
+ };
+
+ char name[KL_NAMELENGTH + 1];
+ name[0] = 0;
+ GetKeyboardLayoutNameA(name);
+
+ unsigned long hex = strtoul(name, nullptr, 16);
+
+ int i = 0;
+ while (azerty[i] != 0) {
+ if (azerty[i] == hex) return LATIN_KEYBOARD_AZERTY;
+ i++;
+ }
+
+ i = 0;
+ while (qwertz[i] != 0) {
+ if (qwertz[i] == hex) return LATIN_KEYBOARD_QWERTZ;
+ i++;
+ }
+
+ i = 0;
+ while (dvorak[i] != 0) {
+ if (dvorak[i] == hex) return LATIN_KEYBOARD_DVORAK;
+ i++;
+ }
+
+ return LATIN_KEYBOARD_QWERTY;
+}
+
+void DisplayServerWindows::process_events() {
+
+ _THREAD_SAFE_METHOD_
+
+ MSG msg;
+
+ if (!drop_events) {
+ joypad->process_joypads();
+ }
+
+ while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
+
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+
+ if (!drop_events) {
+ _process_key_events();
+ InputFilter::get_singleton()->flush_accumulated_events();
+ }
+}
+
+void DisplayServerWindows::force_process_and_drop_events() {
+
+ _THREAD_SAFE_METHOD_
+
+ drop_events = true;
+ process_events();
+ drop_events = false;
+}
+
+void DisplayServerWindows::release_rendering_thread() {
+}
+void DisplayServerWindows::make_rendering_thread() {
+}
+void DisplayServerWindows::swap_buffers() {
+}
+
+void DisplayServerWindows::set_native_icon(const String &p_filename) {
+
+ _THREAD_SAFE_METHOD_
+
+ FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
+ ERR_FAIL_COND_MSG(!f, "Cannot open file with icon '" + p_filename + "'.");
+
+ ICONDIR *icon_dir = (ICONDIR *)memalloc(sizeof(ICONDIR));
+ int pos = 0;
+
+ icon_dir->idReserved = f->get_32();
+ pos += sizeof(WORD);
+ f->seek(pos);
+
+ icon_dir->idType = f->get_32();
+ pos += sizeof(WORD);
+ f->seek(pos);
+
+ ERR_FAIL_COND_MSG(icon_dir->idType != 1, "Invalid icon file format!");
+
+ icon_dir->idCount = f->get_32();
+ pos += sizeof(WORD);
+ f->seek(pos);
+
+ icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY));
+ f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
+
+ int small_icon_index = -1; // Select 16x16 with largest color count
+ int small_icon_cc = 0;
+ int big_icon_index = -1; // Select largest
+ int big_icon_width = 16;
+ int big_icon_cc = 0;
+
+ for (int i = 0; i < icon_dir->idCount; i++) {
+ int colors = (icon_dir->idEntries[i].bColorCount == 0) ? 32768 : icon_dir->idEntries[i].bColorCount;
+ int width = (icon_dir->idEntries[i].bWidth == 0) ? 256 : icon_dir->idEntries[i].bWidth;
+ if (width == 16) {
+ if (colors >= small_icon_cc) {
+ small_icon_index = i;
+ small_icon_cc = colors;
+ }
+ }
+ if (width >= big_icon_width) {
+ if (colors >= big_icon_cc) {
+ big_icon_index = i;
+ big_icon_width = width;
+ big_icon_cc = colors;
+ }
+ }
+ }
+
+ ERR_FAIL_COND_MSG(big_icon_index == -1, "No valid icons found!");
+
+ if (small_icon_index == -1) {
+ WARN_PRINT("No small icon found, reusing " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon!");
+ small_icon_index = big_icon_index;
+ small_icon_cc = big_icon_cc;
+ }
+
+ // Read the big icon
+ DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes;
+ Vector<uint8_t> data_big;
+ data_big.resize(bytecount_big);
+ pos = icon_dir->idEntries[big_icon_index].dwImageOffset;
+ f->seek(pos);
+ f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big);
+ HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000);
+ ERR_FAIL_COND_MSG(!icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
+
+ // Read the small icon
+ DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes;
+ Vector<uint8_t> data_small;
+ data_small.resize(bytecount_small);
+ pos = icon_dir->idEntries[small_icon_index].dwImageOffset;
+ f->seek(pos);
+ f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small);
+ HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000);
+ ERR_FAIL_COND_MSG(!icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
+
+ // Online tradition says to be sure last error is cleared and set the small icon first
+ int err = 0;
+ SetLastError(err);
+
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small);
+ err = GetLastError();
+ ERR_FAIL_COND_MSG(err, "Error setting ICON_SMALL: " + format_error_message(err) + ".");
+
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big);
+ err = GetLastError();
+ ERR_FAIL_COND_MSG(err, "Error setting ICON_BIG: " + format_error_message(err) + ".");
+
+ memdelete(f);
+ memdelete(icon_dir);
+}
+void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
+
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!p_icon.is_valid());
+ Ref<Image> icon = p_icon->duplicate();
+ if (icon->get_format() != Image::FORMAT_RGBA8)
+ icon->convert(Image::FORMAT_RGBA8);
+ int w = icon->get_width();
+ int h = icon->get_height();
+
+ /* Create temporary bitmap buffer */
+ int icon_len = 40 + h * w * 4;
+ Vector<BYTE> v;
+ v.resize(icon_len);
+ BYTE *icon_bmp = v.ptrw();
+
+ encode_uint32(40, &icon_bmp[0]);
+ encode_uint32(w, &icon_bmp[4]);
+ encode_uint32(h * 2, &icon_bmp[8]);
+ encode_uint16(1, &icon_bmp[12]);
+ encode_uint16(32, &icon_bmp[14]);
+ encode_uint32(BI_RGB, &icon_bmp[16]);
+ encode_uint32(w * h * 4, &icon_bmp[20]);
+ encode_uint32(0, &icon_bmp[24]);
+ encode_uint32(0, &icon_bmp[28]);
+ encode_uint32(0, &icon_bmp[32]);
+ encode_uint32(0, &icon_bmp[36]);
+
+ uint8_t *wr = &icon_bmp[40];
+ const uint8_t *r = icon->get_data().ptr();
+
+ for (int i = 0; i < h; i++) {
+
+ for (int j = 0; j < w; j++) {
+
+ const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
+ uint8_t *wpx = &wr[(i * w + j) * 4];
+ wpx[0] = rpx[2];
+ wpx[1] = rpx[1];
+ wpx[2] = rpx[0];
+ wpx[3] = rpx[3];
+ }
+ }
+
+ HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+
+ /* Set the icon for the window */
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
+
+ /* Set the icon in the task manager (should we do this?) */
+ SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
+}
+
+void DisplayServerWindows::vsync_set_use_via_compositor(bool p_enable) {
+}
+bool DisplayServerWindows::vsync_is_using_via_compositor() const {
+ return false;
+}
+
+void DisplayServerWindows::set_context(Context p_context) {
+}
+
+#define MI_WP_SIGNATURE 0xFF515700
+#define SIGNATURE_MASK 0xFFFFFF00
+// Keeping the name suggested by Microsoft, but this macro really answers:
+// Is this mouse event emulated from touch or pen input?
+#define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE)
+// This one tells whether the event comes from touchscreen (and not from pen)
+#define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw)&0x80))
+
+void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx) {
+
+ // Defensive
+ if (touch_state.has(idx) == p_pressed)
+ return;
+
+ if (p_pressed) {
+ touch_state.insert(idx, Vector2(p_x, p_y));
+ } else {
+ touch_state.erase(idx);
+ }
+
+ Ref<InputEventScreenTouch> event;
+ event.instance();
+ event->set_index(idx);
+ event->set_window_id(p_window);
+ event->set_pressed(p_pressed);
+ event->set_position(Vector2(p_x, p_y));
+
+ InputFilter::get_singleton()->accumulate_input_event(event);
+}
+
+void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, int idx) {
+
+ Map<int, Vector2>::Element *curr = touch_state.find(idx);
+ // Defensive
+ if (!curr)
+ return;
+
+ if (curr->get() == Vector2(p_x, p_y))
+ return;
+
+ Ref<InputEventScreenDrag> event;
+ event.instance();
+ event->set_window_id(p_window);
+ event->set_index(idx);
+ event->set_position(Vector2(p_x, p_y));
+ event->set_relative(Vector2(p_x, p_y) - curr->get());
+
+ InputFilter::get_singleton()->accumulate_input_event(event);
+
+ curr->get() = Vector2(p_x, p_y);
+}
+
+void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent p_event) {
+
+ if (!wd.event_callback.is_null()) {
+ Variant event = int(p_event);
+ Variant *eventp = &event;
+ Variant ret;
+ Callable::CallError ce;
+ wd.event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ }
+}
+
+void DisplayServerWindows::_dispatch_input_events(const Ref<InputEvent> &p_event) {
+ ((DisplayServerWindows *)(get_singleton()))->_dispatch_input_event(p_event);
+}
+
+void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) {
+
+ Variant ev = p_event;
+ Variant *evp = &ev;
+ Variant ret;
+ Callable::CallError ce;
+
+ Ref<InputEventFromWindow> event_from_window = p_event;
+ if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
+ //send to a window
+ ERR_FAIL_COND(!windows.has(event_from_window->get_window_id()));
+ Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
+ if (callable.is_null()) {
+ return;
+ }
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ } else {
+ //send to all windows
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ Callable callable = E->get().input_event_callback;
+ if (callable.is_null()) {
+ continue;
+ }
+ callable.call((const Variant **)&evp, 1, ret, ce);
+ }
+ }
+}
+
+LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ if (drop_events) {
+
+ if (user_proc) {
+
+ return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
+ } else {
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }
+ };
+
+ WindowID window_id = INVALID_WINDOW_ID;
+
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ if (E->get().hWnd == hWnd) {
+ window_id = E->key();
+ break;
+ }
+ }
+
+ switch (uMsg) // Check For Windows Messages
+ {
+ case WM_SETFOCUS: {
+
+ windows[window_id].window_has_focus = true;
+ last_focused_window = window_id;
+
+ // Restore mouse mode
+ _set_mouse_mode_impl(mouse_mode);
+
+ break;
+ }
+ case WM_KILLFOCUS: {
+ windows[window_id].window_has_focus = false;
+ last_focused_window = window_id;
+
+ // Release capture unconditionally because it can be set due to dragging, in addition to captured mode
+ ReleaseCapture();
+
+ // Release every touch to avoid sticky points
+ for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) {
+ _touch_event(window_id, false, E->get().x, E->get().y, E->key());
+ }
+ touch_state.clear();
+
+ break;
+ }
+ case WM_ACTIVATE: // Watch For Window Activate Message
+ {
+ windows[window_id].minimized = HIWORD(wParam) != 0;
+
+ if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
+
+ _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN);
+ windows[window_id].window_focused = true;
+ alt_mem = false;
+ control_mem = false;
+ shift_mem = false;
+ } else { // WM_INACTIVE
+ InputFilter::get_singleton()->release_pressed_events();
+ _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT);
+ windows[window_id].window_focused = false;
+ alt_mem = false;
+ };
+
+ return 0; // Return To The Message Loop
+ }
+ case WM_GETMINMAXINFO: {
+ if (windows[window_id].resizable && !windows[window_id].fullscreen) {
+ Size2 decor = window_get_size(window_id) - window_get_real_size(window_id); // Size of window decorations
+ MINMAXINFO *min_max_info = (MINMAXINFO *)lParam;
+ if (windows[window_id].min_size != Size2()) {
+ min_max_info->ptMinTrackSize.x = windows[window_id].min_size.x + decor.x;
+ min_max_info->ptMinTrackSize.y = windows[window_id].min_size.y + decor.y;
+ }
+ if (windows[window_id].max_size != Size2()) {
+ min_max_info->ptMaxTrackSize.x = windows[window_id].max_size.x + decor.x;
+ min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y;
+ }
+ return 0;
+ } else {
+ break;
+ }
+ }
+ case WM_PAINT:
+
+ Main::force_redraw();
+ break;
+
+ case WM_SYSCOMMAND: // Intercept System Commands
+ {
+ switch (wParam) // Check System Calls
+ {
+ case SC_SCREENSAVE: // Screensaver Trying To Start?
+ case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
+ return 0; // Prevent From Happening
+ case SC_KEYMENU:
+ if ((lParam >> 16) <= 0)
+ return 0;
+ }
+ break; // Exit
+ }
+
+ case WM_CLOSE: // Did We Receive A Close Message?
+ {
+
+ _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
+
+ return 0; // Jump Back
+ }
+ case WM_MOUSELEAVE: {
+
+ old_invalid = true;
+ outside = true;
+
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+
+ } break;
+ case WM_INPUT: {
+ if (mouse_mode != MOUSE_MODE_CAPTURED || !use_raw_input) {
+ break;
+ }
+
+ UINT dwSize;
+
+ GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
+ LPBYTE lpb = new BYTE[dwSize];
+ if (lpb == nullptr) {
+ return 0;
+ }
+
+ if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
+ OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));
+
+ RAWINPUT *raw = (RAWINPUT *)lpb;
+
+ if (raw->header.dwType == RIM_TYPEMOUSE) {
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+
+ mm->set_window_id(window_id);
+ mm->set_control(control_mem);
+ mm->set_shift(shift_mem);
+ mm->set_alt(alt_mem);
+
+ mm->set_button_mask(last_button_state);
+
+ Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
+
+ // centering just so it works as before
+ POINT pos = { (int)c.x, (int)c.y };
+ ClientToScreen(windows[window_id].hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+
+ mm->set_position(c);
+ mm->set_global_position(c);
+ InputFilter::get_singleton()->set_mouse_position(c);
+ mm->set_speed(Vector2(0, 0));
+
+ if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE) {
+ mm->set_relative(Vector2(raw->data.mouse.lLastX, raw->data.mouse.lLastY));
+
+ } else if (raw->data.mouse.usFlags == MOUSE_MOVE_ABSOLUTE) {
+
+ int nScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ int nScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ int nScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ int nScreenTop = GetSystemMetrics(SM_YVIRTUALSCREEN);
+
+ Vector2 abs_pos(
+ (double(raw->data.mouse.lLastX) - 65536.0 / (nScreenWidth)) * nScreenWidth / 65536.0 + nScreenLeft,
+ (double(raw->data.mouse.lLastY) - 65536.0 / (nScreenHeight)) * nScreenHeight / 65536.0 + nScreenTop);
+
+ POINT coords; //client coords
+ coords.x = abs_pos.x;
+ coords.y = abs_pos.y;
+
+ ScreenToClient(hWnd, &coords);
+
+ mm->set_relative(Vector2(coords.x - old_x, coords.y - old_y));
+ old_x = coords.x;
+ old_y = coords.y;
+
+ /*Input.mi.dx = (int)((((double)(pos.x)-nScreenLeft) * 65536) / nScreenWidth + 65536 / (nScreenWidth));
+ Input.mi.dy = (int)((((double)(pos.y)-nScreenTop) * 65536) / nScreenHeight + 65536 / (nScreenHeight));
+ */
+ }
+
+ if (windows[window_id].window_has_focus && mm->get_relative() != Vector2())
+ InputFilter::get_singleton()->accumulate_input_event(mm);
+ }
+ delete[] lpb;
+ } break;
+ case WM_POINTERUPDATE: {
+ if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
+ break;
+ }
+
+ if (!win8p_GetPointerType || !win8p_GetPointerPenInfo) {
+ break;
+ }
+
+ uint32_t pointer_id = LOWORD(wParam);
+ POINTER_INPUT_TYPE pointer_type = PT_POINTER;
+ if (!win8p_GetPointerType(pointer_id, &pointer_type)) {
+ break;
+ }
+
+ if (pointer_type != PT_PEN) {
+ break;
+ }
+
+ POINTER_PEN_INFO pen_info;
+ if (!win8p_GetPointerPenInfo(pointer_id, &pen_info)) {
+ break;
+ }
+
+ if (InputFilter::get_singleton()->is_emulating_mouse_from_touch()) {
+ // Universal translation enabled; ignore OS translation
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsTouchEvent(extra)) {
+ break;
+ }
+ }
+
+ if (outside) {
+ //mouse enter
+
+ if (mouse_mode != MOUSE_MODE_CAPTURED) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ cursor_set_shape(c);
+ outside = false;
+
+ //Once-Off notification, must call again....
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hWnd;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+ }
+
+ // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
+ if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
+ break;
+
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+
+ mm->set_window_id(window_id);
+ mm->set_pressure(pen_info.pressure ? (float)pen_info.pressure / 1024 : 0);
+ mm->set_tilt(Vector2(pen_info.tiltX ? (float)pen_info.tiltX / 90 : 0, pen_info.tiltY ? (float)pen_info.tiltY / 90 : 0));
+
+ mm->set_control((wParam & MK_CONTROL) != 0);
+ mm->set_shift((wParam & MK_SHIFT) != 0);
+ mm->set_alt(alt_mem);
+
+ mm->set_button_mask(last_button_state);
+
+ POINT coords; //client coords
+ coords.x = GET_X_LPARAM(lParam);
+ coords.y = GET_Y_LPARAM(lParam);
+
+ ScreenToClient(windows[window_id].hWnd, &coords);
+
+ mm->set_position(Vector2(coords.x, coords.y));
+ mm->set_global_position(Vector2(coords.x, coords.y));
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+
+ Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
+ old_x = c.x;
+ old_y = c.y;
+
+ if (mm->get_position() == c) {
+ center = c;
+ return 0;
+ }
+
+ Point2i ncenter = mm->get_position();
+ center = ncenter;
+ POINT pos = { (int)c.x, (int)c.y };
+ ClientToScreen(hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+ }
+
+ InputFilter::get_singleton()->set_mouse_position(mm->get_position());
+ mm->set_speed(InputFilter::get_singleton()->get_last_mouse_speed());
+
+ if (old_invalid) {
+
+ old_x = mm->get_position().x;
+ old_y = mm->get_position().y;
+ old_invalid = false;
+ }
+
+ mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
+ old_x = mm->get_position().x;
+ old_y = mm->get_position().y;
+ if (windows[window_id].window_has_focus) {
+ InputFilter::get_singleton()->parse_input_event(mm);
+ }
+
+ return 0; //Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event
+ } break;
+ case WM_MOUSEMOVE: {
+ if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
+ break;
+ }
+
+ if (InputFilter::get_singleton()->is_emulating_mouse_from_touch()) {
+ // Universal translation enabled; ignore OS translation
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsTouchEvent(extra)) {
+ break;
+ }
+ }
+
+ if (outside) {
+ //mouse enter
+
+ if (mouse_mode != MOUSE_MODE_CAPTURED) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
+
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ cursor_set_shape(c);
+ outside = false;
+
+ //Once-Off notification, must call again....
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hWnd;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+ }
+
+ // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
+ if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
+ break;
+
+ Ref<InputEventMouseMotion> mm;
+ mm.instance();
+ mm->set_window_id(window_id);
+ mm->set_control((wParam & MK_CONTROL) != 0);
+ mm->set_shift((wParam & MK_SHIFT) != 0);
+ mm->set_alt(alt_mem);
+
+ mm->set_button_mask(last_button_state);
+
+ mm->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
+ mm->set_global_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+
+ Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
+ old_x = c.x;
+ old_y = c.y;
+
+ if (mm->get_position() == c) {
+ center = c;
+ return 0;
+ }
+
+ Point2i ncenter = mm->get_position();
+ center = ncenter;
+ POINT pos = { (int)c.x, (int)c.y };
+ ClientToScreen(windows[window_id].hWnd, &pos);
+ SetCursorPos(pos.x, pos.y);
+ }
+
+ InputFilter::get_singleton()->set_mouse_position(mm->get_position());
+ mm->set_speed(InputFilter::get_singleton()->get_last_mouse_speed());
+
+ if (old_invalid) {
+
+ old_x = mm->get_position().x;
+ old_y = mm->get_position().y;
+ old_invalid = false;
+ }
+
+ mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
+ old_x = mm->get_position().x;
+ old_y = mm->get_position().y;
+ if (windows[window_id].window_has_focus)
+ InputFilter::get_singleton()->accumulate_input_event(mm);
+
+ } break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ if (InputFilter::get_singleton()->is_emulating_mouse_from_touch()) {
+ // Universal translation enabled; ignore OS translations for left button
+ LPARAM extra = GetMessageExtraInfo();
+ if (IsTouchEvent(extra)) {
+ break;
+ }
+ }
+ [[fallthrough]];
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_XBUTTONDBLCLK:
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP: {
+
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_window_id(window_id);
+
+ switch (uMsg) {
+ case WM_LBUTTONDOWN: {
+ mb->set_pressed(true);
+ mb->set_button_index(1);
+ } break;
+ case WM_LBUTTONUP: {
+ mb->set_pressed(false);
+ mb->set_button_index(1);
+ } break;
+ case WM_MBUTTONDOWN: {
+ mb->set_pressed(true);
+ mb->set_button_index(3);
+ } break;
+ case WM_MBUTTONUP: {
+ mb->set_pressed(false);
+ mb->set_button_index(3);
+ } break;
+ case WM_RBUTTONDOWN: {
+ mb->set_pressed(true);
+ mb->set_button_index(2);
+ } break;
+ case WM_RBUTTONUP: {
+ mb->set_pressed(false);
+ mb->set_button_index(2);
+ } break;
+ case WM_LBUTTONDBLCLK: {
+ mb->set_pressed(true);
+ mb->set_button_index(1);
+ mb->set_doubleclick(true);
+ } break;
+ case WM_RBUTTONDBLCLK: {
+ mb->set_pressed(true);
+ mb->set_button_index(2);
+ mb->set_doubleclick(true);
+ } break;
+ case WM_MBUTTONDBLCLK: {
+ mb->set_pressed(true);
+ mb->set_button_index(3);
+ mb->set_doubleclick(true);
+ } break;
+ case WM_MOUSEWHEEL: {
+
+ mb->set_pressed(true);
+ int motion = (short)HIWORD(wParam);
+ if (!motion)
+ return 0;
+
+ if (motion > 0)
+ mb->set_button_index(BUTTON_WHEEL_UP);
+ else
+ mb->set_button_index(BUTTON_WHEEL_DOWN);
+
+ } break;
+ case WM_MOUSEHWHEEL: {
+
+ mb->set_pressed(true);
+ int motion = (short)HIWORD(wParam);
+ if (!motion)
+ return 0;
+
+ if (motion < 0) {
+ mb->set_button_index(BUTTON_WHEEL_LEFT);
+ mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
+ } else {
+ mb->set_button_index(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);
+ else
+ mb->set_button_index(BUTTON_XBUTTON2);
+ } break;
+ case WM_XBUTTONUP: {
+
+ mb->set_pressed(false);
+ if (HIWORD(wParam) == XBUTTON1)
+ mb->set_button_index(BUTTON_XBUTTON1);
+ else
+ mb->set_button_index(BUTTON_XBUTTON2);
+ } break;
+ case WM_XBUTTONDBLCLK: {
+
+ mb->set_pressed(true);
+ if (HIWORD(wParam) == XBUTTON1)
+ mb->set_button_index(BUTTON_XBUTTON1);
+ else
+ mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_doubleclick(true);
+ } break;
+ default: {
+ return 0;
+ }
+ }
+
+ mb->set_control((wParam & MK_CONTROL) != 0);
+ mb->set_shift((wParam & MK_SHIFT) != 0);
+ mb->set_alt(alt_mem);
+ //mb->get_alt()=(wParam&MK_MENU)!=0;
+ if (mb->is_pressed())
+ last_button_state |= (1 << (mb->get_button_index() - 1));
+ else
+ last_button_state &= ~(1 << (mb->get_button_index() - 1));
+ mb->set_button_mask(last_button_state);
+
+ mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED && !use_raw_input) {
+
+ mb->set_position(Vector2(old_x, old_y));
+ }
+
+ if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) {
+ if (mb->is_pressed()) {
+
+ if (++pressrc > 0 && mouse_mode != MOUSE_MODE_CAPTURED)
+ SetCapture(hWnd);
+ } else {
+
+ if (--pressrc <= 0) {
+ if (mouse_mode != MOUSE_MODE_CAPTURED) {
+ ReleaseCapture();
+ }
+ pressrc = 0;
+ }
+ }
+ } else {
+ // for reasons unknown to mankind, wheel comes in screen coordinates
+ POINT coords;
+ coords.x = mb->get_position().x;
+ coords.y = mb->get_position().y;
+
+ ScreenToClient(hWnd, &coords);
+
+ mb->set_position(Vector2(coords.x, coords.y));
+ }
+
+ mb->set_global_position(mb->get_position());
+
+ InputFilter::get_singleton()->accumulate_input_event(mb);
+ if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
+ //send release for mouse wheel
+ Ref<InputEventMouseButton> mbd = mb->duplicate();
+ mbd->set_window_id(window_id);
+ last_button_state &= ~(1 << (mbd->get_button_index() - 1));
+ mbd->set_button_mask(last_button_state);
+ mbd->set_pressed(false);
+ InputFilter::get_singleton()->accumulate_input_event(mbd);
+ }
+
+ } break;
+
+ case WM_MOVE: {
+ if (!IsIconic(windows[window_id].hWnd)) {
+ int x = int16_t(LOWORD(lParam));
+ int y = int16_t(HIWORD(lParam));
+ windows[window_id].last_pos = Point2(x, y);
+
+ if (!windows[window_id].rect_changed_callback.is_null()) {
+
+ Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height);
+ Variant *sizep = &size;
+ Variant ret;
+ Callable::CallError ce;
+ windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
+ }
+ }
+ } break;
+
+ case WM_SIZE: {
+ // Ignore size when a SIZE_MINIMIZED event is triggered
+ if (wParam != SIZE_MINIMIZED) {
+ int window_w = LOWORD(lParam);
+ int window_h = HIWORD(lParam);
+ if (window_w > 0 && window_h > 0 && !windows[window_id].preserve_window_size) {
+ windows[window_id].width = window_w;
+ windows[window_id].height = window_h;
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_resize(window_id, windows[window_id].width, windows[window_id].height);
+ }
+#endif
+
+ } else {
+ windows[window_id].preserve_window_size = false;
+ window_set_size(Size2(windows[window_id].width, windows[window_id].height), window_id);
+ }
+ }
+
+ if (!windows[window_id].rect_changed_callback.is_null()) {
+
+ Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height);
+ Variant *sizep = &size;
+ Variant ret;
+ Callable::CallError ce;
+ windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
+ }
+
+ if (wParam == SIZE_MAXIMIZED) {
+ windows[window_id].maximized = true;
+ windows[window_id].minimized = false;
+ } else if (wParam == SIZE_MINIMIZED) {
+ windows[window_id].maximized = false;
+ windows[window_id].minimized = true;
+ } else if (wParam == SIZE_RESTORED) {
+ windows[window_id].maximized = false;
+ windows[window_id].minimized = false;
+ }
+#if 0
+ if (is_layered_allowed() && layered_window) {
+ DeleteObject(hBitmap);
+
+ RECT r;
+ GetWindowRect(hWnd, &r);
+ dib_size = Size2i(r.right - r.left, r.bottom - r.top);
+
+ BITMAPINFO bmi;
+ ZeroMemory(&bmi, sizeof(BITMAPINFO));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = dib_size.x;
+ bmi.bmiHeader.biHeight = dib_size.y;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
+ hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, nullptr, 0x0);
+ SelectObject(hDC_dib, hBitmap);
+
+ ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
+ }
+#endif
+ //return 0; // Jump Back
+ } break;
+
+ case WM_ENTERSIZEMOVE: {
+ InputFilter::get_singleton()->release_pressed_events();
+ move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
+ } break;
+ case WM_EXITSIZEMOVE: {
+ KillTimer(windows[window_id].hWnd, move_timer_id);
+ } break;
+ case WM_TIMER: {
+ if (wParam == move_timer_id) {
+ _process_key_events();
+ if (!Main::is_iterating()) {
+ Main::iteration();
+ }
+ }
+ } break;
+
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ case WM_KEYDOWN: {
+
+ if (wParam == VK_SHIFT)
+ shift_mem = uMsg == WM_KEYDOWN;
+ if (wParam == VK_CONTROL)
+ control_mem = uMsg == WM_KEYDOWN;
+ if (wParam == VK_MENU) {
+ alt_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
+ if (lParam & (1 << 24))
+ gr_mem = alt_mem;
+ }
+
+ if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ // When SetCapture is used, ALT+F4 hotkey is ignored by Windows, so handle it ourselves
+ if (wParam == VK_F4 && alt_mem && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) {
+ _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
+ }
+ }
+ /*
+ if (wParam==VK_WIN) TODO wtf is this?
+ meta_mem=uMsg==WM_KEYDOWN;
+ */
+ [[fallthrough]];
+ }
+ case WM_CHAR: {
+
+ ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
+
+ // Make sure we don't include modifiers for the modifier key itself.
+ KeyEvent ke;
+ ke.shift = (wParam != VK_SHIFT) ? shift_mem : false;
+ ke.alt = (!(wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false;
+ ke.control = (wParam != VK_CONTROL) ? control_mem : false;
+ ke.meta = meta_mem;
+ ke.uMsg = uMsg;
+ ke.window_id = window_id;
+
+ if (ke.uMsg == WM_SYSKEYDOWN)
+ ke.uMsg = WM_KEYDOWN;
+ if (ke.uMsg == WM_SYSKEYUP)
+ ke.uMsg = WM_KEYUP;
+
+ ke.wParam = wParam;
+ ke.lParam = lParam;
+ key_event_buffer[key_event_pos++] = ke;
+
+ } break;
+ case WM_INPUTLANGCHANGEREQUEST: {
+
+ // FIXME: Do something?
+ } break;
+
+ case WM_TOUCH: {
+
+ BOOL bHandled = FALSE;
+ UINT cInputs = LOWORD(wParam);
+ PTOUCHINPUT pInputs = memnew_arr(TOUCHINPUT, cInputs);
+ if (pInputs) {
+ if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))) {
+ for (UINT i = 0; i < cInputs; i++) {
+ TOUCHINPUT ti = pInputs[i];
+ POINT touch_pos = {
+ TOUCH_COORD_TO_PIXEL(ti.x),
+ TOUCH_COORD_TO_PIXEL(ti.y),
+ };
+ ScreenToClient(hWnd, &touch_pos);
+ //do something with each touch input entry
+ if (ti.dwFlags & TOUCHEVENTF_MOVE) {
+
+ _drag_event(window_id, touch_pos.x, touch_pos.y, ti.dwID);
+ } else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
+
+ _touch_event(window_id, ti.dwFlags & TOUCHEVENTF_DOWN, touch_pos.x, touch_pos.y, ti.dwID);
+ };
+ }
+ bHandled = TRUE;
+ } else {
+ /* handle the error here */
+ }
+ memdelete_arr(pInputs);
+ } else {
+ /* handle the error here, probably out of memory */
+ }
+ if (bHandled) {
+ CloseTouchInputHandle((HTOUCHINPUT)lParam);
+ return 0;
+ };
+
+ } break;
+
+ case WM_DEVICECHANGE: {
+
+ joypad->probe_joypads();
+ } break;
+ case WM_SETCURSOR: {
+ if (LOWORD(lParam) == HTCLIENT) {
+ if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED)) {
+ //Hide the cursor
+ if (hCursor == nullptr)
+ hCursor = SetCursor(nullptr);
+ else
+ SetCursor(nullptr);
+ } else {
+ if (hCursor != nullptr) {
+ CursorShape c = cursor_shape;
+ cursor_shape = CURSOR_MAX;
+ cursor_set_shape(c);
+ hCursor = nullptr;
+ }
+ }
+ }
+
+ } break;
+ case WM_DROPFILES: {
+
+ HDROP hDropInfo = (HDROP)wParam;
+ const int buffsize = 4096;
+ wchar_t buf[buffsize];
+
+ int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0);
+
+ Vector<String> files;
+
+ for (int i = 0; i < fcount; i++) {
+
+ DragQueryFileW(hDropInfo, i, buf, buffsize);
+ String file = buf;
+ files.push_back(file);
+ }
+
+ if (files.size() && !windows[window_id].drop_files_callback.is_null()) {
+ Variant v = files;
+ Variant *vp = &v;
+ Variant ret;
+ Callable::CallError ce;
+ windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
+ }
+
+ } break;
+
+ default: {
+
+ if (user_proc) {
+
+ return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
+ };
+ };
+ }
+
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+
+ DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton());
+ if (ds_win)
+ return ds_win->WndProc(hWnd, uMsg, wParam, lParam);
+ else
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+void DisplayServerWindows::_process_key_events() {
+
+ for (int i = 0; i < key_event_pos; i++) {
+
+ KeyEvent &ke = key_event_buffer[i];
+ switch (ke.uMsg) {
+
+ case WM_CHAR: {
+ if ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR)) {
+ Ref<InputEventKey> k;
+ k.instance();
+
+ k->set_window_id(ke.window_id);
+ k->set_shift(ke.shift);
+ k->set_alt(ke.alt);
+ k->set_control(ke.control);
+ k->set_metakey(ke.meta);
+ k->set_pressed(true);
+ k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam));
+ k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
+ k->set_unicode(ke.wParam);
+ if (k->get_unicode() && gr_mem) {
+ k->set_alt(false);
+ k->set_control(false);
+ }
+
+ if (k->get_unicode() < 32)
+ k->set_unicode(0);
+
+ InputFilter::get_singleton()->accumulate_input_event(k);
+ }
+
+ //do nothing
+ } break;
+ case WM_KEYUP:
+ case WM_KEYDOWN: {
+
+ Ref<InputEventKey> k;
+ k.instance();
+
+ k->set_window_id(ke.window_id);
+ k->set_shift(ke.shift);
+ k->set_alt(ke.alt);
+ k->set_control(ke.control);
+ k->set_metakey(ke.meta);
+
+ k->set_pressed(ke.uMsg == WM_KEYDOWN);
+
+ if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
+ // Special case for Numpad Enter key
+ k->set_keycode(KEY_KP_ENTER);
+ } else {
+ k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam));
+ }
+
+ k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
+
+ if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
+ k->set_unicode(key_event_buffer[i + 1].wParam);
+ }
+ if (k->get_unicode() && gr_mem) {
+ k->set_alt(false);
+ k->set_control(false);
+ }
+
+ if (k->get_unicode() < 32)
+ k->set_unicode(0);
+
+ k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30))));
+
+ InputFilter::get_singleton()->accumulate_input_event(k);
+
+ } break;
+ }
+ }
+
+ key_event_pos = 0;
+}
+
+DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+
+ DWORD dwExStyle;
+ DWORD dwStyle;
+
+ _get_window_style(window_id_counter == MAIN_WINDOW_ID, p_mode == WINDOW_MODE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT), dwStyle, dwExStyle);
+
+ RECT WindowRect;
+
+ WindowRect.left = p_rect.position.x;
+ WindowRect.right = p_rect.position.x + p_rect.size.x;
+ WindowRect.top = p_rect.position.y;
+ WindowRect.bottom = p_rect.position.y + p_rect.size.y;
+
+ AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
+
+ WindowID id = window_id_counter;
+ {
+ WindowData wd;
+
+ wd.hWnd = CreateWindowExW(
+ dwExStyle,
+ L"Engine", L"",
+ dwStyle,
+ // (GetSystemMetrics(SM_CXSCREEN) - WindowRect.right) / 2,
+ // (GetSystemMetrics(SM_CYSCREEN) - WindowRect.bottom) / 2,
+ WindowRect.left,
+ WindowRect.top,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ nullptr, nullptr, hInstance, nullptr);
+ if (!wd.hWnd) {
+ MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
+ return INVALID_WINDOW_ID;
+ }
+#ifdef VULKAN_ENABLED
+
+ if (rendering_driver == "vulkan") {
+ if (context_vulkan->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
+ ERR_FAIL_V(INVALID_WINDOW_ID);
+ }
+ }
+#endif
+
+ RegisterTouchWindow(wd.hWnd, 0);
+
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = wd.hWnd;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&tme);
+
+ DragAcceptFiles(wd.hWnd, true);
+
+ // IME
+ wd.im_himc = ImmGetContext(wd.hWnd);
+ ImmReleaseContext(wd.hWnd, wd.im_himc);
+
+ wd.im_position = Vector2();
+ wd.last_pos = p_rect.position;
+ wd.width = p_rect.size.width;
+ wd.height = p_rect.size.height;
+
+ windows[id] = wd;
+
+ window_id_counter++;
+ }
+
+ return id;
+}
+
+GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
+GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
+
+typedef enum _SHC_PROCESS_DPI_AWARENESS {
+ SHC_PROCESS_DPI_UNAWARE = 0,
+ SHC_PROCESS_SYSTEM_DPI_AWARE = 1,
+ SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2
+} SHC_PROCESS_DPI_AWARENESS;
+
+DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+
+ //Note: Functions for pen input, available on Windows 8+
+ HMODULE user32_lib = LoadLibraryW(L"user32.dll");
+ if (user32_lib) {
+ win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
+ win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
+ }
+
+ drop_events = false;
+ key_event_pos = 0;
+
+ alt_mem = false;
+ gr_mem = false;
+ shift_mem = false;
+ control_mem = false;
+ meta_mem = false;
+ console_visible = IsWindowVisible(GetConsoleWindow());
+ hInstance = ((OS_Windows *)OS::get_singleton())->get_hinstance();
+
+ pressrc = 0;
+ old_invalid = true;
+ mouse_mode = MOUSE_MODE_VISIBLE;
+
+ outside = true;
+
+ if (OS::get_singleton()->is_hidpi_allowed()) {
+ HMODULE Shcore = LoadLibraryW(L"Shcore.dll");
+
+ if (Shcore != nullptr) {
+ typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(SHC_PROCESS_DPI_AWARENESS);
+
+ SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)GetProcAddress(Shcore, "SetProcessDpiAwareness");
+
+ if (SetProcessDpiAwareness) {
+ SetProcessDpiAwareness(SHC_PROCESS_SYSTEM_DPI_AWARE);
+ }
+ }
+ }
+
+ memset(&wc, 0, sizeof(WNDCLASSEXW));
+ wc.cbSize = sizeof(WNDCLASSEXW);
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
+ wc.lpfnWndProc = (WNDPROC)::WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ //wc.hInstance = hInstance;
+ wc.hInstance = hInstance ? hInstance : GetModuleHandle(nullptr);
+ wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
+ wc.hCursor = nullptr; //LoadCursor(nullptr, IDC_ARROW);
+ wc.hbrBackground = nullptr;
+ wc.lpszMenuName = nullptr;
+ wc.lpszClassName = L"Engine";
+
+ if (!RegisterClassExW(&wc)) {
+ MessageBox(nullptr, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
+ r_error = ERR_UNAVAILABLE;
+ return;
+ }
+
+ use_raw_input = true;
+
+ RAWINPUTDEVICE Rid[1];
+
+ Rid[0].usUsagePage = 0x01;
+ Rid[0].usUsage = 0x02;
+ Rid[0].dwFlags = 0;
+ Rid[0].hwndTarget = 0;
+
+ if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
+ //registration failed.
+ use_raw_input = false;
+ }
+
+ rendering_driver = "vulkan";
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ context_vulkan = memnew(VulkanContextWindows);
+ if (context_vulkan->initialize() != OK) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
+ }
+ }
+#endif
+#if defined(OPENGL_ENABLED)
+ if (rendering_driver_index == VIDEO_DRIVER_GLES2) {
+
+ context_gles2 = memnew(ContextGL_Windows(hWnd, false));
+
+ if (context_gles2->initialize() != OK) {
+ memdelete(context_gles2);
+ context_gles2 = nullptr;
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+
+ context_gles2->set_use_vsync(video_mode.use_vsync);
+ set_vsync_via_compositor(video_mode.vsync_via_compositor);
+
+ if (RasterizerGLES2::is_viable() == OK) {
+ RasterizerGLES2::register_config();
+ RasterizerGLES2::make_current();
+ } else {
+ memdelete(context_gles2);
+ context_gles2 = nullptr;
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ }
+#endif
+ WindowID main_window = _create_window(p_mode, 0, Rect2i(Point2i(), p_resolution));
+ for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+ if (p_flags & (1 << i)) {
+ window_set_flag(WindowFlags(i), true, main_window);
+ }
+ }
+
+ ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window
+ SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority
+ SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To
+
+#if defined(VULKAN_ENABLED)
+
+ if (rendering_driver == "vulkan") {
+
+ rendering_device_vulkan = memnew(RenderingDeviceVulkan);
+ rendering_device_vulkan->initialize(context_vulkan);
+
+ RasterizerRD::make_current();
+ }
+#endif
+
+ move_timer_id = 1;
+
+ //set_ime_active(false);
+
+ if (!OS::get_singleton()->is_in_low_processor_usage_mode()) {
+ //SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
+ SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
+ DWORD index = 0;
+ HANDLE handle = AvSetMmThreadCharacteristics("Games", &index);
+ if (handle)
+ AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL);
+
+ // This is needed to make sure that background work does not starve the main thread.
+ // This is only setting priority of this thread, not the whole process.
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ }
+
+ cursor_shape = CURSOR_ARROW;
+
+ _update_real_mouse_position(MAIN_WINDOW_ID);
+
+ joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
+
+ r_error = OK;
+
+ ((OS_Windows *)OS::get_singleton())->set_main_window(windows[MAIN_WINDOW_ID].hWnd);
+ InputFilter::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
+}
+
+Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
+ Vector<String> drivers;
+
+#ifdef VULKAN_ENABLED
+ drivers.push_back("vulkan");
+#endif
+#ifdef OPENGL_ENABLED
+ drivers.push_back("opengl");
+#endif
+
+ return drivers;
+}
+
+DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+
+ return memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
+}
+
+void DisplayServerWindows::register_windows_driver() {
+
+ register_create_function("windows", create_func, get_rendering_drivers_func);
+}
+
+DisplayServerWindows::~DisplayServerWindows() {
+
+ delete joypad;
+ touch_state.clear();
+
+ cursors_cache.clear();
+
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+
+ if (rendering_device_vulkan) {
+ rendering_device_vulkan->finalize();
+ memdelete(rendering_device_vulkan);
+ }
+
+ if (context_vulkan)
+ memdelete(context_vulkan);
+ }
+#endif
+
+ if (user_proc) {
+ SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
+ };
+
+ if (windows.has(MAIN_WINDOW_ID)) {
+#ifdef VULKAN_ENABLED
+ if (rendering_driver == "vulkan") {
+ context_vulkan->window_destroy(MAIN_WINDOW_ID);
+ }
+#endif
+
+ DestroyWindow(windows[MAIN_WINDOW_ID].hWnd);
+ }
+}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
new file mode 100644
index 0000000000..5cd240ffb0
--- /dev/null
+++ b/platform/windows/display_server_windows.h
@@ -0,0 +1,418 @@
+/*************************************************************************/
+/* display_server_windows.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 DISPLAY_SERVER_WINDOWS_H
+#define DISPLAY_SERVER_WINDOWS_H
+
+#include "servers/display_server.h"
+
+#include "core/input/input_filter.h"
+#include "core/os/os.h"
+#include "core/project_settings.h"
+#include "crash_handler_windows.h"
+#include "drivers/unix/ip_unix.h"
+#include "drivers/wasapi/audio_driver_wasapi.h"
+#include "drivers/winmidi/midi_driver_winmidi.h"
+#include "joypad_windows.h"
+#include "key_mapping_windows.h"
+#include "servers/audio_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
+#include "servers/rendering_server.h"
+
+#ifdef XAUDIO2_ENABLED
+#include "drivers/xaudio2/audio_driver_xaudio2.h"
+#endif
+
+#if defined(OPENGL_ENABLED)
+#include "context_gl_windows.h"
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_device_vulkan.h"
+#include "platform/windows/vulkan_context_win.h"
+#endif
+
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <windows.h>
+#include <windowsx.h>
+
+#ifndef POINTER_STRUCTURES
+
+#define POINTER_STRUCTURES
+
+typedef DWORD POINTER_INPUT_TYPE;
+typedef UINT32 POINTER_FLAGS;
+typedef UINT32 PEN_FLAGS;
+typedef UINT32 PEN_MASK;
+
+enum tagPOINTER_INPUT_TYPE {
+ PT_POINTER = 0x00000001,
+ PT_TOUCH = 0x00000002,
+ PT_PEN = 0x00000003,
+ PT_MOUSE = 0x00000004,
+ PT_TOUCHPAD = 0x00000005
+};
+
+typedef enum tagPOINTER_BUTTON_CHANGE_TYPE {
+ POINTER_CHANGE_NONE,
+ POINTER_CHANGE_FIRSTBUTTON_DOWN,
+ POINTER_CHANGE_FIRSTBUTTON_UP,
+ POINTER_CHANGE_SECONDBUTTON_DOWN,
+ POINTER_CHANGE_SECONDBUTTON_UP,
+ POINTER_CHANGE_THIRDBUTTON_DOWN,
+ POINTER_CHANGE_THIRDBUTTON_UP,
+ POINTER_CHANGE_FOURTHBUTTON_DOWN,
+ POINTER_CHANGE_FOURTHBUTTON_UP,
+ POINTER_CHANGE_FIFTHBUTTON_DOWN,
+ POINTER_CHANGE_FIFTHBUTTON_UP,
+} POINTER_BUTTON_CHANGE_TYPE;
+
+typedef struct tagPOINTER_INFO {
+ POINTER_INPUT_TYPE pointerType;
+ UINT32 pointerId;
+ UINT32 frameId;
+ POINTER_FLAGS pointerFlags;
+ HANDLE sourceDevice;
+ HWND hwndTarget;
+ POINT ptPixelLocation;
+ POINT ptHimetricLocation;
+ POINT ptPixelLocationRaw;
+ POINT ptHimetricLocationRaw;
+ DWORD dwTime;
+ UINT32 historyCount;
+ INT32 InputData;
+ DWORD dwKeyStates;
+ UINT64 PerformanceCount;
+ POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
+} POINTER_INFO;
+
+typedef struct tagPOINTER_PEN_INFO {
+ POINTER_INFO pointerInfo;
+ PEN_FLAGS penFlags;
+ PEN_MASK penMask;
+ UINT32 pressure;
+ UINT32 rotation;
+ INT32 tiltX;
+ INT32 tiltY;
+} POINTER_PEN_INFO;
+
+#endif //POINTER_STRUCTURES
+
+typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type);
+typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info);
+
+typedef struct {
+ BYTE bWidth; // Width, in pixels, of the image
+ BYTE bHeight; // Height, in pixels, of the image
+ BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
+ BYTE bReserved; // Reserved ( must be 0)
+ WORD wPlanes; // Color Planes
+ WORD wBitCount; // Bits per pixel
+ DWORD dwBytesInRes; // How many bytes in this resource?
+ DWORD dwImageOffset; // Where in the file is this image?
+} ICONDIRENTRY, *LPICONDIRENTRY;
+
+typedef struct {
+ WORD idReserved; // Reserved (must be 0)
+ WORD idType; // Resource Type (1 for icons)
+ WORD idCount; // How many images?
+ ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
+} ICONDIR, *LPICONDIR;
+
+class DisplayServerWindows : public DisplayServer {
+ //No need to register, it's platform-specific and nothing is added
+ //GDCLASS(DisplayServerWindows, DisplayServer)
+
+ _THREAD_SAFE_CLASS_
+
+ static GetPointerTypePtr win8p_GetPointerType;
+ static GetPointerPenInfoPtr win8p_GetPointerPenInfo;
+
+ void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
+
+ enum {
+ KEY_EVENT_BUFFER_SIZE = 512
+ };
+
+ struct KeyEvent {
+
+ WindowID window_id;
+ bool alt, shift, control, meta;
+ UINT uMsg;
+ WPARAM wParam;
+ LPARAM lParam;
+ };
+
+ KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
+ int key_event_pos;
+
+ bool old_invalid;
+ bool outside;
+ int old_x, old_y;
+ Point2i center;
+
+#if defined(OPENGL_ENABLED)
+ ContextGL_Windows *context_gles2;
+#endif
+
+#if defined(VULKAN_ENABLED)
+ VulkanContextWindows *context_vulkan;
+ RenderingDeviceVulkan *rendering_device_vulkan;
+#endif
+
+ Map<int, Vector2> touch_state;
+
+ int pressrc;
+ HINSTANCE hInstance; // Holds The Instance Of The Application
+ String rendering_driver;
+
+ struct WindowData {
+ HWND hWnd;
+ //layered window
+
+ bool preserve_window_size = false;
+ bool pre_fs_valid = false;
+ RECT pre_fs_rect;
+ bool maximized = false;
+ bool minimized = false;
+ bool fullscreen = false;
+ bool borderless = false;
+ bool resizable = true;
+ bool window_focused = false;
+ bool was_maximized = false;
+ bool always_on_top = false;
+ bool no_focus = false;
+ bool window_has_focus = false;
+
+ HBITMAP hBitmap; //DIB section for layered window
+ uint8_t *dib_data = nullptr;
+ Size2 dib_size;
+ HDC hDC_dib;
+ Size2 min_size;
+ Size2 max_size;
+ int width = 0, height = 0;
+
+ Size2 window_rect;
+ Point2 last_pos;
+
+ ObjectID instance_id;
+
+ // IME
+ HIMC im_himc;
+ Vector2 im_position;
+
+ bool layered_window = false;
+
+ Callable rect_changed_callback;
+ Callable event_callback;
+ Callable input_event_callback;
+ Callable input_text_callback;
+ Callable drop_files_callback;
+
+ WindowID transient_parent = INVALID_WINDOW_ID;
+ Set<WindowID> transient_children;
+ };
+
+ JoypadWindows *joypad;
+
+ WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect);
+ WindowID window_id_counter = MAIN_WINDOW_ID;
+ Map<WindowID, WindowData> windows;
+
+ WindowID last_focused_window = INVALID_WINDOW_ID;
+
+ uint32_t move_timer_id;
+
+ HCURSOR hCursor;
+
+ WNDPROC user_proc = nullptr;
+
+ void _send_window_event(const WindowData &wd, WindowEvent p_event);
+ void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
+
+ MouseMode mouse_mode;
+ bool alt_mem = false;
+ bool gr_mem = false;
+ bool shift_mem = false;
+ bool control_mem = false;
+ bool meta_mem = false;
+ uint32_t last_button_state = 0;
+ bool use_raw_input = false;
+ bool drop_events = false;
+ bool console_visible = false;
+
+ WNDCLASSEXW wc;
+
+ HCURSOR cursors[CURSOR_MAX] = { nullptr };
+ CursorShape cursor_shape;
+ Map<CursorShape, Vector<Variant>> cursors_cache;
+
+ void _drag_event(WindowID p_window, float p_x, float p_y, int idx);
+ void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
+
+ void _update_window_style(WindowID p_window, bool p_repaint = true, bool p_maximized = false);
+
+ void _update_real_mouse_position(WindowID p_window);
+
+ void _set_mouse_mode_impl(MouseMode p_mode);
+
+ void _process_key_events();
+
+ static void _dispatch_input_events(const Ref<InputEvent> &p_event);
+ void _dispatch_input_event(const Ref<InputEvent> &p_event);
+
+public:
+ LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ virtual bool has_feature(Feature p_feature) const;
+ virtual String get_name() const;
+
+ virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+
+ virtual void mouse_set_mode(MouseMode p_mode);
+ virtual MouseMode mouse_get_mode() const;
+
+ virtual void mouse_warp_to_position(const Point2i &p_to);
+ virtual Point2i mouse_get_position() const;
+ virtual int mouse_get_button_state() const;
+
+ virtual void clipboard_set(const String &p_text);
+ virtual String clipboard_get() const;
+
+ virtual int get_screen_count() const;
+ virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW);
+ ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual void screen_set_keep_on(bool p_enable); //disable screensaver
+ virtual bool screen_is_kept_on() const;
+
+ virtual Vector<DisplayServer::WindowID> get_window_list() const;
+
+ virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+ virtual void delete_sub_window(WindowID p_window);
+
+ virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
+
+ virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID);
+ virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void window_set_transient(WindowID p_window, WindowID p_parent);
+
+ virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+ virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const; //wtf is this? should probable use proper name
+
+ virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
+ virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
+ virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
+
+ virtual bool can_any_window_draw() const;
+
+ virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual void console_set_visible(bool p_enabled);
+ virtual bool is_console_visible() const;
+
+ virtual void cursor_set_shape(CursorShape p_shape);
+ virtual CursorShape cursor_get_shape() const;
+ virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+
+ virtual bool get_swap_ok_cancel();
+
+ virtual void enable_for_stealing_focus(OS::ProcessID pid);
+
+ virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+ virtual void process_events();
+
+ virtual void force_process_and_drop_events();
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ virtual void set_native_icon(const String &p_filename);
+ virtual void set_icon(const Ref<Image> &p_icon);
+
+ virtual void vsync_set_use_via_compositor(bool p_enable);
+ virtual bool vsync_is_using_via_compositor() const;
+
+ virtual void set_context(Context p_context);
+
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static Vector<String> get_rendering_drivers_func();
+ static void register_windows_driver();
+
+ DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ ~DisplayServerWindows();
+};
+
+#endif // DISPLAY_SERVER_WINDOWS_H
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 78a3fc8f79..d63067587c 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -315,7 +315,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#endif
String str;
- Error err = OS::get_singleton()->execute(signtool_path, args, true, NULL, &str, NULL, true);
+ Error err = OS::get_singleton()->execute(signtool_path, args, true, nullptr, &str, nullptr, true);
ERR_FAIL_COND_V(err != OK, err);
print_line("codesign (" + p_path + "): " + str);
diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp
index dcc12b7649..2aa928c2a7 100644
--- a/platform/windows/godot_windows.cpp
+++ b/platform/windows/godot_windows.cpp
@@ -121,23 +121,23 @@ CommandLineToArgvA(
i++;
}
_argv[j] = '\0';
- argv[argc] = NULL;
+ argv[argc] = nullptr;
(*_argc) = argc;
return argv;
}
char *wc_to_utf8(const wchar_t *wc) {
- int ulen = WideCharToMultiByte(CP_UTF8, 0, wc, -1, NULL, 0, NULL, NULL);
+ int ulen = WideCharToMultiByte(CP_UTF8, 0, wc, -1, nullptr, 0, nullptr, nullptr);
char *ubuf = new char[ulen + 1];
- WideCharToMultiByte(CP_UTF8, 0, wc, -1, ubuf, ulen, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, wc, -1, ubuf, ulen, nullptr, nullptr);
ubuf[ulen] = 0;
return ubuf;
}
int widechar_main(int argc, wchar_t **argv) {
- OS_Windows os(NULL);
+ OS_Windows os(nullptr);
setlocale(LC_CTYPE, "");
@@ -176,7 +176,7 @@ int _main() {
wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
- if (NULL == wc_argv) {
+ if (nullptr == wc_argv) {
wprintf(L"CommandLineToArgvW failed\n");
return 0;
}
@@ -202,9 +202,9 @@ int main(int _argc, char **_argv) {
#endif
}
-HINSTANCE godot_hinstance = NULL;
+HINSTANCE godot_hinstance = nullptr;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
godot_hinstance = hInstance;
- return main(0, NULL);
+ return main(0, nullptr);
}
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index 49432435b9..437c3b733d 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -52,15 +52,15 @@ DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
JoypadWindows::JoypadWindows() {
}
-JoypadWindows::JoypadWindows(InputDefault *_input, HWND *hwnd) {
+JoypadWindows::JoypadWindows(HWND *hwnd) {
- input = _input;
+ input = InputFilter::get_singleton();
hWnd = hwnd;
joypad_count = 0;
- dinput = NULL;
- xinput_dll = NULL;
- xinput_get_state = NULL;
- xinput_set_state = NULL;
+ dinput = nullptr;
+ xinput_dll = nullptr;
+ xinput_get_state = nullptr;
+ xinput_set_state = nullptr;
load_xinput();
@@ -68,7 +68,7 @@ JoypadWindows::JoypadWindows(InputDefault *_input, HWND *hwnd) {
attached_joypads[i] = false;
HRESULT result;
- result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, NULL);
+ result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr);
if (FAILED(result)) {
printf("failed init DINPUT: %ld\n", result);
}
@@ -105,10 +105,10 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
if (p_guid == &IID_ValveStreamingGamepad || p_guid == &IID_X360WiredGamepad || p_guid == &IID_X360WirelessGamepad)
return true;
- PRAWINPUTDEVICELIST dev_list = NULL;
+ PRAWINPUTDEVICELIST dev_list = nullptr;
unsigned int dev_list_count = 0;
- if (GetRawInputDeviceList(NULL, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
+ if (GetRawInputDeviceList(nullptr, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) {
return false;
}
dev_list = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
@@ -130,7 +130,7 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
(GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) &&
(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_") != NULL)) {
+ (strstr(dev_name, "IG_") != nullptr)) {
free(dev_list);
return true;
@@ -157,7 +157,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
return false;
}
- hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, NULL);
+ hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, nullptr);
if (FAILED(hr)) {
return false;
@@ -436,46 +436,46 @@ void JoypadWindows::post_hat(int p_device, DWORD p_dpad) {
// BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);"
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks
if (LOWORD(p_dpad) == 0xFFFF) {
- dpad_val = InputDefault::HAT_MASK_CENTER;
+ dpad_val = InputFilter::HAT_MASK_CENTER;
}
if (p_dpad == 0) {
- dpad_val = InputDefault::HAT_MASK_UP;
+ dpad_val = InputFilter::HAT_MASK_UP;
} else if (p_dpad == 4500) {
- dpad_val = (InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT);
+ dpad_val = (InputFilter::HAT_MASK_UP | InputFilter::HAT_MASK_RIGHT);
} else if (p_dpad == 9000) {
- dpad_val = InputDefault::HAT_MASK_RIGHT;
+ dpad_val = InputFilter::HAT_MASK_RIGHT;
} else if (p_dpad == 13500) {
- dpad_val = (InputDefault::HAT_MASK_RIGHT | InputDefault::HAT_MASK_DOWN);
+ dpad_val = (InputFilter::HAT_MASK_RIGHT | InputFilter::HAT_MASK_DOWN);
} else if (p_dpad == 18000) {
- dpad_val = InputDefault::HAT_MASK_DOWN;
+ dpad_val = InputFilter::HAT_MASK_DOWN;
} else if (p_dpad == 22500) {
- dpad_val = (InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT);
+ dpad_val = (InputFilter::HAT_MASK_DOWN | InputFilter::HAT_MASK_LEFT);
} else if (p_dpad == 27000) {
- dpad_val = InputDefault::HAT_MASK_LEFT;
+ dpad_val = InputFilter::HAT_MASK_LEFT;
} else if (p_dpad == 31500) {
- dpad_val = (InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_UP);
+ dpad_val = (InputFilter::HAT_MASK_LEFT | InputFilter::HAT_MASK_UP);
}
input->joy_hat(p_device, dpad_val);
};
-InputDefault::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
+InputFilter::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
- InputDefault::JoyAxis jx;
+ InputFilter::JoyAxis 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 ab85bc60ac..0db789c335 100644
--- a/platform/windows/joypad_windows.h
+++ b/platform/windows/joypad_windows.h
@@ -39,9 +39,9 @@
#ifndef SAFE_RELEASE // when Windows Media Device M? is not present
#define SAFE_RELEASE(x) \
- if (x != NULL) { \
+ if (x != nullptr) { \
x->Release(); \
- x = NULL; \
+ x = nullptr; \
}
#endif
@@ -52,7 +52,7 @@
class JoypadWindows {
public:
JoypadWindows();
- JoypadWindows(InputDefault *_input, HWND *hwnd);
+ JoypadWindows(HWND *hwnd);
~JoypadWindows();
void probe_joypads();
@@ -117,7 +117,7 @@ private:
HWND *hWnd;
HANDLE xinput_dll;
LPDIRECTINPUT8 dinput;
- InputDefault *input;
+ InputFilter *input;
int id_to_change;
int joypad_count;
@@ -141,7 +141,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);
- InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
+ InputFilter::JoyAxis 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 a112f26ac4..0a67a591b7 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -37,15 +37,6 @@
#include "core/debugger/script_debugger.h"
#include "core/io/marshalls.h"
#include "core/version_generated.gen.h"
-
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
-
-#if defined(VULKAN_ENABLED)
-#include "servers/visual/rasterizer_rd/rasterizer_rd.h"
-#endif
-
#include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h"
#include "drivers/windows/rw_lock_windows.h"
@@ -53,9 +44,10 @@
#include "joypad_windows.h"
#include "lang_table.h"
#include "main/main.h"
+#include "platform/windows/display_server_windows.h"
#include "servers/audio_server.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
+#include "servers/rendering/rendering_server_raster.h"
+#include "servers/rendering/rendering_server_wrap_mt.h"
#include "windows_terminal_logger.h"
#include <avrt.h>
@@ -86,36 +78,12 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#define GetProcAddress (void *)GetProcAddress
#endif
-typedef struct {
- int count;
- int screen;
- Size2 size;
-} EnumSizeData;
-
-typedef struct {
- int count;
- int screen;
- Point2 pos;
-} EnumPosData;
-
-static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
-
- EnumSizeData *data = (EnumSizeData *)dwData;
- if (data->count == data->screen) {
- data->size.x = lprcMonitor->right - lprcMonitor->left;
- data->size.y = lprcMonitor->bottom - lprcMonitor->top;
- }
-
- data->count++;
- return TRUE;
-}
-
#ifdef DEBUG_ENABLED
static String format_error_message(DWORD id) {
- LPWSTR messageBuffer = NULL;
+ LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
+ nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
@@ -125,8 +93,6 @@ static String format_error_message(DWORD id) {
}
#endif // DEBUG_ENABLED
-extern HINSTANCE godot_hinstance;
-
void RedirectIOToConsole() {
int hConHandle;
@@ -163,7 +129,7 @@ void RedirectIOToConsole() {
*stdout = *fp;
- setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stdout, nullptr, _IONBF, 0);
// redirect unbuffered STDIN to the console
@@ -175,7 +141,7 @@ void RedirectIOToConsole() {
*stdin = *fp;
- setvbuf(stdin, NULL, _IONBF, 0);
+ setvbuf(stdin, nullptr, _IONBF, 0);
// redirect unbuffered STDERR to the console
@@ -187,7 +153,7 @@ void RedirectIOToConsole() {
*stderr = *fp;
- setvbuf(stderr, NULL, _IONBF, 0);
+ setvbuf(stderr, nullptr, _IONBF, 0);
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
@@ -208,24 +174,16 @@ BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
}
}
-GetPointerTypePtr OS_Windows::win8p_GetPointerType = NULL;
-GetPointerPenInfoPtr OS_Windows::win8p_GetPointerPenInfo = NULL;
-
void OS_Windows::initialize_debugging() {
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
}
-void OS_Windows::initialize_core() {
+void OS_Windows::initialize() {
crash_handler.initialize();
- last_button_state = 0;
-
//RedirectIOToConsole();
- maximized = false;
- minimized = false;
- borderless = false;
ThreadWindows::make_default();
RWLockWindows::make_default();
@@ -255,1381 +213,18 @@ void OS_Windows::initialize_core() {
process_map = memnew((Map<ProcessID, ProcessInfo>));
IP_Unix::make_default();
-
- cursor_shape = CURSOR_ARROW;
-}
-
-bool OS_Windows::can_draw() const {
-
- return !minimized;
-};
-
-#define MI_WP_SIGNATURE 0xFF515700
-#define SIGNATURE_MASK 0xFFFFFF00
-// Keeping the name suggested by Microsoft, but this macro really answers:
-// Is this mouse event emulated from touch or pen input?
-#define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE)
-// This one tells whether the event comes from touchscreen (and not from pen)
-#define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw)&0x80))
-
-void OS_Windows::_touch_event(bool p_pressed, float p_x, float p_y, int idx) {
-
- // Defensive
- if (touch_state.has(idx) == p_pressed)
- return;
-
- if (p_pressed) {
- touch_state.insert(idx, Vector2(p_x, p_y));
- } else {
- touch_state.erase(idx);
- }
-
- Ref<InputEventScreenTouch> event;
- event.instance();
- event->set_index(idx);
- event->set_pressed(p_pressed);
- event->set_position(Vector2(p_x, p_y));
-
- if (main_loop) {
- input->accumulate_input_event(event);
- }
-};
-
-void OS_Windows::_drag_event(float p_x, float p_y, int idx) {
-
- Map<int, Vector2>::Element *curr = touch_state.find(idx);
- // Defensive
- if (!curr)
- return;
-
- if (curr->get() == Vector2(p_x, p_y))
- return;
-
- Ref<InputEventScreenDrag> event;
- event.instance();
- event->set_index(idx);
- event->set_position(Vector2(p_x, p_y));
- event->set_relative(Vector2(p_x, p_y) - curr->get());
-
- if (main_loop)
- input->accumulate_input_event(event);
-
- curr->get() = Vector2(p_x, p_y);
-};
-
-LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
-
- if (drop_events) {
-
- if (user_proc) {
-
- return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
- } else {
- return DefWindowProcW(hWnd, uMsg, wParam, lParam);
- }
- };
-
- switch (uMsg) // Check For Windows Messages
- {
- case WM_SETFOCUS: {
- window_has_focus = true;
-
- // Restore mouse mode
- _set_mouse_mode_impl(mouse_mode);
-
- break;
- }
- case WM_KILLFOCUS: {
- window_has_focus = false;
-
- // Release capture unconditionally because it can be set due to dragging, in addition to captured mode
- ReleaseCapture();
-
- // Release every touch to avoid sticky points
- for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) {
- _touch_event(false, E->get().x, E->get().y, E->key());
- }
- touch_state.clear();
-
- break;
- }
- case WM_ACTIVATE: // Watch For Window Activate Message
- {
- minimized = HIWORD(wParam) != 0;
- if (!main_loop) {
- return 0;
- };
- if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) {
-
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
- window_focused = true;
- alt_mem = false;
- control_mem = false;
- shift_mem = false;
- } else { // WM_INACTIVE
- input->release_pressed_events();
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
- window_focused = false;
- alt_mem = false;
- };
-
- return 0; // Return To The Message Loop
- }
- case WM_GETMINMAXINFO: {
- if (video_mode.resizable && !video_mode.fullscreen) {
- Size2 decor = get_real_window_size() - get_window_size(); // Size of window decorations
- MINMAXINFO *min_max_info = (MINMAXINFO *)lParam;
- if (min_size != Size2()) {
- min_max_info->ptMinTrackSize.x = min_size.x + decor.x;
- min_max_info->ptMinTrackSize.y = min_size.y + decor.y;
- }
- if (max_size != Size2()) {
- min_max_info->ptMaxTrackSize.x = max_size.x + decor.x;
- min_max_info->ptMaxTrackSize.y = max_size.y + decor.y;
- }
- return 0;
- } else {
- break;
- }
- }
- case WM_PAINT:
-
- Main::force_redraw();
- break;
-
- case WM_SYSCOMMAND: // Intercept System Commands
- {
- switch (wParam) // Check System Calls
- {
- case SC_SCREENSAVE: // Screensaver Trying To Start?
- case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
- return 0; // Prevent From Happening
- case SC_KEYMENU:
- if ((lParam >> 16) <= 0)
- return 0;
- }
- break; // Exit
- }
-
- case WM_CLOSE: // Did We Receive A Close Message?
- {
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
- //force_quit=true;
- return 0; // Jump Back
- }
- case WM_MOUSELEAVE: {
-
- old_invalid = true;
- outside = true;
- if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
- main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
-
- } break;
- case WM_INPUT: {
- if (mouse_mode != MOUSE_MODE_CAPTURED || !use_raw_input) {
- break;
- }
-
- UINT dwSize;
-
- GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
- LPBYTE lpb = new BYTE[dwSize];
- if (lpb == NULL) {
- return 0;
- }
-
- if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
- OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));
-
- RAWINPUT *raw = (RAWINPUT *)lpb;
-
- if (raw->header.dwType == RIM_TYPEMOUSE) {
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- mm->set_control(control_mem);
- mm->set_shift(shift_mem);
- mm->set_alt(alt_mem);
-
- mm->set_button_mask(last_button_state);
-
- Point2i c(video_mode.width / 2, video_mode.height / 2);
-
- // centering just so it works as before
- POINT pos = { (int)c.x, (int)c.y };
- ClientToScreen(hWnd, &pos);
- SetCursorPos(pos.x, pos.y);
-
- mm->set_position(c);
- mm->set_global_position(c);
- input->set_mouse_position(c);
- mm->set_speed(Vector2(0, 0));
-
- if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE) {
- mm->set_relative(Vector2(raw->data.mouse.lLastX, raw->data.mouse.lLastY));
-
- } else if (raw->data.mouse.usFlags == MOUSE_MOVE_ABSOLUTE) {
-
- int nScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
- int nScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
- int nScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN);
- int nScreenTop = GetSystemMetrics(SM_YVIRTUALSCREEN);
-
- Vector2 abs_pos(
- (double(raw->data.mouse.lLastX) - 65536.0 / (nScreenWidth)) * nScreenWidth / 65536.0 + nScreenLeft,
- (double(raw->data.mouse.lLastY) - 65536.0 / (nScreenHeight)) * nScreenHeight / 65536.0 + nScreenTop);
-
- POINT coords; //client coords
- coords.x = abs_pos.x;
- coords.y = abs_pos.y;
-
- ScreenToClient(hWnd, &coords);
-
- mm->set_relative(Vector2(coords.x - old_x, coords.y - old_y));
- old_x = coords.x;
- old_y = coords.y;
-
- /*Input.mi.dx = (int)((((double)(pos.x)-nScreenLeft) * 65536) / nScreenWidth + 65536 / (nScreenWidth));
- Input.mi.dy = (int)((((double)(pos.y)-nScreenTop) * 65536) / nScreenHeight + 65536 / (nScreenHeight));
- */
- }
-
- if (window_has_focus && main_loop && mm->get_relative() != Vector2())
- input->accumulate_input_event(mm);
- }
- delete[] lpb;
- } break;
- case WM_POINTERUPDATE: {
- if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
- break;
- }
-
- if (!win8p_GetPointerType || !win8p_GetPointerPenInfo) {
- break;
- }
-
- uint32_t pointer_id = LOWORD(wParam);
- POINTER_INPUT_TYPE pointer_type = PT_POINTER;
- if (!win8p_GetPointerType(pointer_id, &pointer_type)) {
- break;
- }
-
- if (pointer_type != PT_PEN) {
- break;
- }
-
- POINTER_PEN_INFO pen_info;
- if (!win8p_GetPointerPenInfo(pointer_id, &pen_info)) {
- break;
- }
-
- if (input->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translation
- LPARAM extra = GetMessageExtraInfo();
- if (IsTouchEvent(extra)) {
- break;
- }
- }
-
- if (outside) {
- //mouse enter
-
- if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
- main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
-
- CursorShape c = cursor_shape;
- cursor_shape = CURSOR_MAX;
- set_cursor_shape(c);
- outside = false;
-
- //Once-Off notification, must call again....
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof(TRACKMOUSEEVENT);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hWnd;
- tme.dwHoverTime = HOVER_DEFAULT;
- TrackMouseEvent(&tme);
- }
-
- // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
- if (!window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
- break;
-
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- mm->set_pressure(pen_info.pressure ? (float)pen_info.pressure / 1024 : 0);
- mm->set_tilt(Vector2(pen_info.tiltX ? (float)pen_info.tiltX / 90 : 0, pen_info.tiltY ? (float)pen_info.tiltY / 90 : 0));
-
- mm->set_control((wParam & MK_CONTROL) != 0);
- mm->set_shift((wParam & MK_SHIFT) != 0);
- mm->set_alt(alt_mem);
-
- mm->set_button_mask(last_button_state);
-
- POINT coords; //client coords
- coords.x = GET_X_LPARAM(lParam);
- coords.y = GET_Y_LPARAM(lParam);
-
- ScreenToClient(hWnd, &coords);
-
- mm->set_position(Vector2(coords.x, coords.y));
- mm->set_global_position(Vector2(coords.x, coords.y));
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
-
- Point2i c(video_mode.width / 2, video_mode.height / 2);
- old_x = c.x;
- old_y = c.y;
-
- if (mm->get_position() == c) {
- center = c;
- return 0;
- }
-
- Point2i ncenter = mm->get_position();
- center = ncenter;
- POINT pos = { (int)c.x, (int)c.y };
- ClientToScreen(hWnd, &pos);
- SetCursorPos(pos.x, pos.y);
- }
-
- input->set_mouse_position(mm->get_position());
- mm->set_speed(input->get_last_mouse_speed());
-
- if (old_invalid) {
-
- old_x = mm->get_position().x;
- old_y = mm->get_position().y;
- old_invalid = false;
- }
-
- mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
- old_x = mm->get_position().x;
- old_y = mm->get_position().y;
- if (window_has_focus && main_loop)
- input->parse_input_event(mm);
-
- return 0; //Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event
- } break;
- case WM_MOUSEMOVE: {
- if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
- break;
- }
-
- if (input->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translation
- LPARAM extra = GetMessageExtraInfo();
- if (IsTouchEvent(extra)) {
- break;
- }
- }
-
- if (outside) {
- //mouse enter
-
- if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
- main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
-
- CursorShape c = cursor_shape;
- cursor_shape = CURSOR_MAX;
- set_cursor_shape(c);
- outside = false;
-
- //Once-Off notification, must call again....
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof(TRACKMOUSEEVENT);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hWnd;
- tme.dwHoverTime = HOVER_DEFAULT;
- TrackMouseEvent(&tme);
- }
-
- // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
- if (!window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
- break;
-
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- mm->set_control((wParam & MK_CONTROL) != 0);
- mm->set_shift((wParam & MK_SHIFT) != 0);
- mm->set_alt(alt_mem);
-
- mm->set_button_mask(last_button_state);
-
- mm->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
- mm->set_global_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
-
- Point2i c(video_mode.width / 2, video_mode.height / 2);
- old_x = c.x;
- old_y = c.y;
-
- if (mm->get_position() == c) {
- center = c;
- return 0;
- }
-
- Point2i ncenter = mm->get_position();
- center = ncenter;
- POINT pos = { (int)c.x, (int)c.y };
- ClientToScreen(hWnd, &pos);
- SetCursorPos(pos.x, pos.y);
- }
-
- input->set_mouse_position(mm->get_position());
- mm->set_speed(input->get_last_mouse_speed());
-
- if (old_invalid) {
-
- old_x = mm->get_position().x;
- old_y = mm->get_position().y;
- old_invalid = false;
- }
-
- mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
- old_x = mm->get_position().x;
- old_y = mm->get_position().y;
- if (window_has_focus && main_loop)
- input->accumulate_input_event(mm);
-
- } break;
- case WM_LBUTTONDOWN:
- case WM_LBUTTONUP:
- if (input->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translations for left button
- LPARAM extra = GetMessageExtraInfo();
- if (IsTouchEvent(extra)) {
- break;
- }
- }
- [[fallthrough]];
- case WM_MBUTTONDOWN:
- case WM_MBUTTONUP:
- case WM_RBUTTONDOWN:
- case WM_RBUTTONUP:
- case WM_MOUSEWHEEL:
- case WM_MOUSEHWHEEL:
- case WM_LBUTTONDBLCLK:
- case WM_MBUTTONDBLCLK:
- case WM_RBUTTONDBLCLK:
- case WM_XBUTTONDBLCLK:
- case WM_XBUTTONDOWN:
- case WM_XBUTTONUP: {
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- switch (uMsg) {
- case WM_LBUTTONDOWN: {
- mb->set_pressed(true);
- mb->set_button_index(1);
- } break;
- case WM_LBUTTONUP: {
- mb->set_pressed(false);
- mb->set_button_index(1);
- } break;
- case WM_MBUTTONDOWN: {
- mb->set_pressed(true);
- mb->set_button_index(3);
- } break;
- case WM_MBUTTONUP: {
- mb->set_pressed(false);
- mb->set_button_index(3);
- } break;
- case WM_RBUTTONDOWN: {
- mb->set_pressed(true);
- mb->set_button_index(2);
- } break;
- case WM_RBUTTONUP: {
- mb->set_pressed(false);
- mb->set_button_index(2);
- } break;
- case WM_LBUTTONDBLCLK: {
- mb->set_pressed(true);
- mb->set_button_index(1);
- mb->set_doubleclick(true);
- } break;
- case WM_RBUTTONDBLCLK: {
- mb->set_pressed(true);
- mb->set_button_index(2);
- mb->set_doubleclick(true);
- } break;
- case WM_MBUTTONDBLCLK: {
- mb->set_pressed(true);
- mb->set_button_index(3);
- mb->set_doubleclick(true);
- } break;
- case WM_MOUSEWHEEL: {
-
- mb->set_pressed(true);
- int motion = (short)HIWORD(wParam);
- if (!motion)
- return 0;
-
- if (motion > 0)
- mb->set_button_index(BUTTON_WHEEL_UP);
- else
- mb->set_button_index(BUTTON_WHEEL_DOWN);
-
- } break;
- case WM_MOUSEHWHEEL: {
-
- mb->set_pressed(true);
- int motion = (short)HIWORD(wParam);
- if (!motion)
- return 0;
-
- if (motion < 0) {
- mb->set_button_index(BUTTON_WHEEL_LEFT);
- mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
- } else {
- mb->set_button_index(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);
- else
- mb->set_button_index(BUTTON_XBUTTON2);
- } break;
- case WM_XBUTTONUP: {
-
- mb->set_pressed(false);
- if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
- else
- mb->set_button_index(BUTTON_XBUTTON2);
- } break;
- case WM_XBUTTONDBLCLK: {
-
- mb->set_pressed(true);
- if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
- else
- mb->set_button_index(BUTTON_XBUTTON2);
- mb->set_doubleclick(true);
- } break;
- default: {
- return 0;
- }
- }
-
- mb->set_control((wParam & MK_CONTROL) != 0);
- mb->set_shift((wParam & MK_SHIFT) != 0);
- mb->set_alt(alt_mem);
- //mb->get_alt()=(wParam&MK_MENU)!=0;
- if (mb->is_pressed())
- last_button_state |= (1 << (mb->get_button_index() - 1));
- else
- last_button_state &= ~(1 << (mb->get_button_index() - 1));
- mb->set_button_mask(last_button_state);
-
- mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
-
- if (mouse_mode == MOUSE_MODE_CAPTURED && !use_raw_input) {
-
- mb->set_position(Vector2(old_x, old_y));
- }
-
- if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) {
- if (mb->is_pressed()) {
-
- if (++pressrc > 0 && mouse_mode != MOUSE_MODE_CAPTURED)
- SetCapture(hWnd);
- } else {
-
- if (--pressrc <= 0) {
- if (mouse_mode != MOUSE_MODE_CAPTURED) {
- ReleaseCapture();
- }
- pressrc = 0;
- }
- }
- } else {
- // for reasons unknown to mankind, wheel comes in screen coordinates
- POINT coords;
- coords.x = mb->get_position().x;
- coords.y = mb->get_position().y;
-
- ScreenToClient(hWnd, &coords);
-
- mb->set_position(Vector2(coords.x, coords.y));
- }
-
- mb->set_global_position(mb->get_position());
-
- if (main_loop) {
- input->accumulate_input_event(mb);
- if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
- //send release for mouse wheel
- Ref<InputEventMouseButton> mbd = mb->duplicate();
- last_button_state &= ~(1 << (mbd->get_button_index() - 1));
- mbd->set_button_mask(last_button_state);
- mbd->set_pressed(false);
- input->accumulate_input_event(mbd);
- }
- }
- } break;
-
- case WM_MOVE: {
- if (!IsIconic(hWnd)) {
- int x = LOWORD(lParam);
- int y = HIWORD(lParam);
- last_pos = Point2(x, y);
- }
- } break;
-
- case WM_SIZE: {
- // Ignore size when a SIZE_MINIMIZED event is triggered
- if (wParam != SIZE_MINIMIZED) {
- int window_w = LOWORD(lParam);
- int window_h = HIWORD(lParam);
- if (window_w > 0 && window_h > 0 && !preserve_window_size) {
- video_mode.width = window_w;
- video_mode.height = window_h;
- } else {
- preserve_window_size = false;
- set_window_size(Size2(video_mode.width, video_mode.height));
- }
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
- context_vulkan->window_resize(0, video_mode.width, video_mode.height);
- }
-#endif
- }
-
- if (wParam == SIZE_MAXIMIZED) {
- maximized = true;
- minimized = false;
- } else if (wParam == SIZE_MINIMIZED) {
- maximized = false;
- minimized = true;
- } else if (wParam == SIZE_RESTORED) {
- maximized = false;
- minimized = false;
- }
- if (is_layered_allowed() && layered_window) {
- DeleteObject(hBitmap);
-
- RECT r;
- GetWindowRect(hWnd, &r);
- dib_size = Size2i(r.right - r.left, r.bottom - r.top);
-
- BITMAPINFO bmi;
- ZeroMemory(&bmi, sizeof(BITMAPINFO));
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmi.bmiHeader.biWidth = dib_size.x;
- bmi.bmiHeader.biHeight = dib_size.y;
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
- bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
- hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
- SelectObject(hDC_dib, hBitmap);
-
- ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
- }
- //return 0; // Jump Back
- } break;
-
- case WM_ENTERSIZEMOVE: {
- input->release_pressed_events();
- move_timer_id = SetTimer(hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC)NULL);
- } break;
- case WM_EXITSIZEMOVE: {
- KillTimer(hWnd, move_timer_id);
- } break;
- case WM_TIMER: {
- if (wParam == move_timer_id) {
- process_key_events();
- if (!Main::is_iterating()) {
- Main::iteration();
- }
- }
- } break;
-
- case WM_SYSKEYDOWN:
- case WM_SYSKEYUP:
- case WM_KEYUP:
- case WM_KEYDOWN: {
-
- if (wParam == VK_SHIFT)
- shift_mem = uMsg == WM_KEYDOWN;
- if (wParam == VK_CONTROL)
- control_mem = uMsg == WM_KEYDOWN;
- if (wParam == VK_MENU) {
- alt_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
- if (lParam & (1 << 24))
- gr_mem = alt_mem;
- }
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- // When SetCapture is used, ALT+F4 hotkey is ignored by Windows, so handle it ourselves
- if (wParam == VK_F4 && alt_mem && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) {
- if (main_loop)
- main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
- }
- }
- /*
- if (wParam==VK_WIN) TODO wtf is this?
- meta_mem=uMsg==WM_KEYDOWN;
- */
- [[fallthrough]];
- }
- case WM_CHAR: {
-
- ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
-
- // Make sure we don't include modifiers for the modifier key itself.
- KeyEvent ke;
- ke.shift = (wParam != VK_SHIFT) ? shift_mem : false;
- ke.alt = (!(wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false;
- ke.control = (wParam != VK_CONTROL) ? control_mem : false;
- ke.meta = meta_mem;
- ke.uMsg = uMsg;
-
- if (ke.uMsg == WM_SYSKEYDOWN)
- ke.uMsg = WM_KEYDOWN;
- if (ke.uMsg == WM_SYSKEYUP)
- ke.uMsg = WM_KEYUP;
-
- ke.wParam = wParam;
- ke.lParam = lParam;
- key_event_buffer[key_event_pos++] = ke;
-
- } break;
- case WM_INPUTLANGCHANGEREQUEST: {
-
- // FIXME: Do something?
- } break;
-
- case WM_TOUCH: {
-
- BOOL bHandled = FALSE;
- UINT cInputs = LOWORD(wParam);
- PTOUCHINPUT pInputs = memnew_arr(TOUCHINPUT, cInputs);
- if (pInputs) {
- if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))) {
- for (UINT i = 0; i < cInputs; i++) {
- TOUCHINPUT ti = pInputs[i];
- POINT touch_pos = {
- TOUCH_COORD_TO_PIXEL(ti.x),
- TOUCH_COORD_TO_PIXEL(ti.y),
- };
- ScreenToClient(hWnd, &touch_pos);
- //do something with each touch input entry
- if (ti.dwFlags & TOUCHEVENTF_MOVE) {
-
- _drag_event(touch_pos.x, touch_pos.y, ti.dwID);
- } else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
-
- _touch_event(ti.dwFlags & TOUCHEVENTF_DOWN, touch_pos.x, touch_pos.y, ti.dwID);
- };
- }
- bHandled = TRUE;
- } else {
- /* handle the error here */
- }
- memdelete_arr(pInputs);
- } else {
- /* handle the error here, probably out of memory */
- }
- if (bHandled) {
- CloseTouchInputHandle((HTOUCHINPUT)lParam);
- return 0;
- };
-
- } break;
-
- case WM_DEVICECHANGE: {
-
- joypad->probe_joypads();
- } break;
- case WM_SETCURSOR: {
- if (LOWORD(lParam) == HTCLIENT) {
- if (window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED)) {
- //Hide the cursor
- if (hCursor == NULL)
- hCursor = SetCursor(NULL);
- else
- SetCursor(NULL);
- } else {
- if (hCursor != NULL) {
- CursorShape c = cursor_shape;
- cursor_shape = CURSOR_MAX;
- set_cursor_shape(c);
- hCursor = NULL;
- }
- }
- }
-
- } break;
- case WM_DROPFILES: {
-
- HDROP hDropInfo = (HDROP)wParam;
- const int buffsize = 4096;
- wchar_t buf[buffsize];
-
- int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, NULL, 0);
-
- Vector<String> files;
-
- for (int i = 0; i < fcount; i++) {
-
- DragQueryFileW(hDropInfo, i, buf, buffsize);
- String file = buf;
- files.push_back(file);
- }
-
- if (files.size() && main_loop) {
- main_loop->drop_files(files, 0);
- }
-
- } break;
-
- default: {
-
- if (user_proc) {
-
- return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
- };
- };
- }
-
- return DefWindowProcW(hWnd, uMsg, wParam, lParam);
-}
-
-LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
-
- OS_Windows *os_win = static_cast<OS_Windows *>(OS::get_singleton());
- if (os_win)
- return os_win->WndProc(hWnd, uMsg, wParam, lParam);
- else
- return DefWindowProcW(hWnd, uMsg, wParam, lParam);
-}
-
-void OS_Windows::process_key_events() {
-
- for (int i = 0; i < key_event_pos; i++) {
-
- KeyEvent &ke = key_event_buffer[i];
- switch (ke.uMsg) {
-
- case WM_CHAR: {
- if ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR)) {
- Ref<InputEventKey> k;
- k.instance();
-
- k->set_shift(ke.shift);
- k->set_alt(ke.alt);
- k->set_control(ke.control);
- k->set_metakey(ke.meta);
- k->set_pressed(true);
- k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam));
- k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
- k->set_unicode(ke.wParam);
- if (k->get_unicode() && gr_mem) {
- k->set_alt(false);
- k->set_control(false);
- }
-
- if (k->get_unicode() < 32)
- k->set_unicode(0);
-
- input->accumulate_input_event(k);
- }
-
- //do nothing
- } break;
- case WM_KEYUP:
- case WM_KEYDOWN: {
-
- Ref<InputEventKey> k;
- k.instance();
-
- k->set_shift(ke.shift);
- k->set_alt(ke.alt);
- k->set_control(ke.control);
- k->set_metakey(ke.meta);
-
- k->set_pressed(ke.uMsg == WM_KEYDOWN);
-
- if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
- // Special case for Numpad Enter key
- k->set_keycode(KEY_KP_ENTER);
- } else {
- k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam));
- }
-
- k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
-
- if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
- k->set_unicode(key_event_buffer[i + 1].wParam);
- }
- if (k->get_unicode() && gr_mem) {
- k->set_alt(false);
- k->set_control(false);
- }
-
- if (k->get_unicode() < 32)
- k->set_unicode(0);
-
- k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30))));
-
- input->accumulate_input_event(k);
-
- } break;
- }
- }
-
- key_event_pos = 0;
+ main_loop = nullptr;
}
-enum _MonitorDpiType {
- MDT_Effective_DPI = 0,
- MDT_Angular_DPI = 1,
- MDT_Raw_DPI = 2,
- MDT_Default = MDT_Effective_DPI
-};
-
-static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Default) {
-
- int dpiX = 96, dpiY = 96;
-
- static HMODULE Shcore = NULL;
- typedef HRESULT(WINAPI * GetDPIForMonitor_t)(HMONITOR hmonitor, _MonitorDpiType dpiType, UINT * dpiX, UINT * dpiY);
- static GetDPIForMonitor_t getDPIForMonitor = NULL;
-
- if (Shcore == NULL) {
- Shcore = LoadLibraryW(L"Shcore.dll");
- getDPIForMonitor = Shcore ? (GetDPIForMonitor_t)GetProcAddress(Shcore, "GetDpiForMonitor") : NULL;
-
- if ((Shcore == NULL) || (getDPIForMonitor == NULL)) {
- if (Shcore)
- FreeLibrary(Shcore);
- Shcore = (HMODULE)INVALID_HANDLE_VALUE;
- }
- }
-
- UINT x = 0, y = 0;
- HRESULT hr = E_FAIL;
- if (hmon && (Shcore != (HMODULE)INVALID_HANDLE_VALUE)) {
- hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y);
- if (SUCCEEDED(hr) && (x > 0) && (y > 0)) {
-
- dpiX = (int)x;
- dpiY = (int)y;
- }
- } else {
- static int overallX = 0, overallY = 0;
- if (overallX <= 0 || overallY <= 0) {
- HDC hdc = GetDC(NULL);
- if (hdc) {
- overallX = GetDeviceCaps(hdc, LOGPIXELSX);
- overallY = GetDeviceCaps(hdc, LOGPIXELSY);
- ReleaseDC(NULL, hdc);
- }
- }
- if (overallX > 0 && overallY > 0) {
- dpiX = overallX;
- dpiY = overallY;
- }
- }
-
- return (dpiX + dpiY) / 2;
-}
-
-typedef enum _SHC_PROCESS_DPI_AWARENESS {
- SHC_PROCESS_DPI_UNAWARE = 0,
- SHC_PROCESS_SYSTEM_DPI_AWARE = 1,
- SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2
-} SHC_PROCESS_DPI_AWARENESS;
-
-int OS_Windows::get_current_video_driver() const {
- return video_driver_index;
-}
-
-Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
-
- main_loop = NULL;
- outside = true;
- window_has_focus = true;
- WNDCLASSEXW wc;
-
- if (is_hidpi_allowed()) {
- HMODULE Shcore = LoadLibraryW(L"Shcore.dll");
-
- if (Shcore != NULL) {
- typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(SHC_PROCESS_DPI_AWARENESS);
-
- SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)GetProcAddress(Shcore, "SetProcessDpiAwareness");
-
- if (SetProcessDpiAwareness) {
- SetProcessDpiAwareness(SHC_PROCESS_SYSTEM_DPI_AWARE);
- }
- }
- }
-
- video_mode = p_desired;
- //printf("**************** desired %s, mode %s\n", p_desired.fullscreen?"true":"false", video_mode.fullscreen?"true":"false");
- RECT WindowRect;
-
- WindowRect.left = 0;
- WindowRect.right = video_mode.width;
- WindowRect.top = 0;
- WindowRect.bottom = video_mode.height;
-
- memset(&wc, 0, sizeof(WNDCLASSEXW));
- wc.cbSize = sizeof(WNDCLASSEXW);
- wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
- wc.lpfnWndProc = (WNDPROC)::WndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- //wc.hInstance = hInstance;
- wc.hInstance = godot_hinstance ? godot_hinstance : GetModuleHandle(NULL);
- wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
- wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = NULL;
- wc.lpszMenuName = NULL;
- wc.lpszClassName = L"Engine";
-
- if (!RegisterClassExW(&wc)) {
- MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
- return ERR_UNAVAILABLE;
- }
-
- use_raw_input = true;
-
- RAWINPUTDEVICE Rid[1];
-
- Rid[0].usUsagePage = 0x01;
- Rid[0].usUsage = 0x02;
- Rid[0].dwFlags = 0;
- Rid[0].hwndTarget = 0;
-
- if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
- //registration failed.
- use_raw_input = false;
- }
-
- pre_fs_valid = true;
- if (video_mode.fullscreen) {
-
- /* this returns DPI unaware size, commenting
- DEVMODE current;
- memset(&current, 0, sizeof(current));
- EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &current);
-
- WindowRect.right = current.dmPelsWidth;
- WindowRect.bottom = current.dmPelsHeight;
-
- */
-
- EnumSizeData data = { 0, 0, Size2() };
- EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcSize, (LPARAM)&data);
-
- WindowRect.right = data.size.width;
- WindowRect.bottom = data.size.height;
-
- /* DEVMODE dmScreenSettings;
- memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
- dmScreenSettings.dmSize=sizeof(dmScreenSettings);
- dmScreenSettings.dmPelsWidth = video_mode.width;
- dmScreenSettings.dmPelsHeight = video_mode.height;
- dmScreenSettings.dmBitsPerPel = current.dmBitsPerPel;
- dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
-
- LONG err = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
- if (err!=DISP_CHANGE_SUCCESSFUL) {
-
- video_mode.fullscreen=false;
- }*/
- pre_fs_valid = false;
- }
-
- DWORD dwExStyle;
- DWORD dwStyle;
-
- if (video_mode.fullscreen || video_mode.borderless_window) {
-
- dwExStyle = WS_EX_APPWINDOW;
- dwStyle = WS_POPUP;
-
- } else {
- dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
- dwStyle = WS_OVERLAPPEDWINDOW;
- if (!video_mode.resizable) {
- dwStyle &= ~WS_THICKFRAME;
- dwStyle &= ~WS_MAXIMIZEBOX;
- }
- }
-
- AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
-
- char *windowid;
-#ifdef MINGW_ENABLED
- windowid = getenv("GODOT_WINDOWID");
-#else
- size_t len;
- _dupenv_s(&windowid, &len, "GODOT_WINDOWID");
-#endif
-
- if (windowid) {
-
-// strtoull on mingw
-#ifdef MINGW_ENABLED
- hWnd = (HWND)strtoull(windowid, NULL, 0);
-#else
- hWnd = (HWND)_strtoui64(windowid, NULL, 0);
-#endif
- free(windowid);
- SetLastError(0);
- user_proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
- SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)(WNDPROC)::WndProc);
- DWORD le = GetLastError();
- if (user_proc == 0 && le != 0) {
-
- printf("Error setting WNDPROC: %li\n", le);
- };
- GetWindowLongPtr(hWnd, GWLP_WNDPROC);
-
- RECT rect;
- if (!GetClientRect(hWnd, &rect)) {
- MessageBoxW(NULL, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
- return ERR_UNAVAILABLE;
- };
- video_mode.width = rect.right;
- video_mode.height = rect.bottom;
- video_mode.fullscreen = false;
- } else {
-
- hWnd = CreateWindowExW(
- dwExStyle,
- L"Engine", L"",
- dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
- (GetSystemMetrics(SM_CXSCREEN) - WindowRect.right) / 2,
- (GetSystemMetrics(SM_CYSCREEN) - WindowRect.bottom) / 2,
- WindowRect.right - WindowRect.left,
- WindowRect.bottom - WindowRect.top,
- NULL, NULL, hInstance, NULL);
- if (!hWnd) {
- MessageBoxW(NULL, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
- return ERR_UNAVAILABLE;
- }
- };
-
- if (video_mode.always_on_top) {
- SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- }
-
- //!!!!!!!!!!!!!!!!!!!!!!!!!!
- //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
- video_driver_index = p_video_driver;
- print_verbose("Driver: " + String(get_video_driver_name(video_driver_index)) + " [" + itos(video_driver_index) + "]");
- //!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- // Init context and rendering device
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
-
- context_gles2 = memnew(ContextGL_Windows(hWnd, false));
-
- if (context_gles2->initialize() != OK) {
- memdelete(context_gles2);
- context_gles2 = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
-
- context_gles2->set_use_vsync(video_mode.use_vsync);
- set_vsync_via_compositor(video_mode.vsync_via_compositor);
-
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- } else {
- memdelete(context_gles2);
- context_gles2 = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
-
- context_vulkan = memnew(VulkanContextWindows);
- if (context_vulkan->initialize() != OK) {
- memdelete(context_vulkan);
- context_vulkan = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- if (context_vulkan->window_create(hWnd, hInstance, get_video_mode().width, get_video_mode().height) == -1) {
- memdelete(context_vulkan);
- context_vulkan = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
-
- //temporary
- rendering_device_vulkan = memnew(RenderingDeviceVulkan);
- rendering_device_vulkan->initialize(context_vulkan);
-
- RasterizerRD::make_current();
- }
-#endif
-
- visual_server = memnew(VisualServerRaster);
- if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
- }
-
- visual_server->init();
-
- input = memnew(InputDefault);
- joypad = memnew(JoypadWindows(input, &hWnd));
-
- AudioDriverManager::initialize(p_audio_driver);
-
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof(TRACKMOUSEEVENT);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hWnd;
- tme.dwHoverTime = HOVER_DEFAULT;
- TrackMouseEvent(&tme);
-
- RegisterTouchWindow(hWnd, 0);
-
- _ensure_user_data_dir();
-
- DragAcceptFiles(hWnd, true);
-
- move_timer_id = 1;
-
- if (!is_no_window_mode_enabled()) {
- ShowWindow(hWnd, SW_SHOW); // Show The Window
- SetForegroundWindow(hWnd); // Slightly Higher Priority
- SetFocus(hWnd); // Sets Keyboard Focus To
- }
-
- if (p_desired.layered) {
- set_window_per_pixel_transparency_enabled(true);
- }
-
- // IME
- im_himc = ImmGetContext(hWnd);
- ImmReleaseContext(hWnd, im_himc);
-
- im_position = Vector2();
-
- set_ime_active(false);
-
- if (!OS::get_singleton()->is_in_low_processor_usage_mode()) {
- //SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
- SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
- DWORD index = 0;
- HANDLE handle = AvSetMmThreadCharacteristics("Games", &index);
- if (handle)
- AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL);
-
- // This is needed to make sure that background work does not starve the main thread.
- // This is only setting priority of this thread, not the whole process.
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
- }
-
- update_real_mouse_position();
-
- return OK;
-}
-
-void OS_Windows::set_clipboard(const String &p_text) {
-
- // Convert LF line endings to CRLF in clipboard content
- // Otherwise, line endings won't be visible when pasted in other software
- String text = p_text.replace("\n", "\r\n");
-
- if (!OpenClipboard(hWnd)) {
- ERR_FAIL_MSG("Unable to open clipboard.");
- }
- EmptyClipboard();
-
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType));
- ERR_FAIL_COND_MSG(mem == NULL, "Unable to allocate memory for clipboard contents.");
-
- LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
- memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType));
- GlobalUnlock(mem);
-
- SetClipboardData(CF_UNICODETEXT, mem);
-
- // set the CF_TEXT version (not needed?)
- CharString utf8 = text.utf8();
- mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
- ERR_FAIL_COND_MSG(mem == NULL, "Unable to allocate memory for clipboard contents.");
-
- LPTSTR ptr = (LPTSTR)GlobalLock(mem);
- memcpy(ptr, utf8.get_data(), utf8.length());
- ptr[utf8.length()] = 0;
- GlobalUnlock(mem);
-
- SetClipboardData(CF_TEXT, mem);
-
- CloseClipboard();
-};
-
-String OS_Windows::get_clipboard() const {
-
- String ret;
- if (!OpenClipboard(hWnd)) {
- ERR_FAIL_V_MSG("", "Unable to open clipboard.");
- };
-
- if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
-
- HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
- if (mem != NULL) {
-
- LPWSTR ptr = (LPWSTR)GlobalLock(mem);
- if (ptr != NULL) {
-
- ret = String((CharType *)ptr);
- GlobalUnlock(mem);
- };
- };
-
- } else if (IsClipboardFormatAvailable(CF_TEXT)) {
-
- HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
- if (mem != NULL) {
-
- LPTSTR ptr = (LPTSTR)GlobalLock(mem);
- if (ptr != NULL) {
-
- ret.parse_utf8((const char *)ptr);
- GlobalUnlock(mem);
- };
- };
- };
-
- CloseClipboard();
-
- return ret;
-};
-
void OS_Windows::delete_main_loop() {
if (main_loop)
memdelete(main_loop);
- main_loop = NULL;
+ main_loop = nullptr;
}
void OS_Windows::set_main_loop(MainLoop *p_main_loop) {
- input->set_main_loop(p_main_loop);
main_loop = p_main_loop;
}
@@ -1642,39 +237,7 @@ void OS_Windows::finalize() {
if (main_loop)
memdelete(main_loop);
- main_loop = NULL;
-
- memdelete(joypad);
- memdelete(input);
- touch_state.clear();
-
- cursors_cache.clear();
- visual_server->finish();
- memdelete(visual_server);
-
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
-
- if (context_gles2)
- memdelete(context_gles2);
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
-
- if (rendering_device_vulkan) {
- rendering_device_vulkan->finalize();
- memdelete(rendering_device_vulkan);
- }
-
- if (context_vulkan)
- memdelete(context_vulkan);
- }
-#endif
-
- if (user_proc) {
- SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
- };
+ main_loop = nullptr;
}
void OS_Windows::finalize_core() {
@@ -1685,576 +248,6 @@ void OS_Windows::finalize_core() {
NetSocketPosix::cleanup();
}
-void OS_Windows::alert(const String &p_alert, const String &p_title) {
-
- if (!is_no_window_mode_enabled())
- MessageBoxW(NULL, p_alert.c_str(), p_title.c_str(), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
- else
- print_line("ALERT: " + p_alert);
-}
-
-void OS_Windows::set_mouse_mode(MouseMode p_mode) {
-
- if (mouse_mode == p_mode)
- return;
-
- _set_mouse_mode_impl(p_mode);
-
- mouse_mode = p_mode;
-}
-
-void OS_Windows::_set_mouse_mode_impl(MouseMode p_mode) {
-
- if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED) {
- RECT clipRect;
- GetClientRect(hWnd, &clipRect);
- ClientToScreen(hWnd, (POINT *)&clipRect.left);
- ClientToScreen(hWnd, (POINT *)&clipRect.right);
- ClipCursor(&clipRect);
- if (p_mode == MOUSE_MODE_CAPTURED) {
- center = Point2i(video_mode.width / 2, video_mode.height / 2);
- POINT pos = { (int)center.x, (int)center.y };
- ClientToScreen(hWnd, &pos);
- SetCursorPos(pos.x, pos.y);
- SetCapture(hWnd);
- }
- } else {
- ReleaseCapture();
- ClipCursor(NULL);
- }
-
- if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_HIDDEN) {
- hCursor = SetCursor(NULL);
- } else {
- CursorShape c = cursor_shape;
- cursor_shape = CURSOR_MAX;
- set_cursor_shape(c);
- }
-}
-OS_Windows::MouseMode OS_Windows::get_mouse_mode() const {
-
- return mouse_mode;
-}
-
-void OS_Windows::warp_mouse_position(const Point2 &p_to) {
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
-
- old_x = p_to.x;
- old_y = p_to.y;
- } else {
-
- POINT p;
- p.x = p_to.x;
- p.y = p_to.y;
- ClientToScreen(hWnd, &p);
-
- SetCursorPos(p.x, p.y);
- }
-}
-
-Point2 OS_Windows::get_mouse_position() const {
-
- return Point2(old_x, old_y);
-}
-
-void OS_Windows::update_real_mouse_position() {
-
- POINT mouse_pos;
- if (GetCursorPos(&mouse_pos) && ScreenToClient(hWnd, &mouse_pos)) {
- if (mouse_pos.x > 0 && mouse_pos.y > 0 && mouse_pos.x <= video_mode.width && mouse_pos.y <= video_mode.height) {
- old_x = mouse_pos.x;
- old_y = mouse_pos.y;
- old_invalid = false;
- input->set_mouse_position(Point2i(mouse_pos.x, mouse_pos.y));
- }
- }
-}
-
-int OS_Windows::get_mouse_button_state() const {
-
- return last_button_state;
-}
-
-void OS_Windows::set_window_title(const String &p_title) {
-
- SetWindowTextW(hWnd, p_title.c_str());
-}
-
-void OS_Windows::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
-}
-
-OS::VideoMode OS_Windows::get_video_mode(int p_screen) const {
-
- return video_mode;
-}
-void OS_Windows::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
-}
-
-static BOOL CALLBACK _MonitorEnumProcCount(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
-
- int *data = (int *)dwData;
- (*data)++;
- return TRUE;
-}
-
-int OS_Windows::get_screen_count() const {
-
- int data = 0;
- EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcCount, (LPARAM)&data);
- return data;
-}
-
-typedef struct {
- int count;
- int screen;
- HMONITOR monitor;
-} EnumScreenData;
-
-static BOOL CALLBACK _MonitorEnumProcScreen(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
-
- EnumScreenData *data = (EnumScreenData *)dwData;
- if (data->monitor == hMonitor) {
- data->screen = data->count;
- }
-
- data->count++;
- return TRUE;
-}
-
-int OS_Windows::get_current_screen() const {
-
- EnumScreenData data = { 0, 0, MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST) };
- EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcScreen, (LPARAM)&data);
- return data.screen;
-}
-
-void OS_Windows::set_current_screen(int p_screen) {
-
- Vector2 ofs = get_window_position() - get_screen_position(get_current_screen());
- set_window_position(ofs + get_screen_position(p_screen));
-}
-
-static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
-
- EnumPosData *data = (EnumPosData *)dwData;
- if (data->count == data->screen) {
- data->pos.x = lprcMonitor->left;
- data->pos.y = lprcMonitor->top;
- }
-
- data->count++;
- return TRUE;
-}
-
-Point2 OS_Windows::get_screen_position(int p_screen) const {
-
- EnumPosData data = { 0, p_screen == -1 ? get_current_screen() : p_screen, Point2() };
- EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcPos, (LPARAM)&data);
- return data.pos;
-}
-
-Size2 OS_Windows::get_screen_size(int p_screen) const {
-
- EnumSizeData data = { 0, p_screen == -1 ? get_current_screen() : p_screen, Size2() };
- EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcSize, (LPARAM)&data);
- return data.size;
-}
-
-typedef struct {
- int count;
- int screen;
- int dpi;
-} EnumDpiData;
-
-static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
-
- EnumDpiData *data = (EnumDpiData *)dwData;
- if (data->count == data->screen) {
- data->dpi = QueryDpiForMonitor(hMonitor);
- }
-
- data->count++;
- return TRUE;
-}
-
-int OS_Windows::get_screen_dpi(int p_screen) const {
-
- EnumDpiData data = { 0, p_screen == -1 ? get_current_screen() : p_screen, 72 };
- EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcDpi, (LPARAM)&data);
- return data.dpi;
-}
-
-Point2 OS_Windows::get_window_position() const {
-
- if (minimized) {
- return last_pos;
- }
-
- RECT r;
- GetWindowRect(hWnd, &r);
- return Point2(r.left, r.top);
-}
-
-void OS_Windows::set_window_position(const Point2 &p_position) {
-
- if (video_mode.fullscreen) return;
- RECT r;
- GetWindowRect(hWnd, &r);
- MoveWindow(hWnd, p_position.x, p_position.y, r.right - r.left, r.bottom - r.top, TRUE);
-
- // Don't let the mouse leave the window when moved
- if (mouse_mode == MOUSE_MODE_CONFINED) {
- RECT rect;
- GetClientRect(hWnd, &rect);
- ClientToScreen(hWnd, (POINT *)&rect.left);
- ClientToScreen(hWnd, (POINT *)&rect.right);
- ClipCursor(&rect);
- }
-
- last_pos = p_position;
- update_real_mouse_position();
-}
-
-Size2 OS_Windows::get_window_size() const {
-
- if (minimized) {
- return Size2(video_mode.width, video_mode.height);
- }
-
- RECT r;
- if (GetClientRect(hWnd, &r)) { // Only area inside of window border
- return Size2(r.right - r.left, r.bottom - r.top);
- }
- return Size2();
-}
-
-Size2 OS_Windows::get_max_window_size() const {
- return max_size;
-}
-
-Size2 OS_Windows::get_min_window_size() const {
- return min_size;
-}
-
-void OS_Windows::set_min_window_size(const Size2 p_size) {
-
- if ((p_size != Size2()) && (max_size != Size2()) && ((p_size.x > max_size.x) || (p_size.y > max_size.y))) {
- ERR_PRINT("Minimum window size can't be larger than maximum window size!");
- return;
- }
- min_size = p_size;
-}
-
-void OS_Windows::set_max_window_size(const Size2 p_size) {
-
- if ((p_size != Size2()) && ((p_size.x < min_size.x) || (p_size.y < min_size.y))) {
- ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
- return;
- }
- max_size = p_size;
-}
-
-Size2 OS_Windows::get_real_window_size() const {
-
- RECT r;
- if (GetWindowRect(hWnd, &r)) { // Includes area of the window border
- return Size2(r.right - r.left, r.bottom - r.top);
- }
- return Size2();
-}
-
-void OS_Windows::set_window_size(const Size2 p_size) {
-
- int w = p_size.width;
- int h = p_size.height;
-
- video_mode.width = w;
- video_mode.height = h;
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
- context_vulkan->window_resize(0, video_mode.width, video_mode.height);
- }
-#endif
-
- if (video_mode.fullscreen) {
- return;
- }
-
- RECT rect;
- GetWindowRect(hWnd, &rect);
-
- if (!video_mode.borderless_window) {
- RECT crect;
- GetClientRect(hWnd, &crect);
-
- w += (rect.right - rect.left) - (crect.right - crect.left);
- h += (rect.bottom - rect.top) - (crect.bottom - crect.top);
- }
-
- MoveWindow(hWnd, rect.left, rect.top, w, h, TRUE);
-
- // Don't let the mouse leave the window when resizing to a smaller resolution
- if (mouse_mode == MOUSE_MODE_CONFINED) {
- RECT crect;
- GetClientRect(hWnd, &crect);
- ClientToScreen(hWnd, (POINT *)&crect.left);
- ClientToScreen(hWnd, (POINT *)&crect.right);
- ClipCursor(&crect);
- }
-}
-void OS_Windows::set_window_fullscreen(bool p_enabled) {
-
- if (video_mode.fullscreen == p_enabled)
- return;
-
- if (layered_window)
- set_window_per_pixel_transparency_enabled(false);
-
- if (p_enabled) {
-
- was_maximized = maximized;
-
- if (pre_fs_valid) {
- GetWindowRect(hWnd, &pre_fs_rect);
- }
-
- int cs = get_current_screen();
- Point2 pos = get_screen_position(cs);
- Size2 size = get_screen_size(cs);
-
- video_mode.fullscreen = true;
-
- _update_window_style(false);
-
- MoveWindow(hWnd, pos.x, pos.y, size.width, size.height, TRUE);
-
- } else {
-
- RECT rect;
-
- video_mode.fullscreen = false;
-
- if (pre_fs_valid) {
- rect = pre_fs_rect;
- } else {
- rect.left = 0;
- rect.right = video_mode.width;
- rect.top = 0;
- rect.bottom = video_mode.height;
- }
-
- _update_window_style(false, was_maximized);
-
- MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
-
- pre_fs_valid = true;
- }
-}
-bool OS_Windows::is_window_fullscreen() const {
-
- return video_mode.fullscreen;
-}
-void OS_Windows::set_window_resizable(bool p_enabled) {
-
- if (video_mode.resizable == p_enabled)
- return;
-
- video_mode.resizable = p_enabled;
-
- _update_window_style();
-}
-bool OS_Windows::is_window_resizable() const {
-
- return video_mode.resizable;
-}
-void OS_Windows::set_window_minimized(bool p_enabled) {
-
- if (p_enabled) {
- maximized = false;
- minimized = true;
- ShowWindow(hWnd, SW_MINIMIZE);
- } else {
- ShowWindow(hWnd, SW_RESTORE);
- maximized = false;
- minimized = false;
- }
-}
-bool OS_Windows::is_window_minimized() const {
-
- return minimized;
-}
-void OS_Windows::set_window_maximized(bool p_enabled) {
-
- if (p_enabled) {
- maximized = true;
- minimized = false;
- ShowWindow(hWnd, SW_MAXIMIZE);
- } else {
- ShowWindow(hWnd, SW_RESTORE);
- maximized = false;
- minimized = false;
- }
-}
-bool OS_Windows::is_window_maximized() const {
-
- return maximized;
-}
-
-void OS_Windows::set_window_always_on_top(bool p_enabled) {
- if (video_mode.always_on_top == p_enabled)
- return;
-
- video_mode.always_on_top = p_enabled;
-
- _update_window_style();
-}
-
-bool OS_Windows::is_window_always_on_top() const {
- return video_mode.always_on_top;
-}
-
-bool OS_Windows::is_window_focused() const {
-
- return window_focused;
-}
-
-void OS_Windows::set_console_visible(bool p_enabled) {
- if (console_visible == p_enabled)
- return;
- ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
- console_visible = p_enabled;
-}
-
-bool OS_Windows::is_console_visible() const {
- return console_visible;
-}
-
-bool OS_Windows::get_window_per_pixel_transparency_enabled() const {
-
- if (!is_layered_allowed()) return false;
- return layered_window;
-}
-
-void OS_Windows::set_window_per_pixel_transparency_enabled(bool p_enabled) {
-
- if (!is_layered_allowed()) return;
- if (layered_window != p_enabled) {
- if (p_enabled) {
- set_borderless_window(true);
- //enable per-pixel alpha
- hDC_dib = CreateCompatibleDC(GetDC(hWnd));
-
- SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
-
- RECT r;
- GetWindowRect(hWnd, &r);
- dib_size = Size2(r.right - r.left, r.bottom - r.top);
-
- BITMAPINFO bmi;
- ZeroMemory(&bmi, sizeof(BITMAPINFO));
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmi.bmiHeader.biWidth = dib_size.x;
- bmi.bmiHeader.biHeight = dib_size.y;
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
- bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
- hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
- SelectObject(hDC_dib, hBitmap);
-
- ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
-
- layered_window = true;
- } else {
- //disable per-pixel alpha
- layered_window = false;
-
- SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
-
- //cleanup
- DeleteObject(hBitmap);
- DeleteDC(hDC_dib);
- }
- }
-}
-
-uint8_t *OS_Windows::get_layered_buffer_data() {
-
- return (is_layered_allowed() && layered_window) ? dib_data : NULL;
-}
-
-Size2 OS_Windows::get_layered_buffer_size() {
-
- return (is_layered_allowed() && layered_window) ? dib_size : Size2();
-}
-
-void OS_Windows::swap_layered_buffer() {
-
- if (is_layered_allowed() && layered_window) {
-
- //premultiply alpha
- for (int y = 0; y < dib_size.y; y++) {
- for (int x = 0; x < dib_size.x; x++) {
- float alpha = (float)dib_data[y * (int)dib_size.x * 4 + x * 4 + 3] / (float)0xFF;
- dib_data[y * (int)dib_size.x * 4 + x * 4 + 0] *= alpha;
- dib_data[y * (int)dib_size.x * 4 + x * 4 + 1] *= alpha;
- dib_data[y * (int)dib_size.x * 4 + x * 4 + 2] *= alpha;
- }
- }
- //swap layered window buffer
- POINT ptSrc = { 0, 0 };
- SIZE sizeWnd = { (long)dib_size.x, (long)dib_size.y };
- BLENDFUNCTION bf;
- bf.BlendOp = AC_SRC_OVER;
- bf.BlendFlags = 0;
- bf.AlphaFormat = AC_SRC_ALPHA;
- bf.SourceConstantAlpha = 0xFF;
- UpdateLayeredWindow(hWnd, NULL, NULL, &sizeWnd, hDC_dib, &ptSrc, 0, &bf, ULW_ALPHA);
- }
-}
-
-void OS_Windows::set_borderless_window(bool p_borderless) {
- if (video_mode.borderless_window == p_borderless)
- return;
-
- if (!p_borderless && layered_window)
- set_window_per_pixel_transparency_enabled(false);
-
- video_mode.borderless_window = p_borderless;
-
- preserve_window_size = true;
- _update_window_style();
-}
-
-bool OS_Windows::get_borderless_window() {
- return video_mode.borderless_window;
-}
-
-void OS_Windows::_update_window_style(bool p_repaint, bool p_maximized) {
- if (video_mode.fullscreen || video_mode.borderless_window) {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
- } else {
- if (video_mode.resizable) {
- if (p_maximized) {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE);
- } else {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
- }
- } else {
- SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_MINIMIZEBOX | WS_POPUPWINDOW | WS_VISIBLE);
- }
- }
-
- SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
-
- if (p_repaint) {
- RECT rect;
- GetWindowRect(hWnd, &rect);
- MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
- }
-}
-
Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
String path = p_path;
@@ -2270,14 +263,14 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
PAddDllDirectory add_dll_directory = (PAddDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "AddDllDirectory");
PRemoveDllDirectory remove_dll_directory = (PRemoveDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "RemoveDllDirectory");
- bool has_dll_directory_api = ((add_dll_directory != NULL) && (remove_dll_directory != NULL));
- DLL_DIRECTORY_COOKIE cookie = NULL;
+ bool has_dll_directory_api = ((add_dll_directory != nullptr) && (remove_dll_directory != nullptr));
+ DLL_DIRECTORY_COOKIE cookie = nullptr;
if (p_also_set_library_path && has_dll_directory_api) {
cookie = add_dll_directory(path.get_base_dir().c_str());
}
- p_library_handle = (void *)LoadLibraryExW(path.c_str(), NULL, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
+ p_library_handle = (void *)LoadLibraryExW(path.c_str(), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + ".");
if (cookie) {
@@ -2306,17 +299,6 @@ Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, cons
return OK;
}
-void OS_Windows::request_attention() {
-
- FLASHWINFO info;
- info.cbSize = sizeof(FLASHWINFO);
- info.hwnd = hWnd;
- info.dwFlags = FLASHW_TRAY;
- info.dwTimeout = 0;
- info.uCount = 2;
- FlashWindowEx(&info);
-}
-
String OS_Windows::get_name() const {
return "Windows";
@@ -2448,253 +430,6 @@ uint64_t OS_Windows::get_ticks_usec() const {
return time;
}
-void OS_Windows::process_events() {
-
- MSG msg;
-
- if (!drop_events) {
- joypad->process_joypads();
- }
-
- while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
-
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
-
- if (!drop_events) {
- process_key_events();
- input->flush_accumulated_events();
- }
-}
-
-void OS_Windows::set_cursor_shape(CursorShape p_shape) {
-
- ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
-
- if (cursor_shape == p_shape)
- return;
-
- if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
- cursor_shape = p_shape;
- return;
- }
-
- static const LPCTSTR win_cursors[CURSOR_MAX] = {
- IDC_ARROW,
- IDC_IBEAM,
- IDC_HAND, //finger
- IDC_CROSS,
- IDC_WAIT,
- IDC_APPSTARTING,
- IDC_ARROW,
- IDC_ARROW,
- IDC_NO,
- IDC_SIZENS,
- IDC_SIZEWE,
- IDC_SIZENESW,
- IDC_SIZENWSE,
- IDC_SIZEALL,
- IDC_SIZENS,
- IDC_SIZEWE,
- IDC_HELP
- };
-
- if (cursors[p_shape] != NULL) {
- SetCursor(cursors[p_shape]);
- } else {
- SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
- }
-
- cursor_shape = p_shape;
-}
-
-OS::CursorShape OS_Windows::get_cursor_shape() const {
-
- return cursor_shape;
-}
-
-void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-
- if (p_cursor.is_valid()) {
-
- Map<CursorShape, Vector<Variant> >::Element *cursor_c = cursors_cache.find(p_shape);
-
- if (cursor_c) {
- if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
- set_cursor_shape(p_shape);
- return;
- }
-
- cursors_cache.erase(p_shape);
- }
-
- Ref<Texture2D> texture = p_cursor;
- Ref<AtlasTexture> atlas_texture = p_cursor;
- Ref<Image> image;
- Size2 texture_size;
- Rect2 atlas_rect;
-
- if (texture.is_valid()) {
- image = texture->get_data();
- }
-
- if (!image.is_valid() && atlas_texture.is_valid()) {
- texture = atlas_texture->get_atlas();
-
- atlas_rect.size.width = texture->get_width();
- atlas_rect.size.height = texture->get_height();
- atlas_rect.position.x = atlas_texture->get_region().position.x;
- atlas_rect.position.y = atlas_texture->get_region().position.y;
-
- texture_size.width = atlas_texture->get_region().size.x;
- texture_size.height = atlas_texture->get_region().size.y;
- } else if (image.is_valid()) {
- texture_size.width = texture->get_width();
- texture_size.height = texture->get_height();
- }
-
- ERR_FAIL_COND(!texture.is_valid());
- ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
- 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();
-
- ERR_FAIL_COND(!image.is_valid());
-
- UINT image_size = texture_size.width * texture_size.height;
-
- // Create the BITMAP with alpha channel
- COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
-
- for (UINT index = 0; index < image_size; index++) {
- int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
- int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
-
- if (atlas_texture.is_valid()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
-
- *(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
- }
-
- // Using 4 channels, so 4 * 8 bits
- HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
- COLORREF clrTransparent = -1;
-
- // Create the AND and XOR masks for the bitmap
- HBITMAP hAndMask = NULL;
- HBITMAP hXorMask = NULL;
-
- GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
-
- if (NULL == hAndMask || NULL == hXorMask) {
- memfree(buffer);
- DeleteObject(bitmap);
- return;
- }
-
- // Finally, create the icon
- ICONINFO iconinfo;
- iconinfo.fIcon = FALSE;
- iconinfo.xHotspot = p_hotspot.x;
- iconinfo.yHotspot = p_hotspot.y;
- iconinfo.hbmMask = hAndMask;
- iconinfo.hbmColor = hXorMask;
-
- if (cursors[p_shape])
- DestroyIcon(cursors[p_shape]);
-
- cursors[p_shape] = CreateIconIndirect(&iconinfo);
-
- Vector<Variant> params;
- params.push_back(p_cursor);
- params.push_back(p_hotspot);
- cursors_cache.insert(p_shape, params);
-
- if (p_shape == cursor_shape) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
- SetCursor(cursors[p_shape]);
- }
- }
-
- if (hAndMask != NULL) {
- DeleteObject(hAndMask);
- }
-
- if (hXorMask != NULL) {
- DeleteObject(hXorMask);
- }
-
- memfree(buffer);
- DeleteObject(bitmap);
- } else {
- // Reset to default system cursor
- if (cursors[p_shape]) {
- DestroyIcon(cursors[p_shape]);
- cursors[p_shape] = NULL;
- }
-
- CursorShape c = cursor_shape;
- cursor_shape = CURSOR_MAX;
- set_cursor_shape(c);
-
- cursors_cache.erase(p_shape);
- }
-}
-
-void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
-
- // Get the system display DC
- HDC hDC = GetDC(NULL);
-
- // Create helper DC
- HDC hMainDC = CreateCompatibleDC(hDC);
- HDC hAndMaskDC = CreateCompatibleDC(hDC);
- HDC hXorMaskDC = CreateCompatibleDC(hDC);
-
- // Get the dimensions of the source bitmap
- BITMAP bm;
- GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
-
- // Create the mask bitmaps
- hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
- hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
-
- // Release the system display DC
- ReleaseDC(NULL, hDC);
-
- // Select the bitmaps to helper DC
- HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
- 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
- // 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
- // with 'clrTransparent' will be black and rest the pixels same as corresponding
- // pixels of the source bitmap
- SetBkColor(hXorMaskDC, RGB(0, 0, 0));
- SetTextColor(hXorMaskDC, RGB(255, 255, 255));
- BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
- BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
-
- // Deselect bitmaps from the helper DC
- SelectObject(hMainDC, hOldMainBitmap);
- SelectObject(hAndMaskDC, hOldAndMaskBitmap);
- SelectObject(hXorMaskDC, hOldXorMaskBitmap);
-
- // Delete the helper DC
- DeleteDC(hXorMaskDC);
- DeleteDC(hAndMaskDC);
- DeleteDC(hMainDC);
-}
-
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
if (p_blocking && r_pipe) {
@@ -2755,7 +490,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
modstr.resize(cmdline.size());
for (int i = 0; i < cmdline.size(); i++)
modstr.write[i] = cmdline[i];
- int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, NULL, NULL, si_w, &pi.pi);
+ int ret = CreateProcessW(nullptr, modstr.ptrw(), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
if (p_blocking) {
@@ -2807,165 +542,20 @@ Error OS_Windows::set_cwd(const String &p_cwd) {
String OS_Windows::get_executable_path() const {
wchar_t bufname[4096];
- GetModuleFileNameW(NULL, bufname, 4096);
+ GetModuleFileNameW(nullptr, bufname, 4096);
String s = bufname;
return s;
}
-void OS_Windows::set_native_icon(const String &p_filename) {
-
- FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
- ERR_FAIL_COND_MSG(!f, "Cannot open file with icon '" + p_filename + "'.");
-
- ICONDIR *icon_dir = (ICONDIR *)memalloc(sizeof(ICONDIR));
- int pos = 0;
-
- icon_dir->idReserved = f->get_32();
- pos += sizeof(WORD);
- f->seek(pos);
-
- icon_dir->idType = f->get_32();
- pos += sizeof(WORD);
- f->seek(pos);
-
- ERR_FAIL_COND_MSG(icon_dir->idType != 1, "Invalid icon file format!");
-
- icon_dir->idCount = f->get_32();
- pos += sizeof(WORD);
- f->seek(pos);
-
- icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY));
- f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
-
- int small_icon_index = -1; // Select 16x16 with largest color count
- int small_icon_cc = 0;
- int big_icon_index = -1; // Select largest
- int big_icon_width = 16;
- int big_icon_cc = 0;
-
- for (int i = 0; i < icon_dir->idCount; i++) {
- int colors = (icon_dir->idEntries[i].bColorCount == 0) ? 32768 : icon_dir->idEntries[i].bColorCount;
- int width = (icon_dir->idEntries[i].bWidth == 0) ? 256 : icon_dir->idEntries[i].bWidth;
- if (width == 16) {
- if (colors >= small_icon_cc) {
- small_icon_index = i;
- small_icon_cc = colors;
- }
- }
- if (width >= big_icon_width) {
- if (colors >= big_icon_cc) {
- big_icon_index = i;
- big_icon_width = width;
- big_icon_cc = colors;
- }
- }
- }
-
- ERR_FAIL_COND_MSG(big_icon_index == -1, "No valid icons found!");
-
- if (small_icon_index == -1) {
- WARN_PRINT("No small icon found, reusing " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon!");
- small_icon_index = big_icon_index;
- small_icon_cc = big_icon_cc;
- }
-
- // Read the big icon
- DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes;
- Vector<uint8_t> data_big;
- data_big.resize(bytecount_big);
- pos = icon_dir->idEntries[big_icon_index].dwImageOffset;
- f->seek(pos);
- f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big);
- HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000);
- ERR_FAIL_COND_MSG(!icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
-
- // Read the small icon
- DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes;
- Vector<uint8_t> data_small;
- data_small.resize(bytecount_small);
- pos = icon_dir->idEntries[small_icon_index].dwImageOffset;
- f->seek(pos);
- f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small);
- HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000);
- ERR_FAIL_COND_MSG(!icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
-
- // Online tradition says to be sure last error is cleared and set the small icon first
- int err = 0;
- SetLastError(err);
-
- SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small);
- err = GetLastError();
- ERR_FAIL_COND_MSG(err, "Error setting ICON_SMALL: " + format_error_message(err) + ".");
-
- SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big);
- err = GetLastError();
- ERR_FAIL_COND_MSG(err, "Error setting ICON_BIG: " + format_error_message(err) + ".");
-
- memdelete(f);
- memdelete(icon_dir);
-}
-
-void OS_Windows::set_icon(const Ref<Image> &p_icon) {
-
- ERR_FAIL_COND(!p_icon.is_valid());
- Ref<Image> icon = p_icon->duplicate();
- if (icon->get_format() != Image::FORMAT_RGBA8)
- icon->convert(Image::FORMAT_RGBA8);
- int w = icon->get_width();
- int h = icon->get_height();
-
- /* Create temporary bitmap buffer */
- int icon_len = 40 + h * w * 4;
- Vector<BYTE> v;
- v.resize(icon_len);
- BYTE *icon_bmp = v.ptrw();
-
- encode_uint32(40, &icon_bmp[0]);
- encode_uint32(w, &icon_bmp[4]);
- encode_uint32(h * 2, &icon_bmp[8]);
- encode_uint16(1, &icon_bmp[12]);
- encode_uint16(32, &icon_bmp[14]);
- encode_uint32(BI_RGB, &icon_bmp[16]);
- encode_uint32(w * h * 4, &icon_bmp[20]);
- encode_uint32(0, &icon_bmp[24]);
- encode_uint32(0, &icon_bmp[28]);
- encode_uint32(0, &icon_bmp[32]);
- encode_uint32(0, &icon_bmp[36]);
-
- uint8_t *wr = &icon_bmp[40];
- const uint8_t *r = icon->get_data().ptr();
-
- for (int i = 0; i < h; i++) {
-
- for (int j = 0; j < w; j++) {
-
- const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
- uint8_t *wpx = &wr[(i * w + j) * 4];
- wpx[0] = rpx[2];
- wpx[1] = rpx[1];
- wpx[2] = rpx[0];
- wpx[3] = rpx[3];
- }
- }
-
- HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
-
- /* Set the icon for the window */
- SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
-
- /* Set the icon in the task manager (should we do this?) */
- SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
-}
-
bool OS_Windows::has_environment(const String &p_var) const {
#ifdef MINGW_ENABLED
- return _wgetenv(p_var.c_str()) != NULL;
+ return _wgetenv(p_var.c_str()) != nullptr;
#else
wchar_t *env;
size_t len;
_wdupenv_s(&env, &len, p_var.c_str());
- const bool has_env = env != NULL;
+ const bool has_env = env != nullptr;
free(env);
return has_env;
#endif
@@ -2996,19 +586,9 @@ String OS_Windows::get_stdin_string(bool p_block) {
return String();
}
-void OS_Windows::enable_for_stealing_focus(ProcessID pid) {
-
- AllowSetForegroundWindow(pid);
-}
-
-void OS_Windows::move_window_to_foreground() {
-
- SetForegroundWindow(hWnd);
-}
-
Error OS_Windows::shell_open(String p_uri) {
- ShellExecuteW(NULL, NULL, p_uri.c_str(), NULL, NULL, SW_SHOWNORMAL);
+ ShellExecuteW(nullptr, nullptr, p_uri.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
return OK;
}
@@ -3068,101 +648,6 @@ int OS_Windows::get_processor_count() const {
return sysinfo.dwNumberOfProcessors;
}
-OS::LatinKeyboardVariant OS_Windows::get_latin_keyboard_variant() const {
-
- unsigned long azerty[] = {
- 0x00020401, // Arabic (102) AZERTY
- 0x0001080c, // Belgian (Comma)
- 0x0000080c, // Belgian French
- 0x0000040c, // French
- 0 // <--- STOP MARK
- };
- unsigned long qwertz[] = {
- 0x0000041a, // Croation
- 0x00000405, // Czech
- 0x00000407, // German
- 0x00010407, // German (IBM)
- 0x0000040e, // Hungarian
- 0x0000046e, // Luxembourgish
- 0x00010415, // Polish (214)
- 0x00000418, // Romanian (Legacy)
- 0x0000081a, // Serbian (Latin)
- 0x0000041b, // Slovak
- 0x00000424, // Slovenian
- 0x0001042e, // Sorbian Extended
- 0x0002042e, // Sorbian Standard
- 0x0000042e, // Sorbian Standard (Legacy)
- 0x0000100c, // Swiss French
- 0x00000807, // Swiss German
- 0 // <--- STOP MARK
- };
- unsigned long dvorak[] = {
- 0x00010409, // US-Dvorak
- 0x00030409, // US-Dvorak for left hand
- 0x00040409, // US-Dvorak for right hand
- 0 // <--- STOP MARK
- };
-
- char name[KL_NAMELENGTH + 1];
- name[0] = 0;
- GetKeyboardLayoutNameA(name);
-
- unsigned long hex = strtoul(name, NULL, 16);
-
- int i = 0;
- while (azerty[i] != 0) {
- if (azerty[i] == hex) return LATIN_KEYBOARD_AZERTY;
- i++;
- }
-
- i = 0;
- while (qwertz[i] != 0) {
- if (qwertz[i] == hex) return LATIN_KEYBOARD_QWERTZ;
- i++;
- }
-
- i = 0;
- while (dvorak[i] != 0) {
- if (dvorak[i] == hex) return LATIN_KEYBOARD_DVORAK;
- i++;
- }
-
- return LATIN_KEYBOARD_QWERTY;
-}
-
-void OS_Windows::release_rendering_thread() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->release_current();
- }
-#endif
-}
-
-void OS_Windows::make_rendering_thread() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->make_current();
- }
-#endif
-}
-
-void OS_Windows::swap_buffers() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->swap_buffers();
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
- context_vulkan->swap_buffers();
- }
-#endif
-}
-
-void OS_Windows::force_process_input() {
- process_events(); // get rid of pending events
-}
-
void OS_Windows::run() {
if (!main_loop)
@@ -3172,7 +657,7 @@ void OS_Windows::run() {
while (!force_quit) {
- process_events(); // get rid of pending events
+ DisplayServer::get_singleton()->process_events(); // get rid of pending events
if (Main::iteration())
break;
};
@@ -3254,7 +739,7 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const {
}
PWSTR szPath;
- HRESULT res = SHGetKnownFolderPath(id, 0, NULL, &szPath);
+ HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath);
ERR_FAIL_COND_V(res != S_OK, String());
String path = String(szPath);
CoTaskMemFree(szPath);
@@ -3287,50 +772,6 @@ String OS_Windows::get_unique_id() const {
return String(HwProfInfo.szHwProfileGuid);
}
-void OS_Windows::set_ime_active(const bool p_active) {
-
- if (p_active) {
- ImmAssociateContext(hWnd, im_himc);
-
- set_ime_position(im_position);
- } else {
- ImmAssociateContext(hWnd, (HIMC)0);
- }
-}
-
-void OS_Windows::set_ime_position(const Point2 &p_pos) {
-
- im_position = p_pos;
-
- HIMC himc = ImmGetContext(hWnd);
- if (himc == (HIMC)0)
- return;
-
- COMPOSITIONFORM cps;
- cps.dwStyle = CFS_FORCE_POSITION;
- cps.ptCurrentPos.x = im_position.x;
- cps.ptCurrentPos.y = im_position.y;
- ImmSetCompositionWindow(himc, &cps);
- ImmReleaseContext(hWnd, himc);
-}
-
-bool OS_Windows::is_joy_known(int p_device) {
- return input->is_joy_mapped(p_device);
-}
-
-String OS_Windows::get_joy_guid(int p_device) const {
- return input->get_joy_guid_remapped(p_device);
-}
-
-void OS_Windows::_set_use_vsync(bool p_enable) {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- if (context_gles2)
- context_gles2->set_use_vsync(p_enable);
- }
-#endif
-}
-
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc";
@@ -3344,27 +785,20 @@ bool OS_Windows::is_disable_crash_handler() const {
return crash_handler.is_disabled();
}
-void OS_Windows::process_and_drop_events() {
-
- drop_events = true;
- process_events();
- drop_events = false;
-}
-
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
WCHAR *from = new WCHAR[p_path.length() + 2];
wcscpy_s(from, p_path.length() + 1, p_path.c_str());
from[p_path.length() + 1] = 0;
- sf.hwnd = hWnd;
+ sf.hwnd = main_window;
sf.wFunc = FO_DELETE;
sf.pFrom = from;
- sf.pTo = NULL;
+ sf.pTo = nullptr;
sf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
sf.fAnyOperationsAborted = FALSE;
- sf.hNameMappings = NULL;
- sf.lpszProgressTitle = NULL;
+ sf.hNameMappings = nullptr;
+ sf.lpszProgressTitle = nullptr;
int ret = SHFileOperationW(&sf);
delete[] from;
@@ -3379,36 +813,12 @@ Error OS_Windows::move_to_trash(const String &p_path) {
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
- drop_events = false;
- key_event_pos = 0;
- layered_window = false;
- hBitmap = NULL;
force_quit = false;
- alt_mem = false;
- gr_mem = false;
- shift_mem = false;
- control_mem = false;
- meta_mem = false;
- minimized = false;
- was_maximized = false;
- window_focused = true;
- console_visible = IsWindowVisible(GetConsoleWindow());
-
- //Note: Functions for pen input, available on Windows 8+
- HMODULE user32_lib = LoadLibraryW(L"user32.dll");
- if (user32_lib) {
- win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
- win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)GetProcAddress(user32_lib, "GetPointerPenInfo");
- }
hInstance = _hInstance;
- pressrc = 0;
- old_invalid = true;
- mouse_mode = MOUSE_MODE_VISIBLE;
#ifdef STDOUT_FILE
stdo = fopen("stdout.txt", "wb");
#endif
- user_proc = NULL;
#ifdef WASAPI_ENABLED
AudioDriverManager::add_driver(&driver_wasapi);
@@ -3417,16 +827,14 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
AudioDriverManager::add_driver(&driver_xaudio2);
#endif
+ DisplayServerWindows::register_windows_driver();
+
Vector<Logger *> loggers;
loggers.push_back(memnew(WindowsTerminalLogger));
_set_logger(memnew(CompositeLogger(loggers)));
}
OS_Windows::~OS_Windows() {
- if (is_layered_allowed() && layered_window) {
- DeleteObject(hBitmap);
- DeleteDC(hDC_dib);
- }
#ifdef STDOUT_FILE
fclose(stdo);
#endif
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 6c3769c98c..6bdfc75ebb 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -31,7 +31,7 @@
#ifndef OS_WINDOWS_H
#define OS_WINDOWS_H
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "crash_handler_windows.h"
@@ -39,10 +39,9 @@
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "key_mapping_windows.h"
-#include "main/input_default.h"
#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
#ifdef XAUDIO2_ENABLED
#include "drivers/xaudio2/audio_driver_xaudio2.h"
#endif
@@ -62,183 +61,19 @@
#include <windows.h>
#include <windowsx.h>
-#ifndef POINTER_STRUCTURES
-
-#define POINTER_STRUCTURES
-
-typedef DWORD POINTER_INPUT_TYPE;
-typedef UINT32 POINTER_FLAGS;
-typedef UINT32 PEN_FLAGS;
-typedef UINT32 PEN_MASK;
-
-enum tagPOINTER_INPUT_TYPE {
- PT_POINTER = 0x00000001,
- PT_TOUCH = 0x00000002,
- PT_PEN = 0x00000003,
- PT_MOUSE = 0x00000004,
- PT_TOUCHPAD = 0x00000005
-};
-
-typedef enum tagPOINTER_BUTTON_CHANGE_TYPE {
- POINTER_CHANGE_NONE,
- POINTER_CHANGE_FIRSTBUTTON_DOWN,
- POINTER_CHANGE_FIRSTBUTTON_UP,
- POINTER_CHANGE_SECONDBUTTON_DOWN,
- POINTER_CHANGE_SECONDBUTTON_UP,
- POINTER_CHANGE_THIRDBUTTON_DOWN,
- POINTER_CHANGE_THIRDBUTTON_UP,
- POINTER_CHANGE_FOURTHBUTTON_DOWN,
- POINTER_CHANGE_FOURTHBUTTON_UP,
- POINTER_CHANGE_FIFTHBUTTON_DOWN,
- POINTER_CHANGE_FIFTHBUTTON_UP,
-} POINTER_BUTTON_CHANGE_TYPE;
-
-typedef struct tagPOINTER_INFO {
- POINTER_INPUT_TYPE pointerType;
- UINT32 pointerId;
- UINT32 frameId;
- POINTER_FLAGS pointerFlags;
- HANDLE sourceDevice;
- HWND hwndTarget;
- POINT ptPixelLocation;
- POINT ptHimetricLocation;
- POINT ptPixelLocationRaw;
- POINT ptHimetricLocationRaw;
- DWORD dwTime;
- UINT32 historyCount;
- INT32 InputData;
- DWORD dwKeyStates;
- UINT64 PerformanceCount;
- POINTER_BUTTON_CHANGE_TYPE ButtonChangeType;
-} POINTER_INFO;
-
-typedef struct tagPOINTER_PEN_INFO {
- POINTER_INFO pointerInfo;
- PEN_FLAGS penFlags;
- PEN_MASK penMask;
- UINT32 pressure;
- UINT32 rotation;
- INT32 tiltX;
- INT32 tiltY;
-} POINTER_PEN_INFO;
-
-#endif
-
-typedef BOOL(WINAPI *GetPointerTypePtr)(uint32_t p_id, POINTER_INPUT_TYPE *p_type);
-typedef BOOL(WINAPI *GetPointerPenInfoPtr)(uint32_t p_id, POINTER_PEN_INFO *p_pen_info);
-
-typedef struct {
- BYTE bWidth; // Width, in pixels, of the image
- BYTE bHeight; // Height, in pixels, of the image
- BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
- BYTE bReserved; // Reserved ( must be 0)
- WORD wPlanes; // Color Planes
- WORD wBitCount; // Bits per pixel
- DWORD dwBytesInRes; // How many bytes in this resource?
- DWORD dwImageOffset; // Where in the file is this image?
-} ICONDIRENTRY, *LPICONDIRENTRY;
-
-typedef struct {
- WORD idReserved; // Reserved (must be 0)
- WORD idType; // Resource Type (1 for icons)
- WORD idCount; // How many images?
- ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
-} ICONDIR, *LPICONDIR;
-
class JoypadWindows;
class OS_Windows : public OS {
- static GetPointerTypePtr win8p_GetPointerType;
- static GetPointerPenInfoPtr win8p_GetPointerPenInfo;
-
- enum {
- KEY_EVENT_BUFFER_SIZE = 512
- };
-
#ifdef STDOUT_FILE
FILE *stdo;
#endif
- struct KeyEvent {
-
- bool alt, shift, control, meta;
- UINT uMsg;
- WPARAM wParam;
- LPARAM lParam;
- };
-
- KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
- int key_event_pos;
-
uint64_t ticks_start;
uint64_t ticks_per_second;
- bool old_invalid;
- bool outside;
- int old_x, old_y;
- Point2i center;
-
-#if defined(OPENGL_ENABLED)
- ContextGL_Windows *context_gles2;
-#endif
-
-#if defined(VULKAN_ENABLED)
- VulkanContextWindows *context_vulkan;
- RenderingDeviceVulkan *rendering_device_vulkan;
-#endif
-
- VisualServer *visual_server;
- int pressrc;
- HINSTANCE hInstance; // Holds The Instance Of The Application
- HWND hWnd;
- Point2 last_pos;
-
- HBITMAP hBitmap; //DIB section for layered window
- uint8_t *dib_data;
- Size2 dib_size;
- HDC hDC_dib;
- bool layered_window;
-
- uint32_t move_timer_id;
-
- HCURSOR hCursor;
-
- Size2 min_size;
- Size2 max_size;
-
- Size2 window_rect;
- VideoMode video_mode;
- bool preserve_window_size = false;
-
+ HINSTANCE hInstance;
MainLoop *main_loop;
- WNDPROC user_proc;
-
- // IME
- HIMC im_himc;
- Vector2 im_position;
-
- MouseMode mouse_mode;
- bool alt_mem;
- bool gr_mem;
- bool shift_mem;
- bool control_mem;
- bool meta_mem;
- bool force_quit;
- bool window_has_focus;
- uint32_t last_button_state;
- bool use_raw_input;
- bool drop_events;
-
- HCURSOR cursors[CURSOR_MAX] = { NULL };
- CursorShape cursor_shape;
- Map<CursorShape, Vector<Variant> > cursors_cache;
-
- InputDefault *input;
- JoypadWindows *joypad;
- Map<int, Vector2> touch_state;
-
- int video_driver_index;
#ifdef WASAPI_ENABLED
AudioDriverWASAPI driver_wasapi;
#endif
@@ -251,28 +86,19 @@ class OS_Windows : public OS {
CrashHandler crash_handler;
- void _drag_event(float p_x, float p_y, int idx);
- void _touch_event(bool p_pressed, float p_x, float p_y, int idx);
-
- void _update_window_style(bool p_repaint = true, bool p_maximized = false);
-
- void _set_mouse_mode_impl(MouseMode p_mode);
+ bool force_quit;
+ HWND main_window;
// functions used by main to initialize/deinitialize the OS
protected:
- virtual int get_current_video_driver() const;
-
- virtual void initialize_core();
- virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
+ virtual void initialize();
virtual void set_main_loop(MainLoop *p_main_loop);
virtual void delete_main_loop();
virtual void finalize();
virtual void finalize_core();
-
- void process_events();
- void process_key_events();
+ virtual String get_stdin_string(bool p_block);
struct ProcessInfo {
@@ -281,75 +107,7 @@ protected:
};
Map<ProcessID, ProcessInfo> *process_map;
- bool pre_fs_valid;
- RECT pre_fs_rect;
- bool maximized;
- bool minimized;
- bool borderless;
- bool window_focused;
- bool console_visible;
- bool was_maximized;
-
public:
- LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-
- virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
- String get_stdin_string(bool p_block);
-
- void set_mouse_mode(MouseMode p_mode);
- MouseMode get_mouse_mode() const;
-
- virtual void warp_mouse_position(const Point2 &p_to);
- virtual Point2 get_mouse_position() const;
- void update_real_mouse_position();
- virtual int get_mouse_button_state() const;
- virtual void set_window_title(const String &p_title);
-
- virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
- virtual VideoMode get_video_mode(int p_screen = 0) const;
- virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
-
- virtual int get_screen_count() const;
- virtual int get_current_screen() const;
- virtual void set_current_screen(int p_screen);
- virtual Point2 get_screen_position(int p_screen = -1) const;
- virtual Size2 get_screen_size(int p_screen = -1) const;
- virtual int get_screen_dpi(int p_screen = -1) const;
-
- virtual Point2 get_window_position() const;
- virtual void set_window_position(const Point2 &p_position);
- virtual Size2 get_window_size() const;
- virtual Size2 get_real_window_size() const;
- virtual Size2 get_max_window_size() const;
- virtual Size2 get_min_window_size() const;
- virtual void set_min_window_size(const Size2 p_size);
- virtual void set_max_window_size(const Size2 p_size);
- virtual void set_window_size(const Size2 p_size);
- virtual void set_window_fullscreen(bool p_enabled);
- virtual bool is_window_fullscreen() const;
- virtual void set_window_resizable(bool p_enabled);
- virtual bool is_window_resizable() const;
- virtual void set_window_minimized(bool p_enabled);
- virtual bool is_window_minimized() const;
- virtual void set_window_maximized(bool p_enabled);
- virtual bool is_window_maximized() const;
- virtual void set_window_always_on_top(bool p_enabled);
- virtual bool is_window_always_on_top() const;
- virtual bool is_window_focused() const;
- virtual void set_console_visible(bool p_enabled);
- virtual bool is_console_visible() const;
- virtual void request_attention();
-
- virtual void set_borderless_window(bool p_borderless);
- virtual bool get_borderless_window();
-
- virtual bool get_window_per_pixel_transparency_enabled() const;
- virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
-
- virtual uint8_t *get_layered_buffer_data();
- virtual Size2 get_layered_buffer_size();
- virtual void swap_layered_buffer();
-
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
virtual Error close_dynamic_library(void *p_library_handle);
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
@@ -358,6 +116,8 @@ public:
virtual String get_name() const;
+ virtual void initialize_joypads() {}
+
virtual Date get_date(bool utc) const;
virtual Time get_time(bool utc) const;
virtual TimeZoneInfo get_time_zone_info() const;
@@ -365,13 +125,12 @@ public:
virtual uint64_t get_system_time_secs() const;
virtual uint64_t get_system_time_msecs() const;
- virtual bool can_draw() const;
virtual Error set_cwd(const String &p_cwd);
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL);
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
virtual Error kill(const ProcessID &p_pid);
virtual int get_process_id() const;
@@ -379,28 +138,12 @@ public:
virtual String get_environment(const String &p_var) const;
virtual bool set_environment(const String &p_var, const String &p_value) const;
- virtual void set_clipboard(const String &p_text);
- virtual String get_clipboard() const;
-
- void set_cursor_shape(CursorShape p_shape);
- CursorShape get_cursor_shape() const;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
- void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
-
- void set_native_icon(const String &p_filename);
- void set_icon(const Ref<Image> &p_icon);
-
virtual String get_executable_path() const;
virtual String get_locale() const;
virtual int get_processor_count() const;
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
-
- virtual void enable_for_stealing_focus(ProcessID pid);
- virtual void move_window_to_foreground();
-
virtual String get_config_path() const;
virtual String get_data_path() const;
virtual String get_cache_path() const;
@@ -411,37 +154,21 @@ public:
virtual String get_unique_id() const;
- virtual void set_ime_active(const bool p_active);
- virtual void set_ime_position(const Point2 &p_pos);
-
- virtual void release_rendering_thread();
- virtual void make_rendering_thread();
- virtual void swap_buffers();
-
virtual Error shell_open(String p_uri);
void run();
- virtual bool get_swap_ok_cancel() { return true; }
-
- virtual bool is_joy_known(int p_device);
- virtual String get_joy_guid(int p_device) const;
-
- virtual void _set_use_vsync(bool p_enable);
- //virtual bool is_vsync_enabled() const;
-
virtual bool _check_internal_feature_support(const String &p_feature);
void disable_crash_handler();
bool is_disable_crash_handler() const;
virtual void initialize_debugging();
- void force_process_input();
-
virtual Error move_to_trash(const String &p_path);
- virtual void process_and_drop_events();
+ void set_main_window(HWND p_main_window) { main_window = p_main_window; }
+ HINSTANCE get_hinstance() { return hInstance; }
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
};
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index a1ad3b8b50..22e33b51b4 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -9,14 +9,14 @@ from platform_methods import subprocess_main
def make_debug_mingw(target, source, env):
mingw_prefix = ""
- if (env["bits"] == "32"):
+ if env["bits"] == "32":
mingw_prefix = env["mingw_prefix_32"]
else:
mingw_prefix = env["mingw_prefix_64"]
- os.system(mingw_prefix + 'objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0]))
- os.system(mingw_prefix + 'strip --strip-debug --strip-unneeded {0}'.format(target[0]))
- os.system(mingw_prefix + 'objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0]))
+ os.system(mingw_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ os.system(mingw_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ os.system(mingw_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
-if __name__ == '__main__':
+if __name__ == "__main__":
subprocess_main(globals())
diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp
index 20e1b46682..98aa21411f 100644
--- a/platform/windows/vulkan_context_win.cpp
+++ b/platform/windows/vulkan_context_win.cpp
@@ -35,19 +35,19 @@ const char *VulkanContextWindows::_get_platform_surface_extension() const {
return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
}
-int VulkanContextWindows::window_create(HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
+int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = NULL;
+ createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.hinstance = p_instance;
createInfo.hwnd = p_window;
VkSurfaceKHR surface;
- VkResult err = vkCreateWin32SurfaceKHR(_get_instance(), &createInfo, NULL, &surface);
+ VkResult err = vkCreateWin32SurfaceKHR(_get_instance(), &createInfo, nullptr, &surface);
ERR_FAIL_COND_V(err, -1);
- return _window_create(surface, p_width, p_height);
+ return _window_create(p_window_id, surface, p_width, p_height);
}
VulkanContextWindows::VulkanContextWindows() {
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index 1289f2a299..c9fea9369b 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/vulkan_context_win.h
@@ -39,7 +39,7 @@ class VulkanContextWindows : public VulkanContext {
virtual const char *_get_platform_surface_extension() const;
public:
- int window_create(HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
+ int window_create(DisplayServer::WindowID p_window_id, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
VulkanContextWindows();
~VulkanContextWindows();
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 520b654b94..884d95e082 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -49,7 +49,7 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
len = BUFFER_SIZE; // Output is too big, will be truncated
buf[len] = 0;
- int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0);
+ int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, nullptr, 0);
if (wlen < 0)
return;
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
deleted file mode 100644
index 2268e4cc3d..0000000000
--- a/platform/x11/SCsub
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-from platform_methods import run_in_subprocess
-import platform_x11_builders
-
-common_x11 = [
- "context_gl_x11.cpp",
- "vulkan_context_x11.cpp",
- "crash_handler_x11.cpp",
- "os_x11.cpp",
- "key_mapping_x11.cpp",
- "joypad_linux.cpp",
- "detect_prime.cpp"
-]
-
-prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11)
-
-if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
- env.AddPostAction(prog, run_in_subprocess(platform_x11_builders.make_debug_x11))
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
deleted file mode 100644
index 5442af3bef..0000000000
--- a/platform/x11/context_gl_x11.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*************************************************************************/
-/* context_gl_x11.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "context_gl_x11.h"
-
-#ifdef X11_ENABLED
-#if defined(OPENGL_ENABLED)
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define GLX_GLXEXT_PROTOTYPES
-#include <GL/glx.h>
-#include <GL/glxext.h>
-
-#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
-#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
-
-typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
-
-struct ContextGL_X11_Private {
-
- ::GLXContext glx_context;
-};
-
-void ContextGL_X11::release_current() {
-
- glXMakeCurrent(x11_display, None, NULL);
-}
-
-void ContextGL_X11::make_current() {
-
- glXMakeCurrent(x11_display, x11_window, p->glx_context);
-}
-
-void ContextGL_X11::swap_buffers() {
-
- glXSwapBuffers(x11_display, x11_window);
-}
-
-static bool ctxErrorOccurred = false;
-static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
- ctxErrorOccurred = true;
- return 0;
-}
-
-static void set_class_hint(Display *p_display, Window p_window) {
- XClassHint *classHint;
-
- /* set the name and class hints for the window manager to use */
- classHint = XAllocClassHint();
- if (classHint) {
- classHint->res_name = (char *)"Godot_Engine";
- classHint->res_class = (char *)"Godot";
- }
- XSetClassHint(p_display, p_window, classHint);
- XFree(classHint);
-}
-
-Error ContextGL_X11::initialize() {
-
- //const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
-
- GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
-
- ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED);
-
- static int visual_attribs[] = {
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_DOUBLEBUFFER, true,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DEPTH_SIZE, 24,
- None
- };
-
- static int visual_attribs_layered[] = {
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_DOUBLEBUFFER, true,
- GLX_RED_SIZE, 8,
- GLX_GREEN_SIZE, 8,
- GLX_BLUE_SIZE, 8,
- GLX_ALPHA_SIZE, 8,
- GLX_DEPTH_SIZE, 24,
- None
- };
-
- int fbcount;
- GLXFBConfig fbconfig = 0;
- XVisualInfo *vi = NULL;
-
- XSetWindowAttributes swa;
- swa.event_mask = StructureNotifyMask;
- swa.border_pixel = 0;
- unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
-
- if (OS::get_singleton()->is_layered_allowed()) {
- GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
- ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
-
- for (int i = 0; i < fbcount; i++) {
- vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
- if (!vi)
- continue;
-
- XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual);
- if (!pict_format) {
- XFree(vi);
- vi = NULL;
- continue;
- }
-
- fbconfig = fbc[i];
- if (pict_format->direct.alphaMask > 0) {
- break;
- }
- }
- XFree(fbc);
- ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
-
- swa.background_pixmap = None;
- swa.background_pixel = 0;
- swa.border_pixmap = None;
- valuemask |= CWBackPixel;
-
- } else {
- GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
- ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
-
- vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
-
- fbconfig = fbc[0];
- XFree(fbc);
- }
-
- int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
-
- switch (context_type) {
- case GLES_2_0_COMPATIBLE: {
-
- p->glx_context = glXCreateNewContext(x11_display, fbconfig, GLX_RGBA_TYPE, 0, true);
- ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
- } break;
- }
-
- swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
- x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
- XStoreName(x11_display, x11_window, "Godot Engine");
-
- ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED);
- set_class_hint(x11_display, x11_window);
- XMapWindow(x11_display, x11_window);
-
- XSync(x11_display, False);
- XSetErrorHandler(oldHandler);
-
- glXMakeCurrent(x11_display, x11_window, p->glx_context);
-
- XFree(vi);
-
- return OK;
-}
-
-int ContextGL_X11::get_window_width() {
-
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, x11_window, &xwa);
-
- return xwa.width;
-}
-
-int ContextGL_X11::get_window_height() {
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, x11_window, &xwa);
-
- return xwa.height;
-}
-
-void ContextGL_X11::set_use_vsync(bool p_use) {
- static bool setup = false;
- static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = NULL;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = NULL;
- static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = NULL;
-
- if (!setup) {
- setup = true;
- String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display));
- if (extensions.find("GLX_EXT_swap_control") != -1)
- glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT");
- if (extensions.find("GLX_MESA_swap_control") != -1)
- glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA");
- if (extensions.find("GLX_SGI_swap_control") != -1)
- glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI");
- }
- int val = p_use ? 1 : 0;
- if (glXSwapIntervalMESA) {
- glXSwapIntervalMESA(val);
- } else if (glXSwapIntervalSGI) {
- glXSwapIntervalSGI(val);
- } else if (glXSwapIntervalEXT) {
- GLXDrawable drawable = glXGetCurrentDrawable();
- glXSwapIntervalEXT(x11_display, drawable, val);
- } else
- return;
- use_vsync = p_use;
-}
-bool ContextGL_X11::is_using_vsync() const {
-
- return use_vsync;
-}
-
-ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type) :
- x11_window(p_x11_window) {
-
- default_video_mode = p_default_video_mode;
- x11_display = p_x11_display;
-
- context_type = p_context_type;
-
- double_buffer = false;
- direct_render = false;
- glx_minor = glx_major = 0;
- p = memnew(ContextGL_X11_Private);
- p->glx_context = 0;
- use_vsync = false;
-}
-
-ContextGL_X11::~ContextGL_X11() {
- release_current();
- glXDestroyContext(x11_display, p->glx_context);
- memdelete(p);
-}
-
-#endif
-#endif
diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp
deleted file mode 100644
index 19c8f71d0e..0000000000
--- a/platform/x11/crash_handler_x11.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*************************************************************************/
-/* crash_handler_x11.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "crash_handler_x11.h"
-
-#include "core/os/os.h"
-#include "core/project_settings.h"
-#include "main/main.h"
-
-#ifdef DEBUG_ENABLED
-#define CRASH_HANDLER_ENABLED 1
-#endif
-
-#ifdef CRASH_HANDLER_ENABLED
-#include <cxxabi.h>
-#include <dlfcn.h>
-#include <execinfo.h>
-#include <signal.h>
-#include <stdlib.h>
-
-static void handle_crash(int sig) {
- if (OS::get_singleton() == NULL) {
- abort();
- }
-
- void *bt_buffer[256];
- size_t size = backtrace(bt_buffer, 256);
- String _execpath = OS::get_singleton()->get_executable_path();
-
- String msg;
- const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
- if (proj_settings) {
- msg = proj_settings->get("debug/settings/crash_handler/message");
- }
-
- // Dump the backtrace to stderr with a message to the user
- fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
-
- if (OS::get_singleton()->get_main_loop())
- OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
-
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
- char **strings = backtrace_symbols(bt_buffer, size);
- if (strings) {
- for (size_t i = 1; i < size; i++) {
- char fname[1024];
- Dl_info info;
-
- snprintf(fname, 1024, "%s", strings[i]);
-
- // Try to demangle the function name to provide a more readable one
- 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);
-
- if (status == 0 && demangled) {
- snprintf(fname, 1024, "%s", demangled);
- }
-
- if (demangled)
- free(demangled);
- }
- }
-
- List<String> args;
-
- char str[1024];
- snprintf(str, 1024, "%p", bt_buffer[i]);
- args.push_back(str);
- args.push_back("-e");
- args.push_back(_execpath);
-
- String output = "";
-
- // Try to get the file/line number using addr2line
- int ret;
- Error err = OS::get_singleton()->execute(String("addr2line"), args, true, NULL, &output, &ret);
- if (err == OK) {
- output.erase(output.length() - 1, 1);
- }
-
- fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str());
- }
-
- free(strings);
- }
- fprintf(stderr, "-- END OF BACKTRACE --\n");
-
- // Abort to pass the error to the OS
- abort();
-}
-#endif
-
-CrashHandler::CrashHandler() {
- disabled = false;
-}
-
-CrashHandler::~CrashHandler() {
- disable();
-}
-
-void CrashHandler::disable() {
- if (disabled)
- return;
-
-#ifdef CRASH_HANDLER_ENABLED
- signal(SIGSEGV, NULL);
- signal(SIGFPE, NULL);
- signal(SIGILL, NULL);
-#endif
-
- disabled = true;
-}
-
-void CrashHandler::initialize() {
-#ifdef CRASH_HANDLER_ENABLED
- signal(SIGSEGV, handle_crash);
- signal(SIGFPE, handle_crash);
- signal(SIGILL, handle_crash);
-#endif
-}
diff --git a/platform/x11/crash_handler_x11.h b/platform/x11/crash_handler_x11.h
deleted file mode 100644
index 98620cc789..0000000000
--- a/platform/x11/crash_handler_x11.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* crash_handler_x11.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CRASH_HANDLER_X11_H
-#define CRASH_HANDLER_X11_H
-
-class CrashHandler {
-
- bool disabled;
-
-public:
- void initialize();
-
- void disable();
- bool is_disabled() const { return disabled; };
-
- CrashHandler();
- ~CrashHandler();
-};
-
-#endif // CRASH_HANDLER_X11_H
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
deleted file mode 100644
index 9a9ab86068..0000000000
--- a/platform/x11/detect.py
+++ /dev/null
@@ -1,368 +0,0 @@
-import os
-import platform
-import sys
-
-
-def is_active():
- return True
-
-
-def get_name():
- return "X11"
-
-
-def can_build():
-
- if (os.name != "posix" or sys.platform == "darwin"):
- return False
-
- # Check the minimal dependencies
- x11_error = os.system("pkg-config --version > /dev/null")
- if (x11_error):
- return False
-
- x11_error = os.system("pkg-config x11 --modversion > /dev/null ")
- if (x11_error):
- return False
-
- x11_error = os.system("pkg-config xcursor --modversion > /dev/null ")
- if (x11_error):
- print("xcursor not found.. x11 disabled.")
- return False
-
- x11_error = os.system("pkg-config xinerama --modversion > /dev/null ")
- if (x11_error):
- print("xinerama not found.. x11 disabled.")
- return False
-
- x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
- if (x11_error):
- print("xrandr not found.. x11 disabled.")
- return False
-
- x11_error = os.system("pkg-config xrender --modversion > /dev/null ")
- if (x11_error):
- print("xrender not found.. x11 disabled.")
- return False
-
- x11_error = os.system("pkg-config xi --modversion > /dev/null ")
- if (x11_error):
- print("xi not found.. Aborting.")
- return False
-
- return True
-
-def get_opts():
- from SCons.Variables import BoolVariable, EnumVariable
-
- return [
- BoolVariable('use_llvm', 'Use the LLVM compiler', False),
- BoolVariable('use_lld', 'Use the LLD linker', False),
- BoolVariable('use_thinlto', 'Use ThinLTO', False),
- BoolVariable('use_static_cpp', 'Link libgcc and libstdc++ statically for better portability', False),
- 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('pulseaudio', 'Detect and use PulseAudio', True),
- BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
- EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')),
- BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False),
- BoolVariable('touch', 'Enable touch events', True),
- BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False),
- ]
-
-
-def get_flags():
-
- return []
-
-
-def configure(env):
-
- ## Build type
-
- if (env["target"] == "release"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O3'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
-
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "release_debug"):
- if (env["optimize"] == "speed"): #optimize for speed (default)
- env.Prepend(CCFLAGS=['-O2'])
- else: #optimize for size
- env.Prepend(CCFLAGS=['-Os'])
- env.Prepend(CPPDEFINES=['DEBUG_ENABLED'])
-
- if (env["debug_symbols"] == "yes"):
- env.Prepend(CCFLAGS=['-g1'])
- if (env["debug_symbols"] == "full"):
- env.Prepend(CCFLAGS=['-g2'])
-
- elif (env["target"] == "debug"):
- env.Prepend(CCFLAGS=['-g3'])
- env.Prepend(CPPDEFINES=['DEBUG_ENABLED', 'DEBUG_MEMORY_ENABLED'])
- env.Append(LINKFLAGS=['-rdynamic'])
-
- ## Architecture
-
- is64 = sys.maxsize > 2**32
- if (env["bits"] == "default"):
- env["bits"] = "64" if is64 else "32"
-
- ## Compiler configuration
-
- if 'CXX' in env and 'clang' in os.path.basename(env['CXX']):
- # Convenience check to enforce the use_llvm overrides when CXX is clang(++)
- env['use_llvm'] = True
-
- if env['use_llvm']:
- if ('clang++' not in os.path.basename(env['CXX'])):
- env["CC"] = "clang"
- env["CXX"] = "clang++"
- env["LINK"] = "clang++"
- env.Append(CPPDEFINES=['TYPED_METHOD_BIND'])
- env.extra_suffix = ".llvm" + env.extra_suffix
-
- if env['use_lld']:
- if env['use_llvm']:
- env.Append(LINKFLAGS=['-fuse-ld=lld'])
- if env['use_thinlto']:
- # A convenience so you don't need to write use_lto too when using SCons
- env['use_lto'] = True
- else:
- print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.")
- sys.exit(255)
-
- 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']:
- env.extra_suffix += "s"
-
- if env['use_ubsan']:
- env.Append(CCFLAGS=['-fsanitize=undefined'])
- env.Append(LINKFLAGS=['-fsanitize=undefined'])
-
- if env['use_asan']:
- env.Append(CCFLAGS=['-fsanitize=address'])
- env.Append(LINKFLAGS=['-fsanitize=address'])
-
- if env['use_lsan']:
- env.Append(CCFLAGS=['-fsanitize=leak'])
- env.Append(LINKFLAGS=['-fsanitize=leak'])
-
- if env['use_tsan']:
- env.Append(CCFLAGS=['-fsanitize=thread'])
- env.Append(LINKFLAGS=['-fsanitize=thread'])
-
- if env['use_lto']:
- if not env['use_llvm'] and env.GetOption("num_jobs") > 1:
- env.Append(CCFLAGS=['-flto'])
- env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
- else:
- if env['use_lld'] and env['use_thinlto']:
- env.Append(CCFLAGS=['-flto=thin'])
- env.Append(LINKFLAGS=['-flto=thin'])
- else:
- env.Append(CCFLAGS=['-flto'])
- env.Append(LINKFLAGS=['-flto'])
-
- if not env['use_llvm']:
- env['RANLIB'] = 'gcc-ranlib'
- env['AR'] = 'gcc-ar'
-
- env.Append(CCFLAGS=['-pipe'])
- env.Append(LINKFLAGS=['-pipe'])
-
- # -fpie and -no-pie is supported on GCC 6+ and Clang 4+, both below our
- # minimal requirements.
- env.Append(CCFLAGS=['-fpie'])
- env.Append(LINKFLAGS=['-no-pie'])
-
- ## Dependencies
-
- env.ParseConfig('pkg-config x11 --cflags --libs')
- env.ParseConfig('pkg-config xcursor --cflags --libs')
- env.ParseConfig('pkg-config xinerama --cflags --libs')
- env.ParseConfig('pkg-config xrandr --cflags --libs')
- env.ParseConfig('pkg-config xrender --cflags --libs')
- env.ParseConfig('pkg-config xi --cflags --libs')
-
- if (env['touch']):
- env.Append(CPPDEFINES=['TOUCH_ENABLED'])
-
- # FIXME: Check for existence of the libs before parsing their flags with pkg-config
-
- # freetype depends on libpng and zlib, so bundling one of them while keeping others
- # as shared libraries leads to weird issues
- if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']:
- env['builtin_freetype'] = True
- env['builtin_libpng'] = True
- env['builtin_zlib'] = True
-
- if not env['builtin_freetype']:
- env.ParseConfig('pkg-config freetype2 --cflags --libs')
-
- if not env['builtin_libpng']:
- env.ParseConfig('pkg-config libpng16 --cflags --libs')
-
- if not env['builtin_bullet']:
- # We need at least version 2.89
- import subprocess
- bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
- if str(bullet_version) < "2.89":
- # Abort as system bullet was requested but too old
- print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.89"))
- sys.exit(255)
- env.ParseConfig('pkg-config bullet --cflags --libs')
-
- if False: # not env['builtin_assimp']:
- # FIXME: Add min version check
- env.ParseConfig('pkg-config assimp --cflags --libs')
-
- if not env['builtin_enet']:
- env.ParseConfig('pkg-config libenet --cflags --libs')
-
- if not env['builtin_squish']:
- env.ParseConfig('pkg-config libsquish --cflags --libs')
-
- if not env['builtin_zstd']:
- env.ParseConfig('pkg-config libzstd --cflags --libs')
-
- # Sound and video libraries
- # Keep the order as it triggers chained dependencies (ogg needed by others, etc.)
-
- if not env['builtin_libtheora']:
- env['builtin_libogg'] = False # Needed to link against system libtheora
- env['builtin_libvorbis'] = False # Needed to link against system libtheora
- env.ParseConfig('pkg-config theora theoradec --cflags --libs')
- else:
- list_of_x86 = ['x86_64', 'x86', 'i386', 'i586']
- if any(platform.machine() in s for s in list_of_x86):
- env["x86_libtheora_opt_gcc"] = True
-
- if not env['builtin_libvpx']:
- env.ParseConfig('pkg-config vpx --cflags --libs')
-
- if not env['builtin_libvorbis']:
- env['builtin_libogg'] = False # Needed to link against system libvorbis
- env.ParseConfig('pkg-config vorbis vorbisfile --cflags --libs')
-
- if not env['builtin_opus']:
- env['builtin_libogg'] = False # Needed to link against system opus
- env.ParseConfig('pkg-config opus opusfile --cflags --libs')
-
- if not env['builtin_libogg']:
- env.ParseConfig('pkg-config ogg --cflags --libs')
-
- if not env['builtin_libwebp']:
- env.ParseConfig('pkg-config libwebp --cflags --libs')
-
- if not env['builtin_mbedtls']:
- # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
- env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
-
- if not env['builtin_wslay']:
- env.ParseConfig('pkg-config libwslay --cflags --libs')
-
- if not env['builtin_miniupnpc']:
- # No pkgconfig file so far, hardcode default paths.
- env.Prepend(CPPPATH=["/usr/include/miniupnpc"])
- env.Append(LIBS=["miniupnpc"])
-
- # On Linux wchar_t should be 32-bits
- # 16-bit library shouldn't be required due to compiler optimisations
- if not env['builtin_pcre2']:
- env.ParseConfig('pkg-config libpcre2-32 --cflags --libs')
-
- ## Flags
-
- if (os.system("pkg-config --exists alsa") == 0): # 0 means found
- print("Enabling ALSA")
- 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")
-
- if env['pulseaudio']:
- 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')
- 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")
-
- # Linkflags below this line should typically stay the last ones
- if not env['builtin_zlib']:
- env.ParseConfig('pkg-config zlib --cflags --libs')
-
- env.Prepend(CPPPATH=['#platform/x11'])
- env.Append(CPPDEFINES=['X11_ENABLED', 'UNIX_ENABLED'])
-
- env.Append(CPPDEFINES=['VULKAN_ENABLED'])
- if not env['builtin_vulkan']:
- env.ParseConfig('pkg-config vulkan --cflags --libs')
- if not env['builtin_glslang']:
- # No pkgconfig file for glslang so far
- env.Append(LIBS=['glslang', 'SPIRV'])
-
- #env.Append(CPPDEFINES=['OPENGL_ENABLED'])
- env.Append(LIBS=['GL'])
-
- env.Append(LIBS=['pthread'])
-
- if (platform.system() == "Linux"):
- env.Append(LIBS=['dl'])
-
- if (platform.system().find("BSD") >= 0):
- env["execinfo"] = True
-
- if env["execinfo"]:
- env.Append(LIBS=['execinfo'])
-
- if not env['tools']:
- import subprocess
- import re
- linker_version_str = subprocess.check_output([env.subst(env["LINK"]), '-Wl,--version']).decode("utf-8")
- gnu_ld_version = re.search('^GNU ld [^$]*(\d+\.\d+)$', linker_version_str, re.MULTILINE)
- if not gnu_ld_version:
- print("Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld")
- else:
- if float(gnu_ld_version.group(1)) >= 2.30:
- env.Append(LINKFLAGS=['-T', 'platform/x11/pck_embed.ld'])
- else:
- env.Append(LINKFLAGS=['-T', 'platform/x11/pck_embed.legacy.ld'])
-
- ## Cross-compilation
-
- if (is64 and env["bits"] == "32"):
- env.Append(CCFLAGS=['-m32'])
- env.Append(LINKFLAGS=['-m32', '-L/usr/lib/i386-linux-gnu'])
- elif (not is64 and env["bits"] == "64"):
- env.Append(CCFLAGS=['-m64'])
- env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
-
- # Link those statically for portability
- if env['use_static_cpp']:
- env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])
diff --git a/platform/x11/detect_prime.cpp b/platform/x11/detect_prime.cpp
deleted file mode 100644
index a0e5f835c0..0000000000
--- a/platform/x11/detect_prime.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*************************************************************************/
-/* detect_prime.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 X11_ENABLED
-#if defined(OPENGL_ENABLED)
-
-#include "core/print_string.h"
-#include "core/ustring.h"
-
-#include <stdlib.h>
-
-#include <GL/gl.h>
-#include <GL/glx.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#include <cstring>
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
-#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
-
-typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
-
-struct vendor {
- const char *glxvendor;
- int priority;
-};
-
-vendor vendormap[] = {
- { "Advanced Micro Devices, Inc.", 30 },
- { "NVIDIA Corporation", 30 },
- { "X.Org", 30 },
- { "Intel Open Source Technology Center", 20 },
- { "Intel", 20 },
- { "nouveau", 10 },
- { "Mesa Project", 0 },
- { NULL, 0 }
-};
-
-// Runs inside a child. Exiting will not quit the engine.
-void create_context() {
- Display *x11_display = XOpenDisplay(NULL);
- Window x11_window;
- GLXContext glx_context;
-
- GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
-
- static int visual_attribs[] = {
- GLX_RENDER_TYPE, GLX_RGBA_BIT,
- GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
- GLX_DOUBLEBUFFER, true,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DEPTH_SIZE, 24,
- None
- };
-
- int fbcount;
- GLXFBConfig fbconfig = 0;
- XVisualInfo *vi = NULL;
-
- XSetWindowAttributes swa;
- swa.event_mask = StructureNotifyMask;
- swa.border_pixel = 0;
- unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
-
- GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
- if (!fbc)
- exit(1);
-
- vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
-
- fbconfig = fbc[0];
-
- static int context_attribs[] = {
- GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
- GLX_CONTEXT_MINOR_VERSION_ARB, 3,
- GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
- GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
- None
- };
-
- glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, NULL, true, context_attribs);
-
- swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
- x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, 10, 10, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa);
-
- if (!x11_window)
- exit(1);
-
- glXMakeCurrent(x11_display, x11_window, glx_context);
- XFree(vi);
-}
-
-int detect_prime() {
- pid_t p;
- int priorities[2];
- String vendors[2];
- String renderers[2];
-
- vendors[0] = "Unknown";
- vendors[1] = "Unknown";
- renderers[0] = "Unknown";
- renderers[1] = "Unknown";
-
- for (int i = 0; i < 2; ++i) {
- int fdset[2];
-
- if (pipe(fdset) == -1) {
- print_verbose("Failed to pipe(), using default GPU");
- return 0;
- }
-
- // Fork so the driver initialization can crash without taking down the engine.
- p = fork();
-
- if (p > 0) {
- // Main thread
-
- int stat_loc = 0;
- char string[201];
- string[200] = '\0';
-
- close(fdset[1]);
-
- waitpid(p, &stat_loc, 0);
-
- if (!stat_loc) {
- // No need to do anything complicated here. Anything less than
- // PIPE_BUF will be delivered in one read() call.
- // Leave it 'Unknown' otherwise.
- if (read(fdset[0], string, sizeof(string) - 1) > 0) {
- vendors[i] = string;
- renderers[i] = string + strlen(string) + 1;
- }
- }
-
- close(fdset[0]);
-
- } else {
- // In child, exit() here will not quit the engine.
-
- char string[201];
-
- close(fdset[0]);
-
- if (i) setenv("DRI_PRIME", "1", 1);
- create_context();
-
- const char *vendor = (const char *)glGetString(GL_VENDOR);
- const char *renderer = (const char *)glGetString(GL_RENDERER);
-
- unsigned int vendor_len = strlen(vendor) + 1;
- unsigned int renderer_len = strlen(renderer) + 1;
-
- if (vendor_len + renderer_len >= sizeof(string)) {
- renderer_len = 200 - vendor_len;
- }
-
- memcpy(&string, vendor, vendor_len);
- memcpy(&string[vendor_len], renderer, renderer_len);
-
- if (write(fdset[1], string, vendor_len + renderer_len) == -1) {
- print_verbose("Couldn't write vendor/renderer string.");
- }
- close(fdset[1]);
- exit(0);
- }
- }
-
- int preferred = 0;
- int priority = 0;
-
- if (vendors[0] == vendors[1]) {
- print_verbose("Only one GPU found, using default.");
- return 0;
- }
-
- for (int i = 1; i >= 0; --i) {
- vendor *v = vendormap;
- while (v->glxvendor) {
- if (v->glxvendor == vendors[i]) {
- priorities[i] = v->priority;
-
- if (v->priority >= priority) {
- priority = v->priority;
- preferred = i;
- }
- }
- ++v;
- }
- }
-
- print_verbose("Found renderers:");
- for (int i = 0; i < 2; ++i) {
- print_verbose("Renderer " + itos(i) + ": " + renderers[i] + " with priority: " + itos(priorities[i]));
- }
-
- print_verbose("Using renderer: " + renderers[preferred]);
- return preferred;
-}
-
-#endif
-#endif
diff --git a/platform/x11/detect_prime.h b/platform/x11/detect_prime.h
deleted file mode 100644
index df636449f4..0000000000
--- a/platform/x11/detect_prime.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* detect_prime.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 X11_ENABLED
-#if defined(OPENGL_ENABLED)
-
-int detect_prime();
-
-#endif
-#endif
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
deleted file mode 100644
index 1c0c6ec096..0000000000
--- a/platform/x11/export/export.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*************************************************************************/
-/* export.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "export.h"
-
-#include "core/os/file_access.h"
-#include "editor/editor_export.h"
-#include "platform/x11/logo.gen.h"
-#include "scene/resources/texture.h"
-
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
-
-void register_x11_exporter() {
-
- Ref<EditorExportPlatformPC> platform;
- platform.instance();
-
- Ref<Image> img = memnew(Image(_x11_logo));
- Ref<ImageTexture> logo;
- logo.instance();
- logo->create_from_image(img);
- platform->set_logo(logo);
- platform->set_name("Linux/X11");
- platform->set_extension("x86");
- platform->set_extension("x86_64", "binary_format/64_bits");
- platform->set_release_32("linux_x11_32_release");
- platform->set_debug_32("linux_x11_32_debug");
- platform->set_release_64("linux_x11_64_release");
- platform->set_debug_64("linux_x11_64_debug");
- platform->set_os_name("X11");
- platform->set_chmod_flags(0755);
- platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
-
- EditorExport::get_singleton()->add_export_platform(platform);
-}
-
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
-
- // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
-
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
- if (!f) {
- return ERR_CANT_OPEN;
- }
-
- // Read and check ELF magic number
- {
- uint32_t magic = f->get_32();
- if (magic != 0x464c457f) { // 0x7F + "ELF"
- f->close();
- return ERR_FILE_CORRUPT;
- }
- }
-
- // Read program architecture bits from class field
-
- int bits = f->get_8() * 32;
-
- if (bits == 32 && p_embedded_size >= 0x100000000) {
- f->close();
- ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
- }
-
- // Get info about the section header table
-
- int64_t section_table_pos;
- int64_t section_header_size;
- if (bits == 32) {
- section_header_size = 40;
- f->seek(0x20);
- section_table_pos = f->get_32();
- f->seek(0x30);
- } else { // 64
- section_header_size = 64;
- f->seek(0x28);
- section_table_pos = f->get_64();
- f->seek(0x3c);
- }
- int num_sections = f->get_16();
- int string_section_idx = f->get_16();
-
- // Load the strings table
- uint8_t *strings;
- {
- // Jump to the strings section header
- f->seek(section_table_pos + string_section_idx * section_header_size);
-
- // Read strings data size and offset
- int64_t string_data_pos;
- int64_t string_data_size;
- if (bits == 32) {
- f->seek(f->get_position() + 0x10);
- string_data_pos = f->get_32();
- string_data_size = f->get_32();
- } else { // 64
- f->seek(f->get_position() + 0x18);
- string_data_pos = f->get_64();
- string_data_size = f->get_64();
- }
-
- // Read strings data
- f->seek(string_data_pos);
- strings = (uint8_t *)memalloc(string_data_size);
- if (!strings) {
- f->close();
- return ERR_OUT_OF_MEMORY;
- }
- f->get_buffer(strings, string_data_size);
- }
-
- // Search for the "pck" section
-
- bool found = false;
- for (int i = 0; i < num_sections; ++i) {
-
- int64_t section_header_pos = section_table_pos + i * section_header_size;
- f->seek(section_header_pos);
-
- uint32_t name_offset = f->get_32();
- if (strcmp((char *)strings + name_offset, "pck") == 0) {
- // "pck" section found, let's patch!
-
- if (bits == 32) {
- f->seek(section_header_pos + 0x10);
- f->store_32(p_embedded_start);
- f->store_32(p_embedded_size);
- } else { // 64
- f->seek(section_header_pos + 0x18);
- f->store_64(p_embedded_start);
- f->store_64(p_embedded_size);
- }
-
- found = true;
- break;
- }
- }
-
- memfree(strings);
- f->close();
-
- return found ? OK : ERR_FILE_CORRUPT;
-}
diff --git a/platform/x11/export/export.h b/platform/x11/export/export.h
deleted file mode 100644
index d94ea114a8..0000000000
--- a/platform/x11/export/export.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*************************************************************************/
-/* export.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-void register_x11_exporter();
diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp
deleted file mode 100644
index 77b74184ad..0000000000
--- a/platform/x11/godot_x11.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*************************************************************************/
-/* godot_x11.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 <limits.h>
-#include <locale.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "main/main.h"
-#include "os_x11.h"
-
-int main(int argc, char *argv[]) {
-
- OS_X11 os;
-
- setlocale(LC_CTYPE, "");
-
- char *cwd = (char *)malloc(PATH_MAX);
- ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY);
- char *ret = getcwd(cwd, PATH_MAX);
-
- Error err = Main::setup(argv[0], argc - 1, &argv[1]);
- if (err != OK) {
- free(cwd);
- return 255;
- }
-
- if (Main::start())
- os.run(); // it is actually the OS that decides how to run
- Main::cleanup();
-
- if (ret) { // Previous getcwd was successful
- if (chdir(cwd) != 0) {
- ERR_PRINT("Couldn't return to previous working directory.");
- }
- }
- free(cwd);
-
- return os.get_exit_code();
-}
diff --git a/platform/x11/joypad_linux.cpp b/platform/x11/joypad_linux.cpp
deleted file mode 100644
index a9fe7275c2..0000000000
--- a/platform/x11/joypad_linux.cpp
+++ /dev/null
@@ -1,551 +0,0 @@
-/*************************************************************************/
-/* joypad_linux.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 JOYDEV_ENABLED
-
-#include "joypad_linux.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <unistd.h>
-
-#ifdef UDEV_ENABLED
-#include <libudev.h>
-#endif
-
-#define LONG_BITS (sizeof(long) * 8)
-#define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0)
-#define NBITS(x) ((((x)-1) / LONG_BITS) + 1)
-
-#ifdef UDEV_ENABLED
-static const char *ignore_str = "/dev/input/js";
-#endif
-
-JoypadLinux::Joypad::Joypad() {
- fd = -1;
- dpad = 0;
- devpath = "";
- for (int i = 0; i < MAX_ABS; i++) {
- abs_info[i] = NULL;
- }
-}
-
-JoypadLinux::Joypad::~Joypad() {
-
- for (int i = 0; i < MAX_ABS; i++) {
- if (abs_info[i]) {
- memdelete(abs_info[i]);
- }
- }
-}
-
-void JoypadLinux::Joypad::reset() {
- dpad = 0;
- fd = -1;
-
- InputDefault::JoyAxis jx;
- jx.min = -1;
- jx.value = 0.0f;
- for (int i = 0; i < MAX_ABS; i++) {
- abs_map[i] = -1;
- curr_axis[i] = jx;
- }
-}
-
-JoypadLinux::JoypadLinux(InputDefault *in) {
- exit_udev = false;
- input = in;
- joy_thread = Thread::create(joy_thread_func, this);
-}
-
-JoypadLinux::~JoypadLinux() {
- exit_udev = true;
- Thread::wait_to_finish(joy_thread);
- memdelete(joy_thread);
- close_joypad();
-}
-
-void JoypadLinux::joy_thread_func(void *p_user) {
-
- if (p_user) {
- JoypadLinux *joy = (JoypadLinux *)p_user;
- joy->run_joypad_thread();
- }
-}
-
-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);
-#else
- monitor_joypads();
-#endif
-}
-
-#ifdef UDEV_ENABLED
-void JoypadLinux::enumerate_joypads(udev *p_udev) {
-
- udev_enumerate *enumerate;
- udev_list_entry *devices, *dev_list_entry;
- udev_device *dev;
-
- enumerate = udev_enumerate_new(p_udev);
- udev_enumerate_add_match_subsystem(enumerate, "input");
-
- udev_enumerate_scan_devices(enumerate);
- devices = udev_enumerate_get_list_entry(enumerate);
- udev_list_entry_foreach(dev_list_entry, devices) {
-
- const char *path = udev_list_entry_get_name(dev_list_entry);
- dev = udev_device_new_from_syspath(p_udev, path);
- const char *devnode = udev_device_get_devnode(dev);
-
- if (devnode) {
-
- String devnode_str = devnode;
- if (devnode_str.find(ignore_str) == -1) {
- MutexLock lock(joy_mutex);
- open_joypad(devnode);
- }
- }
- udev_device_unref(dev);
- }
- udev_enumerate_unref(enumerate);
-}
-
-void JoypadLinux::monitor_joypads(udev *p_udev) {
-
- udev_device *dev = NULL;
- udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev");
- udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
- udev_monitor_enable_receiving(mon);
- int fd = udev_monitor_get_fd(mon);
-
- while (!exit_udev) {
-
- fd_set fds;
- struct timeval tv;
- int ret;
-
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- ret = select(fd + 1, &fds, NULL, NULL, &tv);
-
- /* Check if our file descriptor has received data. */
- if (ret > 0 && FD_ISSET(fd, &fds)) {
- /* Make the call to receive the device.
- select() ensured that this will not block. */
- dev = udev_monitor_receive_device(mon);
-
- if (dev && udev_device_get_devnode(dev) != 0) {
-
- 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")
- open_joypad(devnode);
- else if (String(action) == "remove")
- close_joypad(get_joy_from_path(devnode));
- }
- }
-
- udev_device_unref(dev);
- }
- }
- usleep(50000);
- }
- udev_monitor_unref(mon);
-}
-#endif
-
-void JoypadLinux::monitor_joypads() {
-
- while (!exit_udev) {
- {
- MutexLock lock(joy_mutex);
-
- for (int i = 0; i < 32; i++) {
- char fname[64];
- sprintf(fname, "/dev/input/event%d", i);
- if (attached_devices.find(fname) == -1) {
- open_joypad(fname);
- }
- }
- }
- usleep(1000000); // 1s
- }
-}
-
-int JoypadLinux::get_joy_from_path(String p_path) const {
-
- for (int i = 0; i < JOYPADS_MAX; i++) {
-
- if (joypads[i].devpath == p_path) {
- return i;
- }
- }
- return -2;
-}
-
-void JoypadLinux::close_joypad(int p_id) {
- if (p_id == -1) {
- for (int i = 0; i < JOYPADS_MAX; i++) {
-
- close_joypad(i);
- };
- return;
- } else if (p_id < 0)
- return;
-
- Joypad &joy = joypads[p_id];
-
- if (joy.fd != -1) {
-
- close(joy.fd);
- joy.fd = -1;
- attached_devices.remove(attached_devices.find(joy.devpath));
- input->joy_connection_changed(p_id, false, "");
- };
-}
-
-static String _hex_str(uint8_t p_byte) {
-
- static const char *dict = "0123456789abcdef";
- char ret[3];
- ret[2] = 0;
-
- ret[0] = dict[p_byte >> 4];
- ret[1] = dict[p_byte & 0xF];
-
- return ret;
-}
-
-void JoypadLinux::setup_joypad_properties(int p_id) {
-
- Joypad *joy = &joypads[p_id];
-
- unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
- unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
-
- int num_buttons = 0;
- int num_axes = 0;
-
- if ((ioctl(joy->fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
- (ioctl(joy->fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
- return;
- }
- for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
-
- if (test_bit(i, keybit)) {
-
- joy->key_map[i] = num_buttons++;
- }
- }
- for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
-
- if (test_bit(i, keybit)) {
-
- joy->key_map[i] = num_buttons++;
- }
- }
- for (int i = 0; i < ABS_MISC; ++i) {
- /* Skip hats */
- if (i == ABS_HAT0X) {
- i = ABS_HAT3Y;
- continue;
- }
- if (test_bit(i, absbit)) {
-
- joy->abs_map[i] = num_axes++;
- joy->abs_info[i] = memnew(input_absinfo);
- if (ioctl(joy->fd, EVIOCGABS(i), joy->abs_info[i]) < 0) {
- memdelete(joy->abs_info[i]);
- joy->abs_info[i] = NULL;
- }
- }
- }
-
- joy->force_feedback = false;
- joy->ff_effect_timestamp = 0;
- unsigned long ffbit[NBITS(FF_CNT)];
- if (ioctl(joy->fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) {
- if (test_bit(FF_RUMBLE, ffbit)) {
- joy->force_feedback = true;
- }
- }
-}
-
-void JoypadLinux::open_joypad(const char *p_path) {
-
- int joy_num = input->get_unused_joy_id();
- int fd = open(p_path, O_RDWR | O_NONBLOCK);
- if (fd != -1 && joy_num != -1) {
-
- unsigned long evbit[NBITS(EV_MAX)] = { 0 };
- unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
- unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
-
- // add to attached devices so we don't try to open it again
- attached_devices.push_back(String(p_path));
-
- if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
- (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
- (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
- close(fd);
- return;
- }
-
- //check if the device supports basic gamepad events, prevents certain keyboards from
- //being detected as joypads
- if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
- (test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) ||
- test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) &&
- (test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) ||
- test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit)))) {
- close(fd);
- return;
- }
-
- char uid[128];
- char namebuf[128];
- String name = "";
- input_id inpid;
- if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) {
- name = namebuf;
- }
-
- if (ioctl(fd, EVIOCGID, &inpid) < 0) {
- close(fd);
- return;
- }
-
- joypads[joy_num].reset();
-
- Joypad &joy = joypads[joy_num];
- joy.fd = fd;
- joy.devpath = String(p_path);
- setup_joypad_properties(joy_num);
- sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0);
- if (inpid.vendor && inpid.product && inpid.version) {
-
- uint16_t vendor = BSWAP16(inpid.vendor);
- uint16_t product = BSWAP16(inpid.product);
- uint16_t version = BSWAP16(inpid.version);
-
- sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0);
- input->joy_connection_changed(joy_num, true, name, uid);
- } else {
- String uidname = uid;
- int uidlen = MIN(name.length(), 11);
- for (int i = 0; i < uidlen; i++) {
-
- uidname = uidname + _hex_str(name[i]);
- }
- uidname += "00";
- input->joy_connection_changed(joy_num, true, name, uidname);
- }
- }
-}
-
-void JoypadLinux::joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) {
- Joypad &joy = joypads[p_id];
- if (!joy.force_feedback || joy.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
- return;
- }
- if (joy.ff_effect_id != -1) {
- joypad_vibration_stop(p_id, p_timestamp);
- }
-
- struct ff_effect effect;
- effect.type = FF_RUMBLE;
- effect.id = -1;
- effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff);
- effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff);
- effect.replay.length = floor(p_duration * 1000);
- effect.replay.delay = 0;
-
- if (ioctl(joy.fd, EVIOCSFF, &effect) < 0) {
- return;
- }
-
- struct input_event play;
- play.type = EV_FF;
- play.code = effect.id;
- play.value = 1;
- if (write(joy.fd, (const void *)&play, sizeof(play)) == -1) {
- print_verbose("Couldn't write to Joypad device.");
- }
-
- joy.ff_effect_id = effect.id;
- joy.ff_effect_timestamp = p_timestamp;
-}
-
-void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) {
- Joypad &joy = joypads[p_id];
- if (!joy.force_feedback || joy.fd == -1 || joy.ff_effect_id == -1) {
- return;
- }
-
- if (ioctl(joy.fd, EVIOCRMFF, joy.ff_effect_id) < 0) {
- return;
- }
-
- joy.ff_effect_id = -1;
- joy.ff_effect_timestamp = p_timestamp;
-}
-
-InputDefault::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
-
- int min = p_abs->minimum;
- int max = p_abs->maximum;
- InputDefault::JoyAxis jx;
-
- if (min < 0) {
- jx.min = -1;
- if (p_value < 0) {
- jx.value = (float)-p_value / min;
- } else {
- jx.value = (float)p_value / max;
- }
- } else if (min == 0) {
- jx.min = 0;
- jx.value = 0.0f + (float)p_value / max;
- }
- return jx;
-}
-
-void JoypadLinux::process_joypads() {
-
- if (joy_mutex.try_lock() != OK) {
- return;
- }
- for (int i = 0; i < JOYPADS_MAX; i++) {
-
- if (joypads[i].fd == -1) continue;
-
- input_event events[32];
- Joypad *joy = &joypads[i];
-
- int len;
-
- while ((len = read(joy->fd, events, (sizeof events))) > 0) {
- len /= sizeof(events[0]);
- for (int j = 0; j < len; j++) {
-
- input_event &ev = events[j];
-
- // ev may be tainted and out of MAX_KEY range, which will cause
- // joy->key_map[ev.code] to crash
- if (ev.code >= MAX_KEY)
- return;
-
- switch (ev.type) {
- case EV_KEY:
- input->joy_button(i, joy->key_map[ev.code], ev.value);
- break;
-
- case EV_ABS:
-
- switch (ev.code) {
- case ABS_HAT0X:
- if (ev.value != 0) {
- if (ev.value < 0)
- joy->dpad |= InputDefault::HAT_MASK_LEFT;
- else
- joy->dpad |= InputDefault::HAT_MASK_RIGHT;
- } else
- joy->dpad &= ~(InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_RIGHT);
-
- input->joy_hat(i, joy->dpad);
- break;
-
- case ABS_HAT0Y:
- if (ev.value != 0) {
- if (ev.value < 0)
- joy->dpad |= InputDefault::HAT_MASK_UP;
- else
- joy->dpad |= InputDefault::HAT_MASK_DOWN;
- } else
- joy->dpad &= ~(InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_DOWN);
-
- input->joy_hat(i, joy->dpad);
- break;
-
- default:
- if (ev.code >= MAX_ABS)
- return;
- if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
- InputDefault::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
- joy->curr_axis[joy->abs_map[ev.code]] = value;
- }
- break;
- }
- break;
- }
- }
- }
- for (int j = 0; j < MAX_ABS; j++) {
- int index = joy->abs_map[j];
- if (index != -1) {
- input->joy_axis(i, index, joy->curr_axis[index]);
- }
- }
- if (len == 0 || (len < 0 && errno != EAGAIN)) {
- close_joypad(i);
- };
-
- if (joy->force_feedback) {
- uint64_t timestamp = input->get_joy_vibration_timestamp(i);
- if (timestamp > joy->ff_effect_timestamp) {
- Vector2 strength = input->get_joy_vibration_strength(i);
- float duration = input->get_joy_vibration_duration(i);
- if (strength.x == 0 && strength.y == 0) {
- joypad_vibration_stop(i, timestamp);
- } else {
- joypad_vibration_start(i, strength.x, strength.y, duration, timestamp);
- }
- }
- }
- }
- joy_mutex.unlock();
-}
-#endif
diff --git a/platform/x11/joypad_linux.h b/platform/x11/joypad_linux.h
deleted file mode 100644
index d5719b6dbe..0000000000
--- a/platform/x11/joypad_linux.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*************************************************************************/
-/* joypad_linux.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-//author: Andreas Haas <hondres, liugam3@gmail.com>
-#ifndef JOYPAD_LINUX_H
-#define JOYPAD_LINUX_H
-
-#ifdef JOYDEV_ENABLED
-#include "core/os/mutex.h"
-#include "core/os/thread.h"
-#include "main/input_default.h"
-
-struct input_absinfo;
-
-class JoypadLinux {
-public:
- JoypadLinux(InputDefault *in);
- ~JoypadLinux();
- void process_joypads();
-
-private:
- enum {
- JOYPADS_MAX = 16,
- MAX_ABS = 63,
- MAX_KEY = 767, // Hack because <linux/input.h> can't be included here
- };
-
- struct Joypad {
- InputDefault::JoyAxis curr_axis[MAX_ABS];
- int key_map[MAX_KEY];
- int abs_map[MAX_ABS];
- int dpad;
- int fd;
-
- String devpath;
- input_absinfo *abs_info[MAX_ABS];
-
- bool force_feedback;
- int ff_effect_id;
- uint64_t ff_effect_timestamp;
-
- Joypad();
- ~Joypad();
- void reset();
- };
-
- bool exit_udev;
- Mutex joy_mutex;
- Thread *joy_thread;
- InputDefault *input;
- Joypad joypads[JOYPADS_MAX];
- Vector<String> attached_devices;
-
- static void joy_thread_func(void *p_user);
-
- int get_joy_from_path(String p_path) const;
-
- void setup_joypad_properties(int p_id);
- void close_joypad(int p_id = -1);
-#ifdef UDEV_ENABLED
- void enumerate_joypads(struct udev *p_udev);
- void monitor_joypads(struct udev *p_udev);
-#endif
- void monitor_joypads();
- void run_joypad_thread();
- void open_joypad(const char *p_path);
-
- 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);
-
- InputDefault::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
-};
-
-#endif
-#endif // JOYPAD_LINUX_H
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
deleted file mode 100644
index c74981fd55..0000000000
--- a/platform/x11/os_x11.cpp
+++ /dev/null
@@ -1,3566 +0,0 @@
-/*************************************************************************/
-/* os_x11.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "os_x11.h"
-#include "detect_prime.h"
-
-#include "core/os/dir_access.h"
-#include "core/print_string.h"
-#include "errno.h"
-#include "key_mapping_x11.h"
-
-#if defined(OPENGL_ENABLED)
-#include "drivers/gles2/rasterizer_gles2.h"
-#endif
-
-#if defined(VULKAN_ENABLED)
-#include "servers/visual/rasterizer_rd/rasterizer_rd.h"
-#endif
-
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual/visual_server_wrap_mt.h"
-
-#ifdef HAVE_MNTENT
-#include <mntent.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "X11/Xutil.h"
-
-#include "X11/Xatom.h"
-#include "X11/extensions/Xinerama.h"
-// ICCCM
-#define WM_NormalState 1L // window normal state
-#define WM_IconicState 3L // window minimized
-// EWMH
-#define _NET_WM_STATE_REMOVE 0L // remove/unset property
-#define _NET_WM_STATE_ADD 1L // add/set property
-#define _NET_WM_STATE_TOGGLE 2L // toggle property
-
-#include "main/main.h"
-
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-//stupid linux.h
-#ifdef KEY_TAB
-#undef KEY_TAB
-#endif
-
-#include <X11/Xatom.h>
-
-#undef CursorShape
-
-#include <X11/XKBlib.h>
-
-// 2.2 is the first release with multitouch
-#define XINPUT_CLIENT_VERSION_MAJOR 2
-#define XINPUT_CLIENT_VERSION_MINOR 2
-
-#define VALUATOR_ABSX 0
-#define VALUATOR_ABSY 1
-#define VALUATOR_PRESSURE 2
-#define VALUATOR_TILTX 3
-#define VALUATOR_TILTY 4
-
-static const double abs_resolution_mult = 10000.0;
-static const double abs_resolution_range_mult = 10.0;
-
-void OS_X11::initialize_core() {
-
- crash_handler.initialize();
-
- OS_Unix::initialize_core();
-}
-
-int OS_X11::get_current_video_driver() const {
- return video_driver_index;
-}
-
-Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
-
- long im_event_mask = 0;
- last_button_state = 0;
-
- xmbstring = NULL;
- x11_window = 0;
- last_click_ms = 0;
- last_click_button_index = -1;
- last_click_pos = Point2(-100, -100);
- args = OS::get_singleton()->get_cmdline_args();
- current_videomode = p_desired;
- main_loop = NULL;
- last_timestamp = 0;
- last_mouse_pos_valid = false;
- last_keyrelease_time = 0;
- xdnd_version = 0;
-
- if (get_render_thread_mode() == RENDER_SEPARATE_THREAD) {
- XInitThreads();
- }
-
- /** XLIB INITIALIZATION **/
- x11_display = XOpenDisplay(NULL);
-
- if (!x11_display) {
- ERR_PRINT("X11 Display is not available");
- return ERR_UNAVAILABLE;
- }
-
- char *modifiers = NULL;
- Bool xkb_dar = False;
- XAutoRepeatOn(x11_display);
- xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL);
-
- // Try to support IME if detectable auto-repeat is supported
- if (xkb_dar == True) {
-
-#ifdef X_HAVE_UTF8_STRING
- // Xutf8LookupString will be used later instead of XmbLookupString before
- // the multibyte sequences can be converted to unicode string.
- modifiers = XSetLocaleModifiers("");
-#endif
- }
-
- if (modifiers == NULL) {
- if (is_stdout_verbose()) {
- WARN_PRINT("IME is disabled");
- }
- XSetLocaleModifiers("@im=none");
- WARN_PRINT("Error setting locale modifiers");
- }
-
- const char *err;
- xrr_get_monitors = NULL;
- xrr_free_monitors = NULL;
- int xrandr_major = 0;
- int xrandr_minor = 0;
- int event_base, error_base;
- xrandr_ext_ok = XRRQueryExtension(x11_display, &event_base, &error_base);
- xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY);
- if (!xrandr_handle) {
- err = dlerror();
- fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
- } else {
- XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
- if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
- xrr_get_monitors = (xrr_get_monitors_t)dlsym(xrandr_handle, "XRRGetMonitors");
- if (!xrr_get_monitors) {
- err = dlerror();
- fprintf(stderr, "could not find symbol XRRGetMonitors\nError: %s\n", err);
- } else {
- xrr_free_monitors = (xrr_free_monitors_t)dlsym(xrandr_handle, "XRRFreeMonitors");
- if (!xrr_free_monitors) {
- err = dlerror();
- fprintf(stderr, "could not find XRRFreeMonitors\nError: %s\n", err);
- xrr_get_monitors = NULL;
- }
- }
- }
- }
-
- if (!refresh_device_info()) {
- OS::get_singleton()->alert("Your system does not support XInput 2.\n"
- "Please upgrade your distribution.",
- "Unable to initialize XInput");
- return ERR_UNAVAILABLE;
- }
-
- xim = XOpenIM(x11_display, NULL, NULL, NULL);
-
- if (xim == NULL) {
- WARN_PRINT("XOpenIM failed");
- xim_style = 0L;
- } else {
- ::XIMCallback im_destroy_callback;
- im_destroy_callback.client_data = (::XPointer)(this);
- im_destroy_callback.callback = (::XIMProc)(xim_destroy_callback);
- if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback,
- NULL) != NULL) {
- WARN_PRINT("Error setting XIM destroy callback");
- }
-
- ::XIMStyles *xim_styles = NULL;
- xim_style = 0L;
- char *imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
- if (imvalret != NULL || xim_styles == NULL) {
- fprintf(stderr, "Input method doesn't support any styles\n");
- }
-
- if (xim_styles) {
- xim_style = 0L;
- for (int i = 0; i < xim_styles->count_styles; i++) {
-
- if (xim_styles->supported_styles[i] ==
- (XIMPreeditNothing | XIMStatusNothing)) {
-
- xim_style = xim_styles->supported_styles[i];
- break;
- }
- }
-
- XFree(xim_styles);
- }
- XFree(imvalret);
- }
-
- //!!!!!!!!!!!!!!!!!!!!!!!!!!
- //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
- video_driver_index = p_video_driver;
-#ifndef _MSC_VER
-#warning Forcing vulkan video driver because OpenGL not implemented yet
-#endif
- video_driver_index = VIDEO_DRIVER_VULKAN;
-
- print_verbose("Driver: " + String(get_video_driver_name(video_driver_index)) + " [" + itos(video_driver_index) + "]");
- //!!!!!!!!!!!!!!!!!!!!!!!!!!
-
- //Create window
-
- long visualMask = VisualScreenMask;
- int numberOfVisuals;
- XVisualInfo vInfoTemplate = {};
- vInfoTemplate.screen = DefaultScreen(x11_display);
- XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
-
- Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
-
- XSetWindowAttributes windowAttributes = {};
- windowAttributes.colormap = colormap;
- windowAttributes.background_pixel = 0xFFFFFFFF;
- windowAttributes.border_pixel = 0;
- windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
-
- unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
- x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
-
- //set_class_hint(x11_display, x11_window);
- XMapWindow(x11_display, x11_window);
- XFlush(x11_display);
-
- XSync(x11_display, False);
- //XSetErrorHandler(oldHandler);
-
- XFree(visualInfo);
-
- // Init context and rendering device
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- if (getenv("DRI_PRIME") == NULL) {
- int use_prime = -1;
-
- if (getenv("PRIMUS_DISPLAY") ||
- getenv("PRIMUS_libGLd") ||
- getenv("PRIMUS_libGLa") ||
- getenv("PRIMUS_libGL") ||
- getenv("PRIMUS_LOAD_GLOBAL") ||
- getenv("BUMBLEBEE_SOCKET")) {
-
- print_verbose("Optirun/primusrun detected. Skipping GPU detection");
- use_prime = 0;
- }
-
- if (getenv("LD_LIBRARY_PATH")) {
- String ld_library_path(getenv("LD_LIBRARY_PATH"));
- Vector<String> libraries = ld_library_path.split(":");
-
- for (int i = 0; i < libraries.size(); ++i) {
- if (FileAccess::exists(libraries[i] + "/libGL.so.1") ||
- FileAccess::exists(libraries[i] + "/libGL.so")) {
-
- print_verbose("Custom libGL override detected. Skipping GPU detection");
- use_prime = 0;
- }
- }
- }
-
- if (use_prime == -1) {
- print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic.");
- use_prime = detect_prime();
- }
-
- if (use_prime) {
- print_line("Found discrete GPU, setting DRI_PRIME=1 to use it.");
- print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU.");
- setenv("DRI_PRIME", "1", 1);
- }
- }
-
- ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
-
- context_gles2 = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type));
-
- if (context_gles2->initialize() != OK) {
- memdelete(context_gles2);
- context_gles2 = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
-
- context_gles2->set_use_vsync(current_videomode.use_vsync);
-
- if (RasterizerGLES2::is_viable() == OK) {
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- } else {
- memdelete(context_gles2);
- context_gles2 = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
-
- context_vulkan = memnew(VulkanContextX11);
- if (context_vulkan->initialize() != OK) {
- memdelete(context_vulkan);
- context_vulkan = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
- if (context_vulkan->window_create(x11_window, x11_display, get_video_mode().width, get_video_mode().height) == -1) {
- memdelete(context_vulkan);
- context_vulkan = NULL;
- ERR_FAIL_V(ERR_UNAVAILABLE);
- }
-
- //temporary
- rendering_device_vulkan = memnew(RenderingDeviceVulkan);
- rendering_device_vulkan->initialize(context_vulkan);
-
- RasterizerRD::make_current();
- }
-#endif
-
- visual_server = memnew(VisualServerRaster);
- if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
- }
-
- if (current_videomode.maximized) {
- current_videomode.maximized = false;
- set_window_maximized(true);
- // borderless fullscreen window mode
- } else if (current_videomode.fullscreen) {
- current_videomode.fullscreen = false;
- set_window_fullscreen(true);
- } else if (current_videomode.borderless_window) {
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = 0;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
- }
-
- // make PID known to X11
- {
- const long pid = this->get_process_id();
- Atom net_wm_pid = XInternAtom(x11_display, "_NET_WM_PID", False);
- XChangeProperty(x11_display, x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
- }
-
- // disable resizable window
- if (!current_videomode.resizable && !current_videomode.fullscreen) {
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- xsh->flags = PMinSize | PMaxSize;
- XWindowAttributes xwa;
- if (current_videomode.fullscreen) {
- XGetWindowAttributes(x11_display, DefaultRootWindow(x11_display), &xwa);
- } else {
- XGetWindowAttributes(x11_display, x11_window, &xwa);
- }
- xsh->min_width = xwa.width;
- xsh->max_width = xwa.width;
- xsh->min_height = xwa.height;
- xsh->max_height = xwa.height;
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
- }
-
- if (current_videomode.always_on_top) {
- current_videomode.always_on_top = false;
- set_window_always_on_top(true);
- }
-
- ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
- ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE);
-
- XSetWindowAttributes new_attr;
-
- new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
- ButtonReleaseMask | EnterWindowMask |
- LeaveWindowMask | PointerMotionMask |
- Button1MotionMask |
- Button2MotionMask | Button3MotionMask |
- Button4MotionMask | Button5MotionMask |
- ButtonMotionMask | KeymapStateMask |
- ExposureMask | VisibilityChangeMask |
- StructureNotifyMask |
- SubstructureNotifyMask | SubstructureRedirectMask |
- FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask |
- im_event_mask;
-
- XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
-
- static unsigned char all_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
- static unsigned char all_master_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
-
- xi.all_event_mask.deviceid = XIAllDevices;
- xi.all_event_mask.mask_len = sizeof(all_mask_data);
- xi.all_event_mask.mask = all_mask_data;
-
- xi.all_master_event_mask.deviceid = XIAllMasterDevices;
- xi.all_master_event_mask.mask_len = sizeof(all_master_mask_data);
- xi.all_master_event_mask.mask = all_master_mask_data;
-
- XISetMask(xi.all_event_mask.mask, XI_HierarchyChanged);
- XISetMask(xi.all_master_event_mask.mask, XI_DeviceChanged);
- XISetMask(xi.all_master_event_mask.mask, XI_RawMotion);
-
-#ifdef TOUCH_ENABLED
- if (xi.touch_devices.size()) {
- XISetMask(xi.all_event_mask.mask, XI_TouchBegin);
- XISetMask(xi.all_event_mask.mask, XI_TouchUpdate);
- XISetMask(xi.all_event_mask.mask, XI_TouchEnd);
- XISetMask(xi.all_event_mask.mask, XI_TouchOwnership);
- }
-#endif
-
- XISelectEvents(x11_display, x11_window, &xi.all_event_mask, 1);
- XISelectEvents(x11_display, DefaultRootWindow(x11_display), &xi.all_master_event_mask, 1);
-
- // Disabled by now since grabbing also blocks mouse events
- // (they are received as extended events instead of standard events)
- /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership);
-
- // Grab touch devices to avoid OS gesture interference
- for (int i = 0; i < xi.touch_devices.size(); ++i) {
- XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
- }*/
-
- /* set the titlebar name */
- XStoreName(x11_display, x11_window, "Godot");
-
- wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
- XSetWMProtocols(x11_display, x11_window, &wm_delete, 1);
-
- im_active = false;
- im_position = Vector2();
-
- if (xim && xim_style) {
-
- xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, x11_window, XNFocusWindow, x11_window, (char *)NULL);
- if (XGetICValues(xic, XNFilterEvents, &im_event_mask, NULL) != NULL) {
- WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
- XDestroyIC(xic);
- xic = NULL;
- }
- if (xic) {
- XUnsetICFocus(xic);
- } else {
- WARN_PRINT("XCreateIC couldn't create xic");
- }
- } else {
-
- xic = NULL;
- WARN_PRINT("XCreateIC couldn't create xic");
- }
-
- cursor_size = XcursorGetDefaultSize(x11_display);
- cursor_theme = XcursorGetTheme(x11_display);
-
- if (!cursor_theme) {
- print_verbose("XcursorGetTheme could not get cursor theme");
- cursor_theme = "default";
- }
-
- for (int i = 0; i < CURSOR_MAX; i++) {
-
- cursors[i] = None;
- img[i] = NULL;
- }
-
- current_cursor = CURSOR_ARROW;
-
- for (int i = 0; i < CURSOR_MAX; i++) {
-
- static const char *cursor_file[] = {
- "left_ptr",
- "xterm",
- "hand2",
- "cross",
- "watch",
- "left_ptr_watch",
- "fleur",
- "dnd-move",
- "crossed_circle",
- "v_double_arrow",
- "h_double_arrow",
- "size_bdiag",
- "size_fdiag",
- "move",
- "row_resize",
- "col_resize",
- "question_arrow"
- };
-
- img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size);
- if (!img[i]) {
- const char *fallback = NULL;
-
- switch (i) {
- case CURSOR_POINTING_HAND:
- fallback = "pointer";
- break;
- case CURSOR_CROSS:
- fallback = "crosshair";
- break;
- case CURSOR_WAIT:
- fallback = "wait";
- break;
- case CURSOR_BUSY:
- fallback = "progress";
- break;
- case CURSOR_DRAG:
- fallback = "grabbing";
- break;
- case CURSOR_CAN_DROP:
- fallback = "hand1";
- break;
- case CURSOR_FORBIDDEN:
- fallback = "forbidden";
- break;
- case CURSOR_VSIZE:
- fallback = "ns-resize";
- break;
- case CURSOR_HSIZE:
- fallback = "ew-resize";
- break;
- case CURSOR_BDIAGSIZE:
- fallback = "fd_double_arrow";
- break;
- case CURSOR_FDIAGSIZE:
- fallback = "bd_double_arrow";
- break;
- case CURSOR_MOVE:
- img[i] = img[CURSOR_DRAG];
- break;
- case CURSOR_VSPLIT:
- fallback = "sb_v_double_arrow";
- break;
- case CURSOR_HSPLIT:
- fallback = "sb_h_double_arrow";
- break;
- case CURSOR_HELP:
- fallback = "help";
- break;
- }
- if (fallback != NULL) {
- img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size);
- }
- }
- if (img[i]) {
- cursors[i] = XcursorImageLoadCursor(x11_display, img[i]);
- } else {
- print_verbose("Failed loading custom cursor: " + String(cursor_file[i]));
- }
- }
-
- {
- // Creating an empty/transparent cursor
-
- // Create 1x1 bitmap
- Pixmap cursormask = XCreatePixmap(x11_display,
- RootWindow(x11_display, DefaultScreen(x11_display)), 1, 1, 1);
-
- // Fill with zero
- XGCValues xgc;
- xgc.function = GXclear;
- GC gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
- XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
-
- // Color value doesn't matter. Mask zero means no foreground or background will be drawn
- XColor col = {};
-
- Cursor cursor = XCreatePixmapCursor(x11_display,
- cursormask, // source (using cursor mask as placeholder, since it'll all be ignored)
- cursormask, // mask
- &col, &col, 0, 0);
-
- XFreePixmap(x11_display, cursormask);
- XFreeGC(x11_display, gc);
-
- if (cursor == None) {
- ERR_PRINT("FAILED CREATING CURSOR");
- }
-
- null_cursor = cursor;
- }
- set_cursor_shape(CURSOR_BUSY);
-
- //Set Xdnd (drag & drop) support
- Atom XdndAware = XInternAtom(x11_display, "XdndAware", False);
- Atom version = 5;
- XChangeProperty(x11_display, x11_window, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&version, 1);
-
- xdnd_enter = XInternAtom(x11_display, "XdndEnter", False);
- xdnd_position = XInternAtom(x11_display, "XdndPosition", False);
- xdnd_status = XInternAtom(x11_display, "XdndStatus", False);
- xdnd_action_copy = XInternAtom(x11_display, "XdndActionCopy", False);
- xdnd_drop = XInternAtom(x11_display, "XdndDrop", False);
- xdnd_finished = XInternAtom(x11_display, "XdndFinished", False);
- xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
- requested = None;
-
- visual_server->init();
-
- AudioDriverManager::initialize(p_audio_driver);
-
- input = memnew(InputDefault);
-
- window_has_focus = true; // Set focus to true at init
-#ifdef JOYDEV_ENABLED
- joypad = memnew(JoypadLinux(input));
-#endif
- _ensure_user_data_dir();
-
- if (p_desired.layered) {
- set_window_per_pixel_transparency_enabled(true);
- }
-
- XEvent xevent;
- while (XPending(x11_display) > 0) {
- XNextEvent(x11_display, &xevent);
- if (xevent.type == ConfigureNotify) {
- _window_changed(&xevent);
- }
- }
-
- update_real_mouse_position();
-
- return OK;
-}
-
-bool OS_X11::refresh_device_info() {
- int event_base, error_base;
-
- print_verbose("XInput: Refreshing devices.");
-
- if (!XQueryExtension(x11_display, "XInputExtension", &xi.opcode, &event_base, &error_base)) {
- print_verbose("XInput extension not available. Please upgrade your distribution.");
- return false;
- }
-
- int xi_major_query = XINPUT_CLIENT_VERSION_MAJOR;
- int xi_minor_query = XINPUT_CLIENT_VERSION_MINOR;
-
- if (XIQueryVersion(x11_display, &xi_major_query, &xi_minor_query) != Success) {
- print_verbose(vformat("XInput 2 not available (server supports %d.%d).", xi_major_query, xi_minor_query));
- xi.opcode = 0;
- return false;
- }
-
- if (xi_major_query < XINPUT_CLIENT_VERSION_MAJOR || (xi_major_query == XINPUT_CLIENT_VERSION_MAJOR && xi_minor_query < XINPUT_CLIENT_VERSION_MINOR)) {
- print_verbose(vformat("XInput %d.%d not available (server supports %d.%d). Touch input unavailable.",
- XINPUT_CLIENT_VERSION_MAJOR, XINPUT_CLIENT_VERSION_MINOR, xi_major_query, xi_minor_query));
- }
-
- xi.absolute_devices.clear();
- xi.touch_devices.clear();
-
- int dev_count;
- XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
-
- for (int i = 0; i < dev_count; i++) {
- XIDeviceInfo *dev = &info[i];
- if (!dev->enabled)
- continue;
- if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave))
- continue;
-
- bool direct_touch = false;
- bool absolute_mode = false;
- int resolution_x = 0;
- int resolution_y = 0;
- int range_min_x = 0;
- int range_min_y = 0;
- int range_max_x = 0;
- int range_max_y = 0;
- int pressure_resolution = 0;
- int tilt_resolution_x = 0;
- int tilt_resolution_y = 0;
- for (int j = 0; j < dev->num_classes; j++) {
-#ifdef TOUCH_ENABLED
- if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
- direct_touch = true;
- }
-#endif
- if (dev->classes[j]->type == XIValuatorClass) {
- XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j];
-
- if (class_info->number == VALUATOR_ABSX && class_info->mode == XIModeAbsolute) {
- resolution_x = class_info->resolution;
- range_min_x = class_info->min;
- range_max_x = class_info->max;
- absolute_mode = true;
- } else if (class_info->number == VALUATOR_ABSY && class_info->mode == XIModeAbsolute) {
- resolution_y = class_info->resolution;
- range_min_y = class_info->min;
- range_max_y = class_info->max;
- absolute_mode = true;
- } else if (class_info->number == VALUATOR_PRESSURE && class_info->mode == XIModeAbsolute) {
- pressure_resolution = (class_info->max - class_info->min);
- if (pressure_resolution == 0) pressure_resolution = 1;
- } else if (class_info->number == VALUATOR_TILTX && class_info->mode == XIModeAbsolute) {
- tilt_resolution_x = (class_info->max - class_info->min);
- if (tilt_resolution_x == 0) tilt_resolution_x = 1;
- } else if (class_info->number == VALUATOR_TILTY && class_info->mode == XIModeAbsolute) {
- tilt_resolution_y = (class_info->max - class_info->min);
- if (tilt_resolution_y == 0) tilt_resolution_y = 1;
- }
- }
- }
- if (direct_touch) {
- xi.touch_devices.push_back(dev->deviceid);
- print_verbose("XInput: Using touch device: " + String(dev->name));
- }
- if (absolute_mode) {
- // If no resolution was reported, use the min/max ranges.
- if (resolution_x <= 0) {
- resolution_x = (range_max_x - range_min_x) * abs_resolution_range_mult;
- }
- if (resolution_y <= 0) {
- resolution_y = (range_max_y - range_min_y) * abs_resolution_range_mult;
- }
-
- xi.absolute_devices[dev->deviceid] = Vector2(abs_resolution_mult / resolution_x, abs_resolution_mult / resolution_y);
- print_verbose("XInput: Absolute pointing device: " + String(dev->name));
- }
-
- xi.pressure = 0;
- xi.pen_devices[dev->deviceid] = Vector3(pressure_resolution, tilt_resolution_x, tilt_resolution_y);
- }
-
- XIFreeDeviceInfo(info);
-#ifdef TOUCH_ENABLED
- if (!xi.touch_devices.size()) {
- print_verbose("XInput: No touch devices found.");
- }
-#endif
-
- return true;
-}
-
-void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
- ::XPointer call_data) {
-
- WARN_PRINT("Input method stopped");
- OS_X11 *os = reinterpret_cast<OS_X11 *>(client_data);
- os->xim = NULL;
- os->xic = NULL;
-}
-
-void OS_X11::set_ime_active(const bool p_active) {
-
- im_active = p_active;
-
- if (!xic)
- return;
-
- if (p_active) {
- XSetICFocus(xic);
- set_ime_position(im_position);
- } else {
- XUnsetICFocus(xic);
- }
-}
-
-void OS_X11::set_ime_position(const Point2 &p_pos) {
-
- im_position = p_pos;
-
- if (!xic)
- return;
-
- ::XPoint spot;
- spot.x = short(p_pos.x);
- spot.y = short(p_pos.y);
- XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
- XSetICValues(xic, XNPreeditAttributes, preedit_attr, NULL);
- XFree(preedit_attr);
-}
-
-String OS_X11::get_unique_id() const {
-
- static String machine_id;
- if (machine_id.empty()) {
- if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) {
- while (machine_id.empty() && !f->eof_reached()) {
- machine_id = f->get_line().strip_edges();
- }
- f->close();
- memdelete(f);
- }
- }
- return machine_id;
-}
-
-void OS_X11::finalize() {
-
- if (main_loop)
- memdelete(main_loop);
- main_loop = NULL;
-
- /*
- if (debugger_connection_console) {
- memdelete(debugger_connection_console);
- }
- */
-#ifdef ALSAMIDI_ENABLED
- driver_alsamidi.close();
-#endif
-
-#ifdef JOYDEV_ENABLED
- memdelete(joypad);
-#endif
-
- xi.touch_devices.clear();
- xi.state.clear();
-
- memdelete(input);
-
- cursors_cache.clear();
- visual_server->finish();
- memdelete(visual_server);
-
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
-
- if (context_gles2)
- memdelete(context_gles2);
- }
-#endif
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
-
- if (rendering_device_vulkan) {
- rendering_device_vulkan->finalize();
- memdelete(rendering_device_vulkan);
- }
-
- if (context_vulkan)
- memdelete(context_vulkan);
- }
-#endif
-
- if (xrandr_handle)
- dlclose(xrandr_handle);
-
- XUnmapWindow(x11_display, x11_window);
- XDestroyWindow(x11_display, x11_window);
-
- for (int i = 0; i < CURSOR_MAX; i++) {
- if (cursors[i] != None)
- XFreeCursor(x11_display, cursors[i]);
- if (img[i] != NULL)
- XcursorImageDestroy(img[i]);
- };
-
- if (xic) {
- XDestroyIC(xic);
- }
- if (xim) {
- XCloseIM(xim);
- }
-
- XCloseDisplay(x11_display);
- if (xmbstring)
- memfree(xmbstring);
-
- args.clear();
-}
-
-void OS_X11::set_mouse_mode(MouseMode p_mode) {
-
- if (p_mode == mouse_mode)
- return;
-
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED)
- XUngrabPointer(x11_display, CurrentTime);
-
- // The only modes that show a cursor are VISIBLE and CONFINED
- bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
-
- if (showCursor) {
- XDefineCursor(x11_display, x11_window, cursors[current_cursor]); // show cursor
- } else {
- XDefineCursor(x11_display, x11_window, null_cursor); // hide cursor
- }
-
- mouse_mode = p_mode;
-
- if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
-
- //flush pending motion events
- flush_mouse_motion();
-
- if (XGrabPointer(
- x11_display, x11_window, True,
- ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
- GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime) != GrabSuccess) {
- ERR_PRINT("NO GRAB");
- }
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- center.x = current_videomode.width / 2;
- center.y = current_videomode.height / 2;
-
- XWarpPointer(x11_display, None, x11_window,
- 0, 0, 0, 0, (int)center.x, (int)center.y);
-
- input->set_mouse_position(center);
- }
- } else {
- do_mouse_warp = false;
- }
-
- XFlush(x11_display);
-}
-
-void OS_X11::warp_mouse_position(const Point2 &p_to) {
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
-
- last_mouse_pos = p_to;
- } else {
-
- /*XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, x11_window, &xwa);
- printf("%d %d\n", xwa.x, xwa.y); needed? */
-
- XWarpPointer(x11_display, None, x11_window,
- 0, 0, 0, 0, (int)p_to.x, (int)p_to.y);
- }
-}
-
-void OS_X11::flush_mouse_motion() {
- while (true) {
- if (XPending(x11_display) > 0) {
- XEvent event;
- XPeekEvent(x11_display, &event);
-
- if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
- XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
-
- if (event_data->evtype == XI_RawMotion) {
- XNextEvent(x11_display, &event);
- } else {
- break;
- }
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- xi.relative_motion.x = 0;
- xi.relative_motion.y = 0;
-}
-
-OS::MouseMode OS_X11::get_mouse_mode() const {
- return mouse_mode;
-}
-
-int OS_X11::get_mouse_button_state() const {
- return last_button_state;
-}
-
-Point2 OS_X11::get_mouse_position() const {
- return last_mouse_pos;
-}
-
-bool OS_X11::get_window_per_pixel_transparency_enabled() const {
-
- if (!is_layered_allowed()) return false;
- return layered_window;
-}
-
-void OS_X11::set_window_per_pixel_transparency_enabled(bool p_enabled) {
-
- if (!is_layered_allowed()) return;
- if (layered_window != p_enabled) {
- if (p_enabled) {
- set_borderless_window(true);
- layered_window = true;
- } else {
- layered_window = false;
- }
- }
-}
-
-void OS_X11::set_window_title(const String &p_title) {
- XStoreName(x11_display, x11_window, p_title.utf8().get_data());
-
- Atom _net_wm_name = XInternAtom(x11_display, "_NET_WM_NAME", false);
- Atom utf8_string = XInternAtom(x11_display, "UTF8_STRING", false);
- XChangeProperty(x11_display, x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
-}
-
-void OS_X11::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
-}
-
-OS::VideoMode OS_X11::get_video_mode(int p_screen) const {
- return current_videomode;
-}
-
-void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
-}
-
-void OS_X11::set_wm_fullscreen(bool p_enabled) {
- if (p_enabled && !get_borderless_window()) {
- // remove decorations if the window is not already borderless
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = 0;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
- }
-
- if (p_enabled && !is_window_resizable()) {
- // Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
- XSizeHints *xsh;
-
- xsh = XAllocSizeHints();
- xsh->flags = 0L;
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
- }
-
- // Using EWMH -- Extended Window Manager Hints
- XEvent xev;
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
- xev.xclient.data.l[1] = wm_fullscreen;
- xev.xclient.data.l[2] = 0;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- // set bypass compositor hint
- Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
- unsigned long compositing_disable_on = p_enabled ? 1 : 0;
- XChangeProperty(x11_display, x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
-
- XFlush(x11_display);
-
- if (!p_enabled) {
- // Reset the non-resizable flags if we un-set these before.
- Size2 size = get_window_size();
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- if (!is_window_resizable()) {
- xsh->flags = PMinSize | PMaxSize;
- xsh->min_width = size.x;
- xsh->max_width = size.x;
- xsh->min_height = size.y;
- xsh->max_height = size.y;
- } else {
- xsh->flags = 0L;
- if (min_size != Size2()) {
- xsh->flags |= PMinSize;
- xsh->min_width = min_size.x;
- xsh->min_height = min_size.y;
- }
- if (max_size != Size2()) {
- xsh->flags |= PMaxSize;
- xsh->max_width = max_size.x;
- xsh->max_height = max_size.y;
- }
- }
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
-
- // put back or remove decorations according to the last set borderless state
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = current_videomode.borderless_window ? 0 : 1;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
- }
-}
-
-void OS_X11::set_wm_above(bool p_enabled) {
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
-
- XClientMessageEvent xev;
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.window = x11_window;
- xev.message_type = wm_state;
- xev.format = 32;
- xev.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
- xev.data.l[1] = wm_above;
- xev.data.l[3] = 1;
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
-}
-
-int OS_X11::get_screen_count() const {
- // Using Xinerama Extension
- int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) return 0;
-
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
- XFree(xsi);
- return count;
-}
-
-int OS_X11::get_current_screen() const {
- int x, y;
- Window child;
- XTranslateCoordinates(x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
-
- int count = get_screen_count();
- for (int i = 0; i < count; i++) {
- Point2i pos = get_screen_position(i);
- Size2i size = get_screen_size(i);
- if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height))
- return i;
- }
- return 0;
-}
-
-void OS_X11::set_current_screen(int p_screen) {
- int count = get_screen_count();
- if (p_screen >= count) return;
-
- if (current_videomode.fullscreen) {
- Point2i position = get_screen_position(p_screen);
- Size2i size = get_screen_size(p_screen);
-
- XMoveResizeWindow(x11_display, x11_window, position.x, position.y, size.x, size.y);
- } else {
- if (p_screen != get_current_screen()) {
- Point2i position = get_screen_position(p_screen);
- XMoveWindow(x11_display, x11_window, position.x, position.y);
- }
- }
-}
-
-Point2 OS_X11::get_screen_position(int p_screen) const {
- if (p_screen == -1) {
- p_screen = get_current_screen();
- }
-
- // Using Xinerama Extension
- int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) {
- return Point2i(0, 0);
- }
-
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
- if (p_screen >= count) {
- return Point2i(0, 0);
- }
-
- Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
-
- XFree(xsi);
-
- return position;
-}
-
-Size2 OS_X11::get_screen_size(int p_screen) const {
- if (p_screen == -1) {
- p_screen = get_current_screen();
- }
-
- // Using Xinerama Extension
- int event_base, error_base;
- const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if (!ext_okay) return Size2i(0, 0);
-
- int count;
- XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
- if (p_screen >= count) return Size2i(0, 0);
-
- Size2i size = Point2i(xsi[p_screen].width, xsi[p_screen].height);
- XFree(xsi);
- return size;
-}
-
-int OS_X11::get_screen_dpi(int p_screen) const {
- if (p_screen == -1) {
- p_screen = get_current_screen();
- }
-
- //invalid screen?
- ERR_FAIL_INDEX_V(p_screen, get_screen_count(), 0);
-
- //Get physical monitor Dimensions through XRandR and calculate dpi
- Size2 sc = get_screen_size(p_screen);
- if (xrandr_ext_ok) {
- int count = 0;
- if (xrr_get_monitors) {
- xrr_monitor_info *monitors = xrr_get_monitors(x11_display, x11_window, true, &count);
- if (p_screen < count) {
- double xdpi = sc.width / (double)monitors[p_screen].mwidth * 25.4;
- double ydpi = sc.height / (double)monitors[p_screen].mheight * 25.4;
- xrr_free_monitors(monitors);
- return (xdpi + ydpi) / 2;
- }
- xrr_free_monitors(monitors);
- } else if (p_screen == 0) {
- XRRScreenSize *sizes = XRRSizes(x11_display, 0, &count);
- if (sizes) {
- double xdpi = sc.width / (double)sizes[0].mwidth * 25.4;
- double ydpi = sc.height / (double)sizes[0].mheight * 25.4;
- return (xdpi + ydpi) / 2;
- }
- }
- }
-
- int width_mm = DisplayWidthMM(x11_display, p_screen);
- int height_mm = DisplayHeightMM(x11_display, p_screen);
- double xdpi = (width_mm ? sc.width / (double)width_mm * 25.4 : 0);
- double ydpi = (height_mm ? sc.height / (double)height_mm * 25.4 : 0);
- if (xdpi || ydpi)
- return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1);
-
- //could not get dpi
- return 96;
-}
-
-Point2 OS_X11::get_window_position() const {
- int x, y;
- Window child;
- XTranslateCoordinates(x11_display, x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
- return Point2i(x, y);
-}
-
-void OS_X11::set_window_position(const Point2 &p_position) {
- int x = 0;
- int y = 0;
- if (!get_borderless_window()) {
- //exclude window decorations
- XSync(x11_display, False);
- Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
- if (prop != None) {
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = NULL;
- if (XGetWindowProperty(x11_display, x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
- if (format == 32 && len == 4) {
- long *extents = (long *)data;
- x = extents[0];
- y = extents[2];
- }
- XFree(data);
- }
- }
- }
- XMoveWindow(x11_display, x11_window, p_position.x - x, p_position.y - y);
- update_real_mouse_position();
-}
-
-Size2 OS_X11::get_window_size() const {
- // Use current_videomode width and height instead of XGetWindowAttributes
- // since right after a XResizeWindow the attributes may not be updated yet
- return Size2i(current_videomode.width, current_videomode.height);
-}
-
-Size2 OS_X11::get_real_window_size() const {
- XWindowAttributes xwa;
- XSync(x11_display, False);
- XGetWindowAttributes(x11_display, x11_window, &xwa);
- int w = xwa.width;
- int h = xwa.height;
- Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
- if (prop != None) {
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = NULL;
- if (XGetWindowProperty(x11_display, x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
- if (format == 32 && len == 4) {
- long *extents = (long *)data;
- w += extents[0] + extents[1]; // left, right
- h += extents[2] + extents[3]; // top, bottom
- }
- XFree(data);
- }
- }
- return Size2(w, h);
-}
-
-Size2 OS_X11::get_max_window_size() const {
- return max_size;
-}
-
-Size2 OS_X11::get_min_window_size() const {
- return min_size;
-}
-
-void OS_X11::set_min_window_size(const Size2 p_size) {
-
- if ((p_size != Size2()) && (max_size != Size2()) && ((p_size.x > max_size.x) || (p_size.y > max_size.y))) {
- ERR_PRINT("Minimum window size can't be larger than maximum window size!");
- return;
- }
- min_size = p_size;
-
- if (is_window_resizable()) {
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- xsh->flags = 0L;
- if (min_size != Size2()) {
- xsh->flags |= PMinSize;
- xsh->min_width = min_size.x;
- xsh->min_height = min_size.y;
- }
- if (max_size != Size2()) {
- xsh->flags |= PMaxSize;
- xsh->max_width = max_size.x;
- xsh->max_height = max_size.y;
- }
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
-
- XFlush(x11_display);
- }
-}
-
-void OS_X11::set_max_window_size(const Size2 p_size) {
-
- if ((p_size != Size2()) && ((p_size.x < min_size.x) || (p_size.y < min_size.y))) {
- ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
- return;
- }
- max_size = p_size;
-
- if (is_window_resizable()) {
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- xsh->flags = 0L;
- if (min_size != Size2()) {
- xsh->flags |= PMinSize;
- xsh->min_width = min_size.x;
- xsh->min_height = min_size.y;
- }
- if (max_size != Size2()) {
- xsh->flags |= PMaxSize;
- xsh->max_width = max_size.x;
- xsh->max_height = max_size.y;
- }
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
-
- XFlush(x11_display);
- }
-}
-
-void OS_X11::set_window_size(const Size2 p_size) {
-
- if (current_videomode.width == p_size.width && current_videomode.height == p_size.height)
- return;
-
- XWindowAttributes xwa;
- XSync(x11_display, False);
- XGetWindowAttributes(x11_display, x11_window, &xwa);
- int old_w = xwa.width;
- int old_h = xwa.height;
-
- // If window resizable is disabled we need to update the attributes first
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- if (!is_window_resizable()) {
- xsh->flags = PMinSize | PMaxSize;
- xsh->min_width = p_size.x;
- xsh->max_width = p_size.x;
- xsh->min_height = p_size.y;
- xsh->max_height = p_size.y;
- } else {
- xsh->flags = 0L;
- if (min_size != Size2()) {
- xsh->flags |= PMinSize;
- xsh->min_width = min_size.x;
- xsh->min_height = min_size.y;
- }
- if (max_size != Size2()) {
- xsh->flags |= PMaxSize;
- xsh->max_width = max_size.x;
- xsh->max_height = max_size.y;
- }
- }
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
-
- // Resize the window
- XResizeWindow(x11_display, x11_window, p_size.x, p_size.y);
-
- // Update our videomode width and height
- current_videomode.width = p_size.x;
- current_videomode.height = p_size.y;
-
- for (int timeout = 0; timeout < 50; ++timeout) {
- XSync(x11_display, False);
- XGetWindowAttributes(x11_display, x11_window, &xwa);
-
- if (old_w != xwa.width || old_h != xwa.height)
- break;
-
- usleep(10000);
- }
-}
-
-void OS_X11::set_window_fullscreen(bool p_enabled) {
-
- if (current_videomode.fullscreen == p_enabled)
- return;
-
- if (layered_window)
- set_window_per_pixel_transparency_enabled(false);
-
- if (p_enabled && current_videomode.always_on_top) {
- // Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
- set_window_maximized(true);
- }
- set_wm_fullscreen(p_enabled);
- if (!p_enabled && current_videomode.always_on_top) {
- // Restore
- set_window_maximized(false);
- }
- if (!p_enabled) {
- set_window_position(last_position_before_fs);
- } else {
- last_position_before_fs = get_window_position();
- }
- current_videomode.fullscreen = p_enabled;
-}
-
-bool OS_X11::is_window_fullscreen() const {
- return current_videomode.fullscreen;
-}
-
-void OS_X11::set_window_resizable(bool p_enabled) {
-
- XSizeHints *xsh;
- xsh = XAllocSizeHints();
- if (!p_enabled) {
- Size2 size = get_window_size();
-
- xsh->flags = PMinSize | PMaxSize;
- xsh->min_width = size.x;
- xsh->max_width = size.x;
- xsh->min_height = size.y;
- xsh->max_height = size.y;
- } else {
- xsh->flags = 0L;
- if (min_size != Size2()) {
- xsh->flags |= PMinSize;
- xsh->min_width = min_size.x;
- xsh->min_height = min_size.y;
- }
- if (max_size != Size2()) {
- xsh->flags |= PMaxSize;
- xsh->max_width = max_size.x;
- xsh->max_height = max_size.y;
- }
- }
-
- XSetWMNormalHints(x11_display, x11_window, xsh);
- XFree(xsh);
-
- current_videomode.resizable = p_enabled;
-
- XFlush(x11_display);
-}
-
-bool OS_X11::is_window_resizable() const {
- return current_videomode.resizable;
-}
-
-void OS_X11::set_window_minimized(bool p_enabled) {
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-}
-
-bool OS_X11::is_window_minimized() const {
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- Atom property = XInternAtom(x11_display, "WM_STATE", True);
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = NULL;
-
- int result = XGetWindowProperty(
- x11_display,
- x11_window,
- property,
- 0,
- 32,
- False,
- AnyPropertyType,
- &type,
- &format,
- &len,
- &remaining,
- &data);
-
- if (result == Success) {
- long *state = (long *)data;
- if (state[0] == WM_IconicState)
- return true;
- }
- return false;
-}
-
-void OS_X11::set_window_maximized(bool p_enabled) {
- if (is_window_maximized() == p_enabled)
- return;
-
- // Using EWMH -- Extended Window Manager Hints
- XEvent xev;
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
- Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
- xev.xclient.data.l[1] = wm_max_horz;
- xev.xclient.data.l[2] = wm_max_vert;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- if (p_enabled && is_window_maximize_allowed()) {
- // Wait for effective resizing (so the GLX context is too).
- // Give up after 0.5s, it's not going to happen on this WM.
- // https://github.com/godotengine/godot/issues/19978
- for (int attempt = 0; !is_window_maximized() && attempt < 50; attempt++) {
- usleep(10000);
- }
- }
-
- maximized = p_enabled;
-}
-
-bool OS_X11::is_window_maximize_allowed() {
- Atom property = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False);
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = NULL;
-
- int result = XGetWindowProperty(
- x11_display,
- x11_window,
- property,
- 0,
- 1024,
- False,
- XA_ATOM,
- &type,
- &format,
- &len,
- &remaining,
- &data);
-
- if (result == Success) {
- Atom *atoms = (Atom *)data;
- Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
- Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
- bool found_wm_act_max_horz = false;
- bool found_wm_act_max_vert = false;
-
- for (uint64_t i = 0; i < len; i++) {
- if (atoms[i] == wm_act_max_horz)
- found_wm_act_max_horz = true;
- if (atoms[i] == wm_act_max_vert)
- found_wm_act_max_vert = true;
-
- if (found_wm_act_max_horz || found_wm_act_max_vert)
- return true;
- }
- XFree(atoms);
- }
-
- return false;
-}
-
-bool OS_X11::is_window_maximized() const {
- // Using EWMH -- Extended Window Manager Hints
- Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = NULL;
- bool retval = false;
-
- int result = XGetWindowProperty(
- x11_display,
- x11_window,
- property,
- 0,
- 1024,
- False,
- XA_ATOM,
- &type,
- &format,
- &len,
- &remaining,
- &data);
-
- if (result == Success) {
- Atom *atoms = (Atom *)data;
- Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
- Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
- bool found_wm_max_horz = false;
- bool found_wm_max_vert = false;
-
- for (uint64_t i = 0; i < len; i++) {
- if (atoms[i] == wm_max_horz)
- found_wm_max_horz = true;
- if (atoms[i] == wm_max_vert)
- found_wm_max_vert = true;
-
- if (found_wm_max_horz && found_wm_max_vert) {
- retval = true;
- break;
- }
- }
- }
-
- XFree(data);
- return retval;
-}
-
-void OS_X11::set_window_always_on_top(bool p_enabled) {
- if (is_window_always_on_top() == p_enabled)
- return;
-
- if (p_enabled && current_videomode.fullscreen) {
- // Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
- set_window_maximized(true);
- }
- set_wm_above(p_enabled);
- if (!p_enabled && !current_videomode.fullscreen) {
- // Restore
- set_window_maximized(false);
- }
-
- current_videomode.always_on_top = p_enabled;
-}
-
-bool OS_X11::is_window_always_on_top() const {
- return current_videomode.always_on_top;
-}
-
-bool OS_X11::is_window_focused() const {
- return window_focused;
-}
-
-void OS_X11::set_borderless_window(bool p_borderless) {
-
- if (get_borderless_window() == p_borderless)
- return;
-
- if (!p_borderless && layered_window)
- set_window_per_pixel_transparency_enabled(false);
-
- current_videomode.borderless_window = p_borderless;
-
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = current_videomode.borderless_window ? 0 : 1;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
-
- // Preserve window size
- set_window_size(Size2(current_videomode.width, current_videomode.height));
-}
-
-bool OS_X11::get_borderless_window() {
-
- bool borderless = current_videomode.borderless_window;
- Atom prop = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- if (prop != None) {
-
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = NULL;
- if (XGetWindowProperty(x11_display, x11_window, prop, 0, sizeof(Hints), False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
- if (data && (format == 32) && (len >= 5)) {
- borderless = !((Hints *)data)->decorations;
- }
- XFree(data);
- }
- }
- return borderless;
-}
-
-void OS_X11::request_attention() {
- // Using EWMH -- Extended Window Manager Hints
- //
- // Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE
- // Will be unset by the window manager after user react on the request for attention
-
- XEvent xev;
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_attention = XInternAtom(x11_display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_attention;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
- XFlush(x11_display);
-}
-
-void OS_X11::get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) {
-
- state->set_shift((p_x11_state & ShiftMask));
- state->set_control((p_x11_state & ControlMask));
- state->set_alt((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt
- state->set_metakey((p_x11_state & Mod4Mask));
-}
-
-unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) {
-
- unsigned int mask = 1 << (p_x11_button - 1);
-
- if (p_x11_type == ButtonPress) {
- last_button_state |= mask;
- } else {
- last_button_state &= ~mask;
- }
-
- return last_button_state;
-}
-
-void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
-
- // X11 functions don't know what const is
- XKeyEvent *xkeyevent = p_event;
-
- // This code was pretty difficult to write.
- // The docs stink and every toolkit seems to
- // do it in a different way.
-
- /* Phase 1, obtain a proper keysym */
-
- // This was also very difficult to figure out.
- // You'd expect you could just use Keysym provided by
- // XKeycodeToKeysym to obtain internationalized
- // input.. WRONG!!
- // you must use XLookupString (???) which not only wastes
- // cycles generating an unnecessary string, but also
- // still works in half the cases. (won't handle deadkeys)
- // For more complex input methods (deadkeys and more advanced)
- // you have to use XmbLookupString (??).
- // So.. then you have to chosse which of both results
- // you want to keep.
- // This is a real bizarreness and cpu waster.
-
- KeySym keysym_keycode = 0; // keysym used to find a keycode
- KeySym keysym_unicode = 0; // keysym used to find unicode
-
- // XLookupString returns keysyms usable as nice scancodes/
- char str[256 + 1];
- XKeyEvent xkeyevent_no_mod = *xkeyevent;
- xkeyevent_no_mod.state &= ~ShiftMask;
- xkeyevent_no_mod.state &= ~ControlMask;
- XLookupString(xkeyevent, str, 256, &keysym_unicode, NULL);
- XLookupString(&xkeyevent_no_mod, NULL, 0, &keysym_keycode, NULL);
-
- // Meanwhile, XLookupString returns keysyms useful for unicode.
-
- if (!xmbstring) {
- // keep a temporary buffer for the string
- xmbstring = (char *)memalloc(sizeof(char) * 8);
- xmblen = 8;
- }
-
- if (xkeyevent->type == KeyPress && xic) {
-
- Status status;
-#ifdef X_HAVE_UTF8_STRING
- int utf8len = 8;
- char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
- int utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
- utf8len - 1, &keysym_unicode, &status);
- if (status == XBufferOverflow) {
- utf8len = utf8bytes + 1;
- utf8string = (char *)memrealloc(utf8string, utf8len);
- utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
- utf8len - 1, &keysym_unicode, &status);
- }
- utf8string[utf8bytes] = '\0';
-
- if (status == XLookupChars) {
- bool keypress = xkeyevent->type == KeyPress;
- unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
- unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
-
- if (keycode >= 'a' && keycode <= 'z')
- keycode -= 'a' - 'A';
-
- String tmp;
- tmp.parse_utf8(utf8string, utf8bytes);
- for (int i = 0; i < tmp.length(); i++) {
- Ref<InputEventKey> k;
- k.instance();
- if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) {
- continue;
- }
-
- if (keycode == 0)
- keycode = physical_keycode;
-
- get_key_modifier_state(xkeyevent->state, k);
-
- k->set_unicode(tmp[i]);
-
- k->set_pressed(keypress);
-
- k->set_keycode(keycode);
-
- k->set_physical_keycode(physical_keycode);
-
- k->set_echo(false);
-
- if (k->get_keycode() == KEY_BACKTAB) {
- //make it consistent across platforms.
- k->set_keycode(KEY_TAB);
- k->set_physical_keycode(KEY_TAB);
- k->set_shift(true);
- }
-
- input->accumulate_input_event(k);
- }
- memfree(utf8string);
- return;
- }
- memfree(utf8string);
-#else
- do {
-
- int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
- xmbstring[mnbytes] = '\0';
-
- if (status == XBufferOverflow) {
- xmblen = mnbytes + 1;
- xmbstring = (char *)memrealloc(xmbstring, xmblen);
- }
- } while (status == XBufferOverflow);
-#endif
- }
-
- /* Phase 2, obtain a pigui keycode from the keysym */
-
- // KeyMappingX11 just translated the X11 keysym to a PIGUI
- // keysym, so it works in all platforms the same.
-
- unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
- unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
-
- /* Phase 3, obtain a unicode character from the keysym */
-
- // KeyMappingX11 also translates keysym to unicode.
- // It does a binary search on a table to translate
- // most properly.
- unsigned int unicode = keysym_unicode > 0 ? KeyMappingX11::get_unicode_from_keysym(keysym_unicode) : 0;
-
- /* Phase 4, determine if event must be filtered */
-
- // This seems to be a side-effect of using XIM.
- // XEventFilter looks like a core X11 function,
- // but it's actually just used to see if we must
- // ignore a deadkey, or events XIM determines
- // must not reach the actual gui.
- // Guess it was a design problem of the extension
-
- bool keypress = xkeyevent->type == KeyPress;
-
- if (physical_keycode == 0 && keycode == 0 && unicode == 0)
- return;
-
- if (keycode == 0)
- keycode = physical_keycode;
-
- /* Phase 5, determine modifier mask */
-
- // No problems here, except I had no way to
- // know Mod1 was ALT and Mod4 was META (applekey/winkey)
- // just tried Mods until i found them.
-
- //print_verbose("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
-
- Ref<InputEventKey> k;
- k.instance();
-
- get_key_modifier_state(xkeyevent->state, k);
-
- /* Phase 6, determine echo character */
-
- // Echo characters in X11 are a keyrelease and a keypress
- // one after the other with the (almot) same timestamp.
- // To detect them, i use XPeekEvent and check that their
- // difference in time is below a threshold.
-
- if (xkeyevent->type != KeyPress) {
-
- p_echo = false;
-
- // make sure there are events pending,
- // so this call won't block.
- if (XPending(x11_display) > 0) {
- XEvent peek_event;
- XPeekEvent(x11_display, &peek_event);
-
- // I'm using a threshold of 5 msecs,
- // since sometimes there seems to be a little
- // jitter. I'm still not convinced that all this approach
- // is correct, but the xorg developers are
- // not very helpful today.
-
- ::Time tresh = ABSDIFF(peek_event.xkey.time, xkeyevent->time);
- if (peek_event.type == KeyPress && tresh < 5) {
- KeySym rk;
- XLookupString((XKeyEvent *)&peek_event, str, 256, &rk, NULL);
- if (rk == keysym_keycode) {
- XEvent event;
- XNextEvent(x11_display, &event); //erase next event
- handle_key_event((XKeyEvent *)&event, true);
- return; //ignore current, echo next
- }
- }
-
- // use the time from peek_event so it always works
- }
-
- // save the time to check for echo when keypress happens
- }
-
- /* Phase 7, send event to Window */
-
- k->set_pressed(keypress);
-
- if (keycode >= 'a' && keycode <= 'z')
- keycode -= 'a' - 'A';
-
- k->set_keycode(keycode);
- k->set_physical_keycode(physical_keycode);
- k->set_unicode(unicode);
- k->set_echo(p_echo);
-
- if (k->get_keycode() == KEY_BACKTAB) {
- //make it consistent across platforms.
- k->set_keycode(KEY_TAB);
- k->set_physical_keycode(KEY_TAB);
- k->set_shift(true);
- }
-
- //don't set mod state if modifier keys are released by themselves
- //else event.is_action() will not work correctly here
- if (!k->is_pressed()) {
- if (k->get_keycode() == KEY_SHIFT)
- k->set_shift(false);
- else if (k->get_keycode() == KEY_CONTROL)
- k->set_control(false);
- else if (k->get_keycode() == KEY_ALT)
- k->set_alt(false);
- else if (k->get_keycode() == KEY_META)
- k->set_metakey(false);
- }
-
- bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_keycode());
- if (k->is_pressed()) {
- if (last_is_pressed) {
- k->set_echo(true);
- }
- }
-
- //printf("key: %x\n",k->get_keycode());
- input->accumulate_input_event(k);
-}
-
-struct Property {
- unsigned char *data;
- int format, nitems;
- Atom type;
-};
-
-static Property read_property(Display *p_display, Window p_window, Atom p_property) {
-
- Atom actual_type;
- int actual_format;
- unsigned long nitems;
- unsigned long bytes_after;
- unsigned char *ret = 0;
-
- int read_bytes = 1024;
-
- //Keep trying to read the property until there are no
- //bytes unread.
- do {
- if (ret != 0)
- XFree(ret);
-
- XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType,
- &actual_type, &actual_format, &nitems, &bytes_after,
- &ret);
-
- read_bytes *= 2;
-
- } while (bytes_after != 0);
-
- Property p = { ret, actual_format, (int)nitems, actual_type };
-
- return p;
-}
-
-static Atom pick_target_from_list(Display *p_display, Atom *p_list, int p_count) {
-
- static const char *target_type = "text/uri-list";
-
- for (int i = 0; i < p_count; i++) {
-
- Atom atom = p_list[i];
-
- if (atom != None && String(XGetAtomName(p_display, atom)) == target_type)
- return atom;
- }
- return None;
-}
-
-static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p_t3) {
-
- static const char *target_type = "text/uri-list";
- if (p_t1 != None && String(XGetAtomName(p_disp, p_t1)) == target_type)
- return p_t1;
-
- if (p_t2 != None && String(XGetAtomName(p_disp, p_t2)) == target_type)
- return p_t2;
-
- if (p_t3 != None && String(XGetAtomName(p_disp, p_t3)) == target_type)
- return p_t3;
-
- return None;
-}
-
-void OS_X11::_window_changed(XEvent *event) {
-
- if (xic) {
- // Not portable.
- set_ime_position(Point2(0, 1));
- }
- if ((event->xconfigure.width == current_videomode.width) &&
- (event->xconfigure.height == current_videomode.height))
- return;
-
- current_videomode.width = event->xconfigure.width;
- current_videomode.height = event->xconfigure.height;
-
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
- context_vulkan->window_resize(0, current_videomode.width, current_videomode.height);
- }
-#endif
-}
-
-void OS_X11::process_xevents() {
-
- //printf("checking events %i\n", XPending(x11_display));
-
- do_mouse_warp = false;
-
- // Is the current mouse mode one where it needs to be grabbed.
- bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED;
-
- while (XPending(x11_display) > 0) {
- XEvent event;
- XNextEvent(x11_display, &event);
-
- if (XFilterEvent(&event, None)) {
- continue;
- }
-
- if (XGetEventData(x11_display, &event.xcookie)) {
-
- if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
-
- XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
- int index = event_data->detail;
- Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
-
- switch (event_data->evtype) {
- case XI_HierarchyChanged:
- case XI_DeviceChanged: {
- refresh_device_info();
- } break;
- case XI_RawMotion: {
- XIRawEvent *raw_event = (XIRawEvent *)event_data;
- int device_id = raw_event->deviceid;
-
- // Determine the axis used (called valuators in XInput for some forsaken reason)
- // Mask is a bitmask indicating which axes are involved.
- // We are interested in the values of axes 0 and 1.
- if (raw_event->valuators.mask_len <= 0) {
- break;
- }
-
- const double *values = raw_event->raw_values;
-
- double rel_x = 0.0;
- double rel_y = 0.0;
- double pressure = 0.0;
- double tilt_x = 0.0;
- double tilt_y = 0.0;
-
- if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSX)) {
- rel_x = *values;
- values++;
- }
-
- if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSY)) {
- rel_y = *values;
- values++;
- }
-
- if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_PRESSURE)) {
- pressure = *values;
- values++;
- }
-
- if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTX)) {
- tilt_x = *values;
- values++;
- }
-
- if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTY)) {
- tilt_y = *values;
- }
-
- Map<int, Vector3>::Element *pen_info = xi.pen_devices.find(device_id);
- if (pen_info) {
- Vector3 mult = pen_info->value();
- if (mult.x != 0.0) xi.pressure = pressure / mult.x;
- if ((mult.y != 0.0) && (mult.z != 0.0)) xi.tilt = Vector2(tilt_x / mult.y, tilt_y / mult.z);
- }
-
- // https://bugs.freedesktop.org/show_bug.cgi?id=71609
- // http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html
- if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) {
- break; // Flush duplicate to avoid overly fast motion
- }
-
- xi.old_raw_pos.x = xi.raw_pos.x;
- xi.old_raw_pos.y = xi.raw_pos.y;
- xi.raw_pos.x = rel_x;
- xi.raw_pos.y = rel_y;
-
- Map<int, Vector2>::Element *abs_info = xi.absolute_devices.find(device_id);
-
- if (abs_info) {
- // Absolute mode device
- Vector2 mult = abs_info->value();
-
- xi.relative_motion.x += (xi.raw_pos.x - xi.old_raw_pos.x) * mult.x;
- xi.relative_motion.y += (xi.raw_pos.y - xi.old_raw_pos.y) * mult.y;
- } else {
- // Relative mode device
- xi.relative_motion.x = xi.raw_pos.x;
- xi.relative_motion.y = xi.raw_pos.y;
- }
-
- xi.last_relative_time = raw_event->time;
- } break;
-#ifdef TOUCH_ENABLED
- case XI_TouchBegin: // Fall-through
- // Disabled hand-in-hand with the grabbing
- //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
-
- case XI_TouchEnd: {
-
- bool is_begin = event_data->evtype == XI_TouchBegin;
-
- Ref<InputEventScreenTouch> st;
- st.instance();
- st->set_index(index);
- st->set_position(pos);
- st->set_pressed(is_begin);
-
- if (is_begin) {
- if (xi.state.has(index)) // Defensive
- break;
- xi.state[index] = pos;
- if (xi.state.size() == 1) {
- // X11 may send a motion event when a touch gesture begins, that would result
- // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
- xi.mouse_pos_to_filter = pos;
- }
- input->accumulate_input_event(st);
- } else {
- if (!xi.state.has(index)) // Defensive
- break;
- xi.state.erase(index);
- input->accumulate_input_event(st);
- }
- } break;
-
- case XI_TouchUpdate: {
-
- Map<int, Vector2>::Element *curr_pos_elem = xi.state.find(index);
- if (!curr_pos_elem) { // Defensive
- break;
- }
-
- if (curr_pos_elem->value() != pos) {
-
- Ref<InputEventScreenDrag> sd;
- sd.instance();
- sd->set_index(index);
- sd->set_position(pos);
- sd->set_relative(pos - curr_pos_elem->value());
- input->accumulate_input_event(sd);
-
- curr_pos_elem->value() = pos;
- }
- } break;
-#endif
- }
- }
- }
- XFreeEventData(x11_display, &event.xcookie);
-
- switch (event.type) {
- case Expose:
- Main::force_redraw();
- break;
-
- case NoExpose:
- minimized = true;
- break;
-
- case VisibilityNotify: {
- XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
- minimized = (visibility->state == VisibilityFullyObscured);
- } break;
- case LeaveNotify: {
- if (main_loop && !mouse_mode_grab)
- main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
-
- } break;
- case EnterNotify: {
- if (main_loop && !mouse_mode_grab)
- main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
- } break;
- case FocusIn:
- minimized = false;
- window_has_focus = true;
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
- window_focused = true;
-
- if (mouse_mode_grab) {
- // Show and update the cursor if confined and the window regained focus.
- if (mouse_mode == MOUSE_MODE_CONFINED)
- XUndefineCursor(x11_display, x11_window);
- else if (mouse_mode == MOUSE_MODE_CAPTURED) // or re-hide it in captured mode
- XDefineCursor(x11_display, x11_window, null_cursor);
-
- XGrabPointer(
- x11_display, x11_window, True,
- ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
- GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
- }
-#ifdef TOUCH_ENABLED
- // Grab touch devices to avoid OS gesture interference
- /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
- XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
- }*/
-#endif
- if (xic) {
- XSetICFocus(xic);
- }
- break;
-
- case FocusOut:
- window_has_focus = false;
- input->release_pressed_events();
- main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
- window_focused = false;
-
- if (mouse_mode_grab) {
- //dear X11, I try, I really try, but you never work, you do whathever you want.
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- // Show the cursor if we're in captured mode so it doesn't look weird.
- XUndefineCursor(x11_display, x11_window);
- }
- XUngrabPointer(x11_display, CurrentTime);
- }
-#ifdef TOUCH_ENABLED
- // Ungrab touch devices so input works as usual while we are unfocused
- /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
- XIUngrabDevice(x11_display, xi.touch_devices[i], CurrentTime);
- }*/
-
- // Release every pointer to avoid sticky points
- for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) {
-
- Ref<InputEventScreenTouch> st;
- st.instance();
- st->set_index(E->key());
- st->set_position(E->get());
- input->accumulate_input_event(st);
- }
- xi.state.clear();
-#endif
- if (xic) {
- XUnsetICFocus(xic);
- }
- break;
-
- case ConfigureNotify:
- _window_changed(&event);
- break;
- case ButtonPress:
- case ButtonRelease: {
-
- /* exit in case of a mouse button press */
- last_timestamp = event.xbutton.time;
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- event.xbutton.x = last_mouse_pos.x;
- event.xbutton.y = last_mouse_pos.y;
- }
-
- Ref<InputEventMouseButton> mb;
- mb.instance();
-
- get_key_modifier_state(event.xbutton.state, mb);
- mb->set_button_index(event.xbutton.button);
- if (mb->get_button_index() == 2)
- mb->set_button_index(3);
- else if (mb->get_button_index() == 3)
- mb->set_button_index(2);
- mb->set_button_mask(get_mouse_button_state(mb->get_button_index(), event.xbutton.type));
- mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
- mb->set_global_position(mb->get_position());
-
- mb->set_pressed((event.type == ButtonPress));
-
- if (event.type == ButtonPress) {
-
- uint64_t diff = get_ticks_usec() / 1000 - last_click_ms;
-
- if (mb->get_button_index() == last_click_button_index) {
-
- if (diff < 400 && Point2(last_click_pos).distance_to(Point2(event.xbutton.x, event.xbutton.y)) < 5) {
-
- last_click_ms = 0;
- last_click_pos = Point2(-100, -100);
- last_click_button_index = -1;
- mb->set_doubleclick(true);
- }
-
- } else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) {
- last_click_button_index = mb->get_button_index();
- }
-
- if (!mb->is_doubleclick()) {
- last_click_ms += diff;
- last_click_pos = Point2(event.xbutton.x, event.xbutton.y);
- }
- }
-
- input->accumulate_input_event(mb);
-
- } break;
- case MotionNotify: {
-
- // The X11 API requires filtering one-by-one through the motion
- // notify events, in order to figure out which event is the one
- // generated by warping the mouse pointer.
-
- while (true) {
- if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == current_videomode.width / 2 && event.xmotion.y == current_videomode.height / 2) {
- //this is likely the warp event since it was warped here
- center = Vector2(event.xmotion.x, event.xmotion.y);
- break;
- }
-
- if (XPending(x11_display) > 0) {
- XEvent tevent;
- XPeekEvent(x11_display, &tevent);
- if (tevent.type == MotionNotify) {
- XNextEvent(x11_display, &event);
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- last_timestamp = event.xmotion.time;
-
- // Motion is also simple.
- // A little hack is in order
- // to be able to send relative motion events.
- Point2 pos(event.xmotion.x, event.xmotion.y);
-
- // Avoidance of spurious mouse motion (see handling of touch)
- bool filter = false;
- // Adding some tolerance to match better Point2i to Vector2
- if (xi.state.size() && Vector2(pos).distance_squared_to(xi.mouse_pos_to_filter) < 2) {
- filter = true;
- }
- // Invalidate to avoid filtering a possible legitimate similar event coming later
- xi.mouse_pos_to_filter = Vector2(1e10, 1e10);
- if (filter) {
- break;
- }
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
- break;
- }
-
- Point2i new_center = pos;
- pos = last_mouse_pos + xi.relative_motion;
- center = new_center;
- do_mouse_warp = window_has_focus; // warp the cursor if we're focused in
- }
-
- if (!last_mouse_pos_valid) {
-
- last_mouse_pos = pos;
- last_mouse_pos_valid = true;
- }
-
- // Hackish but relative mouse motion is already handled in the RawMotion event.
- // RawMotion does not provide the absolute mouse position (whereas MotionNotify does).
- // Therefore, RawMotion cannot be the authority on absolute mouse position.
- // RawMotion provides more precision than MotionNotify, which doesn't sense subpixel motion.
- // Therefore, MotionNotify cannot be the authority on relative mouse motion.
- // This means we need to take a combined approach...
- Point2 rel;
-
- // Only use raw input if in capture mode. Otherwise use the classic behavior.
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- rel = xi.relative_motion;
- } else {
- rel = pos - last_mouse_pos;
- }
-
- // Reset to prevent lingering motion
- xi.relative_motion.x = 0;
- xi.relative_motion.y = 0;
-
- if (mouse_mode == MOUSE_MODE_CAPTURED) {
- pos = Point2i(current_videomode.width / 2, current_videomode.height / 2);
- }
-
- Ref<InputEventMouseMotion> mm;
- mm.instance();
-
- mm->set_pressure(xi.pressure);
- mm->set_tilt(xi.tilt);
-
- // Make the absolute position integral so it doesn't look _too_ weird :)
- Point2i posi(pos);
-
- get_key_modifier_state(event.xmotion.state, mm);
- mm->set_button_mask(get_mouse_button_state());
- mm->set_position(posi);
- mm->set_global_position(posi);
- input->set_mouse_position(posi);
- mm->set_speed(input->get_last_mouse_speed());
-
- mm->set_relative(rel);
-
- last_mouse_pos = pos;
-
- // printf("rel: %d,%d\n", rel.x, rel.y );
- // Don't propagate the motion event unless we have focus
- // this is so that the relative motion doesn't get messed up
- // after we regain focus.
- if (window_has_focus || !mouse_mode_grab)
- input->accumulate_input_event(mm);
-
- } break;
- case KeyPress:
- case KeyRelease: {
-
- last_timestamp = event.xkey.time;
-
- // key event is a little complex, so
- // it will be handled in its own function.
- handle_key_event((XKeyEvent *)&event);
- } break;
- case SelectionRequest: {
-
- XSelectionRequestEvent *req;
- XEvent e, respond;
- e = event;
-
- req = &(e.xselectionrequest);
- if (req->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
- req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- req->target == XInternAtom(x11_display, "TEXT", 0) ||
- req->target == XA_STRING ||
- req->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
- req->target == XInternAtom(x11_display, "text/plain", 0)) {
- CharString clip = OS::get_clipboard().utf8();
- XChangeProperty(x11_display,
- req->requestor,
- req->property,
- req->target,
- 8,
- PropModeReplace,
- (unsigned char *)clip.get_data(),
- clip.length());
- respond.xselection.property = req->property;
- } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
-
- Atom data[7];
- data[0] = XInternAtom(x11_display, "TARGETS", 0);
- data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
- data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
- data[3] = XInternAtom(x11_display, "TEXT", 0);
- data[4] = XA_STRING;
- data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
- data[6] = XInternAtom(x11_display, "text/plain", 0);
-
- XChangeProperty(x11_display,
- req->requestor,
- req->property,
- XA_ATOM,
- 32,
- PropModeReplace,
- (unsigned char *)&data,
- sizeof(data) / sizeof(data[0]));
- respond.xselection.property = req->property;
-
- } else {
- char *targetname = XGetAtomName(x11_display, req->target);
- printf("No Target '%s'\n", targetname);
- if (targetname)
- XFree(targetname);
- respond.xselection.property = None;
- }
-
- respond.xselection.type = SelectionNotify;
- respond.xselection.display = req->display;
- respond.xselection.requestor = req->requestor;
- respond.xselection.selection = req->selection;
- respond.xselection.target = req->target;
- respond.xselection.time = req->time;
- XSendEvent(x11_display, req->requestor, True, NoEventMask, &respond);
- XFlush(x11_display);
- } break;
-
- case SelectionNotify:
-
- if (event.xselection.target == requested) {
-
- Property p = read_property(x11_display, x11_window, XInternAtom(x11_display, "PRIMARY", 0));
-
- Vector<String> files = String((char *)p.data).split("\n", false);
- for (int i = 0; i < files.size(); i++) {
- files.write[i] = files[i].replace("file://", "").http_unescape().strip_edges();
- }
- main_loop->drop_files(files);
-
- //Reply that all is well.
- XClientMessageEvent m;
- memset(&m, 0, sizeof(m));
- m.type = ClientMessage;
- m.display = x11_display;
- m.window = xdnd_source_window;
- m.message_type = xdnd_finished;
- m.format = 32;
- m.data.l[0] = x11_window;
- m.data.l[1] = 1;
- m.data.l[2] = xdnd_action_copy; //We only ever copy.
-
- XSendEvent(x11_display, xdnd_source_window, False, NoEventMask, (XEvent *)&m);
- }
- break;
-
- case ClientMessage:
-
- if ((unsigned int)event.xclient.data.l[0] == (unsigned int)wm_delete)
- main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
-
- else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_enter) {
-
- //File(s) have been dragged over the window, check for supported target (text/uri-list)
- xdnd_version = (event.xclient.data.l[1] >> 24);
- Window source = event.xclient.data.l[0];
- bool more_than_3 = event.xclient.data.l[1] & 1;
- if (more_than_3) {
- Property p = read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False));
- requested = pick_target_from_list(x11_display, (Atom *)p.data, p.nitems);
- } else
- requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]);
- } else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_position) {
-
- //xdnd position event, reply with an XDND status message
- //just depending on type of data for now
- XClientMessageEvent m;
- memset(&m, 0, sizeof(m));
- m.type = ClientMessage;
- m.display = event.xclient.display;
- m.window = event.xclient.data.l[0];
- m.message_type = xdnd_status;
- m.format = 32;
- m.data.l[0] = x11_window;
- m.data.l[1] = (requested != None);
- m.data.l[2] = 0; //empty rectangle
- m.data.l[3] = 0;
- m.data.l[4] = xdnd_action_copy;
-
- XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
- XFlush(x11_display);
- } else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_drop) {
-
- if (requested != None) {
- xdnd_source_window = event.xclient.data.l[0];
- if (xdnd_version >= 1)
- XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), x11_window, event.xclient.data.l[2]);
- else
- XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), x11_window, CurrentTime);
- } else {
- //Reply that we're not interested.
- XClientMessageEvent m;
- memset(&m, 0, sizeof(m));
- m.type = ClientMessage;
- m.display = event.xclient.display;
- m.window = event.xclient.data.l[0];
- m.message_type = xdnd_finished;
- m.format = 32;
- m.data.l[0] = x11_window;
- m.data.l[1] = 0;
- m.data.l[2] = None; //Failed.
- XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
- }
- }
- break;
- default:
- break;
- }
- }
-
- XFlush(x11_display);
-
- if (do_mouse_warp) {
-
- XWarpPointer(x11_display, None, x11_window,
- 0, 0, 0, 0, (int)current_videomode.width / 2, (int)current_videomode.height / 2);
-
- /*
- Window root, child;
- int root_x, root_y;
- int win_x, win_y;
- unsigned int mask;
- XQueryPointer( x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );
-
- printf("Root: %d,%d\n", root_x, root_y);
- printf("Win: %d,%d\n", win_x, win_y);
- */
- }
-
- input->flush_accumulated_events();
-}
-
-MainLoop *OS_X11::get_main_loop() const {
-
- return main_loop;
-}
-
-void OS_X11::delete_main_loop() {
-
- if (main_loop)
- memdelete(main_loop);
- main_loop = NULL;
-}
-
-void OS_X11::set_main_loop(MainLoop *p_main_loop) {
-
- main_loop = p_main_loop;
- input->set_main_loop(p_main_loop);
-}
-
-bool OS_X11::can_draw() const {
-
- return !minimized;
-};
-
-void OS_X11::set_clipboard(const String &p_text) {
-
- OS::set_clipboard(p_text);
-
- XSetSelectionOwner(x11_display, XA_PRIMARY, x11_window, CurrentTime);
- XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime);
-};
-
-static String _get_clipboard_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) {
-
- String ret;
-
- Atom type;
- Atom selection = XA_PRIMARY;
- int format, result;
- unsigned long len, bytes_left, dummy;
- unsigned char *data;
- Window Sown = XGetSelectionOwner(x11_display, p_source);
-
- if (Sown == x11_window) {
-
- return p_internal_clipboard;
- };
-
- if (Sown != None) {
- XConvertSelection(x11_display, p_source, target, selection,
- x11_window, CurrentTime);
- XFlush(x11_display);
- while (true) {
- XEvent event;
- XNextEvent(x11_display, &event);
- if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
- break;
- };
- };
-
- //
- // Do not get any data, see how much data is there
- //
- XGetWindowProperty(x11_display, x11_window,
- selection, // Tricky..
- 0, 0, // offset - len
- 0, // Delete 0==FALSE
- AnyPropertyType, //flag
- &type, // return type
- &format, // return format
- &len, &bytes_left, //that
- &data);
- // DATA is There
- if (bytes_left > 0) {
- result = XGetWindowProperty(x11_display, x11_window,
- selection, 0, bytes_left, 0,
- AnyPropertyType, &type, &format,
- &len, &dummy, &data);
- if (result == Success) {
- ret.parse_utf8((const char *)data);
- } else
- printf("FAIL\n");
- XFree(data);
- }
- }
-
- return ret;
-}
-
-static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
- String ret;
- Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
- if (utf8_atom != None) {
- ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom);
- }
- if (ret == "") {
- ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING);
- }
- return ret;
-}
-
-String OS_X11::get_clipboard() const {
-
- String ret;
- ret = _get_clipboard(XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, x11_display, OS::get_clipboard());
-
- if (ret == "") {
- ret = _get_clipboard(XA_PRIMARY, x11_window, x11_display, OS::get_clipboard());
- };
-
- return ret;
-}
-
-String OS_X11::get_name() const {
-
- return "X11";
-}
-
-Error OS_X11::shell_open(String p_uri) {
-
- Error ok;
- List<String> args;
- args.push_back(p_uri);
- ok = execute("xdg-open", args, false);
- if (ok == OK)
- return OK;
- ok = execute("gnome-open", args, false);
- if (ok == OK)
- return OK;
- ok = execute("kde-open", args, false);
- return ok;
-}
-
-bool OS_X11::_check_internal_feature_support(const String &p_feature) {
-
- return p_feature == "pc";
-}
-
-String OS_X11::get_config_path() const {
-
- if (has_environment("XDG_CONFIG_HOME")) {
- return get_environment("XDG_CONFIG_HOME");
- } else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".config");
- } else {
- return ".";
- }
-}
-
-String OS_X11::get_data_path() const {
-
- if (has_environment("XDG_DATA_HOME")) {
- return get_environment("XDG_DATA_HOME");
- } else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".local/share");
- } else {
- return get_config_path();
- }
-}
-
-String OS_X11::get_cache_path() const {
-
- if (has_environment("XDG_CACHE_HOME")) {
- return get_environment("XDG_CACHE_HOME");
- } else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".cache");
- } else {
- return get_config_path();
- }
-}
-
-String OS_X11::get_system_dir(SystemDir p_dir) const {
-
- String xdgparam;
-
- switch (p_dir) {
- case SYSTEM_DIR_DESKTOP: {
-
- xdgparam = "DESKTOP";
- } break;
- case SYSTEM_DIR_DCIM: {
-
- xdgparam = "PICTURES";
-
- } break;
- case SYSTEM_DIR_DOCUMENTS: {
-
- xdgparam = "DOCUMENTS";
-
- } break;
- case SYSTEM_DIR_DOWNLOADS: {
-
- xdgparam = "DOWNLOAD";
-
- } break;
- case SYSTEM_DIR_MOVIES: {
-
- xdgparam = "VIDEOS";
-
- } break;
- case SYSTEM_DIR_MUSIC: {
-
- xdgparam = "MUSIC";
-
- } break;
- case SYSTEM_DIR_PICTURES: {
-
- xdgparam = "PICTURES";
-
- } break;
- case SYSTEM_DIR_RINGTONES: {
-
- xdgparam = "MUSIC";
-
- } break;
- }
-
- String pipe;
- List<String> arg;
- arg.push_back(xdgparam);
- Error err = const_cast<OS_X11 *>(this)->execute("xdg-user-dir", arg, true, NULL, &pipe);
- if (err != OK)
- return ".";
- return pipe.strip_edges();
-}
-
-void OS_X11::move_window_to_foreground() {
-
- XEvent xev;
- Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = net_active_window;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = 1;
- xev.xclient.data.l[1] = CurrentTime;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
- XFlush(x11_display);
-}
-
-void OS_X11::set_cursor_shape(CursorShape p_shape) {
-
- ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
-
- if (p_shape == current_cursor) {
- return;
- }
-
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
- if (cursors[p_shape] != None) {
- XDefineCursor(x11_display, x11_window, cursors[p_shape]);
- } else if (cursors[CURSOR_ARROW] != None) {
- XDefineCursor(x11_display, x11_window, cursors[CURSOR_ARROW]);
- }
- }
-
- current_cursor = p_shape;
-}
-
-OS::CursorShape OS_X11::get_cursor_shape() const {
-
- return current_cursor;
-}
-
-void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
-
- if (p_cursor.is_valid()) {
-
- Map<CursorShape, Vector<Variant> >::Element *cursor_c = cursors_cache.find(p_shape);
-
- if (cursor_c) {
- if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
- set_cursor_shape(p_shape);
- return;
- }
-
- cursors_cache.erase(p_shape);
- }
-
- Ref<Texture2D> texture = p_cursor;
- Ref<AtlasTexture> atlas_texture = p_cursor;
- Ref<Image> image;
- Size2 texture_size;
- Rect2 atlas_rect;
-
- if (texture.is_valid()) {
- image = texture->get_data();
- }
-
- if (!image.is_valid() && atlas_texture.is_valid()) {
- texture = atlas_texture->get_atlas();
-
- atlas_rect.size.width = texture->get_width();
- atlas_rect.size.height = texture->get_height();
- atlas_rect.position.x = atlas_texture->get_region().position.x;
- atlas_rect.position.y = atlas_texture->get_region().position.y;
-
- texture_size.width = atlas_texture->get_region().size.x;
- texture_size.height = atlas_texture->get_region().size.y;
- } else if (image.is_valid()) {
- texture_size.width = texture->get_width();
- texture_size.height = texture->get_height();
- }
-
- ERR_FAIL_COND(!texture.is_valid());
- ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
- 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();
-
- ERR_FAIL_COND(!image.is_valid());
-
- // Create the cursor structure
- XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
- XcursorUInt image_size = texture_size.width * texture_size.height;
- XcursorDim size = sizeof(XcursorPixel) * image_size;
-
- cursor_image->version = 1;
- cursor_image->size = size;
- cursor_image->xhot = p_hotspot.x;
- cursor_image->yhot = p_hotspot.y;
-
- // allocate memory to contain the whole file
- cursor_image->pixels = (XcursorPixel *)memalloc(size);
-
- for (XcursorPixel index = 0; index < image_size; index++) {
- int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
- int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
-
- if (atlas_texture.is_valid()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
-
- *(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
- }
-
- ERR_FAIL_COND(cursor_image->pixels == NULL);
-
- // Save it for a further usage
- cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
-
- Vector<Variant> params;
- params.push_back(p_cursor);
- params.push_back(p_hotspot);
- cursors_cache.insert(p_shape, params);
-
- if (p_shape == current_cursor) {
- if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
- XDefineCursor(x11_display, x11_window, cursors[p_shape]);
- }
- }
-
- memfree(cursor_image->pixels);
- XcursorImageDestroy(cursor_image);
- } else {
- // Reset to default system cursor
- if (img[p_shape]) {
- cursors[p_shape] = XcursorImageLoadCursor(x11_display, img[p_shape]);
- }
-
- CursorShape c = current_cursor;
- current_cursor = CURSOR_MAX;
- set_cursor_shape(c);
-
- cursors_cache.erase(p_shape);
- }
-}
-
-void OS_X11::release_rendering_thread() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->release_current();
- }
-#endif
-}
-
-void OS_X11::make_rendering_thread() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->make_current();
- }
-#endif
-}
-
-void OS_X11::swap_buffers() {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- context_gles2->swap_buffers();
- }
-#endif
- /* not needed for now
-#if defined(VULKAN_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_VULKAN) {
- context_vulkan->swap_buffers();
- }
-#endif*/
-}
-
-void OS_X11::alert(const String &p_alert, const String &p_title) {
- const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" };
-
- String path = get_environment("PATH");
- Vector<String> path_elems = path.split(":", false);
- String program;
-
- for (int i = 0; i < path_elems.size(); i++) {
- for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
- String tested_path = path_elems[i].plus_file(message_programs[k]);
-
- if (FileAccess::exists(tested_path)) {
- program = tested_path;
- break;
- }
- }
-
- if (program.length())
- break;
- }
-
- List<String> args;
-
- if (program.ends_with("zenity")) {
- args.push_back("--error");
- args.push_back("--width");
- args.push_back("500");
- args.push_back("--title");
- args.push_back(p_title);
- args.push_back("--text");
- args.push_back(p_alert);
- }
-
- if (program.ends_with("kdialog")) {
- args.push_back("--error");
- args.push_back(p_alert);
- args.push_back("--title");
- args.push_back(p_title);
- }
-
- if (program.ends_with("Xdialog")) {
- args.push_back("--title");
- args.push_back(p_title);
- args.push_back("--msgbox");
- args.push_back(p_alert);
- args.push_back("0");
- args.push_back("0");
- }
-
- if (program.ends_with("xmessage")) {
- args.push_back("-center");
- args.push_back("-title");
- args.push_back(p_title);
- args.push_back(p_alert);
- }
-
- if (program.length()) {
- execute(program, args, true);
- } else {
- print_line(p_alert);
- }
-}
-
-bool g_set_icon_error = false;
-int set_icon_errorhandler(Display *dpy, XErrorEvent *ev) {
- g_set_icon_error = true;
- return 0;
-}
-
-void OS_X11::set_icon(const Ref<Image> &p_icon) {
- int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&set_icon_errorhandler);
-
- Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
-
- if (p_icon.is_valid()) {
- Ref<Image> img = p_icon->duplicate();
- img->convert(Image::FORMAT_RGBA8);
-
- while (true) {
- int w = img->get_width();
- int h = img->get_height();
-
- if (g_set_icon_error) {
- g_set_icon_error = false;
-
- WARN_PRINT("Icon too large, attempting to resize icon.");
-
- int new_width, new_height;
- if (w > h) {
- new_width = w / 2;
- new_height = h * new_width / w;
- } else {
- new_height = h / 2;
- new_width = w * new_height / h;
- }
-
- w = new_width;
- h = new_height;
-
- if (!w || !h) {
- WARN_PRINT("Unable to set icon.");
- break;
- }
-
- img->resize(w, h, Image::INTERPOLATE_CUBIC);
- }
-
- // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
- Vector<long> pd;
-
- pd.resize(2 + w * h);
-
- pd.write[0] = w;
- pd.write[1] = h;
-
- const uint8_t *r = img->get_data().ptr();
-
- long *wr = &pd.write[2];
- uint8_t const *pr = r;
-
- for (int i = 0; i < w * h; i++) {
- long v = 0;
- // A R G B
- v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
- *wr++ = v;
- pr += 4;
- }
-
- XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size());
-
- if (!g_set_icon_error)
- break;
- }
- } else {
- XDeleteProperty(x11_display, x11_window, net_wm_icon);
- }
-
- XFlush(x11_display);
- XSetErrorHandler(oldHandler);
-}
-
-void OS_X11::force_process_input() {
- process_xevents(); // get rid of pending events
-#ifdef JOYDEV_ENABLED
- joypad->process_joypads();
-#endif
-}
-
-void OS_X11::run() {
-
- force_quit = false;
-
- if (!main_loop)
- return;
-
- main_loop->init();
-
- //uint64_t last_ticks=get_ticks_usec();
-
- //int frames=0;
- //uint64_t frame=0;
-
- while (!force_quit) {
-
- process_xevents(); // get rid of pending events
-#ifdef JOYDEV_ENABLED
- joypad->process_joypads();
-#endif
- if (Main::iteration())
- break;
- };
-
- main_loop->finish();
-}
-
-bool OS_X11::is_joy_known(int p_device) {
- return input->is_joy_mapped(p_device);
-}
-
-String OS_X11::get_joy_guid(int p_device) const {
- return input->get_joy_guid_remapped(p_device);
-}
-
-void OS_X11::_set_use_vsync(bool p_enable) {
-#if defined(OPENGL_ENABLED)
- if (video_driver_index == VIDEO_DRIVER_GLES2) {
- if (context_gles2)
- context_gles2->set_use_vsync(p_enable);
- }
-#endif
-}
-
-void OS_X11::set_context(int p_context) {
-
- XClassHint *classHint = XAllocClassHint();
-
- if (classHint) {
-
- CharString name_str;
- switch (p_context) {
- case CONTEXT_EDITOR:
- name_str = "Godot_Editor";
- break;
- case CONTEXT_PROJECTMAN:
- name_str = "Godot_ProjectList";
- break;
- case CONTEXT_ENGINE:
- name_str = "Godot_Engine";
- break;
- }
-
- CharString class_str;
- if (p_context == CONTEXT_ENGINE) {
- String config_name = GLOBAL_GET("application/config/name");
- if (config_name.length() == 0) {
- class_str = "Godot_Engine";
- } else {
- class_str = config_name.utf8();
- }
- } else {
- class_str = "Godot";
- }
-
- classHint->res_class = class_str.ptrw();
- classHint->res_name = name_str.ptrw();
-
- XSetClassHint(x11_display, x11_window, classHint);
- XFree(classHint);
- }
-}
-
-void OS_X11::disable_crash_handler() {
- crash_handler.disable();
-}
-
-bool OS_X11::is_disable_crash_handler() const {
- return crash_handler.is_disabled();
-}
-
-static String get_mountpoint(const String &p_path) {
- struct stat s;
- if (stat(p_path.utf8().get_data(), &s)) {
- return "";
- }
-
-#ifdef HAVE_MNTENT
- dev_t dev = s.st_dev;
- FILE *fd = setmntent("/proc/mounts", "r");
- if (!fd) {
- return "";
- }
-
- struct mntent mnt;
- char buf[1024];
- size_t buflen = 1024;
- while (getmntent_r(fd, &mnt, buf, buflen)) {
- if (!stat(mnt.mnt_dir, &s) && s.st_dev == dev) {
- endmntent(fd);
- return String(mnt.mnt_dir);
- }
- }
-
- endmntent(fd);
-#endif
- return "";
-}
-
-Error OS_X11::move_to_trash(const String &p_path) {
- String trash_can = "";
- String mnt = get_mountpoint(p_path);
-
- // If there is a directory "[Mountpoint]/.Trash-[UID]/files", use it as the trash can.
- if (mnt != "") {
- String path(mnt + "/.Trash-" + itos(getuid()) + "/files");
- struct stat s;
- if (!stat(path.utf8().get_data(), &s)) {
- trash_can = path;
- }
- }
-
- // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash/files" as the trash can.
- if (trash_can == "") {
- char *dhome = getenv("XDG_DATA_HOME");
- if (dhome) {
- trash_can = String(dhome) + "/Trash/files";
- }
- }
-
- // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash/files" as the trash can.
- if (trash_can == "") {
- char *home = getenv("HOME");
- if (home) {
- trash_can = String(home) + "/.local/share/Trash/files";
- }
- }
-
- // Issue an error if none of the previous locations is appropriate for the trash can.
- if (trash_can == "") {
- ERR_PRINT("move_to_trash: Could not determine the trash can location");
- return FAILED;
- }
-
- // Create needed directories for decided trash can location.
- DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- Error err = dir_access->make_dir_recursive(trash_can);
- memdelete(dir_access);
-
- // Issue an error if trash can is not created proprely.
- if (err != OK) {
- ERR_PRINT("move_to_trash: Could not create the trash can \"" + trash_can + "\"");
- return err;
- }
-
- // The trash can is successfully created, now move the given resource to it.
- // Do not use DirAccess:rename() because it can't move files across multiple mountpoints.
- List<String> mv_args;
- mv_args.push_back(p_path);
- mv_args.push_back(trash_can);
- int retval;
- err = execute("mv", mv_args, true, NULL, NULL, &retval);
-
- // Issue an error if "mv" failed to move the given resource to the trash can.
- if (err != OK || retval != 0) {
- ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_can + "\"");
- return FAILED;
- }
-
- return OK;
-}
-
-OS::LatinKeyboardVariant OS_X11::get_latin_keyboard_variant() const {
-
- XkbDescRec *xkbdesc = XkbAllocKeyboard();
- ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY);
-
- XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc);
- ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY);
- ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY);
-
- char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols);
- ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY);
-
- Vector<String> info = String(layout).split("+");
- ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY);
-
- if (info[1].find("colemak") != -1) {
- return LATIN_KEYBOARD_COLEMAK;
- } else if (info[1].find("qwertz") != -1) {
- return LATIN_KEYBOARD_QWERTZ;
- } else if (info[1].find("azerty") != -1) {
- return LATIN_KEYBOARD_AZERTY;
- } else if (info[1].find("qzerty") != -1) {
- return LATIN_KEYBOARD_QZERTY;
- } else if (info[1].find("dvorak") != -1) {
- return LATIN_KEYBOARD_DVORAK;
- } else if (info[1].find("neo") != -1) {
- return LATIN_KEYBOARD_NEO;
- }
-
- return LATIN_KEYBOARD_QWERTY;
-}
-
-void OS_X11::update_real_mouse_position() {
- Window root_return, child_return;
- int root_x, root_y, win_x, win_y;
- unsigned int mask_return;
-
- Bool xquerypointer_result = XQueryPointer(x11_display, x11_window, &root_return, &child_return, &root_x, &root_y,
- &win_x, &win_y, &mask_return);
-
- if (xquerypointer_result) {
- if (win_x > 0 && win_y > 0 && win_x <= current_videomode.width && win_y <= current_videomode.height) {
-
- last_mouse_pos.x = win_x;
- last_mouse_pos.y = win_y;
- last_mouse_pos_valid = true;
- input->set_mouse_position(last_mouse_pos);
- }
- }
-}
-
-OS_X11::OS_X11() {
-
-#ifdef PULSEAUDIO_ENABLED
- AudioDriverManager::add_driver(&driver_pulseaudio);
-#endif
-
-#ifdef ALSA_ENABLED
- AudioDriverManager::add_driver(&driver_alsa);
-#endif
-
- xi.opcode = 0;
- xi.last_relative_time = 0;
- layered_window = false;
- minimized = false;
- window_focused = true;
- xim_style = 0L;
- mouse_mode = MOUSE_MODE_VISIBLE;
- last_position_before_fs = Vector2();
-}
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
deleted file mode 100644
index 55d24d64a3..0000000000
--- a/platform/x11/os_x11.h
+++ /dev/null
@@ -1,339 +0,0 @@
-/*************************************************************************/
-/* os_x11.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 OS_X11_H
-#define OS_X11_H
-
-#include "core/os/input.h"
-#include "crash_handler_x11.h"
-#include "drivers/alsa/audio_driver_alsa.h"
-#include "drivers/alsamidi/midi_driver_alsamidi.h"
-#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
-#include "drivers/unix/os_unix.h"
-#include "joypad_linux.h"
-#include "main/input_default.h"
-#include "servers/audio_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
-
-#if defined(OPENGL_ENABLED)
-#include "context_gl_x11.h"
-#endif
-
-#if defined(VULKAN_ENABLED)
-#include "drivers/vulkan/rendering_device_vulkan.h"
-#include "platform/x11/vulkan_context_x11.h"
-#endif
-
-#include <X11/Xcursor/Xcursor.h>
-#include <X11/Xlib.h>
-#include <X11/extensions/XInput2.h>
-#include <X11/extensions/Xrandr.h>
-#include <X11/keysym.h>
-
-// Hints for X11 fullscreen
-typedef struct {
- unsigned long flags;
- unsigned long functions;
- unsigned long decorations;
- long inputMode;
- unsigned long status;
-} Hints;
-
-typedef struct _xrr_monitor_info {
- Atom name;
- Bool primary;
- Bool automatic;
- int noutput;
- int x;
- int y;
- int width;
- int height;
- int mwidth;
- int mheight;
- RROutput *outputs;
-} xrr_monitor_info;
-
-#undef CursorShape
-
-class OS_X11 : public OS_Unix {
-
- Atom wm_delete;
- Atom xdnd_enter;
- Atom xdnd_position;
- Atom xdnd_status;
- Atom xdnd_action_copy;
- Atom xdnd_drop;
- Atom xdnd_finished;
- Atom xdnd_selection;
- Atom requested;
-
- int xdnd_version;
-
-#if defined(OPENGL_ENABLED)
- ContextGL_X11 *context_gles2;
-#endif
-#if defined(VULKAN_ENABLED)
- VulkanContextX11 *context_vulkan;
- RenderingDeviceVulkan *rendering_device_vulkan;
-#endif
-
- //Rasterizer *rasterizer;
- VisualServer *visual_server;
- VideoMode current_videomode;
- List<String> args;
- Window x11_window;
- Window xdnd_source_window;
- MainLoop *main_loop;
- ::Display *x11_display;
- char *xmbstring;
- int xmblen;
- unsigned long last_timestamp;
- ::Time last_keyrelease_time;
- ::XIC xic;
- ::XIM xim;
- ::XIMStyle xim_style;
- static void xim_destroy_callback(::XIM im, ::XPointer client_data,
- ::XPointer call_data);
-
- // IME
- bool im_active;
- Vector2 im_position;
- Vector2 last_position_before_fs;
-
- Size2 min_size;
- Size2 max_size;
-
- Point2 last_mouse_pos;
- bool last_mouse_pos_valid;
- Point2i last_click_pos;
- uint64_t last_click_ms;
- int last_click_button_index;
- uint32_t last_button_state;
-
- struct {
- int opcode;
- Vector<int> touch_devices;
- Map<int, Vector2> absolute_devices;
- Map<int, Vector3> pen_devices;
- XIEventMask all_event_mask;
- XIEventMask all_master_event_mask;
- Map<int, Vector2> state;
- double pressure;
- Vector2 tilt;
- Vector2 mouse_pos_to_filter;
- Vector2 relative_motion;
- Vector2 raw_pos;
- Vector2 old_raw_pos;
- ::Time last_relative_time;
- } xi;
-
- bool refresh_device_info();
-
- unsigned int get_mouse_button_state(unsigned int p_x11_button, int p_x11_type);
- void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
- void flush_mouse_motion();
-
- MouseMode mouse_mode;
- Point2i center;
-
- void handle_key_event(XKeyEvent *p_event, bool p_echo = false);
- void process_xevents();
- virtual void delete_main_loop();
-
- bool force_quit;
- bool minimized;
- bool window_has_focus;
- bool do_mouse_warp;
-
- const char *cursor_theme;
- int cursor_size;
- XcursorImage *img[CURSOR_MAX];
- Cursor cursors[CURSOR_MAX];
- Cursor null_cursor;
- CursorShape current_cursor;
- Map<CursorShape, Vector<Variant> > cursors_cache;
-
- InputDefault *input;
-
-#ifdef JOYDEV_ENABLED
- JoypadLinux *joypad;
-#endif
-
-#ifdef ALSA_ENABLED
- AudioDriverALSA driver_alsa;
-#endif
-
-#ifdef ALSAMIDI_ENABLED
- MIDIDriverALSAMidi driver_alsamidi;
-#endif
-
-#ifdef PULSEAUDIO_ENABLED
- AudioDriverPulseAudio driver_pulseaudio;
-#endif
-
- bool layered_window;
-
- CrashHandler crash_handler;
-
- int video_driver_index;
- bool maximized;
- bool window_focused;
- //void set_wm_border(bool p_enabled);
- void set_wm_fullscreen(bool p_enabled);
- void set_wm_above(bool p_enabled);
-
- typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
- typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
- xrr_get_monitors_t xrr_get_monitors;
- xrr_free_monitors_t xrr_free_monitors;
- void *xrandr_handle;
- Bool xrandr_ext_ok;
-
-protected:
- virtual int get_current_video_driver() const;
-
- virtual void initialize_core();
- virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
- virtual void finalize();
-
- virtual void set_main_loop(MainLoop *p_main_loop);
-
- void _window_changed(XEvent *event);
-
- bool is_window_maximize_allowed();
-
-public:
- virtual String get_name() const;
-
- virtual void set_cursor_shape(CursorShape p_shape);
- virtual CursorShape get_cursor_shape() const;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
-
- void set_mouse_mode(MouseMode p_mode);
- MouseMode get_mouse_mode() const;
-
- virtual void warp_mouse_position(const Point2 &p_to);
- virtual Point2 get_mouse_position() const;
- virtual int get_mouse_button_state() const;
- virtual void set_window_title(const String &p_title);
-
- virtual void set_icon(const Ref<Image> &p_icon);
-
- virtual MainLoop *get_main_loop() const;
-
- virtual bool can_draw() const;
-
- virtual void set_clipboard(const String &p_text);
- virtual String get_clipboard() const;
-
- virtual void release_rendering_thread();
- virtual void make_rendering_thread();
- virtual void swap_buffers();
-
- virtual String get_config_path() const;
- virtual String get_data_path() const;
- virtual String get_cache_path() const;
-
- virtual String get_system_dir(SystemDir p_dir) const;
-
- virtual Error shell_open(String p_uri);
-
- virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
- virtual VideoMode get_video_mode(int p_screen = 0) const;
- virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
-
- virtual int get_screen_count() const;
- virtual int get_current_screen() const;
- virtual void set_current_screen(int p_screen);
- virtual Point2 get_screen_position(int p_screen = -1) const;
- virtual Size2 get_screen_size(int p_screen = -1) const;
- virtual int get_screen_dpi(int p_screen = -1) const;
- virtual Point2 get_window_position() const;
- virtual void set_window_position(const Point2 &p_position);
- virtual Size2 get_window_size() const;
- virtual Size2 get_real_window_size() const;
- virtual Size2 get_max_window_size() const;
- virtual Size2 get_min_window_size() const;
- virtual void set_min_window_size(const Size2 p_size);
- virtual void set_max_window_size(const Size2 p_size);
- virtual void set_window_size(const Size2 p_size);
- virtual void set_window_fullscreen(bool p_enabled);
- virtual bool is_window_fullscreen() const;
- virtual void set_window_resizable(bool p_enabled);
- virtual bool is_window_resizable() const;
- virtual void set_window_minimized(bool p_enabled);
- virtual bool is_window_minimized() const;
- virtual void set_window_maximized(bool p_enabled);
- virtual bool is_window_maximized() const;
- virtual void set_window_always_on_top(bool p_enabled);
- virtual bool is_window_always_on_top() const;
- virtual bool is_window_focused() const;
- virtual void request_attention();
-
- virtual void set_borderless_window(bool p_borderless);
- virtual bool get_borderless_window();
-
- virtual bool get_window_per_pixel_transparency_enabled() const;
- virtual void set_window_per_pixel_transparency_enabled(bool p_enabled);
-
- virtual void set_ime_active(const bool p_active);
- virtual void set_ime_position(const Point2 &p_pos);
-
- virtual String get_unique_id() const;
-
- virtual void move_window_to_foreground();
- virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
-
- virtual bool is_joy_known(int p_device);
- virtual String get_joy_guid(int p_device) const;
-
- virtual void set_context(int p_context);
-
- virtual void _set_use_vsync(bool p_enable);
- //virtual bool is_vsync_enabled() const;
-
- virtual bool _check_internal_feature_support(const String &p_feature);
-
- virtual void force_process_input();
- void run();
-
- void disable_crash_handler();
- bool is_disable_crash_handler() const;
-
- virtual Error move_to_trash(const String &p_path);
-
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
-
- void update_real_mouse_position();
- OS_X11();
-};
-
-#endif
diff --git a/platform/x11/platform_x11_builders.py b/platform/x11/platform_x11_builders.py
deleted file mode 100644
index 5ff0c6fb14..0000000000
--- a/platform/x11/platform_x11_builders.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Functions used to generate source files during build time
-
-All such functions are invoked in a subprocess on Windows to prevent build flakiness.
-
-"""
-import os
-from platform_methods import subprocess_main
-
-
-def make_debug_x11(target, source, env):
- os.system('objcopy --only-keep-debug {0} {0}.debugsymbols'.format(target[0]))
- os.system('strip --strip-debug --strip-unneeded {0}'.format(target[0]))
- os.system('objcopy --add-gnu-debuglink={0}.debugsymbols {0}'.format(target[0]))
-
-
-if __name__ == '__main__':
- subprocess_main(globals())
diff --git a/platform/x11/vulkan_context_x11.cpp b/platform/x11/vulkan_context_x11.cpp
deleted file mode 100644
index 602dbc77a2..0000000000
--- a/platform/x11/vulkan_context_x11.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*************************************************************************/
-/* vulkan_context_x11.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "vulkan_context_x11.h"
-#include <vulkan/vulkan_xlib.h>
-
-const char *VulkanContextX11::_get_platform_surface_extension() const {
- return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
-}
-
-int VulkanContextX11::window_create(::Window p_window, Display *p_display, int p_width, int p_height) {
-
- VkXlibSurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = NULL;
- createInfo.flags = 0;
- createInfo.dpy = p_display;
- createInfo.window = p_window;
-
- VkSurfaceKHR surface;
- VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, NULL, &surface);
- ERR_FAIL_COND_V(err, -1);
- return _window_create(surface, p_width, p_height);
-}
-
-VulkanContextX11::VulkanContextX11() {
-}
-
-VulkanContextX11::~VulkanContextX11() {
-}
diff --git a/platform/x11/vulkan_context_x11.h b/platform/x11/vulkan_context_x11.h
deleted file mode 100644
index 573f994ea6..0000000000
--- a/platform/x11/vulkan_context_x11.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* vulkan_context_x11.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VULKAN_DEVICE_X11_H
-#define VULKAN_DEVICE_X11_H
-
-#include "drivers/vulkan/vulkan_context.h"
-#include <X11/Xlib.h>
-
-class VulkanContextX11 : public VulkanContext {
-
- virtual const char *_get_platform_surface_extension() const;
-
-public:
- int window_create(::Window p_window, Display *p_display, int p_width, int p_height);
-
- VulkanContextX11();
- ~VulkanContextX11();
-};
-
-#endif // VULKAN_DEVICE_X11_H
diff --git a/platform_methods.py b/platform_methods.py
index 4300216427..805d7de82a 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -7,14 +7,10 @@ import subprocess
# NOTE: The multiprocessing module is not compatible with SCons due to conflict on cPickle
-if sys.version_info[0] < 3:
- JSON_SERIALIZABLE_TYPES = (bool, int, long, float, basestring)
-else:
- JSON_SERIALIZABLE_TYPES = (bool, int, float, str)
+JSON_SERIALIZABLE_TYPES = (bool, int, float, str)
def run_in_subprocess(builder_function):
-
@functools.wraps(builder_function)
def wrapper(target, source, env):
@@ -23,38 +19,36 @@ def run_in_subprocess(builder_function):
source = [node.srcnode().abspath for node in source]
# Short circuit on non-Windows platforms, no need to run in subprocess
- if sys.platform not in ('win32', 'cygwin'):
+ if sys.platform not in ("win32", "cygwin"):
return builder_function(target, source, env)
# Identify module
module_name = builder_function.__module__
function_name = builder_function.__name__
module_path = sys.modules[module_name].__file__
- if module_path.endswith('.pyc') or module_path.endswith('.pyo'):
+ if module_path.endswith(".pyc") or module_path.endswith(".pyo"):
module_path = module_path[:-1]
# Subprocess environment
subprocess_env = os.environ.copy()
- subprocess_env['PYTHONPATH'] = os.pathsep.join([os.getcwd()] + sys.path)
+ subprocess_env["PYTHONPATH"] = os.pathsep.join([os.getcwd()] + sys.path)
# Keep only JSON serializable environment items
- filtered_env = dict(
- (key, value)
- for key, value in env.items()
- if isinstance(value, JSON_SERIALIZABLE_TYPES)
- )
+ filtered_env = dict((key, value) for key, value in env.items() if isinstance(value, JSON_SERIALIZABLE_TYPES))
# Save parameters
args = (target, source, filtered_env)
data = dict(fn=function_name, args=args)
- json_path = os.path.join(os.environ['TMP'], uuid.uuid4().hex + '.json')
- with open(json_path, 'wt') as json_file:
+ json_path = os.path.join(os.environ["TMP"], uuid.uuid4().hex + ".json")
+ with open(json_path, "wt") as json_file:
json.dump(data, json_file, indent=2)
json_file_size = os.stat(json_path).st_size
- print('Executing builder function in subprocess: '
- 'module_path=%r, parameter_file=%r, parameter_file_size=%r, target=%r, source=%r' % (
- module_path, json_path, json_file_size, target, source))
+ print(
+ "Executing builder function in subprocess: "
+ "module_path=%r, parameter_file=%r, parameter_file_size=%r, target=%r, source=%r"
+ % (module_path, json_path, json_file_size, target, source)
+ )
try:
exit_code = subprocess.call([sys.executable, module_path, json_path], env=subprocess_env)
finally:
@@ -62,13 +56,15 @@ def run_in_subprocess(builder_function):
os.remove(json_path)
except (OSError, IOError) as e:
# Do not fail the entire build if it cannot delete a temporary file
- print('WARNING: Could not delete temporary file: path=%r; [%s] %s' %
- (json_path, e.__class__.__name__, e))
+ print(
+ "WARNING: Could not delete temporary file: path=%r; [%s] %s" % (json_path, e.__class__.__name__, e)
+ )
# Must succeed
if exit_code:
raise RuntimeError(
- 'Failed to run builder function in subprocess: module_path=%r; data=%r' % (module_path, data))
+ "Failed to run builder function in subprocess: module_path=%r; data=%r" % (module_path, data)
+ )
return wrapper
@@ -78,5 +74,5 @@ def subprocess_main(namespace):
with open(sys.argv[1]) as json_file:
data = json.load(json_file)
- fn = namespace[data['fn']]
- fn(*data['args'])
+ fn = namespace[data["fn"]]
+ fn(*data["args"])
diff --git a/scene/2d/SCsub b/scene/2d/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/2d/SCsub
+++ b/scene/2d/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
deleted file mode 100644
index f3f7ba9ddd..0000000000
--- a/scene/2d/animated_sprite.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-/*************************************************************************/
-/* animated_sprite.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "animated_sprite.h"
-
-#include "core/os/os.h"
-#include "scene/scene_string_names.h"
-
-#define NORMAL_SUFFIX "_normal"
-#define SPECULAR_SUFFIX "_specular"
-
-#ifdef TOOLS_ENABLED
-Dictionary AnimatedSprite::_edit_get_state() const {
- Dictionary state = Node2D::_edit_get_state();
- state["offset"] = offset;
- return state;
-}
-
-void AnimatedSprite::_edit_set_state(const Dictionary &p_state) {
- Node2D::_edit_set_state(p_state);
- set_offset(p_state["offset"]);
-}
-
-void AnimatedSprite::_edit_set_pivot(const Point2 &p_pivot) {
- set_offset(get_offset() - p_pivot);
- set_position(get_transform().xform(p_pivot));
-}
-
-Point2 AnimatedSprite::_edit_get_pivot() const {
- return Vector2();
-}
-
-bool AnimatedSprite::_edit_use_pivot() const {
- return true;
-}
-
-Rect2 AnimatedSprite::_edit_get_rect() const {
- return _get_rect();
-}
-
-bool AnimatedSprite::_edit_use_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
- return false;
- }
- Ref<Texture2D> t;
- if (animation)
- t = frames->get_frame(animation, frame);
- return t.is_valid();
-}
-#endif
-
-Rect2 AnimatedSprite::get_anchorable_rect() const {
- return _get_rect();
-}
-
-Rect2 AnimatedSprite::_get_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
- return Rect2();
- }
-
- Ref<Texture2D> t;
- if (animation)
- t = frames->get_frame(animation, frame);
- if (t.is_null())
- return Rect2();
- Size2 s = t->get_size();
-
- Point2 ofs = offset;
- if (centered)
- ofs -= Size2(s) / 2;
-
- if (s == Size2(0, 0))
- s = Size2(1, 1);
-
- 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();
- animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX;
- animations[p_anim].specular_name = String(p_anim) + SPECULAR_SUFFIX;
-}
-
-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;
- animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX;
- animations[p_next].specular_name = String(p_next) + SPECULAR_SUFFIX;
-}
-
-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 AnimatedSprite::_validate_property(PropertyInfo &property) const {
-
- if (!frames.is_valid())
- return;
- if (property.name == "animation") {
-
- property.hint = PROPERTY_HINT_ENUM;
- List<StringName> names;
- frames->get_animation_list(&names);
- names.sort_custom<StringName::AlphCompare>();
-
- bool current_found = false;
-
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- if (E->prev()) {
- property.hint_string += ",";
- }
-
- property.hint_string += String(E->get());
- if (animation == E->get()) {
- current_found = true;
- }
- }
-
- if (!current_found) {
- if (property.hint_string == String()) {
- property.hint_string = String(animation);
- } else {
- property.hint_string = String(animation) + "," + property.hint_string;
- }
- }
- }
-
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
- if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) {
- property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
- }
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
- }
-}
-
-void AnimatedSprite::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_INTERNAL_PROCESS: {
-
- if (frames.is_null())
- return;
- if (!frames->has_animation(animation))
- return;
- if (frame < 0)
- return;
-
- float speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0)
- return; //do nothing
-
- float remaining = get_process_delta_time();
-
- while (remaining) {
-
- if (timeout <= 0) {
-
- timeout = _get_frame_duration();
-
- int fc = frames->get_frame_count(animation);
- if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) {
- if (frames->get_animation_loop(animation)) {
- if (backwards)
- frame = fc - 1;
- else
- frame = 0;
-
- emit_signal(SceneStringNames::get_singleton()->animation_finished);
- } else {
- if (backwards)
- frame = 0;
- else
- frame = fc - 1;
-
- if (!is_over) {
- is_over = true;
- emit_signal(SceneStringNames::get_singleton()->animation_finished);
- }
- }
- } else {
- if (backwards)
- frame--;
- else
- frame++;
- }
-
- update();
- _change_notify("frame");
- emit_signal(SceneStringNames::get_singleton()->frame_changed);
- }
-
- float to_process = MIN(timeout, remaining);
- remaining -= to_process;
- timeout -= to_process;
- }
- } break;
-
- case NOTIFICATION_DRAW: {
-
- if (frames.is_null())
- return;
- if (frame < 0)
- return;
- if (!frames->has_animation(animation))
- return;
-
- Ref<Texture2D> texture = frames->get_frame(animation, frame);
- if (texture.is_null())
- return;
-
- Ref<Texture2D> normal = frames->get_normal_frame(animation, frame);
- Ref<Texture2D> specular = frames->get_specular_frame(animation, frame);
-
- RID ci = get_canvas_item();
-
- Size2i s;
- s = texture->get_size();
- Point2 ofs = offset;
- if (centered)
- ofs -= s / 2;
-
- if (Engine::get_singleton()->get_use_pixel_snap()) {
- ofs = ofs.floor();
- }
- Rect2 dst_rect(ofs, s);
-
- if (hflip)
- dst_rect.size.x = -dst_rect.size.x;
- if (vflip)
- dst_rect.size.y = -dst_rect.size.y;
-
- texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess));
-
- } break;
- }
-}
-
-void AnimatedSprite::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
-
- if (frames.is_valid())
- frames->disconnect("changed", callable_mp(this, &AnimatedSprite::_res_changed));
- frames = p_frames;
- if (frames.is_valid())
- frames->connect("changed", callable_mp(this, &AnimatedSprite::_res_changed));
-
- if (!frames.is_valid()) {
- frame = 0;
- } else {
- set_frame(frame);
- }
-
- _change_notify();
- _reset_timeout();
- update();
- update_configuration_warning();
-}
-
-Ref<SpriteFrames> AnimatedSprite::get_sprite_frames() const {
-
- return frames;
-}
-
-void AnimatedSprite::set_frame(int p_frame) {
-
- if (!frames.is_valid()) {
- return;
- }
-
- if (frames->has_animation(animation)) {
- int limit = frames->get_frame_count(animation);
- if (p_frame >= limit)
- p_frame = limit - 1;
- }
-
- if (p_frame < 0)
- p_frame = 0;
-
- if (frame == p_frame)
- return;
-
- frame = p_frame;
- _reset_timeout();
- update();
- _change_notify("frame");
- emit_signal(SceneStringNames::get_singleton()->frame_changed);
-}
-int AnimatedSprite::get_frame() const {
-
- return frame;
-}
-
-void AnimatedSprite::set_speed_scale(float p_speed_scale) {
-
- float elapsed = _get_frame_duration() - timeout;
-
- speed_scale = MAX(p_speed_scale, 0.0f);
-
- // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed
- _reset_timeout();
- timeout -= elapsed;
-}
-
-float AnimatedSprite::get_speed_scale() const {
-
- return speed_scale;
-}
-
-void AnimatedSprite::set_centered(bool p_center) {
-
- centered = p_center;
- update();
- item_rect_changed();
-}
-
-bool AnimatedSprite::is_centered() const {
-
- return centered;
-}
-
-void AnimatedSprite::set_offset(const Point2 &p_offset) {
-
- offset = p_offset;
- update();
- item_rect_changed();
- _change_notify("offset");
-}
-Point2 AnimatedSprite::get_offset() const {
-
- return offset;
-}
-
-void AnimatedSprite::set_flip_h(bool p_flip) {
-
- hflip = p_flip;
- update();
-}
-bool AnimatedSprite::is_flipped_h() const {
-
- return hflip;
-}
-
-void AnimatedSprite::set_flip_v(bool p_flip) {
-
- vflip = p_flip;
- update();
-}
-bool AnimatedSprite::is_flipped_v() const {
-
- return vflip;
-}
-
-void AnimatedSprite::_res_changed() {
-
- set_frame(frame);
- _change_notify("frame");
- _change_notify("animation");
- update();
-}
-
-void AnimatedSprite::_set_playing(bool p_playing) {
-
- if (playing == p_playing)
- return;
- playing = p_playing;
- _reset_timeout();
- set_process_internal(playing);
-}
-
-bool AnimatedSprite::_is_playing() const {
-
- return playing;
-}
-
-void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) {
-
- backwards = p_backwards;
-
- if (p_animation) {
- set_animation(p_animation);
- if (backwards && get_frame() == 0)
- set_frame(frames->get_frame_count(p_animation) - 1);
- }
-
- _set_playing(true);
-}
-
-void AnimatedSprite::stop() {
-
- _set_playing(false);
-}
-
-bool AnimatedSprite::is_playing() const {
-
- return playing;
-}
-
-float AnimatedSprite::_get_frame_duration() {
- if (frames.is_valid() && frames->has_animation(animation)) {
- float speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed > 0) {
- return 1.0 / speed;
- }
- }
- return 0.0;
-}
-
-void AnimatedSprite::_reset_timeout() {
-
- if (!playing)
- return;
-
- timeout = _get_frame_duration();
- is_over = false;
-}
-
-void AnimatedSprite::set_animation(const StringName &p_animation) {
-
- ERR_FAIL_COND_MSG(frames == NULL, vformat("There is no animation with name '%s'.", p_animation));
- ERR_FAIL_COND_MSG(frames->get_animation_names().find(p_animation) == -1, vformat("There is no animation with name '%s'.", p_animation));
-
- if (animation == p_animation)
- return;
-
- animation = p_animation;
- _reset_timeout();
- set_frame(0);
- _change_notify();
- update();
-}
-StringName AnimatedSprite::get_animation() const {
-
- return animation;
-}
-
-String AnimatedSprite::get_configuration_warning() const {
-
- if (frames.is_null()) {
- return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
- }
-
- return String();
-}
-
-void AnimatedSprite::set_specular_color(const Color &p_color) {
- specular_color = p_color;
- update();
-}
-
-Color AnimatedSprite::get_specular_color() const {
- return specular_color;
-}
-
-void AnimatedSprite::set_shininess(float p_shininess) {
- shininess = CLAMP(p_shininess, 0.0, 1.0);
- update();
-}
-
-float AnimatedSprite::get_shininess() const {
- return shininess;
-}
-
-void AnimatedSprite::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite::set_sprite_frames);
- ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite::get_sprite_frames);
-
- ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite::set_animation);
- ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite::get_animation);
-
- ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite::_set_playing);
- ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite::_is_playing);
-
- ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite::stop);
- ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite::is_playing);
-
- ClassDB::bind_method(D_METHOD("set_centered", "centered"), &AnimatedSprite::set_centered);
- ClassDB::bind_method(D_METHOD("is_centered"), &AnimatedSprite::is_centered);
-
- ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AnimatedSprite::set_offset);
- ClassDB::bind_method(D_METHOD("get_offset"), &AnimatedSprite::get_offset);
-
- ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &AnimatedSprite::set_flip_h);
- ClassDB::bind_method(D_METHOD("is_flipped_h"), &AnimatedSprite::is_flipped_h);
-
- ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &AnimatedSprite::set_flip_v);
- ClassDB::bind_method(D_METHOD("is_flipped_v"), &AnimatedSprite::is_flipped_v);
-
- ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite::set_frame);
- ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite::get_frame);
-
- ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite::set_speed_scale);
- ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite::get_speed_scale);
-
- ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &AnimatedSprite::set_specular_color);
- ClassDB::bind_method(D_METHOD("get_specular_color"), &AnimatedSprite::get_specular_color);
-
- ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &AnimatedSprite::set_shininess);
- ClassDB::bind_method(D_METHOD("get_shininess"), &AnimatedSprite::get_shininess);
-
- ADD_SIGNAL(MethodInfo("frame_changed"));
- ADD_SIGNAL(MethodInfo("animation_finished"));
-
- ADD_GROUP("Animation", "");
- 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");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
- ADD_GROUP("Lighting", "");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
- ADD_GROUP("Offset", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
-}
-
-AnimatedSprite::AnimatedSprite() {
-
- centered = true;
- hflip = false;
- vflip = false;
-
- frame = 0;
- speed_scale = 1.0f;
- playing = false;
- backwards = false;
- animation = "default";
- timeout = 0;
- is_over = false;
- specular_color = Color(1, 1, 1, 1);
- shininess = 1.0;
-}
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
deleted file mode 100644
index 37d093e3d8..0000000000
--- a/scene/2d/animated_sprite.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/*************************************************************************/
-/* animated_sprite.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 ANIMATED_SPRITE_H
-#define ANIMATED_SPRITE_H
-
-#include "scene/2d/node_2d.h"
-#include "scene/resources/texture.h"
-
-class SpriteFrames : public Resource {
-
- GDCLASS(SpriteFrames, Resource);
-
- struct Anim {
-
- float speed;
- bool loop;
- Vector<Ref<Texture2D> > frames;
-
- Anim() {
- loop = true;
- speed = 5;
- }
-
- StringName normal_name;
- StringName specular_name;
- };
-
- Color specular_color;
- float shininess;
-
- 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];
- }
-
- _FORCE_INLINE_ Ref<Texture2D> get_normal_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>());
-
- const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name);
-
- if (!EN || p_idx >= EN->get().frames.size())
- return Ref<Texture2D>();
-
- return EN->get().frames[p_idx];
- }
-
- _FORCE_INLINE_ Ref<Texture2D> get_specular_frame(const StringName &p_anim, int p_idx) const {
-
- const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V(!E, Ref<Texture2D>());
- ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
-
- const Map<StringName, Anim>::Element *EN = animations.find(E->get().specular_name);
-
- if (!EN || p_idx >= EN->get().frames.size())
- return Ref<Texture2D>();
-
- return EN->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 AnimatedSprite : public Node2D {
-
- GDCLASS(AnimatedSprite, Node2D);
-
- Ref<SpriteFrames> frames;
- bool playing;
- bool backwards;
- StringName animation;
- int frame;
- float speed_scale;
-
- bool centered;
- Point2 offset;
-
- bool is_over;
- float timeout;
-
- bool hflip;
- bool vflip;
-
- void _res_changed();
-
- float _get_frame_duration();
- void _reset_timeout();
- void _set_playing(bool p_playing);
- bool _is_playing() const;
- Rect2 _get_rect() const;
-
- Color specular_color;
- float shininess;
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const;
-
-public:
-#ifdef TOOLS_ENABLED
- virtual Dictionary _edit_get_state() const;
- virtual void _edit_set_state(const Dictionary &p_state);
-
- virtual void _edit_set_pivot(const Point2 &p_pivot);
- virtual Point2 _edit_get_pivot() const;
- virtual bool _edit_use_pivot() const;
- virtual Rect2 _edit_get_rect() const;
- virtual bool _edit_use_rect() const;
-#endif
-
- virtual Rect2 get_anchorable_rect() const;
-
- void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
- Ref<SpriteFrames> get_sprite_frames() const;
-
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
- void stop();
- bool is_playing() const;
-
- void set_animation(const StringName &p_animation);
- StringName get_animation() const;
-
- void set_frame(int p_frame);
- int get_frame() const;
-
- void set_speed_scale(float p_speed_scale);
- float get_speed_scale() const;
-
- void set_centered(bool p_center);
- bool is_centered() const;
-
- void set_offset(const Point2 &p_offset);
- Point2 get_offset() const;
-
- void set_flip_h(bool p_flip);
- bool is_flipped_h() const;
-
- void set_flip_v(bool p_flip);
- bool is_flipped_v() const;
-
- void set_specular_color(const Color &p_color);
- Color get_specular_color() const;
-
- void set_shininess(float p_shininess);
- float get_shininess() const;
-
- virtual String get_configuration_warning() const;
- AnimatedSprite();
-};
-
-#endif // ANIMATED_SPRITE_H
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
new file mode 100644
index 0000000000..fc34f967ce
--- /dev/null
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -0,0 +1,772 @@
+/*************************************************************************/
+/* animated_sprite_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "animated_sprite_2d.h"
+
+#include "core/os/os.h"
+#include "scene/scene_string_names.h"
+
+#define NORMAL_SUFFIX "_normal"
+#define SPECULAR_SUFFIX "_specular"
+
+#ifdef TOOLS_ENABLED
+Dictionary AnimatedSprite2D::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["offset"] = offset;
+ return state;
+}
+
+void AnimatedSprite2D::_edit_set_state(const Dictionary &p_state) {
+ Node2D::_edit_set_state(p_state);
+ set_offset(p_state["offset"]);
+}
+
+void AnimatedSprite2D::_edit_set_pivot(const Point2 &p_pivot) {
+ set_offset(get_offset() - p_pivot);
+ set_position(get_transform().xform(p_pivot));
+}
+
+Point2 AnimatedSprite2D::_edit_get_pivot() const {
+ return Vector2();
+}
+
+bool AnimatedSprite2D::_edit_use_pivot() const {
+ return true;
+}
+
+Rect2 AnimatedSprite2D::_edit_get_rect() const {
+ return _get_rect();
+}
+
+bool AnimatedSprite2D::_edit_use_rect() const {
+ if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return false;
+ }
+ Ref<Texture2D> t;
+ if (animation)
+ t = frames->get_frame(animation, frame);
+ return t.is_valid();
+}
+#endif
+
+Rect2 AnimatedSprite2D::get_anchorable_rect() const {
+ return _get_rect();
+}
+
+Rect2 AnimatedSprite2D::_get_rect() const {
+ if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return Rect2();
+ }
+
+ Ref<Texture2D> t;
+ if (animation)
+ t = frames->get_frame(animation, frame);
+ if (t.is_null())
+ return Rect2();
+ Size2 s = t->get_size();
+
+ Point2 ofs = offset;
+ if (centered)
+ ofs -= Size2(s) / 2;
+
+ if (s == Size2(0, 0))
+ s = Size2(1, 1);
+
+ 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();
+ animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX;
+ animations[p_anim].specular_name = String(p_anim) + SPECULAR_SUFFIX;
+}
+
+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;
+ animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX;
+ animations[p_next].specular_name = String(p_next) + SPECULAR_SUFFIX;
+}
+
+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;
+ if (property.name == "animation") {
+
+ property.hint = PROPERTY_HINT_ENUM;
+ List<StringName> names;
+ frames->get_animation_list(&names);
+ names.sort_custom<StringName::AlphCompare>();
+
+ bool current_found = false;
+
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (E->prev()) {
+ property.hint_string += ",";
+ }
+
+ property.hint_string += String(E->get());
+ if (animation == E->get()) {
+ current_found = true;
+ }
+ }
+
+ if (!current_found) {
+ if (property.hint_string == String()) {
+ property.hint_string = String(animation);
+ } else {
+ property.hint_string = String(animation) + "," + property.hint_string;
+ }
+ }
+ }
+
+ if (property.name == "frame") {
+ property.hint = PROPERTY_HINT_RANGE;
+ if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) {
+ property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ }
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
+}
+
+void AnimatedSprite2D::_notification(int p_what) {
+
+ switch (p_what) {
+ case NOTIFICATION_INTERNAL_PROCESS: {
+
+ if (frames.is_null())
+ return;
+ if (!frames->has_animation(animation))
+ return;
+ if (frame < 0)
+ return;
+
+ float speed = frames->get_animation_speed(animation) * speed_scale;
+ if (speed == 0)
+ return; //do nothing
+
+ float remaining = get_process_delta_time();
+
+ while (remaining) {
+
+ if (timeout <= 0) {
+
+ timeout = _get_frame_duration();
+
+ int fc = frames->get_frame_count(animation);
+ if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) {
+ if (frames->get_animation_loop(animation)) {
+ if (backwards)
+ frame = fc - 1;
+ else
+ frame = 0;
+
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ if (backwards)
+ frame = 0;
+ else
+ frame = fc - 1;
+
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
+ } else {
+ if (backwards)
+ frame--;
+ else
+ frame++;
+ }
+
+ update();
+ _change_notify("frame");
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
+ }
+
+ float to_process = MIN(timeout, remaining);
+ remaining -= to_process;
+ timeout -= to_process;
+ }
+ } break;
+
+ case NOTIFICATION_DRAW: {
+
+ if (frames.is_null())
+ return;
+ if (frame < 0)
+ return;
+ if (!frames->has_animation(animation))
+ return;
+
+ Ref<Texture2D> texture = frames->get_frame(animation, frame);
+ if (texture.is_null())
+ return;
+
+ Ref<Texture2D> normal = frames->get_normal_frame(animation, frame);
+ Ref<Texture2D> specular = frames->get_specular_frame(animation, frame);
+
+ RID ci = get_canvas_item();
+
+ Size2i s;
+ s = texture->get_size();
+ Point2 ofs = offset;
+ if (centered)
+ ofs -= s / 2;
+
+ if (Engine::get_singleton()->get_use_pixel_snap()) {
+ ofs = ofs.floor();
+ }
+ Rect2 dst_rect(ofs, s);
+
+ if (hflip)
+ dst_rect.size.x = -dst_rect.size.x;
+ if (vflip)
+ dst_rect.size.y = -dst_rect.size.y;
+
+ texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess));
+
+ } break;
+ }
+}
+
+void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
+
+ if (frames.is_valid())
+ frames->disconnect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames = p_frames;
+ if (frames.is_valid())
+ frames->connect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+
+ if (!frames.is_valid()) {
+ frame = 0;
+ } else {
+ set_frame(frame);
+ }
+
+ _change_notify();
+ _reset_timeout();
+ update();
+ update_configuration_warning();
+}
+
+Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
+
+ return frames;
+}
+
+void AnimatedSprite2D::set_frame(int p_frame) {
+
+ if (!frames.is_valid()) {
+ return;
+ }
+
+ if (frames->has_animation(animation)) {
+ int limit = frames->get_frame_count(animation);
+ if (p_frame >= limit)
+ p_frame = limit - 1;
+ }
+
+ if (p_frame < 0)
+ p_frame = 0;
+
+ if (frame == p_frame)
+ return;
+
+ frame = p_frame;
+ _reset_timeout();
+ update();
+ _change_notify("frame");
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
+}
+int AnimatedSprite2D::get_frame() const {
+
+ return frame;
+}
+
+void AnimatedSprite2D::set_speed_scale(float p_speed_scale) {
+
+ float elapsed = _get_frame_duration() - timeout;
+
+ speed_scale = MAX(p_speed_scale, 0.0f);
+
+ // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed
+ _reset_timeout();
+ timeout -= elapsed;
+}
+
+float AnimatedSprite2D::get_speed_scale() const {
+
+ return speed_scale;
+}
+
+void AnimatedSprite2D::set_centered(bool p_center) {
+
+ centered = p_center;
+ update();
+ item_rect_changed();
+}
+
+bool AnimatedSprite2D::is_centered() const {
+
+ return centered;
+}
+
+void AnimatedSprite2D::set_offset(const Point2 &p_offset) {
+
+ offset = p_offset;
+ update();
+ item_rect_changed();
+ _change_notify("offset");
+}
+Point2 AnimatedSprite2D::get_offset() const {
+
+ return offset;
+}
+
+void AnimatedSprite2D::set_flip_h(bool p_flip) {
+
+ hflip = p_flip;
+ update();
+}
+bool AnimatedSprite2D::is_flipped_h() const {
+
+ return hflip;
+}
+
+void AnimatedSprite2D::set_flip_v(bool p_flip) {
+
+ vflip = p_flip;
+ update();
+}
+bool AnimatedSprite2D::is_flipped_v() const {
+
+ return vflip;
+}
+
+void AnimatedSprite2D::_res_changed() {
+
+ set_frame(frame);
+ _change_notify("frame");
+ _change_notify("animation");
+ update();
+}
+
+void AnimatedSprite2D::_set_playing(bool p_playing) {
+
+ if (playing == p_playing)
+ return;
+ playing = p_playing;
+ _reset_timeout();
+ set_process_internal(playing);
+}
+
+bool AnimatedSprite2D::_is_playing() const {
+
+ return playing;
+}
+
+void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) {
+
+ backwards = p_backwards;
+
+ if (p_animation) {
+ set_animation(p_animation);
+ if (backwards && get_frame() == 0)
+ set_frame(frames->get_frame_count(p_animation) - 1);
+ }
+
+ _set_playing(true);
+}
+
+void AnimatedSprite2D::stop() {
+
+ _set_playing(false);
+}
+
+bool AnimatedSprite2D::is_playing() const {
+
+ return playing;
+}
+
+float AnimatedSprite2D::_get_frame_duration() {
+ if (frames.is_valid() && frames->has_animation(animation)) {
+ float speed = frames->get_animation_speed(animation) * speed_scale;
+ if (speed > 0) {
+ return 1.0 / speed;
+ }
+ }
+ return 0.0;
+}
+
+void AnimatedSprite2D::_reset_timeout() {
+
+ if (!playing)
+ return;
+
+ timeout = _get_frame_duration();
+ is_over = false;
+}
+
+void AnimatedSprite2D::set_animation(const StringName &p_animation) {
+
+ ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation));
+ ERR_FAIL_COND_MSG(frames->get_animation_names().find(p_animation) == -1, vformat("There is no animation with name '%s'.", p_animation));
+
+ if (animation == p_animation)
+ return;
+
+ animation = p_animation;
+ _reset_timeout();
+ set_frame(0);
+ _change_notify();
+ update();
+}
+StringName AnimatedSprite2D::get_animation() const {
+
+ return animation;
+}
+
+String AnimatedSprite2D::get_configuration_warning() const {
+
+ if (frames.is_null()) {
+ return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
+ }
+
+ return String();
+}
+
+void AnimatedSprite2D::set_specular_color(const Color &p_color) {
+ specular_color = p_color;
+ update();
+}
+
+Color AnimatedSprite2D::get_specular_color() const {
+ return specular_color;
+}
+
+void AnimatedSprite2D::set_shininess(float p_shininess) {
+ shininess = CLAMP(p_shininess, 0.0, 1.0);
+ update();
+}
+
+float AnimatedSprite2D::get_shininess() const {
+ return shininess;
+}
+
+void AnimatedSprite2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite2D::set_sprite_frames);
+ ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite2D::get_sprite_frames);
+
+ ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite2D::set_animation);
+ ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite2D::get_animation);
+
+ ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite2D::_set_playing);
+ ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite2D::_is_playing);
+
+ ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite2D::play, DEFVAL(StringName()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite2D::stop);
+ ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite2D::is_playing);
+
+ ClassDB::bind_method(D_METHOD("set_centered", "centered"), &AnimatedSprite2D::set_centered);
+ ClassDB::bind_method(D_METHOD("is_centered"), &AnimatedSprite2D::is_centered);
+
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AnimatedSprite2D::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &AnimatedSprite2D::get_offset);
+
+ ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &AnimatedSprite2D::set_flip_h);
+ ClassDB::bind_method(D_METHOD("is_flipped_h"), &AnimatedSprite2D::is_flipped_h);
+
+ ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &AnimatedSprite2D::set_flip_v);
+ ClassDB::bind_method(D_METHOD("is_flipped_v"), &AnimatedSprite2D::is_flipped_v);
+
+ ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite2D::set_frame);
+ ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite2D::get_frame);
+
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite2D::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite2D::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &AnimatedSprite2D::set_specular_color);
+ ClassDB::bind_method(D_METHOD("get_specular_color"), &AnimatedSprite2D::get_specular_color);
+
+ ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &AnimatedSprite2D::set_shininess);
+ ClassDB::bind_method(D_METHOD("get_shininess"), &AnimatedSprite2D::get_shininess);
+
+ ADD_SIGNAL(MethodInfo("frame_changed"));
+ ADD_SIGNAL(MethodInfo("animation_finished"));
+
+ ADD_GROUP("Animation", "");
+ 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");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
+ ADD_GROUP("Lighting", "");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
+ ADD_GROUP("Offset", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
+}
+
+AnimatedSprite2D::AnimatedSprite2D() {
+
+ centered = true;
+ hflip = false;
+ vflip = false;
+
+ frame = 0;
+ speed_scale = 1.0f;
+ playing = false;
+ backwards = false;
+ animation = "default";
+ timeout = 0;
+ is_over = false;
+ specular_color = Color(1, 1, 1, 1);
+ shininess = 1.0;
+}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
new file mode 100644
index 0000000000..726ecefd32
--- /dev/null
+++ b/scene/2d/animated_sprite_2d.h
@@ -0,0 +1,231 @@
+/*************************************************************************/
+/* animated_sprite_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 ANIMATED_SPRITE_2D_H
+#define ANIMATED_SPRITE_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/texture.h"
+
+class SpriteFrames : public Resource {
+
+ GDCLASS(SpriteFrames, Resource);
+
+ struct Anim {
+
+ float speed;
+ bool loop;
+ Vector<Ref<Texture2D>> frames;
+
+ Anim() {
+ loop = true;
+ speed = 5;
+ }
+
+ StringName normal_name;
+ StringName specular_name;
+ };
+
+ Color specular_color;
+ float shininess;
+
+ 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];
+ }
+
+ _FORCE_INLINE_ Ref<Texture2D> get_normal_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>());
+
+ const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name);
+
+ if (!EN || p_idx >= EN->get().frames.size())
+ return Ref<Texture2D>();
+
+ return EN->get().frames[p_idx];
+ }
+
+ _FORCE_INLINE_ Ref<Texture2D> get_specular_frame(const StringName &p_anim, int p_idx) const {
+
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V(!E, Ref<Texture2D>());
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+
+ const Map<StringName, Anim>::Element *EN = animations.find(E->get().specular_name);
+
+ if (!EN || p_idx >= EN->get().frames.size())
+ return Ref<Texture2D>();
+
+ return EN->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);
+
+ Ref<SpriteFrames> frames;
+ bool playing;
+ bool backwards;
+ StringName animation;
+ int frame;
+ float speed_scale;
+
+ bool centered;
+ Point2 offset;
+
+ bool is_over;
+ float timeout;
+
+ bool hflip;
+ bool vflip;
+
+ void _res_changed();
+
+ float _get_frame_duration();
+ void _reset_timeout();
+ void _set_playing(bool p_playing);
+ bool _is_playing() const;
+ Rect2 _get_rect() const;
+
+ Color specular_color;
+ float shininess;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+#ifdef TOOLS_ENABLED
+ virtual Dictionary _edit_get_state() const;
+ virtual void _edit_set_state(const Dictionary &p_state);
+
+ virtual void _edit_set_pivot(const Point2 &p_pivot);
+ virtual Point2 _edit_get_pivot() const;
+ virtual bool _edit_use_pivot() const;
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
+#endif
+
+ virtual Rect2 get_anchorable_rect() const;
+
+ void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
+ Ref<SpriteFrames> get_sprite_frames() const;
+
+ void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void stop();
+ bool is_playing() const;
+
+ void set_animation(const StringName &p_animation);
+ StringName get_animation() const;
+
+ void set_frame(int p_frame);
+ int get_frame() const;
+
+ void set_speed_scale(float p_speed_scale);
+ float get_speed_scale() const;
+
+ void set_centered(bool p_center);
+ bool is_centered() const;
+
+ void set_offset(const Point2 &p_offset);
+ Point2 get_offset() const;
+
+ void set_flip_h(bool p_flip);
+ bool is_flipped_h() const;
+
+ void set_flip_v(bool p_flip);
+ bool is_flipped_v() const;
+
+ void set_specular_color(const Color &p_color);
+ Color get_specular_color() const;
+
+ void set_shininess(float p_shininess);
+ float get_shininess() const;
+
+ virtual String get_configuration_warning() const;
+ AnimatedSprite2D();
+};
+
+#endif // ANIMATED_SPRITE_H
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index b99c4c88bf..c46b6eeb5c 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -32,12 +32,12 @@
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
void Area2D::set_space_override_mode(SpaceOverride p_mode) {
space_override = p_mode;
- Physics2DServer::get_singleton()->area_set_space_override_mode(get_rid(), Physics2DServer::AreaSpaceOverrideMode(p_mode));
+ PhysicsServer2D::get_singleton()->area_set_space_override_mode(get_rid(), PhysicsServer2D::AreaSpaceOverrideMode(p_mode));
}
Area2D::SpaceOverride Area2D::get_space_override_mode() const {
@@ -47,7 +47,7 @@ Area2D::SpaceOverride Area2D::get_space_override_mode() const {
void Area2D::set_gravity_is_point(bool p_enabled) {
gravity_is_point = p_enabled;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT, p_enabled);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT, p_enabled);
}
bool Area2D::is_gravity_a_point() const {
@@ -57,7 +57,7 @@ bool Area2D::is_gravity_a_point() const {
void Area2D::set_gravity_distance_scale(real_t p_scale) {
gravity_distance_scale = p_scale;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
}
real_t Area2D::get_gravity_distance_scale() const {
@@ -67,7 +67,7 @@ real_t Area2D::get_gravity_distance_scale() const {
void Area2D::set_gravity_vector(const Vector2 &p_vec) {
gravity_vec = p_vec;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_GRAVITY_VECTOR, p_vec);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, p_vec);
}
Vector2 Area2D::get_gravity_vector() const {
@@ -77,7 +77,7 @@ Vector2 Area2D::get_gravity_vector() const {
void Area2D::set_gravity(real_t p_gravity) {
gravity = p_gravity;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_GRAVITY, p_gravity);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY, p_gravity);
}
real_t Area2D::get_gravity() const {
@@ -87,7 +87,7 @@ real_t Area2D::get_gravity() const {
void Area2D::set_linear_damp(real_t p_linear_damp) {
linear_damp = p_linear_damp;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_LINEAR_DAMP, p_linear_damp);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, p_linear_damp);
}
real_t Area2D::get_linear_damp() const {
@@ -97,7 +97,7 @@ real_t Area2D::get_linear_damp() const {
void Area2D::set_angular_damp(real_t p_angular_damp) {
angular_damp = p_angular_damp;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_ANGULAR_DAMP, p_angular_damp);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, p_angular_damp);
}
real_t Area2D::get_angular_damp() const {
@@ -108,7 +108,7 @@ real_t Area2D::get_angular_damp() const {
void Area2D::set_priority(real_t p_priority) {
priority = p_priority;
- Physics2DServer::get_singleton()->area_set_param(get_rid(), Physics2DServer::AREA_PARAM_PRIORITY, p_priority);
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_PRIORITY, p_priority);
}
real_t Area2D::get_priority() const {
@@ -151,7 +151,7 @@ void Area2D::_body_exit_tree(ObjectID p_id) {
void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {
- bool body_in = p_status == Physics2DServer::AREA_BODY_ADDED;
+ bool body_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;
ObjectID objid = p_instance;
Object *obj = ObjectDB::get_instance(objid);
@@ -254,7 +254,7 @@ void Area2D::_area_exit_tree(ObjectID p_id) {
void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) {
- bool area_in = p_status == Physics2DServer::AREA_BODY_ADDED;
+ bool area_in = p_status == PhysicsServer2D::AREA_BODY_ADDED;
ObjectID objid = p_instance;
Object *obj = ObjectDB::get_instance(objid);
@@ -403,12 +403,12 @@ void Area2D::set_monitoring(bool p_enable) {
if (monitoring) {
- Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_body_inout);
- Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_area_inout);
+ PhysicsServer2D::get_singleton()->area_set_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_body_inout);
+ PhysicsServer2D::get_singleton()->area_set_area_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_area_inout);
} else {
- Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(), NULL, StringName());
- Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(), NULL, StringName());
+ PhysicsServer2D::get_singleton()->area_set_monitor_callback(get_rid(), nullptr, StringName());
+ PhysicsServer2D::get_singleton()->area_set_area_monitor_callback(get_rid(), nullptr, StringName());
_clear_monitoring();
}
}
@@ -420,14 +420,14 @@ bool Area2D::is_monitoring() const {
void Area2D::set_monitorable(bool p_enable) {
- ERR_FAIL_COND_MSG(locked || (is_inside_tree() && Physics2DServer::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false).");
+ ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer2D::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false).");
if (p_enable == monitorable)
return;
monitorable = p_enable;
- Physics2DServer::get_singleton()->area_set_monitorable(get_rid(), monitorable);
+ PhysicsServer2D::get_singleton()->area_set_monitorable(get_rid(), monitorable);
}
bool Area2D::is_monitorable() const {
@@ -492,7 +492,7 @@ bool Area2D::overlaps_body(Node *p_body) const {
void Area2D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
- Physics2DServer::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
+ PhysicsServer2D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
}
uint32_t Area2D::get_collision_mask() const {
@@ -503,7 +503,7 @@ uint32_t Area2D::get_collision_mask() const {
void Area2D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
- Physics2DServer::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
+ PhysicsServer2D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
}
uint32_t Area2D::get_collision_layer() const {
@@ -676,7 +676,7 @@ void Area2D::_bind_methods() {
}
Area2D::Area2D() :
- CollisionObject2D(Physics2DServer::get_singleton()->area_create(), true) {
+ CollisionObject2D(PhysicsServer2D::get_singleton()->area_create(), true) {
space_override = SPACE_OVERRIDE_DISABLED;
set_gravity(98);
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index aa4ed233fb..55d111439a 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -32,7 +32,7 @@
#include "core/engine.h"
#include "scene/2d/area_2d.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void AudioStreamPlayer2D::_mix_audio() {
@@ -87,7 +87,7 @@ void AudioStreamPlayer2D::_mix_audio() {
AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol;
AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol;
AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol;
+ AudioFrame vol = vol_prev;
int cc = AudioServer::get_singleton()->get_channel_count();
@@ -187,9 +187,9 @@ void AudioStreamPlayer2D::_notification(int p_what) {
//check if any area is diverting sound into a bus
- Physics2DDirectSpaceState *space_state = Physics2DServer::get_singleton()->space_get_direct_state(world_2d->get_space());
+ PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
- Physics2DDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS];
+ PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp
index faeb6b7169..4c952b7ca6 100644
--- a/scene/2d/back_buffer_copy.cpp
+++ b/scene/2d/back_buffer_copy.cpp
@@ -36,15 +36,15 @@ void BackBufferCopy::_update_copy_mode() {
case COPY_MODE_DISABLED: {
- VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(), false, Rect2());
+ RS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(), false, Rect2());
} break;
case COPY_MODE_RECT: {
- VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(), true, rect);
+ RS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(), true, rect);
} break;
case COPY_MODE_VIEWPORT: {
- VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(), true, Rect2());
+ RS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(), true, Rect2());
} break;
}
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index a8860c3d81..d8af14a3fb 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -33,7 +33,7 @@
#include "core/engine.h"
#include "core/math/math_funcs.h"
#include "scene/scene_string_names.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
void Camera2D::_update_scroll() {
@@ -264,7 +264,7 @@ void Camera2D::_notification(int p_what) {
}
remove_from_group(group_name);
remove_from_group(canvas_group_name);
- viewport = NULL;
+ viewport = nullptr;
} break;
case NOTIFICATION_DRAW: {
@@ -433,7 +433,7 @@ void Camera2D::clear_current() {
current = false;
if (is_inside_tree()) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", (Object *)(NULL));
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", (Object *)nullptr);
}
}
@@ -794,7 +794,7 @@ Camera2D::Camera2D() {
first = true;
smoothing_enabled = false;
limit_smoothing_enabled = false;
- custom_viewport = NULL;
+ custom_viewport = nullptr;
process_mode = CAMERA2D_PROCESS_IDLE;
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 04b5260444..7a106ef79a 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -32,7 +32,7 @@
#define CAMERA_2D_H
#include "scene/2d/node_2d.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
class Camera2D : public Node2D {
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
deleted file mode 100644
index ef7aa9ba01..0000000000
--- a/scene/2d/canvas_item.cpp
+++ /dev/null
@@ -1,1439 +0,0 @@
-/*************************************************************************/
-/* canvas_item.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "canvas_item.h"
-#include "core/message_queue.h"
-#include "core/method_bind_ext.gen.inc"
-#include "core/os/input.h"
-#include "scene/main/canvas_layer.h"
-#include "scene/main/viewport.h"
-#include "scene/resources/font.h"
-#include "scene/resources/style_box.h"
-#include "scene/resources/texture.h"
-#include "scene/scene_string_names.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual_server.h"
-
-Mutex CanvasItemMaterial::material_mutex;
-SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = NULL;
-Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
-CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = NULL;
-
-void CanvasItemMaterial::init_shaders() {
-
- dirty_materials = memnew(SelfList<CanvasItemMaterial>::List);
-
- shader_names = memnew(ShaderNames);
-
- shader_names->particles_anim_h_frames = "particles_anim_h_frames";
- shader_names->particles_anim_v_frames = "particles_anim_v_frames";
- shader_names->particles_anim_loop = "particles_anim_loop";
-}
-
-void CanvasItemMaterial::finish_shaders() {
-
- memdelete(dirty_materials);
- memdelete(shader_names);
- dirty_materials = NULL;
-}
-
-void CanvasItemMaterial::_update_shader() {
-
- dirty_materials->remove(&element);
-
- MaterialKey mk = _compute_key();
- if (mk.key == current_key.key)
- return; //no update required in the end
-
- if (shader_map.has(current_key)) {
- shader_map[current_key].users--;
- if (shader_map[current_key].users == 0) {
- //deallocate shader, as it's no longer in use
- VS::get_singleton()->free(shader_map[current_key].shader);
- shader_map.erase(current_key);
- }
- }
-
- current_key = mk;
-
- if (shader_map.has(mk)) {
-
- VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
- shader_map[mk].users++;
- return;
- }
-
- //must create a shader!
-
- String code = "shader_type canvas_item;\nrender_mode ";
- switch (blend_mode) {
- case BLEND_MODE_MIX: code += "blend_mix"; break;
- case BLEND_MODE_ADD: code += "blend_add"; break;
- case BLEND_MODE_SUB: code += "blend_sub"; break;
- case BLEND_MODE_MUL: code += "blend_mul"; break;
- case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
- case BLEND_MODE_DISABLED: code += "blend_disabled"; break;
- }
-
- switch (light_mode) {
- case LIGHT_MODE_NORMAL: break;
- case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
- case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
- }
-
- code += ";\n";
-
- if (particles_animation) {
-
- code += "uniform int particles_anim_h_frames;\n";
- code += "uniform int particles_anim_v_frames;\n";
- code += "uniform bool particles_anim_loop;\n";
-
- code += "void vertex() {\n";
-
- code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
- code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
-
- code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n";
-
- code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
- code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
- code += "\tif (!particles_anim_loop) {\n";
- code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
- code += "\t} else {\n";
- code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n";
- code += "\t}";
- code += "\tUV /= vec2(h_frames, v_frames);\n";
- code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
- code += "}\n";
- }
-
- ShaderData shader_data;
- shader_data.shader = VS::get_singleton()->shader_create();
- shader_data.users = 1;
-
- VS::get_singleton()->shader_set_code(shader_data.shader, code);
-
- shader_map[mk] = shader_data;
-
- VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
-}
-
-void CanvasItemMaterial::flush_changes() {
-
- MutexLock lock(material_mutex);
-
- while (dirty_materials->first()) {
-
- dirty_materials->first()->self()->_update_shader();
- }
-}
-
-void CanvasItemMaterial::_queue_shader_change() {
-
- MutexLock lock(material_mutex);
-
- if (!element.in_list()) {
- dirty_materials->add(&element);
- }
-}
-
-bool CanvasItemMaterial::_is_shader_dirty() const {
-
- MutexLock lock(material_mutex);
-
- return element.in_list();
-}
-void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
-
- blend_mode = p_blend_mode;
- _queue_shader_change();
-}
-
-CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
- return blend_mode;
-}
-
-void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
-
- light_mode = p_light_mode;
- _queue_shader_change();
-}
-
-CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
-
- return light_mode;
-}
-
-void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
- particles_animation = p_particles_anim;
- _queue_shader_change();
- _change_notify();
-}
-
-bool CanvasItemMaterial::get_particles_animation() const {
- return particles_animation;
-}
-
-void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
-
- particles_anim_h_frames = p_frames;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
-}
-
-int CanvasItemMaterial::get_particles_anim_h_frames() const {
-
- return particles_anim_h_frames;
-}
-void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
-
- particles_anim_v_frames = p_frames;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
-}
-
-int CanvasItemMaterial::get_particles_anim_v_frames() const {
-
- return particles_anim_v_frames;
-}
-
-void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
-
- particles_anim_loop = p_loop;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
-}
-
-bool CanvasItemMaterial::get_particles_anim_loop() const {
-
- return particles_anim_loop;
-}
-
-void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("particles_anim_") && !particles_animation) {
- property.usage = 0;
- }
-}
-
-RID CanvasItemMaterial::get_shader_rid() const {
-
- ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
- return shader_map[current_key].shader;
-}
-
-Shader::Mode CanvasItemMaterial::get_shader_mode() const {
-
- return Shader::MODE_CANVAS_ITEM;
-}
-
-void CanvasItemMaterial::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
- ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
-
- ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
- ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
-
- ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
- ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
-
- ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
- ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
-
- ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
- ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
-
- ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
- ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
-
- BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
- BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
- BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
- BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
- BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
-
- BIND_ENUM_CONSTANT(LIGHT_MODE_NORMAL);
- BIND_ENUM_CONSTANT(LIGHT_MODE_UNSHADED);
- BIND_ENUM_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
-}
-
-CanvasItemMaterial::CanvasItemMaterial() :
- element(this) {
-
- blend_mode = BLEND_MODE_MIX;
- light_mode = LIGHT_MODE_NORMAL;
- particles_animation = false;
-
- set_particles_anim_h_frames(1);
- set_particles_anim_v_frames(1);
- set_particles_anim_loop(false);
-
- current_key.key = 0;
- current_key.invalid_key = 1;
- _queue_shader_change();
-}
-
-CanvasItemMaterial::~CanvasItemMaterial() {
-
- MutexLock lock(material_mutex);
-
- if (shader_map.has(current_key)) {
- shader_map[current_key].users--;
- if (shader_map[current_key].users == 0) {
- //deallocate shader, as it's no longer in use
- VS::get_singleton()->free(shader_map[current_key].shader);
- shader_map.erase(current_key);
- }
-
- VS::get_singleton()->material_set_shader(_get_material(), RID());
- }
-}
-
-///////////////////////////////////////////////////////////////////
-#ifdef TOOLS_ENABLED
-bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
- if (_edit_use_rect()) {
- return _edit_get_rect().has_point(p_point);
- } else {
- return p_point.length() < p_tolerance;
- }
-}
-
-Transform2D CanvasItem::_edit_get_transform() const {
- return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot());
-}
-#endif
-
-bool CanvasItem::is_visible_in_tree() const {
-
- if (!is_inside_tree())
- return false;
-
- const CanvasItem *p = this;
-
- while (p) {
- if (!p->visible)
- return false;
- p = p->get_parent_item();
- }
-
- return true;
-}
-
-void CanvasItem::_propagate_visibility_changed(bool p_visible) {
-
- if (p_visible && first_draw) { //avoid propagating it twice
- first_draw = false;
- }
- notification(NOTIFICATION_VISIBILITY_CHANGED);
-
- if (p_visible)
- update(); //todo optimize
- else
- emit_signal(SceneStringNames::get_singleton()->hide);
- _block();
-
- for (int i = 0; i < get_child_count(); i++) {
-
- CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
-
- if (c && c->visible) //should the toplevels stop propagation? i think so but..
- c->_propagate_visibility_changed(p_visible);
- }
-
- _unblock();
-}
-
-void CanvasItem::show() {
-
- if (visible)
- return;
-
- visible = true;
- VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, true);
-
- if (!is_inside_tree())
- return;
-
- _propagate_visibility_changed(true);
- _change_notify("visible");
-}
-
-void CanvasItem::hide() {
-
- if (!visible)
- return;
-
- visible = false;
- VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, false);
-
- if (!is_inside_tree())
- return;
-
- _propagate_visibility_changed(false);
- _change_notify("visible");
-}
-
-CanvasItem *CanvasItem::current_item_drawn = NULL;
-CanvasItem *CanvasItem::get_current_item_drawn() {
- return current_item_drawn;
-}
-
-void CanvasItem::_update_callback() {
-
- if (!is_inside_tree()) {
- pending_update = false;
- return;
- }
-
- VisualServer::get_singleton()->canvas_item_clear(get_canvas_item());
- //todo updating = true - only allow drawing here
- if (is_visible_in_tree()) { //todo optimize this!!
- if (first_draw) {
- notification(NOTIFICATION_VISIBILITY_CHANGED);
- first_draw = false;
- }
- drawing = true;
- current_item_drawn = this;
- notification(NOTIFICATION_DRAW);
- emit_signal(SceneStringNames::get_singleton()->draw);
- if (get_script_instance()) {
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, NULL, 0);
- }
- current_item_drawn = NULL;
- drawing = false;
- }
- //todo updating = false
- pending_update = false; // don't change to false until finished drawing (avoid recursive update)
-}
-
-Transform2D CanvasItem::get_global_transform_with_canvas() const {
-
- if (canvas_layer)
- return canvas_layer->get_transform() * get_global_transform();
- else if (is_inside_tree())
- return get_viewport()->get_canvas_transform() * get_global_transform();
- else
- return get_global_transform();
-}
-
-Transform2D CanvasItem::get_global_transform() const {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
-#endif
- if (global_invalid) {
-
- const CanvasItem *pi = get_parent_item();
- if (pi)
- global_transform = pi->get_global_transform() * get_transform();
- else
- global_transform = get_transform();
-
- global_invalid = false;
- }
-
- return global_transform;
-}
-
-void CanvasItem::_toplevel_raise_self() {
-
- if (!is_inside_tree())
- return;
-
- if (canvas_layer)
- VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, canvas_layer->get_sort_index());
- else
- VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_viewport()->gui_get_canvas_sort_index());
-}
-
-void CanvasItem::_enter_canvas() {
-
- if ((!Object::cast_to<CanvasItem>(get_parent())) || toplevel) {
-
- Node *n = this;
-
- canvas_layer = NULL;
-
- while (n) {
-
- canvas_layer = Object::cast_to<CanvasLayer>(n);
- if (canvas_layer) {
- break;
- }
- if (Object::cast_to<Viewport>(n)) {
- break;
- }
- n = n->get_parent();
- }
-
- RID canvas;
- if (canvas_layer)
- canvas = canvas_layer->get_canvas();
- else
- canvas = get_viewport()->find_world_2d()->get_canvas();
-
- VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
-
- group = "root_canvas" + itos(canvas.get_id());
-
- add_to_group(group);
- if (canvas_layer)
- canvas_layer->reset_sort_index();
- else
- get_viewport()->gui_reset_canvas_sort_index();
-
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
-
- } else {
-
- CanvasItem *parent = get_parent_item();
- canvas_layer = parent->canvas_layer;
- VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, parent->get_canvas_item());
- VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
- }
-
- pending_update = false;
- update();
-
- notification(NOTIFICATION_ENTER_CANVAS);
-}
-
-void CanvasItem::_exit_canvas() {
-
- notification(NOTIFICATION_EXIT_CANVAS, true); //reverse the notification
- VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, RID());
- canvas_layer = NULL;
- group = "";
-}
-
-void CanvasItem::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
-
- _update_texture_filter_changed(false);
- _update_texture_repeat_changed(false);
-
- first_draw = true;
- if (get_parent()) {
- CanvasItem *ci = Object::cast_to<CanvasItem>(get_parent());
- if (ci)
- C = ci->children_items.push_back(this);
- }
- _enter_canvas();
- if (!block_transform_notify && !xform_change.in_list()) {
- get_tree()->xform_change_list.add(&xform_change);
- }
- } break;
- case NOTIFICATION_MOVED_IN_PARENT: {
-
- if (!is_inside_tree())
- break;
-
- if (group != "") {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
- } else {
- CanvasItem *p = get_parent_item();
- ERR_FAIL_COND(!p);
- VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
- }
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
- if (xform_change.in_list())
- get_tree()->xform_change_list.remove(&xform_change);
- _exit_canvas();
- if (C) {
- Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
- C = NULL;
- }
- global_invalid = true;
- } break;
- case NOTIFICATION_DRAW:
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- } break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
-
- emit_signal(SceneStringNames::get_singleton()->visibility_changed);
- } break;
- }
-}
-
-void CanvasItem::set_visible(bool p_visible) {
-
- if (p_visible)
- show();
- else
- hide();
-}
-bool CanvasItem::is_visible() const {
-
- return visible;
-}
-
-void CanvasItem::update() {
-
- if (!is_inside_tree())
- return;
- if (pending_update)
- return;
-
- pending_update = true;
-
- MessageQueue::get_singleton()->push_call(this, "_update_callback");
-}
-
-void CanvasItem::set_modulate(const Color &p_modulate) {
-
- if (modulate == p_modulate)
- return;
-
- modulate = p_modulate;
- VisualServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
-}
-Color CanvasItem::get_modulate() const {
-
- return modulate;
-}
-
-void CanvasItem::set_as_toplevel(bool p_toplevel) {
-
- if (toplevel == p_toplevel)
- return;
-
- if (!is_inside_tree()) {
- toplevel = p_toplevel;
- return;
- }
-
- _exit_canvas();
- toplevel = p_toplevel;
- _enter_canvas();
-}
-
-bool CanvasItem::is_set_as_toplevel() const {
-
- return toplevel;
-}
-
-CanvasItem *CanvasItem::get_parent_item() const {
-
- if (toplevel)
- return NULL;
-
- return Object::cast_to<CanvasItem>(get_parent());
-}
-
-void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
-
- if (self_modulate == p_self_modulate)
- return;
-
- self_modulate = p_self_modulate;
- VisualServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
-}
-Color CanvasItem::get_self_modulate() const {
-
- return self_modulate;
-}
-
-void CanvasItem::set_light_mask(int p_light_mask) {
-
- if (light_mask == p_light_mask)
- return;
-
- light_mask = p_light_mask;
- VS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
-}
-
-int CanvasItem::get_light_mask() const {
-
- return light_mask;
-}
-
-void CanvasItem::item_rect_changed(bool p_size_changed) {
-
- if (p_size_changed)
- update();
- 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) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- VisualServer::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) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- Vector<Color> colors;
- colors.push_back(p_color);
- VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width);
-}
-
-void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width);
-}
-
-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) {
-
- Vector<Point2> points;
- points.resize(p_point_count);
- const float 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;
- points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
- }
-
- draw_polyline(points, p_color, p_width);
-}
-
-void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- Vector<Color> colors;
- colors.push_back(p_color);
- VisualServer::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) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- VisualServer::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) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- if (p_filled) {
- if (p_width != 1.0) {
- WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
- }
-
- VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
- } else {
- // Thick lines are offset depending on their width to avoid partial overlapping.
- // Thin lines don't require an offset, so don't apply one in this case
- float offset;
- if (p_width >= 2) {
- offset = p_width / 2.0;
- } else {
- offset = 0.0;
- }
-
- VisualServer::get_singleton()->canvas_item_add_line(
- canvas_item,
- p_rect.position + Size2(-offset, 0),
- p_rect.position + Size2(p_rect.size.width + offset, 0),
- p_color,
- p_width);
- VisualServer::get_singleton()->canvas_item_add_line(
- canvas_item,
- p_rect.position + Size2(p_rect.size.width, offset),
- p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
- p_color,
- p_width);
- VisualServer::get_singleton()->canvas_item_add_line(
- canvas_item,
- p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
- p_rect.position + Size2(-offset, p_rect.size.height),
- p_color,
- p_width);
- VisualServer::get_singleton()->canvas_item_add_line(
- canvas_item,
- p_rect.position + Size2(0, p_rect.size.height - offset),
- p_rect.position + Size2(0, offset),
- p_color,
- p_width);
- }
-}
-
-void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- VisualServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
-}
-
-void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- ERR_FAIL_COND(p_texture.is_null());
-
- p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map, p_specular_map, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
- ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat), p_clip_uv);
-}
-
-void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- ERR_FAIL_COND(p_style_box.is_null());
-
- 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, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- 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();
- RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- VisualServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal, rid_specular, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-void CanvasItem::draw_set_transform(const Point2 &p_offset, float 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);
- xform.scale_basis(p_scale);
- VisualServer::get_singleton()->canvas_item_add_set_transform(canvas_item, xform);
-}
-
-void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- VisualServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
-}
-
-void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- 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();
- RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- Vector<Color> colors;
- colors.push_back(p_color);
- RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, const Transform2D &p_transform, const Color &p_modulate, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- ERR_FAIL_COND(p_mesh.is_null());
- RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
- ERR_FAIL_COND(p_multimesh.is_null());
- RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
- VisualServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
-
- 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(canvas_item, p_pos, p_text, p_modulate, p_clip_w);
-}
-
-float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, const Color &p_modulate) {
-
- ERR_FAIL_COND_V_MSG(!drawing, 0, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
- ERR_FAIL_COND_V(p_char.length() != 1, 0);
- ERR_FAIL_COND_V(p_font.is_null(), 0);
-
- if (p_font->has_outline()) {
- p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true);
- }
- return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate);
-}
-
-void CanvasItem::_notify_transform(CanvasItem *p_node) {
-
- /* This check exists to avoid re-propagating the transform
- * notification down the tree on dirty nodes. It provides
- * optimization by avoiding redundancy (nodes are dirty, will get the
- * notification anyway).
- */
-
- if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
- return; //nothing to do
- }
-
- p_node->global_invalid = true;
-
- if (p_node->notify_transform && !p_node->xform_change.in_list()) {
- if (!p_node->block_transform_notify) {
- if (p_node->is_inside_tree())
- get_tree()->xform_change_list.add(&p_node->xform_change);
- }
- }
-
- for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) {
-
- CanvasItem *ci = E->get();
- if (ci->toplevel)
- continue;
- _notify_transform(ci);
- }
-}
-
-Rect2 CanvasItem::get_viewport_rect() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- return get_viewport()->get_visible_rect();
-}
-
-RID CanvasItem::get_canvas() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), RID());
-
- if (canvas_layer)
- return canvas_layer->get_canvas();
- else
- return get_viewport()->find_world_2d()->get_canvas();
-}
-
-ObjectID CanvasItem::get_canvas_layer_instance_id() const {
-
- if (canvas_layer) {
- return canvas_layer->get_instance_id();
- } else {
- return ObjectID();
- }
-}
-
-CanvasItem *CanvasItem::get_toplevel() const {
-
- CanvasItem *ci = const_cast<CanvasItem *>(this);
- while (!ci->toplevel && Object::cast_to<CanvasItem>(ci->get_parent())) {
- ci = Object::cast_to<CanvasItem>(ci->get_parent());
- }
-
- return ci;
-}
-
-Ref<World2D> CanvasItem::get_world_2d() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
-
- CanvasItem *tl = get_toplevel();
-
- if (tl->get_viewport()) {
- return tl->get_viewport()->find_world_2d();
- } else {
- return Ref<World2D>();
- }
-}
-
-RID CanvasItem::get_viewport_rid() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), RID());
- return get_viewport()->get_viewport_rid();
-}
-
-void CanvasItem::set_block_transform_notify(bool p_enable) {
- block_transform_notify = p_enable;
-}
-
-bool CanvasItem::is_block_transform_notify_enabled() const {
-
- return block_transform_notify;
-}
-
-void CanvasItem::set_draw_behind_parent(bool p_enable) {
-
- if (behind == p_enable)
- return;
- behind = p_enable;
- VisualServer::get_singleton()->canvas_item_set_draw_behind_parent(canvas_item, behind);
-}
-
-bool CanvasItem::is_draw_behind_parent_enabled() const {
-
- return behind;
-}
-
-void CanvasItem::set_material(const Ref<Material> &p_material) {
-
- material = p_material;
- RID rid;
- if (material.is_valid())
- rid = material->get_rid();
- VS::get_singleton()->canvas_item_set_material(canvas_item, rid);
- _change_notify(); //properties for material exposed
-}
-
-void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
-
- use_parent_material = p_use_parent_material;
- VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
-}
-
-bool CanvasItem::get_use_parent_material() const {
-
- return use_parent_material;
-}
-
-Ref<Material> CanvasItem::get_material() const {
-
- return material;
-}
-
-Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
-
- Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
-
- return local_matrix.xform(screen_point);
-}
-
-Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
-
- ERR_FAIL_COND_V(p_event.is_null(), p_event);
- ERR_FAIL_COND_V(!is_inside_tree(), p_event);
-
- return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse());
-}
-
-Vector2 CanvasItem::get_global_mouse_position() const {
-
- ERR_FAIL_COND_V(!get_viewport(), Vector2());
- return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
-}
-
-Vector2 CanvasItem::get_local_mouse_position() const {
-
- ERR_FAIL_COND_V(!get_viewport(), Vector2());
-
- return get_global_transform().affine_inverse().xform(get_global_mouse_position());
-}
-
-void CanvasItem::force_update_transform() {
- ERR_FAIL_COND(!is_inside_tree());
- if (!xform_change.in_list()) {
- return;
- }
-
- get_tree()->xform_change_list.remove(&xform_change);
-
- notification(NOTIFICATION_TRANSFORM_CHANGED);
-}
-
-void CanvasItem::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self);
- ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
-
-#ifdef TOOLS_ENABLED
- ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state);
- ClassDB::bind_method(D_METHOD("_edit_get_state"), &CanvasItem::_edit_get_state);
- ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
- ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
- ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
- ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
- ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
- ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
- ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
- ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
- ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
- ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
- ClassDB::bind_method(D_METHOD("_edit_set_pivot", "pivot"), &CanvasItem::_edit_set_pivot);
- ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot);
- ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot);
- ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform);
-#endif
-
- ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item);
-
- ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasItem::set_visible);
- ClassDB::bind_method(D_METHOD("is_visible"), &CanvasItem::is_visible);
- ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &CanvasItem::is_visible_in_tree);
- ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show);
- ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
-
- ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update);
-
- ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &CanvasItem::set_as_toplevel);
- ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &CanvasItem::is_set_as_toplevel);
-
- ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask);
- ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask);
-
- ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &CanvasItem::set_modulate);
- ClassDB::bind_method(D_METHOD("get_modulate"), &CanvasItem::get_modulate);
- ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate);
- ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate);
-
- ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
- ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
-
- ClassDB::bind_method(D_METHOD("_set_on_top", "on_top"), &CanvasItem::_set_on_top);
- ClassDB::bind_method(D_METHOD("_is_on_top"), &CanvasItem::_is_on_top);
- //ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
-
- ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width"), &CanvasItem::draw_polyline, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width"), &CanvasItem::draw_arc, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
- ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "clip_uv", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(true), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
- ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1, 1)));
- ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "specular_shininess", "transform", "modulate", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
- ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-
- ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
- ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
- ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform);
- ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform);
- ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas);
- ClassDB::bind_method(D_METHOD("get_viewport_transform"), &CanvasItem::get_viewport_transform);
- ClassDB::bind_method(D_METHOD("get_viewport_rect"), &CanvasItem::get_viewport_rect);
- ClassDB::bind_method(D_METHOD("get_canvas_transform"), &CanvasItem::get_canvas_transform);
- ClassDB::bind_method(D_METHOD("get_local_mouse_position"), &CanvasItem::get_local_mouse_position);
- ClassDB::bind_method(D_METHOD("get_global_mouse_position"), &CanvasItem::get_global_mouse_position);
- ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasItem::get_canvas);
- ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
- //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
-
- ClassDB::bind_method(D_METHOD("set_material", "material"), &CanvasItem::set_material);
- ClassDB::bind_method(D_METHOD("get_material"), &CanvasItem::get_material);
-
- ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
- ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
-
- ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &CanvasItem::set_notify_local_transform);
- ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &CanvasItem::is_local_transform_notification_enabled);
-
- ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &CanvasItem::set_notify_transform);
- ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &CanvasItem::is_transform_notification_enabled);
-
- ClassDB::bind_method(D_METHOD("force_update_transform"), &CanvasItem::force_update_transform);
-
- ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
- ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
-
- ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &CanvasItem::set_texture_filter);
- ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasItem::get_texture_filter);
-
- ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
- ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
-
- BIND_VMETHOD(MethodInfo("_draw"));
-
- ADD_GROUP("Visibility", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
- ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
-
- ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "ParentNode,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "ParentNode,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
-
- ADD_GROUP("Material", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
- //exporting these things doesn't really make much sense i think
- // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
- // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
-
- ADD_SIGNAL(MethodInfo("draw"));
- ADD_SIGNAL(MethodInfo("visibility_changed"));
- ADD_SIGNAL(MethodInfo("hide"));
- ADD_SIGNAL(MethodInfo("item_rect_changed"));
-
- BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
- BIND_CONSTANT(NOTIFICATION_DRAW);
- BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
- BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
- BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
-
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
- BIND_ENUM_CONSTANT(TEXTURE_FILTER_MAX);
-
- BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT_NODE);
- BIND_ENUM_CONSTANT(TEXTURE_REPEAT_DISABLED);
- BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
- BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
- BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
-}
-
-Transform2D CanvasItem::get_canvas_transform() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
-
- if (canvas_layer)
- return canvas_layer->get_transform();
- else if (Object::cast_to<CanvasItem>(get_parent()))
- return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
- else
- return get_viewport()->get_canvas_transform();
-}
-
-Transform2D CanvasItem::get_viewport_transform() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
-
- if (canvas_layer) {
-
- if (get_viewport()) {
- return get_viewport()->get_final_transform() * canvas_layer->get_transform();
- } else {
- return canvas_layer->get_transform();
- }
-
- } else {
- return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform();
- }
-}
-
-void CanvasItem::set_notify_local_transform(bool p_enable) {
- notify_local_transform = p_enable;
-}
-
-bool CanvasItem::is_local_transform_notification_enabled() const {
- return notify_local_transform;
-}
-
-void CanvasItem::set_notify_transform(bool p_enable) {
- if (notify_transform == p_enable)
- return;
-
- notify_transform = p_enable;
-
- if (notify_transform && is_inside_tree()) {
- //this ensures that invalid globals get resolved, so notifications can be received
- get_global_transform();
- }
-}
-
-bool CanvasItem::is_transform_notification_enabled() const {
- return notify_transform;
-}
-
-int CanvasItem::get_canvas_layer() const {
-
- if (canvas_layer)
- return canvas_layer->get_layer();
- else
- return 0;
-}
-
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
-
- if (!is_inside_tree()) {
- return;
- }
-
- if (texture_filter == TEXTURE_FILTER_PARENT_NODE) {
- CanvasItem *parent_item = get_parent_item();
- if (parent_item) {
- texture_filter_cache = parent_item->texture_filter_cache;
- } else {
- //from viewport
- switch (get_viewport()->get_default_canvas_item_texture_filter()) {
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; break;
- default: {
- }
- }
- }
- } else {
- texture_filter_cache = VS::CanvasItemTextureFilter(texture_filter);
- }
- VS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
- update();
-
- if (p_propagate) {
- for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
- if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
- E->get()->_update_texture_filter_changed(true);
- }
- }
- }
-}
-
-void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
- ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
- if (texture_filter == p_texture_filter) {
- return;
- }
- texture_filter = p_texture_filter;
- _update_texture_filter_changed(true);
-}
-
-CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
- return texture_filter;
-}
-
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
-
- if (!is_inside_tree()) {
- return;
- }
-
- if (texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
- CanvasItem *parent_item = get_parent_item();
- if (parent_item) {
- texture_repeat_cache = parent_item->texture_repeat_cache;
- } else {
- //from viewport
- switch (get_viewport()->get_default_canvas_item_texture_repeat()) {
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; break;
- case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR; break;
- default: {
- }
- }
- }
- } else {
- texture_repeat_cache = VS::CanvasItemTextureRepeat(texture_repeat);
- }
- VS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
- update();
- if (p_propagate) {
- for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
- if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
- E->get()->_update_texture_repeat_changed(true);
- }
- }
- }
-}
-
-void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
- ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
- if (texture_repeat == p_texture_repeat) {
- return;
- }
- texture_repeat = p_texture_repeat;
- _update_texture_repeat_changed(true);
-}
-
-CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
- return texture_repeat;
-}
-
-CanvasItem::CanvasItem() :
- xform_change(this) {
-
- canvas_item = VisualServer::get_singleton()->canvas_item_create();
- visible = true;
- pending_update = false;
- modulate = Color(1, 1, 1, 1);
- self_modulate = Color(1, 1, 1, 1);
- toplevel = false;
- first_draw = false;
- drawing = false;
- behind = false;
- block_transform_notify = false;
- //viewport=NULL;
- canvas_layer = NULL;
- use_parent_material = false;
- global_invalid = true;
- notify_local_transform = false;
- notify_transform = false;
- light_mask = 1;
- texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
- texture_filter = TEXTURE_FILTER_PARENT_NODE;
- texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
-
- C = NULL;
-}
-
-CanvasItem::~CanvasItem() {
-
- VisualServer::get_singleton()->free(canvas_item);
-}
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
deleted file mode 100644
index c7f9500ea1..0000000000
--- a/scene/2d/canvas_item.h
+++ /dev/null
@@ -1,422 +0,0 @@
-/*************************************************************************/
-/* canvas_item.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CANVAS_ITEM_H
-#define CANVAS_ITEM_H
-
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-#include "scene/resources/material.h"
-#include "scene/resources/multimesh.h"
-#include "scene/resources/shader.h"
-#include "scene/resources/texture.h"
-
-class CanvasLayer;
-class Viewport;
-class Font;
-
-class StyleBox;
-
-class CanvasItemMaterial : public Material {
-
- GDCLASS(CanvasItemMaterial, Material);
-
-public:
- enum BlendMode {
- BLEND_MODE_MIX,
- BLEND_MODE_ADD,
- BLEND_MODE_SUB,
- BLEND_MODE_MUL,
- BLEND_MODE_PREMULT_ALPHA,
- BLEND_MODE_DISABLED
- };
-
- enum LightMode {
- LIGHT_MODE_NORMAL,
- LIGHT_MODE_UNSHADED,
- LIGHT_MODE_LIGHT_ONLY
- };
-
-private:
- union MaterialKey {
-
- struct {
- uint32_t blend_mode : 4;
- uint32_t light_mode : 4;
- uint32_t particles_animation : 1;
- uint32_t invalid_key : 1;
- };
-
- uint32_t key;
-
- bool operator<(const MaterialKey &p_key) const {
- return key < p_key.key;
- }
- };
-
- struct ShaderNames {
- StringName particles_anim_h_frames;
- StringName particles_anim_v_frames;
- StringName particles_anim_loop;
- };
-
- static ShaderNames *shader_names;
-
- struct ShaderData {
- RID shader;
- int users;
- };
-
- static Map<MaterialKey, ShaderData> shader_map;
-
- MaterialKey current_key;
-
- _FORCE_INLINE_ MaterialKey _compute_key() const {
-
- MaterialKey mk;
- mk.key = 0;
- mk.blend_mode = blend_mode;
- mk.light_mode = light_mode;
- mk.particles_animation = particles_animation;
- return mk;
- }
-
- static Mutex material_mutex;
- static SelfList<CanvasItemMaterial>::List *dirty_materials;
- SelfList<CanvasItemMaterial> element;
-
- void _update_shader();
- _FORCE_INLINE_ void _queue_shader_change();
- _FORCE_INLINE_ bool _is_shader_dirty() const;
-
- BlendMode blend_mode;
- LightMode light_mode;
- bool particles_animation;
-
- int particles_anim_h_frames;
- int particles_anim_v_frames;
- bool particles_anim_loop;
-
-protected:
- static void _bind_methods();
- void _validate_property(PropertyInfo &property) const;
-
-public:
- void set_blend_mode(BlendMode p_blend_mode);
- BlendMode get_blend_mode() const;
-
- void set_light_mode(LightMode p_light_mode);
- LightMode get_light_mode() const;
-
- void set_particles_animation(bool p_particles_anim);
- bool get_particles_animation() const;
-
- void set_particles_anim_h_frames(int p_frames);
- int get_particles_anim_h_frames() const;
- void set_particles_anim_v_frames(int p_frames);
- int get_particles_anim_v_frames() const;
-
- void set_particles_anim_loop(bool p_loop);
- bool get_particles_anim_loop() const;
-
- static void init_shaders();
- static void finish_shaders();
- static void flush_changes();
-
- RID get_shader_rid() const;
-
- virtual Shader::Mode get_shader_mode() const;
-
- CanvasItemMaterial();
- virtual ~CanvasItemMaterial();
-};
-
-VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode)
-VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
-
-class CanvasItem : public Node {
-
- GDCLASS(CanvasItem, Node);
-
-public:
- enum TextureFilter {
- TEXTURE_FILTER_PARENT_NODE,
- TEXTURE_FILTER_NEAREST,
- TEXTURE_FILTER_LINEAR,
- TEXTURE_FILTER_NEAREST_WITH_MIPMAPS,
- TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
- TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC,
- TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
- TEXTURE_FILTER_MAX
- };
-
- enum TextureRepeat {
- TEXTURE_REPEAT_PARENT_NODE,
- TEXTURE_REPEAT_DISABLED,
- TEXTURE_REPEAT_ENABLED,
- TEXTURE_REPEAT_MIRROR,
- TEXTURE_REPEAT_MAX,
- };
-
-private:
- mutable SelfList<Node> xform_change;
-
- RID canvas_item;
- String group;
-
- CanvasLayer *canvas_layer;
-
- Color modulate;
- Color self_modulate;
-
- List<CanvasItem *> children_items;
- List<CanvasItem *>::Element *C;
-
- int light_mask;
-
- bool first_draw;
- bool visible;
- bool pending_update;
- bool toplevel;
- bool drawing;
- bool block_transform_notify;
- bool behind;
- bool use_parent_material;
- bool notify_local_transform;
- bool notify_transform;
-
- VS::CanvasItemTextureFilter texture_filter_cache;
- VS::CanvasItemTextureRepeat texture_repeat_cache;
-
- TextureFilter texture_filter;
- TextureRepeat texture_repeat;
-
- Ref<Material> material;
-
- mutable Transform2D global_transform;
- mutable bool global_invalid;
-
- void _toplevel_raise_self();
-
- void _propagate_visibility_changed(bool p_visible);
-
- void _update_callback();
-
- void _enter_canvas();
- void _exit_canvas();
-
- void _notify_transform(CanvasItem *p_node);
-
- void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
- bool _is_on_top() const { return !is_draw_behind_parent_enabled(); }
-
- static CanvasItem *current_item_drawn;
- friend class Viewport;
- void _update_texture_repeat_changed(bool p_propagate);
- void _update_texture_filter_changed(bool p_propagate);
-
-protected:
- _FORCE_INLINE_ void _notify_transform() {
- if (!is_inside_tree()) return;
- _notify_transform(this);
- if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
- }
-
- void item_rect_changed(bool p_size_changed = true);
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- enum {
- NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
- NOTIFICATION_DRAW = 30,
- NOTIFICATION_VISIBILITY_CHANGED = 31,
- NOTIFICATION_ENTER_CANVAS = 32,
- NOTIFICATION_EXIT_CANVAS = 33,
- NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 35,
- NOTIFICATION_WORLD_2D_CHANGED = 36,
-
- };
-
- /* EDITOR */
-#ifdef TOOLS_ENABLED
- // Select the node
- virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-
- // Save and restore a CanvasItem state
- virtual void _edit_set_state(const Dictionary &p_state){};
- virtual Dictionary _edit_get_state() const { return Dictionary(); };
-
- // Used to move the node
- virtual void _edit_set_position(const Point2 &p_position) = 0;
- virtual Point2 _edit_get_position() const = 0;
-
- // Used to scale the node
- virtual void _edit_set_scale(const Size2 &p_scale) = 0;
- virtual Size2 _edit_get_scale() const = 0;
-
- // 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; };
-
- // Used to resize/move the node
- virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
- virtual void _edit_set_rect(const Rect2 &p_rect){};
- virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
- virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
-
- // Used to set a pivot
- virtual bool _edit_use_pivot() const { return false; };
- virtual void _edit_set_pivot(const Point2 &p_pivot){};
- virtual Point2 _edit_get_pivot() const { return Point2(); };
-
- virtual Transform2D _edit_get_transform() const;
-#endif
-
- /* VISIBILITY */
-
- void set_visible(bool p_visible);
- bool is_visible() const;
- bool is_visible_in_tree() const;
- void show();
- void hide();
-
- void update();
-
- virtual void set_light_mask(int p_light_mask);
- int get_light_mask() const;
-
- void set_modulate(const Color &p_modulate);
- Color get_modulate() const;
-
- void set_self_modulate(const Color &p_self_modulate);
- Color get_self_modulate() const;
-
- /* 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);
- void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- 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);
- 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_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- 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>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-
- void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
- void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-
- void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
- float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
-
- void draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale);
- void draw_set_transform_matrix(const Transform2D &p_matrix);
-
- static CanvasItem *get_current_item_drawn();
-
- /* RECT / TRANSFORM */
-
- void set_as_toplevel(bool p_toplevel);
- bool is_set_as_toplevel() const;
-
- void set_draw_behind_parent(bool p_enable);
- bool is_draw_behind_parent_enabled() const;
-
- CanvasItem *get_parent_item() const;
-
- virtual Transform2D get_transform() const = 0;
-
- virtual Transform2D get_global_transform() const;
- virtual Transform2D get_global_transform_with_canvas() const;
-
- CanvasItem *get_toplevel() const;
- _FORCE_INLINE_ RID get_canvas_item() const {
- return canvas_item;
- }
-
- void set_block_transform_notify(bool p_enable);
- bool is_block_transform_notify_enabled() const;
-
- Transform2D get_canvas_transform() const;
- Transform2D get_viewport_transform() const;
- Rect2 get_viewport_rect() const;
- RID get_viewport_rid() const;
- RID get_canvas() const;
- ObjectID get_canvas_layer_instance_id() const;
- Ref<World2D> get_world_2d() const;
-
- virtual void set_material(const Ref<Material> &p_material);
- Ref<Material> get_material() const;
-
- virtual void set_use_parent_material(bool p_use_parent_material);
- bool get_use_parent_material() const;
-
- Ref<InputEvent> make_input_local(const Ref<InputEvent> &p_event) const;
- Vector2 make_canvas_position_local(const Vector2 &screen_point) const;
-
- Vector2 get_global_mouse_position() const;
- Vector2 get_local_mouse_position() const;
-
- void set_notify_local_transform(bool p_enable);
- bool is_local_transform_notification_enabled() const;
-
- void set_notify_transform(bool p_enable);
- bool is_transform_notification_enabled() const;
-
- void force_update_transform();
-
- void set_texture_filter(TextureFilter p_texture_filter);
- TextureFilter get_texture_filter() const;
-
- void set_texture_repeat(TextureRepeat p_texture_repeat);
- TextureRepeat get_texture_repeat() const;
-
- // Used by control nodes to retrieve the parent's anchorable area
- virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
-
- int get_canvas_layer() const;
-
- CanvasItem();
- ~CanvasItem();
-};
-
-VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
-VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
-
-#endif // CANVAS_ITEM_H
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 25db434918..05f8804e2a 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -35,23 +35,23 @@ void CanvasModulate::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_CANVAS) {
if (is_visible_in_tree()) {
- VS::get_singleton()->canvas_set_modulate(get_canvas(), color);
+ RS::get_singleton()->canvas_set_modulate(get_canvas(), color);
add_to_group("_canvas_modulate_" + itos(get_canvas().get_id()));
}
} else if (p_what == NOTIFICATION_EXIT_CANVAS) {
if (is_visible_in_tree()) {
- VS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1));
+ RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1));
remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));
}
} else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
if (is_visible_in_tree()) {
- VS::get_singleton()->canvas_set_modulate(get_canvas(), color);
+ RS::get_singleton()->canvas_set_modulate(get_canvas(), color);
add_to_group("_canvas_modulate_" + itos(get_canvas().get_id()));
} else {
- VS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1));
+ RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1));
remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));
}
@@ -71,7 +71,7 @@ void CanvasModulate::set_color(const Color &p_color) {
color = p_color;
if (is_visible_in_tree()) {
- VS::get_singleton()->canvas_set_modulate(get_canvas(), color);
+ RS::get_singleton()->canvas_set_modulate(get_canvas(), color);
}
}
Color CanvasModulate::get_color() const {
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 4af2e846f7..d82f4a2f2b 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -31,7 +31,7 @@
#include "collision_object_2d.h"
#include "scene/scene_string_names.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
void CollisionObject2D::_notification(int p_what) {
@@ -42,15 +42,15 @@ void CollisionObject2D::_notification(int p_what) {
Transform2D global_transform = get_global_transform();
if (area)
- Physics2DServer::get_singleton()->area_set_transform(rid, global_transform);
+ PhysicsServer2D::get_singleton()->area_set_transform(rid, global_transform);
else
- Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, global_transform);
+ PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
RID space = get_world_2d()->get_space();
if (area) {
- Physics2DServer::get_singleton()->area_set_space(rid, space);
+ PhysicsServer2D::get_singleton()->area_set_space(rid, space);
} else
- Physics2DServer::get_singleton()->body_set_space(rid, space);
+ PhysicsServer2D::get_singleton()->body_set_space(rid, space);
_update_pickable();
@@ -60,9 +60,9 @@ void CollisionObject2D::_notification(int p_what) {
case NOTIFICATION_ENTER_CANVAS: {
if (area)
- Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
+ PhysicsServer2D::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
else
- Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
+ PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -78,26 +78,26 @@ void CollisionObject2D::_notification(int p_what) {
Transform2D global_transform = get_global_transform();
if (area)
- Physics2DServer::get_singleton()->area_set_transform(rid, global_transform);
+ PhysicsServer2D::get_singleton()->area_set_transform(rid, global_transform);
else
- Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, global_transform);
+ PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
} break;
case NOTIFICATION_EXIT_TREE: {
if (area) {
- Physics2DServer::get_singleton()->area_set_space(rid, RID());
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
} else
- Physics2DServer::get_singleton()->body_set_space(rid, RID());
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
} break;
case NOTIFICATION_EXIT_CANVAS: {
if (area)
- Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, ObjectID());
+ PhysicsServer2D::get_singleton()->area_attach_canvas_instance_id(rid, ObjectID());
else
- Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID());
+ PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID());
} break;
}
}
@@ -136,9 +136,9 @@ void CollisionObject2D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabl
sd.disabled = p_disabled;
for (int i = 0; i < sd.shapes.size(); i++) {
if (area) {
- Physics2DServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
+ PhysicsServer2D::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
} else {
- Physics2DServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
+ PhysicsServer2D::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
}
}
}
@@ -160,7 +160,7 @@ void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool
ShapeData &sd = shapes[p_owner];
sd.one_way_collision = p_enable;
for (int i = 0; i < sd.shapes.size(); i++) {
- Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin);
+ PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin);
}
}
@@ -181,7 +181,7 @@ void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owne
ShapeData &sd = shapes[p_owner];
sd.one_way_collision_margin = p_margin;
for (int i = 0; i < sd.shapes.size(); i++) {
- Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin);
+ PhysicsServer2D::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, sd.one_way_collision, sd.one_way_collision_margin);
}
}
@@ -218,9 +218,9 @@ void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transf
sd.xform = p_transform;
for (int i = 0; i < sd.shapes.size(); i++) {
if (area) {
- Physics2DServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, sd.xform);
+ PhysicsServer2D::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, sd.xform);
} else {
- Physics2DServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, sd.xform);
+ PhysicsServer2D::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, sd.xform);
}
}
}
@@ -233,7 +233,7 @@ Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const
Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const {
- ERR_FAIL_COND_V(!shapes.has(p_owner), NULL);
+ ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr);
return shapes[p_owner].owner;
}
@@ -248,9 +248,9 @@ void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2
s.index = total_subshapes;
s.shape = p_shape;
if (area) {
- Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
+ PhysicsServer2D::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
} else {
- Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
+ PhysicsServer2D::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
}
sd.shapes.push_back(s);
@@ -284,9 +284,9 @@ void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
int index_to_remove = shapes[p_owner].shapes[p_shape].index;
if (area) {
- Physics2DServer::get_singleton()->area_remove_shape(rid, index_to_remove);
+ PhysicsServer2D::get_singleton()->area_remove_shape(rid, index_to_remove);
} else {
- Physics2DServer::get_singleton()->body_remove_shape(rid, index_to_remove);
+ PhysicsServer2D::get_singleton()->body_remove_shape(rid, index_to_remove);
}
shapes[p_owner].shapes.remove(p_shape);
@@ -375,9 +375,9 @@ void CollisionObject2D::_update_pickable() {
bool is_pickable = pickable && is_visible_in_tree();
if (area)
- Physics2DServer::get_singleton()->area_set_pickable(rid, is_pickable);
+ PhysicsServer2D::get_singleton()->area_set_pickable(rid, is_pickable);
else
- Physics2DServer::get_singleton()->body_set_pickable(rid, is_pickable);
+ PhysicsServer2D::get_singleton()->body_set_pickable(rid, is_pickable);
}
String CollisionObject2D::get_configuration_warning() const {
@@ -442,9 +442,9 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
if (p_area) {
- Physics2DServer::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
+ PhysicsServer2D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
} else {
- Physics2DServer::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
+ PhysicsServer2D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
}
}
@@ -457,5 +457,5 @@ CollisionObject2D::CollisionObject2D() {
CollisionObject2D::~CollisionObject2D() {
- Physics2DServer::get_singleton()->free(rid);
+ PhysicsServer2D::get_singleton()->free(rid);
}
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 8874f61bb7..e931f20f40 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -60,7 +60,7 @@ class CollisionObject2D : public Node2D {
disabled = false;
one_way_collision = false;
one_way_collision_margin = 0;
- owner = NULL;
+ owner = nullptr;
}
};
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 4edf92197e..1e48b2d67f 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -50,7 +50,7 @@ void CollisionPolygon2D::_build_polygon() {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
- Vector<Vector<Vector2> > decomp = _decompose_in_convex();
+ Vector<Vector<Vector2>> decomp = _decompose_in_convex();
for (int i = 0; i < decomp.size(); i++) {
Ref<ConvexPolygonShape2D> convex = memnew(ConvexPolygonShape2D);
convex->set_points(decomp[i]);
@@ -76,8 +76,8 @@ void CollisionPolygon2D::_build_polygon() {
}
}
-Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
- Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(polygon);
+Vector<Vector<Vector2>> CollisionPolygon2D::_decompose_in_convex() {
+ Vector<Vector<Vector2>> decomp = Geometry::decompose_polygon_in_convex(polygon);
return decomp;
}
@@ -106,7 +106,7 @@ void CollisionPolygon2D::_notification(int p_what) {
/*if (Engine::get_singleton()->is_editor_hint()) {
//display above all else
set_z_as_relative(false);
- set_z_index(VS::CANVAS_ITEM_Z_MAX - 1);
+ set_z_index(RS::CANVAS_ITEM_Z_MAX - 1);
}*/
} break;
@@ -129,7 +129,7 @@ void CollisionPolygon2D::_notification(int p_what) {
parent->remove_shape_owner(owner_id);
}
owner_id = 0;
- parent = NULL;
+ parent = nullptr;
} break;
case NOTIFICATION_DRAW: {
@@ -148,7 +148,7 @@ void CollisionPolygon2D::_notification(int p_what) {
#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++) {
@@ -319,7 +319,7 @@ CollisionPolygon2D::CollisionPolygon2D() {
aabb = Rect2(-10, -10, 20, 20);
build_mode = BUILD_SOLIDS;
set_notify_local_transform(true);
- parent = NULL;
+ parent = nullptr;
owner_id = 0;
disabled = false;
one_way_collision = false;
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index d8dfec8fd2..92a2758813 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -56,7 +56,7 @@ protected:
bool one_way_collision;
float one_way_collision_margin;
- Vector<Vector<Vector2> > _decompose_in_convex();
+ Vector<Vector<Vector2>> _decompose_in_convex();
void _build_polygon();
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index b2ad040654..b1dbc57c94 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -73,7 +73,7 @@ void CollisionShape2D::_notification(int p_what) {
/*if (Engine::get_singleton()->is_editor_hint()) {
//display above all else
set_z_as_relative(false);
- set_z_index(VS::CANVAS_ITEM_Z_MAX - 1);
+ set_z_index(RS::CANVAS_ITEM_Z_MAX - 1);
}*/
} break;
@@ -96,7 +96,7 @@ void CollisionShape2D::_notification(int p_what) {
parent->remove_shape_owner(owner_id);
}
owner_id = 0;
- parent = NULL;
+ parent = nullptr;
} break;
case NOTIFICATION_DRAW: {
@@ -249,7 +249,7 @@ CollisionShape2D::CollisionShape2D() {
rect = Rect2(-Point2(10, 10), Point2(20, 20));
set_notify_local_transform(true);
owner_id = 0;
- parent = NULL;
+ parent = nullptr;
disabled = false;
one_way_collision = false;
one_way_collision_margin = 1.0;
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 3b8a81d2ca..0a6b091a51 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -31,10 +31,10 @@
#include "cpu_particles_2d.h"
#include "core/core_string_names.h"
-#include "scene/2d/canvas_item.h"
-#include "scene/2d/particles_2d.h"
+#include "scene/2d/gpu_particles_2d.h"
+#include "scene/main/canvas_item.h"
#include "scene/resources/particles_material.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
void CPUParticles2D::set_emitting(bool p_emitting) {
@@ -60,7 +60,7 @@ void CPUParticles2D::set_amount(int p_amount) {
}
particle_data.resize((8 + 4 + 4) * p_amount);
- VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_2D, true, true);
+ RS::get_singleton()->multimesh_allocate(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true);
particle_order.resize(p_amount);
}
@@ -198,14 +198,14 @@ void CPUParticles2D::_update_mesh_texture() {
indices.push_back(0);
Array arr;
- arr.resize(VS::ARRAY_MAX);
- arr[VS::ARRAY_VERTEX] = vertices;
- arr[VS::ARRAY_TEX_UV] = uvs;
- arr[VS::ARRAY_COLOR] = colors;
- arr[VS::ARRAY_INDEX] = indices;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = vertices;
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ arr[RS::ARRAY_COLOR] = colors;
+ arr[RS::ARRAY_INDEX] = indices;
- VS::get_singleton()->mesh_clear(mesh);
- VS::get_singleton()->mesh_add_surface_from_arrays(mesh, VS::PRIMITIVE_TRIANGLES, arr);
+ RS::get_singleton()->mesh_clear(mesh);
+ RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr);
}
void CPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
@@ -976,7 +976,7 @@ void CPUParticles2D::_update_particle_data_buffer() {
int pc = particles.size();
int *ow;
- int *order = NULL;
+ int *order = nullptr;
float *w = particle_data.ptrw();
const Particle *r = particles.ptr();
@@ -1046,17 +1046,17 @@ void CPUParticles2D::_set_redraw(bool p_redraw) {
MutexLock lock(update_mutex);
if (redraw) {
- VS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread));
- VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
+ RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread));
+ RS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
- VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
+ RS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
} else {
- if (VS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread))) {
- VS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread));
+ if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread))) {
+ RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread));
}
- VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
+ RS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
- VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
+ RS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
}
}
@@ -1067,7 +1067,7 @@ void CPUParticles2D::_update_render_thread() {
MutexLock lock(update_mutex);
- VS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
+ RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
}
void CPUParticles2D::_notification(int p_what) {
@@ -1098,7 +1098,7 @@ void CPUParticles2D::_notification(int p_what) {
normrid = normalmap->get_rid();
}
- VS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid, normrid);
+ RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid, normrid);
}
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
@@ -1144,8 +1144,8 @@ void CPUParticles2D::_notification(int p_what) {
void CPUParticles2D::convert_from_particles(Node *p_particles) {
- Particles2D *particles = Object::cast_to<Particles2D>(p_particles);
- ERR_FAIL_COND_MSG(!particles, "Only Particles2D nodes can be converted to CPUParticles2D.");
+ GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(p_particles);
+ ERR_FAIL_COND_MSG(!particles, "Only GPUParticles2D nodes can be converted to CPUParticles2D.");
set_emitting(particles->is_emitting());
set_amount(particles->get_amount());
@@ -1428,9 +1428,9 @@ CPUParticles2D::CPUParticles2D() {
redraw = false;
emitting = false;
- mesh = VisualServer::get_singleton()->mesh_create();
- multimesh = VisualServer::get_singleton()->multimesh_create();
- VisualServer::get_singleton()->multimesh_set_mesh(multimesh, mesh);
+ mesh = RenderingServer::get_singleton()->mesh_create();
+ multimesh = RenderingServer::get_singleton()->multimesh_create();
+ RenderingServer::get_singleton()->multimesh_set_mesh(multimesh, mesh);
set_emitting(true);
set_one_shot(false);
@@ -1481,6 +1481,6 @@ CPUParticles2D::CPUParticles2D() {
}
CPUParticles2D::~CPUParticles2D() {
- VS::get_singleton()->free(multimesh);
- VS::get_singleton()->free(mesh);
+ RS::get_singleton()->free(multimesh);
+ RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
new file mode 100644
index 0000000000..de3f8fa09e
--- /dev/null
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -0,0 +1,432 @@
+/*************************************************************************/
+/* gpu_particles_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "gpu_particles_2d.h"
+
+#include "core/os/os.h"
+#include "scene/resources/particles_material.h"
+#include "scene/scene_string_names.h"
+
+#ifdef TOOLS_ENABLED
+#include "core/engine.h"
+#endif
+
+void GPUParticles2D::set_emitting(bool p_emitting) {
+
+ RS::get_singleton()->particles_set_emitting(particles, p_emitting);
+
+ if (p_emitting && one_shot) {
+ set_process_internal(true);
+ } else if (!p_emitting) {
+ set_process_internal(false);
+ }
+}
+
+void GPUParticles2D::set_amount(int p_amount) {
+
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
+ amount = p_amount;
+ RS::get_singleton()->particles_set_amount(particles, amount);
+}
+void GPUParticles2D::set_lifetime(float p_lifetime) {
+
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
+ lifetime = p_lifetime;
+ RS::get_singleton()->particles_set_lifetime(particles, lifetime);
+}
+
+void GPUParticles2D::set_one_shot(bool p_enable) {
+
+ one_shot = p_enable;
+ RS::get_singleton()->particles_set_one_shot(particles, one_shot);
+
+ if (is_emitting()) {
+
+ set_process_internal(true);
+ if (!one_shot)
+ RenderingServer::get_singleton()->particles_restart(particles);
+ }
+
+ if (!one_shot)
+ set_process_internal(false);
+}
+void GPUParticles2D::set_pre_process_time(float p_time) {
+
+ pre_process_time = p_time;
+ RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
+}
+void GPUParticles2D::set_explosiveness_ratio(float p_ratio) {
+
+ explosiveness_ratio = p_ratio;
+ RS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
+}
+void GPUParticles2D::set_randomness_ratio(float p_ratio) {
+
+ randomness_ratio = p_ratio;
+ RS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
+}
+void GPUParticles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
+
+ visibility_rect = p_visibility_rect;
+ AABB aabb;
+ aabb.position.x = p_visibility_rect.position.x;
+ aabb.position.y = p_visibility_rect.position.y;
+ aabb.size.x = p_visibility_rect.size.x;
+ aabb.size.y = p_visibility_rect.size.y;
+
+ RS::get_singleton()->particles_set_custom_aabb(particles, aabb);
+
+ _change_notify("visibility_rect");
+ update();
+}
+void GPUParticles2D::set_use_local_coordinates(bool p_enable) {
+
+ local_coords = p_enable;
+ RS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
+ set_notify_transform(!p_enable);
+ if (!p_enable && is_inside_tree()) {
+ _update_particle_emission_transform();
+ }
+}
+
+void GPUParticles2D::_update_particle_emission_transform() {
+
+ Transform2D xf2d = get_global_transform();
+ Transform xf;
+ xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
+ xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
+ xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
+
+ RS::get_singleton()->particles_set_emission_transform(particles, xf);
+}
+
+void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
+
+ process_material = p_material;
+ Ref<ParticlesMaterial> pm = p_material;
+ if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
+ // Likely a new (3D) material, modify it to match 2D space
+ pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
+ pm->set_gravity(Vector3(0, 98, 0));
+ }
+ RID material_rid;
+ if (process_material.is_valid())
+ material_rid = process_material->get_rid();
+ RS::get_singleton()->particles_set_process_material(particles, material_rid);
+
+ update_configuration_warning();
+}
+
+void GPUParticles2D::set_speed_scale(float p_scale) {
+
+ speed_scale = p_scale;
+ RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
+}
+
+bool GPUParticles2D::is_emitting() const {
+
+ return RS::get_singleton()->particles_get_emitting(particles);
+}
+int GPUParticles2D::get_amount() const {
+
+ return amount;
+}
+float GPUParticles2D::get_lifetime() const {
+
+ return lifetime;
+}
+
+bool GPUParticles2D::get_one_shot() const {
+
+ return one_shot;
+}
+float GPUParticles2D::get_pre_process_time() const {
+
+ return pre_process_time;
+}
+float GPUParticles2D::get_explosiveness_ratio() const {
+
+ return explosiveness_ratio;
+}
+float GPUParticles2D::get_randomness_ratio() const {
+
+ return randomness_ratio;
+}
+Rect2 GPUParticles2D::get_visibility_rect() const {
+
+ return visibility_rect;
+}
+bool GPUParticles2D::get_use_local_coordinates() const {
+
+ return local_coords;
+}
+Ref<Material> GPUParticles2D::get_process_material() const {
+
+ return process_material;
+}
+
+float GPUParticles2D::get_speed_scale() const {
+
+ return speed_scale;
+}
+
+void GPUParticles2D::set_draw_order(DrawOrder p_order) {
+
+ draw_order = p_order;
+ RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
+}
+
+GPUParticles2D::DrawOrder GPUParticles2D::get_draw_order() const {
+
+ return draw_order;
+}
+
+void GPUParticles2D::set_fixed_fps(int p_count) {
+ fixed_fps = p_count;
+ RS::get_singleton()->particles_set_fixed_fps(particles, p_count);
+}
+
+int GPUParticles2D::get_fixed_fps() const {
+ return fixed_fps;
+}
+
+void GPUParticles2D::set_fractional_delta(bool p_enable) {
+ fractional_delta = p_enable;
+ RS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
+}
+
+bool GPUParticles2D::get_fractional_delta() const {
+ return fractional_delta;
+}
+
+String GPUParticles2D::get_configuration_warning() const {
+
+ 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.");
+ }
+
+ String warnings;
+
+ 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.");
+ } else {
+
+ CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
+
+ if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
+ const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
+ 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.");
+ }
+ }
+ }
+
+ return warnings;
+}
+
+Rect2 GPUParticles2D::capture_rect() const {
+
+ AABB aabb = RS::get_singleton()->particles_get_current_aabb(particles);
+ Rect2 r;
+ r.position.x = aabb.position.x;
+ r.position.y = aabb.position.y;
+ r.size.x = aabb.size.x;
+ r.size.y = aabb.size.y;
+ return r;
+}
+
+void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
+ texture = p_texture;
+ update();
+}
+
+Ref<Texture2D> GPUParticles2D::get_texture() const {
+ return texture;
+}
+
+void GPUParticles2D::set_normal_map(const Ref<Texture2D> &p_normal_map) {
+
+ normal_map = p_normal_map;
+ update();
+}
+
+Ref<Texture2D> GPUParticles2D::get_normal_map() const {
+ return normal_map;
+}
+
+void GPUParticles2D::_validate_property(PropertyInfo &property) const {
+}
+
+void GPUParticles2D::restart() {
+ RS::get_singleton()->particles_restart(particles);
+ RS::get_singleton()->particles_set_emitting(particles, true);
+}
+
+void GPUParticles2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_DRAW) {
+
+ RID texture_rid;
+ if (texture.is_valid())
+ texture_rid = texture->get_rid();
+ RID normal_rid;
+ if (normal_map.is_valid())
+ normal_rid = normal_map->get_rid();
+
+ RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
+
+ draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
+ }
+#endif
+ }
+
+ if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
+ if (can_process()) {
+ RS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
+ } else {
+
+ RS::get_singleton()->particles_set_speed_scale(particles, 0);
+ }
+ }
+
+ if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+ _update_particle_emission_transform();
+ }
+
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+
+ if (one_shot && !is_emitting()) {
+ _change_notify();
+ set_process_internal(false);
+ }
+ }
+}
+
+void GPUParticles2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles2D::set_emitting);
+ ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles2D::set_amount);
+ ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &GPUParticles2D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &GPUParticles2D::set_one_shot);
+ ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &GPUParticles2D::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &GPUParticles2D::set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &GPUParticles2D::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &GPUParticles2D::set_visibility_rect);
+ ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles2D::set_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles2D::set_fixed_fps);
+ ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles2D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles2D::set_process_material);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles2D::set_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles2D::is_emitting);
+ ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles2D::get_amount);
+ ClassDB::bind_method(D_METHOD("get_lifetime"), &GPUParticles2D::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &GPUParticles2D::get_one_shot);
+ ClassDB::bind_method(D_METHOD("get_pre_process_time"), &GPUParticles2D::get_pre_process_time);
+ ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &GPUParticles2D::get_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &GPUParticles2D::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_visibility_rect"), &GPUParticles2D::get_visibility_rect);
+ ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles2D::get_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles2D::get_fixed_fps);
+ ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles2D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles2D::get_process_material);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles2D::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles2D::set_draw_order);
+ ClassDB::bind_method(D_METHOD("get_draw_order"), &GPUParticles2D::get_draw_order);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticles2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticles2D::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normal_map", "texture"), &GPUParticles2D::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map"), &GPUParticles2D::get_normal_map);
+
+ ClassDB::bind_method(D_METHOD("capture_rect"), &GPUParticles2D::capture_rect);
+
+ ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart);
+
+ 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_GROUP("Time", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
+ 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, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
+ 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"), "set_draw_order", "get_draw_order");
+ ADD_GROUP("Process Material", "process_");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
+ ADD_GROUP("Textures", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
+
+ BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+}
+
+GPUParticles2D::GPUParticles2D() {
+
+ particles = RS::get_singleton()->particles_create();
+
+ one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
+ set_emitting(true);
+ set_one_shot(false);
+ set_amount(8);
+ set_lifetime(1);
+ set_fixed_fps(0);
+ set_fractional_delta(true);
+ set_pre_process_time(0);
+ set_explosiveness_ratio(0);
+ set_randomness_ratio(0);
+ set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
+ set_use_local_coordinates(true);
+ set_draw_order(DRAW_ORDER_INDEX);
+ set_speed_scale(1);
+}
+
+GPUParticles2D::~GPUParticles2D() {
+
+ RS::get_singleton()->free(particles);
+}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
new file mode 100644
index 0000000000..47951d76dc
--- /dev/null
+++ b/scene/2d/gpu_particles_2d.h
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* gpu_particles_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PARTICLES_2D_H
+#define PARTICLES_2D_H
+
+#include "core/rid.h"
+#include "scene/2d/node_2d.h"
+#include "scene/resources/texture.h"
+
+class GPUParticles2D : public Node2D {
+private:
+ GDCLASS(GPUParticles2D, Node2D);
+
+public:
+ enum DrawOrder {
+ DRAW_ORDER_INDEX,
+ DRAW_ORDER_LIFETIME,
+ };
+
+private:
+ RID particles;
+
+ bool one_shot;
+ int amount;
+ float lifetime;
+ float pre_process_time;
+ float explosiveness_ratio;
+ float randomness_ratio;
+ float speed_scale;
+ Rect2 visibility_rect;
+ bool local_coords;
+ int fixed_fps;
+ bool fractional_delta;
+
+ Ref<Material> process_material;
+
+ DrawOrder draw_order;
+
+ Ref<Texture2D> texture;
+ Ref<Texture2D> normal_map;
+
+ void _update_particle_emission_transform();
+
+protected:
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const;
+ void _notification(int p_what);
+
+public:
+ void set_emitting(bool p_emitting);
+ void set_amount(int p_amount);
+ void set_lifetime(float p_lifetime);
+ void set_one_shot(bool p_enable);
+ void set_pre_process_time(float p_time);
+ void set_explosiveness_ratio(float p_ratio);
+ void set_randomness_ratio(float p_ratio);
+ void set_visibility_rect(const Rect2 &p_visibility_rect);
+ void set_use_local_coordinates(bool p_enable);
+ void set_process_material(const Ref<Material> &p_material);
+ void set_speed_scale(float 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;
+ Rect2 get_visibility_rect() const;
+ bool get_use_local_coordinates() const;
+ Ref<Material> get_process_material() const;
+ float get_speed_scale() const;
+
+ void set_fixed_fps(int p_count);
+ int get_fixed_fps() const;
+
+ void set_fractional_delta(bool p_enable);
+ bool get_fractional_delta() const;
+
+ void set_draw_order(DrawOrder p_order);
+ DrawOrder get_draw_order() const;
+
+ void set_texture(const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_texture() const;
+
+ void set_normal_map(const Ref<Texture2D> &p_normal_map);
+ Ref<Texture2D> get_normal_map() const;
+
+ virtual String get_configuration_warning() const;
+
+ void restart();
+ Rect2 capture_rect() const;
+ GPUParticles2D();
+ ~GPUParticles2D();
+};
+
+VARIANT_ENUM_CAST(GPUParticles2D::DrawOrder)
+
+#endif // PARTICLES_2D_H
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index 9cc9ab25ac..4d49f4762f 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -32,15 +32,15 @@
#include "core/engine.h"
#include "physics_body_2d.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
void Joint2D::_update_joint(bool p_only_free) {
if (joint.is_valid()) {
if (ba.is_valid() && bb.is_valid() && exclude_from_collision)
- Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, false);
+ PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false);
- Physics2DServer::get_singleton()->free(joint);
+ PhysicsServer2D::get_singleton()->free(joint);
joint = RID();
ba = RID();
bb = RID();
@@ -49,8 +49,8 @@ void Joint2D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree())
return;
- Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
- Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
+ Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)nullptr;
+ Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)nullptr;
if (!node_a || !node_b)
return;
@@ -66,12 +66,12 @@ void Joint2D::_update_joint(bool p_only_free) {
if (!joint.is_valid())
return;
- Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias);
+ PhysicsServer2D::get_singleton()->get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias);
ba = body_a->get_rid();
bb = body_b->get_rid();
- Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
+ PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
}
void Joint2D::set_node_a(const NodePath &p_node_a) {
@@ -119,7 +119,7 @@ void Joint2D::set_bias(real_t p_bias) {
bias = p_bias;
if (joint.is_valid())
- Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias);
+ PhysicsServer2D::get_singleton()->get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias);
}
real_t Joint2D::get_bias() const {
@@ -192,8 +192,8 @@ void PinJoint2D::_notification(int p_what) {
RID PinJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
- RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
- Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness);
+ 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;
}
@@ -202,7 +202,7 @@ void PinJoint2D::set_softness(real_t p_softness) {
softness = p_softness;
update();
if (get_joint().is_valid())
- Physics2DServer::get_singleton()->pin_joint_set_param(get_joint(), Physics2DServer::PIN_JOINT_SOFTNESS, p_softness);
+ PhysicsServer2D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness);
}
real_t PinJoint2D::get_softness() const {
@@ -253,7 +253,7 @@ RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b
Vector2 groove_A2 = gt.xform(Vector2(0, length));
Vector2 anchor_B = gt.xform(Vector2(0, initial_offset));
- return Physics2DServer::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
+ return PhysicsServer2D::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
}
void GrooveJoint2D::set_length(real_t p_length) {
@@ -324,11 +324,11 @@ RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *
Vector2 anchor_A = gt.get_origin();
Vector2 anchor_B = gt.xform(Vector2(0, length));
- RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
+ RID dsj = PhysicsServer2D::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
if (rest_length)
- Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_REST_LENGTH, rest_length);
- Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_STIFFNESS, stiffness);
- Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_DAMPING, damping);
+ PhysicsServer2D::get_singleton()->damped_string_joint_set_param(dsj, PhysicsServer2D::DAMPED_STRING_REST_LENGTH, rest_length);
+ PhysicsServer2D::get_singleton()->damped_string_joint_set_param(dsj, PhysicsServer2D::DAMPED_STRING_STIFFNESS, stiffness);
+ PhysicsServer2D::get_singleton()->damped_string_joint_set_param(dsj, PhysicsServer2D::DAMPED_STRING_DAMPING, damping);
return dsj;
}
@@ -349,7 +349,7 @@ void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) {
rest_length = p_rest_length;
update();
if (get_joint().is_valid())
- Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(), Physics2DServer::DAMPED_STRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
+ PhysicsServer2D::get_singleton()->damped_string_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_STRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
}
real_t DampedSpringJoint2D::get_rest_length() const {
@@ -362,7 +362,7 @@ void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) {
stiffness = p_stiffness;
update();
if (get_joint().is_valid())
- Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(), Physics2DServer::DAMPED_STRING_STIFFNESS, p_stiffness);
+ PhysicsServer2D::get_singleton()->damped_string_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_STRING_STIFFNESS, p_stiffness);
}
real_t DampedSpringJoint2D::get_stiffness() const {
@@ -375,7 +375,7 @@ void DampedSpringJoint2D::set_damping(real_t p_damping) {
damping = p_damping;
update();
if (get_joint().is_valid())
- Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(), Physics2DServer::DAMPED_STRING_DAMPING, p_damping);
+ PhysicsServer2D::get_singleton()->damped_string_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_STRING_DAMPING, p_damping);
}
real_t DampedSpringJoint2D::get_damping() const {
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index e61b1fa339..b3d54b81f8 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -31,7 +31,7 @@
#include "light_2d.h"
#include "core/engine.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
#ifdef TOOLS_ENABLED
Dictionary Light2D::_edit_get_state() const {
@@ -100,7 +100,7 @@ void Light2D::_update_light_visibility() {
}
#endif
- VS::get_singleton()->canvas_light_set_enabled(canvas_light, enabled && is_visible_in_tree() && editor_ok);
+ RS::get_singleton()->canvas_light_set_enabled(canvas_light, enabled && is_visible_in_tree() && editor_ok);
}
void Light2D::set_enabled(bool p_enabled) {
@@ -129,9 +129,9 @@ void Light2D::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
if (texture.is_valid())
- VS::get_singleton()->canvas_light_set_texture(canvas_light, texture->get_rid());
+ RS::get_singleton()->canvas_light_set_texture(canvas_light, texture->get_rid());
else
- VS::get_singleton()->canvas_light_set_texture(canvas_light, RID());
+ RS::get_singleton()->canvas_light_set_texture(canvas_light, RID());
update_configuration_warning();
}
@@ -144,7 +144,7 @@ Ref<Texture2D> Light2D::get_texture() const {
void Light2D::set_texture_offset(const Vector2 &p_offset) {
texture_offset = p_offset;
- VS::get_singleton()->canvas_light_set_texture_offset(canvas_light, texture_offset);
+ RS::get_singleton()->canvas_light_set_texture_offset(canvas_light, texture_offset);
item_rect_changed();
_change_notify("offset");
}
@@ -157,7 +157,7 @@ Vector2 Light2D::get_texture_offset() const {
void Light2D::set_color(const Color &p_color) {
color = p_color;
- VS::get_singleton()->canvas_light_set_color(canvas_light, color);
+ RS::get_singleton()->canvas_light_set_color(canvas_light, color);
}
Color Light2D::get_color() const {
@@ -167,7 +167,7 @@ Color Light2D::get_color() const {
void Light2D::set_height(float p_height) {
height = p_height;
- VS::get_singleton()->canvas_light_set_height(canvas_light, height);
+ RS::get_singleton()->canvas_light_set_height(canvas_light, height);
}
float Light2D::get_height() const {
@@ -178,7 +178,7 @@ float Light2D::get_height() const {
void Light2D::set_energy(float p_energy) {
energy = p_energy;
- VS::get_singleton()->canvas_light_set_energy(canvas_light, energy);
+ RS::get_singleton()->canvas_light_set_energy(canvas_light, energy);
}
float Light2D::get_energy() const {
@@ -193,7 +193,7 @@ void Light2D::set_texture_scale(float p_scale) {
if (_scale == 0) {
_scale = CMP_EPSILON;
}
- VS::get_singleton()->canvas_light_set_scale(canvas_light, _scale);
+ RS::get_singleton()->canvas_light_set_scale(canvas_light, _scale);
item_rect_changed();
}
@@ -205,7 +205,7 @@ float Light2D::get_texture_scale() const {
void Light2D::set_z_range_min(int p_min_z) {
z_min = p_min_z;
- VS::get_singleton()->canvas_light_set_z_range(canvas_light, z_min, z_max);
+ RS::get_singleton()->canvas_light_set_z_range(canvas_light, z_min, z_max);
}
int Light2D::get_z_range_min() const {
@@ -215,7 +215,7 @@ int Light2D::get_z_range_min() const {
void Light2D::set_z_range_max(int p_max_z) {
z_max = p_max_z;
- VS::get_singleton()->canvas_light_set_z_range(canvas_light, z_min, z_max);
+ RS::get_singleton()->canvas_light_set_z_range(canvas_light, z_min, z_max);
}
int Light2D::get_z_range_max() const {
@@ -225,7 +225,7 @@ int Light2D::get_z_range_max() const {
void Light2D::set_layer_range_min(int p_min_layer) {
layer_min = p_min_layer;
- VS::get_singleton()->canvas_light_set_layer_range(canvas_light, layer_min, layer_max);
+ RS::get_singleton()->canvas_light_set_layer_range(canvas_light, layer_min, layer_max);
}
int Light2D::get_layer_range_min() const {
@@ -235,7 +235,7 @@ int Light2D::get_layer_range_min() const {
void Light2D::set_layer_range_max(int p_max_layer) {
layer_max = p_max_layer;
- VS::get_singleton()->canvas_light_set_layer_range(canvas_light, layer_min, layer_max);
+ RS::get_singleton()->canvas_light_set_layer_range(canvas_light, layer_min, layer_max);
}
int Light2D::get_layer_range_max() const {
@@ -245,7 +245,7 @@ int Light2D::get_layer_range_max() const {
void Light2D::set_item_cull_mask(int p_mask) {
item_mask = p_mask;
- VS::get_singleton()->canvas_light_set_item_cull_mask(canvas_light, item_mask);
+ RS::get_singleton()->canvas_light_set_item_cull_mask(canvas_light, item_mask);
}
int Light2D::get_item_cull_mask() const {
@@ -256,7 +256,7 @@ int Light2D::get_item_cull_mask() const {
void Light2D::set_item_shadow_cull_mask(int p_mask) {
item_shadow_mask = p_mask;
- VS::get_singleton()->canvas_light_set_item_shadow_cull_mask(canvas_light, item_shadow_mask);
+ RS::get_singleton()->canvas_light_set_item_shadow_cull_mask(canvas_light, item_shadow_mask);
}
int Light2D::get_item_shadow_cull_mask() const {
@@ -267,7 +267,7 @@ int Light2D::get_item_shadow_cull_mask() const {
void Light2D::set_mode(Mode p_mode) {
mode = p_mode;
- VS::get_singleton()->canvas_light_set_mode(canvas_light, VS::CanvasLightMode(p_mode));
+ RS::get_singleton()->canvas_light_set_mode(canvas_light, RS::CanvasLightMode(p_mode));
}
Light2D::Mode Light2D::get_mode() const {
@@ -278,7 +278,7 @@ Light2D::Mode Light2D::get_mode() const {
void Light2D::set_shadow_enabled(bool p_enabled) {
shadow = p_enabled;
- VS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light, shadow);
+ RS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light, shadow);
}
bool Light2D::is_shadow_enabled() const {
@@ -288,7 +288,7 @@ bool Light2D::is_shadow_enabled() const {
void Light2D::set_shadow_buffer_size(int p_size) {
shadow_buffer_size = p_size;
- VS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light, shadow_buffer_size);
+ RS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light, shadow_buffer_size);
}
int Light2D::get_shadow_buffer_size() const {
@@ -299,7 +299,7 @@ int Light2D::get_shadow_buffer_size() const {
void Light2D::set_shadow_filter(ShadowFilter p_filter) {
ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX);
shadow_filter = p_filter;
- VS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, VS::CanvasLightShadowFilter(p_filter));
+ RS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, RS::CanvasLightShadowFilter(p_filter));
}
Light2D::ShadowFilter Light2D::get_shadow_filter() const {
@@ -309,7 +309,7 @@ Light2D::ShadowFilter Light2D::get_shadow_filter() const {
void Light2D::set_shadow_color(const Color &p_shadow_color) {
shadow_color = p_shadow_color;
- VS::get_singleton()->canvas_light_set_shadow_color(canvas_light, shadow_color);
+ RS::get_singleton()->canvas_light_set_shadow_color(canvas_light, shadow_color);
}
Color Light2D::get_shadow_color() const {
@@ -320,13 +320,13 @@ void Light2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- VS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas());
+ RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas());
_update_light_visibility();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- VS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform());
+ RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform());
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
@@ -335,7 +335,7 @@ void Light2D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
- VS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID());
+ RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID());
_update_light_visibility();
}
}
@@ -352,7 +352,7 @@ String Light2D::get_configuration_warning() const {
void Light2D::set_shadow_smooth(float p_amount) {
shadow_smooth = p_amount;
- VS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth);
+ RS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth);
}
float Light2D::get_shadow_smooth() const {
@@ -432,8 +432,8 @@ void Light2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix,Mask"), "set_mode", "get_mode");
ADD_GROUP("Range", "range_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "range_height", PROPERTY_HINT_RANGE, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_min", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_min", "get_layer_range_min");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_max", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_max", "get_layer_range_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_item_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_item_cull_mask", "get_item_cull_mask");
@@ -458,7 +458,7 @@ void Light2D::_bind_methods() {
Light2D::Light2D() {
- canvas_light = VisualServer::get_singleton()->canvas_light_create();
+ canvas_light = RenderingServer::get_singleton()->canvas_light_create();
enabled = true;
editor_only = false;
shadow = false;
@@ -483,5 +483,5 @@ Light2D::Light2D() {
Light2D::~Light2D() {
- VisualServer::get_singleton()->free(canvas_light);
+ RenderingServer::get_singleton()->free(canvas_light);
}
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index d4a5c93823..bd1a820aec 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -88,7 +88,7 @@ void OccluderPolygon2D::set_polygon(const Vector<Vector2> &p_polygon) {
polygon = p_polygon;
rect_cache_dirty = true;
- VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed);
+ RS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed);
emit_changed();
}
@@ -103,7 +103,7 @@ void OccluderPolygon2D::set_closed(bool p_closed) {
return;
closed = p_closed;
if (polygon.size())
- VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, polygon, closed);
+ RS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, polygon, closed);
emit_changed();
}
@@ -115,7 +115,7 @@ bool OccluderPolygon2D::is_closed() const {
void OccluderPolygon2D::set_cull_mode(CullMode p_mode) {
cull = p_mode;
- VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon, VS::CanvasOccluderPolygonCullMode(p_mode));
+ RS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon, RS::CanvasOccluderPolygonCullMode(p_mode));
}
OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const {
@@ -150,7 +150,7 @@ void OccluderPolygon2D::_bind_methods() {
OccluderPolygon2D::OccluderPolygon2D() {
- occ_polygon = VS::get_singleton()->canvas_occluder_polygon_create();
+ occ_polygon = RS::get_singleton()->canvas_occluder_polygon_create();
closed = true;
cull = CULL_DISABLED;
rect_cache_dirty = true;
@@ -158,7 +158,7 @@ OccluderPolygon2D::OccluderPolygon2D() {
OccluderPolygon2D::~OccluderPolygon2D() {
- VS::get_singleton()->free(occ_polygon);
+ RS::get_singleton()->free(occ_polygon);
}
void LightOccluder2D::_poly_changed() {
@@ -172,17 +172,17 @@ void LightOccluder2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_CANVAS) {
- VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
- VS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
- VS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
+ RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
+ RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- VS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
+ RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- VS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
+ RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
}
if (p_what == NOTIFICATION_DRAW) {
@@ -214,7 +214,7 @@ void LightOccluder2D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_CANVAS) {
- VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID());
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID());
}
}
@@ -239,9 +239,9 @@ void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polyg
occluder_polygon = p_polygon;
if (occluder_polygon.is_valid())
- VS::get_singleton()->canvas_light_occluder_set_polygon(occluder, occluder_polygon->get_rid());
+ RS::get_singleton()->canvas_light_occluder_set_polygon(occluder, occluder_polygon->get_rid());
else
- VS::get_singleton()->canvas_light_occluder_set_polygon(occluder, RID());
+ RS::get_singleton()->canvas_light_occluder_set_polygon(occluder, RID());
#ifdef DEBUG_ENABLED
if (occluder_polygon.is_valid())
@@ -258,7 +258,7 @@ Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const {
void LightOccluder2D::set_occluder_light_mask(int p_mask) {
mask = p_mask;
- VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, mask);
+ RS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, mask);
}
int LightOccluder2D::get_occluder_light_mask() const {
@@ -293,12 +293,12 @@ void LightOccluder2D::_bind_methods() {
LightOccluder2D::LightOccluder2D() {
- occluder = VS::get_singleton()->canvas_light_occluder_create();
+ occluder = RS::get_singleton()->canvas_light_occluder_create();
mask = 1;
set_notify_transform(true);
}
LightOccluder2D::~LightOccluder2D() {
- VS::get_singleton()->free(occluder);
+ RS::get_singleton()->free(occluder);
}
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 873c901c0a..c45eab70df 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -311,7 +311,7 @@ void Line2D::_draw() {
lb.build();
- VS::get_singleton()->canvas_item_add_triangle_array(
+ RS::get_singleton()->canvas_item_add_triangle_array(
get_canvas_item(),
lb.indices,
lb.vertices,
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 3385f2fbe0..6b06f2227a 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -95,9 +95,9 @@ static inline Vector2 interpolate(const Rect2 &r, const Vector2 &v) {
LineBuilder::LineBuilder() {
joint_mode = Line2D::LINE_JOINT_SHARP;
width = 10;
- curve = NULL;
+ curve = nullptr;
default_color = Color(0.4, 0.5, 1);
- gradient = NULL;
+ gradient = nullptr;
sharp_limit = 2.f;
round_precision = 8;
begin_cap_mode = Line2D::LINE_CAP_NONE;
@@ -147,8 +147,8 @@ void LineBuilder::build() {
float current_distance1 = 0.f;
float total_distance = 0.f;
float width_factor = 1.f;
- _interpolate_color = gradient != NULL;
- bool retrieve_curve = curve != NULL;
+ _interpolate_color = gradient != nullptr;
+ bool retrieve_curve = curve != nullptr;
bool distance_required = _interpolate_color ||
retrieve_curve ||
texture_mode == Line2D::LINE_TEXTURE_TILE ||
diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp
index bbabfa16c7..ae9fc0f32c 100644
--- a/scene/2d/navigation_2d.cpp
+++ b/scene/2d/navigation_2d.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "navigation_2d.h"
-#include "servers/navigation_2d_server.h"
+#include "servers/navigation_server_2d.h"
void Navigation2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &Navigation2D::get_rid);
@@ -51,44 +51,44 @@ void Navigation2D::_bind_methods() {
void Navigation2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- Navigation2DServer::get_singleton()->map_set_active(map, true);
+ NavigationServer2D::get_singleton()->map_set_active(map, true);
} break;
case NOTIFICATION_EXIT_TREE: {
- Navigation2DServer::get_singleton()->map_set_active(map, false);
+ NavigationServer2D::get_singleton()->map_set_active(map, false);
} break;
}
}
void Navigation2D::set_cell_size(float p_cell_size) {
cell_size = p_cell_size;
- Navigation2DServer::get_singleton()->map_set_cell_size(map, 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;
- Navigation2DServer::get_singleton()->map_set_edge_connection_margin(map, 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 Navigation2DServer::get_singleton()->map_get_path(map, p_start, p_end, p_optimize);
+ 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 Navigation2DServer::get_singleton()->map_get_closest_point(map, p_point);
+ return NavigationServer2D::get_singleton()->map_get_closest_point(map, p_point);
}
RID Navigation2D::get_closest_point_owner(const Vector2 &p_point) const {
- return Navigation2DServer::get_singleton()->map_get_closest_point_owner(map, p_point);
+ return NavigationServer2D::get_singleton()->map_get_closest_point_owner(map, p_point);
}
Navigation2D::Navigation2D() {
- map = Navigation2DServer::get_singleton()->map_create();
+ map = NavigationServer2D::get_singleton()->map_create();
set_cell_size(10); // Ten pixels
set_edge_connection_margin(100);
}
Navigation2D::~Navigation2D() {
- Navigation2DServer::get_singleton()->free(map);
+ NavigationServer2D::get_singleton()->free(map);
}
diff --git a/scene/2d/navigation_2d.h b/scene/2d/navigation_2d.h
index 5520f5006e..1da13fc78a 100644
--- a/scene/2d/navigation_2d.h
+++ b/scene/2d/navigation_2d.h
@@ -31,7 +31,7 @@
#ifndef NAVIGATION_2D_H
#define NAVIGATION_2D_H
-#include "scene/2d/navigation_polygon.h"
+#include "scene/2d/navigation_region_2d.h"
#include "scene/2d/node_2d.h"
class Navigation2D : public Node2D {
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index f5fe113f29..32da46e8a8 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -32,7 +32,7 @@
#include "core/engine.h"
#include "scene/2d/navigation_2d.h"
-#include "servers/navigation_2d_server.h"
+#include "servers/navigation_server_2d.h"
void NavigationAgent2D::_bind_methods() {
@@ -94,16 +94,16 @@ void NavigationAgent2D::_notification(int p_what) {
agent_parent = Object::cast_to<Node2D>(get_parent());
- Navigation2DServer::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
// Search the navigation node and set it
{
- Navigation2D *nav = NULL;
+ Navigation2D *nav = nullptr;
Node *p = get_parent();
- while (p != NULL) {
+ while (p != nullptr) {
nav = Object::cast_to<Navigation2D>(p);
- if (nav != NULL)
- p = NULL;
+ if (nav != nullptr)
+ p = nullptr;
else
p = p->get_parent();
}
@@ -114,14 +114,14 @@ void NavigationAgent2D::_notification(int p_what) {
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- agent_parent = NULL;
- set_navigation(NULL);
+ agent_parent = nullptr;
+ set_navigation(nullptr);
set_physics_process_internal(false);
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
- Navigation2DServer::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().get_origin());
+ 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");
@@ -134,15 +134,15 @@ void NavigationAgent2D::_notification(int p_what) {
}
NavigationAgent2D::NavigationAgent2D() :
- agent_parent(NULL),
- navigation(NULL),
+ agent_parent(nullptr),
+ navigation(nullptr),
agent(RID()),
target_desired_distance(1.0),
path_max_distance(3.0),
velocity_submitted(false),
target_reached(false),
navigation_finished(true) {
- agent = Navigation2DServer::get_singleton()->agent_create();
+ agent = NavigationServer2D::get_singleton()->agent_create();
set_neighbor_dist(500.0);
set_max_neighbors(10);
set_time_horizon(20.0);
@@ -151,7 +151,7 @@ NavigationAgent2D::NavigationAgent2D() :
}
NavigationAgent2D::~NavigationAgent2D() {
- Navigation2DServer::get_singleton()->free(agent);
+ NavigationServer2D::get_singleton()->free(agent);
agent = RID(); // Pointless
}
@@ -160,12 +160,12 @@ void NavigationAgent2D::set_navigation(Navigation2D *p_nav) {
return; // Pointless
navigation = p_nav;
- Navigation2DServer::get_singleton()->agent_set_map(agent, navigation == NULL ? RID() : navigation->get_rid());
+ 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 == NULL);
+ ERR_FAIL_COND(nav == nullptr);
set_navigation(nav);
}
@@ -179,27 +179,27 @@ void NavigationAgent2D::set_target_desired_distance(real_t p_dd) {
void NavigationAgent2D::set_radius(real_t p_radius) {
radius = p_radius;
- Navigation2DServer::get_singleton()->agent_set_radius(agent, radius);
+ NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
}
void NavigationAgent2D::set_neighbor_dist(real_t p_dist) {
neighbor_dist = p_dist;
- Navigation2DServer::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist);
+ NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist);
}
void NavigationAgent2D::set_max_neighbors(int p_count) {
max_neighbors = p_count;
- Navigation2DServer::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
+ NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
}
void NavigationAgent2D::set_time_horizon(real_t p_time) {
time_horizon = p_time;
- Navigation2DServer::get_singleton()->agent_set_time_horizon(agent, time_horizon);
+ NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
}
void NavigationAgent2D::set_max_speed(real_t p_max_speed) {
max_speed = p_max_speed;
- Navigation2DServer::get_singleton()->agent_set_max_speed(agent, max_speed);
+ NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
}
void NavigationAgent2D::set_path_max_distance(real_t p_pmd) {
@@ -215,6 +215,7 @@ void NavigationAgent2D::set_target_location(Vector2 p_location) {
navigation_path.clear();
target_reached = false;
navigation_finished = false;
+ update_frame_id = 0;
}
Vector2 NavigationAgent2D::get_target_location() const {
@@ -224,7 +225,7 @@ Vector2 NavigationAgent2D::get_target_location() const {
Vector2 NavigationAgent2D::get_next_location() {
update_navigation();
if (navigation_path.size() == 0) {
- ERR_FAIL_COND_V(agent_parent == NULL, Vector2());
+ ERR_FAIL_COND_V(agent_parent == nullptr, Vector2());
return agent_parent->get_global_transform().get_origin();
} else {
return navigation_path[nav_path_index];
@@ -232,7 +233,7 @@ Vector2 NavigationAgent2D::get_next_location() {
}
real_t NavigationAgent2D::distance_to_target() const {
- ERR_FAIL_COND_V(agent_parent == NULL, 0.0);
+ ERR_FAIL_COND_V(agent_parent == nullptr, 0.0);
return agent_parent->get_global_transform().get_origin().distance_to(target_location);
}
@@ -259,8 +260,8 @@ Vector2 NavigationAgent2D::get_final_location() {
void NavigationAgent2D::set_velocity(Vector2 p_velocity) {
target_velocity = p_velocity;
- Navigation2DServer::get_singleton()->agent_set_target_velocity(agent, target_velocity);
- Navigation2DServer::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
+ NavigationServer2D::get_singleton()->agent_set_target_velocity(agent, target_velocity);
+ NavigationServer2D::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
velocity_submitted = true;
}
@@ -287,8 +288,8 @@ String NavigationAgent2D::get_configuration_warning() const {
void NavigationAgent2D::update_navigation() {
- if (agent_parent == NULL) return;
- if (navigation == NULL) return;
+ if (agent_parent == nullptr) return;
+ if (navigation == nullptr) return;
if (update_frame_id == Engine::get_singleton()->get_physics_frames()) return;
update_frame_id = Engine::get_singleton()->get_physics_frames();
@@ -297,7 +298,7 @@ void NavigationAgent2D::update_navigation() {
bool reload_path = false;
- if (Navigation2DServer::get_singleton()->agent_is_map_changed(agent)) {
+ if (NavigationServer2D::get_singleton()->agent_is_map_changed(agent)) {
reload_path = true;
} else if (navigation_path.size() == 0) {
reload_path = true;
@@ -316,7 +317,7 @@ void NavigationAgent2D::update_navigation() {
}
if (reload_path) {
- navigation_path = Navigation2DServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
+ navigation_path = NavigationServer2D::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
navigation_finished = false;
nav_path_index = 0;
emit_signal("path_changed");
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index cc9f5740a9..50d02ca507 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -33,7 +33,7 @@
#include "scene/2d/collision_shape_2d.h"
#include "scene/2d/navigation_2d.h"
#include "scene/2d/physics_body_2d.h"
-#include "servers/navigation_2d_server.h"
+#include "servers/navigation_server_2d.h"
void NavigationObstacle2D::_bind_methods() {
@@ -49,12 +49,12 @@ void NavigationObstacle2D::_notification(int p_what) {
// Search the navigation node and set it
{
- Navigation2D *nav = NULL;
+ Navigation2D *nav = nullptr;
Node *p = get_parent();
- while (p != NULL) {
+ while (p != nullptr) {
nav = Object::cast_to<Navigation2D>(p);
- if (nav != NULL)
- p = NULL;
+ if (nav != nullptr)
+ p = nullptr;
else
p = p->get_parent();
}
@@ -65,13 +65,13 @@ void NavigationObstacle2D::_notification(int p_what) {
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- set_navigation(NULL);
+ set_navigation(nullptr);
set_physics_process_internal(false);
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
Node2D *node = Object::cast_to<Node2D>(get_parent());
if (node) {
- Navigation2DServer::get_singleton()->agent_set_position(agent, node->get_global_transform().get_origin());
+ NavigationServer2D::get_singleton()->agent_set_position(agent, node->get_global_transform().get_origin());
}
} break;
@@ -79,13 +79,13 @@ void NavigationObstacle2D::_notification(int p_what) {
}
NavigationObstacle2D::NavigationObstacle2D() :
- navigation(NULL),
+ navigation(nullptr),
agent(RID()) {
- agent = Navigation2DServer::get_singleton()->agent_create();
+ agent = NavigationServer2D::get_singleton()->agent_create();
}
NavigationObstacle2D::~NavigationObstacle2D() {
- Navigation2DServer::get_singleton()->free(agent);
+ NavigationServer2D::get_singleton()->free(agent);
agent = RID(); // Pointless
}
@@ -94,12 +94,12 @@ void NavigationObstacle2D::set_navigation(Navigation2D *p_nav) {
return; // Pointless
navigation = p_nav;
- Navigation2DServer::get_singleton()->agent_set_map(agent, navigation == NULL ? RID() : navigation->get_rid());
+ 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 == NULL);
+ ERR_FAIL_COND(nav == nullptr);
set_navigation(nav);
}
@@ -146,9 +146,9 @@ void NavigationObstacle2D::update_agent_shape() {
radius = 1.0; // Never a 0 radius
// Initialize the Agent as an object
- Navigation2DServer::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
- Navigation2DServer::get_singleton()->agent_set_max_neighbors(agent, 0);
- Navigation2DServer::get_singleton()->agent_set_time_horizon(agent, 0.0);
- Navigation2DServer::get_singleton()->agent_set_radius(agent, radius);
- Navigation2DServer::get_singleton()->agent_set_max_speed(agent, 0.0);
+ 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_polygon.cpp b/scene/2d/navigation_polygon.cpp
deleted file mode 100644
index 9159ef21c5..0000000000
--- a/scene/2d/navigation_polygon.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/*************************************************************************/
-/* navigation_polygon.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_polygon.h"
-
-#include "core/core_string_names.h"
-#include "core/engine.h"
-#include "core/os/mutex.h"
-#include "navigation_2d.h"
-#include "servers/navigation_2d_server.h"
-
-#include "thirdparty/misc/triangulator.h"
-
-#ifdef TOOLS_ENABLED
-Rect2 NavigationPolygon::_edit_get_rect() const {
-
- if (rect_cache_dirty) {
- item_rect = Rect2();
- bool first = true;
-
- for (int i = 0; i < outlines.size(); i++) {
- const Vector<Vector2> &outline = outlines[i];
- const int outline_size = outline.size();
- if (outline_size < 3)
- continue;
- const Vector2 *p = outline.ptr();
- for (int j = 0; j < outline_size; j++) {
- if (first) {
- item_rect = Rect2(p[j], Vector2(0, 0));
- first = false;
- } else {
- item_rect.expand_to(p[j]);
- }
- }
- }
-
- rect_cache_dirty = false;
- }
- return item_rect;
-}
-
-bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
-
- for (int i = 0; i < outlines.size(); i++) {
- const Vector<Vector2> &outline = outlines[i];
- const int outline_size = outline.size();
- if (outline_size < 3)
- continue;
- if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
- return true;
- }
- return false;
-}
-#endif
-
-void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
-
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
- vertices = p_vertices;
- rect_cache_dirty = true;
-}
-
-Vector<Vector2> NavigationPolygon::get_vertices() const {
-
- return vertices;
-}
-
-void NavigationPolygon::_set_polygons(const Array &p_array) {
-
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
- polygons.resize(p_array.size());
- for (int i = 0; i < p_array.size(); i++) {
- polygons.write[i].indices = p_array[i];
- }
-}
-
-Array NavigationPolygon::_get_polygons() const {
-
- Array ret;
- ret.resize(polygons.size());
- for (int i = 0; i < ret.size(); i++) {
- ret[i] = polygons[i].indices;
- }
-
- return ret;
-}
-
-void NavigationPolygon::_set_outlines(const Array &p_array) {
-
- outlines.resize(p_array.size());
- for (int i = 0; i < p_array.size(); i++) {
- outlines.write[i] = p_array[i];
- }
- rect_cache_dirty = true;
-}
-
-Array NavigationPolygon::_get_outlines() const {
-
- Array ret;
- ret.resize(outlines.size());
- for (int i = 0; i < ret.size(); i++) {
- ret[i] = outlines[i];
- }
-
- return ret;
-}
-
-void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
-
- Polygon polygon;
- polygon.indices = p_polygon;
- polygons.push_back(polygon);
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
-}
-
-void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) {
-
- outlines.insert(p_index, p_outline);
- rect_cache_dirty = true;
-}
-
-int NavigationPolygon::get_polygon_count() const {
-
- return polygons.size();
-}
-Vector<int> NavigationPolygon::get_polygon(int p_idx) {
-
- ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>());
- return polygons[p_idx].indices;
-}
-void NavigationPolygon::clear_polygons() {
-
- polygons.clear();
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
-}
-
-Ref<NavigationMesh> NavigationPolygon::get_mesh() {
- MutexLock lock(navmesh_generation);
-
- if (navmesh.is_null()) {
- navmesh.instance();
- Vector<Vector3> verts;
- {
- verts.resize(get_vertices().size());
- Vector3 *w = verts.ptrw();
-
- const Vector2 *r = get_vertices().ptr();
-
- for (int i(0); i < get_vertices().size(); i++) {
- w[i] = Vector3(r[i].x, 0.0, r[i].y);
- }
- }
- navmesh->set_vertices(verts);
-
- for (int i(0); i < get_polygon_count(); i++) {
- navmesh->add_polygon(get_polygon(i));
- }
- }
-
- return navmesh;
-}
-
-void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) {
-
- outlines.push_back(p_outline);
- rect_cache_dirty = true;
-}
-
-int NavigationPolygon::get_outline_count() const {
-
- return outlines.size();
-}
-
-void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) {
- ERR_FAIL_INDEX(p_idx, outlines.size());
- outlines.write[p_idx] = p_outline;
- rect_cache_dirty = true;
-}
-
-void NavigationPolygon::remove_outline(int p_idx) {
-
- ERR_FAIL_INDEX(p_idx, outlines.size());
- outlines.remove(p_idx);
- rect_cache_dirty = true;
-}
-
-Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>());
- return outlines[p_idx];
-}
-
-void NavigationPolygon::clear_outlines() {
-
- outlines.clear();
- rect_cache_dirty = true;
-}
-void NavigationPolygon::make_polygons_from_outlines() {
-
- {
- MutexLock lock(navmesh_generation);
- navmesh.unref();
- }
- List<TriangulatorPoly> in_poly, out_poly;
-
- Vector2 outside_point(-1e10, -1e10);
-
- for (int i = 0; i < outlines.size(); i++) {
-
- Vector<Vector2> ol = outlines[i];
- int olsize = ol.size();
- if (olsize < 3)
- continue;
- const Vector2 *r = ol.ptr();
- for (int j = 0; j < olsize; j++) {
- outside_point.x = MAX(r[j].x, outside_point.x);
- outside_point.y = MAX(r[j].y, outside_point.y);
- }
- }
-
- outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues
-
- for (int i = 0; i < outlines.size(); i++) {
-
- Vector<Vector2> ol = outlines[i];
- int olsize = ol.size();
- if (olsize < 3)
- continue;
- const Vector2 *r = ol.ptr();
-
- int interscount = 0;
- //test if this is an outer outline
- for (int k = 0; k < outlines.size(); k++) {
-
- if (i == k)
- continue; //no self intersect
-
- Vector<Vector2> ol2 = outlines[k];
- int olsize2 = ol2.size();
- if (olsize2 < 3)
- continue;
- const Vector2 *r2 = ol2.ptr();
-
- for (int l = 0; l < olsize2; l++) {
-
- if (Geometry::segment_intersects_segment_2d(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], NULL)) {
- interscount++;
- }
- }
- }
-
- bool outer = (interscount % 2) == 0;
-
- TriangulatorPoly tp;
- tp.Init(olsize);
- for (int j = 0; j < olsize; j++) {
- tp[j] = r[j];
- }
-
- if (outer)
- tp.SetOrientation(TRIANGULATOR_CCW);
- else {
- tp.SetOrientation(TRIANGULATOR_CW);
- tp.SetHole(true);
- }
-
- in_poly.push_back(tp);
- }
-
- TriangulatorPartition tpart;
- if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- ERR_PRINT("NavigationPolygon: Convex partition failed!");
- return;
- }
-
- polygons.clear();
- vertices.resize(0);
-
- Map<Vector2, int> points;
- for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
-
- TriangulatorPoly &tp = I->get();
-
- struct Polygon p;
-
- for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
-
- Map<Vector2, int>::Element *E = points.find(tp[i]);
- if (!E) {
- E = points.insert(tp[i], vertices.size());
- vertices.push_back(tp[i]);
- }
- p.indices.push_back(E->get());
- }
-
- polygons.push_back(p);
- }
-
- emit_signal(CoreStringNames::get_singleton()->changed);
-}
-
-void NavigationPolygon::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
- ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
-
- ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon);
- ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
- ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
- ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
-
- ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
- ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
- ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count);
- ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline);
- ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
- ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
- ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
- ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
-
- ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
- ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
-
- ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
- ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
-
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
-}
-
-NavigationPolygon::NavigationPolygon() :
- rect_cache_dirty(true) {
-}
-
-NavigationPolygon::~NavigationPolygon() {
-}
-
-void NavigationRegion2D::set_enabled(bool p_enabled) {
-
- if (enabled == p_enabled)
- return;
- enabled = p_enabled;
-
- if (!is_inside_tree())
- return;
-
- if (!enabled) {
-
- Navigation2DServer::get_singleton()->region_set_map(region, RID());
- } else {
-
- if (navigation) {
-
- Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
- }
- }
-
- if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())
- update();
-}
-
-bool NavigationRegion2D::is_enabled() const {
-
- return enabled;
-}
-
-/////////////////////////////
-#ifdef TOOLS_ENABLED
-Rect2 NavigationRegion2D::_edit_get_rect() const {
-
- return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
-}
-
-bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
-
- return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
-}
-#endif
-
-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) {
-
- Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
- }
- break;
- }
-
- c = Object::cast_to<Node2D>(c->get_parent());
- }
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- Navigation2DServer::get_singleton()->region_set_transform(region, get_global_transform());
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- if (navigation) {
-
- Navigation2DServer::get_singleton()->region_set_map(region, RID());
- }
- navigation = NULL;
- } 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)
- return;
-
- Color color;
- if (enabled) {
- color = get_tree()->get_debug_navigation_color();
- } 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;
- }
- }
-
- Vector<int> indices;
-
- for (int i = 0; i < navpoly->get_polygon_count(); i++) {
- 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);
- }
- }
- }
- VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors);
- }
- } break;
- }
-}
-
-void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) {
-
- if (p_navpoly == navpoly) {
- return;
- }
-
- if (navpoly.is_valid()) {
- navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
- }
-
- navpoly = p_navpoly;
- Navigation2DServer::get_singleton()->region_set_navpoly(region, p_navpoly);
-
- if (navpoly.is_valid()) {
- navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
- }
- _navpoly_changed();
-
- _change_notify("navpoly");
- update_configuration_warning();
-}
-
-Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
-
- return navpoly;
-}
-
-void NavigationRegion2D::_navpoly_changed() {
-
- if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()))
- update();
-}
-
-String NavigationRegion2D::get_configuration_warning() const {
-
- if (!is_visible_in_tree() || !is_inside_tree())
- return String();
-
- if (!navpoly.is_valid()) {
- return 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 String();
- }
-
- c = Object::cast_to<Node2D>(c->get_parent());
- }
-
- return TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
-}
-
-void NavigationRegion2D::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon);
- ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon);
-
- 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("_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");
-}
-
-NavigationRegion2D::NavigationRegion2D() {
-
- enabled = true;
- set_notify_transform(true);
- region = Navigation2DServer::get_singleton()->region_create();
-
- navigation = NULL;
-}
-
-NavigationRegion2D::~NavigationRegion2D() {
- Navigation2DServer::get_singleton()->free(region);
-}
diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h
deleted file mode 100644
index 579d6b0e0e..0000000000
--- a/scene/2d/navigation_polygon.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*************************************************************************/
-/* navigation_polygon.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 NAVIGATION_POLYGON_H
-#define NAVIGATION_POLYGON_H
-
-#include "scene/2d/node_2d.h"
-#include "scene/resources/navigation_mesh.h"
-
-class NavigationPolygon : public Resource {
-
- GDCLASS(NavigationPolygon, Resource);
-
- Vector<Vector2> vertices;
- struct Polygon {
- Vector<int> indices;
- };
- Vector<Polygon> polygons;
- Vector<Vector<Vector2> > outlines;
-
- mutable Rect2 item_rect;
- mutable bool rect_cache_dirty;
-
- Mutex navmesh_generation;
- // Navigation mesh
- Ref<NavigationMesh> navmesh;
-
-protected:
- static void _bind_methods();
-
- void _set_polygons(const Array &p_array);
- Array _get_polygons() const;
-
- void _set_outlines(const Array &p_array);
- Array _get_outlines() const;
-
-public:
-#ifdef TOOLS_ENABLED
- Rect2 _edit_get_rect() const;
- bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-#endif
-
- void set_vertices(const Vector<Vector2> &p_vertices);
- Vector<Vector2> get_vertices() const;
-
- void add_polygon(const Vector<int> &p_polygon);
- int get_polygon_count() const;
-
- void add_outline(const Vector<Vector2> &p_outline);
- void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index);
- void set_outline(int p_idx, const Vector<Vector2> &p_outline);
- Vector<Vector2> get_outline(int p_idx) const;
- void remove_outline(int p_idx);
- int get_outline_count() const;
-
- void clear_outlines();
- void make_polygons_from_outlines();
-
- Vector<int> get_polygon(int p_idx);
- void clear_polygons();
-
- Ref<NavigationMesh> get_mesh();
-
- NavigationPolygon();
- ~NavigationPolygon();
-};
-
-class Navigation2D;
-
-class NavigationRegion2D : public Node2D {
-
- GDCLASS(NavigationRegion2D, Node2D);
-
- bool enabled;
- RID region;
- Navigation2D *navigation;
- Ref<NavigationPolygon> navpoly;
-
- void _navpoly_changed();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
-#ifdef TOOLS_ENABLED
- virtual Rect2 _edit_get_rect() const;
- virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-#endif
-
- void set_enabled(bool p_enabled);
- bool is_enabled() const;
-
- void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
- Ref<NavigationPolygon> get_navigation_polygon() const;
-
- String get_configuration_warning() const;
-
- NavigationRegion2D();
- ~NavigationRegion2D();
-};
-
-#endif // NAVIGATIONPOLYGON_H
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
new file mode 100644
index 0000000000..d77fd5b097
--- /dev/null
+++ b/scene/2d/navigation_region_2d.cpp
@@ -0,0 +1,582 @@
+/*************************************************************************/
+/* navigation_region_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_region_2d.h"
+
+#include "core/core_string_names.h"
+#include "core/engine.h"
+#include "core/os/mutex.h"
+#include "navigation_2d.h"
+#include "servers/navigation_server_2d.h"
+
+#include "thirdparty/misc/triangulator.h"
+
+#ifdef TOOLS_ENABLED
+Rect2 NavigationPolygon::_edit_get_rect() const {
+
+ if (rect_cache_dirty) {
+ item_rect = Rect2();
+ bool first = true;
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const Vector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ const Vector2 *p = outline.ptr();
+ for (int j = 0; j < outline_size; j++) {
+ if (first) {
+ item_rect = Rect2(p[j], Vector2(0, 0));
+ first = false;
+ } else {
+ item_rect.expand_to(p[j]);
+ }
+ }
+ }
+
+ rect_cache_dirty = false;
+ }
+ return item_rect;
+}
+
+bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const Vector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
+ return true;
+ }
+ return false;
+}
+#endif
+
+void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
+
+ {
+ MutexLock lock(navmesh_generation);
+ navmesh.unref();
+ }
+ vertices = p_vertices;
+ rect_cache_dirty = true;
+}
+
+Vector<Vector2> NavigationPolygon::get_vertices() const {
+
+ return vertices;
+}
+
+void NavigationPolygon::_set_polygons(const Array &p_array) {
+
+ {
+ MutexLock lock(navmesh_generation);
+ navmesh.unref();
+ }
+ polygons.resize(p_array.size());
+ for (int i = 0; i < p_array.size(); i++) {
+ polygons.write[i].indices = p_array[i];
+ }
+}
+
+Array NavigationPolygon::_get_polygons() const {
+
+ Array ret;
+ ret.resize(polygons.size());
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i] = polygons[i].indices;
+ }
+
+ return ret;
+}
+
+void NavigationPolygon::_set_outlines(const Array &p_array) {
+
+ outlines.resize(p_array.size());
+ for (int i = 0; i < p_array.size(); i++) {
+ outlines.write[i] = p_array[i];
+ }
+ rect_cache_dirty = true;
+}
+
+Array NavigationPolygon::_get_outlines() const {
+
+ Array ret;
+ ret.resize(outlines.size());
+ for (int i = 0; i < ret.size(); i++) {
+ ret[i] = outlines[i];
+ }
+
+ return ret;
+}
+
+void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
+
+ Polygon polygon;
+ polygon.indices = p_polygon;
+ polygons.push_back(polygon);
+ {
+ MutexLock lock(navmesh_generation);
+ navmesh.unref();
+ }
+}
+
+void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) {
+
+ outlines.insert(p_index, p_outline);
+ rect_cache_dirty = true;
+}
+
+int NavigationPolygon::get_polygon_count() const {
+
+ return polygons.size();
+}
+Vector<int> NavigationPolygon::get_polygon(int p_idx) {
+
+ ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>());
+ return polygons[p_idx].indices;
+}
+void NavigationPolygon::clear_polygons() {
+
+ polygons.clear();
+ {
+ MutexLock lock(navmesh_generation);
+ navmesh.unref();
+ }
+}
+
+Ref<NavigationMesh> NavigationPolygon::get_mesh() {
+ MutexLock lock(navmesh_generation);
+
+ if (navmesh.is_null()) {
+ navmesh.instance();
+ Vector<Vector3> verts;
+ {
+ verts.resize(get_vertices().size());
+ Vector3 *w = verts.ptrw();
+
+ const Vector2 *r = get_vertices().ptr();
+
+ for (int i(0); i < get_vertices().size(); i++) {
+ w[i] = Vector3(r[i].x, 0.0, r[i].y);
+ }
+ }
+ navmesh->set_vertices(verts);
+
+ for (int i(0); i < get_polygon_count(); i++) {
+ navmesh->add_polygon(get_polygon(i));
+ }
+ }
+
+ return navmesh;
+}
+
+void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) {
+
+ outlines.push_back(p_outline);
+ rect_cache_dirty = true;
+}
+
+int NavigationPolygon::get_outline_count() const {
+
+ return outlines.size();
+}
+
+void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) {
+ ERR_FAIL_INDEX(p_idx, outlines.size());
+ outlines.write[p_idx] = p_outline;
+ rect_cache_dirty = true;
+}
+
+void NavigationPolygon::remove_outline(int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx, outlines.size());
+ outlines.remove(p_idx);
+ rect_cache_dirty = true;
+}
+
+Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>());
+ return outlines[p_idx];
+}
+
+void NavigationPolygon::clear_outlines() {
+
+ outlines.clear();
+ rect_cache_dirty = true;
+}
+void NavigationPolygon::make_polygons_from_outlines() {
+
+ {
+ MutexLock lock(navmesh_generation);
+ navmesh.unref();
+ }
+ List<TriangulatorPoly> in_poly, out_poly;
+
+ Vector2 outside_point(-1e10, -1e10);
+
+ for (int i = 0; i < outlines.size(); i++) {
+
+ Vector<Vector2> ol = outlines[i];
+ int olsize = ol.size();
+ if (olsize < 3)
+ continue;
+ const Vector2 *r = ol.ptr();
+ for (int j = 0; j < olsize; j++) {
+ outside_point.x = MAX(r[j].x, outside_point.x);
+ outside_point.y = MAX(r[j].y, outside_point.y);
+ }
+ }
+
+ outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues
+
+ for (int i = 0; i < outlines.size(); i++) {
+
+ Vector<Vector2> ol = outlines[i];
+ int olsize = ol.size();
+ if (olsize < 3)
+ continue;
+ const Vector2 *r = ol.ptr();
+
+ int interscount = 0;
+ //test if this is an outer outline
+ for (int k = 0; k < outlines.size(); k++) {
+
+ if (i == k)
+ continue; //no self intersect
+
+ Vector<Vector2> ol2 = outlines[k];
+ int olsize2 = ol2.size();
+ if (olsize2 < 3)
+ continue;
+ const Vector2 *r2 = ol2.ptr();
+
+ for (int l = 0; l < olsize2; l++) {
+
+ if (Geometry::segment_intersects_segment_2d(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], nullptr)) {
+ interscount++;
+ }
+ }
+ }
+
+ bool outer = (interscount % 2) == 0;
+
+ TriangulatorPoly tp;
+ tp.Init(olsize);
+ for (int j = 0; j < olsize; j++) {
+ tp[j] = r[j];
+ }
+
+ if (outer)
+ tp.SetOrientation(TRIANGULATOR_CCW);
+ else {
+ tp.SetOrientation(TRIANGULATOR_CW);
+ tp.SetHole(true);
+ }
+
+ in_poly.push_back(tp);
+ }
+
+ TriangulatorPartition tpart;
+ if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
+ ERR_PRINT("NavigationPolygon: Convex partition failed!");
+ return;
+ }
+
+ polygons.clear();
+ vertices.resize(0);
+
+ Map<Vector2, int> points;
+ for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
+
+ TriangulatorPoly &tp = I->get();
+
+ struct Polygon p;
+
+ for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
+
+ Map<Vector2, int>::Element *E = points.find(tp[i]);
+ if (!E) {
+ E = points.insert(tp[i], vertices.size());
+ vertices.push_back(tp[i]);
+ }
+ p.indices.push_back(E->get());
+ }
+
+ polygons.push_back(p);
+ }
+
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void NavigationPolygon::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
+ ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
+
+ ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon);
+ ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
+ ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
+ ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
+
+ ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
+ ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
+ ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count);
+ ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline);
+ ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
+ ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
+ ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
+ ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
+
+ ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
+ ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
+
+ ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
+ ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
+}
+
+NavigationPolygon::NavigationPolygon() :
+ rect_cache_dirty(true) {
+}
+
+NavigationPolygon::~NavigationPolygon() {
+}
+
+void NavigationRegion2D::set_enabled(bool p_enabled) {
+
+ if (enabled == p_enabled)
+ return;
+ enabled = p_enabled;
+
+ if (!is_inside_tree())
+ return;
+
+ if (!enabled) {
+
+ NavigationServer2D::get_singleton()->region_set_map(region, RID());
+ } else {
+
+ if (navigation) {
+
+ NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid());
+ }
+ }
+
+ if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())
+ update();
+}
+
+bool NavigationRegion2D::is_enabled() const {
+
+ return enabled;
+}
+
+/////////////////////////////
+#ifdef TOOLS_ENABLED
+Rect2 NavigationRegion2D::_edit_get_rect() const {
+
+ return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
+}
+
+bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+#endif
+
+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());
+ }
+
+ } 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());
+ }
+ 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)
+ return;
+
+ Color color;
+ if (enabled) {
+ color = get_tree()->get_debug_navigation_color();
+ } 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;
+ }
+ }
+
+ Vector<int> indices;
+
+ for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+ 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);
+ }
+ }
+ }
+ RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors);
+ }
+ } break;
+ }
+}
+
+void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) {
+
+ if (p_navpoly == navpoly) {
+ return;
+ }
+
+ if (navpoly.is_valid()) {
+ navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
+ }
+
+ navpoly = p_navpoly;
+ NavigationServer2D::get_singleton()->region_set_navpoly(region, p_navpoly);
+
+ if (navpoly.is_valid()) {
+ navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
+ }
+ _navpoly_changed();
+
+ _change_notify("navpoly");
+ update_configuration_warning();
+}
+
+Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
+
+ return navpoly;
+}
+
+void NavigationRegion2D::_navpoly_changed() {
+
+ if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()))
+ update();
+}
+
+String NavigationRegion2D::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!navpoly.is_valid()) {
+ return 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 String();
+ }
+
+ c = Object::cast_to<Node2D>(c->get_parent());
+ }
+
+ return TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
+}
+
+void NavigationRegion2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon);
+ ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon);
+
+ 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("_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");
+}
+
+NavigationRegion2D::NavigationRegion2D() {
+
+ enabled = true;
+ set_notify_transform(true);
+ region = NavigationServer2D::get_singleton()->region_create();
+
+ navigation = nullptr;
+}
+
+NavigationRegion2D::~NavigationRegion2D() {
+ NavigationServer2D::get_singleton()->free(region);
+}
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
new file mode 100644
index 0000000000..73e056a353
--- /dev/null
+++ b/scene/2d/navigation_region_2d.h
@@ -0,0 +1,130 @@
+/*************************************************************************/
+/* navigation_region_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 NAVIGATION_REGION_2D_H
+#define NAVIGATION_REGION_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/navigation_mesh.h"
+
+class NavigationPolygon : public Resource {
+
+ GDCLASS(NavigationPolygon, Resource);
+
+ Vector<Vector2> vertices;
+ struct Polygon {
+ Vector<int> indices;
+ };
+ Vector<Polygon> polygons;
+ Vector<Vector<Vector2>> outlines;
+
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty;
+
+ Mutex navmesh_generation;
+ // Navigation mesh
+ Ref<NavigationMesh> navmesh;
+
+protected:
+ static void _bind_methods();
+
+ void _set_polygons(const Array &p_array);
+ Array _get_polygons() const;
+
+ void _set_outlines(const Array &p_array);
+ Array _get_outlines() const;
+
+public:
+#ifdef TOOLS_ENABLED
+ Rect2 _edit_get_rect() const;
+ bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+#endif
+
+ void set_vertices(const Vector<Vector2> &p_vertices);
+ Vector<Vector2> get_vertices() const;
+
+ void add_polygon(const Vector<int> &p_polygon);
+ int get_polygon_count() const;
+
+ void add_outline(const Vector<Vector2> &p_outline);
+ void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index);
+ void set_outline(int p_idx, const Vector<Vector2> &p_outline);
+ Vector<Vector2> get_outline(int p_idx) const;
+ void remove_outline(int p_idx);
+ int get_outline_count() const;
+
+ void clear_outlines();
+ void make_polygons_from_outlines();
+
+ Vector<int> get_polygon(int p_idx);
+ void clear_polygons();
+
+ Ref<NavigationMesh> get_mesh();
+
+ NavigationPolygon();
+ ~NavigationPolygon();
+};
+
+class Navigation2D;
+
+class NavigationRegion2D : public Node2D {
+
+ GDCLASS(NavigationRegion2D, Node2D);
+
+ bool enabled;
+ RID region;
+ Navigation2D *navigation;
+ Ref<NavigationPolygon> navpoly;
+
+ void _navpoly_changed();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+#ifdef TOOLS_ENABLED
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+#endif
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
+ Ref<NavigationPolygon> get_navigation_polygon() const;
+
+ String get_configuration_warning() const;
+
+ NavigationRegion2D();
+ ~NavigationRegion2D();
+};
+
+#endif // NAVIGATION_REGION_2D_H
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index df21538609..ac8a77b6cb 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -32,8 +32,8 @@
#include "core/message_queue.h"
#include "scene/gui/control.h"
-#include "scene/main/viewport.h"
-#include "servers/visual_server.h"
+#include "scene/main/window.h"
+#include "servers/rendering_server.h"
#ifdef TOOLS_ENABLED
Dictionary Node2D::_edit_get_state() const {
@@ -136,7 +136,7 @@ void Node2D::_update_transform() {
_mat.set_rotation_and_scale(angle, _scale);
_mat.elements[2] = pos;
- VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
+ RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
if (!is_inside_tree())
return;
@@ -315,7 +315,7 @@ void Node2D::set_transform(const Transform2D &p_transform) {
_mat = p_transform;
_xform_dirty = true;
- VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
+ RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat);
if (!is_inside_tree())
return;
@@ -334,10 +334,10 @@ void Node2D::set_global_transform(const Transform2D &p_transform) {
void Node2D::set_z_index(int p_z) {
- ERR_FAIL_COND(p_z < VS::CANVAS_ITEM_Z_MIN);
- ERR_FAIL_COND(p_z > VS::CANVAS_ITEM_Z_MAX);
+ ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN);
+ ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX);
z_index = p_z;
- VS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index);
+ RS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index);
_change_notify("z_index");
}
@@ -346,7 +346,7 @@ void Node2D::set_z_as_relative(bool p_enabled) {
if (z_relative == p_enabled)
return;
z_relative = p_enabled;
- VS::get_singleton()->canvas_item_set_z_as_relative_to_parent(get_canvas_item(), p_enabled);
+ RS::get_singleton()->canvas_item_set_z_as_relative_to_parent(get_canvas_item(), p_enabled);
}
bool Node2D::is_z_relative() const {
@@ -452,7 +452,7 @@ void Node2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
ADD_GROUP("Z Index", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative");
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 00202481a6..abed05ed0c 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -31,7 +31,7 @@
#ifndef NODE2D_H
#define NODE2D_H
-#include "scene/2d/canvas_item.h"
+#include "scene/main/canvas_item.h"
class Node2D : public CanvasItem {
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 5aea1025ef..181f0f158c 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -78,7 +78,7 @@ void ParallaxLayer::_update_mirroring() {
RID c = pb->get_canvas();
RID ci = get_canvas_item();
Point2 mirrorScale = mirroring * get_scale();
- VisualServer::get_singleton()->canvas_set_item_mirroring(c, ci, mirrorScale);
+ RenderingServer::get_singleton()->canvas_set_item_mirroring(c, ci, mirrorScale);
}
}
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
deleted file mode 100644
index 2ba2fd8f79..0000000000
--- a/scene/2d/particles_2d.cpp
+++ /dev/null
@@ -1,432 +0,0 @@
-/*************************************************************************/
-/* particles_2d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "particles_2d.h"
-
-#include "core/os/os.h"
-#include "scene/resources/particles_material.h"
-#include "scene/scene_string_names.h"
-
-#ifdef TOOLS_ENABLED
-#include "core/engine.h"
-#endif
-
-void Particles2D::set_emitting(bool p_emitting) {
-
- VS::get_singleton()->particles_set_emitting(particles, p_emitting);
-
- if (p_emitting && one_shot) {
- set_process_internal(true);
- } else if (!p_emitting) {
- set_process_internal(false);
- }
-}
-
-void Particles2D::set_amount(int p_amount) {
-
- ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
- amount = p_amount;
- VS::get_singleton()->particles_set_amount(particles, amount);
-}
-void Particles2D::set_lifetime(float p_lifetime) {
-
- ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
- lifetime = p_lifetime;
- VS::get_singleton()->particles_set_lifetime(particles, lifetime);
-}
-
-void Particles2D::set_one_shot(bool p_enable) {
-
- one_shot = p_enable;
- VS::get_singleton()->particles_set_one_shot(particles, one_shot);
-
- if (is_emitting()) {
-
- set_process_internal(true);
- if (!one_shot)
- VisualServer::get_singleton()->particles_restart(particles);
- }
-
- if (!one_shot)
- set_process_internal(false);
-}
-void Particles2D::set_pre_process_time(float p_time) {
-
- pre_process_time = p_time;
- VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
-}
-void Particles2D::set_explosiveness_ratio(float p_ratio) {
-
- explosiveness_ratio = p_ratio;
- VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
-}
-void Particles2D::set_randomness_ratio(float p_ratio) {
-
- randomness_ratio = p_ratio;
- VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
-}
-void Particles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
-
- visibility_rect = p_visibility_rect;
- AABB aabb;
- aabb.position.x = p_visibility_rect.position.x;
- aabb.position.y = p_visibility_rect.position.y;
- aabb.size.x = p_visibility_rect.size.x;
- aabb.size.y = p_visibility_rect.size.y;
-
- VS::get_singleton()->particles_set_custom_aabb(particles, aabb);
-
- _change_notify("visibility_rect");
- update();
-}
-void Particles2D::set_use_local_coordinates(bool p_enable) {
-
- local_coords = p_enable;
- VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
- set_notify_transform(!p_enable);
- if (!p_enable && is_inside_tree()) {
- _update_particle_emission_transform();
- }
-}
-
-void Particles2D::_update_particle_emission_transform() {
-
- Transform2D xf2d = get_global_transform();
- Transform xf;
- xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
- xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
- xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
-
- VS::get_singleton()->particles_set_emission_transform(particles, xf);
-}
-
-void Particles2D::set_process_material(const Ref<Material> &p_material) {
-
- process_material = p_material;
- Ref<ParticlesMaterial> pm = p_material;
- if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
- // Likely a new (3D) material, modify it to match 2D space
- pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
- pm->set_gravity(Vector3(0, 98, 0));
- }
- RID material_rid;
- if (process_material.is_valid())
- material_rid = process_material->get_rid();
- VS::get_singleton()->particles_set_process_material(particles, material_rid);
-
- update_configuration_warning();
-}
-
-void Particles2D::set_speed_scale(float p_scale) {
-
- speed_scale = p_scale;
- VS::get_singleton()->particles_set_speed_scale(particles, p_scale);
-}
-
-bool Particles2D::is_emitting() const {
-
- return VS::get_singleton()->particles_get_emitting(particles);
-}
-int Particles2D::get_amount() const {
-
- return amount;
-}
-float Particles2D::get_lifetime() const {
-
- return lifetime;
-}
-
-bool Particles2D::get_one_shot() const {
-
- return one_shot;
-}
-float Particles2D::get_pre_process_time() const {
-
- return pre_process_time;
-}
-float Particles2D::get_explosiveness_ratio() const {
-
- return explosiveness_ratio;
-}
-float Particles2D::get_randomness_ratio() const {
-
- return randomness_ratio;
-}
-Rect2 Particles2D::get_visibility_rect() const {
-
- return visibility_rect;
-}
-bool Particles2D::get_use_local_coordinates() const {
-
- return local_coords;
-}
-Ref<Material> Particles2D::get_process_material() const {
-
- return process_material;
-}
-
-float Particles2D::get_speed_scale() const {
-
- return speed_scale;
-}
-
-void Particles2D::set_draw_order(DrawOrder p_order) {
-
- draw_order = p_order;
- VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order));
-}
-
-Particles2D::DrawOrder Particles2D::get_draw_order() const {
-
- return draw_order;
-}
-
-void Particles2D::set_fixed_fps(int p_count) {
- fixed_fps = p_count;
- VS::get_singleton()->particles_set_fixed_fps(particles, p_count);
-}
-
-int Particles2D::get_fixed_fps() const {
- return fixed_fps;
-}
-
-void Particles2D::set_fractional_delta(bool p_enable) {
- fractional_delta = p_enable;
- VS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
-}
-
-bool Particles2D::get_fractional_delta() const {
- return fractional_delta;
-}
-
-String Particles2D::get_configuration_warning() const {
-
- if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
- }
-
- String warnings;
-
- 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.");
- } else {
-
- CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
-
- if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
- const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
- 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.");
- }
- }
- }
-
- return warnings;
-}
-
-Rect2 Particles2D::capture_rect() const {
-
- AABB aabb = VS::get_singleton()->particles_get_current_aabb(particles);
- Rect2 r;
- r.position.x = aabb.position.x;
- r.position.y = aabb.position.y;
- r.size.x = aabb.size.x;
- r.size.y = aabb.size.y;
- return r;
-}
-
-void Particles2D::set_texture(const Ref<Texture2D> &p_texture) {
- texture = p_texture;
- update();
-}
-
-Ref<Texture2D> Particles2D::get_texture() const {
- return texture;
-}
-
-void Particles2D::set_normal_map(const Ref<Texture2D> &p_normal_map) {
-
- normal_map = p_normal_map;
- update();
-}
-
-Ref<Texture2D> Particles2D::get_normal_map() const {
- return normal_map;
-}
-
-void Particles2D::_validate_property(PropertyInfo &property) const {
-}
-
-void Particles2D::restart() {
- VS::get_singleton()->particles_restart(particles);
- VS::get_singleton()->particles_set_emitting(particles, true);
-}
-
-void Particles2D::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_DRAW) {
-
- RID texture_rid;
- if (texture.is_valid())
- texture_rid = texture->get_rid();
- RID normal_rid;
- if (normal_map.is_valid())
- normal_rid = normal_map->get_rid();
-
- VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
-
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
-
- draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
- }
-#endif
- }
-
- if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
- if (can_process()) {
- VS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
- } else {
-
- VS::get_singleton()->particles_set_speed_scale(particles, 0);
- }
- }
-
- if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- _update_particle_emission_transform();
- }
-
- if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (one_shot && !is_emitting()) {
- _change_notify();
- set_process_internal(false);
- }
- }
-}
-
-void Particles2D::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
- ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
- ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot);
- ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
- ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
- ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &Particles2D::set_visibility_rect);
- ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps);
- ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta);
- ClassDB::bind_method(D_METHOD("set_process_material", "material"), &Particles2D::set_process_material);
- ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles2D::set_speed_scale);
-
- ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
- ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
- ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
- ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot);
- ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
- ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
- ClassDB::bind_method(D_METHOD("get_visibility_rect"), &Particles2D::get_visibility_rect);
- ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles2D::get_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles2D::get_fixed_fps);
- ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles2D::get_fractional_delta);
- ClassDB::bind_method(D_METHOD("get_process_material"), &Particles2D::get_process_material);
- ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles2D::get_speed_scale);
-
- ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles2D::set_draw_order);
- ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles2D::get_draw_order);
-
- ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Particles2D::set_texture);
- ClassDB::bind_method(D_METHOD("get_texture"), &Particles2D::get_texture);
-
- ClassDB::bind_method(D_METHOD("set_normal_map", "texture"), &Particles2D::set_normal_map);
- ClassDB::bind_method(D_METHOD("get_normal_map"), &Particles2D::get_normal_map);
-
- ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect);
-
- ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
-
- 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_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
- 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, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
- ADD_GROUP("Drawing", "");
- ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
- 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"), "set_draw_order", "get_draw_order");
- ADD_GROUP("Process Material", "process_");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
- ADD_GROUP("Textures", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
-
- BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
- BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
-}
-
-Particles2D::Particles2D() {
-
- particles = VS::get_singleton()->particles_create();
-
- one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
- set_emitting(true);
- set_one_shot(false);
- set_amount(8);
- set_lifetime(1);
- set_fixed_fps(0);
- set_fractional_delta(true);
- set_pre_process_time(0);
- set_explosiveness_ratio(0);
- set_randomness_ratio(0);
- set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
- set_use_local_coordinates(true);
- set_draw_order(DRAW_ORDER_INDEX);
- set_speed_scale(1);
-}
-
-Particles2D::~Particles2D() {
-
- VS::get_singleton()->free(particles);
-}
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
deleted file mode 100644
index 66281d7950..0000000000
--- a/scene/2d/particles_2d.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*************************************************************************/
-/* particles_2d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PARTICLES_2D_H
-#define PARTICLES_2D_H
-
-#include "core/rid.h"
-#include "scene/2d/node_2d.h"
-#include "scene/resources/texture.h"
-
-class Particles2D : public Node2D {
-private:
- GDCLASS(Particles2D, Node2D);
-
-public:
- enum DrawOrder {
- DRAW_ORDER_INDEX,
- DRAW_ORDER_LIFETIME,
- };
-
-private:
- RID particles;
-
- bool one_shot;
- int amount;
- float lifetime;
- float pre_process_time;
- float explosiveness_ratio;
- float randomness_ratio;
- float speed_scale;
- Rect2 visibility_rect;
- bool local_coords;
- int fixed_fps;
- bool fractional_delta;
-
- Ref<Material> process_material;
-
- DrawOrder draw_order;
-
- Ref<Texture2D> texture;
- Ref<Texture2D> normal_map;
-
- void _update_particle_emission_transform();
-
-protected:
- static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const;
- void _notification(int p_what);
-
-public:
- void set_emitting(bool p_emitting);
- void set_amount(int p_amount);
- void set_lifetime(float p_lifetime);
- void set_one_shot(bool p_enable);
- void set_pre_process_time(float p_time);
- void set_explosiveness_ratio(float p_ratio);
- void set_randomness_ratio(float p_ratio);
- void set_visibility_rect(const Rect2 &p_visibility_rect);
- void set_use_local_coordinates(bool p_enable);
- void set_process_material(const Ref<Material> &p_material);
- void set_speed_scale(float 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;
- Rect2 get_visibility_rect() const;
- bool get_use_local_coordinates() const;
- Ref<Material> get_process_material() const;
- float get_speed_scale() const;
-
- void set_fixed_fps(int p_count);
- int get_fixed_fps() const;
-
- void set_fractional_delta(bool p_enable);
- bool get_fractional_delta() const;
-
- void set_draw_order(DrawOrder p_order);
- DrawOrder get_draw_order() const;
-
- void set_texture(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_texture() const;
-
- void set_normal_map(const Ref<Texture2D> &p_normal_map);
- Ref<Texture2D> get_normal_map() const;
-
- virtual String get_configuration_warning() const;
-
- void restart();
- Rect2 capture_rect() const;
- Particles2D();
- ~Particles2D();
-};
-
-VARIANT_ENUM_CAST(Particles2D::DrawOrder)
-
-#endif // PARTICLES_2D_H
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 3e807f12dc..ed8481db4a 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -242,7 +242,7 @@ void PathFollow2D::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
- path = NULL;
+ path = nullptr;
} break;
}
}
@@ -321,16 +321,14 @@ void PathFollow2D::set_offset(float p_offset) {
offset = p_offset;
if (path) {
- if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
+ if (path->get_curve().is_valid()) {
float path_length = path->get_curve()->get_baked_length();
if (loop) {
- while (offset > path_length)
- offset -= path_length;
-
- while (offset < 0)
- offset += path_length;
-
+ offset = Math::fposmod(offset, path_length);
+ if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) {
+ offset = path_length;
+ }
} else {
offset = CLAMP(offset, 0, path_length);
}
@@ -421,7 +419,7 @@ PathFollow2D::PathFollow2D() {
offset = 0;
h_offset = 0;
v_offset = 0;
- path = NULL;
+ path = nullptr;
rotate = true;
cubic = true;
loop = true;
diff --git a/scene/2d/path_texture.cpp b/scene/2d/path_texture.cpp
deleted file mode 100644
index 590f70a1b2..0000000000
--- a/scene/2d/path_texture.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*************************************************************************/
-/* path_texture.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "path_texture.h"
-
-void PathTexture::set_begin_texture(const Ref<Texture2D> &p_texture) {
-
- begin = p_texture;
- update();
-}
-
-Ref<Texture2D> PathTexture::get_begin_texture() const {
-
- return begin;
-}
-
-void PathTexture::set_repeat_texture(const Ref<Texture2D> &p_texture) {
-
- repeat = p_texture;
- update();
-}
-Ref<Texture2D> PathTexture::get_repeat_texture() const {
-
- return repeat;
-}
-
-void PathTexture::set_end_texture(const Ref<Texture2D> &p_texture) {
-
- end = p_texture;
- update();
-}
-Ref<Texture2D> PathTexture::get_end_texture() const {
-
- return end;
-}
-
-void PathTexture::set_subdivisions(int p_amount) {
-
- ERR_FAIL_INDEX(p_amount, 32);
- subdivs = p_amount;
- update();
-}
-
-int PathTexture::get_subdivisions() const {
-
- return subdivs;
-}
-
-void PathTexture::set_overlap(int p_amount) {
-
- overlap = p_amount;
- update();
-}
-int PathTexture::get_overlap() const {
-
- return overlap;
-}
-
-PathTexture::PathTexture() {
-
- overlap = 0;
- subdivs = 1;
-}
diff --git a/scene/2d/path_texture.h b/scene/2d/path_texture.h
deleted file mode 100644
index 014d0dc959..0000000000
--- a/scene/2d/path_texture.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*************************************************************************/
-/* path_texture.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PATH_TEXTURE_H
-#define PATH_TEXTURE_H
-
-#include "scene/2d/node_2d.h"
-
-class PathTexture : public Node2D {
- GDCLASS(PathTexture, Node2D);
-
- Ref<Texture2D> begin;
- Ref<Texture2D> repeat;
- Ref<Texture2D> end;
- int subdivs;
- bool overlap;
-
-public:
- void set_begin_texture(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_begin_texture() const;
-
- void set_repeat_texture(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_repeat_texture() const;
-
- void set_end_texture(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_end_texture() const;
-
- void set_subdivisions(int p_amount);
- int get_subdivisions() const;
-
- void set_overlap(int p_amount);
- int get_overlap() const;
-
- PathTexture();
-};
-
-#endif // PATH_TEXTURE_H
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 9bfeca7e56..21dc9537ec 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -82,7 +82,7 @@ void PhysicsBody2D::_bind_methods() {
void PhysicsBody2D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
- Physics2DServer::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
}
uint32_t PhysicsBody2D::get_collision_layer() const {
@@ -93,7 +93,7 @@ uint32_t PhysicsBody2D::get_collision_layer() const {
void PhysicsBody2D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
- Physics2DServer::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
}
uint32_t PhysicsBody2D::get_collision_mask() const {
@@ -130,10 +130,10 @@ bool PhysicsBody2D::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
-PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) :
- CollisionObject2D(Physics2DServer::get_singleton()->body_create(), false) {
+PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
+ CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) {
- Physics2DServer::get_singleton()->body_set_mode(get_rid(), p_mode);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), p_mode);
collision_layer = 1;
collision_mask = 1;
set_pickable(false);
@@ -141,11 +141,11 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) :
Array PhysicsBody2D::get_collision_exceptions() {
List<RID> exceptions;
- Physics2DServer::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
+ PhysicsServer2D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
Array ret;
for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
RID body = E->get();
- ObjectID instance_id = Physics2DServer::get_singleton()->body_get_object_instance_id(body);
+ ObjectID instance_id = PhysicsServer2D::get_singleton()->body_get_object_instance_id(body);
Object *obj = ObjectDB::get_instance(instance_id);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(obj);
ret.append(physics_body);
@@ -157,28 +157,28 @@ void PhysicsBody2D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node);
- ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody type.");
- Physics2DServer::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid());
+ ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type.");
+ PhysicsServer2D::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid());
}
void PhysicsBody2D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node);
- ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody type.");
- Physics2DServer::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid());
+ ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type.");
+ PhysicsServer2D::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid());
}
void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) {
constant_linear_velocity = p_vel;
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
}
void StaticBody2D::set_constant_angular_velocity(real_t p_vel) {
constant_angular_velocity = p_vel;
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
}
Vector2 StaticBody2D::get_constant_linear_velocity() const {
@@ -225,7 +225,7 @@ void StaticBody2D::_bind_methods() {
}
StaticBody2D::StaticBody2D() :
- PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) {
+ PhysicsBody2D(PhysicsServer2D::BODY_MODE_STATIC) {
constant_angular_velocity = 0;
}
@@ -235,11 +235,11 @@ StaticBody2D::~StaticBody2D() {
void StaticBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1);
} else {
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
@@ -360,20 +360,20 @@ struct _RigidBody2DInOut {
int local_shape;
};
-bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) {
+bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) {
- Physics2DServer::MotionResult *r = NULL;
+ PhysicsServer2D::MotionResult *r = nullptr;
if (p_result.is_valid())
r = p_result->get_result_ptr();
- return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r);
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r);
}
void RigidBody2D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
- state = Object::cast_to<Physics2DDirectBodyState>(p_state);
+ state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
#else
- state = (Physics2DDirectBodyState *)p_state; //trust it
+ state = (PhysicsDirectBodyState2D *)p_state; //trust it
#endif
set_block_transform_notify(true); // don't want notify (would feedback loop)
@@ -474,7 +474,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
contact_monitor->locked = false;
}
- state = NULL;
+ state = nullptr;
}
void RigidBody2D::set_mode(Mode p_mode) {
@@ -484,20 +484,20 @@ void RigidBody2D::set_mode(Mode p_mode) {
case MODE_RIGID: {
- Physics2DServer::get_singleton()->body_set_mode(get_rid(), Physics2DServer::BODY_MODE_RIGID);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_RIGID);
} break;
case MODE_STATIC: {
- Physics2DServer::get_singleton()->body_set_mode(get_rid(), Physics2DServer::BODY_MODE_STATIC);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC);
} break;
case MODE_KINEMATIC: {
- Physics2DServer::get_singleton()->body_set_mode(get_rid(), Physics2DServer::BODY_MODE_KINEMATIC);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC);
} break;
case MODE_CHARACTER: {
- Physics2DServer::get_singleton()->body_set_mode(get_rid(), Physics2DServer::BODY_MODE_CHARACTER);
+ PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_CHARACTER);
} break;
}
@@ -514,7 +514,7 @@ void RigidBody2D::set_mass(real_t p_mass) {
mass = p_mass;
_change_notify("mass");
_change_notify("weight");
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_MASS, mass);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_MASS, mass);
}
real_t RigidBody2D::get_mass() const {
@@ -524,12 +524,12 @@ real_t RigidBody2D::get_mass() const {
void RigidBody2D::set_inertia(real_t p_inertia) {
ERR_FAIL_COND(p_inertia < 0);
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_INERTIA, p_inertia);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, p_inertia);
}
real_t RigidBody2D::get_inertia() const {
- return Physics2DServer::get_singleton()->body_get_param(get_rid(), Physics2DServer::BODY_PARAM_INERTIA);
+ return PhysicsServer2D::get_singleton()->body_get_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA);
}
void RigidBody2D::set_weight(real_t p_weight) {
@@ -564,7 +564,7 @@ Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const {
void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) {
gravity_scale = p_gravity_scale;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
}
real_t RigidBody2D::get_gravity_scale() const {
@@ -575,7 +575,7 @@ void RigidBody2D::set_linear_damp(real_t p_linear_damp) {
ERR_FAIL_COND(p_linear_damp < -1);
linear_damp = p_linear_damp;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_LINEAR_DAMP, linear_damp);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP, linear_damp);
}
real_t RigidBody2D::get_linear_damp() const {
@@ -586,7 +586,7 @@ void RigidBody2D::set_angular_damp(real_t p_angular_damp) {
ERR_FAIL_COND(p_angular_damp < -1);
angular_damp = p_angular_damp;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_ANGULAR_DAMP, angular_damp);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
}
real_t RigidBody2D::get_angular_damp() const {
@@ -602,7 +602,7 @@ void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) {
if (state) {
set_linear_velocity(v);
} else {
- Physics2DServer::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
+ PhysicsServer2D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
linear_velocity = v;
}
}
@@ -614,7 +614,7 @@ void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) {
state->set_linear_velocity(linear_velocity);
else {
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
}
@@ -629,7 +629,7 @@ void RigidBody2D::set_angular_velocity(real_t p_velocity) {
if (state)
state->set_angular_velocity(angular_velocity);
else
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
real_t RigidBody2D::get_angular_velocity() const {
@@ -642,7 +642,7 @@ void RigidBody2D::set_use_custom_integrator(bool p_enable) {
return;
custom_integrator = p_enable;
- Physics2DServer::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
+ PhysicsServer2D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
}
bool RigidBody2D::is_using_custom_integrator() {
@@ -652,13 +652,13 @@ bool RigidBody2D::is_using_custom_integrator() {
void RigidBody2D::set_sleeping(bool p_sleeping) {
sleeping = p_sleeping;
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_SLEEPING, sleeping);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_SLEEPING, sleeping);
}
void RigidBody2D::set_can_sleep(bool p_active) {
can_sleep = p_active;
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_CAN_SLEEP, p_active);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_CAN_SLEEP, p_active);
}
bool RigidBody2D::is_able_to_sleep() const {
@@ -674,7 +674,7 @@ bool RigidBody2D::is_sleeping() const {
void RigidBody2D::set_max_contacts_reported(int p_amount) {
max_contacts_reported = p_amount;
- Physics2DServer::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
+ PhysicsServer2D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
int RigidBody2D::get_max_contacts_reported() const {
@@ -683,55 +683,55 @@ int RigidBody2D::get_max_contacts_reported() const {
}
void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) {
- Physics2DServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
+ PhysicsServer2D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
}
void RigidBody2D::apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) {
- Physics2DServer::get_singleton()->body_apply_impulse(get_rid(), p_offset, p_impulse);
+ PhysicsServer2D::get_singleton()->body_apply_impulse(get_rid(), p_offset, p_impulse);
}
void RigidBody2D::apply_torque_impulse(float p_torque) {
- Physics2DServer::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque);
+ PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque);
}
void RigidBody2D::set_applied_force(const Vector2 &p_force) {
- Physics2DServer::get_singleton()->body_set_applied_force(get_rid(), p_force);
+ PhysicsServer2D::get_singleton()->body_set_applied_force(get_rid(), p_force);
};
Vector2 RigidBody2D::get_applied_force() const {
- return Physics2DServer::get_singleton()->body_get_applied_force(get_rid());
+ return PhysicsServer2D::get_singleton()->body_get_applied_force(get_rid());
};
void RigidBody2D::set_applied_torque(const float p_torque) {
- Physics2DServer::get_singleton()->body_set_applied_torque(get_rid(), p_torque);
+ PhysicsServer2D::get_singleton()->body_set_applied_torque(get_rid(), p_torque);
};
float RigidBody2D::get_applied_torque() const {
- return Physics2DServer::get_singleton()->body_get_applied_torque(get_rid());
+ return PhysicsServer2D::get_singleton()->body_get_applied_torque(get_rid());
};
void RigidBody2D::add_central_force(const Vector2 &p_force) {
- Physics2DServer::get_singleton()->body_add_central_force(get_rid(), p_force);
+ PhysicsServer2D::get_singleton()->body_add_central_force(get_rid(), p_force);
}
void RigidBody2D::add_force(const Vector2 &p_offset, const Vector2 &p_force) {
- Physics2DServer::get_singleton()->body_add_force(get_rid(), p_offset, p_force);
+ PhysicsServer2D::get_singleton()->body_add_force(get_rid(), p_offset, p_force);
}
void RigidBody2D::add_torque(const float p_torque) {
- Physics2DServer::get_singleton()->body_add_torque(get_rid(), p_torque);
+ PhysicsServer2D::get_singleton()->body_add_torque(get_rid(), p_torque);
}
void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) {
ccd_mode = p_mode;
- Physics2DServer::get_singleton()->body_set_continuous_collision_detection_mode(get_rid(), Physics2DServer::CCDMode(p_mode));
+ PhysicsServer2D::get_singleton()->body_set_continuous_collision_detection_mode(get_rid(), PhysicsServer2D::CCDMode(p_mode));
}
RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() const {
@@ -780,7 +780,7 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
}
memdelete(contact_monitor);
- contact_monitor = NULL;
+ contact_monitor = nullptr;
} else {
contact_monitor = memnew(ContactMonitor);
@@ -790,7 +790,7 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
bool RigidBody2D::is_contact_monitor_enabled() const {
- return contact_monitor != NULL;
+ return contact_monitor != nullptr;
}
void RigidBody2D::_notification(int p_what) {
@@ -898,7 +898,7 @@ void RigidBody2D::_bind_methods() {
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, "Physics2DDirectBodyState")));
+ BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D")));
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
@@ -939,7 +939,7 @@ void RigidBody2D::_bind_methods() {
}
RigidBody2D::RigidBody2D() :
- PhysicsBody2D(Physics2DServer::BODY_MODE_RIGID) {
+ PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
mode = MODE_RIGID;
@@ -950,17 +950,17 @@ RigidBody2D::RigidBody2D() :
angular_damp = -1;
max_contacts_reported = 0;
- state = NULL;
+ state = nullptr;
angular_velocity = 0;
sleeping = false;
ccd_mode = CCD_MODE_DISABLED;
custom_integrator = false;
- contact_monitor = NULL;
+ contact_monitor = nullptr;
can_sleep = true;
- Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
}
RigidBody2D::~RigidBody2D() {
@@ -971,11 +971,11 @@ RigidBody2D::~RigidBody2D() {
void RigidBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1);
} else {
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
}
}
@@ -1001,12 +1001,12 @@ Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p
bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
- Physics2DServer::SeparationResult sep_res[8]; //max 8 rays
+ PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays
Transform2D gt = get_global_transform();
Vector2 recover;
- int hits = Physics2DServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
int deepest = -1;
float deepest_depth;
for (int i = 0; i < hits; i++) {
@@ -1042,8 +1042,8 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
ERR_PRINT("Functions move_and_slide and move_and_collide do not work together with 'sync to physics' option. Please read the documentation.");
}
Transform2D gt = get_global_transform();
- Physics2DServer::MotionResult result;
- bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes);
+ PhysicsServer2D::MotionResult result;
+ bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes);
if (colliding) {
r_collision.collider_metadata = result.collider_metadata;
@@ -1077,7 +1077,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
Vector2 current_floor_velocity = floor_velocity;
if (on_floor && on_floor_body.is_valid()) {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
- Physics2DDirectBodyState *bs = Physics2DServer::get_singleton()->body_get_direct_state(on_floor_body);
+ PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) {
current_floor_velocity = bs->get_linear_velocity();
}
@@ -1227,7 +1227,7 @@ bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_moti
ERR_FAIL_COND_V(!is_inside_tree(), false);
- return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin);
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin);
}
void KinematicBody2D::set_safe_margin(float p_margin) {
@@ -1277,11 +1277,11 @@ void KinematicBody2D::set_sync_to_physics(bool p_enable) {
return;
if (p_enable) {
- Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
@@ -1296,7 +1296,7 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) {
if (!sync_to_physics)
return;
- Physics2DDirectBodyState *state = Object::cast_to<Physics2DDirectBodyState>(p_state);
+ PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
last_valid_transform = state->get_transform();
set_notify_local_transform(false);
@@ -1320,7 +1320,7 @@ void KinematicBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
//used by sync to physics, send the new transform to the physics
Transform2D new_transform = get_global_transform();
- Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_TRANSFORM, new_transform);
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
//but then revert changes
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
@@ -1357,7 +1357,7 @@ void KinematicBody2D::_bind_methods() {
}
KinematicBody2D::KinematicBody2D() :
- PhysicsBody2D(Physics2DServer::BODY_MODE_KINEMATIC) {
+ PhysicsBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) {
margin = 0.08;
@@ -1368,12 +1368,12 @@ KinematicBody2D::KinematicBody2D() :
}
KinematicBody2D::~KinematicBody2D() {
if (motion_cache.is_valid()) {
- motion_cache->owner = NULL;
+ motion_cache->owner = nullptr;
}
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
- slide_colliders.write[i]->owner = NULL;
+ slide_colliders.write[i]->owner = nullptr;
}
}
}
@@ -1394,7 +1394,7 @@ Vector2 KinematicCollision2D::get_remainder() const {
return collision.remainder;
}
Object *KinematicCollision2D::get_local_shape() const {
- if (!owner) return NULL;
+ if (!owner) return nullptr;
uint32_t ownerid = owner->shape_find_owner(collision.local_shape);
return owner->shape_owner_get_owner(ownerid);
}
@@ -1405,7 +1405,7 @@ Object *KinematicCollision2D::get_collider() const {
return ObjectDB::get_instance(collision.collider);
}
- return NULL;
+ return nullptr;
}
ObjectID KinematicCollision2D::get_collider_id() const {
@@ -1422,7 +1422,7 @@ Object *KinematicCollision2D::get_collider_shape() const {
}
}
- return NULL;
+ return nullptr;
}
int KinematicCollision2D::get_collider_shape_index() const {
@@ -1468,5 +1468,5 @@ KinematicCollision2D::KinematicCollision2D() {
collision.collider_shape = 0;
collision.local_shape = 0;
- owner = NULL;
+ owner = nullptr;
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 20e9f3ffcf..0d92a820e3 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -34,7 +34,7 @@
#include "core/vset.h"
#include "scene/2d/collision_object_2d.h"
#include "scene/resources/physics_material.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
class KinematicCollision2D;
@@ -50,7 +50,7 @@ class PhysicsBody2D : public CollisionObject2D {
protected:
void _notification(int p_what);
- PhysicsBody2D(Physics2DServer::BodyMode p_mode);
+ PhysicsBody2D(PhysicsServer2D::BodyMode p_mode);
static void _bind_methods();
@@ -123,7 +123,7 @@ public:
private:
bool can_sleep;
- Physics2DDirectBodyState *state;
+ PhysicsDirectBodyState2D *state;
Mode mode;
real_t mass;
@@ -185,7 +185,7 @@ private:
void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape);
void _direct_state_changed(Object *p_state);
- bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>());
+ bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, float p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>());
protected:
void _notification(int p_what);
@@ -300,10 +300,10 @@ private:
bool sync_to_physics;
Vector<Collision> colliders;
- Vector<Ref<KinematicCollision2D> > slide_colliders;
+ Vector<Ref<KinematicCollision2D>> slide_colliders;
Ref<KinematicCollision2D> motion_cache;
- _FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const;
+ _FORCE_INLINE_ bool _ignores_mode(PhysicsServer2D::BodyMode) const;
Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 95656b9610..84c1828b47 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -103,7 +103,7 @@ void Polygon2D::_notification(int p_what) {
if (polygon.size() < 3)
return;
- Skeleton2D *skeleton_node = NULL;
+ Skeleton2D *skeleton_node = nullptr;
if (has_node(skeleton)) {
skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton));
}
@@ -111,10 +111,10 @@ void Polygon2D::_notification(int p_what) {
ObjectID new_skeleton_id;
if (skeleton_node) {
- VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton());
+ RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton());
new_skeleton_id = skeleton_node->get_instance_id();
} else {
- VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID());
+ RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID());
}
if (new_skeleton_id != current_skeleton_id) {
@@ -307,7 +307,7 @@ void Polygon2D::_notification(int p_what) {
if (invert || polygons.size() == 0) {
Vector<int> indices = Geometry::triangulate_polygon(points);
if (indices.size()) {
- VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1, normal_map.is_valid() ? normal_map->get_rid() : RID(), specular_map.is_valid() ? specular_map->get_rid() : RID(), Color(specular_color.r, specular_color.g, specular_color.b, shininess));
+ RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1, normal_map.is_valid() ? normal_map->get_rid() : RID(), specular_map.is_valid() ? specular_map->get_rid() : RID(), Color(specular_color.r, specular_color.g, specular_color.b, shininess));
}
} else {
//draw individual polygons
@@ -341,7 +341,7 @@ void Polygon2D::_notification(int p_what) {
}
if (total_indices.size()) {
- VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), total_indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
+ RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), total_indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
}
}
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index fd6e0aebcc..9d6c7304ce 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -33,7 +33,7 @@
#include "collision_object_2d.h"
#include "core/engine.h"
#include "physics_body_2d.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
void RayCast2D::set_cast_to(const Vector2 &p_point) {
@@ -79,7 +79,7 @@ bool RayCast2D::is_colliding() const {
Object *RayCast2D::get_collider() const {
if (against.is_null())
- return NULL;
+ return nullptr;
return ObjectDB::get_instance(against);
}
@@ -205,7 +205,7 @@ void RayCast2D::_update_raycast_state() {
Ref<World2D> w2d = get_world_2d();
ERR_FAIL_COND(w2d.is_null());
- Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(w2d->get_space());
+ PhysicsDirectSpaceState2D *dss = PhysicsServer2D::get_singleton()->space_get_direct_state(w2d->get_space());
ERR_FAIL_COND(!dss);
Transform2D gt = get_global_transform();
@@ -214,7 +214,7 @@ void RayCast2D::_update_raycast_state() {
if (to == Vector2())
to = Vector2(0, 0.01);
- Physics2DDirectSpaceState::RayResult rr;
+ PhysicsDirectSpaceState2D::RayResult rr;
if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 9ebaf23c3a..86c9ff6076 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -35,7 +35,7 @@ void Bone2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
Node *parent = get_parent();
parent_bone = Object::cast_to<Bone2D>(parent);
- skeleton = NULL;
+ skeleton = nullptr;
while (parent) {
skeleton = Object::cast_to<Skeleton2D>(parent);
if (skeleton)
@@ -73,9 +73,9 @@ void Bone2D::_notification(int p_what) {
}
}
skeleton->_make_bone_setup_dirty();
- skeleton = NULL;
+ skeleton = nullptr;
}
- parent_bone = NULL;
+ parent_bone = nullptr;
}
}
void Bone2D::_bind_methods() {
@@ -157,8 +157,8 @@ String Bone2D::get_configuration_warning() const {
}
Bone2D::Bone2D() {
- skeleton = NULL;
- parent_bone = NULL;
+ skeleton = nullptr;
+ parent_bone = nullptr;
skeleton_index = -1;
default_length = 16;
set_notify_local_transform(true);
@@ -186,7 +186,7 @@ void Skeleton2D::_update_bone_setup() {
return;
bone_setup_dirty = false;
- VS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true);
+ RS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true);
bones.sort(); //sorty so they are always in the same order/index
@@ -240,7 +240,7 @@ void Skeleton2D::_update_transform() {
for (int i = 0; i < bones.size(); i++) {
Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse;
- VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform);
+ RS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform);
}
}
@@ -257,8 +257,8 @@ int Skeleton2D::get_bone_count() const {
Bone2D *Skeleton2D::get_bone(int p_idx) {
- ERR_FAIL_COND_V(!is_inside_tree(), NULL);
- ERR_FAIL_INDEX_V(p_idx, bones.size(), NULL);
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
+ ERR_FAIL_INDEX_V(p_idx, bones.size(), nullptr);
return bones[p_idx].bone;
}
@@ -276,7 +276,7 @@ void Skeleton2D::_notification(int p_what) {
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
+ RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
}
}
@@ -300,11 +300,11 @@ Skeleton2D::Skeleton2D() {
bone_setup_dirty = true;
transform_dirty = true;
- skeleton = VS::get_singleton()->skeleton_create();
+ skeleton = RS::get_singleton()->skeleton_create();
set_notify_transform(true);
}
Skeleton2D::~Skeleton2D() {
- VS::get_singleton()->free(skeleton);
+ RS::get_singleton()->free(skeleton);
}
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
deleted file mode 100644
index 7eaafe5348..0000000000
--- a/scene/2d/sprite.cpp
+++ /dev/null
@@ -1,539 +0,0 @@
-/*************************************************************************/
-/* sprite.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.h"
-
-#include "core/core_string_names.h"
-#include "core/os/os.h"
-#include "scene/main/viewport.h"
-#include "scene/scene_string_names.h"
-
-#ifdef TOOLS_ENABLED
-Dictionary Sprite::_edit_get_state() const {
- Dictionary state = Node2D::_edit_get_state();
- state["offset"] = offset;
- return state;
-}
-
-void Sprite::_edit_set_state(const Dictionary &p_state) {
- Node2D::_edit_set_state(p_state);
- set_offset(p_state["offset"]);
-}
-
-void Sprite::_edit_set_pivot(const Point2 &p_pivot) {
- set_offset(get_offset() - p_pivot);
- set_position(get_transform().xform(p_pivot));
-}
-
-Point2 Sprite::_edit_get_pivot() const {
- return Vector2();
-}
-
-bool Sprite::_edit_use_pivot() const {
- return true;
-}
-
-bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
-
- return is_pixel_opaque(p_point);
-}
-
-Rect2 Sprite::_edit_get_rect() const {
- return get_rect();
-}
-
-bool Sprite::_edit_use_rect() const {
- return texture.is_valid();
-}
-#endif
-
-Rect2 Sprite::get_anchorable_rect() const {
- return get_rect();
-}
-
-void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
-
- Rect2 base_rect;
-
- if (region) {
- r_filter_clip = region_filter_clip;
- base_rect = region_rect;
- } else {
- r_filter_clip = false;
- base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
- }
-
- Size2 frame_size = base_rect.size / Size2(hframes, vframes);
- Point2 frame_offset = Point2(frame % hframes, frame / hframes);
- frame_offset *= frame_size;
-
- r_src_rect.size = frame_size;
- r_src_rect.position = base_rect.position + frame_offset;
-
- Point2 dest_offset = offset;
- if (centered)
- dest_offset -= frame_size / 2;
- if (Engine::get_singleton()->get_use_pixel_snap()) {
- dest_offset = dest_offset.floor();
- }
-
- r_dst_rect = Rect2(dest_offset, frame_size);
-
- if (hflip)
- r_dst_rect.size.x = -r_dst_rect.size.x;
- if (vflip)
- r_dst_rect.size.y = -r_dst_rect.size.y;
-}
-
-void Sprite::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_DRAW: {
-
- if (texture.is_null())
- return;
-
- RID ci = get_canvas_item();
-
- /*
- texture->draw(ci,Point2());
- break;
- */
-
- Rect2 src_rect, dst_rect;
- bool filter_clip;
- _get_rects(src_rect, dst_rect, filter_clip);
- texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip);
-
- } break;
- }
-}
-
-void Sprite::set_texture(const Ref<Texture2D> &p_texture) {
-
- if (p_texture == texture)
- return;
-
- if (texture.is_valid())
- texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite::_texture_changed));
-
- texture = p_texture;
-
- if (texture.is_valid())
- texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite::_texture_changed));
-
- update();
- emit_signal("texture_changed");
- item_rect_changed();
- _change_notify("texture");
-}
-
-void Sprite::set_normal_map(const Ref<Texture2D> &p_texture) {
-
- normal_map = p_texture;
- update();
-}
-
-Ref<Texture2D> Sprite::get_normal_map() const {
-
- return normal_map;
-}
-
-void Sprite::set_specular_map(const Ref<Texture2D> &p_texture) {
-
- specular = p_texture;
- update();
-}
-
-Ref<Texture2D> Sprite::get_specular_map() const {
-
- return specular;
-}
-
-void Sprite::set_specular_color(const Color &p_color) {
- specular_color = p_color;
- update();
-}
-
-Color Sprite::get_specular_color() const {
- return specular_color;
-}
-
-void Sprite::set_shininess(float p_shininess) {
- shininess = CLAMP(p_shininess, 0.0, 1.0);
- update();
-}
-
-float Sprite::get_shininess() const {
- return shininess;
-}
-
-Ref<Texture2D> Sprite::get_texture() const {
-
- return texture;
-}
-
-void Sprite::set_centered(bool p_center) {
-
- centered = p_center;
- update();
- item_rect_changed();
-}
-
-bool Sprite::is_centered() const {
-
- return centered;
-}
-
-void Sprite::set_offset(const Point2 &p_offset) {
-
- offset = p_offset;
- update();
- item_rect_changed();
- _change_notify("offset");
-}
-Point2 Sprite::get_offset() const {
-
- return offset;
-}
-
-void Sprite::set_flip_h(bool p_flip) {
-
- hflip = p_flip;
- update();
-}
-bool Sprite::is_flipped_h() const {
-
- return hflip;
-}
-
-void Sprite::set_flip_v(bool p_flip) {
-
- vflip = p_flip;
- update();
-}
-bool Sprite::is_flipped_v() const {
-
- return vflip;
-}
-
-void Sprite::set_region(bool p_region) {
-
- if (p_region == region)
- return;
-
- region = p_region;
- update();
-}
-
-bool Sprite::is_region() const {
-
- return region;
-}
-
-void Sprite::set_region_rect(const Rect2 &p_region_rect) {
-
- if (region_rect == p_region_rect)
- return;
-
- region_rect = p_region_rect;
-
- if (region)
- item_rect_changed();
-
- _change_notify("region_rect");
-}
-
-Rect2 Sprite::get_region_rect() const {
-
- return region_rect;
-}
-
-void Sprite::set_region_filter_clip(bool p_enable) {
- region_filter_clip = p_enable;
- update();
-}
-
-bool Sprite::is_region_filter_clip_enabled() const {
- return region_filter_clip;
-}
-
-void Sprite::set_frame(int p_frame) {
-
- ERR_FAIL_INDEX(p_frame, vframes * hframes);
-
- if (frame != p_frame)
- item_rect_changed();
-
- frame = p_frame;
-
- _change_notify("frame");
- _change_notify("frame_coords");
- emit_signal(SceneStringNames::get_singleton()->frame_changed);
-}
-
-int Sprite::get_frame() const {
-
- return frame;
-}
-
-void Sprite::set_frame_coords(const Vector2 &p_coord) {
- ERR_FAIL_INDEX(int(p_coord.x), hframes);
- ERR_FAIL_INDEX(int(p_coord.y), vframes);
-
- set_frame(int(p_coord.y) * hframes + int(p_coord.x));
-}
-
-Vector2 Sprite::get_frame_coords() const {
- return Vector2(frame % hframes, frame / hframes);
-}
-
-void Sprite::set_vframes(int p_amount) {
-
- ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1.");
- vframes = p_amount;
- update();
- item_rect_changed();
- _change_notify();
-}
-int Sprite::get_vframes() const {
-
- return vframes;
-}
-
-void Sprite::set_hframes(int p_amount) {
-
- ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1.");
- hframes = p_amount;
- update();
- item_rect_changed();
- _change_notify();
-}
-int Sprite::get_hframes() const {
-
- return hframes;
-}
-
-bool Sprite::is_pixel_opaque(const Point2 &p_point) const {
-
- if (texture.is_null())
- return false;
-
- if (texture->get_size().width == 0 || texture->get_size().height == 0)
- return false;
-
- Rect2 src_rect, dst_rect;
- bool filter_clip;
- _get_rects(src_rect, dst_rect, filter_clip);
- dst_rect.size = dst_rect.size.abs();
-
- if (!dst_rect.has_point(p_point))
- return false;
-
- Vector2 q = (p_point - dst_rect.position) / dst_rect.size;
- if (hflip)
- q.x = 1.0f - q.x;
- if (vflip)
- q.y = 1.0f - q.y;
- q = q * src_rect.size + src_rect.position;
-#ifndef _MSC_VER
-#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that)
-#endif
- bool is_repeat = false;
- bool is_mirrored_repeat = false;
- if (is_repeat) {
- int mirror_x = 0;
- int mirror_y = 0;
- if (is_mirrored_repeat) {
- mirror_x = (int)(q.x / texture->get_size().width);
- mirror_y = (int)(q.y / texture->get_size().height);
- }
- q.x = Math::fmod(q.x, texture->get_size().width);
- q.y = Math::fmod(q.y, texture->get_size().height);
- if (mirror_x % 2 == 1) {
- q.x = texture->get_size().width - q.x - 1;
- }
- if (mirror_y % 2 == 1) {
- q.y = texture->get_size().height - q.y - 1;
- }
- } else {
- q.x = MIN(q.x, texture->get_size().width - 1);
- q.y = MIN(q.y, texture->get_size().height - 1);
- }
-
- return texture->is_pixel_opaque((int)q.x, (int)q.y);
-}
-
-Rect2 Sprite::get_rect() const {
-
- if (texture.is_null())
- return Rect2(0, 0, 1, 1);
-
- Size2i s;
-
- if (region) {
- s = region_rect.size;
- } else {
- s = texture->get_size();
- }
-
- s = s / Point2(hframes, vframes);
-
- Point2 ofs = offset;
- if (centered)
- ofs -= Size2(s) / 2;
-
- if (s == Size2(0, 0))
- s = Size2(1, 1);
-
- return Rect2(ofs, s);
-}
-
-void Sprite::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
- property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
- }
-
- if (property.name == "frame_coords") {
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
- }
-}
-
-void Sprite::_texture_changed() {
-
- // Changes to the texture need to trigger an update to make
- // the editor redraw the sprite with the updated texture.
- if (texture.is_valid()) {
- update();
- }
-}
-
-void Sprite::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite::set_texture);
- ClassDB::bind_method(D_METHOD("get_texture"), &Sprite::get_texture);
-
- ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Sprite::set_normal_map);
- ClassDB::bind_method(D_METHOD("get_normal_map"), &Sprite::get_normal_map);
-
- ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Sprite::set_specular_map);
- ClassDB::bind_method(D_METHOD("get_specular_map"), &Sprite::get_specular_map);
-
- ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Sprite::set_specular_color);
- ClassDB::bind_method(D_METHOD("get_specular_color"), &Sprite::get_specular_color);
-
- ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Sprite::set_shininess);
- ClassDB::bind_method(D_METHOD("get_shininess"), &Sprite::get_shininess);
-
- ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite::set_centered);
- ClassDB::bind_method(D_METHOD("is_centered"), &Sprite::is_centered);
-
- ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Sprite::set_offset);
- ClassDB::bind_method(D_METHOD("get_offset"), &Sprite::get_offset);
-
- ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &Sprite::set_flip_h);
- ClassDB::bind_method(D_METHOD("is_flipped_h"), &Sprite::is_flipped_h);
-
- ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &Sprite::set_flip_v);
- ClassDB::bind_method(D_METHOD("is_flipped_v"), &Sprite::is_flipped_v);
-
- ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite::set_region);
- ClassDB::bind_method(D_METHOD("is_region"), &Sprite::is_region);
-
- ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite::is_pixel_opaque);
-
- ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect);
- ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect);
-
- ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite::set_region_filter_clip);
- ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite::is_region_filter_clip_enabled);
-
- ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite::set_frame);
- ClassDB::bind_method(D_METHOD("get_frame"), &Sprite::get_frame);
-
- ClassDB::bind_method(D_METHOD("set_frame_coords", "coords"), &Sprite::set_frame_coords);
- ClassDB::bind_method(D_METHOD("get_frame_coords"), &Sprite::get_frame_coords);
-
- ClassDB::bind_method(D_METHOD("set_vframes", "vframes"), &Sprite::set_vframes);
- ClassDB::bind_method(D_METHOD("get_vframes"), &Sprite::get_vframes);
-
- ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite::set_hframes);
- ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite::get_hframes);
-
- ClassDB::bind_method(D_METHOD("get_rect"), &Sprite::get_rect);
-
- ADD_SIGNAL(MethodInfo("frame_changed"));
- ADD_SIGNAL(MethodInfo("texture_changed"));
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_GROUP("Lighting", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
- ADD_GROUP("Offset", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
- ADD_GROUP("Animation", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
- 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::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");
-}
-
-Sprite::Sprite() {
-
- centered = true;
- hflip = false;
- vflip = false;
- region = false;
- region_filter_clip = false;
- shininess = 1.0;
- specular_color = Color(1, 1, 1, 1);
-
- frame = 0;
-
- vframes = 1;
- hframes = 1;
-}
-
-Sprite::~Sprite() {
-}
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
deleted file mode 100644
index a96f023231..0000000000
--- a/scene/2d/sprite.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*************************************************************************/
-/* sprite.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPRITE_H
-#define SPRITE_H
-
-#include "scene/2d/node_2d.h"
-#include "scene/resources/texture.h"
-
-class Sprite : public Node2D {
-
- GDCLASS(Sprite, Node2D);
-
- Ref<Texture2D> texture;
- Ref<Texture2D> normal_map;
- Ref<Texture2D> specular;
- Color specular_color;
- float shininess;
-
- bool centered;
- Point2 offset;
-
- bool hflip;
- bool vflip;
- bool region;
- Rect2 region_rect;
- bool region_filter_clip;
-
- int frame;
-
- int vframes;
- int hframes;
-
- void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
-
- void _texture_changed();
-
-protected:
- void _notification(int p_what);
-
- static void _bind_methods();
-
- virtual void _validate_property(PropertyInfo &property) const;
-
-public:
-#ifdef TOOLS_ENABLED
- virtual Dictionary _edit_get_state() const;
- virtual void _edit_set_state(const Dictionary &p_state);
-
- virtual void _edit_set_pivot(const Point2 &p_pivot);
- virtual Point2 _edit_get_pivot() const;
- virtual bool _edit_use_pivot() const;
- virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-
- virtual Rect2 _edit_get_rect() const;
- virtual bool _edit_use_rect() const;
-#endif
-
- bool is_pixel_opaque(const Point2 &p_point) const;
-
- void set_texture(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_texture() const;
-
- void set_normal_map(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_normal_map() const;
-
- void set_specular_map(const Ref<Texture2D> &p_texture);
- Ref<Texture2D> get_specular_map() const;
-
- void set_specular_color(const Color &p_color);
- Color get_specular_color() const;
-
- void set_shininess(float p_shininess);
- float get_shininess() const;
-
- void set_centered(bool p_center);
- bool is_centered() const;
-
- void set_offset(const Point2 &p_offset);
- Point2 get_offset() const;
-
- void set_flip_h(bool p_flip);
- bool is_flipped_h() const;
-
- 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_filter_clip(bool p_enable);
- bool is_region_filter_clip_enabled() const;
-
- void set_region_rect(const Rect2 &p_region_rect);
- Rect2 get_region_rect() const;
-
- void set_frame(int p_frame);
- int get_frame() const;
-
- void set_frame_coords(const Vector2 &p_coord);
- Vector2 get_frame_coords() const;
-
- void set_vframes(int p_amount);
- int get_vframes() const;
-
- void set_hframes(int p_amount);
- int get_hframes() const;
-
- Rect2 get_rect() const;
- virtual Rect2 get_anchorable_rect() const;
-
- Sprite();
- ~Sprite();
-};
-
-#endif // SPRITE_H
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
new file mode 100644
index 0000000000..df8859bd9a
--- /dev/null
+++ b/scene/2d/sprite_2d.cpp
@@ -0,0 +1,539 @@
+/*************************************************************************/
+/* sprite_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_2d.h"
+
+#include "core/core_string_names.h"
+#include "core/os/os.h"
+#include "scene/main/window.h"
+#include "scene/scene_string_names.h"
+
+#ifdef TOOLS_ENABLED
+Dictionary Sprite2D::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["offset"] = offset;
+ return state;
+}
+
+void Sprite2D::_edit_set_state(const Dictionary &p_state) {
+ Node2D::_edit_set_state(p_state);
+ set_offset(p_state["offset"]);
+}
+
+void Sprite2D::_edit_set_pivot(const Point2 &p_pivot) {
+ set_offset(get_offset() - p_pivot);
+ set_position(get_transform().xform(p_pivot));
+}
+
+Point2 Sprite2D::_edit_get_pivot() const {
+ return Vector2();
+}
+
+bool Sprite2D::_edit_use_pivot() const {
+ return true;
+}
+
+bool Sprite2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return is_pixel_opaque(p_point);
+}
+
+Rect2 Sprite2D::_edit_get_rect() const {
+ return get_rect();
+}
+
+bool Sprite2D::_edit_use_rect() const {
+ return texture.is_valid();
+}
+#endif
+
+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 {
+
+ Rect2 base_rect;
+
+ if (region) {
+ r_filter_clip = region_filter_clip;
+ base_rect = region_rect;
+ } else {
+ r_filter_clip = false;
+ base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
+ }
+
+ Size2 frame_size = base_rect.size / Size2(hframes, vframes);
+ Point2 frame_offset = Point2(frame % hframes, frame / hframes);
+ frame_offset *= frame_size;
+
+ r_src_rect.size = frame_size;
+ r_src_rect.position = base_rect.position + frame_offset;
+
+ Point2 dest_offset = offset;
+ if (centered)
+ dest_offset -= frame_size / 2;
+ if (Engine::get_singleton()->get_use_pixel_snap()) {
+ dest_offset = dest_offset.floor();
+ }
+
+ r_dst_rect = Rect2(dest_offset, frame_size);
+
+ if (hflip)
+ r_dst_rect.size.x = -r_dst_rect.size.x;
+ if (vflip)
+ r_dst_rect.size.y = -r_dst_rect.size.y;
+}
+
+void Sprite2D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_DRAW: {
+
+ if (texture.is_null())
+ return;
+
+ RID ci = get_canvas_item();
+
+ /*
+ texture->draw(ci,Point2());
+ break;
+ */
+
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
+ texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess), RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip);
+
+ } break;
+ }
+}
+
+void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) {
+
+ if (p_texture == texture)
+ return;
+
+ if (texture.is_valid())
+ texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed));
+
+ texture = p_texture;
+
+ if (texture.is_valid())
+ texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed));
+
+ update();
+ emit_signal("texture_changed");
+ item_rect_changed();
+ _change_notify("texture");
+}
+
+void Sprite2D::set_normal_map(const Ref<Texture2D> &p_texture) {
+
+ normal_map = p_texture;
+ update();
+}
+
+Ref<Texture2D> Sprite2D::get_normal_map() const {
+
+ return normal_map;
+}
+
+void Sprite2D::set_specular_map(const Ref<Texture2D> &p_texture) {
+
+ specular = p_texture;
+ update();
+}
+
+Ref<Texture2D> Sprite2D::get_specular_map() const {
+
+ return specular;
+}
+
+void Sprite2D::set_specular_color(const Color &p_color) {
+ specular_color = p_color;
+ update();
+}
+
+Color Sprite2D::get_specular_color() const {
+ return specular_color;
+}
+
+void Sprite2D::set_shininess(float p_shininess) {
+ shininess = CLAMP(p_shininess, 0.0, 1.0);
+ update();
+}
+
+float Sprite2D::get_shininess() const {
+ return shininess;
+}
+
+Ref<Texture2D> Sprite2D::get_texture() const {
+
+ return texture;
+}
+
+void Sprite2D::set_centered(bool p_center) {
+
+ centered = p_center;
+ update();
+ item_rect_changed();
+}
+
+bool Sprite2D::is_centered() const {
+
+ return centered;
+}
+
+void Sprite2D::set_offset(const Point2 &p_offset) {
+
+ offset = p_offset;
+ update();
+ item_rect_changed();
+ _change_notify("offset");
+}
+Point2 Sprite2D::get_offset() const {
+
+ return offset;
+}
+
+void Sprite2D::set_flip_h(bool p_flip) {
+
+ hflip = p_flip;
+ update();
+}
+bool Sprite2D::is_flipped_h() const {
+
+ return hflip;
+}
+
+void Sprite2D::set_flip_v(bool p_flip) {
+
+ vflip = p_flip;
+ update();
+}
+bool Sprite2D::is_flipped_v() const {
+
+ return vflip;
+}
+
+void Sprite2D::set_region(bool p_region) {
+
+ if (p_region == region)
+ return;
+
+ region = p_region;
+ update();
+}
+
+bool Sprite2D::is_region() const {
+
+ return region;
+}
+
+void Sprite2D::set_region_rect(const Rect2 &p_region_rect) {
+
+ if (region_rect == p_region_rect)
+ return;
+
+ region_rect = p_region_rect;
+
+ if (region)
+ 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;
+ update();
+}
+
+bool Sprite2D::is_region_filter_clip_enabled() const {
+ return region_filter_clip;
+}
+
+void Sprite2D::set_frame(int p_frame) {
+
+ ERR_FAIL_INDEX(p_frame, vframes * hframes);
+
+ if (frame != p_frame)
+ item_rect_changed();
+
+ frame = p_frame;
+
+ _change_notify("frame");
+ _change_notify("frame_coords");
+ emit_signal(SceneStringNames::get_singleton()->frame_changed);
+}
+
+int Sprite2D::get_frame() const {
+
+ return frame;
+}
+
+void Sprite2D::set_frame_coords(const Vector2 &p_coord) {
+ ERR_FAIL_INDEX(int(p_coord.x), hframes);
+ ERR_FAIL_INDEX(int(p_coord.y), vframes);
+
+ set_frame(int(p_coord.y) * hframes + int(p_coord.x));
+}
+
+Vector2 Sprite2D::get_frame_coords() const {
+ return Vector2(frame % hframes, frame / hframes);
+}
+
+void Sprite2D::set_vframes(int p_amount) {
+
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1.");
+ vframes = p_amount;
+ update();
+ item_rect_changed();
+ _change_notify();
+}
+int Sprite2D::get_vframes() const {
+
+ return vframes;
+}
+
+void Sprite2D::set_hframes(int p_amount) {
+
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1.");
+ hframes = p_amount;
+ update();
+ item_rect_changed();
+ _change_notify();
+}
+int Sprite2D::get_hframes() const {
+
+ return hframes;
+}
+
+bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const {
+
+ if (texture.is_null())
+ return false;
+
+ if (texture->get_size().width == 0 || texture->get_size().height == 0)
+ return false;
+
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
+ dst_rect.size = dst_rect.size.abs();
+
+ if (!dst_rect.has_point(p_point))
+ return false;
+
+ Vector2 q = (p_point - dst_rect.position) / dst_rect.size;
+ if (hflip)
+ q.x = 1.0f - q.x;
+ if (vflip)
+ q.y = 1.0f - q.y;
+ q = q * src_rect.size + src_rect.position;
+#ifndef _MSC_VER
+#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that)
+#endif
+ bool is_repeat = false;
+ bool is_mirrored_repeat = false;
+ if (is_repeat) {
+ int mirror_x = 0;
+ int mirror_y = 0;
+ if (is_mirrored_repeat) {
+ mirror_x = (int)(q.x / texture->get_size().width);
+ mirror_y = (int)(q.y / texture->get_size().height);
+ }
+ q.x = Math::fmod(q.x, texture->get_size().width);
+ q.y = Math::fmod(q.y, texture->get_size().height);
+ if (mirror_x % 2 == 1) {
+ q.x = texture->get_size().width - q.x - 1;
+ }
+ if (mirror_y % 2 == 1) {
+ q.y = texture->get_size().height - q.y - 1;
+ }
+ } else {
+ q.x = MIN(q.x, texture->get_size().width - 1);
+ q.y = MIN(q.y, texture->get_size().height - 1);
+ }
+
+ return texture->is_pixel_opaque((int)q.x, (int)q.y);
+}
+
+Rect2 Sprite2D::get_rect() const {
+
+ if (texture.is_null())
+ return Rect2(0, 0, 1, 1);
+
+ Size2i s;
+
+ if (region) {
+ s = region_rect.size;
+ } else {
+ s = texture->get_size();
+ }
+
+ s = s / Point2(hframes, vframes);
+
+ Point2 ofs = offset;
+ if (centered)
+ ofs -= Size2(s) / 2;
+
+ if (s == Size2(0, 0))
+ s = Size2(1, 1);
+
+ return Rect2(ofs, s);
+}
+
+void Sprite2D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "frame") {
+ property.hint = PROPERTY_HINT_RANGE;
+ property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
+
+ if (property.name == "frame_coords") {
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
+}
+
+void Sprite2D::_texture_changed() {
+
+ // Changes to the texture need to trigger an update to make
+ // the editor redraw the sprite with the updated texture.
+ if (texture.is_valid()) {
+ update();
+ }
+}
+
+void Sprite2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &Sprite2D::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Sprite2D::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map"), &Sprite2D::get_normal_map);
+
+ ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Sprite2D::set_specular_map);
+ ClassDB::bind_method(D_METHOD("get_specular_map"), &Sprite2D::get_specular_map);
+
+ ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Sprite2D::set_specular_color);
+ ClassDB::bind_method(D_METHOD("get_specular_color"), &Sprite2D::get_specular_color);
+
+ ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Sprite2D::set_shininess);
+ ClassDB::bind_method(D_METHOD("get_shininess"), &Sprite2D::get_shininess);
+
+ ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite2D::set_centered);
+ ClassDB::bind_method(D_METHOD("is_centered"), &Sprite2D::is_centered);
+
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Sprite2D::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &Sprite2D::get_offset);
+
+ ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &Sprite2D::set_flip_h);
+ ClassDB::bind_method(D_METHOD("is_flipped_h"), &Sprite2D::is_flipped_h);
+
+ 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("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("is_region_filter_clip_enabled"), &Sprite2D::is_region_filter_clip_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite2D::set_frame);
+ ClassDB::bind_method(D_METHOD("get_frame"), &Sprite2D::get_frame);
+
+ ClassDB::bind_method(D_METHOD("set_frame_coords", "coords"), &Sprite2D::set_frame_coords);
+ ClassDB::bind_method(D_METHOD("get_frame_coords"), &Sprite2D::get_frame_coords);
+
+ ClassDB::bind_method(D_METHOD("set_vframes", "vframes"), &Sprite2D::set_vframes);
+ ClassDB::bind_method(D_METHOD("get_vframes"), &Sprite2D::get_vframes);
+
+ ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite2D::set_hframes);
+ ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite2D::get_hframes);
+
+ ClassDB::bind_method(D_METHOD("get_rect"), &Sprite2D::get_rect);
+
+ ADD_SIGNAL(MethodInfo("frame_changed"));
+ ADD_SIGNAL(MethodInfo("texture_changed"));
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
+ ADD_GROUP("Lighting", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess");
+ ADD_GROUP("Offset", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
+ ADD_GROUP("Animation", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
+ 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::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");
+}
+
+Sprite2D::Sprite2D() {
+
+ centered = true;
+ hflip = false;
+ vflip = false;
+ region = false;
+ region_filter_clip = false;
+ shininess = 1.0;
+ specular_color = Color(1, 1, 1, 1);
+
+ frame = 0;
+
+ vframes = 1;
+ hframes = 1;
+}
+
+Sprite2D::~Sprite2D() {
+}
diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h
new file mode 100644
index 0000000000..599a9e937e
--- /dev/null
+++ b/scene/2d/sprite_2d.h
@@ -0,0 +1,143 @@
+/*************************************************************************/
+/* sprite_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPRITE_2D_H
+#define SPRITE_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/texture.h"
+
+class Sprite2D : public Node2D {
+
+ GDCLASS(Sprite2D, Node2D);
+
+ Ref<Texture2D> texture;
+ Ref<Texture2D> normal_map;
+ Ref<Texture2D> specular;
+ Color specular_color;
+ float shininess;
+
+ bool centered;
+ Point2 offset;
+
+ bool hflip;
+ bool vflip;
+ bool region;
+ Rect2 region_rect;
+ bool region_filter_clip;
+
+ int frame;
+
+ int vframes;
+ int hframes;
+
+ void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+
+ void _texture_changed();
+
+protected:
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+#ifdef TOOLS_ENABLED
+ virtual Dictionary _edit_get_state() const;
+ virtual void _edit_set_state(const Dictionary &p_state);
+
+ virtual void _edit_set_pivot(const Point2 &p_pivot);
+ virtual Point2 _edit_get_pivot() const;
+ virtual bool _edit_use_pivot() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
+#endif
+
+ bool is_pixel_opaque(const Point2 &p_point) const;
+
+ void set_texture(const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_texture() const;
+
+ void set_normal_map(const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_normal_map() const;
+
+ void set_specular_map(const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_specular_map() const;
+
+ void set_specular_color(const Color &p_color);
+ Color get_specular_color() const;
+
+ void set_shininess(float p_shininess);
+ float get_shininess() const;
+
+ void set_centered(bool p_center);
+ bool is_centered() const;
+
+ void set_offset(const Point2 &p_offset);
+ Point2 get_offset() const;
+
+ void set_flip_h(bool p_flip);
+ bool is_flipped_h() const;
+
+ 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_filter_clip(bool p_enable);
+ bool is_region_filter_clip_enabled() const;
+
+ void set_region_rect(const Rect2 &p_region_rect);
+ Rect2 get_region_rect() const;
+
+ void set_frame(int p_frame);
+ int get_frame() const;
+
+ void set_frame_coords(const Vector2 &p_coord);
+ Vector2 get_frame_coords() const;
+
+ void set_vframes(int p_amount);
+ int get_vframes() const;
+
+ void set_hframes(int p_amount);
+ int get_hframes() const;
+
+ Rect2 get_rect() const;
+ virtual Rect2 get_anchorable_rect() const;
+
+ Sprite2D();
+ ~Sprite2D();
+};
+
+#endif // SPRITE_H
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 601be17274..1cf12e4421 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -35,8 +35,8 @@
#include "core/method_bind_ext.gen.inc"
#include "core/os/os.h"
#include "scene/2d/area_2d.h"
-#include "servers/navigation_2d_server.h"
-#include "servers/physics_2d_server.h"
+#include "servers/navigation_server_2d.h"
+#include "servers/physics_server_2d.h"
int TileMap::_get_quadrant_size() const {
@@ -87,7 +87,7 @@ void TileMap::_notification(int p_what) {
if (navigation) {
for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
- Navigation2DServer::get_singleton()->region_set_map(F->get().region, RID());
+ NavigationServer2D::get_singleton()->region_set_map(F->get().region, RID());
}
q.navpoly_ids.clear();
}
@@ -98,13 +98,13 @@ void TileMap::_notification(int p_what) {
}
for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) {
- VS::get_singleton()->free(F->get().id);
+ RS::get_singleton()->free(F->get().id);
}
q.occluder_instances.clear();
}
- collision_parent = NULL;
- navigation = NULL;
+ collision_parent = nullptr;
+ navigation = nullptr;
} break;
@@ -130,7 +130,7 @@ void TileMap::_update_quadrant_space(const RID &p_space) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
- Physics2DServer::get_singleton()->body_set_space(q.body, p_space);
+ PhysicsServer2D::get_singleton()->body_set_space(q.body, p_space);
}
}
}
@@ -158,18 +158,18 @@ void TileMap::_update_quadrant_transform() {
if (!use_parent) {
xform = global_transform * xform;
- Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform);
+ PhysicsServer2D::get_singleton()->body_set_state(q.body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
}
if (navigation) {
for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) {
- Navigation2DServer::get_singleton()->region_set_transform(F->get().region, nav_rel * F->get().xform);
+ NavigationServer2D::get_singleton()->region_set_transform(F->get().region, nav_rel * F->get().xform);
}
}
for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) {
- VS::get_singleton()->canvas_light_occluder_set_transform(F->get().id, global_transform * F->get().xform);
+ RS::get_singleton()->canvas_light_occluder_set_transform(F->get().id, global_transform * F->get().xform);
}
}
}
@@ -298,7 +298,7 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const
}
void TileMap::_add_shape(int &shape_idx, const Quadrant &p_q, const Ref<Shape2D> &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata) {
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
if (!use_parent) {
ps->body_add_shape(p_q.body, p_shape->get_rid(), p_xform);
@@ -314,7 +314,7 @@ void TileMap::_add_shape(int &shape_idx, const Quadrant &p_q, const Ref<Shape2D>
int real_index = collision_parent->shape_owner_get_shape_index(p_q.shape_owner_id, shape_idx);
RID rid = collision_parent->get_rid();
- if (Object::cast_to<Area2D>(collision_parent) != NULL) {
+ if (Object::cast_to<Area2D>(collision_parent) != nullptr) {
ps->area_set_shape_transform(rid, real_index, get_transform() * xform);
} else {
ps->body_set_shape_transform(rid, real_index, get_transform() * xform);
@@ -334,8 +334,8 @@ void TileMap::update_dirty_quadrants() {
return;
}
- VisualServer *vs = VisualServer::get_singleton();
- Physics2DServer *ps = Physics2DServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
+ PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
Vector2 tofs = get_cell_draw_offset();
Transform2D nav_rel;
if (navigation)
@@ -378,13 +378,13 @@ void TileMap::update_dirty_quadrants() {
if (navigation) {
for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
- Navigation2DServer::get_singleton()->region_set_map(E->get().region, RID());
+ 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()) {
- VS::get_singleton()->free(E->get().id);
+ RS::get_singleton()->free(E->get().id);
}
q.occluder_instances.clear();
Ref<ShaderMaterial> prev_material;
@@ -439,7 +439,7 @@ void TileMap::update_dirty_quadrants() {
debug_canvas_item = vs->canvas_item_create();
vs->canvas_item_set_parent(debug_canvas_item, canvas_item);
vs->canvas_item_set_z_as_relative_to_parent(debug_canvas_item, false);
- vs->canvas_item_set_z_index(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1);
+ vs->canvas_item_set_z_index(debug_canvas_item, RS::CANVAS_ITEM_Z_MAX - 1);
q.canvas_items.push_back(debug_canvas_item);
prev_debug_canvas_item = debug_canvas_item;
}
@@ -550,7 +550,7 @@ void TileMap::update_dirty_quadrants() {
if (r == Rect2()) {
tex->draw_rect(canvas_item, rect, false, modulate, c.transpose, normal_map);
} else {
- tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map, Ref<Texture2D>(), Color(1, 1, 1, 1), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, clip_uv);
+ tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map, Ref<Texture2D>(), Color(1, 1, 1, 1), RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, clip_uv);
}
Vector<TileSet::ShapeData> shapes = tile_set->tile_get_shapes(c.id);
@@ -612,10 +612,10 @@ void TileMap::update_dirty_quadrants() {
xform.set_origin(offset.floor() + q.pos);
_fix_cell_transform(xform, c, npoly_ofs, s);
- RID region = Navigation2DServer::get_singleton()->region_create();
- Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
- Navigation2DServer::get_singleton()->region_set_transform(region, nav_rel * xform);
- Navigation2DServer::get_singleton()->region_set_navpoly(region, navpoly);
+ 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_navpoly(region, navpoly);
Quadrant::NavPoly np;
np.region = region;
@@ -626,7 +626,7 @@ void TileMap::update_dirty_quadrants() {
RID debug_navigation_item = vs->canvas_item_create();
vs->canvas_item_set_parent(debug_navigation_item, canvas_item);
vs->canvas_item_set_z_as_relative_to_parent(debug_navigation_item, false);
- vs->canvas_item_set_z_index(debug_navigation_item, VS::CANVAS_ITEM_Z_MAX - 2); // Display one below collision debug
+ vs->canvas_item_set_z_index(debug_navigation_item, RS::CANVAS_ITEM_Z_MAX - 2); // Display one below collision debug
if (debug_navigation_item.is_valid()) {
Vector<Vector2> navigation_polygon_vertices = navpoly->get_vertices();
@@ -685,11 +685,11 @@ void TileMap::update_dirty_quadrants() {
xform.set_origin(offset.floor() + q.pos);
_fix_cell_transform(xform, c, occluder_ofs, s);
- RID orid = VS::get_singleton()->canvas_light_occluder_create();
- VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform);
- VS::get_singleton()->canvas_light_occluder_set_polygon(orid, occluder->get_rid());
- VS::get_singleton()->canvas_light_occluder_attach_to_canvas(orid, get_canvas());
- VS::get_singleton()->canvas_light_occluder_set_light_mask(orid, occluder_light_mask);
+ RID orid = RS::get_singleton()->canvas_light_occluder_create();
+ RS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform);
+ RS::get_singleton()->canvas_light_occluder_set_polygon(orid, occluder->get_rid());
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(orid, get_canvas());
+ RS::get_singleton()->canvas_light_occluder_set_light_mask(orid, occluder_light_mask);
Quadrant::Occluder oc;
oc.xform = xform;
oc.id = orid;
@@ -711,7 +711,7 @@ void TileMap::update_dirty_quadrants() {
Quadrant &q = E->get();
for (List<RID>::Element *F = q.canvas_items.front(); F; F = F->next()) {
- VS::get_singleton()->canvas_item_set_draw_index(F->get(), index++);
+ RS::get_singleton()->canvas_item_set_draw_index(F->get(), index++);
}
}
@@ -763,24 +763,24 @@ Map<TileMap::PosKey, TileMap::Quadrant>::Element *TileMap::_create_quadrant(cons
q.pos.y += cell_size.y;
xform.set_origin(q.pos);
- //q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
+ //q.canvas_item = RenderingServer::get_singleton()->canvas_item_create();
if (!use_parent) {
- q.body = Physics2DServer::get_singleton()->body_create();
- Physics2DServer::get_singleton()->body_set_mode(q.body, use_kinematic ? Physics2DServer::BODY_MODE_KINEMATIC : Physics2DServer::BODY_MODE_STATIC);
+ q.body = PhysicsServer2D::get_singleton()->body_create();
+ PhysicsServer2D::get_singleton()->body_set_mode(q.body, use_kinematic ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
- Physics2DServer::get_singleton()->body_attach_object_instance_id(q.body, get_instance_id());
- Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer);
- Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask);
- Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, friction);
- Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, bounce);
+ PhysicsServer2D::get_singleton()->body_attach_object_instance_id(q.body, get_instance_id());
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(q.body, collision_layer);
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(q.body, collision_mask);
+ PhysicsServer2D::get_singleton()->body_set_param(q.body, PhysicsServer2D::BODY_PARAM_FRICTION, friction);
+ PhysicsServer2D::get_singleton()->body_set_param(q.body, PhysicsServer2D::BODY_PARAM_BOUNCE, bounce);
if (is_inside_tree()) {
xform = get_global_transform() * xform;
RID space = get_world_2d()->get_space();
- Physics2DServer::get_singleton()->body_set_space(q.body, space);
+ PhysicsServer2D::get_singleton()->body_set_space(q.body, space);
}
- Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform);
+ PhysicsServer2D::get_singleton()->body_set_state(q.body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
} else if (collision_parent) {
xform = get_transform() * xform;
q.shape_owner_id = collision_parent->create_shape_owner(this);
@@ -797,14 +797,14 @@ void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) {
Quadrant &q = Q->get();
if (!use_parent) {
- Physics2DServer::get_singleton()->free(q.body);
+ PhysicsServer2D::get_singleton()->free(q.body);
} else if (collision_parent) {
collision_parent->remove_shape_owner(q.shape_owner_id);
}
for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
- VisualServer::get_singleton()->free(E->get());
+ RenderingServer::get_singleton()->free(E->get());
}
q.canvas_items.clear();
if (q.dirty_list.in_list())
@@ -813,13 +813,13 @@ void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) {
if (navigation) {
for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
- Navigation2DServer::get_singleton()->region_set_map(E->get().region, RID());
+ 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()) {
- VS::get_singleton()->free(E->get().id);
+ RS::get_singleton()->free(E->get().id);
}
q.occluder_instances.clear();
@@ -921,7 +921,7 @@ void TileMap::make_bitmask_area_dirty(const Vector2 &p_pos) {
for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) {
for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) {
PosKey p(x, y);
- if (dirty_bitmask.find(p) == NULL) {
+ if (dirty_bitmask.find(p) == nullptr) {
dirty_bitmask.push_back(p);
}
}
@@ -962,7 +962,7 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) {
ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot update cell bitmask if Tileset is not open.");
PosKey p(p_x, p_y);
Map<PosKey, Cell>::Element *E = tile_map.find(p);
- if (E != NULL) {
+ if (E != nullptr) {
int id = get_cell(p_x, p_y);
if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) {
uint16_t mask = 0;
@@ -1197,7 +1197,7 @@ void TileMap::_update_all_items_material_state() {
void TileMap::_update_item_material_state(const RID &p_canvas_item) {
- VS::get_singleton()->canvas_item_set_use_parent_material(p_canvas_item, get_use_parent_material() || get_material().is_valid());
+ RS::get_singleton()->canvas_item_set_use_parent_material(p_canvas_item, get_use_parent_material() || get_material().is_valid());
}
void TileMap::clear() {
@@ -1302,7 +1302,7 @@ void TileMap::set_collision_layer(uint32_t p_layer) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
- Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer);
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(q.body, collision_layer);
}
}
}
@@ -1314,7 +1314,7 @@ void TileMap::set_collision_mask(uint32_t p_mask) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
- Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask);
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(q.body, collision_mask);
}
}
}
@@ -1368,7 +1368,7 @@ void TileMap::set_collision_use_parent(bool p_use_parent) {
if (use_parent && is_inside_tree()) {
collision_parent = Object::cast_to<CollisionObject2D>(get_parent());
} else {
- collision_parent = NULL;
+ collision_parent = nullptr;
}
_recreate_quadrants();
@@ -1383,7 +1383,7 @@ void TileMap::set_collision_friction(float p_friction) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
- Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, p_friction);
+ PhysicsServer2D::get_singleton()->body_set_param(q.body, PhysicsServer2D::BODY_PARAM_FRICTION, p_friction);
}
}
}
@@ -1400,7 +1400,7 @@ void TileMap::set_collision_bounce(float p_bounce) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
- Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, p_bounce);
+ PhysicsServer2D::get_singleton()->body_set_param(q.body, PhysicsServer2D::BODY_PARAM_BOUNCE, p_bounce);
}
}
}
@@ -1655,7 +1655,7 @@ void TileMap::set_y_sort_mode(bool p_enable) {
_clear_quadrants();
y_sort_mode = p_enable;
- VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_mode);
+ RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_mode);
_recreate_quadrants();
emit_signal("settings_changed");
}
@@ -1746,7 +1746,7 @@ void TileMap::set_occluder_light_mask(int p_mask) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
for (Map<PosKey, Quadrant::Occluder>::Element *F = E->get().occluder_instances.front(); F; F = F->next()) {
- VisualServer::get_singleton()->canvas_light_occluder_set_light_mask(F->get().id, occluder_light_mask);
+ RenderingServer::get_singleton()->canvas_light_occluder_set_light_mask(F->get().id, occluder_light_mask);
}
}
}
@@ -1762,7 +1762,7 @@ void TileMap::set_light_mask(int p_light_mask) {
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
for (List<RID>::Element *F = E->get().canvas_items.front(); F; F = F->next()) {
- VisualServer::get_singleton()->canvas_item_set_light_mask(F->get(), get_light_mask());
+ RenderingServer::get_singleton()->canvas_item_set_light_mask(F->get(), get_light_mask());
}
}
}
@@ -1959,9 +1959,9 @@ TileMap::TileMap() {
mode = MODE_SQUARE;
half_offset = HALF_OFFSET_DISABLED;
use_parent = false;
- collision_parent = NULL;
+ collision_parent = nullptr;
use_kinematic = false;
- navigation = NULL;
+ navigation = nullptr;
y_sort_mode = false;
compatibility_mode = false;
centered_textures = false;
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 1cca45b422..2cb979a0e0 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -30,10 +30,11 @@
#include "touch_screen_button.h"
-#include "core/input_map.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
+#include "core/input/input_map.h"
#include "core/os/os.h"
-
+#include "scene/main/window.h"
+#
void TouchScreenButton::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
@@ -114,7 +115,7 @@ void TouchScreenButton::_notification(int p_what) {
if (!is_inside_tree())
return;
- if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY)
+ if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY)
return;
if (finger_pressed != -1) {
@@ -145,7 +146,7 @@ void TouchScreenButton::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
- if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility == VISIBILITY_TOUCHSCREEN_ONLY)
+ if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY)
return;
update();
@@ -289,12 +290,12 @@ void TouchScreenButton::_press(int p_finger_pressed) {
if (action != StringName()) {
- Input::get_singleton()->action_press(action);
+ InputFilter::get_singleton()->action_press(action);
Ref<InputEventAction> iea;
iea.instance();
iea->set_action(action);
iea->set_pressed(true);
- get_tree()->input_event(iea);
+ get_viewport()->input(iea, true);
}
emit_signal("pressed");
@@ -307,14 +308,14 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
if (action != StringName()) {
- Input::get_singleton()->action_release(action);
+ InputFilter::get_singleton()->action_release(action);
if (!p_exiting_tree) {
Ref<InputEventAction> iea;
iea.instance();
iea->set_action(action);
iea->set_pressed(false);
- get_tree()->input_event(iea);
+ get_viewport()->input(iea, true);
}
}
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index 366de28386..c374dd5faa 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -31,11 +31,11 @@
#include "visibility_notifier_2d.h"
#include "core/engine.h"
-#include "particles_2d.h"
-#include "scene/2d/animated_sprite.h"
+#include "gpu_particles_2d.h"
+#include "scene/2d/animated_sprite_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/animation/animation_player.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED
@@ -188,8 +188,7 @@ void VisibilityEnabler2D::_find_nodes(Node *p_node) {
bool add = false;
Variant meta;
- if (enabler[ENABLER_FREEZE_BODIES]) {
-
+ {
RigidBody2D *rb2d = Object::cast_to<RigidBody2D>(p_node);
if (rb2d && ((rb2d->get_mode() == RigidBody2D::MODE_CHARACTER || rb2d->get_mode() == RigidBody2D::MODE_RIGID))) {
@@ -198,25 +197,22 @@ void VisibilityEnabler2D::_find_nodes(Node *p_node) {
}
}
- if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
-
+ {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
if (ap) {
add = true;
}
}
- if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) {
-
- AnimatedSprite *as = Object::cast_to<AnimatedSprite>(p_node);
+ {
+ AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
if (as) {
add = true;
}
}
- if (enabler[ENABLER_PAUSE_PARTICLES]) {
-
- Particles2D *ps = Object::cast_to<Particles2D>(p_node);
+ {
+ GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
if (ps) {
add = true;
}
@@ -278,7 +274,7 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
ERR_FAIL_COND(!nodes.has(p_node));
- {
+ if (enabler[ENABLER_FREEZE_BODIES]) {
RigidBody2D *rb = Object::cast_to<RigidBody2D>(p_node);
if (rb) {
@@ -286,7 +282,7 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
}
}
- {
+ if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
if (ap) {
@@ -294,8 +290,9 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
ap->set_active(p_enabled);
}
}
- {
- AnimatedSprite *as = Object::cast_to<AnimatedSprite>(p_node);
+
+ if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) {
+ AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
if (as) {
@@ -306,8 +303,8 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
}
}
- {
- Particles2D *ps = Object::cast_to<Particles2D>(p_node);
+ if (enabler[ENABLER_PAUSE_PARTICLES]) {
+ GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
if (ps) {
diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp
index 62f10a5c96..15d97eeaa0 100644
--- a/scene/2d/y_sort.cpp
+++ b/scene/2d/y_sort.cpp
@@ -33,7 +33,7 @@
void YSort::set_sort_enabled(bool p_enabled) {
sort_enabled = p_enabled;
- VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), sort_enabled);
+ RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), sort_enabled);
}
bool YSort::is_sort_enabled() const {
@@ -53,5 +53,5 @@ void YSort::_bind_methods() {
YSort::YSort() {
sort_enabled = true;
- VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), true);
+ RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), true);
}
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index 31a443bad1..ce69e8aa19 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -1,12 +1,9 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
-if env['disable_3d']:
- env.add_source_files(env.scene_sources, "spatial.cpp")
- env.add_source_files(env.scene_sources, "skeleton.cpp")
- env.add_source_files(env.scene_sources, "particles.cpp")
- env.add_source_files(env.scene_sources, "visual_instance.cpp")
- env.add_source_files(env.scene_sources, "world_environment.cpp")
+if env["disable_3d"]:
+ env.add_source_files(env.scene_sources, "node_3d.cpp")
+ env.add_source_files(env.scene_sources, "skeleton_3d.cpp")
else:
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
deleted file mode 100644
index 321926d841..0000000000
--- a/scene/3d/area.cpp
+++ /dev/null
@@ -1,759 +0,0 @@
-/*************************************************************************/
-/* area.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "area.h"
-
-#include "scene/scene_string_names.h"
-#include "servers/audio_server.h"
-#include "servers/physics_server.h"
-
-void Area::set_space_override_mode(SpaceOverride p_mode) {
-
- space_override = p_mode;
- PhysicsServer::get_singleton()->area_set_space_override_mode(get_rid(), PhysicsServer::AreaSpaceOverrideMode(p_mode));
-}
-Area::SpaceOverride Area::get_space_override_mode() const {
-
- return space_override;
-}
-
-void Area::set_gravity_is_point(bool p_enabled) {
-
- gravity_is_point = p_enabled;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT, p_enabled);
-}
-bool Area::is_gravity_a_point() const {
-
- return gravity_is_point;
-}
-
-void Area::set_gravity_distance_scale(real_t p_scale) {
-
- gravity_distance_scale = p_scale;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
-}
-
-real_t Area::get_gravity_distance_scale() const {
- return gravity_distance_scale;
-}
-
-void Area::set_gravity_vector(const Vector3 &p_vec) {
-
- gravity_vec = p_vec;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY_VECTOR, p_vec);
-}
-Vector3 Area::get_gravity_vector() const {
-
- return gravity_vec;
-}
-
-void Area::set_gravity(real_t p_gravity) {
-
- gravity = p_gravity;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_GRAVITY, p_gravity);
-}
-real_t Area::get_gravity() const {
-
- return gravity;
-}
-void Area::set_linear_damp(real_t p_linear_damp) {
-
- linear_damp = p_linear_damp;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_LINEAR_DAMP, p_linear_damp);
-}
-real_t Area::get_linear_damp() const {
-
- return linear_damp;
-}
-
-void Area::set_angular_damp(real_t p_angular_damp) {
-
- angular_damp = p_angular_damp;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_ANGULAR_DAMP, p_angular_damp);
-}
-
-real_t Area::get_angular_damp() const {
-
- return angular_damp;
-}
-
-void Area::set_priority(real_t p_priority) {
-
- priority = p_priority;
- PhysicsServer::get_singleton()->area_set_param(get_rid(), PhysicsServer::AREA_PARAM_PRIORITY, p_priority);
-}
-real_t Area::get_priority() const {
-
- return priority;
-}
-
-void Area::_body_enter_tree(ObjectID p_id) {
-
- Object *obj = ObjectDB::get_instance(p_id);
- Node *node = Object::cast_to<Node>(obj);
- ERR_FAIL_COND(!node);
-
- Map<ObjectID, BodyState>::Element *E = body_map.find(p_id);
- ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_tree);
-
- E->get().in_tree = true;
- emit_signal(SceneStringNames::get_singleton()->body_entered, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
- }
-}
-
-void Area::_body_exit_tree(ObjectID p_id) {
-
- Object *obj = ObjectDB::get_instance(p_id);
- Node *node = Object::cast_to<Node>(obj);
- ERR_FAIL_COND(!node);
- Map<ObjectID, BodyState>::Element *E = body_map.find(p_id);
- ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_tree);
- E->get().in_tree = false;
- emit_signal(SceneStringNames::get_singleton()->body_exited, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
- }
-}
-
-void Area::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {
-
- bool body_in = p_status == PhysicsServer::AREA_BODY_ADDED;
- ObjectID objid = p_instance;
-
- Object *obj = ObjectDB::get_instance(objid);
- Node *node = Object::cast_to<Node>(obj);
-
- Map<ObjectID, BodyState>::Element *E = body_map.find(objid);
-
- if (!body_in && !E) {
- return; //likely removed from the tree
- }
-
- locked = true;
-
- if (body_in) {
- if (!E) {
-
- E = body_map.insert(objid, BodyState());
- E->get().rc = 0;
- E->get().in_tree = node && node->is_inside_tree();
- if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_body_exit_tree), make_binds(objid));
- if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_entered, node);
- }
- }
- }
- E->get().rc++;
- if (node)
- E->get().shapes.insert(ShapePair(p_body_shape, p_area_shape));
-
- if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_area_shape);
- }
-
- } else {
-
- E->get().rc--;
-
- if (node)
- E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape));
-
- bool eraseit = false;
-
- if (E->get().rc == 0) {
-
- if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_body_exit_tree));
- if (E->get().in_tree)
- emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
- }
-
- eraseit = true;
- }
- if (node && E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape);
- }
-
- if (eraseit)
- body_map.erase(E);
- }
-
- locked = false;
-}
-
-void Area::_clear_monitoring() {
-
- ERR_FAIL_COND_MSG(locked, "This function can't be used during the in/out signal.");
-
- {
- Map<ObjectID, BodyState> bmcopy = body_map;
- body_map.clear();
- //disconnect all monitored stuff
-
- for (Map<ObjectID, BodyState>::Element *E = bmcopy.front(); E; E = E->next()) {
-
- 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
- continue;
- //ERR_CONTINUE(!node);
-
- if (!E->get().in_tree)
- continue;
-
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->key(), node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
- }
-
- emit_signal(SceneStringNames::get_singleton()->body_exited, node);
-
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_body_exit_tree));
- }
- }
-
- {
-
- Map<ObjectID, AreaState> bmcopy = area_map;
- area_map.clear();
- //disconnect all monitored stuff
-
- for (Map<ObjectID, AreaState>::Element *E = bmcopy.front(); E; E = E->next()) {
-
- 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
- continue;
- //ERR_CONTINUE(!node);
-
- if (!E->get().in_tree)
- continue;
-
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->key(), node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
- }
-
- emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
-
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_area_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_area_exit_tree));
- }
- }
-}
-void Area::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- _clear_monitoring();
- }
-}
-
-void Area::set_monitoring(bool p_enable) {
-
- ERR_FAIL_COND_MSG(locked, "Function blocked during in/out signal. Use set_deferred(\"monitoring\", true/false).");
-
- if (p_enable == monitoring)
- return;
-
- monitoring = p_enable;
-
- if (monitoring) {
-
- PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_body_inout);
- PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_area_inout);
- } else {
- PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(), NULL, StringName());
- PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(), NULL, StringName());
- _clear_monitoring();
- }
-}
-
-void Area::_area_enter_tree(ObjectID p_id) {
-
- Object *obj = ObjectDB::get_instance(p_id);
- Node *node = Object::cast_to<Node>(obj);
- ERR_FAIL_COND(!node);
-
- Map<ObjectID, AreaState>::Element *E = area_map.find(p_id);
- ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_tree);
-
- E->get().in_tree = true;
- emit_signal(SceneStringNames::get_singleton()->area_entered, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_id, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
- }
-}
-
-void Area::_area_exit_tree(ObjectID p_id) {
-
- Object *obj = ObjectDB::get_instance(p_id);
- Node *node = Object::cast_to<Node>(obj);
- ERR_FAIL_COND(!node);
- Map<ObjectID, AreaState>::Element *E = area_map.find(p_id);
- ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_tree);
- E->get().in_tree = false;
- emit_signal(SceneStringNames::get_singleton()->area_exited, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_id, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
- }
-}
-
-void Area::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) {
-
- bool area_in = p_status == PhysicsServer::AREA_BODY_ADDED;
- ObjectID objid = p_instance;
-
- Object *obj = ObjectDB::get_instance(objid);
- Node *node = Object::cast_to<Node>(obj);
-
- Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
-
- if (!area_in && !E) {
- return; //likely removed from the tree
- }
-
- locked = true;
-
- if (area_in) {
- if (!E) {
-
- E = area_map.insert(objid, AreaState());
- E->get().rc = 0;
- E->get().in_tree = node && node->is_inside_tree();
- if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_area_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_area_exit_tree), make_binds(objid));
- if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_entered, node);
- }
- }
- }
- E->get().rc++;
- if (node)
- E->get().shapes.insert(AreaShapePair(p_area_shape, p_self_shape));
-
- if (!node || E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, objid, node, p_area_shape, p_self_shape);
- }
-
- } else {
-
- E->get().rc--;
-
- if (node)
- E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
-
- bool eraseit = false;
-
- if (E->get().rc == 0) {
-
- if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area::_area_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area::_area_exit_tree));
- if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
- }
- }
-
- eraseit = true;
- }
- if (!node || E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape);
- }
-
- if (eraseit)
- area_map.erase(E);
- }
-
- locked = false;
-}
-
-bool Area::is_monitoring() const {
-
- return monitoring;
-}
-
-Array Area::get_overlapping_bodies() const {
-
- ERR_FAIL_COND_V(!monitoring, Array());
- Array ret;
- ret.resize(body_map.size());
- int idx = 0;
- for (const Map<ObjectID, BodyState>::Element *E = body_map.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
- }
- }
-
- return ret;
-}
-
-void Area::set_monitorable(bool p_enable) {
-
- ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false).");
-
- if (p_enable == monitorable)
- return;
-
- monitorable = p_enable;
-
- PhysicsServer::get_singleton()->area_set_monitorable(get_rid(), monitorable);
-}
-
-bool Area::is_monitorable() const {
-
- return monitorable;
-}
-
-Array Area::get_overlapping_areas() const {
-
- ERR_FAIL_COND_V(!monitoring, Array());
- Array ret;
- ret.resize(area_map.size());
- int idx = 0;
- for (const Map<ObjectID, AreaState>::Element *E = area_map.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
- }
- }
-
- return ret;
-}
-
-bool Area::overlaps_area(Node *p_area) const {
-
- ERR_FAIL_NULL_V(p_area, false);
- const Map<ObjectID, AreaState>::Element *E = area_map.find(p_area->get_instance_id());
- if (!E)
- return false;
- return E->get().in_tree;
-}
-
-bool Area::overlaps_body(Node *p_body) const {
-
- ERR_FAIL_NULL_V(p_body, false);
- const Map<ObjectID, BodyState>::Element *E = body_map.find(p_body->get_instance_id());
- if (!E)
- return false;
- return E->get().in_tree;
-}
-void Area::set_collision_mask(uint32_t p_mask) {
-
- collision_mask = p_mask;
- PhysicsServer::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t Area::get_collision_mask() const {
-
- return collision_mask;
-}
-void Area::set_collision_layer(uint32_t p_layer) {
-
- collision_layer = p_layer;
- PhysicsServer::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t Area::get_collision_layer() const {
-
- return collision_layer;
-}
-
-void Area::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 Area::get_collision_mask_bit(int p_bit) const {
-
- return get_collision_mask() & (1 << p_bit);
-}
-
-void Area::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 Area::get_collision_layer_bit(int p_bit) const {
-
- return get_collision_layer() & (1 << p_bit);
-}
-
-void Area::set_audio_bus_override(bool p_override) {
-
- audio_bus_override = p_override;
-}
-
-bool Area::is_overriding_audio_bus() const {
-
- return audio_bus_override;
-}
-
-void Area::set_audio_bus(const StringName &p_audio_bus) {
-
- audio_bus = p_audio_bus;
-}
-StringName Area::get_audio_bus() const {
-
- for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
- if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
- return audio_bus;
- }
- }
- return "Master";
-}
-
-void Area::set_use_reverb_bus(bool p_enable) {
-
- use_reverb_bus = p_enable;
-}
-bool Area::is_using_reverb_bus() const {
-
- return use_reverb_bus;
-}
-
-void Area::set_reverb_bus(const StringName &p_audio_bus) {
-
- reverb_bus = p_audio_bus;
-}
-StringName Area::get_reverb_bus() const {
-
- for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
- if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) {
- return reverb_bus;
- }
- }
- return "Master";
-}
-
-void Area::set_reverb_amount(float p_amount) {
-
- reverb_amount = p_amount;
-}
-float Area::get_reverb_amount() const {
-
- return reverb_amount;
-}
-
-void Area::set_reverb_uniformity(float p_uniformity) {
-
- reverb_uniformity = p_uniformity;
-}
-float Area::get_reverb_uniformity() const {
-
- return reverb_uniformity;
-}
-
-void Area::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "audio_bus_name" || property.name == "reverb_bus_name") {
-
- String options;
- for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
- if (i > 0)
- options += ",";
- String name = AudioServer::get_singleton()->get_bus_name(i);
- options += name;
- }
-
- property.hint_string = options;
- }
-}
-
-void Area::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_space_override_mode", "enable"), &Area::set_space_override_mode);
- ClassDB::bind_method(D_METHOD("get_space_override_mode"), &Area::get_space_override_mode);
-
- ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area::set_gravity_is_point);
- ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area::is_gravity_a_point);
-
- ClassDB::bind_method(D_METHOD("set_gravity_distance_scale", "distance_scale"), &Area::set_gravity_distance_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_distance_scale"), &Area::get_gravity_distance_scale);
-
- ClassDB::bind_method(D_METHOD("set_gravity_vector", "vector"), &Area::set_gravity_vector);
- ClassDB::bind_method(D_METHOD("get_gravity_vector"), &Area::get_gravity_vector);
-
- ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &Area::set_gravity);
- ClassDB::bind_method(D_METHOD("get_gravity"), &Area::get_gravity);
-
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &Area::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &Area::get_angular_damp);
-
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &Area::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &Area::get_linear_damp);
-
- ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area::set_priority);
- ClassDB::bind_method(D_METHOD("get_priority"), &Area::get_priority);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area::get_collision_layer_bit);
-
- ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area::set_monitorable);
- ClassDB::bind_method(D_METHOD("is_monitorable"), &Area::is_monitorable);
-
- ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area::set_monitoring);
- ClassDB::bind_method(D_METHOD("is_monitoring"), &Area::is_monitoring);
-
- ClassDB::bind_method(D_METHOD("get_overlapping_bodies"), &Area::get_overlapping_bodies);
- ClassDB::bind_method(D_METHOD("get_overlapping_areas"), &Area::get_overlapping_areas);
-
- ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area::overlaps_body);
- ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area::overlaps_area);
-
- ClassDB::bind_method(D_METHOD("_body_inout"), &Area::_body_inout);
- ClassDB::bind_method(D_METHOD("_area_inout"), &Area::_area_inout);
-
- ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area::set_audio_bus_override);
- ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area::is_overriding_audio_bus);
-
- ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area::set_audio_bus);
- ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area::get_audio_bus);
-
- ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area::set_use_reverb_bus);
- ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area::is_using_reverb_bus);
-
- ClassDB::bind_method(D_METHOD("set_reverb_bus", "name"), &Area::set_reverb_bus);
- ClassDB::bind_method(D_METHOD("get_reverb_bus"), &Area::get_reverb_bus);
-
- ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area::set_reverb_amount);
- ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area::get_reverb_amount);
-
- ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area::set_reverb_uniformity);
- ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area::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, "area_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, "area_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("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape")));
- ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape")));
- ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area")));
- ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area")));
-
- 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");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
- 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", "get_audio_bus");
- 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");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity");
-
- BIND_ENUM_CONSTANT(SPACE_OVERRIDE_DISABLED);
- BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE);
- BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE_REPLACE);
- BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE);
- BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE_COMBINE);
-}
-
-Area::Area() :
- CollisionObject(PhysicsServer::get_singleton()->area_create(), true) {
-
- space_override = SPACE_OVERRIDE_DISABLED;
- set_gravity(9.8);
- locked = false;
- set_gravity_vector(Vector3(0, -1, 0));
- gravity_is_point = false;
- gravity_distance_scale = 0;
- linear_damp = 0.1;
- angular_damp = 0.1;
- priority = 0;
- monitoring = false;
- monitorable = false;
- collision_mask = 1;
- collision_layer = 1;
- set_monitoring(true);
- set_monitorable(true);
-
- audio_bus_override = false;
- audio_bus = "Master";
-
- use_reverb_bus = false;
- reverb_bus = "Master";
- reverb_amount = 0.0;
- reverb_uniformity = 0.0;
-}
-
-Area::~Area() {
-}
diff --git a/scene/3d/area.h b/scene/3d/area.h
deleted file mode 100644
index 7fe61430fa..0000000000
--- a/scene/3d/area.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*************************************************************************/
-/* area.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 AREA_H
-#define AREA_H
-
-#include "core/vset.h"
-#include "scene/3d/collision_object.h"
-
-class Area : public CollisionObject {
-
- GDCLASS(Area, CollisionObject);
-
-public:
- enum SpaceOverride {
- SPACE_OVERRIDE_DISABLED,
- SPACE_OVERRIDE_COMBINE,
- SPACE_OVERRIDE_COMBINE_REPLACE,
- SPACE_OVERRIDE_REPLACE,
- SPACE_OVERRIDE_REPLACE_COMBINE
- };
-
-private:
- SpaceOverride space_override;
- Vector3 gravity_vec;
- real_t gravity;
- bool gravity_is_point;
- real_t gravity_distance_scale;
- real_t angular_damp;
- real_t linear_damp;
- uint32_t collision_mask;
- uint32_t collision_layer;
- int priority;
- bool monitoring;
- bool monitorable;
- bool locked;
-
- void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape);
-
- void _body_enter_tree(ObjectID p_id);
- void _body_exit_tree(ObjectID p_id);
-
- struct ShapePair {
-
- int body_shape;
- int area_shape;
- bool operator<(const ShapePair &p_sp) const {
- if (body_shape == p_sp.body_shape)
- return area_shape < p_sp.area_shape;
- else
- return body_shape < p_sp.body_shape;
- }
-
- ShapePair() {}
- ShapePair(int p_bs, int p_as) {
- body_shape = p_bs;
- area_shape = p_as;
- }
- };
-
- struct BodyState {
-
- int rc;
- bool in_tree;
- VSet<ShapePair> shapes;
- };
-
- Map<ObjectID, BodyState> body_map;
-
- void _area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape);
-
- void _area_enter_tree(ObjectID p_id);
- void _area_exit_tree(ObjectID p_id);
-
- struct AreaShapePair {
-
- int area_shape;
- int self_shape;
- bool operator<(const AreaShapePair &p_sp) const {
- if (area_shape == p_sp.area_shape)
- return self_shape < p_sp.self_shape;
- else
- return area_shape < p_sp.area_shape;
- }
-
- AreaShapePair() {}
- AreaShapePair(int p_bs, int p_as) {
- area_shape = p_bs;
- self_shape = p_as;
- }
- };
-
- struct AreaState {
-
- int rc;
- bool in_tree;
- VSet<AreaShapePair> shapes;
- };
-
- Map<ObjectID, AreaState> area_map;
- void _clear_monitoring();
-
- bool audio_bus_override;
- StringName audio_bus;
-
- bool use_reverb_bus;
- StringName reverb_bus;
- float reverb_amount;
- float reverb_uniformity;
-
- void _validate_property(PropertyInfo &property) const;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_space_override_mode(SpaceOverride p_mode);
- SpaceOverride get_space_override_mode() const;
-
- void set_gravity_is_point(bool p_enabled);
- bool is_gravity_a_point() const;
-
- void set_gravity_distance_scale(real_t p_scale);
- real_t get_gravity_distance_scale() const;
-
- void set_gravity_vector(const Vector3 &p_vec);
- Vector3 get_gravity_vector() const;
-
- void set_gravity(real_t p_gravity);
- real_t get_gravity() const;
-
- void set_angular_damp(real_t p_angular_damp);
- real_t get_angular_damp() const;
-
- void set_linear_damp(real_t p_linear_damp);
- real_t get_linear_damp() const;
-
- void set_priority(real_t p_priority);
- real_t get_priority() const;
-
- void set_monitoring(bool p_enable);
- bool is_monitoring() const;
-
- 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;
-
- Array get_overlapping_bodies() const;
- Array get_overlapping_areas() const; //function for script
-
- bool overlaps_area(Node *p_area) const;
- bool overlaps_body(Node *p_body) const;
-
- void set_audio_bus_override(bool p_override);
- bool is_overriding_audio_bus() const;
-
- void set_audio_bus(const StringName &p_audio_bus);
- StringName get_audio_bus() const;
-
- void set_use_reverb_bus(bool p_enable);
- bool is_using_reverb_bus() const;
-
- void set_reverb_bus(const StringName &p_audio_bus);
- StringName get_reverb_bus() const;
-
- void set_reverb_amount(float p_amount);
- float get_reverb_amount() const;
-
- void set_reverb_uniformity(float p_uniformity);
- float get_reverb_uniformity() const;
-
- Area();
- ~Area();
-};
-
-VARIANT_ENUM_CAST(Area::SpaceOverride);
-
-#endif // AREA__H
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
new file mode 100644
index 0000000000..17ae553e5e
--- /dev/null
+++ b/scene/3d/area_3d.cpp
@@ -0,0 +1,759 @@
+/*************************************************************************/
+/* area_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "area_3d.h"
+
+#include "scene/scene_string_names.h"
+#include "servers/audio_server.h"
+#include "servers/physics_server_3d.h"
+
+void Area3D::set_space_override_mode(SpaceOverride p_mode) {
+
+ space_override = p_mode;
+ PhysicsServer3D::get_singleton()->area_set_space_override_mode(get_rid(), PhysicsServer3D::AreaSpaceOverrideMode(p_mode));
+}
+Area3D::SpaceOverride Area3D::get_space_override_mode() const {
+
+ return space_override;
+}
+
+void Area3D::set_gravity_is_point(bool p_enabled) {
+
+ gravity_is_point = p_enabled;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT, p_enabled);
+}
+bool Area3D::is_gravity_a_point() const {
+
+ return gravity_is_point;
+}
+
+void Area3D::set_gravity_distance_scale(real_t p_scale) {
+
+ gravity_distance_scale = p_scale;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
+}
+
+real_t Area3D::get_gravity_distance_scale() const {
+ return gravity_distance_scale;
+}
+
+void Area3D::set_gravity_vector(const Vector3 &p_vec) {
+
+ gravity_vec = p_vec;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, p_vec);
+}
+Vector3 Area3D::get_gravity_vector() const {
+
+ return gravity_vec;
+}
+
+void Area3D::set_gravity(real_t p_gravity) {
+
+ gravity = p_gravity;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY, p_gravity);
+}
+real_t Area3D::get_gravity() const {
+
+ return gravity;
+}
+void Area3D::set_linear_damp(real_t p_linear_damp) {
+
+ linear_damp = p_linear_damp;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, p_linear_damp);
+}
+real_t Area3D::get_linear_damp() const {
+
+ return linear_damp;
+}
+
+void Area3D::set_angular_damp(real_t p_angular_damp) {
+
+ angular_damp = p_angular_damp;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, p_angular_damp);
+}
+
+real_t Area3D::get_angular_damp() const {
+
+ return angular_damp;
+}
+
+void Area3D::set_priority(real_t p_priority) {
+
+ priority = p_priority;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_PRIORITY, p_priority);
+}
+real_t Area3D::get_priority() const {
+
+ return priority;
+}
+
+void Area3D::_body_enter_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!node);
+
+ Map<ObjectID, BodyState>::Element *E = body_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(E->get().in_tree);
+
+ E->get().in_tree = true;
+ emit_signal(SceneStringNames::get_singleton()->body_entered, node);
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ }
+}
+
+void Area3D::_body_exit_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!node);
+ Map<ObjectID, BodyState>::Element *E = body_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree = false;
+ emit_signal(SceneStringNames::get_singleton()->body_exited, node);
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ }
+}
+
+void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape) {
+
+ bool body_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
+ ObjectID objid = p_instance;
+
+ Object *obj = ObjectDB::get_instance(objid);
+ Node *node = Object::cast_to<Node>(obj);
+
+ Map<ObjectID, BodyState>::Element *E = body_map.find(objid);
+
+ if (!body_in && !E) {
+ return; //likely removed from the tree
+ }
+
+ locked = true;
+
+ if (body_in) {
+ if (!E) {
+
+ E = body_map.insert(objid, BodyState());
+ E->get().rc = 0;
+ E->get().in_tree = node && node->is_inside_tree();
+ if (node) {
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree), make_binds(objid));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->body_entered, node);
+ }
+ }
+ }
+ E->get().rc++;
+ if (node)
+ E->get().shapes.insert(ShapePair(p_body_shape, p_area_shape));
+
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_area_shape);
+ }
+
+ } else {
+
+ E->get().rc--;
+
+ if (node)
+ E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape));
+
+ bool eraseit = false;
+
+ if (E->get().rc == 0) {
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
+ if (E->get().in_tree)
+ emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
+ }
+
+ eraseit = true;
+ }
+ if (node && E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_area_shape);
+ }
+
+ if (eraseit)
+ body_map.erase(E);
+ }
+
+ locked = false;
+}
+
+void Area3D::_clear_monitoring() {
+
+ ERR_FAIL_COND_MSG(locked, "This function can't be used during the in/out signal.");
+
+ {
+ Map<ObjectID, BodyState> bmcopy = body_map;
+ body_map.clear();
+ //disconnect all monitored stuff
+
+ for (Map<ObjectID, BodyState>::Element *E = bmcopy.front(); E; E = E->next()) {
+
+ 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
+ continue;
+ //ERR_CONTINUE(!node);
+
+ if (!E->get().in_tree)
+ continue;
+
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->key(), node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->body_exited, node);
+
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_body_exit_tree));
+ }
+ }
+
+ {
+
+ Map<ObjectID, AreaState> bmcopy = area_map;
+ area_map.clear();
+ //disconnect all monitored stuff
+
+ for (Map<ObjectID, AreaState>::Element *E = bmcopy.front(); E; E = E->next()) {
+
+ 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
+ continue;
+ //ERR_CONTINUE(!node);
+
+ if (!E->get().in_tree)
+ continue;
+
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->key(), node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
+
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
+ }
+ }
+}
+void Area3D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ _clear_monitoring();
+ }
+}
+
+void Area3D::set_monitoring(bool p_enable) {
+
+ ERR_FAIL_COND_MSG(locked, "Function blocked during in/out signal. Use set_deferred(\"monitoring\", true/false).");
+
+ if (p_enable == monitoring)
+ return;
+
+ monitoring = p_enable;
+
+ if (monitoring) {
+
+ PhysicsServer3D::get_singleton()->area_set_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_body_inout);
+ PhysicsServer3D::get_singleton()->area_set_area_monitor_callback(get_rid(), this, SceneStringNames::get_singleton()->_area_inout);
+ } else {
+ PhysicsServer3D::get_singleton()->area_set_monitor_callback(get_rid(), nullptr, StringName());
+ PhysicsServer3D::get_singleton()->area_set_area_monitor_callback(get_rid(), nullptr, StringName());
+ _clear_monitoring();
+ }
+}
+
+void Area3D::_area_enter_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!node);
+
+ Map<ObjectID, AreaState>::Element *E = area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(E->get().in_tree);
+
+ E->get().in_tree = true;
+ emit_signal(SceneStringNames::get_singleton()->area_entered, node);
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_id, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ }
+}
+
+void Area3D::_area_exit_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!node);
+ Map<ObjectID, AreaState>::Element *E = area_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree = false;
+ emit_signal(SceneStringNames::get_singleton()->area_exited, node);
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, p_id, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ }
+}
+
+void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape) {
+
+ bool area_in = p_status == PhysicsServer3D::AREA_BODY_ADDED;
+ ObjectID objid = p_instance;
+
+ Object *obj = ObjectDB::get_instance(objid);
+ Node *node = Object::cast_to<Node>(obj);
+
+ Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
+
+ if (!area_in && !E) {
+ return; //likely removed from the tree
+ }
+
+ locked = true;
+
+ if (area_in) {
+ if (!E) {
+
+ E = area_map.insert(objid, AreaState());
+ E->get().rc = 0;
+ E->get().in_tree = node && node->is_inside_tree();
+ if (node) {
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree), make_binds(objid));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_entered, node);
+ }
+ }
+ }
+ E->get().rc++;
+ if (node)
+ E->get().shapes.insert(AreaShapePair(p_area_shape, p_self_shape));
+
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, objid, node, p_area_shape, p_self_shape);
+ }
+
+ } else {
+
+ E->get().rc--;
+
+ if (node)
+ E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
+
+ bool eraseit = false;
+
+ if (E->get().rc == 0) {
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area3D::_area_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area3D::_area_exit_tree));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
+ }
+ }
+
+ eraseit = true;
+ }
+ if (!node || E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, objid, obj, p_area_shape, p_self_shape);
+ }
+
+ if (eraseit)
+ area_map.erase(E);
+ }
+
+ locked = false;
+}
+
+bool Area3D::is_monitoring() const {
+
+ return monitoring;
+}
+
+Array Area3D::get_overlapping_bodies() const {
+
+ ERR_FAIL_COND_V(!monitoring, Array());
+ Array ret;
+ ret.resize(body_map.size());
+ int idx = 0;
+ for (const Map<ObjectID, BodyState>::Element *E = body_map.front(); E; E = E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize(ret.size() - 1); //ops
+ } else {
+ ret[idx++] = obj;
+ }
+ }
+
+ return ret;
+}
+
+void Area3D::set_monitorable(bool p_enable) {
+
+ ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer3D::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false).");
+
+ if (p_enable == monitorable)
+ return;
+
+ monitorable = p_enable;
+
+ PhysicsServer3D::get_singleton()->area_set_monitorable(get_rid(), monitorable);
+}
+
+bool Area3D::is_monitorable() const {
+
+ return monitorable;
+}
+
+Array Area3D::get_overlapping_areas() const {
+
+ ERR_FAIL_COND_V(!monitoring, Array());
+ Array ret;
+ ret.resize(area_map.size());
+ int idx = 0;
+ for (const Map<ObjectID, AreaState>::Element *E = area_map.front(); E; E = E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize(ret.size() - 1); //ops
+ } else {
+ ret[idx++] = obj;
+ }
+ }
+
+ return ret;
+}
+
+bool Area3D::overlaps_area(Node *p_area) const {
+
+ ERR_FAIL_NULL_V(p_area, false);
+ const Map<ObjectID, AreaState>::Element *E = area_map.find(p_area->get_instance_id());
+ if (!E)
+ return false;
+ return E->get().in_tree;
+}
+
+bool Area3D::overlaps_body(Node *p_body) const {
+
+ ERR_FAIL_NULL_V(p_body, false);
+ const Map<ObjectID, BodyState>::Element *E = body_map.find(p_body->get_instance_id());
+ if (!E)
+ return false;
+ 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;
+}
+
+bool Area3D::is_overriding_audio_bus() const {
+
+ return audio_bus_override;
+}
+
+void Area3D::set_audio_bus(const StringName &p_audio_bus) {
+
+ audio_bus = p_audio_bus;
+}
+StringName Area3D::get_audio_bus() const {
+
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
+ return audio_bus;
+ }
+ }
+ return "Master";
+}
+
+void Area3D::set_use_reverb_bus(bool p_enable) {
+
+ use_reverb_bus = p_enable;
+}
+bool Area3D::is_using_reverb_bus() const {
+
+ return use_reverb_bus;
+}
+
+void Area3D::set_reverb_bus(const StringName &p_audio_bus) {
+
+ reverb_bus = p_audio_bus;
+}
+StringName Area3D::get_reverb_bus() const {
+
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) {
+ return reverb_bus;
+ }
+ }
+ return "Master";
+}
+
+void Area3D::set_reverb_amount(float p_amount) {
+
+ reverb_amount = p_amount;
+}
+float Area3D::get_reverb_amount() const {
+
+ return reverb_amount;
+}
+
+void Area3D::set_reverb_uniformity(float p_uniformity) {
+
+ reverb_uniformity = p_uniformity;
+}
+float Area3D::get_reverb_uniformity() const {
+
+ return reverb_uniformity;
+}
+
+void Area3D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "audio_bus_name" || property.name == "reverb_bus_name") {
+
+ String options;
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (i > 0)
+ options += ",";
+ String name = AudioServer::get_singleton()->get_bus_name(i);
+ options += name;
+ }
+
+ property.hint_string = options;
+ }
+}
+
+void Area3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_space_override_mode", "enable"), &Area3D::set_space_override_mode);
+ ClassDB::bind_method(D_METHOD("get_space_override_mode"), &Area3D::get_space_override_mode);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area3D::set_gravity_is_point);
+ ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area3D::is_gravity_a_point);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_distance_scale", "distance_scale"), &Area3D::set_gravity_distance_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_distance_scale"), &Area3D::get_gravity_distance_scale);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_vector", "vector"), &Area3D::set_gravity_vector);
+ ClassDB::bind_method(D_METHOD("get_gravity_vector"), &Area3D::get_gravity_vector);
+
+ ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &Area3D::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_gravity"), &Area3D::get_gravity);
+
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &Area3D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &Area3D::get_angular_damp);
+
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &Area3D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &Area3D::get_linear_damp);
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area3D::set_monitoring);
+ ClassDB::bind_method(D_METHOD("is_monitoring"), &Area3D::is_monitoring);
+
+ ClassDB::bind_method(D_METHOD("get_overlapping_bodies"), &Area3D::get_overlapping_bodies);
+ ClassDB::bind_method(D_METHOD("get_overlapping_areas"), &Area3D::get_overlapping_areas);
+
+ ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area3D::overlaps_body);
+ ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area3D::overlaps_area);
+
+ ClassDB::bind_method(D_METHOD("_body_inout"), &Area3D::_body_inout);
+ ClassDB::bind_method(D_METHOD("_area_inout"), &Area3D::_area_inout);
+
+ ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area3D::set_audio_bus_override);
+ ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area3D::is_overriding_audio_bus);
+
+ ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area3D::set_audio_bus);
+ ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area3D::get_audio_bus);
+
+ ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus);
+ ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus);
+
+ ClassDB::bind_method(D_METHOD("set_reverb_bus", "name"), &Area3D::set_reverb_bus);
+ ClassDB::bind_method(D_METHOD("get_reverb_bus"), &Area3D::get_reverb_bus);
+
+ ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area3D::set_reverb_amount);
+ ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area3D::get_reverb_amount);
+
+ 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, "area_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, "area_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("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, "self_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, "self_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::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");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
+ 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", "get_audio_bus");
+ 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");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity");
+
+ BIND_ENUM_CONSTANT(SPACE_OVERRIDE_DISABLED);
+ BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE);
+ BIND_ENUM_CONSTANT(SPACE_OVERRIDE_COMBINE_REPLACE);
+ BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE);
+ BIND_ENUM_CONSTANT(SPACE_OVERRIDE_REPLACE_COMBINE);
+}
+
+Area3D::Area3D() :
+ CollisionObject3D(PhysicsServer3D::get_singleton()->area_create(), true) {
+
+ space_override = SPACE_OVERRIDE_DISABLED;
+ set_gravity(9.8);
+ locked = false;
+ set_gravity_vector(Vector3(0, -1, 0));
+ gravity_is_point = false;
+ gravity_distance_scale = 0;
+ linear_damp = 0.1;
+ angular_damp = 0.1;
+ priority = 0;
+ monitoring = false;
+ monitorable = false;
+ collision_mask = 1;
+ collision_layer = 1;
+ set_monitoring(true);
+ set_monitorable(true);
+
+ audio_bus_override = false;
+ audio_bus = "Master";
+
+ use_reverb_bus = false;
+ reverb_bus = "Master";
+ reverb_amount = 0.0;
+ reverb_uniformity = 0.0;
+}
+
+Area3D::~Area3D() {
+}
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
new file mode 100644
index 0000000000..ff6c0b6b08
--- /dev/null
+++ b/scene/3d/area_3d.h
@@ -0,0 +1,217 @@
+/*************************************************************************/
+/* area_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 AREA_3D_H
+#define AREA_3D_H
+
+#include "core/vset.h"
+#include "scene/3d/collision_object_3d.h"
+
+class Area3D : public CollisionObject3D {
+
+ GDCLASS(Area3D, CollisionObject3D);
+
+public:
+ enum SpaceOverride {
+ SPACE_OVERRIDE_DISABLED,
+ SPACE_OVERRIDE_COMBINE,
+ SPACE_OVERRIDE_COMBINE_REPLACE,
+ SPACE_OVERRIDE_REPLACE,
+ SPACE_OVERRIDE_REPLACE_COMBINE
+ };
+
+private:
+ SpaceOverride space_override;
+ Vector3 gravity_vec;
+ real_t gravity;
+ bool gravity_is_point;
+ real_t gravity_distance_scale;
+ real_t angular_damp;
+ real_t linear_damp;
+ uint32_t collision_mask;
+ uint32_t collision_layer;
+ int priority;
+ bool monitoring;
+ bool monitorable;
+ bool locked;
+
+ void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape);
+
+ void _body_enter_tree(ObjectID p_id);
+ void _body_exit_tree(ObjectID p_id);
+
+ struct ShapePair {
+
+ int body_shape;
+ int area_shape;
+ bool operator<(const ShapePair &p_sp) const {
+ if (body_shape == p_sp.body_shape)
+ return area_shape < p_sp.area_shape;
+ else
+ return body_shape < p_sp.body_shape;
+ }
+
+ ShapePair() {}
+ ShapePair(int p_bs, int p_as) {
+ body_shape = p_bs;
+ area_shape = p_as;
+ }
+ };
+
+ struct BodyState {
+
+ int rc;
+ bool in_tree;
+ VSet<ShapePair> shapes;
+ };
+
+ Map<ObjectID, BodyState> body_map;
+
+ void _area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape);
+
+ void _area_enter_tree(ObjectID p_id);
+ void _area_exit_tree(ObjectID p_id);
+
+ struct AreaShapePair {
+
+ int area_shape;
+ int self_shape;
+ bool operator<(const AreaShapePair &p_sp) const {
+ if (area_shape == p_sp.area_shape)
+ return self_shape < p_sp.self_shape;
+ else
+ return area_shape < p_sp.area_shape;
+ }
+
+ AreaShapePair() {}
+ AreaShapePair(int p_bs, int p_as) {
+ area_shape = p_bs;
+ self_shape = p_as;
+ }
+ };
+
+ struct AreaState {
+
+ int rc;
+ bool in_tree;
+ VSet<AreaShapePair> shapes;
+ };
+
+ Map<ObjectID, AreaState> area_map;
+ void _clear_monitoring();
+
+ bool audio_bus_override;
+ StringName audio_bus;
+
+ bool use_reverb_bus;
+ StringName reverb_bus;
+ float reverb_amount;
+ float reverb_uniformity;
+
+ void _validate_property(PropertyInfo &property) const;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_space_override_mode(SpaceOverride p_mode);
+ SpaceOverride get_space_override_mode() const;
+
+ void set_gravity_is_point(bool p_enabled);
+ bool is_gravity_a_point() const;
+
+ void set_gravity_distance_scale(real_t p_scale);
+ real_t get_gravity_distance_scale() const;
+
+ void set_gravity_vector(const Vector3 &p_vec);
+ Vector3 get_gravity_vector() const;
+
+ void set_gravity(real_t p_gravity);
+ real_t get_gravity() const;
+
+ void set_angular_damp(real_t p_angular_damp);
+ real_t get_angular_damp() const;
+
+ void set_linear_damp(real_t p_linear_damp);
+ real_t get_linear_damp() const;
+
+ void set_priority(real_t p_priority);
+ real_t get_priority() const;
+
+ void set_monitoring(bool p_enable);
+ bool is_monitoring() const;
+
+ 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;
+
+ Array get_overlapping_bodies() const;
+ Array get_overlapping_areas() const; //function for script
+
+ bool overlaps_area(Node *p_area) const;
+ bool overlaps_body(Node *p_body) const;
+
+ void set_audio_bus_override(bool p_override);
+ bool is_overriding_audio_bus() const;
+
+ void set_audio_bus(const StringName &p_audio_bus);
+ StringName get_audio_bus() const;
+
+ void set_use_reverb_bus(bool p_enable);
+ bool is_using_reverb_bus() const;
+
+ void set_reverb_bus(const StringName &p_audio_bus);
+ StringName get_reverb_bus() const;
+
+ void set_reverb_amount(float p_amount);
+ float get_reverb_amount() const;
+
+ void set_reverb_uniformity(float p_uniformity);
+ float get_reverb_uniformity() const;
+
+ Area3D();
+ ~Area3D();
+};
+
+VARIANT_ENUM_CAST(Area3D::SpaceOverride);
+
+#endif // AREA__H
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
deleted file mode 100644
index d23e5ffa08..0000000000
--- a/scene/3d/arvr_nodes.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*************************************************************************/
-/* arvr_nodes.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "arvr_nodes.h"
-#include "core/os/input.h"
-#include "servers/arvr/arvr_interface.h"
-#include "servers/arvr_server.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ARVRCamera::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- // need to find our ARVROrigin parent and let it know we're its camera!
- ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
- if (origin != NULL) {
- origin->set_tracked_camera(this);
- }
- }; break;
- case NOTIFICATION_EXIT_TREE: {
- // need to find our ARVROrigin parent and let it know we're no longer its camera!
- ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
- if (origin != NULL) {
- origin->clear_tracked_camera_if(this);
- }
- }; break;
- };
-};
-
-String ARVRCamera::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree())
- return String();
-
- // must be child node of ARVROrigin!
- ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
- if (origin == NULL) {
- return TTR("ARVRCamera must have an ARVROrigin node as its parent.");
- };
-
- return String();
-};
-
-Vector3 ARVRCamera::project_local_ray_normal(const Point2 &p_pos) const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, Vector3());
-
- Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- if (arvr_interface.is_null()) {
- // we might be in the editor or have VR turned off, just call superclass
- return Camera::project_local_ray_normal(p_pos);
- }
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_camera_rect_size();
- Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
- Vector3 ray;
-
- CameraMatrix cm = arvr_interface->get_projection_for_eye(ARVRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
- Vector2 screen_he = cm.get_viewport_half_extents();
- ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_znear()).normalized();
-
- return ray;
-};
-
-Point2 ARVRCamera::unproject_position(const Vector3 &p_pos) const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, Vector2());
-
- Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- if (arvr_interface.is_null()) {
- // we might be in the editor or have VR turned off, just call superclass
- return Camera::unproject_position(p_pos);
- }
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector2(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
-
- CameraMatrix cm = arvr_interface->get_projection_for_eye(ARVRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
-
- Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
-
- p = cm.xform4(p);
- p.normal /= p.d;
-
- Point2 res;
- res.x = (p.normal.x * 0.5 + 0.5) * viewport_size.x;
- res.y = (-p.normal.y * 0.5 + 0.5) * viewport_size.y;
-
- return res;
-};
-
-Vector3 ARVRCamera::project_position(const Point2 &p_point, float p_z_depth) const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, Vector3());
-
- Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- if (arvr_interface.is_null()) {
- // we might be in the editor or have VR turned off, just call superclass
- return Camera::project_position(p_point, p_z_depth);
- }
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
-
- CameraMatrix cm = arvr_interface->get_projection_for_eye(ARVRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
-
- Vector2 vp_he = cm.get_viewport_half_extents();
-
- Vector2 point;
- point.x = (p_point.x / viewport_size.x) * 2.0 - 1.0;
- point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
- point *= vp_he;
-
- Vector3 p(point.x, point.y, -p_z_depth);
-
- return get_camera_transform().xform(p);
-};
-
-Vector<Plane> ARVRCamera::get_frustum() const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, Vector<Plane>());
-
- Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- if (arvr_interface.is_null()) {
- // we might be in the editor or have VR turned off, just call superclass
- return Camera::get_frustum();
- }
-
- ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
-
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm = arvr_interface->get_projection_for_eye(ARVRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
- return cm.get_projection_planes(get_camera_transform());
-};
-
-ARVRCamera::ARVRCamera(){
- // nothing to do here yet for now..
-};
-
-ARVRCamera::~ARVRCamera(){
- // nothing to do here yet for now..
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ARVRController::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
- }; break;
- case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- }; break;
- case NOTIFICATION_INTERNAL_PROCESS: {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- // find the tracker for our controller
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == NULL) {
- // this controller is currently turned off
- is_active = false;
- button_states = 0;
- } else {
- is_active = true;
- set_transform(tracker->get_transform(true));
-
- int joy_id = tracker->get_joy_id();
- if (joy_id >= 0) {
- int mask = 1;
- // check button states
- for (int i = 0; i < 16; i++) {
- bool was_pressed = (button_states & mask) == mask;
- bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, i);
-
- if (!was_pressed && is_pressed) {
- emit_signal("button_pressed", i);
- button_states += mask;
- } else if (was_pressed && !is_pressed) {
- emit_signal("button_release", i);
- button_states -= mask;
- };
-
- mask = mask << 1;
- };
-
- } else {
- button_states = 0;
- };
-
- // check for an updated mesh
- Ref<Mesh> trackerMesh = tracker->get_mesh();
- if (mesh != trackerMesh) {
- mesh = trackerMesh;
- emit_signal("mesh_updated", mesh);
- }
- };
- }; break;
- default:
- break;
- };
-};
-
-void ARVRController::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &ARVRController::set_controller_id);
- ClassDB::bind_method(D_METHOD("get_controller_id"), &ARVRController::get_controller_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id");
- ClassDB::bind_method(D_METHOD("get_controller_name"), &ARVRController::get_controller_name);
-
- // passthroughs to information about our related joystick
- ClassDB::bind_method(D_METHOD("get_joystick_id"), &ARVRController::get_joystick_id);
- ClassDB::bind_method(D_METHOD("is_button_pressed", "button"), &ARVRController::is_button_pressed);
- ClassDB::bind_method(D_METHOD("get_joystick_axis", "axis"), &ARVRController::get_joystick_axis);
-
- ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRController::get_is_active);
- ClassDB::bind_method(D_METHOD("get_hand"), &ARVRController::get_hand);
-
- ClassDB::bind_method(D_METHOD("get_rumble"), &ARVRController::get_rumble);
- ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRController::set_rumble);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
- ADD_PROPERTY_DEFAULT("rumble", 0.0);
-
- ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRController::get_mesh);
-
- ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
- ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button")));
- ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
-};
-
-void ARVRController::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();
-};
-
-int ARVRController::get_controller_id(void) const {
- return controller_id;
-};
-
-String ARVRController::get_controller_name(void) const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, String());
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == NULL) {
- return String("Not connected");
- };
-
- return tracker->get_name();
-};
-
-int ARVRController::get_joystick_id() const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, 0);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == NULL) {
- // No tracker? no joystick id... (0 is our first joystick)
- return -1;
- };
-
- return tracker->get_joy_id();
-};
-
-bool ARVRController::is_button_pressed(int p_button) const {
- int joy_id = get_joystick_id();
- if (joy_id == -1) {
- return false;
- };
-
- return Input::get_singleton()->is_joy_button_pressed(joy_id, p_button);
-};
-
-float ARVRController::get_joystick_axis(int p_axis) const {
- int joy_id = get_joystick_id();
- if (joy_id == -1) {
- return 0.0;
- };
-
- return Input::get_singleton()->get_joy_axis(joy_id, p_axis);
-};
-
-real_t ARVRController::get_rumble() const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, 0.0);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == NULL) {
- return 0.0;
- };
-
- return tracker->get_rumble();
-};
-
-void ARVRController::set_rumble(real_t p_rumble) {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker != NULL) {
- tracker->set_rumble(p_rumble);
- };
-};
-
-Ref<Mesh> ARVRController::get_mesh() const {
- return mesh;
-}
-
-bool ARVRController::get_is_active() const {
- return is_active;
-};
-
-ARVRPositionalTracker::TrackerHand ARVRController::get_hand() const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, ARVRPositionalTracker::TRACKER_HAND_UNKNOWN);
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == NULL) {
- return ARVRPositionalTracker::TRACKER_HAND_UNKNOWN;
- };
-
- return tracker->get_hand();
-};
-
-String ARVRController::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree())
- return String();
-
- // must be child node of ARVROrigin!
- ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
- if (origin == NULL) {
- return TTR("ARVRController must have an ARVROrigin node as its parent.");
- };
-
- if (controller_id == 0) {
- return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
- };
-
- return String();
-};
-
-ARVRController::ARVRController() {
- controller_id = 1;
- is_active = true;
- button_states = 0;
-};
-
-ARVRController::~ARVRController(){
- // nothing to do here yet for now..
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void ARVRAnchor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
- }; break;
- case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- }; break;
- case NOTIFICATION_INTERNAL_PROCESS: {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- // find the tracker for our anchor
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_ANCHOR, anchor_id);
- if (tracker == NULL) {
- // this anchor is currently not available
- is_active = false;
- } else {
- is_active = true;
- Transform transform;
-
- // we'll need our world_scale
- real_t world_scale = arvr_server->get_world_scale();
-
- // get our info from our tracker
- transform.basis = tracker->get_orientation();
- transform.origin = tracker->get_position(); // <-- already adjusted to world scale
-
- // our basis is scaled to the size of the plane the anchor is tracking
- // extract the size from our basis and reset the scale
- size = transform.basis.get_scale() * world_scale;
- transform.basis.orthonormalize();
-
- // apply our reference frame and set our transform
- set_transform(arvr_server->get_reference_frame() * transform);
-
- // check for an updated mesh
- Ref<Mesh> trackerMesh = tracker->get_mesh();
- if (mesh != trackerMesh) {
- mesh = trackerMesh;
- emit_signal("mesh_updated", mesh);
- }
- };
- }; break;
- default:
- break;
- };
-};
-
-void ARVRAnchor::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &ARVRAnchor::set_anchor_id);
- ClassDB::bind_method(D_METHOD("get_anchor_id"), &ARVRAnchor::get_anchor_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id");
- ClassDB::bind_method(D_METHOD("get_anchor_name"), &ARVRAnchor::get_anchor_name);
-
- ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRAnchor::get_is_active);
- ClassDB::bind_method(D_METHOD("get_size"), &ARVRAnchor::get_size);
-
- ClassDB::bind_method(D_METHOD("get_plane"), &ARVRAnchor::get_plane);
-
- ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRAnchor::get_mesh);
- ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
-};
-
-void ARVRAnchor::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();
-};
-
-int ARVRAnchor::get_anchor_id(void) const {
- return anchor_id;
-};
-
-Vector3 ARVRAnchor::get_size() const {
- return size;
-};
-
-String ARVRAnchor::get_anchor_name(void) const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, String());
-
- ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_ANCHOR, anchor_id);
- if (tracker == NULL) {
- return String("Not connected");
- };
-
- return tracker->get_name();
-};
-
-bool ARVRAnchor::get_is_active() const {
- return is_active;
-};
-
-String ARVRAnchor::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree())
- return String();
-
- // must be child node of ARVROrigin!
- ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
- if (origin == NULL) {
- return TTR("ARVRAnchor must have an ARVROrigin node as its parent.");
- };
-
- if (anchor_id == 0) {
- return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
- };
-
- return String();
-};
-
-Plane ARVRAnchor::get_plane() const {
- Vector3 location = get_translation();
- Basis orientation = get_transform().basis;
-
- Plane plane(location, orientation.get_axis(1).normalized());
-
- return plane;
-};
-
-Ref<Mesh> ARVRAnchor::get_mesh() const {
- return mesh;
-}
-
-ARVRAnchor::ARVRAnchor() {
- anchor_id = 1;
- is_active = true;
-};
-
-ARVRAnchor::~ARVRAnchor(){
- // nothing to do here yet for now..
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-String ARVROrigin::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree())
- return String();
-
- if (tracked_camera == NULL)
- return TTR("ARVROrigin requires an ARVRCamera child node.");
-
- return String();
-};
-
-void ARVROrigin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &ARVROrigin::set_world_scale);
- ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVROrigin::get_world_scale);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
-};
-
-void ARVROrigin::set_tracked_camera(ARVRCamera *p_tracked_camera) {
- tracked_camera = p_tracked_camera;
-};
-
-void ARVROrigin::clear_tracked_camera_if(ARVRCamera *p_tracked_camera) {
- if (tracked_camera == p_tracked_camera) {
- tracked_camera = NULL;
- };
-};
-
-float ARVROrigin::get_world_scale() const {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, 1.0);
-
- return arvr_server->get_world_scale();
-};
-
-void ARVROrigin::set_world_scale(float p_world_scale) {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- arvr_server->set_world_scale(p_world_scale);
-};
-
-void ARVROrigin::_notification(int p_what) {
- // get our ARVRServer
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
- }; break;
- case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- }; break;
- case NOTIFICATION_INTERNAL_PROCESS: {
- // set our world origin to our node transform
- arvr_server->set_world_origin(get_global_transform());
-
- // check if we have a primary interface
- Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface();
- if (arvr_interface.is_valid() && tracked_camera != NULL) {
- // get our positioning transform for our headset
- Transform t = arvr_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, Transform());
-
- // now apply this to our camera
- tracked_camera->set_transform(t);
- };
- }; break;
- default:
- break;
- };
-
- // send our notification to all active ARVR interfaces, they may need to react to it also
- for (int i = 0; i < arvr_server->get_interface_count(); i++) {
- Ref<ARVRInterface> interface = arvr_server->get_interface(i);
- if (interface.is_valid() && interface->is_initialized()) {
- interface->notification(p_what);
- }
- }
-};
-
-ARVROrigin::ARVROrigin() {
- tracked_camera = NULL;
-};
-
-ARVROrigin::~ARVROrigin(){
- // nothing to do here yet for now..
-};
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
deleted file mode 100644
index e968e33c9d..0000000000
--- a/scene/3d/arvr_nodes.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*************************************************************************/
-/* arvr_nodes.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 ARVR_NODES_H
-#define ARVR_NODES_H
-
-#include "scene/3d/camera.h"
-#include "scene/3d/spatial.h"
-#include "scene/resources/mesh.h"
-#include "servers/arvr/arvr_positional_tracker.h"
-
-/**
- @author Bastiaan Olij <mux213@gmail.com>
-**/
-
-/*
- ARVRCamera is a subclass of camera which will register itself with its parent ARVROrigin and as a result is automatically positioned
-*/
-class ARVRCamera : public Camera {
-
- GDCLASS(ARVRCamera, Camera);
-
-protected:
- void _notification(int p_what);
-
-public:
- String get_configuration_warning() const;
-
- virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
- virtual Point2 unproject_position(const Vector3 &p_pos) const;
- virtual Vector3 project_position(const Point2 &p_point, float p_z_depth) const;
- virtual Vector<Plane> get_frustum() const;
-
- ARVRCamera();
- ~ARVRCamera();
-};
-
-/*
- ARVRController is a helper node that automatically updates its position based on tracker data.
-
- It must be a child node of our ARVROrigin node
-*/
-
-class ARVRController : public Spatial {
-
- GDCLASS(ARVRController, Spatial);
-
-private:
- int controller_id;
- bool is_active;
- int button_states;
- Ref<Mesh> mesh;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_controller_id(int p_controller_id);
- int get_controller_id(void) const;
- String get_controller_name(void) const;
-
- int get_joystick_id() const;
- bool is_button_pressed(int p_button) const;
- float get_joystick_axis(int p_axis) const;
-
- real_t get_rumble() const;
- void set_rumble(real_t p_rumble);
-
- bool get_is_active() const;
- ARVRPositionalTracker::TrackerHand get_hand() const;
-
- Ref<Mesh> get_mesh(void) const;
-
- String get_configuration_warning() const;
-
- ARVRController();
- ~ARVRController();
-};
-
-/*
- ARVRAnchor is a helper node that automatically updates its position based on anchor data, it represents a real world location.
- It must be a child node of our ARVROrigin node
-*/
-
-class ARVRAnchor : public Spatial {
- GDCLASS(ARVRAnchor, Spatial);
-
-private:
- int anchor_id;
- bool is_active;
- Vector3 size;
- Ref<Mesh> mesh;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_anchor_id(int p_anchor_id);
- int get_anchor_id(void) const;
- String get_anchor_name(void) const;
-
- bool get_is_active() const;
- Vector3 get_size() const;
-
- Plane get_plane() const;
-
- Ref<Mesh> get_mesh(void) const;
-
- String get_configuration_warning() const;
-
- ARVRAnchor();
- ~ARVRAnchor();
-};
-
-/*
- ARVROrigin is special spatial node that acts as our origin point mapping our real world center of our tracking volume into our virtual world.
-
- It is this point that you will move around the world as the player 'moves while standing still', i.e. the player moves through teleporting or controller inputs as opposed to physically moving.
-
- Our camera and controllers will always be child nodes and thus place relative to this origin point.
- This node will automatically locate any camera child nodes and update its position while our ARVRController node will handle tracked controllers.
-*/
-class ARVROrigin : public Spatial {
-
- GDCLASS(ARVROrigin, Spatial);
-
-private:
- ARVRCamera *tracked_camera;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- String get_configuration_warning() const;
-
- void set_tracked_camera(ARVRCamera *p_tracked_camera);
- void clear_tracked_camera_if(ARVRCamera *p_tracked_camera);
-
- float get_world_scale() const;
- void set_world_scale(float p_world_scale);
-
- ARVROrigin();
- ~ARVROrigin();
-};
-
-#endif /* ARVR_NODES_H */
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 855d254bd6..097368853e 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -29,11 +29,12 @@
/*************************************************************************/
#include "audio_stream_player_3d.h"
+
#include "core/engine.h"
-#include "scene/3d/area.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/listener.h"
-#include "scene/main/viewport.h"
+#include "scene/3d/area_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/listener_3d.h"
+#include "scene/main/window.h"
// Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004)
// Speaker-Placement Correction Amplitude Panning (SPCAP)
@@ -96,7 +97,7 @@ static const Vector3 speaker_directions[7] = {
};
void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, AudioStreamPlayer3D::Output &output) {
- unsigned int speaker_count; // only main speakers (no LFE)
+ unsigned int speaker_count = 0; // only main speakers (no LFE)
switch (AudioServer::get_singleton()->get_speaker_mode()) {
case AudioServer::SPEAKER_MODE_STEREO:
speaker_count = 2;
@@ -213,7 +214,7 @@ void AudioStreamPlayer3D::_mix_audio() {
AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k];
AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k];
AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k];
+ AudioFrame vol = vol_prev;
if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k))
continue; //may have been deleted, will be updated on process
@@ -384,7 +385,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
linear_velocity = velocity_tracker->get_tracked_linear_velocity();
}
- Ref<World> world = get_world();
+ Ref<World3D> world = get_world();
ERR_FAIL_COND(world.is_null());
int new_output_count = 0;
@@ -395,18 +396,18 @@ void AudioStreamPlayer3D::_notification(int p_what) {
//check if any area is diverting sound into a bus
- PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(world->get_space());
+ PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world->get_space());
- PhysicsDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS];
+ PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- Area *area = NULL;
+ Area3D *area = nullptr;
for (int i = 0; i < areas; i++) {
if (!sr[i].collider)
continue;
- Area *tarea = Object::cast_to<Area>(sr[i].collider);
+ Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
if (!tarea)
continue;
@@ -417,20 +418,20 @@ void AudioStreamPlayer3D::_notification(int p_what) {
break;
}
- List<Camera *> cameras;
+ List<Camera3D *> cameras;
world->get_camera_list(&cameras);
- for (List<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
+ for (List<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
- Camera *camera = E->get();
+ Camera3D *camera = E->get();
Viewport *vp = camera->get_viewport();
if (!vp->is_audio_listener())
continue;
bool listener_is_camera = true;
- Spatial *listener_node = camera;
+ Node3D *listener_node = camera;
- Listener *listener = vp->get_listener();
+ Listener3D *listener = vp->get_listener();
if (listener) {
listener_node = listener;
listener_is_camera = false;
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 5b4c865475..13e08339e2 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -31,16 +31,16 @@
#ifndef AUDIO_STREAM_PLAYER_3D_H
#define AUDIO_STREAM_PLAYER_3D_H
-#include "scene/3d/spatial.h"
-#include "scene/3d/spatial_velocity_tracker.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/velocity_tracker_3d.h"
#include "servers/audio/audio_filter_sw.h"
#include "servers/audio/audio_stream.h"
#include "servers/audio_server.h"
-class Camera;
-class AudioStreamPlayer3D : public Spatial {
+class Camera3D;
+class AudioStreamPlayer3D : public Node3D {
- GDCLASS(AudioStreamPlayer3D, Spatial);
+ GDCLASS(AudioStreamPlayer3D, Node3D);
public:
enum AttenuationModel {
@@ -82,7 +82,7 @@ private:
Output() {
filter_gain = 0;
- viewport = NULL;
+ viewport = nullptr;
reverb_bus_index = -1;
bus_index = -1;
}
@@ -134,7 +134,7 @@ private:
float max_distance;
- Ref<SpatialVelocityTracker> velocity_tracker;
+ Ref<VelocityTracker3D> velocity_tracker;
DopplerTracking doppler_tracking;
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 73b1d450f0..6bde56104e 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -39,7 +39,7 @@
void BakedLightmapData::set_bounds(const AABB &p_bounds) {
bounds = p_bounds;
- VS::get_singleton()->lightmap_capture_set_bounds(baked_light, p_bounds);
+ RS::get_singleton()->lightmap_capture_set_bounds(baked_light, p_bounds);
}
AABB BakedLightmapData::get_bounds() const {
@@ -49,18 +49,18 @@ AABB BakedLightmapData::get_bounds() const {
void BakedLightmapData::set_octree(const Vector<uint8_t> &p_octree) {
- VS::get_singleton()->lightmap_capture_set_octree(baked_light, p_octree);
+ RS::get_singleton()->lightmap_capture_set_octree(baked_light, p_octree);
}
Vector<uint8_t> BakedLightmapData::get_octree() const {
- return VS::get_singleton()->lightmap_capture_get_octree(baked_light);
+ return RS::get_singleton()->lightmap_capture_get_octree(baked_light);
}
void BakedLightmapData::set_cell_space_transform(const Transform &p_xform) {
cell_space_xform = p_xform;
- VS::get_singleton()->lightmap_capture_set_octree_cell_transform(baked_light, p_xform);
+ RS::get_singleton()->lightmap_capture_set_octree_cell_transform(baked_light, p_xform);
}
Transform BakedLightmapData::get_cell_space_transform() const {
@@ -69,7 +69,7 @@ Transform BakedLightmapData::get_cell_space_transform() const {
void BakedLightmapData::set_cell_subdiv(int p_cell_subdiv) {
cell_subdiv = p_cell_subdiv;
- VS::get_singleton()->lightmap_capture_set_octree_cell_subdiv(baked_light, p_cell_subdiv);
+ RS::get_singleton()->lightmap_capture_set_octree_cell_subdiv(baked_light, p_cell_subdiv);
}
int BakedLightmapData::get_cell_subdiv() const {
@@ -79,7 +79,7 @@ int BakedLightmapData::get_cell_subdiv() const {
void BakedLightmapData::set_energy(float p_energy) {
energy = p_energy;
- VS::get_singleton()->lightmap_capture_set_energy(baked_light, energy);
+ RS::get_singleton()->lightmap_capture_set_energy(baked_light, energy);
}
float BakedLightmapData::get_energy() const {
@@ -181,21 +181,21 @@ void BakedLightmapData::_bind_methods() {
BakedLightmapData::BakedLightmapData() {
- baked_light = VS::get_singleton()->lightmap_capture_create();
+ baked_light = RS::get_singleton()->lightmap_capture_create();
energy = 1;
cell_subdiv = 1;
}
BakedLightmapData::~BakedLightmapData() {
- VS::get_singleton()->free(baked_light);
+ RS::get_singleton()->free(baked_light);
}
///////////////////////////
-BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = NULL;
-BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = NULL;
-BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = NULL;
+BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = nullptr;
+BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = nullptr;
+BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = nullptr;
void BakedLightmap::set_bake_cell_size(float p_cell_size) {
bake_cell_size = p_cell_size;
@@ -425,13 +425,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
pmc++;
PlotLight pl = E->get();
switch (pl.light->get_light_type()) {
- case VS::LIGHT_DIRECTIONAL: {
+ case RS::LIGHT_DIRECTIONAL: {
baker.plot_light_directional(-pl.local_xform.basis.get_axis(2), pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_bake_mode() == Light::BAKE_ALL);
} break;
- case VS::LIGHT_OMNI: {
+ case RS::LIGHT_OMNI: {
baker.plot_light_omni(pl.local_xform.origin, pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_param(Light::PARAM_RANGE), pl.light->get_param(Light::PARAM_ATTENUATION), pl.light->get_bake_mode() == Light::BAKE_ALL);
} break;
- case VS::LIGHT_SPOT: {
+ case RS::LIGHT_SPOT: {
baker.plot_light_spot(pl.local_xform.origin, pl.local_xform.basis.get_axis(2), pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_param(Light::PARAM_RANGE), pl.light->get_param(Light::PARAM_ATTENUATION), pl.light->get_param(Light::PARAM_SPOT_ANGLE), pl.light->get_param(Light::PARAM_SPOT_ATTENUATION), pl.light->get_bake_mode() == Light::BAKE_ALL);
} break;
@@ -675,12 +675,12 @@ void BakedLightmap::_assign_lightmaps() {
if (instance_idx >= 0) {
RID instance = node->call("get_bake_mesh_instance", instance_idx);
if (instance.is_valid()) {
- VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), lightmap->get_rid());
+ RS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), lightmap->get_rid());
}
} else {
VisualInstance *vi = Object::cast_to<VisualInstance>(node);
ERR_CONTINUE(!vi);
- VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
+ RS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
}
}
}
@@ -693,12 +693,12 @@ void BakedLightmap::_clear_lightmaps() {
if (instance_idx >= 0) {
RID instance = node->call("get_bake_mesh_instance", instance_idx);
if (instance.is_valid()) {
- VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), RID());
+ RS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), RID());
}
} else {
VisualInstance *vi = Object::cast_to<VisualInstance>(node);
ERR_CONTINUE(!vi);
- VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), RID());
+ RS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), RID());
}
}
}
diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp
deleted file mode 100644
index b1cd9bfe8b..0000000000
--- a/scene/3d/bone_attachment.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*************************************************************************/
-/* bone_attachment.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "bone_attachment.h"
-
-void BoneAttachment::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "bone_name") {
- Skeleton *parent = Object::cast_to<Skeleton>(get_parent());
-
- if (parent) {
-
- String names;
- for (int i = 0; i < parent->get_bone_count(); i++) {
- if (i > 0)
- names += ",";
- names += parent->get_bone_name(i);
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = names;
- } else {
-
- property.hint = PROPERTY_HINT_NONE;
- property.hint_string = "";
- }
- }
-}
-
-void BoneAttachment::_check_bind() {
-
- Skeleton *sk = Object::cast_to<Skeleton>(get_parent());
- if (sk) {
-
- int idx = sk->find_bone(bone_name);
- if (idx != -1) {
- sk->bind_child_node_to_bone(idx, this);
- set_transform(sk->get_bone_global_pose(idx));
- bound = true;
- }
- }
-}
-
-void BoneAttachment::_check_unbind() {
-
- if (bound) {
-
- Skeleton *sk = Object::cast_to<Skeleton>(get_parent());
- if (sk) {
-
- int idx = sk->find_bone(bone_name);
- if (idx != -1) {
- sk->unbind_child_node_from_bone(idx, this);
- }
- }
- bound = false;
- }
-}
-
-void BoneAttachment::set_bone_name(const String &p_name) {
-
- if (is_inside_tree())
- _check_unbind();
-
- bone_name = p_name;
-
- if (is_inside_tree())
- _check_bind();
-}
-
-String BoneAttachment::get_bone_name() const {
-
- return bone_name;
-}
-
-void BoneAttachment::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- _check_bind();
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- _check_unbind();
- } break;
- }
-}
-
-BoneAttachment::BoneAttachment() {
- bound = false;
-}
-
-void BoneAttachment::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &BoneAttachment::set_bone_name);
- ClassDB::bind_method(D_METHOD("get_bone_name"), &BoneAttachment::get_bone_name);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
-}
diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h
deleted file mode 100644
index 43c46dd759..0000000000
--- a/scene/3d/bone_attachment.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*************************************************************************/
-/* bone_attachment.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BONE_ATTACHMENT_H
-#define BONE_ATTACHMENT_H
-
-#include "scene/3d/skeleton.h"
-
-class BoneAttachment : public Spatial {
-
- GDCLASS(BoneAttachment, Spatial);
-
- bool bound;
- String bone_name;
-
- void _check_bind();
- void _check_unbind();
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const;
- void _notification(int p_what);
-
- static void _bind_methods();
-
-public:
- void set_bone_name(const String &p_name);
- String get_bone_name() const;
-
- BoneAttachment();
-};
-
-#endif // BONE_ATTACHMENT_H
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
new file mode 100644
index 0000000000..825cb39e2d
--- /dev/null
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* bone_attachment_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "bone_attachment_3d.h"
+
+void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "bone_name") {
+ Skeleton3D *parent = Object::cast_to<Skeleton3D>(get_parent());
+
+ if (parent) {
+
+ String names;
+ for (int i = 0; i < parent->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += parent->get_bone_name(i);
+ }
+
+ property.hint = PROPERTY_HINT_ENUM;
+ property.hint_string = names;
+ } else {
+
+ property.hint = PROPERTY_HINT_NONE;
+ property.hint_string = "";
+ }
+ }
+}
+
+void BoneAttachment3D::_check_bind() {
+
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(get_parent());
+ if (sk) {
+
+ int idx = sk->find_bone(bone_name);
+ if (idx != -1) {
+ sk->bind_child_node_to_bone(idx, this);
+ set_transform(sk->get_bone_global_pose(idx));
+ bound = true;
+ }
+ }
+}
+
+void BoneAttachment3D::_check_unbind() {
+
+ if (bound) {
+
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(get_parent());
+ if (sk) {
+
+ int idx = sk->find_bone(bone_name);
+ if (idx != -1) {
+ sk->unbind_child_node_from_bone(idx, this);
+ }
+ }
+ bound = false;
+ }
+}
+
+void BoneAttachment3D::set_bone_name(const String &p_name) {
+
+ if (is_inside_tree())
+ _check_unbind();
+
+ bone_name = p_name;
+
+ if (is_inside_tree())
+ _check_bind();
+}
+
+String BoneAttachment3D::get_bone_name() const {
+
+ return bone_name;
+}
+
+void BoneAttachment3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ _check_bind();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ _check_unbind();
+ } break;
+ }
+}
+
+BoneAttachment3D::BoneAttachment3D() {
+ bound = false;
+}
+
+void BoneAttachment3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &BoneAttachment3D::set_bone_name);
+ ClassDB::bind_method(D_METHOD("get_bone_name"), &BoneAttachment3D::get_bone_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
+}
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
new file mode 100644
index 0000000000..d2a3ffec90
--- /dev/null
+++ b/scene/3d/bone_attachment_3d.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* bone_attachment_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BONE_ATTACHMENT_H
+#define BONE_ATTACHMENT_H
+
+#include "scene/3d/skeleton_3d.h"
+
+class BoneAttachment3D : public Node3D {
+
+ GDCLASS(BoneAttachment3D, Node3D);
+
+ bool bound;
+ String bone_name;
+
+ void _check_bind();
+ void _check_unbind();
+
+protected:
+ virtual void _validate_property(PropertyInfo &property) const;
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ void set_bone_name(const String &p_name);
+ String get_bone_name() const;
+
+ BoneAttachment3D();
+};
+
+#endif // BONE_ATTACHMENT_H
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
deleted file mode 100644
index 741712025c..0000000000
--- a/scene/3d/camera.cpp
+++ /dev/null
@@ -1,954 +0,0 @@
-/*************************************************************************/
-/* camera.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "camera.h"
-
-#include "collision_object.h"
-#include "core/engine.h"
-#include "core/math/camera_matrix.h"
-#include "scene/resources/material.h"
-#include "scene/resources/surface_tool.h"
-void Camera::_update_audio_listener_state() {
-}
-
-void Camera::_request_camera_update() {
-
- _update_camera();
-}
-
-void Camera::_update_camera_mode() {
-
- force_change = true;
- switch (mode) {
- case PROJECTION_PERSPECTIVE: {
-
- set_perspective(fov, near, far);
-
- } break;
- case PROJECTION_ORTHOGONAL: {
- set_orthogonal(size, near, far);
- } break;
- case PROJECTION_FRUSTUM: {
- set_frustum(size, frustum_offset, near, far);
- } break;
- }
-}
-
-void Camera::_validate_property(PropertyInfo &p_property) const {
- if (p_property.name == "fov") {
- if (mode != PROJECTION_PERSPECTIVE) {
- p_property.usage = PROPERTY_USAGE_NOEDITOR;
- }
- } else if (p_property.name == "size") {
- if (mode != PROJECTION_ORTHOGONAL && mode != PROJECTION_FRUSTUM) {
- p_property.usage = PROPERTY_USAGE_NOEDITOR;
- }
- } else if (p_property.name == "frustum_offset") {
- if (mode != PROJECTION_FRUSTUM) {
- p_property.usage = PROPERTY_USAGE_NOEDITOR;
- }
- }
-}
-
-void Camera::_update_camera() {
-
- if (!is_inside_tree())
- return;
-
- VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
-
- // here goes listener stuff
- /*
- if (viewport_ptr && is_inside_scene() && is_current())
- get_viewport()->_camera_transform_changed_notify();
- */
-
- if (get_tree()->is_node_being_edited(this) || !is_current())
- return;
-
- get_viewport()->_camera_transform_changed_notify();
-
- if (get_world().is_valid()) {
- get_world()->_update_camera(this);
- }
-}
-
-void Camera::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_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();
- ERR_FAIL_COND(!viewport);
-
- bool first_camera = viewport->_camera_add(this);
- if (current || first_camera)
- viewport->_camera_set(this);
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- _request_camera_update();
- if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
- velocity_tracker->update_position(get_global_transform().origin);
- }
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- if (!get_tree()->is_node_being_edited(this)) {
- if (is_current()) {
- clear_current();
- current = true; //keep it true
-
- } else {
- current = false;
- }
- }
-
- if (viewport) {
- viewport->_camera_remove(this);
- viewport = NULL;
- }
-
- } break;
- case NOTIFICATION_BECAME_CURRENT: {
- if (viewport) {
- viewport->find_world()->_register_camera(this);
- }
- } break;
- case NOTIFICATION_LOST_CURRENT: {
- if (viewport) {
- viewport->find_world()->_remove_camera(this);
- }
- } break;
- }
-}
-
-Transform Camera::get_camera_transform() const {
-
- Transform tr = get_global_transform().orthonormalized();
- tr.origin += tr.basis.get_axis(1) * v_offset;
- tr.origin += tr.basis.get_axis(0) * h_offset;
- return tr;
-}
-
-void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
-
- if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE)
- return;
-
- fov = p_fovy_degrees;
- near = p_z_near;
- far = p_z_far;
- mode = PROJECTION_PERSPECTIVE;
-
- VisualServer::get_singleton()->camera_set_perspective(camera, fov, near, far);
- update_gizmo();
- force_change = false;
-}
-void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
-
- if (!force_change && size == p_size && p_z_near == near && p_z_far == far && mode == PROJECTION_ORTHOGONAL)
- return;
-
- size = p_size;
-
- near = p_z_near;
- far = p_z_far;
- mode = PROJECTION_ORTHOGONAL;
- force_change = false;
-
- VisualServer::get_singleton()->camera_set_orthogonal(camera, size, near, far);
- update_gizmo();
-}
-
-void Camera::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
- if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM)
- return;
-
- size = p_size;
- frustum_offset = p_offset;
-
- near = p_z_near;
- far = p_z_far;
- mode = PROJECTION_FRUSTUM;
- force_change = false;
-
- VisualServer::get_singleton()->camera_set_frustum(camera, size, frustum_offset, near, far);
- update_gizmo();
-}
-
-void Camera::set_projection(Camera::Projection p_mode) {
- if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) {
- mode = p_mode;
- _update_camera_mode();
- _change_notify();
- }
-}
-
-RID Camera::get_camera() const {
-
- return camera;
-};
-
-void Camera::make_current() {
-
- current = true;
-
- if (!is_inside_tree())
- return;
-
- get_viewport()->_camera_set(this);
-
- //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
-}
-
-void Camera::clear_current(bool p_enable_next) {
-
- current = false;
- if (!is_inside_tree())
- return;
-
- if (get_viewport()->get_camera() == this) {
- get_viewport()->_camera_set(NULL);
-
- if (p_enable_next) {
- get_viewport()->_camera_make_next_current(this);
- }
- }
-}
-
-void Camera::set_current(bool p_current) {
- if (p_current) {
- make_current();
- } else {
- clear_current();
- }
-}
-
-bool Camera::is_current() const {
-
- if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
-
- return get_viewport()->get_camera() == this;
- } else
- return current;
-}
-
-bool Camera::_can_gizmo_scale() const {
-
- return false;
-}
-
-Vector3 Camera::project_ray_normal(const Point2 &p_pos) const {
-
- Vector3 ray = project_local_ray_normal(p_pos);
- return get_camera_transform().basis.xform(ray).normalized();
-};
-
-Vector3 Camera::project_local_ray_normal(const Point2 &p_pos) const {
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_camera_rect_size();
- Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
- Vector3 ray;
-
- if (mode == PROJECTION_ORTHOGONAL) {
-
- ray = Vector3(0, 0, -1);
- } else {
- CameraMatrix cm;
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- Vector2 screen_he = cm.get_viewport_half_extents();
- ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -near).normalized();
- }
-
- return ray;
-};
-
-Vector3 Camera::project_ray_origin(const Point2 &p_pos) const {
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_camera_rect_size();
- Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
- ERR_FAIL_COND_V(viewport_size.y == 0, Vector3());
-
- if (mode == PROJECTION_PERSPECTIVE) {
-
- return get_camera_transform().origin;
- } else {
-
- Vector2 pos = cpos / viewport_size;
- float vsize, hsize;
- if (keep_aspect == KEEP_WIDTH) {
- vsize = size / viewport_size.aspect();
- hsize = size;
- } else {
- hsize = size * viewport_size.aspect();
- vsize = size;
- }
-
- Vector3 ray;
- ray.x = pos.x * (hsize)-hsize / 2;
- ray.y = (1.0 - pos.y) * (vsize)-vsize / 2;
- ray.z = -near;
- ray = get_camera_transform().xform(ray);
- return ray;
- };
-};
-
-bool Camera::is_position_behind(const Vector3 &p_pos) const {
-
- Transform t = get_global_transform();
- Vector3 eyedir = -get_global_transform().basis.get_axis(2).normalized();
- return eyedir.dot(p_pos) < (eyedir.dot(t.origin) + near);
-}
-
-Vector<Vector3> Camera::get_near_plane_points() const {
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector<Vector3>(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
-
- CameraMatrix cm;
-
- if (mode == PROJECTION_ORTHOGONAL)
- cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- else
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
-
- Vector3 endpoints[8];
- cm.get_endpoints(Transform(), endpoints);
-
- Vector<Vector3> points;
- points.push_back(Vector3());
- for (int i = 0; i < 4; i++) {
- points.push_back(endpoints[i + 4]);
- }
- return points;
-}
-
-Point2 Camera::unproject_position(const Vector3 &p_pos) const {
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector2(), "Camera is not inside scene.");
-
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
-
- CameraMatrix cm;
-
- if (mode == PROJECTION_ORTHOGONAL)
- cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- else
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
-
- Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
-
- p = cm.xform4(p);
- p.normal /= p.d;
-
- Point2 res;
- res.x = (p.normal.x * 0.5 + 0.5) * viewport_size.x;
- res.y = (-p.normal.y * 0.5 + 0.5) * viewport_size.y;
-
- return res;
-}
-
-Vector3 Camera::project_position(const Point2 &p_point, float p_z_depth) const {
-
- ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
-
- if (p_z_depth == 0 && mode != PROJECTION_ORTHOGONAL) {
- return get_global_transform().origin;
- }
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
-
- CameraMatrix cm;
-
- if (mode == PROJECTION_ORTHOGONAL)
- cm.set_orthogonal(size, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
- else
- cm.set_perspective(fov, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
-
- Vector2 vp_he = cm.get_viewport_half_extents();
-
- Vector2 point;
- point.x = (p_point.x / viewport_size.x) * 2.0 - 1.0;
- point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
- point *= vp_he;
-
- Vector3 p(point.x, point.y, -p_z_depth);
-
- return get_camera_transform().xform(p);
-}
-
-/*
-void Camera::_camera_make_current(Node *p_camera) {
-
-
- if (p_camera==this) {
- VisualServer::get_singleton()->viewport_attach_camera(viewport_id,camera);
- active=true;
- } else {
- if (active && p_camera==NULL) {
- //detech camera because no one else will claim it
- VisualServer::get_singleton()->viewport_attach_camera(viewport_id,RID());
- }
- active=false;
- }
-}
-*/
-
-void Camera::set_environment(const Ref<Environment> &p_environment) {
-
- environment = p_environment;
- if (environment.is_valid())
- VS::get_singleton()->camera_set_environment(camera, environment->get_rid());
- else
- VS::get_singleton()->camera_set_environment(camera, RID());
- _update_camera_mode();
-}
-
-Ref<Environment> Camera::get_environment() const {
-
- return environment;
-}
-
-void Camera::set_effects(const Ref<CameraEffects> &p_effects) {
-
- effects = p_effects;
- if (effects.is_valid())
- VS::get_singleton()->camera_set_camera_effects(camera, effects->get_rid());
- else
- VS::get_singleton()->camera_set_camera_effects(camera, RID());
- _update_camera_mode();
-}
-
-Ref<CameraEffects> Camera::get_effects() const {
-
- return effects;
-}
-
-void Camera::set_keep_aspect_mode(KeepAspect p_aspect) {
- keep_aspect = p_aspect;
- VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH);
- _update_camera_mode();
- _change_notify();
-}
-
-Camera::KeepAspect Camera::get_keep_aspect_mode() const {
-
- return keep_aspect;
-}
-
-void Camera::set_doppler_tracking(DopplerTracking p_tracking) {
-
- if (doppler_tracking == p_tracking)
- return;
-
- doppler_tracking = p_tracking;
- if (p_tracking != DOPPLER_TRACKING_DISABLED) {
- velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP);
- if (is_inside_tree()) {
- velocity_tracker->reset(get_global_transform().origin);
- }
- }
- _update_camera_mode();
-}
-
-Camera::DopplerTracking Camera::get_doppler_tracking() const {
- return doppler_tracking;
-}
-
-void Camera::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("project_ray_normal", "screen_point"), &Camera::project_ray_normal);
- ClassDB::bind_method(D_METHOD("project_local_ray_normal", "screen_point"), &Camera::project_local_ray_normal);
- ClassDB::bind_method(D_METHOD("project_ray_origin", "screen_point"), &Camera::project_ray_origin);
- ClassDB::bind_method(D_METHOD("unproject_position", "world_point"), &Camera::unproject_position);
- ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera::is_position_behind);
- ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera::project_position);
- ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective);
- ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
- ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera::set_frustum);
- ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current);
- ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current);
- ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current);
- ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform);
- ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov);
- ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera::get_frustum_offset);
- ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size);
- ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar);
- ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear);
- ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov);
- ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera::set_frustum_offset);
- ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size);
- ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar);
- ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear);
- ClassDB::bind_method(D_METHOD("get_projection"), &Camera::get_projection);
- ClassDB::bind_method(D_METHOD("set_projection"), &Camera::set_projection);
- ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera::set_h_offset);
- ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera::get_h_offset);
- ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera::set_v_offset);
- ClassDB::bind_method(D_METHOD("get_v_offset"), &Camera::get_v_offset);
- ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &Camera::set_cull_mask);
- ClassDB::bind_method(D_METHOD("get_cull_mask"), &Camera::get_cull_mask);
- ClassDB::bind_method(D_METHOD("set_environment", "env"), &Camera::set_environment);
- ClassDB::bind_method(D_METHOD("get_environment"), &Camera::get_environment);
- ClassDB::bind_method(D_METHOD("set_effects", "env"), &Camera::set_effects);
- ClassDB::bind_method(D_METHOD("get_effects"), &Camera::get_effects);
- ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera::set_keep_aspect_mode);
- ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode);
- ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking);
- ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
- ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum);
- ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera::get_camera);
-
- ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit);
- ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit);
-
- //ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_effects", "get_effects");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
-
- BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
- BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
- BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM);
-
- BIND_ENUM_CONSTANT(KEEP_WIDTH);
- BIND_ENUM_CONSTANT(KEEP_HEIGHT);
-
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED);
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP);
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
-}
-
-float Camera::get_fov() const {
-
- return fov;
-}
-
-float Camera::get_size() const {
-
- return size;
-}
-
-float Camera::get_znear() const {
-
- return near;
-}
-
-Vector2 Camera::get_frustum_offset() const {
- return frustum_offset;
-}
-
-float Camera::get_zfar() const {
-
- return far;
-}
-
-Camera::Projection Camera::get_projection() const {
-
- return mode;
-}
-
-void Camera::set_fov(float p_fov) {
- ERR_FAIL_COND(p_fov < 1 || p_fov > 179);
- fov = p_fov;
- _update_camera_mode();
- _change_notify("fov");
-}
-
-void Camera::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 Camera::set_znear(float p_znear) {
- near = p_znear;
- _update_camera_mode();
-}
-
-void Camera::set_frustum_offset(Vector2 p_offset) {
- frustum_offset = p_offset;
- _update_camera_mode();
-}
-
-void Camera::set_zfar(float p_zfar) {
- far = p_zfar;
- _update_camera_mode();
-}
-
-void Camera::set_cull_mask(uint32_t p_layers) {
- layers = p_layers;
- VisualServer::get_singleton()->camera_set_cull_mask(camera, layers);
- _update_camera_mode();
-}
-
-uint32_t Camera::get_cull_mask() const {
-
- return layers;
-}
-
-void Camera::set_cull_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_cull_mask(layers | (1 << p_layer));
- } else {
- set_cull_mask(layers & (~(1 << p_layer)));
- }
-}
-
-bool Camera::get_cull_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (layers & (1 << p_layer));
-}
-
-Vector<Plane> Camera::get_frustum() const {
-
- ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
-
- Size2 viewport_size = get_viewport()->get_visible_rect().size;
- CameraMatrix cm;
- if (mode == PROJECTION_PERSPECTIVE)
- cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
- else
- cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
-
- return cm.get_projection_planes(get_camera_transform());
-}
-
-void Camera::set_v_offset(float p_offset) {
-
- v_offset = p_offset;
- _update_camera();
-}
-
-float Camera::get_v_offset() const {
-
- return v_offset;
-}
-
-void Camera::set_h_offset(float p_offset) {
- h_offset = p_offset;
- _update_camera();
-}
-
-float Camera::get_h_offset() const {
-
- return h_offset;
-}
-
-Vector3 Camera::get_doppler_tracked_velocity() const {
-
- if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
- return velocity_tracker->get_tracked_linear_velocity();
- } else {
- return Vector3();
- }
-}
-Camera::Camera() {
-
- camera = VisualServer::get_singleton()->camera_create();
- size = 1;
- fov = 0;
- frustum_offset = Vector2();
- near = 0;
- far = 0;
- current = false;
- viewport = NULL;
- force_change = false;
- mode = PROJECTION_PERSPECTIVE;
- set_perspective(70.0, 0.05, 100.0);
- keep_aspect = KEEP_HEIGHT;
- layers = 0xfffff;
- v_offset = 0;
- h_offset = 0;
- VisualServer::get_singleton()->camera_set_cull_mask(camera, layers);
- //active=false;
- velocity_tracker.instance();
- doppler_tracking = DOPPLER_TRACKING_DISABLED;
- set_notify_transform(true);
- set_disable_scale(true);
-}
-
-Camera::~Camera() {
-
- VisualServer::get_singleton()->free(camera);
-}
-
-////////////////////////////////////////
-
-void ClippedCamera::set_margin(float p_margin) {
- margin = p_margin;
-}
-float ClippedCamera::get_margin() const {
- return margin;
-}
-void ClippedCamera::set_process_mode(ProcessMode p_mode) {
-
- if (process_mode == p_mode) {
- return;
- }
- process_mode = p_mode;
- set_process_internal(process_mode == CLIP_PROCESS_IDLE);
- set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
-}
-ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
- return process_mode;
-}
-
-Transform ClippedCamera::get_camera_transform() const {
-
- Transform t = Camera::get_camera_transform();
- t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
- return t;
-}
-
-void ClippedCamera::_notification(int p_what) {
- if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
-
- Spatial *parent = Object::cast_to<Spatial>(get_parent());
- if (!parent) {
- return;
- }
-
- PhysicsDirectSpaceState *dspace = get_world()->get_direct_space_state();
- ERR_FAIL_COND(!dspace); // most likely physics set to threads
-
- Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
- Vector3 cam_pos = get_global_transform().origin;
- Vector3 parent_pos = parent->get_global_transform().origin;
-
- Plane parent_plane(parent_pos, cam_fw);
-
- if (parent_plane.is_point_over(cam_pos)) {
- //cam is beyond parent plane
- return;
- }
-
- Vector3 ray_from = parent_plane.project(cam_pos);
-
- clip_offset = 0; //reset by defau;t
-
- { //check if points changed
- Vector<Vector3> local_points = get_near_plane_points();
-
- bool all_equal = true;
-
- for (int i = 0; i < 5; i++) {
- if (points[i] != local_points[i]) {
- all_equal = false;
- break;
- }
- }
-
- if (!all_equal) {
- PhysicsServer::get_singleton()->shape_set_data(pyramid_shape, local_points);
- points = local_points;
- }
- }
-
- Transform xf = get_global_transform();
- xf.origin = ray_from;
- xf.orthonormalize();
-
- float csafe, cunsafe;
- if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
- clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * csafe);
- }
-
- _update_camera();
- }
-
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- update_gizmo();
- }
-}
-
-void ClippedCamera::set_collision_mask(uint32_t p_mask) {
-
- collision_mask = p_mask;
-}
-
-uint32_t ClippedCamera::get_collision_mask() const {
-
- return collision_mask;
-}
-
-void ClippedCamera::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 ClippedCamera::get_collision_mask_bit(int p_bit) const {
-
- return get_collision_mask() & (1 << p_bit);
-}
-
-void ClippedCamera::add_exception_rid(const RID &p_rid) {
-
- exclude.insert(p_rid);
-}
-
-void ClippedCamera::add_exception(const Object *p_object) {
-
- ERR_FAIL_NULL(p_object);
- const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
- if (!co)
- return;
- add_exception_rid(co->get_rid());
-}
-
-void ClippedCamera::remove_exception_rid(const RID &p_rid) {
-
- exclude.erase(p_rid);
-}
-
-void ClippedCamera::remove_exception(const Object *p_object) {
-
- ERR_FAIL_NULL(p_object);
- const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
- if (!co)
- return;
- remove_exception_rid(co->get_rid());
-}
-
-void ClippedCamera::clear_exceptions() {
-
- exclude.clear();
-}
-
-float ClippedCamera::get_clip_offset() const {
-
- return clip_offset;
-}
-
-void ClippedCamera::set_clip_to_areas(bool p_clip) {
-
- clip_to_areas = p_clip;
-}
-
-bool ClippedCamera::is_clip_to_areas_enabled() const {
-
- return clip_to_areas;
-}
-
-void ClippedCamera::set_clip_to_bodies(bool p_clip) {
-
- clip_to_bodies = p_clip;
-}
-
-bool ClippedCamera::is_clip_to_bodies_enabled() const {
-
- return clip_to_bodies;
-}
-
-void ClippedCamera::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera::get_margin);
-
- ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera::set_process_mode);
- ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera::get_process_mode);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera::add_exception_rid);
- ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera::add_exception);
-
- ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera::remove_exception_rid);
- ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera::remove_exception);
-
- ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas);
- ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled);
-
- ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera::get_clip_offset);
-
- ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies);
- ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled);
-
- ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera::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, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
-
- ADD_GROUP("Clip To", "clip_to");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
-
- BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
- BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
-}
-ClippedCamera::ClippedCamera() {
- margin = 0;
- clip_offset = 0;
- process_mode = CLIP_PROCESS_PHYSICS;
- set_physics_process_internal(true);
- collision_mask = 1;
- set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
- points.resize(5);
- pyramid_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON);
- clip_to_areas = false;
- clip_to_bodies = true;
-}
-ClippedCamera::~ClippedCamera() {
- PhysicsServer::get_singleton()->free(pyramid_shape);
-}
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
deleted file mode 100644
index 6ac3ece798..0000000000
--- a/scene/3d/camera.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*************************************************************************/
-/* camera.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CAMERA_H
-#define CAMERA_H
-
-#include "scene/3d/spatial.h"
-#include "scene/3d/spatial_velocity_tracker.h"
-#include "scene/main/viewport.h"
-#include "scene/resources/environment.h"
-
-class Camera : public Spatial {
-
- GDCLASS(Camera, Spatial);
-
-public:
- enum Projection {
-
- PROJECTION_PERSPECTIVE,
- PROJECTION_ORTHOGONAL,
- PROJECTION_FRUSTUM
- };
-
- enum KeepAspect {
- KEEP_WIDTH,
- KEEP_HEIGHT
- };
-
- enum DopplerTracking {
- DOPPLER_TRACKING_DISABLED,
- DOPPLER_TRACKING_IDLE_STEP,
- DOPPLER_TRACKING_PHYSICS_STEP
- };
-
-private:
- bool force_change;
- bool current;
- Viewport *viewport;
-
- Projection mode;
-
- float fov;
- float size;
- Vector2 frustum_offset;
- float near, far;
- float v_offset;
- float h_offset;
- KeepAspect keep_aspect;
-
- RID camera;
- RID scenario_id;
-
- //String camera_group;
-
- uint32_t layers;
-
- Ref<Environment> environment;
- Ref<CameraEffects> effects;
-
- virtual bool _can_gizmo_scale() const;
-
- //void _camera_make_current(Node *p_camera);
- friend class Viewport;
- void _update_audio_listener_state();
-
- DopplerTracking doppler_tracking;
- Ref<SpatialVelocityTracker> velocity_tracker;
-
-protected:
- void _update_camera();
- virtual void _request_camera_update();
- void _update_camera_mode();
-
- void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &p_property) const;
-
- static void _bind_methods();
-
-public:
- enum {
-
- NOTIFICATION_BECAME_CURRENT = 50,
- NOTIFICATION_LOST_CURRENT = 51
- };
-
- void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
- void set_orthogonal(float p_size, float p_z_near, float p_z_far);
- void set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far);
- void set_projection(Camera::Projection p_mode);
-
- void make_current();
- void clear_current(bool p_enable_next = true);
- void set_current(bool p_current);
- bool is_current() const;
-
- RID get_camera() const;
-
- float get_fov() const;
- float get_size() const;
- float get_zfar() const;
- float get_znear() const;
- Vector2 get_frustum_offset() const;
-
- Projection get_projection() const;
-
- void set_fov(float p_fov);
- void set_size(float p_size);
- void set_zfar(float p_zfar);
- void set_znear(float p_znear);
- void set_frustum_offset(Vector2 p_offset);
-
- virtual Transform get_camera_transform() const;
-
- virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
- virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
- virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
- virtual Point2 unproject_position(const Vector3 &p_pos) const;
- bool is_position_behind(const Vector3 &p_pos) const;
- virtual Vector3 project_position(const Point2 &p_point, float p_z_depth) const;
-
- Vector<Vector3> get_near_plane_points() const;
-
- void set_cull_mask(uint32_t p_layers);
- uint32_t get_cull_mask() const;
-
- void set_cull_mask_bit(int p_layer, bool p_enable);
- bool get_cull_mask_bit(int p_layer) const;
-
- virtual Vector<Plane> get_frustum() const;
-
- void set_environment(const Ref<Environment> &p_environment);
- Ref<Environment> get_environment() const;
-
- void set_effects(const Ref<CameraEffects> &p_effects);
- Ref<CameraEffects> get_effects() const;
-
- void set_keep_aspect_mode(KeepAspect p_aspect);
- KeepAspect get_keep_aspect_mode() const;
-
- void set_v_offset(float p_offset);
- float get_v_offset() const;
-
- void set_h_offset(float p_offset);
- float get_h_offset() const;
-
- void set_doppler_tracking(DopplerTracking p_tracking);
- DopplerTracking get_doppler_tracking() const;
-
- Vector3 get_doppler_tracked_velocity() const;
-
- Camera();
- ~Camera();
-};
-
-VARIANT_ENUM_CAST(Camera::Projection);
-VARIANT_ENUM_CAST(Camera::KeepAspect);
-VARIANT_ENUM_CAST(Camera::DopplerTracking);
-
-class ClippedCamera : public Camera {
-
- GDCLASS(ClippedCamera, Camera);
-
-public:
- enum ProcessMode {
- CLIP_PROCESS_PHYSICS,
- CLIP_PROCESS_IDLE,
- };
-
-private:
- ProcessMode process_mode;
- RID pyramid_shape;
- float margin;
- float clip_offset;
- uint32_t collision_mask;
- bool clip_to_areas;
- bool clip_to_bodies;
-
- Set<RID> exclude;
-
- Vector<Vector3> points;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
- virtual Transform get_camera_transform() const;
-
-public:
- void set_clip_to_areas(bool p_clip);
- bool is_clip_to_areas_enabled() const;
-
- void set_clip_to_bodies(bool p_clip);
- bool is_clip_to_bodies_enabled() const;
-
- void set_margin(float p_margin);
- float get_margin() const;
-
- void set_process_mode(ProcessMode p_mode);
- ProcessMode get_process_mode() 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 add_exception_rid(const RID &p_rid);
- void add_exception(const Object *p_object);
- void remove_exception_rid(const RID &p_rid);
- void remove_exception(const Object *p_object);
- void clear_exceptions();
-
- float get_clip_offset() const;
-
- ClippedCamera();
- ~ClippedCamera();
-};
-
-VARIANT_ENUM_CAST(ClippedCamera::ProcessMode);
-#endif
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
new file mode 100644
index 0000000000..706c49b43b
--- /dev/null
+++ b/scene/3d/camera_3d.cpp
@@ -0,0 +1,937 @@
+/*************************************************************************/
+/* camera_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "camera_3d.h"
+
+#include "collision_object_3d.h"
+#include "core/engine.h"
+#include "core/math/camera_matrix.h"
+#include "scene/resources/material.h"
+#include "scene/resources/surface_tool.h"
+void Camera3D::_update_audio_listener_state() {
+}
+
+void Camera3D::_request_camera_update() {
+
+ _update_camera();
+}
+
+void Camera3D::_update_camera_mode() {
+
+ force_change = true;
+ switch (mode) {
+ case PROJECTION_PERSPECTIVE: {
+
+ set_perspective(fov, near, far);
+
+ } break;
+ case PROJECTION_ORTHOGONAL: {
+ set_orthogonal(size, near, far);
+ } break;
+ case PROJECTION_FRUSTUM: {
+ set_frustum(size, frustum_offset, near, far);
+ } break;
+ }
+}
+
+void Camera3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "fov") {
+ if (mode != PROJECTION_PERSPECTIVE) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+ } else if (p_property.name == "size") {
+ if (mode != PROJECTION_ORTHOGONAL && mode != PROJECTION_FRUSTUM) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+ } else if (p_property.name == "frustum_offset") {
+ if (mode != PROJECTION_FRUSTUM) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+ }
+}
+
+void Camera3D::_update_camera() {
+
+ if (!is_inside_tree())
+ return;
+
+ RenderingServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
+
+ // here goes listener stuff
+ /*
+ if (viewport_ptr && is_inside_scene() && is_current())
+ get_viewport()->_camera_transform_changed_notify();
+ */
+
+ if (get_tree()->is_node_being_edited(this) || !is_current())
+ return;
+
+ get_viewport()->_camera_transform_changed_notify();
+
+ if (get_world().is_valid()) {
+ get_world()->_update_camera(this);
+ }
+}
+
+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
+ // 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();
+ ERR_FAIL_COND(!viewport);
+
+ bool first_camera = viewport->_camera_add(this);
+ if (current || first_camera)
+ viewport->_camera_set(this);
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ _request_camera_update();
+ if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
+ velocity_tracker->update_position(get_global_transform().origin);
+ }
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ if (!get_tree()->is_node_being_edited(this)) {
+ if (is_current()) {
+ clear_current();
+ current = true; //keep it true
+
+ } else {
+ current = false;
+ }
+ }
+
+ if (viewport) {
+ viewport->_camera_remove(this);
+ viewport = nullptr;
+ }
+
+ } break;
+ case NOTIFICATION_BECAME_CURRENT: {
+ if (viewport) {
+ viewport->find_world()->_register_camera(this);
+ }
+ } break;
+ case NOTIFICATION_LOST_CURRENT: {
+ if (viewport) {
+ viewport->find_world()->_remove_camera(this);
+ }
+ } break;
+ }
+}
+
+Transform Camera3D::get_camera_transform() const {
+
+ Transform tr = get_global_transform().orthonormalized();
+ tr.origin += tr.basis.get_axis(1) * v_offset;
+ tr.origin += tr.basis.get_axis(0) * h_offset;
+ return tr;
+}
+
+void Camera3D::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
+
+ if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE)
+ return;
+
+ fov = p_fovy_degrees;
+ near = p_z_near;
+ far = p_z_far;
+ mode = PROJECTION_PERSPECTIVE;
+
+ RenderingServer::get_singleton()->camera_set_perspective(camera, fov, near, far);
+ update_gizmo();
+ force_change = false;
+}
+void Camera3D::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
+
+ if (!force_change && size == p_size && p_z_near == near && p_z_far == far && mode == PROJECTION_ORTHOGONAL)
+ return;
+
+ size = p_size;
+
+ near = p_z_near;
+ far = p_z_far;
+ mode = PROJECTION_ORTHOGONAL;
+ force_change = false;
+
+ RenderingServer::get_singleton()->camera_set_orthogonal(camera, size, near, far);
+ update_gizmo();
+}
+
+void Camera3D::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
+ if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM)
+ return;
+
+ size = p_size;
+ frustum_offset = p_offset;
+
+ near = p_z_near;
+ far = p_z_far;
+ mode = PROJECTION_FRUSTUM;
+ force_change = false;
+
+ RenderingServer::get_singleton()->camera_set_frustum(camera, size, frustum_offset, near, far);
+ update_gizmo();
+}
+
+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();
+ }
+}
+
+RID Camera3D::get_camera() const {
+
+ return camera;
+};
+
+void Camera3D::make_current() {
+
+ current = true;
+
+ if (!is_inside_tree())
+ return;
+
+ get_viewport()->_camera_set(this);
+
+ //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
+}
+
+void Camera3D::clear_current(bool p_enable_next) {
+
+ current = false;
+ if (!is_inside_tree())
+ return;
+
+ if (get_viewport()->get_camera() == this) {
+ get_viewport()->_camera_set(nullptr);
+
+ if (p_enable_next) {
+ get_viewport()->_camera_make_next_current(this);
+ }
+ }
+}
+
+void Camera3D::set_current(bool p_current) {
+ if (p_current) {
+ make_current();
+ } else {
+ clear_current();
+ }
+}
+
+bool Camera3D::is_current() const {
+
+ if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
+
+ return get_viewport()->get_camera() == this;
+ } else
+ return current;
+}
+
+bool Camera3D::_can_gizmo_scale() const {
+
+ return false;
+}
+
+Vector3 Camera3D::project_ray_normal(const Point2 &p_pos) const {
+
+ Vector3 ray = project_local_ray_normal(p_pos);
+ return get_camera_transform().basis.xform(ray).normalized();
+};
+
+Vector3 Camera3D::project_local_ray_normal(const Point2 &p_pos) const {
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_camera_rect_size();
+ Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
+ Vector3 ray;
+
+ if (mode == PROJECTION_ORTHOGONAL) {
+
+ ray = Vector3(0, 0, -1);
+ } else {
+ CameraMatrix cm;
+ cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ Vector2 screen_he = cm.get_viewport_half_extents();
+ ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -near).normalized();
+ }
+
+ return ray;
+};
+
+Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const {
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_camera_rect_size();
+ Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
+ ERR_FAIL_COND_V(viewport_size.y == 0, Vector3());
+
+ if (mode == PROJECTION_PERSPECTIVE) {
+
+ return get_camera_transform().origin;
+ } else {
+
+ Vector2 pos = cpos / viewport_size;
+ float vsize, hsize;
+ if (keep_aspect == KEEP_WIDTH) {
+ vsize = size / viewport_size.aspect();
+ hsize = size;
+ } else {
+ hsize = size * viewport_size.aspect();
+ vsize = size;
+ }
+
+ Vector3 ray;
+ ray.x = pos.x * (hsize)-hsize / 2;
+ ray.y = (1.0 - pos.y) * (vsize)-vsize / 2;
+ ray.z = -near;
+ ray = get_camera_transform().xform(ray);
+ return ray;
+ };
+};
+
+bool Camera3D::is_position_behind(const Vector3 &p_pos) const {
+
+ Transform t = get_global_transform();
+ Vector3 eyedir = -get_global_transform().basis.get_axis(2).normalized();
+ return eyedir.dot(p_pos) < (eyedir.dot(t.origin) + near);
+}
+
+Vector<Vector3> Camera3D::get_near_plane_points() const {
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector<Vector3>(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm;
+
+ if (mode == PROJECTION_ORTHOGONAL)
+ cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ else
+ cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+
+ Vector3 endpoints[8];
+ cm.get_endpoints(Transform(), endpoints);
+
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ for (int i = 0; i < 4; i++) {
+ points.push_back(endpoints[i + 4]);
+ }
+ return points;
+}
+
+Point2 Camera3D::unproject_position(const Vector3 &p_pos) const {
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector2(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm;
+
+ if (mode == PROJECTION_ORTHOGONAL)
+ cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ else
+ cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+
+ Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
+
+ p = cm.xform4(p);
+ p.normal /= p.d;
+
+ Point2 res;
+ res.x = (p.normal.x * 0.5 + 0.5) * viewport_size.x;
+ res.y = (-p.normal.y * 0.5 + 0.5) * viewport_size.y;
+
+ return res;
+}
+
+Vector3 Camera3D::project_position(const Point2 &p_point, float p_z_depth) const {
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
+
+ if (p_z_depth == 0 && mode != PROJECTION_ORTHOGONAL) {
+ return get_global_transform().origin;
+ }
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm;
+
+ if (mode == PROJECTION_ORTHOGONAL)
+ cm.set_orthogonal(size, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
+ else
+ cm.set_perspective(fov, viewport_size.aspect(), p_z_depth, far, keep_aspect == KEEP_WIDTH);
+
+ Vector2 vp_he = cm.get_viewport_half_extents();
+
+ Vector2 point;
+ point.x = (p_point.x / viewport_size.x) * 2.0 - 1.0;
+ point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
+ point *= vp_he;
+
+ Vector3 p(point.x, point.y, -p_z_depth);
+
+ return get_camera_transform().xform(p);
+}
+
+void Camera3D::set_environment(const Ref<Environment> &p_environment) {
+
+ environment = p_environment;
+ if (environment.is_valid())
+ RS::get_singleton()->camera_set_environment(camera, environment->get_rid());
+ else
+ RS::get_singleton()->camera_set_environment(camera, RID());
+ _update_camera_mode();
+}
+
+Ref<Environment> Camera3D::get_environment() const {
+
+ return environment;
+}
+
+void Camera3D::set_effects(const Ref<CameraEffects> &p_effects) {
+
+ effects = p_effects;
+ if (effects.is_valid())
+ RS::get_singleton()->camera_set_camera_effects(camera, effects->get_rid());
+ else
+ RS::get_singleton()->camera_set_camera_effects(camera, RID());
+ _update_camera_mode();
+}
+
+Ref<CameraEffects> Camera3D::get_effects() const {
+
+ return effects;
+}
+
+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();
+}
+
+Camera3D::KeepAspect Camera3D::get_keep_aspect_mode() const {
+
+ return keep_aspect;
+}
+
+void Camera3D::set_doppler_tracking(DopplerTracking p_tracking) {
+
+ if (doppler_tracking == p_tracking)
+ return;
+
+ doppler_tracking = p_tracking;
+ if (p_tracking != DOPPLER_TRACKING_DISABLED) {
+ velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP);
+ if (is_inside_tree()) {
+ velocity_tracker->reset(get_global_transform().origin);
+ }
+ }
+ _update_camera_mode();
+}
+
+Camera3D::DopplerTracking Camera3D::get_doppler_tracking() const {
+ return doppler_tracking;
+}
+
+void Camera3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("project_ray_normal", "screen_point"), &Camera3D::project_ray_normal);
+ ClassDB::bind_method(D_METHOD("project_local_ray_normal", "screen_point"), &Camera3D::project_local_ray_normal);
+ ClassDB::bind_method(D_METHOD("project_ray_origin", "screen_point"), &Camera3D::project_ray_origin);
+ ClassDB::bind_method(D_METHOD("unproject_position", "world_point"), &Camera3D::unproject_position);
+ ClassDB::bind_method(D_METHOD("is_position_behind", "world_point"), &Camera3D::is_position_behind);
+ ClassDB::bind_method(D_METHOD("project_position", "screen_point", "z_depth"), &Camera3D::project_position);
+ ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera3D::set_perspective);
+ ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera3D::set_orthogonal);
+ ClassDB::bind_method(D_METHOD("set_frustum", "size", "offset", "z_near", "z_far"), &Camera3D::set_frustum);
+ ClassDB::bind_method(D_METHOD("make_current"), &Camera3D::make_current);
+ ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera3D::clear_current, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("set_current"), &Camera3D::set_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &Camera3D::is_current);
+ ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera3D::get_camera_transform);
+ ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov);
+ ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera3D::get_frustum_offset);
+ ClassDB::bind_method(D_METHOD("get_size"), &Camera3D::get_size);
+ ClassDB::bind_method(D_METHOD("get_zfar"), &Camera3D::get_zfar);
+ ClassDB::bind_method(D_METHOD("get_znear"), &Camera3D::get_znear);
+ ClassDB::bind_method(D_METHOD("set_fov"), &Camera3D::set_fov);
+ ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera3D::set_frustum_offset);
+ ClassDB::bind_method(D_METHOD("set_size"), &Camera3D::set_size);
+ ClassDB::bind_method(D_METHOD("set_zfar"), &Camera3D::set_zfar);
+ ClassDB::bind_method(D_METHOD("set_znear"), &Camera3D::set_znear);
+ ClassDB::bind_method(D_METHOD("get_projection"), &Camera3D::get_projection);
+ ClassDB::bind_method(D_METHOD("set_projection"), &Camera3D::set_projection);
+ ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera3D::set_h_offset);
+ ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera3D::get_h_offset);
+ ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera3D::set_v_offset);
+ ClassDB::bind_method(D_METHOD("get_v_offset"), &Camera3D::get_v_offset);
+ ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &Camera3D::set_cull_mask);
+ ClassDB::bind_method(D_METHOD("get_cull_mask"), &Camera3D::get_cull_mask);
+ ClassDB::bind_method(D_METHOD("set_environment", "env"), &Camera3D::set_environment);
+ ClassDB::bind_method(D_METHOD("get_environment"), &Camera3D::get_environment);
+ ClassDB::bind_method(D_METHOD("set_effects", "env"), &Camera3D::set_effects);
+ ClassDB::bind_method(D_METHOD("get_effects"), &Camera3D::get_effects);
+ ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera3D::set_keep_aspect_mode);
+ ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera3D::get_keep_aspect_mode);
+ ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking);
+ ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera3D::get_doppler_tracking);
+ ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum);
+ ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera);
+
+ ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera3D::set_cull_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera3D::get_cull_mask_bit);
+
+ //ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_effects", "get_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
+
+ BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
+ BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
+ BIND_ENUM_CONSTANT(PROJECTION_FRUSTUM);
+
+ BIND_ENUM_CONSTANT(KEEP_WIDTH);
+ BIND_ENUM_CONSTANT(KEEP_HEIGHT);
+
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED);
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP);
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
+}
+
+float Camera3D::get_fov() const {
+
+ return fov;
+}
+
+float Camera3D::get_size() const {
+
+ return size;
+}
+
+float Camera3D::get_znear() const {
+
+ return near;
+}
+
+Vector2 Camera3D::get_frustum_offset() const {
+ return frustum_offset;
+}
+
+float Camera3D::get_zfar() const {
+
+ return far;
+}
+
+Camera3D::Projection Camera3D::get_projection() const {
+
+ return mode;
+}
+
+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_znear(float p_znear) {
+ near = p_znear;
+ _update_camera_mode();
+}
+
+void Camera3D::set_frustum_offset(Vector2 p_offset) {
+ frustum_offset = p_offset;
+ _update_camera_mode();
+}
+
+void Camera3D::set_zfar(float p_zfar) {
+ far = p_zfar;
+ _update_camera_mode();
+}
+
+void Camera3D::set_cull_mask(uint32_t p_layers) {
+ layers = p_layers;
+ RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers);
+ _update_camera_mode();
+}
+
+uint32_t Camera3D::get_cull_mask() const {
+
+ return layers;
+}
+
+void Camera3D::set_cull_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_cull_mask(layers | (1 << p_layer));
+ } else {
+ set_cull_mask(layers & (~(1 << p_layer)));
+ }
+}
+
+bool Camera3D::get_cull_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (layers & (1 << p_layer));
+}
+
+Vector<Plane> Camera3D::get_frustum() const {
+
+ ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+ CameraMatrix cm;
+ if (mode == PROJECTION_PERSPECTIVE)
+ cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ else
+ cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+
+ return cm.get_projection_planes(get_camera_transform());
+}
+
+void Camera3D::set_v_offset(float p_offset) {
+
+ v_offset = p_offset;
+ _update_camera();
+}
+
+float Camera3D::get_v_offset() const {
+
+ return v_offset;
+}
+
+void Camera3D::set_h_offset(float p_offset) {
+ h_offset = p_offset;
+ _update_camera();
+}
+
+float Camera3D::get_h_offset() const {
+
+ return h_offset;
+}
+
+Vector3 Camera3D::get_doppler_tracked_velocity() const {
+
+ if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
+ return velocity_tracker->get_tracked_linear_velocity();
+ } else {
+ return Vector3();
+ }
+}
+Camera3D::Camera3D() {
+
+ camera = RenderingServer::get_singleton()->camera_create();
+ size = 1;
+ fov = 0;
+ frustum_offset = Vector2();
+ near = 0;
+ far = 0;
+ current = false;
+ viewport = nullptr;
+ force_change = false;
+ mode = PROJECTION_PERSPECTIVE;
+ set_perspective(70.0, 0.05, 100.0);
+ keep_aspect = KEEP_HEIGHT;
+ layers = 0xfffff;
+ v_offset = 0;
+ h_offset = 0;
+ RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers);
+ //active=false;
+ velocity_tracker.instance();
+ doppler_tracking = DOPPLER_TRACKING_DISABLED;
+ set_notify_transform(true);
+ set_disable_scale(true);
+}
+
+Camera3D::~Camera3D() {
+
+ RenderingServer::get_singleton()->free(camera);
+}
+
+////////////////////////////////////////
+
+void ClippedCamera3D::set_margin(float p_margin) {
+ margin = p_margin;
+}
+float ClippedCamera3D::get_margin() const {
+ return margin;
+}
+void ClippedCamera3D::set_process_mode(ProcessMode p_mode) {
+
+ if (process_mode == p_mode) {
+ return;
+ }
+ process_mode = p_mode;
+ set_process_internal(process_mode == CLIP_PROCESS_IDLE);
+ set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
+}
+ClippedCamera3D::ProcessMode ClippedCamera3D::get_process_mode() const {
+ return process_mode;
+}
+
+Transform ClippedCamera3D::get_camera_transform() const {
+
+ Transform t = Camera3D::get_camera_transform();
+ t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
+ return t;
+}
+
+void ClippedCamera3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+
+ Node3D *parent = Object::cast_to<Node3D>(get_parent());
+ if (!parent) {
+ return;
+ }
+
+ PhysicsDirectSpaceState3D *dspace = get_world()->get_direct_space_state();
+ ERR_FAIL_COND(!dspace); // most likely physics set to threads
+
+ Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
+ Vector3 cam_pos = get_global_transform().origin;
+ Vector3 parent_pos = parent->get_global_transform().origin;
+
+ Plane parent_plane(parent_pos, cam_fw);
+
+ if (parent_plane.is_point_over(cam_pos)) {
+ //cam is beyond parent plane
+ return;
+ }
+
+ Vector3 ray_from = parent_plane.project(cam_pos);
+
+ clip_offset = 0; //reset by defau;t
+
+ { //check if points changed
+ Vector<Vector3> local_points = get_near_plane_points();
+
+ bool all_equal = true;
+
+ for (int i = 0; i < 5; i++) {
+ if (points[i] != local_points[i]) {
+ all_equal = false;
+ break;
+ }
+ }
+
+ if (!all_equal) {
+ PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
+ points = local_points;
+ }
+ }
+
+ Transform xf = get_global_transform();
+ xf.origin = ray_from;
+ xf.orthonormalize();
+
+ float csafe, cunsafe;
+ if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
+ clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * csafe);
+ }
+
+ _update_camera();
+ }
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ update_gizmo();
+ }
+}
+
+void ClippedCamera3D::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask = p_mask;
+}
+
+uint32_t ClippedCamera3D::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void ClippedCamera3D::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 ClippedCamera3D::get_collision_mask_bit(int p_bit) const {
+
+ return get_collision_mask() & (1 << p_bit);
+}
+
+void ClippedCamera3D::add_exception_rid(const RID &p_rid) {
+
+ exclude.insert(p_rid);
+}
+
+void ClippedCamera3D::add_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
+ if (!co)
+ return;
+ add_exception_rid(co->get_rid());
+}
+
+void ClippedCamera3D::remove_exception_rid(const RID &p_rid) {
+
+ exclude.erase(p_rid);
+}
+
+void ClippedCamera3D::remove_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
+ if (!co)
+ return;
+ remove_exception_rid(co->get_rid());
+}
+
+void ClippedCamera3D::clear_exceptions() {
+
+ exclude.clear();
+}
+
+float ClippedCamera3D::get_clip_offset() const {
+
+ return clip_offset;
+}
+
+void ClippedCamera3D::set_clip_to_areas(bool p_clip) {
+
+ clip_to_areas = p_clip;
+}
+
+bool ClippedCamera3D::is_clip_to_areas_enabled() const {
+
+ return clip_to_areas;
+}
+
+void ClippedCamera3D::set_clip_to_bodies(bool p_clip) {
+
+ clip_to_bodies = p_clip;
+}
+
+bool ClippedCamera3D::is_clip_to_bodies_enabled() const {
+
+ return clip_to_bodies;
+}
+
+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_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera3D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera3D::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera3D::add_exception_rid);
+ ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera3D::add_exception);
+
+ ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera3D::remove_exception_rid);
+ ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera3D::remove_exception);
+
+ ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera3D::set_clip_to_areas);
+ ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera3D::is_clip_to_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera3D::get_clip_offset);
+
+ ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera3D::set_clip_to_bodies);
+ ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera3D::is_clip_to_bodies_enabled);
+
+ 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, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Clip To", "clip_to");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
+
+ BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
+ BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
+}
+ClippedCamera3D::ClippedCamera3D() {
+ margin = 0;
+ clip_offset = 0;
+ process_mode = CLIP_PROCESS_PHYSICS;
+ set_physics_process_internal(true);
+ collision_mask = 1;
+ set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
+ points.resize(5);
+ pyramid_shape = PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON);
+ clip_to_areas = false;
+ clip_to_bodies = true;
+}
+ClippedCamera3D::~ClippedCamera3D() {
+ PhysicsServer3D::get_singleton()->free(pyramid_shape);
+}
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
new file mode 100644
index 0000000000..9a005226cb
--- /dev/null
+++ b/scene/3d/camera_3d.h
@@ -0,0 +1,246 @@
+/*************************************************************************/
+/* camera_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CAMERA_3D_H
+#define CAMERA_3D_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/3d/velocity_tracker_3d.h"
+#include "scene/main/window.h"
+#include "scene/resources/environment.h"
+
+class Camera3D : public Node3D {
+
+ GDCLASS(Camera3D, Node3D);
+
+public:
+ enum Projection {
+
+ PROJECTION_PERSPECTIVE,
+ PROJECTION_ORTHOGONAL,
+ PROJECTION_FRUSTUM
+ };
+
+ enum KeepAspect { KEEP_WIDTH,
+ KEEP_HEIGHT };
+
+ enum DopplerTracking {
+ DOPPLER_TRACKING_DISABLED,
+ DOPPLER_TRACKING_IDLE_STEP,
+ DOPPLER_TRACKING_PHYSICS_STEP
+ };
+
+private:
+ bool force_change;
+ bool current;
+ Viewport *viewport;
+
+ Projection mode;
+
+ float fov;
+ float size;
+ Vector2 frustum_offset;
+ float near, far;
+ float v_offset;
+ float h_offset;
+ KeepAspect keep_aspect;
+
+ RID camera;
+ RID scenario_id;
+
+ // String camera_group;
+
+ uint32_t layers;
+
+ Ref<Environment> environment;
+ Ref<CameraEffects> effects;
+
+ virtual bool _can_gizmo_scale() const;
+
+ // void _camera_make_current(Node *p_camera);
+ friend class Viewport;
+ void _update_audio_listener_state();
+
+ DopplerTracking doppler_tracking;
+ Ref<VelocityTracker3D> velocity_tracker;
+
+protected:
+ void _update_camera();
+ virtual void _request_camera_update();
+ void _update_camera_mode();
+
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &p_property) const;
+
+ static void _bind_methods();
+
+public:
+ enum {
+
+ NOTIFICATION_BECAME_CURRENT = 50,
+ NOTIFICATION_LOST_CURRENT = 51
+ };
+
+ void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
+ void set_orthogonal(float p_size, float p_z_near, float p_z_far);
+ void set_frustum(float p_size, Vector2 p_offset, float p_z_near,
+ float p_z_far);
+ void set_projection(Camera3D::Projection p_mode);
+
+ void make_current();
+ void clear_current(bool p_enable_next = true);
+ void set_current(bool p_current);
+ bool is_current() const;
+
+ RID get_camera() const;
+
+ float get_fov() const;
+ float get_size() const;
+ float get_zfar() const;
+ float get_znear() const;
+ Vector2 get_frustum_offset() const;
+
+ Projection get_projection() const;
+
+ void set_fov(float p_fov);
+ void set_size(float p_size);
+ void set_zfar(float p_zfar);
+ void set_znear(float p_znear);
+ void set_frustum_offset(Vector2 p_offset);
+
+ virtual Transform get_camera_transform() const;
+
+ virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
+ virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
+ virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
+ virtual Point2 unproject_position(const Vector3 &p_pos) const;
+ bool is_position_behind(const Vector3 &p_pos) const;
+ virtual Vector3 project_position(const Point2 &p_point,
+ float p_z_depth) const;
+
+ Vector<Vector3> get_near_plane_points() const;
+
+ void set_cull_mask(uint32_t p_layers);
+ uint32_t get_cull_mask() const;
+
+ void set_cull_mask_bit(int p_layer, bool p_enable);
+ bool get_cull_mask_bit(int p_layer) const;
+
+ virtual Vector<Plane> get_frustum() const;
+
+ void set_environment(const Ref<Environment> &p_environment);
+ Ref<Environment> get_environment() const;
+
+ void set_effects(const Ref<CameraEffects> &p_effects);
+ Ref<CameraEffects> get_effects() const;
+
+ void set_keep_aspect_mode(KeepAspect p_aspect);
+ KeepAspect get_keep_aspect_mode() const;
+
+ void set_v_offset(float p_offset);
+ float get_v_offset() const;
+
+ void set_h_offset(float p_offset);
+ float get_h_offset() const;
+
+ void set_doppler_tracking(DopplerTracking p_tracking);
+ DopplerTracking get_doppler_tracking() const;
+
+ Vector3 get_doppler_tracked_velocity() const;
+
+ Camera3D();
+ ~Camera3D();
+};
+
+VARIANT_ENUM_CAST(Camera3D::Projection);
+VARIANT_ENUM_CAST(Camera3D::KeepAspect);
+VARIANT_ENUM_CAST(Camera3D::DopplerTracking);
+
+class ClippedCamera3D : public Camera3D {
+
+ GDCLASS(ClippedCamera3D, Camera3D);
+
+public:
+ enum ProcessMode {
+ CLIP_PROCESS_PHYSICS,
+ CLIP_PROCESS_IDLE,
+ };
+
+private:
+ ProcessMode process_mode;
+ RID pyramid_shape;
+ float margin;
+ float clip_offset;
+ uint32_t collision_mask;
+ bool clip_to_areas;
+ bool clip_to_bodies;
+
+ Set<RID> exclude;
+
+ Vector<Vector3> points;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ virtual Transform get_camera_transform() const;
+
+public:
+ void set_clip_to_areas(bool p_clip);
+ bool is_clip_to_areas_enabled() const;
+
+ void set_clip_to_bodies(bool p_clip);
+ bool is_clip_to_bodies_enabled() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_process_mode(ProcessMode p_mode);
+ ProcessMode get_process_mode() 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 add_exception_rid(const RID &p_rid);
+ void add_exception(const Object *p_object);
+ void remove_exception_rid(const RID &p_rid);
+ void remove_exception(const Object *p_object);
+ void clear_exceptions();
+
+ float get_clip_offset() const;
+
+ ClippedCamera3D();
+ ~ClippedCamera3D();
+};
+
+VARIANT_ENUM_CAST(ClippedCamera3D::ProcessMode);
+#endif
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
deleted file mode 100644
index c067ef34a6..0000000000
--- a/scene/3d/collision_object.cpp
+++ /dev/null
@@ -1,396 +0,0 @@
-/*************************************************************************/
-/* collision_object.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_object.h"
-
-#include "scene/scene_string_names.h"
-#include "servers/physics_server.h"
-
-void CollisionObject::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_WORLD: {
-
- if (area)
- PhysicsServer::get_singleton()->area_set_transform(rid, get_global_transform());
- else
- PhysicsServer::get_singleton()->body_set_state(rid, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
-
- RID space = get_world()->get_space();
- if (area) {
- PhysicsServer::get_singleton()->area_set_space(rid, space);
- } else
- PhysicsServer::get_singleton()->body_set_space(rid, space);
-
- _update_pickable();
- //get space
- } break;
-
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- if (area)
- PhysicsServer::get_singleton()->area_set_transform(rid, get_global_transform());
- else
- PhysicsServer::get_singleton()->body_set_state(rid, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
-
- } break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
-
- _update_pickable();
-
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- if (area) {
- PhysicsServer::get_singleton()->area_set_space(rid, RID());
- } else
- PhysicsServer::get_singleton()->body_set_space(rid, RID());
-
- } break;
- }
-}
-
-void CollisionObject::_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);
- }
- emit_signal(SceneStringNames::get_singleton()->input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
-}
-
-void CollisionObject::_mouse_enter() {
-
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
- }
- emit_signal(SceneStringNames::get_singleton()->mouse_entered);
-}
-
-void CollisionObject::_mouse_exit() {
-
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
- }
- emit_signal(SceneStringNames::get_singleton()->mouse_exited);
-}
-
-void CollisionObject::_update_pickable() {
- if (!is_inside_tree())
- return;
-
- bool pickable = ray_pickable && is_visible_in_tree();
- if (area)
- PhysicsServer::get_singleton()->area_set_ray_pickable(rid, pickable);
- else
- PhysicsServer::get_singleton()->body_set_ray_pickable(rid, pickable);
-}
-
-void CollisionObject::set_ray_pickable(bool p_ray_pickable) {
-
- ray_pickable = p_ray_pickable;
- _update_pickable();
-}
-
-bool CollisionObject::is_ray_pickable() const {
-
- return ray_pickable;
-}
-
-void CollisionObject::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject::set_ray_pickable);
- ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject::is_ray_pickable);
- ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject::set_capture_input_on_drag);
- ClassDB::bind_method(D_METHOD("get_capture_input_on_drag"), &CollisionObject::get_capture_input_on_drag);
- ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject::get_rid);
- ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject::create_shape_owner);
- ClassDB::bind_method(D_METHOD("remove_shape_owner", "owner_id"), &CollisionObject::remove_shape_owner);
- ClassDB::bind_method(D_METHOD("get_shape_owners"), &CollisionObject::_get_shape_owners);
- ClassDB::bind_method(D_METHOD("shape_owner_set_transform", "owner_id", "transform"), &CollisionObject::shape_owner_set_transform);
- ClassDB::bind_method(D_METHOD("shape_owner_get_transform", "owner_id"), &CollisionObject::shape_owner_get_transform);
- ClassDB::bind_method(D_METHOD("shape_owner_get_owner", "owner_id"), &CollisionObject::shape_owner_get_owner);
- ClassDB::bind_method(D_METHOD("shape_owner_set_disabled", "owner_id", "disabled"), &CollisionObject::shape_owner_set_disabled);
- ClassDB::bind_method(D_METHOD("is_shape_owner_disabled", "owner_id"), &CollisionObject::is_shape_owner_disabled);
- ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape"), &CollisionObject::shape_owner_add_shape);
- ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject::shape_owner_get_shape_count);
- ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject::shape_owner_get_shape);
- ClassDB::bind_method(D_METHOD("shape_owner_get_shape_index", "owner_id", "shape_id"), &CollisionObject::shape_owner_get_shape_index);
- ClassDB::bind_method(D_METHOD("shape_owner_remove_shape", "owner_id", "shape_id"), &CollisionObject::shape_owner_remove_shape);
- ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject::shape_owner_clear_shapes);
- ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject::shape_find_owner);
-
- 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_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");
-}
-
-uint32_t CollisionObject::create_shape_owner(Object *p_owner) {
-
- ShapeData sd;
- uint32_t id;
-
- if (shapes.size() == 0) {
- id = 0;
- } else {
- id = shapes.back()->key() + 1;
- }
-
- sd.owner = p_owner;
-
- shapes[id] = sd;
-
- return id;
-}
-
-void CollisionObject::remove_shape_owner(uint32_t owner) {
-
- ERR_FAIL_COND(!shapes.has(owner));
-
- shape_owner_clear_shapes(owner);
-
- shapes.erase(owner);
-}
-
-void CollisionObject::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) {
- ERR_FAIL_COND(!shapes.has(p_owner));
-
- ShapeData &sd = shapes[p_owner];
- sd.disabled = p_disabled;
- for (int i = 0; i < sd.shapes.size(); i++) {
- if (area) {
- PhysicsServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
- } else {
- PhysicsServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
- }
- }
-}
-
-bool CollisionObject::is_shape_owner_disabled(uint32_t p_owner) const {
-
- ERR_FAIL_COND_V(!shapes.has(p_owner), false);
-
- return shapes[p_owner].disabled;
-}
-
-void CollisionObject::get_shape_owners(List<uint32_t> *r_owners) {
-
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- r_owners->push_back(E->key());
- }
-}
-
-Array CollisionObject::_get_shape_owners() {
-
- Array ret;
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- ret.push_back(E->key());
- }
-
- return ret;
-}
-
-void CollisionObject::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) {
-
- ERR_FAIL_COND(!shapes.has(p_owner));
-
- ShapeData &sd = shapes[p_owner];
- sd.xform = p_transform;
- for (int i = 0; i < sd.shapes.size(); i++) {
- if (area) {
- PhysicsServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform);
- } else {
- PhysicsServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
- }
- }
-}
-Transform CollisionObject::shape_owner_get_transform(uint32_t p_owner) const {
-
- ERR_FAIL_COND_V(!shapes.has(p_owner), Transform());
-
- return shapes[p_owner].xform;
-}
-
-Object *CollisionObject::shape_owner_get_owner(uint32_t p_owner) const {
-
- ERR_FAIL_COND_V(!shapes.has(p_owner), NULL);
-
- return shapes[p_owner].owner;
-}
-
-void CollisionObject::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &p_shape) {
-
- ERR_FAIL_COND(!shapes.has(p_owner));
- ERR_FAIL_COND(p_shape.is_null());
-
- ShapeData &sd = shapes[p_owner];
- ShapeData::ShapeBase s;
- s.index = total_subshapes;
- s.shape = p_shape;
- if (area) {
- PhysicsServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
- } else {
- PhysicsServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
- }
- sd.shapes.push_back(s);
-
- total_subshapes++;
-}
-int CollisionObject::shape_owner_get_shape_count(uint32_t p_owner) const {
-
- ERR_FAIL_COND_V(!shapes.has(p_owner), 0);
-
- return shapes[p_owner].shapes.size();
-}
-Ref<Shape> CollisionObject::shape_owner_get_shape(uint32_t p_owner, int p_shape) const {
-
- ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape>());
- ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape>());
-
- return shapes[p_owner].shapes[p_shape].shape;
-}
-int CollisionObject::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const {
-
- ERR_FAIL_COND_V(!shapes.has(p_owner), -1);
- ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1);
-
- return shapes[p_owner].shapes[p_shape].index;
-}
-
-void CollisionObject::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;
- if (area) {
- PhysicsServer::get_singleton()->area_remove_shape(rid, index_to_remove);
- } else {
- PhysicsServer::get_singleton()->body_remove_shape(rid, index_to_remove);
- }
-
- shapes[p_owner].shapes.remove(p_shape);
-
- for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().shapes.size(); i++) {
- if (E->get().shapes[i].index > index_to_remove) {
- E->get().shapes.write[i].index -= 1;
- }
- }
- }
-
- total_subshapes--;
-}
-
-void CollisionObject::shape_owner_clear_shapes(uint32_t p_owner) {
-
- ERR_FAIL_COND(!shapes.has(p_owner));
-
- while (shape_owner_get_shape_count(p_owner) > 0) {
- shape_owner_remove_shape(p_owner, 0);
- }
-}
-
-uint32_t CollisionObject::shape_find_owner(int p_shape_index) const {
-
- ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);
-
- for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().shapes.size(); i++) {
- if (E->get().shapes[i].index == p_shape_index) {
- return E->key();
- }
- }
- }
-
- //in theory it should be unreachable
- return 0;
-}
-
-CollisionObject::CollisionObject(RID p_rid, bool p_area) {
-
- rid = p_rid;
- area = p_area;
- capture_input_on_drag = false;
- ray_pickable = true;
- set_notify_transform(true);
- total_subshapes = 0;
-
- if (p_area) {
- PhysicsServer::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
- } else {
- PhysicsServer::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
- }
- //set_transform_notify(true);
-}
-
-void CollisionObject::set_capture_input_on_drag(bool p_capture) {
-
- capture_input_on_drag = p_capture;
-}
-
-bool CollisionObject::get_capture_input_on_drag() const {
-
- return capture_input_on_drag;
-}
-
-String CollisionObject::get_configuration_warning() const {
-
- String warning = Spatial::get_configuration_warning();
-
- if (shapes.empty()) {
- if (!warning.empty()) {
- warning += "\n\n";
- }
- warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape or CollisionPolygon as a child to define its shape.");
- }
-
- return warning;
-}
-
-CollisionObject::CollisionObject() {
-
- capture_input_on_drag = false;
- ray_pickable = true;
- set_notify_transform(true);
- //owner=
-
- //set_transform_notify(true);
-}
-
-CollisionObject::~CollisionObject() {
-
- PhysicsServer::get_singleton()->free(rid);
-}
diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h
deleted file mode 100644
index 572e73d51b..0000000000
--- a/scene/3d/collision_object.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*************************************************************************/
-/* collision_object.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_OBJECT_H
-#define COLLISION_OBJECT_H
-
-#include "scene/3d/spatial.h"
-#include "scene/resources/shape.h"
-
-class CollisionObject : public Spatial {
-
- GDCLASS(CollisionObject, Spatial);
-
- bool area;
-
- RID rid;
-
- struct ShapeData {
-
- Object *owner;
- Transform xform;
- struct ShapeBase {
- Ref<Shape> shape;
- int index;
- };
-
- Vector<ShapeBase> shapes;
- bool disabled;
-
- ShapeData() {
- disabled = false;
- owner = NULL;
- }
- };
-
- int total_subshapes;
-
- Map<uint32_t, ShapeData> shapes;
-
- bool capture_input_on_drag;
- bool ray_pickable;
-
- void _update_pickable();
-
-protected:
- CollisionObject(RID p_rid, bool p_area);
-
- void _notification(int p_what);
- static void _bind_methods();
- friend class Viewport;
- virtual void _input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
- virtual void _mouse_enter();
- virtual void _mouse_exit();
-
-public:
- uint32_t create_shape_owner(Object *p_owner);
- void remove_shape_owner(uint32_t owner);
- void get_shape_owners(List<uint32_t> *r_owners);
- Array _get_shape_owners();
-
- void shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform);
- Transform shape_owner_get_transform(uint32_t p_owner) const;
- Object *shape_owner_get_owner(uint32_t p_owner) const;
-
- void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled);
- bool is_shape_owner_disabled(uint32_t p_owner) const;
-
- void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape> &p_shape);
- int shape_owner_get_shape_count(uint32_t p_owner) const;
- Ref<Shape> shape_owner_get_shape(uint32_t p_owner, int p_shape) const;
- int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const;
-
- void shape_owner_remove_shape(uint32_t p_owner, int p_shape);
- void shape_owner_clear_shapes(uint32_t p_owner);
-
- uint32_t shape_find_owner(int p_shape_index) const;
-
- void set_ray_pickable(bool p_ray_pickable);
- bool is_ray_pickable() const;
-
- void set_capture_input_on_drag(bool p_capture);
- bool get_capture_input_on_drag() const;
-
- _FORCE_INLINE_ RID get_rid() const { return rid; }
-
- virtual String get_configuration_warning() const;
-
- CollisionObject();
- ~CollisionObject();
-};
-
-#endif // COLLISION_OBJECT__H
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
new file mode 100644
index 0000000000..e6cd7bfe7e
--- /dev/null
+++ b/scene/3d/collision_object_3d.cpp
@@ -0,0 +1,396 @@
+/*************************************************************************/
+/* collision_object_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_object_3d.h"
+
+#include "scene/scene_string_names.h"
+#include "servers/physics_server_3d.h"
+
+void CollisionObject3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_WORLD: {
+
+ if (area)
+ PhysicsServer3D::get_singleton()->area_set_transform(rid, get_global_transform());
+ else
+ PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+
+ RID space = get_world()->get_space();
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, space);
+ } else
+ PhysicsServer3D::get_singleton()->body_set_space(rid, space);
+
+ _update_pickable();
+ //get space
+ } break;
+
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (area)
+ PhysicsServer3D::get_singleton()->area_set_transform(rid, get_global_transform());
+ else
+ PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_pickable();
+
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+
+ } break;
+ }
+}
+
+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);
+ }
+ emit_signal(SceneStringNames::get_singleton()->input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
+}
+
+void CollisionObject3D::_mouse_enter() {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_enter);
+ }
+ emit_signal(SceneStringNames::get_singleton()->mouse_entered);
+}
+
+void CollisionObject3D::_mouse_exit() {
+
+ if (get_script_instance()) {
+ get_script_instance()->call(SceneStringNames::get_singleton()->_mouse_exit);
+ }
+ emit_signal(SceneStringNames::get_singleton()->mouse_exited);
+}
+
+void CollisionObject3D::_update_pickable() {
+ if (!is_inside_tree())
+ return;
+
+ bool pickable = ray_pickable && is_visible_in_tree();
+ if (area)
+ PhysicsServer3D::get_singleton()->area_set_ray_pickable(rid, pickable);
+ else
+ PhysicsServer3D::get_singleton()->body_set_ray_pickable(rid, pickable);
+}
+
+void CollisionObject3D::set_ray_pickable(bool p_ray_pickable) {
+
+ ray_pickable = p_ray_pickable;
+ _update_pickable();
+}
+
+bool CollisionObject3D::is_ray_pickable() const {
+
+ return ray_pickable;
+}
+
+void CollisionObject3D::_bind_methods() {
+
+ 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);
+ ClassDB::bind_method(D_METHOD("get_capture_input_on_drag"), &CollisionObject3D::get_capture_input_on_drag);
+ ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject3D::get_rid);
+ ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject3D::create_shape_owner);
+ ClassDB::bind_method(D_METHOD("remove_shape_owner", "owner_id"), &CollisionObject3D::remove_shape_owner);
+ ClassDB::bind_method(D_METHOD("get_shape_owners"), &CollisionObject3D::_get_shape_owners);
+ ClassDB::bind_method(D_METHOD("shape_owner_set_transform", "owner_id", "transform"), &CollisionObject3D::shape_owner_set_transform);
+ ClassDB::bind_method(D_METHOD("shape_owner_get_transform", "owner_id"), &CollisionObject3D::shape_owner_get_transform);
+ ClassDB::bind_method(D_METHOD("shape_owner_get_owner", "owner_id"), &CollisionObject3D::shape_owner_get_owner);
+ ClassDB::bind_method(D_METHOD("shape_owner_set_disabled", "owner_id", "disabled"), &CollisionObject3D::shape_owner_set_disabled);
+ ClassDB::bind_method(D_METHOD("is_shape_owner_disabled", "owner_id"), &CollisionObject3D::is_shape_owner_disabled);
+ ClassDB::bind_method(D_METHOD("shape_owner_add_shape", "owner_id", "shape"), &CollisionObject3D::shape_owner_add_shape);
+ ClassDB::bind_method(D_METHOD("shape_owner_get_shape_count", "owner_id"), &CollisionObject3D::shape_owner_get_shape_count);
+ ClassDB::bind_method(D_METHOD("shape_owner_get_shape", "owner_id", "shape_id"), &CollisionObject3D::shape_owner_get_shape);
+ ClassDB::bind_method(D_METHOD("shape_owner_get_shape_index", "owner_id", "shape_id"), &CollisionObject3D::shape_owner_get_shape_index);
+ ClassDB::bind_method(D_METHOD("shape_owner_remove_shape", "owner_id", "shape_id"), &CollisionObject3D::shape_owner_remove_shape);
+ 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);
+
+ 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_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");
+}
+
+uint32_t CollisionObject3D::create_shape_owner(Object *p_owner) {
+
+ ShapeData sd;
+ uint32_t id;
+
+ if (shapes.size() == 0) {
+ id = 0;
+ } else {
+ id = shapes.back()->key() + 1;
+ }
+
+ sd.owner = p_owner;
+
+ shapes[id] = sd;
+
+ return id;
+}
+
+void CollisionObject3D::remove_shape_owner(uint32_t owner) {
+
+ ERR_FAIL_COND(!shapes.has(owner));
+
+ shape_owner_clear_shapes(owner);
+
+ shapes.erase(owner);
+}
+
+void CollisionObject3D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) {
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ ShapeData &sd = shapes[p_owner];
+ sd.disabled = p_disabled;
+ for (int i = 0; i < sd.shapes.size(); i++) {
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
+ }
+ }
+}
+
+bool CollisionObject3D::is_shape_owner_disabled(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), false);
+
+ return shapes[p_owner].disabled;
+}
+
+void CollisionObject3D::get_shape_owners(List<uint32_t> *r_owners) {
+
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ r_owners->push_back(E->key());
+ }
+}
+
+Array CollisionObject3D::_get_shape_owners() {
+
+ Array ret;
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+
+ return ret;
+}
+
+void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) {
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ ShapeData &sd = shapes[p_owner];
+ sd.xform = p_transform;
+ for (int i = 0; i < sd.shapes.size(); i++) {
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
+ }
+ }
+}
+Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Transform());
+
+ return shapes[p_owner].xform;
+}
+
+Object *CollisionObject3D::shape_owner_get_owner(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr);
+
+ return shapes[p_owner].owner;
+}
+
+void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3D> &p_shape) {
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+ ERR_FAIL_COND(p_shape.is_null());
+
+ ShapeData &sd = shapes[p_owner];
+ 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 {
+ PhysicsServer3D::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled);
+ }
+ sd.shapes.push_back(s);
+
+ total_subshapes++;
+}
+int CollisionObject3D::shape_owner_get_shape_count(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), 0);
+
+ return shapes[p_owner].shapes.size();
+}
+Ref<Shape3D> CollisionObject3D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape3D>());
+ ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape3D>());
+
+ return shapes[p_owner].shapes[p_shape].shape;
+}
+int CollisionObject3D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), -1);
+ ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1);
+
+ return shapes[p_owner].shapes[p_shape].index;
+}
+
+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;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_remove_shape(rid, index_to_remove);
+ } else {
+ PhysicsServer3D::get_singleton()->body_remove_shape(rid, index_to_remove);
+ }
+
+ shapes[p_owner].shapes.remove(p_shape);
+
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+ if (E->get().shapes[i].index > index_to_remove) {
+ E->get().shapes.write[i].index -= 1;
+ }
+ }
+ }
+
+ total_subshapes--;
+}
+
+void CollisionObject3D::shape_owner_clear_shapes(uint32_t p_owner) {
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ while (shape_owner_get_shape_count(p_owner) > 0) {
+ shape_owner_remove_shape(p_owner, 0);
+ }
+}
+
+uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const {
+
+ ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);
+
+ for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+ if (E->get().shapes[i].index == p_shape_index) {
+ return E->key();
+ }
+ }
+ }
+
+ //in theory it should be unreachable
+ return 0;
+}
+
+CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) {
+
+ rid = p_rid;
+ area = p_area;
+ capture_input_on_drag = false;
+ ray_pickable = true;
+ set_notify_transform(true);
+ total_subshapes = 0;
+
+ if (p_area) {
+ PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
+ } else {
+ PhysicsServer3D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
+ }
+ //set_transform_notify(true);
+}
+
+void CollisionObject3D::set_capture_input_on_drag(bool p_capture) {
+
+ capture_input_on_drag = p_capture;
+}
+
+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();
+
+ if (shapes.empty()) {
+ if (!warning.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.");
+ }
+
+ return warning;
+}
+
+CollisionObject3D::CollisionObject3D() {
+
+ capture_input_on_drag = false;
+ ray_pickable = true;
+ set_notify_transform(true);
+ //owner=
+
+ //set_transform_notify(true);
+}
+
+CollisionObject3D::~CollisionObject3D() {
+
+ PhysicsServer3D::get_singleton()->free(rid);
+}
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
new file mode 100644
index 0000000000..67d3aed3c8
--- /dev/null
+++ b/scene/3d/collision_object_3d.h
@@ -0,0 +1,119 @@
+/*************************************************************************/
+/* collision_object_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_OBJECT_3D_H
+#define COLLISION_OBJECT_3D_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/shape_3d.h"
+
+class CollisionObject3D : public Node3D {
+
+ GDCLASS(CollisionObject3D, Node3D);
+
+ bool area;
+
+ RID rid;
+
+ struct ShapeData {
+
+ Object *owner;
+ Transform xform;
+ struct ShapeBase {
+ Ref<Shape3D> shape;
+ int index;
+ };
+
+ Vector<ShapeBase> shapes;
+ bool disabled;
+
+ ShapeData() {
+ disabled = false;
+ owner = nullptr;
+ }
+ };
+
+ int total_subshapes;
+
+ Map<uint32_t, ShapeData> shapes;
+
+ bool capture_input_on_drag;
+ bool ray_pickable;
+
+ void _update_pickable();
+
+protected:
+ CollisionObject3D(RID p_rid, bool p_area);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ friend class Viewport;
+ virtual void _input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+ virtual void _mouse_enter();
+ virtual void _mouse_exit();
+
+public:
+ uint32_t create_shape_owner(Object *p_owner);
+ void remove_shape_owner(uint32_t owner);
+ void get_shape_owners(List<uint32_t> *r_owners);
+ Array _get_shape_owners();
+
+ void shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform);
+ Transform shape_owner_get_transform(uint32_t p_owner) const;
+ Object *shape_owner_get_owner(uint32_t p_owner) const;
+
+ void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled);
+ bool is_shape_owner_disabled(uint32_t p_owner) const;
+
+ void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3D> &p_shape);
+ int shape_owner_get_shape_count(uint32_t p_owner) const;
+ Ref<Shape3D> shape_owner_get_shape(uint32_t p_owner, int p_shape) const;
+ int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const;
+
+ void shape_owner_remove_shape(uint32_t p_owner, int p_shape);
+ void shape_owner_clear_shapes(uint32_t p_owner);
+
+ uint32_t shape_find_owner(int p_shape_index) const;
+
+ void set_ray_pickable(bool p_ray_pickable);
+ bool is_ray_pickable() const;
+
+ void set_capture_input_on_drag(bool p_capture);
+ bool get_capture_input_on_drag() const;
+
+ _FORCE_INLINE_ RID get_rid() const { return rid; }
+
+ virtual String get_configuration_warning() const;
+
+ CollisionObject3D();
+ ~CollisionObject3D();
+};
+
+#endif // COLLISION_OBJECT__H
diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp
deleted file mode 100644
index 636b859477..0000000000
--- a/scene/3d/collision_polygon.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/*************************************************************************/
-/* collision_polygon.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_polygon.h"
-
-#include "collision_object.h"
-#include "scene/resources/concave_polygon_shape.h"
-#include "scene/resources/convex_polygon_shape.h"
-
-void CollisionPolygon::_build_polygon() {
-
- if (!parent)
- return;
-
- parent->shape_owner_clear_shapes(owner_id);
-
- if (polygon.size() == 0)
- return;
-
- Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(polygon);
- if (decomp.size() == 0)
- return;
-
- //here comes the sun, lalalala
- //decompose concave into multiple convex polygons and add them
-
- for (int i = 0; i < decomp.size(); i++) {
- Ref<ConvexPolygonShape> convex = memnew(ConvexPolygonShape);
- Vector<Vector3> cp;
- int cs = decomp[i].size();
- cp.resize(cs * 2);
- {
- Vector3 *w = cp.ptrw();
- int idx = 0;
- for (int j = 0; j < cs; j++) {
-
- Vector2 d = decomp[i][j];
- w[idx++] = Vector3(d.x, d.y, depth * 0.5);
- w[idx++] = Vector3(d.x, d.y, -depth * 0.5);
- }
- }
-
- convex->set_points(cp);
- parent->shape_owner_add_shape(owner_id, convex);
- parent->shape_owner_set_disabled(owner_id, disabled);
- }
-}
-
-void CollisionPolygon::_update_in_shape_owner(bool p_xform_only) {
-
- parent->shape_owner_set_transform(owner_id, get_transform());
- if (p_xform_only)
- return;
- parent->shape_owner_set_disabled(owner_id, disabled);
-}
-
-void CollisionPolygon::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_PARENTED: {
- parent = Object::cast_to<CollisionObject>(get_parent());
- if (parent) {
- owner_id = parent->create_shape_owner(this);
- _build_polygon();
- _update_in_shape_owner();
- }
- } break;
- case NOTIFICATION_ENTER_TREE: {
-
- if (parent) {
- _update_in_shape_owner();
- }
-
- } break;
- case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
-
- if (parent) {
- _update_in_shape_owner(true);
- }
-
- } break;
- case NOTIFICATION_UNPARENTED: {
- if (parent) {
- parent->remove_shape_owner(owner_id);
- }
- owner_id = 0;
- parent = NULL;
- } break;
- }
-}
-
-void CollisionPolygon::set_polygon(const Vector<Point2> &p_polygon) {
-
- polygon = p_polygon;
- if (parent) {
- _build_polygon();
- }
- update_configuration_warning();
- update_gizmo();
-}
-
-Vector<Point2> CollisionPolygon::get_polygon() const {
-
- return polygon;
-}
-
-AABB CollisionPolygon::get_item_rect() const {
-
- return aabb;
-}
-
-void CollisionPolygon::set_depth(float p_depth) {
-
- depth = p_depth;
- _build_polygon();
- update_gizmo();
-}
-
-float CollisionPolygon::get_depth() const {
-
- return depth;
-}
-
-void CollisionPolygon::set_disabled(bool p_disabled) {
- disabled = p_disabled;
- update_gizmo();
-
- if (parent) {
- parent->shape_owner_set_disabled(owner_id, p_disabled);
- }
-}
-
-bool CollisionPolygon::is_disabled() const {
- return disabled;
-}
-
-String CollisionPolygon::get_configuration_warning() const {
-
- if (!Object::cast_to<CollisionObject>(get_parent())) {
- return TTR("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.");
- }
-
- if (polygon.empty()) {
- return TTR("An empty CollisionPolygon has no effect on collision.");
- }
-
- return String();
-}
-
-bool CollisionPolygon::_is_editable_3d_polygon() const {
- return true;
-}
-void CollisionPolygon::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth);
- ClassDB::bind_method(D_METHOD("get_depth"), &CollisionPolygon::get_depth);
-
- ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon::set_polygon);
- ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon::get_polygon);
-
- ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled);
- ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled);
-
- ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_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");
-}
-
-CollisionPolygon::CollisionPolygon() {
-
- aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
- depth = 1.0;
- set_notify_local_transform(true);
- parent = NULL;
- owner_id = 0;
- disabled = false;
-}
diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h
deleted file mode 100644
index 9ecdc02697..0000000000
--- a/scene/3d/collision_polygon.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*************************************************************************/
-/* collision_polygon.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_POLYGON_H
-#define COLLISION_POLYGON_H
-
-#include "scene/3d/spatial.h"
-#include "scene/resources/shape.h"
-
-class CollisionObject;
-class CollisionPolygon : public Spatial {
-
- GDCLASS(CollisionPolygon, Spatial);
-
-protected:
- float depth;
- AABB aabb;
- Vector<Point2> polygon;
-
- uint32_t owner_id;
- CollisionObject *parent;
-
- bool disabled;
-
- void _build_polygon();
-
- void _update_in_shape_owner(bool p_xform_only = false);
-
- bool _is_editable_3d_polygon() const;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_depth(float p_depth);
- float get_depth() const;
-
- void set_polygon(const Vector<Point2> &p_polygon);
- Vector<Point2> get_polygon() const;
-
- void set_disabled(bool p_disabled);
- bool is_disabled() const;
-
- virtual AABB get_item_rect() const;
-
- String get_configuration_warning() const;
-
- CollisionPolygon();
-};
-
-#endif // COLLISION_POLYGON_H
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
new file mode 100644
index 0000000000..66bd903eeb
--- /dev/null
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -0,0 +1,207 @@
+/*************************************************************************/
+/* collision_polygon_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_polygon_3d.h"
+
+#include "collision_object_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
+
+void CollisionPolygon3D::_build_polygon() {
+
+ if (!parent)
+ return;
+
+ parent->shape_owner_clear_shapes(owner_id);
+
+ if (polygon.size() == 0)
+ return;
+
+ Vector<Vector<Vector2>> decomp = Geometry::decompose_polygon_in_convex(polygon);
+ if (decomp.size() == 0)
+ return;
+
+ //here comes the sun, lalalala
+ //decompose concave into multiple convex polygons and add them
+
+ for (int i = 0; i < decomp.size(); i++) {
+ Ref<ConvexPolygonShape3D> convex = memnew(ConvexPolygonShape3D);
+ Vector<Vector3> cp;
+ int cs = decomp[i].size();
+ cp.resize(cs * 2);
+ {
+ Vector3 *w = cp.ptrw();
+ int idx = 0;
+ for (int j = 0; j < cs; j++) {
+
+ Vector2 d = decomp[i][j];
+ w[idx++] = Vector3(d.x, d.y, depth * 0.5);
+ w[idx++] = Vector3(d.x, d.y, -depth * 0.5);
+ }
+ }
+
+ convex->set_points(cp);
+ parent->shape_owner_add_shape(owner_id, convex);
+ parent->shape_owner_set_disabled(owner_id, disabled);
+ }
+}
+
+void CollisionPolygon3D::_update_in_shape_owner(bool p_xform_only) {
+
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ if (p_xform_only)
+ return;
+ parent->shape_owner_set_disabled(owner_id, disabled);
+}
+
+void CollisionPolygon3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_PARENTED: {
+ parent = Object::cast_to<CollisionObject3D>(get_parent());
+ if (parent) {
+ owner_id = parent->create_shape_owner(this);
+ _build_polygon();
+ _update_in_shape_owner();
+ }
+ } break;
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (parent) {
+ _update_in_shape_owner();
+ }
+
+ } break;
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+
+ if (parent) {
+ _update_in_shape_owner(true);
+ }
+
+ } break;
+ case NOTIFICATION_UNPARENTED: {
+ if (parent) {
+ parent->remove_shape_owner(owner_id);
+ }
+ owner_id = 0;
+ parent = nullptr;
+ } break;
+ }
+}
+
+void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {
+
+ polygon = p_polygon;
+ if (parent) {
+ _build_polygon();
+ }
+ update_configuration_warning();
+ update_gizmo();
+}
+
+Vector<Point2> CollisionPolygon3D::get_polygon() const {
+
+ return polygon;
+}
+
+AABB CollisionPolygon3D::get_item_rect() const {
+
+ return aabb;
+}
+
+void CollisionPolygon3D::set_depth(float p_depth) {
+
+ depth = p_depth;
+ _build_polygon();
+ update_gizmo();
+}
+
+float CollisionPolygon3D::get_depth() const {
+
+ return depth;
+}
+
+void CollisionPolygon3D::set_disabled(bool p_disabled) {
+ disabled = p_disabled;
+ update_gizmo();
+
+ if (parent) {
+ parent->shape_owner_set_disabled(owner_id, p_disabled);
+ }
+}
+
+bool CollisionPolygon3D::is_disabled() const {
+ return disabled;
+}
+
+String CollisionPolygon3D::get_configuration_warning() const {
+
+ if (!Object::cast_to<CollisionObject3D>(get_parent())) {
+ return 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.empty()) {
+ return TTR("An empty CollisionPolygon3D has no effect on collision.");
+ }
+
+ return String();
+}
+
+bool CollisionPolygon3D::_is_editable_3d_polygon() const {
+ return true;
+}
+void CollisionPolygon3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon3D::set_depth);
+ ClassDB::bind_method(D_METHOD("get_depth"), &CollisionPolygon3D::get_depth);
+
+ ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon3D::set_polygon);
+ ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon3D::get_polygon);
+
+ 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("_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");
+}
+
+CollisionPolygon3D::CollisionPolygon3D() {
+
+ aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ depth = 1.0;
+ set_notify_local_transform(true);
+ parent = nullptr;
+ owner_id = 0;
+ disabled = false;
+}
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
new file mode 100644
index 0000000000..256aee3d7e
--- /dev/null
+++ b/scene/3d/collision_polygon_3d.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* collision_polygon_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_POLYGON_3D_H
+#define COLLISION_POLYGON_3D_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/shape_3d.h"
+
+class CollisionObject3D;
+class CollisionPolygon3D : public Node3D {
+
+ GDCLASS(CollisionPolygon3D, Node3D);
+
+protected:
+ float depth;
+ AABB aabb;
+ Vector<Point2> polygon;
+
+ uint32_t owner_id;
+ CollisionObject3D *parent;
+
+ bool disabled;
+
+ void _build_polygon();
+
+ void _update_in_shape_owner(bool p_xform_only = false);
+
+ bool _is_editable_3d_polygon() const;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_depth(float p_depth);
+ float get_depth() const;
+
+ void set_polygon(const Vector<Point2> &p_polygon);
+ Vector<Point2> get_polygon() const;
+
+ void set_disabled(bool p_disabled);
+ bool is_disabled() const;
+
+ virtual AABB get_item_rect() const;
+
+ String get_configuration_warning() const;
+
+ CollisionPolygon3D();
+};
+
+#endif // COLLISION_POLYGON_H
diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp
deleted file mode 100644
index d825c8daf7..0000000000
--- a/scene/3d/collision_shape.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*************************************************************************/
-/* collision_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_shape.h"
-#include "scene/resources/box_shape.h"
-#include "scene/resources/capsule_shape.h"
-#include "scene/resources/concave_polygon_shape.h"
-#include "scene/resources/convex_polygon_shape.h"
-#include "scene/resources/ray_shape.h"
-#include "scene/resources/sphere_shape.h"
-#include "scene/resources/world_margin_shape.h"
-#include "servers/visual_server.h"
-//TODO: Implement CylinderShape and HeightMapShape?
-#include "core/math/quick_hull.h"
-#include "mesh_instance.h"
-#include "physics_body.h"
-
-void CollisionShape::make_convex_from_brothers() {
-
- Node *p = get_parent();
- if (!p)
- return;
-
- for (int i = 0; i < p->get_child_count(); i++) {
-
- Node *n = p->get_child(i);
- MeshInstance *mi = Object::cast_to<MeshInstance>(n);
- if (mi) {
-
- Ref<Mesh> m = mi->get_mesh();
- if (m.is_valid()) {
-
- Ref<Shape> s = m->create_convex_shape();
- set_shape(s);
- }
- }
- }
-}
-
-void CollisionShape::_update_in_shape_owner(bool p_xform_only) {
- parent->shape_owner_set_transform(owner_id, get_transform());
- if (p_xform_only)
- return;
- parent->shape_owner_set_disabled(owner_id, disabled);
-}
-
-void CollisionShape::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_PARENTED: {
- parent = Object::cast_to<CollisionObject>(get_parent());
- if (parent) {
- owner_id = parent->create_shape_owner(this);
- if (shape.is_valid()) {
- parent->shape_owner_add_shape(owner_id, shape);
- }
- _update_in_shape_owner();
- }
- } break;
- case NOTIFICATION_ENTER_TREE: {
- if (parent) {
- _update_in_shape_owner();
- }
- if (get_tree()->is_debugging_collisions_hint()) {
- _update_debug_shape();
- }
- } break;
- case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (parent) {
- _update_in_shape_owner(true);
- }
- } break;
- case NOTIFICATION_UNPARENTED: {
- if (parent) {
- parent->remove_shape_owner(owner_id);
- }
- owner_id = 0;
- parent = NULL;
- } break;
- }
-}
-
-void CollisionShape::resource_changed(RES res) {
-
- update_gizmo();
-}
-
-String CollisionShape::get_configuration_warning() const {
-
- if (!Object::cast_to<CollisionObject>(get_parent())) {
- return TTR("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.");
- }
-
- if (!shape.is_valid()) {
- return TTR("A shape must be provided for CollisionShape to function. Please create a shape resource for it.");
- }
-
- if (Object::cast_to<RigidBody>(get_parent())) {
- if (Object::cast_to<ConcavePolygonShape>(*shape)) {
- if (Object::cast_to<RigidBody>(get_parent())->get_mode() != RigidBody::MODE_STATIC) {
- return TTR("ConcavePolygonShape doesn't support RigidBody in another mode than static.");
- }
- }
- }
-
- return String();
-}
-
-void CollisionShape::_bind_methods() {
-
- //not sure if this should do anything
- ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &CollisionShape::resource_changed);
- ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape::set_shape);
- ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape::get_shape);
- ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape::set_disabled);
- ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape::is_disabled);
- ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape::make_convex_from_brothers);
- ClassDB::set_method_flags("CollisionShape", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
-
- ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape::_update_debug_shape);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
-}
-
-void CollisionShape::set_shape(const Ref<Shape> &p_shape) {
-
- if (!shape.is_null()) {
- shape->unregister_owner(this);
- shape->disconnect("changed", callable_mp(this, &CollisionShape::_shape_changed));
- }
- shape = p_shape;
- if (!shape.is_null()) {
- shape->register_owner(this);
- shape->connect("changed", callable_mp(this, &CollisionShape::_shape_changed));
- }
- update_gizmo();
- if (parent) {
- parent->shape_owner_clear_shapes(owner_id);
- if (shape.is_valid()) {
- parent->shape_owner_add_shape(owner_id, shape);
- }
- }
-
- if (is_inside_tree())
- _shape_changed();
- update_configuration_warning();
-}
-
-Ref<Shape> CollisionShape::get_shape() const {
-
- return shape;
-}
-
-void CollisionShape::set_disabled(bool p_disabled) {
-
- disabled = p_disabled;
- update_gizmo();
- if (parent) {
- parent->shape_owner_set_disabled(owner_id, p_disabled);
- }
-}
-
-bool CollisionShape::is_disabled() const {
-
- return disabled;
-}
-
-CollisionShape::CollisionShape() {
-
- //indicator = VisualServer::get_singleton()->mesh_create();
- disabled = false;
- debug_shape = NULL;
- parent = NULL;
- owner_id = 0;
- set_notify_local_transform(true);
-}
-
-CollisionShape::~CollisionShape() {
- if (!shape.is_null())
- shape->unregister_owner(this);
- //VisualServer::get_singleton()->free(indicator);
-}
-
-void CollisionShape::_update_debug_shape() {
- debug_shape_dirty = false;
-
- if (debug_shape) {
- debug_shape->queue_delete();
- debug_shape = NULL;
- }
-
- Ref<Shape> s = get_shape();
- if (s.is_null())
- return;
-
- Ref<Mesh> mesh = s->get_debug_mesh();
- MeshInstance *mi = memnew(MeshInstance);
- mi->set_mesh(mesh);
- add_child(mi);
- debug_shape = mi;
-}
-
-void CollisionShape::_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.h b/scene/3d/collision_shape.h
deleted file mode 100644
index 3150a41ebf..0000000000
--- a/scene/3d/collision_shape.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* collision_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_SHAPE_H
-#define COLLISION_SHAPE_H
-
-#include "scene/3d/spatial.h"
-#include "scene/resources/shape.h"
-class CollisionObject;
-class CollisionShape : public Spatial {
-
- GDCLASS(CollisionShape, Spatial);
- OBJ_CATEGORY("3D Physics Nodes");
-
- Ref<Shape> shape;
-
- uint32_t owner_id;
- CollisionObject *parent;
-
- Node *debug_shape;
- bool debug_shape_dirty;
-
- void resource_changed(RES res);
- bool disabled;
-
-protected:
- void _update_debug_shape();
- void _shape_changed();
-
- void _update_in_shape_owner(bool p_xform_only = false);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void make_convex_from_brothers();
-
- void set_shape(const Ref<Shape> &p_shape);
- Ref<Shape> get_shape() const;
-
- void set_disabled(bool p_disabled);
- bool is_disabled() const;
-
- String get_configuration_warning() const;
-
- CollisionShape();
- ~CollisionShape();
-};
-
-#endif // BODY_VOLUME_H
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
new file mode 100644
index 0000000000..a66e84ac3c
--- /dev/null
+++ b/scene/3d/collision_shape_3d.cpp
@@ -0,0 +1,244 @@
+/*************************************************************************/
+/* collision_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_shape_3d.h"
+
+#include "core/math/quick_hull.h"
+#include "mesh_instance_3d.h"
+#include "physics_body_3d.h"
+#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/capsule_shape_3d.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
+#include "scene/resources/ray_shape_3d.h"
+#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/world_margin_shape_3d.h"
+#include "servers/rendering_server.h"
+
+//TODO: Implement CylinderShape and HeightMapShape?
+
+void CollisionShape3D::make_convex_from_brothers() {
+
+ Node *p = get_parent();
+ if (!p)
+ return;
+
+ for (int i = 0; i < p->get_child_count(); i++) {
+
+ Node *n = p->get_child(i);
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(n);
+ if (mi) {
+
+ Ref<Mesh> m = mi->get_mesh();
+ if (m.is_valid()) {
+
+ Ref<Shape3D> s = m->create_convex_shape();
+ set_shape(s);
+ }
+ }
+ }
+}
+
+void CollisionShape3D::_update_in_shape_owner(bool p_xform_only) {
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ if (p_xform_only)
+ return;
+ parent->shape_owner_set_disabled(owner_id, disabled);
+}
+
+void CollisionShape3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_PARENTED: {
+ parent = Object::cast_to<CollisionObject3D>(get_parent());
+ if (parent) {
+ owner_id = parent->create_shape_owner(this);
+ if (shape.is_valid()) {
+ parent->shape_owner_add_shape(owner_id, shape);
+ }
+ _update_in_shape_owner();
+ }
+ } break;
+ case NOTIFICATION_ENTER_TREE: {
+ if (parent) {
+ _update_in_shape_owner();
+ }
+ if (get_tree()->is_debugging_collisions_hint()) {
+ _update_debug_shape();
+ }
+ } break;
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ if (parent) {
+ _update_in_shape_owner(true);
+ }
+ } break;
+ case NOTIFICATION_UNPARENTED: {
+ if (parent) {
+ parent->remove_shape_owner(owner_id);
+ }
+ owner_id = 0;
+ parent = nullptr;
+ } break;
+ }
+}
+
+void CollisionShape3D::resource_changed(RES res) {
+
+ update_gizmo();
+}
+
+String CollisionShape3D::get_configuration_warning() const {
+
+ if (!Object::cast_to<CollisionObject3D>(get_parent())) {
+ return 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()) {
+ return TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
+ }
+
+ if (Object::cast_to<RigidBody3D>(get_parent())) {
+ if (Object::cast_to<ConcavePolygonShape3D>(*shape)) {
+ if (Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
+ return TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
+ }
+ }
+ }
+
+ return String();
+}
+
+void CollisionShape3D::_bind_methods() {
+
+ //not sure if this should do anything
+ ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &CollisionShape3D::resource_changed);
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape3D::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape3D::get_shape);
+ ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape3D::set_disabled);
+ ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape3D::is_disabled);
+ ClassDB::bind_method(D_METHOD("make_convex_from_brothers"), &CollisionShape3D::make_convex_from_brothers);
+ ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_brothers", 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");
+}
+
+void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
+
+ if (!shape.is_null()) {
+ shape->unregister_owner(this);
+ shape->disconnect("changed", callable_mp(this, &CollisionShape3D::_shape_changed));
+ }
+ shape = p_shape;
+ if (!shape.is_null()) {
+ shape->register_owner(this);
+ shape->connect("changed", callable_mp(this, &CollisionShape3D::_shape_changed));
+ }
+ update_gizmo();
+ if (parent) {
+ parent->shape_owner_clear_shapes(owner_id);
+ if (shape.is_valid()) {
+ parent->shape_owner_add_shape(owner_id, shape);
+ }
+ }
+
+ if (is_inside_tree())
+ _shape_changed();
+ update_configuration_warning();
+}
+
+Ref<Shape3D> CollisionShape3D::get_shape() const {
+
+ return shape;
+}
+
+void CollisionShape3D::set_disabled(bool p_disabled) {
+
+ disabled = p_disabled;
+ update_gizmo();
+ if (parent) {
+ parent->shape_owner_set_disabled(owner_id, p_disabled);
+ }
+}
+
+bool CollisionShape3D::is_disabled() const {
+
+ return disabled;
+}
+
+CollisionShape3D::CollisionShape3D() {
+
+ //indicator = RenderingServer::get_singleton()->mesh_create();
+ disabled = false;
+ debug_shape = nullptr;
+ parent = nullptr;
+ owner_id = 0;
+ set_notify_local_transform(true);
+}
+
+CollisionShape3D::~CollisionShape3D() {
+ if (!shape.is_null())
+ shape->unregister_owner(this);
+ //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
new file mode 100644
index 0000000000..8515d292af
--- /dev/null
+++ b/scene/3d/collision_shape_3d.h
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* collision_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_SHAPE_H
+#define COLLISION_SHAPE_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/shape_3d.h"
+class CollisionObject3D;
+class CollisionShape3D : public Node3D {
+
+ GDCLASS(CollisionShape3D, Node3D);
+ OBJ_CATEGORY("3D Physics Nodes");
+
+ Ref<Shape3D> shape;
+
+ uint32_t owner_id;
+ CollisionObject3D *parent;
+
+ Node *debug_shape;
+ bool debug_shape_dirty;
+
+ void resource_changed(RES res);
+ bool disabled;
+
+protected:
+ void _update_debug_shape();
+ void _shape_changed();
+
+ void _update_in_shape_owner(bool p_xform_only = false);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void make_convex_from_brothers();
+
+ void set_shape(const Ref<Shape3D> &p_shape);
+ Ref<Shape3D> get_shape() const;
+
+ void set_disabled(bool p_disabled);
+ bool is_disabled() const;
+
+ String get_configuration_warning() const;
+
+ CollisionShape3D();
+ ~CollisionShape3D();
+};
+
+#endif // BODY_VOLUME_H
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
deleted file mode 100644
index bde578d0af..0000000000
--- a/scene/3d/cpu_particles.cpp
+++ /dev/null
@@ -1,1546 +0,0 @@
-/*************************************************************************/
-/* cpu_particles.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "cpu_particles.h"
-
-#include "scene/3d/camera.h"
-#include "scene/3d/particles.h"
-#include "scene/resources/particles_material.h"
-#include "servers/visual_server.h"
-
-AABB CPUParticles::get_aabb() const {
-
- return AABB();
-}
-Vector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
-
- return Vector<Face3>();
-}
-
-void CPUParticles::set_emitting(bool p_emitting) {
-
- if (emitting == p_emitting)
- return;
-
- emitting = p_emitting;
- if (emitting) {
- set_process_internal(true);
-
- // first update before rendering to avoid one frame delay after emitting starts
- if (time == 0)
- _update_internal();
- }
-}
-
-void CPUParticles::set_amount(int p_amount) {
-
- ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0.");
-
- particles.resize(p_amount);
- {
- Particle *w = particles.ptrw();
-
- for (int i = 0; i < p_amount; i++) {
- w[i].active = false;
- }
- }
-
- particle_data.resize((12 + 4 + 4) * p_amount);
- VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_3D, true, true);
-
- particle_order.resize(p_amount);
-}
-void CPUParticles::set_lifetime(float p_lifetime) {
-
- ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
- lifetime = p_lifetime;
-}
-
-void CPUParticles::set_one_shot(bool p_one_shot) {
-
- one_shot = p_one_shot;
-}
-
-void CPUParticles::set_pre_process_time(float p_time) {
-
- pre_process_time = p_time;
-}
-void CPUParticles::set_explosiveness_ratio(float p_ratio) {
-
- explosiveness_ratio = p_ratio;
-}
-void CPUParticles::set_randomness_ratio(float p_ratio) {
-
- randomness_ratio = p_ratio;
-}
-void CPUParticles::set_lifetime_randomness(float p_random) {
-
- lifetime_randomness = p_random;
-}
-void CPUParticles::set_use_local_coordinates(bool p_enable) {
-
- local_coords = p_enable;
-}
-void CPUParticles::set_speed_scale(float p_scale) {
-
- speed_scale = p_scale;
-}
-
-bool CPUParticles::is_emitting() const {
-
- return emitting;
-}
-int CPUParticles::get_amount() const {
-
- return particles.size();
-}
-float CPUParticles::get_lifetime() const {
-
- return lifetime;
-}
-bool CPUParticles::get_one_shot() const {
-
- return one_shot;
-}
-
-float CPUParticles::get_pre_process_time() const {
-
- return pre_process_time;
-}
-float CPUParticles::get_explosiveness_ratio() const {
-
- return explosiveness_ratio;
-}
-float CPUParticles::get_randomness_ratio() const {
-
- return randomness_ratio;
-}
-float CPUParticles::get_lifetime_randomness() const {
-
- return lifetime_randomness;
-}
-
-bool CPUParticles::get_use_local_coordinates() const {
-
- return local_coords;
-}
-
-float CPUParticles::get_speed_scale() const {
-
- return speed_scale;
-}
-
-void CPUParticles::set_draw_order(DrawOrder p_order) {
-
- draw_order = p_order;
-}
-
-CPUParticles::DrawOrder CPUParticles::get_draw_order() const {
-
- return draw_order;
-}
-
-void CPUParticles::set_mesh(const Ref<Mesh> &p_mesh) {
-
- mesh = p_mesh;
- if (mesh.is_valid()) {
- VS::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid());
- } else {
- VS::get_singleton()->multimesh_set_mesh(multimesh, RID());
- }
-}
-
-Ref<Mesh> CPUParticles::get_mesh() const {
-
- return mesh;
-}
-
-void CPUParticles::set_fixed_fps(int p_count) {
- fixed_fps = p_count;
-}
-
-int CPUParticles::get_fixed_fps() const {
- return fixed_fps;
-}
-
-void CPUParticles::set_fractional_delta(bool p_enable) {
- fractional_delta = p_enable;
-}
-
-bool CPUParticles::get_fractional_delta() const {
- return fractional_delta;
-}
-
-String CPUParticles::get_configuration_warning() const {
-
- String warnings;
-
- bool mesh_found = false;
- bool anim_material_found = false;
-
- if (get_mesh().is_valid()) {
- mesh_found = true;
- for (int j = 0; j < get_mesh()->get_surface_count(); j++) {
- anim_material_found = Object::cast_to<ShaderMaterial>(get_mesh()->surface_get_material(j).ptr()) != NULL;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_mesh()->surface_get_material(j).ptr());
- anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
- }
- }
-
- anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != NULL;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
- 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.");
- }
-
- 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("CPUParticles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
- }
-
- return warnings;
-}
-
-void CPUParticles::restart() {
-
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- emitting = false;
-
- {
- int pc = particles.size();
- Particle *w = particles.ptrw();
-
- for (int i = 0; i < pc; i++) {
- w[i].active = false;
- }
- }
-
- set_emitting(true);
-}
-
-void CPUParticles::set_direction(Vector3 p_direction) {
-
- direction = p_direction;
-}
-
-Vector3 CPUParticles::get_direction() const {
-
- return direction;
-}
-
-void CPUParticles::set_spread(float p_spread) {
-
- spread = p_spread;
-}
-
-float CPUParticles::get_spread() const {
-
- return spread;
-}
-
-void CPUParticles::set_flatness(float p_flatness) {
-
- flatness = p_flatness;
-}
-float CPUParticles::get_flatness() const {
-
- return flatness;
-}
-
-void CPUParticles::set_param(Parameter p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- parameters[p_param] = p_value;
-}
-float CPUParticles::get_param(Parameter p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
-
- return parameters[p_param];
-}
-
-void CPUParticles::set_param_randomness(Parameter p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- randomness[p_param] = p_value;
-}
-float CPUParticles::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) {
-
- Ref<Curve> curve = p_curve;
- if (!curve.is_valid())
- return;
-
- curve->ensure_default_setup(p_min, p_max);
-}
-
-void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- curve_parameters[p_param] = p_curve;
-
- switch (p_param) {
- case PARAM_INITIAL_LINEAR_VELOCITY: {
- //do none for this one
- } break;
- case PARAM_ANGULAR_VELOCITY: {
- _adjust_curve_range(p_curve, -360, 360);
- } break;
- case PARAM_ORBIT_VELOCITY: {
- _adjust_curve_range(p_curve, -500, 500);
- } break;
- case PARAM_LINEAR_ACCEL: {
- _adjust_curve_range(p_curve, -200, 200);
- } break;
- case PARAM_RADIAL_ACCEL: {
- _adjust_curve_range(p_curve, -200, 200);
- } break;
- case PARAM_TANGENTIAL_ACCEL: {
- _adjust_curve_range(p_curve, -200, 200);
- } break;
- case PARAM_DAMPING: {
- _adjust_curve_range(p_curve, 0, 100);
- } break;
- case PARAM_ANGLE: {
- _adjust_curve_range(p_curve, -360, 360);
- } break;
- case PARAM_SCALE: {
-
- } break;
- case PARAM_HUE_VARIATION: {
- _adjust_curve_range(p_curve, -1, 1);
- } break;
- case PARAM_ANIM_SPEED: {
- _adjust_curve_range(p_curve, 0, 200);
- } break;
- case PARAM_ANIM_OFFSET: {
- } break;
- default: {
- }
- }
-}
-Ref<Curve> CPUParticles::get_param_curve(Parameter p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>());
-
- return curve_parameters[p_param];
-}
-
-void CPUParticles::set_color(const Color &p_color) {
-
- color = p_color;
-}
-
-Color CPUParticles::get_color() const {
-
- return color;
-}
-
-void CPUParticles::set_color_ramp(const Ref<Gradient> &p_ramp) {
-
- color_ramp = p_ramp;
-}
-
-Ref<Gradient> CPUParticles::get_color_ramp() const {
-
- return color_ramp;
-}
-
-void CPUParticles::set_particle_flag(Flags p_flag, bool p_enable) {
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- flags[p_flag] = p_enable;
- if (p_flag == FLAG_DISABLE_Z) {
- _change_notify();
- }
-}
-
-bool CPUParticles::get_particle_flag(Flags p_flag) const {
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
-}
-
-void CPUParticles::set_emission_shape(EmissionShape p_shape) {
- ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
- emission_shape = p_shape;
-}
-
-void CPUParticles::set_emission_sphere_radius(float p_radius) {
-
- emission_sphere_radius = p_radius;
-}
-
-void CPUParticles::set_emission_box_extents(Vector3 p_extents) {
-
- emission_box_extents = p_extents;
-}
-
-void CPUParticles::set_emission_points(const Vector<Vector3> &p_points) {
-
- emission_points = p_points;
-}
-
-void CPUParticles::set_emission_normals(const Vector<Vector3> &p_normals) {
-
- emission_normals = p_normals;
-}
-
-void CPUParticles::set_emission_colors(const Vector<Color> &p_colors) {
-
- emission_colors = p_colors;
-}
-
-float CPUParticles::get_emission_sphere_radius() const {
-
- return emission_sphere_radius;
-}
-Vector3 CPUParticles::get_emission_box_extents() const {
-
- return emission_box_extents;
-}
-Vector<Vector3> CPUParticles::get_emission_points() const {
-
- return emission_points;
-}
-Vector<Vector3> CPUParticles::get_emission_normals() const {
-
- return emission_normals;
-}
-
-Vector<Color> CPUParticles::get_emission_colors() const {
-
- return emission_colors;
-}
-
-CPUParticles::EmissionShape CPUParticles::get_emission_shape() const {
- return emission_shape;
-}
-void CPUParticles::set_gravity(const Vector3 &p_gravity) {
-
- gravity = p_gravity;
-}
-
-Vector3 CPUParticles::get_gravity() const {
-
- return gravity;
-}
-
-void CPUParticles::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "color" && color_ramp.is_valid()) {
- property.usage = 0;
- }
-
- if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
- property.usage = 0;
- }
-
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = 0;
- }
-
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
- property.usage = 0;
- }
-
- if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = 0;
- }
-
- if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
- property.usage = 0;
- }
-}
-
-static uint32_t idhash(uint32_t x) {
-
- x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
- x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
- x = (x >> uint32_t(16)) ^ x;
- return x;
-}
-
-static float rand_from_seed(uint32_t &seed) {
- int k;
- int s = int(seed);
- if (s == 0)
- s = 305420679;
- k = s / 127773;
- s = 16807 * (s - k * 127773) - 2836 * k;
- if (s < 0)
- s += 2147483647;
- seed = uint32_t(s);
- return float(seed % uint32_t(65536)) / 65535.0;
-}
-
-void CPUParticles::_update_internal() {
-
- if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
- return;
- }
-
- float delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
-
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
- }
- _set_redraw(true);
-
- bool processed = false;
-
- if (time == 0 && pre_process_time > 0.0) {
-
- float frame_time;
- if (fixed_fps > 0)
- frame_time = 1.0 / fixed_fps;
- else
- frame_time = 1.0 / 30.0;
-
- float todo = pre_process_time;
-
- while (todo >= 0) {
- _particles_process(frame_time);
- processed = true;
- todo -= frame_time;
- }
- }
-
- if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
-
- float ldelta = delta;
- if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
- ldelta = 0.1;
- } else if (ldelta <= 0.0) { //unlikely but..
- ldelta = 0.001;
- }
- float todo = frame_remainder + ldelta;
-
- while (todo >= frame_time) {
- _particles_process(frame_time);
- processed = true;
- todo -= decr;
- }
-
- frame_remainder = todo;
-
- } else {
- _particles_process(delta);
- processed = true;
- }
-
- if (processed) {
- _update_particle_data_buffer();
- }
-}
-
-void CPUParticles::_particles_process(float p_delta) {
-
- p_delta *= speed_scale;
-
- int pcount = particles.size();
- Particle *w = particles.ptrw();
-
- Particle *parray = w;
-
- float prev_time = time;
- time += p_delta;
- if (time > lifetime) {
- time = Math::fmod(time, lifetime);
- cycle++;
- if (one_shot && cycle > 0) {
- set_emitting(false);
- _change_notify();
- }
- }
-
- Transform emission_xform;
- Basis velocity_xform;
- if (!local_coords) {
- emission_xform = get_global_transform();
- velocity_xform = emission_xform.basis;
- }
-
- float system_phase = time / lifetime;
-
- for (int i = 0; i < pcount; i++) {
-
- Particle &p = parray[i];
-
- if (!emitting && !p.active)
- continue;
-
- float local_delta = 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);
-
- if (randomness_ratio > 0.0) {
- uint32_t seed = cycle;
- if (restart_phase >= system_phase) {
- seed -= uint32_t(1);
- }
- 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);
- }
-
- restart_phase *= (1.0 - explosiveness_ratio);
- float restart_time = restart_phase * lifetime;
- bool restart = false;
-
- if (time > prev_time) {
- // restart_time >= prev_time is used so particles emit in the first frame they are processed
-
- if (restart_time >= prev_time && restart_time < time) {
- restart = true;
- if (fractional_delta) {
- local_delta = time - restart_time;
- }
- }
-
- } else if (local_delta > 0.0) {
- if (restart_time >= prev_time) {
- restart = true;
- if (fractional_delta) {
- local_delta = lifetime - restart_time + time;
- }
-
- } else if (restart_time < time) {
- restart = true;
- if (fractional_delta) {
- local_delta = time - restart_time;
- }
- }
- }
-
- if (p.time * (1.0 - explosiveness_ratio) > p.lifetime) {
- restart = true;
- }
-
- if (restart) {
-
- if (!emitting) {
- p.active = false;
- continue;
- }
- p.active = true;
-
- /*float 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;
- if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0);
- }
-
- float tex_anim_offset = 0.0;
- if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0);
- }
-
- p.seed = Math::rand();
-
- p.angle_rand = Math::randf();
- p.scale_rand = Math::randf();
- p.hue_rot_rand = Math::randf();
- p.anim_offset_rand = Math::randf();
-
- if (flags[FLAG_DISABLE_Z]) {
- float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
- Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
- } else {
- //initiate velocity spread in 3D
- float angle1_rad = Math::atan2(direction.x, direction.z) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
- float angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0;
-
- Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad));
- Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad));
- direction_yz.z = direction_yz.z / MAX(0.0001, Math::sqrt(ABS(direction_yz.z))); //better uniform distribution
- Vector3 direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
- direction.normalize();
- p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(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]);
- p.custom[0] = Math::deg2rad(base_angle); //angle
- p.custom[1] = 0.0; //phase
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
- p.transform = Transform();
- p.time = 0;
- p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
- p.base_color = Color(1, 1, 1, 1);
-
- switch (emission_shape) {
- case EMISSION_SHAPE_POINT: {
- //do none
- } break;
- case EMISSION_SHAPE_SPHERE: {
- float s = 2.0 * Math::randf() - 1.0, t = 2.0 * Math_PI * Math::randf();
- float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
- p.transform.origin = Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s);
- } break;
- case EMISSION_SHAPE_BOX: {
- p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_box_extents;
- } break;
- case EMISSION_SHAPE_POINTS:
- case EMISSION_SHAPE_DIRECTED_POINTS: {
-
- int pc = emission_points.size();
- if (pc == 0)
- break;
-
- int random_idx = Math::rand() % pc;
-
- p.transform.origin = emission_points.get(random_idx);
-
- if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
- if (flags[FLAG_DISABLE_Z]) {
- /*
- mat2 rotm;
- ";
- rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;
- rotm[1] = rotm[0].yx * vec2(1.0, -1.0);
- VELOCITY.xy = rotm * VELOCITY.xy;
- */
- } else {
- Vector3 normal = emission_normals.get(random_idx);
- Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0);
- Vector3 tangent = v0.cross(normal).normalized();
- Vector3 bitangent = tangent.cross(normal).normalized();
- Basis m3;
- m3.set_axis(0, tangent);
- m3.set_axis(1, bitangent);
- m3.set_axis(2, normal);
- p.velocity = m3.xform(p.velocity);
- }
- }
-
- if (emission_colors.size() == pc) {
- p.base_color = emission_colors.get(random_idx);
- }
- } break;
- case EMISSION_SHAPE_MAX: { // Max value for validity check.
- break;
- }
- }
-
- if (!local_coords) {
- p.velocity = velocity_xform.xform(p.velocity);
- p.transform = emission_xform * p.transform;
- }
-
- if (flags[FLAG_DISABLE_Z]) {
- p.velocity.z = 0.0;
- p.transform.origin.z = 0.0;
- }
-
- } else if (!p.active) {
- continue;
- } else if (p.time > p.lifetime) {
- p.active = false;
- } else {
-
- uint32_t alt_seed = p.seed;
-
- p.time += local_delta;
- p.custom[1] = p.time / lifetime;
-
- float tex_linear_velocity = 0.0;
- if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]);
- }
-
- float tex_orbit_velocity = 0.0;
- if (flags[FLAG_DISABLE_Z]) {
- if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
- tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]);
- }
- }
-
- float tex_angular_velocity = 0.0;
- if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
- tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]);
- }
-
- float tex_linear_accel = 0.0;
- if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
- tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]);
- }
-
- float tex_tangential_accel = 0.0;
- if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
- tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]);
- }
-
- float tex_radial_accel = 0.0;
- if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
- tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]);
- }
-
- float tex_damping = 0.0;
- if (curve_parameters[PARAM_DAMPING].is_valid()) {
- tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]);
- }
-
- float tex_angle = 0.0;
- if (curve_parameters[PARAM_ANGLE].is_valid()) {
- tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]);
- }
- float tex_anim_speed = 0.0;
- if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
- tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]);
- }
-
- float tex_anim_offset = 0.0;
- if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]);
- }
-
- Vector3 force = gravity;
- Vector3 position = p.transform.origin;
- if (flags[FLAG_DISABLE_Z]) {
- position.z = 0.0;
- }
- //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]) : Vector3();
- //apply radial acceleration
- Vector3 org = emission_xform.origin;
- Vector3 diff = position - 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]) : Vector3();
- //apply tangential acceleration;
- if (flags[FLAG_DISABLE_Z]) {
-
- Vector2 yx = Vector2(diff.y, diff.x);
- Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
- force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
-
- } else {
- Vector3 crossDiff = diff.normalized().cross(gravity.normalized());
- force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
- }
- //apply attractor forces
- p.velocity += force * local_delta;
- //orbit velocity
- if (flags[FLAG_DISABLE_Z]) {
- float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
- if (orbit_amount != 0.0) {
- float ang = orbit_amount * local_delta * Math_PI * 2.0;
- // 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());
- Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y));
- p.transform.origin -= Vector3(diff.x, diff.y, 0);
- p.transform.origin += Vector3(rotv.x, rotv.y, 0);
- }
- }
- if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- p.velocity = p.velocity.normalized() * tex_linear_velocity;
- }
- 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]);
- v -= damp * local_delta;
- if (v < 0.0) {
- p.velocity = Vector3();
- } else {
- 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]);
- p.custom[0] = Math::deg2rad(base_angle); //angle
- p.custom[2] = (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]); //angle
- }
- //apply color
- //apply hue rotation
-
- float tex_scale = 1.0;
- if (curve_parameters[PARAM_SCALE].is_valid()) {
- tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]);
- }
-
- float tex_hue_variation = 0.0;
- if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
- tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]);
- }
-
- float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * 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);
-
- Basis hue_rot_mat;
- {
- Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114);
- Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886);
- Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203);
-
- for (int j = 0; j < 3; j++) {
- hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s;
- }
- }
-
- if (color_ramp.is_valid()) {
- p.color = color_ramp->get_color_at_offset(p.custom[1]) * color;
- } else {
- p.color = color;
- }
-
- Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b));
- p.color.r = color_rgb.x;
- p.color.g = color_rgb.y;
- p.color.b = color_rgb.z;
-
- p.color *= p.base_color;
-
- if (flags[FLAG_DISABLE_Z]) {
-
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
- if (p.velocity.length() > 0.0) {
- p.transform.basis.set_axis(1, p.velocity.normalized());
- } else {
- p.transform.basis.set_axis(1, p.transform.basis.get_axis(1));
- }
- p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
- p.transform.basis.set_axis(2, Vector3(0, 0, 1));
-
- } else {
- p.transform.basis.set_axis(0, Vector3(Math::cos(p.custom[0]), -Math::sin(p.custom[0]), 0.0));
- p.transform.basis.set_axis(1, Vector3(Math::sin(p.custom[0]), Math::cos(p.custom[0]), 0.0));
- p.transform.basis.set_axis(2, Vector3(0, 0, 1));
- }
-
- } else {
- //orient particle Y towards velocity
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
- if (p.velocity.length() > 0.0) {
- p.transform.basis.set_axis(1, p.velocity.normalized());
- } else {
- p.transform.basis.set_axis(1, p.transform.basis.get_axis(1).normalized());
- }
- if (p.transform.basis.get_axis(1) == p.transform.basis.get_axis(0)) {
- p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
- p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized());
- } else {
- p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized());
- p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
- }
- } else {
- p.transform.basis.orthonormalize();
- }
-
- //turn particle by rotation in Y
- if (flags[FLAG_ROTATE_Y]) {
- Basis rot_y(Vector3(0, 1, 0), p.custom[0]);
- p.transform.basis = p.transform.basis * rot_y;
- }
- }
-
- //scale by scale
- float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale < 0.000001) base_scale = 0.000001;
-
- p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
-
- if (flags[FLAG_DISABLE_Z]) {
- p.velocity.z = 0.0;
- p.transform.origin.z = 0.0;
- }
-
- p.transform.origin += p.velocity * local_delta;
- }
-}
-
-void CPUParticles::_update_particle_data_buffer() {
- MutexLock lock(update_mutex);
-
- int pc = particles.size();
-
- int *ow;
- int *order = NULL;
-
- float *w = particle_data.ptrw();
- const Particle *r = particles.ptr();
- float *ptr = w;
-
- if (draw_order != DRAW_ORDER_INDEX) {
- ow = particle_order.ptrw();
- order = ow;
-
- for (int i = 0; i < pc; i++) {
- order[i] = i;
- }
- if (draw_order == DRAW_ORDER_LIFETIME) {
- SortArray<int, SortLifetime> sorter;
- sorter.compare.particles = r;
- sorter.sort(order, pc);
- } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) {
- Camera *c = get_viewport()->get_camera();
- if (c) {
- Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close
-
- if (local_coords) {
-
- // will look different from Particles in editor as this is based on the camera in the scenetree
- // and not the editor camera
- dir = inv_emission_transform.xform(dir).normalized();
- } else {
- dir = dir.normalized();
- }
-
- SortArray<int, SortAxis> sorter;
- sorter.compare.particles = r;
- sorter.compare.axis = dir;
- sorter.sort(order, pc);
- }
- }
- }
-
- for (int i = 0; i < pc; i++) {
-
- int idx = order ? order[i] : i;
-
- Transform t = r[idx].transform;
-
- if (!local_coords) {
- t = inv_emission_transform * t;
- }
-
- if (r[idx].active) {
- ptr[0] = t.basis.elements[0][0];
- ptr[1] = t.basis.elements[0][1];
- ptr[2] = t.basis.elements[0][2];
- ptr[3] = t.origin.x;
- ptr[4] = t.basis.elements[1][0];
- ptr[5] = t.basis.elements[1][1];
- ptr[6] = t.basis.elements[1][2];
- ptr[7] = t.origin.y;
- ptr[8] = t.basis.elements[2][0];
- ptr[9] = t.basis.elements[2][1];
- ptr[10] = t.basis.elements[2][2];
- ptr[11] = t.origin.z;
- } else {
- zeromem(ptr, sizeof(float) * 12);
- }
-
- Color c = r[idx].color;
-
- ptr[12] = c.r;
- ptr[13] = c.g;
- ptr[14] = c.b;
- ptr[15] = c.a;
-
- ptr[16] = r[idx].custom[0];
- ptr[17] = r[idx].custom[1];
- ptr[18] = r[idx].custom[2];
- ptr[19] = r[idx].custom[3];
-
- ptr += 20;
- }
-
- can_update = true;
-}
-
-void CPUParticles::_set_redraw(bool p_redraw) {
- if (redraw == p_redraw)
- return;
- redraw = p_redraw;
-
- {
- MutexLock lock(update_mutex);
-
- if (redraw) {
- VS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles::_update_render_thread));
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
- VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
- } else {
- if (VS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &CPUParticles::_update_render_thread))) {
- VS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &CPUParticles::_update_render_thread));
- }
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
- VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
- }
- }
-}
-
-void CPUParticles::_update_render_thread() {
-
- MutexLock lock(update_mutex);
-
- if (can_update) {
- VS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
- can_update = false; //wait for next time
- }
-}
-
-void CPUParticles::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
- set_process_internal(emitting);
-
- // first update before rendering to avoid one frame delay after emitting starts
- if (emitting && (time == 0))
- _update_internal();
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- _set_redraw(false);
- }
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- // first update before rendering to avoid one frame delay after emitting starts
- if (emitting && (time == 0))
- _update_internal();
- }
-
- if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- _update_internal();
- }
-
- if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
-
- inv_emission_transform = get_global_transform().affine_inverse();
-
- 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++) {
-
- Transform t = inv_emission_transform * r[i].transform;
-
- if (r[i].active) {
- ptr[0] = t.basis.elements[0][0];
- ptr[1] = t.basis.elements[0][1];
- ptr[2] = t.basis.elements[0][2];
- ptr[3] = t.origin.x;
- ptr[4] = t.basis.elements[1][0];
- ptr[5] = t.basis.elements[1][1];
- ptr[6] = t.basis.elements[1][2];
- ptr[7] = t.origin.y;
- ptr[8] = t.basis.elements[2][0];
- ptr[9] = t.basis.elements[2][1];
- ptr[10] = t.basis.elements[2][2];
- ptr[11] = t.origin.z;
- } else {
- zeromem(ptr, sizeof(float) * 12);
- }
-
- ptr += 20;
- }
-
- can_update = true;
- }
- }
-}
-
-void CPUParticles::convert_from_particles(Node *p_particles) {
-
- Particles *particles = Object::cast_to<Particles>(p_particles);
- ERR_FAIL_COND_MSG(!particles, "Only Particles nodes can be converted to CPUParticles.");
-
- set_emitting(particles->is_emitting());
- set_amount(particles->get_amount());
- set_lifetime(particles->get_lifetime());
- set_one_shot(particles->get_one_shot());
- set_pre_process_time(particles->get_pre_process_time());
- set_explosiveness_ratio(particles->get_explosiveness_ratio());
- set_randomness_ratio(particles->get_randomness_ratio());
- set_use_local_coordinates(particles->get_use_local_coordinates());
- set_fixed_fps(particles->get_fixed_fps());
- set_fractional_delta(particles->get_fractional_delta());
- set_speed_scale(particles->get_speed_scale());
- set_draw_order(DrawOrder(particles->get_draw_order()));
- set_mesh(particles->get_draw_pass_mesh(0));
-
- Ref<ParticlesMaterial> material = particles->get_process_material();
- if (material.is_null())
- return;
-
- set_direction(material->get_direction());
- set_spread(material->get_spread());
- set_flatness(material->get_flatness());
-
- set_color(material->get_color());
-
- Ref<GradientTexture> gt = material->get_color_ramp();
- if (gt.is_valid()) {
- set_color_ramp(gt->get_gradient());
- }
-
- set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
- set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
- set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
-
- set_emission_shape(EmissionShape(material->get_emission_shape()));
- set_emission_sphere_radius(material->get_emission_sphere_radius());
- set_emission_box_extents(material->get_emission_box_extents());
-
- set_gravity(material->get_gravity());
- set_lifetime_randomness(material->get_lifetime_randomness());
-
-#define CONVERT_PARAM(m_param) \
- set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
- { \
- Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
- if (ctex.is_valid()) set_param_curve(m_param, ctex->get_curve()); \
- } \
- set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
-
- CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
- CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
- CONVERT_PARAM(PARAM_ORBIT_VELOCITY);
- CONVERT_PARAM(PARAM_LINEAR_ACCEL);
- CONVERT_PARAM(PARAM_RADIAL_ACCEL);
- CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL);
- CONVERT_PARAM(PARAM_DAMPING);
- CONVERT_PARAM(PARAM_ANGLE);
- CONVERT_PARAM(PARAM_SCALE);
- CONVERT_PARAM(PARAM_HUE_VARIATION);
- CONVERT_PARAM(PARAM_ANIM_SPEED);
- CONVERT_PARAM(PARAM_ANIM_OFFSET);
-
-#undef CONVERT_PARAM
-}
-
-void CPUParticles::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles::set_emitting);
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles::set_amount);
- ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles::set_lifetime);
- ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles::set_one_shot);
- ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles::set_pre_process_time);
- ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles::set_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles::set_randomness_ratio);
- ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "random"), &CPUParticles::set_lifetime_randomness);
- ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles::set_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles::set_fixed_fps);
- ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles::set_fractional_delta);
- ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles::set_speed_scale);
-
- ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles::is_emitting);
- ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles::get_amount);
- ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles::get_lifetime);
- ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles::get_one_shot);
- ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles::get_pre_process_time);
- ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles::get_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles::get_randomness_ratio);
- ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &CPUParticles::get_lifetime_randomness);
- ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles::get_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles::get_fixed_fps);
- ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles::get_fractional_delta);
- ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles::get_speed_scale);
-
- ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles::set_draw_order);
-
- ClassDB::bind_method(D_METHOD("get_draw_order"), &CPUParticles::get_draw_order);
-
- ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CPUParticles::set_mesh);
- ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles::get_mesh);
-
- ClassDB::bind_method(D_METHOD("restart"), &CPUParticles::restart);
-
- 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_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
- 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::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
- ADD_GROUP("Drawing", "");
- 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::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
-
- BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
- BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
- BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
-
- ////////////////////////////////
-
- ClassDB::bind_method(D_METHOD("set_direction", "direction"), &CPUParticles::set_direction);
- ClassDB::bind_method(D_METHOD("get_direction"), &CPUParticles::get_direction);
-
- ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles::set_spread);
- ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles::get_spread);
-
- ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles::set_flatness);
- ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles::get_flatness);
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles::get_param);
-
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles::get_param_randomness);
-
- ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles::set_param_curve);
- ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles::get_param_curve);
-
- ClassDB::bind_method(D_METHOD("set_color", "color"), &CPUParticles::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &CPUParticles::get_color);
-
- ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles::set_color_ramp);
- ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles::get_color_ramp);
-
- ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles::set_particle_flag);
- ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles::get_particle_flag);
-
- ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles::set_emission_shape);
- ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles::get_emission_shape);
-
- ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &CPUParticles::set_emission_sphere_radius);
- ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &CPUParticles::get_emission_sphere_radius);
-
- ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &CPUParticles::set_emission_box_extents);
- ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &CPUParticles::get_emission_box_extents);
-
- ClassDB::bind_method(D_METHOD("set_emission_points", "array"), &CPUParticles::set_emission_points);
- ClassDB::bind_method(D_METHOD("get_emission_points"), &CPUParticles::get_emission_points);
-
- ClassDB::bind_method(D_METHOD("set_emission_normals", "array"), &CPUParticles::set_emission_normals);
- ClassDB::bind_method(D_METHOD("get_emission_normals"), &CPUParticles::get_emission_normals);
-
- ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles::set_emission_colors);
- ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles::get_emission_colors);
-
- ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles::get_gravity);
- ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles::set_gravity);
-
- ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles::convert_from_particles);
-
- ADD_GROUP("Emission Shape", "emission_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
- ADD_GROUP("Flags", "flag_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z);
- ADD_GROUP("Direction", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
- ADD_GROUP("Gravity", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
- ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
- ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
- ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
- ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
- ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
- ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
- ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
- ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
- ADD_GROUP("Color", "");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
-
- ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
- ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
-
- BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
- BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
- BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
- BIND_ENUM_CONSTANT(PARAM_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_ANGLE);
- BIND_ENUM_CONSTANT(PARAM_SCALE);
- BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
- BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
- BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
- BIND_ENUM_CONSTANT(PARAM_MAX);
-
- BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
- BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
- BIND_ENUM_CONSTANT(FLAG_DISABLE_Z);
- BIND_ENUM_CONSTANT(FLAG_MAX);
-
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
-}
-
-CPUParticles::CPUParticles() {
-
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- redraw = false;
- emitting = false;
-
- set_notify_transform(true);
-
- multimesh = VisualServer::get_singleton()->multimesh_create();
- VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
- set_base(multimesh);
-
- set_emitting(true);
- set_one_shot(false);
- set_amount(8);
- set_lifetime(1);
- set_fixed_fps(0);
- set_fractional_delta(true);
- set_pre_process_time(0);
- set_explosiveness_ratio(0);
- set_randomness_ratio(0);
- set_lifetime_randomness(0);
- set_use_local_coordinates(true);
-
- set_draw_order(DRAW_ORDER_INDEX);
- set_speed_scale(1);
-
- set_direction(Vector3(1, 0, 0));
- set_spread(45);
- set_flatness(0);
- set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0);
- set_param(PARAM_ANGULAR_VELOCITY, 0);
- set_param(PARAM_ORBIT_VELOCITY, 0);
- set_param(PARAM_LINEAR_ACCEL, 0);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_DAMPING, 0);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- 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 < FLAG_MAX; i++) {
- flags[i] = false;
- }
-
- can_update = false;
-
- set_color(Color(1, 1, 1, 1));
-}
-
-CPUParticles::~CPUParticles() {
- VS::get_singleton()->free(multimesh);
-}
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
deleted file mode 100644
index 231e1f1ad9..0000000000
--- a/scene/3d/cpu_particles.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*************************************************************************/
-/* cpu_particles.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CPU_PARTICLES_H
-#define CPU_PARTICLES_H
-
-#include "core/rid.h"
-#include "scene/3d/visual_instance.h"
-
-class CPUParticles : public GeometryInstance {
-private:
- GDCLASS(CPUParticles, GeometryInstance);
-
-public:
- enum DrawOrder {
- DRAW_ORDER_INDEX,
- DRAW_ORDER_LIFETIME,
- DRAW_ORDER_VIEW_DEPTH,
- };
-
- enum Parameter {
-
- PARAM_INITIAL_LINEAR_VELOCITY,
- PARAM_ANGULAR_VELOCITY,
- PARAM_ORBIT_VELOCITY,
- PARAM_LINEAR_ACCEL,
- PARAM_RADIAL_ACCEL,
- PARAM_TANGENTIAL_ACCEL,
- PARAM_DAMPING,
- PARAM_ANGLE,
- PARAM_SCALE,
- PARAM_HUE_VARIATION,
- PARAM_ANIM_SPEED,
- PARAM_ANIM_OFFSET,
- PARAM_MAX
- };
-
- enum Flags {
- FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ROTATE_Y,
- FLAG_DISABLE_Z,
- FLAG_MAX
- };
-
- enum EmissionShape {
- EMISSION_SHAPE_POINT,
- EMISSION_SHAPE_SPHERE,
- EMISSION_SHAPE_BOX,
- EMISSION_SHAPE_POINTS,
- EMISSION_SHAPE_DIRECTED_POINTS,
- EMISSION_SHAPE_MAX
- };
-
-private:
- bool emitting;
-
- struct Particle {
- Transform transform;
- Color color;
- float custom[4];
- Vector3 velocity;
- bool active;
- float angle_rand;
- float scale_rand;
- float hue_rot_rand;
- float anim_offset_rand;
- float time;
- float lifetime;
- Color base_color;
-
- uint32_t seed;
- };
-
- float time;
- float inactive_time;
- float frame_remainder;
- int cycle;
- bool redraw;
-
- RID multimesh;
-
- Vector<Particle> particles;
- Vector<float> particle_data;
- Vector<int> particle_order;
-
- struct SortLifetime {
- const Particle *particles;
-
- bool operator()(int p_a, int p_b) const {
- return particles[p_a].time > particles[p_b].time;
- }
- };
-
- struct SortAxis {
- const Particle *particles;
- Vector3 axis;
- bool operator()(int p_a, int p_b) const {
-
- return axis.dot(particles[p_a].transform.origin) < axis.dot(particles[p_b].transform.origin);
- }
- };
-
- //
-
- bool one_shot;
-
- float lifetime;
- float pre_process_time;
- float explosiveness_ratio;
- float randomness_ratio;
- float lifetime_randomness;
- float speed_scale;
- bool local_coords;
- int fixed_fps;
- bool fractional_delta;
-
- Transform inv_emission_transform;
-
- volatile bool can_update;
-
- DrawOrder draw_order;
-
- Ref<Mesh> mesh;
-
- ////////
-
- Vector3 direction;
- float spread;
- float flatness;
-
- float parameters[PARAM_MAX];
- float randomness[PARAM_MAX];
-
- Ref<Curve> curve_parameters[PARAM_MAX];
- Color color;
- Ref<Gradient> color_ramp;
-
- bool flags[FLAG_MAX];
-
- EmissionShape emission_shape;
- float emission_sphere_radius;
- Vector3 emission_box_extents;
- Vector<Vector3> emission_points;
- Vector<Vector3> emission_normals;
- Vector<Color> emission_colors;
- int emission_point_count;
-
- Vector3 gravity;
-
- void _update_internal();
- void _particles_process(float p_delta);
- void _update_particle_data_buffer();
-
- Mutex update_mutex;
-
- void _update_render_thread();
-
- void _set_redraw(bool p_redraw);
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const;
-
-public:
- AABB get_aabb() const;
- Vector<Face3> get_faces(uint32_t p_usage_flags) const;
-
- void set_emitting(bool p_emitting);
- void set_amount(int p_amount);
- 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_lifetime_randomness(float p_random);
- void set_visibility_aabb(const AABB &p_aabb);
- void set_use_local_coordinates(bool p_enable);
- void set_speed_scale(float 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;
- float get_lifetime_randomness() const;
- AABB get_visibility_aabb() const;
- bool get_use_local_coordinates() const;
- float get_speed_scale() const;
-
- void set_fixed_fps(int p_count);
- int get_fixed_fps() const;
-
- void set_fractional_delta(bool p_enable);
- bool get_fractional_delta() const;
-
- void set_draw_order(DrawOrder p_order);
- DrawOrder get_draw_order() const;
-
- void set_draw_passes(int p_count);
- int get_draw_passes() const;
-
- void set_mesh(const Ref<Mesh> &p_mesh);
- Ref<Mesh> get_mesh() const;
-
- ///////////////////
-
- void set_direction(Vector3 p_direction);
- Vector3 get_direction() const;
-
- void set_spread(float p_spread);
- float get_spread() const;
-
- void set_flatness(float p_flatness);
- float get_flatness() const;
-
- void set_param(Parameter p_param, float p_value);
- float 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_curve(Parameter p_param, const Ref<Curve> &p_curve);
- Ref<Curve> get_param_curve(Parameter p_param) const;
-
- void set_color(const Color &p_color);
- Color get_color() const;
-
- void set_color_ramp(const Ref<Gradient> &p_ramp);
- Ref<Gradient> get_color_ramp() const;
-
- void set_particle_flag(Flags p_flag, bool p_enable);
- bool get_particle_flag(Flags p_flag) const;
-
- void set_emission_shape(EmissionShape p_shape);
- void set_emission_sphere_radius(float p_radius);
- void set_emission_box_extents(Vector3 p_extents);
- void set_emission_points(const Vector<Vector3> &p_points);
- void set_emission_normals(const Vector<Vector3> &p_normals);
- void set_emission_colors(const Vector<Color> &p_colors);
- void set_emission_point_count(int p_count);
-
- EmissionShape get_emission_shape() const;
- float get_emission_sphere_radius() const;
- Vector3 get_emission_box_extents() const;
- Vector<Vector3> get_emission_points() const;
- Vector<Vector3> get_emission_normals() const;
- Vector<Color> get_emission_colors() const;
- int get_emission_point_count() const;
-
- void set_gravity(const Vector3 &p_gravity);
- Vector3 get_gravity() const;
-
- virtual String get_configuration_warning() const;
-
- void restart();
-
- void convert_from_particles(Node *p_particles);
-
- CPUParticles();
- ~CPUParticles();
-};
-
-VARIANT_ENUM_CAST(CPUParticles::DrawOrder)
-VARIANT_ENUM_CAST(CPUParticles::Parameter)
-VARIANT_ENUM_CAST(CPUParticles::Flags)
-VARIANT_ENUM_CAST(CPUParticles::EmissionShape)
-
-#endif // CPU_PARTICLES_H
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
new file mode 100644
index 0000000000..12c105b0f4
--- /dev/null
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -0,0 +1,1546 @@
+/*************************************************************************/
+/* cpu_particles_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "cpu_particles_3d.h"
+
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/gpu_particles_3d.h"
+#include "scene/resources/particles_material.h"
+#include "servers/rendering_server.h"
+
+AABB CPUParticles3D::get_aabb() const {
+
+ return AABB();
+}
+Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_flags) const {
+
+ return Vector<Face3>();
+}
+
+void CPUParticles3D::set_emitting(bool p_emitting) {
+
+ if (emitting == p_emitting)
+ return;
+
+ emitting = p_emitting;
+ if (emitting) {
+ set_process_internal(true);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (time == 0)
+ _update_internal();
+ }
+}
+
+void CPUParticles3D::set_amount(int p_amount) {
+
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0.");
+
+ particles.resize(p_amount);
+ {
+ Particle *w = particles.ptrw();
+
+ for (int i = 0; i < p_amount; i++) {
+ w[i].active = false;
+ }
+ }
+
+ particle_data.resize((12 + 4 + 4) * p_amount);
+ RS::get_singleton()->multimesh_allocate(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true);
+
+ particle_order.resize(p_amount);
+}
+void CPUParticles3D::set_lifetime(float p_lifetime) {
+
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
+ lifetime = p_lifetime;
+}
+
+void CPUParticles3D::set_one_shot(bool p_one_shot) {
+
+ one_shot = p_one_shot;
+}
+
+void CPUParticles3D::set_pre_process_time(float p_time) {
+
+ pre_process_time = p_time;
+}
+void CPUParticles3D::set_explosiveness_ratio(float p_ratio) {
+
+ explosiveness_ratio = p_ratio;
+}
+void CPUParticles3D::set_randomness_ratio(float p_ratio) {
+
+ randomness_ratio = p_ratio;
+}
+void CPUParticles3D::set_lifetime_randomness(float p_random) {
+
+ lifetime_randomness = p_random;
+}
+void CPUParticles3D::set_use_local_coordinates(bool p_enable) {
+
+ local_coords = p_enable;
+}
+void CPUParticles3D::set_speed_scale(float p_scale) {
+
+ speed_scale = p_scale;
+}
+
+bool CPUParticles3D::is_emitting() const {
+
+ return emitting;
+}
+int CPUParticles3D::get_amount() const {
+
+ return particles.size();
+}
+float CPUParticles3D::get_lifetime() const {
+
+ return lifetime;
+}
+bool CPUParticles3D::get_one_shot() const {
+
+ return one_shot;
+}
+
+float CPUParticles3D::get_pre_process_time() const {
+
+ return pre_process_time;
+}
+float CPUParticles3D::get_explosiveness_ratio() const {
+
+ return explosiveness_ratio;
+}
+float CPUParticles3D::get_randomness_ratio() const {
+
+ return randomness_ratio;
+}
+float CPUParticles3D::get_lifetime_randomness() const {
+
+ return lifetime_randomness;
+}
+
+bool CPUParticles3D::get_use_local_coordinates() const {
+
+ return local_coords;
+}
+
+float CPUParticles3D::get_speed_scale() const {
+
+ return speed_scale;
+}
+
+void CPUParticles3D::set_draw_order(DrawOrder p_order) {
+
+ draw_order = p_order;
+}
+
+CPUParticles3D::DrawOrder CPUParticles3D::get_draw_order() const {
+
+ return draw_order;
+}
+
+void CPUParticles3D::set_mesh(const Ref<Mesh> &p_mesh) {
+
+ mesh = p_mesh;
+ if (mesh.is_valid()) {
+ RS::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid());
+ } else {
+ RS::get_singleton()->multimesh_set_mesh(multimesh, RID());
+ }
+}
+
+Ref<Mesh> CPUParticles3D::get_mesh() const {
+
+ return mesh;
+}
+
+void CPUParticles3D::set_fixed_fps(int p_count) {
+ fixed_fps = p_count;
+}
+
+int CPUParticles3D::get_fixed_fps() const {
+ return fixed_fps;
+}
+
+void CPUParticles3D::set_fractional_delta(bool p_enable) {
+ fractional_delta = p_enable;
+}
+
+bool CPUParticles3D::get_fractional_delta() const {
+ return fractional_delta;
+}
+
+String CPUParticles3D::get_configuration_warning() const {
+
+ String warnings;
+
+ bool mesh_found = false;
+ bool anim_material_found = false;
+
+ if (get_mesh().is_valid()) {
+ mesh_found = true;
+ for (int j = 0; j < get_mesh()->get_surface_count(); j++) {
+ anim_material_found = Object::cast_to<ShaderMaterial>(get_mesh()->surface_get_material(j).ptr()) != nullptr;
+ StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_mesh()->surface_get_material(j).ptr());
+ anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
+ }
+ }
+
+ 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);
+
+ if (!mesh_found) {
+ if (warnings != String())
+ warnings += "\n";
+ warnings += "- " + 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\".");
+ }
+
+ return warnings;
+}
+
+void CPUParticles3D::restart() {
+
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ emitting = false;
+
+ {
+ int pc = particles.size();
+ Particle *w = particles.ptrw();
+
+ for (int i = 0; i < pc; i++) {
+ w[i].active = false;
+ }
+ }
+
+ set_emitting(true);
+}
+
+void CPUParticles3D::set_direction(Vector3 p_direction) {
+
+ direction = p_direction;
+}
+
+Vector3 CPUParticles3D::get_direction() const {
+
+ return direction;
+}
+
+void CPUParticles3D::set_spread(float p_spread) {
+
+ spread = p_spread;
+}
+
+float CPUParticles3D::get_spread() const {
+
+ return spread;
+}
+
+void CPUParticles3D::set_flatness(float p_flatness) {
+
+ flatness = p_flatness;
+}
+float CPUParticles3D::get_flatness() const {
+
+ return flatness;
+}
+
+void CPUParticles3D::set_param(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ parameters[p_param] = p_value;
+}
+float CPUParticles3D::get_param(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return parameters[p_param];
+}
+
+void CPUParticles3D::set_param_randomness(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ randomness[p_param] = p_value;
+}
+float CPUParticles3D::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) {
+
+ Ref<Curve> curve = p_curve;
+ if (!curve.is_valid())
+ return;
+
+ curve->ensure_default_setup(p_min, p_max);
+}
+
+void CPUParticles3D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ curve_parameters[p_param] = p_curve;
+
+ switch (p_param) {
+ case PARAM_INITIAL_LINEAR_VELOCITY: {
+ //do none for this one
+ } break;
+ case PARAM_ANGULAR_VELOCITY: {
+ _adjust_curve_range(p_curve, -360, 360);
+ } break;
+ case PARAM_ORBIT_VELOCITY: {
+ _adjust_curve_range(p_curve, -500, 500);
+ } break;
+ case PARAM_LINEAR_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_RADIAL_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_TANGENTIAL_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_DAMPING: {
+ _adjust_curve_range(p_curve, 0, 100);
+ } break;
+ case PARAM_ANGLE: {
+ _adjust_curve_range(p_curve, -360, 360);
+ } break;
+ case PARAM_SCALE: {
+
+ } break;
+ case PARAM_HUE_VARIATION: {
+ _adjust_curve_range(p_curve, -1, 1);
+ } break;
+ case PARAM_ANIM_SPEED: {
+ _adjust_curve_range(p_curve, 0, 200);
+ } break;
+ case PARAM_ANIM_OFFSET: {
+ } break;
+ default: {
+ }
+ }
+}
+Ref<Curve> CPUParticles3D::get_param_curve(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>());
+
+ return curve_parameters[p_param];
+}
+
+void CPUParticles3D::set_color(const Color &p_color) {
+
+ color = p_color;
+}
+
+Color CPUParticles3D::get_color() const {
+
+ return color;
+}
+
+void CPUParticles3D::set_color_ramp(const Ref<Gradient> &p_ramp) {
+
+ color_ramp = p_ramp;
+}
+
+Ref<Gradient> CPUParticles3D::get_color_ramp() const {
+
+ return color_ramp;
+}
+
+void CPUParticles3D::set_particle_flag(Flags p_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ flags[p_flag] = p_enable;
+ if (p_flag == FLAG_DISABLE_Z) {
+ _change_notify();
+ }
+}
+
+bool CPUParticles3D::get_particle_flag(Flags p_flag) const {
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags[p_flag];
+}
+
+void CPUParticles3D::set_emission_shape(EmissionShape p_shape) {
+ ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
+ emission_shape = p_shape;
+}
+
+void CPUParticles3D::set_emission_sphere_radius(float p_radius) {
+
+ emission_sphere_radius = p_radius;
+}
+
+void CPUParticles3D::set_emission_box_extents(Vector3 p_extents) {
+
+ emission_box_extents = p_extents;
+}
+
+void CPUParticles3D::set_emission_points(const Vector<Vector3> &p_points) {
+
+ emission_points = p_points;
+}
+
+void CPUParticles3D::set_emission_normals(const Vector<Vector3> &p_normals) {
+
+ emission_normals = p_normals;
+}
+
+void CPUParticles3D::set_emission_colors(const Vector<Color> &p_colors) {
+
+ emission_colors = p_colors;
+}
+
+float CPUParticles3D::get_emission_sphere_radius() const {
+
+ return emission_sphere_radius;
+}
+Vector3 CPUParticles3D::get_emission_box_extents() const {
+
+ return emission_box_extents;
+}
+Vector<Vector3> CPUParticles3D::get_emission_points() const {
+
+ return emission_points;
+}
+Vector<Vector3> CPUParticles3D::get_emission_normals() const {
+
+ return emission_normals;
+}
+
+Vector<Color> CPUParticles3D::get_emission_colors() const {
+
+ return emission_colors;
+}
+
+CPUParticles3D::EmissionShape CPUParticles3D::get_emission_shape() const {
+ return emission_shape;
+}
+void CPUParticles3D::set_gravity(const Vector3 &p_gravity) {
+
+ gravity = p_gravity;
+}
+
+Vector3 CPUParticles3D::get_gravity() const {
+
+ return gravity;
+}
+
+void CPUParticles3D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "color" && color_ramp.is_valid()) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ property.usage = 0;
+ }
+
+ if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ property.usage = 0;
+ }
+
+ if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ property.usage = 0;
+ }
+}
+
+static uint32_t idhash(uint32_t x) {
+
+ x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
+ x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
+ x = (x >> uint32_t(16)) ^ x;
+ return x;
+}
+
+static float rand_from_seed(uint32_t &seed) {
+ int k;
+ int s = int(seed);
+ if (s == 0)
+ s = 305420679;
+ k = s / 127773;
+ s = 16807 * (s - k * 127773) - 2836 * k;
+ if (s < 0)
+ s += 2147483647;
+ seed = uint32_t(s);
+ return float(seed % uint32_t(65536)) / 65535.0;
+}
+
+void CPUParticles3D::_update_internal() {
+
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
+ return;
+ }
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+ _set_redraw(false);
+
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+ _set_redraw(true);
+
+ bool processed = false;
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ processed = true;
+ }
+
+ if (processed) {
+ _update_particle_data_buffer();
+ }
+}
+
+void CPUParticles3D::_particles_process(float p_delta) {
+
+ p_delta *= speed_scale;
+
+ int pcount = particles.size();
+ Particle *w = particles.ptrw();
+
+ Particle *parray = w;
+
+ float prev_time = time;
+ time += p_delta;
+ if (time > lifetime) {
+ time = Math::fmod(time, lifetime);
+ cycle++;
+ if (one_shot && cycle > 0) {
+ set_emitting(false);
+ _change_notify();
+ }
+ }
+
+ Transform emission_xform;
+ Basis velocity_xform;
+ if (!local_coords) {
+ emission_xform = get_global_transform();
+ velocity_xform = emission_xform.basis;
+ }
+
+ float system_phase = time / lifetime;
+
+ for (int i = 0; i < pcount; i++) {
+
+ Particle &p = parray[i];
+
+ if (!emitting && !p.active)
+ continue;
+
+ float local_delta = 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);
+
+ if (randomness_ratio > 0.0) {
+ uint32_t seed = cycle;
+ if (restart_phase >= system_phase) {
+ seed -= uint32_t(1);
+ }
+ 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);
+ }
+
+ restart_phase *= (1.0 - explosiveness_ratio);
+ float restart_time = restart_phase * lifetime;
+ bool restart = false;
+
+ if (time > prev_time) {
+ // restart_time >= prev_time is used so particles emit in the first frame they are processed
+
+ if (restart_time >= prev_time && restart_time < time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = time - restart_time;
+ }
+ }
+
+ } else if (local_delta > 0.0) {
+ if (restart_time >= prev_time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = lifetime - restart_time + time;
+ }
+
+ } else if (restart_time < time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = time - restart_time;
+ }
+ }
+ }
+
+ if (p.time * (1.0 - explosiveness_ratio) > p.lifetime) {
+ restart = true;
+ }
+
+ if (restart) {
+
+ if (!emitting) {
+ p.active = false;
+ continue;
+ }
+ p.active = true;
+
+ /*float 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;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0);
+ }
+
+ float tex_anim_offset = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0);
+ }
+
+ p.seed = Math::rand();
+
+ p.angle_rand = Math::randf();
+ p.scale_rand = Math::randf();
+ p.hue_rot_rand = Math::randf();
+ p.anim_offset_rand = Math::randf();
+
+ if (flags[FLAG_DISABLE_Z]) {
+ float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
+ Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
+ p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ } else {
+ //initiate velocity spread in 3D
+ float angle1_rad = Math::atan2(direction.x, direction.z) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
+ float angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0;
+
+ Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad));
+ Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad));
+ direction_yz.z = direction_yz.z / MAX(0.0001, Math::sqrt(ABS(direction_yz.z))); //better uniform distribution
+ Vector3 direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
+ direction.normalize();
+ p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(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]);
+ p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[1] = 0.0; //phase
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
+ p.transform = Transform();
+ p.time = 0;
+ p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
+ p.base_color = Color(1, 1, 1, 1);
+
+ switch (emission_shape) {
+ case EMISSION_SHAPE_POINT: {
+ //do none
+ } break;
+ case EMISSION_SHAPE_SPHERE: {
+ float s = 2.0 * Math::randf() - 1.0, t = 2.0 * Math_PI * Math::randf();
+ float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
+ p.transform.origin = Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s);
+ } break;
+ case EMISSION_SHAPE_BOX: {
+ p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_box_extents;
+ } break;
+ case EMISSION_SHAPE_POINTS:
+ case EMISSION_SHAPE_DIRECTED_POINTS: {
+
+ int pc = emission_points.size();
+ if (pc == 0)
+ break;
+
+ int random_idx = Math::rand() % pc;
+
+ p.transform.origin = emission_points.get(random_idx);
+
+ if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
+ if (flags[FLAG_DISABLE_Z]) {
+ /*
+ mat2 rotm;
+ ";
+ rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;
+ rotm[1] = rotm[0].yx * vec2(1.0, -1.0);
+ VELOCITY.xy = rotm * VELOCITY.xy;
+ */
+ } else {
+ Vector3 normal = emission_normals.get(random_idx);
+ Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0);
+ Vector3 tangent = v0.cross(normal).normalized();
+ Vector3 bitangent = tangent.cross(normal).normalized();
+ Basis m3;
+ m3.set_axis(0, tangent);
+ m3.set_axis(1, bitangent);
+ m3.set_axis(2, normal);
+ p.velocity = m3.xform(p.velocity);
+ }
+ }
+
+ if (emission_colors.size() == pc) {
+ p.base_color = emission_colors.get(random_idx);
+ }
+ } break;
+ case EMISSION_SHAPE_MAX: { // Max value for validity check.
+ break;
+ }
+ }
+
+ if (!local_coords) {
+ p.velocity = velocity_xform.xform(p.velocity);
+ p.transform = emission_xform * p.transform;
+ }
+
+ if (flags[FLAG_DISABLE_Z]) {
+ p.velocity.z = 0.0;
+ p.transform.origin.z = 0.0;
+ }
+
+ } else if (!p.active) {
+ continue;
+ } else if (p.time > p.lifetime) {
+ p.active = false;
+ } else {
+
+ uint32_t alt_seed = p.seed;
+
+ p.time += local_delta;
+ p.custom[1] = p.time / lifetime;
+
+ float tex_linear_velocity = 0.0;
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]);
+ }
+
+ float tex_orbit_velocity = 0.0;
+ if (flags[FLAG_DISABLE_Z]) {
+ if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
+ tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]);
+ }
+ }
+
+ float tex_angular_velocity = 0.0;
+ if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
+ tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]);
+ }
+
+ float tex_linear_accel = 0.0;
+ if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
+ tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_tangential_accel = 0.0;
+ if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
+ tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_radial_accel = 0.0;
+ if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
+ tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_damping = 0.0;
+ if (curve_parameters[PARAM_DAMPING].is_valid()) {
+ tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]);
+ }
+
+ float tex_angle = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]);
+ }
+ float tex_anim_speed = 0.0;
+ if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
+ tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]);
+ }
+
+ float tex_anim_offset = 0.0;
+ if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
+ tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]);
+ }
+
+ Vector3 force = gravity;
+ Vector3 position = p.transform.origin;
+ if (flags[FLAG_DISABLE_Z]) {
+ position.z = 0.0;
+ }
+ //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]) : Vector3();
+ //apply radial acceleration
+ Vector3 org = emission_xform.origin;
+ Vector3 diff = position - 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]) : Vector3();
+ //apply tangential acceleration;
+ if (flags[FLAG_DISABLE_Z]) {
+
+ Vector2 yx = Vector2(diff.y, diff.x);
+ Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
+ force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+
+ } else {
+ Vector3 crossDiff = diff.normalized().cross(gravity.normalized());
+ force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+ }
+ //apply attractor forces
+ p.velocity += force * local_delta;
+ //orbit velocity
+ if (flags[FLAG_DISABLE_Z]) {
+ float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ if (orbit_amount != 0.0) {
+ float ang = orbit_amount * local_delta * Math_PI * 2.0;
+ // 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());
+ Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y));
+ p.transform.origin -= Vector3(diff.x, diff.y, 0);
+ p.transform.origin += Vector3(rotv.x, rotv.y, 0);
+ }
+ }
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ p.velocity = p.velocity.normalized() * tex_linear_velocity;
+ }
+ 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]);
+ v -= damp * local_delta;
+ if (v < 0.0) {
+ p.velocity = Vector3();
+ } else {
+ 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]);
+ p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[2] = (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]); //angle
+ }
+ //apply color
+ //apply hue rotation
+
+ float tex_scale = 1.0;
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]);
+ }
+
+ float tex_hue_variation = 0.0;
+ if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
+ tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]);
+ }
+
+ float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * 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);
+
+ Basis hue_rot_mat;
+ {
+ Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114);
+ Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886);
+ Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203);
+
+ for (int j = 0; j < 3; j++) {
+ hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s;
+ }
+ }
+
+ if (color_ramp.is_valid()) {
+ p.color = color_ramp->get_color_at_offset(p.custom[1]) * color;
+ } else {
+ p.color = color;
+ }
+
+ Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b));
+ p.color.r = color_rgb.x;
+ p.color.g = color_rgb.y;
+ p.color.b = color_rgb.z;
+
+ p.color *= p.base_color;
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (p.velocity.length() > 0.0) {
+ p.transform.basis.set_axis(1, p.velocity.normalized());
+ } else {
+ p.transform.basis.set_axis(1, p.transform.basis.get_axis(1));
+ }
+ p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
+ p.transform.basis.set_axis(2, Vector3(0, 0, 1));
+
+ } else {
+ p.transform.basis.set_axis(0, Vector3(Math::cos(p.custom[0]), -Math::sin(p.custom[0]), 0.0));
+ p.transform.basis.set_axis(1, Vector3(Math::sin(p.custom[0]), Math::cos(p.custom[0]), 0.0));
+ p.transform.basis.set_axis(2, Vector3(0, 0, 1));
+ }
+
+ } else {
+ //orient particle Y towards velocity
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (p.velocity.length() > 0.0) {
+ p.transform.basis.set_axis(1, p.velocity.normalized());
+ } else {
+ p.transform.basis.set_axis(1, p.transform.basis.get_axis(1).normalized());
+ }
+ if (p.transform.basis.get_axis(1) == p.transform.basis.get_axis(0)) {
+ p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
+ p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized());
+ } else {
+ p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized());
+ p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
+ }
+ } else {
+ p.transform.basis.orthonormalize();
+ }
+
+ //turn particle by rotation in Y
+ if (flags[FLAG_ROTATE_Y]) {
+ Basis rot_y(Vector3(0, 1, 0), p.custom[0]);
+ p.transform.basis = p.transform.basis * rot_y;
+ }
+ }
+
+ //scale by scale
+ float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ if (base_scale < 0.000001) base_scale = 0.000001;
+
+ p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
+
+ if (flags[FLAG_DISABLE_Z]) {
+ p.velocity.z = 0.0;
+ p.transform.origin.z = 0.0;
+ }
+
+ p.transform.origin += p.velocity * local_delta;
+ }
+}
+
+void CPUParticles3D::_update_particle_data_buffer() {
+ MutexLock lock(update_mutex);
+
+ int pc = particles.size();
+
+ int *ow;
+ int *order = nullptr;
+
+ float *w = particle_data.ptrw();
+ const Particle *r = particles.ptr();
+ float *ptr = w;
+
+ if (draw_order != DRAW_ORDER_INDEX) {
+ ow = particle_order.ptrw();
+ order = ow;
+
+ for (int i = 0; i < pc; i++) {
+ order[i] = i;
+ }
+ if (draw_order == DRAW_ORDER_LIFETIME) {
+ SortArray<int, SortLifetime> sorter;
+ sorter.compare.particles = r;
+ sorter.sort(order, pc);
+ } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) {
+ Camera3D *c = get_viewport()->get_camera();
+ if (c) {
+ Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close
+
+ if (local_coords) {
+
+ // will look different from Particles in editor as this is based on the camera in the scenetree
+ // and not the editor camera
+ dir = inv_emission_transform.xform(dir).normalized();
+ } else {
+ dir = dir.normalized();
+ }
+
+ SortArray<int, SortAxis> sorter;
+ sorter.compare.particles = r;
+ sorter.compare.axis = dir;
+ sorter.sort(order, pc);
+ }
+ }
+ }
+
+ for (int i = 0; i < pc; i++) {
+
+ int idx = order ? order[i] : i;
+
+ Transform t = r[idx].transform;
+
+ if (!local_coords) {
+ t = inv_emission_transform * t;
+ }
+
+ if (r[idx].active) {
+ ptr[0] = t.basis.elements[0][0];
+ ptr[1] = t.basis.elements[0][1];
+ ptr[2] = t.basis.elements[0][2];
+ ptr[3] = t.origin.x;
+ ptr[4] = t.basis.elements[1][0];
+ ptr[5] = t.basis.elements[1][1];
+ ptr[6] = t.basis.elements[1][2];
+ ptr[7] = t.origin.y;
+ ptr[8] = t.basis.elements[2][0];
+ ptr[9] = t.basis.elements[2][1];
+ ptr[10] = t.basis.elements[2][2];
+ ptr[11] = t.origin.z;
+ } else {
+ zeromem(ptr, sizeof(float) * 12);
+ }
+
+ Color c = r[idx].color;
+
+ ptr[12] = c.r;
+ ptr[13] = c.g;
+ ptr[14] = c.b;
+ ptr[15] = c.a;
+
+ ptr[16] = r[idx].custom[0];
+ ptr[17] = r[idx].custom[1];
+ ptr[18] = r[idx].custom[2];
+ ptr[19] = r[idx].custom[3];
+
+ ptr += 20;
+ }
+
+ can_update = true;
+}
+
+void CPUParticles3D::_set_redraw(bool p_redraw) {
+ if (redraw == p_redraw)
+ return;
+ redraw = p_redraw;
+
+ {
+ MutexLock lock(update_mutex);
+
+ if (redraw) {
+ RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles3D::_update_render_thread));
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
+ RS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
+ } else {
+ if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &CPUParticles3D::_update_render_thread))) {
+ RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &CPUParticles3D::_update_render_thread));
+ }
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
+ RS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
+ }
+ }
+}
+
+void CPUParticles3D::_update_render_thread() {
+
+ MutexLock lock(update_mutex);
+
+ if (can_update) {
+ RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data);
+ can_update = false; //wait for next time
+ }
+}
+
+void CPUParticles3D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ set_process_internal(emitting);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ _set_redraw(false);
+ }
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+ }
+
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+ _update_internal();
+ }
+
+ if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+
+ inv_emission_transform = get_global_transform().affine_inverse();
+
+ 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++) {
+
+ Transform t = inv_emission_transform * r[i].transform;
+
+ if (r[i].active) {
+ ptr[0] = t.basis.elements[0][0];
+ ptr[1] = t.basis.elements[0][1];
+ ptr[2] = t.basis.elements[0][2];
+ ptr[3] = t.origin.x;
+ ptr[4] = t.basis.elements[1][0];
+ ptr[5] = t.basis.elements[1][1];
+ ptr[6] = t.basis.elements[1][2];
+ ptr[7] = t.origin.y;
+ ptr[8] = t.basis.elements[2][0];
+ ptr[9] = t.basis.elements[2][1];
+ ptr[10] = t.basis.elements[2][2];
+ ptr[11] = t.origin.z;
+ } else {
+ zeromem(ptr, sizeof(float) * 12);
+ }
+
+ ptr += 20;
+ }
+
+ can_update = true;
+ }
+ }
+}
+
+void CPUParticles3D::convert_from_particles(Node *p_particles) {
+
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_particles);
+ ERR_FAIL_COND_MSG(!particles, "Only GPUParticles3D nodes can be converted to CPUParticles3D.");
+
+ set_emitting(particles->is_emitting());
+ set_amount(particles->get_amount());
+ set_lifetime(particles->get_lifetime());
+ set_one_shot(particles->get_one_shot());
+ set_pre_process_time(particles->get_pre_process_time());
+ set_explosiveness_ratio(particles->get_explosiveness_ratio());
+ set_randomness_ratio(particles->get_randomness_ratio());
+ set_use_local_coordinates(particles->get_use_local_coordinates());
+ set_fixed_fps(particles->get_fixed_fps());
+ set_fractional_delta(particles->get_fractional_delta());
+ set_speed_scale(particles->get_speed_scale());
+ set_draw_order(DrawOrder(particles->get_draw_order()));
+ set_mesh(particles->get_draw_pass_mesh(0));
+
+ Ref<ParticlesMaterial> material = particles->get_process_material();
+ if (material.is_null())
+ return;
+
+ set_direction(material->get_direction());
+ set_spread(material->get_spread());
+ set_flatness(material->get_flatness());
+
+ set_color(material->get_color());
+
+ Ref<GradientTexture> gt = material->get_color_ramp();
+ if (gt.is_valid()) {
+ set_color_ramp(gt->get_gradient());
+ }
+
+ set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
+ set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
+
+ set_emission_shape(EmissionShape(material->get_emission_shape()));
+ set_emission_sphere_radius(material->get_emission_sphere_radius());
+ set_emission_box_extents(material->get_emission_box_extents());
+
+ set_gravity(material->get_gravity());
+ set_lifetime_randomness(material->get_lifetime_randomness());
+
+#define CONVERT_PARAM(m_param) \
+ set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ { \
+ Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
+ if (ctex.is_valid()) set_param_curve(m_param, ctex->get_curve()); \
+ } \
+ set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+
+ CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
+ CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
+ CONVERT_PARAM(PARAM_ORBIT_VELOCITY);
+ CONVERT_PARAM(PARAM_LINEAR_ACCEL);
+ CONVERT_PARAM(PARAM_RADIAL_ACCEL);
+ CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL);
+ CONVERT_PARAM(PARAM_DAMPING);
+ CONVERT_PARAM(PARAM_ANGLE);
+ CONVERT_PARAM(PARAM_SCALE);
+ CONVERT_PARAM(PARAM_HUE_VARIATION);
+ CONVERT_PARAM(PARAM_ANIM_SPEED);
+ CONVERT_PARAM(PARAM_ANIM_OFFSET);
+
+#undef CONVERT_PARAM
+}
+
+void CPUParticles3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles3D::set_emitting);
+ ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles3D::set_amount);
+ ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles3D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles3D::set_one_shot);
+ ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles3D::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles3D::set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles3D::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "random"), &CPUParticles3D::set_lifetime_randomness);
+ ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles3D::set_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles3D::set_fixed_fps);
+ ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles3D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles3D::set_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles3D::is_emitting);
+ ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles3D::get_amount);
+ ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles3D::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles3D::get_one_shot);
+ ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles3D::get_pre_process_time);
+ ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles3D::get_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles3D::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &CPUParticles3D::get_lifetime_randomness);
+ ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles3D::get_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles3D::get_fixed_fps);
+ ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles3D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles3D::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles3D::set_draw_order);
+
+ ClassDB::bind_method(D_METHOD("get_draw_order"), &CPUParticles3D::get_draw_order);
+
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CPUParticles3D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles3D::get_mesh);
+
+ ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart);
+
+ 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_GROUP("Time", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
+ 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::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ 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::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+
+ BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
+
+ ////////////////////////////////
+
+ ClassDB::bind_method(D_METHOD("set_direction", "direction"), &CPUParticles3D::set_direction);
+ ClassDB::bind_method(D_METHOD("get_direction"), &CPUParticles3D::get_direction);
+
+ ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles3D::set_spread);
+ ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles3D::get_spread);
+
+ ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles3D::set_flatness);
+ ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles3D::get_flatness);
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles3D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles3D::get_param);
+
+ ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles3D::set_param_randomness);
+ ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles3D::get_param_randomness);
+
+ ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles3D::set_param_curve);
+ ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles3D::get_param_curve);
+
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &CPUParticles3D::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &CPUParticles3D::get_color);
+
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles3D::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles3D::get_color_ramp);
+
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles3D::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles3D::get_particle_flag);
+
+ ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles3D::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles3D::get_emission_shape);
+
+ ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &CPUParticles3D::set_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &CPUParticles3D::get_emission_sphere_radius);
+
+ ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &CPUParticles3D::set_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &CPUParticles3D::get_emission_box_extents);
+
+ ClassDB::bind_method(D_METHOD("set_emission_points", "array"), &CPUParticles3D::set_emission_points);
+ ClassDB::bind_method(D_METHOD("get_emission_points"), &CPUParticles3D::get_emission_points);
+
+ ClassDB::bind_method(D_METHOD("set_emission_normals", "array"), &CPUParticles3D::set_emission_normals);
+ ClassDB::bind_method(D_METHOD("get_emission_normals"), &CPUParticles3D::get_emission_normals);
+
+ ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles3D::set_emission_colors);
+ ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles3D::get_emission_colors);
+
+ ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles3D::get_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles3D::set_gravity);
+
+ ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles);
+
+ ADD_GROUP("Emission Shape", "emission_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
+ ADD_GROUP("Flags", "flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z);
+ ADD_GROUP("Direction", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "direction"), "set_direction", "get_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
+ ADD_GROUP("Gravity", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
+ ADD_GROUP("Initial Velocity", "initial_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_GROUP("Angular Velocity", "angular_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
+ ADD_GROUP("Orbit Velocity", "orbit_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
+ ADD_GROUP("Linear Accel", "linear_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
+ ADD_GROUP("Radial Accel", "radial_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
+ ADD_GROUP("Tangential Accel", "tangential_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
+ ADD_GROUP("Damping", "");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
+ ADD_GROUP("Angle", "");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
+ ADD_GROUP("Scale", "");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_GROUP("Color", "");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
+
+ ADD_GROUP("Hue Variation", "hue_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
+ ADD_GROUP("Animation", "anim_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
+
+ BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGLE);
+ BIND_ENUM_CONSTANT(PARAM_SCALE);
+ BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(FLAG_DISABLE_Z);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
+}
+
+CPUParticles3D::CPUParticles3D() {
+
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ redraw = false;
+ emitting = false;
+
+ set_notify_transform(true);
+
+ multimesh = RenderingServer::get_singleton()->multimesh_create();
+ RenderingServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
+ set_base(multimesh);
+
+ set_emitting(true);
+ set_one_shot(false);
+ set_amount(8);
+ set_lifetime(1);
+ set_fixed_fps(0);
+ set_fractional_delta(true);
+ set_pre_process_time(0);
+ set_explosiveness_ratio(0);
+ set_randomness_ratio(0);
+ set_lifetime_randomness(0);
+ set_use_local_coordinates(true);
+
+ set_draw_order(DRAW_ORDER_INDEX);
+ set_speed_scale(1);
+
+ set_direction(Vector3(1, 0, 0));
+ set_spread(45);
+ set_flatness(0);
+ set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param(PARAM_ANGULAR_VELOCITY, 0);
+ set_param(PARAM_ORBIT_VELOCITY, 0);
+ set_param(PARAM_LINEAR_ACCEL, 0);
+ set_param(PARAM_RADIAL_ACCEL, 0);
+ set_param(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param(PARAM_DAMPING, 0);
+ set_param(PARAM_ANGLE, 0);
+ set_param(PARAM_SCALE, 1);
+ 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 < FLAG_MAX; i++) {
+ flags[i] = false;
+ }
+
+ can_update = false;
+
+ set_color(Color(1, 1, 1, 1));
+}
+
+CPUParticles3D::~CPUParticles3D() {
+ RS::get_singleton()->free(multimesh);
+}
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
new file mode 100644
index 0000000000..ffe0ecc9a9
--- /dev/null
+++ b/scene/3d/cpu_particles_3d.h
@@ -0,0 +1,298 @@
+/*************************************************************************/
+/* cpu_particles_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CPU_PARTICLES_H
+#define CPU_PARTICLES_H
+
+#include "core/rid.h"
+#include "scene/3d/visual_instance_3d.h"
+
+class CPUParticles3D : public GeometryInstance3D {
+private:
+ GDCLASS(CPUParticles3D, GeometryInstance3D);
+
+public:
+ enum DrawOrder {
+ DRAW_ORDER_INDEX,
+ DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_VIEW_DEPTH,
+ };
+
+ enum Parameter {
+
+ PARAM_INITIAL_LINEAR_VELOCITY,
+ PARAM_ANGULAR_VELOCITY,
+ PARAM_ORBIT_VELOCITY,
+ PARAM_LINEAR_ACCEL,
+ PARAM_RADIAL_ACCEL,
+ PARAM_TANGENTIAL_ACCEL,
+ PARAM_DAMPING,
+ PARAM_ANGLE,
+ PARAM_SCALE,
+ PARAM_HUE_VARIATION,
+ PARAM_ANIM_SPEED,
+ PARAM_ANIM_OFFSET,
+ PARAM_MAX
+ };
+
+ enum Flags {
+ FLAG_ALIGN_Y_TO_VELOCITY,
+ FLAG_ROTATE_Y,
+ FLAG_DISABLE_Z,
+ FLAG_MAX
+ };
+
+ enum EmissionShape {
+ EMISSION_SHAPE_POINT,
+ EMISSION_SHAPE_SPHERE,
+ EMISSION_SHAPE_BOX,
+ EMISSION_SHAPE_POINTS,
+ EMISSION_SHAPE_DIRECTED_POINTS,
+ EMISSION_SHAPE_MAX
+ };
+
+private:
+ bool emitting;
+
+ struct Particle {
+ Transform transform;
+ Color color;
+ float custom[4];
+ Vector3 velocity;
+ bool active;
+ float angle_rand;
+ float scale_rand;
+ float hue_rot_rand;
+ float anim_offset_rand;
+ float time;
+ float lifetime;
+ Color base_color;
+
+ uint32_t seed;
+ };
+
+ float time;
+ float inactive_time;
+ float frame_remainder;
+ int cycle;
+ bool redraw;
+
+ RID multimesh;
+
+ Vector<Particle> particles;
+ Vector<float> particle_data;
+ Vector<int> particle_order;
+
+ struct SortLifetime {
+ const Particle *particles;
+
+ bool operator()(int p_a, int p_b) const {
+ return particles[p_a].time > particles[p_b].time;
+ }
+ };
+
+ struct SortAxis {
+ const Particle *particles;
+ Vector3 axis;
+ bool operator()(int p_a, int p_b) const {
+
+ return axis.dot(particles[p_a].transform.origin) < axis.dot(particles[p_b].transform.origin);
+ }
+ };
+
+ //
+
+ bool one_shot;
+
+ float lifetime;
+ float pre_process_time;
+ float explosiveness_ratio;
+ float randomness_ratio;
+ float lifetime_randomness;
+ float speed_scale;
+ bool local_coords;
+ int fixed_fps;
+ bool fractional_delta;
+
+ Transform inv_emission_transform;
+
+ volatile bool can_update;
+
+ DrawOrder draw_order;
+
+ Ref<Mesh> mesh;
+
+ ////////
+
+ Vector3 direction;
+ float spread;
+ float flatness;
+
+ float parameters[PARAM_MAX];
+ float randomness[PARAM_MAX];
+
+ Ref<Curve> curve_parameters[PARAM_MAX];
+ Color color;
+ Ref<Gradient> color_ramp;
+
+ bool flags[FLAG_MAX];
+
+ EmissionShape emission_shape;
+ float emission_sphere_radius;
+ Vector3 emission_box_extents;
+ Vector<Vector3> emission_points;
+ Vector<Vector3> emission_normals;
+ Vector<Color> emission_colors;
+ int emission_point_count;
+
+ Vector3 gravity;
+
+ void _update_internal();
+ void _particles_process(float p_delta);
+ void _update_particle_data_buffer();
+
+ Mutex update_mutex;
+
+ void _update_render_thread();
+
+ void _set_redraw(bool p_redraw);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+ AABB get_aabb() const;
+ Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ void set_emitting(bool p_emitting);
+ void set_amount(int p_amount);
+ 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_lifetime_randomness(float p_random);
+ void set_visibility_aabb(const AABB &p_aabb);
+ void set_use_local_coordinates(bool p_enable);
+ void set_speed_scale(float 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;
+ float get_lifetime_randomness() const;
+ AABB get_visibility_aabb() const;
+ bool get_use_local_coordinates() const;
+ float get_speed_scale() const;
+
+ void set_fixed_fps(int p_count);
+ int get_fixed_fps() const;
+
+ void set_fractional_delta(bool p_enable);
+ bool get_fractional_delta() const;
+
+ void set_draw_order(DrawOrder p_order);
+ DrawOrder get_draw_order() const;
+
+ void set_draw_passes(int p_count);
+ int get_draw_passes() const;
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ ///////////////////
+
+ void set_direction(Vector3 p_direction);
+ Vector3 get_direction() const;
+
+ void set_spread(float p_spread);
+ float get_spread() const;
+
+ void set_flatness(float p_flatness);
+ float get_flatness() const;
+
+ void set_param(Parameter p_param, float p_value);
+ float 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_curve(Parameter p_param, const Ref<Curve> &p_curve);
+ Ref<Curve> get_param_curve(Parameter p_param) const;
+
+ void set_color(const Color &p_color);
+ Color get_color() const;
+
+ void set_color_ramp(const Ref<Gradient> &p_ramp);
+ Ref<Gradient> get_color_ramp() const;
+
+ void set_particle_flag(Flags p_flag, bool p_enable);
+ bool get_particle_flag(Flags p_flag) const;
+
+ void set_emission_shape(EmissionShape p_shape);
+ void set_emission_sphere_radius(float p_radius);
+ void set_emission_box_extents(Vector3 p_extents);
+ void set_emission_points(const Vector<Vector3> &p_points);
+ void set_emission_normals(const Vector<Vector3> &p_normals);
+ void set_emission_colors(const Vector<Color> &p_colors);
+ void set_emission_point_count(int p_count);
+
+ EmissionShape get_emission_shape() const;
+ float get_emission_sphere_radius() const;
+ Vector3 get_emission_box_extents() const;
+ Vector<Vector3> get_emission_points() const;
+ Vector<Vector3> get_emission_normals() const;
+ Vector<Color> get_emission_colors() const;
+ int get_emission_point_count() const;
+
+ void set_gravity(const Vector3 &p_gravity);
+ Vector3 get_gravity() const;
+
+ virtual String get_configuration_warning() const;
+
+ void restart();
+
+ void convert_from_particles(Node *p_particles);
+
+ CPUParticles3D();
+ ~CPUParticles3D();
+};
+
+VARIANT_ENUM_CAST(CPUParticles3D::DrawOrder)
+VARIANT_ENUM_CAST(CPUParticles3D::Parameter)
+VARIANT_ENUM_CAST(CPUParticles3D::Flags)
+VARIANT_ENUM_CAST(CPUParticles3D::EmissionShape)
+
+#endif // CPU_PARTICLES_H
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
new file mode 100644
index 0000000000..4c824aedc4
--- /dev/null
+++ b/scene/3d/decal.cpp
@@ -0,0 +1,235 @@
+/*************************************************************************/
+/* decal.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "decal.h"
+
+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 {
+ return extents;
+}
+
+void Decal::set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture) {
+ ERR_FAIL_INDEX(p_type, TEXTURE_MAX);
+ textures[p_type] = p_texture;
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RS::get_singleton()->decal_set_texture(decal, RS::DecalTexture(p_type), texture_rid);
+}
+Ref<Texture2D> Decal::get_texture(DecalTexture p_type) const {
+ ERR_FAIL_INDEX_V(p_type, TEXTURE_MAX, Ref<Texture2D>());
+ return textures[p_type];
+}
+
+void Decal::set_emission_energy(float p_energy) {
+ emission_energy = p_energy;
+ RS::get_singleton()->decal_set_emission_energy(decal, emission_energy);
+}
+float Decal::get_emission_energy() const {
+ return emission_energy;
+}
+
+void Decal::set_albedo_mix(float p_mix) {
+ albedo_mix = p_mix;
+ RS::get_singleton()->decal_set_albedo_mix(decal, albedo_mix);
+}
+float Decal::get_albedo_mix() const {
+ return albedo_mix;
+}
+
+void Decal::set_upper_fade(float p_fade) {
+ upper_fade = p_fade;
+ RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade);
+}
+float Decal::get_upper_fade() const {
+ return upper_fade;
+}
+
+void Decal::set_lower_fade(float p_fade) {
+ lower_fade = p_fade;
+ RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade);
+}
+float Decal::get_lower_fade() const {
+ return lower_fade;
+}
+
+void Decal::set_normal_fade(float p_fade) {
+ normal_fade = p_fade;
+ RS::get_singleton()->decal_set_normal_fade(decal, normal_fade);
+}
+float Decal::get_normal_fade() const {
+ return normal_fade;
+}
+
+void Decal::set_modulate(Color p_modulate) {
+ modulate = p_modulate;
+ RS::get_singleton()->decal_set_modulate(decal, p_modulate);
+}
+
+Color Decal::get_modulate() const {
+ return modulate;
+}
+
+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);
+}
+bool Decal::is_distance_fade_enabled() const {
+ return distance_fade_enabled;
+}
+
+void Decal::set_distance_fade_begin(float p_distance) {
+ distance_fade_begin = p_distance;
+ RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length);
+}
+float Decal::get_distance_fade_begin() const {
+ return distance_fade_begin;
+}
+
+void Decal::set_distance_fade_length(float p_length) {
+ distance_fade_length = p_length;
+ RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length);
+}
+float Decal::get_distance_fade_length() const {
+ return distance_fade_length;
+}
+
+void Decal::set_cull_mask(uint32_t p_layers) {
+ cull_mask = p_layers;
+ RS::get_singleton()->decal_set_cull_mask(decal, cull_mask);
+}
+uint32_t Decal::get_cull_mask() const {
+ return cull_mask;
+}
+
+AABB Decal::get_aabb() const {
+
+ AABB aabb;
+ aabb.position = -extents;
+ aabb.size = extents * 2.0;
+ return aabb;
+}
+Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const {
+
+ return Vector<Face3>();
+}
+
+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);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "type", "texture"), &Decal::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture", "type"), &Decal::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_emission_energy", "energy"), &Decal::set_emission_energy);
+ ClassDB::bind_method(D_METHOD("get_emission_energy"), &Decal::get_emission_energy);
+
+ ClassDB::bind_method(D_METHOD("set_albedo_mix", "energy"), &Decal::set_albedo_mix);
+ ClassDB::bind_method(D_METHOD("get_albedo_mix"), &Decal::get_albedo_mix);
+
+ ClassDB::bind_method(D_METHOD("set_modulate", "color"), &Decal::set_modulate);
+ ClassDB::bind_method(D_METHOD("get_modulate"), &Decal::get_modulate);
+
+ ClassDB::bind_method(D_METHOD("set_upper_fade", "fade"), &Decal::set_upper_fade);
+ ClassDB::bind_method(D_METHOD("get_upper_fade"), &Decal::get_upper_fade);
+
+ ClassDB::bind_method(D_METHOD("set_lower_fade", "fade"), &Decal::set_lower_fade);
+ ClassDB::bind_method(D_METHOD("get_lower_fade"), &Decal::get_lower_fade);
+
+ ClassDB::bind_method(D_METHOD("set_normal_fade", "fade"), &Decal::set_normal_fade);
+ ClassDB::bind_method(D_METHOD("get_normal_fade"), &Decal::get_normal_fade);
+
+ ClassDB::bind_method(D_METHOD("set_enable_distance_fade", "enable"), &Decal::set_enable_distance_fade);
+ ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &Decal::is_distance_fade_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_begin", "distance"), &Decal::set_distance_fade_begin);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_begin"), &Decal::get_distance_fade_begin);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_length", "distance"), &Decal::set_distance_fade_length);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_length"), &Decal::get_distance_fade_length);
+
+ ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &Decal::set_cull_mask);
+ ClassDB::bind_method(D_METHOD("get_cull_mask"), &Decal::get_cull_mask);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater"), "set_extents", "get_extents");
+ ADD_GROUP("Textures", "texture_");
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_albedo", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ALBEDO);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_NORMAL);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_orm", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ORM);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_emission", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION);
+ ADD_GROUP("Parameters", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "albedo_mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_albedo_mix", "get_albedo_mix");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_fade", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_normal_fade", "get_normal_fade");
+ ADD_GROUP("Vertical Fade", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "upper_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_upper_fade", "get_upper_fade");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lower_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_lower_fade", "get_lower_fade");
+ ADD_GROUP("Distance Fade", "distance_fade_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin"), "set_distance_fade_begin", "get_distance_fade_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length"), "set_distance_fade_length", "get_distance_fade_length");
+ ADD_GROUP("Cull Mask", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+
+ BIND_ENUM_CONSTANT(TEXTURE_ALBEDO);
+ BIND_ENUM_CONSTANT(TEXTURE_NORMAL);
+ BIND_ENUM_CONSTANT(TEXTURE_ORM);
+ BIND_ENUM_CONSTANT(TEXTURE_EMISSION);
+ BIND_ENUM_CONSTANT(TEXTURE_MAX);
+}
+
+Decal::Decal() {
+
+ extents = Vector3(1, 1, 1);
+ emission_energy = 1.0;
+ modulate = Color(1, 1, 1, 1);
+ albedo_mix = 1.0;
+ cull_mask = (1 << 20) - 1;
+ upper_fade = 0.3;
+ lower_fade = 0.3;
+ normal_fade = 0;
+ distance_fade_enabled = false;
+ distance_fade_begin = 10;
+ distance_fade_length = 1;
+
+ decal = RenderingServer::get_singleton()->decal_create();
+ RS::get_singleton()->instance_set_base(get_instance(), decal);
+}
+
+Decal::~Decal() {
+
+ RS::get_singleton()->free(decal);
+}
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
new file mode 100644
index 0000000000..665444829d
--- /dev/null
+++ b/scene/3d/decal.h
@@ -0,0 +1,114 @@
+/*************************************************************************/
+/* decal.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 DECAL_H
+#define DECAL_H
+
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/texture.h"
+#include "servers/rendering_server.h"
+
+class Decal : public VisualInstance3D {
+ GDCLASS(Decal, VisualInstance3D);
+
+public:
+ enum DecalTexture {
+ TEXTURE_ALBEDO,
+ TEXTURE_NORMAL,
+ TEXTURE_ORM,
+ TEXTURE_EMISSION,
+ TEXTURE_MAX
+ };
+
+private:
+ RID decal;
+ Vector3 extents;
+ Ref<Texture2D> textures[TEXTURE_MAX];
+ float emission_energy;
+ float albedo_mix;
+ Color modulate;
+ uint32_t cull_mask;
+ float normal_fade;
+ float upper_fade;
+ float lower_fade;
+ bool distance_fade_enabled;
+ float distance_fade_begin;
+ float distance_fade_length;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ void set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_texture(DecalTexture p_type) const;
+
+ void set_emission_energy(float p_energy);
+ float get_emission_energy() const;
+
+ void set_albedo_mix(float p_mix);
+ float get_albedo_mix() const;
+
+ void set_modulate(Color p_modulate);
+ Color get_modulate() const;
+
+ void set_upper_fade(float p_energy);
+ float get_upper_fade() const;
+
+ void set_lower_fade(float p_fade);
+ float get_lower_fade() const;
+
+ void set_normal_fade(float p_fade);
+ float get_normal_fade() const;
+
+ void set_enable_distance_fade(bool p_enable);
+ bool is_distance_fade_enabled() const;
+
+ void set_distance_fade_begin(float p_distance);
+ float get_distance_fade_begin() const;
+
+ void set_distance_fade_length(float p_length);
+ float get_distance_fade_length() const;
+
+ void set_cull_mask(uint32_t p_layers);
+ uint32_t get_cull_mask() const;
+
+ virtual AABB get_aabb() const;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ Decal();
+ ~Decal();
+};
+
+VARIANT_ENUM_CAST(Decal::DecalTexture);
+
+#endif // DECAL_H
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index c3f039ae85..6d571ee4f2 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/method_bind_ext.gen.inc"
-#include "mesh_instance.h"
+#include "mesh_instance_3d.h"
#include "voxelizer.h"
void GIProbeData::_set_data(const Dictionary &p_data) {
@@ -92,7 +92,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) {
- VS::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(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;
@@ -105,24 +105,24 @@ Vector3 GIProbeData::get_octree_size() const {
return octree_size;
}
Vector<uint8_t> GIProbeData::get_octree_cells() const {
- return VS::get_singleton()->gi_probe_get_octree_cells(probe);
+ return RS::get_singleton()->gi_probe_get_octree_cells(probe);
}
Vector<uint8_t> GIProbeData::get_data_cells() const {
- return VS::get_singleton()->gi_probe_get_data_cells(probe);
+ return RS::get_singleton()->gi_probe_get_data_cells(probe);
}
Vector<uint8_t> GIProbeData::get_distance_field() const {
- return VS::get_singleton()->gi_probe_get_distance_field(probe);
+ return RS::get_singleton()->gi_probe_get_distance_field(probe);
}
Vector<int> GIProbeData::get_level_counts() const {
- return VS::get_singleton()->gi_probe_get_level_counts(probe);
+ return RS::get_singleton()->gi_probe_get_level_counts(probe);
}
Transform GIProbeData::get_to_cell_xform() const {
return to_cell_xform;
}
void GIProbeData::set_dynamic_range(float p_range) {
- VS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range);
+ RS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range);
dynamic_range = p_range;
}
@@ -131,7 +131,7 @@ float GIProbeData::get_dynamic_range() const {
}
void GIProbeData::set_propagation(float p_propagation) {
- VS::get_singleton()->gi_probe_set_propagation(probe, p_propagation);
+ RS::get_singleton()->gi_probe_set_propagation(probe, p_propagation);
propagation = p_propagation;
}
@@ -140,7 +140,7 @@ float GIProbeData::get_propagation() const {
}
void GIProbeData::set_anisotropy_strength(float p_anisotropy_strength) {
- VS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength);
+ RS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength);
anisotropy_strength = p_anisotropy_strength;
}
@@ -149,7 +149,7 @@ float GIProbeData::get_anisotropy_strength() const {
}
void GIProbeData::set_energy(float p_energy) {
- VS::get_singleton()->gi_probe_set_energy(probe, p_energy);
+ RS::get_singleton()->gi_probe_set_energy(probe, p_energy);
energy = p_energy;
}
@@ -158,7 +158,7 @@ float GIProbeData::get_energy() const {
}
void GIProbeData::set_ao(float p_ao) {
- VS::get_singleton()->gi_probe_set_ao(probe, p_ao);
+ RS::get_singleton()->gi_probe_set_ao(probe, p_ao);
ao = p_ao;
}
@@ -167,7 +167,7 @@ float GIProbeData::get_ao() const {
}
void GIProbeData::set_ao_size(float p_ao_size) {
- VS::get_singleton()->gi_probe_set_ao_size(probe, p_ao_size);
+ RS::get_singleton()->gi_probe_set_ao_size(probe, p_ao_size);
ao_size = p_ao_size;
}
@@ -176,7 +176,7 @@ float GIProbeData::get_ao_size() const {
}
void GIProbeData::set_bias(float p_bias) {
- VS::get_singleton()->gi_probe_set_bias(probe, p_bias);
+ RS::get_singleton()->gi_probe_set_bias(probe, p_bias);
bias = p_bias;
}
@@ -185,7 +185,7 @@ float GIProbeData::get_bias() const {
}
void GIProbeData::set_normal_bias(float p_normal_bias) {
- VS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias);
+ RS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias);
normal_bias = p_normal_bias;
}
@@ -194,7 +194,7 @@ float GIProbeData::get_normal_bias() const {
}
void GIProbeData::set_interior(bool p_enable) {
- VS::get_singleton()->gi_probe_set_interior(probe, p_enable);
+ RS::get_singleton()->gi_probe_set_interior(probe, p_enable);
interior = p_enable;
}
@@ -203,7 +203,7 @@ bool GIProbeData::is_interior() const {
}
void GIProbeData::set_use_two_bounces(bool p_enable) {
- VS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable);
+ RS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable);
use_two_bounces = p_enable;
}
@@ -293,13 +293,14 @@ GIProbeData::GIProbeData() {
propagation = 0.7;
anisotropy_strength = 0.5;
interior = false;
+ use_two_bounces = false;
- probe = VS::get_singleton()->gi_probe_create();
+ probe = RS::get_singleton()->gi_probe_create();
}
GIProbeData::~GIProbeData() {
- VS::get_singleton()->free(probe);
+ RS::get_singleton()->free(probe);
}
//////////////////////
@@ -308,9 +309,9 @@ GIProbeData::~GIProbeData() {
void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) {
if (p_data.is_valid()) {
- VS::get_singleton()->instance_set_base(get_instance(), p_data->get_rid());
+ RS::get_singleton()->instance_set_base(get_instance(), p_data->get_rid());
} else {
- VS::get_singleton()->instance_set_base(get_instance(), RID());
+ RS::get_singleton()->instance_set_base(get_instance(), RID());
}
probe_data = p_data;
@@ -347,8 +348,8 @@ Vector3 GIProbe::get_extents() const {
void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
- MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node);
- if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
+ if (mi && mi->get_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) {
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
@@ -369,7 +370,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
}
}
- Spatial *s = Object::cast_to<Spatial>(p_at_node);
+ Node3D *s = Object::cast_to<Node3D>(p_at_node);
if (s) {
if (s->is_visible_in_tree()) {
@@ -402,9 +403,9 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
}
}
-GIProbe::BakeBeginFunc GIProbe::bake_begin_function = NULL;
-GIProbe::BakeStepFunc GIProbe::bake_step_function = NULL;
-GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL;
+GIProbe::BakeBeginFunc GIProbe::bake_begin_function = nullptr;
+GIProbe::BakeStepFunc GIProbe::bake_step_function = nullptr;
+GIProbe::BakeEndFunc GIProbe::bake_end_function = nullptr;
Vector3i GIProbe::get_estimated_cell_size() const {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
@@ -468,7 +469,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
//create the data for visual server
if (p_create_visual_debug) {
- MultiMeshInstance *mmi = memnew(MultiMeshInstance);
+ MultiMeshInstance3D *mmi = memnew(MultiMeshInstance3D);
mmi->set_multimesh(baker.create_debug_multimesh());
add_child(mmi);
#ifdef TOOLS_ENABLED
@@ -511,7 +512,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
void GIProbe::_debug_bake() {
- bake(NULL, true);
+ bake(nullptr, true);
}
AABB GIProbe::get_aabb() const {
@@ -526,7 +527,7 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
String GIProbe::get_configuration_warning() const {
- if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
+ if (RenderingServer::get_singleton()->is_low_end()) {
return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
}
return String();
@@ -563,10 +564,10 @@ GIProbe::GIProbe() {
subdiv = SUBDIV_128;
extents = Vector3(10, 10, 10);
- gi_probe = VS::get_singleton()->gi_probe_create();
+ gi_probe = RS::get_singleton()->gi_probe_create();
set_disable_scale(true);
}
GIProbe::~GIProbe() {
- VS::get_singleton()->free(gi_probe);
+ RS::get_singleton()->free(gi_probe);
}
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
index 354eaad7c0..28b533e82d 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/gi_probe.h
@@ -31,8 +31,8 @@
#ifndef GIPROBE_H
#define GIPROBE_H
-#include "multimesh_instance.h"
-#include "scene/3d/visual_instance.h"
+#include "multimesh_instance_3d.h"
+#include "scene/3d/visual_instance_3d.h"
class GIProbeData : public Resource {
@@ -108,8 +108,8 @@ public:
~GIProbeData();
};
-class GIProbe : public VisualInstance {
- GDCLASS(GIProbe, VisualInstance);
+class GIProbe : public VisualInstance3D {
+ GDCLASS(GIProbe, VisualInstance3D);
public:
enum Subdiv {
@@ -135,7 +135,7 @@ private:
struct PlotMesh {
Ref<Material> override_material;
- Vector<Ref<Material> > instance_materials;
+ Vector<Ref<Material>> instance_materials;
Ref<Mesh> mesh;
Transform local_xform;
};
@@ -161,7 +161,7 @@ public:
Vector3 get_extents() const;
Vector3i get_estimated_cell_size() const;
- void bake(Node *p_from_node = NULL, bool p_create_visual_debug = false);
+ void bake(Node *p_from_node = nullptr, bool p_create_visual_debug = false);
virtual AABB get_aabb() const;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
new file mode 100644
index 0000000000..7744c477cb
--- /dev/null
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -0,0 +1,441 @@
+/*************************************************************************/
+/* gpu_particles_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "gpu_particles_3d.h"
+
+#include "core/os/os.h"
+#include "scene/resources/particles_material.h"
+
+#include "servers/rendering_server.h"
+
+AABB GPUParticles3D::get_aabb() const {
+
+ return AABB();
+}
+Vector<Face3> GPUParticles3D::get_faces(uint32_t p_usage_flags) const {
+
+ return Vector<Face3>();
+}
+
+void GPUParticles3D::set_emitting(bool p_emitting) {
+
+ RS::get_singleton()->particles_set_emitting(particles, p_emitting);
+
+ if (p_emitting && one_shot) {
+ set_process_internal(true);
+ } else if (!p_emitting) {
+ set_process_internal(false);
+ }
+}
+
+void GPUParticles3D::set_amount(int p_amount) {
+
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
+ amount = p_amount;
+ RS::get_singleton()->particles_set_amount(particles, amount);
+}
+void GPUParticles3D::set_lifetime(float p_lifetime) {
+
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
+ lifetime = p_lifetime;
+ RS::get_singleton()->particles_set_lifetime(particles, lifetime);
+}
+
+void GPUParticles3D::set_one_shot(bool p_one_shot) {
+
+ one_shot = p_one_shot;
+ RS::get_singleton()->particles_set_one_shot(particles, one_shot);
+
+ if (is_emitting()) {
+
+ set_process_internal(true);
+ if (!one_shot)
+ RenderingServer::get_singleton()->particles_restart(particles);
+ }
+
+ if (!one_shot)
+ set_process_internal(false);
+}
+
+void GPUParticles3D::set_pre_process_time(float p_time) {
+
+ pre_process_time = p_time;
+ RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
+}
+void GPUParticles3D::set_explosiveness_ratio(float p_ratio) {
+
+ explosiveness_ratio = p_ratio;
+ RS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
+}
+void GPUParticles3D::set_randomness_ratio(float p_ratio) {
+
+ randomness_ratio = p_ratio;
+ RS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
+}
+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) {
+
+ local_coords = p_enable;
+ RS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
+}
+void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {
+
+ process_material = p_material;
+ RID material_rid;
+ if (process_material.is_valid())
+ material_rid = process_material->get_rid();
+ RS::get_singleton()->particles_set_process_material(particles, material_rid);
+
+ update_configuration_warning();
+}
+
+void GPUParticles3D::set_speed_scale(float p_scale) {
+
+ speed_scale = p_scale;
+ RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
+}
+
+bool GPUParticles3D::is_emitting() const {
+
+ return RS::get_singleton()->particles_get_emitting(particles);
+}
+int GPUParticles3D::get_amount() const {
+
+ return amount;
+}
+float GPUParticles3D::get_lifetime() const {
+
+ return lifetime;
+}
+bool GPUParticles3D::get_one_shot() const {
+
+ return one_shot;
+}
+
+float GPUParticles3D::get_pre_process_time() const {
+
+ return pre_process_time;
+}
+float GPUParticles3D::get_explosiveness_ratio() const {
+
+ return explosiveness_ratio;
+}
+float GPUParticles3D::get_randomness_ratio() const {
+
+ return randomness_ratio;
+}
+AABB GPUParticles3D::get_visibility_aabb() const {
+
+ return visibility_aabb;
+}
+bool GPUParticles3D::get_use_local_coordinates() const {
+
+ return local_coords;
+}
+Ref<Material> GPUParticles3D::get_process_material() const {
+
+ return process_material;
+}
+
+float GPUParticles3D::get_speed_scale() const {
+
+ return speed_scale;
+}
+
+void GPUParticles3D::set_draw_order(DrawOrder p_order) {
+
+ draw_order = p_order;
+ RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
+}
+
+GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const {
+
+ return draw_order;
+}
+
+void GPUParticles3D::set_draw_passes(int p_count) {
+
+ ERR_FAIL_COND(p_count < 1);
+ draw_passes.resize(p_count);
+ RS::get_singleton()->particles_set_draw_passes(particles, p_count);
+ _change_notify();
+}
+int GPUParticles3D::get_draw_passes() const {
+
+ return draw_passes.size();
+}
+
+void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
+
+ ERR_FAIL_INDEX(p_pass, draw_passes.size());
+
+ draw_passes.write[p_pass] = p_mesh;
+
+ RID mesh_rid;
+ if (p_mesh.is_valid())
+ mesh_rid = p_mesh->get_rid();
+
+ RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
+
+ update_configuration_warning();
+}
+
+Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const {
+
+ ERR_FAIL_INDEX_V(p_pass, draw_passes.size(), Ref<Mesh>());
+
+ return draw_passes[p_pass];
+}
+
+void GPUParticles3D::set_fixed_fps(int p_count) {
+ fixed_fps = p_count;
+ RS::get_singleton()->particles_set_fixed_fps(particles, p_count);
+}
+
+int GPUParticles3D::get_fixed_fps() const {
+ return fixed_fps;
+}
+
+void GPUParticles3D::set_fractional_delta(bool p_enable) {
+ fractional_delta = p_enable;
+ RS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
+}
+
+bool GPUParticles3D::get_fractional_delta() const {
+ return fractional_delta;
+}
+
+String GPUParticles3D::get_configuration_warning() const {
+
+ 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.");
+ }
+
+ String warnings;
+
+ bool meshes_found = false;
+ bool anim_material_found = false;
+
+ for (int i = 0; i < draw_passes.size(); i++) {
+ if (draw_passes[i].is_valid()) {
+ 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());
+ anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
+ }
+ if (anim_material_found) break;
+ }
+ }
+
+ 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);
+
+ if (!meshes_found) {
+ if (warnings != String())
+ warnings += "\n";
+ warnings += "- " + 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.");
+ } else {
+ const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
+ if (!anim_material_found && process &&
+ (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
+ if (warnings != String())
+ warnings += "\n";
+ warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ }
+ }
+
+ return warnings;
+}
+
+void GPUParticles3D::restart() {
+
+ RenderingServer::get_singleton()->particles_restart(particles);
+ RenderingServer::get_singleton()->particles_set_emitting(particles, true);
+}
+
+AABB GPUParticles3D::capture_aabb() const {
+
+ return RS::get_singleton()->particles_get_current_aabb(particles);
+}
+
+void GPUParticles3D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name.begins_with("draw_pass_")) {
+ int index = property.name.get_slicec('_', 2).to_int() - 1;
+ if (index >= draw_passes.size()) {
+ property.usage = 0;
+ return;
+ }
+ }
+}
+
+void GPUParticles3D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
+ if (can_process()) {
+ RS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
+ } else {
+
+ RS::get_singleton()->particles_set_speed_scale(particles, 0);
+ }
+ }
+
+ // Use internal process when emitting and one_shot are 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();
+ set_process_internal(false);
+ }
+ }
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ // make sure particles are updated before rendering occurs if they were active before
+ if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) {
+ RS::get_singleton()->particles_request_process(particles);
+ }
+ }
+}
+
+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);
+ ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &GPUParticles3D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &GPUParticles3D::set_one_shot);
+ ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &GPUParticles3D::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &GPUParticles3D::set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &GPUParticles3D::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_visibility_aabb", "aabb"), &GPUParticles3D::set_visibility_aabb);
+ 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_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("is_emitting"), &GPUParticles3D::is_emitting);
+ ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles3D::get_amount);
+ ClassDB::bind_method(D_METHOD("get_lifetime"), &GPUParticles3D::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &GPUParticles3D::get_one_shot);
+ ClassDB::bind_method(D_METHOD("get_pre_process_time"), &GPUParticles3D::get_pre_process_time);
+ ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &GPUParticles3D::get_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &GPUParticles3D::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_visibility_aabb"), &GPUParticles3D::get_visibility_aabb);
+ 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_process_material"), &GPUParticles3D::get_process_material);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles3D::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles3D::set_draw_order);
+
+ ClassDB::bind_method(D_METHOD("get_draw_order"), &GPUParticles3D::get_draw_order);
+
+ ClassDB::bind_method(D_METHOD("set_draw_passes", "passes"), &GPUParticles3D::set_draw_passes);
+ ClassDB::bind_method(D_METHOD("set_draw_pass_mesh", "pass", "mesh"), &GPUParticles3D::set_draw_pass_mesh);
+
+ 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("restart"), &GPUParticles3D::restart);
+ ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
+
+ 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_GROUP("Time", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
+ 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, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ 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_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_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes");
+ 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);
+ }
+
+ BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
+
+ BIND_CONSTANT(MAX_DRAW_PASSES);
+}
+
+GPUParticles3D::GPUParticles3D() {
+
+ particles = RS::get_singleton()->particles_create();
+ set_base(particles);
+ one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
+ set_emitting(true);
+ set_one_shot(false);
+ set_amount(8);
+ set_lifetime(1);
+ set_fixed_fps(0);
+ set_fractional_delta(true);
+ set_pre_process_time(0);
+ set_explosiveness_ratio(0);
+ set_randomness_ratio(0);
+ 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);
+}
+
+GPUParticles3D::~GPUParticles3D() {
+
+ RS::get_singleton()->free(particles);
+}
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
new file mode 100644
index 0000000000..0c6653294b
--- /dev/null
+++ b/scene/3d/gpu_particles_3d.h
@@ -0,0 +1,133 @@
+/*************************************************************************/
+/* gpu_particles_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PARTICLES_H
+#define PARTICLES_H
+
+#include "core/rid.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/material.h"
+
+class GPUParticles3D : public GeometryInstance3D {
+private:
+ GDCLASS(GPUParticles3D, GeometryInstance3D);
+
+public:
+ enum DrawOrder {
+ DRAW_ORDER_INDEX,
+ DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_VIEW_DEPTH,
+ };
+
+ enum {
+ MAX_DRAW_PASSES = 4
+ };
+
+private:
+ RID particles;
+
+ bool one_shot;
+ int amount;
+ float lifetime;
+ float pre_process_time;
+ float explosiveness_ratio;
+ float randomness_ratio;
+ float speed_scale;
+ AABB visibility_aabb;
+ bool local_coords;
+ int fixed_fps;
+ bool fractional_delta;
+
+ Ref<Material> process_material;
+
+ DrawOrder draw_order;
+
+ Vector<Ref<Mesh>> draw_passes;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+ AABB get_aabb() const;
+ Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ void set_emitting(bool p_emitting);
+ void set_amount(int p_amount);
+ 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_visibility_aabb(const AABB &p_aabb);
+ void set_use_local_coordinates(bool p_enable);
+ void set_process_material(const Ref<Material> &p_material);
+ void set_speed_scale(float 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;
+ AABB get_visibility_aabb() const;
+ bool get_use_local_coordinates() const;
+ Ref<Material> get_process_material() const;
+ float get_speed_scale() const;
+
+ void set_fixed_fps(int p_count);
+ int get_fixed_fps() const;
+
+ void set_fractional_delta(bool p_enable);
+ bool get_fractional_delta() const;
+
+ void set_draw_order(DrawOrder p_order);
+ DrawOrder get_draw_order() const;
+
+ void set_draw_passes(int p_count);
+ int get_draw_passes() const;
+
+ 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;
+
+ void restart();
+
+ AABB capture_aabb() const;
+ GPUParticles3D();
+ ~GPUParticles3D();
+};
+
+VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+
+#endif // PARTICLES_H
diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp
deleted file mode 100644
index f5b08b86e1..0000000000
--- a/scene/3d/immediate_geometry.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*************************************************************************/
-/* immediate_geometry.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "immediate_geometry.h"
-
-void ImmediateGeometry::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture) {
-
- VS::get_singleton()->immediate_begin(im, (VS::PrimitiveType)p_primitive, p_texture.is_valid() ? p_texture->get_rid() : RID());
- if (p_texture.is_valid())
- cached_textures.push_back(p_texture);
-}
-
-void ImmediateGeometry::set_normal(const Vector3 &p_normal) {
-
- VS::get_singleton()->immediate_normal(im, p_normal);
-}
-
-void ImmediateGeometry::set_tangent(const Plane &p_tangent) {
-
- VS::get_singleton()->immediate_tangent(im, p_tangent);
-}
-
-void ImmediateGeometry::set_color(const Color &p_color) {
-
- VS::get_singleton()->immediate_color(im, p_color);
-}
-
-void ImmediateGeometry::set_uv(const Vector2 &p_uv) {
-
- VS::get_singleton()->immediate_uv(im, p_uv);
-}
-
-void ImmediateGeometry::set_uv2(const Vector2 &p_uv2) {
-
- VS::get_singleton()->immediate_uv2(im, p_uv2);
-}
-
-void ImmediateGeometry::add_vertex(const Vector3 &p_vertex) {
-
- VS::get_singleton()->immediate_vertex(im, p_vertex);
- if (empty) {
- aabb.position = p_vertex;
- aabb.size = Vector3();
- empty = false;
- } else {
- aabb.expand_to(p_vertex);
- }
-}
-
-void ImmediateGeometry::end() {
-
- VS::get_singleton()->immediate_end(im);
-}
-
-void ImmediateGeometry::clear() {
-
- VS::get_singleton()->immediate_clear(im);
- empty = true;
- cached_textures.clear();
-}
-
-AABB ImmediateGeometry::get_aabb() const {
-
- return aabb;
-}
-Vector<Face3> ImmediateGeometry::get_faces(uint32_t p_usage_flags) const {
-
- return Vector<Face3>();
-}
-
-void ImmediateGeometry::add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv) {
-
- for (int i = 1; i <= p_lats; i++) {
- double lat0 = Math_PI * (-0.5 + (double)(i - 1) / p_lats);
- double z0 = Math::sin(lat0);
- double zr0 = Math::cos(lat0);
-
- double lat1 = Math_PI * (-0.5 + (double)i / p_lats);
- double z1 = Math::sin(lat1);
- double zr1 = Math::cos(lat1);
-
- for (int j = p_lons; j >= 1; j--) {
-
- double lng0 = 2 * Math_PI * (double)(j - 1) / p_lons;
- double x0 = Math::cos(lng0);
- double y0 = Math::sin(lng0);
-
- double lng1 = 2 * Math_PI * (double)(j) / p_lons;
- double x1 = Math::cos(lng1);
- double y1 = Math::sin(lng1);
-
- Vector3 v[4] = {
- Vector3(x1 * zr0, z0, y1 * zr0),
- Vector3(x1 * zr1, z1, y1 * zr1),
- Vector3(x0 * zr1, z1, y0 * zr1),
- Vector3(x0 * zr0, z0, y0 * zr0)
- };
-
-#define ADD_POINT(m_idx) \
- if (p_add_uv) { \
- set_uv(Vector2(Math::atan2(v[m_idx].x, v[m_idx].z) / Math_PI * 0.5 + 0.5, v[m_idx].y * 0.5 + 0.5)); \
- set_tangent(Plane(Vector3(-v[m_idx].z, v[m_idx].y, v[m_idx].x), 1)); \
- } \
- set_normal(v[m_idx]); \
- add_vertex(v[m_idx] * p_radius);
-
- ADD_POINT(0);
- ADD_POINT(1);
- ADD_POINT(2);
-
- ADD_POINT(2);
- ADD_POINT(3);
- ADD_POINT(0);
- }
- }
-}
-
-void ImmediateGeometry::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("begin", "primitive", "texture"), &ImmediateGeometry::begin, DEFVAL(Ref<Texture2D>()));
- ClassDB::bind_method(D_METHOD("set_normal", "normal"), &ImmediateGeometry::set_normal);
- ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &ImmediateGeometry::set_tangent);
- ClassDB::bind_method(D_METHOD("set_color", "color"), &ImmediateGeometry::set_color);
- ClassDB::bind_method(D_METHOD("set_uv", "uv"), &ImmediateGeometry::set_uv);
- ClassDB::bind_method(D_METHOD("set_uv2", "uv"), &ImmediateGeometry::set_uv2);
- ClassDB::bind_method(D_METHOD("add_vertex", "position"), &ImmediateGeometry::add_vertex);
- ClassDB::bind_method(D_METHOD("add_sphere", "lats", "lons", "radius", "add_uv"), &ImmediateGeometry::add_sphere, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("end"), &ImmediateGeometry::end);
- ClassDB::bind_method(D_METHOD("clear"), &ImmediateGeometry::clear);
-}
-
-ImmediateGeometry::ImmediateGeometry() {
-
- im = VisualServer::get_singleton()->immediate_create();
- set_base(im);
- empty = true;
-}
-
-ImmediateGeometry::~ImmediateGeometry() {
-
- VisualServer::get_singleton()->free(im);
-}
diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h
deleted file mode 100644
index 77a20e8d4d..0000000000
--- a/scene/3d/immediate_geometry.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*************************************************************************/
-/* immediate_geometry.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 IMMEDIATE_GEOMETRY_H
-#define IMMEDIATE_GEOMETRY_H
-
-#include "scene/3d/visual_instance.h"
-#include "scene/resources/mesh.h"
-
-class ImmediateGeometry : public GeometryInstance {
-
- GDCLASS(ImmediateGeometry, GeometryInstance);
-
- RID im;
- //a list of textures drawn need to be kept, to avoid references
- // in VisualServer from becoming invalid if the texture is no longer used
- List<Ref<Texture2D> > cached_textures;
- bool empty;
- AABB aabb;
-
-protected:
- static void _bind_methods();
-
-public:
- void begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture = Ref<Texture2D>());
- void set_normal(const Vector3 &p_normal);
- void set_tangent(const Plane &p_tangent);
- void set_color(const Color &p_color);
- void set_uv(const Vector2 &p_uv);
- void set_uv2(const Vector2 &p_uv2);
-
- void add_vertex(const Vector3 &p_vertex);
-
- void end();
- void clear();
-
- void add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv = true);
-
- virtual AABB get_aabb() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
-
- ImmediateGeometry();
- ~ImmediateGeometry();
-};
-
-#endif // IMMEDIATE_GEOMETRY_H
diff --git a/scene/3d/immediate_geometry_3d.cpp b/scene/3d/immediate_geometry_3d.cpp
new file mode 100644
index 0000000000..63d4b1ac84
--- /dev/null
+++ b/scene/3d/immediate_geometry_3d.cpp
@@ -0,0 +1,169 @@
+/*************************************************************************/
+/* immediate_geometry_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "immediate_geometry_3d.h"
+
+void ImmediateGeometry3D::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture) {
+
+ RS::get_singleton()->immediate_begin(im, (RS::PrimitiveType)p_primitive, p_texture.is_valid() ? p_texture->get_rid() : RID());
+ if (p_texture.is_valid())
+ cached_textures.push_back(p_texture);
+}
+
+void ImmediateGeometry3D::set_normal(const Vector3 &p_normal) {
+
+ RS::get_singleton()->immediate_normal(im, p_normal);
+}
+
+void ImmediateGeometry3D::set_tangent(const Plane &p_tangent) {
+
+ RS::get_singleton()->immediate_tangent(im, p_tangent);
+}
+
+void ImmediateGeometry3D::set_color(const Color &p_color) {
+
+ RS::get_singleton()->immediate_color(im, p_color);
+}
+
+void ImmediateGeometry3D::set_uv(const Vector2 &p_uv) {
+
+ RS::get_singleton()->immediate_uv(im, p_uv);
+}
+
+void ImmediateGeometry3D::set_uv2(const Vector2 &p_uv2) {
+
+ RS::get_singleton()->immediate_uv2(im, p_uv2);
+}
+
+void ImmediateGeometry3D::add_vertex(const Vector3 &p_vertex) {
+
+ RS::get_singleton()->immediate_vertex(im, p_vertex);
+ if (empty) {
+ aabb.position = p_vertex;
+ aabb.size = Vector3();
+ empty = false;
+ } else {
+ aabb.expand_to(p_vertex);
+ }
+}
+
+void ImmediateGeometry3D::end() {
+
+ RS::get_singleton()->immediate_end(im);
+}
+
+void ImmediateGeometry3D::clear() {
+
+ RS::get_singleton()->immediate_clear(im);
+ empty = true;
+ cached_textures.clear();
+}
+
+AABB ImmediateGeometry3D::get_aabb() const {
+
+ return aabb;
+}
+Vector<Face3> ImmediateGeometry3D::get_faces(uint32_t p_usage_flags) const {
+
+ return Vector<Face3>();
+}
+
+void ImmediateGeometry3D::add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv) {
+
+ for (int i = 1; i <= p_lats; i++) {
+ double lat0 = Math_PI * (-0.5 + (double)(i - 1) / p_lats);
+ double z0 = Math::sin(lat0);
+ double zr0 = Math::cos(lat0);
+
+ double lat1 = Math_PI * (-0.5 + (double)i / p_lats);
+ double z1 = Math::sin(lat1);
+ double zr1 = Math::cos(lat1);
+
+ for (int j = p_lons; j >= 1; j--) {
+
+ double lng0 = 2 * Math_PI * (double)(j - 1) / p_lons;
+ double x0 = Math::cos(lng0);
+ double y0 = Math::sin(lng0);
+
+ double lng1 = 2 * Math_PI * (double)(j) / p_lons;
+ double x1 = Math::cos(lng1);
+ double y1 = Math::sin(lng1);
+
+ Vector3 v[4] = {
+ Vector3(x1 * zr0, z0, y1 * zr0),
+ Vector3(x1 * zr1, z1, y1 * zr1),
+ Vector3(x0 * zr1, z1, y0 * zr1),
+ Vector3(x0 * zr0, z0, y0 * zr0)
+ };
+
+#define ADD_POINT(m_idx) \
+ if (p_add_uv) { \
+ set_uv(Vector2(Math::atan2(v[m_idx].x, v[m_idx].z) / Math_PI * 0.5 + 0.5, v[m_idx].y * 0.5 + 0.5)); \
+ set_tangent(Plane(Vector3(-v[m_idx].z, v[m_idx].y, v[m_idx].x), 1)); \
+ } \
+ set_normal(v[m_idx]); \
+ add_vertex(v[m_idx] * p_radius);
+
+ ADD_POINT(0);
+ ADD_POINT(1);
+ ADD_POINT(2);
+
+ ADD_POINT(2);
+ ADD_POINT(3);
+ ADD_POINT(0);
+ }
+ }
+}
+
+void ImmediateGeometry3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("begin", "primitive", "texture"), &ImmediateGeometry3D::begin, DEFVAL(Ref<Texture2D>()));
+ ClassDB::bind_method(D_METHOD("set_normal", "normal"), &ImmediateGeometry3D::set_normal);
+ ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &ImmediateGeometry3D::set_tangent);
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &ImmediateGeometry3D::set_color);
+ ClassDB::bind_method(D_METHOD("set_uv", "uv"), &ImmediateGeometry3D::set_uv);
+ ClassDB::bind_method(D_METHOD("set_uv2", "uv"), &ImmediateGeometry3D::set_uv2);
+ ClassDB::bind_method(D_METHOD("add_vertex", "position"), &ImmediateGeometry3D::add_vertex);
+ ClassDB::bind_method(D_METHOD("add_sphere", "lats", "lons", "radius", "add_uv"), &ImmediateGeometry3D::add_sphere, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("end"), &ImmediateGeometry3D::end);
+ ClassDB::bind_method(D_METHOD("clear"), &ImmediateGeometry3D::clear);
+}
+
+ImmediateGeometry3D::ImmediateGeometry3D() {
+
+ im = RenderingServer::get_singleton()->immediate_create();
+ set_base(im);
+ empty = true;
+}
+
+ImmediateGeometry3D::~ImmediateGeometry3D() {
+
+ RenderingServer::get_singleton()->free(im);
+}
diff --git a/scene/3d/immediate_geometry_3d.h b/scene/3d/immediate_geometry_3d.h
new file mode 100644
index 0000000000..6e15450a5b
--- /dev/null
+++ b/scene/3d/immediate_geometry_3d.h
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* immediate_geometry_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 IMMEDIATE_GEOMETRY_3D_H
+#define IMMEDIATE_GEOMETRY_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/mesh.h"
+
+class ImmediateGeometry3D : public GeometryInstance3D {
+
+ GDCLASS(ImmediateGeometry3D, GeometryInstance3D);
+
+ RID im;
+ //a list of textures drawn need to be kept, to avoid references
+ // in RenderingServer from becoming invalid if the texture is no longer used
+ List<Ref<Texture2D>> cached_textures;
+ bool empty;
+ AABB aabb;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture = Ref<Texture2D>());
+ void set_normal(const Vector3 &p_normal);
+ void set_tangent(const Plane &p_tangent);
+ void set_color(const Color &p_color);
+ void set_uv(const Vector2 &p_uv);
+ void set_uv2(const Vector2 &p_uv2);
+
+ void add_vertex(const Vector3 &p_vertex);
+
+ void end();
+ void clear();
+
+ void add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv = true);
+
+ virtual AABB get_aabb() const;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ ImmediateGeometry3D();
+ ~ImmediateGeometry3D();
+};
+
+#endif // IMMEDIATE_GEOMETRY_H
diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp
deleted file mode 100644
index 592d592a38..0000000000
--- a/scene/3d/interpolated_camera.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*************************************************************************/
-/* interpolated_camera.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "interpolated_camera.h"
-
-#include "core/engine.h"
-
-void InterpolatedCamera::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
-
- if (Engine::get_singleton()->is_editor_hint() && enabled)
- set_process_internal(false);
-
- } break;
- case NOTIFICATION_INTERNAL_PROCESS: {
-
- if (!enabled)
- break;
- if (has_node(target)) {
-
- Spatial *node = Object::cast_to<Spatial>(get_node(target));
- if (!node)
- break;
-
- float delta = speed * get_process_delta_time();
- Transform target_xform = node->get_global_transform();
- Transform local_transform = get_global_transform();
- local_transform = local_transform.interpolate_with(target_xform, delta);
- set_global_transform(local_transform);
- Camera *cam = Object::cast_to<Camera>(node);
- if (cam) {
-
- if (cam->get_projection() == get_projection()) {
-
- float new_near = Math::lerp(get_znear(), cam->get_znear(), delta);
- float new_far = Math::lerp(get_zfar(), cam->get_zfar(), delta);
-
- if (cam->get_projection() == PROJECTION_ORTHOGONAL) {
-
- float size = Math::lerp(get_size(), cam->get_size(), delta);
- set_orthogonal(size, new_near, new_far);
- } else {
-
- float fov = Math::lerp(get_fov(), cam->get_fov(), delta);
- set_perspective(fov, new_near, new_far);
- }
- }
- }
- }
-
- } break;
- }
-}
-
-void InterpolatedCamera::_set_target(const Object *p_target) {
-
- ERR_FAIL_NULL(p_target);
- set_target(Object::cast_to<Spatial>(p_target));
-}
-
-void InterpolatedCamera::set_target(const Spatial *p_target) {
-
- ERR_FAIL_NULL(p_target);
- target = get_path_to(p_target);
-}
-
-void InterpolatedCamera::set_target_path(const NodePath &p_path) {
-
- target = p_path;
-}
-
-NodePath InterpolatedCamera::get_target_path() const {
-
- return target;
-}
-
-void InterpolatedCamera::set_interpolation_enabled(bool p_enable) {
-
- if (enabled == p_enable)
- return;
- enabled = p_enable;
- if (p_enable) {
- if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
- return;
- set_process_internal(true);
- } else
- set_process_internal(false);
-}
-
-bool InterpolatedCamera::is_interpolation_enabled() const {
-
- return enabled;
-}
-
-void InterpolatedCamera::set_speed(real_t p_speed) {
-
- speed = p_speed;
-}
-
-real_t InterpolatedCamera::get_speed() const {
-
- return speed;
-}
-
-void InterpolatedCamera::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_target_path", "target_path"), &InterpolatedCamera::set_target_path);
- ClassDB::bind_method(D_METHOD("get_target_path"), &InterpolatedCamera::get_target_path);
- ClassDB::bind_method(D_METHOD("set_target", "target"), &InterpolatedCamera::_set_target);
-
- ClassDB::bind_method(D_METHOD("set_speed", "speed"), &InterpolatedCamera::set_speed);
- ClassDB::bind_method(D_METHOD("get_speed"), &InterpolatedCamera::get_speed);
-
- ClassDB::bind_method(D_METHOD("set_interpolation_enabled", "target_path"), &InterpolatedCamera::set_interpolation_enabled);
- ClassDB::bind_method(D_METHOD("is_interpolation_enabled"), &InterpolatedCamera::is_interpolation_enabled);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target"), "set_target_path", "get_target_path");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_interpolation_enabled", "is_interpolation_enabled");
-}
-
-InterpolatedCamera::InterpolatedCamera() {
-
- enabled = false;
- speed = 1;
-}
diff --git a/scene/3d/interpolated_camera.h b/scene/3d/interpolated_camera.h
deleted file mode 100644
index 7b160c66fa..0000000000
--- a/scene/3d/interpolated_camera.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*************************************************************************/
-/* interpolated_camera.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 INTERPOLATED_CAMERA_H
-#define INTERPOLATED_CAMERA_H
-
-#include "scene/3d/camera.h"
-
-class InterpolatedCamera : public Camera {
-
- GDCLASS(InterpolatedCamera, Camera);
-
- bool enabled;
- real_t speed;
- NodePath target;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
- void _set_target(const Object *p_target);
-
-public:
- void set_target(const Spatial *p_target);
- void set_target_path(const NodePath &p_path);
- NodePath get_target_path() const;
-
- void set_speed(real_t p_speed);
- real_t get_speed() const;
-
- void set_interpolation_enabled(bool p_enable);
- bool is_interpolation_enabled() const;
-
- InterpolatedCamera();
-};
-
-#endif // INTERPOLATED_CAMERA_H
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
deleted file mode 100644
index 7c922ce1cd..0000000000
--- a/scene/3d/light.cpp
+++ /dev/null
@@ -1,480 +0,0 @@
-/*************************************************************************/
-/* light.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "light.h"
-
-#include "core/engine.h"
-#include "core/project_settings.h"
-#include "scene/resources/surface_tool.h"
-
-bool Light::_can_gizmo_scale() const {
-
- return false;
-}
-
-void Light::set_param(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- param[p_param] = p_value;
-
- VS::get_singleton()->light_set_param(light, VS::LightParam(p_param), p_value);
-
- if (p_param == PARAM_SPOT_ANGLE || p_param == PARAM_RANGE) {
- 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");
- }
- }
-}
-
-float Light::get_param(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return param[p_param];
-}
-
-void Light::set_shadow(bool p_enable) {
-
- shadow = p_enable;
- VS::get_singleton()->light_set_shadow(light, p_enable);
-
- if (type == VisualServer::LIGHT_SPOT) {
- update_configuration_warning();
- }
-}
-bool Light::has_shadow() const {
-
- return shadow;
-}
-
-void Light::set_negative(bool p_enable) {
-
- negative = p_enable;
- VS::get_singleton()->light_set_negative(light, p_enable);
-}
-bool Light::is_negative() const {
-
- return negative;
-}
-
-void Light::set_cull_mask(uint32_t p_cull_mask) {
-
- cull_mask = p_cull_mask;
- VS::get_singleton()->light_set_cull_mask(light, p_cull_mask);
-}
-uint32_t Light::get_cull_mask() const {
-
- return cull_mask;
-}
-
-void Light::set_color(const Color &p_color) {
-
- color = p_color;
- VS::get_singleton()->light_set_color(light, p_color);
- // The gizmo color depends on the light color, so update it.
- update_gizmo();
-}
-Color Light::get_color() const {
-
- return color;
-}
-
-void Light::set_shadow_color(const Color &p_shadow_color) {
-
- shadow_color = p_shadow_color;
- VS::get_singleton()->light_set_shadow_color(light, p_shadow_color);
-}
-
-Color Light::get_shadow_color() const {
-
- return shadow_color;
-}
-
-void Light::set_shadow_reverse_cull_face(bool p_enable) {
- reverse_cull = p_enable;
- VS::get_singleton()->light_set_reverse_cull_face_mode(light, reverse_cull);
-}
-
-bool Light::get_shadow_reverse_cull_face() const {
-
- return reverse_cull;
-}
-
-AABB Light::get_aabb() const {
-
- if (type == VisualServer::LIGHT_DIRECTIONAL) {
-
- return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
-
- } else if (type == VisualServer::LIGHT_OMNI) {
-
- return AABB(Vector3(-1, -1, -1) * param[PARAM_RANGE], Vector3(2, 2, 2) * param[PARAM_RANGE]);
-
- } else if (type == VisualServer::LIGHT_SPOT) {
-
- float len = param[PARAM_RANGE];
- float size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
- return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
- }
-
- return AABB();
-}
-
-Vector<Face3> Light::get_faces(uint32_t p_usage_flags) const {
-
- return Vector<Face3>();
-}
-
-void Light::set_bake_mode(BakeMode p_mode) {
- bake_mode = p_mode;
- VS::get_singleton()->light_set_use_gi(light, p_mode != BAKE_DISABLED);
-}
-
-Light::BakeMode Light::get_bake_mode() const {
- return bake_mode;
-}
-
-void Light::_update_visibility() {
-
- if (!is_inside_tree())
- return;
-
- bool editor_ok = true;
-
-#ifdef TOOLS_ENABLED
- if (editor_only) {
- if (!Engine::get_singleton()->is_editor_hint()) {
- editor_ok = false;
- } else {
- editor_ok = (get_tree()->get_edited_scene_root() && (this == get_tree()->get_edited_scene_root() || get_owner() == get_tree()->get_edited_scene_root()));
- }
- }
-#else
- if (editor_only) {
- editor_ok = false;
- }
-#endif
-
- VS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree() && editor_ok);
-
- _change_notify("geometry/visible");
-}
-
-void Light::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
-
- _update_visibility();
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
- _update_visibility();
- }
-}
-
-void Light::set_editor_only(bool p_editor_only) {
-
- editor_only = p_editor_only;
- _update_visibility();
-}
-
-bool Light::is_editor_only() const {
-
- return editor_only;
-}
-
-void Light::_validate_property(PropertyInfo &property) const {
-
- if (VisualServer::get_singleton()->is_low_end() && property.name == "shadow_contact") {
- property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
- }
-}
-
-void Light::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light::set_editor_only);
- ClassDB::bind_method(D_METHOD("is_editor_only"), &Light::is_editor_only);
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &Light::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &Light::get_param);
-
- ClassDB::bind_method(D_METHOD("set_shadow", "enabled"), &Light::set_shadow);
- ClassDB::bind_method(D_METHOD("has_shadow"), &Light::has_shadow);
-
- ClassDB::bind_method(D_METHOD("set_negative", "enabled"), &Light::set_negative);
- ClassDB::bind_method(D_METHOD("is_negative"), &Light::is_negative);
-
- ClassDB::bind_method(D_METHOD("set_cull_mask", "cull_mask"), &Light::set_cull_mask);
- ClassDB::bind_method(D_METHOD("get_cull_mask"), &Light::get_cull_mask);
-
- ClassDB::bind_method(D_METHOD("set_color", "color"), &Light::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &Light::get_color);
-
- ClassDB::bind_method(D_METHOD("set_shadow_reverse_cull_face", "enable"), &Light::set_shadow_reverse_cull_face);
- ClassDB::bind_method(D_METHOD("get_shadow_reverse_cull_face"), &Light::get_shadow_reverse_cull_face);
-
- ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light::set_shadow_color);
- ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light::get_shadow_color);
-
- ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light::set_bake_mode);
- ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light::get_bake_mode);
-
- ADD_GROUP("Light", "light_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
- ADD_GROUP("Shadow", "shadow_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_contact", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_CONTACT_SHADOW_SIZE);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
- ADD_GROUP("Editor", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
- ADD_GROUP("", "");
-
- BIND_ENUM_CONSTANT(PARAM_ENERGY);
- BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY);
- BIND_ENUM_CONSTANT(PARAM_SPECULAR);
- BIND_ENUM_CONSTANT(PARAM_RANGE);
- BIND_ENUM_CONSTANT(PARAM_ATTENUATION);
- BIND_ENUM_CONSTANT(PARAM_SPOT_ANGLE);
- BIND_ENUM_CONSTANT(PARAM_SPOT_ATTENUATION);
- BIND_ENUM_CONSTANT(PARAM_CONTACT_SHADOW_SIZE);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_MAX_DISTANCE);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_1_OFFSET);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_2_OFFSET);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_3_OFFSET);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_FADE_START);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
- BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE);
- BIND_ENUM_CONSTANT(PARAM_MAX);
-
- BIND_ENUM_CONSTANT(BAKE_DISABLED);
- BIND_ENUM_CONSTANT(BAKE_INDIRECT);
- BIND_ENUM_CONSTANT(BAKE_ALL);
-}
-
-Light::Light(VisualServer::LightType p_type) {
-
- type = p_type;
- switch (p_type) {
- case VS::LIGHT_DIRECTIONAL: light = VisualServer::get_singleton()->directional_light_create(); break;
- case VS::LIGHT_OMNI: light = VisualServer::get_singleton()->omni_light_create(); break;
- case VS::LIGHT_SPOT: light = VisualServer::get_singleton()->spot_light_create(); break;
- default: {
- };
- }
-
- VS::get_singleton()->instance_set_base(get_instance(), light);
-
- reverse_cull = false;
- bake_mode = BAKE_INDIRECT;
-
- editor_only = false;
- set_color(Color(1, 1, 1, 1));
- set_shadow(false);
- set_negative(false);
- set_cull_mask(0xFFFFFFFF);
-
- set_param(PARAM_ENERGY, 1);
- set_param(PARAM_INDIRECT_ENERGY, 1);
- set_param(PARAM_SPECULAR, 0.5);
- set_param(PARAM_RANGE, 5);
- set_param(PARAM_ATTENUATION, 1);
- set_param(PARAM_SPOT_ANGLE, 45);
- set_param(PARAM_SPOT_ATTENUATION, 1);
- set_param(PARAM_CONTACT_SHADOW_SIZE, 0);
- set_param(PARAM_SHADOW_MAX_DISTANCE, 0);
- set_param(PARAM_SHADOW_SPLIT_1_OFFSET, 0.1);
- set_param(PARAM_SHADOW_SPLIT_2_OFFSET, 0.2);
- set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
- set_param(PARAM_SHADOW_FADE_START, 0.8);
- set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0);
- set_param(PARAM_SHADOW_BIAS, 0.15);
- set_param(PARAM_SHADOW_FADE_START, 1);
- set_disable_scale(true);
-}
-
-Light::Light() {
-
- type = VisualServer::LIGHT_DIRECTIONAL;
- ERR_PRINT("Light should not be instanced directly; use the DirectionalLight, OmniLight or SpotLight subtypes instead.");
-}
-
-Light::~Light() {
-
- VS::get_singleton()->instance_set_base(get_instance(), RID());
-
- if (light.is_valid())
- VisualServer::get_singleton()->free(light);
-}
-/////////////////////////////////////////
-
-void DirectionalLight::set_shadow_mode(ShadowMode p_mode) {
-
- shadow_mode = p_mode;
- VS::get_singleton()->light_directional_set_shadow_mode(light, VS::LightDirectionalShadowMode(p_mode));
-}
-
-DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const {
-
- return shadow_mode;
-}
-
-void DirectionalLight::set_shadow_depth_range(ShadowDepthRange p_range) {
- shadow_depth_range = p_range;
- VS::get_singleton()->light_directional_set_shadow_depth_range_mode(light, VS::LightDirectionalShadowDepthRangeMode(p_range));
-}
-
-DirectionalLight::ShadowDepthRange DirectionalLight::get_shadow_depth_range() const {
-
- return shadow_depth_range;
-}
-
-void DirectionalLight::set_blend_splits(bool p_enable) {
-
- blend_splits = p_enable;
- VS::get_singleton()->light_directional_set_blend_splits(light, p_enable);
-}
-
-bool DirectionalLight::is_blend_splits_enabled() const {
-
- return blend_splits;
-}
-
-void DirectionalLight::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight::set_shadow_mode);
- ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight::get_shadow_mode);
-
- ClassDB::bind_method(D_METHOD("set_shadow_depth_range", "mode"), &DirectionalLight::set_shadow_depth_range);
- ClassDB::bind_method(D_METHOD("get_shadow_depth_range"), &DirectionalLight::get_shadow_depth_range);
-
- ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight::set_blend_splits);
- ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight::is_blend_splits_enabled);
-
- ADD_GROUP("Directional Shadow", "directional_shadow_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), "set_shadow_mode", "get_shadow_mode");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
-
- BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
- BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
- BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
-
- BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_STABLE);
- BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_OPTIMIZED);
-}
-
-DirectionalLight::DirectionalLight() :
- Light(VisualServer::LIGHT_DIRECTIONAL) {
-
- set_param(PARAM_SHADOW_NORMAL_BIAS, 0.8);
- set_param(PARAM_SHADOW_BIAS, 0.1);
- set_param(PARAM_SHADOW_MAX_DISTANCE, 100);
- set_param(PARAM_SHADOW_FADE_START, 0.8);
- set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25);
- set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
- set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);
-
- blend_splits = false;
-}
-
-void OmniLight::set_shadow_mode(ShadowMode p_mode) {
-
- shadow_mode = p_mode;
- VS::get_singleton()->light_omni_set_shadow_mode(light, VS::LightOmniShadowMode(p_mode));
-}
-
-OmniLight::ShadowMode OmniLight::get_shadow_mode() const {
-
- return shadow_mode;
-}
-
-void OmniLight::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &OmniLight::set_shadow_mode);
- ClassDB::bind_method(D_METHOD("get_shadow_mode"), &OmniLight::get_shadow_mode);
-
- ADD_GROUP("Omni", "omni_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
-
- BIND_ENUM_CONSTANT(SHADOW_DUAL_PARABOLOID);
- BIND_ENUM_CONSTANT(SHADOW_CUBE);
-}
-
-OmniLight::OmniLight() :
- Light(VisualServer::LIGHT_OMNI) {
-
- set_shadow_mode(SHADOW_CUBE);
-}
-
-String SpotLight::get_configuration_warning() const {
- String warning = Light::get_configuration_warning();
-
- if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
- if (warning != String()) {
- warning += "\n\n";
- }
-
- warning += TTR("A SpotLight with an angle wider than 90 degrees cannot cast shadows.");
- }
-
- return warning;
-}
-
-void SpotLight::_bind_methods() {
-
- ADD_GROUP("Spot", "spot_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
-}
diff --git a/scene/3d/light.h b/scene/3d/light.h
deleted file mode 100644
index 16e0c47083..0000000000
--- a/scene/3d/light.h
+++ /dev/null
@@ -1,216 +0,0 @@
-/*************************************************************************/
-/* light.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 LIGHT_H
-#define LIGHT_H
-
-#include "scene/3d/visual_instance.h"
-#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
-
-class Light : public VisualInstance {
-
- GDCLASS(Light, VisualInstance);
- OBJ_CATEGORY("3D Light Nodes");
-
-public:
- enum Param {
- PARAM_ENERGY = VS::LIGHT_PARAM_ENERGY,
- PARAM_INDIRECT_ENERGY = VS::LIGHT_PARAM_INDIRECT_ENERGY,
- PARAM_SPECULAR = VS::LIGHT_PARAM_SPECULAR,
- PARAM_RANGE = VS::LIGHT_PARAM_RANGE,
- PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION,
- PARAM_SPOT_ANGLE = VS::LIGHT_PARAM_SPOT_ANGLE,
- PARAM_SPOT_ATTENUATION = VS::LIGHT_PARAM_SPOT_ATTENUATION,
- PARAM_CONTACT_SHADOW_SIZE = VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE,
- PARAM_SHADOW_MAX_DISTANCE = VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE,
- PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
- PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
- PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
- PARAM_SHADOW_FADE_START = VS::LIGHT_PARAM_SHADOW_FADE_START,
- PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
- PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS,
- PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
- PARAM_MAX = VS::LIGHT_PARAM_MAX
- };
-
- enum BakeMode {
- BAKE_DISABLED,
- BAKE_INDIRECT,
- BAKE_ALL
- };
-
-private:
- Color color;
- float param[PARAM_MAX];
- Color shadow_color;
- bool shadow;
- bool negative;
- bool reverse_cull;
- uint32_t cull_mask;
- VS::LightType type;
- bool editor_only;
- void _update_visibility();
- BakeMode bake_mode;
-
- // bind helpers
-
-protected:
- RID light;
-
- virtual bool _can_gizmo_scale() const;
-
- static void _bind_methods();
- void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const;
-
- Light(VisualServer::LightType p_type);
-
-public:
- VS::LightType get_light_type() const { return type; }
-
- void set_editor_only(bool p_editor_only);
- bool is_editor_only() const;
-
- void set_param(Param p_param, float p_value);
- float get_param(Param p_param) const;
-
- void set_shadow(bool p_enable);
- bool has_shadow() const;
-
- void set_negative(bool p_enable);
- bool is_negative() const;
-
- void set_cull_mask(uint32_t p_cull_mask);
- uint32_t get_cull_mask() const;
-
- void set_color(const Color &p_color);
- Color get_color() const;
-
- void set_shadow_color(const Color &p_shadow_color);
- Color get_shadow_color() const;
-
- void set_shadow_reverse_cull_face(bool p_enable);
- bool get_shadow_reverse_cull_face() const;
-
- void set_bake_mode(BakeMode p_mode);
- BakeMode get_bake_mode() const;
-
- virtual AABB get_aabb() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
-
- Light();
- ~Light();
-};
-
-VARIANT_ENUM_CAST(Light::Param);
-VARIANT_ENUM_CAST(Light::BakeMode);
-
-class DirectionalLight : public Light {
-
- GDCLASS(DirectionalLight, Light);
-
-public:
- enum ShadowMode {
- SHADOW_ORTHOGONAL,
- SHADOW_PARALLEL_2_SPLITS,
- SHADOW_PARALLEL_4_SPLITS
- };
-
- enum ShadowDepthRange {
- SHADOW_DEPTH_RANGE_STABLE = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
- SHADOW_DEPTH_RANGE_OPTIMIZED = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED,
- };
-
-private:
- bool blend_splits;
- ShadowMode shadow_mode;
- ShadowDepthRange shadow_depth_range;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_shadow_mode(ShadowMode p_mode);
- ShadowMode get_shadow_mode() const;
-
- void set_shadow_depth_range(ShadowDepthRange p_range);
- ShadowDepthRange get_shadow_depth_range() const;
-
- void set_blend_splits(bool p_enable);
- bool is_blend_splits_enabled() const;
-
- DirectionalLight();
-};
-
-VARIANT_ENUM_CAST(DirectionalLight::ShadowMode)
-VARIANT_ENUM_CAST(DirectionalLight::ShadowDepthRange)
-
-class OmniLight : public Light {
-
- GDCLASS(OmniLight, Light);
-
-public:
- // omni light
- enum ShadowMode {
- SHADOW_DUAL_PARABOLOID,
- SHADOW_CUBE,
- };
-
-private:
- ShadowMode shadow_mode;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_shadow_mode(ShadowMode p_mode);
- ShadowMode get_shadow_mode() const;
-
- OmniLight();
-};
-
-VARIANT_ENUM_CAST(OmniLight::ShadowMode)
-
-class SpotLight : public Light {
-
- GDCLASS(SpotLight, Light);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual String get_configuration_warning() const;
-
- SpotLight() :
- Light(VisualServer::LIGHT_SPOT) {}
-};
-
-#endif
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
new file mode 100644
index 0000000000..9928246d2b
--- /dev/null
+++ b/scene/3d/light_3d.cpp
@@ -0,0 +1,528 @@
+/*************************************************************************/
+/* light_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "light_3d.h"
+
+#include "core/engine.h"
+#include "core/project_settings.h"
+#include "scene/resources/surface_tool.h"
+
+bool Light3D::_can_gizmo_scale() const {
+
+ return false;
+}
+
+void Light3D::set_param(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ param[p_param] = p_value;
+
+ RS::get_singleton()->light_set_param(light, RS::LightParam(p_param), p_value);
+
+ if (p_param == PARAM_SPOT_ANGLE || p_param == PARAM_RANGE) {
+ 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");
+ }
+ }
+}
+
+float Light3D::get_param(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return param[p_param];
+}
+
+void Light3D::set_shadow(bool p_enable) {
+
+ shadow = p_enable;
+ RS::get_singleton()->light_set_shadow(light, p_enable);
+
+ if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {
+ update_configuration_warning();
+ }
+}
+bool Light3D::has_shadow() const {
+
+ return shadow;
+}
+
+void Light3D::set_negative(bool p_enable) {
+
+ negative = p_enable;
+ RS::get_singleton()->light_set_negative(light, p_enable);
+}
+bool Light3D::is_negative() const {
+
+ return negative;
+}
+
+void Light3D::set_cull_mask(uint32_t p_cull_mask) {
+
+ cull_mask = p_cull_mask;
+ RS::get_singleton()->light_set_cull_mask(light, p_cull_mask);
+}
+uint32_t Light3D::get_cull_mask() const {
+
+ return cull_mask;
+}
+
+void Light3D::set_color(const Color &p_color) {
+
+ color = p_color;
+ RS::get_singleton()->light_set_color(light, p_color);
+ // The gizmo color depends on the light color, so update it.
+ update_gizmo();
+}
+Color Light3D::get_color() const {
+
+ return color;
+}
+
+void Light3D::set_shadow_color(const Color &p_shadow_color) {
+
+ shadow_color = p_shadow_color;
+ RS::get_singleton()->light_set_shadow_color(light, p_shadow_color);
+}
+
+Color Light3D::get_shadow_color() const {
+
+ return shadow_color;
+}
+
+void Light3D::set_shadow_reverse_cull_face(bool p_enable) {
+ reverse_cull = p_enable;
+ RS::get_singleton()->light_set_reverse_cull_face_mode(light, reverse_cull);
+}
+
+bool Light3D::get_shadow_reverse_cull_face() const {
+
+ return reverse_cull;
+}
+
+AABB Light3D::get_aabb() const {
+
+ if (type == RenderingServer::LIGHT_DIRECTIONAL) {
+
+ return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+
+ } else if (type == RenderingServer::LIGHT_OMNI) {
+
+ return AABB(Vector3(-1, -1, -1) * param[PARAM_RANGE], Vector3(2, 2, 2) * param[PARAM_RANGE]);
+
+ } else if (type == RenderingServer::LIGHT_SPOT) {
+
+ float len = param[PARAM_RANGE];
+ float size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
+ return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
+ }
+
+ return AABB();
+}
+
+Vector<Face3> Light3D::get_faces(uint32_t p_usage_flags) const {
+
+ return Vector<Face3>();
+}
+
+void Light3D::set_bake_mode(BakeMode p_mode) {
+ bake_mode = p_mode;
+ RS::get_singleton()->light_set_use_gi(light, p_mode != BAKE_DISABLED);
+}
+
+Light3D::BakeMode Light3D::get_bake_mode() const {
+ return bake_mode;
+}
+
+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();
+}
+
+Ref<Texture2D> Light3D::get_projector() const {
+ return projector;
+}
+
+void Light3D::_update_visibility() {
+
+ if (!is_inside_tree())
+ return;
+
+ bool editor_ok = true;
+
+#ifdef TOOLS_ENABLED
+ if (editor_only) {
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ editor_ok = false;
+ } else {
+ editor_ok = (get_tree()->get_edited_scene_root() && (this == get_tree()->get_edited_scene_root() || get_owner() == get_tree()->get_edited_scene_root()));
+ }
+ }
+#else
+ if (editor_only) {
+ editor_ok = false;
+ }
+#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) {
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ _update_visibility();
+ }
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ _update_visibility();
+ }
+}
+
+void Light3D::set_editor_only(bool p_editor_only) {
+
+ editor_only = p_editor_only;
+ _update_visibility();
+}
+
+bool Light3D::is_editor_only() const {
+
+ return editor_only;
+}
+
+void Light3D::_validate_property(PropertyInfo &property) const {
+
+ if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") {
+ property.usage = 0;
+ }
+
+ if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_projector") {
+ property.usage = 0;
+ }
+
+ if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
+ property.usage = 0;
+ }
+}
+
+void Light3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_editor_only", "editor_only"), &Light3D::set_editor_only);
+ ClassDB::bind_method(D_METHOD("is_editor_only"), &Light3D::is_editor_only);
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &Light3D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &Light3D::get_param);
+
+ ClassDB::bind_method(D_METHOD("set_shadow", "enabled"), &Light3D::set_shadow);
+ ClassDB::bind_method(D_METHOD("has_shadow"), &Light3D::has_shadow);
+
+ ClassDB::bind_method(D_METHOD("set_negative", "enabled"), &Light3D::set_negative);
+ ClassDB::bind_method(D_METHOD("is_negative"), &Light3D::is_negative);
+
+ ClassDB::bind_method(D_METHOD("set_cull_mask", "cull_mask"), &Light3D::set_cull_mask);
+ ClassDB::bind_method(D_METHOD("get_cull_mask"), &Light3D::get_cull_mask);
+
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &Light3D::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &Light3D::get_color);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_reverse_cull_face", "enable"), &Light3D::set_shadow_reverse_cull_face);
+ ClassDB::bind_method(D_METHOD("get_shadow_reverse_cull_face"), &Light3D::get_shadow_reverse_cull_face);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light3D::set_shadow_color);
+ ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light3D::get_shadow_color);
+
+ ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode);
+ ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode);
+
+ ClassDB::bind_method(D_METHOD("set_projector", "projector"), &Light3D::set_projector);
+ ClassDB::bind_method(D_METHOD("get_projector"), &Light3D::get_projector);
+
+ ADD_GROUP("Light", "light_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_projector", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_projector", "get_projector");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,64,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+ ADD_GROUP("Shadow", "shadow_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR);
+ ADD_GROUP("Editor", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
+ ADD_GROUP("", "");
+
+ BIND_ENUM_CONSTANT(PARAM_ENERGY);
+ BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY);
+ BIND_ENUM_CONSTANT(PARAM_SPECULAR);
+ BIND_ENUM_CONSTANT(PARAM_RANGE);
+ BIND_ENUM_CONSTANT(PARAM_ATTENUATION);
+ BIND_ENUM_CONSTANT(PARAM_SPOT_ANGLE);
+ BIND_ENUM_CONSTANT(PARAM_SPOT_ATTENUATION);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_MAX_DISTANCE);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_1_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_2_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_3_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_FADE_START);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
+ BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(BAKE_DISABLED);
+ BIND_ENUM_CONSTANT(BAKE_INDIRECT);
+ BIND_ENUM_CONSTANT(BAKE_ALL);
+}
+
+Light3D::Light3D(RenderingServer::LightType p_type) {
+
+ type = p_type;
+ switch (p_type) {
+ case RS::LIGHT_DIRECTIONAL: light = RenderingServer::get_singleton()->directional_light_create(); break;
+ case RS::LIGHT_OMNI: light = RenderingServer::get_singleton()->omni_light_create(); break;
+ case RS::LIGHT_SPOT: light = RenderingServer::get_singleton()->spot_light_create(); break;
+ default: {
+ };
+ }
+
+ RS::get_singleton()->instance_set_base(get_instance(), light);
+
+ reverse_cull = false;
+ bake_mode = BAKE_INDIRECT;
+
+ editor_only = false;
+ set_color(Color(1, 1, 1, 1));
+ set_shadow(false);
+ set_negative(false);
+ set_cull_mask(0xFFFFFFFF);
+
+ set_param(PARAM_ENERGY, 1);
+ set_param(PARAM_INDIRECT_ENERGY, 1);
+ set_param(PARAM_SPECULAR, 0.5);
+ set_param(PARAM_RANGE, 5);
+ set_param(PARAM_SIZE, 0);
+ set_param(PARAM_ATTENUATION, 1);
+ set_param(PARAM_SPOT_ANGLE, 45);
+ set_param(PARAM_SPOT_ATTENUATION, 1);
+ set_param(PARAM_SHADOW_MAX_DISTANCE, 0);
+ set_param(PARAM_SHADOW_SPLIT_1_OFFSET, 0.1);
+ set_param(PARAM_SHADOW_SPLIT_2_OFFSET, 0.2);
+ set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
+ set_param(PARAM_SHADOW_FADE_START, 0.8);
+ set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0);
+ set_param(PARAM_SHADOW_BLUR, 1.0);
+ set_param(PARAM_SHADOW_BIAS, 0.02);
+ set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
+ set_param(PARAM_TRANSMITTANCE_BIAS, 0.05);
+ set_param(PARAM_SHADOW_FADE_START, 1);
+ set_disable_scale(true);
+}
+
+Light3D::Light3D() {
+
+ type = RenderingServer::LIGHT_DIRECTIONAL;
+ ERR_PRINT("Light3D should not be instanced directly; use the DirectionalLight3D, OmniLight3D or SpotLight3D subtypes instead.");
+}
+
+Light3D::~Light3D() {
+
+ RS::get_singleton()->instance_set_base(get_instance(), RID());
+
+ if (light.is_valid())
+ RenderingServer::get_singleton()->free(light);
+}
+/////////////////////////////////////////
+
+void DirectionalLight3D::set_shadow_mode(ShadowMode p_mode) {
+
+ shadow_mode = p_mode;
+ RS::get_singleton()->light_directional_set_shadow_mode(light, RS::LightDirectionalShadowMode(p_mode));
+}
+
+DirectionalLight3D::ShadowMode DirectionalLight3D::get_shadow_mode() const {
+
+ return shadow_mode;
+}
+
+void DirectionalLight3D::set_shadow_depth_range(ShadowDepthRange p_range) {
+ shadow_depth_range = p_range;
+ RS::get_singleton()->light_directional_set_shadow_depth_range_mode(light, RS::LightDirectionalShadowDepthRangeMode(p_range));
+}
+
+DirectionalLight3D::ShadowDepthRange DirectionalLight3D::get_shadow_depth_range() const {
+
+ return shadow_depth_range;
+}
+
+void DirectionalLight3D::set_blend_splits(bool p_enable) {
+
+ blend_splits = p_enable;
+ RS::get_singleton()->light_directional_set_blend_splits(light, p_enable);
+}
+
+bool DirectionalLight3D::is_blend_splits_enabled() const {
+
+ return blend_splits;
+}
+
+void DirectionalLight3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight3D::set_shadow_mode);
+ ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight3D::get_shadow_mode);
+
+ ClassDB::bind_method(D_METHOD("set_shadow_depth_range", "mode"), &DirectionalLight3D::set_shadow_depth_range);
+ ClassDB::bind_method(D_METHOD("get_shadow_depth_range"), &DirectionalLight3D::get_shadow_depth_range);
+
+ ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight3D::set_blend_splits);
+ ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight3D::is_blend_splits_enabled);
+
+ ADD_GROUP("Directional Shadow", "directional_shadow_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), "set_shadow_mode", "get_shadow_mode");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_EXP_RANGE, "0,1024,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE);
+
+ BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
+ BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
+ BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
+
+ BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_STABLE);
+ BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_OPTIMIZED);
+}
+
+DirectionalLight3D::DirectionalLight3D() :
+ Light3D(RenderingServer::LIGHT_DIRECTIONAL) {
+
+ set_param(PARAM_SHADOW_MAX_DISTANCE, 100);
+ set_param(PARAM_SHADOW_FADE_START, 0.8);
+ set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
+ set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);
+
+ blend_splits = false;
+}
+
+void OmniLight3D::set_shadow_mode(ShadowMode p_mode) {
+
+ shadow_mode = p_mode;
+ RS::get_singleton()->light_omni_set_shadow_mode(light, RS::LightOmniShadowMode(p_mode));
+}
+
+OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
+
+ return shadow_mode;
+}
+
+String OmniLight3D::get_configuration_warning() const {
+ String warning = Light3D::get_configuration_warning();
+
+ if (!has_shadow() && get_projector().is_valid()) {
+ if (warning != String()) {
+ warning += "\n\n";
+ }
+ warning += TTR("Projector texture only works with shadows active.");
+ }
+
+ return warning;
+}
+
+void OmniLight3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &OmniLight3D::set_shadow_mode);
+ ClassDB::bind_method(D_METHOD("get_shadow_mode"), &OmniLight3D::get_shadow_mode);
+
+ ADD_GROUP("Omni", "omni_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
+
+ BIND_ENUM_CONSTANT(SHADOW_DUAL_PARABOLOID);
+ BIND_ENUM_CONSTANT(SHADOW_CUBE);
+}
+
+OmniLight3D::OmniLight3D() :
+ Light3D(RenderingServer::LIGHT_OMNI) {
+
+ set_shadow_mode(SHADOW_CUBE);
+}
+
+String SpotLight3D::get_configuration_warning() const {
+ String warning = Light3D::get_configuration_warning();
+
+ if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
+ if (warning != String()) {
+ warning += "\n\n";
+ }
+
+ warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
+ }
+
+ if (!has_shadow() && get_projector().is_valid()) {
+ if (warning != String()) {
+ warning += "\n\n";
+ }
+ warning += TTR("Projector texture only works with shadows active.");
+ }
+
+ return warning;
+}
+
+void SpotLight3D::_bind_methods() {
+
+ ADD_GROUP("Spot", "spot_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
+}
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
new file mode 100644
index 0000000000..6e78217342
--- /dev/null
+++ b/scene/3d/light_3d.h
@@ -0,0 +1,224 @@
+/*************************************************************************/
+/* light_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 LIGHT_H
+#define LIGHT_H
+
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/texture.h"
+#include "servers/rendering_server.h"
+
+class Light3D : public VisualInstance3D {
+
+ GDCLASS(Light3D, VisualInstance3D);
+ OBJ_CATEGORY("3D Light Nodes");
+
+public:
+ enum Param {
+ PARAM_ENERGY = RS::LIGHT_PARAM_ENERGY,
+ PARAM_INDIRECT_ENERGY = RS::LIGHT_PARAM_INDIRECT_ENERGY,
+ PARAM_SPECULAR = RS::LIGHT_PARAM_SPECULAR,
+ PARAM_RANGE = RS::LIGHT_PARAM_RANGE,
+ PARAM_SIZE = RS::LIGHT_PARAM_SIZE,
+ PARAM_ATTENUATION = RS::LIGHT_PARAM_ATTENUATION,
+ PARAM_SPOT_ANGLE = RS::LIGHT_PARAM_SPOT_ANGLE,
+ PARAM_SPOT_ATTENUATION = RS::LIGHT_PARAM_SPOT_ATTENUATION,
+ PARAM_SHADOW_MAX_DISTANCE = RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE,
+ PARAM_SHADOW_SPLIT_1_OFFSET = RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
+ PARAM_SHADOW_SPLIT_2_OFFSET = RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
+ PARAM_SHADOW_SPLIT_3_OFFSET = RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
+ PARAM_SHADOW_FADE_START = RS::LIGHT_PARAM_SHADOW_FADE_START,
+ PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
+ PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
+ PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
+ PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR,
+ PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
+ PARAM_MAX = RS::LIGHT_PARAM_MAX
+ };
+
+ enum BakeMode {
+ BAKE_DISABLED,
+ BAKE_INDIRECT,
+ BAKE_ALL
+ };
+
+private:
+ Color color;
+ float param[PARAM_MAX];
+ Color shadow_color;
+ bool shadow;
+ bool negative;
+ bool reverse_cull;
+ uint32_t cull_mask;
+ RS::LightType type;
+ bool editor_only;
+ void _update_visibility();
+ BakeMode bake_mode;
+ Ref<Texture2D> projector;
+
+ // bind helpers
+
+protected:
+ RID light;
+
+ virtual bool _can_gizmo_scale() const;
+
+ static void _bind_methods();
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
+
+ Light3D(RenderingServer::LightType p_type);
+
+public:
+ RS::LightType get_light_type() const { return type; }
+
+ void set_editor_only(bool p_editor_only);
+ bool is_editor_only() const;
+
+ void set_param(Param p_param, float p_value);
+ float get_param(Param p_param) const;
+
+ void set_shadow(bool p_enable);
+ bool has_shadow() const;
+
+ void set_negative(bool p_enable);
+ bool is_negative() const;
+
+ void set_cull_mask(uint32_t p_cull_mask);
+ uint32_t get_cull_mask() const;
+
+ void set_color(const Color &p_color);
+ Color get_color() const;
+
+ void set_shadow_color(const Color &p_shadow_color);
+ Color get_shadow_color() const;
+
+ void set_shadow_reverse_cull_face(bool p_enable);
+ bool get_shadow_reverse_cull_face() const;
+
+ void set_bake_mode(BakeMode p_mode);
+ BakeMode get_bake_mode() const;
+
+ void set_projector(const Ref<Texture2D> &p_texture);
+ Ref<Texture2D> get_projector() const;
+
+ virtual AABB get_aabb() const;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ Light3D();
+ ~Light3D();
+};
+
+VARIANT_ENUM_CAST(Light3D::Param);
+VARIANT_ENUM_CAST(Light3D::BakeMode);
+
+class DirectionalLight3D : public Light3D {
+
+ GDCLASS(DirectionalLight3D, Light3D);
+
+public:
+ enum ShadowMode {
+ SHADOW_ORTHOGONAL,
+ SHADOW_PARALLEL_2_SPLITS,
+ SHADOW_PARALLEL_4_SPLITS
+ };
+
+ enum ShadowDepthRange {
+ SHADOW_DEPTH_RANGE_STABLE = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
+ SHADOW_DEPTH_RANGE_OPTIMIZED = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED,
+ };
+
+private:
+ bool blend_splits;
+ ShadowMode shadow_mode;
+ ShadowDepthRange shadow_depth_range;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_shadow_mode(ShadowMode p_mode);
+ ShadowMode get_shadow_mode() const;
+
+ void set_shadow_depth_range(ShadowDepthRange p_range);
+ ShadowDepthRange get_shadow_depth_range() const;
+
+ void set_blend_splits(bool p_enable);
+ bool is_blend_splits_enabled() const;
+
+ DirectionalLight3D();
+};
+
+VARIANT_ENUM_CAST(DirectionalLight3D::ShadowMode)
+VARIANT_ENUM_CAST(DirectionalLight3D::ShadowDepthRange)
+
+class OmniLight3D : public Light3D {
+
+ GDCLASS(OmniLight3D, Light3D);
+
+public:
+ // omni light
+ enum ShadowMode {
+ SHADOW_DUAL_PARABOLOID,
+ SHADOW_CUBE,
+ };
+
+private:
+ ShadowMode shadow_mode;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_shadow_mode(ShadowMode p_mode);
+ ShadowMode get_shadow_mode() const;
+
+ virtual String get_configuration_warning() const;
+
+ OmniLight3D();
+};
+
+VARIANT_ENUM_CAST(OmniLight3D::ShadowMode)
+
+class SpotLight3D : public Light3D {
+
+ GDCLASS(SpotLight3D, Light3D);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_configuration_warning() const;
+
+ SpotLight3D() :
+ Light3D(RenderingServer::LIGHT_SPOT) {}
+};
+
+#endif
diff --git a/scene/3d/listener.cpp b/scene/3d/listener.cpp
deleted file mode 100644
index 2779d14b57..0000000000
--- a/scene/3d/listener.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*************************************************************************/
-/* listener.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "listener.h"
-
-#include "scene/resources/mesh.h"
-
-void Listener::_update_audio_listener_state() {
-}
-
-void Listener::_request_listener_update() {
-
- _update_listener();
-}
-
-bool Listener::_set(const StringName &p_name, const Variant &p_value) {
-
- if (p_name == "current") {
- if (p_value.operator bool()) {
- make_current();
- } else {
- clear_current();
- }
- } else
- return false;
-
- return true;
-}
-bool Listener::_get(const StringName &p_name, Variant &r_ret) const {
-
- if (p_name == "current") {
- if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
- r_ret = current;
- } else {
- r_ret = is_current();
- }
- } else
- return false;
-
- return true;
-}
-
-void Listener::_get_property_list(List<PropertyInfo> *p_list) const {
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
-}
-
-void Listener::_update_listener() {
-
- if (is_inside_tree() && is_current()) {
- get_viewport()->_listener_transform_changed_notify();
- }
-}
-
-void Listener::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_WORLD: {
- bool first_listener = get_viewport()->_listener_add(this);
- if (!get_tree()->is_node_being_edited(this) && (current || first_listener))
- make_current();
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
- _request_listener_update();
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- if (!get_tree()->is_node_being_edited(this)) {
- if (is_current()) {
- clear_current();
- current = true; //keep it true
-
- } else {
- current = false;
- }
- }
-
- get_viewport()->_listener_remove(this);
-
- } break;
- }
-}
-
-Transform Listener::get_listener_transform() const {
-
- return get_global_transform().orthonormalized();
-}
-
-void Listener::make_current() {
-
- current = true;
-
- if (!is_inside_tree())
- return;
-
- get_viewport()->_listener_set(this);
-}
-
-void Listener::clear_current() {
-
- current = false;
- if (!is_inside_tree())
- return;
-
- if (get_viewport()->get_listener() == this) {
- get_viewport()->_listener_set(NULL);
- get_viewport()->_listener_make_next_current(this);
- }
-}
-
-bool Listener::is_current() const {
-
- if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
-
- return get_viewport()->get_listener() == this;
- } else
- return current;
-
- return false;
-}
-
-bool Listener::_can_gizmo_scale() const {
-
- return false;
-}
-
-RES Listener::_get_gizmo_geometry() const {
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
-
- return mesh;
-}
-
-void Listener::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("make_current"), &Listener::make_current);
- ClassDB::bind_method(D_METHOD("clear_current"), &Listener::clear_current);
- ClassDB::bind_method(D_METHOD("is_current"), &Listener::is_current);
- ClassDB::bind_method(D_METHOD("get_listener_transform"), &Listener::get_listener_transform);
-}
-
-Listener::Listener() {
-
- current = false;
- force_change = false;
- set_notify_transform(true);
- //active=false;
-}
-
-Listener::~Listener() {
-}
diff --git a/scene/3d/listener.h b/scene/3d/listener.h
deleted file mode 100644
index 287e67f31e..0000000000
--- a/scene/3d/listener.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* listener.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 LISTENER_H
-#define LISTENER_H
-
-#include "scene/3d/spatial.h"
-#include "scene/main/viewport.h"
-
-class Listener : public Spatial {
-
- GDCLASS(Listener, Spatial);
-
-private:
- bool force_change;
- bool current;
-
- RID scenario_id;
-
- virtual bool _can_gizmo_scale() const;
- virtual RES _get_gizmo_geometry() const;
-
- friend class Viewport;
- void _update_audio_listener_state();
-
-protected:
- void _update_listener();
- virtual void _request_listener_update();
-
- 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 _notification(int p_what);
-
- static void _bind_methods();
-
-public:
- void make_current();
- void clear_current();
- bool is_current() const;
-
- virtual Transform get_listener_transform() const;
-
- void set_visible_layers(uint32_t p_layers);
- uint32_t get_visible_layers() const;
-
- Listener();
- ~Listener();
-};
-
-#endif
diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp
new file mode 100644
index 0000000000..426e34ea80
--- /dev/null
+++ b/scene/3d/listener_3d.cpp
@@ -0,0 +1,178 @@
+/*************************************************************************/
+/* listener_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "listener_3d.h"
+
+#include "scene/resources/mesh.h"
+
+void Listener3D::_update_audio_listener_state() {
+}
+
+void Listener3D::_request_listener_update() {
+
+ _update_listener();
+}
+
+bool Listener3D::_set(const StringName &p_name, const Variant &p_value) {
+
+ if (p_name == "current") {
+ if (p_value.operator bool()) {
+ make_current();
+ } else {
+ clear_current();
+ }
+ } else
+ return false;
+
+ return true;
+}
+bool Listener3D::_get(const StringName &p_name, Variant &r_ret) const {
+
+ if (p_name == "current") {
+ if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
+ r_ret = current;
+ } else {
+ r_ret = is_current();
+ }
+ } else
+ return false;
+
+ return true;
+}
+
+void Listener3D::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
+}
+
+void Listener3D::_update_listener() {
+
+ if (is_inside_tree() && is_current()) {
+ get_viewport()->_listener_transform_changed_notify();
+ }
+}
+
+void Listener3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_WORLD: {
+ bool first_listener = get_viewport()->_listener_add(this);
+ if (!get_tree()->is_node_being_edited(this) && (current || first_listener))
+ make_current();
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ _request_listener_update();
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ if (!get_tree()->is_node_being_edited(this)) {
+ if (is_current()) {
+ clear_current();
+ current = true; //keep it true
+
+ } else {
+ current = false;
+ }
+ }
+
+ get_viewport()->_listener_remove(this);
+
+ } break;
+ }
+}
+
+Transform Listener3D::get_listener_transform() const {
+
+ return get_global_transform().orthonormalized();
+}
+
+void Listener3D::make_current() {
+
+ current = true;
+
+ if (!is_inside_tree())
+ return;
+
+ get_viewport()->_listener_set(this);
+}
+
+void Listener3D::clear_current() {
+
+ current = false;
+ if (!is_inside_tree())
+ return;
+
+ if (get_viewport()->get_listener() == this) {
+ get_viewport()->_listener_set(nullptr);
+ get_viewport()->_listener_make_next_current(this);
+ }
+}
+
+bool Listener3D::is_current() const {
+
+ if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
+
+ return get_viewport()->get_listener() == this;
+ } else
+ return current;
+
+ return false;
+}
+
+bool Listener3D::_can_gizmo_scale() const {
+
+ return false;
+}
+
+RES Listener3D::_get_gizmo_geometry() const {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+
+ return mesh;
+}
+
+void Listener3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("make_current"), &Listener3D::make_current);
+ ClassDB::bind_method(D_METHOD("clear_current"), &Listener3D::clear_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &Listener3D::is_current);
+ ClassDB::bind_method(D_METHOD("get_listener_transform"), &Listener3D::get_listener_transform);
+}
+
+Listener3D::Listener3D() {
+
+ current = false;
+ force_change = false;
+ set_notify_transform(true);
+ //active=false;
+}
+
+Listener3D::~Listener3D() {
+}
diff --git a/scene/3d/listener_3d.h b/scene/3d/listener_3d.h
new file mode 100644
index 0000000000..3383d6725e
--- /dev/null
+++ b/scene/3d/listener_3d.h
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* listener_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 LISTENER_3D_H
+#define LISTENER_3D_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/main/window.h"
+
+class Listener3D : public Node3D {
+
+ GDCLASS(Listener3D, Node3D);
+
+private:
+ bool force_change;
+ bool current;
+
+ RID scenario_id;
+
+ virtual bool _can_gizmo_scale() const;
+ virtual RES _get_gizmo_geometry() const;
+
+ friend class Viewport;
+ void _update_audio_listener_state();
+
+protected:
+ void _update_listener();
+ virtual void _request_listener_update();
+
+ 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 _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ void make_current();
+ void clear_current();
+ bool is_current() const;
+
+ virtual Transform get_listener_transform() const;
+
+ void set_visible_layers(uint32_t p_layers);
+ uint32_t get_visible_layers() const;
+
+ Listener3D();
+ ~Listener3D();
+};
+
+#endif
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
deleted file mode 100644
index 4ca139ebbc..0000000000
--- a/scene/3d/mesh_instance.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
-/*************************************************************************/
-/* mesh_instance.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "mesh_instance.h"
-
-#include "collision_shape.h"
-#include "core/core_string_names.h"
-#include "physics_body.h"
-#include "scene/resources/material.h"
-#include "skeleton.h"
-
-bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) {
-
- //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
- //add to it that it's probably found on first call to _set anyway.
-
- if (!get_instance().is_valid())
- return false;
-
- Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.find(p_name);
- if (E) {
- E->get().value = p_value;
- VisualServer::get_singleton()->instance_set_blend_shape_weight(get_instance(), E->get().idx, E->get().value);
- return true;
- }
-
- if (p_name.operator String().begins_with("material/")) {
- int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0)
- return false;
-
- set_surface_material(idx, p_value);
- return true;
- }
-
- return false;
-}
-
-bool MeshInstance::_get(const StringName &p_name, Variant &r_ret) const {
-
- if (!get_instance().is_valid())
- return false;
-
- const Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.find(p_name);
- if (E) {
- r_ret = E->get().value;
- return true;
- }
-
- if (p_name.operator String().begins_with("material/")) {
- int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0)
- return false;
- r_ret = materials[idx];
- return true;
- }
- return false;
-}
-
-void MeshInstance::_get_property_list(List<PropertyInfo> *p_list) const {
-
- List<String> ls;
- for (const Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.front(); E; E = E->next()) {
-
- ls.push_back(E->key());
- }
-
- 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"));
- }
-
- 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));
- }
- }
-}
-
-void MeshInstance::set_mesh(const Ref<Mesh> &p_mesh) {
-
- if (mesh == p_mesh)
- return;
-
- if (mesh.is_valid()) {
- mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance::_mesh_changed));
- materials.clear();
- }
-
- mesh = p_mesh;
-
- blend_shape_tracks.clear();
- if (mesh.is_valid()) {
-
- for (int i = 0; i < mesh->get_blend_shape_count(); i++) {
-
- BlendShapeTrack mt;
- mt.idx = i;
- mt.value = 0;
- blend_shape_tracks["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = mt;
- }
-
- mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance::_mesh_changed));
- materials.resize(mesh->get_surface_count());
-
- set_base(mesh->get_rid());
- } else {
-
- set_base(RID());
- }
-
- update_gizmo();
-
- _change_notify();
-}
-Ref<Mesh> MeshInstance::get_mesh() const {
-
- return mesh;
-}
-
-void MeshInstance::_resolve_skeleton_path() {
-
- Ref<SkinReference> new_skin_reference;
-
- if (!skeleton_path.is_empty()) {
- Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path));
- if (skeleton) {
- new_skin_reference = skeleton->register_skin(skin_internal);
- if (skin_internal.is_null()) {
- //a skin was created for us
- skin_internal = new_skin_reference->get_skin();
- _change_notify();
- }
- }
- }
-
- skin_ref = new_skin_reference;
-
- if (skin_ref.is_valid()) {
- VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skin_ref->get_skeleton());
- } else {
- VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), RID());
- }
-}
-
-void MeshInstance::set_skin(const Ref<Skin> &p_skin) {
- skin_internal = p_skin;
- skin = p_skin;
- if (!is_inside_tree())
- return;
- _resolve_skeleton_path();
-}
-
-Ref<Skin> MeshInstance::get_skin() const {
- return skin;
-}
-
-void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) {
-
- skeleton_path = p_skeleton;
- if (!is_inside_tree())
- return;
- _resolve_skeleton_path();
-}
-
-NodePath MeshInstance::get_skeleton_path() {
- return skeleton_path;
-}
-
-AABB MeshInstance::get_aabb() const {
-
- if (!mesh.is_null())
- return mesh->get_aabb();
-
- return AABB();
-}
-
-Vector<Face3> MeshInstance::get_faces(uint32_t p_usage_flags) const {
-
- if (!(p_usage_flags & (FACES_SOLID | FACES_ENCLOSING)))
- return Vector<Face3>();
-
- if (mesh.is_null())
- return Vector<Face3>();
-
- return mesh->get_faces();
-}
-
-Node *MeshInstance::create_trimesh_collision_node() {
-
- if (mesh.is_null())
- return NULL;
-
- Ref<Shape> shape = mesh->create_trimesh_shape();
- if (shape.is_null())
- return NULL;
-
- StaticBody *static_body = memnew(StaticBody);
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shape);
- static_body->add_child(cshape);
- return static_body;
-}
-
-void MeshInstance::create_trimesh_collision() {
-
- StaticBody *static_body = Object::cast_to<StaticBody>(create_trimesh_collision_node());
- ERR_FAIL_COND(!static_body);
- static_body->set_name(String(get_name()) + "_col");
-
- add_child(static_body);
- if (get_owner()) {
- CollisionShape *cshape = Object::cast_to<CollisionShape>(static_body->get_child(0));
- static_body->set_owner(get_owner());
- cshape->set_owner(get_owner());
- }
-}
-
-Node *MeshInstance::create_convex_collision_node() {
-
- if (mesh.is_null())
- return NULL;
-
- Ref<Shape> shape = mesh->create_convex_shape();
- if (shape.is_null())
- return NULL;
-
- StaticBody *static_body = memnew(StaticBody);
- CollisionShape *cshape = memnew(CollisionShape);
- cshape->set_shape(shape);
- static_body->add_child(cshape);
- return static_body;
-}
-
-void MeshInstance::create_convex_collision() {
-
- StaticBody *static_body = Object::cast_to<StaticBody>(create_convex_collision_node());
- ERR_FAIL_COND(!static_body);
- static_body->set_name(String(get_name()) + "_col");
-
- add_child(static_body);
- if (get_owner()) {
- CollisionShape *cshape = Object::cast_to<CollisionShape>(static_body->get_child(0));
- static_body->set_owner(get_owner());
- cshape->set_owner(get_owner());
- }
-}
-
-void MeshInstance::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
- _resolve_skeleton_path();
- }
-}
-
-int MeshInstance::get_surface_material_count() const {
-
- return materials.size();
-}
-
-void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_material) {
-
- ERR_FAIL_INDEX(p_surface, materials.size());
-
- materials.write[p_surface] = p_material;
-
- if (materials[p_surface].is_valid())
- VS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid());
- else
- VS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, RID());
-}
-
-Ref<Material> MeshInstance::get_surface_material(int p_surface) const {
-
- ERR_FAIL_INDEX_V(p_surface, materials.size(), Ref<Material>());
-
- return materials[p_surface];
-}
-
-void MeshInstance::_mesh_changed() {
-
- materials.resize(mesh->get_surface_count());
-}
-
-void MeshInstance::create_debug_tangents() {
-
- Vector<Vector3> lines;
- Vector<Color> colors;
-
- Ref<Mesh> mesh = get_mesh();
- if (!mesh.is_valid())
- return;
-
- for (int i = 0; i < mesh->get_surface_count(); i++) {
- Array arrays = mesh->surface_get_arrays(i);
- Vector<Vector3> verts = arrays[Mesh::ARRAY_VERTEX];
- Vector<Vector3> norms = arrays[Mesh::ARRAY_NORMAL];
- if (norms.size() == 0)
- continue;
- Vector<float> tangents = arrays[Mesh::ARRAY_TANGENT];
- if (tangents.size() == 0)
- continue;
-
- for (int j = 0; j < verts.size(); j++) {
- Vector3 v = verts[j];
- Vector3 n = norms[j];
- Vector3 t = Vector3(tangents[j * 4 + 0], tangents[j * 4 + 1], tangents[j * 4 + 2]);
- Vector3 b = (n.cross(t)).normalized() * tangents[j * 4 + 3];
-
- lines.push_back(v); //normal
- colors.push_back(Color(0, 0, 1)); //color
- lines.push_back(v + n * 0.04); //normal
- colors.push_back(Color(0, 0, 1)); //color
-
- lines.push_back(v); //tangent
- colors.push_back(Color(1, 0, 0)); //color
- lines.push_back(v + t * 0.04); //tangent
- colors.push_back(Color(1, 0, 0)); //color
-
- lines.push_back(v); //binormal
- colors.push_back(Color(0, 1, 0)); //color
- lines.push_back(v + b * 0.04); //binormal
- colors.push_back(Color(0, 1, 0)); //color
- }
- }
-
- if (lines.size()) {
-
- Ref<StandardMaterial3D> sm;
- sm.instance();
-
- sm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- sm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- sm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-
- Ref<ArrayMesh> am;
- am.instance();
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX] = lines;
- a[Mesh::ARRAY_COLOR] = colors;
-
- am->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
- am->surface_set_material(0, sm);
-
- MeshInstance *mi = memnew(MeshInstance);
- mi->set_mesh(am);
- mi->set_name("DebugTangents");
- add_child(mi);
-#ifdef TOOLS_ENABLED
-
- if (this == get_tree()->get_edited_scene_root())
- mi->set_owner(this);
- else
- mi->set_owner(get_owner());
-#endif
- }
-}
-
-void MeshInstance::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshInstance::set_mesh);
- ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance::get_mesh);
- ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path);
- ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path);
- ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance::set_skin);
- ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance::get_skin);
-
- ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count);
- ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material);
- ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance::get_surface_material);
-
- ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance::create_trimesh_collision);
- ClassDB::set_method_flags("MeshInstance", "create_trimesh_collision", METHOD_FLAGS_DEFAULT);
- ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance::create_convex_collision);
- ClassDB::set_method_flags("MeshInstance", "create_convex_collision", METHOD_FLAGS_DEFAULT);
-
- ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance::create_debug_tangents);
- ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_GROUP("Skeleton", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
- ADD_GROUP("", "");
-}
-
-MeshInstance::MeshInstance() {
- skeleton_path = NodePath("..");
-}
-
-MeshInstance::~MeshInstance() {
-}
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
deleted file mode 100644
index d49d9ed98f..0000000000
--- a/scene/3d/mesh_instance.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*************************************************************************/
-/* mesh_instance.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 MESH_INSTANCE_H
-#define MESH_INSTANCE_H
-
-#include "scene/3d/skeleton.h"
-#include "scene/3d/visual_instance.h"
-#include "scene/resources/mesh.h"
-#include "scene/resources/skin.h"
-
-class MeshInstance : public GeometryInstance {
-
- GDCLASS(MeshInstance, GeometryInstance);
-
-protected:
- Ref<Mesh> mesh;
- Ref<Skin> skin;
- Ref<Skin> skin_internal;
- Ref<SkinReference> skin_ref;
- NodePath skeleton_path;
-
- struct BlendShapeTrack {
-
- int idx;
- float value;
- BlendShapeTrack() {
- idx = 0;
- value = 0;
- }
- };
-
- Map<StringName, BlendShapeTrack> blend_shape_tracks;
- Vector<Ref<Material> > materials;
-
- void _mesh_changed();
- void _resolve_skeleton_path();
-
-protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_mesh(const Ref<Mesh> &p_mesh);
- Ref<Mesh> get_mesh() const;
-
- void set_skin(const Ref<Skin> &p_skin);
- Ref<Skin> get_skin() const;
-
- 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;
-
- Node *create_trimesh_collision_node();
- void create_trimesh_collision();
-
- Node *create_convex_collision_node();
- void create_convex_collision();
-
- void create_debug_tangents();
-
- virtual AABB get_aabb() const;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
-
- MeshInstance();
- ~MeshInstance();
-};
-
-#endif
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
new file mode 100644
index 0000000000..d56a095a5b
--- /dev/null
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -0,0 +1,439 @@
+/*************************************************************************/
+/* mesh_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "mesh_instance_3d.h"
+
+#include "collision_shape_3d.h"
+#include "core/core_string_names.h"
+#include "physics_body_3d.h"
+#include "scene/resources/material.h"
+#include "skeleton_3d.h"
+
+bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
+
+ //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
+ //add to it that it's probably found on first call to _set anyway.
+
+ if (!get_instance().is_valid())
+ return false;
+
+ Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.find(p_name);
+ if (E) {
+ E->get().value = p_value;
+ RenderingServer::get_singleton()->instance_set_blend_shape_weight(get_instance(), E->get().idx, E->get().value);
+ return true;
+ }
+
+ if (p_name.operator String().begins_with("material/")) {
+ int idx = p_name.operator String().get_slicec('/', 1).to_int();
+ if (idx >= materials.size() || idx < 0)
+ return false;
+
+ set_surface_material(idx, p_value);
+ return true;
+ }
+
+ return false;
+}
+
+bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
+
+ if (!get_instance().is_valid())
+ return false;
+
+ const Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.find(p_name);
+ if (E) {
+ r_ret = E->get().value;
+ return true;
+ }
+
+ if (p_name.operator String().begins_with("material/")) {
+ int idx = p_name.operator String().get_slicec('/', 1).to_int();
+ if (idx >= materials.size() || idx < 0)
+ return false;
+ r_ret = materials[idx];
+ return true;
+ }
+ return false;
+}
+
+void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ List<String> ls;
+ for (const Map<StringName, BlendShapeTrack>::Element *E = blend_shape_tracks.front(); E; E = E->next()) {
+
+ ls.push_back(E->key());
+ }
+
+ 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"));
+ }
+
+ 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));
+ }
+ }
+}
+
+void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
+
+ if (mesh == p_mesh)
+ return;
+
+ if (mesh.is_valid()) {
+ mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
+ materials.clear();
+ }
+
+ mesh = p_mesh;
+
+ blend_shape_tracks.clear();
+ if (mesh.is_valid()) {
+
+ for (int i = 0; i < mesh->get_blend_shape_count(); i++) {
+
+ BlendShapeTrack mt;
+ mt.idx = i;
+ mt.value = 0;
+ blend_shape_tracks["blend_shapes/" + String(mesh->get_blend_shape_name(i))] = mt;
+ }
+
+ mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
+ materials.resize(mesh->get_surface_count());
+
+ set_base(mesh->get_rid());
+ } else {
+
+ set_base(RID());
+ }
+
+ update_gizmo();
+
+ _change_notify();
+}
+Ref<Mesh> MeshInstance3D::get_mesh() const {
+
+ return mesh;
+}
+
+void MeshInstance3D::_resolve_skeleton_path() {
+
+ Ref<SkinReference> new_skin_reference;
+
+ if (!skeleton_path.is_empty()) {
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(get_node(skeleton_path));
+ if (skeleton) {
+ new_skin_reference = skeleton->register_skin(skin_internal);
+ if (skin_internal.is_null()) {
+ //a skin was created for us
+ skin_internal = new_skin_reference->get_skin();
+ _change_notify();
+ }
+ }
+ }
+
+ skin_ref = new_skin_reference;
+
+ if (skin_ref.is_valid()) {
+ RenderingServer::get_singleton()->instance_attach_skeleton(get_instance(), skin_ref->get_skeleton());
+ } else {
+ RenderingServer::get_singleton()->instance_attach_skeleton(get_instance(), RID());
+ }
+}
+
+void MeshInstance3D::set_skin(const Ref<Skin> &p_skin) {
+ skin_internal = p_skin;
+ skin = p_skin;
+ if (!is_inside_tree())
+ return;
+ _resolve_skeleton_path();
+}
+
+Ref<Skin> MeshInstance3D::get_skin() const {
+ return skin;
+}
+
+void MeshInstance3D::set_skeleton_path(const NodePath &p_skeleton) {
+
+ skeleton_path = p_skeleton;
+ if (!is_inside_tree())
+ return;
+ _resolve_skeleton_path();
+}
+
+NodePath MeshInstance3D::get_skeleton_path() {
+ return skeleton_path;
+}
+
+AABB MeshInstance3D::get_aabb() const {
+
+ if (!mesh.is_null())
+ return mesh->get_aabb();
+
+ return AABB();
+}
+
+Vector<Face3> MeshInstance3D::get_faces(uint32_t p_usage_flags) const {
+
+ if (!(p_usage_flags & (FACES_SOLID | FACES_ENCLOSING)))
+ return Vector<Face3>();
+
+ if (mesh.is_null())
+ return Vector<Face3>();
+
+ return mesh->get_faces();
+}
+
+Node *MeshInstance3D::create_trimesh_collision_node() {
+
+ if (mesh.is_null())
+ return nullptr;
+
+ Ref<Shape3D> shape = mesh->create_trimesh_shape();
+ if (shape.is_null())
+ return nullptr;
+
+ StaticBody3D *static_body = memnew(StaticBody3D);
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shape);
+ static_body->add_child(cshape);
+ return static_body;
+}
+
+void MeshInstance3D::create_trimesh_collision() {
+
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_trimesh_collision_node());
+ ERR_FAIL_COND(!static_body);
+ static_body->set_name(String(get_name()) + "_col");
+
+ add_child(static_body);
+ if (get_owner()) {
+ CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(0));
+ static_body->set_owner(get_owner());
+ cshape->set_owner(get_owner());
+ }
+}
+
+Node *MeshInstance3D::create_convex_collision_node() {
+
+ if (mesh.is_null())
+ return nullptr;
+
+ Ref<Shape3D> shape = mesh->create_convex_shape();
+ if (shape.is_null())
+ return nullptr;
+
+ StaticBody3D *static_body = memnew(StaticBody3D);
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(shape);
+ static_body->add_child(cshape);
+ return static_body;
+}
+
+void MeshInstance3D::create_convex_collision() {
+
+ StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_convex_collision_node());
+ ERR_FAIL_COND(!static_body);
+ static_body->set_name(String(get_name()) + "_col");
+
+ add_child(static_body);
+ if (get_owner()) {
+ CollisionShape3D *cshape = Object::cast_to<CollisionShape3D>(static_body->get_child(0));
+ static_body->set_owner(get_owner());
+ 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();
+}
+
+void MeshInstance3D::set_surface_material(int p_surface, const Ref<Material> &p_material) {
+
+ ERR_FAIL_INDEX(p_surface, materials.size());
+
+ 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());
+ else
+ RS::get_singleton()->instance_set_surface_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>());
+
+ return materials[p_surface];
+}
+
+Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
+
+ if (get_material_override() != Ref<Material>()) {
+ return get_material_override();
+ } else if (p_surface < materials.size()) {
+ return materials[p_surface];
+ } else {
+ Ref<Mesh> mesh = get_mesh();
+
+ if (mesh.is_null() || p_surface >= mesh->get_surface_count()) {
+ return Ref<Material>();
+ }
+
+ return mesh->surface_get_material(p_surface);
+ }
+}
+
+void MeshInstance3D::_mesh_changed() {
+
+ materials.resize(mesh->get_surface_count());
+}
+
+void MeshInstance3D::create_debug_tangents() {
+
+ Vector<Vector3> lines;
+ Vector<Color> colors;
+
+ Ref<Mesh> mesh = get_mesh();
+ if (!mesh.is_valid())
+ return;
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ Array arrays = mesh->surface_get_arrays(i);
+ Vector<Vector3> verts = arrays[Mesh::ARRAY_VERTEX];
+ Vector<Vector3> norms = arrays[Mesh::ARRAY_NORMAL];
+ if (norms.size() == 0)
+ continue;
+ Vector<float> tangents = arrays[Mesh::ARRAY_TANGENT];
+ if (tangents.size() == 0)
+ continue;
+
+ for (int j = 0; j < verts.size(); j++) {
+ Vector3 v = verts[j];
+ Vector3 n = norms[j];
+ Vector3 t = Vector3(tangents[j * 4 + 0], tangents[j * 4 + 1], tangents[j * 4 + 2]);
+ Vector3 b = (n.cross(t)).normalized() * tangents[j * 4 + 3];
+
+ lines.push_back(v); //normal
+ colors.push_back(Color(0, 0, 1)); //color
+ lines.push_back(v + n * 0.04); //normal
+ colors.push_back(Color(0, 0, 1)); //color
+
+ lines.push_back(v); //tangent
+ colors.push_back(Color(1, 0, 0)); //color
+ lines.push_back(v + t * 0.04); //tangent
+ colors.push_back(Color(1, 0, 0)); //color
+
+ lines.push_back(v); //binormal
+ colors.push_back(Color(0, 1, 0)); //color
+ lines.push_back(v + b * 0.04); //binormal
+ colors.push_back(Color(0, 1, 0)); //color
+ }
+ }
+
+ if (lines.size()) {
+
+ Ref<StandardMaterial3D> sm;
+ sm.instance();
+
+ sm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ sm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ sm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+
+ Ref<ArrayMesh> am;
+ am.instance();
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX] = lines;
+ a[Mesh::ARRAY_COLOR] = colors;
+
+ am->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
+ am->surface_set_material(0, sm);
+
+ MeshInstance3D *mi = memnew(MeshInstance3D);
+ mi->set_mesh(am);
+ mi->set_name("DebugTangents");
+ add_child(mi);
+#ifdef TOOLS_ENABLED
+
+ if (this == get_tree()->get_edited_scene_root())
+ mi->set_owner(this);
+ else
+ mi->set_owner(get_owner());
+#endif
+ }
+}
+
+void MeshInstance3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshInstance3D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance3D::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance3D::set_skeleton_path);
+ ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance3D::get_skeleton_path);
+ 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_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_debug_tangents"), &MeshInstance3D::create_debug_tangents);
+ ClassDB::set_method_flags("MeshInstance3D", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+ ADD_GROUP("Skeleton", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_skeleton_path", "get_skeleton_path");
+ ADD_GROUP("", "");
+}
+
+MeshInstance3D::MeshInstance3D() {
+ skeleton_path = NodePath("..");
+}
+
+MeshInstance3D::~MeshInstance3D() {
+}
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
new file mode 100644
index 0000000000..914148f427
--- /dev/null
+++ b/scene/3d/mesh_instance_3d.h
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* mesh_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 MESH_INSTANCE_H
+#define MESH_INSTANCE_H
+
+#include "scene/3d/skeleton_3d.h"
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/mesh.h"
+#include "scene/resources/skin.h"
+
+class MeshInstance3D : public GeometryInstance3D {
+
+ GDCLASS(MeshInstance3D, GeometryInstance3D);
+
+protected:
+ Ref<Mesh> mesh;
+ Ref<Skin> skin;
+ Ref<Skin> skin_internal;
+ Ref<SkinReference> skin_ref;
+ NodePath skeleton_path;
+
+ struct BlendShapeTrack {
+
+ int idx;
+ float value;
+ BlendShapeTrack() {
+ idx = 0;
+ value = 0;
+ }
+ };
+
+ Map<StringName, BlendShapeTrack> blend_shape_tracks;
+ Vector<Ref<Material>> materials;
+
+ void _mesh_changed();
+ void _resolve_skeleton_path();
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
+ 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;
+ Ref<Material> get_active_material(int p_surface) const;
+
+ Node *create_trimesh_collision_node();
+ void create_trimesh_collision();
+
+ Node *create_convex_collision_node();
+ void create_convex_collision();
+
+ void create_debug_tangents();
+
+ virtual AABB get_aabb() const;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ MeshInstance3D();
+ ~MeshInstance3D();
+};
+
+#endif
diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp
deleted file mode 100644
index 075eb0a1ec..0000000000
--- a/scene/3d/multimesh_instance.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* multimesh_instance.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "multimesh_instance.h"
-
-void MultiMeshInstance::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance::set_multimesh);
- ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance::get_multimesh);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh");
-}
-
-void MultiMeshInstance::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
-
- multimesh = p_multimesh;
- if (multimesh.is_valid())
- set_base(multimesh->get_rid());
- else
- set_base(RID());
-}
-
-Ref<MultiMesh> MultiMeshInstance::get_multimesh() const {
-
- return multimesh;
-}
-
-Vector<Face3> MultiMeshInstance::get_faces(uint32_t p_usage_flags) const {
-
- return Vector<Face3>();
-}
-
-AABB MultiMeshInstance::get_aabb() const {
-
- if (multimesh.is_null())
- return AABB();
- else
- return multimesh->get_aabb();
-}
-
-MultiMeshInstance::MultiMeshInstance() {
-}
-
-MultiMeshInstance::~MultiMeshInstance() {
-}
diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h
deleted file mode 100644
index 2b59c3b96c..0000000000
--- a/scene/3d/multimesh_instance.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*************************************************************************/
-/* multimesh_instance.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 MULTIMESH_INSTANCE_H
-#define MULTIMESH_INSTANCE_H
-
-#include "scene/3d/visual_instance.h"
-#include "scene/resources/multimesh.h"
-
-class MultiMeshInstance : public GeometryInstance {
- GDCLASS(MultiMeshInstance, GeometryInstance);
-
- Ref<MultiMesh> multimesh;
-
-protected:
- static void _bind_methods();
- // bind helpers
-
-public:
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
-
- void set_multimesh(const Ref<MultiMesh> &p_multimesh);
- Ref<MultiMesh> get_multimesh() const;
-
- virtual AABB get_aabb() const;
-
- MultiMeshInstance();
- ~MultiMeshInstance();
-};
-
-#endif // MULTIMESH_INSTANCE_H
diff --git a/scene/3d/multimesh_instance_3d.cpp b/scene/3d/multimesh_instance_3d.cpp
new file mode 100644
index 0000000000..a625a34283
--- /dev/null
+++ b/scene/3d/multimesh_instance_3d.cpp
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* multimesh_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "multimesh_instance_3d.h"
+
+void MultiMeshInstance3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance3D::set_multimesh);
+ ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance3D::get_multimesh);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh");
+}
+
+void MultiMeshInstance3D::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
+
+ multimesh = p_multimesh;
+ if (multimesh.is_valid())
+ set_base(multimesh->get_rid());
+ else
+ set_base(RID());
+}
+
+Ref<MultiMesh> MultiMeshInstance3D::get_multimesh() const {
+
+ return multimesh;
+}
+
+Vector<Face3> MultiMeshInstance3D::get_faces(uint32_t p_usage_flags) const {
+
+ return Vector<Face3>();
+}
+
+AABB MultiMeshInstance3D::get_aabb() const {
+
+ if (multimesh.is_null())
+ return AABB();
+ else
+ return multimesh->get_aabb();
+}
+
+MultiMeshInstance3D::MultiMeshInstance3D() {
+}
+
+MultiMeshInstance3D::~MultiMeshInstance3D() {
+}
diff --git a/scene/3d/multimesh_instance_3d.h b/scene/3d/multimesh_instance_3d.h
new file mode 100644
index 0000000000..87ec9e120e
--- /dev/null
+++ b/scene/3d/multimesh_instance_3d.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* multimesh_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 MULTIMESH_INSTANCE_3D_H
+#define MULTIMESH_INSTANCE_3D_H
+
+#include "scene/3d/visual_instance_3d.h"
+#include "scene/resources/multimesh.h"
+
+class MultiMeshInstance3D : public GeometryInstance3D {
+ GDCLASS(MultiMeshInstance3D, GeometryInstance3D);
+
+ Ref<MultiMesh> multimesh;
+
+protected:
+ static void _bind_methods();
+ // bind helpers
+
+public:
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ void set_multimesh(const Ref<MultiMesh> &p_multimesh);
+ Ref<MultiMesh> get_multimesh() const;
+
+ virtual AABB get_aabb() const;
+
+ MultiMeshInstance3D();
+ ~MultiMeshInstance3D();
+};
+
+#endif // MULTIMESH_INSTANCE_H
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
deleted file mode 100644
index 8c543bc97f..0000000000
--- a/scene/3d/navigation.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*************************************************************************/
-/* navigation.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.h"
-
-#include "servers/navigation_server.h"
-
-Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize) const {
-
- return NavigationServer::get_singleton()->map_get_path(map, p_start, p_end, p_optimize);
-}
-
-Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const {
- return NavigationServer::get_singleton()->map_get_closest_point_to_segment(map, p_from, p_to, p_use_collision);
-}
-
-Vector3 Navigation::get_closest_point(const Vector3 &p_point) const {
- return NavigationServer::get_singleton()->map_get_closest_point(map, p_point);
-}
-
-Vector3 Navigation::get_closest_point_normal(const Vector3 &p_point) const {
- return NavigationServer::get_singleton()->map_get_closest_point_normal(map, p_point);
-}
-
-RID Navigation::get_closest_point_owner(const Vector3 &p_point) const {
- return NavigationServer::get_singleton()->map_get_closest_point_owner(map, p_point);
-}
-
-void Navigation::set_up_vector(const Vector3 &p_up) {
-
- up = p_up;
- NavigationServer::get_singleton()->map_set_up(map, up);
-}
-
-Vector3 Navigation::get_up_vector() const {
-
- return up;
-}
-
-void Navigation::set_cell_size(float p_cell_size) {
- cell_size = p_cell_size;
- NavigationServer::get_singleton()->map_set_cell_size(map, cell_size);
-}
-
-void Navigation::set_edge_connection_margin(float p_edge_connection_margin) {
- edge_connection_margin = p_edge_connection_margin;
- NavigationServer::get_singleton()->map_set_edge_connection_margin(map, edge_connection_margin);
-}
-
-void Navigation::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_rid"), &Navigation::get_rid);
-
- ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation::get_simple_path, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "start", "end", "use_collision"), &Navigation::get_closest_point_to_segment, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation::get_closest_point);
- ClassDB::bind_method(D_METHOD("get_closest_point_normal", "to_point"), &Navigation::get_closest_point_normal);
- ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation::get_closest_point_owner);
-
- ClassDB::bind_method(D_METHOD("set_up_vector", "up"), &Navigation::set_up_vector);
- ClassDB::bind_method(D_METHOD("get_up_vector"), &Navigation::get_up_vector);
-
- ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &Navigation::set_cell_size);
- ClassDB::bind_method(D_METHOD("get_cell_size"), &Navigation::get_cell_size);
-
- ClassDB::bind_method(D_METHOD("set_edge_connection_margin", "margin"), &Navigation::set_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("get_edge_connection_margin"), &Navigation::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 Navigation::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
- NavigationServer::get_singleton()->map_set_active(map, true);
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- NavigationServer::get_singleton()->map_set_active(map, false);
- } break;
- }
-}
-
-Navigation::Navigation() {
-
- map = NavigationServer::get_singleton()->map_create();
-
- set_cell_size(0.3);
- set_edge_connection_margin(5.0); // Five meters, depends alot on the agents radius
-
- up = Vector3(0, 1, 0);
-}
-
-Navigation::~Navigation() {
- NavigationServer::get_singleton()->free(map);
-}
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
deleted file mode 100644
index 08f306611f..0000000000
--- a/scene/3d/navigation.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*************************************************************************/
-/* navigation.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 NAVIGATION_H
-#define NAVIGATION_H
-
-#include "scene/3d/navigation_region.h"
-#include "scene/3d/spatial.h"
-
-class Navigation : public Spatial {
-
- GDCLASS(Navigation, Spatial);
-
- RID map;
-
- Vector3 up;
- real_t cell_size;
- real_t edge_connection_margin;
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
- RID get_rid() const {
- return map;
- }
-
- void set_up_vector(const Vector3 &p_up);
- Vector3 get_up_vector() const;
-
- void set_cell_size(float p_cell_size);
- float get_cell_size() const {
- return cell_size;
- }
-
- void set_edge_connection_margin(float p_edge_connection_margin);
- float get_edge_connection_margin() const {
- return edge_connection_margin;
- }
-
- 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;
-
- Navigation();
- ~Navigation();
-};
-
-#endif // NAVIGATION_H
diff --git a/scene/3d/navigation_3d.cpp b/scene/3d/navigation_3d.cpp
new file mode 100644
index 0000000000..f880f65d37
--- /dev/null
+++ b/scene/3d/navigation_3d.cpp
@@ -0,0 +1,125 @@
+/*************************************************************************/
+/* navigation_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 alot on the agents radius
+
+ up = Vector3(0, 1, 0);
+}
+
+Navigation3D::~Navigation3D() {
+ NavigationServer3D::get_singleton()->free(map);
+}
diff --git a/scene/3d/navigation_3d.h b/scene/3d/navigation_3d.h
new file mode 100644
index 0000000000..daa9558125
--- /dev/null
+++ b/scene/3d/navigation_3d.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* navigation_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 NAVIGATION_3D_H
+#define NAVIGATION_3D_H
+
+#include "scene/3d/navigation_region_3d.h"
+#include "scene/3d/node_3d.h"
+
+class Navigation3D : public Node3D {
+
+ GDCLASS(Navigation3D, Node3D);
+
+ RID map;
+
+ Vector3 up;
+ real_t cell_size;
+ real_t edge_connection_margin;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ RID get_rid() const {
+ return map;
+ }
+
+ void set_up_vector(const Vector3 &p_up);
+ Vector3 get_up_vector() const;
+
+ void set_cell_size(float p_cell_size);
+ float get_cell_size() const {
+ return cell_size;
+ }
+
+ void set_edge_connection_margin(float p_edge_connection_margin);
+ float get_edge_connection_margin() const {
+ return edge_connection_margin;
+ }
+
+ 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;
+
+ Navigation3D();
+ ~Navigation3D();
+};
+
+#endif // NAVIGATION_H
diff --git a/scene/3d/navigation_agent.cpp b/scene/3d/navigation_agent.cpp
deleted file mode 100644
index 728fc947e9..0000000000
--- a/scene/3d/navigation_agent.cpp
+++ /dev/null
@@ -1,361 +0,0 @@
-/*************************************************************************/
-/* navigation_agent.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_agent.h"
-
-#include "core/engine.h"
-#include "scene/3d/navigation.h"
-#include "servers/navigation_server.h"
-
-void NavigationAgent::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent::set_target_desired_distance);
- ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent::get_target_desired_distance);
-
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent::get_radius);
-
- ClassDB::bind_method(D_METHOD("set_agent_height_offset", "agent_height_offset"), &NavigationAgent::set_agent_height_offset);
- ClassDB::bind_method(D_METHOD("get_agent_height_offset"), &NavigationAgent::get_agent_height_offset);
-
- ClassDB::bind_method(D_METHOD("set_ignore_y", "ignore"), &NavigationAgent::set_ignore_y);
- ClassDB::bind_method(D_METHOD("get_ignore_y"), &NavigationAgent::get_ignore_y);
-
- ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent::set_navigation_node);
- ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent::get_navigation_node);
-
- ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent::set_neighbor_dist);
- ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent::get_neighbor_dist);
-
- ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent::set_max_neighbors);
- ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent::get_max_neighbors);
-
- ClassDB::bind_method(D_METHOD("set_time_horizon", "time_horizon"), &NavigationAgent::set_time_horizon);
- ClassDB::bind_method(D_METHOD("get_time_horizon"), &NavigationAgent::get_time_horizon);
-
- ClassDB::bind_method(D_METHOD("set_max_speed", "max_speed"), &NavigationAgent::set_max_speed);
- ClassDB::bind_method(D_METHOD("get_max_speed"), &NavigationAgent::get_max_speed);
-
- ClassDB::bind_method(D_METHOD("set_path_max_distance", "max_speed"), &NavigationAgent::set_path_max_distance);
- ClassDB::bind_method(D_METHOD("get_path_max_distance"), &NavigationAgent::get_path_max_distance);
-
- ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent::set_target_location);
- ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent::get_target_location);
- ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent::get_next_location);
- ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent::distance_to_target);
- ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent::set_velocity);
- ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent::get_nav_path);
- ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent::get_nav_path_index);
- ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent::is_target_reached);
- ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent::is_target_reachable);
- ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent::is_navigation_finished);
- ClassDB::bind_method(D_METHOD("get_final_location"), &NavigationAgent::get_final_location);
-
- ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent::_avoidance_done);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_target_desired_distance", "get_target_desired_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01"), "set_agent_height_offset", "get_agent_height_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_neighbor_dist", "get_neighbor_dist");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_time_horizon", "get_time_horizon");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_max_speed", "get_max_speed");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1"), "set_path_max_distance", "get_path_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y");
-
- ADD_SIGNAL(MethodInfo("path_changed"));
- ADD_SIGNAL(MethodInfo("target_reached"));
- ADD_SIGNAL(MethodInfo("navigation_finished"));
- ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
-}
-
-void NavigationAgent::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
-
- agent_parent = Object::cast_to<Spatial>(get_parent());
-
- NavigationServer::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
-
- // Search the navigation node and set it
- {
- Navigation *nav = NULL;
- Node *p = get_parent();
- while (p != NULL) {
- nav = Object::cast_to<Navigation>(p);
- if (nav != NULL)
- p = NULL;
- else
- p = p->get_parent();
- }
-
- set_navigation(nav);
- }
-
- set_physics_process_internal(true);
- } break;
- case NOTIFICATION_EXIT_TREE: {
- agent_parent = NULL;
- set_navigation(NULL);
- set_physics_process_internal(false);
- } break;
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (agent_parent) {
-
- NavigationServer::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;
- }
- }
- }
- } break;
- }
-}
-
-NavigationAgent::NavigationAgent() :
- agent_parent(NULL),
- navigation(NULL),
- agent(RID()),
- target_desired_distance(1.0),
- navigation_height_offset(0.0),
- path_max_distance(3.0),
- velocity_submitted(false),
- target_reached(false),
- navigation_finished(true) {
- agent = NavigationServer::get_singleton()->agent_create();
- set_neighbor_dist(50.0);
- set_max_neighbors(10);
- set_time_horizon(5.0);
- set_radius(1.0);
- set_max_speed(10.0);
- set_ignore_y(true);
-}
-
-NavigationAgent::~NavigationAgent() {
- NavigationServer::get_singleton()->free(agent);
- agent = RID(); // Pointless
-}
-
-void NavigationAgent::set_navigation(Navigation *p_nav) {
- if (navigation == p_nav)
- return; // Pointless
-
- navigation = p_nav;
- NavigationServer::get_singleton()->agent_set_map(agent, navigation == NULL ? RID() : navigation->get_rid());
-}
-
-void NavigationAgent::set_navigation_node(Node *p_nav) {
- Navigation *nav = Object::cast_to<Navigation>(p_nav);
- ERR_FAIL_COND(nav == NULL);
- set_navigation(nav);
-}
-
-Node *NavigationAgent::get_navigation_node() const {
- return Object::cast_to<Node>(navigation);
-}
-
-void NavigationAgent::set_target_desired_distance(real_t p_dd) {
- target_desired_distance = p_dd;
-}
-
-void NavigationAgent::set_radius(real_t p_radius) {
- radius = p_radius;
- NavigationServer::get_singleton()->agent_set_radius(agent, radius);
-}
-
-void NavigationAgent::set_agent_height_offset(real_t p_hh) {
- navigation_height_offset = p_hh;
-}
-
-void NavigationAgent::set_ignore_y(bool p_ignore_y) {
- ignore_y = p_ignore_y;
- NavigationServer::get_singleton()->agent_set_ignore_y(agent, ignore_y);
-}
-
-void NavigationAgent::set_neighbor_dist(real_t p_dist) {
- neighbor_dist = p_dist;
- NavigationServer::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist);
-}
-
-void NavigationAgent::set_max_neighbors(int p_count) {
- max_neighbors = p_count;
- NavigationServer::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
-}
-
-void NavigationAgent::set_time_horizon(real_t p_time) {
- time_horizon = p_time;
- NavigationServer::get_singleton()->agent_set_time_horizon(agent, time_horizon);
-}
-
-void NavigationAgent::set_max_speed(real_t p_max_speed) {
- max_speed = p_max_speed;
- NavigationServer::get_singleton()->agent_set_max_speed(agent, max_speed);
-}
-
-void NavigationAgent::set_path_max_distance(real_t p_pmd) {
- path_max_distance = p_pmd;
-}
-
-real_t NavigationAgent::get_path_max_distance() {
- return path_max_distance;
-}
-
-void NavigationAgent::set_target_location(Vector3 p_location) {
- target_location = p_location;
- navigation_path.clear();
- target_reached = false;
- navigation_finished = false;
-}
-
-Vector3 NavigationAgent::get_target_location() const {
- return target_location;
-}
-
-Vector3 NavigationAgent::get_next_location() {
- update_navigation();
- if (navigation_path.size() == 0) {
- ERR_FAIL_COND_V(agent_parent == NULL, Vector3());
- return agent_parent->get_global_transform().origin;
- } else {
- return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0);
- }
-}
-
-real_t NavigationAgent::distance_to_target() const {
- ERR_FAIL_COND_V(agent_parent == NULL, 0.0);
- return agent_parent->get_global_transform().origin.distance_to(target_location);
-}
-
-bool NavigationAgent::is_target_reached() const {
- return target_reached;
-}
-
-bool NavigationAgent::is_target_reachable() {
- return target_desired_distance >= get_final_location().distance_to(target_location);
-}
-
-bool NavigationAgent::is_navigation_finished() {
- update_navigation();
- return navigation_finished;
-}
-
-Vector3 NavigationAgent::get_final_location() {
- update_navigation();
- if (navigation_path.size() == 0) {
- return Vector3();
- }
- return navigation_path[navigation_path.size() - 1];
-}
-
-void NavigationAgent::set_velocity(Vector3 p_velocity) {
- target_velocity = p_velocity;
- NavigationServer::get_singleton()->agent_set_target_velocity(agent, target_velocity);
- NavigationServer::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
- velocity_submitted = true;
-}
-
-void NavigationAgent::_avoidance_done(Vector3 p_new_velocity) {
- prev_safe_velocity = p_new_velocity;
-
- if (!velocity_submitted) {
- target_velocity = Vector3();
- return;
- }
- velocity_submitted = false;
-
- emit_signal("velocity_computed", p_new_velocity);
-}
-
-String NavigationAgent::get_configuration_warning() const {
- if (!Object::cast_to<Spatial>(get_parent())) {
- return TTR("The NavigationAgent can be used only under a spatial node.");
- }
-
- return String();
-}
-
-void NavigationAgent::update_navigation() {
-
- if (agent_parent == NULL) return;
- if (navigation == NULL) return;
- if (update_frame_id == Engine::get_singleton()->get_physics_frames()) return;
-
- update_frame_id = Engine::get_singleton()->get_physics_frames();
-
- Vector3 o = agent_parent->get_global_transform().origin;
-
- bool reload_path = false;
-
- if (NavigationServer::get_singleton()->agent_is_map_changed(agent)) {
- reload_path = true;
- } else if (navigation_path.size() == 0) {
- reload_path = true;
- } else {
- // Check if too far from the navigation path
- if (nav_path_index > 0) {
- Vector3 segment[2];
- segment[0] = navigation_path[nav_path_index - 1];
- segment[1] = navigation_path[nav_path_index];
- segment[0].y -= navigation_height_offset;
- segment[1].y -= navigation_height_offset;
- Vector3 p = Geometry::get_closest_point_to_segment(o, segment);
- if (o.distance_to(p) >= path_max_distance) {
- // To faraway, reload path
- reload_path = true;
- }
- }
- }
-
- if (reload_path) {
- navigation_path = NavigationServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
- navigation_finished = false;
- nav_path_index = 0;
- emit_signal("path_changed");
- }
-
- if (navigation_path.size() == 0)
- return;
-
- // Check if we can advance the navigation path
- if (navigation_finished == false) {
- // Advances to the next far away location.
- 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()) {
- nav_path_index -= 1;
- navigation_finished = true;
- emit_signal("navigation_finished");
- break;
- }
- }
- }
-}
diff --git a/scene/3d/navigation_agent.h b/scene/3d/navigation_agent.h
deleted file mode 100644
index 200d5db475..0000000000
--- a/scene/3d/navigation_agent.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*************************************************************************/
-/* navigation_agent.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 NAVIGATION_AGENT_H
-#define NAVIGATION_AGENT_H
-
-#include "core/vector.h"
-#include "scene/main/node.h"
-
-class Spatial;
-class Navigation;
-
-class NavigationAgent : public Node {
- GDCLASS(NavigationAgent, Node);
-
- Spatial *agent_parent;
- Navigation *navigation;
-
- RID agent;
-
- real_t target_desired_distance;
- real_t radius;
- real_t navigation_height_offset;
- bool ignore_y;
- real_t neighbor_dist;
- int max_neighbors;
- real_t time_horizon;
- real_t max_speed;
-
- real_t path_max_distance;
-
- Vector3 target_location;
- Vector<Vector3> navigation_path;
- int nav_path_index;
- bool velocity_submitted;
- Vector3 prev_safe_velocity;
- /// The submitted target velocity
- Vector3 target_velocity;
- bool target_reached;
- bool navigation_finished;
- // No initialized on purpose
- uint32_t update_frame_id;
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
- NavigationAgent();
- virtual ~NavigationAgent();
-
- void set_navigation(Navigation *p_nav);
- const Navigation *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_target_desired_distance(real_t p_dd);
- real_t get_target_desired_distance() const {
- return target_desired_distance;
- }
-
- void set_radius(real_t p_radius);
- real_t get_radius() const {
- return radius;
- }
-
- void set_agent_height_offset(real_t p_hh);
- real_t get_agent_height_offset() const {
- return navigation_height_offset;
- }
-
- void set_ignore_y(bool p_ignore_y);
- bool get_ignore_y() const {
- return ignore_y;
- }
-
- void set_neighbor_dist(real_t p_dist);
- real_t get_neighbor_dist() const {
- return neighbor_dist;
- }
-
- void set_max_neighbors(int p_count);
- int get_max_neighbors() const {
- return max_neighbors;
- }
-
- void set_time_horizon(real_t p_time);
- real_t get_time_horizon() const {
- return time_horizon;
- }
-
- void set_max_speed(real_t p_max_speed);
- real_t get_max_speed() const {
- return max_speed;
- }
-
- void set_path_max_distance(real_t p_pmd);
- real_t get_path_max_distance();
-
- void set_target_location(Vector3 p_location);
- Vector3 get_target_location() const;
-
- Vector3 get_next_location();
-
- Vector<Vector3> get_nav_path() const {
- return navigation_path;
- }
-
- int get_nav_path_index() const {
- return nav_path_index;
- }
-
- real_t distance_to_target() const;
- bool is_target_reached() const;
- bool is_target_reachable();
- bool is_navigation_finished();
- Vector3 get_final_location();
-
- void set_velocity(Vector3 p_velocity);
- void _avoidance_done(Vector3 p_new_velocity);
-
- virtual String get_configuration_warning() const;
-
-private:
- void update_navigation();
-};
-
-#endif
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
new file mode 100644
index 0000000000..0449ab15b7
--- /dev/null
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -0,0 +1,362 @@
+/*************************************************************************/
+/* navigation_agent_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_agent_3d.h"
+
+#include "core/engine.h"
+#include "scene/3d/navigation_3d.h"
+#include "servers/navigation_server_3d.h"
+
+void NavigationAgent3D::_bind_methods() {
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent3D::get_radius);
+
+ ClassDB::bind_method(D_METHOD("set_agent_height_offset", "agent_height_offset"), &NavigationAgent3D::set_agent_height_offset);
+ ClassDB::bind_method(D_METHOD("get_agent_height_offset"), &NavigationAgent3D::get_agent_height_offset);
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent3D::set_max_neighbors);
+ ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent3D::get_max_neighbors);
+
+ ClassDB::bind_method(D_METHOD("set_time_horizon", "time_horizon"), &NavigationAgent3D::set_time_horizon);
+ ClassDB::bind_method(D_METHOD("get_time_horizon"), &NavigationAgent3D::get_time_horizon);
+
+ ClassDB::bind_method(D_METHOD("set_max_speed", "max_speed"), &NavigationAgent3D::set_max_speed);
+ ClassDB::bind_method(D_METHOD("get_max_speed"), &NavigationAgent3D::get_max_speed);
+
+ ClassDB::bind_method(D_METHOD("set_path_max_distance", "max_speed"), &NavigationAgent3D::set_path_max_distance);
+ ClassDB::bind_method(D_METHOD("get_path_max_distance"), &NavigationAgent3D::get_path_max_distance);
+
+ ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent3D::set_target_location);
+ ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent3D::get_target_location);
+ ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent3D::get_next_location);
+ ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent3D::distance_to_target);
+ ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent3D::set_velocity);
+ ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent3D::get_nav_path);
+ ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent3D::get_nav_path_index);
+ ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent3D::is_target_reached);
+ ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent3D::is_target_reachable);
+ ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent3D::is_navigation_finished);
+ ClassDB::bind_method(D_METHOD("get_final_location"), &NavigationAgent3D::get_final_location);
+
+ ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_target_desired_distance", "get_target_desired_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01"), "set_agent_height_offset", "get_agent_height_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_neighbor_dist", "get_neighbor_dist");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_time_horizon", "get_time_horizon");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_max_speed", "get_max_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1"), "set_path_max_distance", "get_path_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y");
+
+ ADD_SIGNAL(MethodInfo("path_changed"));
+ ADD_SIGNAL(MethodInfo("target_reached"));
+ ADD_SIGNAL(MethodInfo("navigation_finished"));
+ ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
+}
+
+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);
+ }
+
+ 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;
+ }
+ }
+ }
+ } break;
+ }
+}
+
+NavigationAgent3D::NavigationAgent3D() :
+ agent_parent(nullptr),
+ navigation(nullptr),
+ agent(RID()),
+ target_desired_distance(1.0),
+ navigation_height_offset(0.0),
+ path_max_distance(3.0),
+ velocity_submitted(false),
+ target_reached(false),
+ navigation_finished(true) {
+ agent = NavigationServer3D::get_singleton()->agent_create();
+ set_neighbor_dist(50.0);
+ set_max_neighbors(10);
+ set_time_horizon(5.0);
+ set_radius(1.0);
+ set_max_speed(10.0);
+ set_ignore_y(true);
+}
+
+NavigationAgent3D::~NavigationAgent3D() {
+ NavigationServer3D::get_singleton()->free(agent);
+ 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;
+}
+
+void NavigationAgent3D::set_radius(real_t p_radius) {
+ radius = p_radius;
+ NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
+}
+
+void NavigationAgent3D::set_agent_height_offset(real_t p_hh) {
+ navigation_height_offset = p_hh;
+}
+
+void NavigationAgent3D::set_ignore_y(bool p_ignore_y) {
+ ignore_y = p_ignore_y;
+ NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y);
+}
+
+void NavigationAgent3D::set_neighbor_dist(real_t p_dist) {
+ neighbor_dist = p_dist;
+ NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist);
+}
+
+void NavigationAgent3D::set_max_neighbors(int p_count) {
+ max_neighbors = p_count;
+ NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
+}
+
+void NavigationAgent3D::set_time_horizon(real_t p_time) {
+ time_horizon = p_time;
+ NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
+}
+
+void NavigationAgent3D::set_max_speed(real_t p_max_speed) {
+ max_speed = p_max_speed;
+ NavigationServer3D::get_singleton()->agent_set_max_speed(agent, max_speed);
+}
+
+void NavigationAgent3D::set_path_max_distance(real_t p_pmd) {
+ path_max_distance = p_pmd;
+}
+
+real_t NavigationAgent3D::get_path_max_distance() {
+ return path_max_distance;
+}
+
+void NavigationAgent3D::set_target_location(Vector3 p_location) {
+ target_location = p_location;
+ navigation_path.clear();
+ target_reached = false;
+ navigation_finished = false;
+ update_frame_id = 0;
+}
+
+Vector3 NavigationAgent3D::get_target_location() const {
+ return target_location;
+}
+
+Vector3 NavigationAgent3D::get_next_location() {
+ update_navigation();
+ if (navigation_path.size() == 0) {
+ ERR_FAIL_COND_V(agent_parent == nullptr, Vector3());
+ return agent_parent->get_global_transform().origin;
+ } else {
+ return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0);
+ }
+}
+
+real_t NavigationAgent3D::distance_to_target() const {
+ ERR_FAIL_COND_V(agent_parent == nullptr, 0.0);
+ return agent_parent->get_global_transform().origin.distance_to(target_location);
+}
+
+bool NavigationAgent3D::is_target_reached() const {
+ return target_reached;
+}
+
+bool NavigationAgent3D::is_target_reachable() {
+ return target_desired_distance >= get_final_location().distance_to(target_location);
+}
+
+bool NavigationAgent3D::is_navigation_finished() {
+ update_navigation();
+ return navigation_finished;
+}
+
+Vector3 NavigationAgent3D::get_final_location() {
+ update_navigation();
+ if (navigation_path.size() == 0) {
+ return Vector3();
+ }
+ return navigation_path[navigation_path.size() - 1];
+}
+
+void NavigationAgent3D::set_velocity(Vector3 p_velocity) {
+ target_velocity = p_velocity;
+ NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, target_velocity);
+ NavigationServer3D::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
+ velocity_submitted = true;
+}
+
+void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
+ prev_safe_velocity = p_new_velocity;
+
+ if (!velocity_submitted) {
+ target_velocity = Vector3();
+ return;
+ }
+ velocity_submitted = false;
+
+ emit_signal("velocity_computed", p_new_velocity);
+}
+
+String NavigationAgent3D::get_configuration_warning() const {
+ if (!Object::cast_to<Node3D>(get_parent())) {
+ return TTR("The NavigationAgent3D can be used only under a spatial node.");
+ }
+
+ return String();
+}
+
+void NavigationAgent3D::update_navigation() {
+
+ if (agent_parent == nullptr) return;
+ if (navigation == nullptr) return;
+ if (update_frame_id == Engine::get_singleton()->get_physics_frames()) return;
+
+ update_frame_id = Engine::get_singleton()->get_physics_frames();
+
+ Vector3 o = agent_parent->get_global_transform().origin;
+
+ bool reload_path = false;
+
+ if (NavigationServer3D::get_singleton()->agent_is_map_changed(agent)) {
+ reload_path = true;
+ } else if (navigation_path.size() == 0) {
+ reload_path = true;
+ } else {
+ // Check if too far from the navigation path
+ if (nav_path_index > 0) {
+ Vector3 segment[2];
+ segment[0] = navigation_path[nav_path_index - 1];
+ segment[1] = navigation_path[nav_path_index];
+ segment[0].y -= navigation_height_offset;
+ segment[1].y -= navigation_height_offset;
+ Vector3 p = Geometry::get_closest_point_to_segment(o, segment);
+ if (o.distance_to(p) >= path_max_distance) {
+ // To faraway, reload path
+ reload_path = true;
+ }
+ }
+ }
+
+ if (reload_path) {
+ navigation_path = NavigationServer3D::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
+ navigation_finished = false;
+ nav_path_index = 0;
+ emit_signal("path_changed");
+ }
+
+ if (navigation_path.size() == 0)
+ return;
+
+ // Check if we can advance the navigation path
+ if (navigation_finished == false) {
+ // Advances to the next far away location.
+ 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()) {
+ nav_path_index -= 1;
+ navigation_finished = true;
+ emit_signal("navigation_finished");
+ break;
+ }
+ }
+ }
+}
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
new file mode 100644
index 0000000000..3558b4e51b
--- /dev/null
+++ b/scene/3d/navigation_agent_3d.h
@@ -0,0 +1,162 @@
+/*************************************************************************/
+/* navigation_agent_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 NAVIGATION_AGENT_H
+#define NAVIGATION_AGENT_H
+
+#include "core/vector.h"
+#include "scene/main/node.h"
+
+class Node3D;
+class Navigation3D;
+
+class NavigationAgent3D : public Node {
+ GDCLASS(NavigationAgent3D, Node);
+
+ Node3D *agent_parent;
+ Navigation3D *navigation;
+
+ RID agent;
+
+ real_t target_desired_distance;
+ real_t radius;
+ real_t navigation_height_offset;
+ bool ignore_y;
+ real_t neighbor_dist;
+ int max_neighbors;
+ real_t time_horizon;
+ real_t max_speed;
+
+ real_t path_max_distance;
+
+ Vector3 target_location;
+ Vector<Vector3> navigation_path;
+ int nav_path_index;
+ bool velocity_submitted;
+ Vector3 prev_safe_velocity;
+ /// The submitted target velocity
+ Vector3 target_velocity;
+ bool target_reached;
+ bool navigation_finished;
+ // No initialized on purpose
+ uint32_t update_frame_id;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+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;
+ }
+
+ void set_target_desired_distance(real_t p_dd);
+ real_t get_target_desired_distance() const {
+ return target_desired_distance;
+ }
+
+ void set_radius(real_t p_radius);
+ real_t get_radius() const {
+ return radius;
+ }
+
+ void set_agent_height_offset(real_t p_hh);
+ real_t get_agent_height_offset() const {
+ return navigation_height_offset;
+ }
+
+ void set_ignore_y(bool p_ignore_y);
+ bool get_ignore_y() const {
+ return ignore_y;
+ }
+
+ void set_neighbor_dist(real_t p_dist);
+ real_t get_neighbor_dist() const {
+ return neighbor_dist;
+ }
+
+ void set_max_neighbors(int p_count);
+ int get_max_neighbors() const {
+ return max_neighbors;
+ }
+
+ void set_time_horizon(real_t p_time);
+ real_t get_time_horizon() const {
+ return time_horizon;
+ }
+
+ void set_max_speed(real_t p_max_speed);
+ real_t get_max_speed() const {
+ return max_speed;
+ }
+
+ void set_path_max_distance(real_t p_pmd);
+ real_t get_path_max_distance();
+
+ void set_target_location(Vector3 p_location);
+ Vector3 get_target_location() const;
+
+ Vector3 get_next_location();
+
+ Vector<Vector3> get_nav_path() const {
+ return navigation_path;
+ }
+
+ int get_nav_path_index() const {
+ return nav_path_index;
+ }
+
+ real_t distance_to_target() const;
+ bool is_target_reached() const;
+ bool is_target_reachable();
+ bool is_navigation_finished();
+ Vector3 get_final_location();
+
+ void set_velocity(Vector3 p_velocity);
+ void _avoidance_done(Vector3 p_new_velocity);
+
+ virtual String get_configuration_warning() const;
+
+private:
+ void update_navigation();
+};
+
+#endif
diff --git a/scene/3d/navigation_obstacle.cpp b/scene/3d/navigation_obstacle.cpp
deleted file mode 100644
index befc41eee5..0000000000
--- a/scene/3d/navigation_obstacle.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*************************************************************************/
-/* navigation_obstacle.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_obstacle.h"
-
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/navigation.h"
-#include "scene/3d/physics_body.h"
-#include "servers/navigation_server.h"
-
-void NavigationObstacle::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle::set_navigation_node);
- ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle::get_navigation_node);
-}
-
-void NavigationObstacle::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
-
- update_agent_shape();
-
- // Search the navigation node and set it
- {
- Navigation *nav = NULL;
- Node *p = get_parent();
- while (p != NULL) {
- nav = Object::cast_to<Navigation>(p);
- if (nav != NULL)
- p = NULL;
- else
- p = p->get_parent();
- }
-
- set_navigation(nav);
- }
-
- set_physics_process_internal(true);
- } break;
- case NOTIFICATION_EXIT_TREE: {
- set_navigation(NULL);
- set_physics_process_internal(false);
- } break;
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- Spatial *spatial = Object::cast_to<Spatial>(get_parent());
- if (spatial) {
- NavigationServer::get_singleton()->agent_set_position(agent, spatial->get_global_transform().origin);
- }
-
- PhysicsBody *rigid = Object::cast_to<PhysicsBody>(get_parent());
- if (rigid) {
-
- Vector3 v = rigid->get_linear_velocity();
- NavigationServer::get_singleton()->agent_set_velocity(agent, v);
- NavigationServer::get_singleton()->agent_set_target_velocity(agent, v);
- }
-
- } break;
- }
-}
-
-NavigationObstacle::NavigationObstacle() :
- navigation(NULL),
- agent(RID()) {
- agent = NavigationServer::get_singleton()->agent_create();
-}
-
-NavigationObstacle::~NavigationObstacle() {
- NavigationServer::get_singleton()->free(agent);
- agent = RID(); // Pointless
-}
-
-void NavigationObstacle::set_navigation(Navigation *p_nav) {
- if (navigation == p_nav)
- return; // Pointless
-
- navigation = p_nav;
- NavigationServer::get_singleton()->agent_set_map(agent, navigation == NULL ? RID() : navigation->get_rid());
-}
-
-void NavigationObstacle::set_navigation_node(Node *p_nav) {
- Navigation *nav = Object::cast_to<Navigation>(p_nav);
- ERR_FAIL_COND(nav == NULL);
- set_navigation(nav);
-}
-
-Node *NavigationObstacle::get_navigation_node() const {
- return Object::cast_to<Node>(navigation);
-}
-
-String NavigationObstacle::get_configuration_warning() const {
- if (!Object::cast_to<Spatial>(get_parent())) {
-
- return TTR("The NavigationObstacle only serves to provide collision avoidance to a spatial object.");
- }
-
- return String();
-}
-
-void NavigationObstacle::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
- CollisionShape *cs = Object::cast_to<CollisionShape>(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();
- }
- 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);
- }
- }
- Spatial *spa = Object::cast_to<Spatial>(node);
- if (spa) {
- Vector3 s = spa->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
-
- // Initialize the Agent as an object
- NavigationServer::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
- NavigationServer::get_singleton()->agent_set_max_neighbors(agent, 0);
- NavigationServer::get_singleton()->agent_set_time_horizon(agent, 0.0);
- NavigationServer::get_singleton()->agent_set_radius(agent, radius);
- NavigationServer::get_singleton()->agent_set_max_speed(agent, 0.0);
-}
diff --git a/scene/3d/navigation_obstacle.h b/scene/3d/navigation_obstacle.h
deleted file mode 100644
index 7257a43150..0000000000
--- a/scene/3d/navigation_obstacle.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* navigation_obstacle.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 NAVIGATION_OBSTACLE_H
-#define NAVIGATION_OBSTACLE_H
-
-#include "scene/main/node.h"
-
-class Navigation;
-
-class NavigationObstacle : public Node {
- GDCLASS(NavigationObstacle, Node);
-
- Navigation *navigation;
-
- RID agent;
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
- NavigationObstacle();
- virtual ~NavigationObstacle();
-
- void set_navigation(Navigation *p_nav);
- const Navigation *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;
-
-private:
- void update_agent_shape();
-};
-
-#endif
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
new file mode 100644
index 0000000000..2ee2008799
--- /dev/null
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* navigation_obstacle_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_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_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);
+ }
+
+ } break;
+ }
+}
+
+NavigationObstacle3D::NavigationObstacle3D() :
+ navigation(nullptr),
+ agent(RID()) {
+ agent = NavigationServer3D::get_singleton()->agent_create();
+}
+
+NavigationObstacle3D::~NavigationObstacle3D() {
+ NavigationServer3D::get_singleton()->free(agent);
+ 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 {
+ if (!Object::cast_to<Node3D>(get_parent())) {
+
+ return TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
+ }
+
+ return String();
+}
+
+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();
+ }
+ 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();
+ radius *= MAX(s.x, MAX(s.y, s.z));
+ }
+
+ 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);
+}
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
new file mode 100644
index 0000000000..b58d7c4991
--- /dev/null
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* navigation_obstacle_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 NAVIGATION_OBSTACLE_H
+#define NAVIGATION_OBSTACLE_H
+
+#include "scene/main/node.h"
+
+class Navigation3D;
+
+class NavigationObstacle3D : public Node {
+ GDCLASS(NavigationObstacle3D, Node);
+
+ Navigation3D *navigation;
+
+ RID agent;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+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;
+
+private:
+ void update_agent_shape();
+};
+
+#endif
diff --git a/scene/3d/navigation_region.cpp b/scene/3d/navigation_region.cpp
deleted file mode 100644
index 53b707a29a..0000000000
--- a/scene/3d/navigation_region.cpp
+++ /dev/null
@@ -1,258 +0,0 @@
-/*************************************************************************/
-/* navigation_region.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_region.h"
-#include "core/os/thread.h"
-#include "mesh_instance.h"
-#include "navigation.h"
-#include "servers/navigation_server.h"
-
-void NavigationRegion::set_enabled(bool p_enabled) {
-
- if (enabled == p_enabled)
- return;
- enabled = p_enabled;
-
- if (!is_inside_tree())
- return;
-
- if (!enabled) {
-
- NavigationServer::get_singleton()->region_set_map(region, RID());
- } else {
-
- if (navigation) {
-
- NavigationServer::get_singleton()->region_set_map(region, navigation->get_rid());
- }
- }
-
- if (debug_view) {
- MeshInstance *dm = Object::cast_to<MeshInstance>(debug_view);
- if (is_enabled()) {
- dm->set_material_override(get_tree()->get_debug_navigation_material());
- } else {
- dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
- }
- }
-
- update_gizmo();
-}
-
-bool NavigationRegion::is_enabled() const {
-
- return enabled;
-}
-
-/////////////////////////////
-
-void NavigationRegion::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
-
- Spatial *c = this;
- while (c) {
-
- navigation = Object::cast_to<Navigation>(c);
- if (navigation) {
-
- if (enabled) {
-
- NavigationServer::get_singleton()->region_set_map(region, navigation->get_rid());
- }
- break;
- }
-
- c = c->get_parent_spatial();
- }
-
- if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
-
- MeshInstance *dm = memnew(MeshInstance);
- dm->set_mesh(navmesh->get_debug_mesh());
- if (is_enabled()) {
- dm->set_material_override(get_tree()->get_debug_navigation_material());
- } else {
- dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
- }
- add_child(dm);
- debug_view = dm;
- }
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- NavigationServer::get_singleton()->region_set_transform(region, get_global_transform());
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- if (navigation) {
-
- NavigationServer::get_singleton()->region_set_map(region, RID());
- }
-
- if (debug_view) {
- debug_view->queue_delete();
- debug_view = NULL;
- }
- navigation = NULL;
- } break;
- }
-}
-
-void NavigationRegion::set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh) {
-
- if (p_navmesh == navmesh)
- return;
-
- if (navmesh.is_valid()) {
- navmesh->remove_change_receptor(this);
- }
-
- navmesh = p_navmesh;
-
- if (navmesh.is_valid()) {
- navmesh->add_change_receptor(this);
- }
-
- NavigationServer::get_singleton()->region_set_navmesh(region, p_navmesh);
-
- if (debug_view && navmesh.is_valid()) {
- Object::cast_to<MeshInstance>(debug_view)->set_mesh(navmesh->get_debug_mesh());
- }
-
- emit_signal("navigation_mesh_changed");
-
- update_gizmo();
- update_configuration_warning();
-}
-
-Ref<NavigationMesh> NavigationRegion::get_navigation_mesh() const {
-
- return navmesh;
-}
-
-struct BakeThreadsArgs {
- NavigationRegion *nav_region;
-};
-
-void _bake_navigation_mesh(void *p_user_data) {
- BakeThreadsArgs *args = static_cast<BakeThreadsArgs *>(p_user_data);
-
- if (args->nav_region->get_navigation_mesh().is_valid()) {
- Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate();
-
- NavigationServer::get_singleton()->region_bake_navmesh(nav_mesh, args->nav_region);
- args->nav_region->call_deferred("_bake_finished", nav_mesh);
- memdelete(args);
- } else {
-
- ERR_PRINT("Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist");
- args->nav_region->call_deferred("_bake_finished", Ref<NavigationMesh>());
- memdelete(args);
- }
-}
-
-void NavigationRegion::bake_navigation_mesh() {
- ERR_FAIL_COND(bake_thread != NULL);
-
- BakeThreadsArgs *args = memnew(BakeThreadsArgs);
- args->nav_region = this;
-
- bake_thread = Thread::create(_bake_navigation_mesh, args);
- ERR_FAIL_COND(bake_thread == NULL);
-}
-
-void NavigationRegion::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
- set_navigation_mesh(p_nav_mesh);
- bake_thread = NULL;
-}
-
-String NavigationRegion::get_configuration_warning() const {
-
- if (!is_visible_in_tree() || !is_inside_tree())
- return String();
-
- if (!navmesh.is_valid()) {
- return TTR("A NavigationMesh resource must be set or created for this node to work.");
- }
- const Spatial *c = this;
- while (c) {
-
- if (Object::cast_to<Navigation>(c))
- return String();
-
- c = Object::cast_to<Spatial>(c->get_parent());
- }
-
- return TTR("NavigationRegion must be a child or grandchild to a Navigation node. It only provides navigation data.");
-}
-
-void NavigationRegion::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationRegion::set_navigation_mesh);
- ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion::get_navigation_mesh);
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion::set_enabled);
- ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion::is_enabled);
-
- ClassDB::bind_method(D_METHOD("bake_navigation_mesh"), &NavigationRegion::bake_navigation_mesh);
- ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion::_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_SIGNAL(MethodInfo("navigation_mesh_changed"));
- ADD_SIGNAL(MethodInfo("bake_finished"));
-}
-
-void NavigationRegion::_changed_callback(Object *p_changed, const char *p_prop) {
- update_gizmo();
- update_configuration_warning();
-}
-
-NavigationRegion::NavigationRegion() {
-
- enabled = true;
- set_notify_transform(true);
- region = NavigationServer::get_singleton()->region_create();
-
- navigation = NULL;
- debug_view = NULL;
- bake_thread = NULL;
-}
-
-NavigationRegion::~NavigationRegion() {
- if (navmesh.is_valid())
- navmesh->remove_change_receptor(this);
- NavigationServer::get_singleton()->free(region);
-}
diff --git a/scene/3d/navigation_region.h b/scene/3d/navigation_region.h
deleted file mode 100644
index f215e92c97..0000000000
--- a/scene/3d/navigation_region.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*************************************************************************/
-/* navigation_region.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 NAVIGATION_REGION_H
-#define NAVIGATION_REGION_H
-
-#include "scene/3d/spatial.h"
-#include "scene/resources/mesh.h"
-#include "scene/resources/navigation_mesh.h"
-
-class Navigation;
-
-class NavigationRegion : public Spatial {
-
- GDCLASS(NavigationRegion, Spatial);
-
- bool enabled;
- RID region;
- Ref<NavigationMesh> navmesh;
-
- Navigation *navigation;
- Node *debug_view;
- Thread *bake_thread;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
- void _changed_callback(Object *p_changed, const char *p_prop);
-
-public:
- void set_enabled(bool p_enabled);
- bool is_enabled() const;
-
- void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);
- Ref<NavigationMesh> get_navigation_mesh() const;
-
- /// Bakes the navigation mesh in a dedicated thread; once done, automatically
- /// sets the new navigation mesh and emits a signal
- void bake_navigation_mesh();
- void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
-
- String get_configuration_warning() const;
-
- NavigationRegion();
- ~NavigationRegion();
-};
-
-#endif // NAVIGATION_REGION_H
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
new file mode 100644
index 0000000000..043b816033
--- /dev/null
+++ b/scene/3d/navigation_region_3d.cpp
@@ -0,0 +1,259 @@
+/*************************************************************************/
+/* navigation_region_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_region_3d.h"
+
+#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) {
+
+ if (enabled == p_enabled)
+ return;
+ enabled = p_enabled;
+
+ if (!is_inside_tree())
+ return;
+
+ if (!enabled) {
+
+ NavigationServer3D::get_singleton()->region_set_map(region, RID());
+ } else {
+
+ if (navigation) {
+
+ NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid());
+ }
+ }
+
+ if (debug_view) {
+ MeshInstance3D *dm = Object::cast_to<MeshInstance3D>(debug_view);
+ if (is_enabled()) {
+ dm->set_material_override(get_tree()->get_debug_navigation_material());
+ } else {
+ dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
+ }
+ }
+
+ update_gizmo();
+}
+
+bool NavigationRegion3D::is_enabled() const {
+
+ return enabled;
+}
+
+/////////////////////////////
+
+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 (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
+
+ MeshInstance3D *dm = memnew(MeshInstance3D);
+ dm->set_mesh(navmesh->get_debug_mesh());
+ if (is_enabled()) {
+ dm->set_material_override(get_tree()->get_debug_navigation_material());
+ } else {
+ dm->set_material_override(get_tree()->get_debug_navigation_disabled_material());
+ }
+ add_child(dm);
+ debug_view = dm;
+ }
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform());
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ if (navigation) {
+
+ NavigationServer3D::get_singleton()->region_set_map(region, RID());
+ }
+
+ if (debug_view) {
+ debug_view->queue_delete();
+ debug_view = nullptr;
+ }
+ navigation = nullptr;
+ } break;
+ }
+}
+
+void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh) {
+
+ if (p_navmesh == navmesh)
+ return;
+
+ if (navmesh.is_valid()) {
+ navmesh->remove_change_receptor(this);
+ }
+
+ navmesh = p_navmesh;
+
+ if (navmesh.is_valid()) {
+ navmesh->add_change_receptor(this);
+ }
+
+ NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh);
+
+ if (debug_view && navmesh.is_valid()) {
+ Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh());
+ }
+
+ emit_signal("navigation_mesh_changed");
+
+ update_gizmo();
+ update_configuration_warning();
+}
+
+Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
+
+ return navmesh;
+}
+
+struct BakeThreadsArgs {
+ NavigationRegion3D *nav_region;
+};
+
+void _bake_navigation_mesh(void *p_user_data) {
+ BakeThreadsArgs *args = static_cast<BakeThreadsArgs *>(p_user_data);
+
+ if (args->nav_region->get_navigation_mesh().is_valid()) {
+ Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate();
+
+ NavigationServer3D::get_singleton()->region_bake_navmesh(nav_mesh, args->nav_region);
+ args->nav_region->call_deferred("_bake_finished", nav_mesh);
+ memdelete(args);
+ } else {
+
+ ERR_PRINT("Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist");
+ args->nav_region->call_deferred("_bake_finished", Ref<NavigationMesh>());
+ memdelete(args);
+ }
+}
+
+void NavigationRegion3D::bake_navigation_mesh() {
+ ERR_FAIL_COND(bake_thread != nullptr);
+
+ BakeThreadsArgs *args = memnew(BakeThreadsArgs);
+ args->nav_region = this;
+
+ bake_thread = Thread::create(_bake_navigation_mesh, args);
+ ERR_FAIL_COND(bake_thread == nullptr);
+}
+
+void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
+ set_navigation_mesh(p_nav_mesh);
+ bake_thread = nullptr;
+}
+
+String NavigationRegion3D::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!navmesh.is_valid()) {
+ return TTR("A NavigationMesh resource must be set or created for this node to work.");
+ }
+ const Node3D *c = this;
+ while (c) {
+
+ if (Object::cast_to<Navigation3D>(c))
+ return String();
+
+ c = Object::cast_to<Node3D>(c->get_parent());
+ }
+
+ return TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data.");
+}
+
+void NavigationRegion3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationRegion3D::set_navigation_mesh);
+ ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion3D::get_navigation_mesh);
+
+ 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("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_SIGNAL(MethodInfo("navigation_mesh_changed"));
+ ADD_SIGNAL(MethodInfo("bake_finished"));
+}
+
+void NavigationRegion3D::_changed_callback(Object *p_changed, const char *p_prop) {
+ update_gizmo();
+ update_configuration_warning();
+}
+
+NavigationRegion3D::NavigationRegion3D() {
+
+ enabled = true;
+ set_notify_transform(true);
+ region = NavigationServer3D::get_singleton()->region_create();
+
+ navigation = nullptr;
+ debug_view = nullptr;
+ bake_thread = nullptr;
+}
+
+NavigationRegion3D::~NavigationRegion3D() {
+ if (navmesh.is_valid())
+ navmesh->remove_change_receptor(this);
+ NavigationServer3D::get_singleton()->free(region);
+}
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
new file mode 100644
index 0000000000..ae071e6b7a
--- /dev/null
+++ b/scene/3d/navigation_region_3d.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* navigation_region_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 NAVIGATION_REGION_H
+#define NAVIGATION_REGION_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/mesh.h"
+#include "scene/resources/navigation_mesh.h"
+
+class Navigation3D;
+
+class NavigationRegion3D : public Node3D {
+
+ GDCLASS(NavigationRegion3D, Node3D);
+
+ bool enabled;
+ RID region;
+ Ref<NavigationMesh> navmesh;
+
+ Navigation3D *navigation;
+ Node *debug_view;
+ Thread *bake_thread;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ void _changed_callback(Object *p_changed, const char *p_prop);
+
+public:
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);
+ Ref<NavigationMesh> get_navigation_mesh() const;
+
+ /// Bakes the navigation mesh in a dedicated thread; once done, automatically
+ /// sets the new navigation mesh and emits a signal
+ void bake_navigation_mesh();
+ void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
+
+ String get_configuration_warning() const;
+
+ NavigationRegion3D();
+ ~NavigationRegion3D();
+};
+
+#endif // NAVIGATION_REGION_H
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
new file mode 100644
index 0000000000..0b7407e049
--- /dev/null
+++ b/scene/3d/node_3d.cpp
@@ -0,0 +1,848 @@
+/*************************************************************************/
+/* node_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "node_3d.h"
+
+#include "core/engine.h"
+#include "core/message_queue.h"
+#include "scene/main/scene_tree.h"
+#include "scene/main/window.h"
+#include "scene/scene_string_names.h"
+
+/*
+
+ possible algorithms:
+
+ Algorithm 1: (current)
+
+ definition of invalidation: global is invalid
+
+ 1) If a node sets a LOCAL, it produces an invalidation of everything above
+ 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
+
+---
+
+ Algorithm 2: (no longer current)
+
+ definition of invalidation: NONE dirty, LOCAL dirty, GLOBAL dirty
+
+ 1) If a node sets a LOCAL, it must climb the tree and set it as GLOBAL dirty
+ a) marking GLOBALs as dirty up all the tree must be done always
+ 2) If a node sets a GLOBAL, it marks local as dirty, and that's all?
+
+ //is clearing the dirty state correct in this case?
+
+ drawback: setting a local down the tree forces many tree walks often
+
+--
+
+future: no idea
+
+ */
+
+Node3DGizmo::Node3DGizmo() {
+}
+
+void Node3D::_notify_dirty() {
+
+#ifdef TOOLS_ENABLED
+ if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
+#else
+ if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
+
+#endif
+ get_tree()->xform_change_list.add(&xform_change);
+ }
+}
+
+void Node3D::_update_local_transform() const {
+ data.local_transform.basis.set_euler_scale(data.rotation, data.scale);
+
+ data.dirty &= ~DIRTY_LOCAL;
+}
+void Node3D::_propagate_transform_changed(Node3D *p_origin) {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ /*
+ if (data.dirty&DIRTY_GLOBAL)
+ return; //already dirty
+ */
+
+ data.children_lock++;
+
+ for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
+
+ if (E->get()->data.toplevel_active)
+ continue; //don't propagate to a toplevel
+ E->get()->_propagate_transform_changed(p_origin);
+ }
+#ifdef TOOLS_ENABLED
+ if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
+#else
+ if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
+#endif
+ get_tree()->xform_change_list.add(&xform_change);
+ }
+ data.dirty |= DIRTY_GLOBAL;
+
+ data.children_lock--;
+}
+
+void Node3D::_notification(int p_what) {
+
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ ERR_FAIL_COND(!get_tree());
+
+ Node *p = get_parent();
+ if (p)
+ data.parent = Object::cast_to<Node3D>(p);
+
+ if (data.parent)
+ data.C = data.parent->data.children.push_back(this);
+ else
+ data.C = nullptr;
+
+ if (data.toplevel && !Engine::get_singleton()->is_editor_hint()) {
+
+ if (data.parent) {
+ data.local_transform = data.parent->get_global_transform() * get_transform();
+ data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene
+ }
+ data.toplevel_active = true;
+ }
+
+ data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene
+ _notify_dirty();
+
+ notification(NOTIFICATION_ENTER_WORLD);
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ notification(NOTIFICATION_EXIT_WORLD, true);
+ if (xform_change.in_list())
+ get_tree()->xform_change_list.remove(&xform_change);
+ if (data.C)
+ data.parent->data.children.erase(data.C);
+ data.parent = nullptr;
+ data.C = nullptr;
+ data.toplevel_active = false;
+ } break;
+ case NOTIFICATION_ENTER_WORLD: {
+
+ data.inside_world = true;
+ data.viewport = nullptr;
+ Node *parent = get_parent();
+ while (parent && !data.viewport) {
+ data.viewport = Object::cast_to<Viewport>(parent);
+ parent = parent->get_parent();
+ }
+
+ ERR_FAIL_COND(!data.viewport);
+
+ if (get_script_instance()) {
+
+ get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, nullptr, 0);
+ }
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
+
+ //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
+ get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
+ if (!data.gizmo_disabled) {
+
+ if (data.gizmo.is_valid()) {
+ data.gizmo->create();
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
+ }
+ data.gizmo->transform();
+ }
+ }
+ }
+#endif
+
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+#ifdef TOOLS_ENABLED
+ if (data.gizmo.is_valid()) {
+ data.gizmo->free();
+ data.gizmo.unref();
+ }
+#endif
+
+ if (get_script_instance()) {
+
+ get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, nullptr, 0);
+ }
+
+ data.viewport = nullptr;
+ data.inside_world = false;
+
+ } break;
+
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+#ifdef TOOLS_ENABLED
+ if (data.gizmo.is_valid()) {
+ data.gizmo->transform();
+ }
+#endif
+ } break;
+
+ default: {
+ }
+ }
+}
+
+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);
+ }
+}
+
+void Node3D::set_global_transform(const Transform &p_transform) {
+
+ Transform xform =
+ (data.parent && !data.toplevel_active) ?
+ data.parent->get_global_transform().affine_inverse() * p_transform :
+ p_transform;
+
+ set_transform(xform);
+}
+
+Transform Node3D::get_transform() const {
+
+ if (data.dirty & DIRTY_LOCAL) {
+
+ _update_local_transform();
+ }
+
+ return data.local_transform;
+}
+Transform Node3D::get_global_transform() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform());
+
+ if (data.dirty & DIRTY_GLOBAL) {
+
+ if (data.dirty & DIRTY_LOCAL) {
+
+ _update_local_transform();
+ }
+
+ if (data.parent && !data.toplevel_active) {
+
+ data.global_transform = data.parent->get_global_transform() * data.local_transform;
+ } else {
+
+ data.global_transform = data.local_transform;
+ }
+
+ if (data.disable_scale) {
+ data.global_transform.basis.orthonormalize();
+ }
+
+ data.dirty &= ~DIRTY_GLOBAL;
+ }
+
+ return data.global_transform;
+}
+
+#ifdef TOOLS_ENABLED
+Transform Node3D::get_global_gizmo_transform() const {
+ return get_global_transform();
+}
+
+Transform Node3D::get_local_gizmo_transform() const {
+ return get_transform();
+}
+#endif
+
+Node3D *Node3D::get_parent_spatial() const {
+
+ return data.parent;
+}
+
+Transform Node3D::get_relative_transform(const Node *p_parent) const {
+
+ if (p_parent == this)
+ return Transform();
+
+ ERR_FAIL_COND_V(!data.parent, Transform());
+
+ if (p_parent == data.parent)
+ return get_transform();
+ else
+ return data.parent->get_relative_transform(p_parent) * get_transform();
+}
+
+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);
+ }
+}
+
+void Node3D::set_rotation(const Vector3 &p_euler_rad) {
+
+ if (data.dirty & DIRTY_VECTORS) {
+ data.scale = data.local_transform.basis.get_scale();
+ data.dirty &= ~DIRTY_VECTORS;
+ }
+
+ 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);
+ }
+}
+
+void Node3D::set_rotation_degrees(const Vector3 &p_euler_deg) {
+
+ set_rotation(p_euler_deg * Math_PI / 180.0);
+}
+
+void Node3D::set_scale(const Vector3 &p_scale) {
+
+ if (data.dirty & DIRTY_VECTORS) {
+ data.rotation = data.local_transform.basis.get_rotation();
+ data.dirty &= ~DIRTY_VECTORS;
+ }
+
+ 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);
+ }
+}
+
+Vector3 Node3D::get_translation() const {
+
+ return data.local_transform.origin;
+}
+
+Vector3 Node3D::get_rotation() const {
+
+ if (data.dirty & DIRTY_VECTORS) {
+ data.scale = data.local_transform.basis.get_scale();
+ data.rotation = data.local_transform.basis.get_rotation();
+
+ data.dirty &= ~DIRTY_VECTORS;
+ }
+
+ return data.rotation;
+}
+
+Vector3 Node3D::get_rotation_degrees() const {
+
+ return get_rotation() * 180.0 / Math_PI;
+}
+
+Vector3 Node3D::get_scale() const {
+
+ if (data.dirty & DIRTY_VECTORS) {
+ data.scale = data.local_transform.basis.get_scale();
+ data.rotation = data.local_transform.basis.get_rotation();
+
+ data.dirty &= ~DIRTY_VECTORS;
+ }
+
+ return data.scale;
+}
+
+void Node3D::update_gizmo() {
+
+#ifdef TOOLS_ENABLED
+ if (!is_inside_world())
+ return;
+ if (!data.gizmo.is_valid())
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
+ if (!data.gizmo.is_valid())
+ return;
+ if (data.gizmo_dirty)
+ return;
+ data.gizmo_dirty = true;
+ MessageQueue::get_singleton()->push_call(this, "_update_gizmo");
+#endif
+}
+
+void Node3D::set_gizmo(const Ref<Node3DGizmo> &p_gizmo) {
+
+#ifdef TOOLS_ENABLED
+
+ if (data.gizmo_disabled)
+ return;
+ if (data.gizmo.is_valid() && is_inside_world())
+ data.gizmo->free();
+ data.gizmo = p_gizmo;
+ if (data.gizmo.is_valid() && is_inside_world()) {
+
+ data.gizmo->create();
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
+ }
+ data.gizmo->transform();
+ }
+
+#endif
+}
+
+Ref<Node3DGizmo> Node3D::get_gizmo() const {
+
+#ifdef TOOLS_ENABLED
+
+ return data.gizmo;
+#else
+
+ return Ref<Node3DGizmo>();
+#endif
+}
+
+void Node3D::_update_gizmo() {
+
+#ifdef TOOLS_ENABLED
+ if (!is_inside_world())
+ return;
+ data.gizmo_dirty = false;
+ if (data.gizmo.is_valid()) {
+ if (is_visible_in_tree())
+ data.gizmo->redraw();
+ else
+ data.gizmo->clear();
+ }
+#endif
+}
+
+#ifdef TOOLS_ENABLED
+void Node3D::set_disable_gizmo(bool p_enabled) {
+
+ data.gizmo_disabled = p_enabled;
+ if (!p_enabled && data.gizmo.is_valid())
+ data.gizmo = Ref<Node3DGizmo>();
+}
+
+#endif
+
+void Node3D::set_disable_scale(bool p_enabled) {
+
+ data.disable_scale = p_enabled;
+}
+
+bool Node3D::is_scale_disabled() const {
+ return data.disable_scale;
+}
+
+void Node3D::set_as_toplevel(bool p_enabled) {
+
+ if (data.toplevel == p_enabled)
+ return;
+ if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
+
+ if (p_enabled)
+ set_transform(get_global_transform());
+ else if (data.parent)
+ set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform());
+
+ data.toplevel = p_enabled;
+ data.toplevel_active = p_enabled;
+
+ } else {
+ data.toplevel = p_enabled;
+ }
+}
+
+bool Node3D::is_set_as_toplevel() const {
+
+ return data.toplevel;
+}
+
+Ref<World3D> Node3D::get_world() const {
+
+ ERR_FAIL_COND_V(!is_inside_world(), Ref<World3D>());
+ ERR_FAIL_COND_V(!data.viewport, Ref<World3D>());
+
+ return data.viewport->find_world();
+}
+
+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();
+#endif
+
+ for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
+
+ Node3D *c = E->get();
+ if (!c || !c->data.visible)
+ continue;
+ c->_propagate_visibility_changed();
+ }
+}
+
+void Node3D::show() {
+
+ if (data.visible)
+ return;
+
+ data.visible = true;
+
+ if (!is_inside_tree())
+ return;
+
+ _propagate_visibility_changed();
+}
+
+void Node3D::hide() {
+
+ if (!data.visible)
+ return;
+
+ data.visible = false;
+
+ if (!is_inside_tree())
+ return;
+
+ _propagate_visibility_changed();
+}
+
+bool Node3D::is_visible_in_tree() const {
+
+ const Node3D *s = this;
+
+ while (s) {
+ if (!s->data.visible) {
+ return false;
+ }
+ s = s->data.parent;
+ }
+
+ return true;
+}
+
+void Node3D::set_visible(bool p_visible) {
+
+ if (p_visible)
+ show();
+ else
+ hide();
+}
+
+bool Node3D::is_visible() const {
+
+ return data.visible;
+}
+
+void Node3D::rotate_object_local(const Vector3 &p_axis, float p_angle) {
+ Transform t = get_transform();
+ t.basis.rotate_local(p_axis, p_angle);
+ set_transform(t);
+}
+
+void Node3D::rotate(const Vector3 &p_axis, float p_angle) {
+
+ Transform t = get_transform();
+ t.basis.rotate(p_axis, p_angle);
+ set_transform(t);
+}
+
+void Node3D::rotate_x(float p_angle) {
+
+ Transform t = get_transform();
+ t.basis.rotate(Vector3(1, 0, 0), p_angle);
+ set_transform(t);
+}
+
+void Node3D::rotate_y(float p_angle) {
+
+ Transform t = get_transform();
+ t.basis.rotate(Vector3(0, 1, 0), p_angle);
+ set_transform(t);
+}
+void Node3D::rotate_z(float p_angle) {
+
+ Transform t = get_transform();
+ t.basis.rotate(Vector3(0, 0, 1), p_angle);
+ set_transform(t);
+}
+
+void Node3D::translate(const Vector3 &p_offset) {
+
+ Transform t = get_transform();
+ t.translate(p_offset);
+ set_transform(t);
+}
+
+void Node3D::translate_object_local(const Vector3 &p_offset) {
+ Transform t = get_transform();
+
+ Transform s;
+ s.translate(p_offset);
+ set_transform(t * s);
+}
+
+void Node3D::scale(const Vector3 &p_ratio) {
+
+ Transform t = get_transform();
+ t.basis.scale(p_ratio);
+ set_transform(t);
+}
+
+void Node3D::scale_object_local(const Vector3 &p_scale) {
+ Transform t = get_transform();
+ t.basis.scale_local(p_scale);
+ set_transform(t);
+}
+
+void Node3D::global_rotate(const Vector3 &p_axis, float p_angle) {
+
+ Transform t = get_global_transform();
+ t.basis.rotate(p_axis, p_angle);
+ set_global_transform(t);
+}
+
+void Node3D::global_scale(const Vector3 &p_scale) {
+
+ Transform t = get_global_transform();
+ t.basis.scale(p_scale);
+ set_global_transform(t);
+}
+
+void Node3D::global_translate(const Vector3 &p_offset) {
+ Transform t = get_global_transform();
+ t.origin += p_offset;
+ set_global_transform(t);
+}
+
+void Node3D::orthonormalize() {
+
+ Transform t = get_transform();
+ t.orthonormalize();
+ set_transform(t);
+}
+
+void Node3D::set_identity() {
+
+ set_transform(Transform());
+}
+
+void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
+
+ Vector3 origin(get_global_transform().origin);
+ look_at_from_position(origin, p_target, p_up);
+}
+
+void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
+
+ ERR_FAIL_COND_MSG(p_pos == p_target, "Node origin and target are in the same position, look_at() failed.");
+ ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos) == Vector3(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
+
+ Transform lookat;
+ lookat.origin = p_pos;
+
+ Vector3 original_scale(get_scale());
+ lookat = lookat.looking_at(p_target, p_up);
+ set_global_transform(lookat);
+ set_scale(original_scale);
+}
+
+Vector3 Node3D::to_local(Vector3 p_global) const {
+
+ return get_global_transform().affine_inverse().xform(p_global);
+}
+
+Vector3 Node3D::to_global(Vector3 p_local) const {
+
+ return get_global_transform().xform(p_local);
+}
+
+void Node3D::set_notify_transform(bool p_enable) {
+ data.notify_transform = p_enable;
+}
+
+bool Node3D::is_transform_notification_enabled() const {
+ return data.notify_transform;
+}
+
+void Node3D::set_notify_local_transform(bool p_enable) {
+ data.notify_local_transform = p_enable;
+}
+
+bool Node3D::is_local_transform_notification_enabled() const {
+ return data.notify_local_transform;
+}
+
+void Node3D::force_update_transform() {
+ ERR_FAIL_COND(!is_inside_tree());
+ if (!xform_change.in_list()) {
+ return; //nothing to update
+ }
+ get_tree()->xform_change_list.remove(&xform_change);
+
+ notification(NOTIFICATION_TRANSFORM_CHANGED);
+}
+
+void Node3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_transform", "local"), &Node3D::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform"), &Node3D::get_transform);
+ ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Node3D::set_translation);
+ ClassDB::bind_method(D_METHOD("get_translation"), &Node3D::get_translation);
+ ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Node3D::set_rotation);
+ ClassDB::bind_method(D_METHOD("get_rotation"), &Node3D::get_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Node3D::set_rotation_degrees);
+ ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node3D::get_rotation_degrees);
+ ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node3D::set_scale);
+ ClassDB::bind_method(D_METHOD("get_scale"), &Node3D::get_scale);
+ ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Node3D::set_global_transform);
+ ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform);
+ ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Node3D::get_parent_spatial);
+ ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification);
+ ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Node3D::set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Node3D::is_set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Node3D::set_disable_scale);
+ ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Node3D::is_scale_disabled);
+ ClassDB::bind_method(D_METHOD("get_world"), &Node3D::get_world);
+
+ ClassDB::bind_method(D_METHOD("force_update_transform"), &Node3D::force_update_transform);
+
+ ClassDB::bind_method(D_METHOD("_update_gizmo"), &Node3D::_update_gizmo);
+
+ ClassDB::bind_method(D_METHOD("update_gizmo"), &Node3D::update_gizmo);
+ ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Node3D::set_gizmo);
+ ClassDB::bind_method(D_METHOD("get_gizmo"), &Node3D::get_gizmo);
+
+ ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Node3D::set_visible);
+ ClassDB::bind_method(D_METHOD("is_visible"), &Node3D::is_visible);
+ ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &Node3D::is_visible_in_tree);
+ ClassDB::bind_method(D_METHOD("show"), &Node3D::show);
+ ClassDB::bind_method(D_METHOD("hide"), &Node3D::hide);
+
+ ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &Node3D::set_notify_local_transform);
+ ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &Node3D::is_local_transform_notification_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Node3D::set_notify_transform);
+ ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Node3D::is_transform_notification_enabled);
+
+ ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Node3D::rotate);
+ ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Node3D::global_rotate);
+ ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Node3D::global_scale);
+ ClassDB::bind_method(D_METHOD("global_translate", "offset"), &Node3D::global_translate);
+ ClassDB::bind_method(D_METHOD("rotate_object_local", "axis", "angle"), &Node3D::rotate_object_local);
+ ClassDB::bind_method(D_METHOD("scale_object_local", "scale"), &Node3D::scale_object_local);
+ ClassDB::bind_method(D_METHOD("translate_object_local", "offset"), &Node3D::translate_object_local);
+ ClassDB::bind_method(D_METHOD("rotate_x", "angle"), &Node3D::rotate_x);
+ ClassDB::bind_method(D_METHOD("rotate_y", "angle"), &Node3D::rotate_y);
+ ClassDB::bind_method(D_METHOD("rotate_z", "angle"), &Node3D::rotate_z);
+ ClassDB::bind_method(D_METHOD("translate", "offset"), &Node3D::translate);
+ 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("to_local", "global_point"), &Node3D::to_local);
+ ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global);
+
+ BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
+ BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
+ BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+
+ //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
+ ADD_GROUP("Transform", "");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
+ ADD_GROUP("Matrix", "");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
+ ADD_GROUP("Visibility", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", 0), "set_gizmo", "get_gizmo");
+
+ ADD_SIGNAL(MethodInfo("visibility_changed"));
+}
+
+Node3D::Node3D() :
+ xform_change(this) {
+
+ data.dirty = DIRTY_NONE;
+ data.children_lock = 0;
+
+ data.ignore_notification = false;
+ data.toplevel = false;
+ data.toplevel_active = false;
+ data.scale = Vector3(1, 1, 1);
+ data.viewport = nullptr;
+ data.inside_world = false;
+ data.visible = true;
+ data.disable_scale = false;
+
+#ifdef TOOLS_ENABLED
+ data.gizmo_disabled = false;
+ data.gizmo_dirty = false;
+#endif
+ data.notify_local_transform = false;
+ data.notify_transform = false;
+ data.parent = nullptr;
+ data.C = nullptr;
+}
+
+Node3D::~Node3D() {
+}
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
new file mode 100644
index 0000000000..f97a8a97dc
--- /dev/null
+++ b/scene/3d/node_3d.h
@@ -0,0 +1,207 @@
+/*************************************************************************/
+/* node_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 NODE_3D_H
+#define NODE_3D_H
+
+#include "scene/main/node.h"
+#include "scene/main/scene_tree.h"
+
+class Node3DGizmo : public Reference {
+
+ GDCLASS(Node3DGizmo, Reference);
+
+public:
+ virtual void create() = 0;
+ virtual void transform() = 0;
+ virtual void clear() = 0;
+ virtual void redraw() = 0;
+ virtual void free() = 0;
+
+ Node3DGizmo();
+ virtual ~Node3DGizmo() {}
+};
+
+class Node3D : public Node {
+
+ GDCLASS(Node3D, Node);
+ OBJ_CATEGORY("3D");
+
+ enum TransformDirty {
+ DIRTY_NONE = 0,
+ DIRTY_VECTORS = 1,
+ DIRTY_LOCAL = 2,
+ DIRTY_GLOBAL = 4
+ };
+
+ mutable SelfList<Node> xform_change;
+
+ struct Data {
+
+ mutable Transform global_transform;
+ mutable Transform local_transform;
+ mutable Vector3 rotation;
+ mutable Vector3 scale;
+
+ mutable int dirty;
+
+ Viewport *viewport;
+
+ bool toplevel_active;
+ bool toplevel;
+ bool inside_world;
+
+ int children_lock;
+ Node3D *parent;
+ List<Node3D *> children;
+ List<Node3D *>::Element *C;
+
+ bool ignore_notification;
+ bool notify_local_transform;
+ bool notify_transform;
+
+ bool visible;
+ bool disable_scale;
+
+#ifdef TOOLS_ENABLED
+ Ref<Node3DGizmo> gizmo;
+ bool gizmo_disabled;
+ bool gizmo_dirty;
+#endif
+
+ } data;
+
+ void _update_gizmo();
+ void _notify_dirty();
+ void _propagate_transform_changed(Node3D *p_origin);
+
+ void _propagate_visibility_changed();
+
+protected:
+ _FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }
+
+ _FORCE_INLINE_ void _update_local_transform() const;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ enum {
+
+ NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED,
+ NOTIFICATION_ENTER_WORLD = 41,
+ NOTIFICATION_EXIT_WORLD = 42,
+ NOTIFICATION_VISIBILITY_CHANGED = 43,
+ NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 44,
+ };
+
+ Node3D *get_parent_spatial() const;
+
+ Ref<World3D> get_world() const;
+
+ void set_translation(const Vector3 &p_translation);
+ void set_rotation(const Vector3 &p_euler_rad);
+ void set_rotation_degrees(const Vector3 &p_euler_deg);
+ void set_scale(const Vector3 &p_scale);
+
+ Vector3 get_translation() const;
+ Vector3 get_rotation() const;
+ Vector3 get_rotation_degrees() const;
+ Vector3 get_scale() const;
+
+ void set_transform(const Transform &p_transform);
+ void set_global_transform(const Transform &p_transform);
+
+ Transform get_transform() const;
+ Transform get_global_transform() const;
+
+#ifdef TOOLS_ENABLED
+ virtual Transform get_global_gizmo_transform() const;
+ virtual Transform get_local_gizmo_transform() const;
+#endif
+
+ void set_as_toplevel(bool p_enabled);
+ bool is_set_as_toplevel() const;
+
+ void set_disable_scale(bool p_enabled);
+ bool is_scale_disabled() const;
+
+ void set_disable_gizmo(bool p_enabled);
+ void update_gizmo();
+ void set_gizmo(const Ref<Node3DGizmo> &p_gizmo);
+ Ref<Node3DGizmo> get_gizmo() const;
+
+ _FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; }
+
+ Transform get_relative_transform(const Node *p_parent) const;
+
+ void rotate(const Vector3 &p_axis, float p_angle);
+ void rotate_x(float p_angle);
+ void rotate_y(float p_angle);
+ void rotate_z(float p_angle);
+ void translate(const Vector3 &p_offset);
+ void scale(const Vector3 &p_ratio);
+
+ void rotate_object_local(const Vector3 &p_axis, float p_angle);
+ void scale_object_local(const Vector3 &p_scale);
+ void translate_object_local(const Vector3 &p_offset);
+
+ void global_rotate(const Vector3 &p_axis, float p_angle);
+ 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);
+
+ Vector3 to_local(Vector3 p_global) const;
+ Vector3 to_global(Vector3 p_local) const;
+
+ void set_notify_transform(bool p_enable);
+ bool is_transform_notification_enabled() const;
+
+ void set_notify_local_transform(bool p_enable);
+ bool is_local_transform_notification_enabled() const;
+
+ void orthonormalize();
+ void set_identity();
+
+ void set_visible(bool p_visible);
+ bool is_visible() const;
+ void show();
+ void hide();
+ bool is_visible_in_tree() const;
+
+ void force_update_transform();
+
+ Node3D();
+ ~Node3D();
+};
+
+#endif // NODE_3D_H
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
deleted file mode 100644
index e502b0c037..0000000000
--- a/scene/3d/particles.cpp
+++ /dev/null
@@ -1,441 +0,0 @@
-/*************************************************************************/
-/* particles.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "particles.h"
-
-#include "core/os/os.h"
-#include "scene/resources/particles_material.h"
-
-#include "servers/visual_server.h"
-
-AABB Particles::get_aabb() const {
-
- return AABB();
-}
-Vector<Face3> Particles::get_faces(uint32_t p_usage_flags) const {
-
- return Vector<Face3>();
-}
-
-void Particles::set_emitting(bool p_emitting) {
-
- VS::get_singleton()->particles_set_emitting(particles, p_emitting);
-
- if (p_emitting && one_shot) {
- set_process_internal(true);
- } else if (!p_emitting) {
- set_process_internal(false);
- }
-}
-
-void Particles::set_amount(int p_amount) {
-
- ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
- amount = p_amount;
- VS::get_singleton()->particles_set_amount(particles, amount);
-}
-void Particles::set_lifetime(float p_lifetime) {
-
- ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
- lifetime = p_lifetime;
- VS::get_singleton()->particles_set_lifetime(particles, lifetime);
-}
-
-void Particles::set_one_shot(bool p_one_shot) {
-
- one_shot = p_one_shot;
- VS::get_singleton()->particles_set_one_shot(particles, one_shot);
-
- if (is_emitting()) {
-
- set_process_internal(true);
- if (!one_shot)
- VisualServer::get_singleton()->particles_restart(particles);
- }
-
- if (!one_shot)
- set_process_internal(false);
-}
-
-void Particles::set_pre_process_time(float p_time) {
-
- pre_process_time = p_time;
- VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
-}
-void Particles::set_explosiveness_ratio(float p_ratio) {
-
- explosiveness_ratio = p_ratio;
- VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
-}
-void Particles::set_randomness_ratio(float p_ratio) {
-
- randomness_ratio = p_ratio;
- VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
-}
-void Particles::set_visibility_aabb(const AABB &p_aabb) {
-
- visibility_aabb = p_aabb;
- VS::get_singleton()->particles_set_custom_aabb(particles, visibility_aabb);
- update_gizmo();
- _change_notify("visibility_aabb");
-}
-void Particles::set_use_local_coordinates(bool p_enable) {
-
- local_coords = p_enable;
- VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
-}
-void Particles::set_process_material(const Ref<Material> &p_material) {
-
- process_material = p_material;
- RID material_rid;
- if (process_material.is_valid())
- material_rid = process_material->get_rid();
- VS::get_singleton()->particles_set_process_material(particles, material_rid);
-
- update_configuration_warning();
-}
-
-void Particles::set_speed_scale(float p_scale) {
-
- speed_scale = p_scale;
- VS::get_singleton()->particles_set_speed_scale(particles, p_scale);
-}
-
-bool Particles::is_emitting() const {
-
- return VS::get_singleton()->particles_get_emitting(particles);
-}
-int Particles::get_amount() const {
-
- return amount;
-}
-float Particles::get_lifetime() const {
-
- return lifetime;
-}
-bool Particles::get_one_shot() const {
-
- return one_shot;
-}
-
-float Particles::get_pre_process_time() const {
-
- return pre_process_time;
-}
-float Particles::get_explosiveness_ratio() const {
-
- return explosiveness_ratio;
-}
-float Particles::get_randomness_ratio() const {
-
- return randomness_ratio;
-}
-AABB Particles::get_visibility_aabb() const {
-
- return visibility_aabb;
-}
-bool Particles::get_use_local_coordinates() const {
-
- return local_coords;
-}
-Ref<Material> Particles::get_process_material() const {
-
- return process_material;
-}
-
-float Particles::get_speed_scale() const {
-
- return speed_scale;
-}
-
-void Particles::set_draw_order(DrawOrder p_order) {
-
- draw_order = p_order;
- VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order));
-}
-
-Particles::DrawOrder Particles::get_draw_order() const {
-
- return draw_order;
-}
-
-void Particles::set_draw_passes(int p_count) {
-
- ERR_FAIL_COND(p_count < 1);
- draw_passes.resize(p_count);
- VS::get_singleton()->particles_set_draw_passes(particles, p_count);
- _change_notify();
-}
-int Particles::get_draw_passes() const {
-
- return draw_passes.size();
-}
-
-void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
-
- ERR_FAIL_INDEX(p_pass, draw_passes.size());
-
- draw_passes.write[p_pass] = p_mesh;
-
- RID mesh_rid;
- if (p_mesh.is_valid())
- mesh_rid = p_mesh->get_rid();
-
- VS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
-
- update_configuration_warning();
-}
-
-Ref<Mesh> Particles::get_draw_pass_mesh(int p_pass) const {
-
- ERR_FAIL_INDEX_V(p_pass, draw_passes.size(), Ref<Mesh>());
-
- return draw_passes[p_pass];
-}
-
-void Particles::set_fixed_fps(int p_count) {
- fixed_fps = p_count;
- VS::get_singleton()->particles_set_fixed_fps(particles, p_count);
-}
-
-int Particles::get_fixed_fps() const {
- return fixed_fps;
-}
-
-void Particles::set_fractional_delta(bool p_enable) {
- fractional_delta = p_enable;
- VS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
-}
-
-bool Particles::get_fractional_delta() const {
- return fractional_delta;
-}
-
-String Particles::get_configuration_warning() const {
-
- if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
- }
-
- String warnings;
-
- bool meshes_found = false;
- bool anim_material_found = false;
-
- for (int i = 0; i < draw_passes.size(); i++) {
- if (draw_passes[i].is_valid()) {
- 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()) != NULL;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(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) break;
- }
- }
-
- anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != NULL;
- StandardMaterial3D *spat = Object::cast_to<StandardMaterial3D>(get_material_override().ptr());
- anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
-
- if (!meshes_found) {
- if (warnings != String())
- warnings += "\n";
- warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
- }
-
- 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.");
- } else {
- const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
- if (!anim_material_found && process &&
- (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
- process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String())
- warnings += "\n";
- warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
- }
- }
-
- return warnings;
-}
-
-void Particles::restart() {
-
- VisualServer::get_singleton()->particles_restart(particles);
- VisualServer::get_singleton()->particles_set_emitting(particles, true);
-}
-
-AABB Particles::capture_aabb() const {
-
- return VS::get_singleton()->particles_get_current_aabb(particles);
-}
-
-void Particles::_validate_property(PropertyInfo &property) const {
-
- if (property.name.begins_with("draw_pass_")) {
- int index = property.name.get_slicec('_', 2).to_int() - 1;
- if (index >= draw_passes.size()) {
- property.usage = 0;
- return;
- }
- }
-}
-
-void Particles::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
- if (can_process()) {
- VS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
- } else {
-
- VS::get_singleton()->particles_set_speed_scale(particles, 0);
- }
- }
-
- // Use internal process when emitting and one_shot are 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();
- set_process_internal(false);
- }
- }
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- // make sure particles are updated before rendering occurs if they were active before
- if (is_visible_in_tree() && !VS::get_singleton()->particles_is_inactive(particles)) {
- VS::get_singleton()->particles_request_process(particles);
- }
- }
-}
-
-void Particles::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting);
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount);
- ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime);
- ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Particles::set_one_shot);
- ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time);
- ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio);
- ClassDB::bind_method(D_METHOD("set_visibility_aabb", "aabb"), &Particles::set_visibility_aabb);
- ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles::set_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles::set_fixed_fps);
- ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles::set_fractional_delta);
- ClassDB::bind_method(D_METHOD("set_process_material", "material"), &Particles::set_process_material);
- ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles::set_speed_scale);
-
- ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting);
- ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount);
- ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime);
- ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles::get_one_shot);
- ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time);
- ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio);
- ClassDB::bind_method(D_METHOD("get_visibility_aabb"), &Particles::get_visibility_aabb);
- ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles::get_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles::get_fixed_fps);
- ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles::get_fractional_delta);
- ClassDB::bind_method(D_METHOD("get_process_material"), &Particles::get_process_material);
- ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles::get_speed_scale);
-
- ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles::set_draw_order);
-
- ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles::get_draw_order);
-
- ClassDB::bind_method(D_METHOD("set_draw_passes", "passes"), &Particles::set_draw_passes);
- ClassDB::bind_method(D_METHOD("set_draw_pass_mesh", "pass", "mesh"), &Particles::set_draw_pass_mesh);
-
- ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes);
- ClassDB::bind_method(D_METHOD("get_draw_pass_mesh", "pass"), &Particles::get_draw_pass_mesh);
-
- ClassDB::bind_method(D_METHOD("restart"), &Particles::restart);
- ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
-
- 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_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
- 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, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
- ADD_GROUP("Drawing", "");
- 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_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_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes");
- 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);
- }
-
- BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
- BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
- BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
-
- BIND_CONSTANT(MAX_DRAW_PASSES);
-}
-
-Particles::Particles() {
-
- particles = VS::get_singleton()->particles_create();
- set_base(particles);
- one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
- set_emitting(true);
- set_one_shot(false);
- set_amount(8);
- set_lifetime(1);
- set_fixed_fps(0);
- set_fractional_delta(true);
- set_pre_process_time(0);
- set_explosiveness_ratio(0);
- set_randomness_ratio(0);
- 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);
-}
-
-Particles::~Particles() {
-
- VS::get_singleton()->free(particles);
-}
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
deleted file mode 100644
index 95c6de15ec..0000000000
--- a/scene/3d/particles.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*************************************************************************/
-/* particles.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PARTICLES_H
-#define PARTICLES_H
-
-#include "core/rid.h"
-#include "scene/3d/visual_instance.h"
-#include "scene/resources/material.h"
-
-class Particles : public GeometryInstance {
-private:
- GDCLASS(Particles, GeometryInstance);
-
-public:
- enum DrawOrder {
- DRAW_ORDER_INDEX,
- DRAW_ORDER_LIFETIME,
- DRAW_ORDER_VIEW_DEPTH,
- };
-
- enum {
- MAX_DRAW_PASSES = 4
- };
-
-private:
- RID particles;
-
- bool one_shot;
- int amount;
- float lifetime;
- float pre_process_time;
- float explosiveness_ratio;
- float randomness_ratio;
- float speed_scale;
- AABB visibility_aabb;
- bool local_coords;
- int fixed_fps;
- bool fractional_delta;
-
- Ref<Material> process_material;
-
- DrawOrder draw_order;
-
- Vector<Ref<Mesh> > draw_passes;
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const;
-
-public:
- AABB get_aabb() const;
- Vector<Face3> get_faces(uint32_t p_usage_flags) const;
-
- void set_emitting(bool p_emitting);
- void set_amount(int p_amount);
- 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_visibility_aabb(const AABB &p_aabb);
- void set_use_local_coordinates(bool p_enable);
- void set_process_material(const Ref<Material> &p_material);
- void set_speed_scale(float 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;
- AABB get_visibility_aabb() const;
- bool get_use_local_coordinates() const;
- Ref<Material> get_process_material() const;
- float get_speed_scale() const;
-
- void set_fixed_fps(int p_count);
- int get_fixed_fps() const;
-
- void set_fractional_delta(bool p_enable);
- bool get_fractional_delta() const;
-
- void set_draw_order(DrawOrder p_order);
- DrawOrder get_draw_order() const;
-
- void set_draw_passes(int p_count);
- int get_draw_passes() const;
-
- 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;
-
- void restart();
-
- AABB capture_aabb() const;
- Particles();
- ~Particles();
-};
-
-VARIANT_ENUM_CAST(Particles::DrawOrder)
-
-#endif // PARTICLES_H
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
deleted file mode 100644
index f93485d79f..0000000000
--- a/scene/3d/path.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-/*************************************************************************/
-/* path.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "path.h"
-
-#include "core/engine.h"
-#include "scene/scene_string_names.h"
-
-void Path::_notification(int p_what) {
-}
-
-void Path::_curve_changed() {
-
- if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
- update_gizmo();
- if (is_inside_tree()) {
- emit_signal("curve_changed");
- }
-
- // update the configuration warnings of all children of type PathFollow
- // previously used for PathFollowOriented (now enforced orientation is done in PathFollow)
- if (is_inside_tree()) {
- for (int i = 0; i < get_child_count(); i++) {
- PathFollow *child = Object::cast_to<PathFollow>(get_child(i));
- if (child) {
- child->update_configuration_warning();
- }
- }
- }
-}
-
-void Path::set_curve(const Ref<Curve3D> &p_curve) {
-
- if (curve.is_valid()) {
- curve->disconnect("changed", callable_mp(this, &Path::_curve_changed));
- }
-
- curve = p_curve;
-
- if (curve.is_valid()) {
- curve->connect("changed", callable_mp(this, &Path::_curve_changed));
- }
- _curve_changed();
-}
-
-Ref<Curve3D> Path::get_curve() const {
-
- return curve;
-}
-
-void Path::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Path::set_curve);
- ClassDB::bind_method(D_METHOD("get_curve"), &Path::get_curve);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve");
-
- ADD_SIGNAL(MethodInfo("curve_changed"));
-}
-
-Path::Path() {
-
- set_curve(Ref<Curve3D>(memnew(Curve3D))); //create one by default
-}
-
-//////////////
-
-void PathFollow::_update_transform() {
-
- if (!path)
- return;
-
- Ref<Curve3D> c = path->get_curve();
- if (!c.is_valid())
- return;
-
- if (delta_offset == 0) {
- return;
- }
-
- float bl = c->get_baked_length();
- if (bl == 0.0) {
- return;
- }
- float bi = c->get_bake_interval();
- float o_next = offset + bi;
-
- if (loop) {
- o_next = Math::fposmod(o_next, bl);
- } else if (rotation_mode == ROTATION_ORIENTED && o_next >= bl) {
- o_next = bl;
- }
-
- Vector3 pos = c->interpolate_baked(offset, cubic);
- Transform t = get_transform();
- // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases
- // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used
-
- if (rotation_mode == ROTATION_ORIENTED) {
-
- Vector3 forward = c->interpolate_baked(o_next, cubic) - pos;
-
- if (forward.length_squared() < CMP_EPSILON2)
- forward = Vector3(0, 0, 1);
- else
- forward.normalize();
-
- Vector3 up = c->interpolate_baked_up_vector(offset, true);
-
- if (o_next < offset) {
- Vector3 up1 = c->interpolate_baked_up_vector(o_next, true);
- Vector3 axis = up.cross(up1);
-
- if (axis.length_squared() < CMP_EPSILON2)
- axis = forward;
- else
- axis.normalize();
-
- up.rotate(axis, up.angle_to(up1) * 0.5f);
- }
-
- Vector3 scale = t.basis.get_scale();
- Vector3 sideways = up.cross(forward).normalized();
- up = forward.cross(sideways).normalized();
-
- t.basis.set(sideways, up, forward);
- t.basis.scale_local(scale);
-
- t.origin = pos + sideways * h_offset + up * v_offset;
- } else if (rotation_mode != ROTATION_NONE) {
- // perform parallel transport
- //
- // see C. Dougan, The Parallel Transport Frame, Game Programming Gems 2 for example
- // for a discussion about why not Frenet frame.
-
- t.origin = pos;
-
- Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized();
- Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized();
-
- Vector3 axis = t_prev.cross(t_cur);
- float dot = t_prev.dot(t_cur);
- float angle = Math::acos(CLAMP(dot, -1, 1));
-
- if (likely(!Math::is_zero_approx(angle))) {
- if (rotation_mode == ROTATION_Y) {
- // assuming we're referring to global Y-axis. is this correct?
- axis.x = 0;
- axis.z = 0;
- } else if (rotation_mode == ROTATION_XY) {
- axis.z = 0;
- } else if (rotation_mode == ROTATION_XYZ) {
- // all components are allowed
- }
-
- if (likely(!Math::is_zero_approx(axis.length()))) {
- t.rotate_basis(axis.normalized(), angle);
- }
- }
-
- // do the additional tilting
- float tilt_angle = c->interpolate_baked_tilt(offset);
- Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
-
- if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
- if (rotation_mode == ROTATION_Y) {
- tilt_axis.x = 0;
- tilt_axis.z = 0;
- } else if (rotation_mode == ROTATION_XY) {
- tilt_axis.z = 0;
- } else if (rotation_mode == ROTATION_XYZ) {
- // all components are allowed
- }
-
- if (likely(!Math::is_zero_approx(tilt_axis.length()))) {
- t.rotate_basis(tilt_axis.normalized(), tilt_angle);
- }
- }
-
- t.translate(Vector3(h_offset, v_offset, 0));
- } else {
- t.origin = pos + Vector3(h_offset, v_offset, 0);
- }
-
- set_transform(t);
-}
-
-void PathFollow::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- Node *parent = get_parent();
- if (parent) {
- path = Object::cast_to<Path>(parent);
- if (path) {
- _update_transform();
- }
- }
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- path = NULL;
- } break;
- }
-}
-
-void PathFollow::set_cubic_interpolation(bool p_enable) {
-
- cubic = p_enable;
-}
-
-bool PathFollow::get_cubic_interpolation() const {
-
- return cubic;
-}
-
-void PathFollow::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "offset") {
-
- float max = 10000;
- if (path && path->get_curve().is_valid())
- max = path->get_curve()->get_baked_length();
-
- property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
- }
-}
-
-String PathFollow::get_configuration_warning() const {
-
- if (!is_visible_in_tree() || !is_inside_tree())
- return String();
-
- if (!Object::cast_to<Path>(get_parent())) {
- return TTR("PathFollow only works when set as a child of a Path node.");
- } else {
- Path *path = Object::cast_to<Path>(get_parent());
- if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
- return TTR("PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path's Curve resource.");
- }
- }
-
- return String();
-}
-
-void PathFollow::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow::set_offset);
- ClassDB::bind_method(D_METHOD("get_offset"), &PathFollow::get_offset);
-
- ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow::set_h_offset);
- ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow::get_h_offset);
-
- ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow::set_v_offset);
- ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow::get_v_offset);
-
- ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow::set_unit_offset);
- ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow::get_unit_offset);
-
- ClassDB::bind_method(D_METHOD("set_rotation_mode", "rotation_mode"), &PathFollow::set_rotation_mode);
- ClassDB::bind_method(D_METHOD("get_rotation_mode"), &PathFollow::get_rotation_mode);
-
- ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow::set_cubic_interpolation);
- ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow::get_cubic_interpolation);
-
- ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop);
- ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
-
- BIND_ENUM_CONSTANT(ROTATION_NONE);
- BIND_ENUM_CONSTANT(ROTATION_Y);
- BIND_ENUM_CONSTANT(ROTATION_XY);
- BIND_ENUM_CONSTANT(ROTATION_XYZ);
- BIND_ENUM_CONSTANT(ROTATION_ORIENTED);
-}
-
-void PathFollow::set_offset(float p_offset) {
- delta_offset = p_offset - offset;
- offset = p_offset;
-
- if (path) {
- if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
- float path_length = path->get_curve()->get_baked_length();
-
- if (loop) {
- while (offset > path_length)
- offset -= path_length;
-
- while (offset < 0)
- offset += path_length;
-
- } else {
- offset = CLAMP(offset, 0, path_length);
- }
- }
-
- _update_transform();
- }
- _change_notify("offset");
- _change_notify("unit_offset");
-}
-
-void PathFollow::set_h_offset(float p_h_offset) {
-
- h_offset = p_h_offset;
- if (path)
- _update_transform();
-}
-
-float PathFollow::get_h_offset() const {
-
- return h_offset;
-}
-
-void PathFollow::set_v_offset(float p_v_offset) {
-
- v_offset = p_v_offset;
- if (path)
- _update_transform();
-}
-
-float PathFollow::get_v_offset() const {
-
- return v_offset;
-}
-
-float PathFollow::get_offset() const {
-
- return offset;
-}
-
-void PathFollow::set_unit_offset(float 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 PathFollow::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
- return 0;
-}
-
-void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) {
-
- rotation_mode = p_rotation_mode;
-
- update_configuration_warning();
- _update_transform();
-}
-
-PathFollow::RotationMode PathFollow::get_rotation_mode() const {
-
- return rotation_mode;
-}
-
-void PathFollow::set_loop(bool p_loop) {
-
- loop = p_loop;
-}
-
-bool PathFollow::has_loop() const {
-
- return loop;
-}
-
-PathFollow::PathFollow() {
-
- offset = 0;
- delta_offset = 0;
- h_offset = 0;
- v_offset = 0;
- path = NULL;
- rotation_mode = ROTATION_XYZ;
- cubic = true;
- loop = true;
-}
diff --git a/scene/3d/path.h b/scene/3d/path.h
deleted file mode 100644
index 497913b925..0000000000
--- a/scene/3d/path.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*************************************************************************/
-/* path.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PATH_H
-#define PATH_H
-
-#include "scene/3d/spatial.h"
-#include "scene/resources/curve.h"
-
-class Path : public Spatial {
-
- GDCLASS(Path, Spatial);
-
- Ref<Curve3D> curve;
-
- void _curve_changed();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_curve(const Ref<Curve3D> &p_curve);
- Ref<Curve3D> get_curve() const;
-
- Path();
-};
-
-class PathFollow : public Spatial {
-
- GDCLASS(PathFollow, Spatial);
-
-public:
- enum RotationMode {
-
- ROTATION_NONE,
- ROTATION_Y,
- ROTATION_XY,
- ROTATION_XYZ,
- ROTATION_ORIENTED
- };
-
-private:
- Path *path;
- real_t delta_offset; // change in offset since last _update_transform
- real_t offset;
- real_t h_offset;
- real_t v_offset;
- bool cubic;
- bool loop;
- RotationMode rotation_mode;
-
- void _update_transform();
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const;
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_offset(float p_offset);
- float get_offset() const;
-
- void set_h_offset(float p_h_offset);
- float get_h_offset() const;
-
- void set_v_offset(float p_v_offset);
- float get_v_offset() const;
-
- void set_unit_offset(float p_unit_offset);
- float get_unit_offset() const;
-
- void set_loop(bool p_loop);
- bool has_loop() const;
-
- void set_rotation_mode(RotationMode p_rotation_mode);
- RotationMode get_rotation_mode() const;
-
- void set_cubic_interpolation(bool p_enable);
- bool get_cubic_interpolation() const;
-
- String get_configuration_warning() const;
-
- PathFollow();
-};
-
-VARIANT_ENUM_CAST(PathFollow::RotationMode);
-
-#endif // PATH_H
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
new file mode 100644
index 0000000000..4a425d1e0e
--- /dev/null
+++ b/scene/3d/path_3d.cpp
@@ -0,0 +1,414 @@
+/*************************************************************************/
+/* path_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "path_3d.h"
+
+#include "core/engine.h"
+#include "scene/scene_string_names.h"
+
+void Path3D::_notification(int p_what) {
+}
+
+void Path3D::_curve_changed() {
+
+ if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
+ update_gizmo();
+ if (is_inside_tree()) {
+ emit_signal("curve_changed");
+ }
+
+ // update the configuration warnings of all children of type PathFollow
+ // previously used for PathFollowOriented (now enforced orientation is done in PathFollow)
+ if (is_inside_tree()) {
+ for (int i = 0; i < get_child_count(); i++) {
+ PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i));
+ if (child) {
+ child->update_configuration_warning();
+ }
+ }
+ }
+}
+
+void Path3D::set_curve(const Ref<Curve3D> &p_curve) {
+
+ if (curve.is_valid()) {
+ curve->disconnect("changed", callable_mp(this, &Path3D::_curve_changed));
+ }
+
+ curve = p_curve;
+
+ if (curve.is_valid()) {
+ curve->connect("changed", callable_mp(this, &Path3D::_curve_changed));
+ }
+ _curve_changed();
+}
+
+Ref<Curve3D> Path3D::get_curve() const {
+
+ return curve;
+}
+
+void Path3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Path3D::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve"), &Path3D::get_curve);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve");
+
+ ADD_SIGNAL(MethodInfo("curve_changed"));
+}
+
+Path3D::Path3D() {
+
+ set_curve(Ref<Curve3D>(memnew(Curve3D))); //create one by default
+}
+
+//////////////
+
+void PathFollow3D::_update_transform() {
+
+ if (!path)
+ return;
+
+ Ref<Curve3D> c = path->get_curve();
+ if (!c.is_valid())
+ return;
+
+ if (delta_offset == 0) {
+ return;
+ }
+
+ float bl = c->get_baked_length();
+ if (bl == 0.0) {
+ return;
+ }
+ float bi = c->get_bake_interval();
+ float o_next = offset + bi;
+
+ if (loop) {
+ o_next = Math::fposmod(o_next, bl);
+ } else if (rotation_mode == ROTATION_ORIENTED && o_next >= bl) {
+ o_next = bl;
+ }
+
+ Vector3 pos = c->interpolate_baked(offset, cubic);
+ Transform t = get_transform();
+ // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases
+ // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used
+
+ if (rotation_mode == ROTATION_ORIENTED) {
+
+ Vector3 forward = c->interpolate_baked(o_next, cubic) - pos;
+
+ if (forward.length_squared() < CMP_EPSILON2)
+ forward = Vector3(0, 0, 1);
+ else
+ forward.normalize();
+
+ Vector3 up = c->interpolate_baked_up_vector(offset, true);
+
+ if (o_next < offset) {
+ Vector3 up1 = c->interpolate_baked_up_vector(o_next, true);
+ Vector3 axis = up.cross(up1);
+
+ if (axis.length_squared() < CMP_EPSILON2)
+ axis = forward;
+ else
+ axis.normalize();
+
+ up.rotate(axis, up.angle_to(up1) * 0.5f);
+ }
+
+ Vector3 scale = t.basis.get_scale();
+ Vector3 sideways = up.cross(forward).normalized();
+ up = forward.cross(sideways).normalized();
+
+ t.basis.set(sideways, up, forward);
+ t.basis.scale_local(scale);
+
+ t.origin = pos + sideways * h_offset + up * v_offset;
+ } else if (rotation_mode != ROTATION_NONE) {
+ // perform parallel transport
+ //
+ // see C. Dougan, The Parallel Transport Frame, Game Programming Gems 2 for example
+ // for a discussion about why not Frenet frame.
+
+ t.origin = pos;
+
+ Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized();
+ Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized();
+
+ Vector3 axis = t_prev.cross(t_cur);
+ float dot = t_prev.dot(t_cur);
+ float angle = Math::acos(CLAMP(dot, -1, 1));
+
+ if (likely(!Math::is_zero_approx(angle))) {
+ if (rotation_mode == ROTATION_Y) {
+ // assuming we're referring to global Y-axis. is this correct?
+ axis.x = 0;
+ axis.z = 0;
+ } else if (rotation_mode == ROTATION_XY) {
+ axis.z = 0;
+ } else if (rotation_mode == ROTATION_XYZ) {
+ // all components are allowed
+ }
+
+ if (likely(!Math::is_zero_approx(axis.length()))) {
+ t.rotate_basis(axis.normalized(), angle);
+ }
+ }
+
+ // do the additional tilting
+ float tilt_angle = c->interpolate_baked_tilt(offset);
+ Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
+
+ if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
+ if (rotation_mode == ROTATION_Y) {
+ tilt_axis.x = 0;
+ tilt_axis.z = 0;
+ } else if (rotation_mode == ROTATION_XY) {
+ tilt_axis.z = 0;
+ } else if (rotation_mode == ROTATION_XYZ) {
+ // all components are allowed
+ }
+
+ if (likely(!Math::is_zero_approx(tilt_axis.length()))) {
+ t.rotate_basis(tilt_axis.normalized(), tilt_angle);
+ }
+ }
+
+ t.translate(Vector3(h_offset, v_offset, 0));
+ } else {
+ t.origin = pos + Vector3(h_offset, v_offset, 0);
+ }
+
+ set_transform(t);
+}
+
+void PathFollow3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ Node *parent = get_parent();
+ if (parent) {
+ path = Object::cast_to<Path3D>(parent);
+ if (path) {
+ _update_transform();
+ }
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ path = nullptr;
+ } break;
+ }
+}
+
+void PathFollow3D::set_cubic_interpolation(bool p_enable) {
+
+ cubic = p_enable;
+}
+
+bool PathFollow3D::get_cubic_interpolation() const {
+
+ return cubic;
+}
+
+void PathFollow3D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "offset") {
+
+ float max = 10000;
+ if (path && path->get_curve().is_valid())
+ max = path->get_curve()->get_baked_length();
+
+ property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ }
+}
+
+String PathFollow3D::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!Object::cast_to<Path3D>(get_parent())) {
+ return 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) {
+ return TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
+ }
+ }
+
+ return String();
+}
+
+void PathFollow3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow3D::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &PathFollow3D::get_offset);
+
+ ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow3D::set_h_offset);
+ ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow3D::get_h_offset);
+
+ ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow3D::set_v_offset);
+ ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow3D::get_v_offset);
+
+ ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow3D::set_unit_offset);
+ ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow3D::get_unit_offset);
+
+ ClassDB::bind_method(D_METHOD("set_rotation_mode", "rotation_mode"), &PathFollow3D::set_rotation_mode);
+ ClassDB::bind_method(D_METHOD("get_rotation_mode"), &PathFollow3D::get_rotation_mode);
+
+ ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow3D::set_cubic_interpolation);
+ ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow3D::get_cubic_interpolation);
+
+ ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+
+ BIND_ENUM_CONSTANT(ROTATION_NONE);
+ BIND_ENUM_CONSTANT(ROTATION_Y);
+ BIND_ENUM_CONSTANT(ROTATION_XY);
+ BIND_ENUM_CONSTANT(ROTATION_XYZ);
+ BIND_ENUM_CONSTANT(ROTATION_ORIENTED);
+}
+
+void PathFollow3D::set_offset(float p_offset) {
+ delta_offset = p_offset - offset;
+ offset = p_offset;
+
+ if (path) {
+ if (path->get_curve().is_valid()) {
+ float path_length = path->get_curve()->get_baked_length();
+
+ if (loop) {
+ offset = Math::fposmod(offset, path_length);
+ if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) {
+ offset = path_length;
+ }
+ } else {
+ offset = CLAMP(offset, 0, path_length);
+ }
+ }
+
+ _update_transform();
+ }
+ _change_notify("offset");
+ _change_notify("unit_offset");
+}
+
+void PathFollow3D::set_h_offset(float p_h_offset) {
+
+ h_offset = p_h_offset;
+ if (path)
+ _update_transform();
+}
+
+float PathFollow3D::get_h_offset() const {
+
+ return h_offset;
+}
+
+void PathFollow3D::set_v_offset(float p_v_offset) {
+
+ v_offset = p_v_offset;
+ if (path)
+ _update_transform();
+}
+
+float PathFollow3D::get_v_offset() const {
+
+ return v_offset;
+}
+
+float PathFollow3D::get_offset() const {
+
+ return offset;
+}
+
+void PathFollow3D::set_unit_offset(float 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 PathFollow3D::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
+ return 0;
+}
+
+void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) {
+
+ rotation_mode = p_rotation_mode;
+
+ update_configuration_warning();
+ _update_transform();
+}
+
+PathFollow3D::RotationMode PathFollow3D::get_rotation_mode() const {
+
+ return rotation_mode;
+}
+
+void PathFollow3D::set_loop(bool p_loop) {
+
+ loop = p_loop;
+}
+
+bool PathFollow3D::has_loop() const {
+
+ return loop;
+}
+
+PathFollow3D::PathFollow3D() {
+
+ offset = 0;
+ delta_offset = 0;
+ h_offset = 0;
+ v_offset = 0;
+ path = nullptr;
+ rotation_mode = ROTATION_XYZ;
+ cubic = true;
+ loop = true;
+}
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
new file mode 100644
index 0000000000..6f0db8c5c2
--- /dev/null
+++ b/scene/3d/path_3d.h
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* path_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PATH_H
+#define PATH_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/resources/curve.h"
+
+class Path3D : public Node3D {
+
+ GDCLASS(Path3D, Node3D);
+
+ Ref<Curve3D> curve;
+
+ void _curve_changed();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_curve(const Ref<Curve3D> &p_curve);
+ Ref<Curve3D> get_curve() const;
+
+ Path3D();
+};
+
+class PathFollow3D : public Node3D {
+
+ GDCLASS(PathFollow3D, Node3D);
+
+public:
+ enum RotationMode {
+
+ ROTATION_NONE,
+ ROTATION_Y,
+ ROTATION_XY,
+ ROTATION_XYZ,
+ ROTATION_ORIENTED
+ };
+
+private:
+ Path3D *path;
+ real_t delta_offset; // change in offset since last _update_transform
+ real_t offset;
+ real_t h_offset;
+ real_t v_offset;
+ bool cubic;
+ bool loop;
+ RotationMode rotation_mode;
+
+ void _update_transform();
+
+protected:
+ virtual void _validate_property(PropertyInfo &property) const;
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_offset(float p_offset);
+ float get_offset() const;
+
+ void set_h_offset(float p_h_offset);
+ float get_h_offset() const;
+
+ void set_v_offset(float p_v_offset);
+ float get_v_offset() const;
+
+ void set_unit_offset(float p_unit_offset);
+ float get_unit_offset() const;
+
+ void set_loop(bool p_loop);
+ bool has_loop() const;
+
+ void set_rotation_mode(RotationMode p_rotation_mode);
+ RotationMode get_rotation_mode() const;
+
+ void set_cubic_interpolation(bool p_enable);
+ bool get_cubic_interpolation() const;
+
+ String get_configuration_warning() const;
+
+ PathFollow3D();
+};
+
+VARIANT_ENUM_CAST(PathFollow3D::RotationMode);
+
+#endif // PATH_H
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
deleted file mode 100644
index 2f8dc31cb6..0000000000
--- a/scene/3d/physics_body.cpp
+++ /dev/null
@@ -1,2596 +0,0 @@
-/*************************************************************************/
-/* physics_body.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_body.h"
-
-#include "core/core_string_names.h"
-#include "core/engine.h"
-#include "core/list.h"
-#include "core/method_bind_ext.gen.inc"
-#include "core/object.h"
-#include "core/rid.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/scene_string_names.h"
-#include "servers/navigation_server.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/plugins/spatial_editor_plugin.h"
-#endif
-
-Vector3 PhysicsBody::get_linear_velocity() const {
-
- return Vector3();
-}
-Vector3 PhysicsBody::get_angular_velocity() const {
-
- return Vector3();
-}
-
-float PhysicsBody::get_inverse_mass() const {
-
- return 0;
-}
-
-void PhysicsBody::set_collision_layer(uint32_t p_layer) {
-
- collision_layer = p_layer;
- PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t PhysicsBody::get_collision_layer() const {
-
- return collision_layer;
-}
-
-void PhysicsBody::set_collision_mask(uint32_t p_mask) {
-
- collision_mask = p_mask;
- PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t PhysicsBody::get_collision_mask() const {
-
- return collision_mask;
-}
-
-void PhysicsBody::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 PhysicsBody::get_collision_mask_bit(int p_bit) const {
-
- return get_collision_mask() & (1 << p_bit);
-}
-
-void PhysicsBody::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 PhysicsBody::get_collision_layer_bit(int p_bit) const {
-
- return get_collision_layer() & (1 << p_bit);
-}
-
-Array PhysicsBody::get_collision_exceptions() {
- List<RID> exceptions;
- PhysicsServer::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
- Array ret;
- for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
- RID body = E->get();
- ObjectID instance_id = PhysicsServer::get_singleton()->body_get_object_instance_id(body);
- Object *obj = ObjectDB::get_instance(instance_id);
- PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(obj);
- ret.append(physics_body);
- }
- return ret;
-}
-
-void PhysicsBody::add_collision_exception_with(Node *p_node) {
-
- ERR_FAIL_NULL(p_node);
- CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject.");
- PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid());
-}
-
-void PhysicsBody::remove_collision_exception_with(Node *p_node) {
-
- ERR_FAIL_NULL(p_node);
- CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject.");
- PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
-}
-
-void PhysicsBody::_set_layers(uint32_t p_mask) {
- set_collision_layer(p_mask);
- set_collision_mask(p_mask);
-}
-
-uint32_t PhysicsBody::_get_layers() const {
-
- return get_collision_layer();
-}
-
-void PhysicsBody::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody::get_collision_layer_bit);
-
- ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody::_set_layers);
- ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody::_get_layers);
-
- 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");
-}
-
-PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) :
- CollisionObject(PhysicsServer::get_singleton()->body_create(p_mode), false) {
-
- collision_layer = 1;
- collision_mask = 1;
-}
-
-void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
- if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody::_reload_physics_characteristics));
- }
- }
-
- physics_material_override = p_physics_material_override;
-
- if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody::_reload_physics_characteristics));
- }
- _reload_physics_characteristics();
-}
-
-Ref<PhysicsMaterial> StaticBody::get_physics_material_override() const {
- return physics_material_override;
-}
-
-void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) {
-
- constant_linear_velocity = p_vel;
- PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
-}
-
-void StaticBody::set_constant_angular_velocity(const Vector3 &p_vel) {
-
- constant_angular_velocity = p_vel;
- PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
-}
-
-Vector3 StaticBody::get_constant_linear_velocity() const {
-
- return constant_linear_velocity;
-}
-Vector3 StaticBody::get_constant_angular_velocity() const {
-
- return constant_angular_velocity;
-}
-
-void StaticBody::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody::set_constant_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody::set_constant_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody::get_constant_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody::get_constant_angular_velocity);
-
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override);
-
- ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody::get_collision_exceptions);
- ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with);
- ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
-}
-
-StaticBody::StaticBody() :
- PhysicsBody(PhysicsServer::BODY_MODE_STATIC) {
-}
-
-StaticBody::~StaticBody() {}
-
-void StaticBody::_reload_physics_characteristics() {
- if (physics_material_override.is_null()) {
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
- } else {
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
- }
-}
-
-void RigidBody::_body_enter_tree(ObjectID p_id) {
-
- Object *obj = ObjectDB::get_instance(p_id);
- Node *node = Object::cast_to<Node>(obj);
- ERR_FAIL_COND(!node);
-
- ERR_FAIL_COND(!contact_monitor);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
- ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_tree);
-
- E->get().in_tree = true;
-
- contact_monitor->locked = true;
-
- emit_signal(SceneStringNames::get_singleton()->body_entered, node);
-
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
- }
-
- contact_monitor->locked = false;
-}
-
-void RigidBody::_body_exit_tree(ObjectID p_id) {
-
- Object *obj = ObjectDB::get_instance(p_id);
- Node *node = Object::cast_to<Node>(obj);
- ERR_FAIL_COND(!node);
- ERR_FAIL_COND(!contact_monitor);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
- ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_tree);
- E->get().in_tree = false;
-
- contact_monitor->locked = true;
-
- emit_signal(SceneStringNames::get_singleton()->body_exited, node);
-
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
- }
-
- contact_monitor->locked = false;
-}
-
-void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape) {
-
- bool body_in = p_status == 1;
- ObjectID objid = p_instance;
-
- Object *obj = ObjectDB::get_instance(objid);
- Node *node = Object::cast_to<Node>(obj);
-
- ERR_FAIL_COND(!contact_monitor);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
-
- ERR_FAIL_COND(!body_in && !E);
-
- if (body_in) {
- if (!E) {
-
- E = contact_monitor->body_map.insert(objid, BodyState());
- //E->get().rc=0;
- E->get().in_tree = node && node->is_inside_tree();
- if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody::_body_enter_tree), make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody::_body_exit_tree), make_binds(objid));
- if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_entered, node);
- }
- }
- }
- //E->get().rc++;
- if (node)
- E->get().shapes.insert(ShapePair(p_body_shape, p_local_shape));
-
- if (E->get().in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_local_shape);
- }
-
- } else {
-
- //E->get().rc--;
-
- if (node)
- E->get().shapes.erase(ShapePair(p_body_shape, p_local_shape));
-
- bool in_tree = E->get().in_tree;
-
- if (E->get().shapes.empty()) {
-
- if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody::_body_exit_tree));
- if (in_tree)
- emit_signal(SceneStringNames::get_singleton()->body_exited, node);
- }
-
- contact_monitor->body_map.erase(E);
- }
- if (node && in_tree) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_local_shape);
- }
- }
-}
-
-struct _RigidBodyInOut {
-
- ObjectID id;
- int shape;
- int local_shape;
-};
-
-void RigidBody::_direct_state_changed(Object *p_state) {
-
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState>(p_state);
-#else
- state = (PhysicsDirectBodyState *)p_state; //trust it
-#endif
-
- set_ignore_transform_notification(true);
- set_global_transform(state->get_transform());
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
- if (sleeping != state->is_sleeping()) {
- sleeping = state->is_sleeping();
- emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
- }
- if (get_script_instance())
- get_script_instance()->call("_integrate_forces", state);
- set_ignore_transform_notification(false);
-
- if (contact_monitor) {
-
- contact_monitor->locked = true;
-
- //untag all
- int rc = 0;
- for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
-
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- E->get().shapes[i].tagged = false;
- rc++;
- }
- }
-
- _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(state->get_contact_count() * sizeof(_RigidBodyInOut));
- int toadd_count = 0; //state->get_contact_count();
- RigidBody_RemoveAction *toremove = (RigidBody_RemoveAction *)alloca(rc * sizeof(RigidBody_RemoveAction));
- int toremove_count = 0;
-
- //put the ones to add
-
- for (int i = 0; i < state->get_contact_count(); i++) {
-
- ObjectID obj = state->get_contact_collider_id(i);
- int local_shape = state->get_contact_local_shape(i);
- int shape = state->get_contact_collider_shape(i);
-
- //bool found=false;
-
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
- if (!E) {
- toadd[toadd_count].local_shape = local_shape;
- toadd[toadd_count].id = obj;
- toadd[toadd_count].shape = shape;
- toadd_count++;
- continue;
- }
-
- ShapePair sp(shape, local_shape);
- int idx = E->get().shapes.find(sp);
- if (idx == -1) {
-
- toadd[toadd_count].local_shape = local_shape;
- toadd[toadd_count].id = obj;
- toadd[toadd_count].shape = shape;
- toadd_count++;
- continue;
- }
-
- E->get().shapes[idx].tagged = true;
- }
-
- //put the ones to remove
-
- for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
-
- for (int i = 0; i < E->get().shapes.size(); i++) {
-
- if (!E->get().shapes[i].tagged) {
-
- toremove[toremove_count].body_id = E->key();
- toremove[toremove_count].pair = E->get().shapes[i];
- toremove_count++;
- }
- }
- }
-
- //process remotions
-
- 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
-
- for (int i = 0; i < toadd_count; i++) {
-
- _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
- }
-
- contact_monitor->locked = false;
- }
-
- state = NULL;
-}
-
-void RigidBody::_notification(int p_what) {
-
-#ifdef TOOLS_ENABLED
- if (p_what == NOTIFICATION_ENTER_TREE) {
- if (Engine::get_singleton()->is_editor_hint()) {
- set_notify_local_transform(true); //used for warnings and only in editor
- }
- }
-
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
- }
- }
-
-#endif
-}
-
-void RigidBody::set_mode(Mode p_mode) {
-
- mode = p_mode;
- switch (p_mode) {
-
- case MODE_RIGID: {
-
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_RIGID);
- } break;
- case MODE_STATIC: {
-
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC);
-
- } break;
- case MODE_CHARACTER: {
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_CHARACTER);
-
- } break;
- case MODE_KINEMATIC: {
-
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_KINEMATIC);
- } break;
- }
- update_configuration_warning();
-}
-
-RigidBody::Mode RigidBody::get_mode() const {
-
- return mode;
-}
-
-void RigidBody::set_mass(real_t p_mass) {
-
- ERR_FAIL_COND(p_mass <= 0);
- mass = p_mass;
- _change_notify("mass");
- _change_notify("weight");
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_MASS, mass);
-}
-real_t RigidBody::get_mass() const {
-
- return mass;
-}
-
-void RigidBody::set_weight(real_t p_weight) {
-
- set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
-}
-real_t RigidBody::get_weight() const {
-
- return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
-}
-
-void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
- if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody::_reload_physics_characteristics));
- }
- }
-
- physics_material_override = p_physics_material_override;
-
- if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody::_reload_physics_characteristics));
- }
- _reload_physics_characteristics();
-}
-
-Ref<PhysicsMaterial> RigidBody::get_physics_material_override() const {
- return physics_material_override;
-}
-
-void RigidBody::set_gravity_scale(real_t p_gravity_scale) {
-
- gravity_scale = p_gravity_scale;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
-}
-real_t RigidBody::get_gravity_scale() const {
-
- return gravity_scale;
-}
-
-void RigidBody::set_linear_damp(real_t p_linear_damp) {
-
- ERR_FAIL_COND(p_linear_damp < -1);
- linear_damp = p_linear_damp;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_LINEAR_DAMP, linear_damp);
-}
-real_t RigidBody::get_linear_damp() const {
-
- return linear_damp;
-}
-
-void RigidBody::set_angular_damp(real_t p_angular_damp) {
-
- ERR_FAIL_COND(p_angular_damp < -1);
- angular_damp = p_angular_damp;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_ANGULAR_DAMP, angular_damp);
-}
-real_t RigidBody::get_angular_damp() const {
-
- return angular_damp;
-}
-
-void RigidBody::set_axis_velocity(const Vector3 &p_axis) {
-
- Vector3 v = state ? state->get_linear_velocity() : linear_velocity;
- Vector3 axis = p_axis.normalized();
- v -= axis * axis.dot(v);
- v += p_axis;
- if (state) {
- set_linear_velocity(v);
- } else {
- PhysicsServer::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
- linear_velocity = v;
- }
-}
-
-void RigidBody::set_linear_velocity(const Vector3 &p_velocity) {
-
- linear_velocity = p_velocity;
- if (state)
- state->set_linear_velocity(linear_velocity);
- else
- PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
-}
-
-Vector3 RigidBody::get_linear_velocity() const {
-
- return linear_velocity;
-}
-
-void RigidBody::set_angular_velocity(const Vector3 &p_velocity) {
-
- angular_velocity = p_velocity;
- if (state)
- state->set_angular_velocity(angular_velocity);
- else
- PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
-}
-Vector3 RigidBody::get_angular_velocity() const {
-
- return angular_velocity;
-}
-
-void RigidBody::set_use_custom_integrator(bool p_enable) {
-
- if (custom_integrator == p_enable)
- return;
-
- custom_integrator = p_enable;
- PhysicsServer::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
-}
-bool RigidBody::is_using_custom_integrator() {
-
- return custom_integrator;
-}
-
-void RigidBody::set_sleeping(bool p_sleeping) {
-
- sleeping = p_sleeping;
- PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::BODY_STATE_SLEEPING, sleeping);
-}
-
-void RigidBody::set_can_sleep(bool p_active) {
-
- can_sleep = p_active;
- PhysicsServer::get_singleton()->body_set_state(get_rid(), PhysicsServer::BODY_STATE_CAN_SLEEP, p_active);
-}
-
-bool RigidBody::is_able_to_sleep() const {
-
- return can_sleep;
-}
-
-bool RigidBody::is_sleeping() const {
-
- return sleeping;
-}
-
-void RigidBody::set_max_contacts_reported(int p_amount) {
-
- max_contacts_reported = p_amount;
- PhysicsServer::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
-}
-
-int RigidBody::get_max_contacts_reported() const {
-
- return max_contacts_reported;
-}
-
-void RigidBody::add_central_force(const Vector3 &p_force) {
- PhysicsServer::get_singleton()->body_add_central_force(get_rid(), p_force);
-}
-
-void RigidBody::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
- PhysicsServer::get_singleton()->body_add_force(get_rid(), p_force, p_pos);
-}
-
-void RigidBody::add_torque(const Vector3 &p_torque) {
- PhysicsServer::get_singleton()->body_add_torque(get_rid(), p_torque);
-}
-
-void RigidBody::apply_central_impulse(const Vector3 &p_impulse) {
- PhysicsServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
-}
-
-void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
-
- PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
-}
-
-void RigidBody::apply_torque_impulse(const Vector3 &p_impulse) {
- PhysicsServer::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse);
-}
-
-void RigidBody::set_use_continuous_collision_detection(bool p_enable) {
-
- ccd = p_enable;
- PhysicsServer::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable);
-}
-
-bool RigidBody::is_using_continuous_collision_detection() const {
-
- return ccd;
-}
-
-void RigidBody::set_contact_monitor(bool p_enabled) {
-
- if (p_enabled == is_contact_monitor_enabled())
- return;
-
- if (!p_enabled) {
-
- ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead.");
-
- for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
-
- //clean up mess
- Object *obj = ObjectDB::get_instance(E->key());
- Node *node = Object::cast_to<Node>(obj);
-
- if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody::_body_exit_tree));
- }
- }
-
- memdelete(contact_monitor);
- contact_monitor = NULL;
- } else {
-
- contact_monitor = memnew(ContactMonitor);
- contact_monitor->locked = false;
- }
-}
-
-bool RigidBody::is_contact_monitor_enabled() const {
-
- return contact_monitor != NULL;
-}
-
-void RigidBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) {
- PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
-}
-
-bool RigidBody::get_axis_lock(PhysicsServer::BodyAxis p_axis) const {
- return PhysicsServer::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
-}
-
-Array RigidBody::get_colliding_bodies() const {
-
- ERR_FAIL_COND_V(!contact_monitor, Array());
-
- Array ret;
- ret.resize(contact_monitor->body_map.size());
- int idx = 0;
- for (const Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
- Object *obj = ObjectDB::get_instance(E->key());
- if (!obj) {
- ret.resize(ret.size() - 1); //ops
- } else {
- ret[idx++] = obj;
- }
- }
-
- return ret;
-}
-
-String RigidBody::get_configuration_warning() const {
-
- Transform t = get_transform();
-
- String warning = CollisionObject::get_configuration_warning();
-
- 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 != String()) {
- warning += "\n\n";
- }
- warning += TTR("Size changes to RigidBody (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
- }
-
- return warning;
-}
-
-void RigidBody::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidBody::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &RigidBody::get_mode);
-
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody::get_mass);
-
- ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody::set_weight);
- ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody::get_weight);
-
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override);
-
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity);
-
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody::get_angular_velocity);
-
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody::get_gravity_scale);
-
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody::get_linear_damp);
-
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody::get_angular_damp);
-
- ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody::set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody::get_max_contacts_reported);
-
- ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody::set_use_custom_integrator);
- ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody::is_using_custom_integrator);
-
- ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody::set_contact_monitor);
- ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody::is_contact_monitor_enabled);
-
- ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody::set_use_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody::is_using_continuous_collision_detection);
-
- ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity);
-
- ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody::add_central_force);
- ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody::add_force);
- ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody::add_torque);
-
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody::apply_impulse);
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody::apply_torque_impulse);
-
- ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody::set_sleeping);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody::is_sleeping);
-
- ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody::set_can_sleep);
- ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody::is_able_to_sleep);
-
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody::_direct_state_changed);
-
- ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody::set_axis_lock);
- ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody::get_axis_lock);
-
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody::get_colliding_bodies);
-
- BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState")));
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
- ADD_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z);
- ADD_GROUP("Linear", "linear_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
- ADD_GROUP("Angular", "angular_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
-
- 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("sleeping_state_changed"));
-
- BIND_ENUM_CONSTANT(MODE_RIGID);
- BIND_ENUM_CONSTANT(MODE_STATIC);
- BIND_ENUM_CONSTANT(MODE_CHARACTER);
- BIND_ENUM_CONSTANT(MODE_KINEMATIC);
-}
-
-RigidBody::RigidBody() :
- PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
-
- mode = MODE_RIGID;
-
- mass = 1;
- max_contacts_reported = 0;
- state = NULL;
-
- gravity_scale = 1;
- linear_damp = -1;
- angular_damp = -1;
-
- //angular_velocity=0;
- sleeping = false;
- ccd = false;
-
- custom_integrator = false;
- contact_monitor = NULL;
- can_sleep = true;
-
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
-}
-
-RigidBody::~RigidBody() {
-
- if (contact_monitor)
- memdelete(contact_monitor);
-}
-
-void RigidBody::_reload_physics_characteristics() {
- if (physics_material_override.is_null()) {
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
- } else {
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
- }
-}
-
-//////////////////////////////////////////////////////
-//////////////////////////
-
-Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
-
- Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) {
- if (motion_cache.is_null()) {
- motion_cache.instance();
- motion_cache->owner = this;
- }
-
- motion_cache->collision = col;
-
- return motion_cache;
- }
-
- return Ref<KinematicCollision>();
-}
-
-Vector3 KinematicBody::get_linear_velocity() const {
- return linear_velocity;
-}
-
-Vector3 KinematicBody::get_angular_velocity() const {
- return angular_velocity;
-}
-
-bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
-
- Transform gt = get_global_transform();
- PhysicsServer::MotionResult result;
- bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes);
-
- if (colliding) {
- r_collision.collider_metadata = result.collider_metadata;
- r_collision.collider_shape = result.collider_shape;
- r_collision.collider_vel = result.collider_velocity;
- r_collision.collision = result.collision_point;
- r_collision.normal = result.collision_normal;
- r_collision.collider = result.collider_id;
- r_collision.collider_rid = result.collider;
- r_collision.travel = result.motion;
- r_collision.remainder = result.remainder;
- r_collision.local_shape = result.collision_local_shape;
- }
-
- for (int i = 0; i < 3; i++) {
- if (locked_axis & (1 << i)) {
- result.motion[i] = 0;
- }
- }
-
- if (!p_test_only) {
- gt.origin += result.motion;
- set_global_transform(gt);
- }
-
- return colliding;
-}
-
-//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
-#define FLOOR_ANGLE_THRESHOLD 0.01
-
-Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
-
- Vector3 body_velocity = p_linear_velocity;
- Vector3 body_velocity_normal = body_velocity.normalized();
-
- for (int i = 0; i < 3; i++) {
- if (locked_axis & (1 << i)) {
- body_velocity[i] = 0;
- }
- }
-
- // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
- Vector3 motion = (floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
-
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
- colliders.clear();
- floor_normal = Vector3();
- floor_velocity = Vector3();
-
- while (p_max_slides) {
-
- Collision collision;
- bool found_collision = false;
-
- for (int i = 0; i < 2; ++i) {
- bool collided;
- if (i == 0) { //collide
- collided = move_and_collide(motion, p_infinite_inertia, collision);
- if (!collided) {
- motion = Vector3(); //clear because no collision happened and motion completed
- }
- } else { //separate raycasts (if any)
- collided = separate_raycast_shapes(p_infinite_inertia, collision);
- if (collided) {
- collision.remainder = motion; //keep
- collision.travel = Vector3();
- }
- }
-
- if (collided) {
- found_collision = true;
-
- colliders.push_back(collision);
- motion = collision.remainder;
-
- if (p_up_direction == Vector3()) {
- //all is a wall
- on_wall = true;
- } else {
- if (Math::acos(collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
-
- on_floor = true;
- floor_normal = collision.normal;
- on_floor_body = collision.collider_rid;
- floor_velocity = collision.collider_vel;
-
- if (p_stop_on_slope) {
- if ((body_velocity_normal + p_up_direction).length() < 0.01 && collision.travel.length() < 1) {
- Transform gt = get_global_transform();
- gt.origin -= collision.travel.slide(p_up_direction);
- set_global_transform(gt);
- return Vector3();
- }
- }
- } else if (Math::acos(collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
- on_ceiling = true;
- } else {
- on_wall = true;
- }
- }
-
- motion = motion.slide(collision.normal);
- body_velocity = body_velocity.slide(collision.normal);
-
- for (int j = 0; j < 3; j++) {
- if (locked_axis & (1 << j)) {
- body_velocity[j] = 0;
- }
- }
- }
- }
-
- if (!found_collision || motion == Vector3())
- break;
-
- --p_max_slides;
- }
-
- return body_velocity;
-}
-
-Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
-
- bool was_on_floor = on_floor;
-
- Vector3 ret = move_and_slide(p_linear_velocity, p_up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia);
- if (!was_on_floor || p_snap == Vector3()) {
- return ret;
- }
-
- Collision col;
- Transform gt = get_global_transform();
-
- if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
-
- bool apply = true;
- if (p_up_direction != Vector3()) {
- if (Math::acos(p_up_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
- on_floor = true;
- floor_normal = col.normal;
- on_floor_body = col.collider_rid;
- floor_velocity = col.collider_vel;
- if (p_stop_on_slope) {
- // move and collide may stray the object a bit because of pre un-stucking,
- // so only ensure that motion happens on floor direction in this case.
- col.travel = col.travel.project(p_up_direction);
- }
- } else {
- apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
- }
- }
- if (apply) {
- gt.origin += col.travel;
- set_global_transform(gt);
- }
- }
-
- return ret;
-}
-
-bool KinematicBody::is_on_floor() const {
-
- return on_floor;
-}
-
-bool KinematicBody::is_on_wall() const {
-
- return on_wall;
-}
-bool KinematicBody::is_on_ceiling() const {
-
- return on_ceiling;
-}
-
-Vector3 KinematicBody::get_floor_normal() const {
-
- return floor_normal;
-}
-
-Vector3 KinematicBody::get_floor_velocity() const {
-
- return floor_velocity;
-}
-
-bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) {
-
- ERR_FAIL_COND_V(!is_inside_tree(), false);
-
- return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
-}
-
-bool KinematicBody::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
-
- PhysicsServer::SeparationResult sep_res[8]; //max 8 rays
-
- Transform gt = get_global_transform();
-
- Vector3 recover;
- int hits = PhysicsServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- float deepest_depth;
- for (int i = 0; i < hits; i++) {
- if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
- deepest = i;
- deepest_depth = sep_res[i].collision_depth;
- }
- }
-
- gt.origin += recover;
- set_global_transform(gt);
-
- if (deepest != -1) {
- r_collision.collider = sep_res[deepest].collider_id;
- r_collision.collider_metadata = sep_res[deepest].collider_metadata;
- r_collision.collider_shape = sep_res[deepest].collider_shape;
- r_collision.collider_vel = sep_res[deepest].collider_velocity;
- r_collision.collision = sep_res[deepest].collision_point;
- r_collision.normal = sep_res[deepest].collision_normal;
- r_collision.local_shape = sep_res[deepest].collision_local_shape;
- r_collision.travel = recover;
- r_collision.remainder = Vector3();
-
- return true;
- } else {
- return false;
- }
-}
-
-void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) {
- PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
-}
-
-bool KinematicBody::get_axis_lock(PhysicsServer::BodyAxis p_axis) const {
- return PhysicsServer::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
-}
-
-void KinematicBody::set_safe_margin(float p_margin) {
-
- margin = p_margin;
- PhysicsServer::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin);
-}
-
-float KinematicBody::get_safe_margin() const {
-
- return margin;
-}
-int KinematicBody::get_slide_count() const {
-
- return colliders.size();
-}
-
-KinematicBody::Collision KinematicBody::get_slide_collision(int p_bounce) const {
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision());
- return colliders[p_bounce];
-}
-
-Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
-
- ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision>());
- if (p_bounce >= slide_colliders.size()) {
- slide_colliders.resize(p_bounce + 1);
- }
-
- if (slide_colliders[p_bounce].is_null()) {
- slide_colliders.write[p_bounce].instance();
- slide_colliders.write[p_bounce]->owner = this;
- }
-
- slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
- return slide_colliders[p_bounce];
-}
-
-void KinematicBody::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- // Reset move_and_slide() data.
- on_floor = false;
- on_floor_body = RID();
- on_ceiling = false;
- on_wall = false;
- colliders.clear();
- floor_velocity = Vector3();
- }
-}
-
-void KinematicBody::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody::_direct_state_changed);
-
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody::_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"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), 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"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
-
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move, DEFVAL(true));
-
- ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody::is_on_floor);
- ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody::is_on_ceiling);
- ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody::is_on_wall);
- ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody::get_floor_normal);
- ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody::get_floor_velocity);
-
- ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody::set_axis_lock);
- ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &KinematicBody::get_axis_lock);
-
- ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody::set_safe_margin);
- ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody::get_safe_margin);
-
- ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count);
- ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
-}
-
-void KinematicBody::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- PhysicsDirectBodyState *state = Object::cast_to<PhysicsDirectBodyState>(p_state);
-#else
- PhysicsDirectBodyState *state = (PhysicsDirectBodyState *)p_state; //trust it
-#endif
-
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
-}
-
-KinematicBody::KinematicBody() :
- PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC) {
-
- margin = 0.001;
- locked_axis = 0;
- on_floor = false;
- on_ceiling = false;
- on_wall = false;
-
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
-}
-KinematicBody::~KinematicBody() {
-
- if (motion_cache.is_valid()) {
- motion_cache->owner = NULL;
- }
-
- for (int i = 0; i < slide_colliders.size(); i++) {
- if (slide_colliders[i].is_valid()) {
- slide_colliders.write[i]->owner = NULL;
- }
- }
-}
-///////////////////////////////////////
-
-Vector3 KinematicCollision::get_position() const {
-
- return collision.collision;
-}
-Vector3 KinematicCollision::get_normal() const {
- return collision.normal;
-}
-Vector3 KinematicCollision::get_travel() const {
- return collision.travel;
-}
-Vector3 KinematicCollision::get_remainder() const {
- return collision.remainder;
-}
-Object *KinematicCollision::get_local_shape() const {
- if (!owner) return NULL;
- uint32_t ownerid = owner->shape_find_owner(collision.local_shape);
- return owner->shape_owner_get_owner(ownerid);
-}
-
-Object *KinematicCollision::get_collider() const {
-
- if (collision.collider.is_valid()) {
- return ObjectDB::get_instance(collision.collider);
- }
-
- return NULL;
-}
-ObjectID KinematicCollision::get_collider_id() const {
-
- return collision.collider;
-}
-Object *KinematicCollision::get_collider_shape() const {
-
- Object *collider = get_collider();
- if (collider) {
- CollisionObject *obj2d = Object::cast_to<CollisionObject>(collider);
- if (obj2d) {
- uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape);
- return obj2d->shape_owner_get_owner(ownerid);
- }
- }
-
- return NULL;
-}
-int KinematicCollision::get_collider_shape_index() const {
-
- return collision.collider_shape;
-}
-Vector3 KinematicCollision::get_collider_velocity() const {
-
- return collision.collider_vel;
-}
-Variant KinematicCollision::get_collider_metadata() const {
-
- return Variant();
-}
-
-void KinematicCollision::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision::get_position);
- ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision::get_normal);
- ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision::get_travel);
- ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision::get_remainder);
- ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision::get_local_shape);
- ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision::get_collider);
- ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision::get_collider_id);
- ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision::get_collider_shape);
- ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision::get_collider_shape_index);
- ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision::get_collider_velocity);
- ClassDB::bind_method(D_METHOD("get_collider_metadata"), &KinematicCollision::get_collider_metadata);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "", "get_position");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "", "get_normal");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata");
-}
-
-KinematicCollision::KinematicCollision() {
-
- collision.collider_shape = 0;
- collision.local_shape = 0;
- owner = NULL;
-}
-
-///////////////////////////////////////
-
-bool PhysicalBone::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
- return false;
-}
-
-bool PhysicalBone::JointData::_get(const StringName &p_name, Variant &r_ret) const {
- return false;
-}
-
-void PhysicalBone::JointData::_get_property_list(List<PropertyInfo> *p_list) const {
-}
-
-void PhysicalBone::apply_central_impulse(const Vector3 &p_impulse) {
- PhysicsServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
-}
-
-void PhysicalBone::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
- PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
-}
-
-void PhysicalBone::reset_physics_simulation_state() {
- if (simulate_physics) {
- _start_physics_simulation();
- } else {
- _stop_physics_simulation();
- }
-}
-
-void PhysicalBone::reset_to_rest_position() {
- if (parent_skeleton) {
- if (-1 == bone_id) {
- set_global_transform(parent_skeleton->get_global_transform() * body_offset);
- } else {
- set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset);
- }
- }
-}
-
-bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
- if (JointData::_set(p_name, p_value, j)) {
- return true;
- }
-
- if ("joint_constraints/bias" == p_name) {
- bias = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_BIAS, bias);
-
- } else if ("joint_constraints/damping" == p_name) {
- damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_DAMPING, damping);
-
- } else if ("joint_constraints/impulse_clamp" == p_name) {
- impulse_clamp = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-bool PhysicalBone::PinJointData::_get(const StringName &p_name, Variant &r_ret) const {
- if (JointData::_get(p_name, r_ret)) {
- return true;
- }
-
- if ("joint_constraints/bias" == p_name) {
- r_ret = bias;
- } else if ("joint_constraints/damping" == p_name) {
- r_ret = damping;
- } else if ("joint_constraints/impulse_clamp" == p_name) {
- r_ret = impulse_clamp;
- } else {
- return false;
- }
-
- return true;
-}
-
-void PhysicalBone::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const {
- JointData::_get_property_list(p_list);
-
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"));
-}
-
-bool PhysicalBone::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
- if (JointData::_set(p_name, p_value, j)) {
- return true;
- }
-
- if ("joint_constraints/swing_span" == p_name) {
- swing_span = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, swing_span);
-
- } else if ("joint_constraints/twist_span" == p_name) {
- twist_span = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, twist_span);
-
- } else if ("joint_constraints/bias" == p_name) {
- bias = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_BIAS, bias);
-
- } else if ("joint_constraints/softness" == p_name) {
- softness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, softness);
-
- } else if ("joint_constraints/relaxation" == p_name) {
- relaxation = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, relaxation);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-bool PhysicalBone::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const {
- if (JointData::_get(p_name, r_ret)) {
- return true;
- }
-
- if ("joint_constraints/swing_span" == p_name) {
- r_ret = Math::rad2deg(swing_span);
- } else if ("joint_constraints/twist_span" == p_name) {
- r_ret = Math::rad2deg(twist_span);
- } else if ("joint_constraints/bias" == p_name) {
- r_ret = bias;
- } else if ("joint_constraints/softness" == p_name) {
- r_ret = softness;
- } else if ("joint_constraints/relaxation" == p_name) {
- r_ret = relaxation;
- } else {
- return false;
- }
-
- return true;
-}
-
-void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
- JointData::_get_property_list(p_list);
-
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
-}
-
-bool PhysicalBone::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
- if (JointData::_set(p_name, p_value, j)) {
- return true;
- }
-
- if ("joint_constraints/angular_limit_enabled" == p_name) {
- angular_limit_enabled = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_flag(j, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled);
-
- } else if ("joint_constraints/angular_limit_upper" == p_name) {
- angular_limit_upper = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper);
-
- } else if ("joint_constraints/angular_limit_lower" == p_name) {
- angular_limit_lower = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower);
-
- } else if ("joint_constraints/angular_limit_bias" == p_name) {
- angular_limit_bias = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias);
-
- } else if ("joint_constraints/angular_limit_softness" == p_name) {
- angular_limit_softness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness);
-
- } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
- angular_limit_relaxation = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-bool PhysicalBone::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const {
- if (JointData::_get(p_name, r_ret)) {
- return true;
- }
-
- if ("joint_constraints/angular_limit_enabled" == p_name) {
- r_ret = angular_limit_enabled;
- } else if ("joint_constraints/angular_limit_upper" == p_name) {
- r_ret = Math::rad2deg(angular_limit_upper);
- } else if ("joint_constraints/angular_limit_lower" == p_name) {
- r_ret = Math::rad2deg(angular_limit_lower);
- } else if ("joint_constraints/angular_limit_bias" == p_name) {
- r_ret = angular_limit_bias;
- } else if ("joint_constraints/angular_limit_softness" == p_name) {
- r_ret = angular_limit_softness;
- } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
- r_ret = angular_limit_relaxation;
- } else {
- return false;
- }
-
- return true;
-}
-
-void PhysicalBone::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
- JointData::_get_property_list(p_list);
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/angular_limit_enabled"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
-}
-
-bool PhysicalBone::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
- if (JointData::_set(p_name, p_value, j)) {
- return true;
- }
-
- if ("joint_constraints/linear_limit_upper" == p_name) {
- linear_limit_upper = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper);
-
- } else if ("joint_constraints/linear_limit_lower" == p_name) {
- linear_limit_lower = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower);
-
- } else if ("joint_constraints/linear_limit_softness" == p_name) {
- linear_limit_softness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness);
-
- } else if ("joint_constraints/linear_limit_restitution" == p_name) {
- linear_limit_restitution = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution);
-
- } else if ("joint_constraints/linear_limit_damping" == p_name) {
- linear_limit_damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution);
-
- } else if ("joint_constraints/angular_limit_upper" == p_name) {
- angular_limit_upper = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper);
-
- } else if ("joint_constraints/angular_limit_lower" == p_name) {
- angular_limit_lower = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower);
-
- } else if ("joint_constraints/angular_limit_softness" == p_name) {
- angular_limit_softness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
-
- } else if ("joint_constraints/angular_limit_restitution" == p_name) {
- angular_limit_restitution = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
-
- } else if ("joint_constraints/angular_limit_damping" == p_name) {
- angular_limit_damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-bool PhysicalBone::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const {
- if (JointData::_get(p_name, r_ret)) {
- return true;
- }
-
- if ("joint_constraints/linear_limit_upper" == p_name) {
- r_ret = linear_limit_upper;
- } else if ("joint_constraints/linear_limit_lower" == p_name) {
- r_ret = linear_limit_lower;
- } else if ("joint_constraints/linear_limit_softness" == p_name) {
- r_ret = linear_limit_softness;
- } else if ("joint_constraints/linear_limit_restitution" == p_name) {
- r_ret = linear_limit_restitution;
- } else if ("joint_constraints/linear_limit_damping" == p_name) {
- r_ret = linear_limit_damping;
- } else if ("joint_constraints/angular_limit_upper" == p_name) {
- r_ret = Math::rad2deg(angular_limit_upper);
- } else if ("joint_constraints/angular_limit_lower" == p_name) {
- r_ret = Math::rad2deg(angular_limit_lower);
- } else if ("joint_constraints/angular_limit_softness" == p_name) {
- r_ret = angular_limit_softness;
- } else if ("joint_constraints/angular_limit_restitution" == p_name) {
- r_ret = angular_limit_restitution;
- } else if ("joint_constraints/angular_limit_damping" == p_name) {
- r_ret = angular_limit_damping;
- } else {
- return false;
- }
-
- return true;
-}
-
-void PhysicalBone::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const {
- JointData::_get_property_list(p_list);
-
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_upper"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_lower"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
-
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
-}
-
-bool PhysicalBone::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
- if (JointData::_set(p_name, p_value, j)) {
- return true;
- }
-
- String path = p_name;
-
- Vector3::Axis axis;
- {
- const String axis_s = path.get_slicec('/', 1);
- if ("x" == axis_s) {
- axis = Vector3::AXIS_X;
- } else if ("y" == axis_s) {
- axis = Vector3::AXIS_Y;
- } else if ("z" == axis_s) {
- axis = Vector3::AXIS_Z;
- } else {
- return false;
- }
- }
-
- String var_name = path.get_slicec('/', 2);
-
- if ("linear_limit_enabled" == var_name) {
- axis_data[axis].linear_limit_enabled = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled);
-
- } else if ("linear_limit_upper" == var_name) {
- axis_data[axis].linear_limit_upper = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper);
-
- } else if ("linear_limit_lower" == var_name) {
- axis_data[axis].linear_limit_lower = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower);
-
- } else if ("linear_limit_softness" == var_name) {
- axis_data[axis].linear_limit_softness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness);
-
- } else if ("linear_spring_enabled" == var_name) {
- axis_data[axis].linear_spring_enabled = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, axis_data[axis].linear_spring_enabled);
-
- } else if ("linear_spring_stiffness" == var_name) {
- axis_data[axis].linear_spring_stiffness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, axis_data[axis].linear_spring_stiffness);
-
- } else if ("linear_spring_damping" == var_name) {
- axis_data[axis].linear_spring_damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING, axis_data[axis].linear_spring_damping);
-
- } else if ("linear_equilibrium_point" == var_name) {
- axis_data[axis].linear_equilibrium_point = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].linear_equilibrium_point);
-
- } else if ("linear_restitution" == var_name) {
- axis_data[axis].linear_restitution = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution);
-
- } else if ("linear_damping" == var_name) {
- axis_data[axis].linear_damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping);
-
- } else if ("angular_limit_enabled" == var_name) {
- axis_data[axis].angular_limit_enabled = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled);
-
- } else if ("angular_limit_upper" == var_name) {
- axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper);
-
- } else if ("angular_limit_lower" == var_name) {
- axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value));
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower);
-
- } else if ("angular_limit_softness" == var_name) {
- axis_data[axis].angular_limit_softness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness);
-
- } else if ("angular_restitution" == var_name) {
- axis_data[axis].angular_restitution = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution);
-
- } else if ("angular_damping" == var_name) {
- axis_data[axis].angular_damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping);
-
- } else if ("erp" == var_name) {
- axis_data[axis].erp = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp);
-
- } else if ("angular_spring_enabled" == var_name) {
- axis_data[axis].angular_spring_enabled = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, axis_data[axis].angular_spring_enabled);
-
- } else if ("angular_spring_stiffness" == var_name) {
- axis_data[axis].angular_spring_stiffness = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, axis_data[axis].angular_spring_stiffness);
-
- } else if ("angular_spring_damping" == var_name) {
- axis_data[axis].angular_spring_damping = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, axis_data[axis].angular_spring_damping);
-
- } else if ("angular_equilibrium_point" == var_name) {
- axis_data[axis].angular_equilibrium_point = p_value;
- if (j.is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].angular_equilibrium_point);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-bool PhysicalBone::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const {
- if (JointData::_get(p_name, r_ret)) {
- return true;
- }
-
- String path = p_name;
-
- int axis;
- {
- const String axis_s = path.get_slicec('/', 1);
- if ("x" == axis_s) {
- axis = 0;
- } else if ("y" == axis_s) {
- axis = 1;
- } else if ("z" == axis_s) {
- axis = 2;
- } else {
- return false;
- }
- }
-
- String var_name = path.get_slicec('/', 2);
-
- if ("linear_limit_enabled" == var_name) {
- r_ret = axis_data[axis].linear_limit_enabled;
- } else if ("linear_limit_upper" == var_name) {
- r_ret = axis_data[axis].linear_limit_upper;
- } else if ("linear_limit_lower" == var_name) {
- r_ret = axis_data[axis].linear_limit_lower;
- } else if ("linear_limit_softness" == var_name) {
- r_ret = axis_data[axis].linear_limit_softness;
- } else if ("linear_spring_enabled" == var_name) {
- r_ret = axis_data[axis].linear_spring_enabled;
- } else if ("linear_spring_stiffness" == var_name) {
- r_ret = axis_data[axis].linear_spring_stiffness;
- } else if ("linear_spring_damping" == var_name) {
- r_ret = axis_data[axis].linear_spring_damping;
- } else if ("linear_equilibrium_point" == var_name) {
- r_ret = axis_data[axis].linear_equilibrium_point;
- } else if ("linear_restitution" == var_name) {
- r_ret = axis_data[axis].linear_restitution;
- } else if ("linear_damping" == var_name) {
- r_ret = axis_data[axis].linear_damping;
- } else if ("angular_limit_enabled" == var_name) {
- r_ret = axis_data[axis].angular_limit_enabled;
- } else if ("angular_limit_upper" == var_name) {
- r_ret = Math::rad2deg(axis_data[axis].angular_limit_upper);
- } else if ("angular_limit_lower" == var_name) {
- r_ret = Math::rad2deg(axis_data[axis].angular_limit_lower);
- } else if ("angular_limit_softness" == var_name) {
- r_ret = axis_data[axis].angular_limit_softness;
- } else if ("angular_restitution" == var_name) {
- r_ret = axis_data[axis].angular_restitution;
- } else if ("angular_damping" == var_name) {
- r_ret = axis_data[axis].angular_damping;
- } else if ("erp" == var_name) {
- r_ret = axis_data[axis].erp;
- } else if ("angular_spring_enabled" == var_name) {
- r_ret = axis_data[axis].angular_spring_enabled;
- } else if ("angular_spring_stiffness" == var_name) {
- r_ret = axis_data[axis].angular_spring_stiffness;
- } else if ("angular_spring_damping" == var_name) {
- r_ret = axis_data[axis].angular_spring_damping;
- } else if ("angular_equilibrium_point" == var_name) {
- r_ret = axis_data[axis].angular_equilibrium_point;
- } else {
- return false;
- }
-
- return true;
-}
-
-void PhysicalBone::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const {
- const StringName axis_names[] = { "x", "y", "z" };
- for (int i = 0; i < 3; ++i) {
- p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_limit_enabled"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_upper"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_lower"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_spring_enabled"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_spring_stiffness"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_spring_damping"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_equilibrium_point"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_limit_enabled"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/erp"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_spring_enabled"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_spring_stiffness"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_spring_damping"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_equilibrium_point"));
- }
-}
-
-bool PhysicalBone::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == "bone_name") {
- set_bone_name(p_value);
- return true;
- }
-
- if (joint_data) {
- if (joint_data->_set(p_name, p_value)) {
-#ifdef TOOLS_ENABLED
- if (get_gizmo().is_valid())
- get_gizmo()->redraw();
-#endif
- return true;
- }
- }
-
- return false;
-}
-
-bool PhysicalBone::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == "bone_name") {
- r_ret = get_bone_name();
- return true;
- }
-
- if (joint_data) {
- return joint_data->_get(p_name, r_ret);
- }
-
- return false;
-}
-
-void PhysicalBone::_get_property_list(List<PropertyInfo> *p_list) const {
-
- Skeleton *parent = find_skeleton_parent(get_parent());
-
- if (parent) {
-
- String names;
- for (int i = 0; i < parent->get_bone_count(); i++) {
- if (i > 0)
- names += ",";
- names += parent->get_bone_name(i);
- }
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name", PROPERTY_HINT_ENUM, names));
- } else {
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name"));
- }
-
- if (joint_data) {
- joint_data->_get_property_list(p_list);
- }
-}
-
-void PhysicalBone::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- parent_skeleton = find_skeleton_parent(get_parent());
- update_bone_id();
- reset_to_rest_position();
- reset_physics_simulation_state();
- if (!joint.is_valid() && joint_data) {
- _reload_joint();
- }
- break;
- case NOTIFICATION_EXIT_TREE:
- if (parent_skeleton) {
- if (-1 != bone_id) {
- parent_skeleton->unbind_physical_bone_from_bone(bone_id);
- }
- }
- parent_skeleton = NULL;
- if (joint.is_valid()) {
- PhysicsServer::get_singleton()->free(joint);
- joint = RID();
- }
- break;
- case NOTIFICATION_TRANSFORM_CHANGED:
- if (Engine::get_singleton()->is_editor_hint()) {
-
- update_offset();
- }
- break;
- }
-}
-
-void PhysicalBone::_direct_state_changed(Object *p_state) {
-
- if (!simulate_physics || !_internal_simulate_physics) {
- return;
- }
-
- /// Update bone transform
-
- PhysicsDirectBodyState *state;
-
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState>(p_state);
-#else
- state = (PhysicsDirectBodyState *)p_state; //trust it
-#endif
-
- Transform global_transform(state->get_transform());
-
- set_ignore_transform_notification(true);
- set_global_transform(global_transform);
- set_ignore_transform_notification(false);
-
- // Update skeleton
- if (parent_skeleton) {
- if (-1 != bone_id) {
- parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true);
- }
- }
-}
-
-void PhysicalBone::_bind_methods() {
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &PhysicalBone::apply_impulse);
-
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone::_direct_state_changed);
-
- ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone::set_joint_type);
- ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone::get_joint_type);
-
- ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone::set_joint_offset);
- ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone::get_joint_offset);
-
- ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset);
- ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset);
-
- ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
-
- ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
-
- ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone::get_bone_id);
-
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass);
-
- ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone::set_weight);
- ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone::get_weight);
-
- ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone::set_friction);
- ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone::get_friction);
-
- ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone::set_bounce);
- ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone::get_bounce);
-
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone::get_gravity_scale);
-
- ADD_GROUP("Joint", "joint_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
-
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
-
- BIND_ENUM_CONSTANT(JOINT_TYPE_NONE);
- BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
- BIND_ENUM_CONSTANT(JOINT_TYPE_CONE);
- BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE);
- BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER);
- BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF);
-}
-
-Skeleton *PhysicalBone::find_skeleton_parent(Node *p_parent) {
- if (!p_parent) {
- return NULL;
- }
- Skeleton *s = Object::cast_to<Skeleton>(p_parent);
- return s ? s : find_skeleton_parent(p_parent->get_parent());
-}
-
-void PhysicalBone::_fix_joint_offset() {
- // Clamp joint origin to bone origin
- if (parent_skeleton) {
- joint_offset.origin = body_offset.affine_inverse().origin;
- }
-}
-
-void PhysicalBone::_reload_joint() {
-
- if (joint.is_valid()) {
- PhysicsServer::get_singleton()->free(joint);
- joint = RID();
- }
-
- if (!parent_skeleton) {
- return;
- }
-
- PhysicalBone *body_a = parent_skeleton->get_physical_bone_parent(bone_id);
- if (!body_a) {
- return;
- }
-
- Transform joint_transf = get_global_transform() * joint_offset;
- Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
- local_a.orthonormalize();
-
- switch (get_joint_type()) {
- case JOINT_TYPE_PIN: {
-
- joint = PhysicsServer::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin);
- const PinJointData *pjd(static_cast<const PinJointData *>(joint_data));
- PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_BIAS, pjd->bias);
- PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_DAMPING, pjd->damping);
- PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp);
-
- } break;
- case JOINT_TYPE_CONE: {
-
- joint = PhysicsServer::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset);
- const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data));
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span);
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span);
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_BIAS, cjd->bias);
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, cjd->softness);
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation);
-
- } break;
- case JOINT_TYPE_HINGE: {
-
- joint = PhysicsServer::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset);
- const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data));
- PhysicsServer::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled);
- PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper);
- PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower);
- PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias);
- PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness);
- PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation);
-
- } break;
- case JOINT_TYPE_SLIDER: {
-
- joint = PhysicsServer::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset);
- const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data));
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
- PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping);
-
- } break;
- case JOINT_TYPE_6DOF: {
-
- joint = PhysicsServer::get_singleton()->joint_create_generic_6dof(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) {
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, g6dofjd->axis_data[axis].linear_spring_enabled);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].linear_spring_stiffness);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING, g6dofjd->axis_data[axis].linear_spring_damping);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].linear_equilibrium_point);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, g6dofjd->axis_data[axis].angular_spring_enabled);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].angular_spring_stiffness);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, g6dofjd->axis_data[axis].angular_spring_damping);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].angular_equilibrium_point);
- }
-
- } break;
- case JOINT_TYPE_NONE: {
- } break;
- }
-}
-
-void PhysicalBone::_on_bone_parent_changed() {
- _reload_joint();
-}
-
-void PhysicalBone::_set_gizmo_move_joint(bool p_move_joint) {
-#ifdef TOOLS_ENABLED
- gizmo_move_joint = p_move_joint;
- SpatialEditor::get_singleton()->update_transform_gizmo();
-#endif
-}
-
-#ifdef TOOLS_ENABLED
-Transform PhysicalBone::get_global_gizmo_transform() const {
- return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform();
-}
-
-Transform PhysicalBone::get_local_gizmo_transform() const {
- return gizmo_move_joint ? get_transform() * joint_offset : get_transform();
-}
-#endif
-
-const PhysicalBone::JointData *PhysicalBone::get_joint_data() const {
- return joint_data;
-}
-
-Skeleton *PhysicalBone::find_skeleton_parent() {
- return find_skeleton_parent(this);
-}
-
-void PhysicalBone::set_joint_type(JointType p_joint_type) {
-
- if (p_joint_type == get_joint_type())
- return;
-
- if (joint_data)
- memdelete(joint_data);
- joint_data = NULL;
- switch (p_joint_type) {
- case JOINT_TYPE_PIN:
- joint_data = memnew(PinJointData);
- break;
- case JOINT_TYPE_CONE:
- joint_data = memnew(ConeJointData);
- break;
- case JOINT_TYPE_HINGE:
- joint_data = memnew(HingeJointData);
- break;
- case JOINT_TYPE_SLIDER:
- joint_data = memnew(SliderJointData);
- break;
- case JOINT_TYPE_6DOF:
- joint_data = memnew(SixDOFJointData);
- break;
- case JOINT_TYPE_NONE:
- break;
- }
-
- _reload_joint();
-
-#ifdef TOOLS_ENABLED
- _change_notify();
- if (get_gizmo().is_valid())
- get_gizmo()->redraw();
-#endif
-}
-
-PhysicalBone::JointType PhysicalBone::get_joint_type() const {
- return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE;
-}
-
-void PhysicalBone::set_joint_offset(const Transform &p_offset) {
- joint_offset = p_offset;
-
- _fix_joint_offset();
-
- set_ignore_transform_notification(true);
- reset_to_rest_position();
- set_ignore_transform_notification(false);
-
-#ifdef TOOLS_ENABLED
- if (get_gizmo().is_valid())
- get_gizmo()->redraw();
-#endif
-}
-
-const Transform &PhysicalBone::get_body_offset() const {
- return body_offset;
-}
-
-void PhysicalBone::set_body_offset(const Transform &p_offset) {
- body_offset = p_offset;
- body_offset_inverse = body_offset.affine_inverse();
-
- _fix_joint_offset();
-
- set_ignore_transform_notification(true);
- reset_to_rest_position();
- set_ignore_transform_notification(false);
-
-#ifdef TOOLS_ENABLED
- if (get_gizmo().is_valid())
- get_gizmo()->redraw();
-#endif
-}
-
-const Transform &PhysicalBone::get_joint_offset() const {
- return joint_offset;
-}
-
-void PhysicalBone::set_simulate_physics(bool p_simulate) {
- if (simulate_physics == p_simulate) {
- return;
- }
-
- simulate_physics = p_simulate;
- reset_physics_simulation_state();
-}
-
-bool PhysicalBone::get_simulate_physics() {
- return simulate_physics;
-}
-
-bool PhysicalBone::is_simulating_physics() {
- return _internal_simulate_physics;
-}
-
-void PhysicalBone::set_bone_name(const String &p_name) {
-
- bone_name = p_name;
- bone_id = -1;
-
- update_bone_id();
- reset_to_rest_position();
-}
-
-const String &PhysicalBone::get_bone_name() const {
-
- return bone_name;
-}
-
-void PhysicalBone::set_mass(real_t p_mass) {
-
- ERR_FAIL_COND(p_mass <= 0);
- mass = p_mass;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_MASS, mass);
-}
-
-real_t PhysicalBone::get_mass() const {
-
- return mass;
-}
-
-void PhysicalBone::set_weight(real_t p_weight) {
-
- set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
-}
-
-real_t PhysicalBone::get_weight() const {
-
- return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
-}
-
-void PhysicalBone::set_friction(real_t p_friction) {
-
- ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
-
- friction = p_friction;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
-}
-
-real_t PhysicalBone::get_friction() const {
-
- return friction;
-}
-
-void PhysicalBone::set_bounce(real_t p_bounce) {
-
- ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
-
- bounce = p_bounce;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
-}
-
-real_t PhysicalBone::get_bounce() const {
-
- return bounce;
-}
-
-void PhysicalBone::set_gravity_scale(real_t p_gravity_scale) {
-
- gravity_scale = p_gravity_scale;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
-}
-
-real_t PhysicalBone::get_gravity_scale() const {
-
- return gravity_scale;
-}
-
-PhysicalBone::PhysicalBone() :
- PhysicsBody(PhysicsServer::BODY_MODE_STATIC),
-#ifdef TOOLS_ENABLED
- gizmo_move_joint(false),
-#endif
- joint_data(NULL),
- parent_skeleton(NULL),
- simulate_physics(false),
- _internal_simulate_physics(false),
- bone_id(-1),
- bone_name(""),
- bounce(0),
- mass(1),
- friction(1),
- gravity_scale(1) {
-
- reset_physics_simulation_state();
-}
-
-PhysicalBone::~PhysicalBone() {
- if (joint_data)
- memdelete(joint_data);
-}
-
-void PhysicalBone::update_bone_id() {
- if (!parent_skeleton) {
- return;
- }
-
- const int new_bone_id = parent_skeleton->find_bone(bone_name);
-
- if (new_bone_id != bone_id) {
- if (-1 != bone_id) {
- // Assert the unbind from old node
- parent_skeleton->unbind_physical_bone_from_bone(bone_id);
- parent_skeleton->unbind_child_node_from_bone(bone_id, this);
- }
-
- bone_id = new_bone_id;
-
- parent_skeleton->bind_physical_bone_to_bone(bone_id, this);
-
- _fix_joint_offset();
- reset_physics_simulation_state();
- }
-}
-
-void PhysicalBone::update_offset() {
-#ifdef TOOLS_ENABLED
- if (parent_skeleton) {
-
- Transform bone_transform(parent_skeleton->get_global_transform());
- if (-1 != bone_id)
- bone_transform *= parent_skeleton->get_bone_global_pose(bone_id);
-
- if (gizmo_move_joint) {
- bone_transform *= body_offset;
- set_joint_offset(bone_transform.affine_inverse() * get_global_transform());
- } else {
- set_body_offset(bone_transform.affine_inverse() * get_global_transform());
- }
- }
-#endif
-}
-
-void PhysicalBone::_start_physics_simulation() {
- if (_internal_simulate_physics || !parent_skeleton) {
- return;
- }
- reset_to_rest_position();
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_RIGID);
- PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
- PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
- set_as_toplevel(true);
- _internal_simulate_physics = true;
-}
-
-void PhysicalBone::_stop_physics_simulation() {
- if (!parent_skeleton) {
- return;
- }
- if (parent_skeleton->get_animate_physical_bones()) {
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_KINEMATIC);
- PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
- PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- } else {
- PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC);
- PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0);
- PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0);
- }
- if (_internal_simulate_physics) {
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
- parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
- set_as_toplevel(false);
- _internal_simulate_physics = false;
- }
-}
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
deleted file mode 100644
index 5362baf8ee..0000000000
--- a/scene/3d/physics_body.h
+++ /dev/null
@@ -1,646 +0,0 @@
-/*************************************************************************/
-/* physics_body.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS_BODY__H
-#define PHYSICS_BODY__H
-
-#include "core/vset.h"
-#include "scene/3d/collision_object.h"
-#include "scene/resources/physics_material.h"
-#include "servers/physics_server.h"
-#include "skeleton.h"
-
-class PhysicsBody : public CollisionObject {
-
- GDCLASS(PhysicsBody, CollisionObject);
-
- uint32_t collision_layer;
- uint32_t collision_mask;
-
- void _set_layers(uint32_t p_mask);
- uint32_t _get_layers() const;
-
-protected:
- static void _bind_methods();
- PhysicsBody(PhysicsServer::BodyMode p_mode);
-
-public:
- virtual Vector3 get_linear_velocity() const;
- virtual Vector3 get_angular_velocity() const;
- virtual float 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;
-
- Array get_collision_exceptions();
- void add_collision_exception_with(Node *p_node); //must be physicsbody
- void remove_collision_exception_with(Node *p_node);
-
- PhysicsBody();
-};
-
-class StaticBody : public PhysicsBody {
-
- GDCLASS(StaticBody, PhysicsBody);
-
- Vector3 constant_linear_velocity;
- Vector3 constant_angular_velocity;
-
- Ref<PhysicsMaterial> physics_material_override;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
- Ref<PhysicsMaterial> get_physics_material_override() const;
-
- void set_constant_linear_velocity(const Vector3 &p_vel);
- void set_constant_angular_velocity(const Vector3 &p_vel);
-
- Vector3 get_constant_linear_velocity() const;
- Vector3 get_constant_angular_velocity() const;
-
- StaticBody();
- ~StaticBody();
-
-private:
- void _reload_physics_characteristics();
-};
-
-class RigidBody : public PhysicsBody {
-
- GDCLASS(RigidBody, PhysicsBody);
-
-public:
- enum Mode {
- MODE_RIGID,
- MODE_STATIC,
- MODE_CHARACTER,
- MODE_KINEMATIC,
- };
-
-protected:
- bool can_sleep;
- PhysicsDirectBodyState *state;
- Mode mode;
-
- real_t mass;
- Ref<PhysicsMaterial> physics_material_override;
-
- Vector3 linear_velocity;
- Vector3 angular_velocity;
- real_t gravity_scale;
- real_t linear_damp;
- real_t angular_damp;
-
- bool sleeping;
- bool ccd;
-
- int max_contacts_reported;
-
- bool custom_integrator;
-
- struct ShapePair {
-
- int body_shape;
- int local_shape;
- bool tagged;
- bool operator<(const ShapePair &p_sp) const {
- if (body_shape == p_sp.body_shape)
- return local_shape < p_sp.local_shape;
- else
- return body_shape < p_sp.body_shape;
- }
-
- ShapePair() {}
- ShapePair(int p_bs, int p_ls) {
- body_shape = p_bs;
- local_shape = p_ls;
- tagged = false;
- }
- };
- struct RigidBody_RemoveAction {
-
- ObjectID body_id;
- ShapePair pair;
- };
- struct BodyState {
-
- //int rc;
- bool in_tree;
- VSet<ShapePair> shapes;
- };
-
- struct ContactMonitor {
-
- bool locked;
- Map<ObjectID, BodyState> body_map;
- };
-
- ContactMonitor *contact_monitor;
- void _body_enter_tree(ObjectID p_id);
- void _body_exit_tree(ObjectID p_id);
-
- void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape);
- virtual void _direct_state_changed(Object *p_state);
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_mode(Mode p_mode);
- Mode get_mode() const;
-
- void set_mass(real_t p_mass);
- real_t get_mass() const;
-
- virtual float get_inverse_mass() const { return 1.0 / mass; }
-
- void set_weight(real_t p_weight);
- real_t get_weight() const;
-
- void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
- Ref<PhysicsMaterial> get_physics_material_override() const;
-
- void set_linear_velocity(const Vector3 &p_velocity);
- Vector3 get_linear_velocity() const;
-
- void set_axis_velocity(const Vector3 &p_axis);
-
- void set_angular_velocity(const Vector3 &p_velocity);
- Vector3 get_angular_velocity() const;
-
- void set_gravity_scale(real_t p_gravity_scale);
- real_t get_gravity_scale() const;
-
- void set_linear_damp(real_t p_linear_damp);
- real_t get_linear_damp() const;
-
- void set_angular_damp(real_t p_angular_damp);
- real_t get_angular_damp() const;
-
- void set_use_custom_integrator(bool p_enable);
- bool is_using_custom_integrator();
-
- void set_sleeping(bool p_sleeping);
- bool is_sleeping() const;
-
- void set_can_sleep(bool p_active);
- bool is_able_to_sleep() const;
-
- void set_contact_monitor(bool p_enabled);
- bool is_contact_monitor_enabled() const;
-
- void set_max_contacts_reported(int p_amount);
- int get_max_contacts_reported() const;
-
- void set_use_continuous_collision_detection(bool p_enable);
- bool is_using_continuous_collision_detection() const;
-
- void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
- bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
-
- Array get_colliding_bodies() const;
-
- void add_central_force(const Vector3 &p_force);
- void add_force(const Vector3 &p_force, const Vector3 &p_pos);
- void add_torque(const Vector3 &p_torque);
-
- void apply_central_impulse(const Vector3 &p_impulse);
- void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
- void apply_torque_impulse(const Vector3 &p_impulse);
-
- virtual String get_configuration_warning() const;
-
- RigidBody();
- ~RigidBody();
-
-private:
- void _reload_physics_characteristics();
-};
-
-VARIANT_ENUM_CAST(RigidBody::Mode);
-
-class KinematicCollision;
-
-class KinematicBody : public PhysicsBody {
-
- GDCLASS(KinematicBody, PhysicsBody);
-
-public:
- struct Collision {
- Vector3 collision;
- Vector3 normal;
- Vector3 collider_vel;
- ObjectID collider;
- RID collider_rid;
- int collider_shape;
- Variant collider_metadata;
- Vector3 remainder;
- Vector3 travel;
- int local_shape;
- };
-
-private:
- Vector3 linear_velocity;
- Vector3 angular_velocity;
-
- uint16_t locked_axis;
-
- float margin;
-
- Vector3 floor_normal;
- Vector3 floor_velocity;
- RID on_floor_body;
- bool on_floor;
- bool on_ceiling;
- bool on_wall;
- Vector<Collision> colliders;
- Vector<Ref<KinematicCollision> > slide_colliders;
- Ref<KinematicCollision> motion_cache;
-
- _FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const;
-
- Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
- Ref<KinematicCollision> _get_slide_collision(int p_bounce);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
- virtual void _direct_state_changed(Object *p_state);
-
-public:
- virtual Vector3 get_linear_velocity() const;
- virtual Vector3 get_angular_velocity() const;
-
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
- bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
-
- bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
-
- void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
- bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
-
- void set_safe_margin(float p_margin);
- float get_safe_margin() const;
-
- Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
- Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
- bool is_on_floor() const;
- bool is_on_wall() const;
- bool is_on_ceiling() const;
- Vector3 get_floor_normal() const;
- Vector3 get_floor_velocity() const;
-
- int get_slide_count() const;
- Collision get_slide_collision(int p_bounce) const;
-
- KinematicBody();
- ~KinematicBody();
-};
-
-class KinematicCollision : public Reference {
-
- GDCLASS(KinematicCollision, Reference);
-
- KinematicBody *owner;
- friend class KinematicBody;
- KinematicBody::Collision collision;
-
-protected:
- static void _bind_methods();
-
-public:
- Vector3 get_position() const;
- Vector3 get_normal() const;
- Vector3 get_travel() const;
- Vector3 get_remainder() const;
- Object *get_local_shape() const;
- Object *get_collider() const;
- ObjectID get_collider_id() const;
- Object *get_collider_shape() const;
- int get_collider_shape_index() const;
- Vector3 get_collider_velocity() const;
- Variant get_collider_metadata() const;
-
- KinematicCollision();
-};
-
-class PhysicalBone : public PhysicsBody {
-
- GDCLASS(PhysicalBone, PhysicsBody);
-
-public:
- enum JointType {
- JOINT_TYPE_NONE,
- JOINT_TYPE_PIN,
- JOINT_TYPE_CONE,
- JOINT_TYPE_HINGE,
- JOINT_TYPE_SLIDER,
- JOINT_TYPE_6DOF
- };
-
- struct JointData {
- virtual JointType get_joint_type() { return JOINT_TYPE_NONE; }
-
- /// "j" is used to set the parameter inside the PhysicsServer
- virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
- virtual bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
-
- virtual ~JointData() {}
- };
-
- struct PinJointData : public JointData {
- virtual JointType get_joint_type() { return JOINT_TYPE_PIN; }
-
- virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
- virtual bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
-
- real_t bias;
- real_t damping;
- real_t impulse_clamp;
-
- PinJointData() :
- bias(0.3),
- damping(1.),
- impulse_clamp(0) {}
- };
-
- struct ConeJointData : public JointData {
- virtual JointType get_joint_type() { return JOINT_TYPE_CONE; }
-
- virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
- virtual bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
-
- real_t swing_span;
- real_t twist_span;
- real_t bias;
- real_t softness;
- real_t relaxation;
-
- ConeJointData() :
- swing_span(Math_PI * 0.25),
- twist_span(Math_PI),
- bias(0.3),
- softness(0.8),
- relaxation(1.) {}
- };
-
- struct HingeJointData : public JointData {
- virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; }
-
- virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
- virtual bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
-
- bool angular_limit_enabled;
- real_t angular_limit_upper;
- real_t angular_limit_lower;
- real_t angular_limit_bias;
- real_t angular_limit_softness;
- real_t angular_limit_relaxation;
-
- HingeJointData() :
- angular_limit_enabled(false),
- angular_limit_upper(Math_PI * 0.5),
- angular_limit_lower(-Math_PI * 0.5),
- angular_limit_bias(0.3),
- angular_limit_softness(0.9),
- angular_limit_relaxation(1.) {}
- };
-
- struct SliderJointData : public JointData {
- virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; }
-
- virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
- virtual bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
-
- real_t linear_limit_upper;
- real_t linear_limit_lower;
- real_t linear_limit_softness;
- real_t linear_limit_restitution;
- real_t linear_limit_damping;
- real_t angular_limit_upper;
- real_t angular_limit_lower;
- real_t angular_limit_softness;
- real_t angular_limit_restitution;
- real_t angular_limit_damping;
-
- SliderJointData() :
- linear_limit_upper(1.),
- linear_limit_lower(-1.),
- linear_limit_softness(1.),
- linear_limit_restitution(0.7),
- linear_limit_damping(1.),
- angular_limit_upper(0),
- angular_limit_lower(0),
- angular_limit_softness(1.),
- angular_limit_restitution(0.7),
- angular_limit_damping(1.) {}
- };
-
- struct SixDOFJointData : public JointData {
- struct SixDOFAxisData {
- bool linear_limit_enabled;
- real_t linear_limit_upper;
- real_t linear_limit_lower;
- real_t linear_limit_softness;
- real_t linear_restitution;
- real_t linear_damping;
- bool linear_spring_enabled;
- real_t linear_spring_stiffness;
- real_t linear_spring_damping;
- real_t linear_equilibrium_point;
- bool angular_limit_enabled;
- real_t angular_limit_upper;
- real_t angular_limit_lower;
- real_t angular_limit_softness;
- real_t angular_restitution;
- real_t angular_damping;
- real_t erp;
- bool angular_spring_enabled;
- real_t angular_spring_stiffness;
- real_t angular_spring_damping;
- real_t angular_equilibrium_point;
-
- SixDOFAxisData() :
- linear_limit_enabled(true),
- linear_limit_upper(0),
- linear_limit_lower(0),
- linear_limit_softness(0.7),
- linear_restitution(0.5),
- linear_damping(1.),
- linear_spring_enabled(false),
- linear_spring_stiffness(0),
- linear_spring_damping(0),
- linear_equilibrium_point(0),
- angular_limit_enabled(true),
- angular_limit_upper(0),
- angular_limit_lower(0),
- angular_limit_softness(0.5),
- angular_restitution(0),
- angular_damping(1.),
- erp(0.5),
- angular_spring_enabled(false),
- angular_spring_stiffness(0),
- angular_spring_damping(0.),
- angular_equilibrium_point(0) {}
- };
-
- virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; }
-
- virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
- virtual bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
-
- SixDOFAxisData axis_data[3];
-
- SixDOFJointData() {}
- };
-
-private:
-#ifdef TOOLS_ENABLED
- // if false gizmo move body
- bool gizmo_move_joint;
-#endif
-
- JointData *joint_data;
- Transform joint_offset;
- RID joint;
-
- Skeleton *parent_skeleton;
- Transform body_offset;
- Transform body_offset_inverse;
- bool simulate_physics;
- bool _internal_simulate_physics;
- int bone_id;
-
- String bone_name;
- real_t bounce;
- real_t mass;
- real_t friction;
- real_t gravity_scale;
-
-protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
- void _notification(int p_what);
- void _direct_state_changed(Object *p_state);
-
- static void _bind_methods();
-
-private:
- static Skeleton *find_skeleton_parent(Node *p_parent);
-
- void _fix_joint_offset();
- void _reload_joint();
-
-public:
- void _on_bone_parent_changed();
- void _set_gizmo_move_joint(bool p_move_joint);
-
-public:
-#ifdef TOOLS_ENABLED
- virtual Transform get_global_gizmo_transform() const;
- virtual Transform get_local_gizmo_transform() const;
-#endif
-
- const JointData *get_joint_data() const;
- Skeleton *find_skeleton_parent();
-
- int get_bone_id() const { return bone_id; }
-
- void set_joint_type(JointType p_joint_type);
- JointType get_joint_type() const;
-
- void set_joint_offset(const Transform &p_offset);
- const Transform &get_joint_offset() const;
-
- void set_body_offset(const Transform &p_offset);
- const Transform &get_body_offset() const;
-
- void set_simulate_physics(bool p_simulate);
- bool get_simulate_physics();
- bool is_simulating_physics();
-
- void set_bone_name(const String &p_name);
- const String &get_bone_name() const;
-
- void set_mass(real_t p_mass);
- real_t get_mass() const;
-
- void set_weight(real_t p_weight);
- real_t get_weight() const;
-
- void set_friction(real_t p_friction);
- real_t get_friction() const;
-
- void set_bounce(real_t p_bounce);
- real_t get_bounce() const;
-
- void set_gravity_scale(real_t p_gravity_scale);
- real_t get_gravity_scale() const;
-
- void apply_central_impulse(const Vector3 &p_impulse);
- void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
-
- void reset_physics_simulation_state();
- void reset_to_rest_position();
-
- PhysicalBone();
- ~PhysicalBone();
-
-private:
- void update_bone_id();
- void update_offset();
-
- void _start_physics_simulation();
- void _stop_physics_simulation();
-};
-
-VARIANT_ENUM_CAST(PhysicalBone::JointType);
-
-#endif // PHYSICS_BODY__H
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
new file mode 100644
index 0000000000..72d1762ab5
--- /dev/null
+++ b/scene/3d/physics_body_3d.cpp
@@ -0,0 +1,2680 @@
+/*************************************************************************/
+/* physics_body_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_body_3d.h"
+
+#include "core/core_string_names.h"
+#include "core/engine.h"
+#include "core/list.h"
+#include "core/method_bind_ext.gen.inc"
+#include "core/object.h"
+#include "core/rid.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/scene_string_names.h"
+#include "servers/navigation_server_3d.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/plugins/node_3d_editor_plugin.h"
+#endif
+
+Vector3 PhysicsBody3D::get_linear_velocity() const {
+
+ return Vector3();
+}
+Vector3 PhysicsBody3D::get_angular_velocity() const {
+
+ return Vector3();
+}
+
+float 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);
+}
+
+Array PhysicsBody3D::get_collision_exceptions() {
+ List<RID> exceptions;
+ PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
+ Array ret;
+ for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
+ RID body = E->get();
+ ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body);
+ Object *obj = ObjectDB::get_instance(instance_id);
+ PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj);
+ ret.append(physics_body);
+ }
+ return ret;
+}
+
+void PhysicsBody3D::add_collision_exception_with(Node *p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ PhysicsServer3D::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid());
+}
+
+void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
+}
+
+void PhysicsBody3D::_set_layers(uint32_t p_mask) {
+ set_collision_layer(p_mask);
+ set_collision_mask(p_mask);
+}
+
+uint32_t PhysicsBody3D::_get_layers() const {
+
+ return get_collision_layer();
+}
+
+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);
+
+ ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody3D::_set_layers);
+ ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody3D::_get_layers);
+
+ 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");
+}
+
+PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
+ CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(p_mode), false) {
+
+ collision_layer = 1;
+ collision_mask = 1;
+}
+
+void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody3D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody3D::_reload_physics_characteristics));
+ }
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &StaticBody3D::_reload_physics_characteristics));
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const {
+ return physics_material_override;
+}
+
+void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) {
+
+ constant_linear_velocity = p_vel;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
+}
+
+void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) {
+
+ constant_angular_velocity = p_vel;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
+}
+
+Vector3 StaticBody3D::get_constant_linear_velocity() const {
+
+ return constant_linear_velocity;
+}
+Vector3 StaticBody3D::get_constant_angular_velocity() const {
+
+ return constant_angular_velocity;
+}
+
+void StaticBody3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions);
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
+}
+
+StaticBody3D::StaticBody3D() :
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) {
+}
+
+StaticBody3D::~StaticBody3D() {}
+
+void StaticBody3D::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
+}
+
+void RigidBody3D::_body_enter_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!node);
+
+ ERR_FAIL_COND(!contact_monitor);
+ Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(E->get().in_tree);
+
+ E->get().in_tree = true;
+
+ contact_monitor->locked = true;
+
+ emit_signal(SceneStringNames::get_singleton()->body_entered, node);
+
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
+ }
+
+ contact_monitor->locked = false;
+}
+
+void RigidBody3D::_body_exit_tree(ObjectID p_id) {
+
+ Object *obj = ObjectDB::get_instance(p_id);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!node);
+ ERR_FAIL_COND(!contact_monitor);
+ Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ ERR_FAIL_COND(!E->get().in_tree);
+ E->get().in_tree = false;
+
+ contact_monitor->locked = true;
+
+ emit_signal(SceneStringNames::get_singleton()->body_exited, node);
+
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_id, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
+ }
+
+ contact_monitor->locked = false;
+}
+
+void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+
+ bool body_in = p_status == 1;
+ ObjectID objid = p_instance;
+
+ Object *obj = ObjectDB::get_instance(objid);
+ Node *node = Object::cast_to<Node>(obj);
+
+ ERR_FAIL_COND(!contact_monitor);
+ Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
+
+ ERR_FAIL_COND(!body_in && !E);
+
+ if (body_in) {
+ if (!E) {
+
+ E = contact_monitor->body_map.insert(objid, BodyState());
+ //E->get().rc=0;
+ E->get().in_tree = node && node->is_inside_tree();
+ if (node) {
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree), make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree), make_binds(objid));
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->body_entered, node);
+ }
+ }
+ }
+ //E->get().rc++;
+ if (node)
+ E->get().shapes.insert(ShapePair(p_body_shape, p_local_shape));
+
+ if (E->get().in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, objid, node, p_body_shape, p_local_shape);
+ }
+
+ } else {
+
+ //E->get().rc--;
+
+ if (node)
+ E->get().shapes.erase(ShapePair(p_body_shape, p_local_shape));
+
+ bool in_tree = E->get().in_tree;
+
+ if (E->get().shapes.empty()) {
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
+ if (in_tree)
+ emit_signal(SceneStringNames::get_singleton()->body_exited, node);
+ }
+
+ contact_monitor->body_map.erase(E);
+ }
+ if (node && in_tree) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_local_shape);
+ }
+ }
+}
+
+struct _RigidBodyInOut {
+
+ ObjectID id;
+ int shape;
+ int local_shape;
+};
+
+void RigidBody3D::_direct_state_changed(Object *p_state) {
+
+#ifdef DEBUG_ENABLED
+ state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+#else
+ state = (PhysicsDirectBodyState3D *)p_state; //trust it
+#endif
+
+ set_ignore_transform_notification(true);
+ set_global_transform(state->get_transform());
+ linear_velocity = state->get_linear_velocity();
+ angular_velocity = state->get_angular_velocity();
+ if (sleeping != state->is_sleeping()) {
+ sleeping = state->is_sleeping();
+ emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
+ }
+ if (get_script_instance())
+ get_script_instance()->call("_integrate_forces", state);
+ set_ignore_transform_notification(false);
+
+ if (contact_monitor) {
+
+ contact_monitor->locked = true;
+
+ //untag all
+ int rc = 0;
+ for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
+
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ E->get().shapes[i].tagged = false;
+ rc++;
+ }
+ }
+
+ _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(state->get_contact_count() * sizeof(_RigidBodyInOut));
+ int toadd_count = 0; //state->get_contact_count();
+ RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction));
+ int toremove_count = 0;
+
+ //put the ones to add
+
+ for (int i = 0; i < state->get_contact_count(); i++) {
+
+ ObjectID obj = state->get_contact_collider_id(i);
+ int local_shape = state->get_contact_local_shape(i);
+ int shape = state->get_contact_collider_shape(i);
+
+ //bool found=false;
+
+ Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
+ if (!E) {
+ toadd[toadd_count].local_shape = local_shape;
+ toadd[toadd_count].id = obj;
+ toadd[toadd_count].shape = shape;
+ toadd_count++;
+ continue;
+ }
+
+ ShapePair sp(shape, local_shape);
+ int idx = E->get().shapes.find(sp);
+ if (idx == -1) {
+
+ toadd[toadd_count].local_shape = local_shape;
+ toadd[toadd_count].id = obj;
+ toadd[toadd_count].shape = shape;
+ toadd_count++;
+ continue;
+ }
+
+ E->get().shapes[idx].tagged = true;
+ }
+
+ //put the ones to remove
+
+ for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
+
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+
+ if (!E->get().shapes[i].tagged) {
+
+ toremove[toremove_count].body_id = E->key();
+ toremove[toremove_count].pair = E->get().shapes[i];
+ toremove_count++;
+ }
+ }
+ }
+
+ //process remotions
+
+ 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
+
+ for (int i = 0; i < toadd_count; i++) {
+
+ _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape);
+ }
+
+ contact_monitor->locked = false;
+ }
+
+ state = nullptr;
+}
+
+void RigidBody3D::_notification(int p_what) {
+
+#ifdef TOOLS_ENABLED
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_notify_local_transform(true); //used for warnings and only in editor
+ }
+ }
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warning();
+ }
+ }
+
+#endif
+}
+
+void RigidBody3D::set_mode(Mode p_mode) {
+
+ mode = p_mode;
+ switch (p_mode) {
+
+ case MODE_RIGID: {
+
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID);
+ } break;
+ case MODE_STATIC: {
+
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC);
+
+ } break;
+ case MODE_CHARACTER: {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_CHARACTER);
+
+ } break;
+ case MODE_KINEMATIC: {
+
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
+ } break;
+ }
+ update_configuration_warning();
+}
+
+RigidBody3D::Mode RigidBody3D::get_mode() const {
+
+ return mode;
+}
+
+void RigidBody3D::set_mass(real_t p_mass) {
+
+ ERR_FAIL_COND(p_mass <= 0);
+ mass = p_mass;
+ _change_notify("mass");
+ _change_notify("weight");
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass);
+}
+real_t RigidBody3D::get_mass() const {
+
+ return mass;
+}
+
+void RigidBody3D::set_weight(real_t p_weight) {
+
+ set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
+}
+real_t RigidBody3D::get_weight() const {
+
+ return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
+}
+
+void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ }
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const {
+ return physics_material_override;
+}
+
+void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) {
+
+ gravity_scale = p_gravity_scale;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
+}
+real_t RigidBody3D::get_gravity_scale() const {
+
+ return gravity_scale;
+}
+
+void RigidBody3D::set_linear_damp(real_t p_linear_damp) {
+
+ ERR_FAIL_COND(p_linear_damp < -1);
+ linear_damp = p_linear_damp;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp);
+}
+real_t RigidBody3D::get_linear_damp() const {
+
+ return linear_damp;
+}
+
+void RigidBody3D::set_angular_damp(real_t p_angular_damp) {
+
+ ERR_FAIL_COND(p_angular_damp < -1);
+ angular_damp = p_angular_damp;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
+}
+real_t RigidBody3D::get_angular_damp() const {
+
+ return angular_damp;
+}
+
+void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) {
+
+ Vector3 v = state ? state->get_linear_velocity() : linear_velocity;
+ Vector3 axis = p_axis.normalized();
+ v -= axis * axis.dot(v);
+ v += p_axis;
+ if (state) {
+ set_linear_velocity(v);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
+ linear_velocity = v;
+ }
+}
+
+void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) {
+
+ linear_velocity = p_velocity;
+ if (state)
+ state->set_linear_velocity(linear_velocity);
+ else
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
+}
+
+Vector3 RigidBody3D::get_linear_velocity() const {
+
+ return linear_velocity;
+}
+
+void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) {
+
+ angular_velocity = p_velocity;
+ if (state)
+ state->set_angular_velocity(angular_velocity);
+ else
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
+}
+Vector3 RigidBody3D::get_angular_velocity() const {
+
+ return angular_velocity;
+}
+
+void RigidBody3D::set_use_custom_integrator(bool p_enable) {
+
+ if (custom_integrator == p_enable)
+ return;
+
+ custom_integrator = p_enable;
+ PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
+}
+bool RigidBody3D::is_using_custom_integrator() {
+
+ return custom_integrator;
+}
+
+void RigidBody3D::set_sleeping(bool p_sleeping) {
+
+ sleeping = p_sleeping;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping);
+}
+
+void RigidBody3D::set_can_sleep(bool p_active) {
+
+ can_sleep = p_active;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active);
+}
+
+bool RigidBody3D::is_able_to_sleep() const {
+
+ return can_sleep;
+}
+
+bool RigidBody3D::is_sleeping() const {
+
+ return sleeping;
+}
+
+void RigidBody3D::set_max_contacts_reported(int p_amount) {
+
+ max_contacts_reported = p_amount;
+ PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
+}
+
+int RigidBody3D::get_max_contacts_reported() const {
+
+ return max_contacts_reported;
+}
+
+void RigidBody3D::add_central_force(const Vector3 &p_force) {
+ PhysicsServer3D::get_singleton()->body_add_central_force(get_rid(), p_force);
+}
+
+void RigidBody3D::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
+ PhysicsServer3D::get_singleton()->body_add_force(get_rid(), p_force, p_pos);
+}
+
+void RigidBody3D::add_torque(const Vector3 &p_torque) {
+ PhysicsServer3D::get_singleton()->body_add_torque(get_rid(), p_torque);
+}
+
+void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+ PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
+}
+
+void RigidBody3D::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
+
+ PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
+}
+
+void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
+ PhysicsServer3D::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse);
+}
+
+void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) {
+
+ ccd = p_enable;
+ PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable);
+}
+
+bool RigidBody3D::is_using_continuous_collision_detection() const {
+
+ return ccd;
+}
+
+void RigidBody3D::set_contact_monitor(bool p_enabled) {
+
+ if (p_enabled == is_contact_monitor_enabled())
+ return;
+
+ if (!p_enabled) {
+
+ ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead.");
+
+ for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
+
+ //clean up mess
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = Object::cast_to<Node>(obj);
+
+ if (node) {
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
+ }
+ }
+
+ memdelete(contact_monitor);
+ contact_monitor = nullptr;
+ } else {
+
+ contact_monitor = memnew(ContactMonitor);
+ contact_monitor->locked = false;
+ }
+}
+
+bool RigidBody3D::is_contact_monitor_enabled() const {
+
+ return contact_monitor != nullptr;
+}
+
+void RigidBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
+ PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+}
+
+bool RigidBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
+ return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
+}
+
+Array RigidBody3D::get_colliding_bodies() const {
+
+ ERR_FAIL_COND_V(!contact_monitor, Array());
+
+ Array ret;
+ ret.resize(contact_monitor->body_map.size());
+ int idx = 0;
+ for (const Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
+ Object *obj = ObjectDB::get_instance(E->key());
+ if (!obj) {
+ ret.resize(ret.size() - 1); //ops
+ } else {
+ ret[idx++] = obj;
+ }
+ }
+
+ return ret;
+}
+
+String RigidBody3D::get_configuration_warning() const {
+
+ Transform t = get_transform();
+
+ String warning = CollisionObject3D::get_configuration_warning();
+
+ 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 != String()) {
+ 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.");
+ }
+
+ return warning;
+}
+
+void RigidBody3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &RigidBody3D::set_mode);
+ ClassDB::bind_method(D_METHOD("get_mode"), &RigidBody3D::get_mode);
+
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass);
+
+ ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody3D::set_weight);
+ ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody3D::get_weight);
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody3D::get_linear_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale);
+
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody3D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody3D::get_linear_damp);
+
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody3D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody3D::get_angular_damp);
+
+ ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody3D::set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody3D::get_max_contacts_reported);
+
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody3D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody3D::is_using_custom_integrator);
+
+ ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody3D::set_contact_monitor);
+ ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody3D::is_contact_monitor_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody3D::set_use_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody3D::is_using_continuous_collision_detection);
+
+ ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity);
+
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody3D::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody3D::add_force);
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody3D::add_torque);
+
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody3D::apply_impulse);
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse);
+
+ ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody3D::is_sleeping);
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
+
+ BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D")));
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
+ ADD_GROUP("Axis Lock", "axis_lock_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z);
+ ADD_GROUP("Linear", "linear_");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
+ ADD_GROUP("Angular", "angular_");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
+
+ 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("sleeping_state_changed"));
+
+ BIND_ENUM_CONSTANT(MODE_RIGID);
+ BIND_ENUM_CONSTANT(MODE_STATIC);
+ BIND_ENUM_CONSTANT(MODE_CHARACTER);
+ BIND_ENUM_CONSTANT(MODE_KINEMATIC);
+}
+
+RigidBody3D::RigidBody3D() :
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
+
+ mode = MODE_RIGID;
+
+ mass = 1;
+ max_contacts_reported = 0;
+ state = nullptr;
+
+ gravity_scale = 1;
+ linear_damp = -1;
+ angular_damp = -1;
+
+ //angular_velocity=0;
+ sleeping = false;
+ ccd = false;
+
+ custom_integrator = false;
+ contact_monitor = nullptr;
+ can_sleep = true;
+
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+}
+
+RigidBody3D::~RigidBody3D() {
+
+ if (contact_monitor)
+ memdelete(contact_monitor);
+}
+
+void RigidBody3D::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
+}
+
+//////////////////////////////////////////////////////
+//////////////////////////
+
+Ref<KinematicCollision3D> KinematicBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
+
+ Collision col;
+ if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) {
+ if (motion_cache.is_null()) {
+ motion_cache.instance();
+ motion_cache->owner = this;
+ }
+
+ motion_cache->collision = col;
+
+ return motion_cache;
+ }
+
+ return Ref<KinematicCollision3D>();
+}
+
+Vector3 KinematicBody3D::get_linear_velocity() const {
+ return linear_velocity;
+}
+
+Vector3 KinematicBody3D::get_angular_velocity() const {
+ return angular_velocity;
+}
+
+bool KinematicBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
+
+ Transform gt = get_global_transform();
+ PhysicsServer3D::MotionResult result;
+ bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes);
+
+ if (colliding) {
+ r_collision.collider_metadata = result.collider_metadata;
+ r_collision.collider_shape = result.collider_shape;
+ r_collision.collider_vel = result.collider_velocity;
+ r_collision.collision = result.collision_point;
+ r_collision.normal = result.collision_normal;
+ r_collision.collider = result.collider_id;
+ r_collision.collider_rid = result.collider;
+ r_collision.travel = result.motion;
+ r_collision.remainder = result.remainder;
+ r_collision.local_shape = result.collision_local_shape;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ if (locked_axis & (1 << i)) {
+ result.motion[i] = 0;
+ }
+ }
+
+ if (!p_test_only) {
+ gt.origin += result.motion;
+ set_global_transform(gt);
+ }
+
+ return colliding;
+}
+
+//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
+#define FLOOR_ANGLE_THRESHOLD 0.01
+
+Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
+
+ Vector3 body_velocity = p_linear_velocity;
+ Vector3 body_velocity_normal = body_velocity.normalized();
+
+ for (int i = 0; i < 3; i++) {
+ if (locked_axis & (1 << i)) {
+ body_velocity[i] = 0;
+ }
+ }
+
+ // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+ Vector3 motion = (floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
+
+ on_floor = false;
+ on_floor_body = RID();
+ on_ceiling = false;
+ on_wall = false;
+ colliders.clear();
+ floor_normal = Vector3();
+ floor_velocity = Vector3();
+
+ while (p_max_slides) {
+
+ Collision collision;
+ bool found_collision = false;
+
+ for (int i = 0; i < 2; ++i) {
+ bool collided;
+ if (i == 0) { //collide
+ collided = move_and_collide(motion, p_infinite_inertia, collision);
+ if (!collided) {
+ motion = Vector3(); //clear because no collision happened and motion completed
+ }
+ } else { //separate raycasts (if any)
+ collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ if (collided) {
+ collision.remainder = motion; //keep
+ collision.travel = Vector3();
+ }
+ }
+
+ if (collided) {
+ found_collision = true;
+
+ colliders.push_back(collision);
+ motion = collision.remainder;
+
+ if (p_up_direction == Vector3()) {
+ //all is a wall
+ on_wall = true;
+ } else {
+ if (Math::acos(collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+
+ on_floor = true;
+ floor_normal = collision.normal;
+ on_floor_body = collision.collider_rid;
+ floor_velocity = collision.collider_vel;
+
+ if (p_stop_on_slope) {
+ if ((body_velocity_normal + p_up_direction).length() < 0.01 && collision.travel.length() < 1) {
+ Transform gt = get_global_transform();
+ gt.origin -= collision.travel.slide(p_up_direction);
+ set_global_transform(gt);
+ return Vector3();
+ }
+ }
+ } else if (Math::acos(collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
+ }
+ }
+
+ motion = motion.slide(collision.normal);
+ body_velocity = body_velocity.slide(collision.normal);
+
+ for (int j = 0; j < 3; j++) {
+ if (locked_axis & (1 << j)) {
+ body_velocity[j] = 0;
+ }
+ }
+ }
+ }
+
+ if (!found_collision || motion == Vector3())
+ break;
+
+ --p_max_slides;
+ }
+
+ return body_velocity;
+}
+
+Vector3 KinematicBody3D::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
+
+ bool was_on_floor = on_floor;
+
+ Vector3 ret = move_and_slide(p_linear_velocity, p_up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia);
+ if (!was_on_floor || p_snap == Vector3()) {
+ return ret;
+ }
+
+ Collision col;
+ Transform gt = get_global_transform();
+
+ if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
+
+ bool apply = true;
+ if (p_up_direction != Vector3()) {
+ if (Math::acos(p_up_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
+ on_floor = true;
+ floor_normal = col.normal;
+ on_floor_body = col.collider_rid;
+ floor_velocity = col.collider_vel;
+ if (p_stop_on_slope) {
+ // move and collide may stray the object a bit because of pre un-stucking,
+ // so only ensure that motion happens on floor direction in this case.
+ col.travel = col.travel.project(p_up_direction);
+ }
+ } else {
+ apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
+ }
+ }
+ if (apply) {
+ gt.origin += col.travel;
+ set_global_transform(gt);
+ }
+ }
+
+ return ret;
+}
+
+bool KinematicBody3D::is_on_floor() const {
+
+ return on_floor;
+}
+
+bool KinematicBody3D::is_on_wall() const {
+
+ return on_wall;
+}
+bool KinematicBody3D::is_on_ceiling() const {
+
+ return on_ceiling;
+}
+
+Vector3 KinematicBody3D::get_floor_normal() const {
+
+ return floor_normal;
+}
+
+Vector3 KinematicBody3D::get_floor_velocity() const {
+
+ return floor_velocity;
+}
+
+bool KinematicBody3D::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+
+ return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
+}
+
+bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
+
+ PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
+
+ Transform gt = get_global_transform();
+
+ Vector3 recover;
+ int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ int deepest = -1;
+ float deepest_depth;
+ for (int i = 0; i < hits; i++) {
+ if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
+ deepest = i;
+ deepest_depth = sep_res[i].collision_depth;
+ }
+ }
+
+ gt.origin += recover;
+ set_global_transform(gt);
+
+ if (deepest != -1) {
+ r_collision.collider = sep_res[deepest].collider_id;
+ r_collision.collider_metadata = sep_res[deepest].collider_metadata;
+ r_collision.collider_shape = sep_res[deepest].collider_shape;
+ r_collision.collider_vel = sep_res[deepest].collider_velocity;
+ r_collision.collision = sep_res[deepest].collision_point;
+ r_collision.normal = sep_res[deepest].collision_normal;
+ r_collision.local_shape = sep_res[deepest].collision_local_shape;
+ r_collision.travel = recover;
+ r_collision.remainder = Vector3();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void KinematicBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
+ PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+}
+
+bool KinematicBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
+ return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
+}
+
+void KinematicBody3D::set_safe_margin(float p_margin) {
+
+ margin = p_margin;
+ PhysicsServer3D::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin);
+}
+
+float KinematicBody3D::get_safe_margin() const {
+
+ return margin;
+}
+int KinematicBody3D::get_slide_count() const {
+
+ return colliders.size();
+}
+
+KinematicBody3D::Collision KinematicBody3D::get_slide_collision(int p_bounce) const {
+ ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision());
+ return colliders[p_bounce];
+}
+
+Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) {
+
+ ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision3D>());
+ if (p_bounce >= slide_colliders.size()) {
+ slide_colliders.resize(p_bounce + 1);
+ }
+
+ if (slide_colliders[p_bounce].is_null()) {
+ slide_colliders.write[p_bounce].instance();
+ slide_colliders.write[p_bounce]->owner = this;
+ }
+
+ slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
+ return slide_colliders[p_bounce];
+}
+
+void KinematicBody3D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ // Reset move_and_slide() data.
+ on_floor = false;
+ on_floor_body = RID();
+ on_ceiling = false;
+ on_wall = false;
+ colliders.clear();
+ floor_velocity = Vector3();
+ }
+}
+
+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((float)45)), 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((float)45)), DEFVAL(true));
+
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody3D::test_move, DEFVAL(true));
+
+ ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody3D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody3D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody3D::is_on_wall);
+ ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody3D::get_floor_normal);
+ ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody3D::get_floor_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody3D::set_axis_lock);
+ ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &KinematicBody3D::get_axis_lock);
+
+ ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody3D::set_safe_margin);
+ ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody3D::get_safe_margin);
+
+ ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody3D::get_slide_count);
+ ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody3D::_get_slide_collision);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
+}
+
+void KinematicBody3D::_direct_state_changed(Object *p_state) {
+#ifdef DEBUG_ENABLED
+ PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+#else
+ PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it
+#endif
+
+ linear_velocity = state->get_linear_velocity();
+ angular_velocity = state->get_angular_velocity();
+}
+
+KinematicBody3D::KinematicBody3D() :
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
+
+ margin = 0.001;
+ locked_axis = 0;
+ on_floor = false;
+ on_ceiling = false;
+ on_wall = false;
+
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+}
+KinematicBody3D::~KinematicBody3D() {
+
+ if (motion_cache.is_valid()) {
+ motion_cache->owner = nullptr;
+ }
+
+ for (int i = 0; i < slide_colliders.size(); i++) {
+ if (slide_colliders[i].is_valid()) {
+ slide_colliders.write[i]->owner = nullptr;
+ }
+ }
+}
+///////////////////////////////////////
+
+Vector3 KinematicCollision3D::get_position() const {
+
+ return collision.collision;
+}
+Vector3 KinematicCollision3D::get_normal() const {
+ return collision.normal;
+}
+Vector3 KinematicCollision3D::get_travel() const {
+ return collision.travel;
+}
+Vector3 KinematicCollision3D::get_remainder() const {
+ return collision.remainder;
+}
+Object *KinematicCollision3D::get_local_shape() const {
+ if (!owner) return nullptr;
+ uint32_t ownerid = owner->shape_find_owner(collision.local_shape);
+ return owner->shape_owner_get_owner(ownerid);
+}
+
+Object *KinematicCollision3D::get_collider() const {
+
+ if (collision.collider.is_valid()) {
+ return ObjectDB::get_instance(collision.collider);
+ }
+
+ return nullptr;
+}
+ObjectID KinematicCollision3D::get_collider_id() const {
+
+ return collision.collider;
+}
+Object *KinematicCollision3D::get_collider_shape() const {
+
+ Object *collider = get_collider();
+ if (collider) {
+ CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider);
+ if (obj2d) {
+ uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape);
+ return obj2d->shape_owner_get_owner(ownerid);
+ }
+ }
+
+ return nullptr;
+}
+int KinematicCollision3D::get_collider_shape_index() const {
+
+ return collision.collider_shape;
+}
+Vector3 KinematicCollision3D::get_collider_velocity() const {
+
+ return collision.collider_vel;
+}
+Variant KinematicCollision3D::get_collider_metadata() const {
+
+ return Variant();
+}
+
+void KinematicCollision3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision3D::get_position);
+ ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision3D::get_normal);
+ ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel);
+ ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder);
+ ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision3D::get_local_shape);
+ ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision3D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision3D::get_collider_id);
+ ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision3D::get_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision3D::get_collider_shape_index);
+ ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision3D::get_collider_velocity);
+ ClassDB::bind_method(D_METHOD("get_collider_metadata"), &KinematicCollision3D::get_collider_metadata);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "", "get_normal");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata");
+}
+
+KinematicCollision3D::KinematicCollision3D() {
+
+ collision.collider_shape = 0;
+ collision.local_shape = 0;
+ owner = nullptr;
+}
+
+///////////////////////////////////////
+
+bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ return false;
+}
+
+bool PhysicalBone3D::JointData::_get(const StringName &p_name, Variant &r_ret) const {
+ return false;
+}
+
+void PhysicalBone3D::JointData::_get_property_list(List<PropertyInfo> *p_list) const {
+}
+
+void PhysicalBone3D::apply_central_impulse(const Vector3 &p_impulse) {
+ PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
+}
+
+void PhysicalBone3D::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
+ PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
+}
+
+void PhysicalBone3D::reset_physics_simulation_state() {
+ if (simulate_physics) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
+}
+
+void PhysicalBone3D::reset_to_rest_position() {
+ if (parent_skeleton) {
+ if (-1 == bone_id) {
+ set_global_transform(parent_skeleton->get_global_transform() * body_offset);
+ } else {
+ set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset);
+ }
+ }
+}
+
+bool PhysicalBone3D::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/bias" == p_name) {
+ bias = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_BIAS, bias);
+
+ } else if ("joint_constraints/damping" == p_name) {
+ damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_DAMPING, damping);
+
+ } else if ("joint_constraints/impulse_clamp" == p_name) {
+ impulse_clamp = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone3D::PinJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/bias" == p_name) {
+ r_ret = bias;
+ } else if ("joint_constraints/damping" == p_name) {
+ r_ret = damping;
+ } else if ("joint_constraints/impulse_clamp" == p_name) {
+ r_ret = impulse_clamp;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone3D::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"));
+}
+
+bool PhysicalBone3D::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/swing_span" == p_name) {
+ swing_span = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, swing_span);
+
+ } else if ("joint_constraints/twist_span" == p_name) {
+ twist_span = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, twist_span);
+
+ } else if ("joint_constraints/bias" == p_name) {
+ bias = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, bias);
+
+ } else if ("joint_constraints/softness" == p_name) {
+ softness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, softness);
+
+ } else if ("joint_constraints/relaxation" == p_name) {
+ relaxation = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, relaxation);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone3D::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/swing_span" == p_name) {
+ r_ret = Math::rad2deg(swing_span);
+ } else if ("joint_constraints/twist_span" == p_name) {
+ r_ret = Math::rad2deg(twist_span);
+ } else if ("joint_constraints/bias" == p_name) {
+ r_ret = bias;
+ } else if ("joint_constraints/softness" == p_name) {
+ r_ret = softness;
+ } else if ("joint_constraints/relaxation" == p_name) {
+ r_ret = relaxation;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone3D::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+}
+
+bool PhysicalBone3D::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/angular_limit_enabled" == p_name) {
+ angular_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_flag(j, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled);
+
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper);
+
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower);
+
+ } else if ("joint_constraints/angular_limit_bias" == p_name) {
+ angular_limit_bias = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias);
+
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
+ angular_limit_relaxation = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone3D::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/angular_limit_enabled" == p_name) {
+ r_ret = angular_limit_enabled;
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_upper);
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_lower);
+ } else if ("joint_constraints/angular_limit_bias" == p_name) {
+ r_ret = angular_limit_bias;
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ r_ret = angular_limit_softness;
+ } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
+ r_ret = angular_limit_relaxation;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone3D::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/angular_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+}
+
+bool PhysicalBone3D::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/linear_limit_upper" == p_name) {
+ linear_limit_upper = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper);
+
+ } else if ("joint_constraints/linear_limit_lower" == p_name) {
+ linear_limit_lower = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower);
+
+ } else if ("joint_constraints/linear_limit_softness" == p_name) {
+ linear_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness);
+
+ } else if ("joint_constraints/linear_limit_restitution" == p_name) {
+ linear_limit_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution);
+
+ } else if ("joint_constraints/linear_limit_damping" == p_name) {
+ linear_limit_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution);
+
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper);
+
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower);
+
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_restitution" == p_name) {
+ angular_limit_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_damping" == p_name) {
+ angular_limit_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone3D::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/linear_limit_upper" == p_name) {
+ r_ret = linear_limit_upper;
+ } else if ("joint_constraints/linear_limit_lower" == p_name) {
+ r_ret = linear_limit_lower;
+ } else if ("joint_constraints/linear_limit_softness" == p_name) {
+ r_ret = linear_limit_softness;
+ } else if ("joint_constraints/linear_limit_restitution" == p_name) {
+ r_ret = linear_limit_restitution;
+ } else if ("joint_constraints/linear_limit_damping" == p_name) {
+ r_ret = linear_limit_damping;
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_upper);
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_lower);
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ r_ret = angular_limit_softness;
+ } else if ("joint_constraints/angular_limit_restitution" == p_name) {
+ r_ret = angular_limit_restitution;
+ } else if ("joint_constraints/angular_limit_damping" == p_name) {
+ r_ret = angular_limit_damping;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone3D::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_upper"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_lower"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
+
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
+}
+
+bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ String path = p_name;
+
+ Vector3::Axis axis;
+ {
+ const String axis_s = path.get_slicec('/', 1);
+ if ("x" == axis_s) {
+ axis = Vector3::AXIS_X;
+ } else if ("y" == axis_s) {
+ axis = Vector3::AXIS_Y;
+ } else if ("z" == axis_s) {
+ axis = Vector3::AXIS_Z;
+ } else {
+ return false;
+ }
+ }
+
+ String var_name = path.get_slicec('/', 2);
+
+ if ("linear_limit_enabled" == var_name) {
+ axis_data[axis].linear_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled);
+
+ } else if ("linear_limit_upper" == var_name) {
+ axis_data[axis].linear_limit_upper = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper);
+
+ } else if ("linear_limit_lower" == var_name) {
+ axis_data[axis].linear_limit_lower = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower);
+
+ } else if ("linear_limit_softness" == var_name) {
+ axis_data[axis].linear_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness);
+
+ } else if ("linear_spring_enabled" == var_name) {
+ axis_data[axis].linear_spring_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, axis_data[axis].linear_spring_enabled);
+
+ } else if ("linear_spring_stiffness" == var_name) {
+ axis_data[axis].linear_spring_stiffness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, axis_data[axis].linear_spring_stiffness);
+
+ } else if ("linear_spring_damping" == var_name) {
+ axis_data[axis].linear_spring_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, axis_data[axis].linear_spring_damping);
+
+ } else if ("linear_equilibrium_point" == var_name) {
+ axis_data[axis].linear_equilibrium_point = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].linear_equilibrium_point);
+
+ } else if ("linear_restitution" == var_name) {
+ axis_data[axis].linear_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution);
+
+ } else if ("linear_damping" == var_name) {
+ axis_data[axis].linear_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping);
+
+ } else if ("angular_limit_enabled" == var_name) {
+ axis_data[axis].angular_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled);
+
+ } else if ("angular_limit_upper" == var_name) {
+ axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper);
+
+ } else if ("angular_limit_lower" == var_name) {
+ axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower);
+
+ } else if ("angular_limit_softness" == var_name) {
+ axis_data[axis].angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness);
+
+ } else if ("angular_restitution" == var_name) {
+ axis_data[axis].angular_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution);
+
+ } else if ("angular_damping" == var_name) {
+ axis_data[axis].angular_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping);
+
+ } else if ("erp" == var_name) {
+ axis_data[axis].erp = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp);
+
+ } else if ("angular_spring_enabled" == var_name) {
+ axis_data[axis].angular_spring_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, axis_data[axis].angular_spring_enabled);
+
+ } else if ("angular_spring_stiffness" == var_name) {
+ axis_data[axis].angular_spring_stiffness = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, axis_data[axis].angular_spring_stiffness);
+
+ } else if ("angular_spring_damping" == var_name) {
+ axis_data[axis].angular_spring_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, axis_data[axis].angular_spring_damping);
+
+ } else if ("angular_equilibrium_point" == var_name) {
+ axis_data[axis].angular_equilibrium_point = p_value;
+ if (j.is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].angular_equilibrium_point);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone3D::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ String path = p_name;
+
+ int axis;
+ {
+ const String axis_s = path.get_slicec('/', 1);
+ if ("x" == axis_s) {
+ axis = 0;
+ } else if ("y" == axis_s) {
+ axis = 1;
+ } else if ("z" == axis_s) {
+ axis = 2;
+ } else {
+ return false;
+ }
+ }
+
+ String var_name = path.get_slicec('/', 2);
+
+ if ("linear_limit_enabled" == var_name) {
+ r_ret = axis_data[axis].linear_limit_enabled;
+ } else if ("linear_limit_upper" == var_name) {
+ r_ret = axis_data[axis].linear_limit_upper;
+ } else if ("linear_limit_lower" == var_name) {
+ r_ret = axis_data[axis].linear_limit_lower;
+ } else if ("linear_limit_softness" == var_name) {
+ r_ret = axis_data[axis].linear_limit_softness;
+ } else if ("linear_spring_enabled" == var_name) {
+ r_ret = axis_data[axis].linear_spring_enabled;
+ } else if ("linear_spring_stiffness" == var_name) {
+ r_ret = axis_data[axis].linear_spring_stiffness;
+ } else if ("linear_spring_damping" == var_name) {
+ r_ret = axis_data[axis].linear_spring_damping;
+ } else if ("linear_equilibrium_point" == var_name) {
+ r_ret = axis_data[axis].linear_equilibrium_point;
+ } else if ("linear_restitution" == var_name) {
+ r_ret = axis_data[axis].linear_restitution;
+ } else if ("linear_damping" == var_name) {
+ r_ret = axis_data[axis].linear_damping;
+ } else if ("angular_limit_enabled" == var_name) {
+ r_ret = axis_data[axis].angular_limit_enabled;
+ } else if ("angular_limit_upper" == var_name) {
+ r_ret = Math::rad2deg(axis_data[axis].angular_limit_upper);
+ } else if ("angular_limit_lower" == var_name) {
+ r_ret = Math::rad2deg(axis_data[axis].angular_limit_lower);
+ } else if ("angular_limit_softness" == var_name) {
+ r_ret = axis_data[axis].angular_limit_softness;
+ } else if ("angular_restitution" == var_name) {
+ r_ret = axis_data[axis].angular_restitution;
+ } else if ("angular_damping" == var_name) {
+ r_ret = axis_data[axis].angular_damping;
+ } else if ("erp" == var_name) {
+ r_ret = axis_data[axis].erp;
+ } else if ("angular_spring_enabled" == var_name) {
+ r_ret = axis_data[axis].angular_spring_enabled;
+ } else if ("angular_spring_stiffness" == var_name) {
+ r_ret = axis_data[axis].angular_spring_stiffness;
+ } else if ("angular_spring_damping" == var_name) {
+ r_ret = axis_data[axis].angular_spring_damping;
+ } else if ("angular_equilibrium_point" == var_name) {
+ r_ret = axis_data[axis].angular_equilibrium_point;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone3D::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ const StringName axis_names[] = { "x", "y", "z" };
+ for (int i = 0; i < 3; ++i) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_upper"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_lower"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_spring_enabled"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_spring_stiffness"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_spring_damping"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_equilibrium_point"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/erp"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_spring_enabled"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_spring_stiffness"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_spring_damping"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_constraints/" + axis_names[i] + "/angular_equilibrium_point"));
+ }
+}
+
+bool PhysicalBone3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "bone_name") {
+ set_bone_name(p_value);
+ return true;
+ }
+
+ if (joint_data) {
+ if (joint_data->_set(p_name, p_value)) {
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PhysicalBone3D::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "bone_name") {
+ r_ret = get_bone_name();
+ return true;
+ }
+
+ if (joint_data) {
+ return joint_data->_get(p_name, r_ret);
+ }
+
+ return false;
+}
+
+void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ Skeleton3D *parent = find_skeleton_parent(get_parent());
+
+ if (parent) {
+
+ String names;
+ for (int i = 0; i < parent->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += parent->get_bone_name(i);
+ }
+
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name", PROPERTY_HINT_ENUM, names));
+ } else {
+
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_name"));
+ }
+
+ if (joint_data) {
+ joint_data->_get_property_list(p_list);
+ }
+}
+
+void PhysicalBone3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ parent_skeleton = find_skeleton_parent(get_parent());
+ update_bone_id();
+ reset_to_rest_position();
+ reset_physics_simulation_state();
+ if (!joint.is_valid() && joint_data) {
+ _reload_joint();
+ }
+ break;
+ case NOTIFICATION_EXIT_TREE:
+ if (parent_skeleton) {
+ if (-1 != bone_id) {
+ parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ }
+ }
+ parent_skeleton = nullptr;
+ if (joint.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(joint);
+ joint = RID();
+ }
+ break;
+ case NOTIFICATION_TRANSFORM_CHANGED:
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ update_offset();
+ }
+ break;
+ }
+}
+
+void PhysicalBone3D::_direct_state_changed(Object *p_state) {
+
+ if (!simulate_physics || !_internal_simulate_physics) {
+ return;
+ }
+
+ /// Update bone transform
+
+ PhysicsDirectBodyState3D *state;
+
+#ifdef DEBUG_ENABLED
+ state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+#else
+ state = (PhysicsDirectBodyState3D *)p_state; //trust it
+#endif
+
+ Transform global_transform(state->get_transform());
+
+ set_ignore_transform_notification(true);
+ set_global_transform(global_transform);
+ set_ignore_transform_notification(false);
+
+ // Update skeleton
+ if (parent_skeleton) {
+ if (-1 != bone_id) {
+ parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true);
+ }
+ }
+}
+
+void PhysicalBone3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &PhysicalBone3D::apply_impulse);
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone3D::set_joint_offset);
+ ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone3D::get_joint_offset);
+ ClassDB::bind_method(D_METHOD("set_joint_rotation", "euler"), &PhysicalBone3D::set_joint_rotation);
+ ClassDB::bind_method(D_METHOD("get_joint_rotation"), &PhysicalBone3D::get_joint_rotation);
+ ClassDB::bind_method(D_METHOD("set_joint_rotation_degrees", "euler_degrees"), &PhysicalBone3D::set_joint_rotation_degrees);
+ ClassDB::bind_method(D_METHOD("get_joint_rotation_degrees"), &PhysicalBone3D::get_joint_rotation_degrees);
+
+ ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone3D::set_body_offset);
+ ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone3D::get_body_offset);
+
+ ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone3D::get_simulate_physics);
+
+ ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone3D::is_simulating_physics);
+
+ ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone3D::get_bone_id);
+
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone3D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone3D::get_mass);
+
+ ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone3D::set_weight);
+ ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone3D::get_weight);
+
+ ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone3D::set_friction);
+ ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone3D::get_friction);
+
+ ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone3D::set_bounce);
+ ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone3D::get_bounce);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone3D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone3D::get_gravity_scale);
+
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &PhysicalBone3D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &PhysicalBone3D::get_linear_damp);
+
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &PhysicalBone3D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &PhysicalBone3D::get_angular_damp);
+
+ ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep);
+ ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep);
+
+ ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicalBone3D::set_axis_lock);
+ ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicalBone3D::get_axis_lock);
+
+ ADD_GROUP("Joint", "joint_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_joint_rotation_degrees", "get_joint_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_NONE, "", 0), "set_joint_rotation", "get_joint_rotation");
+
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
+
+ ADD_GROUP("Axis Lock", "axis_lock_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z);
+
+ BIND_ENUM_CONSTANT(JOINT_TYPE_NONE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_CONE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF);
+}
+
+Skeleton3D *PhysicalBone3D::find_skeleton_parent(Node *p_parent) {
+ if (!p_parent) {
+ return nullptr;
+ }
+ Skeleton3D *s = Object::cast_to<Skeleton3D>(p_parent);
+ return s ? s : find_skeleton_parent(p_parent->get_parent());
+}
+
+void PhysicalBone3D::_update_joint_offset() {
+ _fix_joint_offset();
+
+ set_ignore_transform_notification(true);
+ reset_to_rest_position();
+ set_ignore_transform_notification(false);
+
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+void PhysicalBone3D::_fix_joint_offset() {
+ // Clamp joint origin to bone origin
+ if (parent_skeleton) {
+ joint_offset.origin = body_offset.affine_inverse().origin;
+ }
+}
+
+void PhysicalBone3D::_reload_joint() {
+
+ if (joint.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(joint);
+ joint = RID();
+ }
+
+ if (!parent_skeleton) {
+ return;
+ }
+
+ PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id);
+ if (!body_a) {
+ return;
+ }
+
+ Transform joint_transf = get_global_transform() * joint_offset;
+ Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
+ local_a.orthonormalize();
+
+ 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);
+ 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);
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp);
+
+ } break;
+ case JOINT_TYPE_CONE: {
+
+ joint = PhysicsServer3D::get_singleton()->joint_create_cone_twist(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);
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, cjd->bias);
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, cjd->softness);
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation);
+
+ } break;
+ case JOINT_TYPE_HINGE: {
+
+ joint = PhysicsServer3D::get_singleton()->joint_create_hinge(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);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation);
+
+ } break;
+ case JOINT_TYPE_SLIDER: {
+
+ joint = PhysicsServer3D::get_singleton()->joint_create_slider(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);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping);
+
+ } break;
+ case JOINT_TYPE_6DOF: {
+
+ joint = PhysicsServer3D::get_singleton()->joint_create_generic_6dof(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);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, g6dofjd->axis_data[axis].linear_spring_enabled);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].linear_spring_stiffness);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, g6dofjd->axis_data[axis].linear_spring_damping);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].linear_equilibrium_point);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, g6dofjd->axis_data[axis].angular_spring_enabled);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].angular_spring_stiffness);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, g6dofjd->axis_data[axis].angular_spring_damping);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].angular_equilibrium_point);
+ }
+
+ } break;
+ case JOINT_TYPE_NONE: {
+ } break;
+ }
+}
+
+void PhysicalBone3D::_on_bone_parent_changed() {
+ _reload_joint();
+}
+
+void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) {
+#ifdef TOOLS_ENABLED
+ gizmo_move_joint = p_move_joint;
+ Node3DEditor::get_singleton()->update_transform_gizmo();
+#endif
+}
+
+#ifdef TOOLS_ENABLED
+Transform PhysicalBone3D::get_global_gizmo_transform() const {
+ return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform();
+}
+
+Transform PhysicalBone3D::get_local_gizmo_transform() const {
+ return gizmo_move_joint ? get_transform() * joint_offset : get_transform();
+}
+#endif
+
+const PhysicalBone3D::JointData *PhysicalBone3D::get_joint_data() const {
+ return joint_data;
+}
+
+Skeleton3D *PhysicalBone3D::find_skeleton_parent() {
+ return find_skeleton_parent(this);
+}
+
+void PhysicalBone3D::set_joint_type(JointType p_joint_type) {
+
+ if (p_joint_type == get_joint_type())
+ return;
+
+ if (joint_data)
+ memdelete(joint_data);
+ joint_data = nullptr;
+ switch (p_joint_type) {
+ case JOINT_TYPE_PIN:
+ joint_data = memnew(PinJointData);
+ break;
+ case JOINT_TYPE_CONE:
+ joint_data = memnew(ConeJointData);
+ break;
+ case JOINT_TYPE_HINGE:
+ joint_data = memnew(HingeJointData);
+ break;
+ case JOINT_TYPE_SLIDER:
+ joint_data = memnew(SliderJointData);
+ break;
+ case JOINT_TYPE_6DOF:
+ joint_data = memnew(SixDOFJointData);
+ break;
+ case JOINT_TYPE_NONE:
+ break;
+ }
+
+ _reload_joint();
+
+#ifdef TOOLS_ENABLED
+ _change_notify();
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+PhysicalBone3D::JointType PhysicalBone3D::get_joint_type() const {
+ return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE;
+}
+
+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 {
+ return joint_offset;
+}
+
+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 {
+ return joint_offset.basis.get_rotation();
+}
+
+void PhysicalBone3D::set_joint_rotation_degrees(const Vector3 &p_euler_deg) {
+ set_joint_rotation(p_euler_deg * Math_PI / 180.0);
+}
+
+Vector3 PhysicalBone3D::get_joint_rotation_degrees() const {
+ return get_joint_rotation() * 180.0 / Math_PI;
+}
+
+const Transform &PhysicalBone3D::get_body_offset() const {
+ return body_offset;
+}
+
+void PhysicalBone3D::set_body_offset(const Transform &p_offset) {
+ body_offset = p_offset;
+ body_offset_inverse = body_offset.affine_inverse();
+
+ _update_joint_offset();
+}
+
+void PhysicalBone3D::set_simulate_physics(bool p_simulate) {
+ if (simulate_physics == p_simulate) {
+ return;
+ }
+
+ simulate_physics = p_simulate;
+ reset_physics_simulation_state();
+}
+
+bool PhysicalBone3D::get_simulate_physics() {
+ return simulate_physics;
+}
+
+bool PhysicalBone3D::is_simulating_physics() {
+ return _internal_simulate_physics;
+}
+
+void PhysicalBone3D::set_bone_name(const String &p_name) {
+
+ bone_name = p_name;
+ bone_id = -1;
+
+ update_bone_id();
+ reset_to_rest_position();
+}
+
+const String &PhysicalBone3D::get_bone_name() const {
+
+ return bone_name;
+}
+
+void PhysicalBone3D::set_mass(real_t p_mass) {
+
+ ERR_FAIL_COND(p_mass <= 0);
+ mass = p_mass;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass);
+}
+
+real_t PhysicalBone3D::get_mass() const {
+
+ return mass;
+}
+
+void PhysicalBone3D::set_weight(real_t p_weight) {
+
+ set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
+}
+
+real_t PhysicalBone3D::get_weight() const {
+
+ return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
+}
+
+void PhysicalBone3D::set_friction(real_t p_friction) {
+
+ ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
+
+ friction = p_friction;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, friction);
+}
+
+real_t PhysicalBone3D::get_friction() const {
+
+ return friction;
+}
+
+void PhysicalBone3D::set_bounce(real_t p_bounce) {
+
+ ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
+
+ bounce = p_bounce;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, bounce);
+}
+
+real_t PhysicalBone3D::get_bounce() const {
+
+ return bounce;
+}
+
+void PhysicalBone3D::set_gravity_scale(real_t p_gravity_scale) {
+
+ gravity_scale = p_gravity_scale;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
+}
+
+real_t PhysicalBone3D::get_gravity_scale() const {
+
+ return gravity_scale;
+}
+
+void PhysicalBone3D::set_linear_damp(real_t p_linear_damp) {
+ ERR_FAIL_COND(p_linear_damp < -1);
+ linear_damp = p_linear_damp;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp);
+}
+
+real_t PhysicalBone3D::get_linear_damp() const {
+ return linear_damp;
+}
+
+void PhysicalBone3D::set_angular_damp(real_t p_angular_damp) {
+ ERR_FAIL_COND(p_angular_damp < -1);
+ angular_damp = p_angular_damp;
+ PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
+}
+
+real_t PhysicalBone3D::get_angular_damp() const {
+ return angular_damp;
+}
+
+void PhysicalBone3D::set_can_sleep(bool p_active) {
+ can_sleep = p_active;
+ PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active);
+}
+
+bool PhysicalBone3D::is_able_to_sleep() const {
+ return can_sleep;
+}
+
+void PhysicalBone3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
+ PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
+}
+
+bool PhysicalBone3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const {
+ return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis);
+}
+
+PhysicalBone3D::PhysicalBone3D() :
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC),
+#ifdef TOOLS_ENABLED
+ gizmo_move_joint(false),
+#endif
+ joint_data(nullptr),
+ parent_skeleton(nullptr),
+ simulate_physics(false),
+ _internal_simulate_physics(false),
+ bone_id(-1),
+ bone_name(""),
+ bounce(0),
+ mass(1),
+ friction(1),
+ gravity_scale(1),
+ linear_damp(-1),
+ angular_damp(-1),
+ can_sleep(true) {
+
+ reset_physics_simulation_state();
+}
+
+PhysicalBone3D::~PhysicalBone3D() {
+ if (joint_data)
+ memdelete(joint_data);
+}
+
+void PhysicalBone3D::update_bone_id() {
+ if (!parent_skeleton) {
+ return;
+ }
+
+ const int new_bone_id = parent_skeleton->find_bone(bone_name);
+
+ if (new_bone_id != bone_id) {
+ if (-1 != bone_id) {
+ // Assert the unbind from old node
+ parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ }
+
+ bone_id = new_bone_id;
+
+ parent_skeleton->bind_physical_bone_to_bone(bone_id, this);
+
+ _fix_joint_offset();
+ reset_physics_simulation_state();
+ }
+}
+
+void PhysicalBone3D::update_offset() {
+#ifdef TOOLS_ENABLED
+ if (parent_skeleton) {
+
+ Transform bone_transform(parent_skeleton->get_global_transform());
+ if (-1 != bone_id)
+ bone_transform *= parent_skeleton->get_bone_global_pose(bone_id);
+
+ if (gizmo_move_joint) {
+ bone_transform *= body_offset;
+ set_joint_offset(bone_transform.affine_inverse() * get_global_transform());
+ } else {
+ set_body_offset(bone_transform.affine_inverse() * get_global_transform());
+ }
+ }
+#endif
+}
+
+void PhysicalBone3D::_start_physics_simulation() {
+ if (_internal_simulate_physics || !parent_skeleton) {
+ return;
+ }
+ reset_to_rest_position();
+ 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");
+ set_as_toplevel(true);
+ _internal_simulate_physics = true;
+}
+
+void PhysicalBone3D::_stop_physics_simulation() {
+ if (!parent_skeleton) {
+ return;
+ }
+ if (parent_skeleton->get_animate_physical_bones()) {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC);
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0);
+ 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, "");
+ parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
+ set_as_toplevel(false);
+ _internal_simulate_physics = false;
+ }
+}
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
new file mode 100644
index 0000000000..2e71020233
--- /dev/null
+++ b/scene/3d/physics_body_3d.h
@@ -0,0 +1,668 @@
+/*************************************************************************/
+/* physics_body_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS_BODY_3D_H
+#define PHYSICS_BODY_3D_H
+
+#include "core/vset.h"
+#include "scene/3d/collision_object_3d.h"
+#include "scene/resources/physics_material.h"
+#include "servers/physics_server_3d.h"
+#include "skeleton_3d.h"
+
+class PhysicsBody3D : public CollisionObject3D {
+
+ GDCLASS(PhysicsBody3D, CollisionObject3D);
+
+ uint32_t collision_layer;
+ uint32_t collision_mask;
+
+ void _set_layers(uint32_t p_mask);
+ uint32_t _get_layers() const;
+
+protected:
+ static void _bind_methods();
+ PhysicsBody3D(PhysicsServer3D::BodyMode p_mode);
+
+public:
+ virtual Vector3 get_linear_velocity() const;
+ virtual Vector3 get_angular_velocity() const;
+ virtual float 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;
+
+ Array get_collision_exceptions();
+ void add_collision_exception_with(Node *p_node); //must be physicsbody
+ void remove_collision_exception_with(Node *p_node);
+
+ PhysicsBody3D();
+};
+
+class StaticBody3D : public PhysicsBody3D {
+
+ GDCLASS(StaticBody3D, PhysicsBody3D);
+
+ Vector3 constant_linear_velocity;
+ Vector3 constant_angular_velocity;
+
+ Ref<PhysicsMaterial> physics_material_override;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
+
+ void set_constant_linear_velocity(const Vector3 &p_vel);
+ void set_constant_angular_velocity(const Vector3 &p_vel);
+
+ Vector3 get_constant_linear_velocity() const;
+ Vector3 get_constant_angular_velocity() const;
+
+ StaticBody3D();
+ ~StaticBody3D();
+
+private:
+ void _reload_physics_characteristics();
+};
+
+class RigidBody3D : public PhysicsBody3D {
+
+ GDCLASS(RigidBody3D, PhysicsBody3D);
+
+public:
+ enum Mode {
+ MODE_RIGID,
+ MODE_STATIC,
+ MODE_CHARACTER,
+ MODE_KINEMATIC,
+ };
+
+protected:
+ bool can_sleep;
+ PhysicsDirectBodyState3D *state;
+ Mode mode;
+
+ real_t mass;
+ Ref<PhysicsMaterial> physics_material_override;
+
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+ real_t gravity_scale;
+ real_t linear_damp;
+ real_t angular_damp;
+
+ bool sleeping;
+ bool ccd;
+
+ int max_contacts_reported;
+
+ bool custom_integrator;
+
+ struct ShapePair {
+
+ int body_shape;
+ int local_shape;
+ bool tagged;
+ bool operator<(const ShapePair &p_sp) const {
+ if (body_shape == p_sp.body_shape)
+ return local_shape < p_sp.local_shape;
+ else
+ return body_shape < p_sp.body_shape;
+ }
+
+ ShapePair() {}
+ ShapePair(int p_bs, int p_ls) {
+ body_shape = p_bs;
+ local_shape = p_ls;
+ tagged = false;
+ }
+ };
+ struct RigidBody3D_RemoveAction {
+
+ ObjectID body_id;
+ ShapePair pair;
+ };
+ struct BodyState {
+
+ //int rc;
+ bool in_tree;
+ VSet<ShapePair> shapes;
+ };
+
+ struct ContactMonitor {
+
+ bool locked;
+ Map<ObjectID, BodyState> body_map;
+ };
+
+ ContactMonitor *contact_monitor;
+ void _body_enter_tree(ObjectID p_id);
+ void _body_exit_tree(ObjectID p_id);
+
+ void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape);
+ virtual void _direct_state_changed(Object *p_state);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ void set_mass(real_t p_mass);
+ real_t get_mass() const;
+
+ virtual float get_inverse_mass() const { return 1.0 / mass; }
+
+ void set_weight(real_t p_weight);
+ real_t get_weight() const;
+
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
+
+ void set_linear_velocity(const Vector3 &p_velocity);
+ Vector3 get_linear_velocity() const;
+
+ void set_axis_velocity(const Vector3 &p_axis);
+
+ void set_angular_velocity(const Vector3 &p_velocity);
+ Vector3 get_angular_velocity() const;
+
+ void set_gravity_scale(real_t p_gravity_scale);
+ real_t get_gravity_scale() const;
+
+ void set_linear_damp(real_t p_linear_damp);
+ real_t get_linear_damp() const;
+
+ void set_angular_damp(real_t p_angular_damp);
+ real_t get_angular_damp() const;
+
+ void set_use_custom_integrator(bool p_enable);
+ bool is_using_custom_integrator();
+
+ void set_sleeping(bool p_sleeping);
+ bool is_sleeping() const;
+
+ void set_can_sleep(bool p_active);
+ bool is_able_to_sleep() const;
+
+ void set_contact_monitor(bool p_enabled);
+ bool is_contact_monitor_enabled() const;
+
+ void set_max_contacts_reported(int p_amount);
+ int get_max_contacts_reported() const;
+
+ void set_use_continuous_collision_detection(bool p_enable);
+ bool is_using_continuous_collision_detection() const;
+
+ void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
+ bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
+
+ Array get_colliding_bodies() const;
+
+ void add_central_force(const Vector3 &p_force);
+ void add_force(const Vector3 &p_force, const Vector3 &p_pos);
+ void add_torque(const Vector3 &p_torque);
+
+ void apply_central_impulse(const Vector3 &p_impulse);
+ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
+ void apply_torque_impulse(const Vector3 &p_impulse);
+
+ virtual String get_configuration_warning() const;
+
+ RigidBody3D();
+ ~RigidBody3D();
+
+private:
+ void _reload_physics_characteristics();
+};
+
+VARIANT_ENUM_CAST(RigidBody3D::Mode);
+
+class KinematicCollision3D;
+
+class KinematicBody3D : public PhysicsBody3D {
+
+ GDCLASS(KinematicBody3D, PhysicsBody3D);
+
+public:
+ struct Collision {
+ Vector3 collision;
+ Vector3 normal;
+ Vector3 collider_vel;
+ ObjectID collider;
+ RID collider_rid;
+ int collider_shape;
+ Variant collider_metadata;
+ Vector3 remainder;
+ Vector3 travel;
+ int local_shape;
+ };
+
+private:
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+
+ uint16_t locked_axis;
+
+ float margin;
+
+ Vector3 floor_normal;
+ Vector3 floor_velocity;
+ RID on_floor_body;
+ bool on_floor;
+ bool on_ceiling;
+ bool on_wall;
+ Vector<Collision> colliders;
+ Vector<Ref<KinematicCollision3D>> slide_colliders;
+ Ref<KinematicCollision3D> motion_cache;
+
+ _FORCE_INLINE_ bool _ignores_mode(PhysicsServer3D::BodyMode) const;
+
+ Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
+ Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ virtual void _direct_state_changed(Object *p_state);
+
+public:
+ virtual Vector3 get_linear_velocity() const;
+ virtual Vector3 get_angular_velocity() const;
+
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
+ bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
+
+ bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+
+ void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
+ bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
+
+ void set_safe_margin(float p_margin);
+ float get_safe_margin() const;
+
+ Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
+ Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
+ bool is_on_floor() const;
+ bool is_on_wall() const;
+ bool is_on_ceiling() const;
+ Vector3 get_floor_normal() const;
+ Vector3 get_floor_velocity() const;
+
+ int get_slide_count() const;
+ Collision get_slide_collision(int p_bounce) const;
+
+ KinematicBody3D();
+ ~KinematicBody3D();
+};
+
+class KinematicCollision3D : public Reference {
+
+ GDCLASS(KinematicCollision3D, Reference);
+
+ KinematicBody3D *owner;
+ friend class KinematicBody3D;
+ KinematicBody3D::Collision collision;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Vector3 get_position() const;
+ Vector3 get_normal() const;
+ Vector3 get_travel() const;
+ Vector3 get_remainder() const;
+ Object *get_local_shape() const;
+ Object *get_collider() const;
+ ObjectID get_collider_id() const;
+ Object *get_collider_shape() const;
+ int get_collider_shape_index() const;
+ Vector3 get_collider_velocity() const;
+ Variant get_collider_metadata() const;
+
+ KinematicCollision3D();
+};
+
+class PhysicalBone3D : public PhysicsBody3D {
+
+ GDCLASS(PhysicalBone3D, PhysicsBody3D);
+
+public:
+ enum JointType {
+ JOINT_TYPE_NONE,
+ JOINT_TYPE_PIN,
+ JOINT_TYPE_CONE,
+ JOINT_TYPE_HINGE,
+ JOINT_TYPE_SLIDER,
+ JOINT_TYPE_6DOF
+ };
+
+ struct JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_NONE; }
+
+ /// "j" is used to set the parameter inside the PhysicsServer3D
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ virtual ~JointData() {}
+ };
+
+ struct PinJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_PIN; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t bias;
+ real_t damping;
+ real_t impulse_clamp;
+
+ PinJointData() :
+ bias(0.3),
+ damping(1.),
+ impulse_clamp(0) {}
+ };
+
+ struct ConeJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_CONE; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t swing_span;
+ real_t twist_span;
+ real_t bias;
+ real_t softness;
+ real_t relaxation;
+
+ ConeJointData() :
+ swing_span(Math_PI * 0.25),
+ twist_span(Math_PI),
+ bias(0.3),
+ softness(0.8),
+ relaxation(1.) {}
+ };
+
+ struct HingeJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ bool angular_limit_enabled;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_bias;
+ real_t angular_limit_softness;
+ real_t angular_limit_relaxation;
+
+ HingeJointData() :
+ angular_limit_enabled(false),
+ angular_limit_upper(Math_PI * 0.5),
+ angular_limit_lower(-Math_PI * 0.5),
+ angular_limit_bias(0.3),
+ angular_limit_softness(0.9),
+ angular_limit_relaxation(1.) {}
+ };
+
+ struct SliderJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t linear_limit_upper;
+ real_t linear_limit_lower;
+ real_t linear_limit_softness;
+ real_t linear_limit_restitution;
+ real_t linear_limit_damping;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_softness;
+ real_t angular_limit_restitution;
+ real_t angular_limit_damping;
+
+ SliderJointData() :
+ linear_limit_upper(1.),
+ linear_limit_lower(-1.),
+ linear_limit_softness(1.),
+ linear_limit_restitution(0.7),
+ linear_limit_damping(1.),
+ angular_limit_upper(0),
+ angular_limit_lower(0),
+ angular_limit_softness(1.),
+ angular_limit_restitution(0.7),
+ angular_limit_damping(1.) {}
+ };
+
+ struct SixDOFJointData : public JointData {
+ struct SixDOFAxisData {
+ bool linear_limit_enabled;
+ real_t linear_limit_upper;
+ real_t linear_limit_lower;
+ real_t linear_limit_softness;
+ real_t linear_restitution;
+ real_t linear_damping;
+ bool linear_spring_enabled;
+ real_t linear_spring_stiffness;
+ real_t linear_spring_damping;
+ real_t linear_equilibrium_point;
+ bool angular_limit_enabled;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_softness;
+ real_t angular_restitution;
+ real_t angular_damping;
+ real_t erp;
+ bool angular_spring_enabled;
+ real_t angular_spring_stiffness;
+ real_t angular_spring_damping;
+ real_t angular_equilibrium_point;
+
+ SixDOFAxisData() :
+ linear_limit_enabled(true),
+ linear_limit_upper(0),
+ linear_limit_lower(0),
+ linear_limit_softness(0.7),
+ linear_restitution(0.5),
+ linear_damping(1.),
+ linear_spring_enabled(false),
+ linear_spring_stiffness(0),
+ linear_spring_damping(0),
+ linear_equilibrium_point(0),
+ angular_limit_enabled(true),
+ angular_limit_upper(0),
+ angular_limit_lower(0),
+ angular_limit_softness(0.5),
+ angular_restitution(0),
+ angular_damping(1.),
+ erp(0.5),
+ angular_spring_enabled(false),
+ angular_spring_stiffness(0),
+ angular_spring_damping(0.),
+ angular_equilibrium_point(0) {}
+ };
+
+ virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ SixDOFAxisData axis_data[3];
+
+ SixDOFJointData() {}
+ };
+
+private:
+#ifdef TOOLS_ENABLED
+ // if false gizmo move body
+ bool gizmo_move_joint;
+#endif
+
+ JointData *joint_data;
+ Transform joint_offset;
+ RID joint;
+
+ Skeleton3D *parent_skeleton;
+ Transform body_offset;
+ Transform body_offset_inverse;
+ bool simulate_physics;
+ bool _internal_simulate_physics;
+ int bone_id;
+
+ String bone_name;
+ real_t bounce;
+ real_t mass;
+ real_t friction;
+ real_t gravity_scale;
+ real_t linear_damp;
+ real_t angular_damp;
+ bool can_sleep;
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _notification(int p_what);
+ void _direct_state_changed(Object *p_state);
+
+ static void _bind_methods();
+
+private:
+ static Skeleton3D *find_skeleton_parent(Node *p_parent);
+
+ void _update_joint_offset();
+ void _fix_joint_offset();
+ void _reload_joint();
+
+public:
+ void _on_bone_parent_changed();
+ void _set_gizmo_move_joint(bool p_move_joint);
+
+public:
+#ifdef TOOLS_ENABLED
+ virtual Transform get_global_gizmo_transform() const;
+ virtual Transform get_local_gizmo_transform() const;
+#endif
+
+ const JointData *get_joint_data() const;
+ Skeleton3D *find_skeleton_parent();
+
+ int get_bone_id() const { return bone_id; }
+
+ void set_joint_type(JointType p_joint_type);
+ JointType get_joint_type() const;
+
+ void set_joint_offset(const Transform &p_offset);
+ const Transform &get_joint_offset() const;
+
+ void set_joint_rotation(const Vector3 &p_euler_rad);
+ Vector3 get_joint_rotation() const;
+
+ void set_joint_rotation_degrees(const Vector3 &p_euler_deg);
+ Vector3 get_joint_rotation_degrees() const;
+
+ void set_body_offset(const Transform &p_offset);
+ const Transform &get_body_offset() const;
+
+ void set_simulate_physics(bool p_simulate);
+ bool get_simulate_physics();
+ bool is_simulating_physics();
+
+ void set_bone_name(const String &p_name);
+ const String &get_bone_name() const;
+
+ void set_mass(real_t p_mass);
+ real_t get_mass() const;
+
+ void set_weight(real_t p_weight);
+ real_t get_weight() const;
+
+ void set_friction(real_t p_friction);
+ real_t get_friction() const;
+
+ void set_bounce(real_t p_bounce);
+ real_t get_bounce() const;
+
+ void set_gravity_scale(real_t p_gravity_scale);
+ real_t get_gravity_scale() const;
+
+ void set_linear_damp(real_t p_linear_damp);
+ real_t get_linear_damp() const;
+
+ void set_angular_damp(real_t p_angular_damp);
+ real_t get_angular_damp() const;
+
+ void set_can_sleep(bool p_active);
+ bool is_able_to_sleep() const;
+
+ void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
+ bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
+
+ void apply_central_impulse(const Vector3 &p_impulse);
+ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
+
+ void reset_physics_simulation_state();
+ void reset_to_rest_position();
+
+ PhysicalBone3D();
+ ~PhysicalBone3D();
+
+private:
+ void update_bone_id();
+ void update_offset();
+
+ void _start_physics_simulation();
+ void _stop_physics_simulation();
+};
+
+VARIANT_ENUM_CAST(PhysicalBone3D::JointType);
+
+#endif // PHYSICS_BODY__H
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
deleted file mode 100644
index 0699e366e0..0000000000
--- a/scene/3d/physics_joint.cpp
+++ /dev/null
@@ -1,1049 +0,0 @@
-/*************************************************************************/
-/* physics_joint.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_joint.h"
-
-void Joint::_update_joint(bool p_only_free) {
-
- if (joint.is_valid()) {
- if (ba.is_valid() && bb.is_valid())
- PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb);
-
- PhysicsServer::get_singleton()->free(joint);
- joint = RID();
- ba = RID();
- bb = RID();
- }
-
- if (p_only_free || !is_inside_tree())
- return;
-
- Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
- Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
-
- PhysicsBody *body_a = Object::cast_to<PhysicsBody>(node_a);
- PhysicsBody *body_b = Object::cast_to<PhysicsBody>(node_b);
-
- if (!body_a && body_b)
- SWAP(body_a, body_b);
-
- if (!body_a)
- return;
-
- joint = _configure_joint(body_a, body_b);
-
- if (!joint.is_valid())
- return;
-
- PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority);
-
- ba = body_a->get_rid();
- if (body_b)
- bb = body_b->get_rid();
-
- PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
-}
-
-void Joint::set_node_a(const NodePath &p_node_a) {
-
- if (a == p_node_a)
- return;
-
- a = p_node_a;
- _update_joint();
-}
-
-NodePath Joint::get_node_a() const {
-
- return a;
-}
-
-void Joint::set_node_b(const NodePath &p_node_b) {
-
- if (b == p_node_b)
- return;
- b = p_node_b;
- _update_joint();
-}
-NodePath Joint::get_node_b() const {
-
- return b;
-}
-
-void Joint::set_solver_priority(int p_priority) {
-
- solver_priority = p_priority;
- if (joint.is_valid())
- PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority);
-}
-
-int Joint::get_solver_priority() const {
-
- return solver_priority;
-}
-
-void Joint::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_READY: {
- _update_joint();
- } break;
- case NOTIFICATION_EXIT_TREE: {
- if (joint.is_valid()) {
- _update_joint(true);
- }
- } break;
- }
-}
-
-void Joint::set_exclude_nodes_from_collision(bool p_enable) {
-
- if (exclude_from_collision == p_enable)
- return;
- exclude_from_collision = p_enable;
- _update_joint();
-}
-
-bool Joint::get_exclude_nodes_from_collision() const {
-
- return exclude_from_collision;
-}
-
-void Joint::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint::set_node_a);
- ClassDB::bind_method(D_METHOD("get_node_a"), &Joint::get_node_a);
-
- ClassDB::bind_method(D_METHOD("set_node_b", "node"), &Joint::set_node_b);
- ClassDB::bind_method(D_METHOD("get_node_b"), &Joint::get_node_b);
-
- ClassDB::bind_method(D_METHOD("set_solver_priority", "priority"), &Joint::set_solver_priority);
- ClassDB::bind_method(D_METHOD("get_solver_priority"), &Joint::get_solver_priority);
-
- ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint::set_exclude_nodes_from_collision);
- ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint::get_exclude_nodes_from_collision);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_a", "get_node_a");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_b", "get_node_b");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
-}
-
-Joint::Joint() {
-
- exclude_from_collision = true;
- solver_priority = 1;
- set_notify_transform(true);
-}
-
-///////////////////////////////////
-
-void PinJoint::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &PinJoint::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &PinJoint::get_param);
-
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"), "set_param", "get_param", PARAM_IMPULSE_CLAMP);
-
- BIND_ENUM_CONSTANT(PARAM_BIAS);
- BIND_ENUM_CONSTANT(PARAM_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_IMPULSE_CLAMP);
-}
-
-void PinJoint::set_param(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, 3);
- params[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer::PinJointParam(p_param), p_value);
-}
-float PinJoint::get_param(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, 3, 0);
- return params[p_param];
-}
-
-RID PinJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) {
-
- Vector3 pinpos = get_global_transform().origin;
- Vector3 local_a = body_a->get_global_transform().affine_inverse().xform(pinpos);
- Vector3 local_b;
-
- if (body_b)
- local_b = body_b->get_global_transform().affine_inverse().xform(pinpos);
- else
- local_b = pinpos;
-
- RID j = PhysicsServer::get_singleton()->joint_create_pin(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
- for (int i = 0; i < 3; i++) {
- PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PinJointParam(i), params[i]);
- }
- return j;
-}
-
-PinJoint::PinJoint() {
-
- params[PARAM_BIAS] = 0.3;
- params[PARAM_DAMPING] = 1;
- params[PARAM_IMPULSE_CLAMP] = 0;
-}
-
-/////////////////////////////////////////////////
-
-///////////////////////////////////
-
-void HingeJoint::_set_upper_limit(float p_limit) {
-
- set_param(PARAM_LIMIT_UPPER, Math::deg2rad(p_limit));
-}
-
-float HingeJoint::_get_upper_limit() const {
-
- return Math::rad2deg(get_param(PARAM_LIMIT_UPPER));
-}
-
-void HingeJoint::_set_lower_limit(float p_limit) {
-
- set_param(PARAM_LIMIT_LOWER, Math::deg2rad(p_limit));
-}
-
-float HingeJoint::_get_lower_limit() const {
-
- return Math::rad2deg(get_param(PARAM_LIMIT_LOWER));
-}
-
-void HingeJoint::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &HingeJoint::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &HingeJoint::get_param);
-
- ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &HingeJoint::set_flag);
- ClassDB::bind_method(D_METHOD("get_flag", "flag"), &HingeJoint::get_flag);
-
- ClassDB::bind_method(D_METHOD("_set_upper_limit", "upper_limit"), &HingeJoint::_set_upper_limit);
- ClassDB::bind_method(D_METHOD("_get_upper_limit"), &HingeJoint::_get_upper_limit);
-
- ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint::_set_lower_limit);
- ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint::_get_lower_limit);
-
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit", "_get_lower_limit");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE);
-
- BIND_ENUM_CONSTANT(PARAM_BIAS);
- BIND_ENUM_CONSTANT(PARAM_LIMIT_UPPER);
- BIND_ENUM_CONSTANT(PARAM_LIMIT_LOWER);
- BIND_ENUM_CONSTANT(PARAM_LIMIT_BIAS);
- BIND_ENUM_CONSTANT(PARAM_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_LIMIT_RELAXATION);
- BIND_ENUM_CONSTANT(PARAM_MOTOR_TARGET_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_MOTOR_MAX_IMPULSE);
- BIND_ENUM_CONSTANT(PARAM_MAX);
-
- BIND_ENUM_CONSTANT(FLAG_USE_LIMIT);
- BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR);
- BIND_ENUM_CONSTANT(FLAG_MAX);
-}
-
-void HingeJoint::set_param(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- params[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->hinge_joint_set_param(get_joint(), PhysicsServer::HingeJointParam(p_param), p_value);
-
- update_gizmo();
-}
-float HingeJoint::get_param(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return params[p_param];
-}
-
-void HingeJoint::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())
- PhysicsServer::get_singleton()->hinge_joint_set_flag(get_joint(), PhysicsServer::HingeJointFlag(p_flag), p_value);
-
- update_gizmo();
-}
-bool HingeJoint::get_flag(Flag p_flag) const {
-
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
-}
-
-RID HingeJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) {
-
- Transform gt = get_global_transform();
- Transform ainv = body_a->get_global_transform().affine_inverse();
-
- Transform local_a = ainv * gt;
- local_a.orthonormalize();
- Transform local_b = gt;
-
- if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
- local_b = binv * gt;
- }
-
- local_b.orthonormalize();
-
- RID j = PhysicsServer::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
- for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HingeJointParam(i), params[i]);
- }
- for (int i = 0; i < FLAG_MAX; i++) {
- set_flag(Flag(i), flags[i]);
- PhysicsServer::get_singleton()->hinge_joint_set_flag(j, PhysicsServer::HingeJointFlag(i), flags[i]);
- }
- return j;
-}
-
-HingeJoint::HingeJoint() {
-
- params[PARAM_BIAS] = 0.3;
- params[PARAM_LIMIT_UPPER] = Math_PI * 0.5;
- params[PARAM_LIMIT_LOWER] = -Math_PI * 0.5;
- params[PARAM_LIMIT_BIAS] = 0.3;
- params[PARAM_LIMIT_SOFTNESS] = 0.9;
- params[PARAM_LIMIT_RELAXATION] = 1.0;
- params[PARAM_MOTOR_TARGET_VELOCITY] = 1;
- params[PARAM_MOTOR_MAX_IMPULSE] = 1;
-
- flags[FLAG_USE_LIMIT] = false;
- flags[FLAG_ENABLE_MOTOR] = false;
-}
-
-/////////////////////////////////////////////////
-
-//////////////////////////////////
-
-void SliderJoint::_set_upper_limit_angular(float p_limit_angular) {
-
- set_param(PARAM_ANGULAR_LIMIT_UPPER, Math::deg2rad(p_limit_angular));
-}
-
-float SliderJoint::_get_upper_limit_angular() const {
-
- return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_UPPER));
-}
-
-void SliderJoint::_set_lower_limit_angular(float p_limit_angular) {
-
- set_param(PARAM_ANGULAR_LIMIT_LOWER, Math::deg2rad(p_limit_angular));
-}
-
-float SliderJoint::_get_lower_limit_angular() const {
-
- return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_LOWER));
-}
-
-void SliderJoint::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &SliderJoint::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &SliderJoint::get_param);
-
- ClassDB::bind_method(D_METHOD("_set_upper_limit_angular", "upper_limit_angular"), &SliderJoint::_set_upper_limit_angular);
- ClassDB::bind_method(D_METHOD("_get_upper_limit_angular"), &SliderJoint::_get_upper_limit_angular);
-
- ClassDB::bind_method(D_METHOD("_set_lower_limit_angular", "lower_limit_angular"), &SliderJoint::_set_lower_limit_angular);
- ClassDB::bind_method(D_METHOD("_get_lower_limit_angular"), &SliderJoint::_get_lower_limit_angular);
-
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit_angular", "_get_upper_limit_angular");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit_angular", "_get_lower_limit_angular");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_DAMPING);
-
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_UPPER);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_LOWER);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_DAMPING);
-
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_UPPER);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_LOWER);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_DAMPING);
-
- BIND_ENUM_CONSTANT(PARAM_MAX);
-}
-
-void SliderJoint::set_param(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- params[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->slider_joint_set_param(get_joint(), PhysicsServer::SliderJointParam(p_param), p_value);
- update_gizmo();
-}
-float SliderJoint::get_param(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return params[p_param];
-}
-
-RID SliderJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) {
-
- Transform gt = get_global_transform();
- Transform ainv = body_a->get_global_transform().affine_inverse();
-
- Transform local_a = ainv * gt;
- local_a.orthonormalize();
- Transform local_b = gt;
-
- if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
- local_b = binv * gt;
- }
-
- local_b.orthonormalize();
-
- RID j = PhysicsServer::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
- for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SliderJointParam(i), params[i]);
- }
-
- return j;
-}
-
-SliderJoint::SliderJoint() {
-
- params[PARAM_LINEAR_LIMIT_UPPER] = 1.0;
- params[PARAM_LINEAR_LIMIT_LOWER] = -1.0;
- params[PARAM_LINEAR_LIMIT_SOFTNESS] = 1.0;
- params[PARAM_LINEAR_LIMIT_RESTITUTION] = 0.7;
- params[PARAM_LINEAR_LIMIT_DAMPING] = 1.0;
- params[PARAM_LINEAR_MOTION_SOFTNESS] = 1.0;
- params[PARAM_LINEAR_MOTION_RESTITUTION] = 0.7;
- params[PARAM_LINEAR_MOTION_DAMPING] = 0; //1.0;
- params[PARAM_LINEAR_ORTHOGONAL_SOFTNESS] = 1.0;
- params[PARAM_LINEAR_ORTHOGONAL_RESTITUTION] = 0.7;
- params[PARAM_LINEAR_ORTHOGONAL_DAMPING] = 1.0;
-
- params[PARAM_ANGULAR_LIMIT_UPPER] = 0;
- params[PARAM_ANGULAR_LIMIT_LOWER] = 0;
- params[PARAM_ANGULAR_LIMIT_SOFTNESS] = 1.0;
- params[PARAM_ANGULAR_LIMIT_RESTITUTION] = 0.7;
- params[PARAM_ANGULAR_LIMIT_DAMPING] = 0; //1.0;
- params[PARAM_ANGULAR_MOTION_SOFTNESS] = 1.0;
- params[PARAM_ANGULAR_MOTION_RESTITUTION] = 0.7;
- params[PARAM_ANGULAR_MOTION_DAMPING] = 1.0;
- params[PARAM_ANGULAR_ORTHOGONAL_SOFTNESS] = 1.0;
- params[PARAM_ANGULAR_ORTHOGONAL_RESTITUTION] = 0.7;
- params[PARAM_ANGULAR_ORTHOGONAL_DAMPING] = 1.0;
-}
-
-//////////////////////////////////
-
-void ConeTwistJoint::_set_swing_span(float p_limit_angular) {
-
- set_param(PARAM_SWING_SPAN, Math::deg2rad(p_limit_angular));
-}
-
-float ConeTwistJoint::_get_swing_span() const {
-
- return Math::rad2deg(get_param(PARAM_SWING_SPAN));
-}
-
-void ConeTwistJoint::_set_twist_span(float p_limit_angular) {
-
- set_param(PARAM_TWIST_SPAN, Math::deg2rad(p_limit_angular));
-}
-
-float ConeTwistJoint::_get_twist_span() const {
-
- return Math::rad2deg(get_param(PARAM_TWIST_SPAN));
-}
-
-void ConeTwistJoint::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ConeTwistJoint::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &ConeTwistJoint::get_param);
-
- ClassDB::bind_method(D_METHOD("_set_swing_span", "swing_span"), &ConeTwistJoint::_set_swing_span);
- ClassDB::bind_method(D_METHOD("_get_swing_span"), &ConeTwistJoint::_get_swing_span);
-
- ClassDB::bind_method(D_METHOD("_set_twist_span", "twist_span"), &ConeTwistJoint::_set_twist_span);
- ClassDB::bind_method(D_METHOD("_get_twist_span"), &ConeTwistJoint::_get_twist_span);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_swing_span", "_get_swing_span");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"), "_set_twist_span", "_get_twist_span");
-
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_RELAXATION);
-
- BIND_ENUM_CONSTANT(PARAM_SWING_SPAN);
- BIND_ENUM_CONSTANT(PARAM_TWIST_SPAN);
- BIND_ENUM_CONSTANT(PARAM_BIAS);
- BIND_ENUM_CONSTANT(PARAM_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_RELAXATION);
- BIND_ENUM_CONSTANT(PARAM_MAX);
-}
-
-void ConeTwistJoint::set_param(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- params[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(get_joint(), PhysicsServer::ConeTwistJointParam(p_param), p_value);
-
- update_gizmo();
-}
-float ConeTwistJoint::get_param(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return params[p_param];
-}
-
-RID ConeTwistJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) {
-
- Transform gt = get_global_transform();
- //Vector3 cone_twistpos = gt.origin;
- //Vector3 cone_twistdir = gt.basis.get_axis(2);
-
- Transform ainv = body_a->get_global_transform().affine_inverse();
-
- Transform local_a = ainv * gt;
- local_a.orthonormalize();
- Transform local_b = gt;
-
- if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
- local_b = binv * gt;
- }
-
- local_b.orthonormalize();
-
- RID j = PhysicsServer::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
- for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::ConeTwistJointParam(i), params[i]);
- }
-
- return j;
-}
-
-ConeTwistJoint::ConeTwistJoint() {
-
- params[PARAM_SWING_SPAN] = Math_PI * 0.25;
- params[PARAM_TWIST_SPAN] = Math_PI;
- params[PARAM_BIAS] = 0.3;
- params[PARAM_SOFTNESS] = 0.8;
- params[PARAM_RELAXATION] = 1.0;
-}
-
-/////////////////////////////////////////////////////////////////////
-
-void Generic6DOFJoint::_set_angular_hi_limit_x(float p_limit_angular) {
-
- set_param_x(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-float Generic6DOFJoint::_get_angular_hi_limit_x() const {
-
- return Math::rad2deg(get_param_x(PARAM_ANGULAR_UPPER_LIMIT));
-}
-
-void Generic6DOFJoint::_set_angular_lo_limit_x(float p_limit_angular) {
-
- set_param_x(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-float Generic6DOFJoint::_get_angular_lo_limit_x() const {
-
- return Math::rad2deg(get_param_x(PARAM_ANGULAR_LOWER_LIMIT));
-}
-
-void Generic6DOFJoint::_set_angular_hi_limit_y(float p_limit_angular) {
-
- set_param_y(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-float Generic6DOFJoint::_get_angular_hi_limit_y() const {
-
- return Math::rad2deg(get_param_y(PARAM_ANGULAR_UPPER_LIMIT));
-}
-
-void Generic6DOFJoint::_set_angular_lo_limit_y(float p_limit_angular) {
-
- set_param_y(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-float Generic6DOFJoint::_get_angular_lo_limit_y() const {
-
- return Math::rad2deg(get_param_y(PARAM_ANGULAR_LOWER_LIMIT));
-}
-
-void Generic6DOFJoint::_set_angular_hi_limit_z(float p_limit_angular) {
-
- set_param_z(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-float Generic6DOFJoint::_get_angular_hi_limit_z() const {
-
- return Math::rad2deg(get_param_z(PARAM_ANGULAR_UPPER_LIMIT));
-}
-
-void Generic6DOFJoint::_set_angular_lo_limit_z(float p_limit_angular) {
-
- set_param_z(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-float Generic6DOFJoint::_get_angular_lo_limit_z() const {
-
- return Math::rad2deg(get_param_z(PARAM_ANGULAR_LOWER_LIMIT));
-}
-
-void Generic6DOFJoint::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_x", "angle"), &Generic6DOFJoint::_set_angular_hi_limit_x);
- ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_x"), &Generic6DOFJoint::_get_angular_hi_limit_x);
-
- ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_x", "angle"), &Generic6DOFJoint::_set_angular_lo_limit_x);
- ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_x"), &Generic6DOFJoint::_get_angular_lo_limit_x);
-
- ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_y", "angle"), &Generic6DOFJoint::_set_angular_hi_limit_y);
- ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_y"), &Generic6DOFJoint::_get_angular_hi_limit_y);
-
- ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_y", "angle"), &Generic6DOFJoint::_set_angular_lo_limit_y);
- ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_y"), &Generic6DOFJoint::_get_angular_lo_limit_y);
-
- ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_z", "angle"), &Generic6DOFJoint::_set_angular_hi_limit_z);
- ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_z"), &Generic6DOFJoint::_get_angular_hi_limit_z);
-
- ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_z", "angle"), &Generic6DOFJoint::_set_angular_lo_limit_z);
- ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_z"), &Generic6DOFJoint::_get_angular_lo_limit_z);
-
- ClassDB::bind_method(D_METHOD("set_param_x", "param", "value"), &Generic6DOFJoint::set_param_x);
- ClassDB::bind_method(D_METHOD("get_param_x", "param"), &Generic6DOFJoint::get_param_x);
-
- ClassDB::bind_method(D_METHOD("set_param_y", "param", "value"), &Generic6DOFJoint::set_param_y);
- ClassDB::bind_method(D_METHOD("get_param_y", "param"), &Generic6DOFJoint::get_param_y);
-
- ClassDB::bind_method(D_METHOD("set_param_z", "param", "value"), &Generic6DOFJoint::set_param_z);
- ClassDB::bind_method(D_METHOD("get_param_z", "param"), &Generic6DOFJoint::get_param_z);
-
- ClassDB::bind_method(D_METHOD("set_flag_x", "flag", "value"), &Generic6DOFJoint::set_flag_x);
- ClassDB::bind_method(D_METHOD("get_flag_x", "flag"), &Generic6DOFJoint::get_flag_x);
-
- ClassDB::bind_method(D_METHOD("set_flag_y", "flag", "value"), &Generic6DOFJoint::set_flag_y);
- ClassDB::bind_method(D_METHOD("get_flag_y", "flag"), &Generic6DOFJoint::get_flag_y);
-
- ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint::set_flag_z);
- ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint::get_flag_z);
-
- ClassDB::bind_method(D_METHOD("set_precision", "precision"), &Generic6DOFJoint::set_precision);
- ClassDB::bind_method(D_METHOD("get_precision"), &Generic6DOFJoint::get_precision);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/damping"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/damping"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/upper_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_UPPER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/lower_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_LOWER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/damping"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/damping"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/upper_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_UPPER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/lower_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_LOWER_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/damping"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_LIMIT_SOFTNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_RESTITUTION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/erp"), "set_param_z", "get_param_z", PARAM_ANGULAR_ERP);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_SPRING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_STIFFNESS);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_RANGE, "1,99999,1"), "set_precision", "get_precision");
-
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LOWER_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_UPPER_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_FORCE_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LOWER_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_UPPER_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_RESTITUTION);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_FORCE_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_ERP);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
- BIND_ENUM_CONSTANT(PARAM_MAX);
-
- BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_LIMIT);
- BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_LIMIT);
- BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_SPRING);
- BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_SPRING);
- BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR);
- BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_MOTOR);
- BIND_ENUM_CONSTANT(FLAG_MAX);
-}
-
-void Generic6DOFJoint::set_param_x(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- params_x[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_X, PhysicsServer::G6DOFJointAxisParam(p_param), p_value);
-
- update_gizmo();
-}
-float Generic6DOFJoint::get_param_x(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return params_x[p_param];
-}
-
-void Generic6DOFJoint::set_param_y(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- params_y[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Y, PhysicsServer::G6DOFJointAxisParam(p_param), p_value);
- update_gizmo();
-}
-float Generic6DOFJoint::get_param_y(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return params_y[p_param];
-}
-
-void Generic6DOFJoint::set_param_z(Param p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- params_z[p_param] = p_value;
- if (get_joint().is_valid())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Z, PhysicsServer::G6DOFJointAxisParam(p_param), p_value);
- update_gizmo();
-}
-float Generic6DOFJoint::get_param_z(Param p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return params_z[p_param];
-}
-
-void Generic6DOFJoint::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())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_X, PhysicsServer::G6DOFJointAxisFlag(p_flag), p_enabled);
- update_gizmo();
-}
-bool Generic6DOFJoint::get_flag_x(Flag p_flag) const {
-
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags_x[p_flag];
-}
-
-void Generic6DOFJoint::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())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Y, PhysicsServer::G6DOFJointAxisFlag(p_flag), p_enabled);
- update_gizmo();
-}
-bool Generic6DOFJoint::get_flag_y(Flag p_flag) const {
-
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags_y[p_flag];
-}
-
-void Generic6DOFJoint::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())
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Z, PhysicsServer::G6DOFJointAxisFlag(p_flag), p_enabled);
- update_gizmo();
-}
-bool Generic6DOFJoint::get_flag_z(Flag p_flag) const {
-
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags_z[p_flag];
-}
-
-void Generic6DOFJoint::set_precision(int p_precision) {
- precision = p_precision;
-
- PhysicsServer::get_singleton()->generic_6dof_joint_set_precision(
- get_joint(),
- precision);
-}
-
-RID Generic6DOFJoint::_configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) {
-
- Transform gt = get_global_transform();
- //Vector3 cone_twistpos = gt.origin;
- //Vector3 cone_twistdir = gt.basis.get_axis(2);
-
- Transform ainv = body_a->get_global_transform().affine_inverse();
-
- Transform local_a = ainv * gt;
- local_a.orthonormalize();
- Transform local_b = gt;
-
- if (body_b) {
- Transform binv = body_b->get_global_transform().affine_inverse();
- local_b = binv * gt;
- }
-
- local_b.orthonormalize();
-
- RID j = PhysicsServer::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b);
- for (int i = 0; i < PARAM_MAX; i++) {
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_X, PhysicsServer::G6DOFJointAxisParam(i), params_x[i]);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_Y, PhysicsServer::G6DOFJointAxisParam(i), params_y[i]);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_Z, PhysicsServer::G6DOFJointAxisParam(i), params_z[i]);
- }
- for (int i = 0; i < FLAG_MAX; i++) {
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_X, PhysicsServer::G6DOFJointAxisFlag(i), flags_x[i]);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_Y, PhysicsServer::G6DOFJointAxisFlag(i), flags_y[i]);
- PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_Z, PhysicsServer::G6DOFJointAxisFlag(i), flags_z[i]);
- }
-
- return j;
-}
-
-Generic6DOFJoint::Generic6DOFJoint() :
- precision(1) {
-
- set_param_x(PARAM_LINEAR_LOWER_LIMIT, 0);
- set_param_x(PARAM_LINEAR_UPPER_LIMIT, 0);
- set_param_x(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
- set_param_x(PARAM_LINEAR_RESTITUTION, 0.5);
- set_param_x(PARAM_LINEAR_DAMPING, 1.0);
- set_param_x(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
- set_param_x(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
- set_param_x(PARAM_LINEAR_SPRING_STIFFNESS, 0.01);
- set_param_x(PARAM_LINEAR_SPRING_DAMPING, 0.01);
- set_param_x(PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT, 0.0);
- set_param_x(PARAM_ANGULAR_LOWER_LIMIT, 0);
- set_param_x(PARAM_ANGULAR_UPPER_LIMIT, 0);
- set_param_x(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
- set_param_x(PARAM_ANGULAR_DAMPING, 1.0f);
- set_param_x(PARAM_ANGULAR_RESTITUTION, 0);
- set_param_x(PARAM_ANGULAR_FORCE_LIMIT, 0);
- set_param_x(PARAM_ANGULAR_ERP, 0.5);
- set_param_x(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY, 0);
- set_param_x(PARAM_ANGULAR_MOTOR_FORCE_LIMIT, 300);
- set_param_x(PARAM_ANGULAR_SPRING_STIFFNESS, 0);
- set_param_x(PARAM_ANGULAR_SPRING_DAMPING, 0);
- set_param_x(PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0);
-
- set_flag_x(FLAG_ENABLE_ANGULAR_LIMIT, true);
- set_flag_x(FLAG_ENABLE_LINEAR_LIMIT, true);
- set_flag_x(FLAG_ENABLE_ANGULAR_SPRING, false);
- set_flag_x(FLAG_ENABLE_LINEAR_SPRING, false);
- set_flag_x(FLAG_ENABLE_MOTOR, false);
- set_flag_x(FLAG_ENABLE_LINEAR_MOTOR, false);
-
- set_param_y(PARAM_LINEAR_LOWER_LIMIT, 0);
- set_param_y(PARAM_LINEAR_UPPER_LIMIT, 0);
- set_param_y(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
- set_param_y(PARAM_LINEAR_RESTITUTION, 0.5);
- set_param_y(PARAM_LINEAR_DAMPING, 1.0);
- set_param_y(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
- set_param_y(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
- set_param_y(PARAM_LINEAR_SPRING_STIFFNESS, 0.01);
- set_param_y(PARAM_LINEAR_SPRING_DAMPING, 0.01);
- set_param_y(PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT, 0.0);
- set_param_y(PARAM_ANGULAR_LOWER_LIMIT, 0);
- set_param_y(PARAM_ANGULAR_UPPER_LIMIT, 0);
- set_param_y(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
- set_param_y(PARAM_ANGULAR_DAMPING, 1.0f);
- set_param_y(PARAM_ANGULAR_RESTITUTION, 0);
- set_param_y(PARAM_ANGULAR_FORCE_LIMIT, 0);
- set_param_y(PARAM_ANGULAR_ERP, 0.5);
- set_param_y(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY, 0);
- set_param_y(PARAM_ANGULAR_MOTOR_FORCE_LIMIT, 300);
- set_param_y(PARAM_ANGULAR_SPRING_STIFFNESS, 0);
- set_param_y(PARAM_ANGULAR_SPRING_DAMPING, 0);
- set_param_y(PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0);
-
- set_flag_y(FLAG_ENABLE_ANGULAR_LIMIT, true);
- set_flag_y(FLAG_ENABLE_LINEAR_LIMIT, true);
- set_flag_y(FLAG_ENABLE_ANGULAR_SPRING, false);
- set_flag_y(FLAG_ENABLE_LINEAR_SPRING, false);
- set_flag_y(FLAG_ENABLE_MOTOR, false);
- set_flag_y(FLAG_ENABLE_LINEAR_MOTOR, false);
-
- set_param_z(PARAM_LINEAR_LOWER_LIMIT, 0);
- set_param_z(PARAM_LINEAR_UPPER_LIMIT, 0);
- set_param_z(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
- set_param_z(PARAM_LINEAR_RESTITUTION, 0.5);
- set_param_z(PARAM_LINEAR_DAMPING, 1.0);
- set_param_z(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
- set_param_z(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
- set_param_z(PARAM_LINEAR_SPRING_STIFFNESS, 0.01);
- set_param_z(PARAM_LINEAR_SPRING_DAMPING, 0.01);
- set_param_z(PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT, 0.0);
- set_param_z(PARAM_ANGULAR_LOWER_LIMIT, 0);
- set_param_z(PARAM_ANGULAR_UPPER_LIMIT, 0);
- set_param_z(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
- set_param_z(PARAM_ANGULAR_DAMPING, 1.0f);
- set_param_z(PARAM_ANGULAR_RESTITUTION, 0);
- set_param_z(PARAM_ANGULAR_FORCE_LIMIT, 0);
- set_param_z(PARAM_ANGULAR_ERP, 0.5);
- set_param_z(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY, 0);
- set_param_z(PARAM_ANGULAR_MOTOR_FORCE_LIMIT, 300);
- set_param_z(PARAM_ANGULAR_SPRING_STIFFNESS, 0);
- set_param_z(PARAM_ANGULAR_SPRING_DAMPING, 0);
- set_param_z(PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0);
-
- set_flag_z(FLAG_ENABLE_ANGULAR_LIMIT, true);
- set_flag_z(FLAG_ENABLE_LINEAR_LIMIT, true);
- set_flag_z(FLAG_ENABLE_ANGULAR_SPRING, false);
- set_flag_z(FLAG_ENABLE_LINEAR_SPRING, false);
- set_flag_z(FLAG_ENABLE_MOTOR, false);
- set_flag_z(FLAG_ENABLE_LINEAR_MOTOR, false);
-}
diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h
deleted file mode 100644
index d03dbac392..0000000000
--- a/scene/3d/physics_joint.h
+++ /dev/null
@@ -1,343 +0,0 @@
-/*************************************************************************/
-/* physics_joint.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS_JOINT_H
-#define PHYSICS_JOINT_H
-
-#include "scene/3d/physics_body.h"
-#include "scene/3d/spatial.h"
-
-class Joint : public Spatial {
-
- GDCLASS(Joint, Spatial);
-
- RID ba, bb;
-
- RID joint;
-
- NodePath a;
- NodePath b;
-
- int solver_priority;
- bool exclude_from_collision;
-
-protected:
- void _update_joint(bool p_only_free = false);
-
- void _notification(int p_what);
-
- virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b) = 0;
-
- static void _bind_methods();
-
-public:
- void set_node_a(const NodePath &p_node_a);
- NodePath get_node_a() const;
-
- void set_node_b(const NodePath &p_node_b);
- NodePath get_node_b() const;
-
- void set_solver_priority(int p_priority);
- int get_solver_priority() const;
-
- void set_exclude_nodes_from_collision(bool p_enable);
- bool get_exclude_nodes_from_collision() const;
-
- RID get_joint() const { return joint; }
- Joint();
-};
-
-///////////////////////////////////////////
-
-class PinJoint : public Joint {
-
- GDCLASS(PinJoint, Joint);
-
-public:
- enum Param {
- PARAM_BIAS = PhysicsServer::PIN_JOINT_BIAS,
- PARAM_DAMPING = PhysicsServer::PIN_JOINT_DAMPING,
- PARAM_IMPULSE_CLAMP = PhysicsServer::PIN_JOINT_IMPULSE_CLAMP
- };
-
-protected:
- float params[3];
- virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
- static void _bind_methods();
-
-public:
- void set_param(Param p_param, float p_value);
- float get_param(Param p_param) const;
-
- PinJoint();
-};
-
-VARIANT_ENUM_CAST(PinJoint::Param);
-
-class HingeJoint : public Joint {
-
- GDCLASS(HingeJoint, Joint);
-
-public:
- enum Param {
- PARAM_BIAS = PhysicsServer::HINGE_JOINT_BIAS,
- PARAM_LIMIT_UPPER = PhysicsServer::HINGE_JOINT_LIMIT_UPPER,
- PARAM_LIMIT_LOWER = PhysicsServer::HINGE_JOINT_LIMIT_LOWER,
- PARAM_LIMIT_BIAS = PhysicsServer::HINGE_JOINT_LIMIT_BIAS,
- PARAM_LIMIT_SOFTNESS = PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS,
- PARAM_LIMIT_RELAXATION = PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION,
- PARAM_MOTOR_TARGET_VELOCITY = PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY,
- PARAM_MOTOR_MAX_IMPULSE = PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE,
- PARAM_MAX = PhysicsServer::HINGE_JOINT_MAX
- };
-
- enum Flag {
- FLAG_USE_LIMIT = PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT,
- FLAG_ENABLE_MOTOR = PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR,
- FLAG_MAX = PhysicsServer::HINGE_JOINT_FLAG_MAX
- };
-
-protected:
- float params[PARAM_MAX];
- bool flags[FLAG_MAX];
- virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
- static void _bind_methods();
-
- void _set_upper_limit(float p_limit);
- float _get_upper_limit() const;
-
- void _set_lower_limit(float p_limit);
- float _get_lower_limit() const;
-
-public:
- void set_param(Param p_param, float p_value);
- float get_param(Param p_param) const;
-
- void set_flag(Flag p_flag, bool p_value);
- bool get_flag(Flag p_flag) const;
-
- HingeJoint();
-};
-
-VARIANT_ENUM_CAST(HingeJoint::Param);
-VARIANT_ENUM_CAST(HingeJoint::Flag);
-
-class SliderJoint : public Joint {
-
- GDCLASS(SliderJoint, Joint);
-
-public:
- enum Param {
- PARAM_LINEAR_LIMIT_UPPER = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER,
- PARAM_LINEAR_LIMIT_LOWER = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER,
- PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
- PARAM_LINEAR_LIMIT_RESTITUTION = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
- PARAM_LINEAR_LIMIT_DAMPING = PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
- PARAM_LINEAR_MOTION_SOFTNESS = PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
- PARAM_LINEAR_MOTION_RESTITUTION = PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
- PARAM_LINEAR_MOTION_DAMPING = PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING,
- PARAM_LINEAR_ORTHOGONAL_SOFTNESS = PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
- PARAM_LINEAR_ORTHOGONAL_RESTITUTION = PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
- PARAM_LINEAR_ORTHOGONAL_DAMPING = PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
-
- PARAM_ANGULAR_LIMIT_UPPER = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
- PARAM_ANGULAR_LIMIT_LOWER = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
- PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
- PARAM_ANGULAR_LIMIT_RESTITUTION = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
- PARAM_ANGULAR_LIMIT_DAMPING = PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
- PARAM_ANGULAR_MOTION_SOFTNESS = PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
- PARAM_ANGULAR_MOTION_RESTITUTION = PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
- PARAM_ANGULAR_MOTION_DAMPING = PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
- PARAM_ANGULAR_ORTHOGONAL_SOFTNESS = PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
- PARAM_ANGULAR_ORTHOGONAL_RESTITUTION = PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
- PARAM_ANGULAR_ORTHOGONAL_DAMPING = PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
- PARAM_MAX = PhysicsServer::SLIDER_JOINT_MAX
-
- };
-
-protected:
- void _set_upper_limit_angular(float p_limit_angular);
- float _get_upper_limit_angular() const;
-
- void _set_lower_limit_angular(float p_limit_angular);
- float _get_lower_limit_angular() const;
-
- float params[PARAM_MAX];
- virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
- static void _bind_methods();
-
-public:
- void set_param(Param p_param, float p_value);
- float get_param(Param p_param) const;
-
- SliderJoint();
-};
-
-VARIANT_ENUM_CAST(SliderJoint::Param);
-
-class ConeTwistJoint : public Joint {
-
- GDCLASS(ConeTwistJoint, Joint);
-
-public:
- enum Param {
-
- PARAM_SWING_SPAN,
- PARAM_TWIST_SPAN,
- PARAM_BIAS,
- PARAM_SOFTNESS,
- PARAM_RELAXATION,
- PARAM_MAX
- };
-
-protected:
- void _set_swing_span(float p_limit_angular);
- float _get_swing_span() const;
-
- void _set_twist_span(float p_limit_angular);
- float _get_twist_span() const;
-
- float params[PARAM_MAX];
- virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
- static void _bind_methods();
-
-public:
- void set_param(Param p_param, float p_value);
- float get_param(Param p_param) const;
-
- ConeTwistJoint();
-};
-
-VARIANT_ENUM_CAST(ConeTwistJoint::Param);
-
-class Generic6DOFJoint : public Joint {
-
- GDCLASS(Generic6DOFJoint, Joint);
-
-public:
- enum Param {
-
- PARAM_LINEAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT,
- PARAM_LINEAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT,
- PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
- PARAM_LINEAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION,
- PARAM_LINEAR_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING,
- PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
- PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
- PARAM_LINEAR_SPRING_STIFFNESS = PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS,
- PARAM_LINEAR_SPRING_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING,
- PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT,
- PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
- PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
- PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
- PARAM_ANGULAR_DAMPING = PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING,
- PARAM_ANGULAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION,
- PARAM_ANGULAR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
- PARAM_ANGULAR_ERP = PhysicsServer::G6DOF_JOINT_ANGULAR_ERP,
- PARAM_ANGULAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
- PARAM_ANGULAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
- PARAM_ANGULAR_SPRING_STIFFNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS,
- PARAM_ANGULAR_SPRING_DAMPING = PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING,
- PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT,
- PARAM_MAX = PhysicsServer::G6DOF_JOINT_MAX,
- };
-
- enum Flag {
- FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
- FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
- FLAG_ENABLE_LINEAR_SPRING = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING,
- FLAG_ENABLE_ANGULAR_SPRING = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING,
- FLAG_ENABLE_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR,
- FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
- FLAG_MAX = PhysicsServer::G6DOF_JOINT_FLAG_MAX
- };
-
-protected:
- void _set_angular_hi_limit_x(float p_limit_angular);
- float _get_angular_hi_limit_x() const;
-
- void _set_angular_hi_limit_y(float p_limit_angular);
- float _get_angular_hi_limit_y() const;
-
- void _set_angular_hi_limit_z(float p_limit_angular);
- float _get_angular_hi_limit_z() const;
-
- void _set_angular_lo_limit_x(float p_limit_angular);
- float _get_angular_lo_limit_x() const;
-
- void _set_angular_lo_limit_y(float p_limit_angular);
- float _get_angular_lo_limit_y() const;
-
- void _set_angular_lo_limit_z(float p_limit_angular);
- float _get_angular_lo_limit_z() const;
-
- float params_x[PARAM_MAX];
- bool flags_x[FLAG_MAX];
- float params_y[PARAM_MAX];
- bool flags_y[FLAG_MAX];
- float params_z[PARAM_MAX];
- bool flags_z[FLAG_MAX];
-
- int precision;
-
- virtual RID _configure_joint(PhysicsBody *body_a, PhysicsBody *body_b);
- static void _bind_methods();
-
-public:
- void set_param_x(Param p_param, float p_value);
- float get_param_x(Param p_param) const;
-
- void set_param_y(Param p_param, float p_value);
- float get_param_y(Param p_param) const;
-
- void set_param_z(Param p_param, float p_value);
- float get_param_z(Param p_param) const;
-
- void set_flag_x(Flag p_flag, bool p_enabled);
- bool get_flag_x(Flag p_flag) const;
-
- void set_flag_y(Flag p_flag, bool p_enabled);
- bool get_flag_y(Flag p_flag) const;
-
- void set_flag_z(Flag p_flag, bool p_enabled);
- bool get_flag_z(Flag p_flag) const;
-
- void set_precision(int p_precision);
- int get_precision() const {
- return precision;
- }
-
- Generic6DOFJoint();
-};
-
-VARIANT_ENUM_CAST(Generic6DOFJoint::Param);
-VARIANT_ENUM_CAST(Generic6DOFJoint::Flag);
-
-#endif // PHYSICS_JOINT_H
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
new file mode 100644
index 0000000000..591c17a91e
--- /dev/null
+++ b/scene/3d/physics_joint_3d.cpp
@@ -0,0 +1,1049 @@
+/*************************************************************************/
+/* physics_joint_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_joint_3d.h"
+
+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 (p_only_free || !is_inside_tree())
+ return;
+
+ Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)nullptr;
+ Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)nullptr;
+
+ PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a);
+ PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b);
+
+ if (!body_a && body_b)
+ SWAP(body_a, body_b);
+
+ if (!body_a)
+ return;
+
+ joint = _configure_joint(body_a, body_b);
+
+ if (!joint.is_valid())
+ return;
+
+ PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority);
+
+ ba = body_a->get_rid();
+ if (body_b)
+ bb = body_b->get_rid();
+
+ PhysicsServer3D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
+}
+
+void Joint3D::set_node_a(const NodePath &p_node_a) {
+
+ if (a == p_node_a)
+ return;
+
+ a = p_node_a;
+ _update_joint();
+}
+
+NodePath Joint3D::get_node_a() const {
+
+ return a;
+}
+
+void Joint3D::set_node_b(const NodePath &p_node_b) {
+
+ if (b == p_node_b)
+ return;
+ b = p_node_b;
+ _update_joint();
+}
+NodePath Joint3D::get_node_b() const {
+
+ return b;
+}
+
+void Joint3D::set_solver_priority(int p_priority) {
+
+ solver_priority = p_priority;
+ if (joint.is_valid())
+ PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority);
+}
+
+int Joint3D::get_solver_priority() const {
+
+ return solver_priority;
+}
+
+void Joint3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_READY: {
+ _update_joint();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (joint.is_valid()) {
+ _update_joint(true);
+ }
+ } break;
+ }
+}
+
+void Joint3D::set_exclude_nodes_from_collision(bool p_enable) {
+
+ if (exclude_from_collision == p_enable)
+ return;
+ exclude_from_collision = p_enable;
+ _update_joint();
+}
+
+bool Joint3D::get_exclude_nodes_from_collision() const {
+
+ return exclude_from_collision;
+}
+
+void Joint3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint3D::set_node_a);
+ ClassDB::bind_method(D_METHOD("get_node_a"), &Joint3D::get_node_a);
+
+ ClassDB::bind_method(D_METHOD("set_node_b", "node"), &Joint3D::set_node_b);
+ ClassDB::bind_method(D_METHOD("get_node_b"), &Joint3D::get_node_b);
+
+ ClassDB::bind_method(D_METHOD("set_solver_priority", "priority"), &Joint3D::set_solver_priority);
+ ClassDB::bind_method(D_METHOD("get_solver_priority"), &Joint3D::get_solver_priority);
+
+ ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision);
+ ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject3D"), "set_node_a", "get_node_a");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject3D"), "set_node_b", "get_node_b");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
+}
+
+Joint3D::Joint3D() {
+
+ exclude_from_collision = true;
+ solver_priority = 1;
+ set_notify_transform(true);
+}
+
+///////////////////////////////////
+
+void PinJoint3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &PinJoint3D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &PinJoint3D::get_param);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"), "set_param", "get_param", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"), "set_param", "get_param", PARAM_IMPULSE_CLAMP);
+
+ BIND_ENUM_CONSTANT(PARAM_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_IMPULSE_CLAMP);
+}
+
+void PinJoint3D::set_param(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, 3);
+ params[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer3D::PinJointParam(p_param), p_value);
+}
+float PinJoint3D::get_param(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, 3, 0);
+ return params[p_param];
+}
+
+RID PinJoint3D::_configure_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;
+
+ if (body_b)
+ local_b = body_b->get_global_transform().affine_inverse().xform(pinpos);
+ else
+ 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);
+ for (int i = 0; i < 3; i++) {
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PinJointParam(i), params[i]);
+ }
+ return j;
+}
+
+PinJoint3D::PinJoint3D() {
+
+ params[PARAM_BIAS] = 0.3;
+ params[PARAM_DAMPING] = 1;
+ params[PARAM_IMPULSE_CLAMP] = 0;
+}
+
+/////////////////////////////////////////////////
+
+///////////////////////////////////
+
+void HingeJoint3D::_set_upper_limit(float p_limit) {
+
+ set_param(PARAM_LIMIT_UPPER, Math::deg2rad(p_limit));
+}
+
+float HingeJoint3D::_get_upper_limit() const {
+
+ return Math::rad2deg(get_param(PARAM_LIMIT_UPPER));
+}
+
+void HingeJoint3D::_set_lower_limit(float p_limit) {
+
+ set_param(PARAM_LIMIT_LOWER, Math::deg2rad(p_limit));
+}
+
+float HingeJoint3D::_get_lower_limit() const {
+
+ return Math::rad2deg(get_param(PARAM_LIMIT_LOWER));
+}
+
+void HingeJoint3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &HingeJoint3D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &HingeJoint3D::get_param);
+
+ ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &HingeJoint3D::set_flag);
+ ClassDB::bind_method(D_METHOD("get_flag", "flag"), &HingeJoint3D::get_flag);
+
+ ClassDB::bind_method(D_METHOD("_set_upper_limit", "upper_limit"), &HingeJoint3D::_set_upper_limit);
+ ClassDB::bind_method(D_METHOD("_get_upper_limit"), &HingeJoint3D::_get_upper_limit);
+
+ ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint3D::_set_lower_limit);
+ ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint3D::_get_lower_limit);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit", "_get_lower_limit");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE);
+
+ BIND_ENUM_CONSTANT(PARAM_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_LIMIT_UPPER);
+ BIND_ENUM_CONSTANT(PARAM_LIMIT_LOWER);
+ BIND_ENUM_CONSTANT(PARAM_LIMIT_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_LIMIT_RELAXATION);
+ BIND_ENUM_CONSTANT(PARAM_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_MOTOR_MAX_IMPULSE);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(FLAG_USE_LIMIT);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+}
+
+void HingeJoint3D::set_param(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ params[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_joint(), PhysicsServer3D::HingeJointParam(p_param), p_value);
+
+ update_gizmo();
+}
+float HingeJoint3D::get_param(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return params[p_param];
+}
+
+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())
+ PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_joint(), PhysicsServer3D::HingeJointFlag(p_flag), p_value);
+
+ update_gizmo();
+}
+bool HingeJoint3D::get_flag(Flag p_flag) const {
+
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags[p_flag];
+}
+
+RID HingeJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+
+ Transform gt = get_global_transform();
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ 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);
+ for (int i = 0; i < PARAM_MAX; i++) {
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, 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]);
+ }
+ return j;
+}
+
+HingeJoint3D::HingeJoint3D() {
+
+ params[PARAM_BIAS] = 0.3;
+ params[PARAM_LIMIT_UPPER] = Math_PI * 0.5;
+ params[PARAM_LIMIT_LOWER] = -Math_PI * 0.5;
+ params[PARAM_LIMIT_BIAS] = 0.3;
+ params[PARAM_LIMIT_SOFTNESS] = 0.9;
+ params[PARAM_LIMIT_RELAXATION] = 1.0;
+ params[PARAM_MOTOR_TARGET_VELOCITY] = 1;
+ params[PARAM_MOTOR_MAX_IMPULSE] = 1;
+
+ flags[FLAG_USE_LIMIT] = false;
+ flags[FLAG_ENABLE_MOTOR] = false;
+}
+
+/////////////////////////////////////////////////
+
+//////////////////////////////////
+
+void SliderJoint3D::_set_upper_limit_angular(float p_limit_angular) {
+
+ set_param(PARAM_ANGULAR_LIMIT_UPPER, Math::deg2rad(p_limit_angular));
+}
+
+float SliderJoint3D::_get_upper_limit_angular() const {
+
+ return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_UPPER));
+}
+
+void SliderJoint3D::_set_lower_limit_angular(float p_limit_angular) {
+
+ set_param(PARAM_ANGULAR_LIMIT_LOWER, Math::deg2rad(p_limit_angular));
+}
+
+float SliderJoint3D::_get_lower_limit_angular() const {
+
+ return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_LOWER));
+}
+
+void SliderJoint3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &SliderJoint3D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &SliderJoint3D::get_param);
+
+ ClassDB::bind_method(D_METHOD("_set_upper_limit_angular", "upper_limit_angular"), &SliderJoint3D::_set_upper_limit_angular);
+ ClassDB::bind_method(D_METHOD("_get_upper_limit_angular"), &SliderJoint3D::_get_upper_limit_angular);
+
+ ClassDB::bind_method(D_METHOD("_set_lower_limit_angular", "lower_limit_angular"), &SliderJoint3D::_set_lower_limit_angular);
+ ClassDB::bind_method(D_METHOD("_get_lower_limit_angular"), &SliderJoint3D::_get_lower_limit_angular);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit_angular", "_get_upper_limit_angular");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit_angular", "_get_lower_limit_angular");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_DAMPING);
+
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_UPPER);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_LOWER);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_DAMPING);
+
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_UPPER);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_LOWER);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_DAMPING);
+
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+}
+
+void SliderJoint3D::set_param(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ params[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(get_joint(), PhysicsServer3D::SliderJointParam(p_param), p_value);
+ update_gizmo();
+}
+float SliderJoint3D::get_param(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return params[p_param];
+}
+
+RID SliderJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
+
+ Transform gt = get_global_transform();
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ 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);
+ for (int i = 0; i < PARAM_MAX; i++) {
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SliderJointParam(i), params[i]);
+ }
+
+ return j;
+}
+
+SliderJoint3D::SliderJoint3D() {
+
+ params[PARAM_LINEAR_LIMIT_UPPER] = 1.0;
+ params[PARAM_LINEAR_LIMIT_LOWER] = -1.0;
+ params[PARAM_LINEAR_LIMIT_SOFTNESS] = 1.0;
+ params[PARAM_LINEAR_LIMIT_RESTITUTION] = 0.7;
+ params[PARAM_LINEAR_LIMIT_DAMPING] = 1.0;
+ params[PARAM_LINEAR_MOTION_SOFTNESS] = 1.0;
+ params[PARAM_LINEAR_MOTION_RESTITUTION] = 0.7;
+ params[PARAM_LINEAR_MOTION_DAMPING] = 0; //1.0;
+ params[PARAM_LINEAR_ORTHOGONAL_SOFTNESS] = 1.0;
+ params[PARAM_LINEAR_ORTHOGONAL_RESTITUTION] = 0.7;
+ params[PARAM_LINEAR_ORTHOGONAL_DAMPING] = 1.0;
+
+ params[PARAM_ANGULAR_LIMIT_UPPER] = 0;
+ params[PARAM_ANGULAR_LIMIT_LOWER] = 0;
+ params[PARAM_ANGULAR_LIMIT_SOFTNESS] = 1.0;
+ params[PARAM_ANGULAR_LIMIT_RESTITUTION] = 0.7;
+ params[PARAM_ANGULAR_LIMIT_DAMPING] = 0; //1.0;
+ params[PARAM_ANGULAR_MOTION_SOFTNESS] = 1.0;
+ params[PARAM_ANGULAR_MOTION_RESTITUTION] = 0.7;
+ params[PARAM_ANGULAR_MOTION_DAMPING] = 1.0;
+ params[PARAM_ANGULAR_ORTHOGONAL_SOFTNESS] = 1.0;
+ params[PARAM_ANGULAR_ORTHOGONAL_RESTITUTION] = 0.7;
+ params[PARAM_ANGULAR_ORTHOGONAL_DAMPING] = 1.0;
+}
+
+//////////////////////////////////
+
+void ConeTwistJoint3D::_set_swing_span(float p_limit_angular) {
+
+ set_param(PARAM_SWING_SPAN, Math::deg2rad(p_limit_angular));
+}
+
+float ConeTwistJoint3D::_get_swing_span() const {
+
+ return Math::rad2deg(get_param(PARAM_SWING_SPAN));
+}
+
+void ConeTwistJoint3D::_set_twist_span(float p_limit_angular) {
+
+ set_param(PARAM_TWIST_SPAN, Math::deg2rad(p_limit_angular));
+}
+
+float ConeTwistJoint3D::_get_twist_span() const {
+
+ return Math::rad2deg(get_param(PARAM_TWIST_SPAN));
+}
+
+void ConeTwistJoint3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ConeTwistJoint3D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &ConeTwistJoint3D::get_param);
+
+ ClassDB::bind_method(D_METHOD("_set_swing_span", "swing_span"), &ConeTwistJoint3D::_set_swing_span);
+ ClassDB::bind_method(D_METHOD("_get_swing_span"), &ConeTwistJoint3D::_get_swing_span);
+
+ ClassDB::bind_method(D_METHOD("_set_twist_span", "twist_span"), &ConeTwistJoint3D::_set_twist_span);
+ ClassDB::bind_method(D_METHOD("_get_twist_span"), &ConeTwistJoint3D::_get_twist_span);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_swing_span", "_get_swing_span");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"), "_set_twist_span", "_get_twist_span");
+
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_RELAXATION);
+
+ BIND_ENUM_CONSTANT(PARAM_SWING_SPAN);
+ BIND_ENUM_CONSTANT(PARAM_TWIST_SPAN);
+ BIND_ENUM_CONSTANT(PARAM_BIAS);
+ BIND_ENUM_CONSTANT(PARAM_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_RELAXATION);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+}
+
+void ConeTwistJoint3D::set_param(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ params[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_joint(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value);
+
+ update_gizmo();
+}
+float ConeTwistJoint3D::get_param(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return params[p_param];
+}
+
+RID ConeTwistJoint3D::_configure_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);
+
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ 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);
+ for (int i = 0; i < PARAM_MAX; i++) {
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::ConeTwistJointParam(i), params[i]);
+ }
+
+ return j;
+}
+
+ConeTwistJoint3D::ConeTwistJoint3D() {
+
+ params[PARAM_SWING_SPAN] = Math_PI * 0.25;
+ params[PARAM_TWIST_SPAN] = Math_PI;
+ params[PARAM_BIAS] = 0.3;
+ params[PARAM_SOFTNESS] = 0.8;
+ params[PARAM_RELAXATION] = 1.0;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+void Generic6DOFJoint3D::_set_angular_hi_limit_x(float p_limit_angular) {
+
+ set_param_x(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint3D::_get_angular_hi_limit_x() const {
+
+ return Math::rad2deg(get_param_x(PARAM_ANGULAR_UPPER_LIMIT));
+}
+
+void Generic6DOFJoint3D::_set_angular_lo_limit_x(float p_limit_angular) {
+
+ set_param_x(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint3D::_get_angular_lo_limit_x() const {
+
+ return Math::rad2deg(get_param_x(PARAM_ANGULAR_LOWER_LIMIT));
+}
+
+void Generic6DOFJoint3D::_set_angular_hi_limit_y(float p_limit_angular) {
+
+ set_param_y(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint3D::_get_angular_hi_limit_y() const {
+
+ return Math::rad2deg(get_param_y(PARAM_ANGULAR_UPPER_LIMIT));
+}
+
+void Generic6DOFJoint3D::_set_angular_lo_limit_y(float p_limit_angular) {
+
+ set_param_y(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint3D::_get_angular_lo_limit_y() const {
+
+ return Math::rad2deg(get_param_y(PARAM_ANGULAR_LOWER_LIMIT));
+}
+
+void Generic6DOFJoint3D::_set_angular_hi_limit_z(float p_limit_angular) {
+
+ set_param_z(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint3D::_get_angular_hi_limit_z() const {
+
+ return Math::rad2deg(get_param_z(PARAM_ANGULAR_UPPER_LIMIT));
+}
+
+void Generic6DOFJoint3D::_set_angular_lo_limit_z(float p_limit_angular) {
+
+ set_param_z(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
+}
+
+float Generic6DOFJoint3D::_get_angular_lo_limit_z() const {
+
+ return Math::rad2deg(get_param_z(PARAM_ANGULAR_LOWER_LIMIT));
+}
+
+void Generic6DOFJoint3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_x", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_x);
+ ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_x"), &Generic6DOFJoint3D::_get_angular_hi_limit_x);
+
+ ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_x", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_x);
+ ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_x"), &Generic6DOFJoint3D::_get_angular_lo_limit_x);
+
+ ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_y", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_y);
+ ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_y"), &Generic6DOFJoint3D::_get_angular_hi_limit_y);
+
+ ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_y", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_y);
+ ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_y"), &Generic6DOFJoint3D::_get_angular_lo_limit_y);
+
+ ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_z", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_z);
+ ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_z"), &Generic6DOFJoint3D::_get_angular_hi_limit_z);
+
+ ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_z", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_z);
+ ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_z"), &Generic6DOFJoint3D::_get_angular_lo_limit_z);
+
+ ClassDB::bind_method(D_METHOD("set_param_x", "param", "value"), &Generic6DOFJoint3D::set_param_x);
+ ClassDB::bind_method(D_METHOD("get_param_x", "param"), &Generic6DOFJoint3D::get_param_x);
+
+ ClassDB::bind_method(D_METHOD("set_param_y", "param", "value"), &Generic6DOFJoint3D::set_param_y);
+ ClassDB::bind_method(D_METHOD("get_param_y", "param"), &Generic6DOFJoint3D::get_param_y);
+
+ ClassDB::bind_method(D_METHOD("set_param_z", "param", "value"), &Generic6DOFJoint3D::set_param_z);
+ ClassDB::bind_method(D_METHOD("get_param_z", "param"), &Generic6DOFJoint3D::get_param_z);
+
+ ClassDB::bind_method(D_METHOD("set_flag_x", "flag", "value"), &Generic6DOFJoint3D::set_flag_x);
+ ClassDB::bind_method(D_METHOD("get_flag_x", "flag"), &Generic6DOFJoint3D::get_flag_x);
+
+ ClassDB::bind_method(D_METHOD("set_flag_y", "flag", "value"), &Generic6DOFJoint3D::set_flag_y);
+ ClassDB::bind_method(D_METHOD("get_flag_y", "flag"), &Generic6DOFJoint3D::get_flag_y);
+
+ ClassDB::bind_method(D_METHOD("set_flag_z", "flag", "value"), &Generic6DOFJoint3D::set_flag_z);
+ ClassDB::bind_method(D_METHOD("get_flag_z", "flag"), &Generic6DOFJoint3D::get_flag_z);
+
+ ClassDB::bind_method(D_METHOD("set_precision", "precision"), &Generic6DOFJoint3D::set_precision);
+ ClassDB::bind_method(D_METHOD("get_precision"), &Generic6DOFJoint3D::get_precision);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/upper_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/lower_distance"), "set_param_x", "get_param_x", PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/damping"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/stiffness"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/damping"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_x/equilibrium_point"), "set_param_x", "get_param_x", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/upper_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/lower_distance"), "set_param_y", "get_param_y", PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/damping"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/stiffness"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/damping"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_y/equilibrium_point"), "set_param_y", "get_param_y", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/upper_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/lower_distance"), "set_param_z", "get_param_z", PARAM_LINEAR_LOWER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/damping"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_LIMIT_SOFTNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_RESTITUTION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/erp"), "set_param_z", "get_param_z", PARAM_ANGULAR_ERP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_spring_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_SPRING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/stiffness"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_STIFFNESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/damping"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_spring_z/equilibrium_point"), "set_param_z", "get_param_z", PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "precision", PROPERTY_HINT_RANGE, "1,99999,1"), "set_precision", "get_precision");
+
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LOWER_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_UPPER_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LOWER_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_UPPER_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_RESTITUTION);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_ERP);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_LIMIT);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_LIMIT);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_SPRING);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_SPRING);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_MOTOR);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+}
+
+void Generic6DOFJoint3D::set_param_x(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ params_x[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
+
+ update_gizmo();
+}
+float Generic6DOFJoint3D::get_param_x(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return params_x[p_param];
+}
+
+void Generic6DOFJoint3D::set_param_y(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ params_y[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
+ update_gizmo();
+}
+float Generic6DOFJoint3D::get_param_y(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return params_y[p_param];
+}
+
+void Generic6DOFJoint3D::set_param_z(Param p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+ params_z[p_param] = p_value;
+ if (get_joint().is_valid())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
+ update_gizmo();
+}
+float Generic6DOFJoint3D::get_param_z(Param p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+ return params_z[p_param];
+}
+
+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())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
+ update_gizmo();
+}
+bool Generic6DOFJoint3D::get_flag_x(Flag p_flag) const {
+
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags_x[p_flag];
+}
+
+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())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
+ update_gizmo();
+}
+bool Generic6DOFJoint3D::get_flag_y(Flag p_flag) const {
+
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags_y[p_flag];
+}
+
+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())
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
+ update_gizmo();
+}
+bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const {
+
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags_z[p_flag];
+}
+
+void Generic6DOFJoint3D::set_precision(int p_precision) {
+ precision = p_precision;
+
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_precision(
+ get_joint(),
+ precision);
+}
+
+RID Generic6DOFJoint3D::_configure_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);
+
+ Transform ainv = body_a->get_global_transform().affine_inverse();
+
+ Transform local_a = ainv * gt;
+ local_a.orthonormalize();
+ Transform local_b = gt;
+
+ if (body_b) {
+ Transform binv = body_b->get_global_transform().affine_inverse();
+ local_b = binv * gt;
+ }
+
+ 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);
+ 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]);
+ }
+ 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]);
+ }
+
+ return j;
+}
+
+Generic6DOFJoint3D::Generic6DOFJoint3D() :
+ precision(1) {
+
+ set_param_x(PARAM_LINEAR_LOWER_LIMIT, 0);
+ set_param_x(PARAM_LINEAR_UPPER_LIMIT, 0);
+ set_param_x(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
+ set_param_x(PARAM_LINEAR_RESTITUTION, 0.5);
+ set_param_x(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_x(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_x(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
+ set_param_x(PARAM_LINEAR_SPRING_STIFFNESS, 0.01);
+ set_param_x(PARAM_LINEAR_SPRING_DAMPING, 0.01);
+ set_param_x(PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT, 0.0);
+ set_param_x(PARAM_ANGULAR_LOWER_LIMIT, 0);
+ set_param_x(PARAM_ANGULAR_UPPER_LIMIT, 0);
+ set_param_x(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
+ set_param_x(PARAM_ANGULAR_DAMPING, 1.0f);
+ set_param_x(PARAM_ANGULAR_RESTITUTION, 0);
+ set_param_x(PARAM_ANGULAR_FORCE_LIMIT, 0);
+ set_param_x(PARAM_ANGULAR_ERP, 0.5);
+ set_param_x(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_x(PARAM_ANGULAR_MOTOR_FORCE_LIMIT, 300);
+ set_param_x(PARAM_ANGULAR_SPRING_STIFFNESS, 0);
+ set_param_x(PARAM_ANGULAR_SPRING_DAMPING, 0);
+ set_param_x(PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0);
+
+ set_flag_x(FLAG_ENABLE_ANGULAR_LIMIT, true);
+ set_flag_x(FLAG_ENABLE_LINEAR_LIMIT, true);
+ set_flag_x(FLAG_ENABLE_ANGULAR_SPRING, false);
+ set_flag_x(FLAG_ENABLE_LINEAR_SPRING, false);
+ set_flag_x(FLAG_ENABLE_MOTOR, false);
+ set_flag_x(FLAG_ENABLE_LINEAR_MOTOR, false);
+
+ set_param_y(PARAM_LINEAR_LOWER_LIMIT, 0);
+ set_param_y(PARAM_LINEAR_UPPER_LIMIT, 0);
+ set_param_y(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
+ set_param_y(PARAM_LINEAR_RESTITUTION, 0.5);
+ set_param_y(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_y(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_y(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
+ set_param_y(PARAM_LINEAR_SPRING_STIFFNESS, 0.01);
+ set_param_y(PARAM_LINEAR_SPRING_DAMPING, 0.01);
+ set_param_y(PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT, 0.0);
+ set_param_y(PARAM_ANGULAR_LOWER_LIMIT, 0);
+ set_param_y(PARAM_ANGULAR_UPPER_LIMIT, 0);
+ set_param_y(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
+ set_param_y(PARAM_ANGULAR_DAMPING, 1.0f);
+ set_param_y(PARAM_ANGULAR_RESTITUTION, 0);
+ set_param_y(PARAM_ANGULAR_FORCE_LIMIT, 0);
+ set_param_y(PARAM_ANGULAR_ERP, 0.5);
+ set_param_y(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_y(PARAM_ANGULAR_MOTOR_FORCE_LIMIT, 300);
+ set_param_y(PARAM_ANGULAR_SPRING_STIFFNESS, 0);
+ set_param_y(PARAM_ANGULAR_SPRING_DAMPING, 0);
+ set_param_y(PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0);
+
+ set_flag_y(FLAG_ENABLE_ANGULAR_LIMIT, true);
+ set_flag_y(FLAG_ENABLE_LINEAR_LIMIT, true);
+ set_flag_y(FLAG_ENABLE_ANGULAR_SPRING, false);
+ set_flag_y(FLAG_ENABLE_LINEAR_SPRING, false);
+ set_flag_y(FLAG_ENABLE_MOTOR, false);
+ set_flag_y(FLAG_ENABLE_LINEAR_MOTOR, false);
+
+ set_param_z(PARAM_LINEAR_LOWER_LIMIT, 0);
+ set_param_z(PARAM_LINEAR_UPPER_LIMIT, 0);
+ set_param_z(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
+ set_param_z(PARAM_LINEAR_RESTITUTION, 0.5);
+ set_param_z(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_z(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_z(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
+ set_param_z(PARAM_LINEAR_SPRING_STIFFNESS, 0.01);
+ set_param_z(PARAM_LINEAR_SPRING_DAMPING, 0.01);
+ set_param_z(PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT, 0.0);
+ set_param_z(PARAM_ANGULAR_LOWER_LIMIT, 0);
+ set_param_z(PARAM_ANGULAR_UPPER_LIMIT, 0);
+ set_param_z(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
+ set_param_z(PARAM_ANGULAR_DAMPING, 1.0f);
+ set_param_z(PARAM_ANGULAR_RESTITUTION, 0);
+ set_param_z(PARAM_ANGULAR_FORCE_LIMIT, 0);
+ set_param_z(PARAM_ANGULAR_ERP, 0.5);
+ set_param_z(PARAM_ANGULAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_z(PARAM_ANGULAR_MOTOR_FORCE_LIMIT, 300);
+ set_param_z(PARAM_ANGULAR_SPRING_STIFFNESS, 0);
+ set_param_z(PARAM_ANGULAR_SPRING_DAMPING, 0);
+ set_param_z(PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT, 0);
+
+ set_flag_z(FLAG_ENABLE_ANGULAR_LIMIT, true);
+ set_flag_z(FLAG_ENABLE_LINEAR_LIMIT, true);
+ set_flag_z(FLAG_ENABLE_ANGULAR_SPRING, false);
+ set_flag_z(FLAG_ENABLE_LINEAR_SPRING, false);
+ set_flag_z(FLAG_ENABLE_MOTOR, false);
+ set_flag_z(FLAG_ENABLE_LINEAR_MOTOR, false);
+}
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
new file mode 100644
index 0000000000..ce0c7af5d1
--- /dev/null
+++ b/scene/3d/physics_joint_3d.h
@@ -0,0 +1,343 @@
+/*************************************************************************/
+/* physics_joint_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS_JOINT_H
+#define PHYSICS_JOINT_H
+
+#include "scene/3d/node_3d.h"
+#include "scene/3d/physics_body_3d.h"
+
+class Joint3D : public Node3D {
+
+ GDCLASS(Joint3D, Node3D);
+
+ RID ba, bb;
+
+ RID joint;
+
+ NodePath a;
+ NodePath b;
+
+ int solver_priority;
+ bool exclude_from_collision;
+
+protected:
+ void _update_joint(bool p_only_free = false);
+
+ void _notification(int p_what);
+
+ virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0;
+
+ static void _bind_methods();
+
+public:
+ void set_node_a(const NodePath &p_node_a);
+ NodePath get_node_a() const;
+
+ void set_node_b(const NodePath &p_node_b);
+ NodePath get_node_b() const;
+
+ void set_solver_priority(int p_priority);
+ int get_solver_priority() const;
+
+ void set_exclude_nodes_from_collision(bool p_enable);
+ bool get_exclude_nodes_from_collision() const;
+
+ RID get_joint() const { return joint; }
+ Joint3D();
+};
+
+///////////////////////////////////////////
+
+class PinJoint3D : public Joint3D {
+
+ GDCLASS(PinJoint3D, Joint3D);
+
+public:
+ enum Param {
+ PARAM_BIAS = PhysicsServer3D::PIN_JOINT_BIAS,
+ PARAM_DAMPING = PhysicsServer3D::PIN_JOINT_DAMPING,
+ PARAM_IMPULSE_CLAMP = PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP
+ };
+
+protected:
+ float params[3];
+ virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b);
+ static void _bind_methods();
+
+public:
+ void set_param(Param p_param, float p_value);
+ float get_param(Param p_param) const;
+
+ PinJoint3D();
+};
+
+VARIANT_ENUM_CAST(PinJoint3D::Param);
+
+class HingeJoint3D : public Joint3D {
+
+ GDCLASS(HingeJoint3D, Joint3D);
+
+public:
+ enum Param {
+ PARAM_BIAS = PhysicsServer3D::HINGE_JOINT_BIAS,
+ PARAM_LIMIT_UPPER = PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER,
+ PARAM_LIMIT_LOWER = PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER,
+ PARAM_LIMIT_BIAS = PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS,
+ PARAM_LIMIT_SOFTNESS = PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS,
+ PARAM_LIMIT_RELAXATION = PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION,
+ PARAM_MOTOR_TARGET_VELOCITY = PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY,
+ PARAM_MOTOR_MAX_IMPULSE = PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE,
+ PARAM_MAX = PhysicsServer3D::HINGE_JOINT_MAX
+ };
+
+ enum Flag {
+ FLAG_USE_LIMIT = PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT,
+ FLAG_ENABLE_MOTOR = PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR,
+ FLAG_MAX = PhysicsServer3D::HINGE_JOINT_FLAG_MAX
+ };
+
+protected:
+ float params[PARAM_MAX];
+ bool flags[FLAG_MAX];
+ virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b);
+ static void _bind_methods();
+
+ void _set_upper_limit(float p_limit);
+ float _get_upper_limit() const;
+
+ void _set_lower_limit(float p_limit);
+ float _get_lower_limit() const;
+
+public:
+ void set_param(Param p_param, float p_value);
+ float get_param(Param p_param) const;
+
+ void set_flag(Flag p_flag, bool p_value);
+ bool get_flag(Flag p_flag) const;
+
+ HingeJoint3D();
+};
+
+VARIANT_ENUM_CAST(HingeJoint3D::Param);
+VARIANT_ENUM_CAST(HingeJoint3D::Flag);
+
+class SliderJoint3D : public Joint3D {
+
+ GDCLASS(SliderJoint3D, Joint3D);
+
+public:
+ enum Param {
+ PARAM_LINEAR_LIMIT_UPPER = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER,
+ PARAM_LINEAR_LIMIT_LOWER = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER,
+ PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
+ PARAM_LINEAR_LIMIT_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
+ PARAM_LINEAR_LIMIT_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
+ PARAM_LINEAR_MOTION_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
+ PARAM_LINEAR_MOTION_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
+ PARAM_LINEAR_MOTION_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING,
+ PARAM_LINEAR_ORTHOGONAL_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
+ PARAM_LINEAR_ORTHOGONAL_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
+ PARAM_LINEAR_ORTHOGONAL_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
+
+ PARAM_ANGULAR_LIMIT_UPPER = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
+ PARAM_ANGULAR_LIMIT_LOWER = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
+ PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ PARAM_ANGULAR_LIMIT_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
+ PARAM_ANGULAR_LIMIT_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
+ PARAM_ANGULAR_MOTION_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
+ PARAM_ANGULAR_MOTION_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
+ PARAM_ANGULAR_MOTION_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
+ PARAM_ANGULAR_ORTHOGONAL_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
+ PARAM_ANGULAR_ORTHOGONAL_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
+ PARAM_ANGULAR_ORTHOGONAL_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
+ PARAM_MAX = PhysicsServer3D::SLIDER_JOINT_MAX
+
+ };
+
+protected:
+ void _set_upper_limit_angular(float p_limit_angular);
+ float _get_upper_limit_angular() const;
+
+ void _set_lower_limit_angular(float p_limit_angular);
+ float _get_lower_limit_angular() const;
+
+ float params[PARAM_MAX];
+ virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b);
+ static void _bind_methods();
+
+public:
+ void set_param(Param p_param, float p_value);
+ float get_param(Param p_param) const;
+
+ SliderJoint3D();
+};
+
+VARIANT_ENUM_CAST(SliderJoint3D::Param);
+
+class ConeTwistJoint3D : public Joint3D {
+
+ GDCLASS(ConeTwistJoint3D, Joint3D);
+
+public:
+ enum Param {
+
+ PARAM_SWING_SPAN,
+ PARAM_TWIST_SPAN,
+ PARAM_BIAS,
+ PARAM_SOFTNESS,
+ PARAM_RELAXATION,
+ PARAM_MAX
+ };
+
+protected:
+ void _set_swing_span(float p_limit_angular);
+ float _get_swing_span() const;
+
+ void _set_twist_span(float p_limit_angular);
+ float _get_twist_span() const;
+
+ float params[PARAM_MAX];
+ virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b);
+ static void _bind_methods();
+
+public:
+ void set_param(Param p_param, float p_value);
+ float get_param(Param p_param) const;
+
+ ConeTwistJoint3D();
+};
+
+VARIANT_ENUM_CAST(ConeTwistJoint3D::Param);
+
+class Generic6DOFJoint3D : public Joint3D {
+
+ GDCLASS(Generic6DOFJoint3D, Joint3D);
+
+public:
+ enum Param {
+
+ PARAM_LINEAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT,
+ PARAM_LINEAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT,
+ PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
+ PARAM_LINEAR_RESTITUTION = PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION,
+ PARAM_LINEAR_DAMPING = PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING,
+ PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
+ PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
+ PARAM_LINEAR_SPRING_STIFFNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS,
+ PARAM_LINEAR_SPRING_DAMPING = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING,
+ PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT,
+ PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
+ PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
+ PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ PARAM_ANGULAR_DAMPING = PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING,
+ PARAM_ANGULAR_RESTITUTION = PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION,
+ PARAM_ANGULAR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
+ PARAM_ANGULAR_ERP = PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP,
+ PARAM_ANGULAR_MOTOR_TARGET_VELOCITY = PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
+ PARAM_ANGULAR_MOTOR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
+ PARAM_ANGULAR_SPRING_STIFFNESS = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS,
+ PARAM_ANGULAR_SPRING_DAMPING = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING,
+ PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT,
+ PARAM_MAX = PhysicsServer3D::G6DOF_JOINT_MAX,
+ };
+
+ enum Flag {
+ FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
+ FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
+ FLAG_ENABLE_LINEAR_SPRING = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING,
+ FLAG_ENABLE_ANGULAR_SPRING = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING,
+ FLAG_ENABLE_MOTOR = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR,
+ FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
+ FLAG_MAX = PhysicsServer3D::G6DOF_JOINT_FLAG_MAX
+ };
+
+protected:
+ void _set_angular_hi_limit_x(float p_limit_angular);
+ float _get_angular_hi_limit_x() const;
+
+ void _set_angular_hi_limit_y(float p_limit_angular);
+ float _get_angular_hi_limit_y() const;
+
+ void _set_angular_hi_limit_z(float p_limit_angular);
+ float _get_angular_hi_limit_z() const;
+
+ void _set_angular_lo_limit_x(float p_limit_angular);
+ float _get_angular_lo_limit_x() const;
+
+ void _set_angular_lo_limit_y(float p_limit_angular);
+ float _get_angular_lo_limit_y() const;
+
+ void _set_angular_lo_limit_z(float p_limit_angular);
+ float _get_angular_lo_limit_z() const;
+
+ float params_x[PARAM_MAX];
+ bool flags_x[FLAG_MAX];
+ float params_y[PARAM_MAX];
+ bool flags_y[FLAG_MAX];
+ float params_z[PARAM_MAX];
+ bool flags_z[FLAG_MAX];
+
+ int precision;
+
+ virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b);
+ static void _bind_methods();
+
+public:
+ void set_param_x(Param p_param, float p_value);
+ float get_param_x(Param p_param) const;
+
+ void set_param_y(Param p_param, float p_value);
+ float get_param_y(Param p_param) const;
+
+ void set_param_z(Param p_param, float p_value);
+ float get_param_z(Param p_param) const;
+
+ void set_flag_x(Flag p_flag, bool p_enabled);
+ bool get_flag_x(Flag p_flag) const;
+
+ void set_flag_y(Flag p_flag, bool p_enabled);
+ bool get_flag_y(Flag p_flag) const;
+
+ void set_flag_z(Flag p_flag, bool p_enabled);
+ bool get_flag_z(Flag p_flag) const;
+
+ void set_precision(int p_precision);
+ int get_precision() const {
+ return precision;
+ }
+
+ Generic6DOFJoint3D();
+};
+
+VARIANT_ENUM_CAST(Generic6DOFJoint3D::Param);
+VARIANT_ENUM_CAST(Generic6DOFJoint3D::Flag);
+
+#endif // PHYSICS_JOINT_H
diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h
index cd5080c95a..9c806723fb 100644
--- a/scene/3d/position_3d.h
+++ b/scene/3d/position_3d.h
@@ -31,11 +31,11 @@
#ifndef POSITION_3D_H
#define POSITION_3D_H
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
-class Position3D : public Spatial {
+class Position3D : public Node3D {
- GDCLASS(Position3D, Spatial);
+ GDCLASS(Position3D, Node3D);
public:
Position3D();
diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp
deleted file mode 100644
index 2e1478b1cf..0000000000
--- a/scene/3d/proximity_group.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*************************************************************************/
-/* proximity_group.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "proximity_group.h"
-
-#include "core/math/math_funcs.h"
-
-void ProximityGroup::clear_groups() {
-
- Map<StringName, uint32_t>::Element *E;
-
- {
- const int size = 16;
- StringName remove_list[size];
- E = groups.front();
- int num = 0;
- while (E && num < size) {
-
- if (E->get() != group_version) {
- remove_list[num++] = E->key();
- };
-
- E = E->next();
- };
- for (int i = 0; i < num; i++) {
-
- groups.erase(remove_list[i]);
- };
- };
-
- if (E) {
- clear_groups(); // call until we go through the whole list
- };
-};
-
-void ProximityGroup::update_groups() {
-
- if (grid_radius == Vector3(0, 0, 0))
- return;
-
- ++group_version;
-
- Vector3 pos = get_global_transform().get_origin();
- Vector3 vcell = pos / cell_size;
- int cell[3] = { Math::fast_ftoi(vcell.x), Math::fast_ftoi(vcell.y), Math::fast_ftoi(vcell.z) };
-
- add_groups(cell, group_name, 0);
-
- clear_groups();
-};
-
-void ProximityGroup::add_groups(int *p_cell, String p_base, int p_depth) {
-
- p_base = p_base + "|";
- if (grid_radius[p_depth] == 0) {
-
- if (p_depth == 2) {
- _new_group(p_base);
- } else {
- add_groups(p_cell, p_base, p_depth + 1);
- };
- };
-
- int start = p_cell[p_depth] - grid_radius[p_depth];
- int end = p_cell[p_depth] + grid_radius[p_depth];
-
- for (int i = start; i <= end; i++) {
-
- String gname = p_base + itos(i);
- if (p_depth == 2) {
- _new_group(gname);
- } else {
- add_groups(p_cell, gname, p_depth + 1);
- };
- };
-};
-
-void ProximityGroup::_new_group(StringName p_name) {
-
- const Map<StringName, uint32_t>::Element *E = groups.find(p_name);
- if (!E) {
- add_to_group(p_name);
- };
-
- groups[p_name] = group_version;
-};
-
-void ProximityGroup::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_EXIT_TREE:
- ++group_version;
- clear_groups();
- break;
- case NOTIFICATION_TRANSFORM_CHANGED:
- update_groups();
- break;
- };
-};
-
-void ProximityGroup::broadcast(String p_name, Variant p_params) {
-
- Map<StringName, uint32_t>::Element *E;
- E = groups.front();
- while (E) {
-
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
- E = E->next();
- };
-};
-
-void ProximityGroup::_proximity_group_broadcast(String p_name, Variant p_params) {
-
- if (dispatch_mode == MODE_PROXY) {
-
- get_parent()->call(p_name, p_params);
- } else {
-
- emit_signal("broadcast", p_name, p_params);
- };
-};
-
-void ProximityGroup::set_group_name(const String &p_group_name) {
-
- group_name = p_group_name;
-};
-
-String ProximityGroup::get_group_name() const {
-
- return group_name;
-};
-
-void ProximityGroup::set_dispatch_mode(DispatchMode p_mode) {
-
- dispatch_mode = p_mode;
-};
-
-ProximityGroup::DispatchMode ProximityGroup::get_dispatch_mode() const {
-
- return dispatch_mode;
-};
-
-void ProximityGroup::set_grid_radius(const Vector3 &p_radius) {
-
- grid_radius = p_radius;
-};
-
-Vector3 ProximityGroup::get_grid_radius() const {
-
- return grid_radius;
-};
-
-void ProximityGroup::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup::set_group_name);
- ClassDB::bind_method(D_METHOD("get_group_name"), &ProximityGroup::get_group_name);
- ClassDB::bind_method(D_METHOD("set_dispatch_mode", "mode"), &ProximityGroup::set_dispatch_mode);
- ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup::get_dispatch_mode);
- ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup::set_grid_radius);
- ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup::get_grid_radius);
- ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup::broadcast);
- ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup::_proximity_group_broadcast);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius");
-
- ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters")));
-
- BIND_ENUM_CONSTANT(MODE_PROXY);
- BIND_ENUM_CONSTANT(MODE_SIGNAL);
-};
-
-ProximityGroup::ProximityGroup() {
-
- group_version = 0;
- dispatch_mode = MODE_PROXY;
-
- cell_size = 1.0;
- grid_radius = Vector3(1, 1, 1);
- set_notify_transform(true);
-};
-
-ProximityGroup::~ProximityGroup(){
-
-};
diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h
deleted file mode 100644
index 9ff8853178..0000000000
--- a/scene/3d/proximity_group.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*************************************************************************/
-/* proximity_group.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PROXIMITY_GROUP_H
-#define PROXIMITY_GROUP_H
-
-#include "spatial.h"
-
-class ProximityGroup : public Spatial {
-
- GDCLASS(ProximityGroup, Spatial);
- OBJ_CATEGORY("3D");
-
-public:
- enum DispatchMode {
- MODE_PROXY,
- MODE_SIGNAL,
- };
-
-public:
- void clear_groups();
- void update_groups();
-
- void _notification(int p_what);
-
- DispatchMode dispatch_mode;
-
- Map<StringName, uint32_t> groups;
- String group_name;
-
- float cell_size;
- Vector3 grid_radius;
- uint32_t group_version;
-
- void add_groups(int *p_cell, String p_base, int p_depth);
- void _new_group(StringName p_name);
-
- void _proximity_group_broadcast(String p_name, Variant p_params);
-
- static void _bind_methods();
-
-public:
- void set_group_name(const String &p_group_name);
- String get_group_name() const;
-
- void set_dispatch_mode(DispatchMode p_mode);
- DispatchMode get_dispatch_mode() const;
-
- void set_grid_radius(const Vector3 &p_radius);
- Vector3 get_grid_radius() const;
-
- void broadcast(String p_name, Variant p_params);
-
- ProximityGroup();
- ~ProximityGroup();
-};
-
-VARIANT_ENUM_CAST(ProximityGroup::DispatchMode);
-
-#endif
diff --git a/scene/3d/proximity_group_3d.cpp b/scene/3d/proximity_group_3d.cpp
new file mode 100644
index 0000000000..44ffabb655
--- /dev/null
+++ b/scene/3d/proximity_group_3d.cpp
@@ -0,0 +1,214 @@
+/*************************************************************************/
+/* proximity_group_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "proximity_group_3d.h"
+
+#include "core/math/math_funcs.h"
+
+void ProximityGroup3D::clear_groups() {
+
+ Map<StringName, uint32_t>::Element *E;
+
+ {
+ const int size = 16;
+ StringName remove_list[size];
+ E = groups.front();
+ int num = 0;
+ while (E && num < size) {
+
+ if (E->get() != group_version) {
+ remove_list[num++] = E->key();
+ };
+
+ E = E->next();
+ };
+ for (int i = 0; i < num; i++) {
+
+ groups.erase(remove_list[i]);
+ };
+ };
+
+ if (E) {
+ clear_groups(); // call until we go through the whole list
+ };
+};
+
+void ProximityGroup3D::update_groups() {
+
+ if (grid_radius == Vector3(0, 0, 0))
+ return;
+
+ ++group_version;
+
+ Vector3 pos = get_global_transform().get_origin();
+ Vector3 vcell = pos / cell_size;
+ int cell[3] = { Math::fast_ftoi(vcell.x), Math::fast_ftoi(vcell.y), Math::fast_ftoi(vcell.z) };
+
+ add_groups(cell, group_name, 0);
+
+ clear_groups();
+};
+
+void ProximityGroup3D::add_groups(int *p_cell, String p_base, int p_depth) {
+
+ p_base = p_base + "|";
+ if (grid_radius[p_depth] == 0) {
+
+ if (p_depth == 2) {
+ _new_group(p_base);
+ } else {
+ add_groups(p_cell, p_base, p_depth + 1);
+ };
+ };
+
+ int start = p_cell[p_depth] - grid_radius[p_depth];
+ int end = p_cell[p_depth] + grid_radius[p_depth];
+
+ for (int i = start; i <= end; i++) {
+
+ String gname = p_base + itos(i);
+ if (p_depth == 2) {
+ _new_group(gname);
+ } else {
+ add_groups(p_cell, gname, p_depth + 1);
+ };
+ };
+};
+
+void ProximityGroup3D::_new_group(StringName p_name) {
+
+ const Map<StringName, uint32_t>::Element *E = groups.find(p_name);
+ if (!E) {
+ add_to_group(p_name);
+ };
+
+ groups[p_name] = group_version;
+};
+
+void ProximityGroup3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_EXIT_TREE:
+ ++group_version;
+ clear_groups();
+ break;
+ case NOTIFICATION_TRANSFORM_CHANGED:
+ update_groups();
+ break;
+ };
+};
+
+void ProximityGroup3D::broadcast(String p_name, Variant p_params) {
+
+ Map<StringName, uint32_t>::Element *E;
+ E = groups.front();
+ while (E) {
+
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params);
+ E = E->next();
+ };
+};
+
+void ProximityGroup3D::_proximity_group_broadcast(String p_name, Variant p_params) {
+
+ if (dispatch_mode == MODE_PROXY) {
+
+ get_parent()->call(p_name, p_params);
+ } else {
+
+ emit_signal("broadcast", p_name, p_params);
+ };
+};
+
+void ProximityGroup3D::set_group_name(const String &p_group_name) {
+
+ group_name = p_group_name;
+};
+
+String ProximityGroup3D::get_group_name() const {
+
+ return group_name;
+};
+
+void ProximityGroup3D::set_dispatch_mode(DispatchMode p_mode) {
+
+ dispatch_mode = p_mode;
+};
+
+ProximityGroup3D::DispatchMode ProximityGroup3D::get_dispatch_mode() const {
+
+ return dispatch_mode;
+};
+
+void ProximityGroup3D::set_grid_radius(const Vector3 &p_radius) {
+
+ grid_radius = p_radius;
+};
+
+Vector3 ProximityGroup3D::get_grid_radius() const {
+
+ return grid_radius;
+};
+
+void ProximityGroup3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup3D::set_group_name);
+ ClassDB::bind_method(D_METHOD("get_group_name"), &ProximityGroup3D::get_group_name);
+ ClassDB::bind_method(D_METHOD("set_dispatch_mode", "mode"), &ProximityGroup3D::set_dispatch_mode);
+ ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup3D::get_dispatch_mode);
+ ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup3D::set_grid_radius);
+ ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup3D::get_grid_radius);
+ ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup3D::broadcast);
+ ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup3D::_proximity_group_broadcast);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius");
+
+ ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters")));
+
+ BIND_ENUM_CONSTANT(MODE_PROXY);
+ BIND_ENUM_CONSTANT(MODE_SIGNAL);
+};
+
+ProximityGroup3D::ProximityGroup3D() {
+
+ group_version = 0;
+ dispatch_mode = MODE_PROXY;
+
+ cell_size = 1.0;
+ grid_radius = Vector3(1, 1, 1);
+ set_notify_transform(true);
+};
+
+ProximityGroup3D::~ProximityGroup3D(){
+
+};
diff --git a/scene/3d/proximity_group_3d.h b/scene/3d/proximity_group_3d.h
new file mode 100644
index 0000000000..751bfbdb52
--- /dev/null
+++ b/scene/3d/proximity_group_3d.h
@@ -0,0 +1,87 @@
+/*************************************************************************/
+/* proximity_group_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PROXIMITY_GROUP_H
+#define PROXIMITY_GROUP_H
+
+#include "node_3d.h"
+
+class ProximityGroup3D : public Node3D {
+
+ GDCLASS(ProximityGroup3D, Node3D);
+ OBJ_CATEGORY("3D");
+
+public:
+ enum DispatchMode {
+ MODE_PROXY,
+ MODE_SIGNAL,
+ };
+
+public:
+ void clear_groups();
+ void update_groups();
+
+ void _notification(int p_what);
+
+ DispatchMode dispatch_mode;
+
+ Map<StringName, uint32_t> groups;
+ String group_name;
+
+ float cell_size;
+ Vector3 grid_radius;
+ uint32_t group_version;
+
+ void add_groups(int *p_cell, String p_base, int p_depth);
+ void _new_group(StringName p_name);
+
+ void _proximity_group_broadcast(String p_name, Variant p_params);
+
+ static void _bind_methods();
+
+public:
+ void set_group_name(const String &p_group_name);
+ String get_group_name() const;
+
+ void set_dispatch_mode(DispatchMode p_mode);
+ DispatchMode get_dispatch_mode() const;
+
+ void set_grid_radius(const Vector3 &p_radius);
+ Vector3 get_grid_radius() const;
+
+ void broadcast(String p_name, Variant p_params);
+
+ ProximityGroup3D();
+ ~ProximityGroup3D();
+};
+
+VARIANT_ENUM_CAST(ProximityGroup3D::DispatchMode);
+
+#endif
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
deleted file mode 100644
index be1426f13c..0000000000
--- a/scene/3d/ray_cast.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-/*************************************************************************/
-/* ray_cast.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "ray_cast.h"
-
-#include "collision_object.h"
-#include "core/engine.h"
-#include "mesh_instance.h"
-#include "servers/physics_server.h"
-
-void RayCast::set_cast_to(const Vector3 &p_point) {
-
- cast_to = 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_debug_shape();
-}
-
-Vector3 RayCast::get_cast_to() const {
-
- return cast_to;
-}
-
-void RayCast::set_collision_mask(uint32_t p_mask) {
-
- collision_mask = p_mask;
-}
-
-uint32_t RayCast::get_collision_mask() const {
-
- return collision_mask;
-}
-
-void RayCast::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 RayCast::get_collision_mask_bit(int p_bit) const {
-
- return get_collision_mask() & (1 << p_bit);
-}
-
-bool RayCast::is_colliding() const {
-
- return collided;
-}
-Object *RayCast::get_collider() const {
-
- if (against.is_null())
- return NULL;
-
- return ObjectDB::get_instance(against);
-}
-
-int RayCast::get_collider_shape() const {
-
- return against_shape;
-}
-Vector3 RayCast::get_collision_point() const {
-
- return collision_point;
-}
-Vector3 RayCast::get_collision_normal() const {
-
- return collision_normal;
-}
-
-void RayCast::set_enabled(bool p_enabled) {
-
- enabled = p_enabled;
- update_gizmo();
-
- if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint())
- set_physics_process_internal(p_enabled);
- if (!p_enabled)
- collided = false;
-
- if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
- if (p_enabled)
- _update_debug_shape();
- else
- _clear_debug_shape();
- }
-}
-
-bool RayCast::is_enabled() const {
-
- return enabled;
-}
-
-void RayCast::set_exclude_parent_body(bool p_exclude_parent_body) {
-
- if (exclude_parent_body == p_exclude_parent_body)
- return;
-
- exclude_parent_body = p_exclude_parent_body;
-
- if (!is_inside_tree())
- return;
-
- if (Object::cast_to<CollisionObject>(get_parent())) {
- if (exclude_parent_body)
- exclude.insert(Object::cast_to<CollisionObject>(get_parent())->get_rid());
- else
- exclude.erase(Object::cast_to<CollisionObject>(get_parent())->get_rid());
- }
-}
-
-bool RayCast::get_exclude_parent_body() const {
-
- return exclude_parent_body;
-}
-
-void RayCast::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- if (enabled && !Engine::get_singleton()->is_editor_hint()) {
- set_physics_process_internal(true);
-
- if (get_tree()->is_debugging_collisions_hint())
- _update_debug_shape();
- } else
- set_physics_process_internal(false);
-
- if (Object::cast_to<CollisionObject>(get_parent())) {
- if (exclude_parent_body)
- exclude.insert(Object::cast_to<CollisionObject>(get_parent())->get_rid());
- else
- exclude.erase(Object::cast_to<CollisionObject>(get_parent())->get_rid());
- }
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- if (enabled) {
- set_physics_process_internal(false);
- }
-
- if (debug_shape)
- _clear_debug_shape();
-
- } break;
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
-
- if (!enabled)
- break;
-
- 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));
- }
- }
-
- } break;
- }
-}
-
-void RayCast::_update_raycast_state() {
- Ref<World> w3d = get_world();
- ERR_FAIL_COND(w3d.is_null());
-
- PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(w3d->get_space());
- ERR_FAIL_COND(!dss);
-
- Transform gt = get_global_transform();
-
- Vector3 to = cast_to;
- if (to == Vector3())
- to = Vector3(0, 0.01, 0);
-
- PhysicsDirectSpaceState::RayResult rr;
-
- 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;
- collision_point = rr.position;
- collision_normal = rr.normal;
- against_shape = rr.shape;
- } else {
- collided = false;
- against = ObjectID();
- against_shape = 0;
- }
-}
-
-void RayCast::force_raycast_update() {
- _update_raycast_state();
-}
-
-void RayCast::add_exception_rid(const RID &p_rid) {
-
- exclude.insert(p_rid);
-}
-
-void RayCast::add_exception(const Object *p_object) {
-
- ERR_FAIL_NULL(p_object);
- const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
- if (!co)
- return;
- add_exception_rid(co->get_rid());
-}
-
-void RayCast::remove_exception_rid(const RID &p_rid) {
-
- exclude.erase(p_rid);
-}
-
-void RayCast::remove_exception(const Object *p_object) {
-
- ERR_FAIL_NULL(p_object);
- const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
- if (!co)
- return;
- remove_exception_rid(co->get_rid());
-}
-
-void RayCast::clear_exceptions() {
-
- exclude.clear();
-}
-
-void RayCast::set_collide_with_areas(bool p_clip) {
-
- collide_with_areas = p_clip;
-}
-
-bool RayCast::is_collide_with_areas_enabled() const {
-
- return collide_with_areas;
-}
-
-void RayCast::set_collide_with_bodies(bool p_clip) {
-
- collide_with_bodies = p_clip;
-}
-
-bool RayCast::is_collide_with_bodies_enabled() const {
-
- return collide_with_bodies;
-}
-
-void RayCast::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast::set_enabled);
- ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast::is_enabled);
-
- ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast::set_cast_to);
- ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast::get_cast_to);
-
- ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast::is_colliding);
- ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast::force_raycast_update);
-
- ClassDB::bind_method(D_METHOD("get_collider"), &RayCast::get_collider);
- ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast::get_collider_shape);
- ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast::get_collision_point);
- ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast::get_collision_normal);
-
- ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &RayCast::add_exception_rid);
- ClassDB::bind_method(D_METHOD("add_exception", "node"), &RayCast::add_exception);
-
- ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &RayCast::remove_exception_rid);
- ClassDB::bind_method(D_METHOD("remove_exception", "node"), &RayCast::remove_exception);
-
- ClassDB::bind_method(D_METHOD("clear_exceptions"), &RayCast::clear_exceptions);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast::set_exclude_parent_body);
- ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast::get_exclude_parent_body);
-
- ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast::set_collide_with_areas);
- ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast::is_collide_with_areas_enabled);
-
- ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast::set_collide_with_bodies);
- ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast::is_collide_with_bodies_enabled);
-
- 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, "cast_to"), "set_cast_to", "get_cast_to");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
-
- 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");
-}
-
-void RayCast::_create_debug_shape() {
-
- if (!debug_material.is_valid()) {
- debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
-
- 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));
- }
-
- Ref<ArrayMesh> mesh = memnew(ArrayMesh);
-
- MeshInstance *mi = memnew(MeshInstance);
- mi->set_mesh(mesh);
-
- add_child(mi);
- debug_shape = mi;
-}
-
-void RayCast::_update_debug_shape() {
-
- if (!enabled)
- return;
-
- if (!debug_shape)
- _create_debug_shape();
-
- MeshInstance *mi = static_cast<MeshInstance *>(debug_shape);
- if (!mi->get_mesh().is_valid())
- return;
-
- Ref<ArrayMesh> mesh = mi->get_mesh();
- mesh->clear_surfaces();
-
- Array a;
- a.resize(Mesh::ARRAY_MAX);
-
- Vector<Vector3> verts;
- verts.push_back(Vector3());
- verts.push_back(cast_to);
- a[Mesh::ARRAY_VERTEX] = verts;
-
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
- mesh->surface_set_material(0, debug_material);
-}
-
-void RayCast::_clear_debug_shape() {
-
- if (!debug_shape)
- return;
-
- MeshInstance *mi = static_cast<MeshInstance *>(debug_shape);
- if (mi->is_inside_tree())
- mi->queue_delete();
- else
- memdelete(mi);
-
- debug_shape = NULL;
-}
-
-RayCast::RayCast() {
-
- enabled = false;
-
- collided = false;
- against_shape = 0;
- collision_mask = 1;
- cast_to = Vector3(0, -1, 0);
- debug_shape = NULL;
- exclude_parent_body = true;
- collide_with_areas = false;
- collide_with_bodies = true;
-}
diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h
deleted file mode 100644
index 5cebfe3ac2..0000000000
--- a/scene/3d/ray_cast.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*************************************************************************/
-/* ray_cast.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RAY_CAST_H
-#define RAY_CAST_H
-
-#include "scene/3d/spatial.h"
-
-class RayCast : public Spatial {
-
- GDCLASS(RayCast, Spatial);
-
- bool enabled;
- bool collided;
- ObjectID against;
- int against_shape;
- Vector3 collision_point;
- Vector3 collision_normal;
-
- Vector3 cast_to;
- Set<RID> exclude;
-
- uint32_t collision_mask;
- bool exclude_parent_body;
-
- Node *debug_shape;
- Ref<Material> debug_material;
-
- void _create_debug_shape();
- void _update_debug_shape();
- void _clear_debug_shape();
-
- bool collide_with_areas;
- bool collide_with_bodies;
-
-protected:
- void _notification(int p_what);
- void _update_raycast_state();
- static void _bind_methods();
-
-public:
- void set_collide_with_areas(bool p_clip);
- bool is_collide_with_areas_enabled() const;
-
- void set_collide_with_bodies(bool p_clip);
- bool is_collide_with_bodies_enabled() const;
-
- void set_enabled(bool p_enabled);
- bool is_enabled() const;
-
- void set_cast_to(const Vector3 &p_point);
- Vector3 get_cast_to() 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_exclude_parent_body(bool p_exclude_parent_body);
- bool get_exclude_parent_body() const;
-
- void force_raycast_update();
- bool is_colliding() const;
- Object *get_collider() const;
- int get_collider_shape() const;
- Vector3 get_collision_point() const;
- Vector3 get_collision_normal() const;
-
- void add_exception_rid(const RID &p_rid);
- void add_exception(const Object *p_object);
- void remove_exception_rid(const RID &p_rid);
- void remove_exception(const Object *p_object);
- void clear_exceptions();
-
- RayCast();
-};
-
-#endif // RAY_CAST_H
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
new file mode 100644
index 0000000000..a18da61656
--- /dev/null
+++ b/scene/3d/ray_cast_3d.cpp
@@ -0,0 +1,405 @@
+/*************************************************************************/
+/* ray_cast_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "ray_cast_3d.h"
+
+#include "collision_object_3d.h"
+#include "core/engine.h"
+#include "mesh_instance_3d.h"
+#include "servers/physics_server_3d.h"
+
+void RayCast3D::set_cast_to(const Vector3 &p_point) {
+
+ cast_to = 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_debug_shape();
+}
+
+Vector3 RayCast3D::get_cast_to() const {
+
+ return cast_to;
+}
+
+void RayCast3D::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask = p_mask;
+}
+
+uint32_t RayCast3D::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void RayCast3D::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 RayCast3D::get_collision_mask_bit(int p_bit) const {
+
+ return get_collision_mask() & (1 << p_bit);
+}
+
+bool RayCast3D::is_colliding() const {
+
+ return collided;
+}
+Object *RayCast3D::get_collider() const {
+
+ if (against.is_null())
+ return nullptr;
+
+ return ObjectDB::get_instance(against);
+}
+
+int RayCast3D::get_collider_shape() const {
+
+ return against_shape;
+}
+Vector3 RayCast3D::get_collision_point() const {
+
+ return collision_point;
+}
+Vector3 RayCast3D::get_collision_normal() const {
+
+ return collision_normal;
+}
+
+void RayCast3D::set_enabled(bool p_enabled) {
+
+ enabled = p_enabled;
+ update_gizmo();
+
+ if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint())
+ set_physics_process_internal(p_enabled);
+ if (!p_enabled)
+ collided = false;
+
+ if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) {
+ if (p_enabled)
+ _update_debug_shape();
+ else
+ _clear_debug_shape();
+ }
+}
+
+bool RayCast3D::is_enabled() const {
+
+ return enabled;
+}
+
+void RayCast3D::set_exclude_parent_body(bool p_exclude_parent_body) {
+
+ if (exclude_parent_body == p_exclude_parent_body)
+ return;
+
+ exclude_parent_body = p_exclude_parent_body;
+
+ if (!is_inside_tree())
+ return;
+
+ if (Object::cast_to<CollisionObject3D>(get_parent())) {
+ if (exclude_parent_body)
+ exclude.insert(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ else
+ exclude.erase(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ }
+}
+
+bool RayCast3D::get_exclude_parent_body() const {
+
+ return exclude_parent_body;
+}
+
+void RayCast3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (enabled && !Engine::get_singleton()->is_editor_hint()) {
+ set_physics_process_internal(true);
+
+ if (get_tree()->is_debugging_collisions_hint())
+ _update_debug_shape();
+ } else
+ set_physics_process_internal(false);
+
+ if (Object::cast_to<CollisionObject3D>(get_parent())) {
+ if (exclude_parent_body)
+ exclude.insert(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ else
+ exclude.erase(Object::cast_to<CollisionObject3D>(get_parent())->get_rid());
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+
+ if (enabled) {
+ set_physics_process_internal(false);
+ }
+
+ if (debug_shape)
+ _clear_debug_shape();
+
+ } break;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+
+ if (!enabled)
+ break;
+
+ 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));
+ }
+ }
+
+ } break;
+ }
+}
+
+void RayCast3D::_update_raycast_state() {
+ Ref<World3D> w3d = get_world();
+ ERR_FAIL_COND(w3d.is_null());
+
+ PhysicsDirectSpaceState3D *dss = PhysicsServer3D::get_singleton()->space_get_direct_state(w3d->get_space());
+ ERR_FAIL_COND(!dss);
+
+ Transform gt = get_global_transform();
+
+ Vector3 to = cast_to;
+ if (to == Vector3())
+ to = Vector3(0, 0.01, 0);
+
+ PhysicsDirectSpaceState3D::RayResult rr;
+
+ 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;
+ collision_point = rr.position;
+ collision_normal = rr.normal;
+ against_shape = rr.shape;
+ } else {
+ collided = false;
+ against = ObjectID();
+ against_shape = 0;
+ }
+}
+
+void RayCast3D::force_raycast_update() {
+ _update_raycast_state();
+}
+
+void RayCast3D::add_exception_rid(const RID &p_rid) {
+
+ exclude.insert(p_rid);
+}
+
+void RayCast3D::add_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
+ if (!co)
+ return;
+ add_exception_rid(co->get_rid());
+}
+
+void RayCast3D::remove_exception_rid(const RID &p_rid) {
+
+ exclude.erase(p_rid);
+}
+
+void RayCast3D::remove_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
+ if (!co)
+ return;
+ remove_exception_rid(co->get_rid());
+}
+
+void RayCast3D::clear_exceptions() {
+
+ exclude.clear();
+}
+
+void RayCast3D::set_collide_with_areas(bool p_clip) {
+
+ collide_with_areas = p_clip;
+}
+
+bool RayCast3D::is_collide_with_areas_enabled() const {
+
+ return collide_with_areas;
+}
+
+void RayCast3D::set_collide_with_bodies(bool p_clip) {
+
+ collide_with_bodies = p_clip;
+}
+
+bool RayCast3D::is_collide_with_bodies_enabled() const {
+
+ return collide_with_bodies;
+}
+
+void RayCast3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast3D::set_enabled);
+ ClassDB::bind_method(D_METHOD("is_enabled"), &RayCast3D::is_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_cast_to", "local_point"), &RayCast3D::set_cast_to);
+ ClassDB::bind_method(D_METHOD("get_cast_to"), &RayCast3D::get_cast_to);
+
+ ClassDB::bind_method(D_METHOD("is_colliding"), &RayCast3D::is_colliding);
+ ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update);
+
+ ClassDB::bind_method(D_METHOD("get_collider"), &RayCast3D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast3D::get_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast3D::get_collision_point);
+ ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast3D::get_collision_normal);
+
+ ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &RayCast3D::add_exception_rid);
+ ClassDB::bind_method(D_METHOD("add_exception", "node"), &RayCast3D::add_exception);
+
+ ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &RayCast3D::remove_exception_rid);
+ ClassDB::bind_method(D_METHOD("remove_exception", "node"), &RayCast3D::remove_exception);
+
+ ClassDB::bind_method(D_METHOD("clear_exceptions"), &RayCast3D::clear_exceptions);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast3D::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast3D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast3D::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast3D::set_exclude_parent_body);
+ ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast3D::get_exclude_parent_body);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast3D::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast3D::is_collide_with_areas_enabled);
+
+ 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);
+
+ 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, "cast_to"), "set_cast_to", "get_cast_to");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ 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");
+}
+
+void RayCast3D::_create_debug_shape() {
+
+ if (!debug_material.is_valid()) {
+ debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+
+ 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));
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+
+ MeshInstance3D *mi = memnew(MeshInstance3D);
+ mi->set_mesh(mesh);
+
+ add_child(mi);
+ debug_shape = mi;
+}
+
+void RayCast3D::_update_debug_shape() {
+
+ if (!enabled)
+ return;
+
+ if (!debug_shape)
+ _create_debug_shape();
+
+ MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
+ if (!mi->get_mesh().is_valid())
+ return;
+
+ Ref<ArrayMesh> mesh = mi->get_mesh();
+ mesh->clear_surfaces();
+
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+
+ Vector<Vector3> verts;
+ verts.push_back(Vector3());
+ verts.push_back(cast_to);
+ a[Mesh::ARRAY_VERTEX] = verts;
+
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a);
+ mesh->surface_set_material(0, debug_material);
+}
+
+void RayCast3D::_clear_debug_shape() {
+
+ if (!debug_shape)
+ return;
+
+ MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
+ if (mi->is_inside_tree())
+ mi->queue_delete();
+ else
+ memdelete(mi);
+
+ debug_shape = nullptr;
+}
+
+RayCast3D::RayCast3D() {
+
+ enabled = false;
+
+ collided = false;
+ against_shape = 0;
+ collision_mask = 1;
+ cast_to = Vector3(0, -1, 0);
+ debug_shape = nullptr;
+ exclude_parent_body = true;
+ collide_with_areas = false;
+ collide_with_bodies = true;
+}
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
new file mode 100644
index 0000000000..f8bfb7846a
--- /dev/null
+++ b/scene/3d/ray_cast_3d.h
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* ray_cast_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RAY_CAST_3D_H
+#define RAY_CAST_3D_H
+
+#include "scene/3d/node_3d.h"
+
+class RayCast3D : public Node3D {
+
+ GDCLASS(RayCast3D, Node3D);
+
+ bool enabled;
+ bool collided;
+ ObjectID against;
+ int against_shape;
+ Vector3 collision_point;
+ Vector3 collision_normal;
+
+ Vector3 cast_to;
+ Set<RID> exclude;
+
+ uint32_t collision_mask;
+ bool exclude_parent_body;
+
+ Node *debug_shape;
+ Ref<Material> debug_material;
+
+ void _create_debug_shape();
+ void _update_debug_shape();
+ void _clear_debug_shape();
+
+ bool collide_with_areas;
+ bool collide_with_bodies;
+
+protected:
+ void _notification(int p_what);
+ void _update_raycast_state();
+ static void _bind_methods();
+
+public:
+ void set_collide_with_areas(bool p_clip);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_collide_with_bodies(bool p_clip);
+ bool is_collide_with_bodies_enabled() const;
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_cast_to(const Vector3 &p_point);
+ Vector3 get_cast_to() 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_exclude_parent_body(bool p_exclude_parent_body);
+ bool get_exclude_parent_body() const;
+
+ void force_raycast_update();
+ bool is_colliding() const;
+ Object *get_collider() const;
+ int get_collider_shape() const;
+ Vector3 get_collision_point() const;
+ Vector3 get_collision_normal() const;
+
+ void add_exception_rid(const RID &p_rid);
+ void add_exception(const Object *p_object);
+ void remove_exception_rid(const RID &p_rid);
+ void remove_exception(const Object *p_object);
+ void clear_exceptions();
+
+ RayCast3D();
+};
+
+#endif // RAY_CAST_H
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 3cf8e43ec2..24bf8b43d1 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -33,7 +33,7 @@
void ReflectionProbe::set_intensity(float p_intensity) {
intensity = p_intensity;
- VS::get_singleton()->reflection_probe_set_intensity(probe, p_intensity);
+ RS::get_singleton()->reflection_probe_set_intensity(probe, p_intensity);
}
float ReflectionProbe::get_intensity() const {
@@ -44,12 +44,12 @@ float ReflectionProbe::get_intensity() const {
void ReflectionProbe::set_interior_ambient(Color p_ambient) {
interior_ambient = p_ambient;
- VS::get_singleton()->reflection_probe_set_interior_ambient(probe, p_ambient);
+ RS::get_singleton()->reflection_probe_set_interior_ambient(probe, p_ambient);
}
void ReflectionProbe::set_interior_ambient_energy(float p_energy) {
interior_ambient_energy = p_energy;
- VS::get_singleton()->reflection_probe_set_interior_ambient_energy(probe, p_energy);
+ RS::get_singleton()->reflection_probe_set_interior_ambient_energy(probe, p_energy);
}
float ReflectionProbe::get_interior_ambient_energy() const {
@@ -64,7 +64,7 @@ Color ReflectionProbe::get_interior_ambient() const {
void ReflectionProbe::set_interior_ambient_probe_contribution(float p_contribution) {
interior_ambient_probe_contribution = p_contribution;
- VS::get_singleton()->reflection_probe_set_interior_ambient_probe_contribution(probe, p_contribution);
+ RS::get_singleton()->reflection_probe_set_interior_ambient_probe_contribution(probe, p_contribution);
}
float ReflectionProbe::get_interior_ambient_probe_contribution() const {
@@ -75,7 +75,7 @@ float ReflectionProbe::get_interior_ambient_probe_contribution() const {
void ReflectionProbe::set_max_distance(float p_distance) {
max_distance = p_distance;
- VS::get_singleton()->reflection_probe_set_max_distance(probe, p_distance);
+ RS::get_singleton()->reflection_probe_set_max_distance(probe, p_distance);
}
float ReflectionProbe::get_max_distance() const {
@@ -97,8 +97,8 @@ void ReflectionProbe::set_extents(const Vector3 &p_extents) {
}
}
- VS::get_singleton()->reflection_probe_set_extents(probe, extents);
- VS::get_singleton()->reflection_probe_set_origin_offset(probe, 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();
}
@@ -117,8 +117,8 @@ void ReflectionProbe::set_origin_offset(const Vector3 &p_extents) {
origin_offset[i] = SGN(origin_offset[i]) * (extents[i] - 0.01);
}
}
- VS::get_singleton()->reflection_probe_set_extents(probe, extents);
- VS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
+ 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();
@@ -131,7 +131,7 @@ Vector3 ReflectionProbe::get_origin_offset() const {
void ReflectionProbe::set_enable_box_projection(bool p_enable) {
box_projection = p_enable;
- VS::get_singleton()->reflection_probe_set_enable_box_projection(probe, p_enable);
+ RS::get_singleton()->reflection_probe_set_enable_box_projection(probe, p_enable);
}
bool ReflectionProbe::is_box_projection_enabled() const {
@@ -141,7 +141,7 @@ bool ReflectionProbe::is_box_projection_enabled() const {
void ReflectionProbe::set_as_interior(bool p_enable) {
interior = p_enable;
- VS::get_singleton()->reflection_probe_set_as_interior(probe, interior);
+ RS::get_singleton()->reflection_probe_set_as_interior(probe, interior);
_change_notify();
}
@@ -153,7 +153,7 @@ bool ReflectionProbe::is_set_as_interior() const {
void ReflectionProbe::set_enable_shadows(bool p_enable) {
enable_shadows = p_enable;
- VS::get_singleton()->reflection_probe_set_enable_shadows(probe, p_enable);
+ RS::get_singleton()->reflection_probe_set_enable_shadows(probe, p_enable);
}
bool ReflectionProbe::are_shadows_enabled() const {
@@ -163,7 +163,7 @@ bool ReflectionProbe::are_shadows_enabled() const {
void ReflectionProbe::set_cull_mask(uint32_t p_layers) {
cull_mask = p_layers;
- VS::get_singleton()->reflection_probe_set_cull_mask(probe, p_layers);
+ RS::get_singleton()->reflection_probe_set_cull_mask(probe, p_layers);
}
uint32_t ReflectionProbe::get_cull_mask() const {
@@ -172,7 +172,7 @@ uint32_t ReflectionProbe::get_cull_mask() const {
void ReflectionProbe::set_update_mode(UpdateMode p_mode) {
update_mode = p_mode;
- VS::get_singleton()->reflection_probe_set_update_mode(probe, VS::ReflectionProbeUpdateMode(p_mode));
+ RS::get_singleton()->reflection_probe_set_update_mode(probe, RS::ReflectionProbeUpdateMode(p_mode));
}
ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const {
@@ -272,12 +272,12 @@ ReflectionProbe::ReflectionProbe() {
cull_mask = (1 << 20) - 1;
update_mode = UPDATE_ONCE;
- probe = VisualServer::get_singleton()->reflection_probe_create();
- VS::get_singleton()->instance_set_base(get_instance(), probe);
+ probe = RenderingServer::get_singleton()->reflection_probe_create();
+ RS::get_singleton()->instance_set_base(get_instance(), probe);
set_disable_scale(true);
}
ReflectionProbe::~ReflectionProbe() {
- VS::get_singleton()->free(probe);
+ RS::get_singleton()->free(probe);
}
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 57c1b0a320..3867d13435 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -31,13 +31,13 @@
#ifndef REFLECTIONPROBE_H
#define REFLECTIONPROBE_H
-#include "scene/3d/visual_instance.h"
+#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/sky.h"
#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
-class ReflectionProbe : public VisualInstance {
- GDCLASS(ReflectionProbe, VisualInstance);
+class ReflectionProbe : public VisualInstance3D {
+ GDCLASS(ReflectionProbe, VisualInstance3D);
public:
enum UpdateMode {
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
deleted file mode 100644
index 9ef43647ba..0000000000
--- a/scene/3d/remote_transform.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/*************************************************************************/
-/* remote_transform.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "remote_transform.h"
-
-void RemoteTransform::_update_cache() {
- cache = ObjectID();
- if (has_node(remote_node)) {
- Node *node = get_node(remote_node);
- if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
- return;
- }
-
- cache = node->get_instance_id();
- }
-}
-
-void RemoteTransform::_update_remote() {
-
- if (!is_inside_tree())
- return;
-
- if (cache.is_null())
- return;
-
- Spatial *n = Object::cast_to<Spatial>(ObjectDB::get_instance(cache));
- if (!n)
- return;
-
- if (!n->is_inside_tree())
- return;
-
- //todo make faster
- if (use_global_coordinates) {
-
- if (update_remote_position && update_remote_rotation && update_remote_scale) {
- n->set_global_transform(get_global_transform());
- } else {
- Transform our_trans = get_global_transform();
-
- if (update_remote_rotation)
- n->set_rotation(our_trans.basis.get_rotation());
-
- if (update_remote_scale)
- n->set_scale(our_trans.basis.get_scale());
-
- if (update_remote_position) {
- Transform n_trans = n->get_global_transform();
-
- n_trans.set_origin(our_trans.get_origin());
- n->set_global_transform(n_trans);
- }
- }
-
- } else {
- if (update_remote_position && update_remote_rotation && update_remote_scale) {
- n->set_transform(get_transform());
- } else {
- Transform our_trans = get_transform();
-
- if (update_remote_rotation)
- n->set_rotation(our_trans.basis.get_rotation());
-
- if (update_remote_scale)
- n->set_scale(our_trans.basis.get_scale());
-
- if (update_remote_position) {
- Transform n_trans = n->get_transform();
-
- n_trans.set_origin(our_trans.get_origin());
- n->set_transform(n_trans);
- }
- }
- }
-}
-
-void RemoteTransform::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- _update_cache();
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
- if (!is_inside_tree())
- break;
-
- if (cache.is_valid()) {
-
- _update_remote();
- }
-
- } break;
- }
-}
-
-void RemoteTransform::set_remote_node(const NodePath &p_remote_node) {
-
- remote_node = p_remote_node;
- if (is_inside_tree()) {
- _update_cache();
- _update_remote();
- }
-
- update_configuration_warning();
-}
-
-NodePath RemoteTransform::get_remote_node() const {
-
- return remote_node;
-}
-
-void RemoteTransform::set_use_global_coordinates(const bool p_enable) {
- use_global_coordinates = p_enable;
-}
-
-bool RemoteTransform::get_use_global_coordinates() const {
- return use_global_coordinates;
-}
-
-void RemoteTransform::set_update_position(const bool p_update) {
- update_remote_position = p_update;
- _update_remote();
-}
-
-bool RemoteTransform::get_update_position() const {
- return update_remote_position;
-}
-
-void RemoteTransform::set_update_rotation(const bool p_update) {
- update_remote_rotation = p_update;
- _update_remote();
-}
-
-bool RemoteTransform::get_update_rotation() const {
- return update_remote_rotation;
-}
-
-void RemoteTransform::set_update_scale(const bool p_update) {
- update_remote_scale = p_update;
- _update_remote();
-}
-
-bool RemoteTransform::get_update_scale() const {
- return update_remote_scale;
-}
-
-void RemoteTransform::force_update_cache() {
- _update_cache();
-}
-
-String RemoteTransform::get_configuration_warning() const {
-
- if (!has_node(remote_node) || !Object::cast_to<Spatial>(get_node(remote_node))) {
- return TTR("The \"Remote Path\" property must point to a valid Spatial or Spatial-derived node to work.");
- }
-
- return String();
-}
-
-void RemoteTransform::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_remote_node", "path"), &RemoteTransform::set_remote_node);
- ClassDB::bind_method(D_METHOD("get_remote_node"), &RemoteTransform::get_remote_node);
- ClassDB::bind_method(D_METHOD("force_update_cache"), &RemoteTransform::force_update_cache);
-
- ClassDB::bind_method(D_METHOD("set_use_global_coordinates", "use_global_coordinates"), &RemoteTransform::set_use_global_coordinates);
- ClassDB::bind_method(D_METHOD("get_use_global_coordinates"), &RemoteTransform::get_use_global_coordinates);
-
- ClassDB::bind_method(D_METHOD("set_update_position", "update_remote_position"), &RemoteTransform::set_update_position);
- ClassDB::bind_method(D_METHOD("get_update_position"), &RemoteTransform::get_update_position);
- ClassDB::bind_method(D_METHOD("set_update_rotation", "update_remote_rotation"), &RemoteTransform::set_update_rotation);
- ClassDB::bind_method(D_METHOD("get_update_rotation"), &RemoteTransform::get_update_rotation);
- ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale);
- ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");
-
- ADD_GROUP("Update", "update_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_position"), "set_update_position", "get_update_position");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_rotation"), "set_update_rotation", "get_update_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_scale"), "set_update_scale", "get_update_scale");
-}
-
-RemoteTransform::RemoteTransform() {
-
- use_global_coordinates = true;
- update_remote_position = true;
- update_remote_rotation = true;
- update_remote_scale = true;
-
- set_notify_transform(true);
-}
diff --git a/scene/3d/remote_transform.h b/scene/3d/remote_transform.h
deleted file mode 100644
index 02e448832f..0000000000
--- a/scene/3d/remote_transform.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* remote_transform.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 REMOTETRANSFORM_H
-#define REMOTETRANSFORM_H
-
-#include "scene/3d/spatial.h"
-
-class RemoteTransform : public Spatial {
- GDCLASS(RemoteTransform, Spatial);
-
- NodePath remote_node;
-
- ObjectID cache;
-
- bool use_global_coordinates;
- bool update_remote_position;
- bool update_remote_rotation;
- bool update_remote_scale;
-
- void _update_remote();
- void _update_cache();
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
- void set_remote_node(const NodePath &p_remote_node);
- NodePath get_remote_node() const;
-
- void set_use_global_coordinates(const bool p_enable);
- bool get_use_global_coordinates() const;
-
- void set_update_position(const bool p_update);
- bool get_update_position() const;
-
- void set_update_rotation(const bool p_update);
- bool get_update_rotation() const;
-
- void set_update_scale(const bool p_update);
- bool get_update_scale() const;
-
- void force_update_cache();
-
- virtual String get_configuration_warning() const;
-
- RemoteTransform();
-};
-
-#endif // REMOTETRANSFORM_H
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
new file mode 100644
index 0000000000..38792bbb58
--- /dev/null
+++ b/scene/3d/remote_transform_3d.cpp
@@ -0,0 +1,223 @@
+/*************************************************************************/
+/* remote_transform_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "remote_transform_3d.h"
+
+void RemoteTransform3D::_update_cache() {
+ cache = ObjectID();
+ if (has_node(remote_node)) {
+ Node *node = get_node(remote_node);
+ if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
+ return;
+ }
+
+ cache = node->get_instance_id();
+ }
+}
+
+void RemoteTransform3D::_update_remote() {
+
+ if (!is_inside_tree())
+ return;
+
+ if (cache.is_null())
+ return;
+
+ Node3D *n = Object::cast_to<Node3D>(ObjectDB::get_instance(cache));
+ if (!n)
+ return;
+
+ if (!n->is_inside_tree())
+ return;
+
+ //todo make faster
+ if (use_global_coordinates) {
+
+ if (update_remote_position && update_remote_rotation && update_remote_scale) {
+ n->set_global_transform(get_global_transform());
+ } else {
+ Transform our_trans = get_global_transform();
+
+ if (update_remote_rotation)
+ n->set_rotation(our_trans.basis.get_rotation());
+
+ if (update_remote_scale)
+ n->set_scale(our_trans.basis.get_scale());
+
+ if (update_remote_position) {
+ Transform n_trans = n->get_global_transform();
+
+ n_trans.set_origin(our_trans.get_origin());
+ n->set_global_transform(n_trans);
+ }
+ }
+
+ } else {
+ if (update_remote_position && update_remote_rotation && update_remote_scale) {
+ n->set_transform(get_transform());
+ } else {
+ Transform our_trans = get_transform();
+
+ if (update_remote_rotation)
+ n->set_rotation(our_trans.basis.get_rotation());
+
+ if (update_remote_scale)
+ n->set_scale(our_trans.basis.get_scale());
+
+ if (update_remote_position) {
+ Transform n_trans = n->get_transform();
+
+ n_trans.set_origin(our_trans.get_origin());
+ n->set_transform(n_trans);
+ }
+ }
+ }
+}
+
+void RemoteTransform3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ _update_cache();
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ if (!is_inside_tree())
+ break;
+
+ if (cache.is_valid()) {
+
+ _update_remote();
+ }
+
+ } break;
+ }
+}
+
+void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) {
+
+ remote_node = p_remote_node;
+ if (is_inside_tree()) {
+ _update_cache();
+ _update_remote();
+ }
+
+ update_configuration_warning();
+}
+
+NodePath RemoteTransform3D::get_remote_node() const {
+
+ return remote_node;
+}
+
+void RemoteTransform3D::set_use_global_coordinates(const bool p_enable) {
+ use_global_coordinates = p_enable;
+}
+
+bool RemoteTransform3D::get_use_global_coordinates() const {
+ return use_global_coordinates;
+}
+
+void RemoteTransform3D::set_update_position(const bool p_update) {
+ update_remote_position = p_update;
+ _update_remote();
+}
+
+bool RemoteTransform3D::get_update_position() const {
+ return update_remote_position;
+}
+
+void RemoteTransform3D::set_update_rotation(const bool p_update) {
+ update_remote_rotation = p_update;
+ _update_remote();
+}
+
+bool RemoteTransform3D::get_update_rotation() const {
+ return update_remote_rotation;
+}
+
+void RemoteTransform3D::set_update_scale(const bool p_update) {
+ update_remote_scale = p_update;
+ _update_remote();
+}
+
+bool RemoteTransform3D::get_update_scale() const {
+ return update_remote_scale;
+}
+
+void RemoteTransform3D::force_update_cache() {
+ _update_cache();
+}
+
+String RemoteTransform3D::get_configuration_warning() const {
+
+ if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
+ return TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
+ }
+
+ return String();
+}
+
+void RemoteTransform3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_remote_node", "path"), &RemoteTransform3D::set_remote_node);
+ ClassDB::bind_method(D_METHOD("get_remote_node"), &RemoteTransform3D::get_remote_node);
+ ClassDB::bind_method(D_METHOD("force_update_cache"), &RemoteTransform3D::force_update_cache);
+
+ ClassDB::bind_method(D_METHOD("set_use_global_coordinates", "use_global_coordinates"), &RemoteTransform3D::set_use_global_coordinates);
+ ClassDB::bind_method(D_METHOD("get_use_global_coordinates"), &RemoteTransform3D::get_use_global_coordinates);
+
+ ClassDB::bind_method(D_METHOD("set_update_position", "update_remote_position"), &RemoteTransform3D::set_update_position);
+ ClassDB::bind_method(D_METHOD("get_update_position"), &RemoteTransform3D::get_update_position);
+ ClassDB::bind_method(D_METHOD("set_update_rotation", "update_remote_rotation"), &RemoteTransform3D::set_update_rotation);
+ ClassDB::bind_method(D_METHOD("get_update_rotation"), &RemoteTransform3D::get_update_rotation);
+ ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform3D::set_update_scale);
+ ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform3D::get_update_scale);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_remote_node", "get_remote_node");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");
+
+ ADD_GROUP("Update", "update_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_position"), "set_update_position", "get_update_position");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_rotation"), "set_update_rotation", "get_update_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_scale"), "set_update_scale", "get_update_scale");
+}
+
+RemoteTransform3D::RemoteTransform3D() {
+
+ use_global_coordinates = true;
+ update_remote_position = true;
+ update_remote_rotation = true;
+ update_remote_scale = true;
+
+ set_notify_transform(true);
+}
diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h
new file mode 100644
index 0000000000..50d7c5a9b2
--- /dev/null
+++ b/scene/3d/remote_transform_3d.h
@@ -0,0 +1,78 @@
+/*************************************************************************/
+/* remote_transform_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 REMOTETRANSFORM_H
+#define REMOTETRANSFORM_H
+
+#include "scene/3d/node_3d.h"
+
+class RemoteTransform3D : public Node3D {
+ GDCLASS(RemoteTransform3D, Node3D);
+
+ NodePath remote_node;
+
+ ObjectID cache;
+
+ bool use_global_coordinates;
+ bool update_remote_position;
+ bool update_remote_rotation;
+ bool update_remote_scale;
+
+ void _update_remote();
+ void _update_cache();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void set_remote_node(const NodePath &p_remote_node);
+ NodePath get_remote_node() const;
+
+ void set_use_global_coordinates(const bool p_enable);
+ bool get_use_global_coordinates() const;
+
+ void set_update_position(const bool p_update);
+ bool get_update_position() const;
+
+ void set_update_rotation(const bool p_update);
+ bool get_update_rotation() const;
+
+ void set_update_scale(const bool p_update);
+ bool get_update_scale() const;
+
+ void force_update_cache();
+
+ virtual String get_configuration_warning() const;
+
+ RemoteTransform3D();
+};
+
+#endif // REMOTETRANSFORM_H
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
deleted file mode 100644
index b2252bcb04..0000000000
--- a/scene/3d/skeleton.cpp
+++ /dev/null
@@ -1,948 +0,0 @@
-/*************************************************************************/
-/* skeleton.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "skeleton.h"
-
-#include "core/engine.h"
-#include "core/message_queue.h"
-#include "core/project_settings.h"
-#include "scene/3d/physics_body.h"
-#include "scene/resources/surface_tool.h"
-
-void SkinReference::_skin_changed() {
- if (skeleton_node) {
- skeleton_node->_make_dirty();
- }
- skeleton_version = 0;
-}
-
-void SkinReference::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed);
- ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton);
- ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin);
-}
-
-RID SkinReference::get_skeleton() const {
- return skeleton;
-}
-
-Ref<Skin> SkinReference::get_skin() const {
- return skin;
-}
-
-SkinReference::~SkinReference() {
- if (skeleton_node) {
- skeleton_node->skin_bindings.erase(this);
- }
-
- VS::get_singleton()->free(skeleton);
-}
-
-bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
-
- String path = p_path;
-
- if (!path.begins_with("bones/"))
- return false;
-
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
-
- if (which == bones.size() && what == "name") {
-
- add_bone(p_value);
- return true;
- }
-
- ERR_FAIL_INDEX_V(which, bones.size(), false);
-
- if (what == "parent")
- set_bone_parent(which, p_value);
- else if (what == "rest")
- set_bone_rest(which, p_value);
- else if (what == "enabled")
- set_bone_enabled(which, p_value);
- else if (what == "pose")
- set_bone_pose(which, p_value);
- else if (what == "bound_children") {
- Array children = p_value;
-
- if (is_inside_tree()) {
- bones.write[which].nodes_bound.clear();
-
- for (int i = 0; i < children.size(); i++) {
-
- NodePath npath = children[i];
- ERR_CONTINUE(npath.operator String() == "");
- Node *node = get_node(npath);
- ERR_CONTINUE(!node);
- bind_child_node_to_bone(which, node);
- }
- }
- } else {
- return false;
- }
-
- return true;
-}
-
-bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const {
-
- String path = p_path;
-
- if (!path.begins_with("bones/"))
- return false;
-
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
-
- ERR_FAIL_INDEX_V(which, bones.size(), false);
-
- if (what == "name")
- r_ret = get_bone_name(which);
- else if (what == "parent")
- r_ret = get_bone_parent(which);
- else if (what == "rest")
- r_ret = get_bone_rest(which);
- else if (what == "enabled")
- r_ret = is_bone_enabled(which);
- else if (what == "pose")
- r_ret = get_bone_pose(which);
- else if (what == "bound_children") {
- Array children;
-
- for (const List<ObjectID>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) {
-
- Object *obj = ObjectDB::get_instance(E->get());
- ERR_CONTINUE(!obj);
- Node *node = Object::cast_to<Node>(obj);
- ERR_CONTINUE(!node);
- NodePath npath = get_path_to(node);
- children.push_back(npath);
- }
-
- r_ret = children;
- } else
- return false;
-
- return true;
-}
-void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
-
- for (int i = 0; i < bones.size(); i++) {
-
- String prep = "bones/" + itos(i) + "/";
- p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
- p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
- p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
- }
-}
-
-void Skeleton::_update_process_order() {
-
- if (!process_order_dirty)
- return;
-
- Bone *bonesptr = bones.ptrw();
- int len = bones.size();
-
- process_order.resize(len);
- int *order = process_order.ptrw();
- for (int i = 0; i < len; i++) {
-
- if (bonesptr[i].parent >= len) {
- //validate this just in case
- ERR_PRINT("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
- bonesptr[i].parent = -1;
- }
- order[i] = i;
- bonesptr[i].sort_index = i;
- }
- //now check process order
- int pass_count = 0;
- while (pass_count < len * len) {
- //using bubblesort because of simplicity, it won't run every frame though.
- //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
- bool swapped = false;
- for (int i = 0; i < len; i++) {
- int parent_idx = bonesptr[order[i]].parent;
- if (parent_idx < 0)
- continue; //do nothing because it has no parent
- //swap indices
- int parent_order = bonesptr[parent_idx].sort_index;
- if (parent_order > i) {
- bonesptr[order[i]].sort_index = parent_order;
- bonesptr[parent_idx].sort_index = i;
- //swap order
- SWAP(order[i], order[parent_order]);
- swapped = true;
- }
- }
-
- if (!swapped)
- break;
- pass_count++;
- }
-
- if (pass_count == len * len) {
- ERR_PRINT("Skeleton parenthood graph is cyclic");
- }
-
- process_order_dirty = false;
-}
-
-void Skeleton::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_UPDATE_SKELETON: {
-
- VisualServer *vs = VisualServer::get_singleton();
- Bone *bonesptr = bones.ptrw();
- int len = bones.size();
-
- _update_process_order();
-
- const int *order = process_order.ptr();
-
- for (int i = 0; i < len; i++) {
-
- Bone &b = bonesptr[order[i]];
-
- if (b.global_pose_override_amount >= 0.999) {
- b.pose_global = b.global_pose_override;
- } else {
- if (b.disable_rest) {
- if (b.enabled) {
-
- Transform pose = b.pose;
- if (b.custom_pose_enable) {
- pose = b.custom_pose * pose;
- }
- if (b.parent >= 0) {
-
- b.pose_global = bonesptr[b.parent].pose_global * pose;
- } else {
-
- b.pose_global = pose;
- }
- } else {
-
- if (b.parent >= 0) {
-
- b.pose_global = bonesptr[b.parent].pose_global;
- } else {
-
- b.pose_global = Transform();
- }
- }
-
- } else {
- if (b.enabled) {
-
- Transform pose = b.pose;
- if (b.custom_pose_enable) {
- pose = b.custom_pose * pose;
- }
- if (b.parent >= 0) {
-
- b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
- } else {
-
- b.pose_global = b.rest * pose;
- }
- } else {
-
- if (b.parent >= 0) {
-
- b.pose_global = bonesptr[b.parent].pose_global * b.rest;
- } else {
-
- b.pose_global = b.rest;
- }
- }
- }
-
- if (b.global_pose_override_amount >= CMP_EPSILON) {
- b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
- }
- }
-
- if (b.global_pose_override_reset) {
- b.global_pose_override_amount = 0.0;
- }
-
- for (List<ObjectID>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
-
- Object *obj = ObjectDB::get_instance(E->get());
- ERR_CONTINUE(!obj);
- Spatial *sp = Object::cast_to<Spatial>(obj);
- ERR_CONTINUE(!sp);
- sp->set_transform(b.pose_global);
- }
- }
-
- //update skins
- for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
-
- const Skin *skin = E->get()->skin.operator->();
- RID skeleton = E->get()->skeleton;
- uint32_t bind_count = skin->get_bind_count();
-
- if (E->get()->bind_count != bind_count) {
- VS::get_singleton()->skeleton_allocate(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();
- }
-
- if (E->get()->skeleton_version != version) {
-
- for (uint32_t i = 0; i < bind_count; i++) {
- StringName bind_name = skin->get_bind_name(i);
-
- if (bind_name != StringName()) {
- //bind name used, use this
- bool found = false;
- for (int j = 0; j < len; j++) {
- if (bonesptr[j].name == bind_name) {
- E->get()->skin_bone_indices_ptrs[i] = j;
- found = true;
- break;
- }
- }
-
- if (!found) {
- ERR_PRINT("Skin bind #" + itos(i) + " contains named bind '" + String(bind_name) + "' but Skeleton has no bone by that name.");
- E->get()->skin_bone_indices_ptrs[i] = 0;
- }
- } else if (skin->get_bind_bone(i) >= 0) {
- int bind_index = skin->get_bind_bone(i);
- if (bind_index >= len) {
- ERR_PRINT("Skin bind #" + itos(i) + " contains bone index bind: " + itos(bind_index) + " , which is greater than the skeleton bone count: " + itos(len) + ".");
- E->get()->skin_bone_indices_ptrs[i] = 0;
- } else {
- E->get()->skin_bone_indices_ptrs[i] = bind_index;
- }
- } else {
- ERR_PRINT("Skin bind #" + itos(i) + " does not contain a name nor a bone index.");
- E->get()->skin_bone_indices_ptrs[i] = 0;
- }
- }
-
- E->get()->skeleton_version = version;
- }
-
- for (uint32_t i = 0; i < bind_count; i++) {
- uint32_t bone_index = E->get()->skin_bone_indices_ptrs[i];
- ERR_CONTINUE(bone_index >= (uint32_t)len);
- vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
- }
- }
-
- dirty = false;
- } break;
-
-#ifndef _3D_DISABLED
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- // This is active only if the skeleton animates the physical bones
- // and the state of the bone is not active.
- if (animate_physical_bones) {
- for (int i = 0; i < bones.size(); i += 1) {
- if (bones[i].physical_bone) {
- if (bones[i].physical_bone->is_simulating_physics() == false) {
- bones[i].physical_bone->reset_to_rest_position();
- }
- }
- }
- }
- } break;
- case NOTIFICATION_READY: {
- if (Engine::get_singleton()->is_editor_hint()) {
- set_physics_process_internal(true);
- }
- } break;
-#endif
- }
-}
-
-void Skeleton::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
- bones.write[p_bone].global_pose_override_amount = p_amount;
- bones.write[p_bone].global_pose_override = p_pose;
- bones.write[p_bone].global_pose_override_reset = !p_persistent;
- _make_dirty();
-}
-
-Transform Skeleton::get_bone_global_pose(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
- if (dirty)
- const_cast<Skeleton *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
- return bones[p_bone].pose_global;
-}
-
-// skeleton creation api
-void Skeleton::add_bone(const String &p_name) {
-
- ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);
-
- for (int i = 0; i < bones.size(); i++) {
-
- ERR_FAIL_COND(bones[i].name == p_name);
- }
-
- Bone b;
- b.name = p_name;
- bones.push_back(b);
- process_order_dirty = true;
- version++;
- _make_dirty();
- update_gizmo();
-}
-int Skeleton::find_bone(const String &p_name) const {
-
- for (int i = 0; i < bones.size(); i++) {
-
- if (bones[i].name == p_name)
- return i;
- }
-
- return -1;
-}
-String Skeleton::get_bone_name(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), "");
-
- return bones[p_bone].name;
-}
-
-bool Skeleton::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
-
- int parent_of_bone = get_bone_parent(p_bone);
-
- if (-1 == parent_of_bone)
- return false;
-
- if (parent_of_bone == p_parent_bone_id)
- return true;
-
- return is_bone_parent_of(parent_of_bone, p_parent_bone_id);
-}
-
-int Skeleton::get_bone_count() const {
-
- return bones.size();
-}
-
-void Skeleton::set_bone_parent(int p_bone, int p_parent) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
-
- bones.write[p_bone].parent = p_parent;
- process_order_dirty = true;
- _make_dirty();
-}
-
-void Skeleton::unparent_bone_and_rest(int p_bone) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- _update_process_order();
-
- int parent = bones[p_bone].parent;
- while (parent >= 0) {
- bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
- parent = bones[parent].parent;
- }
-
- bones.write[p_bone].parent = -1;
- process_order_dirty = true;
-
- _make_dirty();
-}
-
-void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
- bones.write[p_bone].disable_rest = p_disable;
-}
-
-bool Skeleton::is_bone_rest_disabled(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
- return bones[p_bone].disable_rest;
-}
-
-int Skeleton::get_bone_parent(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), -1);
-
- return bones[p_bone].parent;
-}
-
-void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- bones.write[p_bone].rest = p_rest;
- _make_dirty();
-}
-Transform Skeleton::get_bone_rest(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
-
- return bones[p_bone].rest;
-}
-
-void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- bones.write[p_bone].enabled = p_enabled;
- _make_dirty();
-}
-bool Skeleton::is_bone_enabled(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
- return bones[p_bone].enabled;
-}
-
-void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) {
-
- ERR_FAIL_NULL(p_node);
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- ObjectID id = p_node->get_instance_id();
-
- for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
-
- if (E->get() == id)
- return; // already here
- }
-
- bones.write[p_bone].nodes_bound.push_back(id);
-}
-void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) {
-
- ERR_FAIL_NULL(p_node);
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- ObjectID id = p_node->get_instance_id();
- bones.write[p_bone].nodes_bound.erase(id);
-}
-void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
-
- Object *obj = ObjectDB::get_instance(E->get());
- ERR_CONTINUE(!obj);
- p_bound->push_back(Object::cast_to<Node>(obj));
- }
-}
-
-void Skeleton::clear_bones() {
-
- bones.clear();
- process_order_dirty = true;
- version++;
- _make_dirty();
-}
-
-// posing api
-
-void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
-
- bones.write[p_bone].pose = p_pose;
- if (is_inside_tree()) {
- _make_dirty();
- }
-}
-Transform Skeleton::get_bone_pose(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
- return bones[p_bone].pose;
-}
-
-void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) {
-
- ERR_FAIL_INDEX(p_bone, bones.size());
- //ERR_FAIL_COND( !is_inside_scene() );
-
- bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
- bones.write[p_bone].custom_pose = p_custom_pose;
-
- _make_dirty();
-}
-
-Transform Skeleton::get_bone_custom_pose(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
- return bones[p_bone].custom_pose;
-}
-
-void Skeleton::_make_dirty() {
-
- if (dirty)
- return;
-
- MessageQueue::get_singleton()->push_notification(this, NOTIFICATION_UPDATE_SKELETON);
- dirty = true;
-}
-
-int Skeleton::get_process_order(int p_idx) {
- ERR_FAIL_INDEX_V(p_idx, bones.size(), -1);
- _update_process_order();
- return process_order[p_idx];
-}
-
-void Skeleton::localize_rests() {
-
- _update_process_order();
-
- for (int i = bones.size() - 1; i >= 0; i--) {
- int idx = process_order[i];
- if (bones[idx].parent >= 0) {
- set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest);
- }
- }
-}
-
-#ifndef _3D_DISABLED
-
-void Skeleton::set_animate_physical_bones(bool p_animate) {
- animate_physical_bones = p_animate;
-
- if (Engine::get_singleton()->is_editor_hint() == false) {
- bool sim = false;
- for (int i = 0; i < bones.size(); i += 1) {
- if (bones[i].physical_bone) {
- bones[i].physical_bone->reset_physics_simulation_state();
- if (bones[i].physical_bone->is_simulating_physics()) {
- sim = true;
- }
- }
- }
- set_physics_process_internal(sim == false && p_animate);
- }
-}
-
-bool Skeleton::get_animate_physical_bones() const {
- return animate_physical_bones;
-}
-
-void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
- ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(bones[p_bone].physical_bone);
- ERR_FAIL_COND(!p_physical_bone);
- bones.write[p_bone].physical_bone = p_physical_bone;
-
- _rebuild_physical_bones_cache();
-}
-
-void Skeleton::unbind_physical_bone_from_bone(int p_bone) {
- ERR_FAIL_INDEX(p_bone, bones.size());
- bones.write[p_bone].physical_bone = NULL;
-
- _rebuild_physical_bones_cache();
-}
-
-PhysicalBone *Skeleton::get_physical_bone(int p_bone) {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
-
- return bones[p_bone].physical_bone;
-}
-
-PhysicalBone *Skeleton::get_physical_bone_parent(int p_bone) {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
-
- if (bones[p_bone].cache_parent_physical_bone) {
- return bones[p_bone].cache_parent_physical_bone;
- }
-
- return _get_physical_bone_parent(p_bone);
-}
-
-PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
-
- const int parent_bone = bones[p_bone].parent;
- if (0 > parent_bone) {
- return NULL;
- }
-
- PhysicalBone *pb = bones[parent_bone].physical_bone;
- if (pb) {
- return pb;
- } else {
- return get_physical_bone_parent(parent_bone);
- }
-}
-
-void Skeleton::_rebuild_physical_bones_cache() {
- const int b_size = bones.size();
- for (int i = 0; i < b_size; ++i) {
- PhysicalBone *parent_pb = _get_physical_bone_parent(i);
- if (parent_pb != bones[i].physical_bone) {
- bones.write[i].cache_parent_physical_bone = parent_pb;
- if (bones[i].physical_bone)
- bones[i].physical_bone->_on_bone_parent_changed();
- }
- }
-}
-
-void _pb_stop_simulation(Node *p_node) {
-
- for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
- _pb_stop_simulation(p_node->get_child(i));
- }
-
- PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
- if (pb) {
- pb->set_simulate_physics(false);
- }
-}
-
-void Skeleton::physical_bones_stop_simulation() {
- _pb_stop_simulation(this);
- if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) {
- set_physics_process_internal(true);
- }
-}
-
-void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
-
- for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
- _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones);
- }
-
- PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
- if (pb) {
- for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
- if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
- pb->set_simulate_physics(true);
- break;
- }
- }
- }
-}
-
-void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
- set_physics_process_internal(false);
-
- Vector<int> sim_bones;
- if (p_bones.size() <= 0) {
- sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
- } else {
- sim_bones.resize(p_bones.size());
- int c = 0;
- for (int i = sim_bones.size() - 1; 0 <= i; --i) {
- Variant::Type type = p_bones.get(i).get_type();
- if (Variant::STRING == type || Variant::STRING_NAME == type) {
- int bone_id = find_bone(p_bones.get(i));
- if (bone_id != -1)
- sim_bones.write[c++] = bone_id;
- }
- }
- sim_bones.resize(c);
- }
-
- _pb_start_simulation(this, this, sim_bones);
-}
-
-void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
-
- for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
- _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception);
- }
-
- CollisionObject *co = Object::cast_to<CollisionObject>(p_node);
- if (co) {
- if (p_add) {
- PhysicsServer::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception);
- } else {
- PhysicsServer::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception);
- }
- }
-}
-
-void Skeleton::physical_bones_add_collision_exception(RID p_exception) {
- _physical_bones_add_remove_collision_exception(true, this, p_exception);
-}
-
-void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
- _physical_bones_add_remove_collision_exception(false, this, p_exception);
-}
-
-#endif // _3D_DISABLED
-
-void Skeleton::_skin_changed() {
- _make_dirty();
-}
-
-Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
-
- for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
- if (E->get()->skin == p_skin) {
- return Ref<SkinReference>(E->get());
- }
- }
-
- Ref<Skin> skin = p_skin;
-
- if (skin.is_null()) {
- //need to create one from existing code, this is for compatibility only
- //when skeletons did not support skins. It is also used by gizmo
- //to display the skeleton.
-
- skin.instance();
- skin->set_bind_count(bones.size());
- _update_process_order(); //just in case
-
- // pose changed, rebuild cache of inverses
- const Bone *bonesptr = bones.ptr();
- int len = bones.size();
- const int *order = process_order.ptr();
-
- // calculate global rests and invert them
- for (int i = 0; i < len; i++) {
- const Bone &b = bonesptr[order[i]];
- if (b.parent >= 0) {
- skin->set_bind_pose(order[i], skin->get_bind_pose(b.parent) * b.rest);
- } else {
- skin->set_bind_pose(order[i], b.rest);
- }
- }
-
- for (int i = 0; i < len; i++) {
- //the inverse is what is actually required
- skin->set_bind_bone(i, i);
- skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
- }
- }
-
- ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>());
-
- Ref<SkinReference> skin_ref;
- skin_ref.instance();
-
- skin_ref->skeleton_node = this;
- skin_ref->bind_count = 0;
- skin_ref->skeleton = VisualServer::get_singleton()->skeleton_create();
- skin_ref->skeleton_node = this;
- skin_ref->skin = skin;
-
- skin_bindings.insert(skin_ref.operator->());
-
- skin->connect_compat("changed", skin_ref.operator->(), "_skin_changed");
-
- _make_dirty(); //skin needs to be updated, so update skeleton
-
- return skin_ref;
-}
-
-void Skeleton::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
- ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton::find_bone);
- ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &Skeleton::get_bone_name);
-
- ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &Skeleton::get_bone_parent);
- ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton::set_bone_parent);
-
- ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton::get_bone_count);
-
- ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton::unparent_bone_and_rest);
-
- ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest);
- ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest);
-
- ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton::register_skin);
-
- ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests);
-
- ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest);
- ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton::is_bone_rest_disabled);
-
- ClassDB::bind_method(D_METHOD("bind_child_node_to_bone", "bone_idx", "node"), &Skeleton::bind_child_node_to_bone);
- ClassDB::bind_method(D_METHOD("unbind_child_node_from_bone", "bone_idx", "node"), &Skeleton::unbind_child_node_from_bone);
- ClassDB::bind_method(D_METHOD("get_bound_child_nodes_to_bone", "bone_idx"), &Skeleton::_get_bound_child_nodes_to_bone);
-
- ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton::clear_bones);
-
- ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose);
- ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose);
-
- ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose);
-
- ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton::get_bone_custom_pose);
- ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton::set_bone_custom_pose);
-
-#ifndef _3D_DISABLED
-
- ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton::set_animate_physical_bones);
- ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::get_animate_physical_bones);
-
- ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
- ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array()));
- ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception);
- ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
-#endif // _3D_DISABLED
-
- BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
-}
-
-Skeleton::Skeleton() {
-
- animate_physical_bones = true;
- dirty = false;
- version = 1;
- process_order_dirty = true;
-}
-
-Skeleton::~Skeleton() {
-
- //some skins may remain bound
- for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
- E->get()->skeleton_node = nullptr;
- }
-}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
deleted file mode 100644
index 76fd96f30a..0000000000
--- a/scene/3d/skeleton.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*************************************************************************/
-/* skeleton.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SKELETON_H
-#define SKELETON_H
-
-#include "core/rid.h"
-#include "scene/3d/spatial.h"
-#include "scene/resources/skin.h"
-
-#ifndef _3D_DISABLED
-typedef int BoneId;
-
-class PhysicalBone;
-#endif // _3D_DISABLED
-
-class Skeleton;
-
-class SkinReference : public Reference {
- GDCLASS(SkinReference, Reference)
- friend class Skeleton;
-
- Skeleton *skeleton_node;
- RID skeleton;
- Ref<Skin> skin;
- uint32_t bind_count = 0;
- uint64_t skeleton_version = 0;
- Vector<uint32_t> skin_bone_indices;
- uint32_t *skin_bone_indices_ptrs;
- void _skin_changed();
-
-protected:
- static void _bind_methods();
-
-public:
- RID get_skeleton() const;
- Ref<Skin> get_skin() const;
- ~SkinReference();
-};
-
-class Skeleton : public Spatial {
-
- GDCLASS(Skeleton, Spatial);
-
-private:
- friend class SkinReference;
-
- Set<SkinReference *> skin_bindings;
-
- void _skin_changed();
-
- struct Bone {
-
- String name;
-
- bool enabled;
- int parent;
- int sort_index; //used for re-sorting process order
-
- bool disable_rest;
- Transform rest;
-
- Transform pose;
- Transform pose_global;
-
- bool custom_pose_enable;
- Transform custom_pose;
-
- float global_pose_override_amount;
- bool global_pose_override_reset;
- Transform global_pose_override;
-
-#ifndef _3D_DISABLED
- PhysicalBone *physical_bone;
- PhysicalBone *cache_parent_physical_bone;
-#endif // _3D_DISABLED
-
- List<ObjectID> nodes_bound;
-
- Bone() {
- parent = -1;
- enabled = true;
- disable_rest = false;
- custom_pose_enable = false;
- global_pose_override_amount = 0;
- global_pose_override_reset = false;
-#ifndef _3D_DISABLED
- physical_bone = NULL;
- cache_parent_physical_bone = NULL;
-#endif // _3D_DISABLED
- }
- };
-
- bool animate_physical_bones;
- Vector<Bone> bones;
- Vector<int> process_order;
- bool process_order_dirty;
-
- void _make_dirty();
- bool dirty;
-
- uint64_t version;
-
- // bind helpers
- Array _get_bound_child_nodes_to_bone(int p_bone) const {
-
- Array bound;
- List<Node *> children;
- get_bound_child_nodes_to_bone(p_bone, &children);
-
- for (int i = 0; i < children.size(); i++) {
-
- bound.push_back(children[i]);
- }
- return bound;
- }
-
- void _update_process_order();
-
-protected:
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- enum {
-
- NOTIFICATION_UPDATE_SKELETON = 50
- };
-
- // skeleton creation api
- void add_bone(const String &p_name);
- int find_bone(const String &p_name) const;
- String get_bone_name(int p_bone) const;
-
- bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
-
- void set_bone_parent(int p_bone, int p_parent);
- int get_bone_parent(int p_bone) const;
-
- void unparent_bone_and_rest(int p_bone);
-
- void set_bone_disable_rest(int p_bone, bool p_disable);
- bool is_bone_rest_disabled(int p_bone) const;
-
- int get_bone_count() const;
-
- void set_bone_rest(int p_bone, const Transform &p_rest);
- Transform get_bone_rest(int p_bone) const;
- Transform get_bone_global_pose(int p_bone) const;
-
- void set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent = false);
-
- void set_bone_enabled(int p_bone, bool p_enabled);
- bool is_bone_enabled(int p_bone) const;
-
- void bind_child_node_to_bone(int p_bone, Node *p_node);
- void unbind_child_node_from_bone(int p_bone, Node *p_node);
- void get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const;
-
- void clear_bones();
-
- // posing api
-
- void set_bone_pose(int p_bone, const Transform &p_pose);
- Transform get_bone_pose(int p_bone) const;
-
- void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose);
- Transform get_bone_custom_pose(int p_bone) const;
-
- void localize_rests(); // used for loaders and tools
- int get_process_order(int p_idx);
-
- Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
-
-#ifndef _3D_DISABLED
- // Physical bone API
-
- void set_animate_physical_bones(bool p_animate);
- bool get_animate_physical_bones() const;
-
- void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
- void unbind_physical_bone_from_bone(int p_bone);
-
- PhysicalBone *get_physical_bone(int p_bone);
- PhysicalBone *get_physical_bone_parent(int p_bone);
-
-private:
- /// This is a slow API os it's cached
- PhysicalBone *_get_physical_bone_parent(int p_bone);
- void _rebuild_physical_bones_cache();
-
-public:
- void physical_bones_stop_simulation();
- void physical_bones_start_simulation_on(const Array &p_bones);
- void physical_bones_add_collision_exception(RID p_exception);
- void physical_bones_remove_collision_exception(RID p_exception);
-#endif // _3D_DISABLED
-
-public:
- Skeleton();
- ~Skeleton();
-};
-
-#endif
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
new file mode 100644
index 0000000000..59a6e23005
--- /dev/null
+++ b/scene/3d/skeleton_3d.cpp
@@ -0,0 +1,956 @@
+/*************************************************************************/
+/* skeleton_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "skeleton_3d.h"
+
+#include "core/engine.h"
+#include "core/message_queue.h"
+#include "core/project_settings.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/resources/surface_tool.h"
+
+void SkinReference::_skin_changed() {
+ if (skeleton_node) {
+ skeleton_node->_make_dirty();
+ }
+ skeleton_version = 0;
+}
+
+void SkinReference::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed);
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton);
+ ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin);
+}
+
+RID SkinReference::get_skeleton() const {
+ return skeleton;
+}
+
+Ref<Skin> SkinReference::get_skin() const {
+ return skin;
+}
+
+SkinReference::~SkinReference() {
+ if (skeleton_node) {
+ skeleton_node->skin_bindings.erase(this);
+ }
+
+ RS::get_singleton()->free(skeleton);
+}
+
+bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
+
+ String path = p_path;
+
+ if (!path.begins_with("bones/"))
+ return false;
+
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+
+ if (which == bones.size() && what == "name") {
+
+ add_bone(p_value);
+ return true;
+ }
+
+ ERR_FAIL_INDEX_V(which, bones.size(), false);
+
+ if (what == "parent")
+ set_bone_parent(which, p_value);
+ else if (what == "rest")
+ set_bone_rest(which, p_value);
+ else if (what == "enabled")
+ set_bone_enabled(which, p_value);
+ else if (what == "pose")
+ set_bone_pose(which, p_value);
+ else if (what == "bound_children") {
+ Array children = p_value;
+
+ if (is_inside_tree()) {
+ bones.write[which].nodes_bound.clear();
+
+ for (int i = 0; i < children.size(); i++) {
+
+ NodePath npath = children[i];
+ ERR_CONTINUE(npath.operator String() == "");
+ Node *node = get_node(npath);
+ ERR_CONTINUE(!node);
+ bind_child_node_to_bone(which, node);
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
+
+ String path = p_path;
+
+ if (!path.begins_with("bones/"))
+ return false;
+
+ int which = path.get_slicec('/', 1).to_int();
+ String what = path.get_slicec('/', 2);
+
+ ERR_FAIL_INDEX_V(which, bones.size(), false);
+
+ if (what == "name")
+ r_ret = get_bone_name(which);
+ else if (what == "parent")
+ r_ret = get_bone_parent(which);
+ else if (what == "rest")
+ r_ret = get_bone_rest(which);
+ else if (what == "enabled")
+ r_ret = is_bone_enabled(which);
+ else if (what == "pose")
+ r_ret = get_bone_pose(which);
+ else if (what == "bound_children") {
+ Array children;
+
+ for (const List<ObjectID>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->get());
+ ERR_CONTINUE(!obj);
+ Node *node = Object::cast_to<Node>(obj);
+ ERR_CONTINUE(!node);
+ NodePath npath = get_path_to(node);
+ children.push_back(npath);
+ }
+
+ r_ret = children;
+ } else
+ return false;
+
+ return true;
+}
+void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ for (int i = 0; i < bones.size(); i++) {
+
+ String prep = "bones/" + itos(i) + "/";
+ p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
+ p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
+ }
+}
+
+void Skeleton3D::_update_process_order() {
+
+ if (!process_order_dirty)
+ return;
+
+ Bone *bonesptr = bones.ptrw();
+ int len = bones.size();
+
+ process_order.resize(len);
+ int *order = process_order.ptrw();
+ for (int i = 0; i < len; i++) {
+
+ if (bonesptr[i].parent >= len) {
+ //validate this just in case
+ ERR_PRINT("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
+ bonesptr[i].parent = -1;
+ }
+ order[i] = i;
+ bonesptr[i].sort_index = i;
+ }
+ //now check process order
+ int pass_count = 0;
+ while (pass_count < len * len) {
+ //using bubblesort because of simplicity, it won't run every frame though.
+ //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
+ bool swapped = false;
+ for (int i = 0; i < len; i++) {
+ int parent_idx = bonesptr[order[i]].parent;
+ if (parent_idx < 0)
+ continue; //do nothing because it has no parent
+ //swap indices
+ int parent_order = bonesptr[parent_idx].sort_index;
+ if (parent_order > i) {
+ bonesptr[order[i]].sort_index = parent_order;
+ bonesptr[parent_idx].sort_index = i;
+ //swap order
+ SWAP(order[i], order[parent_order]);
+ swapped = true;
+ }
+ }
+
+ if (!swapped)
+ break;
+ pass_count++;
+ }
+
+ if (pass_count == len * len) {
+ ERR_PRINT("Skeleton parenthood graph is cyclic");
+ }
+
+ process_order_dirty = false;
+}
+
+void Skeleton3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_UPDATE_SKELETON: {
+
+ RenderingServer *vs = RenderingServer::get_singleton();
+ Bone *bonesptr = bones.ptrw();
+ int len = bones.size();
+
+ _update_process_order();
+
+ const int *order = process_order.ptr();
+
+ for (int i = 0; i < len; i++) {
+
+ Bone &b = bonesptr[order[i]];
+
+ if (b.global_pose_override_amount >= 0.999) {
+ b.pose_global = b.global_pose_override;
+ } else {
+ if (b.disable_rest) {
+ if (b.enabled) {
+
+ Transform pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
+ if (b.parent >= 0) {
+
+ b.pose_global = bonesptr[b.parent].pose_global * pose;
+ } else {
+
+ b.pose_global = pose;
+ }
+ } else {
+
+ if (b.parent >= 0) {
+
+ b.pose_global = bonesptr[b.parent].pose_global;
+ } else {
+
+ b.pose_global = Transform();
+ }
+ }
+
+ } else {
+ if (b.enabled) {
+
+ Transform pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
+ if (b.parent >= 0) {
+
+ b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
+ } else {
+
+ b.pose_global = b.rest * pose;
+ }
+ } else {
+
+ if (b.parent >= 0) {
+
+ b.pose_global = bonesptr[b.parent].pose_global * b.rest;
+ } else {
+
+ b.pose_global = b.rest;
+ }
+ }
+ }
+
+ if (b.global_pose_override_amount >= CMP_EPSILON) {
+ b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
+ }
+ }
+
+ if (b.global_pose_override_reset) {
+ b.global_pose_override_amount = 0.0;
+ }
+
+ for (List<ObjectID>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->get());
+ ERR_CONTINUE(!obj);
+ Node3D *sp = Object::cast_to<Node3D>(obj);
+ ERR_CONTINUE(!sp);
+ sp->set_transform(b.pose_global);
+ }
+ }
+
+ //update skins
+ for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
+
+ const Skin *skin = E->get()->skin.operator->();
+ RID skeleton = E->get()->skeleton;
+ uint32_t bind_count = skin->get_bind_count();
+
+ if (E->get()->bind_count != bind_count) {
+ RS::get_singleton()->skeleton_allocate(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();
+ }
+
+ if (E->get()->skeleton_version != version) {
+
+ for (uint32_t i = 0; i < bind_count; i++) {
+ StringName bind_name = skin->get_bind_name(i);
+
+ if (bind_name != StringName()) {
+ //bind name used, use this
+ bool found = false;
+ for (int j = 0; j < len; j++) {
+ if (bonesptr[j].name == bind_name) {
+ E->get()->skin_bone_indices_ptrs[i] = j;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ ERR_PRINT("Skin bind #" + itos(i) + " contains named bind '" + String(bind_name) + "' but Skeleton has no bone by that name.");
+ E->get()->skin_bone_indices_ptrs[i] = 0;
+ }
+ } else if (skin->get_bind_bone(i) >= 0) {
+ int bind_index = skin->get_bind_bone(i);
+ if (bind_index >= len) {
+ ERR_PRINT("Skin bind #" + itos(i) + " contains bone index bind: " + itos(bind_index) + " , which is greater than the skeleton bone count: " + itos(len) + ".");
+ E->get()->skin_bone_indices_ptrs[i] = 0;
+ } else {
+ E->get()->skin_bone_indices_ptrs[i] = bind_index;
+ }
+ } else {
+ ERR_PRINT("Skin bind #" + itos(i) + " does not contain a name nor a bone index.");
+ E->get()->skin_bone_indices_ptrs[i] = 0;
+ }
+ }
+
+ E->get()->skeleton_version = version;
+ }
+
+ for (uint32_t i = 0; i < bind_count; i++) {
+ uint32_t bone_index = E->get()->skin_bone_indices_ptrs[i];
+ ERR_CONTINUE(bone_index >= (uint32_t)len);
+ vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
+ }
+ }
+
+ dirty = false;
+ } break;
+
+#ifndef _3D_DISABLED
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ // This is active only if the skeleton animates the physical bones
+ // and the state of the bone is not active.
+ if (animate_physical_bones) {
+ for (int i = 0; i < bones.size(); i += 1) {
+ if (bones[i].physical_bone) {
+ if (bones[i].physical_bone->is_simulating_physics() == false) {
+ bones[i].physical_bone->reset_to_rest_position();
+ }
+ }
+ }
+ }
+ } break;
+ case NOTIFICATION_READY: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_physics_process_internal(true);
+ }
+ } break;
+#endif
+ }
+}
+
+void Skeleton3D::clear_bones_global_pose_override() {
+ for (int i = 0; i < bones.size(); i += 1) {
+ bones.write[i].global_pose_override_amount = 0;
+ }
+ _make_dirty();
+}
+
+void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones.write[p_bone].global_pose_override_amount = p_amount;
+ bones.write[p_bone].global_pose_override = p_pose;
+ bones.write[p_bone].global_pose_override_reset = !p_persistent;
+ _make_dirty();
+}
+
+Transform Skeleton3D::get_bone_global_pose(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+ if (dirty)
+ const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+ return bones[p_bone].pose_global;
+}
+
+// skeleton creation api
+void Skeleton3D::add_bone(const String &p_name) {
+
+ ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);
+
+ for (int i = 0; i < bones.size(); i++) {
+
+ ERR_FAIL_COND(bones[i].name == p_name);
+ }
+
+ Bone b;
+ b.name = p_name;
+ bones.push_back(b);
+ process_order_dirty = true;
+ version++;
+ _make_dirty();
+ update_gizmo();
+}
+int Skeleton3D::find_bone(const String &p_name) const {
+
+ for (int i = 0; i < bones.size(); i++) {
+
+ if (bones[i].name == p_name)
+ return i;
+ }
+
+ return -1;
+}
+String Skeleton3D::get_bone_name(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), "");
+
+ return bones[p_bone].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);
+
+ if (-1 == parent_of_bone)
+ return false;
+
+ if (parent_of_bone == p_parent_bone_id)
+ return true;
+
+ return is_bone_parent_of(parent_of_bone, p_parent_bone_id);
+}
+
+int Skeleton3D::get_bone_count() const {
+
+ return bones.size();
+}
+
+void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
+
+ bones.write[p_bone].parent = p_parent;
+ process_order_dirty = true;
+ _make_dirty();
+}
+
+void Skeleton3D::unparent_bone_and_rest(int p_bone) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ _update_process_order();
+
+ int parent = bones[p_bone].parent;
+ while (parent >= 0) {
+ bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
+ parent = bones[parent].parent;
+ }
+
+ bones.write[p_bone].parent = -1;
+ process_order_dirty = true;
+
+ _make_dirty();
+}
+
+void Skeleton3D::set_bone_disable_rest(int p_bone, bool p_disable) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones.write[p_bone].disable_rest = p_disable;
+}
+
+bool Skeleton3D::is_bone_rest_disabled(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
+ return bones[p_bone].disable_rest;
+}
+
+int Skeleton3D::get_bone_parent(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), -1);
+
+ return bones[p_bone].parent;
+}
+
+void Skeleton3D::set_bone_rest(int p_bone, const Transform &p_rest) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ bones.write[p_bone].rest = p_rest;
+ _make_dirty();
+}
+Transform Skeleton3D::get_bone_rest(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+
+ return bones[p_bone].rest;
+}
+
+void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ bones.write[p_bone].enabled = p_enabled;
+ _make_dirty();
+}
+bool Skeleton3D::is_bone_enabled(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
+ return bones[p_bone].enabled;
+}
+
+void Skeleton3D::bind_child_node_to_bone(int p_bone, Node *p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ ObjectID id = p_node->get_instance_id();
+
+ for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
+
+ if (E->get() == id)
+ return; // already here
+ }
+
+ bones.write[p_bone].nodes_bound.push_back(id);
+}
+void Skeleton3D::unbind_child_node_from_bone(int p_bone, Node *p_node) {
+
+ ERR_FAIL_NULL(p_node);
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ ObjectID id = p_node->get_instance_id();
+ bones.write[p_bone].nodes_bound.erase(id);
+}
+void Skeleton3D::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ for (const List<ObjectID>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
+
+ Object *obj = ObjectDB::get_instance(E->get());
+ ERR_CONTINUE(!obj);
+ p_bound->push_back(Object::cast_to<Node>(obj));
+ }
+}
+
+void Skeleton3D::clear_bones() {
+
+ bones.clear();
+ process_order_dirty = true;
+ version++;
+ _make_dirty();
+}
+
+// posing api
+
+void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ bones.write[p_bone].pose = p_pose;
+ if (is_inside_tree()) {
+ _make_dirty();
+ }
+}
+Transform Skeleton3D::get_bone_pose(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+ return bones[p_bone].pose;
+}
+
+void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) {
+
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ //ERR_FAIL_COND( !is_inside_scene() );
+
+ bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
+ bones.write[p_bone].custom_pose = p_custom_pose;
+
+ _make_dirty();
+}
+
+Transform Skeleton3D::get_bone_custom_pose(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
+ return bones[p_bone].custom_pose;
+}
+
+void Skeleton3D::_make_dirty() {
+
+ if (dirty)
+ return;
+
+ MessageQueue::get_singleton()->push_notification(this, NOTIFICATION_UPDATE_SKELETON);
+ dirty = true;
+}
+
+int Skeleton3D::get_process_order(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, bones.size(), -1);
+ _update_process_order();
+ return process_order[p_idx];
+}
+
+void Skeleton3D::localize_rests() {
+
+ _update_process_order();
+
+ for (int i = bones.size() - 1; i >= 0; i--) {
+ int idx = process_order[i];
+ if (bones[idx].parent >= 0) {
+ set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest);
+ }
+ }
+}
+
+#ifndef _3D_DISABLED
+
+void Skeleton3D::set_animate_physical_bones(bool p_animate) {
+ animate_physical_bones = p_animate;
+
+ if (Engine::get_singleton()->is_editor_hint() == false) {
+ bool sim = false;
+ for (int i = 0; i < bones.size(); i += 1) {
+ if (bones[i].physical_bone) {
+ bones[i].physical_bone->reset_physics_simulation_state();
+ if (bones[i].physical_bone->is_simulating_physics()) {
+ sim = true;
+ }
+ }
+ }
+ set_physics_process_internal(sim == false && p_animate);
+ }
+}
+
+bool Skeleton3D::get_animate_physical_bones() const {
+ return animate_physical_bones;
+}
+
+void Skeleton3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ ERR_FAIL_COND(bones[p_bone].physical_bone);
+ ERR_FAIL_COND(!p_physical_bone);
+ bones.write[p_bone].physical_bone = p_physical_bone;
+
+ _rebuild_physical_bones_cache();
+}
+
+void Skeleton3D::unbind_physical_bone_from_bone(int p_bone) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones.write[p_bone].physical_bone = nullptr;
+
+ _rebuild_physical_bones_cache();
+}
+
+PhysicalBone3D *Skeleton3D::get_physical_bone(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), nullptr);
+
+ return bones[p_bone].physical_bone;
+}
+
+PhysicalBone3D *Skeleton3D::get_physical_bone_parent(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), nullptr);
+
+ if (bones[p_bone].cache_parent_physical_bone) {
+ return bones[p_bone].cache_parent_physical_bone;
+ }
+
+ return _get_physical_bone_parent(p_bone);
+}
+
+PhysicalBone3D *Skeleton3D::_get_physical_bone_parent(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), nullptr);
+
+ const int parent_bone = bones[p_bone].parent;
+ if (0 > parent_bone) {
+ return nullptr;
+ }
+
+ PhysicalBone3D *pb = bones[parent_bone].physical_bone;
+ if (pb) {
+ return pb;
+ } else {
+ return get_physical_bone_parent(parent_bone);
+ }
+}
+
+void Skeleton3D::_rebuild_physical_bones_cache() {
+ const int b_size = bones.size();
+ for (int i = 0; i < b_size; ++i) {
+ PhysicalBone3D *parent_pb = _get_physical_bone_parent(i);
+ if (parent_pb != bones[i].physical_bone) {
+ bones.write[i].cache_parent_physical_bone = parent_pb;
+ if (bones[i].physical_bone)
+ bones[i].physical_bone->_on_bone_parent_changed();
+ }
+ }
+}
+
+void _pb_stop_simulation(Node *p_node) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_stop_simulation(p_node->get_child(i));
+ }
+
+ PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
+ if (pb) {
+ pb->set_simulate_physics(false);
+ }
+}
+
+void Skeleton3D::physical_bones_stop_simulation() {
+ _pb_stop_simulation(this);
+ if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) {
+ set_physics_process_internal(true);
+ }
+}
+
+void _pb_start_simulation(const Skeleton3D *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones);
+ }
+
+ PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
+ if (pb) {
+ for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+ if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+ pb->set_simulate_physics(true);
+ break;
+ }
+ }
+ }
+}
+
+void Skeleton3D::physical_bones_start_simulation_on(const Array &p_bones) {
+ set_physics_process_internal(false);
+
+ Vector<int> sim_bones;
+ if (p_bones.size() <= 0) {
+ sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
+ } else {
+ sim_bones.resize(p_bones.size());
+ int c = 0;
+ for (int i = sim_bones.size() - 1; 0 <= i; --i) {
+ Variant::Type type = p_bones.get(i).get_type();
+ if (Variant::STRING == type || Variant::STRING_NAME == type) {
+ int bone_id = find_bone(p_bones.get(i));
+ if (bone_id != -1)
+ sim_bones.write[c++] = bone_id;
+ }
+ }
+ sim_bones.resize(c);
+ }
+
+ _pb_start_simulation(this, this, sim_bones);
+}
+
+void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception);
+ }
+
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_node);
+ if (co) {
+ if (p_add) {
+ PhysicsServer3D::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception);
+ } else {
+ PhysicsServer3D::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception);
+ }
+ }
+}
+
+void Skeleton3D::physical_bones_add_collision_exception(RID p_exception) {
+ _physical_bones_add_remove_collision_exception(true, this, p_exception);
+}
+
+void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) {
+ _physical_bones_add_remove_collision_exception(false, this, p_exception);
+}
+
+#endif // _3D_DISABLED
+
+void Skeleton3D::_skin_changed() {
+ _make_dirty();
+}
+
+Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
+
+ for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
+ if (E->get()->skin == p_skin) {
+ return Ref<SkinReference>(E->get());
+ }
+ }
+
+ Ref<Skin> skin = p_skin;
+
+ if (skin.is_null()) {
+ //need to create one from existing code, this is for compatibility only
+ //when skeletons did not support skins. It is also used by gizmo
+ //to display the skeleton.
+
+ skin.instance();
+ skin->set_bind_count(bones.size());
+ _update_process_order(); //just in case
+
+ // pose changed, rebuild cache of inverses
+ const Bone *bonesptr = bones.ptr();
+ int len = bones.size();
+ const int *order = process_order.ptr();
+
+ // calculate global rests and invert them
+ for (int i = 0; i < len; i++) {
+ const Bone &b = bonesptr[order[i]];
+ if (b.parent >= 0) {
+ skin->set_bind_pose(order[i], skin->get_bind_pose(b.parent) * b.rest);
+ } else {
+ skin->set_bind_pose(order[i], b.rest);
+ }
+ }
+
+ for (int i = 0; i < len; i++) {
+ //the inverse is what is actually required
+ skin->set_bind_bone(i, i);
+ skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
+ }
+ }
+
+ ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>());
+
+ Ref<SkinReference> skin_ref;
+ skin_ref.instance();
+
+ skin_ref->skeleton_node = this;
+ skin_ref->bind_count = 0;
+ skin_ref->skeleton = RenderingServer::get_singleton()->skeleton_create();
+ skin_ref->skeleton_node = this;
+ skin_ref->skin = skin;
+
+ skin_bindings.insert(skin_ref.operator->());
+
+ skin->connect_compat("changed", skin_ref.operator->(), "_skin_changed");
+
+ _make_dirty(); //skin needs to be updated, so update skeleton
+
+ return skin_ref;
+}
+
+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("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);
+
+ ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton3D::get_bone_count);
+
+ ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest);
+
+ ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton3D::get_bone_rest);
+ ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton3D::set_bone_rest);
+
+ ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton3D::register_skin);
+
+ ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton3D::localize_rests);
+
+ ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton3D::set_bone_disable_rest);
+ ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton3D::is_bone_rest_disabled);
+
+ ClassDB::bind_method(D_METHOD("bind_child_node_to_bone", "bone_idx", "node"), &Skeleton3D::bind_child_node_to_bone);
+ ClassDB::bind_method(D_METHOD("unbind_child_node_from_bone", "bone_idx", "node"), &Skeleton3D::unbind_child_node_from_bone);
+ ClassDB::bind_method(D_METHOD("get_bound_child_nodes_to_bone", "bone_idx"), &Skeleton3D::_get_bound_child_nodes_to_bone);
+
+ ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones);
+
+ ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose);
+ ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose);
+
+ ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override);
+ ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose);
+
+ ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton3D::get_bone_custom_pose);
+ ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton3D::set_bone_custom_pose);
+
+#ifndef _3D_DISABLED
+
+ ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton3D::set_animate_physical_bones);
+ ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones);
+
+ ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton3D::physical_bones_stop_simulation);
+ ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton3D::physical_bones_start_simulation_on, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception);
+ ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
+#endif // _3D_DISABLED
+
+ BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
+}
+
+Skeleton3D::Skeleton3D() {
+
+ animate_physical_bones = true;
+ dirty = false;
+ version = 1;
+ process_order_dirty = true;
+}
+
+Skeleton3D::~Skeleton3D() {
+
+ //some skins may remain bound
+ for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
+ E->get()->skeleton_node = nullptr;
+ }
+}
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
new file mode 100644
index 0000000000..08b8691658
--- /dev/null
+++ b/scene/3d/skeleton_3d.h
@@ -0,0 +1,235 @@
+/*************************************************************************/
+/* skeleton_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SKELETON_3D_H
+#define SKELETON_3D_H
+
+#include "core/rid.h"
+#include "scene/3d/node_3d.h"
+#include "scene/resources/skin.h"
+
+#ifndef _3D_DISABLED
+typedef int BoneId;
+
+class PhysicalBone3D;
+#endif // _3D_DISABLED
+
+class Skeleton3D;
+
+class SkinReference : public Reference {
+ GDCLASS(SkinReference, Reference)
+ friend class Skeleton3D;
+
+ Skeleton3D *skeleton_node;
+ RID skeleton;
+ Ref<Skin> skin;
+ uint32_t bind_count = 0;
+ uint64_t skeleton_version = 0;
+ Vector<uint32_t> skin_bone_indices;
+ uint32_t *skin_bone_indices_ptrs;
+ void _skin_changed();
+
+protected:
+ static void _bind_methods();
+
+public:
+ RID get_skeleton() const;
+ Ref<Skin> get_skin() const;
+ ~SkinReference();
+};
+
+class Skeleton3D : public Node3D {
+
+ GDCLASS(Skeleton3D, Node3D);
+
+private:
+ friend class SkinReference;
+
+ Set<SkinReference *> skin_bindings;
+
+ void _skin_changed();
+
+ struct Bone {
+
+ String name;
+
+ bool enabled;
+ int parent;
+ int sort_index; //used for re-sorting process order
+
+ bool disable_rest;
+ Transform rest;
+
+ Transform pose;
+ Transform pose_global;
+
+ bool custom_pose_enable;
+ Transform custom_pose;
+
+ float global_pose_override_amount;
+ bool global_pose_override_reset;
+ Transform global_pose_override;
+
+#ifndef _3D_DISABLED
+ PhysicalBone3D *physical_bone;
+ PhysicalBone3D *cache_parent_physical_bone;
+#endif // _3D_DISABLED
+
+ List<ObjectID> nodes_bound;
+
+ Bone() {
+ parent = -1;
+ enabled = true;
+ disable_rest = false;
+ custom_pose_enable = false;
+ global_pose_override_amount = 0;
+ global_pose_override_reset = false;
+#ifndef _3D_DISABLED
+ physical_bone = nullptr;
+ cache_parent_physical_bone = nullptr;
+#endif // _3D_DISABLED
+ }
+ };
+
+ bool animate_physical_bones;
+ Vector<Bone> bones;
+ Vector<int> process_order;
+ bool process_order_dirty;
+
+ void _make_dirty();
+ bool dirty;
+
+ uint64_t version;
+
+ // bind helpers
+ Array _get_bound_child_nodes_to_bone(int p_bone) const {
+
+ Array bound;
+ List<Node *> children;
+ get_bound_child_nodes_to_bone(p_bone, &children);
+
+ for (int i = 0; i < children.size(); i++) {
+
+ bound.push_back(children[i]);
+ }
+ return bound;
+ }
+
+ void _update_process_order();
+
+protected:
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ enum {
+
+ NOTIFICATION_UPDATE_SKELETON = 50
+ };
+
+ // skeleton creation api
+ void add_bone(const String &p_name);
+ int find_bone(const String &p_name) const;
+ String get_bone_name(int p_bone) const;
+
+ bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
+
+ void set_bone_parent(int p_bone, int p_parent);
+ int get_bone_parent(int p_bone) const;
+
+ void unparent_bone_and_rest(int p_bone);
+
+ void set_bone_disable_rest(int p_bone, bool p_disable);
+ bool is_bone_rest_disabled(int p_bone) const;
+
+ int get_bone_count() const;
+
+ void set_bone_rest(int p_bone, const Transform &p_rest);
+ Transform get_bone_rest(int p_bone) const;
+ Transform get_bone_global_pose(int p_bone) const;
+
+ void clear_bones_global_pose_override();
+ void set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent = false);
+
+ void set_bone_enabled(int p_bone, bool p_enabled);
+ bool is_bone_enabled(int p_bone) const;
+
+ void bind_child_node_to_bone(int p_bone, Node *p_node);
+ void unbind_child_node_from_bone(int p_bone, Node *p_node);
+ void get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const;
+
+ void clear_bones();
+
+ // posing api
+
+ void set_bone_pose(int p_bone, const Transform &p_pose);
+ Transform get_bone_pose(int p_bone) const;
+
+ void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose);
+ Transform get_bone_custom_pose(int p_bone) const;
+
+ void localize_rests(); // used for loaders and tools
+ int get_process_order(int p_idx);
+
+ Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
+
+#ifndef _3D_DISABLED
+ // Physical bone API
+
+ void set_animate_physical_bones(bool p_animate);
+ bool get_animate_physical_bones() const;
+
+ void bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone);
+ void unbind_physical_bone_from_bone(int p_bone);
+
+ PhysicalBone3D *get_physical_bone(int p_bone);
+ PhysicalBone3D *get_physical_bone_parent(int p_bone);
+
+private:
+ /// This is a slow API os it's cached
+ PhysicalBone3D *_get_physical_bone_parent(int p_bone);
+ void _rebuild_physical_bones_cache();
+
+public:
+ void physical_bones_stop_simulation();
+ void physical_bones_start_simulation_on(const Array &p_bones);
+ void physical_bones_add_collision_exception(RID p_exception);
+ void physical_bones_remove_collision_exception(RID p_exception);
+#endif // _3D_DISABLED
+
+public:
+ Skeleton3D();
+ ~Skeleton3D();
+};
+
+#endif
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
new file mode 100644
index 0000000000..7366290ed3
--- /dev/null
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -0,0 +1,578 @@
+/*************************************************************************/
+/* skeleton_ik_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/**
+ * @author AndreaCatania
+ */
+
+#include "skeleton_ik_3d.h"
+
+#ifndef _3D_DISABLED
+
+FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) {
+ for (int i = children.size() - 1; 0 <= i; --i) {
+ if (p_bone_id == children[i].bone) {
+ return &children.write[i];
+ }
+ }
+ return nullptr;
+}
+
+FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(const BoneId p_bone_id) {
+ const int infant_child_id = children.size();
+ children.resize(infant_child_id + 1);
+ children.write[infant_child_id].bone = p_bone_id;
+ children.write[infant_child_id].parent_item = this;
+ return &children.write[infant_child_id];
+}
+
+/// Build a chain that starts from the root to tip
+bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) {
+
+ ERR_FAIL_COND_V(-1 == p_task->root_bone, false);
+
+ Chain &chain(p_task->chain);
+
+ chain.tips.resize(p_task->end_effectors.size());
+ 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
+ Vector<BoneId> chain_ids;
+ // This is used to know the chain size
+ int sub_chain_size;
+ // Resize only one time in order to fit all joints for performance reason
+ chain_ids.resize(p_task->skeleton->get_bone_count());
+
+ for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) {
+
+ const EndEffector *ee(&p_task->end_effectors[x]);
+ ERR_FAIL_COND_V(p_task->root_bone >= ee->tip_bone, false);
+ ERR_FAIL_INDEX_V(ee->tip_bone, p_task->skeleton->get_bone_count(), false);
+
+ sub_chain_size = 0;
+ // Picks all IDs that composing a single chain in reverse order (except the root)
+ BoneId chain_sub_tip(ee->tip_bone);
+ while (chain_sub_tip > p_task->root_bone) {
+
+ chain_ids.write[sub_chain_size++] = chain_sub_tip;
+ chain_sub_tip = p_task->skeleton->get_bone_parent(chain_sub_tip);
+ }
+
+ BoneId middle_chain_item_id = (((float)sub_chain_size) * 0.5);
+
+ // Build chain by reading chain ids in reverse order
+ // For each chain item id will be created a ChainItem if doesn't exists
+ ChainItem *sub_chain(&chain.chain_root);
+ for (int i = sub_chain_size - 1; 0 <= i; --i) {
+
+ ChainItem *child_ci(sub_chain->find_child(chain_ids[i]));
+ 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;
+
+ if (child_ci->parent_item) {
+ child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length();
+ }
+ }
+
+ sub_chain = child_ci;
+
+ if (middle_chain_item_id == i) {
+ chain.middle_chain_item = child_ci;
+ }
+ }
+
+ if (!middle_chain_item_id)
+ chain.middle_chain_item = nullptr;
+
+ // Initialize current tip
+ chain.tips.write[x].chain_item = sub_chain;
+ chain.tips.write[x].end_effector = ee;
+
+ 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)
+ // is not yet created.
+ // Remove this code when this is done
+ break;
+ }
+ }
+ 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);
+ int can_solve(p_task->max_iterations);
+ while (distance_to_goal > p_task->min_distance && Math::abs(previous_distance_to_goal - distance_to_goal) > 0.005 && can_solve) {
+ previous_distance_to_goal = distance_to_goal;
+ --can_solve;
+
+ solve_simple_backwards(p_task->chain, p_solve_magnet);
+ solve_simple_forwards(p_task->chain, p_solve_magnet);
+
+ distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length();
+ }
+}
+
+void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve_magnet) {
+
+ if (p_solve_magnet && !r_chain.middle_chain_item) {
+ return;
+ }
+
+ Vector3 goal;
+ ChainItem *sub_chain_tip;
+ if (p_solve_magnet) {
+ goal = r_chain.magnet_position;
+ sub_chain_tip = r_chain.middle_chain_item;
+ } else {
+ goal = r_chain.tips[0].end_effector->goal_transform.origin;
+ sub_chain_tip = r_chain.tips[0].chain_item;
+ }
+
+ while (sub_chain_tip) {
+ sub_chain_tip->current_pos = goal;
+
+ if (sub_chain_tip->parent_item) {
+ // Not yet in the chain root
+ // So calculate next goal location
+
+ const Vector3 look_parent((sub_chain_tip->parent_item->current_pos - sub_chain_tip->current_pos).normalized());
+ goal = sub_chain_tip->current_pos + (look_parent * sub_chain_tip->length);
+
+ // [TODO] Constraints goes here
+ }
+
+ sub_chain_tip = sub_chain_tip->parent_item;
+ }
+}
+
+void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) {
+
+ if (p_solve_magnet && !r_chain.middle_chain_item) {
+ return;
+ }
+
+ ChainItem *sub_chain_root(&r_chain.chain_root);
+ Vector3 origin(r_chain.chain_root.initial_transform.origin);
+
+ while (sub_chain_root) { // Reach the tip
+ sub_chain_root->current_pos = origin;
+
+ if (!sub_chain_root->children.empty()) {
+
+ ChainItem &child(sub_chain_root->children.write[0]);
+
+ // Is not tip
+ // So calculate next origin location
+
+ // Look child
+ sub_chain_root->current_ori = (child.current_pos - sub_chain_root->current_pos).normalized();
+ origin = sub_chain_root->current_pos + (sub_chain_root->current_ori * child.length);
+
+ // [TODO] Constraints goes here
+
+ if (p_solve_magnet && sub_chain_root == r_chain.middle_chain_item) {
+ // In case of magnet solving this is the tip
+ sub_chain_root = nullptr;
+ } else {
+ sub_chain_root = &child;
+ }
+ } else {
+
+ // Is tip
+ sub_chain_root = nullptr;
+ }
+ }
+}
+
+FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) {
+
+ FabrikInverseKinematic::EndEffector ee;
+ ee.tip_bone = tip_bone;
+
+ Task *task(memnew(Task));
+ task->skeleton = p_sk;
+ task->root_bone = root_bone;
+ task->end_effectors.push_back(ee);
+ task->goal_global_transform = goal_transform;
+
+ if (!build_chain(task)) {
+ free_task(task);
+ return nullptr;
+ }
+
+ return task;
+}
+
+void FabrikInverseKinematic::free_task(Task *p_task) {
+ if (p_task)
+ memdelete(p_task);
+}
+
+void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) {
+ p_task->goal_global_transform = p_goal;
+}
+
+void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta) {
+
+ if (blending_delta >= 0.99f) {
+ // Update the end_effector (local transform) without blending
+ 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));
+
+ // 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);
+ }
+}
+
+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) {
+ return; // Skip solving
+ }
+
+ p_task->skeleton->clear_bones_global_pose_override();
+
+ 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_chain(p_task->skeleton, &p_task->chain.chain_root);
+
+ if (p_use_magnet && p_task->chain.middle_chain_item) {
+ p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.linear_interpolate(p_magnet_position, blending_delta);
+ solve_simple(p_task, true);
+ }
+ solve_simple(p_task, false);
+
+ // Assign new bone position.
+ ChainItem *ci(&p_task->chain.chain_root);
+ while (ci) {
+ Transform new_bone_pose(ci->initial_transform);
+ new_bone_pose.origin = ci->current_pos;
+
+ if (!ci->children.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 {
+ // 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;
+ }
+
+ p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0, true);
+
+ if (!ci->children.empty())
+ ci = &ci->children.write[0];
+ else
+ ci = nullptr;
+ }
+}
+
+void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "root_bone" || property.name == "tip_bone") {
+
+ if (skeleton) {
+
+ String names("--,");
+ for (int i = 0; i < skeleton->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += skeleton->get_bone_name(i);
+ }
+
+ property.hint = PROPERTY_HINT_ENUM;
+ property.hint_string = names;
+ } else {
+
+ property.hint = PROPERTY_HINT_NONE;
+ property.hint_string = "";
+ }
+ }
+}
+
+void SkeletonIK3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_root_bone", "root_bone"), &SkeletonIK3D::set_root_bone);
+ ClassDB::bind_method(D_METHOD("get_root_bone"), &SkeletonIK3D::get_root_bone);
+
+ ClassDB::bind_method(D_METHOD("set_tip_bone", "tip_bone"), &SkeletonIK3D::set_tip_bone);
+ ClassDB::bind_method(D_METHOD("get_tip_bone"), &SkeletonIK3D::get_tip_bone);
+
+ ClassDB::bind_method(D_METHOD("set_interpolation", "interpolation"), &SkeletonIK3D::set_interpolation);
+ ClassDB::bind_method(D_METHOD("get_interpolation"), &SkeletonIK3D::get_interpolation);
+
+ ClassDB::bind_method(D_METHOD("set_target_transform", "target"), &SkeletonIK3D::set_target_transform);
+ ClassDB::bind_method(D_METHOD("get_target_transform"), &SkeletonIK3D::get_target_transform);
+
+ ClassDB::bind_method(D_METHOD("set_target_node", "node"), &SkeletonIK3D::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonIK3D::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_override_tip_basis", "override"), &SkeletonIK3D::set_override_tip_basis);
+ ClassDB::bind_method(D_METHOD("is_override_tip_basis"), &SkeletonIK3D::is_override_tip_basis);
+
+ ClassDB::bind_method(D_METHOD("set_use_magnet", "use"), &SkeletonIK3D::set_use_magnet);
+ ClassDB::bind_method(D_METHOD("is_using_magnet"), &SkeletonIK3D::is_using_magnet);
+
+ ClassDB::bind_method(D_METHOD("set_magnet_position", "local_position"), &SkeletonIK3D::set_magnet_position);
+ ClassDB::bind_method(D_METHOD("get_magnet_position"), &SkeletonIK3D::get_magnet_position);
+
+ ClassDB::bind_method(D_METHOD("get_parent_skeleton"), &SkeletonIK3D::get_parent_skeleton);
+ ClassDB::bind_method(D_METHOD("is_running"), &SkeletonIK3D::is_running);
+
+ ClassDB::bind_method(D_METHOD("set_min_distance", "min_distance"), &SkeletonIK3D::set_min_distance);
+ ClassDB::bind_method(D_METHOD("get_min_distance"), &SkeletonIK3D::get_min_distance);
+
+ ClassDB::bind_method(D_METHOD("set_max_iterations", "iterations"), &SkeletonIK3D::set_max_iterations);
+ ClassDB::bind_method(D_METHOD("get_max_iterations"), &SkeletonIK3D::get_max_iterations);
+
+ ClassDB::bind_method(D_METHOD("start", "one_time"), &SkeletonIK3D::start, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("stop"), &SkeletonIK3D::stop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone"), "set_root_bone", "get_root_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "tip_bone"), "set_tip_bone", "get_tip_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_tip_basis"), "set_override_tip_basis", "is_override_tip_basis");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node"), "set_target_node", "get_target_node");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min_distance"), "set_min_distance", "get_min_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_iterations"), "set_max_iterations", "get_max_iterations");
+}
+
+void SkeletonIK3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ skeleton = Object::cast_to<Skeleton3D>(get_parent());
+ set_process_priority(1);
+ reload_chain();
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+
+ if (target_node_override)
+ reload_goal();
+
+ _solve_chain();
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ reload_chain();
+ } break;
+ }
+}
+
+SkeletonIK3D::SkeletonIK3D() :
+ interpolation(1),
+ override_tip_basis(true),
+ use_magnet(false),
+ min_distance(0.01),
+ max_iterations(10),
+ skeleton(nullptr),
+ target_node_override(nullptr),
+ task(nullptr) {
+}
+
+SkeletonIK3D::~SkeletonIK3D() {
+ FabrikInverseKinematic::free_task(task);
+ task = nullptr;
+}
+
+void SkeletonIK3D::set_root_bone(const StringName &p_root_bone) {
+ root_bone = p_root_bone;
+ reload_chain();
+}
+
+StringName SkeletonIK3D::get_root_bone() const {
+ return root_bone;
+}
+
+void SkeletonIK3D::set_tip_bone(const StringName &p_tip_bone) {
+ tip_bone = p_tip_bone;
+ reload_chain();
+}
+
+StringName SkeletonIK3D::get_tip_bone() const {
+ return tip_bone;
+}
+
+void SkeletonIK3D::set_interpolation(real_t p_interpolation) {
+ interpolation = p_interpolation;
+}
+
+real_t SkeletonIK3D::get_interpolation() const {
+ return interpolation;
+}
+
+void SkeletonIK3D::set_target_transform(const Transform &p_target) {
+ target = p_target;
+ reload_goal();
+}
+
+const Transform &SkeletonIK3D::get_target_transform() const {
+ return target;
+}
+
+void SkeletonIK3D::set_target_node(const NodePath &p_node) {
+ target_node_path_override = p_node;
+ target_node_override = nullptr;
+ reload_goal();
+}
+
+NodePath SkeletonIK3D::get_target_node() {
+ return target_node_path_override;
+}
+
+void SkeletonIK3D::set_override_tip_basis(bool p_override) {
+ override_tip_basis = p_override;
+}
+
+bool SkeletonIK3D::is_override_tip_basis() const {
+ return override_tip_basis;
+}
+
+void SkeletonIK3D::set_use_magnet(bool p_use) {
+ use_magnet = p_use;
+}
+
+bool SkeletonIK3D::is_using_magnet() const {
+ return use_magnet;
+}
+
+void SkeletonIK3D::set_magnet_position(const Vector3 &p_local_position) {
+ magnet_position = p_local_position;
+}
+
+const Vector3 &SkeletonIK3D::get_magnet_position() const {
+ return magnet_position;
+}
+
+void SkeletonIK3D::set_min_distance(real_t p_min_distance) {
+ min_distance = p_min_distance;
+}
+
+void SkeletonIK3D::set_max_iterations(int p_iterations) {
+ max_iterations = p_iterations;
+}
+
+bool SkeletonIK3D::is_running() {
+ return is_processing_internal();
+}
+
+void SkeletonIK3D::start(bool p_one_time) {
+ if (p_one_time) {
+ set_process_internal(false);
+ _solve_chain();
+ } else {
+ set_process_internal(true);
+ }
+}
+
+void SkeletonIK3D::stop() {
+ set_process_internal(false);
+}
+
+Transform SkeletonIK3D::_get_target_transform() {
+
+ if (!target_node_override && !target_node_path_override.is_empty())
+ target_node_override = Object::cast_to<Node3D>(get_node(target_node_path_override));
+
+ if (target_node_override)
+ return target_node_override->get_global_transform();
+ else
+ return target;
+}
+
+void SkeletonIK3D::reload_chain() {
+
+ FabrikInverseKinematic::free_task(task);
+ task = nullptr;
+
+ if (!skeleton)
+ return;
+
+ task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform());
+ if (task) {
+ task->max_iterations = max_iterations;
+ task->min_distance = min_distance;
+ }
+}
+
+void SkeletonIK3D::reload_goal() {
+ if (!task)
+ return;
+
+ FabrikInverseKinematic::set_goal(task, _get_target_transform());
+}
+
+void SkeletonIK3D::_solve_chain() {
+ if (!task)
+ return;
+ FabrikInverseKinematic::solve(task, interpolation, override_tip_basis, use_magnet, magnet_position);
+}
+
+#endif // _3D_DISABLED
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
new file mode 100644
index 0000000000..5fbbe6e9e7
--- /dev/null
+++ b/scene/3d/skeleton_ik_3d.h
@@ -0,0 +1,220 @@
+/*************************************************************************/
+/* skeleton_ik_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SKELETON_IK_H
+#define SKELETON_IK_H
+
+#ifndef _3D_DISABLED
+
+/**
+ * @author AndreaCatania
+ */
+
+#include "core/math/transform.h"
+#include "scene/3d/skeleton_3d.h"
+
+class FabrikInverseKinematic {
+
+ struct EndEffector {
+ BoneId tip_bone;
+ Transform goal_transform;
+ };
+
+ struct ChainItem {
+
+ Vector<ChainItem> children;
+ ChainItem *parent_item;
+
+ // Bone info
+ BoneId bone;
+ PhysicalBone3D *pb;
+
+ real_t length;
+ /// Positions relative to root bone
+ Transform initial_transform;
+ Vector3 current_pos;
+ // Direction from this bone to child
+ Vector3 current_ori;
+
+ ChainItem() :
+ parent_item(nullptr),
+ bone(-1),
+ pb(nullptr),
+ length(0) {}
+
+ ChainItem *find_child(const BoneId p_bone_id);
+ ChainItem *add_child(const BoneId p_bone_id);
+ };
+
+ struct ChainTip {
+ ChainItem *chain_item;
+ const EndEffector *end_effector;
+
+ ChainTip() :
+ chain_item(nullptr),
+ end_effector(nullptr) {}
+
+ ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) :
+ chain_item(p_chain_item),
+ end_effector(p_end_effector) {}
+
+ ChainTip(const ChainTip &p_other_ct) :
+ chain_item(p_other_ct.chain_item),
+ end_effector(p_other_ct.end_effector) {}
+ };
+
+ struct Chain {
+ ChainItem chain_root;
+ ChainItem *middle_chain_item;
+ Vector<ChainTip> tips;
+ Vector3 magnet_position;
+ };
+
+public:
+ struct Task {
+ RID self;
+ Skeleton3D *skeleton;
+
+ Chain chain;
+
+ // Settings
+ real_t min_distance;
+ int max_iterations;
+
+ // Bone data
+ BoneId root_bone;
+ Vector<EndEffector> end_effectors;
+
+ Transform goal_global_transform;
+
+ Task() :
+ skeleton(nullptr),
+ min_distance(0.01),
+ max_iterations(10),
+ root_bone(-1) {}
+ };
+
+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);
+ static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet);
+
+public:
+ static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform);
+ static void free_task(Task *p_task);
+ // The goal of chain should be always in local space
+ 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);
+};
+
+class SkeletonIK3D : public Node {
+ GDCLASS(SkeletonIK3D, Node);
+
+ StringName root_bone;
+ StringName tip_bone;
+ real_t interpolation;
+ Transform target;
+ NodePath target_node_path_override;
+ bool override_tip_basis;
+ bool use_magnet;
+ Vector3 magnet_position;
+
+ real_t min_distance;
+ int max_iterations;
+
+ Skeleton3D *skeleton;
+ Node3D *target_node_override;
+ FabrikInverseKinematic::Task *task;
+
+protected:
+ virtual void
+ _validate_property(PropertyInfo &property) const;
+
+ static void _bind_methods();
+ virtual void _notification(int p_what);
+
+public:
+ SkeletonIK3D();
+ virtual ~SkeletonIK3D();
+
+ void set_root_bone(const StringName &p_root_bone);
+ StringName get_root_bone() const;
+
+ void set_tip_bone(const StringName &p_tip_bone);
+ StringName get_tip_bone() const;
+
+ void set_interpolation(real_t p_interpolation);
+ real_t get_interpolation() const;
+
+ void set_target_transform(const Transform &p_target);
+ const Transform &get_target_transform() const;
+
+ void set_target_node(const NodePath &p_node);
+ NodePath get_target_node();
+
+ void set_override_tip_basis(bool p_override);
+ bool is_override_tip_basis() const;
+
+ void set_use_magnet(bool p_use);
+ bool is_using_magnet() const;
+
+ void set_magnet_position(const Vector3 &p_local_position);
+ const Vector3 &get_magnet_position() const;
+
+ void set_min_distance(real_t p_min_distance);
+ real_t get_min_distance() const { return min_distance; }
+
+ void set_max_iterations(int p_iterations);
+ int get_max_iterations() const { return max_iterations; }
+
+ Skeleton3D *get_parent_skeleton() const { return skeleton; }
+
+ bool is_running();
+
+ void start(bool p_one_time = false);
+ void stop();
+
+private:
+ Transform _get_target_transform();
+ void reload_chain();
+ void reload_goal();
+ void _solve_chain();
+};
+
+#endif // _3D_DISABLED
+
+#endif // SKELETON_IK_H
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
deleted file mode 100644
index 3859a278ef..0000000000
--- a/scene/3d/soft_body.cpp
+++ /dev/null
@@ -1,826 +0,0 @@
-/*************************************************************************/
-/* soft_body.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.h"
-#include "core/list.h"
-#include "core/object.h"
-#include "core/os/os.h"
-#include "core/rid.h"
-#include "scene/3d/collision_object.h"
-#include "scene/3d/physics_body.h"
-#include "scene/3d/skeleton.h"
-#include "servers/physics_server.h"
-
-SoftBodyVisualServerHandler::SoftBodyVisualServerHandler() {}
-
-void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) {
- clear();
-
- ERR_FAIL_COND(!p_mesh.is_valid());
-
- 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 = VS::get_singleton()->mesh_surface_get_format(mesh, surface);
- const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface);
- const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface);
- uint32_t surface_offsets[VS::ARRAY_MAX];
-
- buffer = VS::get_singleton()->mesh_surface_get_array(mesh, surface);
- stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets);
- offset_vertices = surface_offsets[VS::ARRAY_VERTEX];
- offset_normal = surface_offsets[VS::ARRAY_NORMAL];
-#endif
-}
-
-void SoftBodyVisualServerHandler::clear() {
-
- if (mesh.is_valid()) {
- buffer.resize(0);
- }
-
- mesh = RID();
-}
-
-void SoftBodyVisualServerHandler::open() {
- write_buffer = buffer.ptrw();
-}
-
-void SoftBodyVisualServerHandler::close() {
- //write_buffer.release();
-}
-
-void SoftBodyVisualServerHandler::commit_changes() {
- VS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer);
-}
-
-void SoftBodyVisualServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
-}
-
-void SoftBodyVisualServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
-}
-
-void SoftBodyVisualServerHandler::set_aabb(const AABB &p_aabb) {
- VS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
-}
-
-SoftBody::PinnedPoint::PinnedPoint() :
- point_index(-1),
- spatial_attachment(NULL) {
-}
-
-SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
- point_index = obj_tocopy.point_index;
- spatial_attachment_path = obj_tocopy.spatial_attachment_path;
- spatial_attachment = obj_tocopy.spatial_attachment;
- offset = obj_tocopy.offset;
-}
-
-SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) {
- point_index = obj.point_index;
- spatial_attachment_path = obj.spatial_attachment_path;
- spatial_attachment = obj.spatial_attachment;
- offset = obj.offset;
- return *this;
-}
-
-void SoftBody::_update_pickable() {
- if (!is_inside_tree())
- return;
- bool pickable = ray_pickable && is_visible_in_tree();
- PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
-}
-
-bool SoftBody::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- String which = name.get_slicec('/', 0);
-
- if ("pinned_points" == which) {
-
- return _set_property_pinned_points_indices(p_value);
-
- } else if ("attachments" == which) {
-
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
-
- return _set_property_pinned_points_attachment(idx, what, p_value);
- }
-
- return false;
-}
-
-bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- String which = name.get_slicec('/', 0);
-
- if ("pinned_points" == which) {
- Array arr_ret;
- const int pinned_points_indices_size = pinned_points.size();
- const PinnedPoint *r = pinned_points.ptr();
- arr_ret.resize(pinned_points_indices_size);
-
- for (int i = 0; i < pinned_points_indices_size; ++i) {
- arr_ret[i] = r[i].point_index;
- }
-
- r_ret = arr_ret;
- return true;
-
- } else if ("attachments" == which) {
-
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
-
- return _get_property_pinned_points(idx, what, r_ret);
- }
-
- return false;
-}
-
-void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const {
-
- const int pinned_points_indices_size = pinned_points.size();
-
- p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "pinned_points"));
-
- for (int i = 0; i < pinned_points_indices_size; ++i) {
- p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index"));
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path"));
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset"));
- }
-}
-
-bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) {
-
- const int p_indices_size = p_indices.size();
-
- { // Remove the pined points on physics server that will be removed by resize
- const PinnedPoint *r = pinned_points.ptr();
- if (p_indices_size < pinned_points.size()) {
- for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) {
- pin_point(r[i].point_index, false);
- }
- }
- }
-
- pinned_points.resize(p_indices_size);
-
- PinnedPoint *w = pinned_points.ptrw();
- int point_index;
- for (int i = 0; i < p_indices_size; ++i) {
- point_index = p_indices.get(i);
- if (w[i].point_index != point_index) {
- if (-1 != w[i].point_index)
- pin_point(w[i].point_index, false);
- w[i].point_index = point_index;
- pin_point(w[i].point_index, true);
- }
- }
- return true;
-}
-
-bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
- if (pinned_points.size() <= p_item) {
- return false;
- }
-
- if ("spatial_attachment_path" == p_what) {
- PinnedPoint *w = pinned_points.ptrw();
- pin_point(w[p_item].point_index, true, p_value);
- _make_cache_dirty();
- } else if ("offset" == p_what) {
- PinnedPoint *w = pinned_points.ptrw();
- w[p_item].offset = p_value;
- } else {
- return false;
- }
-
- return true;
-}
-
-bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
- if (pinned_points.size() <= p_item) {
- return false;
- }
- const PinnedPoint *r = pinned_points.ptr();
-
- if ("point_index" == p_what) {
- r_ret = r[p_item].point_index;
- } else if ("spatial_attachment_path" == p_what) {
- r_ret = r[p_item].spatial_attachment_path;
- } else if ("offset" == p_what) {
- r_ret = r[p_item].offset;
- } else {
- return false;
- }
-
- return true;
-}
-
-void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) {
- prepare_physics_server();
- _reset_points_offsets();
-#ifdef TOOLS_ENABLED
- if (p_changed == this) {
- update_configuration_warning();
- }
-#endif
-}
-
-void SoftBody::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_WORLD: {
-
- if (Engine::get_singleton()->is_editor_hint()) {
-
- add_change_receptor(this);
- }
-
- RID space = get_world()->get_space();
- PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space);
- prepare_physics_server();
- } break;
- case NOTIFICATION_READY: {
- if (!parent_collision_ignore.is_empty())
- add_collision_exception_with(get_node(parent_collision_ignore));
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- if (Engine::get_singleton()->is_editor_hint()) {
- _reset_points_offsets();
- return;
- }
-
- PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform());
-
- set_notify_transform(false);
- // Required to be top level with Transform at center of world in order to modify VisualServer only to support custom Transform
- set_as_toplevel(true);
- set_transform(Transform());
- set_notify_transform(true);
-
- } break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
-
- _update_pickable();
-
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, RID());
-
- } break;
- }
-
-#ifdef TOOLS_ENABLED
-
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
- }
- }
-
-#endif
-}
-
-void SoftBody::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody::get_collision_layer_bit);
-
- ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore);
-
- ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody::get_collision_exceptions);
- ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with);
- ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with);
-
- ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody::set_simulation_precision);
- ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody::get_simulation_precision);
-
- ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody::set_total_mass);
- ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody::get_total_mass);
-
- ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody::set_linear_stiffness);
- ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody::get_linear_stiffness);
-
- ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody::set_areaAngular_stiffness);
- ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody::get_areaAngular_stiffness);
-
- ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody::set_volume_stiffness);
- ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody::get_volume_stiffness);
-
- ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody::set_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody::get_pressure_coefficient);
-
- ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody::set_pose_matching_coefficient);
- ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody::get_pose_matching_coefficient);
-
- ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody::set_damping_coefficient);
- ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody::get_damping_coefficient);
-
- ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody::set_drag_coefficient);
- ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody::get_drag_coefficient);
-
- ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody::set_ray_pickable);
- ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody::is_ray_pickable);
-
- 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_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore");
- 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 SoftBody::get_configuration_warning() const {
-
- String warning = MeshInstance::get_configuration_warning();
-
- if (get_mesh().is_null()) {
- if (!warning.empty())
- warning += "\n\n";
-
- warning += 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.empty())
- warning += "\n\n";
-
- warning += TTR("Size changes to SoftBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
- }
-
- return warning;
-}
-
-void SoftBody::_update_physics_server() {
- if (!simulation_started)
- return;
-
- _update_cache_pin_points_datas();
- // Submit bone attachment
- const int pinned_points_indices_size = pinned_points.size();
- const PinnedPoint *r = pinned_points.ptr();
- for (int i = 0; i < pinned_points_indices_size; ++i) {
- if (r[i].spatial_attachment) {
- PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset));
- }
- }
-}
-
-void SoftBody::_draw_soft_mesh() {
- if (get_mesh().is_null())
- return;
-
- if (!visual_server_handler.is_ready()) {
-
- visual_server_handler.prepare(get_mesh()->get_rid(), 0);
-
- /// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
- simulation_started = true;
- call_deferred("set_as_toplevel", true);
- call_deferred("set_transform", Transform());
- }
-
- _update_physics_server();
-
- visual_server_handler.open();
- PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler);
- visual_server_handler.close();
-
- visual_server_handler.commit_changes();
-}
-
-void SoftBody::prepare_physics_server() {
-
- if (Engine::get_singleton()->is_editor_hint()) {
-
- if (get_mesh().is_valid())
- PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
- else
- PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
-
- return;
- }
-
- if (get_mesh().is_valid()) {
-
- become_mesh_owner();
- PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
- VS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody::_draw_soft_mesh));
- } else {
-
- PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
- if (VS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody::_draw_soft_mesh))) {
- VS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody::_draw_soft_mesh));
- }
- }
-}
-
-void SoftBody::become_mesh_owner() {
- if (mesh.is_null())
- return;
-
- if (!mesh_owner) {
- mesh_owner = true;
-
- Vector<Ref<Material> > copy_materials;
- copy_materials.append_array(materials);
-
- ERR_FAIL_COND(!mesh->get_surface_count());
-
- // Get current mesh array and create new mesh array with necessary flag for softbody
- Array surface_arrays = mesh->surface_get_arrays(0);
- Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
- Dictionary surface_lods = mesh->surface_get_lods(0);
- uint32_t surface_format = mesh->surface_get_format(0);
-
- surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL);
- surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
-
- Ref<ArrayMesh> soft_mesh;
- soft_mesh.instance();
- soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format);
- soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
-
- set_mesh(soft_mesh);
-
- for (int i = copy_materials.size() - 1; 0 <= i; --i) {
- set_surface_material(i, copy_materials[i]);
- }
- }
-}
-
-void SoftBody::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
-}
-
-uint32_t SoftBody::get_collision_mask() const {
- return collision_mask;
-}
-void SoftBody::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
-}
-
-uint32_t SoftBody::get_collision_layer() const {
- return collision_layer;
-}
-
-void SoftBody::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 SoftBody::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void SoftBody::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 SoftBody::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
-void SoftBody::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
- parent_collision_ignore = p_parent_collision_ignore;
-}
-
-const NodePath &SoftBody::get_parent_collision_ignore() const {
- return parent_collision_ignore;
-}
-
-void SoftBody::set_pinned_points_indices(Vector<SoftBody::PinnedPoint> p_pinned_points_indices) {
- pinned_points = p_pinned_points_indices;
- for (int i = pinned_points.size() - 1; 0 <= i; --i) {
- pin_point(p_pinned_points_indices[i].point_index, true);
- }
-}
-
-Vector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() {
- return pinned_points;
-}
-
-Array SoftBody::get_collision_exceptions() {
- List<RID> exceptions;
- PhysicsServer::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
- Array ret;
- for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
- RID body = E->get();
- ObjectID instance_id = PhysicsServer::get_singleton()->body_get_object_instance_id(body);
- Object *obj = ObjectDB::get_instance(instance_id);
- PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(obj);
- ret.append(physics_body);
- }
- return ret;
-}
-
-void SoftBody::add_collision_exception_with(Node *p_node) {
- ERR_FAIL_NULL(p_node);
- CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject.");
- PhysicsServer::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
-}
-
-void SoftBody::remove_collision_exception_with(Node *p_node) {
- ERR_FAIL_NULL(p_node);
- CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
- ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject.");
- PhysicsServer::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
-}
-
-int SoftBody::get_simulation_precision() {
- return PhysicsServer::get_singleton()->soft_body_get_simulation_precision(physics_rid);
-}
-
-void SoftBody::set_simulation_precision(int p_simulation_precision) {
- PhysicsServer::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
-}
-
-real_t SoftBody::get_total_mass() {
- return PhysicsServer::get_singleton()->soft_body_get_total_mass(physics_rid);
-}
-
-void SoftBody::set_total_mass(real_t p_total_mass) {
- PhysicsServer::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
-}
-
-void SoftBody::set_linear_stiffness(real_t p_linear_stiffness) {
- PhysicsServer::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
-}
-
-real_t SoftBody::get_linear_stiffness() {
- return PhysicsServer::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
-}
-
-void SoftBody::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) {
- PhysicsServer::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness);
-}
-
-real_t SoftBody::get_areaAngular_stiffness() {
- return PhysicsServer::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid);
-}
-
-void SoftBody::set_volume_stiffness(real_t p_volume_stiffness) {
- PhysicsServer::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness);
-}
-
-real_t SoftBody::get_volume_stiffness() {
- return PhysicsServer::get_singleton()->soft_body_get_volume_stiffness(physics_rid);
-}
-
-real_t SoftBody::get_pressure_coefficient() {
- return PhysicsServer::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
-}
-
-void SoftBody::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) {
- PhysicsServer::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient);
-}
-
-real_t SoftBody::get_pose_matching_coefficient() {
- return PhysicsServer::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid);
-}
-
-void SoftBody::set_pressure_coefficient(real_t p_pressure_coefficient) {
- PhysicsServer::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
-}
-
-real_t SoftBody::get_damping_coefficient() {
- return PhysicsServer::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
-}
-
-void SoftBody::set_damping_coefficient(real_t p_damping_coefficient) {
- PhysicsServer::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
-}
-
-real_t SoftBody::get_drag_coefficient() {
- return PhysicsServer::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
-}
-
-void SoftBody::set_drag_coefficient(real_t p_drag_coefficient) {
- PhysicsServer::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
-}
-
-Vector3 SoftBody::get_point_transform(int p_point_index) {
- return PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
-}
-
-void SoftBody::pin_point_toggle(int p_point_index) {
- pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
-}
-
-void SoftBody::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
- _pin_point_on_physics_server(p_point_index, pin);
- if (pin) {
- _add_pinned_point(p_point_index, p_spatial_attachment_path);
- } else {
- _remove_pinned_point(p_point_index);
- }
-}
-
-bool SoftBody::is_point_pinned(int p_point_index) const {
- return -1 != _has_pinned_point(p_point_index);
-}
-
-void SoftBody::set_ray_pickable(bool p_ray_pickable) {
-
- ray_pickable = p_ray_pickable;
- _update_pickable();
-}
-
-bool SoftBody::is_ray_pickable() const {
-
- return ray_pickable;
-}
-
-SoftBody::SoftBody() :
- physics_rid(PhysicsServer::get_singleton()->soft_body_create()),
- mesh_owner(false),
- collision_mask(1),
- collision_layer(1),
- simulation_started(false),
- pinned_points_cache_dirty(true),
- ray_pickable(true) {
-
- PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
-}
-
-SoftBody::~SoftBody() {
- PhysicsServer::get_singleton()->free(physics_rid);
-}
-
-void SoftBody::reset_softbody_pin() {
- PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
- const PinnedPoint *pps = pinned_points.ptr();
- for (int i = pinned_points.size() - 1; 0 < i; --i) {
- PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
- }
-}
-
-void SoftBody::_make_cache_dirty() {
- pinned_points_cache_dirty = true;
-}
-
-void SoftBody::_update_cache_pin_points_datas() {
- if (!pinned_points_cache_dirty)
- return;
-
- pinned_points_cache_dirty = false;
-
- PinnedPoint *w = pinned_points.ptrw();
- for (int i = pinned_points.size() - 1; 0 <= i; --i) {
-
- if (!w[i].spatial_attachment_path.is_empty()) {
- w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path));
- }
- if (!w[i].spatial_attachment) {
- ERR_PRINT("Spatial node not defined in the pinned point, Softbody undefined behaviour!");
- }
- }
-}
-
-void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) {
- PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
-}
-
-void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
- SoftBody::PinnedPoint *pinned_point;
- if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
-
- // Create new
- PinnedPoint pp;
- pp.point_index = p_point_index;
- pp.spatial_attachment_path = p_spatial_attachment_path;
-
- if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
- pp.spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
- pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index));
- }
-
- pinned_points.push_back(pp);
-
- } else {
-
- pinned_point->point_index = p_point_index;
- pinned_point->spatial_attachment_path = p_spatial_attachment_path;
-
- if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
- pinned_point->spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
- pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index));
- }
- }
-}
-
-void SoftBody::_reset_points_offsets() {
-
- if (!Engine::get_singleton()->is_editor_hint())
- return;
-
- const PinnedPoint *r = pinned_points.ptr();
- 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<Spatial>(get_node(r[i].spatial_attachment_path));
-
- if (!r[i].spatial_attachment)
- continue;
-
- w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index));
- }
-}
-
-void SoftBody::_remove_pinned_point(int p_point_index) {
- const int id(_has_pinned_point(p_point_index));
- if (-1 != id) {
- pinned_points.remove(id);
- }
-}
-
-int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_point) const {
- const int id = _has_pinned_point(p_point_index);
- if (-1 == id) {
- r_point = NULL;
- return -1;
- } else {
- r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.ptr()[id]);
- return id;
- }
-}
-
-int SoftBody::_has_pinned_point(int p_point_index) const {
- const PinnedPoint *r = pinned_points.ptr();
- for (int i = pinned_points.size() - 1; 0 <= i; --i) {
- if (p_point_index == r[i].point_index) {
- return i;
- }
- }
- return -1;
-}
diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h
deleted file mode 100644
index d6c35a5989..0000000000
--- a/scene/3d/soft_body.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*************************************************************************/
-/* soft_body.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_PHYSICS_BODY_H
-#define SOFT_PHYSICS_BODY_H
-
-#include "scene/3d/mesh_instance.h"
-
-class SoftBody;
-
-class SoftBodyVisualServerHandler {
-
- friend class SoftBody;
-
- RID mesh;
- int surface;
- Vector<uint8_t> buffer;
- uint32_t stride;
- uint32_t offset_vertices;
- uint32_t offset_normal;
-
- uint8_t *write_buffer;
-
-private:
- SoftBodyVisualServerHandler();
- bool is_ready() { return mesh.is_valid(); }
- void prepare(RID p_mesh_rid, int p_surface);
- void clear();
- void open();
- void close();
- 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);
-};
-
-class SoftBody : public MeshInstance {
- GDCLASS(SoftBody, MeshInstance);
-
-public:
- struct PinnedPoint {
- int point_index;
- NodePath spatial_attachment_path;
- Spatial *spatial_attachment; // Cache
- Vector3 offset;
-
- PinnedPoint();
- PinnedPoint(const PinnedPoint &obj_tocopy);
- PinnedPoint operator=(const PinnedPoint &obj);
- };
-
-private:
- SoftBodyVisualServerHandler visual_server_handler;
-
- RID physics_rid;
-
- bool mesh_owner;
- uint32_t collision_mask;
- uint32_t collision_layer;
- NodePath parent_collision_ignore;
- Vector<PinnedPoint> pinned_points;
- bool simulation_started;
- bool pinned_points_cache_dirty;
-
- Ref<ArrayMesh> debug_mesh_cache;
- class MeshInstance *debug_mesh;
-
- bool capture_input_on_drag;
- bool ray_pickable;
-
- void _update_pickable();
-
-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;
-
- bool _set_property_pinned_points_indices(const Array &p_indices);
- 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);
-
- void _notification(int p_what);
- static void _bind_methods();
-
- virtual String get_configuration_warning() const;
-
-protected:
- void _update_physics_server();
- void _draw_soft_mesh();
-
-public:
- void prepare_physics_server();
- void become_mesh_owner();
-
- 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;
-
- void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
- const NodePath &get_parent_collision_ignore() const;
-
- void set_pinned_points_indices(Vector<PinnedPoint> p_pinned_points_indices);
- Vector<PinnedPoint> get_pinned_points_indices();
-
- void set_simulation_precision(int p_simulation_precision);
- int get_simulation_precision();
-
- void set_total_mass(real_t p_total_mass);
- real_t get_total_mass();
-
- 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();
-
- void set_drag_coefficient(real_t p_drag_coefficient);
- real_t get_drag_coefficient();
-
- Array get_collision_exceptions();
- void add_collision_exception_with(Node *p_node);
- void remove_collision_exception_with(Node *p_node);
-
- Vector3 get_point_transform(int p_point_index);
-
- void pin_point_toggle(int p_point_index);
- void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
- bool is_point_pinned(int p_point_index) const;
-
- void set_ray_pickable(bool p_ray_pickable);
- bool is_ray_pickable() const;
-
- SoftBody();
- ~SoftBody();
-
-private:
- void reset_softbody_pin();
-
- void _make_cache_dirty();
- void _update_cache_pin_points_datas();
-
- void _pin_point_on_physics_server(int p_point_index, bool pin);
- void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path);
- void _reset_points_offsets();
-
- void _remove_pinned_point(int p_point_index);
- int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const;
- int _has_pinned_point(int p_point_index) const;
-};
-
-#endif // SOFT_PHYSICS_BODY_H
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
new file mode 100644
index 0000000000..6092818252
--- /dev/null
+++ b/scene/3d/soft_body_3d.cpp
@@ -0,0 +1,827 @@
+/*************************************************************************/
+/* soft_body_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.h"
+
+#include "core/list.h"
+#include "core/object.h"
+#include "core/os/os.h"
+#include "core/rid.h"
+#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() {}
+
+void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
+ clear();
+
+ ERR_FAIL_COND(!p_mesh.is_valid());
+
+ 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);
+ uint32_t surface_offsets[RS::ARRAY_MAX];
+
+ 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);
+ 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);
+ }
+
+ mesh = RID();
+}
+
+void SoftBodyRenderingServerHandler::open() {
+ write_buffer = buffer.ptrw();
+}
+
+void SoftBodyRenderingServerHandler::close() {
+ //write_buffer.release();
+}
+
+void SoftBodyRenderingServerHandler::commit_changes() {
+ RS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer);
+}
+
+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);
+}
+
+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);
+}
+
+void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
+}
+
+SoftBody3D::PinnedPoint::PinnedPoint() :
+ point_index(-1),
+ spatial_attachment(nullptr) {
+}
+
+SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
+ point_index = obj_tocopy.point_index;
+ spatial_attachment_path = obj_tocopy.spatial_attachment_path;
+ spatial_attachment = obj_tocopy.spatial_attachment;
+ offset = obj_tocopy.offset;
+}
+
+SoftBody3D::PinnedPoint SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
+ point_index = obj.point_index;
+ spatial_attachment_path = obj.spatial_attachment_path;
+ spatial_attachment = obj.spatial_attachment;
+ offset = obj.offset;
+ return *this;
+}
+
+void SoftBody3D::_update_pickable() {
+ if (!is_inside_tree())
+ return;
+ bool pickable = ray_pickable && is_visible_in_tree();
+ PhysicsServer3D::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
+}
+
+bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ String which = name.get_slicec('/', 0);
+
+ if ("pinned_points" == which) {
+
+ return _set_property_pinned_points_indices(p_value);
+
+ } else if ("attachments" == which) {
+
+ int idx = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+
+ return _set_property_pinned_points_attachment(idx, what, p_value);
+ }
+
+ return false;
+}
+
+bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
+ String name = p_name;
+ String which = name.get_slicec('/', 0);
+
+ if ("pinned_points" == which) {
+ Array arr_ret;
+ const int pinned_points_indices_size = pinned_points.size();
+ const PinnedPoint *r = pinned_points.ptr();
+ arr_ret.resize(pinned_points_indices_size);
+
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ arr_ret[i] = r[i].point_index;
+ }
+
+ r_ret = arr_ret;
+ return true;
+
+ } else if ("attachments" == which) {
+
+ int idx = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+
+ return _get_property_pinned_points(idx, what, r_ret);
+ }
+
+ return false;
+}
+
+void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ const int pinned_points_indices_size = pinned_points.size();
+
+ p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "pinned_points"));
+
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index"));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset"));
+ }
+}
+
+bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
+
+ const int p_indices_size = p_indices.size();
+
+ { // Remove the pined points on physics server that will be removed by resize
+ const PinnedPoint *r = pinned_points.ptr();
+ if (p_indices_size < pinned_points.size()) {
+ for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) {
+ pin_point(r[i].point_index, false);
+ }
+ }
+ }
+
+ pinned_points.resize(p_indices_size);
+
+ PinnedPoint *w = pinned_points.ptrw();
+ int point_index;
+ for (int i = 0; i < p_indices_size; ++i) {
+ point_index = p_indices.get(i);
+ if (w[i].point_index != point_index) {
+ if (-1 != w[i].point_index)
+ pin_point(w[i].point_index, false);
+ w[i].point_index = point_index;
+ pin_point(w[i].point_index, true);
+ }
+ }
+ return true;
+}
+
+bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
+ if (pinned_points.size() <= p_item) {
+ return false;
+ }
+
+ if ("spatial_attachment_path" == p_what) {
+ PinnedPoint *w = pinned_points.ptrw();
+ pin_point(w[p_item].point_index, true, p_value);
+ _make_cache_dirty();
+ } else if ("offset" == p_what) {
+ PinnedPoint *w = pinned_points.ptrw();
+ w[p_item].offset = p_value;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
+ if (pinned_points.size() <= p_item) {
+ return false;
+ }
+ const PinnedPoint *r = pinned_points.ptr();
+
+ if ("point_index" == p_what) {
+ r_ret = r[p_item].point_index;
+ } else if ("spatial_attachment_path" == p_what) {
+ r_ret = r[p_item].spatial_attachment_path;
+ } else if ("offset" == p_what) {
+ r_ret = r[p_item].offset;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void SoftBody3D::_changed_callback(Object *p_changed, const char *p_prop) {
+ prepare_physics_server();
+ _reset_points_offsets();
+#ifdef TOOLS_ENABLED
+ if (p_changed == this) {
+ update_configuration_warning();
+ }
+#endif
+}
+
+void SoftBody3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_WORLD: {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ add_change_receptor(this);
+ }
+
+ RID space = get_world()->get_space();
+ PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
+ prepare_physics_server();
+ } break;
+ case NOTIFICATION_READY: {
+ if (!parent_collision_ignore.is_empty())
+ add_collision_exception_with(get_node(parent_collision_ignore));
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ _reset_points_offsets();
+ return;
+ }
+
+ PhysicsServer3D::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform());
+
+ set_notify_transform(false);
+ // Required to be top level with Transform at center of world in order to modify RenderingServer only to support custom Transform
+ set_as_toplevel(true);
+ set_transform(Transform());
+ set_notify_transform(true);
+
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_pickable();
+
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID());
+
+ } break;
+ }
+
+#ifdef TOOLS_ENABLED
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warning();
+ }
+ }
+
+#endif
+}
+
+void SoftBody3D::_bind_methods() {
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody3D::get_collision_layer);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody3D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody3D::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody3D::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody3D::get_collision_layer_bit);
+
+ ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore);
+
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions);
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with);
+
+ ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody3D::set_simulation_precision);
+ ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody3D::get_simulation_precision);
+
+ ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody3D::set_total_mass);
+ ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody3D::get_total_mass);
+
+ 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);
+
+ ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody3D::set_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody3D::get_drag_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody3D::set_ray_pickable);
+ ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody3D::is_ray_pickable);
+
+ 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_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore");
+ 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();
+
+ if (get_mesh().is_null()) {
+ if (!warning.empty())
+ warning += "\n\n";
+
+ warning += 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.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.");
+ }
+
+ return warning;
+}
+
+void SoftBody3D::_update_physics_server() {
+ if (!simulation_started)
+ return;
+
+ _update_cache_pin_points_datas();
+ // Submit bone attachment
+ const int pinned_points_indices_size = pinned_points.size();
+ const PinnedPoint *r = pinned_points.ptr();
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ if (r[i].spatial_attachment) {
+ PhysicsServer3D::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset));
+ }
+ }
+}
+
+void SoftBody3D::_draw_soft_mesh() {
+ if (get_mesh().is_null())
+ return;
+
+ if (!rendering_server_handler.is_ready()) {
+
+ rendering_server_handler.prepare(get_mesh()->get_rid(), 0);
+
+ /// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
+ simulation_started = true;
+ call_deferred("set_as_toplevel", true);
+ call_deferred("set_transform", Transform());
+ }
+
+ _update_physics_server();
+
+ rendering_server_handler.open();
+ PhysicsServer3D::get_singleton()->soft_body_update_rendering_server(physics_rid, &rendering_server_handler);
+ rendering_server_handler.close();
+
+ rendering_server_handler.commit_changes();
+}
+
+void SoftBody3D::prepare_physics_server() {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ if (get_mesh().is_valid())
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ else
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
+
+ return;
+ }
+
+ if (get_mesh().is_valid()) {
+
+ become_mesh_owner();
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
+ } else {
+
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, nullptr);
+ if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh))) {
+ RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
+ }
+ }
+}
+
+void SoftBody3D::become_mesh_owner() {
+ if (mesh.is_null())
+ return;
+
+ if (!mesh_owner) {
+ mesh_owner = true;
+
+ Vector<Ref<Material>> copy_materials;
+ copy_materials.append_array(materials);
+
+ ERR_FAIL_COND(!mesh->get_surface_count());
+
+ // Get current mesh array and create new mesh array with necessary flag for softbody
+ Array surface_arrays = mesh->surface_get_arrays(0);
+ Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
+ Dictionary surface_lods = mesh->surface_get_lods(0);
+ uint32_t surface_format = mesh->surface_get_format(0);
+
+ surface_format &= ~(Mesh::ARRAY_COMPRESS_NORMAL);
+ surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
+
+ Ref<ArrayMesh> soft_mesh;
+ soft_mesh.instance();
+ soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format);
+ soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
+
+ set_mesh(soft_mesh);
+
+ for (int i = copy_materials.size() - 1; 0 <= i; --i) {
+ set_surface_material(i, copy_materials[i]);
+ }
+ }
+}
+
+void SoftBody3D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ PhysicsServer3D::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
+}
+
+uint32_t SoftBody3D::get_collision_mask() const {
+ return collision_mask;
+}
+void SoftBody3D::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ PhysicsServer3D::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
+}
+
+uint32_t SoftBody3D::get_collision_layer() const {
+ return collision_layer;
+}
+
+void SoftBody3D::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 SoftBody3D::get_collision_mask_bit(int p_bit) const {
+ return get_collision_mask() & (1 << p_bit);
+}
+
+void SoftBody3D::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 SoftBody3D::get_collision_layer_bit(int p_bit) const {
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+ parent_collision_ignore = p_parent_collision_ignore;
+}
+
+const NodePath &SoftBody3D::get_parent_collision_ignore() const {
+ return parent_collision_ignore;
+}
+
+void SoftBody3D::set_pinned_points_indices(Vector<SoftBody3D::PinnedPoint> p_pinned_points_indices) {
+ pinned_points = p_pinned_points_indices;
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+ pin_point(p_pinned_points_indices[i].point_index, true);
+ }
+}
+
+Vector<SoftBody3D::PinnedPoint> SoftBody3D::get_pinned_points_indices() {
+ return pinned_points;
+}
+
+Array SoftBody3D::get_collision_exceptions() {
+ List<RID> exceptions;
+ PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
+ Array ret;
+ for (List<RID>::Element *E = exceptions.front(); E; E = E->next()) {
+ RID body = E->get();
+ ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body);
+ Object *obj = ObjectDB::get_instance(instance_id);
+ PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj);
+ ret.append(physics_body);
+ }
+ return ret;
+}
+
+void SoftBody3D::add_collision_exception_with(Node *p_node) {
+ ERR_FAIL_NULL(p_node);
+ CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
+}
+
+void SoftBody3D::remove_collision_exception_with(Node *p_node) {
+ ERR_FAIL_NULL(p_node);
+ CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
+ ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
+ PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
+}
+
+int SoftBody3D::get_simulation_precision() {
+ return PhysicsServer3D::get_singleton()->soft_body_get_simulation_precision(physics_rid);
+}
+
+void SoftBody3D::set_simulation_precision(int p_simulation_precision) {
+ PhysicsServer3D::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
+}
+
+real_t SoftBody3D::get_total_mass() {
+ return PhysicsServer3D::get_singleton()->soft_body_get_total_mass(physics_rid);
+}
+
+void SoftBody3D::set_total_mass(real_t p_total_mass) {
+ PhysicsServer3D::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
+}
+
+void SoftBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
+ PhysicsServer3D::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
+}
+
+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);
+}
+
+real_t SoftBody3D::get_damping_coefficient() {
+ return PhysicsServer3D::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
+}
+
+void SoftBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
+ PhysicsServer3D::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
+}
+
+real_t SoftBody3D::get_drag_coefficient() {
+ return PhysicsServer3D::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
+}
+
+void SoftBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
+ PhysicsServer3D::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
+}
+
+Vector3 SoftBody3D::get_point_transform(int p_point_index) {
+ return PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
+}
+
+void SoftBody3D::pin_point_toggle(int p_point_index) {
+ pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
+}
+
+void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
+ _pin_point_on_physics_server(p_point_index, pin);
+ if (pin) {
+ _add_pinned_point(p_point_index, p_spatial_attachment_path);
+ } else {
+ _remove_pinned_point(p_point_index);
+ }
+}
+
+bool SoftBody3D::is_point_pinned(int p_point_index) const {
+ return -1 != _has_pinned_point(p_point_index);
+}
+
+void SoftBody3D::set_ray_pickable(bool p_ray_pickable) {
+
+ ray_pickable = p_ray_pickable;
+ _update_pickable();
+}
+
+bool SoftBody3D::is_ray_pickable() const {
+
+ return ray_pickable;
+}
+
+SoftBody3D::SoftBody3D() :
+ physics_rid(PhysicsServer3D::get_singleton()->soft_body_create()),
+ mesh_owner(false),
+ collision_mask(1),
+ collision_layer(1),
+ simulation_started(false),
+ pinned_points_cache_dirty(true),
+ ray_pickable(true) {
+
+ PhysicsServer3D::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
+}
+
+SoftBody3D::~SoftBody3D() {
+ PhysicsServer3D::get_singleton()->free(physics_rid);
+}
+
+void SoftBody3D::reset_softbody_pin() {
+ PhysicsServer3D::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
+ const PinnedPoint *pps = pinned_points.ptr();
+ for (int i = pinned_points.size() - 1; 0 < i; --i) {
+ PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
+ }
+}
+
+void SoftBody3D::_make_cache_dirty() {
+ pinned_points_cache_dirty = true;
+}
+
+void SoftBody3D::_update_cache_pin_points_datas() {
+ if (!pinned_points_cache_dirty)
+ return;
+
+ pinned_points_cache_dirty = false;
+
+ PinnedPoint *w = pinned_points.ptrw();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+
+ if (!w[i].spatial_attachment_path.is_empty()) {
+ w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
+ }
+ if (!w[i].spatial_attachment) {
+ ERR_PRINT("Node3D node not defined in the pinned point, Softbody undefined behaviour!");
+ }
+ }
+}
+
+void SoftBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
+ PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
+}
+
+void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
+ SoftBody3D::PinnedPoint *pinned_point;
+ if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
+
+ // Create new
+ PinnedPoint pp;
+ pp.point_index = p_point_index;
+ pp.spatial_attachment_path = p_spatial_attachment_path;
+
+ if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
+ pp.spatial_attachment = Object::cast_to<Node3D>(get_node(p_spatial_attachment_path));
+ pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index));
+ }
+
+ pinned_points.push_back(pp);
+
+ } else {
+
+ pinned_point->point_index = p_point_index;
+ pinned_point->spatial_attachment_path = p_spatial_attachment_path;
+
+ if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
+ pinned_point->spatial_attachment = Object::cast_to<Node3D>(get_node(p_spatial_attachment_path));
+ pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index));
+ }
+ }
+}
+
+void SoftBody3D::_reset_points_offsets() {
+
+ if (!Engine::get_singleton()->is_editor_hint())
+ return;
+
+ const PinnedPoint *r = pinned_points.ptr();
+ 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)
+ continue;
+
+ w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index));
+ }
+}
+
+void SoftBody3D::_remove_pinned_point(int p_point_index) {
+ const int id(_has_pinned_point(p_point_index));
+ if (-1 != id) {
+ pinned_points.remove(id);
+ }
+}
+
+int SoftBody3D::_get_pinned_point(int p_point_index, SoftBody3D::PinnedPoint *&r_point) const {
+ const int id = _has_pinned_point(p_point_index);
+ if (-1 == id) {
+ r_point = nullptr;
+ return -1;
+ } else {
+ r_point = const_cast<SoftBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
+ return id;
+ }
+}
+
+int SoftBody3D::_has_pinned_point(int p_point_index) const {
+ const PinnedPoint *r = pinned_points.ptr();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+ if (p_point_index == r[i].point_index) {
+ return i;
+ }
+ }
+ return -1;
+}
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
new file mode 100644
index 0000000000..7dd5880985
--- /dev/null
+++ b/scene/3d/soft_body_3d.h
@@ -0,0 +1,202 @@
+/*************************************************************************/
+/* soft_body_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_PHYSICS_BODY_H
+#define SOFT_PHYSICS_BODY_H
+
+#include "scene/3d/mesh_instance_3d.h"
+
+class SoftBody3D;
+
+class SoftBodyRenderingServerHandler {
+
+ friend class SoftBody3D;
+
+ RID mesh;
+ int surface;
+ Vector<uint8_t> buffer;
+ uint32_t stride;
+ uint32_t offset_vertices;
+ uint32_t offset_normal;
+
+ uint8_t *write_buffer;
+
+private:
+ SoftBodyRenderingServerHandler();
+ bool is_ready() { return mesh.is_valid(); }
+ void prepare(RID p_mesh_rid, int p_surface);
+ void clear();
+ void open();
+ void close();
+ 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);
+};
+
+class SoftBody3D : public MeshInstance3D {
+ GDCLASS(SoftBody3D, MeshInstance3D);
+
+public:
+ struct PinnedPoint {
+ int point_index;
+ NodePath spatial_attachment_path;
+ Node3D *spatial_attachment; // Cache
+ Vector3 offset;
+
+ PinnedPoint();
+ PinnedPoint(const PinnedPoint &obj_tocopy);
+ PinnedPoint operator=(const PinnedPoint &obj);
+ };
+
+private:
+ SoftBodyRenderingServerHandler rendering_server_handler;
+
+ RID physics_rid;
+
+ bool mesh_owner;
+ uint32_t collision_mask;
+ uint32_t collision_layer;
+ NodePath parent_collision_ignore;
+ Vector<PinnedPoint> pinned_points;
+ bool simulation_started;
+ bool pinned_points_cache_dirty;
+
+ Ref<ArrayMesh> debug_mesh_cache;
+ class MeshInstance3D *debug_mesh;
+
+ bool capture_input_on_drag;
+ bool ray_pickable;
+
+ void _update_pickable();
+
+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;
+
+ bool _set_property_pinned_points_indices(const Array &p_indices);
+ 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);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ virtual String get_configuration_warning() const;
+
+protected:
+ void _update_physics_server();
+ void _draw_soft_mesh();
+
+public:
+ void prepare_physics_server();
+ void become_mesh_owner();
+
+ 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;
+
+ void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
+ const NodePath &get_parent_collision_ignore() const;
+
+ void set_pinned_points_indices(Vector<PinnedPoint> p_pinned_points_indices);
+ Vector<PinnedPoint> get_pinned_points_indices();
+
+ void set_simulation_precision(int p_simulation_precision);
+ int get_simulation_precision();
+
+ void set_total_mass(real_t p_total_mass);
+ real_t get_total_mass();
+
+ 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();
+
+ void set_drag_coefficient(real_t p_drag_coefficient);
+ real_t get_drag_coefficient();
+
+ Array get_collision_exceptions();
+ void add_collision_exception_with(Node *p_node);
+ void remove_collision_exception_with(Node *p_node);
+
+ Vector3 get_point_transform(int p_point_index);
+
+ void pin_point_toggle(int p_point_index);
+ void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
+ bool is_point_pinned(int p_point_index) const;
+
+ void set_ray_pickable(bool p_ray_pickable);
+ bool is_ray_pickable() const;
+
+ SoftBody3D();
+ ~SoftBody3D();
+
+private:
+ void reset_softbody_pin();
+
+ void _make_cache_dirty();
+ void _update_cache_pin_points_datas();
+
+ void _pin_point_on_physics_server(int p_point_index, bool pin);
+ void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path);
+ void _reset_points_offsets();
+
+ void _remove_pinned_point(int p_point_index);
+ int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const;
+ int _has_pinned_point(int p_point_index) const;
+};
+
+#endif // SOFT_PHYSICS_BODY_H
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
deleted file mode 100644
index f1911348ce..0000000000
--- a/scene/3d/spatial.cpp
+++ /dev/null
@@ -1,848 +0,0 @@
-/*************************************************************************/
-/* spatial.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "spatial.h"
-
-#include "core/engine.h"
-#include "core/message_queue.h"
-#include "scene/main/scene_tree.h"
-#include "scene/main/viewport.h"
-#include "scene/scene_string_names.h"
-
-/*
-
- possible algorithms:
-
- Algorithm 1: (current)
-
- definition of invalidation: global is invalid
-
- 1) If a node sets a LOCAL, it produces an invalidation of everything above
- 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
-
----
-
- Algorithm 2: (no longer current)
-
- definition of invalidation: NONE dirty, LOCAL dirty, GLOBAL dirty
-
- 1) If a node sets a LOCAL, it must climb the tree and set it as GLOBAL dirty
- a) marking GLOBALs as dirty up all the tree must be done always
- 2) If a node sets a GLOBAL, it marks local as dirty, and that's all?
-
- //is clearing the dirty state correct in this case?
-
- drawback: setting a local down the tree forces many tree walks often
-
---
-
-future: no idea
-
- */
-
-SpatialGizmo::SpatialGizmo() {
-}
-
-void Spatial::_notify_dirty() {
-
-#ifdef TOOLS_ENABLED
- if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
-#else
- if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
-
-#endif
- get_tree()->xform_change_list.add(&xform_change);
- }
-}
-
-void Spatial::_update_local_transform() const {
- data.local_transform.basis.set_euler_scale(data.rotation, data.scale);
-
- data.dirty &= ~DIRTY_LOCAL;
-}
-void Spatial::_propagate_transform_changed(Spatial *p_origin) {
-
- if (!is_inside_tree()) {
- return;
- }
-
- /*
- if (data.dirty&DIRTY_GLOBAL)
- return; //already dirty
- */
-
- data.children_lock++;
-
- for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
-
- if (E->get()->data.toplevel_active)
- continue; //don't propagate to a toplevel
- E->get()->_propagate_transform_changed(p_origin);
- }
-#ifdef TOOLS_ENABLED
- if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
-#else
- if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
-#endif
- get_tree()->xform_change_list.add(&xform_change);
- }
- data.dirty |= DIRTY_GLOBAL;
-
- data.children_lock--;
-}
-
-void Spatial::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- ERR_FAIL_COND(!get_tree());
-
- Node *p = get_parent();
- if (p)
- data.parent = Object::cast_to<Spatial>(p);
-
- if (data.parent)
- data.C = data.parent->data.children.push_back(this);
- else
- data.C = NULL;
-
- if (data.toplevel && !Engine::get_singleton()->is_editor_hint()) {
-
- if (data.parent) {
- data.local_transform = data.parent->get_global_transform() * get_transform();
- data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene
- }
- data.toplevel_active = true;
- }
-
- data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene
- _notify_dirty();
-
- notification(NOTIFICATION_ENTER_WORLD);
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
-
- notification(NOTIFICATION_EXIT_WORLD, true);
- if (xform_change.in_list())
- get_tree()->xform_change_list.remove(&xform_change);
- if (data.C)
- data.parent->data.children.erase(data.C);
- data.parent = NULL;
- data.C = NULL;
- data.toplevel_active = false;
- } break;
- case NOTIFICATION_ENTER_WORLD: {
-
- data.inside_world = true;
- data.viewport = NULL;
- Node *parent = get_parent();
- while (parent && !data.viewport) {
- data.viewport = Object::cast_to<Viewport>(parent);
- parent = parent->get_parent();
- }
-
- ERR_FAIL_COND(!data.viewport);
-
- if (get_script_instance()) {
-
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, NULL, 0);
- }
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
-
- //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
- get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
- if (!data.gizmo_disabled) {
-
- if (data.gizmo.is_valid()) {
- data.gizmo->create();
- if (is_visible_in_tree()) {
- data.gizmo->redraw();
- }
- data.gizmo->transform();
- }
- }
- }
-#endif
-
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
-#ifdef TOOLS_ENABLED
- if (data.gizmo.is_valid()) {
- data.gizmo->free();
- data.gizmo.unref();
- }
-#endif
-
- if (get_script_instance()) {
-
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, NULL, 0);
- }
-
- data.viewport = NULL;
- data.inside_world = false;
-
- } break;
-
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
-#ifdef TOOLS_ENABLED
- if (data.gizmo.is_valid()) {
- data.gizmo->transform();
- }
-#endif
- } break;
-
- default: {
- }
- }
-}
-
-void Spatial::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);
- }
-}
-
-void Spatial::set_global_transform(const Transform &p_transform) {
-
- Transform xform =
- (data.parent && !data.toplevel_active) ?
- data.parent->get_global_transform().affine_inverse() * p_transform :
- p_transform;
-
- set_transform(xform);
-}
-
-Transform Spatial::get_transform() const {
-
- if (data.dirty & DIRTY_LOCAL) {
-
- _update_local_transform();
- }
-
- return data.local_transform;
-}
-Transform Spatial::get_global_transform() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), Transform());
-
- if (data.dirty & DIRTY_GLOBAL) {
-
- if (data.dirty & DIRTY_LOCAL) {
-
- _update_local_transform();
- }
-
- if (data.parent && !data.toplevel_active) {
-
- data.global_transform = data.parent->get_global_transform() * data.local_transform;
- } else {
-
- data.global_transform = data.local_transform;
- }
-
- if (data.disable_scale) {
- data.global_transform.basis.orthonormalize();
- }
-
- data.dirty &= ~DIRTY_GLOBAL;
- }
-
- return data.global_transform;
-}
-
-#ifdef TOOLS_ENABLED
-Transform Spatial::get_global_gizmo_transform() const {
- return get_global_transform();
-}
-
-Transform Spatial::get_local_gizmo_transform() const {
- return get_transform();
-}
-#endif
-
-Spatial *Spatial::get_parent_spatial() const {
-
- return data.parent;
-}
-
-Transform Spatial::get_relative_transform(const Node *p_parent) const {
-
- if (p_parent == this)
- return Transform();
-
- ERR_FAIL_COND_V(!data.parent, Transform());
-
- if (p_parent == data.parent)
- return get_transform();
- else
- return data.parent->get_relative_transform(p_parent) * get_transform();
-}
-
-void Spatial::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);
- }
-}
-
-void Spatial::set_rotation(const Vector3 &p_euler_rad) {
-
- if (data.dirty & DIRTY_VECTORS) {
- data.scale = data.local_transform.basis.get_scale();
- data.dirty &= ~DIRTY_VECTORS;
- }
-
- 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);
- }
-}
-
-void Spatial::set_rotation_degrees(const Vector3 &p_euler_deg) {
-
- set_rotation(p_euler_deg * Math_PI / 180.0);
-}
-
-void Spatial::set_scale(const Vector3 &p_scale) {
-
- if (data.dirty & DIRTY_VECTORS) {
- data.rotation = data.local_transform.basis.get_rotation();
- data.dirty &= ~DIRTY_VECTORS;
- }
-
- 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);
- }
-}
-
-Vector3 Spatial::get_translation() const {
-
- return data.local_transform.origin;
-}
-
-Vector3 Spatial::get_rotation() const {
-
- if (data.dirty & DIRTY_VECTORS) {
- data.scale = data.local_transform.basis.get_scale();
- data.rotation = data.local_transform.basis.get_rotation();
-
- data.dirty &= ~DIRTY_VECTORS;
- }
-
- return data.rotation;
-}
-
-Vector3 Spatial::get_rotation_degrees() const {
-
- return get_rotation() * 180.0 / Math_PI;
-}
-
-Vector3 Spatial::get_scale() const {
-
- if (data.dirty & DIRTY_VECTORS) {
- data.scale = data.local_transform.basis.get_scale();
- data.rotation = data.local_transform.basis.get_rotation();
-
- data.dirty &= ~DIRTY_VECTORS;
- }
-
- return data.scale;
-}
-
-void Spatial::update_gizmo() {
-
-#ifdef TOOLS_ENABLED
- if (!is_inside_world())
- return;
- if (!data.gizmo.is_valid())
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
- if (!data.gizmo.is_valid())
- return;
- if (data.gizmo_dirty)
- return;
- data.gizmo_dirty = true;
- MessageQueue::get_singleton()->push_call(this, "_update_gizmo");
-#endif
-}
-
-void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {
-
-#ifdef TOOLS_ENABLED
-
- if (data.gizmo_disabled)
- return;
- if (data.gizmo.is_valid() && is_inside_world())
- data.gizmo->free();
- data.gizmo = p_gizmo;
- if (data.gizmo.is_valid() && is_inside_world()) {
-
- data.gizmo->create();
- if (is_visible_in_tree()) {
- data.gizmo->redraw();
- }
- data.gizmo->transform();
- }
-
-#endif
-}
-
-Ref<SpatialGizmo> Spatial::get_gizmo() const {
-
-#ifdef TOOLS_ENABLED
-
- return data.gizmo;
-#else
-
- return Ref<SpatialGizmo>();
-#endif
-}
-
-void Spatial::_update_gizmo() {
-
-#ifdef TOOLS_ENABLED
- if (!is_inside_world())
- return;
- data.gizmo_dirty = false;
- if (data.gizmo.is_valid()) {
- if (is_visible_in_tree())
- data.gizmo->redraw();
- else
- data.gizmo->clear();
- }
-#endif
-}
-
-#ifdef TOOLS_ENABLED
-void Spatial::set_disable_gizmo(bool p_enabled) {
-
- data.gizmo_disabled = p_enabled;
- if (!p_enabled && data.gizmo.is_valid())
- data.gizmo = Ref<SpatialGizmo>();
-}
-
-#endif
-
-void Spatial::set_disable_scale(bool p_enabled) {
-
- data.disable_scale = p_enabled;
-}
-
-bool Spatial::is_scale_disabled() const {
- return data.disable_scale;
-}
-
-void Spatial::set_as_toplevel(bool p_enabled) {
-
- if (data.toplevel == p_enabled)
- return;
- if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
-
- if (p_enabled)
- set_transform(get_global_transform());
- else if (data.parent)
- set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform());
-
- data.toplevel = p_enabled;
- data.toplevel_active = p_enabled;
-
- } else {
- data.toplevel = p_enabled;
- }
-}
-
-bool Spatial::is_set_as_toplevel() const {
-
- return data.toplevel;
-}
-
-Ref<World> Spatial::get_world() const {
-
- ERR_FAIL_COND_V(!is_inside_world(), Ref<World>());
- ERR_FAIL_COND_V(!data.viewport, Ref<World>());
-
- return data.viewport->find_world();
-}
-
-void Spatial::_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();
-#endif
-
- for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
-
- Spatial *c = E->get();
- if (!c || !c->data.visible)
- continue;
- c->_propagate_visibility_changed();
- }
-}
-
-void Spatial::show() {
-
- if (data.visible)
- return;
-
- data.visible = true;
-
- if (!is_inside_tree())
- return;
-
- _propagate_visibility_changed();
-}
-
-void Spatial::hide() {
-
- if (!data.visible)
- return;
-
- data.visible = false;
-
- if (!is_inside_tree())
- return;
-
- _propagate_visibility_changed();
-}
-
-bool Spatial::is_visible_in_tree() const {
-
- const Spatial *s = this;
-
- while (s) {
- if (!s->data.visible) {
- return false;
- }
- s = s->data.parent;
- }
-
- return true;
-}
-
-void Spatial::set_visible(bool p_visible) {
-
- if (p_visible)
- show();
- else
- hide();
-}
-
-bool Spatial::is_visible() const {
-
- return data.visible;
-}
-
-void Spatial::rotate_object_local(const Vector3 &p_axis, float p_angle) {
- Transform t = get_transform();
- t.basis.rotate_local(p_axis, p_angle);
- set_transform(t);
-}
-
-void Spatial::rotate(const Vector3 &p_axis, float p_angle) {
-
- Transform t = get_transform();
- t.basis.rotate(p_axis, p_angle);
- set_transform(t);
-}
-
-void Spatial::rotate_x(float p_angle) {
-
- Transform t = get_transform();
- t.basis.rotate(Vector3(1, 0, 0), p_angle);
- set_transform(t);
-}
-
-void Spatial::rotate_y(float p_angle) {
-
- Transform t = get_transform();
- t.basis.rotate(Vector3(0, 1, 0), p_angle);
- set_transform(t);
-}
-void Spatial::rotate_z(float p_angle) {
-
- Transform t = get_transform();
- t.basis.rotate(Vector3(0, 0, 1), p_angle);
- set_transform(t);
-}
-
-void Spatial::translate(const Vector3 &p_offset) {
-
- Transform t = get_transform();
- t.translate(p_offset);
- set_transform(t);
-}
-
-void Spatial::translate_object_local(const Vector3 &p_offset) {
- Transform t = get_transform();
-
- Transform s;
- s.translate(p_offset);
- set_transform(t * s);
-}
-
-void Spatial::scale(const Vector3 &p_ratio) {
-
- Transform t = get_transform();
- t.basis.scale(p_ratio);
- set_transform(t);
-}
-
-void Spatial::scale_object_local(const Vector3 &p_scale) {
- Transform t = get_transform();
- t.basis.scale_local(p_scale);
- set_transform(t);
-}
-
-void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) {
-
- Transform t = get_global_transform();
- t.basis.rotate(p_axis, p_angle);
- set_global_transform(t);
-}
-
-void Spatial::global_scale(const Vector3 &p_scale) {
-
- Transform t = get_global_transform();
- t.basis.scale(p_scale);
- set_global_transform(t);
-}
-
-void Spatial::global_translate(const Vector3 &p_offset) {
- Transform t = get_global_transform();
- t.origin += p_offset;
- set_global_transform(t);
-}
-
-void Spatial::orthonormalize() {
-
- Transform t = get_transform();
- t.orthonormalize();
- set_transform(t);
-}
-
-void Spatial::set_identity() {
-
- set_transform(Transform());
-}
-
-void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) {
-
- Vector3 origin(get_global_transform().origin);
- look_at_from_position(origin, p_target, p_up);
-}
-
-void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
-
- ERR_FAIL_COND_MSG(p_pos == p_target, "Node origin and target are in the same position, look_at() failed.");
- ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos) == Vector3(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
-
- Transform lookat;
- lookat.origin = p_pos;
-
- Vector3 original_scale(get_scale());
- lookat = lookat.looking_at(p_target, p_up);
- set_global_transform(lookat);
- set_scale(original_scale);
-}
-
-Vector3 Spatial::to_local(Vector3 p_global) const {
-
- return get_global_transform().affine_inverse().xform(p_global);
-}
-
-Vector3 Spatial::to_global(Vector3 p_local) const {
-
- return get_global_transform().xform(p_local);
-}
-
-void Spatial::set_notify_transform(bool p_enable) {
- data.notify_transform = p_enable;
-}
-
-bool Spatial::is_transform_notification_enabled() const {
- return data.notify_transform;
-}
-
-void Spatial::set_notify_local_transform(bool p_enable) {
- data.notify_local_transform = p_enable;
-}
-
-bool Spatial::is_local_transform_notification_enabled() const {
- return data.notify_local_transform;
-}
-
-void Spatial::force_update_transform() {
- ERR_FAIL_COND(!is_inside_tree());
- if (!xform_change.in_list()) {
- return; //nothing to update
- }
- get_tree()->xform_change_list.remove(&xform_change);
-
- notification(NOTIFICATION_TRANSFORM_CHANGED);
-}
-
-void Spatial::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_transform", "local"), &Spatial::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &Spatial::get_transform);
- ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Spatial::set_translation);
- ClassDB::bind_method(D_METHOD("get_translation"), &Spatial::get_translation);
- ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Spatial::set_rotation);
- ClassDB::bind_method(D_METHOD("get_rotation"), &Spatial::get_rotation);
- ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Spatial::set_rotation_degrees);
- ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Spatial::get_rotation_degrees);
- ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Spatial::set_scale);
- ClassDB::bind_method(D_METHOD("get_scale"), &Spatial::get_scale);
- ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Spatial::set_global_transform);
- ClassDB::bind_method(D_METHOD("get_global_transform"), &Spatial::get_global_transform);
- ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Spatial::get_parent_spatial);
- ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification);
- ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel);
- ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
- ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Spatial::set_disable_scale);
- ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Spatial::is_scale_disabled);
- ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world);
-
- ClassDB::bind_method(D_METHOD("force_update_transform"), &Spatial::force_update_transform);
-
- ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
-
- ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo);
- ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Spatial::set_gizmo);
- ClassDB::bind_method(D_METHOD("get_gizmo"), &Spatial::get_gizmo);
-
- ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Spatial::set_visible);
- ClassDB::bind_method(D_METHOD("is_visible"), &Spatial::is_visible);
- ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &Spatial::is_visible_in_tree);
- ClassDB::bind_method(D_METHOD("show"), &Spatial::show);
- ClassDB::bind_method(D_METHOD("hide"), &Spatial::hide);
-
- ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &Spatial::set_notify_local_transform);
- ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &Spatial::is_local_transform_notification_enabled);
-
- ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Spatial::set_notify_transform);
- ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Spatial::is_transform_notification_enabled);
-
- ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Spatial::rotate);
- ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Spatial::global_rotate);
- ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Spatial::global_scale);
- ClassDB::bind_method(D_METHOD("global_translate", "offset"), &Spatial::global_translate);
- ClassDB::bind_method(D_METHOD("rotate_object_local", "axis", "angle"), &Spatial::rotate_object_local);
- ClassDB::bind_method(D_METHOD("scale_object_local", "scale"), &Spatial::scale_object_local);
- ClassDB::bind_method(D_METHOD("translate_object_local", "offset"), &Spatial::translate_object_local);
- ClassDB::bind_method(D_METHOD("rotate_x", "angle"), &Spatial::rotate_x);
- ClassDB::bind_method(D_METHOD("rotate_y", "angle"), &Spatial::rotate_y);
- ClassDB::bind_method(D_METHOD("rotate_z", "angle"), &Spatial::rotate_z);
- ClassDB::bind_method(D_METHOD("translate", "offset"), &Spatial::translate);
- ClassDB::bind_method(D_METHOD("orthonormalize"), &Spatial::orthonormalize);
- ClassDB::bind_method(D_METHOD("set_identity"), &Spatial::set_identity);
-
- ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Spatial::look_at);
- ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Spatial::look_at_from_position);
-
- ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Spatial::to_local);
- ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Spatial::to_global);
-
- BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
- BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
- BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
- BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
-
- //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
- ADD_GROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
- ADD_GROUP("Matrix", "");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
- ADD_GROUP("Visibility", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
-
- ADD_SIGNAL(MethodInfo("visibility_changed"));
-}
-
-Spatial::Spatial() :
- xform_change(this) {
-
- data.dirty = DIRTY_NONE;
- data.children_lock = 0;
-
- data.ignore_notification = false;
- data.toplevel = false;
- data.toplevel_active = false;
- data.scale = Vector3(1, 1, 1);
- data.viewport = NULL;
- data.inside_world = false;
- data.visible = true;
- data.disable_scale = false;
-
-#ifdef TOOLS_ENABLED
- data.gizmo_disabled = false;
- data.gizmo_dirty = false;
-#endif
- data.notify_local_transform = false;
- data.notify_transform = false;
- data.parent = NULL;
- data.C = NULL;
-}
-
-Spatial::~Spatial() {
-}
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
deleted file mode 100644
index 9d4705700b..0000000000
--- a/scene/3d/spatial.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*************************************************************************/
-/* spatial.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPATIAL_H
-#define SPATIAL_H
-
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-
-class SpatialGizmo : public Reference {
-
- GDCLASS(SpatialGizmo, Reference);
-
-public:
- virtual void create() = 0;
- virtual void transform() = 0;
- virtual void clear() = 0;
- virtual void redraw() = 0;
- virtual void free() = 0;
-
- SpatialGizmo();
- virtual ~SpatialGizmo() {}
-};
-
-class Spatial : public Node {
-
- GDCLASS(Spatial, Node);
- OBJ_CATEGORY("3D");
-
- enum TransformDirty {
- DIRTY_NONE = 0,
- DIRTY_VECTORS = 1,
- DIRTY_LOCAL = 2,
- DIRTY_GLOBAL = 4
- };
-
- mutable SelfList<Node> xform_change;
-
- struct Data {
-
- mutable Transform global_transform;
- mutable Transform local_transform;
- mutable Vector3 rotation;
- mutable Vector3 scale;
-
- mutable int dirty;
-
- Viewport *viewport;
-
- bool toplevel_active;
- bool toplevel;
- bool inside_world;
-
- int children_lock;
- Spatial *parent;
- List<Spatial *> children;
- List<Spatial *>::Element *C;
-
- bool ignore_notification;
- bool notify_local_transform;
- bool notify_transform;
-
- bool visible;
- bool disable_scale;
-
-#ifdef TOOLS_ENABLED
- Ref<SpatialGizmo> gizmo;
- bool gizmo_disabled;
- bool gizmo_dirty;
-#endif
-
- } data;
-
- void _update_gizmo();
- void _notify_dirty();
- void _propagate_transform_changed(Spatial *p_origin);
-
- void _propagate_visibility_changed();
-
-protected:
- _FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }
-
- _FORCE_INLINE_ void _update_local_transform() const;
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- enum {
-
- NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED,
- NOTIFICATION_ENTER_WORLD = 41,
- NOTIFICATION_EXIT_WORLD = 42,
- NOTIFICATION_VISIBILITY_CHANGED = 43,
- NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 44,
- };
-
- Spatial *get_parent_spatial() const;
-
- Ref<World> get_world() const;
-
- void set_translation(const Vector3 &p_translation);
- void set_rotation(const Vector3 &p_euler_rad);
- void set_rotation_degrees(const Vector3 &p_euler_deg);
- void set_scale(const Vector3 &p_scale);
-
- Vector3 get_translation() const;
- Vector3 get_rotation() const;
- Vector3 get_rotation_degrees() const;
- Vector3 get_scale() const;
-
- void set_transform(const Transform &p_transform);
- void set_global_transform(const Transform &p_transform);
-
- Transform get_transform() const;
- Transform get_global_transform() const;
-
-#ifdef TOOLS_ENABLED
- virtual Transform get_global_gizmo_transform() const;
- virtual Transform get_local_gizmo_transform() const;
-#endif
-
- void set_as_toplevel(bool p_enabled);
- bool is_set_as_toplevel() const;
-
- void set_disable_scale(bool p_enabled);
- bool is_scale_disabled() const;
-
- void set_disable_gizmo(bool p_enabled);
- void update_gizmo();
- void set_gizmo(const Ref<SpatialGizmo> &p_gizmo);
- Ref<SpatialGizmo> get_gizmo() const;
-
- _FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; }
-
- Transform get_relative_transform(const Node *p_parent) const;
-
- void rotate(const Vector3 &p_axis, float p_angle);
- void rotate_x(float p_angle);
- void rotate_y(float p_angle);
- void rotate_z(float p_angle);
- void translate(const Vector3 &p_offset);
- void scale(const Vector3 &p_ratio);
-
- void rotate_object_local(const Vector3 &p_axis, float p_angle);
- void scale_object_local(const Vector3 &p_scale);
- void translate_object_local(const Vector3 &p_offset);
-
- void global_rotate(const Vector3 &p_axis, float p_angle);
- 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);
-
- Vector3 to_local(Vector3 p_global) const;
- Vector3 to_global(Vector3 p_local) const;
-
- void set_notify_transform(bool p_enable);
- bool is_transform_notification_enabled() const;
-
- void set_notify_local_transform(bool p_enable);
- bool is_local_transform_notification_enabled() const;
-
- void orthonormalize();
- void set_identity();
-
- void set_visible(bool p_visible);
- bool is_visible() const;
- void show();
- void hide();
- bool is_visible_in_tree() const;
-
- void force_update_transform();
-
- Spatial();
- ~Spatial();
-};
-
-#endif
diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp
deleted file mode 100644
index ec1bb1f991..0000000000
--- a/scene/3d/spatial_velocity_tracker.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*************************************************************************/
-/* spatial_velocity_tracker.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "spatial_velocity_tracker.h"
-#include "core/engine.h"
-
-void SpatialVelocityTracker::set_track_physics_step(bool p_track_physics_step) {
-
- physics_step = p_track_physics_step;
-}
-
-bool SpatialVelocityTracker::is_tracking_physics_step() const {
-
- return physics_step;
-}
-void SpatialVelocityTracker::update_position(const Vector3 &p_position) {
-
- PositionHistory ph;
- ph.position = p_position;
- if (physics_step) {
- ph.frame = Engine::get_singleton()->get_physics_frames();
- } else {
- ph.frame = Engine::get_singleton()->get_idle_frame_ticks();
- }
-
- if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest
- position_history_len = MIN(position_history.size(), position_history_len + 1);
- for (int i = position_history_len - 1; i > 0; i--) {
- position_history.write[i] = position_history[i - 1];
- }
- }
-
- position_history.write[0] = ph;
-}
-Vector3 SpatialVelocityTracker::get_tracked_linear_velocity() const {
-
- Vector3 linear_velocity;
-
- float max_time = 1 / 5.0; //maximum time to interpolate a velocity
-
- Vector3 distance_accum;
- float time_accum = 0.0;
- float base_time = 0.0;
-
- if (position_history_len) {
- if (physics_step) {
- uint64_t base = Engine::get_singleton()->get_physics_frames();
- base_time = float(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second();
- } else {
- uint64_t base = Engine::get_singleton()->get_idle_frame_ticks();
- base_time = double(base - position_history[0].frame) / 1000000.0;
- }
- }
-
- for (int i = 0; i < position_history_len - 1; i++) {
- float delta = 0.0;
- uint64_t diff = position_history[i].frame - position_history[i + 1].frame;
- Vector3 distance = position_history[i].position - position_history[i + 1].position;
-
- if (physics_step) {
- delta = float(diff) / Engine::get_singleton()->get_iterations_per_second();
- } else {
- delta = double(diff) / 1000000.0;
- }
-
- if (base_time + time_accum + delta > max_time)
- break;
-
- distance_accum += distance;
- time_accum += delta;
- }
-
- if (time_accum) {
- linear_velocity = distance_accum / time_accum;
- }
-
- return linear_velocity;
-}
-
-void SpatialVelocityTracker::reset(const Vector3 &p_new_pos) {
-
- PositionHistory ph;
- ph.position = p_new_pos;
- if (physics_step) {
- ph.frame = Engine::get_singleton()->get_physics_frames();
- } else {
- ph.frame = Engine::get_singleton()->get_idle_frame_ticks();
- }
-
- position_history.write[0] = ph;
- position_history_len = 1;
-}
-
-void SpatialVelocityTracker::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_track_physics_step", "enable"), &SpatialVelocityTracker::set_track_physics_step);
- ClassDB::bind_method(D_METHOD("is_tracking_physics_step"), &SpatialVelocityTracker::is_tracking_physics_step);
- ClassDB::bind_method(D_METHOD("update_position", "position"), &SpatialVelocityTracker::update_position);
- ClassDB::bind_method(D_METHOD("get_tracked_linear_velocity"), &SpatialVelocityTracker::get_tracked_linear_velocity);
- ClassDB::bind_method(D_METHOD("reset", "position"), &SpatialVelocityTracker::reset);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "track_physics_step"), "set_track_physics_step", "is_tracking_physics_step");
-}
-
-SpatialVelocityTracker::SpatialVelocityTracker() {
- position_history.resize(4); // should be configurable
- position_history_len = 0;
- physics_step = false;
-}
diff --git a/scene/3d/spatial_velocity_tracker.h b/scene/3d/spatial_velocity_tracker.h
deleted file mode 100644
index 92b527b93c..0000000000
--- a/scene/3d/spatial_velocity_tracker.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*************************************************************************/
-/* spatial_velocity_tracker.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPATIAL_VELOCITY_TRACKER_H
-#define SPATIAL_VELOCITY_TRACKER_H
-
-#include "scene/3d/spatial.h"
-
-class SpatialVelocityTracker : public Reference {
- GDCLASS(SpatialVelocityTracker, Reference);
-
- struct PositionHistory {
- uint64_t frame;
- Vector3 position;
- };
-
- bool physics_step;
- Vector<PositionHistory> position_history;
- int position_history_len;
-
-protected:
- static void _bind_methods();
-
-public:
- void reset(const Vector3 &p_new_pos);
- void set_track_physics_step(bool p_track_physics_step);
- bool is_tracking_physics_step() const;
- void update_position(const Vector3 &p_position);
- Vector3 get_tracked_linear_velocity() const;
-
- SpatialVelocityTracker();
-};
-
-#endif // SPATIAL_VELOCITY_TRACKER_H
diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp
deleted file mode 100644
index ce277dae5b..0000000000
--- a/scene/3d/spring_arm.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*************************************************************************/
-/* spring_arm.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "spring_arm.h"
-#include "core/engine.h"
-#include "scene/3d/collision_object.h"
-#include "scene/resources/sphere_shape.h"
-#include "servers/physics_server.h"
-
-SpringArm::SpringArm() :
- spring_length(1),
- current_spring_length(0),
- keep_child_basis(false),
- mask(1),
- margin(0.01) {}
-
-void SpringArm::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- if (!Engine::get_singleton()->is_editor_hint()) {
- set_process_internal(true);
- }
- break;
- case NOTIFICATION_EXIT_TREE:
- if (!Engine::get_singleton()->is_editor_hint()) {
- set_process_internal(false);
- }
- break;
- case NOTIFICATION_INTERNAL_PROCESS:
- process_spring();
- break;
- }
-}
-
-void SpringArm::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm::get_hit_length);
-
- ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm::set_length);
- ClassDB::bind_method(D_METHOD("get_length"), &SpringArm::get_length);
-
- ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm::set_shape);
- ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm::get_shape);
-
- ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm::add_excluded_object);
- ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm::remove_excluded_object);
- ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm::clear_excluded_objects);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm::set_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm::get_mask);
-
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm::get_margin);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spring_length"), "set_length", "get_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin");
-}
-
-float SpringArm::get_length() const {
- return spring_length;
-}
-
-void SpringArm::set_length(float p_length) {
- if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint()))
- update_gizmo();
-
- spring_length = p_length;
-}
-
-void SpringArm::set_shape(Ref<Shape> p_shape) {
- shape = p_shape;
-}
-
-Ref<Shape> SpringArm::get_shape() const {
- return shape;
-}
-
-void SpringArm::set_mask(uint32_t p_mask) {
- mask = p_mask;
-}
-
-uint32_t SpringArm::get_mask() {
- return mask;
-}
-
-float SpringArm::get_margin() {
- return margin;
-}
-
-void SpringArm::set_margin(float p_margin) {
- margin = p_margin;
-}
-
-void SpringArm::add_excluded_object(RID p_rid) {
- excluded_objects.insert(p_rid);
-}
-
-bool SpringArm::remove_excluded_object(RID p_rid) {
- return excluded_objects.erase(p_rid);
-}
-
-void SpringArm::clear_excluded_objects() {
- excluded_objects.clear();
-}
-
-float SpringArm::get_hit_length() {
- return current_spring_length;
-}
-
-void SpringArm::process_spring() {
- // From
- real_t motion_delta(1);
- real_t motion_delta_unsafe(1);
-
- Vector3 motion;
- const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
-
- if (shape.is_null()) {
- motion = Vector3(cast_direction * (spring_length));
- PhysicsDirectSpaceState::RayResult r;
- bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
- if (intersected) {
- float dist = get_global_transform().origin.distance_to(r.position);
- dist -= margin;
- motion_delta = dist / (spring_length);
- }
- } else {
- motion = Vector3(cast_direction * spring_length);
- get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
- }
-
- current_spring_length = spring_length * motion_delta;
- Transform childs_transform;
- childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);
-
- for (int i = get_child_count() - 1; 0 <= i; --i) {
-
- Spatial *child = Object::cast_to<Spatial>(get_child(i));
- if (child) {
- childs_transform.basis = child->get_global_transform().basis;
- child->set_global_transform(childs_transform);
- }
- }
-}
diff --git a/scene/3d/spring_arm.h b/scene/3d/spring_arm.h
deleted file mode 100644
index 1a12370564..0000000000
--- a/scene/3d/spring_arm.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* spring_arm.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPRING_ARM_H
-#define SPRING_ARM_H
-
-#include "scene/3d/spatial.h"
-
-class SpringArm : public Spatial {
- GDCLASS(SpringArm, Spatial);
-
- Ref<Shape> shape;
- Set<RID> excluded_objects;
- float spring_length;
- float current_spring_length;
- bool keep_child_basis;
- uint32_t mask;
- float margin;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_length(float p_length);
- float get_length() const;
- void set_shape(Ref<Shape> p_shape);
- Ref<Shape> get_shape() const;
- void set_mask(uint32_t p_mask);
- uint32_t get_mask();
- void add_excluded_object(RID p_rid);
- bool remove_excluded_object(RID p_rid);
- void clear_excluded_objects();
- float get_hit_length();
- void set_margin(float p_margin);
- float get_margin();
-
- SpringArm();
-
-private:
- void process_spring();
-};
-
-#endif
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
new file mode 100644
index 0000000000..a5460593c9
--- /dev/null
+++ b/scene/3d/spring_arm_3d.cpp
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* spring_arm_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "spring_arm_3d.h"
+#include "core/engine.h"
+#include "scene/3d/collision_object_3d.h"
+#include "scene/resources/sphere_shape_3d.h"
+#include "servers/physics_server_3d.h"
+
+SpringArm3D::SpringArm3D() :
+ spring_length(1),
+ current_spring_length(0),
+ keep_child_basis(false),
+ mask(1),
+ margin(0.01) {}
+
+void SpringArm3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ set_process_internal(true);
+ }
+ break;
+ case NOTIFICATION_EXIT_TREE:
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ set_process_internal(false);
+ }
+ break;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS:
+ process_spring();
+ break;
+ }
+}
+
+void SpringArm3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm3D::get_hit_length);
+
+ ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm3D::set_length);
+ ClassDB::bind_method(D_METHOD("get_length"), &SpringArm3D::get_length);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm3D::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm3D::get_shape);
+
+ ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm3D::add_excluded_object);
+ ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm3D::remove_excluded_object);
+ ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm3D::clear_excluded_objects);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm3D::set_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm3D::get_mask);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm3D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm3D::get_margin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spring_length"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin");
+}
+
+float SpringArm3D::get_length() const {
+ return spring_length;
+}
+
+void SpringArm3D::set_length(float p_length) {
+ if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint()))
+ update_gizmo();
+
+ spring_length = p_length;
+}
+
+void SpringArm3D::set_shape(Ref<Shape3D> p_shape) {
+ shape = p_shape;
+}
+
+Ref<Shape3D> SpringArm3D::get_shape() const {
+ return shape;
+}
+
+void SpringArm3D::set_mask(uint32_t p_mask) {
+ mask = p_mask;
+}
+
+uint32_t SpringArm3D::get_mask() {
+ return mask;
+}
+
+float SpringArm3D::get_margin() {
+ return margin;
+}
+
+void SpringArm3D::set_margin(float p_margin) {
+ margin = p_margin;
+}
+
+void SpringArm3D::add_excluded_object(RID p_rid) {
+ excluded_objects.insert(p_rid);
+}
+
+bool SpringArm3D::remove_excluded_object(RID p_rid) {
+ return excluded_objects.erase(p_rid);
+}
+
+void SpringArm3D::clear_excluded_objects() {
+ excluded_objects.clear();
+}
+
+float SpringArm3D::get_hit_length() {
+ return current_spring_length;
+}
+
+void SpringArm3D::process_spring() {
+ // From
+ real_t motion_delta(1);
+ real_t motion_delta_unsafe(1);
+
+ Vector3 motion;
+ const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
+
+ if (shape.is_null()) {
+ motion = Vector3(cast_direction * (spring_length));
+ PhysicsDirectSpaceState3D::RayResult r;
+ bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
+ if (intersected) {
+ float dist = get_global_transform().origin.distance_to(r.position);
+ dist -= margin;
+ motion_delta = dist / (spring_length);
+ }
+ } else {
+ motion = Vector3(cast_direction * spring_length);
+ get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
+ }
+
+ current_spring_length = spring_length * motion_delta;
+ Transform childs_transform;
+ childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);
+
+ for (int i = get_child_count() - 1; 0 <= i; --i) {
+
+ Node3D *child = Object::cast_to<Node3D>(get_child(i));
+ if (child) {
+ childs_transform.basis = child->get_global_transform().basis;
+ child->set_global_transform(childs_transform);
+ }
+ }
+}
diff --git a/scene/3d/spring_arm_3d.h b/scene/3d/spring_arm_3d.h
new file mode 100644
index 0000000000..cb8a00ecf9
--- /dev/null
+++ b/scene/3d/spring_arm_3d.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* spring_arm_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPRING_ARM_H
+#define SPRING_ARM_H
+
+#include "scene/3d/node_3d.h"
+
+class SpringArm3D : public Node3D {
+ GDCLASS(SpringArm3D, Node3D);
+
+ Ref<Shape3D> shape;
+ Set<RID> excluded_objects;
+ float spring_length;
+ float current_spring_length;
+ bool keep_child_basis;
+ uint32_t mask;
+ float margin;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_length(float p_length);
+ float get_length() const;
+ void set_shape(Ref<Shape3D> p_shape);
+ Ref<Shape3D> get_shape() const;
+ void set_mask(uint32_t p_mask);
+ uint32_t get_mask();
+ void add_excluded_object(RID p_rid);
+ bool remove_excluded_object(RID p_rid);
+ void clear_excluded_objects();
+ float get_hit_length();
+ void set_margin(float p_margin);
+ float get_margin();
+
+ SpringArm3D();
+
+private:
+ void process_spring();
+};
+
+#endif
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index fd22076091..85e5ebc475 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -83,8 +83,8 @@ void SpriteBase3D::_notification(int p_what) {
if (parent_sprite) {
parent_sprite->children.erase(pI);
- pI = NULL;
- parent_sprite = NULL;
+ pI = nullptr;
+ parent_sprite = nullptr;
}
}
}
@@ -364,8 +364,8 @@ SpriteBase3D::SpriteBase3D() {
centered = true;
hflip = false;
vflip = false;
- parent_sprite = NULL;
- pI = NULL;
+ parent_sprite = nullptr;
+ pI = nullptr;
for (int i = 0; i < FLAG_MAX; i++)
flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
@@ -377,13 +377,13 @@ SpriteBase3D::SpriteBase3D() {
modulate = Color(1, 1, 1, 1);
pending_update = false;
opacity = 1.0;
- immediate = VisualServer::get_singleton()->immediate_create();
+ immediate = RenderingServer::get_singleton()->immediate_create();
set_base(immediate);
}
SpriteBase3D::~SpriteBase3D() {
- VisualServer::get_singleton()->free(immediate);
+ RenderingServer::get_singleton()->free(immediate);
}
///////////////////////////////////////////
@@ -392,7 +392,7 @@ void Sprite3D::_draw() {
RID immediate = get_immediate();
- VS::get_singleton()->immediate_clear(immediate);
+ RS::get_singleton()->immediate_clear(immediate);
if (!texture.is_valid())
return;
Vector2 tsize = texture->get_size();
@@ -441,7 +441,7 @@ void Sprite3D::_draw() {
// Properly setup UVs for impostor textures (AtlasTexture).
Ref<AtlasTexture> atlas_tex = texture;
- if (atlas_tex != NULL) {
+ if (atlas_tex != nullptr) {
src_tsize[0] = atlas_tex->get_atlas()->get_width();
src_tsize[1] = atlas_tex->get_atlas()->get_height();
}
@@ -475,9 +475,9 @@ void Sprite3D::_draw() {
}
RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y);
- VS::get_singleton()->immediate_set_material(immediate, mat);
+ RS::get_singleton()->immediate_set_material(immediate, mat);
- VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLES, texture->get_rid());
+ RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_TRIANGLES, texture->get_rid());
int x_axis = ((axis + 1) % 3);
int y_axis = ((axis + 2) % 3);
@@ -502,15 +502,15 @@ void Sprite3D::_draw() {
static const int index[6] = { 0, 1, 2, 0, 2, 3 };
- VS::get_singleton()->immediate_normal(immediate, normal);
- VS::get_singleton()->immediate_tangent(immediate, tangent);
- VS::get_singleton()->immediate_color(immediate, color);
- VS::get_singleton()->immediate_uv(immediate, uvs[i]);
+ RS::get_singleton()->immediate_normal(immediate, normal);
+ RS::get_singleton()->immediate_tangent(immediate, tangent);
+ RS::get_singleton()->immediate_color(immediate, color);
+ RS::get_singleton()->immediate_uv(immediate, uvs[i]);
Vector3 vtx;
vtx[x_axis] = vertices[index[i]][0];
vtx[y_axis] = vertices[index[i]][1];
- VS::get_singleton()->immediate_vertex(immediate, vtx);
+ RS::get_singleton()->immediate_vertex(immediate, vtx);
if (i == 0) {
aabb.position = vtx;
aabb.size = Vector3();
@@ -519,7 +519,7 @@ void Sprite3D::_draw() {
}
}
set_aabb(aabb);
- VS::get_singleton()->immediate_end(immediate);
+ RS::get_singleton()->immediate_end(immediate);
}
void Sprite3D::_texture_changed() {
@@ -717,7 +717,7 @@ Sprite3D::Sprite3D() {
void AnimatedSprite3D::_draw() {
RID immediate = get_immediate();
- VS::get_singleton()->immediate_clear(immediate);
+ RS::get_singleton()->immediate_clear(immediate);
if (frames.is_null()) {
return;
@@ -775,7 +775,7 @@ void AnimatedSprite3D::_draw() {
// Properly setup UVs for impostor textures (AtlasTexture).
Ref<AtlasTexture> atlas_tex = texture;
- if (atlas_tex != NULL) {
+ if (atlas_tex != nullptr) {
src_tsize[0] = atlas_tex->get_atlas()->get_width();
src_tsize[1] = atlas_tex->get_atlas()->get_height();
}
@@ -810,9 +810,9 @@ void AnimatedSprite3D::_draw() {
RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y);
- VS::get_singleton()->immediate_set_material(immediate, mat);
+ RS::get_singleton()->immediate_set_material(immediate, mat);
- VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_TRIANGLES, texture->get_rid());
+ RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_TRIANGLES, texture->get_rid());
int x_axis = ((axis + 1) % 3);
int y_axis = ((axis + 2) % 3);
@@ -840,15 +840,15 @@ void AnimatedSprite3D::_draw() {
0, 2, 3
};
- VS::get_singleton()->immediate_normal(immediate, normal);
- VS::get_singleton()->immediate_tangent(immediate, tangent);
- VS::get_singleton()->immediate_color(immediate, color);
- VS::get_singleton()->immediate_uv(immediate, uvs[i]);
+ RS::get_singleton()->immediate_normal(immediate, normal);
+ RS::get_singleton()->immediate_tangent(immediate, tangent);
+ RS::get_singleton()->immediate_color(immediate, color);
+ RS::get_singleton()->immediate_uv(immediate, uvs[i]);
Vector3 vtx;
vtx[x_axis] = vertices[indices[i]][0];
vtx[y_axis] = vertices[indices[i]][1];
- VS::get_singleton()->immediate_vertex(immediate, vtx);
+ RS::get_singleton()->immediate_vertex(immediate, vtx);
if (i == 0) {
aabb.position = vtx;
aabb.size = Vector3();
@@ -857,7 +857,7 @@ void AnimatedSprite3D::_draw() {
}
}
set_aabb(aabb);
- VS::get_singleton()->immediate_end(immediate);
+ RS::get_singleton()->immediate_end(immediate);
}
void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 082884c83b..64bef41fd8 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -31,12 +31,12 @@
#ifndef SPRITE_3D_H
#define SPRITE_3D_H
-#include "scene/2d/animated_sprite.h"
-#include "scene/3d/visual_instance.h"
+#include "scene/2d/animated_sprite_2d.h"
+#include "scene/3d/visual_instance_3d.h"
-class SpriteBase3D : public GeometryInstance {
+class SpriteBase3D : public GeometryInstance3D {
- GDCLASS(SpriteBase3D, GeometryInstance);
+ GDCLASS(SpriteBase3D, GeometryInstance3D);
mutable Ref<TriangleMesh> triangle_mesh; //cached
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
deleted file mode 100644
index c249d844d1..0000000000
--- a/scene/3d/vehicle_body.cpp
+++ /dev/null
@@ -1,998 +0,0 @@
-/*************************************************************************/
-/* vehicle_body.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "vehicle_body.h"
-
-#define ROLLING_INFLUENCE_FIX
-
-class btVehicleJacobianEntry {
-public:
- Vector3 m_linearJointAxis;
- Vector3 m_aJ;
- Vector3 m_bJ;
- Vector3 m_0MinvJt;
- Vector3 m_1MinvJt;
- //Optimization: can be stored in the w/last component of one of the vectors
- real_t m_Adiag;
-
- real_t getDiagonal() const { return m_Adiag; }
-
- btVehicleJacobianEntry(){};
- //constraint between two different rigidbodies
- btVehicleJacobianEntry(
- const Basis &world2A,
- const Basis &world2B,
- const Vector3 &rel_pos1,
- const Vector3 &rel_pos2,
- const Vector3 &jointAxis,
- const Vector3 &inertiaInvA,
- const real_t massInvA,
- const Vector3 &inertiaInvB,
- const real_t massInvB) :
- m_linearJointAxis(jointAxis) {
- m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
- m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
- m_0MinvJt = inertiaInvA * m_aJ;
- m_1MinvJt = inertiaInvB * m_bJ;
- m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
-
- //btAssert(m_Adiag > real_t(0.0));
- }
-
- real_t getRelativeVelocity(const Vector3 &linvelA, const Vector3 &angvelA, const Vector3 &linvelB, const Vector3 &angvelB) {
- Vector3 linrel = linvelA - linvelB;
- Vector3 angvela = angvelA * m_aJ;
- Vector3 angvelb = angvelB * m_bJ;
- linrel *= m_linearJointAxis;
- angvela += angvelb;
- angvela += linrel;
- real_t rel_vel2 = angvela[0] + angvela[1] + angvela[2];
- return rel_vel2 + CMP_EPSILON;
- }
-};
-
-void VehicleWheel::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- VehicleBody *cb = Object::cast_to<VehicleBody>(get_parent());
- if (!cb)
- return;
- body = cb;
- local_xform = get_transform();
- cb->wheels.push_back(this);
-
- m_chassisConnectionPointCS = get_transform().origin;
- m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
- m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
- }
- if (p_what == NOTIFICATION_EXIT_TREE) {
-
- VehicleBody *cb = Object::cast_to<VehicleBody>(get_parent());
- if (!cb)
- return;
- cb->wheels.erase(this);
- body = NULL;
- }
-}
-
-String VehicleWheel::get_configuration_warning() const {
- if (!Object::cast_to<VehicleBody>(get_parent())) {
- return TTR("VehicleWheel serves to provide a wheel system to a VehicleBody. Please use it as a child of a VehicleBody.");
- }
-
- return String();
-}
-
-void VehicleWheel::_update(PhysicsDirectBodyState *s) {
-
- if (m_raycastInfo.m_isInContact)
-
- {
- real_t project = m_raycastInfo.m_contactNormalWS.dot(m_raycastInfo.m_wheelDirectionWS);
- Vector3 chassis_velocity_at_contactPoint;
- Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin;
-
- chassis_velocity_at_contactPoint = s->get_linear_velocity() +
- (s->get_angular_velocity()).cross(relpos); // * mPos);
-
- real_t projVel = m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
- if (project >= real_t(-0.1)) {
- m_suspensionRelativeVelocity = real_t(0.0);
- m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
- } else {
- real_t inv = real_t(-1.) / project;
- m_suspensionRelativeVelocity = projVel * inv;
- m_clippedInvContactDotSuspension = inv;
- }
-
- }
-
- else // Not in contact : position wheel in a nice (rest length) position
- {
- m_raycastInfo.m_suspensionLength = m_suspensionRestLength;
- m_suspensionRelativeVelocity = real_t(0.0);
- m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS;
- m_clippedInvContactDotSuspension = real_t(1.0);
- }
-}
-
-void VehicleWheel::set_radius(float p_radius) {
-
- m_wheelRadius = p_radius;
- update_gizmo();
-}
-
-float VehicleWheel::get_radius() const {
-
- return m_wheelRadius;
-}
-
-void VehicleWheel::set_suspension_rest_length(float p_length) {
-
- m_suspensionRestLength = p_length;
- update_gizmo();
-}
-float VehicleWheel::get_suspension_rest_length() const {
-
- return m_suspensionRestLength;
-}
-
-void VehicleWheel::set_suspension_travel(float p_length) {
-
- m_maxSuspensionTravelCm = p_length / 0.01;
-}
-float VehicleWheel::get_suspension_travel() const {
-
- return m_maxSuspensionTravelCm * 0.01;
-}
-
-void VehicleWheel::set_suspension_stiffness(float p_value) {
-
- m_suspensionStiffness = p_value;
-}
-float VehicleWheel::get_suspension_stiffness() const {
-
- return m_suspensionStiffness;
-}
-
-void VehicleWheel::set_suspension_max_force(float p_value) {
-
- m_maxSuspensionForce = p_value;
-}
-float VehicleWheel::get_suspension_max_force() const {
-
- return m_maxSuspensionForce;
-}
-
-void VehicleWheel::set_damping_compression(float p_value) {
-
- m_wheelsDampingCompression = p_value;
-}
-float VehicleWheel::get_damping_compression() const {
-
- return m_wheelsDampingCompression;
-}
-
-void VehicleWheel::set_damping_relaxation(float p_value) {
-
- m_wheelsDampingRelaxation = p_value;
-}
-float VehicleWheel::get_damping_relaxation() const {
-
- return m_wheelsDampingRelaxation;
-}
-
-void VehicleWheel::set_friction_slip(float p_value) {
-
- m_frictionSlip = p_value;
-}
-float VehicleWheel::get_friction_slip() const {
-
- return m_frictionSlip;
-}
-
-void VehicleWheel::set_roll_influence(float p_value) {
- m_rollInfluence = p_value;
-}
-
-float VehicleWheel::get_roll_influence() const {
- return m_rollInfluence;
-}
-
-bool VehicleWheel::is_in_contact() const {
- return m_raycastInfo.m_isInContact;
-}
-
-void VehicleWheel::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_radius", "length"), &VehicleWheel::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &VehicleWheel::get_radius);
-
- ClassDB::bind_method(D_METHOD("set_suspension_rest_length", "length"), &VehicleWheel::set_suspension_rest_length);
- ClassDB::bind_method(D_METHOD("get_suspension_rest_length"), &VehicleWheel::get_suspension_rest_length);
-
- ClassDB::bind_method(D_METHOD("set_suspension_travel", "length"), &VehicleWheel::set_suspension_travel);
- ClassDB::bind_method(D_METHOD("get_suspension_travel"), &VehicleWheel::get_suspension_travel);
-
- ClassDB::bind_method(D_METHOD("set_suspension_stiffness", "length"), &VehicleWheel::set_suspension_stiffness);
- ClassDB::bind_method(D_METHOD("get_suspension_stiffness"), &VehicleWheel::get_suspension_stiffness);
-
- ClassDB::bind_method(D_METHOD("set_suspension_max_force", "length"), &VehicleWheel::set_suspension_max_force);
- ClassDB::bind_method(D_METHOD("get_suspension_max_force"), &VehicleWheel::get_suspension_max_force);
-
- ClassDB::bind_method(D_METHOD("set_damping_compression", "length"), &VehicleWheel::set_damping_compression);
- ClassDB::bind_method(D_METHOD("get_damping_compression"), &VehicleWheel::get_damping_compression);
-
- ClassDB::bind_method(D_METHOD("set_damping_relaxation", "length"), &VehicleWheel::set_damping_relaxation);
- ClassDB::bind_method(D_METHOD("get_damping_relaxation"), &VehicleWheel::get_damping_relaxation);
-
- ClassDB::bind_method(D_METHOD("set_use_as_traction", "enable"), &VehicleWheel::set_use_as_traction);
- ClassDB::bind_method(D_METHOD("is_used_as_traction"), &VehicleWheel::is_used_as_traction);
-
- ClassDB::bind_method(D_METHOD("set_use_as_steering", "enable"), &VehicleWheel::set_use_as_steering);
- ClassDB::bind_method(D_METHOD("is_used_as_steering"), &VehicleWheel::is_used_as_steering);
-
- ClassDB::bind_method(D_METHOD("set_friction_slip", "length"), &VehicleWheel::set_friction_slip);
- ClassDB::bind_method(D_METHOD("get_friction_slip"), &VehicleWheel::get_friction_slip);
-
- ClassDB::bind_method(D_METHOD("is_in_contact"), &VehicleWheel::is_in_contact);
-
- ClassDB::bind_method(D_METHOD("set_roll_influence", "roll_influence"), &VehicleWheel::set_roll_influence);
- ClassDB::bind_method(D_METHOD("get_roll_influence"), &VehicleWheel::get_roll_influence);
-
- ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel::get_skidinfo);
-
- ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel::get_rpm);
-
- ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleWheel::set_engine_force);
- ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleWheel::get_engine_force);
-
- ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleWheel::set_brake);
- ClassDB::bind_method(D_METHOD("get_brake"), &VehicleWheel::get_brake);
-
- ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleWheel::set_steering);
- ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel::get_steering);
-
- ADD_GROUP("Per-Wheel Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
- ADD_GROUP("VehicleBody Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering");
- ADD_GROUP("Wheel", "wheel_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_roll_influence"), "set_roll_influence", "get_roll_influence");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_radius"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_rest_length"), "set_suspension_rest_length", "get_suspension_rest_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_friction_slip"), "set_friction_slip", "get_friction_slip");
- ADD_GROUP("Suspension", "suspension_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_travel"), "set_suspension_travel", "get_suspension_travel");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_stiffness"), "set_suspension_stiffness", "get_suspension_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_max_force"), "set_suspension_max_force", "get_suspension_max_force");
- ADD_GROUP("Damping", "damping_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_compression"), "set_damping_compression", "get_damping_compression");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation");
-}
-
-void VehicleWheel::set_engine_force(float p_engine_force) {
-
- m_engineForce = p_engine_force;
-}
-
-float VehicleWheel::get_engine_force() const {
-
- return m_engineForce;
-}
-
-void VehicleWheel::set_brake(float p_brake) {
-
- m_brake = p_brake;
-}
-float VehicleWheel::get_brake() const {
-
- return m_brake;
-}
-
-void VehicleWheel::set_steering(float p_steering) {
-
- m_steering = p_steering;
-}
-float VehicleWheel::get_steering() const {
-
- return m_steering;
-}
-
-void VehicleWheel::set_use_as_traction(bool p_enable) {
-
- engine_traction = p_enable;
-}
-
-bool VehicleWheel::is_used_as_traction() const {
-
- return engine_traction;
-}
-
-void VehicleWheel::set_use_as_steering(bool p_enabled) {
-
- steers = p_enabled;
-}
-
-bool VehicleWheel::is_used_as_steering() const {
-
- return steers;
-}
-
-float VehicleWheel::get_skidinfo() const {
-
- return m_skidInfo;
-}
-
-float VehicleWheel::get_rpm() const {
-
- return m_rpm;
-}
-
-VehicleWheel::VehicleWheel() {
-
- steers = false;
- engine_traction = false;
- m_steering = real_t(0.);
- m_engineForce = real_t(0.);
- m_rotation = real_t(0.);
- m_deltaRotation = real_t(0.);
- m_brake = real_t(0.);
- m_rollInfluence = real_t(0.1);
-
- m_suspensionRestLength = 0.15;
- m_wheelRadius = 0.5; //0.28;
- m_suspensionStiffness = 5.88;
- m_wheelsDampingCompression = 0.83;
- m_wheelsDampingRelaxation = 0.88;
- m_frictionSlip = 10.5;
- m_bIsFrontWheel = false;
- m_maxSuspensionTravelCm = 500;
- m_maxSuspensionForce = 6000;
-
- m_suspensionRelativeVelocity = 0;
- m_clippedInvContactDotSuspension = 1.0;
- m_raycastInfo.m_isInContact = false;
-
- body = NULL;
-}
-
-void VehicleBody::_update_wheel_transform(VehicleWheel &wheel, PhysicsDirectBodyState *s) {
-
- wheel.m_raycastInfo.m_isInContact = false;
-
- Transform chassisTrans = s->get_transform();
- /*
- if (interpolatedTransform && (getRigidBody()->getMotionState())) {
- getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
- }
- */
-
- wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform(wheel.m_chassisConnectionPointCS);
- //wheel.m_raycastInfo.m_hardPointWS+=s->get_linear_velocity()*s->get_step();
- wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform(wheel.m_wheelDirectionCS).normalized();
- wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform(wheel.m_wheelAxleCS).normalized();
-}
-
-void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) {
-
- VehicleWheel &wheel = *wheels[p_idx];
- _update_wheel_transform(wheel, s);
-
- Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
- const Vector3 &right = wheel.m_raycastInfo.m_wheelAxleWS;
- Vector3 fwd = up.cross(right);
- fwd = fwd.normalized();
-
- Basis steeringMat(up, wheel.m_steering);
-
- Basis rotatingMat(right, wheel.m_rotation);
-
- Basis basis2(
- right[0], up[0], fwd[0],
- right[1], up[1], fwd[1],
- right[2], up[2], fwd[2]);
-
- wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2);
- //wheel.m_worldTransform.set_basis(basis2 * (steeringMat * rotatingMat));
- wheel.m_worldTransform.set_origin(
- wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength);
-}
-
-real_t VehicleBody::_ray_cast(int p_idx, PhysicsDirectBodyState *s) {
-
- VehicleWheel &wheel = *wheels[p_idx];
-
- _update_wheel_transform(wheel, s);
-
- real_t depth = -1;
-
- real_t raylen = wheel.m_suspensionRestLength + wheel.m_wheelRadius;
-
- Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
- Vector3 source = wheel.m_raycastInfo.m_hardPointWS;
- wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
- const Vector3 &target = wheel.m_raycastInfo.m_contactPointWS;
- source -= wheel.m_wheelRadius * wheel.m_raycastInfo.m_wheelDirectionWS;
-
- real_t param = real_t(0.);
-
- PhysicsDirectSpaceState::RayResult rr;
-
- PhysicsDirectSpaceState *ss = s->get_space_state();
-
- bool col = ss->intersect_ray(source, target, rr, exclude);
-
- wheel.m_raycastInfo.m_groundObject = 0;
-
- if (col) {
- param = source.distance_to(rr.position) / source.distance_to(target);
- depth = raylen * param;
- wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
-
- wheel.m_raycastInfo.m_isInContact = true;
- if (rr.collider)
- wheel.m_raycastInfo.m_groundObject = Object::cast_to<PhysicsBody>(rr.collider);
-
- real_t hitDistance = param * raylen;
- wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius;
- //clamp on max suspension travel
-
- real_t minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm * real_t(0.01);
- real_t maxSuspensionLength = wheel.m_suspensionRestLength + wheel.m_maxSuspensionTravelCm * real_t(0.01);
- if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) {
- wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
- }
- if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) {
- wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
- }
-
- wheel.m_raycastInfo.m_contactPointWS = rr.position;
-
- real_t denominator = wheel.m_raycastInfo.m_contactNormalWS.dot(wheel.m_raycastInfo.m_wheelDirectionWS);
-
- Vector3 chassis_velocity_at_contactPoint;
- //Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition();
-
- //chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
-
- chassis_velocity_at_contactPoint = s->get_linear_velocity() +
- (s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin); // * mPos);
-
- real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
-
- if (denominator >= real_t(-0.1)) {
- wheel.m_suspensionRelativeVelocity = real_t(0.0);
- wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
- } else {
- real_t inv = real_t(-1.) / denominator;
- wheel.m_suspensionRelativeVelocity = projVel * inv;
- wheel.m_clippedInvContactDotSuspension = inv;
- }
-
- } else {
- wheel.m_raycastInfo.m_isInContact = false;
- //put wheel info as in rest position
- wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength;
- wheel.m_suspensionRelativeVelocity = real_t(0.0);
- wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
- wheel.m_clippedInvContactDotSuspension = real_t(1.0);
- }
-
- return depth;
-}
-
-void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) {
-
- real_t chassisMass = mass;
-
- for (int w_it = 0; w_it < wheels.size(); w_it++) {
- VehicleWheel &wheel_info = *wheels[w_it];
-
- if (wheel_info.m_raycastInfo.m_isInContact) {
- real_t force;
- //Spring
- {
- real_t susp_length = wheel_info.m_suspensionRestLength;
- real_t current_length = wheel_info.m_raycastInfo.m_suspensionLength;
-
- real_t length_diff = (susp_length - current_length);
-
- force = wheel_info.m_suspensionStiffness * length_diff * wheel_info.m_clippedInvContactDotSuspension;
- }
-
- // Damper
- {
- real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
- {
- real_t susp_damping;
- if (projected_rel_vel < real_t(0.0)) {
- susp_damping = wheel_info.m_wheelsDampingCompression;
- } else {
- susp_damping = wheel_info.m_wheelsDampingRelaxation;
- }
- force -= susp_damping * projected_rel_vel;
- }
- }
-
- // RESULT
- wheel_info.m_wheelsSuspensionForce = force * chassisMass;
- if (wheel_info.m_wheelsSuspensionForce < real_t(0.)) {
- wheel_info.m_wheelsSuspensionForce = real_t(0.);
- }
- } else {
- wheel_info.m_wheelsSuspensionForce = real_t(0.0);
- }
- }
-}
-
-//bilateral constraint between two dynamic objects
-void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1,
- PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) {
-
- real_t normalLenSqr = normal.length_squared();
- //ERR_FAIL_COND( normalLenSqr < real_t(1.1));
-
- if (normalLenSqr > real_t(1.1)) {
- impulse = real_t(0.);
- return;
- }
-
- Vector3 rel_pos1 = pos1 - s->get_transform().origin;
- Vector3 rel_pos2;
- if (body2)
- rel_pos2 = pos2 - body2->get_global_transform().origin;
- //this jacobian entry could be re-used for all iterations
-
- Vector3 vel1 = s->get_linear_velocity() + (s->get_angular_velocity()).cross(rel_pos1); // * mPos);
- Vector3 vel2;
-
- if (body2)
- vel2 = body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2);
-
- Vector3 vel = vel1 - vel2;
-
- Basis b2trans;
- float b2invmass = 0;
- Vector3 b2lv;
- Vector3 b2av;
- Vector3 b2invinertia; //todo
-
- if (body2) {
- b2trans = body2->get_global_transform().basis.transposed();
- b2invmass = body2->get_inverse_mass();
- b2lv = body2->get_linear_velocity();
- b2av = body2->get_angular_velocity();
- }
-
- btVehicleJacobianEntry jac(s->get_transform().basis.transposed(),
- b2trans,
- rel_pos1,
- rel_pos2,
- normal,
- s->get_inverse_inertia_tensor().get_main_diagonal(),
- 1.0 / mass,
- b2invinertia,
- 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);
- // Investigate why.
- real_t rel_vel = jac.getRelativeVelocity(
- s->get_linear_velocity(),
- s->get_transform().basis.transposed().xform(s->get_angular_velocity()),
- b2lv,
- b2trans.xform(b2av));
-
- rel_vel = normal.dot(vel);
-
- // !BAS! We had this set to 0.4, in bullet its 0.2
- real_t contactDamping = real_t(0.2);
-
- if (p_rollInfluence > 0.0) {
- // !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based
- // keeping in mind our anti roll factor if it is set
- contactDamping = MIN(contactDamping, s->get_step() / p_rollInfluence);
- }
-
-#define ONLY_USE_LINEAR_MASS
-#ifdef ONLY_USE_LINEAR_MASS
- real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
- impulse = -contactDamping * rel_vel * massTerm;
-#else
- real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
- impulse = velocityImpulse;
-#endif
-}
-
-VehicleBody::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse) :
- m_s(s),
- m_body1(body1),
- m_frictionPositionWorld(frictionPosWorld),
- m_frictionDirectionWorld(frictionDirectionWorld),
- m_maxImpulse(maxImpulse) {
- float denom0 = 0;
- float denom1 = 0;
-
- {
- Vector3 r0 = frictionPosWorld - s->get_transform().origin;
- Vector3 c0 = (r0).cross(frictionDirectionWorld);
- Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
- denom0 = s->get_inverse_mass() + frictionDirectionWorld.dot(vec);
- }
-
- /* TODO: Why is this code unused?
- if (body1) {
-
- Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
- Vector3 c0 = (r0).cross(frictionDirectionWorld);
- Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
- //denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec);
-
- }
- */
-
- real_t relaxation = 1.f;
- m_jacDiagABInv = relaxation / (denom0 + denom1);
-}
-
-real_t VehicleBody::_calc_rolling_friction(btVehicleWheelContactPoint &contactPoint) {
-
- real_t j1 = 0.f;
-
- const Vector3 &contactPosWorld = contactPoint.m_frictionPositionWorld;
-
- Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin;
- Vector3 rel_pos2;
- if (contactPoint.m_body1)
- rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin;
-
- real_t maxImpulse = contactPoint.m_maxImpulse;
-
- Vector3 vel1 = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1); // * mPos);
-
- Vector3 vel2;
- if (contactPoint.m_body1) {
- vel2 = contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2);
- }
-
- Vector3 vel = vel1 - vel2;
-
- real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
-
- // calculate j that moves us to zero relative velocity
- j1 = -vrel * contactPoint.m_jacDiagABInv;
-
- return CLAMP(j1, -maxImpulse, maxImpulse);
-}
-
-static const real_t sideFrictionStiffness2 = real_t(1.0);
-void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
-
- //calculate the impulse, so that the wheels don't move sidewards
- int numWheel = wheels.size();
- if (!numWheel)
- return;
-
- m_forwardWS.resize(numWheel);
- m_axle.resize(numWheel);
- m_forwardImpulse.resize(numWheel);
- m_sideImpulse.resize(numWheel);
-
- //collapse all those loops into one!
- for (int i = 0; i < wheels.size(); i++) {
- m_sideImpulse.write[i] = real_t(0.);
- m_forwardImpulse.write[i] = real_t(0.);
- }
-
- {
-
- for (int i = 0; i < wheels.size(); i++) {
-
- VehicleWheel &wheelInfo = *wheels[i];
-
- if (wheelInfo.m_raycastInfo.m_isInContact) {
-
- //const btTransform& wheelTrans = getWheelTransformWS( i );
-
- Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis;
-
- m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
- //m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
-
- const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
- real_t proj = m_axle[i].dot(surfNormalWS);
- m_axle.write[i] -= surfNormalWS * proj;
- m_axle.write[i] = m_axle[i].normalized();
-
- m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]);
- m_forwardWS.write[i].normalize();
-
- _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
- wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
- m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence);
-
- m_sideImpulse.write[i] *= sideFrictionStiffness2;
- }
- }
- }
-
- real_t sideFactor = real_t(1.);
- real_t fwdFactor = 0.5;
-
- bool sliding = false;
- {
- for (int wheel = 0; wheel < wheels.size(); wheel++) {
- VehicleWheel &wheelInfo = *wheels[wheel];
-
- //class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
-
- real_t rollingFriction = 0.f;
-
- if (wheelInfo.m_raycastInfo.m_isInContact) {
- if (wheelInfo.m_engineForce != 0.f) {
- rollingFriction = -wheelInfo.m_engineForce * s->get_step();
- } else {
- real_t defaultRollingFrictionImpulse = 0.f;
- real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
- btVehicleWheelContactPoint contactPt(s, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel], maxImpulse);
- rollingFriction = _calc_rolling_friction(contactPt);
- }
- }
-
- //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
-
- m_forwardImpulse.write[wheel] = real_t(0.);
- wheelInfo.m_skidInfo = real_t(1.);
-
- if (wheelInfo.m_raycastInfo.m_isInContact) {
- wheelInfo.m_skidInfo = real_t(1.);
-
- real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip;
- real_t maximpSide = maximp;
-
- real_t maximpSquared = maximp * maximpSide;
-
- m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
-
- real_t x = (m_forwardImpulse[wheel]) * fwdFactor;
- real_t y = (m_sideImpulse[wheel]) * sideFactor;
-
- real_t impulseSquared = (x * x + y * y);
-
- if (impulseSquared > maximpSquared) {
- sliding = true;
-
- real_t factor = maximp / Math::sqrt(impulseSquared);
-
- wheelInfo.m_skidInfo *= factor;
- }
- }
- }
- }
-
- if (sliding) {
- for (int wheel = 0; wheel < wheels.size(); wheel++) {
- if (m_sideImpulse[wheel] != real_t(0.)) {
- if (wheels[wheel]->m_skidInfo < real_t(1.)) {
- m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
- m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
- }
- }
- }
- }
-
- // apply the impulses
- {
- for (int wheel = 0; wheel < wheels.size(); wheel++) {
- VehicleWheel &wheelInfo = *wheels[wheel];
-
- Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
- s->get_transform().origin;
-
- if (m_forwardImpulse[wheel] != real_t(0.)) {
- s->apply_impulse(rel_pos, m_forwardWS[wheel] * (m_forwardImpulse[wheel]));
- }
- if (m_sideImpulse[wheel] != real_t(0.)) {
- PhysicsBody *groundObject = wheelInfo.m_raycastInfo.m_groundObject;
-
- Vector3 rel_pos2;
- if (groundObject) {
- rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin;
- }
-
- Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
-
-#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
- Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
- rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
-#else
- rel_pos[1] *= wheelInfo.m_rollInfluence; //?
-#endif
- s->apply_impulse(rel_pos, sideImp);
-
- //apply friction impulse on the ground
- //todo
- //groundObject->applyImpulse(-sideImp,rel_pos2);
- }
- }
- }
-}
-
-void VehicleBody::_direct_state_changed(Object *p_state) {
-
- RigidBody::_direct_state_changed(p_state);
-
- state = Object::cast_to<PhysicsDirectBodyState>(p_state);
-
- float step = state->get_step();
-
- for (int i = 0; i < wheels.size(); i++) {
-
- _update_wheel(i, state);
- }
-
- for (int i = 0; i < wheels.size(); i++) {
-
- _ray_cast(i, state);
- wheels[i]->set_transform(state->get_transform().inverse() * wheels[i]->m_worldTransform);
- }
-
- _update_suspension(state);
-
- for (int i = 0; i < wheels.size(); i++) {
-
- //apply suspension force
- VehicleWheel &wheel = *wheels[i];
-
- real_t suspensionForce = wheel.m_wheelsSuspensionForce;
-
- if (suspensionForce > wheel.m_maxSuspensionForce) {
- suspensionForce = wheel.m_maxSuspensionForce;
- }
- Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
- Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - state->get_transform().origin;
-
- state->apply_impulse(relpos, impulse);
- //getRigidBody()->applyImpulse(impulse, relpos);
- }
-
- _update_friction(state);
-
- for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheel = *wheels[i];
- Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - state->get_transform().origin;
- Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
-
- if (wheel.m_raycastInfo.m_isInContact) {
- const Transform &chassisWorldTransform = state->get_transform();
-
- Vector3 fwd(
- chassisWorldTransform.basis[0][Vector3::AXIS_Z],
- chassisWorldTransform.basis[1][Vector3::AXIS_Z],
- chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
-
- real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
- fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
-
- real_t proj2 = fwd.dot(vel);
-
- wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
- }
-
- wheel.m_rotation += wheel.m_deltaRotation;
- wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU;
-
- wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
- }
-
- state = NULL;
-}
-
-void VehicleBody::set_engine_force(float p_engine_force) {
-
- engine_force = p_engine_force;
- for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheelInfo = *wheels[i];
- if (wheelInfo.engine_traction)
- wheelInfo.m_engineForce = p_engine_force;
- }
-}
-
-float VehicleBody::get_engine_force() const {
-
- return engine_force;
-}
-
-void VehicleBody::set_brake(float p_brake) {
-
- brake = p_brake;
- for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheelInfo = *wheels[i];
- wheelInfo.m_brake = p_brake;
- }
-}
-float VehicleBody::get_brake() const {
-
- return brake;
-}
-
-void VehicleBody::set_steering(float p_steering) {
-
- m_steeringValue = p_steering;
- for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheelInfo = *wheels[i];
- if (wheelInfo.steers)
- wheelInfo.m_steering = p_steering;
- }
-}
-float VehicleBody::get_steering() const {
-
- return m_steeringValue;
-}
-
-void VehicleBody::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleBody::set_engine_force);
- ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleBody::get_engine_force);
-
- ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleBody::set_brake);
- ClassDB::bind_method(D_METHOD("get_brake"), &VehicleBody::get_brake);
-
- ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleBody::set_steering);
- ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering);
-
- ADD_GROUP("Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
-}
-
-VehicleBody::VehicleBody() {
-
- m_pitchControl = 0;
- m_currentVehicleSpeedKmHour = real_t(0.);
- m_steeringValue = real_t(0.);
-
- engine_force = 0;
- brake = 0;
-
- state = NULL;
- ccd = false;
-
- exclude.insert(get_rid());
- //PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
-
- set_mass(40);
-}
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
deleted file mode 100644
index c05ea30f94..0000000000
--- a/scene/3d/vehicle_body.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*************************************************************************/
-/* vehicle_body.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VEHICLE_BODY_H
-#define VEHICLE_BODY_H
-
-#include "scene/3d/physics_body.h"
-
-class VehicleBody;
-
-class VehicleWheel : public Spatial {
-
- GDCLASS(VehicleWheel, Spatial);
-
- friend class VehicleBody;
-
- Transform m_worldTransform;
- Transform local_xform;
- bool engine_traction;
- bool steers;
-
- Vector3 m_chassisConnectionPointCS; //const
- Vector3 m_wheelDirectionCS; //const
- Vector3 m_wheelAxleCS; // const or modified by steering
-
- real_t m_suspensionRestLength;
- real_t m_maxSuspensionTravelCm;
- real_t m_wheelRadius;
-
- real_t m_suspensionStiffness;
- real_t m_wheelsDampingCompression;
- real_t m_wheelsDampingRelaxation;
- real_t m_frictionSlip;
- real_t m_maxSuspensionForce;
- bool m_bIsFrontWheel;
-
- VehicleBody *body;
-
- //btVector3 m_wheelAxleCS; // const or modified by steering ?
-
- real_t m_steering;
- real_t m_rotation;
- real_t m_deltaRotation;
- real_t m_rpm;
- real_t m_rollInfluence;
- real_t m_engineForce;
- real_t m_brake;
-
- real_t m_clippedInvContactDotSuspension;
- real_t m_suspensionRelativeVelocity;
- //calculated by suspension
- real_t m_wheelsSuspensionForce;
- real_t m_skidInfo;
-
- struct RaycastInfo {
- //set by raycaster
- Vector3 m_contactNormalWS; //contactnormal
- Vector3 m_contactPointWS; //raycast hitpoint
- real_t m_suspensionLength;
- Vector3 m_hardPointWS; //raycast starting point
- Vector3 m_wheelDirectionWS; //direction in worldspace
- Vector3 m_wheelAxleWS; // axle in worldspace
- bool m_isInContact;
- PhysicsBody *m_groundObject; //could be general void* ptr
- } m_raycastInfo;
-
- void _update(PhysicsDirectBodyState *s);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_radius(float p_radius);
- float get_radius() const;
-
- void set_suspension_rest_length(float p_length);
- float get_suspension_rest_length() const;
-
- void set_suspension_travel(float p_length);
- float get_suspension_travel() const;
-
- void set_suspension_stiffness(float p_value);
- float get_suspension_stiffness() const;
-
- void set_suspension_max_force(float p_value);
- float get_suspension_max_force() const;
-
- void set_damping_compression(float p_value);
- float get_damping_compression() const;
-
- void set_damping_relaxation(float p_value);
- float get_damping_relaxation() const;
-
- void set_friction_slip(float p_value);
- float get_friction_slip() const;
-
- void set_use_as_traction(bool p_enable);
- bool is_used_as_traction() const;
-
- void set_use_as_steering(bool p_enabled);
- bool is_used_as_steering() const;
-
- bool is_in_contact() const;
-
- void set_roll_influence(float p_value);
- float get_roll_influence() const;
-
- float get_skidinfo() const;
-
- float get_rpm() const;
-
- void set_engine_force(float p_engine_force);
- float get_engine_force() const;
-
- void set_brake(float p_brake);
- float get_brake() const;
-
- void set_steering(float p_steering);
- float get_steering() const;
-
- String get_configuration_warning() const;
-
- VehicleWheel();
-};
-
-class VehicleBody : public RigidBody {
-
- GDCLASS(VehicleBody, RigidBody);
-
- float engine_force;
- float brake;
-
- real_t m_pitchControl;
- real_t m_steeringValue;
- real_t m_currentVehicleSpeedKmHour;
-
- Set<RID> exclude;
-
- Vector<Vector3> m_forwardWS;
- Vector<Vector3> m_axle;
- Vector<real_t> m_forwardImpulse;
- Vector<real_t> m_sideImpulse;
-
- struct btVehicleWheelContactPoint {
- PhysicsDirectBodyState *m_s;
- PhysicsBody *m_body1;
- Vector3 m_frictionPositionWorld;
- Vector3 m_frictionDirectionWorld;
- real_t m_jacDiagABInv;
- real_t m_maxImpulse;
-
- btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse);
- };
-
- void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence);
- real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
-
- void _update_friction(PhysicsDirectBodyState *s);
- void _update_suspension(PhysicsDirectBodyState *s);
- real_t _ray_cast(int p_idx, PhysicsDirectBodyState *s);
- void _update_wheel_transform(VehicleWheel &wheel, PhysicsDirectBodyState *s);
- void _update_wheel(int p_idx, PhysicsDirectBodyState *s);
-
- friend class VehicleWheel;
- Vector<VehicleWheel *> wheels;
-
- static void _bind_methods();
-
- void _direct_state_changed(Object *p_state);
-
-public:
- void set_engine_force(float p_engine_force);
- float get_engine_force() const;
-
- void set_brake(float p_brake);
- float get_brake() const;
-
- void set_steering(float p_steering);
- float get_steering() const;
-
- VehicleBody();
-};
-
-#endif // VEHICLE_BODY_H
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
new file mode 100644
index 0000000000..5c2fa59a21
--- /dev/null
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -0,0 +1,998 @@
+/*************************************************************************/
+/* vehicle_body_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "vehicle_body_3d.h"
+
+#define ROLLING_INFLUENCE_FIX
+
+class btVehicleJacobianEntry {
+public:
+ Vector3 m_linearJointAxis;
+ Vector3 m_aJ;
+ Vector3 m_bJ;
+ Vector3 m_0MinvJt;
+ Vector3 m_1MinvJt;
+ //Optimization: can be stored in the w/last component of one of the vectors
+ real_t m_Adiag;
+
+ real_t getDiagonal() const { return m_Adiag; }
+
+ btVehicleJacobianEntry(){};
+ //constraint between two different rigidbodies
+ btVehicleJacobianEntry(
+ const Basis &world2A,
+ const Basis &world2B,
+ const Vector3 &rel_pos1,
+ const Vector3 &rel_pos2,
+ const Vector3 &jointAxis,
+ const Vector3 &inertiaInvA,
+ const real_t massInvA,
+ const Vector3 &inertiaInvB,
+ const real_t massInvB) :
+ m_linearJointAxis(jointAxis) {
+ m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
+ m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
+
+ //btAssert(m_Adiag > real_t(0.0));
+ }
+
+ real_t getRelativeVelocity(const Vector3 &linvelA, const Vector3 &angvelA, const Vector3 &linvelB, const Vector3 &angvelB) {
+ Vector3 linrel = linvelA - linvelB;
+ Vector3 angvela = angvelA * m_aJ;
+ Vector3 angvelb = angvelB * m_bJ;
+ linrel *= m_linearJointAxis;
+ angvela += angvelb;
+ angvela += linrel;
+ real_t rel_vel2 = angvela[0] + angvela[1] + angvela[2];
+ return rel_vel2 + CMP_EPSILON;
+ }
+};
+
+void VehicleWheel3D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
+ if (!cb)
+ return;
+ body = cb;
+ local_xform = get_transform();
+ cb->wheels.push_back(this);
+
+ m_chassisConnectionPointCS = get_transform().origin;
+ m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
+ m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
+ }
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent());
+ if (!cb)
+ return;
+ cb->wheels.erase(this);
+ body = nullptr;
+ }
+}
+
+String VehicleWheel3D::get_configuration_warning() const {
+ if (!Object::cast_to<VehicleBody3D>(get_parent())) {
+ return TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.");
+ }
+
+ return String();
+}
+
+void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {
+
+ if (m_raycastInfo.m_isInContact)
+
+ {
+ real_t project = m_raycastInfo.m_contactNormalWS.dot(m_raycastInfo.m_wheelDirectionWS);
+ Vector3 chassis_velocity_at_contactPoint;
+ Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+ chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+ (s->get_angular_velocity()).cross(relpos); // * mPos);
+
+ real_t projVel = m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
+ if (project >= real_t(-0.1)) {
+ m_suspensionRelativeVelocity = real_t(0.0);
+ m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+ } else {
+ real_t inv = real_t(-1.) / project;
+ m_suspensionRelativeVelocity = projVel * inv;
+ m_clippedInvContactDotSuspension = inv;
+ }
+
+ }
+
+ else // Not in contact : position wheel in a nice (rest length) position
+ {
+ m_raycastInfo.m_suspensionLength = m_suspensionRestLength;
+ m_suspensionRelativeVelocity = real_t(0.0);
+ m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS;
+ m_clippedInvContactDotSuspension = real_t(1.0);
+ }
+}
+
+void VehicleWheel3D::set_radius(float p_radius) {
+
+ m_wheelRadius = p_radius;
+ update_gizmo();
+}
+
+float VehicleWheel3D::get_radius() const {
+
+ return m_wheelRadius;
+}
+
+void VehicleWheel3D::set_suspension_rest_length(float p_length) {
+
+ m_suspensionRestLength = p_length;
+ update_gizmo();
+}
+float VehicleWheel3D::get_suspension_rest_length() const {
+
+ return m_suspensionRestLength;
+}
+
+void VehicleWheel3D::set_suspension_travel(float p_length) {
+
+ m_maxSuspensionTravelCm = p_length / 0.01;
+}
+float VehicleWheel3D::get_suspension_travel() const {
+
+ return m_maxSuspensionTravelCm * 0.01;
+}
+
+void VehicleWheel3D::set_suspension_stiffness(float p_value) {
+
+ m_suspensionStiffness = p_value;
+}
+float VehicleWheel3D::get_suspension_stiffness() const {
+
+ return m_suspensionStiffness;
+}
+
+void VehicleWheel3D::set_suspension_max_force(float p_value) {
+
+ m_maxSuspensionForce = p_value;
+}
+float VehicleWheel3D::get_suspension_max_force() const {
+
+ return m_maxSuspensionForce;
+}
+
+void VehicleWheel3D::set_damping_compression(float p_value) {
+
+ m_wheelsDampingCompression = p_value;
+}
+float VehicleWheel3D::get_damping_compression() const {
+
+ return m_wheelsDampingCompression;
+}
+
+void VehicleWheel3D::set_damping_relaxation(float p_value) {
+
+ m_wheelsDampingRelaxation = p_value;
+}
+float VehicleWheel3D::get_damping_relaxation() const {
+
+ return m_wheelsDampingRelaxation;
+}
+
+void VehicleWheel3D::set_friction_slip(float p_value) {
+
+ m_frictionSlip = p_value;
+}
+float VehicleWheel3D::get_friction_slip() const {
+
+ return m_frictionSlip;
+}
+
+void VehicleWheel3D::set_roll_influence(float p_value) {
+ m_rollInfluence = p_value;
+}
+
+float VehicleWheel3D::get_roll_influence() const {
+ return m_rollInfluence;
+}
+
+bool VehicleWheel3D::is_in_contact() const {
+ return m_raycastInfo.m_isInContact;
+}
+
+void VehicleWheel3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_radius", "length"), &VehicleWheel3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &VehicleWheel3D::get_radius);
+
+ ClassDB::bind_method(D_METHOD("set_suspension_rest_length", "length"), &VehicleWheel3D::set_suspension_rest_length);
+ ClassDB::bind_method(D_METHOD("get_suspension_rest_length"), &VehicleWheel3D::get_suspension_rest_length);
+
+ ClassDB::bind_method(D_METHOD("set_suspension_travel", "length"), &VehicleWheel3D::set_suspension_travel);
+ ClassDB::bind_method(D_METHOD("get_suspension_travel"), &VehicleWheel3D::get_suspension_travel);
+
+ ClassDB::bind_method(D_METHOD("set_suspension_stiffness", "length"), &VehicleWheel3D::set_suspension_stiffness);
+ ClassDB::bind_method(D_METHOD("get_suspension_stiffness"), &VehicleWheel3D::get_suspension_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_suspension_max_force", "length"), &VehicleWheel3D::set_suspension_max_force);
+ ClassDB::bind_method(D_METHOD("get_suspension_max_force"), &VehicleWheel3D::get_suspension_max_force);
+
+ ClassDB::bind_method(D_METHOD("set_damping_compression", "length"), &VehicleWheel3D::set_damping_compression);
+ ClassDB::bind_method(D_METHOD("get_damping_compression"), &VehicleWheel3D::get_damping_compression);
+
+ ClassDB::bind_method(D_METHOD("set_damping_relaxation", "length"), &VehicleWheel3D::set_damping_relaxation);
+ ClassDB::bind_method(D_METHOD("get_damping_relaxation"), &VehicleWheel3D::get_damping_relaxation);
+
+ ClassDB::bind_method(D_METHOD("set_use_as_traction", "enable"), &VehicleWheel3D::set_use_as_traction);
+ ClassDB::bind_method(D_METHOD("is_used_as_traction"), &VehicleWheel3D::is_used_as_traction);
+
+ ClassDB::bind_method(D_METHOD("set_use_as_steering", "enable"), &VehicleWheel3D::set_use_as_steering);
+ ClassDB::bind_method(D_METHOD("is_used_as_steering"), &VehicleWheel3D::is_used_as_steering);
+
+ ClassDB::bind_method(D_METHOD("set_friction_slip", "length"), &VehicleWheel3D::set_friction_slip);
+ ClassDB::bind_method(D_METHOD("get_friction_slip"), &VehicleWheel3D::get_friction_slip);
+
+ ClassDB::bind_method(D_METHOD("is_in_contact"), &VehicleWheel3D::is_in_contact);
+
+ ClassDB::bind_method(D_METHOD("set_roll_influence", "roll_influence"), &VehicleWheel3D::set_roll_influence);
+ ClassDB::bind_method(D_METHOD("get_roll_influence"), &VehicleWheel3D::get_roll_influence);
+
+ ClassDB::bind_method(D_METHOD("get_skidinfo"), &VehicleWheel3D::get_skidinfo);
+
+ ClassDB::bind_method(D_METHOD("get_rpm"), &VehicleWheel3D::get_rpm);
+
+ ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleWheel3D::set_engine_force);
+ ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleWheel3D::get_engine_force);
+
+ ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleWheel3D::set_brake);
+ ClassDB::bind_method(D_METHOD("get_brake"), &VehicleWheel3D::get_brake);
+
+ ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleWheel3D::set_steering);
+ ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel3D::get_steering);
+
+ ADD_GROUP("Per-Wheel Motion", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
+ ADD_GROUP("VehicleBody3D Motion", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_traction"), "set_use_as_traction", "is_used_as_traction");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_as_steering"), "set_use_as_steering", "is_used_as_steering");
+ ADD_GROUP("Wheel", "wheel_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_roll_influence"), "set_roll_influence", "get_roll_influence");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_radius"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_rest_length"), "set_suspension_rest_length", "get_suspension_rest_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wheel_friction_slip"), "set_friction_slip", "get_friction_slip");
+ ADD_GROUP("Suspension", "suspension_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_travel"), "set_suspension_travel", "get_suspension_travel");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_stiffness"), "set_suspension_stiffness", "get_suspension_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "suspension_max_force"), "set_suspension_max_force", "get_suspension_max_force");
+ ADD_GROUP("Damping", "damping_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_compression"), "set_damping_compression", "get_damping_compression");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation");
+}
+
+void VehicleWheel3D::set_engine_force(float p_engine_force) {
+
+ m_engineForce = p_engine_force;
+}
+
+float VehicleWheel3D::get_engine_force() const {
+
+ return m_engineForce;
+}
+
+void VehicleWheel3D::set_brake(float p_brake) {
+
+ m_brake = p_brake;
+}
+float VehicleWheel3D::get_brake() const {
+
+ return m_brake;
+}
+
+void VehicleWheel3D::set_steering(float p_steering) {
+
+ m_steering = p_steering;
+}
+float VehicleWheel3D::get_steering() const {
+
+ return m_steering;
+}
+
+void VehicleWheel3D::set_use_as_traction(bool p_enable) {
+
+ engine_traction = p_enable;
+}
+
+bool VehicleWheel3D::is_used_as_traction() const {
+
+ return engine_traction;
+}
+
+void VehicleWheel3D::set_use_as_steering(bool p_enabled) {
+
+ steers = p_enabled;
+}
+
+bool VehicleWheel3D::is_used_as_steering() const {
+
+ return steers;
+}
+
+float VehicleWheel3D::get_skidinfo() const {
+
+ return m_skidInfo;
+}
+
+float VehicleWheel3D::get_rpm() const {
+
+ return m_rpm;
+}
+
+VehicleWheel3D::VehicleWheel3D() {
+
+ steers = false;
+ engine_traction = false;
+ m_steering = real_t(0.);
+ m_engineForce = real_t(0.);
+ m_rotation = real_t(0.);
+ m_deltaRotation = real_t(0.);
+ m_brake = real_t(0.);
+ m_rollInfluence = real_t(0.1);
+
+ m_suspensionRestLength = 0.15;
+ m_wheelRadius = 0.5; //0.28;
+ m_suspensionStiffness = 5.88;
+ m_wheelsDampingCompression = 0.83;
+ m_wheelsDampingRelaxation = 0.88;
+ m_frictionSlip = 10.5;
+ m_bIsFrontWheel = false;
+ m_maxSuspensionTravelCm = 500;
+ m_maxSuspensionForce = 6000;
+
+ m_suspensionRelativeVelocity = 0;
+ m_clippedInvContactDotSuspension = 1.0;
+ m_raycastInfo.m_isInContact = false;
+
+ body = nullptr;
+}
+
+void VehicleBody3D::_update_wheel_transform(VehicleWheel3D &wheel, PhysicsDirectBodyState3D *s) {
+
+ wheel.m_raycastInfo.m_isInContact = false;
+
+ Transform chassisTrans = s->get_transform();
+ /*
+ if (interpolatedTransform && (getRigidBody()->getMotionState())) {
+ getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
+ }
+ */
+
+ wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform(wheel.m_chassisConnectionPointCS);
+ //wheel.m_raycastInfo.m_hardPointWS+=s->get_linear_velocity()*s->get_step();
+ wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform(wheel.m_wheelDirectionCS).normalized();
+ wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform(wheel.m_wheelAxleCS).normalized();
+}
+
+void VehicleBody3D::_update_wheel(int p_idx, PhysicsDirectBodyState3D *s) {
+
+ VehicleWheel3D &wheel = *wheels[p_idx];
+ _update_wheel_transform(wheel, s);
+
+ Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
+ const Vector3 &right = wheel.m_raycastInfo.m_wheelAxleWS;
+ Vector3 fwd = up.cross(right);
+ fwd = fwd.normalized();
+
+ Basis steeringMat(up, wheel.m_steering);
+
+ Basis rotatingMat(right, wheel.m_rotation);
+
+ Basis basis2(
+ right[0], up[0], fwd[0],
+ right[1], up[1], fwd[1],
+ right[2], up[2], fwd[2]);
+
+ wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2);
+ //wheel.m_worldTransform.set_basis(basis2 * (steeringMat * rotatingMat));
+ wheel.m_worldTransform.set_origin(
+ wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength);
+}
+
+real_t VehicleBody3D::_ray_cast(int p_idx, PhysicsDirectBodyState3D *s) {
+
+ VehicleWheel3D &wheel = *wheels[p_idx];
+
+ _update_wheel_transform(wheel, s);
+
+ real_t depth = -1;
+
+ real_t raylen = wheel.m_suspensionRestLength + wheel.m_wheelRadius;
+
+ Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
+ Vector3 source = wheel.m_raycastInfo.m_hardPointWS;
+ wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
+ const Vector3 &target = wheel.m_raycastInfo.m_contactPointWS;
+ source -= wheel.m_wheelRadius * wheel.m_raycastInfo.m_wheelDirectionWS;
+
+ real_t param = real_t(0.);
+
+ PhysicsDirectSpaceState3D::RayResult rr;
+
+ PhysicsDirectSpaceState3D *ss = s->get_space_state();
+
+ bool col = ss->intersect_ray(source, target, rr, exclude);
+
+ wheel.m_raycastInfo.m_groundObject = nullptr;
+
+ if (col) {
+ param = source.distance_to(rr.position) / source.distance_to(target);
+ depth = raylen * param;
+ wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
+
+ wheel.m_raycastInfo.m_isInContact = true;
+ if (rr.collider)
+ wheel.m_raycastInfo.m_groundObject = Object::cast_to<PhysicsBody3D>(rr.collider);
+
+ real_t hitDistance = param * raylen;
+ wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius;
+ //clamp on max suspension travel
+
+ real_t minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm * real_t(0.01);
+ real_t maxSuspensionLength = wheel.m_suspensionRestLength + wheel.m_maxSuspensionTravelCm * real_t(0.01);
+ if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) {
+ wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
+ }
+ if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) {
+ wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
+ }
+
+ wheel.m_raycastInfo.m_contactPointWS = rr.position;
+
+ real_t denominator = wheel.m_raycastInfo.m_contactNormalWS.dot(wheel.m_raycastInfo.m_wheelDirectionWS);
+
+ Vector3 chassis_velocity_at_contactPoint;
+ //Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition();
+
+ //chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
+
+ chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+ (s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin); // * mPos);
+
+ real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot(chassis_velocity_at_contactPoint);
+
+ if (denominator >= real_t(-0.1)) {
+ wheel.m_suspensionRelativeVelocity = real_t(0.0);
+ wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+ } else {
+ real_t inv = real_t(-1.) / denominator;
+ wheel.m_suspensionRelativeVelocity = projVel * inv;
+ wheel.m_clippedInvContactDotSuspension = inv;
+ }
+
+ } else {
+ wheel.m_raycastInfo.m_isInContact = false;
+ //put wheel info as in rest position
+ wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength;
+ wheel.m_suspensionRelativeVelocity = real_t(0.0);
+ wheel.m_raycastInfo.m_contactNormalWS = -wheel.m_raycastInfo.m_wheelDirectionWS;
+ wheel.m_clippedInvContactDotSuspension = real_t(1.0);
+ }
+
+ return depth;
+}
+
+void VehicleBody3D::_update_suspension(PhysicsDirectBodyState3D *s) {
+
+ real_t chassisMass = mass;
+
+ for (int w_it = 0; w_it < wheels.size(); w_it++) {
+ VehicleWheel3D &wheel_info = *wheels[w_it];
+
+ if (wheel_info.m_raycastInfo.m_isInContact) {
+ real_t force;
+ //Spring
+ {
+ real_t susp_length = wheel_info.m_suspensionRestLength;
+ real_t current_length = wheel_info.m_raycastInfo.m_suspensionLength;
+
+ real_t length_diff = (susp_length - current_length);
+
+ force = wheel_info.m_suspensionStiffness * length_diff * wheel_info.m_clippedInvContactDotSuspension;
+ }
+
+ // Damper
+ {
+ real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
+ {
+ real_t susp_damping;
+ if (projected_rel_vel < real_t(0.0)) {
+ susp_damping = wheel_info.m_wheelsDampingCompression;
+ } else {
+ susp_damping = wheel_info.m_wheelsDampingRelaxation;
+ }
+ force -= susp_damping * projected_rel_vel;
+ }
+ }
+
+ // RESULT
+ wheel_info.m_wheelsSuspensionForce = force * chassisMass;
+ if (wheel_info.m_wheelsSuspensionForce < real_t(0.)) {
+ wheel_info.m_wheelsSuspensionForce = real_t(0.);
+ }
+ } else {
+ wheel_info.m_wheelsSuspensionForce = real_t(0.0);
+ }
+ }
+}
+
+//bilateral constraint between two dynamic objects
+void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const Vector3 &pos1,
+ PhysicsBody3D *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) {
+
+ real_t normalLenSqr = normal.length_squared();
+ //ERR_FAIL_COND( normalLenSqr < real_t(1.1));
+
+ if (normalLenSqr > real_t(1.1)) {
+ impulse = real_t(0.);
+ return;
+ }
+
+ Vector3 rel_pos1 = pos1 - s->get_transform().origin;
+ Vector3 rel_pos2;
+ if (body2)
+ rel_pos2 = pos2 - body2->get_global_transform().origin;
+ //this jacobian entry could be re-used for all iterations
+
+ Vector3 vel1 = s->get_linear_velocity() + (s->get_angular_velocity()).cross(rel_pos1); // * mPos);
+ Vector3 vel2;
+
+ if (body2)
+ vel2 = body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2);
+
+ Vector3 vel = vel1 - vel2;
+
+ Basis b2trans;
+ float b2invmass = 0;
+ Vector3 b2lv;
+ Vector3 b2av;
+ Vector3 b2invinertia; //todo
+
+ if (body2) {
+ b2trans = body2->get_global_transform().basis.transposed();
+ b2invmass = body2->get_inverse_mass();
+ b2lv = body2->get_linear_velocity();
+ b2av = body2->get_angular_velocity();
+ }
+
+ btVehicleJacobianEntry jac(s->get_transform().basis.transposed(),
+ b2trans,
+ rel_pos1,
+ rel_pos2,
+ normal,
+ s->get_inverse_inertia_tensor().get_main_diagonal(),
+ 1.0 / mass,
+ b2invinertia,
+ 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);
+ // Investigate why.
+ real_t rel_vel = jac.getRelativeVelocity(
+ s->get_linear_velocity(),
+ s->get_transform().basis.transposed().xform(s->get_angular_velocity()),
+ b2lv,
+ b2trans.xform(b2av));
+
+ rel_vel = normal.dot(vel);
+
+ // !BAS! We had this set to 0.4, in bullet its 0.2
+ real_t contactDamping = real_t(0.2);
+
+ if (p_rollInfluence > 0.0) {
+ // !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based
+ // keeping in mind our anti roll factor if it is set
+ contactDamping = MIN(contactDamping, s->get_step() / p_rollInfluence);
+ }
+
+#define ONLY_USE_LINEAR_MASS
+#ifdef ONLY_USE_LINEAR_MASS
+ real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
+ impulse = -contactDamping * rel_vel * massTerm;
+#else
+ real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
+ impulse = velocityImpulse;
+#endif
+}
+
+VehicleBody3D::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState3D *s, PhysicsBody3D *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse) :
+ m_s(s),
+ m_body1(body1),
+ m_frictionPositionWorld(frictionPosWorld),
+ m_frictionDirectionWorld(frictionDirectionWorld),
+ m_maxImpulse(maxImpulse) {
+ float denom0 = 0;
+ float denom1 = 0;
+
+ {
+ Vector3 r0 = frictionPosWorld - s->get_transform().origin;
+ Vector3 c0 = (r0).cross(frictionDirectionWorld);
+ Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+ denom0 = s->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+ }
+
+ /* TODO: Why is this code unused?
+ if (body1) {
+
+ Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
+ Vector3 c0 = (r0).cross(frictionDirectionWorld);
+ Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+ //denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+
+ }
+ */
+
+ real_t relaxation = 1.f;
+ m_jacDiagABInv = relaxation / (denom0 + denom1);
+}
+
+real_t VehicleBody3D::_calc_rolling_friction(btVehicleWheelContactPoint &contactPoint) {
+
+ real_t j1 = 0.f;
+
+ const Vector3 &contactPosWorld = contactPoint.m_frictionPositionWorld;
+
+ Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin;
+ Vector3 rel_pos2;
+ if (contactPoint.m_body1)
+ rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin;
+
+ real_t maxImpulse = contactPoint.m_maxImpulse;
+
+ Vector3 vel1 = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1); // * mPos);
+
+ Vector3 vel2;
+ if (contactPoint.m_body1) {
+ vel2 = contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2);
+ }
+
+ Vector3 vel = vel1 - vel2;
+
+ real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
+
+ // calculate j that moves us to zero relative velocity
+ j1 = -vrel * contactPoint.m_jacDiagABInv;
+
+ return CLAMP(j1, -maxImpulse, maxImpulse);
+}
+
+static const real_t sideFrictionStiffness2 = real_t(1.0);
+void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
+
+ //calculate the impulse, so that the wheels don't move sidewards
+ int numWheel = wheels.size();
+ if (!numWheel)
+ return;
+
+ m_forwardWS.resize(numWheel);
+ m_axle.resize(numWheel);
+ m_forwardImpulse.resize(numWheel);
+ m_sideImpulse.resize(numWheel);
+
+ //collapse all those loops into one!
+ for (int i = 0; i < wheels.size(); i++) {
+ m_sideImpulse.write[i] = real_t(0.);
+ m_forwardImpulse.write[i] = real_t(0.);
+ }
+
+ {
+
+ for (int i = 0; i < wheels.size(); i++) {
+
+ VehicleWheel3D &wheelInfo = *wheels[i];
+
+ if (wheelInfo.m_raycastInfo.m_isInContact) {
+
+ //const btTransform& wheelTrans = getWheelTransformWS( i );
+
+ Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis;
+
+ m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
+ //m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
+
+ const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
+ real_t proj = m_axle[i].dot(surfNormalWS);
+ m_axle.write[i] -= surfNormalWS * proj;
+ m_axle.write[i] = m_axle[i].normalized();
+
+ m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]);
+ m_forwardWS.write[i].normalize();
+
+ _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
+ wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
+ m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence);
+
+ m_sideImpulse.write[i] *= sideFrictionStiffness2;
+ }
+ }
+ }
+
+ real_t sideFactor = real_t(1.);
+ real_t fwdFactor = 0.5;
+
+ bool sliding = false;
+ {
+ for (int wheel = 0; wheel < wheels.size(); wheel++) {
+ VehicleWheel3D &wheelInfo = *wheels[wheel];
+
+ //class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
+
+ real_t rollingFriction = 0.f;
+
+ if (wheelInfo.m_raycastInfo.m_isInContact) {
+ if (wheelInfo.m_engineForce != 0.f) {
+ rollingFriction = -wheelInfo.m_engineForce * s->get_step();
+ } else {
+ real_t defaultRollingFrictionImpulse = 0.f;
+ real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
+ btVehicleWheelContactPoint contactPt(s, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, m_forwardWS[wheel], maxImpulse);
+ rollingFriction = _calc_rolling_friction(contactPt);
+ }
+ }
+
+ //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
+
+ m_forwardImpulse.write[wheel] = real_t(0.);
+ wheelInfo.m_skidInfo = real_t(1.);
+
+ if (wheelInfo.m_raycastInfo.m_isInContact) {
+ wheelInfo.m_skidInfo = real_t(1.);
+
+ real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip;
+ real_t maximpSide = maximp;
+
+ real_t maximpSquared = maximp * maximpSide;
+
+ m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
+
+ real_t x = (m_forwardImpulse[wheel]) * fwdFactor;
+ real_t y = (m_sideImpulse[wheel]) * sideFactor;
+
+ real_t impulseSquared = (x * x + y * y);
+
+ if (impulseSquared > maximpSquared) {
+ sliding = true;
+
+ real_t factor = maximp / Math::sqrt(impulseSquared);
+
+ wheelInfo.m_skidInfo *= factor;
+ }
+ }
+ }
+ }
+
+ if (sliding) {
+ for (int wheel = 0; wheel < wheels.size(); wheel++) {
+ if (m_sideImpulse[wheel] != real_t(0.)) {
+ if (wheels[wheel]->m_skidInfo < real_t(1.)) {
+ m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
+ m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
+ }
+ }
+ }
+ }
+
+ // apply the impulses
+ {
+ for (int wheel = 0; wheel < wheels.size(); wheel++) {
+ VehicleWheel3D &wheelInfo = *wheels[wheel];
+
+ Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
+ s->get_transform().origin;
+
+ if (m_forwardImpulse[wheel] != real_t(0.)) {
+ s->apply_impulse(rel_pos, m_forwardWS[wheel] * (m_forwardImpulse[wheel]));
+ }
+ if (m_sideImpulse[wheel] != real_t(0.)) {
+ PhysicsBody3D *groundObject = wheelInfo.m_raycastInfo.m_groundObject;
+
+ Vector3 rel_pos2;
+ if (groundObject) {
+ rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin;
+ }
+
+ Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
+
+#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
+ Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
+ rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence));
+#else
+ rel_pos[1] *= wheelInfo.m_rollInfluence; //?
+#endif
+ s->apply_impulse(rel_pos, sideImp);
+
+ //apply friction impulse on the ground
+ //todo
+ //groundObject->applyImpulse(-sideImp,rel_pos2);
+ }
+ }
+ }
+}
+
+void VehicleBody3D::_direct_state_changed(Object *p_state) {
+
+ RigidBody3D::_direct_state_changed(p_state);
+
+ state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+
+ float step = state->get_step();
+
+ for (int i = 0; i < wheels.size(); i++) {
+
+ _update_wheel(i, state);
+ }
+
+ for (int i = 0; i < wheels.size(); i++) {
+
+ _ray_cast(i, state);
+ wheels[i]->set_transform(state->get_transform().inverse() * wheels[i]->m_worldTransform);
+ }
+
+ _update_suspension(state);
+
+ for (int i = 0; i < wheels.size(); i++) {
+
+ //apply suspension force
+ VehicleWheel3D &wheel = *wheels[i];
+
+ real_t suspensionForce = wheel.m_wheelsSuspensionForce;
+
+ if (suspensionForce > wheel.m_maxSuspensionForce) {
+ suspensionForce = wheel.m_maxSuspensionForce;
+ }
+ Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
+ Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - state->get_transform().origin;
+
+ state->apply_impulse(relpos, impulse);
+ //getRigidBody()->applyImpulse(impulse, relpos);
+ }
+
+ _update_friction(state);
+
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel3D &wheel = *wheels[i];
+ Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - state->get_transform().origin;
+ Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
+
+ if (wheel.m_raycastInfo.m_isInContact) {
+ const Transform &chassisWorldTransform = state->get_transform();
+
+ Vector3 fwd(
+ chassisWorldTransform.basis[0][Vector3::AXIS_Z],
+ chassisWorldTransform.basis[1][Vector3::AXIS_Z],
+ chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
+
+ real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
+ fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
+
+ real_t proj2 = fwd.dot(vel);
+
+ wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
+ }
+
+ wheel.m_rotation += wheel.m_deltaRotation;
+ wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU;
+
+ wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
+ }
+
+ state = nullptr;
+}
+
+void VehicleBody3D::set_engine_force(float p_engine_force) {
+
+ engine_force = p_engine_force;
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel3D &wheelInfo = *wheels[i];
+ if (wheelInfo.engine_traction)
+ wheelInfo.m_engineForce = p_engine_force;
+ }
+}
+
+float VehicleBody3D::get_engine_force() const {
+
+ return engine_force;
+}
+
+void VehicleBody3D::set_brake(float p_brake) {
+
+ brake = p_brake;
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel3D &wheelInfo = *wheels[i];
+ wheelInfo.m_brake = p_brake;
+ }
+}
+float VehicleBody3D::get_brake() const {
+
+ return brake;
+}
+
+void VehicleBody3D::set_steering(float p_steering) {
+
+ m_steeringValue = p_steering;
+ for (int i = 0; i < wheels.size(); i++) {
+ VehicleWheel3D &wheelInfo = *wheels[i];
+ if (wheelInfo.steers)
+ wheelInfo.m_steering = p_steering;
+ }
+}
+float VehicleBody3D::get_steering() const {
+
+ return m_steeringValue;
+}
+
+void VehicleBody3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleBody3D::set_engine_force);
+ ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleBody3D::get_engine_force);
+
+ ClassDB::bind_method(D_METHOD("set_brake", "brake"), &VehicleBody3D::set_brake);
+ ClassDB::bind_method(D_METHOD("get_brake"), &VehicleBody3D::get_brake);
+
+ ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleBody3D::set_steering);
+ ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody3D::get_steering);
+
+ ADD_GROUP("Motion", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
+}
+
+VehicleBody3D::VehicleBody3D() {
+
+ m_pitchControl = 0;
+ m_currentVehicleSpeedKmHour = real_t(0.);
+ m_steeringValue = real_t(0.);
+
+ engine_force = 0;
+ brake = 0;
+
+ state = nullptr;
+ ccd = false;
+
+ exclude.insert(get_rid());
+ //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+
+ set_mass(40);
+}
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
new file mode 100644
index 0000000000..d5e896263d
--- /dev/null
+++ b/scene/3d/vehicle_body_3d.h
@@ -0,0 +1,212 @@
+/*************************************************************************/
+/* vehicle_body_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VEHICLE_BODY_H
+#define VEHICLE_BODY_H
+
+#include "scene/3d/physics_body_3d.h"
+
+class VehicleBody3D;
+
+class VehicleWheel3D : public Node3D {
+
+ GDCLASS(VehicleWheel3D, Node3D);
+
+ friend class VehicleBody3D;
+
+ Transform m_worldTransform;
+ Transform local_xform;
+ bool engine_traction;
+ bool steers;
+
+ Vector3 m_chassisConnectionPointCS; //const
+ Vector3 m_wheelDirectionCS; //const
+ Vector3 m_wheelAxleCS; // const or modified by steering
+
+ real_t m_suspensionRestLength;
+ real_t m_maxSuspensionTravelCm;
+ real_t m_wheelRadius;
+
+ real_t m_suspensionStiffness;
+ real_t m_wheelsDampingCompression;
+ real_t m_wheelsDampingRelaxation;
+ real_t m_frictionSlip;
+ real_t m_maxSuspensionForce;
+ bool m_bIsFrontWheel;
+
+ VehicleBody3D *body;
+
+ //btVector3 m_wheelAxleCS; // const or modified by steering ?
+
+ real_t m_steering;
+ real_t m_rotation;
+ real_t m_deltaRotation;
+ real_t m_rpm;
+ real_t m_rollInfluence;
+ real_t m_engineForce;
+ real_t m_brake;
+
+ real_t m_clippedInvContactDotSuspension;
+ real_t m_suspensionRelativeVelocity;
+ //calculated by suspension
+ real_t m_wheelsSuspensionForce;
+ real_t m_skidInfo;
+
+ struct RaycastInfo {
+ //set by raycaster
+ Vector3 m_contactNormalWS; //contactnormal
+ Vector3 m_contactPointWS; //raycast hitpoint
+ real_t m_suspensionLength;
+ Vector3 m_hardPointWS; //raycast starting point
+ Vector3 m_wheelDirectionWS; //direction in worldspace
+ Vector3 m_wheelAxleWS; // axle in worldspace
+ bool m_isInContact;
+ PhysicsBody3D *m_groundObject; //could be general void* ptr
+ } m_raycastInfo;
+
+ void _update(PhysicsDirectBodyState3D *s);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+
+ void set_suspension_rest_length(float p_length);
+ float get_suspension_rest_length() const;
+
+ void set_suspension_travel(float p_length);
+ float get_suspension_travel() const;
+
+ void set_suspension_stiffness(float p_value);
+ float get_suspension_stiffness() const;
+
+ void set_suspension_max_force(float p_value);
+ float get_suspension_max_force() const;
+
+ void set_damping_compression(float p_value);
+ float get_damping_compression() const;
+
+ void set_damping_relaxation(float p_value);
+ float get_damping_relaxation() const;
+
+ void set_friction_slip(float p_value);
+ float get_friction_slip() const;
+
+ void set_use_as_traction(bool p_enable);
+ bool is_used_as_traction() const;
+
+ void set_use_as_steering(bool p_enabled);
+ bool is_used_as_steering() const;
+
+ bool is_in_contact() const;
+
+ void set_roll_influence(float p_value);
+ float get_roll_influence() const;
+
+ float get_skidinfo() const;
+
+ float get_rpm() const;
+
+ void set_engine_force(float p_engine_force);
+ float get_engine_force() const;
+
+ void set_brake(float p_brake);
+ float get_brake() const;
+
+ void set_steering(float p_steering);
+ float get_steering() const;
+
+ String get_configuration_warning() const;
+
+ VehicleWheel3D();
+};
+
+class VehicleBody3D : public RigidBody3D {
+
+ GDCLASS(VehicleBody3D, RigidBody3D);
+
+ float engine_force;
+ float brake;
+
+ real_t m_pitchControl;
+ real_t m_steeringValue;
+ real_t m_currentVehicleSpeedKmHour;
+
+ Set<RID> exclude;
+
+ Vector<Vector3> m_forwardWS;
+ Vector<Vector3> m_axle;
+ Vector<real_t> m_forwardImpulse;
+ Vector<real_t> m_sideImpulse;
+
+ struct btVehicleWheelContactPoint {
+ PhysicsDirectBodyState3D *m_s;
+ PhysicsBody3D *m_body1;
+ Vector3 m_frictionPositionWorld;
+ Vector3 m_frictionDirectionWorld;
+ real_t m_jacDiagABInv;
+ real_t m_maxImpulse;
+
+ btVehicleWheelContactPoint(PhysicsDirectBodyState3D *s, PhysicsBody3D *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse);
+ };
+
+ void _resolve_single_bilateral(PhysicsDirectBodyState3D *s, const Vector3 &pos1, PhysicsBody3D *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence);
+ real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
+
+ void _update_friction(PhysicsDirectBodyState3D *s);
+ void _update_suspension(PhysicsDirectBodyState3D *s);
+ real_t _ray_cast(int p_idx, PhysicsDirectBodyState3D *s);
+ void _update_wheel_transform(VehicleWheel3D &wheel, PhysicsDirectBodyState3D *s);
+ void _update_wheel(int p_idx, PhysicsDirectBodyState3D *s);
+
+ friend class VehicleWheel3D;
+ Vector<VehicleWheel3D *> wheels;
+
+ static void _bind_methods();
+
+ void _direct_state_changed(Object *p_state);
+
+public:
+ void set_engine_force(float p_engine_force);
+ float get_engine_force() const;
+
+ void set_brake(float p_brake);
+ float get_brake() const;
+
+ void set_steering(float p_steering);
+ float get_steering() const;
+
+ VehicleBody3D();
+};
+
+#endif // VEHICLE_BODY_H
diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp
new file mode 100644
index 0000000000..c9b95e6397
--- /dev/null
+++ b/scene/3d/velocity_tracker_3d.cpp
@@ -0,0 +1,136 @@
+/*************************************************************************/
+/* velocity_tracker_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "velocity_tracker_3d.h"
+#include "core/engine.h"
+
+void VelocityTracker3D::set_track_physics_step(bool p_track_physics_step) {
+
+ physics_step = p_track_physics_step;
+}
+
+bool VelocityTracker3D::is_tracking_physics_step() const {
+
+ return physics_step;
+}
+void VelocityTracker3D::update_position(const Vector3 &p_position) {
+
+ PositionHistory ph;
+ ph.position = p_position;
+ if (physics_step) {
+ ph.frame = Engine::get_singleton()->get_physics_frames();
+ } else {
+ ph.frame = Engine::get_singleton()->get_idle_frame_ticks();
+ }
+
+ if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest
+ position_history_len = MIN(position_history.size(), position_history_len + 1);
+ for (int i = position_history_len - 1; i > 0; i--) {
+ position_history.write[i] = position_history[i - 1];
+ }
+ }
+
+ position_history.write[0] = ph;
+}
+Vector3 VelocityTracker3D::get_tracked_linear_velocity() const {
+
+ Vector3 linear_velocity;
+
+ float max_time = 1 / 5.0; //maximum time to interpolate a velocity
+
+ Vector3 distance_accum;
+ float time_accum = 0.0;
+ float base_time = 0.0;
+
+ if (position_history_len) {
+ if (physics_step) {
+ uint64_t base = Engine::get_singleton()->get_physics_frames();
+ base_time = float(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second();
+ } else {
+ uint64_t base = Engine::get_singleton()->get_idle_frame_ticks();
+ base_time = double(base - position_history[0].frame) / 1000000.0;
+ }
+ }
+
+ for (int i = 0; i < position_history_len - 1; i++) {
+ float delta = 0.0;
+ uint64_t diff = position_history[i].frame - position_history[i + 1].frame;
+ Vector3 distance = position_history[i].position - position_history[i + 1].position;
+
+ if (physics_step) {
+ delta = float(diff) / Engine::get_singleton()->get_iterations_per_second();
+ } else {
+ delta = double(diff) / 1000000.0;
+ }
+
+ if (base_time + time_accum + delta > max_time)
+ break;
+
+ distance_accum += distance;
+ time_accum += delta;
+ }
+
+ if (time_accum) {
+ linear_velocity = distance_accum / time_accum;
+ }
+
+ return linear_velocity;
+}
+
+void VelocityTracker3D::reset(const Vector3 &p_new_pos) {
+
+ PositionHistory ph;
+ ph.position = p_new_pos;
+ if (physics_step) {
+ ph.frame = Engine::get_singleton()->get_physics_frames();
+ } else {
+ ph.frame = Engine::get_singleton()->get_idle_frame_ticks();
+ }
+
+ position_history.write[0] = ph;
+ position_history_len = 1;
+}
+
+void VelocityTracker3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_track_physics_step", "enable"), &VelocityTracker3D::set_track_physics_step);
+ ClassDB::bind_method(D_METHOD("is_tracking_physics_step"), &VelocityTracker3D::is_tracking_physics_step);
+ ClassDB::bind_method(D_METHOD("update_position", "position"), &VelocityTracker3D::update_position);
+ ClassDB::bind_method(D_METHOD("get_tracked_linear_velocity"), &VelocityTracker3D::get_tracked_linear_velocity);
+ ClassDB::bind_method(D_METHOD("reset", "position"), &VelocityTracker3D::reset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "track_physics_step"), "set_track_physics_step", "is_tracking_physics_step");
+}
+
+VelocityTracker3D::VelocityTracker3D() {
+ position_history.resize(4); // should be configurable
+ position_history_len = 0;
+ physics_step = false;
+}
diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h
new file mode 100644
index 0000000000..a7ab3dce4d
--- /dev/null
+++ b/scene/3d/velocity_tracker_3d.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* velocity_tracker_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPATIAL_VELOCITY_TRACKER_H
+#define SPATIAL_VELOCITY_TRACKER_H
+
+#include "scene/3d/node_3d.h"
+
+class VelocityTracker3D : public Reference {
+ GDCLASS(VelocityTracker3D, Reference);
+
+ struct PositionHistory {
+ uint64_t frame;
+ Vector3 position;
+ };
+
+ bool physics_step;
+ Vector<PositionHistory> position_history;
+ int position_history_len;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void reset(const Vector3 &p_new_pos);
+ void set_track_physics_step(bool p_track_physics_step);
+ bool is_tracking_physics_step() const;
+ void update_position(const Vector3 &p_position);
+ Vector3 get_tracked_linear_velocity() const;
+
+ VelocityTracker3D();
+};
+
+#endif // SPATIAL_VELOCITY_TRACKER_H
diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp
deleted file mode 100644
index 986607f18d..0000000000
--- a/scene/3d/visibility_notifier.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*************************************************************************/
-/* visibility_notifier.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visibility_notifier.h"
-
-#include "core/engine.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/physics_body.h"
-#include "scene/animation/animation_player.h"
-#include "scene/scene_string_names.h"
-
-void VisibilityNotifier::_enter_camera(Camera *p_camera) {
-
- ERR_FAIL_COND(cameras.has(p_camera));
- cameras.insert(p_camera);
- if (cameras.size() == 1) {
- emit_signal(SceneStringNames::get_singleton()->screen_entered);
- _screen_enter();
- }
-
- emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera);
-}
-
-void VisibilityNotifier::_exit_camera(Camera *p_camera) {
-
- ERR_FAIL_COND(!cameras.has(p_camera));
- cameras.erase(p_camera);
-
- emit_signal(SceneStringNames::get_singleton()->camera_exited, p_camera);
- if (cameras.size() == 0) {
- emit_signal(SceneStringNames::get_singleton()->screen_exited);
-
- _screen_exit();
- }
-}
-
-void VisibilityNotifier::set_aabb(const AABB &p_aabb) {
-
- if (aabb == p_aabb)
- return;
- aabb = p_aabb;
-
- if (is_inside_world()) {
- get_world()->_update_notifier(this, get_global_transform().xform(aabb));
- }
-
- _change_notify("aabb");
- update_gizmo();
-}
-
-AABB VisibilityNotifier::get_aabb() const {
-
- return aabb;
-}
-
-void VisibilityNotifier::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_ENTER_WORLD: {
-
- get_world()->_register_notifier(this, get_global_transform().xform(aabb));
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- get_world()->_update_notifier(this, get_global_transform().xform(aabb));
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- get_world()->_remove_notifier(this);
- } break;
- }
-}
-
-bool VisibilityNotifier::is_on_screen() const {
-
- return cameras.size() != 0;
-}
-
-void VisibilityNotifier::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibilityNotifier::set_aabb);
- ClassDB::bind_method(D_METHOD("get_aabb"), &VisibilityNotifier::get_aabb);
- ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibilityNotifier::is_on_screen);
-
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb");
-
- ADD_SIGNAL(MethodInfo("camera_entered", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera")));
- ADD_SIGNAL(MethodInfo("camera_exited", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera")));
- ADD_SIGNAL(MethodInfo("screen_entered"));
- ADD_SIGNAL(MethodInfo("screen_exited"));
-}
-
-VisibilityNotifier::VisibilityNotifier() {
-
- aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
- set_notify_transform(true);
-}
-
-//////////////////////////////////////
-
-void VisibilityEnabler::_screen_enter() {
-
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
-
- _change_node_state(E->key(), true);
- }
-
- visible = true;
-}
-
-void VisibilityEnabler::_screen_exit() {
-
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
-
- _change_node_state(E->key(), false);
- }
-
- visible = false;
-}
-
-void VisibilityEnabler::_find_nodes(Node *p_node) {
-
- bool add = false;
- Variant meta;
-
- if (enabler[ENABLER_FREEZE_BODIES]) {
-
- RigidBody *rb = Object::cast_to<RigidBody>(p_node);
- if (rb && ((rb->get_mode() == RigidBody::MODE_CHARACTER || rb->get_mode() == RigidBody::MODE_RIGID))) {
-
- add = true;
- meta = rb->get_mode();
- }
- }
-
- if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
-
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
- if (ap) {
- add = true;
- }
- }
-
- if (add) {
-
- p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler::_node_removed), varray(p_node), CONNECT_ONESHOT);
- nodes[p_node] = meta;
- _change_node_state(p_node, false);
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- Node *c = p_node->get_child(i);
- if (c->get_filename() != String())
- continue; //skip, instance
-
- _find_nodes(c);
- }
-}
-
-void VisibilityEnabler::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
-
- if (Engine::get_singleton()->is_editor_hint())
- return;
-
- Node *from = this;
- //find where current scene starts
- while (from->get_parent() && from->get_filename() == String())
- from = from->get_parent();
-
- _find_nodes(from);
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
-
- if (Engine::get_singleton()->is_editor_hint())
- return;
-
- for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
-
- if (!visible)
- _change_node_state(E->key(), true);
- E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler::_node_removed));
- }
-
- nodes.clear();
- }
-}
-
-void VisibilityEnabler::_change_node_state(Node *p_node, bool p_enabled) {
-
- ERR_FAIL_COND(!nodes.has(p_node));
-
- {
- RigidBody *rb = Object::cast_to<RigidBody>(p_node);
- if (rb)
-
- rb->set_sleeping(!p_enabled);
- }
-
- {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
-
- if (ap) {
-
- ap->set_active(p_enabled);
- }
- }
-}
-
-void VisibilityEnabler::_node_removed(Node *p_node) {
-
- if (!visible)
- _change_node_state(p_node, true);
- nodes.erase(p_node);
-}
-
-void VisibilityEnabler::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler::set_enabler);
- ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler::is_enabler_enabled);
-
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES);
-
- BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
- BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
- BIND_ENUM_CONSTANT(ENABLER_MAX);
-}
-
-void VisibilityEnabler::set_enabler(Enabler p_enabler, bool p_enable) {
-
- ERR_FAIL_INDEX(p_enabler, ENABLER_MAX);
- enabler[p_enabler] = p_enable;
-}
-bool VisibilityEnabler::is_enabler_enabled(Enabler p_enabler) const {
-
- ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false);
- return enabler[p_enabler];
-}
-
-VisibilityEnabler::VisibilityEnabler() {
-
- for (int i = 0; i < ENABLER_MAX; i++)
- enabler[i] = true;
-
- visible = false;
-}
diff --git a/scene/3d/visibility_notifier.h b/scene/3d/visibility_notifier.h
deleted file mode 100644
index 71fdfdb78c..0000000000
--- a/scene/3d/visibility_notifier.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*************************************************************************/
-/* visibility_notifier.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISIBILITY_NOTIFIER_H
-#define VISIBILITY_NOTIFIER_H
-
-#include "scene/3d/spatial.h"
-
-class Camera;
-class VisibilityNotifier : public Spatial {
-
- GDCLASS(VisibilityNotifier, Spatial);
-
- Set<Camera *> cameras;
-
- AABB aabb;
-
-protected:
- virtual void _screen_enter() {}
- virtual void _screen_exit() {}
-
- void _notification(int p_what);
- static void _bind_methods();
- friend struct SpatialIndexer;
-
- void _enter_camera(Camera *p_camera);
- void _exit_camera(Camera *p_camera);
-
-public:
- void set_aabb(const AABB &p_aabb);
- AABB get_aabb() const;
- bool is_on_screen() const;
-
- VisibilityNotifier();
-};
-
-class VisibilityEnabler : public VisibilityNotifier {
-
- GDCLASS(VisibilityEnabler, VisibilityNotifier);
-
-public:
- enum Enabler {
- ENABLER_PAUSE_ANIMATIONS,
- ENABLER_FREEZE_BODIES,
- ENABLER_MAX
- };
-
-protected:
- virtual void _screen_enter();
- virtual void _screen_exit();
-
- bool visible;
-
- void _find_nodes(Node *p_node);
-
- Map<Node *, Variant> nodes;
- void _node_removed(Node *p_node);
- bool enabler[ENABLER_MAX];
-
- void _change_node_state(Node *p_node, bool p_enabled);
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_enabler(Enabler p_enabler, bool p_enable);
- bool is_enabler_enabled(Enabler p_enabler) const;
-
- VisibilityEnabler();
-};
-
-VARIANT_ENUM_CAST(VisibilityEnabler::Enabler);
-
-#endif // VISIBILITY_NOTIFIER_H
diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp
new file mode 100644
index 0000000000..2f657fe7b1
--- /dev/null
+++ b/scene/3d/visibility_notifier_3d.cpp
@@ -0,0 +1,274 @@
+/*************************************************************************/
+/* visibility_notifier_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "visibility_notifier_3d.h"
+
+#include "core/engine.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/animation/animation_player.h"
+#include "scene/scene_string_names.h"
+
+void VisibilityNotifier3D::_enter_camera(Camera3D *p_camera) {
+
+ ERR_FAIL_COND(cameras.has(p_camera));
+ cameras.insert(p_camera);
+ if (cameras.size() == 1) {
+ emit_signal(SceneStringNames::get_singleton()->screen_entered);
+ _screen_enter();
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera);
+}
+
+void VisibilityNotifier3D::_exit_camera(Camera3D *p_camera) {
+
+ ERR_FAIL_COND(!cameras.has(p_camera));
+ cameras.erase(p_camera);
+
+ emit_signal(SceneStringNames::get_singleton()->camera_exited, p_camera);
+ if (cameras.size() == 0) {
+ emit_signal(SceneStringNames::get_singleton()->screen_exited);
+
+ _screen_exit();
+ }
+}
+
+void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) {
+
+ if (aabb == p_aabb)
+ return;
+ aabb = p_aabb;
+
+ if (is_inside_world()) {
+ get_world()->_update_notifier(this, get_global_transform().xform(aabb));
+ }
+
+ _change_notify("aabb");
+ update_gizmo();
+}
+
+AABB VisibilityNotifier3D::get_aabb() const {
+
+ return aabb;
+}
+
+void VisibilityNotifier3D::_notification(int p_what) {
+
+ switch (p_what) {
+ case NOTIFICATION_ENTER_WORLD: {
+
+ get_world()->_register_notifier(this, get_global_transform().xform(aabb));
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ get_world()->_update_notifier(this, get_global_transform().xform(aabb));
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ get_world()->_remove_notifier(this);
+ } break;
+ }
+}
+
+bool VisibilityNotifier3D::is_on_screen() const {
+
+ return cameras.size() != 0;
+}
+
+void VisibilityNotifier3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibilityNotifier3D::set_aabb);
+ ClassDB::bind_method(D_METHOD("get_aabb"), &VisibilityNotifier3D::get_aabb);
+ ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibilityNotifier3D::is_on_screen);
+
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb");
+
+ ADD_SIGNAL(MethodInfo("camera_entered", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D")));
+ ADD_SIGNAL(MethodInfo("camera_exited", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D")));
+ ADD_SIGNAL(MethodInfo("screen_entered"));
+ ADD_SIGNAL(MethodInfo("screen_exited"));
+}
+
+VisibilityNotifier3D::VisibilityNotifier3D() {
+
+ aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2));
+ set_notify_transform(true);
+}
+
+//////////////////////////////////////
+
+void VisibilityEnabler3D::_screen_enter() {
+
+ for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
+
+ _change_node_state(E->key(), true);
+ }
+
+ visible = true;
+}
+
+void VisibilityEnabler3D::_screen_exit() {
+
+ for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
+
+ _change_node_state(E->key(), false);
+ }
+
+ visible = false;
+}
+
+void VisibilityEnabler3D::_find_nodes(Node *p_node) {
+
+ bool add = false;
+ Variant meta;
+
+ {
+ RigidBody3D *rb = Object::cast_to<RigidBody3D>(p_node);
+ if (rb && ((rb->get_mode() == RigidBody3D::MODE_CHARACTER || rb->get_mode() == RigidBody3D::MODE_RIGID))) {
+
+ add = true;
+ meta = rb->get_mode();
+ }
+ }
+
+ {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
+ if (ap) {
+ add = true;
+ }
+ }
+
+ if (add) {
+
+ p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed), varray(p_node), CONNECT_ONESHOT);
+ nodes[p_node] = meta;
+ _change_node_state(p_node, false);
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *c = p_node->get_child(i);
+ if (c->get_filename() != String())
+ continue; //skip, instance
+
+ _find_nodes(c);
+ }
+}
+
+void VisibilityEnabler3D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
+ Node *from = this;
+ //find where current scene starts
+ while (from->get_parent() && from->get_filename() == String())
+ from = from->get_parent();
+
+ _find_nodes(from);
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
+ for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) {
+
+ if (!visible)
+ _change_node_state(E->key(), true);
+ E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed));
+ }
+
+ nodes.clear();
+ }
+}
+
+void VisibilityEnabler3D::_change_node_state(Node *p_node, bool p_enabled) {
+
+ ERR_FAIL_COND(!nodes.has(p_node));
+
+ if (enabler[ENABLER_FREEZE_BODIES]) {
+ RigidBody3D *rb = Object::cast_to<RigidBody3D>(p_node);
+ if (rb)
+
+ rb->set_sleeping(!p_enabled);
+ }
+
+ if (enabler[ENABLER_PAUSE_ANIMATIONS]) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
+
+ if (ap) {
+
+ ap->set_active(p_enabled);
+ }
+ }
+}
+
+void VisibilityEnabler3D::_node_removed(Node *p_node) {
+
+ if (!visible)
+ _change_node_state(p_node, true);
+ nodes.erase(p_node);
+}
+
+void VisibilityEnabler3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler3D::set_enabler);
+ ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler3D::is_enabler_enabled);
+
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES);
+
+ BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS);
+ BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES);
+ BIND_ENUM_CONSTANT(ENABLER_MAX);
+}
+
+void VisibilityEnabler3D::set_enabler(Enabler p_enabler, bool p_enable) {
+
+ ERR_FAIL_INDEX(p_enabler, ENABLER_MAX);
+ enabler[p_enabler] = p_enable;
+}
+bool VisibilityEnabler3D::is_enabler_enabled(Enabler p_enabler) const {
+
+ ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false);
+ return enabler[p_enabler];
+}
+
+VisibilityEnabler3D::VisibilityEnabler3D() {
+
+ for (int i = 0; i < ENABLER_MAX; i++)
+ enabler[i] = true;
+
+ visible = false;
+}
diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visibility_notifier_3d.h
new file mode 100644
index 0000000000..19204a6a4e
--- /dev/null
+++ b/scene/3d/visibility_notifier_3d.h
@@ -0,0 +1,101 @@
+/*************************************************************************/
+/* visibility_notifier_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VISIBILITY_NOTIFIER_H
+#define VISIBILITY_NOTIFIER_H
+
+#include "scene/3d/node_3d.h"
+
+class Camera3D;
+class VisibilityNotifier3D : public Node3D {
+
+ GDCLASS(VisibilityNotifier3D, Node3D);
+
+ Set<Camera3D *> cameras;
+
+ AABB aabb;
+
+protected:
+ virtual void _screen_enter() {}
+ virtual void _screen_exit() {}
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ friend struct SpatialIndexer;
+
+ void _enter_camera(Camera3D *p_camera);
+ void _exit_camera(Camera3D *p_camera);
+
+public:
+ void set_aabb(const AABB &p_aabb);
+ AABB get_aabb() const;
+ bool is_on_screen() const;
+
+ VisibilityNotifier3D();
+};
+
+class VisibilityEnabler3D : public VisibilityNotifier3D {
+
+ GDCLASS(VisibilityEnabler3D, VisibilityNotifier3D);
+
+public:
+ enum Enabler {
+ ENABLER_PAUSE_ANIMATIONS,
+ ENABLER_FREEZE_BODIES,
+ ENABLER_MAX
+ };
+
+protected:
+ virtual void _screen_enter();
+ virtual void _screen_exit();
+
+ bool visible;
+
+ void _find_nodes(Node *p_node);
+
+ Map<Node *, Variant> nodes;
+ void _node_removed(Node *p_node);
+ bool enabler[ENABLER_MAX];
+
+ void _change_node_state(Node *p_node, bool p_enabled);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_enabler(Enabler p_enabler, bool p_enable);
+ bool is_enabler_enabled(Enabler p_enabler) const;
+
+ VisibilityEnabler3D();
+};
+
+VARIANT_ENUM_CAST(VisibilityEnabler3D::Enabler);
+
+#endif // VISIBILITY_NOTIFIER_H
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
deleted file mode 100644
index 105ce9ca74..0000000000
--- a/scene/3d/visual_instance.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*************************************************************************/
-/* visual_instance.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_instance.h"
-
-#include "scene/scene_string_names.h"
-#include "servers/visual_server.h"
-#include "skeleton.h"
-
-AABB VisualInstance::get_transformed_aabb() const {
-
- return get_global_transform().xform(get_aabb());
-}
-
-void VisualInstance::_update_visibility() {
-
- if (!is_inside_tree())
- return;
-
- _change_notify("visible");
- VS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree());
-}
-
-void VisualInstance::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_WORLD: {
-
- // CHECK SKELETON => moving skeleton attaching logic to MeshInstance
- /*
- Skeleton *skeleton=Object::cast_to<Skeleton>(get_parent());
- if (skeleton)
- VisualServer::get_singleton()->instance_attach_skeleton( instance, skeleton->get_skeleton() );
- */
- ERR_FAIL_COND(get_world().is_null());
- VisualServer::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
- _update_visibility();
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- Transform gt = get_global_transform();
- VisualServer::get_singleton()->instance_set_transform(instance, gt);
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- VisualServer::get_singleton()->instance_set_scenario(instance, RID());
- VisualServer::get_singleton()->instance_attach_skeleton(instance, RID());
- //VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() );
-
- } break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
-
- _update_visibility();
- } break;
- }
-}
-
-RID VisualInstance::get_instance() const {
-
- return instance;
-}
-
-RID VisualInstance::_get_visual_instance_rid() const {
-
- return instance;
-}
-
-void VisualInstance::set_layer_mask(uint32_t p_mask) {
-
- layers = p_mask;
- VisualServer::get_singleton()->instance_set_layer_mask(instance, p_mask);
-}
-
-uint32_t VisualInstance::get_layer_mask() const {
-
- return layers;
-}
-
-void VisualInstance::set_layer_mask_bit(int p_layer, bool p_enable) {
- ERR_FAIL_INDEX(p_layer, 32);
- if (p_enable) {
- set_layer_mask(layers | (1 << p_layer));
- } else {
- set_layer_mask(layers & (~(1 << p_layer)));
- }
-}
-
-bool VisualInstance::get_layer_mask_bit(int p_layer) const {
- ERR_FAIL_INDEX_V(p_layer, 32, false);
- return (layers & (1 << p_layer));
-}
-
-void VisualInstance::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid);
- ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base);
- ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance::get_base);
- ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance::get_instance);
- ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance::set_layer_mask);
- ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance::get_layer_mask);
- ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit);
- ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance::get_layer_mask_bit);
-
- ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance::get_transformed_aabb);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
-}
-
-void VisualInstance::set_base(const RID &p_base) {
-
- VisualServer::get_singleton()->instance_set_base(instance, p_base);
- base = p_base;
-}
-
-RID VisualInstance::get_base() const {
-
- return base;
-}
-
-VisualInstance::VisualInstance() {
-
- instance = VisualServer::get_singleton()->instance_create();
- VisualServer::get_singleton()->instance_attach_object_instance_id(instance, get_instance_id());
- layers = 1;
- set_notify_transform(true);
-}
-
-VisualInstance::~VisualInstance() {
-
- VisualServer::get_singleton()->free(instance);
-}
-
-void GeometryInstance::set_material_override(const Ref<Material> &p_material) {
-
- material_override = p_material;
- VS::get_singleton()->instance_geometry_set_material_override(get_instance(), p_material.is_valid() ? p_material->get_rid() : RID());
-}
-
-Ref<Material> GeometryInstance::get_material_override() const {
-
- return material_override;
-}
-
-void GeometryInstance::set_lod_min_distance(float p_dist) {
-
- lod_min_distance = p_dist;
- VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
-}
-
-float GeometryInstance::get_lod_min_distance() const {
-
- return lod_min_distance;
-}
-
-void GeometryInstance::set_lod_max_distance(float p_dist) {
-
- lod_max_distance = p_dist;
- VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
-}
-
-float GeometryInstance::get_lod_max_distance() const {
-
- return lod_max_distance;
-}
-
-void GeometryInstance::set_lod_min_hysteresis(float p_dist) {
-
- lod_min_hysteresis = p_dist;
- VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
-}
-
-float GeometryInstance::get_lod_min_hysteresis() const {
-
- return lod_min_hysteresis;
-}
-
-void GeometryInstance::set_lod_max_hysteresis(float p_dist) {
-
- lod_max_hysteresis = p_dist;
- VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
-}
-
-float GeometryInstance::get_lod_max_hysteresis() const {
-
- return lod_max_hysteresis;
-}
-
-void GeometryInstance::_notification(int p_what) {
-}
-
-void GeometryInstance::set_flag(Flags p_flag, bool p_value) {
-
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- if (flags[p_flag] == p_value)
- return;
-
- flags[p_flag] = p_value;
- VS::get_singleton()->instance_geometry_set_flag(get_instance(), (VS::InstanceFlags)p_flag, p_value);
-}
-
-bool GeometryInstance::get_flag(Flags p_flag) const {
-
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
-
- return flags[p_flag];
-}
-
-void GeometryInstance::set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting) {
-
- shadow_casting_setting = p_shadow_casting_setting;
-
- VS::get_singleton()->instance_geometry_set_cast_shadows_setting(get_instance(), (VS::ShadowCastingSetting)p_shadow_casting_setting);
-}
-
-GeometryInstance::ShadowCastingSetting GeometryInstance::get_cast_shadows_setting() const {
-
- return shadow_casting_setting;
-}
-
-void GeometryInstance::set_extra_cull_margin(float p_margin) {
-
- ERR_FAIL_COND(p_margin < 0);
- extra_cull_margin = p_margin;
- VS::get_singleton()->instance_set_extra_visibility_margin(get_instance(), extra_cull_margin);
-}
-
-float GeometryInstance::get_extra_cull_margin() const {
-
- return extra_cull_margin;
-}
-
-void GeometryInstance::set_custom_aabb(AABB aabb) {
-
- VS::get_singleton()->instance_set_custom_aabb(get_instance(), aabb);
-}
-
-void GeometryInstance::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance::set_material_override);
- ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance::get_material_override);
-
- ClassDB::bind_method(D_METHOD("set_flag", "flag", "value"), &GeometryInstance::set_flag);
- ClassDB::bind_method(D_METHOD("get_flag", "flag"), &GeometryInstance::get_flag);
-
- ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance::set_cast_shadows_setting);
- ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance::get_cast_shadows_setting);
-
- ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance::set_lod_max_hysteresis);
- ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance::get_lod_max_hysteresis);
-
- ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance::set_lod_max_distance);
- ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance::get_lod_max_distance);
-
- ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance::set_lod_min_hysteresis);
- ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance::get_lod_min_hysteresis);
-
- ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance::set_lod_min_distance);
- ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance::get_lod_min_distance);
-
- ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin);
- ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
-
- ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance::set_custom_aabb);
-
- ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb);
-
- ADD_GROUP("Geometry", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
- 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_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_dynamic_gi"), "set_flag", "get_flag", FLAG_USE_DYNAMIC_GI);
-
- ADD_GROUP("LOD", "lod_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_hysteresis", "get_lod_min_hysteresis");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_distance", "get_lod_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_hysteresis", "get_lod_max_hysteresis");
-
- //ADD_SIGNAL( MethodInfo("visibility_changed"));
-
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON);
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED);
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
-
- BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT);
- BIND_ENUM_CONSTANT(FLAG_USE_DYNAMIC_GI);
- BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
- BIND_ENUM_CONSTANT(FLAG_MAX);
-}
-
-GeometryInstance::GeometryInstance() {
- lod_min_distance = 0;
- lod_max_distance = 0;
- lod_min_hysteresis = 0;
- lod_max_hysteresis = 0;
-
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
- }
-
- shadow_casting_setting = SHADOW_CASTING_SETTING_ON;
- extra_cull_margin = 0;
- //VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
-}
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
deleted file mode 100644
index fee6787c87..0000000000
--- a/scene/3d/visual_instance.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*************************************************************************/
-/* visual_instance.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUAL_INSTANCE_H
-#define VISUAL_INSTANCE_H
-
-#include "core/math/face3.h"
-#include "core/rid.h"
-#include "scene/3d/spatial.h"
-#include "scene/resources/material.h"
-
-class VisualInstance : public Spatial {
-
- GDCLASS(VisualInstance, Spatial);
- OBJ_CATEGORY("3D Visual Nodes");
-
- RID base;
- RID instance;
- uint32_t layers;
-
- RID _get_visual_instance_rid() const;
-
-protected:
- void _update_visibility();
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- enum GetFacesFlags {
- FACES_SOLID = 1, // solid geometry
- FACES_ENCLOSING = 2,
- FACES_DYNAMIC = 4 // dynamic object geometry
-
- };
-
- RID get_instance() const;
- virtual AABB get_aabb() const = 0;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const = 0;
-
- virtual AABB get_transformed_aabb() const; // helper
-
- void set_base(const RID &p_base);
- RID get_base() const;
-
- void set_layer_mask(uint32_t p_mask);
- uint32_t get_layer_mask() const;
-
- void set_layer_mask_bit(int p_layer, bool p_enable);
- bool get_layer_mask_bit(int p_layer) const;
-
- VisualInstance();
- ~VisualInstance();
-};
-
-class GeometryInstance : public VisualInstance {
-
- GDCLASS(GeometryInstance, VisualInstance);
-
-public:
- enum Flags {
- FLAG_USE_BAKED_LIGHT = VS::INSTANCE_FLAG_USE_BAKED_LIGHT,
- FLAG_USE_DYNAMIC_GI = VS::INSTANCE_FLAG_USE_DYNAMIC_GI,
- FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
- FLAG_MAX = VS::INSTANCE_FLAG_MAX,
- };
-
- enum ShadowCastingSetting {
- SHADOW_CASTING_SETTING_OFF = VS::SHADOW_CASTING_SETTING_OFF,
- SHADOW_CASTING_SETTING_ON = VS::SHADOW_CASTING_SETTING_ON,
- SHADOW_CASTING_SETTING_DOUBLE_SIDED = VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED,
- SHADOW_CASTING_SETTING_SHADOWS_ONLY = VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY
- };
-
-private:
- bool flags[FLAG_MAX];
- ShadowCastingSetting shadow_casting_setting;
- Ref<Material> material_override;
- float lod_min_distance;
- float lod_max_distance;
- float lod_min_hysteresis;
- float lod_max_hysteresis;
-
- float extra_cull_margin;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_flag(Flags p_flag, bool p_value);
- bool get_flag(Flags p_flag) const;
-
- void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting);
- ShadowCastingSetting get_cast_shadows_setting() const;
-
- void set_lod_min_distance(float p_dist);
- float get_lod_min_distance() const;
-
- void set_lod_max_distance(float p_dist);
- float get_lod_max_distance() const;
-
- void set_lod_min_hysteresis(float p_dist);
- float get_lod_min_hysteresis() const;
-
- void set_lod_max_hysteresis(float p_dist);
- float get_lod_max_hysteresis() const;
-
- void set_material_override(const Ref<Material> &p_material);
- Ref<Material> get_material_override() const;
-
- void set_extra_cull_margin(float p_margin);
- float get_extra_cull_margin() const;
-
- void set_custom_aabb(AABB aabb);
-
- GeometryInstance();
-};
-
-VARIANT_ENUM_CAST(GeometryInstance::Flags);
-VARIANT_ENUM_CAST(GeometryInstance::ShadowCastingSetting);
-
-#endif
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
new file mode 100644
index 0000000000..775a9b76e2
--- /dev/null
+++ b/scene/3d/visual_instance_3d.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* visual_instance_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "visual_instance_3d.h"
+
+#include "scene/scene_string_names.h"
+#include "servers/rendering_server.h"
+#include "skeleton_3d.h"
+
+AABB VisualInstance3D::get_transformed_aabb() const {
+
+ return get_global_transform().xform(get_aabb());
+}
+
+void VisualInstance3D::_update_visibility() {
+
+ if (!is_inside_tree())
+ return;
+
+ _change_notify("visible");
+ RS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree());
+}
+
+void VisualInstance3D::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_WORLD: {
+
+ // CHECK SKELETON => moving skeleton attaching logic to MeshInstance
+ /*
+ Skeleton *skeleton=Object::cast_to<Skeleton>(get_parent());
+ if (skeleton)
+ RenderingServer::get_singleton()->instance_attach_skeleton( instance, skeleton->get_skeleton() );
+ */
+ ERR_FAIL_COND(get_world().is_null());
+ RenderingServer::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
+ _update_visibility();
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ Transform gt = get_global_transform();
+ RenderingServer::get_singleton()->instance_set_transform(instance, gt);
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ RenderingServer::get_singleton()->instance_set_scenario(instance, RID());
+ RenderingServer::get_singleton()->instance_attach_skeleton(instance, RID());
+ //RS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() );
+
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_visibility();
+ } break;
+ }
+}
+
+RID VisualInstance3D::get_instance() const {
+
+ return instance;
+}
+
+RID VisualInstance3D::_get_visual_instance_rid() const {
+
+ return instance;
+}
+
+void VisualInstance3D::set_layer_mask(uint32_t p_mask) {
+
+ layers = p_mask;
+ RenderingServer::get_singleton()->instance_set_layer_mask(instance, p_mask);
+}
+
+uint32_t VisualInstance3D::get_layer_mask() const {
+
+ return layers;
+}
+
+void VisualInstance3D::set_layer_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_layer_mask(layers | (1 << p_layer));
+ } else {
+ set_layer_mask(layers & (~(1 << p_layer)));
+ }
+}
+
+bool VisualInstance3D::get_layer_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (layers & (1 << p_layer));
+}
+
+void VisualInstance3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance3D::_get_visual_instance_rid);
+ ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base);
+ ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base);
+ ClassDB::bind_method(D_METHOD("get_instance"), &VisualInstance3D::get_instance);
+ ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance3D::set_layer_mask);
+ ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance3D::get_layer_mask);
+ ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance3D::set_layer_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance3D::get_layer_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
+}
+
+void VisualInstance3D::set_base(const RID &p_base) {
+
+ RenderingServer::get_singleton()->instance_set_base(instance, p_base);
+ base = p_base;
+}
+
+RID VisualInstance3D::get_base() const {
+
+ return base;
+}
+
+VisualInstance3D::VisualInstance3D() {
+
+ instance = RenderingServer::get_singleton()->instance_create();
+ RenderingServer::get_singleton()->instance_attach_object_instance_id(instance, get_instance_id());
+ layers = 1;
+ set_notify_transform(true);
+}
+
+VisualInstance3D::~VisualInstance3D() {
+
+ RenderingServer::get_singleton()->free(instance);
+}
+
+void GeometryInstance3D::set_material_override(const Ref<Material> &p_material) {
+
+ material_override = p_material;
+ RS::get_singleton()->instance_geometry_set_material_override(get_instance(), p_material.is_valid() ? p_material->get_rid() : RID());
+}
+
+Ref<Material> GeometryInstance3D::get_material_override() const {
+
+ return material_override;
+}
+
+void GeometryInstance3D::set_lod_min_distance(float p_dist) {
+
+ lod_min_distance = p_dist;
+ RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+}
+
+float GeometryInstance3D::get_lod_min_distance() const {
+
+ return lod_min_distance;
+}
+
+void GeometryInstance3D::set_lod_max_distance(float p_dist) {
+
+ lod_max_distance = p_dist;
+ RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+}
+
+float GeometryInstance3D::get_lod_max_distance() const {
+
+ return lod_max_distance;
+}
+
+void GeometryInstance3D::set_lod_min_hysteresis(float p_dist) {
+
+ lod_min_hysteresis = p_dist;
+ RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+}
+
+float GeometryInstance3D::get_lod_min_hysteresis() const {
+
+ return lod_min_hysteresis;
+}
+
+void GeometryInstance3D::set_lod_max_hysteresis(float p_dist) {
+
+ lod_max_hysteresis = p_dist;
+ RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
+}
+
+float GeometryInstance3D::get_lod_max_hysteresis() const {
+
+ return lod_max_hysteresis;
+}
+
+void GeometryInstance3D::_notification(int p_what) {
+}
+
+void GeometryInstance3D::set_flag(Flags p_flag, bool p_value) {
+
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ if (flags[p_flag] == p_value)
+ return;
+
+ flags[p_flag] = p_value;
+ RS::get_singleton()->instance_geometry_set_flag(get_instance(), (RS::InstanceFlags)p_flag, p_value);
+}
+
+bool GeometryInstance3D::get_flag(Flags p_flag) const {
+
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+
+ return flags[p_flag];
+}
+
+void GeometryInstance3D::set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting) {
+
+ shadow_casting_setting = p_shadow_casting_setting;
+
+ RS::get_singleton()->instance_geometry_set_cast_shadows_setting(get_instance(), (RS::ShadowCastingSetting)p_shadow_casting_setting);
+}
+
+GeometryInstance3D::ShadowCastingSetting GeometryInstance3D::get_cast_shadows_setting() const {
+
+ return shadow_casting_setting;
+}
+
+void GeometryInstance3D::set_extra_cull_margin(float p_margin) {
+
+ ERR_FAIL_COND(p_margin < 0);
+ extra_cull_margin = p_margin;
+ RS::get_singleton()->instance_set_extra_visibility_margin(get_instance(), extra_cull_margin);
+}
+
+float GeometryInstance3D::get_extra_cull_margin() const {
+
+ return extra_cull_margin;
+}
+
+void GeometryInstance3D::set_custom_aabb(AABB aabb) {
+
+ RS::get_singleton()->instance_set_custom_aabb(get_instance(), aabb);
+}
+
+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);
+
+ ClassDB::bind_method(D_METHOD("set_flag", "flag", "value"), &GeometryInstance3D::set_flag);
+ ClassDB::bind_method(D_METHOD("get_flag", "flag"), &GeometryInstance3D::get_flag);
+
+ 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_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_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_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
+ ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
+
+ ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb);
+
+ ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance3D::get_aabb);
+
+ ADD_GROUP("Geometry", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override");
+ 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_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_dynamic_gi"), "set_flag", "get_flag", FLAG_USE_DYNAMIC_GI);
+
+ ADD_GROUP("LOD", "lod_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_hysteresis", "get_lod_min_hysteresis");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_distance", "get_lod_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_hysteresis", "get_lod_max_hysteresis");
+
+ //ADD_SIGNAL( MethodInfo("visibility_changed"));
+
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON);
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED);
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
+
+ BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT);
+ BIND_ENUM_CONSTANT(FLAG_USE_DYNAMIC_GI);
+ BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+}
+
+GeometryInstance3D::GeometryInstance3D() {
+ lod_min_distance = 0;
+ lod_max_distance = 0;
+ lod_min_hysteresis = 0;
+ lod_max_hysteresis = 0;
+
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = false;
+ }
+
+ shadow_casting_setting = SHADOW_CASTING_SETTING_ON;
+ extra_cull_margin = 0;
+ //RS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
+}
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
new file mode 100644
index 0000000000..9476c28848
--- /dev/null
+++ b/scene/3d/visual_instance_3d.h
@@ -0,0 +1,150 @@
+/*************************************************************************/
+/* visual_instance_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VISUAL_INSTANCE_H
+#define VISUAL_INSTANCE_H
+
+#include "core/math/face3.h"
+#include "core/rid.h"
+#include "scene/3d/node_3d.h"
+#include "scene/resources/material.h"
+
+class VisualInstance3D : public Node3D {
+
+ GDCLASS(VisualInstance3D, Node3D);
+ OBJ_CATEGORY("3D Visual Nodes");
+
+ RID base;
+ RID instance;
+ uint32_t layers;
+
+ RID _get_visual_instance_rid() const;
+
+protected:
+ void _update_visibility();
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ enum GetFacesFlags {
+ FACES_SOLID = 1, // solid geometry
+ FACES_ENCLOSING = 2,
+ FACES_DYNAMIC = 4 // dynamic object geometry
+
+ };
+
+ RID get_instance() const;
+ virtual AABB get_aabb() const = 0;
+ virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const = 0;
+
+ virtual AABB get_transformed_aabb() const; // helper
+
+ void set_base(const RID &p_base);
+ RID get_base() const;
+
+ void set_layer_mask(uint32_t p_mask);
+ uint32_t get_layer_mask() const;
+
+ void set_layer_mask_bit(int p_layer, bool p_enable);
+ bool get_layer_mask_bit(int p_layer) const;
+
+ VisualInstance3D();
+ ~VisualInstance3D();
+};
+
+class GeometryInstance3D : public VisualInstance3D {
+
+ GDCLASS(GeometryInstance3D, VisualInstance3D);
+
+public:
+ enum Flags {
+ FLAG_USE_BAKED_LIGHT = RS::INSTANCE_FLAG_USE_BAKED_LIGHT,
+ FLAG_USE_DYNAMIC_GI = RS::INSTANCE_FLAG_USE_DYNAMIC_GI,
+ FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
+ FLAG_MAX = RS::INSTANCE_FLAG_MAX,
+ };
+
+ enum ShadowCastingSetting {
+ SHADOW_CASTING_SETTING_OFF = RS::SHADOW_CASTING_SETTING_OFF,
+ SHADOW_CASTING_SETTING_ON = RS::SHADOW_CASTING_SETTING_ON,
+ SHADOW_CASTING_SETTING_DOUBLE_SIDED = RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED,
+ SHADOW_CASTING_SETTING_SHADOWS_ONLY = RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY
+ };
+
+private:
+ bool flags[FLAG_MAX];
+ ShadowCastingSetting shadow_casting_setting;
+ Ref<Material> material_override;
+ float lod_min_distance;
+ float lod_max_distance;
+ float lod_min_hysteresis;
+ float lod_max_hysteresis;
+
+ float extra_cull_margin;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_flag(Flags p_flag, bool p_value);
+ bool get_flag(Flags p_flag) const;
+
+ void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting);
+ ShadowCastingSetting get_cast_shadows_setting() const;
+
+ void set_lod_min_distance(float p_dist);
+ float get_lod_min_distance() const;
+
+ void set_lod_max_distance(float p_dist);
+ float get_lod_max_distance() const;
+
+ void set_lod_min_hysteresis(float p_dist);
+ float get_lod_min_hysteresis() const;
+
+ void set_lod_max_hysteresis(float p_dist);
+ float get_lod_max_hysteresis() const;
+
+ void set_material_override(const Ref<Material> &p_material);
+ Ref<Material> get_material_override() const;
+
+ void set_extra_cull_margin(float p_margin);
+ float get_extra_cull_margin() const;
+
+ void set_custom_aabb(AABB aabb);
+
+ GeometryInstance3D();
+};
+
+VARIANT_ENUM_CAST(GeometryInstance3D::Flags);
+VARIANT_ENUM_CAST(GeometryInstance3D::ShadowCastingSetting);
+
+#endif
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 0257e6e83d..203c3cd812 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -569,7 +569,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
return mc;
}
-void Voxelizer::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) {
+void Voxelizer::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) {
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index 1d50f1cd18..1fde6237a2 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -32,7 +32,7 @@
#define VOXEL_LIGHT_BAKER_H
#include "core/math/vector3i.h"
-#include "scene/3d/mesh_instance.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/multimesh.h"
class Voxelizer {
@@ -125,7 +125,7 @@ private:
public:
void begin_bake(int p_subdiv, const AABB &p_bounds);
- void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material);
+ void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
void end_bake();
int get_gi_probe_octree_depth() const;
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index 83a7243906..8cf4554653 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -29,11 +29,11 @@
/*************************************************************************/
#include "world_environment.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void WorldEnvironment::_notification(int p_what) {
- if (p_what == Spatial::NOTIFICATION_ENTER_WORLD || p_what == Spatial::NOTIFICATION_ENTER_TREE) {
+ if (p_what == Node3D::NOTIFICATION_ENTER_WORLD || p_what == Node3D::NOTIFICATION_ENTER_TREE) {
if (environment.is_valid()) {
if (get_viewport()->find_world()->get_environment().is_valid()) {
@@ -51,7 +51,7 @@ void WorldEnvironment::_notification(int p_what) {
add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world()->get_scenario().get_id()));
}
- } else if (p_what == Spatial::NOTIFICATION_EXIT_WORLD || p_what == Spatial::NOTIFICATION_EXIT_TREE) {
+ } else if (p_what == Node3D::NOTIFICATION_EXIT_WORLD || p_what == Node3D::NOTIFICATION_EXIT_TREE) {
if (environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) {
get_viewport()->find_world()->set_environment(Ref<Environment>());
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index 0c590bfc07..e4c9fc071d 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -31,7 +31,7 @@
#ifndef SCENARIO_FX_H
#define SCENARIO_FX_H
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
class WorldEnvironment : public Node {
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
new file mode 100644
index 0000000000..0373114e7d
--- /dev/null
+++ b/scene/3d/xr_nodes.cpp
@@ -0,0 +1,621 @@
+/*************************************************************************/
+/* xr_nodes.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "xr_nodes.h"
+#include "core/input/input_filter.h"
+#include "servers/xr/xr_interface.h"
+#include "servers/xr_server.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void XRCamera3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ // need to find our XROrigin3D parent and let it know we're its camera!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin != nullptr) {
+ origin->set_tracked_camera(this);
+ }
+ }; break;
+ case NOTIFICATION_EXIT_TREE: {
+ // need to find our XROrigin3D parent and let it know we're no longer its camera!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin != nullptr) {
+ origin->clear_tracked_camera_if(this);
+ }
+ }; break;
+ };
+};
+
+String XRCamera3D::get_configuration_warning() const {
+ if (!is_visible() || !is_inside_tree())
+ return String();
+
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ return TTR("XRCamera3D must have an XROrigin3D node as its parent.");
+ };
+
+ return String();
+};
+
+Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, Vector3());
+
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
+ if (xr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera3D::project_local_ray_normal(p_pos);
+ }
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_camera_rect_size();
+ Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
+ Vector3 ray;
+
+ CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
+ Vector2 screen_he = cm.get_viewport_half_extents();
+ ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_znear()).normalized();
+
+ return ray;
+};
+
+Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, Vector2());
+
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
+ if (xr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera3D::unproject_position(p_pos);
+ }
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector2(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
+
+ Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
+
+ p = cm.xform4(p);
+ p.normal /= p.d;
+
+ Point2 res;
+ res.x = (p.normal.x * 0.5 + 0.5) * viewport_size.x;
+ res.y = (-p.normal.y * 0.5 + 0.5) * viewport_size.y;
+
+ return res;
+};
+
+Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) const {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, Vector3());
+
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
+ if (xr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera3D::project_position(p_point, p_z_depth);
+ }
+
+ ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
+
+ Vector2 vp_he = cm.get_viewport_half_extents();
+
+ Vector2 point;
+ point.x = (p_point.x / viewport_size.x) * 2.0 - 1.0;
+ point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
+ point *= vp_he;
+
+ Vector3 p(point.x, point.y, -p_z_depth);
+
+ return get_camera_transform().xform(p);
+};
+
+Vector<Plane> XRCamera3D::get_frustum() const {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, Vector<Plane>());
+
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
+ if (xr_interface.is_null()) {
+ // we might be in the editor or have VR turned off, just call superclass
+ return Camera3D::get_frustum();
+ }
+
+ ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+ CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar());
+ return cm.get_projection_planes(get_camera_transform());
+};
+
+XRCamera3D::XRCamera3D(){
+ // nothing to do here yet for now..
+};
+
+XRCamera3D::~XRCamera3D(){
+ // nothing to do here yet for now..
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void XRController3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ set_process_internal(true);
+ }; break;
+ case NOTIFICATION_EXIT_TREE: {
+ set_process_internal(false);
+ }; break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ 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) {
+ // this controller is currently turned off
+ is_active = false;
+ button_states = 0;
+ } else {
+ is_active = true;
+ set_transform(tracker->get_transform(true));
+
+ int joy_id = tracker->get_joy_id();
+ if (joy_id >= 0) {
+ int mask = 1;
+ // check button states
+ for (int i = 0; i < 16; i++) {
+ bool was_pressed = (button_states & mask) == mask;
+ bool is_pressed = InputFilter::get_singleton()->is_joy_button_pressed(joy_id, i);
+
+ if (!was_pressed && is_pressed) {
+ emit_signal("button_pressed", i);
+ button_states += mask;
+ } else if (was_pressed && !is_pressed) {
+ emit_signal("button_release", i);
+ button_states -= mask;
+ };
+
+ mask = mask << 1;
+ };
+
+ } else {
+ button_states = 0;
+ };
+
+ // check for an updated mesh
+ Ref<Mesh> trackerMesh = tracker->get_mesh();
+ if (mesh != trackerMesh) {
+ mesh = trackerMesh;
+ emit_signal("mesh_updated", mesh);
+ }
+ };
+ }; break;
+ default:
+ break;
+ };
+};
+
+void XRController3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &XRController3D::set_controller_id);
+ ClassDB::bind_method(D_METHOD("get_controller_id"), &XRController3D::get_controller_id);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id");
+ ClassDB::bind_method(D_METHOD("get_controller_name"), &XRController3D::get_controller_name);
+
+ // passthroughs to information about our related joystick
+ ClassDB::bind_method(D_METHOD("get_joystick_id"), &XRController3D::get_joystick_id);
+ ClassDB::bind_method(D_METHOD("is_button_pressed", "button"), &XRController3D::is_button_pressed);
+ ClassDB::bind_method(D_METHOD("get_joystick_axis", "axis"), &XRController3D::get_joystick_axis);
+
+ ClassDB::bind_method(D_METHOD("get_is_active"), &XRController3D::get_is_active);
+ ClassDB::bind_method(D_METHOD("get_hand"), &XRController3D::get_hand);
+
+ ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble);
+ ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
+ ADD_PROPERTY_DEFAULT("rumble", 0.0);
+
+ ClassDB::bind_method(D_METHOD("get_mesh"), &XRController3D::get_mesh);
+
+ ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
+ ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button")));
+ ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
+};
+
+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();
+};
+
+int XRController3D::get_controller_id(void) const {
+ return controller_id;
+};
+
+String XRController3D::get_controller_name(void) const {
+ // get our XRServer
+ 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) {
+ return String("Not connected");
+ };
+
+ return tracker->get_name();
+};
+
+int XRController3D::get_joystick_id() const {
+ // get our XRServer
+ 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) {
+ // No tracker? no joystick id... (0 is our first joystick)
+ return -1;
+ };
+
+ return tracker->get_joy_id();
+};
+
+bool XRController3D::is_button_pressed(int p_button) const {
+ int joy_id = get_joystick_id();
+ if (joy_id == -1) {
+ return false;
+ };
+
+ return InputFilter::get_singleton()->is_joy_button_pressed(joy_id, p_button);
+};
+
+float XRController3D::get_joystick_axis(int p_axis) const {
+ int joy_id = get_joystick_id();
+ if (joy_id == -1) {
+ return 0.0;
+ };
+
+ return InputFilter::get_singleton()->get_joy_axis(joy_id, p_axis);
+};
+
+real_t XRController3D::get_rumble() const {
+ // get our XRServer
+ 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) {
+ return 0.0;
+ };
+
+ return tracker->get_rumble();
+};
+
+void XRController3D::set_rumble(real_t p_rumble) {
+ // get our XRServer
+ 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) {
+ tracker->set_rumble(p_rumble);
+ };
+};
+
+Ref<Mesh> XRController3D::get_mesh() const {
+ return mesh;
+}
+
+bool XRController3D::get_is_active() const {
+ return is_active;
+};
+
+XRPositionalTracker::TrackerHand XRController3D::get_hand() const {
+ // get our XRServer
+ 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) {
+ return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
+ };
+
+ return tracker->get_hand();
+};
+
+String XRController3D::get_configuration_warning() const {
+ if (!is_visible() || !is_inside_tree())
+ return String();
+
+ // must be child node of XROrigin!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ return TTR("XRController3D must have an XROrigin3D node as its parent.");
+ };
+
+ if (controller_id == 0) {
+ return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
+ };
+
+ return String();
+};
+
+XRController3D::XRController3D() {
+ controller_id = 1;
+ is_active = true;
+ button_states = 0;
+};
+
+XRController3D::~XRController3D(){
+ // nothing to do here yet for now..
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void XRAnchor3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ set_process_internal(true);
+ }; break;
+ case NOTIFICATION_EXIT_TREE: {
+ set_process_internal(false);
+ }; break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ 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) {
+ // this anchor is currently not available
+ is_active = false;
+ } else {
+ is_active = true;
+ Transform transform;
+
+ // we'll need our world_scale
+ real_t world_scale = xr_server->get_world_scale();
+
+ // get our info from our tracker
+ transform.basis = tracker->get_orientation();
+ transform.origin = tracker->get_position(); // <-- already adjusted to world scale
+
+ // our basis is scaled to the size of the plane the anchor is tracking
+ // extract the size from our basis and reset the scale
+ size = transform.basis.get_scale() * world_scale;
+ transform.basis.orthonormalize();
+
+ // apply our reference frame and set our transform
+ set_transform(xr_server->get_reference_frame() * transform);
+
+ // check for an updated mesh
+ Ref<Mesh> trackerMesh = tracker->get_mesh();
+ if (mesh != trackerMesh) {
+ mesh = trackerMesh;
+ emit_signal("mesh_updated", mesh);
+ }
+ };
+ }; break;
+ default:
+ break;
+ };
+};
+
+void XRAnchor3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &XRAnchor3D::set_anchor_id);
+ ClassDB::bind_method(D_METHOD("get_anchor_id"), &XRAnchor3D::get_anchor_id);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id");
+ ClassDB::bind_method(D_METHOD("get_anchor_name"), &XRAnchor3D::get_anchor_name);
+
+ ClassDB::bind_method(D_METHOD("get_is_active"), &XRAnchor3D::get_is_active);
+ ClassDB::bind_method(D_METHOD("get_size"), &XRAnchor3D::get_size);
+
+ ClassDB::bind_method(D_METHOD("get_plane"), &XRAnchor3D::get_plane);
+
+ ClassDB::bind_method(D_METHOD("get_mesh"), &XRAnchor3D::get_mesh);
+ ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
+};
+
+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();
+};
+
+int XRAnchor3D::get_anchor_id(void) const {
+ return anchor_id;
+};
+
+Vector3 XRAnchor3D::get_size() const {
+ return size;
+};
+
+String XRAnchor3D::get_anchor_name(void) const {
+ // get our XRServer
+ 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) {
+ return String("Not connected");
+ };
+
+ return tracker->get_name();
+};
+
+bool XRAnchor3D::get_is_active() const {
+ return is_active;
+};
+
+String XRAnchor3D::get_configuration_warning() const {
+ if (!is_visible() || !is_inside_tree())
+ return String();
+
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ return TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
+ };
+
+ if (anchor_id == 0) {
+ return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
+ };
+
+ return String();
+};
+
+Plane XRAnchor3D::get_plane() const {
+ Vector3 location = get_translation();
+ Basis orientation = get_transform().basis;
+
+ Plane plane(location, orientation.get_axis(1).normalized());
+
+ return plane;
+};
+
+Ref<Mesh> XRAnchor3D::get_mesh() const {
+ return mesh;
+}
+
+XRAnchor3D::XRAnchor3D() {
+ anchor_id = 1;
+ is_active = true;
+};
+
+XRAnchor3D::~XRAnchor3D(){
+ // nothing to do here yet for now..
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+String XROrigin3D::get_configuration_warning() const {
+ if (!is_visible() || !is_inside_tree())
+ return String();
+
+ if (tracked_camera == nullptr)
+ return TTR("XROrigin3D requires an XRCamera3D child node.");
+
+ return String();
+};
+
+void XROrigin3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale);
+ ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
+};
+
+void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) {
+ tracked_camera = p_tracked_camera;
+};
+
+void XROrigin3D::clear_tracked_camera_if(XRCamera3D *p_tracked_camera) {
+ if (tracked_camera == p_tracked_camera) {
+ tracked_camera = nullptr;
+ };
+};
+
+float XROrigin3D::get_world_scale() const {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, 1.0);
+
+ return xr_server->get_world_scale();
+};
+
+void XROrigin3D::set_world_scale(float p_world_scale) {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ xr_server->set_world_scale(p_world_scale);
+};
+
+void XROrigin3D::_notification(int p_what) {
+ // get our XRServer
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ set_process_internal(true);
+ }; break;
+ case NOTIFICATION_EXIT_TREE: {
+ set_process_internal(false);
+ }; break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ // set our world origin to our node transform
+ xr_server->set_world_origin(get_global_transform());
+
+ // check if we have a primary interface
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
+ if (xr_interface.is_valid() && tracked_camera != nullptr) {
+ // get our positioning transform for our headset
+ Transform t = xr_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform());
+
+ // now apply this to our camera
+ tracked_camera->set_transform(t);
+ };
+ }; break;
+ default:
+ break;
+ };
+
+ // send our notification to all active XE interfaces, they may need to react to it also
+ for (int i = 0; i < xr_server->get_interface_count(); i++) {
+ Ref<XRInterface> interface = xr_server->get_interface(i);
+ if (interface.is_valid() && interface->is_initialized()) {
+ interface->notification(p_what);
+ }
+ }
+};
+
+XROrigin3D::XROrigin3D() {
+ tracked_camera = nullptr;
+};
+
+XROrigin3D::~XROrigin3D(){
+ // nothing to do here yet for now..
+};
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
new file mode 100644
index 0000000000..a2f16545d1
--- /dev/null
+++ b/scene/3d/xr_nodes.h
@@ -0,0 +1,176 @@
+/*************************************************************************/
+/* xr_nodes.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 XR_NODES_H
+#define XR_NODES_H
+
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/resources/mesh.h"
+#include "servers/xr/xr_positional_tracker.h"
+
+/**
+ @author Bastiaan Olij <mux213@gmail.com>
+**/
+
+/*
+ XRCamera is a subclass of camera which will register itself with its parent XROrigin and as a result is automatically positioned
+*/
+class XRCamera3D : public Camera3D {
+
+ GDCLASS(XRCamera3D, Camera3D);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ String get_configuration_warning() const;
+
+ virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
+ virtual Point2 unproject_position(const Vector3 &p_pos) const;
+ virtual Vector3 project_position(const Point2 &p_point, float p_z_depth) const;
+ virtual Vector<Plane> get_frustum() const;
+
+ XRCamera3D();
+ ~XRCamera3D();
+};
+
+/*
+ XRController3D is a helper node that automatically updates its position based on tracker data.
+
+ It must be a child node of our XROrigin node
+*/
+
+class XRController3D : public Node3D {
+
+ GDCLASS(XRController3D, Node3D);
+
+private:
+ int controller_id;
+ bool is_active;
+ int button_states;
+ Ref<Mesh> mesh;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_controller_id(int p_controller_id);
+ int get_controller_id(void) const;
+ String get_controller_name(void) const;
+
+ int get_joystick_id() const;
+ bool is_button_pressed(int p_button) const;
+ float get_joystick_axis(int p_axis) const;
+
+ real_t get_rumble() const;
+ void set_rumble(real_t p_rumble);
+
+ bool get_is_active() const;
+ XRPositionalTracker::TrackerHand get_hand() const;
+
+ Ref<Mesh> get_mesh(void) const;
+
+ String get_configuration_warning() const;
+
+ XRController3D();
+ ~XRController3D();
+};
+
+/*
+ XRAnchor3D is a helper node that automatically updates its position based on anchor data, it represents a real world location.
+ It must be a child node of our XROrigin3D node
+*/
+
+class XRAnchor3D : public Node3D {
+ GDCLASS(XRAnchor3D, Node3D);
+
+private:
+ int anchor_id;
+ bool is_active;
+ Vector3 size;
+ Ref<Mesh> mesh;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_anchor_id(int p_anchor_id);
+ int get_anchor_id(void) const;
+ String get_anchor_name(void) const;
+
+ bool get_is_active() const;
+ Vector3 get_size() const;
+
+ Plane get_plane() const;
+
+ Ref<Mesh> get_mesh(void) const;
+
+ String get_configuration_warning() const;
+
+ XRAnchor3D();
+ ~XRAnchor3D();
+};
+
+/*
+ XROrigin3D is special spatial node that acts as our origin point mapping our real world center of our tracking volume into our virtual world.
+
+ It is this point that you will move around the world as the player 'moves while standing still', i.e. the player moves through teleporting or controller inputs as opposed to physically moving.
+
+ Our camera and controllers will always be child nodes and thus place relative to this origin point.
+ This node will automatically locate any camera child nodes and update its position while our XRController3D node will handle tracked controllers.
+*/
+class XROrigin3D : public Node3D {
+
+ GDCLASS(XROrigin3D, Node3D);
+
+private:
+ XRCamera3D *tracked_camera;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ String get_configuration_warning() const;
+
+ void set_tracked_camera(XRCamera3D *p_tracked_camera);
+ void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);
+
+ float get_world_scale() const;
+ void set_world_scale(float p_world_scale);
+
+ XROrigin3D();
+ ~XROrigin3D();
+};
+
+#endif /* XR_NODES_H */
diff --git a/scene/SCsub b/scene/SCsub
index 1c5b87b87a..f9fc00f3f2 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -1,16 +1,16 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.scene_sources = []
# Thirdparty code
thirdparty_dir = "#thirdparty/misc/"
thirdparty_sources = [
- # C++ sources
- "easing_equations.cpp",
- # C sources
- "mikktspace.c",
+ # C++ sources
+ "easing_equations.cpp",
+ # C sources
+ "mikktspace.c",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -23,14 +23,14 @@ env.add_source_files(env.scene_sources, "*.cpp")
# Chain load SCsubs
-SConscript('main/SCsub')
-SConscript('gui/SCsub')
-SConscript('3d/SCsub')
-SConscript('2d/SCsub')
-SConscript('animation/SCsub')
-SConscript('audio/SCsub')
-SConscript('resources/SCsub')
-SConscript('debugger/SCsub')
+SConscript("main/SCsub")
+SConscript("gui/SCsub")
+SConscript("3d/SCsub")
+SConscript("2d/SCsub")
+SConscript("animation/SCsub")
+SConscript("audio/SCsub")
+SConscript("resources/SCsub")
+SConscript("debugger/SCsub")
# Build it all as a library
diff --git a/scene/animation/SCsub b/scene/animation/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/animation/SCsub
+++ b/scene/animation/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 8ba7a38628..570735ad87 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -41,7 +41,7 @@ StringName AnimationNodeAnimation::get_animation() const {
return animation;
}
-Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL;
+Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr;
void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", 0));
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
index 9ed8155bdc..ab8be47b4d 100644
--- a/scene/animation/animation_cache.cpp
+++ b/scene/animation/animation_cache.cpp
@@ -94,19 +94,19 @@ void AnimationCache::_update_cache() {
ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath '" + np + "'.");
}
- Spatial *sp = Object::cast_to<Spatial>(node);
+ Node3D *sp = Object::cast_to<Node3D>(node);
if (!sp) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!sp, "Transform track not of type Spatial '" + np + "'.");
+ ERR_CONTINUE_MSG(!sp, "Transform track not of type Node3D '" + np + "'.");
}
if (np.get_subname_count() == 1) {
StringName property = np.get_subname(0);
String ps = property;
- Skeleton *sk = Object::cast_to<Skeleton>(node);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(node);
if (!sk) {
path_cache.push_back(Path());
@@ -287,7 +287,7 @@ void AnimationCache::set_all(float p_time, float p_delta) {
if (!args.size()) {
- call_track(i, name, NULL, 0, err);
+ call_track(i, name, nullptr, 0, err);
} else {
Vector<const Variant *> argptrs;
@@ -332,7 +332,7 @@ void AnimationCache::set_root(Node *p_root) {
AnimationCache::AnimationCache() {
- root = NULL;
+ root = nullptr;
cache_dirty = true;
cache_valid = false;
}
diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h
index e73b9e2498..23312ca7ec 100644
--- a/scene/animation/animation_cache.h
+++ b/scene/animation/animation_cache.h
@@ -31,7 +31,7 @@
#ifndef ANIMATION_CACHE_H
#define ANIMATION_CACHE_H
-#include "scene/3d/skeleton.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/resources/animation.h"
class AnimationCache : public Object {
@@ -42,20 +42,20 @@ class AnimationCache : public Object {
RES resource;
Object *object;
- Skeleton *skeleton; // haxor
+ Skeleton3D *skeleton; // haxor
Node *node;
- Spatial *spatial;
+ Node3D *spatial;
int bone_idx;
Vector<StringName> subpath;
bool valid;
Path() {
- object = NULL;
- skeleton = NULL;
- node = NULL;
+ object = nullptr;
+ skeleton = nullptr;
+ node = nullptr;
bone_idx = -1;
valid = false;
- spatial = NULL;
+ spatial = nullptr;
}
};
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index fbd9a2aa7d..9f5e06c43d 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -225,7 +225,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
}
//find the last cost transition
- List<int>::Element *least_cost_transition = NULL;
+ List<int>::Element *least_cost_transition = nullptr;
float least_cost = 1e20;
for (List<int>::Element *E = open_list.front(); E; E = E->next()) {
@@ -516,6 +516,11 @@ AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
len_current = 0;
fading_time = 0;
stop_request = false;
+ len_total = 0.0;
+ pos_current = 0.0;
+ loops_current = 0;
+ fading_pos = 0.0;
+ start_request_travel = false;
}
///////////////////////////////////////////////////////
@@ -525,7 +530,7 @@ void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) c
List<StringName> advance_conditions;
for (int i = 0; i < transitions.size(); i++) {
StringName ac = transitions[i].transition->get_advance_condition_name();
- if (ac != StringName() && advance_conditions.find(ac) == NULL) {
+ if (ac != StringName() && advance_conditions.find(ac) == nullptr) {
advance_conditions.push_back(ac);
}
}
@@ -565,6 +570,27 @@ void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<Animation
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
+void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<AnimationNode> p_node) {
+
+ ERR_FAIL_COND(states.has(p_name) == false);
+ ERR_FAIL_COND(p_node.is_null());
+ ERR_FAIL_COND(String(p_name).find("/") != -1);
+
+ {
+ Ref<AnimationNode> node = states[p_name].node;
+ if (node.is_valid()) {
+ node->disconnect_compat("tree_changed", this, "_tree_changed");
+ }
+ }
+
+ states[p_name].node = p_node;
+
+ emit_changed();
+ emit_signal("tree_changed");
+
+ p_node->connect_compat("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+}
+
Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const {
ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>());
@@ -949,6 +975,7 @@ void AnimationNodeStateMachine::_tree_changed() {
void AnimationNodeStateMachine::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeStateMachine::add_node, DEFVAL(Vector2()));
+ ClassDB::bind_method(D_METHOD("replace_node", "name", "node"), &AnimationNodeStateMachine::replace_node);
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node);
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeStateMachine::remove_node);
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeStateMachine::rename_node);
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 55c9c3f00e..27a4451f08 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -178,6 +178,7 @@ public:
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
+ void replace_node(const StringName &p_name, Ref<AnimationNode> p_node);
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 587485669e..b657833a3b 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -44,7 +44,7 @@ void AnimatedValuesBackup::update_skeletons() {
for (int i = 0; i < entries.size(); i++) {
if (entries[i].bone_idx != -1) {
// 3D bone
- Object::cast_to<Skeleton>(entries[i].object)->notification(Skeleton::NOTIFICATION_UPDATE_SKELETON);
+ Object::cast_to<Skeleton3D>(entries[i].object)->notification(Skeleton3D::NOTIFICATION_UPDATE_SKELETON);
} else {
Bone2D *bone = Object::cast_to<Bone2D>(entries[i].object);
if (bone && bone->skeleton) {
@@ -244,7 +244,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
for (int i = 0; i < a->get_track_count(); i++) {
- p_anim->node_cache.write[i] = NULL;
+ p_anim->node_cache.write[i] = nullptr;
RES resource;
Vector<StringName> leftover_path;
Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path);
@@ -252,9 +252,9 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
ObjectID id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
int bone_idx = -1;
- if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton>(child)) {
+ if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton3D>(child)) {
- Skeleton *sk = Object::cast_to<Skeleton>(child);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(child);
bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
if (bone_idx == -1) {
@@ -283,9 +283,9 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
// special cases and caches for transform tracks
// cache spatial
- p_anim->node_cache[i]->spatial = Object::cast_to<Spatial>(child);
+ p_anim->node_cache[i]->spatial = Object::cast_to<Node3D>(child);
// cache skeleton
- p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton>(child);
+ p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton3D>(child);
if (p_anim->node_cache[i]->skeleton) {
if (a->track_get_path(i).get_subname_count() == 1) {
StringName bone_name = a->track_get_path(i).get_subname(0);
@@ -293,13 +293,13 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name);
if (p_anim->node_cache[i]->bone_idx < 0) {
// broken track (nonexistent bone)
- p_anim->node_cache[i]->skeleton = NULL;
- p_anim->node_cache[i]->spatial = NULL;
+ p_anim->node_cache[i]->skeleton = nullptr;
+ p_anim->node_cache[i]->spatial = nullptr;
ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0);
}
} else {
// no property, just use spatialnode
- p_anim->node_cache[i]->skeleton = NULL;
+ p_anim->node_cache[i]->skeleton = nullptr;
}
}
}
@@ -830,7 +830,7 @@ void AnimationPlayer::_animation_process2(float p_delta, bool p_started) {
c.seeked = false;
}
- List<Blend>::Element *prev = NULL;
+ List<Blend>::Element *prev = nullptr;
for (List<Blend>::Element *E = c.blend.back(); E; E = prev) {
Blend &b = E->get();
@@ -1242,19 +1242,6 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float
bool AnimationPlayer::is_playing() const {
return playing;
- /*
- if (playback.current.from==NULL)
- return false;
-
- float len=playback.current.from->animation->get_length();
- float pos = playback.current.pos;
- bool loop=playback.current.from->animation->has_loop();
- if (!loop && pos >= len) {
- return false;
- };
-
- return true;
- */
}
void AnimationPlayer::set_current_animation(const String &p_anim) {
@@ -1296,7 +1283,7 @@ void AnimationPlayer::stop(bool p_reset) {
Playback &c = playback;
c.blend.clear();
if (p_reset) {
- c.current.from = NULL;
+ c.current.from = nullptr;
c.current.speed_scale = 1;
c.current.pos = 0;
}
@@ -1612,7 +1599,7 @@ void AnimationPlayer::restore_animated_values(const AnimatedValuesBackup &p_back
if (entry->bone_idx == -1) {
entry->object->set_indexed(entry->subpath, entry->value);
} else {
- Object::cast_to<Skeleton>(entry->object)->set_bone_pose(entry->bone_idx, entry->value);
+ Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose(entry->bone_idx, entry->value);
}
}
}
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 24f60363ed..c134aff707 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -32,8 +32,8 @@
#define ANIMATION_PLAYER_H
#include "scene/2d/node_2d.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/resources/animation.h"
#ifdef TOOLS_ENABLED
@@ -90,9 +90,9 @@ private:
uint32_t id;
RES resource;
Node *node;
- Spatial *spatial;
+ Node3D *spatial;
Node2D *node_2d;
- Skeleton *skeleton;
+ Skeleton3D *skeleton;
int bone_idx;
// accumulated transforms
@@ -118,9 +118,9 @@ private:
Variant capture;
PropertyAnim() :
- owner(NULL),
+ owner(nullptr),
special(SP_NONE),
- object(NULL),
+ object(nullptr),
accum_pass(0) {}
};
@@ -135,9 +135,9 @@ private:
uint64_t accum_pass;
BezierAnim() :
- owner(NULL),
+ owner(nullptr),
bezier_accum(0.0),
- object(NULL),
+ object(nullptr),
accum_pass(0) {}
};
@@ -145,10 +145,10 @@ private:
TrackNodeCache() :
id(0),
- node(NULL),
- spatial(NULL),
- node_2d(NULL),
- skeleton(NULL),
+ node(nullptr),
+ spatial(nullptr),
+ node_2d(nullptr),
+ skeleton(nullptr),
bone_idx(-1),
accum_pass(0),
audio_playing(false),
@@ -212,7 +212,7 @@ private:
pos = 0;
speed_scale = 1.0;
- from = NULL;
+ from = nullptr;
}
};
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 95afd74ee5..f8b3ca291b 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -128,8 +128,8 @@ float AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *
float t = process(p_time, p_seek);
- state = NULL;
- parent = NULL;
+ state = nullptr;
+ parent = nullptr;
base_path = StringName();
connections.clear();
@@ -164,7 +164,7 @@ float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p
//inputs.write[p_input].last_pass = state->last_pass;
float activity = 0;
- float ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), NULL, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity);
+ 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);
@@ -202,7 +202,7 @@ float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Strin
blendw[i] = 0.0; //all to zero by default
}
- const NodePath *K = NULL;
+ const NodePath *K = nullptr;
while ((K = filter.next(K))) {
if (!state->track_map.has(*K)) {
continue;
@@ -316,7 +316,7 @@ String AnimationNode::get_caption() const {
void AnimationNode::add_input(const String &p_name) {
//root nodes can't add inputs
- ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != NULL);
+ ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != nullptr);
Input input;
ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1);
input.name = p_name;
@@ -374,7 +374,7 @@ Array AnimationNode::_get_filters() const {
Array paths;
- const NodePath *K = NULL;
+ const NodePath *K = nullptr;
while ((K = filter.next(K))) {
paths.push_back(String(*K)); //use strings, so sorting is possible
}
@@ -453,8 +453,8 @@ void AnimationNode::_bind_methods() {
AnimationNode::AnimationNode() {
- state = NULL;
- parent = NULL;
+ state = nullptr;
+ parent = nullptr;
filter_enabled = false;
}
@@ -558,17 +558,17 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
NodePath path = anim->track_get_path(i);
Animation::TrackType track_type = anim->track_get_type(i);
- TrackCache *track = NULL;
+ TrackCache *track = nullptr;
if (track_cache.has(path)) {
track = track_cache.get(path);
}
//if not valid, delete track
- if (track && (track->type != track_type || ObjectDB::get_instance(track->object_id) == NULL)) {
+ if (track && (track->type != track_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
playing_caches.erase(track);
memdelete(track);
track_cache.erase(path);
- track = NULL;
+ track = nullptr;
}
if (!track) {
@@ -605,7 +605,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
} break;
case Animation::TYPE_TRANSFORM: {
- Spatial *spatial = Object::cast_to<Spatial>(child);
+ Node3D *spatial = Object::cast_to<Node3D>(child);
if (!spatial) {
ERR_PRINT("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'");
@@ -615,12 +615,12 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
track_xform->spatial = spatial;
- track_xform->skeleton = NULL;
+ track_xform->skeleton = nullptr;
track_xform->bone_idx = -1;
- if (path.get_subname_count() == 1 && Object::cast_to<Skeleton>(spatial)) {
+ if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(spatial)) {
- Skeleton *sk = Object::cast_to<Skeleton>(spatial);
+ Skeleton3D *sk = Object::cast_to<Skeleton3D>(spatial);
int bone_idx = sk->find_bone(path.get_subname(0));
if (bone_idx != -1) {
@@ -700,7 +700,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
List<NodePath> to_delete;
- const NodePath *K = NULL;
+ const NodePath *K = nullptr;
while ((K = track_cache.next(K))) {
TrackCache *tc = track_cache[*K];
if (tc->setup_pass != setup_pass) {
@@ -717,7 +717,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
state.track_map.clear();
- K = NULL;
+ K = nullptr;
int idx = 0;
while ((K = track_cache.next(K))) {
state.track_map[*K] = idx;
@@ -733,7 +733,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
void AnimationTree::_clear_caches() {
- const NodePath *K = NULL;
+ const NodePath *K = nullptr;
while ((K = track_cache.next(K))) {
memdelete(track_cache[*K]);
}
@@ -829,11 +829,11 @@ void AnimationTree::_process_graph(float p_delta) {
if (started) {
//if started, seek
- root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, 0, true, Vector<StringName>());
+ root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, nullptr, &state, 0, true, Vector<StringName>());
started = false;
}
- root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, p_delta, false, Vector<StringName>());
+ root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, nullptr, &state, p_delta, false, Vector<StringName>());
}
if (!state.valid) {
@@ -1224,7 +1224,7 @@ void AnimationTree::_process_graph(float p_delta) {
{
// finally, set the tracks
- const NodePath *K = NULL;
+ const NodePath *K = nullptr;
while ((K = track_cache.next(K))) {
TrackCache *track = track_cache[*K];
if (track->process_pass != process_pass)
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 8769e2c61d..d558170f23 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -32,8 +32,8 @@
#define ANIMATION_GRAPH_PLAYER_H
#include "animation_player.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/resources/animation.h"
class AnimationNodeBlendTree;
@@ -101,7 +101,7 @@ public:
Array _get_filters() const;
void _set_filters(const Array &p_filters);
friend class AnimationNodeBlendTree;
- float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
+ float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = nullptr);
protected:
void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend);
@@ -186,14 +186,14 @@ private:
root_motion = false;
setup_pass = 0;
process_pass = 0;
- object = NULL;
+ object = nullptr;
}
virtual ~TrackCache() {}
};
struct TrackCacheTransform : public TrackCache {
- Spatial *spatial;
- Skeleton *skeleton;
+ Node3D *spatial;
+ Skeleton3D *skeleton;
int bone_idx;
Vector3 loc;
Quat rot;
@@ -202,9 +202,9 @@ private:
TrackCacheTransform() {
type = Animation::TYPE_TRANSFORM;
- spatial = NULL;
+ spatial = nullptr;
bone_idx = -1;
- skeleton = NULL;
+ skeleton = nullptr;
}
};
@@ -285,7 +285,7 @@ private:
void _tree_changed();
void _update_properties();
List<PropertyInfo> properties;
- HashMap<StringName, HashMap<StringName, StringName> > property_parent_map;
+ HashMap<StringName, HashMap<StringName, StringName>> property_parent_map;
HashMap<StringName, Variant> property_map;
struct Activity {
@@ -293,7 +293,7 @@ private:
float activity;
};
- HashMap<StringName, Vector<Activity> > input_activity_map;
+ HashMap<StringName, Vector<Activity>> input_activity_map;
HashMap<StringName, Vector<Activity> *> input_activity_map_get;
void _update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node);
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index ce9b8bd213..f993127b07 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -79,7 +79,7 @@ void RootMotionView::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- VS::get_singleton()->immediate_set_material(immediate, StandardMaterial3D::get_material_rid_for_2d(false, true, false, false, false));
+ RS::get_singleton()->immediate_set_material(immediate, StandardMaterial3D::get_material_rid_for_2d(false, true, false, false, false));
first = true;
}
@@ -122,11 +122,11 @@ void RootMotionView::_notification(int p_what) {
}
accumulated.origin.z = Math::fposmod(accumulated.origin.z, cell_size);
- VS::get_singleton()->immediate_clear(immediate);
+ RS::get_singleton()->immediate_clear(immediate);
int cells_in_radius = int((radius / cell_size) + 1.0);
- VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_LINES);
+ RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_LINES);
for (int i = -cells_in_radius; i < cells_in_radius; i++) {
for (int j = -cells_in_radius; j < cells_in_radius; j++) {
@@ -142,21 +142,21 @@ void RootMotionView::_notification(int p_what) {
c_i.a *= MAX(0, 1.0 - from_i.length() / radius);
c_j.a *= MAX(0, 1.0 - from_j.length() / radius);
- VS::get_singleton()->immediate_color(immediate, c);
- VS::get_singleton()->immediate_vertex(immediate, from);
+ RS::get_singleton()->immediate_color(immediate, c);
+ RS::get_singleton()->immediate_vertex(immediate, from);
- VS::get_singleton()->immediate_color(immediate, c_i);
- VS::get_singleton()->immediate_vertex(immediate, from_i);
+ RS::get_singleton()->immediate_color(immediate, c_i);
+ RS::get_singleton()->immediate_vertex(immediate, from_i);
- VS::get_singleton()->immediate_color(immediate, c);
- VS::get_singleton()->immediate_vertex(immediate, from);
+ RS::get_singleton()->immediate_color(immediate, c);
+ RS::get_singleton()->immediate_vertex(immediate, from);
- VS::get_singleton()->immediate_color(immediate, c_j);
- VS::get_singleton()->immediate_vertex(immediate, from_j);
+ RS::get_singleton()->immediate_color(immediate, c_j);
+ RS::get_singleton()->immediate_vertex(immediate, from_j);
}
}
- VS::get_singleton()->immediate_end(immediate);
+ RS::get_singleton()->immediate_end(immediate);
}
}
@@ -197,12 +197,12 @@ RootMotionView::RootMotionView() {
radius = 10;
cell_size = 1;
set_process_internal(true);
- immediate = VisualServer::get_singleton()->immediate_create();
+ immediate = RenderingServer::get_singleton()->immediate_create();
set_base(immediate);
color = Color(0.5, 0.5, 1.0);
}
RootMotionView::~RootMotionView() {
set_base(RID());
- VisualServer::get_singleton()->free(immediate);
+ RenderingServer::get_singleton()->free(immediate);
}
diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h
index 42950dde42..c8a755a854 100644
--- a/scene/animation/root_motion_view.h
+++ b/scene/animation/root_motion_view.h
@@ -31,10 +31,10 @@
#ifndef ROOT_MOTION_VIEW_H
#define ROOT_MOTION_VIEW_H
-#include "scene/3d/visual_instance.h"
+#include "scene/3d/visual_instance_3d.h"
-class RootMotionView : public VisualInstance {
- GDCLASS(RootMotionView, VisualInstance);
+class RootMotionView : public VisualInstance3D {
+ GDCLASS(RootMotionView, VisualInstance3D);
public:
RID immediate;
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
deleted file mode 100644
index 5cdb38b5c2..0000000000
--- a/scene/animation/skeleton_ik.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-/*************************************************************************/
-/* skeleton_ik.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/**
- * @author AndreaCatania
- */
-
-#include "skeleton_ik.h"
-
-#ifndef _3D_DISABLED
-
-FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) {
- for (int i = children.size() - 1; 0 <= i; --i) {
- if (p_bone_id == children[i].bone) {
- return &children.write[i];
- }
- }
- return NULL;
-}
-
-FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(const BoneId p_bone_id) {
- const int infant_child_id = children.size();
- children.resize(infant_child_id + 1);
- children.write[infant_child_id].bone = p_bone_id;
- children.write[infant_child_id].parent_item = this;
- return &children.write[infant_child_id];
-}
-
-/// Build a chain that starts from the root to tip
-bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) {
-
- ERR_FAIL_COND_V(-1 == p_task->root_bone, false);
-
- Chain &chain(p_task->chain);
-
- chain.tips.resize(p_task->end_effectors.size());
- 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 = NULL;
-
- // Holds all IDs that are composing a single chain in reverse order
- Vector<BoneId> chain_ids;
- // This is used to know the chain size
- int sub_chain_size;
- // Resize only one time in order to fit all joints for performance reason
- chain_ids.resize(p_task->skeleton->get_bone_count());
-
- for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) {
-
- const EndEffector *ee(&p_task->end_effectors[x]);
- ERR_FAIL_COND_V(p_task->root_bone >= ee->tip_bone, false);
- ERR_FAIL_INDEX_V(ee->tip_bone, p_task->skeleton->get_bone_count(), false);
-
- sub_chain_size = 0;
- // Picks all IDs that composing a single chain in reverse order (except the root)
- BoneId chain_sub_tip(ee->tip_bone);
- while (chain_sub_tip > p_task->root_bone) {
-
- chain_ids.write[sub_chain_size++] = chain_sub_tip;
- chain_sub_tip = p_task->skeleton->get_bone_parent(chain_sub_tip);
- }
-
- BoneId middle_chain_item_id = (((float)sub_chain_size) * 0.5);
-
- // Build chain by reading chain ids in reverse order
- // For each chain item id will be created a ChainItem if doesn't exists
- ChainItem *sub_chain(&chain.chain_root);
- for (int i = sub_chain_size - 1; 0 <= i; --i) {
-
- ChainItem *child_ci(sub_chain->find_child(chain_ids[i]));
- 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;
-
- if (child_ci->parent_item) {
- child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length();
- }
- }
-
- sub_chain = child_ci;
-
- if (middle_chain_item_id == i) {
- chain.middle_chain_item = child_ci;
- }
- }
-
- if (!middle_chain_item_id)
- chain.middle_chain_item = NULL;
-
- // Initialize current tip
- chain.tips.write[x].chain_item = sub_chain;
- chain.tips.write[x].end_effector = ee;
-
- 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)
- // is not yet created.
- // Remove this code when this is done
- break;
- }
- }
- return true;
-}
-
-void FabrikInverseKinematic::update_chain(const Skeleton *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;
-
- for (int i = p_chain_item->children.size() - 1; 0 <= i; --i) {
- update_chain(p_sk, &p_chain_item->children.write[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);
- int can_solve(p_task->max_iterations);
- while (distance_to_goal > p_task->min_distance && Math::abs(previous_distance_to_goal - distance_to_goal) > 0.005 && can_solve) {
- previous_distance_to_goal = distance_to_goal;
- --can_solve;
-
- solve_simple_backwards(p_task->chain, p_solve_magnet);
- solve_simple_forwards(p_task->chain, p_solve_magnet);
-
- distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length();
- }
-}
-
-void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve_magnet) {
-
- if (p_solve_magnet && !r_chain.middle_chain_item) {
- return;
- }
-
- Vector3 goal;
- ChainItem *sub_chain_tip;
- if (p_solve_magnet) {
- goal = r_chain.magnet_position;
- sub_chain_tip = r_chain.middle_chain_item;
- } else {
- goal = r_chain.tips[0].end_effector->goal_transform.origin;
- sub_chain_tip = r_chain.tips[0].chain_item;
- }
-
- while (sub_chain_tip) {
- sub_chain_tip->current_pos = goal;
-
- if (sub_chain_tip->parent_item) {
- // Not yet in the chain root
- // So calculate next goal location
-
- const Vector3 look_parent((sub_chain_tip->parent_item->current_pos - sub_chain_tip->current_pos).normalized());
- goal = sub_chain_tip->current_pos + (look_parent * sub_chain_tip->length);
-
- // [TODO] Constraints goes here
- }
-
- sub_chain_tip = sub_chain_tip->parent_item;
- }
-}
-
-void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) {
-
- if (p_solve_magnet && !r_chain.middle_chain_item) {
- return;
- }
-
- ChainItem *sub_chain_root(&r_chain.chain_root);
- Vector3 origin(r_chain.chain_root.initial_transform.origin);
-
- while (sub_chain_root) { // Reach the tip
- sub_chain_root->current_pos = origin;
-
- if (!sub_chain_root->children.empty()) {
-
- ChainItem &child(sub_chain_root->children.write[0]);
-
- // Is not tip
- // So calculate next origin location
-
- // Look child
- sub_chain_root->current_ori = (child.current_pos - sub_chain_root->current_pos).normalized();
- origin = sub_chain_root->current_pos + (sub_chain_root->current_ori * child.length);
-
- // [TODO] Constraints goes here
-
- if (p_solve_magnet && sub_chain_root == r_chain.middle_chain_item) {
- // In case of magnet solving this is the tip
- sub_chain_root = NULL;
- } else {
- sub_chain_root = &child;
- }
- } else {
-
- // Is tip
- sub_chain_root = NULL;
- }
- }
-}
-
-FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) {
-
- FabrikInverseKinematic::EndEffector ee;
- ee.tip_bone = tip_bone;
-
- Task *task(memnew(Task));
- task->skeleton = p_sk;
- task->root_bone = root_bone;
- task->end_effectors.push_back(ee);
- task->goal_global_transform = goal_transform;
-
- if (!build_chain(task)) {
- free_task(task);
- return NULL;
- }
-
- return task;
-}
-
-void FabrikInverseKinematic::free_task(Task *p_task) {
- if (p_task)
- memdelete(p_task);
-}
-
-void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) {
- p_task->goal_global_transform = p_goal;
-}
-
-void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta) {
-
- if (blending_delta >= 0.99f) {
- // Update the end_effector (local transform) without blending
- 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));
-
- // 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);
- }
-}
-
-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) {
- return; // Skip solving
- }
-
- 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_chain(p_task->skeleton, &p_task->chain.chain_root);
-
- if (p_use_magnet && p_task->chain.middle_chain_item) {
- p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.linear_interpolate(p_magnet_position, blending_delta);
- solve_simple(p_task, true);
- }
- solve_simple(p_task, false);
-
- // Assign new bone position.
- ChainItem *ci(&p_task->chain.chain_root);
- while (ci) {
- Transform new_bone_pose(ci->initial_transform);
- new_bone_pose.origin = ci->current_pos;
-
- if (!ci->children.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 {
- // 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;
- }
-
- p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0, true);
-
- if (!ci->children.empty())
- ci = &ci->children.write[0];
- else
- ci = NULL;
- }
-}
-
-void SkeletonIK::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "root_bone" || property.name == "tip_bone") {
-
- if (skeleton) {
-
- String names("--,");
- for (int i = 0; i < skeleton->get_bone_count(); i++) {
- if (i > 0)
- names += ",";
- names += skeleton->get_bone_name(i);
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = names;
- } else {
-
- property.hint = PROPERTY_HINT_NONE;
- property.hint_string = "";
- }
- }
-}
-
-void SkeletonIK::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_root_bone", "root_bone"), &SkeletonIK::set_root_bone);
- ClassDB::bind_method(D_METHOD("get_root_bone"), &SkeletonIK::get_root_bone);
-
- ClassDB::bind_method(D_METHOD("set_tip_bone", "tip_bone"), &SkeletonIK::set_tip_bone);
- ClassDB::bind_method(D_METHOD("get_tip_bone"), &SkeletonIK::get_tip_bone);
-
- ClassDB::bind_method(D_METHOD("set_interpolation", "interpolation"), &SkeletonIK::set_interpolation);
- ClassDB::bind_method(D_METHOD("get_interpolation"), &SkeletonIK::get_interpolation);
-
- ClassDB::bind_method(D_METHOD("set_target_transform", "target"), &SkeletonIK::set_target_transform);
- ClassDB::bind_method(D_METHOD("get_target_transform"), &SkeletonIK::get_target_transform);
-
- ClassDB::bind_method(D_METHOD("set_target_node", "node"), &SkeletonIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonIK::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_override_tip_basis", "override"), &SkeletonIK::set_override_tip_basis);
- ClassDB::bind_method(D_METHOD("is_override_tip_basis"), &SkeletonIK::is_override_tip_basis);
-
- ClassDB::bind_method(D_METHOD("set_use_magnet", "use"), &SkeletonIK::set_use_magnet);
- ClassDB::bind_method(D_METHOD("is_using_magnet"), &SkeletonIK::is_using_magnet);
-
- ClassDB::bind_method(D_METHOD("set_magnet_position", "local_position"), &SkeletonIK::set_magnet_position);
- ClassDB::bind_method(D_METHOD("get_magnet_position"), &SkeletonIK::get_magnet_position);
-
- ClassDB::bind_method(D_METHOD("get_parent_skeleton"), &SkeletonIK::get_parent_skeleton);
- ClassDB::bind_method(D_METHOD("is_running"), &SkeletonIK::is_running);
-
- ClassDB::bind_method(D_METHOD("set_min_distance", "min_distance"), &SkeletonIK::set_min_distance);
- ClassDB::bind_method(D_METHOD("get_min_distance"), &SkeletonIK::get_min_distance);
-
- ClassDB::bind_method(D_METHOD("set_max_iterations", "iterations"), &SkeletonIK::set_max_iterations);
- ClassDB::bind_method(D_METHOD("get_max_iterations"), &SkeletonIK::get_max_iterations);
-
- ClassDB::bind_method(D_METHOD("start", "one_time"), &SkeletonIK::start, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("stop"), &SkeletonIK::stop);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone"), "set_root_bone", "get_root_bone");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "tip_bone"), "set_tip_bone", "get_tip_bone");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_tip_basis"), "set_override_tip_basis", "is_override_tip_basis");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min_distance"), "set_min_distance", "get_min_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_iterations"), "set_max_iterations", "get_max_iterations");
-}
-
-void SkeletonIK::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- skeleton = Object::cast_to<Skeleton>(get_parent());
- set_process_priority(1);
- reload_chain();
- } break;
- case NOTIFICATION_INTERNAL_PROCESS: {
-
- if (target_node_override)
- reload_goal();
-
- _solve_chain();
-
- } break;
- case NOTIFICATION_EXIT_TREE: {
- reload_chain();
- } break;
- }
-}
-
-SkeletonIK::SkeletonIK() :
- interpolation(1),
- override_tip_basis(true),
- use_magnet(false),
- min_distance(0.01),
- max_iterations(10),
- skeleton(NULL),
- target_node_override(NULL),
- task(NULL) {
-}
-
-SkeletonIK::~SkeletonIK() {
- FabrikInverseKinematic::free_task(task);
- task = NULL;
-}
-
-void SkeletonIK::set_root_bone(const StringName &p_root_bone) {
- root_bone = p_root_bone;
- reload_chain();
-}
-
-StringName SkeletonIK::get_root_bone() const {
- return root_bone;
-}
-
-void SkeletonIK::set_tip_bone(const StringName &p_tip_bone) {
- tip_bone = p_tip_bone;
- reload_chain();
-}
-
-StringName SkeletonIK::get_tip_bone() const {
- return tip_bone;
-}
-
-void SkeletonIK::set_interpolation(real_t p_interpolation) {
- interpolation = p_interpolation;
-}
-
-real_t SkeletonIK::get_interpolation() const {
- return interpolation;
-}
-
-void SkeletonIK::set_target_transform(const Transform &p_target) {
- target = p_target;
- reload_goal();
-}
-
-const Transform &SkeletonIK::get_target_transform() const {
- return target;
-}
-
-void SkeletonIK::set_target_node(const NodePath &p_node) {
- target_node_path_override = p_node;
- target_node_override = NULL;
- reload_goal();
-}
-
-NodePath SkeletonIK::get_target_node() {
- return target_node_path_override;
-}
-
-void SkeletonIK::set_override_tip_basis(bool p_override) {
- override_tip_basis = p_override;
-}
-
-bool SkeletonIK::is_override_tip_basis() const {
- return override_tip_basis;
-}
-
-void SkeletonIK::set_use_magnet(bool p_use) {
- use_magnet = p_use;
-}
-
-bool SkeletonIK::is_using_magnet() const {
- return use_magnet;
-}
-
-void SkeletonIK::set_magnet_position(const Vector3 &p_local_position) {
- magnet_position = p_local_position;
-}
-
-const Vector3 &SkeletonIK::get_magnet_position() const {
- return magnet_position;
-}
-
-void SkeletonIK::set_min_distance(real_t p_min_distance) {
- min_distance = p_min_distance;
-}
-
-void SkeletonIK::set_max_iterations(int p_iterations) {
- max_iterations = p_iterations;
-}
-
-bool SkeletonIK::is_running() {
- return is_processing_internal();
-}
-
-void SkeletonIK::start(bool p_one_time) {
- if (p_one_time) {
- set_process_internal(false);
- _solve_chain();
- } else {
- set_process_internal(true);
- }
-}
-
-void SkeletonIK::stop() {
- set_process_internal(false);
-}
-
-Transform SkeletonIK::_get_target_transform() {
-
- if (!target_node_override && !target_node_path_override.is_empty())
- target_node_override = Object::cast_to<Spatial>(get_node(target_node_path_override));
-
- if (target_node_override)
- return target_node_override->get_global_transform();
- else
- return target;
-}
-
-void SkeletonIK::reload_chain() {
-
- FabrikInverseKinematic::free_task(task);
- task = NULL;
-
- if (!skeleton)
- return;
-
- task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform());
- if (task) {
- task->max_iterations = max_iterations;
- task->min_distance = min_distance;
- }
-}
-
-void SkeletonIK::reload_goal() {
- if (!task)
- return;
-
- FabrikInverseKinematic::set_goal(task, _get_target_transform());
-}
-
-void SkeletonIK::_solve_chain() {
- if (!task)
- return;
- FabrikInverseKinematic::solve(task, interpolation, override_tip_basis, use_magnet, magnet_position);
-}
-
-#endif // _3D_DISABLED
diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h
deleted file mode 100644
index 02d5aba5ba..0000000000
--- a/scene/animation/skeleton_ik.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*************************************************************************/
-/* skeleton_ik.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SKELETON_IK_H
-#define SKELETON_IK_H
-
-#ifndef _3D_DISABLED
-
-/**
- * @author AndreaCatania
- */
-
-#include "core/math/transform.h"
-#include "scene/3d/skeleton.h"
-
-class FabrikInverseKinematic {
-
- struct EndEffector {
- BoneId tip_bone;
- Transform goal_transform;
- };
-
- struct ChainItem {
-
- Vector<ChainItem> children;
- ChainItem *parent_item;
-
- // Bone info
- BoneId bone;
- PhysicalBone *pb;
-
- real_t length;
- /// Positions relative to root bone
- Transform initial_transform;
- Vector3 current_pos;
- // Direction from this bone to child
- Vector3 current_ori;
-
- ChainItem() :
- parent_item(NULL),
- bone(-1),
- pb(NULL),
- length(0) {}
-
- ChainItem *find_child(const BoneId p_bone_id);
- ChainItem *add_child(const BoneId p_bone_id);
- };
-
- struct ChainTip {
- ChainItem *chain_item;
- const EndEffector *end_effector;
-
- ChainTip() :
- chain_item(NULL),
- end_effector(NULL) {}
-
- ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) :
- chain_item(p_chain_item),
- end_effector(p_end_effector) {}
-
- ChainTip(const ChainTip &p_other_ct) :
- chain_item(p_other_ct.chain_item),
- end_effector(p_other_ct.end_effector) {}
- };
-
- struct Chain {
- ChainItem chain_root;
- ChainItem *middle_chain_item;
- Vector<ChainTip> tips;
- Vector3 magnet_position;
- };
-
-public:
- struct Task {
- RID self;
- Skeleton *skeleton;
-
- Chain chain;
-
- // Settings
- real_t min_distance;
- int max_iterations;
-
- // Bone data
- BoneId root_bone;
- Vector<EndEffector> end_effectors;
-
- Transform goal_global_transform;
-
- Task() :
- skeleton(NULL),
- min_distance(0.01),
- max_iterations(10),
- root_bone(-1) {}
- };
-
-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 Skeleton *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);
- static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet);
-
-public:
- static Task *create_simple_task(Skeleton *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform);
- static void free_task(Task *p_task);
- // The goal of chain should be always in local space
- 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);
-};
-
-class SkeletonIK : public Node {
- GDCLASS(SkeletonIK, Node);
-
- StringName root_bone;
- StringName tip_bone;
- real_t interpolation;
- Transform target;
- NodePath target_node_path_override;
- bool override_tip_basis;
- bool use_magnet;
- Vector3 magnet_position;
-
- real_t min_distance;
- int max_iterations;
-
- Skeleton *skeleton;
- Spatial *target_node_override;
- FabrikInverseKinematic::Task *task;
-
-protected:
- virtual void
- _validate_property(PropertyInfo &property) const;
-
- static void _bind_methods();
- virtual void _notification(int p_what);
-
-public:
- SkeletonIK();
- virtual ~SkeletonIK();
-
- void set_root_bone(const StringName &p_root_bone);
- StringName get_root_bone() const;
-
- void set_tip_bone(const StringName &p_tip_bone);
- StringName get_tip_bone() const;
-
- void set_interpolation(real_t p_interpolation);
- real_t get_interpolation() const;
-
- void set_target_transform(const Transform &p_target);
- const Transform &get_target_transform() const;
-
- void set_target_node(const NodePath &p_node);
- NodePath get_target_node();
-
- void set_override_tip_basis(bool p_override);
- bool is_override_tip_basis() const;
-
- void set_use_magnet(bool p_use);
- bool is_using_magnet() const;
-
- void set_magnet_position(const Vector3 &p_local_position);
- const Vector3 &get_magnet_position() const;
-
- void set_min_distance(real_t p_min_distance);
- real_t get_min_distance() const { return min_distance; }
-
- void set_max_iterations(int p_iterations);
- int get_max_iterations() const { return max_iterations; }
-
- Skeleton *get_parent_skeleton() const { return skeleton; }
-
- bool is_running();
-
- void start(bool p_one_time = false);
- void stop();
-
-private:
- Transform _get_target_transform();
- void reload_chain();
- void reload_goal();
- void _solve_chain();
-};
-
-#endif // _3D_DISABLED
-
-#endif // SKELETON_IK_H
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 628568afbb..bc28c38e2c 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -297,7 +297,7 @@ Variant Tween::_get_initial_val(const InterpolateData &p_data) const {
case TARGETING_METHOD: {
// Get the object that is being targeted
Object *object = ObjectDB::get_instance(p_data.target_id);
- ERR_FAIL_COND_V(object == NULL, p_data.initial_val);
+ ERR_FAIL_COND_V(object == nullptr, p_data.initial_val);
// Are we targeting a property or a method?
Variant initial_val;
@@ -309,7 +309,7 @@ Variant Tween::_get_initial_val(const InterpolateData &p_data) const {
} else {
// Call the method and get the initial value from it
Callable::CallError error;
- initial_val = object->call(p_data.target_key[0], NULL, 0, error);
+ initial_val = object->call(p_data.target_key[0], nullptr, 0, error);
ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, p_data.initial_val);
}
return initial_val;
@@ -329,7 +329,7 @@ Variant Tween::_get_final_val(const InterpolateData &p_data) const {
case FOLLOW_METHOD: {
// Get the object that is being followed
Object *target = ObjectDB::get_instance(p_data.target_id);
- ERR_FAIL_COND_V(target == NULL, p_data.initial_val);
+ ERR_FAIL_COND_V(target == nullptr, p_data.initial_val);
// We want to figure out the final value
Variant final_val;
@@ -341,7 +341,7 @@ Variant Tween::_get_final_val(const InterpolateData &p_data) const {
} else {
// We're looking at a method. Call the method on the target object
Callable::CallError error;
- final_val = target->call(p_data.target_key[0], NULL, 0, error);
+ final_val = target->call(p_data.target_key[0], nullptr, 0, error);
ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, p_data.initial_val);
}
@@ -371,7 +371,7 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) {
case FOLLOW_METHOD: {
// We're following an object, so grab that instance
Object *target = ObjectDB::get_instance(p_data.target_id);
- ERR_FAIL_COND_V(target == NULL, p_data.initial_val);
+ ERR_FAIL_COND_V(target == nullptr, p_data.initial_val);
// We want to figure out the final value
Variant final_val;
@@ -383,7 +383,7 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) {
} else {
// We're looking at a method. Call the method on the target object
Callable::CallError error;
- final_val = target->call(p_data.target_key[0], NULL, 0, error);
+ final_val = target->call(p_data.target_key[0], nullptr, 0, error);
ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, p_data.initial_val);
}
@@ -607,7 +607,7 @@ bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) {
// Get the object we want to apply the new value to
Object *object = ObjectDB::get_instance(p_data.id);
- ERR_FAIL_COND_V(object == NULL, false);
+ ERR_FAIL_COND_V(object == nullptr, false);
// What kind of data are we mutating?
switch (p_data.type) {
@@ -634,7 +634,7 @@ bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) {
object->call(p_data.key[0], (const Variant **)arg, 1, error);
} else {
// Don't pass any argument
- object->call(p_data.key[0], NULL, 0, error);
+ object->call(p_data.key[0], nullptr, 0, error);
}
// Did we get an error from the function call?
@@ -700,7 +700,7 @@ void Tween::_tween_process(float p_delta) {
// Get the target object for this interpolation
Object *object = ObjectDB::get_instance(data.id);
- if (object == NULL)
+ if (object == nullptr)
continue;
// Are we still delaying this tween?
@@ -860,7 +860,7 @@ void Tween::reset(Object *p_object, StringName p_key) {
// Get the target object
InterpolateData &data = E->get();
Object *object = ObjectDB::get_instance(data.id);
- if (object == NULL)
+ if (object == nullptr)
continue;
// Do we have the correct object and key?
@@ -901,7 +901,7 @@ void Tween::stop(Object *p_object, StringName p_key) {
// Get the object the tween is targeting
InterpolateData &data = E->get();
Object *object = ObjectDB::get_instance(data.id);
- if (object == NULL)
+ if (object == nullptr)
continue;
// Is this the correct object and does it have the given key?
@@ -937,7 +937,7 @@ void Tween::resume(Object *p_object, StringName p_key) {
// Grab the object
InterpolateData &data = E->get();
Object *object = ObjectDB::get_instance(data.id);
- if (object == NULL)
+ if (object == nullptr)
continue;
// If the object and string key match, activate it
@@ -975,7 +975,7 @@ void Tween::remove(Object *p_object, StringName p_key) {
// Get the target object
InterpolateData &data = E->get();
Object *object = ObjectDB::get_instance(data.id);
- if (object == NULL)
+ if (object == nullptr)
continue;
// If the target object and string key match, queue it for removal
@@ -1264,7 +1264,7 @@ void Tween::_build_interpolation(InterpolateType p_interpolation_type, Object *p
// Validate and apply interpolation data
// Give it the object
- ERR_FAIL_COND_MSG(p_object == NULL, "Invalid object provided to Tween.");
+ ERR_FAIL_COND_MSG(p_object == nullptr, "Invalid object provided to Tween.");
data.id = p_object->get_instance_id();
// Validate the initial and final values
@@ -1335,7 +1335,7 @@ void Tween::interpolate_property(Object *p_object, NodePath p_property, Variant
if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
// Build the interpolation data
- _build_interpolation(INTER_PROPERTY, p_object, &p_property, NULL, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);
+ _build_interpolation(INTER_PROPERTY, p_object, &p_property, nullptr, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);
}
void Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) {
@@ -1350,7 +1350,7 @@ void Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_
if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
// Build the interpolation data
- _build_interpolation(INTER_METHOD, p_object, NULL, &p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);
+ _build_interpolation(INTER_METHOD, p_object, nullptr, &p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay);
}
void Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE) {
@@ -1361,7 +1361,7 @@ void Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_c
}
// Check that the target object is valid
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
// Duration cannot be negative
ERR_FAIL_COND(p_duration < 0);
@@ -1418,7 +1418,7 @@ void Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S
}
// Check that the target object is valid
- ERR_FAIL_COND(p_object == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
// No negative durations allowed
ERR_FAIL_COND(p_duration < 0);
@@ -1486,8 +1486,8 @@ void Tween::follow_property(Object *p_object, NodePath p_property, Variant p_ini
if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
// Confirm the source and target objects are valid
- ERR_FAIL_COND(p_object == NULL);
- ERR_FAIL_COND(p_target == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_COND(p_target == nullptr);
// No negative durations
ERR_FAIL_COND(p_duration < 0);
@@ -1547,8 +1547,8 @@ void Tween::follow_method(Object *p_object, StringName p_method, Variant p_initi
if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
// Verify the source and target objects are valid
- ERR_FAIL_COND(p_object == NULL);
- ERR_FAIL_COND(p_target == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_COND(p_target == nullptr);
// No negative durations
ERR_FAIL_COND(p_duration < 0);
@@ -1566,7 +1566,7 @@ void Tween::follow_method(Object *p_object, StringName p_method, Variant p_initi
// Call the method to get the target value
Callable::CallError error;
- Variant target_val = p_target->call(p_target_method, NULL, 0, error);
+ Variant target_val = p_target->call(p_target_method, nullptr, 0, error);
ERR_FAIL_COND(error.error != Callable::CallError::CALL_OK);
// Convert target INT values to FLOAT as they are better for interpolation
@@ -1610,8 +1610,8 @@ void Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_
if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
// Verify both objects are valid
- ERR_FAIL_COND(p_object == NULL);
- ERR_FAIL_COND(p_initial == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_COND(p_initial == nullptr);
// No negative durations
ERR_FAIL_COND(p_duration < 0);
@@ -1676,8 +1676,8 @@ void Tween::targeting_method(Object *p_object, StringName p_method, Object *p_in
if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
// Make sure the given objects are valid
- ERR_FAIL_COND(p_object == NULL);
- ERR_FAIL_COND(p_initial == NULL);
+ ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_COND(p_initial == nullptr);
// No negative durations
ERR_FAIL_COND(p_duration < 0);
@@ -1695,7 +1695,7 @@ void Tween::targeting_method(Object *p_object, StringName p_method, Object *p_in
// Call the method to get the initial value
Callable::CallError error;
- Variant initial_val = p_initial->call(p_initial_method, NULL, 0, error);
+ Variant initial_val = p_initial->call(p_initial_method, nullptr, 0, error);
ERR_FAIL_COND(error.error != Callable::CallError::CALL_OK);
// Convert initial INT values to FLOAT as they aer better for interpolation
diff --git a/scene/audio/SCsub b/scene/audio/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/audio/SCsub
+++ b/scene/audio/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 2582bab200..f612944a62 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -36,7 +36,7 @@ void AudioStreamPlayer::_mix_to_bus(const AudioFrame *p_frames, int p_amount) {
int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
- AudioFrame *targets[4] = { NULL, NULL, NULL, NULL };
+ AudioFrame *targets[4] = { nullptr, nullptr, nullptr, nullptr };
if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) {
targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
diff --git a/scene/debugger/SCsub b/scene/debugger/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/debugger/SCsub
+++ b/scene/debugger/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 2a98b4cf22..8cb63c4ab5 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -34,13 +34,13 @@
#include "core/io/marshalls.h"
#include "core/script_language.h"
#include "scene/main/scene_tree.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
void SceneDebugger::initialize() {
#ifdef DEBUG_ENABLED
LiveEditor::singleton = memnew(LiveEditor);
- EngineDebugger::register_message_capture("scene", EngineDebugger::Capture(NULL, SceneDebugger::parse_message));
+ EngineDebugger::register_message_capture("scene", EngineDebugger::Capture(nullptr, SceneDebugger::parse_message));
#endif
}
@@ -51,7 +51,7 @@ void SceneDebugger::deinitialize() {
if (EngineDebugger::has_capture("scene"))
EngineDebugger::unregister_message_capture("scene");
memdelete(LiveEditor::singleton);
- LiveEditor::singleton = NULL;
+ LiveEditor::singleton = nullptr;
}
#endif
}
@@ -230,8 +230,8 @@ void SceneDebugger::remove_from_cache(const String &p_filename, Node *p_node) {
if (!debugger)
return;
- Map<String, Set<Node *> > &edit_cache = debugger->live_scene_edit_cache;
- Map<String, Set<Node *> >::Element *E = edit_cache.find(p_filename);
+ Map<String, Set<Node *>> &edit_cache = debugger->live_scene_edit_cache;
+ Map<String, Set<Node *>>::Element *E = edit_cache.find(p_filename);
if (E) {
E->get().erase(p_node);
if (E->get().size() == 0) {
@@ -239,8 +239,8 @@ void SceneDebugger::remove_from_cache(const String &p_filename, Node *p_node) {
}
}
- Map<Node *, Map<ObjectID, Node *> > &remove_list = debugger->live_edit_remove_list;
- Map<Node *, Map<ObjectID, Node *> >::Element *F = remove_list.find(p_node);
+ Map<Node *, Map<ObjectID, Node *>> &remove_list = debugger->live_edit_remove_list;
+ Map<Node *, Map<ObjectID, Node *>>::Element *F = remove_list.find(p_node);
if (F) {
for (Map<ObjectID, Node *>::Element *G = F->get().front(); G; G = G->next()) {
@@ -279,7 +279,7 @@ SceneDebuggerObject::SceneDebuggerObject(ObjectID p_id) {
}
} else if (Script *s = Object::cast_to<Script>(obj)) {
// Add script constants (no instance).
- _parse_script_properties(s, NULL);
+ _parse_script_properties(s, nullptr);
}
// Add base object properties.
@@ -293,8 +293,8 @@ SceneDebuggerObject::SceneDebuggerObject(ObjectID p_id) {
}
void SceneDebuggerObject::_parse_script_properties(Script *p_script, ScriptInstance *p_instance) {
- typedef Map<const Script *, Set<StringName> > ScriptMemberMap;
- typedef Map<const Script *, Map<StringName, Variant> > ScriptConstantsMap;
+ typedef Map<const Script *, Set<StringName>> ScriptMemberMap;
+ typedef Map<const Script *, Map<StringName, Variant>> ScriptConstantsMap;
ScriptMemberMap members;
if (p_instance) {
@@ -373,7 +373,7 @@ void SceneDebuggerObject::serialize(Array &r_arr, int p_max_size) {
var = res->get_path();
} else { //only send information that can be sent..
int len = 0; //test how big is this to encode
- encode_variant(var, NULL, len);
+ encode_variant(var, nullptr, len);
if (len > p_max_size) { //limit to max size
hint = PROPERTY_HINT_OBJECT_TOO_BIG;
hint_string = "";
@@ -478,7 +478,7 @@ void SceneDebuggerTree::deserialize(const Array &p_arr) {
}
/// LiveEditor
-LiveEditor *LiveEditor::singleton = NULL;
+LiveEditor *LiveEditor::singleton = nullptr;
LiveEditor *LiveEditor::get_singleton() {
return singleton;
}
@@ -515,11 +515,11 @@ void LiveEditor::_node_set_func(int p_id, const StringName &p_prop, const Varian
return;
NodePath np = live_edit_node_path_cache[p_id];
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -553,11 +553,11 @@ void LiveEditor::_node_call_func(int p_id, const StringName &p_method, VARIANT_A
return;
NodePath np = live_edit_node_path_cache[p_id];
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -626,11 +626,11 @@ void LiveEditor::_create_node_func(const NodePath &p_parent, const String &p_typ
if (!scene_tree)
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -664,11 +664,11 @@ void LiveEditor::_instance_node_func(const NodePath &p_parent, const String &p_p
if (!ps.is_valid())
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -697,11 +697,11 @@ void LiveEditor::_remove_node_func(const NodePath &p_at) {
if (!scene_tree)
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -728,11 +728,11 @@ void LiveEditor::_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_kee
if (!scene_tree)
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -762,11 +762,11 @@ void LiveEditor::_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_a
if (!scene_tree)
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -783,7 +783,7 @@ void LiveEditor::_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_a
continue;
Node *n2 = n->get_node(p_at);
- Map<Node *, Map<ObjectID, Node *> >::Element *EN = live_edit_remove_list.find(n);
+ Map<Node *, Map<ObjectID, Node *>>::Element *EN = live_edit_remove_list.find(n);
if (!EN)
continue;
@@ -808,11 +808,11 @@ void LiveEditor::_duplicate_node_func(const NodePath &p_at, const String &p_new_
if (!scene_tree)
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
@@ -841,11 +841,11 @@ void LiveEditor::_reparent_node_func(const NodePath &p_at, const NodePath &p_new
if (!scene_tree)
return;
- Node *base = NULL;
+ Node *base = nullptr;
if (scene_tree->root->has_node(live_edit_root))
base = scene_tree->root->get_node(live_edit_root);
- Map<String, Set<Node *> >::Element *E = live_scene_edit_cache.find(live_edit_scene);
+ Map<String, Set<Node *>>::Element *E = live_scene_edit_cache.find(live_edit_scene);
if (!E)
return; //scene not editable
diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h
index afe58a5d01..e295510960 100644
--- a/scene/debugger/scene_debugger.h
+++ b/scene/debugger/scene_debugger.h
@@ -113,8 +113,8 @@ private:
NodePath live_edit_root;
String live_edit_scene;
- Map<String, Set<Node *> > live_scene_edit_cache;
- Map<Node *, Map<ObjectID, Node *> > live_edit_remove_list;
+ Map<String, Set<Node *>> live_scene_edit_cache;
+ Map<Node *, Map<ObjectID, Node *>> live_edit_remove_list;
void _send_tree();
diff --git a/scene/gui/SCsub b/scene/gui/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/gui/SCsub
+++ b/scene/gui/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index b2020d44e8..1cdc6f8057 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -31,7 +31,7 @@
#include "base_button.h"
#include "core/os/keyboard.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/scene_string_names.h"
void BaseButton::_unpress_group() {
@@ -357,9 +357,6 @@ void BaseButton::_unhandled_input(Ref<InputEvent> p_event) {
if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) {
- if (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this))
- return; //ignore because of modal window
-
on_action_event(p_event);
}
}
@@ -501,7 +498,7 @@ BaseButton *ButtonGroup::get_pressed_button() {
return E->get();
}
- return NULL;
+ return nullptr;
}
void ButtonGroup::_bind_methods() {
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index e0bfeac9f7..0da6e0fdfa 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -45,7 +45,7 @@ void BoxContainer::_resort() {
Size2i new_size = get_size();
- int sep = get_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer");
+ int sep = get_theme_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer");
bool first = true;
int children_count = 0;
@@ -206,7 +206,7 @@ Size2 BoxContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
- int sep = get_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer");
+ int sep = get_theme_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer");
bool first = true;
@@ -310,7 +310,7 @@ MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control
l->set_text(p_label);
add_child(l);
MarginContainer *mc = memnew(MarginContainer);
- mc->add_constant_override("margin_left", 0);
+ mc->add_theme_constant_override("margin_left", 0);
mc->add_child(p_control);
add_child(mc);
if (p_expand)
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 784d298bff..1f8487c173 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -31,18 +31,18 @@
#include "button.h"
#include "core/translation.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
Size2 Button::get_minimum_size() const {
- Size2 minsize = get_font("font")->get_string_size(xl_text);
+ Size2 minsize = get_theme_font("font")->get_string_size(xl_text);
if (clip_text)
minsize.width = 0;
if (!expand_icon) {
Ref<Texture2D> _icon;
- if (icon.is_null() && has_icon("icon"))
- _icon = Control::get_icon("icon");
+ if (icon.is_null() && has_theme_icon("icon"))
+ _icon = Control::get_theme_icon("icon");
else
_icon = icon;
@@ -51,11 +51,11 @@ Size2 Button::get_minimum_size() const {
minsize.height = MAX(minsize.height, _icon->get_height());
minsize.width += _icon->get_width();
if (xl_text != "")
- minsize.width += get_constant("hseparation");
+ minsize.width += get_theme_constant("hseparation");
}
}
- return get_stylebox("normal")->get_minimum_size() + minsize;
+ return get_theme_stylebox("normal")->get_minimum_size() + minsize;
}
void Button::_set_internal_margin(Margin p_margin, float p_value) {
@@ -79,30 +79,30 @@ void Button::_notification(int p_what) {
Color color;
Color color_icon(1, 1, 1, 1);
- Ref<StyleBox> style = get_stylebox("normal");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
switch (get_draw_mode()) {
case DRAW_NORMAL: {
- style = get_stylebox("normal");
+ style = get_theme_stylebox("normal");
if (!flat)
style->draw(ci, Rect2(Point2(0, 0), size));
- color = get_color("font_color");
- if (has_color("icon_color_normal"))
- color_icon = get_color("icon_color_normal");
+ color = get_theme_color("font_color");
+ if (has_theme_color("icon_color_normal"))
+ color_icon = get_theme_color("icon_color_normal");
} break;
case DRAW_HOVER_PRESSED: {
- if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) {
- style = get_stylebox("hover_pressed");
+ if (has_theme_stylebox("hover_pressed") && has_theme_stylebox_override("hover_pressed")) {
+ style = get_theme_stylebox("hover_pressed");
if (!flat)
style->draw(ci, Rect2(Point2(0, 0), size));
- if (has_color("font_color_hover_pressed"))
- color = get_color("font_color_hover_pressed");
+ if (has_theme_color("font_color_hover_pressed"))
+ color = get_theme_color("font_color_hover_pressed");
else
- color = get_color("font_color");
- if (has_color("icon_color_hover_pressed"))
- color_icon = get_color("icon_color_hover_pressed");
+ color = get_theme_color("font_color");
+ if (has_theme_color("icon_color_hover_pressed"))
+ color_icon = get_theme_color("icon_color_hover_pressed");
break;
}
@@ -110,49 +110,49 @@ void Button::_notification(int p_what) {
}
case DRAW_PRESSED: {
- style = get_stylebox("pressed");
+ style = get_theme_stylebox("pressed");
if (!flat)
style->draw(ci, Rect2(Point2(0, 0), size));
- if (has_color("font_color_pressed"))
- color = get_color("font_color_pressed");
+ if (has_theme_color("font_color_pressed"))
+ color = get_theme_color("font_color_pressed");
else
- color = get_color("font_color");
- if (has_color("icon_color_pressed"))
- color_icon = get_color("icon_color_pressed");
+ color = get_theme_color("font_color");
+ if (has_theme_color("icon_color_pressed"))
+ color_icon = get_theme_color("icon_color_pressed");
} break;
case DRAW_HOVER: {
- style = get_stylebox("hover");
+ style = get_theme_stylebox("hover");
if (!flat)
style->draw(ci, Rect2(Point2(0, 0), size));
- color = get_color("font_color_hover");
- if (has_color("icon_color_hover"))
- color_icon = get_color("icon_color_hover");
+ color = get_theme_color("font_color_hover");
+ if (has_theme_color("icon_color_hover"))
+ color_icon = get_theme_color("icon_color_hover");
} break;
case DRAW_DISABLED: {
- style = get_stylebox("disabled");
+ style = get_theme_stylebox("disabled");
if (!flat)
style->draw(ci, Rect2(Point2(0, 0), size));
- color = get_color("font_color_disabled");
- if (has_color("icon_color_disabled"))
- color_icon = get_color("icon_color_disabled");
+ color = get_theme_color("font_color_disabled");
+ if (has_theme_color("icon_color_disabled"))
+ color_icon = get_theme_color("icon_color_disabled");
} break;
}
if (has_focus()) {
- Ref<StyleBox> style2 = get_stylebox("focus");
+ Ref<StyleBox> style2 = get_theme_stylebox("focus");
style2->draw(ci, Rect2(Point2(), size));
}
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
Ref<Texture2D> _icon;
- if (icon.is_null() && has_icon("icon"))
- _icon = Control::get_icon("icon");
+ if (icon.is_null() && has_theme_icon("icon"))
+ _icon = Control::get_theme_icon("icon");
else
_icon = icon;
@@ -166,14 +166,14 @@ void Button::_notification(int p_what) {
float icon_ofs_region = 0;
if (_internal_margin[MARGIN_LEFT] > 0) {
- icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
+ icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation");
}
if (expand_icon) {
Size2 _size = get_size() - style->get_offset() * 2;
- _size.width -= get_constant("hseparation") + icon_ofs_region;
+ _size.width -= get_theme_constant("hseparation") + icon_ofs_region;
if (!clip_text)
- _size.width -= get_font("font")->get_string_size(xl_text).width;
+ _size.width -= get_theme_font("font")->get_string_size(xl_text).width;
float icon_width = _icon->get_width() * _size.height / _icon->get_height();
float icon_height = _size.height;
@@ -188,13 +188,13 @@ void Button::_notification(int p_what) {
}
}
- Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_constant("hseparation"), 0) : Point2();
+ Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_theme_constant("hseparation"), 0) : Point2();
int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
if (_internal_margin[MARGIN_LEFT] > 0) {
- text_clip -= _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
+ text_clip -= _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation");
}
if (_internal_margin[MARGIN_RIGHT] > 0) {
- text_clip -= _internal_margin[MARGIN_RIGHT] + get_constant("hseparation");
+ text_clip -= _internal_margin[MARGIN_RIGHT] + get_theme_constant("hseparation");
}
Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0;
@@ -202,7 +202,7 @@ void Button::_notification(int p_what) {
switch (align) {
case ALIGN_LEFT: {
if (_internal_margin[MARGIN_LEFT] > 0) {
- text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
+ text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation");
} else {
text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x;
}
@@ -216,7 +216,7 @@ void Button::_notification(int p_what) {
} break;
case ALIGN_RIGHT: {
if (_internal_margin[MARGIN_RIGHT] > 0) {
- text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation");
+ text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_theme_constant("hseparation");
} else {
text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x;
}
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index 89bd8ab0dd..470450e3ed 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -30,13 +30,13 @@
#include "check_box.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
Size2 CheckBox::get_icon_size() const {
- Ref<Texture2D> checked = Control::get_icon("checked");
- Ref<Texture2D> unchecked = Control::get_icon("unchecked");
- Ref<Texture2D> radio_checked = Control::get_icon("radio_checked");
- Ref<Texture2D> radio_unchecked = Control::get_icon("radio_unchecked");
+ Ref<Texture2D> checked = Control::get_theme_icon("checked");
+ Ref<Texture2D> unchecked = Control::get_theme_icon("unchecked");
+ Ref<Texture2D> radio_checked = Control::get_theme_icon("radio_checked");
+ Ref<Texture2D> radio_unchecked = Control::get_theme_icon("radio_unchecked");
Size2 tex_size = Size2(0, 0);
if (!checked.is_null())
@@ -56,9 +56,9 @@ Size2 CheckBox::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
- minsize.width += get_constant("hseparation");
+ minsize.width += get_theme_constant("hseparation");
}
- Ref<StyleBox> sb = get_stylebox("normal");
+ Ref<StyleBox> sb = get_theme_stylebox("normal");
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM));
return minsize;
@@ -73,13 +73,13 @@ void CheckBox::_notification(int p_what) {
RID ci = get_canvas_item();
- Ref<Texture2D> on = Control::get_icon(is_radio() ? "radio_checked" : "checked");
- Ref<Texture2D> off = Control::get_icon(is_radio() ? "radio_unchecked" : "unchecked");
- Ref<StyleBox> sb = get_stylebox("normal");
+ 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<StyleBox> sb = get_theme_stylebox("normal");
Vector2 ofs;
ofs.x = sb->get_margin(MARGIN_LEFT);
- ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_constant("check_vadjust");
+ ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant("check_vadjust");
if (is_pressed())
on->draw(ci, ofs);
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index 0b093ce850..96484424f8 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -31,12 +31,12 @@
#include "check_button.h"
#include "core/print_string.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
Size2 CheckButton::get_icon_size() const {
- Ref<Texture2D> on = Control::get_icon(is_disabled() ? "on_disabled" : "on");
- Ref<Texture2D> off = Control::get_icon(is_disabled() ? "off_disabled" : "off");
+ Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on");
+ Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off");
Size2 tex_size = Size2(0, 0);
if (!on.is_null())
tex_size = Size2(on->get_width(), on->get_height());
@@ -52,8 +52,8 @@ Size2 CheckButton::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0)
- minsize.width += get_constant("hseparation");
- Ref<StyleBox> sb = get_stylebox("normal");
+ minsize.width += get_theme_constant("hseparation");
+ Ref<StyleBox> sb = get_theme_stylebox("normal");
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM));
return minsize;
@@ -68,15 +68,15 @@ void CheckButton::_notification(int p_what) {
RID ci = get_canvas_item();
- Ref<Texture2D> on = Control::get_icon(is_disabled() ? "on_disabled" : "on");
- Ref<Texture2D> off = Control::get_icon(is_disabled() ? "off_disabled" : "off");
+ Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on");
+ Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off");
- Ref<StyleBox> sb = get_stylebox("normal");
+ Ref<StyleBox> sb = get_theme_stylebox("normal");
Vector2 ofs;
Size2 tex_size = get_icon_size();
ofs.x = get_size().width - (tex_size.width + sb->get_margin(MARGIN_RIGHT));
- ofs.y = (get_size().height - tex_size.height) / 2 + get_constant("check_vadjust");
+ ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant("check_vadjust");
if (is_pressed())
on->draw(ci, ofs);
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index cbbad79811..5e0f4c91e8 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -30,7 +30,7 @@
#include "color_picker.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -38,22 +38,22 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#endif
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
- bt_add_preset->set_icon(get_icon("add_preset"));
+ btn_pick->set_icon(get_theme_icon("screen_picker", "ColorPicker"));
+ bt_add_preset->set_icon(get_theme_icon("add_preset"));
_update_controls();
} break;
case NOTIFICATION_ENTER_TREE: {
- btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
- bt_add_preset->set_icon(get_icon("add_preset"));
+ btn_pick->set_icon(get_theme_icon("screen_picker", "ColorPicker"));
+ bt_add_preset->set_icon(get_theme_icon("add_preset"));
_update_color();
@@ -70,17 +70,17 @@ void ColorPicker::_notification(int p_what) {
case NOTIFICATION_PARENTED: {
for (int i = 0; i < 4; i++)
- set_margin((Margin)i, get_constant("margin"));
+ set_margin((Margin)i, get_theme_constant("margin"));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
Popup *p = Object::cast_to<Popup>(get_parent());
if (p)
- p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2));
+ p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant("margin") * 2, get_combined_minimum_size().height + get_theme_constant("margin") * 2));
} break;
- case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
- if (screen != NULL && screen->is_visible())
+ if (screen != nullptr && screen->is_visible())
screen->hide();
} break;
}
@@ -247,6 +247,9 @@ void ColorPicker::_update_color(bool p_update_sliders) {
}
void ColorPicker::_update_presets() {
+ return;
+ //presets should be shown using buttons or something else, this method is not a good idea
+
presets_per_row = 10;
Size2 size = bt_add_preset->get_size();
Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row)));
@@ -267,12 +270,12 @@ void ColorPicker::_text_type_toggled() {
text_is_constructor = !text_is_constructor;
if (text_is_constructor) {
text_type->set_text("");
- text_type->set_icon(get_icon("Script", "EditorIcons"));
+ text_type->set_icon(get_theme_icon("Script", "EditorIcons"));
c_text->set_editable(false);
} else {
text_type->set_text("#");
- text_type->set_icon(NULL);
+ text_type->set_icon(nullptr);
c_text->set_editable(true);
}
@@ -399,14 +402,14 @@ void ColorPicker::_sample_draw() {
const Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95));
if (color.a < 1.0) {
- sample->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), r, true);
+ sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), r, true);
}
sample->draw_rect(r, color);
if (color.r > 1 || color.g > 1 || color.b > 1) {
// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
- sample->draw_texture(get_icon("overbright_indicator", "ColorPicker"), Point2());
+ sample->draw_texture(get_theme_icon("overbright_indicator", "ColorPicker"), Point2());
}
}
@@ -445,7 +448,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
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);
} else if (p_which == 1) {
- Ref<Texture2D> hue = get_icon("color_hue", "ColorPicker");
+ 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();
@@ -620,30 +623,40 @@ void ColorPicker::_screen_pick_pressed() {
screen->call_deferred("connect", "hide", Callable(btn_pick, "set_pressed"), varray(false));
}
screen->raise();
- screen->show_modal();
+#ifndef _MSC_VER
+#warning show modal no longer works, needs to be converted to a popup
+#endif
+ //screen->show_modal();
}
void ColorPicker::_focus_enter() {
- if (c_text->has_focus()) {
+ bool has_ctext_focus = c_text->has_focus();
+ if (has_ctext_focus) {
c_text->select_all();
- return;
+ } else {
+ c_text->select(0, 0);
}
+
for (int i = 0; i < 4; i++) {
- if (values[i]->get_line_edit()->has_focus()) {
+ if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) {
values[i]->get_line_edit()->select_all();
- break;
+ } else {
+ values[i]->get_line_edit()->select(0, 0);
}
}
}
void ColorPicker::_focus_exit() {
for (int i = 0; i < 4; i++) {
- values[i]->get_line_edit()->select(0, 0);
+ if (!values[i]->get_line_edit()->get_menu()->is_visible())
+ values[i]->get_line_edit()->select(0, 0);
}
c_text->select(0, 0);
}
void ColorPicker::_html_focus_exit() {
+ if (c_text->get_menu()->is_visible())
+ return;
_html_entered(c_text->get_text());
_focus_exit();
}
@@ -719,7 +732,7 @@ ColorPicker::ColorPicker() :
changing_color = false;
presets_enabled = true;
presets_visible = true;
- screen = NULL;
+ screen = nullptr;
HBoxContainer *hb_edit = memnew(HBoxContainer);
add_child(hb_edit);
@@ -731,12 +744,12 @@ ColorPicker::ColorPicker() :
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_constant("sv_width"), get_constant("sv_height")));
+ 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_constant("h_width"), 0));
+ 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));
@@ -770,7 +783,7 @@ ColorPicker::ColorPicker() :
HBoxContainer *hbc = memnew(HBoxContainer);
labels[i] = memnew(Label());
- labels[i]->set_custom_minimum_size(Size2(get_constant("label_width"), 0));
+ labels[i]->set_custom_minimum_size(Size2(get_theme_constant("label_width"), 0));
labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER);
hbc->add_child(labels[i]);
@@ -874,8 +887,32 @@ void ColorPickerButton::_modal_closed() {
void ColorPickerButton::pressed() {
_update_picker();
- popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale());
- popup->set_scale(get_global_transform().get_scale());
+
+ popup->set_as_minsize();
+
+ Rect2i usable_rect = popup->get_usable_parent_rect();
+ //let's try different positions to see which one we can use
+
+ Rect2i cp_rect(Point2i(), popup->get_size());
+ for (int i = 0; i < 4; i++) {
+ if (i > 1) {
+ cp_rect.position.y = get_screen_position().y - cp_rect.size.y;
+ } else {
+ cp_rect.position.y = get_screen_position().y + get_size().height;
+ }
+
+ if (i & 1) {
+ cp_rect.position.x = get_screen_position().x;
+ } else {
+
+ cp_rect.position.x = get_screen_position().x - MAX(0, (cp_rect.size.x - get_size().x));
+ }
+
+ if (usable_rect.encloses(cp_rect)) {
+ break;
+ }
+ }
+ popup->set_position(cp_rect.position);
popup->popup();
picker->set_focus_on_line_edit();
}
@@ -885,17 +922,17 @@ void ColorPickerButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- const Ref<StyleBox> normal = get_stylebox("normal");
+ const Ref<StyleBox> normal = get_theme_stylebox("normal");
const Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
- draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
+ draw_texture_rect(Control::get_theme_icon("bg", "ColorPickerButton"), r, true);
draw_rect(r, color);
if (color.r > 1 || color.g > 1 || color.b > 1) {
// Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
- draw_texture(Control::get_icon("overbright_indicator", "ColorPicker"), normal->get_offset());
+ draw_texture(Control::get_theme_icon("overbright_indicator", "ColorPicker"), normal->get_offset());
}
} break;
- case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
if (popup)
popup->hide();
@@ -951,12 +988,14 @@ PopupPanel *ColorPickerButton::get_popup() {
void ColorPickerButton::_update_picker() {
if (!picker) {
popup = memnew(PopupPanel);
+ popup->set_wrap_controls(true);
picker = memnew(ColorPicker);
+ picker->set_anchors_and_margins_preset(PRESET_WIDE);
popup->add_child(picker);
add_child(popup);
picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed));
popup->connect("modal_closed", callable_mp(this, &ColorPickerButton::_modal_closed));
- popup->connect("about_to_show", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true));
+ popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true));
popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false));
picker->set_pick_color(color);
picker->set_edit_alpha(edit_alpha);
@@ -985,8 +1024,8 @@ ColorPickerButton::ColorPickerButton() {
// Initialization is now done deferred,
// this improves performance in the inspector as the color picker
// can be expensive to initialize.
- picker = NULL;
- popup = NULL;
+ picker = nullptr;
+ popup = nullptr;
edit_alpha = true;
set_toggle_mode(true);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 1a231e368b..b4dc37c74f 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -38,9 +38,9 @@
#include "scene/gui/label.h"
#include "scene/gui/panel.h"
#include "scene/main/canvas_layer.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/scene_string_names.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
@@ -260,22 +260,22 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
} else {
if (name.begins_with("custom_icons/")) {
String dname = name.get_slicec('/', 1);
- add_icon_override(dname, p_value);
+ add_theme_icon_override(dname, p_value);
} else if (name.begins_with("custom_shaders/")) {
String dname = name.get_slicec('/', 1);
- add_shader_override(dname, p_value);
+ add_theme_shader_override(dname, p_value);
} else if (name.begins_with("custom_styles/")) {
String dname = name.get_slicec('/', 1);
- add_style_override(dname, p_value);
+ add_theme_style_override(dname, p_value);
} else if (name.begins_with("custom_fonts/")) {
String dname = name.get_slicec('/', 1);
- add_font_override(dname, p_value);
+ add_theme_font_override(dname, p_value);
} else if (name.begins_with("custom_colors/")) {
String dname = name.get_slicec('/', 1);
- add_color_override(dname, p_value);
+ add_theme_color_override(dname, p_value);
} else if (name.begins_with("custom_constants/")) {
String dname = name.get_slicec('/', 1);
- add_constant_override(dname, p_value);
+ add_theme_constant_override(dname, p_value);
} else
return false;
}
@@ -438,22 +438,30 @@ void Control::_resize(const Size2 &p_size) {
void Control::add_child_notify(Node *p_child) {
Control *child_c = Object::cast_to<Control>(p_child);
- if (!child_c)
- return;
- if (child_c->data.theme.is_null() && data.theme_owner) {
- _propagate_theme_changed(child_c, data.theme_owner); //need to propagate here, since many controls may require setting up stuff
+ if (child_c && child_c->data.theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
+ _propagate_theme_changed(child_c, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ }
+
+ Window *child_w = Object::cast_to<Window>(p_child);
+
+ if (child_w && child_w->theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
+ _propagate_theme_changed(child_w, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
}
}
void Control::remove_child_notify(Node *p_child) {
Control *child_c = Object::cast_to<Control>(p_child);
- if (!child_c)
- return;
- if (child_c->data.theme_owner && child_c->data.theme.is_null()) {
- _propagate_theme_changed(child_c, NULL);
+ if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
+ _propagate_theme_changed(child_c, nullptr, nullptr);
+ }
+
+ Window *child_w = Object::cast_to<Window>(p_child);
+
+ if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
+ _propagate_theme_changed(child_w, nullptr, nullptr);
}
}
@@ -462,7 +470,7 @@ void Control::_update_canvas_item_transform() {
Transform2D xform = _get_internal_transform();
xform[2] += get_position();
- VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), xform);
+ RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), xform);
}
void Control::_notification(int p_notification) {
@@ -486,111 +494,73 @@ void Control::_notification(int p_notification) {
data.parent = Object::cast_to<Control>(get_parent());
- if (is_set_as_toplevel()) {
- data.SI = get_viewport()->_gui_add_subwindow_control(this);
-
- if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) {
- data.theme_owner = data.parent->data.theme_owner;
- notification(NOTIFICATION_THEME_CHANGED);
- }
-
- } else {
-
- Node *parent = this; //meh
- Control *parent_control = NULL;
- bool subwindow = false;
+ Node *parent = this; //meh
+ Control *parent_control = nullptr;
+ bool subwindow = false;
- while (parent) {
-
- parent = parent->get_parent();
-
- if (!parent)
- break;
-
- CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
- if (ci && ci->is_set_as_toplevel()) {
- subwindow = true;
- break;
- }
+ while (parent) {
- parent_control = Object::cast_to<Control>(parent);
+ parent = parent->get_parent();
- if (parent_control) {
- break;
- } else if (ci) {
+ if (!parent)
+ break;
- } else {
- break;
- }
+ CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
+ if (ci && ci->is_set_as_toplevel()) {
+ subwindow = true;
+ break;
}
- if (parent_control) {
- //do nothing, has a parent control
- if (data.theme.is_null() && parent_control->data.theme_owner) {
- data.theme_owner = parent_control->data.theme_owner;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- } else if (subwindow) {
- //is a subwindow (process input before other controls for that canvas)
- data.SI = get_viewport()->_gui_add_subwindow_control(this);
- } else {
- //is a regular root control
- data.RI = get_viewport()->_gui_add_root_control(this);
- }
+ parent_control = Object::cast_to<Control>(parent);
- data.parent_canvas_item = get_parent_item();
-
- if (data.parent_canvas_item) {
+ if (parent_control) {
+ break;
+ } else if (ci) {
- data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed));
} else {
- //connect viewport
- get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed));
+ break;
}
}
- /*
- if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) {
- data.theme_owner=data.parent->data.theme_owner;
- notification(NOTIFICATION_THEME_CHANGED);
+ if (parent_control && !subwindow) {
+ //do nothing, has a parent control and not toplevel
+ if (data.theme.is_null() && parent_control->data.theme_owner) {
+ data.theme_owner = parent_control->data.theme_owner;
+ notification(NOTIFICATION_THEME_CHANGED);
+ }
+ } else {
+ //is a regular root control or toplevel
+ data.RI = get_viewport()->_gui_add_root_control(this);
}
- */
+ data.parent_canvas_item = get_parent_item();
+
+ if (data.parent_canvas_item) {
+
+ data.parent_canvas_item->connect("item_rect_changed", callable_mp(this, &Control::_size_changed));
+ } else {
+ //connect viewport
+ get_viewport()->connect("size_changed", callable_mp(this, &Control::_size_changed));
+ }
} break;
case NOTIFICATION_EXIT_CANVAS: {
if (data.parent_canvas_item) {
data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed));
- data.parent_canvas_item = NULL;
+ data.parent_canvas_item = nullptr;
} else if (!is_set_as_toplevel()) {
//disconnect viewport
get_viewport()->disconnect("size_changed", callable_mp(this, &Control::_size_changed));
}
- if (data.MI) {
- get_viewport()->_gui_remove_modal_control(data.MI);
- data.MI = NULL;
- }
-
- if (data.SI) {
- get_viewport()->_gui_remove_subwindow_control(data.SI);
- data.SI = NULL;
- }
-
if (data.RI) {
get_viewport()->_gui_remove_root_control(data.RI);
- data.RI = NULL;
+ data.RI = nullptr;
}
- data.parent = NULL;
- data.parent_canvas_item = NULL;
- /*
- if (data.theme_owner && data.theme.is_null()) {
- data.theme_owner=NULL;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- */
+ data.parent = nullptr;
+ data.parent_canvas_item = nullptr;
} break;
case NOTIFICATION_MOVED_IN_PARENT: {
@@ -600,9 +570,6 @@ void Control::_notification(int p_notification) {
data.parent->update();
update();
- if (data.SI) {
- get_viewport()->_gui_set_subwindow_order_dirty();
- }
if (data.RI) {
get_viewport()->_gui_set_root_order_dirty();
}
@@ -615,8 +582,8 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_DRAW: {
_update_canvas_item_transform();
- VisualServer::get_singleton()->canvas_item_set_custom_rect(get_canvas_item(), !data.disable_visibility_clip, Rect2(Point2(), get_size()));
- VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), data.clip_contents);
+ RenderingServer::get_singleton()->canvas_item_set_custom_rect(get_canvas_item(), !data.disable_visibility_clip, Rect2(Point2(), get_size()));
+ RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), data.clip_contents);
//emit_signal(SceneStringNames::get_singleton()->draw);
} break;
@@ -644,34 +611,21 @@ void Control::_notification(int p_notification) {
minimum_size_changed();
update();
} break;
- case NOTIFICATION_MODAL_CLOSE: {
-
- emit_signal("modal_closed");
- } break;
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible_in_tree()) {
- if (get_viewport() != NULL)
+ if (get_viewport() != nullptr)
get_viewport()->_gui_hid_control(this);
- if (is_inside_tree()) {
- _modal_stack_remove();
- }
-
//remove key focus
- //remove modalness
+
} else {
data.minimum_size_valid = false;
_size_changed();
}
} break;
- case SceneTree::NOTIFICATION_WM_UNFOCUS_REQUEST: {
-
- get_viewport()->_gui_unfocus_control(this);
-
- } break;
}
}
@@ -787,76 +741,143 @@ void Control::set_drag_preview(Control *p_control) {
get_viewport()->_gui_set_drag_preview(this, p_control);
}
-bool Control::is_window_modal_on_top() const {
-
- if (!is_inside_tree())
- return false;
-
- return get_viewport()->_gui_is_modal_on_top(this);
-}
-
-uint64_t Control::get_modal_frame() const {
-
- return data.modal_frame;
-}
-
Size2 Control::get_minimum_size() const {
ScriptInstance *si = const_cast<Control *>(this)->get_script_instance();
if (si) {
Callable::CallError ce;
- Variant s = si->call(SceneStringNames::get_singleton()->_get_minimum_size, NULL, 0, ce);
+ Variant s = si->call(SceneStringNames::get_singleton()->_get_minimum_size, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK)
return s;
}
return Size2();
}
-Ref<Texture2D> Control::get_icon(const StringName &p_name, const StringName &p_type) const {
+template <class T>
+bool Control::_find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &r_ret, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type) {
- if (p_type == StringName() || p_type == get_class_name()) {
+ // try with custom themes
+ Control *theme_owner = p_theme_owner;
+ Window *theme_owner_window = p_theme_owner_window;
- const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
- if (tex)
- return *tex;
+ while (theme_owner || theme_owner_window) {
+
+ StringName class_name = p_type;
+
+ while (class_name != StringName()) {
+ if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) {
+ r_ret = (theme_owner->data.theme.operator->()->*get_func)(p_name, class_name);
+ return true;
+ }
+
+ if (theme_owner_window && (theme_owner_window->theme.operator->()->*has_func)(p_name, class_name)) {
+ r_ret = (theme_owner_window->theme.operator->()->*get_func)(p_name, class_name);
+ return true;
+ }
+
+ class_name = ClassDB::get_parent_class_nocheck(class_name);
+ }
+
+ Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
+
+ if (parent_c) {
+ theme_owner = parent_c->data.theme_owner;
+ theme_owner_window = parent_c->data.theme_owner_window;
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ theme_owner = parent_w->theme_owner;
+ theme_owner_window = parent_w->theme_owner_window;
+ } else {
+
+ theme_owner = nullptr;
+ theme_owner_window = nullptr;
+ }
+ }
}
+ return false;
+}
- StringName type = p_type ? p_type : get_class_name();
+bool Control::_has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type) {
// try with custom themes
- Control *theme_owner = data.theme_owner;
+ Control *theme_owner = p_theme_owner;
+ Window *theme_owner_window = p_theme_owner_window;
- while (theme_owner) {
+ while (theme_owner || theme_owner_window) {
- StringName class_name = type;
+ StringName class_name = p_type;
while (class_name != StringName()) {
- if (theme_owner->data.theme->has_icon(p_name, class_name)) {
- return theme_owner->data.theme->get_icon(p_name, class_name);
+ if (theme_owner && (theme_owner->data.theme.operator->()->*has_func)(p_name, class_name)) {
+ return true;
+ }
+
+ if (theme_owner_window && (theme_owner_window->theme.operator->()->*has_func)(p_name, class_name)) {
+ return true;
}
class_name = ClassDB::get_parent_class_nocheck(class_name);
}
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+
+ Control *parent_c = Object::cast_to<Control>(parent);
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (parent_c) {
+ theme_owner = parent_c->data.theme_owner;
+ theme_owner_window = parent_c->data.theme_owner_window;
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ theme_owner = parent_w->theme_owner;
+ theme_owner_window = parent_w->theme_owner_window;
+ } else {
+
+ theme_owner = nullptr;
+ theme_owner_window = nullptr;
+ }
+ }
+ }
+ return false;
+}
+
+Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_type) const {
+
+ if (p_type == StringName() || p_type == get_class_name()) {
+
+ const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
+ if (tex)
+ return *tex;
+ }
+
+ StringName type = p_type ? p_type : get_class_name();
+
+ return get_icons(data.theme_owner, data.theme_owner_window, p_name, type);
+}
+
+Ref<Texture2D> Control::get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
+
+ Ref<Texture2D> icon;
+
+ if (_find_theme_item(p_theme_owner, p_theme_owner_window, icon, &Theme::get_icon, &Theme::has_icon, p_name, p_type)) {
+ return icon;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_icon(p_name, type)) {
- return Theme::get_project_default()->get_icon(p_name, type);
+ if (Theme::get_project_default()->has_icon(p_name, p_type)) {
+ return Theme::get_project_default()->get_icon(p_name, p_type);
}
}
- return Theme::get_default()->get_icon(p_name, type);
+ return Theme::get_default()->get_icon(p_name, p_type);
}
-Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_type) const {
+Ref<Shader> Control::get_theme_shader(const StringName &p_name, const StringName &p_type) const {
+
if (p_type == StringName() || p_type == get_class_name()) {
const Ref<Shader> *sdr = data.shader_override.getptr(p_name);
@@ -866,39 +887,27 @@ Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_ty
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_shader(p_name, class_name)) {
- return theme_owner->data.theme->get_shader(p_name, class_name);
- }
+ return get_shaders(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+Ref<Shader> Control::get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ Ref<Shader> shader;
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_find_theme_item(p_theme_owner, p_theme_owner_window, shader, &Theme::get_shader, &Theme::has_shader, p_name, p_type)) {
+ return shader;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_shader(p_name, type)) {
- return Theme::get_project_default()->get_shader(p_name, type);
+ if (Theme::get_project_default()->has_shader(p_name, p_type)) {
+ return Theme::get_project_default()->get_shader(p_name, p_type);
}
}
- return Theme::get_default()->get_shader(p_name, type);
+ return Theme::get_default()->get_shader(p_name, p_type);
}
-Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &p_type) const {
+Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
@@ -908,43 +917,27 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
+ return get_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- StringName class_name = type;
+Ref<StyleBox> Control::get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- while (theme_owner) {
+ Ref<StyleBox> stylebox;
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_stylebox(p_name, class_name)) {
- return theme_owner->data.theme->get_stylebox(p_name, class_name);
- }
+ if (_find_theme_item(p_theme_owner, p_theme_owner_window, stylebox, &Theme::get_stylebox, &Theme::has_stylebox, p_name, p_type)) {
+ return stylebox;
+ }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
+ if (Theme::get_project_default().is_valid()) {
+ if (Theme::get_project_default()->has_stylebox(p_name, p_type)) {
+ return Theme::get_project_default()->get_stylebox(p_name, p_type);
}
-
- class_name = type;
-
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
-
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
}
- while (class_name != StringName()) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->has_stylebox(p_name, type))
- return Theme::get_project_default()->get_stylebox(p_name, type);
-
- if (Theme::get_default()->has_stylebox(p_name, class_name))
- return Theme::get_default()->get_stylebox(p_name, class_name);
-
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
- return Theme::get_default()->get_stylebox(p_name, type);
+ return Theme::get_default()->get_stylebox(p_name, p_type);
}
-Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type) const {
+
+Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
const Ref<Font> *font = data.font_override.getptr(p_name);
@@ -954,34 +947,27 @@ Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type)
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
+ return get_fonts(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- while (theme_owner) {
+Ref<Font> Control::get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- StringName class_name = type;
+ Ref<Font> font;
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_font(p_name, class_name)) {
- return theme_owner->data.theme->get_font(p_name, class_name);
- }
+ if (_find_theme_item(p_theme_owner, p_theme_owner_window, font, &Theme::get_font, &Theme::has_font, p_name, p_type)) {
+ return font;
+ }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
+ if (Theme::get_project_default().is_valid()) {
+ if (Theme::get_project_default()->has_font(p_name, p_type)) {
+ return Theme::get_project_default()->get_font(p_name, p_type);
}
-
- if (theme_owner->data.theme->get_default_theme_font().is_valid())
- return theme_owner->data.theme->get_default_theme_font();
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
-
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
}
- return Theme::get_default()->get_font(p_name, type);
+ return Theme::get_default()->get_font(p_name, p_type);
}
-Color Control::get_color(const StringName &p_name, const StringName &p_type) const {
+
+Color Control::get_theme_color(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
const Color *color = data.color_override.getptr(p_name);
@@ -990,38 +976,27 @@ Color Control::get_color(const StringName &p_name, const StringName &p_type) con
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_color(p_name, class_name)) {
- return theme_owner->data.theme->get_color(p_name, class_name);
- }
+ return get_colors(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+Color Control::get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ Color color;
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_find_theme_item(p_theme_owner, p_theme_owner_window, color, &Theme::get_color, &Theme::has_color, p_name, p_type)) {
+ return color;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_color(p_name, type)) {
- return Theme::get_project_default()->get_color(p_name, type);
+ if (Theme::get_project_default()->has_color(p_name, p_type)) {
+ return Theme::get_project_default()->get_color(p_name, p_type);
}
}
- return Theme::get_default()->get_color(p_name, type);
+ return Theme::get_default()->get_color(p_name, p_type);
}
-int Control::get_constant(const StringName &p_name, const StringName &p_type) const {
+int Control::get_theme_constant(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
const int *constant = data.constant_override.getptr(p_name);
@@ -1030,303 +1005,213 @@ int Control::get_constant(const StringName &p_name, const StringName &p_type) co
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_constant(p_name, class_name)) {
- return theme_owner->data.theme->get_constant(p_name, class_name);
- }
+ return get_constants(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+int Control::get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ int constant;
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_find_theme_item(p_theme_owner, p_theme_owner_window, constant, &Theme::get_constant, &Theme::has_constant, p_name, p_type)) {
+ return constant;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_constant(p_name, type)) {
- return Theme::get_project_default()->get_constant(p_name, type);
+ if (Theme::get_project_default()->has_constant(p_name, p_type)) {
+ return Theme::get_project_default()->get_constant(p_name, p_type);
}
}
- return Theme::get_default()->get_constant(p_name, type);
+ return Theme::get_default()->get_constant(p_name, p_type);
}
-bool Control::has_icon_override(const StringName &p_name) const {
+bool Control::has_theme_icon_override(const StringName &p_name) const {
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
- return tex != NULL;
+ return tex != nullptr;
}
-bool Control::has_shader_override(const StringName &p_name) const {
+bool Control::has_theme_shader_override(const StringName &p_name) const {
const Ref<Shader> *sdr = data.shader_override.getptr(p_name);
- return sdr != NULL;
+ return sdr != nullptr;
}
-bool Control::has_stylebox_override(const StringName &p_name) const {
+bool Control::has_theme_stylebox_override(const StringName &p_name) const {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
- return style != NULL;
+ return style != nullptr;
}
-bool Control::has_font_override(const StringName &p_name) const {
+bool Control::has_theme_font_override(const StringName &p_name) const {
const Ref<Font> *font = data.font_override.getptr(p_name);
- return font != NULL;
+ return font != nullptr;
}
-bool Control::has_color_override(const StringName &p_name) const {
+bool Control::has_theme_color_override(const StringName &p_name) const {
const Color *color = data.color_override.getptr(p_name);
- return color != NULL;
+ return color != nullptr;
}
-bool Control::has_constant_override(const StringName &p_name) const {
+bool Control::has_theme_constant_override(const StringName &p_name) const {
const int *constant = data.constant_override.getptr(p_name);
- return constant != NULL;
+ return constant != nullptr;
}
-bool Control::has_icon(const StringName &p_name, const StringName &p_type) const {
+bool Control::has_theme_icon(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
- if (has_icon_override(p_name))
+ if (has_theme_icon_override(p_name))
return true;
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_icon(p_name, class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+ return has_icons(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+bool Control::has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_icon, p_name, p_type)) {
+ return true;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_color(p_name, type)) {
+ if (Theme::get_project_default()->has_color(p_name, p_type)) {
return true;
}
}
- return Theme::get_default()->has_icon(p_name, type);
+ return Theme::get_default()->has_icon(p_name, p_type);
}
-bool Control::has_shader(const StringName &p_name, const StringName &p_type) const {
+bool Control::has_theme_shader(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
- if (has_shader_override(p_name))
+ if (has_theme_shader_override(p_name))
return true;
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_shader(p_name, class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
-
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ return has_shaders(data.theme_owner, data.theme_owner_window, p_name, type);
+}
+bool Control::has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_shader, p_name, p_type)) {
+ return true;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_shader(p_name, type)) {
+ if (Theme::get_project_default()->has_shader(p_name, p_type)) {
return true;
}
}
- return Theme::get_default()->has_shader(p_name, type);
+ return Theme::get_default()->has_shader(p_name, p_type);
}
-bool Control::has_stylebox(const StringName &p_name, const StringName &p_type) const {
+
+bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
- if (has_stylebox_override(p_name))
+ if (has_theme_stylebox_override(p_name))
return true;
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_stylebox(p_name, class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+ return has_styleboxs(data.theme_owner, data.theme_owner_window, p_name, type);
+}
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+bool Control::has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_stylebox, p_name, p_type)) {
+ return true;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_stylebox(p_name, type)) {
+ if (Theme::get_project_default()->has_stylebox(p_name, p_type)) {
return true;
}
}
- return Theme::get_default()->has_stylebox(p_name, type);
+ return Theme::get_default()->has_stylebox(p_name, p_type);
}
-bool Control::has_font(const StringName &p_name, const StringName &p_type) const {
+
+bool Control::has_theme_font(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
- if (has_font_override(p_name))
+ if (has_theme_font_override(p_name))
return true;
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_font(p_name, class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
-
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ return has_fonts(data.theme_owner, data.theme_owner_window, p_name, type);
+}
+bool Control::has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_font, p_name, p_type)) {
+ return true;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_font(p_name, type)) {
+ if (Theme::get_project_default()->has_font(p_name, p_type)) {
return true;
}
}
- return Theme::get_default()->has_font(p_name, type);
+ return Theme::get_default()->has_font(p_name, p_type);
}
-bool Control::has_color(const StringName &p_name, const StringName &p_type) const {
+bool Control::has_theme_color(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
- if (has_color_override(p_name))
+ if (has_theme_color_override(p_name))
return true;
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_color(p_name, class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
-
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+ return has_colors(data.theme_owner, data.theme_owner_window, p_name, type);
+}
+bool Control::has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_color, p_name, p_type)) {
+ return true;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_color(p_name, type)) {
+ if (Theme::get_project_default()->has_color(p_name, p_type)) {
return true;
}
}
- return Theme::get_default()->has_color(p_name, type);
+ return Theme::get_default()->has_color(p_name, p_type);
}
-bool Control::has_constant(const StringName &p_name, const StringName &p_type) const {
+bool Control::has_theme_constant(const StringName &p_name, const StringName &p_type) const {
if (p_type == StringName() || p_type == get_class_name()) {
- if (has_constant_override(p_name))
+ if (has_theme_constant_override(p_name))
return true;
}
StringName type = p_type ? p_type : get_class_name();
- // try with custom themes
- Control *theme_owner = data.theme_owner;
-
- while (theme_owner) {
-
- StringName class_name = type;
-
- while (class_name != StringName()) {
- if (theme_owner->data.theme->has_constant(p_name, class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+ return has_constants(data.theme_owner, data.theme_owner_window, p_name, p_type);
+}
- Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
+bool Control::has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type) {
- if (parent)
- theme_owner = parent->data.theme_owner;
- else
- theme_owner = NULL;
+ if (_has_theme_item(p_theme_owner, p_theme_owner_window, &Theme::has_constant, p_name, p_type)) {
+ return true;
}
if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_constant(p_name, type)) {
+ if (Theme::get_project_default()->has_constant(p_name, p_type)) {
return true;
}
}
- return Theme::get_default()->has_constant(p_name, type);
+ return Theme::get_default()->has_constant(p_name, p_type);
}
Rect2 Control::get_parent_anchorable_rect() const {
@@ -1769,6 +1654,17 @@ Point2 Control::get_global_position() const {
return get_global_transform().get_origin();
}
+Point2 Control::get_screen_position() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Point2());
+ Point2 global_pos = get_global_position();
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w && !w->is_embedding_subwindows()) {
+ global_pos += w->get_position();
+ }
+
+ return global_pos;
+}
+
void Control::_set_global_position(const Point2 &p_point) {
set_global_position(p_point);
}
@@ -1863,6 +1759,20 @@ Rect2 Control::get_global_rect() const {
return Rect2(get_global_position(), get_size());
}
+Rect2 Control::get_screen_rect() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
+
+ Rect2 r(get_global_position(), get_size());
+
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w && !w->is_embedding_subwindows()) {
+ r.position += w->get_position();
+ }
+
+ return r;
+}
+
Rect2 Control::get_window_rect() const {
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
Rect2 gr = get_global_rect();
@@ -1880,7 +1790,7 @@ Rect2 Control::get_anchorable_rect() const {
return Rect2(Point2(), get_size());
}
-void Control::add_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) {
+void Control::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) {
if (data.icon_override.has(p_name)) {
data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
@@ -1898,7 +1808,7 @@ void Control::add_icon_override(const StringName &p_name, const Ref<Texture2D> &
notification(NOTIFICATION_THEME_CHANGED);
}
-void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) {
+void Control::add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) {
if (data.shader_override.has(p_name)) {
data.shader_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
@@ -1915,7 +1825,7 @@ void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p
}
notification(NOTIFICATION_THEME_CHANGED);
}
-void Control::add_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
+void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
if (data.style_override.has(p_name)) {
data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
@@ -1933,7 +1843,7 @@ void Control::add_style_override(const StringName &p_name, const Ref<StyleBox> &
notification(NOTIFICATION_THEME_CHANGED);
}
-void Control::add_font_override(const StringName &p_name, const Ref<Font> &p_font) {
+void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
if (data.font_override.has(p_name)) {
data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
@@ -1950,12 +1860,12 @@ void Control::add_font_override(const StringName &p_name, const Ref<Font> &p_fon
}
notification(NOTIFICATION_THEME_CHANGED);
}
-void Control::add_color_override(const StringName &p_name, const Color &p_color) {
+void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) {
data.color_override[p_name] = p_color;
notification(NOTIFICATION_THEME_CHANGED);
}
-void Control::add_constant_override(const StringName &p_name, int p_constant) {
+void Control::add_theme_constant_override(const StringName &p_name, int p_constant) {
data.constant_override[p_name] = p_constant;
notification(NOTIFICATION_THEME_CHANGED);
@@ -1974,17 +1884,17 @@ void Control::set_focus_mode(FocusMode p_focus_mode) {
static Control *_next_control(Control *p_from) {
if (p_from->is_set_as_toplevel())
- return NULL; // can't go above
+ return nullptr; // can't go above
Control *parent = Object::cast_to<Control>(p_from->get_parent());
if (!parent) {
- return NULL;
+ return nullptr;
}
- int next = p_from->get_position_in_parent();
- ERR_FAIL_INDEX_V(next, parent->get_child_count(), NULL);
+ int next = p_from->get_index();
+ ERR_FAIL_INDEX_V(next, parent->get_child_count(), nullptr);
for (int i = (next + 1); i < parent->get_child_count(); i++) {
Control *c = Object::cast_to<Control>(parent->get_child(i));
@@ -2011,9 +1921,9 @@ Control *Control::find_next_valid_focus() const {
Control *c;
if (n) {
c = Object::cast_to<Control>(n);
- ERR_FAIL_COND_V_MSG(!c, NULL, "Next focus node is not a control: " + n->get_name() + ".");
+ ERR_FAIL_COND_V_MSG(!c, nullptr, "Next focus node is not a control: " + n->get_name() + ".");
} else {
- return NULL;
+ return nullptr;
}
if (c->is_visible() && c->get_focus_mode() != FOCUS_NONE)
return c;
@@ -2021,7 +1931,7 @@ Control *Control::find_next_valid_focus() const {
// find next child
- Control *next_child = NULL;
+ Control *next_child = nullptr;
for (int i = 0; i < from->get_child_count(); i++) {
@@ -2049,7 +1959,7 @@ Control *Control::find_next_valid_focus() const {
next_child = const_cast<Control *>(this);
while (next_child) {
- if (next_child->data.SI || next_child->data.RI)
+ if (next_child->data.RI)
break;
next_child = next_child->get_parent_control();
}
@@ -2058,7 +1968,7 @@ Control *Control::find_next_valid_focus() const {
}
if (next_child == this) // no next control->
- return (get_focus_mode() == FOCUS_ALL) ? next_child : NULL;
+ return (get_focus_mode() == FOCUS_ALL) ? next_child : nullptr;
if (next_child) {
if (next_child->get_focus_mode() == FOCUS_ALL)
return next_child;
@@ -2067,12 +1977,12 @@ Control *Control::find_next_valid_focus() const {
break;
}
- return NULL;
+ return nullptr;
}
static Control *_prev_control(Control *p_from) {
- Control *child = NULL;
+ Control *child = nullptr;
for (int i = p_from->get_child_count() - 1; i >= 0; i--) {
Control *c = Object::cast_to<Control>(p_from->get_child(i));
@@ -2102,9 +2012,9 @@ Control *Control::find_prev_valid_focus() const {
Control *c;
if (n) {
c = Object::cast_to<Control>(n);
- ERR_FAIL_COND_V_MSG(!c, NULL, "Previous focus node is not a control: " + n->get_name() + ".");
+ ERR_FAIL_COND_V_MSG(!c, nullptr, "Previous focus node is not a control: " + n->get_name() + ".");
} else {
- return NULL;
+ return nullptr;
}
if (c->is_visible() && c->get_focus_mode() != FOCUS_NONE)
return c;
@@ -2112,7 +2022,7 @@ Control *Control::find_prev_valid_focus() const {
// find prev child
- Control *prev_child = NULL;
+ Control *prev_child = nullptr;
if (from->is_set_as_toplevel() || !Object::cast_to<Control>(from->get_parent())) {
@@ -2122,7 +2032,7 @@ Control *Control::find_prev_valid_focus() const {
} else {
- for (int i = (from->get_position_in_parent() - 1); i >= 0; i--) {
+ for (int i = (from->get_index() - 1); i >= 0; i--) {
Control *c = Object::cast_to<Control>(from->get_parent()->get_child(i));
@@ -2144,7 +2054,7 @@ Control *Control::find_prev_valid_focus() const {
}
if (prev_child == this) // no prev control->
- return (get_focus_mode() == FOCUS_ALL) ? prev_child : NULL;
+ return (get_focus_mode() == FOCUS_ALL) ? prev_child : nullptr;
if (prev_child->get_focus_mode() == FOCUS_ALL)
return prev_child;
@@ -2152,7 +2062,7 @@ Control *Control::find_prev_valid_focus() const {
from = prev_child;
}
- return NULL;
+ return nullptr;
}
Control::FocusMode Control::get_focus_mode() const {
@@ -2192,53 +2102,29 @@ bool Control::is_toplevel_control() const {
return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_toplevel());
}
-void Control::show_modal(bool p_exclusive) {
-
- ERR_FAIL_COND(!is_inside_tree());
- ERR_FAIL_COND(!data.SI);
-
- if (is_visible_in_tree())
- hide();
-
- ERR_FAIL_COND(data.MI != NULL);
- show();
- raise();
- data.modal_exclusive = p_exclusive;
- data.MI = get_viewport()->_gui_show_modal(this);
- data.modal_frame = Engine::get_singleton()->get_frames_drawn();
-}
+void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) {
-void Control::_modal_set_prev_focus_owner(ObjectID p_prev) {
- data.modal_prev_focus_owner = p_prev;
-}
-
-void Control::_modal_stack_remove() {
-
- ERR_FAIL_COND(!is_inside_tree());
+ Control *c = Object::cast_to<Control>(p_at);
- if (!data.MI)
+ if (c && c != p_owner && c->data.theme.is_valid()) // has a theme, this can't be propagated
return;
- List<Control *>::Element *element = data.MI;
- data.MI = NULL;
-
- get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner);
-
- data.modal_prev_focus_owner = ObjectID();
-}
+ Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr;
-void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign) {
-
- Control *c = Object::cast_to<Control>(p_at);
-
- if (c && c != p_owner && c->data.theme.is_valid()) // has a theme, this can't be propagated
+ if (w && w != p_owner_window && w->theme.is_valid()) // has a theme, this can't be propagated
return;
for (int i = 0; i < p_at->get_child_count(); i++) {
CanvasItem *child = Object::cast_to<CanvasItem>(p_at->get_child(i));
if (child) {
- _propagate_theme_changed(child, p_owner, p_assign);
+ _propagate_theme_changed(child, p_owner, p_owner_window, p_assign);
+ } else {
+
+ Window *window = Object::cast_to<Window>(p_at->get_child(i));
+ if (window) {
+ _propagate_theme_changed(window, p_owner, p_owner_window, p_assign);
+ }
}
}
@@ -2246,14 +2132,26 @@ void Control::_propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool
if (p_assign) {
c->data.theme_owner = p_owner;
+ c->data.theme_owner_window = p_owner_window;
+ }
+ c->notification(Control::NOTIFICATION_THEME_CHANGED);
+ c->emit_signal(SceneStringNames::get_singleton()->theme_changed);
+ }
+
+ if (w) {
+
+ if (p_assign) {
+ w->theme_owner = p_owner;
+ w->theme_owner_window = p_owner_window;
}
- c->notification(NOTIFICATION_THEME_CHANGED);
+ w->notification(Window::NOTIFICATION_THEME_CHANGED);
+ w->emit_signal(SceneStringNames::get_singleton()->theme_changed);
}
}
void Control::_theme_changed() {
- _propagate_theme_changed(this, this, false);
+ _propagate_theme_changed(this, this, nullptr, false);
}
void Control::set_theme(const Ref<Theme> &p_theme) {
@@ -2269,15 +2167,21 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
if (!p_theme.is_null()) {
data.theme_owner = this;
- _propagate_theme_changed(this, this);
+ data.theme_owner_window = nullptr;
+ _propagate_theme_changed(this, this, nullptr);
} else {
- Control *parent = cast_to<Control>(get_parent());
- if (parent && parent->data.theme_owner) {
- _propagate_theme_changed(this, parent->data.theme_owner);
- } else {
+ Control *parent_c = Object::cast_to<Control>(get_parent());
- _propagate_theme_changed(this, NULL);
+ if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
+ } else {
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
+ } else {
+ Control::_propagate_theme_changed(this, nullptr, nullptr);
+ }
}
}
@@ -2311,7 +2215,7 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
if (get_script_instance()) {
return const_cast<Control *>(this)->call("_make_custom_tooltip", p_text);
}
- return NULL;
+ return nullptr;
}
void Control::set_default_cursor_shape(CursorShape p_shape) {
@@ -2378,19 +2282,19 @@ NodePath Control::get_focus_previous() const {
Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
- ERR_FAIL_INDEX_V((int)p_margin, 4, NULL);
+ ERR_FAIL_INDEX_V((int)p_margin, 4, nullptr);
if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT)
- return NULL;
+ return nullptr;
if (!data.focus_neighbour[p_margin].is_empty()) {
- Control *c = NULL;
+ Control *c = nullptr;
Node *n = get_node(data.focus_neighbour[p_margin]);
if (n) {
c = Object::cast_to<Control>(n);
- ERR_FAIL_COND_V_MSG(!c, NULL, "Neighbor focus node is not a control: " + n->get_name() + ".");
+ ERR_FAIL_COND_V_MSG(!c, nullptr, "Neighbor focus node is not a control: " + n->get_name() + ".");
} else {
- return NULL;
+ return nullptr;
}
bool valid = true;
if (!c->is_visible())
@@ -2405,7 +2309,7 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
}
float dist = 1e7;
- Control *result = NULL;
+ Control *result = nullptr;
Point2 points[4];
@@ -2440,8 +2344,6 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
Control *c = Object::cast_to<Control>(base);
if (c) {
- if (c->data.SI)
- break;
if (c->data.RI)
break;
}
@@ -2449,7 +2351,7 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
}
if (!base)
- return NULL;
+ return nullptr;
_window_find_focus_neighbour(vdir, base, points, maxd, dist, &result);
@@ -2511,7 +2413,7 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con
Node *child = p_at->get_child(i);
Control *childc = Object::cast_to<Control>(child);
- if (childc && childc->data.SI)
+ if (childc && childc->data.RI)
continue; //subwindow, ignore
_window_find_focus_neighbour(p_dir, p_at->get_child(i), p_points, p_min, r_closest_dist, r_closest);
}
@@ -2569,6 +2471,12 @@ void Control::minimum_size_changed() {
invalidate->data.minimum_size_valid = false;
if (invalidate->is_set_as_toplevel())
break; // do not go further up
+ if (!invalidate->data.parent && get_parent()) {
+ Window *parent_window = Object::cast_to<Window>(get_parent());
+ if (parent_window && parent_window->is_wrapping_controls()) {
+ parent_window->child_controls_changed();
+ }
+ }
invalidate = invalidate->data.parent;
}
@@ -2599,19 +2507,9 @@ Control::MouseFilter Control::get_mouse_filter() const {
return data.mouse_filter;
}
-void Control::set_pass_on_modal_close_click(bool p_pass_on) {
-
- data.pass_on_modal_close_click = p_pass_on;
-}
-
-bool Control::pass_on_modal_close_click() const {
-
- return data.pass_on_modal_close_click;
-}
-
Control *Control::get_focus_owner() const {
- ERR_FAIL_COND_V(!is_inside_tree(), NULL);
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
return get_viewport()->_gui_get_focus_owner();
}
@@ -2658,6 +2556,7 @@ float Control::get_rotation_degrees() const {
void Control::_override_changed() {
notification(NOTIFICATION_THEME_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->theme_changed);
minimum_size_changed(); // overrides are likely to affect minimum size
}
@@ -2701,7 +2600,7 @@ Control *Control::get_root_parent_control() const {
if (c) {
root = c;
- if (c->data.RI || c->data.MI || c->is_toplevel_control())
+ if (c->data.RI || c->is_toplevel_control())
break;
}
@@ -2853,7 +2752,6 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_global_position"), &Control::get_global_position);
ClassDB::bind_method(D_METHOD("get_rect"), &Control::get_rect);
ClassDB::bind_method(D_METHOD("get_global_rect"), &Control::get_global_rect);
- ClassDB::bind_method(D_METHOD("show_modal", "exclusive"), &Control::show_modal, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_focus_mode", "mode"), &Control::set_focus_mode);
ClassDB::bind_method(D_METHOD("get_focus_mode"), &Control::get_focus_mode);
ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus);
@@ -2873,31 +2771,31 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Control::set_theme);
ClassDB::bind_method(D_METHOD("get_theme"), &Control::get_theme);
- ClassDB::bind_method(D_METHOD("add_icon_override", "name", "texture"), &Control::add_icon_override);
- ClassDB::bind_method(D_METHOD("add_shader_override", "name", "shader"), &Control::add_shader_override);
- ClassDB::bind_method(D_METHOD("add_stylebox_override", "name", "stylebox"), &Control::add_style_override);
- ClassDB::bind_method(D_METHOD("add_font_override", "name", "font"), &Control::add_font_override);
- ClassDB::bind_method(D_METHOD("add_color_override", "name", "color"), &Control::add_color_override);
- ClassDB::bind_method(D_METHOD("add_constant_override", "name", "constant"), &Control::add_constant_override);
-
- ClassDB::bind_method(D_METHOD("get_icon", "name", "type"), &Control::get_icon, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_stylebox", "name", "type"), &Control::get_stylebox, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_font", "name", "type"), &Control::get_font, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_color", "name", "type"), &Control::get_color, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_constant", "name", "type"), &Control::get_constant, DEFVAL(""));
-
- ClassDB::bind_method(D_METHOD("has_icon_override", "name"), &Control::has_icon_override);
- ClassDB::bind_method(D_METHOD("has_shader_override", "name"), &Control::has_shader_override);
- ClassDB::bind_method(D_METHOD("has_stylebox_override", "name"), &Control::has_stylebox_override);
- ClassDB::bind_method(D_METHOD("has_font_override", "name"), &Control::has_font_override);
- ClassDB::bind_method(D_METHOD("has_color_override", "name"), &Control::has_color_override);
- ClassDB::bind_method(D_METHOD("has_constant_override", "name"), &Control::has_constant_override);
-
- ClassDB::bind_method(D_METHOD("has_icon", "name", "type"), &Control::has_icon, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_stylebox", "name", "type"), &Control::has_stylebox, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_font", "name", "type"), &Control::has_font, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_color", "name", "type"), &Control::has_color, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("has_constant", "name", "type"), &Control::has_constant, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Control::add_theme_icon_override);
+ ClassDB::bind_method(D_METHOD("add_theme_shader_override", "name", "shader"), &Control::add_theme_shader_override);
+ ClassDB::bind_method(D_METHOD("add_theme_stylebox_override", "name", "stylebox"), &Control::add_theme_style_override);
+ ClassDB::bind_method(D_METHOD("add_theme_font_override", "name", "font"), &Control::add_theme_font_override);
+ 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("get_theme_icon", "name", "type"), &Control::get_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "type"), &Control::get_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font", "name", "type"), &Control::get_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_color", "name", "type"), &Control::get_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "type"), &Control::get_theme_constant, DEFVAL(""));
+
+ ClassDB::bind_method(D_METHOD("has_theme_icon_override", "name"), &Control::has_theme_icon_override);
+ ClassDB::bind_method(D_METHOD("has_theme_shader_override", "name"), &Control::has_theme_shader_override);
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox_override", "name"), &Control::has_theme_stylebox_override);
+ ClassDB::bind_method(D_METHOD("has_theme_font_override", "name"), &Control::has_theme_font_override);
+ ClassDB::bind_method(D_METHOD("has_theme_color_override", "name"), &Control::has_theme_color_override);
+ ClassDB::bind_method(D_METHOD("has_theme_constant_override", "name"), &Control::has_theme_constant_override);
+
+ ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "type"), &Control::has_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "type"), &Control::has_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font", "name", "type"), &Control::has_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_color", "name", "type"), &Control::has_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "type"), &Control::has_theme_constant, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control);
@@ -3013,7 +2911,6 @@ void Control::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_FOCUS_ENTER);
BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
- BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN);
BIND_CONSTANT(NOTIFICATION_SCROLL_END);
@@ -3082,31 +2979,27 @@ void Control::_bind_methods() {
ADD_SIGNAL(MethodInfo("focus_exited"));
ADD_SIGNAL(MethodInfo("size_flags_changed"));
ADD_SIGNAL(MethodInfo("minimum_size_changed"));
- ADD_SIGNAL(MethodInfo("modal_closed"));
+ ADD_SIGNAL(MethodInfo("theme_changed"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point")));
}
Control::Control() {
- data.parent = NULL;
+ data.parent = nullptr;
data.mouse_filter = MOUSE_FILTER_STOP;
- data.pass_on_modal_close_click = true;
- data.SI = NULL;
- data.MI = NULL;
- data.RI = NULL;
- data.theme_owner = NULL;
- data.modal_exclusive = false;
+ data.RI = nullptr;
+ data.theme_owner = nullptr;
+ data.theme_owner_window = nullptr;
data.default_cursor = CURSOR_ARROW;
data.h_size_flags = SIZE_FILL;
data.v_size_flags = SIZE_FILL;
data.expand = 1;
data.rotation = 0;
- data.parent_canvas_item = NULL;
+ data.parent_canvas_item = nullptr;
data.scale = Vector2(1, 1);
- data.modal_frame = 0;
data.block_minimum_size_adjust = false;
data.disable_visibility_clip = false;
data.h_grow = GROW_DIRECTION_END;
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 67e8ed0d27..d02fea20a6 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -33,8 +33,8 @@
#include "core/math/transform_2d.h"
#include "core/rid.h"
-#include "scene/2d/canvas_item.h"
#include "scene/gui/shortcut.h"
+#include "scene/main/canvas_item.h"
#include "scene/main/node.h"
#include "scene/main/timer.h"
#include "scene/resources/theme.h"
@@ -168,8 +168,6 @@ private:
float expand;
Point2 custom_minimum_size;
- bool pass_on_modal_close_click;
-
MouseFilter mouse_filter;
bool clip_contents;
@@ -179,29 +177,24 @@ private:
Control *parent;
ObjectID drag_owner;
- bool modal_exclusive;
- uint64_t modal_frame; //frame used to put something as modal
Ref<Theme> theme;
Control *theme_owner;
+ Window *theme_owner_window;
String tooltip;
CursorShape default_cursor;
- List<Control *>::Element *MI; //modal item
- List<Control *>::Element *SI;
List<Control *>::Element *RI;
CanvasItem *parent_canvas_item;
- ObjectID modal_prev_focus_owner;
-
NodePath focus_neighbour[4];
NodePath focus_next;
NodePath focus_prev;
- HashMap<StringName, Ref<Texture2D> > icon_override;
- HashMap<StringName, Ref<Shader> > shader_override;
- HashMap<StringName, Ref<StyleBox> > style_override;
- HashMap<StringName, Ref<Font> > font_override;
+ HashMap<StringName, Ref<Texture2D>> icon_override;
+ HashMap<StringName, Ref<Shader>> shader_override;
+ HashMap<StringName, Ref<StyleBox>> style_override;
+ HashMap<StringName, Ref<Font>> font_override;
HashMap<StringName, Color> color_override;
HashMap<StringName, int> constant_override;
@@ -218,7 +211,6 @@ private:
void _set_global_position(const Point2 &p_point);
void _set_size(const Size2 &p_size);
- void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign = true);
void _theme_changed();
void _change_notify_margins();
@@ -240,10 +232,29 @@ private:
Transform2D _get_internal_transform() const;
friend class Viewport;
- void _modal_stack_remove();
- void _modal_set_prev_focus_owner(ObjectID p_prev);
void _update_minimum_size_cache();
+ friend class Window;
+ static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true);
+
+ template <class T>
+ _FORCE_INLINE_ static bool _find_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, T &, T (Theme::*get_func)(const StringName &, const StringName &) const, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type);
+
+ _FORCE_INLINE_ static bool _has_theme_item(Control *p_theme_owner, Window *p_theme_owner_window, bool (Theme::*has_func)(const StringName &, const StringName &) const, const StringName &p_name, const StringName &p_type);
+
+ static Ref<Texture2D> get_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static Ref<Shader> get_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static Ref<StyleBox> get_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static Ref<Font> get_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static Color get_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static int get_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+
+ static bool has_icons(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static bool has_shaders(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static bool has_styleboxs(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static bool has_fonts(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static bool has_colors(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
+ static bool has_constants(Control *p_theme_owner, Window *p_theme_owner_window, const StringName &p_name, const StringName &p_type = StringName());
protected:
virtual void add_child_notify(Node *p_child);
@@ -272,7 +283,6 @@ public:
NOTIFICATION_FOCUS_ENTER = 43,
NOTIFICATION_FOCUS_EXIT = 44,
NOTIFICATION_THEME_CHANGED = 45,
- NOTIFICATION_MODAL_CLOSE = 46,
NOTIFICATION_SCROLL_BEGIN = 47,
NOTIFICATION_SCROLL_END = 48,
@@ -320,9 +330,6 @@ public:
void set_custom_minimum_size(const Size2 &p_custom);
Size2 get_custom_minimum_size() const;
- bool is_window_modal_on_top() const;
- uint64_t get_modal_frame() const; //frame in which this was made modal
-
Control *get_parent_control() const;
/* POSITIONING */
@@ -349,12 +356,14 @@ public:
void set_global_position(const Point2 &p_point, bool p_keep_margins = false);
Point2 get_position() const;
Point2 get_global_position() const;
+ Point2 get_screen_position() const;
void set_size(const Size2 &p_size, bool p_keep_margins = false);
Size2 get_size() const;
Rect2 get_rect() const;
Rect2 get_global_rect() const;
+ Rect2 get_screen_rect() const;
Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server
Rect2 get_anchorable_rect() const;
@@ -375,8 +384,6 @@ public:
void set_scale(const Vector2 &p_scale);
Vector2 get_scale() const;
- void show_modal(bool p_exclusive = false);
-
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
@@ -415,38 +422,35 @@ public:
void set_mouse_filter(MouseFilter p_filter);
MouseFilter get_mouse_filter() const;
- void set_pass_on_modal_close_click(bool p_pass_on);
- bool pass_on_modal_close_click() const;
-
/* SKINNING */
- void add_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon);
- void add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader);
- void add_style_override(const StringName &p_name, const Ref<StyleBox> &p_style);
- void add_font_override(const StringName &p_name, const Ref<Font> &p_font);
- void add_color_override(const StringName &p_name, const Color &p_color);
- void add_constant_override(const StringName &p_name, int p_constant);
-
- Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<Shader> get_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
- Ref<Font> get_font(const StringName &p_name, const StringName &p_type = StringName()) const;
- Color get_color(const StringName &p_name, const StringName &p_type = StringName()) const;
- int get_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
-
- bool has_icon_override(const StringName &p_name) const;
- bool has_shader_override(const StringName &p_name) const;
- bool has_stylebox_override(const StringName &p_name) const;
- bool has_font_override(const StringName &p_name) const;
- bool has_color_override(const StringName &p_name) const;
- bool has_constant_override(const StringName &p_name) const;
-
- bool has_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_font(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_color(const StringName &p_name, const StringName &p_type = StringName()) const;
- bool has_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+ void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon);
+ void add_theme_shader_override(const StringName &p_name, const Ref<Shader> &p_shader);
+ void add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style);
+ void add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font);
+ 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);
+
+ Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
+ int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+
+ bool has_theme_icon_override(const StringName &p_name) const;
+ bool has_theme_shader_override(const StringName &p_name) const;
+ bool has_theme_stylebox_override(const StringName &p_name) const;
+ bool has_theme_font_override(const StringName &p_name) const;
+ bool has_theme_color_override(const StringName &p_name) const;
+ bool has_theme_constant_override(const StringName &p_name) const;
+
+ bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
/* TOOLTIP */
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 6cadd0a63e..5654219a3e 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -29,6 +29,8 @@
/*************************************************************************/
#include "dialogs.h"
+
+#include "core/os/keyboard.h"
#include "core/print_string.h"
#include "core/translation.h"
#include "line_edit.h"
@@ -36,362 +38,61 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
-#include "scene/main/viewport.h" // Only used to check for more modals when dimming the editor.
+#include "scene/main/window.h" // Only used to check for more modals when dimming the editor.
#endif
-// WindowDialog
-
-void WindowDialog::_post_popup() {
-
- drag_type = DRAG_NONE; // just in case
-}
-
-void WindowDialog::_fix_size() {
-
- // Perhaps this should be called when the viewport resizes as well or windows go out of bounds...
-
- // Ensure the whole window is visible.
- Point2i pos = get_global_position();
- Size2i size = get_size();
- Size2i viewport_size = get_viewport_rect().size;
-
- // Windows require additional padding to keep the window chrome visible.
- Ref<StyleBox> panel = get_stylebox("panel", "WindowDialog");
- float top = 0;
- float left = 0;
- float bottom = 0;
- float right = 0;
- // Check validity, because the theme could contain a different type of StyleBox.
- if (panel->get_class() == "StyleBoxTexture") {
- Ref<StyleBoxTexture> panel_texture = Object::cast_to<StyleBoxTexture>(*panel);
- top = panel_texture->get_expand_margin_size(MARGIN_TOP);
- left = panel_texture->get_expand_margin_size(MARGIN_LEFT);
- bottom = panel_texture->get_expand_margin_size(MARGIN_BOTTOM);
- right = panel_texture->get_expand_margin_size(MARGIN_RIGHT);
- } else if (panel->get_class() == "StyleBoxFlat") {
- Ref<StyleBoxFlat> panel_flat = Object::cast_to<StyleBoxFlat>(*panel);
- top = panel_flat->get_expand_margin_size(MARGIN_TOP);
- left = panel_flat->get_expand_margin_size(MARGIN_LEFT);
- bottom = panel_flat->get_expand_margin_size(MARGIN_BOTTOM);
- right = panel_flat->get_expand_margin_size(MARGIN_RIGHT);
- }
-
- pos.x = MAX(left, MIN(pos.x, viewport_size.x - size.x - right));
- pos.y = MAX(top, MIN(pos.y, viewport_size.y - size.y - bottom));
- set_global_position(pos);
+// AcceptDialog
- if (resizable) {
- size.x = MIN(size.x, viewport_size.x - left - right);
- size.y = MIN(size.y, viewport_size.y - top - bottom);
- set_size(size);
+void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid() && key->is_pressed() && key->get_keycode() == KEY_ESCAPE) {
+ _cancel_pressed();
}
}
-bool WindowDialog::has_point(const Point2 &p_point) const {
-
- Rect2 r(Point2(), get_size());
-
- // Enlarge upwards for title bar.
- int title_height = get_constant("title_height", "WindowDialog");
- r.position.y -= title_height;
- r.size.y += title_height;
-
- // Inflate by the resizable border thickness.
- if (resizable) {
- int scaleborder_size = get_constant("scaleborder_size", "WindowDialog");
- r.position.x -= scaleborder_size;
- r.size.width += scaleborder_size * 2;
- r.position.y -= scaleborder_size;
- r.size.height += scaleborder_size * 2;
- }
-
- return r.has_point(p_point);
+void AcceptDialog::_parent_focused() {
+ _cancel_pressed();
}
-void WindowDialog::_gui_input(const Ref<InputEvent> &p_event) {
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
-
- if (mb->is_pressed()) {
- // Begin a possible dragging operation.
- drag_type = _drag_hit_test(Point2(mb->get_position().x, mb->get_position().y));
- if (drag_type != DRAG_NONE)
- drag_offset = get_global_mouse_position() - get_position();
- drag_offset_far = get_position() + get_size() - get_global_mouse_position();
- } else if (drag_type != DRAG_NONE && !mb->is_pressed()) {
- // End a dragging operation.
- drag_type = DRAG_NONE;
- }
- }
+void AcceptDialog::_notification(int p_what) {
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
-
- if (drag_type == DRAG_NONE) {
- // Update the cursor while moving along the borders.
- CursorShape cursor = CURSOR_ARROW;
- if (resizable) {
- int preview_drag_type = _drag_hit_test(Point2(mm->get_position().x, mm->get_position().y));
- switch (preview_drag_type) {
- case DRAG_RESIZE_TOP:
- case DRAG_RESIZE_BOTTOM:
- cursor = CURSOR_VSIZE;
- break;
- case DRAG_RESIZE_LEFT:
- case DRAG_RESIZE_RIGHT:
- cursor = CURSOR_HSIZE;
- break;
- case DRAG_RESIZE_TOP + DRAG_RESIZE_LEFT:
- case DRAG_RESIZE_BOTTOM + DRAG_RESIZE_RIGHT:
- cursor = CURSOR_FDIAGSIZE;
- break;
- case DRAG_RESIZE_TOP + DRAG_RESIZE_RIGHT:
- case DRAG_RESIZE_BOTTOM + DRAG_RESIZE_LEFT:
- cursor = CURSOR_BDIAGSIZE;
- break;
+ switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+
+ get_ok()->grab_focus();
+ _update_child_rects();
+ parent_visible = get_parent_visible_window();
+ if (parent_visible) {
+ parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
}
- }
- if (get_cursor_shape() != cursor)
- set_default_cursor_shape(cursor);
- } else {
- // Update while in a dragging operation.
- Point2 global_pos = get_global_mouse_position();
- global_pos.y = MAX(global_pos.y, 0); // Ensure title bar stays visible.
-
- Rect2 rect = get_rect();
- Size2 min_size = get_combined_minimum_size();
-
- if (drag_type == DRAG_MOVE) {
- rect.position = global_pos - drag_offset;
} else {
- if (drag_type & DRAG_RESIZE_TOP) {
- int bottom = rect.position.y + rect.size.height;
- int max_y = bottom - min_size.height;
- rect.position.y = MIN(global_pos.y - drag_offset.y, max_y);
- rect.size.height = bottom - rect.position.y;
- } else if (drag_type & DRAG_RESIZE_BOTTOM) {
- rect.size.height = global_pos.y - rect.position.y + drag_offset_far.y;
- }
- if (drag_type & DRAG_RESIZE_LEFT) {
- int right = rect.position.x + rect.size.width;
- int max_x = right - min_size.width;
- rect.position.x = MIN(global_pos.x - drag_offset.x, max_x);
- rect.size.width = right - rect.position.x;
- } else if (drag_type & DRAG_RESIZE_RIGHT) {
- rect.size.width = global_pos.x - rect.position.x + drag_offset_far.x;
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ parent_visible = nullptr;
}
}
- set_size(rect.size);
- set_position(rect.position);
- }
- }
-}
-
-void WindowDialog::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_DRAW: {
- RID canvas = get_canvas_item();
-
- // Draw the background.
- Ref<StyleBox> panel = get_stylebox("panel");
- Size2 size = get_size();
- panel->draw(canvas, Rect2(0, 0, size.x, size.y));
-
- // Draw the title bar text.
- Ref<Font> title_font = get_font("title_font", "WindowDialog");
- Color title_color = get_color("title_color", "WindowDialog");
- int title_height = get_constant("title_height", "WindowDialog");
- int font_height = title_font->get_height() - title_font->get_descent() * 2;
- int x = (size.x - title_font->get_string_size(xl_title).x) / 2;
- int y = (-title_height + font_height) / 2;
- title_font->draw(canvas, Point2(x, y), xl_title, title_color, size.x - panel->get_minimum_size().x);
} break;
- case NOTIFICATION_THEME_CHANGED:
- case NOTIFICATION_ENTER_TREE: {
- close_button->set_normal_texture(get_icon("close", "WindowDialog"));
- close_button->set_pressed_texture(get_icon("close", "WindowDialog"));
- close_button->set_hover_texture(get_icon("close_highlight", "WindowDialog"));
- close_button->set_anchor(MARGIN_LEFT, ANCHOR_END);
- close_button->set_begin(Point2(-get_constant("close_h_ofs", "WindowDialog"), -get_constant("close_v_ofs", "WindowDialog")));
- } break;
-
- case NOTIFICATION_TRANSLATION_CHANGED: {
- String new_title = tr(title);
- if (new_title != xl_title) {
- xl_title = new_title;
- minimum_size_changed();
- update();
- }
+ case NOTIFICATION_THEME_CHANGED: {
+ bg->add_theme_style_override("panel", bg->get_theme_stylebox("panel", "AcceptDialog"));
} break;
- case NOTIFICATION_MOUSE_EXIT: {
- // Reset the mouse cursor when leaving the resizable window border.
- if (resizable && !drag_type) {
- if (get_default_cursor_shape() != CURSOR_ARROW)
- set_default_cursor_shape(CURSOR_ARROW);
+ case NOTIFICATION_EXIT_TREE: {
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ parent_visible = nullptr;
}
} break;
-
-#ifdef TOOLS_ENABLED
- case NOTIFICATION_POST_POPUP: {
- if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton()) {
- was_editor_dimmed = EditorNode::get_singleton()->is_editor_dimmed();
- EditorNode::get_singleton()->dim_editor(true);
+ case NOTIFICATION_READY:
+ case NOTIFICATION_WM_SIZE_CHANGED: {
+ if (is_visible()) {
+ _update_child_rects();
}
} break;
-
- case NOTIFICATION_POPUP_HIDE: {
- if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton() && !was_editor_dimmed) {
- EditorNode::get_singleton()->dim_editor(false);
- set_pass_on_modal_close_click(false);
- }
- } break;
-#endif
- }
-}
-
-void WindowDialog::_closed() {
-
- _close_pressed();
- hide();
-}
-
-int WindowDialog::_drag_hit_test(const Point2 &pos) const {
- int drag_type = DRAG_NONE;
-
- if (resizable) {
- int title_height = get_constant("title_height", "WindowDialog");
- int scaleborder_size = get_constant("scaleborder_size", "WindowDialog");
-
- Rect2 rect = get_rect();
-
- if (pos.y < (-title_height + scaleborder_size))
- drag_type = DRAG_RESIZE_TOP;
- else if (pos.y >= (rect.size.height - scaleborder_size))
- drag_type = DRAG_RESIZE_BOTTOM;
- if (pos.x < scaleborder_size)
- drag_type |= DRAG_RESIZE_LEFT;
- else if (pos.x >= (rect.size.width - scaleborder_size))
- drag_type |= DRAG_RESIZE_RIGHT;
- }
-
- if (drag_type == DRAG_NONE && pos.y < 0)
- drag_type = DRAG_MOVE;
-
- return drag_type;
-}
-
-void WindowDialog::set_title(const String &p_title) {
-
- if (title != p_title) {
- title = p_title;
- xl_title = tr(p_title);
- minimum_size_changed();
- update();
- }
-}
-String WindowDialog::get_title() const {
-
- return title;
-}
-
-void WindowDialog::set_resizable(bool p_resizable) {
- resizable = p_resizable;
-}
-bool WindowDialog::get_resizable() const {
- return resizable;
-}
-
-Size2 WindowDialog::get_minimum_size() const {
-
- Ref<Font> font = get_font("title_font", "WindowDialog");
-
- const int button_width = close_button->get_combined_minimum_size().x;
- const int title_width = font->get_string_size(xl_title).x;
- const int padding = button_width / 2;
- const int button_area = button_width + padding;
-
- // As the title gets centered, title_width + close_button_width is not enough.
- // We want a width w, such that w / 2 - title_width / 2 >= button_area, i.e.
- // w >= 2 * button_area + title_width
-
- return Size2(2 * button_area + title_width, 1);
-}
-
-TextureButton *WindowDialog::get_close_button() {
-
- return close_button;
-}
-
-void WindowDialog::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_gui_input"), &WindowDialog::_gui_input);
- ClassDB::bind_method(D_METHOD("set_title", "title"), &WindowDialog::set_title);
- ClassDB::bind_method(D_METHOD("get_title"), &WindowDialog::get_title);
- ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &WindowDialog::set_resizable);
- ClassDB::bind_method(D_METHOD("get_resizable"), &WindowDialog::get_resizable);
- ClassDB::bind_method(D_METHOD("get_close_button"), &WindowDialog::get_close_button);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "window_title", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_title", "get_title");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_resizable", "get_resizable");
-}
-
-WindowDialog::WindowDialog() {
-
- drag_type = DRAG_NONE;
- resizable = false;
- close_button = memnew(TextureButton);
- add_child(close_button);
- close_button->connect("pressed", callable_mp(this, &WindowDialog::_closed));
-
-#ifdef TOOLS_ENABLED
- was_editor_dimmed = false;
-#endif
-}
-
-WindowDialog::~WindowDialog() {
-}
-
-// PopupDialog
-
-void PopupDialog::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_DRAW) {
- RID ci = get_canvas_item();
- get_stylebox("panel")->draw(ci, Rect2(Point2(), get_size()));
- }
-}
-
-PopupDialog::PopupDialog() {
-}
-
-PopupDialog::~PopupDialog() {
-}
-
-// AcceptDialog
-
-void AcceptDialog::_post_popup() {
-
- WindowDialog::_post_popup();
- get_ok()->grab_focus();
-}
-
-void AcceptDialog::_notification(int p_what) {
-
- switch (p_what) {
- case NOTIFICATION_MODAL_CLOSE: {
- cancel_pressed();
- } break;
-
- case NOTIFICATION_READY:
- case NOTIFICATION_RESIZED: {
- _update_child_rects();
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
+ _cancel_pressed();
} break;
}
}
@@ -404,20 +105,28 @@ void AcceptDialog::_text_entered(const String &p_text) {
void AcceptDialog::_ok_pressed() {
if (hide_on_ok)
- hide();
+ set_visible(false);
ok_pressed();
emit_signal("confirmed");
}
-void AcceptDialog::_close_pressed() {
+void AcceptDialog::_cancel_pressed() {
+
+ Window *parent_window = parent_visible;
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused));
+ parent_visible = nullptr;
+ }
+
+ call_deferred("hide");
+
+ emit_signal("cancelled");
cancel_pressed();
-}
-// FIXME: This is redundant with _closed_pressed, but there's a slight behavior
-// change (WindowDialog's _closed() also calls hide()) which should be assessed.
-void AcceptDialog::_on_close_pressed() {
- _closed(); // From WindowDialog.
+ if (parent_window) {
+ //parent_window->grab_focus();
+ }
}
String AcceptDialog::get_text() const {
@@ -427,8 +136,10 @@ String AcceptDialog::get_text() const {
void AcceptDialog::set_text(String p_text) {
label->set_text(p_text);
- minimum_size_changed();
- _update_child_rects();
+ child_controls_changed();
+ if (is_visible()) {
+ _update_child_rects();
+ }
}
void AcceptDialog::set_hide_on_ok(bool p_hide) {
@@ -463,7 +174,7 @@ void AcceptDialog::_update_child_rects() {
if (label->get_text().empty()) {
label_size.height = 0;
}
- int margin = get_constant("margin", "Dialogs");
+ int margin = hbc->get_theme_constant("margin", "Dialogs");
Size2 size = get_size();
Size2 hminsize = hbc->get_combined_minimum_size();
@@ -475,7 +186,7 @@ void AcceptDialog::_update_child_rects() {
if (!c)
continue;
- if (c == hbc || c == label || c == get_close_button() || c->is_set_as_toplevel())
+ if (c == hbc || c == label || c == bg || c->is_set_as_toplevel())
continue;
c->set_position(cpos);
@@ -487,11 +198,14 @@ void AcceptDialog::_update_child_rects() {
hbc->set_position(cpos);
hbc->set_size(csize);
+
+ bg->set_position(Point2());
+ bg->set_size(size);
}
-Size2 AcceptDialog::get_minimum_size() const {
+Size2 AcceptDialog::_get_contents_minimum_size() const {
- int margin = get_constant("margin", "Dialogs");
+ int margin = hbc->get_theme_constant("margin", "Dialogs");
Size2 minsize = label->get_combined_minimum_size();
for (int i = 0; i < get_child_count(); i++) {
@@ -499,7 +213,7 @@ Size2 AcceptDialog::get_minimum_size() const {
if (!c)
continue;
- if (c == hbc || c == label || c == const_cast<AcceptDialog *>(this)->get_close_button() || c->is_set_as_toplevel())
+ if (c == hbc || c == label || c->is_set_as_toplevel())
continue;
Size2 cminsize = c->get_combined_minimum_size();
@@ -513,7 +227,7 @@ Size2 AcceptDialog::get_minimum_size() const {
minsize.x += margin * 2;
minsize.y += margin * 3; //one as separation between hbc and child
- Size2 wmsize = WindowDialog::get_minimum_size();
+ Size2 wmsize = get_min_size();
minsize.x = MAX(wmsize.x, minsize.x);
return minsize;
}
@@ -551,7 +265,7 @@ Button *AcceptDialog::add_cancel(const String &p_cancel) {
if (p_cancel == "")
c = RTR("Cancel");
Button *b = swap_ok_cancel ? add_button(c, true) : add_button(c);
- b->connect("pressed", callable_mp(this, &AcceptDialog::_on_close_pressed));
+ b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
return b;
}
@@ -570,6 +284,7 @@ void AcceptDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_autowrap"), &AcceptDialog::has_autowrap);
ADD_SIGNAL(MethodInfo("confirmed"));
+ ADD_SIGNAL(MethodInfo("cancelled"));
ADD_SIGNAL(MethodInfo("custom_action", PropertyInfo(Variant::STRING_NAME, "action")));
ADD_GROUP("Dialog", "dialog");
@@ -586,17 +301,27 @@ void AcceptDialog::set_swap_ok_cancel(bool p_swap) {
AcceptDialog::AcceptDialog() {
- int margin = get_constant("margin", "Dialogs");
- int button_margin = get_constant("button_margin", "Dialogs");
+ parent_visible = nullptr;
+
+ set_wrap_controls(true);
+ set_visible(false);
+ set_transient(true);
+
+ bg = memnew(Panel);
+ add_child(bg);
+
+ hbc = memnew(HBoxContainer);
+
+ int margin = hbc->get_theme_constant("margin", "Dialogs");
+ int button_margin = hbc->get_theme_constant("button_margin", "Dialogs");
label = memnew(Label);
- label->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- label->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
+ label->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END);
+ label->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END);
label->set_begin(Point2(margin, margin));
label->set_end(Point2(-margin, -button_margin - 10));
add_child(label);
- hbc = memnew(HBoxContainer);
add_child(hbc);
hbc->add_spacer();
@@ -606,10 +331,11 @@ AcceptDialog::AcceptDialog() {
hbc->add_spacer();
ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
- set_as_toplevel(true);
hide_on_ok = true;
set_title(RTR("Alert!"));
+
+ connect("window_input", callable_mp(this, &AcceptDialog::_input_from_window));
}
AcceptDialog::~AcceptDialog() {
@@ -631,7 +357,7 @@ ConfirmationDialog::ConfirmationDialog() {
set_title(RTR("Please Confirm..."));
#ifdef TOOLS_ENABLED
- set_custom_minimum_size(Size2(200, 70) * EDSCALE);
+ set_min_size(Size2(200, 70) * EDSCALE);
#endif
cancel = add_cancel();
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index c474f7849d..b68b4297d7 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -37,91 +37,32 @@
#include "scene/gui/panel.h"
#include "scene/gui/popup.h"
#include "scene/gui/texture_button.h"
-
-class WindowDialog : public Popup {
-
- GDCLASS(WindowDialog, Popup);
-
- enum DRAG_TYPE {
- DRAG_NONE = 0,
- DRAG_MOVE = 1,
- DRAG_RESIZE_TOP = 1 << 1,
- DRAG_RESIZE_RIGHT = 1 << 2,
- DRAG_RESIZE_BOTTOM = 1 << 3,
- DRAG_RESIZE_LEFT = 1 << 4
- };
-
- TextureButton *close_button;
- String title;
- String xl_title;
- int drag_type;
- Point2 drag_offset;
- Point2 drag_offset_far;
- bool resizable;
-
-#ifdef TOOLS_ENABLED
- bool was_editor_dimmed;
-#endif
-
- void _gui_input(const Ref<InputEvent> &p_event);
- int _drag_hit_test(const Point2 &pos) const;
-
-protected:
- virtual void _post_popup();
- virtual void _fix_size();
- virtual void _close_pressed() {}
- virtual bool has_point(const Point2 &p_point) const;
- void _notification(int p_what);
- static void _bind_methods();
-
- // Not private since used by derived classes signal.
- void _closed();
-
-public:
- TextureButton *get_close_button();
-
- void set_title(const String &p_title);
- String get_title() const;
- void set_resizable(bool p_resizable);
- bool get_resizable() const;
-
- Size2 get_minimum_size() const;
-
- WindowDialog();
- ~WindowDialog();
-};
-
-class PopupDialog : public Popup {
-
- GDCLASS(PopupDialog, Popup);
-
-protected:
- void _notification(int p_what);
-
-public:
- PopupDialog();
- ~PopupDialog();
-};
+#include "scene/main/window.h"
class LineEdit;
-class AcceptDialog : public WindowDialog {
+class AcceptDialog : public Window {
- GDCLASS(AcceptDialog, WindowDialog);
+ GDCLASS(AcceptDialog, Window);
+ Window *parent_visible;
+ Panel *bg;
HBoxContainer *hbc;
Label *label;
Button *ok;
bool hide_on_ok;
void _custom_action(const String &p_action);
- void _close_pressed();
void _update_child_rects();
static bool swap_ok_cancel;
+ void _input_from_window(const Ref<InputEvent> &p_event);
+ void _parent_focused();
+
protected:
- virtual void _post_popup();
+ virtual Size2 _get_contents_minimum_size() const;
+
void _notification(int p_what);
static void _bind_methods();
virtual void ok_pressed() {}
@@ -131,11 +72,9 @@ protected:
// Not private since used by derived classes signal.
void _text_entered(const String &p_text);
void _ok_pressed();
- void _on_close_pressed();
+ void _cancel_pressed();
public:
- Size2 get_minimum_size() const;
-
Label *get_label() { return label; }
static void set_swap_ok_cancel(bool p_swap);
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 3be77ff4b3..89d13ecd7f 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -34,52 +34,56 @@
#include "core/print_string.h"
#include "scene/gui/label.h"
-FileDialog::GetIconFunc FileDialog::get_icon_func = NULL;
-FileDialog::GetIconFunc FileDialog::get_large_icon_func = NULL;
+FileDialog::GetIconFunc FileDialog::get_icon_func = nullptr;
+FileDialog::GetIconFunc FileDialog::get_large_icon_func = nullptr;
-FileDialog::RegisterFunc FileDialog::register_func = NULL;
-FileDialog::RegisterFunc FileDialog::unregister_func = NULL;
+FileDialog::RegisterFunc FileDialog::register_func = nullptr;
+FileDialog::RegisterFunc FileDialog::unregister_func = nullptr;
VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
-void FileDialog::_notification(int p_what) {
+void FileDialog::_theme_changed() {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ Color font_color = vbox->get_theme_color("font_color", "ToolButton");
+ Color font_color_hover = vbox->get_theme_color("font_color_hover", "ToolButton");
+ Color font_color_pressed = vbox->get_theme_color("font_color_pressed", "ToolButton");
- if (p_what == NOTIFICATION_ENTER_TREE) {
- dir_up->set_icon(get_icon("parent_folder"));
- refresh->set_icon(get_icon("reload"));
- show_hidden->set_icon(get_icon("toggle_hidden"));
- }
+ dir_up->add_theme_color_override("icon_color_normal", font_color);
+ dir_up->add_theme_color_override("icon_color_hover", font_color_hover);
+ dir_up->add_theme_color_override("icon_color_pressed", font_color_pressed);
- Color font_color = get_color("font_color", "ToolButton");
- Color font_color_hover = get_color("font_color_hover", "ToolButton");
- Color font_color_pressed = get_color("font_color_pressed", "ToolButton");
+ refresh->add_theme_color_override("icon_color_normal", font_color);
+ refresh->add_theme_color_override("icon_color_hover", font_color_hover);
+ refresh->add_theme_color_override("icon_color_pressed", font_color_pressed);
- dir_up->add_color_override("icon_color_normal", font_color);
- dir_up->add_color_override("icon_color_hover", font_color_hover);
- dir_up->add_color_override("icon_color_pressed", font_color_pressed);
+ show_hidden->add_theme_color_override("icon_color_normal", font_color);
+ show_hidden->add_theme_color_override("icon_color_hover", font_color_hover);
+ show_hidden->add_theme_color_override("icon_color_pressed", font_color_pressed);
+}
- refresh->add_color_override("icon_color_normal", font_color);
- refresh->add_color_override("icon_color_hover", font_color_hover);
- refresh->add_color_override("icon_color_pressed", font_color_pressed);
+void FileDialog::_notification(int p_what) {
- show_hidden->add_color_override("icon_color_normal", font_color);
- show_hidden->add_color_override("icon_color_hover", font_color_hover);
- show_hidden->add_color_override("icon_color_pressed", font_color_pressed);
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ if (!is_visible()) {
- } else if (p_what == NOTIFICATION_POPUP_HIDE) {
+ set_process_unhandled_input(false);
+ }
+ }
+ if (p_what == NOTIFICATION_ENTER_TREE) {
- set_process_unhandled_input(false);
+ dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog"));
+ refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog"));
+ show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog"));
+ _theme_changed();
}
}
void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && is_window_modal_on_top()) {
+ if (k.is_valid() && has_focus()) {
if (k->is_pressed()) {
@@ -110,7 +114,7 @@ void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
}
if (handled)
- accept_event();
+ set_input_as_handled();
}
}
}
@@ -171,7 +175,7 @@ void FileDialog::_post_popup() {
update_file_list();
invalidated = false;
}
- if (mode == MODE_SAVE_FILE)
+ if (mode == FILE_MODE_SAVE_FILE)
file->grab_focus();
else
tree->grab_focus();
@@ -179,7 +183,7 @@ void FileDialog::_post_popup() {
set_process_unhandled_input(true);
// For open dir mode, deselect all items on file dialog open.
- if (mode == MODE_OPEN_DIR) {
+ if (mode == FILE_MODE_OPEN_DIR) {
deselect_items();
file_box->set_visible(false);
} else {
@@ -189,9 +193,9 @@ void FileDialog::_post_popup() {
void FileDialog::_action_pressed() {
- if (mode == MODE_OPEN_FILES) {
+ if (mode == FILE_MODE_OPEN_FILES) {
- TreeItem *ti = tree->get_next_selected(NULL);
+ TreeItem *ti = tree->get_next_selected(nullptr);
String fbase = dir_access->get_current_dir();
Vector<String> files;
@@ -211,10 +215,10 @@ void FileDialog::_action_pressed() {
String f = dir_access->get_current_dir().plus_file(file->get_text());
- if ((mode == MODE_OPEN_ANY || mode == MODE_OPEN_FILE) && dir_access->file_exists(f)) {
+ if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
emit_signal("file_selected", f);
hide();
- } else if (mode == MODE_OPEN_ANY || mode == MODE_OPEN_DIR) {
+ } else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) {
String path = dir_access->get_current_dir();
@@ -231,7 +235,7 @@ void FileDialog::_action_pressed() {
hide();
}
- if (mode == MODE_SAVE_FILE) {
+ if (mode == FILE_MODE_SAVE_FILE) {
bool valid = false;
@@ -283,7 +287,7 @@ void FileDialog::_action_pressed() {
if (!valid) {
- exterr->popup_centered_minsize(Size2(250, 80));
+ exterr->popup_centered(Size2(250, 80));
return;
}
@@ -307,7 +311,7 @@ void FileDialog::_cancel_pressed() {
bool FileDialog::_is_open_should_be_disabled() {
- if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE)
+ if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_SAVE_FILE)
return false;
TreeItem *ti = tree->get_next_selected(tree->get_root());
@@ -319,13 +323,13 @@ bool FileDialog::_is_open_should_be_disabled() {
}
// We have something that we can't select?
if (!ti)
- return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder.
+ return mode != FILE_MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder.
Dictionary d = ti->get_metadata(0);
// Opening a file, but selected a folder? Forbidden.
- return ((mode == MODE_OPEN_FILE || mode == MODE_OPEN_FILES) && d["dir"]) || // Flipped case, also forbidden.
- (mode == MODE_OPEN_DIR && !d["dir"]);
+ return ((mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES) && d["dir"]) || // Flipped case, also forbidden.
+ (mode == FILE_MODE_OPEN_DIR && !d["dir"]);
}
void FileDialog::_go_up() {
@@ -346,15 +350,15 @@ void FileDialog::deselect_items() {
switch (mode) {
- case MODE_OPEN_FILE:
- case MODE_OPEN_FILES:
+ case FILE_MODE_OPEN_FILE:
+ case FILE_MODE_OPEN_FILES:
get_ok()->set_text(RTR("Open"));
break;
- case MODE_OPEN_DIR:
+ case FILE_MODE_OPEN_DIR:
get_ok()->set_text(RTR("Select Current Folder"));
break;
- case MODE_OPEN_ANY:
- case MODE_SAVE_FILE:
+ case FILE_MODE_OPEN_ANY:
+ case FILE_MODE_SAVE_FILE:
// FIXME: Implement, or refactor to avoid duplication with set_mode
break;
}
@@ -375,7 +379,7 @@ void FileDialog::_tree_selected() {
if (!d["dir"]) {
file->set_text(d["name"]);
- } else if (mode == MODE_OPEN_DIR) {
+ } else if (mode == FILE_MODE_OPEN_DIR) {
get_ok()->set_text(RTR("Select This Folder"));
}
@@ -393,7 +397,7 @@ void FileDialog::_tree_item_activated() {
if (d["dir"]) {
dir_access->change_dir(d["name"]);
- if (mode == MODE_OPEN_FILE || mode == MODE_OPEN_FILES || mode == MODE_OPEN_DIR || mode == MODE_OPEN_ANY)
+ if (mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES || mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY)
file->set_text("");
call_deferred("_update_file_list");
call_deferred("_update_dir");
@@ -425,8 +429,8 @@ void FileDialog::update_file_list() {
dir_access->list_dir_begin();
TreeItem *root = tree->create_item();
- Ref<Texture2D> folder = get_icon("folder");
- const Color folder_color = get_color("folder_icon_modulate");
+ Ref<Texture2D> folder = vbox->get_theme_icon("folder", "FileDialog");
+ const Color folder_color = vbox->get_theme_color("folder_icon_modulate", "FileDialog");
List<String> files;
List<String> dirs;
@@ -523,8 +527,8 @@ void FileDialog::update_file_list() {
ti->set_icon(0, icon);
}
- if (mode == MODE_OPEN_DIR) {
- ti->set_custom_color(0, get_color("files_disabled"));
+ if (mode == FILE_MODE_OPEN_DIR) {
+ ti->set_custom_color(0, vbox->get_theme_color("files_disabled", "FileDialog"));
ti->set_selectable(0, false);
}
Dictionary d;
@@ -539,7 +543,7 @@ void FileDialog::update_file_list() {
files.pop_front();
}
- if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == NULL)
+ if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == nullptr)
tree->get_root()->get_children()->select(0);
}
@@ -661,38 +665,38 @@ bool FileDialog::is_mode_overriding_title() const {
return mode_overrides_title;
}
-void FileDialog::set_mode(Mode p_mode) {
+void FileDialog::set_file_mode(FileMode p_mode) {
ERR_FAIL_INDEX((int)p_mode, 5);
mode = p_mode;
switch (mode) {
- case MODE_OPEN_FILE:
+ case FILE_MODE_OPEN_FILE:
get_ok()->set_text(RTR("Open"));
if (mode_overrides_title)
set_title(RTR("Open a File"));
makedir->hide();
break;
- case MODE_OPEN_FILES:
+ case FILE_MODE_OPEN_FILES:
get_ok()->set_text(RTR("Open"));
if (mode_overrides_title)
set_title(RTR("Open File(s)"));
makedir->hide();
break;
- case MODE_OPEN_DIR:
+ case FILE_MODE_OPEN_DIR:
get_ok()->set_text(RTR("Select Current Folder"));
if (mode_overrides_title)
set_title(RTR("Open a Directory"));
makedir->show();
break;
- case MODE_OPEN_ANY:
+ case FILE_MODE_OPEN_ANY:
get_ok()->set_text(RTR("Open"));
if (mode_overrides_title)
set_title(RTR("Open a File or Directory"));
makedir->show();
break;
- case MODE_SAVE_FILE:
+ case FILE_MODE_SAVE_FILE:
get_ok()->set_text(RTR("Save"));
if (mode_overrides_title)
set_title(RTR("Save a File"));
@@ -700,14 +704,14 @@ void FileDialog::set_mode(Mode p_mode) {
break;
}
- if (mode == MODE_OPEN_FILES) {
+ if (mode == FILE_MODE_OPEN_FILES) {
tree->set_select_mode(Tree::SELECT_MULTI);
} else {
tree->set_select_mode(Tree::SELECT_SINGLE);
}
}
-FileDialog::Mode FileDialog::get_mode() const {
+FileDialog::FileMode FileDialog::get_file_mode() const {
return mode;
}
@@ -741,7 +745,7 @@ void FileDialog::set_access(Access p_access) {
void FileDialog::invalidate() {
- if (is_visible_in_tree()) {
+ if (is_visible()) {
update_file_list();
invalidated = false;
} else {
@@ -763,14 +767,14 @@ void FileDialog::_make_dir_confirm() {
update_filters();
update_dir();
} else {
- mkdirerr->popup_centered_minsize(Size2(250, 50));
+ mkdirerr->popup_centered(Size2(250, 50));
}
makedirname->set_text(""); // reset label
}
void FileDialog::_make_dir() {
- makedialog->popup_centered_minsize(Size2(250, 80));
+ makedialog->popup_centered(Size2(250, 80));
makedirname->grab_focus();
}
@@ -826,8 +830,8 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_path", "path"), &FileDialog::set_current_path);
ClassDB::bind_method(D_METHOD("set_mode_overrides_title", "override"), &FileDialog::set_mode_overrides_title);
ClassDB::bind_method(D_METHOD("is_mode_overriding_title"), &FileDialog::is_mode_overriding_title);
- ClassDB::bind_method(D_METHOD("set_mode", "mode"), &FileDialog::set_mode);
- ClassDB::bind_method(D_METHOD("get_mode"), &FileDialog::get_mode);
+ ClassDB::bind_method(D_METHOD("set_file_mode", "mode"), &FileDialog::set_file_mode);
+ ClassDB::bind_method(D_METHOD("get_file_mode"), &FileDialog::get_file_mode);
ClassDB::bind_method(D_METHOD("get_vbox"), &FileDialog::get_vbox);
ClassDB::bind_method(D_METHOD("get_line_edit"), &FileDialog::get_line_edit);
ClassDB::bind_method(D_METHOD("set_access", "access"), &FileDialog::set_access);
@@ -842,7 +846,7 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "file_mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_file_mode", "get_file_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
@@ -854,11 +858,11 @@ void FileDialog::_bind_methods() {
ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths")));
ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir")));
- BIND_ENUM_CONSTANT(MODE_OPEN_FILE);
- BIND_ENUM_CONSTANT(MODE_OPEN_FILES);
- BIND_ENUM_CONSTANT(MODE_OPEN_DIR);
- BIND_ENUM_CONSTANT(MODE_OPEN_ANY);
- BIND_ENUM_CONSTANT(MODE_SAVE_FILE);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILE);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILES);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_DIR);
+ BIND_ENUM_CONSTANT(FILE_MODE_OPEN_ANY);
+ BIND_ENUM_CONSTANT(FILE_MODE_SAVE_FILE);
BIND_ENUM_CONSTANT(ACCESS_RESOURCES);
BIND_ENUM_CONSTANT(ACCESS_USERDATA);
@@ -884,10 +888,11 @@ FileDialog::FileDialog() {
mode_overrides_title = true;
- VBoxContainer *vbc = memnew(VBoxContainer);
- add_child(vbc);
+ vbox = memnew(VBoxContainer);
+ add_child(vbox);
+ vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed));
- mode = MODE_SAVE_FILE;
+ mode = FILE_MODE_SAVE_FILE;
set_title(RTR("Save a File"));
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -904,10 +909,11 @@ FileDialog::FileDialog() {
drives = memnew(OptionButton);
drives->connect("item_selected", callable_mp(this, &FileDialog::_select_drive));
+ hbc->add_child(drives);
dir = memnew(LineEdit);
hbc->add_child(dir);
- dir->set_h_size_flags(SIZE_EXPAND_FILL);
+ dir->set_h_size_flags(Control::SIZE_EXPAND_FILL);
refresh = memnew(ToolButton);
refresh->set_tooltip(RTR("Refresh files."));
@@ -928,24 +934,24 @@ FileDialog::FileDialog() {
makedir->set_text(RTR("Create Folder"));
makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir));
hbc->add_child(makedir);
- vbc->add_child(hbc);
+ vbox->add_child(hbc);
tree = memnew(Tree);
tree->set_hide_root(true);
- vbc->add_margin_child(RTR("Directories & Files:"), tree, true);
+ vbox->add_margin_child(RTR("Directories & Files:"), tree, true);
file_box = memnew(HBoxContainer);
file_box->add_child(memnew(Label(RTR("File:"))));
file = memnew(LineEdit);
file->set_stretch_ratio(4);
- file->set_h_size_flags(SIZE_EXPAND_FILL);
+ file->set_h_size_flags(Control::SIZE_EXPAND_FILL);
file_box->add_child(file);
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);
- filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->set_clip_text(true); // too many extensions overflows it
file_box->add_child(filter);
- vbc->add_child(file_box);
+ vbox->add_child(file_box);
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
access = ACCESS_RESOURCES;
@@ -961,7 +967,7 @@ FileDialog::FileDialog() {
filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected));
confirm_save = memnew(ConfirmationDialog);
- confirm_save->set_as_toplevel(true);
+ // confirm_save->set_as_toplevel(true);
add_child(confirm_save);
confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed));
@@ -988,7 +994,6 @@ FileDialog::FileDialog() {
update_dir();
set_hide_on_ok(false);
- vbox = vbc;
invalidated = true;
if (register_func)
@@ -1001,37 +1006,3 @@ FileDialog::~FileDialog() {
unregister_func(this);
memdelete(dir_access);
}
-
-void LineEditFileChooser::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_button"), &LineEditFileChooser::get_button);
- ClassDB::bind_method(D_METHOD("get_line_edit"), &LineEditFileChooser::get_line_edit);
- ClassDB::bind_method(D_METHOD("get_file_dialog"), &LineEditFileChooser::get_file_dialog);
-}
-
-void LineEditFileChooser::_chosen(const String &p_text) {
-
- line_edit->set_text(p_text);
- line_edit->emit_signal("text_entered", p_text);
-}
-
-void LineEditFileChooser::_browse() {
-
- dialog->popup_centered_ratio();
-}
-
-LineEditFileChooser::LineEditFileChooser() {
-
- line_edit = memnew(LineEdit);
- add_child(line_edit);
- line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- button = memnew(Button);
- button->set_text(" .. ");
- add_child(button);
- button->connect("pressed", callable_mp(this, &LineEditFileChooser::_browse));
- dialog = memnew(FileDialog);
- add_child(dialog);
- dialog->connect("file_selected", callable_mp(this, &LineEditFileChooser::_chosen));
- dialog->connect("dir_selected", callable_mp(this, &LineEditFileChooser::_chosen));
- dialog->connect("files_selected", callable_mp(this, &LineEditFileChooser::_chosen));
-}
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index a7dc101d12..ac0e733abc 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -50,12 +50,12 @@ public:
ACCESS_FILESYSTEM
};
- enum Mode {
- MODE_OPEN_FILE,
- MODE_OPEN_FILES,
- MODE_OPEN_DIR,
- MODE_OPEN_ANY,
- MODE_SAVE_FILE
+ enum FileMode {
+ FILE_MODE_OPEN_FILE,
+ FILE_MODE_OPEN_FILES,
+ FILE_MODE_OPEN_DIR,
+ FILE_MODE_OPEN_ANY,
+ FILE_MODE_SAVE_FILE
};
typedef Ref<Texture2D> (*GetIconFunc)(const String &);
@@ -74,7 +74,7 @@ private:
Access access;
//Button *action;
VBoxContainer *vbox;
- Mode mode;
+ FileMode mode;
LineEdit *dir;
HBoxContainer *drives_container;
HBoxContainer *shortcuts_container;
@@ -131,6 +131,8 @@ private:
virtual void _post_popup();
protected:
+ void _theme_changed();
+
void _notification(int p_what);
static void _bind_methods();
//bind helpers
@@ -153,8 +155,8 @@ public:
void set_mode_overrides_title(bool p_override);
bool is_mode_overriding_title() const;
- void set_mode(Mode p_mode);
- Mode get_mode() const;
+ void set_file_mode(FileMode p_mode);
+ FileMode get_file_mode() const;
VBoxContainer *get_vbox();
LineEdit *get_line_edit() { return file; }
@@ -175,28 +177,7 @@ public:
~FileDialog();
};
-class LineEditFileChooser : public HBoxContainer {
-
- GDCLASS(LineEditFileChooser, HBoxContainer);
- Button *button;
- LineEdit *line_edit;
- FileDialog *dialog;
-
- void _chosen(const String &p_text);
- void _browse();
-
-protected:
- static void _bind_methods();
-
-public:
- Button *get_button() { return button; }
- LineEdit *get_line_edit() { return line_edit; }
- FileDialog *get_file_dialog() { return dialog; }
-
- LineEditFileChooser();
-};
-
-VARIANT_ENUM_CAST(FileDialog::Mode);
+VARIANT_ENUM_CAST(FileDialog::FileMode);
VARIANT_ENUM_CAST(FileDialog::Access);
#endif
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 6345bfe562..88107f754c 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -76,15 +76,15 @@ void GradientEdit::_show_color_picker() {
if (grabbed == -1)
return;
picker->set_pick_color(points[grabbed].color);
- Size2 minsize = popup->get_combined_minimum_size();
+ Size2 minsize = popup->get_contents_minimum_size();
bool show_above = false;
if (get_global_position().y + get_size().y + minsize.y > get_viewport_rect().size.y) {
show_above = true;
}
if (show_above) {
- popup->set_position(get_global_position() - Vector2(0, minsize.y));
+ popup->set_position(get_screen_position() - Vector2(0, minsize.y));
} else {
- popup->set_position(get_global_position() + Vector2(0, get_size().y));
+ popup->set_position(get_screen_position() + Vector2(0, get_size().y));
}
popup->popup();
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 4bc33b220e..0fe65462e4 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -30,7 +30,7 @@
#include "graph_edit.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "scene/gui/box_container.h"
@@ -281,13 +281,13 @@ void GraphEdit::remove_child_notify(Node *p_child) {
void GraphEdit::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal");
- port_grab_distance_vertical = get_constant("port_grab_distance_vertical");
+ port_grab_distance_horizontal = get_theme_constant("port_grab_distance_horizontal");
+ port_grab_distance_vertical = get_theme_constant("port_grab_distance_vertical");
- zoom_minus->set_icon(get_icon("minus"));
- zoom_reset->set_icon(get_icon("reset"));
- zoom_plus->set_icon(get_icon("more"));
- snap_button->set_icon(get_icon("snap"));
+ zoom_minus->set_icon(get_theme_icon("minus"));
+ zoom_reset->set_icon(get_theme_icon("reset"));
+ zoom_plus->set_icon(get_theme_icon("more"));
+ snap_button->set_icon(get_theme_icon("snap"));
}
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -305,7 +305,7 @@ void GraphEdit::_notification(int p_what) {
}
if (p_what == NOTIFICATION_DRAW) {
- draw_style_box(get_stylebox("bg"), Rect2(Point2(), get_size()));
+ draw_style_box(get_theme_stylebox("bg"), Rect2(Point2(), get_size()));
if (is_using_snap()) {
//draw grid
@@ -318,8 +318,8 @@ void GraphEdit::_notification(int p_what) {
Point2i from = (offset / float(snap)).floor();
Point2i len = (size / float(snap)).floor() + Vector2(1, 1);
- Color grid_minor = get_color("grid_minor");
- Color grid_major = get_color("grid_major");
+ Color grid_minor = get_theme_color("grid_minor");
+ Color grid_major = get_theme_color("grid_major");
for (int i = from.x; i < from.x + len.x; i++) {
@@ -357,7 +357,7 @@ void GraphEdit::_notification(int p_what) {
bool GraphEdit::_filter_input(const Point2 &p_point) {
- Ref<Texture2D> port = get_icon("port", "GraphNode");
+ Ref<Texture2D> port = get_theme_icon("port", "GraphNode");
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -389,7 +389,7 @@ 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()) {
- Ref<Texture2D> port = get_icon("port", "GraphNode");
+ Ref<Texture2D> port = get_theme_icon("port", "GraphNode");
Vector2 mpos(mb->get_position().x, mb->get_position().y);
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -501,7 +501,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_target = false;
top_layer->update();
- Ref<Texture2D> port = get_icon("port", "GraphNode");
+ Ref<Texture2D> port = get_theme_icon("port", "GraphNode");
Vector2 mpos = mm->get_position();
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -666,8 +666,8 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const
//cubic bezier code
float diff = p_to.x - p_from.x;
float cp_offset;
- int cp_len = get_constant("bezier_len_pos");
- int cp_neg_len = get_constant("bezier_len_neg");
+ int cp_len = get_theme_constant("bezier_len_pos");
+ int cp_neg_len = get_theme_constant("bezier_len_neg");
if (diff > 0) {
cp_offset = MIN(cp_len, diff * 0.5);
@@ -697,7 +697,7 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const
void GraphEdit::_connections_layer_draw() {
- Color activity_color = get_color("activity");
+ Color activity_color = get_theme_color("activity");
//draw connections
List<List<Connection>::Element *> to_erase;
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
@@ -784,8 +784,8 @@ void GraphEdit::_top_layer_draw() {
}
if (box_selecting) {
- top_layer->draw_rect(box_selecting_rect, get_color("selection_fill"));
- top_layer->draw_rect(box_selecting_rect, get_color("selection_stroke"), false);
+ top_layer->draw_rect(box_selecting_rect, get_theme_color("selection_fill"));
+ top_layer->draw_rect(box_selecting_rect, get_theme_color("selection_stroke"), false);
}
}
@@ -804,7 +804,7 @@ void GraphEdit::set_selected(Node *p_child) {
void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
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() & BUTTON_MASK_MIDDLE || (mm->get_button_mask() & BUTTON_MASK_LEFT && InputFilter::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);
}
@@ -823,7 +823,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
// Snapping can be toggled temporarily by holding down Ctrl.
// This is done here as to not toggle the grid when holding down Ctrl.
- if (is_using_snap() ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (is_using_snap() ^ InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) {
const int snap = get_snap();
pos = pos.snapped(Vector2(snap, snap));
}
@@ -852,9 +852,9 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
bool in_box = r.intersects(box_selecting_rect);
if (in_box)
- gn->set_selected(box_selection_mode_aditive);
+ gn->set_selected(box_selection_mode_additive);
else
- gn->set_selected(previus_selected.find(gn) != NULL);
+ gn->set_selected(previus_selected.find(gn) != nullptr);
}
top_layer->update();
@@ -872,7 +872,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
if (!gn)
continue;
- gn->set_selected(previus_selected.find(gn) != NULL);
+ gn->set_selected(previus_selected.find(gn) != nullptr);
}
top_layer->update();
} else {
@@ -886,7 +886,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && dragging) {
- if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (!just_selected && drag_accum == Vector2() && InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) {
//deselect current node
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -922,7 +922,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
if (b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
- GraphNode *gn = NULL;
+ GraphNode *gn = nullptr;
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -948,11 +948,19 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
drag_accum = Vector2();
drag_origin = get_local_mouse_position();
just_selected = !gn->is_selected();
- if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ if (!gn->is_selected() && !InputFilter::get_singleton()->is_key_pressed(KEY_CONTROL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
- if (o_gn)
- o_gn->set_selected(o_gn == gn);
+ if (o_gn) {
+ if (o_gn == gn) {
+ o_gn->set_selected(true);
+ } else {
+ if (o_gn->is_selected()) {
+ emit_signal("node_unselected", o_gn);
+ }
+ o_gn->set_selected(false);
+ }
+ }
}
}
@@ -968,13 +976,13 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
} else {
if (_filter_input(b->get_position()))
return;
- if (Input::get_singleton()->is_key_pressed(KEY_SPACE))
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_SPACE))
return;
box_selecting = true;
box_selecting_from = get_local_mouse_position();
if (b->get_control()) {
- box_selection_mode_aditive = true;
+ box_selection_mode_additive = true;
previus_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -985,7 +993,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
previus_selected.push_back(gn2);
}
} else if (b->get_shift()) {
- box_selection_mode_aditive = false;
+ box_selection_mode_additive = false;
previus_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -996,14 +1004,16 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
previus_selected.push_back(gn2);
}
} else {
- box_selection_mode_aditive = true;
+ box_selection_mode_additive = true;
previus_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2)
continue;
-
+ if (gn2->is_selected()) {
+ emit_signal("node_unselected", gn2);
+ }
gn2->set_selected(false);
}
}
@@ -1025,16 +1035,16 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
//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() == BUTTON_WHEEL_UP && !InputFilter::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)) {
+ if (b->get_button_index() == BUTTON_WHEEL_DOWN && !InputFilter::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))) {
+ if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && InputFilter::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))) {
+ if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && InputFilter::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8);
}
}
@@ -1311,6 +1321,7 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("copy_nodes_request"));
ADD_SIGNAL(MethodInfo("paste_nodes_request"));
ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("node_unselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("delete_nodes_request"));
@@ -1323,7 +1334,7 @@ GraphEdit::GraphEdit() {
set_focus_mode(FOCUS_ALL);
awaiting_scroll_offset_update = false;
- top_layer = NULL;
+ top_layer = nullptr;
top_layer = memnew(GraphEditFilter(this));
add_child(top_layer);
top_layer->set_mouse_filter(MOUSE_FILTER_PASS);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 7f1d2699ba..f675f8c7f3 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -104,7 +104,7 @@ private:
float zoom;
bool box_selecting;
- bool box_selection_mode_aditive;
+ bool box_selection_mode_additive;
Point2 box_selecting_from;
Point2 box_selecting_to;
Rect2 box_selecting_rect;
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 82e890395a..5dbc5bc50d 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -117,8 +117,8 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
void GraphNode::_resort() {
- int sep = get_constant("separation");
- Ref<StyleBox> sb = get_stylebox("frame");
+ int sep = get_theme_constant("separation");
+ Ref<StyleBox> sb = get_theme_stylebox("frame");
bool first = true;
Size2 minsize;
@@ -169,8 +169,8 @@ void GraphNode::_resort() {
bool GraphNode::has_point(const Point2 &p_point) const {
if (comment) {
- Ref<StyleBox> comment = get_stylebox("comment");
- Ref<Texture2D> resizer = get_icon("resizer");
+ Ref<StyleBox> comment = get_theme_stylebox("comment");
+ Ref<Texture2D> resizer = get_theme_icon("resizer");
if (Rect2(get_size() - resizer->get_size(), resizer->get_size()).has_point(p_point)) {
return true;
@@ -195,28 +195,28 @@ void GraphNode::_notification(int p_what) {
Ref<StyleBox> sb;
if (comment) {
- sb = get_stylebox(selected ? "commentfocus" : "comment");
+ sb = get_theme_stylebox(selected ? "commentfocus" : "comment");
} else {
- sb = get_stylebox(selected ? "selectedframe" : "frame");
+ sb = get_theme_stylebox(selected ? "selectedframe" : "frame");
}
//sb=sb->duplicate();
//sb->call("set_modulate",modulate);
- Ref<Texture2D> port = get_icon("port");
- Ref<Texture2D> close = get_icon("close");
- Ref<Texture2D> resizer = get_icon("resizer");
- int close_offset = get_constant("close_offset");
- int close_h_offset = get_constant("close_h_offset");
- Color close_color = get_color("close_color");
- Color resizer_color = get_color("resizer_color");
- Ref<Font> title_font = get_font("title_font");
- int title_offset = get_constant("title_offset");
- int title_h_offset = get_constant("title_h_offset");
- Color title_color = get_color("title_color");
+ Ref<Texture2D> port = get_theme_icon("port");
+ Ref<Texture2D> close = get_theme_icon("close");
+ Ref<Texture2D> resizer = get_theme_icon("resizer");
+ int close_offset = get_theme_constant("close_offset");
+ int close_h_offset = get_theme_constant("close_h_offset");
+ Color close_color = get_theme_color("close_color");
+ Color resizer_color = get_theme_color("resizer_color");
+ Ref<Font> title_font = get_theme_font("title_font");
+ int title_offset = get_theme_constant("title_offset");
+ int title_h_offset = get_theme_constant("title_h_offset");
+ Color title_color = get_theme_color("title_color");
Point2i icofs = -port->get_size() * 0.5;
- int edgeofs = get_constant("port_offset");
+ int edgeofs = get_theme_constant("port_offset");
icofs.y += sb->get_margin(MARGIN_TOP);
draw_style_box(sb, Rect2(Point2(), get_size()));
@@ -227,10 +227,10 @@ void GraphNode::_notification(int p_what) {
} break;
case OVERLAY_BREAKPOINT: {
- draw_style_box(get_stylebox("breakpoint"), Rect2(Point2(), get_size()));
+ draw_style_box(get_theme_stylebox("breakpoint"), Rect2(Point2(), get_size()));
} break;
case OVERLAY_POSITION: {
- draw_style_box(get_stylebox("position"), Rect2(Point2(), get_size()));
+ draw_style_box(get_theme_stylebox("position"), Rect2(Point2(), get_size()));
} break;
}
@@ -370,16 +370,16 @@ Color GraphNode::get_slot_color_right(int p_idx) const {
Size2 GraphNode::get_minimum_size() const {
- Ref<Font> title_font = get_font("title_font");
+ Ref<Font> title_font = get_theme_font("title_font");
- int sep = get_constant("separation");
- Ref<StyleBox> sb = get_stylebox("frame");
+ int sep = get_theme_constant("separation");
+ Ref<StyleBox> sb = get_theme_stylebox("frame");
bool first = true;
Size2 minsize;
minsize.x = title_font->get_string_size(title).x;
if (show_close) {
- Ref<Texture2D> close = get_icon("close");
+ Ref<Texture2D> close = get_theme_icon("close");
minsize.x += sep + close->get_width();
}
@@ -464,10 +464,10 @@ bool GraphNode::is_close_button_visible() const {
void GraphNode::_connpos_update() {
- int edgeofs = get_constant("port_offset");
- int sep = get_constant("separation");
+ int edgeofs = get_theme_constant("port_offset");
+ int sep = get_theme_constant("separation");
- Ref<StyleBox> sb = get_stylebox("frame");
+ Ref<StyleBox> sb = get_theme_stylebox("frame");
conn_input_cache.clear();
conn_output_cache.clear();
int vofs = 0;
@@ -593,7 +593,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
- ERR_FAIL_COND_MSG(get_parent_control() == NULL, "GraphNode must be the child of a GraphEdit node.");
+ 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) {
@@ -606,7 +606,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
return;
}
- Ref<Texture2D> resizer = get_icon("resizer");
+ Ref<Texture2D> resizer = get_theme_icon("resizer");
if (resizable && mpos.x > get_size().x - resizer->get_width() && mpos.y > get_size().y - resizer->get_height()) {
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 0028093a95..16f6fd0111 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -41,8 +41,8 @@ void GridContainer::_notification(int p_what) {
Set<int> col_expanded; // Columns which have the SIZE_EXPAND flag set.
Set<int> row_expanded; // Rows which have the SIZE_EXPAND flag set.
- int hsep = get_constant("hseparation");
- int vsep = get_constant("vseparation");
+ int hsep = get_theme_constant("hseparation");
+ int vsep = get_theme_constant("vseparation");
int max_col = MIN(get_child_count(), columns);
int max_row = ceil((float)get_child_count() / (float)columns);
@@ -200,8 +200,8 @@ Size2 GridContainer::get_minimum_size() const {
Map<int, int> col_minw;
Map<int, int> row_minh;
- int hsep = get_constant("hseparation");
- int vsep = get_constant("vseparation");
+ int hsep = get_theme_constant("hseparation");
+ int vsep = get_theme_constant("vseparation");
int max_row = 0;
int max_col = 0;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 5e662b8df0..47a5ac68d2 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -495,7 +495,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
search_string = ""; //any mousepress cancels
Vector2 pos = mb->get_position();
- Ref<StyleBox> bg = get_stylebox("bg");
+ Ref<StyleBox> bg = get_theme_stylebox("bg");
pos -= bg->get_offset();
pos.y += scroll_bar->get_value();
@@ -820,7 +820,7 @@ void ItemList::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<StyleBox> bg = get_stylebox("bg");
+ Ref<StyleBox> bg = get_theme_stylebox("bg");
int mw = scroll_bar->get_minimum_size().x;
scroll_bar->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -mw);
@@ -837,18 +837,18 @@ void ItemList::_notification(int p_what) {
draw_style_box(bg, Rect2(Point2(), size));
- int hseparation = get_constant("hseparation");
- int vseparation = get_constant("vseparation");
- int icon_margin = get_constant("icon_margin");
- int line_separation = get_constant("line_separation");
+ int hseparation = get_theme_constant("hseparation");
+ int vseparation = get_theme_constant("vseparation");
+ int icon_margin = get_theme_constant("icon_margin");
+ int line_separation = get_theme_constant("line_separation");
- Ref<StyleBox> sbsel = has_focus() ? get_stylebox("selected_focus") : get_stylebox("selected");
- Ref<StyleBox> cursor = has_focus() ? get_stylebox("cursor") : get_stylebox("cursor_unfocused");
+ 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");
- Ref<Font> font = get_font("font");
- Color guide_color = get_color("guide_color");
- Color font_color = get_color("font_color");
- Color font_color_selected = get_color("font_color_selected");
+ Ref<Font> font = get_theme_font("font");
+ Color guide_color = get_theme_color("guide_color");
+ Color font_color = get_theme_color("font_color");
+ Color font_color_selected = get_theme_color("font_color_selected");
int font_height = font->get_height();
Vector<int> line_size_cache;
Vector<int> line_limit_cache;
@@ -859,9 +859,9 @@ void ItemList::_notification(int p_what) {
}
if (has_focus()) {
- VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
- draw_style_box(get_stylebox("bg_focus"), Rect2(Point2(), size));
- VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
+ draw_style_box(get_theme_stylebox("bg_focus"), Rect2(Point2(), size));
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
}
if (shape_changed) {
@@ -1251,7 +1251,7 @@ void ItemList::_scroll_changed(double) {
int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
Vector2 pos = p_pos;
- Ref<StyleBox> bg = get_stylebox("bg");
+ Ref<StyleBox> bg = get_theme_stylebox("bg");
pos -= bg->get_offset();
pos.y += scroll_bar->get_value();
@@ -1286,7 +1286,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
return true;
Vector2 pos = p_pos;
- Ref<StyleBox> bg = get_stylebox("bg");
+ Ref<StyleBox> bg = get_theme_stylebox("bg");
pos -= bg->get_offset();
pos.y += scroll_bar->get_value();
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index c900b35d65..bedcef2df2 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -65,7 +65,7 @@ bool Label::is_uppercase() const {
int Label::get_line_height() const {
- return get_font("font")->get_height();
+ return get_theme_font("font")->get_height();
}
void Label::_notification(int p_what) {
@@ -84,7 +84,7 @@ void Label::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
if (clip) {
- VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
+ RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
}
if (word_cache_dirty)
@@ -94,18 +94,18 @@ void Label::_notification(int p_what) {
Size2 string_size;
Size2 size = get_size();
- Ref<StyleBox> style = get_stylebox("normal");
- Ref<Font> font = get_font("font");
- Color font_color = get_color("font_color");
- Color font_color_shadow = get_color("font_color_shadow");
- bool use_outline = get_constant("shadow_as_outline");
- Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
- int line_spacing = get_constant("line_spacing");
- Color font_outline_modulate = get_color("font_outline_modulate");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
+ Ref<Font> font = get_theme_font("font");
+ Color font_color = get_theme_color("font_color");
+ Color font_color_shadow = get_theme_color("font_color_shadow");
+ bool use_outline = get_theme_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
+ int line_spacing = get_theme_constant("line_spacing");
+ Color font_outline_modulate = get_theme_color("font_outline_modulate");
style->draw(ci, Rect2(Point2(0, 0), get_size()));
- VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(), font.is_valid() && font->is_distance_field_hint());
+ RenderingServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(), font.is_valid() && font->is_distance_field_hint());
int font_h = font->get_height() + line_spacing;
@@ -282,7 +282,7 @@ void Label::_notification(int p_what) {
from = from->next;
}
- wc = to ? to->next : 0;
+ wc = to ? to->next : nullptr;
line++;
}
}
@@ -300,7 +300,7 @@ void Label::_notification(int p_what) {
Size2 Label::get_minimum_size() const {
- Size2 min_style = get_stylebox("normal")->get_minimum_size();
+ Size2 min_style = get_theme_stylebox("normal")->get_minimum_size();
// don't want to mutable everything
if (word_cache_dirty) {
@@ -319,7 +319,7 @@ Size2 Label::get_minimum_size() const {
int Label::get_longest_line_width() const {
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
real_t max_line_width = 0;
real_t line_width = 0;
@@ -363,9 +363,9 @@ int Label::get_line_count() const {
int Label::get_visible_line_count() const {
- int line_spacing = get_constant("line_spacing");
- int font_h = get_font("font")->get_height() + line_spacing;
- int lines_visible = (get_size().height - get_stylebox("normal")->get_minimum_size().height + line_spacing) / font_h;
+ int line_spacing = get_theme_constant("line_spacing");
+ int font_h = get_theme_font("font")->get_height() + line_spacing;
+ int lines_visible = (get_size().height - get_theme_stylebox("normal")->get_minimum_size().height + line_spacing) / font_h;
if (lines_visible > line_count)
lines_visible = line_count;
@@ -387,24 +387,24 @@ void Label::regenerate_word_cache() {
int width;
if (autowrap) {
- Ref<StyleBox> style = get_stylebox("normal");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
width = MAX(get_size().width, get_custom_minimum_size().width) - style->get_minimum_size().width;
} else {
width = get_longest_line_width();
}
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
real_t current_word_size = 0;
int word_pos = 0;
real_t line_width = 0;
int space_count = 0;
real_t space_width = font->get_char_size(' ').width;
- int line_spacing = get_constant("line_spacing");
+ int line_spacing = get_theme_constant("line_spacing");
line_count = 1;
total_char_cache = 0;
- WordCache *last = NULL;
+ WordCache *last = nullptr;
for (int i = 0; i <= xl_text.length(); i++) {
@@ -447,7 +447,7 @@ void Label::regenerate_word_cache() {
}
if (i < xl_text.length() && xl_text[i] == ' ') {
- if (line_width > 0 || last == NULL || last->char_pos != WordCache::CHAR_WRAPLINE) {
+ if (line_width > 0 || last == nullptr || last->char_pos != WordCache::CHAR_WRAPLINE) {
space_count++;
line_width += space_width;
} else {
@@ -697,7 +697,7 @@ Label::Label(const String &p_text) {
align = ALIGN_LEFT;
valign = VALIGN_TOP;
xl_text = "";
- word_cache = NULL;
+ word_cache = nullptr;
word_cache_dirty = true;
autowrap = false;
line_count = 0;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index fdddf0b5fa..b9b7560f2e 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -36,12 +36,12 @@
#include "core/print_string.h"
#include "core/translation.h"
#include "label.h"
-
+#include "servers/display_server.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#endif
-
+#include "scene/main/window.h"
static bool _is_text_char(CharType c) {
return !is_symbol(c);
@@ -56,7 +56,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
- menu->set_scale(get_global_transform().get_scale());
+ //menu->set_scale(get_global_transform().get_scale());
menu->popup();
grab_focus();
accept_event();
@@ -127,8 +127,8 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.creating = false;
selection.doubleclick = false;
- if (OS::get_singleton()->has_virtual_keyboard())
- OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD))
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length);
}
update();
@@ -304,10 +304,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
case KEY_ENTER: {
emit_signal("text_entered", text);
- if (OS::get_singleton()->has_virtual_keyboard())
- OS::get_singleton()->hide_virtual_keyboard();
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD))
+ DisplayServer::get_singleton()->virtual_keyboard_hide();
- return;
} break;
case KEY_BACKSPACE: {
@@ -553,10 +552,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
case KEY_MENU: {
if (context_menu_enabled) {
- Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_font("font")->get_height()) / 2);
+ Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_theme_font("font")->get_height()) / 2);
menu->set_position(get_global_transform().xform(pos));
menu->set_size(Vector2(1, 1));
- menu->set_scale(get_global_transform().get_scale());
+ // menu->set_scale(get_global_transform().get_scale());
menu->popup();
menu->grab_focus();
}
@@ -630,10 +629,10 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
set_cursor_at_pixel_pos(p_point.x);
int selected = selection.end - selection.begin;
- Ref<Font> font = get_font("font");
- if (font != NULL) {
+ Ref<Font> font = get_theme_font("font");
+ if (font != nullptr) {
for (int i = selection.begin; i < selection.end; i++)
- cached_width -= font->get_char_size(text[i]).width;
+ cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width;
}
text.erase(selection.begin, selected);
@@ -655,8 +654,8 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const {
if (!clear_button_enabled || !has_point(p_pos)) {
return false;
}
- Ref<Texture2D> icon = Control::get_icon("clear");
- int x_ofs = get_stylebox("normal")->get_offset().x;
+ Ref<Texture2D> icon = Control::get_theme_icon("clear");
+ int x_ofs = get_theme_stylebox("normal")->get_offset().x;
return p_pos.x > get_size().width - icon->get_width() - x_ofs;
}
@@ -686,12 +685,12 @@ void LineEdit::_notification(int p_what) {
update_placeholder_width();
update();
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_FOCUS_IN: {
window_has_focus = true;
draw_caret = true;
update();
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_WM_FOCUS_OUT: {
window_has_focus = false;
draw_caret = false;
update();
@@ -710,19 +709,19 @@ void LineEdit::_notification(int p_what) {
RID ci = get_canvas_item();
- Ref<StyleBox> style = get_stylebox("normal");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
if (!is_editable()) {
- style = get_stylebox("read_only");
+ style = get_theme_stylebox("read_only");
draw_caret = false;
}
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
style->draw(ci, Rect2(Point2(), size));
if (has_focus()) {
- get_stylebox("focus")->draw(ci, Rect2(Point2(), size));
+ get_theme_stylebox("focus")->draw(ci, Rect2(Point2(), size));
}
int x_ofs = 0;
@@ -757,10 +756,10 @@ void LineEdit::_notification(int p_what) {
int font_ascent = font->get_ascent();
- Color selection_color = get_color("selection_color");
- Color font_color = is_editable() ? get_color("font_color") : get_color("font_color_uneditable");
- Color font_color_selected = get_color("font_color_selected");
- Color cursor_color = get_color("cursor_color");
+ Color selection_color = get_theme_color("selection_color");
+ Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_color_uneditable");
+ Color font_color_selected = get_theme_color("font_color_selected");
+ Color cursor_color = get_theme_color("cursor_color");
const String &t = using_placeholder ? placeholder_translated : text;
// Draw placeholder color.
@@ -769,13 +768,13 @@ void LineEdit::_notification(int p_what) {
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9);
if (display_clear_icon) {
if (clear_button_status.press_attempt && clear_button_status.pressing_inside) {
- color_icon = get_color("clear_button_color_pressed");
+ color_icon = get_theme_color("clear_button_color_pressed");
} else {
- color_icon = get_color("clear_button_color");
+ color_icon = get_theme_color("clear_button_color");
}
}
@@ -816,9 +815,9 @@ void LineEdit::_notification(int p_what) {
bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
if (selected) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 3)), font_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 3)), font_color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 1)), font_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 1)), font_color);
}
drawer.draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, font_color);
@@ -840,7 +839,7 @@ void LineEdit::_notification(int p_what) {
bool selected = selection.enabled && char_ofs >= selection.begin && char_ofs < selection.end;
if (selected)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, caret_height)), selection_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, caret_height)), selection_color);
int yofs = y_ofs + (caret_height - font->get_height()) / 2;
drawer.draw_char(ci, Point2(x_ofs, yofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
@@ -848,9 +847,9 @@ void LineEdit::_notification(int p_what) {
if (char_ofs == cursor_pos && draw_caret && !using_placeholder) {
if (ime_text.length() == 0) {
#ifdef TOOLS_ENABLED
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
#else
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(1, caret_height)), cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(1, caret_height)), cursor_color);
#endif
}
}
@@ -875,9 +874,9 @@ void LineEdit::_notification(int p_what) {
bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
if (selected) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 3)), font_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 3)), font_color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 1)), font_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 1)), font_color);
}
drawer.draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, font_color);
@@ -906,17 +905,18 @@ void LineEdit::_notification(int p_what) {
}
}
#ifdef TOOLS_ENABLED
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(caret_x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(caret_x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
#else
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(caret_x_ofs, y_ofs), Size2(1, caret_height)), cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(caret_x_ofs, y_ofs), Size2(1, caret_height)), cursor_color);
#endif
}
}
if (has_focus()) {
-
- OS::get_singleton()->set_ime_active(true);
- OS::get_singleton()->set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + caret_height));
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ 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 + caret_height), get_viewport()->get_window_id());
+ }
}
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -927,12 +927,14 @@ void LineEdit::_notification(int p_what) {
draw_caret = true;
}
- OS::get_singleton()->set_ime_active(true);
- Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height;
- OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos);
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ 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());
+ }
- if (OS::get_singleton()->has_virtual_keyboard())
- OS::get_singleton()->show_virtual_keyboard(text, get_global_rect(), max_length);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD))
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length);
} break;
case NOTIFICATION_FOCUS_EXIT: {
@@ -941,20 +943,22 @@ void LineEdit::_notification(int p_what) {
caret_blink_timer->stop();
}
- OS::get_singleton()->set_ime_position(Point2());
- OS::get_singleton()->set_ime_active(false);
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ 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();
- if (OS::get_singleton()->has_virtual_keyboard())
- OS::get_singleton()->hide_virtual_keyboard();
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD))
+ DisplayServer::get_singleton()->virtual_keyboard_hide();
} break;
case MainLoop::NOTIFICATION_OS_IME_UPDATE: {
if (has_focus()) {
- ime_text = OS::get_singleton()->get_ime_text();
- ime_selection = OS::get_singleton()->get_ime_selection();
+ ime_text = DisplayServer::get_singleton()->ime_get_text();
+ ime_selection = DisplayServer::get_singleton()->ime_get_selection();
update();
}
} break;
@@ -964,14 +968,14 @@ void LineEdit::_notification(int p_what) {
void LineEdit::copy_text() {
if (selection.enabled && !pass) {
- OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
+ DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin));
}
}
void LineEdit::cut_text() {
if (selection.enabled && !pass) {
- OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
+ DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin));
selection_delete();
}
}
@@ -979,7 +983,7 @@ void LineEdit::cut_text() {
void LineEdit::paste_text() {
// Strip escape characters like \n and \t as they can't be displayed on LineEdit.
- String paste_buffer = OS::get_singleton()->get_clipboard().strip_escapes();
+ String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes();
if (paste_buffer != "") {
@@ -997,7 +1001,7 @@ void LineEdit::paste_text() {
}
void LineEdit::undo() {
- if (undo_stack_pos == NULL) {
+ if (undo_stack_pos == nullptr) {
if (undo_stack.size() <= 1) {
return;
}
@@ -1019,7 +1023,7 @@ void LineEdit::undo() {
}
void LineEdit::redo() {
- if (undo_stack_pos == NULL) {
+ if (undo_stack_pos == nullptr) {
return;
}
if (undo_stack_pos == undo_stack.back()) {
@@ -1055,13 +1059,13 @@ void LineEdit::shift_selection_check_post(bool p_shift) {
void LineEdit::set_cursor_at_pixel_pos(int p_x) {
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
int ofs = window_pos;
- Ref<StyleBox> style = get_stylebox("normal");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
int pixel_ofs = 0;
Size2 size = get_size();
bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
- int r_icon_width = Control::get_icon("clear")->get_width();
+ int r_icon_width = Control::get_theme_icon("clear")->get_width();
switch (align) {
@@ -1092,8 +1096,8 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
while (ofs < text.length()) {
int char_w = 0;
- if (font != NULL) {
- char_w = font->get_char_size(text[ofs]).width;
+ if (font != nullptr) {
+ char_w = font->get_char_size(pass ? secret_character[0] : text[ofs]).width;
}
pixel_ofs += char_w;
@@ -1109,13 +1113,13 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
int LineEdit::get_cursor_pixel_pos() {
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
int ofs = window_pos;
- Ref<StyleBox> style = get_stylebox("normal");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
int pixel_ofs = 0;
Size2 size = get_size();
bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
- int r_icon_width = Control::get_icon("clear")->get_width();
+ int r_icon_width = Control::get_theme_icon("clear")->get_width();
switch (align) {
@@ -1144,8 +1148,8 @@ int LineEdit::get_cursor_pixel_pos() {
}
while (ofs < cursor_pos) {
- if (font != NULL) {
- pixel_ofs += font->get_char_size(text[ofs]).width;
+ if (font != nullptr) {
+ pixel_ofs += font->get_char_size(pass ? secret_character[0] : text[ofs]).width;
}
ofs++;
}
@@ -1202,9 +1206,9 @@ void LineEdit::delete_char() {
if ((text.length() <= 0) || (cursor_pos == 0)) return;
- Ref<Font> font = get_font("font");
- if (font != NULL) {
- cached_width -= font->get_char_size(text[cursor_pos - 1]).width;
+ Ref<Font> font = get_theme_font("font");
+ if (font != nullptr) {
+ cached_width -= font->get_char_size(pass ? secret_character[0] : text[cursor_pos - 1]).width;
}
text.erase(cursor_pos - 1, 1);
@@ -1221,10 +1225,10 @@ void LineEdit::delete_char() {
void LineEdit::delete_text(int p_from_column, int p_to_column) {
if (text.size() > 0) {
- Ref<Font> font = get_font("font");
- if (font != NULL) {
+ Ref<Font> font = get_theme_font("font");
+ if (font != nullptr) {
for (int i = p_from_column; i < p_to_column; i++)
- cached_width -= font->get_char_size(text[i]).width;
+ cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width;
}
} else {
cached_width = 0;
@@ -1319,8 +1323,8 @@ void LineEdit::set_cursor_position(int p_pos) {
return;
}
- Ref<StyleBox> style = get_stylebox("normal");
- Ref<Font> font = get_font("font");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
+ Ref<Font> font = get_theme_font("font");
if (cursor_pos <= window_pos) {
// Adjust window if cursor goes too much to the left.
@@ -1330,7 +1334,7 @@ void LineEdit::set_cursor_position(int p_pos) {
int window_width = get_size().width - style->get_minimum_size().width;
bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
- Ref<Texture2D> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon;
+ Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
window_width -= r_icon->get_width();
}
@@ -1348,7 +1352,11 @@ void LineEdit::set_cursor_position(int p_pos) {
// Do not do this, because if the cursor is at the end, its just fine that it takes no space.
// accum_width = font->get_char_size(' ').width;
} else {
- accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; // Anything should do.
+ if (pass) {
+ accum_width += font->get_char_size(secret_character[0], i + 1 < text.length() ? secret_character[0] : 0).width;
+ } else {
+ accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; // Anything should do.
+ }
}
if (accum_width > window_width)
break;
@@ -1401,14 +1409,14 @@ void LineEdit::clear_internal() {
Size2 LineEdit::get_minimum_size() const {
- Ref<StyleBox> style = get_stylebox("normal");
- Ref<Font> font = get_font("font");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
+ Ref<Font> font = get_theme_font("font");
Size2 min_size;
// Minimum size of text.
int space_size = font->get_char_size(' ').x;
- min_size.width = get_constant("minimum_spaces") * space_size;
+ min_size.width = get_theme_constant("minimum_spaces") * 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.
@@ -1419,8 +1427,8 @@ Size2 LineEdit::get_minimum_size() const {
// Take icons into account.
if (!text.empty() && is_editable() && clear_button_enabled) {
- min_size.width = MAX(min_size.width, Control::get_icon("clear")->get_width());
- min_size.height = MAX(min_size.height, Control::get_icon("clear")->get_height());
+ min_size.width = MAX(min_size.width, Control::get_theme_icon("clear")->get_width());
+ min_size.height = MAX(min_size.height, Control::get_theme_icon("clear")->get_height());
}
if (right_icon.is_valid()) {
min_size.width = MAX(min_size.width, right_icon->get_width());
@@ -1699,9 +1707,9 @@ void LineEdit::_emit_text_change() {
}
void LineEdit::update_cached_width() {
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
cached_width = 0;
- if (font != NULL) {
+ if (font != nullptr) {
String text = get_text();
for (int i = 0; i < text.length(); i++) {
cached_width += font->get_char_size(pass ? secret_character[0] : text[i]).width;
@@ -1710,20 +1718,18 @@ void LineEdit::update_cached_width() {
}
void LineEdit::update_placeholder_width() {
- if ((max_length <= 0) || (placeholder_translated.length() <= max_length)) {
- Ref<Font> font = get_font("font");
- cached_placeholder_width = 0;
- if (font != NULL) {
- for (int i = 0; i < placeholder_translated.length(); i++) {
- cached_placeholder_width += font->get_char_size(placeholder_translated[i]).width;
- }
+ Ref<Font> font = get_theme_font("font");
+ cached_placeholder_width = 0;
+ if (font != nullptr) {
+ for (int i = 0; i < placeholder_translated.length(); i++) {
+ cached_placeholder_width += font->get_char_size(placeholder_translated[i]).width;
}
}
}
void LineEdit::_clear_redo() {
_create_undo_state();
- if (undo_stack_pos == NULL) {
+ if (undo_stack_pos == nullptr) {
return;
}
@@ -1738,7 +1744,7 @@ void LineEdit::_clear_redo() {
void LineEdit::_clear_undo_stack() {
undo_stack.clear();
- undo_stack_pos = NULL;
+ undo_stack_pos = nullptr;
_create_undo_state();
}
@@ -1859,7 +1865,7 @@ void LineEdit::_bind_methods() {
LineEdit::LineEdit() {
- undo_stack_pos = NULL;
+ undo_stack_pos = nullptr;
_create_undo_state();
align = ALIGN_LEFT;
cached_width = 0;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 4b8054bac6..3dffa06b49 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -54,7 +54,7 @@ LinkButton::UnderlineMode LinkButton::get_underline_mode() const {
Size2 LinkButton::get_minimum_size() const {
- return get_font("font")->get_string_size(text);
+ return get_theme_font("font")->get_string_size(text);
}
void LinkButton::_notification(int p_what) {
@@ -72,29 +72,29 @@ void LinkButton::_notification(int p_what) {
case DRAW_NORMAL: {
- color = get_color("font_color");
+ color = get_theme_color("font_color");
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
} break;
case DRAW_HOVER_PRESSED:
case DRAW_PRESSED: {
- if (has_color("font_color_pressed"))
- color = get_color("font_color_pressed");
+ if (has_theme_color("font_color_pressed"))
+ color = get_theme_color("font_color_pressed");
else
- color = get_color("font_color");
+ color = get_theme_color("font_color");
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
case DRAW_HOVER: {
- color = get_color("font_color_hover");
+ color = get_theme_color("font_color_hover");
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
case DRAW_DISABLED: {
- color = get_color("font_color_disabled");
+ color = get_theme_color("font_color_disabled");
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
} break;
@@ -102,16 +102,16 @@ void LinkButton::_notification(int p_what) {
if (has_focus()) {
- Ref<StyleBox> style = get_stylebox("focus");
+ Ref<StyleBox> style = get_theme_stylebox("focus");
style->draw(ci, Rect2(Point2(), size));
}
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
draw_string(font, Vector2(0, font->get_ascent()), text, color);
if (do_underline) {
- int underline_spacing = get_constant("underline_spacing");
+ int underline_spacing = get_theme_constant("underline_spacing");
int width = font->get_string_size(text).width;
int y = font->get_ascent() + underline_spacing;
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index 53373fc297..1cd4ff4ff8 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -32,10 +32,10 @@
Size2 MarginContainer::get_minimum_size() const {
- int margin_left = get_constant("margin_left");
- int margin_top = get_constant("margin_top");
- int margin_right = get_constant("margin_right");
- int margin_bottom = get_constant("margin_bottom");
+ int margin_left = get_theme_constant("margin_left");
+ int margin_top = get_theme_constant("margin_top");
+ int margin_right = get_theme_constant("margin_right");
+ int margin_bottom = get_theme_constant("margin_bottom");
Size2 max;
@@ -67,10 +67,10 @@ void MarginContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
- int margin_left = get_constant("margin_left");
- int margin_top = get_constant("margin_top");
- int margin_right = get_constant("margin_right");
- int margin_bottom = get_constant("margin_bottom");
+ int margin_left = get_theme_constant("margin_left");
+ int margin_top = get_theme_constant("margin_top");
+ int margin_right = get_theme_constant("margin_right");
+ int margin_bottom = get_theme_constant("margin_bottom");
Size2 s = get_size();
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 2b163187c5..a7d1f64e93 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -31,7 +31,7 @@
#include "menu_button.h"
#include "core/os/keyboard.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
@@ -43,23 +43,34 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
if (!get_parent() || !is_visible_in_tree() || is_disabled())
return;
- bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this));
-
- if (popup->activate_item_by_event(p_event, global_only))
+ //bool global_only = (get_viewport()->get_modal_stack_top() && !get_viewport()->get_modal_stack_top()->is_a_parent_of(this));
+ //if (popup->activate_item_by_event(p_event, global_only))
+ // accept_event();
+ if (popup->activate_item_by_event(p_event, false))
accept_event();
}
}
void MenuButton::pressed() {
- emit_signal("about_to_show");
+ {
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w && !w->is_embedding_subwindows()) {
+ print_line("windowpos: " + w->get_position());
+ }
+ }
Size2 size = get_size();
- Point2 gp = get_global_position();
- popup->set_global_position(gp + Size2(0, size.height * get_global_transform().get_scale().y));
+ Point2 gp = get_screen_position();
+
+ print_line("screenpos: " + gp);
+ gp.y += get_size().y;
+
+ popup->set_position(gp);
+
popup->set_size(Size2(size.width, 0));
- popup->set_scale(get_global_transform().get_scale());
- popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size()));
+ popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), get_size()));
+ popup->take_mouse_focus();
popup->popup();
}
@@ -116,7 +127,7 @@ void MenuButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
- ADD_SIGNAL(MethodInfo("about_to_show"));
+ ADD_SIGNAL(MethodInfo("about_to_popup"));
}
void MenuButton::set_disable_shortcuts(bool p_disabled) {
@@ -137,8 +148,7 @@ MenuButton::MenuButton() {
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
- popup->set_pass_on_modal_close_click(false);
- popup->connect("about_to_show", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); // For when switching from another MenuButton.
+ popup->connect("about_to_popup", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(true)); // For when switching from another MenuButton.
popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed), varray(false));
}
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index 0ef1f53006..cf10c4cfbd 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -30,7 +30,7 @@
#include "nine_patch_rect.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
void NinePatchRect::_notification(int p_what) {
@@ -45,7 +45,7 @@ void NinePatchRect::_notification(int p_what) {
texture->get_rect_region(rect, src_rect, rect, src_rect);
RID ci = get_canvas_item();
- VS::get_singleton()->canvas_item_add_nine_patch(ci, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), VS::NinePatchAxisMode(axis_h), VS::NinePatchAxisMode(axis_v), draw_center);
+ RS::get_singleton()->canvas_item_add_nine_patch(ci, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center);
}
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index c185761beb..a03d6d0cdc 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -36,12 +36,12 @@ Size2 OptionButton::get_minimum_size() const {
Size2 minsize = Button::get_minimum_size();
- if (has_icon("arrow")) {
- const Size2 padding = get_stylebox("normal")->get_minimum_size();
- const Size2 arrow_size = Control::get_icon("arrow")->get_size();
+ if (has_theme_icon("arrow")) {
+ const Size2 padding = get_theme_stylebox("normal")->get_minimum_size();
+ const Size2 arrow_size = Control::get_theme_icon("arrow")->get_size();
Size2 content_size = minsize - padding;
- content_size.width += arrow_size.width + get_constant("hseparation");
+ content_size.width += arrow_size.width + get_theme_constant("hseparation");
content_size.height = MAX(content_size.height, arrow_size.height);
minsize = content_size + padding;
@@ -55,37 +55,37 @@ void OptionButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- if (!has_icon("arrow"))
+ if (!has_theme_icon("arrow"))
return;
RID ci = get_canvas_item();
- Ref<Texture2D> arrow = Control::get_icon("arrow");
+ Ref<Texture2D> arrow = Control::get_theme_icon("arrow");
Color clr = Color(1, 1, 1);
- if (get_constant("modulate_arrow")) {
+ if (get_theme_constant("modulate_arrow")) {
switch (get_draw_mode()) {
case DRAW_PRESSED:
- clr = get_color("font_color_pressed");
+ clr = get_theme_color("font_color_pressed");
break;
case DRAW_HOVER:
- clr = get_color("font_color_hover");
+ clr = get_theme_color("font_color_hover");
break;
case DRAW_DISABLED:
- clr = get_color("font_color_disabled");
+ clr = get_theme_color("font_color_disabled");
break;
default:
- clr = get_color("font_color");
+ clr = get_theme_color("font_color");
}
}
Size2 size = get_size();
- Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ Point2 ofs(size.width - arrow->get_width() - get_theme_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2)));
arrow->draw(ci, ofs, clr);
} break;
case NOTIFICATION_THEME_CHANGED: {
- if (has_icon("arrow")) {
- _set_internal_margin(MARGIN_RIGHT, Control::get_icon("arrow")->get_width());
+ if (has_theme_icon("arrow")) {
+ _set_internal_margin(MARGIN_RIGHT, Control::get_theme_icon("arrow")->get_width());
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -109,9 +109,8 @@ void OptionButton::_selected(int p_which) {
void OptionButton::pressed() {
Size2 size = get_size();
- popup->set_global_position(get_global_position() + Size2(0, size.height * get_global_transform().get_scale().y));
+ popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
- popup->set_scale(get_global_transform().get_scale());
popup->popup();
}
@@ -341,8 +340,8 @@ void OptionButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
// "selected" property must come after "items", otherwise GH-10213 occurs.
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
- ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "id")));
- ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index")));
}
OptionButton::OptionButton() {
@@ -351,15 +350,15 @@ OptionButton::OptionButton() {
set_toggle_mode(true);
set_text_align(ALIGN_LEFT);
set_action_mode(ACTION_MODE_BUTTON_PRESS);
- if (has_icon("arrow")) {
- _set_internal_margin(MARGIN_RIGHT, Control::get_icon("arrow")->get_width());
+ if (has_theme_icon("arrow")) {
+ _set_internal_margin(MARGIN_RIGHT, Control::get_theme_icon("arrow")->get_width());
}
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
- popup->set_pass_on_modal_close_click(false);
- popup->set_notify_transform(true);
+ // popup->set_pass_on_modal_close_click(false);
+ // popup->set_notify_transform(true);
popup->set_allow_search(true);
popup->connect("index_pressed", callable_mp(this, &OptionButton::_selected));
popup->connect("id_focused", callable_mp(this, &OptionButton::_focused));
diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp
index 0356607071..a17d0eb9c6 100644
--- a/scene/gui/panel.cpp
+++ b/scene/gui/panel.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "panel.h"
+
#include "core/print_string.h"
void Panel::_notification(int p_what) {
@@ -36,11 +37,29 @@ void Panel::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
- Ref<StyleBox> style = get_stylebox("panel");
+ Ref<StyleBox> style = mode == MODE_BACKGROUND ? get_theme_stylebox("panel") : get_theme_stylebox("panel_fg");
style->draw(ci, Rect2(Point2(), get_size()));
}
}
+void Panel::set_mode(Mode p_mode) {
+ mode = p_mode;
+ update();
+}
+Panel::Mode Panel::get_mode() const {
+ return mode;
+}
+
+void Panel::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Panel::set_mode);
+ ClassDB::bind_method(D_METHOD("get_mode"), &Panel::get_mode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Background,Foreground"), "set_mode", "get_mode");
+
+ BIND_ENUM_CONSTANT(MODE_BACKGROUND);
+ BIND_ENUM_CONSTANT(MODE_FOREGROUND);
+}
+
Panel::Panel() {
// Has visible stylebox, so stop by default.
set_mouse_filter(MOUSE_FILTER_STOP);
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index 3538126d22..75e266b6a6 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -37,12 +37,27 @@ class Panel : public Control {
GDCLASS(Panel, Control);
+public:
+ enum Mode {
+ MODE_BACKGROUND,
+ MODE_FOREGROUND,
+ };
+
+private:
+ Mode mode = MODE_BACKGROUND;
+
protected:
void _notification(int p_what);
+ static void _bind_methods();
public:
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
Panel();
~Panel();
};
-#endif
+VARIANT_ENUM_CAST(Panel::Mode)
+
+#endif // PANEL_H
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index 6cf23b8a32..62b9296409 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -34,16 +34,16 @@ Size2 PanelContainer::get_minimum_size() const {
Ref<StyleBox> style;
- if (has_stylebox("panel"))
- style = get_stylebox("panel");
+ if (has_theme_stylebox("panel"))
+ style = get_theme_stylebox("panel");
else
- style = get_stylebox("panel", "PanelContainer");
+ style = get_theme_stylebox("panel", "PanelContainer");
Size2 ms;
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())
+ if (!c || !c->is_visible())
continue;
if (c->is_set_as_toplevel())
continue;
@@ -65,10 +65,10 @@ void PanelContainer::_notification(int p_what) {
RID ci = get_canvas_item();
Ref<StyleBox> style;
- if (has_stylebox("panel"))
- style = get_stylebox("panel");
+ if (has_theme_stylebox("panel"))
+ style = get_theme_stylebox("panel");
else
- style = get_stylebox("panel", "PanelContainer");
+ style = get_theme_stylebox("panel", "PanelContainer");
style->draw(ci, Rect2(Point2(), get_size()));
}
@@ -77,10 +77,10 @@ void PanelContainer::_notification(int p_what) {
Ref<StyleBox> style;
- if (has_stylebox("panel"))
- style = get_stylebox("panel");
+ if (has_theme_stylebox("panel"))
+ style = get_theme_stylebox("panel");
else
- style = get_stylebox("panel", "PanelContainer");
+ style = get_theme_stylebox("panel", "PanelContainer");
Size2 size = get_size();
Point2 ofs;
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 64ef4a01f6..6edafc65a0 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -32,227 +32,131 @@
#include "core/engine.h"
#include "core/os/keyboard.h"
+#include "scene/gui/panel.h"
-void Popup::_gui_input(Ref<InputEvent> p_event) {
-}
-
-void Popup::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (popped_up && !is_visible_in_tree()) {
- popped_up = false;
- notification(NOTIFICATION_POPUP_HIDE);
- emit_signal("popup_hide");
- }
-
- update_configuration_warning();
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- if (popped_up) {
- popped_up = false;
- notification(NOTIFICATION_POPUP_HIDE);
- emit_signal("popup_hide");
- }
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
-//small helper to make editing of these easier in editor
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
- //edited on editor
- set_as_toplevel(false);
- } else
-#endif
- if (is_visible()) {
- hide();
- }
+void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid() && key->is_pressed() && key->get_keycode() == KEY_ESCAPE) {
+ _close_pressed();
}
}
-void Popup::_fix_size() {
-
- Point2 pos = get_global_position();
- Size2 size = get_size() * get_scale();
- Point2 window_size = get_viewport_rect().size - get_viewport_transform().get_origin();
-
- if (pos.x + size.width > window_size.width)
- pos.x = window_size.width - size.width;
- if (pos.x < 0)
- pos.x = 0;
+void Popup::_parent_focused() {
- if (pos.y + size.height > window_size.height)
- pos.y = window_size.height - size.height;
- if (pos.y < 0)
- pos.y = 0;
- if (pos != get_position())
- set_global_position(pos);
+ _close_pressed();
}
+void Popup::_notification(int p_what) {
-void Popup::set_as_minsize() {
-
- Size2 total_minsize;
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c)
- continue;
- if (!c->is_visible())
- continue;
-
- Size2 minsize = c->get_combined_minimum_size();
-
- for (int j = 0; j < 2; j++) {
-
- Margin m_beg = Margin(0 + j);
- Margin m_end = Margin(2 + j);
-
- float margin_begin = c->get_margin(m_beg);
- float margin_end = c->get_margin(m_end);
- float anchor_begin = c->get_anchor(m_beg);
- float anchor_end = c->get_anchor(m_end);
-
- minsize[j] += margin_begin * (ANCHOR_END - anchor_begin) + margin_end * anchor_end;
- }
-
- total_minsize.width = MAX(total_minsize.width, minsize.width);
- total_minsize.height = MAX(total_minsize.height, minsize.height);
+ switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible()) {
+
+ parent_visible = get_parent_visible_window();
+ if (parent_visible) {
+ parent_visible->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ }
+ } else {
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ parent_visible = nullptr;
+ }
+
+ emit_signal("popup_hide");
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ parent_visible = nullptr;
+ }
+ } break;
+ case NOTIFICATION_WM_CLOSE_REQUEST: {
+ _close_pressed();
+
+ } break;
}
-
- set_size(total_minsize);
}
-void Popup::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) {
-
- Size2 popup_size = p_size;
- Size2 window_size = get_viewport_rect().size;
-
- // clamp popup size in each dimension if window size is too small (using fallback ratio)
- popup_size.x = MIN(window_size.x * p_fallback_ratio, popup_size.x);
- popup_size.y = MIN(window_size.y * p_fallback_ratio, popup_size.y);
-
- popup_centered(popup_size);
-}
+void Popup::_close_pressed() {
-void Popup::popup_centered_minsize(const Size2 &p_minsize) {
-
- set_custom_minimum_size(p_minsize);
- _fix_size();
- popup_centered();
-}
+ Window *parent_window = parent_visible;
+ if (parent_visible) {
+ parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ parent_visible = nullptr;
+ }
-void Popup::popup_centered(const Size2 &p_size) {
+ call_deferred("hide");
- Rect2 rect;
- Size2 window_size = get_viewport_rect().size;
- rect.size = p_size == Size2() ? get_size() : p_size;
- rect.position = ((window_size - rect.size) / 2.0).floor();
+ emit_signal("cancelled");
- _popup(rect, true);
+ if (parent_window) {
+ //parent_window->grab_focus();
+ }
}
-void Popup::popup_centered_ratio(float p_screen_ratio) {
-
- Rect2 rect;
- Size2 window_size = get_viewport_rect().size;
- rect.size = (window_size * p_screen_ratio).floor();
- rect.position = ((window_size - rect.size) / 2.0).floor();
-
- _popup(rect, true);
+void Popup::set_as_minsize() {
+ set_size(get_contents_minimum_size());
}
+void Popup::_bind_methods() {
-void Popup::popup(const Rect2 &p_bounds) {
-
- _popup(p_bounds);
+ ADD_SIGNAL(MethodInfo("popup_hide"));
}
-void Popup::_popup(const Rect2 &p_bounds, const bool p_centered) {
-
- emit_signal("about_to_show");
- show_modal(exclusive);
-
- // Fit the popup into the optionally provided bounds.
- if (!p_bounds.has_no_area()) {
- set_size(p_bounds.size);
+Rect2i Popup::_popup_adjust_rect() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
+ Rect2i parent = get_usable_parent_rect();
- // check if p_bounds.size was using an outdated cached values
- if (p_centered && p_bounds.size != get_size()) {
- set_position(p_bounds.position - ((get_size() - p_bounds.size) / 2.0).floor());
- } else {
- set_position(p_bounds.position);
- }
+ if (parent == Rect2i()) {
+ return Rect2i();
}
- _fix_size();
-
- Control *focusable = find_next_valid_focus();
-
- if (focusable)
- focusable->grab_focus();
-
- _post_popup();
- notification(NOTIFICATION_POST_POPUP);
- popped_up = true;
-}
-void Popup::set_exclusive(bool p_exclusive) {
+ Rect2i current(get_position(), get_size());
- exclusive = p_exclusive;
-}
-
-bool Popup::is_exclusive() const {
+ if (current.position.x + current.size.x > parent.position.x + parent.size.x) {
+ current.position.x = parent.position.x + parent.size.x - current.size.x;
+ }
- return exclusive;
-}
+ if (current.position.x < parent.position.x) {
+ current.position.x = parent.position.x;
+ }
-void Popup::_bind_methods() {
+ if (current.position.y + current.size.y > parent.position.y + parent.size.y) {
+ current.position.y = parent.position.y + parent.size.y - current.size.y;
+ }
- ClassDB::bind_method(D_METHOD("set_as_minsize"), &Popup::set_as_minsize);
- ClassDB::bind_method(D_METHOD("popup_centered", "size"), &Popup::popup_centered, DEFVAL(Size2()));
- ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Popup::popup_centered_ratio, DEFVAL(0.75));
- ClassDB::bind_method(D_METHOD("popup_centered_minsize", "minsize"), &Popup::popup_centered_minsize, DEFVAL(Size2()));
- ClassDB::bind_method(D_METHOD("popup_centered_clamped", "size", "fallback_ratio"), &Popup::popup_centered_clamped, DEFVAL(Size2()), DEFVAL(0.75));
- ClassDB::bind_method(D_METHOD("popup", "bounds"), &Popup::popup, DEFVAL(Rect2()));
- ClassDB::bind_method(D_METHOD("set_exclusive", "enable"), &Popup::set_exclusive);
- ClassDB::bind_method(D_METHOD("is_exclusive"), &Popup::is_exclusive);
- ADD_SIGNAL(MethodInfo("about_to_show"));
- ADD_SIGNAL(MethodInfo("popup_hide"));
- ADD_GROUP("Popup", "popup_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "popup_exclusive"), "set_exclusive", "is_exclusive");
+ if (current.position.y < parent.position.y) {
+ current.position.y = parent.position.y;
+ }
- BIND_CONSTANT(NOTIFICATION_POST_POPUP);
- BIND_CONSTANT(NOTIFICATION_POPUP_HIDE);
+ return current;
}
Popup::Popup() {
- set_as_toplevel(true);
- exclusive = false;
- popped_up = false;
- hide();
-}
-
-String Popup::get_configuration_warning() const {
+ parent_visible = nullptr;
- if (is_visible_in_tree()) {
- return TTR("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.");
- }
+ set_wrap_controls(true);
+ set_visible(false);
+ set_transient(true);
+ set_flag(FLAG_BORDERLESS, true);
+ set_flag(FLAG_RESIZE_DISABLED, true);
- return String();
+ connect("window_input", callable_mp(this, &Popup::_input_from_window));
}
Popup::~Popup() {
}
-Size2 PopupPanel::get_minimum_size() const {
+Size2 PopupPanel::_get_contents_minimum_size() const {
- Ref<StyleBox> p = get_stylebox("panel");
+ Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name());
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
- if (!c)
+ if (!c || c == panel)
continue;
if (c->is_set_as_toplevel())
@@ -268,7 +172,7 @@ Size2 PopupPanel::get_minimum_size() const {
void PopupPanel::_update_child_rects() {
- Ref<StyleBox> p = get_stylebox("panel");
+ Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name());
Vector2 cpos(p->get_offset());
Vector2 csize(get_size() - p->get_minimum_size());
@@ -281,24 +185,32 @@ void PopupPanel::_update_child_rects() {
if (c->is_set_as_toplevel())
continue;
- c->set_position(cpos);
- c->set_size(csize);
+ if (c == panel) {
+ c->set_position(Vector2());
+ c->set_size(get_size());
+ } else {
+ c->set_position(cpos);
+ c->set_size(csize);
+ }
}
}
void PopupPanel::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
-
- get_stylebox("panel")->draw(get_canvas_item(), Rect2(Point2(), get_size()));
- } else if (p_what == NOTIFICATION_READY) {
+ if (p_what == NOTIFICATION_THEME_CHANGED) {
+ panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name()));
+ } else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) {
+ panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name()));
_update_child_rects();
- } else if (p_what == NOTIFICATION_RESIZED) {
+ } else if (p_what == NOTIFICATION_WM_SIZE_CHANGED) {
_update_child_rects();
}
}
PopupPanel::PopupPanel() {
+
+ panel = memnew(Panel);
+ add_child(panel);
}
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index ff472170b3..6cd2b4028f 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -31,44 +31,26 @@
#ifndef POPUP_H
#define POPUP_H
-#include "scene/gui/control.h"
+#include "scene/main/window.h"
-class Popup : public Control {
+class Popup : public Window {
- GDCLASS(Popup, Control);
+ GDCLASS(Popup, Window);
- bool exclusive;
- bool popped_up;
+ Window *parent_visible;
-private:
- void _popup(const Rect2 &p_bounds = Rect2(), const bool p_centered = false);
+ void _input_from_window(const Ref<InputEvent> &p_event);
+ void _parent_focused();
protected:
- virtual void _post_popup() {}
+ void _close_pressed();
+ virtual Rect2i _popup_adjust_rect() const;
- void _gui_input(Ref<InputEvent> p_event);
void _notification(int p_what);
- virtual void _fix_size();
static void _bind_methods();
public:
- enum {
- NOTIFICATION_POST_POPUP = 80,
- NOTIFICATION_POPUP_HIDE = 81
- };
-
- void set_exclusive(bool p_exclusive);
- bool is_exclusive() const;
-
- void popup_centered_ratio(float p_screen_ratio = 0.75);
- void popup_centered(const Size2 &p_size = Size2());
- void popup_centered_minsize(const Size2 &p_minsize = Size2());
void set_as_minsize();
- void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75);
- virtual void popup(const Rect2 &p_bounds = Rect2());
-
- virtual String get_configuration_warning() const;
-
Popup();
~Popup();
};
@@ -77,13 +59,16 @@ class PopupPanel : public Popup {
GDCLASS(PopupPanel, Popup);
+ Panel *panel;
+
protected:
void _update_child_rects();
void _notification(int p_what);
+ virtual Size2 _get_contents_minimum_size() const;
+
public:
void set_child_rect(Control *p_child);
- virtual Size2 get_minimum_size() const;
PopupPanel();
};
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index e75dadd5e0..1e933c9aa1 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -30,11 +30,12 @@
#include "popup_menu.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/translation.h"
+#include "scene/gui/control.h"
String PopupMenu::_get_accel_text(int p_item) const {
@@ -47,18 +48,18 @@ String PopupMenu::_get_accel_text(int p_item) const {
return String();
}
-Size2 PopupMenu::get_minimum_size() const {
+Size2 PopupMenu::_get_contents_minimum_size() const {
- int vseparation = get_constant("vseparation");
- int hseparation = get_constant("hseparation");
+ int vseparation = get_theme_constant("vseparation");
+ int hseparation = get_theme_constant("hseparation");
- Size2 minsize = get_stylebox("panel")->get_minimum_size();
- Ref<Font> font = get_font("font");
+ Size2 minsize = get_theme_stylebox("panel")->get_minimum_size();
+ Ref<Font> font = get_theme_font("font");
float max_w = 0;
float icon_w = 0;
int font_h = font->get_height();
- int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
+ 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;
@@ -93,7 +94,7 @@ Size2 PopupMenu::get_minimum_size() const {
}
if (items[i].submenu != "")
- size.width += get_icon("submenu")->get_width();
+ size.width += get_theme_icon("submenu")->get_width();
max_w = MAX(max_w, size.width);
@@ -112,15 +113,15 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
if (p_over.x < 0 || p_over.x >= get_size().width)
return -1;
- Ref<StyleBox> style = get_stylebox("panel");
+ Ref<StyleBox> style = get_theme_stylebox("panel");
Point2 ofs = style->get_offset();
if (ofs.y > p_over.y)
return -1;
- Ref<Font> font = get_font("font");
- int vseparation = get_constant("vseparation");
+ Ref<Font> font = get_theme_font("font");
+ int vseparation = get_theme_constant("vseparation");
float font_h = font->get_height();
for (int i = 0; i < items.size(); i++) {
@@ -152,27 +153,27 @@ void PopupMenu::_activate_submenu(int over) {
ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[over].submenu + ".");
Popup *pm = Object::cast_to<Popup>(n);
ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + ".");
- if (pm->is_visible_in_tree())
+ if (pm->is_visible())
return; //already visible!
- Point2 p = get_global_position();
+ Point2 p = get_position();
Rect2 pr(p, get_size());
- Ref<StyleBox> style = get_stylebox("panel");
+ Ref<StyleBox> style = get_theme_stylebox("panel");
- Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y) * get_global_transform().get_scale();
+ Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
Size2 size = pm->get_size();
// fix pos
- if (pos.x + size.width > get_viewport_rect().size.width)
+ if (pos.x + size.width > get_parent_rect().size.width)
pos.x = p.x - size.width;
pm->set_position(pos);
- pm->set_scale(get_global_transform().get_scale());
+ // pm->set_scale(get_global_transform().get_scale());
pm->popup();
PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
if (pum) {
- pr.position -= pum->get_global_position();
+ pr.position -= pum->get_position();
pum->clear_autohide_areas();
pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache));
if (over < items.size() - 1) {
@@ -184,6 +185,9 @@ void PopupMenu::_activate_submenu(int over) {
void PopupMenu::_submenu_timeout() {
+ //if (!has_focus()) {
+ // return; //do not activate if not has focus
+ //}
if (mouse_over == submenu_over)
_activate_submenu(mouse_over);
@@ -192,20 +196,27 @@ void PopupMenu::_submenu_timeout() {
void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
- int vseparation = get_constant("vseparation");
- Ref<Font> font = get_font("font");
+ int vseparation = get_theme_constant("vseparation");
+ Ref<Font> font = get_theme_font("font");
- float dy = (vseparation + font->get_height()) * 3 * p_factor * get_global_transform().get_scale().y;
+ Rect2 visible_rect = get_usable_parent_rect();
+
+ int dy = (vseparation + font->get_height()) * 3 * p_factor;
if (dy > 0) {
- const float global_top = get_global_position().y;
- const float limit = global_top < 0 ? -global_top : 0;
+ const float global_top = get_position().y;
+ const float limit = global_top < visible_rect.position.y ? visible_rect.position.y - global_top : 0;
dy = MIN(dy, limit);
} else if (dy < 0) {
- const float global_bottom = get_global_position().y + get_size().y * get_global_transform().get_scale().y;
- const float viewport_height = get_viewport_rect().size.y;
+ const float global_bottom = get_position().y + get_size().y;
+ const float viewport_height = visible_rect.position.y + visible_rect.size.y;
const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0;
dy = -MIN(-dy, limit);
}
+
+ if (dy == 0) {
+ return;
+ }
+
set_position(get_position() + Vector2(0, dy));
Ref<InputEventMouseMotion> ie;
@@ -231,8 +242,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
emit_signal("id_focused", i);
- update();
- accept_event();
+ control->update();
+ set_input_as_handled();
break;
}
}
@@ -251,8 +262,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
emit_signal("id_focused", i);
- update();
- accept_event();
+ control->update();
+ set_input_as_handled();
break;
}
}
@@ -261,13 +272,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
Node *n = get_parent();
if (n && Object::cast_to<PopupMenu>(n)) {
hide();
- accept_event();
+ set_input_as_handled();
}
} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) {
_activate_submenu(mouse_over);
- accept_event();
+ set_input_as_handled();
}
} else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
@@ -278,7 +289,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
} else {
activate_item(mouse_over);
}
- accept_event();
+ set_input_as_handled();
}
}
@@ -294,15 +305,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_WHEEL_DOWN: {
- if (get_global_position().y + get_size().y * get_global_transform().get_scale().y > get_viewport_rect().size.y) {
- _scroll(-b->get_factor(), b->get_position());
- }
+ _scroll(-b->get_factor(), b->get_position());
} break;
case BUTTON_WHEEL_UP: {
- if (get_global_position().y < 0) {
- _scroll(b->get_factor(), b->get_position());
- }
+ _scroll(b->get_factor(), b->get_position());
} break;
default: {
// Allow activating item by releasing the LMB or any that was down when the popup appeared
@@ -338,7 +345,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- //update();
+ //control->update();
}
Ref<InputEventMouseMotion> m = p_event;
@@ -354,7 +361,8 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) {
if (!Rect2(Point2(), get_size()).has_point(m->get_position()) && E->get().has_point(m->get_position())) {
- call_deferred("hide");
+
+ _close_pressed();
return;
}
}
@@ -364,7 +372,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (id < 0) {
mouse_over = -1;
- update();
+ control->update();
return;
}
@@ -375,20 +383,18 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (over != mouse_over) {
mouse_over = over;
- update();
+ control->update();
}
}
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
- if (get_global_position().y + get_size().y > get_viewport_rect().size.y || get_global_position().y < 0) {
- _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
- }
+ _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
}
Ref<InputEventKey> k = p_event;
- if (allow_search && k.is_valid() && k->get_unicode()) {
+ if (allow_search && k.is_valid() && k->get_unicode() && k->is_pressed()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
@@ -416,218 +422,227 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (items[i].text.findn(search_string) == 0) {
mouse_over = i;
emit_signal("id_focused", i);
- update();
- accept_event();
+ control->update();
+ set_input_as_handled();
break;
}
}
}
}
-bool PopupMenu::has_point(const Point2 &p_point) const {
+void PopupMenu::_draw() {
- if (parent_rect.has_point(p_point))
- return true;
- for (const List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) {
+ RID ci = control->get_canvas_item();
+ Size2 size = get_size();
- if (E->get().has_point(p_point))
- return true;
- }
+ Ref<StyleBox> style = get_theme_stylebox("panel");
+ Ref<StyleBox> hover = get_theme_stylebox("hover");
+ Ref<Font> font = get_theme_font("font");
+ // In Item::checkable_type enum order (less the non-checkable member)
+ Ref<Texture2D> check[] = { get_theme_icon("checked"), get_theme_icon("radio_checked") };
+ Ref<Texture2D> uncheck[] = { get_theme_icon("unchecked"), get_theme_icon("radio_unchecked") };
+ Ref<Texture2D> submenu = get_theme_icon("submenu");
+ Ref<StyleBox> separator = get_theme_stylebox("separator");
+ Ref<StyleBox> labeled_separator_left = get_theme_stylebox("labeled_separator_left");
+ Ref<StyleBox> labeled_separator_right = get_theme_stylebox("labeled_separator_right");
- return Control::has_point(p_point);
-}
-
-void PopupMenu::_notification(int p_what) {
+ style->draw(ci, Rect2(Point2(), get_size()));
+ Point2 ofs = style->get_offset();
+ int vseparation = get_theme_constant("vseparation");
+ int hseparation = get_theme_constant("hseparation");
+ Color font_color = get_theme_color("font_color");
+ Color font_color_disabled = get_theme_color("font_color_disabled");
+ Color font_color_accel = get_theme_color("font_color_accel");
+ Color font_color_hover = get_theme_color("font_color_hover");
+ float font_h = font->get_height();
- switch (p_what) {
+ // Add the check and the wider icon to the offset of all items.
+ float icon_ofs = 0.0;
+ bool has_check = false;
+ for (int i = 0; i < items.size(); i++) {
- case NOTIFICATION_ENTER_TREE: {
+ if (!items[i].icon.is_null())
+ icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs);
- PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent());
- if (pm) {
- // Inherit submenu's popup delay time from parent menu
- float pm_delay = pm->get_submenu_popup_delay();
- set_submenu_popup_delay(pm_delay);
- }
- } break;
- case NOTIFICATION_TRANSLATION_CHANGED: {
+ if (items[i].checkable_type)
+ has_check = true;
+ }
+ if (icon_ofs > 0.0)
+ icon_ofs += hseparation;
- for (int i = 0; i < items.size(); i++) {
- items.write[i].xl_text = tr(items[i].text);
- }
+ float check_ofs = 0.0;
+ if (has_check)
+ check_ofs = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation;
- minimum_size_changed();
- update();
- } break;
- case NOTIFICATION_DRAW: {
-
- RID ci = get_canvas_item();
- Size2 size = get_size();
-
- Ref<StyleBox> style = get_stylebox("panel");
- Ref<StyleBox> hover = get_stylebox("hover");
- Ref<Font> font = get_font("font");
- // In Item::checkable_type enum order (less the non-checkable member)
- Ref<Texture2D> check[] = { get_icon("checked"), get_icon("radio_checked") };
- Ref<Texture2D> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") };
- Ref<Texture2D> submenu = get_icon("submenu");
- Ref<StyleBox> separator = get_stylebox("separator");
- Ref<StyleBox> labeled_separator_left = get_stylebox("labeled_separator_left");
- Ref<StyleBox> labeled_separator_right = get_stylebox("labeled_separator_right");
-
- style->draw(ci, Rect2(Point2(), get_size()));
- Point2 ofs = style->get_offset();
- int vseparation = get_constant("vseparation");
- int hseparation = get_constant("hseparation");
- Color font_color = get_color("font_color");
- Color font_color_disabled = get_color("font_color_disabled");
- Color font_color_accel = get_color("font_color_accel");
- Color font_color_hover = get_color("font_color_hover");
- float font_h = font->get_height();
-
- // Add the check and the wider icon to the offset of all items.
- float icon_ofs = 0.0;
- bool has_check = false;
- for (int i = 0; i < items.size(); i++) {
+ for (int i = 0; i < items.size(); i++) {
- if (!items[i].icon.is_null())
- icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs);
+ if (i > 0)
+ ofs.y += vseparation;
+ Point2 item_ofs = ofs;
+ Size2 icon_size;
+ float h;
- if (items[i].checkable_type)
- has_check = true;
- }
- if (icon_ofs > 0.0)
- icon_ofs += hseparation;
+ if (!items[i].icon.is_null()) {
- float check_ofs = 0.0;
- if (has_check)
- check_ofs = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width()) + hseparation;
+ icon_size = items[i].icon->get_size();
+ h = MAX(icon_size.height, font_h);
+ } else {
- for (int i = 0; i < items.size(); i++) {
+ h = font_h;
+ }
- if (i > 0)
- ofs.y += vseparation;
- Point2 item_ofs = ofs;
- Size2 icon_size;
- float h;
+ if (i == mouse_over) {
- if (!items[i].icon.is_null()) {
+ hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
+ }
- icon_size = items[i].icon->get_size();
- h = MAX(icon_size.height, font_h);
- } else {
+ String text = items[i].xl_text;
- h = font_h;
+ item_ofs.x += items[i].h_ofs;
+ if (items[i].separator) {
+
+ int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
+ if (text != String()) {
+ int ss = font->get_string_size(text).width;
+ int center = (get_size().width) / 2;
+ int l = center - ss / 2;
+ int r = center + ss / 2;
+ if (l > item_ofs.x) {
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
}
-
- if (i == mouse_over) {
-
- hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
+ if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
+ labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
}
+ } else {
+ separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
+ }
+ }
- String text = items[i].xl_text;
+ Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
- item_ofs.x += items[i].h_ofs;
- if (items[i].separator) {
+ if (items[i].checkable_type) {
+ Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
+ icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
+ }
- int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
- if (text != String()) {
- int ss = font->get_string_size(text).width;
- int center = (get_size().width) / 2;
- int l = center - ss / 2;
- int r = center + ss / 2;
- if (l > item_ofs.x) {
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
- }
- if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
- labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
- }
- } else {
- separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
- }
- }
+ if (!items[i].icon.is_null()) {
+ items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
+ }
- Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ if (items[i].submenu != "") {
+ submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ }
- if (items[i].checkable_type) {
- Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
- icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
- }
+ item_ofs.y += font->get_ascent();
+ if (items[i].separator) {
- if (!items[i].icon.is_null()) {
- items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
- }
+ if (text != String()) {
+ int center = (get_size().width - font->get_string_size(text).width) / 2;
+ font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
+ }
+ } else {
- if (items[i].submenu != "") {
- submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
- }
+ item_ofs.x += icon_ofs + check_ofs;
+ font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
+ }
- item_ofs.y += font->get_ascent();
- if (items[i].separator) {
+ if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
+ //accelerator
+ String text2 = _get_accel_text(i);
+ item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width;
+ font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel);
+ }
- if (text != String()) {
- int center = (get_size().width - font->get_string_size(text).width) / 2;
- font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
- }
- } else {
+ items.write[i]._ofs_cache = ofs.y;
- item_ofs.x += icon_ofs + check_ofs;
- font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
- }
+ ofs.y += h;
+ }
+}
- if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
- //accelerator
- String text2 = _get_accel_text(i);
- item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width;
- font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel);
- }
+void PopupMenu::_notification(int p_what) {
+
+ switch (p_what) {
- items.write[i]._ofs_cache = ofs.y;
+ case NOTIFICATION_ENTER_TREE: {
- ofs.y += h;
+ PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent());
+ if (pm) {
+ // Inherit submenu's popup delay time from parent menu
+ float pm_delay = pm->get_submenu_popup_delay();
+ set_submenu_popup_delay(pm_delay);
}
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_TRANSLATION_CHANGED: {
- if (hide_on_window_lose_focus)
- hide();
+ for (int i = 0; i < items.size(); i++) {
+ items.write[i].xl_text = tr(items[i].text);
+ }
+
+ child_controls_changed();
+ control->update();
} break;
- case NOTIFICATION_MOUSE_ENTER: {
+ case NOTIFICATION_WM_MOUSE_ENTER: {
- grab_focus();
+ //grab_focus();
} break;
- case NOTIFICATION_MOUSE_EXIT: {
+ case NOTIFICATION_WM_MOUSE_EXIT: {
if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) {
mouse_over = -1;
- update();
+ control->update();
}
} break;
case NOTIFICATION_POST_POPUP: {
- initial_button_mask = Input::get_singleton()->get_mouse_button_mask();
+ initial_button_mask = InputFilter::get_singleton()->get_mouse_button_mask();
during_grabbed_click = (bool)initial_button_mask;
} break;
- case NOTIFICATION_POPUP_HIDE: {
+ case NOTIFICATION_WM_SIZE_CHANGED: {
- if (mouse_over >= 0) {
- mouse_over = -1;
- update();
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ //only used when using operating system windows
+ if (get_window_id() != DisplayServer::INVALID_WINDOW_ID && autohide_areas.size()) {
+ Point2 mouse_pos = DisplayServer::get_singleton()->mouse_get_position();
+ mouse_pos -= get_position();
+
+ for (List<Rect2>::Element *E = autohide_areas.front(); E; E = E->next()) {
+
+ if (!Rect2(Point2(), get_size()).has_point(mouse_pos) && E->get().has_point(mouse_pos)) {
+ _close_pressed();
+ return;
+ }
+ }
}
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
- for (int i = 0; i < items.size(); i++) {
- if (items[i].submenu == "")
- continue;
+ if (!is_visible()) {
+ if (mouse_over >= 0) {
+ mouse_over = -1;
+ control->update();
+ }
+
+ for (int i = 0; i < items.size(); i++) {
+ if (items[i].submenu == "")
+ continue;
- Node *n = get_node(items[i].submenu);
- if (!n)
- continue;
+ Node *n = get_node(items[i].submenu);
+ if (!n)
+ continue;
- PopupMenu *pm = Object::cast_to<PopupMenu>(n);
- if (!pm || !pm->is_visible())
- continue;
+ PopupMenu *pm = Object::cast_to<PopupMenu>(n);
+ if (!pm || !pm->is_visible())
+ continue;
- pm->hide();
+ pm->hide();
+ }
+
+ set_process_internal(false);
+ } else {
+ if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ set_process_internal(true);
+ }
}
} break;
}
@@ -648,8 +663,8 @@ void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) {
Item item;
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
@@ -658,8 +673,8 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.icon = p_icon;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) {
@@ -668,8 +683,8 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
@@ -679,8 +694,8 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p_accel) {
@@ -689,8 +704,8 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
@@ -700,8 +715,8 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) {
@@ -711,8 +726,8 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
item.max_states = p_max_states;
item.state = p_default_state;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \
@@ -729,8 +744,8 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_g
Item item;
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -739,8 +754,8 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortC
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.icon = p_icon;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -749,8 +764,8 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -760,8 +775,8 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -770,8 +785,8 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
@@ -781,8 +796,8 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
@@ -793,8 +808,8 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
item.id = p_id == -1 ? items.size() : p_id;
item.submenu = p_submenu;
items.push_back(item);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
#undef ITEM_SETUP_WITH_ACCEL
@@ -808,16 +823,16 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
items.write[p_idx].text = p_text;
items.write[p_idx].xl_text = tr(p_text);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon = p_icon;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
@@ -825,16 +840,16 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
items.write[p_idx].checked = p_checked;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_id(int p_idx, int p_id) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].id = p_id;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
@@ -842,40 +857,40 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].accel = p_accel;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].metadata = p_meta;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].disabled = p_disabled;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].submenu = p_submenu;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checked = !items[p_idx].checked;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
String PopupMenu::get_item_text(int p_idx) const {
@@ -968,7 +983,7 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].separator = p_separator;
- update();
+ control->update();
}
bool PopupMenu::is_item_separator(int p_idx) const {
@@ -980,21 +995,21 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
- update();
+ control->update();
}
void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
- update();
+ control->update();
}
void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tooltip = p_tooltip;
- update();
+ control->update();
}
void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global) {
@@ -1009,29 +1024,29 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo
_ref_shortcut(items[p_idx].shortcut);
}
- update();
+ control->update();
}
void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].h_ofs = p_offset;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].state = p_state;
- update();
+ control->update();
}
void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].shortcut_is_disabled = p_disabled;
- update();
+ control->update();
}
void PopupMenu::toggle_item_multistate(int p_idx) {
@@ -1045,7 +1060,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
if (items.write[p_idx].max_states <= items[p_idx].state)
items.write[p_idx].state = 0;
- update();
+ control->update();
}
bool PopupMenu::is_item_checkable(int p_idx) const {
@@ -1177,8 +1192,8 @@ void PopupMenu::remove_item(int p_idx) {
}
items.remove(p_idx);
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
void PopupMenu::add_separator(const String &p_text) {
@@ -1191,7 +1206,7 @@ void PopupMenu::add_separator(const String &p_text) {
sep.xl_text = tr(p_text);
}
items.push_back(sep);
- update();
+ control->update();
}
void PopupMenu::clear() {
@@ -1203,8 +1218,8 @@ void PopupMenu::clear() {
}
items.clear();
mouse_over = -1;
- update();
- minimum_size_changed();
+ control->update();
+ child_controls_changed();
}
Array PopupMenu::_get_items() const {
@@ -1345,16 +1360,6 @@ bool PopupMenu::get_allow_search() const {
return allow_search;
}
-void PopupMenu::set_hide_on_window_lose_focus(bool p_enabled) {
-
- hide_on_window_lose_focus = p_enabled;
-}
-
-bool PopupMenu::is_hide_on_window_lose_focus() const {
-
- return hide_on_window_lose_focus;
-}
-
String PopupMenu::get_tooltip(const Point2 &p_pos) const {
int over = _get_mouse_over(p_pos);
@@ -1387,6 +1392,14 @@ void PopupMenu::clear_autohide_areas() {
autohide_areas.clear();
}
+void PopupMenu::take_mouse_focus() {
+ ERR_FAIL_COND(!is_inside_tree());
+
+ if (get_parent()) {
+ get_parent()->get_viewport()->pass_mouse_focus_to(this, control);
+ }
+}
+
void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input);
@@ -1466,9 +1479,6 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_submenu_popup_delay", "seconds"), &PopupMenu::set_submenu_popup_delay);
ClassDB::bind_method(D_METHOD("get_submenu_popup_delay"), &PopupMenu::get_submenu_popup_delay);
- ClassDB::bind_method(D_METHOD("set_hide_on_window_lose_focus", "enable"), &PopupMenu::set_hide_on_window_lose_focus);
- ClassDB::bind_method(D_METHOD("is_hide_on_window_lose_focus"), &PopupMenu::is_hide_on_window_lose_focus);
-
ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search);
ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search);
@@ -1486,7 +1496,6 @@ void PopupMenu::_bind_methods() {
void PopupMenu::popup(const Rect2 &p_bounds) {
- grab_click_focus();
moved = Vector2();
invalidated_click = true;
Popup::popup(p_bounds);
@@ -1494,21 +1503,26 @@ void PopupMenu::popup(const Rect2 &p_bounds) {
PopupMenu::PopupMenu() {
+ control = memnew(Control);
+ add_child(control);
+
+ control->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ connect("window_input", callable_mp(this, &PopupMenu::_gui_input));
+ control->connect("draw", callable_mp(this, &PopupMenu::_draw));
+
mouse_over = -1;
submenu_over = -1;
initial_button_mask = 0;
during_grabbed_click = false;
+ invalidated_click = false;
allow_search = false;
search_time_msec = 0;
search_string = "";
- set_focus_mode(FOCUS_ALL);
- set_as_toplevel(true);
set_hide_on_item_selection(true);
set_hide_on_checkable_item_selection(true);
set_hide_on_multistate_item_selection(false);
- set_hide_on_window_lose_focus(true);
submenu_timer = memnew(Timer);
submenu_timer->set_wait_time(0.3);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index a3a858cfde..2eef1f009d 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -32,6 +32,7 @@
#define POPUP_MENU_H
#include "scene/gui/popup.h"
+#include "scene/gui/shortcut.h"
class PopupMenu : public Popup {
@@ -87,7 +88,7 @@ class PopupMenu : public Popup {
Rect2 parent_rect;
String _get_accel_text(int p_item) const;
int _get_mouse_over(const Point2 &p_over) const;
- virtual Size2 get_minimum_size() const;
+ virtual Size2 _get_contents_minimum_size() const;
void _scroll(float p_factor, const Point2 &p_over);
void _gui_input(const Ref<InputEvent> &p_event);
void _activate_submenu(int over);
@@ -97,7 +98,6 @@ class PopupMenu : public Popup {
bool hide_on_item_selection;
bool hide_on_checkable_item_selection;
bool hide_on_multistate_item_selection;
- bool hide_on_window_lose_focus;
Vector2 moved;
Array _get_items() const;
@@ -112,9 +112,11 @@ class PopupMenu : public Popup {
uint64_t search_time_msec;
String search_string;
-protected:
- virtual bool has_point(const Point2 &p_point) const;
+ Control *control;
+
+ void _draw();
+protected:
friend class MenuButton;
void _notification(int p_what);
static void _bind_methods();
@@ -213,8 +215,7 @@ public:
virtual void popup(const Rect2 &p_bounds = Rect2());
- void set_hide_on_window_lose_focus(bool p_enabled);
- bool is_hide_on_window_lose_focus() const;
+ void take_mouse_focus();
PopupMenu();
~PopupMenu();
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index e11295d7e7..362c45453d 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -32,9 +32,9 @@
Size2 ProgressBar::get_minimum_size() const {
- Ref<StyleBox> bg = get_stylebox("bg");
- Ref<StyleBox> fg = get_stylebox("fg");
- Ref<Font> font = get_font("font");
+ Ref<StyleBox> bg = get_theme_stylebox("bg");
+ Ref<StyleBox> fg = get_theme_stylebox("fg");
+ Ref<Font> font = get_theme_font("font");
Size2 minimum_size = bg->get_minimum_size();
minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height);
@@ -52,10 +52,10 @@ void ProgressBar::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<StyleBox> bg = get_stylebox("bg");
- Ref<StyleBox> fg = get_stylebox("fg");
- Ref<Font> font = get_font("font");
- Color font_color = get_color("font_color");
+ Ref<StyleBox> bg = get_theme_stylebox("bg");
+ Ref<StyleBox> fg = get_theme_stylebox("fg");
+ Ref<Font> font = get_theme_font("font");
+ Color font_color = get_theme_color("font_color");
draw_style_box(bg, Rect2(Point2(), get_size()));
float r = get_as_ratio();
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index adc5f81465..ab2f64e1b4 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -236,7 +236,7 @@ void Range::_unref_shared() {
shared->owners.erase(this);
if (shared->owners.size() == 0) {
memdelete(shared);
- shared = NULL;
+ shared = nullptr;
}
}
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index bc1510d6f6..9fab9005f9 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -34,6 +34,7 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "scene/scene_string_names.h"
+#include "servers/display_server.h"
#include "modules/modules_enabled.gen.h"
#ifdef MODULE_REGEX_ENABLED
@@ -52,7 +53,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
return p_item->subitems.front()->get();
} else if (!p_item->parent) {
- return NULL;
+ return nullptr;
} else if (p_item->E->next()) {
return p_item->E->next()->get();
@@ -65,7 +66,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
if (p_item->parent)
return p_item->E->next()->get();
else
- return NULL;
+ return nullptr;
}
} else {
@@ -73,7 +74,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
return p_item->subitems.front()->get();
} else if (p_item->type == ITEM_FRAME) {
- return NULL;
+ return nullptr;
} else if (p_item->E->next()) {
return p_item->E->next()->get();
@@ -86,11 +87,11 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
if (p_item->type != ITEM_FRAME)
return p_item->E->next()->get();
else
- return NULL;
+ return nullptr;
}
}
- return NULL;
+ return nullptr;
}
RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
@@ -100,7 +101,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
return p_item->subitems.back()->get();
} else if (!p_item->parent) {
- return NULL;
+ return nullptr;
} else if (p_item->E->prev()) {
return p_item->E->prev()->get();
@@ -113,7 +114,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
if (p_item->parent)
return p_item->E->prev()->get();
else
- return NULL;
+ return nullptr;
}
} else {
@@ -121,7 +122,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
return p_item->subitems.back()->get();
} else if (p_item->type == ITEM_FRAME) {
- return NULL;
+ return nullptr;
} else if (p_item->E->prev()) {
return p_item->E->prev()->get();
@@ -134,15 +135,15 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
if (p_item->type != ITEM_FRAME)
return p_item->E->prev()->get();
else
- return NULL;
+ return nullptr;
}
}
- return NULL;
+ return nullptr;
}
Rect2 RichTextLabel::_get_text_rect() {
- Ref<StyleBox> style = get_stylebox("normal");
+ Ref<StyleBox> style = get_theme_stylebox("normal");
return Rect2(style->get_offset(), get_size() - style->get_minimum_size());
}
@@ -157,7 +158,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
ci = get_canvas_item();
if (r_click_item)
- *r_click_item = NULL;
+ *r_click_item = nullptr;
}
Line &l = p_frame->lines.write[p_line];
Item *it = l.from;
@@ -240,7 +241,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
l.space_caches.push_back(spaces); \
} \
line_wrapped = false; \
- y += line_height + get_constant(SceneStringNames::get_singleton()->line_separation); \
+ y += line_height + get_theme_constant(SceneStringNames::get_singleton()->line_separation); \
line_height = 0; \
line_ascent = 0; \
line_descent = 0; \
@@ -305,8 +306,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
Color selection_bg;
if (p_mode == PROCESS_DRAW) {
- selection_fg = get_color("font_color_selected");
- selection_bg = get_color("selection_color");
+ selection_fg = get_theme_color("font_color_selected");
+ selection_bg = get_theme_color("selection_color");
}
int rchar = 0;
@@ -355,7 +356,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
Color font_color_shadow;
bool underline = false;
bool strikethrough = false;
- ItemFade *fade = NULL;
+ ItemFade *fade = nullptr;
int it_char_start = p_char_count;
Vector<ItemFX *> fx_stack = Vector<ItemFX *>();
@@ -406,17 +407,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
cw = tab_size * font->get_char_size(' ').width;
}
- if (end > 0 && w + cw + begin > p_width) {
+ if (end > 0 && fw + cw + begin > p_width) {
break; //don't allow lines longer than assigned width
}
- w += cw;
fw += cw;
end++;
}
CHECK_HEIGHT(fh);
- ENSURE_WIDTH(w);
+ ENSURE_WIDTH(fw);
line_ascent = MAX(line_ascent, ascent);
line_descent = MAX(line_descent, descent);
@@ -551,8 +551,10 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
}
}
- if (visible)
+ if (visible) {
line_is_blank = false;
+ w += font->get_char_size(c[i], c[i + 1]).x;
+ }
if (c[i] == '\t')
visible = false;
@@ -581,13 +583,14 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
} else {
cw = drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], fx_color);
}
- } else if (previously_visible) {
+ } else if (previously_visible && c[i] != '\t') {
backtrack += font->get_char_size(fx_char, c[i + 1]).x;
}
p_char_count++;
if (c[i] == '\t') {
cw = tab_size * font->get_char_size(' ').width;
+ backtrack = MAX(0, backtrack - cw);
}
ofs += cw;
@@ -602,16 +605,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
#ifdef TOOLS_ENABLED
underline_width *= EDSCALE;
#endif
- VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width);
+ RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width);
} else if (strikethrough) {
Color uc = color;
uc.a *= 0.5;
- int uy = y + lh / 2 - line_descent + 2;
+ int uy = y + lh - (line_ascent + line_descent) / 2;
float strikethrough_width = 1.0;
#ifdef TOOLS_ENABLED
strikethrough_width *= EDSCALE;
#endif
- VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, strikethrough_width);
+ RS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, strikethrough_width);
}
}
@@ -667,13 +670,13 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
lh = 0;
ItemTable *table = static_cast<ItemTable *>(it);
- int hseparation = get_constant("table_hseparation");
- int vseparation = get_constant("table_vseparation");
+ int hseparation = get_theme_constant("table_hseparation");
+ int vseparation = get_theme_constant("table_vseparation");
Color ccolor = _find_color(table, p_base_color);
Vector2 draw_ofs = Point2(wofs, y);
- Color font_color_shadow = get_color("font_color_shadow");
- bool use_outline = get_constant("shadow_as_outline");
- Point2 shadow_ofs2(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
+ Color font_color_shadow = get_theme_color("font_color_shadow");
+ bool use_outline = get_theme_constant("shadow_as_outline");
+ Point2 shadow_ofs2(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
if (p_mode == PROCESS_CACHE) {
@@ -914,7 +917,7 @@ void RichTextLabel::_update_scroll() {
void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_time) {
Item *it = p_frame;
while (it) {
- ItemFX *ifx = NULL;
+ ItemFX *ifx = nullptr;
if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW) {
ifx = static_cast<ItemFX *>(it);
@@ -927,7 +930,7 @@ void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_
ifx->elapsed_time += p_delta_time;
- ItemShake *shake = NULL;
+ ItemShake *shake = nullptr;
if (it->type == ITEM_SHAKE) {
shake = static_cast<ItemShake *>(it);
@@ -951,7 +954,7 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
if (meta_hovering) {
- meta_hovering = NULL;
+ meta_hovering = nullptr;
emit_signal("meta_hover_ended", current_meta);
current_meta = false;
update();
@@ -987,12 +990,12 @@ void RichTextLabel::_notification(int p_what) {
Size2 size = get_size();
Rect2 text_rect = _get_text_rect();
- draw_style_box(get_stylebox("normal"), Rect2(Point2(), size));
+ draw_style_box(get_theme_stylebox("normal"), Rect2(Point2(), size));
if (has_focus()) {
- VisualServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
- draw_style_box(get_stylebox("focus"), Rect2(Point2(), size));
- VisualServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
+ draw_style_box(get_theme_stylebox("focus"), Rect2(Point2(), size));
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
int ofs = vscroll->get_value();
@@ -1012,16 +1015,16 @@ void RichTextLabel::_notification(int p_what) {
if (from_line >= main->lines.size())
break; //nothing to draw
int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs;
- Ref<Font> base_font = get_font("normal_font");
- Color base_color = get_color("default_color");
- Color font_color_shadow = get_color("font_color_shadow");
- bool use_outline = get_constant("shadow_as_outline");
- Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
+ Ref<Font> base_font = get_theme_font("normal_font");
+ Color base_color = get_theme_color("default_color");
+ Color font_color_shadow = get_theme_color("font_color_shadow");
+ bool use_outline = get_theme_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
visible_line_count = 0;
while (y < size.height && from_line < main->lines.size()) {
- visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), NULL, NULL, NULL, total_chars);
+ visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), nullptr, nullptr, nullptr, total_chars);
total_chars += main->lines[from_line].char_count;
from_line++;
@@ -1039,13 +1042,13 @@ void RichTextLabel::_notification(int p_what) {
void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item, int *r_click_char, bool *r_outside) {
if (r_click_item)
- *r_click_item = NULL;
+ *r_click_item = nullptr;
Rect2 text_rect = _get_text_rect();
int ofs = vscroll->get_value();
- Color font_color_shadow = get_color("font_color_shadow");
- bool use_outline = get_constant("shadow_as_outline");
- Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
+ Color font_color_shadow = get_theme_color("font_color_shadow");
+ bool use_outline = get_theme_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
//todo, change to binary search
int from_line = 0;
@@ -1061,8 +1064,8 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
return;
int y = (p_frame->lines[from_line].height_accum_cache - p_frame->lines[from_line].height_cache) - ofs;
- Ref<Font> base_font = get_font("normal_font");
- Color base_color = get_color("default_color");
+ Ref<Font> base_font = get_theme_font("normal_font");
+ Color base_color = get_theme_color("default_color");
while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) {
@@ -1085,11 +1088,11 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
return CURSOR_ARROW; //invalid
int line = 0;
- Item *item = NULL;
+ Item *item = nullptr;
bool outside;
((RichTextLabel *)(this))->_find_click(main, p_pos, &item, &line, &outside);
- if (item && !outside && ((RichTextLabel *)(this))->_find_meta(item, NULL))
+ if (item && !outside && ((RichTextLabel *)(this))->_find_meta(item, nullptr))
return CURSOR_POINTING_HAND;
return CURSOR_ARROW;
@@ -1107,7 +1110,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
if (b->is_pressed() && !b->is_doubleclick()) {
scroll_updated = false;
int line = 0;
- Item *item = NULL;
+ Item *item = nullptr;
bool outside;
_find_click(main, b->get_position(), &item, &line, &outside);
@@ -1121,9 +1124,9 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
// Erase previous selection.
if (selection.active) {
- selection.from = NULL;
+ selection.from = nullptr;
selection.from_char = '\0';
- selection.to = NULL;
+ selection.to = nullptr;
selection.to_char = '\0';
selection.active = false;
@@ -1135,7 +1138,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
//doubleclick: select word
int line = 0;
- Item *item = NULL;
+ Item *item = nullptr;
bool outside;
_find_click(main, b->get_position(), &item, &line, &outside);
@@ -1162,11 +1165,11 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
} else if (!b->is_pressed()) {
- selection.click = NULL;
+ selection.click = nullptr;
if (!b->is_doubleclick() && !scroll_updated) {
int line = 0;
- Item *item = NULL;
+ Item *item = nullptr;
bool outside;
_find_click(main, b->get_position(), &item, &line, &outside);
@@ -1227,14 +1230,14 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
case KEY_UP: {
if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() - get_font("normal_font")->get_height());
+ vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height());
handled = true;
}
} break;
case KEY_DOWN: {
if (vscroll->is_visible_in_tree()) {
- vscroll->set_value(vscroll->get_value() + get_font("normal_font")->get_height());
+ vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height());
handled = true;
}
} break;
@@ -1275,7 +1278,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
return;
int line = 0;
- Item *item = NULL;
+ Item *item = nullptr;
bool outside;
_find_click(main, m->get_position(), &item, &line, &outside);
@@ -1324,7 +1327,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
emit_signal("meta_hover_started", meta);
}
} else if (meta_hovering) {
- meta_hovering = NULL;
+ meta_hovering = nullptr;
emit_signal("meta_hover_ended", current_meta);
current_meta = false;
}
@@ -1525,11 +1528,11 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
size.width = fixed_width;
}
Rect2 text_rect = _get_text_rect();
- Color font_color_shadow = get_color("font_color_shadow");
- bool use_outline = get_constant("shadow_as_outline");
- Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
+ Color font_color_shadow = get_theme_color("font_color_shadow");
+ bool use_outline = get_theme_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y"));
- Ref<Font> base_font = get_font("normal_font");
+ Ref<Font> base_font = get_theme_font("normal_font");
for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) {
@@ -1544,7 +1547,7 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
int total_height = 0;
if (p_frame->lines.size())
- total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_stylebox("normal")->get_minimum_size().height;
+ total_height = p_frame->lines[p_frame->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height;
main->first_invalid_line = p_frame->lines.size();
@@ -1640,12 +1643,16 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
}
}
- if (current_frame->lines[current_frame->lines.size() - 1].from == NULL) {
+ if (current_frame->lines[current_frame->lines.size() - 1].from == nullptr) {
current_frame->lines.write[current_frame->lines.size() - 1].from = p_item;
}
p_item->line = current_frame->lines.size() - 1;
_invalidate_current_line(current_frame);
+
+ if (fixed_width != -1) {
+ minimum_size_changed();
+ }
}
void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_subitem_line) {
@@ -1758,35 +1765,35 @@ void RichTextLabel::push_font(const Ref<Font> &p_font) {
}
void RichTextLabel::push_normal() {
- Ref<Font> normal_font = get_font("normal_font");
+ Ref<Font> normal_font = get_theme_font("normal_font");
ERR_FAIL_COND(normal_font.is_null());
push_font(normal_font);
}
void RichTextLabel::push_bold() {
- Ref<Font> bold_font = get_font("bold_font");
+ Ref<Font> bold_font = get_theme_font("bold_font");
ERR_FAIL_COND(bold_font.is_null());
push_font(bold_font);
}
void RichTextLabel::push_bold_italics() {
- Ref<Font> bold_italics_font = get_font("bold_italics_font");
+ Ref<Font> bold_italics_font = get_theme_font("bold_italics_font");
ERR_FAIL_COND(bold_italics_font.is_null());
push_font(bold_italics_font);
}
void RichTextLabel::push_italics() {
- Ref<Font> italics_font = get_font("italics_font");
+ Ref<Font> italics_font = get_theme_font("italics_font");
ERR_FAIL_COND(italics_font.is_null());
push_font(italics_font);
}
void RichTextLabel::push_mono() {
- Ref<Font> mono_font = get_font("mono_font");
+ Ref<Font> mono_font = get_theme_font("mono_font");
ERR_FAIL_COND(mono_font.is_null());
push_font(mono_font);
@@ -1933,7 +1940,7 @@ void RichTextLabel::push_cell() {
item->cell = true;
item->parent_line = item->parent_frame->lines.size() - 1;
item->lines.resize(1);
- item->lines.write[0].from = NULL;
+ item->lines.write[0].from = nullptr;
item->first_invalid_line = 0;
}
@@ -1964,9 +1971,13 @@ void RichTextLabel::clear() {
main->lines.resize(1);
main->first_invalid_line = 0;
update();
- selection.click = NULL;
+ selection.click = nullptr;
selection.active = false;
current_idx = 1;
+
+ if (fixed_width != -1) {
+ minimum_size_changed();
+ }
}
void RichTextLabel::set_tab_size(int p_spaces) {
@@ -2044,13 +2055,13 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
int pos = 0;
List<String> tag_stack;
- Ref<Font> normal_font = get_font("normal_font");
- Ref<Font> bold_font = get_font("bold_font");
- Ref<Font> italics_font = get_font("italics_font");
- Ref<Font> bold_italics_font = get_font("bold_italics_font");
- Ref<Font> mono_font = get_font("mono_font");
+ Ref<Font> normal_font = get_theme_font("normal_font");
+ Ref<Font> bold_font = get_theme_font("bold_font");
+ Ref<Font> italics_font = get_theme_font("italics_font");
+ Ref<Font> bold_italics_font = get_theme_font("bold_italics_font");
+ Ref<Font> mono_font = get_theme_font("mono_font");
- Color base_color = get_color("default_color");
+ Color base_color = get_theme_color("default_color");
int indent_level = 0;
@@ -2507,7 +2518,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
if (it->type == ITEM_TEXT) {
ItemText *t = static_cast<ItemText *>(it);
- int sp = t->text.find(p_string, charidx);
+ int sp = t->text.findn(p_string, charidx);
if (sp != -1) {
selection.from = it;
selection.from_char = sp;
@@ -2518,7 +2529,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
_validate_line_caches(main);
- int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_font("normal_font")->get_height();
+ int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_theme_font("normal_font")->get_height();
float offset = 0;
@@ -2584,7 +2595,7 @@ void RichTextLabel::selection_copy() {
}
if (text != "") {
- OS::get_singleton()->set_clipboard(text);
+ DisplayServer::get_singleton()->clipboard_set(text);
}
}
@@ -2692,7 +2703,7 @@ void RichTextLabel::install_effect(const Variant effect) {
int RichTextLabel::get_content_height() {
int total_height = 0;
if (main->lines.size())
- total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_stylebox("normal")->get_minimum_size().height;
+ total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_theme_stylebox("normal")->get_minimum_size().height;
return total_height;
}
@@ -2944,7 +2955,7 @@ RichTextLabel::RichTextLabel() {
tab_size = 4;
default_align = ALIGN_LEFT;
underline_meta = true;
- meta_hovering = NULL;
+ meta_hovering = nullptr;
override_selected_font_color = false;
scroll_visible = false;
@@ -2968,7 +2979,7 @@ RichTextLabel::RichTextLabel() {
current_idx = 1;
use_bbcode = false;
- selection.click = NULL;
+ selection.click = nullptr;
selection.active = false;
selection.enabled = false;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 409aec0ca6..7f2b5facb9 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -98,7 +98,7 @@ private:
int maximum_width;
Line() {
- from = NULL;
+ from = nullptr;
char_count = 0;
}
};
@@ -119,9 +119,11 @@ private:
}
Item() {
- parent = NULL;
- E = NULL;
+ parent = nullptr;
+ E = nullptr;
line = 0;
+ index = 0;
+ type = ITEM_FRAME;
}
virtual ~Item() { _clear_children(); }
};
@@ -135,7 +137,7 @@ private:
ItemFrame() {
type = ITEM_FRAME;
- parent_frame = NULL;
+ parent_frame = nullptr;
cell = false;
parent_line = 0;
}
@@ -330,7 +332,7 @@ private:
ItemMeta *meta_hovering;
Variant current_meta;
- Vector<Ref<RichTextEffect> > custom_effects;
+ Vector<Ref<RichTextEffect>> custom_effects;
void _invalidate_current_line(ItemFrame *p_frame);
void _validate_line_caches(ItemFrame *p_frame);
@@ -368,8 +370,8 @@ private:
int visible_characters;
float percent_visible;
- int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL, int p_char_count = 0);
- void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL);
+ int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, int p_char_count = 0);
+ void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
Ref<Font> _find_font(Item *p_item);
int _find_margin(Item *p_item, const Ref<Font> &p_base_font);
@@ -377,7 +379,7 @@ private:
Color _find_color(Item *p_item, const Color &p_default_color);
bool _find_underline(Item *p_item);
bool _find_strikethrough(Item *p_item);
- bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = NULL);
+ bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr);
bool _find_layout_subitem(Item *from, Item *to);
bool _find_by_type(Item *p_item, ItemType p_type);
void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index fef5e00984..1c63c25e28 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -33,6 +33,7 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/print_string.h"
+#include "scene/main/window.h"
bool ScrollBar::focus_by_default = false;
@@ -71,8 +72,8 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
if (b->is_pressed()) {
double ofs = orientation == VERTICAL ? b->get_position().y : b->get_position().x;
- Ref<Texture2D> decr = get_icon("decrement");
- Ref<Texture2D> incr = get_icon("increment");
+ Ref<Texture2D> decr = get_theme_icon("decrement");
+ Ref<Texture2D> incr = get_theme_icon("increment");
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width();
@@ -148,7 +149,7 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
if (drag.active) {
double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x;
- Ref<Texture2D> decr = get_icon("decrement");
+ Ref<Texture2D> decr = get_theme_icon("decrement");
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
ofs -= decr_size;
@@ -159,8 +160,8 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
} else {
double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x;
- Ref<Texture2D> decr = get_icon("decrement");
- Ref<Texture2D> incr = get_icon("increment");
+ Ref<Texture2D> decr = get_theme_icon("decrement");
+ Ref<Texture2D> incr = get_theme_icon("increment");
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width();
@@ -233,17 +234,17 @@ void ScrollBar::_notification(int p_what) {
RID ci = get_canvas_item();
- Ref<Texture2D> decr = highlight == HIGHLIGHT_DECR ? get_icon("decrement_highlight") : get_icon("decrement");
- Ref<Texture2D> incr = highlight == HIGHLIGHT_INCR ? get_icon("increment_highlight") : get_icon("increment");
- Ref<StyleBox> bg = has_focus() ? get_stylebox("scroll_focus") : get_stylebox("scroll");
+ Ref<Texture2D> decr = highlight == HIGHLIGHT_DECR ? get_theme_icon("decrement_highlight") : get_theme_icon("decrement");
+ Ref<Texture2D> incr = highlight == HIGHLIGHT_INCR ? get_theme_icon("increment_highlight") : get_theme_icon("increment");
+ Ref<StyleBox> bg = has_focus() ? get_theme_stylebox("scroll_focus") : get_theme_stylebox("scroll");
Ref<StyleBox> grabber;
if (drag.active)
- grabber = get_stylebox("grabber_pressed");
+ grabber = get_theme_stylebox("grabber_pressed");
else if (highlight == HIGHLIGHT_RANGE)
- grabber = get_stylebox("grabber_highlight");
+ grabber = get_theme_stylebox("grabber_highlight");
else
- grabber = get_stylebox("grabber");
+ grabber = get_theme_stylebox("grabber");
Point2 ofs;
@@ -307,7 +308,7 @@ void ScrollBar::_notification(int p_what) {
drag_node->disconnect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit));
}
- drag_node = NULL;
+ drag_node = nullptr;
}
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
@@ -416,7 +417,7 @@ void ScrollBar::_notification(int p_what) {
double ScrollBar::get_grabber_min_size() const {
- Ref<StyleBox> grabber = get_stylebox("grabber");
+ Ref<StyleBox> grabber = get_theme_stylebox("grabber");
Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size();
return (orientation == VERTICAL) ? gminsize.height : gminsize.width;
}
@@ -442,17 +443,17 @@ double ScrollBar::get_area_size() const {
switch (orientation) {
case VERTICAL: {
double area = get_size().height;
- area -= get_stylebox("scroll")->get_minimum_size().height;
- area -= get_icon("increment")->get_height();
- area -= get_icon("decrement")->get_height();
+ area -= get_theme_stylebox("scroll")->get_minimum_size().height;
+ area -= get_theme_icon("increment")->get_height();
+ area -= get_theme_icon("decrement")->get_height();
area -= get_grabber_min_size();
return area;
} break;
case HORIZONTAL: {
double area = get_size().width;
- area -= get_stylebox("scroll")->get_minimum_size().width;
- area -= get_icon("increment")->get_width();
- area -= get_icon("decrement")->get_width();
+ area -= get_theme_stylebox("scroll")->get_minimum_size().width;
+ area -= get_theme_icon("increment")->get_width();
+ area -= get_theme_icon("decrement")->get_width();
area -= get_grabber_min_size();
return area;
} break;
@@ -468,14 +469,14 @@ double ScrollBar::get_area_offset() const {
if (orientation == VERTICAL) {
- ofs += get_stylebox("hscroll")->get_margin(MARGIN_TOP);
- ofs += get_icon("decrement")->get_height();
+ ofs += get_theme_stylebox("hscroll")->get_margin(MARGIN_TOP);
+ ofs += get_theme_icon("decrement")->get_height();
}
if (orientation == HORIZONTAL) {
- ofs += get_stylebox("hscroll")->get_margin(MARGIN_LEFT);
- ofs += get_icon("decrement")->get_width();
+ ofs += get_theme_stylebox("hscroll")->get_margin(MARGIN_LEFT);
+ ofs += get_theme_icon("decrement")->get_width();
}
return ofs;
@@ -500,9 +501,9 @@ double ScrollBar::get_grabber_offset() const {
Size2 ScrollBar::get_minimum_size() const {
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
- Ref<StyleBox> bg = get_stylebox("scroll");
+ Ref<Texture2D> incr = get_theme_icon("increment");
+ Ref<Texture2D> decr = get_theme_icon("decrement");
+ Ref<StyleBox> bg = get_theme_stylebox("scroll");
Size2 minsize;
if (orientation == VERTICAL) {
@@ -541,7 +542,7 @@ void ScrollBar::_drag_node_exit() {
if (drag_node) {
drag_node->disconnect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input));
}
- drag_node = NULL;
+ drag_node = nullptr;
}
void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) {
@@ -559,8 +560,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) {
drag_node_accum = Vector2();
last_drag_node_accum = Vector2();
drag_node_from = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0);
-
- drag_node_touching = OS::get_singleton()->has_touchscreen_ui_hint();
+ drag_node_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
drag_node_touching_deaccel = false;
time_since_motion = 0;
@@ -616,7 +616,7 @@ void ScrollBar::set_drag_node(const NodePath &p_path) {
}
}
- drag_node = NULL;
+ drag_node = nullptr;
drag_node_path = p_path;
if (is_inside_tree()) {
@@ -662,7 +662,7 @@ ScrollBar::ScrollBar(Orientation p_orientation) {
orientation = p_orientation;
highlight = HIGHLIGHT_NONE;
custom_step = -1;
- drag_node = NULL;
+ drag_node = nullptr;
drag.active = false;
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index c25a6d5a0c..fb17adf96e 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -30,7 +30,7 @@
#include "scroll_container.h"
#include "core/os/os.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
bool ScrollContainer::clips_input() const {
@@ -39,7 +39,7 @@ bool ScrollContainer::clips_input() const {
Size2 ScrollContainer::get_minimum_size() const {
- Ref<StyleBox> sb = get_stylebox("bg");
+ Ref<StyleBox> sb = get_theme_stylebox("bg");
Size2 min_size;
for (int i = 0; i < get_child_count(); i++) {
@@ -129,7 +129,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll)
accept_event(); //accept event if scroll changed
- if (!OS::get_singleton()->has_touchscreen_ui_hint())
+ if (!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())))
return;
if (mb->get_button_index() != BUTTON_LEFT)
@@ -145,7 +145,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
drag_accum = Vector2();
last_drag_accum = Vector2();
drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value());
- drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
+ drag_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
drag_touching_deaccel = false;
beyond_deadzone = false;
time_since_motion = 0;
@@ -276,7 +276,7 @@ void ScrollContainer::_notification(int p_what) {
Size2 size = get_size();
Point2 ofs;
- Ref<StyleBox> sb = get_stylebox("bg");
+ Ref<StyleBox> sb = get_theme_stylebox("bg");
size -= sb->get_minimum_size();
ofs += sb->get_offset();
@@ -323,7 +323,7 @@ void ScrollContainer::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<StyleBox> sb = get_stylebox("bg");
+ Ref<StyleBox> sb = get_theme_stylebox("bg");
draw_style_box(sb, Rect2(Vector2(), get_size()));
update_scrollbars();
@@ -404,7 +404,7 @@ void ScrollContainer::_notification(int p_what) {
void ScrollContainer::update_scrollbars() {
Size2 size = get_size();
- Ref<StyleBox> sb = get_stylebox("bg");
+ Ref<StyleBox> sb = get_theme_stylebox("bg");
size -= sb->get_minimum_size();
Size2 hmin;
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index 4635efb233..75c4b7cce9 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -34,9 +34,9 @@ Size2 Separator::get_minimum_size() const {
Size2 ms(3, 3);
if (orientation == VERTICAL) {
- ms.x = get_constant("separation");
+ ms.x = get_theme_constant("separation");
} else { // HORIZONTAL
- ms.y = get_constant("separation");
+ ms.y = get_theme_constant("separation");
}
return ms;
}
@@ -48,7 +48,7 @@ void Separator::_notification(int p_what) {
case NOTIFICATION_DRAW: {
Size2i size = get_size();
- Ref<StyleBox> style = get_stylebox("separator");
+ Ref<StyleBox> style = get_theme_stylebox("separator");
Size2i ssize = style->get_minimum_size() + style->get_center_size();
if (orientation == VERTICAL) {
diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h
index 59d3245db5..b22c3441c5 100644
--- a/scene/gui/shortcut.h
+++ b/scene/gui/shortcut.h
@@ -31,7 +31,7 @@
#ifndef SHORTCUT_H
#define SHORTCUT_H
-#include "core/os/input_event.h"
+#include "core/input/input_event.h"
#include "core/resource.h"
class ShortCut : public Resource {
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 85887ef7b1..1f135163d4 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -33,10 +33,10 @@
Size2 Slider::get_minimum_size() const {
- Ref<StyleBox> style = get_stylebox("slider");
+ Ref<StyleBox> style = get_theme_stylebox("slider");
Size2i ss = style->get_minimum_size() + style->get_center_size();
- Ref<Texture2D> grabber = get_icon("grabber");
+ Ref<Texture2D> grabber = get_theme_icon("grabber");
Size2i rs = grabber->get_size();
if (orientation == HORIZONTAL)
@@ -57,7 +57,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
if (mb->get_button_index() == BUTTON_LEFT) {
if (mb->is_pressed()) {
- Ref<Texture2D> grabber = get_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber");
+ 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;
double grab_width = (double)grabber->get_size().width;
@@ -87,7 +87,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
if (grab.active) {
Size2i size = get_size();
- Ref<Texture2D> grabber = get_icon("grabber");
+ Ref<Texture2D> grabber = get_theme_icon("grabber");
float motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos;
if (orientation == VERTICAL)
motion = -motion;
@@ -165,10 +165,11 @@ void Slider::_notification(int p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Size2i size = get_size();
- Ref<StyleBox> style = get_stylebox("slider");
- Ref<StyleBox> grabber_area = get_stylebox("grabber_area");
- Ref<Texture2D> grabber = get_icon(editable ? ((mouse_inside || has_focus()) ? "grabber_highlight" : "grabber") : "grabber_disabled");
- Ref<Texture2D> tick = get_icon("tick");
+ Ref<StyleBox> style = get_theme_stylebox("slider");
+ bool highlighted = mouse_inside || has_focus();
+ Ref<StyleBox> grabber_area = get_theme_stylebox(highlighted ? "grabber_area_highlight" : "grabber_area");
+ Ref<Texture2D> grabber = get_theme_icon(editable ? (highlighted ? "grabber_highlight" : "grabber") : "grabber_disabled");
+ Ref<Texture2D> tick = get_theme_icon("tick");
double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio();
if (orientation == VERTICAL) {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 576de98a4f..8572d570fb 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -29,8 +29,9 @@
/*************************************************************************/
#include "spin_box.h"
+
+#include "core/input/input_filter.h"
#include "core/math/expression.h"
-#include "core/os/input.h"
Size2 SpinBox::get_minimum_size() const {
@@ -59,7 +60,7 @@ void SpinBox::_text_entered(const String &p_string) {
return;
}
- Variant value = expr->execute(Array(), NULL, false);
+ Variant value = expr->execute(Array(), nullptr, false);
if (value.get_type() != Variant::NIL) {
set_value(value);
_value_changed(0);
@@ -76,7 +77,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 && InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
bool up = get_local_mouse_position().y < (get_size().height / 2);
set_value(get_value() + (up ? get_step() : -get_step()));
@@ -148,7 +149,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
if (drag.enabled) {
drag.enabled = false;
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE);
warp_mouse(drag.capture_pos);
}
drag.allowed = false;
@@ -165,7 +166,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
set_value(CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max()));
} else if (drag.allowed && drag.capture_pos.distance_to(mm->get_position()) > 2) {
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_CAPTURED);
drag.enabled = true;
drag.base_val = get_value();
drag.diff_y = 0;
@@ -195,7 +196,7 @@ void SpinBox::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- Ref<Texture2D> updown = get_icon("updown");
+ Ref<Texture2D> updown = get_theme_icon("updown");
_adjust_width_for_icon(updown);
@@ -209,7 +210,7 @@ void SpinBox::_notification(int p_what) {
//_value_changed(0);
} else if (p_what == NOTIFICATION_ENTER_TREE) {
- _adjust_width_for_icon(get_icon("updown"));
+ _adjust_width_for_icon(get_theme_icon("updown"));
_value_changed(0);
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 255278be2b..de892a4fb9 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -50,7 +50,7 @@ Control *SplitContainer::_getch(int p_idx) const {
idx++;
}
- return NULL;
+ return nullptr;
}
void SplitContainer::_resort() {
@@ -74,8 +74,8 @@ void SplitContainer::_resort() {
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
// Determine the separation between items
- Ref<Texture2D> g = get_icon("grabber");
- int sep = get_constant("separation");
+ Ref<Texture2D> g = get_theme_icon("grabber");
+ int sep = get_theme_constant("separation");
sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
// Compute the minimum size
@@ -123,8 +123,8 @@ Size2 SplitContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
- Ref<Texture2D> g = get_icon("grabber");
- int sep = get_constant("separation");
+ Ref<Texture2D> g = get_theme_icon("grabber");
+ int sep = get_theme_constant("separation");
sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
for (int i = 0; i < 2; i++) {
@@ -167,7 +167,7 @@ void SplitContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
mouse_inside = false;
- if (get_constant("autohide"))
+ if (get_theme_constant("autohide"))
update();
} break;
case NOTIFICATION_DRAW: {
@@ -175,14 +175,14 @@ void SplitContainer::_notification(int p_what) {
if (!_getch(0) || !_getch(1))
return;
- if (collapsed || (!dragging && !mouse_inside && get_constant("autohide")))
+ if (collapsed || (!dragging && !mouse_inside && get_theme_constant("autohide")))
return;
if (dragger_visibility != DRAGGER_VISIBLE)
return;
- int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0;
- Ref<Texture2D> tex = get_icon("grabber");
+ int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant("separation") : 0;
+ Ref<Texture2D> tex = get_theme_icon("grabber");
Size2 size = get_size();
if (vertical)
@@ -210,7 +210,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->is_pressed()) {
- int sep = get_constant("separation");
+ int sep = get_theme_constant("separation");
if (vertical) {
@@ -242,14 +242,14 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
bool mouse_inside_state = false;
if (vertical)
- mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_constant("separation");
+ mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_theme_constant("separation");
else
- mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_constant("separation");
+ mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_theme_constant("separation");
if (mouse_inside != mouse_inside_state) {
mouse_inside = mouse_inside_state;
- if (get_constant("autohide"))
+ if (get_theme_constant("autohide"))
update();
}
@@ -270,7 +270,7 @@ Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const
if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) {
- int sep = get_constant("separation");
+ int sep = get_theme_constant("separation");
if (vertical) {
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
new file mode 100644
index 0000000000..50f468741d
--- /dev/null
+++ b/scene/gui/subviewport_container.cpp
@@ -0,0 +1,215 @@
+/*************************************************************************/
+/* subviewport_container.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "subviewport_container.h"
+
+#include "core/engine.h"
+#include "scene/main/viewport.h"
+
+Size2 SubViewportContainer::get_minimum_size() const {
+
+ if (stretch)
+ return Size2();
+ Size2 ms;
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c)
+ continue;
+
+ Size2 minsize = c->get_size();
+ ms.width = MAX(ms.width, minsize.width);
+ ms.height = MAX(ms.height, minsize.height);
+ }
+
+ return ms;
+}
+
+void SubViewportContainer::set_stretch(bool p_enable) {
+
+ stretch = p_enable;
+ queue_sort();
+ update();
+}
+
+bool SubViewportContainer::is_stretch_enabled() const {
+
+ return stretch;
+}
+
+void SubViewportContainer::set_stretch_shrink(int p_shrink) {
+
+ ERR_FAIL_COND(p_shrink < 1);
+ if (shrink == p_shrink)
+ return;
+
+ shrink = p_shrink;
+
+ if (!stretch)
+ return;
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c)
+ continue;
+
+ c->set_size(get_size() / shrink);
+ }
+
+ update();
+}
+
+int SubViewportContainer::get_stretch_shrink() const {
+
+ return shrink;
+}
+
+void SubViewportContainer::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_RESIZED) {
+
+ if (!stretch)
+ return;
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c)
+ continue;
+
+ c->set_size(get_size() / shrink);
+ }
+ }
+
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c)
+ continue;
+
+ if (is_visible_in_tree())
+ c->set_update_mode(SubViewport::UPDATE_ALWAYS);
+ else
+ c->set_update_mode(SubViewport::UPDATE_DISABLED);
+
+ c->set_handle_input_locally(false); //do not handle input locally here
+ }
+ }
+
+ if (p_what == NOTIFICATION_DRAW) {
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c)
+ continue;
+
+ if (stretch)
+ draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size()));
+ else
+ draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size()));
+ }
+ }
+}
+
+void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
+
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
+ Transform2D xform = get_global_transform();
+
+ if (stretch) {
+ Transform2D scale_xf;
+ scale_xf.scale(Vector2(shrink, shrink));
+ xform *= scale_xf;
+ }
+
+ Ref<InputEvent> ev = p_event->xformed_by(xform.affine_inverse());
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c || c->is_input_disabled())
+ continue;
+
+ c->input(ev);
+ }
+}
+
+void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) {
+
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
+ Transform2D xform = get_global_transform();
+
+ if (stretch) {
+ Transform2D scale_xf;
+ scale_xf.scale(Vector2(shrink, shrink));
+ xform *= scale_xf;
+ }
+
+ Ref<InputEvent> ev = p_event->xformed_by(xform.affine_inverse());
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ SubViewport *c = Object::cast_to<SubViewport>(get_child(i));
+ if (!c || c->is_input_disabled())
+ continue;
+
+ c->unhandled_input(ev);
+ }
+}
+
+void SubViewportContainer::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_unhandled_input", "event"), &SubViewportContainer::_unhandled_input);
+ ClassDB::bind_method(D_METHOD("_input", "event"), &SubViewportContainer::_input);
+ ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &SubViewportContainer::set_stretch);
+ ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &SubViewportContainer::is_stretch_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_stretch_shrink", "amount"), &SubViewportContainer::set_stretch_shrink);
+ ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink");
+}
+
+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
new file mode 100644
index 0000000000..6ff3d188e2
--- /dev/null
+++ b/scene/gui/subviewport_container.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* subviewport_container.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VIEWPORTCONTAINER_H
+#define VIEWPORTCONTAINER_H
+
+#include "scene/gui/container.h"
+
+class SubViewportContainer : public Container {
+
+ GDCLASS(SubViewportContainer, Container);
+
+ bool stretch;
+ int shrink;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_stretch(bool p_enable);
+ bool is_stretch_enabled() const;
+
+ void _input(const Ref<InputEvent> &p_event);
+ void _unhandled_input(const Ref<InputEvent> &p_event);
+ void set_stretch_shrink(int p_shrink);
+ int get_stretch_shrink() const;
+
+ virtual Size2 get_minimum_size() const;
+
+ SubViewportContainer();
+};
+
+#endif // VIEWPORTCONTAINER_H
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 6290d364fc..3a128cf8e6 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -41,14 +41,14 @@ int TabContainer::_get_top_margin() const {
return 0;
// Respect the minimum tab height.
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
int tab_height = MAX(MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height), tab_disabled->get_minimum_size().height);
// Font height or higher icon wins.
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
int content_height = font->get_height();
Vector<Control *> tabs = _get_tabs();
@@ -81,15 +81,15 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
return;
// Handle menu button.
- Ref<Texture2D> menu = get_icon("menu");
+ Ref<Texture2D> menu = get_theme_icon("menu");
if (popup && pos.x > size.width - menu->get_width()) {
emit_signal("pre_popup_pressed");
- Vector2 popup_pos = get_global_position();
- popup_pos.x += size.width * get_global_transform().get_scale().x - popup->get_size().width * popup->get_global_transform().get_scale().x;
- popup_pos.y += menu->get_height() * get_global_transform().get_scale().y;
+ Vector2 popup_pos = get_screen_position();
+ popup_pos.x += size.width - popup->get_size().width;
+ popup_pos.y += menu->get_height();
- popup->set_global_position(popup_pos);
+ popup->set_position(popup_pos);
popup->popup();
return;
}
@@ -107,8 +107,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
popup_ofs = menu->get_width();
}
- Ref<Texture2D> increment = get_icon("increment");
- Ref<Texture2D> decrement = get_icon("decrement");
+ Ref<Texture2D> increment = get_theme_icon("increment");
+ Ref<Texture2D> decrement = get_theme_icon("decrement");
if (pos.x > size.width - increment->get_width() - popup_ofs) {
if (last_tab_cache < tabs.size() - 1) {
first_tab_cache += 1;
@@ -159,7 +159,7 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- Ref<Texture2D> menu = get_icon("menu");
+ Ref<Texture2D> menu = get_theme_icon("menu");
if (popup) {
if (pos.x >= size.width - menu->get_width()) {
@@ -191,8 +191,8 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
popup_ofs = menu->get_width();
}
- Ref<Texture2D> increment = get_icon("increment");
- Ref<Texture2D> decrement = get_icon("decrement");
+ Ref<Texture2D> increment = get_theme_icon("increment");
+ Ref<Texture2D> decrement = get_theme_icon("decrement");
if (pos.x >= size.width - increment->get_width() - popup_ofs) {
if (highlight_arrow != 1) {
@@ -224,10 +224,10 @@ void TabContainer::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
Vector<Control *> tabs = _get_tabs();
- int side_margin = get_constant("side_margin");
- Ref<Texture2D> menu = get_icon("menu");
- Ref<Texture2D> increment = get_icon("increment");
- Ref<Texture2D> decrement = get_icon("decrement");
+ int side_margin = get_theme_constant("side_margin");
+ Ref<Texture2D> menu = get_theme_icon("menu");
+ Ref<Texture2D> increment = get_theme_icon("increment");
+ Ref<Texture2D> decrement = get_theme_icon("decrement");
int header_width = get_size().width - side_margin * 2;
// Find the width of the header area.
@@ -262,28 +262,28 @@ void TabContainer::_notification(int p_what) {
Size2 size = get_size();
// Draw only the tab area if the header is hidden.
- Ref<StyleBox> panel = get_stylebox("panel");
+ Ref<StyleBox> panel = get_theme_stylebox("panel");
if (!tabs_visible) {
panel->draw(canvas, Rect2(0, 0, size.width, size.height));
return;
}
Vector<Control *> tabs = _get_tabs();
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
- Ref<Texture2D> increment = get_icon("increment");
- Ref<Texture2D> increment_hl = get_icon("increment_highlight");
- Ref<Texture2D> decrement = get_icon("decrement");
- Ref<Texture2D> decrement_hl = get_icon("decrement_highlight");
- Ref<Texture2D> menu = get_icon("menu");
- Ref<Texture2D> menu_hl = get_icon("menu_highlight");
- Ref<Font> font = get_font("font");
- Color font_color_fg = get_color("font_color_fg");
- Color font_color_bg = get_color("font_color_bg");
- Color font_color_disabled = get_color("font_color_disabled");
- int side_margin = get_constant("side_margin");
- int icon_text_distance = get_constant("hseparation");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
+ Ref<Texture2D> increment = get_theme_icon("increment");
+ Ref<Texture2D> increment_hl = get_theme_icon("increment_highlight");
+ Ref<Texture2D> decrement = get_theme_icon("decrement");
+ Ref<Texture2D> decrement_hl = get_theme_icon("decrement_highlight");
+ Ref<Texture2D> menu = get_theme_icon("menu");
+ Ref<Texture2D> menu_hl = get_theme_icon("menu_highlight");
+ Ref<Font> font = get_theme_font("font");
+ Color font_color_fg = get_theme_color("font_color_fg");
+ Color font_color_bg = get_theme_color("font_color_bg");
+ Color font_color_disabled = get_theme_color("font_color_disabled");
+ int side_margin = get_theme_constant("side_margin");
+ int icon_text_distance = get_theme_constant("hseparation");
// Find out start and width of the header area.
int header_x = side_margin;
@@ -458,7 +458,7 @@ int TabContainer::_get_tab_width(int p_index) const {
return 0;
// Get the width of the text displayed on the tab.
- Ref<Font> font = get_font("font");
+ Ref<Font> font = get_theme_font("font");
String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(control->get_name());
int width = font->get_string_size(text).width;
@@ -468,14 +468,14 @@ int TabContainer::_get_tab_width(int p_index) const {
if (icon.is_valid()) {
width += icon->get_width();
if (text != "")
- width += get_constant("hseparation");
+ width += get_theme_constant("hseparation");
}
}
// Respect a minimum size.
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
if (get_tab_disabled(p_index)) {
width += tab_disabled->get_minimum_size().width;
} else if (p_index == current) {
@@ -530,7 +530,7 @@ void TabContainer::add_child_notify(Node *p_child) {
c->set_anchors_and_margins_preset(Control::PRESET_WIDE);
if (tabs_visible)
c->set_margin(MARGIN_TOP, _get_top_margin());
- Ref<StyleBox> sb = get_stylebox("panel");
+ Ref<StyleBox> sb = get_theme_stylebox("panel");
c->set_margin(Margin(MARGIN_TOP), c->get_margin(Margin(MARGIN_TOP)) + sb->get_margin(Margin(MARGIN_TOP)));
c->set_margin(Margin(MARGIN_LEFT), c->get_margin(Margin(MARGIN_LEFT)) + sb->get_margin(Margin(MARGIN_LEFT)));
c->set_margin(Margin(MARGIN_RIGHT), c->get_margin(Margin(MARGIN_RIGHT)) - sb->get_margin(Margin(MARGIN_RIGHT)));
@@ -554,7 +554,7 @@ void TabContainer::set_current_tab(int p_current) {
int pending_previous = current;
current = p_current;
- Ref<StyleBox> sb = get_stylebox("panel");
+ Ref<StyleBox> sb = get_theme_stylebox("panel");
Vector<Control *> tabs = _get_tabs();
for (int i = 0; i < tabs.size(); i++) {
@@ -602,7 +602,7 @@ Control *TabContainer::get_tab_control(int p_idx) const {
if (p_idx >= 0 && p_idx < tabs.size())
return tabs[p_idx];
else
- return NULL;
+ return nullptr;
}
Control *TabContainer::get_current_tab_control() const {
@@ -611,7 +611,7 @@ Control *TabContainer::get_current_tab_control() const {
if (current >= 0 && current < tabs.size())
return tabs[current];
else
- return NULL;
+ return nullptr;
}
void TabContainer::remove_child_notify(Node *p_child) {
@@ -745,12 +745,12 @@ int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const {
int right_ofs = 0;
if (popup) {
- Ref<Texture2D> menu = get_icon("menu");
+ Ref<Texture2D> menu = get_theme_icon("menu");
right_ofs += menu->get_width();
}
if (buttons_visible_cache) {
- Ref<Texture2D> increment = get_icon("increment");
- Ref<Texture2D> decrement = get_icon("decrement");
+ Ref<Texture2D> increment = get_theme_icon("increment");
+ Ref<Texture2D> decrement = get_theme_icon("decrement");
right_ofs += increment->get_width() + decrement->get_width();
}
if (p_point.x > size.width - right_ofs) {
@@ -933,17 +933,17 @@ Size2 TabContainer::get_minimum_size() const {
ms.y = MAX(ms.y, cms.y);
}
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
- Ref<Font> font = get_font("font");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
+ Ref<Font> font = get_theme_font("font");
if (tabs_visible) {
ms.y += MAX(MAX(tab_bg->get_minimum_size().y, tab_fg->get_minimum_size().y), tab_disabled->get_minimum_size().y);
ms.y += font->get_height();
}
- Ref<StyleBox> sb = get_stylebox("panel");
+ Ref<StyleBox> sb = get_theme_stylebox("panel");
ms += sb->get_minimum_size();
return ms;
@@ -990,7 +990,7 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_current_tab"), &TabContainer::get_current_tab);
ClassDB::bind_method(D_METHOD("get_previous_tab"), &TabContainer::get_previous_tab);
ClassDB::bind_method(D_METHOD("get_current_tab_control"), &TabContainer::get_current_tab_control);
- ClassDB::bind_method(D_METHOD("get_tab_control", "idx"), &TabContainer::get_tab_control);
+ ClassDB::bind_method(D_METHOD("get_tab_control", "tab_idx"), &TabContainer::get_tab_control);
ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &TabContainer::set_tab_align);
ClassDB::bind_method(D_METHOD("get_tab_align"), &TabContainer::get_tab_align);
ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible);
@@ -1041,7 +1041,7 @@ TabContainer::TabContainer() {
previous = 0;
align = ALIGN_CENTER;
tabs_visible = true;
- popup = NULL;
+ popup = nullptr;
drag_to_rearrange_enabled = false;
tabs_rearrange_group = -1;
use_hidden_tabs_for_min_size = false;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 901408919a..1a3b53f489 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -37,10 +37,10 @@
Size2 Tabs::get_minimum_size() const {
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
- Ref<Font> font = get_font("font");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
+ Ref<Font> font = get_theme_font("font");
Size2 ms(0, MAX(MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height), tab_disabled->get_minimum_size().height) + font->get_height());
@@ -50,7 +50,7 @@ Size2 Tabs::get_minimum_size() const {
if (tex.is_valid()) {
ms.height = MAX(ms.height, tex->get_size().height);
if (tabs[i].text != "")
- ms.width += get_constant("hseparation");
+ ms.width += get_theme_constant("hseparation");
}
ms.width += Math::ceil(font->get_string_size(tabs[i].xl_text).width);
@@ -65,15 +65,15 @@ Size2 Tabs::get_minimum_size() const {
if (tabs[i].right_button.is_valid()) {
Ref<Texture2D> rb = tabs[i].right_button;
Size2 bms = rb->get_size();
- bms.width += get_constant("hseparation");
+ bms.width += get_theme_constant("hseparation");
ms.width += bms.width;
ms.height = MAX(bms.height + tab_bg->get_minimum_size().height, ms.height);
}
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) {
- Ref<Texture2D> cb = get_icon("close");
+ Ref<Texture2D> cb = get_theme_icon("close");
Size2 bms = cb->get_size();
- bms.width += get_constant("hseparation");
+ bms.width += get_theme_constant("hseparation");
ms.width += bms.width;
ms.height = MAX(bms.height + tab_bg->get_minimum_size().height, ms.height);
}
@@ -94,8 +94,8 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
highlight_arrow = -1;
if (buttons_visible) {
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
+ 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();
@@ -163,8 +163,8 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
if (buttons_visible) {
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
+ 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();
@@ -184,10 +184,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
int found = -1;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset)
- continue;
+ for (int i = offset; i < tabs.size(); i++) {
if (tabs[i].rb_rect.has_point(pos)) {
rb_pressing = true;
@@ -238,14 +235,14 @@ void Tabs::_notification(int p_what) {
_update_cache();
RID ci = get_canvas_item();
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
- Ref<Font> font = get_font("font");
- Color color_fg = get_color("font_color_fg");
- Color color_bg = get_color("font_color_bg");
- Color color_disabled = get_color("font_color_disabled");
- Ref<Texture2D> close = get_icon("close");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
+ Ref<Font> font = get_theme_font("font");
+ Color color_fg = get_theme_color("font_color_fg");
+ Color color_bg = get_theme_color("font_color_bg");
+ Color color_disabled = get_theme_color("font_color_disabled");
+ Ref<Texture2D> close = get_theme_icon("close");
int h = get_size().height;
int w = 0;
@@ -267,19 +264,16 @@ void Tabs::_notification(int p_what) {
w = 0;
}
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
- Ref<Texture2D> incr_hl = get_icon("increment_highlight");
- Ref<Texture2D> decr_hl = get_icon("decrement_highlight");
+ Ref<Texture2D> incr = get_theme_icon("increment");
+ Ref<Texture2D> decr = get_theme_icon("decrement");
+ 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;
missing_right = false;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset)
- continue;
+ for (int i = offset; i < tabs.size(); i++) {
tabs.write[i].ofs_cache = w;
@@ -318,7 +312,7 @@ void Tabs::_notification(int p_what) {
icon->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2));
if (tabs[i].text != "")
- w += icon->get_width() + get_constant("hseparation");
+ w += icon->get_width() + get_theme_constant("hseparation");
}
font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].xl_text, col, tabs[i].size_text);
@@ -327,10 +321,10 @@ void Tabs::_notification(int p_what) {
if (tabs[i].right_button.is_valid()) {
- Ref<StyleBox> style = get_stylebox("button");
+ Ref<StyleBox> style = get_theme_stylebox("button");
Ref<Texture2D> rb = tabs[i].right_button;
- w += get_constant("hseparation");
+ w += get_theme_constant("hseparation");
Rect2 rb_rect;
rb_rect.size = style->get_minimum_size() + rb->get_size();
@@ -339,7 +333,7 @@ void Tabs::_notification(int p_what) {
if (rb_hover == i) {
if (rb_pressing)
- get_stylebox("button_pressed")->draw(ci, rb_rect);
+ get_theme_stylebox("button_pressed")->draw(ci, rb_rect);
else
style->draw(ci, rb_rect);
}
@@ -351,10 +345,10 @@ void Tabs::_notification(int p_what) {
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) {
- Ref<StyleBox> style = get_stylebox("button");
+ Ref<StyleBox> style = get_theme_stylebox("button");
Ref<Texture2D> cb = close;
- w += get_constant("hseparation");
+ w += get_theme_constant("hseparation");
Rect2 cb_rect;
cb_rect.size = style->get_minimum_size() + cb->get_size();
@@ -363,7 +357,7 @@ void Tabs::_notification(int p_what) {
if (!tabs[i].disabled && cb_hover == i) {
if (cb_pressing)
- get_stylebox("button_pressed")->draw(ci, cb_rect);
+ get_theme_stylebox("button_pressed")->draw(ci, cb_rect);
else
style->draw(ci, cb_rect);
}
@@ -499,10 +493,7 @@ void Tabs::_update_hover() {
// test hovering to display right or close button
int hover_now = -1;
int hover_buttons = -1;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset)
- continue;
+ for (int i = offset; i < tabs.size(); i++) {
Rect2 rect = get_tab_rect(i);
if (rect.has_point(pos)) {
@@ -532,12 +523,12 @@ void Tabs::_update_hover() {
}
void Tabs::_update_cache() {
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<Font> font = get_font("font");
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<Font> font = get_theme_font("font");
+ 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 w = 0;
@@ -559,9 +550,8 @@ void Tabs::_update_cache() {
if (count_resize > 0) {
m_width = MAX((limit - size_fixed) / count_resize, min_width);
}
- for (int i = 0; i < tabs.size(); i++) {
- if (i < offset)
- continue;
+ for (int i = offset; i < tabs.size(); i++) {
+
Ref<StyleBox> sb;
if (tabs[i].disabled) {
sb = tab_disabled;
@@ -577,12 +567,12 @@ void Tabs::_update_cache() {
slen = m_width - (sb->get_margin(MARGIN_LEFT) + sb->get_margin(MARGIN_RIGHT));
if (tabs[i].icon.is_valid()) {
slen -= tabs[i].icon->get_width();
- slen -= get_constant("hseparation");
+ slen -= get_theme_constant("hseparation");
}
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) {
- Ref<Texture2D> cb = get_icon("close");
+ Ref<Texture2D> cb = get_theme_icon("close");
slen -= cb->get_width();
- slen -= get_constant("hseparation");
+ slen -= get_theme_constant("hseparation");
}
slen = MAX(slen, 1);
lsize = m_width;
@@ -753,10 +743,7 @@ void Tabs::drop_data(const Point2 &p_point, const Variant &p_data) {
int Tabs::get_tab_idx_at_point(const Point2 &p_point) const {
int hover_now = -1;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset)
- continue;
+ for (int i = offset; i < tabs.size(); i++) {
Rect2 rect = get_tab_rect(i);
if (rect.has_point(p_point)) {
@@ -799,10 +786,10 @@ int Tabs::get_tab_width(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0);
- Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
- Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
- Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
- Ref<Font> font = get_font("font");
+ Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg");
+ Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled");
+ Ref<Font> font = get_theme_font("font");
int x = 0;
@@ -810,7 +797,7 @@ int Tabs::get_tab_width(int p_idx) const {
if (tex.is_valid()) {
x += tex->get_width();
if (tabs[p_idx].text != "")
- x += get_constant("hseparation");
+ x += get_theme_constant("hseparation");
}
x += Math::ceil(font->get_string_size(tabs[p_idx].xl_text).width);
@@ -825,13 +812,13 @@ int Tabs::get_tab_width(int p_idx) const {
if (tabs[p_idx].right_button.is_valid()) {
Ref<Texture2D> rb = tabs[p_idx].right_button;
x += rb->get_width();
- x += get_constant("hseparation");
+ x += get_theme_constant("hseparation");
}
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current)) {
- Ref<Texture2D> cb = get_icon("close");
+ Ref<Texture2D> cb = get_theme_icon("close");
x += cb->get_width();
- x += get_constant("hseparation");
+ x += get_theme_constant("hseparation");
}
return x;
@@ -842,18 +829,15 @@ void Tabs::_ensure_no_over_offset() {
if (!is_inside_tree())
return;
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
+ 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();
while (offset > 0) {
int total_w = 0;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset - 1)
- continue;
+ for (int i = offset - 1; i < tabs.size(); i++) {
total_w += tabs[i].size_cache;
}
@@ -885,8 +869,8 @@ void Tabs::ensure_tab_visible(int p_idx) {
}
int prev_offset = offset;
- Ref<Texture2D> incr = get_icon("increment");
- Ref<Texture2D> decr = get_icon("decrement");
+ 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();
for (int i = offset; i <= p_idx; i++) {
if (tabs[i].ofs_cache + tabs[i].size_cache > limit) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 784a6afc7b..36e35897d1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -30,13 +30,13 @@
#include "text_edit.h"
+#include "core/input/input_filter.h"
#include "core/message_queue.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "core/script_language.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
@@ -446,7 +446,7 @@ 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
// 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 != Selection::MODE_NONE) {
+ if (InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) {
switch (selection.selecting_mode) {
case Selection::MODE_POINTER: {
_update_selection_mode_pointer();
@@ -639,12 +639,12 @@ void TextEdit::_notification(int p_what) {
_update_wrap_at();
syntax_highlighting_cache.clear();
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_FOCUS_IN: {
window_has_focus = true;
draw_caret = true;
update();
} break;
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_WM_FOCUS_OUT: {
window_has_focus = false;
draw_caret = false;
update();
@@ -728,7 +728,7 @@ void TextEdit::_notification(int p_what) {
_update_scrollbars();
RID ci = get_canvas_item();
- VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
+ RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width;
int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT) - cache.minimap_width;
@@ -749,14 +749,14 @@ void TextEdit::_notification(int p_what) {
if (syntax_coloring) {
if (cache.background_color.a > 0.01) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), cache.background_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), cache.background_color);
}
}
if (line_length_guidelines) {
const int hard_x = xmargin_beg + (int)cache.font->get_char_size('0').width * line_length_guideline_hard_col - cursor.x_ofs;
if (hard_x > xmargin_beg && hard_x < xmargin_end) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(hard_x, 0), Point2(hard_x, size.height), cache.line_length_guideline_color);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2(hard_x, 0), Point2(hard_x, size.height), cache.line_length_guideline_color);
}
// Draw a "Soft" line length guideline, less visible than the hard line length guideline.
@@ -764,7 +764,7 @@ void TextEdit::_notification(int p_what) {
// Only drawn if its column differs from the hard line length guideline.
const int soft_x = xmargin_beg + (int)cache.font->get_char_size('0').width * line_length_guideline_soft_col - cursor.x_ofs;
if (hard_x != soft_x && soft_x > xmargin_beg && soft_x < xmargin_end) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(soft_x, 0), Point2(soft_x, size.height), cache.line_length_guideline_color * Color(1, 1, 1, 0.5));
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2(soft_x, 0), Point2(soft_x, size.height), cache.line_length_guideline_color * Color(1, 1, 1, 0.5));
}
}
@@ -955,7 +955,7 @@ void TextEdit::_notification(int p_what) {
// draw the minimap
Color viewport_color = (cache.background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, cache.minimap_width, viewport_height), viewport_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, cache.minimap_width, viewport_height), viewport_color);
for (int i = 0; i < minimap_draw_amount; i++) {
minimap_line++;
@@ -1008,7 +1008,7 @@ void TextEdit::_notification(int p_what) {
}
if (minimap_line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), cache.current_line_color);
}
Color previous_color;
@@ -1057,7 +1057,7 @@ void TextEdit::_notification(int p_what) {
// take one for zero indexing, and if we hit whitespace / the end of a word.
int chars = MAX(0, (j - (characters - 1)) - (is_whitespace ? 1 : 0)) + 1;
int char_x_ofs = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * chars)) + tabs;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_x_ofs, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_x_ofs, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color);
}
if (out_of_bounds) {
@@ -1164,24 +1164,24 @@ void TextEdit::_notification(int p_what) {
}
if (text.is_marked(line)) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
}
if (str.length() == 0) {
// Draw line background if empty as we won't loop at at all.
if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
}
// 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(' ').width;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color);
}
} else {
// If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later.
if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg + ofs_x, get_row_height()), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg + ofs_x, get_row_height()), cache.current_line_color);
}
}
@@ -1190,9 +1190,9 @@ void TextEdit::_notification(int p_what) {
if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
#ifdef TOOLS_ENABLED
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
#else
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
#endif
}
@@ -1202,7 +1202,7 @@ void TextEdit::_notification(int p_what) {
int vertical_gap = (get_row_height() * 40) / 100;
int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
int marker_radius = get_row_height() - (vertical_gap * 2);
- VisualServer::get_singleton()->canvas_item_add_circle(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 + marker_radius / 2, ofs_y + vertical_gap + marker_radius / 2), marker_radius, Color(cache.bookmark_color.r, cache.bookmark_color.g, cache.bookmark_color.b));
+ RenderingServer::get_singleton()->canvas_item_add_circle(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 + marker_radius / 2, ofs_y + vertical_gap + marker_radius / 2), marker_radius, Color(cache.bookmark_color.r, cache.bookmark_color.g, cache.bookmark_color.b));
}
}
@@ -1214,7 +1214,7 @@ void TextEdit::_notification(int p_what) {
int marker_height = get_row_height() - (vertical_gap * 2);
int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2);
// No transparency on marker.
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b));
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b));
}
}
@@ -1254,9 +1254,9 @@ void TextEdit::_notification(int p_what) {
cache.executing_icon->draw_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2 - icon_extra_size / 2, ofs_y + vertical_gap - icon_extra_size / 2, marker_width, marker_height), false, Color(cache.executing_line_color.r, cache.executing_line_color.g, cache.executing_line_color.b));
} else {
#ifdef TOOLS_ENABLED
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.executing_line_color);
#else
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.executing_line_color);
#endif
}
}
@@ -1315,10 +1315,10 @@ void TextEdit::_notification(int p_what) {
if (j == str.length() - 1) {
// End of line when last char is skipped.
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
} else if ((char_ofs + char_margin) > xmargin_beg) {
// Char next to margin is skipped.
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, (char_ofs + char_margin) - (xmargin_beg + ofs_x), get_row_height()), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, (char_ofs + char_margin) - (xmargin_beg + ofs_x), get_row_height()), cache.current_line_color);
}
}
continue;
@@ -1338,7 +1338,7 @@ void TextEdit::_notification(int p_what) {
in_search_result = j >= search_text_col && j < search_text_col + search_text.length();
if (in_search_result) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.search_result_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.search_result_color);
}
}
@@ -1348,32 +1348,32 @@ void TextEdit::_notification(int p_what) {
if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
// Draw the wrap indent offset highlight.
if (line_wrap_index != 0 && j == 0) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + ofs_x - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + ofs_x - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color);
}
// If its the last char draw to end of the line.
if (j == str.length() - 1) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
}
// Actual text.
if (!in_selection) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
}
}
if (in_selection) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color);
}
if (in_search_result) {
Color border_color = (line == search_result_line && j >= search_result_col && j < search_result_col + search_text.length()) ? cache.font_color : cache.search_result_border_color;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color);
if (j == search_text_col)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color);
if (j == search_text_col + search_text.length() - 1)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
}
if (highlight_all_occurrences && !only_whitespaces_highlighted) {
@@ -1392,7 +1392,7 @@ void TextEdit::_notification(int p_what) {
}
if (in_highlighted_word) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color);
}
}
}
@@ -1449,9 +1449,9 @@ void TextEdit::_notification(int p_what) {
bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
if (selected) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
}
drawer.draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
@@ -1468,7 +1468,7 @@ void TextEdit::_notification(int p_what) {
#else
int caret_h = (block_caret) ? 4 : 2;
#endif
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, caret_h)), cache.caret_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, caret_h)), cache.caret_color);
} else {
#ifdef TOOLS_ENABLED
caret_w = (block_caret) ? caret_w : 2 * EDSCALE;
@@ -1476,7 +1476,7 @@ void TextEdit::_notification(int p_what) {
caret_w = (block_caret) ? caret_w : 2;
#endif
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, cache.font->get_height())), cache.caret_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, cache.font->get_height())), cache.caret_color);
}
}
}
@@ -1544,9 +1544,9 @@ void TextEdit::_notification(int p_what) {
bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
if (selected) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
}
drawer.draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
@@ -1564,7 +1564,7 @@ void TextEdit::_notification(int p_what) {
#else
int caret_h = (block_caret) ? 4 : 2;
#endif
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(char_w, caret_h)), cache.caret_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(char_w, caret_h)), cache.caret_color);
} else {
int char_w = cache.font->get_char_size(' ').width;
#ifdef TOOLS_ENABLED
@@ -1573,7 +1573,7 @@ void TextEdit::_notification(int p_what) {
int caret_w = (block_caret) ? char_w : 2;
#endif
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, cache.font->get_height())), cache.caret_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, cache.font->get_height())), cache.caret_color);
}
}
}
@@ -1582,21 +1582,22 @@ void TextEdit::_notification(int p_what) {
}
bool completion_below = false;
- if (completion_active) {
+ if (completion_active && completion_options.size() > 0) {
// Code completion box.
- Ref<StyleBox> csb = get_stylebox("completion");
- int maxlines = get_constant("completion_lines");
- int cmax_width = get_constant("completion_max_width") * cache.font->get_char_size('x').x;
- int scrollw = get_constant("completion_scroll_width");
- Color scrollc = get_color("completion_scroll_color");
-
- int lines = MIN(completion_options.size(), maxlines);
+ Ref<StyleBox> csb = get_theme_stylebox("completion");
+ int maxlines = get_theme_constant("completion_lines");
+ int cmax_width = get_theme_constant("completion_max_width") * cache.font->get_char_size('x').x;
+ int scrollw = get_theme_constant("completion_scroll_width");
+ Color scrollc = get_theme_color("completion_scroll_color");
+
+ const int completion_options_size = completion_options.size();
+ int lines = MIN(completion_options_size, maxlines);
int w = 0;
int h = lines * get_row_height();
int nofs = cache.font->get_string_size(completion_base).width;
- if (completion_options.size() < 50) {
- for (int i = 0; i < completion_options.size(); i++) {
+ if (completion_options_size < 50) {
+ for (int i = 0; i < completion_options_size; i++) {
int w2 = MIN(cache.font->get_string_size(completion_options[i].display).x, cmax_width);
if (w2 > w)
w = w2;
@@ -1606,7 +1607,7 @@ void TextEdit::_notification(int p_what) {
}
// Add space for completion icons.
- const int icon_hsep = get_constant("hseparation", "ItemList");
+ const int icon_hsep = get_theme_constant("hseparation", "ItemList");
Size2 icon_area_size(get_row_height(), get_row_height());
w += icon_area_size.width + icon_hsep;
@@ -1627,22 +1628,22 @@ void TextEdit::_notification(int p_what) {
completion_rect.size.width = w + 2;
completion_rect.size.height = h;
- if (completion_options.size() <= maxlines)
+ if (completion_options_size <= maxlines)
scrollw = 0;
draw_style_box(csb, Rect2(completion_rect.position - csb->get_offset(), completion_rect.size + csb->get_minimum_size() + Size2(scrollw, 0)));
if (cache.completion_background_color.a > 0.01) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scrollw, 0)), cache.completion_background_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scrollw, 0)), cache.completion_background_color);
}
- int line_from = CLAMP(completion_index - lines / 2, 0, completion_options.size() - lines);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(completion_rect.position.x, completion_rect.position.y + (completion_index - line_from) * get_row_height()), Size2(completion_rect.size.width, get_row_height())), cache.completion_selected_color);
+ int line_from = CLAMP(completion_index - lines / 2, 0, completion_options_size - lines);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(completion_rect.position.x, completion_rect.position.y + (completion_index - line_from) * get_row_height()), Size2(completion_rect.size.width, get_row_height())), cache.completion_selected_color);
draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(nofs, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color);
for (int i = 0; i < lines; i++) {
int l = line_from + i;
- ERR_CONTINUE(l < 0 || l >= completion_options.size());
+ ERR_CONTINUE(l < 0 || l >= completion_options_size);
Color text_color = cache.completion_font_color;
for (int j = 0; j < color_regions.size(); j++) {
if (completion_options[l].insert_text.begins_with(color_regions[j].begin_key)) {
@@ -1669,8 +1670,8 @@ void TextEdit::_notification(int p_what) {
if (scrollw) {
// Draw a small scroll rectangle to show a position in the options.
- float r = maxlines / (float)completion_options.size();
- float o = line_from / (float)completion_options.size();
+ float r = (float)maxlines / completion_options_size;
+ float o = (float)line_from / completion_options_size;
draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scrollw, completion_rect.size.y * r), scrollc);
}
@@ -1693,9 +1694,9 @@ void TextEdit::_notification(int p_what) {
if (show_hint) {
- Ref<StyleBox> sb = get_stylebox("panel", "TooltipPanel");
+ Ref<StyleBox> sb = get_theme_stylebox("panel", "TooltipPanel");
Ref<Font> font = cache.font;
- Color font_color = get_color("font_color", "TooltipLabel");
+ Color font_color = get_theme_color("font_color", "TooltipLabel");
int max_w = 0;
int sc = completion_hint.get_slice_count("\n");
@@ -1753,8 +1754,10 @@ void TextEdit::_notification(int p_what) {
}
if (has_focus()) {
- OS::get_singleton()->set_ime_active(true);
- OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos + Point2(0, get_row_height()));
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ 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 + Point2(0, get_row_height()), get_viewport()->get_window_id());
+ }
}
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -1765,12 +1768,14 @@ void TextEdit::_notification(int p_what) {
draw_caret = true;
}
- OS::get_singleton()->set_ime_active(true);
- Point2 cursor_pos = Point2(cursor_get_column(), cursor_get_line()) * get_row_height();
- OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos);
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
+ Point2 cursor_pos = Point2(cursor_get_column(), cursor_get_line()) * get_row_height();
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
+ }
- if (OS::get_singleton()->has_virtual_keyboard())
- OS::get_singleton()->show_virtual_keyboard(get_text(), get_global_rect());
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD))
+ DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect());
} break;
case NOTIFICATION_FOCUS_EXIT: {
@@ -1778,19 +1783,21 @@ void TextEdit::_notification(int p_what) {
caret_blink_timer->stop();
}
- OS::get_singleton()->set_ime_position(Point2());
- OS::get_singleton()->set_ime_active(false);
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ 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();
- if (OS::get_singleton()->has_virtual_keyboard())
- OS::get_singleton()->hide_virtual_keyboard();
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD))
+ DisplayServer::get_singleton()->virtual_keyboard_hide();
} break;
case MainLoop::NOTIFICATION_OS_IME_UPDATE: {
if (has_focus()) {
- ime_text = OS::get_singleton()->get_ime_text();
- ime_selection = OS::get_singleton()->get_ime_selection();
+ ime_text = DisplayServer::get_singleton()->ime_get_text();
+ ime_selection = DisplayServer::get_singleton()->ime_get_selection();
update();
}
} break;
@@ -2179,7 +2186,7 @@ Vector2i TextEdit::_get_cursor_pixel_pos() {
int x = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs;
int ix = 0;
while (ix < rows2[0].size() && ix < cursor.column) {
- if (cache.font != NULL) {
+ if (cache.font != nullptr) {
x += cache.font->get_char_size(rows2[0].get(ix)).width;
}
ix++;
@@ -2476,9 +2483,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+ 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());
+ // menu->set_scale(get_global_transform().get_scale());
menu->popup();
grab_focus();
}
@@ -2529,13 +2536,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
String new_word = get_word_at_pos(mm->get_position());
if (new_word != highlighted_word) {
- highlighted_word = new_word;
- update();
+ emit_signal("symbol_validate", new_word);
}
} else {
if (highlighted_word != String()) {
- highlighted_word = String();
- update();
+ set_highlighted_word(String());
}
}
}
@@ -2584,13 +2589,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (select_identifiers_enabled) {
if (k->is_pressed() && !dragging_minimap && !dragging_selection) {
-
- highlighted_word = get_word_at_pos(get_local_mouse_position());
- update();
-
+ emit_signal("symbol_validate", get_word_at_pos(get_local_mouse_position()));
} else {
- highlighted_word = String();
- update();
+ set_highlighted_word(String());
}
}
}
@@ -2639,7 +2640,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_keycode() == KEY_PAGEUP) {
- completion_index -= get_constant("completion_lines");
+ completion_index -= get_theme_constant("completion_lines");
if (completion_index < 0)
completion_index = 0;
completion_current = completion_options[completion_index];
@@ -2650,7 +2651,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_keycode() == KEY_PAGEDOWN) {
- completion_index += get_constant("completion_lines");
+ 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];
@@ -3740,7 +3741,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (context_menu_enabled) {
menu->set_position(get_global_transform().xform(_get_cursor_pixel_pos()));
menu->set_size(Vector2(1, 1));
- menu->set_scale(get_global_transform().get_scale());
+ // menu->set_scale(get_global_transform().get_scale());
menu->popup();
menu->grab_focus();
}
@@ -3989,7 +3990,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
text.set_breakpoint(p_line, false);
text.set_hidden(p_line, false);
- text.set_info_icon(p_line, NULL, "");
+ text.set_info_icon(p_line, nullptr, "");
}
text.set_line_wrap_amount(p_line, -1);
@@ -5031,51 +5032,51 @@ void TextEdit::_toggle_draw_caret() {
void TextEdit::_update_caches() {
- cache.style_normal = get_stylebox("normal");
- cache.style_focus = get_stylebox("focus");
- cache.style_readonly = get_stylebox("read_only");
- cache.completion_background_color = get_color("completion_background_color");
- cache.completion_selected_color = get_color("completion_selected_color");
- cache.completion_existing_color = get_color("completion_existing_color");
- cache.completion_font_color = get_color("completion_font_color");
- cache.font = get_font("font");
- cache.caret_color = get_color("caret_color");
- cache.caret_background_color = get_color("caret_background_color");
- cache.line_number_color = get_color("line_number_color");
- cache.safe_line_number_color = get_color("safe_line_number_color");
- cache.font_color = get_color("font_color");
- cache.font_color_selected = get_color("font_color_selected");
- cache.font_color_readonly = get_color("font_color_readonly");
- cache.keyword_color = get_color("keyword_color");
- cache.function_color = get_color("function_color");
- cache.member_variable_color = get_color("member_variable_color");
- cache.number_color = get_color("number_color");
- cache.selection_color = get_color("selection_color");
- cache.mark_color = get_color("mark_color");
- cache.current_line_color = get_color("current_line_color");
- cache.line_length_guideline_color = get_color("line_length_guideline_color");
- cache.bookmark_color = get_color("bookmark_color");
- cache.breakpoint_color = get_color("breakpoint_color");
- cache.executing_line_color = get_color("executing_line_color");
- cache.code_folding_color = get_color("code_folding_color");
- cache.brace_mismatch_color = get_color("brace_mismatch_color");
- cache.word_highlighted_color = get_color("word_highlighted_color");
- cache.search_result_color = get_color("search_result_color");
- cache.search_result_border_color = get_color("search_result_border_color");
- cache.symbol_color = get_color("symbol_color");
- cache.background_color = get_color("background_color");
+ cache.style_normal = get_theme_stylebox("normal");
+ cache.style_focus = get_theme_stylebox("focus");
+ cache.style_readonly = get_theme_stylebox("read_only");
+ cache.completion_background_color = get_theme_color("completion_background_color");
+ cache.completion_selected_color = get_theme_color("completion_selected_color");
+ cache.completion_existing_color = get_theme_color("completion_existing_color");
+ cache.completion_font_color = get_theme_color("completion_font_color");
+ cache.font = get_theme_font("font");
+ cache.caret_color = get_theme_color("caret_color");
+ cache.caret_background_color = get_theme_color("caret_background_color");
+ cache.line_number_color = get_theme_color("line_number_color");
+ cache.safe_line_number_color = get_theme_color("safe_line_number_color");
+ cache.font_color = get_theme_color("font_color");
+ cache.font_color_selected = get_theme_color("font_color_selected");
+ cache.font_color_readonly = get_theme_color("font_color_readonly");
+ cache.keyword_color = get_theme_color("keyword_color");
+ cache.function_color = get_theme_color("function_color");
+ cache.member_variable_color = get_theme_color("member_variable_color");
+ cache.number_color = get_theme_color("number_color");
+ cache.selection_color = get_theme_color("selection_color");
+ cache.mark_color = get_theme_color("mark_color");
+ cache.current_line_color = get_theme_color("current_line_color");
+ cache.line_length_guideline_color = get_theme_color("line_length_guideline_color");
+ cache.bookmark_color = get_theme_color("bookmark_color");
+ cache.breakpoint_color = get_theme_color("breakpoint_color");
+ cache.executing_line_color = get_theme_color("executing_line_color");
+ cache.code_folding_color = get_theme_color("code_folding_color");
+ cache.brace_mismatch_color = get_theme_color("brace_mismatch_color");
+ cache.word_highlighted_color = get_theme_color("word_highlighted_color");
+ cache.search_result_color = get_theme_color("search_result_color");
+ cache.search_result_border_color = get_theme_color("search_result_border_color");
+ cache.symbol_color = get_theme_color("symbol_color");
+ cache.background_color = get_theme_color("background_color");
#ifdef TOOLS_ENABLED
- cache.line_spacing = get_constant("line_spacing") * EDSCALE;
+ cache.line_spacing = get_theme_constant("line_spacing") * EDSCALE;
#else
- cache.line_spacing = get_constant("line_spacing");
+ cache.line_spacing = get_theme_constant("line_spacing");
#endif
cache.row_height = cache.font->get_height() + cache.line_spacing;
- cache.tab_icon = get_icon("tab");
- cache.space_icon = get_icon("space");
- cache.folded_icon = get_icon("folded");
- cache.can_fold_icon = get_icon("fold");
- cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons");
- cache.executing_icon = get_icon("MainPlay", "EditorIcons");
+ cache.tab_icon = get_theme_icon("tab");
+ cache.space_icon = get_theme_icon("space");
+ cache.folded_icon = get_theme_icon("folded");
+ cache.can_fold_icon = get_theme_icon("fold");
+ cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons");
+ cache.executing_icon = get_theme_icon("MainPlay", "EditorIcons");
text.set_font(cache.font);
if (syntax_highlighter) {
@@ -5231,7 +5232,7 @@ void TextEdit::cut() {
if (!selection.active) {
String clipboard = text[cursor.line];
- OS::get_singleton()->set_clipboard(clipboard);
+ DisplayServer::get_singleton()->clipboard_set(clipboard);
cursor_set_line(cursor.line);
cursor_set_column(0);
@@ -5249,7 +5250,7 @@ void TextEdit::cut() {
} else {
String clipboard = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- OS::get_singleton()->set_clipboard(clipboard);
+ 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.
@@ -5269,19 +5270,19 @@ void TextEdit::copy() {
if (text[cursor.line].length() != 0) {
String clipboard = _base_get_text(cursor.line, 0, cursor.line, text[cursor.line].length());
- OS::get_singleton()->set_clipboard(clipboard);
+ DisplayServer::get_singleton()->clipboard_set(clipboard);
cut_copy_line = clipboard;
}
} else {
String clipboard = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- OS::get_singleton()->set_clipboard(clipboard);
+ DisplayServer::get_singleton()->clipboard_set(clipboard);
cut_copy_line = "";
}
}
void TextEdit::paste() {
- String clipboard = OS::get_singleton()->get_clipboard();
+ String clipboard = DisplayServer::get_singleton()->clipboard_get();
begin_complex_operation();
if (selection.active) {
@@ -6086,7 +6087,7 @@ void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) {
void TextEdit::_clear_redo() {
- if (undo_stack_pos == NULL)
+ if (undo_stack_pos == nullptr)
return; // Nothing to clear.
_push_current_op();
@@ -6102,7 +6103,7 @@ void TextEdit::undo() {
_push_current_op();
- if (undo_stack_pos == NULL) {
+ if (undo_stack_pos == nullptr) {
if (!undo_stack.size())
return; // Nothing to undo.
@@ -6151,7 +6152,7 @@ void TextEdit::redo() {
_push_current_op();
- if (undo_stack_pos == NULL)
+ if (undo_stack_pos == nullptr)
return; // Nothing to do.
deselect();
@@ -6183,7 +6184,7 @@ void TextEdit::clear_undo_history() {
saved_version = 0;
current_op.type = TextOperation::TYPE_NONE;
- undo_stack_pos = NULL;
+ undo_stack_pos = nullptr;
undo_stack.clear();
}
@@ -6632,8 +6633,8 @@ void TextEdit::_update_completion_candidates() {
const CharType *tgt = &option.display[0];
const CharType *tgt_lower = &display_lower[0];
- const CharType *ssq_last_tgt = NULL;
- const CharType *ssq_lower_last_tgt = NULL;
+ const CharType *ssq_last_tgt = nullptr;
+ const CharType *ssq_lower_last_tgt = nullptr;
for (; *tgt; tgt++, tgt_lower++) {
if (*ssq == *tgt) {
@@ -6700,7 +6701,7 @@ void TextEdit::query_code_comple() {
bool ignored = completion_active && !completion_options.empty();
if (ignored) {
ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_PLAIN_TEXT;
- const ScriptCodeCompletionOption *previous_option = NULL;
+ const ScriptCodeCompletionOption *previous_option = nullptr;
for (int i = 0; i < completion_options.size(); i++) {
const ScriptCodeCompletionOption &current_option = completion_options[i];
if (!previous_option) {
@@ -7008,6 +7009,11 @@ void TextEdit::menu_option(int p_option) {
}
}
+void TextEdit::set_highlighted_word(const String &new_word) {
+ highlighted_word = new_word;
+ update();
+}
+
void TextEdit::set_select_identifiers_on_hover(bool p_enable) {
select_identifiers_enabled = p_enable;
@@ -7225,6 +7231,7 @@ void TextEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "row")));
ADD_SIGNAL(MethodInfo("symbol_lookup", PropertyInfo(Variant::STRING, "symbol"), PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::INT, "column")));
ADD_SIGNAL(MethodInfo("info_clicked", PropertyInfo(Variant::INT, "row"), PropertyInfo(Variant::STRING, "info")));
+ ADD_SIGNAL(MethodInfo("symbol_validate", PropertyInfo(Variant::STRING, "symbol")));
BIND_ENUM_CONSTANT(MENU_CUT);
BIND_ENUM_CONSTANT(MENU_COPY);
@@ -7252,7 +7259,7 @@ TextEdit::TextEdit() {
wrap_at = 0;
wrap_right_offset = 10;
set_focus_mode(FOCUS_ALL);
- syntax_highlighter = NULL;
+ syntax_highlighter = nullptr;
_update_caches();
cache.row_height = 1;
cache.line_spacing = 1;
@@ -7316,7 +7323,7 @@ TextEdit::TextEdit() {
current_op.type = TextOperation::TYPE_NONE;
undo_enabled = true;
- undo_stack_pos = NULL;
+ undo_stack_pos = nullptr;
setting_text = false;
last_dblclk = 0;
current_op.version = 0;
@@ -7326,7 +7333,7 @@ TextEdit::TextEdit() {
completion_enabled = false;
completion_active = false;
completion_line_ofs = 0;
- tooltip_obj = NULL;
+ tooltip_obj = nullptr;
line_numbers = false;
line_numbers_zero_padded = false;
line_length_guidelines = false;
@@ -7387,7 +7394,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
return syntax_highlighting_cache[p_line];
}
- if (syntax_highlighter != NULL) {
+ if (syntax_highlighter != nullptr) {
Map<int, HighlighterInfo> color_map = syntax_highlighter->_get_line_syntax_highlighting(p_line);
syntax_highlighting_cache[p_line] = color_map;
return color_map;
@@ -7501,7 +7508,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
if (col) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
- col = NULL; // Member indexing not allowed.
+ col = nullptr; // Member indexing not allowed.
break;
} else if (str[k] > 32) {
break;
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 6e267f5a47..ef8c39d32f 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -268,7 +268,7 @@ private:
} cache;
Map<int, int> color_region_cache;
- Map<int, Map<int, HighlighterInfo> > syntax_highlighting_cache;
+ Map<int, Map<int, HighlighterInfo>> syntax_highlighting_cache;
struct TextOperation {
@@ -530,7 +530,7 @@ private:
protected:
virtual String get_tooltip(const Point2 &p_pos) const;
- void _insert_text(int p_line, int p_char, const String &p_text, int *r_end_line = NULL, int *r_end_char = NULL);
+ void _insert_text(int p_line, int p_char, const String &p_text, int *r_end_line = nullptr, int *r_end_char = nullptr);
void _remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
void _insert_text_at_cursor(const String &p_text);
void _gui_input(const Ref<InputEvent> &p_gui_input);
@@ -585,6 +585,7 @@ public:
bool is_insert_text_operation();
+ void set_highlighted_word(const String &new_word);
void set_text(String p_text);
void insert_text_at_cursor(const String &p_text);
void insert_at(const String &p_text, int at);
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index abf6b2ed49..0dd43e4a35 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -300,7 +300,7 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture,
p_texture->get_rect_region(dst_rect, src_rect, dst_rect, src_rect);
RID ci = get_canvas_item();
- VS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright, VS::NINE_PATCH_STRETCH, VS::NINE_PATCH_STRETCH, true, p_modulate);
+ RS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright, RS::NINE_PATCH_STRETCH, RS::NINE_PATCH_STRETCH, true, p_modulate);
}
void TextureProgress::_notification(int p_what) {
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 6dafd3bf4f..92f3c5b5d9 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -30,7 +30,7 @@
#include "texture_rect.h"
#include "core/core_string_names.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
void TextureRect::_notification(int p_what) {
@@ -95,6 +95,15 @@ void TextureRect::_notification(int p_what) {
} break;
}
+ Ref<AtlasTexture> p_atlas = texture;
+
+ if (p_atlas.is_valid() && region.has_no_area()) {
+ Size2 scale_size(size.width / texture->get_width(), size.height / texture->get_height());
+
+ offset.width += hflip ? p_atlas->get_margin().get_position().width * scale_size.width * 2 : 0;
+ offset.height += vflip ? p_atlas->get_margin().get_position().height * scale_size.height * 2 : 0;
+ }
+
size.width *= hflip ? -1.0f : 1.0f;
size.height *= vflip ? -1.0f : 1.0f;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 12b3d56938..509a52d36a 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -30,13 +30,15 @@
#include "tree.h"
+#include "core/input/input_filter.h"
#include "core/math/math_funcs.h"
-#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/project_settings.h"
-#include "scene/main/viewport.h"
+#include "scene/main/window.h"
+
+#include "box_container.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
@@ -69,7 +71,7 @@ void TreeItem::move_to_bottom() {
parent->children = next;
}
last->next = this;
- next = NULL;
+ next = nullptr;
}
Size2 TreeItem::Cell::get_icon_size() const {
@@ -369,7 +371,7 @@ TreeItem *TreeItem::get_next() {
TreeItem *TreeItem::get_prev() {
if (!parent || parent->children == this)
- return NULL;
+ return nullptr;
TreeItem *prev = parent->children;
while (prev && prev->next != this)
@@ -398,7 +400,7 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
current = current->parent;
if (current == tree->root && tree->hide_root) {
- return NULL;
+ return nullptr;
} else if (!current) {
if (p_wrap) {
current = this;
@@ -408,7 +410,7 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
temp = temp->get_next_visible();
}
} else {
- return NULL;
+ return nullptr;
}
}
} else {
@@ -448,7 +450,7 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
if (p_wrap)
return tree->root;
else
- return NULL;
+ return nullptr;
} else {
current = current->next;
}
@@ -470,7 +472,7 @@ void TreeItem::remove_child(TreeItem *p_item) {
*c = (*c)->next;
- aux->parent = NULL;
+ aux->parent = nullptr;
return;
}
@@ -888,11 +890,11 @@ void TreeItem::clear_children() {
TreeItem *aux = c;
c = c->get_next();
- aux->parent = 0; // so it won't try to recursively autoremove from me in here
+ aux->parent = nullptr; // so it won't try to recursively autoremove from me in here
memdelete(aux);
}
- children = 0;
+ children = nullptr;
};
TreeItem::TreeItem(Tree *p_tree) {
@@ -902,9 +904,9 @@ TreeItem::TreeItem(Tree *p_tree) {
disable_folding = false;
custom_min_height = 0;
- parent = 0; // parent item
- next = 0; // next in list
- children = 0; //child items
+ parent = nullptr; // parent item
+ next = nullptr; // next in list
+ children = nullptr; //child items
}
TreeItem::~TreeItem() {
@@ -916,29 +918,29 @@ TreeItem::~TreeItem() {
if (tree && tree->root == this) {
- tree->root = 0;
+ tree->root = nullptr;
}
if (tree && tree->popup_edited_item == this) {
- tree->popup_edited_item = NULL;
+ tree->popup_edited_item = nullptr;
tree->pressing_for_editor = false;
}
if (tree && tree->cache.hover_item == this) {
- tree->cache.hover_item = NULL;
+ tree->cache.hover_item = nullptr;
}
if (tree && tree->selected_item == this)
- tree->selected_item = NULL;
+ tree->selected_item = nullptr;
if (tree && tree->drop_mode_over == this)
- tree->drop_mode_over = NULL;
+ tree->drop_mode_over = nullptr;
if (tree && tree->single_select_defer == this)
- tree->single_select_defer = NULL;
+ tree->single_select_defer = nullptr;
if (tree && tree->edited_item == this) {
- tree->edited_item = NULL;
+ tree->edited_item = nullptr;
tree->pressing_for_editor = false;
}
}
@@ -952,45 +954,45 @@ TreeItem::~TreeItem() {
void Tree::update_cache() {
- cache.font = get_font("font");
- cache.tb_font = get_font("title_button_font");
- cache.bg = get_stylebox("bg");
- cache.selected = get_stylebox("selected");
- cache.selected_focus = get_stylebox("selected_focus");
- cache.cursor = get_stylebox("cursor");
- cache.cursor_unfocus = get_stylebox("cursor_unfocused");
- cache.button_pressed = get_stylebox("button_pressed");
-
- cache.checked = get_icon("checked");
- cache.unchecked = get_icon("unchecked");
- cache.arrow_collapsed = get_icon("arrow_collapsed");
- cache.arrow = get_icon("arrow");
- cache.select_arrow = get_icon("select_arrow");
- cache.updown = get_icon("updown");
-
- cache.custom_button = get_stylebox("custom_button");
- cache.custom_button_hover = get_stylebox("custom_button_hover");
- cache.custom_button_pressed = get_stylebox("custom_button_pressed");
- cache.custom_button_font_highlight = get_color("custom_button_font_highlight");
-
- cache.font_color = get_color("font_color");
- cache.font_color_selected = get_color("font_color_selected");
- cache.guide_color = get_color("guide_color");
- cache.drop_position_color = get_color("drop_position_color");
- cache.hseparation = get_constant("hseparation");
- cache.vseparation = get_constant("vseparation");
- cache.item_margin = get_constant("item_margin");
- cache.button_margin = get_constant("button_margin");
- cache.draw_guides = get_constant("draw_guides");
- cache.draw_relationship_lines = get_constant("draw_relationship_lines");
- cache.relationship_line_color = get_color("relationship_line_color");
- cache.scroll_border = get_constant("scroll_border");
- cache.scroll_speed = get_constant("scroll_speed");
-
- cache.title_button = get_stylebox("title_button_normal");
- cache.title_button_pressed = get_stylebox("title_button_pressed");
- cache.title_button_hover = get_stylebox("title_button_hover");
- cache.title_button_color = get_color("title_button_color");
+ cache.font = get_theme_font("font");
+ cache.tb_font = get_theme_font("title_button_font");
+ cache.bg = get_theme_stylebox("bg");
+ cache.selected = get_theme_stylebox("selected");
+ cache.selected_focus = get_theme_stylebox("selected_focus");
+ cache.cursor = get_theme_stylebox("cursor");
+ cache.cursor_unfocus = get_theme_stylebox("cursor_unfocused");
+ cache.button_pressed = get_theme_stylebox("button_pressed");
+
+ cache.checked = get_theme_icon("checked");
+ cache.unchecked = get_theme_icon("unchecked");
+ cache.arrow_collapsed = get_theme_icon("arrow_collapsed");
+ cache.arrow = get_theme_icon("arrow");
+ cache.select_arrow = get_theme_icon("select_arrow");
+ cache.updown = get_theme_icon("updown");
+
+ cache.custom_button = get_theme_stylebox("custom_button");
+ cache.custom_button_hover = get_theme_stylebox("custom_button_hover");
+ cache.custom_button_pressed = get_theme_stylebox("custom_button_pressed");
+ cache.custom_button_font_highlight = get_theme_color("custom_button_font_highlight");
+
+ cache.font_color = get_theme_color("font_color");
+ cache.font_color_selected = get_theme_color("font_color_selected");
+ cache.guide_color = get_theme_color("guide_color");
+ cache.drop_position_color = get_theme_color("drop_position_color");
+ cache.hseparation = get_theme_constant("hseparation");
+ cache.vseparation = get_theme_constant("vseparation");
+ cache.item_margin = get_theme_constant("item_margin");
+ cache.button_margin = get_theme_constant("button_margin");
+ cache.draw_guides = get_theme_constant("draw_guides");
+ cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines");
+ cache.relationship_line_color = get_theme_color("relationship_line_color");
+ cache.scroll_border = get_theme_constant("scroll_border");
+ cache.scroll_speed = get_theme_constant("scroll_speed");
+
+ cache.title_button = get_theme_stylebox("title_button_normal");
+ cache.title_button_pressed = get_theme_stylebox("title_button_pressed");
+ cache.title_button_hover = get_theme_stylebox("title_button_hover");
+ cache.title_button_color = get_theme_color("title_button_color");
v_scroll->set_custom_step(cache.font->get_height());
}
@@ -1218,7 +1220,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
if (cache.draw_guides) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(cell_rect.position.x, cell_rect.position.y + cell_rect.size.height), cell_rect.position + cell_rect.size, cache.guide_color, 1);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(cell_rect.position.x, cell_rect.position.y + cell_rect.size.height), cell_rect.position + cell_rect.size, cache.guide_color, 1);
}
if (i == 0) {
@@ -1264,12 +1266,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
r.size.x += cache.hseparation;
}
if (p_item->cells[i].custom_bg_outline) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), p_item->cells[i].bg_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y - 1, r.size.x, 1), p_item->cells[i].bg_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), p_item->cells[i].bg_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), p_item->cells[i].bg_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), p_item->cells[i].bg_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y - 1, r.size.x, 1), p_item->cells[i].bg_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), p_item->cells[i].bg_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), p_item->cells[i].bg_color);
} else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, r, p_item->cells[i].bg_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, r, p_item->cells[i].bg_color);
}
}
@@ -1278,20 +1280,20 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
Rect2 r = cell_rect;
if (drop_mode_section == -1 || drop_mode_section == 0) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color);
}
if (drop_mode_section == 0) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), cache.drop_position_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color);
}
if (drop_mode_section == 1 || drop_mode_section == 0) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color);
}
}
- Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_color(p_item->cells[i].selected ? "font_color_selected" : "font_color");
+ Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_color_selected" : "font_color");
Color icon_col = p_item->cells[i].icon_color;
Point2i text_pos = item_rect.position;
@@ -1423,7 +1425,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 (InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
draw_style_box(cache.custom_button_pressed, ir);
} else {
draw_style_box(cache.custom_button_hover, ir);
@@ -1496,7 +1498,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
- if (c->get_children() != NULL)
+ if (c->get_children() != nullptr)
root_pos -= Point2i(cache.arrow->get_width(), 0);
float line_width = 1.0;
@@ -1507,8 +1509,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
if (root_pos.y + line_width >= 0) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), Point2i(parent_pos.x, prev_ofs), cache.relationship_line_color, line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), Point2i(parent_pos.x, prev_ofs), cache.relationship_line_color, line_width);
}
if (htotal < 0) {
@@ -1659,7 +1661,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 && InputFilter::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
Point2 pos = get_local_mouse_position() - cache.bg->get_offset();
if (show_column_titles) {
@@ -2046,9 +2048,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
void Tree::_text_editor_modal_close() {
- if (Input::get_singleton()->is_key_pressed(KEY_ESCAPE) ||
- Input::get_singleton()->is_key_pressed(KEY_KP_ENTER) ||
- Input::get_singleton()->is_key_pressed(KEY_ENTER)) {
+ if (InputFilter::get_singleton()->is_key_pressed(KEY_ESCAPE) ||
+ InputFilter::get_singleton()->is_key_pressed(KEY_KP_ENTER) ||
+ InputFilter::get_singleton()->is_key_pressed(KEY_ENTER)) {
return;
}
@@ -2056,13 +2058,12 @@ void Tree::_text_editor_modal_close() {
if (value_editor->has_point(value_editor->get_local_mouse_position()))
return;
- text_editor_enter(text_editor->get_text());
+ _text_editor_enter(text_editor->get_text());
}
-void Tree::text_editor_enter(String p_text) {
+void Tree::_text_editor_enter(String p_text) {
- text_editor->hide();
- value_editor->hide();
+ popup_editor->hide();
if (!popup_edited_item)
return;
@@ -2130,7 +2131,7 @@ void Tree::popup_select(int p_option) {
void Tree::_go_left() {
if (selected_col == 0) {
- if (selected_item->get_children() != NULL && !selected_item->is_collapsed()) {
+ if (selected_item->get_children() != nullptr && !selected_item->is_collapsed()) {
selected_item->set_collapsed(true);
} else {
if (columns.size() == 1) { // goto parent with one column
@@ -2159,7 +2160,7 @@ void Tree::_go_left() {
void Tree::_go_right() {
if (selected_col == (columns.size() - 1)) {
- if (selected_item->get_children() != NULL && selected_item->is_collapsed()) {
+ if (selected_item->get_children() != nullptr && selected_item->is_collapsed()) {
selected_item->set_collapsed(false);
} else if (selected_item->get_next_visible()) {
selected_col = 0;
@@ -2180,7 +2181,7 @@ void Tree::_go_right() {
}
void Tree::_go_up() {
- TreeItem *prev = NULL;
+ TreeItem *prev = nullptr;
if (!selected_item) {
prev = get_last_item();
selected_col = 0;
@@ -2220,7 +2221,7 @@ void Tree::_go_up() {
}
void Tree::_go_down() {
- TreeItem *next = NULL;
+ TreeItem *next = nullptr;
if (!selected_item) {
if (root) {
@@ -2323,7 +2324,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (!cursor_can_exit_tree) accept_event();
- TreeItem *next = NULL;
+ TreeItem *next = nullptr;
if (!selected_item)
return;
next = selected_item;
@@ -2361,7 +2362,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (!cursor_can_exit_tree) accept_event();
- TreeItem *prev = NULL;
+ TreeItem *prev = nullptr;
if (!selected_item)
return;
prev = selected_item;
@@ -2531,7 +2532,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
range_drag_enabled = true;
range_drag_capture_pos = cpos;
range_drag_base = popup_edited_item->get_range(popup_edited_item_col);
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_CAPTURED);
}
} else {
@@ -2583,7 +2584,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (single_select_defer) {
select_single_item(single_select_defer, root, single_select_defer_column);
- single_select_defer = NULL;
+ single_select_defer = nullptr;
}
range_click_timer->stop();
@@ -2593,7 +2594,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (range_drag_enabled) {
range_drag_enabled = false;
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE);
warp_mouse(range_drag_capture_pos);
} else {
Rect2 rect = get_selected()->get_meta("__focus_rect");
@@ -2608,7 +2609,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
pressing_for_editor = false;
}
- if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != NULL) {
+ if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item != nullptr) {
// make sure in case of wrong reference after reconstructing whole TreeItems
cache.click_item = get_item_at_position(cache.click_pos);
emit_signal("button_pressed", cache.click_item, cache.click_column, cache.click_id);
@@ -2616,7 +2617,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
cache.click_type = Cache::CLICK_NONE;
cache.click_index = -1;
cache.click_id = -1;
- cache.click_item = NULL;
+ cache.click_item = nullptr;
cache.click_column = 0;
if (drag_touching) {
@@ -2703,14 +2704,14 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
drag_accum = 0;
//last_drag_accum=0;
drag_from = v_scroll->get_value();
- drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
+ drag_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
drag_touching_deaccel = false;
if (drag_touching) {
set_physics_process_internal(true);
}
if (b->get_button_index() == BUTTON_LEFT) {
- if (get_item_at_position(b->get_position()) == NULL && !b->get_shift() && !b->get_control() && !b->get_command())
+ if (get_item_at_position(b->get_position()) == nullptr && !b->get_shift() && !b->get_control() && !b->get_command())
emit_signal("nothing_selected");
}
}
@@ -2806,20 +2807,23 @@ bool Tree::edit_selected() {
} else if (c.mode == TreeItem::CELL_MODE_STRING || c.mode == TreeItem::CELL_MODE_RANGE) {
+ Rect2 popup_rect;
+
Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2);
- Point2i textedpos = get_global_position() + rect.position - ofs;
+
+ Point2i textedpos = get_screen_position() + rect.position - ofs;
cache.text_editor_position = textedpos;
- text_editor->set_position(textedpos);
- text_editor->set_size(rect.size);
+ popup_rect.position = textedpos;
+ popup_rect.size = rect.size;
text_editor->clear();
text_editor->set_text(c.mode == TreeItem::CELL_MODE_STRING ? c.text : String::num(c.val, Math::range_step_decimals(c.step)));
text_editor->select_all();
if (c.mode == TreeItem::CELL_MODE_RANGE) {
- value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height));
- value_editor->set_size(Size2(rect.size.width, 1));
- value_editor->show_modal();
+ popup_rect.size.y += value_editor->get_minimum_size().height;
+
+ value_editor->show();
updating_value_editor = true;
value_editor->set_min(c.min);
value_editor->set_max(c.max);
@@ -2827,10 +2831,17 @@ bool Tree::edit_selected() {
value_editor->set_value(c.val);
value_editor->set_exp_ratio(c.expr);
updating_value_editor = false;
+ } else {
+ value_editor->hide();
}
- text_editor->show_modal();
+ popup_editor->set_position(popup_rect.position);
+ popup_editor->set_size(popup_rect.size);
+ popup_editor->popup();
+ popup_editor->child_controls_changed();
+
text_editor->grab_focus();
+
return true;
}
@@ -2935,7 +2946,7 @@ void Tree::_notification(int p_what) {
}
if (p_what == NOTIFICATION_DRAG_BEGIN) {
- single_select_defer = NULL;
+ single_select_defer = nullptr;
if (cache.scroll_speed > 0) {
scrolling = true;
set_physics_process_internal(true);
@@ -3011,7 +3022,7 @@ void Tree::_notification(int p_what) {
RID ci = get_canvas_item();
Ref<StyleBox> bg = cache.bg;
- Ref<StyleBox> bg_focus = get_stylebox("bg_focus");
+ Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus");
Point2 draw_ofs;
draw_ofs += bg->get_offset();
@@ -3019,9 +3030,9 @@ void Tree::_notification(int p_what) {
bg->draw(ci, Rect2(Point2(), get_size()));
if (has_focus()) {
- VisualServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true);
bg_focus->draw(ci, Rect2(Point2(), get_size()));
- VisualServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
+ RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false);
}
int tbh = _get_title_button_height();
@@ -3034,13 +3045,6 @@ void Tree::_notification(int p_what) {
draw_item(Point2(), draw_ofs, draw_size, root);
}
- int ofs = 0;
-
- for (int i = 0; i < (columns.size() - 1 - 1); i++) {
-
- ofs += get_column_width(i);
- }
-
if (show_column_titles) {
//title buttons
@@ -3065,7 +3069,7 @@ void Tree::_notification(int p_what) {
if (p_what == NOTIFICATION_RESIZED || p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- if (popup_edited_item != NULL) {
+ if (popup_edited_item != nullptr) {
Rect2 rect = popup_edited_item->get_meta("__focus_rect");
Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2);
Point2i textedpos = get_global_position() + rect.position - ofs;
@@ -3086,18 +3090,18 @@ Size2 Tree::get_minimum_size() const {
TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
- ERR_FAIL_COND_V(blocked > 0, NULL);
+ ERR_FAIL_COND_V(blocked > 0, nullptr);
- TreeItem *ti = NULL;
+ TreeItem *ti = nullptr;
if (p_parent) {
// Append or insert a new item to the given parent.
ti = memnew(TreeItem(this));
- ERR_FAIL_COND_V(!ti, NULL);
+ ERR_FAIL_COND_V(!ti, nullptr);
ti->cells.resize(columns.size());
- TreeItem *prev = NULL;
+ TreeItem *prev = nullptr;
TreeItem *c = p_parent->children;
int idx = 0;
@@ -3121,7 +3125,7 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
if (!root) {
// No root exists, make the given item the new root.
ti = memnew(TreeItem(this));
- ERR_FAIL_COND_V(!ti, NULL);
+ ERR_FAIL_COND_V(!ti, nullptr);
ti->cells.resize(columns.size());
root = ti;
@@ -3216,7 +3220,7 @@ void Tree::deselect_all() {
ERR_FAIL_COND(item == prev_item);
}
- selected_item = NULL;
+ selected_item = nullptr;
selected_col = -1;
update();
@@ -3224,7 +3228,7 @@ void Tree::deselect_all() {
bool Tree::is_anything_selected() {
- return (selected_item != NULL);
+ return (selected_item != nullptr);
}
void Tree::clear() {
@@ -3234,7 +3238,7 @@ void Tree::clear() {
if (pressing_for_editor) {
if (range_drag_enabled) {
range_drag_enabled = false;
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ InputFilter::get_singleton()->set_mouse_mode(InputFilter::MOUSE_MODE_VISIBLE);
warp_mouse(range_drag_capture_pos);
}
pressing_for_editor = false;
@@ -3242,12 +3246,12 @@ void Tree::clear() {
if (root) {
memdelete(root);
- root = NULL;
+ root = nullptr;
};
- selected_item = NULL;
- edited_item = NULL;
- popup_edited_item = NULL;
+ selected_item = nullptr;
+ edited_item = nullptr;
+ popup_edited_item = nullptr;
update();
};
@@ -3304,10 +3308,10 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
/*
if (!p_item)
- return NULL;
+ return nullptr;
*/
if (!root)
- return NULL;
+ return nullptr;
while (true) {
@@ -3327,8 +3331,8 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
while (!p_item->next) {
p_item = p_item->parent;
- if (p_item == NULL)
- return NULL;
+ if (p_item == nullptr)
+ return nullptr;
}
p_item = p_item->next;
@@ -3340,7 +3344,7 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
return p_item;
}
- return NULL;
+ return nullptr;
}
int Tree::get_column_width(int p_column) const {
@@ -3447,7 +3451,7 @@ int Tree::get_item_offset(TreeItem *p_item) const {
while (!it->next) {
it = it->parent;
- if (it == NULL)
+ if (it == nullptr)
return 0;
}
@@ -3615,7 +3619,7 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c
break;
}
- return NULL;
+ return nullptr;
}
TreeItem *Tree::search_item_text(const String &p_find, int *r_col, bool p_selectable) {
@@ -3625,7 +3629,7 @@ TreeItem *Tree::search_item_text(const String &p_find, int *r_col, bool p_select
if (!from)
from = root;
if (!from)
- return NULL;
+ return nullptr;
return _search_item_text(from->get_next_visible(true), p_find, r_col, p_selectable);
}
@@ -3638,7 +3642,7 @@ TreeItem *Tree::get_item_with_text(const String &p_find) const {
}
}
}
- return NULL;
+ return nullptr;
}
void Tree::_do_incr_search(const String &p_add) {
@@ -3692,7 +3696,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
pos.x -= w;
}
- return NULL;
+ return nullptr;
} else {
pos.y -= h;
@@ -3703,7 +3707,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
}
if (p_item->is_collapsed())
- return NULL; // do not try children, it's collapsed
+ return nullptr; // do not try children, it's collapsed
TreeItem *n = p_item->get_children();
while (n) {
@@ -3717,7 +3721,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
n = n->get_next();
}
- return NULL;
+ return nullptr;
}
int Tree::get_column_at_position(const Point2 &p_pos) const {
@@ -3779,7 +3783,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const {
pos -= cache.bg->get_offset();
pos.y -= _get_title_button_height();
if (pos.y < 0)
- return NULL;
+ return nullptr;
if (h_scroll->is_visible_in_tree())
pos.x += h_scroll->get_value();
@@ -3795,7 +3799,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const {
}
}
- return NULL;
+ return nullptr;
}
String Tree::get_tooltip(const Point2 &p_pos) const {
@@ -3872,7 +3876,7 @@ void Tree::set_drop_mode_flags(int p_flags) {
return;
drop_mode_flags = p_flags;
if (drop_mode_flags == 0) {
- drop_mode_over = NULL;
+ drop_mode_over = nullptr;
}
update();
@@ -4004,30 +4008,39 @@ Tree::Tree() {
selected_col = 0;
columns.resize(1);
- selected_item = NULL;
- edited_item = NULL;
+ selected_item = nullptr;
+ edited_item = nullptr;
selected_col = -1;
edited_col = -1;
hide_root = false;
select_mode = SELECT_SINGLE;
- root = 0;
- popup_menu = NULL;
- popup_edited_item = NULL;
- text_editor = NULL;
+ root = nullptr;
+ popup_menu = nullptr;
+ popup_edited_item = nullptr;
+ text_editor = nullptr;
set_focus_mode(FOCUS_ALL);
popup_menu = memnew(PopupMenu);
popup_menu->hide();
add_child(popup_menu);
- popup_menu->set_as_toplevel(true);
+ // popup_menu->set_as_toplevel(true);
+
+ popup_editor = memnew(PopupPanel);
+ popup_editor->set_wrap_controls(true);
+ add_child(popup_editor);
+ popup_editor_vb = memnew(VBoxContainer);
+ popup_editor->add_child(popup_editor_vb);
+ popup_editor_vb->add_theme_constant_override("separation", 0);
+ popup_editor_vb->set_anchors_and_margins_preset(PRESET_WIDE);
text_editor = memnew(LineEdit);
- add_child(text_editor);
- text_editor->set_as_toplevel(true);
- text_editor->hide();
+ popup_editor_vb->add_child(text_editor);
+ text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ text_editor->set_h_size_flags(SIZE_EXPAND_FILL);
value_editor = memnew(HSlider);
- add_child(value_editor);
- value_editor->set_as_toplevel(true);
+ value_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ value_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ popup_editor_vb->add_child(value_editor);
value_editor->hide();
h_scroll = memnew(HScrollBar);
@@ -4042,13 +4055,11 @@ Tree::Tree() {
h_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved));
v_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved));
- text_editor->connect("text_entered", callable_mp(this, &Tree::text_editor_enter));
- text_editor->connect("modal_closed", callable_mp(this, &Tree::_text_editor_modal_close));
+ text_editor->connect("text_entered", callable_mp(this, &Tree::_text_editor_enter));
+ popup_editor->connect("popup_hide", callable_mp(this, &Tree::_text_editor_modal_close));
popup_menu->connect("id_pressed", callable_mp(this, &Tree::popup_select));
value_editor->connect("value_changed", callable_mp(this, &Tree::value_editor_changed));
- value_editor->set_as_toplevel(true);
- text_editor->set_as_toplevel(true);
set_notify_transform(true);
updating_value_editor = false;
@@ -4060,7 +4071,7 @@ Tree::Tree() {
cache.hover_index = -1;
cache.click_index = -1;
cache.click_id = -1;
- cache.click_item = NULL;
+ cache.click_item = nullptr;
cache.click_column = 0;
cache.hover_cell = -1;
last_keypress = 0;
@@ -4080,9 +4091,9 @@ Tree::Tree() {
hide_folding = false;
drop_mode_flags = 0;
- drop_mode_over = NULL;
+ drop_mode_over = nullptr;
drop_mode_section = 0;
- single_select_defer = NULL;
+ single_select_defer = nullptr;
scrolling = false;
allow_rmb_select = false;
@@ -4090,7 +4101,7 @@ Tree::Tree() {
set_clip_contents(true);
- cache.hover_item = NULL;
+ cache.hover_item = nullptr;
cache.hover_cell = -1;
allow_reselect = false;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index b179c5bcba..87c2588a12 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -290,6 +290,8 @@ public:
VARIANT_ENUM_CAST(TreeItem::TreeCellMode);
VARIANT_ENUM_CAST(TreeItem::TextAlign);
+class VBoxContainer;
+
class Tree : public Control {
GDCLASS(Tree, Control);
@@ -359,6 +361,10 @@ private:
};
bool show_column_titles;
+
+ VBoxContainer *popup_editor_vb;
+
+ PopupPanel *popup_editor;
LineEdit *text_editor;
HSlider *value_editor;
bool updating_value_editor;
@@ -377,9 +383,9 @@ private:
//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(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_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 = NULL, bool *r_in_range = NULL, bool p_force_deselect = false);
+ 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);
- void text_editor_enter(String p_text);
+ void _text_editor_enter(String p_text);
void _text_editor_modal_close();
void value_editor_changed(double p_value);
@@ -578,7 +584,7 @@ public:
bool edit_selected();
// First item that starts with the text, from the current focused item down and wraps around.
- TreeItem *search_item_text(const String &p_find, int *r_col = NULL, bool p_selectable = false);
+ TreeItem *search_item_text(const String &p_find, int *r_col = nullptr, bool p_selectable = false);
// First item that matches the whole text, from the first item down.
TreeItem *get_item_with_text(const String &p_find) const;
diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp
deleted file mode 100644
index a76f2924d3..0000000000
--- a/scene/gui/viewport_container.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/*************************************************************************/
-/* viewport_container.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "viewport_container.h"
-
-#include "core/engine.h"
-#include "scene/main/viewport.h"
-
-Size2 ViewportContainer::get_minimum_size() const {
-
- if (stretch)
- return Size2();
- Size2 ms;
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c)
- continue;
-
- Size2 minsize = c->get_size();
- ms.width = MAX(ms.width, minsize.width);
- ms.height = MAX(ms.height, minsize.height);
- }
-
- return ms;
-}
-
-void ViewportContainer::set_stretch(bool p_enable) {
-
- stretch = p_enable;
- queue_sort();
- update();
-}
-
-bool ViewportContainer::is_stretch_enabled() const {
-
- return stretch;
-}
-
-void ViewportContainer::set_stretch_shrink(int p_shrink) {
-
- ERR_FAIL_COND(p_shrink < 1);
- if (shrink == p_shrink)
- return;
-
- shrink = p_shrink;
-
- if (!stretch)
- return;
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c)
- continue;
-
- c->set_size(get_size() / shrink);
- }
-
- update();
-}
-
-int ViewportContainer::get_stretch_shrink() const {
-
- return shrink;
-}
-
-void ViewportContainer::_notification(int p_what) {
-
- if (p_what == NOTIFICATION_RESIZED) {
-
- if (!stretch)
- return;
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c)
- continue;
-
- c->set_size(get_size() / shrink);
- }
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_VISIBILITY_CHANGED) {
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c)
- continue;
-
- if (is_visible_in_tree())
- c->set_update_mode(Viewport::UPDATE_ALWAYS);
- else
- c->set_update_mode(Viewport::UPDATE_DISABLED);
-
- c->set_handle_input_locally(false); //do not handle input locally here
- }
- }
-
- if (p_what == NOTIFICATION_DRAW) {
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c)
- continue;
-
- if (stretch)
- draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size()));
- else
- draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size()));
- }
- }
-}
-
-void ViewportContainer::_input(const Ref<InputEvent> &p_event) {
-
- if (Engine::get_singleton()->is_editor_hint())
- return;
-
- Transform2D xform = get_global_transform();
-
- if (stretch) {
- Transform2D scale_xf;
- scale_xf.scale(Vector2(shrink, shrink));
- xform *= scale_xf;
- }
-
- Ref<InputEvent> ev = p_event->xformed_by(xform.affine_inverse());
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c || c->is_input_disabled())
- continue;
-
- c->input(ev);
- }
-}
-
-void ViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) {
-
- if (Engine::get_singleton()->is_editor_hint())
- return;
-
- Transform2D xform = get_global_transform();
-
- if (stretch) {
- Transform2D scale_xf;
- scale_xf.scale(Vector2(shrink, shrink));
- xform *= scale_xf;
- }
-
- Ref<InputEvent> ev = p_event->xformed_by(xform.affine_inverse());
-
- for (int i = 0; i < get_child_count(); i++) {
-
- Viewport *c = Object::cast_to<Viewport>(get_child(i));
- if (!c || c->is_input_disabled())
- continue;
-
- c->unhandled_input(ev);
- }
-}
-
-void ViewportContainer::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_unhandled_input", "event"), &ViewportContainer::_unhandled_input);
- ClassDB::bind_method(D_METHOD("_input", "event"), &ViewportContainer::_input);
- ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &ViewportContainer::set_stretch);
- ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &ViewportContainer::is_stretch_enabled);
-
- ClassDB::bind_method(D_METHOD("set_stretch_shrink", "amount"), &ViewportContainer::set_stretch_shrink);
- ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &ViewportContainer::get_stretch_shrink);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink");
-}
-
-ViewportContainer::ViewportContainer() {
-
- stretch = false;
- shrink = 1;
- set_process_input(true);
- set_process_unhandled_input(true);
-}
diff --git a/scene/gui/viewport_container.h b/scene/gui/viewport_container.h
deleted file mode 100644
index 8597444426..0000000000
--- a/scene/gui/viewport_container.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*************************************************************************/
-/* viewport_container.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VIEWPORTCONTAINER_H
-#define VIEWPORTCONTAINER_H
-
-#include "scene/gui/container.h"
-
-class ViewportContainer : public Container {
-
- GDCLASS(ViewportContainer, Container);
-
- bool stretch;
- int shrink;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_stretch(bool p_enable);
- bool is_stretch_enabled() const;
-
- void _input(const Ref<InputEvent> &p_event);
- void _unhandled_input(const Ref<InputEvent> &p_event);
- void set_stretch_shrink(int p_shrink);
- int get_stretch_shrink() const;
-
- virtual Size2 get_minimum_size() const;
-
- ViewportContainer();
-};
-
-#endif // VIEWPORTCONTAINER_H
diff --git a/scene/main/SCsub b/scene/main/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/main/SCsub
+++ b/scene/main/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
new file mode 100644
index 0000000000..2eacad68c3
--- /dev/null
+++ b/scene/main/canvas_item.cpp
@@ -0,0 +1,1489 @@
+/*************************************************************************/
+/* canvas_item.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "canvas_item.h"
+
+#include "core/input/input_filter.h"
+#include "core/message_queue.h"
+#include "core/method_bind_ext.gen.inc"
+#include "scene/main/canvas_layer.h"
+#include "scene/main/viewport.h"
+#include "scene/main/window.h"
+#include "scene/resources/font.h"
+#include "scene/resources/style_box.h"
+#include "scene/resources/texture.h"
+#include "scene/scene_string_names.h"
+#include "servers/rendering_server.h"
+
+Mutex CanvasItemMaterial::material_mutex;
+SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = nullptr;
+Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
+CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = nullptr;
+
+void CanvasItemMaterial::init_shaders() {
+
+ dirty_materials = memnew(SelfList<CanvasItemMaterial>::List);
+
+ shader_names = memnew(ShaderNames);
+
+ shader_names->particles_anim_h_frames = "particles_anim_h_frames";
+ shader_names->particles_anim_v_frames = "particles_anim_v_frames";
+ shader_names->particles_anim_loop = "particles_anim_loop";
+}
+
+void CanvasItemMaterial::finish_shaders() {
+
+ memdelete(dirty_materials);
+ memdelete(shader_names);
+ dirty_materials = nullptr;
+}
+
+void CanvasItemMaterial::_update_shader() {
+
+ dirty_materials->remove(&element);
+
+ MaterialKey mk = _compute_key();
+ if (mk.key == current_key.key)
+ return; //no update required in the end
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ RS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+ }
+
+ current_key = mk;
+
+ if (shader_map.has(mk)) {
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ shader_map[mk].users++;
+ return;
+ }
+
+ //must create a shader!
+
+ String code = "shader_type canvas_item;\nrender_mode ";
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: code += "blend_mix"; break;
+ case BLEND_MODE_ADD: code += "blend_add"; break;
+ case BLEND_MODE_SUB: code += "blend_sub"; break;
+ case BLEND_MODE_MUL: code += "blend_mul"; break;
+ case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
+ case BLEND_MODE_DISABLED: code += "blend_disabled"; break;
+ }
+
+ switch (light_mode) {
+ case LIGHT_MODE_NORMAL: break;
+ case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
+ case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
+ }
+
+ code += ";\n";
+
+ if (particles_animation) {
+
+ code += "uniform int particles_anim_h_frames;\n";
+ code += "uniform int particles_anim_v_frames;\n";
+ code += "uniform bool particles_anim_loop;\n";
+
+ code += "void vertex() {\n";
+
+ code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
+ code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
+
+ code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n";
+
+ code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
+ code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
+ code += "\tif (!particles_anim_loop) {\n";
+ code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
+ code += "\t} else {\n";
+ code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n";
+ code += "\t}";
+ code += "\tUV /= vec2(h_frames, v_frames);\n";
+ code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
+ code += "}\n";
+ }
+
+ ShaderData shader_data;
+ shader_data.shader = RS::get_singleton()->shader_create();
+ shader_data.users = 1;
+
+ RS::get_singleton()->shader_set_code(shader_data.shader, code);
+
+ shader_map[mk] = shader_data;
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+}
+
+void CanvasItemMaterial::flush_changes() {
+
+ MutexLock lock(material_mutex);
+
+ while (dirty_materials->first()) {
+
+ dirty_materials->first()->self()->_update_shader();
+ }
+}
+
+void CanvasItemMaterial::_queue_shader_change() {
+
+ MutexLock lock(material_mutex);
+
+ if (!element.in_list()) {
+ dirty_materials->add(&element);
+ }
+}
+
+bool CanvasItemMaterial::_is_shader_dirty() const {
+
+ MutexLock lock(material_mutex);
+
+ return element.in_list();
+}
+void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
+
+ blend_mode = p_blend_mode;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
+ return blend_mode;
+}
+
+void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
+
+ light_mode = p_light_mode;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
+
+ return light_mode;
+}
+
+void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
+ particles_animation = p_particles_anim;
+ _queue_shader_change();
+ _change_notify();
+}
+
+bool CanvasItemMaterial::get_particles_animation() const {
+ return particles_animation;
+}
+
+void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
+
+ particles_anim_h_frames = p_frames;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
+}
+
+int CanvasItemMaterial::get_particles_anim_h_frames() const {
+
+ return particles_anim_h_frames;
+}
+void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
+
+ particles_anim_v_frames = p_frames;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
+}
+
+int CanvasItemMaterial::get_particles_anim_v_frames() const {
+
+ return particles_anim_v_frames;
+}
+
+void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
+
+ particles_anim_loop = p_loop;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
+}
+
+bool CanvasItemMaterial::get_particles_anim_loop() const {
+
+ return particles_anim_loop;
+}
+
+void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
+ if (property.name.begins_with("particles_anim_") && !particles_animation) {
+ property.usage = 0;
+ }
+}
+
+RID CanvasItemMaterial::get_shader_rid() const {
+
+ ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
+ return shader_map[current_key].shader;
+}
+
+Shader::Mode CanvasItemMaterial::get_shader_mode() const {
+
+ return Shader::MODE_CANVAS_ITEM;
+}
+
+void CanvasItemMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
+
+ ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
+ ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
+
+ ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
+ ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
+
+ ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
+ ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
+
+ BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
+ BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
+ BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
+ BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
+ BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
+
+ BIND_ENUM_CONSTANT(LIGHT_MODE_NORMAL);
+ BIND_ENUM_CONSTANT(LIGHT_MODE_UNSHADED);
+ BIND_ENUM_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
+}
+
+CanvasItemMaterial::CanvasItemMaterial() :
+ element(this) {
+
+ blend_mode = BLEND_MODE_MIX;
+ light_mode = LIGHT_MODE_NORMAL;
+ particles_animation = false;
+
+ set_particles_anim_h_frames(1);
+ set_particles_anim_v_frames(1);
+ set_particles_anim_loop(false);
+
+ current_key.key = 0;
+ current_key.invalid_key = 1;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::~CanvasItemMaterial() {
+
+ MutexLock lock(material_mutex);
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ RS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+#ifdef TOOLS_ENABLED
+bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ if (_edit_use_rect()) {
+ return _edit_get_rect().has_point(p_point);
+ } else {
+ return p_point.length() < p_tolerance;
+ }
+}
+
+Transform2D CanvasItem::_edit_get_transform() const {
+ return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot());
+}
+#endif
+
+bool CanvasItem::is_visible_in_tree() const {
+
+ if (!is_inside_tree())
+ return false;
+
+ const CanvasItem *p = this;
+
+ while (p) {
+ if (!p->visible)
+ return false;
+ if (p->window && !p->window->is_visible()) {
+ return false;
+ }
+ p = p->get_parent_item();
+ }
+
+ return true;
+}
+
+void CanvasItem::_propagate_visibility_changed(bool p_visible) {
+
+ if (p_visible && first_draw) { //avoid propagating it twice
+ first_draw = false;
+ }
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+
+ if (p_visible)
+ update(); //todo optimize
+ else
+ emit_signal(SceneStringNames::get_singleton()->hide);
+ _block();
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
+
+ if (c && c->visible) //should the toplevels stop propagation? i think so but..
+ c->_propagate_visibility_changed(p_visible);
+ }
+
+ _unblock();
+}
+
+void CanvasItem::show() {
+
+ if (visible)
+ return;
+
+ visible = true;
+ RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, true);
+
+ if (!is_inside_tree())
+ return;
+
+ _propagate_visibility_changed(true);
+ _change_notify("visible");
+}
+
+void CanvasItem::hide() {
+
+ if (!visible)
+ return;
+
+ visible = false;
+ RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, false);
+
+ if (!is_inside_tree())
+ return;
+
+ _propagate_visibility_changed(false);
+ _change_notify("visible");
+}
+
+CanvasItem *CanvasItem::current_item_drawn = nullptr;
+CanvasItem *CanvasItem::get_current_item_drawn() {
+ return current_item_drawn;
+}
+
+void CanvasItem::_update_callback() {
+
+ if (!is_inside_tree()) {
+ pending_update = false;
+ return;
+ }
+
+ RenderingServer::get_singleton()->canvas_item_clear(get_canvas_item());
+ //todo updating = true - only allow drawing here
+ if (is_visible_in_tree()) { //todo optimize this!!
+ if (first_draw) {
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ first_draw = false;
+ }
+ drawing = true;
+ current_item_drawn = this;
+ notification(NOTIFICATION_DRAW);
+ emit_signal(SceneStringNames::get_singleton()->draw);
+ if (get_script_instance()) {
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, nullptr, 0);
+ }
+ current_item_drawn = nullptr;
+ drawing = false;
+ }
+ //todo updating = false
+ pending_update = false; // don't change to false until finished drawing (avoid recursive update)
+}
+
+Transform2D CanvasItem::get_global_transform_with_canvas() const {
+
+ if (canvas_layer)
+ return canvas_layer->get_transform() * get_global_transform();
+ else if (is_inside_tree())
+ return get_viewport()->get_canvas_transform() * get_global_transform();
+ else
+ return get_global_transform();
+}
+
+Transform2D CanvasItem::get_screen_transform() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
+ Transform2D xform = get_global_transform_with_canvas();
+
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w && !w->is_embedding_subwindows()) {
+ Transform2D s;
+ s.set_origin(w->get_position());
+
+ xform = s * xform;
+ }
+
+ return xform;
+}
+
+Transform2D CanvasItem::get_global_transform() const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
+#endif
+ if (global_invalid) {
+
+ const CanvasItem *pi = get_parent_item();
+ if (pi)
+ global_transform = pi->get_global_transform() * get_transform();
+ else
+ global_transform = get_transform();
+
+ global_invalid = false;
+ }
+
+ return global_transform;
+}
+
+void CanvasItem::_toplevel_raise_self() {
+
+ if (!is_inside_tree())
+ return;
+
+ if (canvas_layer)
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, canvas_layer->get_sort_index());
+ else
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_viewport()->gui_get_canvas_sort_index());
+}
+
+void CanvasItem::_enter_canvas() {
+
+ if ((!Object::cast_to<CanvasItem>(get_parent())) || toplevel) {
+
+ Node *n = this;
+
+ canvas_layer = nullptr;
+
+ while (n) {
+
+ canvas_layer = Object::cast_to<CanvasLayer>(n);
+ if (canvas_layer) {
+ break;
+ }
+ if (Object::cast_to<Viewport>(n)) {
+ break;
+ }
+ n = n->get_parent();
+ }
+
+ RID canvas;
+ if (canvas_layer)
+ canvas = canvas_layer->get_canvas();
+ else
+ canvas = get_viewport()->find_world_2d()->get_canvas();
+
+ RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
+
+ group = "root_canvas" + itos(canvas.get_id());
+
+ add_to_group(group);
+ if (canvas_layer)
+ canvas_layer->reset_sort_index();
+ else
+ get_viewport()->gui_reset_canvas_sort_index();
+
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
+
+ } else {
+
+ CanvasItem *parent = get_parent_item();
+ canvas_layer = parent->canvas_layer;
+ RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, parent->get_canvas_item());
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
+ }
+
+ pending_update = false;
+ update();
+
+ notification(NOTIFICATION_ENTER_CANVAS);
+}
+
+void CanvasItem::_exit_canvas() {
+
+ notification(NOTIFICATION_EXIT_CANVAS, true); //reverse the notification
+ RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, RID());
+ canvas_layer = nullptr;
+ group = "";
+}
+
+void CanvasItem::_notification(int p_what) {
+
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+
+ _update_texture_filter_changed(false);
+ _update_texture_repeat_changed(false);
+
+ first_draw = true;
+ Node *parent = get_parent();
+ if (parent) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
+ if (ci)
+ C = ci->children_items.push_back(this);
+ if (!ci) {
+ //look for a window
+ Viewport *viewport = nullptr;
+
+ while (parent) {
+ viewport = Object::cast_to<Viewport>(parent);
+ if (viewport) {
+ break;
+ }
+ parent = parent->get_parent();
+ }
+
+ ERR_FAIL_COND(!viewport);
+
+ window = Object::cast_to<Window>(viewport);
+ if (window) {
+ window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
+ }
+ }
+ }
+ _enter_canvas();
+ if (!block_transform_notify && !xform_change.in_list()) {
+ get_tree()->xform_change_list.add(&xform_change);
+ }
+ } break;
+ case NOTIFICATION_MOVED_IN_PARENT: {
+
+ if (!is_inside_tree())
+ break;
+
+ if (group != "") {
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
+ } else {
+ CanvasItem *p = get_parent_item();
+ ERR_FAIL_COND(!p);
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (xform_change.in_list())
+ get_tree()->xform_change_list.remove(&xform_change);
+ _exit_canvas();
+ if (C) {
+ Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
+ C = nullptr;
+ }
+ if (window) {
+ window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
+ }
+ global_invalid = true;
+ } break;
+ case NOTIFICATION_DRAW:
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ } break;
+ }
+}
+
+void CanvasItem::set_visible(bool p_visible) {
+
+ if (p_visible)
+ show();
+ else
+ hide();
+}
+
+void CanvasItem::_window_visibility_changed() {
+
+ if (visible) {
+ _propagate_visibility_changed(window->is_visible());
+ }
+}
+
+bool CanvasItem::is_visible() const {
+
+ return visible;
+}
+
+void CanvasItem::update() {
+
+ if (!is_inside_tree())
+ return;
+ if (pending_update)
+ return;
+
+ pending_update = true;
+
+ MessageQueue::get_singleton()->push_call(this, "_update_callback");
+}
+
+void CanvasItem::set_modulate(const Color &p_modulate) {
+
+ if (modulate == p_modulate)
+ return;
+
+ modulate = p_modulate;
+ RenderingServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
+}
+Color CanvasItem::get_modulate() const {
+
+ return modulate;
+}
+
+void CanvasItem::set_as_toplevel(bool p_toplevel) {
+
+ if (toplevel == p_toplevel)
+ return;
+
+ if (!is_inside_tree()) {
+ toplevel = p_toplevel;
+ return;
+ }
+
+ _exit_canvas();
+ toplevel = p_toplevel;
+ _enter_canvas();
+}
+
+bool CanvasItem::is_set_as_toplevel() const {
+
+ return toplevel;
+}
+
+CanvasItem *CanvasItem::get_parent_item() const {
+
+ if (toplevel)
+ return nullptr;
+
+ return Object::cast_to<CanvasItem>(get_parent());
+}
+
+void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
+
+ if (self_modulate == p_self_modulate)
+ return;
+
+ self_modulate = p_self_modulate;
+ RenderingServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
+}
+Color CanvasItem::get_self_modulate() const {
+
+ return self_modulate;
+}
+
+void CanvasItem::set_light_mask(int p_light_mask) {
+
+ if (light_mask == p_light_mask)
+ return;
+
+ light_mask = p_light_mask;
+ RS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
+}
+
+int CanvasItem::get_light_mask() const {
+
+ return light_mask;
+}
+
+void CanvasItem::item_rect_changed(bool p_size_changed) {
+
+ if (p_size_changed)
+ update();
+ 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) {
+
+ 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) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Vector<Color> colors;
+ colors.push_back(p_color);
+ RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width);
+}
+
+void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float 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_polyline(canvas_item, p_points, p_colors, p_width);
+}
+
+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) {
+
+ Vector<Point2> points;
+ points.resize(p_point_count);
+ const float 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;
+ points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
+ }
+
+ draw_polyline(points, p_color, p_width);
+}
+
+void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Vector<Color> colors;
+ colors.push_back(p_color);
+ 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) {
+
+ 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) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ if (p_filled) {
+ if (p_width != 1.0) {
+ WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
+ } 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;
+ if (p_width >= 2) {
+ offset = p_width / 2.0;
+ } else {
+ offset = 0.0;
+ }
+
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(-offset, 0),
+ p_rect.position + Size2(p_rect.size.width + offset, 0),
+ p_color,
+ p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(p_rect.size.width, offset),
+ p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
+ p_color,
+ p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
+ p_rect.position + Size2(-offset, p_rect.size.height),
+ p_color,
+ p_width);
+ RenderingServer::get_singleton()->canvas_item_add_line(
+ canvas_item,
+ p_rect.position + Size2(0, p_rect.size.height - offset),
+ p_rect.position + Size2(0, offset),
+ p_color,
+ p_width);
+ }
+}
+
+void CanvasItem::draw_circle(const Point2 &p_pos, float 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);
+}
+
+void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_texture.is_null());
+
+ p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_texture.is_null());
+ p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_FAIL_COND(p_texture.is_null());
+ p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat), p_clip_uv);
+}
+
+void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND(p_style_box.is_null());
+
+ 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, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ 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();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+void CanvasItem::draw_set_transform(const Point2 &p_offset, float 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);
+ xform.scale_basis(p_scale);
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, xform);
+}
+
+void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
+}
+
+void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ 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();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ Vector<Color> colors;
+ colors.push_back(p_color);
+ RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, const Transform2D &p_transform, const Color &p_modulate, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND(p_mesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
+
+ ERR_FAIL_COND(p_multimesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
+
+ RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, RS::CanvasItemTextureFilter(p_texture_filter), RS::CanvasItemTextureRepeat(p_texture_repeat));
+}
+
+void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
+
+ 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(canvas_item, p_pos, p_text, p_modulate, p_clip_w);
+}
+
+float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, const Color &p_modulate) {
+
+ ERR_FAIL_COND_V_MSG(!drawing, 0, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+
+ ERR_FAIL_COND_V(p_char.length() != 1, 0);
+ ERR_FAIL_COND_V(p_font.is_null(), 0);
+
+ if (p_font->has_outline()) {
+ p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true);
+ }
+ return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate);
+}
+
+void CanvasItem::_notify_transform(CanvasItem *p_node) {
+
+ /* This check exists to avoid re-propagating the transform
+ * notification down the tree on dirty nodes. It provides
+ * optimization by avoiding redundancy (nodes are dirty, will get the
+ * notification anyway).
+ */
+
+ if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
+ return; //nothing to do
+ }
+
+ p_node->global_invalid = true;
+
+ if (p_node->notify_transform && !p_node->xform_change.in_list()) {
+ if (!p_node->block_transform_notify) {
+ if (p_node->is_inside_tree())
+ get_tree()->xform_change_list.add(&p_node->xform_change);
+ }
+ }
+
+ for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) {
+
+ CanvasItem *ci = E->get();
+ if (ci->toplevel)
+ continue;
+ _notify_transform(ci);
+ }
+}
+
+Rect2 CanvasItem::get_viewport_rect() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
+ return get_viewport()->get_visible_rect();
+}
+
+RID CanvasItem::get_canvas() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), RID());
+
+ if (canvas_layer)
+ return canvas_layer->get_canvas();
+ else
+ return get_viewport()->find_world_2d()->get_canvas();
+}
+
+ObjectID CanvasItem::get_canvas_layer_instance_id() const {
+
+ if (canvas_layer) {
+ return canvas_layer->get_instance_id();
+ } else {
+ return ObjectID();
+ }
+}
+
+CanvasItem *CanvasItem::get_toplevel() const {
+
+ CanvasItem *ci = const_cast<CanvasItem *>(this);
+ while (!ci->toplevel && Object::cast_to<CanvasItem>(ci->get_parent())) {
+ ci = Object::cast_to<CanvasItem>(ci->get_parent());
+ }
+
+ return ci;
+}
+
+Ref<World2D> CanvasItem::get_world_2d() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
+
+ CanvasItem *tl = get_toplevel();
+
+ if (tl->get_viewport()) {
+ return tl->get_viewport()->find_world_2d();
+ } else {
+ return Ref<World2D>();
+ }
+}
+
+RID CanvasItem::get_viewport_rid() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), RID());
+ return get_viewport()->get_viewport_rid();
+}
+
+void CanvasItem::set_block_transform_notify(bool p_enable) {
+ block_transform_notify = p_enable;
+}
+
+bool CanvasItem::is_block_transform_notify_enabled() const {
+
+ return block_transform_notify;
+}
+
+void CanvasItem::set_draw_behind_parent(bool p_enable) {
+
+ if (behind == p_enable)
+ return;
+ behind = p_enable;
+ RenderingServer::get_singleton()->canvas_item_set_draw_behind_parent(canvas_item, behind);
+}
+
+bool CanvasItem::is_draw_behind_parent_enabled() const {
+
+ return behind;
+}
+
+void CanvasItem::set_material(const Ref<Material> &p_material) {
+
+ material = p_material;
+ RID rid;
+ if (material.is_valid())
+ rid = material->get_rid();
+ RS::get_singleton()->canvas_item_set_material(canvas_item, rid);
+ _change_notify(); //properties for material exposed
+}
+
+void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
+
+ use_parent_material = p_use_parent_material;
+ RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
+}
+
+bool CanvasItem::get_use_parent_material() const {
+
+ return use_parent_material;
+}
+
+Ref<Material> CanvasItem::get_material() const {
+
+ return material;
+}
+
+Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
+
+ Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
+
+ return local_matrix.xform(screen_point);
+}
+
+Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
+
+ ERR_FAIL_COND_V(p_event.is_null(), p_event);
+ ERR_FAIL_COND_V(!is_inside_tree(), p_event);
+
+ return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse());
+}
+
+Vector2 CanvasItem::get_global_mouse_position() const {
+
+ ERR_FAIL_COND_V(!get_viewport(), Vector2());
+ return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
+}
+
+Vector2 CanvasItem::get_local_mouse_position() const {
+
+ ERR_FAIL_COND_V(!get_viewport(), Vector2());
+
+ return get_global_transform().affine_inverse().xform(get_global_mouse_position());
+}
+
+void CanvasItem::force_update_transform() {
+ ERR_FAIL_COND(!is_inside_tree());
+ if (!xform_change.in_list()) {
+ return;
+ }
+
+ get_tree()->xform_change_list.remove(&xform_change);
+
+ notification(NOTIFICATION_TRANSFORM_CHANGED);
+}
+
+void CanvasItem::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self);
+ ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
+
+#ifdef TOOLS_ENABLED
+ ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state);
+ ClassDB::bind_method(D_METHOD("_edit_get_state"), &CanvasItem::_edit_get_state);
+ ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
+ ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
+ ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
+ ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
+ ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
+ ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
+ ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
+ ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
+ ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
+ ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
+ ClassDB::bind_method(D_METHOD("_edit_set_pivot", "pivot"), &CanvasItem::_edit_set_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform);
+#endif
+
+ ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item);
+
+ ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasItem::set_visible);
+ ClassDB::bind_method(D_METHOD("is_visible"), &CanvasItem::is_visible);
+ ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &CanvasItem::is_visible_in_tree);
+ ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show);
+ ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
+
+ ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update);
+
+ ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &CanvasItem::set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &CanvasItem::is_set_as_toplevel);
+
+ ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask);
+ ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask);
+
+ ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &CanvasItem::set_modulate);
+ ClassDB::bind_method(D_METHOD("get_modulate"), &CanvasItem::get_modulate);
+ ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate);
+ ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate);
+
+ ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
+ ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
+
+ ClassDB::bind_method(D_METHOD("_set_on_top", "on_top"), &CanvasItem::_set_on_top);
+ ClassDB::bind_method(D_METHOD("_is_on_top"), &CanvasItem::_is_on_top);
+ //ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
+
+ ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width"), &CanvasItem::draw_polyline, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width"), &CanvasItem::draw_arc, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
+ ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "clip_uv", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(true), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
+ ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "specular_shininess", "transform", "modulate", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+ ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
+
+ ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
+ ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
+ ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform);
+ ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform);
+ ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas);
+ ClassDB::bind_method(D_METHOD("get_viewport_transform"), &CanvasItem::get_viewport_transform);
+ ClassDB::bind_method(D_METHOD("get_viewport_rect"), &CanvasItem::get_viewport_rect);
+ ClassDB::bind_method(D_METHOD("get_canvas_transform"), &CanvasItem::get_canvas_transform);
+ ClassDB::bind_method(D_METHOD("get_local_mouse_position"), &CanvasItem::get_local_mouse_position);
+ ClassDB::bind_method(D_METHOD("get_global_mouse_position"), &CanvasItem::get_global_mouse_position);
+ ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasItem::get_canvas);
+ ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
+ //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
+
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &CanvasItem::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &CanvasItem::get_material);
+
+ ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
+ ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
+
+ ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &CanvasItem::set_notify_local_transform);
+ ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &CanvasItem::is_local_transform_notification_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &CanvasItem::set_notify_transform);
+ ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &CanvasItem::is_transform_notification_enabled);
+
+ ClassDB::bind_method(D_METHOD("force_update_transform"), &CanvasItem::force_update_transform);
+
+ ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
+ ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
+
+ ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &CanvasItem::set_texture_filter);
+ ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasItem::get_texture_filter);
+
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
+
+ BIND_VMETHOD(MethodInfo("_draw"));
+
+ ADD_GROUP("Visibility", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
+
+ ADD_GROUP("Texture", "texture_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "ParentNode,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "ParentNode,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
+
+ ADD_GROUP("Material", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
+ //exporting these things doesn't really make much sense i think
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
+
+ ADD_SIGNAL(MethodInfo("draw"));
+ ADD_SIGNAL(MethodInfo("visibility_changed"));
+ ADD_SIGNAL(MethodInfo("hide"));
+ ADD_SIGNAL(MethodInfo("item_rect_changed"));
+
+ BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_DRAW);
+ BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
+ BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
+
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
+ BIND_ENUM_CONSTANT(TEXTURE_FILTER_MAX);
+
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT_NODE);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_DISABLED);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
+ BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
+}
+
+Transform2D CanvasItem::get_canvas_transform() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
+
+ if (canvas_layer)
+ return canvas_layer->get_transform();
+ else if (Object::cast_to<CanvasItem>(get_parent()))
+ return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
+ else
+ return get_viewport()->get_canvas_transform();
+}
+
+Transform2D CanvasItem::get_viewport_transform() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
+
+ if (canvas_layer) {
+
+ if (get_viewport()) {
+ return get_viewport()->get_final_transform() * canvas_layer->get_transform();
+ } else {
+ return canvas_layer->get_transform();
+ }
+
+ } else {
+ return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform();
+ }
+}
+
+void CanvasItem::set_notify_local_transform(bool p_enable) {
+ notify_local_transform = p_enable;
+}
+
+bool CanvasItem::is_local_transform_notification_enabled() const {
+ return notify_local_transform;
+}
+
+void CanvasItem::set_notify_transform(bool p_enable) {
+ if (notify_transform == p_enable)
+ return;
+
+ notify_transform = p_enable;
+
+ if (notify_transform && is_inside_tree()) {
+ //this ensures that invalid globals get resolved, so notifications can be received
+ get_global_transform();
+ }
+}
+
+bool CanvasItem::is_transform_notification_enabled() const {
+ return notify_transform;
+}
+
+int CanvasItem::get_canvas_layer() const {
+
+ if (canvas_layer)
+ return canvas_layer->get_layer();
+ else
+ return 0;
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (texture_filter == TEXTURE_FILTER_PARENT_NODE) {
+ CanvasItem *parent_item = get_parent_item();
+ if (parent_item) {
+ texture_filter_cache = parent_item->texture_filter_cache;
+ } else {
+ //from viewport
+ switch (get_viewport()->get_default_canvas_item_texture_filter()) {
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; break;
+ default: {
+ }
+ }
+ }
+ } else {
+ texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
+ }
+ RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
+ update();
+
+ if (p_propagate) {
+ for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
+ if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
+ E->get()->_update_texture_filter_changed(true);
+ }
+ }
+ }
+}
+
+void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
+ ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
+ if (texture_filter == p_texture_filter) {
+ return;
+ }
+ texture_filter = p_texture_filter;
+ _update_texture_filter_changed(true);
+}
+
+CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
+ return texture_filter;
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
+ CanvasItem *parent_item = get_parent_item();
+ if (parent_item) {
+ texture_repeat_cache = parent_item->texture_repeat_cache;
+ } else {
+ //from viewport
+ switch (get_viewport()->get_default_canvas_item_texture_repeat()) {
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; break;
+ case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR; break;
+ default: {
+ }
+ }
+ }
+ } else {
+ texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
+ }
+ RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
+ update();
+ if (p_propagate) {
+ for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
+ if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
+ E->get()->_update_texture_repeat_changed(true);
+ }
+ }
+ }
+}
+
+void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
+ ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
+ if (texture_repeat == p_texture_repeat) {
+ return;
+ }
+ texture_repeat = p_texture_repeat;
+ _update_texture_repeat_changed(true);
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
+ return texture_repeat;
+}
+
+CanvasItem::CanvasItem() :
+ xform_change(this) {
+
+ window = nullptr;
+ canvas_item = RenderingServer::get_singleton()->canvas_item_create();
+ visible = true;
+ pending_update = false;
+ modulate = Color(1, 1, 1, 1);
+ self_modulate = Color(1, 1, 1, 1);
+ toplevel = false;
+ first_draw = false;
+ drawing = false;
+ behind = false;
+ block_transform_notify = false;
+ canvas_layer = nullptr;
+ use_parent_material = false;
+ global_invalid = true;
+ notify_local_transform = false;
+ notify_transform = false;
+ light_mask = 1;
+ texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
+ texture_filter = TEXTURE_FILTER_PARENT_NODE;
+ texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+
+ C = nullptr;
+}
+
+CanvasItem::~CanvasItem() {
+
+ RenderingServer::get_singleton()->free(canvas_item);
+}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
new file mode 100644
index 0000000000..dc17c5283b
--- /dev/null
+++ b/scene/main/canvas_item.h
@@ -0,0 +1,426 @@
+/*************************************************************************/
+/* canvas_item.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CANVAS_ITEM_H
+#define CANVAS_ITEM_H
+
+#include "scene/main/node.h"
+#include "scene/main/scene_tree.h"
+#include "scene/resources/material.h"
+#include "scene/resources/multimesh.h"
+#include "scene/resources/shader.h"
+#include "scene/resources/texture.h"
+
+class CanvasLayer;
+class Viewport;
+class Font;
+
+class StyleBox;
+
+class CanvasItemMaterial : public Material {
+
+ GDCLASS(CanvasItemMaterial, Material);
+
+public:
+ enum BlendMode {
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_PREMULT_ALPHA,
+ BLEND_MODE_DISABLED
+ };
+
+ enum LightMode {
+ LIGHT_MODE_NORMAL,
+ LIGHT_MODE_UNSHADED,
+ LIGHT_MODE_LIGHT_ONLY
+ };
+
+private:
+ union MaterialKey {
+
+ struct {
+ uint32_t blend_mode : 4;
+ uint32_t light_mode : 4;
+ uint32_t particles_animation : 1;
+ uint32_t invalid_key : 1;
+ };
+
+ uint32_t key;
+
+ bool operator<(const MaterialKey &p_key) const {
+ return key < p_key.key;
+ }
+ };
+
+ struct ShaderNames {
+ StringName particles_anim_h_frames;
+ StringName particles_anim_v_frames;
+ StringName particles_anim_loop;
+ };
+
+ static ShaderNames *shader_names;
+
+ struct ShaderData {
+ RID shader;
+ int users;
+ };
+
+ static Map<MaterialKey, ShaderData> shader_map;
+
+ MaterialKey current_key;
+
+ _FORCE_INLINE_ MaterialKey _compute_key() const {
+
+ MaterialKey mk;
+ mk.key = 0;
+ mk.blend_mode = blend_mode;
+ mk.light_mode = light_mode;
+ mk.particles_animation = particles_animation;
+ return mk;
+ }
+
+ static Mutex material_mutex;
+ static SelfList<CanvasItemMaterial>::List *dirty_materials;
+ SelfList<CanvasItemMaterial> element;
+
+ void _update_shader();
+ _FORCE_INLINE_ void _queue_shader_change();
+ _FORCE_INLINE_ bool _is_shader_dirty() const;
+
+ BlendMode blend_mode;
+ LightMode light_mode;
+ bool particles_animation;
+
+ int particles_anim_h_frames;
+ int particles_anim_v_frames;
+ bool particles_anim_loop;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_blend_mode(BlendMode p_blend_mode);
+ BlendMode get_blend_mode() const;
+
+ void set_light_mode(LightMode p_light_mode);
+ LightMode get_light_mode() const;
+
+ void set_particles_animation(bool p_particles_anim);
+ bool get_particles_animation() const;
+
+ void set_particles_anim_h_frames(int p_frames);
+ int get_particles_anim_h_frames() const;
+ void set_particles_anim_v_frames(int p_frames);
+ int get_particles_anim_v_frames() const;
+
+ void set_particles_anim_loop(bool p_loop);
+ bool get_particles_anim_loop() const;
+
+ static void init_shaders();
+ static void finish_shaders();
+ static void flush_changes();
+
+ RID get_shader_rid() const;
+
+ virtual Shader::Mode get_shader_mode() const;
+
+ CanvasItemMaterial();
+ virtual ~CanvasItemMaterial();
+};
+
+VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode)
+VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
+
+class CanvasItem : public Node {
+
+ GDCLASS(CanvasItem, Node);
+
+public:
+ enum TextureFilter {
+ TEXTURE_FILTER_PARENT_NODE,
+ TEXTURE_FILTER_NEAREST,
+ TEXTURE_FILTER_LINEAR,
+ TEXTURE_FILTER_NEAREST_WITH_MIPMAPS,
+ TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
+ TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC,
+ TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
+ TEXTURE_FILTER_MAX
+ };
+
+ enum TextureRepeat {
+ TEXTURE_REPEAT_PARENT_NODE,
+ TEXTURE_REPEAT_DISABLED,
+ TEXTURE_REPEAT_ENABLED,
+ TEXTURE_REPEAT_MIRROR,
+ TEXTURE_REPEAT_MAX,
+ };
+
+private:
+ mutable SelfList<Node> xform_change;
+
+ RID canvas_item;
+ String group;
+
+ CanvasLayer *canvas_layer;
+
+ Color modulate;
+ Color self_modulate;
+
+ List<CanvasItem *> children_items;
+ List<CanvasItem *>::Element *C;
+
+ int light_mask;
+
+ Window *window;
+ bool first_draw;
+ bool visible;
+ bool pending_update;
+ bool toplevel;
+ bool drawing;
+ bool block_transform_notify;
+ bool behind;
+ bool use_parent_material;
+ bool notify_local_transform;
+ bool notify_transform;
+
+ RS::CanvasItemTextureFilter texture_filter_cache;
+ RS::CanvasItemTextureRepeat texture_repeat_cache;
+
+ TextureFilter texture_filter;
+ TextureRepeat texture_repeat;
+
+ Ref<Material> material;
+
+ mutable Transform2D global_transform;
+ mutable bool global_invalid;
+
+ void _toplevel_raise_self();
+
+ void _propagate_visibility_changed(bool p_visible);
+
+ void _update_callback();
+
+ void _enter_canvas();
+ void _exit_canvas();
+
+ void _window_visibility_changed();
+
+ void _notify_transform(CanvasItem *p_node);
+
+ void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
+ bool _is_on_top() const { return !is_draw_behind_parent_enabled(); }
+
+ static CanvasItem *current_item_drawn;
+ friend class Viewport;
+ void _update_texture_repeat_changed(bool p_propagate);
+ void _update_texture_filter_changed(bool p_propagate);
+
+protected:
+ _FORCE_INLINE_ void _notify_transform() {
+ if (!is_inside_tree()) return;
+ _notify_transform(this);
+ if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
+
+ void item_rect_changed(bool p_size_changed = true);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ enum {
+ NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
+ NOTIFICATION_DRAW = 30,
+ NOTIFICATION_VISIBILITY_CHANGED = 31,
+ NOTIFICATION_ENTER_CANVAS = 32,
+ NOTIFICATION_EXIT_CANVAS = 33,
+ NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 35,
+ NOTIFICATION_WORLD_2D_CHANGED = 36,
+
+ };
+
+ /* EDITOR */
+#ifdef TOOLS_ENABLED
+ // Select the node
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
+ // Save and restore a CanvasItem state
+ virtual void _edit_set_state(const Dictionary &p_state){};
+ virtual Dictionary _edit_get_state() const { return Dictionary(); };
+
+ // Used to move the node
+ virtual void _edit_set_position(const Point2 &p_position) = 0;
+ virtual Point2 _edit_get_position() const = 0;
+
+ // Used to scale the node
+ virtual void _edit_set_scale(const Size2 &p_scale) = 0;
+ virtual Size2 _edit_get_scale() const = 0;
+
+ // 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; };
+
+ // Used to resize/move the node
+ virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
+ virtual void _edit_set_rect(const Rect2 &p_rect){};
+ virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
+ virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
+
+ // Used to set a pivot
+ virtual bool _edit_use_pivot() const { return false; };
+ virtual void _edit_set_pivot(const Point2 &p_pivot){};
+ virtual Point2 _edit_get_pivot() const { return Point2(); };
+
+ virtual Transform2D _edit_get_transform() const;
+#endif
+
+ /* VISIBILITY */
+
+ void set_visible(bool p_visible);
+ bool is_visible() const;
+ bool is_visible_in_tree() const;
+ void show();
+ void hide();
+
+ void update();
+
+ virtual void set_light_mask(int p_light_mask);
+ int get_light_mask() const;
+
+ void set_modulate(const Color &p_modulate);
+ Color get_modulate() const;
+
+ void set_self_modulate(const Color &p_self_modulate);
+ Color get_self_modulate() const;
+
+ /* 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);
+ void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ 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);
+ 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_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ 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>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+
+ void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+ void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
+
+ void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
+ float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
+
+ void draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale);
+ void draw_set_transform_matrix(const Transform2D &p_matrix);
+
+ static CanvasItem *get_current_item_drawn();
+
+ /* RECT / TRANSFORM */
+
+ void set_as_toplevel(bool p_toplevel);
+ bool is_set_as_toplevel() const;
+
+ void set_draw_behind_parent(bool p_enable);
+ bool is_draw_behind_parent_enabled() const;
+
+ CanvasItem *get_parent_item() const;
+
+ virtual Transform2D get_transform() const = 0;
+
+ virtual Transform2D get_global_transform() const;
+ virtual Transform2D get_global_transform_with_canvas() const;
+ virtual Transform2D get_screen_transform() const;
+
+ CanvasItem *get_toplevel() const;
+ _FORCE_INLINE_ RID get_canvas_item() const {
+ return canvas_item;
+ }
+
+ void set_block_transform_notify(bool p_enable);
+ bool is_block_transform_notify_enabled() const;
+
+ Transform2D get_canvas_transform() const;
+ Transform2D get_viewport_transform() const;
+ Rect2 get_viewport_rect() const;
+ RID get_viewport_rid() const;
+ RID get_canvas() const;
+ ObjectID get_canvas_layer_instance_id() const;
+ Ref<World2D> get_world_2d() const;
+
+ virtual void set_material(const Ref<Material> &p_material);
+ Ref<Material> get_material() const;
+
+ virtual void set_use_parent_material(bool p_use_parent_material);
+ bool get_use_parent_material() const;
+
+ Ref<InputEvent> make_input_local(const Ref<InputEvent> &p_event) const;
+ Vector2 make_canvas_position_local(const Vector2 &screen_point) const;
+
+ Vector2 get_global_mouse_position() const;
+ Vector2 get_local_mouse_position() const;
+
+ void set_notify_local_transform(bool p_enable);
+ bool is_local_transform_notification_enabled() const;
+
+ void set_notify_transform(bool p_enable);
+ bool is_transform_notification_enabled() const;
+
+ void force_update_transform();
+
+ void set_texture_filter(TextureFilter p_texture_filter);
+ TextureFilter get_texture_filter() const;
+
+ void set_texture_repeat(TextureRepeat p_texture_repeat);
+ TextureRepeat get_texture_repeat() const;
+
+ // Used by control nodes to retrieve the parent's anchorable area
+ virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
+
+ int get_canvas_layer() const;
+
+ CanvasItem();
+ ~CanvasItem();
+};
+
+VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
+VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+
+#endif // CANVAS_ITEM_H
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 2085fa3a60..c1caa943e3 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -35,7 +35,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
}
int CanvasLayer::get_layer() const {
@@ -48,7 +48,7 @@ void CanvasLayer::set_transform(const Transform2D &p_xform) {
transform = p_xform;
locrotscale_dirty = true;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
Transform2D CanvasLayer::get_transform() const {
@@ -61,7 +61,7 @@ void CanvasLayer::_update_xform() {
transform.set_rotation_and_scale(rot, scale);
transform.set_origin(ofs);
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
void CanvasLayer::_update_locrotscale() {
@@ -150,16 +150,16 @@ void CanvasLayer::_notification(int p_what) {
vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
_update_follow_viewport();
} break;
case NOTIFICATION_EXIT_TREE: {
vp->_canvas_layer_remove(this);
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
_update_follow_viewport(false);
@@ -167,7 +167,7 @@ void CanvasLayer::_notification(int p_what) {
case NOTIFICATION_MOVED_IN_PARENT: {
if (is_inside_tree())
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
} break;
}
@@ -191,7 +191,7 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
ERR_FAIL_NULL(p_viewport);
if (is_inside_tree()) {
vp->_canvas_layer_remove(this);
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
}
@@ -213,9 +213,9 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
vp->_canvas_layer_add(this);
viewport = vp->get_viewport_rid();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
- VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent());
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
}
@@ -266,9 +266,9 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
return;
}
if (p_force_exit || !follow_viewport) {
- VS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0);
+ RS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0);
} else {
- VS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale);
+ RS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale);
}
}
@@ -320,13 +320,13 @@ void CanvasLayer::_bind_methods() {
CanvasLayer::CanvasLayer() {
- vp = NULL;
+ vp = nullptr;
scale = Vector2(1, 1);
rot = 0;
locrotscale_dirty = false;
layer = 1;
- canvas = VS::get_singleton()->canvas_create();
- custom_viewport = NULL;
+ canvas = RS::get_singleton()->canvas_create();
+ custom_viewport = nullptr;
sort_index = 0;
follow_viewport = false;
@@ -335,5 +335,5 @@ CanvasLayer::CanvasLayer() {
CanvasLayer::~CanvasLayer() {
- VS::get_singleton()->free(canvas);
+ RS::get_singleton()->free(canvas);
}
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index fee2ada76d..dc0da015ac 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -162,12 +162,12 @@ void HTTPRequest::cancel_request() {
thread_request_quit = true;
Thread::wait_to_finish(thread);
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
}
if (file) {
memdelete(file);
- file = NULL;
+ file = nullptr;
}
client->close();
body.resize(0);
@@ -566,7 +566,7 @@ void HTTPRequest::_bind_methods() {
HTTPRequest::HTTPRequest() {
- thread = NULL;
+ thread = nullptr;
port = 80;
redirections = 0;
@@ -583,7 +583,7 @@ HTTPRequest::HTTPRequest() {
thread_done = false;
downloaded = 0;
body_size_limit = -1;
- file = NULL;
+ file = nullptr;
timer = memnew(Timer);
timer->set_one_shot(true);
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index fe238af1c4..062b221c84 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -77,11 +77,11 @@ String InstancePlaceholder::get_instance_path() const {
Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene> &p_custom_scene) {
- ERR_FAIL_COND_V(!is_inside_tree(), NULL);
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
Node *base = get_parent();
if (!base)
- return NULL;
+ return nullptr;
Ref<PackedScene> ps;
if (p_custom_scene.is_valid())
@@ -90,12 +90,12 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
ps = ResourceLoader::load(path, "PackedScene");
if (!ps.is_valid())
- return NULL;
+ return nullptr;
Node *scene = ps->instance();
if (!scene)
- return NULL;
+ return nullptr;
scene->set_name(get_name());
- int pos = get_position_in_parent();
+ int pos = get_index();
for (List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
scene->set(E->get().name, E->get().value);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 973dff07d2..50f3bf834f 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -82,7 +82,7 @@ void Node::_notification(int p_notification) {
if (data.parent)
data.pause_owner = data.parent->data.pause_owner;
else
- data.pause_owner = NULL;
+ data.pause_owner = nullptr;
} else {
data.pause_owner = this;
}
@@ -112,17 +112,17 @@ void Node::_notification(int p_notification) {
if (data.unhandled_key_input)
remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id()));
- data.pause_owner = NULL;
+ data.pause_owner = nullptr;
if (data.path_cache) {
memdelete(data.path_cache);
- data.path_cache = NULL;
+ data.path_cache = nullptr;
}
} break;
case NOTIFICATION_PATH_CHANGED: {
if (data.path_cache) {
memdelete(data.path_cache);
- data.path_cache = NULL;
+ data.path_cache = nullptr;
}
} break;
case NOTIFICATION_READY: {
@@ -149,7 +149,7 @@ void Node::_notification(int p_notification) {
set_physics_process(true);
}
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, NULL, 0);
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, nullptr, 0);
}
} break;
@@ -158,11 +158,11 @@ void Node::_notification(int p_notification) {
} break;
case NOTIFICATION_PREDELETE: {
- set_owner(NULL);
+ set_owner(nullptr);
while (data.owned.size()) {
- data.owned.front()->get()->set_owner(NULL);
+ data.owned.front()->get()->set_owner(nullptr);
}
if (data.parent) {
@@ -226,7 +226,7 @@ void Node::_propagate_enter_tree() {
if (get_script_instance()) {
- get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, NULL, 0);
+ get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, nullptr, 0);
}
emit_signal(SceneStringNames::get_singleton()->tree_entered);
@@ -278,7 +278,7 @@ void Node::_propagate_exit_tree() {
if (get_script_instance()) {
- get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, NULL, 0);
+ get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, nullptr, 0);
}
emit_signal(SceneStringNames::get_singleton()->tree_exiting);
@@ -290,17 +290,17 @@ void Node::_propagate_exit_tree() {
for (Map<StringName, GroupData>::Element *E = data.grouped.front(); E; E = E->next()) {
data.tree->remove_from_group(E->key(), this);
- E->get().group = NULL;
+ E->get().group = nullptr;
}
- data.viewport = NULL;
+ data.viewport = nullptr;
if (data.tree)
data.tree->tree_changed();
data.inside_tree = false;
data.ready_notified = false;
- data.tree = NULL;
+ data.tree = nullptr;
data.depth = -1;
}
@@ -423,7 +423,7 @@ void Node::set_pause_mode(PauseMode p_mode) {
if ((data.pause_mode == PAUSE_MODE_INHERIT) == prev_inherits)
return; ///nothing changed
- Node *owner = NULL;
+ Node *owner = nullptr;
if (data.pause_mode == PAUSE_MODE_INHERIT) {
@@ -914,7 +914,7 @@ void Node::set_process_priority(int p_priority) {
data.process_priority = p_priority;
// Make sure we are in SceneTree.
- if (data.tree == NULL) {
+ if (data.tree == nullptr) {
return;
}
@@ -1268,7 +1268,7 @@ void Node::add_child_below_node(Node *p_node, Node *p_child, bool p_legible_uniq
add_child(p_child, p_legible_unique_name);
if (is_a_parent_of(p_node)) {
- move_child(p_child, p_node->get_position_in_parent() + 1);
+ move_child(p_child, p_node->get_index() + 1);
} else {
WARN_PRINT("Cannot move under node " + p_node->get_name() + " as " + p_child->get_name() + " does not share a parent.");
}
@@ -1295,7 +1295,7 @@ void Node::_propagate_validate_owner() {
if (!found) {
data.owner->data.owned.erase(data.OW);
- data.owner = NULL;
+ data.owner = nullptr;
}
}
@@ -1336,7 +1336,7 @@ void Node::remove_child(Node *p_child) {
//if (data.scene) { does not matter
- p_child->_set_tree(NULL);
+ p_child->_set_tree(nullptr);
//}
remove_child_notify(p_child);
@@ -1354,7 +1354,7 @@ void Node::remove_child(Node *p_child) {
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
- p_child->data.parent = NULL;
+ p_child->data.parent = nullptr;
p_child->data.pos = -1;
// validate owner
@@ -1371,7 +1371,7 @@ int Node::get_child_count() const {
}
Node *Node::get_child(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, data.children.size(), NULL);
+ ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
return data.children[p_index];
}
@@ -1386,19 +1386,19 @@ Node *Node::_get_child_by_name(const StringName &p_name) const {
return cd[i];
}
- return NULL;
+ return nullptr;
}
Node *Node::get_node_or_null(const NodePath &p_path) const {
if (p_path.is_empty()) {
- return NULL;
+ return nullptr;
}
- ERR_FAIL_COND_V_MSG(!data.inside_tree && p_path.is_absolute(), NULL, "Can't use get_node() with absolute paths from outside the active scene tree.");
+ ERR_FAIL_COND_V_MSG(!data.inside_tree && p_path.is_absolute(), nullptr, "Can't use get_node() with absolute paths from outside the active scene tree.");
- Node *current = NULL;
- Node *root = NULL;
+ Node *current = nullptr;
+ Node *root = nullptr;
if (!p_path.is_absolute()) {
current = const_cast<Node *>(this); //start from this
@@ -1412,7 +1412,7 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
for (int i = 0; i < p_path.get_name_count(); i++) {
StringName name = p_path.get_name(i);
- Node *next = NULL;
+ Node *next = nullptr;
if (name == SceneStringNames::get_singleton()->dot) { // .
@@ -1420,18 +1420,18 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
} else if (name == SceneStringNames::get_singleton()->doubledot) { // ..
- if (current == NULL || !current->data.parent)
- return NULL;
+ if (current == nullptr || !current->data.parent)
+ return nullptr;
next = current->data.parent;
- } else if (current == NULL) {
+ } else if (current == nullptr) {
if (name == root->get_name())
next = root;
} else {
- next = NULL;
+ next = nullptr;
for (int j = 0; j < current->data.children.size(); j++) {
@@ -1443,8 +1443,8 @@ Node *Node::get_node_or_null(const NodePath &p_path) const {
break;
}
}
- if (next == NULL) {
- return NULL;
+ if (next == nullptr) {
+ return nullptr;
};
}
current = next;
@@ -1456,13 +1456,13 @@ 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, NULL, "Node not found: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!node, nullptr, "Node not found: " + p_path + ".");
return node;
}
bool Node::has_node(const NodePath &p_path) const {
- return get_node_or_null(p_path) != NULL;
+ return get_node_or_null(p_path) != nullptr;
}
Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const {
@@ -1482,7 +1482,7 @@ Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) cons
if (ret)
return ret;
}
- return NULL;
+ return nullptr;
}
Node *Node::get_parent() const {
@@ -1500,7 +1500,7 @@ Node *Node::find_parent(const String &p_mask) const {
p = p->data.parent;
}
- return NULL;
+ return nullptr;
}
bool Node::is_a_parent_of(const Node *p_node) const {
@@ -1607,8 +1607,8 @@ void Node::set_owner(Node *p_owner) {
if (data.owner) {
data.owner->data.owned.erase(data.OW);
- data.OW = NULL;
- data.owner = NULL;
+ data.OW = nullptr;
+ data.owner = nullptr;
}
ERR_FAIL_COND(p_owner == this);
@@ -1663,7 +1663,7 @@ Node *Node::find_common_parent_with(const Node *p_node) const {
}
if (!common_parent)
- return NULL;
+ return nullptr;
return const_cast<Node *>(common_parent);
}
@@ -1762,7 +1762,7 @@ void Node::add_to_group(const StringName &p_identifier, bool p_persistent) {
if (data.tree) {
gd.group = data.tree->add_to_group(p_identifier, this);
} else {
- gd.group = NULL;
+ gd.group = nullptr;
}
gd.persistent = p_persistent;
@@ -1918,6 +1918,7 @@ int Node::get_index() const {
return data.pos;
}
+
void Node::remove_and_skip() {
ERR_FAIL_COND(!data.parent);
@@ -1935,7 +1936,7 @@ void Node::remove_and_skip() {
continue;
remove_child(c_node);
- c_node->_propagate_replace_owner(this, NULL);
+ c_node->_propagate_replace_owner(this, nullptr);
children.push_back(c_node);
clear = false;
break;
@@ -1949,7 +1950,7 @@ void Node::remove_and_skip() {
Node *c_node = children.front()->get();
data.parent->add_child(c_node);
- c_node->_propagate_replace_owner(NULL, new_owner);
+ c_node->_propagate_replace_owner(nullptr, new_owner);
children.pop_front();
}
@@ -2042,14 +2043,9 @@ bool Node::get_scene_instance_load_placeholder() const {
return data.use_placeholder;
}
-int Node::get_position_in_parent() const {
-
- return data.pos;
-}
-
Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const {
- Node *node = NULL;
+ Node *node = nullptr;
bool instanced = false;
@@ -2063,25 +2059,25 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
} else if ((p_flags & DUPLICATE_USE_INSTANCING) && get_filename() != String()) {
Ref<PackedScene> res = ResourceLoader::load(get_filename());
- ERR_FAIL_COND_V(res.is_null(), NULL);
+ ERR_FAIL_COND_V(res.is_null(), nullptr);
PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED;
#ifdef TOOLS_ENABLED
if (p_flags & DUPLICATE_FROM_EDITOR)
ges = PackedScene::GEN_EDIT_STATE_INSTANCE;
#endif
node = res->instance(ges);
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
instanced = true;
} else {
Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_V(!obj, NULL);
+ ERR_FAIL_COND_V(!obj, nullptr);
node = Object::cast_to<Node>(obj);
if (!node)
memdelete(obj);
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
}
if (get_filename() != "") { //an instance
@@ -2189,7 +2185,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (!dup) {
memdelete(node);
- return NULL;
+ return nullptr;
}
node->add_child(dup);
@@ -2204,18 +2200,18 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (!parent) {
memdelete(node);
- return NULL;
+ return nullptr;
}
Node *dup = E->get()->_duplicate(p_flags, r_duplimap);
if (!dup) {
memdelete(node);
- return NULL;
+ return nullptr;
}
parent->add_child(dup);
- int pos = E->get()->get_position_in_parent();
+ int pos = E->get()->get_index();
if (pos < parent->get_child_count() - 1) {
@@ -2256,7 +2252,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
if (get_owner() != get_parent()->get_owner())
return;
- Node *node = NULL;
+ Node *node = nullptr;
if (get_filename() != "") {
@@ -2369,15 +2365,15 @@ 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() != "", NULL);
+ ERR_FAIL_COND_V(get_filename() != "", nullptr);
Object *obj = ClassDB::instance(get_class());
- ERR_FAIL_COND_V_MSG(!obj, NULL, "Node: Could not duplicate: " + String(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(NULL, "Node: Could not duplicate: " + String(get_class()) + ".");
+ ERR_FAIL_V_MSG(nullptr, "Node: Could not duplicate: " + String(get_class()) + ".");
}
node->set_name(get_name());
@@ -2591,7 +2587,7 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
r_res = RES();
r_leftover_subpath = Vector<StringName>();
if (!node)
- return NULL;
+ return nullptr;
if (p_path.get_subname_count()) {
@@ -2601,7 +2597,7 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
Variant new_res_v = j == 0 ? node->get(p_path.get_subname(j)) : r_res->get(p_path.get_subname(j));
if (new_res_v.get_type() == Variant::NIL) { // Found nothing on that path
- return NULL;
+ return nullptr;
}
RES new_res = new_res_v;
@@ -2623,8 +2619,8 @@ Node *Node::get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<Str
void Node::_set_tree(SceneTree *p_tree) {
- SceneTree *tree_changed_a = NULL;
- SceneTree *tree_changed_b = NULL;
+ SceneTree *tree_changed_a = nullptr;
+ SceneTree *tree_changed_b = nullptr;
//ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
@@ -2860,7 +2856,6 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pause_mode"), &Node::get_pause_mode);
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes);
- ClassDB::bind_method(D_METHOD("get_position_in_parent"), &Node::get_position_in_parent);
ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded);
ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded);
@@ -2950,9 +2945,9 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
- BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST);
BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST);
- BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST);
+ BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED);
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
@@ -3012,8 +3007,8 @@ Node::Node() {
data.pos = -1;
data.depth = -1;
data.blocked = 0;
- data.parent = NULL;
- data.tree = NULL;
+ data.parent = nullptr;
+ data.tree = nullptr;
data.physics_process = false;
data.idle_process = false;
data.process_priority = 0;
@@ -3022,18 +3017,18 @@ Node::Node() {
data.inside_tree = false;
data.ready_notified = false;
- data.owner = NULL;
- data.OW = NULL;
+ data.owner = nullptr;
+ data.OW = nullptr;
data.input = false;
data.unhandled_input = false;
data.unhandled_key_input = false;
data.pause_mode = PAUSE_MODE_INHERIT;
- data.pause_owner = NULL;
+ data.pause_owner = nullptr;
data.network_master = 1; //server by default
- data.path_cache = NULL;
+ data.path_cache = nullptr;
data.parent_owned = false;
data.in_constructor = true;
- data.viewport = NULL;
+ data.viewport = nullptr;
data.use_placeholder = false;
data.display_folded = false;
data.ready_first = true;
diff --git a/scene/main/node.h b/scene/main/node.h
index d1f75b71ec..5de07d506e 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -180,7 +180,7 @@ private:
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 = NULL) const;
+ Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const;
Array _get_children() const;
Array _get_groups() const;
@@ -244,13 +244,16 @@ public:
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27,
//keep these linked to node
- NOTIFICATION_WM_MOUSE_ENTER = MainLoop::NOTIFICATION_WM_MOUSE_ENTER,
- NOTIFICATION_WM_MOUSE_EXIT = MainLoop::NOTIFICATION_WM_MOUSE_EXIT,
- NOTIFICATION_WM_FOCUS_IN = MainLoop::NOTIFICATION_WM_FOCUS_IN,
- NOTIFICATION_WM_FOCUS_OUT = MainLoop::NOTIFICATION_WM_FOCUS_OUT,
- NOTIFICATION_WM_QUIT_REQUEST = MainLoop::NOTIFICATION_WM_QUIT_REQUEST,
- NOTIFICATION_WM_GO_BACK_REQUEST = MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST,
- NOTIFICATION_WM_UNFOCUS_REQUEST = MainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST,
+
+ NOTIFICATION_WM_MOUSE_ENTER = 1002,
+ NOTIFICATION_WM_MOUSE_EXIT = 1003,
+ NOTIFICATION_WM_FOCUS_IN = 1004,
+ NOTIFICATION_WM_FOCUS_OUT = 1005,
+ NOTIFICATION_WM_CLOSE_REQUEST = 1006,
+ NOTIFICATION_WM_GO_BACK_REQUEST = 1007,
+ NOTIFICATION_WM_SIZE_CHANGED = 1008,
+ NOTIFICATION_WM_DPI_CHANGE = 1009,
+
NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING,
NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED,
NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT,
@@ -283,7 +286,7 @@ public:
Node *find_parent(const String &p_mask) const;
_FORCE_INLINE_ SceneTree *get_tree() const {
- ERR_FAIL_COND_V(!data.tree, NULL);
+ ERR_FAIL_COND_V(!data.tree, nullptr);
return data.tree;
}
@@ -366,8 +369,6 @@ public:
void set_process_unhandled_key_input(bool p_enable);
bool is_processing_unhandled_key_input() const;
- int get_position_in_parent() 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
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 57bb3b6b5e..0418b20e9c 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -31,6 +31,7 @@
#include "scene_tree.h"
#include "core/debugger/engine_debugger.h"
+#include "core/input/input_filter.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/message_queue.h"
@@ -39,7 +40,6 @@
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/project_settings.h"
-#include "main/input_default.h"
#include "node.h"
#include "scene/debugger/scene_debugger.h"
#include "scene/resources/dynamic_font.h"
@@ -47,10 +47,11 @@
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/scene_string_names.h"
-#include "servers/navigation_server.h"
-#include "servers/physics_2d_server.h"
-#include "servers/physics_server.h"
-#include "viewport.h"
+#include "servers/display_server.h"
+#include "servers/navigation_server_3d.h"
+#include "servers/physics_server_2d.h"
+#include "servers/physics_server_3d.h"
+#include "window.h"
#include <stdio.h>
@@ -111,7 +112,7 @@ void SceneTree::node_added(Node *p_node) {
void SceneTree::node_removed(Node *p_node) {
if (current_scene == p_node) {
- current_scene = NULL;
+ current_scene = nullptr;
}
emit_signal(node_removed_name, p_node);
if (call_lock > 0)
@@ -172,7 +173,7 @@ void SceneTree::_flush_ugc() {
while (unique_group_calls.size()) {
- Map<UGCall, Vector<Variant> >::Element *E = unique_group_calls.front();
+ Map<UGCall, Vector<Variant>>::Element *E = unique_group_calls.front();
Variant v[VARIANT_ARG_MAX];
for (int i = 0; i < E->get().size(); i++)
@@ -397,69 +398,6 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const
set_group_flags(0, p_group, p_name, p_value);
}
-void SceneTree::set_input_as_handled() {
-
- input_handled = true;
-}
-
-void SceneTree::input_text(const String &p_text) {
-
- root_lock++;
-
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input_text", p_text); //special one for GUI, as controls use their own process check
-
- root_lock--;
-}
-
-bool SceneTree::is_input_handled() {
- return input_handled;
-}
-
-void SceneTree::input_event(const Ref<InputEvent> &p_event) {
-
- if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event)))
- return; //avoid joy input on editor
-
- current_event++;
- root_lock++;
-
- input_handled = false;
-
- // Don't make const ref unless you can find and fix what caused GH-34691.
- Ref<InputEvent> ev = p_event;
-
- MainLoop::input_event(ev);
-
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input", ev); //special one for GUI, as controls use their own process check
-
- if (EngineDebugger::is_active()) {
- //quit from game window using F8
- Ref<InputEventKey> k = ev;
- if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_F8) {
- EngineDebugger::get_singleton()->send_message("request_quit", Array());
- }
- }
-
- _flush_ugc();
- root_lock--;
- //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness
-
- root_lock++;
-
- if (!input_handled) {
- call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_unhandled_input", ev); //special one for GUI, as controls use their own process check
- _flush_ugc();
- // input_handled = true; - no reason to set this as handled
- root_lock--;
- //MessageQueue::get_singleton()->flush(); //flushing here causes UI and other places slowness
- } else {
- // input_handled = true; - no reason to set this as handled
- root_lock--;
- }
-
- _call_idle_callbacks();
-}
-
void SceneTree::init() {
initialized = true;
root->_set_tree(this);
@@ -493,19 +431,11 @@ bool SceneTree::iteration(float p_time) {
return _quit;
}
-void SceneTree::_update_font_oversampling(float p_ratio) {
-
- if (use_font_oversampling) {
- DynamicFontAtSize::font_oversampling = p_ratio;
- DynamicFont::update_oversampling();
- }
-}
-
bool SceneTree::idle(float p_time) {
//print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage()));
//print_line("node count: "+itos(get_node_count()));
- //print_line("TEXTURE RAM: "+itos(VS::get_singleton()->get_render_info(VS::INFO_TEXTURE_MEM_USED)));
+ //print_line("TEXTURE RAM: "+itos(RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED)));
root_lock++;
@@ -526,15 +456,6 @@ bool SceneTree::idle(float p_time) {
_notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS);
_notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS);
- Size2 win_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
-
- if (win_size != last_screen_size) {
-
- last_screen_size = win_size;
- _update_root_rect();
- emit_signal("screen_resized");
- }
-
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
@@ -546,11 +467,11 @@ bool SceneTree::idle(float p_time) {
//go through timers
- List<Ref<SceneTreeTimer> >::Element *L = timers.back(); //last element
+ List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
- for (List<Ref<SceneTreeTimer> >::Element *E = timers.front(); E;) {
+ for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
- List<Ref<SceneTreeTimer> >::Element *N = E->next();
+ List<Ref<SceneTreeTimer>>::Element *N = E->next();
if (pause && !E->get()->is_pause_mode_process()) {
if (E == L) {
break; //break on last, so if new timers were added during list traversal, ignore them.
@@ -618,14 +539,14 @@ void SceneTree::finish() {
MainLoop::finish();
if (root) {
- root->_set_tree(NULL);
+ root->_set_tree(nullptr);
root->_propagate_after_exit_tree();
memdelete(root); //delete root
- root = NULL;
+ root = nullptr;
}
// cleanup timers
- for (List<Ref<SceneTreeTimer> >::Element *E = timers.front(); E; E = E->next()) {
+ for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E; E = E->next()) {
E->get()->release_connections();
}
timers.clear();
@@ -642,59 +563,36 @@ void SceneTree::quit(int p_exit_code) {
_quit = true;
}
-void SceneTree::_notification(int p_notification) {
-
- switch (p_notification) {
-
- case NOTIFICATION_WM_QUIT_REQUEST: {
-
- get_root()->propagate_notification(p_notification);
-
- if (accept_quit) {
- _quit = true;
- break;
- }
- } break;
-
- case NOTIFICATION_WM_GO_BACK_REQUEST: {
-
- get_root()->propagate_notification(p_notification);
+void SceneTree::_main_window_close() {
- if (quit_on_go_back) {
- _quit = true;
- break;
- }
- } break;
+ if (accept_quit) {
+ _quit = true;
+ }
+}
+void SceneTree::_main_window_go_back() {
+ if (quit_on_go_back) {
+ _quit = true;
+ }
+}
- case NOTIFICATION_WM_FOCUS_IN: {
+void SceneTree::_main_window_focus_in() {
+ InputFilter *id = InputFilter::get_singleton();
+ if (id) {
+ id->ensure_touch_mouse_raised();
+ }
+}
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
- if (id) {
- id->ensure_touch_mouse_raised();
- }
+void SceneTree::_notification(int p_notification) {
- get_root()->propagate_notification(p_notification);
- } break;
+ switch (p_notification) {
case NOTIFICATION_TRANSLATION_CHANGED: {
if (!Engine::get_singleton()->is_editor_hint()) {
get_root()->propagate_notification(p_notification);
}
} break;
-
- case NOTIFICATION_WM_UNFOCUS_REQUEST: {
-
- notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST);
-
- get_root()->propagate_notification(p_notification);
-
- } break;
-
case NOTIFICATION_OS_MEMORY_WARNING:
case NOTIFICATION_OS_IME_UPDATE:
- case NOTIFICATION_WM_MOUSE_ENTER:
- case NOTIFICATION_WM_MOUSE_EXIT:
- case NOTIFICATION_WM_FOCUS_OUT:
case NOTIFICATION_WM_ABOUT:
case NOTIFICATION_CRASH:
case NOTIFICATION_APP_RESUMED:
@@ -898,9 +796,9 @@ void SceneTree::set_pause(bool p_enabled) {
if (p_enabled == pause)
return;
pause = p_enabled;
- NavigationServer::get_singleton()->set_active(!p_enabled);
- PhysicsServer::get_singleton()->set_active(!p_enabled);
- Physics2DServer::get_singleton()->set_active(!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);
}
@@ -910,7 +808,7 @@ bool SceneTree::is_paused() const {
return pause;
}
-void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input) {
+void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E)
@@ -919,7 +817,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
if (g.nodes.empty())
return;
- _update_group_order(g);
+ _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
//copy, so copy on write happens in case something is removed from process while being called
//performance is not lost because only if something is added/removed the vector is copied.
@@ -928,15 +826,9 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
int node_count = nodes_copy.size();
Node **nodes = nodes_copy.ptrw();
- Variant arg = p_input;
- const Variant *v[1] = { &arg };
-
call_lock++;
- for (int i = node_count - 1; i >= 0; i--) {
-
- if (input_handled)
- break;
+ for (int i = 0; i < node_count; i++) {
Node *n = nodes[i];
if (call_lock && call_skip.has(n))
@@ -944,8 +836,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
if (!n->can_process())
continue;
+ if (!n->can_process_notification(p_notification))
+ continue;
- n->call_multilevel(p_method, (const Variant **)v, 1);
+ n->notification(p_notification);
//ERR_FAIL_COND(node_count != g.nodes.size());
}
@@ -954,7 +848,18 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
call_skip.clear();
}
-void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) {
+/*
+void SceneMainLoop::_update_listener_2d() {
+
+ if (listener_2d.is_valid()) {
+
+ SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() );
+ }
+
+}
+*/
+
+void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E)
@@ -963,7 +868,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (g.nodes.empty())
return;
- _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
+ _update_group_order(g);
//copy, so copy on write happens in case something is removed from process while being called
//performance is not lost because only if something is added/removed the vector is copied.
@@ -972,9 +877,15 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
int node_count = nodes_copy.size();
Node **nodes = nodes_copy.ptrw();
+ Variant arg = p_input;
+ const Variant *v[1] = { &arg };
+
call_lock++;
- for (int i = 0; i < node_count; i++) {
+ for (int i = node_count - 1; i >= 0; i--) {
+
+ if (p_viewport->is_input_handled())
+ break;
Node *n = nodes[i];
if (call_lock && call_skip.has(n))
@@ -982,10 +893,8 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (!n->can_process())
continue;
- if (!n->can_process_notification(p_notification))
- continue;
- n->notification(p_notification);
+ n->call_multilevel(p_method, (const Variant **)v, 1);
//ERR_FAIL_COND(node_count != g.nodes.size());
}
@@ -993,18 +902,6 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (call_lock == 0)
call_skip.clear();
}
-
-/*
-void SceneMainLoop::_update_listener_2d() {
-
- if (listener_2d.is_valid()) {
-
- SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() );
- }
-
-}
-*/
-
Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
@@ -1129,129 +1026,6 @@ int SceneTree::get_node_count() const {
return node_count;
}
-void SceneTree::_update_root_rect() {
-
- if (stretch_mode == STRETCH_MODE_DISABLED) {
-
- _update_font_oversampling(1.0);
- root->set_size((last_screen_size / stretch_shrink).floor());
- root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size));
- root->set_size_override_stretch(false);
- root->set_size_override(false, Size2());
- root->update_canvas_items();
- return; //user will take care
- }
-
- //actual screen video mode
- Size2 video_mode = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
- Size2 desired_res = stretch_min;
-
- Size2 viewport_size;
- Size2 screen_size;
-
- float viewport_aspect = desired_res.aspect();
- float video_mode_aspect = video_mode.aspect();
-
- if (use_font_oversampling && stretch_aspect == STRETCH_ASPECT_IGNORE) {
- WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'.");
- }
-
- if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
- //same aspect or ignore aspect
- viewport_size = desired_res;
- screen_size = video_mode;
- } else if (viewport_aspect < video_mode_aspect) {
- // screen ratio is smaller vertically
-
- if (stretch_aspect == STRETCH_ASPECT_KEEP_HEIGHT || stretch_aspect == STRETCH_ASPECT_EXPAND) {
-
- //will stretch horizontally
- viewport_size.x = desired_res.y * video_mode_aspect;
- viewport_size.y = desired_res.y;
- screen_size = video_mode;
-
- } else {
- //will need black bars
- viewport_size = desired_res;
- screen_size.x = video_mode.y * viewport_aspect;
- screen_size.y = video_mode.y;
- }
- } else {
- //screen ratio is smaller horizontally
- if (stretch_aspect == STRETCH_ASPECT_KEEP_WIDTH || stretch_aspect == STRETCH_ASPECT_EXPAND) {
-
- //will stretch horizontally
- viewport_size.x = desired_res.x;
- viewport_size.y = desired_res.x / video_mode_aspect;
- screen_size = video_mode;
-
- } else {
- //will need black bars
- viewport_size = desired_res;
- screen_size.x = video_mode.x;
- screen_size.y = video_mode.x / viewport_aspect;
- }
- }
-
- screen_size = screen_size.floor();
- viewport_size = viewport_size.floor();
-
- Size2 margin;
- Size2 offset;
- //black bars and margin
- if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.x < video_mode.x) {
- margin.x = Math::round((video_mode.x - screen_size.x) / 2.0);
- VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0);
- offset.x = Math::round(margin.x * viewport_size.y / screen_size.y);
- } else if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.y < video_mode.y) {
- margin.y = Math::round((video_mode.y - screen_size.y) / 2.0);
- VisualServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y);
- offset.y = Math::round(margin.y * viewport_size.x / screen_size.x);
- } else {
- VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0);
- }
-
- switch (stretch_mode) {
- case STRETCH_MODE_DISABLED: {
- // Already handled above
- _update_font_oversampling(1.0);
- } break;
- case STRETCH_MODE_2D: {
-
- _update_font_oversampling(screen_size.x / viewport_size.x); //screen / viewport radio drives oversampling
- root->set_size((screen_size / stretch_shrink).floor());
- root->set_attach_to_screen_rect(Rect2(margin, screen_size));
- root->set_size_override_stretch(true);
- root->set_size_override(true, (viewport_size / stretch_shrink).floor());
- root->update_canvas_items(); //force them to update just in case
-
- } break;
- case STRETCH_MODE_VIEWPORT: {
-
- _update_font_oversampling(1.0);
- root->set_size((viewport_size / stretch_shrink).floor());
- root->set_attach_to_screen_rect(Rect2(margin, screen_size));
- root->set_size_override_stretch(false);
- root->set_size_override(false, Size2());
- root->update_canvas_items(); //force them to update just in case
-
- if (use_font_oversampling) {
- WARN_PRINT("Font oversampling does not work in 'Viewport' stretch mode, only '2D'.");
- }
-
- } break;
- }
-}
-
-void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 &p_minsize, real_t p_shrink) {
-
- stretch_mode = p_mode;
- stretch_aspect = p_aspect;
- stretch_min = p_minsize;
- stretch_shrink = p_shrink;
- _update_root_rect();
-}
-
void SceneTree::set_edited_scene_root(Node *p_node) {
#ifdef TOOLS_ENABLED
edited_scene_root = p_node;
@@ -1263,7 +1037,7 @@ Node *SceneTree::get_edited_scene_root() const {
#ifdef TOOLS_ENABLED
return edited_scene_root;
#else
- return NULL;
+ return nullptr;
#endif
}
@@ -1282,7 +1056,7 @@ void SceneTree::_change_scene(Node *p_to) {
if (current_scene) {
memdelete(current_scene);
- current_scene = NULL;
+ current_scene = nullptr;
}
// If we're quitting, abort.
@@ -1308,7 +1082,7 @@ Error SceneTree::change_scene(const String &p_path) {
}
Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) {
- Node *new_scene = NULL;
+ Node *new_scene = nullptr;
if (p_scene.is_valid()) {
new_scene = p_scene->instance();
ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE);
@@ -1330,18 +1104,6 @@ void SceneTree::add_current_scene(Node *p_current) {
root->add_child(p_current);
}
-void SceneTree::drop_files(const Vector<String> &p_files, int p_from_screen) {
-
- emit_signal("files_dropped", p_files, p_from_screen);
- MainLoop::drop_files(p_files, p_from_screen);
-}
-
-void SceneTree::global_menu_action(const Variant &p_id, const Variant &p_meta) {
-
- emit_signal("global_menu_action", p_id, p_meta);
- MainLoop::global_menu_action(p_id, p_meta);
-}
-
Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) {
Ref<SceneTreeTimer> stt;
@@ -1469,8 +1231,6 @@ 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("set_input_as_handled"), &SceneTree::set_input_as_handled);
- ClassDB::bind_method(D_METHOD("is_input_handled"), &SceneTree::is_input_handled);
ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true));
@@ -1478,8 +1238,6 @@ void SceneTree::_bind_methods() {
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("set_screen_stretch", "mode", "aspect", "minsize", "shrink"), &SceneTree::set_screen_stretch, DEFVAL(1));
-
ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete);
MethodInfo mi;
@@ -1529,15 +1287,11 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections);
- ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling);
- ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling);
-
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_font_oversampling"), "set_use_font_oversampling", "is_using_font_oversampling");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
@@ -1549,14 +1303,12 @@ void SceneTree::_bind_methods() {
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")));
- ADD_SIGNAL(MethodInfo("screen_resized"));
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("idle_frame"));
ADD_SIGNAL(MethodInfo("physics_frame"));
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen")));
- ADD_SIGNAL(MethodInfo("global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("connected_to_server"));
@@ -1567,19 +1319,9 @@ void SceneTree::_bind_methods() {
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
BIND_ENUM_CONSTANT(GROUP_CALL_REALTIME);
BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE);
-
- BIND_ENUM_CONSTANT(STRETCH_MODE_DISABLED);
- BIND_ENUM_CONSTANT(STRETCH_MODE_2D);
- BIND_ENUM_CONSTANT(STRETCH_MODE_VIEWPORT);
-
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_IGNORE);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP_WIDTH);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_KEEP_HEIGHT);
- BIND_ENUM_CONSTANT(STRETCH_ASPECT_EXPAND);
}
-SceneTree *SceneTree::singleton = NULL;
+SceneTree *SceneTree::singleton = nullptr;
SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS];
int SceneTree::idle_callback_count = 0;
@@ -1596,19 +1338,6 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
idle_callbacks[idle_callback_count++] = p_callback;
}
-void SceneTree::set_use_font_oversampling(bool p_oversampling) {
-
- if (use_font_oversampling == p_oversampling)
- return;
-
- use_font_oversampling = p_oversampling;
- _update_root_rect();
-}
-
-bool SceneTree::is_using_font_oversampling() const {
- return use_font_oversampling;
-}
-
void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
if (p_function == "change_scene") {
@@ -1643,12 +1372,11 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li
SceneTree::SceneTree() {
- if (singleton == NULL) singleton = this;
+ if (singleton == nullptr) singleton = this;
_quit = false;
accept_quit = true;
quit_on_go_back = true;
initialized = false;
- use_font_oversampling = false;
#ifdef DEBUG_ENABLED
debug_collisions_hint = false;
debug_navigation_hint = false;
@@ -1664,8 +1392,7 @@ SceneTree::SceneTree() {
physics_process_time = 1;
idle_process_time = 1;
- root = NULL;
- input_handled = false;
+ root = nullptr;
pause = false;
current_frame = 0;
current_event = 0;
@@ -1680,11 +1407,10 @@ SceneTree::SceneTree() {
//create with mainloop
- root = memnew(Viewport);
+ root = memnew(Window);
root->set_name("root");
- root->set_handle_input_locally(false);
if (!root->get_world().is_valid())
- root->set_world(Ref<World>(memnew(World)));
+ root->set_world(Ref<World3D>(memnew(World3D)));
// Initialize network state
multiplayer_poll = true;
@@ -1693,12 +1419,16 @@ SceneTree::SceneTree() {
//root->set_world_2d( Ref<World2D>( memnew( World2D )));
root->set_as_audio_listener(true);
root->set_as_audio_listener_2d(true);
- current_scene = NULL;
+ current_scene = nullptr;
- int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"));
+ 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,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"));
root->set_msaa(Viewport::MSAA(msaa_mode));
+ 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,FXAA"));
+ root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
+
{ //load default fallback environment
//get possible extensions
List<String> exts;
@@ -1730,26 +1460,23 @@ SceneTree::SceneTree() {
}
}
- stretch_mode = STRETCH_MODE_DISABLED;
- stretch_aspect = STRETCH_ASPECT_IGNORE;
- stretch_shrink = 1;
-
- last_screen_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
- _update_root_rect();
-
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
+ root->connect("close_requested", callable_mp(this, &SceneTree::_main_window_close));
+ root->connect("go_back_requested", callable_mp(this, &SceneTree::_main_window_go_back));
+ root->connect("focus_entered", callable_mp(this, &SceneTree::_main_window_focus_in));
+
#ifdef TOOLS_ENABLED
- edited_scene_root = NULL;
+ edited_scene_root = nullptr;
#endif
}
SceneTree::~SceneTree() {
if (root) {
- root->_set_tree(NULL);
+ root->_set_tree(nullptr);
root->_propagate_after_exit_tree();
memdelete(root);
}
- if (singleton == this) singleton = NULL;
+ if (singleton == this) singleton = nullptr;
}
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 1bef0d3131..319b5a7e74 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -36,12 +36,14 @@
#include "core/os/thread_safe.h"
#include "core/self_list.h"
#include "scene/resources/mesh.h"
-#include "scene/resources/world.h"
#include "scene/resources/world_2d.h"
+#include "scene/resources/world_3d.h"
+
+#undef Window
class PackedScene;
class Node;
-class Viewport;
+class Window;
class Material;
class Mesh;
class SceneDebugger;
@@ -76,22 +78,6 @@ class SceneTree : public MainLoop {
public:
typedef void (*IdleCallback)();
- enum StretchMode {
-
- STRETCH_MODE_DISABLED,
- STRETCH_MODE_2D,
- STRETCH_MODE_VIEWPORT,
- };
-
- enum StretchAspect {
-
- STRETCH_ASPECT_IGNORE,
- STRETCH_ASPECT_KEEP,
- STRETCH_ASPECT_KEEP_WIDTH,
- STRETCH_ASPECT_KEEP_HEIGHT,
- STRETCH_ASPECT_EXPAND,
- };
-
private:
struct Group {
@@ -101,7 +87,7 @@ private:
Group() { changed = false; };
};
- Viewport *root;
+ Window *root;
uint64_t tree_version;
float physics_process_time;
@@ -119,15 +105,12 @@ private:
Map<StringName, Group> group_map;
bool _quit;
bool initialized;
- bool input_handled;
- Size2 last_screen_size;
StringName tree_changed_name;
StringName node_added_name;
StringName node_removed_name;
StringName node_renamed_name;
- bool use_font_oversampling;
int64_t current_frame;
int64_t current_event;
int node_count;
@@ -147,17 +130,9 @@ private:
int call_lock;
Set<Node *> call_skip; //skip erased nodes
- StretchMode stretch_mode;
- StretchAspect stretch_aspect;
- Size2i stretch_min;
- real_t stretch_shrink;
-
- void _update_font_oversampling(float p_ratio);
- void _update_root_rect();
-
List<ObjectID> delete_queue;
- Map<UGCall, Vector<Variant> > unique_group_calls;
+ Map<UGCall, Vector<Variant>> unique_group_calls;
bool ugc_locked;
void _flush_ugc();
@@ -181,7 +156,7 @@ private:
void _change_scene(Node *p_to);
//void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2);
- List<Ref<SceneTreeTimer> > timers;
+ List<Ref<SceneTreeTimer>> timers;
///network///
@@ -208,14 +183,13 @@ private:
void make_group_changed(const StringName &p_group);
void _notify_group_pause(const StringName &p_group, int p_notification);
- void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input);
Variant _call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
void _flush_delete_queue();
//optimization
friend class CanvasItem;
- friend class Spatial;
+ friend class Node3D;
friend class Viewport;
SelfList<Node>::List xform_change_list;
@@ -232,6 +206,13 @@ private:
static int idle_callback_count;
void _call_idle_callbacks();
+ void _main_window_focus_in();
+ void _main_window_close();
+ void _main_window_go_back();
+
+ //used by viewport
+ void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport);
+
protected:
void _notification(int p_notification);
static void _bind_methods();
@@ -249,7 +230,7 @@ public:
GROUP_CALL_MULTILEVEL = 8,
};
- _FORCE_INLINE_ Viewport *get_root() const { return root; }
+ _FORCE_INLINE_ Window *get_root() const { return root; }
void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST);
void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification);
@@ -261,8 +242,6 @@ public:
void flush_transform_notifications();
- virtual void input_text(const String &p_text);
- virtual void input_event(const Ref<InputEvent> &p_event);
virtual void init();
virtual bool iteration(float p_time);
@@ -275,8 +254,6 @@ public:
void quit(int p_exit_code = -1);
- void set_input_as_handled();
- bool is_input_handled();
_FORCE_INLINE_ float get_physics_process_time() const { return physics_process_time; }
_FORCE_INLINE_ float get_idle_process_time() const { return idle_process_time; }
@@ -335,11 +312,6 @@ public:
void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list);
bool has_group(const StringName &p_identifier) const;
- void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 &p_minsize, real_t p_shrink = 1);
-
- void set_use_font_oversampling(bool p_oversampling);
- bool is_using_font_oversampling() const;
-
//void change_scene(const String& p_path);
//Node *get_loaded_scene();
@@ -359,8 +331,6 @@ public:
static SceneTree *get_singleton() { return singleton; }
- void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
- void global_menu_action(const Variant &p_id, const Variant &p_meta);
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
//network API
@@ -388,8 +358,6 @@ public:
~SceneTree();
};
-VARIANT_ENUM_CAST(SceneTree::StretchMode);
-VARIANT_ENUM_CAST(SceneTree::StretchAspect);
VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
#endif
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 7c847095e1..7c847095e1 100755..100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 044566738e..044566738e 100755..100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index c11b11bc71..72b1a877c1 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -32,14 +32,14 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
-#include "core/os/input.h"
+#include "core/input/input_filter.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "scene/2d/collision_object_2d.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/collision_object.h"
-#include "scene/3d/listener.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/collision_object_3d.h"
+#include "scene/3d/listener_3d.h"
+#include "scene/3d/node_3d.h"
#include "scene/3d/world_environment.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
@@ -49,9 +49,11 @@
#include "scene/gui/popup_menu.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/timer.h"
+#include "scene/main/window.h"
#include "scene/resources/mesh.h"
#include "scene/scene_string_names.h"
-#include "servers/physics_2d_server.h"
+#include "servers/display_server.h"
+#include "servers/physics_server_2d.h"
void ViewportTexture::setup_local_to_scene() {
@@ -59,7 +61,7 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.erase(this);
}
- vp = NULL;
+ vp = nullptr;
Node *local_scene = get_local_scene();
if (!local_scene) {
@@ -76,11 +78,11 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.insert(this);
if (proxy_ph.is_valid()) {
- VS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
+ RS::get_singleton()->free(proxy_ph);
} else {
ERR_FAIL_COND(proxy.is_valid()); //should be invalid
- proxy = VS::get_singleton()->texture_proxy_create(vp->texture_rid);
+ proxy = RS::get_singleton()->texture_proxy_create(vp->texture_rid);
}
}
@@ -120,8 +122,8 @@ RID ViewportTexture::get_rid() const {
//ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it.");
if (proxy.is_null()) {
- proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
- proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
+ proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
+ proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
}
return proxy;
}
@@ -133,7 +135,7 @@ bool ViewportTexture::has_alpha() const {
Ref<Image> ViewportTexture::get_data() const {
ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
- return VS::get_singleton()->texture_2d_get(vp->texture_rid);
+ return RS::get_singleton()->texture_2d_get(vp->texture_rid);
}
void ViewportTexture::_bind_methods() {
@@ -141,12 +143,12 @@ void ViewportTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene);
ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "SubViewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
}
ViewportTexture::ViewportTexture() {
- vp = NULL;
+ vp = nullptr;
set_local_to_scene(true);
}
@@ -157,18 +159,18 @@ ViewportTexture::~ViewportTexture() {
}
if (proxy_ph.is_valid()) {
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->free(proxy_ph);
}
if (proxy.is_valid()) {
- VS::get_singleton()->free(proxy);
+ RS::get_singleton()->free(proxy);
}
}
/////////////////////////////////////
-class TooltipPanel : public PanelContainer {
+class TooltipPanel : public PopupPanel {
- GDCLASS(TooltipPanel, PanelContainer);
+ GDCLASS(TooltipPanel, PopupPanel);
public:
TooltipPanel(){};
@@ -184,39 +186,25 @@ public:
Viewport::GUI::GUI() {
+ embed_subwindows_hint = false;
+ embedding_subwindows = false;
+
dragging = false;
- mouse_focus = NULL;
- mouse_click_grabber = NULL;
+ mouse_focus = nullptr;
+ forced_mouse_focus = false;
+ mouse_click_grabber = nullptr;
mouse_focus_mask = 0;
- key_focus = NULL;
- mouse_over = NULL;
+ key_focus = nullptr;
+ mouse_over = nullptr;
+ drag_mouse_over = nullptr;
- tooltip = NULL;
- tooltip_popup = NULL;
- tooltip_label = NULL;
- subwindow_visibility_dirty = false;
- subwindow_order_dirty = false;
+ tooltip = nullptr;
+ tooltip_popup = nullptr;
+ tooltip_label = nullptr;
}
/////////////////////////////////////
-void Viewport::_update_stretch_transform() {
-
- if (size_override_stretch && size_override) {
-
- stretch_transform = Transform2D();
- Size2 scale = size / (size_override_size + size_override_margin * 2);
- stretch_transform.scale(scale);
- stretch_transform.elements[2] = size_override_margin * scale;
-
- } else {
-
- stretch_transform = Transform2D();
- }
-
- _update_global_transform();
-}
-
void Viewport::update_worlds() {
if (!is_inside_tree())
@@ -230,7 +218,7 @@ void Viewport::update_worlds() {
find_world()->_update(get_tree()->get_frame());
}
-void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
+void Viewport::_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) {
Transform object_transform = p_object->get_global_transform();
Transform camera_transform = p_camera->get_global_transform();
@@ -249,6 +237,191 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *
physics_last_id = id;
}
+void Viewport::_sub_window_update_order() {
+
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ RS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i);
+ }
+}
+
+void Viewport::_sub_window_register(Window *p_window) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ ERR_FAIL_COND(gui.sub_windows[i].window == p_window);
+ }
+
+ if (gui.sub_windows.size() == 0) {
+ subwindow_canvas = RS::get_singleton()->canvas_create();
+ RS::get_singleton()->viewport_attach_canvas(viewport, subwindow_canvas);
+ RS::get_singleton()->viewport_set_canvas_stacking(viewport, subwindow_canvas, SUBWINDOW_CANVAS_LAYER, 0);
+ }
+ SubWindow sw;
+ sw.canvas_item = RS::get_singleton()->canvas_item_create();
+ RS::get_singleton()->canvas_item_set_parent(sw.canvas_item, subwindow_canvas);
+ sw.window = p_window;
+ gui.sub_windows.push_back(sw);
+
+ _sub_window_grab_focus(p_window);
+
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, viewport);
+}
+
+void Viewport::_sub_window_update(Window *p_window) {
+
+ int index = -1;
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ index = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(index == -1);
+
+ const SubWindow &sw = gui.sub_windows[index];
+
+ Transform2D pos;
+ pos.set_origin(p_window->get_position());
+ RS::get_singleton()->canvas_item_clear(sw.canvas_item);
+ Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size());
+
+ if (!p_window->get_flag(Window::FLAG_BORDERLESS)) {
+ Ref<StyleBox> panel = p_window->get_theme_stylebox("panel_window");
+ panel->draw(sw.canvas_item, r);
+
+ // Draw the title bar text.
+ Ref<Font> title_font = p_window->get_theme_font("title_font");
+ Color title_color = p_window->get_theme_color("title_color");
+ int title_height = p_window->get_theme_constant("title_height");
+ int font_height = title_font->get_height() - title_font->get_descent() * 2;
+ int x = (r.size.width - title_font->get_string_size(p_window->get_title()).x) / 2;
+ int y = (-title_height + font_height) / 2;
+
+ int close_h_ofs = p_window->get_theme_constant("close_h_ofs");
+ int close_v_ofs = p_window->get_theme_constant("close_v_ofs");
+
+ title_font->draw(sw.canvas_item, r.position + Point2(x, y), p_window->get_title(), title_color, r.size.width - panel->get_minimum_size().x - close_h_ofs);
+
+ bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
+
+ Ref<Texture2D> close_icon = p_window->get_theme_icon(hl ? "close_highlight" : "close");
+ close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs));
+ }
+
+ RS::get_singleton()->canvas_item_add_texture_rect(sw.canvas_item, r, sw.window->get_texture()->get_rid());
+}
+
+void Viewport::_sub_window_grab_focus(Window *p_window) {
+
+ if (p_window == nullptr) {
+ //release current focus
+ if (gui.subwindow_focused) {
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ gui.subwindow_focused = nullptr;
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+ }
+
+ Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ }
+
+ return;
+ }
+
+ int index = -1;
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ index = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(index == -1);
+
+ if (p_window->get_flag(Window::FLAG_NO_FOCUS)) {
+ //can only move to foreground, but no focus granted
+ SubWindow sw = gui.sub_windows[index];
+ gui.sub_windows.remove(index);
+ gui.sub_windows.push_back(sw);
+ index = gui.sub_windows.size() - 1;
+ _sub_window_update_order();
+ return; //i guess not...
+ }
+
+ if (gui.subwindow_focused) {
+ if (gui.subwindow_focused == p_window) {
+ return; //nothing to do
+ }
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+ } else {
+ Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+ }
+ }
+
+ Window *old_focus = gui.subwindow_focused;
+
+ gui.subwindow_focused = p_window;
+
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+
+ { //move to foreground
+ SubWindow sw = gui.sub_windows[index];
+ gui.sub_windows.remove(index);
+ gui.sub_windows.push_back(sw);
+ index = gui.sub_windows.size() - 1;
+ _sub_window_update_order();
+ }
+
+ if (old_focus) {
+ _sub_window_update(old_focus);
+ }
+
+ _sub_window_update(p_window);
+}
+
+void Viewport::_sub_window_remove(Window *p_window) {
+
+ for (int i = 0; i < gui.sub_windows.size(); i++) {
+ if (gui.sub_windows[i].window == p_window) {
+ RS::get_singleton()->free(gui.sub_windows[i].canvas_item);
+ gui.sub_windows.remove(i);
+ break;
+ }
+ }
+
+ if (gui.sub_windows.size() == 0) {
+ RS::get_singleton()->free(subwindow_canvas);
+ subwindow_canvas = RID();
+ }
+
+ if (gui.subwindow_focused == p_window) {
+ Window *parent_visible = p_window->get_parent_visible_window();
+
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
+
+ if (parent_visible && parent_visible != this) {
+
+ gui.subwindow_focused = parent_visible;
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ } else {
+ gui.subwindow_focused = nullptr;
+ Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN);
+ }
+ }
+ }
+
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID());
+}
+
void Viewport::_own_world_changed() {
ERR_FAIL_COND(world.is_null());
ERR_FAIL_COND(own_world.is_null());
@@ -264,7 +437,7 @@ void Viewport::_own_world_changed() {
}
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
_update_listener();
@@ -276,16 +449,18 @@ void Viewport::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
+ gui.embedding_subwindows = gui.embed_subwindows_hint;
+
if (get_parent()) {
parent = get_parent()->get_viewport();
- VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid());
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid());
} else {
- parent = NULL;
+ parent = nullptr;
}
current_canvas = find_world_2d()->get_canvas();
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
_update_listener();
_update_listener_2d();
@@ -295,30 +470,29 @@ void Viewport::_notification(int p_what) {
add_to_group("_viewports");
if (get_tree()->is_debugging_collisions_hint()) {
//2D
- Physics2DServer::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
- contact_2d_debug = VisualServer::get_singleton()->canvas_item_create();
- VisualServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
+ PhysicsServer2D::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
+ contact_2d_debug = RenderingServer::get_singleton()->canvas_item_create();
+ RenderingServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
//3D
- PhysicsServer::get_singleton()->space_set_debug_contacts(find_world()->get_space(), get_tree()->get_collision_debug_contact_count());
- contact_3d_debug_multimesh = VisualServer::get_singleton()->multimesh_create();
- VisualServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), VS::MULTIMESH_TRANSFORM_3D, true);
- VisualServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
- VisualServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
- contact_3d_debug_instance = VisualServer::get_singleton()->instance_create();
- VisualServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
- VisualServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world()->get_scenario());
- //VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
- }
-
- VS::get_singleton()->viewport_set_active(viewport, true);
+ PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world()->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_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();
+ RenderingServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
+ RenderingServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world()->get_scenario());
+ //RenderingServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, RS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
+ }
+
} break;
case NOTIFICATION_READY: {
#ifndef _3D_DISABLED
if (listeners.size() && !listener) {
- Listener *first = NULL;
- for (Set<Listener *>::Element *E = listeners.front(); E; E = E->next()) {
+ Listener3D *first = nullptr;
+ for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
- if (first == NULL || first->is_greater_than(E->get())) {
+ if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
}
@@ -329,10 +503,10 @@ void Viewport::_notification(int p_what) {
if (cameras.size() && !camera) {
//there are cameras but no current camera, pick first in tree and make it current
- Camera *first = NULL;
- for (Set<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
+ Camera3D *first = nullptr;
+ for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
- if (first == NULL || first->is_greater_than(E->get())) {
+ if (first == nullptr || first->is_greater_than(E->get())) {
first = E->get();
}
}
@@ -353,24 +527,24 @@ void Viewport::_notification(int p_what) {
if (world_2d.is_valid())
world_2d->_remove_viewport(this);
- VisualServer::get_singleton()->viewport_set_scenario(viewport, RID());
- // SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID());
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
if (contact_2d_debug.is_valid()) {
- VisualServer::get_singleton()->free(contact_2d_debug);
+ RenderingServer::get_singleton()->free(contact_2d_debug);
contact_2d_debug = RID();
}
if (contact_3d_debug_multimesh.is_valid()) {
- VisualServer::get_singleton()->free(contact_3d_debug_multimesh);
- VisualServer::get_singleton()->free(contact_3d_debug_instance);
+ RenderingServer::get_singleton()->free(contact_3d_debug_multimesh);
+ RenderingServer::get_singleton()->free(contact_3d_debug_instance);
contact_3d_debug_instance = RID();
contact_3d_debug_multimesh = RID();
}
remove_from_group("_viewports");
- VS::get_singleton()->viewport_set_active(viewport, false);
+ RS::get_singleton()->viewport_set_active(viewport, false);
+ RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, RID());
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
@@ -387,42 +561,42 @@ void Viewport::_notification(int p_what) {
if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
- VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug);
- VisualServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
+ RenderingServer::get_singleton()->canvas_item_clear(contact_2d_debug);
+ RenderingServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
- Vector<Vector2> points = Physics2DServer::get_singleton()->space_get_contacts(find_world_2d()->get_space());
- int point_count = Physics2DServer::get_singleton()->space_get_contact_count(find_world_2d()->get_space());
+ Vector<Vector2> points = PhysicsServer2D::get_singleton()->space_get_contacts(find_world_2d()->get_space());
+ int point_count = PhysicsServer2D::get_singleton()->space_get_contact_count(find_world_2d()->get_space());
Color ccol = get_tree()->get_debug_collision_contact_color();
for (int i = 0; i < point_count; i++) {
- VisualServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
+ RenderingServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
}
}
if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
- Vector<Vector3> points = PhysicsServer::get_singleton()->space_get_contacts(find_world()->get_space());
- int point_count = PhysicsServer::get_singleton()->space_get_contact_count(find_world()->get_space());
+ Vector<Vector3> points = PhysicsServer3D::get_singleton()->space_get_contacts(find_world()->get_space());
+ int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world()->get_space());
- VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
+ RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
}
- if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) {
+ if (physics_object_picking && (to_screen_rect == Rect2i() || InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED)) {
#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
- CollisionObject *last_object = NULL;
+ CollisionObject3D *last_object = nullptr;
ObjectID last_id;
#endif
- PhysicsDirectSpaceState::RayResult result;
- Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
+ PhysicsDirectSpaceState3D::RayResult result;
+ PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
if (physics_has_last_mousepos) {
// if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
// while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame
bool has_mouse_event = false;
- for (List<Ref<InputEvent> >::Element *E = physics_picking_events.front(); E; E = E->next()) {
+ for (List<Ref<InputEvent>>::Element *E = physics_picking_events.front(); E; E = E->next()) {
Ref<InputEventMouse> m = E->get();
if (m.is_valid()) {
has_mouse_event = true;
@@ -433,6 +607,7 @@ void Viewport::_notification(int p_what) {
if (!has_mouse_event) {
Ref<InputEventMouseMotion> mm;
mm.instance();
+
mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
mm->set_global_position(physics_last_mousepos);
mm->set_position(physics_last_mousepos);
@@ -522,7 +697,7 @@ void Viewport::_notification(int p_what) {
uint64_t frame = get_tree()->get_frame();
- Physics2DDirectSpaceState::ShapeResult res[64];
+ PhysicsDirectSpaceState2D::ShapeResult res[64];
for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
Transform2D canvas_transform;
ObjectID canvas_layer_id;
@@ -597,7 +772,7 @@ void Viewport::_notification(int p_what) {
if (physics_object_capture.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture));
if (co && camera) {
_collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0);
captured = true;
@@ -630,14 +805,14 @@ void Viewport::_notification(int p_what) {
Vector3 from = camera->project_ray_origin(pos);
Vector3 dir = camera->project_ray_normal(pos);
- PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
+ PhysicsDirectSpaceState3D *space = PhysicsServer3D::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider;
if (col) {
- CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider);
if (co) {
_collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape);
@@ -654,7 +829,7 @@ void Viewport::_notification(int p_what) {
if (physics_object_over.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
if (co) {
co->_mouse_exit();
}
@@ -662,7 +837,7 @@ void Viewport::_notification(int p_what) {
if (new_collider.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider));
if (co) {
co->_mouse_enter();
}
@@ -680,13 +855,12 @@ void Viewport::_notification(int p_what) {
}
} break;
- case SceneTree::NOTIFICATION_WM_MOUSE_EXIT:
- case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_WM_MOUSE_EXIT:
+ case NOTIFICATION_WM_FOCUS_OUT: {
_drop_physics_mouseover();
- if (gui.mouse_focus) {
- //if mouse is being pressed, send a release event
+ if (gui.mouse_focus && !gui.forced_mouse_focus) {
_drop_mouse_focus();
}
} break;
@@ -698,16 +872,6 @@ RID Viewport::get_viewport_rid() const {
return viewport;
}
-void Viewport::set_use_arvr(bool p_use_arvr) {
- arvr = p_use_arvr;
-
- VS::get_singleton()->viewport_set_use_arvr(viewport, arvr);
-}
-
-bool Viewport::use_arvr() {
- return arvr;
-}
-
void Viewport::update_canvas_items() {
if (!is_inside_tree())
return;
@@ -715,48 +879,57 @@ void Viewport::update_canvas_items() {
_update_canvas_items(this);
}
-void Viewport::set_size(const Size2 &p_size) {
+void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) {
- if (size == p_size.floor())
+ if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect != p_to_screen_rect)
return;
- size = p_size.floor();
- VS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- _update_stretch_transform();
+ size = p_size;
+ size_allocated = p_allocated;
+ size_2d_override = p_size_2d_override;
+ stretch_transform = p_stretch_transform;
+ to_screen_rect = p_to_screen_rect;
+
+ if (p_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+ _update_global_transform();
+
+ update_canvas_items();
emit_signal("size_changed");
}
+Size2i Viewport::_get_size() const {
+ return size;
+}
+Size2i Viewport::_get_size_2d_override() const {
+ return size_2d_override;
+}
+bool Viewport::_is_size_allocated() const {
+ return size_allocated;
+}
+
Rect2 Viewport::get_visible_rect() const {
Rect2 r;
if (size == Size2()) {
- r = Rect2(Point2(), OS::get_singleton()->get_window_size());
+ r = Rect2(Point2(), DisplayServer::get_singleton()->window_get_size());
} else {
r = Rect2(Point2(), size);
}
- if (size_override) {
- r.size = size_override_size;
+ if (size_2d_override != Size2i()) {
+ r.size = size_2d_override;
}
return r;
}
-Size2 Viewport::get_size() const {
-
- return size;
-}
-
void Viewport::_update_listener() {
- /*
- if (is_inside_tree() && audio_listener && (camera || listener) && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree()))) {
- SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, find_world()->get_sound_space());
- } else {
- SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
- }
-*/
}
void Viewport::_update_listener_2d() {
@@ -805,9 +978,9 @@ void Viewport::enable_canvas_transform_override(bool p_enable) {
override_canvas_transform = p_enable;
if (p_enable) {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
} else {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
}
}
@@ -822,7 +995,7 @@ void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
canvas_transform_override = p_transform;
if (override_canvas_transform) {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
}
}
@@ -835,7 +1008,7 @@ void Viewport::set_canvas_transform(const Transform2D &p_transform) {
canvas_transform = p_transform;
if (!override_canvas_transform) {
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+ RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
}
}
@@ -848,7 +1021,7 @@ void Viewport::_update_global_transform() {
Transform2D sxform = stretch_transform * global_canvas_transform;
- VisualServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform);
+ RenderingServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform);
}
void Viewport::set_global_canvas_transform(const Transform2D &p_transform) {
@@ -864,14 +1037,9 @@ Transform2D Viewport::get_global_canvas_transform() const {
}
void Viewport::_listener_transform_changed_notify() {
-
-#ifndef _3D_DISABLED
-//if (listener)
-// SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, listener->get_listener_transform());
-#endif
}
-void Viewport::_listener_set(Listener *p_listener) {
+void Viewport::_listener_set(Listener3D *p_listener) {
#ifndef _3D_DISABLED
@@ -885,38 +1053,38 @@ void Viewport::_listener_set(Listener *p_listener) {
#endif
}
-bool Viewport::_listener_add(Listener *p_listener) {
+bool Viewport::_listener_add(Listener3D *p_listener) {
listeners.insert(p_listener);
return listeners.size() == 1;
}
-void Viewport::_listener_remove(Listener *p_listener) {
+void Viewport::_listener_remove(Listener3D *p_listener) {
listeners.erase(p_listener);
if (listener == p_listener) {
- listener = NULL;
+ listener = nullptr;
}
}
#ifndef _3D_DISABLED
-void Viewport::_listener_make_next_current(Listener *p_exclude) {
+void Viewport::_listener_make_next_current(Listener3D *p_exclude) {
if (listeners.size() > 0) {
- for (Set<Listener *>::Element *E = listeners.front(); E; E = E->next()) {
+ for (Set<Listener3D *>::Element *E = listeners.front(); E; E = E->next()) {
if (p_exclude == E->get())
continue;
if (!E->get()->is_inside_tree())
continue;
- if (listener != NULL)
+ if (listener != nullptr)
return;
E->get()->make_current();
}
} else {
// Attempt to reset listener to the camera position
- if (camera != NULL) {
+ if (camera != nullptr) {
_update_listener();
_camera_transform_changed_notify();
}
@@ -927,13 +1095,10 @@ void Viewport::_listener_make_next_current(Listener *p_exclude) {
void Viewport::_camera_transform_changed_notify() {
#ifndef _3D_DISABLED
-// If there is an active listener in the scene, it takes priority over the camera
-// if (camera && !listener)
-// SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, camera->get_camera_transform());
#endif
}
-void Viewport::_camera_set(Camera *p_camera) {
+void Viewport::_camera_set(Camera3D *p_camera) {
#ifndef _3D_DISABLED
@@ -941,18 +1106,20 @@ void Viewport::_camera_set(Camera *p_camera) {
return;
if (camera) {
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
+ camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
}
+
camera = p_camera;
+
if (!camera_override) {
if (camera)
- VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
else
- VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
}
if (camera) {
- camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
+ camera->notification(Camera3D::NOTIFICATION_BECAME_CURRENT);
}
_update_listener();
@@ -960,31 +1127,31 @@ void Viewport::_camera_set(Camera *p_camera) {
#endif
}
-bool Viewport::_camera_add(Camera *p_camera) {
+bool Viewport::_camera_add(Camera3D *p_camera) {
cameras.insert(p_camera);
return cameras.size() == 1;
}
-void Viewport::_camera_remove(Camera *p_camera) {
+void Viewport::_camera_remove(Camera3D *p_camera) {
cameras.erase(p_camera);
if (camera == p_camera) {
- camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
- camera = NULL;
+ camera->notification(Camera3D::NOTIFICATION_LOST_CURRENT);
+ camera = nullptr;
}
}
#ifndef _3D_DISABLED
-void Viewport::_camera_make_next_current(Camera *p_exclude) {
+void Viewport::_camera_make_next_current(Camera3D *p_exclude) {
- for (Set<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
+ for (Set<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) {
if (p_exclude == E->get())
continue;
if (!E->get()->is_inside_tree())
continue;
- if (camera != NULL)
+ if (camera != nullptr)
return;
E->get()->make_current();
@@ -1005,7 +1172,7 @@ void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
void Viewport::set_transparent_background(bool p_enable) {
transparent_bg = p_enable;
- VS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
+ RS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
}
bool Viewport::has_transparent_background() const {
@@ -1024,7 +1191,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (is_inside_tree()) {
find_world_2d()->_remove_viewport(this);
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
}
if (p_world_2d.is_valid())
@@ -1038,7 +1205,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
if (is_inside_tree()) {
current_canvas = find_world_2d()->get_canvas();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
find_world_2d()->_register_viewport(this, Rect2());
}
}
@@ -1060,17 +1227,20 @@ void Viewport::_propagate_enter_world(Node *p_node) {
if (!p_node->is_inside_tree()) //may not have entered scene yet
return;
- if (Object::cast_to<Spatial>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
-
- p_node->notification(Spatial::NOTIFICATION_ENTER_WORLD);
+#ifndef _3D_DISABLED
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_ENTER_WORLD);
} else {
+#endif
Viewport *v = Object::cast_to<Viewport>(p_node);
if (v) {
if (v->world.is_valid() || v->own_world.is_valid())
return;
}
+#ifndef _3D_DISABLED
}
+#endif
}
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -1097,17 +1267,20 @@ void Viewport::_propagate_exit_world(Node *p_node) {
if (!p_node->is_inside_tree()) //may have exited scene already
return;
- if (Object::cast_to<Spatial>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
-
- p_node->notification(Spatial::NOTIFICATION_EXIT_WORLD);
+#ifndef _3D_DISABLED
+ if (Object::cast_to<Node3D>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
+ p_node->notification(Node3D::NOTIFICATION_EXIT_WORLD);
} else {
+#endif
Viewport *v = Object::cast_to<Viewport>(p_node);
if (v) {
if (v->world.is_valid() || v->own_world.is_valid())
return;
}
+#ifndef _3D_DISABLED
}
+#endif
}
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -1116,7 +1289,7 @@ void Viewport::_propagate_exit_world(Node *p_node) {
}
}
-void Viewport::set_world(const Ref<World> &p_world) {
+void Viewport::set_world(const Ref<World3D> &p_world) {
if (world == p_world)
return;
@@ -1135,7 +1308,7 @@ void Viewport::set_world(const Ref<World> &p_world) {
own_world = world->duplicate();
world->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
} else {
- own_world = Ref<World>(memnew(World));
+ own_world = Ref<World3D>(memnew(World3D));
}
}
@@ -1143,13 +1316,13 @@ void Viewport::set_world(const Ref<World> &p_world) {
_propagate_enter_world(this);
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
_update_listener();
}
-Ref<World> Viewport::get_world() const {
+Ref<World3D> Viewport::get_world() const {
return world;
}
@@ -1159,7 +1332,7 @@ Ref<World2D> Viewport::get_world_2d() const {
return world_2d;
}
-Ref<World> Viewport::find_world() const {
+Ref<World3D> Viewport::find_world() const {
if (own_world.is_valid())
return own_world;
@@ -1168,15 +1341,15 @@ Ref<World> Viewport::find_world() const {
else if (parent)
return parent->find_world();
else
- return Ref<World>();
+ return Ref<World3D>();
}
-Listener *Viewport::get_listener() const {
+Listener3D *Viewport::get_listener() const {
return listener;
}
-Camera *Viewport::get_camera() const {
+Camera3D *Viewport::get_camera() const {
return camera;
}
@@ -1188,18 +1361,18 @@ void Viewport::enable_camera_override(bool p_enable) {
}
if (p_enable) {
- camera_override.rid = VisualServer::get_singleton()->camera_create();
+ camera_override.rid = RenderingServer::get_singleton()->camera_create();
} else {
- VisualServer::get_singleton()->free(camera_override.rid);
+ RenderingServer::get_singleton()->free(camera_override.rid);
camera_override.rid = RID();
}
if (p_enable) {
- VisualServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
} else if (camera) {
- VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
} else {
- VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+ RenderingServer::get_singleton()->viewport_attach_camera(viewport, RID());
}
#endif
}
@@ -1211,7 +1384,7 @@ bool Viewport::is_camera_override_enabled() const {
void Viewport::set_camera_override_transform(const Transform &p_transform) {
if (camera_override) {
camera_override.transform = p_transform;
- VisualServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
+ RenderingServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
}
}
@@ -1234,7 +1407,7 @@ void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_n
camera_override.z_far = p_z_far;
camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE;
- VisualServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
+ RenderingServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
}
}
@@ -1249,7 +1422,7 @@ void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, floa
camera_override.z_far = p_z_far;
camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL;
- VisualServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
+ RenderingServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
}
}
@@ -1278,77 +1451,18 @@ void Viewport::_update_canvas_items(Node *p_node) {
}
}
-void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vector2 &p_margin) {
-
- if (size_override == p_enable && p_size == size_override_size)
- return;
-
- size_override = p_enable;
- if (p_size.x >= 0 || p_size.y >= 0) {
- size_override_size = p_size;
- }
- size_override_margin = p_margin;
-
- _update_stretch_transform();
- emit_signal("size_changed");
-}
-
-Size2 Viewport::get_size_override() const {
-
- return size_override_size;
-}
-bool Viewport::is_size_override_enabled() const {
-
- return size_override;
-}
-void Viewport::set_size_override_stretch(bool p_enable) {
-
- if (p_enable == size_override_stretch)
- return;
-
- size_override_stretch = p_enable;
-
- _update_stretch_transform();
-}
-
-bool Viewport::is_size_override_stretch_enabled() const {
-
- return size_override_stretch;
-}
-
-void Viewport::set_update_mode(UpdateMode p_mode) {
-
- update_mode = p_mode;
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::ViewportUpdateMode(p_mode));
-}
-Viewport::UpdateMode Viewport::get_update_mode() const {
-
- return update_mode;
-}
-
Ref<ViewportTexture> Viewport::get_texture() const {
return default_texture;
}
-void Viewport::set_clear_mode(ClearMode p_mode) {
-
- clear_mode = p_mode;
- VS::get_singleton()->viewport_set_clear_mode(viewport, VS::ViewportClearMode(p_mode));
-}
-
-Viewport::ClearMode Viewport::get_clear_mode() const {
-
- return clear_mode;
-}
-
void Viewport::set_shadow_atlas_size(int p_size) {
if (shadow_atlas_size == p_size)
return;
shadow_atlas_size = p_size;
- VS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size);
+ RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size);
}
int Viewport::get_shadow_atlas_size() const {
@@ -1367,7 +1481,7 @@ void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadr
shadow_atlas_quadrant_subdiv[p_quadrant] = p_subdiv;
static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX] = { 0, 1, 4, 16, 64, 256, 1024 };
- VS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport, p_quadrant, subdiv[p_subdiv]);
+ RS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport, p_quadrant, subdiv[p_subdiv]);
}
Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
@@ -1379,7 +1493,7 @@ Transform2D Viewport::_get_input_pre_xform() const {
Transform2D pre_xf;
- if (to_screen_rect != Rect2()) {
+ if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
pre_xf.elements[2] = -to_screen_rect.position;
pre_xf.scale(size / to_screen_rect.size);
@@ -1388,118 +1502,22 @@ Transform2D Viewport::_get_input_pre_xform() const {
return pre_xf;
}
-Vector2 Viewport::_get_window_offset() const {
-
- if (get_parent() && get_parent()->has_method("get_global_position")) {
- return get_parent()->call("get_global_position");
- }
- return Vector2();
-}
-
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
- Vector2 vp_ofs = _get_window_offset();
Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
- return ev->xformed_by(ai, -vp_ofs);
-}
-
-void Viewport::_vp_input_text(const String &p_text) {
-
- if (gui.key_focus) {
- gui.key_focus->call("set_text", p_text);
- }
-}
-
-void Viewport::_vp_input(const Ref<InputEvent> &p_ev) {
-
- if (disable_input)
- return;
-
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
- return;
- }
-#endif
-
- if (to_screen_rect == Rect2())
- return; //if render target, can't get input events
-
- //this one handles system input, p_ev are in system coordinates
- //they are converted to viewport coordinates
-
- Ref<InputEvent> ev = _make_input_local(p_ev);
- input(ev);
-}
-
-void Viewport::_vp_unhandled_input(const Ref<InputEvent> &p_ev) {
-
- if (disable_input)
- return;
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
- return;
- }
-#endif
-
- /*
- if (parent_control && !parent_control->is_visible_in_tree())
- return;
- */
-
- if (to_screen_rect == Rect2())
- return; //if render target, can't get input events
-
- //this one handles system input, p_ev are in system coordinates
- //they are converted to viewport coordinates
-
- Ref<InputEvent> ev = _make_input_local(p_ev);
- unhandled_input(ev);
+ return ev->xformed_by(ai);
}
Vector2 Viewport::get_mouse_position() const {
- return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(Input::get_singleton()->get_mouse_position() - _get_window_offset());
+ return gui.last_mouse_pos;
}
void Viewport::warp_mouse(const Vector2 &p_pos) {
Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos);
- Input::get_singleton()->warp_mouse_position(gpos);
-}
-
-void Viewport::_gui_prepare_subwindows() {
-
- if (gui.subwindow_visibility_dirty) {
-
- gui.subwindows.clear();
- for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) {
- if (E->get()->is_visible_in_tree()) {
- gui.subwindows.push_back(E->get());
- }
- }
-
- gui.subwindow_visibility_dirty = false;
- gui.subwindow_order_dirty = true;
- }
-
- _gui_sort_subwindows();
-}
-
-void Viewport::_gui_sort_subwindows() {
-
- if (!gui.subwindow_order_dirty)
- return;
-
- gui.modal_stack.sort_custom<Control::CComparator>();
- gui.subwindows.sort_custom<Control::CComparator>();
-
- gui.subwindow_order_dirty = false;
-}
-
-void Viewport::_gui_sort_modal_stack() {
-
- gui.modal_stack.sort_custom<Control::CComparator>();
+ InputFilter::get_singleton()->warp_mouse_position(gpos);
}
void Viewport::_gui_sort_roots() {
@@ -1514,12 +1532,12 @@ void Viewport::_gui_sort_roots() {
void Viewport::_gui_cancel_tooltip() {
- gui.tooltip = NULL;
+ gui.tooltip = nullptr;
gui.tooltip_timer = -1;
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
- gui.tooltip_popup = NULL;
- gui.tooltip_label = NULL;
+ gui.tooltip_popup = nullptr;
+ gui.tooltip_label = nullptr;
}
}
@@ -1557,7 +1575,7 @@ void Viewport::_gui_show_tooltip() {
return;
}
- Control *which = NULL;
+ Control *which = nullptr;
String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
tooltip = tooltip.strip_edges();
if (tooltip.length() == 0)
@@ -1565,8 +1583,8 @@ void Viewport::_gui_show_tooltip() {
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
- gui.tooltip_popup = NULL;
- gui.tooltip_label = NULL;
+ gui.tooltip_popup = nullptr;
+ gui.tooltip_label = nullptr;
}
if (!which) {
@@ -1575,47 +1593,49 @@ void Viewport::_gui_show_tooltip() {
Control *rp = which;
- gui.tooltip_popup = which->make_custom_tooltip(tooltip);
-
- if (!gui.tooltip_popup) {
- gui.tooltip_popup = memnew(TooltipPanel);
+ Control *base_tooltip = which->make_custom_tooltip(tooltip);
+ if (!base_tooltip) {
gui.tooltip_label = memnew(TooltipLabel);
- gui.tooltip_popup->add_child(gui.tooltip_label);
-
- Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel");
-
- gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT));
- gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP));
- gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
- gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
gui.tooltip_label->set_text(tooltip);
+ base_tooltip = gui.tooltip_label;
}
+ base_tooltip->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+
+ TooltipPanel *panel = memnew(TooltipPanel);
+ panel->set_transient(false);
+ panel->set_flag(Window::FLAG_NO_FOCUS, true);
+ panel->set_wrap_controls(true);
+ panel->add_child(base_tooltip);
+
+ gui.tooltip_popup = panel;
+
rp->add_child(gui.tooltip_popup);
- gui.tooltip_popup->force_parent_owned();
- gui.tooltip_popup->set_as_toplevel(true);
- if (gui.tooltip) // Avoids crash when rapidly switching controls.
- gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
+
+ //if (gui.tooltip) // Avoids crash when rapidly switching controls.
+ // gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
- Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
- Rect2 vr = gui.tooltip_popup->get_viewport_rect();
- if (r.size.x * gui.tooltip_popup->get_scale().x + r.position.x > vr.size.x)
- r.position.x = vr.size.x - r.size.x * gui.tooltip_popup->get_scale().x;
- else if (r.position.x < 0)
- r.position.x = 0;
-
- if (r.size.y * gui.tooltip_popup->get_scale().y + r.position.y > vr.size.y)
- r.position.y = vr.size.y - r.size.y * gui.tooltip_popup->get_scale().y;
- else if (r.position.y < 0)
- r.position.y = 0;
-
- gui.tooltip_popup->set_global_position(r.position);
+ Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
+
+ Rect2i vr = gui.tooltip_popup->get_parent_visible_window()->get_usable_parent_rect();
+
+ if (r.size.x + r.position.x > vr.size.x + vr.position.x)
+ r.position.x = vr.position.x + vr.size.x - r.size.x;
+ else if (r.position.x < vr.position.x)
+ r.position.x = vr.position.x;
+
+ if (r.size.y + r.position.y > vr.size.y + vr.position.y)
+ r.position.y = vr.position.y + vr.size.y - r.size.y;
+ else if (r.position.y < vr.position.y)
+ r.position.y = vr.position.y;
+
+ gui.tooltip_popup->set_position(r.position);
gui.tooltip_popup->set_size(r.size);
- gui.tooltip_popup->raise();
gui.tooltip_popup->show();
+ gui.tooltip_popup->child_controls_changed();
}
void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_input) {
@@ -1635,7 +1655,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Ref<InputEventPanGesture> pn = p_input;
cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
- bool ismouse = ev.is_valid() || Object::cast_to<InputEventMouseMotion>(*p_input) != NULL;
+ bool ismouse = ev.is_valid() || Object::cast_to<InputEventMouseMotion>(*p_input) != nullptr;
CanvasItem *ci = p_control;
while (ci) {
@@ -1704,26 +1724,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
}
Control *Viewport::_gui_find_control(const Point2 &p_global) {
- _gui_prepare_subwindows();
-
- for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) {
-
- Control *sw = E->get();
- if (!sw->is_visible_in_tree())
- continue;
-
- Transform2D xform;
- CanvasItem *pci = sw->get_parent_item();
- if (pci)
- xform = pci->get_global_transform_with_canvas();
- else
- xform = sw->get_canvas_transform();
-
- Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
- if (ret)
- return ret;
- }
-
+ //aca va subwindows
_gui_sort_roots();
for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) {
@@ -1744,25 +1745,23 @@ Control *Viewport::_gui_find_control(const Point2 &p_global) {
return ret;
}
- return NULL;
+ return nullptr;
}
Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
if (Object::cast_to<Viewport>(p_node))
- return NULL;
-
- //subwindows first!!
+ return nullptr;
if (!p_node->is_visible()) {
//return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
- return NULL; //canvas item hidden, discard
+ return nullptr; //canvas item hidden, discard
}
Transform2D matrix = p_xform * p_node->get_transform();
// matrix.basis_determinant() == 0.0f implies that node does not exist on scene
if (matrix.basis_determinant() == 0.0f)
- return NULL;
+ return nullptr;
Control *c = Object::cast_to<Control>(p_node);
@@ -1770,9 +1769,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
- if (p_node == gui.tooltip_popup)
- continue;
-
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i));
if (!ci || ci->is_set_as_toplevel())
continue;
@@ -1784,7 +1780,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
}
if (!c)
- return NULL;
+ return nullptr;
matrix.affine_invert();
@@ -1793,7 +1789,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
r_inv_xform = matrix;
return c;
} else
- return NULL;
+ return nullptr;
}
bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) {
@@ -1858,39 +1854,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool is_handled = false;
- _gui_sort_modal_stack();
- while (!gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
- Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
- if (!top->has_point(pos2)) {
-
- if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) {
- //cancel event, sorry, modal exclusive EATS UP ALL
- //alternative, you can't pop out a window the same frame it was made modal (fixes many issues)
- set_input_as_handled();
-
- return; // no one gets the event if exclusive NO ONE
- }
-
- if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
- //cancel scroll wheel events, only clicks should trigger focus changes.
- set_input_as_handled();
- return;
- }
-
- top->notification(Control::NOTIFICATION_MODAL_CLOSE);
- top->_modal_stack_remove();
- top->hide();
-
- if (!top->pass_on_modal_close_click()) {
- is_handled = true;
- }
- } else {
- break;
- }
- }
-
if (is_handled) {
set_input_as_handled();
return;
@@ -1979,7 +1942,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_preview) {
memdelete(gui.drag_preview);
- gui.drag_preview = NULL;
+ gui.drag_preview = nullptr;
}
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
@@ -1992,20 +1955,18 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
- if (gui.mouse_over) {
- Size2 pos = mpos;
- pos = gui.focus_inv_xform.xform(pos);
-
- _gui_drop(gui.mouse_over, pos, false);
+ 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 = NULL;
+ gui.drag_preview = nullptr;
}
gui.drag_data = Variant();
gui.dragging = false;
+ gui.drag_mouse_over = nullptr;
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
}
@@ -2028,7 +1989,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
if (gui.mouse_focus_mask == 0) {
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
}
if (mouse_focus && mouse_focus->can_process()) {
@@ -2053,7 +2015,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.last_mouse_pos = mpos;
- Control *over = NULL;
+ Control *over = nullptr;
// D&D
if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) {
@@ -2073,14 +2035,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum);
if (gui.drag_data.get_type() != Variant::NIL) {
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
gui.mouse_focus_mask = 0;
break;
} else {
- if (gui.drag_preview != NULL) {
+ if (gui.drag_preview != nullptr) {
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 = NULL;
+ gui.drag_preview = nullptr;
}
gui.dragging = false;
}
@@ -2113,45 +2076,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
over = _gui_find_control(mpos);
}
- if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
-
- if (over != top && !top->is_a_parent_of(over)) {
-
- PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top);
- MenuButton *popup_menu_parent = NULL;
- MenuButton *menu_button = Object::cast_to<MenuButton>(over);
-
- if (popup_menu) {
- popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
- if (!popup_menu_parent) {
- // Go through the parents to see if there's a MenuButton at the end.
- while (Object::cast_to<PopupMenu>(popup_menu->get_parent())) {
- popup_menu = Object::cast_to<PopupMenu>(popup_menu->get_parent());
- }
- popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
- }
- }
-
- // If the mouse is over a menu button, this menu will open automatically
- // if there is already a pop-up menu open at the same hierarchical level.
- if (popup_menu_parent && menu_button && popup_menu_parent->is_switch_on_hover() &&
- !menu_button->is_disabled() && menu_button->is_switch_on_hover() &&
- (popup_menu_parent->get_parent()->is_a_parent_of(menu_button) ||
- menu_button->get_parent()->is_a_parent_of(popup_menu))) {
-
- popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE);
- popup_menu->_modal_stack_remove();
- popup_menu->hide();
-
- menu_button->pressed();
- } else {
- over = NULL; //nothing can be found outside the modal stack
- }
- }
- }
-
if (over != gui.mouse_over) {
if (gui.mouse_over) {
@@ -2167,103 +2091,195 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_over = over;
- if (gui.drag_preview) {
- gui.drag_preview->set_position(mpos);
- }
+ DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)InputFilter::get_singleton()->get_default_cursor_shape();
- if (!over) {
- OS::get_singleton()->set_cursor_shape((OS::CursorShape)Input::get_singleton()->get_default_cursor_shape());
- return;
- }
+ if (over) {
- Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
- Size2 pos = localizer.xform(mpos);
- Vector2 speed = localizer.basis_xform(mm->get_speed());
- Vector2 rel = localizer.basis_xform(mm->get_relative());
+ Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
+ Size2 pos = localizer.xform(mpos);
+ Vector2 speed = localizer.basis_xform(mm->get_speed());
+ Vector2 rel = localizer.basis_xform(mm->get_relative());
- mm = mm->xformed_by(Transform2D()); //make a copy
+ mm = mm->xformed_by(Transform2D()); //make a copy
- mm->set_global_position(mpos);
- mm->set_speed(speed);
- mm->set_relative(rel);
+ mm->set_global_position(mpos);
+ mm->set_speed(speed);
+ mm->set_relative(rel);
- if (mm->get_button_mask() == 0) {
- //nothing pressed
+ if (mm->get_button_mask() == 0) {
+ //nothing pressed
- bool can_tooltip = true;
+ bool can_tooltip = true;
- if (!gui.modal_stack.empty()) {
- if (gui.modal_stack.back()->get() != over && !gui.modal_stack.back()->get()->is_a_parent_of(over))
- can_tooltip = false;
- }
+ bool is_tooltip_shown = false;
- bool is_tooltip_shown = false;
+ if (gui.tooltip_popup) {
+ if (can_tooltip && gui.tooltip) {
+ String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
- if (gui.tooltip_popup) {
- if (can_tooltip && gui.tooltip) {
- String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
+ if (tooltip.length() == 0)
+ _gui_cancel_tooltip();
+ else if (gui.tooltip_label) {
+ if (tooltip == gui.tooltip_label->get_text()) {
+ is_tooltip_shown = true;
+ }
+ } else {
- if (tooltip.length() == 0)
- _gui_cancel_tooltip();
- else if (gui.tooltip_label) {
- if (tooltip == gui.tooltip_label->get_text()) {
- is_tooltip_shown = true;
+ Variant t = gui.tooltip_popup->call("get_tooltip_text");
+
+ if (t.get_type() == Variant::STRING) {
+ if (tooltip == String(t)) {
+ is_tooltip_shown = true;
+ }
+ } else {
+ is_tooltip_shown = true; //well, nothing to compare against, likely using custom control, so if it changes there is nothing we can do
+ }
}
- } else if (tooltip == String(gui.tooltip_popup->call("get_tooltip_text"))) {
- is_tooltip_shown = true;
- }
- } else
- _gui_cancel_tooltip();
+ } else
+ _gui_cancel_tooltip();
+ }
+
+ if (can_tooltip && !is_tooltip_shown) {
+
+ gui.tooltip = over;
+ gui.tooltip_pos = over->get_screen_transform().xform(pos); //(parent_xform * get_transform()).affine_inverse().xform(pos);
+ gui.tooltip_timer = gui.tooltip_delay;
+ }
}
- if (can_tooltip && !is_tooltip_shown) {
+ //pos = gui.focus_inv_xform.xform(pos);
+
+ mm->set_position(pos);
- gui.tooltip = over;
- gui.tooltip_pos = mpos; //(parent_xform * get_transform()).affine_inverse().xform(pos);
- gui.tooltip_timer = gui.tooltip_delay;
+ Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
+ {
+ Control *c = over;
+ Vector2 cpos = pos;
+ while (c) {
+ cursor_shape = c->get_cursor_shape(cpos);
+ cpos = c->get_transform().xform(cpos);
+ if (cursor_shape != Control::CURSOR_ARROW)
+ break;
+ if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP)
+ break;
+ if (c->is_set_as_toplevel())
+ break;
+ c = c->get_parent_control();
+ }
}
+
+ ds_cursor_shape = (DisplayServer::CursorShape)cursor_shape;
+
+ if (over && over->can_process()) {
+ _gui_call_input(over, mm);
+ }
+
+ set_input_as_handled();
}
- //pos = gui.focus_inv_xform.xform(pos);
+ if (gui.drag_data.get_type() != Variant::NIL) {
+ //handle dragandrop
- mm->set_position(pos);
+ if (gui.drag_preview) {
+ gui.drag_preview->set_position(mpos);
+ }
- Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
- {
- Control *c = over;
- Vector2 cpos = pos;
- while (c) {
- cursor_shape = c->get_cursor_shape(cpos);
- cpos = c->get_transform().xform(cpos);
- if (cursor_shape != Control::CURSOR_ARROW)
- break;
- if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP)
- break;
- if (c->is_set_as_toplevel())
- break;
- c = c->get_parent_control();
+ gui.drag_mouse_over = over;
+ gui.drag_mouse_over_pos = Vector2();
+
+ //find the window this is above of
+
+ //see if there is an embedder
+ Viewport *embedder = nullptr;
+ Vector2 viewport_pos;
+
+ if (is_embedding_subwindows()) {
+ embedder = this;
+ viewport_pos = mpos;
+ } else {
+ //not an embeder, but may be a subwindow of an embedder
+ Window *w = Object::cast_to<Window>(this);
+ if (w) {
+ if (w->is_embedded()) {
+ embedder = w->_get_embedder();
+
+ Transform2D ai = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse();
+
+ viewport_pos = ai.xform(mpos) + w->get_position(); //to parent coords
+ }
+ }
}
- }
- OS::get_singleton()->set_cursor_shape((OS::CursorShape)cursor_shape);
+ Viewport *viewport_under = nullptr;
- if (over && over->can_process()) {
- _gui_call_input(over, mm);
- }
+ if (embedder) {
+ //use embedder logic
- set_input_as_handled();
+ for (int i = embedder->gui.sub_windows.size() - 1; i >= 0; i--) {
+ Window *sw = embedder->gui.sub_windows[i].window;
+ Rect2 swrect = Rect2i(sw->get_position(), sw->get_size());
+ if (!sw->get_flag(Window::FLAG_BORDERLESS)) {
+ int title_height = sw->get_theme_constant("title_height");
+ swrect.position.y -= title_height;
+ swrect.size.y += title_height;
+ }
+
+ if (swrect.has_point(viewport_pos)) {
+ viewport_under = sw;
+ viewport_pos -= sw->get_position();
+ }
+ }
+
+ if (!viewport_under) {
+ //not in a subwindow, likely in embedder
+ viewport_under = embedder;
+ }
+ } else {
+ //use displayserver logic
+ Vector2i screen_mouse_pos = DisplayServer::get_singleton()->mouse_get_position();
+
+ DisplayServer::WindowID window_id = DisplayServer::get_singleton()->get_window_at_screen_position(screen_mouse_pos);
- if (gui.drag_data.get_type() != Variant::NIL && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ ObjectID object_under = DisplayServer::get_singleton()->window_get_attached_instance_id(window_id);
- bool can_drop = _gui_drop(over, pos, true);
+ if (object_under != ObjectID()) { //fetch window
+ Window *w = Object::cast_to<Window>(ObjectDB::get_instance(object_under));
+ if (w) {
+ viewport_under = w;
+ viewport_pos = screen_mouse_pos - w->get_position();
+ }
+ }
+ }
+ }
+
+ if (viewport_under) {
+ Transform2D ai = (viewport_under->get_final_transform().affine_inverse() * viewport_under->_get_input_pre_xform());
+ viewport_pos = ai.xform(viewport_pos);
+ //find control under at pos
+ gui.drag_mouse_over = viewport_under->_gui_find_control(viewport_pos);
+ if (gui.drag_mouse_over) {
+ 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) {
+
+ bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true);
+
+ if (!can_drop) {
+ ds_cursor_shape = DisplayServer::CURSOR_FORBIDDEN;
+ } else {
+ ds_cursor_shape = DisplayServer::CURSOR_CAN_DROP;
+ }
+ }
+ }
- if (!can_drop) {
- OS::get_singleton()->set_cursor_shape(OS::CURSOR_FORBIDDEN);
} else {
- OS::get_singleton()->set_cursor_shape(OS::CURSOR_CAN_DROP);
+ gui.drag_mouse_over = nullptr;
}
- //change mouse accordingly i guess
}
+
+ DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
}
Ref<InputEventScreenTouch> touch_event = p_event;
@@ -2275,14 +2291,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = _gui_find_control(pos);
if (over) {
- if (!gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
- if (over != top && !top->is_a_parent_of(over)) {
-
- return;
- }
- }
if (over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); //make a copy
@@ -2348,14 +2356,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (over) {
- if (!gui.modal_stack.empty()) {
-
- Control *top = gui.modal_stack.back()->get();
- if (over != top && !top->is_a_parent_of(over)) {
-
- return;
- }
- }
if (over->can_process()) {
Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
@@ -2399,22 +2399,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- if (p_event->is_pressed() && p_event->is_action("ui_cancel") && !gui.modal_stack.empty()) {
-
- _gui_sort_modal_stack();
- Control *top = gui.modal_stack.back()->get();
- if (!top->data.modal_exclusive) {
-
- top->notification(Control::NOTIFICATION_MODAL_CLOSE);
- top->_modal_stack_remove();
- top->hide();
- // Close modal, set input as handled
- set_input_as_handled();
- return;
- }
- }
-
- Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm
+ Control *from = gui.key_focus ? gui.key_focus : nullptr; //hmm
//keyboard focus
//if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) {
@@ -2424,9 +2409,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
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 = NULL;
+ Control *next = nullptr;
- Input *input = Input::get_singleton();
+ InputFilter *input = InputFilter::get_singleton();
if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
@@ -2472,68 +2457,17 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
return gui.roots.push_back(p_control);
}
-List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) {
-
- p_control->connect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
- if (p_control->is_visible_in_tree()) {
- gui.subwindow_order_dirty = true;
- gui.subwindows.push_back(p_control);
- }
-
- return gui.all_known_subwindows.push_back(p_control);
-}
-
-void Viewport::_gui_set_subwindow_order_dirty() {
- gui.subwindow_order_dirty = true;
-}
-
void Viewport::_gui_set_root_order_dirty() {
gui.roots_order_dirty = true;
}
-void Viewport::_gui_remove_modal_control(List<Control *>::Element *MI) {
-
- gui.modal_stack.erase(MI);
-}
-
-void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner) {
-
- //transfer the focus stack to the next
-
- List<Control *>::Element *next = MI->next();
-
- gui.modal_stack.erase(MI);
-
- if (p_prev_focus_owner.is_valid()) {
-
- // for previous window in stack, pass the focus so it feels more
- // natural
-
- if (!next) { //top of stack
-
- Object *pfo = ObjectDB::get_instance(p_prev_focus_owner);
- Control *pfoc = Object::cast_to<Control>(pfo);
- if (!pfoc)
- return;
-
- if (!pfoc->is_inside_tree() || !pfoc->is_visible_in_tree())
- return;
- pfoc->grab_focus();
- } else {
-
- next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner);
- }
- }
-}
-
void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) {
ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value.");
gui.dragging = true;
gui.drag_data = p_data;
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
if (p_control) {
_gui_set_drag_preview(p_base, p_control);
@@ -2545,7 +2479,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
ERR_FAIL_NULL(p_control);
ERR_FAIL_COND(!Object::cast_to<Control>((Object *)p_control));
ERR_FAIL_COND(p_control->is_inside_tree());
- ERR_FAIL_COND(p_control->get_parent() != NULL);
+ ERR_FAIL_COND(p_control->get_parent() != nullptr);
if (gui.drag_preview) {
memdelete(gui.drag_preview);
@@ -2563,21 +2497,6 @@ void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
gui.roots.erase(RI);
}
-void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) {
-
- ERR_FAIL_COND(!SI);
-
- Control *control = SI->get();
-
- control->disconnect("visibility_changed", callable_mp(this, &Viewport::_subwindow_visibility_changed));
-
- List<Control *>::Element *E = gui.subwindows.find(control);
- if (E)
- gui.subwindows.erase(E);
-
- gui.all_known_subwindows.erase(SI);
-}
-
void Viewport::_gui_unfocus_control(Control *p_control) {
if (gui.key_focus == p_control) {
@@ -2591,20 +2510,12 @@ void Viewport::_gui_hid_control(Control *p_control) {
_drop_mouse_focus();
}
- /* ???
- if (data.window==p_control) {
- window->drag_data=Variant();
- if (window->drag_preview) {
- memdelete( window->drag_preview);
- window->drag_preview=NULL;
- }
- }
- */
-
if (gui.key_focus == p_control)
_gui_remove_focus();
if (gui.mouse_over == p_control)
- gui.mouse_over = NULL;
+ gui.mouse_over = nullptr;
+ if (gui.drag_mouse_over == p_control)
+ gui.drag_mouse_over = nullptr;
if (gui.tooltip == p_control)
_gui_cancel_tooltip();
}
@@ -2612,37 +2523,32 @@ void Viewport::_gui_hid_control(Control *p_control) {
void Viewport::_gui_remove_control(Control *p_control) {
if (gui.mouse_focus == p_control) {
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
gui.mouse_focus_mask = 0;
}
if (gui.last_mouse_focus == p_control) {
- gui.last_mouse_focus = NULL;
+ gui.last_mouse_focus = nullptr;
}
if (gui.key_focus == p_control)
- gui.key_focus = NULL;
+ gui.key_focus = nullptr;
if (gui.mouse_over == p_control)
- gui.mouse_over = NULL;
+ gui.mouse_over = nullptr;
+ if (gui.drag_mouse_over == p_control)
+ gui.drag_mouse_over = nullptr;
if (gui.tooltip == p_control)
- gui.tooltip = NULL;
- if (gui.tooltip_popup == p_control) {
- _gui_cancel_tooltip();
- }
+ gui.tooltip = nullptr;
}
void Viewport::_gui_remove_focus() {
if (gui.key_focus) {
Node *f = gui.key_focus;
- gui.key_focus = NULL;
+ gui.key_focus = nullptr;
f->notification(Control::NOTIFICATION_FOCUS_EXIT, true);
}
}
-bool Viewport::_gui_is_modal_on_top(const Control *p_control) {
-
- return (gui.modal_stack.size() && gui.modal_stack.back()->get() == p_control);
-}
-
bool Viewport::_gui_control_has_focus(const Control *p_control) {
return gui.key_focus == p_control;
@@ -2671,7 +2577,8 @@ void Viewport::_drop_mouse_focus() {
Control *c = gui.mouse_focus;
int mask = gui.mouse_focus_mask;
- gui.mouse_focus = NULL;
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
gui.mouse_focus_mask = 0;
for (int i = 0; i < 3; i++) {
@@ -2703,7 +2610,7 @@ void Viewport::_drop_physics_mouseover() {
#ifndef _3D_DISABLED
if (physics_object_over.is_valid()) {
- CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over));
if (co) {
co->_mouse_exit();
}
@@ -2714,22 +2621,6 @@ void Viewport::_drop_physics_mouseover() {
#endif
}
-List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
-
- List<Control *>::Element *node = gui.modal_stack.push_back(p_control);
- if (gui.key_focus)
- p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id());
- else
- p_control->_modal_set_prev_focus_owner(ObjectID());
-
- if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
-
- _drop_mouse_focus();
- }
-
- return node;
-}
-
Control *Viewport::_gui_get_focus_owner() {
return gui.key_focus;
@@ -2748,7 +2639,7 @@ void Viewport::_post_gui_grab_click_focus() {
// Redundant grab requests were made
return;
}
- gui.mouse_click_grabber = NULL;
+ gui.mouse_click_grabber = nullptr;
if (gui.mouse_focus) {
@@ -2798,44 +2689,390 @@ void Viewport::_post_gui_grab_click_focus() {
///////////////////////////////
-void Viewport::input(const Ref<InputEvent> &p_event) {
+void Viewport::input_text(const String &p_text) {
+
+ if (gui.subwindow_focused) {
+ gui.subwindow_focused->input_text(p_text);
+ return;
+ }
+
+ if (gui.key_focus) {
+ gui.key_focus->call("set_text", p_text);
+ }
+}
+Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) {
+
+ if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) {
+ return SUB_WINDOW_RESIZE_DISABLED;
+ }
+
+ Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size());
+
+ int title_height = p_subwindow->get_theme_constant("title_height");
+
+ r.position.y -= title_height;
+ r.size.y += title_height;
+
+ if (r.has_point(p_point)) {
+ return SUB_WINDOW_RESIZE_DISABLED; //it's inside, so no resize
+ }
+
+ int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0);
+ int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0);
+
+ int limit = p_subwindow->get_theme_constant("resize_margin");
+
+ if (ABS(dist_x) > limit) {
+ return SUB_WINDOW_RESIZE_DISABLED;
+ }
+
+ if (ABS(dist_y) > limit) {
+ return SUB_WINDOW_RESIZE_DISABLED;
+ }
+
+ if (dist_x < 0 && dist_y < 0) {
+ return SUB_WINDOW_RESIZE_TOP_LEFT;
+ }
+
+ if (dist_x == 0 && dist_y < 0) {
+ return SUB_WINDOW_RESIZE_TOP;
+ }
+
+ if (dist_x > 0 && dist_y < 0) {
+ return SUB_WINDOW_RESIZE_TOP_RIGHT;
+ }
+
+ if (dist_x < 0 && dist_y == 0) {
+ return SUB_WINDOW_RESIZE_LEFT;
+ }
+
+ if (dist_x > 0 && dist_y == 0) {
+ return SUB_WINDOW_RESIZE_RIGHT;
+ }
+
+ if (dist_x < 0 && dist_y > 0) {
+ return SUB_WINDOW_RESIZE_BOTTOM_LEFT;
+ }
+
+ if (dist_x == 0 && dist_y > 0) {
+ return SUB_WINDOW_RESIZE_BOTTOM;
+ }
+
+ if (dist_x > 0 && dist_y > 0) {
+ return SUB_WINDOW_RESIZE_BOTTOM_RIGHT;
+ }
+
+ return SUB_WINDOW_RESIZE_DISABLED;
+}
+bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
+
+ if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+
+ 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 (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
+ if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) {
+ //close window
+ gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
+ }
+ }
+ gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED;
+ if (gui.subwindow_focused != nullptr) { //may have been erased
+ _sub_window_update(gui.subwindow_focused);
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_MOVE) {
+ Vector2 diff = mm->get_position() - gui.subwindow_drag_from;
+ Rect2i new_rect(gui.subwindow_drag_pos + diff, gui.subwindow_focused->get_size());
+ gui.subwindow_focused->_rect_changed_callback(new_rect);
+ }
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
+ gui.subwindow_drag_close_inside = gui.subwindow_drag_close_rect.has_point(mm->get_position());
+ }
+ if (gui.subwindow_drag == SUB_WINDOW_DRAG_RESIZE) {
+ Vector2i diff = mm->get_position() - gui.subwindow_drag_from;
+ Size2i min_size = gui.subwindow_focused->get_min_size();
+ if (gui.subwindow_focused->is_wrapping_controls()) {
+ Size2i cms = gui.subwindow_focused->get_contents_minimum_size();
+ min_size.x = MAX(cms.x, min_size.x);
+ min_size.y = MAX(cms.y, min_size.y);
+ }
+ min_size.x = MAX(min_size.x, 1);
+ min_size.y = MAX(min_size.y, 1);
+
+ Rect2i r = gui.subwindow_resize_from_rect;
+
+ Size2i limit = r.size - min_size;
+
+ switch (gui.subwindow_resize_mode) {
+ case SUB_WINDOW_RESIZE_TOP_LEFT: {
+
+ diff.x = MIN(diff.x, limit.x);
+ diff.y = MIN(diff.y, limit.y);
+ r.position += diff;
+ r.size -= diff;
+ } break;
+ case SUB_WINDOW_RESIZE_TOP: {
+ diff.x = 0;
+ diff.y = MIN(diff.y, limit.y);
+ r.position += diff;
+ r.size -= diff;
+ } break;
+ case SUB_WINDOW_RESIZE_TOP_RIGHT: {
+ diff.x = MAX(diff.x, -limit.x);
+ diff.y = MIN(diff.y, limit.y);
+ r.position.y += diff.y;
+ r.size.y -= diff.y;
+ r.size.x += diff.x;
+ } break;
+ case SUB_WINDOW_RESIZE_LEFT: {
+ diff.x = MIN(diff.x, limit.x);
+ diff.y = 0;
+ r.position += diff;
+ r.size -= diff;
+
+ } break;
+ case SUB_WINDOW_RESIZE_RIGHT: {
+ diff.x = MAX(diff.x, -limit.x);
+ r.size.x += diff.x;
+ } break;
+ case SUB_WINDOW_RESIZE_BOTTOM_LEFT: {
+ diff.x = MIN(diff.x, limit.x);
+ diff.y = MAX(diff.y, -limit.y);
+ r.position.x += diff.x;
+ r.size.x -= diff.x;
+ r.size.y += diff.y;
+
+ } break;
+ case SUB_WINDOW_RESIZE_BOTTOM: {
+ diff.y = MAX(diff.y, -limit.y);
+ r.size.y += diff.y;
+ } break;
+ case SUB_WINDOW_RESIZE_BOTTOM_RIGHT: {
+ diff.x = MAX(diff.x, -limit.x);
+ diff.y = MAX(diff.y, -limit.y);
+ r.size += diff;
+
+ } break;
+ default: {
+ }
+ }
+
+ gui.subwindow_focused->_rect_changed_callback(r);
+ }
+
+ if (gui.subwindow_focused) { //may have been erased
+ _sub_window_update(gui.subwindow_focused);
+ }
+ }
+
+ return true; //handled
+ }
+ 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) {
+
+ bool click_on_window = false;
+ for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
+ SubWindow &sw = gui.sub_windows.write[i];
+
+ //clicked inside window?
+
+ Rect2i r = Rect2i(sw.window->get_position(), sw.window->get_size());
+
+ if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) {
+ //check top bar
+ int title_height = sw.window->get_theme_constant("title_height");
+ Rect2i title_bar = r;
+ title_bar.position.y -= title_height;
+ title_bar.size.y = title_height;
+
+ if (title_bar.has_point(mb->get_position())) {
+
+ click_on_window = true;
+
+ int close_h_ofs = sw.window->get_theme_constant("close_h_ofs");
+ int close_v_ofs = sw.window->get_theme_constant("close_v_ofs");
+ Ref<Texture2D> close_icon = sw.window->get_theme_icon("close");
+
+ Rect2 close_rect;
+ close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs);
+ close_rect.size = close_icon->get_size();
+
+ if (gui.subwindow_focused != sw.window) {
+ //refocus
+ _sub_window_grab_focus(sw.window);
+ }
+
+ if (close_rect.has_point(mb->get_position())) {
+
+ gui.subwindow_drag = SUB_WINDOW_DRAG_CLOSE;
+ gui.subwindow_drag_close_inside = true; //starts inside
+ gui.subwindow_drag_close_rect = close_rect;
+ } else {
+
+ gui.subwindow_drag = SUB_WINDOW_DRAG_MOVE;
+ }
+
+ gui.subwindow_drag_from = mb->get_position();
+ gui.subwindow_drag_pos = sw.window->get_position();
+
+ _sub_window_update(sw.window);
+ } else {
+ gui.subwindow_resize_mode = _sub_window_get_resize_margin(sw.window, mb->get_position());
+ if (gui.subwindow_resize_mode != SUB_WINDOW_RESIZE_DISABLED) {
+ gui.subwindow_resize_from_rect = r;
+ gui.subwindow_drag_from = mb->get_position();
+ gui.subwindow_drag = SUB_WINDOW_DRAG_RESIZE;
+ click_on_window = true;
+ }
+ }
+ }
+ if (!click_on_window && r.has_point(mb->get_position())) {
+ //clicked, see if it needs to fetch focus
+ if (gui.subwindow_focused != sw.window) {
+ //refocus
+ _sub_window_grab_focus(sw.window);
+ }
+
+ click_on_window = true;
+ }
+
+ if (click_on_window) {
+ break;
+ }
+ }
+
+ if (!click_on_window && gui.subwindow_focused) {
+ //no window found and clicked, remove focus
+ _sub_window_grab_focus(nullptr);
+ }
+ }
+
+ if (gui.subwindow_focused) {
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+
+ SubWindowResize resize = _sub_window_get_resize_margin(gui.subwindow_focused, mm->get_position());
+ if (resize != SUB_WINDOW_RESIZE_DISABLED) {
+
+ DisplayServer::CursorShape shapes[SUB_WINDOW_RESIZE_MAX] = {
+ DisplayServer::CURSOR_ARROW,
+ DisplayServer::CURSOR_FDIAGSIZE,
+ DisplayServer::CURSOR_VSIZE,
+ DisplayServer::CURSOR_BDIAGSIZE,
+ DisplayServer::CURSOR_HSIZE,
+ DisplayServer::CURSOR_HSIZE,
+ DisplayServer::CURSOR_BDIAGSIZE,
+ DisplayServer::CURSOR_VSIZE,
+ DisplayServer::CURSOR_FDIAGSIZE
+ };
+
+ DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]);
+
+ return true; //reserved for showing the resize cursor
+ }
+ }
+ }
+
+ if (gui.subwindow_drag != SUB_WINDOW_DRAG_DISABLED) {
+ return true; // dragging, don't pass the event
+ }
+
+ if (!gui.subwindow_focused) {
+ return false;
+ }
+
+ Transform2D window_ofs;
+ window_ofs.set_origin(-gui.subwindow_focused->get_position());
+
+ Ref<InputEvent> ev = p_event->xformed_by(window_ofs);
+
+ gui.subwindow_focused->_window_input(ev);
+
+ return true;
+}
+
+void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
+ if (disable_input)
+ return;
+
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ return;
+ }
+
local_input_handled = false;
+ Ref<InputEvent> ev;
+ if (!p_local_coords) {
+ ev = _make_input_local(p_event);
+ } else {
+ ev = p_event;
+ }
+
+ if (is_embedding_subwindows() && _sub_windows_forward_input(p_event)) {
+ set_input_as_handled();
+ return;
+ }
+
if (!is_input_handled()) {
- get_tree()->_call_input_pause(input_group, "_input", p_event); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
+ get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
}
if (!is_input_handled()) {
- _gui_input_event(p_event);
+ _gui_input_event(ev);
}
- //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check
+ //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",ev); //special one for GUI, as controls use their own process check
}
-void Viewport::unhandled_input(const Ref<InputEvent> &p_event) {
+void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
- get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", p_event);
+ if (disable_input)
+ return;
+
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ return;
+ }
+
+ Ref<InputEvent> ev;
+ if (!p_local_coords) {
+ ev = _make_input_local(p_event);
+ } else {
+ ev = p_event;
+ }
+
+ get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this);
//call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev);
- if (!get_tree()->input_handled && Object::cast_to<InputEventKey>(*p_event) != NULL) {
- get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", p_event);
+ if (!is_input_handled() && Object::cast_to<InputEventKey>(*ev) != nullptr) {
+ get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this);
//call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev);
}
- if (physics_object_picking && !get_tree()->input_handled) {
+ if (physics_object_picking && !is_input_handled()) {
- if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
- (Object::cast_to<InputEventMouseButton>(*p_event) ||
- Object::cast_to<InputEventMouseMotion>(*p_event) ||
- Object::cast_to<InputEventScreenDrag>(*p_event) ||
- Object::cast_to<InputEventScreenTouch>(*p_event) ||
- Object::cast_to<InputEventKey>(*p_event) //to remember state
+ if (InputFilter::get_singleton()->get_mouse_mode() != InputFilter::MOUSE_MODE_CAPTURED &&
+ (Object::cast_to<InputEventMouseButton>(*ev) ||
+ Object::cast_to<InputEventMouseMotion>(*ev) ||
+ Object::cast_to<InputEventScreenDrag>(*ev) ||
+ Object::cast_to<InputEventScreenTouch>(*ev) ||
+ Object::cast_to<InputEventKey>(*ev) //to remember state
)) {
- physics_picking_events.push_back(p_event);
+ physics_picking_events.push_back(ev);
}
}
}
@@ -2849,7 +3086,7 @@ void Viewport::set_use_own_world(bool p_world) {
_propagate_exit_world(this);
if (!p_world) {
- own_world = Ref<World>();
+ own_world = Ref<World3D>();
if (world.is_valid()) {
world->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
}
@@ -2858,7 +3095,7 @@ void Viewport::set_use_own_world(bool p_world) {
own_world = world->duplicate();
world->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_changed));
} else {
- own_world = Ref<World>(memnew(World));
+ own_world = Ref<World3D>(memnew(World3D));
}
}
@@ -2866,7 +3103,7 @@ void Viewport::set_use_own_world(bool p_world) {
_propagate_enter_world(this);
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
+ RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
}
_update_listener();
@@ -2877,30 +3114,6 @@ bool Viewport::is_using_own_world() const {
return own_world.is_valid();
}
-void Viewport::set_attach_to_screen_rect(const Rect2 &p_rect) {
-
- VS::get_singleton()->viewport_attach_to_screen(viewport, p_rect);
- to_screen_rect = p_rect;
-}
-
-Rect2 Viewport::get_attach_to_screen_rect() const {
-
- return to_screen_rect;
-}
-
-void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) {
-
- if (p_render_direct_to_screen == render_direct_to_screen)
- return;
-
- render_direct_to_screen = p_render_direct_to_screen;
- VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen);
-}
-
-bool Viewport::is_using_render_direct_to_screen() const {
- return render_direct_to_screen;
-}
-
void Viewport::set_physics_object_picking(bool p_enable) {
physics_object_picking = p_enable;
@@ -2925,11 +3138,6 @@ Vector2 Viewport::get_camera_rect_size() const {
return size;
}
-bool Viewport::gui_has_modal_stack() const {
-
- return gui.modal_stack.size();
-}
-
void Viewport::set_disable_input(bool p_disable) {
disable_input = p_disable;
}
@@ -2943,17 +3151,15 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-Control *Viewport::get_modal_stack_top() const {
- return gui.modal_stack.size() ? gui.modal_stack.back()->get() : NULL;
-}
-
String Viewport::get_configuration_warning() 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.");
}*/
+ if (size.x == 0 || size.y == 0) {
+ return TTR("Viewport size must be greater than 0 to render anything.");
+ }
return String();
}
@@ -2967,11 +3173,11 @@ int Viewport::gui_get_canvas_sort_index() {
void Viewport::set_msaa(MSAA p_msaa) {
- ERR_FAIL_INDEX(p_msaa, 7);
+ ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
if (msaa == p_msaa)
return;
msaa = p_msaa;
- VS::get_singleton()->viewport_set_msaa(viewport, VS::ViewportMSAA(p_msaa));
+ RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa));
}
Viewport::MSAA Viewport::get_msaa() const {
@@ -2979,10 +3185,23 @@ Viewport::MSAA Viewport::get_msaa() const {
return msaa;
}
+void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
+
+ ERR_FAIL_INDEX(p_screen_space_aa, SCREEN_SPACE_AA_MAX);
+ if (screen_space_aa == p_screen_space_aa)
+ return;
+ screen_space_aa = p_screen_space_aa;
+ RS::get_singleton()->viewport_set_screen_space_aa(viewport, RS::ViewportScreenSpaceAA(p_screen_space_aa));
+}
+
+Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
+
+ return screen_space_aa;
+}
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
- VS::get_singleton()->viewport_set_debug_draw(viewport, VS::ViewportDebugDraw(p_debug_draw));
+ RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
}
Viewport::DebugDraw Viewport::get_debug_draw() const {
@@ -2992,7 +3211,7 @@ Viewport::DebugDraw Viewport::get_debug_draw() const {
int Viewport::get_render_info(RenderInfo p_info) {
- return VS::get_singleton()->viewport_get_render_info(viewport, VS::ViewportRenderInfo(p_info));
+ return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfo(p_info));
}
void Viewport::set_snap_controls_to_pixels(bool p_enable) {
@@ -3015,7 +3234,17 @@ void Viewport::set_input_as_handled() {
local_input_handled = true;
} else {
ERR_FAIL_COND(!is_inside_tree());
- get_tree()->set_input_as_handled();
+ Viewport *vp = this;
+ while (true) {
+ if (Object::cast_to<Window>(vp)) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+ vp = vp->get_parent()->get_viewport();
+ }
+ vp->set_input_as_handled();
}
}
@@ -3023,8 +3252,17 @@ bool Viewport::is_input_handled() const {
if (handle_input_locally) {
return local_input_handled;
} else {
- ERR_FAIL_COND_V(!is_inside_tree(), false);
- return get_tree()->is_input_handled();
+ const Viewport *vp = this;
+ while (true) {
+ if (Object::cast_to<Window>(vp)) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+ vp = vp->get_parent()->get_viewport();
+ }
+ return vp->is_input_handled();
}
}
@@ -3084,13 +3322,47 @@ void Viewport::_propagate_update_default_repeat(Node *p_node) {
}
}
-void Viewport::_bind_methods() {
+DisplayServer::WindowID Viewport::get_window_id() const {
+ return DisplayServer::MAIN_WINDOW_ID;
+}
- ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr);
- ClassDB::bind_method(D_METHOD("use_arvr"), &Viewport::use_arvr);
+Viewport *Viewport::get_parent_viewport() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
+ if (!get_parent()) {
+ return nullptr; //root viewport
+ }
+
+ return get_parent()->get_viewport();
+}
+
+void Viewport::set_embed_subwindows_hint(bool p_embed) {
+ gui.embed_subwindows_hint = p_embed;
+}
+bool Viewport::get_embed_subwindows_hint() const {
+ return gui.embed_subwindows_hint;
+}
+bool Viewport::is_embedding_subwindows() const {
+ return gui.embed_subwindows_hint;
+}
+
+void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
+ ERR_FAIL_NULL(p_viewport);
+ ERR_FAIL_NULL(p_control);
+
+ if (gui.mouse_focus) {
+ p_viewport->gui.mouse_focus = p_control;
+ p_viewport->gui.mouse_focus_mask = gui.mouse_focus_mask;
+ p_viewport->gui.key_focus = p_control;
+ p_viewport->gui.forced_mouse_focus = true;
+
+ gui.mouse_focus = nullptr;
+ gui.forced_mouse_focus = false;
+ gui.mouse_focus_mask = 0;
+ }
+}
+
+void Viewport::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &Viewport::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &Viewport::get_size);
ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d);
ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d);
ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d);
@@ -3109,25 +3381,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background);
- ClassDB::bind_method(D_METHOD("_vp_input"), &Viewport::_vp_input);
- ClassDB::bind_method(D_METHOD("_vp_input_text", "text"), &Viewport::_vp_input_text);
- ClassDB::bind_method(D_METHOD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input);
-
- ClassDB::bind_method(D_METHOD("set_size_override", "enable", "size", "margin"), &Viewport::set_size_override, DEFVAL(Size2(-1, -1)), DEFVAL(Size2(0, 0)));
- ClassDB::bind_method(D_METHOD("get_size_override"), &Viewport::get_size_override);
- ClassDB::bind_method(D_METHOD("is_size_override_enabled"), &Viewport::is_size_override_enabled);
- ClassDB::bind_method(D_METHOD("set_size_override_stretch", "enabled"), &Viewport::set_size_override_stretch);
- ClassDB::bind_method(D_METHOD("is_size_override_stretch_enabled"), &Viewport::is_size_override_stretch_enabled);
-
- ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &Viewport::set_clear_mode);
- ClassDB::bind_method(D_METHOD("get_clear_mode"), &Viewport::get_clear_mode);
-
- ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &Viewport::set_update_mode);
- ClassDB::bind_method(D_METHOD("get_update_mode"), &Viewport::get_update_mode);
-
ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa);
ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa);
+ ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa);
+ ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa);
+
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);
@@ -3139,8 +3398,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
- ClassDB::bind_method(D_METHOD("input", "local_event"), &Viewport::input);
- ClassDB::bind_method(D_METHOD("unhandled_input", "local_event"), &Viewport::unhandled_input);
+ ClassDB::bind_method(D_METHOD("input_text", "text"), &Viewport::input_text);
+ ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false));
ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds);
@@ -3154,19 +3414,13 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
- ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect);
- ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen);
- ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen);
ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse);
- ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
- ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top);
-
ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
@@ -3192,13 +3446,13 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_filter", "mode"), &Viewport::set_default_canvas_item_texture_filter);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_filter"), &Viewport::get_default_canvas_item_texture_filter);
+ ClassDB::bind_method(D_METHOD("set_embed_subwindows_hint", "enable"), &Viewport::set_embed_subwindows_hint);
+ ClassDB::bind_method(D_METHOD("get_embed_subwindows_hint"), &Viewport::get_embed_subwindows_hint);
+ ClassDB::bind_method(D_METHOD("is_embedding_subwindows"), &Viewport::is_embedding_subwindows);
+
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_repeat", "mode"), &Viewport::set_default_canvas_item_texture_repeat);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_repeat"), &Viewport::get_default_canvas_item_texture_repeat);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr");
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_override_stretch"), "set_size_override_stretch", "is_size_override_stretch_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
@@ -3206,11 +3460,8 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally");
ADD_GROUP("Rendering", "");
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::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen");
+ 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::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
- ADD_GROUP("Render Target", "render_target_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
@@ -3222,6 +3473,7 @@ void Viewport::_bind_methods() {
ADD_GROUP("GUI", "gui_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_embed_subwindows"), "set_embed_subwindows_hint", "get_embed_subwindows_hint");
ADD_GROUP("Shadow Atlas", "shadow_atlas_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 0);
@@ -3234,11 +3486,6 @@ void Viewport::_bind_methods() {
ADD_SIGNAL(MethodInfo("size_changed"));
ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
- BIND_ENUM_CONSTANT(UPDATE_DISABLED);
- BIND_ENUM_CONSTANT(UPDATE_ONCE);
- BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
- BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
-
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_4);
@@ -3268,6 +3515,9 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SCENE_LUMINANCE);
BIND_ENUM_CONSTANT(DEBUG_DRAW_SSAO);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_ROUGHNESS_LIMITER);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_PSSM_SPLITS);
+ BIND_ENUM_CONSTANT(DEBUG_DRAW_DECAL_ATLAS);
BIND_ENUM_CONSTANT(MSAA_DISABLED);
BIND_ENUM_CONSTANT(MSAA_2X);
@@ -3275,10 +3525,6 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(MSAA_8X);
BIND_ENUM_CONSTANT(MSAA_16X);
- BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
- BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
- BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
-
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
@@ -3291,45 +3537,31 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
}
-void Viewport::_subwindow_visibility_changed() {
-
- // unfortunately, we don't know the sender, i.e. which subwindow changed;
- // so we have to check them all.
- gui.subwindow_visibility_dirty = true;
-}
-
Viewport::Viewport() {
world_2d = Ref<World2D>(memnew(World2D));
- viewport = VisualServer::get_singleton()->viewport_create();
- texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport);
-
- render_direct_to_screen = false;
+ viewport = RenderingServer::get_singleton()->viewport_create();
+ texture_rid = RenderingServer::get_singleton()->viewport_get_texture(viewport);
default_texture.instance();
default_texture->vp = const_cast<Viewport *>(this);
viewport_textures.insert(default_texture.ptr());
- default_texture->proxy = VS::get_singleton()->texture_proxy_create(texture_rid);
+ default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid);
- //internal_listener = SpatialSoundServer::get_singleton()->listener_create();
audio_listener = false;
//internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
audio_listener_2d = false;
transparent_bg = false;
- parent = NULL;
- listener = NULL;
- camera = NULL;
+ parent = nullptr;
+ listener = nullptr;
+ camera = nullptr;
override_canvas_transform = false;
- canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport)
- arvr = false;
- size_override = false;
- size_override_stretch = false;
- size_override_size = Size2(1, 1);
+ canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport)
+
gen_mipmaps = false;
//clear=true;
- update_mode = UPDATE_WHEN_VISIBLE;
physics_object_picking = false;
physics_has_last_mousepos = false;
@@ -3359,19 +3591,21 @@ Viewport::Viewport() {
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 = NULL;
- gui.tooltip_label = NULL;
- gui.drag_preview = NULL;
+ gui.tooltip = 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 = NULL;
- gui.last_mouse_focus = NULL;
+ 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;
- clear_mode = CLEAR_MODE_ALWAYS;
snap_controls_to_pixels = true;
physics_last_mouse_state.alt = false;
@@ -3382,6 +3616,8 @@ Viewport::Viewport() {
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;
}
@@ -3390,9 +3626,143 @@ Viewport::~Viewport() {
//erase itself from viewport textures
for (Set<ViewportTexture *>::Element *E = viewport_textures.front(); E; E = E->next()) {
- E->get()->vp = NULL;
+ E->get()->vp = nullptr;
}
- VisualServer::get_singleton()->free(viewport);
- //SpatialSoundServer::get_singleton()->free(internal_listener);
- //SpatialSound2DServer::get_singleton()->free(internal_listener_2d);
+ RenderingServer::get_singleton()->free(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);
+}
+Size2i SubViewport::get_size() const {
+ return _get_size();
+}
+
+void SubViewport::set_size_2d_override(const Size2i &p_size) {
+
+ _set_size(_get_size(), p_size, Rect2i(), _stretch_transform(), true);
+}
+Size2i SubViewport::get_size_2d_override() const {
+
+ return _get_size_2d_override();
+}
+
+void SubViewport::set_size_2d_override_stretch(bool p_enable) {
+
+ if (p_enable == size_2d_override_stretch) {
+ return;
+ }
+
+ size_2d_override_stretch = p_enable;
+ _set_size(_get_size(), _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+}
+bool SubViewport::is_size_2d_override_stretch_enabled() const {
+
+ return size_2d_override_stretch;
+}
+
+void SubViewport::set_update_mode(UpdateMode p_mode) {
+
+ update_mode = p_mode;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::ViewportUpdateMode(p_mode));
+}
+SubViewport::UpdateMode SubViewport::get_update_mode() const {
+
+ return update_mode;
+}
+
+void SubViewport::set_clear_mode(ClearMode p_mode) {
+
+ clear_mode = p_mode;
+ RS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), RS::ViewportClearMode(p_mode));
+}
+SubViewport::ClearMode SubViewport::get_clear_mode() const {
+
+ return clear_mode;
+}
+
+DisplayServer::WindowID SubViewport::get_window_id() const {
+ return DisplayServer::INVALID_WINDOW_ID;
+}
+
+Transform2D SubViewport::_stretch_transform() {
+
+ Transform2D transform = Transform2D();
+ Size2i view_size_2d_override = _get_size_2d_override();
+ if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) {
+ Size2 scale = _get_size() / view_size_2d_override;
+ transform.scale(scale);
+ }
+
+ return transform;
+}
+
+void SubViewport::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
+ }
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+ }
+}
+
+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);
+
+ ClassDB::bind_method(D_METHOD("set_size_2d_override", "size"), &SubViewport::set_size_2d_override);
+ ClassDB::bind_method(D_METHOD("get_size_2d_override"), &SubViewport::get_size_2d_override);
+
+ ClassDB::bind_method(D_METHOD("set_size_2d_override_stretch", "enable"), &SubViewport::set_size_2d_override_stretch);
+ ClassDB::bind_method(D_METHOD("is_size_2d_override_stretch_enabled"), &SubViewport::is_size_2d_override_stretch_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &SubViewport::set_update_mode);
+ ClassDB::bind_method(D_METHOD("get_update_mode"), &SubViewport::get_update_mode);
+
+ 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");
+ ADD_GROUP("Render Target", "render_target_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode");
+
+ BIND_ENUM_CONSTANT(UPDATE_DISABLED);
+ BIND_ENUM_CONSTANT(UPDATE_ONCE);
+ BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
+ BIND_ENUM_CONSTANT(UPDATE_WHEN_PARENT_VISIBLE);
+ BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
+
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
+ BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
+}
+
+SubViewport::SubViewport() {
+ xr = false;
+ size_2d_override_stretch = false;
+ update_mode = UPDATE_WHEN_VISIBLE;
+ clear_mode = CLEAR_MODE_ALWAYS;
+}
+
+SubViewport::~SubViewport() {
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 30c872b6ed..0cbc957307 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -35,11 +35,12 @@
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "scene/resources/world_2d.h"
-#include "servers/visual_server.h"
+#include "servers/display_server.h"
+#include "servers/rendering_server.h"
-class Camera;
+class Camera3D;
class Camera2D;
-class Listener;
+class Listener3D;
class Control;
class CanvasItem;
class CanvasLayer;
@@ -47,7 +48,7 @@ class Panel;
class Label;
class Timer;
class Viewport;
-class CollisionObject;
+class CollisionObject3D;
class ViewportTexture : public Texture2D {
@@ -88,13 +89,6 @@ class Viewport : public Node {
GDCLASS(Viewport, Node);
public:
- enum UpdateMode {
- UPDATE_DISABLED,
- UPDATE_ONCE, //then goes to disabled
- UPDATE_WHEN_VISIBLE, // default
- UPDATE_ALWAYS
- };
-
enum ShadowAtlasQuadrantSubdiv {
SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED,
SHADOW_ATLAS_QUADRANT_SUBDIV_1,
@@ -112,6 +106,13 @@ public:
MSAA_4X,
MSAA_8X,
MSAA_16X,
+ MSAA_MAX
+ };
+
+ enum ScreenSpaceAA {
+ SCREEN_SPACE_AA_DISABLED,
+ SCREEN_SPACE_AA_FXAA,
+ SCREEN_SPACE_AA_MAX
};
enum RenderInfo {
@@ -139,14 +140,9 @@ public:
DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
DEBUG_DRAW_SCENE_LUMINANCE,
DEBUG_DRAW_SSAO,
- DEBUG_DRAW_ROUGHNESS_LIMITER
- };
-
- enum ClearMode {
-
- CLEAR_MODE_ALWAYS,
- CLEAR_MODE_NEVER,
- CLEAR_MODE_ONLY_NEXT_FRAME
+ DEBUG_DRAW_ROUGHNESS_LIMITER,
+ DEBUG_DRAW_PSSM_SPLITS,
+ DEBUG_DRAW_DECAL_ATLAS
};
enum DefaultCanvasItemTextureFilter {
@@ -164,15 +160,17 @@ public:
DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX,
};
+ enum {
+ SUBWINDOW_CANVAS_LAYER = 1024
+ };
+
private:
friend class ViewportTexture;
Viewport *parent;
- Listener *listener;
- Set<Listener *> listeners;
-
- bool arvr;
+ Listener3D *listener;
+ Set<Listener3D *> listeners;
struct CameraOverrideData {
Transform transform;
@@ -192,12 +190,13 @@ private:
}
} camera_override;
- Camera *camera;
- Set<Camera *> cameras;
+ Camera3D *camera;
+ Set<Camera3D *> cameras;
Set<CanvasLayer *> canvas_layers;
RID viewport;
RID current_canvas;
+ RID subwindow_canvas;
bool audio_listener;
RID internal_listener;
@@ -212,30 +211,24 @@ private:
Transform2D global_canvas_transform;
Transform2D stretch_transform;
- Size2 size;
- Rect2 to_screen_rect;
- bool render_direct_to_screen;
+ Size2i size;
+ Size2i size_2d_override;
+ bool size_allocated;
RID contact_2d_debug;
RID contact_3d_debug_multimesh;
RID contact_3d_debug_instance;
- bool size_override;
- bool size_override_stretch;
- Size2 size_override_size;
- Size2 size_override_margin;
-
Rect2 last_vp_rect;
bool transparent_bg;
- ClearMode clear_mode;
bool filter;
bool gen_mipmaps;
bool snap_controls_to_pixels;
bool physics_object_picking;
- List<Ref<InputEvent> > physics_picking_events;
+ List<Ref<InputEvent>> physics_picking_events;
ObjectID physics_object_capture;
ObjectID physics_object_over;
Transform physics_last_object_transform;
@@ -253,7 +246,7 @@ private:
} physics_last_mouse_state;
- void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+ 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;
@@ -261,9 +254,10 @@ private:
Map<ObjectID, uint64_t> physics_2d_mouseover;
Ref<World2D> world_2d;
- Ref<World> world;
- Ref<World> own_world;
+ Ref<World3D> world;
+ Ref<World3D> own_world;
+ Rect2i to_screen_rect;
StringName input_group;
StringName gui_input_group;
StringName unhandled_input_group;
@@ -276,10 +270,8 @@ private:
void _propagate_exit_world(Node *p_node);
void _propagate_viewport_notification(Node *p_node, int p_what);
- void _update_stretch_transform();
void _update_global_transform();
- UpdateMode update_mode;
RID texture_rid;
DebugDraw debug_draw;
@@ -288,12 +280,39 @@ private:
ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
MSAA msaa;
+ ScreenSpaceAA screen_space_aa;
Ref<ViewportTexture> default_texture;
Set<ViewportTexture *> viewport_textures;
+ enum SubWindowDrag {
+ SUB_WINDOW_DRAG_DISABLED,
+ SUB_WINDOW_DRAG_MOVE,
+ SUB_WINDOW_DRAG_CLOSE,
+ SUB_WINDOW_DRAG_RESIZE,
+ };
+
+ enum SubWindowResize {
+ SUB_WINDOW_RESIZE_DISABLED,
+ SUB_WINDOW_RESIZE_TOP_LEFT,
+ SUB_WINDOW_RESIZE_TOP,
+ SUB_WINDOW_RESIZE_TOP_RIGHT,
+ SUB_WINDOW_RESIZE_LEFT,
+ SUB_WINDOW_RESIZE_RIGHT,
+ SUB_WINDOW_RESIZE_BOTTOM_LEFT,
+ SUB_WINDOW_RESIZE_BOTTOM,
+ SUB_WINDOW_RESIZE_BOTTOM_RIGHT,
+ SUB_WINDOW_RESIZE_MAX
+ };
+
+ struct SubWindow {
+ Window *window;
+ 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;
@@ -301,8 +320,10 @@ private:
int mouse_focus_mask;
Control *key_focus;
Control *mouse_over;
+ Control *drag_mouse_over;
+ Vector2 drag_mouse_over_pos;
Control *tooltip;
- Control *tooltip_popup;
+ Window *tooltip_popup;
Label *tooltip_label;
Point2 tooltip_pos;
Point2 last_mouse_pos;
@@ -312,16 +333,24 @@ private:
Control *drag_preview;
float tooltip_timer;
float tooltip_delay;
- List<Control *> modal_stack;
Transform2D focus_inv_xform;
- bool subwindow_order_dirty;
- bool subwindow_visibility_dirty;
- List<Control *> subwindows; // visible subwindows
- List<Control *> all_known_subwindows;
bool roots_order_dirty;
List<Control *> roots;
int canvas_sort_index; //for sorting items with canvas as root
bool dragging;
+ bool embed_subwindows_hint;
+ bool embedding_subwindows;
+
+ Window *subwindow_focused;
+ SubWindowDrag subwindow_drag;
+ Vector2 subwindow_drag_from;
+ Vector2 subwindow_drag_pos;
+ Rect2i subwindow_drag_close_rect;
+ bool subwindow_drag_close_inside;
+ SubWindowResize subwindow_resize_mode;
+ Rect2i subwindow_resize_from_rect;
+
+ Vector<SubWindow> sub_windows;
GUI();
} gui;
@@ -337,10 +366,7 @@ private:
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
void _gui_call_notification(Control *p_control, int p_what);
- void _gui_prepare_subwindows();
- void _gui_sort_subwindows();
void _gui_sort_roots();
- void _gui_sort_modal_stack();
Control *_gui_find_control(const Point2 &p_global);
Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform);
@@ -350,25 +376,15 @@ private:
_FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
- void _vp_input(const Ref<InputEvent> &p_ev);
- void _vp_input_text(const String &p_text);
- void _vp_unhandled_input(const Ref<InputEvent> &p_ev);
Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev);
friend class Control;
List<Control *>::Element *_gui_add_root_control(Control *p_control);
- List<Control *>::Element *_gui_add_subwindow_control(Control *p_control);
- void _gui_set_subwindow_order_dirty();
- void _gui_set_root_order_dirty();
-
- void _gui_remove_modal_control(List<Control *>::Element *MI);
- void _gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner);
void _gui_remove_root_control(List<Control *>::Element *RI);
- void _gui_remove_subwindow_control(List<Control *>::Element *SI);
- String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL);
+ String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = nullptr);
void _gui_cancel_tooltip();
void _gui_show_tooltip();
@@ -378,9 +394,6 @@ 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);
- bool _gui_is_modal_on_top(const Control *p_control);
- List<Control *>::Element *_gui_show_modal(Control *p_control);
-
void _gui_remove_focus();
void _gui_unfocus_control(Control *p_control);
bool _gui_control_has_focus(const Control *p_control);
@@ -391,23 +404,21 @@ private:
Control *_gui_get_focus_owner();
- Vector2 _get_window_offset() const;
-
bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
- friend class Listener;
+ friend class Listener3D;
void _listener_transform_changed_notify();
- void _listener_set(Listener *p_listener);
- bool _listener_add(Listener *p_listener); //true if first
- void _listener_remove(Listener *p_listener);
- void _listener_make_next_current(Listener *p_exclude);
+ void _listener_set(Listener3D *p_listener);
+ bool _listener_add(Listener3D *p_listener); //true if first
+ void _listener_remove(Listener3D *p_listener);
+ void _listener_make_next_current(Listener3D *p_exclude);
- friend class Camera;
+ friend class Camera3D;
void _camera_transform_changed_notify();
- void _camera_set(Camera *p_camera);
- bool _camera_add(Camera *p_camera); //true if first
- void _camera_remove(Camera *p_camera);
- void _camera_make_next_current(Camera *p_exclude);
+ void _camera_set(Camera3D *p_camera);
+ bool _camera_add(Camera3D *p_camera); //true if first
+ void _camera_remove(Camera3D *p_camera);
+ void _camera_make_next_current(Camera3D *p_exclude);
friend class CanvasLayer;
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
@@ -418,16 +429,34 @@ private:
void _update_canvas_items(Node *p_node);
+ void _gui_set_root_order_dirty();
+
void _own_world_changed();
+ friend class Window;
+
+ void _sub_window_update_order();
+ void _sub_window_register(Window *p_window);
+ void _sub_window_update(Window *p_window);
+ void _sub_window_grab_focus(Window *p_window);
+ void _sub_window_remove(Window *p_window);
+ bool _sub_windows_forward_input(const Ref<InputEvent> &p_event);
+ SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point);
+
protected:
+ void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated);
+
+ Size2i _get_size() const;
+ Size2i _get_size_2d_override() const;
+ bool _is_size_allocated() const;
+
void _notification(int p_what);
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const;
public:
- Listener *get_listener() const;
- Camera *get_camera() const;
+ Listener3D *get_listener() const;
+ Camera3D *get_camera() const;
void enable_camera_override(bool p_enable);
bool is_camera_override_enabled() const;
@@ -438,26 +467,21 @@ public:
void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far);
- void set_use_arvr(bool p_use_arvr);
- bool use_arvr();
-
void set_as_audio_listener(bool p_enable);
bool is_audio_listener() const;
void set_as_audio_listener_2d(bool p_enable);
bool is_audio_listener_2d() const;
- void set_size(const Size2 &p_size);
void update_canvas_items();
- Size2 get_size() const;
Rect2 get_visible_rect() const;
RID get_viewport_rid() const;
- void set_world(const Ref<World> &p_world);
+ void set_world(const Ref<World3D> &p_world);
void set_world_2d(const Ref<World2D> &p_world_2d);
- Ref<World> get_world() const;
- Ref<World> find_world() const;
+ Ref<World3D> get_world() const;
+ Ref<World3D> find_world() const;
Ref<World2D> get_world_2d() const;
Ref<World2D> find_world_2d() const;
@@ -479,18 +503,6 @@ public:
void set_transparent_background(bool p_enable);
bool has_transparent_background() const;
- void set_size_override(bool p_enable, const Size2 &p_size = Size2(-1, -1), const Vector2 &p_margin = Vector2());
- Size2 get_size_override() const;
-
- bool is_size_override_enabled() const;
- void set_size_override_stretch(bool p_enable);
- bool is_size_override_stretch_enabled() const;
-
- void set_clear_mode(ClearMode p_mode);
- ClearMode get_clear_mode() const;
-
- void set_update_mode(UpdateMode p_mode);
- UpdateMode get_update_mode() const;
Ref<ViewportTexture> get_texture() const;
void set_shadow_atlas_size(int p_size);
@@ -502,34 +514,29 @@ public:
void set_msaa(MSAA p_msaa);
MSAA get_msaa() const;
+ void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa);
+ ScreenSpaceAA get_screen_space_aa() const;
+
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
void set_use_own_world(bool p_world);
bool is_using_own_world() const;
- void input(const Ref<InputEvent> &p_event);
- void unhandled_input(const Ref<InputEvent> &p_event);
+ void input_text(const String &p_text);
+ void input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
+ void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
void set_disable_input(bool p_disable);
bool is_input_disabled() const;
- void set_attach_to_screen_rect(const Rect2 &p_rect);
- Rect2 get_attach_to_screen_rect() const;
-
- void set_use_render_direct_to_screen(bool p_render_direct_to_screen);
- bool is_using_render_direct_to_screen() const;
-
Vector2 get_mouse_position() const;
void warp_mouse(const Vector2 &p_pos);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
- bool gui_has_modal_stack() const;
-
Variant gui_get_drag_data() const;
- Control *get_modal_stack_top() const;
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
@@ -544,8 +551,6 @@ public:
void set_snap_controls_to_pixels(bool p_enable);
bool is_snap_controls_to_pixels_enabled() const;
- void _subwindow_visibility_changed();
-
void set_input_as_handled();
bool is_input_handled() const;
@@ -560,15 +565,80 @@ public:
void set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat);
DefaultCanvasItemTextureRepeat get_default_canvas_item_texture_repeat() const;
+ virtual DisplayServer::WindowID get_window_id() const = 0;
+
+ void set_embed_subwindows_hint(bool p_embed);
+ bool get_embed_subwindows_hint() const;
+ bool is_embedding_subwindows() const;
+
+ Viewport *get_parent_viewport() const;
+
+ void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control);
+
Viewport();
~Viewport();
};
-VARIANT_ENUM_CAST(Viewport::UpdateMode);
+class SubViewport : public Viewport {
+
+ GDCLASS(SubViewport, Viewport);
+
+public:
+ enum ClearMode {
+
+ CLEAR_MODE_ALWAYS,
+ CLEAR_MODE_NEVER,
+ CLEAR_MODE_ONLY_NEXT_FRAME
+ };
+
+ enum UpdateMode {
+ UPDATE_DISABLED,
+ UPDATE_ONCE, //then goes to disabled
+ UPDATE_WHEN_VISIBLE, // default
+ UPDATE_WHEN_PARENT_VISIBLE,
+ UPDATE_ALWAYS
+ };
+
+private:
+ UpdateMode update_mode;
+ ClearMode clear_mode;
+ bool xr;
+ bool size_2d_override_stretch;
+
+protected:
+ static void _bind_methods();
+ virtual DisplayServer::WindowID get_window_id() const;
+ Transform2D _stretch_transform();
+ void _notification(int p_what);
+
+public:
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+
+ 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;
+
+ void set_update_mode(UpdateMode p_mode);
+ UpdateMode get_update_mode() const;
+
+ void set_clear_mode(ClearMode p_mode);
+ ClearMode get_clear_mode() const;
+
+ SubViewport();
+ ~SubViewport();
+};
+VARIANT_ENUM_CAST(SubViewport::UpdateMode);
VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
VARIANT_ENUM_CAST(Viewport::MSAA);
+VARIANT_ENUM_CAST(Viewport::ScreenSpaceAA);
VARIANT_ENUM_CAST(Viewport::DebugDraw);
-VARIANT_ENUM_CAST(Viewport::ClearMode);
+VARIANT_ENUM_CAST(SubViewport::ClearMode);
VARIANT_ENUM_CAST(Viewport::RenderInfo);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter);
VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureRepeat);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
new file mode 100644
index 0000000000..19954299de
--- /dev/null
+++ b/scene/main/window.cpp
@@ -0,0 +1,1406 @@
+/*************************************************************************/
+/* window.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "window.h"
+
+#include "core/debugger/engine_debugger.h"
+#include "core/os/keyboard.h"
+#include "scene/gui/control.h"
+#include "scene/resources/dynamic_font.h"
+#include "scene/scene_string_names.h"
+
+void Window::set_title(const String &p_title) {
+ title = p_title;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_title(p_title, window_id);
+ }
+}
+String Window::get_title() const {
+ return title;
+}
+
+void Window::set_current_screen(int p_screen) {
+ current_screen = p_screen;
+ if (window_id == DisplayServer::INVALID_WINDOW_ID)
+ return;
+ DisplayServer::get_singleton()->window_set_current_screen(p_screen, window_id);
+}
+int Window::get_current_screen() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id);
+ }
+ return current_screen;
+}
+
+void Window::set_position(const Point2i &p_position) {
+
+ position = p_position;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_position(p_position, window_id);
+ }
+}
+Point2i Window::get_position() const {
+ return position;
+}
+
+void Window::set_size(const Size2i &p_size) {
+ size = p_size;
+ _update_window_size();
+}
+Size2i Window::get_size() const {
+
+ return size;
+}
+
+Size2i Window::get_real_size() const {
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_get_real_size(window_id);
+ }
+ return size;
+}
+
+void Window::set_max_size(const Size2i &p_max_size) {
+ max_size = p_max_size;
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
+ }
+ _update_window_size();
+}
+
+Size2i Window::get_max_size() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ max_size = DisplayServer::get_singleton()->window_get_max_size(window_id);
+ }
+ return max_size;
+}
+
+void Window::set_min_size(const Size2i &p_min_size) {
+ min_size = p_min_size;
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
+ }
+ _update_window_size();
+}
+
+Size2i Window::get_min_size() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ min_size = DisplayServer::get_singleton()->window_get_min_size(window_id);
+ }
+ return min_size;
+}
+
+void Window::set_mode(Mode p_mode) {
+
+ mode = p_mode;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_mode(DisplayServer::WindowMode(p_mode), window_id);
+ }
+}
+
+Window::Mode Window::get_mode() const {
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
+ }
+ return mode;
+}
+
+void Window::set_flag(Flags p_flag, bool p_enabled) {
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ flags[p_flag] = p_enabled;
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
+ }
+}
+
+bool Window::get_flag(Flags p_flag) const {
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
+ }
+ return flags[p_flag];
+}
+
+bool Window::is_maximize_allowed() const {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_is_maximize_allowed(window_id);
+ }
+ return true;
+}
+
+void Window::request_attention() {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_request_attention(window_id);
+ }
+}
+void Window::move_to_foreground() {
+
+ if (embedder) {
+ embedder->_sub_window_grab_focus(this);
+
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_move_to_foreground(window_id);
+ }
+}
+
+bool Window::can_draw() const {
+ if (!is_inside_tree()) {
+ return false;
+ }
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ return DisplayServer::get_singleton()->window_can_draw(window_id);
+ }
+
+ return visible;
+}
+
+void Window::set_ime_active(bool p_active) {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id);
+ }
+}
+void Window::set_ime_position(const Point2i &p_pos) {
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id);
+ }
+}
+
+bool Window::is_embedded() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), false);
+
+ return _get_embedder() != nullptr;
+}
+
+void Window::_make_window() {
+ ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
+
+ uint32_t f = 0;
+ for (int i = 0; i < FLAG_MAX; i++) {
+ if (flags[i]) {
+ f |= (1 << i);
+ }
+ }
+
+ window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size));
+ ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+ 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_attach_instance_id(get_instance_id(), window_id);
+
+ _update_window_size();
+
+ if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id);
+ }
+
+ for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) {
+ if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, transient_parent->window_id);
+ }
+ }
+
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+}
+void Window::_update_from_window() {
+
+ ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+ mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(i), window_id);
+ }
+}
+
+void Window::_clear_window() {
+ ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
+
+ if (transient_parent && transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID);
+ }
+
+ for (Set<Window *>::Element *E = transient_children.front(); E; E = E->next()) {
+ if (E->get()->window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(E->get()->window_id, DisplayServer::INVALID_WINDOW_ID);
+ }
+ }
+
+ _update_from_window();
+
+ DisplayServer::get_singleton()->delete_sub_window(window_id);
+ window_id = DisplayServer::INVALID_WINDOW_ID;
+
+ _update_viewport_size();
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+}
+
+void Window::_rect_changed_callback(const Rect2i &p_callback) {
+
+ //we must always accept this as the truth
+ if (size == p_callback.size && position == p_callback.position) {
+ return;
+ }
+ position = p_callback.position;
+
+ if (size != p_callback.size) {
+ size = p_callback.size;
+ _update_viewport_size();
+ }
+}
+
+void Window::_propagate_window_notification(Node *p_node, int p_notification) {
+ p_node->notification(p_notification);
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ Window *window = Object::cast_to<Window>(child);
+ if (window) {
+ break;
+ }
+ _propagate_window_notification(child, p_notification);
+ }
+}
+
+void Window::_event_callback(DisplayServer::WindowEvent p_event) {
+
+ switch (p_event) {
+ case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: {
+ _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER);
+ emit_signal("mouse_entered");
+ } break;
+ case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: {
+ _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT);
+ emit_signal("mouse_exited");
+ } break;
+ case DisplayServer::WINDOW_EVENT_FOCUS_IN: {
+ focused = true;
+ _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_IN);
+ emit_signal("focus_entered");
+
+ } break;
+ case DisplayServer::WINDOW_EVENT_FOCUS_OUT: {
+ focused = false;
+ _propagate_window_notification(this, NOTIFICATION_WM_FOCUS_OUT);
+ emit_signal("focus_exited");
+ } break;
+ case DisplayServer::WINDOW_EVENT_CLOSE_REQUEST: {
+ if (exclusive_child != nullptr) {
+ break; //has an exclusive child, can't get events until child is closed
+ }
+ _propagate_window_notification(this, NOTIFICATION_WM_CLOSE_REQUEST);
+ emit_signal("close_requested");
+ } break;
+ case DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST: {
+ _propagate_window_notification(this, NOTIFICATION_WM_GO_BACK_REQUEST);
+ emit_signal("go_back_requested");
+ } break;
+ case DisplayServer::WINDOW_EVENT_DPI_CHANGE: {
+ _propagate_window_notification(this, NOTIFICATION_WM_DPI_CHANGE);
+ emit_signal("dpi_changed");
+ } break;
+ }
+}
+
+void Window::show() {
+ set_visible(true);
+}
+void Window::hide() {
+ set_visible(false);
+}
+
+void Window::set_visible(bool p_visible) {
+
+ if (visible == p_visible) {
+ return;
+ }
+
+ visible = p_visible;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (updating_child_controls) {
+ _update_child_controls();
+ }
+
+ ERR_FAIL_COND_MSG(get_parent() == nullptr, "Can't change visibility of main window.");
+
+ Viewport *embedder_vp = _get_embedder();
+
+ if (!embedder_vp) {
+ if (!p_visible && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ _clear_window();
+ }
+ if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) {
+ _make_window();
+ _update_window_callbacks();
+ }
+ } else {
+ if (visible) {
+ embedder = embedder_vp;
+ embedder->_sub_window_register(this);
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+ } else {
+ embedder->_sub_window_remove(this);
+ embedder = nullptr;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ }
+ _update_window_size();
+ }
+
+ if (!visible) {
+ focused = false;
+ }
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), visible);
+}
+
+void Window::_clear_transient() {
+ if (transient_parent) {
+ if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, DisplayServer::INVALID_WINDOW_ID);
+ }
+ transient_parent->transient_children.erase(this);
+ if (transient_parent->exclusive_child == this) {
+ transient_parent->exclusive_child = nullptr;
+ }
+ transient_parent = nullptr;
+ }
+}
+
+void Window::_make_transient() {
+ if (!get_parent()) {
+ //main window, can't be transient
+ return;
+ }
+ //find transient parent
+ Viewport *vp = get_parent()->get_viewport();
+ Window *window = nullptr;
+ while (vp) {
+ window = Object::cast_to<Window>(vp);
+ if (window) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+
+ vp = vp->get_parent()->get_viewport();
+ }
+
+ if (window) {
+ transient_parent = window;
+ window->transient_children.insert(this);
+ if (is_inside_tree() && is_visible() && exclusive) {
+ if (transient_parent->exclusive_child == nullptr) {
+ transient_parent->exclusive_child = this;
+ } else if (transient_parent->exclusive_child != this) {
+ ERR_PRINT("Making child transient exclusive, but parent has another exclusive child");
+ }
+ }
+ }
+
+ //see if we can make transient
+ if (transient_parent->window_id != DisplayServer::INVALID_WINDOW_ID && window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_transient(window_id, transient_parent->window_id);
+ }
+}
+
+void Window::set_transient(bool p_transient) {
+ if (transient == p_transient) {
+ return;
+ }
+
+ transient = p_transient;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ if (transient) {
+ _make_transient();
+ } else {
+ _clear_transient();
+ }
+}
+bool Window::is_transient() const {
+ return transient;
+}
+
+void Window::set_exclusive(bool p_exclusive) {
+
+ if (exclusive == p_exclusive) {
+ return;
+ }
+
+ exclusive = p_exclusive;
+
+ if (transient_parent) {
+ if (p_exclusive && is_inside_tree() && is_visible()) {
+ ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
+ transient_parent->exclusive_child = this;
+ } else {
+ if (transient_parent->exclusive_child == this) {
+ transient_parent->exclusive_child = nullptr;
+ }
+ }
+ }
+}
+
+bool Window::is_exclusive() const {
+ return exclusive;
+}
+
+bool Window::is_visible() const {
+ return visible;
+}
+
+void Window::_update_window_size() {
+
+ Size2i size_limit;
+ if (wrap_controls) {
+ size_limit = get_contents_minimum_size();
+ }
+
+ size_limit.x = MAX(size_limit.x, min_size.x);
+ size_limit.y = MAX(size_limit.y, min_size.y);
+
+ size.x = MAX(size_limit.x, size.x);
+ size.y = MAX(size_limit.y, size.y);
+
+ if (max_size.x > 0 && max_size.x > min_size.x && max_size.x > size.x) {
+ size.x = max_size.x;
+ }
+
+ if (max_size.y > 0 && max_size.y > min_size.y && max_size.y > size.y) {
+ size.y = max_size.y;
+ }
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_set_size(size, window_id);
+ }
+
+ //update the viewport
+ _update_viewport_size();
+}
+void Window::_update_viewport_size() {
+ //update the viewport part
+
+ Size2i final_size;
+ Size2i final_size_override;
+ Rect2i attach_to_screen_rect(Point2i(), size);
+ Transform2D stretch_transform;
+ float font_oversampling = 1.0;
+
+ if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
+
+ stretch_transform = Transform2D();
+ final_size = size;
+
+ } else {
+
+ //actual screen video mode
+ Size2 video_mode = size;
+ Size2 desired_res = content_scale_size;
+
+ Size2 viewport_size;
+ Size2 screen_size;
+
+ float viewport_aspect = desired_res.aspect();
+ float video_mode_aspect = video_mode.aspect();
+
+ if (content_scale_aspect == CONTENT_SCALE_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
+ //same aspect or ignore aspect
+ viewport_size = desired_res;
+ screen_size = video_mode;
+ } else if (viewport_aspect < video_mode_aspect) {
+ // screen ratio is smaller vertically
+
+ if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_HEIGHT || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) {
+
+ //will stretch horizontally
+ viewport_size.x = desired_res.y * video_mode_aspect;
+ viewport_size.y = desired_res.y;
+ screen_size = video_mode;
+
+ } else {
+ //will need black bars
+ viewport_size = desired_res;
+ screen_size.x = video_mode.y * viewport_aspect;
+ screen_size.y = video_mode.y;
+ }
+ } else {
+ //screen ratio is smaller horizontally
+ if (content_scale_aspect == CONTENT_SCALE_ASPECT_KEEP_WIDTH || content_scale_aspect == CONTENT_SCALE_ASPECT_EXPAND) {
+
+ //will stretch horizontally
+ viewport_size.x = desired_res.x;
+ viewport_size.y = desired_res.x / video_mode_aspect;
+ screen_size = video_mode;
+
+ } else {
+ //will need black bars
+ viewport_size = desired_res;
+ screen_size.x = video_mode.x;
+ screen_size.y = video_mode.x / viewport_aspect;
+ }
+ }
+
+ screen_size = screen_size.floor();
+ viewport_size = viewport_size.floor();
+
+ Size2 margin;
+ Size2 offset;
+ //black bars and margin
+ if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.x < video_mode.x) {
+ margin.x = Math::round((video_mode.x - screen_size.x) / 2.0);
+ //RenderingServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0);
+ offset.x = Math::round(margin.x * viewport_size.y / screen_size.y);
+ } else if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.y < video_mode.y) {
+ margin.y = Math::round((video_mode.y - screen_size.y) / 2.0);
+ //RenderingServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y);
+ offset.y = Math::round(margin.y * viewport_size.x / screen_size.x);
+ } else {
+ //RenderingServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0);
+ }
+
+ switch (content_scale_mode) {
+ case CONTENT_SCALE_MODE_DISABLED: {
+ // Already handled above
+ //_update_font_oversampling(1.0);
+ } break;
+ case CONTENT_SCALE_MODE_OBJECTS: {
+
+ final_size = screen_size;
+ final_size_override = viewport_size;
+ attach_to_screen_rect = Rect2(margin, screen_size);
+ font_oversampling = screen_size.x / viewport_size.x;
+ } break;
+ case CONTENT_SCALE_MODE_PIXELS: {
+
+ final_size = viewport_size;
+ attach_to_screen_rect = Rect2(margin, screen_size);
+
+ } break;
+ }
+
+ Size2 scale = size / (Vector2(final_size) + margin * 2);
+ stretch_transform.scale(scale);
+ stretch_transform.elements[2] = margin * scale;
+ }
+
+ bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
+
+ _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate);
+
+ if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id);
+ } else {
+ RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), Rect2i(), DisplayServer::INVALID_WINDOW_ID);
+ }
+
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+
+ if (!use_font_oversampling) {
+ font_oversampling = 1.0;
+ }
+ if (DynamicFontAtSize::font_oversampling != font_oversampling) {
+
+ DynamicFontAtSize::font_oversampling = font_oversampling;
+ DynamicFont::update_oversampling();
+ }
+ }
+
+ notification(NOTIFICATION_WM_SIZE_CHANGED);
+
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ }
+}
+
+void Window::_update_window_callbacks() {
+ DisplayServer::get_singleton()->window_set_rect_changed_callback(callable_mp(this, &Window::_rect_changed_callback), window_id);
+ DisplayServer::get_singleton()->window_set_window_event_callback(callable_mp(this, &Window::_event_callback), window_id);
+ DisplayServer::get_singleton()->window_set_input_event_callback(callable_mp(this, &Window::_window_input), window_id);
+ DisplayServer::get_singleton()->window_set_input_text_callback(callable_mp(this, &Window::_window_input_text), window_id);
+ DisplayServer::get_singleton()->window_set_drop_files_callback(callable_mp(this, &Window::_window_drop_files), window_id);
+}
+
+Viewport *Window::_get_embedder() const {
+
+ Viewport *vp = get_parent_viewport();
+
+ while (vp) {
+
+ if (vp->is_embedding_subwindows()) {
+ return vp;
+ }
+
+ if (vp->get_parent()) {
+ vp = vp->get_parent()->get_viewport();
+ } else {
+ vp = nullptr;
+ }
+ }
+ return nullptr;
+}
+
+void Window::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ bool embedded = false;
+ {
+
+ embedder = _get_embedder();
+
+ if (embedder) {
+ embedded = true;
+
+ if (!visible) {
+ embedder = nullptr; //not yet since not visible
+ }
+ }
+ }
+
+ if (embedded) {
+ //create as embedded
+ if (embedder) {
+ embedder->_sub_window_register(this);
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+ _update_window_size();
+ }
+
+ } else {
+ if (get_parent() == nullptr) {
+ //it's the root window!
+ visible = true; //always visible
+ window_id = DisplayServer::MAIN_WINDOW_ID;
+ DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
+ _update_from_window();
+ //since this window already exists (created on start), we must update pos and size from it
+ {
+ position = DisplayServer::get_singleton()->window_get_position(window_id);
+ size = DisplayServer::get_singleton()->window_get_size(window_id);
+ }
+ _update_viewport_size(); //then feed back to the viewport
+ _update_window_callbacks();
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+ } else {
+ //create
+ if (visible) {
+ _make_window();
+ _update_window_callbacks();
+ }
+ }
+ }
+
+ if (transient) {
+ _make_transient();
+ }
+ if (visible) {
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
+ }
+ }
+
+ if (p_what == NOTIFICATION_READY) {
+
+ if (wrap_controls) {
+ _update_child_controls();
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ if (transient) {
+ _clear_transient();
+ }
+
+ if (!is_embedded() && window_id != DisplayServer::INVALID_WINDOW_ID) {
+
+ if (window_id == DisplayServer::MAIN_WINDOW_ID) {
+
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ _update_window_callbacks();
+ } else {
+ _clear_window();
+ }
+ } else {
+
+ if (embedder) {
+ embedder->_sub_window_remove(this);
+ embedder = nullptr;
+ RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
+ }
+ _update_viewport_size(); //called by clear and make, which does not happen here
+ }
+
+ RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
+ }
+}
+
+void Window::set_content_scale_size(const Size2i &p_size) {
+ ERR_FAIL_COND(p_size.x < 0);
+ ERR_FAIL_COND(p_size.y < 0);
+ content_scale_size = p_size;
+ _update_viewport_size();
+}
+
+Size2i Window::get_content_scale_size() const {
+ return content_scale_size;
+}
+
+void Window::set_content_scale_mode(ContentScaleMode p_mode) {
+ content_scale_mode = p_mode;
+ _update_viewport_size();
+}
+Window::ContentScaleMode Window::get_content_scale_mode() const {
+ return content_scale_mode;
+}
+
+void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
+ content_scale_aspect = p_aspect;
+ _update_viewport_size();
+}
+Window::ContentScaleAspect Window::get_content_scale_aspect() const {
+ return content_scale_aspect;
+}
+
+void Window::set_use_font_oversampling(bool p_oversampling) {
+ if (is_inside_tree() && window_id != DisplayServer::MAIN_WINDOW_ID) {
+ ERR_FAIL_MSG("Only the root window can set and use font oversampling.");
+ }
+ use_font_oversampling = p_oversampling;
+ _update_viewport_size();
+}
+bool Window::is_using_font_oversampling() const {
+ return use_font_oversampling;
+}
+
+DisplayServer::WindowID Window::get_window_id() const {
+ return window_id;
+}
+
+void Window::set_wrap_controls(bool p_enable) {
+ wrap_controls = p_enable;
+ if (wrap_controls) {
+ child_controls_changed();
+ }
+}
+
+bool Window::is_wrapping_controls() const {
+ return wrap_controls;
+}
+
+Size2 Window::_get_contents_minimum_size() const {
+ Size2 max;
+
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *c = Object::cast_to<Control>(get_child(i));
+ if (c) {
+ Point2i pos = c->get_position();
+ Size2i min = c->get_combined_minimum_size();
+
+ max.x = MAX(pos.x + min.x, max.x);
+ max.y = MAX(pos.y + min.y, max.y);
+ }
+ }
+
+ return max;
+}
+void Window::_update_child_controls() {
+
+ if (!updating_child_controls) {
+ return;
+ }
+
+ _update_window_size();
+
+ updating_child_controls = false;
+}
+void Window::child_controls_changed() {
+
+ if (!is_inside_tree() || !visible || updating_child_controls) {
+ return;
+ }
+
+ updating_child_controls = true;
+ call_deferred("_update_child_controls");
+}
+
+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;
+ if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_F8) {
+ EngineDebugger::get_singleton()->send_message("request_quit", Array());
+ }
+ }
+
+ if (exclusive_child != nullptr) {
+ exclusive_child->grab_focus();
+
+ return; //has an exclusive child, can't get events until child is closed
+ }
+
+ emit_signal(SceneStringNames::get_singleton()->window_input, p_ev);
+ input(p_ev);
+ if (!is_input_handled()) {
+ unhandled_input(p_ev);
+ }
+}
+void Window::_window_input_text(const String &p_text) {
+ input_text(p_text);
+}
+void Window::_window_drop_files(const Vector<String> &p_files) {
+ emit_signal("files_dropped", p_files, current_screen);
+}
+
+Viewport *Window::get_parent_viewport() const {
+
+ if (get_parent()) {
+ return get_parent()->get_viewport();
+ } else {
+ return nullptr;
+ }
+}
+
+Window *Window::get_parent_visible_window() const {
+
+ Viewport *vp = get_parent_viewport();
+ Window *window = nullptr;
+ while (vp) {
+ window = Object::cast_to<Window>(vp);
+ if (window && window->visible) {
+ break;
+ }
+ if (!vp->get_parent()) {
+ break;
+ }
+
+ vp = vp->get_parent()->get_viewport();
+ }
+ return window;
+}
+
+void Window::popup_on_parent(const Rect2i &p_parent_rect) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ if (!is_embedded()) {
+ Window *window = get_parent_visible_window();
+
+ if (!window) {
+ popup(p_parent_rect);
+ } else {
+ popup(Rect2i(window->get_position() + p_parent_rect.position, p_parent_rect.size));
+ }
+ } else {
+ popup(p_parent_rect);
+ }
+}
+
+void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ Rect2 parent_rect;
+
+ if (is_embedded()) {
+ parent_rect = get_parent_viewport()->get_visible_rect();
+ } else {
+ DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
+ int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
+ parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen);
+ parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
+ }
+
+ Vector2i size_ratio = parent_rect.size * p_fallback_ratio;
+
+ Rect2i popup_rect;
+ popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y));
+ popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+
+ popup(popup_rect);
+}
+
+void Window::popup_centered(const Size2i &p_minsize) {
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ Rect2 parent_rect;
+
+ if (is_embedded()) {
+ parent_rect = get_parent_viewport()->get_visible_rect();
+ } else {
+ DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
+ int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
+ parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen);
+ parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
+ }
+
+ Rect2i popup_rect;
+ if (p_minsize == Size2i()) {
+ popup_rect.size = _get_contents_minimum_size();
+ } else {
+ popup_rect.size = p_minsize;
+ }
+ popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+
+ popup(popup_rect);
+}
+
+void Window::popup_centered_ratio(float p_ratio) {
+
+ ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
+
+ Rect2i parent_rect;
+
+ if (is_embedded()) {
+ parent_rect = get_parent_viewport()->get_visible_rect();
+ } else {
+ DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
+ int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
+ parent_rect.position = DisplayServer::get_singleton()->screen_get_position(parent_screen);
+ parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
+ }
+
+ Rect2i popup_rect;
+ popup_rect.size = parent_rect.size * p_ratio;
+ popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
+
+ popup(popup_rect);
+}
+
+void Window::popup(const Rect2i &p_screen_rect) {
+
+ emit_signal("about_to_popup");
+
+ if (p_screen_rect != Rect2i()) {
+ set_position(p_screen_rect.position);
+ set_size(p_screen_rect.size);
+ }
+
+ Rect2i adjust = _popup_adjust_rect();
+ if (adjust != Rect2i()) {
+ set_position(adjust.position);
+ set_size(adjust.size);
+ }
+
+ set_transient(true);
+ set_visible(true);
+ _post_popup();
+ notification(NOTIFICATION_POST_POPUP);
+}
+
+Size2 Window::get_contents_minimum_size() const {
+ return _get_contents_minimum_size();
+}
+
+void Window::grab_focus() {
+ if (embedder) {
+ embedder->_sub_window_grab_focus(this);
+ } else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ DisplayServer::get_singleton()->window_move_to_foreground(window_id);
+ }
+}
+
+bool Window::has_focus() const {
+ return focused;
+}
+
+Rect2i Window::get_usable_parent_rect() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
+ Rect2i parent;
+ if (is_embedded()) {
+ parent = _get_embedder()->get_visible_rect();
+ } else {
+
+ const Window *w = is_visible() ? this : get_parent_visible_window();
+ //find a parent that can contain us
+ ERR_FAIL_COND_V(!w, Rect2());
+
+ parent = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id()));
+ }
+ return parent;
+}
+
+void Window::add_child_notify(Node *p_child) {
+
+ Control *child_c = Object::cast_to<Control>(p_child);
+
+ if (child_c && child_c->data.theme.is_null() && (theme_owner || theme_owner_window)) {
+ Control::_propagate_theme_changed(child_c, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ }
+
+ Window *child_w = Object::cast_to<Window>(p_child);
+
+ if (child_w && child_w->theme.is_null() && (theme_owner || theme_owner_window)) {
+ Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ }
+
+ if (is_inside_tree() && wrap_controls) {
+ child_controls_changed();
+ }
+}
+
+void Window::remove_child_notify(Node *p_child) {
+
+ Control *child_c = Object::cast_to<Control>(p_child);
+
+ if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
+ Control::_propagate_theme_changed(child_c, nullptr, nullptr);
+ }
+
+ Window *child_w = Object::cast_to<Window>(p_child);
+
+ if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
+ Control::_propagate_theme_changed(child_w, nullptr, nullptr);
+ }
+
+ if (is_inside_tree() && wrap_controls) {
+ child_controls_changed();
+ }
+}
+
+void Window::set_theme(const Ref<Theme> &p_theme) {
+
+ if (theme == p_theme)
+ return;
+
+ theme = p_theme;
+
+ if (!p_theme.is_null()) {
+
+ theme_owner = nullptr;
+ theme_owner_window = this;
+ Control::_propagate_theme_changed(this, nullptr, this);
+ } else {
+
+ Control *parent_c = cast_to<Control>(get_parent());
+ if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
+ } else {
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
+ } else {
+ Control::_propagate_theme_changed(this, nullptr, nullptr);
+ }
+ }
+ }
+}
+Ref<Theme> Window::get_theme() const {
+ return theme;
+}
+
+Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_icons(theme_owner, theme_owner_window, p_name, type);
+}
+Ref<Shader> Window::get_theme_shader(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_shaders(theme_owner, theme_owner_window, p_name, type);
+}
+Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_styleboxs(theme_owner, theme_owner_window, p_name, type);
+}
+Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_fonts(theme_owner, theme_owner_window, p_name, type);
+}
+Color Window::get_theme_color(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_colors(theme_owner, theme_owner_window, p_name, type);
+}
+int Window::get_theme_constant(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::get_constants(theme_owner, theme_owner_window, p_name, type);
+}
+
+bool Window::has_theme_icon(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_icons(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_shader(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_shaders(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_styleboxs(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_font(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_fonts(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_color(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_colors(theme_owner, theme_owner_window, p_name, type);
+}
+bool Window::has_theme_constant(const StringName &p_name, const StringName &p_type) const {
+ StringName type = p_type ? p_type : get_class_name();
+ return Control::has_constants(theme_owner, theme_owner_window, p_name, type);
+}
+
+Rect2i Window::get_parent_rect() const {
+ ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
+ if (is_embedded()) {
+ //viewport
+ Node *n = get_parent();
+ ERR_FAIL_COND_V(!n, Rect2i());
+ Viewport *p = n->get_viewport();
+ ERR_FAIL_COND_V(!p, Rect2i());
+
+ return p->get_visible_rect();
+ } else {
+ int x = get_position().x;
+ int closest_dist = 0x7FFFFFFF;
+ Rect2i closest_rect;
+ for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
+ Rect2i s(DisplayServer::get_singleton()->screen_get_position(i), DisplayServer::get_singleton()->screen_get_size(i));
+ int d;
+ if (x >= s.position.x && x < s.size.x) {
+ //contained
+ closest_rect = s;
+ break;
+ } else if (x < s.position.x) {
+ d = s.position.x - x;
+ } else {
+ d = x - (s.position.x + s.size.x);
+ }
+
+ if (d < closest_dist) {
+ closest_dist = d;
+ closest_rect = s;
+ }
+ }
+ return closest_rect;
+ }
+}
+
+void Window::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
+ ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
+
+ ClassDB::bind_method(D_METHOD("set_current_screen", "index"), &Window::set_current_screen);
+ ClassDB::bind_method(D_METHOD("get_current_screen"), &Window::get_current_screen);
+
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &Window::set_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &Window::get_position);
+
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size);
+
+ ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size);
+
+ ClassDB::bind_method(D_METHOD("set_max_size", "max_size"), &Window::set_max_size);
+ ClassDB::bind_method(D_METHOD("get_max_size"), &Window::get_max_size);
+
+ ClassDB::bind_method(D_METHOD("set_min_size", "min_size"), &Window::set_min_size);
+ ClassDB::bind_method(D_METHOD("get_min_size"), &Window::get_min_size);
+
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &Window::set_mode);
+ ClassDB::bind_method(D_METHOD("get_mode"), &Window::get_mode);
+
+ ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &Window::set_flag);
+ ClassDB::bind_method(D_METHOD("get_flag", "flag"), &Window::get_flag);
+
+ ClassDB::bind_method(D_METHOD("is_maximize_allowed"), &Window::is_maximize_allowed);
+
+ ClassDB::bind_method(D_METHOD("request_attention"), &Window::request_attention);
+
+ ClassDB::bind_method(D_METHOD("move_to_foreground"), &Window::move_to_foreground);
+
+ ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Window::set_visible);
+ ClassDB::bind_method(D_METHOD("is_visible"), &Window::is_visible);
+
+ ClassDB::bind_method(D_METHOD("hide"), &Window::hide);
+ ClassDB::bind_method(D_METHOD("show"), &Window::show);
+
+ ClassDB::bind_method(D_METHOD("set_transient", "transient"), &Window::set_transient);
+ ClassDB::bind_method(D_METHOD("is_transient"), &Window::is_transient);
+
+ ClassDB::bind_method(D_METHOD("set_exclusive", "exclusive"), &Window::set_exclusive);
+ ClassDB::bind_method(D_METHOD("is_exclusive"), &Window::is_exclusive);
+
+ ClassDB::bind_method(D_METHOD("can_draw"), &Window::can_draw);
+ 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("is_embedded"), &Window::is_embedded);
+
+ ClassDB::bind_method(D_METHOD("set_content_scale_size", "size"), &Window::set_content_scale_size);
+ ClassDB::bind_method(D_METHOD("get_content_scale_size"), &Window::get_content_scale_size);
+
+ ClassDB::bind_method(D_METHOD("set_content_scale_mode", "mode"), &Window::set_content_scale_mode);
+ ClassDB::bind_method(D_METHOD("get_content_scale_mode"), &Window::get_content_scale_mode);
+
+ ClassDB::bind_method(D_METHOD("set_content_scale_aspect", "aspect"), &Window::set_content_scale_aspect);
+ ClassDB::bind_method(D_METHOD("get_content_scale_aspect"), &Window::get_content_scale_aspect);
+
+ ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling);
+ ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling);
+
+ ClassDB::bind_method(D_METHOD("set_wrap_controls", "enable"), &Window::set_wrap_controls);
+ ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls);
+ ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed);
+
+ ClassDB::bind_method(D_METHOD("_update_child_controls"), &Window::_update_child_controls);
+
+ ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Window::set_theme);
+ ClassDB::bind_method(D_METHOD("get_theme"), &Window::get_theme);
+
+ ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "type"), &Window::get_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "type"), &Window::get_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_font", "name", "type"), &Window::get_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_color", "name", "type"), &Window::get_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "type"), &Window::get_theme_constant, DEFVAL(""));
+
+ ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "type"), &Window::has_theme_icon, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "type"), &Window::has_theme_stylebox, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_font", "name", "type"), &Window::has_theme_font, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_color", "name", "type"), &Window::has_theme_color, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "type"), &Window::has_theme_constant, DEFVAL(""));
+
+ ClassDB::bind_method(D_METHOD("popup", "rect"), &Window::popup, DEFVAL(Rect2i()));
+ ClassDB::bind_method(D_METHOD("popup_on_parent", "parent_rect"), &Window::popup_on_parent);
+ ClassDB::bind_method(D_METHOD("popup_centered_ratio", "ratio"), &Window::popup_centered_ratio, DEFVAL(0.8));
+ ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i()));
+ ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75));
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,FullScreen"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_screen"), "set_current_screen", "get_current_screen");
+ ADD_GROUP("Flags", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transient"), "set_transient", "is_transient");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclusive"), "set_exclusive", "is_exclusive");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unresizable"), "set_flag", "get_flag", FLAG_RESIZE_DISABLED);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "borderless"), "set_flag", "get_flag", FLAG_BORDERLESS);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
+ ADD_GROUP("Limits", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "max_size"), "set_max_size", "get_max_size");
+ ADD_GROUP("Content Scale", "content_scale_");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Object,Pixels"), "set_content_scale_mode", "get_content_scale_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,KeepWidth,KeepHeight,Expand"), "set_content_scale_aspect", "get_content_scale_aspect");
+ ADD_GROUP("Theme", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
+
+ ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
+ ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
+ ADD_SIGNAL(MethodInfo("mouse_entered"));
+ ADD_SIGNAL(MethodInfo("mouse_exited"));
+ ADD_SIGNAL(MethodInfo("focus_entered"));
+ ADD_SIGNAL(MethodInfo("focus_exited"));
+ ADD_SIGNAL(MethodInfo("close_requested"));
+ ADD_SIGNAL(MethodInfo("go_back_requested"));
+ ADD_SIGNAL(MethodInfo("visibility_changed"));
+ ADD_SIGNAL(MethodInfo("about_to_popup"));
+
+ BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+
+ BIND_ENUM_CONSTANT(MODE_WINDOWED);
+ BIND_ENUM_CONSTANT(MODE_MINIMIZED);
+ BIND_ENUM_CONSTANT(MODE_MAXIMIZED);
+ BIND_ENUM_CONSTANT(MODE_FULLSCREEN);
+
+ BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED);
+ BIND_ENUM_CONSTANT(FLAG_BORDERLESS);
+ BIND_ENUM_CONSTANT(FLAG_ALWAYS_ON_TOP);
+ BIND_ENUM_CONSTANT(FLAG_TRANSPARENT);
+ BIND_ENUM_CONSTANT(FLAG_NO_FOCUS);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_OBJECTS);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_PIXELS);
+
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_IGNORE);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_WIDTH);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_HEIGHT);
+ BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_EXPAND);
+}
+
+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);
+}
+Window::~Window() {
+}
diff --git a/scene/main/window.h b/scene/main/window.h
new file mode 100644
index 0000000000..adaa5ca3be
--- /dev/null
+++ b/scene/main/window.h
@@ -0,0 +1,265 @@
+/*************************************************************************/
+/* window.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 WINDOW_H
+#define WINDOW_H
+
+#include "scene/main/viewport.h"
+#include "scene/resources/theme.h"
+#include "servers/display_server.h"
+
+class Control;
+class Window : public Viewport {
+ GDCLASS(Window, Viewport)
+public:
+ enum Mode {
+ MODE_WINDOWED = DisplayServer::WINDOW_MODE_WINDOWED,
+ MODE_MINIMIZED = DisplayServer::WINDOW_MODE_MINIMIZED,
+ MODE_MAXIMIZED = DisplayServer::WINDOW_MODE_MAXIMIZED,
+ MODE_FULLSCREEN = DisplayServer::WINDOW_MODE_FULLSCREEN,
+ };
+
+ enum Flags {
+ FLAG_RESIZE_DISABLED = DisplayServer::WINDOW_FLAG_RESIZE_DISABLED,
+ FLAG_BORDERLESS = DisplayServer::WINDOW_FLAG_BORDERLESS,
+ FLAG_ALWAYS_ON_TOP = DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP,
+ FLAG_TRANSPARENT = DisplayServer::WINDOW_FLAG_TRANSPARENT,
+ FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS,
+ FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
+ };
+
+ enum ContentScaleMode {
+ CONTENT_SCALE_MODE_DISABLED,
+ CONTENT_SCALE_MODE_OBJECTS,
+ CONTENT_SCALE_MODE_PIXELS,
+ };
+
+ enum ContentScaleAspect {
+ CONTENT_SCALE_ASPECT_IGNORE,
+ CONTENT_SCALE_ASPECT_KEEP,
+ CONTENT_SCALE_ASPECT_KEEP_WIDTH,
+ CONTENT_SCALE_ASPECT_KEEP_HEIGHT,
+ CONTENT_SCALE_ASPECT_EXPAND,
+ };
+
+ enum {
+ DEFAULT_WINDOW_SIZE = 100,
+ };
+
+private:
+ DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
+
+ String title;
+ mutable int current_screen = 0;
+ mutable Vector2i position;
+ mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
+ mutable Size2i min_size;
+ mutable Size2i max_size;
+ mutable Mode mode = MODE_WINDOWED;
+ mutable bool flags[FLAG_MAX];
+ bool visible = true;
+ bool focused = false;
+
+ bool use_font_oversampling = false;
+ bool transient = false;
+ bool exclusive = false;
+ bool wrap_controls = false;
+ bool updating_child_controls = false;
+
+ void _update_child_controls();
+
+ Size2i content_scale_size;
+ ContentScaleMode content_scale_mode;
+ ContentScaleAspect content_scale_aspect;
+
+ void _make_window();
+ void _clear_window();
+ void _update_from_window();
+
+ void _update_viewport_size();
+ void _update_window_size();
+
+ void _propagate_window_notification(Node *p_node, int p_notification);
+
+ void _update_window_callbacks();
+
+ void _clear_transient();
+ void _make_transient();
+ Window *transient_parent = nullptr;
+ Window *exclusive_child = nullptr;
+ Set<Window *> transient_children;
+
+ friend class Control;
+ Ref<Theme> theme;
+ Control *theme_owner = nullptr;
+ Window *theme_owner_window = nullptr;
+
+ Viewport *embedder = nullptr;
+
+ friend class Viewport; //friend back, can call the methods below
+
+ void _window_input(const Ref<InputEvent> &p_ev);
+ void _window_input_text(const String &p_text);
+ void _window_drop_files(const Vector<String> &p_files);
+ void _rect_changed_callback(const Rect2i &p_callback);
+ void _event_callback(DisplayServer::WindowEvent p_event);
+
+protected:
+ Viewport *_get_embedder() const;
+
+ virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
+
+ virtual void _post_popup() {}
+ virtual Size2 _get_contents_minimum_size() const;
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ virtual void add_child_notify(Node *p_child);
+ virtual void remove_child_notify(Node *p_child);
+
+public:
+ enum {
+
+ NOTIFICATION_VISIBILITY_CHANGED = 30,
+ NOTIFICATION_POST_POPUP = 31,
+ NOTIFICATION_THEME_CHANGED = 32,
+ };
+
+ void set_title(const String &p_title);
+ String get_title() const;
+
+ void set_current_screen(int p_screen);
+ int get_current_screen() const;
+
+ void set_position(const Point2i &p_position);
+ Point2i get_position() const;
+
+ void set_size(const Size2i &p_size);
+ Size2i get_size() const;
+
+ Size2i get_real_size() const;
+
+ void set_max_size(const Size2i &p_max_size);
+ Size2i get_max_size() const;
+
+ void set_min_size(const Size2i &p_min_size);
+ Size2i get_min_size() const;
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ void set_flag(Flags p_flag, bool p_enabled);
+ bool get_flag(Flags p_flag) const;
+
+ bool is_maximize_allowed() const;
+
+ void request_attention();
+ void move_to_foreground();
+
+ void set_visible(bool p_visible);
+ bool is_visible() const;
+
+ void show();
+ void hide();
+
+ void set_transient(bool p_transient);
+ bool is_transient() const;
+
+ void set_exclusive(bool p_exclusive);
+ bool is_exclusive() const;
+
+ bool can_draw() const;
+
+ void set_ime_active(bool p_active);
+ void set_ime_position(const Point2i &p_pos);
+
+ bool is_embedded() const;
+
+ void set_content_scale_size(const Size2i &p_size);
+ Size2i get_content_scale_size() const;
+
+ void set_content_scale_mode(ContentScaleMode p_mode);
+ ContentScaleMode get_content_scale_mode() const;
+
+ void set_content_scale_aspect(ContentScaleAspect p_aspect);
+ ContentScaleAspect get_content_scale_aspect() const;
+
+ void set_use_font_oversampling(bool p_oversampling);
+ bool is_using_font_oversampling() const;
+
+ void set_wrap_controls(bool p_enable);
+ bool is_wrapping_controls() const;
+ void child_controls_changed();
+
+ Window *get_parent_visible_window() const;
+ Viewport *get_parent_viewport() const;
+ void popup(const Rect2i &p_rect = Rect2i());
+ void popup_on_parent(const Rect2i &p_parent_rect);
+ void popup_centered_ratio(float p_ratio = 0.8);
+ void popup_centered(const Size2i &p_minsize = Size2i());
+ void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
+
+ void set_theme(const Ref<Theme> &p_theme);
+ Ref<Theme> get_theme() const;
+
+ Size2 get_contents_minimum_size() const;
+
+ void grab_focus();
+ bool has_focus() const;
+
+ Rect2i get_usable_parent_rect() const;
+
+ Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Shader> get_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
+ Color get_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
+ int get_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+
+ bool has_theme_icon(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_shader(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_stylebox(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_font(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_color(const StringName &p_name, const StringName &p_type = StringName()) const;
+ bool has_theme_constant(const StringName &p_name, const StringName &p_type = StringName()) const;
+
+ Rect2i get_parent_rect() const;
+ virtual DisplayServer::WindowID get_window_id() const;
+
+ Window();
+ ~Window();
+};
+
+VARIANT_ENUM_CAST(Window::Mode);
+VARIANT_ENUM_CAST(Window::Flags);
+VARIANT_ENUM_CAST(Window::ContentScaleMode);
+VARIANT_ENUM_CAST(Window::ContentScaleAspect);
+
+#endif // WINDOW_H
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index dd00565929..ff49dbdc8f 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -33,16 +33,16 @@
#include "core/class_db.h"
#include "core/os/os.h"
#include "core/project_settings.h"
-#include "scene/2d/animated_sprite.h"
+#include "scene/2d/animated_sprite_2d.h"
#include "scene/2d/area_2d.h"
#include "scene/2d/audio_stream_player_2d.h"
#include "scene/2d/back_buffer_copy.h"
#include "scene/2d/camera_2d.h"
-#include "scene/2d/canvas_item.h"
#include "scene/2d/canvas_modulate.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/collision_shape_2d.h"
#include "scene/2d/cpu_particles_2d.h"
+#include "scene/2d/gpu_particles_2d.h"
#include "scene/2d/joints_2d.h"
#include "scene/2d/light_2d.h"
#include "scene/2d/light_occluder_2d.h"
@@ -54,7 +54,6 @@
#include "scene/2d/navigation_obstacle_2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
-#include "scene/2d/particles_2d.h"
#include "scene/2d/path_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/2d/polygon_2d.h"
@@ -62,7 +61,7 @@
#include "scene/2d/ray_cast_2d.h"
#include "scene/2d/remote_transform_2d.h"
#include "scene/2d/skeleton_2d.h"
-#include "scene/2d/sprite.h"
+#include "scene/2d/sprite_2d.h"
#include "scene/2d/tile_map.h"
#include "scene/2d/touch_screen_button.h"
#include "scene/2d/visibility_notifier_2d.h"
@@ -111,6 +110,7 @@
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/split_container.h"
+#include "scene/gui/subviewport_container.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/tabs.h"
#include "scene/gui/text_edit.h"
@@ -120,7 +120,7 @@
#include "scene/gui/tool_button.h"
#include "scene/gui/tree.h"
#include "scene/gui/video_player.h"
-#include "scene/gui/viewport_container.h"
+#include "scene/main/canvas_item.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/http_request.h"
#include "scene/main/instance_placeholder.h"
@@ -128,21 +128,22 @@
#include "scene/main/scene_tree.h"
#include "scene/main/timer.h"
#include "scene/main/viewport.h"
+#include "scene/main/window.h"
#include "scene/resources/audio_stream_sample.h"
#include "scene/resources/bit_map.h"
-#include "scene/resources/box_shape.h"
-#include "scene/resources/capsule_shape.h"
+#include "scene/resources/box_shape_3d.h"
#include "scene/resources/capsule_shape_2d.h"
+#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/circle_shape_2d.h"
-#include "scene/resources/concave_polygon_shape.h"
#include "scene/resources/concave_polygon_shape_2d.h"
-#include "scene/resources/convex_polygon_shape.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
-#include "scene/resources/cylinder_shape.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
+#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/dynamic_font.h"
#include "scene/resources/gradient.h"
-#include "scene/resources/height_map_shape.h"
+#include "scene/resources/height_map_shape_3d.h"
#include "scene/resources/line_shape_2d.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
@@ -153,12 +154,13 @@
#include "scene/resources/physics_material.h"
#include "scene/resources/polygon_path_finder.h"
#include "scene/resources/primitive_meshes.h"
-#include "scene/resources/ray_shape.h"
+#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/segment_shape_2d.h"
#include "scene/resources/sky.h"
-#include "scene/resources/sphere_shape.h"
+#include "scene/resources/sky_material.h"
+#include "scene/resources/sphere_shape_3d.h"
#include "scene/resources/surface_tool.h"
#include "scene/resources/text_file.h"
#include "scene/resources/texture.h"
@@ -166,50 +168,52 @@
#include "scene/resources/video_stream.h"
#include "scene/resources/visual_shader.h"
#include "scene/resources/visual_shader_nodes.h"
-#include "scene/resources/world.h"
#include "scene/resources/world_2d.h"
-#include "scene/resources/world_margin_shape.h"
+#include "scene/resources/world_3d.h"
+#include "scene/resources/world_margin_shape_3d.h"
#include "scene/scene_string_names.h"
+// Needed by animation code, so keep when 3D disabled.
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
+
#ifndef _3D_DISABLED
-#include "scene/3d/area.h"
-#include "scene/3d/arvr_nodes.h"
+#include "scene/3d/area_3d.h"
#include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/baked_lightmap.h"
-#include "scene/3d/bone_attachment.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/collision_polygon.h"
-#include "scene/3d/collision_shape.h"
-#include "scene/3d/cpu_particles.h"
+#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/collision_polygon_3d.h"
+#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/cpu_particles_3d.h"
+#include "scene/3d/decal.h"
#include "scene/3d/gi_probe.h"
-#include "scene/3d/immediate_geometry.h"
-#include "scene/3d/interpolated_camera.h"
-#include "scene/3d/light.h"
-#include "scene/3d/listener.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/multimesh_instance.h"
-#include "scene/3d/navigation.h"
-#include "scene/3d/navigation_agent.h"
-#include "scene/3d/navigation_obstacle.h"
-#include "scene/3d/navigation_region.h"
-#include "scene/3d/particles.h"
-#include "scene/3d/path.h"
-#include "scene/3d/physics_body.h"
-#include "scene/3d/physics_joint.h"
+#include "scene/3d/gpu_particles_3d.h"
+#include "scene/3d/immediate_geometry_3d.h"
+#include "scene/3d/light_3d.h"
+#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/path_3d.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/3d/physics_joint_3d.h"
#include "scene/3d/position_3d.h"
-#include "scene/3d/proximity_group.h"
-#include "scene/3d/ray_cast.h"
+#include "scene/3d/proximity_group_3d.h"
+#include "scene/3d/ray_cast_3d.h"
#include "scene/3d/reflection_probe.h"
-#include "scene/3d/remote_transform.h"
-#include "scene/3d/skeleton.h"
-#include "scene/3d/soft_body.h"
-#include "scene/3d/spatial.h"
-#include "scene/3d/spring_arm.h"
+#include "scene/3d/remote_transform_3d.h"
+#include "scene/3d/skeleton_ik_3d.h"
+#include "scene/3d/soft_body_3d.h"
+#include "scene/3d/spring_arm_3d.h"
#include "scene/3d/sprite_3d.h"
-#include "scene/3d/vehicle_body.h"
-#include "scene/3d/visibility_notifier.h"
+#include "scene/3d/vehicle_body_3d.h"
+#include "scene/3d/visibility_notifier_3d.h"
#include "scene/3d/world_environment.h"
-#include "scene/animation/skeleton_ik.h"
+#include "scene/3d/xr_nodes.h"
#include "scene/resources/environment.h"
#include "scene/resources/mesh_library.h"
#endif
@@ -266,15 +270,18 @@ void register_scene_types() {
ClassDB::register_class<Node>();
ClassDB::register_virtual_class<InstancePlaceholder>();
- ClassDB::register_class<Viewport>();
+ ClassDB::register_virtual_class<Viewport>();
+ ClassDB::register_class<SubViewport>();
ClassDB::register_class<ViewportTexture>();
ClassDB::register_class<HTTPRequest>();
ClassDB::register_class<Timer>();
ClassDB::register_class<CanvasLayer>();
ClassDB::register_class<CanvasModulate>();
ClassDB::register_class<ResourcePreloader>();
+ ClassDB::register_class<Window>();
/* REGISTER GUI */
+
ClassDB::register_class<ButtonGroup>();
ClassDB::register_virtual_class<BaseButton>();
@@ -331,7 +338,6 @@ void register_scene_types() {
ClassDB::register_class<VideoPlayer>();
#ifndef ADVANCED_GUI_DISABLED
-
ClassDB::register_class<FileDialog>();
ClassDB::register_class<PopupMenu>();
@@ -347,12 +353,12 @@ void register_scene_types() {
ClassDB::register_class<RichTextLabel>();
ClassDB::register_class<RichTextEffect>();
ClassDB::register_class<CharFXTransform>();
- ClassDB::register_class<PopupDialog>();
- ClassDB::register_class<WindowDialog>();
+
ClassDB::register_class<AcceptDialog>();
ClassDB::register_class<ConfirmationDialog>();
+
ClassDB::register_class<MarginContainer>();
- ClassDB::register_class<ViewportContainer>();
+ ClassDB::register_class<SubViewportContainer>();
ClassDB::register_virtual_class<SplitContainer>();
ClassDB::register_class<HSplitContainer>();
ClassDB::register_class<VSplitContainer>();
@@ -361,16 +367,18 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
+ AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(DisplayServer::get_singleton()->get_swap_ok_cancel())));
#endif
/* REGISTER 3D */
+ // Needed even with _3D_DISABLED as used in animation code.
+ ClassDB::register_class<Node3D>();
+ ClassDB::register_virtual_class<Node3DGizmo>();
ClassDB::register_class<Skin>();
ClassDB::register_virtual_class<SkinReference>();
+ ClassDB::register_class<Skeleton3D>();
- ClassDB::register_class<Spatial>();
- ClassDB::register_virtual_class<SpatialGizmo>();
- ClassDB::register_class<Skeleton>();
ClassDB::register_class<AnimationPlayer>();
ClassDB::register_class<Tween>();
@@ -398,32 +406,32 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
#ifndef _3D_DISABLED
- ClassDB::register_virtual_class<VisualInstance>();
- ClassDB::register_virtual_class<GeometryInstance>();
- ClassDB::register_class<Camera>();
- ClassDB::register_class<ClippedCamera>();
- ClassDB::register_class<Listener>();
- ClassDB::register_class<ARVRCamera>();
- ClassDB::register_class<ARVRController>();
- ClassDB::register_class<ARVRAnchor>();
- ClassDB::register_class<ARVROrigin>();
- ClassDB::register_class<InterpolatedCamera>();
- ClassDB::register_class<MeshInstance>();
- ClassDB::register_class<ImmediateGeometry>();
+ ClassDB::register_virtual_class<VisualInstance3D>();
+ ClassDB::register_virtual_class<GeometryInstance3D>();
+ ClassDB::register_class<Camera3D>();
+ ClassDB::register_class<ClippedCamera3D>();
+ ClassDB::register_class<Listener3D>();
+ ClassDB::register_class<XRCamera3D>();
+ ClassDB::register_class<XRController3D>();
+ ClassDB::register_class<XRAnchor3D>();
+ ClassDB::register_class<XROrigin3D>();
+ ClassDB::register_class<MeshInstance3D>();
+ ClassDB::register_class<ImmediateGeometry3D>();
ClassDB::register_virtual_class<SpriteBase3D>();
ClassDB::register_class<Sprite3D>();
ClassDB::register_class<AnimatedSprite3D>();
- ClassDB::register_virtual_class<Light>();
- ClassDB::register_class<DirectionalLight>();
- ClassDB::register_class<OmniLight>();
- ClassDB::register_class<SpotLight>();
+ ClassDB::register_virtual_class<Light3D>();
+ ClassDB::register_class<DirectionalLight3D>();
+ ClassDB::register_class<OmniLight3D>();
+ ClassDB::register_class<SpotLight3D>();
ClassDB::register_class<ReflectionProbe>();
+ ClassDB::register_class<Decal>();
ClassDB::register_class<GIProbe>();
ClassDB::register_class<GIProbeData>();
//ClassDB::register_class<BakedLightmap>();
//ClassDB::register_class<BakedLightmapData>();
- ClassDB::register_class<Particles>();
- ClassDB::register_class<CPUParticles>();
+ ClassDB::register_class<GPUParticles3D>();
+ ClassDB::register_class<CPUParticles3D>();
ClassDB::register_class<Position3D>();
ClassDB::register_class<RootMotionView>();
@@ -431,55 +439,53 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_virtual_class<CollisionObject>();
- ClassDB::register_virtual_class<PhysicsBody>();
- ClassDB::register_class<StaticBody>();
- ClassDB::register_class<RigidBody>();
- ClassDB::register_class<KinematicCollision>();
- ClassDB::register_class<KinematicBody>();
- ClassDB::register_class<SpringArm>();
-
- ClassDB::register_class<PhysicalBone>();
- ClassDB::register_class<SoftBody>();
-
- ClassDB::register_class<SkeletonIK>();
- ClassDB::register_class<BoneAttachment>();
-
- ClassDB::register_class<VehicleBody>();
- ClassDB::register_class<VehicleWheel>();
- ClassDB::register_class<Area>();
- ClassDB::register_class<ProximityGroup>();
- ClassDB::register_class<CollisionShape>();
- ClassDB::register_class<CollisionPolygon>();
- ClassDB::register_class<RayCast>();
- ClassDB::register_class<MultiMeshInstance>();
+ ClassDB::register_virtual_class<CollisionObject3D>();
+ ClassDB::register_virtual_class<PhysicsBody3D>();
+ ClassDB::register_class<StaticBody3D>();
+ ClassDB::register_class<RigidBody3D>();
+ ClassDB::register_class<KinematicCollision3D>();
+ ClassDB::register_class<KinematicBody3D>();
+ ClassDB::register_class<SpringArm3D>();
+
+ ClassDB::register_class<PhysicalBone3D>();
+ ClassDB::register_class<SoftBody3D>();
+
+ ClassDB::register_class<SkeletonIK3D>();
+ ClassDB::register_class<BoneAttachment3D>();
+
+ ClassDB::register_class<VehicleBody3D>();
+ ClassDB::register_class<VehicleWheel3D>();
+ ClassDB::register_class<Area3D>();
+ ClassDB::register_class<ProximityGroup3D>();
+ ClassDB::register_class<CollisionShape3D>();
+ ClassDB::register_class<CollisionPolygon3D>();
+ ClassDB::register_class<RayCast3D>();
+ ClassDB::register_class<MultiMeshInstance3D>();
ClassDB::register_class<Curve3D>();
- ClassDB::register_class<Path>();
- ClassDB::register_class<PathFollow>();
- ClassDB::register_class<VisibilityNotifier>();
- ClassDB::register_class<VisibilityEnabler>();
+ ClassDB::register_class<Path3D>();
+ ClassDB::register_class<PathFollow3D>();
+ ClassDB::register_class<VisibilityNotifier3D>();
+ ClassDB::register_class<VisibilityEnabler3D>();
ClassDB::register_class<WorldEnvironment>();
- ClassDB::register_class<RemoteTransform>();
+ ClassDB::register_class<RemoteTransform3D>();
- ClassDB::register_virtual_class<Joint>();
- ClassDB::register_class<PinJoint>();
- ClassDB::register_class<HingeJoint>();
- ClassDB::register_class<SliderJoint>();
- ClassDB::register_class<ConeTwistJoint>();
- ClassDB::register_class<Generic6DOFJoint>();
+ ClassDB::register_virtual_class<Joint3D>();
+ ClassDB::register_class<PinJoint3D>();
+ ClassDB::register_class<HingeJoint3D>();
+ ClassDB::register_class<SliderJoint3D>();
+ ClassDB::register_class<ConeTwistJoint3D>();
+ ClassDB::register_class<Generic6DOFJoint3D>();
- ClassDB::register_class<Navigation>();
- ClassDB::register_class<NavigationRegion>();
- ClassDB::register_class<NavigationAgent>();
- ClassDB::register_class<NavigationObstacle>();
+ ClassDB::register_class<Navigation3D>();
+ ClassDB::register_class<NavigationRegion3D>();
+ ClassDB::register_class<NavigationAgent3D>();
+ ClassDB::register_class<NavigationObstacle3D>();
OS::get_singleton()->yield(); //may take time to init
-
#endif
- ClassDB::register_class<NavigationMesh>();
- AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(OS::get_singleton()->get_swap_ok_cancel())));
+ /* REGISTER SHADER */
ClassDB::register_class<Shader>();
ClassDB::register_class<VisualShader>();
@@ -553,14 +559,15 @@ void register_scene_types() {
ClassDB::register_class<CanvasItemMaterial>();
SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes);
CanvasItemMaterial::init_shaders();
+
+ /* REGISTER 2D */
+
ClassDB::register_class<Node2D>();
ClassDB::register_class<CPUParticles2D>();
- ClassDB::register_class<Particles2D>();
- //ClassDB::register_class<ParticleAttractor2D>();
- ClassDB::register_class<Sprite>();
- //ClassDB::register_type<ViewportSprite>();
+ ClassDB::register_class<GPUParticles2D>();
+ ClassDB::register_class<Sprite2D>();
ClassDB::register_class<SpriteFrames>();
- ClassDB::register_class<AnimatedSprite>();
+ ClassDB::register_class<AnimatedSprite2D>();
ClassDB::register_class<Position2D>();
ClassDB::register_class<Line2D>();
ClassDB::register_class<MeshInstance2D>();
@@ -609,6 +616,10 @@ void register_scene_types() {
SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
ParticlesMaterial::init_shaders();
+ ClassDB::register_class<ProceduralSkyMaterial>();
+ ClassDB::register_class<PanoramaSkyMaterial>();
+ ClassDB::register_class<PhysicalSkyMaterial>();
+
ClassDB::register_virtual_class<Mesh>();
ClassDB::register_class<ArrayMesh>();
ClassDB::register_class<MultiMesh>();
@@ -636,32 +647,30 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_virtual_class<Shape>();
- ClassDB::register_class<RayShape>();
- ClassDB::register_class<SphereShape>();
- ClassDB::register_class<BoxShape>();
- ClassDB::register_class<CapsuleShape>();
- ClassDB::register_class<CylinderShape>();
- ClassDB::register_class<HeightMapShape>();
- ClassDB::register_class<WorldMarginShape>();
- ClassDB::register_class<ConvexPolygonShape>();
- ClassDB::register_class<ConcavePolygonShape>();
+ ClassDB::register_virtual_class<Shape3D>();
+ ClassDB::register_class<RayShape3D>();
+ ClassDB::register_class<SphereShape3D>();
+ ClassDB::register_class<BoxShape3D>();
+ ClassDB::register_class<CapsuleShape3D>();
+ ClassDB::register_class<CylinderShape3D>();
+ ClassDB::register_class<HeightMapShape3D>();
+ ClassDB::register_class<WorldMarginShape3D>();
+ ClassDB::register_class<ConvexPolygonShape3D>();
+ ClassDB::register_class<ConcavePolygonShape3D>();
OS::get_singleton()->yield(); //may take time to init
- ClassDB::register_class<SpatialVelocityTracker>();
-
+ ClassDB::register_class<VelocityTracker3D>();
#endif
+
ClassDB::register_class<PhysicsMaterial>();
- ClassDB::register_class<World>();
+ ClassDB::register_class<World3D>();
ClassDB::register_class<Environment>();
ClassDB::register_class<CameraEffects>();
ClassDB::register_class<World2D>();
ClassDB::register_virtual_class<Texture>();
ClassDB::register_virtual_class<Texture2D>();
- ClassDB::register_virtual_class<Sky>();
- ClassDB::register_class<PanoramaSky>();
- ClassDB::register_class<ProceduralSky>();
+ ClassDB::register_class<Sky>();
ClassDB::register_class<StreamTexture>();
ClassDB::register_class<ImageTexture>();
ClassDB::register_class<AtlasTexture>();
@@ -724,6 +733,7 @@ void register_scene_types() {
ClassDB::register_class<Path2D>();
ClassDB::register_class<PathFollow2D>();
+ ClassDB::register_class<NavigationMesh>();
ClassDB::register_class<Navigation2D>();
ClassDB::register_class<NavigationPolygon>();
ClassDB::register_class<NavigationRegion2D>();
@@ -739,16 +749,117 @@ void register_scene_types() {
ClassDB::register_virtual_class<SceneTreeTimer>(); //sorry, you can't create it
#ifndef DISABLE_DEPRECATED
- ClassDB::add_compatibility_class("SpatialMaterial", "StandardMaterial3D");
- ClassDB::add_compatibility_class("Mesh", "ArrayMesh");
+ // Dropped in 4.0, near approximation.
ClassDB::add_compatibility_class("AnimationTreePlayer", "AnimationTree");
+
+ // Renamed in 4.0.
+ ClassDB::add_compatibility_class("AnimatedSprite", "AnimatedSprite2D");
+ ClassDB::add_compatibility_class("Area", "Area3D");
+ ClassDB::add_compatibility_class("BoneAttachment", "BoneAttachment3D");
+ ClassDB::add_compatibility_class("BoxShape", "BoxShape3D");
+ ClassDB::add_compatibility_class("BulletPhysicsDirectBodyState", "BulletPhysicsDirectBodyState3D");
+ ClassDB::add_compatibility_class("BulletPhysicsServer", "BulletPhysicsServer3D");
+ ClassDB::add_compatibility_class("Camera", "Camera3D");
+ ClassDB::add_compatibility_class("CapsuleShape", "CapsuleShape3D");
+ ClassDB::add_compatibility_class("ClippedCamera", "ClippedCamera3D");
+ ClassDB::add_compatibility_class("CollisionObject", "CollisionObject3D");
+ ClassDB::add_compatibility_class("CollisionPolygon", "CollisionPolygon3D");
+ ClassDB::add_compatibility_class("CollisionShape", "CollisionShape3D");
+ ClassDB::add_compatibility_class("ConcavePolygonShape", "ConcavePolygonShape3D");
+ ClassDB::add_compatibility_class("ConeTwistJoint", "ConeTwistJoint3D");
+ ClassDB::add_compatibility_class("ConvexPolygonShape", "ConvexPolygonShape3D");
+ ClassDB::add_compatibility_class("CPUParticles", "CPUParticles3D");
+ ClassDB::add_compatibility_class("CSGBox", "CSGBox3D");
+ ClassDB::add_compatibility_class("CSGCombiner", "CSGCombiner3D");
+ ClassDB::add_compatibility_class("CSGCylinder", "CSGCylinder3D");
+ ClassDB::add_compatibility_class("CSGMesh", "CSGMesh3D");
+ ClassDB::add_compatibility_class("CSGPolygon", "CSGPolygon3D");
+ ClassDB::add_compatibility_class("CSGPrimitive", "CSGPrimitive3D");
+ ClassDB::add_compatibility_class("CSGShape", "CSGShape3D");
+ ClassDB::add_compatibility_class("CSGSphere", "CSGSphere3D");
+ ClassDB::add_compatibility_class("CSGTorus", "CSGTorus3D");
+ ClassDB::add_compatibility_class("CylinderShape", "CylinderShape3D");
+ ClassDB::add_compatibility_class("DirectionalLight", "DirectionalLight3D");
+ ClassDB::add_compatibility_class("EditorSpatialGizmo", "EditorNode3DGizmo");
+ ClassDB::add_compatibility_class("EditorSpatialGizmoPlugin", "EditorNode3DGizmoPlugin");
+ ClassDB::add_compatibility_class("Generic6DOFJoint", "Generic6DOFJoint3D");
+ ClassDB::add_compatibility_class("HeightMapShape", "HeightMapShape3D");
+ ClassDB::add_compatibility_class("HingeJoint", "HingeJoint3D");
+ ClassDB::add_compatibility_class("ImmediateGeometry", "ImmediateGeometry3D");
+ ClassDB::add_compatibility_class("Joint", "Joint3D");
+ ClassDB::add_compatibility_class("KinematicBody", "KinematicBody3D");
+ ClassDB::add_compatibility_class("KinematicCollision", "KinematicCollision3D");
+ ClassDB::add_compatibility_class("Light", "Light3D");
+ 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");
+ ClassDB::add_compatibility_class("NavigationPolygonInstance", "NavigationRegion2D");
+ ClassDB::add_compatibility_class("NavigationRegion", "NavigationRegion3D");
+ ClassDB::add_compatibility_class("Navigation2DServer", "NavigationServer2D");
+ ClassDB::add_compatibility_class("NavigationServer", "NavigationServer3D");
+ ClassDB::add_compatibility_class("OmniLight", "OmniLight3D");
+ ClassDB::add_compatibility_class("Particles", "GPUParticles3D");
+ ClassDB::add_compatibility_class("Particles2D", "GPUParticles2D");
+ ClassDB::add_compatibility_class("Path", "Path3D");
+ ClassDB::add_compatibility_class("PathFollow", "PathFollow3D");
+ ClassDB::add_compatibility_class("PhysicalBone", "PhysicalBone3D");
+ ClassDB::add_compatibility_class("Physics2DDirectBodyStateSW", "PhysicsDirectBodyState2DSW");
+ ClassDB::add_compatibility_class("Physics2DDirectBodyState", "PhysicsDirectBodyState2D");
+ ClassDB::add_compatibility_class("Physics2DDirectSpaceState", "PhysicsDirectSpaceState2D");
+ ClassDB::add_compatibility_class("Physics2DServerSW", "PhysicsServer2DSW");
+ ClassDB::add_compatibility_class("Physics2DServer", "PhysicsServer2D");
+ ClassDB::add_compatibility_class("Physics2DShapeQueryParameters", "PhysicsShapeQueryParameters2D");
+ ClassDB::add_compatibility_class("Physics2DShapeQueryResult", "PhysicsShapeQueryResult2D");
+ ClassDB::add_compatibility_class("Physics2DTestMotionResult", "PhysicsTestMotionResult2D");
+ ClassDB::add_compatibility_class("PhysicsBody", "PhysicsBody3D");
+ ClassDB::add_compatibility_class("PhysicsDirectBodyState", "PhysicsDirectBodyState3D");
+ ClassDB::add_compatibility_class("PhysicsDirectSpaceState", "PhysicsDirectSpaceState3D");
+ ClassDB::add_compatibility_class("PhysicsServer", "PhysicsServer3D");
+ ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D");
+ ClassDB::add_compatibility_class("PhysicsShapeQueryResult", "PhysicsShapeQueryResult3D");
+ ClassDB::add_compatibility_class("PinJoint", "PinJoint3D");
+ ClassDB::add_compatibility_class("PlaneShape", "WorldMarginShape3D");
+ ClassDB::add_compatibility_class("ProximityGroup", "ProximityGroup3D");
+ ClassDB::add_compatibility_class("RayCast", "RayCast3D");
+ ClassDB::add_compatibility_class("RayShape", "RayShape3D");
+ ClassDB::add_compatibility_class("RemoteTransform", "RemoteTransform3D");
+ ClassDB::add_compatibility_class("RigidBody", "RigidBody3D");
+ ClassDB::add_compatibility_class("Shape", "Shape3D");
+ ClassDB::add_compatibility_class("Skeleton", "Skeleton3D");
+ ClassDB::add_compatibility_class("SkeletonIK", "SkeletonIK3D");
+ ClassDB::add_compatibility_class("SliderJoint", "SliderJoint3D");
+ ClassDB::add_compatibility_class("SoftBody", "SoftBody3D");
+ ClassDB::add_compatibility_class("Spatial", "Node3D");
+ ClassDB::add_compatibility_class("SpatialGizmo", "Node3DGizmo");
+ ClassDB::add_compatibility_class("SpatialMaterial", "StandardMaterial3D");
+ ClassDB::add_compatibility_class("SpatialVelocityTracker", "VelocityTracker3D");
+ ClassDB::add_compatibility_class("SphereShape", "SphereShape3D");
+ ClassDB::add_compatibility_class("SpotLight", "SpotLight3D");
+ ClassDB::add_compatibility_class("SpringArm", "SpringArm3D");
+ ClassDB::add_compatibility_class("Sprite", "Sprite2D");
+ ClassDB::add_compatibility_class("StaticBody", "StaticBody3D");
+ ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D");
+ ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D");
+ ClassDB::add_compatibility_class("ViewportContainer", "SubViewportContainer");
+ ClassDB::add_compatibility_class("VisibilityEnabler", "VisibilityEnabler3D");
+ ClassDB::add_compatibility_class("VisibilityNotifier", "VisibilityNotifier3D");
+ ClassDB::add_compatibility_class("VisualServer", "RenderingServer");
ClassDB::add_compatibility_class("VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant");
- ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform");
- ClassDB::add_compatibility_class("VisualShaderNodeScalarOp", "VisualShaderNodeFloatOp");
ClassDB::add_compatibility_class("VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc");
- ClassDB::add_compatibility_class("NavigationMeshInstance", "NavigationRegion");
- ClassDB::add_compatibility_class("NavigationPolygonInstance", "NavigationRegion2D");
- ClassDB::add_compatibility_class("PlaneShape", "WorldMarginShape");
+ ClassDB::add_compatibility_class("VisualShaderNodeScalarOp", "VisualShaderNodeFloatOp");
+ ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform");
+ ClassDB::add_compatibility_class("World", "World3D");
+ ClassDB::add_compatibility_class("ProceduralSky", "Sky");
+ ClassDB::add_compatibility_class("PanoramaSky", "Sky");
+ ClassDB::add_compatibility_class("ARVRCamera", "XRCamera3D");
+ ClassDB::add_compatibility_class("ARVROrigin", "XROrigin3D");
+ ClassDB::add_compatibility_class("ARVRController", "XRController3D");
+ ClassDB::add_compatibility_class("ARVRAnchor", "XRAnchor3D");
+
#endif
OS::get_singleton()->yield(); //may take time to init
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index 5e5b6f8fd5..3a86b22835 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index ba1f738115..aa4c9bf225 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -1705,7 +1705,7 @@ float Animation::_cubic_interpolate(const float &p_pre_a, const float &p_a, cons
}
template <class T>
-T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const {
+T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const {
int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end)
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index ea4f92878d..e4e5177a8c 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -84,7 +84,10 @@ private:
float transition;
float time; // time in secs
- Key() { transition = 1; }
+ Key() {
+ transition = 1;
+ time = 0;
+ }
};
// transform key holds either Vector3 or Quaternion
@@ -105,7 +108,7 @@ private:
struct TransformTrack : public Track {
- Vector<TKey<TransformKey> > transforms;
+ Vector<TKey<TransformKey>> transforms;
TransformTrack() { type = TYPE_TRANSFORM; }
};
@@ -116,7 +119,7 @@ private:
UpdateMode update_mode;
bool update_on_seek;
- Vector<TKey<Variant> > values;
+ Vector<TKey<Variant>> values;
ValueTrack() {
type = TYPE_VALUE;
@@ -148,7 +151,7 @@ private:
struct BezierTrack : public Track {
- Vector<TKey<BezierKey> > values;
+ Vector<TKey<BezierKey>> values;
BezierTrack() {
type = TYPE_BEZIER;
@@ -169,7 +172,7 @@ private:
struct AudioTrack : public Track {
- Vector<TKey<AudioKey> > values;
+ Vector<TKey<AudioKey>> values;
AudioTrack() {
type = TYPE_AUDIO;
@@ -180,7 +183,7 @@ private:
struct AnimationTrack : public Track {
- Vector<TKey<StringName> > values;
+ Vector<TKey<StringName>> values;
AnimationTrack() {
type = TYPE_ANIMATION;
@@ -216,7 +219,7 @@ private:
_FORCE_INLINE_ float _cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const;
template <class T>
- _FORCE_INLINE_ T _interpolate(const Vector<TKey<T> > &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const;
+ _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const;
template <class T>
_FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, float from_time, float to_time, List<int> *p_indices) const;
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index ed25729c40..d630a1f3ee 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -258,7 +258,7 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in
float srate = base->mix_rate;
srate *= p_rate_scale;
float fincrement = srate / base_rate;
- int32_t increment = int32_t(fincrement * MIX_FRAC_LEN);
+ int32_t increment = int32_t(MAX(fincrement * MIX_FRAC_LEN, 1));
increment *= sign;
//looping
@@ -481,8 +481,8 @@ void AudioStreamSample::set_data(const Vector<uint8_t> &p_data) {
AudioServer::get_singleton()->lock();
if (data) {
- AudioServer::get_singleton()->audio_data_free(data);
- data = NULL;
+ memfree(data);
+ data = nullptr;
data_bytes = 0;
}
@@ -491,7 +491,7 @@ 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 = AudioServer::get_singleton()->audio_data_alloc(alloc_len); //alloc with some padding for interpolation
+ data = memalloc(alloc_len); //alloc with some padding for interpolation
zeromem(data, alloc_len);
uint8_t *dataptr = (uint8_t *)data;
copymem(dataptr + DATA_PAD, r, datalen);
@@ -654,14 +654,14 @@ AudioStreamSample::AudioStreamSample() {
loop_begin = 0;
loop_end = 0;
mix_rate = 44100;
- data = NULL;
+ data = nullptr;
data_bytes = 0;
}
AudioStreamSample::~AudioStreamSample() {
if (data) {
- AudioServer::get_singleton()->audio_data_free(data);
- data = NULL;
+ memfree(data);
+ data = nullptr;
data_bytes = 0;
}
}
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 6730f86e0c..d45f36dfd1 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -493,7 +493,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
print_verbose("BitMap: Max stack size: " + itos(stack.size()));
}
-Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
+Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
print_verbose("BitMap: Rect: " + r);
@@ -503,7 +503,7 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
fill.instance();
fill->create(get_size());
- Vector<Vector<Vector2> > polygons;
+ Vector<Vector<Vector2>> polygons;
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
@@ -591,7 +591,7 @@ void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) {
Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
- Vector<Vector<Vector2> > result = clip_opaque_to_polygons(p_rect, p_epsilon);
+ Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon);
// Convert result to bindable types
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index ed332dffa4..05313a0cff 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -72,7 +72,7 @@ public:
void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap);
Ref<Image> convert_to_image() const;
- Vector<Vector<Vector2> > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
+ Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
BitMap();
};
diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp
deleted file mode 100644
index e1f485bae6..0000000000
--- a/scene/resources/box_shape.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*************************************************************************/
-/* box_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "box_shape.h"
-#include "servers/physics_server.h"
-
-Vector<Vector3> BoxShape::get_debug_mesh_lines() {
-
- Vector<Vector3> lines;
- AABB aabb;
- aabb.position = -get_extents();
- aabb.size = aabb.position * -2;
-
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- return lines;
-}
-
-real_t BoxShape::get_enclosing_radius() const {
- return extents.length();
-}
-
-void BoxShape::_update_shape() {
-
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), extents);
- Shape::_update_shape();
-}
-
-void BoxShape::set_extents(const Vector3 &p_extents) {
-
- extents = p_extents;
- _update_shape();
- notify_change_to_owners();
- _change_notify("extents");
-}
-
-Vector3 BoxShape::get_extents() const {
-
- return extents;
-}
-
-void BoxShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BoxShape::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &BoxShape::get_extents);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
-}
-
-BoxShape::BoxShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_BOX)) {
-
- set_extents(Vector3(1, 1, 1));
-}
diff --git a/scene/resources/box_shape.h b/scene/resources/box_shape.h
deleted file mode 100644
index fb164cc300..0000000000
--- a/scene/resources/box_shape.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*************************************************************************/
-/* box_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BOX_SHAPE_H
-#define BOX_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class BoxShape : public Shape {
-
- GDCLASS(BoxShape, Shape);
- Vector3 extents;
-
-protected:
- static void _bind_methods();
-
- virtual void _update_shape();
-
-public:
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- BoxShape();
-};
-
-#endif // BOX_SHAPE_H
diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp
new file mode 100644
index 0000000000..64c821a011
--- /dev/null
+++ b/scene/resources/box_shape_3d.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* box_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "box_shape_3d.h"
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> BoxShape3D::get_debug_mesh_lines() {
+
+ Vector<Vector3> lines;
+ AABB aabb;
+ aabb.position = -get_extents();
+ aabb.size = aabb.position * -2;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ return lines;
+}
+
+real_t BoxShape3D::get_enclosing_radius() const {
+ return extents.length();
+}
+
+void BoxShape3D::_update_shape() {
+
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), extents);
+ Shape3D::_update_shape();
+}
+
+void BoxShape3D::set_extents(const Vector3 &p_extents) {
+
+ extents = p_extents;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("extents");
+}
+
+Vector3 BoxShape3D::get_extents() const {
+
+ return extents;
+}
+
+void BoxShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BoxShape3D::set_extents);
+ ClassDB::bind_method(D_METHOD("get_extents"), &BoxShape3D::get_extents);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
+}
+
+BoxShape3D::BoxShape3D() :
+ Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_BOX)) {
+
+ set_extents(Vector3(1, 1, 1));
+}
diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h
new file mode 100644
index 0000000000..a93fd8d33a
--- /dev/null
+++ b/scene/resources/box_shape_3d.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* box_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BOX_SHAPE_H
+#define BOX_SHAPE_H
+
+#include "scene/resources/shape_3d.h"
+
+class BoxShape3D : public Shape3D {
+
+ GDCLASS(BoxShape3D, Shape3D);
+ Vector3 extents;
+
+protected:
+ static void _bind_methods();
+
+ virtual void _update_shape();
+
+public:
+ void set_extents(const Vector3 &p_extents);
+ Vector3 get_extents() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ BoxShape3D();
+};
+
+#endif // BOX_SHAPE_H
diff --git a/scene/resources/canvas.cpp b/scene/resources/canvas.cpp
deleted file mode 100644
index 1dbd02ea28..0000000000
--- a/scene/resources/canvas.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*************************************************************************/
-/* canvas.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "canvas.h"
-#include "servers/visual_server.h"
-
-RID Canvas::get_rid() const {
-
- return canvas;
-}
-
-Canvas::Canvas() {
-
- canvas = VisualServer::get_singleton()->canvas_create();
-}
-
-Canvas::~Canvas() {
- VisualServer::get_singleton()->free(canvas);
-}
diff --git a/scene/resources/canvas.h b/scene/resources/canvas.h
deleted file mode 100644
index 621911fe0a..0000000000
--- a/scene/resources/canvas.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* canvas.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CANVAS_H
-#define CANVAS_H
-
-#include "core/resource.h"
-
-class Canvas : public Resource {
-
- GDCLASS(Canvas, Resource);
-
- RID canvas;
-
-public:
- virtual RID get_rid() const;
- Canvas();
- ~Canvas();
-};
-
-#endif // CANVAS_H
diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp
deleted file mode 100644
index dddbd7fef3..0000000000
--- a/scene/resources/capsule_shape.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*************************************************************************/
-/* capsule_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "capsule_shape.h"
-#include "servers/physics_server.h"
-
-Vector<Vector3> CapsuleShape::get_debug_mesh_lines() {
-
- float radius = get_radius();
- float height = get_height();
-
- Vector<Vector3> points;
-
- Vector3 d(0, height * 0.5, 0);
- for (int i = 0; i < 360; i++) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(b.x, 0, b.y) + d);
-
- points.push_back(Vector3(a.x, 0, a.y) - d);
- points.push_back(Vector3(b.x, 0, b.y) - d);
-
- if (i % 90 == 0) {
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(a.x, 0, a.y) - d);
- }
-
- Vector3 dud = i < 180 ? d : -d;
-
- points.push_back(Vector3(0, a.x, a.y) + dud);
- points.push_back(Vector3(0, b.x, b.y) + dud);
- points.push_back(Vector3(a.y, a.x, 0) + dud);
- points.push_back(Vector3(b.y, b.x, 0) + dud);
- }
-
- return points;
-}
-
-real_t CapsuleShape::get_enclosing_radius() const {
- return radius + height * 0.5;
-}
-
-void CapsuleShape::_update_shape() {
-
- Dictionary d;
- d["radius"] = radius;
- d["height"] = height;
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
- Shape::_update_shape();
-}
-
-void CapsuleShape::set_radius(float p_radius) {
-
- radius = p_radius;
- _update_shape();
- notify_change_to_owners();
- _change_notify("radius");
-}
-
-float CapsuleShape::get_radius() const {
-
- return radius;
-}
-
-void CapsuleShape::set_height(float p_height) {
-
- height = p_height;
- _update_shape();
- notify_change_to_owners();
- _change_notify("height");
-}
-
-float CapsuleShape::get_height() const {
-
- return height;
-}
-
-void CapsuleShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleShape::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleShape::get_radius);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape::set_height);
- ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape::get_height);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height");
-}
-
-CapsuleShape::CapsuleShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CAPSULE)) {
-
- radius = 1.0;
- height = 1.0;
- _update_shape();
-}
diff --git a/scene/resources/capsule_shape.h b/scene/resources/capsule_shape.h
deleted file mode 100644
index f097e51175..0000000000
--- a/scene/resources/capsule_shape.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*************************************************************************/
-/* capsule_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CAPSULE_SHAPE_H
-#define CAPSULE_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class CapsuleShape : public Shape {
-
- GDCLASS(CapsuleShape, Shape);
- float radius;
- float height;
-
-protected:
- static void _bind_methods();
-
- virtual void _update_shape();
-
-public:
- void set_radius(float p_radius);
- float get_radius() const;
- void set_height(float p_height);
- float get_height() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- CapsuleShape();
-};
-
-#endif // CAPSULE_SHAPE_H
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 9b8083de97..ab2657c892 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -30,8 +30,8 @@
#include "capsule_shape_2d.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
Vector<Vector2> CapsuleShape2D::_get_points() const {
@@ -54,7 +54,7 @@ bool CapsuleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_
void CapsuleShape2D::_update_shape() {
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), Vector2(radius, height));
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), Vector2(radius, height));
emit_changed();
}
@@ -85,7 +85,7 @@ void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector<Vector2> points = _get_points();
Vector<Color> col;
col.push_back(p_color);
- VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+ RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
}
Rect2 CapsuleShape2D::get_rect() const {
@@ -114,7 +114,7 @@ void CapsuleShape2D::_bind_methods() {
}
CapsuleShape2D::CapsuleShape2D() :
- Shape2D(Physics2DServer::get_singleton()->capsule_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->capsule_shape_create()) {
radius = 10;
height = 20;
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
new file mode 100644
index 0000000000..da3ffcb306
--- /dev/null
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -0,0 +1,128 @@
+/*************************************************************************/
+/* capsule_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "capsule_shape_3d.h"
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() {
+
+ float radius = get_radius();
+ float height = get_height();
+
+ Vector<Vector3> points;
+
+ Vector3 d(0, height * 0.5, 0);
+ for (int i = 0; i < 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(b.x, 0, b.y) + d);
+
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ points.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 90 == 0) {
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+
+ Vector3 dud = i < 180 ? d : -d;
+
+ points.push_back(Vector3(0, a.x, a.y) + dud);
+ points.push_back(Vector3(0, b.x, b.y) + dud);
+ points.push_back(Vector3(a.y, a.x, 0) + dud);
+ points.push_back(Vector3(b.y, b.x, 0) + dud);
+ }
+
+ return points;
+}
+
+real_t CapsuleShape3D::get_enclosing_radius() const {
+ return radius + height * 0.5;
+}
+
+void CapsuleShape3D::_update_shape() {
+
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+ Shape3D::_update_shape();
+}
+
+void CapsuleShape3D::set_radius(float p_radius) {
+
+ radius = p_radius;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("radius");
+}
+
+float CapsuleShape3D::get_radius() const {
+
+ return radius;
+}
+
+void CapsuleShape3D::set_height(float p_height) {
+
+ height = p_height;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("height");
+}
+
+float CapsuleShape3D::get_height() const {
+
+ return height;
+}
+
+void CapsuleShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleShape3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleShape3D::get_radius);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleShape3D::set_height);
+ ClassDB::bind_method(D_METHOD("get_height"), &CapsuleShape3D::get_height);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height");
+}
+
+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
new file mode 100644
index 0000000000..dca7a6c983
--- /dev/null
+++ b/scene/resources/capsule_shape_3d.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* capsule_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CAPSULE_SHAPE_H
+#define CAPSULE_SHAPE_H
+
+#include "scene/resources/shape_3d.h"
+
+class CapsuleShape3D : public Shape3D {
+
+ GDCLASS(CapsuleShape3D, Shape3D);
+ float radius;
+ float height;
+
+protected:
+ static void _bind_methods();
+
+ virtual void _update_shape();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+ void set_height(float p_height);
+ float get_height() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ CapsuleShape3D();
+};
+
+#endif // CAPSULE_SHAPE_H
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index 37874e17ef..afb7597280 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -30,8 +30,8 @@
#include "circle_shape_2d.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
bool CircleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
@@ -40,7 +40,7 @@ bool CircleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_t
void CircleShape2D::_update_shape() {
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), radius);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), radius);
emit_changed();
}
@@ -84,11 +84,11 @@ void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector<Color> col;
col.push_back(p_color);
- VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+ RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
}
CircleShape2D::CircleShape2D() :
- Shape2D(Physics2DServer::get_singleton()->circle_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->circle_shape_create()) {
radius = 10;
_update_shape();
diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp
deleted file mode 100644
index fe123a2df7..0000000000
--- a/scene/resources/concave_polygon_shape.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*************************************************************************/
-/* concave_polygon_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "concave_polygon_shape.h"
-
-#include "servers/physics_server.h"
-
-Vector<Vector3> ConcavePolygonShape::get_debug_mesh_lines() {
-
- Set<DrawEdge> edges;
-
- Vector<Vector3> data = get_faces();
- int datalen = data.size();
- ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>());
-
- const Vector3 *r = data.ptr();
-
- for (int i = 0; i < datalen; i += 3) {
-
- for (int j = 0; j < 3; j++) {
-
- DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
- edges.insert(de);
- }
- }
-
- Vector<Vector3> points;
- points.resize(edges.size() * 2);
- int idx = 0;
- for (Set<DrawEdge>::Element *E = edges.front(); E; E = E->next()) {
-
- points.write[idx + 0] = E->get().a;
- points.write[idx + 1] = E->get().b;
- idx += 2;
- }
-
- return points;
-}
-
-real_t ConcavePolygonShape::get_enclosing_radius() const {
- Vector<Vector3> data = get_faces();
- const Vector3 *read = data.ptr();
- real_t r = 0;
- for (int i(0); i < data.size(); i++) {
- r = MAX(read[i].length_squared(), r);
- }
- return Math::sqrt(r);
-}
-
-void ConcavePolygonShape::_update_shape() {
- Shape::_update_shape();
-}
-
-void ConcavePolygonShape::set_faces(const Vector<Vector3> &p_faces) {
-
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), p_faces);
- notify_change_to_owners();
-}
-
-Vector<Vector3> ConcavePolygonShape::get_faces() const {
-
- return PhysicsServer::get_singleton()->shape_get_data(get_shape());
-}
-
-void ConcavePolygonShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape::set_faces);
- ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape::get_faces);
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
-}
-
-ConcavePolygonShape::ConcavePolygonShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONCAVE_POLYGON)) {
-
- //set_planes(Vector3(1,1,1));
-}
diff --git a/scene/resources/concave_polygon_shape.h b/scene/resources/concave_polygon_shape.h
deleted file mode 100644
index 63aabb27d7..0000000000
--- a/scene/resources/concave_polygon_shape.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*************************************************************************/
-/* concave_polygon_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CONCAVE_POLYGON_SHAPE_H
-#define CONCAVE_POLYGON_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class ConcavePolygonShape : public Shape {
-
- GDCLASS(ConcavePolygonShape, Shape);
-
- struct DrawEdge {
-
- Vector3 a;
- Vector3 b;
- bool operator<(const DrawEdge &p_edge) const {
- if (a == p_edge.a)
- return b < p_edge.b;
- else
- return a < p_edge.a;
- }
-
- DrawEdge(const Vector3 &p_a = Vector3(), const Vector3 &p_b = Vector3()) {
- a = p_a;
- b = p_b;
- if (a < b) {
- SWAP(a, b);
- }
- }
- };
-
-protected:
- static void _bind_methods();
-
- virtual void _update_shape();
-
-public:
- void set_faces(const Vector<Vector3> &p_faces);
- Vector<Vector3> get_faces() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- ConcavePolygonShape();
-};
-
-#endif // CONCAVE_POLYGON_SHAPE_H
diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp
index c3e9e19721..c8fec3b72d 100644
--- a/scene/resources/concave_polygon_shape_2d.cpp
+++ b/scene/resources/concave_polygon_shape_2d.cpp
@@ -30,8 +30,8 @@
#include "concave_polygon_shape_2d.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
@@ -52,13 +52,13 @@ bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, do
void ConcavePolygonShape2D::set_segments(const Vector<Vector2> &p_segments) {
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), p_segments);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), p_segments);
emit_changed();
}
Vector<Vector2> ConcavePolygonShape2D::get_segments() const {
- return Physics2DServer::get_singleton()->shape_get_data(get_rid());
+ return PhysicsServer2D::get_singleton()->shape_get_data(get_rid());
}
void ConcavePolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
@@ -70,7 +70,7 @@ void ConcavePolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
const Vector2 *r = s.ptr();
for (int i = 0; i < len; i += 2) {
- VisualServer::get_singleton()->canvas_item_add_line(p_to_rid, r[i], r[i + 1], p_color, 2);
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, r[i], r[i + 1], p_color, 2);
}
}
@@ -113,7 +113,7 @@ void ConcavePolygonShape2D::_bind_methods() {
}
ConcavePolygonShape2D::ConcavePolygonShape2D() :
- Shape2D(Physics2DServer::get_singleton()->concave_polygon_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->concave_polygon_shape_create()) {
Vector<Vector2> empty;
set_segments(empty);
}
diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp
new file mode 100644
index 0000000000..42e06a49b6
--- /dev/null
+++ b/scene/resources/concave_polygon_shape_3d.cpp
@@ -0,0 +1,103 @@
+/*************************************************************************/
+/* concave_polygon_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "concave_polygon_shape_3d.h"
+
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() {
+
+ Set<DrawEdge> edges;
+
+ Vector<Vector3> data = get_faces();
+ int datalen = data.size();
+ ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>());
+
+ const Vector3 *r = data.ptr();
+
+ for (int i = 0; i < datalen; i += 3) {
+
+ for (int j = 0; j < 3; j++) {
+
+ DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
+ edges.insert(de);
+ }
+ }
+
+ Vector<Vector3> points;
+ points.resize(edges.size() * 2);
+ int idx = 0;
+ for (Set<DrawEdge>::Element *E = edges.front(); E; E = E->next()) {
+
+ points.write[idx + 0] = E->get().a;
+ points.write[idx + 1] = E->get().b;
+ idx += 2;
+ }
+
+ return points;
+}
+
+real_t ConcavePolygonShape3D::get_enclosing_radius() const {
+ Vector<Vector3> data = get_faces();
+ const Vector3 *read = data.ptr();
+ real_t r = 0;
+ for (int i(0); i < data.size(); i++) {
+ r = MAX(read[i].length_squared(), r);
+ }
+ return Math::sqrt(r);
+}
+
+void ConcavePolygonShape3D::_update_shape() {
+ Shape3D::_update_shape();
+}
+
+void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
+
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), p_faces);
+ notify_change_to_owners();
+}
+
+Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
+
+ return PhysicsServer3D::get_singleton()->shape_get_data(get_shape());
+}
+
+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);
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
+}
+
+ConcavePolygonShape3D::ConcavePolygonShape3D() :
+ Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON)) {
+
+ //set_planes(Vector3(1,1,1));
+}
diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h
new file mode 100644
index 0000000000..b4e96c662f
--- /dev/null
+++ b/scene/resources/concave_polygon_shape_3d.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* concave_polygon_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CONCAVE_POLYGON_SHAPE_3D_H
+#define CONCAVE_POLYGON_SHAPE_3D_H
+
+#include "scene/resources/shape_3d.h"
+
+class ConcavePolygonShape3D : public Shape3D {
+
+ GDCLASS(ConcavePolygonShape3D, Shape3D);
+
+ struct DrawEdge {
+
+ Vector3 a;
+ Vector3 b;
+ bool operator<(const DrawEdge &p_edge) const {
+ if (a == p_edge.a)
+ return b < p_edge.b;
+ else
+ return a < p_edge.a;
+ }
+
+ DrawEdge(const Vector3 &p_a = Vector3(), const Vector3 &p_b = Vector3()) {
+ a = p_a;
+ b = p_b;
+ if (a < b) {
+ SWAP(a, b);
+ }
+ }
+ };
+
+protected:
+ static void _bind_methods();
+
+ virtual void _update_shape();
+
+public:
+ void set_faces(const Vector<Vector3> &p_faces);
+ Vector<Vector3> get_faces() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ ConcavePolygonShape3D();
+};
+
+#endif // CONCAVE_POLYGON_SHAPE_H
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
deleted file mode 100644
index b7463605b4..0000000000
--- a/scene/resources/convex_polygon_shape.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************************************/
-/* convex_polygon_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "convex_polygon_shape.h"
-#include "core/math/quick_hull.h"
-#include "servers/physics_server.h"
-
-Vector<Vector3> ConvexPolygonShape::get_debug_mesh_lines() {
-
- Vector<Vector3> points = get_points();
-
- if (points.size() > 3) {
-
- Vector<Vector3> varr = Variant(points);
- Geometry::MeshData md;
- Error err = QuickHull::build(varr, md);
- if (err == OK) {
- Vector<Vector3> lines;
- lines.resize(md.edges.size() * 2);
- for (int i = 0; i < md.edges.size(); i++) {
- lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
- lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
- }
- return lines;
- }
- }
-
- return Vector<Vector3>();
-}
-
-real_t ConvexPolygonShape::get_enclosing_radius() const {
- Vector<Vector3> data = get_points();
- const Vector3 *read = data.ptr();
- real_t r = 0;
- for (int i(0); i < data.size(); i++) {
- r = MAX(read[i].length_squared(), r);
- }
- return Math::sqrt(r);
-}
-
-void ConvexPolygonShape::_update_shape() {
-
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), points);
- Shape::_update_shape();
-}
-
-void ConvexPolygonShape::set_points(const Vector<Vector3> &p_points) {
-
- points = p_points;
- _update_shape();
- notify_change_to_owners();
-}
-
-Vector<Vector3> ConvexPolygonShape::get_points() const {
-
- return points;
-}
-
-void ConvexPolygonShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_points", "points"), &ConvexPolygonShape::set_points);
- ClassDB::bind_method(D_METHOD("get_points"), &ConvexPolygonShape::get_points);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "points"), "set_points", "get_points");
-}
-
-ConvexPolygonShape::ConvexPolygonShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON)) {
-}
diff --git a/scene/resources/convex_polygon_shape.h b/scene/resources/convex_polygon_shape.h
deleted file mode 100644
index fcd733887e..0000000000
--- a/scene/resources/convex_polygon_shape.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*************************************************************************/
-/* convex_polygon_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CONVEX_POLYGON_SHAPE_H
-#define CONVEX_POLYGON_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class ConvexPolygonShape : public Shape {
-
- GDCLASS(ConvexPolygonShape, Shape);
- Vector<Vector3> points;
-
-protected:
- static void _bind_methods();
-
- virtual void _update_shape();
-
-public:
- void set_points(const Vector<Vector3> &p_points);
- Vector<Vector3> get_points() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- ConvexPolygonShape();
-};
-
-#endif // CONVEX_POLYGON_SHAPE_H
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 95967429c9..6b1ddec507 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -31,8 +31,8 @@
#include "convex_polygon_shape_2d.h"
#include "core/math/geometry.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
@@ -45,7 +45,7 @@ void ConvexPolygonShape2D::_update_shape() {
if (Geometry::is_polygon_clockwise(final_points)) { //needs to be counter clockwise
final_points.invert();
}
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), final_points);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), final_points);
emit_changed();
}
@@ -81,7 +81,7 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector<Color> col;
col.push_back(p_color);
- VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+ RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
}
Rect2 ConvexPolygonShape2D::get_rect() const {
@@ -106,5 +106,5 @@ real_t ConvexPolygonShape2D::get_enclosing_radius() const {
}
ConvexPolygonShape2D::ConvexPolygonShape2D() :
- Shape2D(Physics2DServer::get_singleton()->convex_polygon_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->convex_polygon_shape_create()) {
}
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
new file mode 100644
index 0000000000..ec9ab68015
--- /dev/null
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* convex_polygon_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "convex_polygon_shape_3d.h"
+#include "core/math/quick_hull.h"
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() {
+
+ Vector<Vector3> points = get_points();
+
+ if (points.size() > 3) {
+
+ Vector<Vector3> varr = Variant(points);
+ Geometry::MeshData md;
+ Error err = QuickHull::build(varr, md);
+ if (err == OK) {
+ Vector<Vector3> lines;
+ lines.resize(md.edges.size() * 2);
+ for (int i = 0; i < md.edges.size(); i++) {
+ lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
+ lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
+ }
+ return lines;
+ }
+ }
+
+ return Vector<Vector3>();
+}
+
+real_t ConvexPolygonShape3D::get_enclosing_radius() const {
+ Vector<Vector3> data = get_points();
+ const Vector3 *read = data.ptr();
+ real_t r = 0;
+ for (int i(0); i < data.size(); i++) {
+ r = MAX(read[i].length_squared(), r);
+ }
+ return Math::sqrt(r);
+}
+
+void ConvexPolygonShape3D::_update_shape() {
+
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), points);
+ Shape3D::_update_shape();
+}
+
+void ConvexPolygonShape3D::set_points(const Vector<Vector3> &p_points) {
+
+ points = p_points;
+ _update_shape();
+ notify_change_to_owners();
+}
+
+Vector<Vector3> ConvexPolygonShape3D::get_points() const {
+
+ return points;
+}
+
+void ConvexPolygonShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_points", "points"), &ConvexPolygonShape3D::set_points);
+ ClassDB::bind_method(D_METHOD("get_points"), &ConvexPolygonShape3D::get_points);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "points"), "set_points", "get_points");
+}
+
+ConvexPolygonShape3D::ConvexPolygonShape3D() :
+ Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON)) {
+}
diff --git a/scene/resources/convex_polygon_shape_3d.h b/scene/resources/convex_polygon_shape_3d.h
new file mode 100644
index 0000000000..51e4c8eb0b
--- /dev/null
+++ b/scene/resources/convex_polygon_shape_3d.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* convex_polygon_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CONVEX_POLYGON_SHAPE_H
+#define CONVEX_POLYGON_SHAPE_H
+
+#include "scene/resources/shape_3d.h"
+
+class ConvexPolygonShape3D : public Shape3D {
+
+ GDCLASS(ConvexPolygonShape3D, Shape3D);
+ Vector<Vector3> points;
+
+protected:
+ static void _bind_methods();
+
+ virtual void _update_shape();
+
+public:
+ void set_points(const Vector<Vector3> &p_points);
+ Vector<Vector3> get_points() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ ConvexPolygonShape3D();
+};
+
+#endif // CONVEX_POLYGON_SHAPE_H
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index a68eb77378..d19eae0d4f 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -941,7 +941,7 @@ PackedVector2Array Curve2D::tessellate(int p_max_stages, float p_tolerance) cons
if (points.size() == 0) {
return tess;
}
- Vector<Map<float, Vector2> > midpoints;
+ Vector<Map<float, Vector2>> midpoints;
midpoints.resize(points.size() - 1);
@@ -1615,7 +1615,7 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, float p_tolerance) cons
if (points.size() == 0) {
return tess;
}
- Vector<Map<float, Vector3> > midpoints;
+ Vector<Map<float, Vector3>> midpoints;
midpoints.resize(points.size() - 1);
diff --git a/scene/resources/cylinder_shape.cpp b/scene/resources/cylinder_shape.cpp
deleted file mode 100644
index 53d368d32a..0000000000
--- a/scene/resources/cylinder_shape.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*************************************************************************/
-/* cylinder_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "cylinder_shape.h"
-#include "servers/physics_server.h"
-
-Vector<Vector3> CylinderShape::get_debug_mesh_lines() {
-
- float radius = get_radius();
- float height = get_height();
-
- Vector<Vector3> points;
-
- Vector3 d(0, height * 0.5, 0);
- for (int i = 0; i < 360; i++) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(b.x, 0, b.y) + d);
-
- points.push_back(Vector3(a.x, 0, a.y) - d);
- points.push_back(Vector3(b.x, 0, b.y) - d);
-
- if (i % 90 == 0) {
-
- points.push_back(Vector3(a.x, 0, a.y) + d);
- points.push_back(Vector3(a.x, 0, a.y) - d);
- }
- }
-
- return points;
-}
-
-real_t CylinderShape::get_enclosing_radius() const {
- return Vector2(radius, height * 0.5).length();
-}
-
-void CylinderShape::_update_shape() {
-
- Dictionary d;
- d["radius"] = radius;
- d["height"] = height;
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
- Shape::_update_shape();
-}
-
-void CylinderShape::set_radius(float p_radius) {
-
- radius = p_radius;
- _update_shape();
- notify_change_to_owners();
- _change_notify("radius");
-}
-
-float CylinderShape::get_radius() const {
-
- return radius;
-}
-
-void CylinderShape::set_height(float p_height) {
-
- height = p_height;
- _update_shape();
- notify_change_to_owners();
- _change_notify("height");
-}
-
-float CylinderShape::get_height() const {
-
- return height;
-}
-
-void CylinderShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape::get_radius);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape::set_height);
- ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape::get_height);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height");
-}
-
-CylinderShape::CylinderShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CYLINDER)) {
-
- radius = 1.0;
- height = 2.0;
- _update_shape();
-}
diff --git a/scene/resources/cylinder_shape.h b/scene/resources/cylinder_shape.h
deleted file mode 100644
index a26fda10cd..0000000000
--- a/scene/resources/cylinder_shape.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*************************************************************************/
-/* cylinder_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CYLINDER_SHAPE_H
-#define CYLINDER_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class CylinderShape : public Shape {
-
- GDCLASS(CylinderShape, Shape);
- float radius;
- float height;
-
-protected:
- static void _bind_methods();
- virtual void _update_shape();
-
-public:
- void set_radius(float p_radius);
- float get_radius() const;
- void set_height(float p_height);
- float get_height() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- CylinderShape();
-};
-
-#endif // CYLINDER_SHAPE_H
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
new file mode 100644
index 0000000000..19f0542818
--- /dev/null
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -0,0 +1,121 @@
+/*************************************************************************/
+/* cylinder_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "cylinder_shape_3d.h"
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() {
+
+ float radius = get_radius();
+ float height = get_height();
+
+ Vector<Vector3> points;
+
+ Vector3 d(0, height * 0.5, 0);
+ for (int i = 0; i < 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(b.x, 0, b.y) + d);
+
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ points.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 90 == 0) {
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+ }
+
+ return points;
+}
+
+real_t CylinderShape3D::get_enclosing_radius() const {
+ return Vector2(radius, height * 0.5).length();
+}
+
+void CylinderShape3D::_update_shape() {
+
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+ Shape3D::_update_shape();
+}
+
+void CylinderShape3D::set_radius(float p_radius) {
+
+ radius = p_radius;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("radius");
+}
+
+float CylinderShape3D::get_radius() const {
+
+ return radius;
+}
+
+void CylinderShape3D::set_height(float p_height) {
+
+ height = p_height;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("height");
+}
+
+float CylinderShape3D::get_height() const {
+
+ return height;
+}
+
+void CylinderShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape3D::get_radius);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape3D::set_height);
+ ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape3D::get_height);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height");
+}
+
+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
new file mode 100644
index 0000000000..7b37f733e0
--- /dev/null
+++ b/scene/resources/cylinder_shape_3d.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* cylinder_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CYLINDER_SHAPE_3D_H
+#define CYLINDER_SHAPE_3D_H
+
+#include "scene/resources/shape_3d.h"
+
+class CylinderShape3D : public Shape3D {
+
+ GDCLASS(CylinderShape3D, Shape3D);
+ float radius;
+ float height;
+
+protected:
+ static void _bind_methods();
+ virtual void _update_shape();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+ void set_height(float p_height);
+ float get_height() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ CylinderShape3D();
+};
+
+#endif // CYLINDER_SHAPE_H
diff --git a/scene/resources/default_theme/SCsub b/scene/resources/default_theme/SCsub
index b01e2fd54d..fc61250247 100644
--- a/scene/resources/default_theme/SCsub
+++ b/scene/resources/default_theme/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 04bc95ade6..a1e8bf51bd 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -38,7 +38,7 @@
#include "font_hidpi.inc"
#include "font_lodpi.inc"
-typedef Map<const void *, Ref<ImageTexture> > TexCacheMap;
+typedef Map<const void *, Ref<ImageTexture>> TexCacheMap;
static TexCacheMap *tex_cache;
static float scale = 1;
@@ -188,6 +188,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Panel
theme->set_stylebox("panel", "Panel", make_stylebox(panel_bg_png, 0, 0, 0, 0));
+ theme->set_stylebox("panel_fg", "Panel", make_stylebox(panel_bg_png, 0, 0, 0, 0));
// Focus
@@ -496,6 +497,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("slider", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4));
theme->set_stylebox("grabber_area", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4));
+ theme->set_stylebox("grabber_area_highlight", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4));
theme->set_icon("grabber", "HSlider", make_icon(hslider_grabber_png));
theme->set_icon("grabber_highlight", "HSlider", make_icon(hslider_grabber_hl_png));
@@ -506,6 +508,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("slider", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4));
theme->set_stylebox("grabber_area", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4));
+ theme->set_stylebox("grabber_area_highlight", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4));
theme->set_icon("grabber", "VSlider", make_icon(vslider_grabber_png));
theme->set_icon("grabber_highlight", "VSlider", make_icon(vslider_grabber_hl_png));
@@ -523,17 +526,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// WindowDialog
- theme->set_stylebox("panel", "WindowDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
- theme->set_constant("scaleborder_size", "WindowDialog", 4 * scale);
+ theme->set_stylebox("panel", "Window", default_style);
+ theme->set_stylebox("window_panel", "Window", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
+ theme->set_constant("scaleborder_size", "Window", 4 * scale);
- theme->set_font("title_font", "WindowDialog", large_font);
- theme->set_color("title_color", "WindowDialog", Color(0, 0, 0));
- theme->set_constant("title_height", "WindowDialog", 20 * scale);
+ theme->set_font("title_font", "Window", large_font);
+ theme->set_color("title_color", "Window", Color(0, 0, 0));
+ theme->set_constant("title_height", "Window", 20 * scale);
+ theme->set_constant("resize_margin", "Window", 4 * scale);
- theme->set_icon("close", "WindowDialog", make_icon(close_png));
- theme->set_icon("close_highlight", "WindowDialog", make_icon(close_hl_png));
- theme->set_constant("close_h_ofs", "WindowDialog", 18 * scale);
- theme->set_constant("close_v_ofs", "WindowDialog", 18 * scale);
+ theme->set_icon("close", "Window", make_icon(close_png));
+ theme->set_icon("close_highlight", "Window", make_icon(close_hl_png));
+ theme->set_constant("close_h_ofs", "Window", 18 * scale);
+ theme->set_constant("close_v_ofs", "Window", 18 * scale);
// File Dialog
@@ -887,9 +892,9 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
void clear_default_theme() {
- Theme::set_project_default(NULL);
- Theme::set_default(NULL);
- Theme::set_default_icon(NULL);
- Theme::set_default_style(NULL);
- Theme::set_default_font(NULL);
+ Theme::set_project_default(nullptr);
+ Theme::set_default(nullptr);
+ Theme::set_default_icon(nullptr);
+ Theme::set_default_style(nullptr);
+ Theme::set_default_font(nullptr);
}
diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py
index cf0ccf1c3a..efad3b2815 100755
--- a/scene/resources/default_theme/make_header.py
+++ b/scene/resources/default_theme/make_header.py
@@ -13,7 +13,7 @@ os.chdir(os.path.dirname(os.path.realpath(__file__)))
f = open("theme_data.h", "wb")
-f.write(b"// THIS FILE HAS BEEN AUTOGENERATED, DON\'T EDIT!!\n")
+f.write(b"// THIS FILE HAS BEEN AUTOGENERATED, DON'T EDIT!!\n")
# Generate png image block
f.write(b"\n// png image block\n")
@@ -31,17 +31,17 @@ for x in pixmaps:
pngf = open(x, "rb")
b = pngf.read(1)
- while(len(b) == 1):
+ while len(b) == 1:
f.write(hex(ord(b)).encode(enc))
b = pngf.read(1)
- if (len(b) == 1):
+ if len(b) == 1:
f.write(b", ")
f.write(b"\n};\n")
pngf.close()
# Generate shaders block
-f.write(b"\n// shaders block\n");
+f.write(b"\n// shaders block\n")
shaders = glob.glob("*.gsl")
shaders.sort()
@@ -56,15 +56,15 @@ for x in shaders:
sf = open(x, "rb")
b = sf.readline()
- while(b != ""):
- if (b.endswith("\r\n")):
+ while b != "":
+ if b.endswith("\r\n"):
b = b[:-2]
- if (b.endswith("\n")):
+ if b.endswith("\n"):
b = b[:-1]
- s = ' \"' + b
+ s = ' "' + b
f.write(s.encode(enc))
b = sf.readline()
- if (b != ""):
+ if b != "":
f.write(b'"\n')
f.write(b'";\n')
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index ebd5b02dbc..a613b01376 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -107,7 +107,7 @@ DynamicFontData::DynamicFontData() {
antialiased = true;
force_autohinter = false;
hinting = DynamicFontData::HINTING_NORMAL;
- font_mem = NULL;
+ font_mem = nullptr;
font_mem_size = 0;
}
@@ -115,7 +115,7 @@ DynamicFontData::~DynamicFontData() {
}
////////////////////
-HashMap<String, Vector<uint8_t> > DynamicFontAtSize::_fontdata;
+HashMap<String, Vector<uint8_t>> DynamicFontAtSize::_fontdata;
Error DynamicFontAtSize::_load() {
@@ -124,7 +124,7 @@ Error DynamicFontAtSize::_load() {
ERR_FAIL_COND_V_MSG(error != 0, ERR_CANT_CREATE, "Error initializing FreeType.");
// FT_OPEN_STREAM is extremely slow only on Android.
- if (OS::get_singleton()->get_name() == "Android" && font->font_mem == NULL && font->font_path != String()) {
+ if (OS::get_singleton()->get_name() == "Android" && font->font_mem == nullptr && font->font_path != String()) {
// cache font only once for each font->font_path
if (_fontdata.has(font->font_path)) {
@@ -148,7 +148,7 @@ Error DynamicFontAtSize::_load() {
}
}
- if (font->font_mem == NULL && font->font_path != String()) {
+ if (font->font_mem == nullptr && font->font_path != String()) {
FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ);
if (!f) {
@@ -157,7 +157,7 @@ Error DynamicFontAtSize::_load() {
}
memset(&stream, 0, sizeof(FT_StreamRec));
- stream.base = NULL;
+ stream.base = nullptr;
stream.size = f->get_len();
stream.pos = 0;
stream.descriptor.pointer = f;
@@ -243,9 +243,9 @@ float DynamicFontAtSize::get_descent() const {
return descent;
}
-const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
+const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const {
const Character *chr = char_map.getptr(p_char);
- ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(NULL, NULL)));
+ ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(nullptr, nullptr)));
if (!chr->found) {
@@ -269,13 +269,13 @@ const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFon
//not found, try 0xFFFD to display 'not found'.
const_cast<DynamicFontAtSize *>(this)->_update_char(0xFFFD);
chr = char_map.getptr(0xFFFD);
- ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(NULL, NULL)));
+ ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(nullptr, nullptr)));
}
return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this));
}
-Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
+Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const {
if (!valid)
return Size2(1, 1);
@@ -294,7 +294,7 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V
return ret;
}
-float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only, bool p_outline) const {
+float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const {
if (!valid)
return 0;
@@ -336,7 +336,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
modulate.r = modulate.g = modulate.b = 1.0;
}
RID texture = font->textures[ch->texture_idx].texture->get_rid();
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, RID(), RID(), Color(1, 1, 1, 1), false);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, RID(), RID(), Color(1, 1, 1, 1), false);
}
advance = ch->advance;
@@ -565,7 +565,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_ch
goto cleanup_stroker;
if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0)
goto cleanup_glyph;
- if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1) != 0)
+ if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, 1) != 0)
goto cleanup_glyph;
glyph_bitmap = (FT_BitmapGlyph)glyph;
@@ -850,7 +850,7 @@ float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_
if (!font_at_size.is_valid())
return 0;
- const Vector<Ref<DynamicFontAtSize> > &fallbacks = p_outline && outline_cache_id.outline_size > 0 ? fallback_outline_data_at_size : fallback_data_at_size;
+ const Vector<Ref<DynamicFontAtSize>> &fallbacks = p_outline && outline_cache_id.outline_size > 0 ? fallback_outline_data_at_size : fallback_data_at_size;
Color color = p_outline && outline_cache_id.outline_size > 0 ? p_modulate * outline_color : p_modulate;
// If requested outline draw, but no outline is present, simply return advance without drawing anything
@@ -992,11 +992,12 @@ void DynamicFont::_bind_methods() {
Mutex DynamicFont::dynamic_font_mutex;
-SelfList<DynamicFont>::List *DynamicFont::dynamic_fonts = NULL;
+SelfList<DynamicFont>::List *DynamicFont::dynamic_fonts = nullptr;
DynamicFont::DynamicFont() :
font_list(this) {
+ valid = false;
cache_id.size = 16;
outline_cache_id.size = 16;
spacing_top = 0;
@@ -1020,12 +1021,12 @@ void DynamicFont::initialize_dynamic_fonts() {
void DynamicFont::finish_dynamic_fonts() {
memdelete(dynamic_fonts);
- dynamic_fonts = NULL;
+ dynamic_fonts = nullptr;
}
void DynamicFont::update_oversampling() {
- Vector<Ref<DynamicFont> > changed;
+ Vector<Ref<DynamicFont>> changed;
{
MutexLock lock(dynamic_font_mutex);
diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h
index c10f1e6681..9e628fc35a 100644
--- a/scene/resources/dynamic_font.h
+++ b/scene/resources/dynamic_font.h
@@ -161,7 +161,7 @@ class DynamicFontAtSize : public Reference {
int y;
};
- const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const;
+ const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
Character _make_outline_char(CharType p_char);
TexturePosition _find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height);
Character _bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance);
@@ -177,7 +177,7 @@ class DynamicFontAtSize : public Reference {
Ref<DynamicFontData> font;
DynamicFontData::CacheID id;
- static HashMap<String, Vector<uint8_t> > _fontdata;
+ static HashMap<String, Vector<uint8_t>> _fontdata;
Error _load();
public:
@@ -188,9 +188,9 @@ public:
float get_ascent() const;
float get_descent() const;
- Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const;
+ Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const;
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const;
void set_texture_flags(uint32_t p_flags);
void update_oversampling();
@@ -218,9 +218,9 @@ private:
Ref<DynamicFontAtSize> data_at_size;
Ref<DynamicFontAtSize> outline_data_at_size;
- Vector<Ref<DynamicFontData> > fallbacks;
- Vector<Ref<DynamicFontAtSize> > fallback_data_at_size;
- Vector<Ref<DynamicFontAtSize> > fallback_outline_data_at_size;
+ Vector<Ref<DynamicFontData>> fallbacks;
+ Vector<Ref<DynamicFontAtSize>> fallback_data_at_size;
+ Vector<Ref<DynamicFontAtSize>> fallback_outline_data_at_size;
DynamicFontData::CacheID cache_id;
DynamicFontData::CacheID outline_cache_id;
@@ -302,7 +302,7 @@ VARIANT_ENUM_CAST(DynamicFont::SpacingType);
class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/environment.cpp b/scene/resources/environment.cpp
index d407dd3722..835fef81e1 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -30,7 +30,7 @@
#include "environment.h"
#include "core/project_settings.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
#include "texture.h"
RID Environment::get_rid() const {
@@ -41,7 +41,7 @@ RID Environment::get_rid() const {
void Environment::set_background(BGMode p_bg) {
bg_mode = p_bg;
- VS::get_singleton()->environment_set_background(environment, VS::EnvironmentBG(p_bg));
+ RS::get_singleton()->environment_set_background(environment, RS::EnvironmentBG(p_bg));
_change_notify();
}
@@ -53,56 +53,56 @@ void Environment::set_sky(const Ref<Sky> &p_sky) {
if (bg_sky.is_valid())
sb_rid = bg_sky->get_rid();
- VS::get_singleton()->environment_set_sky(environment, sb_rid);
+ RS::get_singleton()->environment_set_sky(environment, sb_rid);
}
void Environment::set_sky_custom_fov(float p_scale) {
bg_sky_custom_fov = p_scale;
- VS::get_singleton()->environment_set_sky_custom_fov(environment, p_scale);
+ RS::get_singleton()->environment_set_sky_custom_fov(environment, p_scale);
}
void Environment::set_bg_color(const Color &p_color) {
bg_color = p_color;
- VS::get_singleton()->environment_set_bg_color(environment, p_color);
+ RS::get_singleton()->environment_set_bg_color(environment, p_color);
}
void Environment::set_bg_energy(float p_energy) {
bg_energy = p_energy;
- VS::get_singleton()->environment_set_bg_energy(environment, p_energy);
+ RS::get_singleton()->environment_set_bg_energy(environment, p_energy);
}
void Environment::set_canvas_max_layer(int p_max_layer) {
bg_canvas_max_layer = p_max_layer;
- VS::get_singleton()->environment_set_canvas_max_layer(environment, p_max_layer);
+ RS::get_singleton()->environment_set_canvas_max_layer(environment, p_max_layer);
}
void Environment::set_ambient_light_color(const Color &p_color) {
ambient_color = p_color;
- VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, VS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, VS::EnvironmentReflectionSource(reflection_source), ao_color);
+ RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color);
}
void Environment::set_ambient_light_energy(float p_energy) {
ambient_energy = p_energy;
- VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, VS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, VS::EnvironmentReflectionSource(reflection_source), ao_color);
+ RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color);
}
void Environment::set_ambient_light_sky_contribution(float p_energy) {
ambient_sky_contribution = p_energy;
- VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, VS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, VS::EnvironmentReflectionSource(reflection_source), ao_color);
+ RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color);
}
void Environment::set_camera_feed_id(int p_camera_feed_id) {
camera_feed_id = p_camera_feed_id;
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
- VS::get_singleton()->environment_set_camera_feed_id(environment, camera_feed_id);
+ RS::get_singleton()->environment_set_camera_feed_id(environment, camera_feed_id);
#endif
};
void Environment::set_ambient_source(AmbientSource p_source) {
ambient_source = p_source;
- VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, VS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, VS::EnvironmentReflectionSource(reflection_source), ao_color);
+ RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color);
}
Environment::AmbientSource Environment::get_ambient_source() const {
@@ -110,7 +110,7 @@ Environment::AmbientSource Environment::get_ambient_source() const {
}
void Environment::set_reflection_source(ReflectionSource p_source) {
reflection_source = p_source;
- VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, VS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, VS::EnvironmentReflectionSource(reflection_source), ao_color);
+ RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color);
}
Environment::ReflectionSource Environment::get_reflection_source() const {
return reflection_source;
@@ -132,7 +132,7 @@ float Environment::get_sky_custom_fov() const {
void Environment::set_sky_rotation(const Vector3 &p_rotation) {
sky_rotation = p_rotation;
- VS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation));
+ RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation));
}
Vector3 Environment::get_sky_rotation() const {
@@ -172,7 +172,7 @@ int Environment::get_camera_feed_id(void) const {
void Environment::set_tonemapper(ToneMapper p_tone_mapper) {
tone_mapper = p_tone_mapper;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
Environment::ToneMapper Environment::get_tonemapper() const {
@@ -183,7 +183,7 @@ Environment::ToneMapper Environment::get_tonemapper() const {
void Environment::set_tonemap_exposure(float p_exposure) {
tonemap_exposure = p_exposure;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
float Environment::get_tonemap_exposure() const {
@@ -194,7 +194,7 @@ float Environment::get_tonemap_exposure() const {
void Environment::set_tonemap_white(float p_white) {
tonemap_white = p_white;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
float Environment::get_tonemap_white() const {
@@ -204,7 +204,7 @@ float Environment::get_tonemap_white() const {
void Environment::set_tonemap_auto_exposure(bool p_enabled) {
tonemap_auto_exposure = p_enabled;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
_change_notify();
}
bool Environment::get_tonemap_auto_exposure() const {
@@ -215,7 +215,7 @@ bool Environment::get_tonemap_auto_exposure() const {
void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) {
tonemap_auto_exposure_max = p_auto_exposure_max;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
float Environment::get_tonemap_auto_exposure_max() const {
@@ -225,7 +225,7 @@ float Environment::get_tonemap_auto_exposure_max() const {
void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) {
tonemap_auto_exposure_min = p_auto_exposure_min;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
float Environment::get_tonemap_auto_exposure_min() const {
@@ -235,7 +235,7 @@ float Environment::get_tonemap_auto_exposure_min() const {
void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) {
tonemap_auto_exposure_speed = p_auto_exposure_speed;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
float Environment::get_tonemap_auto_exposure_speed() const {
@@ -245,7 +245,7 @@ float Environment::get_tonemap_auto_exposure_speed() const {
void Environment::set_tonemap_auto_exposure_grey(float p_auto_exposure_grey) {
tonemap_auto_exposure_grey = p_auto_exposure_grey;
- VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
+ RS::get_singleton()->environment_set_tonemap(environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey);
}
float Environment::get_tonemap_auto_exposure_grey() const {
@@ -255,7 +255,7 @@ float Environment::get_tonemap_auto_exposure_grey() const {
void Environment::set_adjustment_enable(bool p_enable) {
adjustment_enabled = p_enable;
- VS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
+ RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
_change_notify();
}
@@ -267,7 +267,7 @@ bool Environment::is_adjustment_enabled() const {
void Environment::set_adjustment_brightness(float p_brightness) {
adjustment_brightness = p_brightness;
- VS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
+ RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
}
float Environment::get_adjustment_brightness() const {
@@ -277,7 +277,7 @@ float Environment::get_adjustment_brightness() const {
void Environment::set_adjustment_contrast(float p_contrast) {
adjustment_contrast = p_contrast;
- VS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
+ RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
}
float Environment::get_adjustment_contrast() const {
@@ -287,7 +287,7 @@ float Environment::get_adjustment_contrast() const {
void Environment::set_adjustment_saturation(float p_saturation) {
adjustment_saturation = p_saturation;
- VS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
+ RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
}
float Environment::get_adjustment_saturation() const {
@@ -297,7 +297,7 @@ float Environment::get_adjustment_saturation() const {
void Environment::set_adjustment_color_correction(const Ref<Texture2D> &p_ramp) {
adjustment_color_correction = p_ramp;
- VS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
+ RS::get_singleton()->environment_set_adjustment(environment, adjustment_enabled, adjustment_brightness, adjustment_contrast, adjustment_saturation, adjustment_color_correction.is_valid() ? adjustment_color_correction->get_rid() : RID());
}
Ref<Texture2D> Environment::get_adjustment_color_correction() const {
@@ -345,7 +345,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
"ssao_",
"glow_",
"adjustment_",
- NULL
+ nullptr
};
@@ -354,7 +354,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
"tonemap_",
"ss_reflections_",
"ssao_",
- NULL
+ nullptr
};
@@ -371,7 +371,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
prefixes++;
}
- if (VisualServer::get_singleton()->is_low_end()) {
+ if (RenderingServer::get_singleton()->is_low_end()) {
prefixes = high_end_prefixes;
while (*prefixes) {
String prefix = String(*prefixes);
@@ -389,7 +389,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
void Environment::set_ssr_enabled(bool p_enable) {
ssr_enabled = p_enable;
- VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness);
+ RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance);
_change_notify();
}
@@ -401,7 +401,7 @@ bool Environment::is_ssr_enabled() const {
void Environment::set_ssr_max_steps(int p_steps) {
ssr_max_steps = p_steps;
- VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness);
+ RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance);
}
int Environment::get_ssr_max_steps() const {
@@ -411,7 +411,7 @@ int Environment::get_ssr_max_steps() const {
void Environment::set_ssr_fade_in(float p_fade_in) {
ssr_fade_in = p_fade_in;
- VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness);
+ RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance);
}
float Environment::get_ssr_fade_in() const {
@@ -421,7 +421,7 @@ float Environment::get_ssr_fade_in() const {
void Environment::set_ssr_fade_out(float p_fade_out) {
ssr_fade_out = p_fade_out;
- VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness);
+ RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance);
}
float Environment::get_ssr_fade_out() const {
@@ -431,27 +431,17 @@ float Environment::get_ssr_fade_out() const {
void Environment::set_ssr_depth_tolerance(float p_depth_tolerance) {
ssr_depth_tolerance = p_depth_tolerance;
- VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness);
+ RS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance);
}
float Environment::get_ssr_depth_tolerance() const {
return ssr_depth_tolerance;
}
-void Environment::set_ssr_rough(bool p_enable) {
-
- ssr_roughness = p_enable;
- VS::get_singleton()->environment_set_ssr(environment, ssr_enabled, ssr_max_steps, ssr_fade_in, ssr_fade_out, ssr_depth_tolerance, ssr_roughness);
-}
-bool Environment::is_ssr_rough() const {
-
- return ssr_roughness;
-}
-
void Environment::set_ssao_enabled(bool p_enable) {
ssao_enabled = p_enable;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
_change_notify();
}
@@ -463,7 +453,7 @@ bool Environment::is_ssao_enabled() const {
void Environment::set_ssao_radius(float p_radius) {
ssao_radius = p_radius;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_radius() const {
@@ -473,7 +463,7 @@ float Environment::get_ssao_radius() const {
void Environment::set_ssao_intensity(float p_intensity) {
ssao_intensity = p_intensity;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_intensity() const {
@@ -484,7 +474,7 @@ float Environment::get_ssao_intensity() const {
void Environment::set_ssao_bias(float p_bias) {
ssao_bias = p_bias;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_bias() const {
@@ -494,7 +484,7 @@ float Environment::get_ssao_bias() const {
void Environment::set_ssao_direct_light_affect(float p_direct_light_affect) {
ssao_direct_light_affect = p_direct_light_affect;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_direct_light_affect() const {
@@ -504,7 +494,7 @@ float Environment::get_ssao_direct_light_affect() const {
void Environment::set_ssao_ao_channel_affect(float p_ao_channel_affect) {
ssao_ao_channel_affect = p_ao_channel_affect;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_ao_channel_affect() const {
@@ -514,7 +504,7 @@ float Environment::get_ssao_ao_channel_affect() const {
void Environment::set_ao_color(const Color &p_color) {
ao_color = p_color;
- VS::get_singleton()->environment_set_ambient_light(environment, ambient_color, VS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, VS::EnvironmentReflectionSource(reflection_source), ao_color);
+ RS::get_singleton()->environment_set_ambient_light(environment, ambient_color, RS::EnvironmentAmbientSource(ambient_source), ambient_energy, ambient_sky_contribution, RS::EnvironmentReflectionSource(reflection_source), ao_color);
}
Color Environment::get_ao_color() const {
@@ -525,7 +515,7 @@ Color Environment::get_ao_color() const {
void Environment::set_ssao_blur(SSAOBlur p_blur) {
ssao_blur = p_blur;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
Environment::SSAOBlur Environment::get_ssao_blur() const {
@@ -535,7 +525,7 @@ Environment::SSAOBlur Environment::get_ssao_blur() const {
void Environment::set_ssao_edge_sharpness(float p_edge_sharpness) {
ssao_edge_sharpness = p_edge_sharpness;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ RS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, RS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_edge_sharpness() const {
@@ -546,7 +536,7 @@ float Environment::get_ssao_edge_sharpness() const {
void Environment::set_glow_enabled(bool p_enabled) {
glow_enabled = p_enabled;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
_change_notify();
}
@@ -557,18 +547,18 @@ bool Environment::is_glow_enabled() const {
void Environment::set_glow_level(int p_level, bool p_enabled) {
- ERR_FAIL_INDEX(p_level, VS::MAX_GLOW_LEVELS);
+ ERR_FAIL_INDEX(p_level, RS::MAX_GLOW_LEVELS);
if (p_enabled)
glow_levels |= (1 << p_level);
else
glow_levels &= ~(1 << p_level);
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
bool Environment::is_glow_level_enabled(int p_level) const {
- ERR_FAIL_INDEX_V(p_level, VS::MAX_GLOW_LEVELS, false);
+ ERR_FAIL_INDEX_V(p_level, RS::MAX_GLOW_LEVELS, false);
return glow_levels & (1 << p_level);
}
@@ -577,7 +567,7 @@ void Environment::set_glow_intensity(float p_intensity) {
glow_intensity = p_intensity;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_intensity() const {
@@ -587,7 +577,7 @@ float Environment::get_glow_intensity() const {
void Environment::set_glow_strength(float p_strength) {
glow_strength = p_strength;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_strength() const {
@@ -597,7 +587,7 @@ float Environment::get_glow_strength() const {
void Environment::set_glow_mix(float p_mix) {
glow_mix = p_mix;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_mix() const {
@@ -608,7 +598,7 @@ void Environment::set_glow_bloom(float p_threshold) {
glow_bloom = p_threshold;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_bloom() const {
@@ -619,7 +609,7 @@ void Environment::set_glow_blend_mode(GlowBlendMode p_mode) {
glow_blend_mode = p_mode;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
_change_notify();
}
Environment::GlowBlendMode Environment::get_glow_blend_mode() const {
@@ -631,7 +621,7 @@ void Environment::set_glow_hdr_bleed_threshold(float p_threshold) {
glow_hdr_bleed_threshold = p_threshold;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_hdr_bleed_threshold() const {
@@ -642,7 +632,7 @@ void Environment::set_glow_hdr_luminance_cap(float p_amount) {
glow_hdr_luminance_cap = p_amount;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_hdr_luminance_cap() const {
@@ -653,28 +643,17 @@ void Environment::set_glow_hdr_bleed_scale(float p_scale) {
glow_hdr_bleed_scale = p_scale;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
+ RS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap);
}
float Environment::get_glow_hdr_bleed_scale() const {
return glow_hdr_bleed_scale;
}
-void Environment::set_glow_bicubic_upscale(bool p_enable) {
-
- glow_bicubic_upscale = p_enable;
- VS::get_singleton()->environment_set_glow(environment, glow_enabled, glow_levels, glow_intensity, glow_strength, glow_mix, glow_bloom, VS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_threshold, glow_hdr_luminance_cap, glow_bicubic_upscale);
-}
-
-bool Environment::is_glow_bicubic_upscale_enabled() const {
-
- return glow_bicubic_upscale;
-}
-
void Environment::set_fog_enabled(bool p_enabled) {
fog_enabled = p_enabled;
- VS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
+ RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
_change_notify();
}
@@ -686,7 +665,7 @@ bool Environment::is_fog_enabled() const {
void Environment::set_fog_color(const Color &p_color) {
fog_color = p_color;
- VS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
+ RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
}
Color Environment::get_fog_color() const {
@@ -696,7 +675,7 @@ Color Environment::get_fog_color() const {
void Environment::set_fog_sun_color(const Color &p_color) {
fog_sun_color = p_color;
- VS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
+ RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
}
Color Environment::get_fog_sun_color() const {
@@ -706,7 +685,7 @@ Color Environment::get_fog_sun_color() const {
void Environment::set_fog_sun_amount(float p_amount) {
fog_sun_amount = p_amount;
- VS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
+ RS::get_singleton()->environment_set_fog(environment, fog_enabled, fog_color, fog_sun_color, fog_sun_amount);
}
float Environment::get_fog_sun_amount() const {
@@ -716,7 +695,7 @@ float Environment::get_fog_sun_amount() const {
void Environment::set_fog_depth_enabled(bool p_enabled) {
fog_depth_enabled = p_enabled;
- VS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
+ RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
}
bool Environment::is_fog_depth_enabled() const {
@@ -726,7 +705,7 @@ bool Environment::is_fog_depth_enabled() const {
void Environment::set_fog_depth_begin(float p_distance) {
fog_depth_begin = p_distance;
- VS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
+ RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
}
float Environment::get_fog_depth_begin() const {
@@ -736,7 +715,7 @@ float Environment::get_fog_depth_begin() const {
void Environment::set_fog_depth_end(float p_distance) {
fog_depth_end = p_distance;
- VS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
+ RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
}
float Environment::get_fog_depth_end() const {
@@ -747,7 +726,7 @@ float Environment::get_fog_depth_end() const {
void Environment::set_fog_depth_curve(float p_curve) {
fog_depth_curve = p_curve;
- VS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
+ RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
}
float Environment::get_fog_depth_curve() const {
@@ -757,7 +736,7 @@ float Environment::get_fog_depth_curve() const {
void Environment::set_fog_transmit_enabled(bool p_enabled) {
fog_transmit_enabled = p_enabled;
- VS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
+ RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
}
bool Environment::is_fog_transmit_enabled() const {
@@ -767,7 +746,7 @@ bool Environment::is_fog_transmit_enabled() const {
void Environment::set_fog_transmit_curve(float p_curve) {
fog_transmit_curve = p_curve;
- VS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
+ RS::get_singleton()->environment_set_fog_depth(environment, fog_depth_enabled, fog_depth_begin, fog_depth_end, fog_depth_curve, fog_transmit_enabled, fog_transmit_curve);
}
float Environment::get_fog_transmit_curve() const {
@@ -777,7 +756,7 @@ float Environment::get_fog_transmit_curve() const {
void Environment::set_fog_height_enabled(bool p_enabled) {
fog_height_enabled = p_enabled;
- VS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
+ RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
}
bool Environment::is_fog_height_enabled() const {
@@ -787,7 +766,7 @@ bool Environment::is_fog_height_enabled() const {
void Environment::set_fog_height_min(float p_distance) {
fog_height_min = p_distance;
- VS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
+ RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
}
float Environment::get_fog_height_min() const {
@@ -797,7 +776,7 @@ float Environment::get_fog_height_min() const {
void Environment::set_fog_height_max(float p_distance) {
fog_height_max = p_distance;
- VS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
+ RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
}
float Environment::get_fog_height_max() const {
@@ -807,7 +786,7 @@ float Environment::get_fog_height_max() const {
void Environment::set_fog_height_curve(float p_distance) {
fog_height_curve = p_distance;
- VS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
+ RS::get_singleton()->environment_set_fog_height(environment, fog_height_enabled, fog_height_min, fog_height_max, fog_height_curve);
}
float Environment::get_fog_height_curve() const {
@@ -992,16 +971,12 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ssr_depth_tolerance", "depth_tolerance"), &Environment::set_ssr_depth_tolerance);
ClassDB::bind_method(D_METHOD("get_ssr_depth_tolerance"), &Environment::get_ssr_depth_tolerance);
- ClassDB::bind_method(D_METHOD("set_ssr_rough", "rough"), &Environment::set_ssr_rough);
- ClassDB::bind_method(D_METHOD("is_ssr_rough"), &Environment::is_ssr_rough);
-
ADD_GROUP("SS Reflections", "ss_reflections_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_enabled"), "set_ssr_enabled", "is_ssr_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ss_reflections_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ss_reflections_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ss_reflections_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ss_reflections_depth_tolerance", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_roughness"), "set_ssr_rough", "is_ssr_rough");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ss_reflections_depth_tolerance", PROPERTY_HINT_RANGE, "0.01,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance");
ClassDB::bind_method(D_METHOD("set_ssao_enabled", "enabled"), &Environment::set_ssao_enabled);
ClassDB::bind_method(D_METHOD("is_ssao_enabled"), &Environment::is_ssao_enabled);
@@ -1067,9 +1042,6 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_glow_hdr_bleed_scale", "scale"), &Environment::set_glow_hdr_bleed_scale);
ClassDB::bind_method(D_METHOD("get_glow_hdr_bleed_scale"), &Environment::get_glow_hdr_bleed_scale);
- ClassDB::bind_method(D_METHOD("set_glow_bicubic_upscale", "enabled"), &Environment::set_glow_bicubic_upscale);
- ClassDB::bind_method(D_METHOD("is_glow_bicubic_upscale_enabled"), &Environment::is_glow_bicubic_upscale_enabled);
-
ADD_GROUP("Glow", "glow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_enabled"), "set_glow_enabled", "is_glow_enabled");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "glow_levels/1"), "set_glow_level", "is_glow_level_enabled", 0);
@@ -1088,7 +1060,6 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_threshold", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_threshold", "get_glow_hdr_bleed_threshold");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_luminance_cap", PROPERTY_HINT_RANGE, "0.0,256.0,0.01"), "set_glow_hdr_luminance_cap", "get_glow_hdr_luminance_cap");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_scale", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_scale", "get_glow_hdr_bleed_scale");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_bicubic_upscale"), "set_glow_bicubic_upscale", "is_glow_bicubic_upscale_enabled");
ClassDB::bind_method(D_METHOD("set_adjustment_enable", "enabled"), &Environment::set_adjustment_enable);
ClassDB::bind_method(D_METHOD("is_adjustment_enabled"), &Environment::is_adjustment_enabled);
@@ -1152,7 +1123,7 @@ Environment::Environment() :
ssao_blur(SSAO_BLUR_3x3),
glow_blend_mode(GLOW_BLEND_MODE_ADDITIVE) {
- environment = VS::get_singleton()->environment_create();
+ environment = RS::get_singleton()->environment_create();
bg_mode = BG_CLEAR_COLOR;
bg_sky_custom_fov = 0;
@@ -1188,7 +1159,6 @@ Environment::Environment() :
ssr_fade_in = 0.15;
ssr_fade_out = 2.0;
ssr_depth_tolerance = 0.2;
- ssr_roughness = true;
ssao_enabled = false;
ssao_radius = 1;
@@ -1209,7 +1179,6 @@ Environment::Environment() :
glow_hdr_bleed_threshold = 1.0;
glow_hdr_luminance_cap = 12.0;
glow_hdr_bleed_scale = 2.0;
- glow_bicubic_upscale = false;
fog_enabled = false;
fog_color = Color(0.5, 0.5, 0.5);
@@ -1236,7 +1205,7 @@ Environment::Environment() :
Environment::~Environment() {
- VS::get_singleton()->free(environment);
+ RS::get_singleton()->free(environment);
}
//////////////////////
@@ -1244,7 +1213,7 @@ Environment::~Environment() {
void CameraEffects::set_dof_blur_far_enabled(bool p_enable) {
dof_blur_far_enabled = p_enable;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
}
bool CameraEffects::is_dof_blur_far_enabled() const {
@@ -1255,7 +1224,7 @@ bool CameraEffects::is_dof_blur_far_enabled() const {
void CameraEffects::set_dof_blur_far_distance(float p_distance) {
dof_blur_far_distance = p_distance;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
}
float CameraEffects::get_dof_blur_far_distance() const {
@@ -1265,7 +1234,7 @@ float CameraEffects::get_dof_blur_far_distance() const {
void CameraEffects::set_dof_blur_far_transition(float p_distance) {
dof_blur_far_transition = p_distance;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
}
float CameraEffects::get_dof_blur_far_transition() const {
@@ -1275,7 +1244,7 @@ float CameraEffects::get_dof_blur_far_transition() const {
void CameraEffects::set_dof_blur_near_enabled(bool p_enable) {
dof_blur_near_enabled = p_enable;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
_change_notify();
}
@@ -1287,7 +1256,7 @@ bool CameraEffects::is_dof_blur_near_enabled() const {
void CameraEffects::set_dof_blur_near_distance(float p_distance) {
dof_blur_near_distance = p_distance;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
}
float CameraEffects::get_dof_blur_near_distance() const {
@@ -1298,7 +1267,7 @@ float CameraEffects::get_dof_blur_near_distance() const {
void CameraEffects::set_dof_blur_near_transition(float p_distance) {
dof_blur_near_transition = p_distance;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
}
float CameraEffects::get_dof_blur_near_transition() const {
@@ -1309,7 +1278,7 @@ float CameraEffects::get_dof_blur_near_transition() const {
void CameraEffects::set_dof_blur_amount(float p_amount) {
dof_blur_amount = p_amount;
- VS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
+ RS::get_singleton()->camera_effects_set_dof_blur(camera_effects, dof_blur_far_enabled, dof_blur_far_distance, dof_blur_far_transition, dof_blur_near_enabled, dof_blur_near_distance, dof_blur_near_transition, dof_blur_amount);
}
float CameraEffects::get_dof_blur_amount() const {
@@ -1318,7 +1287,7 @@ float CameraEffects::get_dof_blur_amount() const {
void CameraEffects::set_override_exposure_enabled(bool p_enabled) {
override_exposure_enabled = p_enabled;
- VS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure);
+ RS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure);
}
bool CameraEffects::is_override_exposure_enabled() const {
@@ -1327,7 +1296,7 @@ bool CameraEffects::is_override_exposure_enabled() const {
void CameraEffects::set_override_exposure(float p_exposure) {
override_exposure = p_exposure;
- VS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure);
+ RS::get_singleton()->camera_effects_set_custom_exposure(camera_effects, override_exposure_enabled, override_exposure);
}
float CameraEffects::get_override_exposure() const {
@@ -1382,7 +1351,7 @@ void CameraEffects::_bind_methods() {
CameraEffects::CameraEffects() {
- camera_effects = VS::get_singleton()->camera_effects_create();
+ camera_effects = RS::get_singleton()->camera_effects_create();
dof_blur_far_enabled = false;
dof_blur_far_distance = 10;
@@ -1400,5 +1369,5 @@ CameraEffects::CameraEffects() {
CameraEffects::~CameraEffects() {
- VS::get_singleton()->free(camera_effects);
+ RS::get_singleton()->free(camera_effects);
}
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index f9fe26f792..02434bc592 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -34,7 +34,7 @@
#include "core/resource.h"
#include "scene/resources/sky.h"
#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
class Environment : public Resource {
@@ -125,7 +125,6 @@ private:
float ssr_fade_in;
float ssr_fade_out;
float ssr_depth_tolerance;
- bool ssr_roughness;
bool ssao_enabled;
float ssao_radius;
@@ -146,7 +145,6 @@ private:
float glow_hdr_bleed_threshold;
float glow_hdr_bleed_scale;
float glow_hdr_luminance_cap;
- bool glow_bicubic_upscale;
bool fog_enabled;
Color fog_color;
@@ -258,9 +256,6 @@ public:
void set_ssr_depth_tolerance(float p_depth_tolerance);
float get_ssr_depth_tolerance() const;
- void set_ssr_rough(bool p_enable);
- bool is_ssr_rough() const;
-
void set_ssao_enabled(bool p_enable);
bool is_ssao_enabled() const;
@@ -318,9 +313,6 @@ public:
void set_glow_hdr_bleed_scale(float p_scale);
float get_glow_hdr_bleed_scale() const;
- void set_glow_bicubic_upscale(bool p_enable);
- bool is_glow_bicubic_upscale_enabled() const;
-
void set_fog_enabled(bool p_enabled);
bool is_fog_enabled() const;
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 1f5e4b647a..192eefbf6a 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -128,7 +128,7 @@ Vector<int> BitmapFont::_get_chars() const {
Vector<int> chars;
- const CharType *key = NULL;
+ const CharType *key = nullptr;
while ((key = char_map.next(key))) {
@@ -382,7 +382,7 @@ Vector<CharType> BitmapFont::get_char_keys() const {
Vector<CharType> chars;
chars.resize(char_map.size());
- const CharType *ct = NULL;
+ const CharType *ct = nullptr;
int count = 0;
while ((ct = char_map.next(ct))) {
@@ -528,7 +528,7 @@ Size2 Font::get_wordwrap_string_size(const String &p_string, float p_width) cons
void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) {
- for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != NULL; fallback_child = fallback_child->get_fallback()) {
+ for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != nullptr; fallback_child = fallback_child->get_fallback()) {
ERR_FAIL_COND_MSG(fallback_child == this, "Can't set as fallback one of its parents to prevent crashes due to recursive loop.");
}
@@ -556,7 +556,7 @@ float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_c
cpos.x += c->h_align;
cpos.y -= ascent;
cpos.y += c->v_align;
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), RID(), Color(1, 1, 1, 1), false);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), RID(), Color(1, 1, 1, 1), false);
}
return get_char_size(p_char, p_next).width;
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 85b295b5f8..ce75f27e2a 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -108,7 +108,7 @@ class BitmapFont : public Font {
GDCLASS(BitmapFont, Font);
RES_BASE_EXTENSION("font");
- Vector<Ref<Texture2D> > textures;
+ Vector<Ref<Texture2D>> textures;
public:
struct Character {
@@ -200,7 +200,7 @@ public:
class ResourceFormatLoaderBMFont : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/height_map_shape.cpp b/scene/resources/height_map_shape.cpp
deleted file mode 100644
index fa45ddcabb..0000000000
--- a/scene/resources/height_map_shape.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*************************************************************************/
-/* height_map_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "height_map_shape.h"
-#include "servers/physics_server.h"
-
-Vector<Vector3> HeightMapShape::get_debug_mesh_lines() {
- Vector<Vector3> points;
-
- if ((map_width != 0) && (map_depth != 0)) {
-
- // This will be slow for large maps...
- // also we'll have to figure out how well bullet centers this shape...
-
- Vector2 size(map_width - 1, map_depth - 1);
- Vector2 start = size * -0.5;
-
- const real_t *r = map_data.ptr();
-
- // reserve some memory for our points..
- points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2));
-
- // now set our points
- int r_offset = 0;
- int w_offset = 0;
- for (int d = 0; d < map_depth; d++) {
- Vector3 height(start.x, 0.0, start.y);
-
- for (int w = 0; w < map_width; w++) {
- height.y = r[r_offset++];
-
- if (w != map_width - 1) {
- points.write[w_offset++] = height;
- points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
- }
-
- if (d != map_depth - 1) {
- points.write[w_offset++] = height;
- points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
- }
-
- height.x += 1.0;
- }
-
- start.y += 1.0;
- }
- }
-
- return points;
-}
-
-real_t HeightMapShape::get_enclosing_radius() const {
- return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
-}
-
-void HeightMapShape::_update_shape() {
-
- Dictionary d;
- d["width"] = map_width;
- d["depth"] = map_depth;
- d["heights"] = map_data;
- d["min_height"] = min_height;
- d["max_height"] = max_height;
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
- Shape::_update_shape();
-}
-
-void HeightMapShape::set_map_width(int p_new) {
- if (p_new < 1) {
- // ignore
- } else if (map_width != p_new) {
- int was_size = map_width * map_depth;
- map_width = p_new;
-
- int new_size = map_width * map_depth;
- map_data.resize(map_width * map_depth);
-
- real_t *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");
- }
-}
-
-int HeightMapShape::get_map_width() const {
- return map_width;
-}
-
-void HeightMapShape::set_map_depth(int p_new) {
- if (p_new < 1) {
- // ignore
- } else if (map_depth != p_new) {
- int was_size = map_width * map_depth;
- map_depth = p_new;
-
- int new_size = map_width * map_depth;
- map_data.resize(new_size);
-
- real_t *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");
- }
-}
-
-int HeightMapShape::get_map_depth() const {
- return map_depth;
-}
-
-void HeightMapShape::set_map_data(PackedFloat32Array p_new) {
- int size = (map_width * map_depth);
- if (p_new.size() != size) {
- // fail
- return;
- }
-
- // copy
- real_t *w = map_data.ptrw();
- const real_t *r = p_new.ptr();
- for (int i = 0; i < size; i++) {
- float val = r[i];
- w[i] = val;
- if (i == 0) {
- min_height = val;
- max_height = val;
- } else {
- if (min_height > val)
- min_height = val;
-
- if (max_height < val)
- max_height = val;
- }
- }
-
- _update_shape();
- notify_change_to_owners();
- _change_notify("map_data");
-}
-
-PackedFloat32Array HeightMapShape::get_map_data() const {
- return map_data;
-}
-
-void HeightMapShape::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape::set_map_width);
- ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape::get_map_width);
- ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape::set_map_depth);
- ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape::get_map_depth);
- ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape::set_map_data);
- ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape::get_map_data);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_width", "get_map_width");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_depth", "get_map_depth");
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");
-}
-
-HeightMapShape::HeightMapShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_HEIGHTMAP)) {
-
- map_width = 2;
- map_depth = 2;
- map_data.resize(map_width * map_depth);
- real_t *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.h b/scene/resources/height_map_shape.h
deleted file mode 100644
index b8204f6c98..0000000000
--- a/scene/resources/height_map_shape.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*************************************************************************/
-/* height_map_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 HEIGHT_MAP_SHAPE_H
-#define HEIGHT_MAP_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class HeightMapShape : public Shape {
- GDCLASS(HeightMapShape, Shape);
-
- int map_width;
- int map_depth;
- PackedFloat32Array map_data;
- float min_height;
- float max_height;
-
-protected:
- static void _bind_methods();
- virtual void _update_shape();
-
-public:
- void set_map_width(int p_new);
- int get_map_width() const;
- void set_map_depth(int p_new);
- int get_map_depth() const;
- void set_map_data(PackedFloat32Array p_new);
- PackedFloat32Array get_map_data() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- HeightMapShape();
-};
-
-#endif /* !HEIGHT_MAP_SHAPE_H */
diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp
new file mode 100644
index 0000000000..33b6063299
--- /dev/null
+++ b/scene/resources/height_map_shape_3d.cpp
@@ -0,0 +1,209 @@
+/*************************************************************************/
+/* height_map_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "height_map_shape_3d.h"
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() {
+ Vector<Vector3> points;
+
+ if ((map_width != 0) && (map_depth != 0)) {
+
+ // This will be slow for large maps...
+ // also we'll have to figure out how well bullet centers this shape...
+
+ Vector2 size(map_width - 1, map_depth - 1);
+ Vector2 start = size * -0.5;
+
+ const real_t *r = map_data.ptr();
+
+ // reserve some memory for our points..
+ points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2));
+
+ // now set our points
+ int r_offset = 0;
+ int w_offset = 0;
+ for (int d = 0; d < map_depth; d++) {
+ Vector3 height(start.x, 0.0, start.y);
+
+ for (int w = 0; w < map_width; w++) {
+ height.y = r[r_offset++];
+
+ if (w != map_width - 1) {
+ points.write[w_offset++] = height;
+ points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
+ }
+
+ if (d != map_depth - 1) {
+ points.write[w_offset++] = height;
+ points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
+ }
+
+ height.x += 1.0;
+ }
+
+ start.y += 1.0;
+ }
+ }
+
+ return points;
+}
+
+real_t HeightMapShape3D::get_enclosing_radius() const {
+ return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
+}
+
+void HeightMapShape3D::_update_shape() {
+
+ Dictionary d;
+ d["width"] = map_width;
+ d["depth"] = map_depth;
+ d["heights"] = map_data;
+ d["min_height"] = min_height;
+ d["max_height"] = max_height;
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+ Shape3D::_update_shape();
+}
+
+void HeightMapShape3D::set_map_width(int p_new) {
+ if (p_new < 1) {
+ // ignore
+ } else if (map_width != p_new) {
+ int was_size = map_width * map_depth;
+ map_width = p_new;
+
+ int new_size = map_width * map_depth;
+ map_data.resize(map_width * map_depth);
+
+ real_t *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");
+ }
+}
+
+int HeightMapShape3D::get_map_width() const {
+ return map_width;
+}
+
+void HeightMapShape3D::set_map_depth(int p_new) {
+ if (p_new < 1) {
+ // ignore
+ } else if (map_depth != p_new) {
+ int was_size = map_width * map_depth;
+ map_depth = p_new;
+
+ int new_size = map_width * map_depth;
+ map_data.resize(new_size);
+
+ real_t *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");
+ }
+}
+
+int HeightMapShape3D::get_map_depth() const {
+ return map_depth;
+}
+
+void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) {
+ int size = (map_width * map_depth);
+ if (p_new.size() != size) {
+ // fail
+ return;
+ }
+
+ // copy
+ real_t *w = map_data.ptrw();
+ const real_t *r = p_new.ptr();
+ for (int i = 0; i < size; i++) {
+ float val = r[i];
+ w[i] = val;
+ if (i == 0) {
+ min_height = val;
+ max_height = val;
+ } else {
+ if (min_height > val)
+ min_height = val;
+
+ if (max_height < val)
+ max_height = val;
+ }
+ }
+
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("map_data");
+}
+
+PackedFloat32Array HeightMapShape3D::get_map_data() const {
+ return map_data;
+}
+
+void HeightMapShape3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width);
+ ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width);
+ ClassDB::bind_method(D_METHOD("set_map_depth", "height"), &HeightMapShape3D::set_map_depth);
+ ClassDB::bind_method(D_METHOD("get_map_depth"), &HeightMapShape3D::get_map_depth);
+ ClassDB::bind_method(D_METHOD("set_map_data", "data"), &HeightMapShape3D::set_map_data);
+ ClassDB::bind_method(D_METHOD("get_map_data"), &HeightMapShape3D::get_map_data);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_width", "get_map_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "1,4096,1"), "set_map_depth", "get_map_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data");
+}
+
+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();
+ 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
new file mode 100644
index 0000000000..291d41a34e
--- /dev/null
+++ b/scene/resources/height_map_shape_3d.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* height_map_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 HEIGHT_MAP_SHAPE_H
+#define HEIGHT_MAP_SHAPE_H
+
+#include "scene/resources/shape_3d.h"
+
+class HeightMapShape3D : public Shape3D {
+ GDCLASS(HeightMapShape3D, Shape3D);
+
+ int map_width;
+ int map_depth;
+ PackedFloat32Array map_data;
+ float min_height;
+ float max_height;
+
+protected:
+ static void _bind_methods();
+ virtual void _update_shape();
+
+public:
+ void set_map_width(int p_new);
+ int get_map_width() const;
+ void set_map_depth(int p_new);
+ int get_map_depth() const;
+ void set_map_data(PackedFloat32Array p_new);
+ PackedFloat32Array get_map_data() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ HeightMapShape3D();
+};
+
+#endif /* !HEIGHT_MAP_SHAPE_H */
diff --git a/scene/resources/line_shape_2d.cpp b/scene/resources/line_shape_2d.cpp
index 3b30b4528a..a1c1b2f9f4 100644
--- a/scene/resources/line_shape_2d.cpp
+++ b/scene/resources/line_shape_2d.cpp
@@ -30,8 +30,8 @@
#include "line_shape_2d.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
@@ -52,7 +52,7 @@ void LineShape2D::_update_shape() {
Array arr;
arr.push_back(normal);
arr.push_back(d);
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), arr);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), arr);
emit_changed();
}
@@ -82,9 +82,9 @@ void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector2 point = get_d() * get_normal();
Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 };
- VS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3);
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3);
Vector2 l2[2] = { point, point + get_normal() * 30 };
- VS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3);
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3);
}
Rect2 LineShape2D::get_rect() const {
@@ -117,7 +117,7 @@ void LineShape2D::_bind_methods() {
}
LineShape2D::LineShape2D() :
- Shape2D(Physics2DServer::get_singleton()->line_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->line_shape_create()) {
normal = Vector2(0, 1);
d = 0;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index d387a39dbe..fd8cff7cd0 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -40,7 +40,7 @@
void Material::set_next_pass(const Ref<Material> &p_pass) {
- for (Ref<Material> pass_child = p_pass; pass_child != NULL; pass_child = pass_child->get_next_pass()) {
+ for (Ref<Material> pass_child = p_pass; pass_child != nullptr; pass_child = pass_child->get_next_pass()) {
ERR_FAIL_COND_MSG(pass_child == this, "Can't set as next_pass one of its parents to prevent crashes due to recursive loop.");
}
@@ -51,7 +51,7 @@ void Material::set_next_pass(const Ref<Material> &p_pass) {
RID next_pass_rid;
if (next_pass.is_valid())
next_pass_rid = next_pass->get_rid();
- VS::get_singleton()->material_set_next_pass(material, next_pass_rid);
+ RS::get_singleton()->material_set_next_pass(material, next_pass_rid);
}
Ref<Material> Material::get_next_pass() const {
@@ -64,7 +64,7 @@ void Material::set_render_priority(int p_priority) {
ERR_FAIL_COND(p_priority < RENDER_PRIORITY_MIN);
ERR_FAIL_COND(p_priority > RENDER_PRIORITY_MAX);
render_priority = p_priority;
- VS::get_singleton()->material_set_render_priority(material, p_priority);
+ RS::get_singleton()->material_set_render_priority(material, p_priority);
}
int Material::get_render_priority() const {
@@ -100,13 +100,13 @@ void Material::_bind_methods() {
Material::Material() {
- material = VisualServer::get_singleton()->material_create();
+ material = RenderingServer::get_singleton()->material_create();
render_priority = 0;
}
Material::~Material() {
- VisualServer::get_singleton()->free(material);
+ RenderingServer::get_singleton()->free(material);
}
///////////////////////////////////
@@ -126,7 +126,7 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
}
}
if (pr) {
- VisualServer::get_singleton()->material_set_param(_get_material(), pr, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), pr, p_value);
return true;
}
}
@@ -150,7 +150,7 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
}
if (pr) {
- r_ret = VisualServer::get_singleton()->material_get_param(_get_material(), pr);
+ r_ret = RenderingServer::get_singleton()->material_get_param(_get_material(), pr);
return true;
}
}
@@ -171,7 +171,7 @@ bool ShaderMaterial::property_can_revert(const String &p_name) {
StringName pr = shader->remap_param(p_name);
if (pr) {
- Variant default_value = VisualServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ Variant default_value = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
Variant current_value;
_get(p_name, current_value);
return default_value.get_type() != Variant::NIL && default_value != current_value;
@@ -185,7 +185,7 @@ Variant ShaderMaterial::property_get_revert(const String &p_name) {
if (shader.is_valid()) {
StringName pr = shader->remap_param(p_name);
if (pr) {
- r_ret = VisualServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ r_ret = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
}
}
return r_ret;
@@ -211,7 +211,7 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
}
}
- VS::get_singleton()->material_set_shader(_get_material(), rid);
+ RS::get_singleton()->material_set_shader(_get_material(), rid);
_change_notify(); //properties for shader exposed
emit_changed();
}
@@ -223,12 +223,12 @@ Ref<Shader> ShaderMaterial::get_shader() const {
void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) {
- VS::get_singleton()->material_set_param(_get_material(), p_param, p_value);
+ RS::get_singleton()->material_set_param(_get_material(), p_param, p_value);
}
Variant ShaderMaterial::get_shader_param(const StringName &p_param) const {
- return VS::get_singleton()->material_get_param(_get_material(), p_param);
+ return RS::get_singleton()->material_get_param(_get_material(), p_param);
}
void ShaderMaterial::_shader_changed() {
@@ -290,9 +290,9 @@ ShaderMaterial::~ShaderMaterial() {
/////////////////////////////////
Mutex BaseMaterial3D::material_mutex;
-SelfList<BaseMaterial3D>::List *BaseMaterial3D::dirty_materials = NULL;
+SelfList<BaseMaterial3D>::List *BaseMaterial3D::dirty_materials = nullptr;
Map<BaseMaterial3D::MaterialKey, BaseMaterial3D::ShaderData> BaseMaterial3D::shader_map;
-BaseMaterial3D::ShaderNames *BaseMaterial3D::shader_names = NULL;
+BaseMaterial3D::ShaderNames *BaseMaterial3D::shader_names = nullptr;
void BaseMaterial3D::init_shaders() {
@@ -314,7 +314,7 @@ void BaseMaterial3D::init_shaders() {
shader_names->anisotropy = "anisotropy_ratio";
shader_names->heightmap_scale = "heightmap_scale";
shader_names->subsurface_scattering_strength = "subsurface_scattering_strength";
- shader_names->transmission = "transmission";
+ shader_names->backlight = "backlight";
shader_names->refraction = "refraction";
shader_names->point_size = "point_size";
shader_names->uv1_scale = "uv1_scale";
@@ -347,6 +347,11 @@ void BaseMaterial3D::init_shaders() {
shader_names->refraction_texture_channel = "refraction_texture_channel";
shader_names->alpha_scissor_threshold = "alpha_scissor_threshold";
+ shader_names->transmittance_color = "transmittance_color";
+ shader_names->transmittance_curve = "transmittance_curve";
+ shader_names->transmittance_depth = "transmittance_depth";
+ shader_names->transmittance_boost = "transmittance_boost";
+
shader_names->texture_names[TEXTURE_ALBEDO] = "texture_albedo";
shader_names->texture_names[TEXTURE_METALLIC] = "texture_metallic";
shader_names->texture_names[TEXTURE_ROUGHNESS] = "texture_roughness";
@@ -358,7 +363,8 @@ void BaseMaterial3D::init_shaders() {
shader_names->texture_names[TEXTURE_AMBIENT_OCCLUSION] = "texture_ambient_occlusion";
shader_names->texture_names[TEXTURE_HEIGHTMAP] = "texture_heightmap";
shader_names->texture_names[TEXTURE_SUBSURFACE_SCATTERING] = "texture_subsurface_scattering";
- shader_names->texture_names[TEXTURE_TRANSMISSION] = "texture_transmission";
+ shader_names->texture_names[TEXTURE_SUBSURFACE_TRANSMITTANCE] = "texture_subsurface_transmittance";
+ shader_names->texture_names[TEXTURE_BACKLIGHT] = "texture_backlight";
shader_names->texture_names[TEXTURE_REFRACTION] = "texture_refraction";
shader_names->texture_names[TEXTURE_DETAIL_MASK] = "texture_detail_mask";
shader_names->texture_names[TEXTURE_DETAIL_ALBEDO] = "texture_detail_albedo";
@@ -375,7 +381,7 @@ void BaseMaterial3D::finish_shaders() {
}
memdelete(dirty_materials);
- dirty_materials = NULL;
+ dirty_materials = nullptr;
memdelete(shader_names);
}
@@ -385,14 +391,14 @@ void BaseMaterial3D::_update_shader() {
dirty_materials->remove(&element);
MaterialKey mk = _compute_key();
- if (mk.key == current_key.key)
+ if (mk == current_key)
return; //no update required in the end
if (shader_map.has(current_key)) {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
//deallocate shader, as it's no longer in use
- VS::get_singleton()->free(shader_map[current_key].shader);
+ RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
}
@@ -401,7 +407,7 @@ void BaseMaterial3D::_update_shader() {
if (shader_map.has(mk)) {
- VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
shader_map[mk].users++;
return;
}
@@ -467,6 +473,9 @@ void BaseMaterial3D::_update_shader() {
case SPECULAR_TOON: code += ",specular_toon"; break;
case SPECULAR_DISABLED: code += ",specular_disabled"; break;
}
+ if (features[FEATURE_SUBSURFACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) {
+ code += ",sss_mode_skin";
+ }
if (shading_mode == SHADING_MODE_UNSHADED) {
code += ",unshaded";
@@ -586,16 +595,25 @@ void BaseMaterial3D::_update_shader() {
code += "uniform sampler2D texture_detail_mask : hint_white," + texfilter_str + ";\n";
}
- if (features[FEATURE_SUBSURACE_SCATTERING]) {
+ if (features[FEATURE_SUBSURFACE_SCATTERING]) {
code += "uniform float subsurface_scattering_strength : hint_range(0,1);\n";
code += "uniform sampler2D texture_subsurface_scattering : hint_white," + texfilter_str + ";\n";
}
- if (features[FEATURE_TRANSMISSION]) {
+ if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) {
+
+ code += "uniform vec4 transmittance_color : hint_color;\n";
+ code += "uniform float transmittance_depth;\n";
+ code += "uniform sampler2D texture_subsurface_transmittance : hint_white," + texfilter_str + ";\n";
+ code += "uniform float transmittance_curve;\n";
+ code += "uniform float transmittance_boost;\n";
+ }
+
+ if (features[FEATURE_BACKLIGHT]) {
- code += "uniform vec4 transmission : hint_color;\n";
- code += "uniform sampler2D texture_transmission : hint_black," + texfilter_str + ";\n";
+ code += "uniform vec4 backlight : hint_color;\n";
+ code += "uniform sampler2D texture_backlight : hint_black," + texfilter_str + ";\n";
}
if (features[FEATURE_HEIGHT_MAPPING]) {
@@ -773,7 +791,7 @@ void BaseMaterial3D::_update_shader() {
code += "\tvec2 base_uv2 = UV2;\n";
}
- if (!VisualServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //heightmap not supported with triplanar
+ if (!RenderingServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //heightmap not supported with triplanar
code += "\t{\n";
code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*heightmap_flip.x,-BINORMAL*heightmap_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-)
@@ -953,7 +971,7 @@ void BaseMaterial3D::_update_shader() {
if (distance_fade != DISTANCE_FADE_DISABLED) {
if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) {
- if (!VisualServer::get_singleton()->is_low_end()) {
+ if (!RenderingServer::get_singleton()->is_low_end()) {
code += "\t{\n";
if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
code += "\t\tfloat fade_distance = abs((INV_CAMERA_MATRIX * WORLD_MATRIX[3]).z);\n";
@@ -1048,7 +1066,7 @@ void BaseMaterial3D::_update_shader() {
code += "\tAO_LIGHT_AFFECT = ao_light_affect;\n";
}
- if (features[FEATURE_SUBSURACE_SCATTERING]) {
+ if (features[FEATURE_SUBSURFACE_SCATTERING]) {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
code += "\tfloat sss_tex = triplanar_texture(texture_subsurface_scattering,uv1_power_normal,uv1_triplanar_pos).r;\n";
@@ -1058,13 +1076,27 @@ void BaseMaterial3D::_update_shader() {
code += "\tSSS_STRENGTH=subsurface_scattering_strength*sss_tex;\n";
}
- if (features[FEATURE_TRANSMISSION]) {
+ if (features[FEATURE_SUBSURFACE_TRANSMITTANCE]) {
+
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tvec4 trans_color_tex = triplanar_texture(texture_subsurface_transmittance,uv1_power_normal,uv1_triplanar_pos);\n";
+ } else {
+ code += "\tvec4 trans_color_tex = texture(texture_subsurface_transmittance,base_uv);\n";
+ }
+ code += "\tSSS_TRANSMITTANCE_COLOR=transmittance_color*trans_color_tex;\n";
+
+ code += "\tSSS_TRANSMITTANCE_DEPTH=transmittance_depth;\n";
+ code += "\tSSS_TRANSMITTANCE_CURVE=transmittance_curve;\n";
+ code += "\tSSS_TRANSMITTANCE_BOOST=transmittance_boost;\n";
+ }
+
+ if (features[FEATURE_BACKLIGHT]) {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tvec3 transmission_tex = triplanar_texture(texture_transmission,uv1_power_normal,uv1_triplanar_pos).rgb;\n";
+ code += "\tvec3 backlight_tex = triplanar_texture(texture_backlight,uv1_power_normal,uv1_triplanar_pos).rgb;\n";
} else {
- code += "\tvec3 transmission_tex = texture(texture_transmission,base_uv).rgb;\n";
+ code += "\tvec3 backlight_tex = texture(texture_backlight,base_uv).rgb;\n";
}
- code += "\tTRANSMISSION = (transmission.rgb+transmission_tex);\n";
+ code += "\tBACKLIGHT = (backlight.rgb+backlight_tex);\n";
}
if (features[FEATURE_DETAIL]) {
@@ -1112,14 +1144,14 @@ void BaseMaterial3D::_update_shader() {
code += "}\n";
ShaderData shader_data;
- shader_data.shader = VS::get_singleton()->shader_create();
+ shader_data.shader = RS::get_singleton()->shader_create();
shader_data.users = 1;
- VS::get_singleton()->shader_set_code(shader_data.shader, code);
+ RS::get_singleton()->shader_set_code(shader_data.shader, code);
shader_map[mk] = shader_data;
- VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
}
void BaseMaterial3D::flush_changes() {
@@ -1151,7 +1183,7 @@ void BaseMaterial3D::set_albedo(const Color &p_albedo) {
albedo = p_albedo;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->albedo, p_albedo);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo, p_albedo);
}
Color BaseMaterial3D::get_albedo() const {
@@ -1162,7 +1194,7 @@ Color BaseMaterial3D::get_albedo() const {
void BaseMaterial3D::set_specular(float p_specular) {
specular = p_specular;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->specular, p_specular);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->specular, p_specular);
}
float BaseMaterial3D::get_specular() const {
@@ -1173,7 +1205,7 @@ float BaseMaterial3D::get_specular() const {
void BaseMaterial3D::set_roughness(float p_roughness) {
roughness = p_roughness;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->roughness, p_roughness);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->roughness, p_roughness);
}
float BaseMaterial3D::get_roughness() const {
@@ -1184,7 +1216,7 @@ float BaseMaterial3D::get_roughness() const {
void BaseMaterial3D::set_metallic(float p_metallic) {
metallic = p_metallic;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->metallic, p_metallic);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->metallic, p_metallic);
}
float BaseMaterial3D::get_metallic() const {
@@ -1195,7 +1227,7 @@ float BaseMaterial3D::get_metallic() const {
void BaseMaterial3D::set_emission(const Color &p_emission) {
emission = p_emission;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->emission, p_emission);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission, p_emission);
}
Color BaseMaterial3D::get_emission() const {
@@ -1205,7 +1237,7 @@ Color BaseMaterial3D::get_emission() const {
void BaseMaterial3D::set_emission_energy(float p_emission_energy) {
emission_energy = p_emission_energy;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy);
}
float BaseMaterial3D::get_emission_energy() const {
@@ -1215,7 +1247,7 @@ float BaseMaterial3D::get_emission_energy() const {
void BaseMaterial3D::set_normal_scale(float p_normal_scale) {
normal_scale = p_normal_scale;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->normal_scale, p_normal_scale);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->normal_scale, p_normal_scale);
}
float BaseMaterial3D::get_normal_scale() const {
@@ -1225,7 +1257,7 @@ float BaseMaterial3D::get_normal_scale() const {
void BaseMaterial3D::set_rim(float p_rim) {
rim = p_rim;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->rim, p_rim);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->rim, p_rim);
}
float BaseMaterial3D::get_rim() const {
@@ -1235,7 +1267,7 @@ float BaseMaterial3D::get_rim() const {
void BaseMaterial3D::set_rim_tint(float p_rim_tint) {
rim_tint = p_rim_tint;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->rim_tint, p_rim_tint);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->rim_tint, p_rim_tint);
}
float BaseMaterial3D::get_rim_tint() const {
@@ -1245,7 +1277,7 @@ float BaseMaterial3D::get_rim_tint() const {
void BaseMaterial3D::set_ao_light_affect(float p_ao_light_affect) {
ao_light_affect = p_ao_light_affect;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->ao_light_affect, p_ao_light_affect);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->ao_light_affect, p_ao_light_affect);
}
float BaseMaterial3D::get_ao_light_affect() const {
@@ -1255,7 +1287,7 @@ float BaseMaterial3D::get_ao_light_affect() const {
void BaseMaterial3D::set_clearcoat(float p_clearcoat) {
clearcoat = p_clearcoat;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat, p_clearcoat);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat, p_clearcoat);
}
float BaseMaterial3D::get_clearcoat() const {
@@ -1266,7 +1298,7 @@ float BaseMaterial3D::get_clearcoat() const {
void BaseMaterial3D::set_clearcoat_gloss(float p_clearcoat_gloss) {
clearcoat_gloss = p_clearcoat_gloss;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_gloss, p_clearcoat_gloss);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_gloss, p_clearcoat_gloss);
}
float BaseMaterial3D::get_clearcoat_gloss() const {
@@ -1277,7 +1309,7 @@ float BaseMaterial3D::get_clearcoat_gloss() const {
void BaseMaterial3D::set_anisotropy(float p_anisotropy) {
anisotropy = p_anisotropy;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->anisotropy, p_anisotropy);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->anisotropy, p_anisotropy);
}
float BaseMaterial3D::get_anisotropy() const {
@@ -1287,7 +1319,7 @@ float BaseMaterial3D::get_anisotropy() const {
void BaseMaterial3D::set_heightmap_scale(float p_heightmap_scale) {
heightmap_scale = p_heightmap_scale;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_scale, p_heightmap_scale);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_scale, p_heightmap_scale);
}
float BaseMaterial3D::get_heightmap_scale() const {
@@ -1298,7 +1330,7 @@ float BaseMaterial3D::get_heightmap_scale() const {
void BaseMaterial3D::set_subsurface_scattering_strength(float p_subsurface_scattering_strength) {
subsurface_scattering_strength = p_subsurface_scattering_strength;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->subsurface_scattering_strength, subsurface_scattering_strength);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->subsurface_scattering_strength, subsurface_scattering_strength);
}
float BaseMaterial3D::get_subsurface_scattering_strength() const {
@@ -1306,21 +1338,54 @@ float BaseMaterial3D::get_subsurface_scattering_strength() const {
return subsurface_scattering_strength;
}
-void BaseMaterial3D::set_transmission(const Color &p_transmission) {
+void BaseMaterial3D::set_transmittance_color(const Color &p_color) {
+ transmittance_color = p_color;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_color, p_color);
+}
+
+Color BaseMaterial3D::get_transmittance_color() const {
+ return transmittance_color;
+}
+
+void BaseMaterial3D::set_transmittance_depth(float p_depth) {
+ transmittance_depth = p_depth;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_depth, p_depth);
+}
+float BaseMaterial3D::get_transmittance_depth() const {
+ return transmittance_depth;
+}
+
+void BaseMaterial3D::set_transmittance_curve(float p_curve) {
+ transmittance_curve = p_curve;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_curve, p_curve);
+}
+float BaseMaterial3D::get_transmittance_curve() const {
+ return transmittance_curve;
+}
- transmission = p_transmission;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->transmission, transmission);
+void BaseMaterial3D::set_transmittance_boost(float p_boost) {
+ transmittance_boost = p_boost;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_boost, p_boost);
+}
+float BaseMaterial3D::get_transmittance_boost() const {
+ return transmittance_boost;
}
-Color BaseMaterial3D::get_transmission() const {
+void BaseMaterial3D::set_backlight(const Color &p_backlight) {
- return transmission;
+ backlight = p_backlight;
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->backlight, backlight);
+}
+
+Color BaseMaterial3D::get_backlight() const {
+
+ return backlight;
}
void BaseMaterial3D::set_refraction(float p_refraction) {
refraction = p_refraction;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->refraction, refraction);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->refraction, refraction);
}
float BaseMaterial3D::get_refraction() const {
@@ -1454,7 +1519,7 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
return;
flags[p_flag] = p_enabled;
- if ((p_flag == FLAG_USE_SHADOW_TO_OPACITY) || (p_flag == FLAG_USE_TEXTURE_REPEAT)) {
+ if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN) {
_change_notify();
}
_queue_shader_change();
@@ -1488,7 +1553,7 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t
ERR_FAIL_INDEX(p_param, TEXTURE_MAX);
textures[p_param] = p_texture;
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- VS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid);
_change_notify();
_queue_shader_change();
}
@@ -1537,8 +1602,8 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
_validate_feature("anisotropy", FEATURE_ANISOTROPY, property);
_validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, property);
_validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, property);
- _validate_feature("subsurf_scatter", FEATURE_SUBSURACE_SCATTERING, property);
- _validate_feature("transmission", FEATURE_TRANSMISSION, property);
+ _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, property);
+ _validate_feature("backlight", FEATURE_BACKLIGHT, property);
_validate_feature("refraction", FEATURE_REFRACTION, property);
_validate_feature("detail", FEATURE_DETAIL, property);
@@ -1572,6 +1637,10 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
+ if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture" || property.name == "subsurf_scatter_transmittance_curve")) {
+ property.usage = 0;
+ }
+
if (orm) {
if (property.name == "shading_mode") {
@@ -1628,7 +1697,11 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if (property.name.begins_with("transmission")) {
+ if (property.name.begins_with("backlight")) {
+ property.usage = 0;
+ }
+
+ if (property.name.begins_with("transmittance")) {
property.usage = 0;
}
}
@@ -1637,7 +1710,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
void BaseMaterial3D::set_point_size(float p_point_size) {
point_size = p_point_size;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->point_size, p_point_size);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->point_size, p_point_size);
}
float BaseMaterial3D::get_point_size() const {
@@ -1648,7 +1721,7 @@ float BaseMaterial3D::get_point_size() const {
void BaseMaterial3D::set_uv1_scale(const Vector3 &p_scale) {
uv1_scale = p_scale;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_scale, p_scale);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_scale, p_scale);
}
Vector3 BaseMaterial3D::get_uv1_scale() const {
@@ -1659,7 +1732,7 @@ Vector3 BaseMaterial3D::get_uv1_scale() const {
void BaseMaterial3D::set_uv1_offset(const Vector3 &p_offset) {
uv1_offset = p_offset;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_offset, p_offset);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_offset, p_offset);
}
Vector3 BaseMaterial3D::get_uv1_offset() const {
@@ -1669,7 +1742,7 @@ Vector3 BaseMaterial3D::get_uv1_offset() const {
void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) {
uv1_triplanar_sharpness = p_sharpness;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, p_sharpness);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, p_sharpness);
}
float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
@@ -1680,7 +1753,7 @@ float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
void BaseMaterial3D::set_uv2_scale(const Vector3 &p_scale) {
uv2_scale = p_scale;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_scale, p_scale);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_scale, p_scale);
}
Vector3 BaseMaterial3D::get_uv2_scale() const {
@@ -1691,7 +1764,7 @@ Vector3 BaseMaterial3D::get_uv2_scale() const {
void BaseMaterial3D::set_uv2_offset(const Vector3 &p_offset) {
uv2_offset = p_offset;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_offset, p_offset);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_offset, p_offset);
}
Vector3 BaseMaterial3D::get_uv2_offset() const {
@@ -1702,7 +1775,7 @@ Vector3 BaseMaterial3D::get_uv2_offset() const {
void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) {
uv2_triplanar_sharpness = p_sharpness;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, p_sharpness);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, p_sharpness);
}
float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
@@ -1725,7 +1798,7 @@ BaseMaterial3D::BillboardMode BaseMaterial3D::get_billboard_mode() const {
void BaseMaterial3D::set_particles_anim_h_frames(int p_frames) {
particles_anim_h_frames = p_frames;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
}
int BaseMaterial3D::get_particles_anim_h_frames() const {
@@ -1735,7 +1808,7 @@ int BaseMaterial3D::get_particles_anim_h_frames() const {
void BaseMaterial3D::set_particles_anim_v_frames(int p_frames) {
particles_anim_v_frames = p_frames;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
}
int BaseMaterial3D::get_particles_anim_v_frames() const {
@@ -1746,7 +1819,7 @@ int BaseMaterial3D::get_particles_anim_v_frames() const {
void BaseMaterial3D::set_particles_anim_loop(bool p_loop) {
particles_anim_loop = p_loop;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
}
bool BaseMaterial3D::get_particles_anim_loop() const {
@@ -1769,7 +1842,7 @@ bool BaseMaterial3D::is_heightmap_deep_parallax_enabled() const {
void BaseMaterial3D::set_heightmap_deep_parallax_min_layers(int p_layer) {
deep_parallax_min_layers = p_layer;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_min_layers, p_layer);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_min_layers, p_layer);
}
int BaseMaterial3D::get_heightmap_deep_parallax_min_layers() const {
@@ -1779,7 +1852,7 @@ int BaseMaterial3D::get_heightmap_deep_parallax_min_layers() const {
void BaseMaterial3D::set_heightmap_deep_parallax_max_layers(int p_layer) {
deep_parallax_max_layers = p_layer;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_max_layers, p_layer);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_max_layers, p_layer);
}
int BaseMaterial3D::get_heightmap_deep_parallax_max_layers() const {
@@ -1789,7 +1862,7 @@ int BaseMaterial3D::get_heightmap_deep_parallax_max_layers() const {
void BaseMaterial3D::set_heightmap_deep_parallax_flip_tangent(bool p_flip) {
heightmap_parallax_flip_tangent = p_flip;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
}
bool BaseMaterial3D::get_heightmap_deep_parallax_flip_tangent() const {
@@ -1800,7 +1873,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_tangent() const {
void BaseMaterial3D::set_heightmap_deep_parallax_flip_binormal(bool p_flip) {
heightmap_parallax_flip_binormal = p_flip;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
}
bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const {
@@ -1820,7 +1893,7 @@ bool BaseMaterial3D::is_grow_enabled() const {
void BaseMaterial3D::set_alpha_scissor_threshold(float p_threshold) {
alpha_scissor_threshold = p_threshold;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_scissor_threshold, p_threshold);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_scissor_threshold, p_threshold);
}
float BaseMaterial3D::get_alpha_scissor_threshold() const {
@@ -1830,7 +1903,7 @@ float BaseMaterial3D::get_alpha_scissor_threshold() const {
void BaseMaterial3D::set_grow(float p_grow) {
grow = p_grow;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->grow, p_grow);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->grow, p_grow);
}
float BaseMaterial3D::get_grow() const {
@@ -1853,7 +1926,7 @@ static Plane _get_texture_mask(BaseMaterial3D::TextureChannel p_channel) {
void BaseMaterial3D::set_metallic_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
metallic_texture_channel = p_channel;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_metallic_texture_channel() const {
@@ -1875,7 +1948,7 @@ void BaseMaterial3D::set_ao_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
ao_texture_channel = p_channel;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_ao_texture_channel() const {
@@ -1886,7 +1959,7 @@ void BaseMaterial3D::set_refraction_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
refraction_texture_channel = p_channel;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel() const {
@@ -1954,7 +2027,7 @@ bool BaseMaterial3D::is_proximity_fade_enabled() const {
void BaseMaterial3D::set_proximity_fade_distance(float p_distance) {
proximity_fade_distance = p_distance;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->proximity_fade_distance, p_distance);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->proximity_fade_distance, p_distance);
}
float BaseMaterial3D::get_proximity_fade_distance() const {
@@ -1975,7 +2048,7 @@ BaseMaterial3D::DistanceFadeMode BaseMaterial3D::get_distance_fade() const {
void BaseMaterial3D::set_distance_fade_max_distance(float p_distance) {
distance_fade_max_distance = p_distance;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_max, distance_fade_max_distance);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_max, distance_fade_max_distance);
}
float BaseMaterial3D::get_distance_fade_max_distance() const {
@@ -1985,7 +2058,7 @@ float BaseMaterial3D::get_distance_fade_max_distance() const {
void BaseMaterial3D::set_distance_fade_min_distance(float p_distance) {
distance_fade_min_distance = p_distance;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_min, distance_fade_min_distance);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_min, distance_fade_min_distance);
}
float BaseMaterial3D::get_distance_fade_min_distance() const {
@@ -2067,8 +2140,20 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subsurface_scattering_strength", "strength"), &BaseMaterial3D::set_subsurface_scattering_strength);
ClassDB::bind_method(D_METHOD("get_subsurface_scattering_strength"), &BaseMaterial3D::get_subsurface_scattering_strength);
- ClassDB::bind_method(D_METHOD("set_transmission", "transmission"), &BaseMaterial3D::set_transmission);
- ClassDB::bind_method(D_METHOD("get_transmission"), &BaseMaterial3D::get_transmission);
+ ClassDB::bind_method(D_METHOD("set_transmittance_color", "color"), &BaseMaterial3D::set_transmittance_color);
+ ClassDB::bind_method(D_METHOD("get_transmittance_color"), &BaseMaterial3D::get_transmittance_color);
+
+ ClassDB::bind_method(D_METHOD("set_transmittance_depth", "depth"), &BaseMaterial3D::set_transmittance_depth);
+ ClassDB::bind_method(D_METHOD("get_transmittance_depth"), &BaseMaterial3D::get_transmittance_depth);
+
+ ClassDB::bind_method(D_METHOD("set_transmittance_curve", "curve"), &BaseMaterial3D::set_transmittance_curve);
+ ClassDB::bind_method(D_METHOD("get_transmittance_curve"), &BaseMaterial3D::get_transmittance_curve);
+
+ ClassDB::bind_method(D_METHOD("set_transmittance_boost", "boost"), &BaseMaterial3D::set_transmittance_boost);
+ ClassDB::bind_method(D_METHOD("get_transmittance_boost"), &BaseMaterial3D::get_transmittance_boost);
+
+ ClassDB::bind_method(D_METHOD("set_backlight", "backlight"), &BaseMaterial3D::set_backlight);
+ ClassDB::bind_method(D_METHOD("get_backlight"), &BaseMaterial3D::get_backlight);
ClassDB::bind_method(D_METHOD("set_refraction", "refraction"), &BaseMaterial3D::set_refraction);
ClassDB::bind_method(D_METHOD("get_refraction"), &BaseMaterial3D::get_refraction);
@@ -2282,14 +2367,23 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "heightmap_flip_texture"), "set_flag", "get_flag", FLAG_INVERT_HEIGHTMAP);
ADD_GROUP("Subsurf Scatter", "subsurf_scatter_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURACE_SCATTERING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURFACE_SCATTERING);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_subsurface_scattering_strength", "get_subsurface_scattering_strength");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_skin_mode"), "set_flag", "get_flag", FLAG_SUBSURFACE_MODE_SKIN);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_SCATTERING);
- ADD_GROUP("Transmission", "transmission_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transmission_enabled"), "set_feature", "get_feature", FEATURE_TRANSMISSION);
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "transmission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_transmission", "get_transmission");
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "transmission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_TRANSMISSION);
+ ADD_SUBGROUP("Transmittance", "subsurf_scatter_transmittance_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_transmittance_enabled"), "set_feature", "get_feature", FEATURE_SUBSURFACE_TRANSMITTANCE);
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "subsurf_scatter_transmittance_color"), "set_transmittance_color", "get_transmittance_color");
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_transmittance_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_TRANSMITTANCE);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_depth", PROPERTY_HINT_RANGE, "0.001,8,0.001,or_greater"), "set_transmittance_depth", "get_transmittance_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_curve", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_transmittance_curve", "get_transmittance_curve");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_boost", PROPERTY_HINT_RANGE, "0.00,1.0,0.01"), "set_transmittance_boost", "get_transmittance_boost");
+
+ ADD_GROUP("Back Lighting", "backlight_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "backlight_enabled"), "set_feature", "get_feature", FEATURE_BACKLIGHT);
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "backlight", PROPERTY_HINT_COLOR_NO_ALPHA), "set_backlight", "get_backlight");
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "backlight_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_BACKLIGHT);
ADD_GROUP("Refraction", "refraction_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "refraction_enabled"), "set_feature", "get_feature", FEATURE_REFRACTION);
@@ -2362,7 +2456,8 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_AMBIENT_OCCLUSION);
BIND_ENUM_CONSTANT(TEXTURE_HEIGHTMAP);
BIND_ENUM_CONSTANT(TEXTURE_SUBSURFACE_SCATTERING);
- BIND_ENUM_CONSTANT(TEXTURE_TRANSMISSION);
+ BIND_ENUM_CONSTANT(TEXTURE_SUBSURFACE_TRANSMITTANCE);
+ BIND_ENUM_CONSTANT(TEXTURE_BACKLIGHT);
BIND_ENUM_CONSTANT(TEXTURE_REFRACTION);
BIND_ENUM_CONSTANT(TEXTURE_DETAIL_MASK);
BIND_ENUM_CONSTANT(TEXTURE_DETAIL_ALBEDO);
@@ -2399,8 +2494,9 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_ANISOTROPY);
BIND_ENUM_CONSTANT(FEATURE_AMBIENT_OCCLUSION);
BIND_ENUM_CONSTANT(FEATURE_HEIGHT_MAPPING);
- BIND_ENUM_CONSTANT(FEATURE_SUBSURACE_SCATTERING);
- BIND_ENUM_CONSTANT(FEATURE_TRANSMISSION);
+ BIND_ENUM_CONSTANT(FEATURE_SUBSURFACE_SCATTERING);
+ BIND_ENUM_CONSTANT(FEATURE_SUBSURFACE_TRANSMITTANCE);
+ BIND_ENUM_CONSTANT(FEATURE_BACKLIGHT);
BIND_ENUM_CONSTANT(FEATURE_REFRACTION);
BIND_ENUM_CONSTANT(FEATURE_DETAIL);
BIND_ENUM_CONSTANT(FEATURE_MAX);
@@ -2436,6 +2532,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY);
BIND_ENUM_CONSTANT(FLAG_USE_TEXTURE_REPEAT);
BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP);
+ BIND_ENUM_CONSTANT(FLAG_SUBSURFACE_MODE_SKIN);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
@@ -2491,7 +2588,11 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_anisotropy(0);
set_heightmap_scale(0.05);
set_subsurface_scattering_strength(0);
- set_transmission(Color(0, 0, 0));
+ set_backlight(Color(0, 0, 0));
+ set_transmittance_color(Color(1, 1, 1, 1));
+ set_transmittance_depth(0.1);
+ set_transmittance_curve(1.0);
+ set_transmittance_boost(0.0);
set_refraction(0.05);
set_point_size(1);
set_uv1_offset(Vector3(0, 0, 0));
@@ -2547,7 +2648,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
features[i] = false;
}
- current_key.key = 0;
+ current_key.key0 = 0;
+ current_key.key1 = 0;
current_key.invalid_key = 1;
texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
_queue_shader_change();
@@ -2561,11 +2663,11 @@ BaseMaterial3D::~BaseMaterial3D() {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
//deallocate shader, as it's no longer in use
- VS::get_singleton()->free(shader_map[current_key].shader);
+ RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
- VS::get_singleton()->material_set_shader(_get_material(), RID());
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
}
}
@@ -2641,7 +2743,7 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value)
{ "depth_flip_binormal", "heightmap_flip_binormal" },
{ "depth_texture", "heightmap_texture" },
- { NULL, NULL },
+ { nullptr, nullptr },
};
int idx = 0;
diff --git a/scene/resources/material.h b/scene/resources/material.h
index fc77226fb9..241357ba9b 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -35,8 +35,8 @@
#include "core/self_list.h"
#include "scene/resources/shader.h"
#include "scene/resources/texture.h"
-#include "servers/visual/shader_language.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/shader_language.h"
+#include "servers/rendering_server.h"
class Material : public Resource {
@@ -57,8 +57,8 @@ protected:
public:
enum {
- RENDER_PRIORITY_MAX = VS::MATERIAL_RENDER_PRIORITY_MAX,
- RENDER_PRIORITY_MIN = VS::MATERIAL_RENDER_PRIORITY_MIN,
+ RENDER_PRIORITY_MAX = RS::MATERIAL_RENDER_PRIORITY_MAX,
+ RENDER_PRIORITY_MIN = RS::MATERIAL_RENDER_PRIORITY_MIN,
};
void set_next_pass(const Ref<Material> &p_pass);
Ref<Material> get_next_pass() const;
@@ -125,7 +125,8 @@ public:
TEXTURE_AMBIENT_OCCLUSION,
TEXTURE_HEIGHTMAP,
TEXTURE_SUBSURFACE_SCATTERING,
- TEXTURE_TRANSMISSION,
+ TEXTURE_SUBSURFACE_TRANSMITTANCE,
+ TEXTURE_BACKLIGHT,
TEXTURE_REFRACTION,
TEXTURE_DETAIL_MASK,
TEXTURE_DETAIL_ALBEDO,
@@ -173,8 +174,9 @@ public:
FEATURE_ANISOTROPY,
FEATURE_AMBIENT_OCCLUSION,
FEATURE_HEIGHT_MAPPING,
- FEATURE_SUBSURACE_SCATTERING,
- FEATURE_TRANSMISSION,
+ FEATURE_SUBSURFACE_SCATTERING,
+ FEATURE_SUBSURFACE_TRANSMITTANCE,
+ FEATURE_BACKLIGHT,
FEATURE_REFRACTION,
FEATURE_DETAIL,
FEATURE_MAX
@@ -218,6 +220,7 @@ public:
FLAG_USE_SHADOW_TO_OPACITY,
FLAG_USE_TEXTURE_REPEAT,
FLAG_INVERT_HEIGHTMAP,
+ FLAG_SUBSURFACE_MODE_SKIN,
FLAG_MAX
};
@@ -290,10 +293,16 @@ private:
uint64_t roughness_channel : 3;
};
- uint64_t key;
+ struct {
+ uint64_t key0;
+ uint64_t key1;
+ };
+ bool operator==(const MaterialKey &p_key) const {
+ return (key0 == p_key.key0) && (key1 == p_key.key1);
+ }
bool operator<(const MaterialKey &p_key) const {
- return key < p_key.key;
+ return (key0 == p_key.key0) ? (key1 < p_key.key1) : (key0 < p_key.key0);
}
};
@@ -309,7 +318,8 @@ private:
_FORCE_INLINE_ MaterialKey _compute_key() const {
MaterialKey mk;
- mk.key = 0;
+ mk.key0 = 0;
+ mk.key1 = 0;
for (int i = 0; i < FEATURE_MAX; i++) {
if (features[i]) {
mk.feature_mask |= ((uint64_t)1 << i);
@@ -356,7 +366,11 @@ private:
StringName anisotropy;
StringName heightmap_scale;
StringName subsurface_scattering_strength;
- StringName transmission;
+ StringName transmittance_color;
+ StringName transmittance_curve;
+ StringName transmittance_depth;
+ StringName transmittance_boost;
+ StringName backlight;
StringName refraction;
StringName point_size;
StringName uv1_scale;
@@ -414,7 +428,13 @@ private:
float anisotropy;
float heightmap_scale;
float subsurface_scattering_strength;
- Color transmission;
+ float transmittance_amount;
+ Color transmittance_color;
+ float transmittance_depth;
+ float transmittance_curve;
+ float transmittance_boost;
+
+ Color backlight;
float refraction;
float point_size;
float alpha_scissor_threshold;
@@ -545,8 +565,20 @@ public:
void set_subsurface_scattering_strength(float p_subsurface_scattering_strength);
float get_subsurface_scattering_strength() const;
- void set_transmission(const Color &p_transmission);
- Color get_transmission() const;
+ void set_transmittance_color(const Color &p_color);
+ Color get_transmittance_color() const;
+
+ void set_transmittance_depth(float p_depth);
+ float get_transmittance_depth() const;
+
+ void set_transmittance_curve(float p_curve);
+ float get_transmittance_curve() const;
+
+ void set_transmittance_boost(float p_boost);
+ float get_transmittance_boost() const;
+
+ void set_backlight(const Color &p_backlight);
+ Color get_backlight() const;
void set_refraction(float p_refraction);
float get_refraction() const;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 5e032c41bf..6bb5be15f3 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -31,13 +31,13 @@
#include "mesh.h"
#include "core/pair.h"
-#include "scene/resources/concave_polygon_shape.h"
-#include "scene/resources/convex_polygon_shape.h"
+#include "scene/resources/concave_polygon_shape_3d.h"
+#include "scene/resources/convex_polygon_shape_3d.h"
#include "surface_tool.h"
#include <stdlib.h>
-Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = NULL;
+Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = nullptr;
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
@@ -169,20 +169,20 @@ Vector<Face3> Mesh::get_faces() const {
/*
for (int i=0;i<surfaces.size();i++) {
- if (VisualServer::get_singleton()->mesh_surface_get_primitive_type( mesh, i ) != VisualServer::PRIMITIVE_TRIANGLES )
+ if (RenderingServer::get_singleton()->mesh_surface_get_primitive_type( mesh, i ) != RenderingServer::PRIMITIVE_TRIANGLES )
continue;
Vector<int> indices;
Vector<Vector3> vertices;
- vertices=VisualServer::get_singleton()->mesh_surface_get_array(mesh, i,VisualServer::ARRAY_VERTEX);
+ vertices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_VERTEX);
- int len=VisualServer::get_singleton()->mesh_surface_get_array_index_len(mesh, i);
+ int len=RenderingServer::get_singleton()->mesh_surface_get_array_index_len(mesh, i);
bool has_indices;
if (len>0) {
- indices=VisualServer::get_singleton()->mesh_surface_get_array(mesh, i,VisualServer::ARRAY_INDEX);
+ indices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_INDEX);
has_indices=true;
} else {
@@ -226,28 +226,28 @@ Vector<Face3> Mesh::get_faces() const {
*/
}
-Ref<Shape> Mesh::create_convex_shape() const {
+Ref<Shape3D> Mesh::create_convex_shape() const {
Vector<Vector3> vertices;
for (int i = 0; i < get_surface_count(); i++) {
Array a = surface_get_arrays(i);
- ERR_FAIL_COND_V(a.empty(), Ref<ConvexPolygonShape>());
+ ERR_FAIL_COND_V(a.empty(), Ref<ConvexPolygonShape3D>());
Vector<Vector3> v = a[ARRAY_VERTEX];
vertices.append_array(v);
}
- Ref<ConvexPolygonShape> shape = memnew(ConvexPolygonShape);
+ Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D);
shape->set_points(vertices);
return shape;
}
-Ref<Shape> Mesh::create_trimesh_shape() const {
+Ref<Shape3D> Mesh::create_trimesh_shape() const {
Vector<Face3> faces = get_faces();
if (faces.size() == 0)
- return Ref<Shape>();
+ return Ref<Shape3D>();
Vector<Vector3> face_points;
face_points.resize(faces.size() * 3);
@@ -260,7 +260,7 @@ Ref<Shape> Mesh::create_trimesh_shape() const {
face_points.set(i + 2, f.vertex[2]);
}
- Ref<ConcavePolygonShape> shape = memnew(ConcavePolygonShape);
+ Ref<ConcavePolygonShape3D> shape = memnew(ConcavePolygonShape3D);
shape->set_faces(face_points);
return shape;
}
@@ -372,7 +372,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
ERR_FAIL_COND_V(arrays.size() != ARRAY_MAX, Ref<ArrayMesh>());
{
- int *ir;
+ int *ir = nullptr;
Vector<int> indices = arrays[ARRAY_INDEX];
bool has_indices = false;
Vector<Vector3> vertices = arrays[ARRAY_VERTEX];
@@ -541,15 +541,15 @@ void Mesh::clear_cache() const {
debug_lines.clear();
}
-Vector<Ref<Shape> > Mesh::convex_decompose() const {
+Vector<Ref<Shape3D>> Mesh::convex_decompose() const {
- ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape> >());
+ ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape3D>>());
const Vector<Face3> faces = get_faces();
- Vector<Vector<Face3> > decomposed = convex_composition_function(faces);
+ Vector<Vector<Face3>> decomposed = convex_composition_function(faces);
- Vector<Ref<Shape> > ret;
+ Vector<Ref<Shape3D>> ret;
for (int i = 0; i < decomposed.size(); i++) {
Set<Vector3> points;
@@ -569,7 +569,7 @@ Vector<Ref<Shape> > Mesh::convex_decompose() const {
}
}
- Ref<ConvexPolygonShape> shape;
+ Ref<ConvexPolygonShape3D> shape;
shape.instance();
shape->set_points(convex_points);
ret.push_back(shape);
@@ -788,7 +788,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
if (d.has("index_count"))
index_count = d["index_count"];
- Vector<Vector<uint8_t> > blend_shapes;
+ Vector<Vector<uint8_t>> blend_shapes;
if (d.has("blend_shape_data")) {
Array blend_shape_data = d["blend_shape_data"];
@@ -846,7 +846,7 @@ Array ArrayMesh::_get_surfaces() const {
Array ret;
for (int i = 0; i < surfaces.size(); i++) {
- VisualServer::SurfaceData surface = VS::get_singleton()->mesh_get_surface(mesh, i);
+ RenderingServer::SurfaceData surface = RS::get_singleton()->mesh_get_surface(mesh, i);
Dictionary data;
data["format"] = surface.format;
data["primitive"] = surface.primitive;
@@ -902,20 +902,20 @@ Array ArrayMesh::_get_surfaces() const {
void ArrayMesh::_create_if_empty() const {
if (!mesh.is_valid()) {
- mesh = VS::get_singleton()->mesh_create();
- VS::get_singleton()->mesh_set_blend_shape_mode(mesh, (VS::BlendShapeMode)blend_shape_mode);
+ mesh = RS::get_singleton()->mesh_create();
+ RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
}
}
void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
- Vector<VS::SurfaceData> surface_data;
- Vector<Ref<Material> > surface_materials;
+ Vector<RS::SurfaceData> surface_data;
+ Vector<Ref<Material>> surface_materials;
Vector<String> surface_names;
Vector<bool> surface_2d;
for (int i = 0; i < p_surfaces.size(); i++) {
- VS::SurfaceData surface;
+ RS::SurfaceData surface;
Dictionary d = p_surfaces[i];
ERR_FAIL_COND(!d.has("format"));
ERR_FAIL_COND(!d.has("primitive"));
@@ -923,7 +923,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
ERR_FAIL_COND(!d.has("vertex_count"));
ERR_FAIL_COND(!d.has("aabb"));
surface.format = d["format"];
- surface.primitive = VS::PrimitiveType(int(d["primitive"]));
+ surface.primitive = RS::PrimitiveType(int(d["primitive"]));
surface.vertex_data = d["vertex_data"];
surface.vertex_count = d["vertex_count"];
surface.aabb = d["aabb"];
@@ -938,7 +938,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
Array lods = d["lods"];
ERR_FAIL_COND(lods.size() & 1); //must be even
for (int j = 0; j < lods.size(); j += 2) {
- VS::SurfaceData::LOD lod;
+ RS::SurfaceData::LOD lod;
lod.edge_length = lods[j + 0];
lod.index_data = lods[j + 1];
surface.lods.push_back(lod);
@@ -993,15 +993,15 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
if (mesh.is_valid()) {
//if mesh exists, it needs to be updated
- VS::get_singleton()->mesh_clear(mesh);
+ RS::get_singleton()->mesh_clear(mesh);
for (int i = 0; i < surface_data.size(); i++) {
- VS::get_singleton()->mesh_add_surface(mesh, surface_data[i]);
+ RS::get_singleton()->mesh_add_surface(mesh, surface_data[i]);
}
} else {
// if mesh does not exist (first time this is loaded, most likely),
// we can create it with a single call, which is a lot more efficient and thread friendly
- mesh = VS::get_singleton()->mesh_create_from_surfaces(surface_data);
- VS::get_singleton()->mesh_set_blend_shape_mode(mesh, (VS::BlendShapeMode)blend_shape_mode);
+ mesh = RS::get_singleton()->mesh_create_from_surfaces(surface_data);
+ RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)blend_shape_mode);
}
surfaces.clear();
@@ -1102,7 +1102,7 @@ void ArrayMesh::_recompute_aabb() {
#ifndef _MSC_VER
#warning need to add binding to add_surface using future MeshSurfaceData object
#endif
-void ArrayMesh::add_surface(uint32_t p_format, 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, const Vector<AABB> &p_bone_aabb, const Vector<VS::SurfaceData::LOD> &p_lods) {
+void ArrayMesh::add_surface(uint32_t p_format, 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, const Vector<AABB> &p_bone_aabb, const Vector<RS::SurfaceData::LOD> &p_lods) {
_create_if_empty();
@@ -1117,9 +1117,9 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
surfaces.push_back(s);
_recompute_aabb();
- VS::SurfaceData sd;
+ RS::SurfaceData sd;
sd.format = p_format;
- sd.primitive = VS::PrimitiveType(p_primitive);
+ sd.primitive = RS::PrimitiveType(p_primitive);
sd.aabb = p_aabb;
sd.vertex_count = p_vertex_count;
sd.vertex_data = p_array;
@@ -1129,7 +1129,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const
sd.bone_aabbs = p_bone_aabb;
sd.lods = p_lods;
- VisualServer::get_singleton()->mesh_add_surface(mesh, sd);
+ RenderingServer::get_singleton()->mesh_add_surface(mesh, sd);
clear_cache();
_change_notify();
@@ -1140,9 +1140,9 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX);
- VS::SurfaceData surface;
+ RS::SurfaceData surface;
- Error err = VS::get_singleton()->mesh_create_surface_data_from_arrays(&surface, (VisualServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_lods, p_flags);
+ Error err = RS::get_singleton()->mesh_create_surface_data_from_arrays(&surface, (RenderingServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_lods, p_flags);
ERR_FAIL_COND(err != OK);
/* print_line("format: " + itos(surface.format));
@@ -1159,16 +1159,16 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
Array ArrayMesh::surface_get_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
- return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
+ return RenderingServer::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
}
Array ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
- return VisualServer::get_singleton()->mesh_surface_get_blend_shape_arrays(mesh, p_surface);
+ return RenderingServer::get_singleton()->mesh_surface_get_blend_shape_arrays(mesh, p_surface);
}
Dictionary ArrayMesh::surface_get_lods(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Dictionary());
- return VisualServer::get_singleton()->mesh_surface_get_lods(mesh, p_surface);
+ return RenderingServer::get_singleton()->mesh_surface_get_lods(mesh, p_surface);
}
int ArrayMesh::get_surface_count() const {
@@ -1193,7 +1193,7 @@ void ArrayMesh::add_blend_shape(const StringName &p_name) {
}
blend_shapes.push_back(name);
- //VS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
+ //RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
}
int ArrayMesh::get_blend_shape_count() const {
@@ -1215,7 +1215,7 @@ void ArrayMesh::set_blend_shape_mode(BlendShapeMode p_mode) {
blend_shape_mode = p_mode;
if (mesh.is_valid()) {
- VS::get_singleton()->mesh_set_blend_shape_mode(mesh, (VS::BlendShapeMode)p_mode);
+ RS::get_singleton()->mesh_set_blend_shape_mode(mesh, (RS::BlendShapeMode)p_mode);
}
}
@@ -1254,7 +1254,7 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material)
if (surfaces[p_idx].material == p_material)
return;
surfaces.write[p_idx].material = p_material;
- VisualServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid());
+ RenderingServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid());
_change_notify("material");
emit_changed();
@@ -1286,7 +1286,7 @@ String ArrayMesh::surface_get_name(int p_idx) const {
void ArrayMesh::surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
ERR_FAIL_INDEX(p_surface, surfaces.size());
- VS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data);
+ RS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data);
emit_changed();
}
@@ -1318,7 +1318,7 @@ void ArrayMesh::clear_surfaces() {
if (!mesh.is_valid()) {
return;
}
- VS::get_singleton()->mesh_clear(mesh);
+ RS::get_singleton()->mesh_clear(mesh);
surfaces.clear();
aabb = AABB();
}
@@ -1327,7 +1327,7 @@ void ArrayMesh::set_custom_aabb(const AABB &p_custom) {
_create_if_empty();
custom_aabb = p_custom;
- VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
emit_changed();
}
@@ -1341,7 +1341,7 @@ void ArrayMesh::regen_normalmaps() {
if (surfaces.size() == 0) {
return;
}
- Vector<Ref<SurfaceTool> > surfs;
+ Vector<Ref<SurfaceTool>> surfs;
for (int i = 0; i < get_surface_count(); i++) {
Ref<SurfaceTool> st = memnew(SurfaceTool);
@@ -1359,7 +1359,7 @@ void ArrayMesh::regen_normalmaps() {
}
//dirty hack
-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, const int *p_face_materials, 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) = NULL;
+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, const int *p_face_materials, 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) = nullptr;
struct ArrayMeshLightmapSurface {
@@ -1379,7 +1379,7 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
Vector<int> indices;
Vector<int> face_materials;
Vector<float> uv;
- Vector<Pair<int, int> > uv_index;
+ Vector<Pair<int, int>> uv_index;
Vector<ArrayMeshLightmapSurface> surfaces;
for (int i = 0; i < get_surface_count(); i++) {
@@ -1472,7 +1472,7 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
clear_surfaces();
//create surfacetools for each surface..
- Vector<Ref<SurfaceTool> > surfaces_tools;
+ Vector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < surfaces.size(); i++) {
Ref<SurfaceTool> st;
@@ -1609,7 +1609,7 @@ void ArrayMesh::_bind_methods() {
}
void ArrayMesh::reload_from_file() {
- VisualServer::get_singleton()->mesh_clear(mesh);
+ RenderingServer::get_singleton()->mesh_clear(mesh);
surfaces.clear();
clear_blend_shapes();
clear_cache();
@@ -1622,13 +1622,13 @@ void ArrayMesh::reload_from_file() {
ArrayMesh::ArrayMesh() {
//mesh is now created on demand
- //mesh = VisualServer::get_singleton()->mesh_create();
+ //mesh = RenderingServer::get_singleton()->mesh_create();
blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE;
}
ArrayMesh::~ArrayMesh() {
if (mesh.is_valid()) {
- VisualServer::get_singleton()->free(mesh);
+ RenderingServer::get_singleton()->free(mesh);
}
}
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 0e356c16a6..25a9722046 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -35,8 +35,8 @@
#include "core/math/triangle_mesh.h"
#include "core/resource.h"
#include "scene/resources/material.h"
-#include "scene/resources/shape.h"
-#include "servers/visual_server.h"
+#include "scene/resources/shape_3d.h"
+#include "servers/rendering_server.h"
class Mesh : public Resource {
GDCLASS(Mesh, Resource);
@@ -51,22 +51,22 @@ protected:
public:
enum {
- NO_INDEX_ARRAY = VisualServer::NO_INDEX_ARRAY,
- ARRAY_WEIGHTS_SIZE = VisualServer::ARRAY_WEIGHTS_SIZE
+ NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY,
+ ARRAY_WEIGHTS_SIZE = RenderingServer::ARRAY_WEIGHTS_SIZE
};
enum ArrayType {
- ARRAY_VERTEX = VisualServer::ARRAY_VERTEX,
- ARRAY_NORMAL = VisualServer::ARRAY_NORMAL,
- ARRAY_TANGENT = VisualServer::ARRAY_TANGENT,
- ARRAY_COLOR = VisualServer::ARRAY_COLOR,
- ARRAY_TEX_UV = VisualServer::ARRAY_TEX_UV,
- ARRAY_TEX_UV2 = VisualServer::ARRAY_TEX_UV2,
- ARRAY_BONES = VisualServer::ARRAY_BONES,
- ARRAY_WEIGHTS = VisualServer::ARRAY_WEIGHTS,
- ARRAY_INDEX = VisualServer::ARRAY_INDEX,
- ARRAY_MAX = VisualServer::ARRAY_MAX
+ ARRAY_VERTEX = RenderingServer::ARRAY_VERTEX,
+ ARRAY_NORMAL = RenderingServer::ARRAY_NORMAL,
+ ARRAY_TANGENT = RenderingServer::ARRAY_TANGENT,
+ ARRAY_COLOR = RenderingServer::ARRAY_COLOR,
+ ARRAY_TEX_UV = RenderingServer::ARRAY_TEX_UV,
+ ARRAY_TEX_UV2 = RenderingServer::ARRAY_TEX_UV2,
+ ARRAY_BONES = RenderingServer::ARRAY_BONES,
+ ARRAY_WEIGHTS = RenderingServer::ARRAY_WEIGHTS,
+ ARRAY_INDEX = RenderingServer::ARRAY_INDEX,
+ ARRAY_MAX = RenderingServer::ARRAY_MAX
};
@@ -98,18 +98,18 @@ public:
};
enum PrimitiveType {
- PRIMITIVE_POINTS = VisualServer::PRIMITIVE_POINTS,
- PRIMITIVE_LINES = VisualServer::PRIMITIVE_LINES,
- PRIMITIVE_LINE_STRIP = VisualServer::PRIMITIVE_LINE_STRIP,
- PRIMITIVE_TRIANGLES = VisualServer::PRIMITIVE_TRIANGLES,
- PRIMITIVE_TRIANGLE_STRIP = VisualServer::PRIMITIVE_TRIANGLE_STRIP,
- PRIMITIVE_MAX = VisualServer::PRIMITIVE_MAX,
+ PRIMITIVE_POINTS = RenderingServer::PRIMITIVE_POINTS,
+ PRIMITIVE_LINES = RenderingServer::PRIMITIVE_LINES,
+ PRIMITIVE_LINE_STRIP = RenderingServer::PRIMITIVE_LINE_STRIP,
+ PRIMITIVE_TRIANGLES = RenderingServer::PRIMITIVE_TRIANGLES,
+ PRIMITIVE_TRIANGLE_STRIP = RenderingServer::PRIMITIVE_TRIANGLE_STRIP,
+ PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX,
};
enum BlendShapeMode {
- BLEND_SHAPE_MODE_NORMALIZED = VS::BLEND_SHAPE_MODE_NORMALIZED,
- BLEND_SHAPE_MODE_RELATIVE = VS::BLEND_SHAPE_MODE_RELATIVE,
+ BLEND_SHAPE_MODE_NORMALIZED = RS::BLEND_SHAPE_MODE_NORMALIZED,
+ BLEND_SHAPE_MODE_RELATIVE = RS::BLEND_SHAPE_MODE_RELATIVE,
};
virtual int get_surface_count() const = 0;
@@ -131,8 +131,8 @@ public:
void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
void generate_debug_mesh_indices(Vector<Vector3> &r_points);
- Ref<Shape> create_trimesh_shape() const;
- Ref<Shape> create_convex_shape() const;
+ Ref<Shape3D> create_trimesh_shape() const;
+ Ref<Shape3D> create_convex_shape() const;
Ref<Mesh> create_outline(float p_margin) const;
@@ -142,11 +142,11 @@ public:
Size2 get_lightmap_size_hint() const;
void clear_cache() const;
- typedef Vector<Vector<Face3> > (*ConvexDecompositionFunc)(const Vector<Face3> &);
+ typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &);
static ConvexDecompositionFunc convex_composition_function;
- Vector<Ref<Shape> > convex_decompose() const;
+ Vector<Ref<Shape3D>> convex_decompose() const;
Mesh();
};
@@ -193,7 +193,7 @@ protected:
public:
void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = ARRAY_COMPRESS_DEFAULT);
- void add_surface(uint32_t p_format, 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>(), const Vector<VS::SurfaceData::LOD> &p_lods = Vector<VS::SurfaceData::LOD>());
+ void add_surface(uint32_t p_format, 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>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
Array surface_get_arrays(int p_surface) const;
Array surface_get_blend_shape_arrays(int p_surface) const;
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 675cfc6d64..76d96786bc 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -58,30 +58,30 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
const Vector3 *vr = varray.ptr();
- const Vector3 *nr;
+ const Vector3 *nr = nullptr;
if (arrays[Mesh::ARRAY_NORMAL].get_type() != Variant::NIL)
nr = arrays[Mesh::ARRAY_NORMAL].operator Vector<Vector3>().ptr();
- const real_t *ta;
+ const real_t *ta = nullptr;
if (arrays[Mesh::ARRAY_TANGENT].get_type() != Variant::NIL)
ta = arrays[Mesh::ARRAY_TANGENT].operator Vector<real_t>().ptr();
- const Vector2 *uv;
+ const Vector2 *uv = nullptr;
if (arrays[Mesh::ARRAY_TEX_UV].get_type() != Variant::NIL)
uv = arrays[Mesh::ARRAY_TEX_UV].operator Vector<Vector2>().ptr();
- const Vector2 *uv2;
+ const Vector2 *uv2 = nullptr;
if (arrays[Mesh::ARRAY_TEX_UV2].get_type() != Variant::NIL)
uv2 = arrays[Mesh::ARRAY_TEX_UV2].operator Vector<Vector2>().ptr();
- const Color *col;
+ const Color *col = nullptr;
if (arrays[Mesh::ARRAY_COLOR].get_type() != Variant::NIL)
col = arrays[Mesh::ARRAY_COLOR].operator Vector<Color>().ptr();
- const int *bo;
+ const int *bo = nullptr;
if (arrays[Mesh::ARRAY_BONES].get_type() != Variant::NIL)
bo = arrays[Mesh::ARRAY_BONES].operator Vector<int>().ptr();
- const real_t *we;
+ const real_t *we = nullptr;
if (arrays[Mesh::ARRAY_WEIGHTS].get_type() != Variant::NIL)
we = arrays[Mesh::ARRAY_WEIGHTS].operator Vector<real_t>().ptr();
@@ -202,43 +202,43 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) {
v.resize(vcount);
Vector3 *vr = v.ptrw();
- Vector3 *nr;
+ Vector3 *nr = nullptr;
if (format & Mesh::ARRAY_FORMAT_NORMAL) {
n.resize(vcount);
nr = n.ptrw();
}
- real_t *ta;
+ real_t *ta = nullptr;
if (format & Mesh::ARRAY_FORMAT_TANGENT) {
t.resize(vcount * 4);
ta = t.ptrw();
}
- Vector2 *uv;
+ Vector2 *uv = nullptr;
if (format & Mesh::ARRAY_FORMAT_TEX_UV) {
u.resize(vcount);
uv = u.ptrw();
}
- Vector2 *uv2;
+ Vector2 *uv2 = nullptr;
if (format & Mesh::ARRAY_FORMAT_TEX_UV2) {
u2.resize(vcount);
uv2 = u2.ptrw();
}
- Color *col;
+ Color *col = nullptr;
if (format & Mesh::ARRAY_FORMAT_COLOR) {
c.resize(vcount);
col = c.ptrw();
}
- int *bo;
+ int *bo = nullptr;
if (format & Mesh::ARRAY_FORMAT_BONES) {
b.resize(vcount * 4);
bo = b.ptrw();
}
- real_t *we;
+ real_t *we = nullptr;
if (format & Mesh::ARRAY_FORMAT_WEIGHTS) {
w.resize(vcount * 4);
we = w.ptrw();
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index b256e86b96..55001f2545 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -34,8 +34,8 @@
#include "core/map.h"
#include "core/resource.h"
#include "mesh.h"
-#include "scene/3d/navigation_region.h"
-#include "shape.h"
+#include "scene/3d/navigation_region_3d.h"
+#include "shape_3d.h"
class MeshLibrary : public Resource {
@@ -44,7 +44,7 @@ class MeshLibrary : public Resource {
public:
struct ShapeData {
- Ref<Shape> shape;
+ Ref<Shape3D> shape;
Transform local_transform;
};
struct Item {
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index aa8be326f5..ce561bfaaf 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -30,7 +30,7 @@
#include "multimesh.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
#ifndef DISABLE_DEPRECATED
// Kept for compatibility from 3.x to 4.0.
@@ -198,20 +198,20 @@ Vector<Color> MultiMesh::_get_custom_data_array() const {
#endif // DISABLE_DEPRECATED
void MultiMesh::set_buffer(const Vector<float> &p_buffer) {
- VS::get_singleton()->multimesh_set_buffer(multimesh, p_buffer);
+ RS::get_singleton()->multimesh_set_buffer(multimesh, p_buffer);
}
Vector<float> MultiMesh::get_buffer() const {
- return VS::get_singleton()->multimesh_get_buffer(multimesh);
+ return RS::get_singleton()->multimesh_get_buffer(multimesh);
}
void MultiMesh::set_mesh(const Ref<Mesh> &p_mesh) {
mesh = p_mesh;
if (!mesh.is_null())
- VisualServer::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid());
+ RenderingServer::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid());
else
- VisualServer::get_singleton()->multimesh_set_mesh(multimesh, RID());
+ RenderingServer::get_singleton()->multimesh_set_mesh(multimesh, RID());
}
Ref<Mesh> MultiMesh::get_mesh() const {
@@ -221,7 +221,7 @@ Ref<Mesh> MultiMesh::get_mesh() const {
void MultiMesh::set_instance_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
- VisualServer::get_singleton()->multimesh_allocate(multimesh, p_count, VS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data);
+ RenderingServer::get_singleton()->multimesh_allocate(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data);
instance_count = p_count;
}
int MultiMesh::get_instance_count() const {
@@ -232,7 +232,7 @@ int MultiMesh::get_instance_count() const {
void MultiMesh::set_visible_instance_count(int p_count) {
ERR_FAIL_COND(p_count < -1);
ERR_FAIL_COND(p_count > instance_count);
- VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, p_count);
+ RenderingServer::get_singleton()->multimesh_set_visible_instances(multimesh, p_count);
visible_instance_count = p_count;
}
int MultiMesh::get_visible_instance_count() const {
@@ -242,45 +242,45 @@ int MultiMesh::get_visible_instance_count() const {
void MultiMesh::set_instance_transform(int p_instance, const Transform &p_transform) {
- VisualServer::get_singleton()->multimesh_instance_set_transform(multimesh, p_instance, p_transform);
+ RenderingServer::get_singleton()->multimesh_instance_set_transform(multimesh, p_instance, p_transform);
}
void MultiMesh::set_instance_transform_2d(int p_instance, const Transform2D &p_transform) {
- VisualServer::get_singleton()->multimesh_instance_set_transform_2d(multimesh, p_instance, p_transform);
+ RenderingServer::get_singleton()->multimesh_instance_set_transform_2d(multimesh, p_instance, p_transform);
}
Transform MultiMesh::get_instance_transform(int p_instance) const {
- return VisualServer::get_singleton()->multimesh_instance_get_transform(multimesh, p_instance);
+ return RenderingServer::get_singleton()->multimesh_instance_get_transform(multimesh, p_instance);
}
Transform2D MultiMesh::get_instance_transform_2d(int p_instance) const {
- return VisualServer::get_singleton()->multimesh_instance_get_transform_2d(multimesh, p_instance);
+ return RenderingServer::get_singleton()->multimesh_instance_get_transform_2d(multimesh, p_instance);
}
void MultiMesh::set_instance_color(int p_instance, const Color &p_color) {
- VisualServer::get_singleton()->multimesh_instance_set_color(multimesh, p_instance, p_color);
+ RenderingServer::get_singleton()->multimesh_instance_set_color(multimesh, p_instance, p_color);
}
Color MultiMesh::get_instance_color(int p_instance) const {
- return VisualServer::get_singleton()->multimesh_instance_get_color(multimesh, p_instance);
+ return RenderingServer::get_singleton()->multimesh_instance_get_color(multimesh, p_instance);
}
void MultiMesh::set_instance_custom_data(int p_instance, const Color &p_custom_data) {
- VisualServer::get_singleton()->multimesh_instance_set_custom_data(multimesh, p_instance, p_custom_data);
+ RenderingServer::get_singleton()->multimesh_instance_set_custom_data(multimesh, p_instance, p_custom_data);
}
Color MultiMesh::get_instance_custom_data(int p_instance) const {
- return VisualServer::get_singleton()->multimesh_instance_get_custom_data(multimesh, p_instance);
+ return RenderingServer::get_singleton()->multimesh_instance_get_custom_data(multimesh, p_instance);
}
AABB MultiMesh::get_aabb() const {
- return VisualServer::get_singleton()->multimesh_get_aabb(multimesh);
+ return RenderingServer::get_singleton()->multimesh_get_aabb(multimesh);
}
RID MultiMesh::get_rid() const {
@@ -375,7 +375,7 @@ void MultiMesh::_bind_methods() {
MultiMesh::MultiMesh() {
- multimesh = VisualServer::get_singleton()->multimesh_create();
+ multimesh = RenderingServer::get_singleton()->multimesh_create();
use_colors = false;
use_custom_data = false;
transform_format = TRANSFORM_2D;
@@ -385,5 +385,5 @@ MultiMesh::MultiMesh() {
MultiMesh::~MultiMesh() {
- VisualServer::get_singleton()->free(multimesh);
+ RenderingServer::get_singleton()->free(multimesh);
}
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index 8ca30a5b88..c1e52bc981 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -32,7 +32,7 @@
#define MULTIMESH_H
#include "scene/resources/mesh.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
class MultiMesh : public Resource {
@@ -41,8 +41,8 @@ class MultiMesh : public Resource {
public:
enum TransformFormat {
- TRANSFORM_2D = VS::MULTIMESH_TRANSFORM_2D,
- TRANSFORM_3D = VS::MULTIMESH_TRANSFORM_3D
+ TRANSFORM_2D = RS::MULTIMESH_TRANSFORM_2D,
+ TRANSFORM_3D = RS::MULTIMESH_TRANSFORM_3D
};
private:
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 0538f679cc..633771506e 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -35,7 +35,7 @@
#include "core/io/resource_loader.h"
#include "core/project_settings.h"
#include "scene/2d/node_2d.h"
-#include "scene/3d/spatial.h"
+#include "scene/3d/node_3d.h"
#include "scene/gui/control.h"
#include "scene/main/instance_placeholder.h"
@@ -51,25 +51,25 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
// nodes where instancing failed (because something is missing)
List<Node *> stray_instances;
-#define NODE_FROM_ID(p_name, p_id) \
- Node *p_name; \
- if (p_id & FLAG_ID_IS_PATH) { \
- NodePath np = node_paths[p_id & FLAG_MASK]; \
- p_name = ret_nodes[0]->get_node_or_null(np); \
- } else { \
- ERR_FAIL_INDEX_V(p_id &FLAG_MASK, nc, NULL); \
- p_name = ret_nodes[p_id & FLAG_MASK]; \
+#define NODE_FROM_ID(p_name, p_id) \
+ Node *p_name; \
+ if (p_id & FLAG_ID_IS_PATH) { \
+ NodePath np = node_paths[p_id & FLAG_MASK]; \
+ p_name = ret_nodes[0]->get_node_or_null(np); \
+ } else { \
+ ERR_FAIL_INDEX_V(p_id &FLAG_MASK, nc, nullptr); \
+ p_name = ret_nodes[p_id & FLAG_MASK]; \
}
int nc = nodes.size();
- ERR_FAIL_COND_V(nc == 0, NULL);
+ ERR_FAIL_COND_V(nc == 0, nullptr);
- const StringName *snames = NULL;
+ const StringName *snames = nullptr;
int sname_count = names.size();
if (sname_count)
snames = &names[0];
- const Variant *props = NULL;
+ const Variant *props = nullptr;
int prop_count = variants.size();
if (prop_count)
props = &variants[0];
@@ -82,17 +82,17 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.empty();
- Map<Ref<Resource>, Ref<Resource> > resources_local_to_scene;
+ Map<Ref<Resource>, Ref<Resource>> resources_local_to_scene;
for (int i = 0; i < nc; i++) {
const NodeData &n = nd[i];
- Node *parent = NULL;
+ Node *parent = nullptr;
if (i > 0) {
- ERR_FAIL_COND_V_MSG(n.parent == -1, NULL, vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name]));
+ ERR_FAIL_COND_V_MSG(n.parent == -1, nullptr, vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name]));
NODE_FROM_ID(nparent, n.parent);
#ifdef DEBUG_ENABLED
if (!nparent && (n.parent & FLAG_ID_IS_PATH)) {
@@ -103,14 +103,14 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
parent = nparent;
}
- Node *node = NULL;
+ Node *node = nullptr;
if (i == 0 && base_scene_idx >= 0) {
//scene inheritance on root node
Ref<PackedScene> sdata = props[base_scene_idx];
- ERR_FAIL_COND_V(!sdata.is_valid(), NULL);
+ ERR_FAIL_COND_V(!sdata.is_valid(), nullptr);
node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); //only main gets main edit state
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
if (p_edit_state != GEN_EDIT_STATE_DISABLED) {
node->set_scene_inherited_state(sdata->get_state());
}
@@ -123,9 +123,9 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (disable_placeholders) {
Ref<PackedScene> sdata = ResourceLoader::load(path, "PackedScene");
- ERR_FAIL_COND_V(!sdata.is_valid(), NULL);
+ ERR_FAIL_COND_V(!sdata.is_valid(), nullptr);
node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE);
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
} else {
InstancePlaceholder *ip = memnew(InstancePlaceholder);
ip->set_instance_path(path);
@@ -134,9 +134,9 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
node->set_scene_instance_load_placeholder(true);
} else {
Ref<PackedScene> sdata = props[n.instance & FLAG_MASK];
- ERR_FAIL_COND_V(!sdata.is_valid(), NULL);
+ ERR_FAIL_COND_V(!sdata.is_valid(), nullptr);
node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE);
- ERR_FAIL_COND_V(!node, NULL);
+ ERR_FAIL_COND_V(!node, nullptr);
}
} else if (n.type == TYPE_INSTANCED) {
@@ -155,12 +155,12 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (!Object::cast_to<Node>(obj)) {
if (obj) {
memdelete(obj);
- obj = NULL;
+ obj = nullptr;
}
WARN_PRINT(String("Warning node of type " + snames[n.type].operator String() + " does not exist.").ascii().get_data());
if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) {
- if (Object::cast_to<Spatial>(ret_nodes[n.parent])) {
- obj = memnew(Spatial);
+ if (Object::cast_to<Node3D>(ret_nodes[n.parent])) {
+ obj = memnew(Node3D);
} else if (Object::cast_to<Control>(ret_nodes[n.parent])) {
obj = memnew(Control);
} else if (Object::cast_to<Node2D>(ret_nodes[n.parent])) {
@@ -193,15 +193,15 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
for (int j = 0; j < nprop_count; j++) {
bool valid;
- ERR_FAIL_INDEX_V(nprops[j].name, sname_count, NULL);
- ERR_FAIL_INDEX_V(nprops[j].value, prop_count, NULL);
+ ERR_FAIL_INDEX_V(nprops[j].name, sname_count, nullptr);
+ ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
if (snames[nprops[j].name] == CoreStringNames::get_singleton()->_script) {
//work around to avoid old script variables from disappearing, should be the proper fix to:
//https://github.com/godotengine/godot/issues/2958
//store old state
- List<Pair<StringName, Variant> > old_state;
+ List<Pair<StringName, Variant>> old_state;
if (node->get_script_instance()) {
node->get_script_instance()->get_property_state(old_state);
}
@@ -209,7 +209,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
node->set(snames[nprops[j].name], props[nprops[j].value], &valid);
//restore old state for new script, if exists
- for (List<Pair<StringName, Variant> >::Element *E = old_state.front(); E; E = E->next()) {
+ for (List<Pair<StringName, Variant>>::Element *E = old_state.front(); E; E = E->next()) {
node->set(E->get().first, E->get().second);
}
} else {
@@ -222,7 +222,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (res.is_valid()) {
if (res->is_local_to_scene()) {
- Map<Ref<Resource>, Ref<Resource> >::Element *E = resources_local_to_scene.find(res);
+ Map<Ref<Resource>, Ref<Resource>>::Element *E = resources_local_to_scene.find(res);
if (E) {
value = E->get();
@@ -260,7 +260,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
//groups
for (int j = 0; j < n.groups.size(); j++) {
- ERR_FAIL_INDEX_V(n.groups[j], sname_count, NULL);
+ ERR_FAIL_INDEX_V(n.groups[j], sname_count, nullptr);
node->add_to_group(snames[n.groups[j]], true);
}
@@ -302,7 +302,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
}
- for (Map<Ref<Resource>, Ref<Resource> >::Element *E = resources_local_to_scene.front(); E; E = E->next()) {
+ for (Map<Ref<Resource>, Ref<Resource>>::Element *E = resources_local_to_scene.front(); E; E = E->next()) {
E->get()->setup_local_to_scene();
}
@@ -315,8 +315,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
for (int i = 0; i < cc; i++) {
const ConnectionData &c = cdata[i];
- //ERR_FAIL_INDEX_V( c.from, nc, NULL );
- //ERR_FAIL_INDEX_V( c.to, nc, NULL );
+ //ERR_FAIL_INDEX_V( c.from, nc, nullptr );
+ //ERR_FAIL_INDEX_V( c.to, nc, nullptr );
NODE_FROM_ID(cfrom, c.from);
NODE_FROM_ID(cto, c.to);
@@ -450,7 +450,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
nd.instance = _vm_get_variant(instance, variant_map);
}
}
- n = NULL;
+ n = nullptr;
} else {
if (n->get_filename() != String()) {
//is an instance
@@ -773,7 +773,7 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, Map<StringName
}
}
- nl = NULL;
+ nl = nullptr;
} else {
if (nl->get_filename() != String()) {
//is an instance
@@ -896,7 +896,7 @@ Error SceneState::pack(Node *p_scene) {
}
variants.resize(variant_map.size());
- const Variant *K = NULL;
+ const Variant *K = nullptr;
while ((K = variant_map.next(K))) {
int idx = variant_map[*K];
@@ -1689,12 +1689,12 @@ bool PackedScene::can_instance() const {
Node *PackedScene::instance(GenEditState p_edit_state) const {
#ifndef TOOLS_ENABLED
- ERR_FAIL_COND_V_MSG(p_edit_state != GEN_EDIT_STATE_DISABLED, NULL, "Edit state is only for editors, does not work without tools compiled.");
+ ERR_FAIL_COND_V_MSG(p_edit_state != GEN_EDIT_STATE_DISABLED, nullptr, "Edit state is only for editors, does not work without tools compiled.");
#endif
Node *s = state->instance((SceneState::GenEditState)p_edit_state);
if (!s)
- return NULL;
+ return nullptr;
if (p_edit_state != GEN_EDIT_STATE_DISABLED) {
s->set_scene_instance_state(state);
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index f18e8956f1..83430aef9e 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -31,9 +31,9 @@
#include "particles_material.h"
Mutex ParticlesMaterial::material_mutex;
-SelfList<ParticlesMaterial>::List *ParticlesMaterial::dirty_materials = NULL;
+SelfList<ParticlesMaterial>::List *ParticlesMaterial::dirty_materials = nullptr;
Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map;
-ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = NULL;
+ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = nullptr;
void ParticlesMaterial::init_shaders() {
@@ -104,7 +104,7 @@ void ParticlesMaterial::init_shaders() {
void ParticlesMaterial::finish_shaders() {
memdelete(dirty_materials);
- dirty_materials = NULL;
+ dirty_materials = nullptr;
memdelete(shader_names);
}
@@ -121,7 +121,7 @@ void ParticlesMaterial::_update_shader() {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
//deallocate shader, as it's no longer in use
- VS::get_singleton()->free(shader_map[current_key].shader);
+ RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
}
@@ -130,7 +130,7 @@ void ParticlesMaterial::_update_shader() {
if (shader_map.has(mk)) {
- VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
shader_map[mk].users++;
return;
}
@@ -592,14 +592,14 @@ void ParticlesMaterial::_update_shader() {
code += "\n";
ShaderData shader_data;
- shader_data.shader = VS::get_singleton()->shader_create();
+ shader_data.shader = RS::get_singleton()->shader_create();
shader_data.users = 1;
- VS::get_singleton()->shader_set_code(shader_data.shader, code);
+ RS::get_singleton()->shader_set_code(shader_data.shader, code);
shader_map[mk] = shader_data;
- VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+ RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
}
void ParticlesMaterial::flush_changes() {
@@ -631,7 +631,7 @@ bool ParticlesMaterial::_is_shader_dirty() const {
void ParticlesMaterial::set_direction(Vector3 p_direction) {
direction = p_direction;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction);
}
Vector3 ParticlesMaterial::get_direction() const {
@@ -642,7 +642,7 @@ Vector3 ParticlesMaterial::get_direction() const {
void ParticlesMaterial::set_spread(float p_spread) {
spread = p_spread;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
}
float ParticlesMaterial::get_spread() const {
@@ -653,7 +653,7 @@ float ParticlesMaterial::get_spread() const {
void ParticlesMaterial::set_flatness(float p_flatness) {
flatness = p_flatness;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
}
float ParticlesMaterial::get_flatness() const {
@@ -668,40 +668,40 @@ void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value);
} break;
case PARAM_ANGULAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value);
} break;
case PARAM_ORBIT_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value);
} break;
case PARAM_LINEAR_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value);
} break;
case PARAM_RADIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value);
} break;
case PARAM_TANGENTIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value);
} break;
case PARAM_DAMPING: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value);
} break;
case PARAM_ANGLE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value);
} break;
case PARAM_SCALE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value);
} break;
case PARAM_HUE_VARIATION: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value);
} break;
case PARAM_ANIM_SPEED: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value);
} break;
case PARAM_ANIM_OFFSET: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
} break;
case PARAM_MAX: break; // Can't happen, but silences warning
}
@@ -721,40 +721,40 @@ void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value);
} break;
case PARAM_ANGULAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value);
} break;
case PARAM_ORBIT_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value);
} break;
case PARAM_LINEAR_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value);
} break;
case PARAM_RADIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value);
} break;
case PARAM_TANGENTIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value);
} break;
case PARAM_DAMPING: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value);
} break;
case PARAM_ANGLE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value);
} break;
case PARAM_SCALE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value);
} break;
case PARAM_HUE_VARIATION: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value);
} break;
case PARAM_ANIM_SPEED: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value);
} break;
case PARAM_ANIM_OFFSET: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
} break;
case PARAM_MAX: break; // Can't happen, but silences warning
}
@@ -786,47 +786,47 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D
//do none for this one
} break;
case PARAM_ANGULAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture);
_adjust_curve_range(p_texture, -360, 360);
} break;
case PARAM_ORBIT_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture);
_adjust_curve_range(p_texture, -500, 500);
} break;
case PARAM_LINEAR_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture);
_adjust_curve_range(p_texture, -200, 200);
} break;
case PARAM_RADIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture);
_adjust_curve_range(p_texture, -200, 200);
} break;
case PARAM_TANGENTIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture);
_adjust_curve_range(p_texture, -200, 200);
} break;
case PARAM_DAMPING: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture);
_adjust_curve_range(p_texture, 0, 100);
} break;
case PARAM_ANGLE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture);
_adjust_curve_range(p_texture, -360, 360);
} break;
case PARAM_SCALE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture);
_adjust_curve_range(p_texture, 0, 1);
} break;
case PARAM_HUE_VARIATION: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture);
_adjust_curve_range(p_texture, -1, 1);
} break;
case PARAM_ANIM_SPEED: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture);
_adjust_curve_range(p_texture, 0, 200);
} break;
case PARAM_ANIM_OFFSET: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
} break;
case PARAM_MAX: break; // Can't happen, but silences warning
}
@@ -842,7 +842,7 @@ Ref<Texture2D> ParticlesMaterial::get_param_texture(Parameter p_param) const {
void ParticlesMaterial::set_color(const Color &p_color) {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
color = p_color;
}
@@ -854,7 +854,7 @@ Color ParticlesMaterial::get_color() const {
void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
color_ramp = p_texture;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture);
_queue_shader_change();
_change_notify();
}
@@ -888,38 +888,38 @@ void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
void ParticlesMaterial::set_emission_sphere_radius(float p_radius) {
emission_sphere_radius = p_radius;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
}
void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
emission_box_extents = p_extents;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
}
void ParticlesMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) {
emission_point_texture = p_points;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points);
}
void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) {
emission_normal_texture = p_normals;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals);
}
void ParticlesMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) {
emission_color_texture = p_colors;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors);
_queue_shader_change();
}
void ParticlesMaterial::set_emission_point_count(int p_count) {
emission_point_count = p_count;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
}
ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const {
@@ -957,7 +957,7 @@ int ParticlesMaterial::get_emission_point_count() const {
void ParticlesMaterial::set_trail_divisor(int p_divisor) {
trail_divisor = p_divisor;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor);
}
int ParticlesMaterial::get_trail_divisor() const {
@@ -974,7 +974,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail
curve->ensure_default_setup();
}
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
_queue_shader_change();
}
@@ -986,7 +986,7 @@ Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
trail_color_modifier = p_trail_color_modifier;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
_queue_shader_change();
}
@@ -1002,7 +1002,7 @@ void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
if (gset == Vector3()) {
gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations
}
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset);
}
Vector3 ParticlesMaterial::get_gravity() const {
@@ -1013,7 +1013,7 @@ Vector3 ParticlesMaterial::get_gravity() const {
void ParticlesMaterial::set_lifetime_randomness(float p_lifetime) {
lifetime_randomness = p_lifetime;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness);
}
float ParticlesMaterial::get_lifetime_randomness() const {
@@ -1280,10 +1280,10 @@ ParticlesMaterial::~ParticlesMaterial() {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
//deallocate shader, as it's no longer in use
- VS::get_singleton()->free(shader_map[current_key].shader);
+ RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
- VS::get_singleton()->material_set_shader(_get_material(), RID());
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
}
}
diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h
index 2f7f4424b2..f4a77d9854 100644
--- a/scene/resources/physics_material.h
+++ b/scene/resources/physics_material.h
@@ -32,7 +32,7 @@
#define physics_material_override_H
#include "core/resource.h"
-#include "servers/physics_server.h"
+#include "servers/physics_server_3d.h"
class PhysicsMaterial : public Resource {
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index eff0721cef..c3daedf918 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -42,7 +42,7 @@ bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const {
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
- if (Geometry::segment_intersects_segment_2d(a, b, p_point, outside_point, NULL)) {
+ if (Geometry::segment_intersects_segment_2d(a, b, p_point, outside_point, nullptr)) {
crosses++;
}
}
@@ -119,7 +119,7 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
- if (Geometry::segment_intersects_segment_2d(a, b, from, to, NULL)) {
+ if (Geometry::segment_intersects_segment_2d(a, b, from, to, nullptr)) {
valid = false;
break;
}
@@ -209,7 +209,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
- if (Geometry::segment_intersects_segment_2d(a, b, from, to, NULL)) {
+ if (Geometry::segment_intersects_segment_2d(a, b, from, to, nullptr)) {
can_see_eachother = false;
break;
}
@@ -268,7 +268,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
e.points[0] != ignore_from_edge.points[0] &&
e.points[1] != ignore_from_edge.points[0]) {
- if (Geometry::segment_intersects_segment_2d(a, b, from, points[i].pos, NULL)) {
+ if (Geometry::segment_intersects_segment_2d(a, b, from, points[i].pos, nullptr)) {
valid_a = false;
}
}
@@ -281,7 +281,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
e.points[0] != ignore_to_edge.points[0] &&
e.points[1] != ignore_to_edge.points[0]) {
- if (Geometry::segment_intersects_segment_2d(a, b, to, points[i].pos, NULL)) {
+ if (Geometry::segment_intersects_segment_2d(a, b, to, points[i].pos, nullptr)) {
valid_b = false;
}
}
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 959ee214a2..46e8575018 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "primitive_meshes.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
/**
PrimitiveMesh
@@ -37,10 +37,10 @@
void PrimitiveMesh::_update() const {
Array arr;
- arr.resize(VS::ARRAY_MAX);
+ arr.resize(RS::ARRAY_MAX);
_create_mesh_array(arr);
- Vector<Vector3> points = arr[VS::ARRAY_VERTEX];
+ Vector<Vector3> points = arr[RS::ARRAY_VERTEX];
aabb = AABB();
@@ -57,10 +57,10 @@ void PrimitiveMesh::_update() const {
}
}
- Vector<int> indices = arr[VS::ARRAY_INDEX];
+ Vector<int> indices = arr[RS::ARRAY_INDEX];
if (flip_faces) {
- Vector<Vector3> normals = arr[VS::ARRAY_NORMAL];
+ Vector<Vector3> normals = arr[RS::ARRAY_NORMAL];
if (normals.size() && indices.size()) {
@@ -79,17 +79,17 @@ void PrimitiveMesh::_update() const {
SWAP(w[i + 0], w[i + 1]);
}
}
- arr[VS::ARRAY_NORMAL] = normals;
- arr[VS::ARRAY_INDEX] = indices;
+ arr[RS::ARRAY_NORMAL] = normals;
+ arr[RS::ARRAY_INDEX] = indices;
}
}
array_len = pc;
index_array_len = indices.size();
// in with the new
- VisualServer::get_singleton()->mesh_clear(mesh);
- VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr);
- VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
+ RenderingServer::get_singleton()->mesh_clear(mesh);
+ RenderingServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (RenderingServer::PrimitiveType)primitive_type, arr);
+ RenderingServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
pending_request = false;
@@ -136,7 +136,7 @@ Array PrimitiveMesh::surface_get_arrays(int p_surface) const {
_update();
}
- return VisualServer::get_singleton()->mesh_surface_get_arrays(mesh, 0);
+ return RenderingServer::get_singleton()->mesh_surface_get_arrays(mesh, 0);
}
Dictionary PrimitiveMesh::surface_get_lods(int p_surface) const {
@@ -150,7 +150,7 @@ Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, 1, 0);
- return VS::ARRAY_FORMAT_VERTEX | VS::ARRAY_FORMAT_NORMAL | VS::ARRAY_FORMAT_TANGENT | VS::ARRAY_FORMAT_TEX_UV | VS::ARRAY_FORMAT_INDEX | VS::ARRAY_COMPRESS_DEFAULT;
+ return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX | RS::ARRAY_COMPRESS_DEFAULT;
}
Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {
@@ -164,7 +164,7 @@ void PrimitiveMesh::surface_set_material(int p_idx, const Ref<Material> &p_mater
}
Ref<Material> PrimitiveMesh::surface_get_material(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, 1, NULL);
+ ERR_FAIL_INDEX_V(p_idx, 1, nullptr);
return material;
}
@@ -215,7 +215,7 @@ void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
material = p_material;
if (!pending_request) {
// just apply it, else it'll happen when _update is called.
- VisualServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
+ RenderingServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid());
_change_notify();
emit_changed();
};
@@ -232,7 +232,7 @@ Array PrimitiveMesh::get_mesh_arrays() const {
void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
custom_aabb = p_custom;
- VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
+ RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
emit_changed();
}
@@ -254,7 +254,7 @@ PrimitiveMesh::PrimitiveMesh() {
flip_faces = false;
// defaults
- mesh = VisualServer::get_singleton()->mesh_create();
+ 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;
@@ -267,7 +267,7 @@ PrimitiveMesh::PrimitiveMesh() {
}
PrimitiveMesh::~PrimitiveMesh() {
- VisualServer::get_singleton()->free(mesh);
+ RenderingServer::get_singleton()->free(mesh);
}
/**
@@ -413,11 +413,11 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
};
- p_arr[VS::ARRAY_VERTEX] = points;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
- p_arr[VS::ARRAY_INDEX] = indices;
+ 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_INDEX] = indices;
}
void CapsuleMesh::_bind_methods() {
@@ -670,11 +670,11 @@ void CubeMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
};
- p_arr[VS::ARRAY_VERTEX] = points;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
- p_arr[VS::ARRAY_INDEX] = indices;
+ 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_INDEX] = indices;
}
void CubeMesh::_bind_methods() {
@@ -871,11 +871,11 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const {
};
};
- p_arr[VS::ARRAY_VERTEX] = points;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
- p_arr[VS::ARRAY_INDEX] = indices;
+ 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_INDEX] = indices;
}
void CylinderMesh::_bind_methods() {
@@ -1010,11 +1010,11 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
};
- p_arr[VS::ARRAY_VERTEX] = points;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
- p_arr[VS::ARRAY_INDEX] = indices;
+ 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_INDEX] = indices;
}
void PlaneMesh::_bind_methods() {
@@ -1270,11 +1270,11 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
};
- p_arr[VS::ARRAY_VERTEX] = points;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
- p_arr[VS::ARRAY_INDEX] = indices;
+ 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_INDEX] = indices;
}
void PrismMesh::_bind_methods() {
@@ -1401,10 +1401,10 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
uvs.set(i, quad_uv[j]);
}
- p_arr[VS::ARRAY_VERTEX] = faces;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_VERTEX] = faces;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
}
void QuadMesh::_bind_methods() {
@@ -1494,11 +1494,11 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const {
thisrow = point;
};
- p_arr[VS::ARRAY_VERTEX] = points;
- p_arr[VS::ARRAY_NORMAL] = normals;
- p_arr[VS::ARRAY_TANGENT] = tangents;
- p_arr[VS::ARRAY_TEX_UV] = uvs;
- p_arr[VS::ARRAY_INDEX] = indices;
+ 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_INDEX] = indices;
}
void SphereMesh::_bind_methods() {
@@ -1585,7 +1585,7 @@ void PointMesh::_create_mesh_array(Array &p_arr) const {
faces.resize(1);
faces.set(0, Vector3(0.0, 0.0, 0.0));
- p_arr[VS::ARRAY_VERTEX] = faces;
+ p_arr[RS::ARRAY_VERTEX] = faces;
}
PointMesh::PointMesh() {
diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp
deleted file mode 100644
index 906abaf60c..0000000000
--- a/scene/resources/ray_shape.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*************************************************************************/
-/* ray_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "ray_shape.h"
-
-#include "servers/physics_server.h"
-
-Vector<Vector3> RayShape::get_debug_mesh_lines() {
-
- Vector<Vector3> points;
- points.push_back(Vector3());
- points.push_back(Vector3(0, 0, get_length()));
-
- return points;
-}
-
-real_t RayShape::get_enclosing_radius() const {
- return length;
-}
-
-void RayShape::_update_shape() {
-
- Dictionary d;
- d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
- Shape::_update_shape();
-}
-
-void RayShape::set_length(float p_length) {
-
- length = p_length;
- _update_shape();
- notify_change_to_owners();
- _change_notify("length");
-}
-
-float RayShape::get_length() const {
-
- return length;
-}
-
-void RayShape::set_slips_on_slope(bool p_active) {
-
- slips_on_slope = p_active;
- _update_shape();
- notify_change_to_owners();
- _change_notify("slips_on_slope");
-}
-
-bool RayShape::get_slips_on_slope() const {
- return slips_on_slope;
-}
-
-void RayShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape::set_length);
- ClassDB::bind_method(D_METHOD("get_length"), &RayShape::get_length);
-
- ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape::set_slips_on_slope);
- ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape::get_slips_on_slope);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_length", "get_length");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
-}
-
-RayShape::RayShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::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.h b/scene/resources/ray_shape.h
deleted file mode 100644
index c89705ad7d..0000000000
--- a/scene/resources/ray_shape.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*************************************************************************/
-/* ray_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RAY_SHAPE_H
-#define RAY_SHAPE_H
-#include "scene/resources/shape.h"
-
-class RayShape : public Shape {
-
- GDCLASS(RayShape, Shape);
- float length;
- bool slips_on_slope;
-
-protected:
- static void _bind_methods();
- virtual void _update_shape();
-
-public:
- void set_length(float p_length);
- float get_length() const;
-
- void set_slips_on_slope(bool p_active);
- bool get_slips_on_slope() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- RayShape();
-};
-#endif // RAY_SHAPE_H
diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp
new file mode 100644
index 0000000000..0211c55f46
--- /dev/null
+++ b/scene/resources/ray_shape_3d.cpp
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* ray_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "ray_shape_3d.h"
+
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> RayShape3D::get_debug_mesh_lines() {
+
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ points.push_back(Vector3(0, 0, get_length()));
+
+ return points;
+}
+
+real_t RayShape3D::get_enclosing_radius() const {
+ return length;
+}
+
+void RayShape3D::_update_shape() {
+
+ Dictionary d;
+ d["length"] = length;
+ d["slips_on_slope"] = slips_on_slope;
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+ Shape3D::_update_shape();
+}
+
+void RayShape3D::set_length(float p_length) {
+
+ length = p_length;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("length");
+}
+
+float RayShape3D::get_length() const {
+
+ return length;
+}
+
+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 {
+ return slips_on_slope;
+}
+
+void RayShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape3D::set_length);
+ ClassDB::bind_method(D_METHOD("get_length"), &RayShape3D::get_length);
+
+ ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape3D::set_slips_on_slope);
+ ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape3D::get_slips_on_slope);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
+}
+
+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
new file mode 100644
index 0000000000..83bb71cca3
--- /dev/null
+++ b/scene/resources/ray_shape_3d.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* ray_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RAY_SHAPE_H
+#define RAY_SHAPE_H
+#include "scene/resources/shape_3d.h"
+
+class RayShape3D : public Shape3D {
+
+ GDCLASS(RayShape3D, Shape3D);
+ float length;
+ bool slips_on_slope;
+
+protected:
+ static void _bind_methods();
+ virtual void _update_shape();
+
+public:
+ void set_length(float p_length);
+ float get_length() const;
+
+ void set_slips_on_slope(bool p_active);
+ bool get_slips_on_slope() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ RayShape3D();
+};
+#endif // RAY_SHAPE_H
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index f8c8ffb289..19e72a65b0 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -30,11 +30,11 @@
#include "rectangle_shape_2d.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
void RectangleShape2D::_update_shape() {
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), extents);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), extents);
emit_changed();
}
@@ -51,7 +51,7 @@ Vector2 RectangleShape2D::get_extents() const {
void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- VisualServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-extents, extents * 2.0), p_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-extents, extents * 2.0), p_color);
}
Rect2 RectangleShape2D::get_rect() const {
@@ -72,7 +72,7 @@ void RectangleShape2D::_bind_methods() {
}
RectangleShape2D::RectangleShape2D() :
- Shape2D(Physics2DServer::get_singleton()->rectangle_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->rectangle_shape_create()) {
extents = Vector2(10, 10);
_update_shape();
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 238bdf05ef..5068bb548f 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -795,7 +795,7 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p
ignore_resource_parsing = true;
//FileAccess
- FileAccess *fw = NULL;
+ FileAccess *fw = nullptr;
String base_path = local_path.get_base_dir();
@@ -961,7 +961,7 @@ void ResourceLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) {
rp.ext_func = _parse_ext_resources;
rp.sub_func = _parse_sub_resources;
- rp.func = NULL;
+ rp.func = nullptr;
rp.userdata = this;
}
@@ -1392,7 +1392,7 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
return loader.rename_dependencies(f, p_path, p_map);
}
-ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL;
+ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr;
Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) {
@@ -1674,7 +1674,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
RES res = E->get();
ERR_CONTINUE(!resource_set.has(res));
- bool main = (E->next() == NULL);
+ bool main = (E->next() == nullptr);
if (main && packed_scene.is_valid())
break; //save as a scene
@@ -1880,7 +1880,7 @@ void ResourceFormatSaverText::get_recognized_extensions(const RES &p_resource, L
p_extensions->push_back("tres"); //text resource
}
-ResourceFormatSaverText *ResourceFormatSaverText::singleton = NULL;
+ResourceFormatSaverText *ResourceFormatSaverText::singleton = nullptr;
ResourceFormatSaverText::ResourceFormatSaverText() {
singleton = this;
}
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 2425ac7f6c..fbbd2e3346 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -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 = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index 2e78a4fccf..814c349784 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -30,8 +30,8 @@
#include "segment_shape_2d.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
@@ -45,7 +45,7 @@ void SegmentShape2D::_update_shape() {
Rect2 r;
r.position = a;
r.size = b;
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), r);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), r);
emit_changed();
}
@@ -71,7 +71,7 @@ Vector2 SegmentShape2D::get_b() const {
void SegmentShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- VisualServer::get_singleton()->canvas_item_add_line(p_to_rid, a, b, p_color, 3);
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, a, b, p_color, 3);
}
Rect2 SegmentShape2D::get_rect() const {
@@ -99,7 +99,7 @@ void SegmentShape2D::_bind_methods() {
}
SegmentShape2D::SegmentShape2D() :
- Shape2D(Physics2DServer::get_singleton()->segment_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->segment_shape_create()) {
a = Vector2();
b = Vector2(0, 10);
@@ -113,14 +113,14 @@ void RayShape2D::_update_shape() {
Dictionary d;
d["length"] = length;
d["slips_on_slope"] = slips_on_slope;
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), d);
+ PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), d);
emit_changed();
}
void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector2 tip = Vector2(0, get_length());
- VS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3);
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3);
Vector<Vector2> pts;
float tsize = 4;
pts.push_back(tip + Vector2(0, tsize));
@@ -130,7 +130,7 @@ void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) {
for (int i = 0; i < 3; i++)
cols.push_back(p_color);
- VS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID());
+ RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID());
}
Rect2 RayShape2D::get_rect() const {
@@ -179,7 +179,7 @@ bool RayShape2D::get_slips_on_slope() const {
}
RayShape2D::RayShape2D() :
- Shape2D(Physics2DServer::get_singleton()->ray_shape_create()) {
+ Shape2D(PhysicsServer2D::get_singleton()->ray_shape_create()) {
length = 20;
slips_on_slope = false;
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 8f76c0165f..a62e7ded16 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -31,8 +31,8 @@
#include "shader.h"
#include "core/os/file_access.h"
#include "scene/scene_string_names.h"
-#include "servers/visual/shader_language.h"
-#include "servers/visual_server.h"
+#include "servers/rendering/shader_language.h"
+#include "servers/rendering_server.h"
#include "texture.h"
Shader::Mode Shader::get_mode() const {
@@ -48,11 +48,13 @@ void Shader::set_code(const String &p_code) {
mode = MODE_CANVAS_ITEM;
} else if (type == "particles") {
mode = MODE_PARTICLES;
+ } else if (type == "sky") {
+ mode = MODE_SKY;
} else {
mode = MODE_SPATIAL;
}
- VisualServer::get_singleton()->shader_set_code(shader, p_code);
+ RenderingServer::get_singleton()->shader_set_code(shader, p_code);
params_cache_dirty = true;
emit_changed();
@@ -61,7 +63,7 @@ void Shader::set_code(const String &p_code) {
String Shader::get_code() const {
_update_shader();
- return VisualServer::get_singleton()->shader_get_code(shader);
+ return RenderingServer::get_singleton()->shader_get_code(shader);
}
void Shader::get_param_list(List<PropertyInfo> *p_params) const {
@@ -69,7 +71,7 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
_update_shader();
List<PropertyInfo> local;
- VisualServer::get_singleton()->shader_get_param_list(shader, &local);
+ RenderingServer::get_singleton()->shader_get_param_list(shader, &local);
params_cache.clear();
params_cache_dirty = false;
@@ -102,10 +104,10 @@ void Shader::set_default_texture_param(const StringName &p_param, const Ref<Text
if (p_texture.is_valid()) {
default_textures[p_param] = p_texture;
- VS::get_singleton()->shader_set_default_texture_param(shader, p_param, p_texture->get_rid());
+ RS::get_singleton()->shader_set_default_texture_param(shader, p_param, p_texture->get_rid());
} else {
default_textures.erase(p_param);
- VS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID());
+ RS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID());
}
emit_changed();
@@ -121,7 +123,7 @@ Ref<Texture2D> Shader::get_default_texture_param(const StringName &p_param) cons
void Shader::get_default_texture_param_list(List<StringName> *r_textures) const {
- for (const Map<StringName, Ref<Texture2D> >::Element *E = default_textures.front(); E; E = E->next()) {
+ for (const Map<StringName, Ref<Texture2D>>::Element *E = default_textures.front(); E; E = E->next()) {
r_textures->push_back(E->key());
}
@@ -158,18 +160,19 @@ void Shader::_bind_methods() {
BIND_ENUM_CONSTANT(MODE_SPATIAL);
BIND_ENUM_CONSTANT(MODE_CANVAS_ITEM);
BIND_ENUM_CONSTANT(MODE_PARTICLES);
+ BIND_ENUM_CONSTANT(MODE_SKY);
}
Shader::Shader() {
mode = MODE_SPATIAL;
- shader = VisualServer::get_singleton()->shader_create();
+ shader = RenderingServer::get_singleton()->shader_create();
params_cache_dirty = true;
}
Shader::~Shader() {
- VisualServer::get_singleton()->free(shader);
+ RenderingServer::get_singleton()->free(shader);
}
////////////
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 5050632dd5..cf0cec362c 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -47,6 +47,7 @@ public:
MODE_SPATIAL,
MODE_CANVAS_ITEM,
MODE_PARTICLES,
+ MODE_SKY,
MODE_MAX
};
@@ -55,11 +56,11 @@ private:
Mode mode;
// hack the name of performance
- // shaders keep a list of ShaderMaterial -> VisualServer name translations, to make
+ // shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make
// conversion fast and save memory.
mutable bool params_cache_dirty;
mutable Map<StringName, StringName> params_cache; //map a shader param to a material param..
- Map<StringName, Ref<Texture2D> > default_textures;
+ Map<StringName, Ref<Texture2D>> default_textures;
virtual void _update_shader() const; //used for visual shader
protected:
@@ -83,7 +84,7 @@ public:
_FORCE_INLINE_ StringName remap_param(const StringName &p_param) const {
if (params_cache_dirty)
- get_param_list(NULL);
+ get_param_list(nullptr);
const Map<StringName, StringName>::Element *E = params_cache.find(p_param);
if (E)
@@ -101,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 = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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.cpp b/scene/resources/shape.cpp
deleted file mode 100644
index 4a6da18f2b..0000000000
--- a/scene/resources/shape.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*************************************************************************/
-/* shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "shape.h"
-
-#include "core/os/os.h"
-#include "scene/main/scene_tree.h"
-#include "scene/resources/mesh.h"
-#include "servers/physics_server.h"
-
-void Shape::add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform) {
-
- Vector<Vector3> toadd = get_debug_mesh_lines();
-
- if (toadd.size()) {
-
- int base = array.size();
- array.resize(base + toadd.size());
- Vector3 *w = array.ptrw();
- for (int i = 0; i < toadd.size(); i++) {
- w[i + base] = p_xform.xform(toadd[i]);
- }
- }
-}
-
-real_t Shape::get_margin() const {
- return margin;
-}
-
-void Shape::set_margin(real_t p_margin) {
- margin = p_margin;
- PhysicsServer::get_singleton()->shape_set_margin(shape, margin);
-}
-
-Ref<ArrayMesh> Shape::get_debug_mesh() {
-
- if (debug_mesh_cache.is_valid())
- return debug_mesh_cache;
-
- Vector<Vector3> lines = get_debug_mesh_lines();
-
- debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh));
-
- if (!lines.empty()) {
- //make mesh
- Vector<Vector3> array;
- array.resize(lines.size());
- {
-
- Vector3 *w = array.ptrw();
- for (int i = 0; i < lines.size(); i++) {
- w[i] = lines[i];
- }
- }
-
- Array arr;
- arr.resize(Mesh::ARRAY_MAX);
- arr[Mesh::ARRAY_VERTEX] = array;
-
- SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
-
- debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
-
- if (st) {
- debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
- }
- }
-
- return debug_mesh_cache;
-}
-
-void Shape::_update_shape() {
- emit_changed();
- debug_mesh_cache.unref();
-}
-
-void Shape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &Shape::get_margin);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
-}
-
-Shape::Shape() :
- margin(0.04) {
-
- ERR_PRINT("Constructor must not be called!");
-}
-
-Shape::Shape(RID p_shape) :
- margin(0.04) {
-
- shape = p_shape;
-}
-
-Shape::~Shape() {
-
- PhysicsServer::get_singleton()->free(shape);
-}
diff --git a/scene/resources/shape.h b/scene/resources/shape.h
deleted file mode 100644
index e5ccbf7e28..0000000000
--- a/scene/resources/shape.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*************************************************************************/
-/* shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SHAPE_H
-#define SHAPE_H
-
-#include "core/resource.h"
-
-class ArrayMesh;
-
-class Shape : public Resource {
-
- GDCLASS(Shape, Resource);
- OBJ_SAVE_TYPE(Shape);
- RES_BASE_EXTENSION("shape");
- RID shape;
- real_t margin;
-
- Ref<ArrayMesh> debug_mesh_cache;
-
-protected:
- static void _bind_methods();
-
- _FORCE_INLINE_ RID get_shape() const { return shape; }
- Shape(RID p_shape);
-
- virtual void _update_shape();
-
-public:
- virtual RID get_rid() const { return shape; }
-
- Ref<ArrayMesh> get_debug_mesh();
- virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); }
- /// Returns the radius of a sphere that fully enclose this shape
- virtual real_t get_enclosing_radius() const = 0;
-
- void add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform);
-
- real_t get_margin() const;
- void set_margin(real_t p_margin);
-
- Shape();
- ~Shape();
-};
-
-#endif // SHAPE_H
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 64930c3117..4fe585053a 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "shape_2d.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
RID Shape2D::get_rid() const {
return shape;
@@ -38,7 +38,7 @@ RID Shape2D::get_rid() const {
void Shape2D::set_custom_solver_bias(real_t p_bias) {
custom_bias = p_bias;
- Physics2DServer::get_singleton()->shape_set_custom_solver_bias(shape, custom_bias);
+ PhysicsServer2D::get_singleton()->shape_set_custom_solver_bias(shape, custom_bias);
}
real_t Shape2D::get_custom_solver_bias() const {
@@ -50,13 +50,13 @@ bool Shape2D::collide_with_motion(const Transform2D &p_local_xform, const Vector
ERR_FAIL_COND_V(p_shape.is_null(), false);
int r;
- return Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, NULL, 0, r);
+ return PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, nullptr, 0, r);
}
bool Shape2D::collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) {
ERR_FAIL_COND_V(p_shape.is_null(), false);
int r;
- return Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), NULL, 0, r);
+ return PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), nullptr, 0, r);
}
Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) {
@@ -66,7 +66,7 @@ Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_x
Vector2 result[max_contacts * 2];
int contacts = 0;
- if (!Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, result, max_contacts, contacts))
+ if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, result, max_contacts, contacts))
return Array();
Array results;
@@ -84,7 +84,7 @@ Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const
Vector2 result[max_contacts * 2];
int contacts = 0;
- if (!Physics2DServer::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), result, max_contacts, contacts))
+ if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), result, max_contacts, contacts))
return Array();
Array results;
@@ -115,5 +115,5 @@ Shape2D::Shape2D(const RID &p_rid) {
Shape2D::~Shape2D() {
- Physics2DServer::get_singleton()->free(shape);
+ PhysicsServer2D::get_singleton()->free(shape);
}
diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp
new file mode 100644
index 0000000000..f4a5d91e52
--- /dev/null
+++ b/scene/resources/shape_3d.cpp
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "shape_3d.h"
+
+#include "core/os/os.h"
+#include "scene/main/scene_tree.h"
+#include "scene/resources/mesh.h"
+#include "servers/physics_server_3d.h"
+
+void Shape3D::add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform) {
+
+ Vector<Vector3> toadd = get_debug_mesh_lines();
+
+ if (toadd.size()) {
+
+ int base = array.size();
+ array.resize(base + toadd.size());
+ Vector3 *w = array.ptrw();
+ for (int i = 0; i < toadd.size(); i++) {
+ w[i + base] = p_xform.xform(toadd[i]);
+ }
+ }
+}
+
+real_t Shape3D::get_margin() const {
+ return margin;
+}
+
+void Shape3D::set_margin(real_t p_margin) {
+ margin = p_margin;
+ PhysicsServer3D::get_singleton()->shape_set_margin(shape, margin);
+}
+
+Ref<ArrayMesh> Shape3D::get_debug_mesh() {
+
+ if (debug_mesh_cache.is_valid())
+ return debug_mesh_cache;
+
+ Vector<Vector3> lines = get_debug_mesh_lines();
+
+ debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh));
+
+ if (!lines.empty()) {
+ //make mesh
+ Vector<Vector3> array;
+ array.resize(lines.size());
+ {
+
+ Vector3 *w = array.ptrw();
+ for (int i = 0; i < lines.size(); i++) {
+ w[i] = lines[i];
+ }
+ }
+
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+ arr[Mesh::ARRAY_VERTEX] = array;
+
+ SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
+
+ debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
+
+ if (st) {
+ debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
+ }
+ }
+
+ return debug_mesh_cache;
+}
+
+void Shape3D::_update_shape() {
+ emit_changed();
+ debug_mesh_cache.unref();
+}
+
+void Shape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape3D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &Shape3D::get_margin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
+}
+
+Shape3D::Shape3D() :
+ margin(0.04) {
+
+ ERR_PRINT("Constructor must not be called!");
+}
+
+Shape3D::Shape3D(RID p_shape) :
+ margin(0.04) {
+
+ shape = p_shape;
+}
+
+Shape3D::~Shape3D() {
+
+ PhysicsServer3D::get_singleton()->free(shape);
+}
diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h
new file mode 100644
index 0000000000..e7a516412d
--- /dev/null
+++ b/scene/resources/shape_3d.h
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SHAPE_3D_H
+#define SHAPE_3D_H
+
+#include "core/resource.h"
+
+class ArrayMesh;
+
+class Shape3D : public Resource {
+
+ GDCLASS(Shape3D, Resource);
+ OBJ_SAVE_TYPE(Shape3D);
+ RES_BASE_EXTENSION("shape");
+ RID shape;
+ real_t margin;
+
+ Ref<ArrayMesh> debug_mesh_cache;
+
+protected:
+ static void _bind_methods();
+
+ _FORCE_INLINE_ RID get_shape() const { return shape; }
+ Shape3D(RID p_shape);
+
+ virtual void _update_shape();
+
+public:
+ virtual RID get_rid() const { return shape; }
+
+ Ref<ArrayMesh> get_debug_mesh();
+ virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); }
+ /// Returns the radius of a sphere that fully enclose this shape
+ virtual real_t get_enclosing_radius() const = 0;
+
+ void add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform);
+
+ real_t get_margin() const;
+ void set_margin(real_t p_margin);
+
+ Shape3D();
+ ~Shape3D();
+};
+
+#endif // SHAPE_H
diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp
index 54648e8af7..cbe86b16b2 100644
--- a/scene/resources/sky.cpp
+++ b/scene/resources/sky.cpp
@@ -39,7 +39,7 @@ void Sky::set_radiance_size(RadianceSize p_size) {
static const int size[RADIANCE_SIZE_MAX] = {
32, 64, 128, 256, 512, 1024, 2048
};
- VS::get_singleton()->sky_set_radiance_size(sky, size[radiance_size]);
+ RS::get_singleton()->sky_set_radiance_size(sky, size[radiance_size]);
}
Sky::RadianceSize Sky::get_radiance_size() const {
@@ -49,13 +49,25 @@ Sky::RadianceSize Sky::get_radiance_size() const {
void Sky::set_process_mode(ProcessMode p_mode) {
mode = p_mode;
- VS::get_singleton()->sky_set_mode(sky, VS::SkyMode(mode));
+ RS::get_singleton()->sky_set_mode(sky, RS::SkyMode(mode));
}
Sky::ProcessMode Sky::get_process_mode() const {
return mode;
}
+void Sky::set_material(const Ref<Material> &p_material) {
+ sky_material = p_material;
+ RID material_rid;
+ if (sky_material.is_valid())
+ material_rid = sky_material->get_rid();
+ RS::get_singleton()->sky_set_material(sky, material_rid);
+}
+
+Ref<Material> Sky::get_material() const {
+ return sky_material;
+}
+
RID Sky::get_rid() const {
return sky;
@@ -69,6 +81,10 @@ void Sky::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Sky::set_process_mode);
ClassDB::bind_method(D_METHOD("get_process_mode"), &Sky::get_process_mode);
+ ClassDB::bind_method(D_METHOD("set_material", "material"), &Sky::set_material);
+ ClassDB::bind_method(D_METHOD("get_material"), &Sky::get_material);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,PanoramaSkyMaterial,ProceduralSkyMaterial,PhysicalSkyMaterial"), "set_material", "get_material");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radiance_size", PROPERTY_HINT_ENUM, "32,64,128,256,512,1024,2048"), "set_radiance_size", "get_radiance_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "HighQuality,RealTime"), "set_process_mode", "get_process_mode");
@@ -87,500 +103,11 @@ void Sky::_bind_methods() {
Sky::Sky() {
mode = PROCESS_MODE_QUALITY;
- radiance_size = RADIANCE_SIZE_128;
- sky = VS::get_singleton()->sky_create();
+ radiance_size = RADIANCE_SIZE_256;
+ sky = RS::get_singleton()->sky_create();
}
Sky::~Sky() {
- VS::get_singleton()->free(sky);
-}
-
-/////////////////////////////////////////
-
-void PanoramaSky::set_panorama(const Ref<Texture2D> &p_panorama) {
-
- panorama = p_panorama;
-
- RID rid = p_panorama.is_valid() ? p_panorama->get_rid() : RID();
- VS::get_singleton()->sky_set_texture(get_rid(), rid);
-}
-
-Ref<Texture2D> PanoramaSky::get_panorama() const {
-
- return panorama;
-}
-
-void PanoramaSky::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSky::set_panorama);
- ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSky::get_panorama);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama");
-}
-
-PanoramaSky::PanoramaSky() {
-}
-
-PanoramaSky::~PanoramaSky() {
-}
-//////////////////////////////////
-
-Ref<Image> ProceduralSky::_generate_sky() {
-
- update_queued = false;
-
- Vector<uint8_t> imgdata;
-
- static const int size[TEXTURE_SIZE_MAX] = {
- 256, 512, 1024, 2048, 4096
- };
-
- int w = size[texture_size];
- int h = w / 2;
-
- imgdata.resize(w * h * 4); //RGBE
-
- {
- uint8_t *dataw = imgdata.ptrw();
-
- uint32_t *ptr = (uint32_t *)dataw;
-
- Color sky_top_linear = sky_top_color.to_linear();
- Color sky_horizon_linear = sky_horizon_color.to_linear();
-
- Color ground_bottom_linear = ground_bottom_color.to_linear();
- Color ground_horizon_linear = ground_horizon_color.to_linear();
-
- Color sun_linear;
- sun_linear.r = sun_color.r * sun_energy;
- sun_linear.g = sun_color.g * sun_energy;
- sun_linear.b = sun_color.b * sun_energy;
-
- Vector3 sun(0, 0, -1);
-
- sun = Basis(Vector3(1, 0, 0), Math::deg2rad(sun_latitude)).xform(sun);
- sun = Basis(Vector3(0, 1, 0), Math::deg2rad(sun_longitude)).xform(sun);
-
- sun.normalize();
-
- for (int i = 0; i < w; i++) {
-
- float u = float(i) / (w - 1);
- float phi = u * 2.0 * Math_PI;
-
- for (int j = 0; j < h; j++) {
-
- float v = float(j) / (h - 1);
- float theta = v * Math_PI;
-
- Vector3 normal(
- Math::sin(phi) * Math::sin(theta) * -1.0,
- Math::cos(theta),
- Math::cos(phi) * Math::sin(theta) * -1.0);
-
- normal.normalize();
-
- float v_angle = Math::acos(CLAMP(normal.y, -1.0, 1.0));
-
- Color color;
-
- if (normal.y < 0) {
- //ground
-
- float c = (v_angle - (Math_PI * 0.5)) / (Math_PI * 0.5);
- color = ground_horizon_linear.linear_interpolate(ground_bottom_linear, Math::ease(c, ground_curve));
- color.r *= ground_energy;
- color.g *= ground_energy;
- color.b *= ground_energy;
- } else {
- float c = v_angle / (Math_PI * 0.5);
- color = sky_horizon_linear.linear_interpolate(sky_top_linear, Math::ease(1.0 - c, sky_curve));
- color.r *= sky_energy;
- color.g *= sky_energy;
- color.b *= sky_energy;
-
- float sun_angle = Math::rad2deg(Math::acos(CLAMP(sun.dot(normal), -1.0, 1.0)));
-
- if (sun_angle < sun_angle_min) {
- color = color.blend(sun_linear);
- } else if (sun_angle < sun_angle_max) {
-
- float c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min);
- c2 = Math::ease(c2, sun_curve);
-
- color = color.blend(sun_linear).linear_interpolate(color, c2);
- }
- }
-
- ptr[j * w + i] = color.to_rgbe9995();
- }
- }
- }
-
- Ref<Image> image;
- image.instance();
- image->create(w, h, false, Image::FORMAT_RGBE9995, imgdata);
-
- return image;
-}
-
-void ProceduralSky::set_sky_top_color(const Color &p_sky_top) {
-
- sky_top_color = p_sky_top;
- _queue_update();
-}
-
-Color ProceduralSky::get_sky_top_color() const {
-
- return sky_top_color;
-}
-
-void ProceduralSky::set_sky_horizon_color(const Color &p_sky_horizon) {
-
- sky_horizon_color = p_sky_horizon;
- _queue_update();
-}
-Color ProceduralSky::get_sky_horizon_color() const {
-
- return sky_horizon_color;
-}
-
-void ProceduralSky::set_sky_curve(float p_curve) {
-
- sky_curve = p_curve;
- _queue_update();
-}
-float ProceduralSky::get_sky_curve() const {
-
- return sky_curve;
-}
-
-void ProceduralSky::set_sky_energy(float p_energy) {
-
- sky_energy = p_energy;
- _queue_update();
-}
-float ProceduralSky::get_sky_energy() const {
-
- return sky_energy;
-}
-
-void ProceduralSky::set_ground_bottom_color(const Color &p_ground_bottom) {
-
- ground_bottom_color = p_ground_bottom;
- _queue_update();
-}
-Color ProceduralSky::get_ground_bottom_color() const {
-
- return ground_bottom_color;
-}
-
-void ProceduralSky::set_ground_horizon_color(const Color &p_ground_horizon) {
-
- ground_horizon_color = p_ground_horizon;
- _queue_update();
-}
-Color ProceduralSky::get_ground_horizon_color() const {
-
- return ground_horizon_color;
-}
-
-void ProceduralSky::set_ground_curve(float p_curve) {
-
- ground_curve = p_curve;
- _queue_update();
-}
-float ProceduralSky::get_ground_curve() const {
-
- return ground_curve;
-}
-
-void ProceduralSky::set_ground_energy(float p_energy) {
-
- ground_energy = p_energy;
- _queue_update();
-}
-float ProceduralSky::get_ground_energy() const {
-
- return ground_energy;
-}
-
-void ProceduralSky::set_sun_color(const Color &p_sun) {
-
- sun_color = p_sun;
- _queue_update();
-}
-Color ProceduralSky::get_sun_color() const {
-
- return sun_color;
-}
-
-void ProceduralSky::set_sun_latitude(float p_angle) {
-
- sun_latitude = p_angle;
- _queue_update();
-}
-float ProceduralSky::get_sun_latitude() const {
-
- return sun_latitude;
-}
-
-void ProceduralSky::set_sun_longitude(float p_angle) {
-
- sun_longitude = p_angle;
- _queue_update();
-}
-float ProceduralSky::get_sun_longitude() const {
-
- return sun_longitude;
-}
-
-void ProceduralSky::set_sun_angle_min(float p_angle) {
-
- sun_angle_min = p_angle;
- _queue_update();
-}
-float ProceduralSky::get_sun_angle_min() const {
-
- return sun_angle_min;
-}
-
-void ProceduralSky::set_sun_angle_max(float p_angle) {
-
- sun_angle_max = p_angle;
- _queue_update();
-}
-float ProceduralSky::get_sun_angle_max() const {
-
- return sun_angle_max;
-}
-
-void ProceduralSky::set_sun_curve(float p_curve) {
-
- sun_curve = p_curve;
- _queue_update();
-}
-float ProceduralSky::get_sun_curve() const {
-
- return sun_curve;
-}
-
-void ProceduralSky::set_sun_energy(float p_energy) {
-
- sun_energy = p_energy;
- _queue_update();
-}
-float ProceduralSky::get_sun_energy() const {
-
- return sun_energy;
-}
-
-void ProceduralSky::set_texture_size(TextureSize p_size) {
- ERR_FAIL_INDEX(p_size, TEXTURE_SIZE_MAX);
-
- texture_size = p_size;
- _queue_update();
-}
-ProceduralSky::TextureSize ProceduralSky::get_texture_size() const {
- return texture_size;
-}
-
-void ProceduralSky::_update_sky() {
-
- bool use_thread = true;
- if (first_time) {
- use_thread = false;
- first_time = false;
- }
-#ifdef NO_THREADS
- use_thread = false;
-#endif
- if (use_thread) {
-
- if (!sky_thread) {
- sky_thread = Thread::create(_thread_function, this);
- regen_queued = false;
- } else {
- regen_queued = true;
- }
-
- } else {
- Ref<Image> image = _generate_sky();
- if (texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_create(image);
- VS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = VS::get_singleton()->texture_2d_create(image);
- }
- VS::get_singleton()->sky_set_texture(get_rid(), texture);
- }
-}
-
-void ProceduralSky::_queue_update() {
-
- if (update_queued)
- return;
-
- update_queued = true;
- call_deferred("_update_sky");
-}
-
-void ProceduralSky::_thread_done(const Ref<Image> &p_image) {
-
- if (texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_create(p_image);
- VS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = VS::get_singleton()->texture_2d_create(p_image);
- }
-
- VS::get_singleton()->sky_set_texture(get_rid(), texture);
-
- Thread::wait_to_finish(sky_thread);
- memdelete(sky_thread);
- sky_thread = NULL;
- if (regen_queued) {
- sky_thread = Thread::create(_thread_function, this);
- regen_queued = false;
- }
-}
-
-void ProceduralSky::_thread_function(void *p_ud) {
-
- ProceduralSky *psky = (ProceduralSky *)p_ud;
- psky->call_deferred("_thread_done", psky->_generate_sky());
-}
-
-void ProceduralSky::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_update_sky"), &ProceduralSky::_update_sky);
-
- ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSky::set_sky_top_color);
- ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSky::get_sky_top_color);
-
- ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSky::set_sky_horizon_color);
- ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSky::get_sky_horizon_color);
-
- ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSky::set_sky_curve);
- ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSky::get_sky_curve);
-
- ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSky::set_sky_energy);
- ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSky::get_sky_energy);
-
- ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSky::set_ground_bottom_color);
- ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSky::get_ground_bottom_color);
-
- ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSky::set_ground_horizon_color);
- ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSky::get_ground_horizon_color);
-
- ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSky::set_ground_curve);
- ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSky::get_ground_curve);
-
- ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSky::set_ground_energy);
- ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSky::get_ground_energy);
-
- ClassDB::bind_method(D_METHOD("set_sun_color", "color"), &ProceduralSky::set_sun_color);
- ClassDB::bind_method(D_METHOD("get_sun_color"), &ProceduralSky::get_sun_color);
-
- ClassDB::bind_method(D_METHOD("set_sun_latitude", "degrees"), &ProceduralSky::set_sun_latitude);
- ClassDB::bind_method(D_METHOD("get_sun_latitude"), &ProceduralSky::get_sun_latitude);
-
- ClassDB::bind_method(D_METHOD("set_sun_longitude", "degrees"), &ProceduralSky::set_sun_longitude);
- ClassDB::bind_method(D_METHOD("get_sun_longitude"), &ProceduralSky::get_sun_longitude);
-
- ClassDB::bind_method(D_METHOD("set_sun_angle_min", "degrees"), &ProceduralSky::set_sun_angle_min);
- ClassDB::bind_method(D_METHOD("get_sun_angle_min"), &ProceduralSky::get_sun_angle_min);
-
- ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSky::set_sun_angle_max);
- ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSky::get_sun_angle_max);
-
- ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSky::set_sun_curve);
- ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSky::get_sun_curve);
-
- ClassDB::bind_method(D_METHOD("set_sun_energy", "energy"), &ProceduralSky::set_sun_energy);
- ClassDB::bind_method(D_METHOD("get_sun_energy"), &ProceduralSky::get_sun_energy);
-
- ClassDB::bind_method(D_METHOD("set_texture_size", "size"), &ProceduralSky::set_texture_size);
- ClassDB::bind_method(D_METHOD("get_texture_size"), &ProceduralSky::get_texture_size);
-
- ClassDB::bind_method(D_METHOD("_thread_done", "image"), &ProceduralSky::_thread_done);
-
- ADD_GROUP("Sky", "sky_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color"), "set_sky_top_color", "get_sky_top_color");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color"), "set_sky_horizon_color", "get_sky_horizon_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy");
-
- ADD_GROUP("Ground", "ground_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color"), "set_ground_bottom_color", "get_ground_bottom_color");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color"), "set_ground_horizon_color", "get_ground_horizon_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy");
-
- ADD_GROUP("Sun", "sun_");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sun_color"), "set_sun_color", "get_sun_color");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_latitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_latitude", "get_sun_latitude");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_longitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_longitude", "get_sun_longitude");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_min", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_min", "get_sun_angle_min");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sun_energy", "get_sun_energy");
-
- ADD_GROUP("Texture2D", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_size", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096"), "set_texture_size", "get_texture_size");
-
- BIND_ENUM_CONSTANT(TEXTURE_SIZE_256);
- BIND_ENUM_CONSTANT(TEXTURE_SIZE_512);
- BIND_ENUM_CONSTANT(TEXTURE_SIZE_1024);
- BIND_ENUM_CONSTANT(TEXTURE_SIZE_2048);
- BIND_ENUM_CONSTANT(TEXTURE_SIZE_4096);
- BIND_ENUM_CONSTANT(TEXTURE_SIZE_MAX);
-}
-
-ProceduralSky::ProceduralSky(bool p_desaturate) {
-
- update_queued = false;
- sky_top_color = Color::hex(0xa5d6f1ff);
- sky_horizon_color = Color::hex(0xd6eafaff);
- sky_curve = 0.09;
- sky_energy = 1;
-
- ground_bottom_color = Color::hex(0x282f36ff);
- ground_horizon_color = Color::hex(0x6c655fff);
- ground_curve = 0.02;
- ground_energy = 1;
-
- if (p_desaturate) {
- sky_top_color.set_hsv(sky_top_color.get_h(), 0, sky_top_color.get_v());
- sky_horizon_color.set_hsv(sky_horizon_color.get_h(), 0, sky_horizon_color.get_v());
- ground_bottom_color.set_hsv(ground_bottom_color.get_h(), 0, ground_bottom_color.get_v());
- ground_horizon_color.set_hsv(ground_horizon_color.get_h(), 0, ground_horizon_color.get_v());
- }
- sun_color = Color(1, 1, 1);
- sun_latitude = 35;
- sun_longitude = 0;
- sun_angle_min = 1;
- sun_angle_max = 100;
- sun_curve = 0.05;
- sun_energy = 1;
-
- texture_size = TEXTURE_SIZE_1024;
- sky_thread = NULL;
- regen_queued = false;
- first_time = true;
-
- _queue_update();
-}
-
-ProceduralSky::~ProceduralSky() {
-
- if (sky_thread) {
- Thread::wait_to_finish(sky_thread);
- memdelete(sky_thread);
- sky_thread = NULL;
- }
- if (texture.is_valid()) {
- VS::get_singleton()->free(texture);
- }
-}
+ RS::get_singleton()->free(sky);
+} \ No newline at end of file
diff --git a/scene/resources/sky.h b/scene/resources/sky.h
index 09ebbd88a0..37f0a589f9 100644
--- a/scene/resources/sky.h
+++ b/scene/resources/sky.h
@@ -32,6 +32,7 @@
#define SKY_H
#include "core/os/thread.h"
+#include "scene/resources/material.h"
#include "scene/resources/texture.h"
class Sky : public Resource {
@@ -58,6 +59,7 @@ private:
RID sky;
ProcessMode mode;
RadianceSize radiance_size;
+ Ref<Material> sky_material;
protected:
static void _bind_methods();
@@ -69,6 +71,9 @@ public:
void set_process_mode(ProcessMode p_mode);
ProcessMode get_process_mode() const;
+ void set_material(const Ref<Material> &p_material);
+ Ref<Material> get_material() const;
+
virtual RID get_rid() const;
Sky();
@@ -78,129 +83,4 @@ public:
VARIANT_ENUM_CAST(Sky::RadianceSize)
VARIANT_ENUM_CAST(Sky::ProcessMode)
-class PanoramaSky : public Sky {
- GDCLASS(PanoramaSky, Sky);
-
-private:
- Ref<Texture2D> panorama;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_panorama(const Ref<Texture2D> &p_panorama);
- Ref<Texture2D> get_panorama() const;
-
- PanoramaSky();
- ~PanoramaSky();
-};
-
-class ProceduralSky : public Sky {
- GDCLASS(ProceduralSky, Sky);
-
-public:
- enum TextureSize {
- TEXTURE_SIZE_256,
- TEXTURE_SIZE_512,
- TEXTURE_SIZE_1024,
- TEXTURE_SIZE_2048,
- TEXTURE_SIZE_4096,
- TEXTURE_SIZE_MAX
- };
-
-private:
- Thread *sky_thread;
- Color sky_top_color;
- Color sky_horizon_color;
- float sky_curve;
- float sky_energy;
-
- Color ground_bottom_color;
- Color ground_horizon_color;
- float ground_curve;
- float ground_energy;
-
- Color sun_color;
- float sun_latitude;
- float sun_longitude;
- float sun_angle_min;
- float sun_angle_max;
- float sun_curve;
- float sun_energy;
-
- TextureSize texture_size;
-
- RID texture;
-
- bool update_queued;
- bool regen_queued;
-
- bool first_time;
-
- void _thread_done(const Ref<Image> &p_image);
- static void _thread_function(void *p_ud);
-
-protected:
- static void _bind_methods();
-
- Ref<Image> _generate_sky();
- void _update_sky();
-
- void _queue_update();
-
-public:
- void set_sky_top_color(const Color &p_sky_top);
- Color get_sky_top_color() const;
-
- void set_sky_horizon_color(const Color &p_sky_horizon);
- Color get_sky_horizon_color() const;
-
- void set_sky_curve(float p_curve);
- float get_sky_curve() const;
-
- void set_sky_energy(float p_energy);
- float get_sky_energy() const;
-
- void set_ground_bottom_color(const Color &p_ground_bottom);
- Color get_ground_bottom_color() const;
-
- void set_ground_horizon_color(const Color &p_ground_horizon);
- Color get_ground_horizon_color() const;
-
- void set_ground_curve(float p_curve);
- float get_ground_curve() const;
-
- void set_ground_energy(float p_energy);
- float get_ground_energy() const;
-
- void set_sun_color(const Color &p_sun);
- Color get_sun_color() const;
-
- void set_sun_latitude(float p_angle);
- float get_sun_latitude() const;
-
- void set_sun_longitude(float p_angle);
- float get_sun_longitude() const;
-
- void set_sun_angle_min(float p_angle);
- float get_sun_angle_min() const;
-
- void set_sun_angle_max(float p_angle);
- float get_sun_angle_max() const;
-
- void set_sun_curve(float p_curve);
- float get_sun_curve() const;
-
- void set_sun_energy(float p_energy);
- float get_sun_energy() const;
-
- void set_texture_size(TextureSize p_size);
- TextureSize get_texture_size() const;
-
- ProceduralSky(bool p_desaturate = false);
- ~ProceduralSky();
-};
-
-VARIANT_ENUM_CAST(ProceduralSky::TextureSize)
-
#endif // SKY_H
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
new file mode 100644
index 0000000000..37b88cccea
--- /dev/null
+++ b/scene/resources/sky_material.cpp
@@ -0,0 +1,628 @@
+/*************************************************************************/
+/* sky_material.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "sky_material.h"
+
+void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
+
+ sky_top_color = p_sky_top;
+ RS::get_singleton()->material_set_param(_get_material(), "sky_top_color", sky_top_color.to_linear());
+}
+
+Color ProceduralSkyMaterial::get_sky_top_color() const {
+
+ return sky_top_color;
+}
+
+void ProceduralSkyMaterial::set_sky_horizon_color(const Color &p_sky_horizon) {
+
+ sky_horizon_color = p_sky_horizon;
+ RS::get_singleton()->material_set_param(_get_material(), "sky_horizon_color", sky_horizon_color.to_linear());
+}
+Color ProceduralSkyMaterial::get_sky_horizon_color() const {
+
+ return sky_horizon_color;
+}
+
+void ProceduralSkyMaterial::set_sky_curve(float p_curve) {
+
+ sky_curve = p_curve;
+ RS::get_singleton()->material_set_param(_get_material(), "sky_curve", sky_curve);
+}
+float ProceduralSkyMaterial::get_sky_curve() const {
+
+ return sky_curve;
+}
+
+void ProceduralSkyMaterial::set_sky_energy(float p_energy) {
+
+ sky_energy = p_energy;
+ RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy);
+}
+float ProceduralSkyMaterial::get_sky_energy() const {
+
+ return sky_energy;
+}
+
+void ProceduralSkyMaterial::set_ground_bottom_color(const Color &p_ground_bottom) {
+
+ ground_bottom_color = p_ground_bottom;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_bottom_color", ground_bottom_color.to_linear());
+}
+Color ProceduralSkyMaterial::get_ground_bottom_color() const {
+
+ return ground_bottom_color;
+}
+
+void ProceduralSkyMaterial::set_ground_horizon_color(const Color &p_ground_horizon) {
+
+ ground_horizon_color = p_ground_horizon;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_horizon_color", ground_horizon_color.to_linear());
+}
+Color ProceduralSkyMaterial::get_ground_horizon_color() const {
+
+ return ground_horizon_color;
+}
+
+void ProceduralSkyMaterial::set_ground_curve(float p_curve) {
+
+ ground_curve = p_curve;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_curve", ground_curve);
+}
+float ProceduralSkyMaterial::get_ground_curve() const {
+
+ return ground_curve;
+}
+
+void ProceduralSkyMaterial::set_ground_energy(float p_energy) {
+
+ ground_energy = p_energy;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy);
+}
+float ProceduralSkyMaterial::get_ground_energy() const {
+
+ return ground_energy;
+}
+
+void ProceduralSkyMaterial::set_sun_angle_min(float p_angle) {
+
+ sun_angle_min = p_angle;
+ RS::get_singleton()->material_set_param(_get_material(), "sun_angle_min", Math::deg2rad(sun_angle_min));
+}
+float ProceduralSkyMaterial::get_sun_angle_min() const {
+
+ return sun_angle_min;
+}
+
+void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {
+
+ sun_angle_max = p_angle;
+ RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::deg2rad(sun_angle_max));
+}
+float ProceduralSkyMaterial::get_sun_angle_max() const {
+
+ return sun_angle_max;
+}
+
+void ProceduralSkyMaterial::set_sun_curve(float p_curve) {
+
+ sun_curve = p_curve;
+ RS::get_singleton()->material_set_param(_get_material(), "sun_curve", sun_curve);
+}
+float ProceduralSkyMaterial::get_sun_curve() const {
+
+ return sun_curve;
+}
+
+bool ProceduralSkyMaterial::_can_do_next_pass() const {
+ return false;
+}
+
+Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
+
+ return Shader::MODE_SKY;
+}
+
+RID ProceduralSkyMaterial::get_shader_rid() const {
+
+ return shader;
+}
+
+void ProceduralSkyMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSkyMaterial::set_sky_top_color);
+ ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSkyMaterial::get_sky_top_color);
+
+ ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSkyMaterial::set_sky_horizon_color);
+ ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSkyMaterial::get_sky_horizon_color);
+
+ ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve);
+ ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve);
+
+ ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSkyMaterial::set_sky_energy);
+ ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSkyMaterial::get_sky_energy);
+
+ ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSkyMaterial::set_ground_bottom_color);
+ ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSkyMaterial::get_ground_bottom_color);
+
+ ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSkyMaterial::set_ground_horizon_color);
+ ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSkyMaterial::get_ground_horizon_color);
+
+ ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve);
+ ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve);
+
+ ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSkyMaterial::set_ground_energy);
+ ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSkyMaterial::get_ground_energy);
+
+ ClassDB::bind_method(D_METHOD("set_sun_angle_min", "degrees"), &ProceduralSkyMaterial::set_sun_angle_min);
+ ClassDB::bind_method(D_METHOD("get_sun_angle_min"), &ProceduralSkyMaterial::get_sun_angle_min);
+
+ ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max);
+ ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max);
+
+ ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSkyMaterial::set_sun_curve);
+ ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSkyMaterial::get_sun_curve);
+
+ ADD_GROUP("Sky", "sky_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color"), "set_sky_top_color", "get_sky_top_color");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color"), "set_sky_horizon_color", "get_sky_horizon_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy");
+
+ ADD_GROUP("Ground", "ground_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color"), "set_ground_bottom_color", "get_ground_bottom_color");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color"), "set_ground_horizon_color", "get_ground_horizon_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy");
+
+ ADD_GROUP("Sun", "sun_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_min", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_min", "get_sun_angle_min");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve");
+}
+
+ProceduralSkyMaterial::ProceduralSkyMaterial() {
+
+ String code = "shader_type sky;\n\n";
+
+ code += "uniform vec4 sky_top_color : hint_color = vec4(0.35, 0.46, 0.71, 1.0);\n";
+ code += "uniform vec4 sky_horizon_color : hint_color = vec4(0.55, 0.69, 0.81, 1.0);\n";
+ code += "uniform float sky_curve : hint_range(0, 1) = 0.09;\n";
+ code += "uniform float sky_energy = 1.0;\n\n";
+ code += "uniform vec4 ground_bottom_color : hint_color = vec4(0.12, 0.12, 0.13, 1.0);\n";
+ code += "uniform vec4 ground_horizon_color : hint_color = vec4(0.37, 0.33, 0.31, 1.0);\n";
+ code += "uniform float ground_curve : hint_range(0, 1) = 0.02;\n";
+ code += "uniform float ground_energy = 1.0;\n\n";
+ code += "uniform float sun_angle_min = 0.01;\n";
+ code += "uniform float sun_angle_max = 1.0;\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 += "\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";
+ code += "\tsky *= sky_energy;\n";
+ code += "\tif (LIGHT0_ENABLED) {\n";
+ code += "\t\tfloat sun_angle = acos(dot(LIGHT0_DIRECTION, EYEDIR));\n";
+ code += "\t\tif (sun_angle < sun_angle_min) {\n";
+ code += "\t\t\tsky = LIGHT0_COLOR * LIGHT0_ENERGY;\n";
+ code += "\t\t} else if (sun_angle < sun_angle_max) {\n";
+ code += "\t\t\tfloat c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min);\n";
+ code += "\t\t\tsky = mix(LIGHT0_COLOR * LIGHT0_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ code += "\tif (LIGHT1_ENABLED) {\n";
+ code += "\t\tfloat sun_angle = acos(dot(LIGHT1_DIRECTION, EYEDIR));\n";
+ code += "\t\tif (sun_angle < sun_angle_min) {\n";
+ code += "\t\t\tsky = LIGHT1_COLOR * LIGHT1_ENERGY;\n";
+ code += "\t\t} else if (sun_angle < sun_angle_max) {\n";
+ code += "\t\t\tfloat c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min);\n";
+ code += "\t\t\tsky = mix(LIGHT1_COLOR * LIGHT1_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ code += "\tif (LIGHT2_ENABLED) {\n";
+ code += "\t\tfloat sun_angle = acos(dot(LIGHT2_DIRECTION, EYEDIR));\n";
+ code += "\t\tif (sun_angle < sun_angle_min) {\n";
+ code += "\t\t\tsky = LIGHT2_COLOR * LIGHT2_ENERGY;\n";
+ code += "\t\t} else if (sun_angle < sun_angle_max) {\n";
+ code += "\t\t\tfloat c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min);\n";
+ code += "\t\t\tsky = mix(LIGHT2_COLOR * LIGHT2_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ code += "\tif (LIGHT3_ENABLED) {\n";
+ code += "\t\tfloat sun_angle = acos(dot(LIGHT3_DIRECTION, EYEDIR));\n";
+ code += "\t\tif (sun_angle < sun_angle_min) {\n";
+ code += "\t\t\tsky = LIGHT3_COLOR * LIGHT3_ENERGY;\n";
+ code += "\t\t} else if (sun_angle < sun_angle_max) {\n";
+ code += "\t\t\tfloat c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min);\n";
+ code += "\t\t\tsky = mix(LIGHT3_COLOR * LIGHT3_ENERGY, sky, clamp(1.0 - pow(1.0 - c2, 1.0 / sun_curve), 0.0, 1.0));\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ code += "\tc = (v_angle - (PI * 0.5)) / (PI * 0.5);\n";
+ code += "\tvec3 ground = mix(ground_horizon_color.rgb, ground_bottom_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / ground_curve), 0.0, 1.0));\n";
+ code += "\tground *= ground_energy;\n";
+ code += "\tCOLOR = mix(ground, sky, step(0.0, EYEDIR.y));\n";
+ code += "}\n";
+
+ shader = RS::get_singleton()->shader_create();
+
+ RS::get_singleton()->shader_set_code(shader, code);
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader);
+
+ set_sky_top_color(Color(0.35, 0.46, 0.71));
+ set_sky_horizon_color(Color(0.55, 0.69, 0.81));
+ set_sky_curve(0.09);
+ set_sky_energy(1.0);
+
+ set_ground_bottom_color(Color(0.12, 0.12, 0.13));
+ set_ground_horizon_color(Color(0.37, 0.33, 0.31));
+ set_ground_curve(0.02);
+ set_ground_energy(1.0);
+
+ set_sun_angle_min(1.0);
+ set_sun_angle_max(100.0);
+ set_sun_curve(0.05);
+}
+
+ProceduralSkyMaterial::~ProceduralSkyMaterial() {
+ RS::get_singleton()->free(shader);
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
+}
+
+/////////////////////////////////////////
+/* PanoramaSkyMaterial */
+
+void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) {
+
+ panorama = p_panorama;
+ RS::get_singleton()->material_set_param(_get_material(), "source_panorama", panorama);
+}
+
+Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {
+
+ return panorama;
+}
+
+bool PanoramaSkyMaterial::_can_do_next_pass() const {
+ return false;
+}
+
+Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {
+
+ return Shader::MODE_SKY;
+}
+
+RID PanoramaSkyMaterial::get_shader_rid() const {
+
+ return shader;
+}
+
+void PanoramaSkyMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);
+ ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama");
+}
+
+PanoramaSkyMaterial::PanoramaSkyMaterial() {
+ String code = "shader_type sky;\n\n";
+
+ code += "uniform sampler2D source_panorama : filter_linear;\n";
+ code += "void fragment() {\n";
+ code += "\tCOLOR = texture(source_panorama, SKY_COORDS).rgb;\n";
+ code += "}";
+
+ shader = RS::get_singleton()->shader_create();
+
+ RS::get_singleton()->shader_set_code(shader, code);
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader);
+}
+
+PanoramaSkyMaterial::~PanoramaSkyMaterial() {
+ RS::get_singleton()->free(shader);
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
+}
+//////////////////////////////////
+/* PhysicalSkyMaterial */
+
+void PhysicalSkyMaterial::set_rayleigh_coefficient(float p_rayleigh) {
+
+ rayleigh = p_rayleigh;
+ RS::get_singleton()->material_set_param(_get_material(), "rayleigh", rayleigh);
+}
+float PhysicalSkyMaterial::get_rayleigh_coefficient() const {
+
+ return rayleigh;
+}
+
+void PhysicalSkyMaterial::set_rayleigh_color(Color p_rayleigh_color) {
+
+ rayleigh_color = p_rayleigh_color;
+ RS::get_singleton()->material_set_param(_get_material(), "rayleigh_color", rayleigh_color);
+}
+Color PhysicalSkyMaterial::get_rayleigh_color() const {
+
+ return rayleigh_color;
+}
+
+void PhysicalSkyMaterial::set_mie_coefficient(float p_mie) {
+
+ mie = p_mie;
+ RS::get_singleton()->material_set_param(_get_material(), "mie", mie);
+}
+float PhysicalSkyMaterial::get_mie_coefficient() const {
+
+ return mie;
+}
+
+void PhysicalSkyMaterial::set_mie_eccentricity(float p_eccentricity) {
+
+ mie_eccentricity = p_eccentricity;
+ RS::get_singleton()->material_set_param(_get_material(), "mie_eccentricity", mie_eccentricity);
+}
+float PhysicalSkyMaterial::get_mie_eccentricity() const {
+
+ return mie_eccentricity;
+}
+
+void PhysicalSkyMaterial::set_mie_color(Color p_mie_color) {
+
+ mie_color = p_mie_color;
+ RS::get_singleton()->material_set_param(_get_material(), "mie_color", mie_color);
+}
+Color PhysicalSkyMaterial::get_mie_color() const {
+ return mie_color;
+}
+
+void PhysicalSkyMaterial::set_turbidity(float p_turbidity) {
+
+ turbidity = p_turbidity;
+ RS::get_singleton()->material_set_param(_get_material(), "turbidity", turbidity);
+}
+float PhysicalSkyMaterial::get_turbidity() const {
+
+ return turbidity;
+}
+
+void PhysicalSkyMaterial::set_sun_disk_scale(float p_sun_disk_scale) {
+
+ sun_disk_scale = p_sun_disk_scale;
+ RS::get_singleton()->material_set_param(_get_material(), "sun_disk_scale", sun_disk_scale);
+}
+float PhysicalSkyMaterial::get_sun_disk_scale() const {
+
+ return sun_disk_scale;
+}
+
+void PhysicalSkyMaterial::set_ground_color(Color p_ground_color) {
+
+ ground_color = p_ground_color;
+ RS::get_singleton()->material_set_param(_get_material(), "ground_color", ground_color);
+}
+Color PhysicalSkyMaterial::get_ground_color() const {
+
+ return ground_color;
+}
+
+void PhysicalSkyMaterial::set_exposure(float p_exposure) {
+
+ exposure = p_exposure;
+ RS::get_singleton()->material_set_param(_get_material(), "exposure", exposure);
+}
+float PhysicalSkyMaterial::get_exposure() const {
+
+ return exposure;
+}
+
+void PhysicalSkyMaterial::set_dither_strength(float p_dither_strength) {
+
+ dither_strength = p_dither_strength;
+ RS::get_singleton()->material_set_param(_get_material(), "dither_strength", dither_strength);
+}
+float PhysicalSkyMaterial::get_dither_strength() const {
+
+ return dither_strength;
+}
+
+bool PhysicalSkyMaterial::_can_do_next_pass() const {
+ return false;
+}
+
+Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
+
+ return Shader::MODE_SKY;
+}
+
+RID PhysicalSkyMaterial::get_shader_rid() const {
+
+ return shader;
+}
+
+void PhysicalSkyMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
+ ClassDB::bind_method(D_METHOD("get_rayleigh_coefficient"), &PhysicalSkyMaterial::get_rayleigh_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_rayleigh_color", "color"), &PhysicalSkyMaterial::set_rayleigh_color);
+ ClassDB::bind_method(D_METHOD("get_rayleigh_color"), &PhysicalSkyMaterial::get_rayleigh_color);
+
+ ClassDB::bind_method(D_METHOD("set_mie_coefficient", "mie"), &PhysicalSkyMaterial::set_mie_coefficient);
+ ClassDB::bind_method(D_METHOD("get_mie_coefficient"), &PhysicalSkyMaterial::get_mie_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_mie_eccentricity", "eccentricity"), &PhysicalSkyMaterial::set_mie_eccentricity);
+ ClassDB::bind_method(D_METHOD("get_mie_eccentricity"), &PhysicalSkyMaterial::get_mie_eccentricity);
+
+ ClassDB::bind_method(D_METHOD("set_mie_color", "color"), &PhysicalSkyMaterial::set_mie_color);
+ ClassDB::bind_method(D_METHOD("get_mie_color"), &PhysicalSkyMaterial::get_mie_color);
+
+ ClassDB::bind_method(D_METHOD("set_turbidity", "turbidity"), &PhysicalSkyMaterial::set_turbidity);
+ ClassDB::bind_method(D_METHOD("get_turbidity"), &PhysicalSkyMaterial::get_turbidity);
+
+ ClassDB::bind_method(D_METHOD("set_sun_disk_scale", "scale"), &PhysicalSkyMaterial::set_sun_disk_scale);
+ ClassDB::bind_method(D_METHOD("get_sun_disk_scale"), &PhysicalSkyMaterial::get_sun_disk_scale);
+
+ ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color);
+ ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color);
+
+ ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure);
+ ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure);
+
+ ClassDB::bind_method(D_METHOD("set_dither_strength", "strength"), &PhysicalSkyMaterial::set_dither_strength);
+ ClassDB::bind_method(D_METHOD("get_dither_strength"), &PhysicalSkyMaterial::get_dither_strength);
+
+ ADD_GROUP("Rayleigh", "rayleigh_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rayleigh_coefficient", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_rayleigh_coefficient", "get_rayleigh_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "rayleigh_color"), "set_rayleigh_color", "get_rayleigh_color");
+
+ ADD_GROUP("Mie", "mie_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_coefficient", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_mie_coefficient", "get_mie_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mie_eccentricity", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_mie_eccentricity", "get_mie_eccentricity");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "mie_color"), "set_mie_color", "get_mie_color");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color"), "set_ground_color", "get_ground_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dither_strength", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_dither_strength", "get_dither_strength");
+}
+
+PhysicalSkyMaterial::PhysicalSkyMaterial() {
+ String code = "shader_type sky;\n\n";
+
+ code += "uniform float rayleigh : hint_range(0, 64) = 2.0;\n";
+ code += "uniform vec4 rayleigh_color : hint_color = vec4(0.056, 0.14, 0.3, 1.0);\n";
+ code += "uniform float mie : hint_range(0, 1) = 0.005;\n";
+ code += "uniform float mie_eccentricity : hint_range(-1, 1) = 0.8;\n";
+ code += "uniform vec4 mie_color : hint_color = vec4(0.36, 0.56, 0.82, 1.0);\n\n";
+
+ code += "uniform float turbidity : hint_range(0, 1000) = 10.0;\n";
+ code += "uniform float sun_disk_scale : hint_range(0, 360) = 1.0;\n";
+ code += "uniform vec4 ground_color : hint_color = vec4(1.0);\n";
+ code += "uniform float exposure : hint_range(0, 128) = 0.1;\n";
+ code += "uniform float dither_strength : hint_range(0, 10) = 1.0;\n\n";
+
+ code += "const float PI = 3.141592653589793238462643383279502884197169;\n";
+ code += "const vec3 UP = vec3( 0.0, 1.0, 0.0 );\n\n";
+
+ code += "// Sun constants\n";
+ code += "const float SOL_SIZE = 0.00872663806;\n";
+ code += "const float SUN_ENERGY = 1000.0;\n\n";
+
+ code += "// optical length at zenith for molecules\n";
+ code += "const float rayleigh_zenith_size = 8.4e3;\n";
+ code += "const float mie_zenith_size = 1.25e3;\n\n";
+
+ code += "float henyey_greenstein(float cos_theta, float g) {\n";
+ code += "\tconst float k = 0.0795774715459;\n";
+ code += "\treturn k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));\n";
+ code += "}\n\n";
+
+ code += "// From: https://www.shadertoy.com/view/4sfGzS credit to iq\n";
+ code += "float hash(vec3 p) {\n";
+ code += "\tp = fract( p * 0.3183099 + 0.1 );\n";
+ code += "\tp *= 17.0;\n";
+ code += "\treturn fract(p.x * p.y * p.z * (p.x + p.y + p.z));\n";
+ code += "}\n\n";
+
+ code += "void fragment() {\n";
+ code += "\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n";
+ code += "\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n";
+ code += "\tfloat sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);\n\n";
+
+ code += "\t// rayleigh coefficients\n";
+ code += "\tfloat rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );\n";
+ code += "\tvec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;\n";
+ code += "\t// mie coefficients from Preetham\n";
+ code += "\tvec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;\n\n";
+
+ code += "\t// optical length\n";
+ code += "\tfloat zenith = acos(max(0.0, dot(UP, EYEDIR)));\n";
+ code += "\tfloat optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));\n";
+ code += "\tfloat rayleigh_scatter = rayleigh_zenith_size * optical_mass;\n";
+ code += "\tfloat mie_scatter = mie_zenith_size * optical_mass;\n\n";
+
+ code += "\t// light extinction based on thickness of atmosphere\n";
+ code += "\tvec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));\n\n";
+
+ code += "\t// in scattering\n";
+ code += "\tfloat cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));\n\n";
+
+ code += "\tfloat rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));\n";
+ code += "\tvec3 betaRTheta = rayleigh_beta * rayleigh_phase;\n\n";
+
+ code += "\tfloat mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);\n";
+ code += "\tvec3 betaMTheta = mie_beta * mie_phase;\n\n";
+
+ code += "\tvec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));\n";
+ code += "\t// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js\n";
+ code += "\tLin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));\n\n";
+
+ code += "\t// Hack in the ground color\n";
+ code += "\tLin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));\n\n";
+
+ code += "\t// Solar disk and out-scattering\n";
+ code += "\tfloat sunAngularDiameterCos = cos(SOL_SIZE * sun_disk_scale);\n";
+ code += "\tfloat sunAngularDiameterCos2 = cos(SOL_SIZE * sun_disk_scale*0.5);\n";
+ code += "\tfloat sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);\n";
+ code += "\tvec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;\n";
+ code += "\t// Note: Add nightime here: L0 += night_sky * extinction\n\n";
+
+ code += "\tvec3 color = (Lin + L0) * 0.04;\n";
+ code += "\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n";
+ code += "\tCOLOR *= exposure;\n";
+ code += "\t// Make optional, eliminates banding\n";
+ code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.008 * dither_strength;\n";
+ code += "}\n";
+
+ shader = RS::get_singleton()->shader_create();
+
+ RS::get_singleton()->shader_set_code(shader, code);
+
+ RS::get_singleton()->material_set_shader(_get_material(), shader);
+
+ set_rayleigh_coefficient(2.0);
+ set_rayleigh_color(Color(0.056, 0.14, 0.3));
+ set_mie_coefficient(0.005);
+ set_mie_eccentricity(0.8);
+ set_mie_color(Color(0.36, 0.56, 0.82));
+ set_turbidity(10.0);
+ set_sun_disk_scale(1.0);
+ set_ground_color(Color(1.0, 1.0, 1.0));
+ set_exposure(0.1);
+ set_dither_strength(1.0);
+}
+
+PhysicalSkyMaterial::~PhysicalSkyMaterial() {
+ RS::get_singleton()->free(shader);
+ RS::get_singleton()->material_set_shader(_get_material(), RID());
+}
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
new file mode 100644
index 0000000000..515706b0c5
--- /dev/null
+++ b/scene/resources/sky_material.h
@@ -0,0 +1,190 @@
+/*************************************************************************/
+/* sky_material.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "core/rid.h"
+#include "scene/resources/material.h"
+
+#ifndef SKY_MATERIAL_H
+#define SKY_MATERIAL_H
+
+class ProceduralSkyMaterial : public Material {
+
+ GDCLASS(ProceduralSkyMaterial, Material);
+
+private:
+ Color sky_top_color;
+ Color sky_horizon_color;
+ float sky_curve;
+ float sky_energy;
+
+ Color ground_bottom_color;
+ Color ground_horizon_color;
+ float ground_curve;
+ float ground_energy;
+
+ float sun_angle_min;
+ float sun_angle_max;
+ float sun_curve;
+
+ RID shader;
+
+protected:
+ static void _bind_methods();
+ virtual bool _can_do_next_pass() const;
+
+public:
+ void set_sky_top_color(const Color &p_sky_top);
+ Color get_sky_top_color() const;
+
+ void set_sky_horizon_color(const Color &p_sky_horizon);
+ Color get_sky_horizon_color() const;
+
+ void set_sky_curve(float p_curve);
+ float get_sky_curve() const;
+
+ void set_sky_energy(float p_energy);
+ float get_sky_energy() const;
+
+ void set_ground_bottom_color(const Color &p_ground_bottom);
+ Color get_ground_bottom_color() const;
+
+ void set_ground_horizon_color(const Color &p_ground_horizon);
+ Color get_ground_horizon_color() const;
+
+ void set_ground_curve(float p_curve);
+ float get_ground_curve() const;
+
+ void set_ground_energy(float p_energy);
+ float get_ground_energy() const;
+
+ void set_sun_angle_min(float p_angle);
+ float get_sun_angle_min() const;
+
+ void set_sun_angle_max(float p_angle);
+ float get_sun_angle_max() const;
+
+ void set_sun_curve(float p_curve);
+ float get_sun_curve() const;
+
+ virtual Shader::Mode get_shader_mode() const;
+ RID get_shader_rid() const;
+
+ ProceduralSkyMaterial();
+ ~ProceduralSkyMaterial();
+};
+
+//////////////////////////////////////////////////////
+/* PanoramaSkyMaterial */
+
+class PanoramaSkyMaterial : public Material {
+ GDCLASS(PanoramaSkyMaterial, Material);
+
+private:
+ Ref<Texture2D> panorama;
+ RID shader;
+
+protected:
+ static void _bind_methods();
+ virtual bool _can_do_next_pass() const;
+
+public:
+ void set_panorama(const Ref<Texture2D> &p_panorama);
+ Ref<Texture2D> get_panorama() const;
+
+ virtual Shader::Mode get_shader_mode() const;
+ RID get_shader_rid() const;
+
+ PanoramaSkyMaterial();
+ ~PanoramaSkyMaterial();
+};
+
+//////////////////////////////////////////////////////
+/* PanoramaSkyMaterial */
+
+class PhysicalSkyMaterial : public Material {
+ GDCLASS(PhysicalSkyMaterial, Material);
+
+private:
+ RID shader;
+
+ float rayleigh;
+ Color rayleigh_color;
+ float mie;
+ float mie_eccentricity;
+ Color mie_color;
+ float turbidity;
+ float sun_disk_scale;
+ Color ground_color;
+ float exposure;
+ float dither_strength;
+
+protected:
+ static void _bind_methods();
+ virtual bool _can_do_next_pass() const;
+
+public:
+ void set_rayleigh_coefficient(float p_rayleigh);
+ float get_rayleigh_coefficient() const;
+
+ void set_rayleigh_color(Color p_rayleigh_color);
+ Color get_rayleigh_color() const;
+
+ void set_turbidity(float p_turbidity);
+ float get_turbidity() const;
+
+ void set_mie_coefficient(float p_mie);
+ float get_mie_coefficient() const;
+
+ void set_mie_eccentricity(float p_eccentricity);
+ float get_mie_eccentricity() const;
+
+ void set_mie_color(Color p_mie_color);
+ Color get_mie_color() const;
+
+ void set_sun_disk_scale(float p_sun_disk_scale);
+ float get_sun_disk_scale() const;
+
+ void set_ground_color(Color p_ground_color);
+ Color get_ground_color() const;
+
+ void set_exposure(float p_exposure);
+ float get_exposure() const;
+
+ void set_dither_strength(float p_dither_strength);
+ float get_dither_strength() const;
+
+ virtual Shader::Mode get_shader_mode() const;
+ RID get_shader_rid() const;
+
+ PhysicalSkyMaterial();
+ ~PhysicalSkyMaterial();
+};
+
+#endif /* !SKY_MATERIAL_H */
diff --git a/scene/resources/space_2d.cpp b/scene/resources/space_2d.cpp
deleted file mode 100644
index 376e926548..0000000000
--- a/scene/resources/space_2d.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*************************************************************************/
-/* space_2d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "space_2d.h"
-
-RID Space2D::get_rid() const {
-
- return space;
-}
-
-void Space2D::set_active(bool p_active) {
-
- active = p_active;
- Physics2DServer::get_singleton()->space_set_active(space, active);
-}
-
-bool Space2D::is_active() const {
-
- return active;
-}
-
-void Space2D::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_active", "active"), &Space2D::set_active);
- ClassDB::bind_method(D_METHOD("is_active"), &Space2D::is_active);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
-}
-
-Space2D::Space2D() {
-
- active = false;
- space = Physics2DServer::get_singleton()->space_create();
-}
-
-Space2D::~Space2D() {
-
- Physics2DServer::get_singleton()->free(space);
-}
diff --git a/scene/resources/space_2d.h b/scene/resources/space_2d.h
deleted file mode 100644
index ff88c40348..0000000000
--- a/scene/resources/space_2d.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*************************************************************************/
-/* space_2d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPACE_2D_H
-#define SPACE_2D_H
-
-#include "core/resource.h"
-#include "servers/physics_2d_server.h"
-
-class Space2D : public Resource {
-
- GDCLASS(Space2D, Resource);
- bool active;
- RID space;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_active(bool p_active);
- bool is_active() const;
-
- virtual RID get_rid() const;
-
- Space2D();
- ~Space2D();
-};
-
-#endif // SPACE_2D_H
diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp
deleted file mode 100644
index 825708d1e2..0000000000
--- a/scene/resources/sphere_shape.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*************************************************************************/
-/* sphere_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "sphere_shape.h"
-#include "servers/physics_server.h"
-
-Vector<Vector3> SphereShape::get_debug_mesh_lines() {
-
- float r = get_radius();
-
- Vector<Vector3> points;
-
- for (int i = 0; i <= 360; i++) {
-
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- points.push_back(Vector3(a.x, 0, a.y));
- points.push_back(Vector3(b.x, 0, b.y));
- points.push_back(Vector3(0, a.x, a.y));
- points.push_back(Vector3(0, b.x, b.y));
- points.push_back(Vector3(a.x, a.y, 0));
- points.push_back(Vector3(b.x, b.y, 0));
- }
-
- return points;
-}
-
-real_t SphereShape::get_enclosing_radius() const {
- return radius;
-}
-
-void SphereShape::_update_shape() {
-
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), radius);
- Shape::_update_shape();
-}
-
-void SphereShape::set_radius(float p_radius) {
-
- radius = p_radius;
- _update_shape();
- notify_change_to_owners();
- _change_notify("radius");
-}
-
-float SphereShape::get_radius() const {
-
- return radius;
-}
-
-void SphereShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape::get_radius);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_radius", "get_radius");
-}
-
-SphereShape::SphereShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_SPHERE)) {
-
- set_radius(1.0);
-}
diff --git a/scene/resources/sphere_shape.h b/scene/resources/sphere_shape.h
deleted file mode 100644
index 07e8f1e233..0000000000
--- a/scene/resources/sphere_shape.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*************************************************************************/
-/* sphere_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPHERE_SHAPE_H
-#define SPHERE_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class SphereShape : public Shape {
-
- GDCLASS(SphereShape, Shape);
- float radius;
-
-protected:
- static void _bind_methods();
-
- virtual void _update_shape();
-
-public:
- void set_radius(float p_radius);
- float get_radius() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const;
-
- SphereShape();
-};
-
-#endif // SPHERE_SHAPE_H
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
new file mode 100644
index 0000000000..153db4c291
--- /dev/null
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -0,0 +1,93 @@
+/*************************************************************************/
+/* sphere_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "sphere_shape_3d.h"
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> SphereShape3D::get_debug_mesh_lines() {
+
+ float r = get_radius();
+
+ Vector<Vector3> points;
+
+ for (int i = 0; i <= 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ points.push_back(Vector3(a.x, 0, a.y));
+ points.push_back(Vector3(b.x, 0, b.y));
+ points.push_back(Vector3(0, a.x, a.y));
+ points.push_back(Vector3(0, b.x, b.y));
+ points.push_back(Vector3(a.x, a.y, 0));
+ points.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ return points;
+}
+
+real_t SphereShape3D::get_enclosing_radius() const {
+ return radius;
+}
+
+void SphereShape3D::_update_shape() {
+
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), radius);
+ Shape3D::_update_shape();
+}
+
+void SphereShape3D::set_radius(float p_radius) {
+
+ radius = p_radius;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("radius");
+}
+
+float SphereShape3D::get_radius() const {
+
+ return radius;
+}
+
+void SphereShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SphereShape3D::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &SphereShape3D::get_radius);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_radius", "get_radius");
+}
+
+SphereShape3D::SphereShape3D() :
+ Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_SPHERE)) {
+
+ set_radius(1.0);
+}
diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h
new file mode 100644
index 0000000000..3ed50cfe83
--- /dev/null
+++ b/scene/resources/sphere_shape_3d.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* sphere_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPHERE_SHAPE_3D_H
+#define SPHERE_SHAPE_3D_H
+
+#include "scene/resources/shape_3d.h"
+
+class SphereShape3D : public Shape3D {
+
+ GDCLASS(SphereShape3D, Shape3D);
+ float radius;
+
+protected:
+ static void _bind_methods();
+
+ virtual void _update_shape();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const;
+
+ SphereShape3D();
+};
+
+#endif // SPHERE_SHAPE_H
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 119cbcd098..56fb5d441f 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -29,7 +29,8 @@
/*************************************************************************/
#include "style_box.h"
-#include "scene/2d/canvas_item.h"
+
+#include "scene/main/canvas_item.h"
#include <limits.h>
@@ -201,7 +202,7 @@ void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const {
if (normal_map.is_valid())
normal_rid = normal_map->get_rid();
- VisualServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), VS::NinePatchAxisMode(axis_h), VS::NinePatchAxisMode(axis_v), draw_center, modulate, normal_rid);
+ RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[MARGIN_LEFT], margin[MARGIN_TOP]), Vector2(margin[MARGIN_RIGHT], margin[MARGIN_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate, normal_rid);
}
void StyleBoxTexture::set_draw_center(bool p_enabled) {
@@ -852,7 +853,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
//DRAWING
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs);
}
@@ -1049,7 +1050,7 @@ Size2 StyleBoxLine::get_center_size() const {
}
void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
Rect2i r = p_rect;
if (vertical) {
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 1aa1a00c55..f19b93d00d 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -33,7 +33,7 @@
#include "core/resource.h"
#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
class CanvasItem;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index fa177d03fb..4b392e23b7 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -519,7 +519,7 @@ void SurfaceTool::deindex() {
void SurfaceTool::_create_list(const Ref<Mesh> &p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
Array arr = p_existing->surface_get_arrays(p_surface);
- ERR_FAIL_COND(arr.size() != VS::ARRAY_MAX);
+ ERR_FAIL_COND(arr.size() != RS::ARRAY_MAX);
_create_list_from_arrays(arr, r_vertex, r_index, lformat);
}
@@ -527,14 +527,14 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
Vector<SurfaceTool::Vertex> ret;
- Vector<Vector3> varr = p_arrays[VS::ARRAY_VERTEX];
- Vector<Vector3> narr = p_arrays[VS::ARRAY_NORMAL];
- Vector<float> tarr = p_arrays[VS::ARRAY_TANGENT];
- Vector<Color> carr = p_arrays[VS::ARRAY_COLOR];
- Vector<Vector2> uvarr = p_arrays[VS::ARRAY_TEX_UV];
- Vector<Vector2> uv2arr = p_arrays[VS::ARRAY_TEX_UV2];
- Vector<int> barr = p_arrays[VS::ARRAY_BONES];
- Vector<float> warr = p_arrays[VS::ARRAY_WEIGHTS];
+ Vector<Vector3> varr = p_arrays[RS::ARRAY_VERTEX];
+ Vector<Vector3> narr = p_arrays[RS::ARRAY_NORMAL];
+ Vector<float> tarr = p_arrays[RS::ARRAY_TANGENT];
+ Vector<Color> carr = p_arrays[RS::ARRAY_COLOR];
+ Vector<Vector2> uvarr = p_arrays[RS::ARRAY_TEX_UV];
+ Vector<Vector2> uv2arr = p_arrays[RS::ARRAY_TEX_UV2];
+ Vector<int> barr = p_arrays[RS::ARRAY_BONES];
+ Vector<float> warr = p_arrays[RS::ARRAY_WEIGHTS];
int vc = varr.size();
if (vc == 0)
@@ -542,48 +542,48 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
int lformat = 0;
if (varr.size()) {
- lformat |= VS::ARRAY_FORMAT_VERTEX;
+ lformat |= RS::ARRAY_FORMAT_VERTEX;
}
if (narr.size()) {
- lformat |= VS::ARRAY_FORMAT_NORMAL;
+ lformat |= RS::ARRAY_FORMAT_NORMAL;
}
if (tarr.size()) {
- lformat |= VS::ARRAY_FORMAT_TANGENT;
+ lformat |= RS::ARRAY_FORMAT_TANGENT;
}
if (carr.size()) {
- lformat |= VS::ARRAY_FORMAT_COLOR;
+ lformat |= RS::ARRAY_FORMAT_COLOR;
}
if (uvarr.size()) {
- lformat |= VS::ARRAY_FORMAT_TEX_UV;
+ lformat |= RS::ARRAY_FORMAT_TEX_UV;
}
if (uv2arr.size()) {
- lformat |= VS::ARRAY_FORMAT_TEX_UV2;
+ lformat |= RS::ARRAY_FORMAT_TEX_UV2;
}
if (barr.size()) {
- lformat |= VS::ARRAY_FORMAT_BONES;
+ lformat |= RS::ARRAY_FORMAT_BONES;
}
if (warr.size()) {
- lformat |= VS::ARRAY_FORMAT_WEIGHTS;
+ lformat |= RS::ARRAY_FORMAT_WEIGHTS;
}
for (int i = 0; i < vc; i++) {
Vertex v;
- if (lformat & VS::ARRAY_FORMAT_VERTEX)
+ if (lformat & RS::ARRAY_FORMAT_VERTEX)
v.vertex = varr[i];
- if (lformat & VS::ARRAY_FORMAT_NORMAL)
+ if (lformat & RS::ARRAY_FORMAT_NORMAL)
v.normal = narr[i];
- if (lformat & VS::ARRAY_FORMAT_TANGENT) {
+ if (lformat & RS::ARRAY_FORMAT_TANGENT) {
Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]);
v.tangent = p.normal;
v.binormal = p.normal.cross(v.tangent).normalized() * p.d;
}
- if (lformat & VS::ARRAY_FORMAT_COLOR)
+ if (lformat & RS::ARRAY_FORMAT_COLOR)
v.color = carr[i];
- if (lformat & VS::ARRAY_FORMAT_TEX_UV)
+ if (lformat & RS::ARRAY_FORMAT_TEX_UV)
v.uv = uvarr[i];
- if (lformat & VS::ARRAY_FORMAT_TEX_UV2)
+ if (lformat & RS::ARRAY_FORMAT_TEX_UV2)
v.uv2 = uv2arr[i];
- if (lformat & VS::ARRAY_FORMAT_BONES) {
+ if (lformat & RS::ARRAY_FORMAT_BONES) {
Vector<int> b;
b.resize(4);
b.write[0] = barr[i * 4 + 0];
@@ -592,7 +592,7 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
b.write[3] = barr[i * 4 + 3];
v.bones = b;
}
- if (lformat & VS::ARRAY_FORMAT_WEIGHTS) {
+ if (lformat & RS::ARRAY_FORMAT_WEIGHTS) {
Vector<float> w;
w.resize(4);
w.write[0] = warr[i * 4 + 0];
@@ -610,14 +610,14 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, List<int> *r_index, int &lformat) {
- Vector<Vector3> varr = arr[VS::ARRAY_VERTEX];
- Vector<Vector3> narr = arr[VS::ARRAY_NORMAL];
- Vector<float> tarr = arr[VS::ARRAY_TANGENT];
- Vector<Color> carr = arr[VS::ARRAY_COLOR];
- Vector<Vector2> uvarr = arr[VS::ARRAY_TEX_UV];
- Vector<Vector2> uv2arr = arr[VS::ARRAY_TEX_UV2];
- Vector<int> barr = arr[VS::ARRAY_BONES];
- Vector<float> warr = arr[VS::ARRAY_WEIGHTS];
+ Vector<Vector3> varr = arr[RS::ARRAY_VERTEX];
+ Vector<Vector3> narr = arr[RS::ARRAY_NORMAL];
+ Vector<float> tarr = arr[RS::ARRAY_TANGENT];
+ Vector<Color> carr = arr[RS::ARRAY_COLOR];
+ Vector<Vector2> uvarr = arr[RS::ARRAY_TEX_UV];
+ Vector<Vector2> uv2arr = arr[RS::ARRAY_TEX_UV2];
+ Vector<int> barr = arr[RS::ARRAY_BONES];
+ Vector<float> warr = arr[RS::ARRAY_WEIGHTS];
int vc = varr.size();
if (vc == 0)
@@ -625,48 +625,48 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li
lformat = 0;
if (varr.size()) {
- lformat |= VS::ARRAY_FORMAT_VERTEX;
+ lformat |= RS::ARRAY_FORMAT_VERTEX;
}
if (narr.size()) {
- lformat |= VS::ARRAY_FORMAT_NORMAL;
+ lformat |= RS::ARRAY_FORMAT_NORMAL;
}
if (tarr.size()) {
- lformat |= VS::ARRAY_FORMAT_TANGENT;
+ lformat |= RS::ARRAY_FORMAT_TANGENT;
}
if (carr.size()) {
- lformat |= VS::ARRAY_FORMAT_COLOR;
+ lformat |= RS::ARRAY_FORMAT_COLOR;
}
if (uvarr.size()) {
- lformat |= VS::ARRAY_FORMAT_TEX_UV;
+ lformat |= RS::ARRAY_FORMAT_TEX_UV;
}
if (uv2arr.size()) {
- lformat |= VS::ARRAY_FORMAT_TEX_UV2;
+ lformat |= RS::ARRAY_FORMAT_TEX_UV2;
}
if (barr.size()) {
- lformat |= VS::ARRAY_FORMAT_BONES;
+ lformat |= RS::ARRAY_FORMAT_BONES;
}
if (warr.size()) {
- lformat |= VS::ARRAY_FORMAT_WEIGHTS;
+ lformat |= RS::ARRAY_FORMAT_WEIGHTS;
}
for (int i = 0; i < vc; i++) {
Vertex v;
- if (lformat & VS::ARRAY_FORMAT_VERTEX)
+ if (lformat & RS::ARRAY_FORMAT_VERTEX)
v.vertex = varr[i];
- if (lformat & VS::ARRAY_FORMAT_NORMAL)
+ if (lformat & RS::ARRAY_FORMAT_NORMAL)
v.normal = narr[i];
- if (lformat & VS::ARRAY_FORMAT_TANGENT) {
+ if (lformat & RS::ARRAY_FORMAT_TANGENT) {
Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]);
v.tangent = p.normal;
v.binormal = p.normal.cross(v.tangent).normalized() * p.d;
}
- if (lformat & VS::ARRAY_FORMAT_COLOR)
+ if (lformat & RS::ARRAY_FORMAT_COLOR)
v.color = carr[i];
- if (lformat & VS::ARRAY_FORMAT_TEX_UV)
+ if (lformat & RS::ARRAY_FORMAT_TEX_UV)
v.uv = uvarr[i];
- if (lformat & VS::ARRAY_FORMAT_TEX_UV2)
+ if (lformat & RS::ARRAY_FORMAT_TEX_UV2)
v.uv2 = uv2arr[i];
- if (lformat & VS::ARRAY_FORMAT_BONES) {
+ if (lformat & RS::ARRAY_FORMAT_BONES) {
Vector<int> b;
b.resize(4);
b.write[0] = barr[i * 4 + 0];
@@ -675,7 +675,7 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li
b.write[3] = barr[i * 4 + 3];
v.bones = b;
}
- if (lformat & VS::ARRAY_FORMAT_WEIGHTS) {
+ if (lformat & RS::ARRAY_FORMAT_WEIGHTS) {
Vector<float> w;
w.resize(4);
w.write[0] = warr[i * 4 + 0];
@@ -690,11 +690,11 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li
//indices
- Vector<int> idx = arr[VS::ARRAY_INDEX];
+ Vector<int> idx = arr[RS::ARRAY_INDEX];
int is = idx.size();
if (is) {
- lformat |= VS::ARRAY_FORMAT_INDEX;
+ lformat |= RS::ARRAY_FORMAT_INDEX;
const int *iarr = idx.ptr();
for (int i = 0; i < is; i++) {
r_index->push_back(iarr[i]);
@@ -733,7 +733,7 @@ void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_sur
ERR_FAIL_COND(shape_idx == -1);
ERR_FAIL_COND(shape_idx >= arr.size());
Array mesh = arr[shape_idx];
- ERR_FAIL_COND(mesh.size() != VS::ARRAY_MAX);
+ ERR_FAIL_COND(mesh.size() != RS::ARRAY_MAX);
_create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format);
}
@@ -755,10 +755,10 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
Vertex v = E->get();
v.vertex = p_xform.xform(v.vertex);
- if (nformat & VS::ARRAY_FORMAT_NORMAL) {
+ if (nformat & RS::ARRAY_FORMAT_NORMAL) {
v.normal = p_xform.basis.xform(v.normal);
}
- if (nformat & VS::ARRAY_FORMAT_TANGENT) {
+ if (nformat & RS::ARRAY_FORMAT_TANGENT) {
v.tangent = p_xform.basis.xform(v.tangent);
v.binormal = p_xform.basis.xform(v.binormal);
}
@@ -854,7 +854,7 @@ void SurfaceTool::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, cons
const tbool bIsOrientationPreserving, const int iFace, const int iVert) {
TangentGenerationContextUserData &triangle_data = *reinterpret_cast<TangentGenerationContextUserData *>(pContext->m_pUserData);
- Vertex *vtx = NULL;
+ Vertex *vtx = nullptr;
if (triangle_data.indices.size() > 0) {
int index = triangle_data.indices[iFace * 3 + iVert]->get();
if (index < triangle_data.vertices.size()) {
@@ -864,7 +864,7 @@ void SurfaceTool::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, cons
vtx = &triangle_data.vertices[iFace * 3 + iVert]->get();
}
- if (vtx != NULL) {
+ if (vtx != nullptr) {
vtx->tangent = Vector3(fvTangent[0], fvTangent[1], fvTangent[2]);
vtx->binormal = Vector3(-fvBiTangent[0], -fvBiTangent[1], -fvBiTangent[2]); // for some reason these are reversed, something with the coordinate system in Godot
}
@@ -882,7 +882,7 @@ void SurfaceTool::generate_tangents() {
mkif.m_getPosition = mikktGetPosition;
mkif.m_getTexCoord = mikktGetTexCoord;
mkif.m_setTSpace = mikktSetTSpaceDefault;
- mkif.m_setTSpaceBasic = NULL;
+ mkif.m_setTSpaceBasic = nullptr;
SMikkTSpaceContext msc;
msc.m_pInterface = &mkif;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index cb827c4b0b..749dff24f2 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -47,25 +47,25 @@ bool Texture2D::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
+void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat);
}
bool Texture2D::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
@@ -82,9 +82,9 @@ void Texture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_height"), &Texture2D::get_height);
ClassDB::bind_method(D_METHOD("get_size"), &Texture2D::get_size);
ClassDB::bind_method(D_METHOD("has_alpha"), &Texture2D::has_alpha);
- ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT));
- ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT));
- ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT));
+ ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT));
+ ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_color_shininess", "texture_filter", "texture_repeat", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT), DEFVAL(RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT), DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_data"), &Texture2D::get_data);
ADD_GROUP("", "");
@@ -121,7 +121,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
Size2 s = p_value;
w = s.width;
h = s.height;
- VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
+ RenderingServer::get_singleton()->texture_set_size_override(texture, w, h);
} else
return false;
@@ -158,8 +158,8 @@ void ImageTexture::_reload_hook(const RID &p_hook) {
ERR_FAIL_COND_MSG(err != OK, "Cannot load image from path '" + path + "'.");
- RID new_texture = VisualServer::get_singleton()->texture_2d_create(img);
- VisualServer::get_singleton()->texture_replace(texture, new_texture);
+ RID new_texture = RenderingServer::get_singleton()->texture_2d_create(img);
+ RenderingServer::get_singleton()->texture_replace(texture, new_texture);
_change_notify();
emit_changed();
@@ -174,10 +174,10 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image) {
mipmaps = p_image->has_mipmaps();
if (texture.is_null()) {
- texture = VisualServer::get_singleton()->texture_2d_create(p_image);
+ texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
} else {
- RID new_texture = VisualServer::get_singleton()->texture_2d_create(p_image);
- VisualServer::get_singleton()->texture_replace(texture, new_texture);
+ RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_image);
+ RenderingServer::get_singleton()->texture_replace(texture, new_texture);
}
_change_notify();
emit_changed();
@@ -199,9 +199,9 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) {
ERR_FAIL_COND(mipmaps != p_image->has_mipmaps());
if (p_immediate) {
- VisualServer::get_singleton()->texture_2d_update_immediate(texture, p_image);
+ RenderingServer::get_singleton()->texture_2d_update_immediate(texture, p_image);
} else {
- VisualServer::get_singleton()->texture_2d_update(texture, p_image);
+ RenderingServer::get_singleton()->texture_2d_update(texture, p_image);
}
_change_notify();
@@ -219,7 +219,7 @@ void ImageTexture::_resource_path_changed() {
Ref<Image> ImageTexture::get_data() const {
if (image_stored) {
- return VisualServer::get_singleton()->texture_2d_get(texture);
+ return RenderingServer::get_singleton()->texture_2d_get(texture);
} else {
return Ref<Image>();
}
@@ -239,7 +239,7 @@ RID ImageTexture::get_rid() const {
if (texture.is_null()) {
//we are in trouble, create something temporary
- texture = VisualServer::get_singleton()->texture_2d_placeholder_create();
+ texture = RenderingServer::get_singleton()->texture_2d_placeholder_create();
}
return texture;
}
@@ -249,29 +249,29 @@ bool ImageTexture::has_alpha() const {
return (format == Image::FORMAT_LA8 || format == Image::FORMAT_RGBA8);
}
-void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if ((w | h) == 0)
return;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if ((w | h) == 0)
return;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
+void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
if ((w | h) == 0)
return;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat);
}
bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
@@ -316,13 +316,13 @@ void ImageTexture::set_size_override(const Size2 &p_size) {
w = s.x;
if (s.y != 0)
h = s.y;
- VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
+ RenderingServer::get_singleton()->texture_set_size_override(texture, w, h);
}
void ImageTexture::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
- VisualServer::get_singleton()->texture_set_path(texture, p_path);
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
Resource::set_path(p_path, p_take_over);
@@ -349,7 +349,7 @@ ImageTexture::ImageTexture() {
ImageTexture::~ImageTexture() {
if (texture.is_valid()) {
- VisualServer::get_singleton()->free(texture);
+ RenderingServer::get_singleton()->free(texture);
}
}
@@ -370,7 +370,7 @@ Ref<Image> StreamTexture::load_image_from_file(FileAccess *f, int p_size_limit)
int sh = h;
//mipmaps need to be read independently, they will be later combined
- Vector<Ref<Image> > mipmap_images;
+ Vector<Ref<Image>> mipmap_images;
int total_size = 0;
bool first = true;
@@ -495,7 +495,7 @@ Ref<Image> StreamTexture::load_image_from_file(FileAccess *f, int p_size_limit)
void StreamTexture::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
- VisualServer::get_singleton()->texture_set_path(texture, p_path);
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
Resource::set_path(p_path, p_take_over);
@@ -509,7 +509,7 @@ void StreamTexture::_requested_3d(void *p_ud) {
request_3d_callback(stex);
}
-void StreamTexture::_requested_roughness(void *p_ud, const String &p_normal_path, VS::TextureDetectRoughnessChannel p_roughness_channel) {
+void StreamTexture::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) {
StreamTexture *st = (StreamTexture *)p_ud;
Ref<StreamTexture> stex(st);
@@ -525,9 +525,9 @@ void StreamTexture::_requested_normal(void *p_ud) {
request_normal_callback(stex);
}
-StreamTexture::TextureFormatRequestCallback StreamTexture::request_3d_callback = NULL;
-StreamTexture::TextureFormatRoughnessRequestCallback StreamTexture::request_roughness_callback = NULL;
-StreamTexture::TextureFormatRequestCallback StreamTexture::request_normal_callback = NULL;
+StreamTexture::TextureFormatRequestCallback StreamTexture::request_3d_callback = nullptr;
+StreamTexture::TextureFormatRoughnessRequestCallback StreamTexture::request_roughness_callback = nullptr;
+StreamTexture::TextureFormatRequestCallback StreamTexture::request_normal_callback = nullptr;
Image::Format StreamTexture::get_format() const {
@@ -611,13 +611,13 @@ Error StreamTexture::load(const String &p_path) {
return err;
if (texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_create(image);
- VS::get_singleton()->texture_replace(texture, new_texture);
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
} else {
- texture = VS::get_singleton()->texture_2d_create(image);
+ texture = RS::get_singleton()->texture_2d_create(image);
}
if (lwc || lhc) {
- VS::get_singleton()->texture_set_size_override(texture, lwc, lhc);
+ RS::get_singleton()->texture_set_size_override(texture, lwc, lhc);
}
w = lwc ? lwc : lw;
@@ -627,33 +627,33 @@ Error StreamTexture::load(const String &p_path) {
if (get_path() == String()) {
//temporarily set path if no path set for resource, helps find errors
- VisualServer::get_singleton()->texture_set_path(texture, p_path);
+ RenderingServer::get_singleton()->texture_set_path(texture, p_path);
}
#ifdef TOOLS_ENABLED
if (request_3d) {
//print_line("request detect 3D at " + p_path);
- VS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);
+ RS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);
} else {
//print_line("not requesting detect 3D at " + p_path);
- VS::get_singleton()->texture_set_detect_3d_callback(texture, NULL, NULL);
+ RS::get_singleton()->texture_set_detect_3d_callback(texture, nullptr, nullptr);
}
if (request_roughness) {
//print_line("request detect srgb at " + p_path);
- VS::get_singleton()->texture_set_detect_roughness_callback(texture, _requested_roughness, this);
+ RS::get_singleton()->texture_set_detect_roughness_callback(texture, _requested_roughness, this);
} else {
//print_line("not requesting detect srgb at " + p_path);
- VS::get_singleton()->texture_set_detect_roughness_callback(texture, NULL, NULL);
+ RS::get_singleton()->texture_set_detect_roughness_callback(texture, nullptr, nullptr);
}
if (request_normal) {
//print_line("request detect srgb at " + p_path);
- VS::get_singleton()->texture_set_detect_normal_callback(texture, _requested_normal, this);
+ RS::get_singleton()->texture_set_detect_normal_callback(texture, _requested_normal, this);
} else {
//print_line("not requesting detect normal at " + p_path);
- VS::get_singleton()->texture_set_detect_normal_callback(texture, NULL, NULL);
+ RS::get_singleton()->texture_set_detect_normal_callback(texture, nullptr, nullptr);
}
#endif
@@ -677,34 +677,34 @@ int StreamTexture::get_height() const {
RID StreamTexture::get_rid() const {
if (!texture.is_valid()) {
- texture = VS::get_singleton()->texture_2d_placeholder_create();
+ texture = RS::get_singleton()->texture_2d_placeholder_create();
}
return texture;
}
-void StreamTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void StreamTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if ((w | h) == 0)
return;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void StreamTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void StreamTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if ((w | h) == 0)
return;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void StreamTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
+void StreamTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
if ((w | h) == 0)
return;
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat);
}
bool StreamTexture::has_alpha() const {
@@ -715,7 +715,7 @@ bool StreamTexture::has_alpha() const {
Ref<Image> StreamTexture::get_data() const {
if (texture.is_valid()) {
- return VS::get_singleton()->texture_2d_get(texture);
+ return RS::get_singleton()->texture_2d_get(texture);
} else {
return Ref<Image>();
}
@@ -792,7 +792,7 @@ StreamTexture::StreamTexture() {
StreamTexture::~StreamTexture() {
if (texture.is_valid()) {
- VS::get_singleton()->free(texture);
+ RS::get_singleton()->free(texture);
}
}
@@ -935,7 +935,7 @@ void AtlasTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
}
-void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if (!atlas.is_valid())
return;
@@ -952,10 +952,10 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_m
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat);
+ RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat);
}
-void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if (!atlas.is_valid())
return;
@@ -975,9 +975,9 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat);
+ RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat);
}
-void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
+void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
//this might not necessarily work well if using a rect, needs to be fixed properly
if (!atlas.is_valid())
@@ -989,7 +989,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat);
+ RS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, filter_clip, p_texture_filter, p_texture_repeat);
}
bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
@@ -1087,7 +1087,7 @@ Ref<Texture2D> MeshTexture::get_base_texture() const {
return base_texture;
}
-void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if (mesh.is_null() || base_texture.is_null()) {
return;
@@ -1100,9 +1100,9 @@ void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_mo
}
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
if (mesh.is_null() || base_texture.is_null()) {
return;
}
@@ -1123,9 +1123,9 @@ void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile,
}
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
-void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
+void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
if (mesh.is_null() || base_texture.is_null()) {
return;
@@ -1147,7 +1147,7 @@ void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const
}
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
+ RenderingServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
r_rect = p_rect;
@@ -1300,7 +1300,7 @@ void LargeTexture::_bind_methods() {
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 Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
for (int i = 0; i < pieces.size(); i++) {
@@ -1309,7 +1309,7 @@ void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_m
}
}
-void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat) const {
+void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const {
//tiling not supported for this
if (size.x == 0 || size.y == 0)
@@ -1323,7 +1323,7 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
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, p_normal_map, p_specular_map, p_specular_color_shininess, p_texture_filter, p_texture_repeat);
}
}
-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, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, VS::CanvasItemTextureFilter p_texture_filter, VS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
+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, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const {
//tiling not supported for this
if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0)
@@ -1445,10 +1445,10 @@ void CurveTexture::_update() {
Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data));
if (_texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_create(image);
- VS::get_singleton()->texture_replace(_texture, new_texture);
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(_texture, new_texture);
} else {
- _texture = VS::get_singleton()->texture_2d_create(image);
+ _texture = RS::get_singleton()->texture_2d_create(image);
}
emit_changed();
@@ -1462,7 +1462,7 @@ Ref<Curve> CurveTexture::get_curve() const {
RID CurveTexture::get_rid() const {
if (!_texture.is_valid()) {
- _texture = VS::get_singleton()->texture_2d_placeholder_create();
+ _texture = RS::get_singleton()->texture_2d_placeholder_create();
}
return _texture;
}
@@ -1472,7 +1472,7 @@ CurveTexture::CurveTexture() {
}
CurveTexture::~CurveTexture() {
if (_texture.is_valid()) {
- VS::get_singleton()->free(_texture);
+ RS::get_singleton()->free(_texture);
}
}
//////////////////
@@ -1492,7 +1492,7 @@ GradientTexture::GradientTexture() {
GradientTexture::~GradientTexture() {
if (texture.is_valid()) {
- VS::get_singleton()->free(texture);
+ RS::get_singleton()->free(texture);
}
}
@@ -1564,10 +1564,10 @@ void GradientTexture::_update() {
Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
if (texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_create(image);
- VS::get_singleton()->texture_replace(texture, new_texture);
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
} else {
- texture = VS::get_singleton()->texture_2d_create(image);
+ texture = RS::get_singleton()->texture_2d_create(image);
}
emit_changed();
@@ -1587,7 +1587,7 @@ Ref<Image> GradientTexture::get_data() const {
if (!texture.is_valid()) {
return Ref<Image>();
}
- return VisualServer::get_singleton()->texture_2d_get(texture);
+ return RenderingServer::get_singleton()->texture_2d_get(texture);
}
//////////////////////////////////////
@@ -1607,13 +1607,13 @@ void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) {
base = p_texture;
if (base.is_valid()) {
if (proxy_ph.is_valid()) {
- VS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
+ RS::get_singleton()->free(proxy_ph);
proxy_ph = RID();
} else if (proxy.is_valid()) {
- VS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
+ RS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
} else {
- proxy = VS::get_singleton()->texture_proxy_create(base->get_rid());
+ proxy = RS::get_singleton()->texture_proxy_create(base->get_rid());
}
}
}
@@ -1638,8 +1638,8 @@ int ProxyTexture::get_height() const {
RID ProxyTexture::get_rid() const {
if (proxy.is_null()) {
- proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
- proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
+ proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
+ proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
}
return proxy;
}
@@ -1653,16 +1653,16 @@ bool ProxyTexture::has_alpha() const {
ProxyTexture::ProxyTexture() {
- //proxy = VS::get_singleton()->texture_create();
+ //proxy = RS::get_singleton()->texture_create();
}
ProxyTexture::~ProxyTexture() {
if (proxy_ph.is_valid()) {
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->free(proxy_ph);
}
if (proxy.is_valid()) {
- VS::get_singleton()->free(proxy);
+ RS::get_singleton()->free(proxy);
}
}
//////////////////////////////////////////////
@@ -1708,7 +1708,7 @@ void AnimatedTexture::_update_proxy() {
}
if (frames[current_frame].texture.is_valid()) {
- VisualServer::get_singleton()->texture_proxy_update(proxy, frames[current_frame].texture->get_rid());
+ RenderingServer::get_singleton()->texture_proxy_update(proxy, frames[current_frame].texture->get_rid());
}
}
@@ -1854,28 +1854,28 @@ void AnimatedTexture::_bind_methods() {
}
AnimatedTexture::AnimatedTexture() {
- //proxy = VS::get_singleton()->texture_create();
- proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
- proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
+ //proxy = RS::get_singleton()->texture_create();
+ proxy_ph = RS::get_singleton()->texture_2d_placeholder_create();
+ proxy = RS::get_singleton()->texture_proxy_create(proxy_ph);
- VisualServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
+ RenderingServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
time = 0;
frame_count = 1;
fps = 4;
prev_ticks = 0;
current_frame = 0;
- VisualServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy));
+ RenderingServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy));
#ifndef NO_THREADS
rw_lock = RWLock::create();
#else
- rw_lock = NULL;
+ rw_lock = nullptr;
#endif
}
AnimatedTexture::~AnimatedTexture() {
- VS::get_singleton()->free(proxy);
- VS::get_singleton()->free(proxy_ph);
+ RS::get_singleton()->free(proxy);
+ RS::get_singleton()->free(proxy_ph);
if (rw_lock) {
memdelete(rw_lock);
}
@@ -1899,7 +1899,7 @@ uint32_t TextureLayered::get_layers() const {
}
Error TextureLayered::_create_from_images(const Array &p_images) {
- Vector<Ref<Image> > images;
+ Vector<Ref<Image>> images;
for (int i = 0; i < p_images.size(); i++) {
Ref<Image> img = p_images[i];
ERR_FAIL_COND_V(img.is_null(), ERR_INVALID_PARAMETER);
@@ -1917,14 +1917,14 @@ Array TextureLayered::_get_images() const {
return images;
}
-Error TextureLayered::create_from_images(Vector<Ref<Image> > p_images) {
+Error TextureLayered::create_from_images(Vector<Ref<Image>> p_images) {
int new_layers = p_images.size();
ERR_FAIL_COND_V(new_layers == 0, ERR_INVALID_PARAMETER);
- if (layered_type == VS::TEXTURE_LAYERED_CUBEMAP) {
+ if (layered_type == RS::TEXTURE_LAYERED_CUBEMAP) {
ERR_FAIL_COND_V_MSG(new_layers != 6, ERR_INVALID_PARAMETER,
"Cubemaps require exactly 6 layers");
- } else if (layered_type == VS::TEXTURE_LAYERED_CUBEMAP_ARRAY) {
+ } else if (layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY) {
ERR_FAIL_COND_V_MSG((new_layers % 6) != 0, ERR_INVALID_PARAMETER,
"Cubemap array layers must be a multiple of 6");
}
@@ -1946,11 +1946,11 @@ Error TextureLayered::create_from_images(Vector<Ref<Image> > p_images) {
}
if (texture.is_valid()) {
- RID new_texture = VS::get_singleton()->texture_2d_layered_create(p_images, layered_type);
+ RID new_texture = RS::get_singleton()->texture_2d_layered_create(p_images, layered_type);
ERR_FAIL_COND_V(!new_texture.is_valid(), ERR_CANT_CREATE);
- VS::get_singleton()->texture_replace(texture, new_texture);
+ RS::get_singleton()->texture_replace(texture, new_texture);
} else {
- texture = VS::get_singleton()->texture_2d_layered_create(p_images, layered_type);
+ texture = RS::get_singleton()->texture_2d_layered_create(p_images, layered_type);
ERR_FAIL_COND_V(!texture.is_valid(), ERR_CANT_CREATE);
}
@@ -1969,24 +1969,24 @@ void TextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) {
ERR_FAIL_COND(p_image->get_width() != width || p_image->get_height() != height);
ERR_FAIL_INDEX(p_layer, layers);
ERR_FAIL_COND(p_image->has_mipmaps() != mipmaps);
- VS::get_singleton()->texture_2d_update(texture, p_image, p_layer);
+ RS::get_singleton()->texture_2d_update(texture, p_image, p_layer);
}
Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
ERR_FAIL_INDEX_V(p_layer, layers, Ref<Image>());
- return VS::get_singleton()->texture_2d_layer_get(texture, p_layer);
+ return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);
}
RID TextureLayered::get_rid() const {
if (texture.is_null()) {
- texture = VS::get_singleton()->texture_2d_layered_placeholder_create();
+ texture = RS::get_singleton()->texture_2d_layered_placeholder_create();
}
return texture;
}
void TextureLayered::set_path(const String &p_path, bool p_take_over) {
if (texture.is_valid()) {
- VS::get_singleton()->texture_set_path(texture, p_path);
+ RS::get_singleton()->texture_set_path(texture, p_path);
}
Resource::set_path(p_path, p_take_over);
@@ -2009,7 +2009,7 @@ void TextureLayered::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images");
}
-TextureLayered::TextureLayered(VisualServer::TextureLayeredType p_layered_type) {
+TextureLayered::TextureLayered(RenderingServer::TextureLayeredType p_layered_type) {
layered_type = p_layered_type;
format = Image::FORMAT_MAX;
@@ -2020,7 +2020,7 @@ TextureLayered::TextureLayered(VisualServer::TextureLayeredType p_layered_type)
TextureLayered::~TextureLayered() {
if (texture.is_valid()) {
- VS::get_singleton()->free(texture);
+ RS::get_singleton()->free(texture);
}
}
@@ -2077,7 +2077,7 @@ RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String
Image::Format format = Image::Format(f->get_32());
uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
- Vector<Ref<Image> > images;
+ Vector<Ref<Image>> images;
for (int layer = 0; layer < td; layer++) {
Ref<Image> image;
@@ -2087,7 +2087,7 @@ RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String
//look for a PNG file inside
int mipmaps = f->get_32();
- Vector<Ref<Image> > mipmap_images;
+ Vector<Ref<Image>> mipmap_images;
for (int i = 0; i < mipmaps; i++) {
uint32_t size = f->get_32();
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 237c02a8cd..18f70baa07 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -41,7 +41,7 @@
#include "scene/resources/curve.h"
#include "scene/resources/gradient.h"
#include "servers/camera_server.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
class Texture : public Resource {
GDCLASS(Texture, Resource);
@@ -68,9 +68,9 @@ public:
virtual bool has_alpha() const = 0;
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, 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>(); }
@@ -118,9 +118,9 @@ public:
virtual RID get_rid() const;
bool has_alpha() 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const;
bool is_pixel_opaque(int p_x, int p_y) const;
@@ -171,7 +171,7 @@ private:
virtual void reload_from_file();
static void _requested_3d(void *p_ud);
- static void _requested_roughness(void *p_ud, const String &p_normal_path, VS::TextureDetectRoughnessChannel p_roughness_channel);
+ static void _requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
static void _requested_normal(void *p_ud);
protected:
@@ -182,7 +182,7 @@ public:
static Ref<Image> load_image_from_file(FileAccess *p_file, int p_size_limit);
typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture> &);
- typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<StreamTexture> &, const String &p_normal_path, VS::TextureDetectRoughnessChannel p_roughness_channel);
+ typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<StreamTexture> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel);
static TextureFormatRequestCallback request_3d_callback;
static TextureFormatRoughnessRequestCallback request_roughness_callback;
@@ -198,9 +198,9 @@ public:
virtual void set_path(const String &p_path, bool p_take_over);
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const;
virtual bool has_alpha() const;
bool is_pixel_opaque(int p_x, int p_y) const;
@@ -213,7 +213,7 @@ public:
class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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;
@@ -251,9 +251,9 @@ public:
void set_filter_clip(const bool p_enable);
bool has_filter_clip() const;
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, 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;
bool is_pixel_opaque(int p_x, int p_y) const;
@@ -291,9 +291,9 @@ public:
void set_base_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_base_texture() const;
- virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, 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;
bool is_pixel_opaque(int p_x, int p_y) const;
@@ -339,9 +339,9 @@ public:
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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
- 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), VS::CanvasItemTextureFilter p_texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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 Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) const;
+ 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, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), RS::CanvasItemTextureFilter p_texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, bool p_clip_uv = true) const;
bool is_pixel_opaque(int p_x, int p_y) const;
@@ -352,7 +352,7 @@ class TextureLayered : public Texture {
GDCLASS(TextureLayered, Texture);
- VS::TextureLayeredType layered_type;
+ RS::TextureLayeredType layered_type;
mutable RID texture;
Image::Format format;
@@ -376,14 +376,14 @@ public:
uint32_t get_layers() const;
bool has_mipmaps() const;
- Error create_from_images(Vector<Ref<Image> > p_images);
+ Error create_from_images(Vector<Ref<Image>> p_images);
void update_layer(const Ref<Image> &p_image, int p_layer);
Ref<Image> get_layer_data(int p_layer) const;
virtual RID get_rid() const;
virtual void set_path(const String &p_path, bool p_take_over = false);
- TextureLayered(VS::TextureLayeredType p_layered_type);
+ TextureLayered(RS::TextureLayeredType p_layered_type);
~TextureLayered();
};
@@ -392,7 +392,7 @@ class Texture2DArray : public TextureLayered {
GDCLASS(Texture2DArray, TextureLayered)
public:
Texture2DArray() :
- TextureLayered(VS::TEXTURE_LAYERED_2D_ARRAY) {}
+ TextureLayered(RS::TEXTURE_LAYERED_2D_ARRAY) {}
};
class Cubemap : public TextureLayered {
@@ -401,7 +401,7 @@ class Cubemap : public TextureLayered {
public:
Cubemap() :
- TextureLayered(VS::TEXTURE_LAYERED_CUBEMAP) {}
+ TextureLayered(RS::TEXTURE_LAYERED_CUBEMAP) {}
};
class CubemapArray : public TextureLayered {
@@ -410,7 +410,7 @@ class CubemapArray : public TextureLayered {
public:
CubemapArray() :
- TextureLayered(VS::TEXTURE_LAYERED_CUBEMAP_ARRAY) {}
+ TextureLayered(RS::TEXTURE_LAYERED_CUBEMAP_ARRAY) {}
};
class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader {
@@ -421,7 +421,7 @@ public:
COMPRESSION_UNCOMPRESSED
};
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, bool p_use_sub_threads = false, float *r_progress = 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);
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/theme.cpp b/scene/resources/theme.cpp
index d67f5f9ff2..98ebf048dc 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -230,11 +230,11 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> list;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = icon_map.next(key))) {
- const StringName *key2 = NULL;
+ const StringName *key2 = nullptr;
while ((key2 = icon_map[*key].next(key2))) {
@@ -242,11 +242,11 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
- key = NULL;
+ key = nullptr;
while ((key = style_map.next(key))) {
- const StringName *key2 = NULL;
+ const StringName *key2 = nullptr;
while ((key2 = style_map[*key].next(key2))) {
@@ -254,11 +254,11 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
- key = NULL;
+ key = nullptr;
while ((key = font_map.next(key))) {
- const StringName *key2 = NULL;
+ const StringName *key2 = nullptr;
while ((key2 = font_map[*key].next(key2))) {
@@ -266,11 +266,11 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
- key = NULL;
+ key = nullptr;
while ((key = color_map.next(key))) {
- const StringName *key2 = NULL;
+ const StringName *key2 = nullptr;
while ((key2 = color_map[*key].next(key2))) {
@@ -278,11 +278,11 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
- key = NULL;
+ key = nullptr;
while ((key = constant_map.next(key))) {
- const StringName *key2 = NULL;
+ const StringName *key2 = nullptr;
while ((key2 = constant_map[*key].next(key2))) {
@@ -417,7 +417,7 @@ void Theme::get_icon_list(StringName p_type, List<StringName> *p_list) const {
if (!icon_map.has(p_type))
return;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = icon_map[p_type].next(key))) {
@@ -440,7 +440,7 @@ Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_type
if (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid()) {
return shader_map[p_type][p_name];
} else {
- return NULL;
+ return nullptr;
}
}
@@ -464,7 +464,7 @@ void Theme::get_shader_list(const StringName &p_type, List<StringName> *p_list)
if (!shader_map.has(p_type))
return;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = shader_map[p_type].next(key))) {
@@ -530,7 +530,7 @@ void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const
if (!style_map.has(p_type))
return;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = style_map[p_type].next(key))) {
@@ -541,7 +541,7 @@ void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const
void Theme::get_stylebox_types(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = style_map.next(key))) {
p_list->push_back(*key);
}
@@ -604,7 +604,7 @@ void Theme::get_font_list(StringName p_type, List<StringName> *p_list) const {
if (!font_map.has(p_type))
return;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = font_map[p_type].next(key))) {
@@ -654,7 +654,7 @@ void Theme::get_color_list(StringName p_type, List<StringName> *p_list) const {
if (!color_map.has(p_type))
return;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = color_map[p_type].next(key))) {
@@ -704,7 +704,7 @@ void Theme::get_constant_list(StringName p_type, List<StringName> *p_list) const
if (!constant_map.has(p_type))
return;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = constant_map[p_type].next(key))) {
@@ -716,9 +716,9 @@ void Theme::clear() {
//these need disconnecting
{
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = icon_map.next(K))) {
- const StringName *L = NULL;
+ const StringName *L = nullptr;
while ((L = icon_map[*K].next(L))) {
Ref<Texture2D> icon = icon_map[*K][*L];
if (icon.is_valid()) {
@@ -729,9 +729,9 @@ void Theme::clear() {
}
{
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = style_map.next(K))) {
- const StringName *L = NULL;
+ const StringName *L = nullptr;
while ((L = style_map[*K].next(L))) {
Ref<StyleBox> style = style_map[*K][*L];
if (style.is_valid()) {
@@ -742,9 +742,9 @@ void Theme::clear() {
}
{
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = font_map.next(K))) {
- const StringName *L = NULL;
+ const StringName *L = nullptr;
while ((L = font_map[*K].next(L))) {
Ref<Font> font = font_map[*K][*L];
if (font.is_valid()) {
@@ -781,9 +781,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
//these need reconnecting, so add normally
{
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = p_other->icon_map.next(K))) {
- const StringName *L = NULL;
+ const StringName *L = nullptr;
while ((L = p_other->icon_map[*K].next(L))) {
set_icon(*L, *K, p_other->icon_map[*K][*L]);
}
@@ -791,9 +791,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
}
{
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = p_other->style_map.next(K))) {
- const StringName *L = NULL;
+ const StringName *L = nullptr;
while ((L = p_other->style_map[*K].next(L))) {
set_stylebox(*L, *K, p_other->style_map[*K][*L]);
}
@@ -801,9 +801,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
}
{
- const StringName *K = NULL;
+ const StringName *K = nullptr;
while ((K = p_other->font_map.next(K))) {
- const StringName *L = NULL;
+ const StringName *L = nullptr;
while ((L = p_other->font_map[*K].next(L))) {
set_font(*L, *K, p_other->font_map[*K][*L]);
}
@@ -825,35 +825,35 @@ void Theme::get_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
Set<StringName> types;
- const StringName *key = NULL;
+ const StringName *key = nullptr;
while ((key = icon_map.next(key))) {
types.insert(*key);
}
- key = NULL;
+ key = nullptr;
while ((key = style_map.next(key))) {
types.insert(*key);
}
- key = NULL;
+ key = nullptr;
while ((key = font_map.next(key))) {
types.insert(*key);
}
- key = NULL;
+ key = nullptr;
while ((key = color_map.next(key))) {
types.insert(*key);
}
- key = NULL;
+ key = nullptr;
while ((key = constant_map.next(key))) {
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 3d01f71ea0..d6d724e3f7 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -45,12 +45,12 @@ class Theme : public Resource {
void _emit_theme_changed();
- HashMap<StringName, HashMap<StringName, Ref<Texture2D> > > icon_map;
- HashMap<StringName, HashMap<StringName, Ref<StyleBox> > > style_map;
- HashMap<StringName, HashMap<StringName, Ref<Font> > > font_map;
- HashMap<StringName, HashMap<StringName, Ref<Shader> > > shader_map;
- HashMap<StringName, HashMap<StringName, Color> > color_map;
- HashMap<StringName, HashMap<StringName, int> > constant_map;
+ HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
+ HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map;
+ HashMap<StringName, HashMap<StringName, Ref<Font>>> font_map;
+ HashMap<StringName, HashMap<StringName, Ref<Shader>>> shader_map;
+ HashMap<StringName, HashMap<StringName, Color>> color_map;
+ HashMap<StringName, HashMap<StringName, int>> constant_map;
Vector<String> _get_icon_list(const String &p_type) const;
Vector<String> _get_stylebox_list(const String &p_type) const;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index f42b56bc83..6f8a53be1a 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -252,14 +252,14 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = p;
} else if (what == "occluder_map") {
Array p;
- for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = tile_map[id].autotile_data.occluder_map.front(); E; E = E->next()) {
+ for (Map<Vector2, Ref<OccluderPolygon2D>>::Element *E = tile_map[id].autotile_data.occluder_map.front(); E; E = E->next()) {
p.push_back(E->key());
p.push_back(E->value());
}
r_ret = p;
} else if (what == "navpoly_map") {
Array p;
- for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = tile_map[id].autotile_data.navpoly_map.front(); E; E = E->next()) {
+ for (Map<Vector2, Ref<NavigationPolygon>>::Element *E = tile_map[id].autotile_data.navpoly_map.front(); E; E = E->next()) {
p.push_back(E->key());
p.push_back(E->value());
}
@@ -362,7 +362,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, pre + "shape_one_way", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::FLOAT, pre + "shape_one_way_margin", PROPERTY_HINT_RANGE, "0,128,0.01", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "shapes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::INT, pre + "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1", PROPERTY_USAGE_NOEDITOR));
}
}
@@ -620,7 +620,7 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask,
ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
//First try to forward selection to script
if (p_tilemap_node->get_class_name() == "TileMap") {
- if (get_script_instance() != NULL) {
+ if (get_script_instance() != nullptr) {
if (get_script_instance()->has_method("_forward_subtile_selection")) {
Variant ret = get_script_instance()->call("_forward_subtile_selection", p_id, p_bitmask, p_tilemap_node, p_tile_location);
if (ret.get_type() == Variant::VECTOR2) {
@@ -681,7 +681,7 @@ Vector2 TileSet::atlastile_get_subtile_by_priority(int p_id, const Node *p_tilem
ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
//First try to forward selection to script
- if (get_script_instance() != NULL) {
+ if (get_script_instance() != nullptr) {
if (get_script_instance()->has_method("_forward_atlas_subtile_selection")) {
Variant ret = get_script_instance()->call("_forward_atlas_subtile_selection", p_id, p_tilemap_node, p_tile_location);
if (ret.get_type() == Variant::VECTOR2) {
@@ -903,9 +903,9 @@ Ref<NavigationPolygon> TileSet::tile_get_navigation_polygon(int p_id) const {
return tile_map[p_id].navigation_polygon;
}
-const Map<Vector2, Ref<OccluderPolygon2D> > &TileSet::autotile_get_light_oclusion_map(int p_id) const {
+const Map<Vector2, Ref<OccluderPolygon2D>> &TileSet::autotile_get_light_oclusion_map(int p_id) const {
- static Map<Vector2, Ref<OccluderPolygon2D> > dummy;
+ static Map<Vector2, Ref<OccluderPolygon2D>> dummy;
ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
return tile_map[p_id].autotile_data.occluder_map;
}
@@ -932,9 +932,9 @@ Ref<NavigationPolygon> TileSet::autotile_get_navigation_polygon(int p_id, const
}
}
-const Map<Vector2, Ref<NavigationPolygon> > &TileSet::autotile_get_navigation_map(int p_id) const {
+const Map<Vector2, Ref<NavigationPolygon>> &TileSet::autotile_get_navigation_map(int p_id) const {
- static Map<Vector2, Ref<NavigationPolygon> > dummy;
+ static Map<Vector2, Ref<NavigationPolygon>> dummy;
ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
return tile_map[p_id].autotile_data.navpoly_map;
}
@@ -1077,7 +1077,7 @@ void TileSet::_decompose_convex_shape(Ref<Shape2D> p_shape) {
Ref<ConvexPolygonShape2D> convex = p_shape;
if (!convex.is_valid())
return;
- Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(convex->get_points());
+ Vector<Vector<Vector2>> decomp = Geometry::decompose_polygon_in_convex(convex->get_points());
if (decomp.size() > 1) {
Array sub_shapes;
for (int i = 0; i < decomp.size(); i++) {
@@ -1108,7 +1108,7 @@ bool TileSet::is_tile_bound(int p_drawn_id, int p_neighbor_id) {
if (p_drawn_id == p_neighbor_id) {
return true;
- } else if (get_script_instance() != NULL) {
+ } else if (get_script_instance() != nullptr) {
if (get_script_instance()->has_method("_is_tile_bound")) {
Variant ret = get_script_instance()->call("_is_tile_bound", p_drawn_id, p_neighbor_id);
if (ret.get_type() == Variant::BOOL) {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 8b540982a4..05b43dfb89 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -34,7 +34,7 @@
#include "core/array.h"
#include "core/resource.h"
#include "scene/2d/light_occluder_2d.h"
-#include "scene/2d/navigation_polygon.h"
+#include "scene/2d/navigation_region_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/shape_2d.h"
#include "scene/resources/texture.h"
@@ -97,8 +97,8 @@ public:
int spacing;
Vector2 icon_coord;
Map<Vector2, uint32_t> flags;
- Map<Vector2, Ref<OccluderPolygon2D> > occluder_map;
- Map<Vector2, Ref<NavigationPolygon> > navpoly_map;
+ Map<Vector2, Ref<OccluderPolygon2D>> occluder_map;
+ Map<Vector2, Ref<NavigationPolygon>> navpoly_map;
Map<Vector2, int> priority_map;
Map<Vector2, int> z_index_map;
@@ -194,8 +194,8 @@ public:
void autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag);
uint32_t autotile_get_bitmask(int p_id, Vector2 p_coord);
const Map<Vector2, uint32_t> &autotile_get_bitmask_map(int p_id);
- Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2());
- Vector2 atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2());
+ Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = nullptr, const Vector2 &p_tile_location = Vector2());
+ Vector2 atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node = nullptr, const Vector2 &p_tile_location = Vector2());
void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape);
Ref<Shape2D> tile_get_shape(int p_id, int p_shape_id) const;
@@ -233,7 +233,7 @@ public:
void autotile_set_light_occluder(int p_id, const Ref<OccluderPolygon2D> &p_light_occluder, const Vector2 &p_coord);
Ref<OccluderPolygon2D> autotile_get_light_occluder(int p_id, const Vector2 &p_coord) const;
- const Map<Vector2, Ref<OccluderPolygon2D> > &autotile_get_light_oclusion_map(int p_id) const;
+ const Map<Vector2, Ref<OccluderPolygon2D>> &autotile_get_light_oclusion_map(int p_id) const;
void tile_set_navigation_polygon_offset(int p_id, const Vector2 &p_offset);
Vector2 tile_get_navigation_polygon_offset(int p_id) const;
@@ -243,7 +243,7 @@ public:
void autotile_set_navigation_polygon(int p_id, const Ref<NavigationPolygon> &p_navigation_polygon, const Vector2 &p_coord);
Ref<NavigationPolygon> autotile_get_navigation_polygon(int p_id, const Vector2 &p_coord) const;
- const Map<Vector2, Ref<NavigationPolygon> > &autotile_get_navigation_map(int p_id) const;
+ const Map<Vector2, Ref<NavigationPolygon>> &autotile_get_navigation_map(int p_id) const;
void tile_set_z_index(int p_id, int p_z_index);
int tile_get_z_index(int p_id) const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 407325c199..310a7ef4e4 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -31,7 +31,7 @@
#include "visual_shader.h"
#include "core/vmap.h"
-#include "servers/visual/shader_types.h"
+#include "servers/rendering/shader_types.h"
#include "visual_shader_nodes.h"
bool VisualShaderNode::is_simple_decl() const {
@@ -881,7 +881,7 @@ VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = {
{ Shader::MODE_SPATIAL, "diffuse" },
{ Shader::MODE_SPATIAL, "specular" },
{ Shader::MODE_CANVAS_ITEM, "blend" },
- { Shader::MODE_CANVAS_ITEM, NULL }
+ { Shader::MODE_CANVAS_ITEM, nullptr }
};
static const char *type_string[VisualShader::TYPE_MAX] = {
@@ -1034,14 +1034,14 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
- p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Spatial,CanvasItem,Particles"));
+ p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky"));
//render modes
Map<String, String> blend_mode_enums;
Set<String> toggles;
- for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) {
- String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i];
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
+ String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
int idx = 0;
bool in_enum = false;
while (render_mode_enums[idx].string) {
@@ -1085,12 +1085,12 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- if (Object::cast_to<VisualShaderNodeGroupBase>(E->get().node.ptr()) != NULL) {
+ if (Object::cast_to<VisualShaderNodeGroupBase>(E->get().node.ptr()) != nullptr) {
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/input_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
- if (Object::cast_to<VisualShaderNodeExpression>(E->get().node.ptr()) != NULL) {
+ if (Object::cast_to<VisualShaderNodeExpression>(E->get().node.ptr()) != nullptr) {
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
}
@@ -1299,8 +1299,8 @@ void VisualShader::_update_shader() const {
StringBuilder code;
Vector<VisualShader::DefaultTextureParam> default_tex_params;
Set<StringName> classes;
- List<int> insertion_pos;
- static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles" };
+ Map<int, int> insertion_pos;
+ static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles", "sky" };
global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
@@ -1317,8 +1317,8 @@ void VisualShader::_update_shader() const {
int which = modes[render_mode_enums[idx].string];
int count = 0;
- for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) {
- String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i];
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
+ String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
if (mode.begins_with(render_mode_enums[idx].string)) {
if (count == which) {
if (render_mode != String()) {
@@ -1336,9 +1336,9 @@ void VisualShader::_update_shader() const {
}
//fill render mode flags
- for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) {
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
- String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i];
+ String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
if (flags.has(mode)) {
if (render_mode != String()) {
render_mode += ", ";
@@ -1357,6 +1357,11 @@ void VisualShader::_update_shader() const {
String global_expressions;
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
+
+ if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) {
+ continue;
+ }
+
for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr());
if (global_expression.is_valid()) {
@@ -1373,6 +1378,10 @@ void VisualShader::_update_shader() const {
for (int i = 0; i < TYPE_MAX; i++) {
+ if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) {
+ continue;
+ }
+
//make it faster to go around through shader
VMap<ConnectionKey, const List<Connection>::Element *> input_connections;
VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
@@ -1396,7 +1405,7 @@ void VisualShader::_update_shader() const {
Set<int> processed;
Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
ERR_FAIL_COND(err != OK);
- insertion_pos.push_back(code.get_string_length());
+ insertion_pos.insert(i, code.get_string_length());
code += "}\n";
}
@@ -1408,6 +1417,9 @@ void VisualShader::_update_shader() const {
final_code += global_expressions;
String tcode = code;
for (int i = 0; i < TYPE_MAX; i++) {
+ if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) {
+ continue;
+ }
tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]);
}
final_code += tcode;
@@ -1466,7 +1478,7 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node);
ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
- ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
+ ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::can_connect_nodes);
ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes);
ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes);
@@ -1643,7 +1655,39 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
- { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL },
+
+ // 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" },
+
+ { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
@@ -1692,7 +1736,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "vec3(0.0, 0.0, 1.0)" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
- { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL },
+ { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
int VisualShaderNodeInput::get_input_port_count() const {
@@ -1986,7 +2030,11 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
- { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL },
+ // 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" },
+
+ { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
int VisualShaderNodeOutput::get_input_port_count() const {
@@ -2116,6 +2164,17 @@ void VisualShaderNodeUniform::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name"), "set_uniform_name", "get_uniform_name");
}
+String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+
+ List<String> keyword_list;
+ ShaderLanguage::get_keyword_list(&keyword_list);
+ if (keyword_list.find(uniform_name)) {
+ return TTR("Uniform name cannot be equal to a shader keyword. Choose another name.");
+ }
+
+ return String();
+}
+
VisualShaderNodeUniform::VisualShaderNodeUniform() {
}
@@ -2517,7 +2576,7 @@ void VisualShaderNodeGroupBase::set_control(Control *p_control, int p_index) {
}
Control *VisualShaderNodeGroupBase::get_control(int p_index) {
- ERR_FAIL_COND_V(!controls.has(p_index), NULL);
+ ERR_FAIL_COND_V(!controls.has(p_index), nullptr);
return controls[p_index];
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 450dcfa081..ecf3f93fbb 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -379,6 +379,8 @@ public:
void set_uniform_name(const String &p_name);
String get_uniform_name() const;
+ virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const;
+
VisualShaderNodeUniform();
};
diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp
deleted file mode 100644
index a7e519479f..0000000000
--- a/scene/resources/world.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*************************************************************************/
-/* world.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "world.h"
-
-#include "core/math/camera_matrix.h"
-#include "core/math/octree.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/visibility_notifier.h"
-#include "scene/scene_string_names.h"
-
-struct SpatialIndexer {
-
- Octree<VisibilityNotifier> octree;
-
- struct NotifierData {
-
- AABB aabb;
- OctreeElementID id;
- };
-
- Map<VisibilityNotifier *, NotifierData> notifiers;
- struct CameraData {
-
- Map<VisibilityNotifier *, uint64_t> notifiers;
- };
-
- Map<Camera *, CameraData> cameras;
-
- enum {
- VISIBILITY_CULL_MAX = 32768
- };
-
- Vector<VisibilityNotifier *> cull;
-
- bool changed;
- uint64_t pass;
- uint64_t last_frame;
-
- void _notifier_add(VisibilityNotifier *p_notifier, const AABB &p_rect) {
-
- ERR_FAIL_COND(notifiers.has(p_notifier));
- notifiers[p_notifier].aabb = p_rect;
- notifiers[p_notifier].id = octree.create(p_notifier, p_rect);
- changed = true;
- }
-
- void _notifier_update(VisibilityNotifier *p_notifier, const AABB &p_rect) {
-
- Map<VisibilityNotifier *, NotifierData>::Element *E = notifiers.find(p_notifier);
- ERR_FAIL_COND(!E);
- if (E->get().aabb == p_rect)
- return;
-
- E->get().aabb = p_rect;
- octree.move(E->get().id, E->get().aabb);
- changed = true;
- }
-
- void _notifier_remove(VisibilityNotifier *p_notifier) {
-
- Map<VisibilityNotifier *, NotifierData>::Element *E = notifiers.find(p_notifier);
- ERR_FAIL_COND(!E);
-
- octree.erase(E->get().id);
- notifiers.erase(p_notifier);
-
- List<Camera *> removed;
- for (Map<Camera *, CameraData>::Element *F = cameras.front(); F; F = F->next()) {
-
- Map<VisibilityNotifier *, uint64_t>::Element *G = F->get().notifiers.find(p_notifier);
-
- if (G) {
- F->get().notifiers.erase(G);
- removed.push_back(F->key());
- }
- }
-
- while (!removed.empty()) {
-
- p_notifier->_exit_camera(removed.front()->get());
- removed.pop_front();
- }
-
- changed = true;
- }
-
- void _add_camera(Camera *p_camera) {
-
- ERR_FAIL_COND(cameras.has(p_camera));
- CameraData vd;
- cameras[p_camera] = vd;
- changed = true;
- }
-
- void _update_camera(Camera *p_camera) {
-
- Map<Camera *, CameraData>::Element *E = cameras.find(p_camera);
- ERR_FAIL_COND(!E);
- changed = true;
- }
-
- void _remove_camera(Camera *p_camera) {
- ERR_FAIL_COND(!cameras.has(p_camera));
- List<VisibilityNotifier *> removed;
- for (Map<VisibilityNotifier *, uint64_t>::Element *E = cameras[p_camera].notifiers.front(); E; E = E->next()) {
-
- removed.push_back(E->key());
- }
-
- while (!removed.empty()) {
- removed.front()->get()->_exit_camera(p_camera);
- removed.pop_front();
- }
-
- cameras.erase(p_camera);
- }
-
- void _update(uint64_t p_frame) {
-
- if (p_frame == last_frame)
- return;
- last_frame = p_frame;
-
- if (!changed)
- return;
-
- for (Map<Camera *, CameraData>::Element *E = cameras.front(); E; E = E->next()) {
-
- pass++;
-
- Camera *c = E->key();
-
- Vector<Plane> planes = c->get_frustum();
-
- int culled = octree.cull_convex(planes, cull.ptrw(), cull.size());
-
- VisibilityNotifier **ptr = cull.ptrw();
-
- List<VisibilityNotifier *> added;
- List<VisibilityNotifier *> removed;
-
- for (int i = 0; i < culled; i++) {
-
- //notifiers in frustum
-
- Map<VisibilityNotifier *, uint64_t>::Element *H = E->get().notifiers.find(ptr[i]);
- if (!H) {
-
- E->get().notifiers.insert(ptr[i], pass);
- added.push_back(ptr[i]);
- } else {
- H->get() = pass;
- }
- }
-
- for (Map<VisibilityNotifier *, uint64_t>::Element *F = E->get().notifiers.front(); F; F = F->next()) {
-
- if (F->get() != pass)
- removed.push_back(F->key());
- }
-
- while (!added.empty()) {
- added.front()->get()->_enter_camera(E->key());
- added.pop_front();
- }
-
- while (!removed.empty()) {
- E->get().notifiers.erase(removed.front()->get());
- removed.front()->get()->_exit_camera(E->key());
- removed.pop_front();
- }
- }
- changed = false;
- }
-
- SpatialIndexer() {
-
- pass = 0;
- last_frame = 0;
- changed = false;
- cull.resize(VISIBILITY_CULL_MAX);
- }
-};
-
-void World::_register_camera(Camera *p_camera) {
-
-#ifndef _3D_DISABLED
- indexer->_add_camera(p_camera);
-#endif
-}
-
-void World::_update_camera(Camera *p_camera) {
-
-#ifndef _3D_DISABLED
- indexer->_update_camera(p_camera);
-#endif
-}
-void World::_remove_camera(Camera *p_camera) {
-
-#ifndef _3D_DISABLED
- indexer->_remove_camera(p_camera);
-#endif
-}
-
-void World::_register_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect) {
-
-#ifndef _3D_DISABLED
- indexer->_notifier_add(p_notifier, p_rect);
-#endif
-}
-
-void World::_update_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect) {
-
-#ifndef _3D_DISABLED
- indexer->_notifier_update(p_notifier, p_rect);
-#endif
-}
-
-void World::_remove_notifier(VisibilityNotifier *p_notifier) {
-
-#ifndef _3D_DISABLED
- indexer->_notifier_remove(p_notifier);
-#endif
-}
-
-void World::_update(uint64_t p_frame) {
-
-#ifndef _3D_DISABLED
- indexer->_update(p_frame);
-#endif
-}
-
-RID World::get_space() const {
-
- return space;
-}
-
-RID World::get_scenario() const {
-
- return scenario;
-}
-
-void World::set_environment(const Ref<Environment> &p_environment) {
- if (environment == p_environment) {
- return;
- }
-
- environment = p_environment;
- if (environment.is_valid())
- VS::get_singleton()->scenario_set_environment(scenario, environment->get_rid());
- else
- VS::get_singleton()->scenario_set_environment(scenario, RID());
-
- emit_changed();
-}
-
-Ref<Environment> World::get_environment() const {
-
- return environment;
-}
-
-void World::set_fallback_environment(const Ref<Environment> &p_environment) {
- if (fallback_environment == p_environment) {
- return;
- }
-
- fallback_environment = p_environment;
- if (fallback_environment.is_valid())
- VS::get_singleton()->scenario_set_fallback_environment(scenario, p_environment->get_rid());
- else
- VS::get_singleton()->scenario_set_fallback_environment(scenario, RID());
-
- emit_changed();
-}
-
-Ref<Environment> World::get_fallback_environment() const {
-
- return fallback_environment;
-}
-
-void World::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) {
-
- camera_effects = p_camera_effects;
- if (camera_effects.is_valid())
- VS::get_singleton()->scenario_set_camera_effects(scenario, camera_effects->get_rid());
- else
- VS::get_singleton()->scenario_set_camera_effects(scenario, RID());
-}
-
-Ref<CameraEffects> World::get_camera_effects() const {
-
- return camera_effects;
-}
-
-PhysicsDirectSpaceState *World::get_direct_space_state() {
-
- return PhysicsServer::get_singleton()->space_get_direct_state(space);
-}
-
-void World::get_camera_list(List<Camera *> *r_cameras) {
-
- for (Map<Camera *, SpatialIndexer::CameraData>::Element *E = indexer->cameras.front(); E; E = E->next()) {
- r_cameras->push_back(E->key());
- }
-}
-
-void World::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_space"), &World::get_space);
- ClassDB::bind_method(D_METHOD("get_scenario"), &World::get_scenario);
- ClassDB::bind_method(D_METHOD("set_environment", "env"), &World::set_environment);
- ClassDB::bind_method(D_METHOD("get_environment"), &World::get_environment);
- ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World::set_fallback_environment);
- ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World::get_fallback_environment);
- ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &World::set_camera_effects);
- ClassDB::bind_method(D_METHOD("get_camera_effects"), &World::get_camera_effects);
- ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World::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, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState", 0), "", "get_direct_space_state");
-}
-
-World::World() {
-
- space = PhysicsServer::get_singleton()->space_create();
- scenario = VisualServer::get_singleton()->scenario_create();
-
- PhysicsServer::get_singleton()->space_set_active(space, true);
- PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
- PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
- PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
- ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
- PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::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"));
-
-#ifdef _3D_DISABLED
- indexer = NULL;
-#else
- indexer = memnew(SpatialIndexer);
-#endif
-}
-
-World::~World() {
-
- PhysicsServer::get_singleton()->free(space);
- VisualServer::get_singleton()->free(scenario);
-
-#ifndef _3D_DISABLED
- memdelete(indexer);
-#endif
-}
diff --git a/scene/resources/world.h b/scene/resources/world.h
deleted file mode 100644
index 6fd79abaaf..0000000000
--- a/scene/resources/world.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*************************************************************************/
-/* world.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 WORLD_H
-#define WORLD_H
-
-#include "core/resource.h"
-#include "scene/resources/environment.h"
-#include "servers/physics_server.h"
-#include "servers/visual_server.h"
-
-class Camera;
-class VisibilityNotifier;
-struct SpatialIndexer;
-
-class World : public Resource {
- GDCLASS(World, Resource);
- RES_BASE_EXTENSION("world");
-
-private:
- RID space;
- RID scenario;
- SpatialIndexer *indexer;
- Ref<Environment> environment;
- Ref<Environment> fallback_environment;
- Ref<CameraEffects> camera_effects;
-
-protected:
- static void _bind_methods();
-
- friend class Camera;
- friend class VisibilityNotifier;
-
- void _register_camera(Camera *p_camera);
- void _update_camera(Camera *p_camera);
- void _remove_camera(Camera *p_camera);
-
- void _register_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect);
- void _update_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect);
- void _remove_notifier(VisibilityNotifier *p_notifier);
- friend class Viewport;
- void _update(uint64_t p_frame);
-
-public:
- RID get_space() const;
- RID get_scenario() const;
-
- void set_environment(const Ref<Environment> &p_environment);
- Ref<Environment> get_environment() const;
-
- void set_fallback_environment(const Ref<Environment> &p_environment);
- Ref<Environment> get_fallback_environment() const;
-
- void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
- Ref<CameraEffects> get_camera_effects() const;
-
- void get_camera_list(List<Camera *> *r_cameras);
-
- PhysicsDirectSpaceState *get_direct_space_state();
-
- World();
- ~World();
-};
-
-#endif // WORLD_H
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 6bdc4cf6f0..742ef106d9 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -33,9 +33,9 @@
#include "core/project_settings.h"
#include "scene/2d/camera_2d.h"
#include "scene/2d/visibility_notifier_2d.h"
-#include "scene/main/viewport.h"
-#include "servers/physics_2d_server.h"
-#include "servers/visual_server.h"
+#include "scene/main/window.h"
+#include "servers/physics_server_2d.h"
+#include "servers/rendering_server.h"
struct SpatialIndexer2D {
@@ -376,33 +376,33 @@ void World2D::_bind_methods() {
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::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "Physics2DDirectSpaceState", 0), "", "get_direct_space_state");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", 0), "", "get_direct_space_state");
}
-Physics2DDirectSpaceState *World2D::get_direct_space_state() {
+PhysicsDirectSpaceState2D *World2D::get_direct_space_state() {
- return Physics2DServer::get_singleton()->space_get_direct_state(space);
+ return PhysicsServer2D::get_singleton()->space_get_direct_state(space);
}
World2D::World2D() {
- canvas = VisualServer::get_singleton()->canvas_create();
- space = Physics2DServer::get_singleton()->space_create();
+ 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
- Physics2DServer::get_singleton()->space_set_active(space, true);
- Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 98));
- Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1)));
- Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/2d/default_linear_damp", 0.1));
+ 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)));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/2d/default_linear_damp", 0.1));
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"));
- Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0));
+ 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"));
indexer = memnew(SpatialIndexer2D);
}
World2D::~World2D() {
- VisualServer::get_singleton()->free(canvas);
- Physics2DServer::get_singleton()->free(space);
+ RenderingServer::get_singleton()->free(canvas);
+ PhysicsServer2D::get_singleton()->free(space);
memdelete(indexer);
}
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index d837ef58c2..88b4c2594c 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -33,7 +33,7 @@
#include "core/project_settings.h"
#include "core/resource.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
class VisibilityNotifier2D;
class Viewport;
@@ -67,7 +67,7 @@ public:
RID get_canvas();
RID get_space();
- Physics2DDirectSpaceState *get_direct_space_state();
+ PhysicsDirectSpaceState2D *get_direct_space_state();
void get_viewport_list(List<Viewport *> *r_viewports);
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
new file mode 100644
index 0000000000..dee00dd82a
--- /dev/null
+++ b/scene/resources/world_3d.cpp
@@ -0,0 +1,382 @@
+/*************************************************************************/
+/* world_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "world_3d.h"
+
+#include "core/math/camera_matrix.h"
+#include "core/math/octree.h"
+#include "scene/3d/camera_3d.h"
+#include "scene/3d/visibility_notifier_3d.h"
+#include "scene/scene_string_names.h"
+
+struct SpatialIndexer {
+
+ Octree<VisibilityNotifier3D> octree;
+
+ struct NotifierData {
+
+ AABB aabb;
+ OctreeElementID id;
+ };
+
+ Map<VisibilityNotifier3D *, NotifierData> notifiers;
+ struct CameraData {
+
+ Map<VisibilityNotifier3D *, uint64_t> notifiers;
+ };
+
+ Map<Camera3D *, CameraData> cameras;
+
+ enum {
+ VISIBILITY_CULL_MAX = 32768
+ };
+
+ Vector<VisibilityNotifier3D *> cull;
+
+ bool changed;
+ uint64_t pass;
+ uint64_t last_frame;
+
+ void _notifier_add(VisibilityNotifier3D *p_notifier, const AABB &p_rect) {
+
+ ERR_FAIL_COND(notifiers.has(p_notifier));
+ notifiers[p_notifier].aabb = p_rect;
+ notifiers[p_notifier].id = octree.create(p_notifier, p_rect);
+ changed = true;
+ }
+
+ void _notifier_update(VisibilityNotifier3D *p_notifier, const AABB &p_rect) {
+
+ Map<VisibilityNotifier3D *, NotifierData>::Element *E = notifiers.find(p_notifier);
+ ERR_FAIL_COND(!E);
+ if (E->get().aabb == p_rect)
+ return;
+
+ E->get().aabb = p_rect;
+ octree.move(E->get().id, E->get().aabb);
+ changed = true;
+ }
+
+ void _notifier_remove(VisibilityNotifier3D *p_notifier) {
+
+ Map<VisibilityNotifier3D *, NotifierData>::Element *E = notifiers.find(p_notifier);
+ ERR_FAIL_COND(!E);
+
+ octree.erase(E->get().id);
+ notifiers.erase(p_notifier);
+
+ List<Camera3D *> removed;
+ for (Map<Camera3D *, CameraData>::Element *F = cameras.front(); F; F = F->next()) {
+
+ Map<VisibilityNotifier3D *, uint64_t>::Element *G = F->get().notifiers.find(p_notifier);
+
+ if (G) {
+ F->get().notifiers.erase(G);
+ removed.push_back(F->key());
+ }
+ }
+
+ while (!removed.empty()) {
+
+ p_notifier->_exit_camera(removed.front()->get());
+ removed.pop_front();
+ }
+
+ changed = true;
+ }
+
+ void _add_camera(Camera3D *p_camera) {
+
+ ERR_FAIL_COND(cameras.has(p_camera));
+ CameraData vd;
+ cameras[p_camera] = vd;
+ changed = true;
+ }
+
+ void _update_camera(Camera3D *p_camera) {
+
+ Map<Camera3D *, CameraData>::Element *E = cameras.find(p_camera);
+ ERR_FAIL_COND(!E);
+ changed = true;
+ }
+
+ void _remove_camera(Camera3D *p_camera) {
+ ERR_FAIL_COND(!cameras.has(p_camera));
+ List<VisibilityNotifier3D *> removed;
+ for (Map<VisibilityNotifier3D *, uint64_t>::Element *E = cameras[p_camera].notifiers.front(); E; E = E->next()) {
+
+ removed.push_back(E->key());
+ }
+
+ while (!removed.empty()) {
+ removed.front()->get()->_exit_camera(p_camera);
+ removed.pop_front();
+ }
+
+ cameras.erase(p_camera);
+ }
+
+ void _update(uint64_t p_frame) {
+
+ if (p_frame == last_frame)
+ return;
+ last_frame = p_frame;
+
+ if (!changed)
+ return;
+
+ for (Map<Camera3D *, CameraData>::Element *E = cameras.front(); E; E = E->next()) {
+
+ pass++;
+
+ Camera3D *c = E->key();
+
+ Vector<Plane> planes = c->get_frustum();
+
+ int culled = octree.cull_convex(planes, cull.ptrw(), cull.size());
+
+ VisibilityNotifier3D **ptr = cull.ptrw();
+
+ List<VisibilityNotifier3D *> added;
+ List<VisibilityNotifier3D *> removed;
+
+ for (int i = 0; i < culled; i++) {
+
+ //notifiers in frustum
+
+ Map<VisibilityNotifier3D *, uint64_t>::Element *H = E->get().notifiers.find(ptr[i]);
+ if (!H) {
+
+ E->get().notifiers.insert(ptr[i], pass);
+ added.push_back(ptr[i]);
+ } else {
+ H->get() = pass;
+ }
+ }
+
+ for (Map<VisibilityNotifier3D *, uint64_t>::Element *F = E->get().notifiers.front(); F; F = F->next()) {
+
+ if (F->get() != pass)
+ removed.push_back(F->key());
+ }
+
+ while (!added.empty()) {
+ added.front()->get()->_enter_camera(E->key());
+ added.pop_front();
+ }
+
+ while (!removed.empty()) {
+ E->get().notifiers.erase(removed.front()->get());
+ removed.front()->get()->_exit_camera(E->key());
+ removed.pop_front();
+ }
+ }
+ changed = false;
+ }
+
+ SpatialIndexer() {
+
+ pass = 0;
+ last_frame = 0;
+ changed = false;
+ cull.resize(VISIBILITY_CULL_MAX);
+ }
+};
+
+void World3D::_register_camera(Camera3D *p_camera) {
+
+#ifndef _3D_DISABLED
+ indexer->_add_camera(p_camera);
+#endif
+}
+
+void World3D::_update_camera(Camera3D *p_camera) {
+
+#ifndef _3D_DISABLED
+ indexer->_update_camera(p_camera);
+#endif
+}
+void World3D::_remove_camera(Camera3D *p_camera) {
+
+#ifndef _3D_DISABLED
+ indexer->_remove_camera(p_camera);
+#endif
+}
+
+void World3D::_register_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect) {
+
+#ifndef _3D_DISABLED
+ indexer->_notifier_add(p_notifier, p_rect);
+#endif
+}
+
+void World3D::_update_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect) {
+
+#ifndef _3D_DISABLED
+ indexer->_notifier_update(p_notifier, p_rect);
+#endif
+}
+
+void World3D::_remove_notifier(VisibilityNotifier3D *p_notifier) {
+
+#ifndef _3D_DISABLED
+ indexer->_notifier_remove(p_notifier);
+#endif
+}
+
+void World3D::_update(uint64_t p_frame) {
+
+#ifndef _3D_DISABLED
+ indexer->_update(p_frame);
+#endif
+}
+
+RID World3D::get_space() const {
+
+ return space;
+}
+
+RID World3D::get_scenario() const {
+
+ return scenario;
+}
+
+void World3D::set_environment(const Ref<Environment> &p_environment) {
+ if (environment == p_environment) {
+ return;
+ }
+
+ environment = p_environment;
+ if (environment.is_valid())
+ RS::get_singleton()->scenario_set_environment(scenario, environment->get_rid());
+ else
+ RS::get_singleton()->scenario_set_environment(scenario, RID());
+
+ emit_changed();
+}
+
+Ref<Environment> World3D::get_environment() const {
+
+ return environment;
+}
+
+void World3D::set_fallback_environment(const Ref<Environment> &p_environment) {
+ if (fallback_environment == p_environment) {
+ return;
+ }
+
+ fallback_environment = p_environment;
+ if (fallback_environment.is_valid())
+ RS::get_singleton()->scenario_set_fallback_environment(scenario, p_environment->get_rid());
+ else
+ RS::get_singleton()->scenario_set_fallback_environment(scenario, RID());
+
+ emit_changed();
+}
+
+Ref<Environment> World3D::get_fallback_environment() const {
+
+ return fallback_environment;
+}
+
+void World3D::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) {
+
+ camera_effects = p_camera_effects;
+ if (camera_effects.is_valid())
+ RS::get_singleton()->scenario_set_camera_effects(scenario, camera_effects->get_rid());
+ else
+ RS::get_singleton()->scenario_set_camera_effects(scenario, RID());
+}
+
+Ref<CameraEffects> World3D::get_camera_effects() const {
+
+ return camera_effects;
+}
+
+PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
+
+ return PhysicsServer3D::get_singleton()->space_get_direct_state(space);
+}
+
+void World3D::get_camera_list(List<Camera3D *> *r_cameras) {
+
+ for (Map<Camera3D *, SpatialIndexer::CameraData>::Element *E = indexer->cameras.front(); E; E = E->next()) {
+ r_cameras->push_back(E->key());
+ }
+}
+
+void World3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space);
+ 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("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, "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");
+}
+
+World3D::World3D() {
+
+ space = PhysicsServer3D::get_singleton()->space_create();
+ scenario = RenderingServer::get_singleton()->scenario_create();
+
+ PhysicsServer3D::get_singleton()->space_set_active(space, true);
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
+ 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"));
+
+#ifdef _3D_DISABLED
+ indexer = nullptr;
+#else
+ indexer = memnew(SpatialIndexer);
+#endif
+}
+
+World3D::~World3D() {
+
+ PhysicsServer3D::get_singleton()->free(space);
+ RenderingServer::get_singleton()->free(scenario);
+
+#ifndef _3D_DISABLED
+ memdelete(indexer);
+#endif
+}
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
new file mode 100644
index 0000000000..81a27a7349
--- /dev/null
+++ b/scene/resources/world_3d.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* world_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 WORLD_3D_H
+#define WORLD_3D_H
+
+#include "core/resource.h"
+#include "scene/resources/environment.h"
+#include "servers/physics_server_3d.h"
+#include "servers/rendering_server.h"
+
+class Camera3D;
+class VisibilityNotifier3D;
+struct SpatialIndexer;
+
+class World3D : public Resource {
+ GDCLASS(World3D, Resource);
+
+private:
+ RID space;
+ RID scenario;
+ SpatialIndexer *indexer;
+ Ref<Environment> environment;
+ Ref<Environment> fallback_environment;
+ Ref<CameraEffects> camera_effects;
+
+protected:
+ static void _bind_methods();
+
+ friend class Camera3D;
+ friend class VisibilityNotifier3D;
+
+ void _register_camera(Camera3D *p_camera);
+ void _update_camera(Camera3D *p_camera);
+ void _remove_camera(Camera3D *p_camera);
+
+ void _register_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect);
+ void _update_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect);
+ void _remove_notifier(VisibilityNotifier3D *p_notifier);
+ friend class Viewport;
+ void _update(uint64_t p_frame);
+
+public:
+ RID get_space() const;
+ RID get_scenario() const;
+
+ void set_environment(const Ref<Environment> &p_environment);
+ Ref<Environment> get_environment() const;
+
+ void set_fallback_environment(const Ref<Environment> &p_environment);
+ Ref<Environment> get_fallback_environment() const;
+
+ void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
+ Ref<CameraEffects> get_camera_effects() const;
+
+ void get_camera_list(List<Camera3D *> *r_cameras);
+
+ PhysicsDirectSpaceState3D *get_direct_space_state();
+
+ World3D();
+ ~World3D();
+};
+
+#endif // WORLD_3D_H
diff --git a/scene/resources/world_margin_shape.cpp b/scene/resources/world_margin_shape.cpp
deleted file mode 100644
index b5b701327c..0000000000
--- a/scene/resources/world_margin_shape.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*************************************************************************/
-/* world_margin_shape.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "world_margin_shape.h"
-
-#include "servers/physics_server.h"
-
-Vector<Vector3> WorldMarginShape::get_debug_mesh_lines() {
-
- Plane p = get_plane();
- Vector<Vector3> points;
-
- Vector3 n1 = p.get_any_perpendicular_normal();
- Vector3 n2 = p.normal.cross(n1).normalized();
-
- Vector3 pface[4] = {
- p.normal * p.d + n1 * 10.0 + n2 * 10.0,
- p.normal * p.d + n1 * 10.0 + n2 * -10.0,
- p.normal * p.d + n1 * -10.0 + n2 * -10.0,
- p.normal * p.d + n1 * -10.0 + n2 * 10.0,
- };
-
- points.push_back(pface[0]);
- points.push_back(pface[1]);
- points.push_back(pface[1]);
- points.push_back(pface[2]);
- points.push_back(pface[2]);
- points.push_back(pface[3]);
- points.push_back(pface[3]);
- points.push_back(pface[0]);
- points.push_back(p.normal * p.d);
- points.push_back(p.normal * p.d + p.normal * 3);
-
- return points;
-}
-
-void WorldMarginShape::_update_shape() {
-
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), plane);
- Shape::_update_shape();
-}
-
-void WorldMarginShape::set_plane(Plane p_plane) {
-
- plane = p_plane;
- _update_shape();
- notify_change_to_owners();
- _change_notify("plane");
-}
-
-Plane WorldMarginShape::get_plane() const {
-
- return plane;
-}
-
-void WorldMarginShape::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldMarginShape::set_plane);
- ClassDB::bind_method(D_METHOD("get_plane"), &WorldMarginShape::get_plane);
-
- ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane");
-}
-
-WorldMarginShape::WorldMarginShape() :
- Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_PLANE)) {
-
- set_plane(Plane(0, 1, 0, 0));
-}
diff --git a/scene/resources/world_margin_shape.h b/scene/resources/world_margin_shape.h
deleted file mode 100644
index 78ea570212..0000000000
--- a/scene/resources/world_margin_shape.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*************************************************************************/
-/* world_margin_shape.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 WORLD_MARGIN_SHAPE_H
-#define WORLD_MARGIN_SHAPE_H
-
-#include "scene/resources/shape.h"
-
-class WorldMarginShape : public Shape {
-
- GDCLASS(WorldMarginShape, Shape);
- Plane plane;
-
-protected:
- static void _bind_methods();
- virtual void _update_shape();
-
-public:
- void set_plane(Plane p_plane);
- Plane get_plane() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines();
- virtual real_t get_enclosing_radius() const {
- // Should be infinite?
- return 0;
- }
-
- WorldMarginShape();
-};
-#endif // WORLD_MARGIN_SHAPE_H
diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_margin_shape_3d.cpp
new file mode 100644
index 0000000000..aa96f8aa68
--- /dev/null
+++ b/scene/resources/world_margin_shape_3d.cpp
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* world_margin_shape_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "world_margin_shape_3d.h"
+
+#include "servers/physics_server_3d.h"
+
+Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() {
+
+ Plane p = get_plane();
+ Vector<Vector3> points;
+
+ Vector3 n1 = p.get_any_perpendicular_normal();
+ Vector3 n2 = p.normal.cross(n1).normalized();
+
+ Vector3 pface[4] = {
+ p.normal * p.d + n1 * 10.0 + n2 * 10.0,
+ p.normal * p.d + n1 * 10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * 10.0,
+ };
+
+ points.push_back(pface[0]);
+ points.push_back(pface[1]);
+ points.push_back(pface[1]);
+ points.push_back(pface[2]);
+ points.push_back(pface[2]);
+ points.push_back(pface[3]);
+ points.push_back(pface[3]);
+ points.push_back(pface[0]);
+ points.push_back(p.normal * p.d);
+ points.push_back(p.normal * p.d + p.normal * 3);
+
+ return points;
+}
+
+void WorldMarginShape3D::_update_shape() {
+
+ PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane);
+ Shape3D::_update_shape();
+}
+
+void WorldMarginShape3D::set_plane(Plane p_plane) {
+
+ plane = p_plane;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("plane");
+}
+
+Plane WorldMarginShape3D::get_plane() const {
+
+ return plane;
+}
+
+void WorldMarginShape3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldMarginShape3D::set_plane);
+ ClassDB::bind_method(D_METHOD("get_plane"), &WorldMarginShape3D::get_plane);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane");
+}
+
+WorldMarginShape3D::WorldMarginShape3D() :
+ Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_PLANE)) {
+
+ set_plane(Plane(0, 1, 0, 0));
+}
diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_margin_shape_3d.h
new file mode 100644
index 0000000000..5e0f046628
--- /dev/null
+++ b/scene/resources/world_margin_shape_3d.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* world_margin_shape_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 WORLD_MARGIN_SHAPE_3D_H
+#define WORLD_MARGIN_SHAPE_3D_H
+
+#include "scene/resources/shape_3d.h"
+
+class WorldMarginShape3D : public Shape3D {
+
+ GDCLASS(WorldMarginShape3D, Shape3D);
+ Plane plane;
+
+protected:
+ static void _bind_methods();
+ virtual void _update_shape();
+
+public:
+ void set_plane(Plane p_plane);
+ Plane get_plane() const;
+
+ virtual Vector<Vector3> get_debug_mesh_lines();
+ virtual real_t get_enclosing_radius() const {
+ // Should be infinite?
+ return 0;
+ }
+
+ WorldMarginShape3D();
+};
+#endif // WORLD_MARGIN_SHAPE_H
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index d3c5a87cae..ad996e7d50 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -30,7 +30,7 @@
#include "scene_string_names.h"
-SceneStringNames *SceneStringNames::singleton = NULL;
+SceneStringNames *SceneStringNames::singleton = nullptr;
SceneStringNames::SceneStringNames() {
@@ -193,6 +193,12 @@ SceneStringNames::SceneStringNames() {
mesh_materials[i] = "material/" + itos(i);
}
+ _window_group = StaticCString::create("_window_group");
+ _window_input = StaticCString::create("_window_input");
+ window_input = StaticCString::create("window_input");
+ _window_unhandled_input = StaticCString::create("_window_unhandled_input");
+
+ theme_changed = StaticCString::create("theme_changed");
parameters_base_path = "parameters/";
tracks_changed = "tracks_changed";
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 7976a2072c..58e8c28454 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -44,7 +44,7 @@ class SceneStringNames {
static void create() { singleton = memnew(SceneStringNames); }
static void free() {
memdelete(singleton);
- singleton = NULL;
+ singleton = nullptr;
}
SceneStringNames();
@@ -201,6 +201,13 @@ public:
StringName tracks_changed;
+ StringName _window_group;
+ StringName _window_input;
+ StringName _window_unhandled_input;
+ StringName window_input;
+
+ StringName theme_changed;
+
enum {
MAX_MATERIALS = 32
};
diff --git a/servers/SCsub b/servers/SCsub
index 34ba70b8cb..121990f2e1 100644
--- a/servers/SCsub
+++ b/servers/SCsub
@@ -1,16 +1,16 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.servers_sources = []
env.add_source_files(env.servers_sources, "*.cpp")
-SConscript('arvr/SCsub')
-SConscript('camera/SCsub')
-SConscript('physics/SCsub')
-SConscript('physics_2d/SCsub')
-SConscript('visual/SCsub')
-SConscript('audio/SCsub')
+SConscript("xr/SCsub")
+SConscript("camera/SCsub")
+SConscript("physics_3d/SCsub")
+SConscript("physics_2d/SCsub")
+SConscript("rendering/SCsub")
+SConscript("audio/SCsub")
lib = env.add_library("servers", env.servers_sources)
diff --git a/servers/arvr/SCsub b/servers/arvr/SCsub
deleted file mode 100644
index d730144861..0000000000
--- a/servers/arvr/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp
deleted file mode 100644
index 577b4cdd8a..0000000000
--- a/servers/arvr/arvr_interface.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*************************************************************************/
-/* arvr_interface.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "arvr_interface.h"
-
-void ARVRInterface::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_name"), &ARVRInterface::get_name);
- ClassDB::bind_method(D_METHOD("get_capabilities"), &ARVRInterface::get_capabilities);
-
- ClassDB::bind_method(D_METHOD("is_primary"), &ARVRInterface::is_primary);
- ClassDB::bind_method(D_METHOD("set_is_primary", "enable"), &ARVRInterface::set_is_primary);
-
- ClassDB::bind_method(D_METHOD("is_initialized"), &ARVRInterface::is_initialized);
- ClassDB::bind_method(D_METHOD("set_is_initialized", "initialized"), &ARVRInterface::set_is_initialized);
- ClassDB::bind_method(D_METHOD("initialize"), &ARVRInterface::initialize);
- ClassDB::bind_method(D_METHOD("uninitialize"), &ARVRInterface::uninitialize);
-
- ClassDB::bind_method(D_METHOD("get_tracking_status"), &ARVRInterface::get_tracking_status);
-
- ClassDB::bind_method(D_METHOD("get_render_targetsize"), &ARVRInterface::get_render_targetsize);
- ClassDB::bind_method(D_METHOD("is_stereo"), &ARVRInterface::is_stereo);
-
- ADD_GROUP("Interface", "interface_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_is_primary", "is_primary");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_initialized"), "set_is_initialized", "is_initialized");
-
- // we don't have any properties specific to VR yet....
-
- // but we do have properties specific to AR....
- ClassDB::bind_method(D_METHOD("get_anchor_detection_is_enabled"), &ARVRInterface::get_anchor_detection_is_enabled);
- ClassDB::bind_method(D_METHOD("set_anchor_detection_is_enabled", "enable"), &ARVRInterface::set_anchor_detection_is_enabled);
- ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &ARVRInterface::get_camera_feed_id);
-
- ADD_GROUP("AR", "ar_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled");
-
- BIND_ENUM_CONSTANT(ARVR_NONE);
- BIND_ENUM_CONSTANT(ARVR_MONO);
- BIND_ENUM_CONSTANT(ARVR_STEREO);
- BIND_ENUM_CONSTANT(ARVR_AR);
- BIND_ENUM_CONSTANT(ARVR_EXTERNAL);
-
- BIND_ENUM_CONSTANT(EYE_MONO);
- BIND_ENUM_CONSTANT(EYE_LEFT);
- BIND_ENUM_CONSTANT(EYE_RIGHT);
-
- BIND_ENUM_CONSTANT(ARVR_NORMAL_TRACKING);
- BIND_ENUM_CONSTANT(ARVR_EXCESSIVE_MOTION);
- BIND_ENUM_CONSTANT(ARVR_INSUFFICIENT_FEATURES);
- BIND_ENUM_CONSTANT(ARVR_UNKNOWN_TRACKING);
- BIND_ENUM_CONSTANT(ARVR_NOT_TRACKING);
-};
-
-StringName ARVRInterface::get_name() const {
- return "Unknown";
-};
-
-bool ARVRInterface::is_primary() {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, false);
-
- return arvr_server->get_primary_interface() == this;
-};
-
-void ARVRInterface::set_is_primary(bool p_is_primary) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- if (p_is_primary) {
- ERR_FAIL_COND(!is_initialized());
-
- arvr_server->set_primary_interface(this);
- } else {
- arvr_server->clear_primary_interface_if(this);
- };
-};
-
-void ARVRInterface::set_is_initialized(bool p_initialized) {
- if (p_initialized) {
- if (!is_initialized()) {
- initialize();
- };
- } else {
- if (is_initialized()) {
- uninitialize();
- };
- };
-};
-
-ARVRInterface::Tracking_status ARVRInterface::get_tracking_status() const {
- return tracking_state;
-};
-
-ARVRInterface::ARVRInterface() {
- tracking_state = ARVR_UNKNOWN_TRACKING;
-};
-
-ARVRInterface::~ARVRInterface(){};
-
-// optional render to external texture which enhances performance on those platforms that require us to submit our end result into special textures.
-unsigned int ARVRInterface::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) {
- return 0;
-};
-
-/** these will only be implemented on AR interfaces, so we want dummies for VR **/
-bool ARVRInterface::get_anchor_detection_is_enabled() const {
- return false;
-};
-
-void ARVRInterface::set_anchor_detection_is_enabled(bool p_enable){
- // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
-};
-
-int ARVRInterface::get_camera_feed_id() {
- // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
-
- return 0;
-};
diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h
deleted file mode 100644
index f33ddb2411..0000000000
--- a/servers/arvr/arvr_interface.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*************************************************************************/
-/* arvr_interface.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 ARVR_INTERFACE_H
-#define ARVR_INTERFACE_H
-
-#include "core/math/camera_matrix.h"
-#include "core/os/thread_safe.h"
-#include "scene/main/viewport.h"
-#include "servers/arvr_server.h"
-
-/**
- @author Bastiaan Olij <mux213@gmail.com>
-
- The ARVR interface is a template class ontop of which we build interface to different AR, VR and tracking SDKs.
- The idea is that we subclass this class, implement the logic, and then instantiate a singleton of each interface
- when Godot starts. These instances do not initialize themselves but register themselves with the AR/VR server.
-
- If the user wants to enable AR/VR the choose the interface they want to use and initialize it.
-
- Note that we may make this into a fully instantiable class for GDNative support.
-*/
-
-class ARVRInterface : public Reference {
- GDCLASS(ARVRInterface, Reference);
-
-public:
- enum Capabilities { /* purely meta data, provides some info about what this interface supports */
- ARVR_NONE = 0, /* no capabilities */
- ARVR_MONO = 1, /* can be used with mono output */
- ARVR_STEREO = 2, /* can be used with stereo output */
- ARVR_AR = 4, /* offers a camera feed for AR */
- ARVR_EXTERNAL = 8 /* renders to external device */
- };
-
- enum Eyes {
- EYE_MONO, /* my son says we should call this EYE_CYCLOPS */
- EYE_LEFT,
- EYE_RIGHT
- };
-
- enum Tracking_status { /* tracking status currently based on AR but we can start doing more with this for VR as well */
- ARVR_NORMAL_TRACKING,
- ARVR_EXCESSIVE_MOTION,
- ARVR_INSUFFICIENT_FEATURES,
- ARVR_UNKNOWN_TRACKING,
- ARVR_NOT_TRACKING
- };
-
-protected:
- _THREAD_SAFE_CLASS_
-
- Tracking_status tracking_state;
- static void _bind_methods();
-
-public:
- /** general interface information **/
- virtual StringName get_name() const;
- virtual int get_capabilities() const = 0;
-
- bool is_primary();
- void set_is_primary(bool p_is_primary);
-
- virtual bool is_initialized() const = 0; /* returns true if we've initialized this interface */
- void set_is_initialized(bool p_initialized); /* helper function, will call initialize or uninitialize */
- virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */
- virtual void uninitialize() = 0; /* deinitialize this interface */
-
- Tracking_status get_tracking_status() const; /* get the status of our current tracking */
-
- /** specific to VR **/
- // nothing yet
-
- /** specific to AR **/
- virtual bool get_anchor_detection_is_enabled() const;
- virtual void set_anchor_detection_is_enabled(bool p_enable);
- virtual int get_camera_feed_id();
-
- /** rendering and internal **/
-
- virtual Size2 get_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */
- virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */
- virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */
- virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */
- virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye); /* if applicable return external texture to render to */
- virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */
-
- virtual void process() = 0;
- virtual void notification(int p_what) = 0;
-
- ARVRInterface();
- ~ARVRInterface();
-};
-
-VARIANT_ENUM_CAST(ARVRInterface::Capabilities);
-VARIANT_ENUM_CAST(ARVRInterface::Eyes);
-VARIANT_ENUM_CAST(ARVRInterface::Tracking_status);
-
-#endif
diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp
deleted file mode 100644
index a64e36b6a2..0000000000
--- a/servers/arvr/arvr_positional_tracker.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/*************************************************************************/
-/* arvr_positional_tracker.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "arvr_positional_tracker.h"
-#include "core/os/input.h"
-
-void ARVRPositionalTracker::_bind_methods() {
- BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN);
- BIND_ENUM_CONSTANT(TRACKER_LEFT_HAND);
- BIND_ENUM_CONSTANT(TRACKER_RIGHT_HAND);
-
- // this class is read only from GDScript, so we only have access to getters..
- ClassDB::bind_method(D_METHOD("get_type"), &ARVRPositionalTracker::get_type);
- ClassDB::bind_method(D_METHOD("get_tracker_id"), &ARVRPositionalTracker::get_tracker_id);
- ClassDB::bind_method(D_METHOD("get_name"), &ARVRPositionalTracker::get_name);
- ClassDB::bind_method(D_METHOD("get_joy_id"), &ARVRPositionalTracker::get_joy_id);
- ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &ARVRPositionalTracker::get_tracks_orientation);
- ClassDB::bind_method(D_METHOD("get_orientation"), &ARVRPositionalTracker::get_orientation);
- ClassDB::bind_method(D_METHOD("get_tracks_position"), &ARVRPositionalTracker::get_tracks_position);
- ClassDB::bind_method(D_METHOD("get_position"), &ARVRPositionalTracker::get_position);
- ClassDB::bind_method(D_METHOD("get_hand"), &ARVRPositionalTracker::get_hand);
- ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &ARVRPositionalTracker::get_transform);
- ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRPositionalTracker::get_mesh);
-
- // these functions we don't want to expose to normal users but do need to be callable from GDNative
- ClassDB::bind_method(D_METHOD("_set_type", "type"), &ARVRPositionalTracker::set_type);
- ClassDB::bind_method(D_METHOD("_set_name", "name"), &ARVRPositionalTracker::set_name);
- ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &ARVRPositionalTracker::set_joy_id);
- ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &ARVRPositionalTracker::set_orientation);
- ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &ARVRPositionalTracker::set_rw_position);
- ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &ARVRPositionalTracker::set_mesh);
- ClassDB::bind_method(D_METHOD("get_rumble"), &ARVRPositionalTracker::get_rumble);
- ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRPositionalTracker::set_rumble);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble");
-};
-
-void ARVRPositionalTracker::set_type(ARVRServer::TrackerType p_type) {
- if (type != p_type) {
- type = p_type;
- hand = ARVRPositionalTracker::TRACKER_HAND_UNKNOWN;
-
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- // get a tracker id for our type
- // note if this is a controller this will be 3 or higher but we may change it later.
- tracker_id = arvr_server->get_free_tracker_id_for_type(p_type);
- };
-};
-
-ARVRServer::TrackerType ARVRPositionalTracker::get_type() const {
- return type;
-};
-
-void ARVRPositionalTracker::set_name(const String &p_name) {
- name = p_name;
-};
-
-StringName ARVRPositionalTracker::get_name() const {
- return name;
-};
-
-int ARVRPositionalTracker::get_tracker_id() const {
- return tracker_id;
-};
-
-void ARVRPositionalTracker::set_joy_id(int p_joy_id) {
- joy_id = p_joy_id;
-};
-
-int ARVRPositionalTracker::get_joy_id() const {
- return joy_id;
-};
-
-bool ARVRPositionalTracker::get_tracks_orientation() const {
- return tracks_orientation;
-};
-
-void ARVRPositionalTracker::set_orientation(const Basis &p_orientation) {
- _THREAD_SAFE_METHOD_
-
- tracks_orientation = true; // obviously we have this
- orientation = p_orientation;
-};
-
-Basis ARVRPositionalTracker::get_orientation() const {
- _THREAD_SAFE_METHOD_
-
- return orientation;
-};
-
-bool ARVRPositionalTracker::get_tracks_position() const {
- return tracks_position;
-};
-
-void ARVRPositionalTracker::set_position(const Vector3 &p_position) {
- _THREAD_SAFE_METHOD_
-
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
- real_t world_scale = arvr_server->get_world_scale();
- ERR_FAIL_COND(world_scale == 0);
-
- tracks_position = true; // obviously we have this
- rw_position = p_position / world_scale;
-};
-
-Vector3 ARVRPositionalTracker::get_position() const {
- _THREAD_SAFE_METHOD_
-
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, rw_position);
- real_t world_scale = arvr_server->get_world_scale();
-
- return rw_position * world_scale;
-};
-
-void ARVRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) {
- _THREAD_SAFE_METHOD_
-
- tracks_position = true; // obviously we have this
- rw_position = p_rw_position;
-};
-
-Vector3 ARVRPositionalTracker::get_rw_position() const {
- _THREAD_SAFE_METHOD_
-
- return rw_position;
-};
-
-void ARVRPositionalTracker::set_mesh(const Ref<Mesh> &p_mesh) {
- _THREAD_SAFE_METHOD_
-
- mesh = p_mesh;
-};
-
-Ref<Mesh> ARVRPositionalTracker::get_mesh() const {
- _THREAD_SAFE_METHOD_
-
- return mesh;
-};
-
-ARVRPositionalTracker::TrackerHand ARVRPositionalTracker::get_hand() const {
- return hand;
-};
-
-void ARVRPositionalTracker::set_hand(const ARVRPositionalTracker::TrackerHand p_hand) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL(arvr_server);
-
- if (hand != p_hand) {
- // we can only set this if we've previously set this to be a controller!!
- ERR_FAIL_COND((type != ARVRServer::TRACKER_CONTROLLER) && (p_hand != ARVRPositionalTracker::TRACKER_HAND_UNKNOWN));
-
- hand = p_hand;
- if (hand == ARVRPositionalTracker::TRACKER_LEFT_HAND) {
- if (!arvr_server->is_tracker_id_in_use_for_type(type, 1)) {
- tracker_id = 1;
- };
- } else if (hand == ARVRPositionalTracker::TRACKER_RIGHT_HAND) {
- if (!arvr_server->is_tracker_id_in_use_for_type(type, 2)) {
- tracker_id = 2;
- };
- };
- };
-};
-
-Transform ARVRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
- Transform new_transform;
-
- new_transform.basis = get_orientation();
- new_transform.origin = get_position();
-
- if (p_adjust_by_reference_frame) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, new_transform);
-
- new_transform = arvr_server->get_reference_frame() * new_transform;
- };
-
- return new_transform;
-};
-
-real_t ARVRPositionalTracker::get_rumble() const {
- return rumble;
-};
-
-void ARVRPositionalTracker::set_rumble(real_t p_rumble) {
- if (p_rumble > 0.0) {
- rumble = p_rumble;
- } else {
- rumble = 0.0;
- };
-};
-
-ARVRPositionalTracker::ARVRPositionalTracker() {
- type = ARVRServer::TRACKER_UNKNOWN;
- name = "Unknown";
- joy_id = -1;
- tracker_id = 0;
- tracks_orientation = false;
- tracks_position = false;
- hand = TRACKER_HAND_UNKNOWN;
- rumble = 0.0;
-};
-
-ARVRPositionalTracker::~ARVRPositionalTracker(){
-
-};
diff --git a/servers/arvr/arvr_positional_tracker.h b/servers/arvr/arvr_positional_tracker.h
deleted file mode 100644
index 03c6b33ffe..0000000000
--- a/servers/arvr/arvr_positional_tracker.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*************************************************************************/
-/* arvr_positional_tracker.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 ARVR_POSITIONAL_TRACKER_H
-#define ARVR_POSITIONAL_TRACKER_H
-
-#include "core/os/thread_safe.h"
-#include "scene/resources/mesh.h"
-#include "servers/arvr_server.h"
-
-/**
- @author Bastiaan Olij <mux213@gmail.com>
-
- The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset.
- An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation.
- This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
-*/
-
-class ARVRPositionalTracker : public Object {
- GDCLASS(ARVRPositionalTracker, Object);
- _THREAD_SAFE_CLASS_
-
-public:
- enum TrackerHand {
- TRACKER_HAND_UNKNOWN, /* unknown or not applicable */
- TRACKER_LEFT_HAND, /* controller is the left hand controller */
- TRACKER_RIGHT_HAND /* controller is the right hand controller */
- };
-
-private:
- ARVRServer::TrackerType type; // type of tracker
- StringName name; // (unique) name of the tracker
- int tracker_id; // tracker index id that is unique per type
- int joy_id; // if we also have a related joystick entity, the id of the joystick
- bool tracks_orientation; // do we track orientation?
- Basis orientation; // our orientation
- bool tracks_position; // do we track position?
- Vector3 rw_position; // our position "in the real world, so without world_scale applied"
- Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker
- TrackerHand hand; // if known, the hand this tracker is held in
- real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, arvr_interface is responsible for execution
-
-protected:
- static void _bind_methods();
-
-public:
- void set_type(ARVRServer::TrackerType p_type);
- ARVRServer::TrackerType get_type() const;
- void set_name(const String &p_name);
- StringName get_name() const;
- int get_tracker_id() const;
- void set_joy_id(int p_joy_id);
- int get_joy_id() const;
- bool get_tracks_orientation() const;
- void set_orientation(const Basis &p_orientation);
- Basis get_orientation() const;
- bool get_tracks_position() const;
- void set_position(const Vector3 &p_position); // set position with world_scale applied
- Vector3 get_position() const; // get position with world_scale applied
- void set_rw_position(const Vector3 &p_rw_position);
- Vector3 get_rw_position() const;
- ARVRPositionalTracker::TrackerHand get_hand() const;
- void set_hand(const ARVRPositionalTracker::TrackerHand p_hand);
- real_t get_rumble() const;
- void set_rumble(real_t p_rumble);
- void set_mesh(const Ref<Mesh> &p_mesh);
- Ref<Mesh> get_mesh() const;
-
- Transform get_transform(bool p_adjust_by_reference_frame) const;
-
- ARVRPositionalTracker();
- ~ARVRPositionalTracker();
-};
-
-VARIANT_ENUM_CAST(ARVRPositionalTracker::TrackerHand);
-
-#endif
diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp
deleted file mode 100644
index 4b3417db6c..0000000000
--- a/servers/arvr_server.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-/*************************************************************************/
-/* arvr_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "arvr_server.h"
-#include "arvr/arvr_interface.h"
-#include "arvr/arvr_positional_tracker.h"
-#include "core/project_settings.h"
-
-ARVRServer *ARVRServer::singleton = NULL;
-
-ARVRServer *ARVRServer::get_singleton() {
- return singleton;
-};
-
-void ARVRServer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVRServer::get_world_scale);
- ClassDB::bind_method(D_METHOD("set_world_scale"), &ARVRServer::set_world_scale);
- ClassDB::bind_method(D_METHOD("get_reference_frame"), &ARVRServer::get_reference_frame);
- ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &ARVRServer::center_on_hmd);
- ClassDB::bind_method(D_METHOD("get_hmd_transform"), &ARVRServer::get_hmd_transform);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
-
- ClassDB::bind_method(D_METHOD("get_interface_count"), &ARVRServer::get_interface_count);
- ClassDB::bind_method(D_METHOD("get_interface", "idx"), &ARVRServer::get_interface);
- ClassDB::bind_method(D_METHOD("get_interfaces"), &ARVRServer::get_interfaces);
- ClassDB::bind_method(D_METHOD("find_interface", "name"), &ARVRServer::find_interface);
- ClassDB::bind_method(D_METHOD("get_tracker_count"), &ARVRServer::get_tracker_count);
- ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &ARVRServer::get_tracker);
-
- ClassDB::bind_method(D_METHOD("get_primary_interface"), &ARVRServer::get_primary_interface);
- ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &ARVRServer::set_primary_interface);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "primary_interface"), "set_primary_interface", "get_primary_interface");
-
- ClassDB::bind_method(D_METHOD("get_last_process_usec"), &ARVRServer::get_last_process_usec);
- ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &ARVRServer::get_last_commit_usec);
- ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &ARVRServer::get_last_frame_usec);
-
- BIND_ENUM_CONSTANT(TRACKER_CONTROLLER);
- BIND_ENUM_CONSTANT(TRACKER_BASESTATION);
- BIND_ENUM_CONSTANT(TRACKER_ANCHOR);
- BIND_ENUM_CONSTANT(TRACKER_ANY_KNOWN);
- BIND_ENUM_CONSTANT(TRACKER_UNKNOWN);
- BIND_ENUM_CONSTANT(TRACKER_ANY);
-
- BIND_ENUM_CONSTANT(RESET_FULL_ROTATION);
- BIND_ENUM_CONSTANT(RESET_BUT_KEEP_TILT);
- BIND_ENUM_CONSTANT(DONT_RESET_ROTATION);
-
- ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name")));
- ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name")));
-
- ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id")));
- ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id")));
-};
-
-real_t ARVRServer::get_world_scale() const {
- return world_scale;
-};
-
-void ARVRServer::set_world_scale(real_t p_world_scale) {
- if (p_world_scale < 0.01) {
- p_world_scale = 0.01;
- } else if (p_world_scale > 1000.0) {
- p_world_scale = 1000.0;
- }
-
- world_scale = p_world_scale;
-};
-
-Transform ARVRServer::get_world_origin() const {
- return world_origin;
-};
-
-void ARVRServer::set_world_origin(const Transform &p_world_origin) {
- world_origin = p_world_origin;
-};
-
-Transform ARVRServer::get_reference_frame() const {
- return reference_frame;
-};
-
-void ARVRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
- if (primary_interface != NULL) {
- // clear our current reference frame or we'll end up double adjusting it
- reference_frame = Transform();
-
- // requesting our EYE_MONO transform should return our current HMD position
- Transform new_reference_frame = primary_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, Transform());
-
- // remove our tilt
- if (p_rotation_mode == 1) {
- // take the Y out of our Z
- new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized());
-
- // Y is straight up
- new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0));
-
- // and X is our cross reference
- new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized());
- } else if (p_rotation_mode == 2) {
- // remove our rotation, we're only interesting in centering on position
- new_reference_frame.basis = Basis();
- };
-
- // don't negate our height
- if (p_keep_height) {
- new_reference_frame.origin.y = 0.0;
- };
-
- reference_frame = new_reference_frame.inverse();
- };
-};
-
-Transform ARVRServer::get_hmd_transform() {
- Transform hmd_transform;
- if (primary_interface != NULL) {
- hmd_transform = primary_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, hmd_transform);
- };
- return hmd_transform;
-};
-
-void ARVRServer::add_interface(const Ref<ARVRInterface> &p_interface) {
- ERR_FAIL_COND(p_interface.is_null());
-
- for (int i = 0; i < interfaces.size(); i++) {
-
- if (interfaces[i] == p_interface) {
- ERR_PRINT("Interface was already added");
- return;
- };
- };
-
- interfaces.push_back(p_interface);
- emit_signal("interface_added", p_interface->get_name());
-};
-
-void ARVRServer::remove_interface(const Ref<ARVRInterface> &p_interface) {
- ERR_FAIL_COND(p_interface.is_null());
-
- int idx = -1;
- for (int i = 0; i < interfaces.size(); i++) {
-
- if (interfaces[i] == p_interface) {
-
- idx = i;
- break;
- };
- };
-
- ERR_FAIL_COND(idx == -1);
-
- print_verbose("ARVR: Removed interface" + p_interface->get_name());
-
- emit_signal("interface_removed", p_interface->get_name());
- interfaces.remove(idx);
-};
-
-int ARVRServer::get_interface_count() const {
- return interfaces.size();
-};
-
-Ref<ARVRInterface> ARVRServer::get_interface(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, interfaces.size(), NULL);
-
- return interfaces[p_index];
-};
-
-Ref<ARVRInterface> ARVRServer::find_interface(const String &p_name) const {
- int idx = -1;
- for (int i = 0; i < interfaces.size(); i++) {
-
- if (interfaces[i]->get_name() == p_name) {
-
- idx = i;
- break;
- };
- };
-
- ERR_FAIL_COND_V(idx == -1, NULL);
-
- return interfaces[idx];
-};
-
-Array ARVRServer::get_interfaces() const {
- Array ret;
-
- for (int i = 0; i < interfaces.size(); i++) {
- Dictionary iface_info;
-
- iface_info["id"] = i;
- iface_info["name"] = interfaces[i]->get_name();
-
- ret.push_back(iface_info);
- };
-
- return ret;
-};
-
-/*
- A little extra info on the tracker ids, these are unique per tracker type so we get some consistency in recognising our trackers, specifically controllers.
-
- The first controller that is turned of will get ID 1, the second will get ID 2, etc.
- The magic happens when one of the controllers is turned off, say controller 1 turns off, controller 2 will remain controller 2, controller 3 will remain controller 3.
- If controller number 1 is turned on again it again gets ID 1 unless another new controller was turned on since.
-
- The most likely scenario however is a controller that runs out of battery and another controller being used to replace it.
- Because the controllers are often linked to physical objects, say you're holding a shield in controller 1, your left hand, and a gun in controller 2, your right hand, and controller 1 dies:
- - using our tracker index would suddenly make the gun disappear and the shield jump into your right hand because controller 2 becomes controller 1.
- - using this approach the shield disappears or is no longer tracked, but the gun stays firmly in your right hand because that is still controller 2, further more, if controller 1 is replaced the shield will return.
-*/
-
-bool ARVRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const {
- for (int i = 0; i < trackers.size(); i++) {
- if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) {
- return true;
- };
- };
-
- // all good
- return false;
-};
-
-int ARVRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) {
- // We start checking at 1, 0 means that it's not a controller..
- // Note that for controller we reserve:
- // - 1 for the left hand controller and
- // - 2 for the right hand controller
- // so we start at 3 :)
- int tracker_id = p_tracker_type == ARVRServer::TRACKER_CONTROLLER ? 3 : 1;
-
- while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) {
- // try the next one
- tracker_id++;
- };
-
- return tracker_id;
-};
-
-void ARVRServer::add_tracker(ARVRPositionalTracker *p_tracker) {
- ERR_FAIL_NULL(p_tracker);
-
- trackers.push_back(p_tracker);
- emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id());
-};
-
-void ARVRServer::remove_tracker(ARVRPositionalTracker *p_tracker) {
- ERR_FAIL_NULL(p_tracker);
-
- int idx = -1;
- for (int i = 0; i < trackers.size(); i++) {
-
- if (trackers[i] == p_tracker) {
-
- idx = i;
- break;
- };
- };
-
- ERR_FAIL_COND(idx == -1);
-
- emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id());
- trackers.remove(idx);
-};
-
-int ARVRServer::get_tracker_count() const {
- return trackers.size();
-};
-
-ARVRPositionalTracker *ARVRServer::get_tracker(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, trackers.size(), NULL);
-
- return trackers[p_index];
-};
-
-ARVRPositionalTracker *ARVRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const {
- ERR_FAIL_COND_V(p_tracker_id == 0, NULL);
-
- for (int i = 0; i < trackers.size(); i++) {
- if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) {
- return trackers[i];
- };
- };
-
- return NULL;
-};
-
-Ref<ARVRInterface> ARVRServer::get_primary_interface() const {
- return primary_interface;
-};
-
-void ARVRServer::set_primary_interface(const Ref<ARVRInterface> &p_primary_interface) {
- primary_interface = p_primary_interface;
-
- print_verbose("ARVR: Primary interface set to: " + primary_interface->get_name());
-};
-
-void ARVRServer::clear_primary_interface_if(const Ref<ARVRInterface> &p_primary_interface) {
- if (primary_interface == p_primary_interface) {
- print_verbose("ARVR: Clearing primary interface");
- primary_interface.unref();
- };
-};
-
-uint64_t ARVRServer::get_last_process_usec() {
- return last_process_usec;
-};
-
-uint64_t ARVRServer::get_last_commit_usec() {
- return last_commit_usec;
-};
-
-uint64_t ARVRServer::get_last_frame_usec() {
- return last_frame_usec;
-};
-
-void ARVRServer::_process() {
- /* called from visual_server_viewport.draw_viewports right before we start drawing our viewports */
-
- /* mark for our frame timing */
- last_process_usec = OS::get_singleton()->get_ticks_usec();
-
- /* process all active interfaces */
- for (int i = 0; i < interfaces.size(); i++) {
- if (!interfaces[i].is_valid()) {
- // ignore, not a valid reference
- } else if (interfaces[i]->is_initialized()) {
- interfaces.write[i]->process();
- };
- };
-};
-
-void ARVRServer::_mark_commit() {
- /* time this */
- last_commit_usec = OS::get_singleton()->get_ticks_usec();
-
- /* now store our difference as we may overwrite last_process_usec before this is accessed */
- last_frame_usec = last_commit_usec - last_process_usec;
-};
-
-ARVRServer::ARVRServer() {
- singleton = this;
- world_scale = 1.0;
-};
-
-ARVRServer::~ARVRServer() {
- primary_interface.unref();
-
- while (interfaces.size() > 0) {
- interfaces.remove(0);
- }
-
- while (trackers.size() > 0) {
- trackers.remove(0);
- }
-
- singleton = NULL;
-};
diff --git a/servers/arvr_server.h b/servers/arvr_server.h
deleted file mode 100644
index af1d2ba39f..0000000000
--- a/servers/arvr_server.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*************************************************************************/
-/* arvr_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 ARVR_SERVER_H
-#define ARVR_SERVER_H
-
-#include "core/os/os.h"
-#include "core/os/thread_safe.h"
-#include "core/reference.h"
-#include "core/rid.h"
-#include "core/variant.h"
-
-class ARVRInterface;
-class ARVRPositionalTracker;
-
-/**
- @author Bastiaan Olij <mux213@gmail.com>
-
- The ARVR server is a singleton object that gives access to the various
- objects and SDKs that are available on the system.
- Because there can be multiple SDKs active this is exposed as an array
- and our ARVR server object acts as a pass through
- Also each positioning tracker is accessible from here.
-
- I've added some additional info into this header file that should move
- into the documentation, I will do so when we're close to accepting this PR
- or as a separate PR once this has been merged into the master branch.
-**/
-
-class ARVRServer : public Object {
- GDCLASS(ARVRServer, Object);
- _THREAD_SAFE_CLASS_
-
-public:
- enum TrackerType {
- TRACKER_CONTROLLER = 0x01, /* tracks a controller */
- TRACKER_BASESTATION = 0x02, /* tracks location of a base station */
- TRACKER_ANCHOR = 0x04, /* tracks an anchor point, used in AR to track a real live location */
- TRACKER_UNKNOWN = 0x80, /* unknown tracker */
-
- TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */
- TRACKER_ANY = 0xff /* used by get_connected_trackers to return all types */
- };
-
- enum RotationMode {
- RESET_FULL_ROTATION = 0, /* we reset the full rotation, regardless of how the HMD is oriented, we're looking dead ahead */
- RESET_BUT_KEEP_TILT = 1, /* reset rotation but keep tilt. */
- DONT_RESET_ROTATION = 2, /* don't reset the rotation, we will only center on position */
- };
-
-private:
- Vector<Ref<ARVRInterface> > interfaces;
- Vector<ARVRPositionalTracker *> trackers;
-
- Ref<ARVRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */
-
- real_t world_scale; /* scale by which we multiply our tracker positions */
- Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */
- Transform reference_frame; /* our reference frame */
-
- uint64_t last_process_usec; /* for frame timing, usec when we did our processing */
- uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */
- uint64_t last_frame_usec; /* time it took between process and committing, we should probably average this over the last x frames */
-
-protected:
- static ARVRServer *singleton;
-
- static void _bind_methods();
-
-public:
- static ARVRServer *get_singleton();
-
- /*
- World scale allows you to specify a scale factor that is applied to all positioning vectors in our VR world in essence scaling up, or scaling down the world.
- For stereoscopic rendering specifically this is very important to give an accurate sense of scale.
- Add controllers into the mix and an accurate mapping of real world movement to perceived virtual movement becomes very important.
-
- Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode.
- This scale basically effects the unit size relationship to real world size.
-
- I may remove access to this property in GDScript in favour of exposing it on the ARVROrigin node
- */
- real_t get_world_scale() const;
- void set_world_scale(real_t p_world_scale);
-
- /*
- The world maps the 0,0,0 coordinate of our real world coordinate system for our tracking volume to a location in our
- virtual world. It is this origin point that should be moved when the player is moved through the world by controller
- actions be it straffing, teleporting, etc. Movement of the player by moving through the physical space is always tracked
- in relation to this point.
-
- Note that the ARVROrigin spatial node in your scene automatically updates this property and it should be used instead of
- direct access to this property and it therefore is not available in GDScript
-
- Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world
- and in the virtual world out of sync
- */
- Transform get_world_origin() const;
- void set_world_origin(const Transform &p_world_origin);
-
- /*
- center_on_hmd calculates a new reference frame. This ensures the HMD is positioned to 0,0,0 facing 0,0,-1 (need to verify this direction)
- in the virtual world.
-
- You can ignore the tilt of the device ensuring you're looking straight forward even if the player is looking down or sideways.
- You can chose to keep the height the tracking provides which is important for room scale capable tracking.
-
- Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world
- and in the virtual world out of sync
- */
- Transform get_reference_frame() const;
- void center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height);
-
- /*
- get_hmd_transform gets our hmd transform (centered between eyes) with most up to date tracking, relative to the origin
- */
- Transform get_hmd_transform();
-
- /*
- Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc.
- */
- void add_interface(const Ref<ARVRInterface> &p_interface);
- void remove_interface(const Ref<ARVRInterface> &p_interface);
- int get_interface_count() const;
- Ref<ARVRInterface> get_interface(int p_index) const;
- Ref<ARVRInterface> find_interface(const String &p_name) const;
- Array get_interfaces() const;
-
- /*
- note, more then one interface can technically be active, especially on mobile, but only one interface is used for
- rendering. This interface identifies itself by calling set_primary_interface when it is initialized
- */
- Ref<ARVRInterface> get_primary_interface() const;
- void set_primary_interface(const Ref<ARVRInterface> &p_primary_interface);
- void clear_primary_interface_if(const Ref<ARVRInterface> &p_primary_interface); /* this is automatically called if an interface destructs */
-
- /*
- Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc.
- They are created and managed by our active AR/VR interfaces.
- */
- 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(ARVRPositionalTracker *p_tracker);
- void remove_tracker(ARVRPositionalTracker *p_tracker);
- int get_tracker_count() const;
- ARVRPositionalTracker *get_tracker(int p_index) const;
- ARVRPositionalTracker *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();
- uint64_t get_last_frame_usec();
-
- void _process();
- void _mark_commit();
-
- ARVRServer();
- ~ARVRServer();
-};
-
-#define ARVR ARVRServer
-
-VARIANT_ENUM_CAST(ARVRServer::TrackerType);
-VARIANT_ENUM_CAST(ARVRServer::RotationMode);
-
-#endif
diff --git a/servers/audio/SCsub b/servers/audio/SCsub
index 3c18c18043..5021e578c3 100644
--- a/servers/audio/SCsub
+++ b/servers/audio/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp
index 69b098edfc..ed67e8902a 100644
--- a/servers/audio/audio_driver_dummy.cpp
+++ b/servers/audio/audio_driver_dummy.cpp
@@ -38,7 +38,7 @@ Error AudioDriverDummy::init() {
active = false;
thread_exited = false;
exit_thread = false;
- samples_in = NULL;
+ samples_in = nullptr;
mix_rate = DEFAULT_MIX_RATE;
speaker_mode = SPEAKER_MODE_STEREO;
@@ -119,12 +119,12 @@ void AudioDriverDummy::finish() {
};
memdelete(thread);
- thread = NULL;
+ thread = nullptr;
};
AudioDriverDummy::AudioDriverDummy() {
- thread = NULL;
+ thread = nullptr;
};
AudioDriverDummy::~AudioDriverDummy(){
diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp
index c0bf4f3a55..2771fc177b 100644
--- a/servers/audio/audio_filter_sw.cpp
+++ b/servers/audio/audio_filter_sw.cpp
@@ -237,7 +237,7 @@ AudioFilterSW::AudioFilterSW() {
AudioFilterSW::Processor::Processor() {
- set_filter(NULL);
+ set_filter(nullptr);
}
void AudioFilterSW::Processor::set_filter(AudioFilterSW *p_filter, bool p_clear_history) {
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp
index 092c3315ee..0ac7ddc7a9 100644
--- a/servers/audio/audio_rb_resampler.cpp
+++ b/servers/audio/audio_rb_resampler.cpp
@@ -203,18 +203,18 @@ void AudioRBResampler::clear() {
//should be stopped at this point but just in case
memdelete_arr(rb);
memdelete_arr(read_buf);
- rb = NULL;
+ rb = nullptr;
offset = 0;
rb_read_pos = 0;
rb_write_pos = 0;
- read_buf = NULL;
+ read_buf = nullptr;
}
AudioRBResampler::AudioRBResampler() {
- rb = NULL;
+ rb = nullptr;
offset = 0;
- read_buf = NULL;
+ read_buf = nullptr;
rb_read_pos = 0;
rb_write_pos = 0;
diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h
index 8cd9714d57..40cf3e4cd7 100644
--- a/servers/audio/audio_rb_resampler.h
+++ b/servers/audio/audio_rb_resampler.h
@@ -69,7 +69,7 @@ public:
}
_FORCE_INLINE_ bool is_ready() const {
- return rb != NULL;
+ return rb != nullptr;
}
_FORCE_INLINE_ int get_total() const {
diff --git a/servers/audio/effects/SCsub b/servers/audio/effects/SCsub
index d730144861..86681f9c74 100644
--- a/servers/audio/effects/SCsub
+++ b/servers/audio/effects/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp
index 56529e208e..a74ac3c007 100644
--- a/servers/audio/effects/audio_effect_pitch_shift.cpp
+++ b/servers/audio/effects/audio_effect_pitch_shift.cpp
@@ -363,4 +363,7 @@ AudioEffectPitchShift::AudioEffectPitchShift() {
pitch_scale = 1.0;
oversampling = 4;
fft_size = FFT_SIZE_2048;
+ wet = 0.0;
+ dry = 0.0;
+ filter = false;
}
diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp
index 8f0c55ad83..f2784679b5 100644
--- a/servers/audio/effects/audio_effect_record.cpp
+++ b/servers/audio/effects/audio_effect_record.cpp
@@ -178,14 +178,14 @@ Ref<AudioEffectInstance> AudioEffectRecord::instance() {
void AudioEffectRecord::ensure_thread_stopped() {
recording_active = false;
- if (current_instance != 0) {
+ if (current_instance != nullptr) {
current_instance->finish();
}
}
void AudioEffectRecord::set_recording_active(bool p_record) {
if (p_record) {
- if (current_instance == 0) {
+ if (current_instance == nullptr) {
WARN_PRINT("Recording should not be set as active before Godot has initialized.");
recording_active = false;
return;
@@ -217,8 +217,8 @@ Ref<AudioStreamSample> AudioEffectRecord::get_recording() const {
Vector<uint8_t> dst_data;
- ERR_FAIL_COND_V(current_instance.is_null(), NULL);
- ERR_FAIL_COND_V(current_instance->recording_data.size() == 0, NULL);
+ ERR_FAIL_COND_V(current_instance.is_null(), nullptr);
+ ERR_FAIL_COND_V(current_instance->recording_data.size() == 0, nullptr);
if (dst_format == AudioStreamSample::FORMAT_8_BITS) {
int data_size = current_instance->recording_data.size();
diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.h b/servers/audio/effects/audio_effect_spectrum_analyzer.h
index 8e735b8b50..a110f7a8e5 100644
--- a/servers/audio/effects/audio_effect_spectrum_analyzer.h
+++ b/servers/audio/effects/audio_effect_spectrum_analyzer.h
@@ -48,7 +48,7 @@ private:
friend class AudioEffectSpectrumAnalyzer;
Ref<AudioEffectSpectrumAnalyzer> base;
- Vector<Vector<AudioFrame> > fft_history;
+ Vector<Vector<AudioFrame>> fft_history;
Vector<float> temporal_fft;
int temporal_fft_pos;
int fft_size;
diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp
index 5f24cf3d6b..d272a2cdf7 100644
--- a/servers/audio/effects/audio_stream_generator.cpp
+++ b/servers/audio/effects/audio_stream_generator.cpp
@@ -205,7 +205,7 @@ void AudioStreamGeneratorPlayback::_bind_methods() {
}
AudioStreamGeneratorPlayback::AudioStreamGeneratorPlayback() {
- generator = NULL;
+ generator = nullptr;
skips = 0;
active = false;
mixed = 0;
diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp
index 9946a5eeef..ea2174f1d4 100644
--- a/servers/audio/effects/reverb.cpp
+++ b/servers/audio/effects/reverb.cpp
@@ -314,7 +314,7 @@ void Reverb::clear_buffers() {
if (comb[i].buffer)
memdelete_arr(comb[i].buffer);
- comb[i].buffer = 0;
+ comb[i].buffer = nullptr;
}
for (int i = 0; i < MAX_ALLPASS; i++) {
@@ -322,7 +322,7 @@ void Reverb::clear_buffers() {
if (allpass[i].buffer)
memdelete_arr(allpass[i].buffer);
- allpass[i].buffer = 0;
+ allpass[i].buffer = nullptr;
}
}
@@ -342,7 +342,7 @@ Reverb::Reverb() {
hpf_h2 = 0;
input_buffer = memnew_arr(float, INPUT_BUFFER_MAX_SIZE);
- echo_buffer = 0;
+ echo_buffer = nullptr;
configure_buffers();
update_parameters();
diff --git a/servers/audio/reverb_sw.cpp b/servers/audio/reverb_sw.cpp
deleted file mode 100644
index 3bf0b0ea96..0000000000
--- a/servers/audio/reverb_sw.cpp
+++ /dev/null
@@ -1,538 +0,0 @@
-/*************************************************************************/
-/* reverb_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "reverb_sw.h"
-
-#include "core/print_string.h"
-
-#include <stdlib.h>
-
-#define SETMIN(x, y) (x) = MIN((x), (y))
-
-#define rangeloop(c, min, max) \
- for ((c) = (min); (c) < (max); (c)++)
-
-#define MULSHIFT_S32(Factor1, Factor2, Bits) \
- ((int)(((int64_t)(Factor1) * (Factor2)) >> (Bits)))
-
-struct ReverbParamsSW {
- unsigned int BufferSize; // Required buffer size
- int gLPF; // Coefficient
- int gEcho0; // Coefficient
- int gEcho1; // Coefficient
- int gEcho2; // Coefficient
- int gEcho3; // Coefficient
- int gWall; // Coefficient
- int gReva; // Coefficient
- int gRevb; // Coefficient
- int gInputL; // Coefficient
- int gInputR; // Coefficient
- unsigned int nRevaOldL; // Offset
- unsigned int nRevaOldR; // Offset
- unsigned int nRevbOldL; // Offset
- unsigned int nRevbOldR; // Offset
- unsigned int nLwlNew; // Offset
- unsigned int nRwrNew; // Offset
- unsigned int nEcho0L; // Offset
- unsigned int nEcho0R; // Offset
- unsigned int nEcho1L; // Offset
- unsigned int nEcho1R; // Offset
- unsigned int nLwlOld; // Offset
- unsigned int nRwrOld; // Offset
- unsigned int nLwrNew; // Offset
- unsigned int nRwlNew; // Offset
- unsigned int nEcho2L; // Offset
- unsigned int nEcho2R; // Offset
- unsigned int nEcho3L; // Offset
- unsigned int nEcho3R; // Offset
- unsigned int nLwrOld; // Offset
- unsigned int nRwlOld; // Offset
- unsigned int nRevaNewL; // Offset
- unsigned int nRevaNewR; // Offset
- unsigned int nRevbNewL; // Offset
- unsigned int nRevbNewR; // Offset
-};
-
-static ReverbParamsSW reverb_params_Room = {
- 0x26C0 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x6D80, 0x54B8, -0x4130, 0x0000, 0x0000, -0x4580,
- //gReva gRevb gInputL gInputR
- 0x5800, 0x5300, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x01B4 - 0x007D, 0x0136 - 0x007D, 0x00B8 - 0x005B, 0x005C - 0x005B,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x04D6, 0x0333, 0x03F0, 0x0227, 0x0374, 0x01EF,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x0334, 0x01B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x0000, 0x0000, 0x01B4, 0x0136, 0x00B8, 0x005C
-};
-
-static ReverbParamsSW reverb_params_StudioSmall = {
- 0x1F40 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x70F0, 0x4FA8, -0x4320, 0x4410, -0x3F10, -0x6400,
- //gReva gRevb gInputL gInputR
- 0x5280, 0x4EC0, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x00B4 - 0x0033, 0x0080 - 0x0033, 0x004C - 0x0025, 0x0026 - 0x0025,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x03E4, 0x031B, 0x03A4, 0x02AF, 0x0372, 0x0266,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x031C, 0x025D, 0x025C, 0x018E, 0x022F, 0x0135, 0x01D2, 0x00B7,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x018F, 0x00B5, 0x00B4, 0x0080, 0x004C, 0x0026
-};
-
-static ReverbParamsSW reverb_params_StudioMedium = {
- 0x4840 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x70F0, 0x4FA8, -0x4320, 0x4510, -0x4110, -0x4B40,
- //gReva gRevb gInputL gInputR
- 0x5280, 0x4EC0, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x0264 - 0x00B1, 0x01B2 - 0x00B1, 0x0100 - 0x007F, 0x0080 - 0x007F,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x0904, 0x076B, 0x0824, 0x065F, 0x07A2, 0x0616,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x076C, 0x05ED, 0x05EC, 0x042E, 0x050F, 0x0305, 0x0462, 0x02B7,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x042F, 0x0265, 0x0264, 0x01B2, 0x0100, 0x0080
-};
-
-static ReverbParamsSW reverb_params_StudioLarge = {
- 0x6FE0 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x6F60, 0x4FA8, -0x4320, 0x4510, -0x4110, -0x5980,
- //gReva gRevb gInputL gInputR
- 0x5680, 0x52C0, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x031C - 0x00E3, 0x0238 - 0x00E3, 0x0154 - 0x00A9, 0x00AA - 0x00A9,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x0DFB, 0x0B58, 0x0D09, 0x0A3C, 0x0BD9, 0x0973,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x0B59, 0x08DA, 0x08D9, 0x05E9, 0x07EC, 0x04B0, 0x06EF, 0x03D2,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x05EA, 0x031D, 0x031C, 0x0238, 0x0154, 0x00AA
-};
-
-static ReverbParamsSW reverb_params_Hall = {
- 0xADE0 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x6000, 0x5000, 0x4C00, -0x4800, -0x4400, -0x4000,
- //gReva gRevb gInputL gInputR
- 0x6000, 0x5C00, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x05C0 - 0x01A5, 0x041A - 0x01A5, 0x0274 - 0x0139, 0x013A - 0x0139,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x15BA, 0x11BB, 0x14C2, 0x10BD, 0x11BC, 0x0DC1,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x11C0, 0x0DC3, 0x0DC0, 0x09C1, 0x0BC4, 0x07C1, 0x0A00, 0x06CD,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x09C2, 0x05C1, 0x05C0, 0x041A, 0x0274, 0x013A
-};
-
-static ReverbParamsSW reverb_params_SpaceEcho = {
- 0xF6C0 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x7E00, 0x5000, -0x4C00, -0x5000, 0x4C00, -0x5000,
- //gReva gRevb gInputL gInputR
- 0x6000, 0x5400, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x0AE0 - 0x033D, 0x07A2 - 0x033D, 0x0464 - 0x0231, 0x0232 - 0x0231,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x1ED6, 0x1A31, 0x1D14, 0x183B, 0x1BC2, 0x16B2,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x1A32, 0x15EF, 0x15EE, 0x1055, 0x1334, 0x0F2D, 0x11F6, 0x0C5D,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x1056, 0x0AE1, 0x0AE0, 0x07A2, 0x0464, 0x0232
-};
-
-static ReverbParamsSW reverb_params_Echo = {
- 0x18040 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, -0x7F00,
- //gReva gRevb gInputL gInputR
- 0x0000, 0x0000, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x1004 - 0x0001, 0x1002 - 0x0001, 0x0004 - 0x0001, 0x0002 - 0x0001,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x1FFF, 0x0FFF, 0x1005, 0x0005, 0x0000, 0x0000,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x1005, 0x0005, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x0000, 0x0000, 0x1004, 0x1002, 0x0004, 0x0002
-};
-
-static ReverbParamsSW reverb_params_Delay = {
- 0x18040 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x0000,
- //gReva gRevb gInputL gInputR
- 0x0000, 0x0000, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x1004 - 0x0001, 0x1002 - 0x0001, 0x0004 - 0x0001, 0x0002 - 0x0001,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x1FFF, 0x0FFF, 0x1005, 0x0005, 0x0000, 0x0000,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x1005, 0x0005, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x0000, 0x0000, 0x1004, 0x1002, 0x0004, 0x0002
-};
-
-static ReverbParamsSW reverb_params_HalfEcho = {
- 0x3C00 / 2,
- //gLPF gEcho0 gEcho1 gEcho2 gEcho3 gWall
- 0x70F0, 0x4FA8, -0x4320, 0x4510, -0x4110, -0x7B00,
- //gReva gRevb gInputL gInputR
- 0x5F80, 0x54C0, -0x8000, -0x8000,
- //nRevaOldL nRevaOldR nRevbOldL nRevbOldR
- 0x0058 - 0x0017, 0x0040 - 0x0017, 0x0028 - 0x0013, 0x0014 - 0x0013,
- //nLwlNew nRwrNew nEcho0L nEcho0R nEcho1L nEcho1R
- 0x0371, 0x02AF, 0x02E5, 0x01DF, 0x02B0, 0x01D7,
- //nLwlOld nRwrOld nLwrNew nRwlNew nEcho2L nEcho2R nEcho3L nEcho3R
- 0x0358, 0x026A, 0x01D6, 0x011E, 0x012D, 0x00B1, 0x011F, 0x0059,
- //nLwrOld nRwlOld nRevaNewL nRevaNewR nRevbNewL nRevbNewR
- 0x01A0, 0x00E3, 0x0058, 0x0040, 0x0028, 0x0014
-};
-
-static ReverbParamsSW *reverb_param_modes[] = {
- &reverb_params_Room,
- &reverb_params_StudioSmall,
- &reverb_params_StudioMedium,
- &reverb_params_StudioLarge,
- &reverb_params_Hall,
- &reverb_params_SpaceEcho,
- &reverb_params_Echo,
- &reverb_params_Delay,
- &reverb_params_HalfEcho,
-};
-
-bool ReverbSW::process(int *p_input, int *p_output, int p_frames, int p_stereo_stride) {
-
- // p_input must point to a non-looping buffer.
- // BOTH p_input and p_output must be touched (use ClearModuleBuffer).
-
- if (!reverb_buffer)
- return false;
-
-// LOCAL MACROS
-#undef LM_SETSRCOFFSET
-#define LM_SETSRCOFFSET(x) \
- (x) = current_params->x + Offset; \
- if ((x) >= reverb_buffer_size) { \
- (x) -= reverb_buffer_size; \
- } \
- SETMIN(aSample, reverb_buffer_size - (x));
-
-/*
-#undef LM_SETSRCOFFSET2
-#define LM_SETSRCOFFSET2(x,y) \
- (x) = ((y) << 3) >> HZShift; \
- (x) += Offset; \
- if ( (x) >= reverb_buffer_size ) { \
- (x) -= reverb_buffer_size; \
- } \
- SETMIN ( aSample, reverb_buffer_size - (x) );
-*/
-#undef LM_SRCADVANCE
-#define LM_SRCADVANCE(x) \
- (x) += aSample;
-
-#undef LM_MUL
-#define LM_MUL(x, y) \
- MULSHIFT_S32(x, current_params->y, 15)
-
-#undef LM_REVERB
-#define LM_REVERB(x) reverb_buffer[(x) + cSample]
-
- // LOCAL VARIABLES
-
- unsigned int Offset;
-
- int lwl, lwr, rwl, rwr;
- //unsigned char HZShift;
-
- // CODE
-
- lwl = state.lwl;
- lwr = state.lwr;
- rwl = state.rwl;
- rwr = state.rwr;
- Offset = state.Offset;
-
- int max = 0;
-
- while (p_frames) {
-
- // Offsets
-
- unsigned int nLwlOld;
- unsigned int nRwrOld;
- unsigned int nLwlNew;
- unsigned int nRwrNew;
-
- unsigned int nLwrOld;
- unsigned int nRwlOld;
- unsigned int nLwrNew;
- unsigned int nRwlNew;
-
- unsigned int nEcho0L;
- unsigned int nEcho1L;
- unsigned int nEcho2L;
- unsigned int nEcho3L;
-
- unsigned int nEcho0R;
- unsigned int nEcho1R;
- unsigned int nEcho2R;
- unsigned int nEcho3R;
-
- unsigned int nRevaOldL;
- unsigned int nRevaOldR;
- unsigned int nRevbOldL;
- unsigned int nRevbOldR;
-
- unsigned int nRevaNewL;
- unsigned int nRevaNewR;
- unsigned int nRevbNewL;
- unsigned int nRevbNewR;
-
- // Other variables
-
- unsigned int aSample = p_frames;
-
- // Set initial offsets
-
- LM_SETSRCOFFSET(nLwlOld);
- LM_SETSRCOFFSET(nRwrOld);
- LM_SETSRCOFFSET(nLwlNew);
- LM_SETSRCOFFSET(nRwrNew);
- LM_SETSRCOFFSET(nLwrOld);
- LM_SETSRCOFFSET(nRwlOld);
- LM_SETSRCOFFSET(nLwrNew);
- LM_SETSRCOFFSET(nRwlNew);
- LM_SETSRCOFFSET(nEcho0L);
- LM_SETSRCOFFSET(nEcho1L);
- LM_SETSRCOFFSET(nEcho2L);
- LM_SETSRCOFFSET(nEcho3L);
- LM_SETSRCOFFSET(nEcho0R);
- LM_SETSRCOFFSET(nEcho1R);
- LM_SETSRCOFFSET(nEcho2R);
- LM_SETSRCOFFSET(nEcho3R);
- LM_SETSRCOFFSET(nRevaOldL);
- LM_SETSRCOFFSET(nRevaOldR);
- LM_SETSRCOFFSET(nRevbOldL);
- LM_SETSRCOFFSET(nRevbOldR);
- LM_SETSRCOFFSET(nRevaNewL);
- LM_SETSRCOFFSET(nRevaNewR);
- LM_SETSRCOFFSET(nRevbNewL);
- LM_SETSRCOFFSET(nRevbNewR);
-
- //SETMIN ( aSample, p_output.Size - p_output.Offset );
-
- for (unsigned int cSample = 0; cSample < aSample; cSample++) {
-
- int tempL0, tempL1, tempR0, tempR1;
-
- tempL1 = p_input[(cSample << p_stereo_stride)] >> 8;
- tempR1 = p_input[(cSample << p_stereo_stride) + 1] >> 8;
-
- tempL0 = LM_MUL(tempL1, gInputL);
- tempR0 = LM_MUL(tempR1, gInputR);
-
- /*
- Left -> Wall -> Left Reflection
- */
- tempL1 = tempL0 + LM_MUL(LM_REVERB(nLwlOld), gWall);
- tempR1 = tempR0 + LM_MUL(LM_REVERB(nRwrOld), gWall);
- lwl += LM_MUL(tempL1 - lwl, gLPF);
- rwr += LM_MUL(tempR1 - rwr, gLPF);
- LM_REVERB(nLwlNew) = lwl;
- LM_REVERB(nRwrNew) = rwr;
- /*
- Left -> Wall -> Right Reflection
- */
- tempL1 = tempL0 + LM_MUL(LM_REVERB(nRwlOld), gWall);
- tempR1 = tempR0 + LM_MUL(LM_REVERB(nLwrOld), gWall);
- lwr += LM_MUL(tempL1 - lwr, gLPF);
- rwl += LM_MUL(tempR1 - rwl, gLPF);
- LM_REVERB(nLwrNew) = lwr;
- LM_REVERB(nRwlNew) = rwl;
- /*
- Early Echo(Early Reflection)
- */
- tempL0 =
- LM_MUL(LM_REVERB(nEcho0L), gEcho0) +
- LM_MUL(LM_REVERB(nEcho1L), gEcho1) +
- LM_MUL(LM_REVERB(nEcho2L), gEcho2) +
- LM_MUL(LM_REVERB(nEcho3L), gEcho3);
- tempR0 =
- LM_MUL(LM_REVERB(nEcho0R), gEcho0) +
- LM_MUL(LM_REVERB(nEcho1R), gEcho1) +
- LM_MUL(LM_REVERB(nEcho2R), gEcho2) +
- LM_MUL(LM_REVERB(nEcho3R), gEcho3);
- /*
- Late Reverb
- */
- tempL1 = LM_REVERB(nRevaOldL);
- tempR1 = LM_REVERB(nRevaOldR);
- tempL0 -= LM_MUL(tempL1, gReva);
- tempR0 -= LM_MUL(tempR1, gReva);
- LM_REVERB(nRevaNewL) = tempL0;
- LM_REVERB(nRevaNewR) = tempR0;
- tempL0 = LM_MUL(tempL0, gReva) + tempL1;
- tempR0 = LM_MUL(tempR0, gReva) + tempR1;
- tempL1 = LM_REVERB(nRevbOldL);
- tempR1 = LM_REVERB(nRevbOldR);
- tempL0 -= LM_MUL(tempL1, gRevb);
- tempR0 -= LM_MUL(tempR1, gRevb);
- LM_REVERB(nRevbNewL) = tempL0;
- LM_REVERB(nRevbNewR) = tempR0;
- tempL0 = LM_MUL(tempL0, gRevb) + tempL1;
- tempR0 = LM_MUL(tempR0, gRevb) + tempR1;
- /*
- Output
- */
-
- max |= abs(tempL0);
- max |= abs(tempR0);
-
- p_output[(cSample << p_stereo_stride)] += tempL0 << 8;
- p_output[(cSample << p_stereo_stride) + 1] += tempR0 << 8;
- }
-
- // Advance offsets
-
- Offset += aSample;
- if (Offset >= reverb_buffer_size) {
- Offset -= reverb_buffer_size;
- }
-
- p_input += aSample << p_stereo_stride;
- p_output += aSample << p_stereo_stride;
-
- p_frames -= aSample;
- }
-
- state.lwl = lwl;
- state.lwr = lwr;
- state.rwl = rwl;
- state.rwr = rwr;
- state.Offset = Offset;
-
- return (max & 0x7FFFFF00) != 0; // audio was mixed?
-}
-
-void ReverbSW::adjust_current_params() {
-
- *current_params = *reverb_param_modes[mode];
-
- uint32_t maxofs = 0;
-
-#define LM_CONFIG_PARAM(x) \
- current_params->x = (int)(((int64_t)current_params->x * (int64_t)mix_rate * 8L) / (int64_t)44100); \
- if (current_params->x > maxofs) \
- maxofs = current_params->x;
-
- LM_CONFIG_PARAM(nLwlOld);
- LM_CONFIG_PARAM(nRwrOld);
- LM_CONFIG_PARAM(nLwlNew);
- LM_CONFIG_PARAM(nRwrNew);
- LM_CONFIG_PARAM(nLwrOld);
- LM_CONFIG_PARAM(nRwlOld);
- LM_CONFIG_PARAM(nLwrNew);
- LM_CONFIG_PARAM(nRwlNew);
- LM_CONFIG_PARAM(nEcho0L);
- LM_CONFIG_PARAM(nEcho1L);
- LM_CONFIG_PARAM(nEcho2L);
- LM_CONFIG_PARAM(nEcho3L);
- LM_CONFIG_PARAM(nEcho0R);
- LM_CONFIG_PARAM(nEcho1R);
- LM_CONFIG_PARAM(nEcho2R);
- LM_CONFIG_PARAM(nEcho3R);
- LM_CONFIG_PARAM(nRevaOldL);
- LM_CONFIG_PARAM(nRevaOldR);
- LM_CONFIG_PARAM(nRevbOldL);
- LM_CONFIG_PARAM(nRevbOldR);
- LM_CONFIG_PARAM(nRevaNewL);
- LM_CONFIG_PARAM(nRevaNewR);
- LM_CONFIG_PARAM(nRevbNewL);
- LM_CONFIG_PARAM(nRevbNewR);
-
- int needed_buffer_size = maxofs + 1;
- if (reverb_buffer)
- memdelete_arr(reverb_buffer);
-
- reverb_buffer = memnew_arr(int, needed_buffer_size);
- reverb_buffer_size = needed_buffer_size;
-
- for (uint32_t i = 0; i < reverb_buffer_size; i++)
- reverb_buffer[i] = 0;
-
- state.reset();
-}
-
-void ReverbSW::set_mode(ReverbMode p_mode) {
-
- if (mode == p_mode)
- return;
-
- mode = p_mode;
-
- adjust_current_params();
-}
-
-void ReverbSW::set_mix_rate(int p_mix_rate) {
-
- if (p_mix_rate == mix_rate)
- return;
-
- mix_rate = p_mix_rate;
-
- adjust_current_params();
-}
-
-ReverbSW::ReverbSW() {
-
- reverb_buffer = 0;
- reverb_buffer_size = 0;
- mode = REVERB_MODE_ROOM;
- mix_rate = 1;
- current_params = memnew(ReverbParamsSW);
-}
-
-ReverbSW::~ReverbSW() {
-
- if (reverb_buffer)
- memdelete_arr(reverb_buffer);
-
- memdelete(current_params);
-}
diff --git a/servers/audio/reverb_sw.h b/servers/audio/reverb_sw.h
deleted file mode 100644
index 13c63e602a..0000000000
--- a/servers/audio/reverb_sw.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*************************************************************************/
-/* reverb_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 REVERB_SW_H
-#define REVERB_SW_H
-
-#include "core/os/memory.h"
-#include "core/typedefs.h"
-
-struct ReverbParamsSW;
-
-class ReverbSW {
-public:
- enum ReverbMode {
- REVERB_MODE_ROOM,
- REVERB_MODE_STUDIO_SMALL,
- REVERB_MODE_STUDIO_MEDIUM,
- REVERB_MODE_STUDIO_LARGE,
- REVERB_MODE_HALL,
- REVERB_MODE_SPACE_ECHO,
- REVERB_MODE_ECHO,
- REVERB_MODE_DELAY,
- REVERB_MODE_HALF_ECHO
- };
-
-private:
- struct State {
- int lwl;
- int lwr;
- int rwl;
- int rwr;
- unsigned int Offset;
- void reset() {
- lwl = 0;
- lwr = 0;
- rwl = 0;
- rwr = 0;
- Offset = 0;
- }
- State() { reset(); }
- } state;
-
- ReverbParamsSW *current_params;
-
- int *reverb_buffer;
- unsigned int reverb_buffer_size;
- ReverbMode mode;
- int mix_rate;
-
- void adjust_current_params();
-
-public:
- void set_mode(ReverbMode p_mode);
- bool process(int *p_input, int *p_output, int p_frames, int p_stereo_stride = 1); // return tru if audio was created
- void set_mix_rate(int p_mix_rate);
-
- ReverbSW();
- ~ReverbSW();
-};
-
-#endif
diff --git a/servers/audio/voice_rb_sw.h b/servers/audio/voice_rb_sw.h
deleted file mode 100644
index c51076035c..0000000000
--- a/servers/audio/voice_rb_sw.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*************************************************************************/
-/* voice_rb_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VOICE_RB_SW_H
-#define VOICE_RB_SW_H
-
-#include "core/os/os.h"
-#include "servers/audio_server.h"
-class VoiceRBSW {
-public:
- enum {
- VOICE_RB_SIZE = 1024
- };
-
- struct Command {
-
- enum Type {
- CMD_NONE,
- CMD_PLAY,
- CMD_STOP,
- CMD_SET_VOLUME,
- CMD_SET_PAN,
- CMD_SET_FILTER,
- CMD_SET_CHORUS,
- CMD_SET_REVERB,
- CMD_SET_MIX_RATE,
- CMD_SET_POSITIONAL,
- CMD_CHANGE_ALL_FX_VOLUMES
- };
-
- Type type;
- RID voice;
-
- struct {
-
- RID sample;
-
- } play;
-
- union {
-
- struct {
-
- float volume;
- } volume;
-
- struct {
-
- float pan, depth, height;
- } pan;
-
- struct {
-
- AS::FilterType type;
- float cutoff;
- float resonance;
- float gain;
- } filter;
-
- struct {
- float send;
- } chorus;
- struct {
- float send;
- AS::ReverbRoomType room;
- } reverb;
-
- struct {
-
- int mix_rate;
- } mix_rate;
-
- struct {
-
- bool positional;
- } positional;
- };
-
- Command() { type = CMD_NONE; }
- };
-
-private:
- Command voice_cmd_rb[VOICE_RB_SIZE];
- volatile int read_pos;
- volatile int write_pos;
-
-public:
- _FORCE_INLINE_ bool commands_left() const { return read_pos != write_pos; }
- _FORCE_INLINE_ Command pop_command() {
- ERR_FAIL_COND_V(read_pos == write_pos, Command());
- Command cmd = voice_cmd_rb[read_pos];
- read_pos = (read_pos + 1) % VOICE_RB_SIZE;
- return cmd;
- }
- _FORCE_INLINE_ void push_command(const Command &p_command) {
-
- bool full = ((write_pos + 1) % VOICE_RB_SIZE) == read_pos;
- if (full) {
-#ifdef DEBUG_ENABLED
- if (OS::get_singleton()->is_stdout_verbose()) {
- ERR_FAIL_COND_MSG(((write_pos + 1) % VOICE_RB_SIZE) == read_pos, "Audio ring buffer full (too many commands).");
- }
-#endif
- return;
- }
-
- voice_cmd_rb[write_pos] = p_command;
- write_pos = (write_pos + 1) % VOICE_RB_SIZE;
- }
-
- VoiceRBSW() { read_pos = write_pos = 0; }
-};
-
-#endif // VOICE_RB_SW_H
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 0e68c8a543..90033d4a87 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -45,7 +45,7 @@
#define MARK_EDITED
#endif
-AudioDriver *AudioDriver::singleton = NULL;
+AudioDriver *AudioDriver::singleton = nullptr;
AudioDriver *AudioDriver::get_singleton() {
return singleton;
@@ -215,7 +215,7 @@ void AudioDriverManager::initialize(int p_driver) {
AudioDriver *AudioDriverManager::get_driver(int p_driver) {
- ERR_FAIL_INDEX_V(p_driver, driver_count, NULL);
+ ERR_FAIL_INDEX_V(p_driver, driver_count, nullptr);
return drivers[p_driver];
}
@@ -322,7 +322,7 @@ void AudioServer::_mix_step() {
bus->soloed = true;
} else {
- bus = NULL;
+ bus = nullptr;
}
} while (bus);
@@ -388,7 +388,7 @@ void AudioServer::_mix_step() {
//process send
- Bus *send = NULL;
+ Bus *send = nullptr;
if (i > 0) {
//everything has a send save for master bus
@@ -476,8 +476,8 @@ bool AudioServer::thread_has_channel_mix_buffer(int p_bus, int p_buffer) const {
AudioFrame *AudioServer::thread_get_channel_mix_buffer(int p_bus, int p_buffer) {
- ERR_FAIL_INDEX_V(p_bus, buses.size(), NULL);
- ERR_FAIL_INDEX_V(p_buffer, buses[p_bus]->channels.size(), NULL);
+ ERR_FAIL_INDEX_V(p_bus, buses.size(), nullptr);
+ ERR_FAIL_INDEX_V(p_buffer, buses[p_bus]->channels.size(), nullptr);
AudioFrame *data = buses.write[p_bus]->channels.write[p_buffer].buffer.ptrw();
@@ -1129,48 +1129,7 @@ double AudioServer::get_time_since_last_mix() const {
return AudioDriver::get_singleton()->get_time_since_last_mix();
}
-AudioServer *AudioServer::singleton = NULL;
-
-void *AudioServer::audio_data_alloc(uint32_t p_data_len, const uint8_t *p_from_data) {
-
- void *ad = memalloc(p_data_len);
- ERR_FAIL_COND_V(!ad, NULL);
- if (p_from_data) {
- copymem(ad, p_from_data, p_data_len);
- }
-
- {
- MutexLock lock(audio_data_lock);
-
- audio_data[ad] = p_data_len;
- audio_data_total_mem += p_data_len;
- audio_data_max_mem = MAX(audio_data_total_mem, audio_data_max_mem);
- }
-
- return ad;
-}
-
-void AudioServer::audio_data_free(void *p_data) {
-
- MutexLock lock(audio_data_lock);
-
- if (!audio_data.has(p_data)) {
- ERR_FAIL();
- }
-
- audio_data_total_mem -= audio_data[p_data];
- audio_data.erase(p_data);
- memfree(p_data);
-}
-
-size_t AudioServer::audio_data_get_total_memory_usage() const {
-
- return audio_data_total_mem;
-}
-size_t AudioServer::audio_data_get_max_memory_usage() const {
-
- return audio_data_max_mem;
-}
+AudioServer *AudioServer::singleton = nullptr;
void AudioServer::add_callback(AudioCallback p_callback, void *p_userdata) {
lock();
@@ -1400,8 +1359,6 @@ void AudioServer::_bind_methods() {
AudioServer::AudioServer() {
singleton = this;
- audio_data_total_mem = 0;
- audio_data_max_mem = 0;
mix_frames = 0;
channel_count = 0;
to_mix = 0;
@@ -1415,7 +1372,7 @@ AudioServer::AudioServer() {
AudioServer::~AudioServer() {
- singleton = NULL;
+ singleton = nullptr;
}
/////////////////////////////////
diff --git a/servers/audio_server.h b/servers/audio_server.h
index cc0c9d1112..a1a3dde719 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -198,7 +198,7 @@ private:
bool active;
AudioFrame peak_volume;
Vector<AudioFrame> buffer;
- Vector<Ref<AudioEffectInstance> > effect_instances;
+ Vector<Ref<AudioEffectInstance>> effect_instances;
uint64_t last_mix_with_audio;
Channel() {
last_mix_with_audio = 0;
@@ -224,7 +224,7 @@ private:
int index_cache;
};
- Vector<Vector<AudioFrame> > temp_buffer; //temp_buffer for each level
+ Vector<Vector<AudioFrame>> temp_buffer; //temp_buffer for each level
Vector<Bus *> buses;
Map<StringName, Bus *> bus_map;
@@ -232,14 +232,6 @@ private:
static AudioServer *singleton;
- // TODO create an audiodata pool to optimize memory
-
- Map<void *, uint32_t> audio_data;
- size_t audio_data_total_mem;
- size_t audio_data_max_mem;
-
- Mutex audio_data_lock;
-
void init_channels_and_buffers();
void _mix_step();
@@ -350,12 +342,6 @@ public:
virtual double get_time_to_next_mix() const;
virtual double get_time_since_last_mix() const;
- void *audio_data_alloc(uint32_t p_data_len, const uint8_t *p_from_data = NULL);
- void audio_data_free(void *p_data);
-
- size_t audio_data_get_total_memory_usage() const;
- size_t audio_data_get_max_memory_usage() const;
-
void add_callback(AudioCallback p_callback, void *p_userdata);
void remove_callback(AudioCallback p_callback, void *p_userdata);
diff --git a/servers/camera/SCsub b/servers/camera/SCsub
index ccc76e823f..c949f3bb25 100644
--- a/servers/camera/SCsub
+++ b/servers/camera/SCsub
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
-Export('env')
+Export("env")
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index e8537950ec..41f44abae8 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -30,7 +30,7 @@
#include "camera_feed.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
void CameraFeed::_bind_methods() {
// FIXME: Disabled during Vulkan refactoring, should be ported.
@@ -148,7 +148,7 @@ CameraFeed::CameraFeed() {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
// create a texture object
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
texture[CameraServer::FEED_Y_IMAGE] = vs->texture_create(); // also used for RGBA
texture[CameraServer::FEED_CBCR_IMAGE] = vs->texture_create();
#endif
@@ -168,7 +168,7 @@ CameraFeed::CameraFeed(String p_name, FeedPosition p_position) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
// create a texture object
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
texture[CameraServer::FEED_Y_IMAGE] = vs->texture_create(); // also used for RGBA
texture[CameraServer::FEED_CBCR_IMAGE] = vs->texture_create();
#endif
@@ -178,7 +178,7 @@ CameraFeed::~CameraFeed() {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
// Free our textures
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
vs->free(texture[CameraServer::FEED_Y_IMAGE]);
vs->free(texture[CameraServer::FEED_CBCR_IMAGE]);
#endif
@@ -188,7 +188,7 @@ void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
if (active) {
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
int new_width = p_rgb_img->get_width();
int new_height = p_rgb_img->get_height();
@@ -198,7 +198,7 @@ void CameraFeed::set_RGB_img(Ref<Image> p_rgb_img) {
base_width = new_width;
base_height = new_height;
- vs->texture_allocate(texture[CameraServer::FEED_RGBA_IMAGE], new_width, new_height, 0, Image::FORMAT_RGB8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAGS_DEFAULT);
+ vs->texture_allocate(texture[CameraServer::FEED_RGBA_IMAGE], new_width, new_height, 0, Image::FORMAT_RGB8, RS::TEXTURE_TYPE_2D, RS::TEXTURE_FLAGS_DEFAULT);
}
vs->texture_set_data(texture[CameraServer::FEED_RGBA_IMAGE], p_rgb_img);
@@ -211,7 +211,7 @@ void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
if (active) {
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
int new_width = p_ycbcr_img->get_width();
int new_height = p_ycbcr_img->get_height();
@@ -221,7 +221,7 @@ void CameraFeed::set_YCbCr_img(Ref<Image> p_ycbcr_img) {
base_width = new_width;
base_height = new_height;
- vs->texture_allocate(texture[CameraServer::FEED_RGBA_IMAGE], new_width, new_height, 0, Image::FORMAT_RGB8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAGS_DEFAULT);
+ vs->texture_allocate(texture[CameraServer::FEED_RGBA_IMAGE], new_width, new_height, 0, Image::FORMAT_RGB8, RS::TEXTURE_TYPE_2D, RS::TEXTURE_FLAGS_DEFAULT);
}
vs->texture_set_data(texture[CameraServer::FEED_RGBA_IMAGE], p_ycbcr_img);
@@ -234,7 +234,7 @@ void CameraFeed::set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
if (active) {
- VisualServer *vs = VisualServer::get_singleton();
+ RenderingServer *vs = RenderingServer::get_singleton();
///@TODO investigate whether we can use thirdparty/misc/yuv2rgb.h here to convert our YUV data to RGB, our shader approach is potentially faster though..
// Wondering about including that into multiple projects, may cause issues.
@@ -250,10 +250,10 @@ void CameraFeed::set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img) {
base_width = new_y_width;
base_height = new_y_height;
- vs->texture_allocate(texture[CameraServer::FEED_Y_IMAGE], new_y_width, new_y_height, 0, Image::FORMAT_R8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_USED_FOR_STREAMING);
+ vs->texture_allocate(texture[CameraServer::FEED_Y_IMAGE], new_y_width, new_y_height, 0, Image::FORMAT_R8, RS::TEXTURE_TYPE_2D, RS::TEXTURE_FLAG_USED_FOR_STREAMING);
///@TODO GLES2 doesn't support FORMAT_RG8, need to do some form of conversion
- vs->texture_allocate(texture[CameraServer::FEED_CBCR_IMAGE], new_cbcr_width, new_cbcr_height, 0, Image::FORMAT_RG8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_USED_FOR_STREAMING);
+ vs->texture_allocate(texture[CameraServer::FEED_CBCR_IMAGE], new_cbcr_width, new_cbcr_height, 0, Image::FORMAT_RG8, RS::TEXTURE_TYPE_2D, RS::TEXTURE_FLAG_USED_FOR_STREAMING);
}
vs->texture_set_data(texture[CameraServer::FEED_Y_IMAGE], p_y_img);
@@ -265,15 +265,15 @@ void CameraFeed::set_YCbCr_imgs(Ref<Image> p_y_img, Ref<Image> p_cbcr_img) {
// FIXME: Disabled during Vulkan refactoring, should be ported.
#if 0
-void CameraFeed::allocate_texture(int p_width, int p_height, Image::Format p_format, VisualServer::TextureType p_texture_type, FeedDataType p_data_type) {
- VisualServer *vs = VisualServer::get_singleton();
+void CameraFeed::allocate_texture(int p_width, int p_height, Image::Format p_format, RenderingServer::TextureType p_texture_type, FeedDataType p_data_type) {
+ RenderingServer *vs = RenderingServer::get_singleton();
if ((base_width != p_width) || (base_height != p_height)) {
// We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
base_width = p_width;
base_height = p_height;
- vs->texture_allocate(texture[0], p_width, p_height, 0, p_format, p_texture_type, VS::TEXTURE_FLAGS_DEFAULT);
+ vs->texture_allocate(texture[0], p_width, p_height, 0, p_format, p_texture_type, RS::TEXTURE_FLAGS_DEFAULT);
}
datatype = p_data_type;
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index b99ded68e4..52a737cd8d 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -34,7 +34,7 @@
#include "core/image.h"
#include "core/math/transform_2d.h"
#include "servers/camera_server.h"
-#include "servers/visual_server.h"
+#include "servers/rendering_server.h"
/**
@author Bastiaan Olij <mux213@gmail.com>
@@ -105,7 +105,7 @@ public:
void set_YCbCr_imgs(Ref<Image> p_y_img, 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, VisualServer::TextureType p_texture_type, FeedDataType p_data_type);
+ void allocate_texture(int p_width, int p_height, Image::Format p_format, RenderingServer::TextureType p_texture_type, FeedDataType p_data_type);
#endif
virtual bool activate_feed();
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index fd88d15e58..3caea6b7c3 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -29,13 +29,13 @@
/*************************************************************************/
#include "camera_server.h"
+#include "rendering_server.h"
#include "servers/camera/camera_feed.h"
-#include "visual_server.h"
////////////////////////////////////////////////////////
// CameraServer
-CameraServer::CreateFunc CameraServer::create_func = NULL;
+CameraServer::CreateFunc CameraServer::create_func = nullptr;
void CameraServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_feed", "index"), &CameraServer::get_feed);
@@ -54,7 +54,7 @@ void CameraServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEED_CBCR_IMAGE);
};
-CameraServer *CameraServer::singleton = NULL;
+CameraServer *CameraServer::singleton = nullptr;
CameraServer *CameraServer::get_singleton() {
return singleton;
@@ -92,7 +92,7 @@ Ref<CameraFeed> CameraServer::get_feed_by_id(int p_id) {
int index = get_feed_index(p_id);
if (index == -1) {
- return NULL;
+ return nullptr;
} else {
return feeds[index];
}
@@ -132,7 +132,7 @@ void CameraServer::remove_feed(const Ref<CameraFeed> &p_feed) {
};
Ref<CameraFeed> CameraServer::get_feed(int p_index) {
- ERR_FAIL_INDEX_V(p_index, feeds.size(), NULL);
+ ERR_FAIL_INDEX_V(p_index, feeds.size(), nullptr);
return feeds[p_index];
};
@@ -167,5 +167,5 @@ CameraServer::CameraServer() {
};
CameraServer::~CameraServer() {
- singleton = NULL;
+ singleton = nullptr;
};
diff --git a/servers/camera_server.h b/servers/camera_server.h
index c4b3d9f5c9..b268553fe5 100644
--- a/servers/camera_server.h
+++ b/servers/camera_server.h
@@ -65,7 +65,7 @@ private:
protected:
static CreateFunc create_func;
- Vector<Ref<CameraFeed> > feeds;
+ Vector<Ref<CameraFeed>> feeds;
static CameraServer *singleton;
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
new file mode 100644
index 0000000000..da1a68a179
--- /dev/null
+++ b/servers/display_server.cpp
@@ -0,0 +1,593 @@
+/*************************************************************************/
+/* display_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "display_server.h"
+
+#include "core/input/input_filter.h"
+#include "scene/resources/texture.h"
+
+DisplayServer *DisplayServer::singleton = nullptr;
+DisplayServer::SwitchVSyncCallbackInThread DisplayServer::switch_vsync_function = nullptr;
+
+bool DisplayServer::hidpi_allowed = false;
+
+DisplayServer::DisplayServerCreate DisplayServer::server_create_functions[DisplayServer::MAX_SERVERS];
+int DisplayServer::server_create_count = 0;
+
+void DisplayServer::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_add_separator(const String &p_menu_root) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+bool DisplayServer::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return false;
+}
+
+bool DisplayServer::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return false;
+}
+
+Callable DisplayServer::global_menu_get_item_callback(const String &p_menu_root, int p_idx) {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return Callable();
+}
+
+Variant DisplayServer::global_menu_get_item_tag(const String &p_menu_root, int p_idx) {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return Variant();
+}
+
+String DisplayServer::global_menu_get_item_text(const String &p_menu_root, int p_idx) {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return String();
+}
+
+String DisplayServer::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return String();
+}
+
+void DisplayServer::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+int DisplayServer::global_menu_get_item_count(const String &p_menu_root) const {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return 0;
+}
+
+void DisplayServer::global_menu_remove_item(const String &p_menu_root, int p_idx) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::global_menu_clear(const String &p_menu_root) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::mouse_set_mode(MouseMode p_mode) {
+ WARN_PRINT("Mouse is not supported by this display server.");
+}
+DisplayServer::MouseMode DisplayServer::mouse_get_mode() const {
+ return MOUSE_MODE_VISIBLE;
+}
+
+void DisplayServer::mouse_warp_to_position(const Point2i &p_to) {
+ WARN_PRINT("Mouse warping is not supported by this display server.");
+}
+Point2i DisplayServer::mouse_get_absolute_position() const {
+ ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server.");
+}
+Point2i DisplayServer::mouse_get_position() const {
+ ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server.");
+}
+int DisplayServer::mouse_get_button_state() const {
+ ERR_FAIL_V_MSG(0, "Mouse is not supported by this display server.");
+}
+
+void DisplayServer::clipboard_set(const String &p_text) {
+ WARN_PRINT("Clipboard is not supported by this display server.");
+}
+String DisplayServer::clipboard_get() const {
+ ERR_FAIL_V_MSG(String(), "Clipboard is not supported by this display server.");
+}
+
+void DisplayServer::screen_set_orientation(ScreenOrientation p_orientation, int p_screen) {
+ WARN_PRINT("Orientation not supported by this display server.");
+}
+DisplayServer::ScreenOrientation DisplayServer::screen_get_orientation(int p_screen) const {
+ return SCREEN_LANDSCAPE;
+}
+
+float DisplayServer::screen_get_scale(int p_screen) const {
+ return 1.0f;
+};
+
+bool DisplayServer::screen_is_touchscreen(int p_screen) const {
+ //return false;
+ return InputFilter::get_singleton() && InputFilter::get_singleton()->is_emulating_touch_from_mouse();
+}
+
+void DisplayServer::screen_set_keep_on(bool p_enable) {
+ WARN_PRINT("Keeping screen on not supported by this display server.");
+}
+bool DisplayServer::screen_is_kept_on() const {
+ return false;
+}
+
+DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &) {
+ ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
+}
+void DisplayServer::delete_sub_window(WindowID p_id) {
+ ERR_FAIL_MSG("Sub-windows not supported by this display server.");
+}
+
+void DisplayServer::window_set_ime_active(const bool p_active, WindowID p_window) {
+ WARN_PRINT("IME not supported by this display server.");
+}
+void DisplayServer::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
+ WARN_PRINT("IME not supported by this display server.");
+}
+
+Point2i DisplayServer::ime_get_selection() const {
+ ERR_FAIL_V_MSG(Point2i(), "IME or NOTIFICATION_WM_IME_UPDATE not supported by this display server.");
+}
+String DisplayServer::ime_get_text() const {
+ ERR_FAIL_V_MSG(String(), "IME or NOTIFICATION_WM_IME_UPDATEnot supported by this display server.");
+}
+
+void DisplayServer::console_set_visible(bool p_enabled) {
+ WARN_PRINT("Console window not supported by this display server.");
+}
+bool DisplayServer::is_console_visible() const {
+ return false;
+}
+
+void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_legth) {
+ WARN_PRINT("Virtual keyboard not supported by this display server.");
+}
+void DisplayServer::virtual_keyboard_hide() {
+ WARN_PRINT("Virtual keyboard not supported by this display server.");
+}
+
+// returns height of the currently shown keyboard (0 if keyboard is hidden)
+int DisplayServer::virtual_keyboard_get_height() const {
+ ERR_FAIL_V_MSG(0, "Virtual keyboad not supported by this display server.");
+}
+
+void DisplayServer::cursor_set_shape(CursorShape p_shape) {
+ WARN_PRINT("Cursor shape not supported by this display server.");
+}
+DisplayServer::CursorShape DisplayServer::cursor_get_shape() const {
+ return CURSOR_ARROW;
+}
+void DisplayServer::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+ WARN_PRINT("Custom cursor shape not supported by this display server.");
+}
+
+bool DisplayServer::get_swap_ok_cancel() {
+ return false;
+}
+
+void DisplayServer::enable_for_stealing_focus(OS::ProcessID pid) {
+}
+
+//plays video natively, in fullscreen, only implemented in mobile for now, likely not possible to implement on linux also.
+Error DisplayServer::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen) {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Native video not supported by this display server.");
+}
+bool DisplayServer::native_video_is_playing() const {
+ return false;
+}
+void DisplayServer::native_video_pause() {
+ WARN_PRINT("Native video not supported by this display server.");
+}
+void DisplayServer::native_video_unpause() {
+ WARN_PRINT("Native video not supported by this display server.");
+}
+void DisplayServer::native_video_stop() {
+ WARN_PRINT("Native video not supported by this display server.");
+}
+
+Error DisplayServer::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
+ WARN_PRINT("Native dialogs not supported by this display server.");
+ return OK;
+}
+Error DisplayServer::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
+ WARN_PRINT("Native dialogs not supported by this display server.");
+ return OK;
+}
+
+DisplayServer::LatinKeyboardVariant DisplayServer::get_latin_keyboard_variant() const {
+ return LATIN_KEYBOARD_QWERTY;
+}
+
+void DisplayServer::force_process_and_drop_events() {
+}
+
+void DisplayServer::release_rendering_thread() {
+ WARN_PRINT("Rendering thread not supported by this display server.");
+}
+void DisplayServer::make_rendering_thread() {
+ WARN_PRINT("Rendering thread not supported by this display server.");
+}
+void DisplayServer::swap_buffers() {
+ WARN_PRINT("Swap buffers not supported by this display server.");
+}
+
+void DisplayServer::set_native_icon(const String &p_filename) {
+ WARN_PRINT("Native icon not supported by this display server.");
+}
+void DisplayServer::set_icon(const Ref<Image> &p_icon) {
+ WARN_PRINT("Icon not supported by this display server.");
+}
+
+void DisplayServer::_set_use_vsync(bool p_enable) {
+ WARN_PRINT("VSync not supported by this display server.");
+}
+void DisplayServer::vsync_set_enabled(bool p_enable) {
+ vsync_enabled = p_enable;
+ if (switch_vsync_function) { //if a function was set, use function
+ switch_vsync_function(p_enable);
+ } else { //otherwise just call here
+ _set_use_vsync(p_enable);
+ }
+}
+bool DisplayServer::vsync_is_enabled() const {
+ return vsync_enabled;
+}
+
+void DisplayServer::vsync_set_use_via_compositor(bool p_enable) {
+ WARN_PRINT("VSync via compositor not supported by this display server.");
+}
+bool DisplayServer::vsync_is_using_via_compositor() const {
+ return false;
+}
+
+void DisplayServer::set_context(Context p_context) {
+}
+
+void DisplayServer::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("has_feature", "feature"), &DisplayServer::has_feature);
+ ClassDB::bind_method(D_METHOD("get_name"), &DisplayServer::get_name);
+
+ ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu_root", "label", "callback", "tag"), &DisplayServer::global_menu_add_item, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("global_menu_add_check_item", "menu_root", "label", "callback", "tag"), &DisplayServer::global_menu_add_check_item, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("global_menu_add_submenu_item", "menu_root", "label", "submenu"), &DisplayServer::global_menu_add_submenu_item);
+ ClassDB::bind_method(D_METHOD("global_menu_add_separator", "menu_root"), &DisplayServer::global_menu_add_separator);
+
+ ClassDB::bind_method(D_METHOD("global_menu_is_item_checked", "menu_root", "idx"), &DisplayServer::global_menu_is_item_checked);
+ ClassDB::bind_method(D_METHOD("global_menu_is_item_checkable", "menu_root", "idx"), &DisplayServer::global_menu_is_item_checkable);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_callback", "menu_root", "idx"), &DisplayServer::global_menu_get_item_callback);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_tag", "menu_root", "idx"), &DisplayServer::global_menu_get_item_tag);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_text", "menu_root", "idx"), &DisplayServer::global_menu_get_item_text);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_submenu", "menu_root", "idx"), &DisplayServer::global_menu_get_item_submenu);
+
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_checked", "menu_root", "idx", "checked"), &DisplayServer::global_menu_set_item_checked);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_checkable", "menu_root", "idx", "checkable"), &DisplayServer::global_menu_set_item_checkable);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_callback", "menu_root", "idx", "callback"), &DisplayServer::global_menu_set_item_callback);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_tag", "menu_root", "idx", "tag"), &DisplayServer::global_menu_set_item_tag);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_text", "menu_root", "idx", "text"), &DisplayServer::global_menu_set_item_text);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_submenu", "menu_root", "idx", "submenu"), &DisplayServer::global_menu_set_item_submenu);
+
+ ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu_root", "idx"), &DisplayServer::global_menu_remove_item);
+ ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear);
+
+ ClassDB::bind_method(D_METHOD("alert", "text", "title"), &DisplayServer::alert, DEFVAL("Alert!"));
+
+ ClassDB::bind_method(D_METHOD("mouse_set_mode", "mouse_mode"), &DisplayServer::mouse_set_mode);
+ ClassDB::bind_method(D_METHOD("mouse_get_mode"), &DisplayServer::mouse_get_mode);
+
+ ClassDB::bind_method(D_METHOD("mouse_warp_to_position", "position"), &DisplayServer::mouse_warp_to_position);
+ ClassDB::bind_method(D_METHOD("mouse_get_position"), &DisplayServer::mouse_get_position);
+ ClassDB::bind_method(D_METHOD("mouse_get_absolute_position"), &DisplayServer::mouse_get_absolute_position);
+ ClassDB::bind_method(D_METHOD("mouse_get_button_state"), &DisplayServer::mouse_get_button_state);
+
+ ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set);
+ ClassDB::bind_method(D_METHOD("clipboard_get"), &DisplayServer::clipboard_get);
+
+ ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count);
+ ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+ ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+ ClassDB::bind_method(D_METHOD("screen_get_usable_rect", "screen"), &DisplayServer::screen_get_usable_rect, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+ ClassDB::bind_method(D_METHOD("screen_get_dpi", "screen"), &DisplayServer::screen_get_dpi, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+ ClassDB::bind_method(D_METHOD("screen_get_scale", "screen"), &DisplayServer::screen_get_scale, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+ ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+
+ ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+ ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+
+ ClassDB::bind_method(D_METHOD("screen_set_keep_on", "enable"), &DisplayServer::screen_set_keep_on);
+ ClassDB::bind_method(D_METHOD("screen_is_kept_on"), &DisplayServer::screen_is_kept_on);
+
+ ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list);
+ ClassDB::bind_method(D_METHOD("get_window_at_screen_position", "position"), &DisplayServer::get_window_at_screen_position);
+
+ ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i()));
+ ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
+
+ ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_current_screen", "window_id"), &DisplayServer::window_get_current_screen, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_current_screen", "screen", "window_id"), &DisplayServer::window_set_current_screen, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_position", "window_id"), &DisplayServer::window_get_position, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_position", "position", "window_id"), &DisplayServer::window_set_position, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_size", "window_id"), &DisplayServer::window_get_size, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_size", "size", "window_id"), &DisplayServer::window_set_size, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_rect_changed_callback", "callback", "window_id"), &DisplayServer::window_set_rect_changed_callback, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_window_event_callback", "callback", "window_id"), &DisplayServer::window_set_window_event_callback, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_input_event_callback", "callback", "window_id"), &DisplayServer::window_set_input_event_callback, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_drop_files_callback", "callback", "window_id"), &DisplayServer::window_set_drop_files_callback, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_attach_instance_id", "instance_id", "window_id"), &DisplayServer::window_attach_instance_id, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_get_attached_instance_id", "window_id"), &DisplayServer::window_get_attached_instance_id, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_max_size", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_max_size", "max_size", "window_id"), &DisplayServer::window_set_max_size, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_min_size", "window_id"), &DisplayServer::window_get_min_size, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_min_size", "min_size", "window_id"), &DisplayServer::window_set_min_size, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_real_size", "window_id"), &DisplayServer::window_get_real_size, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_get_mode", "window_id"), &DisplayServer::window_get_mode, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_mode", "mode", "window_id"), &DisplayServer::window_set_mode, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_set_flag", "flag", "enabled", "window_id"), &DisplayServer::window_set_flag, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_get_flag", "flag", "window_id"), &DisplayServer::window_get_flag, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_move_to_foreground", "window_id"), &DisplayServer::window_move_to_foreground, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_can_draw", "window_id"), &DisplayServer::window_can_draw, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("window_set_transient", "window_id", "parent_window_id"), &DisplayServer::window_set_transient);
+
+ ClassDB::bind_method(D_METHOD("window_set_ime_active", "active", "window_id"), &DisplayServer::window_set_ime_active, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_set_ime_position", "position", "window_id"), &DisplayServer::window_set_ime_position, DEFVAL(MAIN_WINDOW_ID));
+
+ ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection);
+ ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text);
+
+ ClassDB::bind_method(D_METHOD("console_set_visible", "console_visible"), &DisplayServer::console_set_visible);
+ ClassDB::bind_method(D_METHOD("is_console_visible"), &DisplayServer::is_console_visible);
+
+ ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "max_length"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide);
+
+ ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height);
+
+ ClassDB::bind_method(D_METHOD("cursor_set_shape", "shape"), &DisplayServer::cursor_set_shape);
+ ClassDB::bind_method(D_METHOD("cursor_get_shape"), &DisplayServer::cursor_get_shape);
+ ClassDB::bind_method(D_METHOD("cursor_set_custom_image", "cursor", "shape", "hotspot"), &DisplayServer::cursor_set_custom_image, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
+
+ ClassDB::bind_method(D_METHOD("get_swap_ok_cancel"), &DisplayServer::get_swap_ok_cancel);
+
+ 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_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);
+ ClassDB::bind_method(D_METHOD("native_video_unpause"), &DisplayServer::native_video_unpause);
+
+ ClassDB::bind_method(D_METHOD("dialog_show", "title", "description", "buttons", "callback"), &DisplayServer::dialog_show);
+ ClassDB::bind_method(D_METHOD("dialog_input_text", "title", "description", "existing_text", "callback"), &DisplayServer::dialog_input_text);
+
+ ClassDB::bind_method(D_METHOD("get_latin_keyboard_variant"), &DisplayServer::get_latin_keyboard_variant);
+
+ ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events);
+ ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events);
+
+ ClassDB::bind_method(D_METHOD("vsync_set_enabled", "enabled"), &DisplayServer::vsync_set_enabled);
+ ClassDB::bind_method(D_METHOD("vsync_is_enabled"), &DisplayServer::vsync_is_enabled);
+
+ ClassDB::bind_method(D_METHOD("vsync_set_use_via_compositor", "enabled"), &DisplayServer::vsync_set_use_via_compositor);
+ ClassDB::bind_method(D_METHOD("vsync_is_using_via_compositor"), &DisplayServer::vsync_is_using_via_compositor);
+
+ ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon);
+ ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon);
+
+ BIND_ENUM_CONSTANT(FEATURE_GLOBAL_MENU);
+ BIND_ENUM_CONSTANT(FEATURE_SUBWINDOWS);
+ BIND_ENUM_CONSTANT(FEATURE_TOUCHSCREEN);
+ BIND_ENUM_CONSTANT(FEATURE_MOUSE);
+ BIND_ENUM_CONSTANT(FEATURE_MOUSE_WARP);
+ BIND_ENUM_CONSTANT(FEATURE_CLIPBOARD);
+ BIND_ENUM_CONSTANT(FEATURE_VIRTUAL_KEYBOARD);
+ BIND_ENUM_CONSTANT(FEATURE_CURSOR_SHAPE);
+ BIND_ENUM_CONSTANT(FEATURE_CUSTOM_CURSOR_SHAPE);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_VIDEO);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG);
+ BIND_ENUM_CONSTANT(FEATURE_CONSOLE_WINDOW);
+ BIND_ENUM_CONSTANT(FEATURE_IME);
+ BIND_ENUM_CONSTANT(FEATURE_WINDOW_TRANSPARENCY);
+ BIND_ENUM_CONSTANT(FEATURE_HIDPI);
+ BIND_ENUM_CONSTANT(FEATURE_ICON);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_ICON);
+ BIND_ENUM_CONSTANT(FEATURE_ORIENTATION);
+ BIND_ENUM_CONSTANT(FEATURE_SWAP_BUFFERS);
+
+ BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
+ BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+
+ BIND_CONSTANT(SCREEN_OF_MAIN_WINDOW);
+ BIND_CONSTANT(MAIN_WINDOW_ID);
+ BIND_CONSTANT(INVALID_WINDOW_ID);
+
+ BIND_ENUM_CONSTANT(SCREEN_LANDSCAPE);
+ BIND_ENUM_CONSTANT(SCREEN_PORTRAIT);
+ BIND_ENUM_CONSTANT(SCREEN_REVERSE_LANDSCAPE);
+ BIND_ENUM_CONSTANT(SCREEN_REVERSE_PORTRAIT);
+ BIND_ENUM_CONSTANT(SCREEN_SENSOR_LANDSCAPE);
+ BIND_ENUM_CONSTANT(SCREEN_SENSOR_PORTRAIT);
+ BIND_ENUM_CONSTANT(SCREEN_SENSOR);
+
+ BIND_ENUM_CONSTANT(CURSOR_ARROW);
+ BIND_ENUM_CONSTANT(CURSOR_IBEAM);
+ BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
+ BIND_ENUM_CONSTANT(CURSOR_CROSS);
+ BIND_ENUM_CONSTANT(CURSOR_WAIT);
+ BIND_ENUM_CONSTANT(CURSOR_BUSY);
+ BIND_ENUM_CONSTANT(CURSOR_DRAG);
+ BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
+ BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
+ BIND_ENUM_CONSTANT(CURSOR_VSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_HSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
+ BIND_ENUM_CONSTANT(CURSOR_MOVE);
+ BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
+ BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
+ BIND_ENUM_CONSTANT(CURSOR_HELP);
+ BIND_ENUM_CONSTANT(CURSOR_MAX);
+
+ BIND_ENUM_CONSTANT(WINDOW_MODE_WINDOWED);
+ BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED);
+ BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED);
+ BIND_ENUM_CONSTANT(WINDOW_MODE_FULLSCREEN);
+
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_ALWAYS_ON_TOP);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_TRANSPARENT);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_NO_FOCUS);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_QWERTY);
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_QWERTZ);
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_AZERTY);
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_QZERTY);
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_DVORAK);
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_NEO);
+ BIND_ENUM_CONSTANT(LATIN_KEYBOARD_COLEMAK);
+
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_EXIT);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_FOCUS_IN);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_FOCUS_OUT);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_CLOSE_REQUEST);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST);
+ BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE);
+}
+
+void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) {
+ ERR_FAIL_COND(server_create_count == MAX_SERVERS);
+ server_create_functions[server_create_count].name = p_name;
+ server_create_functions[server_create_count].create_function = p_function;
+ server_create_functions[server_create_count].get_rendering_drivers_function = p_get_drivers;
+ server_create_count++;
+}
+
+int DisplayServer::get_create_function_count() {
+ return server_create_count;
+}
+
+const char *DisplayServer::get_create_function_name(int p_index) {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
+ return server_create_functions[p_index].name;
+}
+
+Vector<String> DisplayServer::get_create_function_rendering_drivers(int p_index) {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, Vector<String>());
+ return server_create_functions[p_index].get_rendering_drivers_function();
+}
+
+DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
+ return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_flags, p_resolution, r_error);
+}
+
+void DisplayServer::_input_set_mouse_mode(InputFilter::MouseMode p_mode) {
+ singleton->mouse_set_mode(MouseMode(p_mode));
+}
+InputFilter::MouseMode DisplayServer::_input_get_mouse_mode() {
+ return InputFilter::MouseMode(singleton->mouse_get_mode());
+}
+
+void DisplayServer::_input_warp(const Vector2 &p_to_pos) {
+ singleton->mouse_warp_to_position(p_to_pos);
+}
+
+InputFilter::CursorShape DisplayServer::_input_get_current_cursor_shape() {
+ return (InputFilter::CursorShape)singleton->cursor_get_shape();
+}
+void DisplayServer::_input_set_custom_mouse_cursor_func(const RES &p_image, InputFilter::CursorShape p_shape, const Vector2 &p_hostspot) {
+ singleton->cursor_set_custom_image(p_image, (CursorShape)p_shape, p_hostspot);
+}
+
+DisplayServer::DisplayServer() {
+ singleton = this;
+ InputFilter::set_mouse_mode_func = _input_set_mouse_mode;
+ InputFilter::get_mouse_mode_func = _input_get_mouse_mode;
+ InputFilter::warp_mouse_func = _input_warp;
+ InputFilter::get_current_cursor_shape_func = _input_get_current_cursor_shape;
+ InputFilter::set_custom_mouse_cursor_func = _input_set_custom_mouse_cursor_func;
+}
+DisplayServer::~DisplayServer() {
+}
diff --git a/servers/display_server.h b/servers/display_server.h
new file mode 100644
index 0000000000..93db7ef844
--- /dev/null
+++ b/servers/display_server.h
@@ -0,0 +1,389 @@
+/*************************************************************************/
+/* display_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 DISPLAY_SERVER_H
+#define DISPLAY_SERVER_H
+
+#include "core/callable.h"
+#include "core/input/input_filter.h"
+#include "core/os/os.h"
+#include "core/resource.h"
+
+class Texture2D;
+
+class DisplayServer : public Object {
+ GDCLASS(DisplayServer, Object)
+
+ static DisplayServer *singleton;
+ bool vsync_enabled = true;
+ static bool hidpi_allowed;
+
+public:
+ _FORCE_INLINE_ static DisplayServer *get_singleton() {
+ return singleton;
+ }
+
+ enum WindowMode {
+ WINDOW_MODE_WINDOWED,
+ WINDOW_MODE_MINIMIZED,
+ WINDOW_MODE_MAXIMIZED,
+ WINDOW_MODE_FULLSCREEN
+ };
+
+ typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, uint32_t, const Size2i &, Error &r_error);
+ typedef Vector<String> (*GetRenderingDriversFunction)();
+
+private:
+ static void _input_set_mouse_mode(InputFilter::MouseMode p_mode);
+ static InputFilter::MouseMode _input_get_mouse_mode();
+ static void _input_warp(const Vector2 &p_to_pos);
+ static InputFilter::CursorShape _input_get_current_cursor_shape();
+ static void _input_set_custom_mouse_cursor_func(const RES &, InputFilter::CursorShape, const Vector2 &p_hostspot);
+
+protected:
+ static void _bind_methods();
+
+ enum {
+ MAX_SERVERS = 64
+ };
+
+ struct DisplayServerCreate {
+ const char *name;
+ CreateFunction create_function;
+ GetRenderingDriversFunction get_rendering_drivers_function;
+ };
+
+ static DisplayServerCreate server_create_functions[MAX_SERVERS];
+ static int server_create_count;
+
+ friend class RenderingServerRaster;
+ virtual void _set_use_vsync(bool p_enable);
+
+public:
+ enum Feature {
+ FEATURE_GLOBAL_MENU,
+ FEATURE_SUBWINDOWS,
+ FEATURE_TOUCHSCREEN,
+ FEATURE_MOUSE,
+ FEATURE_MOUSE_WARP,
+ FEATURE_CLIPBOARD,
+ FEATURE_VIRTUAL_KEYBOARD,
+ FEATURE_CURSOR_SHAPE,
+ FEATURE_CUSTOM_CURSOR_SHAPE,
+ FEATURE_NATIVE_VIDEO,
+ FEATURE_NATIVE_DIALOG,
+ FEATURE_CONSOLE_WINDOW,
+ FEATURE_IME,
+ FEATURE_WINDOW_TRANSPARENCY,
+ FEATURE_HIDPI,
+ FEATURE_ICON,
+ FEATURE_NATIVE_ICON,
+ FEATURE_ORIENTATION,
+ FEATURE_SWAP_BUFFERS,
+ FEATURE_KEEP_SCREEN_ON,
+ };
+
+ virtual bool has_feature(Feature p_feature) const = 0;
+ virtual String get_name() const = 0;
+
+ virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant());
+ virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant());
+ virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu);
+ virtual void global_menu_add_separator(const String &p_menu_root);
+
+ virtual bool global_menu_is_item_checked(const String &p_menu_root, int p_idx) const;
+ virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const;
+ virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx);
+ virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx);
+ virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx);
+ virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx);
+
+ virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked);
+ virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable);
+ virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback);
+ virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag);
+ virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text);
+ virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu);
+
+ virtual int global_menu_get_item_count(const String &p_menu_root) const;
+
+ virtual void global_menu_remove_item(const String &p_menu_root, int p_idx);
+ virtual void global_menu_clear(const String &p_menu_root);
+
+ virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0;
+
+ enum MouseMode {
+ MOUSE_MODE_VISIBLE,
+ MOUSE_MODE_HIDDEN,
+ MOUSE_MODE_CAPTURED,
+ MOUSE_MODE_CONFINED
+ };
+
+ virtual void mouse_set_mode(MouseMode p_mode);
+ virtual MouseMode mouse_get_mode() const;
+
+ virtual void mouse_warp_to_position(const Point2i &p_to);
+ virtual Point2i mouse_get_position() const;
+ virtual Point2i mouse_get_absolute_position() const;
+ virtual int mouse_get_button_state() const;
+
+ virtual void clipboard_set(const String &p_text);
+ virtual String clipboard_get() const;
+
+ enum {
+ SCREEN_OF_MAIN_WINDOW = -1
+ };
+
+ virtual int get_screen_count() const = 0;
+ virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+ virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+ virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+ virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+ virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ enum ScreenOrientation {
+
+ SCREEN_LANDSCAPE,
+ SCREEN_PORTRAIT,
+ SCREEN_REVERSE_LANDSCAPE,
+ SCREEN_REVERSE_PORTRAIT,
+ SCREEN_SENSOR_LANDSCAPE,
+ SCREEN_SENSOR_PORTRAIT,
+ SCREEN_SENSOR,
+ };
+
+ virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW);
+ virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+ virtual void screen_set_keep_on(bool p_enable); //disable screensaver
+ virtual bool screen_is_kept_on() const;
+ enum {
+ MAIN_WINDOW_ID = 0,
+ INVALID_WINDOW_ID = -1
+ };
+
+ typedef int WindowID;
+
+ virtual Vector<DisplayServer::WindowID> get_window_list() const = 0;
+
+ enum WindowFlags {
+ WINDOW_FLAG_RESIZE_DISABLED,
+ WINDOW_FLAG_BORDERLESS,
+ WINDOW_FLAG_ALWAYS_ON_TOP,
+ WINDOW_FLAG_TRANSPARENT,
+ WINDOW_FLAG_NO_FOCUS,
+ WINDOW_FLAG_MAX,
+ };
+
+ // Separate enum otherwise we get warnings in switches not handling all values.
+ enum WindowFlagsBit {
+ WINDOW_FLAG_RESIZE_DISABLED_BIT = (1 << WINDOW_FLAG_RESIZE_DISABLED),
+ WINDOW_FLAG_BORDERLESS_BIT = (1 << WINDOW_FLAG_BORDERLESS),
+ WINDOW_FLAG_ALWAYS_ON_TOP_BIT = (1 << WINDOW_FLAG_ALWAYS_ON_TOP),
+ WINDOW_FLAG_TRANSPARENT_BIT = (1 << WINDOW_FLAG_TRANSPARENT),
+ WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS)
+ };
+
+ virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i & = Rect2i());
+ virtual void delete_sub_window(WindowID p_id);
+
+ virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0;
+
+ virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ enum WindowEvent {
+ WINDOW_EVENT_MOUSE_ENTER,
+ WINDOW_EVENT_MOUSE_EXIT,
+ WINDOW_EVENT_FOCUS_IN,
+ WINDOW_EVENT_FOCUS_OUT,
+ WINDOW_EVENT_CLOSE_REQUEST,
+ WINDOW_EVENT_GO_BACK_REQUEST,
+ WINDOW_EVENT_DPI_CHANGE,
+ };
+ virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+ virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+ virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ virtual void window_set_transient(WindowID p_window, WindowID p_parent) = 0;
+
+ virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+ virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const = 0; // FIXME: Find clearer name for this.
+
+ virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+ virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+ virtual bool can_any_window_draw() const = 0;
+
+ virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+
+ virtual Point2i ime_get_selection() const;
+ virtual String ime_get_text() const;
+
+ virtual void console_set_visible(bool p_enabled);
+ virtual bool is_console_visible() const;
+
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_legth = -1);
+ virtual void virtual_keyboard_hide();
+
+ // returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
+ virtual int virtual_keyboard_get_height() const;
+
+ enum CursorShape {
+ CURSOR_ARROW,
+ CURSOR_IBEAM,
+ CURSOR_POINTING_HAND,
+ CURSOR_CROSS,
+ CURSOR_WAIT,
+ CURSOR_BUSY,
+ CURSOR_DRAG,
+ CURSOR_CAN_DROP,
+ CURSOR_FORBIDDEN,
+ CURSOR_VSIZE,
+ CURSOR_HSIZE,
+ CURSOR_BDIAGSIZE,
+ CURSOR_FDIAGSIZE,
+ CURSOR_MOVE,
+ CURSOR_VSPLIT,
+ CURSOR_HSPLIT,
+ CURSOR_HELP,
+ CURSOR_MAX
+ };
+ virtual void cursor_set_shape(CursorShape p_shape);
+ virtual CursorShape cursor_get_shape() const;
+ virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+
+ virtual bool get_swap_ok_cancel();
+
+ virtual void enable_for_stealing_focus(OS::ProcessID pid);
+
+ //plays video natively, in fullscreen, only implemented in mobile for now, likely not possible to implement on linux also.
+ virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen = SCREEN_OF_MAIN_WINDOW);
+ virtual bool native_video_is_playing() const;
+ virtual void native_video_pause();
+ virtual void native_video_unpause();
+ virtual void native_video_stop();
+
+ virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback);
+ virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback);
+
+ enum LatinKeyboardVariant {
+ LATIN_KEYBOARD_QWERTY,
+ LATIN_KEYBOARD_QWERTZ,
+ LATIN_KEYBOARD_AZERTY,
+ LATIN_KEYBOARD_QZERTY,
+ LATIN_KEYBOARD_DVORAK,
+ LATIN_KEYBOARD_NEO,
+ LATIN_KEYBOARD_COLEMAK,
+ };
+
+ virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+ virtual void process_events() = 0;
+
+ virtual void force_process_and_drop_events();
+
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ virtual void set_native_icon(const String &p_filename);
+ virtual void set_icon(const Ref<Image> &p_icon);
+
+ typedef void (*SwitchVSyncCallbackInThread)(bool);
+
+ static SwitchVSyncCallbackInThread switch_vsync_function;
+
+ void vsync_set_enabled(bool p_enable);
+ bool vsync_is_enabled() const;
+
+ virtual void vsync_set_use_via_compositor(bool p_enable);
+ virtual bool vsync_is_using_via_compositor() const;
+
+ //real, actual overridable function to switch vsync, which needs to be called from graphics thread if needed
+
+ enum Context {
+ CONTEXT_EDITOR,
+ CONTEXT_PROJECTMAN,
+ CONTEXT_ENGINE,
+ };
+
+ virtual void set_context(Context p_context);
+
+ static void register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers);
+ static int get_create_function_count();
+ static const char *get_create_function_name(int p_index);
+ static Vector<String> get_create_function_rendering_drivers(int p_index);
+ static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+
+ DisplayServer();
+ ~DisplayServer();
+};
+
+VARIANT_ENUM_CAST(DisplayServer::WindowEvent)
+VARIANT_ENUM_CAST(DisplayServer::Feature)
+VARIANT_ENUM_CAST(DisplayServer::MouseMode)
+VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation)
+VARIANT_ENUM_CAST(DisplayServer::WindowMode)
+VARIANT_ENUM_CAST(DisplayServer::WindowFlags)
+VARIANT_ENUM_CAST(DisplayServer::CursorShape)
+VARIANT_ENUM_CAST(DisplayServer::LatinKeyboardVariant)
+
+#endif // DISPLAY_SERVER_H
diff --git a/servers/navigation_2d_server.cpp b/servers/navigation_2d_server.cpp
deleted file mode 100644
index d9b53122e2..0000000000
--- a/servers/navigation_2d_server.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*************************************************************************/
-/* navigation_2d_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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/navigation_2d_server.h"
-#include "core/math/transform.h"
-#include "core/math/transform_2d.h"
-#include "servers/navigation_server.h"
-
-/**
- @author AndreaCatania
-*/
-
-Navigation2DServer *Navigation2DServer::singleton = NULL;
-
-#define FORWARD_0_C(FUNC_NAME) \
- Navigation2DServer::FUNC_NAME() \
- const { \
- return NavigationServer::get_singleton()->FUNC_NAME(); \
- }
-
-#define FORWARD_1(FUNC_NAME, T_0, D_0, CONV_0) \
- Navigation2DServer::FUNC_NAME(T_0 D_0) { \
- return NavigationServer::get_singleton_mut()->FUNC_NAME(CONV_0(D_0)); \
- }
-
-#define FORWARD_1_C(FUNC_NAME, T_0, D_0, CONV_0) \
- Navigation2DServer::FUNC_NAME(T_0 D_0) \
- const { \
- return NavigationServer::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
- }
-
-#define FORWARD_2_C(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
- Navigation2DServer::FUNC_NAME(T_0 D_0, T_1 D_1) \
- const { \
- return NavigationServer::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1)); \
- }
-
-#define FORWARD_2_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
- Navigation2DServer::FUNC_NAME(T_0 D_0, T_1 D_1) \
- const { \
- return CONV_R(NavigationServer::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1))); \
- }
-
-#define FORWARD_4_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \
- Navigation2DServer::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) \
- const { \
- return CONV_R(NavigationServer::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3))); \
- }
-
-#define FORWARD_4_C(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \
- Navigation2DServer::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) \
- const { \
- return NavigationServer::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3)); \
- }
-
-RID rid_to_rid(const RID d) {
- return d;
-}
-bool bool_to_bool(const bool d) {
- return d;
-}
-int int_to_int(const int d) {
- return d;
-}
-real_t real_to_real(const real_t d) {
- return d;
-}
-Vector3 v2_to_v3(const Vector2 d) {
- return Vector3(d.x, 0.0, d.y);
-}
-Vector2 v3_to_v2(const Vector3 &d) {
- return Vector2(d.x, d.z);
-}
-Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) {
- Vector<Vector2> nd;
- nd.resize(d.size());
- for (int i(0); i < nd.size(); i++) {
- nd.write[i] = v3_to_v2(d[i]);
- }
- return nd;
-}
-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());
- return Transform(b, o);
-}
-Object *obj_to_obj(Object *d) {
- return d;
-}
-StringName sn_to_sn(StringName &d) {
- return d;
-}
-Variant var_to_var(Variant &d) {
- return d;
-}
-Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
- if (d.is_valid()) {
- return d->get_mesh();
- } else {
- return Ref<NavigationMesh>();
- }
-}
-
-void Navigation2DServer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("map_create"), &Navigation2DServer::map_create);
- ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &Navigation2DServer::map_set_active);
- ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &Navigation2DServer::map_is_active);
- ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &Navigation2DServer::map_set_cell_size);
- ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &Navigation2DServer::map_get_cell_size);
- ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &Navigation2DServer::map_set_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &Navigation2DServer::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize"), &Navigation2DServer::map_get_path);
- ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &Navigation2DServer::map_get_closest_point);
- ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &Navigation2DServer::map_get_closest_point_owner);
-
- ClassDB::bind_method(D_METHOD("region_create"), &Navigation2DServer::region_create);
- ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &Navigation2DServer::region_set_map);
- ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &Navigation2DServer::region_set_transform);
- ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &Navigation2DServer::region_set_navpoly);
-
- ClassDB::bind_method(D_METHOD("agent_create"), &Navigation2DServer::agent_create);
- ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &Navigation2DServer::agent_set_map);
- ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &Navigation2DServer::agent_set_neighbor_dist);
- ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &Navigation2DServer::agent_set_max_neighbors);
- ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &Navigation2DServer::agent_set_time_horizon);
- ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &Navigation2DServer::agent_set_radius);
- ClassDB::bind_method(D_METHOD("agent_set_max_speed", "agent", "max_speed"), &Navigation2DServer::agent_set_max_speed);
- ClassDB::bind_method(D_METHOD("agent_set_velocity", "agent", "velocity"), &Navigation2DServer::agent_set_velocity);
- ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &Navigation2DServer::agent_set_target_velocity);
- ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &Navigation2DServer::agent_set_position);
- ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &Navigation2DServer::agent_is_map_changed);
- ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &Navigation2DServer::agent_set_callback, DEFVAL(Variant()));
-
- ClassDB::bind_method(D_METHOD("free", "object"), &Navigation2DServer::free);
-}
-
-Navigation2DServer::Navigation2DServer() {
- singleton = this;
-}
-
-Navigation2DServer::~Navigation2DServer() {
- singleton = NULL;
-}
-
-RID FORWARD_0_C(map_create);
-
-void FORWARD_2_C(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to_bool);
-
-bool FORWARD_1_C(map_is_active, RID, p_map, rid_to_rid);
-
-void FORWARD_2_C(map_set_cell_size, RID, p_map, real_t, p_cell_size, rid_to_rid, real_to_real);
-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);
-
-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_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3);
-
-void Navigation2DServer::region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const {
- NavigationServer::get_singleton()->region_set_navmesh(p_region, poly_to_mesh(p_nav_mesh));
-}
-
-RID Navigation2DServer::agent_create() const {
- RID agent = NavigationServer::get_singleton()->agent_create();
- NavigationServer::get_singleton()->agent_set_ignore_y(agent, true);
- return agent;
-}
-
-void FORWARD_2_C(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid);
-
-void FORWARD_2_C(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real);
-
-void FORWARD_2_C(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int);
-
-void FORWARD_2_C(agent_set_time_horizon, RID, p_agent, real_t, p_time, rid_to_rid, real_to_real);
-
-void FORWARD_2_C(agent_set_radius, RID, p_agent, real_t, p_radius, rid_to_rid, real_to_real);
-
-void FORWARD_2_C(agent_set_max_speed, RID, p_agent, real_t, p_max_speed, rid_to_rid, real_to_real);
-
-void FORWARD_2_C(agent_set_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
-
-void FORWARD_2_C(agent_set_target_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
-
-void FORWARD_2_C(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3);
-
-void FORWARD_2_C(agent_set_ignore_y, RID, p_agent, bool, p_ignore, rid_to_rid, bool_to_bool);
-
-bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
-
-void FORWARD_4_C(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, rid_to_rid, obj_to_obj, sn_to_sn, var_to_var);
-
-void FORWARD_1_C(free, RID, p_object, rid_to_rid);
diff --git a/servers/navigation_2d_server.h b/servers/navigation_2d_server.h
deleted file mode 100644
index 7b0b9fbb01..0000000000
--- a/servers/navigation_2d_server.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*************************************************************************/
-/* navigation_2d_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/**
- @author AndreaCatania
-*/
-
-#ifndef NAVIGATION_2D_SERVER_H
-#define NAVIGATION_2D_SERVER_H
-
-#include "core/object.h"
-#include "core/rid.h"
-#include "scene/2d/navigation_polygon.h"
-
-// This server exposes the 3D `NavigationServer` features in the 2D world.
-class Navigation2DServer : public Object {
- GDCLASS(Navigation2DServer, Object);
-
- static Navigation2DServer *singleton;
-
-protected:
- static void _bind_methods();
-
-public:
- /// Thread safe, can be used across many threads.
- static const Navigation2DServer *get_singleton() { return singleton; }
-
- /// MUST be used in single thread!
- static Navigation2DServer *get_singleton_mut() { return singleton; }
-
- /// Create a new map.
- virtual RID map_create() const;
-
- /// Set map active.
- virtual void map_set_active(RID p_map, bool p_active) const;
-
- /// Returns true if the map is active.
- virtual bool map_is_active(RID p_map) const;
-
- /// Set the map cell size used to weld the navigation mesh polygons.
- virtual void map_set_cell_size(RID p_map, real_t p_cell_size) const;
-
- /// Returns the map cell size.
- virtual real_t map_get_cell_size(RID p_map) const;
-
- /// Set the map edge connection margin used to weld the compatible region edges.
- virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) const;
-
- /// Returns the edge connection margin of this map.
- 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 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;
-
- /// Creates a new region.
- virtual RID region_create() const;
-
- /// Set the map of this region.
- virtual void region_set_map(RID p_region, RID p_map) 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;
-
- /// Creates the agent.
- virtual RID agent_create() const;
-
- /// Put the agent in the map.
- virtual void agent_set_map(RID p_agent, RID p_map) const;
-
- /// The maximum distance (center point to
- /// center point) to other agents this agent
- /// takes into account in the navigation. The
- /// larger this number, the longer the running
- /// time of the simulation. If the number is too
- /// low, the simulation will not be safe.
- /// Must be non-negative.
- virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const;
-
- /// The maximum number of other agents this
- /// agent takes into account in the navigation.
- /// The larger this number, the longer the
- /// running time of the simulation. If the
- /// number is too low, the simulation will not
- /// be safe.
- virtual void agent_set_max_neighbors(RID p_agent, int p_count) const;
-
- /// The minimal amount of time for which this
- /// agent's velocities that are computed by the
- /// simulation are safe with respect to other
- /// agents. The larger this number, the sooner
- /// this agent will respond to the presence of
- /// other agents, but the less freedom this
- /// agent has in choosing its velocities.
- /// Must be positive.
- virtual void agent_set_time_horizon(RID p_agent, real_t p_time) const;
-
- /// The radius of this agent.
- /// Must be non-negative.
- virtual void agent_set_radius(RID p_agent, real_t p_radius) const;
-
- /// The maximum speed of this agent.
- /// Must be non-negative.
- virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) const;
-
- /// Current velocity of the agent
- virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity) const;
-
- /// The new target velocity.
- virtual void agent_set_target_velocity(RID p_agent, Vector2 p_velocity) const;
-
- /// Position of the agent in world space.
- virtual void agent_set_position(RID p_agent, Vector2 p_position) const;
-
- /// Agent ignore the Y axis and avoid collisions by moving only on the horizontal plane
- virtual void agent_set_ignore_y(RID p_agent, bool p_ignore) const;
-
- /// Returns true if the map got changed the previous frame.
- virtual bool agent_is_map_changed(RID p_agent) const;
-
- /// Callback called at the end of the RVO process
- virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const;
-
- /// Destroy the `RID`
- virtual void free(RID p_object) const;
-
- Navigation2DServer();
- virtual ~Navigation2DServer();
-};
-
-#endif
diff --git a/servers/navigation_server.cpp b/servers/navigation_server.cpp
deleted file mode 100644
index f2b727ac47..0000000000
--- a/servers/navigation_server.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*************************************************************************/
-/* navigation_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/**
- @author AndreaCatania
-*/
-
-#include "navigation_server.h"
-
-NavigationServer *NavigationServer::singleton = NULL;
-
-void NavigationServer::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer::map_create);
- ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer::map_set_active);
- ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer::map_is_active);
- ClassDB::bind_method(D_METHOD("map_set_up", "map", "up"), &NavigationServer::map_set_up);
- ClassDB::bind_method(D_METHOD("map_get_up", "map"), &NavigationServer::map_get_up);
- ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer::map_set_cell_size);
- ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer::map_get_cell_size);
- ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer::map_set_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize"), &NavigationServer::map_get_path);
- ClassDB::bind_method(D_METHOD("map_get_closest_point_to_segment", "map", "start", "end", "use_collision"), &NavigationServer::map_get_closest_point_to_segment, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer::map_get_closest_point);
- ClassDB::bind_method(D_METHOD("map_get_closest_point_normal", "map", "to_point"), &NavigationServer::map_get_closest_point_normal);
- ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer::map_get_closest_point_owner);
-
- ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer::region_create);
- ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer::region_set_map);
- ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer::region_set_transform);
- ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer::region_set_navmesh);
- ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer::region_bake_navmesh);
-
- ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer::agent_create);
- ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer::agent_set_map);
- ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer::agent_set_neighbor_dist);
- ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer::agent_set_max_neighbors);
- ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer::agent_set_time_horizon);
- ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer::agent_set_radius);
- ClassDB::bind_method(D_METHOD("agent_set_max_speed", "agent", "max_speed"), &NavigationServer::agent_set_max_speed);
- ClassDB::bind_method(D_METHOD("agent_set_velocity", "agent", "velocity"), &NavigationServer::agent_set_velocity);
- ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer::agent_set_target_velocity);
- ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer::agent_set_position);
- ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer::agent_is_map_changed);
- ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &NavigationServer::agent_set_callback, DEFVAL(Variant()));
-
- ClassDB::bind_method(D_METHOD("free", "object"), &NavigationServer::free);
-
- ClassDB::bind_method(D_METHOD("set_active", "active"), &NavigationServer::set_active);
- ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer::process);
-}
-
-const NavigationServer *NavigationServer::get_singleton() {
- return singleton;
-}
-
-NavigationServer *NavigationServer::get_singleton_mut() {
- return singleton;
-}
-
-NavigationServer::NavigationServer() {
- ERR_FAIL_COND(singleton != NULL);
- singleton = this;
-}
-
-NavigationServer::~NavigationServer() {
- singleton = NULL;
-}
-
-NavigationServerCallback NavigationServerManager::create_callback = NULL;
-
-void NavigationServerManager::set_default_server(NavigationServerCallback p_callback) {
- create_callback = p_callback;
-}
-
-NavigationServer *NavigationServerManager::new_default_server() {
- ERR_FAIL_COND_V(create_callback == NULL, NULL);
- return create_callback();
-}
diff --git a/servers/navigation_server.h b/servers/navigation_server.h
deleted file mode 100644
index 546e543db3..0000000000
--- a/servers/navigation_server.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*************************************************************************/
-/* navigation_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/**
- @author AndreaCatania
-*/
-
-#ifndef NAVIGATION_SERVER_H
-#define NAVIGATION_SERVER_H
-
-#include "core/object.h"
-#include "core/rid.h"
-#include "scene/3d/navigation_region.h"
-
-/// This server uses the concept of internal mutability.
-/// All the constant functions can be called in multithread because internally
-/// the server takes care to schedule the functions access.
-///
-/// Note: All the `set` functions are commands executed during the `sync` phase,
-/// don't expect that a change is immediately propagated.
-class NavigationServer : public Object {
- GDCLASS(NavigationServer, Object);
-
- static NavigationServer *singleton;
-
-protected:
- static void _bind_methods();
-
-public:
- /// Thread safe, can be used across many threads.
- static const NavigationServer *get_singleton();
-
- /// MUST be used in single thread!
- static NavigationServer *get_singleton_mut();
-
- /// Create a new map.
- virtual RID map_create() const = 0;
-
- /// Set map active.
- virtual void map_set_active(RID p_map, bool p_active) const = 0;
-
- /// Returns true if the map is active.
- virtual bool map_is_active(RID p_map) const = 0;
-
- /// Set the map UP direction.
- virtual void map_set_up(RID p_map, Vector3 p_up) const = 0;
-
- /// Returns the map UP direction.
- virtual Vector3 map_get_up(RID p_map) const = 0;
-
- /// Set the map cell size used to weld the navigation mesh polygons.
- virtual void map_set_cell_size(RID p_map, real_t p_cell_size) const = 0;
-
- /// Returns the map cell size.
- virtual real_t map_get_cell_size(RID p_map) const = 0;
-
- /// Set the map edge connection margin used to weld the compatible region edges.
- virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) const = 0;
-
- /// Returns the edge connection margin of this map.
- 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 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;
- virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const = 0;
- virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const = 0;
-
- /// Creates a new region.
- virtual RID region_create() const = 0;
-
- /// Set the map of this region.
- virtual void region_set_map(RID p_region, RID p_map) 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
- virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0;
-
- /// Creates the agent.
- virtual RID agent_create() const = 0;
-
- /// Put the agent in the map.
- virtual void agent_set_map(RID p_agent, RID p_map) const = 0;
-
- /// The maximum distance (center point to
- /// center point) to other agents this agent
- /// takes into account in the navigation. The
- /// larger this number, the longer the running
- /// time of the simulation. If the number is too
- /// low, the simulation will not be safe.
- /// Must be non-negative.
- virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const = 0;
-
- /// The maximum number of other agents this
- /// agent takes into account in the navigation.
- /// The larger this number, the longer the
- /// running time of the simulation. If the
- /// number is too low, the simulation will not
- /// be safe.
- virtual void agent_set_max_neighbors(RID p_agent, int p_count) const = 0;
-
- /// The minimal amount of time for which this
- /// agent's velocities that are computed by the
- /// simulation are safe with respect to other
- /// agents. The larger this number, the sooner
- /// this agent will respond to the presence of
- /// other agents, but the less freedom this
- /// agent has in choosing its velocities.
- /// Must be positive.
- virtual void agent_set_time_horizon(RID p_agent, real_t p_time) const = 0;
-
- /// The radius of this agent.
- /// Must be non-negative.
- virtual void agent_set_radius(RID p_agent, real_t p_radius) const = 0;
-
- /// The maximum speed of this agent.
- /// Must be non-negative.
- virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) const = 0;
-
- /// Current velocity of the agent
- virtual void agent_set_velocity(RID p_agent, Vector3 p_velocity) const = 0;
-
- /// The new target velocity.
- virtual void agent_set_target_velocity(RID p_agent, Vector3 p_velocity) const = 0;
-
- /// Position of the agent in world space.
- virtual void agent_set_position(RID p_agent, Vector3 p_position) const = 0;
-
- /// Agent ignore the Y axis and avoid collisions by moving only on the horizontal plane
- virtual void agent_set_ignore_y(RID p_agent, bool p_ignore) const = 0;
-
- /// Returns true if the map got changed the previous frame.
- virtual bool agent_is_map_changed(RID p_agent) const = 0;
-
- /// Callback called at the end of the RVO process
- virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const = 0;
-
- /// Destroy the `RID`
- virtual void free(RID p_object) const = 0;
-
- /// Control activation of this server.
- virtual void set_active(bool p_active) const = 0;
-
- /// Process the collision avoidance agents.
- /// The result of this process is needed by the physics server,
- /// so this must be called in the main thread.
- /// Note: This function is not thread safe.
- virtual void process(real_t delta_time) = 0;
-
- NavigationServer();
- virtual ~NavigationServer();
-};
-
-typedef NavigationServer *(*NavigationServerCallback)();
-
-/// Manager used for the server singleton registration
-class NavigationServerManager {
- static NavigationServerCallback create_callback;
-
-public:
- static void set_default_server(NavigationServerCallback p_callback);
- static NavigationServer *new_default_server();
-};
-
-#endif
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
new file mode 100644
index 0000000000..17f2232c72
--- /dev/null
+++ b/servers/navigation_server_2d.cpp
@@ -0,0 +1,229 @@
+/*************************************************************************/
+/* navigation_server_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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/navigation_server_2d.h"
+#include "core/math/transform.h"
+#include "core/math/transform_2d.h"
+#include "servers/navigation_server_3d.h"
+
+/**
+ @author AndreaCatania
+*/
+
+NavigationServer2D *NavigationServer2D::singleton = nullptr;
+
+#define FORWARD_0_C(FUNC_NAME) \
+ NavigationServer2D::FUNC_NAME() \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(); \
+ }
+
+#define FORWARD_1(FUNC_NAME, T_0, D_0, CONV_0) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0) { \
+ return NavigationServer3D::get_singleton_mut()->FUNC_NAME(CONV_0(D_0)); \
+ }
+
+#define FORWARD_1_C(FUNC_NAME, T_0, D_0, CONV_0) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
+ }
+
+#define FORWARD_2_C(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1)); \
+ }
+
+#define FORWARD_2_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1))); \
+ }
+
+#define FORWARD_4_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) \
+ 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))); \
+ }
+
+#define FORWARD_4_C(FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, CONV_0, CONV_1, CONV_2, CONV_3) \
+ NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3)); \
+ }
+
+static RID rid_to_rid(const RID d) {
+ return d;
+}
+static bool bool_to_bool(const bool d) {
+ return d;
+}
+static int int_to_int(const int d) {
+ return d;
+}
+static real_t real_to_real(const real_t d) {
+ return d;
+}
+static Vector3 v2_to_v3(const Vector2 d) {
+ return Vector3(d.x, 0.0, d.y);
+}
+static Vector2 v3_to_v2(const Vector3 &d) {
+ return Vector2(d.x, d.z);
+}
+static Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) {
+ Vector<Vector2> nd;
+ nd.resize(d.size());
+ for (int i(0); i < nd.size(); i++) {
+ nd.write[i] = v3_to_v2(d[i]);
+ }
+ return nd;
+}
+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());
+ return Transform(b, o);
+}
+static Object *obj_to_obj(Object *d) {
+ return d;
+}
+static StringName sn_to_sn(StringName &d) {
+ return d;
+}
+static Variant var_to_var(Variant &d) {
+ return d;
+}
+static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
+ if (d.is_valid()) {
+ return d->get_mesh();
+ } else {
+ return Ref<NavigationMesh>();
+ }
+}
+
+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);
+ ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer2D::map_is_active);
+ ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer2D::map_set_cell_size);
+ 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_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_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("agent_create"), &NavigationServer2D::agent_create);
+ ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
+ ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer2D::agent_set_neighbor_dist);
+ ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer2D::agent_set_max_neighbors);
+ ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer2D::agent_set_time_horizon);
+ ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer2D::agent_set_radius);
+ ClassDB::bind_method(D_METHOD("agent_set_max_speed", "agent", "max_speed"), &NavigationServer2D::agent_set_max_speed);
+ ClassDB::bind_method(D_METHOD("agent_set_velocity", "agent", "velocity"), &NavigationServer2D::agent_set_velocity);
+ ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer2D::agent_set_target_velocity);
+ ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer2D::agent_set_position);
+ ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer2D::agent_is_map_changed);
+ 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);
+}
+
+NavigationServer2D::NavigationServer2D() {
+ singleton = this;
+}
+
+NavigationServer2D::~NavigationServer2D() {
+ singleton = nullptr;
+}
+
+RID FORWARD_0_C(map_create);
+
+void FORWARD_2_C(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to_bool);
+
+bool FORWARD_1_C(map_is_active, RID, p_map, rid_to_rid);
+
+void FORWARD_2_C(map_set_cell_size, RID, p_map, real_t, p_cell_size, rid_to_rid, real_to_real);
+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);
+
+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_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));
+}
+
+RID NavigationServer2D::agent_create() const {
+ RID agent = NavigationServer3D::get_singleton()->agent_create();
+ NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, true);
+ return agent;
+}
+
+void FORWARD_2_C(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid);
+
+void FORWARD_2_C(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real);
+
+void FORWARD_2_C(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int);
+
+void FORWARD_2_C(agent_set_time_horizon, RID, p_agent, real_t, p_time, rid_to_rid, real_to_real);
+
+void FORWARD_2_C(agent_set_radius, RID, p_agent, real_t, p_radius, rid_to_rid, real_to_real);
+
+void FORWARD_2_C(agent_set_max_speed, RID, p_agent, real_t, p_max_speed, rid_to_rid, real_to_real);
+
+void FORWARD_2_C(agent_set_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
+
+void FORWARD_2_C(agent_set_target_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
+
+void FORWARD_2_C(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3);
+
+void FORWARD_2_C(agent_set_ignore_y, RID, p_agent, bool, p_ignore, rid_to_rid, bool_to_bool);
+
+bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
+
+void FORWARD_4_C(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, rid_to_rid, obj_to_obj, sn_to_sn, var_to_var);
+
+void FORWARD_1_C(free, RID, p_object, rid_to_rid);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
new file mode 100644
index 0000000000..d7384bae74
--- /dev/null
+++ b/servers/navigation_server_2d.h
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* navigation_server_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/**
+ @author AndreaCatania
+*/
+
+#ifndef NAVIGATION_2D_SERVER_H
+#define NAVIGATION_2D_SERVER_H
+
+#include "core/object.h"
+#include "core/rid.h"
+#include "scene/2d/navigation_region_2d.h"
+
+// This server exposes the `NavigationServer3D` features in the 2D world.
+class NavigationServer2D : public Object {
+ GDCLASS(NavigationServer2D, Object);
+
+ static NavigationServer2D *singleton;
+
+protected:
+ static void _bind_methods();
+
+public:
+ /// Thread safe, can be used across many threads.
+ static const NavigationServer2D *get_singleton() { return singleton; }
+
+ /// MUST be used in single thread!
+ static NavigationServer2D *get_singleton_mut() { return singleton; }
+
+ /// Create a new map.
+ virtual RID map_create() const;
+
+ /// Set map active.
+ virtual void map_set_active(RID p_map, bool p_active) const;
+
+ /// Returns true if the map is active.
+ virtual bool map_is_active(RID p_map) const;
+
+ /// Set the map cell size used to weld the navigation mesh polygons.
+ virtual void map_set_cell_size(RID p_map, real_t p_cell_size) const;
+
+ /// Returns the map cell size.
+ virtual real_t map_get_cell_size(RID p_map) const;
+
+ /// Set the map edge connection margin used to weld the compatible region edges.
+ virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) const;
+
+ /// Returns the edge connection margin of this map.
+ 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 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;
+
+ /// Creates a new region.
+ virtual RID region_create() const;
+
+ /// Set the map of this region.
+ virtual void region_set_map(RID p_region, RID p_map) 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;
+
+ /// Creates the agent.
+ virtual RID agent_create() const;
+
+ /// Put the agent in the map.
+ virtual void agent_set_map(RID p_agent, RID p_map) const;
+
+ /// The maximum distance (center point to
+ /// center point) to other agents this agent
+ /// takes into account in the navigation. The
+ /// larger this number, the longer the running
+ /// time of the simulation. If the number is too
+ /// low, the simulation will not be safe.
+ /// Must be non-negative.
+ virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const;
+
+ /// The maximum number of other agents this
+ /// agent takes into account in the navigation.
+ /// The larger this number, the longer the
+ /// running time of the simulation. If the
+ /// number is too low, the simulation will not
+ /// be safe.
+ virtual void agent_set_max_neighbors(RID p_agent, int p_count) const;
+
+ /// The minimal amount of time for which this
+ /// agent's velocities that are computed by the
+ /// simulation are safe with respect to other
+ /// agents. The larger this number, the sooner
+ /// this agent will respond to the presence of
+ /// other agents, but the less freedom this
+ /// agent has in choosing its velocities.
+ /// Must be positive.
+ virtual void agent_set_time_horizon(RID p_agent, real_t p_time) const;
+
+ /// The radius of this agent.
+ /// Must be non-negative.
+ virtual void agent_set_radius(RID p_agent, real_t p_radius) const;
+
+ /// The maximum speed of this agent.
+ /// Must be non-negative.
+ virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) const;
+
+ /// Current velocity of the agent
+ virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity) const;
+
+ /// The new target velocity.
+ virtual void agent_set_target_velocity(RID p_agent, Vector2 p_velocity) const;
+
+ /// Position of the agent in world space.
+ virtual void agent_set_position(RID p_agent, Vector2 p_position) const;
+
+ /// Agent ignore the Y axis and avoid collisions by moving only on the horizontal plane
+ virtual void agent_set_ignore_y(RID p_agent, bool p_ignore) const;
+
+ /// Returns true if the map got changed the previous frame.
+ virtual bool agent_is_map_changed(RID p_agent) const;
+
+ /// Callback called at the end of the RVO process
+ virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const;
+
+ /// Destroy the `RID`
+ virtual void free(RID p_object) const;
+
+ NavigationServer2D();
+ virtual ~NavigationServer2D();
+};
+
+#endif
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
new file mode 100644
index 0000000000..67a4d0e413
--- /dev/null
+++ b/servers/navigation_server_3d.cpp
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* navigation_server_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/**
+ @author AndreaCatania
+*/
+
+#include "navigation_server_3d.h"
+
+NavigationServer3D *NavigationServer3D::singleton = nullptr;
+
+void NavigationServer3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer3D::map_create);
+ ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer3D::map_set_active);
+ ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer3D::map_is_active);
+ ClassDB::bind_method(D_METHOD("map_set_up", "map", "up"), &NavigationServer3D::map_set_up);
+ ClassDB::bind_method(D_METHOD("map_get_up", "map"), &NavigationServer3D::map_get_up);
+ ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer3D::map_set_cell_size);
+ 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_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);
+ ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer3D::map_get_closest_point_owner);
+
+ 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_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("agent_create"), &NavigationServer3D::agent_create);
+ ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
+ ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer3D::agent_set_neighbor_dist);
+ ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer3D::agent_set_max_neighbors);
+ ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer3D::agent_set_time_horizon);
+ ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer3D::agent_set_radius);
+ ClassDB::bind_method(D_METHOD("agent_set_max_speed", "agent", "max_speed"), &NavigationServer3D::agent_set_max_speed);
+ ClassDB::bind_method(D_METHOD("agent_set_velocity", "agent", "velocity"), &NavigationServer3D::agent_set_velocity);
+ ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer3D::agent_set_target_velocity);
+ ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer3D::agent_set_position);
+ ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer3D::agent_is_map_changed);
+ ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &NavigationServer3D::agent_set_callback, DEFVAL(Variant()));
+
+ ClassDB::bind_method(D_METHOD("free", "object"), &NavigationServer3D::free);
+
+ ClassDB::bind_method(D_METHOD("set_active", "active"), &NavigationServer3D::set_active);
+ ClassDB::bind_method(D_METHOD("process", "delta_time"), &NavigationServer3D::process);
+}
+
+const NavigationServer3D *NavigationServer3D::get_singleton() {
+ return singleton;
+}
+
+NavigationServer3D *NavigationServer3D::get_singleton_mut() {
+ return singleton;
+}
+
+NavigationServer3D::NavigationServer3D() {
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
+}
+
+NavigationServer3D::~NavigationServer3D() {
+ singleton = nullptr;
+}
+
+NavigationServer3DCallback NavigationServer3DManager::create_callback = nullptr;
+
+void NavigationServer3DManager::set_default_server(NavigationServer3DCallback p_callback) {
+ create_callback = p_callback;
+}
+
+NavigationServer3D *NavigationServer3DManager::new_default_server() {
+ ERR_FAIL_COND_V(create_callback == nullptr, nullptr);
+ return create_callback();
+}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
new file mode 100644
index 0000000000..c34bd2391b
--- /dev/null
+++ b/servers/navigation_server_3d.h
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* navigation_server_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/**
+ @author AndreaCatania
+*/
+
+#ifndef NAVIGATION_SERVER_H
+#define NAVIGATION_SERVER_H
+
+#include "core/object.h"
+#include "core/rid.h"
+#include "scene/3d/navigation_region_3d.h"
+
+/// This server uses the concept of internal mutability.
+/// All the constant functions can be called in multithread because internally
+/// the server takes care to schedule the functions access.
+///
+/// Note: All the `set` functions are commands executed during the `sync` phase,
+/// don't expect that a change is immediately propagated.
+class NavigationServer3D : public Object {
+ GDCLASS(NavigationServer3D, Object);
+
+ static NavigationServer3D *singleton;
+
+protected:
+ static void _bind_methods();
+
+public:
+ /// Thread safe, can be used across many threads.
+ static const NavigationServer3D *get_singleton();
+
+ /// MUST be used in single thread!
+ static NavigationServer3D *get_singleton_mut();
+
+ /// Create a new map.
+ virtual RID map_create() const = 0;
+
+ /// Set map active.
+ virtual void map_set_active(RID p_map, bool p_active) const = 0;
+
+ /// Returns true if the map is active.
+ virtual bool map_is_active(RID p_map) const = 0;
+
+ /// Set the map UP direction.
+ virtual void map_set_up(RID p_map, Vector3 p_up) const = 0;
+
+ /// Returns the map UP direction.
+ virtual Vector3 map_get_up(RID p_map) const = 0;
+
+ /// Set the map cell size used to weld the navigation mesh polygons.
+ virtual void map_set_cell_size(RID p_map, real_t p_cell_size) const = 0;
+
+ /// Returns the map cell size.
+ virtual real_t map_get_cell_size(RID p_map) const = 0;
+
+ /// Set the map edge connection margin used to weld the compatible region edges.
+ virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) const = 0;
+
+ /// Returns the edge connection margin of this map.
+ 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 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;
+ virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const = 0;
+ virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const = 0;
+
+ /// Creates a new region.
+ virtual RID region_create() const = 0;
+
+ /// Set the map of this region.
+ virtual void region_set_map(RID p_region, RID p_map) 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
+ virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0;
+
+ /// Creates the agent.
+ virtual RID agent_create() const = 0;
+
+ /// Put the agent in the map.
+ virtual void agent_set_map(RID p_agent, RID p_map) const = 0;
+
+ /// The maximum distance (center point to
+ /// center point) to other agents this agent
+ /// takes into account in the navigation. The
+ /// larger this number, the longer the running
+ /// time of the simulation. If the number is too
+ /// low, the simulation will not be safe.
+ /// Must be non-negative.
+ virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const = 0;
+
+ /// The maximum number of other agents this
+ /// agent takes into account in the navigation.
+ /// The larger this number, the longer the
+ /// running time of the simulation. If the
+ /// number is too low, the simulation will not
+ /// be safe.
+ virtual void agent_set_max_neighbors(RID p_agent, int p_count) const = 0;
+
+ /// The minimal amount of time for which this
+ /// agent's velocities that are computed by the
+ /// simulation are safe with respect to other
+ /// agents. The larger this number, the sooner
+ /// this agent will respond to the presence of
+ /// other agents, but the less freedom this
+ /// agent has in choosing its velocities.
+ /// Must be positive.
+ virtual void agent_set_time_horizon(RID p_agent, real_t p_time) const = 0;
+
+ /// The radius of this agent.
+ /// Must be non-negative.
+ virtual void agent_set_radius(RID p_agent, real_t p_radius) const = 0;
+
+ /// The maximum speed of this agent.
+ /// Must be non-negative.
+ virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) const = 0;
+
+ /// Current velocity of the agent
+ virtual void agent_set_velocity(RID p_agent, Vector3 p_velocity) const = 0;
+
+ /// The new target velocity.
+ virtual void agent_set_target_velocity(RID p_agent, Vector3 p_velocity) const = 0;
+
+ /// Position of the agent in world space.
+ virtual void agent_set_position(RID p_agent, Vector3 p_position) const = 0;
+
+ /// Agent ignore the Y axis and avoid collisions by moving only on the horizontal plane
+ virtual void agent_set_ignore_y(RID p_agent, bool p_ignore) const = 0;
+
+ /// Returns true if the map got changed the previous frame.
+ virtual bool agent_is_map_changed(RID p_agent) const = 0;
+
+ /// Callback called at the end of the RVO process
+ virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const = 0;
+
+ /// Destroy the `RID`
+ virtual void free(RID p_object) const = 0;
+
+ /// Control activation of this server.
+ virtual void set_active(bool p_active) const = 0;
+
+ /// Process the collision avoidance agents.
+ /// The result of this process is needed by the physics server,
+ /// so this must be called in the main thread.
+ /// Note: This function is not thread safe.
+ virtual void process(real_t delta_time) = 0;
+
+ NavigationServer3D();
+ virtual ~NavigationServer3D();
+};
+
+typedef NavigationServer3D *(*NavigationServer3DCallback)();
+
+/// Manager used for the server singleton registration
+class NavigationServer3DManager {
+ static NavigationServer3DCallback create_callback;
+
+public:
+ static void set_default_server(NavigationServer3DCallback p_callback);
+ static NavigationServer3D *new_default_server();
+};
+
+#endif
diff --git a/servers/physics/SCsub b/servers/physics/SCsub
deleted file mode 100644
index c5cc889112..0000000000
--- a/servers/physics/SCsub
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.servers_sources, "*.cpp")
-
-SConscript("joints/SCsub")
diff --git a/servers/physics/area_pair_sw.cpp b/servers/physics/area_pair_sw.cpp
deleted file mode 100644
index 966a440930..0000000000
--- a/servers/physics/area_pair_sw.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*************************************************************************/
-/* area_pair_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "area_pair_sw.h"
-#include "collision_solver_sw.h"
-
-bool AreaPairSW::setup(real_t p_step) {
-
- bool result = false;
-
- if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) {
- result = false;
- } else if (area->test_collision_mask(body) && CollisionSolverSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), NULL, this)) {
- result = true;
- }
-
- if (result != colliding) {
-
- if (result) {
-
- if (area->get_space_override_mode() != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED)
- body->add_area(area);
- if (area->has_monitor_callback())
- area->add_body_to_query(body, body_shape, area_shape);
-
- } else {
-
- if (area->get_space_override_mode() != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED)
- body->remove_area(area);
- if (area->has_monitor_callback())
- area->remove_body_from_query(body, body_shape, area_shape);
- }
-
- colliding = result;
- }
-
- return false; //never do any post solving
-}
-
-void AreaPairSW::solve(real_t p_step) {
-}
-
-AreaPairSW::AreaPairSW(BodySW *p_body, int p_body_shape, AreaSW *p_area, int p_area_shape) {
-
- body = p_body;
- area = p_area;
- body_shape = p_body_shape;
- area_shape = p_area_shape;
- colliding = false;
- body->add_constraint(this, 0);
- area->add_constraint(this);
- if (p_body->get_mode() == PhysicsServer::BODY_MODE_KINEMATIC)
- p_body->set_active(true);
-}
-
-AreaPairSW::~AreaPairSW() {
-
- if (colliding) {
-
- if (area->get_space_override_mode() != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED)
- body->remove_area(area);
- if (area->has_monitor_callback())
- area->remove_body_from_query(body, body_shape, area_shape);
- }
- body->remove_constraint(this);
- area->remove_constraint(this);
-}
-
-////////////////////////////////////////////////////
-
-bool Area2PairSW::setup(real_t p_step) {
-
- bool result = false;
- if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) {
- result = false;
- } else if (area_a->test_collision_mask(area_b) && CollisionSolverSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), NULL, this)) {
- result = true;
- }
-
- if (result != colliding) {
-
- if (result) {
-
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
- area_b->add_area_to_query(area_a, shape_a, shape_b);
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
- area_a->add_area_to_query(area_b, shape_b, shape_a);
-
- } else {
-
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
-
- colliding = result;
- }
-
- return false; //never do any post solving
-}
-
-void Area2PairSW::solve(real_t p_step) {
-}
-
-Area2PairSW::Area2PairSW(AreaSW *p_area_a, int p_shape_a, AreaSW *p_area_b, int p_shape_b) {
-
- area_a = p_area_a;
- area_b = p_area_b;
- shape_a = p_shape_a;
- shape_b = p_shape_b;
- colliding = false;
- area_a->add_constraint(this);
- area_b->add_constraint(this);
-}
-
-Area2PairSW::~Area2PairSW() {
-
- if (colliding) {
-
- if (area_b->has_area_monitor_callback())
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
-
- if (area_a->has_area_monitor_callback())
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
-
- area_a->remove_constraint(this);
- area_b->remove_constraint(this);
-}
diff --git a/servers/physics/area_pair_sw.h b/servers/physics/area_pair_sw.h
deleted file mode 100644
index 97a37ebf90..0000000000
--- a/servers/physics/area_pair_sw.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*************************************************************************/
-/* area_pair_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 AREA_PAIR_SW_H
-#define AREA_PAIR_SW_H
-
-#include "area_sw.h"
-#include "body_sw.h"
-#include "constraint_sw.h"
-
-class AreaPairSW : public ConstraintSW {
-
- BodySW *body;
- AreaSW *area;
- int body_shape;
- int area_shape;
- bool colliding;
-
-public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
-
- AreaPairSW(BodySW *p_body, int p_body_shape, AreaSW *p_area, int p_area_shape);
- ~AreaPairSW();
-};
-
-class Area2PairSW : public ConstraintSW {
-
- AreaSW *area_a;
- AreaSW *area_b;
- int shape_a;
- int shape_b;
- bool colliding;
-
-public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
-
- Area2PairSW(AreaSW *p_area_a, int p_shape_a, AreaSW *p_area_b, int p_shape_b);
- ~Area2PairSW();
-};
-
-#endif // AREA_PAIR__SW_H
diff --git a/servers/physics/area_sw.cpp b/servers/physics/area_sw.cpp
deleted file mode 100644
index 4b54a56253..0000000000
--- a/servers/physics/area_sw.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/*************************************************************************/
-/* area_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "area_sw.h"
-#include "body_sw.h"
-#include "space_sw.h"
-
-AreaSW::BodyKey::BodyKey(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
- rid = p_body->get_self();
- instance_id = p_body->get_instance_id();
- body_shape = p_body_shape;
- area_shape = p_area_shape;
-}
-AreaSW::BodyKey::BodyKey(AreaSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
- rid = p_body->get_self();
- instance_id = p_body->get_instance_id();
- body_shape = p_body_shape;
- area_shape = p_area_shape;
-}
-
-void AreaSW::_shapes_changed() {
-
- if (!moved_list.in_list() && get_space())
- get_space()->area_add_to_moved_list(&moved_list);
-}
-
-void AreaSW::set_transform(const Transform &p_transform) {
-
- if (!moved_list.in_list() && get_space())
- get_space()->area_add_to_moved_list(&moved_list);
-
- _set_transform(p_transform);
- _set_inv_transform(p_transform.affine_inverse());
-}
-
-void AreaSW::set_space(SpaceSW *p_space) {
-
- if (get_space()) {
- if (monitor_query_list.in_list())
- get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
- if (moved_list.in_list())
- get_space()->area_remove_from_moved_list(&moved_list);
- }
-
- monitored_bodies.clear();
- monitored_areas.clear();
-
- _set_space(p_space);
-}
-
-void AreaSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) {
-
- if (p_id == monitor_callback_id) {
- monitor_callback_method = p_method;
- return;
- }
-
- _unregister_shapes();
-
- monitor_callback_id = p_id;
- monitor_callback_method = p_method;
-
- monitored_bodies.clear();
- monitored_areas.clear();
-
- _shape_changed();
-
- if (!moved_list.in_list() && get_space())
- get_space()->area_add_to_moved_list(&moved_list);
-}
-
-void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_method) {
-
- if (p_id == area_monitor_callback_id) {
- area_monitor_callback_method = p_method;
- return;
- }
-
- _unregister_shapes();
-
- area_monitor_callback_id = p_id;
- area_monitor_callback_method = p_method;
-
- monitored_bodies.clear();
- monitored_areas.clear();
-
- _shape_changed();
-
- if (!moved_list.in_list() && get_space())
- get_space()->area_add_to_moved_list(&moved_list);
-}
-
-void AreaSW::set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) {
- bool do_override = p_mode != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED;
- if (do_override == (space_override_mode != PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED))
- return;
- _unregister_shapes();
- space_override_mode = p_mode;
- _shape_changed();
-}
-
-void AreaSW::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) {
-
- switch (p_param) {
- case PhysicsServer::AREA_PARAM_GRAVITY: gravity = p_value; break;
- case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: gravity_vector = p_value; break;
- case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point = p_value; break;
- case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale = p_value; break;
- case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation = p_value; break;
- case PhysicsServer::AREA_PARAM_LINEAR_DAMP: linear_damp = p_value; break;
- case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: angular_damp = p_value; break;
- case PhysicsServer::AREA_PARAM_PRIORITY: priority = p_value; break;
- }
-}
-
-Variant AreaSW::get_param(PhysicsServer::AreaParameter p_param) const {
-
- switch (p_param) {
- case PhysicsServer::AREA_PARAM_GRAVITY: return gravity;
- case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
- case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
- case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale;
- case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation;
- case PhysicsServer::AREA_PARAM_LINEAR_DAMP: return linear_damp;
- case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
- case PhysicsServer::AREA_PARAM_PRIORITY: return priority;
- }
-
- return Variant();
-}
-
-void AreaSW::_queue_monitor_update() {
-
- ERR_FAIL_COND(!get_space());
-
- if (!monitor_query_list.in_list())
- get_space()->area_add_to_monitor_query_list(&monitor_query_list);
-}
-
-void AreaSW::set_monitorable(bool p_monitorable) {
-
- if (monitorable == p_monitorable)
- return;
-
- monitorable = p_monitorable;
- _set_static(!monitorable);
-}
-
-void AreaSW::call_queries() {
-
- if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) {
-
- Variant res[5];
- Variant *resptr[5];
- for (int i = 0; i < 5; i++)
- resptr[i] = &res[i];
-
- Object *obj = ObjectDB::get_instance(monitor_callback_id);
- if (!obj) {
- monitored_bodies.clear();
- monitor_callback_id = ObjectID();
- return;
- }
-
- for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E; E = E->next()) {
-
- if (E->get().state == 0)
- continue; //nothing happened
-
- res[0] = E->get().state > 0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::AREA_BODY_REMOVED;
- res[1] = E->key().rid;
- res[2] = E->key().instance_id;
- res[3] = E->key().body_shape;
- res[4] = E->key().area_shape;
-
- Callable::CallError ce;
- obj->call(monitor_callback_method, (const Variant **)resptr, 5, ce);
- }
- }
-
- monitored_bodies.clear();
-
- if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) {
-
- Variant res[5];
- Variant *resptr[5];
- for (int i = 0; i < 5; i++)
- resptr[i] = &res[i];
-
- Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
- if (!obj) {
- monitored_areas.clear();
- area_monitor_callback_id = ObjectID();
- return;
- }
-
- for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E; E = E->next()) {
-
- if (E->get().state == 0)
- continue; //nothing happened
-
- res[0] = E->get().state > 0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::AREA_BODY_REMOVED;
- res[1] = E->key().rid;
- res[2] = E->key().instance_id;
- res[3] = E->key().body_shape;
- res[4] = E->key().area_shape;
-
- Callable::CallError ce;
- obj->call(area_monitor_callback_method, (const Variant **)resptr, 5, ce);
- }
- }
-
- monitored_areas.clear();
- //get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
-}
-
-AreaSW::AreaSW() :
- CollisionObjectSW(TYPE_AREA),
- monitor_query_list(this),
- moved_list(this) {
-
- _set_static(true); //areas are never active
- space_override_mode = PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED;
- gravity = 9.80665;
- gravity_vector = Vector3(0, -1, 0);
- gravity_is_point = false;
- gravity_distance_scale = 0;
- point_attenuation = 1;
- angular_damp = 0.1;
- linear_damp = 0.1;
- priority = 0;
- set_ray_pickable(false);
- monitorable = false;
-}
-
-AreaSW::~AreaSW() {
-}
diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h
deleted file mode 100644
index 4da2b00d20..0000000000
--- a/servers/physics/area_sw.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*************************************************************************/
-/* area_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 AREA_SW_H
-#define AREA_SW_H
-
-#include "collision_object_sw.h"
-#include "core/self_list.h"
-#include "servers/physics_server.h"
-//#include "servers/physics/query_sw.h"
-
-class SpaceSW;
-class BodySW;
-class ConstraintSW;
-
-class AreaSW : public CollisionObjectSW {
-
- PhysicsServer::AreaSpaceOverrideMode space_override_mode;
- real_t gravity;
- Vector3 gravity_vector;
- bool gravity_is_point;
- real_t gravity_distance_scale;
- real_t point_attenuation;
- real_t linear_damp;
- real_t angular_damp;
- int priority;
- bool monitorable;
-
- ObjectID monitor_callback_id;
- StringName monitor_callback_method;
-
- ObjectID area_monitor_callback_id;
- StringName area_monitor_callback_method;
-
- SelfList<AreaSW> monitor_query_list;
- SelfList<AreaSW> moved_list;
-
- struct BodyKey {
-
- RID rid;
- ObjectID instance_id;
- uint32_t body_shape;
- uint32_t area_shape;
-
- _FORCE_INLINE_ bool operator<(const BodyKey &p_key) const {
-
- if (rid == p_key.rid) {
-
- if (body_shape == p_key.body_shape) {
-
- return area_shape < p_key.area_shape;
- } else
- return body_shape < p_key.body_shape;
- } else
- return rid < p_key.rid;
- }
-
- _FORCE_INLINE_ BodyKey() {}
- BodyKey(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
- BodyKey(AreaSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
- };
-
- struct BodyState {
-
- int state;
- _FORCE_INLINE_ void inc() { state++; }
- _FORCE_INLINE_ void dec() { state--; }
- _FORCE_INLINE_ BodyState() { state = 0; }
- };
-
- Map<BodyKey, BodyState> monitored_bodies;
- Map<BodyKey, BodyState> monitored_areas;
-
- //virtual void shape_changed_notify(ShapeSW *p_shape);
- //virtual void shape_deleted_notify(ShapeSW *p_shape);
-
- Set<ConstraintSW *> constraints;
-
- virtual void _shapes_changed();
- void _queue_monitor_update();
-
-public:
- //_FORCE_INLINE_ const Transform& get_inverse_transform() const { return inverse_transform; }
- //_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
-
- void set_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); }
-
- void set_area_monitor_callback(ObjectID p_id, const StringName &p_method);
- _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); }
-
- _FORCE_INLINE_ void add_body_to_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
- _FORCE_INLINE_ void remove_body_from_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
-
- _FORCE_INLINE_ void add_area_to_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
- _FORCE_INLINE_ void remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
-
- void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value);
- Variant get_param(PhysicsServer::AreaParameter p_param) const;
-
- void set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode);
- PhysicsServer::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; }
-
- _FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; }
- _FORCE_INLINE_ real_t get_gravity() const { return gravity; }
-
- _FORCE_INLINE_ void set_gravity_vector(const Vector3 &p_gravity) { gravity_vector = p_gravity; }
- _FORCE_INLINE_ Vector3 get_gravity_vector() const { return gravity_vector; }
-
- _FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point = p_enable; }
- _FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; }
-
- _FORCE_INLINE_ void set_gravity_distance_scale(real_t scale) { gravity_distance_scale = scale; }
- _FORCE_INLINE_ real_t get_gravity_distance_scale() const { return gravity_distance_scale; }
-
- _FORCE_INLINE_ void set_point_attenuation(real_t p_point_attenuation) { point_attenuation = p_point_attenuation; }
- _FORCE_INLINE_ real_t get_point_attenuation() const { return point_attenuation; }
-
- _FORCE_INLINE_ void set_linear_damp(real_t p_linear_damp) { linear_damp = p_linear_damp; }
- _FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
-
- _FORCE_INLINE_ void set_angular_damp(real_t p_angular_damp) { angular_damp = p_angular_damp; }
- _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
-
- _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
- _FORCE_INLINE_ int get_priority() const { return priority; }
-
- _FORCE_INLINE_ void add_constraint(ConstraintSW *p_constraint) { constraints.insert(p_constraint); }
- _FORCE_INLINE_ void remove_constraint(ConstraintSW *p_constraint) { constraints.erase(p_constraint); }
- _FORCE_INLINE_ const Set<ConstraintSW *> &get_constraints() const { return constraints; }
- _FORCE_INLINE_ void clear_constraints() { constraints.clear(); }
-
- void set_monitorable(bool p_monitorable);
- _FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
-
- void set_transform(const Transform &p_transform);
-
- void set_space(SpaceSW *p_space);
-
- void call_queries();
-
- AreaSW();
- ~AreaSW();
-};
-
-void AreaSW::add_body_to_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
-
- BodyKey bk(p_body, p_body_shape, p_area_shape);
- monitored_bodies[bk].inc();
- if (!monitor_query_list.in_list())
- _queue_monitor_update();
-}
-void AreaSW::remove_body_from_query(BodySW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
-
- BodyKey bk(p_body, p_body_shape, p_area_shape);
- monitored_bodies[bk].dec();
- if (!monitor_query_list.in_list())
- _queue_monitor_update();
-}
-
-void AreaSW::add_area_to_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
-
- BodyKey bk(p_area, p_area_shape, p_self_shape);
- monitored_areas[bk].inc();
- if (!monitor_query_list.in_list())
- _queue_monitor_update();
-}
-void AreaSW::remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
-
- BodyKey bk(p_area, p_area_shape, p_self_shape);
- monitored_areas[bk].dec();
- if (!monitor_query_list.in_list())
- _queue_monitor_update();
-}
-
-#endif // AREA__SW_H
diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp
deleted file mode 100644
index 31fc1b07d9..0000000000
--- a/servers/physics/body_pair_sw.cpp
+++ /dev/null
@@ -1,495 +0,0 @@
-/*************************************************************************/
-/* body_pair_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "body_pair_sw.h"
-
-#include "collision_solver_sw.h"
-#include "core/os/os.h"
-#include "space_sw.h"
-
-/*
-#define NO_ACCUMULATE_IMPULSES
-#define NO_SPLIT_IMPULSES
-
-#define NO_FRICTION
-*/
-
-#define NO_TANGENTIALS
-/* BODY PAIR */
-
-//#define ALLOWED_PENETRATION 0.01
-#define RELAXATION_TIMESTEPS 3
-#define MIN_VELOCITY 0.0001
-#define MAX_BIAS_ROTATION (Math_PI / 8)
-
-void BodyPairSW::_contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
-
- BodyPairSW *pair = (BodyPairSW *)p_userdata;
- pair->contact_added_callback(p_point_A, p_point_B);
-}
-
-void BodyPairSW::contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B) {
-
- // check if we already have the contact
-
- //Vector3 local_A = A->get_inv_transform().xform(p_point_A);
- //Vector3 local_B = B->get_inv_transform().xform(p_point_B);
-
- Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A);
- Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B);
-
- int new_index = contact_count;
-
- ERR_FAIL_COND(new_index >= (MAX_CONTACTS + 1));
-
- Contact contact;
-
- 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; // will be computed in setup()
-
- // attempt to determine if the contact will be reused
- real_t contact_recycle_radius = space->get_contact_recycle_radius();
-
- for (int i = 0; i < contact_count; i++) {
-
- Contact &c = contacts[i];
- 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;
- new_index = i;
- break;
- }
- }
-
- // figure out if the contact amount must be reduced to fit the new contact
-
- if (new_index == MAX_CONTACTS) {
-
- // remove the contact with the minimum depth
-
- int least_deep = -1;
- real_t min_depth = 1e10;
-
- for (int i = 0; i <= contact_count; i++) {
-
- Contact &c = (i == contact_count) ? contact : contacts[i];
- Vector3 global_A = A->get_transform().basis.xform(c.local_A);
- Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_B;
-
- Vector3 axis = global_A - global_B;
- real_t depth = axis.dot(c.normal);
-
- if (depth < min_depth) {
-
- min_depth = depth;
- least_deep = i;
- }
- }
-
- ERR_FAIL_COND(least_deep == -1);
-
- if (least_deep < contact_count) { //replace the last deep contact by the new one
-
- contacts[least_deep] = contact;
- }
-
- return;
- }
-
- contacts[new_index] = contact;
-
- if (new_index == contact_count) {
-
- contact_count++;
- }
-}
-
-void BodyPairSW::validate_contacts() {
-
- //make sure to erase contacts that are no longer valid
-
- real_t contact_max_separation = space->get_contact_max_separation();
- for (int i = 0; i < contact_count; i++) {
-
- Contact &c = contacts[i];
-
- Vector3 global_A = A->get_transform().basis.xform(c.local_A);
- Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_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 ((i + 1) < contact_count) {
- // swap with the last one
- SWAP(contacts[i], contacts[contact_count - 1]);
- }
-
- i--;
- contact_count--;
- }
- }
-}
-
-bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Transform &p_xform_A, BodySW *p_B, int p_shape_B, const Transform &p_xform_B) {
-
- Vector3 motion = p_A->get_linear_velocity() * p_step;
- real_t mlen = motion.length();
- if (mlen < CMP_EPSILON)
- return false;
-
- Vector3 mnormal = motion / mlen;
-
- real_t min, max;
- p_A->get_shape(p_shape_A)->project_range(mnormal, p_xform_A, min, max);
- bool fast_object = mlen > (max - min) * 0.3; //going too fast in that direction
-
- if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
- return false;
- }
-
- //cast a segment from support in motion normal, in the same direction of motion by motion length
- //support is the worst case collision point, so real collision happened before
- Vector3 s = p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform(mnormal).normalized());
- Vector3 from = p_xform_A.xform(s);
- Vector3 to = from + motion;
-
- Transform from_inv = p_xform_B.affine_inverse();
-
- Vector3 local_from = from_inv.xform(from - mnormal * mlen * 0.1); //start from a little inside the bounding box
- Vector3 local_to = from_inv.xform(to);
-
- Vector3 rpos, rnorm;
- if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm)) {
- return false;
- }
-
- //shorten the linear velocity so it does not hit, but gets close enough, next frame will hit softly or soft enough
- Vector3 hitpos = p_xform_B.xform(rpos);
-
- real_t newlen = hitpos.distance_to(from) - (max - min) * 0.01;
- p_A->set_linear_velocity((mnormal * newlen) / p_step);
-
- return true;
-}
-
-real_t combine_bounce(BodySW *A, BodySW *B) {
- return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1);
-}
-
-real_t combine_friction(BodySW *A, BodySW *B) {
- return ABS(MIN(A->get_friction(), B->get_friction()));
-}
-
-bool BodyPairSW::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() <= PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC && A->get_max_contacts_reported() == 0 && B->get_max_contacts_reported() == 0)) {
- 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;
- }
-
- offset_B = B->get_transform().get_origin() - A->get_transform().get_origin();
-
- validate_contacts();
-
- Vector3 offset_A = A->get_transform().get_origin();
- Transform xform_Au = Transform(A->get_transform().basis, Vector3());
- Transform xform_A = xform_Au * A->get_shape_transform(shape_A);
-
- Transform xform_Bu = B->get_transform();
- xform_Bu.origin -= offset_A;
- Transform xform_B = xform_Bu * B->get_shape_transform(shape_B);
-
- ShapeSW *shape_A_ptr = A->get_shape(shape_A);
- ShapeSW *shape_B_ptr = B->get_shape(shape_B);
-
- bool collided = CollisionSolverSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
- this->collided = collided;
-
- if (!collided) {
-
- //test ccd (currently just a raycast)
-
- if (A->is_continuous_collision_detection_enabled() && A->get_mode() > PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) {
- _test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B);
- }
-
- if (B->is_continuous_collision_detection_enabled() && B->get_mode() > PhysicsServer::BODY_MODE_KINEMATIC && A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) {
- _test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A);
- }
-
- return false;
- }
-
- real_t max_penetration = space->get_contact_max_allowed_penetration();
-
- real_t bias = (real_t)0.3;
-
- if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) {
-
- if (shape_A_ptr->get_custom_bias() == 0)
- bias = shape_B_ptr->get_custom_bias();
- else if (shape_B_ptr->get_custom_bias() == 0)
- bias = shape_A_ptr->get_custom_bias();
- else
- bias = (shape_B_ptr->get_custom_bias() + shape_A_ptr->get_custom_bias()) * 0.5;
- }
-
- real_t inv_dt = 1.0 / p_step;
-
- for (int i = 0; i < contact_count; i++) {
-
- Contact &c = contacts[i];
- c.active = false;
-
- Vector3 global_A = xform_Au.xform(c.local_A);
- Vector3 global_B = xform_Bu.xform(c.local_B);
-
- 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()) {
- space->add_debug_contact(global_A + offset_A);
- space->add_debug_contact(global_B + offset_A);
- }
-#endif
-
- c.rA = global_A - A->get_center_of_mass();
- c.rB = global_B - B->get_center_of_mass() - offset_B;
-
- // contact query reporting...
-
- if (A->can_report_contacts()) {
- Vector3 crA = A->get_angular_velocity().cross(c.rA) + A->get_linear_velocity();
- A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crA);
- }
-
- if (B->can_report_contacts()) {
- Vector3 crB = B->get_angular_velocity().cross(c.rB) + B->get_linear_velocity();
- B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crB);
- }
-
- c.active = true;
-
- // Precompute normal mass, tangent mass, and bias.
- Vector3 inertia_A = A->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
- Vector3 inertia_B = B->get_inv_inertia_tensor().xform(c.rB.cross(c.normal));
- real_t kNormal = A->get_inv_mass() + B->get_inv_mass();
- kNormal += c.normal.dot(inertia_A.cross(c.rA)) + c.normal.dot(inertia_B.cross(c.rB));
- 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;
- A->apply_impulse(c.rA + A->get_center_of_mass(), -j_vec);
- B->apply_impulse(c.rB + B->get_center_of_mass(), j_vec);
- c.acc_bias_impulse = 0;
- c.acc_bias_impulse_center_of_mass = 0;
-
- c.bounce = combine_bounce(A, B);
- if (c.bounce) {
-
- Vector3 crA = A->get_angular_velocity().cross(c.rA);
- Vector3 crB = B->get_angular_velocity().cross(c.rB);
- Vector3 dv = B->get_linear_velocity() + crB - A->get_linear_velocity() - crA;
- //normal impule
- c.bounce = c.bounce * dv.dot(c.normal);
- }
- }
-
- return true;
-}
-
-void BodyPairSW::solve(real_t p_step) {
-
- if (!collided)
- return;
-
- for (int i = 0; i < contact_count; i++) {
-
- Contact &c = contacts[i];
- if (!c.active)
- continue;
-
- c.active = false; //try to deactivate, will activate itself if still needed
-
- //bias impulse
-
- Vector3 crbA = A->get_biased_angular_velocity().cross(c.rA);
- Vector3 crbB = B->get_biased_angular_velocity().cross(c.rB);
- Vector3 dbv = B->get_biased_linear_velocity() + crbB - A->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);
-
- A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step);
- B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step);
-
- crbA = A->get_biased_angular_velocity().cross(c.rA);
- crbB = B->get_biased_angular_velocity().cross(c.rB);
- dbv = B->get_biased_linear_velocity() + crbB - A->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) / (A->get_inv_mass() + B->get_inv_mass());
- 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);
-
- A->apply_bias_impulse(A->get_center_of_mass(), -jb_com, 0.0f);
- B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f);
- }
-
- c.active = true;
- }
-
- Vector3 crA = A->get_angular_velocity().cross(c.rA);
- Vector3 crB = B->get_angular_velocity().cross(c.rB);
- Vector3 dv = B->get_linear_velocity() + crB - A->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);
-
- A->apply_impulse(c.rA + A->get_center_of_mass(), -j);
- B->apply_impulse(c.rB + B->get_center_of_mass(), j);
-
- c.active = true;
- }
-
- //friction impulse
-
- real_t friction = combine_friction(A, B);
-
- Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA);
- Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB);
-
- 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 = A->get_inv_inertia_tensor().xform(c.rA.cross(tv));
- Vector3 temp2 = B->get_inv_inertia_tensor().xform(c.rB.cross(tv));
-
- real_t t = -tvl /
- (A->get_inv_mass() + B->get_inv_mass() + tv.dot(temp1.cross(c.rA) + temp2.cross(c.rB)));
-
- 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;
-
- A->apply_impulse(c.rA + A->get_center_of_mass(), -jt);
- B->apply_impulse(c.rB + B->get_center_of_mass(), jt);
-
- c.active = true;
- }
- }
-}
-
-BodyPairSW::BodyPairSW(BodySW *p_A, int p_shape_A, BodySW *p_B, int p_shape_B) :
- ConstraintSW(_arr, 2) {
-
- A = p_A;
- B = p_B;
- shape_A = p_shape_A;
- shape_B = p_shape_B;
- space = A->get_space();
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
- contact_count = 0;
- collided = false;
-}
-
-BodyPairSW::~BodyPairSW() {
-
- A->remove_constraint(this);
- B->remove_constraint(this);
-}
diff --git a/servers/physics/body_pair_sw.h b/servers/physics/body_pair_sw.h
deleted file mode 100644
index 235aab23b5..0000000000
--- a/servers/physics/body_pair_sw.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*************************************************************************/
-/* body_pair_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BODY_PAIR_SW_H
-#define BODY_PAIR_SW_H
-
-#include "body_sw.h"
-#include "constraint_sw.h"
-
-class BodyPairSW : public ConstraintSW {
- enum {
-
- MAX_CONTACTS = 4
- };
-
- union {
- struct {
- BodySW *A;
- BodySW *B;
- };
-
- BodySW *_arr[2];
- };
-
- int shape_A;
- int shape_B;
-
- struct Contact {
-
- Vector3 position;
- Vector3 normal;
- Vector3 local_A, local_B;
- real_t acc_normal_impulse; // accumulated normal impulse (Pn)
- Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
- real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb)
- real_t acc_bias_impulse_center_of_mass; // accumulated normal impulse for position bias applied to com
- real_t mass_normal;
- real_t bias;
- real_t bounce;
-
- real_t depth;
- bool active;
- Vector3 rA, rB; // Offset in world orientation with respect to center of mass
- };
-
- 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);
-
- void contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B);
-
- void validate_contacts();
- bool _test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Transform &p_xform_A, BodySW *p_B, int p_shape_B, const Transform &p_xform_B);
-
- SpaceSW *space;
-
-public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
-
- BodyPairSW(BodySW *p_A, int p_shape_A, BodySW *p_B, int p_shape_B);
- ~BodyPairSW();
-};
-
-#endif // BODY_PAIR__SW_H
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
deleted file mode 100644
index 8819941f04..0000000000
--- a/servers/physics/body_sw.cpp
+++ /dev/null
@@ -1,814 +0,0 @@
-/*************************************************************************/
-/* body_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "body_sw.h"
-#include "area_sw.h"
-#include "space_sw.h"
-
-void BodySW::_update_inertia() {
-
- if (get_space() && !inertia_update_list.in_list())
- get_space()->body_add_to_inertia_update_list(&inertia_update_list);
-}
-
-void BodySW::_update_transform_dependant() {
-
- center_of_mass = get_transform().basis.xform(center_of_mass_local);
- principal_inertia_axes = get_transform().basis * principal_inertia_axes_local;
-
- // update inertia tensor
- Basis tb = principal_inertia_axes;
- Basis tbt = tb.transposed();
- Basis diag;
- diag.scale(_inv_inertia);
- _inv_inertia_tensor = tb * diag * tbt;
-}
-
-void BodySW::update_inertias() {
-
- //update shapes and motions
-
- switch (mode) {
-
- case PhysicsServer::BODY_MODE_RIGID: {
-
- //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
- center_of_mass_local.zero();
-
- for (int i = 0; i < get_shape_count(); i++) {
- real_t area = get_shape_area(i);
-
- real_t mass = area * this->mass / total_area;
-
- // 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
- Basis inertia_tensor;
- inertia_tensor.set_zero();
-
- for (int i = 0; i < get_shape_count(); i++) {
-
- if (is_shape_disabled(i)) {
- continue;
- }
-
- const ShapeSW *shape = get_shape(i);
-
- real_t area = get_shape_area(i);
-
- real_t mass = area * this->mass / total_area;
-
- Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix();
- Transform shape_transform = get_shape_transform(i);
- Basis shape_basis = shape_transform.basis.orthonormalized();
-
- // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor!
- shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
-
- Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
- inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
- }
-
- // Compute the principal axes of inertia
- principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
- _inv_inertia = inertia_tensor.get_main_diagonal().inverse();
-
- if (mass)
- _inv_mass = 1.0 / mass;
- else
- _inv_mass = 0;
-
- } break;
-
- case PhysicsServer::BODY_MODE_KINEMATIC:
- case PhysicsServer::BODY_MODE_STATIC: {
-
- _inv_inertia_tensor.set_zero();
- _inv_mass = 0;
- } break;
- case PhysicsServer::BODY_MODE_CHARACTER: {
-
- _inv_inertia_tensor.set_zero();
- _inv_mass = 1.0 / mass;
-
- } break;
- }
-
- //_update_shapes();
-
- _update_transform_dependant();
-}
-
-void BodySW::set_active(bool p_active) {
-
- if (active == p_active)
- return;
-
- active = p_active;
- if (!p_active) {
- if (get_space())
- get_space()->body_remove_from_active_list(&active_list);
- } else {
- if (mode == PhysicsServer::BODY_MODE_STATIC)
- return; //static bodies can't become active
- if (get_space())
- get_space()->body_add_to_active_list(&active_list);
-
- //still_time=0;
- }
- /*
- if (!space)
- return;
-
- for(int i=0;i<get_shape_count();i++) {
- Shape &s=shapes[i];
- if (s.bpid>0) {
- get_space()->get_broadphase()->set_active(s.bpid,active);
- }
- }
-*/
-}
-
-void BodySW::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) {
-
- switch (p_param) {
- case PhysicsServer::BODY_PARAM_BOUNCE: {
-
- bounce = p_value;
- } break;
- case PhysicsServer::BODY_PARAM_FRICTION: {
-
- friction = p_value;
- } break;
- case PhysicsServer::BODY_PARAM_MASS: {
- ERR_FAIL_COND(p_value <= 0);
- mass = p_value;
- _update_inertia();
-
- } break;
- case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: {
- gravity_scale = p_value;
- } break;
- case PhysicsServer::BODY_PARAM_LINEAR_DAMP: {
-
- linear_damp = p_value;
- } break;
- case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: {
-
- angular_damp = p_value;
- } break;
- default: {
- }
- }
-}
-
-real_t BodySW::get_param(PhysicsServer::BodyParameter p_param) const {
-
- switch (p_param) {
- case PhysicsServer::BODY_PARAM_BOUNCE: {
-
- return bounce;
- } break;
- case PhysicsServer::BODY_PARAM_FRICTION: {
-
- return friction;
- } break;
- case PhysicsServer::BODY_PARAM_MASS: {
- return mass;
- } break;
- case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: {
- return gravity_scale;
- } break;
- case PhysicsServer::BODY_PARAM_LINEAR_DAMP: {
-
- return linear_damp;
- } break;
- case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: {
-
- return angular_damp;
- } break;
-
- default: {
- }
- }
-
- return 0;
-}
-
-void BodySW::set_mode(PhysicsServer::BodyMode p_mode) {
-
- PhysicsServer::BodyMode prev = mode;
- mode = p_mode;
-
- switch (p_mode) {
- //CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
- case PhysicsServer::BODY_MODE_STATIC:
- case PhysicsServer::BODY_MODE_KINEMATIC: {
-
- _set_inv_transform(get_transform().affine_inverse());
- _inv_mass = 0;
- _set_static(p_mode == PhysicsServer::BODY_MODE_STATIC);
- //set_active(p_mode==PhysicsServer::BODY_MODE_KINEMATIC);
- set_active(p_mode == PhysicsServer::BODY_MODE_KINEMATIC && contacts.size());
- linear_velocity = Vector3();
- angular_velocity = Vector3();
- if (mode == PhysicsServer::BODY_MODE_KINEMATIC && prev != mode) {
- first_time_kinematic = true;
- }
-
- } break;
- case PhysicsServer::BODY_MODE_RIGID: {
-
- _inv_mass = mass > 0 ? (1.0 / mass) : 0;
- _set_static(false);
- set_active(true);
-
- } break;
- case PhysicsServer::BODY_MODE_CHARACTER: {
-
- _inv_mass = mass > 0 ? (1.0 / mass) : 0;
- _set_static(false);
- set_active(true);
- angular_velocity = Vector3();
- } break;
- }
-
- _update_inertia();
- /*
- if (get_space())
- _update_queries();
- */
-}
-PhysicsServer::BodyMode BodySW::get_mode() const {
-
- return mode;
-}
-
-void BodySW::_shapes_changed() {
-
- _update_inertia();
-}
-
-void BodySW::set_state(PhysicsServer::BodyState p_state, const Variant &p_variant) {
-
- switch (p_state) {
- case PhysicsServer::BODY_STATE_TRANSFORM: {
-
- if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
- new_transform = p_variant;
- //wakeup_neighbours();
- set_active(true);
- if (first_time_kinematic) {
- _set_transform(p_variant);
- _set_inv_transform(get_transform().affine_inverse());
- first_time_kinematic = false;
- }
-
- } else if (mode == PhysicsServer::BODY_MODE_STATIC) {
- _set_transform(p_variant);
- _set_inv_transform(get_transform().affine_inverse());
- wakeup_neighbours();
- } else {
- Transform t = p_variant;
- t.orthonormalize();
- new_transform = get_transform(); //used as old to compute motion
- if (new_transform == t)
- break;
- _set_transform(t);
- _set_inv_transform(get_transform().inverse());
- }
- wakeup();
-
- } break;
- case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: {
-
- /*
- if (mode==PhysicsServer::BODY_MODE_STATIC)
- break;
- */
- linear_velocity = p_variant;
- wakeup();
- } break;
- case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: {
- /*
- if (mode!=PhysicsServer::BODY_MODE_RIGID)
- break;
- */
- angular_velocity = p_variant;
- wakeup();
-
- } break;
- case PhysicsServer::BODY_STATE_SLEEPING: {
- //?
- if (mode == PhysicsServer::BODY_MODE_STATIC || mode == PhysicsServer::BODY_MODE_KINEMATIC)
- break;
- bool do_sleep = p_variant;
- if (do_sleep) {
- linear_velocity = Vector3();
- //biased_linear_velocity=Vector3();
- angular_velocity = Vector3();
- //biased_angular_velocity=Vector3();
- set_active(false);
- } else {
- set_active(true);
- }
- } break;
- case PhysicsServer::BODY_STATE_CAN_SLEEP: {
- can_sleep = p_variant;
- if (mode == PhysicsServer::BODY_MODE_RIGID && !active && !can_sleep)
- set_active(true);
-
- } break;
- }
-}
-Variant BodySW::get_state(PhysicsServer::BodyState p_state) const {
-
- switch (p_state) {
- case PhysicsServer::BODY_STATE_TRANSFORM: {
- return get_transform();
- } break;
- case PhysicsServer::BODY_STATE_LINEAR_VELOCITY: {
- return linear_velocity;
- } break;
- case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY: {
- return angular_velocity;
- } break;
- case PhysicsServer::BODY_STATE_SLEEPING: {
- return !is_active();
- } break;
- case PhysicsServer::BODY_STATE_CAN_SLEEP: {
- return can_sleep;
- } break;
- }
-
- return Variant();
-}
-
-void BodySW::set_space(SpaceSW *p_space) {
-
- if (get_space()) {
-
- if (inertia_update_list.in_list())
- get_space()->body_remove_from_inertia_update_list(&inertia_update_list);
- if (active_list.in_list())
- get_space()->body_remove_from_active_list(&active_list);
- if (direct_state_query_list.in_list())
- get_space()->body_remove_from_state_query_list(&direct_state_query_list);
- }
-
- _set_space(p_space);
-
- if (get_space()) {
-
- _update_inertia();
- if (active)
- get_space()->body_add_to_active_list(&active_list);
- /*
- _update_queries();
- if (is_active()) {
- active=false;
- set_active(true);
- }
- */
- }
-
- first_integration = true;
-}
-
-void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) {
-
- if (p_area->is_gravity_point()) {
- if (p_area->get_gravity_distance_scale() > 0) {
- Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
- gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
- } else {
- gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
- }
- } else {
- gravity += p_area->get_gravity_vector() * p_area->get_gravity();
- }
-
- area_linear_damp += p_area->get_linear_damp();
- area_angular_damp += p_area->get_angular_damp();
-}
-
-void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
- if (lock) {
- locked_axis |= p_axis;
- } else {
- locked_axis &= ~p_axis;
- }
-}
-
-bool BodySW::is_axis_locked(PhysicsServer::BodyAxis p_axis) const {
- return locked_axis & p_axis;
-}
-
-void BodySW::integrate_forces(real_t p_step) {
-
- if (mode == PhysicsServer::BODY_MODE_STATIC)
- return;
-
- AreaSW *def_area = get_space()->get_default_area();
- // AreaSW *damp_area = def_area;
-
- ERR_FAIL_COND(!def_area);
-
- int ac = areas.size();
- bool stopped = false;
- gravity = Vector3(0, 0, 0);
- area_linear_damp = 0;
- area_angular_damp = 0;
- if (ac) {
- areas.sort();
- const AreaCMP *aa = &areas[0];
- // damp_area = aa[ac-1].area;
- for (int i = ac - 1; i >= 0 && !stopped; i--) {
- PhysicsServer::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
- switch (mode) {
- case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE:
- case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
- _compute_area_gravity_and_dampenings(aa[i].area);
- stopped = mode == PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
- } break;
- case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE:
- case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
- gravity = Vector3(0, 0, 0);
- area_angular_damp = 0;
- area_linear_damp = 0;
- _compute_area_gravity_and_dampenings(aa[i].area);
- stopped = mode == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE;
- } break;
- default: {
- }
- }
- }
- }
-
- if (!stopped) {
- _compute_area_gravity_and_dampenings(def_area);
- }
-
- gravity *= gravity_scale;
-
- // If less than 0, override dampenings with that of the Body
- if (angular_damp >= 0)
- area_angular_damp = angular_damp;
- /*
- else
- area_angular_damp=damp_area->get_angular_damp();
- */
-
- if (linear_damp >= 0)
- area_linear_damp = linear_damp;
- /*
- else
- area_linear_damp=damp_area->get_linear_damp();
- */
-
- Vector3 motion;
- bool do_motion = false;
-
- if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
-
- //compute motion, angular and etc. velocities from prev transform
- linear_velocity = (new_transform.origin - get_transform().origin) / p_step;
-
- //compute a FAKE angular velocity, not so easy
- Basis rot = new_transform.basis.orthonormalized().transposed() * get_transform().basis.orthonormalized();
- 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;
-
- } else {
- if (!omit_force_integration && !first_integration) {
- //overridden by direct state query
-
- Vector3 force = gravity * mass;
- force += applied_force;
- Vector3 torque = applied_torque;
-
- real_t damp = 1.0 - p_step * area_linear_damp;
-
- if (damp < 0) // reached zero in the given time
- damp = 0;
-
- real_t angular_damp = 1.0 - p_step * area_angular_damp;
-
- if (angular_damp < 0) // reached zero in the given time
- angular_damp = 0;
-
- linear_velocity *= damp;
- angular_velocity *= angular_damp;
-
- linear_velocity += _inv_mass * force * p_step;
- angular_velocity += _inv_inertia_tensor.xform(torque) * p_step;
- }
-
- if (continuous_cd) {
- motion = linear_velocity * p_step;
- do_motion = true;
- }
- }
-
- applied_force = Vector3();
- applied_torque = Vector3();
- first_integration = false;
-
- //motion=linear_velocity*p_step;
-
- biased_angular_velocity = Vector3();
- biased_linear_velocity = Vector3();
-
- if (do_motion) { //shapes temporarily extend for raycast
- _update_shapes_with_motion(motion);
- }
-
- def_area = NULL; // clear the area, so it is set in the next frame
- contact_count = 0;
-}
-
-void BodySW::integrate_velocities(real_t p_step) {
-
- if (mode == PhysicsServer::BODY_MODE_STATIC)
- return;
-
- if (fi_callback)
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
-
- //apply axis lock linear
- for (int i = 0; i < 3; i++) {
- if (is_axis_locked((PhysicsServer::BodyAxis)(1 << i))) {
- linear_velocity[i] = 0;
- biased_linear_velocity[i] = 0;
- new_transform.origin[i] = get_transform().origin[i];
- }
- }
- //apply axis lock angular
- for (int i = 0; i < 3; i++) {
- if (is_axis_locked((PhysicsServer::BodyAxis)(1 << (i + 3)))) {
- angular_velocity[i] = 0;
- biased_angular_velocity[i] = 0;
- }
- }
-
- if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
-
- _set_transform(new_transform, false);
- _set_inv_transform(new_transform.affine_inverse());
- if (contacts.size() == 0 && linear_velocity == Vector3() && angular_velocity == Vector3())
- set_active(false); //stopped moving, deactivate
-
- return;
- }
-
- Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity;
-
- real_t ang_vel = total_angular_velocity.length();
- Transform transform = get_transform();
-
- if (ang_vel != 0.0) {
- Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
- Basis rot(ang_vel_axis, ang_vel * p_step);
- Basis identity3(1, 0, 0, 0, 1, 0, 0, 0, 1);
- transform.origin += ((identity3 - rot) * transform.basis).xform(center_of_mass_local);
- transform.basis = rot * transform.basis;
- transform.orthonormalize();
- }
-
- Vector3 total_linear_velocity = linear_velocity + biased_linear_velocity;
- /*for(int i=0;i<3;i++) {
- if (axis_lock&(1<<i)) {
- transform.origin[i]=0.0;
- }
- }*/
-
- transform.origin += total_linear_velocity * p_step;
-
- _set_transform(transform);
- _set_inv_transform(get_transform().inverse());
-
- _update_transform_dependant();
-
- /*
- if (fi_callback) {
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
- */
-}
-
-/*
-void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) {
-
- Transform inv_xform = p_xform.affine_inverse();
- if (!get_space()) {
- _set_transform(p_xform);
- _set_inv_transform(inv_xform);
-
- return;
- }
-
- //compute a FAKE linear velocity - this is easy
-
- linear_velocity=(p_xform.origin - get_transform().origin)/p_step;
-
- //compute a FAKE angular velocity, not so easy
- Basis rot=get_transform().basis.orthonormalized().transposed() * p_xform.basis.orthonormalized();
- Vector3 axis;
- real_t angle;
-
- rot.get_axis_angle(axis,angle);
- axis.normalize();
- angular_velocity=axis.normalized() * (angle/p_step);
- linear_velocity = (p_xform.origin - get_transform().origin)/p_step;
-
- if (!direct_state_query_list.in_list())// - callalways, so lv and av are cleared && (state_query || direct_state_query))
- get_space()->body_add_to_state_query_list(&direct_state_query_list);
- simulated_motion=true;
- _set_transform(p_xform);
-
-
-}
-*/
-
-void BodySW::wakeup_neighbours() {
-
- for (Map<ConstraintSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) {
-
- const ConstraintSW *c = E->key();
- BodySW **n = c->get_body_ptr();
- int bc = c->get_body_count();
-
- for (int i = 0; i < bc; i++) {
-
- if (i == E->get())
- continue;
- BodySW *b = n[i];
- if (b->mode != PhysicsServer::BODY_MODE_RIGID)
- continue;
-
- if (!b->is_active())
- b->set_active(true);
- }
- }
-}
-
-void BodySW::call_queries() {
-
- if (fi_callback) {
-
- PhysicsDirectBodyStateSW *dbs = PhysicsDirectBodyStateSW::singleton;
- dbs->body = this;
-
- Variant v = dbs;
-
- Object *obj = ObjectDB::get_instance(fi_callback->id);
- if (!obj) {
-
- set_force_integration_callback(ObjectID(), StringName());
- } 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);
- }
- }
-}
-
-bool BodySW::sleep_test(real_t p_step) {
-
- if (mode == PhysicsServer::BODY_MODE_STATIC || mode == PhysicsServer::BODY_MODE_KINEMATIC)
- return true; //
- else if (mode == PhysicsServer::BODY_MODE_CHARACTER)
- return !active; // characters don't sleep unless asked to sleep
- else if (!can_sleep)
- return false;
-
- if (Math::abs(angular_velocity.length()) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) {
-
- still_time += p_step;
-
- return still_time > get_space()->get_body_time_to_sleep();
- } else {
-
- still_time = 0; //maybe this should be set to 0 on set_active?
- return false;
- }
-}
-
-void BodySW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
-
- if (fi_callback) {
-
- memdelete(fi_callback);
- fi_callback = NULL;
- }
-
- if (p_id.is_valid()) {
-
- fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
- fi_callback->udata = p_udata;
- }
-}
-
-void BodySW::set_kinematic_margin(real_t p_margin) {
- kinematic_safe_margin = p_margin;
-}
-
-BodySW::BodySW() :
- CollisionObjectSW(TYPE_BODY),
- locked_axis(0),
- active_list(this),
- inertia_update_list(this),
- direct_state_query_list(this) {
-
- mode = PhysicsServer::BODY_MODE_RIGID;
- active = true;
-
- mass = 1;
- kinematic_safe_margin = 0.01;
- //_inv_inertia=Transform();
- _inv_mass = 1;
- bounce = 0;
- friction = 1;
- omit_force_integration = false;
- //applied_torque=0;
- island_step = 0;
- island_next = NULL;
- island_list_next = NULL;
- first_time_kinematic = false;
- first_integration = false;
- _set_static(false);
-
- contact_count = 0;
- gravity_scale = 1.0;
- linear_damp = -1;
- angular_damp = -1;
- area_angular_damp = 0;
- area_linear_damp = 0;
-
- still_time = 0;
- continuous_cd = false;
- can_sleep = true;
- fi_callback = NULL;
-}
-
-BodySW::~BodySW() {
-
- if (fi_callback)
- memdelete(fi_callback);
-}
-
-PhysicsDirectBodyStateSW *PhysicsDirectBodyStateSW::singleton = NULL;
-
-PhysicsDirectSpaceState *PhysicsDirectBodyStateSW::get_space_state() {
-
- return body->get_space()->get_direct_state();
-}
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
deleted file mode 100644
index d712b09878..0000000000
--- a/servers/physics/body_sw.h
+++ /dev/null
@@ -1,475 +0,0 @@
-/*************************************************************************/
-/* body_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BODY_SW_H
-#define BODY_SW_H
-
-#include "area_sw.h"
-#include "collision_object_sw.h"
-#include "core/vset.h"
-
-class ConstraintSW;
-
-class BodySW : public CollisionObjectSW {
-
- PhysicsServer::BodyMode mode;
-
- Vector3 linear_velocity;
- Vector3 angular_velocity;
-
- Vector3 biased_linear_velocity;
- Vector3 biased_angular_velocity;
- real_t mass;
- real_t bounce;
- real_t friction;
-
- real_t linear_damp;
- real_t angular_damp;
- real_t gravity_scale;
-
- uint16_t locked_axis;
-
- real_t kinematic_safe_margin;
- real_t _inv_mass;
- Vector3 _inv_inertia; // Relative to the principal axes of inertia
-
- // Relative to the local frame of reference
- Basis principal_inertia_axes_local;
- Vector3 center_of_mass_local;
-
- // In world orientation with local origin
- Basis _inv_inertia_tensor;
- Basis principal_inertia_axes;
- Vector3 center_of_mass;
-
- Vector3 gravity;
-
- real_t still_time;
-
- Vector3 applied_force;
- Vector3 applied_torque;
-
- real_t area_angular_damp;
- real_t area_linear_damp;
-
- SelfList<BodySW> active_list;
- SelfList<BodySW> inertia_update_list;
- SelfList<BodySW> direct_state_query_list;
-
- VSet<RID> exceptions;
- bool omit_force_integration;
- bool active;
-
- bool first_integration;
-
- bool continuous_cd;
- bool can_sleep;
- bool first_time_kinematic;
- void _update_inertia();
- virtual void _shapes_changed();
- Transform new_transform;
-
- Map<ConstraintSW *, int> constraint_map;
-
- struct AreaCMP {
-
- AreaSW *area;
- int refCount;
- _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); }
- _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); }
- _FORCE_INLINE_ AreaCMP() {}
- _FORCE_INLINE_ AreaCMP(AreaSW *p_area) {
- area = p_area;
- refCount = 1;
- }
- };
-
- Vector<AreaCMP> areas;
-
- struct Contact {
-
- Vector3 local_pos;
- Vector3 local_normal;
- real_t depth;
- int local_shape;
- Vector3 collider_pos;
- int collider_shape;
- ObjectID collider_instance_id;
- RID collider;
- Vector3 collider_velocity_at_pos;
- };
-
- Vector<Contact> contacts; //no contacts by default
- int contact_count;
-
- struct ForceIntegrationCallback {
-
- ObjectID id;
- StringName method;
- Variant udata;
- };
-
- ForceIntegrationCallback *fi_callback;
-
- uint64_t island_step;
- BodySW *island_next;
- BodySW *island_list_next;
-
- _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const AreaSW *p_area);
-
- _FORCE_INLINE_ void _update_transform_dependant();
-
- friend class PhysicsDirectBodyStateSW; // 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_kinematic_margin(real_t p_margin);
- _FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; }
-
- _FORCE_INLINE_ void add_area(AreaSW *p_area) {
- int index = areas.find(AreaCMP(p_area));
- if (index > -1) {
- areas.write[index].refCount += 1;
- } else {
- areas.ordered_insert(AreaCMP(p_area));
- }
- }
-
- _FORCE_INLINE_ void remove_area(AreaSW *p_area) {
- int index = areas.find(AreaCMP(p_area));
- if (index > -1) {
- areas.write[index].refCount -= 1;
- if (areas[index].refCount < 1)
- areas.remove(index);
- }
- }
-
- _FORCE_INLINE_ void set_max_contacts_reported(int p_size) {
- contacts.resize(p_size);
- contact_count = 0;
- if (mode == PhysicsServer::BODY_MODE_KINEMATIC && p_size) set_active(true);
- }
- _FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }
-
- _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); }
- _FORCE_INLINE_ void add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos);
-
- _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; }
-
- _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_ BodySW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(BodySW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ BodySW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(BodySW *p_next) { island_list_next = p_next; }
-
- _FORCE_INLINE_ void add_constraint(ConstraintSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
- _FORCE_INLINE_ void remove_constraint(ConstraintSW *p_constraint) { constraint_map.erase(p_constraint); }
- const Map<ConstraintSW *, int> &get_constraint_map() const { return constraint_map; }
- _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); }
-
- _FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
- _FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; }
-
- _FORCE_INLINE_ Basis get_principal_inertia_axes() const { return principal_inertia_axes; }
- _FORCE_INLINE_ Vector3 get_center_of_mass() const { return center_of_mass; }
- _FORCE_INLINE_ Vector3 xform_local_to_principal(const Vector3 &p_pos) const { return principal_inertia_axes_local.xform(p_pos - center_of_mass_local); }
-
- _FORCE_INLINE_ void set_linear_velocity(const Vector3 &p_velocity) { linear_velocity = p_velocity; }
- _FORCE_INLINE_ Vector3 get_linear_velocity() const { return linear_velocity; }
-
- _FORCE_INLINE_ void set_angular_velocity(const Vector3 &p_velocity) { angular_velocity = p_velocity; }
- _FORCE_INLINE_ Vector3 get_angular_velocity() const { return angular_velocity; }
-
- _FORCE_INLINE_ const Vector3 &get_biased_linear_velocity() const { return biased_linear_velocity; }
- _FORCE_INLINE_ const Vector3 &get_biased_angular_velocity() const { return biased_angular_velocity; }
-
- _FORCE_INLINE_ void apply_central_impulse(const Vector3 &p_j) {
- linear_velocity += p_j * _inv_mass;
- }
-
- _FORCE_INLINE_ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
-
- linear_velocity += p_j * _inv_mass;
- angular_velocity += _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
- }
-
- _FORCE_INLINE_ void apply_torque_impulse(const Vector3 &p_j) {
-
- angular_velocity += _inv_inertia_tensor.xform(p_j);
- }
-
- _FORCE_INLINE_ void apply_bias_impulse(const Vector3 &p_pos, const Vector3 &p_j, real_t p_max_delta_av = -1.0) {
-
- biased_linear_velocity += p_j * _inv_mass;
- if (p_max_delta_av != 0.0) {
- Vector3 delta_av = _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
- if (p_max_delta_av > 0 && delta_av.length() > p_max_delta_av) {
- delta_av = delta_av.normalized() * p_max_delta_av;
- }
- biased_angular_velocity += delta_av;
- }
- }
-
- _FORCE_INLINE_ void apply_bias_torque_impulse(const Vector3 &p_j) {
-
- biased_angular_velocity += _inv_inertia_tensor.xform(p_j);
- }
-
- _FORCE_INLINE_ void add_central_force(const Vector3 &p_force) {
-
- applied_force += p_force;
- }
-
- _FORCE_INLINE_ void add_force(const Vector3 &p_force, const Vector3 &p_pos) {
-
- applied_force += p_force;
- applied_torque += p_pos.cross(p_force);
- }
-
- _FORCE_INLINE_ void add_torque(const Vector3 &p_torque) {
- applied_torque += p_torque;
- }
-
- void set_active(bool p_active);
- _FORCE_INLINE_ bool is_active() const { return active; }
-
- _FORCE_INLINE_ void wakeup() {
- if ((!get_space()) || mode == PhysicsServer::BODY_MODE_STATIC || mode == PhysicsServer::BODY_MODE_KINEMATIC)
- return;
- set_active(true);
- }
-
- void set_param(PhysicsServer::BodyParameter p_param, real_t);
- real_t get_param(PhysicsServer::BodyParameter p_param) const;
-
- void set_mode(PhysicsServer::BodyMode p_mode);
- PhysicsServer::BodyMode get_mode() const;
-
- void set_state(PhysicsServer::BodyState p_state, const Variant &p_variant);
- Variant get_state(PhysicsServer::BodyState p_state) const;
-
- void set_applied_force(const Vector3 &p_force) { applied_force = p_force; }
- Vector3 get_applied_force() const { return applied_force; }
-
- void set_applied_torque(const Vector3 &p_torque) { applied_torque = p_torque; }
- Vector3 get_applied_torque() const { return applied_torque; }
-
- _FORCE_INLINE_ void set_continuous_collision_detection(bool p_enable) { continuous_cd = p_enable; }
- _FORCE_INLINE_ bool is_continuous_collision_detection_enabled() const { return continuous_cd; }
-
- void set_space(SpaceSW *p_space);
-
- 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_ real_t get_friction() const { return friction; }
- _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
- _FORCE_INLINE_ real_t get_bounce() const { return bounce; }
-
- void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock);
- bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const;
-
- void integrate_forces(real_t p_step);
- void integrate_velocities(real_t p_step);
-
- _FORCE_INLINE_ Vector3 get_velocity_in_local_point(const Vector3 &rel_pos) const {
-
- return linear_velocity + angular_velocity.cross(rel_pos - center_of_mass);
- }
-
- _FORCE_INLINE_ real_t compute_impulse_denominator(const Vector3 &p_pos, const Vector3 &p_normal) const {
-
- Vector3 r0 = p_pos - get_transform().origin - center_of_mass;
-
- Vector3 c0 = (r0).cross(p_normal);
-
- Vector3 vec = (_inv_inertia_tensor.xform_inv(c0)).cross(r0);
-
- return _inv_mass + p_normal.dot(vec);
- }
-
- _FORCE_INLINE_ real_t compute_angular_impulse_denominator(const Vector3 &p_axis) const {
-
- return p_axis.dot(_inv_inertia_tensor.xform_inv(p_axis));
- }
-
- //void simulate_motion(const Transform& p_xform,real_t p_step);
- void call_queries();
- void wakeup_neighbours();
-
- bool sleep_test(real_t p_step);
-
- BodySW();
- ~BodySW();
-};
-
-//add contact inline
-
-void BodySW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos) {
-
- int c_max = contacts.size();
-
- if (c_max == 0)
- return;
-
- Contact *c = contacts.ptrw();
-
- int idx = -1;
-
- if (contact_count < c_max) {
- idx = contact_count++;
- } else {
-
- real_t least_depth = 1e20;
- int least_deep = -1;
- for (int i = 0; i < c_max; i++) {
-
- if (i == 0 || c[i].depth < least_depth) {
- least_deep = i;
- least_depth = c[i].depth;
- }
- }
-
- if (least_deep >= 0 && least_depth < p_depth) {
-
- idx = least_deep;
- }
- if (idx == -1)
- return; //none least deepe than this
- }
-
- c[idx].local_pos = p_local_pos;
- c[idx].local_normal = p_local_normal;
- c[idx].depth = p_depth;
- c[idx].local_shape = p_local_shape;
- c[idx].collider_pos = p_collider_pos;
- c[idx].collider_shape = p_collider_shape;
- c[idx].collider_instance_id = p_collider_instance_id;
- c[idx].collider = p_collider;
- c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
-}
-
-class PhysicsDirectBodyStateSW : public PhysicsDirectBodyState {
-
- GDCLASS(PhysicsDirectBodyStateSW, PhysicsDirectBodyState);
-
-public:
- static PhysicsDirectBodyStateSW *singleton;
- BodySW *body;
- real_t step;
-
- virtual Vector3 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area
- virtual real_t get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area
- virtual real_t get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area
-
- virtual Vector3 get_center_of_mass() const { return body->get_center_of_mass(); }
- virtual Basis get_principal_inertia_axes() const { return body->get_principal_inertia_axes(); }
-
- virtual real_t get_inverse_mass() const { return body->get_inv_mass(); } // get the mass
- virtual Vector3 get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space
- virtual Basis get_inverse_inertia_tensor() const { return body->get_inv_inertia_tensor(); } // get density of this body space
-
- virtual void set_linear_velocity(const Vector3 &p_velocity) { body->set_linear_velocity(p_velocity); }
- virtual Vector3 get_linear_velocity() const { return body->get_linear_velocity(); }
-
- virtual void set_angular_velocity(const Vector3 &p_velocity) { body->set_angular_velocity(p_velocity); }
- virtual Vector3 get_angular_velocity() const { return body->get_angular_velocity(); }
-
- virtual void set_transform(const Transform &p_transform) { body->set_state(PhysicsServer::BODY_STATE_TRANSFORM, p_transform); }
- virtual Transform get_transform() const { return body->get_transform(); }
-
- virtual void add_central_force(const Vector3 &p_force) { body->add_central_force(p_force); }
- virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) { body->add_force(p_force, p_pos); }
- virtual void add_torque(const Vector3 &p_torque) { body->add_torque(p_torque); }
- virtual void apply_central_impulse(const Vector3 &p_j) { body->apply_central_impulse(p_j); }
- virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { body->apply_impulse(p_pos, p_j); }
- virtual void apply_torque_impulse(const Vector3 &p_j) { body->apply_torque_impulse(p_j); }
-
- virtual void set_sleep_state(bool p_enable) { body->set_active(!p_enable); }
- virtual bool is_sleeping() const { return !body->is_active(); }
-
- virtual int get_contact_count() const { return body->contact_count; }
-
- virtual Vector3 get_contact_local_position(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].local_pos;
- }
- virtual Vector3 get_contact_local_normal(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].local_normal;
- }
- virtual float get_contact_impulse(int p_contact_idx) const {
- return 0.0f; // Only implemented for bullet
- }
- virtual int get_contact_local_shape(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
- return body->contacts[p_contact_idx].local_shape;
- }
-
- virtual RID get_contact_collider(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
- return body->contacts[p_contact_idx].collider;
- }
- virtual Vector3 get_contact_collider_position(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].collider_pos;
- }
- virtual ObjectID get_contact_collider_id(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
- return body->contacts[p_contact_idx].collider_instance_id;
- }
- virtual int get_contact_collider_shape(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
- return body->contacts[p_contact_idx].collider_shape;
- }
- virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const {
- ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
- return body->contacts[p_contact_idx].collider_velocity_at_pos;
- }
-
- virtual PhysicsDirectSpaceState *get_space_state();
-
- virtual real_t get_step() const { return step; }
- PhysicsDirectBodyStateSW() {
- singleton = this;
- body = NULL;
- }
-};
-
-#endif // BODY__SW_H
diff --git a/servers/physics/broad_phase_basic.cpp b/servers/physics/broad_phase_basic.cpp
deleted file mode 100644
index f49bf9d4cc..0000000000
--- a/servers/physics/broad_phase_basic.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*************************************************************************/
-/* broad_phase_basic.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "broad_phase_basic.h"
-#include "core/list.h"
-#include "core/print_string.h"
-
-BroadPhaseSW::ID BroadPhaseBasic::create(CollisionObjectSW *p_object, int p_subindex) {
-
- ERR_FAIL_COND_V(p_object == NULL, 0);
-
- current++;
-
- Element e;
- e.owner = p_object;
- e._static = false;
- e.subindex = p_subindex;
-
- element_map[current] = e;
- return current;
-}
-
-void BroadPhaseBasic::move(ID p_id, const AABB &p_aabb) {
-
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- E->get().aabb = p_aabb;
-}
-void BroadPhaseBasic::set_static(ID p_id, bool p_static) {
-
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- E->get()._static = p_static;
-}
-void BroadPhaseBasic::remove(ID p_id) {
-
- Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND(!E);
- List<PairKey> to_erase;
- //unpair must be done immediately on removal to avoid potential invalid pointers
- for (Map<PairKey, void *>::Element *F = pair_map.front(); F; F = F->next()) {
-
- if (F->key().a == p_id || F->key().b == p_id) {
-
- if (unpair_callback) {
- Element *elem_A = &element_map[F->key().a];
- Element *elem_B = &element_map[F->key().b];
- unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, F->get(), unpair_userdata);
- }
- to_erase.push_back(F->key());
- }
- }
- while (to_erase.size()) {
-
- pair_map.erase(to_erase.front()->get());
- to_erase.pop_front();
- }
- element_map.erase(E);
-}
-
-CollisionObjectSW *BroadPhaseBasic::get_object(ID p_id) const {
-
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, NULL);
- return E->get().owner;
-}
-bool BroadPhaseBasic::is_static(ID p_id) const {
-
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, false);
- return E->get()._static;
-}
-int BroadPhaseBasic::get_subindex(ID p_id) const {
-
- const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, -1);
- return E->get().subindex;
-}
-
-int BroadPhaseBasic::cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
-
- int rc = 0;
-
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
-
- const AABB aabb = E->get().aabb;
- if (aabb.has_point(p_point)) {
-
- p_results[rc] = E->get().owner;
- p_result_indices[rc] = E->get().subindex;
- rc++;
- if (rc >= p_max_results)
- break;
- }
- }
-
- return rc;
-}
-
-int BroadPhaseBasic::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
-
- int rc = 0;
-
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
-
- const AABB aabb = E->get().aabb;
- if (aabb.intersects_segment(p_from, p_to)) {
-
- p_results[rc] = E->get().owner;
- p_result_indices[rc] = E->get().subindex;
- rc++;
- if (rc >= p_max_results)
- break;
- }
- }
-
- return rc;
-}
-int BroadPhaseBasic::cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
-
- int rc = 0;
-
- for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
-
- const AABB aabb = E->get().aabb;
- if (aabb.intersects(p_aabb)) {
-
- p_results[rc] = E->get().owner;
- p_result_indices[rc] = E->get().subindex;
- rc++;
- if (rc >= p_max_results)
- break;
- }
- }
-
- return rc;
-}
-
-void BroadPhaseBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
-
- pair_userdata = p_userdata;
- pair_callback = p_pair_callback;
-}
-void BroadPhaseBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
-
- unpair_userdata = p_userdata;
- unpair_callback = p_unpair_callback;
-}
-
-void BroadPhaseBasic::update() {
-
- // recompute pairs
- for (Map<ID, Element>::Element *I = element_map.front(); I; I = I->next()) {
-
- for (Map<ID, Element>::Element *J = I->next(); J; J = J->next()) {
-
- Element *elem_A = &I->get();
- Element *elem_B = &J->get();
-
- if (elem_A->owner == elem_B->owner)
- continue;
-
- bool pair_ok = elem_A->aabb.intersects(elem_B->aabb) && (!elem_A->_static || !elem_B->_static);
-
- PairKey key(I->key(), J->key());
-
- Map<PairKey, void *>::Element *E = pair_map.find(key);
-
- if (!pair_ok && E) {
- if (unpair_callback)
- unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, E->get(), unpair_userdata);
- pair_map.erase(key);
- }
-
- if (pair_ok && !E) {
-
- void *data = NULL;
- if (pair_callback)
- data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, unpair_userdata);
- pair_map.insert(key, data);
- }
- }
- }
-}
-
-BroadPhaseSW *BroadPhaseBasic::_create() {
-
- return memnew(BroadPhaseBasic);
-}
-
-BroadPhaseBasic::BroadPhaseBasic() {
-
- current = 1;
- unpair_callback = NULL;
- unpair_userdata = NULL;
- pair_callback = NULL;
- pair_userdata = NULL;
-}
diff --git a/servers/physics/broad_phase_basic.h b/servers/physics/broad_phase_basic.h
deleted file mode 100644
index 424889d8aa..0000000000
--- a/servers/physics/broad_phase_basic.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*************************************************************************/
-/* broad_phase_basic.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BROAD_PHASE_BASIC_H
-#define BROAD_PHASE_BASIC_H
-
-#include "broad_phase_sw.h"
-#include "core/map.h"
-
-class BroadPhaseBasic : public BroadPhaseSW {
-
- struct Element {
-
- CollisionObjectSW *owner;
- bool _static;
- AABB aabb;
- int subindex;
- };
-
- Map<ID, Element> element_map;
-
- ID current;
-
- struct PairKey {
-
- union {
- struct {
- ID a;
- ID b;
- };
- uint64_t key;
- };
-
- _FORCE_INLINE_ bool operator<(const PairKey &p_key) const {
- return key < p_key.key;
- }
-
- PairKey() { key = 0; }
- PairKey(ID p_a, ID p_b) {
- if (p_a > p_b) {
- a = p_b;
- b = p_a;
- } else {
- a = p_a;
- b = p_b;
- }
- }
- };
-
- Map<PairKey, void *> pair_map;
-
- PairCallback pair_callback;
- void *pair_userdata;
- UnpairCallback unpair_callback;
- void *unpair_userdata;
-
-public:
- // 0 is an invalid ID
- virtual ID create(CollisionObjectSW *p_object, int p_subindex = 0);
- virtual void move(ID p_id, const AABB &p_aabb);
- virtual void set_static(ID p_id, bool p_static);
- virtual void remove(ID p_id);
-
- virtual CollisionObjectSW *get_object(ID p_id) const;
- virtual bool is_static(ID p_id) const;
- virtual int get_subindex(ID p_id) const;
-
- virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL);
- virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL);
- virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL);
-
- virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
- virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
-
- virtual void update();
-
- static BroadPhaseSW *_create();
- BroadPhaseBasic();
-};
-
-#endif // BROAD_PHASE_BASIC_H
diff --git a/servers/physics/broad_phase_octree.cpp b/servers/physics/broad_phase_octree.cpp
deleted file mode 100644
index a9aa662abf..0000000000
--- a/servers/physics/broad_phase_octree.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*************************************************************************/
-/* broad_phase_octree.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "broad_phase_octree.h"
-#include "collision_object_sw.h"
-
-BroadPhaseSW::ID BroadPhaseOctree::create(CollisionObjectSW *p_object, int p_subindex) {
-
- ID oid = octree.create(p_object, AABB(), p_subindex, false, 1 << p_object->get_type(), 0);
- return oid;
-}
-
-void BroadPhaseOctree::move(ID p_id, const AABB &p_aabb) {
-
- octree.move(p_id, p_aabb);
-}
-
-void BroadPhaseOctree::set_static(ID p_id, bool p_static) {
-
- CollisionObjectSW *it = octree.get(p_id);
- octree.set_pairable(p_id, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF); //pair everything, don't care 1?
-}
-void BroadPhaseOctree::remove(ID p_id) {
-
- octree.erase(p_id);
-}
-
-CollisionObjectSW *BroadPhaseOctree::get_object(ID p_id) const {
-
- CollisionObjectSW *it = octree.get(p_id);
- ERR_FAIL_COND_V(!it, NULL);
- return it;
-}
-bool BroadPhaseOctree::is_static(ID p_id) const {
-
- return !octree.is_pairable(p_id);
-}
-int BroadPhaseOctree::get_subindex(ID p_id) const {
-
- return octree.get_subindex(p_id);
-}
-
-int BroadPhaseOctree::cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
-
- return octree.cull_point(p_point, p_results, p_max_results, p_result_indices);
-}
-
-int BroadPhaseOctree::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
-
- return octree.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices);
-}
-
-int BroadPhaseOctree::cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices) {
-
- return octree.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices);
-}
-
-void *BroadPhaseOctree::_pair_callback(void *self, OctreeElementID p_A, CollisionObjectSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObjectSW *p_object_B, int subindex_B) {
-
- BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self);
- if (!bpo->pair_callback)
- return NULL;
-
- return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata);
-}
-
-void BroadPhaseOctree::_unpair_callback(void *self, OctreeElementID p_A, CollisionObjectSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObjectSW *p_object_B, int subindex_B, void *pairdata) {
-
- BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self);
- if (!bpo->unpair_callback)
- return;
-
- bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata);
-}
-
-void BroadPhaseOctree::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
-
- pair_callback = p_pair_callback;
- pair_userdata = p_userdata;
-}
-void BroadPhaseOctree::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
-
- unpair_callback = p_unpair_callback;
- unpair_userdata = p_userdata;
-}
-
-void BroadPhaseOctree::update() {
- // does.. not?
-}
-
-BroadPhaseSW *BroadPhaseOctree::_create() {
-
- return memnew(BroadPhaseOctree);
-}
-
-BroadPhaseOctree::BroadPhaseOctree() {
- octree.set_pair_callback(_pair_callback, this);
- octree.set_unpair_callback(_unpair_callback, this);
- pair_callback = NULL;
- pair_userdata = NULL;
- unpair_userdata = NULL;
-}
diff --git a/servers/physics/broad_phase_octree.h b/servers/physics/broad_phase_octree.h
deleted file mode 100644
index e2a1d82b69..0000000000
--- a/servers/physics/broad_phase_octree.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*************************************************************************/
-/* broad_phase_octree.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BROAD_PHASE_OCTREE_H
-#define BROAD_PHASE_OCTREE_H
-
-#include "broad_phase_sw.h"
-#include "core/math/octree.h"
-
-class BroadPhaseOctree : public BroadPhaseSW {
-
- Octree<CollisionObjectSW, true> octree;
-
- static void *_pair_callback(void *, OctreeElementID, CollisionObjectSW *, int, OctreeElementID, CollisionObjectSW *, int);
- static void _unpair_callback(void *, OctreeElementID, CollisionObjectSW *, int, OctreeElementID, CollisionObjectSW *, int, void *);
-
- PairCallback pair_callback;
- void *pair_userdata;
- UnpairCallback unpair_callback;
- void *unpair_userdata;
-
-public:
- // 0 is an invalid ID
- virtual ID create(CollisionObjectSW *p_object, int p_subindex = 0);
- virtual void move(ID p_id, const AABB &p_aabb);
- virtual void set_static(ID p_id, bool p_static);
- virtual void remove(ID p_id);
-
- virtual CollisionObjectSW *get_object(ID p_id) const;
- virtual bool is_static(ID p_id) const;
- virtual int get_subindex(ID p_id) const;
-
- virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL);
- virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL);
- virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL);
-
- virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
- virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
-
- virtual void update();
-
- static BroadPhaseSW *_create();
- BroadPhaseOctree();
-};
-
-#endif // BROAD_PHASE_OCTREE_H
diff --git a/servers/physics/broad_phase_sw.cpp b/servers/physics/broad_phase_sw.cpp
deleted file mode 100644
index a6fc253b1b..0000000000
--- a/servers/physics/broad_phase_sw.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*************************************************************************/
-/* broad_phase_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "broad_phase_sw.h"
-
-BroadPhaseSW::CreateFunction BroadPhaseSW::create_func = NULL;
-
-BroadPhaseSW::~BroadPhaseSW() {
-}
diff --git a/servers/physics/broad_phase_sw.h b/servers/physics/broad_phase_sw.h
deleted file mode 100644
index e69a2d24ed..0000000000
--- a/servers/physics/broad_phase_sw.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*************************************************************************/
-/* broad_phase_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 BROAD_PHASE_SW_H
-#define BROAD_PHASE_SW_H
-
-#include "core/math/aabb.h"
-#include "core/math/math_funcs.h"
-
-class CollisionObjectSW;
-
-class BroadPhaseSW {
-
-public:
- typedef BroadPhaseSW *(*CreateFunction)();
-
- static CreateFunction create_func;
-
- typedef uint32_t ID;
-
- typedef void *(*PairCallback)(CollisionObjectSW *A, int p_subindex_A, CollisionObjectSW *B, int p_subindex_B, void *p_userdata);
- typedef void (*UnpairCallback)(CollisionObjectSW *A, int p_subindex_A, CollisionObjectSW *B, int p_subindex_B, void *p_data, void *p_userdata);
-
- // 0 is an invalid ID
- virtual ID create(CollisionObjectSW *p_object_, int p_subindex = 0) = 0;
- virtual void move(ID p_id, const AABB &p_aabb) = 0;
- virtual void set_static(ID p_id, bool p_static) = 0;
- virtual void remove(ID p_id) = 0;
-
- virtual CollisionObjectSW *get_object(ID p_id) const = 0;
- virtual bool is_static(ID p_id) const = 0;
- virtual int get_subindex(ID p_id) const = 0;
-
- virtual int cull_point(const Vector3 &p_point, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL) = 0;
- virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL) = 0;
- virtual int cull_aabb(const AABB &p_aabb, CollisionObjectSW **p_results, int p_max_results, int *p_result_indices = NULL) = 0;
-
- virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0;
- virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0;
-
- virtual void update() = 0;
-
- virtual ~BroadPhaseSW();
-};
-
-#endif // BROAD_PHASE__SW_H
diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp
deleted file mode 100644
index 3cabf75ab6..0000000000
--- a/servers/physics/collision_object_sw.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/*************************************************************************/
-/* collision_object_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_object_sw.h"
-#include "servers/physics/physics_server_sw.h"
-#include "space_sw.h"
-
-void CollisionObjectSW::add_shape(ShapeSW *p_shape, const Transform &p_transform, bool p_disabled) {
-
- Shape s;
- s.shape = p_shape;
- s.xform = p_transform;
- s.xform_inv = s.xform.affine_inverse();
- s.bpid = 0; //needs update
- s.disabled = p_disabled;
- shapes.push_back(s);
- p_shape->add_owner(this);
-
- if (!pending_shape_update_list.in_list()) {
- PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
- }
- //_update_shapes();
- //_shapes_changed();
-}
-
-void CollisionObjectSW::set_shape(int p_index, ShapeSW *p_shape) {
-
- ERR_FAIL_INDEX(p_index, shapes.size());
- shapes[p_index].shape->remove_owner(this);
- shapes.write[p_index].shape = p_shape;
-
- p_shape->add_owner(this);
- if (!pending_shape_update_list.in_list()) {
- PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
- }
- //_update_shapes();
- //_shapes_changed();
-}
-void CollisionObjectSW::set_shape_transform(int p_index, const Transform &p_transform) {
-
- ERR_FAIL_INDEX(p_index, shapes.size());
-
- shapes.write[p_index].xform = p_transform;
- shapes.write[p_index].xform_inv = p_transform.affine_inverse();
- if (!pending_shape_update_list.in_list()) {
- PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
- }
- //_update_shapes();
- //_shapes_changed();
-}
-
-void CollisionObjectSW::set_shape_as_disabled(int p_idx, bool p_enable) {
- shapes.write[p_idx].disabled = p_enable;
- if (!pending_shape_update_list.in_list()) {
- PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
- }
-}
-
-void CollisionObjectSW::remove_shape(ShapeSW *p_shape) {
-
- //remove a shape, all the times it appears
- for (int i = 0; i < shapes.size(); i++) {
-
- if (shapes[i].shape == p_shape) {
- remove_shape(i);
- i--;
- }
- }
-}
-
-void CollisionObjectSW::remove_shape(int p_index) {
-
- //remove anything from shape to be erased to end, so subindices don't change
- ERR_FAIL_INDEX(p_index, shapes.size());
- for (int i = p_index; i < shapes.size(); i++) {
-
- if (shapes[i].bpid == 0)
- continue;
- //should never get here with a null owner
- space->get_broadphase()->remove(shapes[i].bpid);
- shapes.write[i].bpid = 0;
- }
- shapes[p_index].shape->remove_owner(this);
- shapes.remove(p_index);
-
- if (!pending_shape_update_list.in_list()) {
- PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
- }
- //_update_shapes();
- //_shapes_changed();
-}
-
-void CollisionObjectSW::_set_static(bool p_static) {
- if (_static == p_static)
- return;
- _static = p_static;
-
- if (!space)
- return;
- for (int i = 0; i < get_shape_count(); i++) {
- const Shape &s = shapes[i];
- if (s.bpid > 0) {
- space->get_broadphase()->set_static(s.bpid, _static);
- }
- }
-}
-
-void CollisionObjectSW::_unregister_shapes() {
-
- for (int i = 0; i < shapes.size(); i++) {
-
- Shape &s = shapes.write[i];
- if (s.bpid > 0) {
- space->get_broadphase()->remove(s.bpid);
- s.bpid = 0;
- }
- }
-}
-
-void CollisionObjectSW::_update_shapes() {
-
- if (!space)
- return;
-
- for (int i = 0; i < shapes.size(); i++) {
-
- Shape &s = shapes.write[i];
- if (s.bpid == 0) {
- s.bpid = space->get_broadphase()->create(this, i);
- space->get_broadphase()->set_static(s.bpid, _static);
- }
-
- //not quite correct, should compute the next matrix..
- AABB shape_aabb = s.shape->get_aabb();
- Transform xform = transform * s.xform;
- shape_aabb = xform.xform(shape_aabb);
- s.aabb_cache = shape_aabb;
- s.aabb_cache = s.aabb_cache.grow((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
-
- Vector3 scale = xform.get_basis().get_scale();
- s.area_cache = s.shape->get_area() * scale.x * scale.y * scale.z;
-
- space->get_broadphase()->move(s.bpid, s.aabb_cache);
- }
-}
-
-void CollisionObjectSW::_update_shapes_with_motion(const Vector3 &p_motion) {
-
- if (!space)
- return;
-
- for (int i = 0; i < shapes.size(); i++) {
-
- Shape &s = shapes.write[i];
- if (s.bpid == 0) {
- s.bpid = space->get_broadphase()->create(this, i);
- space->get_broadphase()->set_static(s.bpid, _static);
- }
-
- //not quite correct, should compute the next matrix..
- AABB shape_aabb = s.shape->get_aabb();
- Transform xform = transform * s.xform;
- shape_aabb = xform.xform(shape_aabb);
- shape_aabb = shape_aabb.merge(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion
- s.aabb_cache = shape_aabb;
-
- space->get_broadphase()->move(s.bpid, shape_aabb);
- }
-}
-
-void CollisionObjectSW::_set_space(SpaceSW *p_space) {
-
- if (space) {
-
- space->remove_object(this);
-
- for (int i = 0; i < shapes.size(); i++) {
-
- Shape &s = shapes.write[i];
- if (s.bpid) {
- space->get_broadphase()->remove(s.bpid);
- s.bpid = 0;
- }
- }
- }
-
- space = p_space;
-
- if (space) {
-
- space->add_object(this);
- _update_shapes();
- }
-}
-
-void CollisionObjectSW::_shape_changed() {
-
- _update_shapes();
- _shapes_changed();
-}
-
-CollisionObjectSW::CollisionObjectSW(Type p_type) :
- pending_shape_update_list(this) {
-
- _static = true;
- type = p_type;
- space = NULL;
-
- collision_layer = 1;
- collision_mask = 1;
- ray_pickable = true;
-}
diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h
deleted file mode 100644
index 7c0e66ff90..0000000000
--- a/servers/physics/collision_object_sw.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*************************************************************************/
-/* collision_object_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_OBJECT_SW_H
-#define COLLISION_OBJECT_SW_H
-
-#include "broad_phase_sw.h"
-#include "core/self_list.h"
-#include "servers/physics_server.h"
-#include "shape_sw.h"
-
-#ifdef DEBUG_ENABLED
-#define MAX_OBJECT_DISTANCE 3.1622776601683791e+18
-
-#define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE * MAX_OBJECT_DISTANCE)
-#endif
-
-class SpaceSW;
-
-class CollisionObjectSW : public ShapeOwnerSW {
-public:
- enum Type {
- TYPE_AREA,
- TYPE_BODY
- };
-
-private:
- Type type;
- RID self;
- ObjectID instance_id;
- uint32_t collision_layer;
- uint32_t collision_mask;
-
- struct Shape {
-
- Transform xform;
- Transform xform_inv;
- BroadPhaseSW::ID bpid;
- AABB aabb_cache; //for rayqueries
- real_t area_cache;
- ShapeSW *shape;
- bool disabled;
-
- Shape() { disabled = false; }
- };
-
- Vector<Shape> shapes;
- SpaceSW *space;
- Transform transform;
- Transform inv_transform;
- bool _static;
-
- SelfList<CollisionObjectSW> pending_shape_update_list;
-
- void _update_shapes();
-
-protected:
- void _update_shapes_with_motion(const Vector3 &p_motion);
- void _unregister_shapes();
-
- _FORCE_INLINE_ void _set_transform(const Transform &p_transform, bool p_update_shapes = true) {
-#ifdef DEBUG_ENABLED
-
- ERR_FAIL_COND_MSG(p_transform.origin.length_squared() > MAX_OBJECT_DISTANCE_X2, "Object went too far away (more than '" + itos(MAX_OBJECT_DISTANCE) + "' units from origin).");
-#endif
-
- transform = p_transform;
- if (p_update_shapes) _update_shapes();
- }
- _FORCE_INLINE_ void _set_inv_transform(const Transform &p_transform) { inv_transform = p_transform; }
- void _set_static(bool p_static);
-
- virtual void _shapes_changed() = 0;
- void _set_space(SpaceSW *p_space);
-
- bool ray_pickable;
-
- CollisionObjectSW(Type p_type);
-
-public:
- _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
- _FORCE_INLINE_ RID get_self() const { return self; }
-
- _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
- _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
-
- void _shape_changed();
-
- _FORCE_INLINE_ Type get_type() const { return type; }
- void add_shape(ShapeSW *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
- void set_shape(int p_index, ShapeSW *p_shape);
- void set_shape_transform(int p_index, const Transform &p_transform);
- _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
- _FORCE_INLINE_ bool is_shape_disabled(int p_index) const {
- CRASH_BAD_INDEX(p_index, shapes.size());
- return shapes[p_index].disabled;
- }
- _FORCE_INLINE_ ShapeSW *get_shape(int p_index) const { return shapes[p_index].shape; }
- _FORCE_INLINE_ const Transform &get_shape_transform(int p_index) const { return shapes[p_index].xform; }
- _FORCE_INLINE_ const Transform &get_shape_inv_transform(int p_index) const { return shapes[p_index].xform_inv; }
- _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_ SpaceSW *get_space() const { return space; }
-
- _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
- _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; }
-
- void set_shape_as_disabled(int p_idx, bool p_enable);
- _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const {
- CRASH_BAD_INDEX(p_idx, shapes.size());
- return shapes[p_idx].disabled;
- }
-
- _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; }
- _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
-
- _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; }
- _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
-
- _FORCE_INLINE_ bool test_collision_mask(CollisionObjectSW *p_other) const {
- return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
- }
-
- void remove_shape(ShapeSW *p_shape);
- void remove_shape(int p_index);
-
- virtual void set_space(SpaceSW *p_space) = 0;
-
- _FORCE_INLINE_ bool is_static() const { return _static; }
-
- virtual ~CollisionObjectSW() {}
-};
-
-#endif // COLLISION_OBJECT_SW_H
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
deleted file mode 100644
index 0e0dfd3cf2..0000000000
--- a/servers/physics/collision_solver_sat.cpp
+++ /dev/null
@@ -1,1591 +0,0 @@
-/*************************************************************************/
-/* collision_solver_sat.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_solver_sat.h"
-#include "core/math/geometry.h"
-
-#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.02
-
-struct _CollectorCallback {
-
- CollisionSolverSW::CallbackResult callback;
- void *userdata;
- bool swap;
- bool collided;
- Vector3 normal;
- Vector3 *prev_axis;
-
- _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
-
- if (swap)
- callback(p_point_B, p_point_A, userdata);
- else
- callback(p_point_A, p_point_B, userdata);
- }
-};
-
-typedef void (*GenerateContactsFunc)(const Vector3 *, int, const Vector3 *, int, _CollectorCallback *);
-
-static void _generate_contacts_point_point(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 != 1);
-#endif
-
- p_callback->call(*p_points_A, *p_points_B);
-}
-
-static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
-
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND(p_point_count_A != 1);
- ERR_FAIL_COND(p_point_count_B != 2);
-#endif
-
- Vector3 closest_B = Geometry::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B);
- p_callback->call(*p_points_A, closest_B);
-}
-
-static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
-
-#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);
- ERR_FAIL_COND(p_point_count_B != 2); // circle is actually a 4x3 matrix
-#endif
-
- Vector3 rel_A = p_points_A[1] - p_points_A[0];
- Vector3 rel_B = p_points_B[1] - p_points_B[0];
-
- Vector3 c = rel_A.cross(rel_B).cross(rel_B);
-
- if (Math::is_zero_approx(rel_A.dot(c))) {
-
- // should handle somehow..
- //ERR_PRINT("TODO FIX");
- //return;
-
- Vector3 axis = rel_A.normalized(); //make an axis
- Vector3 base_A = p_points_A[0] - axis * axis.dot(p_points_A[0]);
- Vector3 base_B = p_points_B[0] - axis * axis.dot(p_points_B[0]);
-
- //sort all 4 points in axis
- real_t dvec[4] = { axis.dot(p_points_A[0]), axis.dot(p_points_A[1]), axis.dot(p_points_B[0]), axis.dot(p_points_B[1]) };
-
- SortArray<real_t> sa;
- sa.sort(dvec, 4);
-
- //use the middle ones as contacts
- p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1]);
- p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2]);
-
- return;
- }
-
- real_t d = (c.dot(p_points_B[0]) - p_points_A[0].dot(c)) / rel_A.dot(c);
-
- if (d < 0.0)
- d = 0.0;
- else if (d > 1.0)
- d = 1.0;
-
- Vector3 closest_A = p_points_A[0] + rel_A * d;
- Vector3 closest_B = Geometry::get_closest_point_to_segment_uncapped(closest_A, p_points_B);
- p_callback->call(closest_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);
- ERR_FAIL_COND(p_point_count_B < 3);
-#endif
-
- static const int max_clip = 32;
-
- Vector3 _clipbuf1[max_clip];
- Vector3 _clipbuf2[max_clip];
- Vector3 *clipbuf_src = _clipbuf1;
- Vector3 *clipbuf_dst = _clipbuf2;
- int clipbuf_len = p_point_count_A;
-
- // copy A points to clipbuf_src
- for (int i = 0; i < p_point_count_A; i++) {
-
- clipbuf_src[i] = p_points_A[i];
- }
-
- Plane plane_B(p_points_B[0], p_points_B[1], p_points_B[2]);
-
- // go through all of B points
- for (int i = 0; i < p_point_count_B; i++) {
-
- int i_n = (i + 1) % p_point_count_B;
-
- Vector3 edge0_B = p_points_B[i];
- Vector3 edge1_B = p_points_B[i_n];
-
- Vector3 clip_normal = (edge0_B - edge1_B).cross(plane_B.normal).normalized();
- // make a clip plane
-
- Plane clip(edge0_B, clip_normal);
- // avoid double clip if A is edge
- int dst_idx = 0;
- bool edge = clipbuf_len == 2;
- for (int j = 0; j < clipbuf_len; j++) {
-
- int j_n = (j + 1) % clipbuf_len;
-
- Vector3 edge0_A = clipbuf_src[j];
- Vector3 edge1_A = clipbuf_src[j_n];
-
- real_t dist0 = clip.distance_to(edge0_A);
- real_t dist1 = clip.distance_to(edge1_A);
-
- if (dist0 <= 0) { // behind plane
-
- ERR_FAIL_COND(dst_idx >= max_clip);
- clipbuf_dst[dst_idx++] = clipbuf_src[j];
- }
-
- // check for different sides and non coplanar
- //if ( (dist0*dist1) < -CMP_EPSILON && !(edge && j)) {
- if ((dist0 * dist1) < 0 && !(edge && j)) {
-
- // calculate intersection
- Vector3 rel = edge1_A - edge0_A;
- real_t den = clip.normal.dot(rel);
- real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;
- Vector3 inters = edge0_A + rel * dist;
-
- ERR_FAIL_COND(dst_idx >= max_clip);
- clipbuf_dst[dst_idx] = inters;
- dst_idx++;
- }
- }
-
- clipbuf_len = dst_idx;
- SWAP(clipbuf_src, clipbuf_dst);
- }
-
- // generate contacts
- //Plane plane_A(p_points_A[0],p_points_A[1],p_points_A[2]);
-
- for (int i = 0; i < clipbuf_len; i++) {
-
- real_t d = plane_B.distance_to(clipbuf_src[i]);
- /*
- if (d>CMP_EPSILON)
- continue;
- */
-
- Vector3 closest_B = clipbuf_src[i] - plane_B.normal * d;
-
- if (p_callback->normal.dot(clipbuf_src[i]) >= p_callback->normal.dot(closest_B))
- continue;
-
- p_callback->call(clipbuf_src[i], closest_B);
- }
-}
-
-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) {
-
-#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] = {
- {
- _generate_contacts_point_point,
- _generate_contacts_point_edge,
- _generate_contacts_point_face,
- },
- {
- 0,
- _generate_contacts_edge_edge,
- _generate_contacts_face_face,
- },
- {
- 0,
- 0,
- _generate_contacts_face_face,
- }
- };
-
- int pointcount_B;
- int pointcount_A;
- const Vector3 *points_A;
- const Vector3 *points_B;
-
- if (p_point_count_A > p_point_count_B) {
- //swap
- p_callback->swap = !p_callback->swap;
- p_callback->normal = -p_callback->normal;
-
- pointcount_B = p_point_count_A;
- pointcount_A = p_point_count_B;
- points_A = p_points_B;
- points_B = p_points_A;
- } else {
-
- pointcount_B = p_point_count_B;
- pointcount_A = p_point_count_A;
- points_A = p_points_A;
- points_B = p_points_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);
-}
-
-template <class ShapeA, class ShapeB, bool withMargin = false>
-class SeparatorAxisTest {
-
- const ShapeA *shape_A;
- const ShapeB *shape_B;
- const Transform *transform_A;
- const Transform *transform_B;
- real_t best_depth;
- Vector3 best_axis;
- _CollectorCallback *callback;
- real_t margin_A;
- real_t margin_B;
- Vector3 separator_axis;
-
-public:
- _FORCE_INLINE_ bool test_previous_axis() {
-
- if (callback && callback->prev_axis && *callback->prev_axis != Vector3())
- return test_axis(*callback->prev_axis);
- else
- return true;
- }
-
- _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
-
- Vector3 axis = p_axis;
-
- if (Math::abs(axis.x) < CMP_EPSILON &&
- Math::abs(axis.y) < CMP_EPSILON &&
- Math::abs(axis.z) < CMP_EPSILON) {
- // strange case, try an upwards separator
- axis = Vector3(0.0, 1.0, 0.0);
- }
-
- real_t min_A, max_A, min_B, max_B;
-
- shape_A->project_range(axis, *transform_A, min_A, max_A);
- shape_B->project_range(axis, *transform_B, min_B, max_B);
-
- if (withMargin) {
- min_A -= margin_A;
- max_A += margin_A;
- min_B -= margin_B;
- max_B += margin_B;
- }
-
- min_B -= (max_A - min_A) * 0.5;
- max_B += (max_A - min_A) * 0.5;
-
- min_B -= (min_A + max_A) * 0.5;
- max_B -= (min_A + max_A) * 0.5;
-
- if (min_B > 0.0 || max_B < 0.0) {
- separator_axis = axis;
- return false; // doesn't contain 0
- }
-
- //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 (max_B < min_B) {
- if (max_B < best_depth) {
- best_depth = max_B;
- best_axis = axis;
- }
- } else {
- if (min_B < best_depth) {
- best_depth = min_B;
- best_axis = -axis; // keep it as A axis
- }
- }
-
- return true;
- }
-
- _FORCE_INLINE_ void generate_contacts() {
-
- // nothing to do, don't generate
- if (best_axis == Vector3(0.0, 0.0, 0.0))
- return;
-
- if (!callback->callback) {
- //just was checking intersection?
- callback->collided = true;
- if (callback->prev_axis)
- *callback->prev_axis = best_axis;
- return;
- }
-
- static const int max_supports = 16;
-
- 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);
- for (int i = 0; i < support_count_A; i++) {
- supports_A[i] = transform_A->xform(supports_A[i]);
- }
-
- if (withMargin) {
-
- for (int i = 0; i < support_count_A; i++) {
- supports_A[i] += -best_axis * margin_A;
- }
- }
-
- 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);
- for (int i = 0; i < support_count_B; i++) {
- supports_B[i] = transform_B->xform(supports_B[i]);
- }
-
- if (withMargin) {
-
- for (int i = 0; i < support_count_B; i++) {
- supports_B[i] += best_axis * margin_B;
- }
- }
-
- callback->normal = best_axis;
- if (callback->prev_axis)
- *callback->prev_axis = best_axis;
- _generate_contacts_from_supports(supports_A, support_count_A, supports_B, support_count_B, callback);
-
- callback->collided = true;
- }
-
- _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A, const Transform &p_transform_A, const ShapeB *p_shape_B, const Transform &p_transform_B, _CollectorCallback *p_callback, real_t p_margin_A = 0, real_t p_margin_B = 0) {
- best_depth = 1e15;
- shape_A = p_shape_A;
- shape_B = p_shape_B;
- transform_A = &p_transform_A;
- transform_B = &p_transform_B;
- callback = p_callback;
- margin_A = p_margin_A;
- margin_B = p_margin_B;
- }
-};
-
-/****** SAT TESTS *******/
-
-typedef void (*CollisionFunc)(const ShapeSW *, const Transform &, const ShapeSW *, const Transform &, _CollectorCallback *p_callback, real_t, real_t);
-
-template <bool withMargin>
-static void _collision_sphere_sphere(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a);
- const SphereShapeSW *sphere_B = static_cast<const SphereShapeSW *>(p_b);
-
- SeparatorAxisTest<SphereShapeSW, SphereShapeSW, withMargin> separator(sphere_A, p_transform_a, sphere_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- // previous axis
-
- if (!separator.test_previous_axis())
- return;
-
- if (!separator.test_axis((p_transform_a.origin - p_transform_b.origin).normalized()))
- return;
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_sphere_box(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a);
- const BoxShapeSW *box_B = static_cast<const BoxShapeSW *>(p_b);
-
- SeparatorAxisTest<SphereShapeSW, BoxShapeSW, withMargin> separator(sphere_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- // test faces
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis = p_transform_b.basis.get_axis(i).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // calculate closest point to sphere
-
- Vector3 cnormal = p_transform_b.xform_inv(p_transform_a.origin);
-
- Vector3 cpoint = p_transform_b.xform(Vector3(
-
- (cnormal.x < 0) ? -box_B->get_half_extents().x : box_B->get_half_extents().x,
- (cnormal.y < 0) ? -box_B->get_half_extents().y : box_B->get_half_extents().y,
- (cnormal.z < 0) ? -box_B->get_half_extents().z : box_B->get_half_extents().z));
-
- // use point to test axis
- Vector3 point_axis = (p_transform_a.origin - cpoint).normalized();
-
- if (!separator.test_axis(point_axis))
- return;
-
- // test edges
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis = point_axis.cross(p_transform_b.basis.get_axis(i)).cross(p_transform_b.basis.get_axis(i)).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_sphere_capsule(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a);
- const CapsuleShapeSW *capsule_B = static_cast<const CapsuleShapeSW *>(p_b);
-
- SeparatorAxisTest<SphereShapeSW, CapsuleShapeSW, withMargin> separator(sphere_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- //capsule sphere 1, sphere
-
- Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
-
- Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis;
-
- if (!separator.test_axis((capsule_ball_1 - p_transform_a.origin).normalized()))
- return;
-
- //capsule sphere 2, sphere
-
- Vector3 capsule_ball_2 = p_transform_b.origin - capsule_axis;
-
- if (!separator.test_axis((capsule_ball_2 - p_transform_a.origin).normalized()))
- return;
-
- //capsule edge, sphere
-
- Vector3 b2a = p_transform_a.origin - p_transform_b.origin;
-
- Vector3 axis = b2a.cross(capsule_axis).cross(capsule_axis).normalized();
-
- if (!separator.test_axis(axis))
- return;
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_sphere_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-}
-
-template <bool withMargin>
-static void _collision_sphere_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a);
- const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW *>(p_b);
-
- SeparatorAxisTest<SphereShapeSW, ConvexPolygonShapeSW, withMargin> separator(sphere_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- const Geometry::MeshData &mesh = convex_polygon_B->get_mesh();
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int face_count = mesh.faces.size();
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int edge_count = mesh.edges.size();
- const Vector3 *vertices = mesh.vertices.ptr();
- int vertex_count = mesh.vertices.size();
-
- // faces of B
- for (int i = 0; i < face_count; i++) {
-
- Vector3 axis = p_transform_b.xform(faces[i].plane).normal;
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // edges of B
- for (int i = 0; i < edge_count; i++) {
-
- Vector3 v1 = p_transform_b.xform(vertices[edges[i].a]);
- Vector3 v2 = p_transform_b.xform(vertices[edges[i].b]);
- Vector3 v3 = p_transform_a.origin;
-
- Vector3 n1 = v2 - v1;
- Vector3 n2 = v2 - v3;
-
- Vector3 axis = n1.cross(n2).cross(n1).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // vertices of B
- for (int i = 0; i < vertex_count; i++) {
-
- Vector3 v1 = p_transform_b.xform(vertices[i]);
- Vector3 v2 = p_transform_a.origin;
-
- Vector3 axis = (v2 - v1).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_sphere_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a);
- const FaceShapeSW *face_B = static_cast<const FaceShapeSW *>(p_b);
-
- SeparatorAxisTest<SphereShapeSW, FaceShapeSW, withMargin> separator(sphere_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- 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]),
- };
-
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
- return;
-
- // edges and points of B
- for (int i = 0; i < 3; i++) {
-
- Vector3 n1 = vertex[i] - p_transform_a.origin;
-
- if (!separator.test_axis(n1.normalized())) {
- return;
- }
-
- Vector3 n2 = vertex[(i + 1) % 3] - vertex[i];
-
- Vector3 axis = n1.cross(n2).cross(n2).normalized();
-
- if (!separator.test_axis(axis)) {
- return;
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_box_box(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a);
- const BoxShapeSW *box_B = static_cast<const BoxShapeSW *>(p_b);
-
- SeparatorAxisTest<BoxShapeSW, BoxShapeSW, withMargin> separator(box_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- // test 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;
- }
-
- // test faces of B
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis = p_transform_b.basis.get_axis(i).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // test combined edges
- for (int i = 0; i < 3; i++) {
-
- for (int j = 0; j < 3; j++) {
-
- Vector3 axis = p_transform_a.basis.get_axis(i).cross(p_transform_b.basis.get_axis(j));
-
- if (Math::is_zero_approx(axis.length_squared()))
- continue;
- axis.normalize();
-
- if (!separator.test_axis(axis)) {
- return;
- }
- }
- }
-
- if (withMargin) {
- //add endpoint test between closest vertices and edges
-
- // calculate closest point to sphere
-
- Vector3 ab_vec = p_transform_b.origin - p_transform_a.origin;
-
- Vector3 cnormal_a = p_transform_a.basis.xform_inv(ab_vec);
-
- Vector3 support_a = p_transform_a.xform(Vector3(
-
- (cnormal_a.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
- (cnormal_a.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
- (cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
-
- Vector3 cnormal_b = p_transform_b.basis.xform_inv(-ab_vec);
-
- Vector3 support_b = p_transform_b.xform(Vector3(
-
- (cnormal_b.x < 0) ? -box_B->get_half_extents().x : box_B->get_half_extents().x,
- (cnormal_b.y < 0) ? -box_B->get_half_extents().y : box_B->get_half_extents().y,
- (cnormal_b.z < 0) ? -box_B->get_half_extents().z : box_B->get_half_extents().z));
-
- Vector3 axis_ab = (support_a - support_b);
-
- if (!separator.test_axis(axis_ab.normalized())) {
- return;
- }
-
- //now try edges, which become cylinders!
-
- for (int i = 0; i < 3; i++) {
-
- //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()))
- return;
-
- //b ->a
- Vector3 axis_b = p_transform_b.basis.get_axis(i);
-
- if (!separator.test_axis(axis_ab.cross(axis_b).cross(axis_b).normalized()))
- return;
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a);
- const CapsuleShapeSW *capsule_B = static_cast<const CapsuleShapeSW *>(p_b);
-
- SeparatorAxisTest<BoxShapeSW, CapsuleShapeSW, withMargin> separator(box_A, p_transform_a, capsule_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);
-
- if (!separator.test_axis(axis))
- return;
- }
-
- Vector3 cyl_axis = p_transform_b.basis.get_axis(2).normalized();
-
- // edges of A, capsule cylinder
-
- for (int i = 0; i < 3; i++) {
-
- // cylinder
- 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;
- }
-
- // points of A, capsule cylinder
- // this sure could be made faster somehow..
-
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < 2; j++) {
- for (int k = 0; k < 2; k++) {
- Vector3 he = box_A->get_half_extents();
- he.x *= (i * 2 - 1);
- he.y *= (j * 2 - 1);
- he.z *= (k * 2 - 1);
- Vector3 point = p_transform_a.origin;
- for (int l = 0; l < 3; l++)
- point += p_transform_a.basis.get_axis(l) * he[l];
-
- //Vector3 axis = (point - cyl_axis * cyl_axis.dot(point)).normalized();
- Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
- }
- }
-
- // 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 sphere_pos = p_transform_b.origin + ((i == 0) ? capsule_axis : -capsule_axis);
-
- Vector3 cnormal = p_transform_a.xform_inv(sphere_pos);
-
- Vector3 cpoint = p_transform_a.xform(Vector3(
-
- (cnormal.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
- (cnormal.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
- (cnormal.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
-
- // use point to test axis
- Vector3 point_axis = (sphere_pos - cpoint).normalized();
-
- if (!separator.test_axis(point_axis))
- return;
-
- // test edges of A
-
- for (int j = 0; j < 3; j++) {
-
- Vector3 axis = point_axis.cross(p_transform_a.basis.get_axis(j)).cross(p_transform_a.basis.get_axis(j)).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_box_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-}
-
-template <bool withMargin>
-static void _collision_box_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a);
- const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW *>(p_b);
-
- SeparatorAxisTest<BoxShapeSW, ConvexPolygonShapeSW, withMargin> separator(box_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- const Geometry::MeshData &mesh = convex_polygon_B->get_mesh();
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int face_count = mesh.faces.size();
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int edge_count = mesh.edges.size();
- const Vector3 *vertices = mesh.vertices.ptr();
- int vertex_count = mesh.vertices.size();
-
- // 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;
- }
-
- // faces of B
- for (int i = 0; i < face_count; i++) {
-
- Vector3 axis = p_transform_b.xform(faces[i].plane).normal;
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // A<->B edges
- for (int i = 0; i < 3; i++) {
-
- Vector3 e1 = p_transform_a.basis.get_axis(i);
-
- for (int j = 0; j < edge_count; j++) {
-
- Vector3 e2 = p_transform_b.basis.xform(vertices[edges[j].a]) - p_transform_b.basis.xform(vertices[edges[j].b]);
-
- Vector3 axis = e1.cross(e2).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
- }
-
- if (withMargin) {
-
- // calculate closest points between vertices and box edges
- for (int v = 0; v < vertex_count; v++) {
-
- Vector3 vtxb = p_transform_b.xform(vertices[v]);
- Vector3 ab_vec = vtxb - p_transform_a.origin;
-
- Vector3 cnormal_a = p_transform_a.basis.xform_inv(ab_vec);
-
- Vector3 support_a = p_transform_a.xform(Vector3(
-
- (cnormal_a.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
- (cnormal_a.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
- (cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
-
- Vector3 axis_ab = support_a - vtxb;
-
- if (!separator.test_axis(axis_ab.normalized())) {
- return;
- }
-
- //now try edges, which become cylinders!
-
- for (int i = 0; i < 3; i++) {
-
- //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()))
- return;
- }
- }
-
- //convex edges and box points
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < 2; j++) {
- for (int k = 0; k < 2; k++) {
- Vector3 he = box_A->get_half_extents();
- he.x *= (i * 2 - 1);
- he.y *= (j * 2 - 1);
- he.z *= (k * 2 - 1);
- Vector3 point = p_transform_a.origin;
- for (int l = 0; l < 3; l++)
- point += p_transform_a.basis.get_axis(l) * he[l];
-
- for (int e = 0; e < edge_count; e++) {
-
- Vector3 p1 = p_transform_b.xform(vertices[edges[e].a]);
- Vector3 p2 = p_transform_b.xform(vertices[edges[e].b]);
- Vector3 n = (p2 - p1);
-
- if (!separator.test_axis((point - p2).cross(n).cross(n).normalized()))
- return;
- }
- }
- }
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_box_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a);
- const FaceShapeSW *face_B = static_cast<const FaceShapeSW *>(p_b);
-
- SeparatorAxisTest<BoxShapeSW, FaceShapeSW, withMargin> separator(box_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- 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]),
- };
-
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
- 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;
- }
-
- // combined edges
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 e = vertex[i] - vertex[(i + 1) % 3];
-
- for (int j = 0; j < 3; j++) {
-
- Vector3 axis = p_transform_a.basis.get_axis(j);
-
- if (!separator.test_axis(e.cross(axis).normalized()))
- return;
- }
- }
-
- if (withMargin) {
-
- // calculate closest points between vertices and box edges
- for (int v = 0; v < 3; v++) {
-
- Vector3 ab_vec = vertex[v] - p_transform_a.origin;
-
- Vector3 cnormal_a = p_transform_a.basis.xform_inv(ab_vec);
-
- Vector3 support_a = p_transform_a.xform(Vector3(
-
- (cnormal_a.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
- (cnormal_a.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
- (cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
-
- Vector3 axis_ab = support_a - vertex[v];
-
- if (!separator.test_axis(axis_ab.normalized())) {
- return;
- }
-
- //now try edges, which become cylinders!
-
- for (int i = 0; i < 3; i++) {
-
- //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()))
- return;
- }
- }
-
- //convex edges and box points, there has to be a way to speed up this (get closest point?)
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < 2; j++) {
- for (int k = 0; k < 2; k++) {
- Vector3 he = box_A->get_half_extents();
- he.x *= (i * 2 - 1);
- he.y *= (j * 2 - 1);
- he.z *= (k * 2 - 1);
- Vector3 point = p_transform_a.origin;
- for (int l = 0; l < 3; l++)
- point += p_transform_a.basis.get_axis(l) * he[l];
-
- for (int e = 0; e < 3; e++) {
-
- Vector3 p1 = vertex[e];
- Vector3 p2 = vertex[(e + 1) % 3];
-
- Vector3 n = (p2 - p1);
-
- if (!separator.test_axis((point - p2).cross(n).cross(n).normalized()))
- return;
- }
- }
- }
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_capsule_capsule(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW *>(p_a);
- const CapsuleShapeSW *capsule_B = static_cast<const CapsuleShapeSW *>(p_b);
-
- SeparatorAxisTest<CapsuleShapeSW, CapsuleShapeSW, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- // 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_ball_1 = p_transform_a.origin + capsule_A_axis;
- Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis;
- Vector3 capsule_B_ball_1 = p_transform_b.origin + capsule_B_axis;
- Vector3 capsule_B_ball_2 = p_transform_b.origin - capsule_B_axis;
-
- //balls-balls
-
- if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_1).normalized()))
- return;
- if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_2).normalized()))
- return;
-
- if (!separator.test_axis((capsule_A_ball_2 - capsule_B_ball_1).normalized()))
- return;
- if (!separator.test_axis((capsule_A_ball_2 - capsule_B_ball_2).normalized()))
- return;
-
- // edges-balls
-
- if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_1).cross(capsule_A_axis).cross(capsule_A_axis).normalized()))
- return;
-
- if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_2).cross(capsule_A_axis).cross(capsule_A_axis).normalized()))
- return;
-
- if (!separator.test_axis((capsule_B_ball_1 - capsule_A_ball_1).cross(capsule_B_axis).cross(capsule_B_axis).normalized()))
- return;
-
- if (!separator.test_axis((capsule_B_ball_1 - capsule_A_ball_2).cross(capsule_B_axis).cross(capsule_B_axis).normalized()))
- return;
-
- // edges
-
- if (!separator.test_axis(capsule_A_axis.cross(capsule_B_axis).normalized()))
- return;
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_capsule_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-}
-
-template <bool withMargin>
-static void _collision_capsule_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW *>(p_a);
- const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW *>(p_b);
-
- SeparatorAxisTest<CapsuleShapeSW, ConvexPolygonShapeSW, withMargin> separator(capsule_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- const Geometry::MeshData &mesh = convex_polygon_B->get_mesh();
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int face_count = mesh.faces.size();
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int edge_count = mesh.edges.size();
- const Vector3 *vertices = mesh.vertices.ptr();
-
- // faces of B
- for (int i = 0; i < face_count; i++) {
-
- Vector3 axis = p_transform_b.xform(faces[i].plane).normal;
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // edges of B, capsule cylinder
-
- 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();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // capsule balls, edges of B
-
- 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 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis);
-
- for (int j = 0; j < edge_count; j++) {
-
- Vector3 n1 = sphere_pos - p_transform_b.xform(vertices[edges[j].a]);
- Vector3 n2 = p_transform_b.basis.xform(vertices[edges[j].a]) - p_transform_b.basis.xform(vertices[edges[j].b]);
-
- Vector3 axis = n1.cross(n2).cross(n2).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_capsule_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW *>(p_a);
- const FaceShapeSW *face_B = static_cast<const FaceShapeSW *>(p_b);
-
- SeparatorAxisTest<CapsuleShapeSW, FaceShapeSW, withMargin> separator(capsule_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- 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]),
- };
-
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
- return;
-
- // edges of B, capsule cylinder
-
- Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (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 (!separator.test_axis(axis))
- return;
-
- if (!separator.test_axis((p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized()))
- return;
-
- for (int j = 0; j < 2; j++) {
-
- // point-spheres
- Vector3 sphere_pos = p_transform_a.origin + ((j == 0) ? capsule_axis : -capsule_axis);
-
- Vector3 n1 = sphere_pos - vertex[i];
-
- if (!separator.test_axis(n1.normalized()))
- return;
-
- Vector3 n2 = edge_axis;
-
- axis = n1.cross(n2).cross(n2);
-
- if (!separator.test_axis(axis.normalized()))
- return;
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_cylinder_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-}
-
-template <bool withMargin>
-static void _collision_cylinder_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-}
-
-template <bool withMargin>
-static void _collision_cylinder_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-}
-
-template <bool withMargin>
-static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW *>(p_a);
- const ConvexPolygonShapeSW *convex_polygon_B = static_cast<const ConvexPolygonShapeSW *>(p_b);
-
- SeparatorAxisTest<ConvexPolygonShapeSW, ConvexPolygonShapeSW, withMargin> separator(convex_polygon_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- if (!separator.test_previous_axis())
- return;
-
- const Geometry::MeshData &mesh_A = convex_polygon_A->get_mesh();
-
- const Geometry::MeshData::Face *faces_A = mesh_A.faces.ptr();
- int face_count_A = mesh_A.faces.size();
- const Geometry::MeshData::Edge *edges_A = mesh_A.edges.ptr();
- int edge_count_A = mesh_A.edges.size();
- const Vector3 *vertices_A = mesh_A.vertices.ptr();
- int vertex_count_A = mesh_A.vertices.size();
-
- const Geometry::MeshData &mesh_B = convex_polygon_B->get_mesh();
-
- const Geometry::MeshData::Face *faces_B = mesh_B.faces.ptr();
- int face_count_B = mesh_B.faces.size();
- const Geometry::MeshData::Edge *edges_B = mesh_B.edges.ptr();
- int edge_count_B = mesh_B.edges.size();
- const Vector3 *vertices_B = mesh_B.vertices.ptr();
- int vertex_count_B = mesh_B.vertices.size();
-
- // faces of A
- for (int i = 0; i < face_count_A; i++) {
-
- Vector3 axis = p_transform_a.xform(faces_A[i].plane).normal;
- //Vector3 axis = p_transform_a.basis.xform( faces_A[i].plane.normal ).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // faces of B
- for (int i = 0; i < face_count_B; i++) {
-
- Vector3 axis = p_transform_b.xform(faces_B[i].plane).normal;
- //Vector3 axis = p_transform_b.basis.xform( faces_B[i].plane.normal ).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
-
- // A<->B edges
- for (int i = 0; i < edge_count_A; i++) {
-
- Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].a]) - p_transform_a.basis.xform(vertices_A[edges_A[i].b]);
-
- for (int j = 0; j < edge_count_B; j++) {
-
- Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[j].a]) - p_transform_b.basis.xform(vertices_B[edges_B[j].b]);
-
- Vector3 axis = e1.cross(e2).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
- }
-
- if (withMargin) {
-
- //vertex-vertex
- for (int i = 0; i < vertex_count_A; i++) {
-
- Vector3 va = p_transform_a.xform(vertices_A[i]);
-
- for (int j = 0; j < vertex_count_B; j++) {
-
- if (!separator.test_axis((va - p_transform_b.xform(vertices_B[j])).normalized()))
- return;
- }
- }
- //edge-vertex (shell)
-
- for (int i = 0; i < edge_count_A; i++) {
-
- Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].a]);
- Vector3 e2 = p_transform_a.basis.xform(vertices_A[edges_A[i].b]);
- Vector3 n = (e2 - e1);
-
- for (int j = 0; j < vertex_count_B; j++) {
-
- Vector3 e3 = p_transform_b.xform(vertices_B[j]);
-
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized()))
- return;
- }
- }
-
- for (int i = 0; i < edge_count_B; i++) {
-
- Vector3 e1 = p_transform_b.basis.xform(vertices_B[edges_B[i].a]);
- Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[i].b]);
- Vector3 n = (e2 - e1);
-
- for (int j = 0; j < vertex_count_A; j++) {
-
- Vector3 e3 = p_transform_a.xform(vertices_A[j]);
-
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized()))
- return;
- }
- }
- }
-
- separator.generate_contacts();
-}
-
-template <bool withMargin>
-static void _collision_convex_polygon_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
-
- const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW *>(p_a);
- const FaceShapeSW *face_B = static_cast<const FaceShapeSW *>(p_b);
-
- SeparatorAxisTest<ConvexPolygonShapeSW, FaceShapeSW, withMargin> separator(convex_polygon_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
-
- const Geometry::MeshData &mesh = convex_polygon_A->get_mesh();
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int face_count = mesh.faces.size();
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int edge_count = mesh.edges.size();
- const Vector3 *vertices = mesh.vertices.ptr();
- int vertex_count = mesh.vertices.size();
-
- 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]),
- };
-
- if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
- return;
-
- // faces of A
- 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 (!separator.test_axis(axis))
- return;
- }
-
- // A<->B edges
- for (int i = 0; i < edge_count; i++) {
-
- Vector3 e1 = p_transform_a.xform(vertices[edges[i].a]) - p_transform_a.xform(vertices[edges[i].b]);
-
- for (int j = 0; j < 3; j++) {
-
- Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
-
- Vector3 axis = e1.cross(e2).normalized();
-
- if (!separator.test_axis(axis))
- return;
- }
- }
-
- if (withMargin) {
-
- //vertex-vertex
- for (int i = 0; i < vertex_count; i++) {
-
- Vector3 va = p_transform_a.xform(vertices[i]);
-
- for (int j = 0; j < 3; j++) {
-
- if (!separator.test_axis((va - vertex[j]).normalized()))
- return;
- }
- }
- //edge-vertex (shell)
-
- for (int i = 0; i < edge_count; i++) {
-
- Vector3 e1 = p_transform_a.basis.xform(vertices[edges[i].a]);
- Vector3 e2 = p_transform_a.basis.xform(vertices[edges[i].b]);
- Vector3 n = (e2 - e1);
-
- for (int j = 0; j < 3; j++) {
-
- Vector3 e3 = vertex[j];
-
- if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized()))
- return;
- }
- }
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 e1 = vertex[i];
- Vector3 e2 = vertex[(i + 1) % 3];
- Vector3 n = (e2 - e1);
-
- 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()))
- return;
- }
- }
- }
-
- separator.generate_contacts();
-}
-
-bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CollisionSolverSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) {
-
- PhysicsServer::ShapeType type_A = p_shape_A->get_type();
-
- ERR_FAIL_COND_V(type_A == PhysicsServer::SHAPE_PLANE, false);
- ERR_FAIL_COND_V(type_A == PhysicsServer::SHAPE_RAY, false);
- ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
-
- PhysicsServer::ShapeType type_B = p_shape_B->get_type();
-
- ERR_FAIL_COND_V(type_B == PhysicsServer::SHAPE_PLANE, false);
- ERR_FAIL_COND_V(type_B == PhysicsServer::SHAPE_RAY, false);
- ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
-
- static const CollisionFunc collision_table[6][6] = {
- { _collision_sphere_sphere<false>,
- _collision_sphere_box<false>,
- _collision_sphere_capsule<false>,
- _collision_sphere_cylinder<false>,
- _collision_sphere_convex_polygon<false>,
- _collision_sphere_face<false> },
- { 0,
- _collision_box_box<false>,
- _collision_box_capsule<false>,
- _collision_box_cylinder<false>,
- _collision_box_convex_polygon<false>,
- _collision_box_face<false> },
- { 0,
- 0,
- _collision_capsule_capsule<false>,
- _collision_capsule_cylinder<false>,
- _collision_capsule_convex_polygon<false>,
- _collision_capsule_face<false> },
- { 0,
- 0,
- 0,
- _collision_cylinder_cylinder<false>,
- _collision_cylinder_convex_polygon<false>,
- _collision_cylinder_face<false> },
- { 0,
- 0,
- 0,
- 0,
- _collision_convex_polygon_convex_polygon<false>,
- _collision_convex_polygon_face<false> },
- { 0,
- 0,
- 0,
- 0,
- 0,
- 0 },
- };
-
- static const CollisionFunc collision_table_margin[6][6] = {
- { _collision_sphere_sphere<true>,
- _collision_sphere_box<true>,
- _collision_sphere_capsule<true>,
- _collision_sphere_cylinder<true>,
- _collision_sphere_convex_polygon<true>,
- _collision_sphere_face<true> },
- { 0,
- _collision_box_box<true>,
- _collision_box_capsule<true>,
- _collision_box_cylinder<true>,
- _collision_box_convex_polygon<true>,
- _collision_box_face<true> },
- { 0,
- 0,
- _collision_capsule_capsule<true>,
- _collision_capsule_cylinder<true>,
- _collision_capsule_convex_polygon<true>,
- _collision_capsule_face<true> },
- { 0,
- 0,
- 0,
- _collision_cylinder_cylinder<true>,
- _collision_cylinder_convex_polygon<true>,
- _collision_cylinder_face<true> },
- { 0,
- 0,
- 0,
- 0,
- _collision_convex_polygon_convex_polygon<true>,
- _collision_convex_polygon_face<true> },
- { 0,
- 0,
- 0,
- 0,
- 0,
- 0 },
- };
-
- _CollectorCallback callback;
- callback.callback = p_result_callback;
- callback.swap = p_swap;
- callback.userdata = p_userdata;
- callback.collided = false;
- callback.prev_axis = r_prev_axis;
-
- const ShapeSW *A = p_shape_A;
- const ShapeSW *B = p_shape_B;
- const Transform *transform_A = &p_transform_A;
- const Transform *transform_B = &p_transform_B;
- real_t margin_A = p_margin_a;
- real_t margin_B = p_margin_b;
-
- if (type_A > type_B) {
- SWAP(A, B);
- SWAP(transform_A, transform_B);
- SWAP(type_A, type_B);
- SWAP(margin_A, margin_B);
- callback.swap = !callback.swap;
- }
-
- CollisionFunc collision_func;
- if (margin_A != 0.0 || margin_B != 0.0) {
- collision_func = collision_table_margin[type_A - 2][type_B - 2];
-
- } else {
- collision_func = collision_table[type_A - 2][type_B - 2];
- }
- ERR_FAIL_COND_V(!collision_func, false);
-
- collision_func(A, *transform_A, B, *transform_B, &callback, margin_A, margin_B);
-
- return callback.collided;
-}
diff --git a/servers/physics/collision_solver_sat.h b/servers/physics/collision_solver_sat.h
deleted file mode 100644
index 31895231f0..0000000000
--- a/servers/physics/collision_solver_sat.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*************************************************************************/
-/* collision_solver_sat.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_SOLVER_SAT_H
-#define COLLISION_SOLVER_SAT_H
-
-#include "collision_solver_sw.h"
-
-bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CollisionSolverSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector3 *r_prev_axis = NULL, real_t p_margin_a = 0, real_t p_margin_b = 0);
-
-#endif // COLLISION_SOLVER_SAT_H
diff --git a/servers/physics/collision_solver_sw.cpp b/servers/physics/collision_solver_sw.cpp
deleted file mode 100644
index ce24ba6bca..0000000000
--- a/servers/physics/collision_solver_sw.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-/*************************************************************************/
-/* collision_solver_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "collision_solver_sw.h"
-#include "collision_solver_sat.h"
-
-#include "gjk_epa.h"
-
-#define collision_solver sat_calculate_penetration
-//#define collision_solver gjk_epa_calculate_penetration
-
-bool CollisionSolverSW::solve_static_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
-
- const PlaneShapeSW *plane = static_cast<const PlaneShapeSW *>(p_shape_A);
- if (p_shape_B->get_type() == PhysicsServer::SHAPE_PLANE)
- return false;
- Plane p = p_transform_A.xform(plane->get_plane());
-
- 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);
-
- bool found = false;
-
- for (int i = 0; i < support_count; i++) {
-
- supports[i] = p_transform_B.xform(supports[i]);
- if (p.distance_to(supports[i]) >= 0)
- continue;
- found = true;
-
- Vector3 support_A = p.project(supports[i]);
-
- if (p_result_callback) {
- if (p_swap_result)
- p_result_callback(supports[i], support_A, p_userdata);
- else
- p_result_callback(support_A, supports[i], p_userdata);
- }
- }
-
- return found;
-}
-
-bool CollisionSolverSW::solve_ray(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
-
- const RayShapeSW *ray = static_cast<const RayShapeSW *>(p_shape_A);
-
- Vector3 from = p_transform_A.origin;
- Vector3 to = from + p_transform_A.basis.get_axis(2) * ray->get_length();
- Vector3 support_A = to;
-
- Transform ai = p_transform_B.affine_inverse();
-
- from = ai.xform(from);
- to = ai.xform(to);
-
- Vector3 p, n;
- if (!p_shape_B->intersect_segment(from, to, p, n))
- return false;
-
- Vector3 support_B = p_transform_B.xform(p);
- if (ray->get_slips_on_slope()) {
- Vector3 global_n = ai.basis.xform_inv(n).normalized();
- support_B = support_A + (support_B - support_A).length() * global_n;
- }
-
- if (p_result_callback) {
- if (p_swap_result)
- p_result_callback(support_B, support_A, p_userdata);
- else
- p_result_callback(support_A, support_B, p_userdata);
- }
- return true;
-}
-
-struct _ConcaveCollisionInfo {
-
- const Transform *transform_A;
- const ShapeSW *shape_A;
- const Transform *transform_B;
- CollisionSolverSW::CallbackResult result_callback;
- void *userdata;
- bool swap_result;
- bool collided;
- int aabb_tests;
- int collisions;
- bool tested;
- real_t margin_A;
- real_t margin_B;
- Vector3 close_A, close_B;
-};
-
-void CollisionSolverSW::concave_callback(void *p_userdata, ShapeSW *p_convex) {
-
- _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
- cinfo.aabb_tests++;
-
- bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result, NULL, cinfo.margin_A, cinfo.margin_B);
- if (!collided)
- return;
-
- cinfo.collided = true;
- cinfo.collisions++;
-}
-
-bool CollisionSolverSW::solve_concave(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) {
-
- const ConcaveShapeSW *concave_B = static_cast<const ConcaveShapeSW *>(p_shape_B);
-
- _ConcaveCollisionInfo cinfo;
- cinfo.transform_A = &p_transform_A;
- cinfo.shape_A = p_shape_A;
- cinfo.transform_B = &p_transform_B;
- cinfo.result_callback = p_result_callback;
- cinfo.userdata = p_userdata;
- cinfo.swap_result = p_swap_result;
- cinfo.collided = false;
- cinfo.collisions = 0;
- cinfo.margin_A = p_margin_A;
- cinfo.margin_B = p_margin_B;
-
- cinfo.aabb_tests = 0;
-
- Transform rel_transform = p_transform_A;
- rel_transform.origin -= p_transform_B.origin;
-
- //quickly compute a local AABB
-
- AABB local_aabb;
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis(p_transform_B.basis.get_axis(i));
- real_t axis_scale = 1.0 / axis.length();
- axis *= axis_scale;
-
- real_t smin, smax;
- p_shape_A->project_range(axis, rel_transform, smin, smax);
- smin -= p_margin_A;
- smax += p_margin_A;
- smin *= axis_scale;
- smax *= axis_scale;
-
- local_aabb.position[i] = smin;
- local_aabb.size[i] = smax - smin;
- }
-
- concave_B->cull(local_aabb, concave_callback, &cinfo);
-
- return cinfo.collided;
-}
-
-bool CollisionSolverSW::solve_static(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) {
-
- PhysicsServer::ShapeType type_A = p_shape_A->get_type();
- PhysicsServer::ShapeType type_B = p_shape_B->get_type();
- bool concave_A = p_shape_A->is_concave();
- bool concave_B = p_shape_B->is_concave();
-
- bool swap = false;
-
- if (type_A > type_B) {
- SWAP(type_A, type_B);
- SWAP(concave_A, concave_B);
- swap = true;
- }
-
- if (type_A == PhysicsServer::SHAPE_PLANE) {
-
- if (type_B == PhysicsServer::SHAPE_PLANE)
- return false;
- if (type_B == PhysicsServer::SHAPE_RAY) {
- 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);
- } else {
- return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
- }
-
- } else if (type_A == PhysicsServer::SHAPE_RAY) {
-
- if (type_B == PhysicsServer::SHAPE_RAY)
- return false;
-
- if (swap) {
- return solve_ray(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
- } else {
- return solve_ray(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;
-
- if (!swap)
- return solve_concave(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_A, p_margin_B);
- else
- return solve_concave(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_A, p_margin_B);
-
- } else {
-
- return collision_solver(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, r_sep_axis, p_margin_A, p_margin_B);
- }
-}
-
-void CollisionSolverSW::concave_distance_callback(void *p_userdata, ShapeSW *p_convex) {
-
- _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
- cinfo.aabb_tests++;
- if (cinfo.collided)
- return;
-
- Vector3 close_A, close_B;
- cinfo.collided = !gjk_epa_calculate_distance(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, close_A, close_B);
-
- if (cinfo.collided)
- return;
- if (!cinfo.tested || close_A.distance_squared_to(close_B) < cinfo.close_A.distance_squared_to(cinfo.close_B)) {
-
- cinfo.close_A = close_A;
- cinfo.close_B = close_B;
- cinfo.tested = true;
- }
-
- cinfo.collisions++;
-}
-
-bool CollisionSolverSW::solve_distance_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) {
-
- const PlaneShapeSW *plane = static_cast<const PlaneShapeSW *>(p_shape_A);
- if (p_shape_B->get_type() == PhysicsServer::SHAPE_PLANE)
- return false;
- Plane p = p_transform_A.xform(plane->get_plane());
-
- 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);
-
- bool collided = false;
- Vector3 closest;
- real_t closest_d = 0;
-
- for (int i = 0; i < support_count; i++) {
-
- supports[i] = p_transform_B.xform(supports[i]);
- real_t d = p.distance_to(supports[i]);
- if (i == 0 || d < closest_d) {
- closest = supports[i];
- closest_d = d;
- if (d <= 0)
- collided = true;
- }
- }
-
- r_point_A = p.project(closest);
- r_point_B = closest;
-
- return collided;
-}
-
-bool CollisionSolverSW::solve_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) {
-
- if (p_shape_A->is_concave())
- return false;
-
- if (p_shape_B->get_type() == PhysicsServer::SHAPE_PLANE) {
-
- Vector3 a, b;
- bool col = solve_distance_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b);
- r_point_A = b;
- r_point_B = a;
- return !col;
-
- } else if (p_shape_B->is_concave()) {
-
- if (p_shape_A->is_concave())
- return false;
-
- const ConcaveShapeSW *concave_B = static_cast<const ConcaveShapeSW *>(p_shape_B);
-
- _ConcaveCollisionInfo cinfo;
- cinfo.transform_A = &p_transform_A;
- cinfo.shape_A = p_shape_A;
- cinfo.transform_B = &p_transform_B;
- cinfo.result_callback = NULL;
- cinfo.userdata = NULL;
- cinfo.swap_result = false;
- cinfo.collided = false;
- cinfo.collisions = 0;
- cinfo.aabb_tests = 0;
- cinfo.tested = false;
-
- Transform rel_transform = p_transform_A;
- rel_transform.origin -= p_transform_B.origin;
-
- //quickly compute a local AABB
-
- bool use_cc_hint = p_concave_hint != AABB();
- AABB cc_hint_aabb;
- if (use_cc_hint) {
- cc_hint_aabb = p_concave_hint;
- cc_hint_aabb.position -= p_transform_B.origin;
- }
-
- AABB local_aabb;
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis(p_transform_B.basis.get_axis(i));
- real_t axis_scale = ((real_t)1.0) / axis.length();
- axis *= axis_scale;
-
- real_t smin, smax;
-
- if (use_cc_hint) {
- cc_hint_aabb.project_range_in_plane(Plane(axis, 0), smin, smax);
- } else {
- p_shape_A->project_range(axis, rel_transform, smin, smax);
- }
-
- smin *= axis_scale;
- smax *= axis_scale;
-
- local_aabb.position[i] = smin;
- local_aabb.size[i] = smax - smin;
- }
-
- concave_B->cull(local_aabb, concave_distance_callback, &cinfo);
- if (!cinfo.collided) {
- r_point_A = cinfo.close_A;
- r_point_B = cinfo.close_B;
- }
-
- return !cinfo.collided;
- } else {
-
- return gjk_epa_calculate_distance(p_shape_A, p_transform_A, p_shape_B, p_transform_B, r_point_A, r_point_B); //should pass sepaxis..
- }
-}
diff --git a/servers/physics/collision_solver_sw.h b/servers/physics/collision_solver_sw.h
deleted file mode 100644
index d4dc1ac2a2..0000000000
--- a/servers/physics/collision_solver_sw.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*************************************************************************/
-/* collision_solver_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 COLLISION_SOLVER_SW_H
-#define COLLISION_SOLVER_SW_H
-
-#include "shape_sw.h"
-
-class CollisionSolverSW {
-public:
- typedef void (*CallbackResult)(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
-
-private:
- static void concave_callback(void *p_userdata, ShapeSW *p_convex);
- static bool solve_static_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static bool solve_ray(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
- static bool solve_concave(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *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, ShapeSW *p_convex);
- static bool solve_distance_plane(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B);
-
-public:
- static bool solve_static(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = NULL, real_t p_margin_A = 0, real_t p_margin_B = 0);
- static bool solve_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis = NULL);
-};
-
-#endif // COLLISION_SOLVER__SW_H
diff --git a/servers/physics/constraint_sw.h b/servers/physics/constraint_sw.h
deleted file mode 100644
index 22f31b411b..0000000000
--- a/servers/physics/constraint_sw.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*************************************************************************/
-/* constraint_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 CONSTRAINT_SW_H
-#define CONSTRAINT_SW_H
-
-#include "body_sw.h"
-
-class ConstraintSW {
-
- BodySW **_body_ptr;
- int _body_count;
- uint64_t island_step;
- ConstraintSW *island_next;
- ConstraintSW *island_list_next;
- int priority;
- bool disabled_collisions_between_bodies;
-
- RID self;
-
-protected:
- ConstraintSW(BodySW **p_body_ptr = NULL, int p_body_count = 0) {
- _body_ptr = p_body_ptr;
- _body_count = p_body_count;
- island_step = 0;
- priority = 1;
- disabled_collisions_between_bodies = true;
- }
-
-public:
- _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
- _FORCE_INLINE_ RID get_self() const { return self; }
-
- _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_ ConstraintSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(ConstraintSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ ConstraintSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(ConstraintSW *p_next) { island_list_next = p_next; }
-
- _FORCE_INLINE_ BodySW **get_body_ptr() const { return _body_ptr; }
- _FORCE_INLINE_ int get_body_count() const { return _body_count; }
-
- _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
- _FORCE_INLINE_ int get_priority() const { return priority; }
-
- _FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; }
- _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
-
- virtual bool setup(real_t p_step) = 0;
- virtual void solve(real_t p_step) = 0;
-
- virtual ~ConstraintSW() {}
-};
-
-#endif // CONSTRAINT__SW_H
diff --git a/servers/physics/gjk_epa.cpp b/servers/physics/gjk_epa.cpp
deleted file mode 100644
index abf0c0dc15..0000000000
--- a/servers/physics/gjk_epa.cpp
+++ /dev/null
@@ -1,946 +0,0 @@
-/*************************************************************************/
-/* gjk_epa.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "gjk_epa.h"
-
-/* Disabling formatting for thirdparty code snippet */
-/* clang-format off */
-
-/*************** Bullet's GJK-EPA2 IMPLEMENTATION *******************/
-
-/*
-Bullet Continuous Collision Detection and Physics Library
-Copyright (c) 2003-2008 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.
-*/
-
-/*
-GJK-EPA collision solver by Nathanael Presson, 2008
-*/
-
- // Config
-
-/* GJK */
-#define GJK_MAX_ITERATIONS 128
-#define GJK_ACCURARY ((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)
-#define GJK_SIMPLEX3_EPS ((real_t)0.0)
-#define GJK_SIMPLEX4_EPS ((real_t)0.0)
-
-/* EPA */
-#define EPA_MAX_VERTICES 64
-#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
-#define EPA_MAX_ITERATIONS 255
-#define EPA_ACCURACY ((real_t)0.0001)
-#define EPA_FALLBACK (10*EPA_ACCURACY)
-#define EPA_PLANE_EPS ((real_t)0.00001)
-#define EPA_INSIDE_EPS ((real_t)0.01)
-
-namespace GjkEpa2 {
-
-
-struct sResults {
- enum eStatus {
- Separated, /* Shapes doesn't penetrate */
- Penetrating, /* Shapes are penetrating */
- GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */
- EPA_Failed /* EPA phase fail, bigger problem, need to save parameters, and debug */
- } status;
-
- Vector3 witnesses[2];
- Vector3 normal;
- real_t distance;
-};
-
-// Shorthands
-typedef unsigned int U;
-typedef unsigned char U1;
-
-// MinkowskiDiff
-struct MinkowskiDiff {
-
- const ShapeSW* m_shapes[2];
-
- Transform transform_A;
- Transform transform_B;
-
- // 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 Support1 ( const Vector3& d ) const {
- return transform_B.xform( m_shapes[1]->get_support( transform_B.basis.xform_inv(d).normalized() ) );
- }
-
- _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 ) );
- else
- return ( Support0 ( d ) );
- }
-};
-
-typedef MinkowskiDiff tShape;
-
-
-// GJK
-struct GJK
-{
- /* Types */
- struct sSV
- {
- Vector3 d,w;
- };
- struct sSimplex
- {
- sSV* c[4];
- real_t p[4];
- U rank;
- };
- struct eStatus { enum _ {
- Valid,
- Inside,
- Failed };};
- /* Fields */
- tShape m_shape;
- Vector3 m_ray;
- real_t m_distance;
- sSimplex m_simplices[2];
- sSV m_store[4];
- sSV* m_free[4];
- U m_nfree;
- U m_current;
- sSimplex* m_simplex;
- eStatus::_ m_status;
- /* Methods */
- GJK()
- {
- Initialize();
- }
- void Initialize()
- {
- m_ray = Vector3(0,0,0);
- m_nfree = 0;
- m_status = eStatus::Failed;
- m_current = 0;
- m_distance = 0;
- }
- eStatus::_ Evaluate(const tShape& shapearg,const Vector3& guess)
- {
- U iterations=0;
- real_t sqdist=0;
- real_t alpha=0;
- Vector3 lastw[4];
- U clastw=0;
- /* Initialize solver */
- m_free[0] = &m_store[0];
- m_free[1] = &m_store[1];
- m_free[2] = &m_store[2];
- m_free[3] = &m_store[3];
- m_nfree = 4;
- m_current = 0;
- m_status = eStatus::Valid;
- m_shape = shapearg;
- m_distance = 0;
- /* Initialize simplex */
- m_simplices[0].rank = 0;
- m_ray = guess;
- const real_t sqrl= m_ray.length_squared();
- appendvertice(m_simplices[0],sqrl>0?-m_ray:Vector3(1,0,0));
- m_simplices[0].p[0] = 1;
- m_ray = m_simplices[0].c[0]->w;
- sqdist = sqrl;
- lastw[0] =
- lastw[1] =
- lastw[2] =
- lastw[3] = m_ray;
- /* Loop */
- do {
- const U next=1-m_current;
- sSimplex& cs=m_simplices[m_current];
- sSimplex& ns=m_simplices[next];
- /* Check zero */
- const real_t rl=m_ray.length();
- if(rl<GJK_MIN_DISTANCE)
- {/* Touching or inside */
- m_status=eStatus::Inside;
- break;
- }
- /* Append new vertice in -'v' direction */
- appendvertice(cs,-m_ray);
- const Vector3& w=cs.c[cs.rank-1]->w;
- bool found=false;
- for(U i=0;i<4;++i)
- {
- if((w-lastw[i]).length_squared()<GJK_DUPLICATED_EPS)
- { found=true;break; }
- }
- if(found)
- {/* Return old simplex */
- removevertice(m_simplices[m_current]);
- break;
- }
- else
- {/* Update lastw */
- lastw[clastw=(clastw+1)&3]=w;
- }
- /* Check for termination */
- const real_t omega=vec3_dot(m_ray,w)/rl;
- alpha=MAX(omega,alpha);
- if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
- {/* Return old simplex */
- removevertice(m_simplices[m_current]);
- break;
- }
- /* Reduce simplex */
- real_t weights[4];
- U mask=0;
- switch(cs.rank)
- {
- case 2: sqdist=projectorigin( cs.c[0]->w,
- cs.c[1]->w,
- weights,mask);break;
- case 3: sqdist=projectorigin( cs.c[0]->w,
- cs.c[1]->w,
- cs.c[2]->w,
- weights,mask);break;
- case 4: sqdist=projectorigin( cs.c[0]->w,
- cs.c[1]->w,
- cs.c[2]->w,
- cs.c[3]->w,
- weights,mask);break;
- }
- if(sqdist>=0)
- {/* Valid */
- ns.rank = 0;
- m_ray = Vector3(0,0,0);
- m_current = next;
- for(U i=0,ni=cs.rank;i<ni;++i)
- {
- if(mask&(1<<i))
- {
- ns.c[ns.rank] = cs.c[i];
- ns.p[ns.rank++] = weights[i];
- m_ray += cs.c[i]->w*weights[i];
- }
- else
- {
- m_free[m_nfree++] = cs.c[i];
- }
- }
- if(mask==15) m_status=eStatus::Inside;
- }
- else
- {/* Return old simplex */
- removevertice(m_simplices[m_current]);
- break;
- }
- m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eStatus::Failed;
- } while(m_status==eStatus::Valid);
- m_simplex=&m_simplices[m_current];
- switch(m_status)
- {
- case eStatus::Valid: m_distance=m_ray.length();break;
- case eStatus::Inside: m_distance=0;break;
- default: {}
- }
- return(m_status);
- }
- bool EncloseOrigin()
- {
- switch(m_simplex->rank)
- {
- case 1:
- {
- for(U i=0;i<3;++i)
- {
- Vector3 axis=Vector3(0,0,0);
- axis[i]=1;
- appendvertice(*m_simplex, axis);
- if(EncloseOrigin()) return(true);
- removevertice(*m_simplex);
- appendvertice(*m_simplex,-axis);
- if(EncloseOrigin()) return(true);
- removevertice(*m_simplex);
- }
- }
- break;
- case 2:
- {
- const Vector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w;
- for(U i=0;i<3;++i)
- {
- Vector3 axis=Vector3(0,0,0);
- axis[i]=1;
- const Vector3 p=vec3_cross(d,axis);
- if(p.length_squared()>0)
- {
- appendvertice(*m_simplex, p);
- if(EncloseOrigin()) return(true);
- removevertice(*m_simplex);
- appendvertice(*m_simplex,-p);
- if(EncloseOrigin()) return(true);
- removevertice(*m_simplex);
- }
- }
- }
- break;
- case 3:
- {
- const Vector3 n=vec3_cross(m_simplex->c[1]->w-m_simplex->c[0]->w,
- m_simplex->c[2]->w-m_simplex->c[0]->w);
- if(n.length_squared()>0)
- {
- appendvertice(*m_simplex,n);
- if(EncloseOrigin()) return(true);
- removevertice(*m_simplex);
- appendvertice(*m_simplex,-n);
- if(EncloseOrigin()) return(true);
- removevertice(*m_simplex);
- }
- }
- break;
- case 4:
- {
- if(Math::abs(det( m_simplex->c[0]->w-m_simplex->c[3]->w,
- m_simplex->c[1]->w-m_simplex->c[3]->w,
- m_simplex->c[2]->w-m_simplex->c[3]->w))>0)
- return(true);
- }
- break;
- }
- return(false);
- }
- /* Internals */
- void getsupport(const Vector3& d,sSV& sv) const
- {
- sv.d = d/d.length();
- sv.w = m_shape.Support(sv.d);
- }
- void removevertice(sSimplex& simplex)
- {
- m_free[m_nfree++]=simplex.c[--simplex.rank];
- }
- void appendvertice(sSimplex& simplex,const Vector3& v)
- {
- simplex.p[simplex.rank]=0;
- simplex.c[simplex.rank]=m_free[--m_nfree];
- getsupport(v,*simplex.c[simplex.rank++]);
- }
- static real_t det(const Vector3& a,const Vector3& b,const Vector3& c)
- {
- return( a.y*b.z*c.x+a.z*b.x*c.y-
- a.x*b.z*c.y-a.y*b.x*c.z+
- a.x*b.y*c.z-a.z*b.y*c.x);
- }
- static real_t projectorigin( const Vector3& a,
- const Vector3& b,
- real_t* w,U& m)
- {
- const Vector3 d=b-a;
- const real_t l=d.length_squared();
- if(l>GJK_SIMPLEX2_EPS)
- {
- const real_t t(l>0?-vec3_dot(a,d)/l:0);
- if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length_squared()); }
- else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length_squared()); }
- else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length_squared()); }
- }
- return(-1);
- }
- static real_t projectorigin( const Vector3& a,
- const Vector3& b,
- const Vector3& c,
- real_t* w,U& m)
- {
- static const U imd3[]={1,2,0};
- const Vector3* vt[]={&a,&b,&c};
- const Vector3 dl[]={a-b,b-c,c-a};
- const Vector3 n=vec3_cross(dl[0],dl[1]);
- const real_t l=n.length_squared();
- if(l>GJK_SIMPLEX3_EPS)
- {
- real_t mindist=-1;
- real_t subw[2] = { 0 , 0};
- U subm = 0;
- for(U i=0;i<3;++i)
- {
- if(vec3_dot(*vt[i],vec3_cross(dl[i],n))>0)
- {
- const U j=imd3[i];
- const real_t subd(projectorigin(*vt[i],*vt[j],subw,subm));
- if((mindist<0)||(subd<mindist))
- {
- mindist = subd;
- m = static_cast<U>(((subm&1)?1<<i:0)+((subm&2)?1<<j:0));
- w[i] = subw[0];
- w[j] = subw[1];
- w[imd3[j]] = 0;
- }
- }
- }
- if(mindist<0)
- {
- const real_t d=vec3_dot(a,n);
- const real_t s=Math::sqrt(l);
- const Vector3 p=n*(d/l);
- mindist = p.length_squared();
- m = 7;
- w[0] = (vec3_cross(dl[1],b-p)).length()/s;
- w[1] = (vec3_cross(dl[2],c-p)).length()/s;
- w[2] = 1-(w[0]+w[1]);
- }
- return(mindist);
- }
- return(-1);
- }
- static real_t projectorigin( const Vector3& a,
- const Vector3& b,
- const Vector3& c,
- const Vector3& d,
- real_t* w,U& m)
- {
- static const U imd3[]={1,2,0};
- const Vector3* vt[]={&a,&b,&c,&d};
- const Vector3 dl[]={a-d,b-d,c-d};
- const real_t vl=det(dl[0],dl[1],dl[2]);
- const bool ng=(vl*vec3_dot(a,vec3_cross(b-c,a-b)))<=0;
- if(ng&&(Math::abs(vl)>GJK_SIMPLEX4_EPS))
- {
- real_t mindist=-1;
- real_t subw[3];
- U subm=0;
- for(U i=0;i<3;++i)
- {
- const U j=imd3[i];
- const real_t s=vl*vec3_dot(d,vec3_cross(dl[i],dl[j]));
- if(s>0)
- {
- const real_t subd=projectorigin(*vt[i],*vt[j],d,subw,subm);
- if((mindist<0)||(subd<mindist))
- {
- mindist = subd;
- m = static_cast<U>((subm&1?1<<i:0)+
- (subm&2?1<<j:0)+
- (subm&4?8:0));
- w[i] = subw[0];
- w[j] = subw[1];
- w[imd3[j]] = 0;
- w[3] = subw[2];
- }
- }
- }
- if(mindist<0)
- {
- mindist = 0;
- m = 15;
- w[0] = det(c,b,d)/vl;
- w[1] = det(a,c,d)/vl;
- w[2] = det(b,a,d)/vl;
- w[3] = 1-(w[0]+w[1]+w[2]);
- }
- return(mindist);
- }
- return(-1);
- }
-};
-
- // EPA
- struct EPA
- {
- /* Types */
- typedef GJK::sSV sSV;
- struct sFace
- {
- Vector3 n;
- real_t d;
- real_t p;
- sSV* c[3];
- sFace* f[3];
- sFace* l[2];
- U1 e[3];
- U1 pass;
- };
- struct sList
- {
- sFace* root;
- U count;
- sList() : root(0),count(0) {}
- };
- struct sHorizon
- {
- sFace* cf;
- sFace* ff;
- U nf;
- sHorizon() : cf(0),ff(0),nf(0) {}
- };
- struct eStatus { enum _ {
- Valid,
- Touching,
- Degenerated,
- NonConvex,
- InvalidHull,
- OutOfFaces,
- OutOfVertices,
- AccuraryReached,
- FallBack,
- Failed };};
- /* Fields */
- eStatus::_ m_status;
- GJK::sSimplex m_result;
- Vector3 m_normal;
- real_t m_depth;
- sSV m_sv_store[EPA_MAX_VERTICES];
- sFace m_fc_store[EPA_MAX_FACES];
- U m_nextsv;
- sList m_hull;
- sList m_stock;
- /* Methods */
- EPA()
- {
- Initialize();
- }
-
-
- static inline void bind(sFace* fa,U ea,sFace* fb,U eb)
- {
- fa->e[ea]=(U1)eb;fa->f[ea]=fb;
- fb->e[eb]=(U1)ea;fb->f[eb]=fa;
- }
- static inline void append(sList& list,sFace* face)
- {
- face->l[0] = 0;
- face->l[1] = list.root;
- if(list.root) list.root->l[0]=face;
- list.root = face;
- ++list.count;
- }
- static inline void remove(sList& list,sFace* face)
- {
- if(face->l[1]) face->l[1]->l[0]=face->l[0];
- if(face->l[0]) face->l[0]->l[1]=face->l[1];
- if(face==list.root) list.root=face->l[1];
- --list.count;
- }
-
-
- void Initialize()
- {
- m_status = eStatus::Failed;
- m_normal = Vector3(0,0,0);
- m_depth = 0;
- m_nextsv = 0;
- for(U i=0;i<EPA_MAX_FACES;++i)
- {
- append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);
- }
- }
- eStatus::_ Evaluate(GJK& gjk,const Vector3& guess)
- {
- GJK::sSimplex& simplex=*gjk.m_simplex;
- if((simplex.rank>1)&&gjk.EncloseOrigin())
- {
-
- /* Clean up */
- while(m_hull.root)
- {
- sFace* f = m_hull.root;
- remove(m_hull,f);
- append(m_stock,f);
- }
- m_status = eStatus::Valid;
- m_nextsv = 0;
- /* Orient simplex */
- if(gjk.det( simplex.c[0]->w-simplex.c[3]->w,
- simplex.c[1]->w-simplex.c[3]->w,
- simplex.c[2]->w-simplex.c[3]->w)<0)
- {
- SWAP(simplex.c[0],simplex.c[1]);
- SWAP(simplex.p[0],simplex.p[1]);
- }
- /* Build initial hull */
- sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),
- newface(simplex.c[1],simplex.c[0],simplex.c[3],true),
- newface(simplex.c[2],simplex.c[1],simplex.c[3],true),
- newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};
- if(m_hull.count==4)
- {
- sFace* best=findbest();
- sFace outer=*best;
- U pass=0;
- U iterations=0;
- bind(tetra[0],0,tetra[1],0);
- bind(tetra[0],1,tetra[2],0);
- bind(tetra[0],2,tetra[3],0);
- bind(tetra[1],1,tetra[3],2);
- bind(tetra[1],2,tetra[2],1);
- bind(tetra[2],2,tetra[3],1);
- m_status=eStatus::Valid;
- for(;iterations<EPA_MAX_ITERATIONS;++iterations)
- {
- if(m_nextsv<EPA_MAX_VERTICES)
- {
- sHorizon horizon;
- sSV* w=&m_sv_store[m_nextsv++];
- bool valid=true;
- best->pass = (U1)(++pass);
- gjk.getsupport(best->n,*w);
- const real_t wdist=vec3_dot(best->n,w->w)-best->d;
- if(wdist>EPA_ACCURACY)
- {
- for(U j=0;(j<3)&&valid;++j)
- {
- valid&=expand( pass,w,
- best->f[j],best->e[j],
- horizon);
- }
- if(valid&&(horizon.nf>=3))
- {
- bind(horizon.cf,1,horizon.ff,2);
- remove(m_hull,best);
- append(m_stock,best);
- best=findbest();
- if(best->p>=outer.p) outer=*best;
- } else { m_status=eStatus::InvalidHull;break; }
- } else { m_status=eStatus::AccuraryReached;break; }
- } else { m_status=eStatus::OutOfVertices;break; }
- }
- const Vector3 projection=outer.n*outer.d;
- m_normal = outer.n;
- m_depth = outer.d;
- m_result.rank = 3;
- m_result.c[0] = outer.c[0];
- m_result.c[1] = outer.c[1];
- m_result.c[2] = outer.c[2];
- m_result.p[0] = vec3_cross( outer.c[1]->w-projection,
- outer.c[2]->w-projection).length();
- m_result.p[1] = vec3_cross( outer.c[2]->w-projection,
- outer.c[0]->w-projection).length();
- m_result.p[2] = vec3_cross( outer.c[0]->w-projection,
- outer.c[1]->w-projection).length();
- const real_t sum=m_result.p[0]+m_result.p[1]+m_result.p[2];
- m_result.p[0] /= sum;
- m_result.p[1] /= sum;
- m_result.p[2] /= sum;
- return(m_status);
- }
- }
- /* Fallback */
- 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_depth = 0;
- m_result.rank=1;
- m_result.c[0]=simplex.c[0];
- m_result.p[0]=1;
- return(m_status);
- }
- sFace* newface(sSV* a,sSV* b,sSV* c,bool forced)
- {
- if(m_stock.root)
- {
- sFace* face=m_stock.root;
- remove(m_stock,face);
- append(m_hull,face);
- face->pass = 0;
- face->c[0] = a;
- face->c[1] = b;
- face->c[2] = c;
- 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;
- face->n /= l;
- if(forced||(face->d>=-EPA_PLANE_EPS))
- {
- return(face);
- } else m_status=eStatus::NonConvex;
- } else m_status=eStatus::Degenerated;
- remove(m_hull,face);
- append(m_stock,face);
- return(0);
- }
- // -- GODOT start --
- //m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces;
- m_status=eStatus::OutOfFaces;
- // -- GODOT end --
- return(0);
- }
- sFace* findbest()
- {
- 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))
- {
- minf=f;
- mind=sqd;
- maxp=f->p;
- }
- }
- return(minf);
- }
- bool expand(U pass,sSV* w,sFace* f,U e,sHorizon& horizon)
- {
- static const U i1m3[]={1,2,0};
- static const U i2m3[]={2,0,1};
- if(f->pass!=pass)
- {
- const U e1=i1m3[e];
- if((vec3_dot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)
- {
- sFace* nf=newface(f->c[e1],f->c[e],w,false);
- if(nf)
- {
- bind(nf,0,f,e);
- if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf;
- horizon.cf=nf;
- ++horizon.nf;
- return(true);
- }
- }
- else
- {
- const U e2=i2m3[e];
- f->pass = (U1)pass;
- if( expand(pass,w,f->f[e1],f->e[e1],horizon)&&
- expand(pass,w,f->f[e2],f->e[e2],horizon))
- {
- remove(m_hull,f);
- append(m_stock,f);
- return(true);
- }
- }
- }
- return(false);
- }
-
- };
-
- //
- static void Initialize( const ShapeSW* shape0,const Transform& wtrs0,
- const ShapeSW* shape1,const Transform& wtrs1,
- sResults& results,
- tShape& shape,
- bool withmargins)
- {
- /* Results */
- results.witnesses[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;
-
- }
-
-
-
-//
-// Api
-//
-
-//
-
-//
-bool Distance( const ShapeSW* shape0,
- const Transform& wtrs0,
- const ShapeSW* shape1,
- const Transform& wtrs1,
- const Vector3& guess,
- sResults& results)
-{
- tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
- GJK gjk;
- GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);
- if(gjk_status==GJK::eStatus::Valid)
- {
- Vector3 w0=Vector3(0,0,0);
- Vector3 w1=Vector3(0,0,0);
- for(U i=0;i<gjk.m_simplex->rank;++i)
- {
- const real_t p=gjk.m_simplex->p[i];
- w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
- w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
- }
- results.witnesses[0] = w0;
- results.witnesses[1] = w1;
- results.normal = w0-w1;
- results.distance = results.normal.length();
- results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1;
- return(true);
- }
- else
- {
- results.status = gjk_status==GJK::eStatus::Inside?
- sResults::Penetrating :
- sResults::GJK_Failed ;
- return(false);
- }
-}
-
-//
-bool Penetration( const ShapeSW* shape0,
- const Transform& wtrs0,
- const ShapeSW* shape1,
- const Transform& wtrs1,
- const Vector3& guess,
- sResults& results
- )
-{
- tShape shape;
- Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
- GJK gjk;
- GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
- switch(gjk_status)
- {
- case GJK::eStatus::Inside:
- {
- EPA epa;
- EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess);
- if(epa_status!=EPA::eStatus::Failed)
- {
- Vector3 w0=Vector3(0,0,0);
- for(U i=0;i<epa.m_result.rank;++i)
- {
- w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];
- }
- results.status = sResults::Penetrating;
- results.witnesses[0] = w0;
- results.witnesses[1] = w0-epa.m_normal*epa.m_depth;
- results.normal = -epa.m_normal;
- results.distance = -epa.m_depth;
- return(true);
- } else results.status=sResults::EPA_Failed;
- }
- break;
- case GJK::eStatus::Failed:
- results.status=sResults::GJK_Failed;
- break;
- default: {}
- }
- return(false);
-}
-
-
-/* Symbols cleanup */
-
-#undef GJK_MAX_ITERATIONS
-#undef GJK_ACCURARY
-#undef GJK_MIN_DISTANCE
-#undef GJK_DUPLICATED_EPS
-#undef GJK_SIMPLEX2_EPS
-#undef GJK_SIMPLEX3_EPS
-#undef GJK_SIMPLEX4_EPS
-
-#undef EPA_MAX_VERTICES
-#undef EPA_MAX_FACES
-#undef EPA_MAX_ITERATIONS
-#undef EPA_ACCURACY
-#undef EPA_FALLBACK
-#undef EPA_PLANE_EPS
-#undef EPA_INSIDE_EPS
-
-
-} // end of namespace
-
-/* clang-format on */
-
-bool gjk_epa_calculate_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *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)) {
-
- r_result_A = res.witnesses[0];
- r_result_B = res.witnesses[1];
- return true;
- }
-
- return false;
-}
-
-bool gjk_epa_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CollisionSolverSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap) {
-
- 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 (p_result_callback) {
- if (p_swap)
- p_result_callback(res.witnesses[1], res.witnesses[0], p_userdata);
- else
- p_result_callback(res.witnesses[0], res.witnesses[1], p_userdata);
- }
- return true;
- }
-
- return false;
-}
diff --git a/servers/physics/gjk_epa.h b/servers/physics/gjk_epa.h
deleted file mode 100644
index 38c616cde0..0000000000
--- a/servers/physics/gjk_epa.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*************************************************************************/
-/* gjk_epa.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 GJK_EPA_H
-#define GJK_EPA_H
-
-#include "collision_solver_sw.h"
-#include "shape_sw.h"
-
-bool gjk_epa_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, CollisionSolverSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false);
-bool gjk_epa_calculate_distance(const ShapeSW *p_shape_A, const Transform &p_transform_A, const ShapeSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B);
-
-#endif
diff --git a/servers/physics/joints/SCsub b/servers/physics/joints/SCsub
deleted file mode 100644
index d730144861..0000000000
--- a/servers/physics/joints/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp
deleted file mode 100644
index 58f66f7ea2..0000000000
--- a/servers/physics/joints/cone_twist_joint_sw.cpp
+++ /dev/null
@@ -1,366 +0,0 @@
-/*************************************************************************/
-/* cone_twist_joint_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-/*
-Bullet Continuous Collision Detection and Physics Library
-ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
-
-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.
-
-Written by: Marcus Hennix
-*/
-
-#include "cone_twist_joint_sw.h"
-
-static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
-
- if (Math::abs(n.z) > Math_SQRT12) {
- // choose p in y-z plane
- real_t a = n[1] * n[1] + n[2] * n[2];
- real_t k = 1.0 / Math::sqrt(a);
- p = Vector3(0, -n[2] * k, n[1] * k);
- // set q = n x p
- q = Vector3(a * k, -n[0] * p[2], n[0] * p[1]);
- } else {
- // choose p in x-y plane
- real_t a = n.x * n.x + n.y * n.y;
- real_t k = 1.0 / Math::sqrt(a);
- p = Vector3(-n.y * k, n.x * k, 0);
- // set q = n x p
- q = Vector3(-n.z * p.y, n.z * p.x, a * k);
- }
-}
-
-static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
- real_t coeff_1 = Math_PI / 4.0f;
- real_t coeff_2 = 3.0f * coeff_1;
- real_t abs_y = Math::abs(y);
- real_t angle;
- if (x >= 0.0f) {
- real_t r = (x - abs_y) / (x + abs_y);
- angle = coeff_1 - coeff_1 * r;
- } else {
- real_t r = (x + abs_y) / (abs_y - x);
- angle = coeff_2 - coeff_1 * r;
- }
- return (y < 0.0f) ? -angle : angle;
-}
-
-ConeTwistJointSW::ConeTwistJointSW(BodySW *rbA, BodySW *rbB, const Transform &rbAFrame, const Transform &rbBFrame) :
- JointSW(_arr, 2) {
-
- A = rbA;
- B = rbB;
-
- m_rbAFrame = rbAFrame;
- m_rbBFrame = rbBFrame;
-
- m_swingSpan1 = Math_PI / 4.0;
- m_swingSpan2 = Math_PI / 4.0;
- m_twistSpan = Math_PI * 2;
- m_biasFactor = 0.3f;
- m_relaxationFactor = 1.0f;
-
- m_angularOnly = false;
- m_solveTwistLimit = false;
- m_solveSwingLimit = false;
-
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
-
- m_appliedImpulse = 0;
-}
-
-bool ConeTwistJointSW::setup(real_t p_timestep) {
- m_appliedImpulse = real_t(0.);
-
- //set bias, sign, clear accumulator
- m_swingCorrection = real_t(0.);
- m_twistLimitSign = real_t(0.);
- m_solveTwistLimit = false;
- m_solveSwingLimit = false;
- m_accTwistLimitImpulse = real_t(0.);
- m_accSwingLimitImpulse = real_t(0.);
-
- if (!m_angularOnly) {
- Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
- Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
- Vector3 relPos = pivotBInW - pivotAInW;
-
- Vector3 normal[3];
- if (Math::is_zero_approx(relPos.length_squared())) {
- normal[0] = Vector3(real_t(1.0), 0, 0);
- } else {
- normal[0] = relPos.normalized();
- }
-
- plane_space(normal[0], normal[1], normal[2]);
-
- for (int i = 0; i < 3; i++) {
- memnew_placement(&m_jac[i], JacobianEntrySW(
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
- pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
- normal[i],
- A->get_inv_inertia(),
- A->get_inv_mass(),
- B->get_inv_inertia(),
- B->get_inv_mass()));
- }
- }
-
- Vector3 b1Axis1, b1Axis2, b1Axis3;
- Vector3 b2Axis1, b2Axis2;
-
- b1Axis1 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(0));
- b2Axis1 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(0));
-
- real_t swing1 = real_t(0.), swing2 = real_t(0.);
-
- real_t swx = real_t(0.), swy = real_t(0.);
- real_t thresh = real_t(10.);
- real_t fact;
-
- // Get Frame into world space
- if (m_swingSpan1 >= real_t(0.05f)) {
- b1Axis2 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(1));
- //swing1 = btAtan2Fast( b2Axis1.dot(b1Axis2),b2Axis1.dot(b1Axis1) );
- swx = b2Axis1.dot(b1Axis1);
- swy = b2Axis1.dot(b1Axis2);
- swing1 = atan2fast(swy, swx);
- fact = (swy * swy + swx * swx) * thresh * thresh;
- fact = fact / (fact + real_t(1.0));
- swing1 *= fact;
- }
-
- if (m_swingSpan2 >= real_t(0.05f)) {
- b1Axis3 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(2));
- //swing2 = btAtan2Fast( b2Axis1.dot(b1Axis3),b2Axis1.dot(b1Axis1) );
- swx = b2Axis1.dot(b1Axis1);
- swy = b2Axis1.dot(b1Axis3);
- swing2 = atan2fast(swy, swx);
- fact = (swy * swy + swx * swx) * thresh * thresh;
- fact = fact / (fact + real_t(1.0));
- swing2 *= fact;
- }
-
- real_t RMaxAngle1Sq = 1.0f / (m_swingSpan1 * m_swingSpan1);
- real_t RMaxAngle2Sq = 1.0f / (m_swingSpan2 * m_swingSpan2);
- real_t EllipseAngle = Math::abs(swing1 * swing1) * RMaxAngle1Sq + Math::abs(swing2 * swing2) * RMaxAngle2Sq;
-
- if (EllipseAngle > 1.0f) {
- m_swingCorrection = EllipseAngle - 1.0f;
- m_solveSwingLimit = true;
-
- // Calculate necessary axis & factors
- m_swingAxis = b2Axis1.cross(b1Axis2 * b2Axis1.dot(b1Axis2) + b1Axis3 * b2Axis1.dot(b1Axis3));
- m_swingAxis.normalize();
-
- real_t swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f;
- m_swingAxis *= swingAxisSign;
-
- m_kSwing = real_t(1.) / (A->compute_angular_impulse_denominator(m_swingAxis) +
- B->compute_angular_impulse_denominator(m_swingAxis));
- }
-
- // Twist limits
- if (m_twistSpan >= real_t(0.)) {
- Vector3 b2Axis22 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(1));
- Quat rotationArc = Quat(b2Axis1, b1Axis1);
- Vector3 TwistRef = rotationArc.xform(b2Axis22);
- real_t twist = atan2fast(TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2));
-
- real_t lockedFreeFactor = (m_twistSpan > real_t(0.05f)) ? m_limitSoftness : real_t(0.);
- if (twist <= -m_twistSpan * lockedFreeFactor) {
- m_twistCorrection = -(twist + m_twistSpan);
- m_solveTwistLimit = true;
-
- m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
- m_twistAxis.normalize();
- m_twistAxis *= -1.0f;
-
- m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) +
- B->compute_angular_impulse_denominator(m_twistAxis));
-
- } else if (twist > m_twistSpan * lockedFreeFactor) {
- m_twistCorrection = (twist - m_twistSpan);
- m_solveTwistLimit = true;
-
- m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
- m_twistAxis.normalize();
-
- m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) +
- B->compute_angular_impulse_denominator(m_twistAxis));
- }
- }
-
- return true;
-}
-
-void ConeTwistJointSW::solve(real_t p_timestep) {
-
- Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
- Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
-
- real_t tau = real_t(0.3);
-
- //linear part
- if (!m_angularOnly) {
- Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
- Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
-
- Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
- Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
- Vector3 vel = vel1 - vel2;
-
- for (int i = 0; i < 3; i++) {
- const Vector3 &normal = m_jac[i].m_linearJointAxis;
- real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
-
- real_t rel_vel;
- rel_vel = normal.dot(vel);
- //positional error (zeroth order error)
- real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
- real_t impulse = depth * tau / p_timestep * jacDiagABInv - rel_vel * jacDiagABInv;
- m_appliedImpulse += impulse;
- Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
- B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
- }
- }
-
- {
- ///solve angular part
- const Vector3 &angVelA = A->get_angular_velocity();
- const Vector3 &angVelB = B->get_angular_velocity();
-
- // solve swing limit
- if (m_solveSwingLimit) {
- real_t amplitude = ((angVelB - angVelA).dot(m_swingAxis) * m_relaxationFactor * m_relaxationFactor + m_swingCorrection * (real_t(1.) / p_timestep) * m_biasFactor);
- real_t impulseMag = amplitude * m_kSwing;
-
- // Clamp the accumulated impulse
- real_t temp = m_accSwingLimitImpulse;
- m_accSwingLimitImpulse = MAX(m_accSwingLimitImpulse + impulseMag, real_t(0.0));
- impulseMag = m_accSwingLimitImpulse - temp;
-
- Vector3 impulse = m_swingAxis * impulseMag;
-
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
- }
-
- // solve twist limit
- if (m_solveTwistLimit) {
- real_t amplitude = ((angVelB - angVelA).dot(m_twistAxis) * m_relaxationFactor * m_relaxationFactor + m_twistCorrection * (real_t(1.) / p_timestep) * m_biasFactor);
- real_t impulseMag = amplitude * m_kTwist;
-
- // Clamp the accumulated impulse
- real_t temp = m_accTwistLimitImpulse;
- m_accTwistLimitImpulse = MAX(m_accTwistLimitImpulse + impulseMag, real_t(0.0));
- impulseMag = m_accTwistLimitImpulse - temp;
-
- Vector3 impulse = m_twistAxis * impulseMag;
-
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
- }
- }
-}
-
-void ConeTwistJointSW::set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value) {
-
- switch (p_param) {
- case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: {
-
- m_swingSpan1 = p_value;
- m_swingSpan2 = p_value;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: {
-
- m_twistSpan = p_value;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_BIAS: {
-
- m_biasFactor = p_value;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: {
-
- m_limitSoftness = p_value;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: {
-
- m_relaxationFactor = p_value;
- } break;
- case PhysicsServer::CONE_TWIST_MAX: break; // Can't happen, but silences warning
- }
-}
-
-real_t ConeTwistJointSW::get_param(PhysicsServer::ConeTwistJointParam p_param) const {
-
- switch (p_param) {
- case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN: {
-
- return m_swingSpan1;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN: {
-
- return m_twistSpan;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_BIAS: {
-
- return m_biasFactor;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS: {
-
- return m_limitSoftness;
- } break;
- case PhysicsServer::CONE_TWIST_JOINT_RELAXATION: {
-
- return m_relaxationFactor;
- } break;
- case PhysicsServer::CONE_TWIST_MAX: break; // Can't happen, but silences warning
- }
-
- return 0;
-}
diff --git a/servers/physics/joints/cone_twist_joint_sw.h b/servers/physics/joints/cone_twist_joint_sw.h
deleted file mode 100644
index 857aaa0d86..0000000000
--- a/servers/physics/joints/cone_twist_joint_sw.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*************************************************************************/
-/* cone_twist_joint_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-/*
-Bullet Continuous Collision Detection and Physics Library
-ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
-
-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.
-
-Written by: Marcus Hennix
-*/
-
-#ifndef CONE_TWIST_JOINT_SW_H
-#define CONE_TWIST_JOINT_SW_H
-
-#include "servers/physics/joints/jacobian_entry_sw.h"
-#include "servers/physics/joints_sw.h"
-
-///ConeTwistJointSW can be used to simulate ragdoll joints (upper arm, leg etc)
-class ConeTwistJointSW : public JointSW {
-#ifdef IN_PARALLELL_SOLVER
-public:
-#endif
-
- union {
- struct {
- BodySW *A;
- BodySW *B;
- };
-
- BodySW *_arr[2];
- };
-
- JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
-
- real_t m_appliedImpulse;
- Transform m_rbAFrame;
- Transform m_rbBFrame;
-
- real_t m_limitSoftness;
- real_t m_biasFactor;
- real_t m_relaxationFactor;
-
- real_t m_swingSpan1;
- real_t m_swingSpan2;
- real_t m_twistSpan;
-
- Vector3 m_swingAxis;
- Vector3 m_twistAxis;
-
- real_t m_kSwing;
- real_t m_kTwist;
-
- real_t m_twistLimitSign;
- real_t m_swingCorrection;
- real_t m_twistCorrection;
-
- real_t m_accSwingLimitImpulse;
- real_t m_accTwistLimitImpulse;
-
- bool m_angularOnly;
- bool m_solveTwistLimit;
- bool m_solveSwingLimit;
-
-public:
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; }
-
- virtual bool setup(real_t p_timestep);
- virtual void solve(real_t p_timestep);
-
- ConeTwistJointSW(BodySW *rbA, BodySW *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
-
- void setAngularOnly(bool angularOnly) {
- m_angularOnly = angularOnly;
- }
-
- void setLimit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f) {
- m_swingSpan1 = _swingSpan1;
- m_swingSpan2 = _swingSpan2;
- m_twistSpan = _twistSpan;
-
- m_limitSoftness = _softness;
- m_biasFactor = _biasFactor;
- m_relaxationFactor = _relaxationFactor;
- }
-
- inline int getSolveTwistLimit() {
- return m_solveTwistLimit;
- }
-
- inline int getSolveSwingLimit() {
- return m_solveTwistLimit;
- }
-
- inline real_t getTwistLimitSign() {
- return m_twistLimitSign;
- }
-
- void set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::ConeTwistJointParam p_param) const;
-};
-
-#endif // CONE_TWIST_JOINT_SW_H
diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp
deleted file mode 100644
index 8f0ccab7f7..0000000000
--- a/servers/physics/joints/generic_6dof_joint_sw.cpp
+++ /dev/null
@@ -1,686 +0,0 @@
-/*************************************************************************/
-/* generic_6dof_joint_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-/*
-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.
-*/
-
-/*
-2007-09-09
-Generic6DOFJointSW Refactored by Francisco Le?n
-email: projectileman@yahoo.com
-http://gimpact.sf.net
-*/
-
-#include "generic_6dof_joint_sw.h"
-
-#define GENERIC_D6_DISABLE_WARMSTARTING 1
-
-//////////////////////////// G6DOFRotationalLimitMotorSW ////////////////////////////////////
-
-int G6DOFRotationalLimitMotorSW::testLimitValue(real_t test_value) {
- if (m_loLimit > m_hiLimit) {
- m_currentLimit = 0; //Free from violation
- return 0;
- }
-
- if (test_value < m_loLimit) {
- m_currentLimit = 1; //low limit violation
- m_currentLimitError = test_value - m_loLimit;
- return 1;
- } else if (test_value > m_hiLimit) {
- m_currentLimit = 2; //High limit violation
- m_currentLimitError = test_value - m_hiLimit;
- return 2;
- };
-
- m_currentLimit = 0; //Free from violation
- return 0;
-}
-
-real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
- real_t timeStep, Vector3 &axis, real_t jacDiagABInv,
- BodySW *body0, BodySW *body1) {
- if (!needApplyTorques()) return 0.0f;
-
- real_t target_velocity = m_targetVelocity;
- real_t maxMotorForce = m_maxMotorForce;
-
- //current error correction
- if (m_currentLimit != 0) {
- target_velocity = -m_ERP * m_currentLimitError / (timeStep);
- maxMotorForce = m_maxLimitForce;
- }
-
- maxMotorForce *= timeStep;
-
- // current velocity difference
- Vector3 vel_diff = body0->get_angular_velocity();
- if (body1) {
- vel_diff -= body1->get_angular_velocity();
- }
-
- real_t rel_vel = axis.dot(vel_diff);
-
- // correction velocity
- real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
-
- if (Math::is_zero_approx(motor_relvel)) {
- return 0.0f; //no need for applying force
- }
-
- // correction impulse
- real_t unclippedMotorImpulse = (1 + m_bounce) * motor_relvel * jacDiagABInv;
-
- // clip correction impulse
- real_t clippedMotorImpulse;
-
- ///@todo: should clip against accumulated impulse
- if (unclippedMotorImpulse > 0.0f) {
- clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce ? maxMotorForce : unclippedMotorImpulse;
- } else {
- clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce : unclippedMotorImpulse;
- }
-
- // sort with accumulated impulses
- real_t lo = real_t(-1e30);
- real_t hi = real_t(1e30);
-
- real_t oldaccumImpulse = m_accumulatedImpulse;
- real_t sum = oldaccumImpulse + clippedMotorImpulse;
- m_accumulatedImpulse = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum;
-
- clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
-
- Vector3 motorImp = clippedMotorImpulse * axis;
-
- body0->apply_torque_impulse(motorImp);
- if (body1) body1->apply_torque_impulse(-motorImp);
-
- return clippedMotorImpulse;
-}
-
-//////////////////////////// End G6DOFRotationalLimitMotorSW ////////////////////////////////////
-
-//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
-real_t G6DOFTranslationalLimitMotorSW::solveLinearAxis(
- real_t timeStep,
- real_t jacDiagABInv,
- BodySW *body1, const Vector3 &pointInA,
- BodySW *body2, const Vector3 &pointInB,
- int limit_index,
- const Vector3 &axis_normal_on_a,
- const Vector3 &anchorPos) {
-
- ///find relative velocity
- // Vector3 rel_pos1 = pointInA - body1->get_transform().origin;
- // Vector3 rel_pos2 = pointInB - body2->get_transform().origin;
- Vector3 rel_pos1 = anchorPos - body1->get_transform().origin;
- Vector3 rel_pos2 = anchorPos - body2->get_transform().origin;
-
- Vector3 vel1 = body1->get_velocity_in_local_point(rel_pos1);
- Vector3 vel2 = body2->get_velocity_in_local_point(rel_pos2);
- Vector3 vel = vel1 - vel2;
-
- real_t rel_vel = axis_normal_on_a.dot(vel);
-
- /// apply displacement correction
-
- //positional error (zeroth order error)
- real_t depth = -(pointInA - pointInB).dot(axis_normal_on_a);
- real_t lo = real_t(-1e30);
- real_t hi = real_t(1e30);
-
- real_t minLimit = m_lowerLimit[limit_index];
- real_t maxLimit = m_upperLimit[limit_index];
-
- //handle the limits
- if (minLimit < maxLimit) {
- {
- if (depth > maxLimit) {
- depth -= maxLimit;
- lo = real_t(0.);
-
- } else {
- if (depth < minLimit) {
- depth -= minLimit;
- hi = real_t(0.);
- } else {
- return 0.0f;
- }
- }
- }
- }
-
- real_t normalImpulse = m_limitSoftness[limit_index] * (m_restitution[limit_index] * depth / timeStep - m_damping[limit_index] * rel_vel) * jacDiagABInv;
-
- real_t oldNormalImpulse = m_accumulatedImpulse[limit_index];
- real_t sum = oldNormalImpulse + normalImpulse;
- m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum;
- normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
-
- Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
- body1->apply_impulse(rel_pos1, impulse_vector);
- body2->apply_impulse(rel_pos2, -impulse_vector);
- return normalImpulse;
-}
-
-//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
-
-Generic6DOFJointSW::Generic6DOFJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) :
- JointSW(_arr, 2),
- m_frameInA(frameInA),
- m_frameInB(frameInB),
- m_useLinearReferenceFrameA(useLinearReferenceFrameA) {
- A = rbA;
- B = rbB;
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
-}
-
-void Generic6DOFJointSW::calculateAngleInfo() {
- Basis relative_frame = m_calculatedTransformB.basis.inverse() * m_calculatedTransformA.basis;
-
- m_calculatedAxisAngleDiff = relative_frame.get_euler_xyz();
-
- // in euler angle mode we do not actually constrain the angular velocity
- // along the axes axis[0] and axis[2] (although we do use axis[1]) :
- //
- // to get constrain w2-w1 along ...not
- // ------ --------------------- ------
- // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
- // d(angle[1])/dt = 0 ax[1]
- // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
- //
- // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
- // to prove the result for angle[0], write the expression for angle[0] from
- // GetInfo1 then take the derivative. to prove this for angle[2] it is
- // easier to take the euler rate expression for d(angle[2])/dt with respect
- // to the components of w and set that to 0.
-
- Vector3 axis0 = m_calculatedTransformB.basis.get_axis(0);
- Vector3 axis2 = m_calculatedTransformA.basis.get_axis(2);
-
- m_calculatedAxis[1] = axis2.cross(axis0);
- m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
- m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
-
- /*
- if(m_debugDrawer)
- {
-
- char buff[300];
- sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
- m_calculatedAxisAngleDiff[0],
- m_calculatedAxisAngleDiff[1],
- m_calculatedAxisAngleDiff[2]);
- m_debugDrawer->reportErrorWarning(buff);
- }
- */
-}
-
-void Generic6DOFJointSW::calculateTransforms() {
- m_calculatedTransformA = A->get_transform() * m_frameInA;
- m_calculatedTransformB = B->get_transform() * m_frameInB;
-
- calculateAngleInfo();
-}
-
-void Generic6DOFJointSW::buildLinearJacobian(
- JacobianEntrySW &jacLinear, const Vector3 &normalWorld,
- const Vector3 &pivotAInW, const Vector3 &pivotBInW) {
- memnew_placement(&jacLinear, JacobianEntrySW(
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
- pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
- normalWorld,
- A->get_inv_inertia(),
- A->get_inv_mass(),
- B->get_inv_inertia(),
- B->get_inv_mass()));
-}
-
-void Generic6DOFJointSW::buildAngularJacobian(
- JacobianEntrySW &jacAngular, const Vector3 &jointAxisW) {
- memnew_placement(&jacAngular, JacobianEntrySW(jointAxisW,
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- A->get_inv_inertia(),
- B->get_inv_inertia()));
-}
-
-bool Generic6DOFJointSW::testAngularLimitMotor(int axis_index) {
- real_t angle = m_calculatedAxisAngleDiff[axis_index];
-
- //test limits
- m_angularLimits[axis_index].testLimitValue(angle);
- return m_angularLimits[axis_index].needApplyTorques();
-}
-
-bool Generic6DOFJointSW::setup(real_t p_timestep) {
-
- // Clear accumulated impulses for the next simulation step
- m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.));
- int i;
- for (i = 0; i < 3; i++) {
- m_angularLimits[i].m_accumulatedImpulse = real_t(0.);
- }
- //calculates transform
- calculateTransforms();
-
- // const Vector3& pivotAInW = m_calculatedTransformA.origin;
- // const Vector3& pivotBInW = m_calculatedTransformB.origin;
- calcAnchorPos();
- Vector3 pivotAInW = m_AnchorPos;
- Vector3 pivotBInW = m_AnchorPos;
-
- // not used here
- // Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
- // Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
-
- Vector3 normalWorld;
- //linear part
- for (i = 0; i < 3; i++) {
- if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
- if (m_useLinearReferenceFrameA)
- normalWorld = m_calculatedTransformA.basis.get_axis(i);
- else
- normalWorld = m_calculatedTransformB.basis.get_axis(i);
-
- buildLinearJacobian(
- m_jacLinear[i], normalWorld,
- pivotAInW, pivotBInW);
- }
- }
-
- // angular part
- for (i = 0; i < 3; i++) {
- //calculates error angle
- if (m_angularLimits[i].m_enableLimit && testAngularLimitMotor(i)) {
- normalWorld = this->getAxis(i);
- // Create angular atom
- buildAngularJacobian(m_jacAng[i], normalWorld);
- }
- }
-
- return true;
-}
-
-void Generic6DOFJointSW::solve(real_t p_timestep) {
- m_timeStep = p_timestep;
-
- //calculateTransforms();
-
- int i;
-
- // linear
-
- Vector3 pointInA = m_calculatedTransformA.origin;
- Vector3 pointInB = m_calculatedTransformB.origin;
-
- real_t jacDiagABInv;
- Vector3 linear_axis;
- for (i = 0; i < 3; i++) {
- if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
- jacDiagABInv = real_t(1.) / m_jacLinear[i].getDiagonal();
-
- if (m_useLinearReferenceFrameA)
- linear_axis = m_calculatedTransformA.basis.get_axis(i);
- else
- linear_axis = m_calculatedTransformB.basis.get_axis(i);
-
- m_linearLimits.solveLinearAxis(
- m_timeStep,
- jacDiagABInv,
- A, pointInA,
- B, pointInB,
- i, linear_axis, m_AnchorPos);
- }
- }
-
- // angular
- Vector3 angular_axis;
- real_t angularJacDiagABInv;
- for (i = 0; i < 3; i++) {
- if (m_angularLimits[i].m_enableLimit && m_angularLimits[i].needApplyTorques()) {
-
- // get axis
- angular_axis = getAxis(i);
-
- angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
-
- m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B);
- }
- }
-}
-
-void Generic6DOFJointSW::updateRHS(real_t timeStep) {
- (void)timeStep;
-}
-
-Vector3 Generic6DOFJointSW::getAxis(int axis_index) const {
- return m_calculatedAxis[axis_index];
-}
-
-real_t Generic6DOFJointSW::getAngle(int axis_index) const {
- return m_calculatedAxisAngleDiff[axis_index];
-}
-
-void Generic6DOFJointSW::calcAnchorPos(void) {
- real_t imA = A->get_inv_mass();
- real_t imB = B->get_inv_mass();
- real_t weight;
- if (imB == real_t(0.0)) {
- weight = real_t(1.0);
- } else {
- weight = imA / (imA + imB);
- }
- const Vector3 &pA = m_calculatedTransformA.origin;
- const Vector3 &pB = m_calculatedTransformB.origin;
- m_AnchorPos = pA * weight + pB * (real_t(1.0) - weight);
-} // Generic6DOFJointSW::calcAnchorPos()
-
-void Generic6DOFJointSW::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value) {
-
- ERR_FAIL_INDEX(p_axis, 3);
- switch (p_param) {
- case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
-
- m_linearLimits.m_lowerLimit[p_axis] = p_value;
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
-
- m_linearLimits.m_upperLimit[p_axis] = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
-
- m_linearLimits.m_limitSoftness[p_axis] = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
-
- m_linearLimits.m_restitution[p_axis] = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
-
- m_linearLimits.m_damping[p_axis] = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
-
- m_angularLimits[p_axis].m_loLimit = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
-
- m_angularLimits[p_axis].m_hiLimit = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
-
- m_angularLimits[p_axis].m_limitSoftness = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
-
- m_angularLimits[p_axis].m_damping = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
-
- m_angularLimits[p_axis].m_bounce = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
-
- m_angularLimits[p_axis].m_maxLimitForce = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
-
- m_angularLimits[p_axis].m_ERP = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
-
- m_angularLimits[p_axis].m_targetVelocity = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
-
- m_angularLimits[p_axis].m_maxLimitForce = p_value;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning
- }
-}
-
-real_t Generic6DOFJointSW::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const {
- ERR_FAIL_INDEX_V(p_axis, 3, 0);
- switch (p_param) {
- case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
-
- return m_linearLimits.m_lowerLimit[p_axis];
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
-
- return m_linearLimits.m_upperLimit[p_axis];
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
-
- return m_linearLimits.m_limitSoftness[p_axis];
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
-
- return m_linearLimits.m_restitution[p_axis];
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
-
- return m_linearLimits.m_damping[p_axis];
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
-
- return m_angularLimits[p_axis].m_loLimit;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
-
- return m_angularLimits[p_axis].m_hiLimit;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
-
- return m_angularLimits[p_axis].m_limitSoftness;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
-
- return m_angularLimits[p_axis].m_damping;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
-
- return m_angularLimits[p_axis].m_bounce;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
-
- return m_angularLimits[p_axis].m_maxLimitForce;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
-
- return m_angularLimits[p_axis].m_ERP;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
-
- return m_angularLimits[p_axis].m_targetVelocity;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
-
- return m_angularLimits[p_axis].m_maxMotorForce;
-
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning
- }
- return 0;
-}
-
-void Generic6DOFJointSW::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value) {
-
- ERR_FAIL_INDEX(p_axis, 3);
-
- switch (p_flag) {
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
-
- m_linearLimits.enable_limit[p_axis] = p_value;
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
-
- m_angularLimits[p_axis].m_enableLimit = p_value;
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
-
- m_angularLimits[p_axis].m_enableMotor = p_value;
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
- }
-}
-bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const {
-
- ERR_FAIL_INDEX_V(p_axis, 3, 0);
- switch (p_flag) {
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
-
- return m_linearLimits.enable_limit[p_axis];
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
-
- return m_angularLimits[p_axis].m_enableLimit;
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
-
- return m_angularLimits[p_axis].m_enableMotor;
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
- // Not implemented in GodotPhysics backend
- } break;
- case PhysicsServer::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
- }
-
- return 0;
-}
diff --git a/servers/physics/joints/generic_6dof_joint_sw.h b/servers/physics/joints/generic_6dof_joint_sw.h
deleted file mode 100644
index 07626ffa97..0000000000
--- a/servers/physics/joints/generic_6dof_joint_sw.h
+++ /dev/null
@@ -1,401 +0,0 @@
-/*************************************************************************/
-/* generic_6dof_joint_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-#ifndef GENERIC_6DOF_JOINT_SW_H
-#define GENERIC_6DOF_JOINT_SW_H
-
-#include "servers/physics/joints/jacobian_entry_sw.h"
-#include "servers/physics/joints_sw.h"
-
-/*
-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.
-*/
-
-/*
-2007-09-09
-Generic6DOFJointSW Refactored by Francisco Le?n
-email: projectileman@yahoo.com
-http://gimpact.sf.net
-*/
-
-//! Rotation Limit structure for generic joints
-class G6DOFRotationalLimitMotorSW {
-public:
- //! limit_parameters
- //!@{
- real_t m_loLimit; //!< joint limit
- real_t m_hiLimit; //!< joint limit
- real_t m_targetVelocity; //!< target motor velocity
- real_t m_maxMotorForce; //!< max force on motor
- real_t m_maxLimitForce; //!< max force on limit
- real_t m_damping; //!< Damping.
- real_t m_limitSoftness; //! Relaxation factor
- real_t m_ERP; //!< Error tolerance factor when joint is at limit
- real_t m_bounce; //!< restitution factor
- bool m_enableMotor;
- bool m_enableLimit;
-
- //!@}
-
- //! temp_variables
- //!@{
- real_t m_currentLimitError; //! How much is violated this limit
- int m_currentLimit; //!< 0=free, 1=at lo limit, 2=at hi limit
- real_t m_accumulatedImpulse;
- //!@}
-
- G6DOFRotationalLimitMotorSW() {
- m_accumulatedImpulse = 0.f;
- m_targetVelocity = 0;
- m_maxMotorForce = 0.1f;
- m_maxLimitForce = 300.0f;
- m_loLimit = -1e30;
- m_hiLimit = 1e30;
- m_ERP = 0.5f;
- m_bounce = 0.0f;
- m_damping = 1.0f;
- m_limitSoftness = 0.5f;
- m_currentLimit = 0;
- m_currentLimitError = 0;
- m_enableMotor = false;
- m_enableLimit = false;
- }
-
- G6DOFRotationalLimitMotorSW(const G6DOFRotationalLimitMotorSW &limot) {
- m_targetVelocity = limot.m_targetVelocity;
- m_maxMotorForce = limot.m_maxMotorForce;
- m_limitSoftness = limot.m_limitSoftness;
- m_loLimit = limot.m_loLimit;
- m_hiLimit = limot.m_hiLimit;
- m_ERP = limot.m_ERP;
- m_bounce = limot.m_bounce;
- m_currentLimit = limot.m_currentLimit;
- m_currentLimitError = limot.m_currentLimitError;
- m_enableMotor = limot.m_enableMotor;
- }
-
- //! Is limited
- bool isLimited() {
- return (m_loLimit < m_hiLimit);
- }
-
- //! Need apply correction
- bool needApplyTorques() {
- return (m_enableMotor || m_currentLimit != 0);
- }
-
- //! calculates error
- /*!
- calculates m_currentLimit and m_currentLimitError.
- */
- int testLimitValue(real_t test_value);
-
- //! apply the correction impulses for two bodies
- real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, BodySW *body0, BodySW *body1);
-};
-
-class G6DOFTranslationalLimitMotorSW {
-public:
- Vector3 m_lowerLimit; //!< the constraint lower limits
- Vector3 m_upperLimit; //!< the constraint upper limits
- Vector3 m_accumulatedImpulse;
- //! Linear_Limit_parameters
- //!@{
- Vector3 m_limitSoftness; //!< Softness for linear limit
- Vector3 m_damping; //!< Damping for linear limit
- Vector3 m_restitution; //! Bounce parameter for linear limit
- //!@}
- bool enable_limit[3];
-
- G6DOFTranslationalLimitMotorSW() {
- m_lowerLimit = Vector3(0.f, 0.f, 0.f);
- m_upperLimit = Vector3(0.f, 0.f, 0.f);
- m_accumulatedImpulse = Vector3(0.f, 0.f, 0.f);
-
- m_limitSoftness = Vector3(1, 1, 1) * 0.7f;
- m_damping = Vector3(1, 1, 1) * real_t(1.0f);
- m_restitution = Vector3(1, 1, 1) * real_t(0.5f);
-
- enable_limit[0] = true;
- enable_limit[1] = true;
- enable_limit[2] = true;
- }
-
- G6DOFTranslationalLimitMotorSW(const G6DOFTranslationalLimitMotorSW &other) {
- m_lowerLimit = other.m_lowerLimit;
- m_upperLimit = other.m_upperLimit;
- m_accumulatedImpulse = other.m_accumulatedImpulse;
-
- m_limitSoftness = other.m_limitSoftness;
- m_damping = other.m_damping;
- m_restitution = other.m_restitution;
- }
-
- //! Test limit
- /*!
- - free means upper < lower,
- - locked means upper == lower
- - limited means upper > lower
- - limitIndex: first 3 are linear, next 3 are angular
- */
- inline bool isLimited(int limitIndex) {
- return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
- }
-
- real_t solveLinearAxis(
- real_t timeStep,
- real_t jacDiagABInv,
- BodySW *body1, const Vector3 &pointInA,
- BodySW *body2, const Vector3 &pointInB,
- int limit_index,
- const Vector3 &axis_normal_on_a,
- const Vector3 &anchorPos);
-};
-
-class Generic6DOFJointSW : public JointSW {
-protected:
- union {
- struct {
- BodySW *A;
- BodySW *B;
- };
-
- BodySW *_arr[2];
- };
-
- //! relative_frames
- //!@{
- Transform m_frameInA; //!< the constraint space w.r.t body A
- Transform m_frameInB; //!< the constraint space w.r.t body B
- //!@}
-
- //! Jacobians
- //!@{
- JacobianEntrySW m_jacLinear[3]; //!< 3 orthogonal linear constraints
- JacobianEntrySW m_jacAng[3]; //!< 3 orthogonal angular constraints
- //!@}
-
- //! Linear_Limit_parameters
- //!@{
- G6DOFTranslationalLimitMotorSW m_linearLimits;
- //!@}
-
- //! hinge_parameters
- //!@{
- G6DOFRotationalLimitMotorSW m_angularLimits[3];
- //!@}
-
-protected:
- //! temporal variables
- //!@{
- real_t m_timeStep;
- Transform m_calculatedTransformA;
- Transform m_calculatedTransformB;
- Vector3 m_calculatedAxisAngleDiff;
- Vector3 m_calculatedAxis[3];
-
- Vector3 m_AnchorPos; // point between pivots of bodies A and B to solve linear axes
-
- bool m_useLinearReferenceFrameA;
-
- //!@}
-
- Generic6DOFJointSW &operator=(Generic6DOFJointSW &other) {
- ERR_PRINT("pito");
- (void)other;
- return *this;
- }
-
- void buildLinearJacobian(
- JacobianEntrySW &jacLinear, const Vector3 &normalWorld,
- const Vector3 &pivotAInW, const Vector3 &pivotBInW);
-
- void buildAngularJacobian(JacobianEntrySW &jacAngular, const Vector3 &jointAxisW);
-
- //! calcs the euler angles between the two bodies.
- void calculateAngleInfo();
-
-public:
- Generic6DOFJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
-
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; }
-
- virtual bool setup(real_t p_timestep);
- virtual void solve(real_t p_timestep);
-
- //! Calcs global transform of the offsets
- /*!
- Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies.
- \sa Generic6DOFJointSW.getCalculatedTransformA , Generic6DOFJointSW.getCalculatedTransformB, Generic6DOFJointSW.calculateAngleInfo
- */
- void calculateTransforms();
-
- //! Gets the global transform of the offset for body A
- /*!
- \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
- */
- const Transform &getCalculatedTransformA() const {
- return m_calculatedTransformA;
- }
-
- //! Gets the global transform of the offset for body B
- /*!
- \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
- */
- const Transform &getCalculatedTransformB() const {
- return m_calculatedTransformB;
- }
-
- const Transform &getFrameOffsetA() const {
- return m_frameInA;
- }
-
- const Transform &getFrameOffsetB() const {
- return m_frameInB;
- }
-
- Transform &getFrameOffsetA() {
- return m_frameInA;
- }
-
- Transform &getFrameOffsetB() {
- return m_frameInB;
- }
-
- //! performs Jacobian calculation, and also calculates angle differences and axis
-
- void updateRHS(real_t timeStep);
-
- //! Get the rotation axis in global coordinates
- /*!
- \pre Generic6DOFJointSW.buildJacobian must be called previously.
- */
- Vector3 getAxis(int axis_index) const;
-
- //! Get the relative Euler angle
- /*!
- \pre Generic6DOFJointSW.buildJacobian must be called previously.
- */
- real_t getAngle(int axis_index) const;
-
- //! Test angular limit.
- /*!
- Calculates angular correction and returns true if limit needs to be corrected.
- \pre Generic6DOFJointSW.buildJacobian must be called previously.
- */
- bool testAngularLimitMotor(int axis_index);
-
- void setLinearLowerLimit(const Vector3 &linearLower) {
- m_linearLimits.m_lowerLimit = linearLower;
- }
-
- void setLinearUpperLimit(const Vector3 &linearUpper) {
- m_linearLimits.m_upperLimit = linearUpper;
- }
-
- void setAngularLowerLimit(const Vector3 &angularLower) {
- m_angularLimits[0].m_loLimit = angularLower.x;
- m_angularLimits[1].m_loLimit = angularLower.y;
- m_angularLimits[2].m_loLimit = angularLower.z;
- }
-
- void setAngularUpperLimit(const Vector3 &angularUpper) {
- m_angularLimits[0].m_hiLimit = angularUpper.x;
- m_angularLimits[1].m_hiLimit = angularUpper.y;
- m_angularLimits[2].m_hiLimit = angularUpper.z;
- }
-
- //! Retrieves the angular limit informacion
- G6DOFRotationalLimitMotorSW *getRotationalLimitMotor(int index) {
- return &m_angularLimits[index];
- }
-
- //! Retrieves the limit informacion
- G6DOFTranslationalLimitMotorSW *getTranslationalLimitMotor() {
- return &m_linearLimits;
- }
-
- //first 3 are linear, next 3 are angular
- void setLimit(int axis, real_t lo, real_t hi) {
- if (axis < 3) {
- m_linearLimits.m_lowerLimit[axis] = lo;
- m_linearLimits.m_upperLimit[axis] = hi;
- } else {
- m_angularLimits[axis - 3].m_loLimit = lo;
- m_angularLimits[axis - 3].m_hiLimit = hi;
- }
- }
-
- //! Test limit
- /*!
- - free means upper < lower,
- - locked means upper == lower
- - limited means upper > lower
- - limitIndex: first 3 are linear, next 3 are angular
- */
- bool isLimited(int limitIndex) {
- if (limitIndex < 3) {
- return m_linearLimits.isLimited(limitIndex);
- }
- return m_angularLimits[limitIndex - 3].isLimited();
- }
-
- const BodySW *getRigidBodyA() const {
- return A;
- }
- const BodySW *getRigidBodyB() const {
- return B;
- }
-
- virtual void calcAnchorPos(void); // overridable
-
- void set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value);
- real_t get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const;
-
- void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value);
- bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const;
-};
-
-#endif // GENERIC_6DOF_JOINT_SW_H
diff --git a/servers/physics/joints/hinge_joint_sw.cpp b/servers/physics/joints/hinge_joint_sw.cpp
deleted file mode 100644
index 1ad3e738ba..0000000000
--- a/servers/physics/joints/hinge_joint_sw.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/*************************************************************************/
-/* hinge_joint_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-/*
-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.
-*/
-
-#include "hinge_joint_sw.h"
-
-static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
-
- if (Math::abs(n.z) > Math_SQRT12) {
- // choose p in y-z plane
- real_t a = n[1] * n[1] + n[2] * n[2];
- real_t k = 1.0 / Math::sqrt(a);
- p = Vector3(0, -n[2] * k, n[1] * k);
- // set q = n x p
- q = Vector3(a * k, -n[0] * p[2], n[0] * p[1]);
- } else {
- // choose p in x-y plane
- real_t a = n.x * n.x + n.y * n.y;
- real_t k = 1.0 / Math::sqrt(a);
- p = Vector3(-n.y * k, n.x * k, 0);
- // set q = n x p
- q = Vector3(-n.z * p.y, n.z * p.x, a * k);
- }
-}
-
-HingeJointSW::HingeJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameA, const Transform &frameB) :
- JointSW(_arr, 2) {
-
- A = rbA;
- B = rbB;
-
- m_rbAFrame = frameA;
- m_rbBFrame = frameB;
- // flip axis
- m_rbBFrame.basis[0][2] *= real_t(-1.);
- m_rbBFrame.basis[1][2] *= real_t(-1.);
- m_rbBFrame.basis[2][2] *= real_t(-1.);
-
- //start with free
- m_lowerLimit = Math_PI;
- m_upperLimit = -Math_PI;
-
- m_useLimit = false;
- m_biasFactor = 0.3f;
- m_relaxationFactor = 1.0f;
- m_limitSoftness = 0.9f;
- m_solveLimit = false;
-
- tau = 0.3;
-
- m_angularOnly = false;
- m_enableAngularMotor = false;
-
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
-}
-
-HingeJointSW::HingeJointSW(BodySW *rbA, BodySW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB,
- const Vector3 &axisInA, const Vector3 &axisInB) :
- JointSW(_arr, 2) {
-
- A = rbA;
- B = rbB;
-
- m_rbAFrame.origin = pivotInA;
-
- // since no frame is given, assume this to be zero angle and just pick rb transform axis
- Vector3 rbAxisA1 = rbA->get_transform().basis.get_axis(0);
-
- Vector3 rbAxisA2;
- real_t projection = axisInA.dot(rbAxisA1);
- if (projection >= 1.0f - CMP_EPSILON) {
- rbAxisA1 = -rbA->get_transform().basis.get_axis(2);
- rbAxisA2 = rbA->get_transform().basis.get_axis(1);
- } else if (projection <= -1.0f + CMP_EPSILON) {
- rbAxisA1 = rbA->get_transform().basis.get_axis(2);
- rbAxisA2 = rbA->get_transform().basis.get_axis(1);
- } else {
- rbAxisA2 = axisInA.cross(rbAxisA1);
- rbAxisA1 = rbAxisA2.cross(axisInA);
- }
-
- m_rbAFrame.basis = Basis(rbAxisA1.x, rbAxisA2.x, axisInA.x,
- rbAxisA1.y, rbAxisA2.y, axisInA.y,
- rbAxisA1.z, rbAxisA2.z, axisInA.z);
-
- Quat rotationArc = Quat(axisInA, axisInB);
- Vector3 rbAxisB1 = rotationArc.xform(rbAxisA1);
- Vector3 rbAxisB2 = axisInB.cross(rbAxisB1);
-
- m_rbBFrame.origin = pivotInB;
- m_rbBFrame.basis = Basis(rbAxisB1.x, rbAxisB2.x, -axisInB.x,
- rbAxisB1.y, rbAxisB2.y, -axisInB.y,
- rbAxisB1.z, rbAxisB2.z, -axisInB.z);
-
- //start with free
- m_lowerLimit = Math_PI;
- m_upperLimit = -Math_PI;
-
- m_useLimit = false;
- m_biasFactor = 0.3f;
- m_relaxationFactor = 1.0f;
- m_limitSoftness = 0.9f;
- m_solveLimit = false;
-
- tau = 0.3;
-
- m_angularOnly = false;
- m_enableAngularMotor = false;
-
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
-}
-
-bool HingeJointSW::setup(real_t p_step) {
-
- m_appliedImpulse = real_t(0.);
-
- if (!m_angularOnly) {
- Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
- Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
- Vector3 relPos = pivotBInW - pivotAInW;
-
- Vector3 normal[3];
- if (Math::is_zero_approx(relPos.length_squared())) {
- normal[0] = Vector3(real_t(1.0), 0, 0);
- } else {
- normal[0] = relPos.normalized();
- }
-
- plane_space(normal[0], normal[1], normal[2]);
-
- for (int i = 0; i < 3; i++) {
- memnew_placement(&m_jac[i], JacobianEntrySW(
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
- pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
- normal[i],
- A->get_inv_inertia(),
- A->get_inv_mass(),
- B->get_inv_inertia(),
- B->get_inv_mass()));
- }
- }
-
- //calculate two perpendicular jointAxis, orthogonal to hingeAxis
- //these two jointAxis require equal angular velocities for both bodies
-
- //this is unused for now, it's a todo
- Vector3 jointAxis0local;
- Vector3 jointAxis1local;
-
- plane_space(m_rbAFrame.basis.get_axis(2), jointAxis0local, jointAxis1local);
-
- Vector3 jointAxis0 = A->get_transform().basis.xform(jointAxis0local);
- Vector3 jointAxis1 = A->get_transform().basis.xform(jointAxis1local);
- Vector3 hingeAxisWorld = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
-
- memnew_placement(&m_jacAng[0], JacobianEntrySW(jointAxis0,
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- A->get_inv_inertia(),
- B->get_inv_inertia()));
-
- memnew_placement(&m_jacAng[1], JacobianEntrySW(jointAxis1,
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- A->get_inv_inertia(),
- B->get_inv_inertia()));
-
- memnew_placement(&m_jacAng[2], JacobianEntrySW(hingeAxisWorld,
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- A->get_inv_inertia(),
- B->get_inv_inertia()));
-
- // Compute limit information
- real_t hingeAngle = get_hinge_angle();
-
- //set bias, sign, clear accumulator
- m_correction = real_t(0.);
- m_limitSign = real_t(0.);
- m_solveLimit = false;
- m_accLimitImpulse = real_t(0.);
-
- //if (m_lowerLimit < m_upperLimit)
- if (m_useLimit && m_lowerLimit <= m_upperLimit) {
- //if (hingeAngle <= m_lowerLimit*m_limitSoftness)
- if (hingeAngle <= m_lowerLimit) {
- m_correction = (m_lowerLimit - hingeAngle);
- m_limitSign = 1.0f;
- m_solveLimit = true;
- }
- //else if (hingeAngle >= m_upperLimit*m_limitSoftness)
- else if (hingeAngle >= m_upperLimit) {
- m_correction = m_upperLimit - hingeAngle;
- m_limitSign = -1.0f;
- m_solveLimit = true;
- }
- }
-
- //Compute K = J*W*J' for hinge axis
- Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
- m_kHinge = 1.0f / (A->compute_angular_impulse_denominator(axisA) +
- B->compute_angular_impulse_denominator(axisA));
-
- return true;
-}
-
-void HingeJointSW::solve(real_t p_step) {
-
- Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
- Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
-
- //real_t tau = real_t(0.3);
-
- //linear part
- if (!m_angularOnly) {
- Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
- Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
-
- Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
- Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
- Vector3 vel = vel1 - vel2;
-
- for (int i = 0; i < 3; i++) {
- const Vector3 &normal = m_jac[i].m_linearJointAxis;
- real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
-
- real_t rel_vel;
- rel_vel = normal.dot(vel);
- //positional error (zeroth order error)
- real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
- real_t impulse = depth * tau / p_step * jacDiagABInv - rel_vel * jacDiagABInv;
- m_appliedImpulse += impulse;
- Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
- B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
- }
- }
-
- {
- ///solve angular part
-
- // get axes in world space
- Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
- Vector3 axisB = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(2));
-
- const Vector3 &angVelA = A->get_angular_velocity();
- const Vector3 &angVelB = B->get_angular_velocity();
-
- Vector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA);
- Vector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB);
-
- Vector3 angAorthog = angVelA - angVelAroundHingeAxisA;
- Vector3 angBorthog = angVelB - angVelAroundHingeAxisB;
- Vector3 velrelOrthog = angAorthog - angBorthog;
- {
- //solve orthogonal angular velocity correction
- real_t relaxation = real_t(1.);
- real_t len = velrelOrthog.length();
- if (len > real_t(0.00001)) {
- Vector3 normal = velrelOrthog.normalized();
- real_t denom = A->compute_angular_impulse_denominator(normal) +
- B->compute_angular_impulse_denominator(normal);
- // scale for mass and relaxation
- velrelOrthog *= (real_t(1.) / denom) * m_relaxationFactor;
- }
-
- //solve angular positional correction
- Vector3 angularError = -axisA.cross(axisB) * (real_t(1.) / p_step);
- real_t len2 = angularError.length();
- if (len2 > real_t(0.00001)) {
- Vector3 normal2 = angularError.normalized();
- real_t denom2 = A->compute_angular_impulse_denominator(normal2) +
- B->compute_angular_impulse_denominator(normal2);
- angularError *= (real_t(1.) / denom2) * relaxation;
- }
-
- A->apply_torque_impulse(-velrelOrthog + angularError);
- B->apply_torque_impulse(velrelOrthog - angularError);
-
- // solve limit
- if (m_solveLimit) {
- real_t amplitude = ((angVelB - angVelA).dot(axisA) * m_relaxationFactor + m_correction * (real_t(1.) / p_step) * m_biasFactor) * m_limitSign;
-
- real_t impulseMag = amplitude * m_kHinge;
-
- // Clamp the accumulated impulse
- real_t temp = m_accLimitImpulse;
- m_accLimitImpulse = MAX(m_accLimitImpulse + impulseMag, real_t(0));
- impulseMag = m_accLimitImpulse - temp;
-
- Vector3 impulse = axisA * impulseMag * m_limitSign;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
- }
- }
-
- //apply motor
- if (m_enableAngularMotor) {
- //todo: add limits too
- Vector3 angularLimit(0, 0, 0);
-
- Vector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB;
- real_t projRelVel = velrel.dot(axisA);
-
- real_t desiredMotorVel = m_motorTargetVelocity;
- real_t motor_relvel = desiredMotorVel - projRelVel;
-
- real_t unclippedMotorImpulse = m_kHinge * motor_relvel;
- //todo: should clip against accumulated impulse
- real_t clippedMotorImpulse = unclippedMotorImpulse > m_maxMotorImpulse ? m_maxMotorImpulse : unclippedMotorImpulse;
- clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse;
- Vector3 motorImp = clippedMotorImpulse * axisA;
-
- A->apply_torque_impulse(motorImp + angularLimit);
- B->apply_torque_impulse(-motorImp - angularLimit);
- }
- }
-}
-/*
-void HingeJointSW::updateRHS(real_t timeStep)
-{
- (void)timeStep;
-
-}
-*/
-
-static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
- real_t coeff_1 = Math_PI / 4.0f;
- real_t coeff_2 = 3.0f * coeff_1;
- real_t abs_y = Math::abs(y);
- real_t angle;
- if (x >= 0.0f) {
- real_t r = (x - abs_y) / (x + abs_y);
- angle = coeff_1 - coeff_1 * r;
- } else {
- real_t r = (x + abs_y) / (abs_y - x);
- angle = coeff_2 - coeff_1 * r;
- }
- return (y < 0.0f) ? -angle : angle;
-}
-
-real_t HingeJointSW::get_hinge_angle() {
- const Vector3 refAxis0 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(0));
- const Vector3 refAxis1 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(1));
- const Vector3 swingAxis = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(1));
-
- return atan2fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
-}
-
-void HingeJointSW::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) {
-
- switch (p_param) {
-
- case PhysicsServer::HINGE_JOINT_BIAS: tau = p_value; break;
- case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: m_upperLimit = p_value; break;
- case PhysicsServer::HINGE_JOINT_LIMIT_LOWER: m_lowerLimit = p_value; break;
- case PhysicsServer::HINGE_JOINT_LIMIT_BIAS: m_biasFactor = p_value; break;
- case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS: m_limitSoftness = p_value; break;
- case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: m_relaxationFactor = p_value; break;
- case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: m_motorTargetVelocity = p_value; break;
- case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: m_maxMotorImpulse = p_value; break;
- case PhysicsServer::HINGE_JOINT_MAX: break; // Can't happen, but silences warning
- }
-}
-
-real_t HingeJointSW::get_param(PhysicsServer::HingeJointParam p_param) const {
-
- switch (p_param) {
-
- case PhysicsServer::HINGE_JOINT_BIAS: return tau;
- case PhysicsServer::HINGE_JOINT_LIMIT_UPPER: return m_upperLimit;
- case PhysicsServer::HINGE_JOINT_LIMIT_LOWER: return m_lowerLimit;
- case PhysicsServer::HINGE_JOINT_LIMIT_BIAS: return m_biasFactor;
- case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS: return m_limitSoftness;
- case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION: return m_relaxationFactor;
- case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY: return m_motorTargetVelocity;
- case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE: return m_maxMotorImpulse;
- case PhysicsServer::HINGE_JOINT_MAX: break; // Can't happen, but silences warning
- }
-
- return 0;
-}
-
-void HingeJointSW::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value) {
-
- switch (p_flag) {
- case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: m_useLimit = p_value; break;
- case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: m_enableAngularMotor = p_value; break;
- case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
- }
-}
-bool HingeJointSW::get_flag(PhysicsServer::HingeJointFlag p_flag) const {
-
- switch (p_flag) {
- case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT: return m_useLimit;
- case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR: return m_enableAngularMotor;
- case PhysicsServer::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
- }
-
- return false;
-}
diff --git a/servers/physics/joints/hinge_joint_sw.h b/servers/physics/joints/hinge_joint_sw.h
deleted file mode 100644
index 1c160cfc09..0000000000
--- a/servers/physics/joints/hinge_joint_sw.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*************************************************************************/
-/* hinge_joint_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-#ifndef HINGE_JOINT_SW_H
-#define HINGE_JOINT_SW_H
-
-#include "servers/physics/joints/jacobian_entry_sw.h"
-#include "servers/physics/joints_sw.h"
-
-/*
-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.
-*/
-
-class HingeJointSW : public JointSW {
-
- union {
- struct {
- BodySW *A;
- BodySW *B;
- };
-
- BodySW *_arr[2];
- };
-
- JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
- JacobianEntrySW m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor
-
- Transform m_rbAFrame; // constraint axii. Assumes z is hinge axis.
- Transform m_rbBFrame;
-
- real_t m_motorTargetVelocity;
- real_t m_maxMotorImpulse;
-
- real_t m_limitSoftness;
- real_t m_biasFactor;
- real_t m_relaxationFactor;
-
- real_t m_lowerLimit;
- real_t m_upperLimit;
-
- real_t m_kHinge;
-
- real_t m_limitSign;
- real_t m_correction;
-
- real_t m_accLimitImpulse;
-
- real_t tau;
-
- bool m_useLimit;
- bool m_angularOnly;
- bool m_enableAngularMotor;
- bool m_solveLimit;
-
- real_t m_appliedImpulse;
-
-public:
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_HINGE; }
-
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
-
- real_t get_hinge_angle();
-
- void set_param(PhysicsServer::HingeJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::HingeJointParam p_param) const;
-
- void set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value);
- bool get_flag(PhysicsServer::HingeJointFlag p_flag) const;
-
- HingeJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameA, const Transform &frameB);
- HingeJointSW(BodySW *rbA, BodySW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
-};
-
-#endif // HINGE_JOINT_SW_H
diff --git a/servers/physics/joints/jacobian_entry_sw.h b/servers/physics/joints/jacobian_entry_sw.h
deleted file mode 100644
index a17175e6de..0000000000
--- a/servers/physics/joints/jacobian_entry_sw.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*************************************************************************/
-/* jacobian_entry_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-#ifndef JACOBIAN_ENTRY_SW_H
-#define JACOBIAN_ENTRY_SW_H
-
-/*
-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.
-*/
-
-#include "core/math/transform.h"
-
-class JacobianEntrySW {
-public:
- JacobianEntrySW(){};
- //constraint between two different rigidbodies
- JacobianEntrySW(
- const Basis &world2A,
- const Basis &world2B,
- const Vector3 &rel_pos1, const Vector3 &rel_pos2,
- const Vector3 &jointAxis,
- const Vector3 &inertiaInvA,
- const real_t massInvA,
- const Vector3 &inertiaInvB,
- const real_t massInvB) :
- m_linearJointAxis(jointAxis) {
- m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
- m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
- m_0MinvJt = inertiaInvA * m_aJ;
- m_1MinvJt = inertiaInvB * m_bJ;
- m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
-
- ERR_FAIL_COND(m_Adiag <= real_t(0.0));
- }
-
- //angular constraint between two different rigidbodies
- JacobianEntrySW(const Vector3 &jointAxis,
- const Basis &world2A,
- const Basis &world2B,
- const Vector3 &inertiaInvA,
- const Vector3 &inertiaInvB) :
- m_linearJointAxis(Vector3(real_t(0.), real_t(0.), real_t(0.))) {
- m_aJ = world2A.xform(jointAxis);
- m_bJ = world2B.xform(-jointAxis);
- m_0MinvJt = inertiaInvA * m_aJ;
- m_1MinvJt = inertiaInvB * m_bJ;
- m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ);
-
- ERR_FAIL_COND(m_Adiag <= real_t(0.0));
- }
-
- //angular constraint between two different rigidbodies
- JacobianEntrySW(const Vector3 &axisInA,
- const Vector3 &axisInB,
- const Vector3 &inertiaInvA,
- const Vector3 &inertiaInvB) :
- m_linearJointAxis(Vector3(real_t(0.), real_t(0.), real_t(0.))),
- m_aJ(axisInA),
- m_bJ(-axisInB) {
- m_0MinvJt = inertiaInvA * m_aJ;
- m_1MinvJt = inertiaInvB * m_bJ;
- m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ);
-
- ERR_FAIL_COND(m_Adiag <= real_t(0.0));
- }
-
- //constraint on one rigidbody
- JacobianEntrySW(
- const Basis &world2A,
- const Vector3 &rel_pos1, const Vector3 &rel_pos2,
- const Vector3 &jointAxis,
- const Vector3 &inertiaInvA,
- const real_t massInvA) :
- m_linearJointAxis(jointAxis) {
- m_aJ = world2A.xform(rel_pos1.cross(jointAxis));
- m_bJ = world2A.xform(rel_pos2.cross(-jointAxis));
- m_0MinvJt = inertiaInvA * m_aJ;
- m_1MinvJt = Vector3(real_t(0.), real_t(0.), real_t(0.));
- m_Adiag = massInvA + m_0MinvJt.dot(m_aJ);
-
- ERR_FAIL_COND(m_Adiag <= real_t(0.0));
- }
-
- real_t getDiagonal() const { return m_Adiag; }
-
- // for two constraints on the same rigidbody (for example vehicle friction)
- real_t getNonDiagonal(const JacobianEntrySW &jacB, const real_t massInvA) const {
- const JacobianEntrySW &jacA = *this;
- real_t lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis);
- real_t ang = jacA.m_0MinvJt.dot(jacB.m_aJ);
- return lin + ang;
- }
-
- // for two constraints on sharing two same rigidbodies (for example two contact points between two rigidbodies)
- real_t getNonDiagonal(const JacobianEntrySW &jacB, const real_t massInvA, const real_t massInvB) const {
- const JacobianEntrySW &jacA = *this;
- Vector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis;
- Vector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ;
- Vector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ;
- Vector3 lin0 = massInvA * lin;
- Vector3 lin1 = massInvB * lin;
- Vector3 sum = ang0 + ang1 + lin0 + lin1;
- return sum[0] + sum[1] + sum[2];
- }
-
- real_t getRelativeVelocity(const Vector3 &linvelA, const Vector3 &angvelA, const Vector3 &linvelB, const Vector3 &angvelB) {
- Vector3 linrel = linvelA - linvelB;
- Vector3 angvela = angvelA * m_aJ;
- Vector3 angvelb = angvelB * m_bJ;
- linrel *= m_linearJointAxis;
- angvela += angvelb;
- angvela += linrel;
- real_t rel_vel2 = angvela[0] + angvela[1] + angvela[2];
- return rel_vel2 + CMP_EPSILON;
- }
- //private:
-
- Vector3 m_linearJointAxis;
- Vector3 m_aJ;
- Vector3 m_bJ;
- Vector3 m_0MinvJt;
- Vector3 m_1MinvJt;
- //Optimization: can be stored in the w/last component of one of the vectors
- real_t m_Adiag;
-};
-
-#endif // JACOBIAN_ENTRY_SW_H
diff --git a/servers/physics/joints/pin_joint_sw.cpp b/servers/physics/joints/pin_joint_sw.cpp
deleted file mode 100644
index fe994aa172..0000000000
--- a/servers/physics/joints/pin_joint_sw.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*************************************************************************/
-/* pin_joint_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-/*
-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.
-*/
-
-#include "pin_joint_sw.h"
-
-bool PinJointSW::setup(real_t p_step) {
-
- m_appliedImpulse = real_t(0.);
-
- Vector3 normal(0, 0, 0);
-
- for (int i = 0; i < 3; i++) {
- normal[i] = 1;
- memnew_placement(&m_jac[i], JacobianEntrySW(
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- A->get_transform().xform(m_pivotInA) - A->get_transform().origin - A->get_center_of_mass(),
- B->get_transform().xform(m_pivotInB) - B->get_transform().origin - B->get_center_of_mass(),
- normal,
- A->get_inv_inertia(),
- A->get_inv_mass(),
- B->get_inv_inertia(),
- B->get_inv_mass()));
- normal[i] = 0;
- }
-
- return true;
-}
-
-void PinJointSW::solve(real_t p_step) {
-
- Vector3 pivotAInW = A->get_transform().xform(m_pivotInA);
- Vector3 pivotBInW = B->get_transform().xform(m_pivotInB);
-
- Vector3 normal(0, 0, 0);
-
- //Vector3 angvelA = A->get_transform().origin.getBasis().transpose() * A->getAngularVelocity();
- //Vector3 angvelB = B->get_transform().origin.getBasis().transpose() * B->getAngularVelocity();
-
- for (int i = 0; i < 3; i++) {
- normal[i] = 1;
- real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
-
- Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
- Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
- //this jacobian entry could be re-used for all iterations
-
- Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
- Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
- Vector3 vel = vel1 - vel2;
-
- real_t rel_vel;
- rel_vel = normal.dot(vel);
-
- /*
- //velocity error (first order error)
- real_t rel_vel = m_jac[i].getRelativeVelocity(A->getLinearVelocity(),angvelA,
- B->getLinearVelocity(),angvelB);
- */
-
- //positional error (zeroth order error)
- real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
-
- real_t impulse = depth * m_tau / p_step * jacDiagABInv - m_damping * rel_vel * jacDiagABInv;
-
- real_t impulseClamp = m_impulseClamp;
- if (impulseClamp > 0) {
- if (impulse < -impulseClamp)
- impulse = -impulseClamp;
- if (impulse > impulseClamp)
- impulse = impulseClamp;
- }
-
- m_appliedImpulse += impulse;
- Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
- B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
-
- normal[i] = 0;
- }
-}
-
-void PinJointSW::set_param(PhysicsServer::PinJointParam p_param, real_t p_value) {
-
- switch (p_param) {
- case PhysicsServer::PIN_JOINT_BIAS: m_tau = p_value; break;
- case PhysicsServer::PIN_JOINT_DAMPING: m_damping = p_value; break;
- case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: m_impulseClamp = p_value; break;
- }
-}
-
-real_t PinJointSW::get_param(PhysicsServer::PinJointParam p_param) const {
-
- switch (p_param) {
- case PhysicsServer::PIN_JOINT_BIAS: return m_tau;
- case PhysicsServer::PIN_JOINT_DAMPING: return m_damping;
- case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP: return m_impulseClamp;
- }
-
- return 0;
-}
-
-PinJointSW::PinJointSW(BodySW *p_body_a, const Vector3 &p_pos_a, BodySW *p_body_b, const Vector3 &p_pos_b) :
- JointSW(_arr, 2) {
-
- A = p_body_a;
- B = p_body_b;
- m_pivotInA = p_pos_a;
- m_pivotInB = p_pos_b;
-
- m_tau = 0.3;
- m_damping = 1;
- m_impulseClamp = 0;
- m_appliedImpulse = 0;
-
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
-}
-
-PinJointSW::~PinJointSW() {
-}
diff --git a/servers/physics/joints/pin_joint_sw.h b/servers/physics/joints/pin_joint_sw.h
deleted file mode 100644
index 42884e4940..0000000000
--- a/servers/physics/joints/pin_joint_sw.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************************************/
-/* pin_joint_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-#ifndef PIN_JOINT_SW_H
-#define PIN_JOINT_SW_H
-
-#include "servers/physics/joints/jacobian_entry_sw.h"
-#include "servers/physics/joints_sw.h"
-
-/*
-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.
-*/
-
-class PinJointSW : public JointSW {
-
- union {
- struct {
- BodySW *A;
- BodySW *B;
- };
-
- BodySW *_arr[2];
- };
-
- real_t m_tau; //bias
- real_t m_damping;
- real_t m_impulseClamp;
- real_t m_appliedImpulse;
-
- JacobianEntrySW m_jac[3]; //3 orthogonal linear constraints
-
- Vector3 m_pivotInA;
- Vector3 m_pivotInB;
-
-public:
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_PIN; }
-
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
-
- void set_param(PhysicsServer::PinJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::PinJointParam p_param) const;
-
- void set_pos_a(const Vector3 &p_pos) { m_pivotInA = p_pos; }
- void set_pos_b(const Vector3 &p_pos) { m_pivotInB = p_pos; }
-
- Vector3 get_position_a() { return m_pivotInA; }
- Vector3 get_position_b() { return m_pivotInB; }
-
- PinJointSW(BodySW *p_body_a, const Vector3 &p_pos_a, BodySW *p_body_b, const Vector3 &p_pos_b);
- ~PinJointSW();
-};
-
-#endif // PIN_JOINT_SW_H
diff --git a/servers/physics/joints/slider_joint_sw.cpp b/servers/physics/joints/slider_joint_sw.cpp
deleted file mode 100644
index 9963c7ae89..0000000000
--- a/servers/physics/joints/slider_joint_sw.cpp
+++ /dev/null
@@ -1,443 +0,0 @@
-/*************************************************************************/
-/* slider_joint_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-/*
-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.
-*/
-
-/*
-Added by Roman Ponomarev (rponom@gmail.com)
-April 04, 2008
-
-*/
-
-#include "slider_joint_sw.h"
-
-//-----------------------------------------------------------------------------
-
-static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
- real_t coeff_1 = Math_PI / 4.0f;
- real_t coeff_2 = 3.0f * coeff_1;
- real_t abs_y = Math::abs(y);
- real_t angle;
- if (x >= 0.0f) {
- real_t r = (x - abs_y) / (x + abs_y);
- angle = coeff_1 - coeff_1 * r;
- } else {
- real_t r = (x + abs_y) / (abs_y - x);
- angle = coeff_2 - coeff_1 * r;
- }
- return (y < 0.0f) ? -angle : angle;
-}
-
-void SliderJointSW::initParams() {
- m_lowerLinLimit = real_t(1.0);
- m_upperLinLimit = real_t(-1.0);
- m_lowerAngLimit = real_t(0.);
- m_upperAngLimit = real_t(0.);
- m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
- m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
- m_dampingDirLin = real_t(0.);
- m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
- m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
- m_dampingDirAng = real_t(0.);
- m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
- m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
- m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
- m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
- m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
- m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
- m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
- m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
- m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
- m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
- m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
- m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
-
- m_poweredLinMotor = false;
- m_targetLinMotorVelocity = real_t(0.);
- m_maxLinMotorForce = real_t(0.);
- m_accumulatedLinMotorImpulse = real_t(0.0);
-
- m_poweredAngMotor = false;
- m_targetAngMotorVelocity = real_t(0.);
- m_maxAngMotorForce = real_t(0.);
- m_accumulatedAngMotorImpulse = real_t(0.0);
-
-} // SliderJointSW::initParams()
-
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-
-SliderJointSW::SliderJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB) :
- JointSW(_arr, 2),
- m_frameInA(frameInA),
- m_frameInB(frameInB) {
-
- A = rbA;
- B = rbB;
-
- A->add_constraint(this, 0);
- B->add_constraint(this, 1);
-
- initParams();
-} // SliderJointSW::SliderJointSW()
-
-//-----------------------------------------------------------------------------
-
-bool SliderJointSW::setup(real_t p_step) {
-
- //calculate transforms
- m_calculatedTransformA = A->get_transform() * m_frameInA;
- m_calculatedTransformB = B->get_transform() * m_frameInB;
- m_realPivotAInW = m_calculatedTransformA.origin;
- m_realPivotBInW = m_calculatedTransformB.origin;
- m_sliderAxis = m_calculatedTransformA.basis.get_axis(0); // along X
- m_delta = m_realPivotBInW - m_realPivotAInW;
- m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
- m_relPosA = m_projPivotInW - A->get_transform().origin;
- m_relPosB = m_realPivotBInW - B->get_transform().origin;
- Vector3 normalWorld;
- int i;
- //linear part
- for (i = 0; i < 3; i++) {
- normalWorld = m_calculatedTransformA.basis.get_axis(i);
- memnew_placement(&m_jacLin[i], JacobianEntrySW(
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- m_relPosA - A->get_center_of_mass(),
- m_relPosB - B->get_center_of_mass(),
- normalWorld,
- A->get_inv_inertia(),
- A->get_inv_mass(),
- B->get_inv_inertia(),
- B->get_inv_mass()));
- m_jacLinDiagABInv[i] = real_t(1.) / m_jacLin[i].getDiagonal();
- m_depth[i] = m_delta.dot(normalWorld);
- }
- testLinLimits();
- // angular part
- for (i = 0; i < 3; i++) {
- normalWorld = m_calculatedTransformA.basis.get_axis(i);
- memnew_placement(&m_jacAng[i], JacobianEntrySW(
- normalWorld,
- A->get_principal_inertia_axes().transposed(),
- B->get_principal_inertia_axes().transposed(),
- A->get_inv_inertia(),
- B->get_inv_inertia()));
- }
- testAngLimits();
- Vector3 axisA = m_calculatedTransformA.basis.get_axis(0);
- m_kAngle = real_t(1.0) / (A->compute_angular_impulse_denominator(axisA) + B->compute_angular_impulse_denominator(axisA));
- // clear accumulator for motors
- m_accumulatedLinMotorImpulse = real_t(0.0);
- m_accumulatedAngMotorImpulse = real_t(0.0);
-
- return true;
-} // SliderJointSW::buildJacobianInt()
-
-//-----------------------------------------------------------------------------
-
-void SliderJointSW::solve(real_t p_step) {
-
- int i;
- // linear
- Vector3 velA = A->get_velocity_in_local_point(m_relPosA);
- Vector3 velB = B->get_velocity_in_local_point(m_relPosB);
- Vector3 vel = velA - velB;
- for (i = 0; i < 3; i++) {
- const Vector3 &normal = m_jacLin[i].m_linearJointAxis;
- real_t rel_vel = normal.dot(vel);
- // calculate positional error
- real_t depth = m_depth[i];
- // get parameters
- real_t softness = (i) ? m_softnessOrthoLin : (m_solveLinLim ? m_softnessLimLin : m_softnessDirLin);
- real_t restitution = (i) ? m_restitutionOrthoLin : (m_solveLinLim ? m_restitutionLimLin : m_restitutionDirLin);
- real_t damping = (i) ? m_dampingOrthoLin : (m_solveLinLim ? m_dampingLimLin : m_dampingDirLin);
- // calcutate and apply impulse
- real_t normalImpulse = softness * (restitution * depth / p_step - damping * rel_vel) * m_jacLinDiagABInv[i];
- Vector3 impulse_vector = normal * normalImpulse;
- A->apply_impulse(m_relPosA, impulse_vector);
- B->apply_impulse(m_relPosB, -impulse_vector);
- if (m_poweredLinMotor && (!i)) { // apply linear motor
- if (m_accumulatedLinMotorImpulse < m_maxLinMotorForce) {
- real_t desiredMotorVel = m_targetLinMotorVelocity;
- real_t motor_relvel = desiredMotorVel + rel_vel;
- normalImpulse = -motor_relvel * m_jacLinDiagABInv[i];
- // clamp accumulated impulse
- real_t new_acc = m_accumulatedLinMotorImpulse + Math::abs(normalImpulse);
- if (new_acc > m_maxLinMotorForce) {
- new_acc = m_maxLinMotorForce;
- }
- real_t del = new_acc - m_accumulatedLinMotorImpulse;
- if (normalImpulse < real_t(0.0)) {
- normalImpulse = -del;
- } else {
- normalImpulse = del;
- }
- m_accumulatedLinMotorImpulse = new_acc;
- // apply clamped impulse
- impulse_vector = normal * normalImpulse;
- A->apply_impulse(m_relPosA, impulse_vector);
- B->apply_impulse(m_relPosB, -impulse_vector);
- }
- }
- }
- // angular
- // get axes in world space
- Vector3 axisA = m_calculatedTransformA.basis.get_axis(0);
- Vector3 axisB = m_calculatedTransformB.basis.get_axis(0);
-
- const Vector3 &angVelA = A->get_angular_velocity();
- const Vector3 &angVelB = B->get_angular_velocity();
-
- Vector3 angVelAroundAxisA = axisA * axisA.dot(angVelA);
- Vector3 angVelAroundAxisB = axisB * axisB.dot(angVelB);
-
- Vector3 angAorthog = angVelA - angVelAroundAxisA;
- Vector3 angBorthog = angVelB - angVelAroundAxisB;
- Vector3 velrelOrthog = angAorthog - angBorthog;
- //solve orthogonal angular velocity correction
- real_t len = velrelOrthog.length();
- if (len > real_t(0.00001)) {
- Vector3 normal = velrelOrthog.normalized();
- real_t denom = A->compute_angular_impulse_denominator(normal) + B->compute_angular_impulse_denominator(normal);
- velrelOrthog *= (real_t(1.) / denom) * m_dampingOrthoAng * m_softnessOrthoAng;
- }
- //solve angular positional correction
- Vector3 angularError = axisA.cross(axisB) * (real_t(1.) / p_step);
- real_t len2 = angularError.length();
- if (len2 > real_t(0.00001)) {
- Vector3 normal2 = angularError.normalized();
- real_t denom2 = A->compute_angular_impulse_denominator(normal2) + B->compute_angular_impulse_denominator(normal2);
- angularError *= (real_t(1.) / denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;
- }
- // apply impulse
- A->apply_torque_impulse(-velrelOrthog + angularError);
- B->apply_torque_impulse(velrelOrthog - angularError);
- real_t impulseMag;
- //solve angular limits
- if (m_solveAngLim) {
- impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingLimAng + m_angDepth * m_restitutionLimAng / p_step;
- impulseMag *= m_kAngle * m_softnessLimAng;
- } else {
- impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingDirAng + m_angDepth * m_restitutionDirAng / p_step;
- impulseMag *= m_kAngle * m_softnessDirAng;
- }
- Vector3 impulse = axisA * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
- //apply angular motor
- if (m_poweredAngMotor) {
- if (m_accumulatedAngMotorImpulse < m_maxAngMotorForce) {
- Vector3 velrel = angVelAroundAxisA - angVelAroundAxisB;
- real_t projRelVel = velrel.dot(axisA);
-
- real_t desiredMotorVel = m_targetAngMotorVelocity;
- real_t motor_relvel = desiredMotorVel - projRelVel;
-
- real_t angImpulse = m_kAngle * motor_relvel;
- // clamp accumulated impulse
- real_t new_acc = m_accumulatedAngMotorImpulse + Math::abs(angImpulse);
- if (new_acc > m_maxAngMotorForce) {
- new_acc = m_maxAngMotorForce;
- }
- real_t del = new_acc - m_accumulatedAngMotorImpulse;
- if (angImpulse < real_t(0.0)) {
- angImpulse = -del;
- } else {
- angImpulse = del;
- }
- m_accumulatedAngMotorImpulse = new_acc;
- // apply clamped impulse
- Vector3 motorImp = angImpulse * axisA;
- A->apply_torque_impulse(motorImp);
- B->apply_torque_impulse(-motorImp);
- }
- }
-} // SliderJointSW::solveConstraint()
-
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-
-void SliderJointSW::calculateTransforms(void) {
- m_calculatedTransformA = A->get_transform() * m_frameInA;
- m_calculatedTransformB = B->get_transform() * m_frameInB;
- m_realPivotAInW = m_calculatedTransformA.origin;
- m_realPivotBInW = m_calculatedTransformB.origin;
- m_sliderAxis = m_calculatedTransformA.basis.get_axis(0); // along X
- m_delta = m_realPivotBInW - m_realPivotAInW;
- m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
- Vector3 normalWorld;
- int i;
- //linear part
- for (i = 0; i < 3; i++) {
- normalWorld = m_calculatedTransformA.basis.get_axis(i);
- m_depth[i] = m_delta.dot(normalWorld);
- }
-} // SliderJointSW::calculateTransforms()
-
-//-----------------------------------------------------------------------------
-
-void SliderJointSW::testLinLimits(void) {
- m_solveLinLim = false;
- m_linPos = m_depth[0];
- if (m_lowerLinLimit <= m_upperLinLimit) {
- if (m_depth[0] > m_upperLinLimit) {
- m_depth[0] -= m_upperLinLimit;
- m_solveLinLim = true;
- } else if (m_depth[0] < m_lowerLinLimit) {
- m_depth[0] -= m_lowerLinLimit;
- m_solveLinLim = true;
- } else {
- m_depth[0] = real_t(0.);
- }
- } else {
- m_depth[0] = real_t(0.);
- }
-} // SliderJointSW::testLinLimits()
-
-//-----------------------------------------------------------------------------
-
-void SliderJointSW::testAngLimits(void) {
- m_angDepth = real_t(0.);
- m_solveAngLim = false;
- if (m_lowerAngLimit <= m_upperAngLimit) {
- const Vector3 axisA0 = m_calculatedTransformA.basis.get_axis(1);
- const Vector3 axisA1 = m_calculatedTransformA.basis.get_axis(2);
- const Vector3 axisB0 = m_calculatedTransformB.basis.get_axis(1);
- real_t rot = atan2fast(axisB0.dot(axisA1), axisB0.dot(axisA0));
- if (rot < m_lowerAngLimit) {
- m_angDepth = rot - m_lowerAngLimit;
- m_solveAngLim = true;
- } else if (rot > m_upperAngLimit) {
- m_angDepth = rot - m_upperAngLimit;
- m_solveAngLim = true;
- }
- }
-} // SliderJointSW::testAngLimits()
-
-//-----------------------------------------------------------------------------
-
-Vector3 SliderJointSW::getAncorInA(void) {
- Vector3 ancorInA;
- ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * real_t(0.5) * m_sliderAxis;
- ancorInA = A->get_transform().inverse().xform(ancorInA);
- return ancorInA;
-} // SliderJointSW::getAncorInA()
-
-//-----------------------------------------------------------------------------
-
-Vector3 SliderJointSW::getAncorInB(void) {
- Vector3 ancorInB;
- ancorInB = m_frameInB.origin;
- return ancorInB;
-} // SliderJointSW::getAncorInB();
-
-void SliderJointSW::set_param(PhysicsServer::SliderJointParam p_param, real_t p_value) {
-
- switch (p_param) {
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: m_upperLinLimit = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: m_lowerLinLimit = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: m_softnessLimLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: m_restitutionLimLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: m_dampingLimLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: m_softnessDirLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: m_restitutionDirLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: m_dampingDirLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoLin = p_value; break;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: m_dampingOrthoLin = p_value; break;
-
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: m_upperAngLimit = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: m_lowerAngLimit = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: m_softnessLimAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: m_restitutionLimAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: m_dampingLimAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: m_softnessDirAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: m_restitutionDirAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: m_dampingDirAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoAng = p_value; break;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: m_dampingOrthoAng = p_value; break;
-
- case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning
- }
-}
-
-real_t SliderJointSW::get_param(PhysicsServer::SliderJointParam p_param) const {
-
- switch (p_param) {
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return m_upperLinLimit;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return m_lowerLinLimit;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return m_softnessLimLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return m_restitutionLimLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return m_dampingLimLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return m_softnessDirLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return m_restitutionDirLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return m_dampingDirLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoLin;
- case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return m_dampingOrthoLin;
-
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return m_upperAngLimit;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return m_lowerAngLimit;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return m_softnessLimAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return m_restitutionLimAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return m_dampingLimAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return m_softnessDirAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return m_restitutionDirAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return m_dampingDirAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoAng;
- case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return m_dampingOrthoAng;
-
- case PhysicsServer::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning
- }
-
- return 0;
-}
diff --git a/servers/physics/joints/slider_joint_sw.h b/servers/physics/joints/slider_joint_sw.h
deleted file mode 100644
index 8b416eafc9..0000000000
--- a/servers/physics/joints/slider_joint_sw.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*************************************************************************/
-/* slider_joint_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted to Godot from the Bullet library.
-*/
-
-#ifndef SLIDER_JOINT_SW_H
-#define SLIDER_JOINT_SW_H
-
-#include "servers/physics/joints/jacobian_entry_sw.h"
-#include "servers/physics/joints_sw.h"
-
-/*
-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.
-*/
-
-/*
-Added by Roman Ponomarev (rponom@gmail.com)
-April 04, 2008
-
-*/
-
-#define SLIDER_CONSTRAINT_DEF_SOFTNESS (real_t(1.0))
-#define SLIDER_CONSTRAINT_DEF_DAMPING (real_t(1.0))
-#define SLIDER_CONSTRAINT_DEF_RESTITUTION (real_t(0.7))
-
-//-----------------------------------------------------------------------------
-
-class SliderJointSW : public JointSW {
-protected:
- union {
- struct {
- BodySW *A;
- BodySW *B;
- };
-
- BodySW *_arr[2];
- };
-
- Transform m_frameInA;
- Transform m_frameInB;
-
- // linear limits
- real_t m_lowerLinLimit;
- real_t m_upperLinLimit;
- // angular limits
- real_t m_lowerAngLimit;
- real_t m_upperAngLimit;
- // softness, restitution and damping for different cases
- // DirLin - moving inside linear limits
- // LimLin - hitting linear limit
- // DirAng - moving inside angular limits
- // LimAng - hitting angular limit
- // OrthoLin, OrthoAng - against constraint axis
- real_t m_softnessDirLin;
- real_t m_restitutionDirLin;
- real_t m_dampingDirLin;
- real_t m_softnessDirAng;
- real_t m_restitutionDirAng;
- real_t m_dampingDirAng;
- real_t m_softnessLimLin;
- real_t m_restitutionLimLin;
- real_t m_dampingLimLin;
- real_t m_softnessLimAng;
- real_t m_restitutionLimAng;
- real_t m_dampingLimAng;
- real_t m_softnessOrthoLin;
- real_t m_restitutionOrthoLin;
- real_t m_dampingOrthoLin;
- real_t m_softnessOrthoAng;
- real_t m_restitutionOrthoAng;
- real_t m_dampingOrthoAng;
-
- // for interlal use
- bool m_solveLinLim;
- bool m_solveAngLim;
-
- JacobianEntrySW m_jacLin[3];
- real_t m_jacLinDiagABInv[3];
-
- JacobianEntrySW m_jacAng[3];
-
- real_t m_timeStep;
- Transform m_calculatedTransformA;
- Transform m_calculatedTransformB;
-
- Vector3 m_sliderAxis;
- Vector3 m_realPivotAInW;
- Vector3 m_realPivotBInW;
- Vector3 m_projPivotInW;
- Vector3 m_delta;
- Vector3 m_depth;
- Vector3 m_relPosA;
- Vector3 m_relPosB;
-
- real_t m_linPos;
-
- real_t m_angDepth;
- real_t m_kAngle;
-
- bool m_poweredLinMotor;
- real_t m_targetLinMotorVelocity;
- real_t m_maxLinMotorForce;
- real_t m_accumulatedLinMotorImpulse;
-
- bool m_poweredAngMotor;
- real_t m_targetAngMotorVelocity;
- real_t m_maxAngMotorForce;
- real_t m_accumulatedAngMotorImpulse;
-
- //------------------------
- void initParams();
-
-public:
- // constructors
- SliderJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB);
- //SliderJointSW();
- // overrides
-
- // access
- const BodySW *getRigidBodyA() const { return A; }
- const BodySW *getRigidBodyB() const { return B; }
- const Transform &getCalculatedTransformA() const { return m_calculatedTransformA; }
- const Transform &getCalculatedTransformB() const { return m_calculatedTransformB; }
- const Transform &getFrameOffsetA() const { return m_frameInA; }
- const Transform &getFrameOffsetB() const { return m_frameInB; }
- Transform &getFrameOffsetA() { return m_frameInA; }
- Transform &getFrameOffsetB() { return m_frameInB; }
- real_t getLowerLinLimit() { return m_lowerLinLimit; }
- void setLowerLinLimit(real_t lowerLimit) { m_lowerLinLimit = lowerLimit; }
- real_t getUpperLinLimit() { return m_upperLinLimit; }
- void setUpperLinLimit(real_t upperLimit) { m_upperLinLimit = upperLimit; }
- real_t getLowerAngLimit() { return m_lowerAngLimit; }
- void setLowerAngLimit(real_t lowerLimit) { m_lowerAngLimit = lowerLimit; }
- real_t getUpperAngLimit() { return m_upperAngLimit; }
- void setUpperAngLimit(real_t upperLimit) { m_upperAngLimit = upperLimit; }
-
- real_t getSoftnessDirLin() { return m_softnessDirLin; }
- real_t getRestitutionDirLin() { return m_restitutionDirLin; }
- real_t getDampingDirLin() { return m_dampingDirLin; }
- real_t getSoftnessDirAng() { return m_softnessDirAng; }
- real_t getRestitutionDirAng() { return m_restitutionDirAng; }
- real_t getDampingDirAng() { return m_dampingDirAng; }
- real_t getSoftnessLimLin() { return m_softnessLimLin; }
- real_t getRestitutionLimLin() { return m_restitutionLimLin; }
- real_t getDampingLimLin() { return m_dampingLimLin; }
- real_t getSoftnessLimAng() { return m_softnessLimAng; }
- real_t getRestitutionLimAng() { return m_restitutionLimAng; }
- real_t getDampingLimAng() { return m_dampingLimAng; }
- real_t getSoftnessOrthoLin() { return m_softnessOrthoLin; }
- real_t getRestitutionOrthoLin() { return m_restitutionOrthoLin; }
- real_t getDampingOrthoLin() { return m_dampingOrthoLin; }
- real_t getSoftnessOrthoAng() { return m_softnessOrthoAng; }
- real_t getRestitutionOrthoAng() { return m_restitutionOrthoAng; }
- real_t getDampingOrthoAng() { return m_dampingOrthoAng; }
- void setSoftnessDirLin(real_t softnessDirLin) { m_softnessDirLin = softnessDirLin; }
- void setRestitutionDirLin(real_t restitutionDirLin) { m_restitutionDirLin = restitutionDirLin; }
- void setDampingDirLin(real_t dampingDirLin) { m_dampingDirLin = dampingDirLin; }
- void setSoftnessDirAng(real_t softnessDirAng) { m_softnessDirAng = softnessDirAng; }
- void setRestitutionDirAng(real_t restitutionDirAng) { m_restitutionDirAng = restitutionDirAng; }
- void setDampingDirAng(real_t dampingDirAng) { m_dampingDirAng = dampingDirAng; }
- void setSoftnessLimLin(real_t softnessLimLin) { m_softnessLimLin = softnessLimLin; }
- void setRestitutionLimLin(real_t restitutionLimLin) { m_restitutionLimLin = restitutionLimLin; }
- void setDampingLimLin(real_t dampingLimLin) { m_dampingLimLin = dampingLimLin; }
- void setSoftnessLimAng(real_t softnessLimAng) { m_softnessLimAng = softnessLimAng; }
- void setRestitutionLimAng(real_t restitutionLimAng) { m_restitutionLimAng = restitutionLimAng; }
- void setDampingLimAng(real_t dampingLimAng) { m_dampingLimAng = dampingLimAng; }
- void setSoftnessOrthoLin(real_t softnessOrthoLin) { m_softnessOrthoLin = softnessOrthoLin; }
- void setRestitutionOrthoLin(real_t restitutionOrthoLin) { m_restitutionOrthoLin = restitutionOrthoLin; }
- void setDampingOrthoLin(real_t dampingOrthoLin) { m_dampingOrthoLin = dampingOrthoLin; }
- void setSoftnessOrthoAng(real_t softnessOrthoAng) { m_softnessOrthoAng = softnessOrthoAng; }
- void setRestitutionOrthoAng(real_t restitutionOrthoAng) { m_restitutionOrthoAng = restitutionOrthoAng; }
- void setDampingOrthoAng(real_t dampingOrthoAng) { m_dampingOrthoAng = dampingOrthoAng; }
- void setPoweredLinMotor(bool onOff) { m_poweredLinMotor = onOff; }
- bool getPoweredLinMotor() { return m_poweredLinMotor; }
- void setTargetLinMotorVelocity(real_t targetLinMotorVelocity) { m_targetLinMotorVelocity = targetLinMotorVelocity; }
- real_t getTargetLinMotorVelocity() { return m_targetLinMotorVelocity; }
- void setMaxLinMotorForce(real_t maxLinMotorForce) { m_maxLinMotorForce = maxLinMotorForce; }
- real_t getMaxLinMotorForce() { return m_maxLinMotorForce; }
- void setPoweredAngMotor(bool onOff) { m_poweredAngMotor = onOff; }
- bool getPoweredAngMotor() { return m_poweredAngMotor; }
- void setTargetAngMotorVelocity(real_t targetAngMotorVelocity) { m_targetAngMotorVelocity = targetAngMotorVelocity; }
- real_t getTargetAngMotorVelocity() { return m_targetAngMotorVelocity; }
- void setMaxAngMotorForce(real_t maxAngMotorForce) { m_maxAngMotorForce = maxAngMotorForce; }
- real_t getMaxAngMotorForce() { return m_maxAngMotorForce; }
- real_t getLinearPos() { return m_linPos; }
-
- // access for ODE solver
- bool getSolveLinLimit() { return m_solveLinLim; }
- real_t getLinDepth() { return m_depth[0]; }
- bool getSolveAngLimit() { return m_solveAngLim; }
- real_t getAngDepth() { return m_angDepth; }
- // shared code used by ODE solver
- void calculateTransforms(void);
- void testLinLimits(void);
- void testAngLimits(void);
- // access for PE Solver
- Vector3 getAncorInA(void);
- Vector3 getAncorInB(void);
-
- void set_param(PhysicsServer::SliderJointParam p_param, real_t p_value);
- real_t get_param(PhysicsServer::SliderJointParam p_param) const;
-
- bool setup(real_t p_step);
- void solve(real_t p_step);
-
- virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_SLIDER; }
-};
-
-#endif // SLIDER_JOINT_SW_H
diff --git a/servers/physics/joints_sw.h b/servers/physics/joints_sw.h
deleted file mode 100644
index c284d541e3..0000000000
--- a/servers/physics/joints_sw.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*************************************************************************/
-/* joints_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 JOINTS_SW_H
-#define JOINTS_SW_H
-
-#include "body_sw.h"
-#include "constraint_sw.h"
-
-class JointSW : public ConstraintSW {
-
-public:
- virtual PhysicsServer::JointType get_type() const = 0;
- _FORCE_INLINE_ JointSW(BodySW **p_body_ptr = NULL, int p_body_count = 0) :
- ConstraintSW(p_body_ptr, p_body_count) {
- }
-};
-
-#endif // JOINTS_SW_H
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
deleted file mode 100644
index 25b21a5394..0000000000
--- a/servers/physics/physics_server_sw.cpp
+++ /dev/null
@@ -1,1589 +0,0 @@
-/*************************************************************************/
-/* physics_server_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_sw.h"
-
-#include "broad_phase_basic.h"
-#include "broad_phase_octree.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/os/os.h"
-#include "joints/cone_twist_joint_sw.h"
-#include "joints/generic_6dof_joint_sw.h"
-#include "joints/hinge_joint_sw.h"
-#include "joints/pin_joint_sw.h"
-#include "joints/slider_joint_sw.h"
-
-#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 PhysicsServerSW::shape_create(ShapeType p_shape) {
-
- ShapeSW *shape = NULL;
- switch (p_shape) {
-
- case SHAPE_PLANE: {
-
- shape = memnew(PlaneShapeSW);
- } break;
- case SHAPE_RAY: {
-
- shape = memnew(RayShapeSW);
- } break;
- case SHAPE_SPHERE: {
-
- shape = memnew(SphereShapeSW);
- } break;
- case SHAPE_BOX: {
-
- shape = memnew(BoxShapeSW);
- } break;
- case SHAPE_CAPSULE: {
-
- shape = memnew(CapsuleShapeSW);
- } break;
- case SHAPE_CYLINDER: {
-
- ERR_FAIL_V_MSG(RID(), "CylinderShape is not supported in GodotPhysics. Please switch to Bullet in the Project Settings.");
- } break;
- case SHAPE_CONVEX_POLYGON: {
-
- shape = memnew(ConvexPolygonShapeSW);
- } break;
- case SHAPE_CONCAVE_POLYGON: {
-
- shape = memnew(ConcavePolygonShapeSW);
- } break;
- case SHAPE_HEIGHTMAP: {
-
- shape = memnew(HeightMapShapeSW);
- } break;
- case SHAPE_CUSTOM: {
-
- ERR_FAIL_V(RID());
-
- } break;
- }
-
- RID id = shape_owner.make_rid(shape);
- shape->set_self(id);
-
- return id;
-};
-
-void PhysicsServerSW::shape_set_data(RID p_shape, const Variant &p_data) {
-
- ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- shape->set_data(p_data);
-};
-
-void PhysicsServerSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
-
- ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- shape->set_custom_bias(p_bias);
-}
-
-PhysicsServer::ShapeType PhysicsServerSW::shape_get_type(RID p_shape) const {
-
- const ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM);
- return shape->get_type();
-};
-
-Variant PhysicsServerSW::shape_get_data(RID p_shape) const {
-
- const ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, Variant());
- ERR_FAIL_COND_V(!shape->is_configured(), Variant());
- return shape->get_data();
-};
-
-void PhysicsServerSW::shape_set_margin(RID p_shape, real_t p_margin) {
-}
-
-real_t PhysicsServerSW::shape_get_margin(RID p_shape) const {
- return 0.0;
-}
-
-real_t PhysicsServerSW::shape_get_custom_solver_bias(RID p_shape) const {
-
- const ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
- return shape->get_custom_bias();
-}
-
-RID PhysicsServerSW::space_create() {
-
- SpaceSW *space = memnew(SpaceSW);
- RID id = space_owner.make_rid(space);
- space->set_self(id);
- RID area_id = area_create();
- AreaSW *area = area_owner.getornull(area_id);
- ERR_FAIL_COND_V(!area, RID());
- space->set_default_area(area);
- area->set_space(space);
- area->set_priority(-1);
- RID sgb = body_create();
- body_set_space(sgb, id);
- body_set_mode(sgb, BODY_MODE_STATIC);
- space->set_static_global_body(sgb);
-
- return id;
-};
-
-void PhysicsServerSW::space_set_active(RID p_space, bool p_active) {
-
- SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- if (p_active)
- active_spaces.insert(space);
- else
- active_spaces.erase(space);
-}
-
-bool PhysicsServerSW::space_is_active(RID p_space) const {
-
- const SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, false);
-
- return active_spaces.has(space);
-}
-
-void PhysicsServerSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
-
- SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
-
- space->set_param(p_param, p_value);
-}
-
-real_t PhysicsServerSW::space_get_param(RID p_space, SpaceParameter p_param) const {
-
- const SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, 0);
- return space->get_param(p_param);
-}
-
-PhysicsDirectSpaceState *PhysicsServerSW::space_get_direct_state(RID p_space) {
-
- SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, NULL);
- ERR_FAIL_COND_V_MSG(!doing_sync || space->is_locked(), NULL, "Space state is inaccessible right now, wait for iteration or physics process notification.");
-
- return space->get_direct_state();
-}
-
-void PhysicsServerSW::space_set_debug_contacts(RID p_space, int p_max_contacts) {
-
- SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- space->set_debug_contacts(p_max_contacts);
-}
-
-Vector<Vector3> PhysicsServerSW::space_get_contacts(RID p_space) const {
-
- SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, Vector<Vector3>());
- return space->get_debug_contacts();
-}
-
-int PhysicsServerSW::space_get_contact_count(RID p_space) const {
-
- SpaceSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, 0);
- return space->get_debug_contact_count();
-}
-
-RID PhysicsServerSW::area_create() {
-
- AreaSW *area = memnew(AreaSW);
- RID rid = area_owner.make_rid(area);
- area->set_self(rid);
- return rid;
-};
-
-void PhysicsServerSW::area_set_space(RID p_area, RID p_space) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- SpaceSW *space = NULL;
- if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- }
-
- if (area->get_space() == space)
- return; //pointless
-
- area->clear_constraints();
- area->set_space(space);
-};
-
-RID PhysicsServerSW::area_get_space(RID p_area) const {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, RID());
-
- SpaceSW *space = area->get_space();
- if (!space)
- return RID();
- return space->get_self();
-};
-
-void PhysicsServerSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_space_override_mode(p_mode);
-}
-
-PhysicsServer::AreaSpaceOverrideMode PhysicsServerSW::area_get_space_override_mode(RID p_area) const {
-
- const AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED);
-
- return area->get_space_override_mode();
-}
-
-void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
-
- area->add_shape(shape, p_transform, p_disabled);
-}
-
-void PhysicsServerSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- ERR_FAIL_COND(!shape->is_configured());
-
- area->set_shape(p_shape_idx, shape);
-}
-
-void PhysicsServerSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_shape_transform(p_shape_idx, p_transform);
-}
-
-int PhysicsServerSW::area_get_shape_count(RID p_area) const {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, -1);
-
- return area->get_shape_count();
-}
-RID PhysicsServerSW::area_get_shape(RID p_area, int p_shape_idx) const {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, RID());
-
- ShapeSW *shape = area->get_shape(p_shape_idx);
- ERR_FAIL_COND_V(!shape, RID());
-
- return shape->get_self();
-}
-Transform PhysicsServerSW::area_get_shape_transform(RID p_area, int p_shape_idx) const {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform());
-
- return area->get_shape_transform(p_shape_idx);
-}
-
-void PhysicsServerSW::area_remove_shape(RID p_area, int p_shape_idx) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->remove_shape(p_shape_idx);
-}
-
-void PhysicsServerSW::area_clear_shapes(RID p_area) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- while (area->get_shape_count())
- area->remove_shape(0);
-}
-
-void PhysicsServerSW::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count());
- FLUSH_QUERY_CHECK(area);
- area->set_shape_as_disabled(p_shape_idx, p_disabled);
-}
-
-void PhysicsServerSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
-
- if (space_owner.owns(p_area)) {
- SpaceSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_instance_id(p_id);
-}
-ObjectID PhysicsServerSW::area_get_object_instance_id(RID p_area) const {
-
- if (space_owner.owns(p_area)) {
- SpaceSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, ObjectID());
- return area->get_instance_id();
-}
-
-void PhysicsServerSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
-
- if (space_owner.owns(p_area)) {
- SpaceSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_param(p_param, p_value);
-};
-
-void PhysicsServerSW::area_set_transform(RID p_area, const Transform &p_transform) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_transform(p_transform);
-};
-
-Variant PhysicsServerSW::area_get_param(RID p_area, AreaParameter p_param) const {
-
- if (space_owner.owns(p_area)) {
- SpaceSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Variant());
-
- return area->get_param(p_param);
-};
-
-Transform PhysicsServerSW::area_get_transform(RID p_area) const {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform());
-
- return area->get_transform();
-};
-
-void PhysicsServerSW::area_set_collision_layer(RID p_area, uint32_t p_layer) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_collision_layer(p_layer);
-}
-
-void PhysicsServerSW::area_set_collision_mask(RID p_area, uint32_t p_mask) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_collision_mask(p_mask);
-}
-
-void PhysicsServerSW::area_set_monitorable(RID p_area, bool p_monitorable) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- FLUSH_QUERY_CHECK(area);
-
- area->set_monitorable(p_monitorable);
-}
-
-void PhysicsServerSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
-}
-
-void PhysicsServerSW::area_set_ray_pickable(RID p_area, bool p_enable) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_ray_pickable(p_enable);
-}
-
-bool PhysicsServerSW::area_is_ray_pickable(RID p_area) const {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, false);
-
- return area->is_ray_pickable();
-}
-
-void PhysicsServerSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
-
- AreaSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
-}
-
-/* BODY API */
-
-RID PhysicsServerSW::body_create(BodyMode p_mode, bool p_init_sleeping) {
-
- BodySW *body = memnew(BodySW);
- 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;
-};
-
-void PhysicsServerSW::body_set_space(RID p_body, RID p_space) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- SpaceSW *space = NULL;
- if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- }
-
- if (body->get_space() == space)
- return; //pointless
-
- body->clear_constraint_map();
- body->set_space(space);
-};
-
-RID PhysicsServerSW::body_get_space(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, RID());
-
- SpaceSW *space = body->get_space();
- if (!space)
- return RID();
- return space->get_self();
-};
-
-void PhysicsServerSW::body_set_mode(RID p_body, BodyMode p_mode) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_mode(p_mode);
-};
-
-PhysicsServer::BodyMode PhysicsServerSW::body_get_mode(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
-
- return body->get_mode();
-};
-
-void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
-
- body->add_shape(shape, p_transform, p_disabled);
-}
-
-void PhysicsServerSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- ShapeSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- ERR_FAIL_COND(!shape->is_configured());
-
- body->set_shape(p_shape_idx, shape);
-}
-void PhysicsServerSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_shape_transform(p_shape_idx, p_transform);
-}
-
-int PhysicsServerSW::body_get_shape_count(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, -1);
-
- return body->get_shape_count();
-}
-RID PhysicsServerSW::body_get_shape(RID p_body, int p_shape_idx) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, RID());
-
- ShapeSW *shape = body->get_shape(p_shape_idx);
- ERR_FAIL_COND_V(!shape, RID());
-
- return shape->get_self();
-}
-
-void PhysicsServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
- FLUSH_QUERY_CHECK(body);
-
- body->set_shape_as_disabled(p_shape_idx, p_disabled);
-}
-
-Transform PhysicsServerSW::body_get_shape_transform(RID p_body, int p_shape_idx) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Transform());
-
- return body->get_shape_transform(p_shape_idx);
-}
-
-void PhysicsServerSW::body_remove_shape(RID p_body, int p_shape_idx) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->remove_shape(p_shape_idx);
-}
-
-void PhysicsServerSW::body_clear_shapes(RID p_body) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- while (body->get_shape_count())
- body->remove_shape(0);
-}
-
-void PhysicsServerSW::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_continuous_collision_detection(p_enable);
-}
-
-bool PhysicsServerSW::body_is_continuous_collision_detection_enabled(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
-
- return body->is_continuous_collision_detection_enabled();
-}
-
-void PhysicsServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_collision_layer(p_layer);
- body->wakeup();
-}
-
-uint32_t PhysicsServerSW::body_get_collision_layer(RID p_body) const {
-
- const BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_collision_layer();
-}
-
-void PhysicsServerSW::body_set_collision_mask(RID p_body, uint32_t p_mask) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_collision_mask(p_mask);
- body->wakeup();
-}
-
-uint32_t PhysicsServerSW::body_get_collision_mask(RID p_body) const {
-
- const BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_collision_mask();
-}
-
-void PhysicsServerSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_instance_id(p_id);
-};
-
-ObjectID PhysicsServerSW::body_get_object_instance_id(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, ObjectID());
-
- return body->get_instance_id();
-};
-
-void PhysicsServerSW::body_set_user_flags(RID p_body, uint32_t p_flags) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-};
-
-uint32_t PhysicsServerSW::body_get_user_flags(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return 0;
-};
-
-void PhysicsServerSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_param(p_param, p_value);
-};
-
-real_t PhysicsServerSW::body_get_param(RID p_body, BodyParameter p_param) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_param(p_param);
-};
-
-void PhysicsServerSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_kinematic_margin(p_margin);
-}
-
-real_t PhysicsServerSW::body_get_kinematic_safe_margin(RID p_body) const {
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_kinematic_margin();
-}
-
-void PhysicsServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_state(p_state, p_variant);
-};
-
-Variant PhysicsServerSW::body_get_state(RID p_body, BodyState p_state) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Variant());
-
- return body->get_state(p_state);
-};
-
-void PhysicsServerSW::body_set_applied_force(RID p_body, const Vector3 &p_force) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_applied_force(p_force);
- body->wakeup();
-};
-
-Vector3 PhysicsServerSW::body_get_applied_force(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Vector3());
- return body->get_applied_force();
-};
-
-void PhysicsServerSW::body_set_applied_torque(RID p_body, const Vector3 &p_torque) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_applied_torque(p_torque);
- body->wakeup();
-};
-
-Vector3 PhysicsServerSW::body_get_applied_torque(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Vector3());
-
- return body->get_applied_torque();
-};
-
-void PhysicsServerSW::body_add_central_force(RID p_body, const Vector3 &p_force) {
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_central_force(p_force);
- body->wakeup();
-}
-
-void PhysicsServerSW::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) {
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_force(p_force, p_pos);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_add_torque(RID p_body, const Vector3 &p_torque) {
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_torque(p_torque);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) {
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_central_impulse(p_impulse);
- body->wakeup();
-}
-
-void PhysicsServerSW::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_impulse(p_pos, p_impulse);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_torque_impulse(p_impulse);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- Vector3 v = body->get_linear_velocity();
- Vector3 axis = p_axis_velocity.normalized();
- v -= axis * axis.dot(v);
- v += p_axis_velocity;
- body->set_linear_velocity(v);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_axis_lock(p_axis, p_lock);
- body->wakeup();
-}
-
-bool PhysicsServerSW::body_is_axis_locked(RID p_body, BodyAxis p_axis) const {
-
- const BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
- return body->is_axis_locked(p_axis);
-}
-
-void PhysicsServerSW::body_add_collision_exception(RID p_body, RID p_body_b) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_exception(p_body_b);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_remove_collision_exception(RID p_body, RID p_body_b) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->remove_exception(p_body_b);
- body->wakeup();
-};
-
-void PhysicsServerSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- for (int i = 0; i < body->get_exceptions().size(); i++) {
- p_exceptions->push_back(body->get_exceptions()[i]);
- }
-};
-
-void PhysicsServerSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-};
-
-real_t PhysicsServerSW::body_get_contacts_reported_depth_threshold(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
- return 0;
-};
-
-void PhysicsServerSW::body_set_omit_force_integration(RID p_body, bool p_omit) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_omit_force_integration(p_omit);
-};
-
-bool PhysicsServerSW::body_is_omitting_force_integration(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->get_omit_force_integration();
-};
-
-void PhysicsServerSW::body_set_max_contacts_reported(RID p_body, int p_contacts) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_max_contacts_reported(p_contacts);
-}
-
-int PhysicsServerSW::body_get_max_contacts_reported(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, -1);
- return body->get_max_contacts_reported();
-}
-
-void PhysicsServerSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
-
- BodySW *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);
-}
-
-void PhysicsServerSW::body_set_ray_pickable(RID p_body, bool p_enable) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_ray_pickable(p_enable);
-}
-
-bool PhysicsServerSW::body_is_ray_pickable(RID p_body) const {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->is_ray_pickable();
-}
-
-bool PhysicsServerSW::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) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- _update_shapes();
-
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result, p_exclude_raycast_shapes);
-}
-
-int PhysicsServerSW::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, float p_margin) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- _update_shapes();
-
- return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
-}
-
-PhysicsDirectBodyState *PhysicsServerSW::body_get_direct_state(RID p_body) {
-
- BodySW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, NULL);
- ERR_FAIL_COND_V_MSG(!doing_sync || body->get_space()->is_locked(), NULL, "Body state is inaccessible right now, wait for iteration or physics process notification.");
-
- direct_state->body = body;
- return direct_state;
-}
-
-/* JOINT API */
-
-RID PhysicsServerSW::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
-
- BodySW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
-
- if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
- p_body_B = body_A->get_space()->get_static_global_body();
- }
-
- BodySW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
-
- ERR_FAIL_COND_V(body_A == body_B, RID());
-
- JointSW *joint = memnew(PinJointSW(body_A, p_local_A, body_B, p_local_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
-}
-
-void PhysicsServerSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
- PinJointSW *pin_joint = static_cast<PinJointSW *>(joint);
- pin_joint->set_param(p_param, p_value);
-}
-real_t PhysicsServerSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0);
- PinJointSW *pin_joint = static_cast<PinJointSW *>(joint);
- return pin_joint->get_param(p_param);
-}
-
-void PhysicsServerSW::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
- PinJointSW *pin_joint = static_cast<PinJointSW *>(joint);
- pin_joint->set_pos_a(p_A);
-}
-Vector3 PhysicsServerSW::pin_joint_get_local_a(RID p_joint) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, Vector3());
- ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
- PinJointSW *pin_joint = static_cast<PinJointSW *>(joint);
- return pin_joint->get_position_a();
-}
-
-void PhysicsServerSW::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
- PinJointSW *pin_joint = static_cast<PinJointSW *>(joint);
- pin_joint->set_pos_b(p_B);
-}
-Vector3 PhysicsServerSW::pin_joint_get_local_b(RID p_joint) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, Vector3());
- ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
- PinJointSW *pin_joint = static_cast<PinJointSW *>(joint);
- return pin_joint->get_position_b();
-}
-
-RID PhysicsServerSW::joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) {
-
- BodySW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
-
- if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
- p_body_B = body_A->get_space()->get_static_global_body();
- }
-
- BodySW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
-
- ERR_FAIL_COND_V(body_A == body_B, RID());
-
- JointSW *joint = memnew(HingeJointSW(body_A, body_B, p_frame_A, p_frame_B));
- RID rid = joint_owner.make_rid(joint);
- joint->set_self(rid);
- return rid;
-}
-
-RID PhysicsServerSW::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) {
-
- BodySW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
-
- if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
- p_body_B = body_A->get_space()->get_static_global_body();
- }
-
- BodySW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
-
- ERR_FAIL_COND_V(body_A == body_B, RID());
-
- JointSW *joint = memnew(HingeJointSW(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;
-}
-
-void PhysicsServerSW::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
- HingeJointSW *hinge_joint = static_cast<HingeJointSW *>(joint);
- hinge_joint->set_param(p_param, p_value);
-}
-real_t PhysicsServerSW::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0);
- HingeJointSW *hinge_joint = static_cast<HingeJointSW *>(joint);
- return hinge_joint->get_param(p_param);
-}
-
-void PhysicsServerSW::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
- HingeJointSW *hinge_joint = static_cast<HingeJointSW *>(joint);
- hinge_joint->set_flag(p_flag, p_value);
-}
-bool PhysicsServerSW::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, false);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false);
- HingeJointSW *hinge_joint = static_cast<HingeJointSW *>(joint);
- return hinge_joint->get_flag(p_flag);
-}
-
-void PhysicsServerSW::joint_set_solver_priority(RID p_joint, int p_priority) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- joint->set_priority(p_priority);
-}
-
-int PhysicsServerSW::joint_get_solver_priority(RID p_joint) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- return joint->get_priority();
-}
-
-void PhysicsServerSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
-
- joint->disable_collisions_between_bodies(p_disable);
-
- if (2 == joint->get_body_count()) {
- BodySW *body_a = *joint->get_body_ptr();
- BodySW *body_b = *(joint->get_body_ptr() + 1);
-
- if (p_disable) {
- body_add_collision_exception(body_a->get_self(), body_b->get_self());
- body_add_collision_exception(body_b->get_self(), body_a->get_self());
- } else {
- body_remove_collision_exception(body_a->get_self(), body_b->get_self());
- body_remove_collision_exception(body_b->get_self(), body_a->get_self());
- }
- }
-}
-
-bool PhysicsServerSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, true);
-
- return joint->is_disabled_collisions_between_bodies();
-}
-
-PhysicsServerSW::JointType PhysicsServerSW::joint_get_type(RID p_joint) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, JOINT_PIN);
- return joint->get_type();
-}
-
-RID PhysicsServerSW::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
-
- BodySW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
-
- if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
- p_body_B = body_A->get_space()->get_static_global_body();
- }
-
- BodySW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
-
- ERR_FAIL_COND_V(body_A == body_B, RID());
-
- JointSW *joint = memnew(SliderJointSW(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;
-}
-
-void PhysicsServerSW::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER);
- SliderJointSW *slider_joint = static_cast<SliderJointSW *>(joint);
- slider_joint->set_param(p_param, p_value);
-}
-real_t PhysicsServerSW::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0);
- SliderJointSW *slider_joint = static_cast<SliderJointSW *>(joint);
- return slider_joint->get_param(p_param);
-}
-
-RID PhysicsServerSW::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
-
- BodySW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
-
- if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
- p_body_B = body_A->get_space()->get_static_global_body();
- }
-
- BodySW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
-
- ERR_FAIL_COND_V(body_A == body_B, RID());
-
- JointSW *joint = memnew(ConeTwistJointSW(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;
-}
-
-void PhysicsServerSW::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST);
- ConeTwistJointSW *cone_twist_joint = static_cast<ConeTwistJointSW *>(joint);
- cone_twist_joint->set_param(p_param, p_value);
-}
-real_t PhysicsServerSW::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0);
- ConeTwistJointSW *cone_twist_joint = static_cast<ConeTwistJointSW *>(joint);
- return cone_twist_joint->get_param(p_param);
-}
-
-RID PhysicsServerSW::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
-
- BodySW *body_A = body_owner.getornull(p_body_A);
- ERR_FAIL_COND_V(!body_A, RID());
-
- if (!p_body_B.is_valid()) {
- ERR_FAIL_COND_V(!body_A->get_space(), RID());
- p_body_B = body_A->get_space()->get_static_global_body();
- }
-
- BodySW *body_B = body_owner.getornull(p_body_B);
- ERR_FAIL_COND_V(!body_B, RID());
-
- ERR_FAIL_COND_V(body_A == body_B, RID());
-
- JointSW *joint = memnew(Generic6DOFJointSW(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;
-}
-
-void PhysicsServerSW::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
- Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW *>(joint);
- generic_6dof_joint->set_param(p_axis, p_param, p_value);
-}
-real_t PhysicsServerSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, 0);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
- Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW *>(joint);
- return generic_6dof_joint->get_param(p_axis, p_param);
-}
-
-void PhysicsServerSW::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
- ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
- Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW *>(joint);
- generic_6dof_joint->set_flag(p_axis, p_flag, p_enable);
-}
-bool PhysicsServerSW::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) {
-
- JointSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, false);
- ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false);
- Generic6DOFJointSW *generic_6dof_joint = static_cast<Generic6DOFJointSW *>(joint);
- return generic_6dof_joint->get_flag(p_axis, p_flag);
-}
-
-void PhysicsServerSW::free(RID p_rid) {
-
- _update_shapes(); //just in case
-
- if (shape_owner.owns(p_rid)) {
-
- ShapeSW *shape = shape_owner.getornull(p_rid);
-
- while (shape->get_owners().size()) {
- ShapeOwnerSW *so = shape->get_owners().front()->key();
- so->remove_shape(shape);
- }
-
- shape_owner.free(p_rid);
- memdelete(shape);
- } else if (body_owner.owns(p_rid)) {
-
- BodySW *body = body_owner.getornull(p_rid);
-
- /*
- if (body->get_state_query())
- _clear_query(body->get_state_query());
-
- if (body->get_direct_state_query())
- _clear_query(body->get_direct_state_query());
- */
-
- body->set_space(NULL);
-
- while (body->get_shape_count()) {
-
- body->remove_shape(0);
- }
-
- body_owner.free(p_rid);
- memdelete(body);
-
- } else if (area_owner.owns(p_rid)) {
-
- AreaSW *area = area_owner.getornull(p_rid);
-
- /*
- if (area->get_monitor_query())
- _clear_query(area->get_monitor_query());
- */
-
- area->set_space(NULL);
-
- while (area->get_shape_count()) {
-
- area->remove_shape(0);
- }
-
- area_owner.free(p_rid);
- memdelete(area);
- } else if (space_owner.owns(p_rid)) {
-
- SpaceSW *space = space_owner.getornull(p_rid);
-
- while (space->get_objects().size()) {
- CollisionObjectSW *co = (CollisionObjectSW *)space->get_objects().front()->get();
- co->set_space(NULL);
- }
-
- active_spaces.erase(space);
- free(space->get_default_area()->get_self());
- free(space->get_static_global_body());
-
- space_owner.free(p_rid);
- memdelete(space);
- } else if (joint_owner.owns(p_rid)) {
-
- JointSW *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);
-
- } else {
-
- ERR_FAIL_MSG("Invalid ID.");
- }
-};
-
-void PhysicsServerSW::set_active(bool p_active) {
-
- active = p_active;
-};
-
-void PhysicsServerSW::init() {
-
- doing_sync = true;
- last_step = 0.001;
- iterations = 8; // 8?
- stepper = memnew(StepSW);
- direct_state = memnew(PhysicsDirectBodyStateSW);
-};
-
-void PhysicsServerSW::step(real_t p_step) {
-
-#ifndef _3D_DISABLED
-
- if (!active)
- return;
-
- _update_shapes();
-
- doing_sync = false;
-
- last_step = p_step;
- PhysicsDirectBodyStateSW::singleton->step = p_step;
-
- island_count = 0;
- active_objects = 0;
- collision_pairs = 0;
- for (Set<const SpaceSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
-
- stepper->step((SpaceSW *)E->get(), p_step, iterations);
- island_count += E->get()->get_island_count();
- active_objects += E->get()->get_active_objects();
- collision_pairs += E->get()->get_collision_pairs();
- }
-#endif
-}
-
-void PhysicsServerSW::sync(){
-
-};
-
-void PhysicsServerSW::flush_queries() {
-
-#ifndef _3D_DISABLED
-
- if (!active)
- return;
-
- doing_sync = true;
-
- flushing_queries = true;
-
- uint64_t time_beg = OS::get_singleton()->get_ticks_usec();
-
- for (Set<const SpaceSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
-
- SpaceSW *space = (SpaceSW *)E->get();
- space->call_queries();
- }
-
- flushing_queries = false;
-
- if (EngineDebugger::is_profiling("servers")) {
-
- uint64_t total_time[SpaceSW::ELAPSED_TIME_MAX];
- static const char *time_name[SpaceSW::ELAPSED_TIME_MAX] = {
- "integrate_forces",
- "generate_islands",
- "setup_constraints",
- "solve_constraints",
- "integrate_velocities"
- };
-
- for (int i = 0; i < SpaceSW::ELAPSED_TIME_MAX; i++) {
- total_time[i] = 0;
- }
-
- for (Set<const SpaceSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
-
- for (int i = 0; i < SpaceSW::ELAPSED_TIME_MAX; i++) {
- total_time[i] += E->get()->get_elapsed_time(SpaceSW::ElapsedTime(i));
- }
- }
-
- Array values;
- values.resize(SpaceSW::ELAPSED_TIME_MAX * 2);
- for (int i = 0; i < SpaceSW::ELAPSED_TIME_MAX; i++) {
- values[i * 2 + 0] = time_name[i];
- values[i * 2 + 1] = USEC_TO_SEC(total_time[i]);
- }
- values.push_back("flush_queries");
- values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg));
-
- values.push_front("physics");
- EngineDebugger::profiler_add_frame_data("server", values);
- }
-#endif
-};
-
-void PhysicsServerSW::finish() {
-
- memdelete(stepper);
- memdelete(direct_state);
-};
-
-int PhysicsServerSW::get_process_info(ProcessInfo p_info) {
-
- switch (p_info) {
-
- case INFO_ACTIVE_OBJECTS: {
-
- return active_objects;
- } break;
- case INFO_COLLISION_PAIRS: {
- return collision_pairs;
- } break;
- case INFO_ISLAND_COUNT: {
-
- return island_count;
- } break;
- }
-
- return 0;
-}
-
-void PhysicsServerSW::_update_shapes() {
-
- while (pending_shape_update_list.first()) {
- pending_shape_update_list.first()->self()->_shape_changed();
- pending_shape_update_list.remove(pending_shape_update_list.first());
- }
-}
-
-void PhysicsServerSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
-
- CollCbkData *cbk = (CollCbkData *)p_userdata;
-
- if (cbk->max == 0)
- return;
-
- if (cbk->amount == cbk->max) {
- //find least deep
- real_t min_depth = 1e20;
- int min_depth_idx = 0;
- for (int i = 0; i < cbk->amount; i++) {
-
- real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]);
- if (d < min_depth) {
- min_depth = d;
- min_depth_idx = i;
- }
- }
-
- real_t d = p_point_A.distance_squared_to(p_point_B);
- if (d < min_depth)
- return;
- cbk->ptr[min_depth_idx * 2 + 0] = p_point_A;
- cbk->ptr[min_depth_idx * 2 + 1] = p_point_B;
-
- } else {
-
- cbk->ptr[cbk->amount * 2 + 0] = p_point_A;
- cbk->ptr[cbk->amount * 2 + 1] = p_point_B;
- cbk->amount++;
- }
-}
-
-PhysicsServerSW *PhysicsServerSW::singleton = NULL;
-PhysicsServerSW::PhysicsServerSW() {
- singleton = this;
- BroadPhaseSW::create_func = BroadPhaseOctree::_create;
- island_count = 0;
- active_objects = 0;
- collision_pairs = 0;
-
- active = true;
- flushing_queries = false;
-};
-
-PhysicsServerSW::~PhysicsServerSW(){
-
-};
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
deleted file mode 100644
index 459c7688f0..0000000000
--- a/servers/physics/physics_server_sw.h
+++ /dev/null
@@ -1,382 +0,0 @@
-/*************************************************************************/
-/* physics_server_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS_SERVER_SW
-#define PHYSICS_SERVER_SW
-
-#include "core/rid_owner.h"
-#include "joints_sw.h"
-#include "servers/physics_server.h"
-#include "shape_sw.h"
-#include "space_sw.h"
-#include "step_sw.h"
-
-class PhysicsServerSW : public PhysicsServer {
-
- GDCLASS(PhysicsServerSW, PhysicsServer);
-
- friend class PhysicsDirectSpaceStateSW;
- bool active;
- int iterations;
- bool doing_sync;
- real_t last_step;
-
- int island_count;
- int active_objects;
- int collision_pairs;
-
- bool flushing_queries;
-
- StepSW *stepper;
- Set<const SpaceSW *> active_spaces;
-
- PhysicsDirectBodyStateSW *direct_state;
-
- mutable RID_PtrOwner<ShapeSW> shape_owner;
- mutable RID_PtrOwner<SpaceSW> space_owner;
- mutable RID_PtrOwner<AreaSW> area_owner;
- mutable RID_PtrOwner<BodySW> body_owner;
- mutable RID_PtrOwner<JointSW> joint_owner;
-
- //void _clear_query(QuerySW *p_query);
- friend class CollisionObjectSW;
- SelfList<CollisionObjectSW>::List pending_shape_update_list;
- void _update_shapes();
-
-public:
- static PhysicsServerSW *singleton;
-
- 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);
-
- virtual RID shape_create(ShapeType p_shape);
- virtual void shape_set_data(RID p_shape, const Variant &p_data);
- virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
-
- virtual ShapeType shape_get_type(RID p_shape) const;
- virtual Variant shape_get_data(RID p_shape) const;
-
- virtual void shape_set_margin(RID p_shape, real_t p_margin);
- virtual real_t shape_get_margin(RID p_shape) const;
-
- virtual real_t shape_get_custom_solver_bias(RID p_shape) const;
-
- /* SPACE API */
-
- virtual RID space_create();
- virtual void space_set_active(RID p_space, bool p_active);
- virtual bool space_is_active(RID p_space) const;
-
- virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value);
- virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const;
-
- // this function only works on physics process, errors and returns null otherwise
- virtual PhysicsDirectSpaceState *space_get_direct_state(RID p_space);
-
- virtual void space_set_debug_contacts(RID p_space, int p_max_contacts);
- virtual Vector<Vector3> space_get_contacts(RID p_space) const;
- virtual int space_get_contact_count(RID p_space) const;
-
- /* AREA API */
-
- virtual RID area_create();
-
- virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode);
- virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const;
-
- virtual void area_set_space(RID p_area, RID p_space);
- virtual RID area_get_space(RID p_area) const;
-
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
- virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
- virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform);
-
- virtual int area_get_shape_count(RID p_area) const;
- virtual RID area_get_shape(RID p_area, int p_shape_idx) const;
- virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const;
-
- virtual void area_remove_shape(RID p_area, int p_shape_idx);
- virtual void area_clear_shapes(RID p_area);
-
- virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled);
-
- virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id);
- virtual ObjectID area_get_object_instance_id(RID p_area) const;
-
- virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
- virtual void area_set_transform(RID p_area, const Transform &p_transform);
-
- virtual Variant area_get_param(RID p_area, AreaParameter p_param) const;
- virtual Transform area_get_transform(RID p_area) const;
-
- virtual void area_set_ray_pickable(RID p_area, bool p_enable);
- virtual bool area_is_ray_pickable(RID p_area) const;
-
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask);
- virtual void area_set_collision_layer(RID p_area, uint32_t p_layer);
-
- virtual void area_set_monitorable(RID p_area, bool p_monitorable);
-
- virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
- virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
-
- /* BODY API */
-
- // create a body of a given type
- virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false);
-
- virtual void body_set_space(RID p_body, RID p_space);
- virtual RID body_get_space(RID p_body) const;
-
- virtual void body_set_mode(RID p_body, BodyMode p_mode);
- virtual BodyMode body_get_mode(RID p_body) const;
-
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
- virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
- virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform);
-
- virtual int body_get_shape_count(RID p_body) const;
- virtual RID body_get_shape(RID p_body, int p_shape_idx) const;
- virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const;
-
- virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled);
-
- virtual void body_remove_shape(RID p_body, int p_shape_idx);
- virtual void body_clear_shapes(RID p_body);
-
- virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
- virtual ObjectID body_get_object_instance_id(RID p_body) const;
-
- virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable);
- virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const;
-
- virtual void body_set_collision_layer(RID p_body, uint32_t p_layer);
- virtual uint32_t body_get_collision_layer(RID p_body) const;
-
- virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
- virtual uint32_t body_get_collision_mask(RID p_body) const;
-
- virtual void body_set_user_flags(RID p_body, uint32_t p_flags);
- virtual uint32_t body_get_user_flags(RID p_body) const;
-
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
-
- virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
- virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
-
- virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
- virtual Variant body_get_state(RID p_body, BodyState p_state) const;
-
- virtual void body_set_applied_force(RID p_body, const Vector3 &p_force);
- virtual Vector3 body_get_applied_force(RID p_body) const;
-
- virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque);
- virtual Vector3 body_get_applied_torque(RID p_body) const;
-
- virtual void body_add_central_force(RID p_body, const Vector3 &p_force);
- virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos);
- virtual void body_add_torque(RID p_body, const Vector3 &p_torque);
-
- virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse);
- virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse);
- virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse);
- virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity);
-
- virtual void body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock);
- virtual bool body_is_axis_locked(RID p_body, BodyAxis p_axis) const;
-
- virtual void body_add_collision_exception(RID p_body, RID p_body_b);
- virtual void body_remove_collision_exception(RID p_body, RID p_body_b);
- virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions);
-
- virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold);
- virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const;
-
- virtual void body_set_omit_force_integration(RID p_body, bool p_omit);
- virtual bool body_is_omitting_force_integration(RID p_body) const;
-
- virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
- virtual int body_get_max_contacts_reported(RID p_body) const;
-
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant());
-
- virtual void body_set_ray_pickable(RID p_body, bool p_enable);
- virtual bool body_is_ray_pickable(RID p_body) const;
-
- virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true);
- 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, float p_margin = 0.001);
-
- // this function only works on physics process, errors and returns null otherwise
- virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body);
-
- /* SOFT BODY */
-
- virtual RID soft_body_create(bool p_init_sleeping = false) { return RID(); }
-
- virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) {}
-
- virtual void soft_body_set_space(RID p_body, RID p_space) {}
- virtual RID soft_body_get_space(RID p_body) const { return RID(); }
-
- virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {}
- virtual uint32_t soft_body_get_collision_layer(RID p_body) const { return 0; }
-
- virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {}
- virtual uint32_t soft_body_get_collision_mask(RID p_body) const { return 0; }
-
- virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) {}
- virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) {}
- virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {}
-
- virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {}
- virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const { return Variant(); }
-
- virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) {}
- virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const { return Vector3(); }
-
- virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) {}
- virtual bool soft_body_is_ray_pickable(RID p_body) const { return false; }
-
- virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {}
- virtual int soft_body_get_simulation_precision(RID p_body) { return 0; }
-
- virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) {}
- virtual real_t soft_body_get_total_mass(RID p_body) { return 0.; }
-
- virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {}
- virtual real_t soft_body_get_linear_stiffness(RID p_body) { return 0.; }
-
- virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) {}
- virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) { return 0.; }
-
- virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {}
- virtual real_t soft_body_get_volume_stiffness(RID p_body) { return 0.; }
-
- virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {}
- virtual real_t soft_body_get_pressure_coefficient(RID p_body) { return 0.; }
-
- virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {}
- virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) { return 0.; }
-
- virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {}
- virtual real_t soft_body_get_damping_coefficient(RID p_body) { return 0.; }
-
- virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {}
- virtual real_t soft_body_get_drag_coefficient(RID p_body) { return 0.; }
-
- virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) {}
-
- virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {}
- virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) { return Vector3(); }
-
- virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const { return Vector3(); }
-
- virtual void soft_body_remove_all_pinned_points(RID p_body) {}
- virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {}
- virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) { return 0; }
-
- /* JOINT API */
-
- virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B);
-
- virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value);
- virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
-
- virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A);
- virtual Vector3 pin_joint_get_local_a(RID p_joint) const;
-
- virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B);
- virtual Vector3 pin_joint_get_local_b(RID p_joint) const;
-
- virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B);
- 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);
-
- virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value);
- virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const;
-
- virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value);
- virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const;
-
- 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); //reference frame is A
-
- virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value);
- virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const;
-
- 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); //reference frame is A
-
- virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value);
- virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const;
-
- 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); //reference frame is A
-
- virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value);
- virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param);
-
- virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable);
- virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag);
-
- virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) {}
- virtual int generic_6dof_joint_get_precision(RID p_joint) { return 0; }
-
- virtual JointType joint_get_type(RID p_joint) const;
-
- virtual void joint_set_solver_priority(RID p_joint, int p_priority);
- virtual int joint_get_solver_priority(RID p_joint) const;
-
- virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable);
- virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const;
-
- /* MISC */
-
- virtual void free(RID p_rid);
-
- virtual void set_active(bool p_active);
- virtual void init();
- virtual void step(real_t p_step);
- virtual void sync();
- virtual void flush_queries();
- virtual void finish();
-
- virtual bool is_flushing_queries() const { return flushing_queries; }
-
- int get_process_info(ProcessInfo p_info);
-
- PhysicsServerSW();
- ~PhysicsServerSW();
-};
-
-#endif
diff --git a/servers/physics/shape_sw.cpp b/servers/physics/shape_sw.cpp
deleted file mode 100644
index 4a6ed6be58..0000000000
--- a/servers/physics/shape_sw.cpp
+++ /dev/null
@@ -1,1655 +0,0 @@
-/*************************************************************************/
-/* shape_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "shape_sw.h"
-
-#include "core/math/geometry.h"
-#include "core/math/quick_hull.h"
-#include "core/sort_array.h"
-
-#define _POINT_SNAP 0.001953125
-#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002
-#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998
-
-void ShapeSW::configure(const AABB &p_aabb) {
- aabb = p_aabb;
- configured = true;
- for (Map<ShapeOwnerSW *, int>::Element *E = owners.front(); E; E = E->next()) {
- ShapeOwnerSW *co = (ShapeOwnerSW *)E->key();
- co->_shape_changed();
- }
-}
-
-Vector3 ShapeSW::get_support(const Vector3 &p_normal) const {
-
- Vector3 res;
- int amnt;
- get_supports(p_normal, 1, &res, amnt);
- return res;
-}
-
-void ShapeSW::add_owner(ShapeOwnerSW *p_owner) {
-
- Map<ShapeOwnerSW *, int>::Element *E = owners.find(p_owner);
- if (E) {
- E->get()++;
- } else {
- owners[p_owner] = 1;
- }
-}
-
-void ShapeSW::remove_owner(ShapeOwnerSW *p_owner) {
-
- Map<ShapeOwnerSW *, int>::Element *E = owners.find(p_owner);
- ERR_FAIL_COND(!E);
- E->get()--;
- if (E->get() == 0) {
- owners.erase(E);
- }
-}
-
-bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const {
-
- return owners.has(p_owner);
-}
-
-const Map<ShapeOwnerSW *, int> &ShapeSW::get_owners() const {
- return owners;
-}
-
-ShapeSW::ShapeSW() {
-
- custom_bias = 0;
- configured = false;
-}
-
-ShapeSW::~ShapeSW() {
-
- ERR_FAIL_COND(owners.size());
-}
-
-Plane PlaneShapeSW::get_plane() const {
-
- return plane;
-}
-
-void PlaneShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- // gibberish, a plane is infinity
- r_min = -1e7;
- r_max = 1e7;
-}
-
-Vector3 PlaneShapeSW::get_support(const Vector3 &p_normal) const {
-
- return p_normal * 1e15;
-}
-
-bool PlaneShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- bool inters = plane.intersects_segment(p_begin, p_end, &r_result);
- if (inters)
- r_normal = plane.normal;
- return inters;
-}
-
-bool PlaneShapeSW::intersect_point(const Vector3 &p_point) const {
-
- return plane.distance_to(p_point) < 0;
-}
-
-Vector3 PlaneShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- if (plane.is_point_over(p_point)) {
- return plane.project(p_point);
- } else {
- return p_point;
- }
-}
-
-Vector3 PlaneShapeSW::get_moment_of_inertia(real_t p_mass) const {
-
- return Vector3(); //wtf
-}
-
-void PlaneShapeSW::_setup(const Plane &p_plane) {
-
- plane = p_plane;
- configure(AABB(Vector3(-1e4, -1e4, -1e4), Vector3(1e4 * 2, 1e4 * 2, 1e4 * 2)));
-}
-
-void PlaneShapeSW::set_data(const Variant &p_data) {
-
- _setup(p_data);
-}
-
-Variant PlaneShapeSW::get_data() const {
-
- return plane;
-}
-
-PlaneShapeSW::PlaneShapeSW() {
-}
-
-//
-
-real_t RayShapeSW::get_length() const {
-
- return length;
-}
-
-bool RayShapeSW::get_slips_on_slope() const {
- return slips_on_slope;
-}
-
-void RayShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- // don't think this will be even used
- r_min = 0;
- r_max = 1;
-}
-
-Vector3 RayShapeSW::get_support(const Vector3 &p_normal) const {
-
- if (p_normal.z > 0)
- return Vector3(0, 0, length);
- else
- return Vector3(0, 0, 0);
-}
-
-void RayShapeSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
-
- if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
-
- r_amount = 2;
- r_supports[0] = Vector3(0, 0, 0);
- r_supports[1] = Vector3(0, 0, length);
- } else if (p_normal.z > 0) {
- r_amount = 1;
- *r_supports = Vector3(0, 0, length);
- } else {
- r_amount = 1;
- *r_supports = Vector3(0, 0, 0);
- }
-}
-
-bool RayShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- return false; //simply not possible
-}
-
-bool RayShapeSW::intersect_point(const Vector3 &p_point) const {
-
- return false; //simply not possible
-}
-
-Vector3 RayShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- Vector3 s[2] = {
- Vector3(0, 0, 0),
- Vector3(0, 0, length)
- };
-
- return Geometry::get_closest_point_to_segment(p_point, s);
-}
-
-Vector3 RayShapeSW::get_moment_of_inertia(real_t p_mass) const {
-
- return Vector3();
-}
-
-void RayShapeSW::_setup(real_t p_length, bool p_slips_on_slope) {
-
- length = p_length;
- slips_on_slope = p_slips_on_slope;
- configure(AABB(Vector3(0, 0, 0), Vector3(0.1, 0.1, length)));
-}
-
-void RayShapeSW::set_data(const Variant &p_data) {
-
- Dictionary d = p_data;
- _setup(d["length"], d["slips_on_slope"]);
-}
-
-Variant RayShapeSW::get_data() const {
-
- Dictionary d;
- d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
- return d;
-}
-
-RayShapeSW::RayShapeSW() {
-
- length = 1;
- slips_on_slope = false;
-}
-
-/********** SPHERE *************/
-
-real_t SphereShapeSW::get_radius() const {
-
- return radius;
-}
-
-void SphereShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- real_t d = p_normal.dot(p_transform.origin);
-
- // figure out scale at point
- Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
- real_t scale = local_normal.length();
-
- r_min = d - (radius)*scale;
- r_max = d + (radius)*scale;
-}
-
-Vector3 SphereShapeSW::get_support(const Vector3 &p_normal) const {
-
- return p_normal * radius;
-}
-
-void SphereShapeSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
-
- *r_supports = p_normal * radius;
- r_amount = 1;
-}
-
-bool SphereShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- return Geometry::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal);
-}
-
-bool SphereShapeSW::intersect_point(const Vector3 &p_point) const {
-
- return p_point.length() < radius;
-}
-
-Vector3 SphereShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- Vector3 p = p_point;
- float l = p.length();
- if (l < radius)
- return p_point;
- return (p / l) * radius;
-}
-
-Vector3 SphereShapeSW::get_moment_of_inertia(real_t p_mass) const {
-
- real_t s = 0.4 * p_mass * radius * radius;
- return Vector3(s, s, s);
-}
-
-void SphereShapeSW::_setup(real_t p_radius) {
-
- radius = p_radius;
- configure(AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2.0, radius * 2.0, radius * 2.0)));
-}
-
-void SphereShapeSW::set_data(const Variant &p_data) {
-
- _setup(p_data);
-}
-
-Variant SphereShapeSW::get_data() const {
-
- return radius;
-}
-
-SphereShapeSW::SphereShapeSW() {
-
- radius = 0;
-}
-
-/********** BOX *************/
-
-void BoxShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- // no matter the angle, the box is mirrored anyway
- Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
-
- real_t length = local_normal.abs().dot(half_extents);
- real_t distance = p_normal.dot(p_transform.origin);
-
- r_min = distance - length;
- r_max = distance + length;
-}
-
-Vector3 BoxShapeSW::get_support(const Vector3 &p_normal) const {
-
- Vector3 point(
- (p_normal.x < 0) ? -half_extents.x : half_extents.x,
- (p_normal.y < 0) ? -half_extents.y : half_extents.y,
- (p_normal.z < 0) ? -half_extents.z : half_extents.z);
-
- return point;
-}
-
-void BoxShapeSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
-
- static const int next[3] = { 1, 2, 0 };
- static const int next2[3] = { 2, 0, 1 };
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis;
- axis[i] = 1.0;
- real_t dot = p_normal.dot(axis);
- if (Math::abs(dot) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
-
- //Vector3 axis_b;
-
- bool neg = dot < 0;
- r_amount = 4;
-
- Vector3 point;
- point[i] = half_extents[i];
-
- int i_n = next[i];
- int i_n2 = next2[i];
-
- static const real_t sign[4][2] = {
-
- { -1.0, 1.0 },
- { 1.0, 1.0 },
- { 1.0, -1.0 },
- { -1.0, -1.0 },
- };
-
- for (int j = 0; j < 4; j++) {
-
- point[i_n] = sign[j][0] * half_extents[i_n];
- point[i_n2] = sign[j][1] * half_extents[i_n2];
- r_supports[j] = neg ? -point : point;
- }
-
- if (neg) {
- SWAP(r_supports[1], r_supports[2]);
- SWAP(r_supports[0], r_supports[3]);
- }
-
- return;
- }
-
- r_amount = 0;
- }
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 axis;
- axis[i] = 1.0;
-
- if (Math::abs(p_normal.dot(axis)) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
-
- r_amount = 2;
-
- int i_n = next[i];
- int i_n2 = next2[i];
-
- Vector3 point = half_extents;
-
- if (p_normal[i_n] < 0) {
- point[i_n] = -point[i_n];
- }
- if (p_normal[i_n2] < 0) {
- point[i_n2] = -point[i_n2];
- }
-
- r_supports[0] = point;
- point[i] = -point[i];
- r_supports[1] = point;
- return;
- }
- }
- /* USE POINT */
-
- Vector3 point(
- (p_normal.x < 0) ? -half_extents.x : half_extents.x,
- (p_normal.y < 0) ? -half_extents.y : half_extents.y,
- (p_normal.z < 0) ? -half_extents.z : half_extents.z);
-
- r_amount = 1;
- r_supports[0] = point;
-}
-
-bool BoxShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- AABB aabb(-half_extents, half_extents * 2.0);
-
- return aabb.intersects_segment(p_begin, p_end, &r_result, &r_normal);
-}
-
-bool BoxShapeSW::intersect_point(const Vector3 &p_point) const {
-
- return (Math::abs(p_point.x) < half_extents.x && Math::abs(p_point.y) < half_extents.y && Math::abs(p_point.z) < half_extents.z);
-}
-
-Vector3 BoxShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- int outside = 0;
- Vector3 min_point;
-
- for (int i = 0; i < 3; i++) {
-
- if (Math::abs(p_point[i]) > half_extents[i]) {
- outside++;
- if (outside == 1) {
- //use plane if only one side matches
- Vector3 n;
- n[i] = SGN(p_point[i]);
-
- Plane p(n, half_extents[i]);
- min_point = p.project(p_point);
- }
- }
- }
-
- if (!outside)
- return p_point; //it's inside, don't do anything else
-
- if (outside == 1) //if only above one plane, this plane clearly wins
- return min_point;
-
- //check segments
- float min_distance = 1e20;
- Vector3 closest_vertex = half_extents * p_point.sign();
- Vector3 s[2] = {
- closest_vertex,
- closest_vertex
- };
-
- for (int i = 0; i < 3; i++) {
-
- s[1] = closest_vertex;
- s[1][i] = -s[1][i]; //edge
-
- Vector3 closest_edge = Geometry::get_closest_point_to_segment(p_point, s);
-
- float d = p_point.distance_to(closest_edge);
- if (d < min_distance) {
- min_point = closest_edge;
- min_distance = d;
- }
- }
-
- return min_point;
-}
-
-Vector3 BoxShapeSW::get_moment_of_inertia(real_t p_mass) const {
-
- real_t lx = half_extents.x;
- real_t ly = half_extents.y;
- real_t lz = half_extents.z;
-
- return Vector3((p_mass / 3.0) * (ly * ly + lz * lz), (p_mass / 3.0) * (lx * lx + lz * lz), (p_mass / 3.0) * (lx * lx + ly * ly));
-}
-
-void BoxShapeSW::_setup(const Vector3 &p_half_extents) {
-
- half_extents = p_half_extents.abs();
-
- configure(AABB(-half_extents, half_extents * 2));
-}
-
-void BoxShapeSW::set_data(const Variant &p_data) {
-
- _setup(p_data);
-}
-
-Variant BoxShapeSW::get_data() const {
-
- return half_extents;
-}
-
-BoxShapeSW::BoxShapeSW() {
-}
-
-/********** CAPSULE *************/
-
-void CapsuleShapeSW::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;
-
- n *= radius;
- n.z += h * 0.5;
-
- r_max = p_normal.dot(p_transform.xform(n));
- r_min = p_normal.dot(p_transform.xform(-n));
-}
-
-Vector3 CapsuleShapeSW::get_support(const Vector3 &p_normal) const {
-
- Vector3 n = p_normal;
-
- real_t h = (n.z > 0) ? height : -height;
-
- n *= radius;
- n.z += h * 0.5;
- return n;
-}
-
-void CapsuleShapeSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
-
- Vector3 n = p_normal;
-
- real_t d = n.z;
-
- if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
-
- // make it flat
- n.z = 0.0;
- n.normalize();
- n *= radius;
-
- r_amount = 2;
- r_supports[0] = n;
- r_supports[0].z += height * 0.5;
- r_supports[1] = n;
- r_supports[1].z -= height * 0.5;
-
- } else {
-
- real_t h = (d > 0) ? height : -height;
-
- n *= radius;
- n.z += h * 0.5;
- r_amount = 1;
- *r_supports = n;
- }
-}
-
-bool CapsuleShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- Vector3 norm = (p_end - p_begin).normalized();
- real_t min_d = 1e20;
-
- Vector3 res, n;
- bool collision = false;
-
- Vector3 auxres, auxn;
- bool collided;
-
- // test against cylinder and spheres :-|
-
- collided = Geometry::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn);
-
- if (collided) {
- real_t d = norm.dot(auxres);
- if (d < min_d) {
- min_d = d;
- res = auxres;
- n = auxn;
- collision = true;
- }
- }
-
- collided = Geometry::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * 0.5), radius, &auxres, &auxn);
-
- if (collided) {
- real_t d = norm.dot(auxres);
- if (d < min_d) {
- min_d = d;
- res = auxres;
- n = auxn;
- collision = true;
- }
- }
-
- collided = Geometry::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * -0.5), radius, &auxres, &auxn);
-
- if (collided) {
- real_t d = norm.dot(auxres);
-
- if (d < min_d) {
- min_d = d;
- res = auxres;
- n = auxn;
- collision = true;
- }
- }
-
- if (collision) {
-
- r_result = res;
- r_normal = n;
- }
- return collision;
-}
-
-bool CapsuleShapeSW::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;
- } else {
- Vector3 p = p_point;
- p.z = Math::abs(p.z) - height * 0.5;
- return p.length() < radius;
- }
-}
-
-Vector3 CapsuleShapeSW::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 p = Geometry::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 CapsuleShapeSW::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.y * extents.y + extents.y * extents.y));
-}
-
-void CapsuleShapeSW::_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)));
-}
-
-void CapsuleShapeSW::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 CapsuleShapeSW::get_data() const {
-
- Dictionary d;
- d["radius"] = radius;
- d["height"] = height;
- return d;
-}
-
-CapsuleShapeSW::CapsuleShapeSW() {
-
- height = radius = 0;
-}
-
-/********** CONVEX POLYGON *************/
-
-void ConvexPolygonShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- int vertex_count = mesh.vertices.size();
- if (vertex_count == 0)
- return;
-
- const Vector3 *vrts = &mesh.vertices[0];
-
- for (int i = 0; i < vertex_count; i++) {
-
- real_t d = p_normal.dot(p_transform.xform(vrts[i]));
-
- if (i == 0 || d > r_max)
- r_max = d;
- if (i == 0 || d < r_min)
- r_min = d;
- }
-}
-
-Vector3 ConvexPolygonShapeSW::get_support(const Vector3 &p_normal) const {
-
- Vector3 n = p_normal;
-
- int vert_support_idx = -1;
- real_t support_max = 0;
-
- int vertex_count = mesh.vertices.size();
- if (vertex_count == 0)
- return Vector3();
-
- const Vector3 *vrts = &mesh.vertices[0];
-
- for (int i = 0; i < vertex_count; i++) {
-
- real_t d = n.dot(vrts[i]);
-
- if (i == 0 || d > support_max) {
- support_max = d;
- vert_support_idx = i;
- }
- }
-
- return vrts[vert_support_idx];
-}
-
-void ConvexPolygonShapeSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int ec = mesh.edges.size();
-
- const Vector3 *vertices = mesh.vertices.ptr();
- int vc = mesh.vertices.size();
-
- //find vertex first
- real_t max = 0;
- int vtx = 0;
-
- for (int i = 0; i < vc; i++) {
-
- real_t d = p_normal.dot(vertices[i]);
-
- if (i == 0 || d > max) {
- max = d;
- vtx = i;
- }
- }
-
- for (int i = 0; i < fc; i++) {
-
- if (faces[i].plane.normal.dot(p_normal) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
-
- int ic = faces[i].indices.size();
- const int *ind = faces[i].indices.ptr();
-
- bool valid = false;
- for (int j = 0; j < ic; j++) {
- if (ind[j] == vtx) {
- valid = true;
- break;
- }
- }
-
- if (!valid)
- continue;
-
- int m = MIN(p_max, ic);
- for (int j = 0; j < m; j++) {
-
- r_supports[j] = vertices[ind[j]];
- }
- r_amount = m;
- return;
- }
- }
-
- for (int i = 0; i < ec; i++) {
-
- real_t dot = (vertices[edges[i].a] - vertices[edges[i].b]).normalized().dot(p_normal);
- dot = ABS(dot);
- if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD && (edges[i].a == vtx || edges[i].b == vtx)) {
-
- r_amount = 2;
- r_supports[0] = vertices[edges[i].a];
- r_supports[1] = vertices[edges[i].b];
- return;
- }
- }
-
- r_supports[0] = vertices[vtx];
- r_amount = 1;
-}
-
-bool ConvexPolygonShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- const Vector3 *vertices = mesh.vertices.ptr();
-
- Vector3 n = p_end - p_begin;
- real_t min = 1e20;
- bool col = false;
-
- for (int i = 0; i < fc; i++) {
-
- if (faces[i].plane.normal.dot(n) > 0)
- continue; //opposing face
-
- int ic = faces[i].indices.size();
- const int *ind = faces[i].indices.ptr();
-
- for (int j = 1; j < ic - 1; j++) {
-
- Face3 f(vertices[ind[0]], vertices[ind[j]], vertices[ind[j + 1]]);
- Vector3 result;
- if (f.intersects_segment(p_begin, p_end, &result)) {
- real_t d = n.dot(result);
- if (d < min) {
- min = d;
- r_result = result;
- r_normal = faces[i].plane.normal;
- col = true;
- }
-
- break;
- }
- }
- }
-
- return col;
-}
-
-bool ConvexPolygonShapeSW::intersect_point(const Vector3 &p_point) const {
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- for (int i = 0; i < fc; i++) {
-
- if (faces[i].plane.distance_to(p_point) >= 0)
- return false;
- }
-
- return true;
-}
-
-Vector3 ConvexPolygonShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
- const Vector3 *vertices = mesh.vertices.ptr();
-
- bool all_inside = true;
- for (int i = 0; i < fc; i++) {
-
- if (!faces[i].plane.is_point_over(p_point))
- continue;
-
- all_inside = false;
- bool is_inside = true;
- int ic = faces[i].indices.size();
- const int *indices = faces[i].indices.ptr();
-
- for (int j = 0; j < ic; j++) {
-
- Vector3 a = vertices[indices[j]];
- Vector3 b = vertices[indices[(j + 1) % ic]];
- Vector3 n = (a - b).cross(faces[i].plane.normal).normalized();
- if (Plane(a, n).is_point_over(p_point)) {
- is_inside = false;
- break;
- }
- }
-
- if (is_inside) {
- return faces[i].plane.project(p_point);
- }
- }
-
- if (all_inside) {
- return p_point;
- }
-
- float min_distance = 1e20;
- Vector3 min_point;
-
- //check edges
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int ec = mesh.edges.size();
- for (int i = 0; i < ec; i++) {
-
- Vector3 s[2] = {
- vertices[edges[i].a],
- vertices[edges[i].b]
- };
-
- Vector3 closest = Geometry::get_closest_point_to_segment(p_point, s);
- float d = closest.distance_to(p_point);
- if (d < min_distance) {
- min_distance = d;
- min_point = closest;
- }
- }
-
- return min_point;
-}
-
-Vector3 ConvexPolygonShapeSW::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.y * extents.y + extents.y * extents.y));
-}
-
-void ConvexPolygonShapeSW::_setup(const Vector<Vector3> &p_vertices) {
-
- Error err = QuickHull::build(p_vertices, mesh);
- if (err != OK)
- ERR_PRINT("Failed to build QuickHull");
-
- AABB _aabb;
-
- for (int i = 0; i < mesh.vertices.size(); i++) {
-
- if (i == 0)
- _aabb.position = mesh.vertices[i];
- else
- _aabb.expand_to(mesh.vertices[i]);
- }
-
- configure(_aabb);
-}
-
-void ConvexPolygonShapeSW::set_data(const Variant &p_data) {
-
- _setup(p_data);
-}
-
-Variant ConvexPolygonShapeSW::get_data() const {
-
- return mesh.vertices;
-}
-
-ConvexPolygonShapeSW::ConvexPolygonShapeSW() {
-}
-
-/********** FACE POLYGON *************/
-
-void FaceShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- for (int i = 0; i < 3; i++) {
-
- Vector3 v = p_transform.xform(vertex[i]);
- real_t d = p_normal.dot(v);
-
- if (i == 0 || d > r_max)
- r_max = d;
-
- if (i == 0 || d < r_min)
- r_min = d;
- }
-}
-
-Vector3 FaceShapeSW::get_support(const Vector3 &p_normal) const {
-
- int vert_support_idx = -1;
- real_t support_max = 0;
-
- for (int i = 0; i < 3; i++) {
-
- real_t d = p_normal.dot(vertex[i]);
-
- if (i == 0 || d > support_max) {
- support_max = d;
- vert_support_idx = i;
- }
- }
-
- return vertex[vert_support_idx];
-}
-
-void FaceShapeSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
-
- Vector3 n = p_normal;
-
- /** TEST FACE AS SUPPORT **/
- if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
-
- r_amount = 3;
- for (int i = 0; i < 3; i++) {
-
- r_supports[i] = vertex[i];
- }
- return;
- }
-
- /** FIND SUPPORT VERTEX **/
-
- int vert_support_idx = -1;
- real_t support_max = 0;
-
- for (int i = 0; i < 3; i++) {
-
- real_t d = n.dot(vertex[i]);
-
- if (i == 0 || d > support_max) {
- support_max = d;
- vert_support_idx = i;
- }
- }
-
- /** TEST EDGES AS SUPPORT **/
-
- for (int i = 0; i < 3; i++) {
-
- int nx = (i + 1) % 3;
- if (i != vert_support_idx && nx != vert_support_idx)
- continue;
-
- // check if edge is valid as a support
- real_t dot = (vertex[i] - vertex[nx]).normalized().dot(n);
- dot = ABS(dot);
- if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
-
- r_amount = 2;
- r_supports[0] = vertex[i];
- r_supports[1] = vertex[nx];
- return;
- }
- }
-
- r_amount = 1;
- r_supports[0] = vertex[vert_support_idx];
-}
-
-bool FaceShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- bool c = Geometry::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result);
- 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;
- }
- }
-
- return c;
-}
-
-bool FaceShapeSW::intersect_point(const Vector3 &p_point) const {
-
- return false; //face is flat
-}
-
-Vector3 FaceShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- return Face3(vertex[0], vertex[1], vertex[2]).get_closest_point_to(p_point);
-}
-
-Vector3 FaceShapeSW::get_moment_of_inertia(real_t p_mass) const {
-
- return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
-}
-
-FaceShapeSW::FaceShapeSW() {
-
- configure(AABB());
-}
-
-Vector<Vector3> ConcavePolygonShapeSW::get_faces() const {
-
- Vector<Vector3> rfaces;
- rfaces.resize(faces.size() * 3);
-
- for (int i = 0; i < faces.size(); i++) {
-
- Face f = faces.get(i);
-
- for (int j = 0; j < 3; j++) {
-
- rfaces.set(i * 3 + j, vertices.get(f.indices[j]));
- }
- }
-
- return rfaces;
-}
-
-void ConcavePolygonShapeSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- int count = vertices.size();
- if (count == 0) {
- r_min = 0;
- r_max = 0;
- return;
- }
- const Vector3 *vptr = vertices.ptr();
-
- for (int i = 0; i < count; i++) {
-
- real_t d = p_normal.dot(p_transform.xform(vptr[i]));
-
- if (i == 0 || d > r_max)
- r_max = d;
- if (i == 0 || d < r_min)
- r_min = d;
- }
-}
-
-Vector3 ConcavePolygonShapeSW::get_support(const Vector3 &p_normal) const {
-
- int count = vertices.size();
- if (count == 0)
- return Vector3();
-
- const Vector3 *vptr = vertices.ptr();
-
- Vector3 n = p_normal;
-
- int vert_support_idx = -1;
- real_t support_max = 0;
-
- for (int i = 0; i < count; i++) {
-
- real_t d = n.dot(vptr[i]);
-
- if (i == 0 || d > support_max) {
- support_max = d;
- vert_support_idx = i;
- }
- }
-
- return vptr[vert_support_idx];
-}
-
-void ConcavePolygonShapeSW::_cull_segment(int p_idx, _SegmentCullParams *p_params) const {
-
- const BVH *bvh = &p_params->bvh[p_idx];
-
- /*
- if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
- return; //test against whole AABB, which isn't very costly
- */
-
- //printf("addr: %p\n",bvh);
- if (!bvh->aabb.intersects_segment(p_params->from, p_params->to)) {
-
- return;
- }
-
- 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]]
- };
-
- if (Geometry::segment_intersects_triangle(
- p_params->from,
- p_params->to,
- vertices[0],
- vertices[1],
- vertices[2],
- &res)) {
-
- 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) {
-
- p_params->min_d = d;
- p_params->result = res;
- p_params->normal = Plane(vertices[0], vertices[1], vertices[2]).normal;
- p_params->collisions++;
- }
- }
-
- } else {
-
- if (bvh->left >= 0)
- _cull_segment(bvh->left, p_params);
- if (bvh->right >= 0)
- _cull_segment(bvh->right, p_params);
- }
-}
-
-bool ConcavePolygonShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
-
- if (faces.size() == 0)
- return false;
-
- // unlock data
- const Face *fr = faces.ptr();
- const Vector3 *vr = vertices.ptr();
- const BVH *br = bvh.ptr();
-
- _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;
- // cull
- _cull_segment(0, &params);
-
- if (params.collisions > 0) {
-
- r_result = params.result;
- r_normal = params.normal;
- return true;
- } else {
-
- return false;
- }
-}
-
-bool ConcavePolygonShapeSW::intersect_point(const Vector3 &p_point) const {
-
- return false; //face is flat
-}
-
-Vector3 ConcavePolygonShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- return Vector3();
-}
-
-void ConcavePolygonShapeSW::_cull(int p_idx, _CullParams *p_params) const {
-
- const BVH *bvh = &p_params->bvh[p_idx];
-
- if (!p_params->aabb.intersects(bvh->aabb))
- return;
-
- if (bvh->face_index >= 0) {
-
- const Face *f = &p_params->faces[bvh->face_index];
- FaceShapeSW *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]];
- p_params->callback(p_params->userdata, face);
-
- } else {
-
- if (bvh->left >= 0) {
-
- _cull(bvh->left, p_params);
- }
-
- if (bvh->right >= 0) {
-
- _cull(bvh->right, p_params);
- }
- }
-}
-
-void ConcavePolygonShapeSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
-
- // make matrix local to concave
- if (faces.size() == 0)
- return;
-
- AABB local_aabb = p_local_aabb;
-
- // unlock data
- const Face *fr = faces.ptr();
- const Vector3 *vr = vertices.ptr();
- const BVH *br = bvh.ptr();
-
- FaceShapeSW face; // use this to send in the callback
-
- _CullParams params;
- params.aabb = local_aabb;
- params.face = &face;
- params.faces = fr;
- params.vertices = vr;
- params.bvh = br;
- params.callback = p_callback;
- params.userdata = p_userdata;
-
- // cull
- _cull(0, &params);
-}
-
-Vector3 ConcavePolygonShapeSW::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.y * extents.y + extents.y * extents.y));
-}
-
-struct _VolumeSW_BVH_Element {
-
- AABB aabb;
- Vector3 center;
- int face_index;
-};
-
-struct _VolumeSW_BVH_CompareX {
-
- _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const {
-
- return a.center.x < b.center.x;
- }
-};
-
-struct _VolumeSW_BVH_CompareY {
-
- _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const {
-
- return a.center.y < b.center.y;
- }
-};
-
-struct _VolumeSW_BVH_CompareZ {
-
- _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const {
-
- return a.center.z < b.center.z;
- }
-};
-
-struct _VolumeSW_BVH {
-
- AABB aabb;
- _VolumeSW_BVH *left;
- _VolumeSW_BVH *right;
-
- int face_index;
-};
-
-_VolumeSW_BVH *_volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements, int p_size, int &count) {
-
- _VolumeSW_BVH *bvh = memnew(_VolumeSW_BVH);
-
- if (p_size == 1) {
- //leaf
- bvh->aabb = p_elements[0].aabb;
- bvh->left = NULL;
- bvh->right = NULL;
- bvh->face_index = p_elements->face_index;
- count++;
- return bvh;
- } else {
-
- bvh->face_index = -1;
- }
-
- AABB aabb;
- for (int i = 0; i < p_size; i++) {
-
- if (i == 0)
- aabb = p_elements[i].aabb;
- else
- aabb.merge_with(p_elements[i].aabb);
- }
- bvh->aabb = aabb;
- switch (aabb.get_longest_axis_index()) {
-
- case 0: {
-
- SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareX> sort_x;
- sort_x.sort(p_elements, p_size);
-
- } break;
- case 1: {
-
- SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareY> sort_y;
- sort_y.sort(p_elements, p_size);
- } break;
- case 2: {
-
- SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareZ> sort_z;
- sort_z.sort(p_elements, p_size);
- } break;
- }
-
- int split = p_size / 2;
- bvh->left = _volume_sw_build_bvh(p_elements, split, count);
- bvh->right = _volume_sw_build_bvh(&p_elements[split], p_size - split, count);
-
- //printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
- count++;
- return bvh;
-}
-
-void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx) {
-
- int idx = p_idx;
-
- p_bvh_array[idx].aabb = p_bvh_tree->aabb;
- p_bvh_array[idx].face_index = p_bvh_tree->face_index;
- //printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
-
- if (p_bvh_tree->left) {
- p_bvh_array[idx].left = ++p_idx;
- _fill_bvh(p_bvh_tree->left, p_bvh_array, p_idx);
-
- } else {
-
- p_bvh_array[p_idx].left = -1;
- }
-
- if (p_bvh_tree->right) {
- p_bvh_array[idx].right = ++p_idx;
- _fill_bvh(p_bvh_tree->right, p_bvh_array, p_idx);
-
- } else {
-
- p_bvh_array[p_idx].right = -1;
- }
-
- memdelete(p_bvh_tree);
-}
-
-void ConcavePolygonShapeSW::_setup(Vector<Vector3> p_faces) {
-
- int src_face_count = p_faces.size();
- if (src_face_count == 0) {
- configure(AABB());
- return;
- }
- ERR_FAIL_COND(src_face_count % 3);
- src_face_count /= 3;
-
- const Vector3 *facesr = p_faces.ptr();
-
- Vector<_VolumeSW_BVH_Element> bvh_array;
- bvh_array.resize(src_face_count);
-
- _VolumeSW_BVH_Element *bvh_arrayw = bvh_array.ptrw();
-
- faces.resize(src_face_count);
- Face *facesw = faces.ptrw();
-
- vertices.resize(src_face_count * 3);
-
- Vector3 *verticesw = vertices.ptrw();
-
- AABB _aabb;
-
- for (int i = 0; i < src_face_count; i++) {
-
- Face3 face(facesr[i * 3 + 0], facesr[i * 3 + 1], facesr[i * 3 + 2]);
-
- bvh_arrayw[i].aabb = face.get_aabb();
- bvh_arrayw[i].center = bvh_arrayw[i].aabb.position + bvh_arrayw[i].aabb.size * 0.5;
- bvh_arrayw[i].face_index = i;
- facesw[i].indices[0] = i * 3 + 0;
- facesw[i].indices[1] = i * 3 + 1;
- facesw[i].indices[2] = i * 3 + 2;
- facesw[i].normal = face.get_plane().normal;
- verticesw[i * 3 + 0] = face.vertex[0];
- verticesw[i * 3 + 1] = face.vertex[1];
- verticesw[i * 3 + 2] = face.vertex[2];
- if (i == 0)
- _aabb = bvh_arrayw[i].aabb;
- else
- _aabb.merge_with(bvh_arrayw[i].aabb);
- }
-
- int count = 0;
- _VolumeSW_BVH *bvh_tree = _volume_sw_build_bvh(bvh_arrayw, src_face_count, count);
-
- bvh.resize(count + 1);
-
- BVH *bvh_arrayw2 = bvh.ptrw();
-
- int idx = 0;
- _fill_bvh(bvh_tree, bvh_arrayw2, idx);
-
- configure(_aabb); // this type of shape has no margin
-}
-
-void ConcavePolygonShapeSW::set_data(const Variant &p_data) {
-
- _setup(p_data);
-}
-
-Variant ConcavePolygonShapeSW::get_data() const {
-
- return get_faces();
-}
-
-ConcavePolygonShapeSW::ConcavePolygonShapeSW() {
-}
-
-/* HEIGHT MAP SHAPE */
-
-Vector<real_t> HeightMapShapeSW::get_heights() const {
-
- return heights;
-}
-int HeightMapShapeSW::get_width() const {
-
- return width;
-}
-int HeightMapShapeSW::get_depth() const {
-
- return depth;
-}
-real_t HeightMapShapeSW::get_cell_size() const {
-
- return cell_size;
-}
-
-void HeightMapShapeSW::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);
-}
-
-Vector3 HeightMapShapeSW::get_support(const Vector3 &p_normal) const {
-
- //not very useful, but not very used either
- return get_aabb().get_support(p_normal);
-}
-
-bool HeightMapShapeSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
-
- return false;
-}
-
-bool HeightMapShapeSW::intersect_point(const Vector3 &p_point) const {
- return false;
-}
-
-Vector3 HeightMapShapeSW::get_closest_point_to(const Vector3 &p_point) const {
-
- return Vector3();
-}
-
-void HeightMapShapeSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
-}
-
-Vector3 HeightMapShapeSW::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.y * extents.y + extents.y * extents.y));
-}
-
-void HeightMapShapeSW::_setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size) {
-
- heights = p_heights;
- width = p_width;
- depth = p_depth;
- cell_size = p_cell_size;
-
- const real_t *r = heights.ptr();
-
- AABB aabb;
-
- for (int i = 0; i < depth; i++) {
-
- for (int j = 0; j < width; j++) {
-
- real_t h = r[i * width + j];
-
- Vector3 pos(j * cell_size, h, i * cell_size);
- if (i == 0 || j == 0)
- aabb.position = pos;
- else
- aabb.expand_to(pos);
- }
- }
-
- configure(aabb);
-}
-
-void HeightMapShapeSW::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);
-}
-
-Variant HeightMapShapeSW::get_data() const {
-
- ERR_FAIL_V(Variant());
-}
-
-HeightMapShapeSW::HeightMapShapeSW() {
-
- width = 0;
- depth = 0;
- cell_size = 0;
-}
diff --git a/servers/physics/shape_sw.h b/servers/physics/shape_sw.h
deleted file mode 100644
index eaae64be66..0000000000
--- a/servers/physics/shape_sw.h
+++ /dev/null
@@ -1,470 +0,0 @@
-/*************************************************************************/
-/* shape_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SHAPE_SW_H
-#define SHAPE_SW_H
-
-#include "core/math/geometry.h"
-#include "servers/physics_server.h"
-/*
-
-SHAPE_LINE, ///< plane:"plane"
-SHAPE_SEGMENT, ///< real_t:"length"
-SHAPE_CIRCLE, ///< real_t:"radius"
-SHAPE_RECTANGLE, ///< vec3:"extents"
-SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
-SHAPE_CONCAVE_POLYGON, ///< Vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
-SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
-
-*/
-
-class ShapeSW;
-
-class ShapeOwnerSW {
-public:
- virtual void _shape_changed() = 0;
- virtual void remove_shape(ShapeSW *p_shape) = 0;
-
- virtual ~ShapeOwnerSW() {}
-};
-
-class ShapeSW {
-
- RID self;
- AABB aabb;
- bool configured;
- real_t custom_bias;
-
- Map<ShapeOwnerSW *, int> owners;
-
-protected:
- void configure(const AABB &p_aabb);
-
-public:
- enum {
- MAX_SUPPORTS = 8
- };
-
- virtual real_t get_area() const { return aabb.get_area(); }
-
- _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
- _FORCE_INLINE_ RID get_self() const { return self; }
-
- virtual PhysicsServer::ShapeType get_type() const = 0;
-
- _FORCE_INLINE_ 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 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;
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const = 0;
-
- virtual void set_data(const Variant &p_data) = 0;
- virtual Variant get_data() const = 0;
-
- _FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias = p_bias; }
- _FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; }
-
- void add_owner(ShapeOwnerSW *p_owner);
- void remove_owner(ShapeOwnerSW *p_owner);
- bool is_owner(ShapeOwnerSW *p_owner) const;
- const Map<ShapeOwnerSW *, int> &get_owners() const;
-
- ShapeSW();
- virtual ~ShapeSW();
-};
-
-class ConcaveShapeSW : public ShapeSW {
-
-public:
- virtual bool is_concave() const { return true; }
- typedef void (*Callback)(void *p_userdata, ShapeSW *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 cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
-
- ConcaveShapeSW() {}
-};
-
-class PlaneShapeSW : public ShapeSW {
-
- Plane plane;
-
- void _setup(const Plane &p_plane);
-
-public:
- Plane get_plane() const;
-
- virtual real_t get_area() const { return Math_INF; }
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::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 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;
-
- PlaneShapeSW();
-};
-
-class RayShapeSW : public ShapeSW {
-
- real_t length;
- bool slips_on_slope;
-
- void _setup(real_t p_length, bool p_slips_on_slope);
-
-public:
- real_t get_length() const;
- bool get_slips_on_slope() const;
-
- virtual real_t get_area() const { return 0.0; }
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::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 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;
-
- RayShapeSW();
-};
-
-class SphereShapeSW : public ShapeSW {
-
- real_t radius;
-
- void _setup(real_t p_radius);
-
-public:
- real_t get_radius() const;
-
- virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius; }
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_SPHERE; }
-
- 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 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;
-
- SphereShapeSW();
-};
-
-class BoxShapeSW : public ShapeSW {
-
- Vector3 half_extents;
- void _setup(const Vector3 &p_half_extents);
-
-public:
- _FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; }
- virtual real_t get_area() const { return 8 * half_extents.x * half_extents.y * half_extents.z; }
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_BOX; }
-
- 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 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;
-
- BoxShapeSW();
-};
-
-class CapsuleShapeSW : public ShapeSW {
-
- 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 PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CAPSULE; }
-
- 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 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;
-
- CapsuleShapeSW();
-};
-
-struct ConvexPolygonShapeSW : public ShapeSW {
-
- Geometry::MeshData mesh;
-
- void _setup(const Vector<Vector3> &p_vertices);
-
-public:
- const Geometry::MeshData &get_mesh() const { return mesh; }
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONVEX_POLYGON; }
-
- 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 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;
-
- ConvexPolygonShapeSW();
-};
-
-struct _VolumeSW_BVH;
-struct FaceShapeSW;
-
-struct ConcavePolygonShapeSW : public ConcaveShapeSW {
- // always a trimesh
-
- struct Face {
-
- Vector3 normal;
- int indices[3];
- };
-
- Vector<Face> faces;
- Vector<Vector3> vertices;
-
- struct BVH {
-
- AABB aabb;
- int left;
- int right;
-
- int face_index;
- };
-
- Vector<BVH> bvh;
-
- struct _CullParams {
-
- AABB aabb;
- Callback callback;
- void *userdata;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
- FaceShapeSW *face;
- };
-
- struct _SegmentCullParams {
-
- Vector3 from;
- Vector3 to;
- const Face *faces;
- const Vector3 *vertices;
- const BVH *bvh;
- Vector3 dir;
-
- Vector3 result;
- Vector3 normal;
- real_t min_d;
- int collisions;
- };
-
- 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);
-
-public:
- Vector<Vector3> get_faces() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONCAVE_POLYGON; }
-
- 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 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 void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) 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;
-
- ConcavePolygonShapeSW();
-};
-
-struct HeightMapShapeSW : public ConcaveShapeSW {
-
- Vector<real_t> heights;
- int width;
- int depth;
- real_t cell_size;
-
- //void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
- //void _cull(int p_idx,_CullParams *p_params) const;
-
- void _setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size);
-
-public:
- Vector<real_t> get_heights() const;
- int get_width() const;
- int get_depth() const;
- real_t get_cell_size() const;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_HEIGHTMAP; }
-
- 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 bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, 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 void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) 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;
-
- HeightMapShapeSW();
-};
-
-//used internally
-struct FaceShapeSW : public ShapeSW {
-
- Vector3 normal; //cache
- Vector3 vertex[3];
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONCAVE_POLYGON; }
-
- const Vector3 &get_vertex(int p_idx) const { return vertex[p_idx]; }
-
- 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;
- 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;
-
- Vector3 get_moment_of_inertia(real_t p_mass) const;
-
- virtual void set_data(const Variant &p_data) {}
- virtual Variant get_data() const { return Variant(); }
-
- FaceShapeSW();
-};
-
-struct MotionShapeSW : public ShapeSW {
-
- ShapeSW *shape;
- Vector3 motion;
-
- virtual PhysicsServer::ShapeType get_type() const { return PhysicsServer::SHAPE_CONVEX_POLYGON; }
-
- void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
-
- Vector3 cast = p_transform.basis.xform(motion);
- real_t mina, maxa;
- real_t minb, maxb;
- Transform ofsb = p_transform;
- ofsb.origin += cast;
- shape->project_range(p_normal, p_transform, mina, maxa);
- shape->project_range(p_normal, ofsb, minb, maxb);
- r_min = MIN(mina, minb);
- r_max = MAX(maxa, maxb);
- }
-
- Vector3 get_support(const Vector3 &p_normal) const {
-
- Vector3 support = shape->get_support(p_normal);
- if (p_normal.dot(motion) > 0) {
- support += motion;
- }
- return support;
- }
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) 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; }
-
- 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(); }
-
- MotionShapeSW() { configure(AABB()); }
-};
-
-#endif // SHAPE_SW_H
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
deleted file mode 100644
index 110520db5a..0000000000
--- a/servers/physics/space_sw.cpp
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*************************************************************************/
-/* space_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "space_sw.h"
-
-#include "collision_solver_sw.h"
-#include "core/project_settings.h"
-#include "physics_server_sw.h"
-
-_FORCE_INLINE_ static bool _can_collide_with(CollisionObjectSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- if (!(p_object->get_collision_layer() & p_collision_mask)) {
- return false;
- }
-
- if (p_object->get_type() == CollisionObjectSW::TYPE_AREA && !p_collide_with_areas)
- return false;
-
- if (p_object->get_type() == CollisionObjectSW::TYPE_BODY && !p_collide_with_bodies)
- return false;
-
- return true;
-}
-
-int PhysicsDirectSpaceStateSW::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- ERR_FAIL_COND_V(space->locked, false);
- int amount = space->broadphase->cull_point(p_point, space->intersection_query_results, SpaceSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
- int cc = 0;
-
- //Transform ai = p_xform.affine_inverse();
-
- for (int i = 0; i < amount; i++) {
-
- if (cc >= p_result_max)
- break;
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
- continue;
-
- //area can't be picked by ray (default)
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self()))
- continue;
-
- const CollisionObjectSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
-
- Transform inv_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
- inv_xform.affine_invert();
-
- if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_point)))
- continue;
-
- r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id.is_valid())
- r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
- else
- r_results[cc].collider = NULL;
- r_results[cc].rid = col_obj->get_self();
- r_results[cc].shape = shape_idx;
-
- cc++;
- }
-
- return cc;
-}
-
-bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_ray) {
-
- ERR_FAIL_COND_V(space->locked, false);
-
- Vector3 begin, end;
- Vector3 normal;
- begin = p_from;
- end = p_to;
- normal = (end - begin).normalized();
-
- int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, SpaceSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- //todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
-
- bool collided = false;
- Vector3 res_point, res_normal;
- int res_shape;
- const CollisionObjectSW *res_obj;
- real_t min_d = 1e10;
-
- for (int i = 0; i < amount; i++) {
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
- continue;
-
- if (p_pick_ray && !(space->intersection_query_results[i]->is_ray_pickable()))
- continue;
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self()))
- continue;
-
- const CollisionObjectSW *col_obj = space->intersection_query_results[i];
-
- int shape_idx = space->intersection_query_subindex_results[i];
- Transform inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();
-
- Vector3 local_from = inv_xform.xform(begin);
- Vector3 local_to = inv_xform.xform(end);
-
- const ShapeSW *shape = col_obj->get_shape(shape_idx);
-
- Vector3 shape_point, shape_normal;
-
- if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
-
- Transform xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
- shape_point = xform.xform(shape_point);
-
- real_t ld = normal.dot(shape_point);
-
- if (ld < min_d) {
-
- min_d = ld;
- res_point = shape_point;
- res_normal = inv_xform.basis.xform_inv(shape_normal).normalized();
- res_shape = shape_idx;
- res_obj = col_obj;
- collided = true;
- }
- }
- }
-
- if (!collided)
- return false;
-
- r_result.collider_id = res_obj->get_instance_id();
- if (r_result.collider_id.is_valid())
- r_result.collider = ObjectDB::get_instance(r_result.collider_id);
- else
- r_result.collider = NULL;
- r_result.normal = res_normal;
- r_result.position = res_point;
- r_result.rid = res_obj->get_self();
- r_result.shape = res_shape;
-
- return true;
-}
-
-int PhysicsDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- if (p_result_max <= 0)
- return 0;
-
- ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
-
- AABB aabb = p_xform.xform(shape->get_aabb());
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, SpaceSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- int cc = 0;
-
- //Transform ai = p_xform.affine_inverse();
-
- for (int i = 0; i < amount; i++) {
-
- if (cc >= p_result_max)
- break;
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
- continue;
-
- //area can't be picked by ray (default)
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self()))
- continue;
-
- const CollisionObjectSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
-
- if (!CollisionSolverSW::solve_static(shape, p_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), NULL, NULL, NULL, p_margin, 0))
- continue;
-
- if (r_results) {
- r_results[cc].collider_id = col_obj->get_instance_id();
- if (r_results[cc].collider_id.is_valid())
- r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
- else
- r_results[cc].collider = NULL;
- r_results[cc].rid = col_obj->get_self();
- r_results[cc].shape = shape_idx;
- }
-
- cc++;
- }
-
- return cc;
-}
-
-bool PhysicsDirectSpaceStateSW::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) {
-
- ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, false);
-
- AABB aabb = p_xform.xform(shape->get_aabb());
- aabb = aabb.merge(AABB(aabb.position + p_motion, aabb.size)); //motion
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, SpaceSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- real_t best_safe = 1;
- real_t best_unsafe = 1;
-
- Transform xform_inv = p_xform.affine_inverse();
- MotionShapeSW mshape;
- mshape.shape = shape;
- mshape.motion = xform_inv.basis.xform(p_motion);
-
- bool best_first = true;
-
- Vector3 closest_A, closest_B;
-
- for (int i = 0; i < amount; i++) {
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
- continue;
-
- if (p_exclude.has(space->intersection_query_results[i]->get_self()))
- continue; //ignore excluded
-
- const CollisionObjectSW *col_obj = space->intersection_query_results[i];
- int shape_idx = space->intersection_query_subindex_results[i];
-
- Vector3 point_A, point_B;
- Vector3 sep_axis = p_motion.normalized();
-
- 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 (CollisionSolverSW::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
- continue;
- }
-
- //test initial overlap
- sep_axis = p_motion.normalized();
-
- if (!CollisionSolverSW::solve_distance(shape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
- return false;
- }
-
- //just do kinematic solving
- real_t low = 0;
- real_t hi = 1;
- Vector3 mnormal = p_motion.normalized();
-
- for (int j = 0; j < 8; j++) { //steps should be customizable..
-
- real_t ofs = (low + hi) * 0.5;
-
- Vector3 sep = mnormal; //important optimization for this to work fast enough
-
- mshape.motion = xform_inv.basis.xform(p_motion * ofs);
-
- Vector3 lA, lB;
-
- bool collided = !CollisionSolverSW::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, aabb, &sep);
-
- if (collided) {
-
- hi = ofs;
- } else {
-
- point_A = lA;
- point_B = lB;
- low = ofs;
- }
- }
-
- if (low < best_safe) {
- best_first = true; //force reset
- best_safe = low;
- best_unsafe = hi;
- }
-
- if (r_info && (best_first || (point_A.distance_squared_to(point_B) < closest_A.distance_squared_to(closest_B) && low <= best_safe))) {
- closest_A = point_A;
- closest_B = point_B;
- r_info->collider_id = col_obj->get_instance_id();
- r_info->rid = col_obj->get_self();
- r_info->shape = shape_idx;
- r_info->point = closest_B;
- r_info->normal = (closest_A - closest_B).normalized();
- best_first = false;
- if (col_obj->get_type() == CollisionObjectSW::TYPE_BODY) {
- const BodySW *body = static_cast<const BodySW *>(col_obj);
- r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - closest_B);
- }
- }
- }
-
- p_closest_safe = best_safe;
- p_closest_unsafe = best_unsafe;
-
- return true;
-}
-
-bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- if (p_result_max <= 0)
- return 0;
-
- ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
-
- AABB aabb = p_shape_xform.xform(shape->get_aabb());
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, SpaceSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- bool collided = false;
- r_result_count = 0;
-
- PhysicsServerSW::CollCbkData cbk;
- cbk.max = p_result_max;
- cbk.amount = 0;
- cbk.ptr = r_results;
- CollisionSolverSW::CallbackResult cbkres = PhysicsServerSW::_shape_col_cbk;
-
- PhysicsServerSW::CollCbkData *cbkptr = &cbk;
-
- for (int i = 0; i < amount; i++) {
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
- continue;
-
- const CollisionObjectSW *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;
- }
-
- if (CollisionSolverSW::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, NULL, p_margin)) {
- collided = true;
- }
- }
-
- r_result_count = cbk.amount;
-
- return collided;
-}
-
-struct _RestCallbackData {
-
- const CollisionObjectSW *object;
- const CollisionObjectSW *best_object;
- int shape;
- int best_shape;
- Vector3 best_contact;
- Vector3 best_normal;
- real_t best_len;
- real_t min_allowed_depth;
-};
-
-static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
-
- _RestCallbackData *rd = (_RestCallbackData *)p_userdata;
-
- Vector3 contact_rel = p_point_B - p_point_A;
- real_t len = contact_rel.length();
- if (len < rd->min_allowed_depth)
- return;
- if (len <= rd->best_len)
- return;
-
- rd->best_len = len;
- rd->best_contact = p_point_B;
- rd->best_normal = contact_rel / len;
- rd->best_object = rd->object;
- rd->best_shape = rd->shape;
-}
-bool PhysicsDirectSpaceStateSW::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) {
-
- ShapeSW *shape = static_cast<PhysicsServerSW *>(PhysicsServer::get_singleton())->shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
-
- AABB aabb = p_shape_xform.xform(shape->get_aabb());
- aabb = aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, SpaceSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
-
- _RestCallbackData rcd;
- rcd.best_len = 0;
- rcd.best_object = NULL;
- rcd.best_shape = 0;
- rcd.min_allowed_depth = space->test_motion_min_contact_depth;
-
- for (int i = 0; i < amount; i++) {
-
- if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
- continue;
-
- const CollisionObjectSW *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;
-
- rcd.object = col_obj;
- rcd.shape = shape_idx;
- bool sc = CollisionSolverSW::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, NULL, p_margin);
- if (!sc)
- continue;
- }
-
- if (rcd.best_len == 0 || !rcd.best_object)
- return false;
-
- r_info->collider_id = rcd.best_object->get_instance_id();
- r_info->shape = rcd.best_shape;
- r_info->normal = rcd.best_normal;
- r_info->point = rcd.best_contact;
- r_info->rid = rcd.best_object->get_self();
- if (rcd.best_object->get_type() == CollisionObjectSW::TYPE_BODY) {
-
- const BodySW *body = static_cast<const BodySW *>(rcd.best_object);
- r_info->linear_velocity = body->get_linear_velocity() +
- (body->get_angular_velocity()).cross(body->get_transform().origin - rcd.best_contact); // * mPos);
-
- } else {
- r_info->linear_velocity = Vector3();
- }
-
- return true;
-}
-
-Vector3 PhysicsDirectSpaceStateSW::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const {
-
- CollisionObjectSW *obj = PhysicsServerSW::singleton->area_owner.getornull(p_object);
- if (!obj) {
- obj = PhysicsServerSW::singleton->body_owner.getornull(p_object);
- }
- ERR_FAIL_COND_V(!obj, Vector3());
-
- ERR_FAIL_COND_V(obj->get_space() != space, Vector3());
-
- float min_distance = 1e20;
- Vector3 min_point;
-
- bool shapes_found = false;
-
- for (int i = 0; i < obj->get_shape_count(); i++) {
-
- if (obj->is_shape_set_as_disabled(i))
- continue;
-
- Transform shape_xform = obj->get_transform() * obj->get_shape_transform(i);
- ShapeSW *shape = obj->get_shape(i);
-
- Vector3 point = shape->get_closest_point_to(shape_xform.affine_inverse().xform(p_point));
- point = shape_xform.xform(point);
-
- float dist = point.distance_to(p_point);
- if (dist < min_distance) {
- min_distance = dist;
- min_point = point;
- }
- shapes_found = true;
- }
-
- if (!shapes_found) {
- return obj->get_transform().origin; //no shapes found, use distance to origin.
- } else {
- return min_point;
- }
-}
-
-PhysicsDirectSpaceStateSW::PhysicsDirectSpaceStateSW() {
-
- space = NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-int SpaceSW::_cull_aabb_for_body(BodySW *p_body, const AABB &p_aabb) {
-
- int amount = broadphase->cull_aabb(p_aabb, intersection_query_results, INTERSECTION_QUERY_MAX, intersection_query_subindex_results);
-
- for (int i = 0; i < amount; i++) {
-
- bool keep = true;
-
- if (intersection_query_results[i] == p_body)
- keep = false;
- else if (intersection_query_results[i]->get_type() == CollisionObjectSW::TYPE_AREA)
- keep = false;
- else if ((static_cast<BodySW *>(intersection_query_results[i])->test_collision_mask(p_body)) == 0)
- keep = false;
- else if (static_cast<BodySW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self()))
- keep = false;
- else if (static_cast<BodySW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i]))
- keep = false;
-
- if (!keep) {
-
- if (i < amount - 1) {
- SWAP(intersection_query_results[i], intersection_query_results[amount - 1]);
- SWAP(intersection_query_subindex_results[i], intersection_query_subindex_results[amount - 1]);
- }
-
- amount--;
- i--;
- }
- }
-
- return amount;
-}
-
-int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, real_t p_margin) {
-
- AABB body_aabb;
-
- bool shapes_found = false;
-
- for (int i = 0; i < p_body->get_shape_count(); i++) {
-
- if (p_body->is_shape_set_as_disabled(i))
- continue;
-
- if (!shapes_found) {
- body_aabb = p_body->get_shape_aabb(i);
- shapes_found = true;
- } else {
- body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
- }
- }
-
- if (!shapes_found) {
- return 0;
- }
- // Undo the currently transform the physics server is aware of and apply the provided one
- body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_margin);
-
- Transform body_transform = p_transform;
-
- for (int i = 0; i < p_result_max; i++) {
- //reset results
- r_results[i].collision_depth = 0;
- }
-
- int rays_found = 0;
-
- {
- // raycast AND separate
-
- const int max_results = 32;
- int recover_attempts = 4;
- Vector3 sr[max_results * 2];
- PhysicsServerSW::CollCbkData cbk;
- cbk.max = max_results;
- PhysicsServerSW::CollCbkData *cbkptr = &cbk;
- CollisionSolverSW::CallbackResult cbkres = PhysicsServerSW::_shape_col_cbk;
-
- do {
-
- Vector3 recover_motion;
-
- bool collided = false;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
- if (p_body->is_shape_set_as_disabled(j))
- continue;
-
- ShapeSW *body_shape = p_body->get_shape(j);
-
- if (body_shape->get_type() != PhysicsServer::SHAPE_RAY)
- continue;
-
- Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
-
- for (int i = 0; i < amount; i++) {
-
- const CollisionObjectSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- cbk.amount = 0;
- cbk.ptr = sr;
-
- if (CollisionObjectSW::TYPE_BODY == col_obj->get_type()) {
- const BodySW *b = static_cast<const BodySW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer::BODY_MODE_STATIC != b->get_mode() && PhysicsServer::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- ShapeSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolverSW::solve_static(body_shape, body_shape_xform, against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, NULL, p_margin)) {
- if (cbk.amount > 0) {
- collided = true;
- }
-
- int ray_index = -1; //reuse shape
- for (int k = 0; k < rays_found; k++) {
- if (r_results[k].collision_local_shape == j) {
- ray_index = k;
- }
- }
-
- if (ray_index == -1 && rays_found < p_result_max) {
- ray_index = rays_found;
- rays_found++;
- }
-
- if (ray_index != -1) {
- PhysicsServer::SeparationResult &result = r_results[ray_index];
-
- for (int k = 0; k < cbk.amount; k++) {
- Vector3 a = sr[k * 2 + 0];
- Vector3 b = sr[k * 2 + 1];
-
- recover_motion += (b - a) * 0.4;
-
- float depth = a.distance_to(b);
- if (depth > result.collision_depth) {
-
- result.collision_depth = depth;
- result.collision_point = b;
- result.collision_normal = (b - a).normalized();
- result.collision_local_shape = j;
- result.collider = col_obj->get_self();
- result.collider_id = col_obj->get_instance_id();
- result.collider_shape = shape_idx;
- //result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
- if (col_obj->get_type() == CollisionObjectSW::TYPE_BODY) {
- BodySW *body = (BodySW *)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);
- }
- }
- }
- }
- }
- }
- }
-
- if (!collided || recover_motion == Vector3()) {
- break;
- }
-
- body_transform.origin += recover_motion;
- body_aabb.position += recover_motion;
-
- recover_attempts--;
- } while (recover_attempts);
- }
-
- //optimize results (remove non colliding)
- for (int i = 0; i < rays_found; i++) {
- if (r_results[i].collision_depth == 0) {
- rays_found--;
- SWAP(r_results[i], r_results[rays_found]);
- }
- }
-
- r_recover_motion = body_transform.origin - p_transform.origin;
- return rays_found;
-}
-
-bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes) {
-
- //give me back regular physics engine logic
- //this is madness
- //and most people using this function will think
- //what it does is simpler than using physics
- //this took about a week to get right..
- //but is it right? who knows at this point..
-
- if (r_result) {
- r_result->collider_id = ObjectID();
- r_result->collider_shape = 0;
- }
- AABB body_aabb;
- bool shapes_found = false;
-
- for (int i = 0; i < p_body->get_shape_count(); i++) {
-
- if (p_body->is_shape_set_as_disabled(i))
- continue;
-
- if (!shapes_found) {
- body_aabb = p_body->get_shape_aabb(i);
- shapes_found = true;
- } else {
- body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
- }
- }
-
- if (!shapes_found) {
- if (r_result) {
- *r_result = PhysicsServer::MotionResult();
- r_result->motion = p_motion;
- }
-
- return false;
- }
-
- // Undo the currently transform the physics server is aware of and apply the provided one
- body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_margin);
-
- Transform body_transform = p_from;
-
- {
- //STEP 1, FREE BODY IF STUCK
-
- const int max_results = 32;
- int recover_attempts = 4;
- Vector3 sr[max_results * 2];
-
- do {
-
- PhysicsServerSW::CollCbkData cbk;
- cbk.max = max_results;
- cbk.amount = 0;
- cbk.ptr = sr;
-
- PhysicsServerSW::CollCbkData *cbkptr = &cbk;
- CollisionSolverSW::CallbackResult cbkres = PhysicsServerSW::_shape_col_cbk;
-
- bool collided = false;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
- if (p_body->is_shape_set_as_disabled(j))
- continue;
-
- Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
- ShapeSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer::SHAPE_RAY) {
- continue;
- }
-
- for (int i = 0; i < amount; i++) {
-
- const CollisionObjectSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- if (CollisionSolverSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, NULL, p_margin)) {
- collided = cbk.amount > 0;
- }
- }
- }
-
- if (!collided) {
- break;
- }
-
- Vector3 recover_motion;
-
- for (int i = 0; i < cbk.amount; i++) {
-
- Vector3 a = sr[i * 2 + 0];
- Vector3 b = sr[i * 2 + 1];
- recover_motion += (b - a) * 0.4;
- }
-
- if (recover_motion == Vector3()) {
- collided = false;
- break;
- }
-
- body_transform.origin += recover_motion;
- body_aabb.position += recover_motion;
-
- recover_attempts--;
-
- } while (recover_attempts);
- }
-
- real_t safe = 1.0;
- real_t unsafe = 1.0;
- int best_shape = -1;
-
- {
- // STEP 2 ATTEMPT MOTION
-
- AABB motion_aabb = body_aabb;
- motion_aabb.position += p_motion;
- motion_aabb = motion_aabb.merge(body_aabb);
-
- int amount = _cull_aabb_for_body(p_body, motion_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
-
- if (p_body->is_shape_set_as_disabled(j))
- continue;
-
- Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
- ShapeSW *body_shape = p_body->get_shape(j);
-
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer::SHAPE_RAY) {
- continue;
- }
-
- Transform body_shape_xform_inv = body_shape_xform.affine_inverse();
- MotionShapeSW mshape;
- mshape.shape = body_shape;
- mshape.motion = body_shape_xform_inv.basis.xform(p_motion);
-
- bool stuck = false;
-
- real_t best_safe = 1;
- real_t best_unsafe = 1;
-
- for (int i = 0; i < amount; i++) {
-
- const CollisionObjectSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- //test initial overlap, does it collide if going all the way?
- Vector3 point_A, point_B;
- Vector3 sep_axis = p_motion.normalized();
-
- 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 (CollisionSolverSW::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();
-
- if (!CollisionSolverSW::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;
- break;
- }
-
- //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
-
- mshape.motion = body_shape_xform_inv.basis.xform(p_motion * ofs);
-
- Vector3 lA, lB;
-
- bool collided = !CollisionSolverSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, motion_aabb, &sep);
-
- if (collided) {
-
- hi = ofs;
- } else {
-
- point_A = lA;
- point_B = lB;
- low = ofs;
- }
- }
-
- if (low < best_safe) {
- best_safe = low;
- best_unsafe = hi;
- }
- }
-
- if (stuck) {
-
- safe = 0;
- unsafe = 0;
- best_shape = j; //sadly it's the best
- break;
- }
- if (best_safe == 1.0) {
- continue;
- }
- if (best_safe < safe) {
-
- safe = best_safe;
- unsafe = best_unsafe;
- best_shape = j;
- }
- }
- }
-
- 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());
- }
-
- } else {
-
- //it collided, let's get the rest info in unsafe advance
- Transform ugt = body_transform;
- ugt.origin += p_motion * unsafe;
-
- _RestCallbackData rcd;
- rcd.best_len = 0;
- rcd.best_object = NULL;
- 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);
- ShapeSW *body_shape = p_body->get_shape(best_shape);
-
- body_aabb.position += p_motion * unsafe;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int i = 0; i < amount; i++) {
-
- const CollisionObjectSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- rcd.object = col_obj;
- rcd.shape = shape_idx;
- bool sc = CollisionSolverSW::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, NULL, p_margin);
- if (!sc)
- continue;
- }
-
- if (rcd.best_len != 0) {
-
- if (r_result) {
- 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_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 BodySW *body = static_cast<const BodySW *>(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);
-
- r_result->motion = safe * p_motion;
- r_result->remainder = p_motion - safe * p_motion;
- r_result->motion += (body_transform.get_origin() - p_from.get_origin());
- }
-
- 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;
- }
- }
-
- return collided;
-}
-
-void *SpaceSW::_broadphase_pair(CollisionObjectSW *A, int p_subindex_A, CollisionObjectSW *B, int p_subindex_B, void *p_self) {
-
- CollisionObjectSW::Type type_A = A->get_type();
- CollisionObjectSW::Type type_B = B->get_type();
- if (type_A > type_B) {
-
- SWAP(A, B);
- SWAP(p_subindex_A, p_subindex_B);
- SWAP(type_A, type_B);
- }
-
- SpaceSW *self = (SpaceSW *)p_self;
-
- self->collision_pairs++;
-
- if (type_A == CollisionObjectSW::TYPE_AREA) {
-
- AreaSW *area = static_cast<AreaSW *>(A);
- if (type_B == CollisionObjectSW::TYPE_AREA) {
-
- AreaSW *area_b = static_cast<AreaSW *>(B);
- Area2PairSW *area2_pair = memnew(Area2PairSW(area_b, p_subindex_B, area, p_subindex_A));
- return area2_pair;
- } else {
-
- BodySW *body = static_cast<BodySW *>(B);
- AreaPairSW *area_pair = memnew(AreaPairSW(body, p_subindex_B, area, p_subindex_A));
- return area_pair;
- }
- } else {
-
- BodyPairSW *b = memnew(BodyPairSW((BodySW *)A, p_subindex_A, (BodySW *)B, p_subindex_B));
- return b;
- }
-
- return NULL;
-}
-
-void SpaceSW::_broadphase_unpair(CollisionObjectSW *A, int p_subindex_A, CollisionObjectSW *B, int p_subindex_B, void *p_data, void *p_self) {
-
- SpaceSW *self = (SpaceSW *)p_self;
- self->collision_pairs--;
- ConstraintSW *c = (ConstraintSW *)p_data;
- memdelete(c);
-}
-
-const SelfList<BodySW>::List &SpaceSW::get_active_body_list() const {
-
- return active_list;
-}
-void SpaceSW::body_add_to_active_list(SelfList<BodySW> *p_body) {
-
- active_list.add(p_body);
-}
-void SpaceSW::body_remove_from_active_list(SelfList<BodySW> *p_body) {
-
- active_list.remove(p_body);
-}
-
-void SpaceSW::body_add_to_inertia_update_list(SelfList<BodySW> *p_body) {
-
- inertia_update_list.add(p_body);
-}
-
-void SpaceSW::body_remove_from_inertia_update_list(SelfList<BodySW> *p_body) {
-
- inertia_update_list.remove(p_body);
-}
-
-BroadPhaseSW *SpaceSW::get_broadphase() {
-
- return broadphase;
-}
-
-void SpaceSW::add_object(CollisionObjectSW *p_object) {
-
- ERR_FAIL_COND(objects.has(p_object));
- objects.insert(p_object);
-}
-
-void SpaceSW::remove_object(CollisionObjectSW *p_object) {
-
- ERR_FAIL_COND(!objects.has(p_object));
- objects.erase(p_object);
-}
-
-const Set<CollisionObjectSW *> &SpaceSW::get_objects() const {
-
- return objects;
-}
-
-void SpaceSW::body_add_to_state_query_list(SelfList<BodySW> *p_body) {
-
- state_query_list.add(p_body);
-}
-void SpaceSW::body_remove_from_state_query_list(SelfList<BodySW> *p_body) {
-
- state_query_list.remove(p_body);
-}
-
-void SpaceSW::area_add_to_monitor_query_list(SelfList<AreaSW> *p_area) {
-
- monitor_query_list.add(p_area);
-}
-void SpaceSW::area_remove_from_monitor_query_list(SelfList<AreaSW> *p_area) {
-
- monitor_query_list.remove(p_area);
-}
-
-void SpaceSW::area_add_to_moved_list(SelfList<AreaSW> *p_area) {
-
- area_moved_list.add(p_area);
-}
-
-void SpaceSW::area_remove_from_moved_list(SelfList<AreaSW> *p_area) {
-
- area_moved_list.remove(p_area);
-}
-
-const SelfList<AreaSW>::List &SpaceSW::get_moved_area_list() const {
-
- return area_moved_list;
-}
-
-void SpaceSW::call_queries() {
-
- while (state_query_list.first()) {
-
- BodySW *b = state_query_list.first()->self();
- state_query_list.remove(state_query_list.first());
- b->call_queries();
- }
-
- while (monitor_query_list.first()) {
-
- AreaSW *a = monitor_query_list.first()->self();
- monitor_query_list.remove(monitor_query_list.first());
- a->call_queries();
- }
-}
-
-void SpaceSW::setup() {
-
- contact_debug_count = 0;
- while (inertia_update_list.first()) {
- inertia_update_list.first()->self()->update_inertias();
- inertia_update_list.remove(inertia_update_list.first());
- }
-}
-
-void SpaceSW::update() {
-
- broadphase->update();
-}
-
-void SpaceSW::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) {
-
- switch (p_param) {
-
- case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius = p_value; break;
- case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: contact_max_separation = p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration = p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: body_linear_velocity_sleep_threshold = p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: body_angular_velocity_sleep_threshold = p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio = p_value; break;
- case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break;
- case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break;
- }
-}
-
-real_t SpaceSW::get_param(PhysicsServer::SpaceParameter p_param) const {
-
- switch (p_param) {
-
- case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius;
- case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: return contact_max_separation;
- case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: return contact_max_allowed_penetration;
- case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: return body_linear_velocity_sleep_threshold;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: return body_angular_velocity_sleep_threshold;
- case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio;
- case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
- case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth;
- }
- return 0;
-}
-
-void SpaceSW::lock() {
-
- locked = true;
-}
-
-void SpaceSW::unlock() {
-
- locked = false;
-}
-
-bool SpaceSW::is_locked() const {
-
- return locked;
-}
-
-PhysicsDirectSpaceStateSW *SpaceSW::get_direct_state() {
-
- return direct_access;
-}
-
-SpaceSW::SpaceSW() {
-
- collision_pairs = 0;
- active_objects = 0;
- island_count = 0;
- contact_debug_count = 0;
-
- locked = false;
- contact_recycle_radius = 0.01;
- contact_max_separation = 0.05;
- contact_max_allowed_penetration = 0.01;
- test_motion_min_contact_depth = 0.00001;
-
- constraint_bias = 0.01;
- body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1);
- body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI));
- body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5);
- ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
- body_angular_velocity_damp_ratio = 10;
-
- broadphase = BroadPhaseSW::create_func();
- broadphase->set_pair_callback(_broadphase_pair, this);
- broadphase->set_unpair_callback(_broadphase_unpair, this);
- area = NULL;
-
- direct_access = memnew(PhysicsDirectSpaceStateSW);
- direct_access->space = this;
-
- for (int i = 0; i < ELAPSED_TIME_MAX; i++)
- elapsed_time[i] = 0;
-}
-
-SpaceSW::~SpaceSW() {
-
- memdelete(broadphase);
- memdelete(direct_access);
-}
diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h
deleted file mode 100644
index 9e82720a75..0000000000
--- a/servers/physics/space_sw.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*************************************************************************/
-/* space_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SPACE_SW_H
-#define SPACE_SW_H
-
-#include "area_pair_sw.h"
-#include "area_sw.h"
-#include "body_pair_sw.h"
-#include "body_sw.h"
-#include "broad_phase_sw.h"
-#include "collision_object_sw.h"
-#include "core/hash_map.h"
-#include "core/project_settings.h"
-#include "core/typedefs.h"
-
-class PhysicsDirectSpaceStateSW : public PhysicsDirectSpaceState {
-
- GDCLASS(PhysicsDirectSpaceStateSW, PhysicsDirectSpaceState);
-
-public:
- SpaceSW *space;
-
- virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false);
- virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- virtual bool 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 = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = NULL);
- virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const;
-
- PhysicsDirectSpaceStateSW();
-};
-
-class SpaceSW {
-
-public:
- enum ElapsedTime {
- ELAPSED_TIME_INTEGRATE_FORCES,
- ELAPSED_TIME_GENERATE_ISLANDS,
- ELAPSED_TIME_SETUP_CONSTRAINTS,
- ELAPSED_TIME_SOLVE_CONSTRAINTS,
- ELAPSED_TIME_INTEGRATE_VELOCITIES,
- ELAPSED_TIME_MAX
-
- };
-
-private:
- uint64_t elapsed_time[ELAPSED_TIME_MAX];
-
- PhysicsDirectSpaceStateSW *direct_access;
- RID self;
-
- BroadPhaseSW *broadphase;
- SelfList<BodySW>::List active_list;
- SelfList<BodySW>::List inertia_update_list;
- SelfList<BodySW>::List state_query_list;
- SelfList<AreaSW>::List monitor_query_list;
- SelfList<AreaSW>::List area_moved_list;
-
- static void *_broadphase_pair(CollisionObjectSW *A, int p_subindex_A, CollisionObjectSW *B, int p_subindex_B, void *p_self);
- static void _broadphase_unpair(CollisionObjectSW *A, int p_subindex_A, CollisionObjectSW *B, int p_subindex_B, void *p_data, void *p_self);
-
- Set<CollisionObjectSW *> objects;
-
- AreaSW *area;
-
- real_t contact_recycle_radius;
- real_t contact_max_separation;
- real_t contact_max_allowed_penetration;
- real_t constraint_bias;
- real_t test_motion_min_contact_depth;
-
- enum {
-
- INTERSECTION_QUERY_MAX = 2048
- };
-
- CollisionObjectSW *intersection_query_results[INTERSECTION_QUERY_MAX];
- int intersection_query_subindex_results[INTERSECTION_QUERY_MAX];
-
- real_t body_linear_velocity_sleep_threshold;
- real_t body_angular_velocity_sleep_threshold;
- real_t body_time_to_sleep;
- real_t body_angular_velocity_damp_ratio;
-
- bool locked;
-
- int island_count;
- int active_objects;
- int collision_pairs;
-
- RID static_global_body;
-
- Vector<Vector3> contact_debug;
- int contact_debug_count;
-
- friend class PhysicsDirectSpaceStateSW;
-
- int _cull_aabb_for_body(BodySW *p_body, const AABB &p_aabb);
-
-public:
- _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
- _FORCE_INLINE_ RID get_self() const { return self; }
-
- void set_default_area(AreaSW *p_area) { area = p_area; }
- AreaSW *get_default_area() const { return area; }
-
- const SelfList<BodySW>::List &get_active_body_list() const;
- void body_add_to_active_list(SelfList<BodySW> *p_body);
- void body_remove_from_active_list(SelfList<BodySW> *p_body);
- void body_add_to_inertia_update_list(SelfList<BodySW> *p_body);
- void body_remove_from_inertia_update_list(SelfList<BodySW> *p_body);
-
- void body_add_to_state_query_list(SelfList<BodySW> *p_body);
- void body_remove_from_state_query_list(SelfList<BodySW> *p_body);
-
- void area_add_to_monitor_query_list(SelfList<AreaSW> *p_area);
- void area_remove_from_monitor_query_list(SelfList<AreaSW> *p_area);
- void area_add_to_moved_list(SelfList<AreaSW> *p_area);
- void area_remove_from_moved_list(SelfList<AreaSW> *p_area);
- const SelfList<AreaSW>::List &get_moved_area_list() const;
-
- BroadPhaseSW *get_broadphase();
-
- void add_object(CollisionObjectSW *p_object);
- void remove_object(CollisionObjectSW *p_object);
- const Set<CollisionObjectSW *> &get_objects() const;
-
- _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; }
- _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; }
- _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; }
- _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; }
- _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; }
- _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; }
- _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
- _FORCE_INLINE_ real_t get_body_angular_velocity_damp_ratio() const { return body_angular_velocity_damp_ratio; }
-
- void update();
- void setup();
- void call_queries();
-
- bool is_locked() const;
- void lock();
- void unlock();
-
- void set_param(PhysicsServer::SpaceParameter p_param, real_t p_value);
- real_t get_param(PhysicsServer::SpaceParameter p_param) const;
-
- void set_island_count(int p_island_count) { island_count = p_island_count; }
- int get_island_count() const { return island_count; }
-
- void set_active_objects(int p_active_objects) { active_objects = p_active_objects; }
- int get_active_objects() const { return active_objects; }
-
- int get_collision_pairs() const { return collision_pairs; }
-
- PhysicsDirectSpaceStateSW *get_direct_state();
-
- void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
- _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); }
- _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) {
- if (contact_debug_count < contact_debug.size()) contact_debug.write[contact_debug_count++] = p_contact;
- }
- _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contact_debug; }
- _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
-
- void set_static_global_body(RID p_body) { static_global_body = p_body; }
- RID get_static_global_body() { return static_global_body; }
-
- void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
- uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
-
- int test_body_ray_separation(BodySW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, real_t p_margin);
- bool test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes);
-
- SpaceSW();
- ~SpaceSW();
-};
-
-#endif // SPACE__SW_H
diff --git a/servers/physics/step_sw.cpp b/servers/physics/step_sw.cpp
deleted file mode 100644
index f4055ecff7..0000000000
--- a/servers/physics/step_sw.cpp
+++ /dev/null
@@ -1,299 +0,0 @@
-/*************************************************************************/
-/* step_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "step_sw.h"
-#include "joints_sw.h"
-
-#include "core/os/os.h"
-
-void StepSW::_populate_island(BodySW *p_body, BodySW **p_island, ConstraintSW **p_constraint_island) {
-
- p_body->set_island_step(_step);
- p_body->set_island_next(*p_island);
- *p_island = p_body;
-
- for (Map<ConstraintSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
-
- ConstraintSW *c = (ConstraintSW *)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;
-
- for (int i = 0; i < c->get_body_count(); i++) {
- if (i == E->get())
- continue;
- BodySW *b = c->get_body_ptr()[i];
- if (b->get_island_step() == _step || b->get_mode() == PhysicsServer::BODY_MODE_STATIC || b->get_mode() == PhysicsServer::BODY_MODE_KINEMATIC)
- continue; //no go
- _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island);
- }
- }
-}
-
-void StepSW::_setup_island(ConstraintSW *p_island, real_t p_delta) {
-
- ConstraintSW *ci = p_island;
- while (ci) {
- ci->setup(p_delta);
- //todo remove from island if process fails
- ci = ci->get_island_next();
- }
-}
-
-void StepSW::_solve_island(ConstraintSW *p_island, int p_iterations, real_t p_delta) {
-
- int at_priority = 1;
-
- while (p_island) {
-
- for (int i = 0; i < p_iterations; i++) {
-
- ConstraintSW *ci = p_island;
- while (ci) {
- ci->solve(p_delta);
- ci = ci->get_island_next();
- }
- }
-
- at_priority++;
-
- {
- ConstraintSW *ci = p_island;
- ConstraintSW *prev = NULL;
- 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();
- }
- }
- }
-}
-
-void StepSW::_check_suspend(BodySW *p_island, real_t p_delta) {
-
- bool can_sleep = true;
-
- BodySW *b = p_island;
- while (b) {
-
- if (b->get_mode() == PhysicsServer::BODY_MODE_STATIC || b->get_mode() == PhysicsServer::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
- }
-
- if (!b->sleep_test(p_delta))
- can_sleep = false;
-
- b = b->get_island_next();
- }
-
- //put all to sleep or wake up everyoen
-
- b = p_island;
- while (b) {
-
- if (b->get_mode() == PhysicsServer::BODY_MODE_STATIC || b->get_mode() == PhysicsServer::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
- }
-
- bool active = b->is_active();
-
- if (active == can_sleep)
- b->set_active(!can_sleep);
-
- b = b->get_island_next();
- }
-}
-
-void StepSW::step(SpaceSW *p_space, real_t p_delta, int p_iterations) {
-
- p_space->lock(); // can't access space during this
-
- p_space->setup(); //update inertias, etc
-
- const SelfList<BodySW>::List *body_list = &p_space->get_active_body_list();
-
- /* INTEGRATE FORCES */
-
- uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
- uint64_t profile_endtime = 0;
-
- int active_count = 0;
-
- const SelfList<BodySW> *b = body_list->first();
- while (b) {
-
- b->self()->integrate_forces(p_delta);
- b = b->next();
- active_count++;
- }
-
- p_space->set_active_objects(active_count);
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(SpaceSW::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* GENERATE CONSTRAINT ISLANDS */
-
- BodySW *island_list = NULL;
- ConstraintSW *constraint_island_list = NULL;
- b = body_list->first();
-
- int island_count = 0;
-
- while (b) {
- BodySW *body = b->self();
-
- if (body->get_island_step() != _step) {
-
- BodySW *island = NULL;
- ConstraintSW *constraint_island = NULL;
- _populate_island(body, &island, &constraint_island);
-
- island->set_island_list_next(island_list);
- island_list = island;
-
- if (constraint_island) {
- constraint_island->set_island_list_next(constraint_island_list);
- constraint_island_list = constraint_island;
- island_count++;
- }
- }
- b = b->next();
- }
-
- p_space->set_island_count(island_count);
-
- const SelfList<AreaSW>::List &aml = p_space->get_moved_area_list();
-
- while (aml.first()) {
- for (const Set<ConstraintSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
-
- ConstraintSW *c = E->get();
- if (c->get_island_step() == _step)
- continue;
- c->set_island_step(_step);
- c->set_island_next(NULL);
- c->set_island_list_next(constraint_island_list);
- constraint_island_list = c;
- }
- p_space->area_remove_from_moved_list((SelfList<AreaSW> *)aml.first()); //faster to remove here
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(SpaceSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* SETUP CONSTRAINT ISLANDS */
-
- {
- ConstraintSW *ci = constraint_island_list;
- while (ci) {
-
- _setup_island(ci, p_delta);
- ci = ci->get_island_list_next();
- }
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(SpaceSW::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* SOLVE CONSTRAINT ISLANDS */
-
- {
- ConstraintSW *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();
- }
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(SpaceSW::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- /* INTEGRATE VELOCITIES */
-
- b = body_list->first();
- while (b) {
- const SelfList<BodySW> *n = b->next();
- b->self()->integrate_velocities(p_delta);
- b = n;
- }
-
- /* SLEEP / WAKE UP ISLANDS */
-
- {
- BodySW *bi = island_list;
- while (bi) {
-
- _check_suspend(bi, p_delta);
- bi = bi->get_island_list_next();
- }
- }
-
- { //profile
- profile_endtime = OS::get_singleton()->get_ticks_usec();
- p_space->set_elapsed_time(SpaceSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);
- profile_begtime = profile_endtime;
- }
-
- p_space->update();
- p_space->unlock();
- _step++;
-}
-
-StepSW::StepSW() {
-
- _step = 1;
-}
diff --git a/servers/physics/step_sw.h b/servers/physics/step_sw.h
deleted file mode 100644
index 40022ef8b9..0000000000
--- a/servers/physics/step_sw.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*************************************************************************/
-/* step_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 STEP_SW_H
-#define STEP_SW_H
-
-#include "space_sw.h"
-
-class StepSW {
-
- uint64_t _step;
-
- void _populate_island(BodySW *p_body, BodySW **p_island, ConstraintSW **p_constraint_island);
- void _setup_island(ConstraintSW *p_island, real_t p_delta);
- void _solve_island(ConstraintSW *p_island, int p_iterations, real_t p_delta);
- void _check_suspend(BodySW *p_island, real_t p_delta);
-
-public:
- void step(SpaceSW *p_space, real_t p_delta, int p_iterations);
- StepSW();
-};
-
-#endif // STEP__SW_H
diff --git a/servers/physics_2d/SCsub b/servers/physics_2d/SCsub
index d730144861..86681f9c74 100644
--- a/servers/physics_2d/SCsub
+++ b/servers/physics_2d/SCsub
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-Import('env')
+Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
index 45666d9d09..85ec2aae47 100644
--- a/servers/physics_2d/area_2d_sw.cpp
+++ b/servers/physics_2d/area_2d_sw.cpp
@@ -117,40 +117,40 @@ void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_meth
get_space()->area_add_to_moved_list(&moved_list);
}
-void Area2DSW::set_space_override_mode(Physics2DServer::AreaSpaceOverrideMode p_mode) {
- bool do_override = p_mode != Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED;
- if (do_override == (space_override_mode != Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED))
+void Area2DSW::set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode p_mode) {
+ bool do_override = p_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
+ if (do_override == (space_override_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED))
return;
_unregister_shapes();
space_override_mode = p_mode;
_shape_changed();
}
-void Area2DSW::set_param(Physics2DServer::AreaParameter p_param, const Variant &p_value) {
+void Area2DSW::set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value) {
switch (p_param) {
- case Physics2DServer::AREA_PARAM_GRAVITY: gravity = p_value; break;
- case Physics2DServer::AREA_PARAM_GRAVITY_VECTOR: gravity_vector = p_value; break;
- case Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point = p_value; break;
- case Physics2DServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale = p_value; break;
- case Physics2DServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation = p_value; break;
- case Physics2DServer::AREA_PARAM_LINEAR_DAMP: linear_damp = p_value; break;
- case Physics2DServer::AREA_PARAM_ANGULAR_DAMP: angular_damp = p_value; break;
- case Physics2DServer::AREA_PARAM_PRIORITY: priority = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY: gravity = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR: gravity_vector = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP: linear_damp = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP: angular_damp = p_value; break;
+ case PhysicsServer2D::AREA_PARAM_PRIORITY: priority = p_value; break;
}
}
-Variant Area2DSW::get_param(Physics2DServer::AreaParameter p_param) const {
+Variant Area2DSW::get_param(PhysicsServer2D::AreaParameter p_param) const {
switch (p_param) {
- case Physics2DServer::AREA_PARAM_GRAVITY: return gravity;
- case Physics2DServer::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
- case Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
- case Physics2DServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale;
- case Physics2DServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation;
- case Physics2DServer::AREA_PARAM_LINEAR_DAMP: return linear_damp;
- case Physics2DServer::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
- case Physics2DServer::AREA_PARAM_PRIORITY: return priority;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY: return gravity;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale;
+ case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation;
+ case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP: return linear_damp;
+ case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
+ case PhysicsServer2D::AREA_PARAM_PRIORITY: return priority;
}
return Variant();
@@ -194,7 +194,7 @@ void Area2DSW::call_queries() {
if (E->get().state == 0)
continue; //nothing happened
- res[0] = E->get().state > 0 ? Physics2DServer::AREA_BODY_ADDED : Physics2DServer::AREA_BODY_REMOVED;
+ res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;
res[1] = E->key().rid;
res[2] = E->key().instance_id;
res[3] = E->key().body_shape;
@@ -226,7 +226,7 @@ void Area2DSW::call_queries() {
if (E->get().state == 0)
continue; //nothing happened
- res[0] = E->get().state > 0 ? Physics2DServer::AREA_BODY_ADDED : Physics2DServer::AREA_BODY_REMOVED;
+ res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED;
res[1] = E->key().rid;
res[2] = E->key().instance_id;
res[3] = E->key().body_shape;
@@ -248,7 +248,7 @@ Area2DSW::Area2DSW() :
moved_list(this) {
_set_static(true); //areas are not active by default
- space_override_mode = Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED;
+ space_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED;
gravity = 9.80665;
gravity_vector = Vector2(0, -1);
gravity_is_point = false;
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h
index 54ffd9763d..ae2a8ff995 100644
--- a/servers/physics_2d/area_2d_sw.h
+++ b/servers/physics_2d/area_2d_sw.h
@@ -33,8 +33,8 @@
#include "collision_object_2d_sw.h"
#include "core/self_list.h"
-#include "servers/physics_2d_server.h"
-//#include "servers/physics/query_sw.h"
+#include "servers/physics_server_2d.h"
+//#include "servers/physics_3d/query_sw.h"
class Space2DSW;
class Body2DSW;
@@ -42,7 +42,7 @@ class Constraint2DSW;
class Area2DSW : public CollisionObject2DSW {
- Physics2DServer::AreaSpaceOverrideMode space_override_mode;
+ PhysicsServer2D::AreaSpaceOverrideMode space_override_mode;
real_t gravity;
Vector2 gravity_vector;
bool gravity_is_point;
@@ -121,11 +121,11 @@ public:
_FORCE_INLINE_ void add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
_FORCE_INLINE_ void remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
- void set_param(Physics2DServer::AreaParameter p_param, const Variant &p_value);
- Variant get_param(Physics2DServer::AreaParameter p_param) const;
+ void set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer2D::AreaParameter p_param) const;
- void set_space_override_mode(Physics2DServer::AreaSpaceOverrideMode p_mode);
- Physics2DServer::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; }
+ void set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode p_mode);
+ PhysicsServer2D::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; }
_FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; }
_FORCE_INLINE_ real_t get_gravity() const { return gravity; }
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 05d71cfabe..0e70a626c2 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -37,7 +37,7 @@ bool AreaPair2DSW::setup(real_t p_step) {
if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) {
result = false;
- } else if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), NULL, this)) {
+ } else if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) {
result = true;
}
@@ -45,14 +45,14 @@ bool AreaPair2DSW::setup(real_t p_step) {
if (result) {
- if (area->get_space_override_mode() != Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED)
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)
body->add_area(area);
if (area->has_monitor_callback())
area->add_body_to_query(body, body_shape, area_shape);
} else {
- if (area->get_space_override_mode() != Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED)
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)
body->remove_area(area);
if (area->has_monitor_callback())
area->remove_body_from_query(body, body_shape, area_shape);
@@ -76,7 +76,7 @@ AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area,
colliding = false;
body->add_constraint(this, 0);
area->add_constraint(this);
- if (p_body->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC) //need to be active to process pair
+ if (p_body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) //need to be active to process pair
p_body->set_active(true);
}
@@ -84,7 +84,7 @@ AreaPair2DSW::~AreaPair2DSW() {
if (colliding) {
- if (area->get_space_override_mode() != Physics2DServer::AREA_SPACE_OVERRIDE_DISABLED)
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)
body->remove_area(area);
if (area->has_monitor_callback())
area->remove_body_from_query(body, body_shape, area_shape);
@@ -100,7 +100,7 @@ bool Area2Pair2DSW::setup(real_t p_step) {
bool result = false;
if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) {
result = false;
- } else if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), NULL, this)) {
+ } else if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) {
result = true;
}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 863b422996..39e28fd002 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -30,7 +30,7 @@
#include "body_2d_sw.h"
#include "area_2d_sw.h"
-#include "physics_2d_server_sw.h"
+#include "physics_server_2d_sw.h"
#include "space_2d_sw.h"
void Body2DSW::_update_inertia() {
@@ -45,7 +45,7 @@ void Body2DSW::update_inertias() {
switch (mode) {
- case Physics2DServer::BODY_MODE_RIGID: {
+ case PhysicsServer2D::BODY_MODE_RIGID: {
if (user_inertia) {
_inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
@@ -86,13 +86,13 @@ void Body2DSW::update_inertias() {
_inv_mass = 0;
} break;
- case Physics2DServer::BODY_MODE_KINEMATIC:
- case Physics2DServer::BODY_MODE_STATIC: {
+ case PhysicsServer2D::BODY_MODE_KINEMATIC:
+ case PhysicsServer2D::BODY_MODE_STATIC: {
_inv_inertia = 0;
_inv_mass = 0;
} break;
- case Physics2DServer::BODY_MODE_CHARACTER: {
+ case PhysicsServer2D::BODY_MODE_CHARACTER: {
_inv_inertia = 0;
_inv_mass = 1.0 / mass;
@@ -114,7 +114,7 @@ void Body2DSW::set_active(bool p_active) {
if (get_space())
get_space()->body_remove_from_active_list(&active_list);
} else {
- if (mode == Physics2DServer::BODY_MODE_STATIC)
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC)
return; //static bodies can't become active
if (get_space())
get_space()->body_add_to_active_list(&active_list);
@@ -134,24 +134,24 @@ void Body2DSW::set_active(bool p_active) {
*/
}
-void Body2DSW::set_param(Physics2DServer::BodyParameter p_param, real_t p_value) {
+void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) {
switch (p_param) {
- case Physics2DServer::BODY_PARAM_BOUNCE: {
+ case PhysicsServer2D::BODY_PARAM_BOUNCE: {
bounce = p_value;
} break;
- case Physics2DServer::BODY_PARAM_FRICTION: {
+ case PhysicsServer2D::BODY_PARAM_FRICTION: {
friction = p_value;
} break;
- case Physics2DServer::BODY_PARAM_MASS: {
+ case PhysicsServer2D::BODY_PARAM_MASS: {
ERR_FAIL_COND(p_value <= 0);
mass = p_value;
_update_inertia();
} break;
- case Physics2DServer::BODY_PARAM_INERTIA: {
+ case PhysicsServer2D::BODY_PARAM_INERTIA: {
if (p_value <= 0) {
user_inertia = false;
_update_inertia();
@@ -161,14 +161,14 @@ void Body2DSW::set_param(Physics2DServer::BodyParameter p_param, real_t p_value)
_inv_inertia = 1.0 / p_value;
}
} break;
- case Physics2DServer::BODY_PARAM_GRAVITY_SCALE: {
+ case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
gravity_scale = p_value;
} break;
- case Physics2DServer::BODY_PARAM_LINEAR_DAMP: {
+ case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: {
linear_damp = p_value;
} break;
- case Physics2DServer::BODY_PARAM_ANGULAR_DAMP: {
+ case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP: {
angular_damp = p_value;
} break;
@@ -177,31 +177,31 @@ void Body2DSW::set_param(Physics2DServer::BodyParameter p_param, real_t p_value)
}
}
-real_t Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
+real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const {
switch (p_param) {
- case Physics2DServer::BODY_PARAM_BOUNCE: {
+ case PhysicsServer2D::BODY_PARAM_BOUNCE: {
return bounce;
}
- case Physics2DServer::BODY_PARAM_FRICTION: {
+ case PhysicsServer2D::BODY_PARAM_FRICTION: {
return friction;
}
- case Physics2DServer::BODY_PARAM_MASS: {
+ case PhysicsServer2D::BODY_PARAM_MASS: {
return mass;
}
- case Physics2DServer::BODY_PARAM_INERTIA: {
+ case PhysicsServer2D::BODY_PARAM_INERTIA: {
return inertia;
}
- case Physics2DServer::BODY_PARAM_GRAVITY_SCALE: {
+ case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
return gravity_scale;
}
- case Physics2DServer::BODY_PARAM_LINEAR_DAMP: {
+ case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: {
return linear_damp;
}
- case Physics2DServer::BODY_PARAM_ANGULAR_DAMP: {
+ case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP: {
return angular_damp;
}
@@ -212,28 +212,28 @@ real_t Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
return 0;
}
-void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
+void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) {
- Physics2DServer::BodyMode prev = mode;
+ PhysicsServer2D::BodyMode prev = mode;
mode = p_mode;
switch (p_mode) {
//CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
- case Physics2DServer::BODY_MODE_STATIC:
- case Physics2DServer::BODY_MODE_KINEMATIC: {
+ case PhysicsServer2D::BODY_MODE_STATIC:
+ case PhysicsServer2D::BODY_MODE_KINEMATIC: {
_set_inv_transform(get_transform().affine_inverse());
_inv_mass = 0;
_inv_inertia = 0;
- _set_static(p_mode == Physics2DServer::BODY_MODE_STATIC);
- set_active(p_mode == Physics2DServer::BODY_MODE_KINEMATIC && contacts.size());
+ _set_static(p_mode == PhysicsServer2D::BODY_MODE_STATIC);
+ set_active(p_mode == PhysicsServer2D::BODY_MODE_KINEMATIC && contacts.size());
linear_velocity = Vector2();
angular_velocity = 0;
- if (mode == Physics2DServer::BODY_MODE_KINEMATIC && prev != mode) {
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC && prev != mode) {
first_time_kinematic = true;
}
} break;
- case Physics2DServer::BODY_MODE_RIGID: {
+ case PhysicsServer2D::BODY_MODE_RIGID: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = inertia > 0 ? (1.0 / inertia) : 0;
@@ -241,7 +241,7 @@ void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
set_active(true);
} break;
- case Physics2DServer::BODY_MODE_CHARACTER: {
+ case PhysicsServer2D::BODY_MODE_CHARACTER: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = 0;
@@ -250,7 +250,7 @@ void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
angular_velocity = 0;
} break;
}
- if (p_mode == Physics2DServer::BODY_MODE_RIGID && _inv_inertia == 0) {
+ if (p_mode == PhysicsServer2D::BODY_MODE_RIGID && _inv_inertia == 0) {
_update_inertia();
}
/*
@@ -258,7 +258,7 @@ void Body2DSW::set_mode(Physics2DServer::BodyMode p_mode) {
_update_queries();
*/
}
-Physics2DServer::BodyMode Body2DSW::get_mode() const {
+PhysicsServer2D::BodyMode Body2DSW::get_mode() const {
return mode;
}
@@ -269,12 +269,12 @@ void Body2DSW::_shapes_changed() {
wakeup_neighbours();
}
-void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant &p_variant) {
+void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant) {
switch (p_state) {
- case Physics2DServer::BODY_STATE_TRANSFORM: {
+ case PhysicsServer2D::BODY_STATE_TRANSFORM: {
- if (mode == Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
new_transform = p_variant;
//wakeup_neighbours();
@@ -284,7 +284,7 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant &p_va
_set_inv_transform(get_transform().affine_inverse());
first_time_kinematic = false;
}
- } else if (mode == Physics2DServer::BODY_MODE_STATIC) {
+ } else if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
_set_transform(p_variant);
_set_inv_transform(get_transform().affine_inverse());
wakeup_neighbours();
@@ -300,28 +300,28 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant &p_va
wakeup();
} break;
- case Physics2DServer::BODY_STATE_LINEAR_VELOCITY: {
+ case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
/*
- if (mode==Physics2DServer::BODY_MODE_STATIC)
+ if (mode==PhysicsServer2D::BODY_MODE_STATIC)
break;
*/
linear_velocity = p_variant;
wakeup();
} break;
- case Physics2DServer::BODY_STATE_ANGULAR_VELOCITY: {
+ case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
/*
- if (mode!=Physics2DServer::BODY_MODE_RIGID)
+ if (mode!=PhysicsServer2D::BODY_MODE_RIGID)
break;
*/
angular_velocity = p_variant;
wakeup();
} break;
- case Physics2DServer::BODY_STATE_SLEEPING: {
+ case PhysicsServer2D::BODY_STATE_SLEEPING: {
//?
- if (mode == Physics2DServer::BODY_MODE_STATIC || mode == Physics2DServer::BODY_MODE_KINEMATIC)
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC)
break;
bool do_sleep = p_variant;
if (do_sleep) {
@@ -331,34 +331,34 @@ void Body2DSW::set_state(Physics2DServer::BodyState p_state, const Variant &p_va
//biased_angular_velocity=Vector3();
set_active(false);
} else {
- if (mode != Physics2DServer::BODY_MODE_STATIC)
+ if (mode != PhysicsServer2D::BODY_MODE_STATIC)
set_active(true);
}
} break;
- case Physics2DServer::BODY_STATE_CAN_SLEEP: {
+ case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode == Physics2DServer::BODY_MODE_RIGID && !active && !can_sleep)
+ if (mode == PhysicsServer2D::BODY_MODE_RIGID && !active && !can_sleep)
set_active(true);
} break;
}
}
-Variant Body2DSW::get_state(Physics2DServer::BodyState p_state) const {
+Variant Body2DSW::get_state(PhysicsServer2D::BodyState p_state) const {
switch (p_state) {
- case Physics2DServer::BODY_STATE_TRANSFORM: {
+ case PhysicsServer2D::BODY_STATE_TRANSFORM: {
return get_transform();
}
- case Physics2DServer::BODY_STATE_LINEAR_VELOCITY: {
+ case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: {
return linear_velocity;
}
- case Physics2DServer::BODY_STATE_ANGULAR_VELOCITY: {
+ case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: {
return angular_velocity;
}
- case Physics2DServer::BODY_STATE_SLEEPING: {
+ case PhysicsServer2D::BODY_STATE_SLEEPING: {
return !is_active();
}
- case Physics2DServer::BODY_STATE_CAN_SLEEP: {
+ case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
return can_sleep;
}
}
@@ -418,7 +418,7 @@ void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) {
void Body2DSW::integrate_forces(real_t p_step) {
- if (mode == Physics2DServer::BODY_MODE_STATIC)
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC)
return;
Area2DSW *def_area = get_space()->get_default_area();
@@ -435,20 +435,20 @@ void Body2DSW::integrate_forces(real_t p_step) {
const AreaCMP *aa = &areas[0];
// damp_area = aa[ac-1].area;
for (int i = ac - 1; i >= 0 && !stopped; i--) {
- Physics2DServer::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
+ PhysicsServer2D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
switch (mode) {
- case Physics2DServer::AREA_SPACE_OVERRIDE_COMBINE:
- case Physics2DServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
_compute_area_gravity_and_dampenings(aa[i].area);
- stopped = mode == Physics2DServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ stopped = mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
} break;
- case Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE:
- case Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
gravity = Vector2(0, 0);
area_angular_damp = 0;
area_linear_damp = 0;
_compute_area_gravity_and_dampenings(aa[i].area);
- stopped = mode == Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE;
+ stopped = mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE;
} break;
default: {
}
@@ -478,7 +478,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
Vector2 motion;
bool do_motion = false;
- if (mode == Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
//compute motion, angular and etc. velocities from prev transform
motion = new_transform.get_origin() - get_transform().get_origin();
@@ -521,7 +521,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
angular_velocity += _inv_inertia * torque * p_step;
}
- if (continuous_cd_mode != Physics2DServer::CCD_MODE_DISABLED) {
+ if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) {
motion = linear_velocity * p_step;
do_motion = true;
@@ -538,20 +538,20 @@ void Body2DSW::integrate_forces(real_t p_step) {
_update_shapes_with_motion(motion);
}
- // damp_area=NULL; // clear the area, so it is set in the next frame
- def_area = NULL; // clear the area, so it is set in the next frame
+ // damp_area=nullptr; // clear the area, so it is set in the next frame
+ def_area = nullptr; // clear the area, so it is set in the next frame
contact_count = 0;
}
void Body2DSW::integrate_velocities(real_t p_step) {
- if (mode == Physics2DServer::BODY_MODE_STATIC)
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC)
return;
if (fi_callback)
get_space()->body_add_to_state_query_list(&direct_state_query_list);
- if (mode == Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
_set_transform(new_transform, false);
_set_inv_transform(new_transform.affine_inverse());
@@ -566,10 +566,10 @@ void Body2DSW::integrate_velocities(real_t p_step) {
real_t angle = get_transform().get_rotation() + total_angular_velocity * p_step;
Vector2 pos = get_transform().get_origin() + total_linear_velocity * p_step;
- _set_transform(Transform2D(angle, pos), continuous_cd_mode == Physics2DServer::CCD_MODE_DISABLED);
+ _set_transform(Transform2D(angle, pos), continuous_cd_mode == PhysicsServer2D::CCD_MODE_DISABLED);
_set_inv_transform(get_transform().inverse());
- if (continuous_cd_mode != Physics2DServer::CCD_MODE_DISABLED)
+ if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED)
new_transform = get_transform();
//_update_inertia_tensor();
@@ -588,7 +588,7 @@ void Body2DSW::wakeup_neighbours() {
if (i == E->get())
continue;
Body2DSW *b = n[i];
- if (b->mode != Physics2DServer::BODY_MODE_RIGID)
+ if (b->mode != PhysicsServer2D::BODY_MODE_RIGID)
continue;
if (!b->is_active())
@@ -601,7 +601,7 @@ void Body2DSW::call_queries() {
if (fi_callback) {
- Physics2DDirectBodyStateSW *dbs = Physics2DDirectBodyStateSW::singleton;
+ PhysicsDirectBodyState2DSW *dbs = PhysicsDirectBodyState2DSW::singleton;
dbs->body = this;
Variant v = dbs;
@@ -626,9 +626,9 @@ void Body2DSW::call_queries() {
bool Body2DSW::sleep_test(real_t p_step) {
- if (mode == Physics2DServer::BODY_MODE_STATIC || mode == Physics2DServer::BODY_MODE_KINEMATIC)
+ if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC)
return true; //
- else if (mode == Physics2DServer::BODY_MODE_CHARACTER)
+ else if (mode == PhysicsServer2D::BODY_MODE_CHARACTER)
return !active; // characters and kinematic bodies don't sleep unless asked to sleep
else if (!can_sleep)
return false;
@@ -650,7 +650,7 @@ void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p
if (fi_callback) {
memdelete(fi_callback);
- fi_callback = NULL;
+ fi_callback = nullptr;
}
if (p_id.is_valid()) {
@@ -668,7 +668,7 @@ Body2DSW::Body2DSW() :
inertia_update_list(this),
direct_state_query_list(this) {
- mode = Physics2DServer::BODY_MODE_RIGID;
+ mode = PhysicsServer2D::BODY_MODE_RIGID;
active = true;
angular_velocity = 0;
biased_angular_velocity = 0;
@@ -682,8 +682,8 @@ Body2DSW::Body2DSW() :
omit_force_integration = false;
applied_torque = 0;
island_step = 0;
- island_next = NULL;
- island_list_next = NULL;
+ island_next = nullptr;
+ island_list_next = nullptr;
_set_static(false);
first_time_kinematic = false;
linear_damp = -1;
@@ -695,9 +695,9 @@ Body2DSW::Body2DSW() :
first_integration = false;
still_time = 0;
- continuous_cd_mode = Physics2DServer::CCD_MODE_DISABLED;
+ continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED;
can_sleep = true;
- fi_callback = NULL;
+ fi_callback = nullptr;
}
Body2DSW::~Body2DSW() {
@@ -706,22 +706,22 @@ Body2DSW::~Body2DSW() {
memdelete(fi_callback);
}
-Physics2DDirectBodyStateSW *Physics2DDirectBodyStateSW::singleton = NULL;
+PhysicsDirectBodyState2DSW *PhysicsDirectBodyState2DSW::singleton = nullptr;
-Physics2DDirectSpaceState *Physics2DDirectBodyStateSW::get_space_state() {
+PhysicsDirectSpaceState2D *PhysicsDirectBodyState2DSW::get_space_state() {
return body->get_space()->get_direct_state();
}
-Variant Physics2DDirectBodyStateSW::get_contact_collider_shape_metadata(int p_contact_idx) const {
+Variant PhysicsDirectBodyState2DSW::get_contact_collider_shape_metadata(int p_contact_idx) const {
ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Variant());
- if (!Physics2DServerSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) {
+ if (!PhysicsServer2DSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) {
return Variant();
}
- Body2DSW *other = Physics2DServerSW::singletonsw->body_owner.getornull(body->contacts[p_contact_idx].collider);
+ Body2DSW *other = PhysicsServer2DSW::singletonsw->body_owner.getornull(body->contacts[p_contact_idx].collider);
int sidx = body->contacts[p_contact_idx].collider_shape;
if (sidx < 0 || sidx >= other->get_shape_count()) {
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index ea07b8260c..0514b263b4 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -39,7 +39,7 @@ class Constraint2DSW;
class Body2DSW : public CollisionObject2DSW {
- Physics2DServer::BodyMode mode;
+ PhysicsServer2D::BodyMode mode;
Vector2 biased_linear_velocity;
real_t biased_angular_velocity;
@@ -74,7 +74,7 @@ class Body2DSW : public CollisionObject2DSW {
SelfList<Body2DSW> direct_state_query_list;
VSet<RID> exceptions;
- Physics2DServer::CCDMode continuous_cd_mode;
+ PhysicsServer2D::CCDMode continuous_cd_mode;
bool omit_force_integration;
bool active;
bool can_sleep;
@@ -132,7 +132,7 @@ class Body2DSW : public CollisionObject2DSW {
_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area);
- friend class Physics2DDirectBodyStateSW; // i give up, too many functions to expose
+ 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());
@@ -158,7 +158,7 @@ public:
_FORCE_INLINE_ void set_max_contacts_reported(int p_size) {
contacts.resize(p_size);
contact_count = 0;
- if (mode == Physics2DServer::BODY_MODE_KINEMATIC && p_size) set_active(true);
+ if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC && p_size) set_active(true);
}
_FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }
@@ -224,19 +224,19 @@ public:
_FORCE_INLINE_ bool is_active() const { return active; }
_FORCE_INLINE_ void wakeup() {
- if ((!get_space()) || mode == Physics2DServer::BODY_MODE_STATIC || mode == Physics2DServer::BODY_MODE_KINEMATIC)
+ if ((!get_space()) || mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC)
return;
set_active(true);
}
- void set_param(Physics2DServer::BodyParameter p_param, real_t);
- real_t get_param(Physics2DServer::BodyParameter p_param) const;
+ void set_param(PhysicsServer2D::BodyParameter p_param, real_t);
+ real_t get_param(PhysicsServer2D::BodyParameter p_param) const;
- void set_mode(Physics2DServer::BodyMode p_mode);
- Physics2DServer::BodyMode get_mode() const;
+ void set_mode(PhysicsServer2D::BodyMode p_mode);
+ PhysicsServer2D::BodyMode get_mode() const;
- void set_state(Physics2DServer::BodyState p_state, const Variant &p_variant);
- Variant get_state(Physics2DServer::BodyState p_state) const;
+ void set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer2D::BodyState p_state) const;
void set_applied_force(const Vector2 &p_force) { applied_force = p_force; }
Vector2 get_applied_force() const { return applied_force; }
@@ -258,8 +258,8 @@ public:
applied_torque += p_torque;
}
- _FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode = p_mode; }
- _FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; }
+ _FORCE_INLINE_ void set_continuous_collision_detection_mode(PhysicsServer2D::CCDMode p_mode) { continuous_cd_mode = p_mode; }
+ _FORCE_INLINE_ PhysicsServer2D::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; }
void set_space(Space2DSW *p_space);
@@ -278,9 +278,9 @@ public:
_FORCE_INLINE_ Vector2 get_motion() const {
- if (mode > Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (mode > PhysicsServer2D::BODY_MODE_KINEMATIC) {
return new_transform.get_origin() - get_transform().get_origin();
- } else if (mode == Physics2DServer::BODY_MODE_KINEMATIC) {
+ } else if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) {
return get_transform().get_origin() - new_transform.get_origin(); //kinematic simulates forward
}
return Vector2();
@@ -341,12 +341,12 @@ void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_no
c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
}
-class Physics2DDirectBodyStateSW : public Physics2DDirectBodyState {
+class PhysicsDirectBodyState2DSW : public PhysicsDirectBodyState2D {
- GDCLASS(Physics2DDirectBodyStateSW, Physics2DDirectBodyState);
+ GDCLASS(PhysicsDirectBodyState2DSW, PhysicsDirectBodyState2D);
public:
- static Physics2DDirectBodyStateSW *singleton;
+ static PhysicsDirectBodyState2DSW *singleton;
Body2DSW *body;
real_t step;
@@ -363,7 +363,7 @@ public:
virtual void set_angular_velocity(real_t p_velocity) { body->set_angular_velocity(p_velocity); }
virtual real_t get_angular_velocity() const { return body->get_angular_velocity(); }
- virtual void set_transform(const Transform2D &p_transform) { body->set_state(Physics2DServer::BODY_STATE_TRANSFORM, p_transform); }
+ virtual void set_transform(const Transform2D &p_transform) { body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform); }
virtual Transform2D get_transform() const { return body->get_transform(); }
virtual void add_central_force(const Vector2 &p_force) { body->add_central_force(p_force); }
@@ -414,12 +414,12 @@ public:
return body->contacts[p_contact_idx].collider_velocity_at_pos;
}
- virtual Physics2DDirectSpaceState *get_space_state();
+ virtual PhysicsDirectSpaceState2D *get_space_state();
virtual real_t get_step() const { return step; }
- Physics2DDirectBodyStateSW() {
+ PhysicsDirectBodyState2DSW() {
singleton = this;
- body = NULL;
+ body = nullptr;
}
};
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index 38f33134a5..f38a76cff6 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -230,7 +230,7 @@ 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() <= Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode() <= Physics2DServer::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()) || (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)) {
collided = false;
return false;
}
@@ -258,10 +258,10 @@ bool BodyPair2DSW::setup(real_t p_step) {
Vector2 motion_A, motion_B;
- if (A->get_continuous_collision_detection_mode() == Physics2DServer::CCD_MODE_CAST_SHAPE) {
+ if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_SHAPE) {
motion_A = A->get_motion();
}
- if (B->get_continuous_collision_detection_mode() == Physics2DServer::CCD_MODE_CAST_SHAPE) {
+ if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_SHAPE) {
motion_B = B->get_motion();
}
//faster to set than to check..
@@ -273,12 +273,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
//test ccd (currently just a raycast)
- if (A->get_continuous_collision_detection_mode() == Physics2DServer::CCD_MODE_CAST_RAY && A->get_mode() > Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
if (_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B))
collided = true;
}
- if (B->get_continuous_collision_detection_mode() == Physics2DServer::CCD_MODE_CAST_RAY && B->get_mode() > Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
if (_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A, true))
collided = true;
}
@@ -405,7 +405,7 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
- if ((A->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC)) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
c.active = false;
collided = false;
continue;
diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp
index 11bf8712ac..5e3a13f4dd 100644
--- a/servers/physics_2d/broad_phase_2d_basic.cpp
+++ b/servers/physics_2d/broad_phase_2d_basic.cpp
@@ -65,7 +65,7 @@ void BroadPhase2DBasic::remove(ID p_id) {
CollisionObject2DSW *BroadPhase2DBasic::get_object(ID p_id) const {
const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, NULL);
+ ERR_FAIL_COND_V(!E, nullptr);
return E->get().owner;
}
bool BroadPhase2DBasic::is_static(ID p_id) const {
@@ -158,7 +158,7 @@ void BroadPhase2DBasic::update() {
if (pair_ok && !E) {
- void *data = NULL;
+ void *data = nullptr;
if (pair_callback)
data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, unpair_userdata);
pair_map.insert(key, data);
@@ -175,8 +175,8 @@ BroadPhase2DSW *BroadPhase2DBasic::_create() {
BroadPhase2DBasic::BroadPhase2DBasic() {
current = 1;
- unpair_callback = NULL;
- unpair_userdata = NULL;
- pair_callback = NULL;
- pair_userdata = NULL;
+ unpair_callback = nullptr;
+ unpair_userdata = nullptr;
+ pair_callback = nullptr;
+ pair_userdata = nullptr;
}
diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_basic.h
index fea5668c89..7d02590af9 100644
--- a/servers/physics_2d/broad_phase_2d_basic.h
+++ b/servers/physics_2d/broad_phase_2d_basic.h
@@ -91,8 +91,8 @@ public:
virtual bool is_static(ID p_id) const;
virtual int get_subindex(ID p_id) const;
- virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = NULL);
- virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = NULL);
+ virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+ virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 711ff9f1f7..2cb021258a 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -394,7 +394,7 @@ void BroadPhase2DHashGrid::remove(ID p_id) {
CollisionObject2DSW *BroadPhase2DHashGrid::get_object(ID p_id) const {
const Map<ID, Element>::Element *E = element_map.find(p_id);
- ERR_FAIL_COND_V(!E, NULL);
+ ERR_FAIL_COND_V(!E, nullptr);
return E->get().owner;
}
bool BroadPhase2DHashGrid::is_static(ID p_id) const {
@@ -646,7 +646,7 @@ BroadPhase2DHashGrid::BroadPhase2DHashGrid() {
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/large_object_surface_threshold_in_cells", PropertyInfo(Variant::INT, "physics/2d/large_object_surface_threshold_in_cells", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"));
for (uint32_t i = 0; i < hash_table_size; i++)
- hash_table[i] = NULL;
+ hash_table[i] = nullptr;
pass = 1;
current = 0;
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
index e75b51c19d..dc29d0c619 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.h
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.h
@@ -44,7 +44,7 @@ class BroadPhase2DHashGrid : public BroadPhase2DSW {
PairData() {
colliding = false;
rc = 1;
- ud = NULL;
+ ud = nullptr;
}
};
@@ -177,8 +177,8 @@ public:
virtual bool is_static(ID p_id) const;
virtual int get_subindex(ID p_id) const;
- virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = NULL);
- virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = NULL);
+ virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+ virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/broad_phase_2d_sw.cpp
index c9e1dd8758..5ba557e70a 100644
--- a/servers/physics_2d/broad_phase_2d_sw.cpp
+++ b/servers/physics_2d/broad_phase_2d_sw.cpp
@@ -30,7 +30,7 @@
#include "broad_phase_2d_sw.h"
-BroadPhase2DSW::CreateFunction BroadPhase2DSW::create_func = NULL;
+BroadPhase2DSW::CreateFunction BroadPhase2DSW::create_func = nullptr;
BroadPhase2DSW::~BroadPhase2DSW() {
}
diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h
index c7777d9d92..5e42c72d83 100644
--- a/servers/physics_2d/broad_phase_2d_sw.h
+++ b/servers/physics_2d/broad_phase_2d_sw.h
@@ -58,8 +58,8 @@ public:
virtual bool is_static(ID p_id) const = 0;
virtual int get_subindex(ID p_id) const = 0;
- virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = NULL) = 0;
- virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = NULL) = 0;
+ virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
+ virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0;
virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0;
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 8fb3296be6..0ec293c042 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "collision_object_2d_sw.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/physics_2d/physics_server_2d_sw.h"
#include "space_2d_sw.h"
void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform, bool p_disabled) {
@@ -46,7 +46,7 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
- Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
// _update_shapes();
// _shapes_changed();
@@ -61,7 +61,7 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) {
p_shape->add_owner(this);
if (!pending_shape_update_list.in_list()) {
- Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
// _update_shapes();
// _shapes_changed();
@@ -81,7 +81,7 @@ void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_
shapes.write[p_index].xform_inv = p_transform.affine_inverse();
if (!pending_shape_update_list.in_list()) {
- Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
// _update_shapes();
// _shapes_changed();
@@ -103,12 +103,12 @@ void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) {
space->get_broadphase()->remove(shape.bpid);
shape.bpid = 0;
if (!pending_shape_update_list.in_list()) {
- Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
//_update_shapes();
} else if (!p_disabled && shape.bpid == 0) {
if (!pending_shape_update_list.in_list()) {
- Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
//_update_shapes(); // automatically adds shape with bpid == 0
}
@@ -142,7 +142,7 @@ void CollisionObject2DSW::remove_shape(int p_index) {
shapes.remove(p_index);
if (!pending_shape_update_list.in_list()) {
- Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
+ PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list);
}
// _update_shapes();
// _shapes_changed();
@@ -266,7 +266,7 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) :
_static = true;
type = p_type;
- space = NULL;
+ space = nullptr;
collision_mask = 1;
collision_layer = 1;
pickable = true;
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index 3f9d19bbab..98105a7c0e 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -33,7 +33,7 @@
#include "broad_phase_2d_sw.h"
#include "core/self_list.h"
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
#include "shape_2d_sw.h"
class Space2DSW;
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index da67fcc770..a954cb3de3 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/collision_solver_2d_sat.cpp
@@ -145,7 +145,7 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po
_generate_contacts_point_edge,
},
{
- 0,
+ nullptr,
_generate_contacts_edge_edge,
}
};
@@ -1042,16 +1042,16 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const
bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
- Physics2DServer::ShapeType type_A = p_shape_A->get_type();
+ PhysicsServer2D::ShapeType type_A = p_shape_A->get_type();
- ERR_FAIL_COND_V(type_A == Physics2DServer::SHAPE_LINE, false);
- //ERR_FAIL_COND_V(type_A==Physics2DServer::SHAPE_RAY,false);
+ ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_LINE, false);
+ //ERR_FAIL_COND_V(type_A==PhysicsServer2D::SHAPE_RAY,false);
ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
- Physics2DServer::ShapeType type_B = p_shape_B->get_type();
+ PhysicsServer2D::ShapeType type_B = p_shape_B->get_type();
- ERR_FAIL_COND_V(type_B == Physics2DServer::SHAPE_LINE, false);
- //ERR_FAIL_COND_V(type_B==Physics2DServer::SHAPE_RAY,false);
+ ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_LINE, false);
+ //ERR_FAIL_COND_V(type_B==PhysicsServer2D::SHAPE_RAY,false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
static const CollisionFunc collision_table[5][5] = {
@@ -1060,25 +1060,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<false, false, false>,
_collision_segment_capsule<false, false, false>,
_collision_segment_convex_polygon<false, false, false> },
- { 0,
+ { nullptr,
_collision_circle_circle<false, false, false>,
_collision_circle_rectangle<false, false, false>,
_collision_circle_capsule<false, false, false>,
_collision_circle_convex_polygon<false, false, false> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<false, false, false>,
_collision_rectangle_capsule<false, false, false>,
_collision_rectangle_convex_polygon<false, false, false> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<false, false, false>,
_collision_capsule_convex_polygon<false, false, false> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<false, false, false> }
};
@@ -1089,25 +1089,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<true, false, false>,
_collision_segment_capsule<true, false, false>,
_collision_segment_convex_polygon<true, false, false> },
- { 0,
+ { nullptr,
_collision_circle_circle<true, false, false>,
_collision_circle_rectangle<true, false, false>,
_collision_circle_capsule<true, false, false>,
_collision_circle_convex_polygon<true, false, false> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<true, false, false>,
_collision_rectangle_capsule<true, false, false>,
_collision_rectangle_convex_polygon<true, false, false> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<true, false, false>,
_collision_capsule_convex_polygon<true, false, false> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<true, false, false> }
};
@@ -1118,25 +1118,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<false, true, false>,
_collision_segment_capsule<false, true, false>,
_collision_segment_convex_polygon<false, true, false> },
- { 0,
+ { nullptr,
_collision_circle_circle<false, true, false>,
_collision_circle_rectangle<false, true, false>,
_collision_circle_capsule<false, true, false>,
_collision_circle_convex_polygon<false, true, false> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<false, true, false>,
_collision_rectangle_capsule<false, true, false>,
_collision_rectangle_convex_polygon<false, true, false> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<false, true, false>,
_collision_capsule_convex_polygon<false, true, false> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<false, true, false> }
};
@@ -1147,25 +1147,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<true, true, false>,
_collision_segment_capsule<true, true, false>,
_collision_segment_convex_polygon<true, true, false> },
- { 0,
+ { nullptr,
_collision_circle_circle<true, true, false>,
_collision_circle_rectangle<true, true, false>,
_collision_circle_capsule<true, true, false>,
_collision_circle_convex_polygon<true, true, false> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<true, true, false>,
_collision_rectangle_capsule<true, true, false>,
_collision_rectangle_convex_polygon<true, true, false> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<true, true, false>,
_collision_capsule_convex_polygon<true, true, false> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<true, true, false> }
};
@@ -1176,25 +1176,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<false, false, true>,
_collision_segment_capsule<false, false, true>,
_collision_segment_convex_polygon<false, false, true> },
- { 0,
+ { nullptr,
_collision_circle_circle<false, false, true>,
_collision_circle_rectangle<false, false, true>,
_collision_circle_capsule<false, false, true>,
_collision_circle_convex_polygon<false, false, true> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<false, false, true>,
_collision_rectangle_capsule<false, false, true>,
_collision_rectangle_convex_polygon<false, false, true> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<false, false, true>,
_collision_capsule_convex_polygon<false, false, true> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<false, false, true> }
};
@@ -1205,25 +1205,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<true, false, true>,
_collision_segment_capsule<true, false, true>,
_collision_segment_convex_polygon<true, false, true> },
- { 0,
+ { nullptr,
_collision_circle_circle<true, false, true>,
_collision_circle_rectangle<true, false, true>,
_collision_circle_capsule<true, false, true>,
_collision_circle_convex_polygon<true, false, true> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<true, false, true>,
_collision_rectangle_capsule<true, false, true>,
_collision_rectangle_convex_polygon<true, false, true> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<true, false, true>,
_collision_capsule_convex_polygon<true, false, true> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<true, false, true> }
};
@@ -1234,25 +1234,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<false, true, true>,
_collision_segment_capsule<false, true, true>,
_collision_segment_convex_polygon<false, true, true> },
- { 0,
+ { nullptr,
_collision_circle_circle<false, true, true>,
_collision_circle_rectangle<false, true, true>,
_collision_circle_capsule<false, true, true>,
_collision_circle_convex_polygon<false, true, true> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<false, true, true>,
_collision_rectangle_capsule<false, true, true>,
_collision_rectangle_convex_polygon<false, true, true> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<false, true, true>,
_collision_capsule_convex_polygon<false, true, true> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<false, true, true> }
};
@@ -1263,25 +1263,25 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
_collision_segment_rectangle<true, true, true>,
_collision_segment_capsule<true, true, true>,
_collision_segment_convex_polygon<true, true, true> },
- { 0,
+ { nullptr,
_collision_circle_circle<true, true, true>,
_collision_circle_rectangle<true, true, true>,
_collision_circle_capsule<true, true, true>,
_collision_circle_convex_polygon<true, true, true> },
- { 0,
- 0,
+ { nullptr,
+ nullptr,
_collision_rectangle_rectangle<true, true, true>,
_collision_rectangle_capsule<true, true, true>,
_collision_rectangle_convex_polygon<true, true, true> },
- { 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
_collision_capsule_capsule<true, true, true>,
_collision_capsule_convex_polygon<true, true, true> },
- { 0,
- 0,
- 0,
- 0,
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
_collision_convex_polygon_convex_polygon<true, true, true> }
};
diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/collision_solver_2d_sat.h
index 105cb9104d..6bb485f561 100644
--- a/servers/physics_2d/collision_solver_2d_sat.h
+++ b/servers/physics_2d/collision_solver_2d_sat.h
@@ -33,6 +33,6 @@
#include "collision_solver_2d_sw.h"
-bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector2 *sep_axis = NULL, real_t p_margin_A = 0, real_t p_margin_B = 0);
+bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
#endif // COLLISION_SOLVER_2D_SAT_H
diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp
index 60cca6f825..f117dcbfe5 100644
--- a/servers/physics_2d/collision_solver_2d_sw.cpp
+++ b/servers/physics_2d/collision_solver_2d_sw.cpp
@@ -37,7 +37,7 @@
bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
const LineShape2DSW *line = static_cast<const LineShape2DSW *>(p_shape_A);
- if (p_shape_B->get_type() == Physics2DServer::SHAPE_LINE)
+ if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_LINE)
return false;
Vector2 n = p_transform_A.basis_xform(line->get_normal()).normalized();
@@ -75,7 +75,7 @@ bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Tr
bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis) {
const RayShape2DSW *ray = static_cast<const RayShape2DSW *>(p_shape_A);
- if (p_shape_B->get_type() == Physics2DServer::SHAPE_RAY)
+ if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_RAY)
return false;
Vector2 from = p_transform_A.get_origin();
@@ -195,8 +195,8 @@ bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transf
bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {
- Physics2DServer::ShapeType type_A = p_shape_A->get_type();
- Physics2DServer::ShapeType type_B = p_shape_B->get_type();
+ PhysicsServer2D::ShapeType type_A = p_shape_A->get_type();
+ PhysicsServer2D::ShapeType type_B = p_shape_B->get_type();
bool concave_A = p_shape_A->is_concave();
bool concave_B = p_shape_B->is_concave();
real_t margin_A = p_margin_A, margin_B = p_margin_B;
@@ -210,9 +210,9 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
swap = true;
}
- if (type_A == Physics2DServer::SHAPE_LINE) {
+ if (type_A == PhysicsServer2D::SHAPE_LINE) {
- if (type_B == Physics2DServer::SHAPE_LINE || type_B == Physics2DServer::SHAPE_RAY) {
+ if (type_B == PhysicsServer2D::SHAPE_LINE || type_B == PhysicsServer2D::SHAPE_RAY) {
return false;
}
@@ -222,9 +222,9 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
return solve_static_line(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
- } else if (type_A == Physics2DServer::SHAPE_RAY) {
+ } else if (type_A == PhysicsServer2D::SHAPE_RAY) {
- if (type_B == Physics2DServer::SHAPE_RAY) {
+ if (type_B == PhysicsServer2D::SHAPE_RAY) {
return false; //no ray-ray
}
diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h
index e73ee8fd7e..f39cfee0a9 100644
--- a/servers/physics_2d/collision_solver_2d_sw.h
+++ b/servers/physics_2d/collision_solver_2d_sw.h
@@ -40,11 +40,11 @@ public:
private:
static bool solve_static_line(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static void concave_callback(void *p_userdata, Shape2DSW *p_convex);
- static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = NULL, real_t p_margin_A = 0, real_t p_margin_B = 0);
- static bool solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = NULL);
+ static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
+ static bool solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis = nullptr);
public:
- static bool solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *sep_axis = NULL, real_t p_margin_A = 0, real_t p_margin_B = 0);
+ static bool solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
};
#endif // COLLISION_SOLVER_2D_SW_H
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index b5c994cbdd..f8eb16214f 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/constraint_2d_sw.h
@@ -45,7 +45,7 @@ class Constraint2DSW {
RID self;
protected:
- Constraint2DSW(Body2DSW **p_body_ptr = NULL, int p_body_count = 0) {
+ Constraint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) {
_body_ptr = p_body_ptr;
_body_count = p_body_count;
island_step = 0;
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index 02b3502242..4524629d50 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -171,15 +171,15 @@ void PinJoint2DSW::solve(real_t p_step) {
P += impulse;
}
-void PinJoint2DSW::set_param(Physics2DServer::PinJointParam p_param, real_t p_value) {
+void PinJoint2DSW::set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value) {
- if (p_param == Physics2DServer::PIN_JOINT_SOFTNESS)
+ if (p_param == PhysicsServer2D::PIN_JOINT_SOFTNESS)
softness = p_value;
}
-real_t PinJoint2DSW::get_param(Physics2DServer::PinJointParam p_param) const {
+real_t PinJoint2DSW::get_param(PhysicsServer2D::PinJointParam p_param) const {
- if (p_param == Physics2DServer::PIN_JOINT_SOFTNESS)
+ if (p_param == PhysicsServer2D::PIN_JOINT_SOFTNESS)
return softness;
ERR_FAIL_V(0);
}
@@ -396,38 +396,38 @@ void DampedSpringJoint2DSW::solve(real_t p_step) {
B->apply_impulse(rB, j);
}
-void DampedSpringJoint2DSW::set_param(Physics2DServer::DampedStringParam p_param, real_t p_value) {
+void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedStringParam p_param, real_t p_value) {
switch (p_param) {
- case Physics2DServer::DAMPED_STRING_REST_LENGTH: {
+ case PhysicsServer2D::DAMPED_STRING_REST_LENGTH: {
rest_length = p_value;
} break;
- case Physics2DServer::DAMPED_STRING_DAMPING: {
+ case PhysicsServer2D::DAMPED_STRING_DAMPING: {
damping = p_value;
} break;
- case Physics2DServer::DAMPED_STRING_STIFFNESS: {
+ case PhysicsServer2D::DAMPED_STRING_STIFFNESS: {
stiffness = p_value;
} break;
}
}
-real_t DampedSpringJoint2DSW::get_param(Physics2DServer::DampedStringParam p_param) const {
+real_t DampedSpringJoint2DSW::get_param(PhysicsServer2D::DampedStringParam p_param) const {
switch (p_param) {
- case Physics2DServer::DAMPED_STRING_REST_LENGTH: {
+ case PhysicsServer2D::DAMPED_STRING_REST_LENGTH: {
return rest_length;
} break;
- case Physics2DServer::DAMPED_STRING_DAMPING: {
+ case PhysicsServer2D::DAMPED_STRING_DAMPING: {
return damping;
} break;
- case Physics2DServer::DAMPED_STRING_STIFFNESS: {
+ case PhysicsServer2D::DAMPED_STRING_STIFFNESS: {
return stiffness;
} break;
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h
index 3e8fc1a29f..a0d25dc70d 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/joints_2d_sw.h
@@ -50,8 +50,8 @@ 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 Physics2DServer::JointType get_type() const = 0;
- Joint2DSW(Body2DSW **p_body_ptr = NULL, int p_body_count = 0) :
+ virtual PhysicsServer2D::JointType get_type() const = 0;
+ 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;
@@ -78,15 +78,15 @@ class PinJoint2DSW : public Joint2DSW {
real_t softness;
public:
- virtual Physics2DServer::JointType get_type() const { return Physics2DServer::JOINT_PIN; }
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_PIN; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
- void set_param(Physics2DServer::PinJointParam p_param, real_t p_value);
- real_t get_param(Physics2DServer::PinJointParam p_param) const;
+ void set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer2D::PinJointParam p_param) const;
- PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = NULL);
+ PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = nullptr);
~PinJoint2DSW();
};
@@ -116,7 +116,7 @@ class GrooveJoint2DSW : public Joint2DSW {
bool correct;
public:
- virtual Physics2DServer::JointType get_type() const { return Physics2DServer::JOINT_GROOVE; }
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_GROOVE; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
@@ -150,13 +150,13 @@ class DampedSpringJoint2DSW : public Joint2DSW {
real_t v_coef;
public:
- virtual Physics2DServer::JointType get_type() const { return Physics2DServer::JOINT_DAMPED_SPRING; }
+ virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_DAMPED_SPRING; }
virtual bool setup(real_t p_step);
virtual void solve(real_t p_step);
- void set_param(Physics2DServer::DampedStringParam p_param, real_t p_value);
- real_t get_param(Physics2DServer::DampedStringParam p_param) const;
+ void set_param(PhysicsServer2D::DampedStringParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer2D::DampedStringParam p_param) const;
DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b);
~DampedSpringJoint2DSW();
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
deleted file mode 100644
index baeb3f76b0..0000000000
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ /dev/null
@@ -1,1464 +0,0 @@
-/*************************************************************************/
-/* physics_2d_server_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_2d_server_sw.h"
-#include "broad_phase_2d_basic.h"
-#include "broad_phase_2d_hash_grid.h"
-#include "collision_solver_2d_sw.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-
-#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 Physics2DServerSW::_shape_create(ShapeType p_shape) {
-
- Shape2DSW *shape = NULL;
- switch (p_shape) {
-
- case SHAPE_LINE: {
-
- shape = memnew(LineShape2DSW);
- } break;
- case SHAPE_RAY: {
-
- shape = memnew(RayShape2DSW);
- } break;
- case SHAPE_SEGMENT: {
-
- shape = memnew(SegmentShape2DSW);
- } break;
- case SHAPE_CIRCLE: {
-
- shape = memnew(CircleShape2DSW);
- } break;
- case SHAPE_RECTANGLE: {
-
- shape = memnew(RectangleShape2DSW);
- } break;
- case SHAPE_CAPSULE: {
-
- shape = memnew(CapsuleShape2DSW);
- } break;
- case SHAPE_CONVEX_POLYGON: {
-
- shape = memnew(ConvexPolygonShape2DSW);
- } break;
- case SHAPE_CONCAVE_POLYGON: {
-
- shape = memnew(ConcavePolygonShape2DSW);
- } break;
- case SHAPE_CUSTOM: {
-
- ERR_FAIL_V(RID());
-
- } break;
- }
-
- RID id = shape_owner.make_rid(shape);
- shape->set_self(id);
-
- return id;
-}
-
-RID Physics2DServerSW::line_shape_create() {
-
- return _shape_create(SHAPE_LINE);
-}
-
-RID Physics2DServerSW::ray_shape_create() {
-
- return _shape_create(SHAPE_RAY);
-}
-RID Physics2DServerSW::segment_shape_create() {
-
- return _shape_create(SHAPE_SEGMENT);
-}
-RID Physics2DServerSW::circle_shape_create() {
-
- return _shape_create(SHAPE_CIRCLE);
-}
-RID Physics2DServerSW::rectangle_shape_create() {
-
- return _shape_create(SHAPE_RECTANGLE);
-}
-RID Physics2DServerSW::capsule_shape_create() {
-
- return _shape_create(SHAPE_CAPSULE);
-}
-
-RID Physics2DServerSW::convex_polygon_shape_create() {
-
- return _shape_create(SHAPE_CONVEX_POLYGON);
-}
-RID Physics2DServerSW::concave_polygon_shape_create() {
-
- return _shape_create(SHAPE_CONCAVE_POLYGON);
-}
-
-void Physics2DServerSW::shape_set_data(RID p_shape, const Variant &p_data) {
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- shape->set_data(p_data);
-};
-
-void Physics2DServerSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- shape->set_custom_bias(p_bias);
-}
-
-Physics2DServer::ShapeType Physics2DServerSW::shape_get_type(RID p_shape) const {
-
- const Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM);
- return shape->get_type();
-};
-
-Variant Physics2DServerSW::shape_get_data(RID p_shape) const {
-
- const Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, Variant());
- ERR_FAIL_COND_V(!shape->is_configured(), Variant());
- return shape->get_data();
-};
-
-real_t Physics2DServerSW::shape_get_custom_solver_bias(RID p_shape) const {
-
- const Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND_V(!shape, 0);
- return shape->get_custom_bias();
-}
-
-void Physics2DServerSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) {
-
- CollCbkData *cbk = (CollCbkData *)p_userdata;
-
- if (cbk->max == 0)
- return;
-
- if (cbk->valid_dir != Vector2()) {
- if (p_point_A.distance_squared_to(p_point_B) > cbk->valid_depth * cbk->valid_depth) {
- cbk->invalid_by_dir++;
- return;
- }
- Vector2 rel_dir = (p_point_A - p_point_B).normalized();
-
- if (cbk->valid_dir.dot(rel_dir) < Math_SQRT12) { //sqrt(2)/2.0 - 45 degrees
- cbk->invalid_by_dir++;
-
- /*
- print_line("A: "+p_point_A);
- print_line("B: "+p_point_B);
- print_line("discard too angled "+rtos(cbk->valid_dir.dot((p_point_A-p_point_B))));
- print_line("resnorm: "+(p_point_A-p_point_B).normalized());
- print_line("distance: "+rtos(p_point_A.distance_to(p_point_B)));
- */
- return;
- }
- }
-
- if (cbk->amount == cbk->max) {
- //find least deep
- real_t min_depth = 1e20;
- int min_depth_idx = 0;
- for (int i = 0; i < cbk->amount; i++) {
-
- real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]);
- if (d < min_depth) {
- min_depth = d;
- min_depth_idx = i;
- }
- }
-
- real_t d = p_point_A.distance_squared_to(p_point_B);
- if (d < min_depth)
- return;
- cbk->ptr[min_depth_idx * 2 + 0] = p_point_A;
- cbk->ptr[min_depth_idx * 2 + 1] = p_point_B;
- cbk->passed++;
-
- } else {
-
- cbk->ptr[cbk->amount * 2 + 0] = p_point_A;
- cbk->ptr[cbk->amount * 2 + 1] = p_point_B;
- cbk->amount++;
- cbk->passed++;
- }
-}
-
-bool Physics2DServerSW::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) {
-
- Shape2DSW *shape_A = shape_owner.getornull(p_shape_A);
- ERR_FAIL_COND_V(!shape_A, false);
- Shape2DSW *shape_B = shape_owner.getornull(p_shape_B);
- ERR_FAIL_COND_V(!shape_B, false);
-
- if (p_result_max == 0) {
-
- return CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, NULL, NULL);
- }
-
- CollCbkData cbk;
- cbk.max = p_result_max;
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = r_results;
-
- bool res = CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk);
- r_result_count = cbk.amount;
- return res;
-}
-
-RID Physics2DServerSW::space_create() {
-
- Space2DSW *space = memnew(Space2DSW);
- RID id = space_owner.make_rid(space);
- space->set_self(id);
- RID area_id = area_create();
- Area2DSW *area = area_owner.getornull(area_id);
- ERR_FAIL_COND_V(!area, RID());
- space->set_default_area(area);
- area->set_space(space);
- area->set_priority(-1);
-
- return id;
-};
-
-void Physics2DServerSW::space_set_active(RID p_space, bool p_active) {
-
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- if (p_active)
- active_spaces.insert(space);
- else
- active_spaces.erase(space);
-}
-
-bool Physics2DServerSW::space_is_active(RID p_space) const {
-
- const Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, false);
-
- return active_spaces.has(space);
-}
-
-void Physics2DServerSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
-
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
-
- space->set_param(p_param, p_value);
-}
-
-real_t Physics2DServerSW::space_get_param(RID p_space, SpaceParameter p_param) const {
-
- const Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, 0);
- return space->get_param(p_param);
-}
-
-void Physics2DServerSW::space_set_debug_contacts(RID p_space, int p_max_contacts) {
-
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- space->set_debug_contacts(p_max_contacts);
-}
-
-Vector<Vector2> Physics2DServerSW::space_get_contacts(RID p_space) const {
-
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, Vector<Vector2>());
- return space->get_debug_contacts();
-}
-
-int Physics2DServerSW::space_get_contact_count(RID p_space) const {
-
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, 0);
- return space->get_debug_contact_count();
-}
-
-Physics2DDirectSpaceState *Physics2DServerSW::space_get_direct_state(RID p_space) {
-
- Space2DSW *space = space_owner.getornull(p_space);
- ERR_FAIL_COND_V(!space, NULL);
- ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), NULL, "Space state is inaccessible right now, wait for iteration or physics process notification.");
-
- return space->get_direct_state();
-}
-
-RID Physics2DServerSW::area_create() {
-
- Area2DSW *area = memnew(Area2DSW);
- RID rid = area_owner.make_rid(area);
- area->set_self(rid);
- return rid;
-};
-
-void Physics2DServerSW::area_set_space(RID p_area, RID p_space) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- Space2DSW *space = NULL;
- if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- }
-
- if (area->get_space() == space)
- return; //pointless
-
- area->clear_constraints();
- area->set_space(space);
-};
-
-RID Physics2DServerSW::area_get_space(RID p_area) const {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, RID());
-
- Space2DSW *space = area->get_space();
- if (!space)
- return RID();
- return space->get_self();
-};
-
-void Physics2DServerSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_space_override_mode(p_mode);
-}
-
-Physics2DServer::AreaSpaceOverrideMode Physics2DServerSW::area_get_space_override_mode(RID p_area) const {
-
- const Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED);
-
- return area->get_space_override_mode();
-}
-
-void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
-
- area->add_shape(shape, p_transform, p_disabled);
-}
-
-void Physics2DServerSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- ERR_FAIL_COND(!shape->is_configured());
-
- area->set_shape(p_shape_idx, shape);
-}
-void Physics2DServerSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_shape_transform(p_shape_idx, p_transform);
-}
-
-void Physics2DServerSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- ERR_FAIL_INDEX(p_shape, area->get_shape_count());
- FLUSH_QUERY_CHECK(area);
-
- area->set_shape_as_disabled(p_shape, p_disabled);
-}
-
-int Physics2DServerSW::area_get_shape_count(RID p_area) const {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, -1);
-
- return area->get_shape_count();
-}
-RID Physics2DServerSW::area_get_shape(RID p_area, int p_shape_idx) const {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, RID());
-
- Shape2DSW *shape = area->get_shape(p_shape_idx);
- ERR_FAIL_COND_V(!shape, RID());
-
- return shape->get_self();
-}
-Transform2D Physics2DServerSW::area_get_shape_transform(RID p_area, int p_shape_idx) const {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform2D());
-
- return area->get_shape_transform(p_shape_idx);
-}
-
-void Physics2DServerSW::area_remove_shape(RID p_area, int p_shape_idx) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->remove_shape(p_shape_idx);
-}
-
-void Physics2DServerSW::area_clear_shapes(RID p_area) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- while (area->get_shape_count())
- area->remove_shape(0);
-}
-
-void Physics2DServerSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
-
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_instance_id(p_id);
-}
-ObjectID Physics2DServerSW::area_get_object_instance_id(RID p_area) const {
-
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, ObjectID());
- return area->get_instance_id();
-}
-
-void Physics2DServerSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) {
-
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_canvas_instance_id(p_id);
-}
-ObjectID Physics2DServerSW::area_get_canvas_instance_id(RID p_area) const {
-
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, ObjectID());
- return area->get_canvas_instance_id();
-}
-
-void Physics2DServerSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
-
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_param(p_param, p_value);
-};
-
-void Physics2DServerSW::area_set_transform(RID p_area, const Transform2D &p_transform) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_transform(p_transform);
-};
-
-Variant Physics2DServerSW::area_get_param(RID p_area, AreaParameter p_param) const {
-
- if (space_owner.owns(p_area)) {
- Space2DSW *space = space_owner.getornull(p_area);
- p_area = space->get_default_area()->get_self();
- }
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Variant());
-
- return area->get_param(p_param);
-};
-
-Transform2D Physics2DServerSW::area_get_transform(RID p_area) const {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND_V(!area, Transform2D());
-
- return area->get_transform();
-};
-
-void Physics2DServerSW::area_set_pickable(RID p_area, bool p_pickable) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- area->set_pickable(p_pickable);
-}
-
-void Physics2DServerSW::area_set_monitorable(RID p_area, bool p_monitorable) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
- FLUSH_QUERY_CHECK(area);
-
- area->set_monitorable(p_monitorable);
-}
-
-void Physics2DServerSW::area_set_collision_mask(RID p_area, uint32_t p_mask) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_collision_mask(p_mask);
-}
-
-void Physics2DServerSW::area_set_collision_layer(RID p_area, uint32_t p_layer) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_collision_layer(p_layer);
-}
-
-void Physics2DServerSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
-}
-
-void Physics2DServerSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
-
- Area2DSW *area = area_owner.getornull(p_area);
- ERR_FAIL_COND(!area);
-
- area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
-}
-
-/* BODY API */
-
-RID Physics2DServerSW::body_create() {
-
- Body2DSW *body = memnew(Body2DSW);
- RID rid = body_owner.make_rid(body);
- body->set_self(rid);
- return rid;
-}
-
-void Physics2DServerSW::body_set_space(RID p_body, RID p_space) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- Space2DSW *space = NULL;
- if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
- ERR_FAIL_COND(!space);
- }
-
- if (body->get_space() == space)
- return; //pointless
-
- body->clear_constraint_map();
- body->set_space(space);
-};
-
-RID Physics2DServerSW::body_get_space(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, RID());
-
- Space2DSW *space = body->get_space();
- if (!space)
- return RID();
- return space->get_self();
-};
-
-void Physics2DServerSW::body_set_mode(RID p_body, BodyMode p_mode) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- FLUSH_QUERY_CHECK(body);
-
- body->set_mode(p_mode);
-};
-
-Physics2DServer::BodyMode Physics2DServerSW::body_get_mode(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
-
- return body->get_mode();
-};
-
-void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
-
- body->add_shape(shape, p_transform, p_disabled);
-}
-
-void Physics2DServerSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- Shape2DSW *shape = shape_owner.getornull(p_shape);
- ERR_FAIL_COND(!shape);
- ERR_FAIL_COND(!shape->is_configured());
-
- body->set_shape(p_shape_idx, shape);
-}
-void Physics2DServerSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_shape_transform(p_shape_idx, p_transform);
-}
-
-void Physics2DServerSW::body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_shape_metadata(p_shape_idx, p_metadata);
-}
-
-Variant Physics2DServerSW::body_get_shape_metadata(RID p_body, int p_shape_idx) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Variant());
- return body->get_shape_metadata(p_shape_idx);
-}
-
-int Physics2DServerSW::body_get_shape_count(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, -1);
-
- return body->get_shape_count();
-}
-RID Physics2DServerSW::body_get_shape(RID p_body, int p_shape_idx) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, RID());
-
- Shape2DSW *shape = body->get_shape(p_shape_idx);
- ERR_FAIL_COND_V(!shape, RID());
-
- return shape->get_self();
-}
-Transform2D Physics2DServerSW::body_get_shape_transform(RID p_body, int p_shape_idx) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Transform2D());
-
- return body->get_shape_transform(p_shape_idx);
-}
-
-void Physics2DServerSW::body_remove_shape(RID p_body, int p_shape_idx) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->remove_shape(p_shape_idx);
-}
-
-void Physics2DServerSW::body_clear_shapes(RID p_body) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- while (body->get_shape_count())
- body->remove_shape(0);
-}
-
-void Physics2DServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
- FLUSH_QUERY_CHECK(body);
-
- body->set_shape_as_disabled(p_shape_idx, p_disabled);
-}
-void Physics2DServerSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
- FLUSH_QUERY_CHECK(body);
-
- body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin);
-}
-
-void Physics2DServerSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_continuous_collision_detection_mode(p_mode);
-}
-
-Physics2DServerSW::CCDMode Physics2DServerSW::body_get_continuous_collision_detection_mode(RID p_body) const {
-
- const Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED);
-
- return body->get_continuous_collision_detection_mode();
-}
-
-void Physics2DServerSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_instance_id(p_id);
-};
-
-ObjectID Physics2DServerSW::body_get_object_instance_id(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, ObjectID());
-
- return body->get_instance_id();
-};
-
-void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_canvas_instance_id(p_id);
-};
-
-ObjectID Physics2DServerSW::body_get_canvas_instance_id(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, ObjectID());
-
- return body->get_canvas_instance_id();
-};
-
-void Physics2DServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_collision_layer(p_layer);
-};
-
-uint32_t Physics2DServerSW::body_get_collision_layer(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_collision_layer();
-};
-
-void Physics2DServerSW::body_set_collision_mask(RID p_body, uint32_t p_mask) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_collision_mask(p_mask);
-};
-
-uint32_t Physics2DServerSW::body_get_collision_mask(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_collision_mask();
-};
-
-void Physics2DServerSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_param(p_param, p_value);
-};
-
-real_t Physics2DServerSW::body_get_param(RID p_body, BodyParameter p_param) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_param(p_param);
-};
-
-void Physics2DServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_state(p_state, p_variant);
-};
-
-Variant Physics2DServerSW::body_get_state(RID p_body, BodyState p_state) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Variant());
-
- return body->get_state(p_state);
-};
-
-void Physics2DServerSW::body_set_applied_force(RID p_body, const Vector2 &p_force) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_applied_force(p_force);
- body->wakeup();
-};
-
-Vector2 Physics2DServerSW::body_get_applied_force(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, Vector2());
- return body->get_applied_force();
-};
-
-void Physics2DServerSW::body_set_applied_torque(RID p_body, real_t p_torque) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_applied_torque(p_torque);
- body->wakeup();
-};
-
-real_t Physics2DServerSW::body_get_applied_torque(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
-
- return body->get_applied_torque();
-};
-
-void Physics2DServerSW::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->apply_central_impulse(p_impulse);
- body->wakeup();
-}
-
-void Physics2DServerSW::body_apply_torque_impulse(RID p_body, real_t p_torque) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_torque_impulse(p_torque);
-}
-
-void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- body->apply_impulse(p_pos, p_impulse);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_add_central_force(RID p_body, const Vector2 &p_force) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_central_force(p_force);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_force(p_offset, p_force);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_add_torque(RID p_body, real_t p_torque) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_torque(p_torque);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- _update_shapes();
-
- Vector2 v = body->get_linear_velocity();
- Vector2 axis = p_axis_velocity.normalized();
- v -= axis * axis.dot(v);
- v += p_axis_velocity;
- body->set_linear_velocity(v);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_add_collision_exception(RID p_body, RID p_body_b) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->add_exception(p_body_b);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_remove_collision_exception(RID p_body, RID p_body_b) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->remove_exception(p_body_b);
- body->wakeup();
-};
-
-void Physics2DServerSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- for (int i = 0; i < body->get_exceptions().size(); i++) {
- p_exceptions->push_back(body->get_exceptions()[i]);
- }
-};
-
-void Physics2DServerSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-};
-
-real_t Physics2DServerSW::body_get_contacts_reported_depth_threshold(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, 0);
- return 0;
-};
-
-void Physics2DServerSW::body_set_omit_force_integration(RID p_body, bool p_omit) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_omit_force_integration(p_omit);
-};
-
-bool Physics2DServerSW::body_is_omitting_force_integration(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- return body->get_omit_force_integration();
-};
-
-void Physics2DServerSW::body_set_max_contacts_reported(RID p_body, int p_contacts) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_max_contacts_reported(p_contacts);
-}
-
-int Physics2DServerSW::body_get_max_contacts_reported(RID p_body) const {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, -1);
- return body->get_max_contacts_reported();
-}
-
-void Physics2DServerSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, 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);
-}
-
-bool Physics2DServerSW::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) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false);
-
- return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
-}
-
-void Physics2DServerSW::body_set_pickable(RID p_body, bool p_pickable) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND(!body);
- body->set_pickable(p_pickable);
-}
-
-bool Physics2DServerSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- _update_shapes();
-
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
-}
-
-int Physics2DServerSW::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, float p_margin) {
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
-}
-
-Physics2DDirectBodyState *Physics2DServerSW::body_get_direct_state(RID p_body) {
-
- ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), NULL, "Body state is inaccessible right now, wait for iteration or physics process notification.");
-
- if (!body_owner.owns(p_body))
- return NULL;
-
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, NULL);
- ERR_FAIL_COND_V(!body->get_space(), NULL);
- ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), NULL, "Body state is inaccessible right now, wait for iteration or physics process notification.");
-
- direct_state->body = body;
- return direct_state;
-}
-
-/* JOINT API */
-
-void Physics2DServerSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) {
-
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
-
- switch (p_param) {
- case JOINT_PARAM_BIAS: joint->set_bias(p_value); break;
- case JOINT_PARAM_MAX_BIAS: joint->set_max_bias(p_value); break;
- case JOINT_PARAM_MAX_FORCE: joint->set_max_force(p_value); break;
- }
-}
-
-real_t Physics2DServerSW::joint_get_param(RID p_joint, JointParam p_param) const {
-
- const Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, -1);
-
- switch (p_param) {
- case JOINT_PARAM_BIAS: return joint->get_bias(); break;
- case JOINT_PARAM_MAX_BIAS: return joint->get_max_bias(); break;
- case JOINT_PARAM_MAX_FORCE: return joint->get_max_force(); break;
- }
-
- return 0;
-}
-
-void Physics2DServerSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND(!joint);
-
- joint->disable_collisions_between_bodies(p_disable);
-
- if (2 == joint->get_body_count()) {
- Body2DSW *body_a = *joint->get_body_ptr();
- Body2DSW *body_b = *(joint->get_body_ptr() + 1);
-
- if (p_disable) {
- body_add_collision_exception(body_a->get_self(), body_b->get_self());
- body_add_collision_exception(body_b->get_self(), body_a->get_self());
- } else {
- body_remove_collision_exception(body_a->get_self(), body_b->get_self());
- body_remove_collision_exception(body_b->get_self(), body_a->get_self());
- }
- }
-}
-
-bool Physics2DServerSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
- const Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, true);
-
- return joint->is_disabled_collisions_between_bodies();
-}
-
-RID Physics2DServerSW::pin_joint_create(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());
- Body2DSW *B = NULL;
- if (body_owner.owns(p_body_b)) {
- B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND_V(!B, RID());
- }
-
- Joint2DSW *joint = memnew(PinJoint2DSW(p_pos, A, B));
- RID self = joint_owner.make_rid(joint);
- joint->set_self(self);
-
- return self;
-}
-
-RID Physics2DServerSW::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) {
-
- Body2DSW *A = body_owner.getornull(p_body_a);
- ERR_FAIL_COND_V(!A, RID());
-
- Body2DSW *B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND_V(!B, RID());
-
- 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;
-}
-
-RID Physics2DServerSW::damped_spring_joint_create(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());
-
- Body2DSW *B = body_owner.getornull(p_body_b);
- ERR_FAIL_COND_V(!B, RID());
-
- 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;
-}
-
-void Physics2DServerSW::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);
-
- PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
- pin_joint->set_param(p_param, p_value);
-}
-
-real_t Physics2DServerSW::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);
-
- PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
- return pin_joint->get_param(p_param);
-}
-
-void Physics2DServerSW::damped_string_joint_set_param(RID p_joint, DampedStringParam 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);
-
- DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
- dsj->set_param(p_param, p_value);
-}
-
-real_t Physics2DServerSW::damped_string_joint_get_param(RID p_joint, DampedStringParam 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);
-
- DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
- return dsj->get_param(p_param);
-}
-
-Physics2DServer::JointType Physics2DServerSW::joint_get_type(RID p_joint) const {
-
- Joint2DSW *joint = joint_owner.getornull(p_joint);
- ERR_FAIL_COND_V(!joint, JOINT_PIN);
-
- return joint->get_type();
-}
-
-void Physics2DServerSW::free(RID p_rid) {
-
- _update_shapes(); // just in case
-
- if (shape_owner.owns(p_rid)) {
-
- Shape2DSW *shape = shape_owner.getornull(p_rid);
-
- while (shape->get_owners().size()) {
- ShapeOwner2DSW *so = shape->get_owners().front()->key();
- so->remove_shape(shape);
- }
-
- shape_owner.free(p_rid);
- memdelete(shape);
- } else if (body_owner.owns(p_rid)) {
-
- Body2DSW *body = body_owner.getornull(p_rid);
-
- /*
- if (body->get_state_query())
- _clear_query(body->get_state_query());
-
- if (body->get_direct_state_query())
- _clear_query(body->get_direct_state_query());
- */
-
- body_set_space(p_rid, RID());
-
- while (body->get_shape_count()) {
-
- body->remove_shape(0);
- }
-
- body_owner.free(p_rid);
- memdelete(body);
-
- } else if (area_owner.owns(p_rid)) {
-
- Area2DSW *area = area_owner.getornull(p_rid);
-
- /*
- if (area->get_monitor_query())
- _clear_query(area->get_monitor_query());
- */
-
- area->set_space(NULL);
-
- while (area->get_shape_count()) {
-
- area->remove_shape(0);
- }
-
- area_owner.free(p_rid);
- memdelete(area);
- } else if (space_owner.owns(p_rid)) {
-
- Space2DSW *space = space_owner.getornull(p_rid);
-
- while (space->get_objects().size()) {
- CollisionObject2DSW *co = (CollisionObject2DSW *)space->get_objects().front()->get();
- co->set_space(NULL);
- }
-
- active_spaces.erase(space);
- free(space->get_default_area()->get_self());
- space_owner.free(p_rid);
- memdelete(space);
- } else if (joint_owner.owns(p_rid)) {
-
- Joint2DSW *joint = joint_owner.getornull(p_rid);
-
- joint_owner.free(p_rid);
- memdelete(joint);
-
- } else {
-
- ERR_FAIL_MSG("Invalid ID.");
- }
-};
-
-void Physics2DServerSW::set_active(bool p_active) {
-
- active = p_active;
-};
-
-void Physics2DServerSW::init() {
-
- doing_sync = false;
- last_step = 0.001;
- iterations = 8; // 8?
- stepper = memnew(Step2DSW);
- direct_state = memnew(Physics2DDirectBodyStateSW);
-};
-
-void Physics2DServerSW::step(real_t p_step) {
-
- if (!active)
- return;
-
- _update_shapes();
-
- doing_sync = false;
-
- last_step = p_step;
- Physics2DDirectBodyStateSW::singleton->step = p_step;
- island_count = 0;
- active_objects = 0;
- collision_pairs = 0;
- for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
-
- stepper->step((Space2DSW *)E->get(), p_step, iterations);
- island_count += E->get()->get_island_count();
- active_objects += E->get()->get_active_objects();
- collision_pairs += E->get()->get_collision_pairs();
- }
-};
-
-void Physics2DServerSW::sync() {
-
- doing_sync = true;
-};
-
-void Physics2DServerSW::flush_queries() {
-
- if (!active)
- return;
-
- flushing_queries = true;
-
- uint64_t time_beg = OS::get_singleton()->get_ticks_usec();
-
- for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
-
- Space2DSW *space = (Space2DSW *)E->get();
- space->call_queries();
- }
-
- flushing_queries = false;
-
- if (EngineDebugger::is_profiling("servers")) {
-
- uint64_t total_time[Space2DSW::ELAPSED_TIME_MAX];
- static const char *time_name[Space2DSW::ELAPSED_TIME_MAX] = {
- "integrate_forces",
- "generate_islands",
- "setup_constraints",
- "solve_constraints",
- "integrate_velocities"
- };
-
- for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
- total_time[i] = 0;
- }
-
- for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
-
- for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
- total_time[i] += E->get()->get_elapsed_time(Space2DSW::ElapsedTime(i));
- }
- }
-
- Array values;
- values.resize(Space2DSW::ELAPSED_TIME_MAX * 2);
- for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
- values[i * 2 + 0] = time_name[i];
- values[i * 2 + 1] = USEC_TO_SEC(total_time[i]);
- }
- values.push_back("flush_queries");
- values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg));
-
- values.push_front("physics_2d");
- EngineDebugger::profiler_add_frame_data("servers", values);
- }
-}
-
-void Physics2DServerSW::end_sync() {
- doing_sync = false;
-}
-
-void Physics2DServerSW::finish() {
-
- memdelete(stepper);
- memdelete(direct_state);
-};
-
-void Physics2DServerSW::_update_shapes() {
-
- while (pending_shape_update_list.first()) {
- pending_shape_update_list.first()->self()->_shape_changed();
- pending_shape_update_list.remove(pending_shape_update_list.first());
- }
-}
-
-int Physics2DServerSW::get_process_info(ProcessInfo p_info) {
-
- switch (p_info) {
-
- case INFO_ACTIVE_OBJECTS: {
-
- return active_objects;
- } break;
- case INFO_COLLISION_PAIRS: {
- return collision_pairs;
- } break;
- case INFO_ISLAND_COUNT: {
-
- return island_count;
- } break;
- }
-
- return 0;
-}
-
-Physics2DServerSW *Physics2DServerSW::singletonsw = NULL;
-
-Physics2DServerSW::Physics2DServerSW() {
-
- singletonsw = this;
- BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create;
- //BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
-
- active = true;
- island_count = 0;
- active_objects = 0;
- collision_pairs = 0;
- using_threads = int(ProjectSettings::get_singleton()->get("physics/2d/thread_model")) == 2;
- flushing_queries = false;
-};
-
-Physics2DServerSW::~Physics2DServerSW(){
-
-};
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
deleted file mode 100644
index a95a2ea0dd..0000000000
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/*************************************************************************/
-/* physics_2d_server_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS_2D_SERVER_SW
-#define PHYSICS_2D_SERVER_SW
-
-#include "core/rid_owner.h"
-#include "joints_2d_sw.h"
-#include "servers/physics_2d_server.h"
-#include "shape_2d_sw.h"
-#include "space_2d_sw.h"
-#include "step_2d_sw.h"
-
-class Physics2DServerSW : public Physics2DServer {
-
- GDCLASS(Physics2DServerSW, Physics2DServer);
-
- friend class Physics2DDirectSpaceStateSW;
- friend class Physics2DDirectBodyStateSW;
- bool active;
- int iterations;
- bool doing_sync;
- real_t last_step;
-
- int island_count;
- int active_objects;
- int collision_pairs;
-
- bool using_threads;
-
- bool flushing_queries;
-
- Step2DSW *stepper;
- Set<const Space2DSW *> active_spaces;
-
- Physics2DDirectBodyStateSW *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;
-
- static Physics2DServerSW *singletonsw;
-
- //void _clear_query(Query2DSW *p_query);
- friend class CollisionObject2DSW;
- SelfList<CollisionObject2DSW>::List pending_shape_update_list;
- void _update_shapes();
-
- RID _shape_create(ShapeType p_shape);
-
-public:
- struct CollCbkData {
-
- Vector2 valid_dir;
- real_t valid_depth;
- int max;
- int amount;
- int passed;
- int invalid_by_dir;
- Vector2 *ptr;
- };
-
- virtual RID line_shape_create();
- virtual RID ray_shape_create();
- virtual RID segment_shape_create();
- virtual RID circle_shape_create();
- virtual RID rectangle_shape_create();
- virtual RID capsule_shape_create();
- virtual RID convex_polygon_shape_create();
- virtual RID concave_polygon_shape_create();
-
- static void _shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata);
-
- virtual void shape_set_data(RID p_shape, const Variant &p_data);
- virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
-
- virtual ShapeType shape_get_type(RID p_shape) const;
- virtual Variant shape_get_data(RID p_shape) const;
- virtual real_t shape_get_custom_solver_bias(RID p_shape) const;
-
- virtual 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);
-
- /* SPACE API */
-
- virtual RID space_create();
- virtual void space_set_active(RID p_space, bool p_active);
- virtual bool space_is_active(RID p_space) const;
-
- virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value);
- virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const;
-
- virtual void space_set_debug_contacts(RID p_space, int p_max_contacts);
- virtual Vector<Vector2> space_get_contacts(RID p_space) const;
- virtual int space_get_contact_count(RID p_space) const;
-
- // this function only works on physics process, errors and returns null otherwise
- virtual Physics2DDirectSpaceState *space_get_direct_state(RID p_space);
-
- /* AREA API */
-
- virtual RID area_create();
-
- virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode);
- virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const;
-
- virtual void area_set_space(RID p_area, RID p_space);
- virtual RID area_get_space(RID p_area) const;
-
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
- virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
- virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform);
-
- virtual int area_get_shape_count(RID p_area) const;
- virtual RID area_get_shape(RID p_area, int p_shape_idx) const;
- virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const;
-
- virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled);
-
- virtual void area_remove_shape(RID p_area, int p_shape_idx);
- virtual void area_clear_shapes(RID p_area);
-
- virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id);
- virtual ObjectID area_get_object_instance_id(RID p_area) const;
-
- virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_id);
- virtual ObjectID area_get_canvas_instance_id(RID p_area) const;
-
- virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
- virtual void area_set_transform(RID p_area, const Transform2D &p_transform);
-
- virtual Variant area_get_param(RID p_area, AreaParameter p_param) const;
- virtual Transform2D area_get_transform(RID p_area) const;
- virtual void area_set_monitorable(RID p_area, bool p_monitorable);
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask);
- virtual void area_set_collision_layer(RID p_area, uint32_t p_layer);
-
- virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
- virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
-
- virtual void area_set_pickable(RID p_area, bool p_pickable);
-
- /* BODY API */
-
- // create a body of a given type
- virtual RID body_create();
-
- virtual void body_set_space(RID p_body, RID p_space);
- virtual RID body_get_space(RID p_body) const;
-
- virtual void body_set_mode(RID p_body, BodyMode p_mode);
- virtual BodyMode body_get_mode(RID p_body) const;
-
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
- virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
- virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform);
- virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata);
-
- virtual int body_get_shape_count(RID p_body) const;
- virtual RID body_get_shape(RID p_body, int p_shape_idx) const;
- virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const;
- virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const;
-
- virtual void body_remove_shape(RID p_body, int p_shape_idx);
- virtual void body_clear_shapes(RID p_body);
-
- virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled);
- virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin);
-
- virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
- virtual ObjectID body_get_object_instance_id(RID p_body) const;
-
- virtual void body_attach_canvas_instance_id(RID p_body, ObjectID p_id);
- virtual ObjectID body_get_canvas_instance_id(RID p_body) const;
-
- virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode);
- virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
-
- virtual void body_set_collision_layer(RID p_body, uint32_t p_layer);
- virtual uint32_t body_get_collision_layer(RID p_body) const;
-
- virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
- virtual uint32_t body_get_collision_mask(RID p_body) const;
-
- virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
- virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
-
- virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
- virtual Variant body_get_state(RID p_body, BodyState p_state) const;
-
- virtual void body_set_applied_force(RID p_body, const Vector2 &p_force);
- virtual Vector2 body_get_applied_force(RID p_body) const;
-
- virtual void body_set_applied_torque(RID p_body, real_t p_torque);
- virtual real_t body_get_applied_torque(RID p_body) const;
-
- virtual void body_add_central_force(RID p_body, const Vector2 &p_force);
- virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force);
- virtual void body_add_torque(RID p_body, real_t p_torque);
-
- virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse);
- virtual void body_apply_torque_impulse(RID p_body, real_t p_torque);
- virtual void body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse);
- virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity);
-
- virtual void body_add_collision_exception(RID p_body, RID p_body_b);
- virtual void body_remove_collision_exception(RID p_body, RID p_body_b);
- virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions);
-
- virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold);
- virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const;
-
- virtual void body_set_omit_force_integration(RID p_body, bool p_omit);
- virtual bool body_is_omitting_force_integration(RID p_body) const;
-
- virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
- virtual int body_get_max_contacts_reported(RID p_body) const;
-
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant());
- 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);
-
- virtual void body_set_pickable(RID p_body, bool p_pickable);
-
- virtual 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 = NULL, bool p_exclude_raycast_shapes = true);
- virtual 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, float p_margin = 0.001);
-
- // this function only works on physics process, errors and returns null otherwise
- virtual Physics2DDirectBodyState *body_get_direct_state(RID p_body);
-
- /* JOINT API */
-
- virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value);
- virtual real_t joint_get_param(RID p_joint, JointParam p_param) const;
-
- virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disabled);
- virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const;
-
- virtual RID pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b = RID());
- 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);
- 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());
- virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value);
- virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
- virtual void damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value);
- virtual real_t damped_string_joint_get_param(RID p_joint, DampedStringParam p_param) const;
-
- virtual JointType joint_get_type(RID p_joint) const;
-
- /* MISC */
-
- virtual void free(RID p_rid);
-
- virtual void set_active(bool p_active);
- virtual void init();
- virtual void step(real_t p_step);
- virtual void sync();
- virtual void flush_queries();
- virtual void end_sync();
- virtual void finish();
-
- virtual bool is_flushing_queries() const { return flushing_queries; }
-
- int get_process_info(ProcessInfo p_info);
-
- Physics2DServerSW();
- ~Physics2DServerSW();
-};
-
-#endif
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.cpp b/servers/physics_2d/physics_2d_server_wrap_mt.cpp
deleted file mode 100644
index 76036930c6..0000000000
--- a/servers/physics_2d/physics_2d_server_wrap_mt.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*************************************************************************/
-/* physics_2d_server_wrap_mt.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_2d_server_wrap_mt.h"
-
-#include "core/os/os.h"
-
-void Physics2DServerWrapMT::thread_exit() {
-
- exit = true;
-}
-
-void Physics2DServerWrapMT::thread_step(real_t p_delta) {
-
- physics_2d_server->step(p_delta);
- step_sem.post();
-}
-
-void Physics2DServerWrapMT::_thread_callback(void *_instance) {
-
- Physics2DServerWrapMT *vsmt = reinterpret_cast<Physics2DServerWrapMT *>(_instance);
-
- vsmt->thread_loop();
-}
-
-void Physics2DServerWrapMT::thread_loop() {
-
- server_thread = Thread::get_caller_id();
-
- physics_2d_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_2d_server->finish();
-}
-
-/* EVENT QUEUING */
-
-void Physics2DServerWrapMT::step(real_t p_step) {
-
- if (create_thread) {
-
- command_queue.push(this, &Physics2DServerWrapMT::thread_step, p_step);
- } else {
-
- command_queue.flush_all(); //flush all pending from other threads
- physics_2d_server->step(p_step);
- }
-}
-
-void Physics2DServerWrapMT::sync() {
-
- if (thread) {
- if (first_frame)
- first_frame = false;
- else
- step_sem.wait(); //must not wait if a step was not issued
- }
- physics_2d_server->sync();
-}
-
-void Physics2DServerWrapMT::flush_queries() {
-
- physics_2d_server->flush_queries();
-}
-
-void Physics2DServerWrapMT::end_sync() {
-
- physics_2d_server->end_sync();
-}
-
-void Physics2DServerWrapMT::init() {
-
- if (create_thread) {
-
- //OS::get_singleton()->release_rendering_thread();
- thread = Thread::create(_thread_callback, this);
- while (!step_thread_up) {
- OS::get_singleton()->delay_usec(1000);
- }
- } else {
-
- physics_2d_server->init();
- }
-}
-
-void Physics2DServerWrapMT::finish() {
-
- if (thread) {
-
- command_queue.push(this, &Physics2DServerWrapMT::thread_exit);
- Thread::wait_to_finish(thread);
- memdelete(thread);
-
- thread = NULL;
- } 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();
-}
-
-Physics2DServerWrapMT::Physics2DServerWrapMT(Physics2DServer *p_contained, bool p_create_thread) :
- command_queue(p_create_thread) {
-
- physics_2d_server = p_contained;
- create_thread = p_create_thread;
- thread = NULL;
- 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;
-}
-
-Physics2DServerWrapMT::~Physics2DServerWrapMT() {
-
- memdelete(physics_2d_server);
- //finish();
-}
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
deleted file mode 100644
index 4d5e317c8c..0000000000
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ /dev/null
@@ -1,348 +0,0 @@
-/*************************************************************************/
-/* physics_2d_server_wrap_mt.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS2DSERVERWRAPMT_H
-#define PHYSICS2DSERVERWRAPMT_H
-
-#include "core/command_queue_mt.h"
-#include "core/os/thread.h"
-#include "core/project_settings.h"
-#include "servers/physics_2d_server.h"
-
-#ifdef DEBUG_SYNC
-#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
-#else
-#define SYNC_DEBUG
-#endif
-
-class Physics2DServerWrapMT : public Physics2DServer {
-
- mutable Physics2DServer *physics_2d_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;
- Thread *thread;
- volatile bool step_thread_up;
- bool create_thread;
-
- Semaphore step_sem;
- int step_pending;
- void thread_step(real_t p_delta);
- void thread_flush();
-
- void thread_exit();
-
- bool first_frame;
-
- Mutex alloc_mutex;
- int pool_max_size;
-
-public:
-#define ServerName Physics2DServer
-#define ServerNameWrapMT Physics2DServerWrapMT
-#define server_name physics_2d_server
-#include "servers/server_wrap_mt_common.h"
-
- //FUNC1RID(shape,ShapeType); todo fix
- FUNCRID(line_shape)
- FUNCRID(ray_shape)
- FUNCRID(segment_shape)
- FUNCRID(circle_shape)
- FUNCRID(rectangle_shape)
- FUNCRID(capsule_shape)
- FUNCRID(convex_polygon_shape)
- FUNCRID(concave_polygon_shape)
-
- FUNC2(shape_set_data, RID, const Variant &);
- FUNC2(shape_set_custom_solver_bias, RID, real_t);
-
- FUNC1RC(ShapeType, shape_get_type, RID);
- FUNC1RC(Variant, shape_get_data, RID);
- 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) {
-
- 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);
- }
-
- /* 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
- Physics2DDirectSpaceState *space_get_direct_state(RID p_space) {
-
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), NULL);
- 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 {
-
- 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 {
-
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0);
- return physics_2d_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 Transform2D &, bool);
- FUNC3(area_set_shape, RID, int, RID);
- FUNC3(area_set_shape_transform, RID, int, const Transform2D &);
- FUNC3(area_set_shape_disabled, RID, int, bool);
-
- FUNC1RC(int, area_get_shape_count, RID);
- FUNC2RC(RID, area_get_shape, RID, int);
- FUNC2RC(Transform2D, 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);
-
- FUNC2(area_attach_canvas_instance_id, RID, ObjectID);
- FUNC1RC(ObjectID, area_get_canvas_instance_id, RID);
-
- FUNC3(area_set_param, RID, AreaParameter, const Variant &);
- FUNC2(area_set_transform, RID, const Transform2D &);
-
- FUNC2RC(Variant, area_get_param, RID, AreaParameter);
- FUNC1RC(Transform2D, 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_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 Transform2D &, bool);
- FUNC3(body_set_shape, RID, int, RID);
- FUNC3(body_set_shape_transform, RID, int, const Transform2D &);
- FUNC3(body_set_shape_metadata, RID, int, const Variant &);
-
- FUNC1RC(int, body_get_shape_count, RID);
- FUNC2RC(Transform2D, body_get_shape_transform, RID, int);
- FUNC2RC(Variant, body_get_shape_metadata, RID, int);
- FUNC2RC(RID, body_get_shape, RID, int);
-
- FUNC3(body_set_shape_disabled, RID, int, bool);
- FUNC4(body_set_shape_as_one_way_collision, RID, int, bool, float);
-
- 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_attach_canvas_instance_id, RID, ObjectID);
- FUNC1RC(ObjectID, body_get_canvas_instance_id, RID);
-
- FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
- FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, 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);
-
- FUNC3(body_set_param, RID, BodyParameter, real_t);
- FUNC2RC(real_t, body_get_param, RID, BodyParameter);
-
- FUNC3(body_set_state, RID, BodyState, const Variant &);
- FUNC2RC(Variant, body_get_state, RID, BodyState);
-
- FUNC2(body_set_applied_force, RID, const Vector2 &);
- FUNC1RC(Vector2, body_get_applied_force, RID);
-
- FUNC2(body_set_applied_torque, RID, real_t);
- FUNC1RC(real_t, body_get_applied_torque, RID);
-
- FUNC2(body_add_central_force, RID, const Vector2 &);
- FUNC3(body_add_force, RID, const Vector2 &, const Vector2 &);
- FUNC2(body_add_torque, RID, real_t);
- FUNC2(body_apply_central_impulse, RID, const Vector2 &);
- FUNC2(body_apply_torque_impulse, RID, real_t);
- FUNC3(body_apply_impulse, RID, const Vector2 &, const Vector2 &);
- FUNC2(body_set_axis_velocity, RID, const Vector2 &);
-
- 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);
-
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, 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) {
- 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 = NULL, bool p_exclude_raycast_shapes = true) {
-
- 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, float p_margin = 0.001) {
-
- 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
- Physics2DDirectBodyState *body_get_direct_state(RID p_body) {
-
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), NULL);
- return physics_2d_server->body_get_direct_state(p_body);
- }
-
- /* JOINT API */
-
- FUNC3(joint_set_param, RID, JointParam, real_t);
- FUNC2RC(real_t, joint_get_param, RID, JointParam);
-
- FUNC2(joint_disable_collisions_between_bodies, RID, const bool);
- FUNC1RC(bool, joint_is_disabled_collisions_between_bodies, RID);
-
- ///FUNC3RID(pin_joint,const Vector2&,RID,RID);
- ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID);
- ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID);
-
- //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);
-
- FUNC3(pin_joint_set_param, RID, PinJointParam, real_t);
- FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam);
-
- FUNC3(damped_string_joint_set_param, RID, DampedStringParam, real_t);
- FUNC2RC(real_t, damped_string_joint_get_param, RID, DampedStringParam);
-
- FUNC1RC(JointType, joint_get_type, RID);
-
- /* MISC */
-
- 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 bool is_flushing_queries() const {
- return physics_2d_server->is_flushing_queries();
- }
-
- int get_process_info(ProcessInfo p_info) {
- return physics_2d_server->get_process_info(p_info);
- }
-
- Physics2DServerWrapMT(Physics2DServer *p_contained, bool p_create_thread);
- ~Physics2DServerWrapMT();
-
- template <class T>
- static Physics2DServer *init_server() {
-
- 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(Physics2DServerWrapMT(memnew(T), false));
- else // multi threaded
- return memnew(Physics2DServerWrapMT(memnew(T), true));
- }
-
-#undef ServerNameWrapMT
-#undef ServerName
-#undef server_name
-};
-
-#ifdef DEBUG_SYNC
-#undef DEBUG_SYNC
-#endif
-#undef SYNC_DEBUG
-
-#endif // PHYSICS2DSERVERWRAPMT_H
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
new file mode 100644
index 0000000000..871e2aba1d
--- /dev/null
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -0,0 +1,1465 @@
+/*************************************************************************/
+/* physics_server_2d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_2d_sw.h"
+
+#include "broad_phase_2d_basic.h"
+#include "broad_phase_2d_hash_grid.h"
+#include "collision_solver_2d_sw.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+#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 PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
+
+ Shape2DSW *shape = nullptr;
+ switch (p_shape) {
+
+ case SHAPE_LINE: {
+
+ shape = memnew(LineShape2DSW);
+ } break;
+ case SHAPE_RAY: {
+
+ shape = memnew(RayShape2DSW);
+ } break;
+ case SHAPE_SEGMENT: {
+
+ shape = memnew(SegmentShape2DSW);
+ } break;
+ case SHAPE_CIRCLE: {
+
+ shape = memnew(CircleShape2DSW);
+ } break;
+ case SHAPE_RECTANGLE: {
+
+ shape = memnew(RectangleShape2DSW);
+ } break;
+ case SHAPE_CAPSULE: {
+
+ shape = memnew(CapsuleShape2DSW);
+ } break;
+ case SHAPE_CONVEX_POLYGON: {
+
+ shape = memnew(ConvexPolygonShape2DSW);
+ } break;
+ case SHAPE_CONCAVE_POLYGON: {
+
+ shape = memnew(ConcavePolygonShape2DSW);
+ } break;
+ case SHAPE_CUSTOM: {
+
+ ERR_FAIL_V(RID());
+
+ } break;
+ }
+
+ RID id = shape_owner.make_rid(shape);
+ shape->set_self(id);
+
+ return id;
+}
+
+RID PhysicsServer2DSW::line_shape_create() {
+
+ return _shape_create(SHAPE_LINE);
+}
+
+RID PhysicsServer2DSW::ray_shape_create() {
+
+ return _shape_create(SHAPE_RAY);
+}
+RID PhysicsServer2DSW::segment_shape_create() {
+
+ return _shape_create(SHAPE_SEGMENT);
+}
+RID PhysicsServer2DSW::circle_shape_create() {
+
+ return _shape_create(SHAPE_CIRCLE);
+}
+RID PhysicsServer2DSW::rectangle_shape_create() {
+
+ return _shape_create(SHAPE_RECTANGLE);
+}
+RID PhysicsServer2DSW::capsule_shape_create() {
+
+ return _shape_create(SHAPE_CAPSULE);
+}
+
+RID PhysicsServer2DSW::convex_polygon_shape_create() {
+
+ return _shape_create(SHAPE_CONVEX_POLYGON);
+}
+RID PhysicsServer2DSW::concave_polygon_shape_create() {
+
+ return _shape_create(SHAPE_CONCAVE_POLYGON);
+}
+
+void PhysicsServer2DSW::shape_set_data(RID p_shape, const Variant &p_data) {
+
+ Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_data(p_data);
+};
+
+void PhysicsServer2DSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
+
+ Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_custom_bias(p_bias);
+}
+
+PhysicsServer2D::ShapeType PhysicsServer2DSW::shape_get_type(RID p_shape) const {
+
+ const Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM);
+ return shape->get_type();
+};
+
+Variant PhysicsServer2DSW::shape_get_data(RID p_shape) const {
+
+ const Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, Variant());
+ ERR_FAIL_COND_V(!shape->is_configured(), Variant());
+ return shape->get_data();
+};
+
+real_t PhysicsServer2DSW::shape_get_custom_solver_bias(RID p_shape) const {
+
+ const Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, 0);
+ return shape->get_custom_bias();
+}
+
+void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) {
+
+ CollCbkData *cbk = (CollCbkData *)p_userdata;
+
+ if (cbk->max == 0)
+ return;
+
+ if (cbk->valid_dir != Vector2()) {
+ if (p_point_A.distance_squared_to(p_point_B) > cbk->valid_depth * cbk->valid_depth) {
+ cbk->invalid_by_dir++;
+ return;
+ }
+ Vector2 rel_dir = (p_point_A - p_point_B).normalized();
+
+ if (cbk->valid_dir.dot(rel_dir) < Math_SQRT12) { //sqrt(2)/2.0 - 45 degrees
+ cbk->invalid_by_dir++;
+
+ /*
+ print_line("A: "+p_point_A);
+ print_line("B: "+p_point_B);
+ print_line("discard too angled "+rtos(cbk->valid_dir.dot((p_point_A-p_point_B))));
+ print_line("resnorm: "+(p_point_A-p_point_B).normalized());
+ print_line("distance: "+rtos(p_point_A.distance_to(p_point_B)));
+ */
+ return;
+ }
+ }
+
+ if (cbk->amount == cbk->max) {
+ //find least deep
+ real_t min_depth = 1e20;
+ int min_depth_idx = 0;
+ for (int i = 0; i < cbk->amount; i++) {
+
+ real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]);
+ if (d < min_depth) {
+ min_depth = d;
+ min_depth_idx = i;
+ }
+ }
+
+ real_t d = p_point_A.distance_squared_to(p_point_B);
+ if (d < min_depth)
+ return;
+ cbk->ptr[min_depth_idx * 2 + 0] = p_point_A;
+ cbk->ptr[min_depth_idx * 2 + 1] = p_point_B;
+ cbk->passed++;
+
+ } else {
+
+ cbk->ptr[cbk->amount * 2 + 0] = p_point_A;
+ cbk->ptr[cbk->amount * 2 + 1] = p_point_B;
+ cbk->amount++;
+ cbk->passed++;
+ }
+}
+
+bool PhysicsServer2DSW::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) {
+
+ Shape2DSW *shape_A = shape_owner.getornull(p_shape_A);
+ ERR_FAIL_COND_V(!shape_A, false);
+ Shape2DSW *shape_B = shape_owner.getornull(p_shape_B);
+ ERR_FAIL_COND_V(!shape_B, false);
+
+ if (p_result_max == 0) {
+
+ return CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, nullptr, nullptr);
+ }
+
+ CollCbkData cbk;
+ cbk.max = p_result_max;
+ cbk.amount = 0;
+ cbk.passed = 0;
+ cbk.ptr = r_results;
+
+ bool res = CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk);
+ r_result_count = cbk.amount;
+ return res;
+}
+
+RID PhysicsServer2DSW::space_create() {
+
+ Space2DSW *space = memnew(Space2DSW);
+ RID id = space_owner.make_rid(space);
+ space->set_self(id);
+ RID area_id = area_create();
+ Area2DSW *area = area_owner.getornull(area_id);
+ ERR_FAIL_COND_V(!area, RID());
+ space->set_default_area(area);
+ area->set_space(space);
+ area->set_priority(-1);
+
+ return id;
+};
+
+void PhysicsServer2DSW::space_set_active(RID p_space, bool p_active) {
+
+ Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ if (p_active)
+ active_spaces.insert(space);
+ else
+ active_spaces.erase(space);
+}
+
+bool PhysicsServer2DSW::space_is_active(RID p_space) const {
+
+ const Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, false);
+
+ return active_spaces.has(space);
+}
+
+void PhysicsServer2DSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
+
+ Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+
+ space->set_param(p_param, p_value);
+}
+
+real_t PhysicsServer2DSW::space_get_param(RID p_space, SpaceParameter p_param) const {
+
+ const Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_param(p_param);
+}
+
+void PhysicsServer2DSW::space_set_debug_contacts(RID p_space, int p_max_contacts) {
+
+ Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ space->set_debug_contacts(p_max_contacts);
+}
+
+Vector<Vector2> PhysicsServer2DSW::space_get_contacts(RID p_space) const {
+
+ Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, Vector<Vector2>());
+ return space->get_debug_contacts();
+}
+
+int PhysicsServer2DSW::space_get_contact_count(RID p_space) const {
+
+ Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_debug_contact_count();
+}
+
+PhysicsDirectSpaceState2D *PhysicsServer2DSW::space_get_direct_state(RID p_space) {
+
+ Space2DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, nullptr);
+ 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();
+}
+
+RID PhysicsServer2DSW::area_create() {
+
+ Area2DSW *area = memnew(Area2DSW);
+ RID rid = area_owner.make_rid(area);
+ area->set_self(rid);
+ return rid;
+};
+
+void PhysicsServer2DSW::area_set_space(RID p_area, RID p_space) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ Space2DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (area->get_space() == space)
+ return; //pointless
+
+ area->clear_constraints();
+ area->set_space(space);
+};
+
+RID PhysicsServer2DSW::area_get_space(RID p_area) const {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ Space2DSW *space = area->get_space();
+ if (!space)
+ return RID();
+ return space->get_self();
+};
+
+void PhysicsServer2DSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_space_override_mode(p_mode);
+}
+
+PhysicsServer2D::AreaSpaceOverrideMode PhysicsServer2DSW::area_get_space_override_mode(RID p_area) const {
+
+ const Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED);
+
+ return area->get_space_override_mode();
+}
+
+void PhysicsServer2DSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ area->add_shape(shape, p_transform, p_disabled);
+}
+
+void PhysicsServer2DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ ERR_FAIL_COND(!shape->is_configured());
+
+ area->set_shape(p_shape_idx, shape);
+}
+void PhysicsServer2DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_shape_transform(p_shape_idx, p_transform);
+}
+
+void PhysicsServer2DSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ ERR_FAIL_INDEX(p_shape, area->get_shape_count());
+ FLUSH_QUERY_CHECK(area);
+
+ area->set_shape_as_disabled(p_shape, p_disabled);
+}
+
+int PhysicsServer2DSW::area_get_shape_count(RID p_area) const {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, -1);
+
+ return area->get_shape_count();
+}
+RID PhysicsServer2DSW::area_get_shape(RID p_area, int p_shape_idx) const {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ Shape2DSW *shape = area->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+Transform2D PhysicsServer2DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, Transform2D());
+
+ return area->get_shape_transform(p_shape_idx);
+}
+
+void PhysicsServer2DSW::area_remove_shape(RID p_area, int p_shape_idx) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->remove_shape(p_shape_idx);
+}
+
+void PhysicsServer2DSW::area_clear_shapes(RID p_area) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ while (area->get_shape_count())
+ area->remove_shape(0);
+}
+
+void PhysicsServer2DSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_instance_id(p_id);
+}
+ObjectID PhysicsServer2DSW::area_get_object_instance_id(RID p_area) const {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, ObjectID());
+ return area->get_instance_id();
+}
+
+void PhysicsServer2DSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_canvas_instance_id(p_id);
+}
+ObjectID PhysicsServer2DSW::area_get_canvas_instance_id(RID p_area) const {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, ObjectID());
+ return area->get_canvas_instance_id();
+}
+
+void PhysicsServer2DSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_param(p_param, p_value);
+};
+
+void PhysicsServer2DSW::area_set_transform(RID p_area, const Transform2D &p_transform) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_transform(p_transform);
+};
+
+Variant PhysicsServer2DSW::area_get_param(RID p_area, AreaParameter p_param) const {
+
+ if (space_owner.owns(p_area)) {
+ Space2DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, Variant());
+
+ return area->get_param(p_param);
+};
+
+Transform2D PhysicsServer2DSW::area_get_transform(RID p_area) const {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, Transform2D());
+
+ return area->get_transform();
+};
+
+void PhysicsServer2DSW::area_set_pickable(RID p_area, bool p_pickable) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_pickable(p_pickable);
+}
+
+void PhysicsServer2DSW::area_set_monitorable(RID p_area, bool p_monitorable) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ FLUSH_QUERY_CHECK(area);
+
+ area->set_monitorable(p_monitorable);
+}
+
+void PhysicsServer2DSW::area_set_collision_mask(RID p_area, uint32_t p_mask) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_mask(p_mask);
+}
+
+void PhysicsServer2DSW::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_layer(p_layer);
+}
+
+void PhysicsServer2DSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
+}
+
+void PhysicsServer2DSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+
+ Area2DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
+}
+
+/* BODY API */
+
+RID PhysicsServer2DSW::body_create() {
+
+ Body2DSW *body = memnew(Body2DSW);
+ RID rid = body_owner.make_rid(body);
+ body->set_self(rid);
+ return rid;
+}
+
+void PhysicsServer2DSW::body_set_space(RID p_body, RID p_space) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ Space2DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (body->get_space() == space)
+ return; //pointless
+
+ body->clear_constraint_map();
+ body->set_space(space);
+};
+
+RID PhysicsServer2DSW::body_get_space(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ Space2DSW *space = body->get_space();
+ if (!space)
+ return RID();
+ return space->get_self();
+};
+
+void PhysicsServer2DSW::body_set_mode(RID p_body, BodyMode p_mode) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_mode(p_mode);
+};
+
+PhysicsServer2D::BodyMode PhysicsServer2DSW::body_get_mode(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
+
+ return body->get_mode();
+};
+
+void PhysicsServer2DSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ body->add_shape(shape, p_transform, p_disabled);
+}
+
+void PhysicsServer2DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ Shape2DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ ERR_FAIL_COND(!shape->is_configured());
+
+ body->set_shape(p_shape_idx, shape);
+}
+void PhysicsServer2DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_shape_transform(p_shape_idx, p_transform);
+}
+
+void PhysicsServer2DSW::body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_shape_metadata(p_shape_idx, p_metadata);
+}
+
+Variant PhysicsServer2DSW::body_get_shape_metadata(RID p_body, int p_shape_idx) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Variant());
+ return body->get_shape_metadata(p_shape_idx);
+}
+
+int PhysicsServer2DSW::body_get_shape_count(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, -1);
+
+ return body->get_shape_count();
+}
+RID PhysicsServer2DSW::body_get_shape(RID p_body, int p_shape_idx) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ Shape2DSW *shape = body->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+Transform2D PhysicsServer2DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Transform2D());
+
+ return body->get_shape_transform(p_shape_idx);
+}
+
+void PhysicsServer2DSW::body_remove_shape(RID p_body, int p_shape_idx) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_shape(p_shape_idx);
+}
+
+void PhysicsServer2DSW::body_clear_shapes(RID p_body) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ while (body->get_shape_count())
+ body->remove_shape(0);
+}
+
+void PhysicsServer2DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_shape_as_disabled(p_shape_idx, p_disabled);
+}
+void PhysicsServer2DSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin);
+}
+
+void PhysicsServer2DSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_continuous_collision_detection_mode(p_mode);
+}
+
+PhysicsServer2DSW::CCDMode PhysicsServer2DSW::body_get_continuous_collision_detection_mode(RID p_body) const {
+
+ const Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED);
+
+ return body->get_continuous_collision_detection_mode();
+}
+
+void PhysicsServer2DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_instance_id(p_id);
+};
+
+ObjectID PhysicsServer2DSW::body_get_object_instance_id(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, ObjectID());
+
+ return body->get_instance_id();
+};
+
+void PhysicsServer2DSW::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_canvas_instance_id(p_id);
+};
+
+ObjectID PhysicsServer2DSW::body_get_canvas_instance_id(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, ObjectID());
+
+ return body->get_canvas_instance_id();
+};
+
+void PhysicsServer2DSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_collision_layer(p_layer);
+};
+
+uint32_t PhysicsServer2DSW::body_get_collision_layer(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_layer();
+};
+
+void PhysicsServer2DSW::body_set_collision_mask(RID p_body, uint32_t p_mask) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_collision_mask(p_mask);
+};
+
+uint32_t PhysicsServer2DSW::body_get_collision_mask(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_mask();
+};
+
+void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_param(p_param, p_value);
+};
+
+real_t PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_param(p_param);
+};
+
+void PhysicsServer2DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_state(p_state, p_variant);
+};
+
+Variant PhysicsServer2DSW::body_get_state(RID p_body, BodyState p_state) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Variant());
+
+ return body->get_state(p_state);
+};
+
+void PhysicsServer2DSW::body_set_applied_force(RID p_body, const Vector2 &p_force) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_applied_force(p_force);
+ body->wakeup();
+};
+
+Vector2 PhysicsServer2DSW::body_get_applied_force(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Vector2());
+ return body->get_applied_force();
+};
+
+void PhysicsServer2DSW::body_set_applied_torque(RID p_body, real_t p_torque) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_applied_torque(p_torque);
+ body->wakeup();
+};
+
+real_t PhysicsServer2DSW::body_get_applied_torque(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_applied_torque();
+};
+
+void PhysicsServer2DSW::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) {
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_central_impulse(p_impulse);
+ body->wakeup();
+}
+
+void PhysicsServer2DSW::body_apply_torque_impulse(RID p_body, real_t p_torque) {
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_torque_impulse(p_torque);
+}
+
+void PhysicsServer2DSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_impulse(p_pos, p_impulse);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_add_central_force(RID p_body, const Vector2 &p_force) {
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_central_force(p_force);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_force(p_offset, p_force);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_add_torque(RID p_body, real_t p_torque) {
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_torque(p_torque);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ Vector2 v = body->get_linear_velocity();
+ Vector2 axis = p_axis_velocity.normalized();
+ v -= axis * axis.dot(v);
+ v += p_axis_velocity;
+ body->set_linear_velocity(v);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_add_collision_exception(RID p_body, RID p_body_b) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_exception(p_body_b);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_remove_collision_exception(RID p_body, RID p_body_b) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_exception(p_body_b);
+ body->wakeup();
+};
+
+void PhysicsServer2DSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ for (int i = 0; i < body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(body->get_exceptions()[i]);
+ }
+};
+
+void PhysicsServer2DSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+};
+
+real_t PhysicsServer2DSW::body_get_contacts_reported_depth_threshold(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+ return 0;
+};
+
+void PhysicsServer2DSW::body_set_omit_force_integration(RID p_body, bool p_omit) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_omit_force_integration(p_omit);
+};
+
+bool PhysicsServer2DSW::body_is_omitting_force_integration(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ return body->get_omit_force_integration();
+};
+
+void PhysicsServer2DSW::body_set_max_contacts_reported(RID p_body, int p_contacts) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_max_contacts_reported(p_contacts);
+}
+
+int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, -1);
+ 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) {
+
+ 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);
+}
+
+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) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false);
+
+ return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
+}
+
+void PhysicsServer2DSW::body_set_pickable(RID p_body, bool p_pickable) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_pickable(p_pickable);
+}
+
+bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_COND_V(!body->get_space(), false);
+ ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
+
+ _update_shapes();
+
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
+}
+
+int PhysicsServer2DSW::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, float p_margin) {
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_COND_V(!body->get_space(), false);
+ ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
+
+ return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+}
+
+PhysicsDirectBodyState2D *PhysicsServer2DSW::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.");
+
+ if (!body_owner.owns(p_body))
+ return nullptr;
+
+ Body2DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, nullptr);
+ ERR_FAIL_COND_V(!body->get_space(), 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.");
+
+ direct_state->body = body;
+ return direct_state;
+}
+
+/* JOINT API */
+
+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);
+
+ switch (p_param) {
+ case JOINT_PARAM_BIAS: joint->set_bias(p_value); break;
+ case JOINT_PARAM_MAX_BIAS: joint->set_max_bias(p_value); break;
+ case JOINT_PARAM_MAX_FORCE: joint->set_max_force(p_value); break;
+ }
+}
+
+real_t PhysicsServer2DSW::joint_get_param(RID p_joint, JointParam p_param) const {
+
+ const Joint2DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, -1);
+
+ switch (p_param) {
+ case JOINT_PARAM_BIAS: return joint->get_bias(); break;
+ case JOINT_PARAM_MAX_BIAS: return joint->get_max_bias(); break;
+ case JOINT_PARAM_MAX_FORCE: return joint->get_max_force(); break;
+ }
+
+ return 0;
+}
+
+void PhysicsServer2DSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
+ Joint2DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(!joint);
+
+ joint->disable_collisions_between_bodies(p_disable);
+
+ if (2 == joint->get_body_count()) {
+ Body2DSW *body_a = *joint->get_body_ptr();
+ Body2DSW *body_b = *(joint->get_body_ptr() + 1);
+
+ if (p_disable) {
+ body_add_collision_exception(body_a->get_self(), body_b->get_self());
+ body_add_collision_exception(body_b->get_self(), body_a->get_self());
+ } else {
+ body_remove_collision_exception(body_a->get_self(), body_b->get_self());
+ body_remove_collision_exception(body_b->get_self(), body_a->get_self());
+ }
+ }
+}
+
+bool PhysicsServer2DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
+ const Joint2DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, true);
+
+ return joint->is_disabled_collisions_between_bodies();
+}
+
+RID PhysicsServer2DSW::pin_joint_create(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());
+ Body2DSW *B = nullptr;
+ if (body_owner.owns(p_body_b)) {
+ B = body_owner.getornull(p_body_b);
+ ERR_FAIL_COND_V(!B, RID());
+ }
+
+ Joint2DSW *joint = memnew(PinJoint2DSW(p_pos, A, B));
+ RID self = joint_owner.make_rid(joint);
+ joint->set_self(self);
+
+ return self;
+}
+
+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) {
+
+ Body2DSW *A = body_owner.getornull(p_body_a);
+ ERR_FAIL_COND_V(!A, RID());
+
+ Body2DSW *B = body_owner.getornull(p_body_b);
+ ERR_FAIL_COND_V(!B, RID());
+
+ 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;
+}
+
+RID PhysicsServer2DSW::damped_spring_joint_create(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());
+
+ Body2DSW *B = body_owner.getornull(p_body_b);
+ ERR_FAIL_COND_V(!B, RID());
+
+ 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;
+}
+
+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);
+
+ PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
+ pin_joint->set_param(p_param, p_value);
+}
+
+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);
+
+ PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j);
+ return pin_joint->get_param(p_param);
+}
+
+void PhysicsServer2DSW::damped_string_joint_set_param(RID p_joint, DampedStringParam 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);
+
+ DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
+ dsj->set_param(p_param, p_value);
+}
+
+real_t PhysicsServer2DSW::damped_string_joint_get_param(RID p_joint, DampedStringParam 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);
+
+ DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j);
+ return dsj->get_param(p_param);
+}
+
+PhysicsServer2D::JointType PhysicsServer2DSW::joint_get_type(RID p_joint) const {
+
+ Joint2DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, JOINT_PIN);
+
+ return joint->get_type();
+}
+
+void PhysicsServer2DSW::free(RID p_rid) {
+
+ _update_shapes(); // just in case
+
+ if (shape_owner.owns(p_rid)) {
+
+ Shape2DSW *shape = shape_owner.getornull(p_rid);
+
+ while (shape->get_owners().size()) {
+ ShapeOwner2DSW *so = shape->get_owners().front()->key();
+ so->remove_shape(shape);
+ }
+
+ shape_owner.free(p_rid);
+ memdelete(shape);
+ } else if (body_owner.owns(p_rid)) {
+
+ Body2DSW *body = body_owner.getornull(p_rid);
+
+ /*
+ if (body->get_state_query())
+ _clear_query(body->get_state_query());
+
+ if (body->get_direct_state_query())
+ _clear_query(body->get_direct_state_query());
+ */
+
+ body_set_space(p_rid, RID());
+
+ while (body->get_shape_count()) {
+
+ body->remove_shape(0);
+ }
+
+ body_owner.free(p_rid);
+ memdelete(body);
+
+ } else if (area_owner.owns(p_rid)) {
+
+ Area2DSW *area = area_owner.getornull(p_rid);
+
+ /*
+ if (area->get_monitor_query())
+ _clear_query(area->get_monitor_query());
+ */
+
+ area->set_space(nullptr);
+
+ while (area->get_shape_count()) {
+
+ area->remove_shape(0);
+ }
+
+ area_owner.free(p_rid);
+ memdelete(area);
+ } else if (space_owner.owns(p_rid)) {
+
+ Space2DSW *space = space_owner.getornull(p_rid);
+
+ while (space->get_objects().size()) {
+ CollisionObject2DSW *co = (CollisionObject2DSW *)space->get_objects().front()->get();
+ co->set_space(nullptr);
+ }
+
+ active_spaces.erase(space);
+ free(space->get_default_area()->get_self());
+ space_owner.free(p_rid);
+ memdelete(space);
+ } else if (joint_owner.owns(p_rid)) {
+
+ Joint2DSW *joint = joint_owner.getornull(p_rid);
+
+ joint_owner.free(p_rid);
+ memdelete(joint);
+
+ } else {
+
+ ERR_FAIL_MSG("Invalid ID.");
+ }
+};
+
+void PhysicsServer2DSW::set_active(bool p_active) {
+
+ active = p_active;
+};
+
+void PhysicsServer2DSW::init() {
+
+ doing_sync = false;
+ last_step = 0.001;
+ iterations = 8; // 8?
+ stepper = memnew(Step2DSW);
+ direct_state = memnew(PhysicsDirectBodyState2DSW);
+};
+
+void PhysicsServer2DSW::step(real_t p_step) {
+
+ if (!active)
+ return;
+
+ _update_shapes();
+
+ doing_sync = false;
+
+ last_step = p_step;
+ PhysicsDirectBodyState2DSW::singleton->step = p_step;
+ island_count = 0;
+ active_objects = 0;
+ collision_pairs = 0;
+ for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
+
+ stepper->step((Space2DSW *)E->get(), p_step, iterations);
+ island_count += E->get()->get_island_count();
+ active_objects += E->get()->get_active_objects();
+ collision_pairs += E->get()->get_collision_pairs();
+ }
+};
+
+void PhysicsServer2DSW::sync() {
+
+ doing_sync = true;
+};
+
+void PhysicsServer2DSW::flush_queries() {
+
+ if (!active)
+ return;
+
+ flushing_queries = true;
+
+ uint64_t time_beg = OS::get_singleton()->get_ticks_usec();
+
+ for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
+
+ Space2DSW *space = (Space2DSW *)E->get();
+ space->call_queries();
+ }
+
+ flushing_queries = false;
+
+ if (EngineDebugger::is_profiling("servers")) {
+
+ uint64_t total_time[Space2DSW::ELAPSED_TIME_MAX];
+ static const char *time_name[Space2DSW::ELAPSED_TIME_MAX] = {
+ "integrate_forces",
+ "generate_islands",
+ "setup_constraints",
+ "solve_constraints",
+ "integrate_velocities"
+ };
+
+ for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
+ total_time[i] = 0;
+ }
+
+ for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
+
+ for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
+ total_time[i] += E->get()->get_elapsed_time(Space2DSW::ElapsedTime(i));
+ }
+ }
+
+ Array values;
+ values.resize(Space2DSW::ELAPSED_TIME_MAX * 2);
+ for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) {
+ values[i * 2 + 0] = time_name[i];
+ values[i * 2 + 1] = USEC_TO_SEC(total_time[i]);
+ }
+ values.push_back("flush_queries");
+ values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg));
+
+ values.push_front("physics_2d");
+ EngineDebugger::profiler_add_frame_data("servers", values);
+ }
+}
+
+void PhysicsServer2DSW::end_sync() {
+ doing_sync = false;
+}
+
+void PhysicsServer2DSW::finish() {
+
+ memdelete(stepper);
+ memdelete(direct_state);
+};
+
+void PhysicsServer2DSW::_update_shapes() {
+
+ while (pending_shape_update_list.first()) {
+ pending_shape_update_list.first()->self()->_shape_changed();
+ pending_shape_update_list.remove(pending_shape_update_list.first());
+ }
+}
+
+int PhysicsServer2DSW::get_process_info(ProcessInfo p_info) {
+
+ switch (p_info) {
+
+ case INFO_ACTIVE_OBJECTS: {
+
+ return active_objects;
+ } break;
+ case INFO_COLLISION_PAIRS: {
+ return collision_pairs;
+ } break;
+ case INFO_ISLAND_COUNT: {
+
+ return island_count;
+ } break;
+ }
+
+ return 0;
+}
+
+PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr;
+
+PhysicsServer2DSW::PhysicsServer2DSW() {
+
+ singletonsw = this;
+ BroadPhase2DSW::create_func = BroadPhase2DHashGrid::_create;
+ //BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
+
+ active = true;
+ island_count = 0;
+ active_objects = 0;
+ collision_pairs = 0;
+ using_threads = int(ProjectSettings::get_singleton()->get("physics/2d/thread_model")) == 2;
+ flushing_queries = false;
+};
+
+PhysicsServer2DSW::~PhysicsServer2DSW(){
+
+};
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
new file mode 100644
index 0000000000..918958ffe2
--- /dev/null
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -0,0 +1,296 @@
+/*************************************************************************/
+/* physics_server_2d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS_2D_SERVER_SW
+#define PHYSICS_2D_SERVER_SW
+
+#include "core/rid_owner.h"
+#include "joints_2d_sw.h"
+#include "servers/physics_server_2d.h"
+#include "shape_2d_sw.h"
+#include "space_2d_sw.h"
+#include "step_2d_sw.h"
+
+class PhysicsServer2DSW : public PhysicsServer2D {
+
+ GDCLASS(PhysicsServer2DSW, PhysicsServer2D);
+
+ friend class PhysicsDirectSpaceState2DSW;
+ friend class PhysicsDirectBodyState2DSW;
+ bool active;
+ int iterations;
+ bool doing_sync;
+ real_t last_step;
+
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
+ bool using_threads;
+
+ bool flushing_queries;
+
+ Step2DSW *stepper;
+ Set<const Space2DSW *> active_spaces;
+
+ 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;
+
+ static PhysicsServer2DSW *singletonsw;
+
+ //void _clear_query(Query2DSW *p_query);
+ friend class CollisionObject2DSW;
+ SelfList<CollisionObject2DSW>::List pending_shape_update_list;
+ void _update_shapes();
+
+ RID _shape_create(ShapeType p_shape);
+
+public:
+ struct CollCbkData {
+
+ Vector2 valid_dir;
+ real_t valid_depth;
+ int max;
+ int amount;
+ int passed;
+ int invalid_by_dir;
+ Vector2 *ptr;
+ };
+
+ virtual RID line_shape_create();
+ virtual RID ray_shape_create();
+ virtual RID segment_shape_create();
+ virtual RID circle_shape_create();
+ virtual RID rectangle_shape_create();
+ virtual RID capsule_shape_create();
+ virtual RID convex_polygon_shape_create();
+ virtual RID concave_polygon_shape_create();
+
+ static void _shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata);
+
+ virtual void shape_set_data(RID p_shape, const Variant &p_data);
+ virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
+
+ virtual ShapeType shape_get_type(RID p_shape) const;
+ virtual Variant shape_get_data(RID p_shape) const;
+ virtual real_t shape_get_custom_solver_bias(RID p_shape) const;
+
+ virtual 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);
+
+ /* SPACE API */
+
+ virtual RID space_create();
+ virtual void space_set_active(RID p_space, bool p_active);
+ virtual bool space_is_active(RID p_space) const;
+
+ virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value);
+ virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const;
+
+ virtual void space_set_debug_contacts(RID p_space, int p_max_contacts);
+ virtual Vector<Vector2> space_get_contacts(RID p_space) const;
+ virtual int space_get_contact_count(RID p_space) const;
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space);
+
+ /* AREA API */
+
+ virtual RID area_create();
+
+ virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode);
+ virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const;
+
+ virtual void area_set_space(RID p_area, RID p_space);
+ virtual RID area_get_space(RID p_area) const;
+
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
+ virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform);
+
+ virtual int area_get_shape_count(RID p_area) const;
+ virtual RID area_get_shape(RID p_area, int p_shape_idx) const;
+ virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const;
+
+ virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled);
+
+ virtual void area_remove_shape(RID p_area, int p_shape_idx);
+ virtual void area_clear_shapes(RID p_area);
+
+ virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id);
+ virtual ObjectID area_get_object_instance_id(RID p_area) const;
+
+ virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_id);
+ virtual ObjectID area_get_canvas_instance_id(RID p_area) const;
+
+ virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
+ virtual void area_set_transform(RID p_area, const Transform2D &p_transform);
+
+ virtual Variant area_get_param(RID p_area, AreaParameter p_param) const;
+ virtual Transform2D area_get_transform(RID p_area) const;
+ virtual void area_set_monitorable(RID p_area, bool p_monitorable);
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask);
+ virtual void area_set_collision_layer(RID p_area, uint32_t p_layer);
+
+ virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
+ virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
+
+ virtual void area_set_pickable(RID p_area, bool p_pickable);
+
+ /* BODY API */
+
+ // create a body of a given type
+ virtual RID body_create();
+
+ virtual void body_set_space(RID p_body, RID p_space);
+ virtual RID body_get_space(RID p_body) const;
+
+ virtual void body_set_mode(RID p_body, BodyMode p_mode);
+ virtual BodyMode body_get_mode(RID p_body) const;
+
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
+ virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform);
+ virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata);
+
+ virtual int body_get_shape_count(RID p_body) const;
+ virtual RID body_get_shape(RID p_body, int p_shape_idx) const;
+ virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const;
+ virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const;
+
+ virtual void body_remove_shape(RID p_body, int p_shape_idx);
+ virtual void body_clear_shapes(RID p_body);
+
+ virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled);
+ virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, float p_margin);
+
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_object_instance_id(RID p_body) const;
+
+ virtual void body_attach_canvas_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_canvas_instance_id(RID p_body) const;
+
+ virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode);
+ virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const;
+
+ virtual void body_set_collision_layer(RID p_body, uint32_t p_layer);
+ virtual uint32_t body_get_collision_layer(RID p_body) const;
+
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
+ virtual uint32_t body_get_collision_mask(RID p_body) const;
+
+ virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
+ virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
+
+ virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
+ virtual Variant body_get_state(RID p_body, BodyState p_state) const;
+
+ virtual void body_set_applied_force(RID p_body, const Vector2 &p_force);
+ virtual Vector2 body_get_applied_force(RID p_body) const;
+
+ virtual void body_set_applied_torque(RID p_body, real_t p_torque);
+ virtual real_t body_get_applied_torque(RID p_body) const;
+
+ virtual void body_add_central_force(RID p_body, const Vector2 &p_force);
+ virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force);
+ virtual void body_add_torque(RID p_body, real_t p_torque);
+
+ virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse);
+ virtual void body_apply_torque_impulse(RID p_body, real_t p_torque);
+ virtual void body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse);
+ virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity);
+
+ virtual void body_add_collision_exception(RID p_body, RID p_body_b);
+ virtual void body_remove_collision_exception(RID p_body, RID p_body_b);
+ virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions);
+
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold);
+ virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const;
+
+ virtual void body_set_omit_force_integration(RID p_body, bool p_omit);
+ virtual bool body_is_omitting_force_integration(RID p_body) const;
+
+ virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
+ virtual int body_get_max_contacts_reported(RID p_body) const;
+
+ virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant());
+ 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);
+
+ virtual void body_set_pickable(RID p_body, bool p_pickable);
+
+ virtual 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);
+ virtual 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, float p_margin = 0.001);
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body);
+
+ /* JOINT API */
+
+ virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value);
+ virtual real_t joint_get_param(RID p_joint, JointParam p_param) const;
+
+ virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disabled);
+ virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const;
+
+ virtual RID pin_joint_create(const Vector2 &p_pos, RID p_body_a, RID p_body_b = RID());
+ 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);
+ 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());
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value);
+ virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
+ virtual void damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value);
+ virtual real_t damped_string_joint_get_param(RID p_joint, DampedStringParam p_param) const;
+
+ virtual JointType joint_get_type(RID p_joint) const;
+
+ /* MISC */
+
+ virtual void free(RID p_rid);
+
+ virtual void set_active(bool p_active);
+ virtual void init();
+ virtual void step(real_t p_step);
+ virtual void sync();
+ virtual void flush_queries();
+ virtual void end_sync();
+ virtual void finish();
+
+ virtual bool is_flushing_queries() const { return flushing_queries; }
+
+ int get_process_info(ProcessInfo p_info);
+
+ PhysicsServer2DSW();
+ ~PhysicsServer2DSW();
+};
+
+#endif
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
new file mode 100644
index 0000000000..0a89a76615
--- /dev/null
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* physics_server_2d_wrap_mt.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_2d_wrap_mt.h"
+
+#include "core/os/os.h"
+
+void PhysicsServer2DWrapMT::thread_exit() {
+
+ exit = true;
+}
+
+void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
+
+ physics_2d_server->step(p_delta);
+ step_sem.post();
+}
+
+void PhysicsServer2DWrapMT::_thread_callback(void *_instance) {
+
+ PhysicsServer2DWrapMT *vsmt = reinterpret_cast<PhysicsServer2DWrapMT *>(_instance);
+
+ vsmt->thread_loop();
+}
+
+void PhysicsServer2DWrapMT::thread_loop() {
+
+ server_thread = Thread::get_caller_id();
+
+ physics_2d_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_2d_server->finish();
+}
+
+/* EVENT QUEUING */
+
+void PhysicsServer2DWrapMT::step(real_t p_step) {
+
+ if (create_thread) {
+
+ command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step);
+ } else {
+
+ command_queue.flush_all(); //flush all pending from other threads
+ physics_2d_server->step(p_step);
+ }
+}
+
+void PhysicsServer2DWrapMT::sync() {
+
+ if (thread) {
+ if (first_frame)
+ first_frame = false;
+ else
+ step_sem.wait(); //must not wait if a step was not issued
+ }
+ physics_2d_server->sync();
+}
+
+void PhysicsServer2DWrapMT::flush_queries() {
+
+ physics_2d_server->flush_queries();
+}
+
+void PhysicsServer2DWrapMT::end_sync() {
+
+ physics_2d_server->end_sync();
+}
+
+void PhysicsServer2DWrapMT::init() {
+
+ if (create_thread) {
+
+ //OS::get_singleton()->release_rendering_thread();
+ thread = Thread::create(_thread_callback, this);
+ while (!step_thread_up) {
+ OS::get_singleton()->delay_usec(1000);
+ }
+ } else {
+
+ physics_2d_server->init();
+ }
+}
+
+void PhysicsServer2DWrapMT::finish() {
+
+ if (thread) {
+
+ command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit);
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+
+ thread = nullptr;
+ } 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) :
+ command_queue(p_create_thread) {
+
+ physics_2d_server = p_contained;
+ create_thread = p_create_thread;
+ thread = nullptr;
+ 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;
+}
+
+PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() {
+
+ memdelete(physics_2d_server);
+ //finish();
+}
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
new file mode 100644
index 0000000000..7e61927378
--- /dev/null
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -0,0 +1,348 @@
+/*************************************************************************/
+/* physics_server_2d_wrap_mt.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS2DSERVERWRAPMT_H
+#define PHYSICS2DSERVERWRAPMT_H
+
+#include "core/command_queue_mt.h"
+#include "core/os/thread.h"
+#include "core/project_settings.h"
+#include "servers/physics_server_2d.h"
+
+#ifdef DEBUG_SYNC
+#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
+#else
+#define SYNC_DEBUG
+#endif
+
+class PhysicsServer2DWrapMT : public PhysicsServer2D {
+
+ mutable PhysicsServer2D *physics_2d_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;
+ Thread *thread;
+ volatile bool step_thread_up;
+ bool create_thread;
+
+ Semaphore step_sem;
+ int step_pending;
+ void thread_step(real_t p_delta);
+ void thread_flush();
+
+ void thread_exit();
+
+ bool first_frame;
+
+ Mutex alloc_mutex;
+ int pool_max_size;
+
+public:
+#define ServerName PhysicsServer2D
+#define ServerNameWrapMT PhysicsServer2DWrapMT
+#define server_name physics_2d_server
+#include "servers/server_wrap_mt_common.h"
+
+ //FUNC1RID(shape,ShapeType); todo fix
+ FUNCRID(line_shape)
+ FUNCRID(ray_shape)
+ FUNCRID(segment_shape)
+ FUNCRID(circle_shape)
+ FUNCRID(rectangle_shape)
+ FUNCRID(capsule_shape)
+ FUNCRID(convex_polygon_shape)
+ FUNCRID(concave_polygon_shape)
+
+ FUNC2(shape_set_data, RID, const Variant &);
+ FUNC2(shape_set_custom_solver_bias, RID, real_t);
+
+ FUNC1RC(ShapeType, shape_get_type, RID);
+ FUNC1RC(Variant, shape_get_data, RID);
+ 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) {
+
+ 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);
+ }
+
+ /* 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
+ PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) {
+
+ 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 {
+
+ 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 {
+
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0);
+ return physics_2d_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 Transform2D &, bool);
+ FUNC3(area_set_shape, RID, int, RID);
+ FUNC3(area_set_shape_transform, RID, int, const Transform2D &);
+ FUNC3(area_set_shape_disabled, RID, int, bool);
+
+ FUNC1RC(int, area_get_shape_count, RID);
+ FUNC2RC(RID, area_get_shape, RID, int);
+ FUNC2RC(Transform2D, 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);
+
+ FUNC2(area_attach_canvas_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, area_get_canvas_instance_id, RID);
+
+ FUNC3(area_set_param, RID, AreaParameter, const Variant &);
+ FUNC2(area_set_transform, RID, const Transform2D &);
+
+ FUNC2RC(Variant, area_get_param, RID, AreaParameter);
+ FUNC1RC(Transform2D, 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_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 Transform2D &, bool);
+ FUNC3(body_set_shape, RID, int, RID);
+ FUNC3(body_set_shape_transform, RID, int, const Transform2D &);
+ FUNC3(body_set_shape_metadata, RID, int, const Variant &);
+
+ FUNC1RC(int, body_get_shape_count, RID);
+ FUNC2RC(Transform2D, body_get_shape_transform, RID, int);
+ FUNC2RC(Variant, body_get_shape_metadata, RID, int);
+ FUNC2RC(RID, body_get_shape, RID, int);
+
+ FUNC3(body_set_shape_disabled, RID, int, bool);
+ FUNC4(body_set_shape_as_one_way_collision, RID, int, bool, float);
+
+ 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_attach_canvas_instance_id, RID, ObjectID);
+ FUNC1RC(ObjectID, body_get_canvas_instance_id, RID);
+
+ FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode);
+ FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, 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);
+
+ FUNC3(body_set_param, RID, BodyParameter, real_t);
+ FUNC2RC(real_t, body_get_param, RID, BodyParameter);
+
+ FUNC3(body_set_state, RID, BodyState, const Variant &);
+ FUNC2RC(Variant, body_get_state, RID, BodyState);
+
+ FUNC2(body_set_applied_force, RID, const Vector2 &);
+ FUNC1RC(Vector2, body_get_applied_force, RID);
+
+ FUNC2(body_set_applied_torque, RID, real_t);
+ FUNC1RC(real_t, body_get_applied_torque, RID);
+
+ FUNC2(body_add_central_force, RID, const Vector2 &);
+ FUNC3(body_add_force, RID, const Vector2 &, const Vector2 &);
+ FUNC2(body_add_torque, RID, real_t);
+ FUNC2(body_apply_central_impulse, RID, const Vector2 &);
+ FUNC2(body_apply_torque_impulse, RID, real_t);
+ FUNC3(body_apply_impulse, RID, const Vector2 &, const Vector2 &);
+ FUNC2(body_set_axis_velocity, RID, const Vector2 &);
+
+ 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);
+
+ FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, 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) {
+ 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) {
+
+ 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, float p_margin = 0.001) {
+
+ 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) {
+
+ ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr);
+ return physics_2d_server->body_get_direct_state(p_body);
+ }
+
+ /* JOINT API */
+
+ FUNC3(joint_set_param, RID, JointParam, real_t);
+ FUNC2RC(real_t, joint_get_param, RID, JointParam);
+
+ FUNC2(joint_disable_collisions_between_bodies, RID, const bool);
+ FUNC1RC(bool, joint_is_disabled_collisions_between_bodies, RID);
+
+ ///FUNC3RID(pin_joint,const Vector2&,RID,RID);
+ ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID);
+ ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID);
+
+ //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);
+
+ FUNC3(pin_joint_set_param, RID, PinJointParam, real_t);
+ FUNC2RC(real_t, pin_joint_get_param, RID, PinJointParam);
+
+ FUNC3(damped_string_joint_set_param, RID, DampedStringParam, real_t);
+ FUNC2RC(real_t, damped_string_joint_get_param, RID, DampedStringParam);
+
+ FUNC1RC(JointType, joint_get_type, RID);
+
+ /* MISC */
+
+ 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 bool is_flushing_queries() const {
+ return physics_2d_server->is_flushing_queries();
+ }
+
+ int get_process_info(ProcessInfo p_info) {
+ 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() {
+
+ 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));
+ }
+
+#undef ServerNameWrapMT
+#undef ServerName
+#undef server_name
+};
+
+#ifdef DEBUG_SYNC
+#undef DEBUG_SYNC
+#endif
+#undef SYNC_DEBUG
+
+#endif // PHYSICS2DSERVERWRAPMT_H
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index 5fefb9595f..06096d674a 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -643,7 +643,7 @@ void ConvexPolygonShape2DSW::set_data(const Variant &p_data) {
if (points)
memdelete_arr(points);
- points = NULL;
+ points = nullptr;
point_count = 0;
if (p_data.get_type() == Variant::PACKED_VECTOR2_ARRAY) {
@@ -706,7 +706,7 @@ Variant ConvexPolygonShape2DSW::get_data() const {
ConvexPolygonShape2DSW::ConvexPolygonShape2DSW() {
- points = NULL;
+ points = nullptr;
point_count = 0;
}
diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h
index fa56f2a250..ca001e6dd9 100644
--- a/servers/physics_2d/shape_2d_sw.h
+++ b/servers/physics_2d/shape_2d_sw.h
@@ -31,7 +31,7 @@
#ifndef SHAPE_2D_2DSW_H
#define SHAPE_2D_2DSW_H
-#include "servers/physics_2d_server.h"
+#include "servers/physics_server_2d.h"
#define _SEGMENT_IS_VALID_SUPPORT_THRESHOLD 0.99998
/*
@@ -72,7 +72,7 @@ public:
_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
_FORCE_INLINE_ RID get_self() const { return self; }
- virtual Physics2DServer::ShapeType get_type() const = 0;
+ virtual PhysicsServer2D::ShapeType get_type() const = 0;
_FORCE_INLINE_ Rect2 get_aabb() const { return aabb; }
_FORCE_INLINE_ bool is_configured() const { return configured; }
@@ -165,7 +165,7 @@ public:
_FORCE_INLINE_ Vector2 get_normal() const { return normal; }
_FORCE_INLINE_ real_t get_d() const { return d; }
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_LINE; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_LINE; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
@@ -203,7 +203,7 @@ public:
_FORCE_INLINE_ real_t get_length() const { return length; }
_FORCE_INLINE_ bool get_slips_on_slope() const { return slips_on_slope; }
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_RAY; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_RAY; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
@@ -242,7 +242,7 @@ public:
_FORCE_INLINE_ const Vector2 &get_b() const { return b; }
_FORCE_INLINE_ const Vector2 &get_normal() const { return n; }
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_SEGMENT; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_SEGMENT; }
_FORCE_INLINE_ Vector2 get_xformed_normal(const Transform2D &p_xform) const {
@@ -285,7 +285,7 @@ class CircleShape2DSW : public Shape2DSW {
public:
_FORCE_INLINE_ const real_t &get_radius() const { return radius; }
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_CIRCLE; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CIRCLE; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
@@ -319,7 +319,7 @@ class RectangleShape2DSW : public Shape2DSW {
public:
_FORCE_INLINE_ const Vector2 &get_half_extents() const { return half_extents; }
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_RECTANGLE; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_RECTANGLE; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
@@ -395,7 +395,7 @@ public:
_FORCE_INLINE_ const real_t &get_radius() const { return radius; }
_FORCE_INLINE_ const real_t &get_height() const { return height; }
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_CAPSULE; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CAPSULE; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
@@ -452,7 +452,7 @@ public:
return (p_xform.xform(b) - p_xform.xform(a)).normalized().tangent();
}
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_CONVEX_POLYGON; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONVEX_POLYGON; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
@@ -465,7 +465,11 @@ public:
virtual Variant get_data() const;
_FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
- // no matter the angle, the box is mirrored anyway
+
+ if (!points || point_count <= 0) {
+ r_min = r_max = 0;
+ return;
+ }
r_min = r_max = p_normal.dot(p_transform.xform(points[0].pos));
for (int i = 1; i < point_count; i++) {
@@ -531,7 +535,7 @@ class ConcavePolygonShape2DSW : public ConcaveShape2DSW {
int _generate_bvh(BVH *p_bvh, int p_len, int p_depth);
public:
- virtual Physics2DServer::ShapeType get_type() const { return Physics2DServer::SHAPE_CONCAVE_POLYGON; }
+ virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_CONCAVE_POLYGON; }
virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { /*project_range(p_normal,p_transform,r_min,r_max);*/
}
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 2009cb823d..7ae2e9769f 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -33,7 +33,7 @@
#include "collision_solver_2d_sw.h"
#include "core/os/os.h"
#include "core/pair.h"
-#include "physics_2d_server_sw.h"
+#include "physics_server_2d_sw.h"
_FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (!(p_object->get_collision_layer() & p_collision_mask)) {
@@ -49,7 +49,7 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint
return true;
}
-int Physics2DDirectSpaceStateSW::_intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
+int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
if (p_result_max <= 0)
return 0;
@@ -103,17 +103,17 @@ int Physics2DDirectSpaceStateSW::_intersect_point_impl(const Vector2 &p_point, S
return cc;
}
-int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+int PhysicsDirectSpaceState2DSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point);
}
-int Physics2DDirectSpaceStateSW::intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
+int PhysicsDirectSpaceState2DSW::intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) {
return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point, true, p_canvas_instance_id);
}
-bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+bool PhysicsDirectSpaceState2DSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
ERR_FAIL_COND_V(space->locked, false);
@@ -193,12 +193,12 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vec
return true;
}
-int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0)
return 0;
- Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.getornull(p_shape);
+ Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
Rect2 aabb = p_xform.xform(shape->get_aabb());
@@ -222,7 +222,7 @@ int Physics2DDirectSpaceStateSW::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 (!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(), NULL, NULL, NULL, p_margin))
+ 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;
r_results[cc].collider_id = col_obj->get_instance_id();
@@ -238,9 +238,9 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID &p_shape, const Trans
return cc;
}
-bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &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) {
+bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &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) {
- Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.getornull(p_shape);
+ Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, false);
Rect2 aabb = p_xform.xform(shape->get_aabb());
@@ -265,12 +265,12 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor
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(), NULL, NULL, NULL, p_margin)) {
+ if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) {
continue;
}
//test initial overlap
- if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, p_margin)) {
+ if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) {
return false;
}
@@ -285,7 +285,7 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor
real_t ofs = (low + hi) * 0.5;
Vector2 sep = mnormal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(shape, p_xform, p_motion * ofs, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, &sep, p_margin);
+ bool collided = CollisionSolver2DSW::solve(shape, p_xform, p_motion * ofs, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, &sep, p_margin);
if (collided) {
@@ -308,12 +308,12 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor
return true;
}
-bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0)
return 0;
- Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.getornull(p_shape);
+ Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
@@ -325,14 +325,14 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &
bool collided = false;
r_result_count = 0;
- Physics2DServerSW::CollCbkData cbk;
+ PhysicsServer2DSW::CollCbkData cbk;
cbk.max = p_result_max;
cbk.amount = 0;
cbk.passed = 0;
cbk.ptr = r_results;
- CollisionSolver2DSW::CallbackResult cbkres = Physics2DServerSW::_shape_col_cbk;
+ CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
- Physics2DServerSW::CollCbkData *cbkptr = &cbk;
+ PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
for (int i = 0; i < amount; i++) {
@@ -348,7 +348,7 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &
cbk.valid_dir = Vector2();
cbk.valid_depth = 0;
- if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) {
+ if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
collided = cbk.amount > 0;
}
}
@@ -402,9 +402,9 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B,
rd->best_local_shape = rd->local_shape;
}
-bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, 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) {
+bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, 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) {
- Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.getornull(p_shape);
+ Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape);
ERR_FAIL_COND_V(!shape, 0);
Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
@@ -415,7 +415,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh
_RestCallbackData2D rcd;
rcd.best_len = 0;
- rcd.best_object = NULL;
+ rcd.best_object = nullptr;
rcd.best_shape = 0;
rcd.min_allowed_depth = space->test_motion_min_contact_depth;
@@ -435,7 +435,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh
rcd.object = col_obj;
rcd.shape = shape_idx;
rcd.local_shape = 0;
- bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin);
+ bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, nullptr, p_margin);
if (!sc)
continue;
}
@@ -462,9 +462,9 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh
return true;
}
-Physics2DDirectSpaceStateSW::Physics2DDirectSpaceStateSW() {
+PhysicsDirectSpaceState2DSW::PhysicsDirectSpaceState2DSW() {
- space = NULL;
+ space = nullptr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -503,7 +503,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) {
return amount;
}
-int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, Physics2DServer::SeparationResult *r_results, int p_result_max, real_t p_margin) {
+int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
Rect2 body_aabb;
@@ -514,7 +514,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
if (p_body->is_shape_set_as_disabled(i))
continue;
- if (p_body->get_shape(i)->get_type() != Physics2DServer::SHAPE_RAY)
+ if (p_body->get_shape(i)->get_type() != PhysicsServer2D::SHAPE_RAY)
continue;
if (!shapes_found) {
@@ -548,10 +548,10 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
const int max_results = 32;
int recover_attempts = 4;
Vector2 sr[max_results * 2];
- Physics2DServerSW::CollCbkData cbk;
+ PhysicsServer2DSW::CollCbkData cbk;
cbk.max = max_results;
- Physics2DServerSW::CollCbkData *cbkptr = &cbk;
- CollisionSolver2DSW::CallbackResult cbkres = Physics2DServerSW::_shape_col_cbk;
+ PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
+ CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
do {
@@ -567,7 +567,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
Shape2DSW *body_shape = p_body->get_shape(j);
- if (body_shape->get_type() != Physics2DServer::SHAPE_RAY)
+ if (body_shape->get_type() != PhysicsServer2D::SHAPE_RAY)
continue;
Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
@@ -584,7 +584,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) {
+ if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
continue;
}
}
@@ -613,7 +613,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
*/
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, NULL, p_margin)) {
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
if (cbk.amount > 0) {
collided = true;
}
@@ -632,7 +632,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
if (ray_index != -1) {
- Physics2DServer::SeparationResult &result = r_results[ray_index];
+ PhysicsServer2D::SeparationResult &result = r_results[ray_index];
for (int k = 0; k < cbk.amount; k++) {
Vector2 a = sr[k * 2 + 0];
@@ -687,7 +687,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t
return rays_found;
}
-bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, Physics2DServer::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
//give me back regular physics engine logic
//this is madness
@@ -709,7 +709,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (p_body->is_shape_set_as_disabled(i))
continue;
- if (p_exclude_raycast_shapes && p_body->get_shape(i)->get_type() == Physics2DServer::SHAPE_RAY)
+ if (p_exclude_raycast_shapes && p_body->get_shape(i)->get_type() == PhysicsServer2D::SHAPE_RAY)
continue;
if (!shapes_found) {
@@ -722,7 +722,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (!shapes_found) {
if (r_result) {
- *r_result = Physics2DServer::MotionResult();
+ *r_result = PhysicsServer2D::MotionResult();
r_result->motion = p_motion;
}
return false;
@@ -749,7 +749,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
do {
- Physics2DServerSW::CollCbkData cbk;
+ PhysicsServer2DSW::CollCbkData cbk;
cbk.max = max_results;
cbk.amount = 0;
cbk.passed = 0;
@@ -757,8 +757,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.invalid_by_dir = 0;
excluded_shape_pair_count = 0; //last step is the one valid
- Physics2DServerSW::CollCbkData *cbkptr = &cbk;
- CollisionSolver2DSW::CallbackResult cbkres = Physics2DServerSW::_shape_col_cbk;
+ PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
+ CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
bool collided = false;
@@ -769,7 +769,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
continue;
Shape2DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == Physics2DServer::SHAPE_RAY) {
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
continue;
}
@@ -781,7 +781,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) {
+ if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
continue;
}
}
@@ -798,11 +798,11 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (b->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC || b->get_mode() == Physics2DServer::BODY_MODE_RIGID) {
+ 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 * Physics2DDirectBodyStateSW::singleton->step;
+ Vector2 motion = lv * PhysicsDirectBodyState2DSW::singleton->step;
float motion_len = motion.length();
motion.normalize();
cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0);
@@ -818,7 +818,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, NULL, separation_margin)) {
+ if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, separation_margin)) {
did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
}
@@ -884,7 +884,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
continue;
Shape2DSW *body_shape = p_body->get_shape(body_shape_idx);
- if (p_exclude_raycast_shapes && body_shape->get_type() == Physics2DServer::SHAPE_RAY) {
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
continue;
}
@@ -903,7 +903,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) {
+ if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
continue;
}
}
@@ -925,12 +925,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
//test initial overlap, does it collide if going all the way?
- if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) {
+ if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
continue;
}
//test initial overlap
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) {
+ 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;
@@ -950,7 +950,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
real_t ofs = (low + hi) * 0.5;
Vector2 sep = mnormal; //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(), NULL, NULL, &sep, 0);
+ 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) {
@@ -964,7 +964,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
Vector2 cd[2];
- Physics2DServerSW::CollCbkData cbk;
+ PhysicsServer2DSW::CollCbkData cbk;
cbk.max = 1;
cbk.amount = 0;
cbk.passed = 0;
@@ -974,7 +974,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
- 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(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
+ 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;
}
@@ -1018,7 +1018,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
_RestCallbackData2D rcd;
rcd.best_len = 0;
- rcd.best_object = NULL;
+ rcd.best_object = nullptr;
rcd.best_shape = 0;
rcd.min_allowed_depth = test_motion_min_contact_depth;
@@ -1034,7 +1034,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j);
Shape2DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == Physics2DServer::SHAPE_RAY) {
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
continue;
}
@@ -1049,7 +1049,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) {
+ if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
continue;
}
}
@@ -1081,7 +1081,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.object = col_obj;
rcd.shape = shape_idx;
rcd.local_shape = j;
- bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, NULL, p_margin);
+ bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, nullptr, p_margin);
if (!sc)
continue;
}
@@ -1156,7 +1156,7 @@ void *Space2DSW::_broadphase_pair(CollisionObject2DSW *A, int p_subindex_A, Coll
return b;
}
- return NULL;
+ return nullptr;
}
void Space2DSW::_broadphase_unpair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_self) {
@@ -1277,33 +1277,33 @@ void Space2DSW::update() {
broadphase->update();
}
-void Space2DSW::set_param(Physics2DServer::SpaceParameter p_param, real_t p_value) {
+void Space2DSW::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value) {
switch (p_param) {
- case Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius = p_value; break;
- case Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: contact_max_separation = p_value; break;
- case Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration = p_value; break;
- case Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: body_linear_velocity_sleep_threshold = p_value; break;
- case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: body_angular_velocity_sleep_threshold = p_value; break;
- case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break;
- case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break;
- case Physics2DServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_SEPARATION: contact_max_separation = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: body_linear_velocity_sleep_threshold = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: body_angular_velocity_sleep_threshold = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break;
+ case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break;
}
}
-real_t Space2DSW::get_param(Physics2DServer::SpaceParameter p_param) const {
+real_t Space2DSW::get_param(PhysicsServer2D::SpaceParameter p_param) const {
switch (p_param) {
- case Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius;
- case Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: return contact_max_separation;
- case Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: return contact_max_allowed_penetration;
- case Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: return body_linear_velocity_sleep_threshold;
- case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: return body_angular_velocity_sleep_threshold;
- case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
- case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
- case Physics2DServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius;
+ case PhysicsServer2D::SPACE_PARAM_CONTACT_MAX_SEPARATION: return contact_max_separation;
+ case PhysicsServer2D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: return contact_max_allowed_penetration;
+ case PhysicsServer2D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: return body_linear_velocity_sleep_threshold;
+ case PhysicsServer2D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: return body_angular_velocity_sleep_threshold;
+ case PhysicsServer2D::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
+ case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
+ case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth;
}
return 0;
}
@@ -1323,7 +1323,7 @@ bool Space2DSW::is_locked() const {
return locked;
}
-Physics2DDirectSpaceStateSW *Space2DSW::get_direct_state() {
+PhysicsDirectSpaceState2DSW *Space2DSW::get_direct_state() {
return direct_access;
}
@@ -1351,9 +1351,9 @@ Space2DSW::Space2DSW() {
broadphase = BroadPhase2DSW::create_func();
broadphase->set_pair_callback(_broadphase_pair, this);
broadphase->set_unpair_callback(_broadphase_unpair, this);
- area = NULL;
+ area = nullptr;
- direct_access = memnew(Physics2DDirectSpaceStateSW);
+ direct_access = memnew(PhysicsDirectSpaceState2DSW);
direct_access->space = this;
for (int i = 0; i < ELAPSED_TIME_MAX; i++)
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index 919c65d849..c6b324c928 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -41,9 +41,9 @@
#include "core/project_settings.h"
#include "core/typedefs.h"
-class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState {
+class PhysicsDirectSpaceState2DSW : public PhysicsDirectSpaceState2D {
- GDCLASS(Physics2DDirectSpaceStateSW, Physics2DDirectSpaceState);
+ GDCLASS(PhysicsDirectSpaceState2DSW, PhysicsDirectSpaceState2D);
int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = ObjectID());
@@ -58,7 +58,7 @@ public:
virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- Physics2DDirectSpaceStateSW();
+ PhysicsDirectSpaceState2DSW();
};
class Space2DSW {
@@ -83,7 +83,7 @@ private:
uint64_t elapsed_time[ELAPSED_TIME_MAX];
- Physics2DDirectSpaceStateSW *direct_access;
+ PhysicsDirectSpaceState2DSW *direct_access;
RID self;
BroadPhase2DSW *broadphase;
@@ -129,7 +129,7 @@ private:
Vector<Vector2> contact_debug;
int contact_debug_count;
- friend class Physics2DDirectSpaceStateSW;
+ friend class PhysicsDirectSpaceState2DSW;
public:
_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
@@ -175,8 +175,8 @@ public:
void lock();
void unlock();
- void set_param(Physics2DServer::SpaceParameter p_param, real_t p_value);
- real_t get_param(Physics2DServer::SpaceParameter p_param) const;
+ void set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value);
+ real_t get_param(PhysicsServer2D::SpaceParameter p_param) const;
void set_island_count(int p_island_count) { island_count = p_island_count; }
int get_island_count() const { return island_count; }
@@ -186,8 +186,8 @@ public:
int get_collision_pairs() const { return collision_pairs; }
- bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, Physics2DServer::MotionResult *r_result, bool p_exclude_raycast_shapes = true);
- int test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, Physics2DServer::SeparationResult *r_results, int p_result_max, real_t p_margin);
+ bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_exclude_raycast_shapes = true);
+ int test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin);
void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
_FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); }
@@ -197,7 +197,7 @@ public:
_FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; }
_FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
- Physics2DDirectSpaceStateSW *get_direct_state();
+ PhysicsDirectSpaceState2DSW *get_direct_state();
void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index 21f18229e7..6f3bcfec13 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -50,7 +50,7 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain
if (i == E->get())
continue;
Body2DSW *b = c->get_body_ptr()[i];
- if (b->get_island_step() == _step || b->get_mode() == Physics2DServer::BODY_MODE_STATIC || b->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC)
+ 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);
}
@@ -60,7 +60,7 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain
bool Step2DSW::_setup_island(Constraint2DSW *p_island, real_t p_delta) {
Constraint2DSW *ci = p_island;
- Constraint2DSW *prev_ci = NULL;
+ Constraint2DSW *prev_ci = nullptr;
bool removed_root = false;
while (ci) {
bool process = ci->setup(p_delta);
@@ -101,7 +101,7 @@ void Step2DSW::_check_suspend(Body2DSW *p_island, real_t p_delta) {
Body2DSW *b = p_island;
while (b) {
- if (b->get_mode() == Physics2DServer::BODY_MODE_STATIC || b->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
b = b->get_island_next();
continue; //ignore for static
}
@@ -117,7 +117,7 @@ void Step2DSW::_check_suspend(Body2DSW *p_island, real_t p_delta) {
b = p_island;
while (b) {
- if (b->get_mode() == Physics2DServer::BODY_MODE_STATIC || b->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC) {
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
b = b->get_island_next();
continue; //ignore for static
}
@@ -164,8 +164,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* GENERATE CONSTRAINT ISLANDS */
- Body2DSW *island_list = NULL;
- Constraint2DSW *constraint_island_list = NULL;
+ Body2DSW *island_list = nullptr;
+ Constraint2DSW *constraint_island_list = nullptr;
b = body_list->first();
int island_count = 0;
@@ -175,8 +175,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
if (body->get_island_step() != _step) {
- Body2DSW *island = NULL;
- Constraint2DSW *constraint_island = NULL;
+ Body2DSW *island = nullptr;
+ Constraint2DSW *constraint_island = nullptr;
_populate_island(body, &island, &constraint_island);
island->set_island_list_next(island_list);
@@ -202,7 +202,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
if (c->get_island_step() == _step)
continue;
c->set_island_step(_step);
- c->set_island_next(NULL);
+ c->set_island_next(nullptr);
c->set_island_list_next(constraint_island_list);
constraint_island_list = c;
}
@@ -219,7 +219,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
{
Constraint2DSW *ci = constraint_island_list;
- Constraint2DSW *prev_ci = NULL;
+ Constraint2DSW *prev_ci = nullptr;
while (ci) {
if (_setup_island(ci, p_delta)) {
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
deleted file mode 100644
index 1f92d6e419..0000000000
--- a/servers/physics_2d_server.cpp
+++ /dev/null
@@ -1,840 +0,0 @@
-/*************************************************************************/
-/* physics_2d_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_2d_server.h"
-
-#include "core/method_bind_ext.gen.inc"
-#include "core/print_string.h"
-#include "core/project_settings.h"
-
-Physics2DServer *Physics2DServer::singleton = NULL;
-
-void Physics2DDirectBodyState::integrate_forces() {
-
- real_t step = get_step();
- Vector2 lv = get_linear_velocity();
- lv += get_total_gravity() * step;
-
- real_t av = get_angular_velocity();
-
- float damp = 1.0 - step * get_total_linear_damp();
-
- if (damp < 0) // reached zero in the given time
- damp = 0;
-
- lv *= damp;
-
- damp = 1.0 - step * get_total_angular_damp();
-
- if (damp < 0) // reached zero in the given time
- damp = 0;
-
- av *= damp;
-
- set_linear_velocity(lv);
- set_angular_velocity(av);
-}
-
-Object *Physics2DDirectBodyState::get_contact_collider_object(int p_contact_idx) const {
-
- ObjectID objid = get_contact_collider_id(p_contact_idx);
- Object *obj = ObjectDB::get_instance(objid);
- return obj;
-}
-
-Physics2DServer *Physics2DServer::get_singleton() {
-
- return singleton;
-}
-
-void Physics2DDirectBodyState::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_total_gravity"), &Physics2DDirectBodyState::get_total_gravity);
- ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &Physics2DDirectBodyState::get_total_linear_damp);
- ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &Physics2DDirectBodyState::get_total_angular_damp);
-
- ClassDB::bind_method(D_METHOD("get_inverse_mass"), &Physics2DDirectBodyState::get_inverse_mass);
- ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &Physics2DDirectBodyState::get_inverse_inertia);
-
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &Physics2DDirectBodyState::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &Physics2DDirectBodyState::get_linear_velocity);
-
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &Physics2DDirectBodyState::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &Physics2DDirectBodyState::get_angular_velocity);
-
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &Physics2DDirectBodyState::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &Physics2DDirectBodyState::get_transform);
-
- ClassDB::bind_method(D_METHOD("add_central_force", "force"), &Physics2DDirectBodyState::add_central_force);
- ClassDB::bind_method(D_METHOD("add_force", "offset", "force"), &Physics2DDirectBodyState::add_force);
- ClassDB::bind_method(D_METHOD("add_torque", "torque"), &Physics2DDirectBodyState::add_torque);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &Physics2DDirectBodyState::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &Physics2DDirectBodyState::apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "offset", "impulse"), &Physics2DDirectBodyState::apply_impulse);
-
- ClassDB::bind_method(D_METHOD("set_sleep_state", "enabled"), &Physics2DDirectBodyState::set_sleep_state);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &Physics2DDirectBodyState::is_sleeping);
-
- ClassDB::bind_method(D_METHOD("get_contact_count"), &Physics2DDirectBodyState::get_contact_count);
-
- ClassDB::bind_method(D_METHOD("get_contact_local_position", "contact_idx"), &Physics2DDirectBodyState::get_contact_local_position);
- ClassDB::bind_method(D_METHOD("get_contact_local_normal", "contact_idx"), &Physics2DDirectBodyState::get_contact_local_normal);
- ClassDB::bind_method(D_METHOD("get_contact_local_shape", "contact_idx"), &Physics2DDirectBodyState::get_contact_local_shape);
- ClassDB::bind_method(D_METHOD("get_contact_collider", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider);
- ClassDB::bind_method(D_METHOD("get_contact_collider_position", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider_position);
- ClassDB::bind_method(D_METHOD("get_contact_collider_id", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider_id);
- ClassDB::bind_method(D_METHOD("get_contact_collider_object", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider_object);
- ClassDB::bind_method(D_METHOD("get_contact_collider_shape", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider_shape);
- ClassDB::bind_method(D_METHOD("get_contact_collider_shape_metadata", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider_shape_metadata);
- ClassDB::bind_method(D_METHOD("get_contact_collider_velocity_at_position", "contact_idx"), &Physics2DDirectBodyState::get_contact_collider_velocity_at_position);
- ClassDB::bind_method(D_METHOD("get_step"), &Physics2DDirectBodyState::get_step);
- ClassDB::bind_method(D_METHOD("integrate_forces"), &Physics2DDirectBodyState::integrate_forces);
- ClassDB::bind_method(D_METHOD("get_space_state"), &Physics2DDirectBodyState::get_space_state);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "", "get_step");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inverse_mass"), "", "get_inverse_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inverse_inertia"), "", "get_inverse_inertia");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "total_gravity"), "", "get_total_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
-}
-
-Physics2DDirectBodyState::Physics2DDirectBodyState() {}
-
-///////////////////////////////////////////////////////
-
-void Physics2DShapeQueryParameters::set_shape(const RES &p_shape) {
-
- ERR_FAIL_COND(p_shape.is_null());
- shape = p_shape->get_rid();
-}
-
-void Physics2DShapeQueryParameters::set_shape_rid(const RID &p_shape) {
-
- shape = p_shape;
-}
-
-RID Physics2DShapeQueryParameters::get_shape_rid() const {
-
- return shape;
-}
-
-void Physics2DShapeQueryParameters::set_transform(const Transform2D &p_transform) {
-
- transform = p_transform;
-}
-Transform2D Physics2DShapeQueryParameters::get_transform() const {
-
- return transform;
-}
-
-void Physics2DShapeQueryParameters::set_motion(const Vector2 &p_motion) {
-
- motion = p_motion;
-}
-Vector2 Physics2DShapeQueryParameters::get_motion() const {
-
- return motion;
-}
-
-void Physics2DShapeQueryParameters::set_margin(float p_margin) {
-
- margin = p_margin;
-}
-float Physics2DShapeQueryParameters::get_margin() const {
-
- return margin;
-}
-
-void Physics2DShapeQueryParameters::set_collision_mask(int p_collision_mask) {
-
- collision_mask = p_collision_mask;
-}
-int Physics2DShapeQueryParameters::get_collision_mask() const {
-
- return collision_mask;
-}
-
-void Physics2DShapeQueryParameters::set_exclude(const Vector<RID> &p_exclude) {
-
- exclude.clear();
- for (int i = 0; i < p_exclude.size(); i++)
- exclude.insert(p_exclude[i]);
-}
-
-Vector<RID> Physics2DShapeQueryParameters::get_exclude() const {
-
- Vector<RID> ret;
- ret.resize(exclude.size());
- int idx = 0;
- for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) {
- ret.write[idx] = E->get();
- }
- return ret;
-}
-
-void Physics2DShapeQueryParameters::set_collide_with_bodies(bool p_enable) {
- collide_with_bodies = p_enable;
-}
-
-bool Physics2DShapeQueryParameters::is_collide_with_bodies_enabled() const {
- return collide_with_bodies;
-}
-
-void Physics2DShapeQueryParameters::set_collide_with_areas(bool p_enable) {
- collide_with_areas = p_enable;
-}
-
-bool Physics2DShapeQueryParameters::is_collide_with_areas_enabled() const {
- return collide_with_areas;
-}
-
-void Physics2DShapeQueryParameters::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_shape", "shape"), &Physics2DShapeQueryParameters::set_shape);
- ClassDB::bind_method(D_METHOD("set_shape_rid", "shape"), &Physics2DShapeQueryParameters::set_shape_rid);
- ClassDB::bind_method(D_METHOD("get_shape_rid"), &Physics2DShapeQueryParameters::get_shape_rid);
-
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &Physics2DShapeQueryParameters::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &Physics2DShapeQueryParameters::get_transform);
-
- ClassDB::bind_method(D_METHOD("set_motion", "motion"), &Physics2DShapeQueryParameters::set_motion);
- ClassDB::bind_method(D_METHOD("get_motion"), &Physics2DShapeQueryParameters::get_motion);
-
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Physics2DShapeQueryParameters::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &Physics2DShapeQueryParameters::get_margin);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Physics2DShapeQueryParameters::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Physics2DShapeQueryParameters::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &Physics2DShapeQueryParameters::set_exclude);
- ClassDB::bind_method(D_METHOD("get_exclude"), &Physics2DShapeQueryParameters::get_exclude);
-
- ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &Physics2DShapeQueryParameters::set_collide_with_bodies);
- ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &Physics2DShapeQueryParameters::is_collide_with_bodies_enabled);
-
- ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &Physics2DShapeQueryParameters::set_collide_with_areas);
- ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &Physics2DShapeQueryParameters::is_collide_with_areas_enabled);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::_RID) + ":"), "set_exclude", "get_exclude");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion");
- //ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", ""); // FIXME: Lacks a getter
- ADD_PROPERTY(PropertyInfo(Variant::_RID, "shape_rid"), "set_shape_rid", "get_shape_rid");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
-}
-
-Physics2DShapeQueryParameters::Physics2DShapeQueryParameters() {
-
- margin = 0;
- collision_mask = 0x7FFFFFFF;
- collide_with_bodies = true;
- collide_with_areas = false;
-}
-
-Dictionary Physics2DDirectSpaceState::_intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- RayResult inters;
- Set<RID> exclude;
- for (int i = 0; i < p_exclude.size(); i++)
- exclude.insert(p_exclude[i]);
-
- bool res = intersect_ray(p_from, p_to, inters, exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
-
- if (!res)
- return Dictionary();
-
- Dictionary d;
- d["position"] = inters.position;
- d["normal"] = inters.normal;
- d["collider_id"] = inters.collider_id;
- d["collider"] = inters.collider;
- d["shape"] = inters.shape;
- d["rid"] = inters.rid;
- d["metadata"] = inters.metadata;
-
- return d;
-}
-
-Array Physics2DDirectSpaceState::_intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
-
- Vector<ShapeResult> sr;
- sr.resize(p_max_results);
- int rc = intersect_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, sr.ptrw(), sr.size(), p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- Array ret;
- ret.resize(rc);
- for (int i = 0; i < rc; i++) {
-
- Dictionary d;
- d["rid"] = sr[i].rid;
- d["collider_id"] = sr[i].collider_id;
- d["collider"] = sr[i].collider;
- d["shape"] = sr[i].shape;
- d["metadata"] = sr[i].metadata;
- ret[i] = d;
- }
-
- return ret;
-}
-
-Array Physics2DDirectSpaceState::_cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
-
- float closest_safe, closest_unsafe;
- bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- if (!res)
- return Array();
- Array ret;
- ret.resize(2);
- ret[0] = closest_safe;
- ret[1] = closest_unsafe;
- return ret;
-}
-
-Array Physics2DDirectSpaceState::_intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
-
- Set<RID> exclude;
- for (int i = 0; i < p_exclude.size(); i++)
- exclude.insert(p_exclude[i]);
-
- Vector<ShapeResult> ret;
- ret.resize(p_max_results);
-
- int rc;
- if (p_filter_by_canvas)
- rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
- else
- rc = intersect_point_on_canvas(p_point, p_canvas_instance_id, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
-
- if (rc == 0)
- return Array();
-
- Array r;
- r.resize(rc);
- for (int i = 0; i < rc; i++) {
-
- Dictionary d;
- d["rid"] = ret[i].rid;
- d["collider_id"] = ret[i].collider_id;
- d["collider"] = ret[i].collider;
- d["shape"] = ret[i].shape;
- d["metadata"] = ret[i].metadata;
- r[i] = d;
- }
- return r;
-}
-
-Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
-}
-
-Array Physics2DDirectSpaceState::_intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas, true, p_canvas_intance_id);
-}
-
-Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
-
- Vector<Vector2> ret;
- ret.resize(p_max_results * 2);
- int rc = 0;
- bool res = collide_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, ret.ptrw(), p_max_results, rc, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- if (!res)
- return Array();
- Array r;
- r.resize(rc * 2);
- for (int i = 0; i < rc * 2; i++)
- r[i] = ret[i];
- return r;
-}
-Dictionary Physics2DDirectSpaceState::_get_rest_info(const Ref<Physics2DShapeQueryParameters> &p_shape_query) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Dictionary());
-
- ShapeRestInfo sri;
-
- bool res = rest_info(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, &sri, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- Dictionary r;
- if (!res)
- return r;
-
- r["point"] = sri.point;
- r["normal"] = sri.normal;
- r["rid"] = sri.rid;
- r["collider_id"] = sri.collider_id;
- r["shape"] = sri.shape;
- r["linear_velocity"] = sri.linear_velocity;
- r["metadata"] = sri.metadata;
-
- return r;
-}
-
-Physics2DDirectSpaceState::Physics2DDirectSpaceState() {
-}
-
-void Physics2DDirectSpaceState::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &Physics2DDirectSpaceState::_intersect_shape, DEFVAL(32));
- ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &Physics2DDirectSpaceState::_cast_motion);
- ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &Physics2DDirectSpaceState::_collide_shape, DEFVAL(32));
- ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &Physics2DDirectSpaceState::_get_rest_info);
-}
-
-int Physics2DShapeQueryResult::get_result_count() const {
-
- return result.size();
-}
-RID Physics2DShapeQueryResult::get_result_rid(int p_idx) const {
-
- return result[p_idx].rid;
-}
-ObjectID Physics2DShapeQueryResult::get_result_object_id(int p_idx) const {
-
- return result[p_idx].collider_id;
-}
-Object *Physics2DShapeQueryResult::get_result_object(int p_idx) const {
-
- return result[p_idx].collider;
-}
-int Physics2DShapeQueryResult::get_result_object_shape(int p_idx) const {
-
- return result[p_idx].shape;
-}
-
-Physics2DShapeQueryResult::Physics2DShapeQueryResult() {
-}
-
-void Physics2DShapeQueryResult::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_result_count"), &Physics2DShapeQueryResult::get_result_count);
- ClassDB::bind_method(D_METHOD("get_result_rid", "idx"), &Physics2DShapeQueryResult::get_result_rid);
- ClassDB::bind_method(D_METHOD("get_result_object_id", "idx"), &Physics2DShapeQueryResult::get_result_object_id);
- ClassDB::bind_method(D_METHOD("get_result_object", "idx"), &Physics2DShapeQueryResult::get_result_object);
- ClassDB::bind_method(D_METHOD("get_result_object_shape", "idx"), &Physics2DShapeQueryResult::get_result_object_shape);
-}
-
-///////////////////////////////
-
-Vector2 Physics2DTestMotionResult::get_motion() const {
-
- return result.motion;
-}
-Vector2 Physics2DTestMotionResult::get_motion_remainder() const {
-
- return result.remainder;
-}
-
-Vector2 Physics2DTestMotionResult::get_collision_point() const {
-
- return result.collision_point;
-}
-Vector2 Physics2DTestMotionResult::get_collision_normal() const {
-
- return result.collision_normal;
-}
-Vector2 Physics2DTestMotionResult::get_collider_velocity() const {
-
- return result.collider_velocity;
-}
-ObjectID Physics2DTestMotionResult::get_collider_id() const {
-
- return result.collider_id;
-}
-RID Physics2DTestMotionResult::get_collider_rid() const {
-
- return result.collider;
-}
-
-Object *Physics2DTestMotionResult::get_collider() const {
- return ObjectDB::get_instance(result.collider_id);
-}
-
-int Physics2DTestMotionResult::get_collider_shape() const {
-
- return result.collider_shape;
-}
-
-void Physics2DTestMotionResult::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_motion"), &Physics2DTestMotionResult::get_motion);
- ClassDB::bind_method(D_METHOD("get_motion_remainder"), &Physics2DTestMotionResult::get_motion_remainder);
- ClassDB::bind_method(D_METHOD("get_collision_point"), &Physics2DTestMotionResult::get_collision_point);
- ClassDB::bind_method(D_METHOD("get_collision_normal"), &Physics2DTestMotionResult::get_collision_normal);
- ClassDB::bind_method(D_METHOD("get_collider_velocity"), &Physics2DTestMotionResult::get_collider_velocity);
- ClassDB::bind_method(D_METHOD("get_collider_id"), &Physics2DTestMotionResult::get_collider_id);
- ClassDB::bind_method(D_METHOD("get_collider_rid"), &Physics2DTestMotionResult::get_collider_rid);
- ClassDB::bind_method(D_METHOD("get_collider"), &Physics2DTestMotionResult::get_collider);
- ClassDB::bind_method(D_METHOD("get_collider_shape"), &Physics2DTestMotionResult::get_collider_shape);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "", "get_motion");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_remainder"), "", "get_motion_remainder");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_point"), "", "get_collision_point");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id");
- ADD_PROPERTY(PropertyInfo(Variant::_RID, "collider_rid"), "", "get_collider_rid");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape");
-}
-
-Physics2DTestMotionResult::Physics2DTestMotionResult() {
-
- colliding = false;
-
- result.collider_shape = 0;
-}
-
-///////////////////////////////////////
-
-bool Physics2DServer::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) {
-
- MotionResult *r = NULL;
- if (p_result.is_valid())
- r = p_result->get_result_ptr();
- return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r);
-}
-
-void Physics2DServer::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("line_shape_create"), &Physics2DServer::line_shape_create);
- ClassDB::bind_method(D_METHOD("ray_shape_create"), &Physics2DServer::ray_shape_create);
- ClassDB::bind_method(D_METHOD("segment_shape_create"), &Physics2DServer::segment_shape_create);
- ClassDB::bind_method(D_METHOD("circle_shape_create"), &Physics2DServer::circle_shape_create);
- ClassDB::bind_method(D_METHOD("rectangle_shape_create"), &Physics2DServer::rectangle_shape_create);
- ClassDB::bind_method(D_METHOD("capsule_shape_create"), &Physics2DServer::capsule_shape_create);
- ClassDB::bind_method(D_METHOD("convex_polygon_shape_create"), &Physics2DServer::convex_polygon_shape_create);
- ClassDB::bind_method(D_METHOD("concave_polygon_shape_create"), &Physics2DServer::concave_polygon_shape_create);
-
- ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &Physics2DServer::shape_set_data);
-
- ClassDB::bind_method(D_METHOD("shape_get_type", "shape"), &Physics2DServer::shape_get_type);
- ClassDB::bind_method(D_METHOD("shape_get_data", "shape"), &Physics2DServer::shape_get_data);
-
- ClassDB::bind_method(D_METHOD("space_create"), &Physics2DServer::space_create);
- ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &Physics2DServer::space_set_active);
- ClassDB::bind_method(D_METHOD("space_is_active", "space"), &Physics2DServer::space_is_active);
- ClassDB::bind_method(D_METHOD("space_set_param", "space", "param", "value"), &Physics2DServer::space_set_param);
- ClassDB::bind_method(D_METHOD("space_get_param", "space", "param"), &Physics2DServer::space_get_param);
- ClassDB::bind_method(D_METHOD("space_get_direct_state", "space"), &Physics2DServer::space_get_direct_state);
-
- ClassDB::bind_method(D_METHOD("area_create"), &Physics2DServer::area_create);
- ClassDB::bind_method(D_METHOD("area_set_space", "area", "space"), &Physics2DServer::area_set_space);
- ClassDB::bind_method(D_METHOD("area_get_space", "area"), &Physics2DServer::area_get_space);
-
- ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &Physics2DServer::area_set_space_override_mode);
- ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &Physics2DServer::area_get_space_override_mode);
-
- ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &Physics2DServer::area_add_shape, DEFVAL(Transform2D()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &Physics2DServer::area_set_shape);
- ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &Physics2DServer::area_set_shape_transform);
- ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &Physics2DServer::area_set_shape_disabled);
-
- ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &Physics2DServer::area_get_shape_count);
- ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &Physics2DServer::area_get_shape);
- ClassDB::bind_method(D_METHOD("area_get_shape_transform", "area", "shape_idx"), &Physics2DServer::area_get_shape_transform);
-
- ClassDB::bind_method(D_METHOD("area_remove_shape", "area", "shape_idx"), &Physics2DServer::area_remove_shape);
- ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &Physics2DServer::area_clear_shapes);
-
- ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &Physics2DServer::area_set_collision_layer);
- ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &Physics2DServer::area_set_collision_mask);
-
- ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &Physics2DServer::area_set_param);
- ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &Physics2DServer::area_set_transform);
-
- ClassDB::bind_method(D_METHOD("area_get_param", "area", "param"), &Physics2DServer::area_get_param);
- ClassDB::bind_method(D_METHOD("area_get_transform", "area"), &Physics2DServer::area_get_transform);
-
- ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &Physics2DServer::area_attach_object_instance_id);
- ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &Physics2DServer::area_get_object_instance_id);
-
- ClassDB::bind_method(D_METHOD("area_attach_canvas_instance_id", "area", "id"), &Physics2DServer::area_attach_canvas_instance_id);
- ClassDB::bind_method(D_METHOD("area_get_canvas_instance_id", "area"), &Physics2DServer::area_get_canvas_instance_id);
-
- ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_monitor_callback);
- ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_area_monitor_callback);
- ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &Physics2DServer::area_set_monitorable);
-
- ClassDB::bind_method(D_METHOD("body_create"), &Physics2DServer::body_create);
-
- ClassDB::bind_method(D_METHOD("body_set_space", "body", "space"), &Physics2DServer::body_set_space);
- ClassDB::bind_method(D_METHOD("body_get_space", "body"), &Physics2DServer::body_get_space);
-
- ClassDB::bind_method(D_METHOD("body_set_mode", "body", "mode"), &Physics2DServer::body_set_mode);
- ClassDB::bind_method(D_METHOD("body_get_mode", "body"), &Physics2DServer::body_get_mode);
-
- ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &Physics2DServer::body_add_shape, DEFVAL(Transform2D()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &Physics2DServer::body_set_shape);
- ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &Physics2DServer::body_set_shape_transform);
- ClassDB::bind_method(D_METHOD("body_set_shape_metadata", "body", "shape_idx", "metadata"), &Physics2DServer::body_set_shape_metadata);
-
- ClassDB::bind_method(D_METHOD("body_get_shape_count", "body"), &Physics2DServer::body_get_shape_count);
- ClassDB::bind_method(D_METHOD("body_get_shape", "body", "shape_idx"), &Physics2DServer::body_get_shape);
- ClassDB::bind_method(D_METHOD("body_get_shape_transform", "body", "shape_idx"), &Physics2DServer::body_get_shape_transform);
- ClassDB::bind_method(D_METHOD("body_get_shape_metadata", "body", "shape_idx"), &Physics2DServer::body_get_shape_metadata);
-
- ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &Physics2DServer::body_remove_shape);
- ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &Physics2DServer::body_clear_shapes);
-
- ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &Physics2DServer::body_set_shape_disabled);
- ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable", "margin"), &Physics2DServer::body_set_shape_as_one_way_collision);
-
- ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &Physics2DServer::body_attach_object_instance_id);
- ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &Physics2DServer::body_get_object_instance_id);
-
- ClassDB::bind_method(D_METHOD("body_attach_canvas_instance_id", "body", "id"), &Physics2DServer::body_attach_canvas_instance_id);
- ClassDB::bind_method(D_METHOD("body_get_canvas_instance_id", "body"), &Physics2DServer::body_get_canvas_instance_id);
-
- ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &Physics2DServer::body_set_continuous_collision_detection_mode);
- ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &Physics2DServer::body_get_continuous_collision_detection_mode);
-
- ClassDB::bind_method(D_METHOD("body_set_collision_layer", "body", "layer"), &Physics2DServer::body_set_collision_layer);
- ClassDB::bind_method(D_METHOD("body_get_collision_layer", "body"), &Physics2DServer::body_get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &Physics2DServer::body_set_collision_mask);
- ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &Physics2DServer::body_get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &Physics2DServer::body_set_param);
- ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &Physics2DServer::body_get_param);
-
- ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &Physics2DServer::body_set_state);
- ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &Physics2DServer::body_get_state);
-
- ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &Physics2DServer::body_apply_central_impulse);
- ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &Physics2DServer::body_apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &Physics2DServer::body_apply_impulse);
- ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &Physics2DServer::body_add_central_force);
- ClassDB::bind_method(D_METHOD("body_add_force", "body", "offset", "force"), &Physics2DServer::body_add_force);
- ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &Physics2DServer::body_add_torque);
- ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &Physics2DServer::body_set_axis_velocity);
-
- ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &Physics2DServer::body_add_collision_exception);
- ClassDB::bind_method(D_METHOD("body_remove_collision_exception", "body", "excepted_body"), &Physics2DServer::body_remove_collision_exception);
-
- ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &Physics2DServer::body_set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &Physics2DServer::body_get_max_contacts_reported);
-
- ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &Physics2DServer::body_set_omit_force_integration);
- ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &Physics2DServer::body_is_omitting_force_integration);
-
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &Physics2DServer::body_set_force_integration_callback, DEFVAL(Variant()));
-
- ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &Physics2DServer::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()));
-
- ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &Physics2DServer::body_get_direct_state);
-
- /* JOINT API */
-
- ClassDB::bind_method(D_METHOD("joint_set_param", "joint", "param", "value"), &Physics2DServer::joint_set_param);
- ClassDB::bind_method(D_METHOD("joint_get_param", "joint", "param"), &Physics2DServer::joint_get_param);
-
- ClassDB::bind_method(D_METHOD("pin_joint_create", "anchor", "body_a", "body_b"), &Physics2DServer::pin_joint_create, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("groove_joint_create", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &Physics2DServer::groove_joint_create, DEFVAL(RID()), DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("damped_spring_joint_create", "anchor_a", "anchor_b", "body_a", "body_b"), &Physics2DServer::damped_spring_joint_create, DEFVAL(RID()));
-
- ClassDB::bind_method(D_METHOD("damped_string_joint_set_param", "joint", "param", "value"), &Physics2DServer::damped_string_joint_set_param);
- ClassDB::bind_method(D_METHOD("damped_string_joint_get_param", "joint", "param"), &Physics2DServer::damped_string_joint_get_param);
-
- ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &Physics2DServer::joint_get_type);
-
- ClassDB::bind_method(D_METHOD("free_rid", "rid"), &Physics2DServer::free);
-
- ClassDB::bind_method(D_METHOD("set_active", "active"), &Physics2DServer::set_active);
-
- ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &Physics2DServer::get_process_info);
-
- BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_RECYCLE_RADIUS);
- BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_MAX_SEPARATION);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP);
- BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
- BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);
-
- BIND_ENUM_CONSTANT(SHAPE_LINE);
- BIND_ENUM_CONSTANT(SHAPE_RAY);
- BIND_ENUM_CONSTANT(SHAPE_SEGMENT);
- BIND_ENUM_CONSTANT(SHAPE_CIRCLE);
- BIND_ENUM_CONSTANT(SHAPE_RECTANGLE);
- BIND_ENUM_CONSTANT(SHAPE_CAPSULE);
- BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
- BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
- BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
-
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_DISTANCE_SCALE);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_ATTENUATION);
- BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP);
- BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP);
- BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY);
-
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_DISABLED);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE_REPLACE);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE_COMBINE);
-
- BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
- BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
- BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
- BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER);
-
- BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
- BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
- BIND_ENUM_CONSTANT(BODY_PARAM_MASS);
- BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA);
- BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE);
- BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP);
- BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP);
- BIND_ENUM_CONSTANT(BODY_PARAM_MAX);
-
- BIND_ENUM_CONSTANT(BODY_STATE_TRANSFORM);
- BIND_ENUM_CONSTANT(BODY_STATE_LINEAR_VELOCITY);
- BIND_ENUM_CONSTANT(BODY_STATE_ANGULAR_VELOCITY);
- 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_PARAM_BIAS);
- BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS);
- BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_FORCE);
-
- BIND_ENUM_CONSTANT(DAMPED_STRING_REST_LENGTH);
- BIND_ENUM_CONSTANT(DAMPED_STRING_STIFFNESS);
- BIND_ENUM_CONSTANT(DAMPED_STRING_DAMPING);
-
- BIND_ENUM_CONSTANT(CCD_MODE_DISABLED);
- BIND_ENUM_CONSTANT(CCD_MODE_CAST_RAY);
- BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
-
- BIND_ENUM_CONSTANT(AREA_BODY_ADDED);
- BIND_ENUM_CONSTANT(AREA_BODY_REMOVED);
-
- BIND_ENUM_CONSTANT(INFO_ACTIVE_OBJECTS);
- BIND_ENUM_CONSTANT(INFO_COLLISION_PAIRS);
- BIND_ENUM_CONSTANT(INFO_ISLAND_COUNT);
-}
-
-Physics2DServer::Physics2DServer() {
-
- singleton = this;
-}
-
-Physics2DServer::~Physics2DServer() {
-
- singleton = NULL;
-}
-
-Vector<Physics2DServerManager::ClassInfo> Physics2DServerManager::physics_2d_servers;
-int Physics2DServerManager::default_server_id = -1;
-int Physics2DServerManager::default_server_priority = -1;
-const String Physics2DServerManager::setting_property_name("physics/2d/physics_engine");
-
-void Physics2DServerManager::on_servers_changed() {
-
- String physics_servers("DEFAULT");
- for (int i = get_servers_count() - 1; 0 <= i; --i) {
- physics_servers += "," + get_server_name(i);
- }
- ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers));
-}
-
-void Physics2DServerManager::register_server(const String &p_name, CreatePhysics2DServerCallback p_creat_callback) {
-
- ERR_FAIL_COND(!p_creat_callback);
- ERR_FAIL_COND(find_server_id(p_name) != -1);
- physics_2d_servers.push_back(ClassInfo(p_name, p_creat_callback));
- on_servers_changed();
-}
-
-void Physics2DServerManager::set_default_server(const String &p_name, int p_priority) {
-
- const int id = find_server_id(p_name);
- ERR_FAIL_COND(id == -1); // Not found
- if (default_server_priority < p_priority) {
- default_server_id = id;
- default_server_priority = p_priority;
- }
-}
-
-int Physics2DServerManager::find_server_id(const String &p_name) {
-
- for (int i = physics_2d_servers.size() - 1; 0 <= i; --i) {
- if (p_name == physics_2d_servers[i].name) {
- return i;
- }
- }
- return -1;
-}
-
-int Physics2DServerManager::get_servers_count() {
- return physics_2d_servers.size();
-}
-
-String Physics2DServerManager::get_server_name(int p_id) {
- ERR_FAIL_INDEX_V(p_id, get_servers_count(), "");
- return physics_2d_servers[p_id].name;
-}
-
-Physics2DServer *Physics2DServerManager::new_default_server() {
- ERR_FAIL_COND_V(default_server_id == -1, NULL);
- return physics_2d_servers[default_server_id].create_callback();
-}
-
-Physics2DServer *Physics2DServerManager::new_server(const String &p_name) {
- int id = find_server_id(p_name);
- if (id == -1) {
- return NULL;
- } else {
- return physics_2d_servers[id].create_callback();
- }
-}
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
deleted file mode 100644
index c923ef16b7..0000000000
--- a/servers/physics_2d_server.h
+++ /dev/null
@@ -1,699 +0,0 @@
-/*************************************************************************/
-/* physics_2d_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS_2D_SERVER_H
-#define PHYSICS_2D_SERVER_H
-
-#include "core/object.h"
-#include "core/reference.h"
-#include "core/resource.h"
-
-class Physics2DDirectSpaceState;
-
-class Physics2DDirectBodyState : public Object {
-
- GDCLASS(Physics2DDirectBodyState, Object);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual Vector2 get_total_gravity() const = 0; // get gravity vector working on this body space/area
- virtual float get_total_linear_damp() const = 0; // get density of this body space/area
- virtual float get_total_angular_damp() const = 0; // get density of this body space/area
-
- virtual float get_inverse_mass() const = 0; // get the mass
- virtual real_t get_inverse_inertia() const = 0; // get density of this body space
-
- virtual void set_linear_velocity(const Vector2 &p_velocity) = 0;
- virtual Vector2 get_linear_velocity() const = 0;
-
- virtual void set_angular_velocity(real_t p_velocity) = 0;
- virtual real_t get_angular_velocity() const = 0;
-
- virtual void set_transform(const Transform2D &p_transform) = 0;
- virtual Transform2D get_transform() const = 0;
-
- virtual void add_central_force(const Vector2 &p_force) = 0;
- virtual void add_force(const Vector2 &p_offset, const Vector2 &p_force) = 0;
- virtual void add_torque(real_t p_torque) = 0;
- virtual void apply_central_impulse(const Vector2 &p_impulse) = 0;
- virtual void apply_torque_impulse(real_t p_torque) = 0;
- virtual void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) = 0;
-
- virtual void set_sleep_state(bool p_enable) = 0;
- virtual bool is_sleeping() const = 0;
-
- virtual int get_contact_count() const = 0;
-
- virtual Vector2 get_contact_local_position(int p_contact_idx) const = 0;
- virtual Vector2 get_contact_local_normal(int p_contact_idx) const = 0;
- virtual int get_contact_local_shape(int p_contact_idx) const = 0;
-
- virtual RID get_contact_collider(int p_contact_idx) const = 0;
- virtual Vector2 get_contact_collider_position(int p_contact_idx) const = 0;
- virtual ObjectID get_contact_collider_id(int p_contact_idx) const = 0;
- virtual Object *get_contact_collider_object(int p_contact_idx) const;
- virtual int get_contact_collider_shape(int p_contact_idx) const = 0;
- virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const = 0;
- virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const = 0;
-
- virtual real_t get_step() const = 0;
- virtual void integrate_forces();
-
- virtual Physics2DDirectSpaceState *get_space_state() = 0;
-
- Physics2DDirectBodyState();
-};
-
-class Physics2DShapeQueryResult;
-
-//used for script
-class Physics2DShapeQueryParameters : public Reference {
-
- GDCLASS(Physics2DShapeQueryParameters, Reference);
- friend class Physics2DDirectSpaceState;
- RID shape;
- Transform2D transform;
- Vector2 motion;
- float margin;
- Set<RID> exclude;
- uint32_t collision_mask;
-
- bool collide_with_bodies;
- bool collide_with_areas;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_shape(const RES &p_shape);
- void set_shape_rid(const RID &p_shape);
- RID get_shape_rid() const;
-
- void set_transform(const Transform2D &p_transform);
- Transform2D get_transform() const;
-
- void set_motion(const Vector2 &p_motion);
- Vector2 get_motion() const;
-
- void set_margin(float p_margin);
- float get_margin() const;
-
- void set_collision_mask(int p_collision_mask);
- int get_collision_mask() const;
-
- void set_collide_with_bodies(bool p_enable);
- bool is_collide_with_bodies_enabled() const;
-
- void set_collide_with_areas(bool p_enable);
- bool is_collide_with_areas_enabled() const;
-
- void set_exclude(const Vector<RID> &p_exclude);
- Vector<RID> get_exclude() const;
-
- Physics2DShapeQueryParameters();
-};
-
-class Physics2DDirectSpaceState : public Object {
-
- GDCLASS(Physics2DDirectSpaceState, Object);
-
- Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- Array _intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = ObjectID());
- Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
- Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
- Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32);
- Dictionary _get_rest_info(const Ref<Physics2DShapeQueryParameters> &p_shape_query);
-
-protected:
- static void _bind_methods();
-
-public:
- struct RayResult {
-
- Vector2 position;
- Vector2 normal;
- RID rid;
- ObjectID collider_id;
- Object *collider;
- int shape;
- Variant metadata;
- };
-
- virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- struct ShapeResult {
-
- RID rid;
- ObjectID collider_id;
- Object *collider;
- int shape;
- Variant metadata;
- };
-
- virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
- virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
-
- virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- struct ShapeRestInfo {
-
- Vector2 point;
- Vector2 normal;
- RID rid;
- ObjectID collider_id;
- int shape;
- Vector2 linear_velocity; //velocity at contact point
- Variant metadata;
- };
-
- virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- Physics2DDirectSpaceState();
-};
-
-class Physics2DShapeQueryResult : public Reference {
-
- GDCLASS(Physics2DShapeQueryResult, Reference);
-
- Vector<Physics2DDirectSpaceState::ShapeResult> result;
-
- friend class Physics2DDirectSpaceState;
-
-protected:
- static void _bind_methods();
-
-public:
- int get_result_count() const;
- RID get_result_rid(int p_idx) const;
- ObjectID get_result_object_id(int p_idx) const;
- Object *get_result_object(int p_idx) const;
- int get_result_object_shape(int p_idx) const;
-
- Physics2DShapeQueryResult();
-};
-
-class Physics2DTestMotionResult;
-
-class Physics2DServer : public Object {
-
- GDCLASS(Physics2DServer, Object);
-
- static Physics2DServer *singleton;
-
- virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>());
-
-protected:
- static void _bind_methods();
-
-public:
- static Physics2DServer *get_singleton();
-
- enum ShapeType {
- SHAPE_LINE, ///< plane:"plane"
- SHAPE_RAY, ///< float:"length"
- SHAPE_SEGMENT, ///< float:"length"
- SHAPE_CIRCLE, ///< float:"radius"
- SHAPE_RECTANGLE, ///< vec3:"extents"
- SHAPE_CAPSULE,
- SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
- SHAPE_CONCAVE_POLYGON, ///< Vector2 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector2 array)
- SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
- };
-
- virtual RID line_shape_create() = 0;
- virtual RID ray_shape_create() = 0;
- virtual RID segment_shape_create() = 0;
- virtual RID circle_shape_create() = 0;
- virtual RID rectangle_shape_create() = 0;
- virtual RID capsule_shape_create() = 0;
- virtual RID convex_polygon_shape_create() = 0;
- virtual RID concave_polygon_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;
-
- virtual ShapeType shape_get_type(RID p_shape) const = 0;
- virtual Variant shape_get_data(RID p_shape) const = 0;
- virtual real_t shape_get_custom_solver_bias(RID p_shape) const = 0;
-
- //these work well, but should be used from the main thread only
- virtual 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) = 0;
-
- /* SPACE API */
-
- virtual RID space_create() = 0;
- virtual void space_set_active(RID p_space, bool p_active) = 0;
- virtual bool space_is_active(RID p_space) const = 0;
-
- enum SpaceParameter {
-
- SPACE_PARAM_CONTACT_RECYCLE_RADIUS,
- SPACE_PARAM_CONTACT_MAX_SEPARATION,
- SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,
- SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD,
- SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD,
- SPACE_PARAM_BODY_TIME_TO_SLEEP,
- SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
- SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH,
- };
-
- virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0;
- virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const = 0;
-
- // this function only works on physics process, errors and returns null otherwise
- virtual Physics2DDirectSpaceState *space_get_direct_state(RID p_space) = 0;
-
- virtual void space_set_debug_contacts(RID p_space, int p_max_contacts) = 0;
- virtual Vector<Vector2> space_get_contacts(RID p_space) const = 0;
- virtual int space_get_contact_count(RID p_space) const = 0;
-
- //missing space parameters
-
- /* AREA API */
-
- //missing attenuation? missing better override?
-
- enum AreaParameter {
- AREA_PARAM_GRAVITY,
- AREA_PARAM_GRAVITY_VECTOR,
- AREA_PARAM_GRAVITY_IS_POINT,
- AREA_PARAM_GRAVITY_DISTANCE_SCALE,
- AREA_PARAM_GRAVITY_POINT_ATTENUATION,
- AREA_PARAM_LINEAR_DAMP,
- AREA_PARAM_ANGULAR_DAMP,
- AREA_PARAM_PRIORITY
- };
-
- virtual RID area_create() = 0;
-
- virtual void area_set_space(RID p_area, RID p_space) = 0;
- virtual RID area_get_space(RID p_area) const = 0;
-
- enum AreaSpaceOverrideMode {
- AREA_SPACE_OVERRIDE_DISABLED,
- AREA_SPACE_OVERRIDE_COMBINE,
- AREA_SPACE_OVERRIDE_COMBINE_REPLACE, // Combines, then discards all subsequent calculations
- AREA_SPACE_OVERRIDE_REPLACE,
- AREA_SPACE_OVERRIDE_REPLACE_COMBINE // Discards all previous calculations, then keeps combining
- };
-
- virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
- virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
-
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
- virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
- virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) = 0;
-
- virtual int area_get_shape_count(RID p_area) const = 0;
- virtual RID area_get_shape(RID p_area, int p_shape_idx) const = 0;
- virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const = 0;
-
- virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0;
- virtual void area_clear_shapes(RID p_area) = 0;
-
- virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) = 0;
-
- virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id) = 0;
- virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
-
- virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_id) = 0;
- virtual ObjectID area_get_canvas_instance_id(RID p_area) const = 0;
-
- virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
- virtual void area_set_transform(RID p_area, const Transform2D &p_transform) = 0;
-
- virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
- virtual Transform2D area_get_transform(RID p_area) const = 0;
-
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
- virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
-
- virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
- virtual void area_set_pickable(RID p_area, bool p_pickable) = 0;
-
- virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
- virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
-
- /* BODY API */
-
- //missing ccd?
-
- enum BodyMode {
- BODY_MODE_STATIC,
- BODY_MODE_KINEMATIC,
- BODY_MODE_RIGID,
- BODY_MODE_CHARACTER
- };
-
- 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;
-
- virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
- virtual BodyMode body_get_mode(RID p_body) const = 0;
-
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
- virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
- virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) = 0;
- virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) = 0;
-
- virtual int body_get_shape_count(RID p_body) const = 0;
- virtual RID body_get_shape(RID p_body, int p_shape_idx) const = 0;
- virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0;
- virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0;
-
- virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0;
- virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, float p_margin = 0) = 0;
-
- virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
- virtual void body_clear_shapes(RID p_body) = 0;
-
- virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) = 0;
- virtual ObjectID body_get_object_instance_id(RID p_body) const = 0;
-
- virtual void body_attach_canvas_instance_id(RID p_body, ObjectID p_id) = 0;
- virtual ObjectID body_get_canvas_instance_id(RID p_body) const = 0;
-
- enum CCDMode {
- CCD_MODE_DISABLED,
- CCD_MODE_CAST_RAY,
- CCD_MODE_CAST_SHAPE,
- };
-
- virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) = 0;
- virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const = 0;
-
- virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
- virtual uint32_t body_get_collision_layer(RID p_body) const = 0;
-
- virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
- virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
-
- // common body variables
- enum BodyParameter {
- BODY_PARAM_BOUNCE,
- BODY_PARAM_FRICTION,
- BODY_PARAM_MASS, ///< unused for static, always infinite
- BODY_PARAM_INERTIA, // read-only: computed from mass & shapes
- BODY_PARAM_GRAVITY_SCALE,
- BODY_PARAM_LINEAR_DAMP,
- BODY_PARAM_ANGULAR_DAMP,
- BODY_PARAM_MAX,
- };
-
- virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
- virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
-
- //state
- enum BodyState {
- BODY_STATE_TRANSFORM,
- BODY_STATE_LINEAR_VELOCITY,
- BODY_STATE_ANGULAR_VELOCITY,
- BODY_STATE_SLEEPING,
- BODY_STATE_CAN_SLEEP,
- };
-
- virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0;
- virtual Variant body_get_state(RID p_body, BodyState p_state) const = 0;
-
- //do something about it
- virtual void body_set_applied_force(RID p_body, const Vector2 &p_force) = 0;
- virtual Vector2 body_get_applied_force(RID p_body) const = 0;
-
- virtual void body_set_applied_torque(RID p_body, float p_torque) = 0;
- virtual float body_get_applied_torque(RID p_body) const = 0;
-
- virtual void body_add_central_force(RID p_body, const Vector2 &p_force) = 0;
- virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) = 0;
- virtual void body_add_torque(RID p_body, float p_torque) = 0;
-
- virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) = 0;
- virtual void body_apply_torque_impulse(RID p_body, float p_torque) = 0;
- virtual void body_apply_impulse(RID p_body, const Vector2 &p_offset, const Vector2 &p_impulse) = 0;
- virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) = 0;
-
- //fix
- virtual void body_add_collision_exception(RID p_body, RID p_body_b) = 0;
- virtual void body_remove_collision_exception(RID p_body, RID p_body_b) = 0;
- virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0;
-
- virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0;
- virtual int body_get_max_contacts_reported(RID p_body) const = 0;
-
- //missing remove
- virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) = 0;
- virtual float body_get_contacts_reported_depth_threshold(RID p_body) const = 0;
-
- 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 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;
-
- virtual void body_set_pickable(RID p_body, bool p_pickable) = 0;
-
- // this function only works on physics process, errors and returns null otherwise
- virtual Physics2DDirectBodyState *body_get_direct_state(RID p_body) = 0;
-
- struct MotionResult {
-
- Vector2 motion;
- Vector2 remainder;
-
- Vector2 collision_point;
- Vector2 collision_normal;
- Vector2 collider_velocity;
- int collision_local_shape;
- ObjectID collider_id;
- RID collider;
- int collider_shape;
- Variant collider_metadata;
-
- MotionResult() {
- collision_local_shape = 0;
- collider_shape = 0;
- collider_id = ObjectID();
- }
- };
-
- virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.001, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true) = 0;
-
- struct SeparationResult {
-
- float collision_depth;
- Vector2 collision_point;
- Vector2 collision_normal;
- Vector2 collider_velocity;
- int collision_local_shape;
- ObjectID collider_id;
- RID collider;
- int collider_shape;
- Variant collider_metadata;
- };
-
- virtual 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, float p_margin = 0.001) = 0;
-
- /* JOINT API */
-
- enum JointType {
-
- JOINT_PIN,
- JOINT_GROOVE,
- JOINT_DAMPED_SPRING
- };
-
- enum JointParam {
- JOINT_PARAM_BIAS,
- JOINT_PARAM_MAX_BIAS,
- JOINT_PARAM_MAX_FORCE,
- };
-
- virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value) = 0;
- virtual real_t joint_get_param(RID p_joint, JointParam p_param) const = 0;
-
- 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;
-
- enum PinJointParam {
- PIN_JOINT_SOFTNESS
- };
-
- virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) = 0;
- virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const = 0;
-
- enum DampedStringParam {
- DAMPED_STRING_REST_LENGTH,
- DAMPED_STRING_STIFFNESS,
- DAMPED_STRING_DAMPING
- };
- virtual void damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value) = 0;
- virtual real_t damped_string_joint_get_param(RID p_joint, DampedStringParam p_param) const = 0;
-
- virtual JointType joint_get_type(RID p_joint) const = 0;
-
- /* QUERY API */
-
- enum AreaBodyStatus {
- AREA_BODY_ADDED,
- AREA_BODY_REMOVED
- };
-
- /* MISC */
-
- virtual void free(RID p_rid) = 0;
-
- virtual void set_active(bool p_active) = 0;
- virtual void init() = 0;
- virtual void step(float 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;
-
- enum ProcessInfo {
-
- INFO_ACTIVE_OBJECTS,
- INFO_COLLISION_PAIRS,
- INFO_ISLAND_COUNT
- };
-
- virtual int get_process_info(ProcessInfo p_info) = 0;
-
- Physics2DServer();
- ~Physics2DServer();
-};
-
-class Physics2DTestMotionResult : public Reference {
-
- GDCLASS(Physics2DTestMotionResult, Reference);
-
- Physics2DServer::MotionResult result;
- bool colliding;
- friend class Physics2DServer;
-
-protected:
- static void _bind_methods();
-
-public:
- Physics2DServer::MotionResult *get_result_ptr() const { return const_cast<Physics2DServer::MotionResult *>(&result); }
-
- //bool is_colliding() const;
- Vector2 get_motion() const;
- Vector2 get_motion_remainder() const;
-
- Vector2 get_collision_point() const;
- Vector2 get_collision_normal() const;
- Vector2 get_collider_velocity() const;
- ObjectID get_collider_id() const;
- RID get_collider_rid() const;
- Object *get_collider() const;
- int get_collider_shape() const;
-
- Physics2DTestMotionResult();
-};
-
-typedef Physics2DServer *(*CreatePhysics2DServerCallback)();
-
-class Physics2DServerManager {
- struct ClassInfo {
- String name;
- CreatePhysics2DServerCallback create_callback;
-
- ClassInfo() :
- name(""),
- create_callback(NULL) {}
-
- ClassInfo(String p_name, CreatePhysics2DServerCallback p_create_callback) :
- name(p_name),
- create_callback(p_create_callback) {}
-
- ClassInfo(const ClassInfo &p_ci) :
- name(p_ci.name),
- create_callback(p_ci.create_callback) {}
-
- ClassInfo operator=(const ClassInfo &p_ci) {
- name = p_ci.name;
- create_callback = p_ci.create_callback;
- return *this;
- }
- };
-
- static Vector<ClassInfo> physics_2d_servers;
- static int default_server_id;
- static int default_server_priority;
-
-public:
- static const String setting_property_name;
-
-private:
- static void on_servers_changed();
-
-public:
- static void register_server(const String &p_name, CreatePhysics2DServerCallback p_creat_callback);
- static void set_default_server(const String &p_name, int p_priority = 0);
- static int find_server_id(const String &p_name);
- static int get_servers_count();
- static String get_server_name(int p_id);
- static Physics2DServer *new_default_server();
- static Physics2DServer *new_server(const String &p_name);
-};
-
-VARIANT_ENUM_CAST(Physics2DServer::ShapeType);
-VARIANT_ENUM_CAST(Physics2DServer::SpaceParameter);
-VARIANT_ENUM_CAST(Physics2DServer::AreaParameter);
-VARIANT_ENUM_CAST(Physics2DServer::AreaSpaceOverrideMode);
-VARIANT_ENUM_CAST(Physics2DServer::BodyMode);
-VARIANT_ENUM_CAST(Physics2DServer::BodyParameter);
-VARIANT_ENUM_CAST(Physics2DServer::BodyState);
-VARIANT_ENUM_CAST(Physics2DServer::CCDMode);
-VARIANT_ENUM_CAST(Physics2DServer::JointParam);
-VARIANT_ENUM_CAST(Physics2DServer::JointType);
-VARIANT_ENUM_CAST(Physics2DServer::DampedStringParam);
-//VARIANT_ENUM_CAST( Physics2DServer::ObjectType );
-VARIANT_ENUM_CAST(Physics2DServer::AreaBodyStatus);
-VARIANT_ENUM_CAST(Physics2DServer::ProcessInfo);
-
-#endif
diff --git a/servers/physics_3d/SCsub b/servers/physics_3d/SCsub
new file mode 100644
index 0000000000..df7b521693
--- /dev/null
+++ b/servers/physics_3d/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
+
+SConscript("joints/SCsub")
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp
new file mode 100644
index 0000000000..911a664a10
--- /dev/null
+++ b/servers/physics_3d/area_3d_sw.cpp
@@ -0,0 +1,264 @@
+/*************************************************************************/
+/* area_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "area_3d_sw.h"
+#include "body_3d_sw.h"
+#include "space_3d_sw.h"
+
+Area3DSW::BodyKey::BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+ rid = p_body->get_self();
+ instance_id = p_body->get_instance_id();
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+}
+Area3DSW::BodyKey::BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+ rid = p_body->get_self();
+ instance_id = p_body->get_instance_id();
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+}
+
+void Area3DSW::_shapes_changed() {
+
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+}
+
+void Area3DSW::set_transform(const Transform &p_transform) {
+
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+ _set_transform(p_transform);
+ _set_inv_transform(p_transform.affine_inverse());
+}
+
+void Area3DSW::set_space(Space3DSW *p_space) {
+
+ if (get_space()) {
+ if (monitor_query_list.in_list())
+ get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
+ if (moved_list.in_list())
+ get_space()->area_remove_from_moved_list(&moved_list);
+ }
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _set_space(p_space);
+}
+
+void Area3DSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) {
+
+ if (p_id == monitor_callback_id) {
+ monitor_callback_method = p_method;
+ return;
+ }
+
+ _unregister_shapes();
+
+ monitor_callback_id = p_id;
+ monitor_callback_method = p_method;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+}
+
+void Area3DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_method) {
+
+ if (p_id == area_monitor_callback_id) {
+ area_monitor_callback_method = p_method;
+ return;
+ }
+
+ _unregister_shapes();
+
+ area_monitor_callback_id = p_id;
+ area_monitor_callback_method = p_method;
+
+ monitored_bodies.clear();
+ monitored_areas.clear();
+
+ _shape_changed();
+
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+}
+
+void Area3DSW::set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode p_mode) {
+ bool do_override = p_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED;
+ if (do_override == (space_override_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED))
+ return;
+ _unregister_shapes();
+ space_override_mode = p_mode;
+ _shape_changed();
+}
+
+void Area3DSW::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) {
+
+ switch (p_param) {
+ case PhysicsServer3D::AREA_PARAM_GRAVITY: gravity = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: gravity_vector = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: linear_damp = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: angular_damp = p_value; break;
+ case PhysicsServer3D::AREA_PARAM_PRIORITY: priority = p_value; break;
+ }
+}
+
+Variant Area3DSW::get_param(PhysicsServer3D::AreaParameter p_param) const {
+
+ switch (p_param) {
+ case PhysicsServer3D::AREA_PARAM_GRAVITY: return gravity;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale;
+ case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation;
+ case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: return linear_damp;
+ case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
+ case PhysicsServer3D::AREA_PARAM_PRIORITY: return priority;
+ }
+
+ return Variant();
+}
+
+void Area3DSW::_queue_monitor_update() {
+
+ ERR_FAIL_COND(!get_space());
+
+ if (!monitor_query_list.in_list())
+ get_space()->area_add_to_monitor_query_list(&monitor_query_list);
+}
+
+void Area3DSW::set_monitorable(bool p_monitorable) {
+
+ if (monitorable == p_monitorable)
+ return;
+
+ monitorable = p_monitorable;
+ _set_static(!monitorable);
+}
+
+void Area3DSW::call_queries() {
+
+ if (monitor_callback_id.is_valid() && !monitored_bodies.empty()) {
+
+ Variant res[5];
+ Variant *resptr[5];
+ for (int i = 0; i < 5; i++)
+ resptr[i] = &res[i];
+
+ Object *obj = ObjectDB::get_instance(monitor_callback_id);
+ if (!obj) {
+ monitored_bodies.clear();
+ monitor_callback_id = ObjectID();
+ return;
+ }
+
+ for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E; E = E->next()) {
+
+ if (E->get().state == 0)
+ continue; //nothing happened
+
+ res[0] = E->get().state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED;
+ res[1] = E->key().rid;
+ res[2] = E->key().instance_id;
+ res[3] = E->key().body_shape;
+ res[4] = E->key().area_shape;
+
+ Callable::CallError ce;
+ obj->call(monitor_callback_method, (const Variant **)resptr, 5, ce);
+ }
+ }
+
+ monitored_bodies.clear();
+
+ if (area_monitor_callback_id.is_valid() && !monitored_areas.empty()) {
+
+ Variant res[5];
+ Variant *resptr[5];
+ for (int i = 0; i < 5; i++)
+ resptr[i] = &res[i];
+
+ Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
+ if (!obj) {
+ monitored_areas.clear();
+ area_monitor_callback_id = ObjectID();
+ return;
+ }
+
+ for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E; E = E->next()) {
+
+ if (E->get().state == 0)
+ continue; //nothing happened
+
+ res[0] = E->get().state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED;
+ res[1] = E->key().rid;
+ res[2] = E->key().instance_id;
+ res[3] = E->key().body_shape;
+ res[4] = E->key().area_shape;
+
+ Callable::CallError ce;
+ obj->call(area_monitor_callback_method, (const Variant **)resptr, 5, ce);
+ }
+ }
+
+ monitored_areas.clear();
+ //get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
+}
+
+Area3DSW::Area3DSW() :
+ CollisionObject3DSW(TYPE_AREA),
+ monitor_query_list(this),
+ moved_list(this) {
+
+ _set_static(true); //areas are never active
+ space_override_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED;
+ gravity = 9.80665;
+ gravity_vector = Vector3(0, -1, 0);
+ gravity_is_point = false;
+ gravity_distance_scale = 0;
+ point_attenuation = 1;
+ angular_damp = 0.1;
+ linear_damp = 0.1;
+ priority = 0;
+ set_ray_pickable(false);
+ monitorable = false;
+}
+
+Area3DSW::~Area3DSW() {
+}
diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h
new file mode 100644
index 0000000000..05e74e63dc
--- /dev/null
+++ b/servers/physics_3d/area_3d_sw.h
@@ -0,0 +1,203 @@
+/*************************************************************************/
+/* area_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 AREA_SW_H
+#define AREA_SW_H
+
+#include "collision_object_3d_sw.h"
+#include "core/self_list.h"
+#include "servers/physics_server_3d.h"
+//#include "servers/physics_3d/query_sw.h"
+
+class Space3DSW;
+class Body3DSW;
+class Constraint3DSW;
+
+class Area3DSW : public CollisionObject3DSW {
+
+ PhysicsServer3D::AreaSpaceOverrideMode space_override_mode;
+ real_t gravity;
+ Vector3 gravity_vector;
+ bool gravity_is_point;
+ real_t gravity_distance_scale;
+ real_t point_attenuation;
+ real_t linear_damp;
+ real_t angular_damp;
+ int priority;
+ bool monitorable;
+
+ ObjectID monitor_callback_id;
+ StringName monitor_callback_method;
+
+ ObjectID area_monitor_callback_id;
+ StringName area_monitor_callback_method;
+
+ SelfList<Area3DSW> monitor_query_list;
+ SelfList<Area3DSW> moved_list;
+
+ struct BodyKey {
+
+ RID rid;
+ ObjectID instance_id;
+ uint32_t body_shape;
+ uint32_t area_shape;
+
+ _FORCE_INLINE_ bool operator<(const BodyKey &p_key) const {
+
+ if (rid == p_key.rid) {
+
+ if (body_shape == p_key.body_shape) {
+
+ return area_shape < p_key.area_shape;
+ } else
+ return body_shape < p_key.body_shape;
+ } else
+ return rid < p_key.rid;
+ }
+
+ _FORCE_INLINE_ BodyKey() {}
+ BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ };
+
+ struct BodyState {
+
+ int state;
+ _FORCE_INLINE_ void inc() { state++; }
+ _FORCE_INLINE_ void dec() { state--; }
+ _FORCE_INLINE_ BodyState() { state = 0; }
+ };
+
+ Map<BodyKey, BodyState> monitored_bodies;
+ Map<BodyKey, BodyState> monitored_areas;
+
+ //virtual void shape_changed_notify(ShapeSW *p_shape);
+ //virtual void shape_deleted_notify(ShapeSW *p_shape);
+
+ Set<Constraint3DSW *> constraints;
+
+ virtual void _shapes_changed();
+ void _queue_monitor_update();
+
+public:
+ //_FORCE_INLINE_ const Transform& get_inverse_transform() const { return inverse_transform; }
+ //_FORCE_INLINE_ SpaceSW* get_owner() { return owner; }
+
+ void set_monitor_callback(ObjectID p_id, const StringName &p_method);
+ _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); }
+
+ void set_area_monitor_callback(ObjectID p_id, const StringName &p_method);
+ _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); }
+
+ _FORCE_INLINE_ void add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+ _FORCE_INLINE_ void remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape);
+
+ _FORCE_INLINE_ void add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
+ _FORCE_INLINE_ void remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape);
+
+ void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer3D::AreaParameter p_param) const;
+
+ void set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode p_mode);
+ PhysicsServer3D::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; }
+
+ _FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; }
+ _FORCE_INLINE_ real_t get_gravity() const { return gravity; }
+
+ _FORCE_INLINE_ void set_gravity_vector(const Vector3 &p_gravity) { gravity_vector = p_gravity; }
+ _FORCE_INLINE_ Vector3 get_gravity_vector() const { return gravity_vector; }
+
+ _FORCE_INLINE_ void set_gravity_as_point(bool p_enable) { gravity_is_point = p_enable; }
+ _FORCE_INLINE_ bool is_gravity_point() const { return gravity_is_point; }
+
+ _FORCE_INLINE_ void set_gravity_distance_scale(real_t scale) { gravity_distance_scale = scale; }
+ _FORCE_INLINE_ real_t get_gravity_distance_scale() const { return gravity_distance_scale; }
+
+ _FORCE_INLINE_ void set_point_attenuation(real_t p_point_attenuation) { point_attenuation = p_point_attenuation; }
+ _FORCE_INLINE_ real_t get_point_attenuation() const { return point_attenuation; }
+
+ _FORCE_INLINE_ void set_linear_damp(real_t p_linear_damp) { linear_damp = p_linear_damp; }
+ _FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
+
+ _FORCE_INLINE_ void set_angular_damp(real_t p_angular_damp) { angular_damp = p_angular_damp; }
+ _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
+
+ _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
+ _FORCE_INLINE_ int get_priority() const { return priority; }
+
+ _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(); }
+
+ void set_monitorable(bool p_monitorable);
+ _FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
+
+ void set_transform(const Transform &p_transform);
+
+ void set_space(Space3DSW *p_space);
+
+ void call_queries();
+
+ Area3DSW();
+ ~Area3DSW();
+};
+
+void Area3DSW::add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+
+ BodyKey bk(p_body, p_body_shape, p_area_shape);
+ monitored_bodies[bk].inc();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+}
+void Area3DSW::remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) {
+
+ BodyKey bk(p_body, p_body_shape, p_area_shape);
+ monitored_bodies[bk].dec();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+}
+
+void Area3DSW::add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
+
+ BodyKey bk(p_area, p_area_shape, p_self_shape);
+ monitored_areas[bk].inc();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+}
+void Area3DSW::remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) {
+
+ BodyKey bk(p_area, p_area_shape, p_self_shape);
+ monitored_areas[bk].dec();
+ if (!monitor_query_list.in_list())
+ _queue_monitor_update();
+}
+
+#endif // AREA__SW_H
diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp
new file mode 100644
index 0000000000..fa2fb2dabb
--- /dev/null
+++ b/servers/physics_3d/area_pair_3d_sw.cpp
@@ -0,0 +1,159 @@
+/*************************************************************************/
+/* area_pair_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "area_pair_3d_sw.h"
+#include "collision_solver_3d_sw.h"
+
+bool AreaPair3DSW::setup(real_t p_step) {
+
+ bool result = false;
+
+ if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) {
+ result = false;
+ } else if (area->test_collision_mask(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) {
+ result = true;
+ }
+
+ if (result != colliding) {
+
+ if (result) {
+
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED)
+ body->add_area(area);
+ if (area->has_monitor_callback())
+ area->add_body_to_query(body, body_shape, area_shape);
+
+ } else {
+
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED)
+ body->remove_area(area);
+ if (area->has_monitor_callback())
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+
+ colliding = result;
+ }
+
+ return false; //never do any post solving
+}
+
+void AreaPair3DSW::solve(real_t p_step) {
+}
+
+AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape) {
+
+ body = p_body;
+ area = p_area;
+ body_shape = p_body_shape;
+ area_shape = p_area_shape;
+ colliding = false;
+ body->add_constraint(this, 0);
+ area->add_constraint(this);
+ if (p_body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC)
+ p_body->set_active(true);
+}
+
+AreaPair3DSW::~AreaPair3DSW() {
+
+ if (colliding) {
+
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED)
+ body->remove_area(area);
+ if (area->has_monitor_callback())
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+ body->remove_constraint(this);
+ area->remove_constraint(this);
+}
+
+////////////////////////////////////////////////////
+
+bool Area2Pair3DSW::setup(real_t p_step) {
+
+ bool result = false;
+ if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) {
+ result = false;
+ } else if (area_a->test_collision_mask(area_b) && CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) {
+ result = true;
+ }
+
+ if (result != colliding) {
+
+ if (result) {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->add_area_to_query(area_a, shape_a, shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->add_area_to_query(area_b, shape_b, shape_a);
+
+ } else {
+
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
+
+ colliding = result;
+ }
+
+ return false; //never do any post solving
+}
+
+void Area2Pair3DSW::solve(real_t p_step) {
+}
+
+Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b) {
+
+ area_a = p_area_a;
+ area_b = p_area_b;
+ shape_a = p_shape_a;
+ shape_b = p_shape_b;
+ colliding = false;
+ area_a->add_constraint(this);
+ area_b->add_constraint(this);
+}
+
+Area2Pair3DSW::~Area2Pair3DSW() {
+
+ if (colliding) {
+
+ if (area_b->has_area_monitor_callback())
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+
+ if (area_a->has_area_monitor_callback())
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
+
+ area_a->remove_constraint(this);
+ area_b->remove_constraint(this);
+}
diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h
new file mode 100644
index 0000000000..3490f41c26
--- /dev/null
+++ b/servers/physics_3d/area_pair_3d_sw.h
@@ -0,0 +1,70 @@
+/*************************************************************************/
+/* area_pair_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 AREA_PAIR_SW_H
+#define AREA_PAIR_SW_H
+
+#include "area_3d_sw.h"
+#include "body_3d_sw.h"
+#include "constraint_3d_sw.h"
+
+class AreaPair3DSW : public Constraint3DSW {
+
+ Body3DSW *body;
+ Area3DSW *area;
+ int body_shape;
+ int area_shape;
+ bool colliding;
+
+public:
+ bool setup(real_t p_step);
+ void solve(real_t p_step);
+
+ AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape);
+ ~AreaPair3DSW();
+};
+
+class Area2Pair3DSW : public Constraint3DSW {
+
+ Area3DSW *area_a;
+ Area3DSW *area_b;
+ int shape_a;
+ int shape_b;
+ bool colliding;
+
+public:
+ bool setup(real_t p_step);
+ void solve(real_t p_step);
+
+ Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b);
+ ~Area2Pair3DSW();
+};
+
+#endif // AREA_PAIR__SW_H
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
new file mode 100644
index 0000000000..fea5aed6ad
--- /dev/null
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -0,0 +1,814 @@
+/*************************************************************************/
+/* body_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "body_3d_sw.h"
+#include "area_3d_sw.h"
+#include "space_3d_sw.h"
+
+void Body3DSW::_update_inertia() {
+
+ if (get_space() && !inertia_update_list.in_list())
+ get_space()->body_add_to_inertia_update_list(&inertia_update_list);
+}
+
+void Body3DSW::_update_transform_dependant() {
+
+ center_of_mass = get_transform().basis.xform(center_of_mass_local);
+ principal_inertia_axes = get_transform().basis * principal_inertia_axes_local;
+
+ // update inertia tensor
+ Basis tb = principal_inertia_axes;
+ Basis tbt = tb.transposed();
+ Basis diag;
+ diag.scale(_inv_inertia);
+ _inv_inertia_tensor = tb * diag * tbt;
+}
+
+void Body3DSW::update_inertias() {
+
+ //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)
+ 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
+ center_of_mass_local.zero();
+
+ for (int i = 0; i < get_shape_count(); i++) {
+ real_t area = get_shape_area(i);
+
+ real_t mass = area * this->mass / total_area;
+
+ // 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
+ Basis inertia_tensor;
+ inertia_tensor.set_zero();
+
+ for (int i = 0; i < get_shape_count(); i++) {
+
+ if (is_shape_disabled(i)) {
+ continue;
+ }
+
+ const Shape3DSW *shape = get_shape(i);
+
+ real_t area = get_shape_area(i);
+
+ real_t mass = area * this->mass / total_area;
+
+ Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix();
+ Transform shape_transform = get_shape_transform(i);
+ Basis shape_basis = shape_transform.basis.orthonormalized();
+
+ // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor!
+ shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
+
+ Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
+ inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
+ }
+
+ // Compute the principal axes of inertia
+ principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
+ _inv_inertia = inertia_tensor.get_main_diagonal().inverse();
+
+ if (mass)
+ _inv_mass = 1.0 / mass;
+ else
+ _inv_mass = 0;
+
+ } break;
+
+ case PhysicsServer3D::BODY_MODE_KINEMATIC:
+ case PhysicsServer3D::BODY_MODE_STATIC: {
+
+ _inv_inertia_tensor.set_zero();
+ _inv_mass = 0;
+ } break;
+ case PhysicsServer3D::BODY_MODE_CHARACTER: {
+
+ _inv_inertia_tensor.set_zero();
+ _inv_mass = 1.0 / mass;
+
+ } break;
+ }
+
+ //_update_shapes();
+
+ _update_transform_dependant();
+}
+
+void Body3DSW::set_active(bool p_active) {
+
+ if (active == p_active)
+ return;
+
+ active = p_active;
+ if (!p_active) {
+ if (get_space())
+ get_space()->body_remove_from_active_list(&active_list);
+ } else {
+ if (mode == PhysicsServer3D::BODY_MODE_STATIC)
+ return; //static bodies can't become active
+ if (get_space())
+ get_space()->body_add_to_active_list(&active_list);
+
+ //still_time=0;
+ }
+ /*
+ if (!space)
+ return;
+
+ for(int i=0;i<get_shape_count();i++) {
+ Shape &s=shapes[i];
+ if (s.bpid>0) {
+ get_space()->get_broadphase()->set_active(s.bpid,active);
+ }
+ }
+*/
+}
+
+void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) {
+
+ switch (p_param) {
+ case PhysicsServer3D::BODY_PARAM_BOUNCE: {
+
+ bounce = p_value;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_FRICTION: {
+
+ friction = p_value;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_MASS: {
+ ERR_FAIL_COND(p_value <= 0);
+ mass = p_value;
+ _update_inertia();
+
+ } break;
+ case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
+ gravity_scale = p_value;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
+
+ linear_damp = p_value;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
+
+ angular_damp = p_value;
+ } break;
+ default: {
+ }
+ }
+}
+
+real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const {
+
+ switch (p_param) {
+ case PhysicsServer3D::BODY_PARAM_BOUNCE: {
+
+ return bounce;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_FRICTION: {
+
+ return friction;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_MASS: {
+ return mass;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
+ return gravity_scale;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
+
+ return linear_damp;
+ } break;
+ case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
+
+ return angular_damp;
+ } break;
+
+ default: {
+ }
+ }
+
+ return 0;
+}
+
+void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) {
+
+ PhysicsServer3D::BodyMode prev = mode;
+ mode = p_mode;
+
+ switch (p_mode) {
+ //CLEAR UP EVERYTHING IN CASE IT NOT WORKS!
+ case PhysicsServer3D::BODY_MODE_STATIC:
+ case PhysicsServer3D::BODY_MODE_KINEMATIC: {
+
+ _set_inv_transform(get_transform().affine_inverse());
+ _inv_mass = 0;
+ _set_static(p_mode == PhysicsServer3D::BODY_MODE_STATIC);
+ //set_active(p_mode==PhysicsServer3D::BODY_MODE_KINEMATIC);
+ set_active(p_mode == PhysicsServer3D::BODY_MODE_KINEMATIC && contacts.size());
+ linear_velocity = Vector3();
+ angular_velocity = Vector3();
+ if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC && prev != mode) {
+ first_time_kinematic = true;
+ }
+
+ } break;
+ case PhysicsServer3D::BODY_MODE_RIGID: {
+
+ _inv_mass = mass > 0 ? (1.0 / mass) : 0;
+ _set_static(false);
+ set_active(true);
+
+ } break;
+ case PhysicsServer3D::BODY_MODE_CHARACTER: {
+
+ _inv_mass = mass > 0 ? (1.0 / mass) : 0;
+ _set_static(false);
+ set_active(true);
+ angular_velocity = Vector3();
+ } break;
+ }
+
+ _update_inertia();
+ /*
+ if (get_space())
+ _update_queries();
+ */
+}
+PhysicsServer3D::BodyMode Body3DSW::get_mode() const {
+
+ return mode;
+}
+
+void Body3DSW::_shapes_changed() {
+
+ _update_inertia();
+}
+
+void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
+
+ switch (p_state) {
+ case PhysicsServer3D::BODY_STATE_TRANSFORM: {
+
+ if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ new_transform = p_variant;
+ //wakeup_neighbours();
+ set_active(true);
+ if (first_time_kinematic) {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().affine_inverse());
+ first_time_kinematic = false;
+ }
+
+ } else if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
+ _set_transform(p_variant);
+ _set_inv_transform(get_transform().affine_inverse());
+ wakeup_neighbours();
+ } else {
+ Transform t = p_variant;
+ t.orthonormalize();
+ new_transform = get_transform(); //used as old to compute motion
+ if (new_transform == t)
+ break;
+ _set_transform(t);
+ _set_inv_transform(get_transform().inverse());
+ }
+ wakeup();
+
+ } break;
+ case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
+
+ /*
+ if (mode==PhysicsServer3D::BODY_MODE_STATIC)
+ break;
+ */
+ linear_velocity = p_variant;
+ wakeup();
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ /*
+ if (mode!=PhysicsServer3D::BODY_MODE_RIGID)
+ break;
+ */
+ angular_velocity = p_variant;
+ wakeup();
+
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ //?
+ if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC)
+ break;
+ bool do_sleep = p_variant;
+ if (do_sleep) {
+ linear_velocity = Vector3();
+ //biased_linear_velocity=Vector3();
+ angular_velocity = Vector3();
+ //biased_angular_velocity=Vector3();
+ set_active(false);
+ } else {
+ set_active(true);
+ }
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ can_sleep = p_variant;
+ if (mode == PhysicsServer3D::BODY_MODE_RIGID && !active && !can_sleep)
+ set_active(true);
+
+ } break;
+ }
+}
+Variant Body3DSW::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: {
+ return linear_velocity;
+ } break;
+ case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
+ return angular_velocity;
+ } break;
+ case PhysicsServer3D::BODY_STATE_SLEEPING: {
+ return !is_active();
+ } break;
+ case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
+ return can_sleep;
+ } break;
+ }
+
+ return Variant();
+}
+
+void Body3DSW::set_space(Space3DSW *p_space) {
+
+ if (get_space()) {
+
+ if (inertia_update_list.in_list())
+ get_space()->body_remove_from_inertia_update_list(&inertia_update_list);
+ if (active_list.in_list())
+ get_space()->body_remove_from_active_list(&active_list);
+ if (direct_state_query_list.in_list())
+ get_space()->body_remove_from_state_query_list(&direct_state_query_list);
+ }
+
+ _set_space(p_space);
+
+ if (get_space()) {
+
+ _update_inertia();
+ if (active)
+ get_space()->body_add_to_active_list(&active_list);
+ /*
+ _update_queries();
+ if (is_active()) {
+ active=false;
+ set_active(true);
+ }
+ */
+ }
+
+ first_integration = true;
+}
+
+void Body3DSW::_compute_area_gravity_and_dampenings(const Area3DSW *p_area) {
+
+ if (p_area->is_gravity_point()) {
+ if (p_area->get_gravity_distance_scale() > 0) {
+ Vector3 v = p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin();
+ gravity += v.normalized() * (p_area->get_gravity() / Math::pow(v.length() * p_area->get_gravity_distance_scale() + 1, 2));
+ } else {
+ gravity += (p_area->get_transform().xform(p_area->get_gravity_vector()) - get_transform().get_origin()).normalized() * p_area->get_gravity();
+ }
+ } else {
+ gravity += p_area->get_gravity_vector() * p_area->get_gravity();
+ }
+
+ area_linear_damp += p_area->get_linear_damp();
+ area_angular_damp += p_area->get_angular_damp();
+}
+
+void Body3DSW::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) {
+ if (lock) {
+ locked_axis |= p_axis;
+ } else {
+ locked_axis &= ~p_axis;
+ }
+}
+
+bool Body3DSW::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
+ return locked_axis & p_axis;
+}
+
+void Body3DSW::integrate_forces(real_t p_step) {
+
+ if (mode == PhysicsServer3D::BODY_MODE_STATIC)
+ return;
+
+ Area3DSW *def_area = get_space()->get_default_area();
+ // AreaSW *damp_area = def_area;
+
+ ERR_FAIL_COND(!def_area);
+
+ int ac = areas.size();
+ bool stopped = false;
+ gravity = Vector3(0, 0, 0);
+ area_linear_damp = 0;
+ area_angular_damp = 0;
+ if (ac) {
+ areas.sort();
+ const AreaCMP *aa = &areas[0];
+ // damp_area = aa[ac-1].area;
+ for (int i = ac - 1; i >= 0 && !stopped; i--) {
+ PhysicsServer3D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode();
+ switch (mode) {
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ gravity = Vector3(0, 0, 0);
+ area_angular_damp = 0;
+ area_linear_damp = 0;
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {
+ }
+ }
+ }
+ }
+
+ if (!stopped) {
+ _compute_area_gravity_and_dampenings(def_area);
+ }
+
+ gravity *= gravity_scale;
+
+ // If less than 0, override dampenings with that of the Body
+ if (angular_damp >= 0)
+ area_angular_damp = angular_damp;
+ /*
+ else
+ area_angular_damp=damp_area->get_angular_damp();
+ */
+
+ if (linear_damp >= 0)
+ area_linear_damp = linear_damp;
+ /*
+ else
+ area_linear_damp=damp_area->get_linear_damp();
+ */
+
+ Vector3 motion;
+ bool do_motion = false;
+
+ 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;
+
+ //compute a FAKE angular velocity, not so easy
+ Basis rot = new_transform.basis.orthonormalized().transposed() * get_transform().basis.orthonormalized();
+ 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;
+
+ } else {
+ if (!omit_force_integration && !first_integration) {
+ //overridden by direct state query
+
+ Vector3 force = gravity * mass;
+ force += applied_force;
+ Vector3 torque = applied_torque;
+
+ real_t damp = 1.0 - p_step * area_linear_damp;
+
+ if (damp < 0) // reached zero in the given time
+ damp = 0;
+
+ real_t angular_damp = 1.0 - p_step * area_angular_damp;
+
+ if (angular_damp < 0) // reached zero in the given time
+ angular_damp = 0;
+
+ linear_velocity *= damp;
+ angular_velocity *= angular_damp;
+
+ linear_velocity += _inv_mass * force * p_step;
+ angular_velocity += _inv_inertia_tensor.xform(torque) * p_step;
+ }
+
+ if (continuous_cd) {
+ motion = linear_velocity * p_step;
+ do_motion = true;
+ }
+ }
+
+ applied_force = Vector3();
+ applied_torque = Vector3();
+ first_integration = false;
+
+ //motion=linear_velocity*p_step;
+
+ biased_angular_velocity = Vector3();
+ biased_linear_velocity = Vector3();
+
+ if (do_motion) { //shapes temporarily extend for raycast
+ _update_shapes_with_motion(motion);
+ }
+
+ def_area = nullptr; // clear the area, so it is set in the next frame
+ contact_count = 0;
+}
+
+void Body3DSW::integrate_velocities(real_t p_step) {
+
+ if (mode == PhysicsServer3D::BODY_MODE_STATIC)
+ return;
+
+ if (fi_callback)
+ get_space()->body_add_to_state_query_list(&direct_state_query_list);
+
+ //apply axis lock linear
+ for (int i = 0; i < 3; i++) {
+ if (is_axis_locked((PhysicsServer3D::BodyAxis)(1 << i))) {
+ linear_velocity[i] = 0;
+ biased_linear_velocity[i] = 0;
+ new_transform.origin[i] = get_transform().origin[i];
+ }
+ }
+ //apply axis lock angular
+ for (int i = 0; i < 3; i++) {
+ if (is_axis_locked((PhysicsServer3D::BodyAxis)(1 << (i + 3)))) {
+ angular_velocity[i] = 0;
+ biased_angular_velocity[i] = 0;
+ }
+ }
+
+ if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
+
+ _set_transform(new_transform, false);
+ _set_inv_transform(new_transform.affine_inverse());
+ if (contacts.size() == 0 && linear_velocity == Vector3() && angular_velocity == Vector3())
+ set_active(false); //stopped moving, deactivate
+
+ return;
+ }
+
+ Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity;
+
+ real_t ang_vel = total_angular_velocity.length();
+ Transform transform = get_transform();
+
+ if (ang_vel != 0.0) {
+ Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
+ Basis rot(ang_vel_axis, ang_vel * p_step);
+ Basis identity3(1, 0, 0, 0, 1, 0, 0, 0, 1);
+ transform.origin += ((identity3 - rot) * transform.basis).xform(center_of_mass_local);
+ transform.basis = rot * transform.basis;
+ transform.orthonormalize();
+ }
+
+ Vector3 total_linear_velocity = linear_velocity + biased_linear_velocity;
+ /*for(int i=0;i<3;i++) {
+ if (axis_lock&(1<<i)) {
+ transform.origin[i]=0.0;
+ }
+ }*/
+
+ transform.origin += total_linear_velocity * p_step;
+
+ _set_transform(transform);
+ _set_inv_transform(get_transform().inverse());
+
+ _update_transform_dependant();
+
+ /*
+ if (fi_callback) {
+ get_space()->body_add_to_state_query_list(&direct_state_query_list);
+ */
+}
+
+/*
+void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) {
+
+ Transform inv_xform = p_xform.affine_inverse();
+ if (!get_space()) {
+ _set_transform(p_xform);
+ _set_inv_transform(inv_xform);
+
+ return;
+ }
+
+ //compute a FAKE linear velocity - this is easy
+
+ linear_velocity=(p_xform.origin - get_transform().origin)/p_step;
+
+ //compute a FAKE angular velocity, not so easy
+ Basis rot=get_transform().basis.orthonormalized().transposed() * p_xform.basis.orthonormalized();
+ Vector3 axis;
+ real_t angle;
+
+ rot.get_axis_angle(axis,angle);
+ axis.normalize();
+ angular_velocity=axis.normalized() * (angle/p_step);
+ linear_velocity = (p_xform.origin - get_transform().origin)/p_step;
+
+ if (!direct_state_query_list.in_list())// - callalways, so lv and av are cleared && (state_query || direct_state_query))
+ get_space()->body_add_to_state_query_list(&direct_state_query_list);
+ simulated_motion=true;
+ _set_transform(p_xform);
+
+
+}
+*/
+
+void Body3DSW::wakeup_neighbours() {
+
+ for (Map<Constraint3DSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) {
+
+ const Constraint3DSW *c = E->key();
+ Body3DSW **n = c->get_body_ptr();
+ int bc = c->get_body_count();
+
+ for (int i = 0; i < bc; i++) {
+
+ if (i == E->get())
+ continue;
+ Body3DSW *b = n[i];
+ if (b->mode != PhysicsServer3D::BODY_MODE_RIGID)
+ continue;
+
+ if (!b->is_active())
+ b->set_active(true);
+ }
+ }
+}
+
+void Body3DSW::call_queries() {
+
+ if (fi_callback) {
+
+ PhysicsDirectBodyState3DSW *dbs = PhysicsDirectBodyState3DSW::singleton;
+ dbs->body = this;
+
+ Variant v = dbs;
+
+ Object *obj = ObjectDB::get_instance(fi_callback->id);
+ if (!obj) {
+
+ set_force_integration_callback(ObjectID(), StringName());
+ } 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);
+ }
+ }
+}
+
+bool Body3DSW::sleep_test(real_t p_step) {
+
+ if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC)
+ return true; //
+ else if (mode == PhysicsServer3D::BODY_MODE_CHARACTER)
+ return !active; // characters don't sleep unless asked to sleep
+ else if (!can_sleep)
+ return false;
+
+ if (Math::abs(angular_velocity.length()) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) {
+
+ still_time += p_step;
+
+ return still_time > get_space()->get_body_time_to_sleep();
+ } else {
+
+ still_time = 0; //maybe this should be set to 0 on set_active?
+ return false;
+ }
+}
+
+void Body3DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+
+ if (fi_callback) {
+
+ memdelete(fi_callback);
+ fi_callback = nullptr;
+ }
+
+ if (p_id.is_valid()) {
+
+ fi_callback = memnew(ForceIntegrationCallback);
+ fi_callback->id = p_id;
+ fi_callback->method = p_method;
+ fi_callback->udata = p_udata;
+ }
+}
+
+void Body3DSW::set_kinematic_margin(real_t p_margin) {
+ kinematic_safe_margin = p_margin;
+}
+
+Body3DSW::Body3DSW() :
+ CollisionObject3DSW(TYPE_BODY),
+ locked_axis(0),
+ active_list(this),
+ inertia_update_list(this),
+ direct_state_query_list(this) {
+
+ mode = PhysicsServer3D::BODY_MODE_RIGID;
+ active = true;
+
+ mass = 1;
+ kinematic_safe_margin = 0.01;
+ //_inv_inertia=Transform();
+ _inv_mass = 1;
+ bounce = 0;
+ friction = 1;
+ 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);
+
+ contact_count = 0;
+ gravity_scale = 1.0;
+ linear_damp = -1;
+ angular_damp = -1;
+ area_angular_damp = 0;
+ area_linear_damp = 0;
+
+ still_time = 0;
+ continuous_cd = false;
+ can_sleep = true;
+ fi_callback = nullptr;
+}
+
+Body3DSW::~Body3DSW() {
+
+ if (fi_callback)
+ memdelete(fi_callback);
+}
+
+PhysicsDirectBodyState3DSW *PhysicsDirectBodyState3DSW::singleton = nullptr;
+
+PhysicsDirectSpaceState3D *PhysicsDirectBodyState3DSW::get_space_state() {
+
+ return body->get_space()->get_direct_state();
+}
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
new file mode 100644
index 0000000000..2bd335e6c0
--- /dev/null
+++ b/servers/physics_3d/body_3d_sw.h
@@ -0,0 +1,475 @@
+/*************************************************************************/
+/* body_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BODY_SW_H
+#define BODY_SW_H
+
+#include "area_3d_sw.h"
+#include "collision_object_3d_sw.h"
+#include "core/vset.h"
+
+class Constraint3DSW;
+
+class Body3DSW : public CollisionObject3DSW {
+
+ PhysicsServer3D::BodyMode mode;
+
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+
+ Vector3 biased_linear_velocity;
+ Vector3 biased_angular_velocity;
+ real_t mass;
+ real_t bounce;
+ real_t friction;
+
+ real_t linear_damp;
+ real_t angular_damp;
+ real_t gravity_scale;
+
+ uint16_t locked_axis;
+
+ real_t kinematic_safe_margin;
+ real_t _inv_mass;
+ Vector3 _inv_inertia; // Relative to the principal axes of inertia
+
+ // Relative to the local frame of reference
+ Basis principal_inertia_axes_local;
+ Vector3 center_of_mass_local;
+
+ // In world orientation with local origin
+ Basis _inv_inertia_tensor;
+ Basis principal_inertia_axes;
+ Vector3 center_of_mass;
+
+ Vector3 gravity;
+
+ real_t still_time;
+
+ Vector3 applied_force;
+ Vector3 applied_torque;
+
+ real_t area_angular_damp;
+ real_t area_linear_damp;
+
+ SelfList<Body3DSW> active_list;
+ SelfList<Body3DSW> inertia_update_list;
+ SelfList<Body3DSW> direct_state_query_list;
+
+ VSet<RID> exceptions;
+ bool omit_force_integration;
+ bool active;
+
+ bool first_integration;
+
+ bool continuous_cd;
+ bool can_sleep;
+ bool first_time_kinematic;
+ void _update_inertia();
+ virtual void _shapes_changed();
+ Transform new_transform;
+
+ Map<Constraint3DSW *, int> constraint_map;
+
+ struct AreaCMP {
+
+ Area3DSW *area;
+ int refCount;
+ _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); }
+ _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); }
+ _FORCE_INLINE_ AreaCMP() {}
+ _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) {
+ area = p_area;
+ refCount = 1;
+ }
+ };
+
+ Vector<AreaCMP> areas;
+
+ struct Contact {
+
+ Vector3 local_pos;
+ Vector3 local_normal;
+ real_t depth;
+ int local_shape;
+ Vector3 collider_pos;
+ int collider_shape;
+ ObjectID collider_instance_id;
+ RID collider;
+ Vector3 collider_velocity_at_pos;
+ };
+
+ Vector<Contact> contacts; //no contacts by default
+ int contact_count;
+
+ struct ForceIntegrationCallback {
+
+ ObjectID id;
+ StringName method;
+ 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);
+
+ _FORCE_INLINE_ void _update_transform_dependant();
+
+ 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_kinematic_margin(real_t p_margin);
+ _FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; }
+
+ _FORCE_INLINE_ void add_area(Area3DSW *p_area) {
+ int index = areas.find(AreaCMP(p_area));
+ if (index > -1) {
+ areas.write[index].refCount += 1;
+ } else {
+ areas.ordered_insert(AreaCMP(p_area));
+ }
+ }
+
+ _FORCE_INLINE_ void remove_area(Area3DSW *p_area) {
+ int index = areas.find(AreaCMP(p_area));
+ if (index > -1) {
+ areas.write[index].refCount -= 1;
+ if (areas[index].refCount < 1)
+ areas.remove(index);
+ }
+ }
+
+ _FORCE_INLINE_ void set_max_contacts_reported(int p_size) {
+ contacts.resize(p_size);
+ contact_count = 0;
+ if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC && p_size) set_active(true);
+ }
+ _FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }
+
+ _FORCE_INLINE_ bool can_report_contacts() const { return !contacts.empty(); }
+ _FORCE_INLINE_ void add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos);
+
+ _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; }
+
+ _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; }
+ _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); }
+
+ _FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; }
+ _FORCE_INLINE_ bool get_omit_force_integration() const { return omit_force_integration; }
+
+ _FORCE_INLINE_ Basis get_principal_inertia_axes() const { return principal_inertia_axes; }
+ _FORCE_INLINE_ Vector3 get_center_of_mass() const { return center_of_mass; }
+ _FORCE_INLINE_ Vector3 xform_local_to_principal(const Vector3 &p_pos) const { return principal_inertia_axes_local.xform(p_pos - center_of_mass_local); }
+
+ _FORCE_INLINE_ void set_linear_velocity(const Vector3 &p_velocity) { linear_velocity = p_velocity; }
+ _FORCE_INLINE_ Vector3 get_linear_velocity() const { return linear_velocity; }
+
+ _FORCE_INLINE_ void set_angular_velocity(const Vector3 &p_velocity) { angular_velocity = p_velocity; }
+ _FORCE_INLINE_ Vector3 get_angular_velocity() const { return angular_velocity; }
+
+ _FORCE_INLINE_ const Vector3 &get_biased_linear_velocity() const { return biased_linear_velocity; }
+ _FORCE_INLINE_ const Vector3 &get_biased_angular_velocity() const { return biased_angular_velocity; }
+
+ _FORCE_INLINE_ void apply_central_impulse(const Vector3 &p_j) {
+ linear_velocity += p_j * _inv_mass;
+ }
+
+ _FORCE_INLINE_ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
+
+ linear_velocity += p_j * _inv_mass;
+ angular_velocity += _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
+ }
+
+ _FORCE_INLINE_ void apply_torque_impulse(const Vector3 &p_j) {
+
+ angular_velocity += _inv_inertia_tensor.xform(p_j);
+ }
+
+ _FORCE_INLINE_ void apply_bias_impulse(const Vector3 &p_pos, const Vector3 &p_j, real_t p_max_delta_av = -1.0) {
+
+ biased_linear_velocity += p_j * _inv_mass;
+ if (p_max_delta_av != 0.0) {
+ Vector3 delta_av = _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
+ if (p_max_delta_av > 0 && delta_av.length() > p_max_delta_av) {
+ delta_av = delta_av.normalized() * p_max_delta_av;
+ }
+ biased_angular_velocity += delta_av;
+ }
+ }
+
+ _FORCE_INLINE_ void apply_bias_torque_impulse(const Vector3 &p_j) {
+
+ biased_angular_velocity += _inv_inertia_tensor.xform(p_j);
+ }
+
+ _FORCE_INLINE_ void add_central_force(const Vector3 &p_force) {
+
+ applied_force += p_force;
+ }
+
+ _FORCE_INLINE_ void add_force(const Vector3 &p_force, const Vector3 &p_pos) {
+
+ applied_force += p_force;
+ applied_torque += (p_pos - center_of_mass).cross(p_force);
+ }
+
+ _FORCE_INLINE_ void add_torque(const Vector3 &p_torque) {
+ applied_torque += p_torque;
+ }
+
+ void set_active(bool p_active);
+ _FORCE_INLINE_ bool is_active() const { return active; }
+
+ _FORCE_INLINE_ void wakeup() {
+ if ((!get_space()) || mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC)
+ return;
+ set_active(true);
+ }
+
+ void set_param(PhysicsServer3D::BodyParameter p_param, real_t);
+ real_t get_param(PhysicsServer3D::BodyParameter p_param) const;
+
+ void set_mode(PhysicsServer3D::BodyMode p_mode);
+ PhysicsServer3D::BodyMode get_mode() const;
+
+ void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer3D::BodyState p_state) const;
+
+ void set_applied_force(const Vector3 &p_force) { applied_force = p_force; }
+ Vector3 get_applied_force() const { return applied_force; }
+
+ void set_applied_torque(const Vector3 &p_torque) { applied_torque = p_torque; }
+ Vector3 get_applied_torque() const { return applied_torque; }
+
+ _FORCE_INLINE_ void set_continuous_collision_detection(bool p_enable) { continuous_cd = p_enable; }
+ _FORCE_INLINE_ bool is_continuous_collision_detection_enabled() const { return continuous_cd; }
+
+ void set_space(Space3DSW *p_space);
+
+ 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_ real_t get_friction() const { return friction; }
+ _FORCE_INLINE_ 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);
+ bool is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const;
+
+ void integrate_forces(real_t p_step);
+ void integrate_velocities(real_t p_step);
+
+ _FORCE_INLINE_ Vector3 get_velocity_in_local_point(const Vector3 &rel_pos) const {
+
+ return linear_velocity + angular_velocity.cross(rel_pos - center_of_mass);
+ }
+
+ _FORCE_INLINE_ real_t compute_impulse_denominator(const Vector3 &p_pos, const Vector3 &p_normal) const {
+
+ Vector3 r0 = p_pos - get_transform().origin - center_of_mass;
+
+ Vector3 c0 = (r0).cross(p_normal);
+
+ Vector3 vec = (_inv_inertia_tensor.xform_inv(c0)).cross(r0);
+
+ return _inv_mass + p_normal.dot(vec);
+ }
+
+ _FORCE_INLINE_ real_t compute_angular_impulse_denominator(const Vector3 &p_axis) const {
+
+ return p_axis.dot(_inv_inertia_tensor.xform_inv(p_axis));
+ }
+
+ //void simulate_motion(const Transform& p_xform,real_t p_step);
+ void call_queries();
+ void wakeup_neighbours();
+
+ bool sleep_test(real_t p_step);
+
+ Body3DSW();
+ ~Body3DSW();
+};
+
+//add contact inline
+
+void Body3DSW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos) {
+
+ int c_max = contacts.size();
+
+ if (c_max == 0)
+ return;
+
+ Contact *c = contacts.ptrw();
+
+ int idx = -1;
+
+ if (contact_count < c_max) {
+ idx = contact_count++;
+ } else {
+
+ real_t least_depth = 1e20;
+ int least_deep = -1;
+ for (int i = 0; i < c_max; i++) {
+
+ if (i == 0 || c[i].depth < least_depth) {
+ least_deep = i;
+ least_depth = c[i].depth;
+ }
+ }
+
+ if (least_deep >= 0 && least_depth < p_depth) {
+
+ idx = least_deep;
+ }
+ if (idx == -1)
+ return; //none least deepe than this
+ }
+
+ c[idx].local_pos = p_local_pos;
+ c[idx].local_normal = p_local_normal;
+ c[idx].depth = p_depth;
+ c[idx].local_shape = p_local_shape;
+ c[idx].collider_pos = p_collider_pos;
+ c[idx].collider_shape = p_collider_shape;
+ c[idx].collider_instance_id = p_collider_instance_id;
+ c[idx].collider = p_collider;
+ c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos;
+}
+
+class PhysicsDirectBodyState3DSW : public PhysicsDirectBodyState3D {
+
+ GDCLASS(PhysicsDirectBodyState3DSW, PhysicsDirectBodyState3D);
+
+public:
+ static PhysicsDirectBodyState3DSW *singleton;
+ Body3DSW *body;
+ real_t step;
+
+ virtual Vector3 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area
+ virtual real_t get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area
+ virtual real_t get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area
+
+ virtual Vector3 get_center_of_mass() const { return body->get_center_of_mass(); }
+ virtual Basis get_principal_inertia_axes() const { return body->get_principal_inertia_axes(); }
+
+ virtual real_t get_inverse_mass() const { return body->get_inv_mass(); } // get the mass
+ virtual Vector3 get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space
+ virtual Basis get_inverse_inertia_tensor() const { return body->get_inv_inertia_tensor(); } // get density of this body space
+
+ virtual void set_linear_velocity(const Vector3 &p_velocity) { body->set_linear_velocity(p_velocity); }
+ virtual Vector3 get_linear_velocity() const { return body->get_linear_velocity(); }
+
+ virtual void set_angular_velocity(const Vector3 &p_velocity) { body->set_angular_velocity(p_velocity); }
+ virtual Vector3 get_angular_velocity() const { return body->get_angular_velocity(); }
+
+ virtual void set_transform(const Transform &p_transform) { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); }
+ virtual Transform get_transform() const { return body->get_transform(); }
+
+ virtual void add_central_force(const Vector3 &p_force) { body->add_central_force(p_force); }
+ virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) { body->add_force(p_force, p_pos); }
+ virtual void add_torque(const Vector3 &p_torque) { body->add_torque(p_torque); }
+ virtual void apply_central_impulse(const Vector3 &p_j) { body->apply_central_impulse(p_j); }
+ virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { body->apply_impulse(p_pos, p_j); }
+ virtual void apply_torque_impulse(const Vector3 &p_j) { body->apply_torque_impulse(p_j); }
+
+ virtual void set_sleep_state(bool p_sleep) { body->set_active(!p_sleep); }
+ virtual bool is_sleeping() const { return !body->is_active(); }
+
+ virtual int get_contact_count() const { return body->contact_count; }
+
+ virtual Vector3 get_contact_local_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].local_pos;
+ }
+ virtual Vector3 get_contact_local_normal(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].local_normal;
+ }
+ virtual float get_contact_impulse(int p_contact_idx) const {
+ return 0.0f; // Only implemented for bullet
+ }
+ virtual int get_contact_local_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1);
+ return body->contacts[p_contact_idx].local_shape;
+ }
+
+ virtual RID get_contact_collider(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID());
+ return body->contacts[p_contact_idx].collider;
+ }
+ virtual Vector3 get_contact_collider_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].collider_pos;
+ }
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID());
+ return body->contacts[p_contact_idx].collider_instance_id;
+ }
+ virtual int get_contact_collider_shape(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0);
+ return body->contacts[p_contact_idx].collider_shape;
+ }
+ virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const {
+ ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3());
+ return body->contacts[p_contact_idx].collider_velocity_at_pos;
+ }
+
+ virtual PhysicsDirectSpaceState3D *get_space_state();
+
+ virtual real_t get_step() const { return step; }
+ PhysicsDirectBodyState3DSW() {
+ singleton = this;
+ body = nullptr;
+ }
+};
+
+#endif // BODY__SW_H
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
new file mode 100644
index 0000000000..245fb3449c
--- /dev/null
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -0,0 +1,495 @@
+/*************************************************************************/
+/* body_pair_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "body_pair_3d_sw.h"
+
+#include "collision_solver_3d_sw.h"
+#include "core/os/os.h"
+#include "space_3d_sw.h"
+
+/*
+#define NO_ACCUMULATE_IMPULSES
+#define NO_SPLIT_IMPULSES
+
+#define NO_FRICTION
+*/
+
+#define NO_TANGENTIALS
+/* BODY PAIR */
+
+//#define ALLOWED_PENETRATION 0.01
+#define RELAXATION_TIMESTEPS 3
+#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) {
+
+ BodyPair3DSW *pair = (BodyPair3DSW *)p_userdata;
+ pair->contact_added_callback(p_point_A, p_point_B);
+}
+
+void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+
+ // check if we already have the contact
+
+ //Vector3 local_A = A->get_inv_transform().xform(p_point_A);
+ //Vector3 local_B = B->get_inv_transform().xform(p_point_B);
+
+ Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A);
+ Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B);
+
+ int new_index = contact_count;
+
+ ERR_FAIL_COND(new_index >= (MAX_CONTACTS + 1));
+
+ Contact contact;
+
+ 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; // will be computed in setup()
+
+ // attempt to determine if the contact will be reused
+ real_t contact_recycle_radius = space->get_contact_recycle_radius();
+
+ for (int i = 0; i < contact_count; i++) {
+
+ Contact &c = contacts[i];
+ 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;
+ new_index = i;
+ break;
+ }
+ }
+
+ // figure out if the contact amount must be reduced to fit the new contact
+
+ if (new_index == MAX_CONTACTS) {
+
+ // remove the contact with the minimum depth
+
+ int least_deep = -1;
+ real_t min_depth = 1e10;
+
+ for (int i = 0; i <= contact_count; i++) {
+
+ Contact &c = (i == contact_count) ? contact : contacts[i];
+ Vector3 global_A = A->get_transform().basis.xform(c.local_A);
+ Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_B;
+
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
+
+ if (depth < min_depth) {
+
+ min_depth = depth;
+ least_deep = i;
+ }
+ }
+
+ ERR_FAIL_COND(least_deep == -1);
+
+ if (least_deep < contact_count) { //replace the last deep contact by the new one
+
+ contacts[least_deep] = contact;
+ }
+
+ return;
+ }
+
+ contacts[new_index] = contact;
+
+ if (new_index == contact_count) {
+
+ contact_count++;
+ }
+}
+
+void BodyPair3DSW::validate_contacts() {
+
+ //make sure to erase contacts that are no longer valid
+
+ real_t contact_max_separation = space->get_contact_max_separation();
+ for (int i = 0; i < contact_count; i++) {
+
+ Contact &c = contacts[i];
+
+ Vector3 global_A = A->get_transform().basis.xform(c.local_A);
+ Vector3 global_B = B->get_transform().basis.xform(c.local_B) + offset_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 ((i + 1) < contact_count) {
+ // swap with the last one
+ SWAP(contacts[i], contacts[contact_count - 1]);
+ }
+
+ i--;
+ contact_count--;
+ }
+ }
+}
+
+bool BodyPair3DSW::_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) {
+
+ Vector3 motion = p_A->get_linear_velocity() * p_step;
+ real_t mlen = motion.length();
+ if (mlen < CMP_EPSILON)
+ return false;
+
+ Vector3 mnormal = motion / mlen;
+
+ real_t min, max;
+ p_A->get_shape(p_shape_A)->project_range(mnormal, p_xform_A, min, max);
+ bool fast_object = mlen > (max - min) * 0.3; //going too fast in that direction
+
+ if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
+ return false;
+ }
+
+ //cast a segment from support in motion normal, in the same direction of motion by motion length
+ //support is the worst case collision point, so real collision happened before
+ Vector3 s = p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform(mnormal).normalized());
+ Vector3 from = p_xform_A.xform(s);
+ Vector3 to = from + motion;
+
+ Transform from_inv = p_xform_B.affine_inverse();
+
+ Vector3 local_from = from_inv.xform(from - mnormal * mlen * 0.1); //start from a little inside the bounding box
+ Vector3 local_to = from_inv.xform(to);
+
+ Vector3 rpos, rnorm;
+ if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm)) {
+ return false;
+ }
+
+ //shorten the linear velocity so it does not hit, but gets close enough, next frame will hit softly or soft enough
+ Vector3 hitpos = p_xform_B.xform(rpos);
+
+ real_t newlen = hitpos.distance_to(from) - (max - min) * 0.01;
+ p_A->set_linear_velocity((mnormal * newlen) / p_step);
+
+ return true;
+}
+
+real_t combine_bounce(Body3DSW *A, Body3DSW *B) {
+ return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1);
+}
+
+real_t combine_friction(Body3DSW *A, Body3DSW *B) {
+ return ABS(MIN(A->get_friction(), B->get_friction()));
+}
+
+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)) {
+ 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;
+ }
+
+ offset_B = B->get_transform().get_origin() - A->get_transform().get_origin();
+
+ validate_contacts();
+
+ Vector3 offset_A = A->get_transform().get_origin();
+ Transform xform_Au = Transform(A->get_transform().basis, Vector3());
+ Transform xform_A = xform_Au * A->get_shape_transform(shape_A);
+
+ Transform xform_Bu = B->get_transform();
+ xform_Bu.origin -= offset_A;
+ Transform xform_B = xform_Bu * B->get_shape_transform(shape_B);
+
+ Shape3DSW *shape_A_ptr = A->get_shape(shape_A);
+ Shape3DSW *shape_B_ptr = B->get_shape(shape_B);
+
+ bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
+ this->collided = collided;
+
+ if (!collided) {
+
+ //test ccd (currently just a raycast)
+
+ if (A->is_continuous_collision_detection_enabled() && A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ _test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B);
+ }
+
+ if (B->is_continuous_collision_detection_enabled() && B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC && A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ _test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A);
+ }
+
+ return false;
+ }
+
+ real_t max_penetration = space->get_contact_max_allowed_penetration();
+
+ real_t bias = (real_t)0.3;
+
+ if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) {
+
+ if (shape_A_ptr->get_custom_bias() == 0)
+ bias = shape_B_ptr->get_custom_bias();
+ else if (shape_B_ptr->get_custom_bias() == 0)
+ bias = shape_A_ptr->get_custom_bias();
+ else
+ bias = (shape_B_ptr->get_custom_bias() + shape_A_ptr->get_custom_bias()) * 0.5;
+ }
+
+ real_t inv_dt = 1.0 / p_step;
+
+ for (int i = 0; i < contact_count; i++) {
+
+ Contact &c = contacts[i];
+ c.active = false;
+
+ Vector3 global_A = xform_Au.xform(c.local_A);
+ Vector3 global_B = xform_Bu.xform(c.local_B);
+
+ 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()) {
+ space->add_debug_contact(global_A + offset_A);
+ space->add_debug_contact(global_B + offset_A);
+ }
+#endif
+
+ c.rA = global_A - A->get_center_of_mass();
+ c.rB = global_B - B->get_center_of_mass() - offset_B;
+
+ // contact query reporting...
+
+ if (A->can_report_contacts()) {
+ Vector3 crA = A->get_angular_velocity().cross(c.rA) + A->get_linear_velocity();
+ A->add_contact(global_A, -c.normal, depth, shape_A, global_B, shape_B, B->get_instance_id(), B->get_self(), crA);
+ }
+
+ if (B->can_report_contacts()) {
+ Vector3 crB = B->get_angular_velocity().cross(c.rB) + B->get_linear_velocity();
+ B->add_contact(global_B, c.normal, depth, shape_B, global_A, shape_A, A->get_instance_id(), A->get_self(), crB);
+ }
+
+ c.active = true;
+
+ // Precompute normal mass, tangent mass, and bias.
+ Vector3 inertia_A = A->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
+ Vector3 inertia_B = B->get_inv_inertia_tensor().xform(c.rB.cross(c.normal));
+ real_t kNormal = A->get_inv_mass() + B->get_inv_mass();
+ kNormal += c.normal.dot(inertia_A.cross(c.rA)) + c.normal.dot(inertia_B.cross(c.rB));
+ 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;
+ A->apply_impulse(c.rA + A->get_center_of_mass(), -j_vec);
+ B->apply_impulse(c.rB + B->get_center_of_mass(), j_vec);
+ c.acc_bias_impulse = 0;
+ c.acc_bias_impulse_center_of_mass = 0;
+
+ c.bounce = combine_bounce(A, B);
+ if (c.bounce) {
+
+ Vector3 crA = A->get_angular_velocity().cross(c.rA);
+ Vector3 crB = B->get_angular_velocity().cross(c.rB);
+ Vector3 dv = B->get_linear_velocity() + crB - A->get_linear_velocity() - crA;
+ //normal impule
+ c.bounce = c.bounce * dv.dot(c.normal);
+ }
+ }
+
+ return true;
+}
+
+void BodyPair3DSW::solve(real_t p_step) {
+
+ if (!collided)
+ return;
+
+ for (int i = 0; i < contact_count; i++) {
+
+ Contact &c = contacts[i];
+ if (!c.active)
+ continue;
+
+ c.active = false; //try to deactivate, will activate itself if still needed
+
+ //bias impulse
+
+ Vector3 crbA = A->get_biased_angular_velocity().cross(c.rA);
+ Vector3 crbB = B->get_biased_angular_velocity().cross(c.rB);
+ Vector3 dbv = B->get_biased_linear_velocity() + crbB - A->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);
+
+ A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step);
+ B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step);
+
+ crbA = A->get_biased_angular_velocity().cross(c.rA);
+ crbB = B->get_biased_angular_velocity().cross(c.rB);
+ dbv = B->get_biased_linear_velocity() + crbB - A->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) / (A->get_inv_mass() + B->get_inv_mass());
+ 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);
+
+ A->apply_bias_impulse(A->get_center_of_mass(), -jb_com, 0.0f);
+ B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f);
+ }
+
+ c.active = true;
+ }
+
+ Vector3 crA = A->get_angular_velocity().cross(c.rA);
+ Vector3 crB = B->get_angular_velocity().cross(c.rB);
+ Vector3 dv = B->get_linear_velocity() + crB - A->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);
+
+ A->apply_impulse(c.rA + A->get_center_of_mass(), -j);
+ B->apply_impulse(c.rB + B->get_center_of_mass(), j);
+
+ c.active = true;
+ }
+
+ //friction impulse
+
+ real_t friction = combine_friction(A, B);
+
+ Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA);
+ Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB);
+
+ 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 = A->get_inv_inertia_tensor().xform(c.rA.cross(tv));
+ Vector3 temp2 = B->get_inv_inertia_tensor().xform(c.rB.cross(tv));
+
+ real_t t = -tvl /
+ (A->get_inv_mass() + B->get_inv_mass() + tv.dot(temp1.cross(c.rA) + temp2.cross(c.rB)));
+
+ 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;
+
+ A->apply_impulse(c.rA + A->get_center_of_mass(), -jt);
+ B->apply_impulse(c.rB + B->get_center_of_mass(), jt);
+
+ c.active = true;
+ }
+ }
+}
+
+BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B) :
+ Constraint3DSW(_arr, 2) {
+
+ A = p_A;
+ B = p_B;
+ shape_A = p_shape_A;
+ shape_B = p_shape_B;
+ space = A->get_space();
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+ contact_count = 0;
+ collided = false;
+}
+
+BodyPair3DSW::~BodyPair3DSW() {
+
+ A->remove_constraint(this);
+ B->remove_constraint(this);
+}
diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h
new file mode 100644
index 0000000000..7f4afb9dca
--- /dev/null
+++ b/servers/physics_3d/body_pair_3d_sw.h
@@ -0,0 +1,97 @@
+/*************************************************************************/
+/* body_pair_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BODY_PAIR_SW_H
+#define BODY_PAIR_SW_H
+
+#include "body_3d_sw.h"
+#include "constraint_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;
+
+ struct Contact {
+
+ Vector3 position;
+ Vector3 normal;
+ Vector3 local_A, local_B;
+ real_t acc_normal_impulse; // accumulated normal impulse (Pn)
+ Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
+ real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb)
+ real_t acc_bias_impulse_center_of_mass; // accumulated normal impulse for position bias applied to com
+ real_t mass_normal;
+ real_t bias;
+ real_t bounce;
+
+ real_t depth;
+ bool active;
+ Vector3 rA, rB; // Offset in world orientation with respect to center of mass
+ };
+
+ 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);
+
+ void contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_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);
+
+ BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B);
+ ~BodyPair3DSW();
+};
+
+#endif // BODY_PAIR__SW_H
diff --git a/servers/physics_3d/broad_phase_3d_basic.cpp b/servers/physics_3d/broad_phase_3d_basic.cpp
new file mode 100644
index 0000000000..08ea219869
--- /dev/null
+++ b/servers/physics_3d/broad_phase_3d_basic.cpp
@@ -0,0 +1,225 @@
+/*************************************************************************/
+/* broad_phase_3d_basic.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "broad_phase_3d_basic.h"
+#include "core/list.h"
+#include "core/print_string.h"
+
+BroadPhase3DSW::ID BroadPhase3DBasic::create(CollisionObject3DSW *p_object, int p_subindex) {
+
+ ERR_FAIL_COND_V(p_object == nullptr, 0);
+
+ current++;
+
+ Element e;
+ e.owner = p_object;
+ e._static = false;
+ e.subindex = p_subindex;
+
+ element_map[current] = e;
+ return current;
+}
+
+void BroadPhase3DBasic::move(ID p_id, const AABB &p_aabb) {
+
+ Map<ID, Element>::Element *E = element_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ E->get().aabb = p_aabb;
+}
+void BroadPhase3DBasic::set_static(ID p_id, bool p_static) {
+
+ Map<ID, Element>::Element *E = element_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ E->get()._static = p_static;
+}
+void BroadPhase3DBasic::remove(ID p_id) {
+
+ Map<ID, Element>::Element *E = element_map.find(p_id);
+ ERR_FAIL_COND(!E);
+ List<PairKey> to_erase;
+ //unpair must be done immediately on removal to avoid potential invalid pointers
+ for (Map<PairKey, void *>::Element *F = pair_map.front(); F; F = F->next()) {
+
+ if (F->key().a == p_id || F->key().b == p_id) {
+
+ if (unpair_callback) {
+ Element *elem_A = &element_map[F->key().a];
+ Element *elem_B = &element_map[F->key().b];
+ unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, F->get(), unpair_userdata);
+ }
+ to_erase.push_back(F->key());
+ }
+ }
+ while (to_erase.size()) {
+
+ pair_map.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+ element_map.erase(E);
+}
+
+CollisionObject3DSW *BroadPhase3DBasic::get_object(ID p_id) const {
+
+ const Map<ID, Element>::Element *E = element_map.find(p_id);
+ ERR_FAIL_COND_V(!E, nullptr);
+ return E->get().owner;
+}
+bool BroadPhase3DBasic::is_static(ID p_id) const {
+
+ const Map<ID, Element>::Element *E = element_map.find(p_id);
+ ERR_FAIL_COND_V(!E, false);
+ return E->get()._static;
+}
+int BroadPhase3DBasic::get_subindex(ID p_id) const {
+
+ const Map<ID, Element>::Element *E = element_map.find(p_id);
+ ERR_FAIL_COND_V(!E, -1);
+ return E->get().subindex;
+}
+
+int BroadPhase3DBasic::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+
+ int rc = 0;
+
+ for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
+
+ const AABB aabb = E->get().aabb;
+ if (aabb.has_point(p_point)) {
+
+ p_results[rc] = E->get().owner;
+ p_result_indices[rc] = E->get().subindex;
+ rc++;
+ if (rc >= p_max_results)
+ break;
+ }
+ }
+
+ return rc;
+}
+
+int BroadPhase3DBasic::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+
+ int rc = 0;
+
+ for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
+
+ const AABB aabb = E->get().aabb;
+ if (aabb.intersects_segment(p_from, p_to)) {
+
+ p_results[rc] = E->get().owner;
+ p_result_indices[rc] = E->get().subindex;
+ rc++;
+ if (rc >= p_max_results)
+ break;
+ }
+ }
+
+ return rc;
+}
+int BroadPhase3DBasic::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+
+ int rc = 0;
+
+ for (Map<ID, Element>::Element *E = element_map.front(); E; E = E->next()) {
+
+ const AABB aabb = E->get().aabb;
+ if (aabb.intersects(p_aabb)) {
+
+ p_results[rc] = E->get().owner;
+ p_result_indices[rc] = E->get().subindex;
+ rc++;
+ if (rc >= p_max_results)
+ break;
+ }
+ }
+
+ return rc;
+}
+
+void BroadPhase3DBasic::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
+
+ pair_userdata = p_userdata;
+ pair_callback = p_pair_callback;
+}
+void BroadPhase3DBasic::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
+
+ unpair_userdata = p_userdata;
+ unpair_callback = p_unpair_callback;
+}
+
+void BroadPhase3DBasic::update() {
+
+ // recompute pairs
+ for (Map<ID, Element>::Element *I = element_map.front(); I; I = I->next()) {
+
+ for (Map<ID, Element>::Element *J = I->next(); J; J = J->next()) {
+
+ Element *elem_A = &I->get();
+ Element *elem_B = &J->get();
+
+ if (elem_A->owner == elem_B->owner)
+ continue;
+
+ bool pair_ok = elem_A->aabb.intersects(elem_B->aabb) && (!elem_A->_static || !elem_B->_static);
+
+ PairKey key(I->key(), J->key());
+
+ Map<PairKey, void *>::Element *E = pair_map.find(key);
+
+ if (!pair_ok && E) {
+ if (unpair_callback)
+ unpair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, E->get(), unpair_userdata);
+ pair_map.erase(key);
+ }
+
+ if (pair_ok && !E) {
+
+ void *data = nullptr;
+ if (pair_callback)
+ data = pair_callback(elem_A->owner, elem_A->subindex, elem_B->owner, elem_B->subindex, unpair_userdata);
+ pair_map.insert(key, data);
+ }
+ }
+ }
+}
+
+BroadPhase3DSW *BroadPhase3DBasic::_create() {
+
+ return memnew(BroadPhase3DBasic);
+}
+
+BroadPhase3DBasic::BroadPhase3DBasic() {
+
+ current = 1;
+ unpair_callback = nullptr;
+ unpair_userdata = nullptr;
+ pair_callback = nullptr;
+ pair_userdata = nullptr;
+}
diff --git a/servers/physics_3d/broad_phase_3d_basic.h b/servers/physics_3d/broad_phase_3d_basic.h
new file mode 100644
index 0000000000..563dda6931
--- /dev/null
+++ b/servers/physics_3d/broad_phase_3d_basic.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* broad_phase_3d_basic.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BROAD_PHASE_BASIC_H
+#define BROAD_PHASE_BASIC_H
+
+#include "broad_phase_3d_sw.h"
+#include "core/map.h"
+
+class BroadPhase3DBasic : public BroadPhase3DSW {
+
+ struct Element {
+
+ CollisionObject3DSW *owner;
+ bool _static;
+ AABB aabb;
+ int subindex;
+ };
+
+ Map<ID, Element> element_map;
+
+ ID current;
+
+ struct PairKey {
+
+ union {
+ struct {
+ ID a;
+ ID b;
+ };
+ uint64_t key;
+ };
+
+ _FORCE_INLINE_ bool operator<(const PairKey &p_key) const {
+ return key < p_key.key;
+ }
+
+ PairKey() { key = 0; }
+ PairKey(ID p_a, ID p_b) {
+ if (p_a > p_b) {
+ a = p_b;
+ b = p_a;
+ } else {
+ a = p_a;
+ b = p_b;
+ }
+ }
+ };
+
+ Map<PairKey, void *> pair_map;
+
+ PairCallback pair_callback;
+ void *pair_userdata;
+ UnpairCallback unpair_callback;
+ void *unpair_userdata;
+
+public:
+ // 0 is an invalid ID
+ virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0);
+ virtual void move(ID p_id, const AABB &p_aabb);
+ virtual void set_static(ID p_id, bool p_static);
+ virtual void remove(ID p_id);
+
+ virtual CollisionObject3DSW *get_object(ID p_id) const;
+ virtual bool is_static(ID p_id) const;
+ virtual int get_subindex(ID p_id) const;
+
+ virtual int cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+ virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+ virtual int cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+
+ virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
+ virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
+
+ virtual void update();
+
+ static BroadPhase3DSW *_create();
+ BroadPhase3DBasic();
+};
+
+#endif // BROAD_PHASE_BASIC_H
diff --git a/servers/physics_3d/broad_phase_3d_sw.cpp b/servers/physics_3d/broad_phase_3d_sw.cpp
new file mode 100644
index 0000000000..1a20fdd0cb
--- /dev/null
+++ b/servers/physics_3d/broad_phase_3d_sw.cpp
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* broad_phase_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "broad_phase_3d_sw.h"
+
+BroadPhase3DSW::CreateFunction BroadPhase3DSW::create_func = nullptr;
+
+BroadPhase3DSW::~BroadPhase3DSW() {
+}
diff --git a/servers/physics_3d/broad_phase_3d_sw.h b/servers/physics_3d/broad_phase_3d_sw.h
new file mode 100644
index 0000000000..5950489619
--- /dev/null
+++ b/servers/physics_3d/broad_phase_3d_sw.h
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* broad_phase_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BROAD_PHASE_SW_H
+#define BROAD_PHASE_SW_H
+
+#include "core/math/aabb.h"
+#include "core/math/math_funcs.h"
+
+class CollisionObject3DSW;
+
+class BroadPhase3DSW {
+
+public:
+ typedef BroadPhase3DSW *(*CreateFunction)();
+
+ static CreateFunction create_func;
+
+ typedef uint32_t ID;
+
+ typedef void *(*PairCallback)(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_userdata);
+ typedef void (*UnpairCallback)(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_userdata);
+
+ // 0 is an invalid ID
+ virtual ID create(CollisionObject3DSW *p_object_, int p_subindex = 0) = 0;
+ virtual void move(ID p_id, const AABB &p_aabb) = 0;
+ virtual void set_static(ID p_id, bool p_static) = 0;
+ virtual void remove(ID p_id) = 0;
+
+ virtual CollisionObject3DSW *get_object(ID p_id) const = 0;
+ virtual bool is_static(ID p_id) const = 0;
+ virtual int get_subindex(ID p_id) const = 0;
+
+ virtual int cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
+ virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
+ virtual int cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0;
+
+ virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0;
+ virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0;
+
+ virtual void update() = 0;
+
+ virtual ~BroadPhase3DSW();
+};
+
+#endif // BROAD_PHASE__SW_H
diff --git a/servers/physics_3d/broad_phase_octree.cpp b/servers/physics_3d/broad_phase_octree.cpp
new file mode 100644
index 0000000000..264ab21e1e
--- /dev/null
+++ b/servers/physics_3d/broad_phase_octree.cpp
@@ -0,0 +1,129 @@
+/*************************************************************************/
+/* broad_phase_octree.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "broad_phase_octree.h"
+#include "collision_object_3d_sw.h"
+
+BroadPhase3DSW::ID BroadPhaseOctree::create(CollisionObject3DSW *p_object, int p_subindex) {
+
+ ID oid = octree.create(p_object, AABB(), p_subindex, false, 1 << p_object->get_type(), 0);
+ return oid;
+}
+
+void BroadPhaseOctree::move(ID p_id, const AABB &p_aabb) {
+
+ octree.move(p_id, p_aabb);
+}
+
+void BroadPhaseOctree::set_static(ID p_id, bool p_static) {
+
+ CollisionObject3DSW *it = octree.get(p_id);
+ octree.set_pairable(p_id, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF); //pair everything, don't care 1?
+}
+void BroadPhaseOctree::remove(ID p_id) {
+
+ octree.erase(p_id);
+}
+
+CollisionObject3DSW *BroadPhaseOctree::get_object(ID p_id) const {
+
+ CollisionObject3DSW *it = octree.get(p_id);
+ ERR_FAIL_COND_V(!it, nullptr);
+ return it;
+}
+bool BroadPhaseOctree::is_static(ID p_id) const {
+
+ return !octree.is_pairable(p_id);
+}
+int BroadPhaseOctree::get_subindex(ID p_id) const {
+
+ return octree.get_subindex(p_id);
+}
+
+int BroadPhaseOctree::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+
+ return octree.cull_point(p_point, p_results, p_max_results, p_result_indices);
+}
+
+int BroadPhaseOctree::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+
+ return octree.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices);
+}
+
+int BroadPhaseOctree::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) {
+
+ return octree.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices);
+}
+
+void *BroadPhaseOctree::_pair_callback(void *self, OctreeElementID p_A, CollisionObject3DSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObject3DSW *p_object_B, int subindex_B) {
+
+ BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self);
+ if (!bpo->pair_callback)
+ return nullptr;
+
+ return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata);
+}
+
+void BroadPhaseOctree::_unpair_callback(void *self, OctreeElementID p_A, CollisionObject3DSW *p_object_A, int subindex_A, OctreeElementID p_B, CollisionObject3DSW *p_object_B, int subindex_B, void *pairdata) {
+
+ BroadPhaseOctree *bpo = (BroadPhaseOctree *)(self);
+ if (!bpo->unpair_callback)
+ return;
+
+ bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata);
+}
+
+void BroadPhaseOctree::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) {
+
+ pair_callback = p_pair_callback;
+ pair_userdata = p_userdata;
+}
+void BroadPhaseOctree::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) {
+
+ unpair_callback = p_unpair_callback;
+ unpair_userdata = p_userdata;
+}
+
+void BroadPhaseOctree::update() {
+ // does.. not?
+}
+
+BroadPhase3DSW *BroadPhaseOctree::_create() {
+
+ return memnew(BroadPhaseOctree);
+}
+
+BroadPhaseOctree::BroadPhaseOctree() {
+ octree.set_pair_callback(_pair_callback, this);
+ octree.set_unpair_callback(_unpair_callback, this);
+ pair_callback = nullptr;
+ pair_userdata = nullptr;
+ unpair_userdata = nullptr;
+}
diff --git a/servers/physics_3d/broad_phase_octree.h b/servers/physics_3d/broad_phase_octree.h
new file mode 100644
index 0000000000..0ad59d8b0c
--- /dev/null
+++ b/servers/physics_3d/broad_phase_octree.h
@@ -0,0 +1,73 @@
+/*************************************************************************/
+/* broad_phase_octree.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 BROAD_PHASE_OCTREE_H
+#define BROAD_PHASE_OCTREE_H
+
+#include "broad_phase_3d_sw.h"
+#include "core/math/octree.h"
+
+class BroadPhaseOctree : public BroadPhase3DSW {
+
+ Octree<CollisionObject3DSW, true> octree;
+
+ static void *_pair_callback(void *, OctreeElementID, CollisionObject3DSW *, int, OctreeElementID, CollisionObject3DSW *, int);
+ static void _unpair_callback(void *, OctreeElementID, CollisionObject3DSW *, int, OctreeElementID, CollisionObject3DSW *, int, void *);
+
+ PairCallback pair_callback;
+ void *pair_userdata;
+ UnpairCallback unpair_callback;
+ void *unpair_userdata;
+
+public:
+ // 0 is an invalid ID
+ virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0);
+ virtual void move(ID p_id, const AABB &p_aabb);
+ virtual void set_static(ID p_id, bool p_static);
+ virtual void remove(ID p_id);
+
+ virtual CollisionObject3DSW *get_object(ID p_id) const;
+ virtual bool is_static(ID p_id) const;
+ virtual int get_subindex(ID p_id) const;
+
+ virtual int cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+ virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+ virtual int cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr);
+
+ virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata);
+ virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata);
+
+ virtual void update();
+
+ static BroadPhase3DSW *_create();
+ BroadPhaseOctree();
+};
+
+#endif // BROAD_PHASE_OCTREE_H
diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp
new file mode 100644
index 0000000000..24715d211d
--- /dev/null
+++ b/servers/physics_3d/collision_object_3d_sw.cpp
@@ -0,0 +1,239 @@
+/*************************************************************************/
+/* collision_object_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_object_3d_sw.h"
+#include "servers/physics_3d/physics_server_3d_sw.h"
+#include "space_3d_sw.h"
+
+void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform &p_transform, bool p_disabled) {
+
+ Shape s;
+ s.shape = p_shape;
+ s.xform = p_transform;
+ s.xform_inv = s.xform.affine_inverse();
+ s.bpid = 0; //needs update
+ s.disabled = p_disabled;
+ shapes.push_back(s);
+ p_shape->add_owner(this);
+
+ if (!pending_shape_update_list.in_list()) {
+ PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ }
+ //_update_shapes();
+ //_shapes_changed();
+}
+
+void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) {
+
+ ERR_FAIL_INDEX(p_index, shapes.size());
+ shapes[p_index].shape->remove_owner(this);
+ shapes.write[p_index].shape = 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);
+ }
+ //_update_shapes();
+ //_shapes_changed();
+}
+void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_transform) {
+
+ ERR_FAIL_INDEX(p_index, shapes.size());
+
+ 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);
+ }
+ //_update_shapes();
+ //_shapes_changed();
+}
+
+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);
+ }
+}
+
+void CollisionObject3DSW::remove_shape(Shape3DSW *p_shape) {
+
+ //remove a shape, all the times it appears
+ for (int i = 0; i < shapes.size(); i++) {
+
+ if (shapes[i].shape == p_shape) {
+ remove_shape(i);
+ i--;
+ }
+ }
+}
+
+void CollisionObject3DSW::remove_shape(int p_index) {
+
+ //remove anything from shape to be erased to end, so subindices don't change
+ ERR_FAIL_INDEX(p_index, shapes.size());
+ for (int i = p_index; i < shapes.size(); i++) {
+
+ if (shapes[i].bpid == 0)
+ continue;
+ //should never get here with a null owner
+ space->get_broadphase()->remove(shapes[i].bpid);
+ shapes.write[i].bpid = 0;
+ }
+ shapes[p_index].shape->remove_owner(this);
+ shapes.remove(p_index);
+
+ if (!pending_shape_update_list.in_list()) {
+ PhysicsServer3DSW::singleton->pending_shape_update_list.add(&pending_shape_update_list);
+ }
+ //_update_shapes();
+ //_shapes_changed();
+}
+
+void CollisionObject3DSW::_set_static(bool p_static) {
+ if (_static == p_static)
+ return;
+ _static = p_static;
+
+ if (!space)
+ return;
+ for (int i = 0; i < get_shape_count(); i++) {
+ const Shape &s = shapes[i];
+ if (s.bpid > 0) {
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+ }
+}
+
+void CollisionObject3DSW::_unregister_shapes() {
+
+ for (int i = 0; i < shapes.size(); i++) {
+
+ Shape &s = shapes.write[i];
+ if (s.bpid > 0) {
+ space->get_broadphase()->remove(s.bpid);
+ s.bpid = 0;
+ }
+ }
+}
+
+void CollisionObject3DSW::_update_shapes() {
+
+ if (!space)
+ return;
+
+ for (int i = 0; i < shapes.size(); i++) {
+
+ Shape &s = shapes.write[i];
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
+ //not quite correct, should compute the next matrix..
+ AABB shape_aabb = s.shape->get_aabb();
+ Transform xform = transform * s.xform;
+ shape_aabb = xform.xform(shape_aabb);
+ s.aabb_cache = shape_aabb;
+ s.aabb_cache = s.aabb_cache.grow((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05);
+
+ Vector3 scale = xform.get_basis().get_scale();
+ s.area_cache = s.shape->get_area() * scale.x * scale.y * scale.z;
+
+ space->get_broadphase()->move(s.bpid, s.aabb_cache);
+ }
+}
+
+void CollisionObject3DSW::_update_shapes_with_motion(const Vector3 &p_motion) {
+
+ if (!space)
+ return;
+
+ for (int i = 0; i < shapes.size(); i++) {
+
+ Shape &s = shapes.write[i];
+ if (s.bpid == 0) {
+ s.bpid = space->get_broadphase()->create(this, i);
+ space->get_broadphase()->set_static(s.bpid, _static);
+ }
+
+ //not quite correct, should compute the next matrix..
+ AABB shape_aabb = s.shape->get_aabb();
+ Transform xform = transform * s.xform;
+ shape_aabb = xform.xform(shape_aabb);
+ shape_aabb = shape_aabb.merge(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion
+ s.aabb_cache = shape_aabb;
+
+ space->get_broadphase()->move(s.bpid, shape_aabb);
+ }
+}
+
+void CollisionObject3DSW::_set_space(Space3DSW *p_space) {
+
+ if (space) {
+
+ space->remove_object(this);
+
+ for (int i = 0; i < shapes.size(); i++) {
+
+ Shape &s = shapes.write[i];
+ if (s.bpid) {
+ space->get_broadphase()->remove(s.bpid);
+ s.bpid = 0;
+ }
+ }
+ }
+
+ space = p_space;
+
+ if (space) {
+
+ space->add_object(this);
+ _update_shapes();
+ }
+}
+
+void CollisionObject3DSW::_shape_changed() {
+
+ _update_shapes();
+ _shapes_changed();
+}
+
+CollisionObject3DSW::CollisionObject3DSW(Type p_type) :
+ pending_shape_update_list(this) {
+
+ _static = true;
+ type = p_type;
+ space = nullptr;
+
+ collision_layer = 1;
+ collision_mask = 1;
+ ray_pickable = true;
+}
diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h
new file mode 100644
index 0000000000..c5773d0c61
--- /dev/null
+++ b/servers/physics_3d/collision_object_3d_sw.h
@@ -0,0 +1,164 @@
+/*************************************************************************/
+/* collision_object_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_OBJECT_SW_H
+#define COLLISION_OBJECT_SW_H
+
+#include "broad_phase_3d_sw.h"
+#include "core/self_list.h"
+#include "servers/physics_server_3d.h"
+#include "shape_3d_sw.h"
+
+#ifdef DEBUG_ENABLED
+#define MAX_OBJECT_DISTANCE 3.1622776601683791e+18
+
+#define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE * MAX_OBJECT_DISTANCE)
+#endif
+
+class Space3DSW;
+
+class CollisionObject3DSW : public ShapeOwner3DSW {
+public:
+ enum Type {
+ TYPE_AREA,
+ TYPE_BODY
+ };
+
+private:
+ Type type;
+ RID self;
+ ObjectID instance_id;
+ uint32_t collision_layer;
+ uint32_t collision_mask;
+
+ struct Shape {
+
+ Transform xform;
+ Transform xform_inv;
+ BroadPhase3DSW::ID bpid;
+ AABB aabb_cache; //for rayqueries
+ real_t area_cache;
+ Shape3DSW *shape;
+ bool disabled;
+
+ Shape() { disabled = false; }
+ };
+
+ Vector<Shape> shapes;
+ Space3DSW *space;
+ Transform transform;
+ Transform inv_transform;
+ bool _static;
+
+ SelfList<CollisionObject3DSW> pending_shape_update_list;
+
+ void _update_shapes();
+
+protected:
+ void _update_shapes_with_motion(const Vector3 &p_motion);
+ void _unregister_shapes();
+
+ _FORCE_INLINE_ void _set_transform(const Transform &p_transform, bool p_update_shapes = true) {
+#ifdef DEBUG_ENABLED
+
+ ERR_FAIL_COND_MSG(p_transform.origin.length_squared() > MAX_OBJECT_DISTANCE_X2, "Object went too far away (more than '" + itos(MAX_OBJECT_DISTANCE) + "' units from origin).");
+#endif
+
+ transform = p_transform;
+ if (p_update_shapes) _update_shapes();
+ }
+ _FORCE_INLINE_ void _set_inv_transform(const Transform &p_transform) { inv_transform = p_transform; }
+ void _set_static(bool p_static);
+
+ virtual void _shapes_changed() = 0;
+ void _set_space(Space3DSW *p_space);
+
+ bool ray_pickable;
+
+ CollisionObject3DSW(Type p_type);
+
+public:
+ _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
+ _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
+
+ void _shape_changed();
+
+ _FORCE_INLINE_ Type get_type() const { return type; }
+ void add_shape(Shape3DSW *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
+ void set_shape(int p_index, Shape3DSW *p_shape);
+ void set_shape_transform(int p_index, const Transform &p_transform);
+ _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
+ _FORCE_INLINE_ bool is_shape_disabled(int p_index) const {
+ CRASH_BAD_INDEX(p_index, shapes.size());
+ return shapes[p_index].disabled;
+ }
+ _FORCE_INLINE_ Shape3DSW *get_shape(int p_index) const { return shapes[p_index].shape; }
+ _FORCE_INLINE_ const Transform &get_shape_transform(int p_index) const { return shapes[p_index].xform; }
+ _FORCE_INLINE_ const Transform &get_shape_inv_transform(int p_index) const { return shapes[p_index].xform_inv; }
+ _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_ Space3DSW *get_space() const { return space; }
+
+ _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
+ _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; }
+
+ void set_shape_as_disabled(int p_idx, bool p_enable);
+ _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const {
+ CRASH_BAD_INDEX(p_idx, shapes.size());
+ return shapes[p_idx].disabled;
+ }
+
+ _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; }
+ _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
+
+ _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; }
+ _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
+
+ _FORCE_INLINE_ bool test_collision_mask(CollisionObject3DSW *p_other) const {
+ return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask;
+ }
+
+ void remove_shape(Shape3DSW *p_shape);
+ void remove_shape(int p_index);
+
+ virtual void set_space(Space3DSW *p_space) = 0;
+
+ _FORCE_INLINE_ bool is_static() const { return _static; }
+
+ virtual ~CollisionObject3DSW() {}
+};
+
+#endif // COLLISION_OBJECT_SW_H
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
new file mode 100644
index 0000000000..5096b080ab
--- /dev/null
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -0,0 +1,1591 @@
+/*************************************************************************/
+/* collision_solver_3d_sat.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_solver_3d_sat.h"
+#include "core/math/geometry.h"
+
+#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.02
+
+struct _CollectorCallback {
+
+ CollisionSolver3DSW::CallbackResult callback;
+ void *userdata;
+ bool swap;
+ bool collided;
+ Vector3 normal;
+ Vector3 *prev_axis;
+
+ _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+
+ if (swap)
+ callback(p_point_B, p_point_A, userdata);
+ else
+ callback(p_point_A, p_point_B, userdata);
+ }
+};
+
+typedef void (*GenerateContactsFunc)(const Vector3 *, int, const Vector3 *, int, _CollectorCallback *);
+
+static void _generate_contacts_point_point(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 != 1);
+#endif
+
+ p_callback->call(*p_points_A, *p_points_B);
+}
+
+static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(p_point_count_A != 1);
+ ERR_FAIL_COND(p_point_count_B != 2);
+#endif
+
+ Vector3 closest_B = Geometry::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B);
+ p_callback->call(*p_points_A, closest_B);
+}
+
+static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
+
+#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);
+ ERR_FAIL_COND(p_point_count_B != 2); // circle is actually a 4x3 matrix
+#endif
+
+ Vector3 rel_A = p_points_A[1] - p_points_A[0];
+ Vector3 rel_B = p_points_B[1] - p_points_B[0];
+
+ Vector3 c = rel_A.cross(rel_B).cross(rel_B);
+
+ if (Math::is_zero_approx(rel_A.dot(c))) {
+
+ // should handle somehow..
+ //ERR_PRINT("TODO FIX");
+ //return;
+
+ Vector3 axis = rel_A.normalized(); //make an axis
+ Vector3 base_A = p_points_A[0] - axis * axis.dot(p_points_A[0]);
+ Vector3 base_B = p_points_B[0] - axis * axis.dot(p_points_B[0]);
+
+ //sort all 4 points in axis
+ real_t dvec[4] = { axis.dot(p_points_A[0]), axis.dot(p_points_A[1]), axis.dot(p_points_B[0]), axis.dot(p_points_B[1]) };
+
+ SortArray<real_t> sa;
+ sa.sort(dvec, 4);
+
+ //use the middle ones as contacts
+ p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1]);
+ p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2]);
+
+ return;
+ }
+
+ real_t d = (c.dot(p_points_B[0]) - p_points_A[0].dot(c)) / rel_A.dot(c);
+
+ if (d < 0.0)
+ d = 0.0;
+ else if (d > 1.0)
+ d = 1.0;
+
+ Vector3 closest_A = p_points_A[0] + rel_A * d;
+ Vector3 closest_B = Geometry::get_closest_point_to_segment_uncapped(closest_A, p_points_B);
+ p_callback->call(closest_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);
+ ERR_FAIL_COND(p_point_count_B < 3);
+#endif
+
+ static const int max_clip = 32;
+
+ Vector3 _clipbuf1[max_clip];
+ Vector3 _clipbuf2[max_clip];
+ Vector3 *clipbuf_src = _clipbuf1;
+ Vector3 *clipbuf_dst = _clipbuf2;
+ int clipbuf_len = p_point_count_A;
+
+ // copy A points to clipbuf_src
+ for (int i = 0; i < p_point_count_A; i++) {
+
+ clipbuf_src[i] = p_points_A[i];
+ }
+
+ Plane plane_B(p_points_B[0], p_points_B[1], p_points_B[2]);
+
+ // go through all of B points
+ for (int i = 0; i < p_point_count_B; i++) {
+
+ int i_n = (i + 1) % p_point_count_B;
+
+ Vector3 edge0_B = p_points_B[i];
+ Vector3 edge1_B = p_points_B[i_n];
+
+ Vector3 clip_normal = (edge0_B - edge1_B).cross(plane_B.normal).normalized();
+ // make a clip plane
+
+ Plane clip(edge0_B, clip_normal);
+ // avoid double clip if A is edge
+ int dst_idx = 0;
+ bool edge = clipbuf_len == 2;
+ for (int j = 0; j < clipbuf_len; j++) {
+
+ int j_n = (j + 1) % clipbuf_len;
+
+ Vector3 edge0_A = clipbuf_src[j];
+ Vector3 edge1_A = clipbuf_src[j_n];
+
+ real_t dist0 = clip.distance_to(edge0_A);
+ real_t dist1 = clip.distance_to(edge1_A);
+
+ if (dist0 <= 0) { // behind plane
+
+ ERR_FAIL_COND(dst_idx >= max_clip);
+ clipbuf_dst[dst_idx++] = clipbuf_src[j];
+ }
+
+ // check for different sides and non coplanar
+ //if ( (dist0*dist1) < -CMP_EPSILON && !(edge && j)) {
+ if ((dist0 * dist1) < 0 && !(edge && j)) {
+
+ // calculate intersection
+ Vector3 rel = edge1_A - edge0_A;
+ real_t den = clip.normal.dot(rel);
+ real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;
+ Vector3 inters = edge0_A + rel * dist;
+
+ ERR_FAIL_COND(dst_idx >= max_clip);
+ clipbuf_dst[dst_idx] = inters;
+ dst_idx++;
+ }
+ }
+
+ clipbuf_len = dst_idx;
+ SWAP(clipbuf_src, clipbuf_dst);
+ }
+
+ // generate contacts
+ //Plane plane_A(p_points_A[0],p_points_A[1],p_points_A[2]);
+
+ for (int i = 0; i < clipbuf_len; i++) {
+
+ real_t d = plane_B.distance_to(clipbuf_src[i]);
+ /*
+ if (d>CMP_EPSILON)
+ continue;
+ */
+
+ Vector3 closest_B = clipbuf_src[i] - plane_B.normal * d;
+
+ if (p_callback->normal.dot(clipbuf_src[i]) >= p_callback->normal.dot(closest_B))
+ continue;
+
+ p_callback->call(clipbuf_src[i], closest_B);
+ }
+}
+
+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) {
+
+#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] = {
+ {
+ _generate_contacts_point_point,
+ _generate_contacts_point_edge,
+ _generate_contacts_point_face,
+ },
+ {
+ nullptr,
+ _generate_contacts_edge_edge,
+ _generate_contacts_face_face,
+ },
+ {
+ nullptr,
+ nullptr,
+ _generate_contacts_face_face,
+ }
+ };
+
+ int pointcount_B;
+ int pointcount_A;
+ const Vector3 *points_A;
+ const Vector3 *points_B;
+
+ if (p_point_count_A > p_point_count_B) {
+ //swap
+ p_callback->swap = !p_callback->swap;
+ p_callback->normal = -p_callback->normal;
+
+ pointcount_B = p_point_count_A;
+ pointcount_A = p_point_count_B;
+ points_A = p_points_B;
+ points_B = p_points_A;
+ } else {
+
+ pointcount_B = p_point_count_B;
+ pointcount_A = p_point_count_A;
+ points_A = p_points_A;
+ points_B = p_points_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);
+}
+
+template <class ShapeA, class ShapeB, bool withMargin = false>
+class SeparatorAxisTest {
+
+ const ShapeA *shape_A;
+ const ShapeB *shape_B;
+ const Transform *transform_A;
+ const Transform *transform_B;
+ real_t best_depth;
+ Vector3 best_axis;
+ _CollectorCallback *callback;
+ real_t margin_A;
+ real_t margin_B;
+ Vector3 separator_axis;
+
+public:
+ _FORCE_INLINE_ bool test_previous_axis() {
+
+ if (callback && callback->prev_axis && *callback->prev_axis != Vector3())
+ return test_axis(*callback->prev_axis);
+ else
+ return true;
+ }
+
+ _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
+
+ Vector3 axis = p_axis;
+
+ if (Math::abs(axis.x) < CMP_EPSILON &&
+ Math::abs(axis.y) < CMP_EPSILON &&
+ Math::abs(axis.z) < CMP_EPSILON) {
+ // strange case, try an upwards separator
+ axis = Vector3(0.0, 1.0, 0.0);
+ }
+
+ real_t min_A, max_A, min_B, max_B;
+
+ shape_A->project_range(axis, *transform_A, min_A, max_A);
+ shape_B->project_range(axis, *transform_B, min_B, max_B);
+
+ if (withMargin) {
+ min_A -= margin_A;
+ max_A += margin_A;
+ min_B -= margin_B;
+ max_B += margin_B;
+ }
+
+ min_B -= (max_A - min_A) * 0.5;
+ max_B += (max_A - min_A) * 0.5;
+
+ min_B -= (min_A + max_A) * 0.5;
+ max_B -= (min_A + max_A) * 0.5;
+
+ if (min_B > 0.0 || max_B < 0.0) {
+ separator_axis = axis;
+ return false; // doesn't contain 0
+ }
+
+ //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 (max_B < min_B) {
+ if (max_B < best_depth) {
+ best_depth = max_B;
+ best_axis = axis;
+ }
+ } else {
+ if (min_B < best_depth) {
+ best_depth = min_B;
+ best_axis = -axis; // keep it as A axis
+ }
+ }
+
+ return true;
+ }
+
+ _FORCE_INLINE_ void generate_contacts() {
+
+ // nothing to do, don't generate
+ if (best_axis == Vector3(0.0, 0.0, 0.0))
+ return;
+
+ if (!callback->callback) {
+ //just was checking intersection?
+ callback->collided = true;
+ if (callback->prev_axis)
+ *callback->prev_axis = best_axis;
+ return;
+ }
+
+ static const int max_supports = 16;
+
+ 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);
+ for (int i = 0; i < support_count_A; i++) {
+ supports_A[i] = transform_A->xform(supports_A[i]);
+ }
+
+ if (withMargin) {
+
+ for (int i = 0; i < support_count_A; i++) {
+ supports_A[i] += -best_axis * margin_A;
+ }
+ }
+
+ 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);
+ for (int i = 0; i < support_count_B; i++) {
+ supports_B[i] = transform_B->xform(supports_B[i]);
+ }
+
+ if (withMargin) {
+
+ for (int i = 0; i < support_count_B; i++) {
+ supports_B[i] += best_axis * margin_B;
+ }
+ }
+
+ callback->normal = best_axis;
+ if (callback->prev_axis)
+ *callback->prev_axis = best_axis;
+ _generate_contacts_from_supports(supports_A, support_count_A, supports_B, support_count_B, callback);
+
+ callback->collided = true;
+ }
+
+ _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A, const Transform &p_transform_A, const ShapeB *p_shape_B, const Transform &p_transform_B, _CollectorCallback *p_callback, real_t p_margin_A = 0, real_t p_margin_B = 0) {
+ best_depth = 1e15;
+ shape_A = p_shape_A;
+ shape_B = p_shape_B;
+ transform_A = &p_transform_A;
+ transform_B = &p_transform_B;
+ callback = p_callback;
+ margin_A = p_margin_A;
+ margin_B = p_margin_B;
+ }
+};
+
+/****** SAT TESTS *******/
+
+typedef void (*CollisionFunc)(const Shape3DSW *, const Transform &, const Shape3DSW *, const Transform &, _CollectorCallback *p_callback, real_t, real_t);
+
+template <bool withMargin>
+static void _collision_sphere_sphere(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 SphereShape3DSW *sphere_B = static_cast<const SphereShape3DSW *>(p_b);
+
+ SeparatorAxisTest<SphereShape3DSW, SphereShape3DSW, withMargin> separator(sphere_A, p_transform_a, sphere_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ // previous axis
+
+ if (!separator.test_previous_axis())
+ return;
+
+ if (!separator.test_axis((p_transform_a.origin - p_transform_b.origin).normalized()))
+ return;
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_sphere_box(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 BoxShape3DSW *box_B = static_cast<const BoxShape3DSW *>(p_b);
+
+ SeparatorAxisTest<SphereShape3DSW, BoxShape3DSW, withMargin> separator(sphere_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ // test faces
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis = p_transform_b.basis.get_axis(i).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // calculate closest point to sphere
+
+ Vector3 cnormal = p_transform_b.xform_inv(p_transform_a.origin);
+
+ Vector3 cpoint = p_transform_b.xform(Vector3(
+
+ (cnormal.x < 0) ? -box_B->get_half_extents().x : box_B->get_half_extents().x,
+ (cnormal.y < 0) ? -box_B->get_half_extents().y : box_B->get_half_extents().y,
+ (cnormal.z < 0) ? -box_B->get_half_extents().z : box_B->get_half_extents().z));
+
+ // use point to test axis
+ Vector3 point_axis = (p_transform_a.origin - cpoint).normalized();
+
+ if (!separator.test_axis(point_axis))
+ return;
+
+ // test edges
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis = point_axis.cross(p_transform_b.basis.get_axis(i)).cross(p_transform_b.basis.get_axis(i)).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_sphere_capsule(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 CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b);
+
+ SeparatorAxisTest<SphereShape3DSW, CapsuleShape3DSW, withMargin> separator(sphere_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ //capsule sphere 1, sphere
+
+ Vector3 capsule_axis = p_transform_b.basis.get_axis(2) * (capsule_B->get_height() * 0.5);
+
+ Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis;
+
+ if (!separator.test_axis((capsule_ball_1 - p_transform_a.origin).normalized()))
+ return;
+
+ //capsule sphere 2, sphere
+
+ Vector3 capsule_ball_2 = p_transform_b.origin - capsule_axis;
+
+ if (!separator.test_axis((capsule_ball_2 - p_transform_a.origin).normalized()))
+ return;
+
+ //capsule edge, sphere
+
+ Vector3 b2a = p_transform_a.origin - p_transform_b.origin;
+
+ Vector3 axis = b2a.cross(capsule_axis).cross(capsule_axis).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+
+ separator.generate_contacts();
+}
+
+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) {
+}
+
+template <bool withMargin>
+static void _collision_sphere_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 SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a);
+ const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b);
+
+ SeparatorAxisTest<SphereShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(sphere_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ const Geometry::MeshData &mesh = convex_polygon_B->get_mesh();
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int face_count = mesh.faces.size();
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int edge_count = mesh.edges.size();
+ const Vector3 *vertices = mesh.vertices.ptr();
+ int vertex_count = mesh.vertices.size();
+
+ // faces of B
+ for (int i = 0; i < face_count; i++) {
+
+ Vector3 axis = p_transform_b.xform(faces[i].plane).normal;
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // edges of B
+ for (int i = 0; i < edge_count; i++) {
+
+ Vector3 v1 = p_transform_b.xform(vertices[edges[i].a]);
+ Vector3 v2 = p_transform_b.xform(vertices[edges[i].b]);
+ Vector3 v3 = p_transform_a.origin;
+
+ Vector3 n1 = v2 - v1;
+ Vector3 n2 = v2 - v3;
+
+ Vector3 axis = n1.cross(n2).cross(n1).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // vertices of B
+ for (int i = 0; i < vertex_count; i++) {
+
+ Vector3 v1 = p_transform_b.xform(vertices[i]);
+ Vector3 v2 = p_transform_a.origin;
+
+ Vector3 axis = (v2 - v1).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_sphere_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 SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a);
+ const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b);
+
+ SeparatorAxisTest<SphereShape3DSW, FaceShape3DSW, withMargin> separator(sphere_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ 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]),
+ };
+
+ if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
+ return;
+
+ // edges and points of B
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 n1 = vertex[i] - p_transform_a.origin;
+
+ if (!separator.test_axis(n1.normalized())) {
+ return;
+ }
+
+ Vector3 n2 = vertex[(i + 1) % 3] - vertex[i];
+
+ Vector3 axis = n1.cross(n2).cross(n2).normalized();
+
+ if (!separator.test_axis(axis)) {
+ return;
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_box_box(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 BoxShape3DSW *box_B = static_cast<const BoxShape3DSW *>(p_b);
+
+ SeparatorAxisTest<BoxShape3DSW, BoxShape3DSW, withMargin> separator(box_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ // test 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;
+ }
+
+ // test faces of B
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis = p_transform_b.basis.get_axis(i).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // test combined edges
+ for (int i = 0; i < 3; i++) {
+
+ for (int j = 0; j < 3; j++) {
+
+ Vector3 axis = p_transform_a.basis.get_axis(i).cross(p_transform_b.basis.get_axis(j));
+
+ if (Math::is_zero_approx(axis.length_squared()))
+ continue;
+ axis.normalize();
+
+ if (!separator.test_axis(axis)) {
+ return;
+ }
+ }
+ }
+
+ if (withMargin) {
+ //add endpoint test between closest vertices and edges
+
+ // calculate closest point to sphere
+
+ Vector3 ab_vec = p_transform_b.origin - p_transform_a.origin;
+
+ Vector3 cnormal_a = p_transform_a.basis.xform_inv(ab_vec);
+
+ Vector3 support_a = p_transform_a.xform(Vector3(
+
+ (cnormal_a.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal_a.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
+
+ Vector3 cnormal_b = p_transform_b.basis.xform_inv(-ab_vec);
+
+ Vector3 support_b = p_transform_b.xform(Vector3(
+
+ (cnormal_b.x < 0) ? -box_B->get_half_extents().x : box_B->get_half_extents().x,
+ (cnormal_b.y < 0) ? -box_B->get_half_extents().y : box_B->get_half_extents().y,
+ (cnormal_b.z < 0) ? -box_B->get_half_extents().z : box_B->get_half_extents().z));
+
+ Vector3 axis_ab = (support_a - support_b);
+
+ if (!separator.test_axis(axis_ab.normalized())) {
+ return;
+ }
+
+ //now try edges, which become cylinders!
+
+ for (int i = 0; i < 3; i++) {
+
+ //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()))
+ return;
+
+ //b ->a
+ Vector3 axis_b = p_transform_b.basis.get_axis(i);
+
+ if (!separator.test_axis(axis_ab.cross(axis_b).cross(axis_b).normalized()))
+ return;
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_box_capsule(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 CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b);
+
+ SeparatorAxisTest<BoxShape3DSW, CapsuleShape3DSW, withMargin> separator(box_A, p_transform_a, capsule_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);
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ Vector3 cyl_axis = p_transform_b.basis.get_axis(2).normalized();
+
+ // edges of A, capsule cylinder
+
+ for (int i = 0; i < 3; i++) {
+
+ // cylinder
+ 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;
+ }
+
+ // points of A, capsule cylinder
+ // this sure could be made faster somehow..
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ Vector3 he = box_A->get_half_extents();
+ he.x *= (i * 2 - 1);
+ he.y *= (j * 2 - 1);
+ he.z *= (k * 2 - 1);
+ Vector3 point = p_transform_a.origin;
+ for (int l = 0; l < 3; l++)
+ point += p_transform_a.basis.get_axis(l) * he[l];
+
+ //Vector3 axis = (point - cyl_axis * cyl_axis.dot(point)).normalized();
+ Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+ }
+ }
+
+ // 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 sphere_pos = p_transform_b.origin + ((i == 0) ? capsule_axis : -capsule_axis);
+
+ Vector3 cnormal = p_transform_a.xform_inv(sphere_pos);
+
+ Vector3 cpoint = p_transform_a.xform(Vector3(
+
+ (cnormal.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
+
+ // use point to test axis
+ Vector3 point_axis = (sphere_pos - cpoint).normalized();
+
+ if (!separator.test_axis(point_axis))
+ return;
+
+ // test edges of A
+
+ for (int j = 0; j < 3; j++) {
+
+ Vector3 axis = point_axis.cross(p_transform_a.basis.get_axis(j)).cross(p_transform_a.basis.get_axis(j)).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+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) {
+}
+
+template <bool withMargin>
+static void _collision_box_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 BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a);
+ const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b);
+
+ SeparatorAxisTest<BoxShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(box_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ const Geometry::MeshData &mesh = convex_polygon_B->get_mesh();
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int face_count = mesh.faces.size();
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int edge_count = mesh.edges.size();
+ const Vector3 *vertices = mesh.vertices.ptr();
+ int vertex_count = mesh.vertices.size();
+
+ // 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;
+ }
+
+ // faces of B
+ for (int i = 0; i < face_count; i++) {
+
+ Vector3 axis = p_transform_b.xform(faces[i].plane).normal;
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // A<->B edges
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 e1 = p_transform_a.basis.get_axis(i);
+
+ for (int j = 0; j < edge_count; j++) {
+
+ Vector3 e2 = p_transform_b.basis.xform(vertices[edges[j].a]) - p_transform_b.basis.xform(vertices[edges[j].b]);
+
+ Vector3 axis = e1.cross(e2).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+ }
+
+ if (withMargin) {
+
+ // calculate closest points between vertices and box edges
+ for (int v = 0; v < vertex_count; v++) {
+
+ Vector3 vtxb = p_transform_b.xform(vertices[v]);
+ Vector3 ab_vec = vtxb - p_transform_a.origin;
+
+ Vector3 cnormal_a = p_transform_a.basis.xform_inv(ab_vec);
+
+ Vector3 support_a = p_transform_a.xform(Vector3(
+
+ (cnormal_a.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal_a.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
+
+ Vector3 axis_ab = support_a - vtxb;
+
+ if (!separator.test_axis(axis_ab.normalized())) {
+ return;
+ }
+
+ //now try edges, which become cylinders!
+
+ for (int i = 0; i < 3; i++) {
+
+ //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()))
+ return;
+ }
+ }
+
+ //convex edges and box points
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ Vector3 he = box_A->get_half_extents();
+ he.x *= (i * 2 - 1);
+ he.y *= (j * 2 - 1);
+ he.z *= (k * 2 - 1);
+ Vector3 point = p_transform_a.origin;
+ for (int l = 0; l < 3; l++)
+ point += p_transform_a.basis.get_axis(l) * he[l];
+
+ for (int e = 0; e < edge_count; e++) {
+
+ Vector3 p1 = p_transform_b.xform(vertices[edges[e].a]);
+ Vector3 p2 = p_transform_b.xform(vertices[edges[e].b]);
+ Vector3 n = (p2 - p1);
+
+ if (!separator.test_axis((point - p2).cross(n).cross(n).normalized()))
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_box_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 BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a);
+ const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b);
+
+ SeparatorAxisTest<BoxShape3DSW, FaceShape3DSW, withMargin> separator(box_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ 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]),
+ };
+
+ if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
+ 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;
+ }
+
+ // combined edges
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 e = vertex[i] - vertex[(i + 1) % 3];
+
+ for (int j = 0; j < 3; j++) {
+
+ Vector3 axis = p_transform_a.basis.get_axis(j);
+
+ if (!separator.test_axis(e.cross(axis).normalized()))
+ return;
+ }
+ }
+
+ if (withMargin) {
+
+ // calculate closest points between vertices and box edges
+ for (int v = 0; v < 3; v++) {
+
+ Vector3 ab_vec = vertex[v] - p_transform_a.origin;
+
+ Vector3 cnormal_a = p_transform_a.basis.xform_inv(ab_vec);
+
+ Vector3 support_a = p_transform_a.xform(Vector3(
+
+ (cnormal_a.x < 0) ? -box_A->get_half_extents().x : box_A->get_half_extents().x,
+ (cnormal_a.y < 0) ? -box_A->get_half_extents().y : box_A->get_half_extents().y,
+ (cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
+
+ Vector3 axis_ab = support_a - vertex[v];
+
+ if (!separator.test_axis(axis_ab.normalized())) {
+ return;
+ }
+
+ //now try edges, which become cylinders!
+
+ for (int i = 0; i < 3; i++) {
+
+ //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()))
+ return;
+ }
+ }
+
+ //convex edges and box points, there has to be a way to speed up this (get closest point?)
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ Vector3 he = box_A->get_half_extents();
+ he.x *= (i * 2 - 1);
+ he.y *= (j * 2 - 1);
+ he.z *= (k * 2 - 1);
+ Vector3 point = p_transform_a.origin;
+ for (int l = 0; l < 3; l++)
+ point += p_transform_a.basis.get_axis(l) * he[l];
+
+ for (int e = 0; e < 3; e++) {
+
+ Vector3 p1 = vertex[e];
+ Vector3 p2 = vertex[(e + 1) % 3];
+
+ Vector3 n = (p2 - p1);
+
+ if (!separator.test_axis((point - p2).cross(n).cross(n).normalized()))
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_capsule_capsule(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 CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CapsuleShape3DSW, CapsuleShape3DSW, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ // 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_ball_1 = p_transform_a.origin + capsule_A_axis;
+ Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis;
+ Vector3 capsule_B_ball_1 = p_transform_b.origin + capsule_B_axis;
+ Vector3 capsule_B_ball_2 = p_transform_b.origin - capsule_B_axis;
+
+ //balls-balls
+
+ if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_1).normalized()))
+ return;
+ if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_2).normalized()))
+ return;
+
+ if (!separator.test_axis((capsule_A_ball_2 - capsule_B_ball_1).normalized()))
+ return;
+ if (!separator.test_axis((capsule_A_ball_2 - capsule_B_ball_2).normalized()))
+ return;
+
+ // edges-balls
+
+ if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_1).cross(capsule_A_axis).cross(capsule_A_axis).normalized()))
+ return;
+
+ if (!separator.test_axis((capsule_A_ball_1 - capsule_B_ball_2).cross(capsule_A_axis).cross(capsule_A_axis).normalized()))
+ return;
+
+ if (!separator.test_axis((capsule_B_ball_1 - capsule_A_ball_1).cross(capsule_B_axis).cross(capsule_B_axis).normalized()))
+ return;
+
+ if (!separator.test_axis((capsule_B_ball_1 - capsule_A_ball_2).cross(capsule_B_axis).cross(capsule_B_axis).normalized()))
+ return;
+
+ // edges
+
+ if (!separator.test_axis(capsule_A_axis.cross(capsule_B_axis).normalized()))
+ return;
+
+ separator.generate_contacts();
+}
+
+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) {
+}
+
+template <bool withMargin>
+static void _collision_capsule_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 CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a);
+ const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CapsuleShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(capsule_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ const Geometry::MeshData &mesh = convex_polygon_B->get_mesh();
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int face_count = mesh.faces.size();
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int edge_count = mesh.edges.size();
+ const Vector3 *vertices = mesh.vertices.ptr();
+
+ // faces of B
+ for (int i = 0; i < face_count; i++) {
+
+ Vector3 axis = p_transform_b.xform(faces[i].plane).normal;
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // edges of B, capsule cylinder
+
+ 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();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // capsule balls, edges of B
+
+ 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 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis);
+
+ for (int j = 0; j < edge_count; j++) {
+
+ Vector3 n1 = sphere_pos - p_transform_b.xform(vertices[edges[j].a]);
+ Vector3 n2 = p_transform_b.basis.xform(vertices[edges[j].a]) - p_transform_b.basis.xform(vertices[edges[j].b]);
+
+ Vector3 axis = n1.cross(n2).cross(n2).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_capsule_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 CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a);
+ const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b);
+
+ SeparatorAxisTest<CapsuleShape3DSW, FaceShape3DSW, withMargin> separator(capsule_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ 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]),
+ };
+
+ if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
+ return;
+
+ // edges of B, capsule cylinder
+
+ Vector3 capsule_axis = p_transform_a.basis.get_axis(2) * (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 (!separator.test_axis(axis))
+ return;
+
+ if (!separator.test_axis((p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized()))
+ return;
+
+ for (int j = 0; j < 2; j++) {
+
+ // point-spheres
+ Vector3 sphere_pos = p_transform_a.origin + ((j == 0) ? capsule_axis : -capsule_axis);
+
+ Vector3 n1 = sphere_pos - vertex[i];
+
+ if (!separator.test_axis(n1.normalized()))
+ return;
+
+ Vector3 n2 = edge_axis;
+
+ axis = n1.cross(n2).cross(n2);
+
+ if (!separator.test_axis(axis.normalized()))
+ return;
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+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) {
+}
+
+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) {
+}
+
+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) {
+}
+
+template <bool withMargin>
+static void _collision_convex_polygon_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 ConvexPolygonShape3DSW *convex_polygon_A = static_cast<const ConvexPolygonShape3DSW *>(p_a);
+ const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b);
+
+ SeparatorAxisTest<ConvexPolygonShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(convex_polygon_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ if (!separator.test_previous_axis())
+ return;
+
+ const Geometry::MeshData &mesh_A = convex_polygon_A->get_mesh();
+
+ const Geometry::MeshData::Face *faces_A = mesh_A.faces.ptr();
+ int face_count_A = mesh_A.faces.size();
+ const Geometry::MeshData::Edge *edges_A = mesh_A.edges.ptr();
+ int edge_count_A = mesh_A.edges.size();
+ const Vector3 *vertices_A = mesh_A.vertices.ptr();
+ int vertex_count_A = mesh_A.vertices.size();
+
+ const Geometry::MeshData &mesh_B = convex_polygon_B->get_mesh();
+
+ const Geometry::MeshData::Face *faces_B = mesh_B.faces.ptr();
+ int face_count_B = mesh_B.faces.size();
+ const Geometry::MeshData::Edge *edges_B = mesh_B.edges.ptr();
+ int edge_count_B = mesh_B.edges.size();
+ const Vector3 *vertices_B = mesh_B.vertices.ptr();
+ int vertex_count_B = mesh_B.vertices.size();
+
+ // faces of A
+ for (int i = 0; i < face_count_A; i++) {
+
+ Vector3 axis = p_transform_a.xform(faces_A[i].plane).normal;
+ //Vector3 axis = p_transform_a.basis.xform( faces_A[i].plane.normal ).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // faces of B
+ for (int i = 0; i < face_count_B; i++) {
+
+ Vector3 axis = p_transform_b.xform(faces_B[i].plane).normal;
+ //Vector3 axis = p_transform_b.basis.xform( faces_B[i].plane.normal ).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+
+ // A<->B edges
+ for (int i = 0; i < edge_count_A; i++) {
+
+ Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].a]) - p_transform_a.basis.xform(vertices_A[edges_A[i].b]);
+
+ for (int j = 0; j < edge_count_B; j++) {
+
+ Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[j].a]) - p_transform_b.basis.xform(vertices_B[edges_B[j].b]);
+
+ Vector3 axis = e1.cross(e2).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+ }
+
+ if (withMargin) {
+
+ //vertex-vertex
+ for (int i = 0; i < vertex_count_A; i++) {
+
+ Vector3 va = p_transform_a.xform(vertices_A[i]);
+
+ for (int j = 0; j < vertex_count_B; j++) {
+
+ if (!separator.test_axis((va - p_transform_b.xform(vertices_B[j])).normalized()))
+ return;
+ }
+ }
+ //edge-vertex (shell)
+
+ for (int i = 0; i < edge_count_A; i++) {
+
+ Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].a]);
+ Vector3 e2 = p_transform_a.basis.xform(vertices_A[edges_A[i].b]);
+ Vector3 n = (e2 - e1);
+
+ for (int j = 0; j < vertex_count_B; j++) {
+
+ Vector3 e3 = p_transform_b.xform(vertices_B[j]);
+
+ if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized()))
+ return;
+ }
+ }
+
+ for (int i = 0; i < edge_count_B; i++) {
+
+ Vector3 e1 = p_transform_b.basis.xform(vertices_B[edges_B[i].a]);
+ Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[i].b]);
+ Vector3 n = (e2 - e1);
+
+ for (int j = 0; j < vertex_count_A; j++) {
+
+ Vector3 e3 = p_transform_a.xform(vertices_A[j]);
+
+ if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized()))
+ return;
+ }
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+template <bool withMargin>
+static void _collision_convex_polygon_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 ConvexPolygonShape3DSW *convex_polygon_A = static_cast<const ConvexPolygonShape3DSW *>(p_a);
+ const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b);
+
+ SeparatorAxisTest<ConvexPolygonShape3DSW, FaceShape3DSW, withMargin> separator(convex_polygon_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b);
+
+ const Geometry::MeshData &mesh = convex_polygon_A->get_mesh();
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int face_count = mesh.faces.size();
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int edge_count = mesh.edges.size();
+ const Vector3 *vertices = mesh.vertices.ptr();
+ int vertex_count = mesh.vertices.size();
+
+ 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]),
+ };
+
+ if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized()))
+ return;
+
+ // faces of A
+ 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 (!separator.test_axis(axis))
+ return;
+ }
+
+ // A<->B edges
+ for (int i = 0; i < edge_count; i++) {
+
+ Vector3 e1 = p_transform_a.xform(vertices[edges[i].a]) - p_transform_a.xform(vertices[edges[i].b]);
+
+ for (int j = 0; j < 3; j++) {
+
+ Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
+
+ Vector3 axis = e1.cross(e2).normalized();
+
+ if (!separator.test_axis(axis))
+ return;
+ }
+ }
+
+ if (withMargin) {
+
+ //vertex-vertex
+ for (int i = 0; i < vertex_count; i++) {
+
+ Vector3 va = p_transform_a.xform(vertices[i]);
+
+ for (int j = 0; j < 3; j++) {
+
+ if (!separator.test_axis((va - vertex[j]).normalized()))
+ return;
+ }
+ }
+ //edge-vertex (shell)
+
+ for (int i = 0; i < edge_count; i++) {
+
+ Vector3 e1 = p_transform_a.basis.xform(vertices[edges[i].a]);
+ Vector3 e2 = p_transform_a.basis.xform(vertices[edges[i].b]);
+ Vector3 n = (e2 - e1);
+
+ for (int j = 0; j < 3; j++) {
+
+ Vector3 e3 = vertex[j];
+
+ if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized()))
+ return;
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 e1 = vertex[i];
+ Vector3 e2 = vertex[(i + 1) % 3];
+ Vector3 n = (e2 - e1);
+
+ 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()))
+ return;
+ }
+ }
+ }
+
+ separator.generate_contacts();
+}
+
+bool sat_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, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) {
+
+ PhysicsServer3D::ShapeType type_A = p_shape_A->get_type();
+
+ ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_PLANE, false);
+ ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_RAY, false);
+ ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
+
+ PhysicsServer3D::ShapeType type_B = p_shape_B->get_type();
+
+ ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_PLANE, false);
+ ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_RAY, false);
+ ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
+
+ static const CollisionFunc collision_table[6][6] = {
+ { _collision_sphere_sphere<false>,
+ _collision_sphere_box<false>,
+ _collision_sphere_capsule<false>,
+ _collision_sphere_cylinder<false>,
+ _collision_sphere_convex_polygon<false>,
+ _collision_sphere_face<false> },
+ { nullptr,
+ _collision_box_box<false>,
+ _collision_box_capsule<false>,
+ _collision_box_cylinder<false>,
+ _collision_box_convex_polygon<false>,
+ _collision_box_face<false> },
+ { nullptr,
+ nullptr,
+ _collision_capsule_capsule<false>,
+ _collision_capsule_cylinder<false>,
+ _collision_capsule_convex_polygon<false>,
+ _collision_capsule_face<false> },
+ { nullptr,
+ nullptr,
+ nullptr,
+ _collision_cylinder_cylinder<false>,
+ _collision_cylinder_convex_polygon<false>,
+ _collision_cylinder_face<false> },
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ _collision_convex_polygon_convex_polygon<false>,
+ _collision_convex_polygon_face<false> },
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr },
+ };
+
+ static const CollisionFunc collision_table_margin[6][6] = {
+ { _collision_sphere_sphere<true>,
+ _collision_sphere_box<true>,
+ _collision_sphere_capsule<true>,
+ _collision_sphere_cylinder<true>,
+ _collision_sphere_convex_polygon<true>,
+ _collision_sphere_face<true> },
+ { nullptr,
+ _collision_box_box<true>,
+ _collision_box_capsule<true>,
+ _collision_box_cylinder<true>,
+ _collision_box_convex_polygon<true>,
+ _collision_box_face<true> },
+ { nullptr,
+ nullptr,
+ _collision_capsule_capsule<true>,
+ _collision_capsule_cylinder<true>,
+ _collision_capsule_convex_polygon<true>,
+ _collision_capsule_face<true> },
+ { nullptr,
+ nullptr,
+ nullptr,
+ _collision_cylinder_cylinder<true>,
+ _collision_cylinder_convex_polygon<true>,
+ _collision_cylinder_face<true> },
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ _collision_convex_polygon_convex_polygon<true>,
+ _collision_convex_polygon_face<true> },
+ { nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr },
+ };
+
+ _CollectorCallback callback;
+ callback.callback = p_result_callback;
+ callback.swap = p_swap;
+ callback.userdata = p_userdata;
+ callback.collided = false;
+ callback.prev_axis = r_prev_axis;
+
+ const Shape3DSW *A = p_shape_A;
+ const Shape3DSW *B = p_shape_B;
+ const Transform *transform_A = &p_transform_A;
+ const Transform *transform_B = &p_transform_B;
+ real_t margin_A = p_margin_a;
+ real_t margin_B = p_margin_b;
+
+ if (type_A > type_B) {
+ SWAP(A, B);
+ SWAP(transform_A, transform_B);
+ SWAP(type_A, type_B);
+ SWAP(margin_A, margin_B);
+ callback.swap = !callback.swap;
+ }
+
+ CollisionFunc collision_func;
+ if (margin_A != 0.0 || margin_B != 0.0) {
+ collision_func = collision_table_margin[type_A - 2][type_B - 2];
+
+ } else {
+ collision_func = collision_table[type_A - 2][type_B - 2];
+ }
+ ERR_FAIL_COND_V(!collision_func, false);
+
+ collision_func(A, *transform_A, B, *transform_B, &callback, margin_A, margin_B);
+
+ return callback.collided;
+}
diff --git a/servers/physics_3d/collision_solver_3d_sat.h b/servers/physics_3d/collision_solver_3d_sat.h
new file mode 100644
index 0000000000..5eccfda9ac
--- /dev/null
+++ b/servers/physics_3d/collision_solver_3d_sat.h
@@ -0,0 +1,38 @@
+/*************************************************************************/
+/* collision_solver_3d_sat.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_SOLVER_SAT_H
+#define COLLISION_SOLVER_SAT_H
+
+#include "collision_solver_3d_sw.h"
+
+bool sat_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, Vector3 *r_prev_axis = nullptr, real_t p_margin_a = 0, real_t p_margin_b = 0);
+
+#endif // COLLISION_SOLVER_SAT_H
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
new file mode 100644
index 0000000000..5d31e1f546
--- /dev/null
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -0,0 +1,372 @@
+/*************************************************************************/
+/* collision_solver_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "collision_solver_3d_sw.h"
+#include "collision_solver_3d_sat.h"
+
+#include "gjk_epa.h"
+
+#define collision_solver sat_calculate_penetration
+//#define collision_solver gjk_epa_calculate_penetration
+
+bool CollisionSolver3DSW::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) {
+
+ const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A);
+ if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE)
+ return false;
+ Plane p = p_transform_A.xform(plane->get_plane());
+
+ 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);
+
+ bool found = false;
+
+ for (int i = 0; i < support_count; i++) {
+
+ supports[i] = p_transform_B.xform(supports[i]);
+ if (p.distance_to(supports[i]) >= 0)
+ continue;
+ found = true;
+
+ Vector3 support_A = p.project(supports[i]);
+
+ if (p_result_callback) {
+ if (p_swap_result)
+ p_result_callback(supports[i], support_A, p_userdata);
+ else
+ p_result_callback(support_A, supports[i], p_userdata);
+ }
+ }
+
+ return found;
+}
+
+bool CollisionSolver3DSW::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) {
+
+ const RayShape3DSW *ray = static_cast<const RayShape3DSW *>(p_shape_A);
+
+ Vector3 from = p_transform_A.origin;
+ Vector3 to = from + p_transform_A.basis.get_axis(2) * ray->get_length();
+ Vector3 support_A = to;
+
+ Transform ai = p_transform_B.affine_inverse();
+
+ from = ai.xform(from);
+ to = ai.xform(to);
+
+ Vector3 p, n;
+ if (!p_shape_B->intersect_segment(from, to, p, n))
+ return false;
+
+ Vector3 support_B = p_transform_B.xform(p);
+ if (ray->get_slips_on_slope()) {
+ Vector3 global_n = ai.basis.xform_inv(n).normalized();
+ support_B = support_A + (support_B - support_A).length() * global_n;
+ }
+
+ if (p_result_callback) {
+ if (p_swap_result)
+ p_result_callback(support_B, support_A, p_userdata);
+ else
+ p_result_callback(support_A, support_B, p_userdata);
+ }
+ return true;
+}
+
+struct _ConcaveCollisionInfo {
+
+ const Transform *transform_A;
+ const Shape3DSW *shape_A;
+ const Transform *transform_B;
+ CollisionSolver3DSW::CallbackResult result_callback;
+ void *userdata;
+ bool swap_result;
+ bool collided;
+ int aabb_tests;
+ int collisions;
+ bool tested;
+ real_t margin_A;
+ real_t margin_B;
+ Vector3 close_A, close_B;
+};
+
+void CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex) {
+
+ _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
+ cinfo.aabb_tests++;
+
+ bool collided = collision_solver(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, cinfo.result_callback, cinfo.userdata, cinfo.swap_result, nullptr, cinfo.margin_A, cinfo.margin_B);
+ if (!collided)
+ return;
+
+ cinfo.collided = true;
+ cinfo.collisions++;
+}
+
+bool CollisionSolver3DSW::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, real_t p_margin_B) {
+
+ const ConcaveShape3DSW *concave_B = static_cast<const ConcaveShape3DSW *>(p_shape_B);
+
+ _ConcaveCollisionInfo cinfo;
+ cinfo.transform_A = &p_transform_A;
+ cinfo.shape_A = p_shape_A;
+ cinfo.transform_B = &p_transform_B;
+ cinfo.result_callback = p_result_callback;
+ cinfo.userdata = p_userdata;
+ cinfo.swap_result = p_swap_result;
+ cinfo.collided = false;
+ cinfo.collisions = 0;
+ cinfo.margin_A = p_margin_A;
+ cinfo.margin_B = p_margin_B;
+
+ cinfo.aabb_tests = 0;
+
+ Transform rel_transform = p_transform_A;
+ rel_transform.origin -= p_transform_B.origin;
+
+ //quickly compute a local AABB
+
+ AABB local_aabb;
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis(p_transform_B.basis.get_axis(i));
+ real_t axis_scale = 1.0 / axis.length();
+ axis *= axis_scale;
+
+ real_t smin, smax;
+ p_shape_A->project_range(axis, rel_transform, smin, smax);
+ smin -= p_margin_A;
+ smax += p_margin_A;
+ smin *= axis_scale;
+ smax *= axis_scale;
+
+ local_aabb.position[i] = smin;
+ local_aabb.size[i] = smax - smin;
+ }
+
+ concave_B->cull(local_aabb, concave_callback, &cinfo);
+
+ return cinfo.collided;
+}
+
+bool CollisionSolver3DSW::solve_static(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, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) {
+
+ PhysicsServer3D::ShapeType type_A = p_shape_A->get_type();
+ PhysicsServer3D::ShapeType type_B = p_shape_B->get_type();
+ bool concave_A = p_shape_A->is_concave();
+ bool concave_B = p_shape_B->is_concave();
+
+ bool swap = false;
+
+ if (type_A > type_B) {
+ SWAP(type_A, type_B);
+ SWAP(concave_A, concave_B);
+ swap = true;
+ }
+
+ if (type_A == PhysicsServer3D::SHAPE_PLANE) {
+
+ if (type_B == PhysicsServer3D::SHAPE_PLANE)
+ return false;
+ if (type_B == PhysicsServer3D::SHAPE_RAY) {
+ 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);
+ } else {
+ return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ }
+
+ } else if (type_A == PhysicsServer3D::SHAPE_RAY) {
+
+ if (type_B == PhysicsServer3D::SHAPE_RAY)
+ return false;
+
+ if (swap) {
+ return solve_ray(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ } else {
+ return solve_ray(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;
+
+ if (!swap)
+ return solve_concave(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_A, p_margin_B);
+ else
+ return solve_concave(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_A, p_margin_B);
+
+ } else {
+
+ return collision_solver(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, r_sep_axis, p_margin_A, p_margin_B);
+ }
+}
+
+void CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW *p_convex) {
+
+ _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata);
+ cinfo.aabb_tests++;
+ if (cinfo.collided)
+ return;
+
+ Vector3 close_A, close_B;
+ cinfo.collided = !gjk_epa_calculate_distance(cinfo.shape_A, *cinfo.transform_A, p_convex, *cinfo.transform_B, close_A, close_B);
+
+ if (cinfo.collided)
+ return;
+ if (!cinfo.tested || close_A.distance_squared_to(close_B) < cinfo.close_A.distance_squared_to(cinfo.close_B)) {
+
+ cinfo.close_A = close_A;
+ cinfo.close_B = close_B;
+ cinfo.tested = true;
+ }
+
+ cinfo.collisions++;
+}
+
+bool CollisionSolver3DSW::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) {
+
+ const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A);
+ if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE)
+ return false;
+ Plane p = p_transform_A.xform(plane->get_plane());
+
+ 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);
+
+ bool collided = false;
+ Vector3 closest;
+ real_t closest_d = 0;
+
+ for (int i = 0; i < support_count; i++) {
+
+ supports[i] = p_transform_B.xform(supports[i]);
+ real_t d = p.distance_to(supports[i]);
+ if (i == 0 || d < closest_d) {
+ closest = supports[i];
+ closest_d = d;
+ if (d <= 0)
+ collided = true;
+ }
+ }
+
+ r_point_A = p.project(closest);
+ r_point_B = closest;
+
+ return collided;
+}
+
+bool CollisionSolver3DSW::solve_distance(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, const AABB &p_concave_hint, Vector3 *r_sep_axis) {
+
+ if (p_shape_A->is_concave())
+ return false;
+
+ if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) {
+
+ Vector3 a, b;
+ bool col = solve_distance_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b);
+ r_point_A = b;
+ r_point_B = a;
+ return !col;
+
+ } else if (p_shape_B->is_concave()) {
+
+ if (p_shape_A->is_concave())
+ return false;
+
+ const ConcaveShape3DSW *concave_B = static_cast<const ConcaveShape3DSW *>(p_shape_B);
+
+ _ConcaveCollisionInfo cinfo;
+ cinfo.transform_A = &p_transform_A;
+ cinfo.shape_A = p_shape_A;
+ cinfo.transform_B = &p_transform_B;
+ cinfo.result_callback = nullptr;
+ cinfo.userdata = nullptr;
+ cinfo.swap_result = false;
+ cinfo.collided = false;
+ cinfo.collisions = 0;
+ cinfo.aabb_tests = 0;
+ cinfo.tested = false;
+
+ Transform rel_transform = p_transform_A;
+ rel_transform.origin -= p_transform_B.origin;
+
+ //quickly compute a local AABB
+
+ bool use_cc_hint = p_concave_hint != AABB();
+ AABB cc_hint_aabb;
+ if (use_cc_hint) {
+ cc_hint_aabb = p_concave_hint;
+ cc_hint_aabb.position -= p_transform_B.origin;
+ }
+
+ AABB local_aabb;
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis(p_transform_B.basis.get_axis(i));
+ real_t axis_scale = ((real_t)1.0) / axis.length();
+ axis *= axis_scale;
+
+ real_t smin, smax;
+
+ if (use_cc_hint) {
+ cc_hint_aabb.project_range_in_plane(Plane(axis, 0), smin, smax);
+ } else {
+ p_shape_A->project_range(axis, rel_transform, smin, smax);
+ }
+
+ smin *= axis_scale;
+ smax *= axis_scale;
+
+ local_aabb.position[i] = smin;
+ local_aabb.size[i] = smax - smin;
+ }
+
+ concave_B->cull(local_aabb, concave_distance_callback, &cinfo);
+ if (!cinfo.collided) {
+ r_point_A = cinfo.close_A;
+ r_point_B = cinfo.close_B;
+ }
+
+ return !cinfo.collided;
+ } else {
+
+ return gjk_epa_calculate_distance(p_shape_A, p_transform_A, p_shape_B, p_transform_B, r_point_A, r_point_B); //should pass sepaxis..
+ }
+}
diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h
new file mode 100644
index 0000000000..13f54ca8fb
--- /dev/null
+++ b/servers/physics_3d/collision_solver_3d_sw.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* collision_solver_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 COLLISION_SOLVER_SW_H
+#define COLLISION_SOLVER_SW_H
+
+#include "shape_3d_sw.h"
+
+class CollisionSolver3DSW {
+public:
+ typedef void (*CallbackResult)(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata);
+
+private:
+ 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_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);
+
+public:
+ static bool solve_static(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, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
+ static bool solve_distance(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, const AABB &p_concave_hint, Vector3 *r_sep_axis = nullptr);
+};
+
+#endif // COLLISION_SOLVER__SW_H
diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h
new file mode 100644
index 0000000000..5e2b00404b
--- /dev/null
+++ b/servers/physics_3d/constraint_3d_sw.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* constraint_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 CONSTRAINT_SW_H
+#define CONSTRAINT_SW_H
+
+#include "body_3d_sw.h"
+
+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;
+
+ RID self;
+
+protected:
+ Constraint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) {
+ _body_ptr = p_body_ptr;
+ _body_count = p_body_count;
+ island_step = 0;
+ priority = 1;
+ disabled_collisions_between_bodies = true;
+ }
+
+public:
+ _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ _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; }
+
+ _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
+ _FORCE_INLINE_ int get_priority() const { return priority; }
+
+ _FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; }
+ _FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
+
+ virtual bool setup(real_t p_step) = 0;
+ virtual void solve(real_t p_step) = 0;
+
+ virtual ~Constraint3DSW() {}
+};
+
+#endif // CONSTRAINT__SW_H
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
new file mode 100644
index 0000000000..db37f261ce
--- /dev/null
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -0,0 +1,946 @@
+/*************************************************************************/
+/* gjk_epa.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "gjk_epa.h"
+
+/* Disabling formatting for thirdparty code snippet */
+/* clang-format off */
+
+/*************** Bullet's GJK-EPA2 IMPLEMENTATION *******************/
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2008 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.
+*/
+
+/*
+GJK-EPA collision solver by Nathanael Presson, 2008
+*/
+
+ // Config
+
+/* GJK */
+#define GJK_MAX_ITERATIONS 128
+#define GJK_ACCURARY ((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)
+#define GJK_SIMPLEX3_EPS ((real_t)0.0)
+#define GJK_SIMPLEX4_EPS ((real_t)0.0)
+
+/* EPA */
+#define EPA_MAX_VERTICES 64
+#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
+#define EPA_MAX_ITERATIONS 255
+#define EPA_ACCURACY ((real_t)0.0001)
+#define EPA_FALLBACK (10*EPA_ACCURACY)
+#define EPA_PLANE_EPS ((real_t)0.00001)
+#define EPA_INSIDE_EPS ((real_t)0.01)
+
+namespace GjkEpa2 {
+
+
+struct sResults {
+ enum eStatus {
+ Separated, /* Shapes doesn't penetrate */
+ Penetrating, /* Shapes are penetrating */
+ GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */
+ EPA_Failed /* EPA phase fail, bigger problem, need to save parameters, and debug */
+ } status;
+
+ Vector3 witnesses[2];
+ Vector3 normal;
+ real_t distance;
+};
+
+// Shorthands
+typedef unsigned int U;
+typedef unsigned char U1;
+
+// MinkowskiDiff
+struct MinkowskiDiff {
+
+ const Shape3DSW* m_shapes[2];
+
+ Transform transform_A;
+ Transform transform_B;
+
+ // 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 Support1 ( const Vector3& d ) const {
+ return transform_B.xform( m_shapes[1]->get_support( transform_B.basis.xform_inv(d).normalized() ) );
+ }
+
+ _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 ) );
+ else
+ return ( Support0 ( d ) );
+ }
+};
+
+typedef MinkowskiDiff tShape;
+
+
+// GJK
+struct GJK
+{
+ /* Types */
+ struct sSV
+ {
+ Vector3 d,w;
+ };
+ struct sSimplex
+ {
+ sSV* c[4];
+ real_t p[4];
+ U rank;
+ };
+ struct eStatus { enum _ {
+ Valid,
+ Inside,
+ Failed };};
+ /* Fields */
+ tShape m_shape;
+ Vector3 m_ray;
+ real_t m_distance;
+ sSimplex m_simplices[2];
+ sSV m_store[4];
+ sSV* m_free[4];
+ U m_nfree;
+ U m_current;
+ sSimplex* m_simplex;
+ eStatus::_ m_status;
+ /* Methods */
+ GJK()
+ {
+ Initialize();
+ }
+ void Initialize()
+ {
+ m_ray = Vector3(0,0,0);
+ m_nfree = 0;
+ m_status = eStatus::Failed;
+ m_current = 0;
+ m_distance = 0;
+ }
+ eStatus::_ Evaluate(const tShape& shapearg,const Vector3& guess)
+ {
+ U iterations=0;
+ real_t sqdist=0;
+ real_t alpha=0;
+ Vector3 lastw[4];
+ U clastw=0;
+ /* Initialize solver */
+ m_free[0] = &m_store[0];
+ m_free[1] = &m_store[1];
+ m_free[2] = &m_store[2];
+ m_free[3] = &m_store[3];
+ m_nfree = 4;
+ m_current = 0;
+ m_status = eStatus::Valid;
+ m_shape = shapearg;
+ m_distance = 0;
+ /* Initialize simplex */
+ m_simplices[0].rank = 0;
+ m_ray = guess;
+ const real_t sqrl= m_ray.length_squared();
+ appendvertice(m_simplices[0],sqrl>0?-m_ray:Vector3(1,0,0));
+ m_simplices[0].p[0] = 1;
+ m_ray = m_simplices[0].c[0]->w;
+ sqdist = sqrl;
+ lastw[0] =
+ lastw[1] =
+ lastw[2] =
+ lastw[3] = m_ray;
+ /* Loop */
+ do {
+ const U next=1-m_current;
+ sSimplex& cs=m_simplices[m_current];
+ sSimplex& ns=m_simplices[next];
+ /* Check zero */
+ const real_t rl=m_ray.length();
+ if(rl<GJK_MIN_DISTANCE)
+ {/* Touching or inside */
+ m_status=eStatus::Inside;
+ break;
+ }
+ /* Append new vertice in -'v' direction */
+ appendvertice(cs,-m_ray);
+ const Vector3& w=cs.c[cs.rank-1]->w;
+ bool found=false;
+ for(U i=0;i<4;++i)
+ {
+ if((w-lastw[i]).length_squared()<GJK_DUPLICATED_EPS)
+ { found=true;break; }
+ }
+ if(found)
+ {/* Return old simplex */
+ removevertice(m_simplices[m_current]);
+ break;
+ }
+ else
+ {/* Update lastw */
+ lastw[clastw=(clastw+1)&3]=w;
+ }
+ /* Check for termination */
+ const real_t omega=vec3_dot(m_ray,w)/rl;
+ alpha=MAX(omega,alpha);
+ if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
+ {/* Return old simplex */
+ removevertice(m_simplices[m_current]);
+ break;
+ }
+ /* Reduce simplex */
+ real_t weights[4];
+ U mask=0;
+ switch(cs.rank)
+ {
+ case 2: sqdist=projectorigin( cs.c[0]->w,
+ cs.c[1]->w,
+ weights,mask);break;
+ case 3: sqdist=projectorigin( cs.c[0]->w,
+ cs.c[1]->w,
+ cs.c[2]->w,
+ weights,mask);break;
+ case 4: sqdist=projectorigin( cs.c[0]->w,
+ cs.c[1]->w,
+ cs.c[2]->w,
+ cs.c[3]->w,
+ weights,mask);break;
+ }
+ if(sqdist>=0)
+ {/* Valid */
+ ns.rank = 0;
+ m_ray = Vector3(0,0,0);
+ m_current = next;
+ for(U i=0,ni=cs.rank;i<ni;++i)
+ {
+ if(mask&(1<<i))
+ {
+ ns.c[ns.rank] = cs.c[i];
+ ns.p[ns.rank++] = weights[i];
+ m_ray += cs.c[i]->w*weights[i];
+ }
+ else
+ {
+ m_free[m_nfree++] = cs.c[i];
+ }
+ }
+ if(mask==15) m_status=eStatus::Inside;
+ }
+ else
+ {/* Return old simplex */
+ removevertice(m_simplices[m_current]);
+ break;
+ }
+ m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eStatus::Failed;
+ } while(m_status==eStatus::Valid);
+ m_simplex=&m_simplices[m_current];
+ switch(m_status)
+ {
+ case eStatus::Valid: m_distance=m_ray.length();break;
+ case eStatus::Inside: m_distance=0;break;
+ default: {}
+ }
+ return(m_status);
+ }
+ bool EncloseOrigin()
+ {
+ switch(m_simplex->rank)
+ {
+ case 1:
+ {
+ for(U i=0;i<3;++i)
+ {
+ Vector3 axis=Vector3(0,0,0);
+ axis[i]=1;
+ appendvertice(*m_simplex, axis);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ appendvertice(*m_simplex,-axis);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ }
+ }
+ break;
+ case 2:
+ {
+ const Vector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w;
+ for(U i=0;i<3;++i)
+ {
+ Vector3 axis=Vector3(0,0,0);
+ axis[i]=1;
+ const Vector3 p=vec3_cross(d,axis);
+ if(p.length_squared()>0)
+ {
+ appendvertice(*m_simplex, p);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ appendvertice(*m_simplex,-p);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ }
+ }
+ }
+ break;
+ case 3:
+ {
+ const Vector3 n=vec3_cross(m_simplex->c[1]->w-m_simplex->c[0]->w,
+ m_simplex->c[2]->w-m_simplex->c[0]->w);
+ if(n.length_squared()>0)
+ {
+ appendvertice(*m_simplex,n);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ appendvertice(*m_simplex,-n);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ }
+ }
+ break;
+ case 4:
+ {
+ if(Math::abs(det( m_simplex->c[0]->w-m_simplex->c[3]->w,
+ m_simplex->c[1]->w-m_simplex->c[3]->w,
+ m_simplex->c[2]->w-m_simplex->c[3]->w))>0)
+ return(true);
+ }
+ break;
+ }
+ return(false);
+ }
+ /* Internals */
+ void getsupport(const Vector3& d,sSV& sv) const
+ {
+ sv.d = d/d.length();
+ sv.w = m_shape.Support(sv.d);
+ }
+ void removevertice(sSimplex& simplex)
+ {
+ m_free[m_nfree++]=simplex.c[--simplex.rank];
+ }
+ void appendvertice(sSimplex& simplex,const Vector3& v)
+ {
+ simplex.p[simplex.rank]=0;
+ simplex.c[simplex.rank]=m_free[--m_nfree];
+ getsupport(v,*simplex.c[simplex.rank++]);
+ }
+ static real_t det(const Vector3& a,const Vector3& b,const Vector3& c)
+ {
+ return( a.y*b.z*c.x+a.z*b.x*c.y-
+ a.x*b.z*c.y-a.y*b.x*c.z+
+ a.x*b.y*c.z-a.z*b.y*c.x);
+ }
+ static real_t projectorigin( const Vector3& a,
+ const Vector3& b,
+ real_t* w,U& m)
+ {
+ const Vector3 d=b-a;
+ const real_t l=d.length_squared();
+ if(l>GJK_SIMPLEX2_EPS)
+ {
+ const real_t t(l>0?-vec3_dot(a,d)/l:0);
+ if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length_squared()); }
+ else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length_squared()); }
+ else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length_squared()); }
+ }
+ return(-1);
+ }
+ static real_t projectorigin( const Vector3& a,
+ const Vector3& b,
+ const Vector3& c,
+ real_t* w,U& m)
+ {
+ static const U imd3[]={1,2,0};
+ const Vector3* vt[]={&a,&b,&c};
+ const Vector3 dl[]={a-b,b-c,c-a};
+ const Vector3 n=vec3_cross(dl[0],dl[1]);
+ const real_t l=n.length_squared();
+ if(l>GJK_SIMPLEX3_EPS)
+ {
+ real_t mindist=-1;
+ real_t subw[2] = { 0 , 0};
+ U subm = 0;
+ for(U i=0;i<3;++i)
+ {
+ if(vec3_dot(*vt[i],vec3_cross(dl[i],n))>0)
+ {
+ const U j=imd3[i];
+ const real_t subd(projectorigin(*vt[i],*vt[j],subw,subm));
+ if((mindist<0)||(subd<mindist))
+ {
+ mindist = subd;
+ m = static_cast<U>(((subm&1)?1<<i:0)+((subm&2)?1<<j:0));
+ w[i] = subw[0];
+ w[j] = subw[1];
+ w[imd3[j]] = 0;
+ }
+ }
+ }
+ if(mindist<0)
+ {
+ const real_t d=vec3_dot(a,n);
+ const real_t s=Math::sqrt(l);
+ const Vector3 p=n*(d/l);
+ mindist = p.length_squared();
+ m = 7;
+ w[0] = (vec3_cross(dl[1],b-p)).length()/s;
+ w[1] = (vec3_cross(dl[2],c-p)).length()/s;
+ w[2] = 1-(w[0]+w[1]);
+ }
+ return(mindist);
+ }
+ return(-1);
+ }
+ static real_t projectorigin( const Vector3& a,
+ const Vector3& b,
+ const Vector3& c,
+ const Vector3& d,
+ real_t* w,U& m)
+ {
+ static const U imd3[]={1,2,0};
+ const Vector3* vt[]={&a,&b,&c,&d};
+ const Vector3 dl[]={a-d,b-d,c-d};
+ const real_t vl=det(dl[0],dl[1],dl[2]);
+ const bool ng=(vl*vec3_dot(a,vec3_cross(b-c,a-b)))<=0;
+ if(ng&&(Math::abs(vl)>GJK_SIMPLEX4_EPS))
+ {
+ real_t mindist=-1;
+ real_t subw[3];
+ U subm=0;
+ for(U i=0;i<3;++i)
+ {
+ const U j=imd3[i];
+ const real_t s=vl*vec3_dot(d,vec3_cross(dl[i],dl[j]));
+ if(s>0)
+ {
+ const real_t subd=projectorigin(*vt[i],*vt[j],d,subw,subm);
+ if((mindist<0)||(subd<mindist))
+ {
+ mindist = subd;
+ m = static_cast<U>((subm&1?1<<i:0)+
+ (subm&2?1<<j:0)+
+ (subm&4?8:0));
+ w[i] = subw[0];
+ w[j] = subw[1];
+ w[imd3[j]] = 0;
+ w[3] = subw[2];
+ }
+ }
+ }
+ if(mindist<0)
+ {
+ mindist = 0;
+ m = 15;
+ w[0] = det(c,b,d)/vl;
+ w[1] = det(a,c,d)/vl;
+ w[2] = det(b,a,d)/vl;
+ w[3] = 1-(w[0]+w[1]+w[2]);
+ }
+ return(mindist);
+ }
+ return(-1);
+ }
+};
+
+ // EPA
+ struct EPA
+ {
+ /* Types */
+ typedef GJK::sSV sSV;
+ struct sFace
+ {
+ Vector3 n;
+ real_t d;
+ real_t p;
+ sSV* c[3];
+ sFace* f[3];
+ sFace* l[2];
+ U1 e[3];
+ U1 pass;
+ };
+ struct sList
+ {
+ sFace* root;
+ U count;
+ sList() : root(nullptr),count(0) {}
+ };
+ struct sHorizon
+ {
+ sFace* cf;
+ sFace* ff;
+ U nf;
+ sHorizon() : cf(nullptr),ff(nullptr),nf(0) {}
+ };
+ struct eStatus { enum _ {
+ Valid,
+ Touching,
+ Degenerated,
+ NonConvex,
+ InvalidHull,
+ OutOfFaces,
+ OutOfVertices,
+ AccuraryReached,
+ FallBack,
+ Failed };};
+ /* Fields */
+ eStatus::_ m_status;
+ GJK::sSimplex m_result;
+ Vector3 m_normal;
+ real_t m_depth;
+ sSV m_sv_store[EPA_MAX_VERTICES];
+ sFace m_fc_store[EPA_MAX_FACES];
+ U m_nextsv;
+ sList m_hull;
+ sList m_stock;
+ /* Methods */
+ EPA()
+ {
+ Initialize();
+ }
+
+
+ static inline void bind(sFace* fa,U ea,sFace* fb,U eb)
+ {
+ fa->e[ea]=(U1)eb;fa->f[ea]=fb;
+ fb->e[eb]=(U1)ea;fb->f[eb]=fa;
+ }
+ static inline void append(sList& list,sFace* face)
+ {
+ face->l[0] = nullptr;
+ face->l[1] = list.root;
+ if(list.root) list.root->l[0]=face;
+ list.root = face;
+ ++list.count;
+ }
+ static inline void remove(sList& list,sFace* face)
+ {
+ if(face->l[1]) face->l[1]->l[0]=face->l[0];
+ if(face->l[0]) face->l[0]->l[1]=face->l[1];
+ if(face==list.root) list.root=face->l[1];
+ --list.count;
+ }
+
+
+ void Initialize()
+ {
+ m_status = eStatus::Failed;
+ m_normal = Vector3(0,0,0);
+ m_depth = 0;
+ m_nextsv = 0;
+ for(U i=0;i<EPA_MAX_FACES;++i)
+ {
+ append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);
+ }
+ }
+ eStatus::_ Evaluate(GJK& gjk,const Vector3& guess)
+ {
+ GJK::sSimplex& simplex=*gjk.m_simplex;
+ if((simplex.rank>1)&&gjk.EncloseOrigin())
+ {
+
+ /* Clean up */
+ while(m_hull.root)
+ {
+ sFace* f = m_hull.root;
+ remove(m_hull,f);
+ append(m_stock,f);
+ }
+ m_status = eStatus::Valid;
+ m_nextsv = 0;
+ /* Orient simplex */
+ if(gjk.det( simplex.c[0]->w-simplex.c[3]->w,
+ simplex.c[1]->w-simplex.c[3]->w,
+ simplex.c[2]->w-simplex.c[3]->w)<0)
+ {
+ SWAP(simplex.c[0],simplex.c[1]);
+ SWAP(simplex.p[0],simplex.p[1]);
+ }
+ /* Build initial hull */
+ sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),
+ newface(simplex.c[1],simplex.c[0],simplex.c[3],true),
+ newface(simplex.c[2],simplex.c[1],simplex.c[3],true),
+ newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};
+ if(m_hull.count==4)
+ {
+ sFace* best=findbest();
+ sFace outer=*best;
+ U pass=0;
+ U iterations=0;
+ bind(tetra[0],0,tetra[1],0);
+ bind(tetra[0],1,tetra[2],0);
+ bind(tetra[0],2,tetra[3],0);
+ bind(tetra[1],1,tetra[3],2);
+ bind(tetra[1],2,tetra[2],1);
+ bind(tetra[2],2,tetra[3],1);
+ m_status=eStatus::Valid;
+ for(;iterations<EPA_MAX_ITERATIONS;++iterations)
+ {
+ if(m_nextsv<EPA_MAX_VERTICES)
+ {
+ sHorizon horizon;
+ sSV* w=&m_sv_store[m_nextsv++];
+ bool valid=true;
+ best->pass = (U1)(++pass);
+ gjk.getsupport(best->n,*w);
+ const real_t wdist=vec3_dot(best->n,w->w)-best->d;
+ if(wdist>EPA_ACCURACY)
+ {
+ for(U j=0;(j<3)&&valid;++j)
+ {
+ valid&=expand( pass,w,
+ best->f[j],best->e[j],
+ horizon);
+ }
+ if(valid&&(horizon.nf>=3))
+ {
+ bind(horizon.cf,1,horizon.ff,2);
+ remove(m_hull,best);
+ append(m_stock,best);
+ best=findbest();
+ if(best->p>=outer.p) outer=*best;
+ } else { m_status=eStatus::InvalidHull;break; }
+ } else { m_status=eStatus::AccuraryReached;break; }
+ } else { m_status=eStatus::OutOfVertices;break; }
+ }
+ const Vector3 projection=outer.n*outer.d;
+ m_normal = outer.n;
+ m_depth = outer.d;
+ m_result.rank = 3;
+ m_result.c[0] = outer.c[0];
+ m_result.c[1] = outer.c[1];
+ m_result.c[2] = outer.c[2];
+ m_result.p[0] = vec3_cross( outer.c[1]->w-projection,
+ outer.c[2]->w-projection).length();
+ m_result.p[1] = vec3_cross( outer.c[2]->w-projection,
+ outer.c[0]->w-projection).length();
+ m_result.p[2] = vec3_cross( outer.c[0]->w-projection,
+ outer.c[1]->w-projection).length();
+ const real_t sum=m_result.p[0]+m_result.p[1]+m_result.p[2];
+ m_result.p[0] /= sum;
+ m_result.p[1] /= sum;
+ m_result.p[2] /= sum;
+ return(m_status);
+ }
+ }
+ /* Fallback */
+ 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_depth = 0;
+ m_result.rank=1;
+ m_result.c[0]=simplex.c[0];
+ m_result.p[0]=1;
+ return(m_status);
+ }
+ sFace* newface(sSV* a,sSV* b,sSV* c,bool forced)
+ {
+ if(m_stock.root)
+ {
+ sFace* face=m_stock.root;
+ remove(m_stock,face);
+ append(m_hull,face);
+ face->pass = 0;
+ face->c[0] = a;
+ face->c[1] = b;
+ face->c[2] = c;
+ 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;
+ face->n /= l;
+ if(forced||(face->d>=-EPA_PLANE_EPS))
+ {
+ return(face);
+ } else m_status=eStatus::NonConvex;
+ } else m_status=eStatus::Degenerated;
+ remove(m_hull,face);
+ append(m_stock,face);
+ return(nullptr);
+ }
+ // -- GODOT start --
+ //m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces;
+ m_status=eStatus::OutOfFaces;
+ // -- GODOT end --
+ return(nullptr);
+ }
+ sFace* findbest()
+ {
+ 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))
+ {
+ minf=f;
+ mind=sqd;
+ maxp=f->p;
+ }
+ }
+ return(minf);
+ }
+ bool expand(U pass,sSV* w,sFace* f,U e,sHorizon& horizon)
+ {
+ static const U i1m3[]={1,2,0};
+ static const U i2m3[]={2,0,1};
+ if(f->pass!=pass)
+ {
+ const U e1=i1m3[e];
+ if((vec3_dot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)
+ {
+ sFace* nf=newface(f->c[e1],f->c[e],w,false);
+ if(nf)
+ {
+ bind(nf,0,f,e);
+ if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf;
+ horizon.cf=nf;
+ ++horizon.nf;
+ return(true);
+ }
+ }
+ else
+ {
+ const U e2=i2m3[e];
+ f->pass = (U1)pass;
+ if( expand(pass,w,f->f[e1],f->e[e1],horizon)&&
+ expand(pass,w,f->f[e2],f->e[e2],horizon))
+ {
+ remove(m_hull,f);
+ append(m_stock,f);
+ return(true);
+ }
+ }
+ }
+ return(false);
+ }
+
+ };
+
+ //
+ static void Initialize( const Shape3DSW* shape0,const Transform& wtrs0,
+ const Shape3DSW* shape1,const Transform& wtrs1,
+ sResults& results,
+ tShape& shape,
+ bool withmargins)
+ {
+ /* Results */
+ results.witnesses[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;
+
+ }
+
+
+
+//
+// Api
+//
+
+//
+
+//
+bool Distance( const Shape3DSW* shape0,
+ const Transform& wtrs0,
+ const Shape3DSW* shape1,
+ const Transform& wtrs1,
+ const Vector3& guess,
+ sResults& results)
+{
+ tShape shape;
+ Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ GJK gjk;
+ GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess);
+ if(gjk_status==GJK::eStatus::Valid)
+ {
+ Vector3 w0=Vector3(0,0,0);
+ Vector3 w1=Vector3(0,0,0);
+ for(U i=0;i<gjk.m_simplex->rank;++i)
+ {
+ const real_t p=gjk.m_simplex->p[i];
+ w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
+ w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
+ }
+ results.witnesses[0] = w0;
+ results.witnesses[1] = w1;
+ results.normal = w0-w1;
+ results.distance = results.normal.length();
+ results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1;
+ return(true);
+ }
+ else
+ {
+ results.status = gjk_status==GJK::eStatus::Inside?
+ sResults::Penetrating :
+ sResults::GJK_Failed ;
+ return(false);
+ }
+}
+
+//
+bool Penetration( const Shape3DSW* shape0,
+ const Transform& wtrs0,
+ const Shape3DSW* shape1,
+ const Transform& wtrs1,
+ const Vector3& guess,
+ sResults& results
+ )
+{
+ tShape shape;
+ Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
+ GJK gjk;
+ GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
+ switch(gjk_status)
+ {
+ case GJK::eStatus::Inside:
+ {
+ EPA epa;
+ EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess);
+ if(epa_status!=EPA::eStatus::Failed)
+ {
+ Vector3 w0=Vector3(0,0,0);
+ for(U i=0;i<epa.m_result.rank;++i)
+ {
+ w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];
+ }
+ results.status = sResults::Penetrating;
+ results.witnesses[0] = w0;
+ results.witnesses[1] = w0-epa.m_normal*epa.m_depth;
+ results.normal = -epa.m_normal;
+ results.distance = -epa.m_depth;
+ return(true);
+ } else results.status=sResults::EPA_Failed;
+ }
+ break;
+ case GJK::eStatus::Failed:
+ results.status=sResults::GJK_Failed;
+ break;
+ default: {}
+ }
+ return(false);
+}
+
+
+/* Symbols cleanup */
+
+#undef GJK_MAX_ITERATIONS
+#undef GJK_ACCURARY
+#undef GJK_MIN_DISTANCE
+#undef GJK_DUPLICATED_EPS
+#undef GJK_SIMPLEX2_EPS
+#undef GJK_SIMPLEX3_EPS
+#undef GJK_SIMPLEX4_EPS
+
+#undef EPA_MAX_VERTICES
+#undef EPA_MAX_FACES
+#undef EPA_MAX_ITERATIONS
+#undef EPA_ACCURACY
+#undef EPA_FALLBACK
+#undef EPA_PLANE_EPS
+#undef EPA_INSIDE_EPS
+
+
+} // end of namespace
+
+/* clang-format on */
+
+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)) {
+
+ r_result_A = res.witnesses[0];
+ r_result_B = res.witnesses[1];
+ return true;
+ }
+
+ 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) {
+
+ 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 (p_result_callback) {
+ if (p_swap)
+ p_result_callback(res.witnesses[1], res.witnesses[0], p_userdata);
+ else
+ p_result_callback(res.witnesses[0], res.witnesses[1], p_userdata);
+ }
+ return true;
+ }
+
+ return false;
+}
diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h
new file mode 100644
index 0000000000..dec0f269e1
--- /dev/null
+++ b/servers/physics_3d/gjk_epa.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* gjk_epa.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 GJK_EPA_H
+#define GJK_EPA_H
+
+#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_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/SCsub b/servers/physics_3d/joints/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/physics_3d/joints/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
new file mode 100644
index 0000000000..a072c1f3a0
--- /dev/null
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
@@ -0,0 +1,366 @@
+/*************************************************************************/
+/* cone_twist_joint_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
+
+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.
+
+Written by: Marcus Hennix
+*/
+
+#include "cone_twist_joint_3d_sw.h"
+
+static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
+
+ if (Math::abs(n.z) > Math_SQRT12) {
+ // choose p in y-z plane
+ real_t a = n[1] * n[1] + n[2] * n[2];
+ real_t k = 1.0 / Math::sqrt(a);
+ p = Vector3(0, -n[2] * k, n[1] * k);
+ // set q = n x p
+ q = Vector3(a * k, -n[0] * p[2], n[0] * p[1]);
+ } else {
+ // choose p in x-y plane
+ real_t a = n.x * n.x + n.y * n.y;
+ real_t k = 1.0 / Math::sqrt(a);
+ p = Vector3(-n.y * k, n.x * k, 0);
+ // set q = n x p
+ q = Vector3(-n.z * p.y, n.z * p.x, a * k);
+ }
+}
+
+static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
+ real_t coeff_1 = Math_PI / 4.0f;
+ real_t coeff_2 = 3.0f * coeff_1;
+ real_t abs_y = Math::abs(y);
+ real_t angle;
+ if (x >= 0.0f) {
+ real_t r = (x - abs_y) / (x + abs_y);
+ angle = coeff_1 - coeff_1 * r;
+ } else {
+ real_t r = (x + abs_y) / (abs_y - x);
+ angle = coeff_2 - coeff_1 * r;
+ }
+ return (y < 0.0f) ? -angle : angle;
+}
+
+ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame) :
+ Joint3DSW(_arr, 2) {
+
+ A = rbA;
+ B = rbB;
+
+ m_rbAFrame = rbAFrame;
+ m_rbBFrame = rbBFrame;
+
+ m_swingSpan1 = Math_PI / 4.0;
+ m_swingSpan2 = Math_PI / 4.0;
+ m_twistSpan = Math_PI * 2;
+ m_biasFactor = 0.3f;
+ m_relaxationFactor = 1.0f;
+
+ m_angularOnly = false;
+ m_solveTwistLimit = false;
+ m_solveSwingLimit = false;
+
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+
+ m_appliedImpulse = 0;
+}
+
+bool ConeTwistJoint3DSW::setup(real_t p_timestep) {
+ m_appliedImpulse = real_t(0.);
+
+ //set bias, sign, clear accumulator
+ m_swingCorrection = real_t(0.);
+ m_twistLimitSign = real_t(0.);
+ m_solveTwistLimit = false;
+ m_solveSwingLimit = false;
+ m_accTwistLimitImpulse = real_t(0.);
+ m_accSwingLimitImpulse = real_t(0.);
+
+ if (!m_angularOnly) {
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+ Vector3 relPos = pivotBInW - pivotAInW;
+
+ Vector3 normal[3];
+ if (Math::is_zero_approx(relPos.length_squared())) {
+ normal[0] = Vector3(real_t(1.0), 0, 0);
+ } else {
+ normal[0] = relPos.normalized();
+ }
+
+ plane_space(normal[0], normal[1], normal[2]);
+
+ for (int i = 0; i < 3; i++) {
+ memnew_placement(&m_jac[i], JacobianEntry3DSW(
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
+ pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
+ normal[i],
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+ }
+ }
+
+ Vector3 b1Axis1, b1Axis2, b1Axis3;
+ Vector3 b2Axis1, b2Axis2;
+
+ b1Axis1 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(0));
+ b2Axis1 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(0));
+
+ real_t swing1 = real_t(0.), swing2 = real_t(0.);
+
+ real_t swx = real_t(0.), swy = real_t(0.);
+ real_t thresh = real_t(10.);
+ real_t fact;
+
+ // Get Frame into world space
+ if (m_swingSpan1 >= real_t(0.05f)) {
+ b1Axis2 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(1));
+ //swing1 = btAtan2Fast( b2Axis1.dot(b1Axis2),b2Axis1.dot(b1Axis1) );
+ swx = b2Axis1.dot(b1Axis1);
+ swy = b2Axis1.dot(b1Axis2);
+ swing1 = atan2fast(swy, swx);
+ fact = (swy * swy + swx * swx) * thresh * thresh;
+ fact = fact / (fact + real_t(1.0));
+ swing1 *= fact;
+ }
+
+ if (m_swingSpan2 >= real_t(0.05f)) {
+ b1Axis3 = A->get_transform().basis.xform(this->m_rbAFrame.basis.get_axis(2));
+ //swing2 = btAtan2Fast( b2Axis1.dot(b1Axis3),b2Axis1.dot(b1Axis1) );
+ swx = b2Axis1.dot(b1Axis1);
+ swy = b2Axis1.dot(b1Axis3);
+ swing2 = atan2fast(swy, swx);
+ fact = (swy * swy + swx * swx) * thresh * thresh;
+ fact = fact / (fact + real_t(1.0));
+ swing2 *= fact;
+ }
+
+ real_t RMaxAngle1Sq = 1.0f / (m_swingSpan1 * m_swingSpan1);
+ real_t RMaxAngle2Sq = 1.0f / (m_swingSpan2 * m_swingSpan2);
+ real_t EllipseAngle = Math::abs(swing1 * swing1) * RMaxAngle1Sq + Math::abs(swing2 * swing2) * RMaxAngle2Sq;
+
+ if (EllipseAngle > 1.0f) {
+ m_swingCorrection = EllipseAngle - 1.0f;
+ m_solveSwingLimit = true;
+
+ // Calculate necessary axis & factors
+ m_swingAxis = b2Axis1.cross(b1Axis2 * b2Axis1.dot(b1Axis2) + b1Axis3 * b2Axis1.dot(b1Axis3));
+ m_swingAxis.normalize();
+
+ real_t swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f;
+ m_swingAxis *= swingAxisSign;
+
+ m_kSwing = real_t(1.) / (A->compute_angular_impulse_denominator(m_swingAxis) +
+ B->compute_angular_impulse_denominator(m_swingAxis));
+ }
+
+ // Twist limits
+ if (m_twistSpan >= real_t(0.)) {
+ Vector3 b2Axis22 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(1));
+ Quat rotationArc = Quat(b2Axis1, b1Axis1);
+ Vector3 TwistRef = rotationArc.xform(b2Axis22);
+ real_t twist = atan2fast(TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2));
+
+ real_t lockedFreeFactor = (m_twistSpan > real_t(0.05f)) ? m_limitSoftness : real_t(0.);
+ if (twist <= -m_twistSpan * lockedFreeFactor) {
+ m_twistCorrection = -(twist + m_twistSpan);
+ m_solveTwistLimit = true;
+
+ m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
+ m_twistAxis.normalize();
+ m_twistAxis *= -1.0f;
+
+ m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) +
+ B->compute_angular_impulse_denominator(m_twistAxis));
+
+ } else if (twist > m_twistSpan * lockedFreeFactor) {
+ m_twistCorrection = (twist - m_twistSpan);
+ m_solveTwistLimit = true;
+
+ m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
+ m_twistAxis.normalize();
+
+ m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) +
+ B->compute_angular_impulse_denominator(m_twistAxis));
+ }
+ }
+
+ return true;
+}
+
+void ConeTwistJoint3DSW::solve(real_t p_timestep) {
+
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+
+ real_t tau = real_t(0.3);
+
+ //linear part
+ if (!m_angularOnly) {
+ Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+
+ Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ for (int i = 0; i < 3; i++) {
+ const Vector3 &normal = m_jac[i].m_linearJointAxis;
+ real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
+
+ real_t rel_vel;
+ rel_vel = normal.dot(vel);
+ //positional error (zeroth order error)
+ real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
+ real_t impulse = depth * tau / p_timestep * jacDiagABInv - rel_vel * jacDiagABInv;
+ m_appliedImpulse += impulse;
+ Vector3 impulse_vector = normal * impulse;
+ A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
+ B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
+ }
+ }
+
+ {
+ ///solve angular part
+ const Vector3 &angVelA = A->get_angular_velocity();
+ const Vector3 &angVelB = B->get_angular_velocity();
+
+ // solve swing limit
+ if (m_solveSwingLimit) {
+ real_t amplitude = ((angVelB - angVelA).dot(m_swingAxis) * m_relaxationFactor * m_relaxationFactor + m_swingCorrection * (real_t(1.) / p_timestep) * m_biasFactor);
+ real_t impulseMag = amplitude * m_kSwing;
+
+ // Clamp the accumulated impulse
+ real_t temp = m_accSwingLimitImpulse;
+ m_accSwingLimitImpulse = MAX(m_accSwingLimitImpulse + impulseMag, real_t(0.0));
+ impulseMag = m_accSwingLimitImpulse - temp;
+
+ Vector3 impulse = m_swingAxis * impulseMag;
+
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+ }
+
+ // solve twist limit
+ if (m_solveTwistLimit) {
+ real_t amplitude = ((angVelB - angVelA).dot(m_twistAxis) * m_relaxationFactor * m_relaxationFactor + m_twistCorrection * (real_t(1.) / p_timestep) * m_biasFactor);
+ real_t impulseMag = amplitude * m_kTwist;
+
+ // Clamp the accumulated impulse
+ real_t temp = m_accTwistLimitImpulse;
+ m_accTwistLimitImpulse = MAX(m_accTwistLimitImpulse + impulseMag, real_t(0.0));
+ impulseMag = m_accTwistLimitImpulse - temp;
+
+ Vector3 impulse = m_twistAxis * impulseMag;
+
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+ }
+ }
+}
+
+void ConeTwistJoint3DSW::set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value) {
+
+ switch (p_param) {
+ case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {
+
+ m_swingSpan1 = p_value;
+ m_swingSpan2 = p_value;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {
+
+ m_twistSpan = p_value;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {
+
+ m_biasFactor = p_value;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {
+
+ m_limitSoftness = p_value;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {
+
+ m_relaxationFactor = p_value;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_MAX: break; // Can't happen, but silences warning
+ }
+}
+
+real_t ConeTwistJoint3DSW::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const {
+
+ switch (p_param) {
+ case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: {
+
+ return m_swingSpan1;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN: {
+
+ return m_twistSpan;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_BIAS: {
+
+ return m_biasFactor;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS: {
+
+ return m_limitSoftness;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION: {
+
+ return m_relaxationFactor;
+ } break;
+ case PhysicsServer3D::CONE_TWIST_MAX: break; // Can't happen, but silences warning
+ }
+
+ return 0;
+}
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
new file mode 100644
index 0000000000..c713d8cf17
--- /dev/null
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
@@ -0,0 +1,142 @@
+/*************************************************************************/
+/* cone_twist_joint_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios
+
+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.
+
+Written by: Marcus Hennix
+*/
+
+#ifndef CONE_TWIST_JOINT_SW_H
+#define CONE_TWIST_JOINT_SW_H
+
+#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h"
+#include "servers/physics_3d/joints_3d_sw.h"
+
+///ConeTwistJointSW can be used to simulate ragdoll joints (upper arm, leg etc)
+class ConeTwistJoint3DSW : public Joint3DSW {
+#ifdef IN_PARALLELL_SOLVER
+public:
+#endif
+
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints
+
+ real_t m_appliedImpulse;
+ Transform m_rbAFrame;
+ Transform m_rbBFrame;
+
+ real_t m_limitSoftness;
+ real_t m_biasFactor;
+ real_t m_relaxationFactor;
+
+ real_t m_swingSpan1;
+ real_t m_swingSpan2;
+ real_t m_twistSpan;
+
+ Vector3 m_swingAxis;
+ Vector3 m_twistAxis;
+
+ real_t m_kSwing;
+ real_t m_kTwist;
+
+ real_t m_twistLimitSign;
+ real_t m_swingCorrection;
+ real_t m_twistCorrection;
+
+ real_t m_accSwingLimitImpulse;
+ real_t m_accTwistLimitImpulse;
+
+ bool m_angularOnly;
+ bool m_solveTwistLimit;
+ bool m_solveSwingLimit;
+
+public:
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; }
+
+ virtual bool setup(real_t p_timestep);
+ virtual void solve(real_t p_timestep);
+
+ ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
+
+ void setAngularOnly(bool angularOnly) {
+ m_angularOnly = angularOnly;
+ }
+
+ void setLimit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f) {
+ m_swingSpan1 = _swingSpan1;
+ m_swingSpan2 = _swingSpan2;
+ m_twistSpan = _twistSpan;
+
+ m_limitSoftness = _softness;
+ m_biasFactor = _biasFactor;
+ m_relaxationFactor = _relaxationFactor;
+ }
+
+ inline int getSolveTwistLimit() {
+ return m_solveTwistLimit;
+ }
+
+ inline int getSolveSwingLimit() {
+ return m_solveTwistLimit;
+ }
+
+ inline real_t getTwistLimitSign() {
+ return m_twistLimitSign;
+ }
+
+ void set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::ConeTwistJointParam p_param) const;
+};
+
+#endif // CONE_TWIST_JOINT_SW_H
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
new file mode 100644
index 0000000000..e15aeca842
--- /dev/null
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -0,0 +1,686 @@
+/*************************************************************************/
+/* generic_6dof_joint_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+/*
+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.
+*/
+
+/*
+2007-09-09
+Generic6DOFJointSW Refactored by Francisco Le?n
+email: projectileman@yahoo.com
+http://gimpact.sf.net
+*/
+
+#include "generic_6dof_joint_3d_sw.h"
+
+#define GENERIC_D6_DISABLE_WARMSTARTING 1
+
+//////////////////////////// G6DOFRotationalLimitMotorSW ////////////////////////////////////
+
+int G6DOFRotationalLimitMotor3DSW::testLimitValue(real_t test_value) {
+ if (m_loLimit > m_hiLimit) {
+ m_currentLimit = 0; //Free from violation
+ return 0;
+ }
+
+ if (test_value < m_loLimit) {
+ m_currentLimit = 1; //low limit violation
+ m_currentLimitError = test_value - m_loLimit;
+ return 1;
+ } else if (test_value > m_hiLimit) {
+ m_currentLimit = 2; //High limit violation
+ m_currentLimitError = test_value - m_hiLimit;
+ return 2;
+ };
+
+ m_currentLimit = 0; //Free from violation
+ return 0;
+}
+
+real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits(
+ real_t timeStep, Vector3 &axis, real_t jacDiagABInv,
+ Body3DSW *body0, Body3DSW *body1) {
+ if (!needApplyTorques()) return 0.0f;
+
+ real_t target_velocity = m_targetVelocity;
+ real_t maxMotorForce = m_maxMotorForce;
+
+ //current error correction
+ if (m_currentLimit != 0) {
+ target_velocity = -m_ERP * m_currentLimitError / (timeStep);
+ maxMotorForce = m_maxLimitForce;
+ }
+
+ maxMotorForce *= timeStep;
+
+ // current velocity difference
+ Vector3 vel_diff = body0->get_angular_velocity();
+ if (body1) {
+ vel_diff -= body1->get_angular_velocity();
+ }
+
+ real_t rel_vel = axis.dot(vel_diff);
+
+ // correction velocity
+ real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
+
+ if (Math::is_zero_approx(motor_relvel)) {
+ return 0.0f; //no need for applying force
+ }
+
+ // correction impulse
+ real_t unclippedMotorImpulse = (1 + m_bounce) * motor_relvel * jacDiagABInv;
+
+ // clip correction impulse
+ real_t clippedMotorImpulse;
+
+ ///@todo: should clip against accumulated impulse
+ if (unclippedMotorImpulse > 0.0f) {
+ clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce ? maxMotorForce : unclippedMotorImpulse;
+ } else {
+ clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce : unclippedMotorImpulse;
+ }
+
+ // sort with accumulated impulses
+ real_t lo = real_t(-1e30);
+ real_t hi = real_t(1e30);
+
+ real_t oldaccumImpulse = m_accumulatedImpulse;
+ real_t sum = oldaccumImpulse + clippedMotorImpulse;
+ m_accumulatedImpulse = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum;
+
+ clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
+
+ Vector3 motorImp = clippedMotorImpulse * axis;
+
+ body0->apply_torque_impulse(motorImp);
+ if (body1) body1->apply_torque_impulse(-motorImp);
+
+ return clippedMotorImpulse;
+}
+
+//////////////////////////// End G6DOFRotationalLimitMotorSW ////////////////////////////////////
+
+//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
+real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis(
+ real_t timeStep,
+ real_t jacDiagABInv,
+ Body3DSW *body1, const Vector3 &pointInA,
+ Body3DSW *body2, const Vector3 &pointInB,
+ int limit_index,
+ const Vector3 &axis_normal_on_a,
+ const Vector3 &anchorPos) {
+
+ ///find relative velocity
+ // Vector3 rel_pos1 = pointInA - body1->get_transform().origin;
+ // Vector3 rel_pos2 = pointInB - body2->get_transform().origin;
+ Vector3 rel_pos1 = anchorPos - body1->get_transform().origin;
+ Vector3 rel_pos2 = anchorPos - body2->get_transform().origin;
+
+ Vector3 vel1 = body1->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = body2->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ real_t rel_vel = axis_normal_on_a.dot(vel);
+
+ /// apply displacement correction
+
+ //positional error (zeroth order error)
+ real_t depth = -(pointInA - pointInB).dot(axis_normal_on_a);
+ real_t lo = real_t(-1e30);
+ real_t hi = real_t(1e30);
+
+ real_t minLimit = m_lowerLimit[limit_index];
+ real_t maxLimit = m_upperLimit[limit_index];
+
+ //handle the limits
+ if (minLimit < maxLimit) {
+ {
+ if (depth > maxLimit) {
+ depth -= maxLimit;
+ lo = real_t(0.);
+
+ } else {
+ if (depth < minLimit) {
+ depth -= minLimit;
+ hi = real_t(0.);
+ } else {
+ return 0.0f;
+ }
+ }
+ }
+ }
+
+ real_t normalImpulse = m_limitSoftness[limit_index] * (m_restitution[limit_index] * depth / timeStep - m_damping[limit_index] * rel_vel) * jacDiagABInv;
+
+ real_t oldNormalImpulse = m_accumulatedImpulse[limit_index];
+ real_t sum = oldNormalImpulse + normalImpulse;
+ m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : sum < lo ? real_t(0.) : sum;
+ normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
+
+ Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
+ body1->apply_impulse(rel_pos1, impulse_vector);
+ body2->apply_impulse(rel_pos2, -impulse_vector);
+ return normalImpulse;
+}
+
+//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
+
+Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) :
+ Joint3DSW(_arr, 2),
+ m_frameInA(frameInA),
+ m_frameInB(frameInB),
+ m_useLinearReferenceFrameA(useLinearReferenceFrameA) {
+ A = rbA;
+ B = rbB;
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+}
+
+void Generic6DOFJoint3DSW::calculateAngleInfo() {
+ Basis relative_frame = m_calculatedTransformB.basis.inverse() * m_calculatedTransformA.basis;
+
+ m_calculatedAxisAngleDiff = relative_frame.get_euler_xyz();
+
+ // in euler angle mode we do not actually constrain the angular velocity
+ // along the axes axis[0] and axis[2] (although we do use axis[1]) :
+ //
+ // to get constrain w2-w1 along ...not
+ // ------ --------------------- ------
+ // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
+ // d(angle[1])/dt = 0 ax[1]
+ // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
+ //
+ // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
+ // to prove the result for angle[0], write the expression for angle[0] from
+ // GetInfo1 then take the derivative. to prove this for angle[2] it is
+ // easier to take the euler rate expression for d(angle[2])/dt with respect
+ // to the components of w and set that to 0.
+
+ Vector3 axis0 = m_calculatedTransformB.basis.get_axis(0);
+ Vector3 axis2 = m_calculatedTransformA.basis.get_axis(2);
+
+ m_calculatedAxis[1] = axis2.cross(axis0);
+ m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
+ m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
+
+ /*
+ if(m_debugDrawer)
+ {
+
+ char buff[300];
+ sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
+ m_calculatedAxisAngleDiff[0],
+ m_calculatedAxisAngleDiff[1],
+ m_calculatedAxisAngleDiff[2]);
+ m_debugDrawer->reportErrorWarning(buff);
+ }
+ */
+}
+
+void Generic6DOFJoint3DSW::calculateTransforms() {
+ m_calculatedTransformA = A->get_transform() * m_frameInA;
+ m_calculatedTransformB = B->get_transform() * m_frameInB;
+
+ calculateAngleInfo();
+}
+
+void Generic6DOFJoint3DSW::buildLinearJacobian(
+ JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld,
+ const Vector3 &pivotAInW, const Vector3 &pivotBInW) {
+ memnew_placement(&jacLinear, JacobianEntry3DSW(
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
+ pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
+ normalWorld,
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+}
+
+void Generic6DOFJoint3DSW::buildAngularJacobian(
+ JacobianEntry3DSW &jacAngular, const Vector3 &jointAxisW) {
+ memnew_placement(&jacAngular, JacobianEntry3DSW(jointAxisW,
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+}
+
+bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) {
+ real_t angle = m_calculatedAxisAngleDiff[axis_index];
+
+ //test limits
+ m_angularLimits[axis_index].testLimitValue(angle);
+ return m_angularLimits[axis_index].needApplyTorques();
+}
+
+bool Generic6DOFJoint3DSW::setup(real_t p_timestep) {
+
+ // Clear accumulated impulses for the next simulation step
+ m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.));
+ int i;
+ for (i = 0; i < 3; i++) {
+ m_angularLimits[i].m_accumulatedImpulse = real_t(0.);
+ }
+ //calculates transform
+ calculateTransforms();
+
+ // const Vector3& pivotAInW = m_calculatedTransformA.origin;
+ // const Vector3& pivotBInW = m_calculatedTransformB.origin;
+ calcAnchorPos();
+ Vector3 pivotAInW = m_AnchorPos;
+ Vector3 pivotBInW = m_AnchorPos;
+
+ // not used here
+ // Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ // Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+
+ Vector3 normalWorld;
+ //linear part
+ for (i = 0; i < 3; i++) {
+ if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
+ if (m_useLinearReferenceFrameA)
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ else
+ normalWorld = m_calculatedTransformB.basis.get_axis(i);
+
+ buildLinearJacobian(
+ m_jacLinear[i], normalWorld,
+ pivotAInW, pivotBInW);
+ }
+ }
+
+ // angular part
+ for (i = 0; i < 3; i++) {
+ //calculates error angle
+ if (m_angularLimits[i].m_enableLimit && testAngularLimitMotor(i)) {
+ normalWorld = this->getAxis(i);
+ // Create angular atom
+ buildAngularJacobian(m_jacAng[i], normalWorld);
+ }
+ }
+
+ return true;
+}
+
+void Generic6DOFJoint3DSW::solve(real_t p_timestep) {
+ m_timeStep = p_timestep;
+
+ //calculateTransforms();
+
+ int i;
+
+ // linear
+
+ Vector3 pointInA = m_calculatedTransformA.origin;
+ Vector3 pointInB = m_calculatedTransformB.origin;
+
+ real_t jacDiagABInv;
+ Vector3 linear_axis;
+ for (i = 0; i < 3; i++) {
+ if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
+ jacDiagABInv = real_t(1.) / m_jacLinear[i].getDiagonal();
+
+ if (m_useLinearReferenceFrameA)
+ linear_axis = m_calculatedTransformA.basis.get_axis(i);
+ else
+ linear_axis = m_calculatedTransformB.basis.get_axis(i);
+
+ m_linearLimits.solveLinearAxis(
+ m_timeStep,
+ jacDiagABInv,
+ A, pointInA,
+ B, pointInB,
+ i, linear_axis, m_AnchorPos);
+ }
+ }
+
+ // angular
+ Vector3 angular_axis;
+ real_t angularJacDiagABInv;
+ for (i = 0; i < 3; i++) {
+ if (m_angularLimits[i].m_enableLimit && m_angularLimits[i].needApplyTorques()) {
+
+ // get axis
+ angular_axis = getAxis(i);
+
+ angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
+
+ m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B);
+ }
+ }
+}
+
+void Generic6DOFJoint3DSW::updateRHS(real_t timeStep) {
+ (void)timeStep;
+}
+
+Vector3 Generic6DOFJoint3DSW::getAxis(int axis_index) const {
+ return m_calculatedAxis[axis_index];
+}
+
+real_t Generic6DOFJoint3DSW::getAngle(int axis_index) const {
+ return m_calculatedAxisAngleDiff[axis_index];
+}
+
+void Generic6DOFJoint3DSW::calcAnchorPos(void) {
+ real_t imA = A->get_inv_mass();
+ real_t imB = B->get_inv_mass();
+ real_t weight;
+ if (imB == real_t(0.0)) {
+ weight = real_t(1.0);
+ } else {
+ weight = imA / (imA + imB);
+ }
+ const Vector3 &pA = m_calculatedTransformA.origin;
+ const Vector3 &pB = m_calculatedTransformB.origin;
+ m_AnchorPos = pA * weight + pB * (real_t(1.0) - weight);
+} // Generic6DOFJointSW::calcAnchorPos()
+
+void Generic6DOFJoint3DSW::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value) {
+
+ ERR_FAIL_INDEX(p_axis, 3);
+ switch (p_param) {
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
+
+ m_linearLimits.m_lowerLimit[p_axis] = p_value;
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
+
+ m_linearLimits.m_upperLimit[p_axis] = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
+
+ m_linearLimits.m_limitSoftness[p_axis] = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION: {
+
+ m_linearLimits.m_restitution[p_axis] = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING: {
+
+ m_linearLimits.m_damping[p_axis] = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
+
+ m_angularLimits[p_axis].m_loLimit = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
+
+ m_angularLimits[p_axis].m_hiLimit = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
+
+ m_angularLimits[p_axis].m_limitSoftness = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING: {
+
+ m_angularLimits[p_axis].m_damping = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION: {
+
+ m_angularLimits[p_axis].m_bounce = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
+
+ m_angularLimits[p_axis].m_maxLimitForce = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP: {
+
+ m_angularLimits[p_axis].m_ERP = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
+
+ m_angularLimits[p_axis].m_targetVelocity = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
+
+ m_angularLimits[p_axis].m_maxLimitForce = p_value;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning
+ }
+}
+
+real_t Generic6DOFJoint3DSW::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const {
+ ERR_FAIL_INDEX_V(p_axis, 3, 0);
+ switch (p_param) {
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
+
+ return m_linearLimits.m_lowerLimit[p_axis];
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
+
+ return m_linearLimits.m_upperLimit[p_axis];
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
+
+ return m_linearLimits.m_limitSoftness[p_axis];
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION: {
+
+ return m_linearLimits.m_restitution[p_axis];
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING: {
+
+ return m_linearLimits.m_damping[p_axis];
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
+
+ return m_angularLimits[p_axis].m_loLimit;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
+
+ return m_angularLimits[p_axis].m_hiLimit;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
+
+ return m_angularLimits[p_axis].m_limitSoftness;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING: {
+
+ return m_angularLimits[p_axis].m_damping;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION: {
+
+ return m_angularLimits[p_axis].m_bounce;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
+
+ return m_angularLimits[p_axis].m_maxLimitForce;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP: {
+
+ return m_angularLimits[p_axis].m_ERP;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
+
+ return m_angularLimits[p_axis].m_targetVelocity;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
+
+ return m_angularLimits[p_axis].m_maxMotorForce;
+
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning
+ }
+ return 0;
+}
+
+void Generic6DOFJoint3DSW::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value) {
+
+ ERR_FAIL_INDEX(p_axis, 3);
+
+ switch (p_flag) {
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
+
+ m_linearLimits.enable_limit[p_axis] = p_value;
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
+
+ m_angularLimits[p_axis].m_enableLimit = p_value;
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
+
+ m_angularLimits[p_axis].m_enableMotor = p_value;
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
+ }
+}
+bool Generic6DOFJoint3DSW::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const {
+
+ ERR_FAIL_INDEX_V(p_axis, 3, 0);
+ switch (p_flag) {
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
+
+ return m_linearLimits.enable_limit[p_axis];
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
+
+ return m_angularLimits[p_axis].m_enableLimit;
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
+
+ return m_angularLimits[p_axis].m_enableMotor;
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
+ // Not implemented in GodotPhysics3D backend
+ } break;
+ case PhysicsServer3D::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
+ }
+
+ return 0;
+}
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
new file mode 100644
index 0000000000..f7aa607901
--- /dev/null
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
@@ -0,0 +1,401 @@
+/*************************************************************************/
+/* generic_6dof_joint_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+#ifndef GENERIC_6DOF_JOINT_SW_H
+#define GENERIC_6DOF_JOINT_SW_H
+
+#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h"
+#include "servers/physics_3d/joints_3d_sw.h"
+
+/*
+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.
+*/
+
+/*
+2007-09-09
+Generic6DOFJointSW Refactored by Francisco Le?n
+email: projectileman@yahoo.com
+http://gimpact.sf.net
+*/
+
+//! Rotation Limit structure for generic joints
+class G6DOFRotationalLimitMotor3DSW {
+public:
+ //! limit_parameters
+ //!@{
+ real_t m_loLimit; //!< joint limit
+ real_t m_hiLimit; //!< joint limit
+ real_t m_targetVelocity; //!< target motor velocity
+ real_t m_maxMotorForce; //!< max force on motor
+ real_t m_maxLimitForce; //!< max force on limit
+ real_t m_damping; //!< Damping.
+ real_t m_limitSoftness; //! Relaxation factor
+ real_t m_ERP; //!< Error tolerance factor when joint is at limit
+ real_t m_bounce; //!< restitution factor
+ bool m_enableMotor;
+ bool m_enableLimit;
+
+ //!@}
+
+ //! temp_variables
+ //!@{
+ real_t m_currentLimitError; //! How much is violated this limit
+ int m_currentLimit; //!< 0=free, 1=at lo limit, 2=at hi limit
+ real_t m_accumulatedImpulse;
+ //!@}
+
+ G6DOFRotationalLimitMotor3DSW() {
+ m_accumulatedImpulse = 0.f;
+ m_targetVelocity = 0;
+ m_maxMotorForce = 0.1f;
+ m_maxLimitForce = 300.0f;
+ m_loLimit = -1e30;
+ m_hiLimit = 1e30;
+ m_ERP = 0.5f;
+ m_bounce = 0.0f;
+ m_damping = 1.0f;
+ m_limitSoftness = 0.5f;
+ m_currentLimit = 0;
+ m_currentLimitError = 0;
+ m_enableMotor = false;
+ m_enableLimit = false;
+ }
+
+ G6DOFRotationalLimitMotor3DSW(const G6DOFRotationalLimitMotor3DSW &limot) {
+ m_targetVelocity = limot.m_targetVelocity;
+ m_maxMotorForce = limot.m_maxMotorForce;
+ m_limitSoftness = limot.m_limitSoftness;
+ m_loLimit = limot.m_loLimit;
+ m_hiLimit = limot.m_hiLimit;
+ m_ERP = limot.m_ERP;
+ m_bounce = limot.m_bounce;
+ m_currentLimit = limot.m_currentLimit;
+ m_currentLimitError = limot.m_currentLimitError;
+ m_enableMotor = limot.m_enableMotor;
+ }
+
+ //! Is limited
+ bool isLimited() {
+ return (m_loLimit < m_hiLimit);
+ }
+
+ //! Need apply correction
+ bool needApplyTorques() {
+ return (m_enableMotor || m_currentLimit != 0);
+ }
+
+ //! calculates error
+ /*!
+ calculates m_currentLimit and m_currentLimitError.
+ */
+ int testLimitValue(real_t test_value);
+
+ //! apply the correction impulses for two bodies
+ real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1);
+};
+
+class G6DOFTranslationalLimitMotor3DSW {
+public:
+ Vector3 m_lowerLimit; //!< the constraint lower limits
+ Vector3 m_upperLimit; //!< the constraint upper limits
+ Vector3 m_accumulatedImpulse;
+ //! Linear_Limit_parameters
+ //!@{
+ Vector3 m_limitSoftness; //!< Softness for linear limit
+ Vector3 m_damping; //!< Damping for linear limit
+ Vector3 m_restitution; //! Bounce parameter for linear limit
+ //!@}
+ bool enable_limit[3];
+
+ G6DOFTranslationalLimitMotor3DSW() {
+ m_lowerLimit = Vector3(0.f, 0.f, 0.f);
+ m_upperLimit = Vector3(0.f, 0.f, 0.f);
+ m_accumulatedImpulse = Vector3(0.f, 0.f, 0.f);
+
+ m_limitSoftness = Vector3(1, 1, 1) * 0.7f;
+ m_damping = Vector3(1, 1, 1) * real_t(1.0f);
+ m_restitution = Vector3(1, 1, 1) * real_t(0.5f);
+
+ enable_limit[0] = true;
+ enable_limit[1] = true;
+ enable_limit[2] = true;
+ }
+
+ G6DOFTranslationalLimitMotor3DSW(const G6DOFTranslationalLimitMotor3DSW &other) {
+ m_lowerLimit = other.m_lowerLimit;
+ m_upperLimit = other.m_upperLimit;
+ m_accumulatedImpulse = other.m_accumulatedImpulse;
+
+ m_limitSoftness = other.m_limitSoftness;
+ m_damping = other.m_damping;
+ m_restitution = other.m_restitution;
+ }
+
+ //! Test limit
+ /*!
+ - free means upper < lower,
+ - locked means upper == lower
+ - limited means upper > lower
+ - limitIndex: first 3 are linear, next 3 are angular
+ */
+ inline bool isLimited(int limitIndex) {
+ return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
+ }
+
+ real_t solveLinearAxis(
+ real_t timeStep,
+ real_t jacDiagABInv,
+ Body3DSW *body1, const Vector3 &pointInA,
+ Body3DSW *body2, const Vector3 &pointInB,
+ int limit_index,
+ const Vector3 &axis_normal_on_a,
+ const Vector3 &anchorPos);
+};
+
+class Generic6DOFJoint3DSW : public Joint3DSW {
+protected:
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ //! relative_frames
+ //!@{
+ Transform m_frameInA; //!< the constraint space w.r.t body A
+ Transform m_frameInB; //!< the constraint space w.r.t body B
+ //!@}
+
+ //! Jacobians
+ //!@{
+ JacobianEntry3DSW m_jacLinear[3]; //!< 3 orthogonal linear constraints
+ JacobianEntry3DSW m_jacAng[3]; //!< 3 orthogonal angular constraints
+ //!@}
+
+ //! Linear_Limit_parameters
+ //!@{
+ G6DOFTranslationalLimitMotor3DSW m_linearLimits;
+ //!@}
+
+ //! hinge_parameters
+ //!@{
+ G6DOFRotationalLimitMotor3DSW m_angularLimits[3];
+ //!@}
+
+protected:
+ //! temporal variables
+ //!@{
+ real_t m_timeStep;
+ Transform m_calculatedTransformA;
+ Transform m_calculatedTransformB;
+ Vector3 m_calculatedAxisAngleDiff;
+ Vector3 m_calculatedAxis[3];
+
+ Vector3 m_AnchorPos; // point between pivots of bodies A and B to solve linear axes
+
+ bool m_useLinearReferenceFrameA;
+
+ //!@}
+
+ Generic6DOFJoint3DSW &operator=(Generic6DOFJoint3DSW &other) {
+ ERR_PRINT("pito");
+ (void)other;
+ return *this;
+ }
+
+ void buildLinearJacobian(
+ JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld,
+ const Vector3 &pivotAInW, const Vector3 &pivotBInW);
+
+ void buildAngularJacobian(JacobianEntry3DSW &jacAngular, const Vector3 &jointAxisW);
+
+ //! calcs the euler angles between the two bodies.
+ void calculateAngleInfo();
+
+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 bool setup(real_t p_timestep);
+ virtual void solve(real_t p_timestep);
+
+ //! Calcs global transform of the offsets
+ /*!
+ Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies.
+ \sa Generic6DOFJointSW.getCalculatedTransformA , Generic6DOFJointSW.getCalculatedTransformB, Generic6DOFJointSW.calculateAngleInfo
+ */
+ void calculateTransforms();
+
+ //! Gets the global transform of the offset for body A
+ /*!
+ \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
+ */
+ const Transform &getCalculatedTransformA() const {
+ return m_calculatedTransformA;
+ }
+
+ //! Gets the global transform of the offset for body B
+ /*!
+ \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo.
+ */
+ const Transform &getCalculatedTransformB() const {
+ return m_calculatedTransformB;
+ }
+
+ const Transform &getFrameOffsetA() const {
+ return m_frameInA;
+ }
+
+ const Transform &getFrameOffsetB() const {
+ return m_frameInB;
+ }
+
+ Transform &getFrameOffsetA() {
+ return m_frameInA;
+ }
+
+ Transform &getFrameOffsetB() {
+ return m_frameInB;
+ }
+
+ //! performs Jacobian calculation, and also calculates angle differences and axis
+
+ void updateRHS(real_t timeStep);
+
+ //! Get the rotation axis in global coordinates
+ /*!
+ \pre Generic6DOFJointSW.buildJacobian must be called previously.
+ */
+ Vector3 getAxis(int axis_index) const;
+
+ //! Get the relative Euler angle
+ /*!
+ \pre Generic6DOFJointSW.buildJacobian must be called previously.
+ */
+ real_t getAngle(int axis_index) const;
+
+ //! Test angular limit.
+ /*!
+ Calculates angular correction and returns true if limit needs to be corrected.
+ \pre Generic6DOFJointSW.buildJacobian must be called previously.
+ */
+ bool testAngularLimitMotor(int axis_index);
+
+ void setLinearLowerLimit(const Vector3 &linearLower) {
+ m_linearLimits.m_lowerLimit = linearLower;
+ }
+
+ void setLinearUpperLimit(const Vector3 &linearUpper) {
+ m_linearLimits.m_upperLimit = linearUpper;
+ }
+
+ void setAngularLowerLimit(const Vector3 &angularLower) {
+ m_angularLimits[0].m_loLimit = angularLower.x;
+ m_angularLimits[1].m_loLimit = angularLower.y;
+ m_angularLimits[2].m_loLimit = angularLower.z;
+ }
+
+ void setAngularUpperLimit(const Vector3 &angularUpper) {
+ m_angularLimits[0].m_hiLimit = angularUpper.x;
+ m_angularLimits[1].m_hiLimit = angularUpper.y;
+ m_angularLimits[2].m_hiLimit = angularUpper.z;
+ }
+
+ //! Retrieves the angular limit informacion
+ G6DOFRotationalLimitMotor3DSW *getRotationalLimitMotor(int index) {
+ return &m_angularLimits[index];
+ }
+
+ //! Retrieves the limit informacion
+ G6DOFTranslationalLimitMotor3DSW *getTranslationalLimitMotor() {
+ return &m_linearLimits;
+ }
+
+ //first 3 are linear, next 3 are angular
+ void setLimit(int axis, real_t lo, real_t hi) {
+ if (axis < 3) {
+ m_linearLimits.m_lowerLimit[axis] = lo;
+ m_linearLimits.m_upperLimit[axis] = hi;
+ } else {
+ m_angularLimits[axis - 3].m_loLimit = lo;
+ m_angularLimits[axis - 3].m_hiLimit = hi;
+ }
+ }
+
+ //! Test limit
+ /*!
+ - free means upper < lower,
+ - locked means upper == lower
+ - limited means upper > lower
+ - limitIndex: first 3 are linear, next 3 are angular
+ */
+ bool isLimited(int limitIndex) {
+ if (limitIndex < 3) {
+ return m_linearLimits.isLimited(limitIndex);
+ }
+ return m_angularLimits[limitIndex - 3].isLimited();
+ }
+
+ const Body3DSW *getRigidBodyA() const {
+ return A;
+ }
+ const Body3DSW *getRigidBodyB() const {
+ return B;
+ }
+
+ virtual void calcAnchorPos(void); // overridable
+
+ void set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value);
+ real_t get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const;
+
+ void set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value);
+ bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const;
+};
+
+#endif // GENERIC_6DOF_JOINT_SW_H
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
new file mode 100644
index 0000000000..e76d366422
--- /dev/null
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
@@ -0,0 +1,450 @@
+/*************************************************************************/
+/* hinge_joint_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+/*
+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.
+*/
+
+#include "hinge_joint_3d_sw.h"
+
+static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) {
+
+ if (Math::abs(n.z) > Math_SQRT12) {
+ // choose p in y-z plane
+ real_t a = n[1] * n[1] + n[2] * n[2];
+ real_t k = 1.0 / Math::sqrt(a);
+ p = Vector3(0, -n[2] * k, n[1] * k);
+ // set q = n x p
+ q = Vector3(a * k, -n[0] * p[2], n[0] * p[1]);
+ } else {
+ // choose p in x-y plane
+ real_t a = n.x * n.x + n.y * n.y;
+ real_t k = 1.0 / Math::sqrt(a);
+ p = Vector3(-n.y * k, n.x * k, 0);
+ // set q = n x p
+ q = Vector3(-n.z * p.y, n.z * p.x, a * k);
+ }
+}
+
+HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameA, const Transform &frameB) :
+ Joint3DSW(_arr, 2) {
+
+ A = rbA;
+ B = rbB;
+
+ m_rbAFrame = frameA;
+ m_rbBFrame = frameB;
+ // flip axis
+ m_rbBFrame.basis[0][2] *= real_t(-1.);
+ m_rbBFrame.basis[1][2] *= real_t(-1.);
+ m_rbBFrame.basis[2][2] *= real_t(-1.);
+
+ //start with free
+ m_lowerLimit = Math_PI;
+ m_upperLimit = -Math_PI;
+
+ m_useLimit = false;
+ m_biasFactor = 0.3f;
+ m_relaxationFactor = 1.0f;
+ m_limitSoftness = 0.9f;
+ m_solveLimit = false;
+
+ tau = 0.3;
+
+ m_angularOnly = false;
+ m_enableAngularMotor = false;
+
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+}
+
+HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB,
+ const Vector3 &axisInA, const Vector3 &axisInB) :
+ Joint3DSW(_arr, 2) {
+
+ A = rbA;
+ B = rbB;
+
+ m_rbAFrame.origin = pivotInA;
+
+ // since no frame is given, assume this to be zero angle and just pick rb transform axis
+ Vector3 rbAxisA1 = rbA->get_transform().basis.get_axis(0);
+
+ Vector3 rbAxisA2;
+ real_t projection = axisInA.dot(rbAxisA1);
+ if (projection >= 1.0f - CMP_EPSILON) {
+ rbAxisA1 = -rbA->get_transform().basis.get_axis(2);
+ rbAxisA2 = rbA->get_transform().basis.get_axis(1);
+ } else if (projection <= -1.0f + CMP_EPSILON) {
+ rbAxisA1 = rbA->get_transform().basis.get_axis(2);
+ rbAxisA2 = rbA->get_transform().basis.get_axis(1);
+ } else {
+ rbAxisA2 = axisInA.cross(rbAxisA1);
+ rbAxisA1 = rbAxisA2.cross(axisInA);
+ }
+
+ m_rbAFrame.basis = Basis(rbAxisA1.x, rbAxisA2.x, axisInA.x,
+ rbAxisA1.y, rbAxisA2.y, axisInA.y,
+ rbAxisA1.z, rbAxisA2.z, axisInA.z);
+
+ Quat rotationArc = Quat(axisInA, axisInB);
+ Vector3 rbAxisB1 = rotationArc.xform(rbAxisA1);
+ Vector3 rbAxisB2 = axisInB.cross(rbAxisB1);
+
+ m_rbBFrame.origin = pivotInB;
+ m_rbBFrame.basis = Basis(rbAxisB1.x, rbAxisB2.x, -axisInB.x,
+ rbAxisB1.y, rbAxisB2.y, -axisInB.y,
+ rbAxisB1.z, rbAxisB2.z, -axisInB.z);
+
+ //start with free
+ m_lowerLimit = Math_PI;
+ m_upperLimit = -Math_PI;
+
+ m_useLimit = false;
+ m_biasFactor = 0.3f;
+ m_relaxationFactor = 1.0f;
+ m_limitSoftness = 0.9f;
+ m_solveLimit = false;
+
+ tau = 0.3;
+
+ m_angularOnly = false;
+ m_enableAngularMotor = false;
+
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+}
+
+bool HingeJoint3DSW::setup(real_t p_step) {
+
+ m_appliedImpulse = real_t(0.);
+
+ if (!m_angularOnly) {
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+ Vector3 relPos = pivotBInW - pivotAInW;
+
+ Vector3 normal[3];
+ if (Math::is_zero_approx(relPos.length_squared())) {
+ normal[0] = Vector3(real_t(1.0), 0, 0);
+ } else {
+ normal[0] = relPos.normalized();
+ }
+
+ plane_space(normal[0], normal[1], normal[2]);
+
+ for (int i = 0; i < 3; i++) {
+ memnew_placement(&m_jac[i], JacobianEntry3DSW(
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
+ pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
+ normal[i],
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+ }
+ }
+
+ //calculate two perpendicular jointAxis, orthogonal to hingeAxis
+ //these two jointAxis require equal angular velocities for both bodies
+
+ //this is unused for now, it's a todo
+ Vector3 jointAxis0local;
+ Vector3 jointAxis1local;
+
+ plane_space(m_rbAFrame.basis.get_axis(2), jointAxis0local, jointAxis1local);
+
+ Vector3 jointAxis0 = A->get_transform().basis.xform(jointAxis0local);
+ Vector3 jointAxis1 = A->get_transform().basis.xform(jointAxis1local);
+ Vector3 hingeAxisWorld = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
+
+ memnew_placement(&m_jacAng[0], JacobianEntry3DSW(jointAxis0,
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+ memnew_placement(&m_jacAng[1], JacobianEntry3DSW(jointAxis1,
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+ memnew_placement(&m_jacAng[2], JacobianEntry3DSW(hingeAxisWorld,
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+
+ // Compute limit information
+ real_t hingeAngle = get_hinge_angle();
+
+ //set bias, sign, clear accumulator
+ m_correction = real_t(0.);
+ m_limitSign = real_t(0.);
+ m_solveLimit = false;
+ m_accLimitImpulse = real_t(0.);
+
+ //if (m_lowerLimit < m_upperLimit)
+ if (m_useLimit && m_lowerLimit <= m_upperLimit) {
+ //if (hingeAngle <= m_lowerLimit*m_limitSoftness)
+ if (hingeAngle <= m_lowerLimit) {
+ m_correction = (m_lowerLimit - hingeAngle);
+ m_limitSign = 1.0f;
+ m_solveLimit = true;
+ }
+ //else if (hingeAngle >= m_upperLimit*m_limitSoftness)
+ else if (hingeAngle >= m_upperLimit) {
+ m_correction = m_upperLimit - hingeAngle;
+ m_limitSign = -1.0f;
+ m_solveLimit = true;
+ }
+ }
+
+ //Compute K = J*W*J' for hinge axis
+ Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
+ m_kHinge = 1.0f / (A->compute_angular_impulse_denominator(axisA) +
+ B->compute_angular_impulse_denominator(axisA));
+
+ return true;
+}
+
+void HingeJoint3DSW::solve(real_t p_step) {
+
+ Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin);
+ Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin);
+
+ //real_t tau = real_t(0.3);
+
+ //linear part
+ if (!m_angularOnly) {
+ Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+
+ Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ for (int i = 0; i < 3; i++) {
+ const Vector3 &normal = m_jac[i].m_linearJointAxis;
+ real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
+
+ real_t rel_vel;
+ rel_vel = normal.dot(vel);
+ //positional error (zeroth order error)
+ real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
+ real_t impulse = depth * tau / p_step * jacDiagABInv - rel_vel * jacDiagABInv;
+ m_appliedImpulse += impulse;
+ Vector3 impulse_vector = normal * impulse;
+ A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
+ B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
+ }
+ }
+
+ {
+ ///solve angular part
+
+ // get axes in world space
+ Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2));
+ Vector3 axisB = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(2));
+
+ const Vector3 &angVelA = A->get_angular_velocity();
+ const Vector3 &angVelB = B->get_angular_velocity();
+
+ Vector3 angVelAroundHingeAxisA = axisA * axisA.dot(angVelA);
+ Vector3 angVelAroundHingeAxisB = axisB * axisB.dot(angVelB);
+
+ Vector3 angAorthog = angVelA - angVelAroundHingeAxisA;
+ Vector3 angBorthog = angVelB - angVelAroundHingeAxisB;
+ Vector3 velrelOrthog = angAorthog - angBorthog;
+ {
+ //solve orthogonal angular velocity correction
+ real_t relaxation = real_t(1.);
+ real_t len = velrelOrthog.length();
+ if (len > real_t(0.00001)) {
+ Vector3 normal = velrelOrthog.normalized();
+ real_t denom = A->compute_angular_impulse_denominator(normal) +
+ B->compute_angular_impulse_denominator(normal);
+ // scale for mass and relaxation
+ velrelOrthog *= (real_t(1.) / denom) * m_relaxationFactor;
+ }
+
+ //solve angular positional correction
+ Vector3 angularError = -axisA.cross(axisB) * (real_t(1.) / p_step);
+ real_t len2 = angularError.length();
+ if (len2 > real_t(0.00001)) {
+ Vector3 normal2 = angularError.normalized();
+ real_t denom2 = A->compute_angular_impulse_denominator(normal2) +
+ B->compute_angular_impulse_denominator(normal2);
+ angularError *= (real_t(1.) / denom2) * relaxation;
+ }
+
+ A->apply_torque_impulse(-velrelOrthog + angularError);
+ B->apply_torque_impulse(velrelOrthog - angularError);
+
+ // solve limit
+ if (m_solveLimit) {
+ real_t amplitude = ((angVelB - angVelA).dot(axisA) * m_relaxationFactor + m_correction * (real_t(1.) / p_step) * m_biasFactor) * m_limitSign;
+
+ real_t impulseMag = amplitude * m_kHinge;
+
+ // Clamp the accumulated impulse
+ real_t temp = m_accLimitImpulse;
+ m_accLimitImpulse = MAX(m_accLimitImpulse + impulseMag, real_t(0));
+ impulseMag = m_accLimitImpulse - temp;
+
+ Vector3 impulse = axisA * impulseMag * m_limitSign;
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+ }
+ }
+
+ //apply motor
+ if (m_enableAngularMotor) {
+ //todo: add limits too
+ Vector3 angularLimit(0, 0, 0);
+
+ Vector3 velrel = angVelAroundHingeAxisA - angVelAroundHingeAxisB;
+ real_t projRelVel = velrel.dot(axisA);
+
+ real_t desiredMotorVel = m_motorTargetVelocity;
+ real_t motor_relvel = desiredMotorVel - projRelVel;
+
+ real_t unclippedMotorImpulse = m_kHinge * motor_relvel;
+ //todo: should clip against accumulated impulse
+ real_t clippedMotorImpulse = unclippedMotorImpulse > m_maxMotorImpulse ? m_maxMotorImpulse : unclippedMotorImpulse;
+ clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse;
+ Vector3 motorImp = clippedMotorImpulse * axisA;
+
+ A->apply_torque_impulse(motorImp + angularLimit);
+ B->apply_torque_impulse(-motorImp - angularLimit);
+ }
+ }
+}
+/*
+void HingeJointSW::updateRHS(real_t timeStep)
+{
+ (void)timeStep;
+
+}
+*/
+
+static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
+ real_t coeff_1 = Math_PI / 4.0f;
+ real_t coeff_2 = 3.0f * coeff_1;
+ real_t abs_y = Math::abs(y);
+ real_t angle;
+ if (x >= 0.0f) {
+ real_t r = (x - abs_y) / (x + abs_y);
+ angle = coeff_1 - coeff_1 * r;
+ } else {
+ real_t r = (x + abs_y) / (abs_y - x);
+ angle = coeff_2 - coeff_1 * r;
+ }
+ return (y < 0.0f) ? -angle : angle;
+}
+
+real_t HingeJoint3DSW::get_hinge_angle() {
+ const Vector3 refAxis0 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(0));
+ const Vector3 refAxis1 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(1));
+ const Vector3 swingAxis = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(1));
+
+ return atan2fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1));
+}
+
+void HingeJoint3DSW::set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value) {
+
+ switch (p_param) {
+
+ case PhysicsServer3D::HINGE_JOINT_BIAS: tau = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER: m_upperLimit = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER: m_lowerLimit = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS: m_biasFactor = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS: m_limitSoftness = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION: m_relaxationFactor = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY: m_motorTargetVelocity = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE: m_maxMotorImpulse = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_MAX: break; // Can't happen, but silences warning
+ }
+}
+
+real_t HingeJoint3DSW::get_param(PhysicsServer3D::HingeJointParam p_param) const {
+
+ switch (p_param) {
+
+ case PhysicsServer3D::HINGE_JOINT_BIAS: return tau;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER: return m_upperLimit;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER: return m_lowerLimit;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS: return m_biasFactor;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS: return m_limitSoftness;
+ case PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION: return m_relaxationFactor;
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY: return m_motorTargetVelocity;
+ case PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE: return m_maxMotorImpulse;
+ case PhysicsServer3D::HINGE_JOINT_MAX: break; // Can't happen, but silences warning
+ }
+
+ return 0;
+}
+
+void HingeJoint3DSW::set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value) {
+
+ switch (p_flag) {
+ case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: m_useLimit = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR: m_enableAngularMotor = p_value; break;
+ case PhysicsServer3D::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
+ }
+}
+bool HingeJoint3DSW::get_flag(PhysicsServer3D::HingeJointFlag p_flag) const {
+
+ switch (p_flag) {
+ case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: return m_useLimit;
+ case PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR: return m_enableAngularMotor;
+ case PhysicsServer3D::HINGE_JOINT_FLAG_MAX: break; // Can't happen, but silences warning
+ }
+
+ return false;
+}
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h
new file mode 100644
index 0000000000..eebead20b8
--- /dev/null
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h
@@ -0,0 +1,117 @@
+/*************************************************************************/
+/* hinge_joint_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+#ifndef HINGE_JOINT_SW_H
+#define HINGE_JOINT_SW_H
+
+#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h"
+#include "servers/physics_3d/joints_3d_sw.h"
+
+/*
+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.
+*/
+
+class HingeJoint3DSW : public Joint3DSW {
+
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints
+ JacobianEntry3DSW m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor
+
+ Transform m_rbAFrame; // constraint axii. Assumes z is hinge axis.
+ Transform m_rbBFrame;
+
+ real_t m_motorTargetVelocity;
+ real_t m_maxMotorImpulse;
+
+ real_t m_limitSoftness;
+ real_t m_biasFactor;
+ real_t m_relaxationFactor;
+
+ real_t m_lowerLimit;
+ real_t m_upperLimit;
+
+ real_t m_kHinge;
+
+ real_t m_limitSign;
+ real_t m_correction;
+
+ real_t m_accLimitImpulse;
+
+ real_t tau;
+
+ bool m_useLimit;
+ bool m_angularOnly;
+ bool m_enableAngularMotor;
+ bool m_solveLimit;
+
+ real_t m_appliedImpulse;
+
+public:
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; }
+
+ virtual bool setup(real_t p_step);
+ virtual void solve(real_t p_step);
+
+ real_t get_hinge_angle();
+
+ void set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::HingeJointParam p_param) const;
+
+ void set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value);
+ bool get_flag(PhysicsServer3D::HingeJointFlag p_flag) const;
+
+ HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameA, const Transform &frameB);
+ HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
+};
+
+#endif // HINGE_JOINT_SW_H
diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/jacobian_entry_3d_sw.h
new file mode 100644
index 0000000000..7e605ab173
--- /dev/null
+++ b/servers/physics_3d/joints/jacobian_entry_3d_sw.h
@@ -0,0 +1,169 @@
+/*************************************************************************/
+/* jacobian_entry_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+#ifndef JACOBIAN_ENTRY_SW_H
+#define JACOBIAN_ENTRY_SW_H
+
+/*
+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.
+*/
+
+#include "core/math/transform.h"
+
+class JacobianEntry3DSW {
+public:
+ JacobianEntry3DSW(){};
+ //constraint between two different rigidbodies
+ JacobianEntry3DSW(
+ const Basis &world2A,
+ const Basis &world2B,
+ const Vector3 &rel_pos1, const Vector3 &rel_pos2,
+ const Vector3 &jointAxis,
+ const Vector3 &inertiaInvA,
+ const real_t massInvA,
+ const Vector3 &inertiaInvB,
+ const real_t massInvB) :
+ m_linearJointAxis(jointAxis) {
+ m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
+ m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ //angular constraint between two different rigidbodies
+ JacobianEntry3DSW(const Vector3 &jointAxis,
+ const Basis &world2A,
+ const Basis &world2B,
+ const Vector3 &inertiaInvA,
+ const Vector3 &inertiaInvB) :
+ m_linearJointAxis(Vector3(real_t(0.), real_t(0.), real_t(0.))) {
+ m_aJ = world2A.xform(jointAxis);
+ m_bJ = world2B.xform(-jointAxis);
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ //angular constraint between two different rigidbodies
+ JacobianEntry3DSW(const Vector3 &axisInA,
+ const Vector3 &axisInB,
+ const Vector3 &inertiaInvA,
+ const Vector3 &inertiaInvB) :
+ m_linearJointAxis(Vector3(real_t(0.), real_t(0.), real_t(0.))),
+ m_aJ(axisInA),
+ m_bJ(-axisInB) {
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ //constraint on one rigidbody
+ JacobianEntry3DSW(
+ const Basis &world2A,
+ const Vector3 &rel_pos1, const Vector3 &rel_pos2,
+ const Vector3 &jointAxis,
+ const Vector3 &inertiaInvA,
+ const real_t massInvA) :
+ m_linearJointAxis(jointAxis) {
+ m_aJ = world2A.xform(rel_pos1.cross(jointAxis));
+ m_bJ = world2A.xform(rel_pos2.cross(-jointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = Vector3(real_t(0.), real_t(0.), real_t(0.));
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ);
+
+ ERR_FAIL_COND(m_Adiag <= real_t(0.0));
+ }
+
+ real_t getDiagonal() const { return m_Adiag; }
+
+ // for two constraints on the same rigidbody (for example vehicle friction)
+ real_t getNonDiagonal(const JacobianEntry3DSW &jacB, const real_t massInvA) const {
+ const JacobianEntry3DSW &jacA = *this;
+ real_t lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis);
+ real_t ang = jacA.m_0MinvJt.dot(jacB.m_aJ);
+ return lin + ang;
+ }
+
+ // for two constraints on sharing two same rigidbodies (for example two contact points between two rigidbodies)
+ real_t getNonDiagonal(const JacobianEntry3DSW &jacB, const real_t massInvA, const real_t massInvB) const {
+ const JacobianEntry3DSW &jacA = *this;
+ Vector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis;
+ Vector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ;
+ Vector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ;
+ Vector3 lin0 = massInvA * lin;
+ Vector3 lin1 = massInvB * lin;
+ Vector3 sum = ang0 + ang1 + lin0 + lin1;
+ return sum[0] + sum[1] + sum[2];
+ }
+
+ real_t getRelativeVelocity(const Vector3 &linvelA, const Vector3 &angvelA, const Vector3 &linvelB, const Vector3 &angvelB) {
+ Vector3 linrel = linvelA - linvelB;
+ Vector3 angvela = angvelA * m_aJ;
+ Vector3 angvelb = angvelB * m_bJ;
+ linrel *= m_linearJointAxis;
+ angvela += angvelb;
+ angvela += linrel;
+ real_t rel_vel2 = angvela[0] + angvela[1] + angvela[2];
+ return rel_vel2 + CMP_EPSILON;
+ }
+ //private:
+
+ Vector3 m_linearJointAxis;
+ Vector3 m_aJ;
+ Vector3 m_bJ;
+ Vector3 m_0MinvJt;
+ Vector3 m_1MinvJt;
+ //Optimization: can be stored in the w/last component of one of the vectors
+ real_t m_Adiag;
+};
+
+#endif // JACOBIAN_ENTRY_SW_H
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
new file mode 100644
index 0000000000..95c01bc463
--- /dev/null
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
@@ -0,0 +1,167 @@
+/*************************************************************************/
+/* pin_joint_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+/*
+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.
+*/
+
+#include "pin_joint_3d_sw.h"
+
+bool PinJoint3DSW::setup(real_t p_step) {
+
+ m_appliedImpulse = real_t(0.);
+
+ Vector3 normal(0, 0, 0);
+
+ for (int i = 0; i < 3; i++) {
+ normal[i] = 1;
+ memnew_placement(&m_jac[i], JacobianEntry3DSW(
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ A->get_transform().xform(m_pivotInA) - A->get_transform().origin - A->get_center_of_mass(),
+ B->get_transform().xform(m_pivotInB) - B->get_transform().origin - B->get_center_of_mass(),
+ normal,
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+ normal[i] = 0;
+ }
+
+ return true;
+}
+
+void PinJoint3DSW::solve(real_t p_step) {
+
+ Vector3 pivotAInW = A->get_transform().xform(m_pivotInA);
+ Vector3 pivotBInW = B->get_transform().xform(m_pivotInB);
+
+ Vector3 normal(0, 0, 0);
+
+ //Vector3 angvelA = A->get_transform().origin.getBasis().transpose() * A->getAngularVelocity();
+ //Vector3 angvelB = B->get_transform().origin.getBasis().transpose() * B->getAngularVelocity();
+
+ for (int i = 0; i < 3; i++) {
+ normal[i] = 1;
+ real_t jacDiagABInv = real_t(1.) / m_jac[i].getDiagonal();
+
+ Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
+ Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
+ //this jacobian entry could be re-used for all iterations
+
+ Vector3 vel1 = A->get_velocity_in_local_point(rel_pos1);
+ Vector3 vel2 = B->get_velocity_in_local_point(rel_pos2);
+ Vector3 vel = vel1 - vel2;
+
+ real_t rel_vel;
+ rel_vel = normal.dot(vel);
+
+ /*
+ //velocity error (first order error)
+ real_t rel_vel = m_jac[i].getRelativeVelocity(A->getLinearVelocity(),angvelA,
+ B->getLinearVelocity(),angvelB);
+ */
+
+ //positional error (zeroth order error)
+ real_t depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
+
+ real_t impulse = depth * m_tau / p_step * jacDiagABInv - m_damping * rel_vel * jacDiagABInv;
+
+ real_t impulseClamp = m_impulseClamp;
+ if (impulseClamp > 0) {
+ if (impulse < -impulseClamp)
+ impulse = -impulseClamp;
+ if (impulse > impulseClamp)
+ impulse = impulseClamp;
+ }
+
+ m_appliedImpulse += impulse;
+ Vector3 impulse_vector = normal * impulse;
+ A->apply_impulse(pivotAInW - A->get_transform().origin, impulse_vector);
+ B->apply_impulse(pivotBInW - B->get_transform().origin, -impulse_vector);
+
+ normal[i] = 0;
+ }
+}
+
+void PinJoint3DSW::set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value) {
+
+ switch (p_param) {
+ case PhysicsServer3D::PIN_JOINT_BIAS: m_tau = p_value; break;
+ case PhysicsServer3D::PIN_JOINT_DAMPING: m_damping = p_value; break;
+ case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP: m_impulseClamp = p_value; break;
+ }
+}
+
+real_t PinJoint3DSW::get_param(PhysicsServer3D::PinJointParam p_param) const {
+
+ switch (p_param) {
+ case PhysicsServer3D::PIN_JOINT_BIAS: return m_tau;
+ case PhysicsServer3D::PIN_JOINT_DAMPING: return m_damping;
+ case PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP: return m_impulseClamp;
+ }
+
+ return 0;
+}
+
+PinJoint3DSW::PinJoint3DSW(Body3DSW *p_body_a, const Vector3 &p_pos_a, Body3DSW *p_body_b, const Vector3 &p_pos_b) :
+ Joint3DSW(_arr, 2) {
+
+ A = p_body_a;
+ B = p_body_b;
+ m_pivotInA = p_pos_a;
+ m_pivotInB = p_pos_b;
+
+ m_tau = 0.3;
+ m_damping = 1;
+ m_impulseClamp = 0;
+ m_appliedImpulse = 0;
+
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+}
+
+PinJoint3DSW::~PinJoint3DSW() {
+}
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h
new file mode 100644
index 0000000000..8e81ccf5e0
--- /dev/null
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* pin_joint_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+#ifndef PIN_JOINT_SW_H
+#define PIN_JOINT_SW_H
+
+#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h"
+#include "servers/physics_3d/joints_3d_sw.h"
+
+/*
+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.
+*/
+
+class PinJoint3DSW : public Joint3DSW {
+
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ real_t m_tau; //bias
+ real_t m_damping;
+ real_t m_impulseClamp;
+ real_t m_appliedImpulse;
+
+ JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints
+
+ Vector3 m_pivotInA;
+ Vector3 m_pivotInB;
+
+public:
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_PIN; }
+
+ virtual bool setup(real_t p_step);
+ virtual void solve(real_t p_step);
+
+ void set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::PinJointParam p_param) const;
+
+ void set_pos_a(const Vector3 &p_pos) { m_pivotInA = p_pos; }
+ void set_pos_b(const Vector3 &p_pos) { m_pivotInB = p_pos; }
+
+ Vector3 get_position_a() { return m_pivotInA; }
+ Vector3 get_position_b() { return m_pivotInB; }
+
+ PinJoint3DSW(Body3DSW *p_body_a, const Vector3 &p_pos_a, Body3DSW *p_body_b, const Vector3 &p_pos_b);
+ ~PinJoint3DSW();
+};
+
+#endif // PIN_JOINT_SW_H
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
new file mode 100644
index 0000000000..066c30e0f3
--- /dev/null
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
@@ -0,0 +1,443 @@
+/*************************************************************************/
+/* slider_joint_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+/*
+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.
+*/
+
+/*
+Added by Roman Ponomarev (rponom@gmail.com)
+April 04, 2008
+
+*/
+
+#include "slider_joint_3d_sw.h"
+
+//-----------------------------------------------------------------------------
+
+static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) {
+ real_t coeff_1 = Math_PI / 4.0f;
+ real_t coeff_2 = 3.0f * coeff_1;
+ real_t abs_y = Math::abs(y);
+ real_t angle;
+ if (x >= 0.0f) {
+ real_t r = (x - abs_y) / (x + abs_y);
+ angle = coeff_1 - coeff_1 * r;
+ } else {
+ real_t r = (x + abs_y) / (abs_y - x);
+ angle = coeff_2 - coeff_1 * r;
+ }
+ return (y < 0.0f) ? -angle : angle;
+}
+
+void SliderJoint3DSW::initParams() {
+ m_lowerLinLimit = real_t(1.0);
+ m_upperLinLimit = real_t(-1.0);
+ m_lowerAngLimit = real_t(0.);
+ m_upperAngLimit = real_t(0.);
+ m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingDirLin = real_t(0.);
+ m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingDirAng = real_t(0.);
+ m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
+ m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
+ m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
+ m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
+ m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
+ m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
+
+ m_poweredLinMotor = false;
+ m_targetLinMotorVelocity = real_t(0.);
+ m_maxLinMotorForce = real_t(0.);
+ m_accumulatedLinMotorImpulse = real_t(0.0);
+
+ m_poweredAngMotor = false;
+ m_targetAngMotorVelocity = real_t(0.);
+ m_maxAngMotorForce = real_t(0.);
+ m_accumulatedAngMotorImpulse = real_t(0.0);
+
+} // SliderJointSW::initParams()
+
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+
+SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB) :
+ Joint3DSW(_arr, 2),
+ m_frameInA(frameInA),
+ m_frameInB(frameInB) {
+
+ A = rbA;
+ B = rbB;
+
+ A->add_constraint(this, 0);
+ B->add_constraint(this, 1);
+
+ initParams();
+} // SliderJointSW::SliderJointSW()
+
+//-----------------------------------------------------------------------------
+
+bool SliderJoint3DSW::setup(real_t p_step) {
+
+ //calculate transforms
+ m_calculatedTransformA = A->get_transform() * m_frameInA;
+ m_calculatedTransformB = B->get_transform() * m_frameInB;
+ m_realPivotAInW = m_calculatedTransformA.origin;
+ m_realPivotBInW = m_calculatedTransformB.origin;
+ m_sliderAxis = m_calculatedTransformA.basis.get_axis(0); // along X
+ m_delta = m_realPivotBInW - m_realPivotAInW;
+ m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
+ m_relPosA = m_projPivotInW - A->get_transform().origin;
+ m_relPosB = m_realPivotBInW - B->get_transform().origin;
+ Vector3 normalWorld;
+ int i;
+ //linear part
+ for (i = 0; i < 3; i++) {
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ memnew_placement(&m_jacLin[i], JacobianEntry3DSW(
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ m_relPosA - A->get_center_of_mass(),
+ m_relPosB - B->get_center_of_mass(),
+ normalWorld,
+ A->get_inv_inertia(),
+ A->get_inv_mass(),
+ B->get_inv_inertia(),
+ B->get_inv_mass()));
+ m_jacLinDiagABInv[i] = real_t(1.) / m_jacLin[i].getDiagonal();
+ m_depth[i] = m_delta.dot(normalWorld);
+ }
+ testLinLimits();
+ // angular part
+ for (i = 0; i < 3; i++) {
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ memnew_placement(&m_jacAng[i], JacobianEntry3DSW(
+ normalWorld,
+ A->get_principal_inertia_axes().transposed(),
+ B->get_principal_inertia_axes().transposed(),
+ A->get_inv_inertia(),
+ B->get_inv_inertia()));
+ }
+ testAngLimits();
+ Vector3 axisA = m_calculatedTransformA.basis.get_axis(0);
+ m_kAngle = real_t(1.0) / (A->compute_angular_impulse_denominator(axisA) + B->compute_angular_impulse_denominator(axisA));
+ // clear accumulator for motors
+ m_accumulatedLinMotorImpulse = real_t(0.0);
+ m_accumulatedAngMotorImpulse = real_t(0.0);
+
+ return true;
+} // SliderJointSW::buildJacobianInt()
+
+//-----------------------------------------------------------------------------
+
+void SliderJoint3DSW::solve(real_t p_step) {
+
+ int i;
+ // linear
+ Vector3 velA = A->get_velocity_in_local_point(m_relPosA);
+ Vector3 velB = B->get_velocity_in_local_point(m_relPosB);
+ Vector3 vel = velA - velB;
+ for (i = 0; i < 3; i++) {
+ const Vector3 &normal = m_jacLin[i].m_linearJointAxis;
+ real_t rel_vel = normal.dot(vel);
+ // calculate positional error
+ real_t depth = m_depth[i];
+ // get parameters
+ real_t softness = (i) ? m_softnessOrthoLin : (m_solveLinLim ? m_softnessLimLin : m_softnessDirLin);
+ real_t restitution = (i) ? m_restitutionOrthoLin : (m_solveLinLim ? m_restitutionLimLin : m_restitutionDirLin);
+ real_t damping = (i) ? m_dampingOrthoLin : (m_solveLinLim ? m_dampingLimLin : m_dampingDirLin);
+ // calcutate and apply impulse
+ real_t normalImpulse = softness * (restitution * depth / p_step - damping * rel_vel) * m_jacLinDiagABInv[i];
+ Vector3 impulse_vector = normal * normalImpulse;
+ A->apply_impulse(m_relPosA, impulse_vector);
+ B->apply_impulse(m_relPosB, -impulse_vector);
+ if (m_poweredLinMotor && (!i)) { // apply linear motor
+ if (m_accumulatedLinMotorImpulse < m_maxLinMotorForce) {
+ real_t desiredMotorVel = m_targetLinMotorVelocity;
+ real_t motor_relvel = desiredMotorVel + rel_vel;
+ normalImpulse = -motor_relvel * m_jacLinDiagABInv[i];
+ // clamp accumulated impulse
+ real_t new_acc = m_accumulatedLinMotorImpulse + Math::abs(normalImpulse);
+ if (new_acc > m_maxLinMotorForce) {
+ new_acc = m_maxLinMotorForce;
+ }
+ real_t del = new_acc - m_accumulatedLinMotorImpulse;
+ if (normalImpulse < real_t(0.0)) {
+ normalImpulse = -del;
+ } else {
+ normalImpulse = del;
+ }
+ m_accumulatedLinMotorImpulse = new_acc;
+ // apply clamped impulse
+ impulse_vector = normal * normalImpulse;
+ A->apply_impulse(m_relPosA, impulse_vector);
+ B->apply_impulse(m_relPosB, -impulse_vector);
+ }
+ }
+ }
+ // angular
+ // get axes in world space
+ Vector3 axisA = m_calculatedTransformA.basis.get_axis(0);
+ Vector3 axisB = m_calculatedTransformB.basis.get_axis(0);
+
+ const Vector3 &angVelA = A->get_angular_velocity();
+ const Vector3 &angVelB = B->get_angular_velocity();
+
+ Vector3 angVelAroundAxisA = axisA * axisA.dot(angVelA);
+ Vector3 angVelAroundAxisB = axisB * axisB.dot(angVelB);
+
+ Vector3 angAorthog = angVelA - angVelAroundAxisA;
+ Vector3 angBorthog = angVelB - angVelAroundAxisB;
+ Vector3 velrelOrthog = angAorthog - angBorthog;
+ //solve orthogonal angular velocity correction
+ real_t len = velrelOrthog.length();
+ if (len > real_t(0.00001)) {
+ Vector3 normal = velrelOrthog.normalized();
+ real_t denom = A->compute_angular_impulse_denominator(normal) + B->compute_angular_impulse_denominator(normal);
+ velrelOrthog *= (real_t(1.) / denom) * m_dampingOrthoAng * m_softnessOrthoAng;
+ }
+ //solve angular positional correction
+ Vector3 angularError = axisA.cross(axisB) * (real_t(1.) / p_step);
+ real_t len2 = angularError.length();
+ if (len2 > real_t(0.00001)) {
+ Vector3 normal2 = angularError.normalized();
+ real_t denom2 = A->compute_angular_impulse_denominator(normal2) + B->compute_angular_impulse_denominator(normal2);
+ angularError *= (real_t(1.) / denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;
+ }
+ // apply impulse
+ A->apply_torque_impulse(-velrelOrthog + angularError);
+ B->apply_torque_impulse(velrelOrthog - angularError);
+ real_t impulseMag;
+ //solve angular limits
+ if (m_solveAngLim) {
+ impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingLimAng + m_angDepth * m_restitutionLimAng / p_step;
+ impulseMag *= m_kAngle * m_softnessLimAng;
+ } else {
+ impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingDirAng + m_angDepth * m_restitutionDirAng / p_step;
+ impulseMag *= m_kAngle * m_softnessDirAng;
+ }
+ Vector3 impulse = axisA * impulseMag;
+ A->apply_torque_impulse(impulse);
+ B->apply_torque_impulse(-impulse);
+ //apply angular motor
+ if (m_poweredAngMotor) {
+ if (m_accumulatedAngMotorImpulse < m_maxAngMotorForce) {
+ Vector3 velrel = angVelAroundAxisA - angVelAroundAxisB;
+ real_t projRelVel = velrel.dot(axisA);
+
+ real_t desiredMotorVel = m_targetAngMotorVelocity;
+ real_t motor_relvel = desiredMotorVel - projRelVel;
+
+ real_t angImpulse = m_kAngle * motor_relvel;
+ // clamp accumulated impulse
+ real_t new_acc = m_accumulatedAngMotorImpulse + Math::abs(angImpulse);
+ if (new_acc > m_maxAngMotorForce) {
+ new_acc = m_maxAngMotorForce;
+ }
+ real_t del = new_acc - m_accumulatedAngMotorImpulse;
+ if (angImpulse < real_t(0.0)) {
+ angImpulse = -del;
+ } else {
+ angImpulse = del;
+ }
+ m_accumulatedAngMotorImpulse = new_acc;
+ // apply clamped impulse
+ Vector3 motorImp = angImpulse * axisA;
+ A->apply_torque_impulse(motorImp);
+ B->apply_torque_impulse(-motorImp);
+ }
+ }
+} // SliderJointSW::solveConstraint()
+
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+
+void SliderJoint3DSW::calculateTransforms(void) {
+ m_calculatedTransformA = A->get_transform() * m_frameInA;
+ m_calculatedTransformB = B->get_transform() * m_frameInB;
+ m_realPivotAInW = m_calculatedTransformA.origin;
+ m_realPivotBInW = m_calculatedTransformB.origin;
+ m_sliderAxis = m_calculatedTransformA.basis.get_axis(0); // along X
+ m_delta = m_realPivotBInW - m_realPivotAInW;
+ m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
+ Vector3 normalWorld;
+ int i;
+ //linear part
+ for (i = 0; i < 3; i++) {
+ normalWorld = m_calculatedTransformA.basis.get_axis(i);
+ m_depth[i] = m_delta.dot(normalWorld);
+ }
+} // SliderJointSW::calculateTransforms()
+
+//-----------------------------------------------------------------------------
+
+void SliderJoint3DSW::testLinLimits(void) {
+ m_solveLinLim = false;
+ m_linPos = m_depth[0];
+ if (m_lowerLinLimit <= m_upperLinLimit) {
+ if (m_depth[0] > m_upperLinLimit) {
+ m_depth[0] -= m_upperLinLimit;
+ m_solveLinLim = true;
+ } else if (m_depth[0] < m_lowerLinLimit) {
+ m_depth[0] -= m_lowerLinLimit;
+ m_solveLinLim = true;
+ } else {
+ m_depth[0] = real_t(0.);
+ }
+ } else {
+ m_depth[0] = real_t(0.);
+ }
+} // SliderJointSW::testLinLimits()
+
+//-----------------------------------------------------------------------------
+
+void SliderJoint3DSW::testAngLimits(void) {
+ m_angDepth = real_t(0.);
+ m_solveAngLim = false;
+ if (m_lowerAngLimit <= m_upperAngLimit) {
+ const Vector3 axisA0 = m_calculatedTransformA.basis.get_axis(1);
+ const Vector3 axisA1 = m_calculatedTransformA.basis.get_axis(2);
+ const Vector3 axisB0 = m_calculatedTransformB.basis.get_axis(1);
+ real_t rot = atan2fast(axisB0.dot(axisA1), axisB0.dot(axisA0));
+ if (rot < m_lowerAngLimit) {
+ m_angDepth = rot - m_lowerAngLimit;
+ m_solveAngLim = true;
+ } else if (rot > m_upperAngLimit) {
+ m_angDepth = rot - m_upperAngLimit;
+ m_solveAngLim = true;
+ }
+ }
+} // SliderJointSW::testAngLimits()
+
+//-----------------------------------------------------------------------------
+
+Vector3 SliderJoint3DSW::getAncorInA(void) {
+ Vector3 ancorInA;
+ ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * real_t(0.5) * m_sliderAxis;
+ ancorInA = A->get_transform().inverse().xform(ancorInA);
+ return ancorInA;
+} // SliderJointSW::getAncorInA()
+
+//-----------------------------------------------------------------------------
+
+Vector3 SliderJoint3DSW::getAncorInB(void) {
+ Vector3 ancorInB;
+ ancorInB = m_frameInB.origin;
+ return ancorInB;
+} // SliderJointSW::getAncorInB();
+
+void SliderJoint3DSW::set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value) {
+
+ switch (p_param) {
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: m_upperLinLimit = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: m_lowerLinLimit = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: m_softnessLimLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: m_restitutionLimLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: m_dampingLimLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: m_softnessDirLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: m_restitutionDirLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: m_dampingDirLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoLin = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: m_dampingOrthoLin = p_value; break;
+
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: m_upperAngLimit = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: m_lowerAngLimit = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: m_softnessLimAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: m_restitutionLimAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: m_dampingLimAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: m_softnessDirAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: m_restitutionDirAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: m_dampingDirAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: m_softnessOrthoAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: m_restitutionOrthoAng = p_value; break;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: m_dampingOrthoAng = p_value; break;
+
+ case PhysicsServer3D::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning
+ }
+}
+
+real_t SliderJoint3DSW::get_param(PhysicsServer3D::SliderJointParam p_param) const {
+
+ switch (p_param) {
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return m_upperLinLimit;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return m_lowerLinLimit;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return m_softnessLimLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return m_restitutionLimLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return m_dampingLimLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return m_softnessDirLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return m_restitutionDirLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return m_dampingDirLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoLin;
+ case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return m_dampingOrthoLin;
+
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return m_upperAngLimit;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return m_lowerAngLimit;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return m_softnessLimAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return m_restitutionLimAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return m_dampingLimAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return m_softnessDirAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return m_restitutionDirAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return m_dampingDirAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return m_softnessOrthoAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return m_restitutionOrthoAng;
+ case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return m_dampingOrthoAng;
+
+ case PhysicsServer3D::SLIDER_JOINT_MAX: break; // Can't happen, but silences warning
+ }
+
+ return 0;
+}
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h
new file mode 100644
index 0000000000..18287db9c2
--- /dev/null
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.h
@@ -0,0 +1,249 @@
+/*************************************************************************/
+/* slider_joint_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+/*
+Adapted to Godot from the Bullet library.
+*/
+
+#ifndef SLIDER_JOINT_SW_H
+#define SLIDER_JOINT_SW_H
+
+#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h"
+#include "servers/physics_3d/joints_3d_sw.h"
+
+/*
+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.
+*/
+
+/*
+Added by Roman Ponomarev (rponom@gmail.com)
+April 04, 2008
+
+*/
+
+#define SLIDER_CONSTRAINT_DEF_SOFTNESS (real_t(1.0))
+#define SLIDER_CONSTRAINT_DEF_DAMPING (real_t(1.0))
+#define SLIDER_CONSTRAINT_DEF_RESTITUTION (real_t(0.7))
+
+//-----------------------------------------------------------------------------
+
+class SliderJoint3DSW : public Joint3DSW {
+protected:
+ union {
+ struct {
+ Body3DSW *A;
+ Body3DSW *B;
+ };
+
+ Body3DSW *_arr[2];
+ };
+
+ Transform m_frameInA;
+ Transform m_frameInB;
+
+ // linear limits
+ real_t m_lowerLinLimit;
+ real_t m_upperLinLimit;
+ // angular limits
+ real_t m_lowerAngLimit;
+ real_t m_upperAngLimit;
+ // softness, restitution and damping for different cases
+ // DirLin - moving inside linear limits
+ // LimLin - hitting linear limit
+ // DirAng - moving inside angular limits
+ // LimAng - hitting angular limit
+ // OrthoLin, OrthoAng - against constraint axis
+ real_t m_softnessDirLin;
+ real_t m_restitutionDirLin;
+ real_t m_dampingDirLin;
+ real_t m_softnessDirAng;
+ real_t m_restitutionDirAng;
+ real_t m_dampingDirAng;
+ real_t m_softnessLimLin;
+ real_t m_restitutionLimLin;
+ real_t m_dampingLimLin;
+ real_t m_softnessLimAng;
+ real_t m_restitutionLimAng;
+ real_t m_dampingLimAng;
+ real_t m_softnessOrthoLin;
+ real_t m_restitutionOrthoLin;
+ real_t m_dampingOrthoLin;
+ real_t m_softnessOrthoAng;
+ real_t m_restitutionOrthoAng;
+ real_t m_dampingOrthoAng;
+
+ // for interlal use
+ bool m_solveLinLim;
+ bool m_solveAngLim;
+
+ JacobianEntry3DSW m_jacLin[3];
+ real_t m_jacLinDiagABInv[3];
+
+ JacobianEntry3DSW m_jacAng[3];
+
+ real_t m_timeStep;
+ Transform m_calculatedTransformA;
+ Transform m_calculatedTransformB;
+
+ Vector3 m_sliderAxis;
+ Vector3 m_realPivotAInW;
+ Vector3 m_realPivotBInW;
+ Vector3 m_projPivotInW;
+ Vector3 m_delta;
+ Vector3 m_depth;
+ Vector3 m_relPosA;
+ Vector3 m_relPosB;
+
+ real_t m_linPos;
+
+ real_t m_angDepth;
+ real_t m_kAngle;
+
+ bool m_poweredLinMotor;
+ real_t m_targetLinMotorVelocity;
+ real_t m_maxLinMotorForce;
+ real_t m_accumulatedLinMotorImpulse;
+
+ bool m_poweredAngMotor;
+ real_t m_targetAngMotorVelocity;
+ real_t m_maxAngMotorForce;
+ real_t m_accumulatedAngMotorImpulse;
+
+ //------------------------
+ void initParams();
+
+public:
+ // constructors
+ SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB);
+ //SliderJointSW();
+ // overrides
+
+ // access
+ const Body3DSW *getRigidBodyA() const { return A; }
+ const Body3DSW *getRigidBodyB() const { return B; }
+ const Transform &getCalculatedTransformA() const { return m_calculatedTransformA; }
+ const Transform &getCalculatedTransformB() const { return m_calculatedTransformB; }
+ const Transform &getFrameOffsetA() const { return m_frameInA; }
+ const Transform &getFrameOffsetB() const { return m_frameInB; }
+ Transform &getFrameOffsetA() { return m_frameInA; }
+ Transform &getFrameOffsetB() { return m_frameInB; }
+ real_t getLowerLinLimit() { return m_lowerLinLimit; }
+ void setLowerLinLimit(real_t lowerLimit) { m_lowerLinLimit = lowerLimit; }
+ real_t getUpperLinLimit() { return m_upperLinLimit; }
+ void setUpperLinLimit(real_t upperLimit) { m_upperLinLimit = upperLimit; }
+ real_t getLowerAngLimit() { return m_lowerAngLimit; }
+ void setLowerAngLimit(real_t lowerLimit) { m_lowerAngLimit = lowerLimit; }
+ real_t getUpperAngLimit() { return m_upperAngLimit; }
+ void setUpperAngLimit(real_t upperLimit) { m_upperAngLimit = upperLimit; }
+
+ real_t getSoftnessDirLin() { return m_softnessDirLin; }
+ real_t getRestitutionDirLin() { return m_restitutionDirLin; }
+ real_t getDampingDirLin() { return m_dampingDirLin; }
+ real_t getSoftnessDirAng() { return m_softnessDirAng; }
+ real_t getRestitutionDirAng() { return m_restitutionDirAng; }
+ real_t getDampingDirAng() { return m_dampingDirAng; }
+ real_t getSoftnessLimLin() { return m_softnessLimLin; }
+ real_t getRestitutionLimLin() { return m_restitutionLimLin; }
+ real_t getDampingLimLin() { return m_dampingLimLin; }
+ real_t getSoftnessLimAng() { return m_softnessLimAng; }
+ real_t getRestitutionLimAng() { return m_restitutionLimAng; }
+ real_t getDampingLimAng() { return m_dampingLimAng; }
+ real_t getSoftnessOrthoLin() { return m_softnessOrthoLin; }
+ real_t getRestitutionOrthoLin() { return m_restitutionOrthoLin; }
+ real_t getDampingOrthoLin() { return m_dampingOrthoLin; }
+ real_t getSoftnessOrthoAng() { return m_softnessOrthoAng; }
+ real_t getRestitutionOrthoAng() { return m_restitutionOrthoAng; }
+ real_t getDampingOrthoAng() { return m_dampingOrthoAng; }
+ void setSoftnessDirLin(real_t softnessDirLin) { m_softnessDirLin = softnessDirLin; }
+ void setRestitutionDirLin(real_t restitutionDirLin) { m_restitutionDirLin = restitutionDirLin; }
+ void setDampingDirLin(real_t dampingDirLin) { m_dampingDirLin = dampingDirLin; }
+ void setSoftnessDirAng(real_t softnessDirAng) { m_softnessDirAng = softnessDirAng; }
+ void setRestitutionDirAng(real_t restitutionDirAng) { m_restitutionDirAng = restitutionDirAng; }
+ void setDampingDirAng(real_t dampingDirAng) { m_dampingDirAng = dampingDirAng; }
+ void setSoftnessLimLin(real_t softnessLimLin) { m_softnessLimLin = softnessLimLin; }
+ void setRestitutionLimLin(real_t restitutionLimLin) { m_restitutionLimLin = restitutionLimLin; }
+ void setDampingLimLin(real_t dampingLimLin) { m_dampingLimLin = dampingLimLin; }
+ void setSoftnessLimAng(real_t softnessLimAng) { m_softnessLimAng = softnessLimAng; }
+ void setRestitutionLimAng(real_t restitutionLimAng) { m_restitutionLimAng = restitutionLimAng; }
+ void setDampingLimAng(real_t dampingLimAng) { m_dampingLimAng = dampingLimAng; }
+ void setSoftnessOrthoLin(real_t softnessOrthoLin) { m_softnessOrthoLin = softnessOrthoLin; }
+ void setRestitutionOrthoLin(real_t restitutionOrthoLin) { m_restitutionOrthoLin = restitutionOrthoLin; }
+ void setDampingOrthoLin(real_t dampingOrthoLin) { m_dampingOrthoLin = dampingOrthoLin; }
+ void setSoftnessOrthoAng(real_t softnessOrthoAng) { m_softnessOrthoAng = softnessOrthoAng; }
+ void setRestitutionOrthoAng(real_t restitutionOrthoAng) { m_restitutionOrthoAng = restitutionOrthoAng; }
+ void setDampingOrthoAng(real_t dampingOrthoAng) { m_dampingOrthoAng = dampingOrthoAng; }
+ void setPoweredLinMotor(bool onOff) { m_poweredLinMotor = onOff; }
+ bool getPoweredLinMotor() { return m_poweredLinMotor; }
+ void setTargetLinMotorVelocity(real_t targetLinMotorVelocity) { m_targetLinMotorVelocity = targetLinMotorVelocity; }
+ real_t getTargetLinMotorVelocity() { return m_targetLinMotorVelocity; }
+ void setMaxLinMotorForce(real_t maxLinMotorForce) { m_maxLinMotorForce = maxLinMotorForce; }
+ real_t getMaxLinMotorForce() { return m_maxLinMotorForce; }
+ void setPoweredAngMotor(bool onOff) { m_poweredAngMotor = onOff; }
+ bool getPoweredAngMotor() { return m_poweredAngMotor; }
+ void setTargetAngMotorVelocity(real_t targetAngMotorVelocity) { m_targetAngMotorVelocity = targetAngMotorVelocity; }
+ real_t getTargetAngMotorVelocity() { return m_targetAngMotorVelocity; }
+ void setMaxAngMotorForce(real_t maxAngMotorForce) { m_maxAngMotorForce = maxAngMotorForce; }
+ real_t getMaxAngMotorForce() { return m_maxAngMotorForce; }
+ real_t getLinearPos() { return m_linPos; }
+
+ // access for ODE solver
+ bool getSolveLinLimit() { return m_solveLinLim; }
+ real_t getLinDepth() { return m_depth[0]; }
+ bool getSolveAngLimit() { return m_solveAngLim; }
+ real_t getAngDepth() { return m_angDepth; }
+ // shared code used by ODE solver
+ void calculateTransforms(void);
+ void testLinLimits(void);
+ void testAngLimits(void);
+ // access for PE Solver
+ Vector3 getAncorInA(void);
+ Vector3 getAncorInB(void);
+
+ void set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::SliderJointParam p_param) const;
+
+ bool setup(real_t p_step);
+ void solve(real_t p_step);
+
+ virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; }
+};
+
+#endif // SLIDER_JOINT_SW_H
diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h
new file mode 100644
index 0000000000..0f2d4892a8
--- /dev/null
+++ b/servers/physics_3d/joints_3d_sw.h
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* joints_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 JOINTS_SW_H
+#define JOINTS_SW_H
+
+#include "body_3d_sw.h"
+#include "constraint_3d_sw.h"
+
+class Joint3DSW : public Constraint3DSW {
+
+public:
+ virtual PhysicsServer3D::JointType get_type() const = 0;
+ _FORCE_INLINE_ Joint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
+ Constraint3DSW(p_body_ptr, p_body_count) {
+ }
+};
+
+#endif // JOINTS_SW_H
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
new file mode 100644
index 0000000000..d8da6e715b
--- /dev/null
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -0,0 +1,1589 @@
+/*************************************************************************/
+/* physics_server_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_sw.h"
+
+#include "broad_phase_3d_basic.h"
+#include "broad_phase_octree.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/os/os.h"
+#include "joints/cone_twist_joint_3d_sw.h"
+#include "joints/generic_6dof_joint_3d_sw.h"
+#include "joints/hinge_joint_3d_sw.h"
+#include "joints/pin_joint_3d_sw.h"
+#include "joints/slider_joint_3d_sw.h"
+
+#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;
+};
+
+void PhysicsServer3DSW::shape_set_data(RID p_shape, const Variant &p_data) {
+
+ Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_data(p_data);
+};
+
+void PhysicsServer3DSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
+
+ Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_custom_bias(p_bias);
+}
+
+PhysicsServer3D::ShapeType PhysicsServer3DSW::shape_get_type(RID p_shape) const {
+
+ const Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM);
+ return shape->get_type();
+};
+
+Variant PhysicsServer3DSW::shape_get_data(RID p_shape) const {
+
+ const Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, Variant());
+ ERR_FAIL_COND_V(!shape->is_configured(), Variant());
+ return shape->get_data();
+};
+
+void PhysicsServer3DSW::shape_set_margin(RID p_shape, real_t p_margin) {
+}
+
+real_t PhysicsServer3DSW::shape_get_margin(RID p_shape) const {
+ return 0.0;
+}
+
+real_t PhysicsServer3DSW::shape_get_custom_solver_bias(RID p_shape) const {
+
+ const Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, 0);
+ return shape->get_custom_bias();
+}
+
+RID PhysicsServer3DSW::space_create() {
+
+ Space3DSW *space = memnew(Space3DSW);
+ RID id = space_owner.make_rid(space);
+ space->set_self(id);
+ RID area_id = area_create();
+ Area3DSW *area = area_owner.getornull(area_id);
+ ERR_FAIL_COND_V(!area, RID());
+ space->set_default_area(area);
+ area->set_space(space);
+ area->set_priority(-1);
+ RID sgb = body_create();
+ body_set_space(sgb, id);
+ body_set_mode(sgb, BODY_MODE_STATIC);
+ space->set_static_global_body(sgb);
+
+ return id;
+};
+
+void PhysicsServer3DSW::space_set_active(RID p_space, bool p_active) {
+
+ Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ if (p_active)
+ active_spaces.insert(space);
+ else
+ active_spaces.erase(space);
+}
+
+bool PhysicsServer3DSW::space_is_active(RID p_space) const {
+
+ const Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, false);
+
+ return active_spaces.has(space);
+}
+
+void PhysicsServer3DSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
+
+ Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+
+ space->set_param(p_param, p_value);
+}
+
+real_t PhysicsServer3DSW::space_get_param(RID p_space, SpaceParameter p_param) const {
+
+ const Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_param(p_param);
+}
+
+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(!doing_sync || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification.");
+
+ return space->get_direct_state();
+}
+
+void PhysicsServer3DSW::space_set_debug_contacts(RID p_space, int p_max_contacts) {
+
+ Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ space->set_debug_contacts(p_max_contacts);
+}
+
+Vector<Vector3> PhysicsServer3DSW::space_get_contacts(RID p_space) const {
+
+ Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, Vector<Vector3>());
+ return space->get_debug_contacts();
+}
+
+int PhysicsServer3DSW::space_get_contact_count(RID p_space) const {
+
+ Space3DSW *space = space_owner.getornull(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_debug_contact_count();
+}
+
+RID PhysicsServer3DSW::area_create() {
+
+ Area3DSW *area = memnew(Area3DSW);
+ RID rid = area_owner.make_rid(area);
+ area->set_self(rid);
+ return rid;
+};
+
+void PhysicsServer3DSW::area_set_space(RID p_area, RID p_space) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ Space3DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (area->get_space() == space)
+ return; //pointless
+
+ area->clear_constraints();
+ area->set_space(space);
+};
+
+RID PhysicsServer3DSW::area_get_space(RID p_area) const {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ Space3DSW *space = area->get_space();
+ if (!space)
+ return RID();
+ return space->get_self();
+};
+
+void PhysicsServer3DSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_space_override_mode(p_mode);
+}
+
+PhysicsServer3D::AreaSpaceOverrideMode PhysicsServer3DSW::area_get_space_override_mode(RID p_area) const {
+
+ const Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED);
+
+ return area->get_space_override_mode();
+}
+
+void PhysicsServer3DSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ area->add_shape(shape, p_transform, p_disabled);
+}
+
+void PhysicsServer3DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ ERR_FAIL_COND(!shape->is_configured());
+
+ area->set_shape(p_shape_idx, shape);
+}
+
+void PhysicsServer3DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_shape_transform(p_shape_idx, p_transform);
+}
+
+int PhysicsServer3DSW::area_get_shape_count(RID p_area) const {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, -1);
+
+ return area->get_shape_count();
+}
+RID PhysicsServer3DSW::area_get_shape(RID p_area, int p_shape_idx) const {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ Shape3DSW *shape = area->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+Transform PhysicsServer3DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, Transform());
+
+ return area->get_shape_transform(p_shape_idx);
+}
+
+void PhysicsServer3DSW::area_remove_shape(RID p_area, int p_shape_idx) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->remove_shape(p_shape_idx);
+}
+
+void PhysicsServer3DSW::area_clear_shapes(RID p_area) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ while (area->get_shape_count())
+ area->remove_shape(0);
+}
+
+void PhysicsServer3DSW::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count());
+ FLUSH_QUERY_CHECK(area);
+ area->set_shape_as_disabled(p_shape_idx, p_disabled);
+}
+
+void PhysicsServer3DSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) {
+
+ if (space_owner.owns(p_area)) {
+ Space3DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_instance_id(p_id);
+}
+ObjectID PhysicsServer3DSW::area_get_object_instance_id(RID p_area) const {
+
+ if (space_owner.owns(p_area)) {
+ Space3DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, ObjectID());
+ return area->get_instance_id();
+}
+
+void PhysicsServer3DSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
+
+ if (space_owner.owns(p_area)) {
+ Space3DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_param(p_param, p_value);
+};
+
+void PhysicsServer3DSW::area_set_transform(RID p_area, const Transform &p_transform) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_transform(p_transform);
+};
+
+Variant PhysicsServer3DSW::area_get_param(RID p_area, AreaParameter p_param) const {
+
+ if (space_owner.owns(p_area)) {
+ Space3DSW *space = space_owner.getornull(p_area);
+ p_area = space->get_default_area()->get_self();
+ }
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, Variant());
+
+ return area->get_param(p_param);
+};
+
+Transform PhysicsServer3DSW::area_get_transform(RID p_area) const {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND_V(!area, Transform());
+
+ return area->get_transform();
+};
+
+void PhysicsServer3DSW::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_layer(p_layer);
+}
+
+void PhysicsServer3DSW::area_set_collision_mask(RID p_area, uint32_t p_mask) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_collision_mask(p_mask);
+}
+
+void PhysicsServer3DSW::area_set_monitorable(RID p_area, bool p_monitorable) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+ FLUSH_QUERY_CHECK(area);
+
+ area->set_monitorable(p_monitorable);
+}
+
+void PhysicsServer3DSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
+}
+
+void PhysicsServer3DSW::area_set_ray_pickable(RID p_area, bool p_enable) {
+
+ Area3DSW *area = area_owner.getornull(p_area);
+ ERR_FAIL_COND(!area);
+
+ 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);
+
+ area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
+}
+
+/* BODY API */
+
+RID PhysicsServer3DSW::body_create(BodyMode p_mode, bool p_init_sleeping) {
+
+ 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;
+};
+
+void PhysicsServer3DSW::body_set_space(RID p_body, RID p_space) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ Space3DSW *space = nullptr;
+ if (p_space.is_valid()) {
+ space = space_owner.getornull(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (body->get_space() == space)
+ return; //pointless
+
+ body->clear_constraint_map();
+ body->set_space(space);
+};
+
+RID PhysicsServer3DSW::body_get_space(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ Space3DSW *space = body->get_space();
+ if (!space)
+ return RID();
+ return space->get_self();
+};
+
+void PhysicsServer3DSW::body_set_mode(RID p_body, BodyMode p_mode) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_mode(p_mode);
+};
+
+PhysicsServer3D::BodyMode PhysicsServer3DSW::body_get_mode(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
+
+ return body->get_mode();
+};
+
+void PhysicsServer3DSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ body->add_shape(shape, p_transform, p_disabled);
+}
+
+void PhysicsServer3DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ Shape3DSW *shape = shape_owner.getornull(p_shape);
+ ERR_FAIL_COND(!shape);
+ ERR_FAIL_COND(!shape->is_configured());
+
+ body->set_shape(p_shape_idx, shape);
+}
+void PhysicsServer3DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_shape_transform(p_shape_idx, p_transform);
+}
+
+int PhysicsServer3DSW::body_get_shape_count(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, -1);
+
+ return body->get_shape_count();
+}
+RID PhysicsServer3DSW::body_get_shape(RID p_body, int p_shape_idx) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ Shape3DSW *shape = body->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+
+void PhysicsServer3DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
+ FLUSH_QUERY_CHECK(body);
+
+ body->set_shape_as_disabled(p_shape_idx, p_disabled);
+}
+
+Transform PhysicsServer3DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Transform());
+
+ return body->get_shape_transform(p_shape_idx);
+}
+
+void PhysicsServer3DSW::body_remove_shape(RID p_body, int p_shape_idx) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_shape(p_shape_idx);
+}
+
+void PhysicsServer3DSW::body_clear_shapes(RID p_body) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ while (body->get_shape_count())
+ body->remove_shape(0);
+}
+
+void PhysicsServer3DSW::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_continuous_collision_detection(p_enable);
+}
+
+bool PhysicsServer3DSW::body_is_continuous_collision_detection_enabled(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+
+ return body->is_continuous_collision_detection_enabled();
+}
+
+void PhysicsServer3DSW::body_set_collision_layer(RID p_body, uint32_t p_layer) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_layer(p_layer);
+ body->wakeup();
+}
+
+uint32_t PhysicsServer3DSW::body_get_collision_layer(RID p_body) const {
+
+ const Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_layer();
+}
+
+void PhysicsServer3DSW::body_set_collision_mask(RID p_body, uint32_t p_mask) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_mask(p_mask);
+ body->wakeup();
+}
+
+uint32_t PhysicsServer3DSW::body_get_collision_mask(RID p_body) const {
+
+ const Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_mask();
+}
+
+void PhysicsServer3DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_instance_id(p_id);
+};
+
+ObjectID PhysicsServer3DSW::body_get_object_instance_id(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, ObjectID());
+
+ return body->get_instance_id();
+};
+
+void PhysicsServer3DSW::body_set_user_flags(RID p_body, uint32_t p_flags) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+};
+
+uint32_t PhysicsServer3DSW::body_get_user_flags(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return 0;
+};
+
+void PhysicsServer3DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_param(p_param, p_value);
+};
+
+real_t PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_param(p_param);
+};
+
+void PhysicsServer3DSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_kinematic_margin(p_margin);
+}
+
+real_t PhysicsServer3DSW::body_get_kinematic_safe_margin(RID p_body) const {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_kinematic_margin();
+}
+
+void PhysicsServer3DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_state(p_state, p_variant);
+};
+
+Variant PhysicsServer3DSW::body_get_state(RID p_body, BodyState p_state) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Variant());
+
+ return body->get_state(p_state);
+};
+
+void PhysicsServer3DSW::body_set_applied_force(RID p_body, const Vector3 &p_force) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_applied_force(p_force);
+ body->wakeup();
+};
+
+Vector3 PhysicsServer3DSW::body_get_applied_force(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Vector3());
+ return body->get_applied_force();
+};
+
+void PhysicsServer3DSW::body_set_applied_torque(RID p_body, const Vector3 &p_torque) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_applied_torque(p_torque);
+ body->wakeup();
+};
+
+Vector3 PhysicsServer3DSW::body_get_applied_torque(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, Vector3());
+
+ return body->get_applied_torque();
+};
+
+void PhysicsServer3DSW::body_add_central_force(RID p_body, const Vector3 &p_force) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_central_force(p_force);
+ body->wakeup();
+}
+
+void PhysicsServer3DSW::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_force(p_force, p_pos);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_add_torque(RID p_body, const Vector3 &p_torque) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_torque(p_torque);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) {
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_central_impulse(p_impulse);
+ body->wakeup();
+}
+
+void PhysicsServer3DSW::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_impulse(p_pos, p_impulse);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ body->apply_torque_impulse(p_impulse);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ _update_shapes();
+
+ Vector3 v = body->get_linear_velocity();
+ Vector3 axis = p_axis_velocity.normalized();
+ v -= axis * axis.dot(v);
+ v += p_axis_velocity;
+ body->set_linear_velocity(v);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_axis_lock(p_axis, p_lock);
+ body->wakeup();
+}
+
+bool PhysicsServer3DSW::body_is_axis_locked(RID p_body, BodyAxis p_axis) const {
+
+ const Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+ return body->is_axis_locked(p_axis);
+}
+
+void PhysicsServer3DSW::body_add_collision_exception(RID p_body, RID p_body_b) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->add_exception(p_body_b);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_remove_collision_exception(RID p_body, RID p_body_b) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_exception(p_body_b);
+ body->wakeup();
+};
+
+void PhysicsServer3DSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ for (int i = 0; i < body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(body->get_exceptions()[i]);
+ }
+};
+
+void PhysicsServer3DSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+};
+
+real_t PhysicsServer3DSW::body_get_contacts_reported_depth_threshold(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+ return 0;
+};
+
+void PhysicsServer3DSW::body_set_omit_force_integration(RID p_body, bool p_omit) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_omit_force_integration(p_omit);
+};
+
+bool PhysicsServer3DSW::body_is_omitting_force_integration(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ return body->get_omit_force_integration();
+};
+
+void PhysicsServer3DSW::body_set_max_contacts_reported(RID p_body, int p_contacts) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_max_contacts_reported(p_contacts);
+}
+
+int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, -1);
+ 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) {
+
+ 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);
+}
+
+void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND(!body);
+ 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);
+ ERR_FAIL_COND_V(!body->get_space(), false);
+ ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
+
+ _update_shapes();
+
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result, p_exclude_raycast_shapes);
+}
+
+int PhysicsServer3DSW::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, float p_margin) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_COND_V(!body->get_space(), false);
+ ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
+
+ _update_shapes();
+
+ return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+}
+
+PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
+
+ Body3DSW *body = body_owner.getornull(p_body);
+ ERR_FAIL_COND_V(!body, nullptr);
+ ERR_FAIL_COND_V_MSG(!doing_sync || body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification.");
+
+ direct_state->body = body;
+ return direct_state;
+}
+
+/* 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) {
+
+ Body3DSW *body_A = body_owner.getornull(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ 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_V(body_A == body_B, RID());
+
+ 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;
+}
+
+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);
+ PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
+ pin_joint->set_param(p_param, p_value);
+}
+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);
+ PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
+ return pin_joint->get_param(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);
+ PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
+ pin_joint->set_pos_a(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());
+ PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
+ return pin_joint->get_position_a();
+}
+
+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);
+ PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint);
+ pin_joint->set_pos_b(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());
+ 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) {
+
+ Body3DSW *body_A = body_owner.getornull(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ 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_V(body_A == body_B, RID());
+
+ 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;
+}
+
+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) {
+
+ Body3DSW *body_A = body_owner.getornull(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ 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_V(body_A == body_B, RID());
+
+ 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;
+}
+
+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);
+ HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
+ hinge_joint->set_param(p_param, p_value);
+}
+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);
+ HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
+ return hinge_joint->get_param(p_param);
+}
+
+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);
+ HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
+ hinge_joint->set_flag(p_flag, p_value);
+}
+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);
+ HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint);
+ return hinge_joint->get_flag(p_flag);
+}
+
+void PhysicsServer3DSW::joint_set_solver_priority(RID p_joint, int p_priority) {
+
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(!joint);
+ joint->set_priority(p_priority);
+}
+
+int PhysicsServer3DSW::joint_get_solver_priority(RID p_joint) const {
+
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, 0);
+ return joint->get_priority();
+}
+
+void PhysicsServer3DSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND(!joint);
+
+ joint->disable_collisions_between_bodies(p_disable);
+
+ if (2 == joint->get_body_count()) {
+ Body3DSW *body_a = *joint->get_body_ptr();
+ Body3DSW *body_b = *(joint->get_body_ptr() + 1);
+
+ if (p_disable) {
+ body_add_collision_exception(body_a->get_self(), body_b->get_self());
+ body_add_collision_exception(body_b->get_self(), body_a->get_self());
+ } else {
+ body_remove_collision_exception(body_a->get_self(), body_b->get_self());
+ body_remove_collision_exception(body_b->get_self(), body_a->get_self());
+ }
+ }
+}
+
+bool PhysicsServer3DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, true);
+
+ return joint->is_disabled_collisions_between_bodies();
+}
+
+PhysicsServer3DSW::JointType PhysicsServer3DSW::joint_get_type(RID p_joint) const {
+
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, JOINT_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) {
+
+ Body3DSW *body_A = body_owner.getornull(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ 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_V(body_A == body_B, RID());
+
+ 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;
+}
+
+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);
+ SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint);
+ slider_joint->set_param(p_param, p_value);
+}
+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);
+ 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) {
+
+ Body3DSW *body_A = body_owner.getornull(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ 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_V(body_A == body_B, RID());
+
+ 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;
+}
+
+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);
+ ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint);
+ cone_twist_joint->set_param(p_param, p_value);
+}
+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);
+ 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) {
+
+ Body3DSW *body_A = body_owner.getornull(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ if (!p_body_B.is_valid()) {
+ ERR_FAIL_COND_V(!body_A->get_space(), RID());
+ 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_V(body_A == body_B, RID());
+
+ 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;
+}
+
+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);
+ 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) {
+
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
+ Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint);
+ return generic_6dof_joint->get_param(p_axis, p_param);
+}
+
+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);
+ 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) {
+
+ Joint3DSW *joint = joint_owner.getornull(p_joint);
+ ERR_FAIL_COND_V(!joint, false);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false);
+ Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint);
+ return generic_6dof_joint->get_flag(p_axis, p_flag);
+}
+
+void PhysicsServer3DSW::free(RID p_rid) {
+
+ _update_shapes(); //just in case
+
+ if (shape_owner.owns(p_rid)) {
+
+ Shape3DSW *shape = shape_owner.getornull(p_rid);
+
+ while (shape->get_owners().size()) {
+ ShapeOwner3DSW *so = shape->get_owners().front()->key();
+ so->remove_shape(shape);
+ }
+
+ shape_owner.free(p_rid);
+ memdelete(shape);
+ } else if (body_owner.owns(p_rid)) {
+
+ Body3DSW *body = body_owner.getornull(p_rid);
+
+ /*
+ if (body->get_state_query())
+ _clear_query(body->get_state_query());
+
+ if (body->get_direct_state_query())
+ _clear_query(body->get_direct_state_query());
+ */
+
+ body->set_space(nullptr);
+
+ while (body->get_shape_count()) {
+
+ body->remove_shape(0);
+ }
+
+ body_owner.free(p_rid);
+ memdelete(body);
+
+ } else if (area_owner.owns(p_rid)) {
+
+ Area3DSW *area = area_owner.getornull(p_rid);
+
+ /*
+ if (area->get_monitor_query())
+ _clear_query(area->get_monitor_query());
+ */
+
+ area->set_space(nullptr);
+
+ while (area->get_shape_count()) {
+
+ area->remove_shape(0);
+ }
+
+ area_owner.free(p_rid);
+ memdelete(area);
+ } else if (space_owner.owns(p_rid)) {
+
+ Space3DSW *space = space_owner.getornull(p_rid);
+
+ while (space->get_objects().size()) {
+ CollisionObject3DSW *co = (CollisionObject3DSW *)space->get_objects().front()->get();
+ co->set_space(nullptr);
+ }
+
+ active_spaces.erase(space);
+ free(space->get_default_area()->get_self());
+ free(space->get_static_global_body());
+
+ space_owner.free(p_rid);
+ memdelete(space);
+ } 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);
+
+ } else {
+
+ ERR_FAIL_MSG("Invalid ID.");
+ }
+};
+
+void PhysicsServer3DSW::set_active(bool p_active) {
+
+ active = p_active;
+};
+
+void PhysicsServer3DSW::init() {
+
+ doing_sync = true;
+ last_step = 0.001;
+ iterations = 8; // 8?
+ stepper = memnew(Step3DSW);
+ direct_state = memnew(PhysicsDirectBodyState3DSW);
+};
+
+void PhysicsServer3DSW::step(real_t p_step) {
+
+#ifndef _3D_DISABLED
+
+ if (!active)
+ return;
+
+ _update_shapes();
+
+ doing_sync = false;
+
+ last_step = p_step;
+ PhysicsDirectBodyState3DSW::singleton->step = p_step;
+
+ island_count = 0;
+ active_objects = 0;
+ collision_pairs = 0;
+ for (Set<const Space3DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
+
+ stepper->step((Space3DSW *)E->get(), p_step, iterations);
+ island_count += E->get()->get_island_count();
+ active_objects += E->get()->get_active_objects();
+ collision_pairs += E->get()->get_collision_pairs();
+ }
+#endif
+}
+
+void PhysicsServer3DSW::sync(){
+
+};
+
+void PhysicsServer3DSW::flush_queries() {
+
+#ifndef _3D_DISABLED
+
+ if (!active)
+ return;
+
+ doing_sync = true;
+
+ flushing_queries = true;
+
+ uint64_t time_beg = OS::get_singleton()->get_ticks_usec();
+
+ for (Set<const Space3DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
+
+ Space3DSW *space = (Space3DSW *)E->get();
+ space->call_queries();
+ }
+
+ flushing_queries = false;
+
+ if (EngineDebugger::is_profiling("servers")) {
+
+ uint64_t total_time[Space3DSW::ELAPSED_TIME_MAX];
+ static const char *time_name[Space3DSW::ELAPSED_TIME_MAX] = {
+ "integrate_forces",
+ "generate_islands",
+ "setup_constraints",
+ "solve_constraints",
+ "integrate_velocities"
+ };
+
+ for (int i = 0; i < Space3DSW::ELAPSED_TIME_MAX; i++) {
+ total_time[i] = 0;
+ }
+
+ for (Set<const Space3DSW *>::Element *E = active_spaces.front(); E; E = E->next()) {
+
+ for (int i = 0; i < Space3DSW::ELAPSED_TIME_MAX; i++) {
+ total_time[i] += E->get()->get_elapsed_time(Space3DSW::ElapsedTime(i));
+ }
+ }
+
+ Array values;
+ values.resize(Space3DSW::ELAPSED_TIME_MAX * 2);
+ for (int i = 0; i < Space3DSW::ELAPSED_TIME_MAX; i++) {
+ values[i * 2 + 0] = time_name[i];
+ values[i * 2 + 1] = USEC_TO_SEC(total_time[i]);
+ }
+ values.push_back("flush_queries");
+ values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg));
+
+ values.push_front("physics");
+ EngineDebugger::profiler_add_frame_data("server", values);
+ }
+#endif
+};
+
+void PhysicsServer3DSW::finish() {
+
+ memdelete(stepper);
+ memdelete(direct_state);
+};
+
+int PhysicsServer3DSW::get_process_info(ProcessInfo p_info) {
+
+ switch (p_info) {
+
+ case INFO_ACTIVE_OBJECTS: {
+
+ return active_objects;
+ } break;
+ case INFO_COLLISION_PAIRS: {
+ return collision_pairs;
+ } break;
+ case INFO_ISLAND_COUNT: {
+
+ return island_count;
+ } break;
+ }
+
+ return 0;
+}
+
+void PhysicsServer3DSW::_update_shapes() {
+
+ while (pending_shape_update_list.first()) {
+ pending_shape_update_list.first()->self()->_shape_changed();
+ pending_shape_update_list.remove(pending_shape_update_list.first());
+ }
+}
+
+void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+
+ CollCbkData *cbk = (CollCbkData *)p_userdata;
+
+ if (cbk->max == 0)
+ return;
+
+ if (cbk->amount == cbk->max) {
+ //find least deep
+ real_t min_depth = 1e20;
+ int min_depth_idx = 0;
+ for (int i = 0; i < cbk->amount; i++) {
+
+ real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]);
+ if (d < min_depth) {
+ min_depth = d;
+ min_depth_idx = i;
+ }
+ }
+
+ real_t d = p_point_A.distance_squared_to(p_point_B);
+ if (d < min_depth)
+ return;
+ cbk->ptr[min_depth_idx * 2 + 0] = p_point_A;
+ cbk->ptr[min_depth_idx * 2 + 1] = p_point_B;
+
+ } else {
+
+ cbk->ptr[cbk->amount * 2 + 0] = p_point_A;
+ cbk->ptr[cbk->amount * 2 + 1] = p_point_B;
+ cbk->amount++;
+ }
+}
+
+PhysicsServer3DSW *PhysicsServer3DSW::singleton = nullptr;
+PhysicsServer3DSW::PhysicsServer3DSW() {
+ singleton = this;
+ BroadPhase3DSW::create_func = BroadPhaseOctree::_create;
+ island_count = 0;
+ active_objects = 0;
+ collision_pairs = 0;
+
+ active = true;
+ flushing_queries = false;
+};
+
+PhysicsServer3DSW::~PhysicsServer3DSW(){
+
+};
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
new file mode 100644
index 0000000000..6e79d9eceb
--- /dev/null
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -0,0 +1,382 @@
+/*************************************************************************/
+/* physics_server_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS_SERVER_SW
+#define PHYSICS_SERVER_SW
+
+#include "core/rid_owner.h"
+#include "joints_3d_sw.h"
+#include "servers/physics_server_3d.h"
+#include "shape_3d_sw.h"
+#include "space_3d_sw.h"
+#include "step_3d_sw.h"
+
+class PhysicsServer3DSW : public PhysicsServer3D {
+
+ GDCLASS(PhysicsServer3DSW, PhysicsServer3D);
+
+ friend class PhysicsDirectSpaceState3DSW;
+ bool active;
+ int iterations;
+ bool doing_sync;
+ real_t last_step;
+
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
+ bool flushing_queries;
+
+ Step3DSW *stepper;
+ Set<const Space3DSW *> active_spaces;
+
+ 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;
+
+ //void _clear_query(QuerySW *p_query);
+ friend class CollisionObject3DSW;
+ SelfList<CollisionObject3DSW>::List pending_shape_update_list;
+ void _update_shapes();
+
+public:
+ static PhysicsServer3DSW *singleton;
+
+ 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);
+
+ virtual RID shape_create(ShapeType p_shape);
+ virtual void shape_set_data(RID p_shape, const Variant &p_data);
+ virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
+
+ virtual ShapeType shape_get_type(RID p_shape) const;
+ virtual Variant shape_get_data(RID p_shape) const;
+
+ virtual void shape_set_margin(RID p_shape, real_t p_margin);
+ virtual real_t shape_get_margin(RID p_shape) const;
+
+ virtual real_t shape_get_custom_solver_bias(RID p_shape) const;
+
+ /* SPACE API */
+
+ virtual RID space_create();
+ virtual void space_set_active(RID p_space, bool p_active);
+ virtual bool space_is_active(RID p_space) const;
+
+ virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value);
+ virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const;
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space);
+
+ virtual void space_set_debug_contacts(RID p_space, int p_max_contacts);
+ virtual Vector<Vector3> space_get_contacts(RID p_space) const;
+ virtual int space_get_contact_count(RID p_space) const;
+
+ /* AREA API */
+
+ virtual RID area_create();
+
+ virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode);
+ virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const;
+
+ virtual void area_set_space(RID p_area, RID p_space);
+ virtual RID area_get_space(RID p_area) const;
+
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
+ virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform);
+
+ virtual int area_get_shape_count(RID p_area) const;
+ virtual RID area_get_shape(RID p_area, int p_shape_idx) const;
+ virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const;
+
+ virtual void area_remove_shape(RID p_area, int p_shape_idx);
+ virtual void area_clear_shapes(RID p_area);
+
+ virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled);
+
+ virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id);
+ virtual ObjectID area_get_object_instance_id(RID p_area) const;
+
+ virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
+ virtual void area_set_transform(RID p_area, const Transform &p_transform);
+
+ virtual Variant area_get_param(RID p_area, AreaParameter p_param) const;
+ virtual Transform area_get_transform(RID p_area) const;
+
+ virtual void area_set_ray_pickable(RID p_area, bool p_enable);
+ virtual bool area_is_ray_pickable(RID p_area) const;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask);
+ virtual void area_set_collision_layer(RID p_area, uint32_t p_layer);
+
+ virtual void area_set_monitorable(RID p_area, bool p_monitorable);
+
+ virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
+ virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
+
+ /* BODY API */
+
+ // create a body of a given type
+ virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false);
+
+ virtual void body_set_space(RID p_body, RID p_space);
+ virtual RID body_get_space(RID p_body) const;
+
+ virtual void body_set_mode(RID p_body, BodyMode p_mode);
+ virtual BodyMode body_get_mode(RID p_body) const;
+
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
+ virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform);
+
+ virtual int body_get_shape_count(RID p_body) const;
+ virtual RID body_get_shape(RID p_body, int p_shape_idx) const;
+ virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const;
+
+ virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled);
+
+ virtual void body_remove_shape(RID p_body, int p_shape_idx);
+ virtual void body_clear_shapes(RID p_body);
+
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id);
+ virtual ObjectID body_get_object_instance_id(RID p_body) const;
+
+ virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable);
+ virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const;
+
+ virtual void body_set_collision_layer(RID p_body, uint32_t p_layer);
+ virtual uint32_t body_get_collision_layer(RID p_body) const;
+
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
+ virtual uint32_t body_get_collision_mask(RID p_body) const;
+
+ virtual void body_set_user_flags(RID p_body, uint32_t p_flags);
+ virtual uint32_t body_get_user_flags(RID p_body) const;
+
+ virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
+ virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
+
+ virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
+ virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
+
+ virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
+ virtual Variant body_get_state(RID p_body, BodyState p_state) const;
+
+ virtual void body_set_applied_force(RID p_body, const Vector3 &p_force);
+ virtual Vector3 body_get_applied_force(RID p_body) const;
+
+ virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque);
+ virtual Vector3 body_get_applied_torque(RID p_body) const;
+
+ virtual void body_add_central_force(RID p_body, const Vector3 &p_force);
+ virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos);
+ virtual void body_add_torque(RID p_body, const Vector3 &p_torque);
+
+ virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse);
+ virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse);
+ virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse);
+ virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity);
+
+ virtual void body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock);
+ virtual bool body_is_axis_locked(RID p_body, BodyAxis p_axis) const;
+
+ virtual void body_add_collision_exception(RID p_body, RID p_body_b);
+ virtual void body_remove_collision_exception(RID p_body, RID p_body_b);
+ virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions);
+
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold);
+ virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const;
+
+ virtual void body_set_omit_force_integration(RID p_body, bool p_omit);
+ virtual bool body_is_omitting_force_integration(RID p_body) const;
+
+ virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
+ virtual int body_get_max_contacts_reported(RID p_body) const;
+
+ virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant());
+
+ virtual void body_set_ray_pickable(RID p_body, bool p_enable);
+ virtual bool body_is_ray_pickable(RID p_body) const;
+
+ 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);
+ 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, float p_margin = 0.001);
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body);
+
+ /* SOFT BODY */
+
+ virtual RID soft_body_create(bool p_init_sleeping = false) { return RID(); }
+
+ virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *p_rendering_server_handler) {}
+
+ virtual void soft_body_set_space(RID p_body, RID p_space) {}
+ virtual RID soft_body_get_space(RID p_body) const { return RID(); }
+
+ virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {}
+ virtual uint32_t soft_body_get_collision_layer(RID p_body) const { return 0; }
+
+ virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {}
+ virtual uint32_t soft_body_get_collision_mask(RID p_body) const { return 0; }
+
+ virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) {}
+ virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) {}
+ virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {}
+
+ virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {}
+ virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const { return Variant(); }
+
+ virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) {}
+ virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const { return Vector3(); }
+
+ virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) {}
+ virtual bool soft_body_is_ray_pickable(RID p_body) const { return false; }
+
+ virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {}
+ virtual int soft_body_get_simulation_precision(RID p_body) { return 0; }
+
+ virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) {}
+ virtual real_t soft_body_get_total_mass(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {}
+ virtual real_t soft_body_get_linear_stiffness(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) {}
+ virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {}
+ virtual real_t soft_body_get_volume_stiffness(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {}
+ virtual real_t soft_body_get_pressure_coefficient(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {}
+ virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {}
+ virtual real_t soft_body_get_damping_coefficient(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {}
+ virtual real_t soft_body_get_drag_coefficient(RID p_body) { return 0.; }
+
+ virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) {}
+
+ virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {}
+ virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) { return Vector3(); }
+
+ virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const { return Vector3(); }
+
+ virtual void soft_body_remove_all_pinned_points(RID p_body) {}
+ virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {}
+ virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) { return 0; }
+
+ /* JOINT API */
+
+ virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B);
+
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value);
+ virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
+
+ virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A);
+ virtual Vector3 pin_joint_get_local_a(RID p_joint) const;
+
+ virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B);
+ virtual Vector3 pin_joint_get_local_b(RID p_joint) const;
+
+ virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B);
+ 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);
+
+ virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value);
+ virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const;
+
+ virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value);
+ virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const;
+
+ 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); //reference frame is A
+
+ virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value);
+ virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const;
+
+ 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); //reference frame is A
+
+ virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value);
+ virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const;
+
+ 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); //reference frame is A
+
+ virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value);
+ virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param);
+
+ virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag, bool p_enable);
+ virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis, G6DOFJointAxisFlag p_flag);
+
+ virtual void generic_6dof_joint_set_precision(RID p_joint, int precision) {}
+ virtual int generic_6dof_joint_get_precision(RID p_joint) { return 0; }
+
+ virtual JointType joint_get_type(RID p_joint) const;
+
+ virtual void joint_set_solver_priority(RID p_joint, int p_priority);
+ virtual int joint_get_solver_priority(RID p_joint) const;
+
+ virtual void joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable);
+ virtual bool joint_is_disabled_collisions_between_bodies(RID p_joint) const;
+
+ /* MISC */
+
+ virtual void free(RID p_rid);
+
+ virtual void set_active(bool p_active);
+ virtual void init();
+ virtual void step(real_t p_step);
+ virtual void sync();
+ virtual void flush_queries();
+ virtual void finish();
+
+ virtual bool is_flushing_queries() const { return flushing_queries; }
+
+ int get_process_info(ProcessInfo p_info);
+
+ PhysicsServer3DSW();
+ ~PhysicsServer3DSW();
+};
+
+#endif
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
new file mode 100644
index 0000000000..61c32b779a
--- /dev/null
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -0,0 +1,1655 @@
+/*************************************************************************/
+/* shape_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "shape_3d_sw.h"
+
+#include "core/math/geometry.h"
+#include "core/math/quick_hull.h"
+#include "core/sort_array.h"
+
+#define _POINT_SNAP 0.001953125
+#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002
+#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998
+
+void Shape3DSW::configure(const AABB &p_aabb) {
+ aabb = p_aabb;
+ configured = true;
+ for (Map<ShapeOwner3DSW *, int>::Element *E = owners.front(); E; E = E->next()) {
+ ShapeOwner3DSW *co = (ShapeOwner3DSW *)E->key();
+ co->_shape_changed();
+ }
+}
+
+Vector3 Shape3DSW::get_support(const Vector3 &p_normal) const {
+
+ Vector3 res;
+ int amnt;
+ get_supports(p_normal, 1, &res, amnt);
+ return res;
+}
+
+void Shape3DSW::add_owner(ShapeOwner3DSW *p_owner) {
+
+ Map<ShapeOwner3DSW *, int>::Element *E = owners.find(p_owner);
+ if (E) {
+ E->get()++;
+ } else {
+ owners[p_owner] = 1;
+ }
+}
+
+void Shape3DSW::remove_owner(ShapeOwner3DSW *p_owner) {
+
+ Map<ShapeOwner3DSW *, int>::Element *E = owners.find(p_owner);
+ ERR_FAIL_COND(!E);
+ E->get()--;
+ if (E->get() == 0) {
+ owners.erase(E);
+ }
+}
+
+bool Shape3DSW::is_owner(ShapeOwner3DSW *p_owner) const {
+
+ return owners.has(p_owner);
+}
+
+const Map<ShapeOwner3DSW *, int> &Shape3DSW::get_owners() const {
+ return owners;
+}
+
+Shape3DSW::Shape3DSW() {
+
+ custom_bias = 0;
+ configured = false;
+}
+
+Shape3DSW::~Shape3DSW() {
+
+ ERR_FAIL_COND(owners.size());
+}
+
+Plane PlaneShape3DSW::get_plane() const {
+
+ return plane;
+}
+
+void PlaneShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ // gibberish, a plane is infinity
+ r_min = -1e7;
+ r_max = 1e7;
+}
+
+Vector3 PlaneShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ return p_normal * 1e15;
+}
+
+bool PlaneShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ bool inters = plane.intersects_segment(p_begin, p_end, &r_result);
+ if (inters)
+ r_normal = plane.normal;
+ return inters;
+}
+
+bool PlaneShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ return plane.distance_to(p_point) < 0;
+}
+
+Vector3 PlaneShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ if (plane.is_point_over(p_point)) {
+ return plane.project(p_point);
+ } else {
+ return p_point;
+ }
+}
+
+Vector3 PlaneShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+
+ return Vector3(); //wtf
+}
+
+void PlaneShape3DSW::_setup(const Plane &p_plane) {
+
+ plane = p_plane;
+ configure(AABB(Vector3(-1e4, -1e4, -1e4), Vector3(1e4 * 2, 1e4 * 2, 1e4 * 2)));
+}
+
+void PlaneShape3DSW::set_data(const Variant &p_data) {
+
+ _setup(p_data);
+}
+
+Variant PlaneShape3DSW::get_data() const {
+
+ return plane;
+}
+
+PlaneShape3DSW::PlaneShape3DSW() {
+}
+
+//
+
+real_t RayShape3DSW::get_length() const {
+
+ return length;
+}
+
+bool RayShape3DSW::get_slips_on_slope() const {
+ return slips_on_slope;
+}
+
+void RayShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ // don't think this will be even used
+ r_min = 0;
+ r_max = 1;
+}
+
+Vector3 RayShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ if (p_normal.z > 0)
+ return Vector3(0, 0, length);
+ else
+ return Vector3(0, 0, 0);
+}
+
+void RayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+
+ if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ r_amount = 2;
+ r_supports[0] = Vector3(0, 0, 0);
+ r_supports[1] = Vector3(0, 0, length);
+ } else if (p_normal.z > 0) {
+ r_amount = 1;
+ *r_supports = Vector3(0, 0, length);
+ } else {
+ r_amount = 1;
+ *r_supports = Vector3(0, 0, 0);
+ }
+}
+
+bool RayShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ return false; //simply not possible
+}
+
+bool RayShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ return false; //simply not possible
+}
+
+Vector3 RayShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ Vector3 s[2] = {
+ Vector3(0, 0, 0),
+ Vector3(0, 0, length)
+ };
+
+ return Geometry::get_closest_point_to_segment(p_point, s);
+}
+
+Vector3 RayShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+
+ return Vector3();
+}
+
+void RayShape3DSW::_setup(real_t p_length, bool p_slips_on_slope) {
+
+ length = p_length;
+ slips_on_slope = p_slips_on_slope;
+ configure(AABB(Vector3(0, 0, 0), Vector3(0.1, 0.1, length)));
+}
+
+void RayShape3DSW::set_data(const Variant &p_data) {
+
+ Dictionary d = p_data;
+ _setup(d["length"], d["slips_on_slope"]);
+}
+
+Variant RayShape3DSW::get_data() const {
+
+ Dictionary d;
+ d["length"] = length;
+ d["slips_on_slope"] = slips_on_slope;
+ return d;
+}
+
+RayShape3DSW::RayShape3DSW() {
+
+ length = 1;
+ slips_on_slope = false;
+}
+
+/********** SPHERE *************/
+
+real_t SphereShape3DSW::get_radius() const {
+
+ return radius;
+}
+
+void SphereShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ real_t d = p_normal.dot(p_transform.origin);
+
+ // figure out scale at point
+ Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
+ real_t scale = local_normal.length();
+
+ r_min = d - (radius)*scale;
+ r_max = d + (radius)*scale;
+}
+
+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 {
+
+ *r_supports = p_normal * radius;
+ r_amount = 1;
+}
+
+bool SphereShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ return Geometry::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal);
+}
+
+bool SphereShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ return p_point.length() < radius;
+}
+
+Vector3 SphereShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ Vector3 p = p_point;
+ float l = p.length();
+ if (l < radius)
+ return p_point;
+ return (p / l) * radius;
+}
+
+Vector3 SphereShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+
+ real_t s = 0.4 * p_mass * radius * radius;
+ return Vector3(s, s, s);
+}
+
+void SphereShape3DSW::_setup(real_t p_radius) {
+
+ radius = p_radius;
+ configure(AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2.0, radius * 2.0, radius * 2.0)));
+}
+
+void SphereShape3DSW::set_data(const Variant &p_data) {
+
+ _setup(p_data);
+}
+
+Variant SphereShape3DSW::get_data() const {
+
+ return radius;
+}
+
+SphereShape3DSW::SphereShape3DSW() {
+
+ radius = 0;
+}
+
+/********** BOX *************/
+
+void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ // no matter the angle, the box is mirrored anyway
+ Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
+
+ real_t length = local_normal.abs().dot(half_extents);
+ real_t distance = p_normal.dot(p_transform.origin);
+
+ r_min = distance - length;
+ r_max = distance + length;
+}
+
+Vector3 BoxShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ Vector3 point(
+ (p_normal.x < 0) ? -half_extents.x : half_extents.x,
+ (p_normal.y < 0) ? -half_extents.y : half_extents.y,
+ (p_normal.z < 0) ? -half_extents.z : half_extents.z);
+
+ return point;
+}
+
+void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+
+ static const int next[3] = { 1, 2, 0 };
+ static const int next2[3] = { 2, 0, 1 };
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis;
+ axis[i] = 1.0;
+ real_t dot = p_normal.dot(axis);
+ if (Math::abs(dot) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ //Vector3 axis_b;
+
+ bool neg = dot < 0;
+ r_amount = 4;
+
+ Vector3 point;
+ point[i] = half_extents[i];
+
+ int i_n = next[i];
+ int i_n2 = next2[i];
+
+ static const real_t sign[4][2] = {
+
+ { -1.0, 1.0 },
+ { 1.0, 1.0 },
+ { 1.0, -1.0 },
+ { -1.0, -1.0 },
+ };
+
+ for (int j = 0; j < 4; j++) {
+
+ point[i_n] = sign[j][0] * half_extents[i_n];
+ point[i_n2] = sign[j][1] * half_extents[i_n2];
+ r_supports[j] = neg ? -point : point;
+ }
+
+ if (neg) {
+ SWAP(r_supports[1], r_supports[2]);
+ SWAP(r_supports[0], r_supports[3]);
+ }
+
+ return;
+ }
+
+ r_amount = 0;
+ }
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 axis;
+ axis[i] = 1.0;
+
+ if (Math::abs(p_normal.dot(axis)) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ r_amount = 2;
+
+ int i_n = next[i];
+ int i_n2 = next2[i];
+
+ Vector3 point = half_extents;
+
+ if (p_normal[i_n] < 0) {
+ point[i_n] = -point[i_n];
+ }
+ if (p_normal[i_n2] < 0) {
+ point[i_n2] = -point[i_n2];
+ }
+
+ r_supports[0] = point;
+ point[i] = -point[i];
+ r_supports[1] = point;
+ return;
+ }
+ }
+ /* USE POINT */
+
+ Vector3 point(
+ (p_normal.x < 0) ? -half_extents.x : half_extents.x,
+ (p_normal.y < 0) ? -half_extents.y : half_extents.y,
+ (p_normal.z < 0) ? -half_extents.z : half_extents.z);
+
+ r_amount = 1;
+ r_supports[0] = point;
+}
+
+bool BoxShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ AABB aabb(-half_extents, half_extents * 2.0);
+
+ return aabb.intersects_segment(p_begin, p_end, &r_result, &r_normal);
+}
+
+bool BoxShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ return (Math::abs(p_point.x) < half_extents.x && Math::abs(p_point.y) < half_extents.y && Math::abs(p_point.z) < half_extents.z);
+}
+
+Vector3 BoxShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ int outside = 0;
+ Vector3 min_point;
+
+ for (int i = 0; i < 3; i++) {
+
+ if (Math::abs(p_point[i]) > half_extents[i]) {
+ outside++;
+ if (outside == 1) {
+ //use plane if only one side matches
+ Vector3 n;
+ n[i] = SGN(p_point[i]);
+
+ Plane p(n, half_extents[i]);
+ min_point = p.project(p_point);
+ }
+ }
+ }
+
+ if (!outside)
+ return p_point; //it's inside, don't do anything else
+
+ if (outside == 1) //if only above one plane, this plane clearly wins
+ return min_point;
+
+ //check segments
+ float min_distance = 1e20;
+ Vector3 closest_vertex = half_extents * p_point.sign();
+ Vector3 s[2] = {
+ closest_vertex,
+ closest_vertex
+ };
+
+ for (int i = 0; i < 3; i++) {
+
+ s[1] = closest_vertex;
+ s[1][i] = -s[1][i]; //edge
+
+ Vector3 closest_edge = Geometry::get_closest_point_to_segment(p_point, s);
+
+ float d = p_point.distance_to(closest_edge);
+ if (d < min_distance) {
+ min_point = closest_edge;
+ min_distance = d;
+ }
+ }
+
+ return min_point;
+}
+
+Vector3 BoxShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+
+ real_t lx = half_extents.x;
+ real_t ly = half_extents.y;
+ real_t lz = half_extents.z;
+
+ return Vector3((p_mass / 3.0) * (ly * ly + lz * lz), (p_mass / 3.0) * (lx * lx + lz * lz), (p_mass / 3.0) * (lx * lx + ly * ly));
+}
+
+void BoxShape3DSW::_setup(const Vector3 &p_half_extents) {
+
+ half_extents = p_half_extents.abs();
+
+ configure(AABB(-half_extents, half_extents * 2));
+}
+
+void BoxShape3DSW::set_data(const Variant &p_data) {
+
+ _setup(p_data);
+}
+
+Variant BoxShape3DSW::get_data() const {
+
+ return half_extents;
+}
+
+BoxShape3DSW::BoxShape3DSW() {
+}
+
+/********** CAPSULE *************/
+
+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;
+
+ n *= radius;
+ n.z += h * 0.5;
+
+ r_max = p_normal.dot(p_transform.xform(n));
+ r_min = p_normal.dot(p_transform.xform(-n));
+}
+
+Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ Vector3 n = p_normal;
+
+ real_t h = (n.z > 0) ? height : -height;
+
+ n *= radius;
+ n.z += h * 0.5;
+ return n;
+}
+
+void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+
+ Vector3 n = p_normal;
+
+ real_t d = n.z;
+
+ if (Math::abs(d) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ // make it flat
+ n.z = 0.0;
+ n.normalize();
+ n *= radius;
+
+ r_amount = 2;
+ r_supports[0] = n;
+ r_supports[0].z += height * 0.5;
+ r_supports[1] = n;
+ r_supports[1].z -= height * 0.5;
+
+ } else {
+
+ real_t h = (d > 0) ? height : -height;
+
+ n *= radius;
+ n.z += h * 0.5;
+ r_amount = 1;
+ *r_supports = n;
+ }
+}
+
+bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ Vector3 norm = (p_end - p_begin).normalized();
+ real_t min_d = 1e20;
+
+ Vector3 res, n;
+ bool collision = false;
+
+ Vector3 auxres, auxn;
+ bool collided;
+
+ // test against cylinder and spheres :-|
+
+ collided = Geometry::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn);
+
+ if (collided) {
+ real_t d = norm.dot(auxres);
+ if (d < min_d) {
+ min_d = d;
+ res = auxres;
+ n = auxn;
+ collision = true;
+ }
+ }
+
+ collided = Geometry::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * 0.5), radius, &auxres, &auxn);
+
+ if (collided) {
+ real_t d = norm.dot(auxres);
+ if (d < min_d) {
+ min_d = d;
+ res = auxres;
+ n = auxn;
+ collision = true;
+ }
+ }
+
+ collided = Geometry::segment_intersects_sphere(p_begin, p_end, Vector3(0, 0, height * -0.5), radius, &auxres, &auxn);
+
+ if (collided) {
+ real_t d = norm.dot(auxres);
+
+ if (d < min_d) {
+ min_d = d;
+ res = auxres;
+ n = auxn;
+ collision = true;
+ }
+ }
+
+ if (collision) {
+
+ r_result = res;
+ r_normal = n;
+ }
+ return collision;
+}
+
+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;
+ } else {
+ Vector3 p = p_point;
+ p.z = Math::abs(p.z) - 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 p = Geometry::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 CapsuleShape3DSW::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.y * extents.y + 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)));
+}
+
+void CapsuleShape3DSW::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 CapsuleShape3DSW::get_data() const {
+
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ return d;
+}
+
+CapsuleShape3DSW::CapsuleShape3DSW() {
+
+ 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 {
+
+ int vertex_count = mesh.vertices.size();
+ if (vertex_count == 0)
+ return;
+
+ const Vector3 *vrts = &mesh.vertices[0];
+
+ for (int i = 0; i < vertex_count; i++) {
+
+ real_t d = p_normal.dot(p_transform.xform(vrts[i]));
+
+ if (i == 0 || d > r_max)
+ r_max = d;
+ if (i == 0 || d < r_min)
+ r_min = d;
+ }
+}
+
+Vector3 ConvexPolygonShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ Vector3 n = p_normal;
+
+ int vert_support_idx = -1;
+ real_t support_max = 0;
+
+ int vertex_count = mesh.vertices.size();
+ if (vertex_count == 0)
+ return Vector3();
+
+ const Vector3 *vrts = &mesh.vertices[0];
+
+ for (int i = 0; i < vertex_count; i++) {
+
+ real_t d = n.dot(vrts[i]);
+
+ if (i == 0 || d > support_max) {
+ support_max = d;
+ vert_support_idx = i;
+ }
+ }
+
+ return vrts[vert_support_idx];
+}
+
+void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int fc = mesh.faces.size();
+
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int ec = mesh.edges.size();
+
+ const Vector3 *vertices = mesh.vertices.ptr();
+ int vc = mesh.vertices.size();
+
+ //find vertex first
+ real_t max = 0;
+ int vtx = 0;
+
+ for (int i = 0; i < vc; i++) {
+
+ real_t d = p_normal.dot(vertices[i]);
+
+ if (i == 0 || d > max) {
+ max = d;
+ vtx = i;
+ }
+ }
+
+ for (int i = 0; i < fc; i++) {
+
+ if (faces[i].plane.normal.dot(p_normal) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ int ic = faces[i].indices.size();
+ const int *ind = faces[i].indices.ptr();
+
+ bool valid = false;
+ for (int j = 0; j < ic; j++) {
+ if (ind[j] == vtx) {
+ valid = true;
+ break;
+ }
+ }
+
+ if (!valid)
+ continue;
+
+ int m = MIN(p_max, ic);
+ for (int j = 0; j < m; j++) {
+
+ r_supports[j] = vertices[ind[j]];
+ }
+ r_amount = m;
+ return;
+ }
+ }
+
+ for (int i = 0; i < ec; i++) {
+
+ real_t dot = (vertices[edges[i].a] - vertices[edges[i].b]).normalized().dot(p_normal);
+ dot = ABS(dot);
+ if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD && (edges[i].a == vtx || edges[i].b == vtx)) {
+
+ r_amount = 2;
+ r_supports[0] = vertices[edges[i].a];
+ r_supports[1] = vertices[edges[i].b];
+ return;
+ }
+ }
+
+ r_supports[0] = vertices[vtx];
+ r_amount = 1;
+}
+
+bool ConvexPolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int fc = mesh.faces.size();
+
+ const Vector3 *vertices = mesh.vertices.ptr();
+
+ Vector3 n = p_end - p_begin;
+ real_t min = 1e20;
+ bool col = false;
+
+ for (int i = 0; i < fc; i++) {
+
+ if (faces[i].plane.normal.dot(n) > 0)
+ continue; //opposing face
+
+ int ic = faces[i].indices.size();
+ const int *ind = faces[i].indices.ptr();
+
+ for (int j = 1; j < ic - 1; j++) {
+
+ Face3 f(vertices[ind[0]], vertices[ind[j]], vertices[ind[j + 1]]);
+ Vector3 result;
+ if (f.intersects_segment(p_begin, p_end, &result)) {
+ real_t d = n.dot(result);
+ if (d < min) {
+ min = d;
+ r_result = result;
+ r_normal = faces[i].plane.normal;
+ col = true;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return col;
+}
+
+bool ConvexPolygonShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int fc = mesh.faces.size();
+
+ for (int i = 0; i < fc; i++) {
+
+ if (faces[i].plane.distance_to(p_point) >= 0)
+ return false;
+ }
+
+ return true;
+}
+
+Vector3 ConvexPolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+ int fc = mesh.faces.size();
+ const Vector3 *vertices = mesh.vertices.ptr();
+
+ bool all_inside = true;
+ for (int i = 0; i < fc; i++) {
+
+ if (!faces[i].plane.is_point_over(p_point))
+ continue;
+
+ all_inside = false;
+ bool is_inside = true;
+ int ic = faces[i].indices.size();
+ const int *indices = faces[i].indices.ptr();
+
+ for (int j = 0; j < ic; j++) {
+
+ Vector3 a = vertices[indices[j]];
+ Vector3 b = vertices[indices[(j + 1) % ic]];
+ Vector3 n = (a - b).cross(faces[i].plane.normal).normalized();
+ if (Plane(a, n).is_point_over(p_point)) {
+ is_inside = false;
+ break;
+ }
+ }
+
+ if (is_inside) {
+ return faces[i].plane.project(p_point);
+ }
+ }
+
+ if (all_inside) {
+ return p_point;
+ }
+
+ float min_distance = 1e20;
+ Vector3 min_point;
+
+ //check edges
+ const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+ int ec = mesh.edges.size();
+ for (int i = 0; i < ec; i++) {
+
+ Vector3 s[2] = {
+ vertices[edges[i].a],
+ vertices[edges[i].b]
+ };
+
+ Vector3 closest = Geometry::get_closest_point_to_segment(p_point, s);
+ float d = closest.distance_to(p_point);
+ if (d < min_distance) {
+ min_distance = d;
+ min_point = closest;
+ }
+ }
+
+ return min_point;
+}
+
+Vector3 ConvexPolygonShape3DSW::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.y * extents.y + extents.y * extents.y));
+}
+
+void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) {
+
+ Error err = QuickHull::build(p_vertices, mesh);
+ if (err != OK)
+ ERR_PRINT("Failed to build QuickHull");
+
+ AABB _aabb;
+
+ for (int i = 0; i < mesh.vertices.size(); i++) {
+
+ if (i == 0)
+ _aabb.position = mesh.vertices[i];
+ else
+ _aabb.expand_to(mesh.vertices[i]);
+ }
+
+ configure(_aabb);
+}
+
+void ConvexPolygonShape3DSW::set_data(const Variant &p_data) {
+
+ _setup(p_data);
+}
+
+Variant ConvexPolygonShape3DSW::get_data() const {
+
+ return mesh.vertices;
+}
+
+ConvexPolygonShape3DSW::ConvexPolygonShape3DSW() {
+}
+
+/********** FACE POLYGON *************/
+
+void FaceShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ for (int i = 0; i < 3; i++) {
+
+ Vector3 v = p_transform.xform(vertex[i]);
+ real_t d = p_normal.dot(v);
+
+ if (i == 0 || d > r_max)
+ r_max = d;
+
+ if (i == 0 || d < r_min)
+ r_min = d;
+ }
+}
+
+Vector3 FaceShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ int vert_support_idx = -1;
+ real_t support_max = 0;
+
+ for (int i = 0; i < 3; i++) {
+
+ real_t d = p_normal.dot(vertex[i]);
+
+ if (i == 0 || d > support_max) {
+ support_max = d;
+ vert_support_idx = i;
+ }
+ }
+
+ return vertex[vert_support_idx];
+}
+
+void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) const {
+
+ Vector3 n = p_normal;
+
+ /** TEST FACE AS SUPPORT **/
+ if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ r_amount = 3;
+ for (int i = 0; i < 3; i++) {
+
+ r_supports[i] = vertex[i];
+ }
+ return;
+ }
+
+ /** FIND SUPPORT VERTEX **/
+
+ int vert_support_idx = -1;
+ real_t support_max = 0;
+
+ for (int i = 0; i < 3; i++) {
+
+ real_t d = n.dot(vertex[i]);
+
+ if (i == 0 || d > support_max) {
+ support_max = d;
+ vert_support_idx = i;
+ }
+ }
+
+ /** TEST EDGES AS SUPPORT **/
+
+ for (int i = 0; i < 3; i++) {
+
+ int nx = (i + 1) % 3;
+ if (i != vert_support_idx && nx != vert_support_idx)
+ continue;
+
+ // check if edge is valid as a support
+ real_t dot = (vertex[i] - vertex[nx]).normalized().dot(n);
+ dot = ABS(dot);
+ if (dot < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
+
+ r_amount = 2;
+ r_supports[0] = vertex[i];
+ r_supports[1] = vertex[nx];
+ return;
+ }
+ }
+
+ r_amount = 1;
+ r_supports[0] = vertex[vert_support_idx];
+}
+
+bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ bool c = Geometry::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result);
+ 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;
+ }
+ }
+
+ return c;
+}
+
+bool FaceShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ return false; //face is flat
+}
+
+Vector3 FaceShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ return Face3(vertex[0], vertex[1], vertex[2]).get_closest_point_to(p_point);
+}
+
+Vector3 FaceShape3DSW::get_moment_of_inertia(real_t p_mass) const {
+
+ return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
+}
+
+FaceShape3DSW::FaceShape3DSW() {
+
+ configure(AABB());
+}
+
+Vector<Vector3> ConcavePolygonShape3DSW::get_faces() const {
+
+ Vector<Vector3> rfaces;
+ rfaces.resize(faces.size() * 3);
+
+ for (int i = 0; i < faces.size(); i++) {
+
+ Face f = faces.get(i);
+
+ for (int j = 0; j < 3; j++) {
+
+ rfaces.set(i * 3 + j, vertices.get(f.indices[j]));
+ }
+ }
+
+ return rfaces;
+}
+
+void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ int count = vertices.size();
+ if (count == 0) {
+ r_min = 0;
+ r_max = 0;
+ return;
+ }
+ const Vector3 *vptr = vertices.ptr();
+
+ for (int i = 0; i < count; i++) {
+
+ real_t d = p_normal.dot(p_transform.xform(vptr[i]));
+
+ if (i == 0 || d > r_max)
+ r_max = d;
+ if (i == 0 || d < r_min)
+ r_min = d;
+ }
+}
+
+Vector3 ConcavePolygonShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ int count = vertices.size();
+ if (count == 0)
+ return Vector3();
+
+ const Vector3 *vptr = vertices.ptr();
+
+ Vector3 n = p_normal;
+
+ int vert_support_idx = -1;
+ real_t support_max = 0;
+
+ for (int i = 0; i < count; i++) {
+
+ real_t d = n.dot(vptr[i]);
+
+ if (i == 0 || d > support_max) {
+ support_max = d;
+ vert_support_idx = i;
+ }
+ }
+
+ return vptr[vert_support_idx];
+}
+
+void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_params) const {
+
+ const BVH *bvh = &p_params->bvh[p_idx];
+
+ /*
+ if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
+ return; //test against whole AABB, which isn't very costly
+ */
+
+ //printf("addr: %p\n",bvh);
+ if (!bvh->aabb.intersects_segment(p_params->from, p_params->to)) {
+
+ return;
+ }
+
+ 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]]
+ };
+
+ if (Geometry::segment_intersects_triangle(
+ p_params->from,
+ p_params->to,
+ vertices[0],
+ vertices[1],
+ vertices[2],
+ &res)) {
+
+ 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) {
+
+ p_params->min_d = d;
+ p_params->result = res;
+ p_params->normal = Plane(vertices[0], vertices[1], vertices[2]).normal;
+ p_params->collisions++;
+ }
+ }
+
+ } else {
+
+ if (bvh->left >= 0)
+ _cull_segment(bvh->left, p_params);
+ if (bvh->right >= 0)
+ _cull_segment(bvh->right, p_params);
+ }
+}
+
+bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
+
+ if (faces.size() == 0)
+ return false;
+
+ // unlock data
+ const Face *fr = faces.ptr();
+ const Vector3 *vr = vertices.ptr();
+ const BVH *br = bvh.ptr();
+
+ _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;
+ // cull
+ _cull_segment(0, &params);
+
+ if (params.collisions > 0) {
+
+ r_result = params.result;
+ r_normal = params.normal;
+ return true;
+ } else {
+
+ return false;
+ }
+}
+
+bool ConcavePolygonShape3DSW::intersect_point(const Vector3 &p_point) const {
+
+ return false; //face is flat
+}
+
+Vector3 ConcavePolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ return Vector3();
+}
+
+void ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const {
+
+ const BVH *bvh = &p_params->bvh[p_idx];
+
+ if (!p_params->aabb.intersects(bvh->aabb))
+ return;
+
+ if (bvh->face_index >= 0) {
+
+ 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]];
+ p_params->callback(p_params->userdata, face);
+
+ } else {
+
+ if (bvh->left >= 0) {
+
+ _cull(bvh->left, p_params);
+ }
+
+ if (bvh->right >= 0) {
+
+ _cull(bvh->right, p_params);
+ }
+ }
+}
+
+void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
+
+ // make matrix local to concave
+ if (faces.size() == 0)
+ return;
+
+ AABB local_aabb = p_local_aabb;
+
+ // unlock data
+ const Face *fr = faces.ptr();
+ const Vector3 *vr = vertices.ptr();
+ const BVH *br = bvh.ptr();
+
+ FaceShape3DSW face; // use this to send in the callback
+
+ _CullParams params;
+ params.aabb = local_aabb;
+ params.face = &face;
+ params.faces = fr;
+ params.vertices = vr;
+ params.bvh = br;
+ params.callback = p_callback;
+ params.userdata = p_userdata;
+
+ // cull
+ _cull(0, &params);
+}
+
+Vector3 ConcavePolygonShape3DSW::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.y * extents.y + extents.y * extents.y));
+}
+
+struct _VolumeSW_BVH_Element {
+
+ AABB aabb;
+ Vector3 center;
+ int face_index;
+};
+
+struct _VolumeSW_BVH_CompareX {
+
+ _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const {
+
+ return a.center.x < b.center.x;
+ }
+};
+
+struct _VolumeSW_BVH_CompareY {
+
+ _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const {
+
+ return a.center.y < b.center.y;
+ }
+};
+
+struct _VolumeSW_BVH_CompareZ {
+
+ _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const {
+
+ return a.center.z < b.center.z;
+ }
+};
+
+struct _VolumeSW_BVH {
+
+ AABB aabb;
+ _VolumeSW_BVH *left;
+ _VolumeSW_BVH *right;
+
+ int face_index;
+};
+
+_VolumeSW_BVH *_volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements, int p_size, int &count) {
+
+ _VolumeSW_BVH *bvh = memnew(_VolumeSW_BVH);
+
+ if (p_size == 1) {
+ //leaf
+ bvh->aabb = p_elements[0].aabb;
+ bvh->left = nullptr;
+ bvh->right = nullptr;
+ bvh->face_index = p_elements->face_index;
+ count++;
+ return bvh;
+ } else {
+
+ bvh->face_index = -1;
+ }
+
+ AABB aabb;
+ for (int i = 0; i < p_size; i++) {
+
+ if (i == 0)
+ aabb = p_elements[i].aabb;
+ else
+ aabb.merge_with(p_elements[i].aabb);
+ }
+ bvh->aabb = aabb;
+ switch (aabb.get_longest_axis_index()) {
+
+ case 0: {
+
+ SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareX> sort_x;
+ sort_x.sort(p_elements, p_size);
+
+ } break;
+ case 1: {
+
+ SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareY> sort_y;
+ sort_y.sort(p_elements, p_size);
+ } break;
+ case 2: {
+
+ SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareZ> sort_z;
+ sort_z.sort(p_elements, p_size);
+ } break;
+ }
+
+ int split = p_size / 2;
+ bvh->left = _volume_sw_build_bvh(p_elements, split, count);
+ bvh->right = _volume_sw_build_bvh(&p_elements[split], p_size - split, count);
+
+ //printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
+ count++;
+ return bvh;
+}
+
+void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx) {
+
+ int idx = p_idx;
+
+ p_bvh_array[idx].aabb = p_bvh_tree->aabb;
+ p_bvh_array[idx].face_index = p_bvh_tree->face_index;
+ //printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
+
+ if (p_bvh_tree->left) {
+ p_bvh_array[idx].left = ++p_idx;
+ _fill_bvh(p_bvh_tree->left, p_bvh_array, p_idx);
+
+ } else {
+
+ p_bvh_array[p_idx].left = -1;
+ }
+
+ if (p_bvh_tree->right) {
+ p_bvh_array[idx].right = ++p_idx;
+ _fill_bvh(p_bvh_tree->right, p_bvh_array, p_idx);
+
+ } else {
+
+ p_bvh_array[p_idx].right = -1;
+ }
+
+ memdelete(p_bvh_tree);
+}
+
+void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
+
+ int src_face_count = p_faces.size();
+ if (src_face_count == 0) {
+ configure(AABB());
+ return;
+ }
+ ERR_FAIL_COND(src_face_count % 3);
+ src_face_count /= 3;
+
+ const Vector3 *facesr = p_faces.ptr();
+
+ Vector<_VolumeSW_BVH_Element> bvh_array;
+ bvh_array.resize(src_face_count);
+
+ _VolumeSW_BVH_Element *bvh_arrayw = bvh_array.ptrw();
+
+ faces.resize(src_face_count);
+ Face *facesw = faces.ptrw();
+
+ vertices.resize(src_face_count * 3);
+
+ Vector3 *verticesw = vertices.ptrw();
+
+ AABB _aabb;
+
+ for (int i = 0; i < src_face_count; i++) {
+
+ Face3 face(facesr[i * 3 + 0], facesr[i * 3 + 1], facesr[i * 3 + 2]);
+
+ bvh_arrayw[i].aabb = face.get_aabb();
+ bvh_arrayw[i].center = bvh_arrayw[i].aabb.position + bvh_arrayw[i].aabb.size * 0.5;
+ bvh_arrayw[i].face_index = i;
+ facesw[i].indices[0] = i * 3 + 0;
+ facesw[i].indices[1] = i * 3 + 1;
+ facesw[i].indices[2] = i * 3 + 2;
+ facesw[i].normal = face.get_plane().normal;
+ verticesw[i * 3 + 0] = face.vertex[0];
+ verticesw[i * 3 + 1] = face.vertex[1];
+ verticesw[i * 3 + 2] = face.vertex[2];
+ if (i == 0)
+ _aabb = bvh_arrayw[i].aabb;
+ else
+ _aabb.merge_with(bvh_arrayw[i].aabb);
+ }
+
+ int count = 0;
+ _VolumeSW_BVH *bvh_tree = _volume_sw_build_bvh(bvh_arrayw, src_face_count, count);
+
+ bvh.resize(count + 1);
+
+ BVH *bvh_arrayw2 = bvh.ptrw();
+
+ int idx = 0;
+ _fill_bvh(bvh_tree, bvh_arrayw2, idx);
+
+ configure(_aabb); // this type of shape has no margin
+}
+
+void ConcavePolygonShape3DSW::set_data(const Variant &p_data) {
+
+ _setup(p_data);
+}
+
+Variant ConcavePolygonShape3DSW::get_data() const {
+
+ return get_faces();
+}
+
+ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {
+}
+
+/* HEIGHT MAP SHAPE */
+
+Vector<real_t> HeightMapShape3DSW::get_heights() const {
+
+ return heights;
+}
+int HeightMapShape3DSW::get_width() const {
+
+ return width;
+}
+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);
+}
+
+Vector3 HeightMapShape3DSW::get_support(const Vector3 &p_normal) const {
+
+ //not very useful, but not very used either
+ return get_aabb().get_support(p_normal);
+}
+
+bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
+
+ return false;
+}
+
+bool HeightMapShape3DSW::intersect_point(const Vector3 &p_point) const {
+ return false;
+}
+
+Vector3 HeightMapShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
+
+ return Vector3();
+}
+
+void HeightMapShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
+}
+
+Vector3 HeightMapShape3DSW::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.y * extents.y + extents.y * extents.y));
+}
+
+void HeightMapShape3DSW::_setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size) {
+
+ heights = p_heights;
+ width = p_width;
+ depth = p_depth;
+ cell_size = p_cell_size;
+
+ const real_t *r = heights.ptr();
+
+ AABB aabb;
+
+ for (int i = 0; i < depth; i++) {
+
+ for (int j = 0; j < width; j++) {
+
+ real_t h = r[i * width + j];
+
+ Vector3 pos(j * cell_size, h, i * cell_size);
+ if (i == 0 || j == 0)
+ aabb.position = pos;
+ else
+ aabb.expand_to(pos);
+ }
+ }
+
+ 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);
+}
+
+Variant HeightMapShape3DSW::get_data() const {
+
+ ERR_FAIL_V(Variant());
+}
+
+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
new file mode 100644
index 0000000000..dd29ec849b
--- /dev/null
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -0,0 +1,470 @@
+/*************************************************************************/
+/* shape_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SHAPE_SW_H
+#define SHAPE_SW_H
+
+#include "core/math/geometry.h"
+#include "servers/physics_server_3d.h"
+/*
+
+SHAPE_LINE, ///< plane:"plane"
+SHAPE_SEGMENT, ///< real_t:"length"
+SHAPE_CIRCLE, ///< real_t:"radius"
+SHAPE_RECTANGLE, ///< vec3:"extents"
+SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
+SHAPE_CONCAVE_POLYGON, ///< Vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
+SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
+
+*/
+
+class Shape3DSW;
+
+class ShapeOwner3DSW {
+public:
+ virtual void _shape_changed() = 0;
+ virtual void remove_shape(Shape3DSW *p_shape) = 0;
+
+ virtual ~ShapeOwner3DSW() {}
+};
+
+class Shape3DSW {
+
+ RID self;
+ AABB aabb;
+ bool configured;
+ real_t custom_bias;
+
+ Map<ShapeOwner3DSW *, int> owners;
+
+protected:
+ void configure(const AABB &p_aabb);
+
+public:
+ enum {
+ MAX_SUPPORTS = 8
+ };
+
+ virtual real_t get_area() const { return aabb.get_area(); }
+
+ _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const = 0;
+
+ _FORCE_INLINE_ 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 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;
+ virtual Vector3 get_moment_of_inertia(real_t p_mass) const = 0;
+
+ virtual void set_data(const Variant &p_data) = 0;
+ virtual Variant get_data() const = 0;
+
+ _FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias = p_bias; }
+ _FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; }
+
+ void add_owner(ShapeOwner3DSW *p_owner);
+ void remove_owner(ShapeOwner3DSW *p_owner);
+ bool is_owner(ShapeOwner3DSW *p_owner) const;
+ const Map<ShapeOwner3DSW *, int> &get_owners() const;
+
+ Shape3DSW();
+ virtual ~Shape3DSW();
+};
+
+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 cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const = 0;
+
+ ConcaveShape3DSW() {}
+};
+
+class PlaneShape3DSW : public Shape3DSW {
+
+ Plane plane;
+
+ void _setup(const Plane &p_plane);
+
+public:
+ Plane get_plane() const;
+
+ virtual real_t get_area() const { return Math_INF; }
+ 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 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;
+
+ PlaneShape3DSW();
+};
+
+class RayShape3DSW : public Shape3DSW {
+
+ real_t length;
+ bool slips_on_slope;
+
+ void _setup(real_t p_length, bool p_slips_on_slope);
+
+public:
+ real_t get_length() const;
+ bool get_slips_on_slope() const;
+
+ virtual real_t get_area() const { return 0.0; }
+ 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 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;
+
+ RayShape3DSW();
+};
+
+class SphereShape3DSW : public Shape3DSW {
+
+ real_t radius;
+
+ void _setup(real_t p_radius);
+
+public:
+ real_t get_radius() const;
+
+ virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SPHERE; }
+
+ 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 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;
+
+ SphereShape3DSW();
+};
+
+class BoxShape3DSW : public Shape3DSW {
+
+ Vector3 half_extents;
+ void _setup(const Vector3 &p_half_extents);
+
+public:
+ _FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; }
+ virtual real_t get_area() const { return 8 * half_extents.x * half_extents.y * half_extents.z; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_BOX; }
+
+ 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 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;
+
+ BoxShape3DSW();
+};
+
+class CapsuleShape3DSW : 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_CAPSULE; }
+
+ 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 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;
+
+ CapsuleShape3DSW();
+};
+
+struct ConvexPolygonShape3DSW : public Shape3DSW {
+
+ Geometry::MeshData mesh;
+
+ void _setup(const Vector<Vector3> &p_vertices);
+
+public:
+ const Geometry::MeshData &get_mesh() const { return mesh; }
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }
+
+ 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 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;
+
+ ConvexPolygonShape3DSW();
+};
+
+struct _VolumeSW_BVH;
+struct FaceShape3DSW;
+
+struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
+ // always a trimesh
+
+ struct Face {
+
+ Vector3 normal;
+ int indices[3];
+ };
+
+ Vector<Face> faces;
+ Vector<Vector3> vertices;
+
+ struct BVH {
+
+ AABB aabb;
+ int left;
+ int right;
+
+ int face_index;
+ };
+
+ Vector<BVH> bvh;
+
+ struct _CullParams {
+
+ AABB aabb;
+ Callback callback;
+ void *userdata;
+ const Face *faces;
+ const Vector3 *vertices;
+ const BVH *bvh;
+ FaceShape3DSW *face;
+ };
+
+ struct _SegmentCullParams {
+
+ Vector3 from;
+ Vector3 to;
+ const Face *faces;
+ const Vector3 *vertices;
+ const BVH *bvh;
+ Vector3 dir;
+
+ Vector3 result;
+ Vector3 normal;
+ real_t min_d;
+ int collisions;
+ };
+
+ 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);
+
+public:
+ Vector<Vector3> get_faces() const;
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
+
+ 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 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 void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) 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;
+
+ ConcavePolygonShape3DSW();
+};
+
+struct HeightMapShape3DSW : public ConcaveShape3DSW {
+
+ Vector<real_t> heights;
+ int width;
+ int depth;
+ real_t cell_size;
+
+ //void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
+ //void _cull(int p_idx,_CullParams *p_params) const;
+
+ void _setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size);
+
+public:
+ Vector<real_t> 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; }
+
+ 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 bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, 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 void cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) 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;
+
+ HeightMapShape3DSW();
+};
+
+//used internally
+struct FaceShape3DSW : public Shape3DSW {
+
+ Vector3 normal; //cache
+ Vector3 vertex[3];
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
+
+ const Vector3 &get_vertex(int p_idx) const { return vertex[p_idx]; }
+
+ 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;
+ 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;
+
+ Vector3 get_moment_of_inertia(real_t p_mass) const;
+
+ virtual void set_data(const Variant &p_data) {}
+ virtual Variant get_data() const { return Variant(); }
+
+ FaceShape3DSW();
+};
+
+struct MotionShape3DSW : public Shape3DSW {
+
+ Shape3DSW *shape;
+ Vector3 motion;
+
+ virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; }
+
+ void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
+
+ Vector3 cast = p_transform.basis.xform(motion);
+ real_t mina, maxa;
+ real_t minb, maxb;
+ Transform ofsb = p_transform;
+ ofsb.origin += cast;
+ shape->project_range(p_normal, p_transform, mina, maxa);
+ shape->project_range(p_normal, ofsb, minb, maxb);
+ r_min = MIN(mina, minb);
+ r_max = MAX(maxa, maxb);
+ }
+
+ Vector3 get_support(const Vector3 &p_normal) const {
+
+ Vector3 support = shape->get_support(p_normal);
+ if (p_normal.dot(motion) > 0) {
+ support += motion;
+ }
+ return support;
+ }
+ virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount) 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; }
+
+ 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(); }
+
+ MotionShape3DSW() { configure(AABB()); }
+};
+
+#endif // SHAPE_SW_H
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
new file mode 100644
index 0000000000..bd8e89a8f5
--- /dev/null
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -0,0 +1,1242 @@
+/*************************************************************************/
+/* space_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "space_3d_sw.h"
+
+#include "collision_solver_3d_sw.h"
+#include "core/project_settings.h"
+#include "physics_server_3d_sw.h"
+
+_FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ if (!(p_object->get_collision_layer() & p_collision_mask)) {
+ return false;
+ }
+
+ if (p_object->get_type() == CollisionObject3DSW::TYPE_AREA && !p_collide_with_areas)
+ return false;
+
+ if (p_object->get_type() == CollisionObject3DSW::TYPE_BODY && !p_collide_with_bodies)
+ return false;
+
+ return true;
+}
+
+int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ ERR_FAIL_COND_V(space->locked, false);
+ int amount = space->broadphase->cull_point(p_point, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+ int cc = 0;
+
+ //Transform ai = p_xform.affine_inverse();
+
+ for (int i = 0; i < amount; i++) {
+
+ if (cc >= p_result_max)
+ break;
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
+ continue;
+
+ //area can't be picked by ray (default)
+
+ if (p_exclude.has(space->intersection_query_results[i]->get_self()))
+ continue;
+
+ const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ Transform inv_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ inv_xform.affine_invert();
+
+ if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_point)))
+ continue;
+
+ r_results[cc].collider_id = col_obj->get_instance_id();
+ if (r_results[cc].collider_id.is_valid())
+ r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
+ else
+ r_results[cc].collider = nullptr;
+ r_results[cc].rid = col_obj->get_self();
+ r_results[cc].shape = shape_idx;
+
+ cc++;
+ }
+
+ return cc;
+}
+
+bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_ray) {
+
+ ERR_FAIL_COND_V(space->locked, false);
+
+ Vector3 begin, end;
+ Vector3 normal;
+ begin = p_from;
+ end = p_to;
+ normal = (end - begin).normalized();
+
+ int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ //todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
+
+ bool collided = false;
+ Vector3 res_point, res_normal;
+ int res_shape;
+ const CollisionObject3DSW *res_obj;
+ real_t min_d = 1e10;
+
+ for (int i = 0; i < amount; i++) {
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
+ continue;
+
+ if (p_pick_ray && !(space->intersection_query_results[i]->is_ray_pickable()))
+ continue;
+
+ if (p_exclude.has(space->intersection_query_results[i]->get_self()))
+ continue;
+
+ const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
+
+ int shape_idx = space->intersection_query_subindex_results[i];
+ Transform inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();
+
+ Vector3 local_from = inv_xform.xform(begin);
+ Vector3 local_to = inv_xform.xform(end);
+
+ const Shape3DSW *shape = col_obj->get_shape(shape_idx);
+
+ Vector3 shape_point, shape_normal;
+
+ if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) {
+
+ Transform xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ shape_point = xform.xform(shape_point);
+
+ real_t ld = normal.dot(shape_point);
+
+ if (ld < min_d) {
+
+ min_d = ld;
+ res_point = shape_point;
+ res_normal = inv_xform.basis.xform_inv(shape_normal).normalized();
+ res_shape = shape_idx;
+ res_obj = col_obj;
+ collided = true;
+ }
+ }
+ }
+
+ if (!collided)
+ return false;
+
+ r_result.collider_id = res_obj->get_instance_id();
+ if (r_result.collider_id.is_valid())
+ r_result.collider = ObjectDB::get_instance(r_result.collider_id);
+ else
+ r_result.collider = nullptr;
+ r_result.normal = res_normal;
+ r_result.position = res_point;
+ r_result.rid = res_obj->get_self();
+ r_result.shape = res_shape;
+
+ return true;
+}
+
+int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ if (p_result_max <= 0)
+ return 0;
+
+ Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, 0);
+
+ AABB aabb = p_xform.xform(shape->get_aabb());
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ int cc = 0;
+
+ //Transform ai = p_xform.affine_inverse();
+
+ for (int i = 0; i < amount; i++) {
+
+ if (cc >= p_result_max)
+ break;
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
+ continue;
+
+ //area can't be picked by ray (default)
+
+ if (p_exclude.has(space->intersection_query_results[i]->get_self()))
+ continue;
+
+ const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ 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;
+
+ if (r_results) {
+ r_results[cc].collider_id = col_obj->get_instance_id();
+ if (r_results[cc].collider_id.is_valid())
+ r_results[cc].collider = ObjectDB::get_instance(r_results[cc].collider_id);
+ else
+ r_results[cc].collider = nullptr;
+ r_results[cc].rid = col_obj->get_self();
+ r_results[cc].shape = shape_idx;
+ }
+
+ cc++;
+ }
+
+ return cc;
+}
+
+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);
+ ERR_FAIL_COND_V(!shape, false);
+
+ AABB aabb = p_xform.xform(shape->get_aabb());
+ aabb = aabb.merge(AABB(aabb.position + p_motion, aabb.size)); //motion
+ aabb = aabb.grow(p_margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ real_t best_safe = 1;
+ real_t best_unsafe = 1;
+
+ Transform xform_inv = p_xform.affine_inverse();
+ MotionShape3DSW mshape;
+ mshape.shape = shape;
+ mshape.motion = xform_inv.basis.xform(p_motion);
+
+ bool best_first = true;
+
+ Vector3 closest_A, closest_B;
+
+ for (int i = 0; i < amount; i++) {
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
+ continue;
+
+ if (p_exclude.has(space->intersection_query_results[i]->get_self()))
+ continue; //ignore excluded
+
+ const CollisionObject3DSW *col_obj = space->intersection_query_results[i];
+ int shape_idx = space->intersection_query_subindex_results[i];
+
+ Vector3 point_A, point_B;
+ Vector3 sep_axis = p_motion.normalized();
+
+ 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, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
+ continue;
+ }
+
+ //test initial overlap
+ sep_axis = p_motion.normalized();
+
+ if (!CollisionSolver3DSW::solve_distance(shape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) {
+ return false;
+ }
+
+ //just do kinematic solving
+ real_t low = 0;
+ real_t hi = 1;
+ Vector3 mnormal = p_motion.normalized();
+
+ for (int j = 0; j < 8; j++) { //steps should be customizable..
+
+ real_t ofs = (low + hi) * 0.5;
+
+ Vector3 sep = mnormal; //important optimization for this to work fast enough
+
+ mshape.motion = xform_inv.basis.xform(p_motion * ofs);
+
+ Vector3 lA, lB;
+
+ bool collided = !CollisionSolver3DSW::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, aabb, &sep);
+
+ if (collided) {
+
+ hi = ofs;
+ } else {
+
+ point_A = lA;
+ point_B = lB;
+ low = ofs;
+ }
+ }
+
+ if (low < best_safe) {
+ best_first = true; //force reset
+ best_safe = low;
+ best_unsafe = hi;
+ }
+
+ if (r_info && (best_first || (point_A.distance_squared_to(point_B) < closest_A.distance_squared_to(closest_B) && low <= best_safe))) {
+ closest_A = point_A;
+ closest_B = point_B;
+ r_info->collider_id = col_obj->get_instance_id();
+ r_info->rid = col_obj->get_self();
+ r_info->shape = shape_idx;
+ r_info->point = closest_B;
+ r_info->normal = (closest_A - closest_B).normalized();
+ 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);
+ }
+ }
+ }
+
+ p_closest_safe = best_safe;
+ p_closest_unsafe = best_unsafe;
+
+ return true;
+}
+
+bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ if (p_result_max <= 0)
+ return 0;
+
+ Shape3DSW *shape = static_cast<PhysicsServer3DSW *>(PhysicsServer3D::get_singleton())->shape_owner.getornull(p_shape);
+ ERR_FAIL_COND_V(!shape, 0);
+
+ AABB aabb = p_shape_xform.xform(shape->get_aabb());
+ aabb = aabb.grow(p_margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ bool collided = false;
+ r_result_count = 0;
+
+ PhysicsServer3DSW::CollCbkData cbk;
+ cbk.max = p_result_max;
+ cbk.amount = 0;
+ cbk.ptr = r_results;
+ CollisionSolver3DSW::CallbackResult cbkres = PhysicsServer3DSW::_shape_col_cbk;
+
+ PhysicsServer3DSW::CollCbkData *cbkptr = &cbk;
+
+ for (int i = 0; i < amount; i++) {
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
+ continue;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ r_result_count = cbk.amount;
+
+ return collided;
+}
+
+struct _RestCallbackData {
+
+ const CollisionObject3DSW *object;
+ const CollisionObject3DSW *best_object;
+ int shape;
+ int best_shape;
+ Vector3 best_contact;
+ Vector3 best_normal;
+ real_t best_len;
+ real_t min_allowed_depth;
+};
+
+static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
+
+ _RestCallbackData *rd = (_RestCallbackData *)p_userdata;
+
+ Vector3 contact_rel = p_point_B - p_point_A;
+ real_t len = contact_rel.length();
+ if (len < rd->min_allowed_depth)
+ return;
+ if (len <= rd->best_len)
+ return;
+
+ rd->best_len = len;
+ rd->best_contact = p_point_B;
+ rd->best_normal = contact_rel / len;
+ rd->best_object = rd->object;
+ rd->best_shape = rd->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);
+ ERR_FAIL_COND_V(!shape, 0);
+
+ AABB aabb = p_shape_xform.xform(shape->get_aabb());
+ aabb = aabb.grow(p_margin);
+
+ int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
+
+ _RestCallbackData rcd;
+ rcd.best_len = 0;
+ rcd.best_object = nullptr;
+ rcd.best_shape = 0;
+ rcd.min_allowed_depth = space->test_motion_min_contact_depth;
+
+ for (int i = 0; i < amount; i++) {
+
+ if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas))
+ continue;
+
+ 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;
+
+ 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);
+ if (!sc)
+ continue;
+ }
+
+ if (rcd.best_len == 0 || !rcd.best_object)
+ return false;
+
+ r_info->collider_id = rcd.best_object->get_instance_id();
+ r_info->shape = rcd.best_shape;
+ r_info->normal = rcd.best_normal;
+ r_info->point = rcd.best_contact;
+ 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);
+
+ } else {
+ r_info->linear_velocity = Vector3();
+ }
+
+ return true;
+}
+
+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);
+ if (!obj) {
+ obj = PhysicsServer3DSW::singleton->body_owner.getornull(p_object);
+ }
+ ERR_FAIL_COND_V(!obj, Vector3());
+
+ ERR_FAIL_COND_V(obj->get_space() != space, Vector3());
+
+ float min_distance = 1e20;
+ Vector3 min_point;
+
+ bool shapes_found = false;
+
+ for (int i = 0; i < obj->get_shape_count(); i++) {
+
+ if (obj->is_shape_set_as_disabled(i))
+ continue;
+
+ Transform shape_xform = obj->get_transform() * obj->get_shape_transform(i);
+ Shape3DSW *shape = obj->get_shape(i);
+
+ Vector3 point = shape->get_closest_point_to(shape_xform.affine_inverse().xform(p_point));
+ point = shape_xform.xform(point);
+
+ float dist = point.distance_to(p_point);
+ if (dist < min_distance) {
+ min_distance = dist;
+ min_point = point;
+ }
+ shapes_found = true;
+ }
+
+ if (!shapes_found) {
+ return obj->get_transform().origin; //no shapes found, use distance to origin.
+ } else {
+ return min_point;
+ }
+}
+
+PhysicsDirectSpaceState3DSW::PhysicsDirectSpaceState3DSW() {
+
+ space = nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
+
+ int amount = broadphase->cull_aabb(p_aabb, intersection_query_results, INTERSECTION_QUERY_MAX, intersection_query_subindex_results);
+
+ for (int i = 0; i < amount; i++) {
+
+ bool keep = true;
+
+ if (intersection_query_results[i] == p_body)
+ keep = false;
+ else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_AREA)
+ 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()))
+ keep = false;
+ else if (static_cast<Body3DSW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i]))
+ keep = false;
+
+ if (!keep) {
+
+ if (i < amount - 1) {
+ SWAP(intersection_query_results[i], intersection_query_results[amount - 1]);
+ SWAP(intersection_query_subindex_results[i], intersection_query_subindex_results[amount - 1]);
+ }
+
+ amount--;
+ i--;
+ }
+ }
+
+ return amount;
+}
+
+int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
+
+ AABB body_aabb;
+
+ bool shapes_found = false;
+
+ for (int i = 0; i < p_body->get_shape_count(); i++) {
+
+ if (p_body->is_shape_set_as_disabled(i))
+ continue;
+
+ if (!shapes_found) {
+ body_aabb = p_body->get_shape_aabb(i);
+ shapes_found = true;
+ } else {
+ body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+ }
+
+ if (!shapes_found) {
+ return 0;
+ }
+ // Undo the currently transform the physics server is aware of and apply the provided one
+ body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb));
+ body_aabb = body_aabb.grow(p_margin);
+
+ Transform body_transform = p_transform;
+
+ for (int i = 0; i < p_result_max; i++) {
+ //reset results
+ r_results[i].collision_depth = 0;
+ }
+
+ int rays_found = 0;
+
+ {
+ // raycast AND separate
+
+ const int max_results = 32;
+ int recover_attempts = 4;
+ Vector3 sr[max_results * 2];
+ PhysicsServer3DSW::CollCbkData cbk;
+ cbk.max = max_results;
+ PhysicsServer3DSW::CollCbkData *cbkptr = &cbk;
+ CollisionSolver3DSW::CallbackResult cbkres = PhysicsServer3DSW::_shape_col_cbk;
+
+ do {
+
+ Vector3 recover_motion;
+
+ bool collided = false;
+
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
+ for (int j = 0; j < p_body->get_shape_count(); j++) {
+ if (p_body->is_shape_set_as_disabled(j))
+ continue;
+
+ Shape3DSW *body_shape = p_body->get_shape(j);
+
+ if (body_shape->get_type() != PhysicsServer3D::SHAPE_RAY)
+ continue;
+
+ Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
+
+ for (int i = 0; i < amount; i++) {
+
+ const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ int shape_idx = intersection_query_subindex_results[i];
+
+ cbk.amount = 0;
+ cbk.ptr = sr;
+
+ if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
+ const Body3DSW *b = static_cast<const Body3DSW *>(col_obj);
+ if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) {
+ continue;
+ }
+ }
+
+ Shape3DSW *against_shape = col_obj->get_shape(shape_idx);
+ if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) {
+ if (cbk.amount > 0) {
+ collided = true;
+ }
+
+ int ray_index = -1; //reuse shape
+ for (int k = 0; k < rays_found; k++) {
+ if (r_results[k].collision_local_shape == j) {
+ ray_index = k;
+ }
+ }
+
+ if (ray_index == -1 && rays_found < p_result_max) {
+ ray_index = rays_found;
+ rays_found++;
+ }
+
+ if (ray_index != -1) {
+ PhysicsServer3D::SeparationResult &result = r_results[ray_index];
+
+ for (int k = 0; k < cbk.amount; k++) {
+ Vector3 a = sr[k * 2 + 0];
+ Vector3 b = sr[k * 2 + 1];
+
+ recover_motion += (b - a) * 0.4;
+
+ float depth = a.distance_to(b);
+ if (depth > result.collision_depth) {
+
+ result.collision_depth = depth;
+ result.collision_point = b;
+ result.collision_normal = (b - a).normalized();
+ result.collision_local_shape = j;
+ result.collider = col_obj->get_self();
+ result.collider_id = col_obj->get_instance_id();
+ result.collider_shape = shape_idx;
+ //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);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!collided || recover_motion == Vector3()) {
+ break;
+ }
+
+ body_transform.origin += recover_motion;
+ body_aabb.position += recover_motion;
+
+ recover_attempts--;
+ } while (recover_attempts);
+ }
+
+ //optimize results (remove non colliding)
+ for (int i = 0; i < rays_found; i++) {
+ if (r_results[i].collision_depth == 0) {
+ rays_found--;
+ SWAP(r_results[i], r_results[rays_found]);
+ }
+ }
+
+ r_recover_motion = body_transform.origin - p_transform.origin;
+ return rays_found;
+}
+
+bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+
+ //give me back regular physics engine logic
+ //this is madness
+ //and most people using this function will think
+ //what it does is simpler than using physics
+ //this took about a week to get right..
+ //but is it right? who knows at this point..
+
+ if (r_result) {
+ r_result->collider_id = ObjectID();
+ r_result->collider_shape = 0;
+ }
+ AABB body_aabb;
+ bool shapes_found = false;
+
+ for (int i = 0; i < p_body->get_shape_count(); i++) {
+
+ if (p_body->is_shape_set_as_disabled(i))
+ continue;
+
+ if (!shapes_found) {
+ body_aabb = p_body->get_shape_aabb(i);
+ shapes_found = true;
+ } else {
+ body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
+ }
+ }
+
+ if (!shapes_found) {
+ if (r_result) {
+ *r_result = PhysicsServer3D::MotionResult();
+ r_result->motion = p_motion;
+ }
+
+ return false;
+ }
+
+ // Undo the currently transform the physics server is aware of and apply the provided one
+ body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
+ body_aabb = body_aabb.grow(p_margin);
+
+ Transform body_transform = p_from;
+
+ {
+ //STEP 1, FREE BODY IF STUCK
+
+ const int max_results = 32;
+ int recover_attempts = 4;
+ Vector3 sr[max_results * 2];
+
+ do {
+
+ PhysicsServer3DSW::CollCbkData cbk;
+ cbk.max = max_results;
+ cbk.amount = 0;
+ cbk.ptr = sr;
+
+ PhysicsServer3DSW::CollCbkData *cbkptr = &cbk;
+ CollisionSolver3DSW::CallbackResult cbkres = PhysicsServer3DSW::_shape_col_cbk;
+
+ bool collided = false;
+
+ int amount = _cull_aabb_for_body(p_body, body_aabb);
+
+ for (int j = 0; j < p_body->get_shape_count(); j++) {
+ if (p_body->is_shape_set_as_disabled(j))
+ continue;
+
+ Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Shape3DSW *body_shape = p_body->get_shape(j);
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
+ continue;
+ }
+
+ for (int i = 0; i < amount; i++) {
+
+ const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ int shape_idx = intersection_query_subindex_results[i];
+
+ if (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), cbkres, cbkptr, nullptr, p_margin)) {
+ collided = cbk.amount > 0;
+ }
+ }
+ }
+
+ if (!collided) {
+ break;
+ }
+
+ Vector3 recover_motion;
+
+ for (int i = 0; i < cbk.amount; i++) {
+
+ Vector3 a = sr[i * 2 + 0];
+ Vector3 b = sr[i * 2 + 1];
+ recover_motion += (b - a) * 0.4;
+ }
+
+ if (recover_motion == Vector3()) {
+ collided = false;
+ break;
+ }
+
+ body_transform.origin += recover_motion;
+ body_aabb.position += recover_motion;
+
+ recover_attempts--;
+
+ } while (recover_attempts);
+ }
+
+ real_t safe = 1.0;
+ real_t unsafe = 1.0;
+ int best_shape = -1;
+
+ {
+ // STEP 2 ATTEMPT MOTION
+
+ AABB motion_aabb = body_aabb;
+ motion_aabb.position += p_motion;
+ motion_aabb = motion_aabb.merge(body_aabb);
+
+ int amount = _cull_aabb_for_body(p_body, motion_aabb);
+
+ for (int j = 0; j < p_body->get_shape_count(); j++) {
+
+ if (p_body->is_shape_set_as_disabled(j))
+ continue;
+
+ Transform body_shape_xform = body_transform * p_body->get_shape_transform(j);
+ Shape3DSW *body_shape = p_body->get_shape(j);
+
+ if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
+ continue;
+ }
+
+ Transform body_shape_xform_inv = body_shape_xform.affine_inverse();
+ MotionShape3DSW mshape;
+ mshape.shape = body_shape;
+ mshape.motion = body_shape_xform_inv.basis.xform(p_motion);
+
+ bool stuck = false;
+
+ real_t best_safe = 1;
+ real_t best_unsafe = 1;
+
+ for (int i = 0; i < amount; i++) {
+
+ const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ int shape_idx = intersection_query_subindex_results[i];
+
+ //test initial overlap, does it collide if going all the way?
+ Vector3 point_A, point_B;
+ Vector3 sep_axis = p_motion.normalized();
+
+ 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();
+
+ 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;
+ break;
+ }
+
+ //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
+
+ mshape.motion = body_shape_xform_inv.basis.xform(p_motion * ofs);
+
+ Vector3 lA, lB;
+
+ bool collided = !CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, motion_aabb, &sep);
+
+ if (collided) {
+
+ hi = ofs;
+ } else {
+
+ point_A = lA;
+ point_B = lB;
+ low = ofs;
+ }
+ }
+
+ if (low < best_safe) {
+ best_safe = low;
+ best_unsafe = hi;
+ }
+ }
+
+ if (stuck) {
+
+ safe = 0;
+ unsafe = 0;
+ best_shape = j; //sadly it's the best
+ break;
+ }
+ if (best_safe == 1.0) {
+ continue;
+ }
+ if (best_safe < safe) {
+
+ safe = best_safe;
+ unsafe = best_unsafe;
+ best_shape = j;
+ }
+ }
+ }
+
+ 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());
+ }
+
+ } else {
+
+ //it collided, let's get the rest info in unsafe advance
+ Transform ugt = body_transform;
+ ugt.origin += p_motion * unsafe;
+
+ _RestCallbackData rcd;
+ 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);
+
+ 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) {
+
+ if (r_result) {
+ 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_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);
+
+ r_result->motion = safe * p_motion;
+ r_result->remainder = p_motion - safe * p_motion;
+ r_result->motion += (body_transform.get_origin() - p_from.get_origin());
+ }
+
+ 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;
+ }
+ }
+
+ return collided;
+}
+
+void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self) {
+
+ CollisionObject3DSW::Type type_A = A->get_type();
+ CollisionObject3DSW::Type type_B = B->get_type();
+ if (type_A > type_B) {
+
+ SWAP(A, B);
+ SWAP(p_subindex_A, p_subindex_B);
+ SWAP(type_A, type_B);
+ }
+
+ Space3DSW *self = (Space3DSW *)p_self;
+
+ self->collision_pairs++;
+
+ if (type_A == CollisionObject3DSW::TYPE_AREA) {
+
+ Area3DSW *area = static_cast<Area3DSW *>(A);
+ if (type_B == CollisionObject3DSW::TYPE_AREA) {
+
+ 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 {
+
+ Body3DSW *body = static_cast<Body3DSW *>(B);
+ AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A));
+ return area_pair;
+ }
+ } else {
+
+ BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B));
+ return b;
+ }
+
+ return nullptr;
+}
+
+void Space3DSW::_broadphase_unpair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_self) {
+
+ Space3DSW *self = (Space3DSW *)p_self;
+ self->collision_pairs--;
+ Constraint3DSW *c = (Constraint3DSW *)p_data;
+ memdelete(c);
+}
+
+const SelfList<Body3DSW>::List &Space3DSW::get_active_body_list() const {
+
+ return active_list;
+}
+void Space3DSW::body_add_to_active_list(SelfList<Body3DSW> *p_body) {
+
+ active_list.add(p_body);
+}
+void Space3DSW::body_remove_from_active_list(SelfList<Body3DSW> *p_body) {
+
+ active_list.remove(p_body);
+}
+
+void Space3DSW::body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body) {
+
+ inertia_update_list.add(p_body);
+}
+
+void Space3DSW::body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body) {
+
+ inertia_update_list.remove(p_body);
+}
+
+BroadPhase3DSW *Space3DSW::get_broadphase() {
+
+ return broadphase;
+}
+
+void Space3DSW::add_object(CollisionObject3DSW *p_object) {
+
+ ERR_FAIL_COND(objects.has(p_object));
+ objects.insert(p_object);
+}
+
+void Space3DSW::remove_object(CollisionObject3DSW *p_object) {
+
+ ERR_FAIL_COND(!objects.has(p_object));
+ objects.erase(p_object);
+}
+
+const Set<CollisionObject3DSW *> &Space3DSW::get_objects() const {
+
+ return objects;
+}
+
+void Space3DSW::body_add_to_state_query_list(SelfList<Body3DSW> *p_body) {
+
+ state_query_list.add(p_body);
+}
+void Space3DSW::body_remove_from_state_query_list(SelfList<Body3DSW> *p_body) {
+
+ state_query_list.remove(p_body);
+}
+
+void Space3DSW::area_add_to_monitor_query_list(SelfList<Area3DSW> *p_area) {
+
+ monitor_query_list.add(p_area);
+}
+void Space3DSW::area_remove_from_monitor_query_list(SelfList<Area3DSW> *p_area) {
+
+ monitor_query_list.remove(p_area);
+}
+
+void Space3DSW::area_add_to_moved_list(SelfList<Area3DSW> *p_area) {
+
+ area_moved_list.add(p_area);
+}
+
+void Space3DSW::area_remove_from_moved_list(SelfList<Area3DSW> *p_area) {
+
+ area_moved_list.remove(p_area);
+}
+
+const SelfList<Area3DSW>::List &Space3DSW::get_moved_area_list() const {
+
+ return area_moved_list;
+}
+
+void Space3DSW::call_queries() {
+
+ while (state_query_list.first()) {
+
+ Body3DSW *b = state_query_list.first()->self();
+ state_query_list.remove(state_query_list.first());
+ b->call_queries();
+ }
+
+ while (monitor_query_list.first()) {
+
+ Area3DSW *a = monitor_query_list.first()->self();
+ monitor_query_list.remove(monitor_query_list.first());
+ a->call_queries();
+ }
+}
+
+void Space3DSW::setup() {
+
+ contact_debug_count = 0;
+ while (inertia_update_list.first()) {
+ inertia_update_list.first()->self()->update_inertias();
+ inertia_update_list.remove(inertia_update_list.first());
+ }
+}
+
+void Space3DSW::update() {
+
+ broadphase->update();
+}
+
+void Space3DSW::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value) {
+
+ switch (p_param) {
+
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: contact_max_separation = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: body_linear_velocity_sleep_threshold = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: body_angular_velocity_sleep_threshold = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break;
+ case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break;
+ }
+}
+
+real_t Space3DSW::get_param(PhysicsServer3D::SpaceParameter p_param) const {
+
+ switch (p_param) {
+
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius;
+ case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: return contact_max_separation;
+ case PhysicsServer3D::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: return contact_max_allowed_penetration;
+ case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: return body_linear_velocity_sleep_threshold;
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: return body_angular_velocity_sleep_threshold;
+ case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
+ case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio;
+ case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
+ case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth;
+ }
+ return 0;
+}
+
+void Space3DSW::lock() {
+
+ locked = true;
+}
+
+void Space3DSW::unlock() {
+
+ locked = false;
+}
+
+bool Space3DSW::is_locked() const {
+
+ return locked;
+}
+
+PhysicsDirectSpaceState3DSW *Space3DSW::get_direct_state() {
+
+ return direct_access;
+}
+
+Space3DSW::Space3DSW() {
+
+ collision_pairs = 0;
+ active_objects = 0;
+ island_count = 0;
+ contact_debug_count = 0;
+
+ locked = false;
+ contact_recycle_radius = 0.01;
+ contact_max_separation = 0.05;
+ contact_max_allowed_penetration = 0.01;
+ test_motion_min_contact_depth = 0.00001;
+
+ constraint_bias = 0.01;
+ body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1);
+ body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI));
+ body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
+ body_angular_velocity_damp_ratio = 10;
+
+ broadphase = BroadPhase3DSW::create_func();
+ broadphase->set_pair_callback(_broadphase_pair, this);
+ broadphase->set_unpair_callback(_broadphase_unpair, this);
+ area = nullptr;
+
+ direct_access = memnew(PhysicsDirectSpaceState3DSW);
+ direct_access->space = this;
+
+ for (int i = 0; i < ELAPSED_TIME_MAX; i++)
+ elapsed_time[i] = 0;
+}
+
+Space3DSW::~Space3DSW() {
+
+ memdelete(broadphase);
+ memdelete(direct_access);
+}
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
new file mode 100644
index 0000000000..3634834952
--- /dev/null
+++ b/servers/physics_3d/space_3d_sw.h
@@ -0,0 +1,208 @@
+/*************************************************************************/
+/* space_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SPACE_SW_H
+#define SPACE_SW_H
+
+#include "area_3d_sw.h"
+#include "area_pair_3d_sw.h"
+#include "body_3d_sw.h"
+#include "body_pair_3d_sw.h"
+#include "broad_phase_3d_sw.h"
+#include "collision_object_3d_sw.h"
+#include "core/hash_map.h"
+#include "core/project_settings.h"
+#include "core/typedefs.h"
+
+class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D {
+
+ GDCLASS(PhysicsDirectSpaceState3DSW, PhysicsDirectSpaceState3D);
+
+public:
+ Space3DSW *space;
+
+ virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false);
+ virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ virtual bool 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 = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr);
+ virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const;
+
+ PhysicsDirectSpaceState3DSW();
+};
+
+class Space3DSW {
+
+public:
+ enum ElapsedTime {
+ ELAPSED_TIME_INTEGRATE_FORCES,
+ ELAPSED_TIME_GENERATE_ISLANDS,
+ ELAPSED_TIME_SETUP_CONSTRAINTS,
+ ELAPSED_TIME_SOLVE_CONSTRAINTS,
+ ELAPSED_TIME_INTEGRATE_VELOCITIES,
+ ELAPSED_TIME_MAX
+
+ };
+
+private:
+ uint64_t elapsed_time[ELAPSED_TIME_MAX];
+
+ PhysicsDirectSpaceState3DSW *direct_access;
+ RID self;
+
+ BroadPhase3DSW *broadphase;
+ SelfList<Body3DSW>::List active_list;
+ SelfList<Body3DSW>::List inertia_update_list;
+ SelfList<Body3DSW>::List state_query_list;
+ SelfList<Area3DSW>::List monitor_query_list;
+ SelfList<Area3DSW>::List area_moved_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);
+
+ Set<CollisionObject3DSW *> objects;
+
+ Area3DSW *area;
+
+ real_t contact_recycle_radius;
+ real_t contact_max_separation;
+ real_t contact_max_allowed_penetration;
+ real_t constraint_bias;
+ real_t test_motion_min_contact_depth;
+
+ enum {
+
+ INTERSECTION_QUERY_MAX = 2048
+ };
+
+ CollisionObject3DSW *intersection_query_results[INTERSECTION_QUERY_MAX];
+ int intersection_query_subindex_results[INTERSECTION_QUERY_MAX];
+
+ real_t body_linear_velocity_sleep_threshold;
+ real_t body_angular_velocity_sleep_threshold;
+ real_t body_time_to_sleep;
+ real_t body_angular_velocity_damp_ratio;
+
+ bool locked;
+
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
+ RID static_global_body;
+
+ Vector<Vector3> contact_debug;
+ int contact_debug_count;
+
+ friend class PhysicsDirectSpaceState3DSW;
+
+ int _cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb);
+
+public:
+ _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ void set_default_area(Area3DSW *p_area) { area = p_area; }
+ Area3DSW *get_default_area() const { return area; }
+
+ const SelfList<Body3DSW>::List &get_active_body_list() const;
+ void body_add_to_active_list(SelfList<Body3DSW> *p_body);
+ void body_remove_from_active_list(SelfList<Body3DSW> *p_body);
+ void body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body);
+ void body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body);
+
+ void body_add_to_state_query_list(SelfList<Body3DSW> *p_body);
+ void body_remove_from_state_query_list(SelfList<Body3DSW> *p_body);
+
+ void area_add_to_monitor_query_list(SelfList<Area3DSW> *p_area);
+ void area_remove_from_monitor_query_list(SelfList<Area3DSW> *p_area);
+ void area_add_to_moved_list(SelfList<Area3DSW> *p_area);
+ void area_remove_from_moved_list(SelfList<Area3DSW> *p_area);
+ const SelfList<Area3DSW>::List &get_moved_area_list() const;
+
+ BroadPhase3DSW *get_broadphase();
+
+ void add_object(CollisionObject3DSW *p_object);
+ void remove_object(CollisionObject3DSW *p_object);
+ const Set<CollisionObject3DSW *> &get_objects() const;
+
+ _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; }
+ _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; }
+ _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; }
+ _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; }
+ _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; }
+ _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; }
+ _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
+ _FORCE_INLINE_ real_t get_body_angular_velocity_damp_ratio() const { return body_angular_velocity_damp_ratio; }
+
+ void update();
+ void setup();
+ void call_queries();
+
+ bool is_locked() const;
+ void lock();
+ void unlock();
+
+ void set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value);
+ real_t get_param(PhysicsServer3D::SpaceParameter p_param) const;
+
+ void set_island_count(int p_island_count) { island_count = p_island_count; }
+ int get_island_count() const { return island_count; }
+
+ void set_active_objects(int p_active_objects) { active_objects = p_active_objects; }
+ int get_active_objects() const { return active_objects; }
+
+ int get_collision_pairs() const { return collision_pairs; }
+
+ PhysicsDirectSpaceState3DSW *get_direct_state();
+
+ void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
+ _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); }
+ _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) {
+ if (contact_debug_count < contact_debug.size()) contact_debug.write[contact_debug_count++] = p_contact;
+ }
+ _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contact_debug; }
+ _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
+
+ void set_static_global_body(RID p_body) { static_global_body = p_body; }
+ RID get_static_global_body() { return static_global_body; }
+
+ void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
+ uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
+
+ int test_body_ray_separation(Body3DSW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
+ bool test_body_motion(Body3DSW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
+
+ Space3DSW();
+ ~Space3DSW();
+};
+
+#endif // SPACE__SW_H
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
new file mode 100644
index 0000000000..1a7d5f8cec
--- /dev/null
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -0,0 +1,299 @@
+/*************************************************************************/
+/* step_3d_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "step_3d_sw.h"
+#include "joints_3d_sw.h"
+
+#include "core/os/os.h"
+
+void Step3DSW::_populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island) {
+
+ p_body->set_island_step(_step);
+ p_body->set_island_next(*p_island);
+ *p_island = p_body;
+
+ for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
+
+ 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;
+
+ for (int i = 0; i < c->get_body_count(); i++) {
+ if (i == E->get())
+ continue;
+ Body3DSW *b = c->get_body_ptr()[i];
+ 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);
+ }
+ }
+}
+
+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::_solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta) {
+
+ int at_priority = 1;
+
+ while (p_island) {
+
+ for (int i = 0; i < p_iterations; i++) {
+
+ Constraint3DSW *ci = p_island;
+ while (ci) {
+ ci->solve(p_delta);
+ ci = ci->get_island_next();
+ }
+ }
+
+ 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();
+ }
+ }
+ }
+}
+
+void Step3DSW::_check_suspend(Body3DSW *p_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
+ }
+
+ if (!b->sleep_test(p_delta))
+ can_sleep = false;
+
+ b = b->get_island_next();
+ }
+
+ //put all to sleep or wake up everyoen
+
+ 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
+ }
+
+ bool active = b->is_active();
+
+ if (active == can_sleep)
+ b->set_active(!can_sleep);
+
+ b = b->get_island_next();
+ }
+}
+
+void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
+
+ p_space->lock(); // can't access space during this
+
+ p_space->setup(); //update inertias, etc
+
+ const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list();
+
+ /* INTEGRATE FORCES */
+
+ uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();
+ uint64_t profile_endtime = 0;
+
+ int active_count = 0;
+
+ const SelfList<Body3DSW> *b = body_list->first();
+ while (b) {
+
+ b->self()->integrate_forces(p_delta);
+ b = b->next();
+ active_count++;
+ }
+
+ p_space->set_active_objects(active_count);
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS */
+
+ Body3DSW *island_list = nullptr;
+ Constraint3DSW *constraint_island_list = nullptr;
+ b = body_list->first();
+
+ int 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);
+
+ island->set_island_list_next(island_list);
+ island_list = island;
+
+ if (constraint_island) {
+ constraint_island->set_island_list_next(constraint_island_list);
+ constraint_island_list = constraint_island;
+ island_count++;
+ }
+ }
+ b = b->next();
+ }
+
+ p_space->set_island_count(island_count);
+
+ const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list();
+
+ while (aml.first()) {
+ for (const Set<Constraint3DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
+
+ Constraint3DSW *c = E->get();
+ if (c->get_island_step() == _step)
+ continue;
+ c->set_island_step(_step);
+ c->set_island_next(nullptr);
+ c->set_island_list_next(constraint_island_list);
+ constraint_island_list = c;
+ }
+ p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
+ }
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* SETUP CONSTRAINT ISLANDS */
+
+ {
+ Constraint3DSW *ci = constraint_island_list;
+ while (ci) {
+
+ _setup_island(ci, p_delta);
+ ci = ci->get_island_list_next();
+ }
+ }
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* 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();
+ }
+ }
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ /* INTEGRATE VELOCITIES */
+
+ b = body_list->first();
+ while (b) {
+ const SelfList<Body3DSW> *n = b->next();
+ b->self()->integrate_velocities(p_delta);
+ b = n;
+ }
+
+ /* SLEEP / WAKE UP ISLANDS */
+
+ {
+ Body3DSW *bi = island_list;
+ while (bi) {
+
+ _check_suspend(bi, p_delta);
+ bi = bi->get_island_list_next();
+ }
+ }
+
+ { //profile
+ profile_endtime = OS::get_singleton()->get_ticks_usec();
+ p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);
+ profile_begtime = profile_endtime;
+ }
+
+ p_space->update();
+ p_space->unlock();
+ _step++;
+}
+
+Step3DSW::Step3DSW() {
+
+ _step = 1;
+}
diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h
new file mode 100644
index 0000000000..c735688a9e
--- /dev/null
+++ b/servers/physics_3d/step_3d_sw.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* step_3d_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 STEP_SW_H
+#define STEP_SW_H
+
+#include "space_3d_sw.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);
+
+public:
+ void step(Space3DSW *p_space, real_t p_delta, int p_iterations);
+ Step3DSW();
+};
+
+#endif // STEP__SW_H
diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp
deleted file mode 100644
index 57f3a7979e..0000000000
--- a/servers/physics_server.cpp
+++ /dev/null
@@ -1,800 +0,0 @@
-/*************************************************************************/
-/* physics_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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.h"
-
-#include "core/method_bind_ext.gen.inc"
-#include "core/print_string.h"
-#include "core/project_settings.h"
-
-PhysicsServer *PhysicsServer::singleton = NULL;
-
-void PhysicsDirectBodyState::integrate_forces() {
-
- real_t step = get_step();
- Vector3 lv = get_linear_velocity();
- lv += get_total_gravity() * step;
-
- Vector3 av = get_angular_velocity();
-
- float linear_damp = 1.0 - step * get_total_linear_damp();
-
- if (linear_damp < 0) // reached zero in the given time
- linear_damp = 0;
-
- float angular_damp = 1.0 - step * get_total_angular_damp();
-
- if (angular_damp < 0) // reached zero in the given time
- angular_damp = 0;
-
- lv *= linear_damp;
- av *= angular_damp;
-
- set_linear_velocity(lv);
- set_angular_velocity(av);
-}
-
-Object *PhysicsDirectBodyState::get_contact_collider_object(int p_contact_idx) const {
-
- ObjectID objid = get_contact_collider_id(p_contact_idx);
- Object *obj = ObjectDB::get_instance(objid);
- return obj;
-}
-
-PhysicsServer *PhysicsServer::get_singleton() {
-
- return singleton;
-}
-
-void PhysicsDirectBodyState::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_total_gravity"), &PhysicsDirectBodyState::get_total_gravity);
- ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &PhysicsDirectBodyState::get_total_linear_damp);
- ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState::get_total_angular_damp);
-
- ClassDB::bind_method(D_METHOD("get_center_of_mass"), &PhysicsDirectBodyState::get_center_of_mass);
- ClassDB::bind_method(D_METHOD("get_principal_inertia_axes"), &PhysicsDirectBodyState::get_principal_inertia_axes);
-
- ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState::get_inverse_mass);
- ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState::get_inverse_inertia);
-
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &PhysicsDirectBodyState::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicsDirectBodyState::get_linear_velocity);
-
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &PhysicsDirectBodyState::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicsDirectBodyState::get_angular_velocity);
-
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState::get_transform);
-
- ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState::add_central_force);
- ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState::add_force);
- ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState::add_torque);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "j"), &PhysicsDirectBodyState::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "position", "j"), &PhysicsDirectBodyState::apply_impulse);
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "j"), &PhysicsDirectBodyState::apply_torque_impulse);
-
- ClassDB::bind_method(D_METHOD("set_sleep_state", "enabled"), &PhysicsDirectBodyState::set_sleep_state);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &PhysicsDirectBodyState::is_sleeping);
-
- ClassDB::bind_method(D_METHOD("get_contact_count"), &PhysicsDirectBodyState::get_contact_count);
-
- ClassDB::bind_method(D_METHOD("get_contact_local_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_position);
- ClassDB::bind_method(D_METHOD("get_contact_local_normal", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_normal);
- ClassDB::bind_method(D_METHOD("get_contact_impulse", "contact_idx"), &PhysicsDirectBodyState::get_contact_impulse);
- ClassDB::bind_method(D_METHOD("get_contact_local_shape", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_shape);
- ClassDB::bind_method(D_METHOD("get_contact_collider", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider);
- ClassDB::bind_method(D_METHOD("get_contact_collider_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_position);
- ClassDB::bind_method(D_METHOD("get_contact_collider_id", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_id);
- ClassDB::bind_method(D_METHOD("get_contact_collider_object", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_object);
- ClassDB::bind_method(D_METHOD("get_contact_collider_shape", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_shape);
- ClassDB::bind_method(D_METHOD("get_contact_collider_velocity_at_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_velocity_at_position);
- ClassDB::bind_method(D_METHOD("get_step"), &PhysicsDirectBodyState::get_step);
- ClassDB::bind_method(D_METHOD("integrate_forces"), &PhysicsDirectBodyState::integrate_forces);
- ClassDB::bind_method(D_METHOD("get_space_state"), &PhysicsDirectBodyState::get_space_state);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "", "get_step");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inverse_mass"), "", "get_inverse_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inverse_inertia"), "", "get_inverse_inertia");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "total_gravity"), "", "get_total_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass"), "", "get_center_of_mass");
- ADD_PROPERTY(PropertyInfo(Variant::BASIS, "principal_inertia_axes"), "", "get_principal_inertia_axes");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
-}
-
-PhysicsDirectBodyState::PhysicsDirectBodyState() {}
-
-///////////////////////////////////////////////////////
-
-void PhysicsShapeQueryParameters::set_shape(const RES &p_shape) {
-
- ERR_FAIL_COND(p_shape.is_null());
- shape = p_shape->get_rid();
-}
-
-void PhysicsShapeQueryParameters::set_shape_rid(const RID &p_shape) {
-
- shape = p_shape;
-}
-
-RID PhysicsShapeQueryParameters::get_shape_rid() const {
-
- return shape;
-}
-
-void PhysicsShapeQueryParameters::set_transform(const Transform &p_transform) {
-
- transform = p_transform;
-}
-Transform PhysicsShapeQueryParameters::get_transform() const {
-
- return transform;
-}
-
-void PhysicsShapeQueryParameters::set_margin(float p_margin) {
-
- margin = p_margin;
-}
-
-float PhysicsShapeQueryParameters::get_margin() const {
-
- return margin;
-}
-
-void PhysicsShapeQueryParameters::set_collision_mask(int p_collision_mask) {
-
- collision_mask = p_collision_mask;
-}
-int PhysicsShapeQueryParameters::get_collision_mask() const {
-
- return collision_mask;
-}
-
-void PhysicsShapeQueryParameters::set_exclude(const Vector<RID> &p_exclude) {
-
- exclude.clear();
- for (int i = 0; i < p_exclude.size(); i++)
- exclude.insert(p_exclude[i]);
-}
-
-Vector<RID> PhysicsShapeQueryParameters::get_exclude() const {
-
- Vector<RID> ret;
- ret.resize(exclude.size());
- int idx = 0;
- for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) {
- ret.write[idx] = E->get();
- }
- return ret;
-}
-
-void PhysicsShapeQueryParameters::set_collide_with_bodies(bool p_enable) {
- collide_with_bodies = p_enable;
-}
-
-bool PhysicsShapeQueryParameters::is_collide_with_bodies_enabled() const {
- return collide_with_bodies;
-}
-
-void PhysicsShapeQueryParameters::set_collide_with_areas(bool p_enable) {
- collide_with_areas = p_enable;
-}
-
-bool PhysicsShapeQueryParameters::is_collide_with_areas_enabled() const {
- return collide_with_areas;
-}
-
-void PhysicsShapeQueryParameters::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_shape", "shape"), &PhysicsShapeQueryParameters::set_shape);
- ClassDB::bind_method(D_METHOD("set_shape_rid", "shape"), &PhysicsShapeQueryParameters::set_shape_rid);
- ClassDB::bind_method(D_METHOD("get_shape_rid"), &PhysicsShapeQueryParameters::get_shape_rid);
-
- ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsShapeQueryParameters::set_transform);
- ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsShapeQueryParameters::get_transform);
-
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsShapeQueryParameters::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsShapeQueryParameters::get_margin);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsShapeQueryParameters::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsShapeQueryParameters::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsShapeQueryParameters::set_exclude);
- ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsShapeQueryParameters::get_exclude);
-
- ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsShapeQueryParameters::set_collide_with_bodies);
- ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsShapeQueryParameters::is_collide_with_bodies_enabled);
-
- ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsShapeQueryParameters::set_collide_with_areas);
- ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters::is_collide_with_areas_enabled);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::_RID) + ":"), "set_exclude", "get_exclude");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin");
- //ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", ""); // FIXME: Lacks a getter
- ADD_PROPERTY(PropertyInfo(Variant::_RID, "shape_rid"), "set_shape_rid", "get_shape_rid");
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
-}
-
-PhysicsShapeQueryParameters::PhysicsShapeQueryParameters() {
-
- margin = 0;
- collision_mask = 0x7FFFFFFF;
- collide_with_bodies = true;
- collide_with_areas = false;
-}
-
-/////////////////////////////////////
-
-Dictionary PhysicsDirectSpaceState::_intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
-
- RayResult inters;
- Set<RID> exclude;
- for (int i = 0; i < p_exclude.size(); i++)
- exclude.insert(p_exclude[i]);
-
- bool res = intersect_ray(p_from, p_to, inters, exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas);
-
- if (!res)
- return Dictionary();
-
- Dictionary d;
- d["position"] = inters.position;
- d["normal"] = inters.normal;
- d["collider_id"] = inters.collider_id;
- d["collider"] = inters.collider;
- d["shape"] = inters.shape;
- d["rid"] = inters.rid;
-
- return d;
-}
-
-Array PhysicsDirectSpaceState::_intersect_shape(const Ref<PhysicsShapeQueryParameters> &p_shape_query, int p_max_results) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
-
- Vector<ShapeResult> sr;
- sr.resize(p_max_results);
- int rc = intersect_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, sr.ptrw(), sr.size(), p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- Array ret;
- ret.resize(rc);
- for (int i = 0; i < rc; i++) {
-
- Dictionary d;
- d["rid"] = sr[i].rid;
- d["collider_id"] = sr[i].collider_id;
- d["collider"] = sr[i].collider;
- d["shape"] = sr[i].shape;
- ret[i] = d;
- }
-
- return ret;
-}
-
-Array PhysicsDirectSpaceState::_cast_motion(const Ref<PhysicsShapeQueryParameters> &p_shape_query, const Vector3 &p_motion) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
-
- float closest_safe, closest_unsafe;
- bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- if (!res)
- return Array();
- Array ret;
- ret.resize(2);
- ret[0] = closest_safe;
- ret[1] = closest_unsafe;
- return ret;
-}
-Array PhysicsDirectSpaceState::_collide_shape(const Ref<PhysicsShapeQueryParameters> &p_shape_query, int p_max_results) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
-
- Vector<Vector3> ret;
- ret.resize(p_max_results * 2);
- int rc = 0;
- bool res = collide_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, ret.ptrw(), p_max_results, rc, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- if (!res)
- return Array();
- Array r;
- r.resize(rc * 2);
- for (int i = 0; i < rc * 2; i++)
- r[i] = ret[i];
- return r;
-}
-Dictionary PhysicsDirectSpaceState::_get_rest_info(const Ref<PhysicsShapeQueryParameters> &p_shape_query) {
-
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Dictionary());
-
- ShapeRestInfo sri;
-
- bool res = rest_info(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, &sri, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
- Dictionary r;
- if (!res)
- return r;
-
- r["point"] = sri.point;
- r["normal"] = sri.normal;
- r["rid"] = sri.rid;
- r["collider_id"] = sri.collider_id;
- r["shape"] = sri.shape;
- r["linear_velocity"] = sri.linear_velocity;
-
- return r;
-}
-
-PhysicsDirectSpaceState::PhysicsDirectSpaceState() {
-}
-
-void PhysicsDirectSpaceState::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState::_intersect_shape, DEFVAL(32));
- ClassDB::bind_method(D_METHOD("cast_motion", "shape", "motion"), &PhysicsDirectSpaceState::_cast_motion);
- ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState::_collide_shape, DEFVAL(32));
- ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState::_get_rest_info);
-}
-
-int PhysicsShapeQueryResult::get_result_count() const {
-
- return result.size();
-}
-RID PhysicsShapeQueryResult::get_result_rid(int p_idx) const {
-
- return result[p_idx].rid;
-}
-ObjectID PhysicsShapeQueryResult::get_result_object_id(int p_idx) const {
-
- return result[p_idx].collider_id;
-}
-Object *PhysicsShapeQueryResult::get_result_object(int p_idx) const {
-
- return result[p_idx].collider;
-}
-int PhysicsShapeQueryResult::get_result_object_shape(int p_idx) const {
-
- return result[p_idx].shape;
-}
-
-PhysicsShapeQueryResult::PhysicsShapeQueryResult() {
-}
-
-void PhysicsShapeQueryResult::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("get_result_count"), &PhysicsShapeQueryResult::get_result_count);
- ClassDB::bind_method(D_METHOD("get_result_rid", "idx"), &PhysicsShapeQueryResult::get_result_rid);
- ClassDB::bind_method(D_METHOD("get_result_object_id", "idx"), &PhysicsShapeQueryResult::get_result_object_id);
- ClassDB::bind_method(D_METHOD("get_result_object", "idx"), &PhysicsShapeQueryResult::get_result_object);
- ClassDB::bind_method(D_METHOD("get_result_object_shape", "idx"), &PhysicsShapeQueryResult::get_result_object_shape);
-}
-
-///////////////////////////////////////
-
-void PhysicsServer::_bind_methods() {
-
-#ifndef _3D_DISABLED
-
- ClassDB::bind_method(D_METHOD("shape_create", "type"), &PhysicsServer::shape_create);
- ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &PhysicsServer::shape_set_data);
-
- ClassDB::bind_method(D_METHOD("shape_get_type", "shape"), &PhysicsServer::shape_get_type);
- ClassDB::bind_method(D_METHOD("shape_get_data", "shape"), &PhysicsServer::shape_get_data);
-
- ClassDB::bind_method(D_METHOD("space_create"), &PhysicsServer::space_create);
- ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &PhysicsServer::space_set_active);
- ClassDB::bind_method(D_METHOD("space_is_active", "space"), &PhysicsServer::space_is_active);
- ClassDB::bind_method(D_METHOD("space_set_param", "space", "param", "value"), &PhysicsServer::space_set_param);
- ClassDB::bind_method(D_METHOD("space_get_param", "space", "param"), &PhysicsServer::space_get_param);
- ClassDB::bind_method(D_METHOD("space_get_direct_state", "space"), &PhysicsServer::space_get_direct_state);
-
- ClassDB::bind_method(D_METHOD("area_create"), &PhysicsServer::area_create);
- ClassDB::bind_method(D_METHOD("area_set_space", "area", "space"), &PhysicsServer::area_set_space);
- ClassDB::bind_method(D_METHOD("area_get_space", "area"), &PhysicsServer::area_get_space);
-
- ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer::area_set_space_override_mode);
- ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer::area_get_space_override_mode);
-
- ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer::area_add_shape, DEFVAL(Transform()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer::area_set_shape);
- ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer::area_set_shape_transform);
- ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &PhysicsServer::area_set_shape_disabled);
-
- ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &PhysicsServer::area_get_shape_count);
- ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &PhysicsServer::area_get_shape);
- ClassDB::bind_method(D_METHOD("area_get_shape_transform", "area", "shape_idx"), &PhysicsServer::area_get_shape_transform);
-
- ClassDB::bind_method(D_METHOD("area_remove_shape", "area", "shape_idx"), &PhysicsServer::area_remove_shape);
- ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer::area_clear_shapes);
-
- ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer::area_set_collision_layer);
- ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer::area_set_collision_mask);
-
- ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer::area_set_param);
- ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer::area_set_transform);
-
- ClassDB::bind_method(D_METHOD("area_get_param", "area", "param"), &PhysicsServer::area_get_param);
- ClassDB::bind_method(D_METHOD("area_get_transform", "area"), &PhysicsServer::area_get_transform);
-
- ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &PhysicsServer::area_attach_object_instance_id);
- ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &PhysicsServer::area_get_object_instance_id);
-
- ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &PhysicsServer::area_set_monitor_callback);
- ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &PhysicsServer::area_set_area_monitor_callback);
- ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &PhysicsServer::area_set_monitorable);
-
- ClassDB::bind_method(D_METHOD("area_set_ray_pickable", "area", "enable"), &PhysicsServer::area_set_ray_pickable);
- ClassDB::bind_method(D_METHOD("area_is_ray_pickable", "area"), &PhysicsServer::area_is_ray_pickable);
-
- ClassDB::bind_method(D_METHOD("body_create", "mode", "init_sleeping"), &PhysicsServer::body_create, DEFVAL(BODY_MODE_RIGID), DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("body_set_space", "body", "space"), &PhysicsServer::body_set_space);
- ClassDB::bind_method(D_METHOD("body_get_space", "body"), &PhysicsServer::body_get_space);
-
- ClassDB::bind_method(D_METHOD("body_set_mode", "body", "mode"), &PhysicsServer::body_set_mode);
- ClassDB::bind_method(D_METHOD("body_get_mode", "body"), &PhysicsServer::body_get_mode);
-
- ClassDB::bind_method(D_METHOD("body_set_collision_layer", "body", "layer"), &PhysicsServer::body_set_collision_layer);
- ClassDB::bind_method(D_METHOD("body_get_collision_layer", "body"), &PhysicsServer::body_get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer::body_set_collision_mask);
- ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer::body_get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer::body_add_shape, DEFVAL(Transform()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer::body_set_shape);
- ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer::body_set_shape_transform);
- ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &PhysicsServer::body_set_shape_disabled);
-
- ClassDB::bind_method(D_METHOD("body_get_shape_count", "body"), &PhysicsServer::body_get_shape_count);
- ClassDB::bind_method(D_METHOD("body_get_shape", "body", "shape_idx"), &PhysicsServer::body_get_shape);
- ClassDB::bind_method(D_METHOD("body_get_shape_transform", "body", "shape_idx"), &PhysicsServer::body_get_shape_transform);
-
- ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &PhysicsServer::body_remove_shape);
- ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &PhysicsServer::body_clear_shapes);
-
- ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &PhysicsServer::body_attach_object_instance_id);
- ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &PhysicsServer::body_get_object_instance_id);
-
- ClassDB::bind_method(D_METHOD("body_set_enable_continuous_collision_detection", "body", "enable"), &PhysicsServer::body_set_enable_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("body_is_continuous_collision_detection_enabled", "body"), &PhysicsServer::body_is_continuous_collision_detection_enabled);
-
- ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer::body_set_param);
- ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer::body_get_param);
-
- ClassDB::bind_method(D_METHOD("body_set_kinematic_safe_margin", "body", "margin"), &PhysicsServer::body_set_kinematic_safe_margin);
- ClassDB::bind_method(D_METHOD("body_get_kinematic_safe_margin", "body"), &PhysicsServer::body_get_kinematic_safe_margin);
-
- ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer::body_set_state);
- ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer::body_get_state);
-
- ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &PhysicsServer::body_add_central_force);
- ClassDB::bind_method(D_METHOD("body_add_force", "body", "force", "position"), &PhysicsServer::body_add_force);
- ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &PhysicsServer::body_add_torque);
-
- ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &PhysicsServer::body_apply_central_impulse);
- ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &PhysicsServer::body_apply_impulse);
- ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &PhysicsServer::body_apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &PhysicsServer::body_set_axis_velocity);
-
- ClassDB::bind_method(D_METHOD("body_set_axis_lock", "body", "axis", "lock"), &PhysicsServer::body_set_axis_lock);
- ClassDB::bind_method(D_METHOD("body_is_axis_locked", "body", "axis"), &PhysicsServer::body_is_axis_locked);
-
- ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &PhysicsServer::body_add_collision_exception);
- ClassDB::bind_method(D_METHOD("body_remove_collision_exception", "body", "excepted_body"), &PhysicsServer::body_remove_collision_exception);
-
- ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &PhysicsServer::body_set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &PhysicsServer::body_get_max_contacts_reported);
-
- ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer::body_set_omit_force_integration);
- ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer::body_is_omitting_force_integration);
-
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer::body_set_force_integration_callback, DEFVAL(Variant()));
-
- ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer::body_set_ray_pickable);
- ClassDB::bind_method(D_METHOD("body_is_ray_pickable", "body"), &PhysicsServer::body_is_ray_pickable);
-
- ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer::body_get_direct_state);
-
- /* 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_pin", "body_A", "local_A", "body_B", "local_B"), &PhysicsServer::joint_create_pin);
- ClassDB::bind_method(D_METHOD("pin_joint_set_param", "joint", "param", "value"), &PhysicsServer::pin_joint_set_param);
- ClassDB::bind_method(D_METHOD("pin_joint_get_param", "joint", "param"), &PhysicsServer::pin_joint_get_param);
-
- ClassDB::bind_method(D_METHOD("pin_joint_set_local_a", "joint", "local_A"), &PhysicsServer::pin_joint_set_local_a);
- ClassDB::bind_method(D_METHOD("pin_joint_get_local_a", "joint"), &PhysicsServer::pin_joint_get_local_a);
-
- ClassDB::bind_method(D_METHOD("pin_joint_set_local_b", "joint", "local_B"), &PhysicsServer::pin_joint_set_local_b);
- ClassDB::bind_method(D_METHOD("pin_joint_get_local_b", "joint"), &PhysicsServer::pin_joint_get_local_b);
-
- BIND_ENUM_CONSTANT(PIN_JOINT_BIAS);
- BIND_ENUM_CONSTANT(PIN_JOINT_DAMPING);
- BIND_ENUM_CONSTANT(PIN_JOINT_IMPULSE_CLAMP);
-
- BIND_ENUM_CONSTANT(HINGE_JOINT_BIAS);
- BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_UPPER);
- BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_LOWER);
- BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_BIAS);
- BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_RELAXATION);
- BIND_ENUM_CONSTANT(HINGE_JOINT_MOTOR_TARGET_VELOCITY);
- BIND_ENUM_CONSTANT(HINGE_JOINT_MOTOR_MAX_IMPULSE);
-
- 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"), &PhysicsServer::joint_create_hinge);
-
- ClassDB::bind_method(D_METHOD("hinge_joint_set_param", "joint", "param", "value"), &PhysicsServer::hinge_joint_set_param);
- ClassDB::bind_method(D_METHOD("hinge_joint_get_param", "joint", "param"), &PhysicsServer::hinge_joint_get_param);
-
- ClassDB::bind_method(D_METHOD("hinge_joint_set_flag", "joint", "flag", "enabled"), &PhysicsServer::hinge_joint_set_flag);
- ClassDB::bind_method(D_METHOD("hinge_joint_get_flag", "joint", "flag"), &PhysicsServer::hinge_joint_get_flag);
-
- ClassDB::bind_method(D_METHOD("joint_create_slider", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer::joint_create_slider);
-
- ClassDB::bind_method(D_METHOD("slider_joint_set_param", "joint", "param", "value"), &PhysicsServer::slider_joint_set_param);
- ClassDB::bind_method(D_METHOD("slider_joint_get_param", "joint", "param"), &PhysicsServer::slider_joint_get_param);
-
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_UPPER);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_LOWER);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_DAMPING);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_MOTION_SOFTNESS);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_MOTION_RESTITUTION);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_MOTION_DAMPING);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING);
-
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_UPPER);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_LOWER);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_DAMPING);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_MOTION_DAMPING);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS);
- BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION);
- 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"), &PhysicsServer::joint_create_cone_twist);
-
- ClassDB::bind_method(D_METHOD("cone_twist_joint_set_param", "joint", "param", "value"), &PhysicsServer::cone_twist_joint_set_param);
- ClassDB::bind_method(D_METHOD("cone_twist_joint_get_param", "joint", "param"), &PhysicsServer::cone_twist_joint_get_param);
-
- BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_SWING_SPAN);
- BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_TWIST_SPAN);
- BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_BIAS);
- BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_SOFTNESS);
- BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_RELAXATION);
-
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_LOWER_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_UPPER_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_RESTITUTION);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_DAMPING);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LOWER_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_UPPER_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_DAMPING);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_RESTITUTION);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_FORCE_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_ERP);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT);
-
- BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_MOTOR);
- BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR);
-
- ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer::joint_get_type);
-
- ClassDB::bind_method(D_METHOD("joint_set_solver_priority", "joint", "priority"), &PhysicsServer::joint_set_solver_priority);
- ClassDB::bind_method(D_METHOD("joint_get_solver_priority", "joint"), &PhysicsServer::joint_get_solver_priority);
-
- ClassDB::bind_method(D_METHOD("joint_create_generic_6dof", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer::joint_create_generic_6dof);
-
- ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_param", "joint", "axis", "param", "value"), &PhysicsServer::generic_6dof_joint_set_param);
- ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_param", "joint", "axis", "param"), &PhysicsServer::generic_6dof_joint_get_param);
-
- ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_flag", "joint", "axis", "flag", "enable"), &PhysicsServer::generic_6dof_joint_set_flag);
- ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_flag", "joint", "axis", "flag"), &PhysicsServer::generic_6dof_joint_get_flag);
-
- ClassDB::bind_method(D_METHOD("free_rid", "rid"), &PhysicsServer::free);
-
- ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer::set_active);
-
- ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer::get_process_info);
-
- BIND_ENUM_CONSTANT(SHAPE_PLANE);
- BIND_ENUM_CONSTANT(SHAPE_RAY);
- BIND_ENUM_CONSTANT(SHAPE_SPHERE);
- BIND_ENUM_CONSTANT(SHAPE_BOX);
- BIND_ENUM_CONSTANT(SHAPE_CAPSULE);
- BIND_ENUM_CONSTANT(SHAPE_CYLINDER);
- BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
- BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
- BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP);
- BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
-
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_DISTANCE_SCALE);
- BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_ATTENUATION);
- BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP);
- BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP);
- BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY);
-
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_DISABLED);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE_REPLACE);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE);
- BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE_COMBINE);
-
- BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
- BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
- BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
- BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER);
-
- BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
- BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
- BIND_ENUM_CONSTANT(BODY_PARAM_MASS);
- BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE);
- BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP);
- BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP);
- BIND_ENUM_CONSTANT(BODY_PARAM_MAX);
-
- BIND_ENUM_CONSTANT(BODY_STATE_TRANSFORM);
- BIND_ENUM_CONSTANT(BODY_STATE_LINEAR_VELOCITY);
- BIND_ENUM_CONSTANT(BODY_STATE_ANGULAR_VELOCITY);
- BIND_ENUM_CONSTANT(BODY_STATE_SLEEPING);
- BIND_ENUM_CONSTANT(BODY_STATE_CAN_SLEEP);
-
- BIND_ENUM_CONSTANT(AREA_BODY_ADDED);
- BIND_ENUM_CONSTANT(AREA_BODY_REMOVED);
-
- BIND_ENUM_CONSTANT(INFO_ACTIVE_OBJECTS);
- BIND_ENUM_CONSTANT(INFO_COLLISION_PAIRS);
- BIND_ENUM_CONSTANT(INFO_ISLAND_COUNT);
-
- BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_RECYCLE_RADIUS);
- BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_MAX_SEPARATION);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP);
- BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO);
- BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
- BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);
-
- BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X);
- BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y);
- BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Z);
- BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_X);
- BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Y);
- BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Z);
-
-#endif
-}
-
-PhysicsServer::PhysicsServer() {
-
- ERR_FAIL_COND(singleton != NULL);
- singleton = this;
-}
-
-PhysicsServer::~PhysicsServer() {
-
- singleton = NULL;
-}
-
-Vector<PhysicsServerManager::ClassInfo> PhysicsServerManager::physics_servers;
-int PhysicsServerManager::default_server_id = -1;
-int PhysicsServerManager::default_server_priority = -1;
-const String PhysicsServerManager::setting_property_name("physics/3d/physics_engine");
-
-void PhysicsServerManager::on_servers_changed() {
-
- String physics_servers2("DEFAULT");
- for (int i = get_servers_count() - 1; 0 <= i; --i) {
- physics_servers2 += "," + get_server_name(i);
- }
- ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers2));
-}
-
-void PhysicsServerManager::register_server(const String &p_name, CreatePhysicsServerCallback p_creat_callback) {
-
- ERR_FAIL_COND(!p_creat_callback);
- ERR_FAIL_COND(find_server_id(p_name) != -1);
- physics_servers.push_back(ClassInfo(p_name, p_creat_callback));
- on_servers_changed();
-}
-
-void PhysicsServerManager::set_default_server(const String &p_name, int p_priority) {
-
- const int id = find_server_id(p_name);
- ERR_FAIL_COND(id == -1); // Not found
- if (default_server_priority < p_priority) {
- default_server_id = id;
- default_server_priority = p_priority;
- }
-}
-
-int PhysicsServerManager::find_server_id(const String &p_name) {
-
- for (int i = physics_servers.size() - 1; 0 <= i; --i) {
- if (p_name == physics_servers[i].name) {
- return i;
- }
- }
- return -1;
-}
-
-int PhysicsServerManager::get_servers_count() {
- return physics_servers.size();
-}
-
-String PhysicsServerManager::get_server_name(int p_id) {
- ERR_FAIL_INDEX_V(p_id, get_servers_count(), "");
- return physics_servers[p_id].name;
-}
-
-PhysicsServer *PhysicsServerManager::new_default_server() {
- ERR_FAIL_COND_V(default_server_id == -1, NULL);
- return physics_servers[default_server_id].create_callback();
-}
-
-PhysicsServer *PhysicsServerManager::new_server(const String &p_name) {
- int id = find_server_id(p_name);
- if (id == -1) {
- return NULL;
- } else {
- return physics_servers[id].create_callback();
- }
-}
diff --git a/servers/physics_server.h b/servers/physics_server.h
deleted file mode 100644
index f1388c8758..0000000000
--- a/servers/physics_server.h
+++ /dev/null
@@ -1,844 +0,0 @@
-/*************************************************************************/
-/* physics_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 PHYSICS_SERVER_H
-#define PHYSICS_SERVER_H
-
-#include "core/object.h"
-#include "core/resource.h"
-
-class PhysicsDirectSpaceState;
-
-class PhysicsDirectBodyState : public Object {
-
- GDCLASS(PhysicsDirectBodyState, Object);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual Vector3 get_total_gravity() const = 0;
- virtual float get_total_angular_damp() const = 0;
- virtual float get_total_linear_damp() const = 0;
-
- virtual Vector3 get_center_of_mass() const = 0;
- virtual Basis get_principal_inertia_axes() const = 0;
- virtual float get_inverse_mass() const = 0; // get the mass
- virtual Vector3 get_inverse_inertia() const = 0; // get density of this body space
- virtual Basis get_inverse_inertia_tensor() const = 0; // get density of this body space
-
- virtual void set_linear_velocity(const Vector3 &p_velocity) = 0;
- virtual Vector3 get_linear_velocity() const = 0;
-
- virtual void set_angular_velocity(const Vector3 &p_velocity) = 0;
- virtual Vector3 get_angular_velocity() const = 0;
-
- virtual void set_transform(const Transform &p_transform) = 0;
- virtual Transform get_transform() const = 0;
-
- virtual void add_central_force(const Vector3 &p_force) = 0;
- virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) = 0;
- virtual void add_torque(const Vector3 &p_torque) = 0;
- virtual void apply_central_impulse(const Vector3 &p_j) = 0;
- virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) = 0;
- virtual void apply_torque_impulse(const Vector3 &p_j) = 0;
-
- virtual void set_sleep_state(bool p_enable) = 0;
- virtual bool is_sleeping() const = 0;
-
- virtual int get_contact_count() const = 0;
-
- virtual Vector3 get_contact_local_position(int p_contact_idx) const = 0;
- virtual Vector3 get_contact_local_normal(int p_contact_idx) const = 0;
- virtual float get_contact_impulse(int p_contact_idx) const = 0;
- virtual int get_contact_local_shape(int p_contact_idx) const = 0;
-
- virtual RID get_contact_collider(int p_contact_idx) const = 0;
- virtual Vector3 get_contact_collider_position(int p_contact_idx) const = 0;
- virtual ObjectID get_contact_collider_id(int p_contact_idx) const = 0;
- virtual Object *get_contact_collider_object(int p_contact_idx) const;
- virtual int get_contact_collider_shape(int p_contact_idx) const = 0;
- virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const = 0;
-
- virtual real_t get_step() const = 0;
- virtual void integrate_forces();
-
- virtual PhysicsDirectSpaceState *get_space_state() = 0;
-
- PhysicsDirectBodyState();
-};
-
-class PhysicsShapeQueryResult;
-
-class PhysicsShapeQueryParameters : public Reference {
-
- GDCLASS(PhysicsShapeQueryParameters, Reference);
- friend class PhysicsDirectSpaceState;
-
- RID shape;
- Transform transform;
- float margin;
- Set<RID> exclude;
- uint32_t collision_mask;
-
- bool collide_with_bodies;
- bool collide_with_areas;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_shape(const RES &p_shape);
- void set_shape_rid(const RID &p_shape);
- RID get_shape_rid() const;
-
- void set_transform(const Transform &p_transform);
- Transform get_transform() const;
-
- void set_margin(float p_margin);
- float get_margin() const;
-
- void set_collision_mask(int p_collision_mask);
- int get_collision_mask() const;
-
- void set_exclude(const Vector<RID> &p_exclude);
- Vector<RID> get_exclude() const;
-
- void set_collide_with_bodies(bool p_enable);
- bool is_collide_with_bodies_enabled() const;
-
- void set_collide_with_areas(bool p_enable);
- bool is_collide_with_areas_enabled() const;
-
- PhysicsShapeQueryParameters();
-};
-
-class PhysicsDirectSpaceState : public Object {
-
- GDCLASS(PhysicsDirectSpaceState, Object);
-
-private:
- Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
- Array _intersect_shape(const Ref<PhysicsShapeQueryParameters> &p_shape_query, int p_max_results = 32);
- Array _cast_motion(const Ref<PhysicsShapeQueryParameters> &p_shape_query, const Vector3 &p_motion);
- Array _collide_shape(const Ref<PhysicsShapeQueryParameters> &p_shape_query, int p_max_results = 32);
- Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters> &p_shape_query);
-
-protected:
- static void _bind_methods();
-
-public:
- struct ShapeResult {
-
- RID rid;
- ObjectID collider_id;
- Object *collider;
- int shape;
- };
-
- virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- struct RayResult {
-
- Vector3 position;
- Vector3 normal;
- RID rid;
- ObjectID collider_id;
- Object *collider;
- int shape;
- };
-
- virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0;
-
- virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- struct ShapeRestInfo {
-
- Vector3 point;
- Vector3 normal;
- RID rid;
- ObjectID collider_id;
- int shape;
- Vector3 linear_velocity; //velocity at contact point
- };
-
- virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = NULL) = 0;
-
- virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
-
- virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0;
-
- PhysicsDirectSpaceState();
-};
-
-class PhysicsShapeQueryResult : public Reference {
-
- GDCLASS(PhysicsShapeQueryResult, Reference);
-
- Vector<PhysicsDirectSpaceState::ShapeResult> result;
-
- friend class PhysicsDirectSpaceState;
-
-protected:
- static void _bind_methods();
-
-public:
- int get_result_count() const;
- RID get_result_rid(int p_idx) const;
- ObjectID get_result_object_id(int p_idx) const;
- Object *get_result_object(int p_idx) const;
- int get_result_object_shape(int p_idx) const;
-
- PhysicsShapeQueryResult();
-};
-
-class PhysicsServer : public Object {
-
- GDCLASS(PhysicsServer, Object);
-
- static PhysicsServer *singleton;
-
-protected:
- static void _bind_methods();
-
-public:
- static PhysicsServer *get_singleton();
-
- enum ShapeType {
- SHAPE_PLANE, ///< plane:"plane"
- SHAPE_RAY, ///< float:"length"
- SHAPE_SPHERE, ///< float:"radius"
- SHAPE_BOX, ///< vec3:"extents"
- SHAPE_CAPSULE, ///< dict( float:"radius", float:"height"):capsule
- SHAPE_CYLINDER, ///< dict( float:"radius", float:"height"):cylinder
- 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_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;
- 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;
-
- virtual ShapeType shape_get_type(RID p_shape) const = 0;
- virtual Variant shape_get_data(RID p_shape) const = 0;
-
- virtual void shape_set_margin(RID p_shape, real_t p_margin) = 0;
- virtual real_t shape_get_margin(RID p_shape) const = 0;
-
- virtual real_t shape_get_custom_solver_bias(RID p_shape) const = 0;
-
- /* SPACE API */
-
- virtual RID space_create() = 0;
- virtual void space_set_active(RID p_space, bool p_active) = 0;
- virtual bool space_is_active(RID p_space) const = 0;
-
- enum SpaceParameter {
-
- SPACE_PARAM_CONTACT_RECYCLE_RADIUS,
- SPACE_PARAM_CONTACT_MAX_SEPARATION,
- SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,
- SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD,
- SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD,
- SPACE_PARAM_BODY_TIME_TO_SLEEP,
- SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,
- SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
- SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH
- };
-
- virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0;
- virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const = 0;
-
- // this function only works on physics process, errors and returns null otherwise
- virtual PhysicsDirectSpaceState *space_get_direct_state(RID p_space) = 0;
-
- virtual void space_set_debug_contacts(RID p_space, int p_max_contacts) = 0;
- virtual Vector<Vector3> space_get_contacts(RID p_space) const = 0;
- virtual int space_get_contact_count(RID p_space) const = 0;
-
- //missing space parameters
-
- /* AREA API */
-
- //missing attenuation? missing better override?
-
- enum AreaParameter {
- AREA_PARAM_GRAVITY,
- AREA_PARAM_GRAVITY_VECTOR,
- AREA_PARAM_GRAVITY_IS_POINT,
- AREA_PARAM_GRAVITY_DISTANCE_SCALE,
- AREA_PARAM_GRAVITY_POINT_ATTENUATION,
- AREA_PARAM_LINEAR_DAMP,
- AREA_PARAM_ANGULAR_DAMP,
- AREA_PARAM_PRIORITY
- };
-
- virtual RID area_create() = 0;
-
- virtual void area_set_space(RID p_area, RID p_space) = 0;
- virtual RID area_get_space(RID p_area) const = 0;
-
- enum AreaSpaceOverrideMode {
- AREA_SPACE_OVERRIDE_DISABLED,
- AREA_SPACE_OVERRIDE_COMBINE,
- AREA_SPACE_OVERRIDE_COMBINE_REPLACE,
- AREA_SPACE_OVERRIDE_REPLACE,
- AREA_SPACE_OVERRIDE_REPLACE_COMBINE
- };
-
- virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
- virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
-
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
- virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
- virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) = 0;
-
- virtual int area_get_shape_count(RID p_area) const = 0;
- virtual RID area_get_shape(RID p_area, int p_shape_idx) const = 0;
- virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const = 0;
-
- virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0;
- virtual void area_clear_shapes(RID p_area) = 0;
-
- virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) = 0;
-
- virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id) = 0;
- virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
-
- virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
- virtual void area_set_transform(RID p_area, const Transform &p_transform) = 0;
-
- virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
- virtual Transform area_get_transform(RID p_area) const = 0;
-
- virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
- virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
-
- virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
-
- virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
- 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 */
-
- //missing ccd?
-
- enum BodyMode {
- BODY_MODE_STATIC,
- BODY_MODE_KINEMATIC,
- BODY_MODE_RIGID,
- BODY_MODE_CHARACTER
- };
-
- virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) = 0;
-
- virtual void body_set_space(RID p_body, RID p_space) = 0;
- virtual RID body_get_space(RID p_body) const = 0;
-
- virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
- virtual BodyMode body_get_mode(RID p_body) const = 0;
-
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
- virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
- virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) = 0;
-
- virtual int body_get_shape_count(RID p_body) const = 0;
- virtual RID body_get_shape(RID p_body, int p_shape_idx) const = 0;
- virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const = 0;
-
- virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
- virtual void body_clear_shapes(RID p_body) = 0;
-
- virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) = 0;
-
- virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) = 0;
- virtual ObjectID body_get_object_instance_id(RID p_body) const = 0;
-
- virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) = 0;
- virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const = 0;
-
- virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
- virtual uint32_t body_get_collision_layer(RID p_body) const = 0;
-
- virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
- virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
-
- virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0;
- virtual uint32_t body_get_user_flags(RID p_body) const = 0;
-
- // common body variables
- enum BodyParameter {
- BODY_PARAM_BOUNCE,
- BODY_PARAM_FRICTION,
- BODY_PARAM_MASS, ///< unused for static, always infinite
- BODY_PARAM_GRAVITY_SCALE,
- BODY_PARAM_LINEAR_DAMP,
- BODY_PARAM_ANGULAR_DAMP,
- BODY_PARAM_MAX,
- };
-
- virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
- virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
-
- virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0;
- virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0;
-
- //state
- enum BodyState {
- BODY_STATE_TRANSFORM,
- BODY_STATE_LINEAR_VELOCITY,
- BODY_STATE_ANGULAR_VELOCITY,
- BODY_STATE_SLEEPING,
- BODY_STATE_CAN_SLEEP
- };
-
- virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0;
- virtual Variant body_get_state(RID p_body, BodyState p_state) const = 0;
-
- //do something about it
- virtual void body_set_applied_force(RID p_body, const Vector3 &p_force) = 0;
- virtual Vector3 body_get_applied_force(RID p_body) const = 0;
-
- virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque) = 0;
- virtual Vector3 body_get_applied_torque(RID p_body) const = 0;
-
- virtual void body_add_central_force(RID p_body, const Vector3 &p_force) = 0;
- virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) = 0;
- virtual void body_add_torque(RID p_body, const Vector3 &p_torque) = 0;
-
- virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) = 0;
- virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) = 0;
- virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) = 0;
- virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) = 0;
-
- enum BodyAxis {
- BODY_AXIS_LINEAR_X = 1 << 0,
- BODY_AXIS_LINEAR_Y = 1 << 1,
- BODY_AXIS_LINEAR_Z = 1 << 2,
- BODY_AXIS_ANGULAR_X = 1 << 3,
- BODY_AXIS_ANGULAR_Y = 1 << 4,
- BODY_AXIS_ANGULAR_Z = 1 << 5
- };
-
- virtual void body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) = 0;
- virtual bool body_is_axis_locked(RID p_body, BodyAxis p_axis) const = 0;
-
- //fix
- virtual void body_add_collision_exception(RID p_body, RID p_body_b) = 0;
- virtual void body_remove_collision_exception(RID p_body, RID p_body_b) = 0;
- virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0;
-
- virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0;
- virtual int body_get_max_contacts_reported(RID p_body) const = 0;
-
- //missing remove
- virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) = 0;
- virtual float body_get_contacts_reported_depth_threshold(RID p_body) const = 0;
-
- 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_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 PhysicsDirectBodyState *body_get_direct_state(RID p_body) = 0;
-
- struct MotionResult {
-
- Vector3 motion;
- Vector3 remainder;
-
- Vector3 collision_point;
- Vector3 collision_normal;
- Vector3 collider_velocity;
- int collision_local_shape;
- ObjectID collider_id;
- RID collider;
- int collider_shape;
- Variant collider_metadata;
- MotionResult() {
- collision_local_shape = 0;
- collider_id = ObjectID();
- collider_shape = 0;
- }
- };
-
- virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true) = 0;
-
- struct SeparationResult {
-
- float collision_depth;
- Vector3 collision_point;
- Vector3 collision_normal;
- Vector3 collider_velocity;
- int collision_local_shape;
- ObjectID collider_id;
- RID collider;
- int collider_shape;
- Variant collider_metadata;
- };
-
- 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, float p_margin = 0.001) = 0;
-
- /* SOFT BODY */
-
- virtual RID soft_body_create(bool p_init_sleeping = false) = 0;
-
- virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_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 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;
-
- virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
- virtual uint32_t soft_body_get_collision_mask(RID p_body) const = 0;
-
- virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) = 0;
- virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) = 0;
- virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0;
-
- virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0;
- 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 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 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 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 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 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 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 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;
-
- /* JOINT API */
-
- enum JointType {
-
- JOINT_PIN,
- JOINT_HINGE,
- JOINT_SLIDER,
- JOINT_CONE_TWIST,
- JOINT_6DOF
-
- };
-
- virtual JointType joint_get_type(RID p_joint) const = 0;
-
- virtual void joint_set_solver_priority(RID p_joint, int p_priority) = 0;
- virtual int joint_get_solver_priority(RID p_joint) const = 0;
-
- 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;
-
- enum PinJointParam {
- PIN_JOINT_BIAS,
- PIN_JOINT_DAMPING,
- PIN_JOINT_IMPULSE_CLAMP
- };
-
- virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) = 0;
- virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const = 0;
-
- virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) = 0;
- virtual Vector3 pin_joint_get_local_a(RID p_joint) const = 0;
-
- virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) = 0;
- virtual Vector3 pin_joint_get_local_b(RID p_joint) const = 0;
-
- enum HingeJointParam {
-
- HINGE_JOINT_BIAS,
- HINGE_JOINT_LIMIT_UPPER,
- HINGE_JOINT_LIMIT_LOWER,
- HINGE_JOINT_LIMIT_BIAS,
- HINGE_JOINT_LIMIT_SOFTNESS,
- HINGE_JOINT_LIMIT_RELAXATION,
- HINGE_JOINT_MOTOR_TARGET_VELOCITY,
- HINGE_JOINT_MOTOR_MAX_IMPULSE,
- HINGE_JOINT_MAX
- };
-
- enum HingeJointFlag {
- HINGE_JOINT_FLAG_USE_LIMIT,
- HINGE_JOINT_FLAG_ENABLE_MOTOR,
- 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 hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) = 0;
- virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const = 0;
-
- virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) = 0;
- virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const = 0;
-
- enum SliderJointParam {
- SLIDER_JOINT_LINEAR_LIMIT_UPPER,
- SLIDER_JOINT_LINEAR_LIMIT_LOWER,
- SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
- SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
- SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
- SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
- SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
- SLIDER_JOINT_LINEAR_MOTION_DAMPING,
- SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
- SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
- SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
-
- SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
- SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
- SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
- SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
- SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
- SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
- SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
- SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
- SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
- SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
- SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
- SLIDER_JOINT_MAX
-
- };
-
- 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 slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) = 0;
- virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0;
-
- enum ConeTwistJointParam {
- CONE_TWIST_JOINT_SWING_SPAN,
- CONE_TWIST_JOINT_TWIST_SPAN,
- CONE_TWIST_JOINT_BIAS,
- CONE_TWIST_JOINT_SOFTNESS,
- CONE_TWIST_JOINT_RELAXATION,
- 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 cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) = 0;
- virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0;
-
- enum G6DOFJointAxisParam {
- G6DOF_JOINT_LINEAR_LOWER_LIMIT,
- G6DOF_JOINT_LINEAR_UPPER_LIMIT,
- G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
- G6DOF_JOINT_LINEAR_RESTITUTION,
- G6DOF_JOINT_LINEAR_DAMPING,
- G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
- G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
- G6DOF_JOINT_LINEAR_SPRING_STIFFNESS,
- G6DOF_JOINT_LINEAR_SPRING_DAMPING,
- G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT,
- G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
- G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
- G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
- G6DOF_JOINT_ANGULAR_DAMPING,
- G6DOF_JOINT_ANGULAR_RESTITUTION,
- G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
- G6DOF_JOINT_ANGULAR_ERP,
- G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
- G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
- G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS,
- G6DOF_JOINT_ANGULAR_SPRING_DAMPING,
- G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT,
- G6DOF_JOINT_MAX
- };
-
- enum G6DOFJointAxisFlag {
-
- G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
- G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
- G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING,
- G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING,
- G6DOF_JOINT_FLAG_ENABLE_MOTOR,
- G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
- 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 generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, float p_value) = 0;
- virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) = 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 void generic_6dof_joint_set_precision(RID p_joint, int precision) = 0;
- virtual int generic_6dof_joint_get_precision(RID p_joint) = 0;
-
- /* QUERY API */
-
- enum AreaBodyStatus {
- AREA_BODY_ADDED,
- AREA_BODY_REMOVED
- };
-
- /* MISC */
-
- virtual void free(RID p_rid) = 0;
-
- virtual void set_active(bool p_active) = 0;
- virtual void init() = 0;
- virtual void step(float p_step) = 0;
- virtual void sync() = 0;
- virtual void flush_queries() = 0;
- virtual void finish() = 0;
-
- virtual bool is_flushing_queries() const = 0;
-
- enum ProcessInfo {
-
- INFO_ACTIVE_OBJECTS,
- INFO_COLLISION_PAIRS,
- INFO_ISLAND_COUNT
- };
-
- virtual int get_process_info(ProcessInfo p_info) = 0;
-
- PhysicsServer();
- ~PhysicsServer();
-};
-
-typedef PhysicsServer *(*CreatePhysicsServerCallback)();
-
-class PhysicsServerManager {
- struct ClassInfo {
- String name;
- CreatePhysicsServerCallback create_callback;
-
- ClassInfo() :
- name(""),
- create_callback(NULL) {}
-
- ClassInfo(String p_name, CreatePhysicsServerCallback p_create_callback) :
- name(p_name),
- create_callback(p_create_callback) {}
-
- ClassInfo(const ClassInfo &p_ci) :
- name(p_ci.name),
- create_callback(p_ci.create_callback) {}
-
- ClassInfo operator=(const ClassInfo &p_ci) {
- name = p_ci.name;
- create_callback = p_ci.create_callback;
- return *this;
- }
- };
-
- static Vector<ClassInfo> physics_servers;
- static int default_server_id;
- static int default_server_priority;
-
-public:
- static const String setting_property_name;
-
-private:
- static void on_servers_changed();
-
-public:
- static void register_server(const String &p_name, CreatePhysicsServerCallback p_creat_callback);
- static void set_default_server(const String &p_name, int p_priority = 0);
- static int find_server_id(const String &p_name);
- static int get_servers_count();
- static String get_server_name(int p_id);
- static PhysicsServer *new_default_server();
- static PhysicsServer *new_server(const String &p_name);
-};
-
-VARIANT_ENUM_CAST(PhysicsServer::ShapeType);
-VARIANT_ENUM_CAST(PhysicsServer::SpaceParameter);
-VARIANT_ENUM_CAST(PhysicsServer::AreaParameter);
-VARIANT_ENUM_CAST(PhysicsServer::AreaSpaceOverrideMode);
-VARIANT_ENUM_CAST(PhysicsServer::BodyMode);
-VARIANT_ENUM_CAST(PhysicsServer::BodyParameter);
-VARIANT_ENUM_CAST(PhysicsServer::BodyState);
-VARIANT_ENUM_CAST(PhysicsServer::BodyAxis);
-VARIANT_ENUM_CAST(PhysicsServer::PinJointParam);
-VARIANT_ENUM_CAST(PhysicsServer::JointType);
-VARIANT_ENUM_CAST(PhysicsServer::HingeJointParam);
-VARIANT_ENUM_CAST(PhysicsServer::HingeJointFlag);
-VARIANT_ENUM_CAST(PhysicsServer::SliderJointParam);
-VARIANT_ENUM_CAST(PhysicsServer::ConeTwistJointParam);
-VARIANT_ENUM_CAST(PhysicsServer::G6DOFJointAxisParam);
-VARIANT_ENUM_CAST(PhysicsServer::G6DOFJointAxisFlag);
-VARIANT_ENUM_CAST(PhysicsServer::AreaBodyStatus);
-VARIANT_ENUM_CAST(PhysicsServer::ProcessInfo);
-
-#endif
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
new file mode 100644
index 0000000000..48c51b5350
--- /dev/null
+++ b/servers/physics_server_2d.cpp
@@ -0,0 +1,840 @@
+/*************************************************************************/
+/* physics_server_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_2d.h"
+
+#include "core/method_bind_ext.gen.inc"
+#include "core/print_string.h"
+#include "core/project_settings.h"
+
+PhysicsServer2D *PhysicsServer2D::singleton = nullptr;
+
+void PhysicsDirectBodyState2D::integrate_forces() {
+
+ real_t step = get_step();
+ Vector2 lv = get_linear_velocity();
+ lv += get_total_gravity() * step;
+
+ real_t av = get_angular_velocity();
+
+ float damp = 1.0 - step * get_total_linear_damp();
+
+ if (damp < 0) // reached zero in the given time
+ damp = 0;
+
+ lv *= damp;
+
+ damp = 1.0 - step * get_total_angular_damp();
+
+ if (damp < 0) // reached zero in the given time
+ damp = 0;
+
+ av *= damp;
+
+ set_linear_velocity(lv);
+ set_angular_velocity(av);
+}
+
+Object *PhysicsDirectBodyState2D::get_contact_collider_object(int p_contact_idx) const {
+
+ ObjectID objid = get_contact_collider_id(p_contact_idx);
+ Object *obj = ObjectDB::get_instance(objid);
+ return obj;
+}
+
+PhysicsServer2D *PhysicsServer2D::get_singleton() {
+
+ return singleton;
+}
+
+void PhysicsDirectBodyState2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_total_gravity"), &PhysicsDirectBodyState2D::get_total_gravity);
+ ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &PhysicsDirectBodyState2D::get_total_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState2D::get_total_angular_damp);
+
+ ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState2D::get_inverse_mass);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState2D::get_inverse_inertia);
+
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &PhysicsDirectBodyState2D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicsDirectBodyState2D::get_linear_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &PhysicsDirectBodyState2D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicsDirectBodyState2D::get_angular_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState2D::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState2D::get_transform);
+
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState2D::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "offset", "force"), &PhysicsDirectBodyState2D::add_force);
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState2D::add_torque);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicsDirectBodyState2D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &PhysicsDirectBodyState2D::apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "offset", "impulse"), &PhysicsDirectBodyState2D::apply_impulse);
+
+ ClassDB::bind_method(D_METHOD("set_sleep_state", "enabled"), &PhysicsDirectBodyState2D::set_sleep_state);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &PhysicsDirectBodyState2D::is_sleeping);
+
+ ClassDB::bind_method(D_METHOD("get_contact_count"), &PhysicsDirectBodyState2D::get_contact_count);
+
+ ClassDB::bind_method(D_METHOD("get_contact_local_position", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_local_position);
+ ClassDB::bind_method(D_METHOD("get_contact_local_normal", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_local_normal);
+ ClassDB::bind_method(D_METHOD("get_contact_local_shape", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_local_shape);
+ ClassDB::bind_method(D_METHOD("get_contact_collider", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_position", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_position);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_id", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_id);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_object", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_object);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_shape", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_shape_metadata", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_shape_metadata);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_velocity_at_position", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_velocity_at_position);
+ ClassDB::bind_method(D_METHOD("get_step"), &PhysicsDirectBodyState2D::get_step);
+ ClassDB::bind_method(D_METHOD("integrate_forces"), &PhysicsDirectBodyState2D::integrate_forces);
+ ClassDB::bind_method(D_METHOD("get_space_state"), &PhysicsDirectBodyState2D::get_space_state);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inverse_mass"), "", "get_inverse_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inverse_inertia"), "", "get_inverse_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "total_gravity"), "", "get_total_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
+}
+
+PhysicsDirectBodyState2D::PhysicsDirectBodyState2D() {}
+
+///////////////////////////////////////////////////////
+
+void PhysicsShapeQueryParameters2D::set_shape(const RES &p_shape) {
+
+ ERR_FAIL_COND(p_shape.is_null());
+ shape = p_shape->get_rid();
+}
+
+void PhysicsShapeQueryParameters2D::set_shape_rid(const RID &p_shape) {
+
+ shape = p_shape;
+}
+
+RID PhysicsShapeQueryParameters2D::get_shape_rid() const {
+
+ return shape;
+}
+
+void PhysicsShapeQueryParameters2D::set_transform(const Transform2D &p_transform) {
+
+ transform = p_transform;
+}
+Transform2D PhysicsShapeQueryParameters2D::get_transform() const {
+
+ return transform;
+}
+
+void PhysicsShapeQueryParameters2D::set_motion(const Vector2 &p_motion) {
+
+ motion = p_motion;
+}
+Vector2 PhysicsShapeQueryParameters2D::get_motion() const {
+
+ return motion;
+}
+
+void PhysicsShapeQueryParameters2D::set_margin(float p_margin) {
+
+ margin = p_margin;
+}
+float PhysicsShapeQueryParameters2D::get_margin() const {
+
+ return margin;
+}
+
+void PhysicsShapeQueryParameters2D::set_collision_mask(int p_collision_mask) {
+
+ collision_mask = p_collision_mask;
+}
+int PhysicsShapeQueryParameters2D::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void PhysicsShapeQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) {
+
+ exclude.clear();
+ for (int i = 0; i < p_exclude.size(); i++)
+ exclude.insert(p_exclude[i]);
+}
+
+Vector<RID> PhysicsShapeQueryParameters2D::get_exclude() const {
+
+ Vector<RID> ret;
+ ret.resize(exclude.size());
+ int idx = 0;
+ for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) {
+ ret.write[idx] = E->get();
+ }
+ return ret;
+}
+
+void PhysicsShapeQueryParameters2D::set_collide_with_bodies(bool p_enable) {
+ collide_with_bodies = p_enable;
+}
+
+bool PhysicsShapeQueryParameters2D::is_collide_with_bodies_enabled() const {
+ return collide_with_bodies;
+}
+
+void PhysicsShapeQueryParameters2D::set_collide_with_areas(bool p_enable) {
+ collide_with_areas = p_enable;
+}
+
+bool PhysicsShapeQueryParameters2D::is_collide_with_areas_enabled() const {
+ return collide_with_areas;
+}
+
+void PhysicsShapeQueryParameters2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &PhysicsShapeQueryParameters2D::set_shape);
+ ClassDB::bind_method(D_METHOD("set_shape_rid", "shape"), &PhysicsShapeQueryParameters2D::set_shape_rid);
+ ClassDB::bind_method(D_METHOD("get_shape_rid"), &PhysicsShapeQueryParameters2D::get_shape_rid);
+
+ ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsShapeQueryParameters2D::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsShapeQueryParameters2D::get_transform);
+
+ ClassDB::bind_method(D_METHOD("set_motion", "motion"), &PhysicsShapeQueryParameters2D::set_motion);
+ ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsShapeQueryParameters2D::get_motion);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsShapeQueryParameters2D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsShapeQueryParameters2D::get_margin);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &PhysicsShapeQueryParameters2D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsShapeQueryParameters2D::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsShapeQueryParameters2D::set_exclude);
+ ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsShapeQueryParameters2D::get_exclude);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsShapeQueryParameters2D::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsShapeQueryParameters2D::is_collide_with_bodies_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsShapeQueryParameters2D::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters2D::is_collide_with_areas_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::_RID) + ":"), "set_exclude", "get_exclude");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion");
+ //ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", ""); // FIXME: Lacks a getter
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "shape_rid"), "set_shape_rid", "get_shape_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
+}
+
+PhysicsShapeQueryParameters2D::PhysicsShapeQueryParameters2D() {
+
+ margin = 0;
+ collision_mask = 0x7FFFFFFF;
+ collide_with_bodies = true;
+ collide_with_areas = false;
+}
+
+Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ RayResult inters;
+ Set<RID> exclude;
+ for (int i = 0; i < p_exclude.size(); i++)
+ exclude.insert(p_exclude[i]);
+
+ bool res = intersect_ray(p_from, p_to, inters, exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+
+ if (!res)
+ return Dictionary();
+
+ Dictionary d;
+ d["position"] = inters.position;
+ d["normal"] = inters.normal;
+ d["collider_id"] = inters.collider_id;
+ d["collider"] = inters.collider;
+ d["shape"] = inters.shape;
+ d["rid"] = inters.rid;
+ d["metadata"] = inters.metadata;
+
+ return d;
+}
+
+Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+
+ Vector<ShapeResult> sr;
+ sr.resize(p_max_results);
+ int rc = intersect_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, sr.ptrw(), sr.size(), p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ Array ret;
+ ret.resize(rc);
+ for (int i = 0; i < rc; i++) {
+
+ Dictionary d;
+ d["rid"] = sr[i].rid;
+ d["collider_id"] = sr[i].collider_id;
+ d["collider"] = sr[i].collider;
+ d["shape"] = sr[i].shape;
+ d["metadata"] = sr[i].metadata;
+ ret[i] = d;
+ }
+
+ return ret;
+}
+
+Array PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+
+ float closest_safe, closest_unsafe;
+ bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ if (!res)
+ return Array();
+ Array ret;
+ ret.resize(2);
+ ret[0] = closest_safe;
+ ret[1] = closest_unsafe;
+ return ret;
+}
+
+Array PhysicsDirectSpaceState2D::_intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) {
+
+ Set<RID> exclude;
+ for (int i = 0; i < p_exclude.size(); i++)
+ exclude.insert(p_exclude[i]);
+
+ Vector<ShapeResult> ret;
+ ret.resize(p_max_results);
+
+ int rc;
+ if (p_filter_by_canvas)
+ rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+ else
+ rc = intersect_point_on_canvas(p_point, p_canvas_instance_id, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+
+ if (rc == 0)
+ return Array();
+
+ Array r;
+ r.resize(rc);
+ for (int i = 0; i < rc; i++) {
+
+ Dictionary d;
+ d["rid"] = ret[i].rid;
+ d["collider_id"] = ret[i].collider_id;
+ d["collider"] = ret[i].collider;
+ d["shape"] = ret[i].shape;
+ d["metadata"] = ret[i].metadata;
+ r[i] = d;
+ }
+ return r;
+}
+
+Array PhysicsDirectSpaceState2D::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas);
+}
+
+Array PhysicsDirectSpaceState2D::_intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas, true, p_canvas_intance_id);
+}
+
+Array PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+
+ Vector<Vector2> ret;
+ ret.resize(p_max_results * 2);
+ int rc = 0;
+ bool res = collide_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, ret.ptrw(), p_max_results, rc, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ if (!res)
+ return Array();
+ Array r;
+ r.resize(rc * 2);
+ for (int i = 0; i < rc * 2; i++)
+ r[i] = ret[i];
+ return r;
+}
+Dictionary PhysicsDirectSpaceState2D::_get_rest_info(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Dictionary());
+
+ ShapeRestInfo sri;
+
+ bool res = rest_info(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, &sri, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ Dictionary r;
+ if (!res)
+ return r;
+
+ r["point"] = sri.point;
+ r["normal"] = sri.normal;
+ r["rid"] = sri.rid;
+ r["collider_id"] = sri.collider_id;
+ r["shape"] = sri.shape;
+ r["linear_velocity"] = sri.linear_velocity;
+ r["metadata"] = sri.metadata;
+
+ return r;
+}
+
+PhysicsDirectSpaceState2D::PhysicsDirectSpaceState2D() {
+}
+
+void PhysicsDirectSpaceState2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_intersect_shape, DEFVAL(32));
+ ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &PhysicsDirectSpaceState2D::_cast_motion);
+ ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_collide_shape, DEFVAL(32));
+ ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState2D::_get_rest_info);
+}
+
+int PhysicsShapeQueryResult2D::get_result_count() const {
+
+ return result.size();
+}
+RID PhysicsShapeQueryResult2D::get_result_rid(int p_idx) const {
+
+ return result[p_idx].rid;
+}
+ObjectID PhysicsShapeQueryResult2D::get_result_object_id(int p_idx) const {
+
+ return result[p_idx].collider_id;
+}
+Object *PhysicsShapeQueryResult2D::get_result_object(int p_idx) const {
+
+ return result[p_idx].collider;
+}
+int PhysicsShapeQueryResult2D::get_result_object_shape(int p_idx) const {
+
+ return result[p_idx].shape;
+}
+
+PhysicsShapeQueryResult2D::PhysicsShapeQueryResult2D() {
+}
+
+void PhysicsShapeQueryResult2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_result_count"), &PhysicsShapeQueryResult2D::get_result_count);
+ ClassDB::bind_method(D_METHOD("get_result_rid", "idx"), &PhysicsShapeQueryResult2D::get_result_rid);
+ ClassDB::bind_method(D_METHOD("get_result_object_id", "idx"), &PhysicsShapeQueryResult2D::get_result_object_id);
+ ClassDB::bind_method(D_METHOD("get_result_object", "idx"), &PhysicsShapeQueryResult2D::get_result_object);
+ ClassDB::bind_method(D_METHOD("get_result_object_shape", "idx"), &PhysicsShapeQueryResult2D::get_result_object_shape);
+}
+
+///////////////////////////////
+
+Vector2 PhysicsTestMotionResult2D::get_motion() const {
+
+ return result.motion;
+}
+Vector2 PhysicsTestMotionResult2D::get_motion_remainder() const {
+
+ return result.remainder;
+}
+
+Vector2 PhysicsTestMotionResult2D::get_collision_point() const {
+
+ return result.collision_point;
+}
+Vector2 PhysicsTestMotionResult2D::get_collision_normal() const {
+
+ return result.collision_normal;
+}
+Vector2 PhysicsTestMotionResult2D::get_collider_velocity() const {
+
+ return result.collider_velocity;
+}
+ObjectID PhysicsTestMotionResult2D::get_collider_id() const {
+
+ return result.collider_id;
+}
+RID PhysicsTestMotionResult2D::get_collider_rid() const {
+
+ return result.collider;
+}
+
+Object *PhysicsTestMotionResult2D::get_collider() const {
+ return ObjectDB::get_instance(result.collider_id);
+}
+
+int PhysicsTestMotionResult2D::get_collider_shape() const {
+
+ return result.collider_shape;
+}
+
+void PhysicsTestMotionResult2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult2D::get_motion);
+ ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult2D::get_motion_remainder);
+ ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult2D::get_collision_point);
+ ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult2D::get_collision_normal);
+ ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult2D::get_collider_velocity);
+ ClassDB::bind_method(D_METHOD("get_collider_id"), &PhysicsTestMotionResult2D::get_collider_id);
+ ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult2D::get_collider_rid);
+ ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult2D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult2D::get_collider_shape);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "", "get_motion");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_remainder"), "", "get_motion_remainder");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_point"), "", "get_collision_point");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id");
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "collider_rid"), "", "get_collider_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape");
+}
+
+PhysicsTestMotionResult2D::PhysicsTestMotionResult2D() {
+
+ colliding = false;
+
+ result.collider_shape = 0;
+}
+
+///////////////////////////////////////
+
+bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) {
+
+ MotionResult *r = nullptr;
+ if (p_result.is_valid())
+ r = p_result->get_result_ptr();
+ return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r);
+}
+
+void PhysicsServer2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("line_shape_create"), &PhysicsServer2D::line_shape_create);
+ ClassDB::bind_method(D_METHOD("ray_shape_create"), &PhysicsServer2D::ray_shape_create);
+ ClassDB::bind_method(D_METHOD("segment_shape_create"), &PhysicsServer2D::segment_shape_create);
+ ClassDB::bind_method(D_METHOD("circle_shape_create"), &PhysicsServer2D::circle_shape_create);
+ ClassDB::bind_method(D_METHOD("rectangle_shape_create"), &PhysicsServer2D::rectangle_shape_create);
+ ClassDB::bind_method(D_METHOD("capsule_shape_create"), &PhysicsServer2D::capsule_shape_create);
+ ClassDB::bind_method(D_METHOD("convex_polygon_shape_create"), &PhysicsServer2D::convex_polygon_shape_create);
+ ClassDB::bind_method(D_METHOD("concave_polygon_shape_create"), &PhysicsServer2D::concave_polygon_shape_create);
+
+ ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &PhysicsServer2D::shape_set_data);
+
+ ClassDB::bind_method(D_METHOD("shape_get_type", "shape"), &PhysicsServer2D::shape_get_type);
+ ClassDB::bind_method(D_METHOD("shape_get_data", "shape"), &PhysicsServer2D::shape_get_data);
+
+ ClassDB::bind_method(D_METHOD("space_create"), &PhysicsServer2D::space_create);
+ ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &PhysicsServer2D::space_set_active);
+ ClassDB::bind_method(D_METHOD("space_is_active", "space"), &PhysicsServer2D::space_is_active);
+ ClassDB::bind_method(D_METHOD("space_set_param", "space", "param", "value"), &PhysicsServer2D::space_set_param);
+ ClassDB::bind_method(D_METHOD("space_get_param", "space", "param"), &PhysicsServer2D::space_get_param);
+ ClassDB::bind_method(D_METHOD("space_get_direct_state", "space"), &PhysicsServer2D::space_get_direct_state);
+
+ ClassDB::bind_method(D_METHOD("area_create"), &PhysicsServer2D::area_create);
+ ClassDB::bind_method(D_METHOD("area_set_space", "area", "space"), &PhysicsServer2D::area_set_space);
+ ClassDB::bind_method(D_METHOD("area_get_space", "area"), &PhysicsServer2D::area_get_space);
+
+ ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer2D::area_set_space_override_mode);
+ ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer2D::area_get_space_override_mode);
+
+ ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer2D::area_add_shape, DEFVAL(Transform2D()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer2D::area_set_shape);
+ ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer2D::area_set_shape_transform);
+ ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &PhysicsServer2D::area_set_shape_disabled);
+
+ ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &PhysicsServer2D::area_get_shape_count);
+ ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &PhysicsServer2D::area_get_shape);
+ ClassDB::bind_method(D_METHOD("area_get_shape_transform", "area", "shape_idx"), &PhysicsServer2D::area_get_shape_transform);
+
+ ClassDB::bind_method(D_METHOD("area_remove_shape", "area", "shape_idx"), &PhysicsServer2D::area_remove_shape);
+ ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer2D::area_clear_shapes);
+
+ ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer2D::area_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer2D::area_set_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer2D::area_set_param);
+ ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer2D::area_set_transform);
+
+ ClassDB::bind_method(D_METHOD("area_get_param", "area", "param"), &PhysicsServer2D::area_get_param);
+ ClassDB::bind_method(D_METHOD("area_get_transform", "area"), &PhysicsServer2D::area_get_transform);
+
+ ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &PhysicsServer2D::area_attach_object_instance_id);
+ ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &PhysicsServer2D::area_get_object_instance_id);
+
+ ClassDB::bind_method(D_METHOD("area_attach_canvas_instance_id", "area", "id"), &PhysicsServer2D::area_attach_canvas_instance_id);
+ ClassDB::bind_method(D_METHOD("area_get_canvas_instance_id", "area"), &PhysicsServer2D::area_get_canvas_instance_id);
+
+ ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &PhysicsServer2D::area_set_monitor_callback);
+ ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &PhysicsServer2D::area_set_area_monitor_callback);
+ ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &PhysicsServer2D::area_set_monitorable);
+
+ ClassDB::bind_method(D_METHOD("body_create"), &PhysicsServer2D::body_create);
+
+ ClassDB::bind_method(D_METHOD("body_set_space", "body", "space"), &PhysicsServer2D::body_set_space);
+ ClassDB::bind_method(D_METHOD("body_get_space", "body"), &PhysicsServer2D::body_get_space);
+
+ ClassDB::bind_method(D_METHOD("body_set_mode", "body", "mode"), &PhysicsServer2D::body_set_mode);
+ ClassDB::bind_method(D_METHOD("body_get_mode", "body"), &PhysicsServer2D::body_get_mode);
+
+ ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer2D::body_add_shape, DEFVAL(Transform2D()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer2D::body_set_shape);
+ ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer2D::body_set_shape_transform);
+ ClassDB::bind_method(D_METHOD("body_set_shape_metadata", "body", "shape_idx", "metadata"), &PhysicsServer2D::body_set_shape_metadata);
+
+ ClassDB::bind_method(D_METHOD("body_get_shape_count", "body"), &PhysicsServer2D::body_get_shape_count);
+ ClassDB::bind_method(D_METHOD("body_get_shape", "body", "shape_idx"), &PhysicsServer2D::body_get_shape);
+ ClassDB::bind_method(D_METHOD("body_get_shape_transform", "body", "shape_idx"), &PhysicsServer2D::body_get_shape_transform);
+ ClassDB::bind_method(D_METHOD("body_get_shape_metadata", "body", "shape_idx"), &PhysicsServer2D::body_get_shape_metadata);
+
+ ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &PhysicsServer2D::body_remove_shape);
+ ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &PhysicsServer2D::body_clear_shapes);
+
+ ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &PhysicsServer2D::body_set_shape_disabled);
+ ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable", "margin"), &PhysicsServer2D::body_set_shape_as_one_way_collision);
+
+ ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &PhysicsServer2D::body_attach_object_instance_id);
+ ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &PhysicsServer2D::body_get_object_instance_id);
+
+ ClassDB::bind_method(D_METHOD("body_attach_canvas_instance_id", "body", "id"), &PhysicsServer2D::body_attach_canvas_instance_id);
+ ClassDB::bind_method(D_METHOD("body_get_canvas_instance_id", "body"), &PhysicsServer2D::body_get_canvas_instance_id);
+
+ ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &PhysicsServer2D::body_set_continuous_collision_detection_mode);
+ ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &PhysicsServer2D::body_get_continuous_collision_detection_mode);
+
+ ClassDB::bind_method(D_METHOD("body_set_collision_layer", "body", "layer"), &PhysicsServer2D::body_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("body_get_collision_layer", "body"), &PhysicsServer2D::body_get_collision_layer);
+
+ ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer2D::body_set_collision_mask);
+ ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer2D::body_get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param);
+ ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param);
+
+ ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer2D::body_set_state);
+ ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer2D::body_get_state);
+
+ ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &PhysicsServer2D::body_apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &PhysicsServer2D::body_apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &PhysicsServer2D::body_apply_impulse);
+ ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &PhysicsServer2D::body_add_central_force);
+ ClassDB::bind_method(D_METHOD("body_add_force", "body", "offset", "force"), &PhysicsServer2D::body_add_force);
+ ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &PhysicsServer2D::body_add_torque);
+ ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &PhysicsServer2D::body_set_axis_velocity);
+
+ ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &PhysicsServer2D::body_add_collision_exception);
+ ClassDB::bind_method(D_METHOD("body_remove_collision_exception", "body", "excepted_body"), &PhysicsServer2D::body_remove_collision_exception);
+
+ ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &PhysicsServer2D::body_set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &PhysicsServer2D::body_get_max_contacts_reported);
+
+ 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_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()));
+
+ ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer2D::body_get_direct_state);
+
+ /* JOINT API */
+
+ 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("damped_string_joint_set_param", "joint", "param", "value"), &PhysicsServer2D::damped_string_joint_set_param);
+ ClassDB::bind_method(D_METHOD("damped_string_joint_get_param", "joint", "param"), &PhysicsServer2D::damped_string_joint_get_param);
+
+ ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer2D::joint_get_type);
+
+ ClassDB::bind_method(D_METHOD("free_rid", "rid"), &PhysicsServer2D::free);
+
+ ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer2D::set_active);
+
+ ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer2D::get_process_info);
+
+ BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_RECYCLE_RADIUS);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_MAX_SEPARATION);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);
+
+ BIND_ENUM_CONSTANT(SHAPE_LINE);
+ BIND_ENUM_CONSTANT(SHAPE_RAY);
+ BIND_ENUM_CONSTANT(SHAPE_SEGMENT);
+ BIND_ENUM_CONSTANT(SHAPE_CIRCLE);
+ BIND_ENUM_CONSTANT(SHAPE_RECTANGLE);
+ BIND_ENUM_CONSTANT(SHAPE_CAPSULE);
+ BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
+ BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
+ BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
+
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_DISTANCE_SCALE);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_ATTENUATION);
+ BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP);
+ BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP);
+ BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY);
+
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_DISABLED);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE_REPLACE);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE_COMBINE);
+
+ BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
+ BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
+ BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
+ BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER);
+
+ BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
+ BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
+ BIND_ENUM_CONSTANT(BODY_PARAM_MASS);
+ BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA);
+ BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE);
+ BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP);
+ BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP);
+ BIND_ENUM_CONSTANT(BODY_PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(BODY_STATE_TRANSFORM);
+ BIND_ENUM_CONSTANT(BODY_STATE_LINEAR_VELOCITY);
+ BIND_ENUM_CONSTANT(BODY_STATE_ANGULAR_VELOCITY);
+ 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_PARAM_BIAS);
+ BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_BIAS);
+ BIND_ENUM_CONSTANT(JOINT_PARAM_MAX_FORCE);
+
+ BIND_ENUM_CONSTANT(DAMPED_STRING_REST_LENGTH);
+ BIND_ENUM_CONSTANT(DAMPED_STRING_STIFFNESS);
+ BIND_ENUM_CONSTANT(DAMPED_STRING_DAMPING);
+
+ BIND_ENUM_CONSTANT(CCD_MODE_DISABLED);
+ BIND_ENUM_CONSTANT(CCD_MODE_CAST_RAY);
+ BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
+
+ BIND_ENUM_CONSTANT(AREA_BODY_ADDED);
+ BIND_ENUM_CONSTANT(AREA_BODY_REMOVED);
+
+ BIND_ENUM_CONSTANT(INFO_ACTIVE_OBJECTS);
+ BIND_ENUM_CONSTANT(INFO_COLLISION_PAIRS);
+ BIND_ENUM_CONSTANT(INFO_ISLAND_COUNT);
+}
+
+PhysicsServer2D::PhysicsServer2D() {
+
+ singleton = this;
+}
+
+PhysicsServer2D::~PhysicsServer2D() {
+
+ singleton = nullptr;
+}
+
+Vector<PhysicsServer2DManager::ClassInfo> PhysicsServer2DManager::physics_2d_servers;
+int PhysicsServer2DManager::default_server_id = -1;
+int PhysicsServer2DManager::default_server_priority = -1;
+const String PhysicsServer2DManager::setting_property_name("physics/2d/physics_engine");
+
+void PhysicsServer2DManager::on_servers_changed() {
+
+ String physics_servers("DEFAULT");
+ for (int i = get_servers_count() - 1; 0 <= i; --i) {
+ physics_servers += "," + get_server_name(i);
+ }
+ ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers));
+}
+
+void PhysicsServer2DManager::register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback) {
+
+ ERR_FAIL_COND(!p_creat_callback);
+ ERR_FAIL_COND(find_server_id(p_name) != -1);
+ physics_2d_servers.push_back(ClassInfo(p_name, p_creat_callback));
+ on_servers_changed();
+}
+
+void PhysicsServer2DManager::set_default_server(const String &p_name, int p_priority) {
+
+ const int id = find_server_id(p_name);
+ ERR_FAIL_COND(id == -1); // Not found
+ if (default_server_priority < p_priority) {
+ default_server_id = id;
+ default_server_priority = p_priority;
+ }
+}
+
+int PhysicsServer2DManager::find_server_id(const String &p_name) {
+
+ for (int i = physics_2d_servers.size() - 1; 0 <= i; --i) {
+ if (p_name == physics_2d_servers[i].name) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int PhysicsServer2DManager::get_servers_count() {
+ return physics_2d_servers.size();
+}
+
+String PhysicsServer2DManager::get_server_name(int p_id) {
+ ERR_FAIL_INDEX_V(p_id, get_servers_count(), "");
+ return physics_2d_servers[p_id].name;
+}
+
+PhysicsServer2D *PhysicsServer2DManager::new_default_server() {
+ ERR_FAIL_COND_V(default_server_id == -1, nullptr);
+ return physics_2d_servers[default_server_id].create_callback();
+}
+
+PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) {
+ int id = find_server_id(p_name);
+ if (id == -1) {
+ return nullptr;
+ } else {
+ return physics_2d_servers[id].create_callback();
+ }
+}
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
new file mode 100644
index 0000000000..8c833b390f
--- /dev/null
+++ b/servers/physics_server_2d.h
@@ -0,0 +1,699 @@
+/*************************************************************************/
+/* physics_server_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS_2D_SERVER_H
+#define PHYSICS_2D_SERVER_H
+
+#include "core/object.h"
+#include "core/reference.h"
+#include "core/resource.h"
+
+class PhysicsDirectSpaceState2D;
+
+class PhysicsDirectBodyState2D : public Object {
+
+ GDCLASS(PhysicsDirectBodyState2D, Object);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Vector2 get_total_gravity() const = 0; // get gravity vector working on this body space/area
+ virtual float get_total_linear_damp() const = 0; // get density of this body space/area
+ virtual float get_total_angular_damp() const = 0; // get density of this body space/area
+
+ virtual float get_inverse_mass() const = 0; // get the mass
+ virtual real_t get_inverse_inertia() const = 0; // get density of this body space
+
+ virtual void set_linear_velocity(const Vector2 &p_velocity) = 0;
+ virtual Vector2 get_linear_velocity() const = 0;
+
+ virtual void set_angular_velocity(real_t p_velocity) = 0;
+ virtual real_t get_angular_velocity() const = 0;
+
+ virtual void set_transform(const Transform2D &p_transform) = 0;
+ virtual Transform2D get_transform() const = 0;
+
+ virtual void add_central_force(const Vector2 &p_force) = 0;
+ virtual void add_force(const Vector2 &p_offset, const Vector2 &p_force) = 0;
+ virtual void add_torque(real_t p_torque) = 0;
+ virtual void apply_central_impulse(const Vector2 &p_impulse) = 0;
+ virtual void apply_torque_impulse(real_t p_torque) = 0;
+ virtual void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) = 0;
+
+ virtual void set_sleep_state(bool p_enable) = 0;
+ virtual bool is_sleeping() const = 0;
+
+ virtual int get_contact_count() const = 0;
+
+ virtual Vector2 get_contact_local_position(int p_contact_idx) const = 0;
+ virtual Vector2 get_contact_local_normal(int p_contact_idx) const = 0;
+ virtual int get_contact_local_shape(int p_contact_idx) const = 0;
+
+ virtual RID get_contact_collider(int p_contact_idx) const = 0;
+ virtual Vector2 get_contact_collider_position(int p_contact_idx) const = 0;
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const = 0;
+ virtual Object *get_contact_collider_object(int p_contact_idx) const;
+ virtual int get_contact_collider_shape(int p_contact_idx) const = 0;
+ virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const = 0;
+ virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const = 0;
+
+ virtual real_t get_step() const = 0;
+ virtual void integrate_forces();
+
+ virtual PhysicsDirectSpaceState2D *get_space_state() = 0;
+
+ PhysicsDirectBodyState2D();
+};
+
+class PhysicsShapeQueryResult2D;
+
+//used for script
+class PhysicsShapeQueryParameters2D : public Reference {
+
+ GDCLASS(PhysicsShapeQueryParameters2D, Reference);
+ friend class PhysicsDirectSpaceState2D;
+ RID shape;
+ Transform2D transform;
+ Vector2 motion;
+ float margin;
+ Set<RID> exclude;
+ uint32_t collision_mask;
+
+ bool collide_with_bodies;
+ bool collide_with_areas;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_shape(const RES &p_shape);
+ void set_shape_rid(const RID &p_shape);
+ RID get_shape_rid() const;
+
+ void set_transform(const Transform2D &p_transform);
+ Transform2D get_transform() const;
+
+ void set_motion(const Vector2 &p_motion);
+ Vector2 get_motion() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_collision_mask(int p_collision_mask);
+ int get_collision_mask() const;
+
+ void set_collide_with_bodies(bool p_enable);
+ bool is_collide_with_bodies_enabled() const;
+
+ void set_collide_with_areas(bool p_enable);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_exclude(const Vector<RID> &p_exclude);
+ Vector<RID> get_exclude() const;
+
+ PhysicsShapeQueryParameters2D();
+};
+
+class PhysicsDirectSpaceState2D : public Object {
+
+ GDCLASS(PhysicsDirectSpaceState2D, Object);
+
+ Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Array _intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = ObjectID());
+ Array _intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32);
+ Array _cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query);
+ Array _collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32);
+ Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query);
+
+protected:
+ static void _bind_methods();
+
+public:
+ struct RayResult {
+
+ Vector2 position;
+ Vector2 normal;
+ RID rid;
+ ObjectID collider_id;
+ Object *collider;
+ int shape;
+ Variant metadata;
+ };
+
+ virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ struct ShapeResult {
+
+ RID rid;
+ ObjectID collider_id;
+ Object *collider;
+ int shape;
+ Variant metadata;
+ };
+
+ virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
+ virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0;
+
+ virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ struct ShapeRestInfo {
+
+ Vector2 point;
+ Vector2 normal;
+ RID rid;
+ ObjectID collider_id;
+ int shape;
+ Vector2 linear_velocity; //velocity at contact point
+ Variant metadata;
+ };
+
+ virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ PhysicsDirectSpaceState2D();
+};
+
+class PhysicsShapeQueryResult2D : public Reference {
+
+ GDCLASS(PhysicsShapeQueryResult2D, Reference);
+
+ Vector<PhysicsDirectSpaceState2D::ShapeResult> result;
+
+ friend class PhysicsDirectSpaceState2D;
+
+protected:
+ static void _bind_methods();
+
+public:
+ int get_result_count() const;
+ RID get_result_rid(int p_idx) const;
+ ObjectID get_result_object_id(int p_idx) const;
+ Object *get_result_object(int p_idx) const;
+ int get_result_object_shape(int p_idx) const;
+
+ PhysicsShapeQueryResult2D();
+};
+
+class PhysicsTestMotionResult2D;
+
+class PhysicsServer2D : public Object {
+
+ GDCLASS(PhysicsServer2D, Object);
+
+ static PhysicsServer2D *singleton;
+
+ virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>());
+
+protected:
+ static void _bind_methods();
+
+public:
+ static PhysicsServer2D *get_singleton();
+
+ enum ShapeType {
+ SHAPE_LINE, ///< plane:"plane"
+ SHAPE_RAY, ///< float:"length"
+ SHAPE_SEGMENT, ///< float:"length"
+ SHAPE_CIRCLE, ///< float:"radius"
+ SHAPE_RECTANGLE, ///< vec3:"extents"
+ SHAPE_CAPSULE,
+ SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
+ SHAPE_CONCAVE_POLYGON, ///< Vector2 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector2 array)
+ SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error
+ };
+
+ virtual RID line_shape_create() = 0;
+ virtual RID ray_shape_create() = 0;
+ virtual RID segment_shape_create() = 0;
+ virtual RID circle_shape_create() = 0;
+ virtual RID rectangle_shape_create() = 0;
+ virtual RID capsule_shape_create() = 0;
+ virtual RID convex_polygon_shape_create() = 0;
+ virtual RID concave_polygon_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;
+
+ virtual ShapeType shape_get_type(RID p_shape) const = 0;
+ virtual Variant shape_get_data(RID p_shape) const = 0;
+ virtual real_t shape_get_custom_solver_bias(RID p_shape) const = 0;
+
+ //these work well, but should be used from the main thread only
+ virtual 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) = 0;
+
+ /* SPACE API */
+
+ virtual RID space_create() = 0;
+ virtual void space_set_active(RID p_space, bool p_active) = 0;
+ virtual bool space_is_active(RID p_space) const = 0;
+
+ enum SpaceParameter {
+
+ SPACE_PARAM_CONTACT_RECYCLE_RADIUS,
+ SPACE_PARAM_CONTACT_MAX_SEPARATION,
+ SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,
+ SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD,
+ SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD,
+ SPACE_PARAM_BODY_TIME_TO_SLEEP,
+ SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
+ SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH,
+ };
+
+ virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0;
+ virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const = 0;
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) = 0;
+
+ virtual void space_set_debug_contacts(RID p_space, int p_max_contacts) = 0;
+ virtual Vector<Vector2> space_get_contacts(RID p_space) const = 0;
+ virtual int space_get_contact_count(RID p_space) const = 0;
+
+ //missing space parameters
+
+ /* AREA API */
+
+ //missing attenuation? missing better override?
+
+ enum AreaParameter {
+ AREA_PARAM_GRAVITY,
+ AREA_PARAM_GRAVITY_VECTOR,
+ AREA_PARAM_GRAVITY_IS_POINT,
+ AREA_PARAM_GRAVITY_DISTANCE_SCALE,
+ AREA_PARAM_GRAVITY_POINT_ATTENUATION,
+ AREA_PARAM_LINEAR_DAMP,
+ AREA_PARAM_ANGULAR_DAMP,
+ AREA_PARAM_PRIORITY
+ };
+
+ virtual RID area_create() = 0;
+
+ virtual void area_set_space(RID p_area, RID p_space) = 0;
+ virtual RID area_get_space(RID p_area) const = 0;
+
+ enum AreaSpaceOverrideMode {
+ AREA_SPACE_OVERRIDE_DISABLED,
+ AREA_SPACE_OVERRIDE_COMBINE,
+ AREA_SPACE_OVERRIDE_COMBINE_REPLACE, // Combines, then discards all subsequent calculations
+ AREA_SPACE_OVERRIDE_REPLACE,
+ AREA_SPACE_OVERRIDE_REPLACE_COMBINE // Discards all previous calculations, then keeps combining
+ };
+
+ virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
+ virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
+
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
+ virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) = 0;
+
+ virtual int area_get_shape_count(RID p_area) const = 0;
+ virtual RID area_get_shape(RID p_area, int p_shape_idx) const = 0;
+ virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const = 0;
+
+ virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0;
+ virtual void area_clear_shapes(RID p_area) = 0;
+
+ virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) = 0;
+
+ virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id) = 0;
+ virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
+
+ virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_id) = 0;
+ virtual ObjectID area_get_canvas_instance_id(RID p_area) const = 0;
+
+ virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
+ virtual void area_set_transform(RID p_area, const Transform2D &p_transform) = 0;
+
+ virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
+ virtual Transform2D area_get_transform(RID p_area) const = 0;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
+ virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
+
+ virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
+ virtual void area_set_pickable(RID p_area, bool p_pickable) = 0;
+
+ virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
+ virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
+
+ /* BODY API */
+
+ //missing ccd?
+
+ enum BodyMode {
+ BODY_MODE_STATIC,
+ BODY_MODE_KINEMATIC,
+ BODY_MODE_RIGID,
+ BODY_MODE_CHARACTER
+ };
+
+ 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;
+
+ virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
+ virtual BodyMode body_get_mode(RID p_body) const = 0;
+
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
+ virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) = 0;
+ virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) = 0;
+
+ virtual int body_get_shape_count(RID p_body) const = 0;
+ virtual RID body_get_shape(RID p_body, int p_shape_idx) const = 0;
+ virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0;
+ virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0;
+
+ virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0;
+ virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, float p_margin = 0) = 0;
+
+ virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
+ virtual void body_clear_shapes(RID p_body) = 0;
+
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) = 0;
+ virtual ObjectID body_get_object_instance_id(RID p_body) const = 0;
+
+ virtual void body_attach_canvas_instance_id(RID p_body, ObjectID p_id) = 0;
+ virtual ObjectID body_get_canvas_instance_id(RID p_body) const = 0;
+
+ enum CCDMode {
+ CCD_MODE_DISABLED,
+ CCD_MODE_CAST_RAY,
+ CCD_MODE_CAST_SHAPE,
+ };
+
+ virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) = 0;
+ virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const = 0;
+
+ virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
+ virtual uint32_t body_get_collision_layer(RID p_body) const = 0;
+
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
+ virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
+
+ // common body variables
+ enum BodyParameter {
+ BODY_PARAM_BOUNCE,
+ BODY_PARAM_FRICTION,
+ BODY_PARAM_MASS, ///< unused for static, always infinite
+ BODY_PARAM_INERTIA, // read-only: computed from mass & shapes
+ BODY_PARAM_GRAVITY_SCALE,
+ BODY_PARAM_LINEAR_DAMP,
+ BODY_PARAM_ANGULAR_DAMP,
+ BODY_PARAM_MAX,
+ };
+
+ virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
+ virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
+
+ //state
+ enum BodyState {
+ BODY_STATE_TRANSFORM,
+ BODY_STATE_LINEAR_VELOCITY,
+ BODY_STATE_ANGULAR_VELOCITY,
+ BODY_STATE_SLEEPING,
+ BODY_STATE_CAN_SLEEP,
+ };
+
+ virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0;
+ virtual Variant body_get_state(RID p_body, BodyState p_state) const = 0;
+
+ //do something about it
+ virtual void body_set_applied_force(RID p_body, const Vector2 &p_force) = 0;
+ virtual Vector2 body_get_applied_force(RID p_body) const = 0;
+
+ virtual void body_set_applied_torque(RID p_body, float p_torque) = 0;
+ virtual float body_get_applied_torque(RID p_body) const = 0;
+
+ virtual void body_add_central_force(RID p_body, const Vector2 &p_force) = 0;
+ virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) = 0;
+ virtual void body_add_torque(RID p_body, float p_torque) = 0;
+
+ virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) = 0;
+ virtual void body_apply_torque_impulse(RID p_body, float p_torque) = 0;
+ virtual void body_apply_impulse(RID p_body, const Vector2 &p_offset, const Vector2 &p_impulse) = 0;
+ virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) = 0;
+
+ //fix
+ virtual void body_add_collision_exception(RID p_body, RID p_body_b) = 0;
+ virtual void body_remove_collision_exception(RID p_body, RID p_body_b) = 0;
+ virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0;
+
+ virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0;
+ virtual int body_get_max_contacts_reported(RID p_body) const = 0;
+
+ //missing remove
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) = 0;
+ virtual float body_get_contacts_reported_depth_threshold(RID p_body) const = 0;
+
+ 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 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;
+
+ virtual void body_set_pickable(RID p_body, bool p_pickable) = 0;
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) = 0;
+
+ struct MotionResult {
+
+ Vector2 motion;
+ Vector2 remainder;
+
+ Vector2 collision_point;
+ Vector2 collision_normal;
+ Vector2 collider_velocity;
+ int collision_local_shape;
+ ObjectID collider_id;
+ RID collider;
+ int collider_shape;
+ Variant collider_metadata;
+
+ MotionResult() {
+ collision_local_shape = 0;
+ collider_shape = 0;
+ collider_id = ObjectID();
+ }
+ };
+
+ virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0;
+
+ struct SeparationResult {
+
+ float collision_depth;
+ Vector2 collision_point;
+ Vector2 collision_normal;
+ Vector2 collider_velocity;
+ int collision_local_shape;
+ ObjectID collider_id;
+ RID collider;
+ int collider_shape;
+ Variant collider_metadata;
+ };
+
+ virtual 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, float p_margin = 0.001) = 0;
+
+ /* JOINT API */
+
+ enum JointType {
+
+ JOINT_PIN,
+ JOINT_GROOVE,
+ JOINT_DAMPED_SPRING
+ };
+
+ enum JointParam {
+ JOINT_PARAM_BIAS,
+ JOINT_PARAM_MAX_BIAS,
+ JOINT_PARAM_MAX_FORCE,
+ };
+
+ virtual void joint_set_param(RID p_joint, JointParam p_param, real_t p_value) = 0;
+ virtual real_t joint_get_param(RID p_joint, JointParam p_param) const = 0;
+
+ 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;
+
+ enum PinJointParam {
+ PIN_JOINT_SOFTNESS
+ };
+
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) = 0;
+ virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const = 0;
+
+ enum DampedStringParam {
+ DAMPED_STRING_REST_LENGTH,
+ DAMPED_STRING_STIFFNESS,
+ DAMPED_STRING_DAMPING
+ };
+ virtual void damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value) = 0;
+ virtual real_t damped_string_joint_get_param(RID p_joint, DampedStringParam p_param) const = 0;
+
+ virtual JointType joint_get_type(RID p_joint) const = 0;
+
+ /* QUERY API */
+
+ enum AreaBodyStatus {
+ AREA_BODY_ADDED,
+ AREA_BODY_REMOVED
+ };
+
+ /* MISC */
+
+ virtual void free(RID p_rid) = 0;
+
+ virtual void set_active(bool p_active) = 0;
+ virtual void init() = 0;
+ virtual void step(float 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;
+
+ enum ProcessInfo {
+
+ INFO_ACTIVE_OBJECTS,
+ INFO_COLLISION_PAIRS,
+ INFO_ISLAND_COUNT
+ };
+
+ virtual int get_process_info(ProcessInfo p_info) = 0;
+
+ PhysicsServer2D();
+ ~PhysicsServer2D();
+};
+
+class PhysicsTestMotionResult2D : public Reference {
+
+ GDCLASS(PhysicsTestMotionResult2D, Reference);
+
+ PhysicsServer2D::MotionResult result;
+ bool colliding;
+ friend class PhysicsServer2D;
+
+protected:
+ static void _bind_methods();
+
+public:
+ PhysicsServer2D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer2D::MotionResult *>(&result); }
+
+ //bool is_colliding() const;
+ Vector2 get_motion() const;
+ Vector2 get_motion_remainder() const;
+
+ Vector2 get_collision_point() const;
+ Vector2 get_collision_normal() const;
+ Vector2 get_collider_velocity() const;
+ ObjectID get_collider_id() const;
+ RID get_collider_rid() const;
+ Object *get_collider() const;
+ int get_collider_shape() const;
+
+ PhysicsTestMotionResult2D();
+};
+
+typedef PhysicsServer2D *(*CreatePhysicsServer2DCallback)();
+
+class PhysicsServer2DManager {
+ struct ClassInfo {
+ String name;
+ CreatePhysicsServer2DCallback create_callback;
+
+ ClassInfo() :
+ name(""),
+ create_callback(nullptr) {}
+
+ ClassInfo(String p_name, CreatePhysicsServer2DCallback p_create_callback) :
+ name(p_name),
+ create_callback(p_create_callback) {}
+
+ ClassInfo(const ClassInfo &p_ci) :
+ name(p_ci.name),
+ create_callback(p_ci.create_callback) {}
+
+ ClassInfo operator=(const ClassInfo &p_ci) {
+ name = p_ci.name;
+ create_callback = p_ci.create_callback;
+ return *this;
+ }
+ };
+
+ static Vector<ClassInfo> physics_2d_servers;
+ static int default_server_id;
+ static int default_server_priority;
+
+public:
+ static const String setting_property_name;
+
+private:
+ static void on_servers_changed();
+
+public:
+ static void register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback);
+ static void set_default_server(const String &p_name, int p_priority = 0);
+ static int find_server_id(const String &p_name);
+ static int get_servers_count();
+ static String get_server_name(int p_id);
+ static PhysicsServer2D *new_default_server();
+ static PhysicsServer2D *new_server(const String &p_name);
+};
+
+VARIANT_ENUM_CAST(PhysicsServer2D::ShapeType);
+VARIANT_ENUM_CAST(PhysicsServer2D::SpaceParameter);
+VARIANT_ENUM_CAST(PhysicsServer2D::AreaParameter);
+VARIANT_ENUM_CAST(PhysicsServer2D::AreaSpaceOverrideMode);
+VARIANT_ENUM_CAST(PhysicsServer2D::BodyMode);
+VARIANT_ENUM_CAST(PhysicsServer2D::BodyParameter);
+VARIANT_ENUM_CAST(PhysicsServer2D::BodyState);
+VARIANT_ENUM_CAST(PhysicsServer2D::CCDMode);
+VARIANT_ENUM_CAST(PhysicsServer2D::JointParam);
+VARIANT_ENUM_CAST(PhysicsServer2D::JointType);
+VARIANT_ENUM_CAST(PhysicsServer2D::DampedStringParam);
+//VARIANT_ENUM_CAST( PhysicsServer2D::ObjectType );
+VARIANT_ENUM_CAST(PhysicsServer2D::AreaBodyStatus);
+VARIANT_ENUM_CAST(PhysicsServer2D::ProcessInfo);
+
+#endif
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
new file mode 100644
index 0000000000..a5a02fd1bd
--- /dev/null
+++ b/servers/physics_server_3d.cpp
@@ -0,0 +1,800 @@
+/*************************************************************************/
+/* physics_server_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.h"
+
+#include "core/method_bind_ext.gen.inc"
+#include "core/print_string.h"
+#include "core/project_settings.h"
+
+PhysicsServer3D *PhysicsServer3D::singleton = nullptr;
+
+void PhysicsDirectBodyState3D::integrate_forces() {
+
+ real_t step = get_step();
+ Vector3 lv = get_linear_velocity();
+ lv += get_total_gravity() * step;
+
+ Vector3 av = get_angular_velocity();
+
+ float linear_damp = 1.0 - step * get_total_linear_damp();
+
+ if (linear_damp < 0) // reached zero in the given time
+ linear_damp = 0;
+
+ float angular_damp = 1.0 - step * get_total_angular_damp();
+
+ if (angular_damp < 0) // reached zero in the given time
+ angular_damp = 0;
+
+ lv *= linear_damp;
+ av *= angular_damp;
+
+ set_linear_velocity(lv);
+ set_angular_velocity(av);
+}
+
+Object *PhysicsDirectBodyState3D::get_contact_collider_object(int p_contact_idx) const {
+
+ ObjectID objid = get_contact_collider_id(p_contact_idx);
+ Object *obj = ObjectDB::get_instance(objid);
+ return obj;
+}
+
+PhysicsServer3D *PhysicsServer3D::get_singleton() {
+
+ return singleton;
+}
+
+void PhysicsDirectBodyState3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_total_gravity"), &PhysicsDirectBodyState3D::get_total_gravity);
+ ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &PhysicsDirectBodyState3D::get_total_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState3D::get_total_angular_damp);
+
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &PhysicsDirectBodyState3D::get_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_principal_inertia_axes"), &PhysicsDirectBodyState3D::get_principal_inertia_axes);
+
+ ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState3D::get_inverse_mass);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState3D::get_inverse_inertia);
+
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &PhysicsDirectBodyState3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicsDirectBodyState3D::get_linear_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &PhysicsDirectBodyState3D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicsDirectBodyState3D::get_angular_velocity);
+
+ ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState3D::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState3D::get_transform);
+
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState3D::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState3D::add_force);
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState3D::add_torque);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "j"), &PhysicsDirectBodyState3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "position", "j"), &PhysicsDirectBodyState3D::apply_impulse);
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "j"), &PhysicsDirectBodyState3D::apply_torque_impulse);
+
+ ClassDB::bind_method(D_METHOD("set_sleep_state", "enabled"), &PhysicsDirectBodyState3D::set_sleep_state);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &PhysicsDirectBodyState3D::is_sleeping);
+
+ ClassDB::bind_method(D_METHOD("get_contact_count"), &PhysicsDirectBodyState3D::get_contact_count);
+
+ ClassDB::bind_method(D_METHOD("get_contact_local_position", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_local_position);
+ ClassDB::bind_method(D_METHOD("get_contact_local_normal", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_local_normal);
+ ClassDB::bind_method(D_METHOD("get_contact_impulse", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_impulse);
+ ClassDB::bind_method(D_METHOD("get_contact_local_shape", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_local_shape);
+ ClassDB::bind_method(D_METHOD("get_contact_collider", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_collider);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_position", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_collider_position);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_id", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_collider_id);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_object", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_collider_object);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_shape", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_contact_collider_velocity_at_position", "contact_idx"), &PhysicsDirectBodyState3D::get_contact_collider_velocity_at_position);
+ ClassDB::bind_method(D_METHOD("get_step"), &PhysicsDirectBodyState3D::get_step);
+ ClassDB::bind_method(D_METHOD("integrate_forces"), &PhysicsDirectBodyState3D::integrate_forces);
+ ClassDB::bind_method(D_METHOD("get_space_state"), &PhysicsDirectBodyState3D::get_space_state);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "", "get_step");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inverse_mass"), "", "get_inverse_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inverse_inertia"), "", "get_inverse_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "total_gravity"), "", "get_total_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass"), "", "get_center_of_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::BASIS, "principal_inertia_axes"), "", "get_principal_inertia_axes");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
+}
+
+PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {}
+
+///////////////////////////////////////////////////////
+
+void PhysicsShapeQueryParameters3D::set_shape(const RES &p_shape) {
+
+ ERR_FAIL_COND(p_shape.is_null());
+ shape = p_shape->get_rid();
+}
+
+void PhysicsShapeQueryParameters3D::set_shape_rid(const RID &p_shape) {
+
+ shape = p_shape;
+}
+
+RID PhysicsShapeQueryParameters3D::get_shape_rid() const {
+
+ return shape;
+}
+
+void PhysicsShapeQueryParameters3D::set_transform(const Transform &p_transform) {
+
+ transform = p_transform;
+}
+Transform PhysicsShapeQueryParameters3D::get_transform() const {
+
+ return transform;
+}
+
+void PhysicsShapeQueryParameters3D::set_margin(float p_margin) {
+
+ margin = p_margin;
+}
+
+float PhysicsShapeQueryParameters3D::get_margin() const {
+
+ return margin;
+}
+
+void PhysicsShapeQueryParameters3D::set_collision_mask(int p_collision_mask) {
+
+ collision_mask = p_collision_mask;
+}
+int PhysicsShapeQueryParameters3D::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void PhysicsShapeQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) {
+
+ exclude.clear();
+ for (int i = 0; i < p_exclude.size(); i++)
+ exclude.insert(p_exclude[i]);
+}
+
+Vector<RID> PhysicsShapeQueryParameters3D::get_exclude() const {
+
+ Vector<RID> ret;
+ ret.resize(exclude.size());
+ int idx = 0;
+ for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) {
+ ret.write[idx] = E->get();
+ }
+ return ret;
+}
+
+void PhysicsShapeQueryParameters3D::set_collide_with_bodies(bool p_enable) {
+ collide_with_bodies = p_enable;
+}
+
+bool PhysicsShapeQueryParameters3D::is_collide_with_bodies_enabled() const {
+ return collide_with_bodies;
+}
+
+void PhysicsShapeQueryParameters3D::set_collide_with_areas(bool p_enable) {
+ collide_with_areas = p_enable;
+}
+
+bool PhysicsShapeQueryParameters3D::is_collide_with_areas_enabled() const {
+ return collide_with_areas;
+}
+
+void PhysicsShapeQueryParameters3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &PhysicsShapeQueryParameters3D::set_shape);
+ ClassDB::bind_method(D_METHOD("set_shape_rid", "shape"), &PhysicsShapeQueryParameters3D::set_shape_rid);
+ ClassDB::bind_method(D_METHOD("get_shape_rid"), &PhysicsShapeQueryParameters3D::get_shape_rid);
+
+ ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsShapeQueryParameters3D::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsShapeQueryParameters3D::get_transform);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsShapeQueryParameters3D::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsShapeQueryParameters3D::get_margin);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsShapeQueryParameters3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsShapeQueryParameters3D::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsShapeQueryParameters3D::set_exclude);
+ ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsShapeQueryParameters3D::get_exclude);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsShapeQueryParameters3D::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsShapeQueryParameters3D::is_collide_with_bodies_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsShapeQueryParameters3D::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters3D::is_collide_with_areas_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::_RID) + ":"), "set_exclude", "get_exclude");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin");
+ //ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", ""); // FIXME: Lacks a getter
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "shape_rid"), "set_shape_rid", "get_shape_rid");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled");
+}
+
+PhysicsShapeQueryParameters3D::PhysicsShapeQueryParameters3D() {
+
+ margin = 0;
+ collision_mask = 0x7FFFFFFF;
+ collide_with_bodies = true;
+ collide_with_areas = false;
+}
+
+/////////////////////////////////////
+
+Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
+
+ RayResult inters;
+ Set<RID> exclude;
+ for (int i = 0; i < p_exclude.size(); i++)
+ exclude.insert(p_exclude[i]);
+
+ bool res = intersect_ray(p_from, p_to, inters, exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas);
+
+ if (!res)
+ return Dictionary();
+
+ Dictionary d;
+ d["position"] = inters.position;
+ d["normal"] = inters.normal;
+ d["collider_id"] = inters.collider_id;
+ d["collider"] = inters.collider;
+ d["shape"] = inters.shape;
+ d["rid"] = inters.rid;
+
+ return d;
+}
+
+Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+
+ Vector<ShapeResult> sr;
+ sr.resize(p_max_results);
+ int rc = intersect_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, sr.ptrw(), sr.size(), p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ Array ret;
+ ret.resize(rc);
+ for (int i = 0; i < rc; i++) {
+
+ Dictionary d;
+ d["rid"] = sr[i].rid;
+ d["collider_id"] = sr[i].collider_id;
+ d["collider"] = sr[i].collider;
+ d["shape"] = sr[i].shape;
+ ret[i] = d;
+ }
+
+ return ret;
+}
+
+Array PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+
+ float closest_safe, closest_unsafe;
+ bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ if (!res)
+ return Array();
+ Array ret;
+ ret.resize(2);
+ ret[0] = closest_safe;
+ ret[1] = closest_unsafe;
+ return ret;
+}
+Array PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+
+ Vector<Vector3> ret;
+ ret.resize(p_max_results * 2);
+ int rc = 0;
+ bool res = collide_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, ret.ptrw(), p_max_results, rc, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ if (!res)
+ return Array();
+ Array r;
+ r.resize(rc * 2);
+ for (int i = 0; i < rc * 2; i++)
+ r[i] = ret[i];
+ return r;
+}
+Dictionary PhysicsDirectSpaceState3D::_get_rest_info(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query) {
+
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Dictionary());
+
+ ShapeRestInfo sri;
+
+ bool res = rest_info(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, &sri, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas);
+ Dictionary r;
+ if (!res)
+ return r;
+
+ r["point"] = sri.point;
+ r["normal"] = sri.normal;
+ r["rid"] = sri.rid;
+ r["collider_id"] = sri.collider_id;
+ r["shape"] = sri.shape;
+ r["linear_velocity"] = sri.linear_velocity;
+
+ return r;
+}
+
+PhysicsDirectSpaceState3D::PhysicsDirectSpaceState3D() {
+}
+
+void PhysicsDirectSpaceState3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState3D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_intersect_shape, DEFVAL(32));
+ ClassDB::bind_method(D_METHOD("cast_motion", "shape", "motion"), &PhysicsDirectSpaceState3D::_cast_motion);
+ ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_collide_shape, DEFVAL(32));
+ ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState3D::_get_rest_info);
+}
+
+int PhysicsShapeQueryResult3D::get_result_count() const {
+
+ return result.size();
+}
+RID PhysicsShapeQueryResult3D::get_result_rid(int p_idx) const {
+
+ return result[p_idx].rid;
+}
+ObjectID PhysicsShapeQueryResult3D::get_result_object_id(int p_idx) const {
+
+ return result[p_idx].collider_id;
+}
+Object *PhysicsShapeQueryResult3D::get_result_object(int p_idx) const {
+
+ return result[p_idx].collider;
+}
+int PhysicsShapeQueryResult3D::get_result_object_shape(int p_idx) const {
+
+ return result[p_idx].shape;
+}
+
+PhysicsShapeQueryResult3D::PhysicsShapeQueryResult3D() {
+}
+
+void PhysicsShapeQueryResult3D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_result_count"), &PhysicsShapeQueryResult3D::get_result_count);
+ ClassDB::bind_method(D_METHOD("get_result_rid", "idx"), &PhysicsShapeQueryResult3D::get_result_rid);
+ ClassDB::bind_method(D_METHOD("get_result_object_id", "idx"), &PhysicsShapeQueryResult3D::get_result_object_id);
+ ClassDB::bind_method(D_METHOD("get_result_object", "idx"), &PhysicsShapeQueryResult3D::get_result_object);
+ ClassDB::bind_method(D_METHOD("get_result_object_shape", "idx"), &PhysicsShapeQueryResult3D::get_result_object_shape);
+}
+
+///////////////////////////////////////
+
+void PhysicsServer3D::_bind_methods() {
+
+#ifndef _3D_DISABLED
+
+ ClassDB::bind_method(D_METHOD("shape_create", "type"), &PhysicsServer3D::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);
+ ClassDB::bind_method(D_METHOD("shape_get_data", "shape"), &PhysicsServer3D::shape_get_data);
+
+ ClassDB::bind_method(D_METHOD("space_create"), &PhysicsServer3D::space_create);
+ ClassDB::bind_method(D_METHOD("space_set_active", "space", "active"), &PhysicsServer3D::space_set_active);
+ ClassDB::bind_method(D_METHOD("space_is_active", "space"), &PhysicsServer3D::space_is_active);
+ ClassDB::bind_method(D_METHOD("space_set_param", "space", "param", "value"), &PhysicsServer3D::space_set_param);
+ ClassDB::bind_method(D_METHOD("space_get_param", "space", "param"), &PhysicsServer3D::space_get_param);
+ ClassDB::bind_method(D_METHOD("space_get_direct_state", "space"), &PhysicsServer3D::space_get_direct_state);
+
+ ClassDB::bind_method(D_METHOD("area_create"), &PhysicsServer3D::area_create);
+ ClassDB::bind_method(D_METHOD("area_set_space", "area", "space"), &PhysicsServer3D::area_set_space);
+ ClassDB::bind_method(D_METHOD("area_get_space", "area"), &PhysicsServer3D::area_get_space);
+
+ ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer3D::area_set_space_override_mode);
+ ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer3D::area_get_space_override_mode);
+
+ ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer3D::area_add_shape, DEFVAL(Transform()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer3D::area_set_shape);
+ ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer3D::area_set_shape_transform);
+ ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &PhysicsServer3D::area_set_shape_disabled);
+
+ ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &PhysicsServer3D::area_get_shape_count);
+ ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &PhysicsServer3D::area_get_shape);
+ ClassDB::bind_method(D_METHOD("area_get_shape_transform", "area", "shape_idx"), &PhysicsServer3D::area_get_shape_transform);
+
+ ClassDB::bind_method(D_METHOD("area_remove_shape", "area", "shape_idx"), &PhysicsServer3D::area_remove_shape);
+ ClassDB::bind_method(D_METHOD("area_clear_shapes", "area"), &PhysicsServer3D::area_clear_shapes);
+
+ ClassDB::bind_method(D_METHOD("area_set_collision_layer", "area", "layer"), &PhysicsServer3D::area_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("area_set_collision_mask", "area", "mask"), &PhysicsServer3D::area_set_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("area_set_param", "area", "param", "value"), &PhysicsServer3D::area_set_param);
+ ClassDB::bind_method(D_METHOD("area_set_transform", "area", "transform"), &PhysicsServer3D::area_set_transform);
+
+ ClassDB::bind_method(D_METHOD("area_get_param", "area", "param"), &PhysicsServer3D::area_get_param);
+ ClassDB::bind_method(D_METHOD("area_get_transform", "area"), &PhysicsServer3D::area_get_transform);
+
+ ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &PhysicsServer3D::area_attach_object_instance_id);
+ ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &PhysicsServer3D::area_get_object_instance_id);
+
+ ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &PhysicsServer3D::area_set_monitor_callback);
+ ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &PhysicsServer3D::area_set_area_monitor_callback);
+ 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_set_space", "body", "space"), &PhysicsServer3D::body_set_space);
+ ClassDB::bind_method(D_METHOD("body_get_space", "body"), &PhysicsServer3D::body_get_space);
+
+ ClassDB::bind_method(D_METHOD("body_set_mode", "body", "mode"), &PhysicsServer3D::body_set_mode);
+ ClassDB::bind_method(D_METHOD("body_get_mode", "body"), &PhysicsServer3D::body_get_mode);
+
+ ClassDB::bind_method(D_METHOD("body_set_collision_layer", "body", "layer"), &PhysicsServer3D::body_set_collision_layer);
+ ClassDB::bind_method(D_METHOD("body_get_collision_layer", "body"), &PhysicsServer3D::body_get_collision_layer);
+
+ ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer3D::body_set_collision_mask);
+ ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer3D::body_get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer3D::body_set_shape);
+ ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer3D::body_set_shape_transform);
+ ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &PhysicsServer3D::body_set_shape_disabled);
+
+ ClassDB::bind_method(D_METHOD("body_get_shape_count", "body"), &PhysicsServer3D::body_get_shape_count);
+ ClassDB::bind_method(D_METHOD("body_get_shape", "body", "shape_idx"), &PhysicsServer3D::body_get_shape);
+ ClassDB::bind_method(D_METHOD("body_get_shape_transform", "body", "shape_idx"), &PhysicsServer3D::body_get_shape_transform);
+
+ ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &PhysicsServer3D::body_remove_shape);
+ ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &PhysicsServer3D::body_clear_shapes);
+
+ ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &PhysicsServer3D::body_attach_object_instance_id);
+ ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &PhysicsServer3D::body_get_object_instance_id);
+
+ ClassDB::bind_method(D_METHOD("body_set_enable_continuous_collision_detection", "body", "enable"), &PhysicsServer3D::body_set_enable_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("body_is_continuous_collision_detection_enabled", "body"), &PhysicsServer3D::body_is_continuous_collision_detection_enabled);
+
+ ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer3D::body_set_param);
+ ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer3D::body_get_param);
+
+ ClassDB::bind_method(D_METHOD("body_set_kinematic_safe_margin", "body", "margin"), &PhysicsServer3D::body_set_kinematic_safe_margin);
+ ClassDB::bind_method(D_METHOD("body_get_kinematic_safe_margin", "body"), &PhysicsServer3D::body_get_kinematic_safe_margin);
+
+ ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer3D::body_set_state);
+ ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer3D::body_get_state);
+
+ ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &PhysicsServer3D::body_add_central_force);
+ ClassDB::bind_method(D_METHOD("body_add_force", "body", "force", "position"), &PhysicsServer3D::body_add_force);
+ ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &PhysicsServer3D::body_add_torque);
+
+ ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &PhysicsServer3D::body_apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &PhysicsServer3D::body_apply_impulse);
+ ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &PhysicsServer3D::body_apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &PhysicsServer3D::body_set_axis_velocity);
+
+ ClassDB::bind_method(D_METHOD("body_set_axis_lock", "body", "axis", "lock"), &PhysicsServer3D::body_set_axis_lock);
+ ClassDB::bind_method(D_METHOD("body_is_axis_locked", "body", "axis"), &PhysicsServer3D::body_is_axis_locked);
+
+ ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &PhysicsServer3D::body_add_collision_exception);
+ ClassDB::bind_method(D_METHOD("body_remove_collision_exception", "body", "excepted_body"), &PhysicsServer3D::body_remove_collision_exception);
+
+ ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &PhysicsServer3D::body_set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &PhysicsServer3D::body_get_max_contacts_reported);
+
+ 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_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);
+
+ /* 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_pin", "body_A", "local_A", "body_B", "local_B"), &PhysicsServer3D::joint_create_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);
+
+ ClassDB::bind_method(D_METHOD("pin_joint_set_local_a", "joint", "local_A"), &PhysicsServer3D::pin_joint_set_local_a);
+ ClassDB::bind_method(D_METHOD("pin_joint_get_local_a", "joint"), &PhysicsServer3D::pin_joint_get_local_a);
+
+ ClassDB::bind_method(D_METHOD("pin_joint_set_local_b", "joint", "local_B"), &PhysicsServer3D::pin_joint_set_local_b);
+ ClassDB::bind_method(D_METHOD("pin_joint_get_local_b", "joint"), &PhysicsServer3D::pin_joint_get_local_b);
+
+ BIND_ENUM_CONSTANT(PIN_JOINT_BIAS);
+ BIND_ENUM_CONSTANT(PIN_JOINT_DAMPING);
+ BIND_ENUM_CONSTANT(PIN_JOINT_IMPULSE_CLAMP);
+
+ BIND_ENUM_CONSTANT(HINGE_JOINT_BIAS);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_UPPER);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_LOWER);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_BIAS);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_LIMIT_RELAXATION);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(HINGE_JOINT_MOTOR_MAX_IMPULSE);
+
+ 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("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);
+
+ 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("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);
+
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_UPPER);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_LOWER);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_LIMIT_DAMPING);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_MOTION_SOFTNESS);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_MOTION_RESTITUTION);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_MOTION_DAMPING);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING);
+
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_UPPER);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_LOWER);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_LIMIT_DAMPING);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_MOTION_DAMPING);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS);
+ BIND_ENUM_CONSTANT(SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION);
+ 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("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);
+
+ BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_SWING_SPAN);
+ BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_TWIST_SPAN);
+ BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_BIAS);
+ BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_SOFTNESS);
+ BIND_ENUM_CONSTANT(CONE_TWIST_JOINT_RELAXATION);
+
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_LOWER_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_UPPER_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_RESTITUTION);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_DAMPING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LOWER_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_UPPER_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_DAMPING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_RESTITUTION);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_ERP);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT);
+
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_MOTOR);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR);
+
+ ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer3D::joint_get_type);
+
+ 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("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);
+
+ ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_flag", "joint", "axis", "flag", "enable"), &PhysicsServer3D::generic_6dof_joint_set_flag);
+ ClassDB::bind_method(D_METHOD("generic_6dof_joint_get_flag", "joint", "axis", "flag"), &PhysicsServer3D::generic_6dof_joint_get_flag);
+
+ ClassDB::bind_method(D_METHOD("free_rid", "rid"), &PhysicsServer3D::free);
+
+ ClassDB::bind_method(D_METHOD("set_active", "active"), &PhysicsServer3D::set_active);
+
+ ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer3D::get_process_info);
+
+ BIND_ENUM_CONSTANT(SHAPE_PLANE);
+ BIND_ENUM_CONSTANT(SHAPE_RAY);
+ BIND_ENUM_CONSTANT(SHAPE_SPHERE);
+ BIND_ENUM_CONSTANT(SHAPE_BOX);
+ BIND_ENUM_CONSTANT(SHAPE_CAPSULE);
+ BIND_ENUM_CONSTANT(SHAPE_CYLINDER);
+ BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
+ BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
+ BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP);
+ BIND_ENUM_CONSTANT(SHAPE_CUSTOM);
+
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_DISTANCE_SCALE);
+ BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_ATTENUATION);
+ BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP);
+ BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP);
+ BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY);
+
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_DISABLED);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_COMBINE_REPLACE);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE);
+ BIND_ENUM_CONSTANT(AREA_SPACE_OVERRIDE_REPLACE_COMBINE);
+
+ BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
+ BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
+ BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
+ BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER);
+
+ BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
+ BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
+ BIND_ENUM_CONSTANT(BODY_PARAM_MASS);
+ BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE);
+ BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP);
+ BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP);
+ BIND_ENUM_CONSTANT(BODY_PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(BODY_STATE_TRANSFORM);
+ BIND_ENUM_CONSTANT(BODY_STATE_LINEAR_VELOCITY);
+ BIND_ENUM_CONSTANT(BODY_STATE_ANGULAR_VELOCITY);
+ BIND_ENUM_CONSTANT(BODY_STATE_SLEEPING);
+ BIND_ENUM_CONSTANT(BODY_STATE_CAN_SLEEP);
+
+ BIND_ENUM_CONSTANT(AREA_BODY_ADDED);
+ BIND_ENUM_CONSTANT(AREA_BODY_REMOVED);
+
+ BIND_ENUM_CONSTANT(INFO_ACTIVE_OBJECTS);
+ BIND_ENUM_CONSTANT(INFO_COLLISION_PAIRS);
+ BIND_ENUM_CONSTANT(INFO_ISLAND_COUNT);
+
+ BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_RECYCLE_RADIUS);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_CONTACT_MAX_SEPARATION);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS);
+ BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);
+
+ BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X);
+ BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y);
+ BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Z);
+ BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_X);
+ BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Y);
+ BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Z);
+
+#endif
+}
+
+PhysicsServer3D::PhysicsServer3D() {
+
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
+}
+
+PhysicsServer3D::~PhysicsServer3D() {
+
+ singleton = nullptr;
+}
+
+Vector<PhysicsServer3DManager::ClassInfo> PhysicsServer3DManager::physics_servers;
+int PhysicsServer3DManager::default_server_id = -1;
+int PhysicsServer3DManager::default_server_priority = -1;
+const String PhysicsServer3DManager::setting_property_name("physics/3d/physics_engine");
+
+void PhysicsServer3DManager::on_servers_changed() {
+
+ String physics_servers2("DEFAULT");
+ for (int i = get_servers_count() - 1; 0 <= i; --i) {
+ physics_servers2 += "," + get_server_name(i);
+ }
+ ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers2));
+}
+
+void PhysicsServer3DManager::register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback) {
+
+ ERR_FAIL_COND(!p_creat_callback);
+ ERR_FAIL_COND(find_server_id(p_name) != -1);
+ physics_servers.push_back(ClassInfo(p_name, p_creat_callback));
+ on_servers_changed();
+}
+
+void PhysicsServer3DManager::set_default_server(const String &p_name, int p_priority) {
+
+ const int id = find_server_id(p_name);
+ ERR_FAIL_COND(id == -1); // Not found
+ if (default_server_priority < p_priority) {
+ default_server_id = id;
+ default_server_priority = p_priority;
+ }
+}
+
+int PhysicsServer3DManager::find_server_id(const String &p_name) {
+
+ for (int i = physics_servers.size() - 1; 0 <= i; --i) {
+ if (p_name == physics_servers[i].name) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int PhysicsServer3DManager::get_servers_count() {
+ return physics_servers.size();
+}
+
+String PhysicsServer3DManager::get_server_name(int p_id) {
+ ERR_FAIL_INDEX_V(p_id, get_servers_count(), "");
+ return physics_servers[p_id].name;
+}
+
+PhysicsServer3D *PhysicsServer3DManager::new_default_server() {
+ ERR_FAIL_COND_V(default_server_id == -1, nullptr);
+ return physics_servers[default_server_id].create_callback();
+}
+
+PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) {
+ int id = find_server_id(p_name);
+ if (id == -1) {
+ return nullptr;
+ } else {
+ return physics_servers[id].create_callback();
+ }
+}
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
new file mode 100644
index 0000000000..8ea8b22455
--- /dev/null
+++ b/servers/physics_server_3d.h
@@ -0,0 +1,844 @@
+/*************************************************************************/
+/* physics_server_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 PHYSICS_SERVER_H
+#define PHYSICS_SERVER_H
+
+#include "core/object.h"
+#include "core/resource.h"
+
+class PhysicsDirectSpaceState3D;
+
+class PhysicsDirectBodyState3D : public Object {
+
+ GDCLASS(PhysicsDirectBodyState3D, Object);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Vector3 get_total_gravity() const = 0;
+ virtual float get_total_angular_damp() const = 0;
+ virtual float get_total_linear_damp() const = 0;
+
+ virtual Vector3 get_center_of_mass() const = 0;
+ virtual Basis get_principal_inertia_axes() const = 0;
+ virtual float get_inverse_mass() const = 0; // get the mass
+ virtual Vector3 get_inverse_inertia() const = 0; // get density of this body space
+ virtual Basis get_inverse_inertia_tensor() const = 0; // get density of this body space
+
+ virtual void set_linear_velocity(const Vector3 &p_velocity) = 0;
+ virtual Vector3 get_linear_velocity() const = 0;
+
+ virtual void set_angular_velocity(const Vector3 &p_velocity) = 0;
+ virtual Vector3 get_angular_velocity() const = 0;
+
+ virtual void set_transform(const Transform &p_transform) = 0;
+ virtual Transform get_transform() const = 0;
+
+ virtual void add_central_force(const Vector3 &p_force) = 0;
+ virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) = 0;
+ virtual void add_torque(const Vector3 &p_torque) = 0;
+ virtual void apply_central_impulse(const Vector3 &p_j) = 0;
+ virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) = 0;
+ virtual void apply_torque_impulse(const Vector3 &p_j) = 0;
+
+ virtual void set_sleep_state(bool p_sleep) = 0;
+ virtual bool is_sleeping() const = 0;
+
+ virtual int get_contact_count() const = 0;
+
+ virtual Vector3 get_contact_local_position(int p_contact_idx) const = 0;
+ virtual Vector3 get_contact_local_normal(int p_contact_idx) const = 0;
+ virtual float get_contact_impulse(int p_contact_idx) const = 0;
+ virtual int get_contact_local_shape(int p_contact_idx) const = 0;
+
+ virtual RID get_contact_collider(int p_contact_idx) const = 0;
+ virtual Vector3 get_contact_collider_position(int p_contact_idx) const = 0;
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const = 0;
+ virtual Object *get_contact_collider_object(int p_contact_idx) const;
+ virtual int get_contact_collider_shape(int p_contact_idx) const = 0;
+ virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const = 0;
+
+ virtual real_t get_step() const = 0;
+ virtual void integrate_forces();
+
+ virtual PhysicsDirectSpaceState3D *get_space_state() = 0;
+
+ PhysicsDirectBodyState3D();
+};
+
+class PhysicsShapeQueryResult3D;
+
+class PhysicsShapeQueryParameters3D : public Reference {
+
+ GDCLASS(PhysicsShapeQueryParameters3D, Reference);
+ friend class PhysicsDirectSpaceState3D;
+
+ RID shape;
+ Transform transform;
+ float margin;
+ Set<RID> exclude;
+ uint32_t collision_mask;
+
+ bool collide_with_bodies;
+ bool collide_with_areas;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_shape(const RES &p_shape);
+ void set_shape_rid(const RID &p_shape);
+ RID get_shape_rid() const;
+
+ void set_transform(const Transform &p_transform);
+ Transform get_transform() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_collision_mask(int p_collision_mask);
+ int get_collision_mask() const;
+
+ void set_exclude(const Vector<RID> &p_exclude);
+ Vector<RID> get_exclude() const;
+
+ void set_collide_with_bodies(bool p_enable);
+ bool is_collide_with_bodies_enabled() const;
+
+ void set_collide_with_areas(bool p_enable);
+ bool is_collide_with_areas_enabled() const;
+
+ PhysicsShapeQueryParameters3D();
+};
+
+class PhysicsDirectSpaceState3D : public Object {
+
+ GDCLASS(PhysicsDirectSpaceState3D, Object);
+
+private:
+ Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ Array _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
+ Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion);
+ Array _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
+ Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query);
+
+protected:
+ static void _bind_methods();
+
+public:
+ struct ShapeResult {
+
+ RID rid;
+ ObjectID collider_id;
+ Object *collider;
+ int shape;
+ };
+
+ virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ struct RayResult {
+
+ Vector3 position;
+ Vector3 normal;
+ RID rid;
+ ObjectID collider_id;
+ Object *collider;
+ int shape;
+ };
+
+ virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0;
+
+ virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ struct ShapeRestInfo {
+
+ Vector3 point;
+ Vector3 normal;
+ RID rid;
+ ObjectID collider_id;
+ int shape;
+ Vector3 linear_velocity; //velocity at contact point
+ };
+
+ virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0;
+
+ virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0;
+
+ virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0;
+
+ PhysicsDirectSpaceState3D();
+};
+
+class PhysicsShapeQueryResult3D : public Reference {
+
+ GDCLASS(PhysicsShapeQueryResult3D, Reference);
+
+ Vector<PhysicsDirectSpaceState3D::ShapeResult> result;
+
+ friend class PhysicsDirectSpaceState3D;
+
+protected:
+ static void _bind_methods();
+
+public:
+ int get_result_count() const;
+ RID get_result_rid(int p_idx) const;
+ ObjectID get_result_object_id(int p_idx) const;
+ Object *get_result_object(int p_idx) const;
+ int get_result_object_shape(int p_idx) const;
+
+ PhysicsShapeQueryResult3D();
+};
+
+class PhysicsServer3D : public Object {
+
+ GDCLASS(PhysicsServer3D, Object);
+
+ static PhysicsServer3D *singleton;
+
+protected:
+ static void _bind_methods();
+
+public:
+ static PhysicsServer3D *get_singleton();
+
+ enum ShapeType {
+ SHAPE_PLANE, ///< plane:"plane"
+ SHAPE_RAY, ///< float:"length"
+ SHAPE_SPHERE, ///< float:"radius"
+ SHAPE_BOX, ///< vec3:"extents"
+ SHAPE_CAPSULE, ///< dict( float:"radius", float:"height"):capsule
+ SHAPE_CYLINDER, ///< dict( float:"radius", float:"height"):cylinder
+ 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_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;
+ 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;
+
+ virtual ShapeType shape_get_type(RID p_shape) const = 0;
+ virtual Variant shape_get_data(RID p_shape) const = 0;
+
+ virtual void shape_set_margin(RID p_shape, real_t p_margin) = 0;
+ virtual real_t shape_get_margin(RID p_shape) const = 0;
+
+ virtual real_t shape_get_custom_solver_bias(RID p_shape) const = 0;
+
+ /* SPACE API */
+
+ virtual RID space_create() = 0;
+ virtual void space_set_active(RID p_space, bool p_active) = 0;
+ virtual bool space_is_active(RID p_space) const = 0;
+
+ enum SpaceParameter {
+
+ SPACE_PARAM_CONTACT_RECYCLE_RADIUS,
+ SPACE_PARAM_CONTACT_MAX_SEPARATION,
+ SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,
+ SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD,
+ SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD,
+ SPACE_PARAM_BODY_TIME_TO_SLEEP,
+ SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,
+ SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
+ SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH
+ };
+
+ virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0;
+ virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const = 0;
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) = 0;
+
+ virtual void space_set_debug_contacts(RID p_space, int p_max_contacts) = 0;
+ virtual Vector<Vector3> space_get_contacts(RID p_space) const = 0;
+ virtual int space_get_contact_count(RID p_space) const = 0;
+
+ //missing space parameters
+
+ /* AREA API */
+
+ //missing attenuation? missing better override?
+
+ enum AreaParameter {
+ AREA_PARAM_GRAVITY,
+ AREA_PARAM_GRAVITY_VECTOR,
+ AREA_PARAM_GRAVITY_IS_POINT,
+ AREA_PARAM_GRAVITY_DISTANCE_SCALE,
+ AREA_PARAM_GRAVITY_POINT_ATTENUATION,
+ AREA_PARAM_LINEAR_DAMP,
+ AREA_PARAM_ANGULAR_DAMP,
+ AREA_PARAM_PRIORITY
+ };
+
+ virtual RID area_create() = 0;
+
+ virtual void area_set_space(RID p_area, RID p_space) = 0;
+ virtual RID area_get_space(RID p_area) const = 0;
+
+ enum AreaSpaceOverrideMode {
+ AREA_SPACE_OVERRIDE_DISABLED,
+ AREA_SPACE_OVERRIDE_COMBINE,
+ AREA_SPACE_OVERRIDE_COMBINE_REPLACE,
+ AREA_SPACE_OVERRIDE_REPLACE,
+ AREA_SPACE_OVERRIDE_REPLACE_COMBINE
+ };
+
+ virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
+ virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
+
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
+ virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) = 0;
+
+ virtual int area_get_shape_count(RID p_area) const = 0;
+ virtual RID area_get_shape(RID p_area, int p_shape_idx) const = 0;
+ virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const = 0;
+
+ virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0;
+ virtual void area_clear_shapes(RID p_area) = 0;
+
+ virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) = 0;
+
+ virtual void area_attach_object_instance_id(RID p_area, ObjectID p_id) = 0;
+ virtual ObjectID area_get_object_instance_id(RID p_area) const = 0;
+
+ virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0;
+ virtual void area_set_transform(RID p_area, const Transform &p_transform) = 0;
+
+ virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0;
+ virtual Transform area_get_transform(RID p_area) const = 0;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0;
+ virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0;
+
+ virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0;
+
+ virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0;
+ 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 */
+
+ //missing ccd?
+
+ enum BodyMode {
+ BODY_MODE_STATIC,
+ BODY_MODE_KINEMATIC,
+ BODY_MODE_RIGID,
+ BODY_MODE_CHARACTER
+ };
+
+ virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) = 0;
+
+ virtual void body_set_space(RID p_body, RID p_space) = 0;
+ virtual RID body_get_space(RID p_body) const = 0;
+
+ virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
+ virtual BodyMode body_get_mode(RID p_body) const = 0;
+
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
+ virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) = 0;
+
+ virtual int body_get_shape_count(RID p_body) const = 0;
+ virtual RID body_get_shape(RID p_body, int p_shape_idx) const = 0;
+ virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const = 0;
+
+ virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
+ virtual void body_clear_shapes(RID p_body) = 0;
+
+ virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) = 0;
+
+ virtual void body_attach_object_instance_id(RID p_body, ObjectID p_id) = 0;
+ virtual ObjectID body_get_object_instance_id(RID p_body) const = 0;
+
+ virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) = 0;
+ virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const = 0;
+
+ virtual void body_set_collision_layer(RID p_body, uint32_t p_layer) = 0;
+ virtual uint32_t body_get_collision_layer(RID p_body) const = 0;
+
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
+ virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
+
+ virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0;
+ virtual uint32_t body_get_user_flags(RID p_body) const = 0;
+
+ // common body variables
+ enum BodyParameter {
+ BODY_PARAM_BOUNCE,
+ BODY_PARAM_FRICTION,
+ BODY_PARAM_MASS, ///< unused for static, always infinite
+ BODY_PARAM_GRAVITY_SCALE,
+ BODY_PARAM_LINEAR_DAMP,
+ BODY_PARAM_ANGULAR_DAMP,
+ BODY_PARAM_MAX,
+ };
+
+ virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
+ virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
+
+ virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0;
+ virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0;
+
+ //state
+ enum BodyState {
+ BODY_STATE_TRANSFORM,
+ BODY_STATE_LINEAR_VELOCITY,
+ BODY_STATE_ANGULAR_VELOCITY,
+ BODY_STATE_SLEEPING,
+ BODY_STATE_CAN_SLEEP
+ };
+
+ virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0;
+ virtual Variant body_get_state(RID p_body, BodyState p_state) const = 0;
+
+ //do something about it
+ virtual void body_set_applied_force(RID p_body, const Vector3 &p_force) = 0;
+ virtual Vector3 body_get_applied_force(RID p_body) const = 0;
+
+ virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque) = 0;
+ virtual Vector3 body_get_applied_torque(RID p_body) const = 0;
+
+ virtual void body_add_central_force(RID p_body, const Vector3 &p_force) = 0;
+ virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) = 0;
+ virtual void body_add_torque(RID p_body, const Vector3 &p_torque) = 0;
+
+ virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) = 0;
+ virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) = 0;
+ virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) = 0;
+ virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) = 0;
+
+ enum BodyAxis {
+ BODY_AXIS_LINEAR_X = 1 << 0,
+ BODY_AXIS_LINEAR_Y = 1 << 1,
+ BODY_AXIS_LINEAR_Z = 1 << 2,
+ BODY_AXIS_ANGULAR_X = 1 << 3,
+ BODY_AXIS_ANGULAR_Y = 1 << 4,
+ BODY_AXIS_ANGULAR_Z = 1 << 5
+ };
+
+ virtual void body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) = 0;
+ virtual bool body_is_axis_locked(RID p_body, BodyAxis p_axis) const = 0;
+
+ //fix
+ virtual void body_add_collision_exception(RID p_body, RID p_body_b) = 0;
+ virtual void body_remove_collision_exception(RID p_body, RID p_body_b) = 0;
+ virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0;
+
+ virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0;
+ virtual int body_get_max_contacts_reported(RID p_body) const = 0;
+
+ //missing remove
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) = 0;
+ virtual float body_get_contacts_reported_depth_threshold(RID p_body) const = 0;
+
+ 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_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;
+
+ struct MotionResult {
+
+ Vector3 motion;
+ Vector3 remainder;
+
+ Vector3 collision_point;
+ Vector3 collision_normal;
+ Vector3 collider_velocity;
+ int collision_local_shape;
+ ObjectID collider_id;
+ RID collider;
+ int collider_shape;
+ Variant collider_metadata;
+ MotionResult() {
+ collision_local_shape = 0;
+ collider_id = ObjectID();
+ collider_shape = 0;
+ }
+ };
+
+ 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) = 0;
+
+ struct SeparationResult {
+
+ float collision_depth;
+ Vector3 collision_point;
+ Vector3 collision_normal;
+ Vector3 collider_velocity;
+ int collision_local_shape;
+ ObjectID collider_id;
+ RID collider;
+ int collider_shape;
+ Variant collider_metadata;
+ };
+
+ 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, float p_margin = 0.001) = 0;
+
+ /* SOFT BODY */
+
+ virtual RID soft_body_create(bool p_init_sleeping = false) = 0;
+
+ virtual void soft_body_update_rendering_server(RID p_body, class SoftBodyRenderingServerHandler *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 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;
+
+ virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
+ virtual uint32_t soft_body_get_collision_mask(RID p_body) const = 0;
+
+ virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) = 0;
+ virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) = 0;
+ virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0;
+
+ virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0;
+ 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 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 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 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 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 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 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 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;
+
+ /* JOINT API */
+
+ enum JointType {
+
+ JOINT_PIN,
+ JOINT_HINGE,
+ JOINT_SLIDER,
+ JOINT_CONE_TWIST,
+ JOINT_6DOF
+
+ };
+
+ virtual JointType joint_get_type(RID p_joint) const = 0;
+
+ virtual void joint_set_solver_priority(RID p_joint, int p_priority) = 0;
+ virtual int joint_get_solver_priority(RID p_joint) const = 0;
+
+ 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;
+
+ enum PinJointParam {
+ PIN_JOINT_BIAS,
+ PIN_JOINT_DAMPING,
+ PIN_JOINT_IMPULSE_CLAMP
+ };
+
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) = 0;
+ virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const = 0;
+
+ virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) = 0;
+ virtual Vector3 pin_joint_get_local_a(RID p_joint) const = 0;
+
+ virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) = 0;
+ virtual Vector3 pin_joint_get_local_b(RID p_joint) const = 0;
+
+ enum HingeJointParam {
+
+ HINGE_JOINT_BIAS,
+ HINGE_JOINT_LIMIT_UPPER,
+ HINGE_JOINT_LIMIT_LOWER,
+ HINGE_JOINT_LIMIT_BIAS,
+ HINGE_JOINT_LIMIT_SOFTNESS,
+ HINGE_JOINT_LIMIT_RELAXATION,
+ HINGE_JOINT_MOTOR_TARGET_VELOCITY,
+ HINGE_JOINT_MOTOR_MAX_IMPULSE,
+ HINGE_JOINT_MAX
+ };
+
+ enum HingeJointFlag {
+ HINGE_JOINT_FLAG_USE_LIMIT,
+ HINGE_JOINT_FLAG_ENABLE_MOTOR,
+ 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 hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) = 0;
+ virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const = 0;
+
+ virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) = 0;
+ virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const = 0;
+
+ enum SliderJointParam {
+ SLIDER_JOINT_LINEAR_LIMIT_UPPER,
+ SLIDER_JOINT_LINEAR_LIMIT_LOWER,
+ SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS,
+ SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION,
+ SLIDER_JOINT_LINEAR_LIMIT_DAMPING,
+ SLIDER_JOINT_LINEAR_MOTION_SOFTNESS,
+ SLIDER_JOINT_LINEAR_MOTION_RESTITUTION,
+ SLIDER_JOINT_LINEAR_MOTION_DAMPING,
+ SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS,
+ SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION,
+ SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING,
+
+ SLIDER_JOINT_ANGULAR_LIMIT_UPPER,
+ SLIDER_JOINT_ANGULAR_LIMIT_LOWER,
+ SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION,
+ SLIDER_JOINT_ANGULAR_LIMIT_DAMPING,
+ SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS,
+ SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION,
+ SLIDER_JOINT_ANGULAR_MOTION_DAMPING,
+ SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS,
+ SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION,
+ SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING,
+ SLIDER_JOINT_MAX
+
+ };
+
+ 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 slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) = 0;
+ virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0;
+
+ enum ConeTwistJointParam {
+ CONE_TWIST_JOINT_SWING_SPAN,
+ CONE_TWIST_JOINT_TWIST_SPAN,
+ CONE_TWIST_JOINT_BIAS,
+ CONE_TWIST_JOINT_SOFTNESS,
+ CONE_TWIST_JOINT_RELAXATION,
+ 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 cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) = 0;
+ virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0;
+
+ enum G6DOFJointAxisParam {
+ G6DOF_JOINT_LINEAR_LOWER_LIMIT,
+ G6DOF_JOINT_LINEAR_UPPER_LIMIT,
+ G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
+ G6DOF_JOINT_LINEAR_RESTITUTION,
+ G6DOF_JOINT_LINEAR_DAMPING,
+ G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
+ G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
+ G6DOF_JOINT_LINEAR_SPRING_STIFFNESS,
+ G6DOF_JOINT_LINEAR_SPRING_DAMPING,
+ G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT,
+ G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
+ G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
+ G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
+ G6DOF_JOINT_ANGULAR_DAMPING,
+ G6DOF_JOINT_ANGULAR_RESTITUTION,
+ G6DOF_JOINT_ANGULAR_FORCE_LIMIT,
+ G6DOF_JOINT_ANGULAR_ERP,
+ G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY,
+ G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT,
+ G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS,
+ G6DOF_JOINT_ANGULAR_SPRING_DAMPING,
+ G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT,
+ G6DOF_JOINT_MAX
+ };
+
+ enum G6DOFJointAxisFlag {
+
+ G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
+ G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
+ G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING,
+ G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING,
+ G6DOF_JOINT_FLAG_ENABLE_MOTOR,
+ G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
+ 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 generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, float p_value) = 0;
+ virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) = 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 void generic_6dof_joint_set_precision(RID p_joint, int precision) = 0;
+ virtual int generic_6dof_joint_get_precision(RID p_joint) = 0;
+
+ /* QUERY API */
+
+ enum AreaBodyStatus {
+ AREA_BODY_ADDED,
+ AREA_BODY_REMOVED
+ };
+
+ /* MISC */
+
+ virtual void free(RID p_rid) = 0;
+
+ virtual void set_active(bool p_active) = 0;
+ virtual void init() = 0;
+ virtual void step(float p_step) = 0;
+ virtual void sync() = 0;
+ virtual void flush_queries() = 0;
+ virtual void finish() = 0;
+
+ virtual bool is_flushing_queries() const = 0;
+
+ enum ProcessInfo {
+
+ INFO_ACTIVE_OBJECTS,
+ INFO_COLLISION_PAIRS,
+ INFO_ISLAND_COUNT
+ };
+
+ virtual int get_process_info(ProcessInfo p_info) = 0;
+
+ PhysicsServer3D();
+ ~PhysicsServer3D();
+};
+
+typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)();
+
+class PhysicsServer3DManager {
+ struct ClassInfo {
+ String name;
+ CreatePhysicsServer3DCallback create_callback;
+
+ ClassInfo() :
+ name(""),
+ create_callback(nullptr) {}
+
+ ClassInfo(String p_name, CreatePhysicsServer3DCallback p_create_callback) :
+ name(p_name),
+ create_callback(p_create_callback) {}
+
+ ClassInfo(const ClassInfo &p_ci) :
+ name(p_ci.name),
+ create_callback(p_ci.create_callback) {}
+
+ ClassInfo operator=(const ClassInfo &p_ci) {
+ name = p_ci.name;
+ create_callback = p_ci.create_callback;
+ return *this;
+ }
+ };
+
+ static Vector<ClassInfo> physics_servers;
+ static int default_server_id;
+ static int default_server_priority;
+
+public:
+ static const String setting_property_name;
+
+private:
+ static void on_servers_changed();
+
+public:
+ static void register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback);
+ static void set_default_server(const String &p_name, int p_priority = 0);
+ static int find_server_id(const String &p_name);
+ static int get_servers_count();
+ static String get_server_name(int p_id);
+ static PhysicsServer3D *new_default_server();
+ static PhysicsServer3D *new_server(const String &p_name);
+};
+
+VARIANT_ENUM_CAST(PhysicsServer3D::ShapeType);
+VARIANT_ENUM_CAST(PhysicsServer3D::SpaceParameter);
+VARIANT_ENUM_CAST(PhysicsServer3D::AreaParameter);
+VARIANT_ENUM_CAST(PhysicsServer3D::AreaSpaceOverrideMode);
+VARIANT_ENUM_CAST(PhysicsServer3D::BodyMode);
+VARIANT_ENUM_CAST(PhysicsServer3D::BodyParameter);
+VARIANT_ENUM_CAST(PhysicsServer3D::BodyState);
+VARIANT_ENUM_CAST(PhysicsServer3D::BodyAxis);
+VARIANT_ENUM_CAST(PhysicsServer3D::PinJointParam);
+VARIANT_ENUM_CAST(PhysicsServer3D::JointType);
+VARIANT_ENUM_CAST(PhysicsServer3D::HingeJointParam);
+VARIANT_ENUM_CAST(PhysicsServer3D::HingeJointFlag);
+VARIANT_ENUM_CAST(PhysicsServer3D::SliderJointParam);
+VARIANT_ENUM_CAST(PhysicsServer3D::ConeTwistJointParam);
+VARIANT_ENUM_CAST(PhysicsServer3D::G6DOFJointAxisParam);
+VARIANT_ENUM_CAST(PhysicsServer3D::G6DOFJointAxisFlag);
+VARIANT_ENUM_CAST(PhysicsServer3D::AreaBodyStatus);
+VARIANT_ENUM_CAST(PhysicsServer3D::ProcessInfo);
+
+#endif
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index fd65f57380..556f9cd8e3 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -29,12 +29,10 @@
/*************************************************************************/
#include "register_server_types.h"
+
#include "core/engine.h"
#include "core/project_settings.h"
-#include "arvr/arvr_interface.h"
-#include "arvr/arvr_positional_tracker.h"
-#include "arvr_server.h"
#include "audio/audio_effect.h"
#include "audio/audio_stream.h"
#include "audio/effects/audio_effect_amplify.h"
@@ -56,30 +54,34 @@
#include "audio_server.h"
#include "camera/camera_feed.h"
#include "camera_server.h"
-#include "navigation_2d_server.h"
-#include "navigation_server.h"
-#include "physics/physics_server_sw.h"
-#include "physics_2d/physics_2d_server_sw.h"
-#include "physics_2d/physics_2d_server_wrap_mt.h"
-#include "physics_2d_server.h"
-#include "physics_server.h"
-#include "visual/shader_types.h"
-#include "visual_server.h"
-
-ShaderTypes *shader_types = NULL;
-
-PhysicsServer *_createGodotPhysicsCallback() {
- return memnew(PhysicsServerSW);
+#include "display_server.h"
+#include "navigation_server_2d.h"
+#include "navigation_server_3d.h"
+#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_server_2d.h"
+#include "physics_server_3d.h"
+#include "rendering_server.h"
+#include "servers/rendering/shader_types.h"
+#include "xr/xr_interface.h"
+#include "xr/xr_positional_tracker.h"
+#include "xr_server.h"
+
+ShaderTypes *shader_types = nullptr;
+
+PhysicsServer3D *_createGodotPhysics3DCallback() {
+ return memnew(PhysicsServer3DSW);
}
-Physics2DServer *_createGodotPhysics2DCallback() {
- return Physics2DServerWrapMT::init_server<Physics2DServerSW>();
+PhysicsServer2D *_createGodotPhysics2DCallback() {
+ return PhysicsServer2DWrapMT::init_server<PhysicsServer2DSW>();
}
static bool has_server_feature_callback(const String &p_feature) {
- if (VisualServer::get_singleton()) {
- if (VisualServer::get_singleton()->has_os_feature(p_feature)) {
+ if (RenderingServer::get_singleton()) {
+ if (RenderingServer::get_singleton()->has_os_feature(p_feature)) {
return true;
}
}
@@ -95,15 +97,20 @@ void register_server_types() {
OS::get_singleton()->set_has_server_feature_callback(has_server_feature_callback);
- ClassDB::register_virtual_class<VisualServer>();
+ ClassDB::register_virtual_class<DisplayServer>();
+ ClassDB::register_virtual_class<RenderingServer>();
ClassDB::register_class<AudioServer>();
- ClassDB::register_virtual_class<PhysicsServer>();
- ClassDB::register_virtual_class<Physics2DServer>();
- ClassDB::register_class<ARVRServer>();
+ ClassDB::register_virtual_class<PhysicsServer3D>();
+ ClassDB::register_virtual_class<PhysicsServer2D>();
+ ClassDB::register_class<XRServer>();
ClassDB::register_class<CameraServer>();
- ClassDB::register_virtual_class<ARVRInterface>();
- ClassDB::register_class<ARVRPositionalTracker>();
+ ClassDB::register_virtual_class<XRInterface>();
+ ClassDB::register_class<XRPositionalTracker>();
+
+ ClassDB::add_compatibility_class("ARVRServer", "XRServer");
+ ClassDB::add_compatibility_class("ARVRInterface", "XRInterface");
+ ClassDB::add_compatibility_class("ARVRPositionalTracker", "XRPositionalTracker");
ClassDB::register_virtual_class<AudioStream>();
ClassDB::register_virtual_class<AudioStreamPlayback>();
@@ -156,30 +163,30 @@ void register_server_types() {
ClassDB::register_class<CameraFeed>();
- ClassDB::register_virtual_class<Physics2DDirectBodyState>();
- ClassDB::register_virtual_class<Physics2DDirectSpaceState>();
- ClassDB::register_virtual_class<Physics2DShapeQueryResult>();
- ClassDB::register_class<Physics2DTestMotionResult>();
- ClassDB::register_class<Physics2DShapeQueryParameters>();
+ ClassDB::register_virtual_class<PhysicsDirectBodyState2D>();
+ ClassDB::register_virtual_class<PhysicsDirectSpaceState2D>();
+ ClassDB::register_virtual_class<PhysicsShapeQueryResult2D>();
+ ClassDB::register_class<PhysicsTestMotionResult2D>();
+ ClassDB::register_class<PhysicsShapeQueryParameters2D>();
- ClassDB::register_class<PhysicsShapeQueryParameters>();
- ClassDB::register_virtual_class<PhysicsDirectBodyState>();
- ClassDB::register_virtual_class<PhysicsDirectSpaceState>();
- ClassDB::register_virtual_class<PhysicsShapeQueryResult>();
+ ClassDB::register_class<PhysicsShapeQueryParameters3D>();
+ ClassDB::register_virtual_class<PhysicsDirectBodyState3D>();
+ ClassDB::register_virtual_class<PhysicsDirectSpaceState3D>();
+ ClassDB::register_virtual_class<PhysicsShapeQueryResult3D>();
// Physics 2D
- GLOBAL_DEF(Physics2DServerManager::setting_property_name, "DEFAULT");
- ProjectSettings::get_singleton()->set_custom_property_info(Physics2DServerManager::setting_property_name, PropertyInfo(Variant::STRING, Physics2DServerManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
+ GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT");
+ ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
- Physics2DServerManager::register_server("GodotPhysics", &_createGodotPhysics2DCallback);
- Physics2DServerManager::set_default_server("GodotPhysics");
+ PhysicsServer2DManager::register_server("GodotPhysics2D", &_createGodotPhysics2DCallback);
+ PhysicsServer2DManager::set_default_server("GodotPhysics2D");
// Physics 3D
- GLOBAL_DEF(PhysicsServerManager::setting_property_name, "DEFAULT");
- ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServerManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServerManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
+ GLOBAL_DEF(PhysicsServer3DManager::setting_property_name, "DEFAULT");
+ ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer3DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
- PhysicsServerManager::register_server("GodotPhysics", &_createGodotPhysicsCallback);
- PhysicsServerManager::set_default_server("GodotPhysics");
+ PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback);
+ PhysicsServer3DManager::set_default_server("GodotPhysics3D");
}
void unregister_server_types() {
@@ -189,12 +196,12 @@ void unregister_server_types() {
void register_server_singletons() {
- Engine::get_singleton()->add_singleton(Engine::Singleton("VisualServer", VisualServer::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer", PhysicsServer::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("Physics2DServer", Physics2DServer::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer", NavigationServer::get_singleton_mut()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("Navigation2DServer", Navigation2DServer::get_singleton_mut()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("ARVRServer", ARVRServer::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton()));
}
diff --git a/servers/rendering/SCsub b/servers/rendering/SCsub
new file mode 100644
index 0000000000..5ea0d40486
--- /dev/null
+++ b/servers/rendering/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
+
+SConscript("rasterizer_rd/SCsub")
diff --git a/servers/rendering/rasterizer.cpp b/servers/rendering/rasterizer.cpp
new file mode 100644
index 0000000000..f62e0a43a6
--- /dev/null
+++ b/servers/rendering/rasterizer.cpp
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* rasterizer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer.h"
+
+#include "core/os/os.h"
+#include "core/print_string.h"
+
+Rasterizer *(*Rasterizer::_create_func)() = nullptr;
+
+void RasterizerScene::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) {
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependency_changed(p_aabb, p_dependencies);
+ }
+}
+void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) {
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependency_deleted(p_deleted);
+ }
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependencies.erase(this);
+ }
+
+ instances.clear();
+}
+
+RasterizerScene::InstanceDependency::~InstanceDependency() {
+#ifdef DEBUG_ENABLED
+ if (instances.size()) {
+ WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing.");
+ for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
+ E->key()->dependencies.erase(this);
+ }
+ }
+#endif
+}
+
+Rasterizer *Rasterizer::create() {
+
+ return _create_func();
+}
+
+RasterizerCanvas *RasterizerCanvas::singleton = nullptr;
+
+RasterizerStorage *RasterizerStorage::base_singleton = nullptr;
+
+RasterizerStorage::RasterizerStorage() {
+
+ base_singleton = this;
+}
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
new file mode 100644
index 0000000000..5da9c2aeea
--- /dev/null
+++ b/servers/rendering/rasterizer.h
@@ -0,0 +1,1337 @@
+/*************************************************************************/
+/* rasterizer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_H
+#define RASTERIZER_H
+
+#include "core/math/camera_matrix.h"
+#include "servers/rendering_server.h"
+
+#include "core/pair.h"
+#include "core/self_list.h"
+
+class RasterizerScene {
+
+public:
+ /* SHADOW ATLAS API */
+
+ virtual RID shadow_atlas_create() = 0;
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size) = 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;
+
+ virtual void directional_shadow_atlas_set_size(int p_size) = 0;
+ virtual int get_directional_light_shadow_size(RID p_light_intance) = 0;
+ virtual void set_directional_shadow_count(int p_count) = 0;
+
+ /* SKY API */
+
+ virtual RID sky_create() = 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;
+
+ /* ENVIRONMENT API */
+
+ virtual RID environment_create() = 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;
+ virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0;
+ virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0;
+ virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
+ virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
+ virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
+ virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0;
+// FIXME: Disabled during Vulkan refactoring, should be ported.
+#if 0
+ virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
+#endif
+
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, 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) = 0;
+ virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
+ virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0;
+
+ virtual void 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) = 0;
+ virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0;
+
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0;
+
+ virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) = 0;
+
+ virtual void 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) = 0;
+
+ virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
+
+ virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0;
+ virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;
+ virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0;
+
+ virtual bool is_environment(RID p_env) const = 0;
+ 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 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;
+
+ virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
+ virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
+
+ virtual void shadows_quality_set(RS::ShadowQuality p_quality) = 0;
+ virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0;
+
+ struct InstanceBase;
+
+ struct InstanceDependency {
+ void instance_notify_changed(bool p_aabb, bool p_dependencies);
+ void instance_notify_deleted(RID p_deleted);
+
+ ~InstanceDependency();
+
+ private:
+ friend struct InstanceBase;
+ Map<InstanceBase *, uint32_t> instances;
+ };
+
+ struct InstanceBase {
+ RS::InstanceType base_type;
+ RID base;
+
+ RID skeleton;
+ RID material_override;
+
+ RID instance_data;
+
+ Transform transform;
+
+ int depth_layer;
+ uint32_t layer_mask;
+ uint32_t instance_version;
+
+ //RID sampled_light;
+
+ Vector<RID> materials;
+ Vector<RID> light_instances;
+ Vector<RID> reflection_probe_instances;
+ Vector<RID> gi_probe_instances;
+
+ Vector<float> blend_values;
+
+ RS::ShadowCastingSetting cast_shadows;
+
+ //fit in 32 bits
+ bool mirror : 8;
+ bool receive_shadows : 8;
+ bool visible : 8;
+ bool baked_light : 2; //this flag is only to know if it actually did use baked light
+ bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light
+ bool redraw_if_visible : 4;
+
+ float depth; //used for sorting
+
+ SelfList<InstanceBase> dependency_item;
+
+ InstanceBase *lightmap_capture;
+ RID lightmap;
+ Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
+
+ AABB aabb;
+ AABB transformed_aabb;
+
+ virtual void dependency_deleted(RID p_dependency) = 0;
+ virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0;
+
+ Set<InstanceDependency *> dependencies;
+
+ void instance_increase_version() {
+ instance_version++;
+ }
+
+ void update_dependency(InstanceDependency *p_dependency) {
+ dependencies.insert(p_dependency);
+ p_dependency->instances[this] = instance_version;
+ }
+
+ void clean_up_dependencies() {
+ List<Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *>> to_clean_up;
+ for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
+ InstanceDependency *dep = E->get();
+ Map<InstanceBase *, uint32_t>::Element *F = dep->instances.find(this);
+ ERR_CONTINUE(!F);
+ if (F->get() != instance_version) {
+ Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> p;
+ p.first = dep;
+ p.second = F;
+ to_clean_up.push_back(p);
+ }
+ }
+
+ while (to_clean_up.size()) {
+ to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second);
+ to_clean_up.pop_front();
+ }
+ }
+
+ void clear_dependencies() {
+ for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
+ InstanceDependency *dep = E->get();
+ dep->instances.erase(this);
+ }
+ dependencies.clear();
+ }
+
+ InstanceBase() :
+ dependency_item(this) {
+
+ base_type = RS::INSTANCE_NONE;
+ cast_shadows = RS::SHADOW_CASTING_SETTING_ON;
+ receive_shadows = true;
+ visible = true;
+ depth_layer = 0;
+ layer_mask = 1;
+ instance_version = 0;
+ baked_light = false;
+ dynamic_gi = false;
+ redraw_if_visible = false;
+ lightmap_capture = nullptr;
+ }
+
+ virtual ~InstanceBase() {
+ clear_dependencies();
+ }
+ };
+
+ virtual RID light_instance_create(RID p_light) = 0;
+ virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0;
+ virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0;
+ virtual void light_instance_mark_visible(RID p_light_instance) = 0;
+ virtual bool light_instances_can_render_shadow_cube() const {
+ return true;
+ }
+
+ virtual RID reflection_atlas_create() = 0;
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
+
+ virtual RID reflection_probe_instance_create(RID p_probe) = 0;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
+ virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
+
+ virtual RID decal_instance_create(RID p_decal) = 0;
+ virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0;
+
+ virtual RID gi_probe_instance_create(RID p_gi_probe) = 0;
+ virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;
+ virtual bool gi_probe_needs_update(RID p_probe) const = 0;
+ virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0;
+
+ virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
+
+ virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0;
+ virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
+
+ virtual void set_scene_pass(uint64_t p_pass) = 0;
+ virtual void set_time(double p_time, double p_step) = 0;
+ virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
+
+ 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) = 0;
+
+ virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0;
+ virtual bool screen_space_roughness_limiter_is_active() const = 0;
+
+ virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0;
+ virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0;
+
+ virtual bool free(RID p_rid) = 0;
+
+ virtual void update() = 0;
+ virtual ~RasterizerScene() {}
+};
+
+class RasterizerStorage {
+
+ Color default_clear_color;
+
+public:
+ /* 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(const Vector<Ref<Image>> &p_slices) = 0; //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_proxy_create(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;
+ virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0;
+ 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() = 0;
+ virtual RID texture_3d_placeholder_create() = 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;
+ virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const = 0;
+
+ virtual void texture_replace(RID p_texture, RID p_by_texture) = 0;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;
+// FIXME: Disabled during Vulkan refactoring, should be ported.
+#if 0
+ virtual void texture_bind(RID p_texture, uint32_t p_texture_no) = 0;
+#endif
+
+ virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
+ virtual String texture_get_path(RID p_texture) const = 0;
+
+ virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0;
+ virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) = 0;
+ virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0;
+
+ virtual void texture_debug_usage(List<RS::TextureInfo> *r_info) = 0;
+
+ virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
+
+ virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
+
+ virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
+ virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
+
+ /* SHADER API */
+
+ virtual RID shader_create() = 0;
+
+ virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
+ virtual String shader_get_code(RID p_shader) const = 0;
+ virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
+
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
+ virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0;
+
+ /* COMMON MATERIAL API */
+
+ virtual RID material_create() = 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;
+
+ virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
+ virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
+
+ virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0;
+
+ virtual bool material_is_animated(RID p_material) = 0;
+ virtual bool material_casts_shadows(RID p_material) = 0;
+
+ virtual void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
+
+ /* MESH API */
+
+ virtual RID mesh_create() = 0;
+
+ /// Returns stride
+ virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) = 0;
+
+ virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
+
+ virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0;
+ virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
+
+ virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+
+ virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
+ virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
+
+ virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0;
+
+ virtual int mesh_get_surface_count(RID p_mesh) const = 0;
+
+ virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
+ virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
+
+ virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
+
+ virtual void mesh_clear(RID p_mesh) = 0;
+
+ /* MULTIMESH API */
+
+ virtual RID multimesh_create() = 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 int multimesh_get_instance_count(RID p_multimesh) const = 0;
+
+ virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
+ virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0;
+ virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
+ virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
+
+ virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
+
+ virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
+ virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
+ virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
+ virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
+
+ virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
+ virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
+
+ virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
+ virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
+
+ virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
+
+ /* IMMEDIATE API */
+
+ virtual RID immediate_create() = 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;
+ virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0;
+ virtual void immediate_color(RID p_immediate, const Color &p_color) = 0;
+ virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0;
+ virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0;
+ virtual void immediate_end(RID p_immediate) = 0;
+ virtual void immediate_clear(RID p_immediate) = 0;
+ virtual void immediate_set_material(RID p_immediate, RID p_material) = 0;
+ virtual RID immediate_get_material(RID p_immediate) const = 0;
+ virtual AABB immediate_get_aabb(RID p_immediate) const = 0;
+
+ /* SKELETON API */
+
+ virtual RID skeleton_create() = 0;
+ virtual void skeleton_allocate(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;
+ virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
+ virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
+ virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
+
+ /* Light API */
+
+ virtual RID light_create(RS::LightType p_type) = 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 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;
+ virtual void light_set_shadow(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0;
+ virtual void light_set_projector(RID p_light, RID p_texture) = 0;
+ virtual void light_set_negative(RID p_light, bool p_enable) = 0;
+ virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
+ virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_use_gi(RID p_light, bool p_enable) = 0;
+
+ virtual void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) = 0;
+
+ virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0;
+ virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
+ virtual bool light_directional_get_blend_splits(RID p_light) const = 0;
+ virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
+ virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0;
+
+ virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0;
+ virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0;
+
+ virtual bool light_has_shadow(RID p_light) const = 0;
+
+ virtual RS::LightType light_get_type(RID p_light) const = 0;
+ virtual AABB light_get_aabb(RID p_light) const = 0;
+ virtual float light_get_param(RID p_light, RS::LightParam p_param) = 0;
+ virtual Color light_get_color(RID p_light) = 0;
+ virtual bool light_get_use_gi(RID p_light) = 0;
+ virtual uint64_t light_get_version(RID p_light) const = 0;
+
+ /* PROBE API */
+
+ virtual RID reflection_probe_create() = 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;
+ virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0;
+ virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) = 0;
+ virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) = 0;
+ virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) = 0;
+ virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0;
+ virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0;
+ virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0;
+ virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0;
+ virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
+ virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
+ virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
+
+ virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0;
+ virtual RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0;
+ virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const = 0;
+ virtual Vector3 reflection_probe_get_extents(RID p_probe) const = 0;
+ virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0;
+ virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0;
+ virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
+
+ virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
+ virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
+
+ /* DECAL API */
+
+ virtual RID decal_create() = 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;
+ virtual void decal_set_albedo_mix(RID p_decal, float p_mix) = 0;
+ virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) = 0;
+ virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) = 0;
+ virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) = 0;
+ virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0;
+ virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0;
+
+ virtual AABB decal_get_aabb(RID p_decal) const = 0;
+
+ /* GI PROBE API */
+
+ 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 AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
+ virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
+ virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
+ virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
+ virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0;
+
+ virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
+ virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
+ virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0;
+ virtual float gi_probe_get_ao(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0;
+ virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
+ virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
+ virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
+ virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
+ virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
+
+ virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
+
+ /* LIGHTMAP CAPTURE */
+
+ struct LightmapCaptureOctree {
+
+ enum {
+ CHILD_EMPTY = 0xFFFFFFFF
+ };
+
+ uint16_t light[6][3]; //anisotropic light
+ float alpha;
+ uint32_t children[8];
+ };
+
+ virtual RID lightmap_capture_create() = 0;
+ virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0;
+ virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) = 0;
+ virtual Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0;
+ virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0;
+ virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
+ virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
+ virtual const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const = 0;
+
+ /* PARTICLES */
+
+ virtual RID particles_create() = 0;
+
+ virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
+ virtual bool particles_get_emitting(RID p_particles) = 0;
+
+ virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
+ virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
+ virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
+ virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
+ virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
+ virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
+ virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
+ virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
+ 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_fractional_delta(RID p_particles, bool p_enable) = 0;
+ virtual void particles_restart(RID p_particles) = 0;
+
+ virtual bool particles_is_inactive(RID p_particles) const = 0;
+
+ virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) = 0;
+
+ virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
+ virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
+
+ virtual void particles_request_process(RID p_particles) = 0;
+ virtual AABB particles_get_current_aabb(RID p_particles) = 0;
+ virtual AABB particles_get_aabb(RID p_particles) const = 0;
+
+ virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0;
+
+ 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;
+
+ /* RENDER TARGET */
+
+ enum RenderTargetFlags {
+ RENDER_TARGET_TRANSPARENT,
+ RENDER_TARGET_DIRECT_TO_SCREEN,
+ RENDER_TARGET_FLAG_MAX
+ };
+
+ virtual RID render_target_create() = 0;
+ virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0;
+ virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0;
+ virtual RID render_target_get_texture(RID p_render_target) = 0;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
+ virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
+ virtual bool render_target_was_used(RID p_render_target) = 0;
+ virtual void render_target_set_as_unused(RID p_render_target) = 0;
+
+ virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0;
+ virtual bool render_target_is_clear_requested(RID p_render_target) = 0;
+ virtual Color render_target_get_clear_request_color(RID p_render_target) = 0;
+ virtual void render_target_disable_clear_request(RID p_render_target) = 0;
+ virtual void render_target_do_clear_request(RID p_render_target) = 0;
+
+ virtual RS::InstanceType get_base_type(RID p_rid) const = 0;
+ virtual bool free(RID p_rid) = 0;
+
+ virtual bool has_os_feature(const String &p_feature) const = 0;
+
+ virtual void update_dirty_resources() = 0;
+
+ virtual void set_debug_generate_wireframes(bool p_generate) = 0;
+
+ virtual void render_info_begin_capture() = 0;
+ 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 String get_video_adapter_name() const = 0;
+ virtual String get_video_adapter_vendor() const = 0;
+
+ static RasterizerStorage *base_singleton;
+
+ void set_default_clear_color(const Color &p_color) {
+ default_clear_color = p_color;
+ }
+
+ Color get_default_clear_color() const {
+ return default_clear_color;
+ }
+#define TIMESTAMP_BEGIN() \
+ { \
+ if (RSG::storage->capturing_timestamps) RSG::storage->capture_timestamps_begin(); \
+ }
+
+#define RENDER_TIMESTAMP(m_text) \
+ { \
+ if (RSG::storage->capturing_timestamps) RSG::storage->capture_timestamp(m_text); \
+ }
+
+ bool capturing_timestamps = false;
+
+ virtual void capture_timestamps_begin() = 0;
+ virtual void capture_timestamp(const String &p_name) = 0;
+ virtual uint32_t get_captured_timestamps_count() const = 0;
+ virtual uint64_t get_captured_timestamps_frame() const = 0;
+ virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0;
+ virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0;
+ virtual String get_captured_timestamp_name(uint32_t p_index) const = 0;
+
+ RasterizerStorage();
+ virtual ~RasterizerStorage() {}
+};
+
+class RasterizerCanvas {
+public:
+ static RasterizerCanvas *singleton;
+
+ enum CanvasRectFlags {
+
+ CANVAS_RECT_REGION = 1,
+ CANVAS_RECT_TILE = 2,
+ CANVAS_RECT_FLIP_H = 4,
+ CANVAS_RECT_FLIP_V = 8,
+ CANVAS_RECT_TRANSPOSE = 16,
+ CANVAS_RECT_CLIP_UV = 32
+ };
+
+ struct Light {
+
+ bool enabled;
+ Color color;
+ Transform2D xform;
+ float height;
+ float energy;
+ float scale;
+ int z_min;
+ int z_max;
+ int layer_min;
+ int layer_max;
+ int item_mask;
+ int item_shadow_mask;
+ RS::CanvasLightMode mode;
+ RID texture;
+ Vector2 texture_offset;
+ RID canvas;
+ bool use_shadow;
+ int shadow_buffer_size;
+ RS::CanvasLightShadowFilter shadow_filter;
+ Color shadow_color;
+ float shadow_smooth;
+
+ //void *texture_cache; // implementation dependent
+ Rect2 rect_cache;
+ Transform2D xform_cache;
+ float radius_cache; //used for shadow far plane
+ //CameraMatrix shadow_matrix_cache;
+
+ Transform2D light_shader_xform;
+ //Vector2 light_shader_pos;
+
+ Light *shadows_next_ptr;
+ Light *filter_next_ptr;
+ Light *next_ptr;
+ Light *mask_next_ptr;
+
+ RID light_internal;
+ uint64_t version;
+
+ int32_t render_index_cache;
+
+ Light() {
+ version = 0;
+ enabled = true;
+ color = Color(1, 1, 1);
+ shadow_color = Color(0, 0, 0, 0);
+ height = 0;
+ z_min = -1024;
+ z_max = 1024;
+ layer_min = 0;
+ layer_max = 0;
+ item_mask = 1;
+ scale = 1.0;
+ energy = 1.0;
+ item_shadow_mask = -1;
+ mode = RS::CANVAS_LIGHT_MODE_ADD;
+ // texture_cache = nullptr;
+ next_ptr = nullptr;
+ mask_next_ptr = nullptr;
+ filter_next_ptr = nullptr;
+ use_shadow = false;
+ shadow_buffer_size = 2048;
+ shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE;
+ shadow_smooth = 0.0;
+ render_index_cache = -1;
+ }
+ };
+
+ typedef uint64_t TextureBindingID;
+
+ virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) = 0;
+ virtual void free_texture_binding(TextureBindingID p_binding) = 0;
+
+ //easier wrap to avoid mistakes
+
+ struct Item;
+
+ struct TextureBinding {
+
+ TextureBindingID binding_id;
+
+ _FORCE_INLINE_ void create(RS::CanvasItemTextureFilter p_item_filter, RS::CanvasItemTextureRepeat p_item_repeat, RID p_texture, RID p_normalmap, RID p_specular, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
+ if (p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
+ p_filter = p_item_filter;
+ }
+ if (p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
+ p_repeat = p_item_repeat;
+ }
+ if (p_texture != RID() || p_normalmap != RID() || p_specular != RID() || p_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT || p_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT || p_multimesh.is_valid()) {
+ ERR_FAIL_COND(binding_id != 0);
+ binding_id = singleton->request_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh);
+ }
+ }
+
+ _FORCE_INLINE_ TextureBinding() { binding_id = 0; }
+ _FORCE_INLINE_ ~TextureBinding() {
+ if (binding_id) singleton->free_texture_binding(binding_id);
+ }
+ };
+
+ typedef uint64_t PolygonID;
+ virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0;
+ virtual void free_polygon(PolygonID p_polygon) = 0;
+
+ //also easier to wrap to avoid mistakes
+ struct Polygon {
+
+ PolygonID polygon_id;
+ Rect2 rect_cache;
+
+ _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) {
+ ERR_FAIL_COND(polygon_id != 0);
+ {
+ uint32_t pc = p_points.size();
+ const Vector2 *v2 = p_points.ptr();
+ rect_cache.position = *v2;
+ for (uint32_t i = 1; i < pc; i++) {
+ rect_cache.expand_to(v2[i]);
+ }
+ }
+ polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights);
+ }
+
+ _FORCE_INLINE_ Polygon() { polygon_id = 0; }
+ _FORCE_INLINE_ ~Polygon() {
+ if (polygon_id) singleton->free_polygon(polygon_id);
+ }
+ };
+
+ //item
+
+ struct Item {
+
+ //commands are allocated in blocks of 4k to improve performance
+ //and cache coherence.
+ //blocks always grow but never shrink.
+
+ struct CommandBlock {
+ enum {
+ MAX_SIZE = 4096
+ };
+ uint32_t usage;
+ uint8_t *memory;
+ };
+
+ struct Command {
+
+ enum Type {
+
+ TYPE_RECT,
+ TYPE_NINEPATCH,
+ TYPE_POLYGON,
+ TYPE_PRIMITIVE,
+ TYPE_MESH,
+ TYPE_MULTIMESH,
+ TYPE_PARTICLES,
+ TYPE_TRANSFORM,
+ TYPE_CLIP_IGNORE,
+ };
+
+ Command *next;
+ Type type;
+ virtual ~Command() {}
+ };
+
+ struct CommandRect : public Command {
+
+ Rect2 rect;
+ Color modulate;
+ Rect2 source;
+ uint8_t flags;
+ Color specular_shininess;
+
+ TextureBinding texture_binding;
+
+ CommandRect() {
+ flags = 0;
+ type = TYPE_RECT;
+ }
+ };
+
+ struct CommandNinePatch : public Command {
+
+ Rect2 rect;
+ Rect2 source;
+ float margin[4];
+ bool draw_center;
+ Color color;
+ RS::NinePatchAxisMode axis_x;
+ RS::NinePatchAxisMode axis_y;
+ Color specular_shininess;
+ TextureBinding texture_binding;
+ CommandNinePatch() {
+ draw_center = true;
+ type = TYPE_NINEPATCH;
+ }
+ };
+
+ struct CommandPolygon : public Command {
+
+ RS::PrimitiveType primitive;
+ Polygon polygon;
+ Color specular_shininess;
+ TextureBinding texture_binding;
+ CommandPolygon() {
+ type = TYPE_POLYGON;
+ }
+ };
+
+ struct CommandPrimitive : public Command {
+
+ uint32_t point_count;
+ Vector2 points[4];
+ Vector2 uvs[4];
+ Color colors[4];
+ Color specular_shininess;
+ TextureBinding texture_binding;
+ CommandPrimitive() {
+ type = TYPE_PRIMITIVE;
+ }
+ };
+
+ struct CommandMesh : public Command {
+
+ RID mesh;
+ Transform2D transform;
+ Color modulate;
+ Color specular_shininess;
+ TextureBinding texture_binding;
+ CommandMesh() { type = TYPE_MESH; }
+ };
+
+ struct CommandMultiMesh : public Command {
+
+ RID multimesh;
+ Color specular_shininess;
+ TextureBinding texture_binding;
+ CommandMultiMesh() { type = TYPE_MULTIMESH; }
+ };
+
+ struct CommandParticles : public Command {
+
+ RID particles;
+ Color specular_shininess;
+ TextureBinding texture_binding;
+ CommandParticles() { type = TYPE_PARTICLES; }
+ };
+
+ struct CommandTransform : public Command {
+
+ Transform2D xform;
+ CommandTransform() { type = TYPE_TRANSFORM; }
+ };
+
+ struct CommandClipIgnore : public Command {
+
+ bool ignore;
+ CommandClipIgnore() {
+ type = TYPE_CLIP_IGNORE;
+ ignore = false;
+ }
+ };
+
+ struct ViewportRender {
+ RenderingServer *owner;
+ void *udata;
+ Rect2 rect;
+ };
+
+ Transform2D xform;
+ bool clip;
+ bool visible;
+ bool behind;
+ bool update_when_visible;
+ //RS::MaterialBlendMode blend_mode;
+ int light_mask;
+ int z_final;
+
+ mutable bool custom_rect;
+ mutable bool rect_dirty;
+ mutable Rect2 rect;
+ RID material;
+ RID skeleton;
+
+ Item *next;
+
+ struct CopyBackBuffer {
+ Rect2 rect;
+ Rect2 screen_rect;
+ bool full;
+ };
+ CopyBackBuffer *copy_back_buffer;
+
+ Color final_modulate;
+ Transform2D final_transform;
+ Rect2 final_clip_rect;
+ Item *final_clip_owner;
+ Item *material_owner;
+ ViewportRender *vp_render;
+ bool distance_field;
+ bool light_masked;
+
+ Rect2 global_rect_cache;
+
+ const Rect2 &get_rect() const {
+ if (custom_rect || (!rect_dirty && !update_when_visible))
+ return rect;
+
+ //must update rect
+
+ if (commands == nullptr) {
+
+ rect = Rect2();
+ rect_dirty = false;
+ return rect;
+ }
+
+ Transform2D xf;
+ bool found_xform = false;
+ bool first = true;
+
+ const Item::Command *c = commands;
+
+ while (c) {
+
+ Rect2 r;
+
+ switch (c->type) {
+ case Item::Command::TYPE_RECT: {
+
+ const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c);
+ r = crect->rect;
+
+ } break;
+ case Item::Command::TYPE_NINEPATCH: {
+
+ const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c);
+ r = style->rect;
+ } break;
+
+ case Item::Command::TYPE_POLYGON: {
+
+ const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
+ r = polygon->polygon.rect_cache;
+ } break;
+ case Item::Command::TYPE_PRIMITIVE: {
+
+ const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
+ for (uint32_t j = 0; j < primitive->point_count; j++) {
+ if (j == 0) {
+ r.position = primitive->points[0];
+ } else {
+ r.expand_to(primitive->points[j]);
+ }
+ }
+ } break;
+ case Item::Command::TYPE_MESH: {
+
+ const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
+ AABB aabb = RasterizerStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID());
+
+ r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
+
+ } break;
+ case Item::Command::TYPE_MULTIMESH: {
+
+ const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
+ AABB aabb = RasterizerStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh);
+
+ r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
+
+ } break;
+ case Item::Command::TYPE_PARTICLES: {
+
+ const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
+ if (particles_cmd->particles.is_valid()) {
+ AABB aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles);
+ r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
+ }
+
+ } break;
+ case Item::Command::TYPE_TRANSFORM: {
+
+ const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
+ xf = transform->xform;
+ found_xform = true;
+ [[fallthrough]];
+ }
+ default: {
+ c = c->next;
+ continue;
+ }
+ }
+
+ if (found_xform) {
+ r = xf.xform(r);
+ found_xform = false;
+ }
+
+ if (first) {
+ rect = r;
+ first = false;
+ } else {
+ rect = rect.merge(r);
+ }
+ c = c->next;
+ }
+
+ rect_dirty = false;
+ return rect;
+ }
+
+ Command *commands;
+ Command *last_command;
+ Vector<CommandBlock> blocks;
+ uint32_t current_block;
+
+ template <class T>
+ T *alloc_command() {
+ T *command;
+ if (commands == nullptr) {
+ // As the most common use case of canvas items is to
+ // use only one command, the first is done with it's
+ // own allocation. The rest of them use blocks.
+ command = memnew(T);
+ command->next = nullptr;
+ commands = command;
+ last_command = command;
+ } else {
+ //Subsequent commands go into a block.
+
+ while (true) {
+ if (unlikely(current_block == (uint32_t)blocks.size())) {
+ // If we need more blocks, we allocate them
+ // (they won't be freed until this CanvasItem is
+ // deleted, though).
+ CommandBlock cb;
+ cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE);
+ cb.usage = 0;
+ blocks.push_back(cb);
+ }
+
+ CommandBlock *c = &blocks.write[current_block];
+ size_t space_left = CommandBlock::MAX_SIZE - c->usage;
+ if (space_left < sizeof(T)) {
+ current_block++;
+ continue;
+ }
+
+ //allocate block and add to the linked list
+ void *memory = c->memory + c->usage;
+ command = memnew_placement(memory, T);
+ command->next = nullptr;
+ last_command->next = command;
+ last_command = command;
+ c->usage += sizeof(T);
+ break;
+ }
+ }
+
+ rect_dirty = true;
+ return command;
+ }
+
+ struct CustomData {
+
+ virtual ~CustomData() {}
+ };
+
+ mutable CustomData *custom_data; //implementation dependent
+
+ void clear() {
+ Command *c = commands;
+ while (c) {
+ Command *n = c->next;
+ if (c == commands) {
+ memdelete(commands);
+ commands = nullptr;
+ } else {
+ c->~Command();
+ }
+ c = n;
+ }
+ {
+ uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size());
+ CommandBlock *blockptr = blocks.ptrw();
+ for (uint32_t i = 0; i < cbc; i++) {
+ blockptr[i].usage = 0;
+ }
+ }
+
+ last_command = nullptr;
+ commands = nullptr;
+ current_block = 0;
+ clip = false;
+ rect_dirty = true;
+ final_clip_owner = nullptr;
+ material_owner = nullptr;
+ light_masked = false;
+ }
+ Item() {
+ commands = nullptr;
+ last_command = nullptr;
+ current_block = 0;
+ light_mask = 1;
+ vp_render = nullptr;
+ next = nullptr;
+ final_clip_owner = nullptr;
+ clip = false;
+ final_modulate = Color(1, 1, 1, 1);
+ visible = true;
+ rect_dirty = true;
+ custom_rect = false;
+ behind = false;
+ material_owner = nullptr;
+ copy_back_buffer = nullptr;
+ distance_field = false;
+ light_masked = false;
+ update_when_visible = false;
+ z_final = 0;
+ custom_data = nullptr;
+ }
+ virtual ~Item() {
+ clear();
+ for (int i = 0; i < blocks.size(); i++) {
+ memfree(blocks[i].memory);
+ }
+ if (copy_back_buffer) memdelete(copy_back_buffer);
+ if (custom_data) {
+ memdelete(custom_data);
+ }
+ }
+ };
+
+ virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0;
+ virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
+
+ struct LightOccluderInstance {
+
+ bool enabled;
+ RID canvas;
+ RID polygon;
+ RID occluder;
+ Rect2 aabb_cache;
+ Transform2D xform;
+ Transform2D xform_cache;
+ int light_mask;
+ RS::CanvasOccluderPolygonCullMode cull_cache;
+
+ LightOccluderInstance *next;
+
+ LightOccluderInstance() {
+ enabled = true;
+ next = nullptr;
+ light_mask = 1;
+ cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+ }
+ };
+
+ virtual RID light_create() = 0;
+ virtual void light_set_texture(RID p_rid, RID p_texture) = 0;
+ virtual void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) = 0;
+ virtual void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0;
+
+ virtual RID occluder_polygon_create() = 0;
+ virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) = 0;
+ virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0;
+
+ virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0;
+
+ virtual bool free(RID p_rid) = 0;
+ virtual void update() = 0;
+
+ RasterizerCanvas() { singleton = this; }
+ virtual ~RasterizerCanvas() {}
+};
+
+class Rasterizer {
+protected:
+ static Rasterizer *(*_create_func)();
+
+public:
+ static Rasterizer *create();
+
+ virtual RasterizerStorage *get_storage() = 0;
+ virtual RasterizerCanvas *get_canvas() = 0;
+ virtual RasterizerScene *get_scene() = 0;
+
+ virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0;
+
+ virtual void initialize() = 0;
+ virtual void begin_frame(double frame_step) = 0;
+
+ struct BlitToScreen {
+ RID render_target;
+ Rect2i rect;
+ //lens distorted parameters for VR should go here
+ };
+
+ virtual void prepare_for_blitting_render_targets() = 0;
+ virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
+
+ virtual void end_frame(bool p_swap_buffers) = 0;
+ virtual void finalize() = 0;
+
+ virtual bool is_low_end() const = 0;
+
+ virtual ~Rasterizer() {}
+};
+
+#endif // RASTERIZER_H
diff --git a/servers/rendering/rasterizer_rd/SCsub b/servers/rendering/rasterizer_rd/SCsub
new file mode 100644
index 0000000000..6a2e682c67
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
+
+SConscript("shaders/SCsub")
diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.cpp b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp
new file mode 100644
index 0000000000..f75308a975
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/light_cluster_builder.cpp
@@ -0,0 +1,256 @@
+/*************************************************************************/
+/* light_cluster_builder.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "light_cluster_builder.h"
+
+void LightClusterBuilder::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection) {
+ view_xform = p_view_transform;
+ projection = p_cam_projection;
+ z_near = -projection.get_z_near();
+ z_far = -projection.get_z_far();
+
+ //reset counts
+ light_count = 0;
+ refprobe_count = 0;
+ decal_count = 0;
+ item_count = 0;
+ sort_id_count = 0;
+}
+
+void LightClusterBuilder::bake_cluster() {
+
+ float slice_depth = (z_near - z_far) / depth;
+
+ uint8_t *cluster_dataw = cluster_data.ptrw();
+ Cell *cluster_data_ptr = (Cell *)cluster_dataw;
+ //clear the cluster
+ zeromem(cluster_data_ptr, (width * height * depth * sizeof(Cell)));
+
+ /* Step 1, create cell positions and count them */
+
+ for (uint32_t i = 0; i < item_count; i++) {
+
+ const Item &item = items[i];
+
+ int from_slice = Math::floor((z_near - (item.aabb.position.z + item.aabb.size.z)) / slice_depth);
+ int to_slice = Math::floor((z_near - item.aabb.position.z) / slice_depth);
+
+ if (from_slice >= (int)depth || to_slice < 0) {
+ continue; //sorry no go
+ }
+
+ from_slice = MAX(0, from_slice);
+ to_slice = MIN((int)depth - 1, to_slice);
+
+ for (int j = from_slice; j <= to_slice; j++) {
+
+ Vector3 min = item.aabb.position;
+ Vector3 max = item.aabb.position + item.aabb.size;
+
+ float limit_near = MIN((z_near - slice_depth * j), max.z);
+ float limit_far = MAX((z_near - slice_depth * (j + 1)), min.z);
+
+ max.z = limit_near;
+ min.z = limit_near;
+
+ Vector3 proj_min = projection.xform(min);
+ Vector3 proj_max = projection.xform(max);
+
+ int near_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width));
+ int near_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height));
+ int near_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width));
+ int near_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height));
+
+ max.z = limit_far;
+ min.z = limit_far;
+
+ proj_min = projection.xform(min);
+ proj_max = projection.xform(max);
+
+ int far_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width));
+ int far_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height));
+ int far_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width));
+ int far_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height));
+
+ //print_line(itos(j) + " near - " + Vector2i(near_from_x, near_from_y) + " -> " + Vector2i(near_to_x, near_to_y));
+ //print_line(itos(j) + " far - " + Vector2i(far_from_x, far_from_y) + " -> " + Vector2i(far_to_x, far_to_y));
+
+ int from_x = MIN(near_from_x, far_from_x);
+ int from_y = MIN(near_from_y, far_from_y);
+ int to_x = MAX(near_to_x, far_to_x);
+ int to_y = MAX(near_to_y, far_to_y);
+
+ if (from_x >= (int)width || to_x < 0 || from_y >= (int)height || to_y < 0) {
+ continue;
+ }
+
+ int sx = MAX(0, from_x);
+ int sy = MAX(0, from_y);
+ int dx = MIN((int)width - 1, to_x);
+ int dy = MIN((int)height - 1, to_y);
+
+ //print_line(itos(j) + " - " + Vector2i(sx, sy) + " -> " + Vector2i(dx, dy));
+
+ for (int x = sx; x <= dx; x++) {
+ for (int y = sy; y <= dy; y++) {
+ uint32_t offset = j * (width * height) + y * width + x;
+
+ if (unlikely(sort_id_count == sort_id_max)) {
+ sort_id_max = nearest_power_of_2_templated(sort_id_max + 1);
+ sort_ids = (SortID *)memrealloc(sort_ids, sizeof(SortID) * sort_id_max);
+ if (ids.size()) {
+
+ ids.resize(sort_id_max);
+ RD::get_singleton()->free(items_buffer);
+ items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * sort_id_max);
+ }
+ }
+
+ sort_ids[sort_id_count].cell_index = offset;
+ sort_ids[sort_id_count].item_index = item.index;
+ sort_ids[sort_id_count].item_type = item.type;
+
+ sort_id_count++;
+
+ //for now, only count
+ cluster_data_ptr[offset].item_pointers[item.type]++;
+ //print_line("at offset " + itos(offset) + " value: " + itos(cluster_data_ptr[offset].item_pointers[item.type]));
+ }
+ }
+ }
+ }
+
+ /* Step 2, Assign pointers (and reset counters) */
+
+ uint32_t offset = 0;
+ for (uint32_t i = 0; i < (width * height * depth); i++) {
+ for (int j = 0; j < ITEM_TYPE_MAX; j++) {
+ uint32_t count = cluster_data_ptr[i].item_pointers[j]; //save count
+ cluster_data_ptr[i].item_pointers[j] = offset; //replace count by pointer
+ offset += count; //increase offset by count;
+ }
+ }
+
+ //print_line("offset: " + itos(offset));
+ /* Step 3, Place item lists */
+
+ uint32_t *ids_ptr = ids.ptrw();
+
+ for (uint32_t i = 0; i < sort_id_count; i++) {
+ const SortID &id = sort_ids[i];
+ Cell &cell = cluster_data_ptr[id.cell_index];
+ uint32_t pointer = cell.item_pointers[id.item_type] & POINTER_MASK;
+ uint32_t counter = cell.item_pointers[id.item_type] >> COUNTER_SHIFT;
+ ids_ptr[pointer + counter] = id.item_index;
+
+ cell.item_pointers[id.item_type] = pointer | ((counter + 1) << COUNTER_SHIFT);
+ }
+
+ RD::get_singleton()->texture_update(cluster_texture, 0, cluster_data, true);
+ RD::get_singleton()->buffer_update(items_buffer, 0, offset * sizeof(uint32_t), ids_ptr, true);
+}
+
+void LightClusterBuilder::setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth) {
+
+ if (width == p_width && height == p_height && depth == p_depth) {
+ return;
+ }
+ if (cluster_texture.is_valid()) {
+ RD::get_singleton()->free(cluster_texture);
+ }
+
+ width = p_width;
+ height = p_height;
+ depth = p_depth;
+
+ cluster_data.resize(width * height * depth * sizeof(Cell));
+
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ tf.type = RD::TEXTURE_TYPE_3D;
+ tf.width = width;
+ tf.height = height;
+ tf.depth = depth;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+
+ cluster_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+}
+
+RID LightClusterBuilder::get_cluster_texture() const {
+ return cluster_texture;
+}
+RID LightClusterBuilder::get_cluster_indices_buffer() const {
+ return items_buffer;
+}
+
+LightClusterBuilder::LightClusterBuilder() {
+ //initialize accumulators to something
+ lights = (LightData *)memalloc(sizeof(LightData) * 1024);
+ light_max = 1024;
+
+ refprobes = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024);
+ refprobe_max = 1024;
+
+ decals = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024);
+ decal_max = 1024;
+
+ items = (Item *)memalloc(sizeof(Item) * 1024);
+ item_max = 1024;
+
+ sort_ids = (SortID *)memalloc(sizeof(SortID) * 1024);
+ ids.resize(2014);
+ items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 1024);
+ item_max = 1024;
+}
+LightClusterBuilder::~LightClusterBuilder() {
+
+ if (cluster_data.size()) {
+ RD::get_singleton()->free(cluster_texture);
+ }
+
+ if (lights) {
+ memfree(lights);
+ }
+ if (refprobes) {
+ memfree(refprobes);
+ }
+ if (decals) {
+ memfree(decals);
+ }
+ if (items) {
+ memfree(items);
+ }
+ if (sort_ids) {
+ memfree(sort_ids);
+ RD::get_singleton()->free(items_buffer);
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/light_cluster_builder.h b/servers/rendering/rasterizer_rd/light_cluster_builder.h
new file mode 100644
index 0000000000..78288dc620
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/light_cluster_builder.h
@@ -0,0 +1,293 @@
+/*************************************************************************/
+/* light_cluster_builder.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 LIGHT_CLUSTER_BUILDER_H
+#define LIGHT_CLUSTER_BUILDER_H
+
+#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
+
+class LightClusterBuilder {
+public:
+ enum LightType {
+ LIGHT_TYPE_OMNI,
+ LIGHT_TYPE_SPOT
+ };
+
+ enum ItemType {
+ ITEM_TYPE_OMNI_LIGHT,
+ ITEM_TYPE_SPOT_LIGHT,
+ ITEM_TYPE_REFLECTION_PROBE,
+ ITEM_TYPE_DECAL,
+ ITEM_TYPE_MAX //should always be 4
+ };
+
+ enum {
+ COUNTER_SHIFT = 20, //one million total ids
+ POINTER_MASK = (1 << COUNTER_SHIFT) - 1,
+ COUNTER_MASK = 0xfff // 4096 items per cell
+ };
+
+private:
+ struct LightData {
+ float position[3];
+ uint32_t type;
+ float radius;
+ float spot_aperture;
+ uint32_t pad[2];
+ };
+
+ uint32_t light_count = 0;
+ uint32_t light_max = 0;
+ LightData *lights = nullptr;
+
+ struct OrientedBoxData {
+ float position[3];
+ uint32_t pad;
+ float x_axis[3];
+ uint32_t pad2;
+ float y_axis[3];
+ uint32_t pad3;
+ float z_axis[3];
+ uint32_t pad4;
+ };
+
+ uint32_t refprobe_count = 0;
+ uint32_t refprobe_max = 0;
+ OrientedBoxData *refprobes = nullptr;
+
+ uint32_t decal_count = 0;
+ uint32_t decal_max = 0;
+ OrientedBoxData *decals = nullptr;
+
+ struct Item {
+ AABB aabb;
+ ItemType type;
+ uint32_t index;
+ };
+
+ Item *items = nullptr;
+ uint32_t item_count = 0;
+ uint32_t item_max = 0;
+
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint32_t depth = 0;
+
+ struct Cell {
+ uint32_t item_pointers[ITEM_TYPE_MAX];
+ };
+
+ Vector<uint8_t> cluster_data;
+ RID cluster_texture;
+
+ struct SortID {
+ uint32_t cell_index;
+ uint32_t item_index;
+ ItemType item_type;
+ };
+
+ SortID *sort_ids = nullptr;
+ Vector<uint32_t> ids;
+ uint32_t sort_id_count = 0;
+ uint32_t sort_id_max = 0;
+ RID items_buffer;
+
+ Transform view_xform;
+ CameraMatrix projection;
+ float z_far = 0;
+ float z_near = 0;
+
+ _FORCE_INLINE_ void _add_item(const AABB &p_aabb, ItemType p_type, uint32_t p_index) {
+ if (unlikely(item_count == item_max)) {
+ item_max = nearest_power_of_2_templated(item_max + 1);
+ items = (Item *)memrealloc(items, sizeof(Item) * item_max);
+ }
+
+ Item &item = items[item_count];
+ item.aabb = p_aabb;
+ item.index = p_index;
+ item.type = p_type;
+ item_count++;
+ }
+
+public:
+ void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection);
+
+ _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) {
+ if (unlikely(light_count == light_max)) {
+ light_max = nearest_power_of_2_templated(light_max + 1);
+ lights = (LightData *)memrealloc(lights, sizeof(LightData) * light_max);
+ }
+
+ LightData &ld = lights[light_count];
+ ld.type = p_type;
+ ld.position[0] = p_transform.origin.x;
+ ld.position[1] = p_transform.origin.y;
+ ld.position[2] = p_transform.origin.z;
+ ld.radius = p_radius;
+ ld.spot_aperture = p_spot_aperture;
+
+ Transform xform = view_xform * p_transform;
+
+ ld.radius *= xform.basis.get_uniform_scale();
+
+ AABB aabb;
+
+ switch (p_type) {
+ case LIGHT_TYPE_OMNI: {
+ aabb.position = xform.origin;
+ aabb.size = Vector3(ld.radius, ld.radius, ld.radius);
+ aabb.position -= aabb.size;
+ aabb.size *= 2.0;
+
+ _add_item(aabb, ITEM_TYPE_OMNI_LIGHT, light_count);
+ } break;
+ case LIGHT_TYPE_SPOT: {
+
+ float r = ld.radius;
+ real_t len = Math::tan(Math::deg2rad(ld.spot_aperture)) * r;
+
+ aabb.position = xform.origin;
+ aabb.expand_to(xform.xform(Vector3(len, len, -r)));
+ aabb.expand_to(xform.xform(Vector3(-len, len, -r)));
+ aabb.expand_to(xform.xform(Vector3(-len, -len, -r)));
+ aabb.expand_to(xform.xform(Vector3(len, -len, -r)));
+ _add_item(aabb, ITEM_TYPE_SPOT_LIGHT, light_count);
+ } break;
+ }
+
+ light_count++;
+ }
+
+ _FORCE_INLINE_ void add_reflection_probe(const Transform &p_transform, const Vector3 &p_half_extents) {
+
+ if (unlikely(refprobe_count == refprobe_max)) {
+ refprobe_max = nearest_power_of_2_templated(refprobe_max + 1);
+ refprobes = (OrientedBoxData *)memrealloc(refprobes, sizeof(OrientedBoxData) * refprobe_max);
+ }
+
+ Transform xform = view_xform * p_transform;
+
+ OrientedBoxData &rp = refprobes[refprobe_count];
+ Vector3 origin = xform.origin;
+ rp.position[0] = origin.x;
+ rp.position[1] = origin.y;
+ rp.position[2] = origin.z;
+
+ Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x;
+ rp.x_axis[0] = x_axis.x;
+ rp.x_axis[1] = x_axis.y;
+ rp.x_axis[2] = x_axis.z;
+
+ Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y;
+ rp.y_axis[0] = y_axis.x;
+ rp.y_axis[1] = y_axis.y;
+ rp.y_axis[2] = y_axis.z;
+
+ Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z;
+ rp.z_axis[0] = z_axis.x;
+ rp.z_axis[1] = z_axis.y;
+ rp.z_axis[2] = z_axis.z;
+
+ AABB aabb;
+
+ aabb.position = origin + x_axis + y_axis + z_axis;
+ aabb.expand_to(origin + x_axis + y_axis - z_axis);
+ aabb.expand_to(origin + x_axis - y_axis + z_axis);
+ aabb.expand_to(origin + x_axis - y_axis - z_axis);
+ aabb.expand_to(origin - x_axis + y_axis + z_axis);
+ aabb.expand_to(origin - x_axis + y_axis - z_axis);
+ aabb.expand_to(origin - x_axis - y_axis + z_axis);
+ aabb.expand_to(origin - x_axis - y_axis - z_axis);
+
+ _add_item(aabb, ITEM_TYPE_REFLECTION_PROBE, refprobe_count);
+
+ refprobe_count++;
+ }
+
+ _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector3 &p_half_extents) {
+
+ if (unlikely(decal_count == decal_max)) {
+ decal_max = nearest_power_of_2_templated(decal_max + 1);
+ decals = (OrientedBoxData *)memrealloc(decals, sizeof(OrientedBoxData) * decal_max);
+ }
+
+ Transform xform = view_xform * p_transform;
+
+ OrientedBoxData &dc = decals[decal_count];
+
+ Vector3 origin = xform.origin;
+ dc.position[0] = origin.x;
+ dc.position[1] = origin.y;
+ dc.position[2] = origin.z;
+
+ Vector3 x_axis = xform.basis.get_axis(0) * p_half_extents.x;
+ dc.x_axis[0] = x_axis.x;
+ dc.x_axis[1] = x_axis.y;
+ dc.x_axis[2] = x_axis.z;
+
+ Vector3 y_axis = xform.basis.get_axis(1) * p_half_extents.y;
+ dc.y_axis[0] = y_axis.x;
+ dc.y_axis[1] = y_axis.y;
+ dc.y_axis[2] = y_axis.z;
+
+ Vector3 z_axis = xform.basis.get_axis(2) * p_half_extents.z;
+ dc.z_axis[0] = z_axis.x;
+ dc.z_axis[1] = z_axis.y;
+ dc.z_axis[2] = z_axis.z;
+
+ AABB aabb;
+
+ aabb.position = origin + x_axis + y_axis + z_axis;
+ aabb.expand_to(origin + x_axis + y_axis - z_axis);
+ aabb.expand_to(origin + x_axis - y_axis + z_axis);
+ aabb.expand_to(origin + x_axis - y_axis - z_axis);
+ aabb.expand_to(origin - x_axis + y_axis + z_axis);
+ aabb.expand_to(origin - x_axis + y_axis - z_axis);
+ aabb.expand_to(origin - x_axis - y_axis + z_axis);
+ aabb.expand_to(origin - x_axis - y_axis - z_axis);
+
+ _add_item(aabb, ITEM_TYPE_DECAL, decal_count);
+
+ decal_count++;
+ }
+
+ void bake_cluster();
+
+ void setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
+
+ RID get_cluster_texture() const;
+ RID get_cluster_indices_buffer() const;
+
+ LightClusterBuilder();
+ ~LightClusterBuilder();
+};
+
+#endif // LIGHT_CLUSTER_BUILDER_H
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
new file mode 100644
index 0000000000..ba4f4c4acb
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.cpp
@@ -0,0 +1,2558 @@
+/*************************************************************************/
+/* rasterizer_canvas_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer_canvas_rd.h"
+#include "core/math/math_funcs.h"
+#include "core/project_settings.h"
+#include "rasterizer_rd.h"
+
+void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
+
+ p_mat4[0] = p_transform.elements[0][0];
+ p_mat4[1] = p_transform.elements[0][1];
+ p_mat4[2] = 0;
+ p_mat4[3] = 0;
+ p_mat4[4] = p_transform.elements[1][0];
+ p_mat4[5] = p_transform.elements[1][1];
+ p_mat4[6] = 0;
+ p_mat4[7] = 0;
+ p_mat4[8] = 0;
+ p_mat4[9] = 0;
+ p_mat4[10] = 1;
+ p_mat4[11] = 0;
+ p_mat4[12] = p_transform.elements[2][0];
+ p_mat4[13] = p_transform.elements[2][1];
+ p_mat4[14] = 0;
+ p_mat4[15] = 1;
+}
+
+void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) {
+
+ p_mat2x4[0] = p_transform.elements[0][0];
+ p_mat2x4[1] = p_transform.elements[1][0];
+ p_mat2x4[2] = 0;
+ p_mat2x4[3] = p_transform.elements[2][0];
+
+ p_mat2x4[4] = p_transform.elements[0][1];
+ p_mat2x4[5] = p_transform.elements[1][1];
+ p_mat2x4[6] = 0;
+ p_mat2x4[7] = p_transform.elements[2][1];
+}
+
+void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) {
+
+ p_mat2x3[0] = p_transform.elements[0][0];
+ p_mat2x3[1] = p_transform.elements[0][1];
+ p_mat2x3[2] = p_transform.elements[1][0];
+ p_mat2x3[3] = p_transform.elements[1][1];
+ p_mat2x3[4] = p_transform.elements[2][0];
+ p_mat2x3[5] = p_transform.elements[2][1];
+}
+
+void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) {
+
+ p_mat4[0] = p_transform.basis.elements[0][0];
+ p_mat4[1] = p_transform.basis.elements[1][0];
+ p_mat4[2] = p_transform.basis.elements[2][0];
+ p_mat4[3] = 0;
+ p_mat4[4] = p_transform.basis.elements[0][1];
+ p_mat4[5] = p_transform.basis.elements[1][1];
+ p_mat4[6] = p_transform.basis.elements[2][1];
+ p_mat4[7] = 0;
+ p_mat4[8] = p_transform.basis.elements[0][2];
+ p_mat4[9] = p_transform.basis.elements[1][2];
+ p_mat4[10] = p_transform.basis.elements[2][2];
+ p_mat4[11] = 0;
+ p_mat4[12] = p_transform.origin.x;
+ p_mat4[13] = p_transform.origin.y;
+ p_mat4[14] = p_transform.origin.z;
+ p_mat4[15] = 1;
+}
+
+void RasterizerCanvasRD::_update_specular_shininess(const Color &p_transform, uint32_t *r_ss) {
+
+ *r_ss = uint32_t(CLAMP(p_transform.a * 255.0, 0, 255)) << 24;
+ *r_ss |= uint32_t(CLAMP(p_transform.b * 255.0, 0, 255)) << 16;
+ *r_ss |= uint32_t(CLAMP(p_transform.g * 255.0, 0, 255)) << 8;
+ *r_ss |= uint32_t(CLAMP(p_transform.r * 255.0, 0, 255));
+}
+
+RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
+
+ Vector<RD::Uniform> uniform_set;
+
+ { // COLOR TEXTURE
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ RID texture = storage->texture_get_rd_texture(p_texture);
+ if (!texture.is_valid()) {
+ //use default white texture
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ }
+ u.ids.push_back(texture);
+ uniform_set.push_back(u);
+ }
+
+ { // NORMAL TEXTURE
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ RID texture = storage->texture_get_rd_texture(p_normalmap);
+ if (!texture.is_valid()) {
+ //use default normal texture
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
+ }
+ u.ids.push_back(texture);
+ uniform_set.push_back(u);
+ }
+
+ { // SPECULAR TEXTURE
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 3;
+ RID texture = storage->texture_get_rd_texture(p_specular);
+ if (!texture.is_valid()) {
+ //use default white texture
+ texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ }
+ u.ids.push_back(texture);
+ uniform_set.push_back(u);
+ }
+
+ { // SAMPLER
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 4;
+ RID sampler = storage->sampler_rd_get_default(p_filter, p_repeat);
+ ERR_FAIL_COND_V(sampler.is_null(), RID());
+ u.ids.push_back(sampler);
+ uniform_set.push_back(u);
+ }
+
+ { // MULTIMESH TEXTURE BUFFER
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
+ u.binding = 5;
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER));
+ uniform_set.push_back(u);
+ }
+
+ return RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0);
+}
+
+RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
+
+ if (p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
+ p_filter = default_samplers.default_filter;
+ }
+
+ if (p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
+ p_repeat = default_samplers.default_repeat;
+ }
+
+ TextureBindingKey key;
+ key.texture = p_texture;
+ key.normalmap = p_normalmap;
+ key.specular = p_specular;
+ key.multimesh = p_multimesh;
+ key.texture_filter = p_filter;
+ key.texture_repeat = p_repeat;
+
+ TextureBinding *binding;
+ TextureBindingID id;
+ {
+ TextureBindingID *idptr = bindings.texture_key_bindings.getptr(key);
+
+ if (!idptr) {
+ id = bindings.id_generator++;
+ bindings.texture_key_bindings[key] = id;
+ binding = memnew(TextureBinding);
+ binding->key = key;
+ binding->id = id;
+
+ bindings.texture_bindings[id] = binding;
+
+ } else {
+ id = *idptr;
+ binding = bindings.texture_bindings[id];
+ }
+ }
+
+ binding->reference_count++;
+
+ if (binding->to_dispose.in_list()) {
+ //was queued for disposal previously, but ended up reused.
+ bindings.to_dispose_list.remove(&binding->to_dispose);
+ }
+
+ if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) {
+ binding->uniform_set = _create_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh);
+ }
+
+ return id;
+}
+
+void RasterizerCanvasRD::free_texture_binding(TextureBindingID p_binding) {
+
+ TextureBinding **binding_ptr = bindings.texture_bindings.getptr(p_binding);
+ ERR_FAIL_COND(!binding_ptr);
+ TextureBinding *binding = *binding_ptr;
+ ERR_FAIL_COND(binding->reference_count == 0);
+ binding->reference_count--;
+ if (binding->reference_count == 0) {
+ bindings.to_dispose_list.add(&binding->to_dispose);
+ }
+}
+
+void RasterizerCanvasRD::_dispose_bindings() {
+
+ while (bindings.to_dispose_list.first()) {
+ TextureBinding *binding = bindings.to_dispose_list.first()->self();
+ if (binding->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) {
+ RD::get_singleton()->free(binding->uniform_set);
+ }
+
+ bindings.texture_key_bindings.erase(binding->key);
+ bindings.texture_bindings.erase(binding->id);
+ bindings.to_dispose_list.remove(&binding->to_dispose);
+ memdelete(binding);
+ }
+}
+
+RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) {
+
+ // Care must be taken to generate array formats
+ // in ways where they could be reused, so we will
+ // put single-occuring elements first, and repeated
+ // elements later. This way the generated formats are
+ // the same no matter the length of the arrays.
+ // This dramatically reduces the amount of pipeline objects
+ // that need to be created for these formats.
+
+ uint32_t vertex_count = p_points.size();
+ uint32_t stride = 2; //vertices always repeat
+ if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
+ stride += 4;
+ }
+ if ((uint32_t)p_uvs.size() == vertex_count) {
+ stride += 2;
+ }
+ if ((uint32_t)p_bones.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
+ stride += 4;
+ }
+
+ uint32_t buffer_size = stride * p_points.size();
+
+ Vector<uint8_t> polygon_buffer;
+ polygon_buffer.resize(buffer_size * sizeof(float));
+ Vector<RD::VertexDescription> descriptions;
+ descriptions.resize(4);
+ Vector<RID> buffers;
+ buffers.resize(4);
+
+ {
+ const uint8_t *r = polygon_buffer.ptr();
+ float *fptr = (float *)r;
+ uint32_t *uptr = (uint32_t *)r;
+ uint32_t base_offset = 0;
+ { //vertices
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ vd.offset = base_offset * sizeof(float);
+ vd.location = RS::ARRAY_VERTEX;
+ vd.stride = stride * sizeof(float);
+
+ descriptions.write[0] = vd;
+
+ const Vector2 *points_ptr = p_points.ptr();
+
+ for (uint32_t i = 0; i < vertex_count; i++) {
+ fptr[base_offset + i * stride + 0] = points_ptr[i].x;
+ fptr[base_offset + i * stride + 1] = points_ptr[i].y;
+ }
+
+ base_offset += 2;
+ }
+
+ //colors
+ if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ vd.offset = base_offset * sizeof(float);
+ vd.location = RS::ARRAY_COLOR;
+ vd.stride = stride * sizeof(float);
+
+ descriptions.write[1] = vd;
+
+ if (p_colors.size() == 1) {
+ Color color = p_colors[0];
+ for (uint32_t i = 0; i < vertex_count; i++) {
+ fptr[base_offset + i * stride + 0] = color.r;
+ fptr[base_offset + i * stride + 1] = color.g;
+ fptr[base_offset + i * stride + 2] = color.b;
+ fptr[base_offset + i * stride + 3] = color.a;
+ }
+ } else {
+ const Color *color_ptr = p_colors.ptr();
+
+ for (uint32_t i = 0; i < vertex_count; i++) {
+ fptr[base_offset + i * stride + 0] = color_ptr[i].r;
+ fptr[base_offset + i * stride + 1] = color_ptr[i].g;
+ fptr[base_offset + i * stride + 2] = color_ptr[i].b;
+ fptr[base_offset + i * stride + 3] = color_ptr[i].a;
+ }
+ }
+ base_offset += 4;
+ } else {
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ vd.offset = 0;
+ vd.location = RS::ARRAY_COLOR;
+ vd.stride = 0;
+
+ descriptions.write[1] = vd;
+ buffers.write[1] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_COLOR);
+ }
+
+ //uvs
+ if ((uint32_t)p_uvs.size() == vertex_count) {
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ vd.offset = base_offset * sizeof(float);
+ vd.location = RS::ARRAY_TEX_UV;
+ vd.stride = stride * sizeof(float);
+
+ descriptions.write[2] = vd;
+
+ const Vector2 *uv_ptr = p_uvs.ptr();
+
+ for (uint32_t i = 0; i < vertex_count; i++) {
+ fptr[base_offset + i * stride + 0] = uv_ptr[i].x;
+ fptr[base_offset + i * stride + 1] = uv_ptr[i].y;
+ }
+ base_offset += 2;
+ } else {
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ vd.offset = 0;
+ vd.location = RS::ARRAY_TEX_UV;
+ vd.stride = 0;
+
+ descriptions.write[2] = vd;
+ buffers.write[2] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_TEX_UV);
+ }
+
+ //bones
+ if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ vd.offset = base_offset * sizeof(float);
+ vd.location = RS::ARRAY_BONES;
+ vd.stride = stride * sizeof(float);
+
+ descriptions.write[3] = vd;
+
+ const int *bone_ptr = p_bones.ptr();
+ const float *weight_ptr = p_weights.ptr();
+
+ for (uint32_t i = 0; i < vertex_count; i++) {
+
+ uint16_t *bone16w = (uint16_t *)&uptr[base_offset + i * stride];
+ uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride + 2];
+
+ bone16w[0] = bone_ptr[i * 4 + 0];
+ bone16w[1] = bone_ptr[i * 4 + 1];
+ bone16w[2] = bone_ptr[i * 4 + 2];
+ bone16w[3] = bone_ptr[i * 4 + 3];
+
+ weight16w[0] = CLAMP(weight_ptr[i * 4 + 0] * 65535, 0, 65535);
+ weight16w[1] = CLAMP(weight_ptr[i * 4 + 1] * 65535, 0, 65535);
+ weight16w[2] = CLAMP(weight_ptr[i * 4 + 2] * 65535, 0, 65535);
+ weight16w[3] = CLAMP(weight_ptr[i * 4 + 3] * 65535, 0, 65535);
+ }
+
+ base_offset += 4;
+ } else {
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ vd.offset = 0;
+ vd.location = RS::ARRAY_BONES;
+ vd.stride = 0;
+
+ descriptions.write[3] = vd;
+ buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
+ }
+
+ //check that everything is as it should be
+ ERR_FAIL_COND_V(base_offset != stride, 0); //bug
+ }
+
+ RD::VertexFormatID vertex_id = RD::get_singleton()->vertex_format_create(descriptions);
+ ERR_FAIL_COND_V(vertex_id == RD::INVALID_ID, 0);
+
+ PolygonBuffers pb;
+ pb.vertex_buffer = RD::get_singleton()->vertex_buffer_create(polygon_buffer.size(), polygon_buffer);
+ for (int i = 0; i < descriptions.size(); i++) {
+ if (buffers[i] == RID()) { //if put in vertex, use as vertex
+ buffers.write[i] = pb.vertex_buffer;
+ }
+ }
+
+ pb.vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), vertex_id, buffers);
+
+ if (p_indices.size()) {
+ //create indices, as indices were requested
+ Vector<uint8_t> index_buffer;
+ 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());
+ }
+ 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());
+ }
+
+ pb.vertex_format_id = vertex_id;
+
+ PolygonID id = polygon_buffers.last_id++;
+
+ polygon_buffers.polygons[id] = pb;
+
+ return id;
+}
+
+void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) {
+
+ PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon);
+ ERR_FAIL_COND(!pb_ptr);
+
+ PolygonBuffers &pb = *pb_ptr;
+
+ if (pb.indices.is_valid()) {
+ RD::get_singleton()->free(pb.indices);
+ }
+ if (pb.index_buffer.is_valid()) {
+ RD::get_singleton()->free(pb.index_buffer);
+ }
+
+ RD::get_singleton()->free(pb.vertex_array);
+ RD::get_singleton()->free(pb.vertex_buffer);
+
+ polygon_buffers.polygons.erase(p_polygon);
+}
+
+Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list, uint32_t &flags) {
+
+ TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding);
+ ERR_FAIL_COND_V(!texture_binding_ptr, Size2i());
+ TextureBinding *texture_binding = *texture_binding_ptr;
+
+ if (texture_binding->key.normalmap.is_valid()) {
+ flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ }
+ if (texture_binding->key.specular.is_valid()) {
+ flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ }
+
+ if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) {
+ //texture may have changed (erased or replaced, see if we can fix)
+ texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh);
+ ERR_FAIL_COND_V(!texture_binding->uniform_set.is_valid(), Size2i(1, 1));
+ }
+
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0);
+ if (texture_binding->key.texture.is_valid()) {
+ return storage->texture_2d_get_size(texture_binding->key.texture);
+ } else {
+ return Size2i(1, 1);
+ }
+}
+
+////////////////////
+void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
+
+ //create an empty push constant
+
+ PushConstant push_constant;
+ Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
+ _update_transform_2d_to_mat2x3(base_transform, push_constant.world);
+
+ Color base_color = p_item->final_modulate;
+
+ for (int i = 0; i < 4; i++) {
+ push_constant.modulation[i] = 0;
+ push_constant.ninepatch_margins[i] = 0;
+ push_constant.src_rect[i] = 0;
+ push_constant.dst_rect[i] = 0;
+ }
+ push_constant.flags = 0;
+ push_constant.color_texture_pixel_size[0] = 0;
+ push_constant.color_texture_pixel_size[1] = 0;
+
+ push_constant.pad[0] = 0;
+ push_constant.pad[1] = 0;
+
+ push_constant.lights[0] = 0;
+ push_constant.lights[1] = 0;
+ push_constant.lights[2] = 0;
+ push_constant.lights[3] = 0;
+
+ uint32_t base_flags = 0;
+
+ bool light_uniform_set_dirty = false;
+
+ if (!p_item->custom_data) {
+ p_item->custom_data = memnew(ItemStateData);
+ light_uniform_set_dirty = true;
+ }
+
+ ItemStateData *state_data = (ItemStateData *)p_item->custom_data;
+
+ Light *light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];
+ uint16_t light_count = 0;
+ PipelineLightMode light_mode;
+
+ {
+
+ Light *light = p_lights;
+
+ while (light) {
+
+ if (light->render_index_cache >= 0 && p_item->light_mask & light->item_mask && p_item->z_final >= light->z_min && p_item->z_final <= light->z_max && p_item->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
+
+ uint32_t light_index = light->render_index_cache;
+ push_constant.lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+
+ if (!light_uniform_set_dirty && (state_data->light_cache[light_count].light != light || state_data->light_cache[light_count].light_version != light->version)) {
+ light_uniform_set_dirty = true;
+ }
+
+ light_cache[light_count] = light;
+
+ light_count++;
+ if (light->mode == RS::CANVAS_LIGHT_MODE_MASK) {
+ base_flags |= FLAGS_USING_LIGHT_MASK;
+ }
+ if (light_count == state.max_lights_per_item) {
+ break;
+ }
+ }
+ light = light->next_ptr;
+ }
+
+ if (light_count != state_data->light_cache_count) {
+ light_uniform_set_dirty = true;
+ }
+ base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ }
+
+ {
+
+ RID &canvas_item_state = light_count ? state_data->state_uniform_set_with_light : state_data->state_uniform_set;
+
+ bool invalid_uniform = canvas_item_state.is_valid() && !RD::get_singleton()->uniform_set_is_valid(canvas_item_state);
+
+ if (canvas_item_state.is_null() || invalid_uniform || (light_count > 0 && light_uniform_set_dirty)) {
+ //re create canvas state
+ Vector<RD::Uniform> uniforms;
+
+ if (state_data->state_uniform_set_with_light.is_valid() && !invalid_uniform) {
+ RD::get_singleton()->free(canvas_item_state);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(state.canvas_state_buffer);
+ uniforms.push_back(u);
+ }
+
+ if (false && p_item->skeleton.is_valid()) {
+ //bind skeleton stuff
+ } else {
+ //bind default
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(shader.default_skeleton_texture_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(shader.default_skeleton_uniform_buffer);
+ uniforms.push_back(u);
+ }
+ }
+
+ //validate and update lighs if they are being used
+
+ if (light_count > 0) {
+ //recreate uniform set
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 3;
+ u.ids.push_back(state.lights_uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+
+ RD::Uniform u_lights;
+ u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
+ u_lights.binding = 4;
+
+ RD::Uniform u_shadows;
+ u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
+ u_shadows.binding = 5;
+
+ //lights
+ for (uint32_t i = 0; i < state.max_lights_per_item; i++) {
+ if (i < light_count) {
+
+ CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal);
+ ERR_CONTINUE(!cl);
+
+ RID rd_texture;
+
+ if (cl->texture.is_valid()) {
+ rd_texture = storage->texture_get_rd_texture(cl->texture);
+ }
+ if (rd_texture.is_valid()) {
+ u_lights.ids.push_back(rd_texture);
+ } else {
+ u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ }
+ if (cl->shadow.texture.is_valid()) {
+ u_shadows.ids.push_back(cl->shadow.texture);
+ } else {
+ u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ }
+ } else {
+ u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ }
+ }
+
+ uniforms.push_back(u_lights);
+ uniforms.push_back(u_shadows);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 6;
+ u.ids.push_back(state.shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 2);
+ } else {
+ canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2);
+ }
+ }
+
+ RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, canvas_item_state, 2);
+ }
+
+ light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
+
+ PipelineVariants *pipeline_variants = p_pipeline_variants;
+
+ bool reclip = false;
+
+ const Item::Command *c = p_item->commands;
+ while (c) {
+ push_constant.flags = base_flags; //reset on each command for sanity
+ push_constant.specular_shininess = 0xFFFFFFFF;
+
+ switch (c->type) {
+ case Item::Command::TYPE_RECT: {
+
+ const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
+
+ //bind pipeline
+ {
+ RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+ }
+
+ //bind textures
+
+ Size2 texpixel_size;
+ {
+ texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list, push_constant.flags);
+ texpixel_size.x = 1.0 / texpixel_size.x;
+ texpixel_size.y = 1.0 / texpixel_size.y;
+ }
+
+ if (rect->specular_shininess.a < 0.999) {
+ push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ }
+
+ _update_specular_shininess(rect->specular_shininess, &push_constant.specular_shininess);
+
+ Rect2 src_rect;
+ Rect2 dst_rect;
+
+ if (texpixel_size != Vector2()) {
+ push_constant.color_texture_pixel_size[0] = texpixel_size.x;
+ push_constant.color_texture_pixel_size[1] = texpixel_size.y;
+
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
+ dst_rect = Rect2(rect->rect.position, rect->rect.size);
+
+ if (dst_rect.size.width < 0) {
+ dst_rect.position.x += dst_rect.size.width;
+ dst_rect.size.width *= -1;
+ }
+ if (dst_rect.size.height < 0) {
+ dst_rect.position.y += dst_rect.size.height;
+ dst_rect.size.height *= -1;
+ }
+
+ if (rect->flags & CANVAS_RECT_FLIP_H) {
+ src_rect.size.x *= -1;
+ }
+
+ if (rect->flags & CANVAS_RECT_FLIP_V) {
+ src_rect.size.y *= -1;
+ }
+
+ if (rect->flags & CANVAS_RECT_TRANSPOSE) {
+ dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
+ }
+
+ if (rect->flags & CANVAS_RECT_CLIP_UV) {
+ push_constant.flags |= FLAGS_CLIP_RECT_UV;
+ }
+
+ } else {
+ dst_rect = Rect2(rect->rect.position, rect->rect.size);
+
+ if (dst_rect.size.width < 0) {
+ dst_rect.position.x += dst_rect.size.width;
+ dst_rect.size.width *= -1;
+ }
+ if (dst_rect.size.height < 0) {
+ dst_rect.position.y += dst_rect.size.height;
+ dst_rect.size.height *= -1;
+ }
+
+ src_rect = Rect2(0, 0, 1, 1);
+ texpixel_size = Vector2(1, 1);
+ }
+
+ push_constant.modulation[0] = rect->modulate.r * base_color.r;
+ push_constant.modulation[1] = rect->modulate.g * base_color.g;
+ push_constant.modulation[2] = rect->modulate.b * base_color.b;
+ push_constant.modulation[3] = rect->modulate.a * base_color.a;
+
+ push_constant.src_rect[0] = src_rect.position.x;
+ push_constant.src_rect[1] = src_rect.position.y;
+ push_constant.src_rect[2] = src_rect.size.width;
+ push_constant.src_rect[3] = src_rect.size.height;
+
+ push_constant.dst_rect[0] = dst_rect.position.x;
+ push_constant.dst_rect[1] = dst_rect.position.y;
+ push_constant.dst_rect[2] = dst_rect.size.width;
+ push_constant.dst_rect[3] = dst_rect.size.height;
+
+ push_constant.color_texture_pixel_size[0] = texpixel_size.x;
+ push_constant.color_texture_pixel_size[1] = texpixel_size.y;
+
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
+ RD::get_singleton()->draw_list_draw(p_draw_list, true);
+
+ } break;
+
+ case Item::Command::TYPE_NINEPATCH: {
+
+ const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
+
+ //bind pipeline
+ {
+ RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_NINEPATCH].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+ }
+
+ //bind textures
+
+ Size2 texpixel_size;
+ {
+ texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list, push_constant.flags);
+ texpixel_size.x = 1.0 / texpixel_size.x;
+ texpixel_size.y = 1.0 / texpixel_size.y;
+ }
+
+ if (np->specular_shininess.a < 0.999) {
+ push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ }
+
+ _update_specular_shininess(np->specular_shininess, &push_constant.specular_shininess);
+
+ Rect2 src_rect;
+ Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
+
+ if (texpixel_size == Size2()) {
+
+ texpixel_size = Size2(1, 1);
+ src_rect = Rect2(0, 0, 1, 1);
+
+ } else {
+
+ if (np->source != Rect2()) {
+ src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height);
+ texpixel_size = Size2(1.0 / np->source.size.width, 1.0 / np->source.size.height);
+ } else {
+ src_rect = Rect2(0, 0, 1, 1);
+ }
+ }
+
+ push_constant.modulation[0] = np->color.r * base_color.r;
+ push_constant.modulation[1] = np->color.g * base_color.g;
+ push_constant.modulation[2] = np->color.b * base_color.b;
+ push_constant.modulation[3] = np->color.a * base_color.a;
+
+ push_constant.src_rect[0] = src_rect.position.x;
+ push_constant.src_rect[1] = src_rect.position.y;
+ push_constant.src_rect[2] = src_rect.size.width;
+ push_constant.src_rect[3] = src_rect.size.height;
+
+ push_constant.dst_rect[0] = dst_rect.position.x;
+ push_constant.dst_rect[1] = dst_rect.position.y;
+ push_constant.dst_rect[2] = dst_rect.size.width;
+ push_constant.dst_rect[3] = dst_rect.size.height;
+
+ push_constant.color_texture_pixel_size[0] = texpixel_size.x;
+ push_constant.color_texture_pixel_size[1] = texpixel_size.y;
+
+ push_constant.flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
+ push_constant.flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
+
+ if (np->draw_center) {
+ push_constant.flags |= FLAGS_NINEPACH_DRAW_CENTER;
+ }
+
+ push_constant.ninepatch_margins[0] = np->margin[MARGIN_LEFT];
+ push_constant.ninepatch_margins[1] = np->margin[MARGIN_TOP];
+ push_constant.ninepatch_margins[2] = np->margin[MARGIN_RIGHT];
+ push_constant.ninepatch_margins[3] = np->margin[MARGIN_BOTTOM];
+
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
+ RD::get_singleton()->draw_list_draw(p_draw_list, true);
+
+ } break;
+ case Item::Command::TYPE_POLYGON: {
+
+ const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
+
+ PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
+ ERR_CONTINUE(!pb);
+ //bind pipeline
+ {
+ static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
+ ERR_CONTINUE(polygon->primitive < 0 || polygon->primitive >= RS::PRIMITIVE_MAX);
+ RID pipeline = pipeline_variants->variants[light_mode][variant[polygon->primitive]].get_render_pipeline(pb->vertex_format_id, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+ }
+
+ if (polygon->primitive == RS::PRIMITIVE_LINES) {
+ //not supported in most hardware, so pointless
+ //RD::get_singleton()->draw_list_set_line_width(p_draw_list, polygon->line_width);
+ }
+
+ //bind textures
+
+ Size2 texpixel_size;
+ {
+ texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list, push_constant.flags);
+ texpixel_size.x = 1.0 / texpixel_size.x;
+ texpixel_size.y = 1.0 / texpixel_size.y;
+ }
+
+ if (polygon->specular_shininess.a < 0.999) {
+ push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ }
+
+ _update_specular_shininess(polygon->specular_shininess, &push_constant.specular_shininess);
+
+ push_constant.modulation[0] = base_color.r;
+ push_constant.modulation[1] = base_color.g;
+ push_constant.modulation[2] = base_color.b;
+ push_constant.modulation[3] = base_color.a;
+
+ for (int j = 0; j < 4; j++) {
+ push_constant.src_rect[j] = 0;
+ push_constant.dst_rect[j] = 0;
+ push_constant.ninepatch_margins[j] = 0;
+ }
+
+ push_constant.color_texture_pixel_size[0] = texpixel_size.x;
+ push_constant.color_texture_pixel_size[1] = texpixel_size.y;
+
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
+ if (pb->indices.is_valid()) {
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices);
+ }
+ RD::get_singleton()->draw_list_draw(p_draw_list, pb->indices.is_valid());
+
+ } break;
+ case Item::Command::TYPE_PRIMITIVE: {
+
+ const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
+
+ //bind pipeline
+ {
+ static const PipelineVariant variant[4] = { PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES };
+ ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4);
+ RID pipeline = pipeline_variants->variants[light_mode][variant[primitive->point_count - 1]].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+ }
+
+ //bind textures
+
+ {
+ _bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list, push_constant.flags);
+ }
+
+ if (primitive->specular_shininess.a < 0.999) {
+ push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ }
+
+ _update_specular_shininess(primitive->specular_shininess, &push_constant.specular_shininess);
+
+ RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3, primitive->point_count) - 1]);
+
+ for (uint32_t j = 0; j < MIN(3, primitive->point_count); j++) {
+ push_constant.points[j * 2 + 0] = primitive->points[j].x;
+ push_constant.points[j * 2 + 1] = primitive->points[j].y;
+ push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x;
+ push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y;
+ Color col = primitive->colors[j] * base_color;
+ push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
+ push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
+ }
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, true);
+
+ if (primitive->point_count == 4) {
+ for (uint32_t j = 1; j < 3; j++) {
+ //second half of triangle
+ push_constant.points[j * 2 + 0] = primitive->points[j + 1].x;
+ push_constant.points[j * 2 + 1] = primitive->points[j + 1].y;
+ push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x;
+ push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y;
+ Color col = primitive->colors[j + 1] * base_color;
+ push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
+ push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
+ }
+
+ RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
+ RD::get_singleton()->draw_list_draw(p_draw_list, true);
+ }
+
+ } break;
+ case Item::Command::TYPE_MESH:
+ case Item::Command::TYPE_MULTIMESH:
+ case Item::Command::TYPE_PARTICLES: {
+ ERR_PRINT("FIXME: Mesh, MultiMesh and Particles render commands are unimplemented currently, they need to be ported to the 4.0 rendering architecture.");
+#ifndef _MSC_VER
+#warning Item::Command types for Mesh, MultiMesh and Particles need to be implemented.
+#endif
+ // See #if 0'ed code below to port from GLES3.
+ } break;
+
+#if 0
+ case Item::Command::TYPE_MESH: {
+
+ Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c);
+ _set_texture_rect_mode(false);
+
+ RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map);
+
+ if (texture) {
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ }
+
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform);
+
+ RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh);
+ if (mesh_data) {
+
+ for (int j = 0; j < mesh_data->surfaces.size(); j++) {
+ RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
+ // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
+ glBindVertexArray(s->array_id);
+
+ glVertexAttrib4f(RS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a);
+
+ if (s->index_array_len) {
+ glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
+ } else {
+ glDrawArrays(gl_primitive[s->primitive], 0, s->array_len);
+ }
+
+ glBindVertexArray(0);
+ }
+ }
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform);
+
+ } break;
+ case Item::Command::TYPE_MULTIMESH: {
+
+ Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c);
+
+ RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh);
+
+ if (!multi_mesh)
+ break;
+
+ RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh);
+
+ if (!mesh_data)
+ break;
+
+ RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map);
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
+ //reset shader and force rebind
+ state.using_texture_rect = true;
+ _set_texture_rect_mode(false);
+
+ if (texture) {
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ }
+
+ int amount = MIN(multi_mesh->size, multi_mesh->visible_instances);
+
+ if (amount == -1) {
+ amount = multi_mesh->size;
+ }
+
+ for (int j = 0; j < mesh_data->surfaces.size(); j++) {
+ RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
+ // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
+ glBindVertexArray(s->instancing_array_id);
+
+ glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
+
+ int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4;
+ glEnableVertexAttribArray(8);
+ glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribDivisor(8, 1);
+ glEnableVertexAttribArray(9);
+ glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4));
+ glVertexAttribDivisor(9, 1);
+
+ int color_ofs;
+
+ if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) {
+ glEnableVertexAttribArray(10);
+ glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4));
+ glVertexAttribDivisor(10, 1);
+ color_ofs = 12 * 4;
+ } else {
+ glDisableVertexAttribArray(10);
+ glVertexAttrib4f(10, 0, 0, 1, 0);
+ color_ofs = 8 * 4;
+ }
+
+ int custom_data_ofs = color_ofs;
+
+ switch (multi_mesh->color_format) {
+
+ case RS::MULTIMESH_COLOR_NONE: {
+ glDisableVertexAttribArray(11);
+ glVertexAttrib4f(11, 1, 1, 1, 1);
+ } break;
+ case RS::MULTIMESH_COLOR_8BIT: {
+ glEnableVertexAttribArray(11);
+ glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
+ glVertexAttribDivisor(11, 1);
+ custom_data_ofs += 4;
+
+ } break;
+ case RS::MULTIMESH_COLOR_FLOAT: {
+ glEnableVertexAttribArray(11);
+ glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
+ glVertexAttribDivisor(11, 1);
+ custom_data_ofs += 4 * 4;
+ } break;
+ }
+
+ switch (multi_mesh->custom_data_format) {
+
+ case RS::MULTIMESH_CUSTOM_DATA_NONE: {
+ glDisableVertexAttribArray(12);
+ glVertexAttrib4f(12, 1, 1, 1, 1);
+ } break;
+ case RS::MULTIMESH_CUSTOM_DATA_8BIT: {
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
+ glVertexAttribDivisor(12, 1);
+
+ } break;
+ case RS::MULTIMESH_CUSTOM_DATA_FLOAT: {
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
+ glVertexAttribDivisor(12, 1);
+ } break;
+ }
+
+ if (s->index_array_len) {
+ glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
+ } else {
+ glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
+ }
+
+ glBindVertexArray(0);
+ }
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
+ state.using_texture_rect = true;
+ _set_texture_rect_mode(false);
+
+ } break;
+ case Item::Command::TYPE_PARTICLES: {
+
+ Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c);
+
+ RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles);
+ if (!particles)
+ break;
+
+ if (particles->inactive && !particles->emitting)
+ break;
+
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
+
+ RenderingServerRaster::redraw_request();
+
+ storage->particles_request_process(particles_cmd->particles);
+ //enable instancing
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
+ //reset shader and force rebind
+ state.using_texture_rect = true;
+ _set_texture_rect_mode(false);
+
+ RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
+
+ if (texture) {
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ } else {
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0));
+ }
+
+ if (!particles->use_local_coords) {
+
+ Transform2D inv_xf;
+ inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y));
+ inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y));
+ inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y));
+ inv_xf.affine_invert();
+
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
+ }
+
+ glBindVertexArray(data.particle_quad_array); //use particle quad array
+ glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
+
+ int stride = sizeof(float) * 4 * 6;
+
+ int amount = particles->amount;
+
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) {
+
+ glEnableVertexAttribArray(8); //xform x
+ glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
+ glVertexAttribDivisor(8, 1);
+ glEnableVertexAttribArray(9); //xform y
+ glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
+ glVertexAttribDivisor(9, 1);
+ glEnableVertexAttribArray(10); //xform z
+ glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
+ glVertexAttribDivisor(10, 1);
+ glEnableVertexAttribArray(11); //color
+ glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
+ glVertexAttribDivisor(11, 1);
+ glEnableVertexAttribArray(12); //custom
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
+ glVertexAttribDivisor(12, 1);
+
+ glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount);
+ } else {
+ //split
+ int split = int(Math::ceil(particles->phase * particles->amount));
+
+ if (amount - split > 0) {
+ glEnableVertexAttribArray(8); //xform x
+ glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3));
+ glVertexAttribDivisor(8, 1);
+ glEnableVertexAttribArray(9); //xform y
+ glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4));
+ glVertexAttribDivisor(9, 1);
+ glEnableVertexAttribArray(10); //xform z
+ glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5));
+ glVertexAttribDivisor(10, 1);
+ glEnableVertexAttribArray(11); //color
+ glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0));
+ glVertexAttribDivisor(11, 1);
+ glEnableVertexAttribArray(12); //custom
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2));
+ glVertexAttribDivisor(12, 1);
+
+ glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split);
+ }
+
+ if (split > 0) {
+ glEnableVertexAttribArray(8); //xform x
+ glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
+ glVertexAttribDivisor(8, 1);
+ glEnableVertexAttribArray(9); //xform y
+ glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
+ glVertexAttribDivisor(9, 1);
+ glEnableVertexAttribArray(10); //xform z
+ glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
+ glVertexAttribDivisor(10, 1);
+ glEnableVertexAttribArray(11); //color
+ glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
+ glVertexAttribDivisor(11, 1);
+ glEnableVertexAttribArray(12); //custom
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
+ glVertexAttribDivisor(12, 1);
+
+ glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split);
+ }
+ }
+
+ glBindVertexArray(0);
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
+ state.using_texture_rect = true;
+ _set_texture_rect_mode(false);
+
+ } break;
+#endif
+ case Item::Command::TYPE_TRANSFORM: {
+
+ const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
+ _update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world);
+
+ } break;
+ case Item::Command::TYPE_CLIP_IGNORE: {
+
+ const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
+ if (current_clip) {
+
+ if (ci->ignore != reclip) {
+
+ if (ci->ignore) {
+ RD::get_singleton()->draw_list_disable_scissor(p_draw_list);
+ reclip = true;
+ } else {
+
+ RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect);
+ reclip = false;
+ }
+ }
+ }
+
+ } break;
+ }
+
+ c = c->next;
+ }
+
+ if (current_clip && reclip) {
+ //will make it re-enable clipping if needed afterwards
+ current_clip = nullptr;
+ }
+}
+
+void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set) {
+
+ Item *current_clip = nullptr;
+
+ Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
+
+ RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target);
+
+ Vector<Color> clear_colors;
+ bool clear = false;
+ if (storage->render_target_is_clear_requested(p_to_render_target)) {
+ clear = true;
+ clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target));
+ storage->render_target_disable_clear_request(p_to_render_target);
+ }
+#ifndef _MSC_VER
+#warning TODO obtain from framebuffer format eventually when this is implemented
+#endif
+
+ RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
+
+ if (p_screen_uniform_set.is_valid()) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 3);
+ }
+ RID prev_material;
+
+ PipelineVariants *pipeline_variants = &shader.pipeline_variants;
+
+ for (int i = 0; i < p_item_count; i++) {
+
+ Item *ci = items[i];
+
+ if (current_clip != ci->final_clip_owner) {
+
+ current_clip = ci->final_clip_owner;
+
+ //setup clip
+ if (current_clip) {
+
+ RD::get_singleton()->draw_list_enable_scissor(draw_list, current_clip->final_clip_rect);
+
+ } else {
+
+ RD::get_singleton()->draw_list_disable_scissor(draw_list);
+ }
+ }
+
+ if (ci->material != prev_material) {
+
+ MaterialData *material_data = nullptr;
+ if (ci->material.is_valid()) {
+ material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+ }
+
+ if (material_data) {
+
+ if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
+ pipeline_variants = &material_data->shader_data->pipeline_variants;
+ if (material_data->uniform_set.is_valid()) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, 1);
+ }
+ } else {
+ pipeline_variants = &shader.pipeline_variants;
+ }
+ } else {
+ pipeline_variants = &shader.pipeline_variants;
+ }
+ }
+
+ _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
+
+ prev_material = ci->material;
+ }
+
+ RD::get_singleton()->draw_list_end();
+}
+
+void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) {
+
+ int item_count = 0;
+
+ //setup canvas state uniforms if needed
+
+ Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse();
+
+ {
+ //update canvas state uniform buffer
+ State::Buffer state_buffer;
+
+ Size2i ssize = storage->render_target_get_size(p_to_render_target);
+
+ Transform screen_transform;
+ screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
+ screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
+ _update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
+ _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform);
+
+ Transform2D normal_transform = p_canvas_transform;
+ normal_transform.elements[0].normalize();
+ normal_transform.elements[1].normalize();
+ normal_transform.elements[2] = Vector2();
+ _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
+
+ state_buffer.canvas_modulate[0] = p_modulate.r;
+ state_buffer.canvas_modulate[1] = p_modulate.g;
+ state_buffer.canvas_modulate[2] = p_modulate.b;
+ state_buffer.canvas_modulate[3] = p_modulate.a;
+
+ Size2 render_target_size = storage->render_target_get_size(p_to_render_target);
+ state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
+ state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
+
+ state_buffer.time = state.time;
+ RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
+ }
+
+ //setup lights if exist
+
+ {
+
+ Light *l = p_light_list;
+ uint32_t index = 0;
+
+ while (l) {
+
+ if (index == state.max_lights_per_render) {
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ continue;
+ }
+
+ CanvasLight *clight = canvas_light_owner.getornull(l->light_internal);
+ if (!clight) { //unused or invalid texture
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ ERR_CONTINUE(!clight);
+ }
+ Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
+
+ Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
+ state.light_uniforms[index].position[0] = canvas_light_pos.x;
+ state.light_uniforms[index].position[1] = canvas_light_pos.y;
+
+ _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
+ _update_transform_2d_to_mat2x4(l->xform_cache.affine_inverse(), state.light_uniforms[index].shadow_matrix);
+
+ state.light_uniforms[index].height = l->height * (p_canvas_transform.elements[0].length() + p_canvas_transform.elements[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
+ for (int i = 0; i < 4; i++) {
+ state.light_uniforms[index].shadow_color[i] = l->shadow_color[i];
+ state.light_uniforms[index].color[i] = l->color[i];
+ }
+
+ state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
+
+ if (clight->shadow.texture.is_valid()) {
+ state.light_uniforms[index].shadow_pixel_size = (1.0 / clight->shadow.size) * (1.0 + l->shadow_smooth);
+ } else {
+ state.light_uniforms[index].shadow_pixel_size = 1.0;
+ }
+
+ state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
+ if (clight->shadow.texture.is_valid()) {
+ state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
+ }
+
+ l->render_index_cache = index;
+
+ index++;
+ l = l->next_ptr;
+ }
+
+ if (index > 0) {
+ RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * index, &state.light_uniforms[0], true);
+ }
+ }
+
+ //fill the list until rendering is possible.
+ bool material_screen_texture_found = false;
+ Item *ci = p_item_list;
+ Rect2 back_buffer_rect;
+ bool backbuffer_copy = false;
+ RID screen_uniform_set;
+
+ while (ci) {
+
+ if (ci->copy_back_buffer) {
+ backbuffer_copy = true;
+
+ if (ci->copy_back_buffer->full) {
+ back_buffer_rect = Rect2();
+ } else {
+ back_buffer_rect = ci->copy_back_buffer->rect;
+ }
+ }
+
+ if (ci->material.is_valid()) {
+ MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+ if (md && md->shader_data->valid) {
+
+ if (md->shader_data->uses_screen_texture) {
+ if (!material_screen_texture_found) {
+ backbuffer_copy = true;
+ back_buffer_rect = Rect2();
+ }
+ if (screen_uniform_set.is_null()) {
+ RID backbuffer_shader = shader.canvas_shader.version_get_shader(md->shader_data->version, 0); //any version is fine
+ screen_uniform_set = storage->render_target_get_back_buffer_uniform_set(p_to_render_target, backbuffer_shader);
+ }
+ }
+
+ if (md->last_frame != RasterizerRD::get_frame_number()) {
+ md->last_frame = RasterizerRD::get_frame_number();
+ if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
+ // uniform set may be gone because a dependency was erased. In this case, it will happen
+ // if a texture is deleted, so just re-create it.
+ storage->material_force_update_textures(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
+ }
+ }
+ }
+ }
+
+ if (backbuffer_copy) {
+ //render anything pending, including clearing if no items
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set);
+ item_count = 0;
+
+ storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect);
+
+ backbuffer_copy = false;
+ material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ }
+
+ items[item_count++] = ci;
+
+ if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set);
+ //then reset
+ item_count = 0;
+ }
+
+ ci = ci->next;
+ }
+}
+
+RID RasterizerCanvasRD::light_create() {
+
+ CanvasLight canvas_light;
+ canvas_light.shadow.size = 0;
+ return canvas_light_owner.make_rid(canvas_light);
+}
+
+void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) {
+ CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND(!cl);
+ if (cl->texture == p_texture) {
+ return;
+ }
+
+ cl->texture = p_texture;
+}
+void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) {
+ CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND(!cl);
+ ERR_FAIL_COND(p_resolution < 64);
+ if (cl->shadow.texture.is_valid() == p_enable && p_resolution == cl->shadow.size) {
+ return;
+ }
+
+ if (cl->shadow.texture.is_valid()) {
+
+ RD::get_singleton()->free(cl->shadow.fb);
+ RD::get_singleton()->free(cl->shadow.depth);
+ RD::get_singleton()->free(cl->shadow.texture);
+ cl->shadow.fb = RID();
+ cl->shadow.texture = RID();
+ cl->shadow.depth = RID();
+ }
+
+ if (p_enable) {
+
+ Vector<RID> fb_textures;
+
+ { //texture
+ RD::TextureFormat tf;
+ tf.type = RD::TEXTURE_TYPE_2D;
+ tf.width = p_resolution;
+ tf.height = 1;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+
+ cl->shadow.texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ fb_textures.push_back(cl->shadow.texture);
+ }
+ {
+ RD::TextureFormat tf;
+ tf.type = RD::TEXTURE_TYPE_2D;
+ tf.width = p_resolution;
+ tf.height = 1;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT;
+ //chunks to write
+ cl->shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ fb_textures.push_back(cl->shadow.depth);
+ }
+
+ cl->shadow.fb = RD::get_singleton()->framebuffer_create(fb_textures);
+ }
+
+ cl->shadow.size = p_resolution;
+}
+
+void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
+
+ CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND(cl->shadow.texture.is_null());
+
+ for (int i = 0; i < 4; i++) {
+
+ //make sure it remains orthogonal, makes easy to read angle later
+
+ //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
+
+ Vector<Color> cc;
+ cc.push_back(Color(p_far, p_far, p_far, 1.0));
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1));
+
+ CameraMatrix projection;
+ {
+ real_t fov = 90;
+ real_t nearp = p_near;
+ real_t farp = p_far;
+ real_t aspect = 1.0;
+
+ real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5));
+ real_t ymin = -ymax;
+ real_t xmin = ymin * aspect;
+ real_t xmax = ymax * aspect;
+
+ projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
+ }
+
+ Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
+ projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+
+ ShadowRenderPushConstant push_constant;
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ push_constant.projection[y * 4 + x] = projection.matrix[y][x];
+ }
+ }
+ static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
+ push_constant.direction[0] = directions[i].x;
+ push_constant.direction[1] = directions[i].y;
+ push_constant.pad[0] = 0;
+ push_constant.pad[1] = 0;
+
+ /*if (i == 0)
+ *p_xform_cache = projection;*/
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+
+ OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
+
+ if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) {
+
+ instance = instance->next;
+ continue;
+ }
+
+ _update_transform_2d_to_mat2x4(p_light_xform * instance->xform_cache, push_constant.modelview);
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]);
+ RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+
+ instance = instance->next;
+ }
+
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
+RID RasterizerCanvasRD::occluder_polygon_create() {
+
+ OccluderPolygon occluder;
+ occluder.point_count = 0;
+ occluder.cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+ return occluder_polygon_owner.make_rid(occluder);
+}
+
+void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) {
+
+ OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!oc);
+
+ if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) {
+
+ RD::get_singleton()->free(oc->vertex_array);
+ RD::get_singleton()->free(oc->vertex_buffer);
+ RD::get_singleton()->free(oc->index_array);
+ RD::get_singleton()->free(oc->index_buffer);
+
+ oc->vertex_array = RID();
+ oc->vertex_buffer = RID();
+ oc->index_array = RID();
+ oc->index_buffer = RID();
+ }
+
+ if (p_lines.size()) {
+
+ Vector<uint8_t> geometry;
+ Vector<uint8_t> indices;
+ int lc = p_lines.size();
+
+ geometry.resize(lc * 6 * sizeof(float));
+ indices.resize(lc * 3 * sizeof(uint16_t));
+
+ {
+ uint8_t *vw = geometry.ptrw();
+ float *vwptr = (float *)vw;
+ uint8_t *iw = indices.ptrw();
+ uint16_t *iwptr = (uint16_t *)iw;
+
+ const Vector2 *lr = p_lines.ptr();
+
+ const int POLY_HEIGHT = 16384;
+
+ for (int i = 0; i < lc / 2; i++) {
+
+ vwptr[i * 12 + 0] = lr[i * 2 + 0].x;
+ vwptr[i * 12 + 1] = lr[i * 2 + 0].y;
+ vwptr[i * 12 + 2] = POLY_HEIGHT;
+
+ vwptr[i * 12 + 3] = lr[i * 2 + 1].x;
+ vwptr[i * 12 + 4] = lr[i * 2 + 1].y;
+ vwptr[i * 12 + 5] = POLY_HEIGHT;
+
+ vwptr[i * 12 + 6] = lr[i * 2 + 1].x;
+ vwptr[i * 12 + 7] = lr[i * 2 + 1].y;
+ vwptr[i * 12 + 8] = -POLY_HEIGHT;
+
+ vwptr[i * 12 + 9] = lr[i * 2 + 0].x;
+ vwptr[i * 12 + 10] = lr[i * 2 + 0].y;
+ vwptr[i * 12 + 11] = -POLY_HEIGHT;
+
+ iwptr[i * 6 + 0] = i * 4 + 0;
+ iwptr[i * 6 + 1] = i * 4 + 1;
+ iwptr[i * 6 + 2] = i * 4 + 2;
+
+ iwptr[i * 6 + 3] = i * 4 + 2;
+ iwptr[i * 6 + 4] = i * 4 + 3;
+ iwptr[i * 6 + 5] = i * 4 + 0;
+ }
+ }
+
+ //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
+
+ if (oc->vertex_array.is_null()) {
+ //create from scratch
+ //vertices
+ oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry);
+
+ Vector<RID> buffer;
+ buffer.push_back(oc->vertex_buffer);
+ oc->vertex_array = RD::get_singleton()->vertex_array_create(4 * lc / 2, shadow_render.vertex_format, buffer);
+ //indices
+
+ oc->index_buffer = RD::get_singleton()->index_buffer_create(3 * lc, RD::INDEX_BUFFER_FORMAT_UINT16, indices);
+ oc->index_array = RD::get_singleton()->index_array_create(oc->index_buffer, 0, 3 * lc);
+
+ } else {
+ //update existing
+ const uint8_t *vr = geometry.ptr();
+ RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, geometry.size(), vr);
+ const uint8_t *ir = indices.ptr();
+ RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir);
+ }
+ }
+}
+void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
+ OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!oc);
+ oc->cull_mode = p_mode;
+}
+
+void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+ uses_material_samplers = false;
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+
+ int light_mode = LIGHT_MODE_NORMAL;
+ int blend_mode = BLEND_MODE_MIX;
+ uses_screen_texture = false;
+
+ 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["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
+ actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
+
+ actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED);
+ actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY);
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+
+ actions.uniforms = &uniforms;
+
+ RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+
+ Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = canvas_singleton->shader.canvas_shader.version_create();
+ }
+
+ if (gen_code.texture_uniforms.size() || uses_screen_texture) { //requires the samplers
+ gen_code.defines.push_back("\n#define USE_MATERIAL_SAMPLERS\n");
+ uses_material_samplers = true;
+ }
+#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
+ 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);
+ ERR_FAIL_COND(!canvas_singleton->shader.canvas_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 them pipelines
+
+ RD::PipelineColorBlendState::Attachment attachment;
+
+ switch (blend_mode) {
+ case BLEND_MODE_DISABLED: {
+
+ // nothing to do here, disabled by default
+
+ } break;
+ case BLEND_MODE_MIX: {
+
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ case BLEND_MODE_ADD: {
+
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+
+ } break;
+ case BLEND_MODE_SUB: {
+
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+ attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+
+ } break;
+ case BLEND_MODE_MUL: {
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+
+ } break;
+ case BLEND_MODE_PMALPHA: {
+ attachment.enable_blend = true;
+ attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment.color_blend_op = RD::BLEND_OP_ADD;
+ attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ }
+
+ RD::PipelineColorBlendState blend_state;
+ blend_state.attachments.push_back(attachment);
+
+ //update pipelines
+
+ for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
+ for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
+ RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_LINESTRIPS,
+ RD::RENDER_PRIMITIVE_POINTS,
+ };
+
+ ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
+ { //non lit
+ SHADER_VARIANT_QUAD,
+ SHADER_VARIANT_NINEPATCH,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE_POINTS,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES_POINTS },
+ { //lit
+ SHADER_VARIANT_QUAD_LIGHT,
+ SHADER_VARIANT_NINEPATCH_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
+ };
+
+ RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]);
+ pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ }
+ }
+
+ valid = true;
+}
+
+void RasterizerCanvasRD::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 RasterizerCanvasRD::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().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);
+ }
+}
+
+bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RasterizerCanvasRD::ShaderData::is_animated() const {
+ return false;
+}
+bool RasterizerCanvasRD::ShaderData::casts_shadows() const {
+ return false;
+}
+Variant RasterizerCanvasRD::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();
+}
+
+RasterizerCanvasRD::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+ uses_material_samplers = false;
+}
+
+RasterizerCanvasRD::ShaderData::~ShaderData() {
+ RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
+ ERR_FAIL_COND(!canvas_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ canvas_singleton->shader.canvas_shader.version_free(version);
+ }
+}
+
+RasterizerStorageRD::ShaderData *RasterizerCanvasRD::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+
+ RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::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());
+ }
+
+ 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(), false);
+ }
+
+ if (shader_data->ubo_size == 0 && !shader_data->uses_material_samplers) {
+ // 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->uses_material_samplers) {
+ //needs samplers for the material (uses custom textures) create them
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 0;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = canvas_singleton->storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 1;
+ 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.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), 1);
+}
+RasterizerCanvasRD::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);
+ }
+}
+
+RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_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;
+}
+
+void RasterizerCanvasRD::set_time(double p_time) {
+ state.time = p_time;
+}
+
+void RasterizerCanvasRD::update() {
+ _dispose_bindings();
+}
+
+RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
+ storage = p_storage;
+
+ { //create default samplers
+
+ default_samplers.default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
+ default_samplers.default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
+ }
+
+ { //shader variants
+
+ uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
+
+ String global_defines;
+ if (textures_per_stage <= 16) {
+ //ARM pretty much, and very old Intel GPUs under Linux
+ state.max_lights_per_item = 4; //sad
+ global_defines += "#define MAX_LIGHT_TEXTURES 4\n";
+ } else if (textures_per_stage <= 32) {
+ //Apple (Metal)
+ state.max_lights_per_item = 8; //sad
+ global_defines += "#define MAX_LIGHT_TEXTURES 8\n";
+ } else {
+ //Anything else (16 lights per item)
+ state.max_lights_per_item = DEFAULT_MAX_LIGHTS_PER_ITEM;
+ global_defines += "#define MAX_LIGHT_TEXTURES " + itos(DEFAULT_MAX_LIGHTS_PER_ITEM) + "\n";
+ }
+
+ uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
+ if (uniform_max_size < 65536) {
+ //Yes, you guessed right, ARM again
+ state.max_lights_per_render = 64;
+ global_defines += "#define MAX_LIGHTS 64\n";
+ } else {
+ state.max_lights_per_render = DEFAULT_MAX_LIGHTS_PER_RENDER;
+ global_defines += "#define MAX_LIGHTS " + itos(DEFAULT_MAX_LIGHTS_PER_RENDER) + "\n";
+ }
+
+ state.light_uniforms = memnew_arr(LightUniform, state.max_lights_per_render);
+ Vector<String> variants;
+ //non light variants
+ variants.push_back(""); //none by default is first variant
+ variants.push_back("#define USE_NINEPATCH\n"); //ninepatch is the second variant
+ variants.push_back("#define USE_PRIMITIVE\n"); //primitive is the third
+ variants.push_back("#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size
+ variants.push_back("#define USE_ATTRIBUTES\n"); // attributes for vertex arrays
+ variants.push_back("#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size
+ //light variants
+ variants.push_back("#define USE_LIGHTING\n"); //none by default is first variant
+ variants.push_back("#define USE_LIGHTING\n#define USE_NINEPATCH\n"); //ninepatch is the second variant
+ variants.push_back("#define USE_LIGHTING\n#define USE_PRIMITIVE\n"); //primitive is the third
+ variants.push_back("#define USE_LIGHTING\n#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size
+ variants.push_back("#define USE_LIGHTING\n#define USE_ATTRIBUTES\n"); // attributes for vertex arrays
+ variants.push_back("#define USE_LIGHTING\n#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size
+
+ shader.canvas_shader.initialize(variants, global_defines);
+
+ shader.default_version = shader.canvas_shader.version_create();
+ shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD);
+ shader.default_version_rd_shader_light = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD_LIGHT);
+
+ for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
+ for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
+ RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_LINESTRIPS,
+ RD::RENDER_PRIMITIVE_POINTS,
+ };
+
+ ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
+ { //non lit
+ SHADER_VARIANT_QUAD,
+ SHADER_VARIANT_NINEPATCH,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE_POINTS,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES_POINTS },
+ { //lit
+ SHADER_VARIANT_QUAD_LIGHT,
+ SHADER_VARIANT_NINEPATCH_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
+ };
+
+ RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]);
+ shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
+ }
+ }
+ }
+
+ {
+ //shader compiler
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["LIGHT_VERTEX"] = "light_vertex";
+ actions.renames["SHADOW_VERTEX"] = "shadow_vertex";
+ actions.renames["UV"] = "uv";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+
+ actions.renames["WORLD_MATRIX"] = "world_matrix";
+ actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
+ actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
+ actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["AT_LIGHT_PASS"] = "false";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+
+ actions.renames["COLOR"] = "color";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["NORMALMAP"] = "normal_map";
+ actions.renames["NORMALMAP_DEPTH"] = "normal_depth";
+ actions.renames["TEXTURE"] = "color_texture";
+ actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size";
+ actions.renames["NORMAL_TEXTURE"] = "normal_texture";
+ actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
+ actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+
+ actions.renames["LIGHT_POSITION"] = "light_pos";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT_ENERGY"] = "light_energy";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["SHADOW_MODULATE"] = "shadow_modulate";
+
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+ actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
+ actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+
+ actions.custom_samplers["TEXTURE"] = "texture_sampler";
+ actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
+ actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
+ actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 2;
+ actions.texture_layout_set = 1;
+ actions.base_uniform_string = "material.";
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR;
+ actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
+ actions.base_varying_index = 4;
+
+ shader.compiler.initialize(actions);
+ }
+
+ { //shadow rendering
+ Vector<String> versions;
+ versions.push_back(String()); //no versions
+ shadow_render.shader.initialize(versions);
+
+ {
+ Vector<RD::AttachmentFormat> attachments;
+
+ RD::AttachmentFormat af_color;
+ af_color.format = RD::DATA_FORMAT_R32_SFLOAT;
+ af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ attachments.push_back(af_color);
+
+ RD::AttachmentFormat af_depth;
+ af_depth.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;
+ af_depth.usage_flags = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ attachments.push_back(af_depth);
+
+ shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments);
+ }
+
+ //pipelines
+ Vector<RD::VertexDescription> vf;
+ RD::VertexDescription vd;
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ vd.location = 0;
+ vd.offset = 0;
+ vd.stride = sizeof(float) * 3;
+ vf.push_back(vd);
+ shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf);
+
+ shadow_render.shader_version = shadow_render.shader.version_create();
+
+ for (int i = 0; i < 3; i++) {
+ RD::PipelineRasterizationState rs;
+ rs.cull_mode = i == 0 ? RD::POLYGON_CULL_DISABLED : (i == 1 ? RD::POLYGON_CULL_FRONT : RD::POLYGON_CULL_BACK);
+ RD::PipelineDepthStencilState ds;
+ ds.enable_depth_write = true;
+ ds.enable_depth_test = true;
+ ds.depth_compare_operator = RD::COMPARE_OP_LESS;
+ shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ { //bindings
+ bindings.id_generator = 0;
+ //generate for 0
+ bindings.default_empty = request_texture_binding(RID(), RID(), RID(), RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, RID());
+
+ { //state allocate
+ state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer));
+ state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * state.max_lights_per_render);
+
+ RD::SamplerState shadow_sampler_state;
+ shadow_sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ shadow_sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ shadow_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; //shadow wrap around
+ shadow_sampler_state.compare_op = RD::COMPARE_OP_GREATER;
+ state.shadow_sampler = RD::get_singleton()->sampler_create(shadow_sampler_state);
+ }
+ }
+
+ {
+ //polygon buffers
+ polygon_buffers.last_id = 1;
+ }
+
+ { // default index buffer
+
+ Vector<uint8_t> pv;
+ pv.resize(6 * 4);
+ {
+ uint8_t *w = pv.ptrw();
+ int *p32 = (int *)w;
+ p32[0] = 0;
+ p32[1] = 1;
+ p32[2] = 2;
+ p32[3] = 0;
+ p32[4] = 2;
+ p32[5] = 3;
+ }
+ shader.quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6);
+ }
+
+ { //primitive
+ primitive_arrays.index_array[0] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 1);
+ primitive_arrays.index_array[1] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 2);
+ primitive_arrays.index_array[2] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 3);
+ primitive_arrays.index_array[3] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6);
+ }
+
+ { //default skeleton buffer
+
+ shader.default_skeleton_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform));
+ SkeletonUniform su;
+ _update_transform_2d_to_mat4(Transform2D(), su.skeleton_inverse);
+ _update_transform_2d_to_mat4(Transform2D(), su.skeleton_transform);
+ RD::get_singleton()->buffer_update(shader.default_skeleton_uniform_buffer, 0, sizeof(SkeletonUniform), &su);
+
+ shader.default_skeleton_texture_buffer = RD::get_singleton()->texture_buffer_create(32, RD::DATA_FORMAT_R32G32B32A32_SFLOAT);
+ }
+
+ //create functions for shader and material
+ storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs);
+ storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_material_funcs);
+
+ state.time = 0;
+
+ static_assert(sizeof(PushConstant) == 128);
+}
+
+bool RasterizerCanvasRD::free(RID p_rid) {
+
+ if (canvas_light_owner.owns(p_rid)) {
+ CanvasLight *cl = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!cl, false);
+ light_set_use_shadow(p_rid, false, 64);
+ canvas_light_owner.free(p_rid);
+ } else if (occluder_polygon_owner.owns(p_rid)) {
+ occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>());
+ occluder_polygon_owner.free(p_rid);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+RasterizerCanvasRD::~RasterizerCanvasRD() {
+
+ //canvas state
+
+ {
+ if (state.canvas_state_buffer.is_valid()) {
+ RD::get_singleton()->free(state.canvas_state_buffer);
+ }
+
+ memdelete_arr(state.light_uniforms);
+ RD::get_singleton()->free(state.lights_uniform_buffer);
+ RD::get_singleton()->free(shader.default_skeleton_uniform_buffer);
+ RD::get_singleton()->free(shader.default_skeleton_texture_buffer);
+ }
+
+ //shadow rendering
+ {
+
+ shadow_render.shader.version_free(shadow_render.shader_version);
+ //this will also automatically clear all pipelines
+ RD::get_singleton()->free(state.shadow_sampler);
+ }
+ //bindings
+ {
+
+ free_texture_binding(bindings.default_empty);
+
+ //dispose pending
+ _dispose_bindings();
+ //anything remains?
+ if (bindings.texture_bindings.size()) {
+ ERR_PRINT("Some texture bindings were not properly freed (leaked canvasitems?");
+ const TextureBindingID *key = nullptr;
+ while ((key = bindings.texture_bindings.next(key))) {
+ TextureBinding *tb = bindings.texture_bindings[*key];
+ tb->reference_count = 1;
+ free_texture_binding(*key);
+ }
+ //dispose pending
+ _dispose_bindings();
+ }
+ }
+
+ //shaders
+
+ shader.canvas_shader.version_free(shader.default_version);
+
+ //buffers
+ {
+ RD::get_singleton()->free(shader.quad_index_array);
+ RD::get_singleton()->free(shader.quad_index_buffer);
+ //primitives are erase by dependency
+ }
+
+ //pipelines don't need freeing, they are all gone after shaders are gone
+}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
new file mode 100644
index 0000000000..83b431eaf6
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h
@@ -0,0 +1,501 @@
+/*************************************************************************/
+/* rasterizer_canvas_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_CANVAS_RD_H
+#define RASTERIZER_CANVAS_RD_H
+
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
+#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h"
+#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h"
+#include "servers/rendering/rasterizer_rd/shaders/canvas.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl.gen.h"
+#include "servers/rendering/rendering_device.h"
+
+class RasterizerCanvasRD : public RasterizerCanvas {
+
+ RasterizerStorageRD *storage;
+
+ enum ShaderVariant {
+ SHADER_VARIANT_QUAD,
+ SHADER_VARIANT_NINEPATCH,
+ SHADER_VARIANT_PRIMITIVE,
+ SHADER_VARIANT_PRIMITIVE_POINTS,
+ SHADER_VARIANT_ATTRIBUTES,
+ SHADER_VARIANT_ATTRIBUTES_POINTS,
+ SHADER_VARIANT_QUAD_LIGHT,
+ SHADER_VARIANT_NINEPATCH_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_LIGHT,
+ SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_LIGHT,
+ SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
+ SHADER_VARIANT_MAX
+ };
+
+ enum {
+ FLAGS_INSTANCING_STRIDE_MASK = 0xF,
+ FLAGS_INSTANCING_ENABLED = (1 << 4),
+ FLAGS_INSTANCING_HAS_COLORS = (1 << 5),
+ FLAGS_INSTANCING_COLOR_8BIT = (1 << 6),
+ FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 7),
+ FLAGS_INSTANCING_CUSTOM_DATA_8_BIT = (1 << 8),
+
+ FLAGS_CLIP_RECT_UV = (1 << 9),
+ FLAGS_TRANSPOSE_RECT = (1 << 10),
+ FLAGS_USING_LIGHT_MASK = (1 << 11),
+
+ FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
+ FLAGS_USING_PARTICLES = (1 << 13),
+ FLAGS_USE_PIXEL_SNAP = (1 << 14),
+
+ FLAGS_USE_SKELETON = (1 << 15),
+ FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
+ FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
+ FLAGS_LIGHT_COUNT_SHIFT = 20,
+
+ FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
+ FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27)
+
+ };
+
+ enum {
+ LIGHT_FLAGS_TEXTURE_MASK = 0xFFFF,
+ LIGHT_FLAGS_BLEND_SHIFT = 16,
+ LIGHT_FLAGS_BLEND_MASK = (3 << 16),
+ LIGHT_FLAGS_BLEND_MODE_ADD = (0 << 16),
+ LIGHT_FLAGS_BLEND_MODE_SUB = (1 << 16),
+ LIGHT_FLAGS_BLEND_MODE_MIX = (2 << 16),
+ LIGHT_FLAGS_BLEND_MODE_MASK = (3 << 16),
+ LIGHT_FLAGS_HAS_SHADOW = (1 << 20),
+ LIGHT_FLAGS_FILTER_SHIFT = 22
+
+ };
+
+ enum {
+ MAX_RENDER_ITEMS = 256 * 1024,
+ MAX_LIGHT_TEXTURES = 1024,
+ DEFAULT_MAX_LIGHTS_PER_ITEM = 16,
+ DEFAULT_MAX_LIGHTS_PER_RENDER = 256
+ };
+
+ /****************/
+ /**** SHADER ****/
+ /****************/
+
+ enum PipelineVariant {
+ PIPELINE_VARIANT_QUAD,
+ PIPELINE_VARIANT_NINEPATCH,
+ PIPELINE_VARIANT_PRIMITIVE_TRIANGLES,
+ PIPELINE_VARIANT_PRIMITIVE_LINES,
+ PIPELINE_VARIANT_PRIMITIVE_POINTS,
+ PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES,
+ PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP,
+ PIPELINE_VARIANT_ATTRIBUTE_LINES,
+ PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP,
+ PIPELINE_VARIANT_ATTRIBUTE_POINTS,
+ PIPELINE_VARIANT_MAX
+ };
+ enum PipelineLightMode {
+ PIPELINE_LIGHT_MODE_DISABLED,
+ PIPELINE_LIGHT_MODE_ENABLED,
+ PIPELINE_LIGHT_MODE_MAX
+ };
+
+ struct PipelineVariants {
+ RenderPipelineVertexFormatCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX];
+ };
+
+ struct {
+ CanvasShaderRD canvas_shader;
+ RID default_version;
+ RID default_version_rd_shader;
+ RID default_version_rd_shader_light;
+ RID quad_index_buffer;
+ RID quad_index_array;
+ PipelineVariants pipeline_variants;
+
+ // default_skeleton uniform set
+ RID default_skeleton_uniform_buffer;
+ RID default_skeleton_texture_buffer;
+
+ ShaderCompilerRD compiler;
+ } shader;
+
+ struct ShaderData : public RasterizerStorageRD::ShaderData {
+
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_PMALPHA,
+ BLEND_MODE_DISABLED,
+ };
+
+ enum LightMode {
+ LIGHT_MODE_NORMAL,
+ LIGHT_MODE_UNSHADED,
+ LIGHT_MODE_LIGHT_ONLY
+ };
+
+ bool valid;
+ RID version;
+ PipelineVariants pipeline_variants;
+ 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;
+
+ bool uses_screen_texture;
+ bool uses_material_samplers;
+
+ 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 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;
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RasterizerStorageRD::ShaderData *_create_shader_func();
+ static RasterizerStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<RasterizerCanvasRD *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RasterizerStorageRD::MaterialData {
+ uint64_t last_frame;
+ ShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+
+ 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();
+ };
+
+ RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
+ return static_cast<RasterizerCanvasRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
+ /**************************/
+ /**** TEXTURE BINDINGS ****/
+ /**************************/
+
+ // bindings used to render commands,
+ // cached for performance.
+
+ struct TextureBindingKey {
+ RID texture;
+ RID normalmap;
+ RID specular;
+ RID multimesh;
+ RS::CanvasItemTextureFilter texture_filter;
+ RS::CanvasItemTextureRepeat texture_repeat;
+ bool operator==(const TextureBindingKey &p_key) const {
+ return texture == p_key.texture && normalmap == p_key.normalmap && specular == p_key.specular && multimesh == p_key.specular && texture_filter == p_key.texture_filter && texture_repeat == p_key.texture_repeat;
+ }
+ };
+
+ struct TextureBindingKeyHasher {
+ static _FORCE_INLINE_ uint32_t hash(const TextureBindingKey &p_key) {
+ uint32_t hash = hash_djb2_one_64(p_key.texture.get_id());
+ hash = hash_djb2_one_64(p_key.normalmap.get_id(), hash);
+ hash = hash_djb2_one_64(p_key.specular.get_id(), hash);
+ hash = hash_djb2_one_64(p_key.multimesh.get_id(), hash);
+ hash = hash_djb2_one_32(uint32_t(p_key.texture_filter) << 16 | uint32_t(p_key.texture_repeat), hash);
+ return hash;
+ }
+ };
+
+ struct TextureBinding {
+ TextureBindingID id;
+ TextureBindingKey key;
+ SelfList<TextureBinding> to_dispose;
+ uint32_t reference_count;
+ RID uniform_set;
+ TextureBinding() :
+ to_dispose(this) {
+ reference_count = 0;
+ }
+ };
+
+ struct {
+ SelfList<TextureBinding>::List to_dispose_list;
+
+ TextureBindingID id_generator;
+ HashMap<TextureBindingKey, TextureBindingID, TextureBindingKeyHasher> texture_key_bindings;
+ HashMap<TextureBindingID, TextureBinding *> texture_bindings;
+
+ TextureBindingID default_empty;
+ } bindings;
+
+ RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
+ void _dispose_bindings();
+
+ struct {
+ RS::CanvasItemTextureFilter default_filter;
+ RS::CanvasItemTextureRepeat default_repeat;
+ } default_samplers;
+
+ /******************/
+ /**** POLYGONS ****/
+ /******************/
+
+ struct PolygonBuffers {
+ RD::VertexFormatID vertex_format_id;
+ RID vertex_buffer;
+ RID vertex_array;
+ RID index_buffer;
+ RID indices;
+ };
+
+ struct {
+ HashMap<PolygonID, PolygonBuffers> polygons;
+ PolygonID last_id;
+ } polygon_buffers;
+
+ /********************/
+ /**** PRIMITIVES ****/
+ /********************/
+
+ struct {
+ RID index_array[4];
+ } primitive_arrays;
+
+ /*******************/
+ /**** MATERIALS ****/
+ /*******************/
+
+ /******************/
+ /**** LIGHTING ****/
+ /******************/
+
+ struct CanvasLight {
+
+ RID texture;
+ struct {
+ int size;
+ RID texture;
+ RID depth;
+ RID fb;
+ } shadow;
+ };
+
+ RID_Owner<CanvasLight> canvas_light_owner;
+
+ struct ShadowRenderPushConstant {
+ float projection[16];
+ float modelview[8];
+ float direction[2];
+ float pad[2];
+ };
+
+ struct OccluderPolygon {
+
+ RS::CanvasOccluderPolygonCullMode cull_mode;
+ int point_count;
+ RID vertex_buffer;
+ RID vertex_array;
+ RID index_buffer;
+ RID index_array;
+ };
+
+ struct LightUniform {
+ float matrix[8]; //light to texture coordinate matrix
+ float shadow_matrix[8]; //light to shadow coordinate matrix
+ float color[4];
+ float shadow_color[4];
+ float position[2];
+ uint32_t flags; //index to light texture
+ float height;
+ float shadow_pixel_size;
+ float pad[3];
+ };
+
+ RID_Owner<OccluderPolygon> occluder_polygon_owner;
+
+ struct {
+ CanvasOcclusionShaderRD shader;
+ RID shader_version;
+ RID render_pipelines[3];
+ RD::VertexFormatID vertex_format;
+ RD::FramebufferFormatID framebuffer_format;
+ } shadow_render;
+
+ /***************/
+ /**** STATE ****/
+ /***************/
+
+ //state that does not vary across rendering all items
+
+ struct ItemStateData : public Item::CustomData {
+
+ struct LightCache {
+ uint64_t light_version;
+ Light *light;
+ };
+
+ LightCache light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];
+ uint32_t light_cache_count;
+ RID state_uniform_set_with_light;
+ RID state_uniform_set;
+ ItemStateData() {
+
+ for (int i = 0; i < DEFAULT_MAX_LIGHTS_PER_ITEM; i++) {
+ light_cache[i].light_version = 0;
+ light_cache[i].light = nullptr;
+ }
+ light_cache_count = 0xFFFFFFFF;
+ }
+
+ ~ItemStateData() {
+ if (state_uniform_set_with_light.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set_with_light)) {
+ RD::get_singleton()->free(state_uniform_set_with_light);
+ }
+ if (state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set)) {
+ RD::get_singleton()->free(state_uniform_set);
+ }
+ }
+ };
+
+ struct State {
+
+ //state buffer
+ struct Buffer {
+ float canvas_transform[16];
+ float screen_transform[16];
+ float canvas_normal_transform[16];
+ float canvas_modulate[4];
+ float screen_pixel_size[2];
+ float time;
+ float pad;
+
+ //uint32_t light_count;
+ //uint32_t pad[3];
+ };
+
+ LightUniform *light_uniforms;
+
+ RID lights_uniform_buffer;
+ RID canvas_state_buffer;
+ RID shadow_sampler;
+
+ uint32_t max_lights_per_render;
+ uint32_t max_lights_per_item;
+
+ double time;
+ } state;
+
+ struct PushConstant {
+ float world[6];
+ uint32_t flags;
+ uint32_t specular_shininess;
+ union {
+ //rect
+ struct {
+ float modulation[4];
+ float ninepatch_margins[4];
+ float dst_rect[4];
+ float src_rect[4];
+ float pad[2];
+ };
+ //primitive
+ struct {
+ float points[6]; // vec2 points[3]
+ float uvs[6]; // vec2 points[3]
+ uint32_t colors[6]; // colors encoded as half
+ };
+ };
+ float color_texture_pixel_size[2];
+ uint32_t lights[4];
+ };
+
+ struct SkeletonUniform {
+ float skeleton_transform[16];
+ float skeleton_inverse[16];
+ };
+
+ Item *items[MAX_RENDER_ITEMS];
+
+ Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags);
+ void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
+ void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set);
+
+ _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
+ _FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
+
+ _FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);
+ _FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4);
+
+ _FORCE_INLINE_ void _update_specular_shininess(const Color &p_transform, uint32_t *r_ss);
+
+public:
+ TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
+ void free_texture_binding(TextureBindingID p_binding);
+
+ PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>());
+ void free_polygon(PolygonID p_polygon);
+
+ RID light_create();
+ void light_set_texture(RID p_rid, RID p_texture);
+ void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution);
+ void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders);
+
+ RID occluder_polygon_create();
+ void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines);
+ void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode);
+
+ void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform);
+
+ void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){};
+
+ void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
+
+ void set_time(double p_time);
+ void update();
+ bool free(RID p_rid);
+ RasterizerCanvasRD(RasterizerStorageRD *p_storage);
+ ~RasterizerCanvasRD();
+};
+
+#endif // RASTERIZER_CANVAS_RD_H
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
new file mode 100644
index 0000000000..d469dd97ca
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -0,0 +1,1595 @@
+/*************************************************************************/
+/* rasterizer_effects_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer_effects_rd.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+#include "thirdparty/misc/cubemap_coeffs.h"
+
+static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
+ p_array[0] = p_basis.elements[0][0];
+ p_array[1] = p_basis.elements[1][0];
+ p_array[2] = p_basis.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_basis.elements[0][1];
+ p_array[5] = p_basis.elements[1][1];
+ p_array[6] = p_basis.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_basis.elements[0][2];
+ p_array[9] = p_basis.elements[1][2];
+ p_array[10] = p_basis.elements[2][2];
+ p_array[11] = 0;
+}
+
+static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+
+ p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ }
+ }
+}
+
+RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) {
+
+ if (image_to_uniform_set_cache.has(p_image)) {
+ RID uniform_set = image_to_uniform_set_cache[p_image];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 0;
+ u.ids.push_back(p_image);
+ uniforms.push_back(u);
+ //any thing with the same configuration (one texture in binding 0 for set 0), is good
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, 0), 1);
+
+ image_to_uniform_set_cache[p_image] = uniform_set;
+
+ return uniform_set;
+}
+
+RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
+
+ if (texture_to_uniform_set_cache.has(p_texture)) {
+ RID uniform_set = texture_to_uniform_set_cache[p_texture];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
+ u.ids.push_back(p_texture);
+ uniforms.push_back(u);
+ //any thing with the same configuration (one texture in binding 0 for set 0), is good
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0);
+
+ texture_to_uniform_set_cache[p_texture] = uniform_set;
+
+ return uniform_set;
+}
+
+RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
+
+ if (texture_to_compute_uniform_set_cache.has(p_texture)) {
+ RID uniform_set = texture_to_compute_uniform_set_cache[p_texture];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
+ u.ids.push_back(p_texture);
+ uniforms.push_back(u);
+ //any thing with the same configuration (one texture in binding 0 for set 0), is good
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, 0), 0);
+
+ texture_to_compute_uniform_set_cache[p_texture] = uniform_set;
+
+ return uniform_set;
+}
+
+RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture_pair(RID p_texture1, RID p_texture2, bool p_use_mipmaps) {
+
+ TexturePair tp;
+ tp.texture1 = p_texture1;
+ tp.texture2 = p_texture2;
+
+ if (texture_pair_to_compute_uniform_set_cache.has(tp)) {
+ RID uniform_set = texture_pair_to_compute_uniform_set_cache[tp];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
+ u.ids.push_back(p_texture1);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
+ u.ids.push_back(p_texture2);
+ uniforms.push_back(u);
+ }
+ //any thing with the same configuration (one texture in binding 0 for set 0), is good
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), 1);
+
+ texture_pair_to_compute_uniform_set_cache[tp] = uniform_set;
+
+ return uniform_set;
+}
+
+RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_texture2) {
+
+ TexturePair tp;
+ tp.texture1 = p_texture1;
+ tp.texture2 = p_texture2;
+
+ if (image_pair_to_compute_uniform_set_cache.has(tp)) {
+ RID uniform_set = image_pair_to_compute_uniform_set_cache[tp];
+ if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ return uniform_set;
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 0;
+ u.ids.push_back(p_texture1);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 1;
+ u.ids.push_back(p_texture2);
+ uniforms.push_back(u);
+ }
+ //any thing with the same configuration (one texture in binding 0 for set 0), is good
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), 3);
+
+ image_pair_to_compute_uniform_set_cache[tp] = uniform_set;
+
+ return uniform_set;
+}
+
+void RasterizerEffectsRD::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));
+
+ copy_to_fb.push_constant.use_section = true;
+ copy_to_fb.push_constant.section[0] = p_uv_rect.position.x;
+ copy_to_fb.push_constant.section[1] = p_uv_rect.position.y;
+ copy_to_fb.push_constant.section[2] = p_uv_rect.size.x;
+ copy_to_fb.push_constant.section[3] = p_uv_rect.size.y;
+
+ if (p_flip_y) {
+ copy_to_fb.push_constant.flip_y = true;
+ }
+
+ RD::DrawListID draw_list = p_draw_list;
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_panorama ? COPY_TO_FB_COPY_PANORAMA_TO_DP : COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+}
+
+void RasterizerEffectsRD::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) {
+ zeromem(&copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+
+ if (p_flip_y) {
+ copy_to_fb.push_constant.flip_y = true;
+ }
+ if (p_force_luminance) {
+ copy_to_fb.push_constant.force_luminance = true;
+ }
+ if (p_alpha_to_zero) {
+ copy_to_fb.push_constant.alpha_to_zero = true;
+ }
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void RasterizerEffectsRD::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) {
+
+ zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ if (p_flip_y) {
+ copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
+ }
+
+ if (p_force_luminance) {
+ copy.push_constant.flags |= COPY_FLAG_FORCE_LUMINANCE;
+ }
+
+ if (p_all_source) {
+ copy.push_constant.flags |= COPY_FLAG_ALL_SOURCE;
+ }
+
+ copy.push_constant.section[0] = 0;
+ copy.push_constant.section[1] = 0;
+ copy.push_constant.section[2] = p_rect.size.width;
+ copy.push_constant.section[3] = p_rect.size.height;
+ copy.push_constant.target[0] = p_rect.position.x;
+ copy.push_constant.target[1] = p_rect.position.y;
+
+ int32_t x_groups = (p_rect.size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_rect.size.height - 1) / 8 + 1;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8_bit_dst ? COPY_MODE_SIMPLY_COPY_8BIT : COPY_MODE_SIMPLY_COPY]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::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));
+ if (p_flip_y) {
+ copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
+ }
+
+ copy.push_constant.section[0] = 0;
+ copy.push_constant.section[1] = 0;
+ copy.push_constant.section[2] = p_rect.size.width;
+ copy.push_constant.section[3] = p_rect.size.height;
+ copy.push_constant.target[0] = p_rect.position.x;
+ copy.push_constant.target[1] = p_rect.position.y;
+ copy.push_constant.camera_z_far = p_z_far;
+ copy.push_constant.camera_z_near = p_z_near;
+
+ int32_t x_groups = (p_rect.size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_rect.size.height - 1) / 8 + 1;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_LINEARIZE_DEPTH]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::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));
+ if (p_flip_y) {
+ copy.push_constant.flags |= COPY_FLAG_FLIP_Y;
+ }
+
+ copy.push_constant.section[0] = 0;
+ copy.push_constant.section[1] = 0;
+ copy.push_constant.section[2] = p_rect.size.width;
+ copy.push_constant.section[3] = p_rect.size.height;
+ copy.push_constant.target[0] = p_rect.position.x;
+ copy.push_constant.target[1] = p_rect.position.y;
+
+ int32_t x_groups = (p_rect.size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_rect.size.height - 1) / 8 + 1;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_SIMPLY_COPY_DEPTH]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::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));
+
+ uint32_t base_flags = 0;
+ copy.push_constant.section[0] = p_region.position.x;
+ copy.push_constant.section[1] = p_region.position.y;
+ copy.push_constant.section[2] = p_region.size.width;
+ copy.push_constant.section[3] = p_region.size.height;
+
+ int32_t x_groups = (p_region.size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_region.size.height - 1) / 8 + 1;
+ //HORIZONTAL
+ RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[p_8bit_dst ? COPY_MODE_GAUSSIAN_COPY_8BIT : COPY_MODE_GAUSSIAN_COPY]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 0);
+
+ copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //VERTICAL
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 0);
+
+ copy.push_constant.flags = base_flags;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, 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));
+
+ 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;
+
+ int32_t x_groups = (p_size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_size.height - 1) / 8 + 1;
+
+ copy.push_constant.section[2] = p_size.x;
+ copy.push_constant.section[3] = p_size.y;
+
+ copy.push_constant.glow_strength = p_strength;
+ copy.push_constant.glow_bloom = p_bloom;
+ copy.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold;
+ copy.push_constant.glow_hdr_scale = p_hdr_bleed_scale;
+ copy.push_constant.glow_exposure = p_exposure;
+ copy.push_constant.glow_white = 0; //actually unused
+ copy.push_constant.glow_luminance_cap = p_luminance_cap;
+
+ copy.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also
+
+ //HORIZONTAL
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3);
+ if (p_auto_exposure.is_valid() && p_first_pass) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_auto_exposure), 1);
+ }
+
+ copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ copy_mode = COPY_MODE_GAUSSIAN_GLOW;
+
+ //VERTICAL
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3);
+
+ copy.push_constant.flags = base_flags;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_roughness, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera) {
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ int32_t x_groups = (p_screen_size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_screen_size.height - 1) / 8 + 1;
+
+ { //scale color and depth to half
+ ssr_scale.push_constant.camera_z_far = p_camera.get_z_far();
+ ssr_scale.push_constant.camera_z_near = p_camera.get_z_near();
+ ssr_scale.push_constant.orthogonal = p_camera.is_orthogonal();
+ ssr_scale.push_constant.filter = false; //enabling causes arctifacts
+ ssr_scale.push_constant.screen_size[0] = p_screen_size.x;
+ ssr_scale.push_constant.screen_size[1] = p_screen_size.y;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_scale.pipeline);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_depth, p_normal), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output_blur), 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_scale_depth, p_scale_normal), 3);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_scale.push_constant, sizeof(ScreenSpaceReflectionScalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ {
+
+ ssr.push_constant.camera_z_far = p_camera.get_z_far();
+ ssr.push_constant.camera_z_near = p_camera.get_z_near();
+ ssr.push_constant.orthogonal = p_camera.is_orthogonal();
+ ssr.push_constant.screen_size[0] = p_screen_size.x;
+ ssr.push_constant.screen_size[1] = p_screen_size.y;
+ ssr.push_constant.curve_fade_in = p_fade_in;
+ ssr.push_constant.distance_fade = p_fade_out;
+ ssr.push_constant.num_steps = p_max_steps;
+ ssr.push_constant.depth_tolerance = p_tolerance;
+ ssr.push_constant.use_half_res = true;
+ ssr.push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_camera.matrix[0][0]);
+ ssr.push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_camera.matrix[1][1]);
+ ssr.push_constant.proj_info[2] = (1.0f - p_camera.matrix[0][2]) / p_camera.matrix[0][0];
+ ssr.push_constant.proj_info[3] = (1.0f + p_camera.matrix[1][2]) / p_camera.matrix[1][1];
+ ssr.push_constant.metallic_mask[0] = CLAMP(p_metallic_mask.r * 255.0, 0, 255);
+ ssr.push_constant.metallic_mask[1] = CLAMP(p_metallic_mask.g * 255.0, 0, 255);
+ ssr.push_constant.metallic_mask[2] = CLAMP(p_metallic_mask.b * 255.0, 0, 255);
+ ssr.push_constant.metallic_mask[3] = CLAMP(p_metallic_mask.a * 255.0, 0, 255);
+ store_camera(p_camera, ssr.push_constant.projection);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[(p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL]);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr.push_constant, sizeof(ScreenSpaceReflectionPushConstant));
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_scale_depth), 0);
+
+ if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_metallic, p_roughness), 3);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_metallic), 3);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 2);
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ }
+
+ if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) {
+
+ //blurr
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ ssr_filter.push_constant.orthogonal = p_camera.is_orthogonal();
+ ssr_filter.push_constant.edge_tolerance = Math::sin(Math::deg2rad(15.0));
+ ssr_filter.push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_camera.matrix[0][0]);
+ ssr_filter.push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_camera.matrix[1][1]);
+ ssr_filter.push_constant.proj_info[2] = (1.0f - p_camera.matrix[0][2]) / p_camera.matrix[0][0];
+ ssr_filter.push_constant.proj_info[3] = (1.0f + p_camera.matrix[1][2]) / p_camera.matrix[1][1];
+ ssr_filter.push_constant.vertical = 0;
+ if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_LOW) {
+ ssr_filter.push_constant.steps = p_max_steps / 3;
+ ssr_filter.push_constant.increment = 3;
+ } else if (p_roughness_quality == RS::ENV_SSR_ROUGNESS_QUALITY_MEDIUM) {
+ ssr_filter.push_constant.steps = p_max_steps / 2;
+ ssr_filter.push_constant.increment = 2;
+ } else {
+ ssr_filter.push_constant.steps = p_max_steps;
+ ssr_filter.push_constant.increment = 1;
+ }
+
+ ssr_filter.push_constant.screen_size[0] = p_screen_size.width;
+ ssr_filter.push_constant.screen_size[1] = p_screen_size.height;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_blur_radius2), 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_depth), 3);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_filter.push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[SCREEN_SPACE_REFLECTION_FILTER_VERTICAL]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output_blur, p_blur_radius2), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 2);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_depth), 3);
+
+ ssr_filter.push_constant.vertical = 1;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssr_filter.push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ }
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) {
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ int32_t x_groups = (p_screen_size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_screen_size.height - 1) / 8 + 1;
+
+ Plane p = p_camera.xform4(Plane(1, 0, -1, 1));
+ p.normal /= p.d;
+ float unit_size = p.normal.x;
+
+ { //scale color and depth to half
+ sss.push_constant.camera_z_far = p_camera.get_z_far();
+ sss.push_constant.camera_z_near = p_camera.get_z_near();
+ sss.push_constant.orthogonal = p_camera.is_orthogonal();
+ sss.push_constant.unit_size = unit_size;
+ sss.push_constant.screen_size[0] = p_screen_size.x;
+ sss.push_constant.screen_size[1] = p_screen_size.y;
+ sss.push_constant.vertical = false;
+ sss.push_constant.scale = p_scale;
+ sss.push_constant.depth_scale = p_depth_scale;
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse2), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse2), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2);
+
+ sss.push_constant.vertical = true;
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ RD::get_singleton()->compute_list_end();
+ }
+}
+
+void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) {
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>());
+
+ if (p_reflection.is_valid()) {
+
+ if (p_base.is_valid()) {
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_SSR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base), 2);
+ } else {
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_ADDITIVE_SSR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ }
+
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_specular), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_reflection), 1);
+
+ } else {
+
+ if (p_base.is_valid()) {
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_ADD].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_base), 2);
+ } else {
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[SPECULAR_MERGE_ADDITIVE_ADD].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ }
+
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_specular), 0);
+ }
+
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size) {
+
+ zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+
+ copy.push_constant.section[0] = 0;
+ copy.push_constant.section[1] = 0;
+ copy.push_constant.section[2] = p_size.width;
+ copy.push_constant.section[3] = p_size.height;
+
+ int32_t x_groups = (p_size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_size.height - 1) / 8 + 1;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[COPY_MODE_MIPMAP]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 3);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) {
+
+ CopyToDPPushConstant push_constant;
+ push_constant.screen_size[0] = p_rect.size.x;
+ push_constant.screen_size[1] = p_rect.size.y;
+ push_constant.dest_offset[0] = p_rect.position.x;
+ push_constant.dest_offset[1] = p_rect.position.y;
+ push_constant.bias = p_bias;
+ push_constant.z_far = p_z_far;
+ push_constant.z_near = p_z_near;
+ push_constant.z_flip = p_dp_flip;
+
+ int32_t x_groups = (p_rect.size.width - 1) / 8 + 1;
+ int32_t y_groups = (p_rect.size.height - 1) / 8 + 1;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cube_to_dp.pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(CopyToDPPushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
+
+ zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant));
+
+ tonemap.push_constant.use_bcs = p_settings.use_bcs;
+ tonemap.push_constant.bcs[0] = p_settings.brightness;
+ tonemap.push_constant.bcs[1] = p_settings.contrast;
+ tonemap.push_constant.bcs[2] = p_settings.saturation;
+
+ tonemap.push_constant.use_glow = p_settings.use_glow;
+ tonemap.push_constant.glow_intensity = p_settings.glow_intensity;
+ tonemap.push_constant.glow_level_flags = p_settings.glow_level_flags;
+ tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x;
+ tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y;
+ tonemap.push_constant.glow_mode = p_settings.glow_mode;
+
+ TonemapMode mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL;
+
+ tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
+ tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
+ tonemap.push_constant.exposure = p_settings.exposure;
+ tonemap.push_constant.white = p_settings.white;
+ tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
+
+ tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
+
+ tonemap.push_constant.use_fxaa = p_settings.use_fxaa;
+ tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x;
+ tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y;
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
+
+ luminance_reduce.push_constant.source_size[0] = p_source_size.x;
+ luminance_reduce.push_constant.source_size[1] = p_source_size.y;
+ luminance_reduce.push_constant.max_luminance = p_max_luminance;
+ luminance_reduce.push_constant.min_luminance = p_min_luminance;
+ luminance_reduce.push_constant.exposure_adjust = p_adjust;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ for (int i = 0; i < p_reduce.size(); i++) {
+
+ if (i == 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_READ]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_texture), 0);
+ } else {
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list); //needs barrier, wait until previous is done
+
+ if (i == p_reduce.size() - 1 && !p_set) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_WRITE]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_prev_luminance), 2);
+ } else {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE]);
+ }
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_reduce[i - 1]), 0);
+ }
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_reduce[i]), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &luminance_reduce.push_constant, sizeof(LuminanceReducePushConstant));
+
+ int32_t x_groups = (luminance_reduce.push_constant.source_size[0] - 1) / 8 + 1;
+ int32_t y_groups = (luminance_reduce.push_constant.source_size[1] - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ luminance_reduce.push_constant.source_size[0] = MAX(luminance_reduce.push_constant.source_size[0] / 8, 1);
+ luminance_reduce.push_constant.source_size[1] = MAX(luminance_reduce.push_constant.source_size[1] / 8, 1);
+ }
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RenderingServer::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
+
+ bokeh.push_constant.blur_far_active = p_dof_far;
+ bokeh.push_constant.blur_far_begin = p_dof_far_begin;
+ bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
+
+ bokeh.push_constant.blur_near_active = p_dof_near;
+ bokeh.push_constant.blur_near_begin = p_dof_near_begin;
+ bokeh.push_constant.blur_near_end = MAX(0, p_dof_near_begin - p_dof_near_size);
+ bokeh.push_constant.use_jitter = p_use_jitter;
+ bokeh.push_constant.jitter_seed = Math::randf() * 1000.0;
+
+ bokeh.push_constant.z_near = p_cam_znear;
+ bokeh.push_constant.z_far = p_cam_zfar;
+ bokeh.push_constant.orthogonal = p_cam_orthogonal;
+ bokeh.push_constant.blur_size = p_bokeh_size;
+
+ bokeh.push_constant.second_pass = false;
+ bokeh.push_constant.half_size = false;
+
+ bokeh.push_constant.blur_scale = 0.5;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ /* FIRST PASS */
+ // The alpha channel of the source color texture is filled with the expected circle size
+ // If used for DOF far, the size is positive, if used for near, its negative.
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BLUR_SIZE]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1);
+
+ int32_t x_groups = (p_base_texture_size.x - 1) / 8 + 1;
+ int32_t y_groups = (p_base_texture_size.y - 1) / 8 + 1;
+ bokeh.push_constant.size[0] = p_base_texture_size.x;
+ bokeh.push_constant.size[1] = p_base_texture_size.y;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (p_bokeh_shape == RS::DOF_BOKEH_BOX || p_bokeh_shape == RS::DOF_BOKEH_HEXAGON) {
+
+ //second pass
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == RS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
+
+ static const int quality_samples[4] = { 6, 12, 12, 24 };
+
+ bokeh.push_constant.steps = quality_samples[p_quality];
+
+ if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ //box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+
+ x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1;
+ y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1;
+ bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
+ bokeh.push_constant.half_size = true;
+ bokeh.push_constant.blur_size *= 0.5;
+
+ } else {
+ //medium and high quality use full size
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+ }
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //third pass
+ bokeh.push_constant.second_pass = true;
+
+ if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture2), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 1);
+ }
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ if (p_quality == RS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == RS::DOF_BLUR_QUALITY_LOW) {
+ //forth pass, upscale for low quality
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1);
+
+ x_groups = (p_base_texture_size.x - 1) / 8 + 1;
+ y_groups = (p_base_texture_size.y - 1) / 8 + 1;
+ bokeh.push_constant.size[0] = p_base_texture_size.x;
+ bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.half_size = false;
+ bokeh.push_constant.second_pass = false;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ }
+ } else {
+ //circle
+
+ //second pass
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
+
+ static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
+
+ bokeh.push_constant.steps = 0;
+ bokeh.push_constant.blur_scale = quality_scale[p_quality];
+
+ //circle always runs in half size, otherwise too expensive
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
+
+ x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1;
+ y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1;
+ bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
+ bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
+ bokeh.push_constant.half_size = true;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //circle is just one pass, then upscale
+
+ // upscale
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
+
+ x_groups = (p_base_texture_size.x - 1) / 8 + 1;
+ y_groups = (p_base_texture_size.y - 1) / 8 + 1;
+ bokeh.push_constant.size[0] = p_base_texture_size.x;
+ bokeh.push_constant.size[1] = p_base_texture_size.y;
+ bokeh.push_constant.half_size = false;
+ bokeh.push_constant.second_pass = false;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ }
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness) {
+
+ //minify first
+ ssao.minify_push_constant.orthogonal = p_projection.is_orthogonal();
+ ssao.minify_push_constant.z_near = p_projection.get_z_near();
+ ssao.minify_push_constant.z_far = p_projection.get_z_far();
+ ssao.minify_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x;
+ ssao.minify_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y;
+ ssao.minify_push_constant.source_size[0] = p_depth_buffer_size.x;
+ ssao.minify_push_constant.source_size[1] = p_depth_buffer_size.y;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ /* FIRST PASS */
+ // Minify the depth buffer.
+
+ for (int i = 0; i < depth_mipmaps.size(); i++) {
+
+ if (i == 0) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_FIRST]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0);
+ } else {
+ if (i == 1) {
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_MIPMAP]);
+ }
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i - 1]), 0);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i]), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.minify_push_constant, sizeof(SSAOMinifyPushConstant));
+ // shrink after set
+ ssao.minify_push_constant.source_size[0] = MAX(1, ssao.minify_push_constant.source_size[0] >> 1);
+ ssao.minify_push_constant.source_size[1] = MAX(1, ssao.minify_push_constant.source_size[1] >> 1);
+
+ int x_groups = (ssao.minify_push_constant.source_size[0] - 1) / 8 + 1;
+ int y_groups = (ssao.minify_push_constant.source_size[1] - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ /* SECOND PASS */
+ // Gather samples
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[(SSAO_GATHER_LOW + p_quality) + (p_half_size ? 4 : 0)]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 1);
+ if (!p_half_size) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 2);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_normal_buffer), 3);
+
+ ssao.gather_push_constant.screen_size[0] = p_depth_buffer_size.x;
+ ssao.gather_push_constant.screen_size[1] = p_depth_buffer_size.y;
+ if (p_half_size) {
+ ssao.gather_push_constant.screen_size[0] >>= 1;
+ ssao.gather_push_constant.screen_size[1] >>= 1;
+ }
+ ssao.gather_push_constant.z_far = p_projection.get_z_far();
+ ssao.gather_push_constant.z_near = p_projection.get_z_near();
+ ssao.gather_push_constant.orthogonal = p_projection.is_orthogonal();
+
+ ssao.gather_push_constant.proj_info[0] = -2.0f / (ssao.gather_push_constant.screen_size[0] * p_projection.matrix[0][0]);
+ ssao.gather_push_constant.proj_info[1] = -2.0f / (ssao.gather_push_constant.screen_size[1] * p_projection.matrix[1][1]);
+ ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
+ ssao.gather_push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
+ //ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
+ //ssao.gather_push_constant.proj_info[3] = -(1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
+
+ ssao.gather_push_constant.radius = p_radius;
+
+ ssao.gather_push_constant.proj_scale = float(p_projection.get_pixels_per_meter(ssao.gather_push_constant.screen_size[0]));
+ ssao.gather_push_constant.bias = p_bias;
+ ssao.gather_push_constant.intensity_div_r6 = p_intensity / pow(p_radius, 6.0f);
+
+ ssao.gather_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x;
+ ssao.gather_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant));
+
+ int x_groups = (ssao.gather_push_constant.screen_size[0] - 1) / 8 + 1;
+ int y_groups = (ssao.gather_push_constant.screen_size[1] - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ /* THIRD PASS */
+ // Blur horizontal
+
+ ssao.blur_push_constant.edge_sharpness = p_edge_sharpness;
+ ssao.blur_push_constant.filter_scale = p_blur;
+ ssao.blur_push_constant.screen_size[0] = ssao.gather_push_constant.screen_size[0];
+ ssao.blur_push_constant.screen_size[1] = ssao.gather_push_constant.screen_size[1];
+ ssao.blur_push_constant.z_far = p_projection.get_z_far();
+ ssao.blur_push_constant.z_near = p_projection.get_z_near();
+ ssao.blur_push_constant.orthogonal = p_projection.is_orthogonal();
+ ssao.blur_push_constant.axis[0] = 1;
+ ssao.blur_push_constant.axis[1] = 0;
+
+ if (p_blur != RS::ENV_SSAO_BLUR_DISABLED) {
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[p_half_size ? SSAO_BLUR_PASS_HALF : SSAO_BLUR_PASS]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0);
+ if (p_half_size) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 1);
+ } else {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1);
+ }
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao2), 3);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ /* THIRD PASS */
+ // Blur vertical
+
+ ssao.blur_push_constant.axis[0] = 0;
+ ssao.blur_push_constant.axis[1] = 1;
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao2), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 3);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ }
+ if (p_half_size) { //must upscale
+
+ /* FOURTH PASS */
+ // upscale if half size
+ //back to full size
+ ssao.blur_push_constant.screen_size[0] = p_depth_buffer_size.x;
+ ssao.blur_push_constant.screen_size[1] = p_depth_buffer_size.y;
+
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_BLUR_UPSCALE]);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_upscale_buffer), 3);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 2);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); //not used but set anyway
+
+ x_groups = (p_depth_buffer_size.x - 1) / 8 + 1;
+ y_groups = (p_depth_buffer_size.y - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+ }
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) {
+
+ roughness_limiter.push_constant.screen_size[0] = p_size.x;
+ roughness_limiter.push_constant.screen_size[1] = p_size.y;
+ roughness_limiter.push_constant.curve = p_curve;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness_limiter.pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_normal), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_roughness), 1);
+
+ int x_groups = (p_size.x - 1) / 8 + 1;
+ int y_groups = (p_size.y - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness_limiter.push_constant, sizeof(RoughnessLimiterPushConstant)); //not used but set anyway
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::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));
+
+ roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
+ roughness.push_constant.roughness = p_roughness;
+ roughness.push_constant.sample_count = p_sample_count;
+ roughness.push_constant.use_direct_write = p_roughness == 0.0;
+ roughness.push_constant.face_size = p_size;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipeline);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_framebuffer), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+
+ int x_groups = (p_size - 1) / 8 + 1;
+ int y_groups = (p_size - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
+
+ cubemap_downsampler.push_constant.face_size = p_size.x;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
+
+ int x_groups = (p_size.x - 1) / 8 + 1;
+ int y_groups = (p_size.y - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
+
+ Vector<RD::Uniform> uniforms;
+ for (int i = 0; i < p_dest_cubemap.size(); i++) {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = i;
+ u.ids.push_back(p_dest_cubemap[i]);
+ uniforms.push_back(u);
+ }
+ if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
+ RD::get_singleton()->free(filter.image_uniform_set);
+ }
+ filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, 0), 2);
+
+ int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
+ pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.pipelines[pipeline]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
+
+ int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *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));
+
+ sky_push_constant.proj[0] = p_camera.matrix[2][0];
+ sky_push_constant.proj[1] = p_camera.matrix[0][0];
+ sky_push_constant.proj[2] = p_camera.matrix[2][1];
+ sky_push_constant.proj[3] = p_camera.matrix[1][1];
+ sky_push_constant.position[0] = p_position.x;
+ sky_push_constant.position[1] = p_position.y;
+ sky_push_constant.position[2] = p_position.z;
+ sky_push_constant.multiplier = p_multiplier;
+ sky_push_constant.time = p_time;
+ store_transform_3x3(p_orientation, sky_push_constant.orientation);
+
+ RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb);
+
+ RD::DrawListID draw_list = p_list;
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format));
+
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_samplers, 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_lights, 3);
+
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+}
+
+RasterizerEffectsRD::RasterizerEffectsRD() {
+
+ { // Initialize copy
+ Vector<String> copy_modes;
+ copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n");
+ copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define DST_IMAGE_8BIT\n");
+ copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n");
+ copy_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n");
+ copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n");
+ copy_modes.push_back("\n#define MODE_SIMPLE_COPY\n#define DST_IMAGE_8BIT\n");
+ copy_modes.push_back("\n#define MODE_SIMPLE_COPY_DEPTH\n");
+ copy_modes.push_back("\n#define MODE_MIPMAP\n");
+ copy_modes.push_back("\n#define MODE_LINEARIZE_DEPTH_COPY\n");
+
+ copy.shader.initialize(copy_modes);
+ zeromem(&copy.push_constant, sizeof(CopyPushConstant));
+ copy.shader_version = copy.shader.version_create();
+
+ for (int i = 0; i < COPY_MODE_MAX; i++) {
+ copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i));
+ }
+ }
+ {
+ Vector<String> copy_modes;
+ copy_modes.push_back("\n");
+ copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n");
+
+ copy_to_fb.shader.initialize(copy_modes);
+
+ copy_to_fb.shader_version = copy_to_fb.shader.version_create();
+
+ //use additive
+
+ for (int i = 0; i < COPY_TO_FB_MAX; i++) {
+ copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ {
+ // Initialize roughness
+ Vector<String> cubemap_roughness_modes;
+ cubemap_roughness_modes.push_back("");
+ roughness.shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.shader.version_create();
+
+ roughness.pipeline = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, 0));
+ }
+
+ {
+ // Initialize tonemapper
+ Vector<String> tonemap_modes;
+ tonemap_modes.push_back("\n");
+ tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
+
+ tonemap.shader.initialize(tonemap_modes);
+
+ tonemap.shader_version = tonemap.shader.version_create();
+
+ for (int i = 0; i < TONEMAP_MODE_MAX; i++) {
+ tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ }
+ }
+
+ {
+ // Initialize luminance_reduce
+ Vector<String> luminance_reduce_modes;
+ luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n");
+ luminance_reduce_modes.push_back("\n");
+ luminance_reduce_modes.push_back("\n#define WRITE_LUMINANCE\n");
+
+ luminance_reduce.shader.initialize(luminance_reduce_modes);
+
+ luminance_reduce.shader_version = luminance_reduce.shader.version_create();
+
+ for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) {
+ luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i));
+ }
+ }
+
+ {
+ // Initialize copier
+ Vector<String> copy_modes;
+ copy_modes.push_back("\n");
+
+ cube_to_dp.shader.initialize(copy_modes);
+
+ cube_to_dp.shader_version = cube_to_dp.shader.version_create();
+
+ cube_to_dp.pipeline = RD::get_singleton()->compute_pipeline_create(cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0));
+ }
+
+ {
+ // Initialize bokeh
+ Vector<String> bokeh_modes;
+ bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
+ bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n");
+ bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
+
+ bokeh.shader.initialize(bokeh_modes);
+
+ bokeh.shader_version = bokeh.shader.version_create();
+
+ for (int i = 0; i < BOKEH_MAX; i++) {
+ bokeh.pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.shader.version_get_shader(bokeh.shader_version, i));
+ }
+ }
+
+ {
+ // Initialize ssao
+ uint32_t pipeline = 0;
+ {
+ Vector<String> ssao_modes;
+ ssao_modes.push_back("\n#define MINIFY_START\n");
+ ssao_modes.push_back("\n");
+
+ ssao.minify_shader.initialize(ssao_modes);
+
+ ssao.minify_shader_version = ssao.minify_shader.version_create();
+
+ for (int i = 0; i <= SSAO_MINIFY_MIPMAP; i++) {
+ ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.minify_shader.version_get_shader(ssao.minify_shader_version, i));
+ pipeline++;
+ }
+ }
+ {
+ Vector<String> ssao_modes;
+ ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n");
+ ssao_modes.push_back("\n");
+ ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n");
+ ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n");
+ ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n#define USE_HALF_SIZE\n");
+ ssao_modes.push_back("\n#define USE_HALF_SIZE\n");
+ ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n#define USE_HALF_SIZE\n");
+ ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n#define USE_HALF_SIZE\n");
+
+ ssao.gather_shader.initialize(ssao_modes);
+
+ ssao.gather_shader_version = ssao.gather_shader.version_create();
+
+ for (int i = SSAO_GATHER_LOW; i <= SSAO_GATHER_ULTRA_HALF; i++) {
+ ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER_LOW));
+ pipeline++;
+ }
+ }
+ {
+ Vector<String> ssao_modes;
+ ssao_modes.push_back("\n#define MODE_FULL_SIZE\n");
+ ssao_modes.push_back("\n");
+ ssao_modes.push_back("\n#define MODE_UPSCALE\n");
+
+ ssao.blur_shader.initialize(ssao_modes);
+
+ ssao.blur_shader_version = ssao.blur_shader.version_create();
+
+ for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_UPSCALE; i++) {
+ ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS));
+
+ pipeline++;
+ }
+ }
+
+ ERR_FAIL_COND(pipeline != SSAO_MAX);
+ }
+
+ {
+ // Initialize roughness limiter
+ Vector<String> shader_modes;
+ shader_modes.push_back("");
+
+ roughness_limiter.shader.initialize(shader_modes);
+
+ roughness_limiter.shader_version = roughness_limiter.shader.version_create();
+
+ roughness_limiter.pipeline = RD::get_singleton()->compute_pipeline_create(roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0));
+ }
+
+ {
+ //Initialize cubemap downsampler
+ Vector<String> cubemap_downsampler_modes;
+ cubemap_downsampler_modes.push_back("");
+ cubemap_downsampler.shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create();
+
+ cubemap_downsampler.pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+ }
+
+ {
+ // Initialize cubemap filter
+ filter.use_high_quality = GLOBAL_GET("rendering/quality/reflections/fast_filter_high_quality");
+
+ Vector<String> cubemap_filter_modes;
+ cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n");
+ cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
+ cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
+ cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
+ filter.shader.initialize(cubemap_filter_modes);
+ filter.shader_version = filter.shader.version_create();
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.shader.version_get_shader(filter.shader_version, i));
+ }
+
+ if (filter.use_high_quality) {
+ filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
+ RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0], false);
+ } else {
+ filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs));
+ RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0], false);
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
+ }
+
+ {
+ Vector<String> specular_modes;
+ specular_modes.push_back("\n#define MODE_MERGE\n");
+ specular_modes.push_back("\n#define MODE_MERGE\n#define MODE_SSR\n");
+ specular_modes.push_back("\n");
+ specular_modes.push_back("\n#define MODE_SSR\n");
+
+ specular_merge.shader.initialize(specular_modes);
+
+ specular_merge.shader_version = specular_merge.shader.version_create();
+
+ //use additive
+
+ RD::PipelineColorBlendState::Attachment ba;
+ ba.enable_blend = true;
+ ba.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ ba.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ ba.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ ba.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ ba.color_blend_op = RD::BLEND_OP_ADD;
+ ba.alpha_blend_op = RD::BLEND_OP_ADD;
+
+ RD::PipelineColorBlendState blend_additive;
+ blend_additive.attachments.push_back(ba);
+
+ for (int i = 0; i < SPECULAR_MERGE_MAX; i++) {
+
+ RD::PipelineColorBlendState blend_state;
+ if (i == SPECULAR_MERGE_ADDITIVE_ADD || i == SPECULAR_MERGE_ADDITIVE_SSR) {
+ blend_state = blend_additive;
+ } else {
+ blend_state = RD::PipelineColorBlendState::create_disabled();
+ }
+ specular_merge.pipelines[i].setup(specular_merge.shader.version_get_shader(specular_merge.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ }
+ }
+
+ {
+ Vector<String> ssr_modes;
+ ssr_modes.push_back("\n");
+ ssr_modes.push_back("\n#define MODE_ROUGH\n");
+
+ ssr.shader.initialize(ssr_modes);
+
+ ssr.shader_version = ssr.shader.version_create();
+
+ for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
+ ssr.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i));
+ }
+ }
+
+ {
+ Vector<String> ssr_filter_modes;
+ ssr_filter_modes.push_back("\n");
+ ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n");
+
+ ssr_filter.shader.initialize(ssr_filter_modes);
+
+ ssr_filter.shader_version = ssr_filter.shader.version_create();
+
+ for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
+ ssr_filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i));
+ }
+ }
+
+ {
+ Vector<String> ssr_scale_modes;
+ ssr_scale_modes.push_back("\n");
+
+ ssr_scale.shader.initialize(ssr_scale_modes);
+
+ ssr_scale.shader_version = ssr_scale.shader.version_create();
+
+ ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0));
+ }
+
+ {
+ Vector<String> sss_modes;
+ sss_modes.push_back("\n#define USE_11_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_17_SAMPLES\n");
+ sss_modes.push_back("\n#define USE_25_SAMPLES\n");
+
+ sss.shader.initialize(sss_modes);
+
+ sss.shader_version = sss.shader.version_create();
+
+ for (int i = 0; i < sss_modes.size(); i++) {
+ sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
+ }
+ }
+
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.max_lod = 0;
+
+ default_sampler = RD::get_singleton()->sampler_create(sampler);
+
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.max_lod = 1e20;
+
+ default_mipmap_sampler = RD::get_singleton()->sampler_create(sampler);
+
+ { //create index array for copy shaders
+ Vector<uint8_t> pv;
+ pv.resize(6 * 4);
+ {
+ uint8_t *w = pv.ptrw();
+ int *p32 = (int *)w;
+ p32[0] = 0;
+ p32[1] = 1;
+ p32[2] = 2;
+ p32[3] = 0;
+ p32[4] = 2;
+ p32[5] = 3;
+ }
+ index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6);
+ }
+}
+
+RasterizerEffectsRD::~RasterizerEffectsRD() {
+ if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
+ RD::get_singleton()->free(filter.image_uniform_set);
+ }
+
+ if (RD::get_singleton()->uniform_set_is_valid(filter.uniform_set)) {
+ RD::get_singleton()->free(filter.uniform_set);
+ }
+
+ RD::get_singleton()->free(default_sampler);
+ RD::get_singleton()->free(default_mipmap_sampler);
+ RD::get_singleton()->free(index_buffer); //array gets freed as dependency
+ RD::get_singleton()->free(filter.coefficient_buffer);
+
+ bokeh.shader.version_free(bokeh.shader_version);
+ copy.shader.version_free(copy.shader_version);
+ copy_to_fb.shader.version_free(copy_to_fb.shader_version);
+ cube_to_dp.shader.version_free(cube_to_dp.shader_version);
+ cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
+ filter.shader.version_free(filter.shader_version);
+ luminance_reduce.shader.version_free(luminance_reduce.shader_version);
+ roughness.shader.version_free(roughness.shader_version);
+ roughness_limiter.shader.version_free(roughness_limiter.shader_version);
+ specular_merge.shader.version_free(specular_merge.shader_version);
+ ssao.blur_shader.version_free(ssao.blur_shader_version);
+ ssao.gather_shader.version_free(ssao.gather_shader_version);
+ ssao.minify_shader.version_free(ssao.minify_shader_version);
+ ssr.shader.version_free(ssr.shader_version);
+ ssr_filter.shader.version_free(ssr_filter.shader_version);
+ ssr_scale.shader.version_free(ssr_scale.shader_version);
+ sss.shader.version_free(sss.shader_version);
+ tonemap.shader.version_free(tonemap.shader_version);
+}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
new file mode 100644
index 0000000000..531591442b
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
@@ -0,0 +1,634 @@
+/*************************************************************************/
+/* rasterizer_effects_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_EFFECTS_RD_H
+#define RASTERIZER_EFFECTS_RD_H
+
+#include "core/math/camera_matrix.h"
+#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h"
+#include "servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/copy.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/tonemap.glsl.gen.h"
+
+#include "servers/rendering_server.h"
+
+class RasterizerEffectsRD {
+
+ enum CopyMode {
+ COPY_MODE_GAUSSIAN_COPY,
+ COPY_MODE_GAUSSIAN_COPY_8BIT,
+ COPY_MODE_GAUSSIAN_GLOW,
+ COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
+ COPY_MODE_SIMPLY_COPY,
+ COPY_MODE_SIMPLY_COPY_8BIT,
+ COPY_MODE_SIMPLY_COPY_DEPTH,
+ COPY_MODE_MIPMAP,
+ COPY_MODE_LINEARIZE_DEPTH,
+ COPY_MODE_MAX,
+
+ };
+
+ enum {
+ COPY_FLAG_HORIZONTAL = (1 << 0),
+ COPY_FLAG_USE_COPY_SECTION = (1 << 1),
+ COPY_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2),
+ COPY_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3),
+ COPY_FLAG_GLOW_FIRST_PASS = (1 << 4),
+ COPY_FLAG_FLIP_Y = (1 << 5),
+ COPY_FLAG_FORCE_LUMINANCE = (1 << 6),
+ COPY_FLAG_ALL_SOURCE = (1 << 7)
+ };
+
+ struct CopyPushConstant {
+
+ int32_t section[4];
+ int32_t target[2];
+ uint32_t flags;
+ uint32_t pad;
+ // Glow.
+ float glow_strength;
+ float glow_bloom;
+ float glow_hdr_threshold;
+ float glow_hdr_scale;
+
+ float glow_exposure;
+ float glow_white;
+ float glow_luminance_cap;
+ float glow_auto_exposure_grey;
+ // DOF.
+ float camera_z_far;
+ float camera_z_near;
+ uint32_t pad2[2];
+ };
+
+ struct Copy {
+ CopyPushConstant push_constant;
+ CopyShaderRD shader;
+ RID shader_version;
+ RID pipelines[COPY_MODE_MAX];
+
+ } copy;
+
+ enum CopyToFBMode {
+ COPY_TO_FB_COPY,
+ COPY_TO_FB_COPY_PANORAMA_TO_DP,
+ COPY_TO_FB_MAX,
+
+ };
+
+ struct CopyToFbPushConstant {
+
+ float section[4];
+ float pixel_size[2];
+ uint32_t flip_y;
+ uint32_t use_section;
+
+ uint32_t force_luminance;
+ uint32_t alpha_to_zero;
+ uint32_t pad[2];
+ };
+
+ struct CopyToFb {
+ CopyToFbPushConstant push_constant;
+ CopyToFbShaderRD shader;
+ RID shader_version;
+ RenderPipelineVertexFormatCacheRD pipelines[COPY_TO_FB_MAX];
+
+ } copy_to_fb;
+
+ struct CubemapRoughnessPushConstant {
+ uint32_t face_id;
+ uint32_t sample_count;
+ float roughness;
+ uint32_t use_direct_write;
+ float face_size;
+ float pad[3];
+ };
+
+ struct CubemapRoughness {
+
+ CubemapRoughnessPushConstant push_constant;
+ CubemapRoughnessShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+ } roughness;
+
+ enum TonemapMode {
+ TONEMAP_MODE_NORMAL,
+ TONEMAP_MODE_BICUBIC_GLOW_FILTER,
+ TONEMAP_MODE_MAX
+ };
+
+ struct TonemapPushConstant {
+ float bcs[3];
+ uint32_t use_bcs;
+
+ uint32_t use_glow;
+ uint32_t use_auto_exposure;
+ uint32_t use_color_correction;
+ uint32_t tonemapper;
+
+ uint32_t glow_texture_size[2];
+
+ float glow_intensity;
+ uint32_t glow_level_flags;
+ uint32_t glow_mode;
+
+ float exposure;
+ float white;
+ float auto_exposure_grey;
+
+ float pixel_size[2];
+ uint32_t use_fxaa;
+ uint32_t pad;
+ };
+
+ /* tonemap actually writes to a framebuffer, which is
+ * better to do using the raster pipeline rather than
+ * comptute, as that framebuffer might be in different formats
+ */
+ struct Tonemap {
+ TonemapPushConstant push_constant;
+ TonemapShaderRD shader;
+ RID shader_version;
+ RenderPipelineVertexFormatCacheRD pipelines[TONEMAP_MODE_MAX];
+ } tonemap;
+
+ enum LuminanceReduceMode {
+ LUMINANCE_REDUCE_READ,
+ LUMINANCE_REDUCE,
+ LUMINANCE_REDUCE_WRITE,
+ LUMINANCE_REDUCE_MAX
+ };
+
+ struct LuminanceReducePushConstant {
+ int32_t source_size[2];
+ float max_luminance;
+ float min_luminance;
+ float exposure_adjust;
+ float pad[3];
+ };
+
+ struct LuminanceReduce {
+
+ LuminanceReducePushConstant push_constant;
+ LuminanceReduceShaderRD shader;
+ RID shader_version;
+ RID pipelines[LUMINANCE_REDUCE_MAX];
+ } luminance_reduce;
+
+ struct CopyToDPPushConstant {
+ int32_t screen_size[2];
+ int32_t dest_offset[2];
+ float bias;
+ float z_far;
+ float z_near;
+ uint32_t z_flip;
+ };
+
+ struct CoptToDP {
+
+ CubeToDpShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+ } cube_to_dp;
+
+ struct BokehPushConstant {
+ uint32_t size[2];
+ float z_far;
+ float z_near;
+
+ uint32_t orthogonal;
+ float blur_size;
+ float blur_scale;
+ uint32_t steps;
+
+ uint32_t blur_near_active;
+ float blur_near_begin;
+ float blur_near_end;
+ uint32_t blur_far_active;
+
+ float blur_far_begin;
+ float blur_far_end;
+ uint32_t second_pass;
+ uint32_t half_size;
+
+ uint32_t use_jitter;
+ float jitter_seed;
+ uint32_t pad[2];
+ };
+
+ enum BokehMode {
+ BOKEH_GEN_BLUR_SIZE,
+ BOKEH_GEN_BOKEH_BOX,
+ BOKEH_GEN_BOKEH_HEXAGONAL,
+ BOKEH_GEN_BOKEH_CIRCULAR,
+ BOKEH_COMPOSITE,
+ BOKEH_MAX
+ };
+
+ struct Bokeh {
+
+ BokehPushConstant push_constant;
+ BokehDofShaderRD shader;
+ RID shader_version;
+ RID pipelines[BOKEH_MAX];
+ } bokeh;
+
+ enum SSAOMode {
+ SSAO_MINIFY_FIRST,
+ SSAO_MINIFY_MIPMAP,
+ SSAO_GATHER_LOW,
+ SSAO_GATHER_MEDIUM,
+ SSAO_GATHER_HIGH,
+ SSAO_GATHER_ULTRA,
+ SSAO_GATHER_LOW_HALF,
+ SSAO_GATHER_MEDIUM_HALF,
+ SSAO_GATHER_HIGH_HALF,
+ SSAO_GATHER_ULTRA_HALF,
+ SSAO_BLUR_PASS,
+ SSAO_BLUR_PASS_HALF,
+ SSAO_BLUR_UPSCALE,
+ SSAO_MAX
+ };
+
+ struct SSAOMinifyPushConstant {
+ float pixel_size[2];
+ float z_far;
+ float z_near;
+ int32_t source_size[2];
+ uint32_t orthogonal;
+ uint32_t pad;
+ };
+
+ struct SSAOGatherPushConstant {
+ int32_t screen_size[2];
+ float z_far;
+ float z_near;
+
+ uint32_t orthogonal;
+ float intensity_div_r6;
+ float radius;
+ float bias;
+
+ float proj_info[4];
+ float pixel_size[2];
+ float proj_scale;
+ uint32_t pad;
+ };
+
+ struct SSAOBlurPushConstant {
+ float edge_sharpness;
+ int32_t filter_scale;
+ float z_far;
+ float z_near;
+ uint32_t orthogonal;
+ uint32_t pad[3];
+ int32_t axis[2];
+ int32_t screen_size[2];
+ };
+
+ struct SSAO {
+
+ SSAOMinifyPushConstant minify_push_constant;
+ SsaoMinifyShaderRD minify_shader;
+ RID minify_shader_version;
+
+ SSAOGatherPushConstant gather_push_constant;
+ SsaoShaderRD gather_shader;
+ RID gather_shader_version;
+
+ SSAOBlurPushConstant blur_push_constant;
+ SsaoBlurShaderRD blur_shader;
+ RID blur_shader_version;
+
+ RID pipelines[SSAO_MAX];
+ } ssao;
+
+ struct RoughnessLimiterPushConstant {
+ int32_t screen_size[2];
+ float curve;
+ uint32_t pad;
+ };
+
+ struct RoughnessLimiter {
+
+ RoughnessLimiterPushConstant push_constant;
+ RoughnessLimiterShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+
+ } roughness_limiter;
+
+ struct CubemapDownsamplerPushConstant {
+ uint32_t face_size;
+ float pad[3];
+ };
+
+ struct CubemapDownsampler {
+
+ CubemapDownsamplerPushConstant push_constant;
+ CubemapDownsamplerShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+
+ } cubemap_downsampler;
+
+ enum CubemapFilterMode {
+ FILTER_MODE_HIGH_QUALITY,
+ FILTER_MODE_LOW_QUALITY,
+ FILTER_MODE_HIGH_QUALITY_ARRAY,
+ FILTER_MODE_LOW_QUALITY_ARRAY,
+ FILTER_MODE_MAX,
+ };
+
+ struct CubemapFilter {
+
+ CubemapFilterShaderRD shader;
+ RID shader_version;
+ RID pipelines[FILTER_MODE_MAX];
+ RID uniform_set;
+ RID image_uniform_set;
+ RID coefficient_buffer;
+ bool use_high_quality;
+
+ } filter;
+
+ struct SkyPushConstant {
+ float orientation[12];
+ float proj[4];
+ float position[3];
+ float multiplier;
+ float time;
+ float pad[3];
+ };
+
+ enum SpecularMergeMode {
+ SPECULAR_MERGE_ADD,
+ SPECULAR_MERGE_SSR,
+ SPECULAR_MERGE_ADDITIVE_ADD,
+ SPECULAR_MERGE_ADDITIVE_SSR,
+ SPECULAR_MERGE_MAX
+ };
+
+ /* Specular merge must be done using raster, rather than compute
+ * because it must continue the existing color buffer
+ */
+
+ struct SpecularMerge {
+
+ SpecularMergeShaderRD shader;
+ RID shader_version;
+ RenderPipelineVertexFormatCacheRD pipelines[SPECULAR_MERGE_MAX];
+
+ } specular_merge;
+
+ enum ScreenSpaceReflectionMode {
+ SCREEN_SPACE_REFLECTION_NORMAL,
+ SCREEN_SPACE_REFLECTION_ROUGH,
+ SCREEN_SPACE_REFLECTION_MAX,
+ };
+
+ struct ScreenSpaceReflectionPushConstant {
+
+ float proj_info[4];
+
+ int32_t screen_size[2];
+ float camera_z_near;
+ float camera_z_far;
+
+ int32_t num_steps;
+ float depth_tolerance;
+ float distance_fade;
+ float curve_fade_in;
+
+ uint32_t orthogonal;
+ float filter_mipmap_levels;
+ uint32_t use_half_res;
+ uint8_t metallic_mask[4];
+
+ float projection[16];
+ };
+
+ struct ScreenSpaceReflection {
+
+ ScreenSpaceReflectionPushConstant push_constant;
+ ScreenSpaceReflectionShaderRD shader;
+ RID shader_version;
+ RID pipelines[SCREEN_SPACE_REFLECTION_MAX];
+
+ } ssr;
+
+ struct ScreenSpaceReflectionFilterPushConstant {
+
+ float proj_info[4];
+
+ uint32_t orthogonal;
+ float edge_tolerance;
+ int32_t increment;
+ uint32_t pad;
+
+ int32_t screen_size[2];
+ uint32_t vertical;
+ uint32_t steps;
+ };
+ enum {
+ SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL,
+ SCREEN_SPACE_REFLECTION_FILTER_VERTICAL,
+ SCREEN_SPACE_REFLECTION_FILTER_MAX,
+ };
+
+ struct ScreenSpaceReflectionFilter {
+
+ ScreenSpaceReflectionFilterPushConstant push_constant;
+ ScreenSpaceReflectionFilterShaderRD shader;
+ RID shader_version;
+ RID pipelines[SCREEN_SPACE_REFLECTION_FILTER_MAX];
+ } ssr_filter;
+
+ struct ScreenSpaceReflectionScalePushConstant {
+
+ int32_t screen_size[2];
+ float camera_z_near;
+ float camera_z_far;
+
+ uint32_t orthogonal;
+ uint32_t filter;
+ uint32_t pad[2];
+ };
+
+ struct ScreenSpaceReflectionScale {
+
+ ScreenSpaceReflectionScalePushConstant push_constant;
+ ScreenSpaceReflectionScaleShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+ } ssr_scale;
+
+ struct SubSurfaceScatteringPushConstant {
+
+ int32_t screen_size[2];
+ float camera_z_far;
+ float camera_z_near;
+
+ uint32_t vertical;
+ uint32_t orthogonal;
+ float unit_size;
+ float scale;
+
+ float depth_scale;
+ uint32_t pad[3];
+ };
+
+ struct SubSurfaceScattering {
+
+ SubSurfaceScatteringPushConstant push_constant;
+ SubsurfaceScatteringShaderRD shader;
+ RID shader_version;
+ RID pipelines[3]; //3 quality levels
+ } sss;
+
+ RID default_sampler;
+ RID default_mipmap_sampler;
+ RID index_buffer;
+ RID index_array;
+
+ Map<RID, RID> texture_to_uniform_set_cache;
+
+ Map<RID, RID> image_to_uniform_set_cache;
+
+ struct TexturePair {
+ RID texture1;
+ RID texture2;
+ _FORCE_INLINE_ bool operator<(const TexturePair &p_pair) const {
+ if (texture1 == p_pair.texture1) {
+ return texture2 < p_pair.texture2;
+ } else {
+ return texture1 < p_pair.texture1;
+ }
+ }
+ };
+
+ Map<RID, RID> texture_to_compute_uniform_set_cache;
+ Map<TexturePair, RID> texture_pair_to_compute_uniform_set_cache;
+ Map<TexturePair, RID> image_pair_to_compute_uniform_set_cache;
+
+ RID _get_uniform_set_from_image(RID p_texture);
+ RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
+ RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
+ RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false);
+ RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
+
+public:
+ void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false);
+ void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false);
+ void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
+ void 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);
+ void 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 = false, bool p_panorama = false);
+ void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false);
+ void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
+
+ void 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);
+ void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
+ void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip);
+ void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
+ void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, RS::DOFBokehShape p_bokeh_shape, RS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
+
+ struct TonemapSettings {
+
+ bool use_glow = false;
+ enum GlowMode {
+ GLOW_MODE_ADD,
+ GLOW_MODE_SCREEN,
+ GLOW_MODE_SOFTLIGHT,
+ GLOW_MODE_REPLACE,
+ GLOW_MODE_MIX
+ };
+
+ GlowMode glow_mode = GLOW_MODE_ADD;
+ float glow_intensity = 1.0;
+ uint32_t glow_level_flags = 0;
+ Vector2i glow_texture_size;
+ bool glow_use_bicubic_upscale = false;
+ RID glow_texture;
+
+ RS::EnvironmentToneMapper tonemap_mode = RS::ENV_TONE_MAPPER_LINEAR;
+ float exposure = 1.0;
+ float white = 1.0;
+
+ bool use_auto_exposure = false;
+ float auto_exposure_grey = 0.5;
+ RID exposure_texture;
+
+ bool use_bcs = false;
+ float brightness = 1.0;
+ float contrast = 1.0;
+ float saturation = 1.0;
+
+ bool use_color_correction = false;
+ RID color_correction_texture;
+
+ bool use_fxaa = false;
+ Vector2i texture_size;
+ };
+
+ void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
+
+ void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness);
+
+ void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
+ void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
+ void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
+ void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *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);
+
+ void screen_space_reflection(RID p_diffuse, RID p_normal, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_roughness, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
+ void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
+ void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
+
+ RasterizerEffectsRD();
+ ~RasterizerEffectsRD();
+};
+
+#endif // !RASTERIZER_EFFECTS_RD_H
diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp
new file mode 100644
index 0000000000..9c54f0caae
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp
@@ -0,0 +1,177 @@
+/*************************************************************************/
+/* rasterizer_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer_rd.h"
+
+void RasterizerRD::prepare_for_blitting_render_targets() {
+ RD::get_singleton()->prepare_screen_for_drawing();
+}
+
+void RasterizerRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen);
+
+ for (int i = 0; i < p_amount; i++) {
+ RID texture = storage->render_target_get_texture(p_render_targets[i].render_target);
+ ERR_CONTINUE(texture.is_null());
+ RID rd_texture = storage->texture_get_rd_texture(texture);
+ ERR_CONTINUE(rd_texture.is_null());
+ if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) {
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(copy_viewports_sampler);
+ u.ids.push_back(rd_texture);
+ uniforms.push_back(u);
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, copy_viewports_rd_shader, 0);
+
+ render_target_descriptors[rd_texture] = uniform_set;
+ }
+
+ Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen));
+
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_viewports_rd_pipeline);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, copy_viewports_rd_array);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0);
+
+ float push_constant[4] = {
+ p_render_targets[i].rect.position.x / screen_size.width,
+ p_render_targets[i].rect.position.y / screen_size.height,
+ p_render_targets[i].rect.size.width / screen_size.width,
+ p_render_targets[i].rect.size.height / screen_size.height,
+ };
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, push_constant, 4 * sizeof(float));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ }
+
+ RD::get_singleton()->draw_list_end();
+}
+
+void RasterizerRD::begin_frame(double frame_step) {
+ frame++;
+ time += frame_step;
+ canvas->set_time(time);
+ scene->set_time(time, frame_step);
+}
+
+void RasterizerRD::end_frame(bool p_swap_buffers) {
+
+#ifndef _MSC_VER
+#warning TODO: likely passa bool to swap buffers to avoid display?
+#endif
+ RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?
+}
+
+void RasterizerRD::initialize() {
+
+ { //create framebuffer copy shader
+ RenderingDevice::ShaderStageData vert;
+ vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX;
+ vert.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_VERTEX,
+ "#version 450\n"
+ "layout(push_constant, binding = 0, std140) uniform Pos { vec4 dst_rect; } pos;\n"
+ "layout(location =0) out vec2 uv;\n"
+ "void main() { \n"
+ " vec2 base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0));\n"
+ " uv = base_arr[gl_VertexIndex];\n"
+ " vec2 vtx = pos.dst_rect.xy+uv*pos.dst_rect.zw;\n"
+ " gl_Position = vec4(vtx * 2.0 - 1.0,0.0,1.0);\n"
+ "}\n");
+
+ RenderingDevice::ShaderStageData frag;
+ frag.shader_stage = RenderingDevice::SHADER_STAGE_FRAGMENT;
+ frag.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_FRAGMENT,
+ "#version 450\n"
+ "layout (location = 0) in vec2 uv;\n"
+ "layout (location = 0) out vec4 color;\n"
+ "layout (binding = 0) uniform sampler2D src_rt;\n"
+ "void main() { color=texture(src_rt,uv); }\n");
+
+ Vector<RenderingDevice::ShaderStageData> source;
+ source.push_back(vert);
+ source.push_back(frag);
+ String error;
+ copy_viewports_rd_shader = RD::get_singleton()->shader_create(source);
+ if (!copy_viewports_rd_shader.is_valid()) {
+ print_line("Failed compilation: " + error);
+ }
+ }
+
+ { //create index array for copy shader
+ Vector<uint8_t> pv;
+ pv.resize(6 * 4);
+ {
+ uint8_t *w = pv.ptrw();
+ int *p32 = (int *)w;
+ p32[0] = 0;
+ p32[1] = 1;
+ p32[2] = 2;
+ p32[3] = 0;
+ p32[4] = 2;
+ p32[5] = 3;
+ }
+ copy_viewports_rd_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
+ copy_viewports_rd_array = RD::get_singleton()->index_array_create(copy_viewports_rd_index_buffer, 0, 6);
+ }
+
+ { //pipeline
+ copy_viewports_rd_pipeline = RD::get_singleton()->render_pipeline_create(copy_viewports_rd_shader, RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
+ }
+ { // sampler
+ copy_viewports_sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
+ }
+}
+
+ThreadWorkPool RasterizerRD::thread_work_pool;
+uint32_t RasterizerRD::frame = 1;
+
+void RasterizerRD::finalize() {
+
+ thread_work_pool.finish();
+
+ memdelete(scene);
+ memdelete(canvas);
+ memdelete(storage);
+
+ //only need to erase these, the rest are erased by cascade
+ RD::get_singleton()->free(copy_viewports_rd_index_buffer);
+ RD::get_singleton()->free(copy_viewports_rd_shader);
+ RD::get_singleton()->free(copy_viewports_sampler);
+}
+
+RasterizerRD::RasterizerRD() {
+ thread_work_pool.init();
+ time = 0;
+
+ storage = memnew(RasterizerStorageRD);
+ canvas = memnew(RasterizerCanvasRD(storage));
+ scene = memnew(RasterizerSceneHighEndRD(storage));
+}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.h b/servers/rendering/rasterizer_rd/rasterizer_rd.h
new file mode 100644
index 0000000000..756b9499ca
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_rd.h
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* rasterizer_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_RD_H
+#define RASTERIZER_RD_H
+
+#include "core/os/os.h"
+#include "core/thread_work_pool.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_canvas_rd.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
+
+class RasterizerRD : public Rasterizer {
+protected:
+ RasterizerCanvasRD *canvas;
+ RasterizerStorageRD *storage;
+ RasterizerSceneHighEndRD *scene;
+
+ RID copy_viewports_rd_shader;
+ RID copy_viewports_rd_pipeline;
+ RID copy_viewports_rd_index_buffer;
+ RID copy_viewports_rd_array;
+ RID copy_viewports_sampler;
+
+ Map<RID, RID> render_target_descriptors;
+
+ double time;
+
+ static uint32_t frame;
+
+public:
+ RasterizerStorage *get_storage() { return storage; }
+ RasterizerCanvas *get_canvas() { return canvas; }
+ RasterizerScene *get_scene() { return scene; }
+
+ void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {}
+
+ void initialize();
+ void begin_frame(double frame_step);
+ void prepare_for_blitting_render_targets();
+ void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
+
+ void end_frame(bool p_swap_buffers);
+ void finalize();
+
+ static _ALWAYS_INLINE_ uint64_t get_frame_number() { return frame; }
+
+ static Error is_viable() {
+ return OK;
+ }
+
+ static Rasterizer *_create_current() {
+ return memnew(RasterizerRD);
+ }
+
+ static void make_current() {
+ _create_func = _create_current;
+ }
+
+ virtual bool is_low_end() const { return false; }
+
+ static ThreadWorkPool thread_work_pool;
+
+ RasterizerRD();
+ ~RasterizerRD() {}
+};
+#endif // RASTERIZER_RD_H
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
new file mode 100644
index 0000000000..77096b95ba
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -0,0 +1,3209 @@
+/*************************************************************************/
+/* rasterizer_scene_high_end_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer_scene_high_end_rd.h"
+#include "core/project_settings.h"
+#include "servers/rendering/rendering_device.h"
+#include "servers/rendering/rendering_server_raster.h"
+
+static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.basis.elements[0][0];
+ p_array[1] = p_mtx.basis.elements[1][0];
+ p_array[2] = p_mtx.basis.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.basis.elements[0][1];
+ p_array[5] = p_mtx.basis.elements[1][1];
+ p_array[6] = p_mtx.basis.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.basis.elements[0][2];
+ p_array[9] = p_mtx.basis.elements[1][2];
+ p_array[10] = p_mtx.basis.elements[2][2];
+ p_array[11] = 0;
+ p_array[12] = p_mtx.origin.x;
+ p_array[13] = p_mtx.origin.y;
+ p_array[14] = p_mtx.origin.z;
+ p_array[15] = 1;
+}
+
+static _FORCE_INLINE_ void store_basis_3x4(const Basis &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.elements[0][0];
+ p_array[1] = p_mtx.elements[1][0];
+ p_array[2] = p_mtx.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.elements[0][1];
+ p_array[5] = p_mtx.elements[1][1];
+ p_array[6] = p_mtx.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.elements[0][2];
+ p_array[9] = p_mtx.elements[1][2];
+ p_array[10] = p_mtx.elements[2][2];
+ p_array[11] = 0;
+}
+
+static _FORCE_INLINE_ void store_transform_3x3(const Transform &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.basis.elements[0][0];
+ p_array[1] = p_mtx.basis.elements[1][0];
+ p_array[2] = p_mtx.basis.elements[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.basis.elements[0][1];
+ p_array[5] = p_mtx.basis.elements[1][1];
+ p_array[6] = p_mtx.basis.elements[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.basis.elements[0][2];
+ p_array[9] = p_mtx.basis.elements[1][2];
+ p_array[10] = p_mtx.basis.elements[2][2];
+ p_array[11] = 0;
+}
+
+static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+
+ p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ }
+ }
+}
+
+static _FORCE_INLINE_ void store_soft_shadow_kernel(const float *p_kernel, float *p_array) {
+
+ for (int i = 0; i < 128; i++) {
+ p_array[i] = p_kernel[i];
+ }
+}
+
+/* SCENE SHADER */
+void RasterizerSceneHighEndRD::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 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["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["NORMALMAP"] = &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;
+
+ RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::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
+
+ 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;
+ }
+
+ 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 = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness = 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++) {
+
+ 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;
+
+ if (uses_alpha || uses_blend_alpha) {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_VCT_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 (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || 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_VCT_COLOR_PASS || 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) {
+ blend_state = blend_state_depth_normal;
+ } 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_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+
+ } else {
+ //specular write
+ blend_state = blend_state_opaque_specular;
+ }
+ }
+
+ RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0);
+ }
+ }
+ }
+
+ valid = true;
+}
+
+void RasterizerSceneHighEndRD::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 RasterizerSceneHighEndRD::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().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);
+ }
+}
+
+bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RasterizerSceneHighEndRD::ShaderData::is_animated() const {
+ return false;
+}
+
+bool RasterizerSceneHighEndRD::ShaderData::casts_shadows() const {
+ return false;
+}
+Variant RasterizerSceneHighEndRD::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();
+}
+
+RasterizerSceneHighEndRD::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+RasterizerSceneHighEndRD::ShaderData::~ShaderData() {
+ RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::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);
+ }
+}
+
+RasterizerStorageRD::ShaderData *RasterizerSceneHighEndRD::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+
+void RasterizerSceneHighEndRD::MaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void RasterizerSceneHighEndRD::MaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+
+ RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::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());
+ }
+
+ 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.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.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);
+}
+
+RasterizerSceneHighEndRD::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);
+ }
+}
+
+RasterizerStorageRD::MaterialData *RasterizerSceneHighEndRD::_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;
+}
+
+RasterizerSceneHighEndRD::RenderBufferDataHighEnd::~RenderBufferDataHighEnd() {
+ clear();
+}
+
+void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() {
+
+ if (!specular.is_valid()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = width;
+ tf.height = height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ } else {
+ tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ specular = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ if (msaa == RS::VIEWPORT_MSAA_DISABLED) {
+
+ {
+ Vector<RID> fb;
+ fb.push_back(color);
+ fb.push_back(specular);
+ fb.push_back(depth);
+
+ color_specular_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ {
+ Vector<RID> fb;
+ fb.push_back(specular);
+
+ specular_only_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ } else {
+
+ tf.samples = texture_samples;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ {
+ Vector<RID> fb;
+ fb.push_back(color_msaa);
+ fb.push_back(specular_msaa);
+ fb.push_back(depth_msaa);
+
+ color_specular_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ {
+ Vector<RID> fb;
+ fb.push_back(specular_msaa);
+
+ specular_only_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ }
+ }
+}
+
+void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::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();
+ }
+
+ if (specular.is_valid()) {
+ if (specular_msaa.is_valid()) {
+ RD::get_singleton()->free(specular_msaa);
+ specular_msaa = RID();
+ }
+ RD::get_singleton()->free(specular);
+ specular = RID();
+ }
+
+ color = RID();
+ depth = RID();
+ color_specular_fb = RID();
+ specular_only_fb = RID();
+ color_fb = RID();
+ depth_fb = RID();
+
+ if (normal_buffer.is_valid()) {
+ RD::get_singleton()->free(normal_buffer);
+ if (normal_buffer_msaa.is_valid()) {
+ RD::get_singleton()->free(normal_buffer_msaa);
+ normal_buffer_msaa = RID();
+ }
+ normal_buffer = RID();
+ depth_normal_fb = RID();
+ }
+
+ if (roughness_buffer.is_valid()) {
+ RD::get_singleton()->free(roughness_buffer);
+ if (roughness_buffer_msaa.is_valid()) {
+ RD::get_singleton()->free(roughness_buffer_msaa);
+ roughness_buffer_msaa = RID();
+ }
+ roughness_buffer = RID();
+ depth_normal_roughness_fb = RID();
+ }
+}
+
+void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::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;
+
+ 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);
+ }
+ {
+ Vector<RID> fb;
+ fb.push_back(depth);
+
+ depth_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.type = RD::TEXTURE_TYPE_2D;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_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;
+
+ 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);
+ }
+ {
+ Vector<RID> fb;
+ fb.push_back(depth_msaa);
+
+ depth_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+ }
+}
+
+void RasterizerSceneHighEndRD::_allocate_normal_texture(RenderBufferDataHighEnd *rb) {
+ if (rb->normal_buffer.is_valid()) {
+ return;
+ }
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ } else {
+ tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ rb->normal_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) {
+ Vector<RID> fb;
+ fb.push_back(rb->depth);
+ fb.push_back(rb->normal_buffer);
+ rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb);
+ } else {
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ tf.samples = rb->texture_samples;
+ rb->normal_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ Vector<RID> fb;
+ fb.push_back(rb->depth_msaa);
+ fb.push_back(rb->normal_buffer_msaa);
+ rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ _render_buffers_clear_uniform_set(rb);
+}
+
+void RasterizerSceneHighEndRD::_allocate_roughness_texture(RenderBufferDataHighEnd *rb) {
+
+ if (rb->roughness_buffer.is_valid()) {
+ return;
+ }
+
+ ERR_FAIL_COND(rb->normal_buffer.is_null());
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ } else {
+ tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ rb->roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) {
+
+ Vector<RID> fb;
+ fb.push_back(rb->depth);
+ fb.push_back(rb->normal_buffer);
+ fb.push_back(rb->roughness_buffer);
+ rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb);
+ } else {
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ tf.samples = rb->texture_samples;
+ rb->roughness_buffer_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ Vector<RID> fb;
+ fb.push_back(rb->depth_msaa);
+ fb.push_back(rb->normal_buffer_msaa);
+ fb.push_back(rb->roughness_buffer_msaa);
+ rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ _render_buffers_clear_uniform_set(rb);
+}
+
+RasterizerSceneRD::RenderBufferData *RasterizerSceneHighEndRD::_create_render_buffer_data() {
+ return memnew(RenderBufferDataHighEnd);
+}
+
+bool RasterizerSceneHighEndRD::free(RID p_rid) {
+ if (RasterizerSceneRD::free(p_rid)) {
+ return true;
+ }
+ return false;
+}
+
+void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth) {
+
+ for (int i = 0; i < p_element_count; i++) {
+
+ const RenderList::Element *e = p_elements[i];
+ InstanceData &id = scene_state.instances[i];
+ store_transform(e->instance->transform, id.transform);
+ store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
+ id.flags = 0;
+ id.mask = e->instance->layer_mask;
+
+ if (e->instance->base_type == RS::INSTANCE_MULTIMESH) {
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ uint32_t stride;
+ if (storage->multimesh_get_transform_format(e->instance->base) == RS::MULTIMESH_TRANSFORM_2D) {
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ stride = 2;
+ } else {
+ stride = 3;
+ }
+ if (storage->multimesh_uses_colors(e->instance->base)) {
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ stride += 1;
+ }
+ if (storage->multimesh_uses_custom_data(e->instance->base)) {
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+ stride += 1;
+ }
+
+ id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
+ } else if (e->instance->base_type == RS::INSTANCE_MESH) {
+ if (e->instance->skeleton.is_valid()) {
+ id.flags |= INSTANCE_DATA_FLAG_SKELETON;
+ }
+ }
+
+ if (p_for_depth) {
+ id.gi_offset = 0xFFFFFFFF;
+ continue;
+ }
+
+ if (!e->instance->gi_probe_instances.empty()) {
+ uint32_t written = 0;
+ for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) {
+ RID probe = e->instance->gi_probe_instances[j];
+ int slot = gi_probe_instance_get_slot(probe);
+ if (slot < 0) {
+ continue; //unallocated, dont render
+ }
+
+ if (render_pass != gi_probe_instance_get_render_pass(probe)) {
+ continue; //not rendered in this frame
+ }
+
+ uint32_t index = gi_probe_instance_get_render_index(probe);
+
+ if (written == 0) {
+ id.gi_offset = index;
+ written = 1;
+ } else {
+ id.gi_offset = index << 16;
+ written = 2;
+ break;
+ }
+ }
+ if (written == 0) {
+ id.gi_offset = 0xFFFFFFFF;
+ } else if (written == 1) {
+ id.gi_offset |= 0xFFFF0000;
+ }
+ } else {
+ id.gi_offset = 0xFFFFFFFF;
+ }
+ }
+
+ RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true);
+}
+
+/// RENDERING ///
+
+void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set) {
+
+ 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);
+ if (p_radiance_uniform_set.is_valid()) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_radiance_uniform_set, RADIANCE_UNIFORM_SET);
+ } else {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_radiance_uniform_set, RADIANCE_UNIFORM_SET);
+ }
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, view_dependant_uniform_set, VIEW_DEPENDANT_UNIFORM_SET);
+ if (p_render_buffers_uniform_set.is_valid()) {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET);
+ } else {
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET);
+ }
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
+
+ MaterialData *prev_material = nullptr;
+
+ RID prev_vertex_array_rd;
+ RID prev_index_array_rd;
+ RID prev_pipeline_rd;
+ RID prev_xforms_uniform_set;
+
+ PushConstant push_constant;
+ zeromem(&push_constant, sizeof(PushConstant));
+
+ for (int i = 0; i < p_element_count; i++) {
+
+ const RenderList::Element *e = p_elements[i];
+
+ MaterialData *material = e->material;
+ ShaderData *shader = material->shader_data;
+ RID xforms_uniform_set;
+
+ //find cull variant
+ ShaderData::CullVariant cull_variant;
+
+ if ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && e->instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) {
+ cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED;
+ } else {
+ bool mirror = e->instance->mirror;
+ if (p_reverse_cull) {
+ mirror = !mirror;
+ }
+ cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL;
+ }
+
+ //find primitive and vertex format
+ RS::PrimitiveType primitive;
+
+ switch (e->instance->base_type) {
+ case RS::INSTANCE_MESH: {
+ primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index);
+ if (e->instance->skeleton.is_valid()) {
+ xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ }
+ } break;
+ case RS::INSTANCE_MULTIMESH: {
+ RID mesh = storage->multimesh_get_mesh(e->instance->base);
+ ERR_CONTINUE(!mesh.is_valid()); //should be a bug
+ primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index);
+
+ xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } break;
+ case RS::INSTANCE_IMMEDIATE: {
+ ERR_CONTINUE(true); //should be a bug
+ } break;
+ case RS::INSTANCE_PARTICLES: {
+ ERR_CONTINUE(true); //should be a bug
+ } break;
+ default: {
+ ERR_CONTINUE(true); //should be a bug
+ }
+ }
+
+ ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+
+ switch (p_pass_mode) {
+ case PASS_MODE_COLOR:
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ if (e->uses_lightmap) {
+ shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS;
+ } else if (e->uses_vct) {
+ shader_version = SHADER_VERSION_VCT_COLOR_PASS;
+ } else {
+ shader_version = SHADER_VERSION_COLOR_PASS;
+ }
+ } break;
+ case PASS_MODE_COLOR_SPECULAR: {
+ if (e->uses_lightmap) {
+ shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ } else if (e->uses_vct) {
+ shader_version = SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ } else {
+ shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ }
+ } break;
+ case PASS_MODE_SHADOW:
+ case PASS_MODE_DEPTH: {
+ shader_version = SHADER_VERSION_DEPTH_PASS;
+ } break;
+ case PASS_MODE_SHADOW_DP: {
+ shader_version = SHADER_VERSION_DEPTH_PASS_DP;
+ } break;
+ case PASS_MODE_DEPTH_NORMAL: {
+ shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL;
+ } break;
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
+ shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
+ } break;
+ case PASS_MODE_DEPTH_MATERIAL: {
+ shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ } break;
+ }
+
+ RenderPipelineVertexFormatCacheRD *pipeline = nullptr;
+
+ pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
+
+ RD::VertexFormatID vertex_format = -1;
+ RID vertex_array_rd;
+ RID index_array_rd;
+
+ switch (e->instance->base_type) {
+ case RS::INSTANCE_MESH: {
+ storage->mesh_surface_get_arrays_and_format(e->instance->base, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
+ } break;
+ case RS::INSTANCE_MULTIMESH: {
+ RID mesh = storage->multimesh_get_mesh(e->instance->base);
+ ERR_CONTINUE(!mesh.is_valid()); //should be a bug
+ storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
+ } break;
+ case RS::INSTANCE_IMMEDIATE: {
+ ERR_CONTINUE(true); //should be a bug
+ } break;
+ case RS::INSTANCE_PARTICLES: {
+ ERR_CONTINUE(true); //should be a bug
+ } break;
+ default: {
+ ERR_CONTINUE(true); //should be a bug
+ }
+ }
+
+ 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);
+
+ 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 != prev_material) {
+ //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 = material;
+ }
+
+ push_constant.index = i;
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PushConstant));
+
+ switch (e->instance->base_type) {
+ case RS::INSTANCE_MESH: {
+ RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid());
+ } break;
+ case RS::INSTANCE_MULTIMESH: {
+ uint32_t instances = storage->multimesh_get_instances_to_draw(e->instance->base);
+ RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances);
+ } break;
+ case RS::INSTANCE_IMMEDIATE: {
+
+ } break;
+ case RS::INSTANCE_PARTICLES: {
+
+ } break;
+ default: {
+ ERR_CONTINUE(true); //should be a bug
+ }
+ }
+ }
+}
+
+void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_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) {
+
+ //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
+ store_camera(projection, scene_state.ubo.projection_matrix);
+ store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
+ store_transform(p_cam_transform, scene_state.ubo.camera_matrix);
+ 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;
+
+ store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
+ store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
+ store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
+ 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();
+
+ scene_state.ubo.screen_pixel_size[0] = p_screen_pixel_size.x;
+ scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y;
+
+ 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;
+
+ 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_light_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_ambient_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;
+ 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);
+ 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;
+
+ } 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.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
+
+ RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true);
+}
+
+void RasterizerSceneHighEndRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index) {
+
+ RID m_src;
+
+ m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material;
+
+ if (unlikely(get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_DISABLED)) {
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
+ m_src = overdraw_material;
+ } else if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME) {
+ m_src = wireframe_material;
+ } else if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING) {
+ m_src = default_material;
+ }
+ }
+
+ MaterialData *material = nullptr;
+
+ if (m_src.is_valid()) {
+ material = (MaterialData *)storage->material_get_data(m_src, RasterizerStorageRD::SHADER_TYPE_3D);
+ if (!material || !material->shader_data->valid) {
+ material = nullptr;
+ }
+ }
+
+ if (!material) {
+ material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
+ m_src = default_material;
+ }
+
+ ERR_FAIL_COND(!material);
+
+ _add_geometry_with_material(p_instance, p_surface, material, m_src, p_pass_mode, p_geometry_index);
+
+ while (material->next_pass.is_valid()) {
+
+ material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D);
+ if (!material || !material->shader_data->valid)
+ break;
+ _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index);
+ }
+}
+
+void RasterizerSceneHighEndRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index) {
+
+ 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;
+
+ if (p_material->shader_data->uses_sss) {
+ scene_state.used_sss = true;
+ }
+
+ if (p_material->shader_data->uses_screen_texture) {
+ scene_state.used_screen_texture = true;
+ }
+
+ if (p_material->shader_data->uses_depth_texture) {
+ scene_state.used_depth_texture = true;
+ }
+
+ if (p_material->shader_data->uses_normal_texture) {
+ scene_state.used_normal_texture = true;
+ }
+
+ if (p_pass_mode != PASS_MODE_COLOR && p_pass_mode != PASS_MODE_COLOR_SPECULAR) {
+
+ if (has_blend_alpha || has_read_screen_alpha || (has_base_alpha && !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 || p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) {
+ //conditions in which no depth pass should be processed
+ return;
+ }
+
+ if (p_pass_mode != PASS_MODE_DEPTH_MATERIAL && !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) {
+ //shader does not use discard and does not write a vertex position, use generic material
+ if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) {
+ p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
+ } else if (p_pass_mode == PASS_MODE_DEPTH_NORMAL && !p_material->shader_data->uses_normal) {
+ p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
+ } else if (p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS && !p_material->shader_data->uses_normal && !p_material->shader_data->uses_roughness) {
+ p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
+ }
+ }
+
+ has_alpha = false;
+ }
+
+ RenderList::Element *e = (has_alpha || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) ? render_list.add_alpha_element() : render_list.add_element();
+
+ if (!e)
+ return;
+
+ e->instance = p_instance;
+ e->material = p_material;
+ e->surface_index = p_surface;
+ e->sort_key = 0;
+
+ if (e->material->last_pass != render_pass) {
+ if (!RD::get_singleton()->uniform_set_is_valid(e->material->uniform_set)) {
+ //uniform set no longer valid, probably a texture changed
+ storage->material_force_update_textures(p_material_rid, RasterizerStorageRD::SHADER_TYPE_3D);
+ }
+ e->material->last_pass = render_pass;
+ e->material->index = scene_state.current_material_index++;
+ if (e->material->shader_data->last_pass != render_pass) {
+ e->material->shader_data->last_pass = scene_state.current_material_index++;
+ e->material->shader_data->index = scene_state.current_shader_index++;
+ }
+ }
+ e->geometry_index = p_geometry_index;
+ e->material_index = e->material->index;
+ e->uses_instancing = e->instance->base_type == RS::INSTANCE_MULTIMESH;
+ e->uses_lightmap = e->instance->lightmap.is_valid();
+ e->uses_vct = e->instance->gi_probe_instances.size();
+ e->shader_index = e->shader_index;
+ e->depth_layer = e->instance->depth_layer;
+ e->priority = p_material->priority;
+
+ if (p_material->shader_data->uses_time) {
+ RenderingServerRaster::redraw_request();
+ }
+}
+
+void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi) {
+
+ scene_state.current_shader_index = 0;
+ scene_state.current_material_index = 0;
+ 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 geometry_index = 0;
+
+ //fill list
+
+ for (int i = 0; i < p_cull_count; i++) {
+
+ InstanceBase *inst = p_cull_result[i];
+
+ //add geometry for drawing
+ switch (inst->base_type) {
+
+ case RS::INSTANCE_MESH: {
+
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = storage->mesh_get_surface_count_and_materials(inst->base, surface_count);
+ if (!materials) {
+ continue; //nothing to do
+ }
+
+ const RID *inst_materials = inst->materials.ptr();
+
+ for (uint32_t j = 0; j < surface_count; j++) {
+
+ RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j];
+
+ uint32_t surface_index = storage->mesh_surface_get_render_pass_index(inst->base, j, render_pass, &geometry_index);
+ _add_geometry(inst, j, material, p_pass_mode, surface_index);
+ }
+
+ //mesh->last_pass=frame;
+
+ } break;
+
+ case RS::INSTANCE_MULTIMESH: {
+
+ if (storage->multimesh_get_instances_to_draw(inst->base) == 0) {
+ //not visible, 0 instances
+ continue;
+ }
+
+ RID mesh = storage->multimesh_get_mesh(inst->base);
+ 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) {
+ continue; //nothing to do
+ }
+
+ for (uint32_t j = 0; j < surface_count; j++) {
+
+ uint32_t surface_index = storage->mesh_surface_get_multimesh_render_pass_index(mesh, j, render_pass, &geometry_index);
+ _add_geometry(inst, j, materials[j], p_pass_mode, surface_index);
+ }
+
+ } 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;
+ case RS::INSTANCE_PARTICLES: {
+
+ RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(inst->base);
+ ERR_CONTINUE(!particles);
+
+ for (int j = 0; j < particles->draw_passes.size(); j++) {
+
+ RID pmesh = particles->draw_passes[j];
+ if (!pmesh.is_valid())
+ continue;
+ RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(pmesh);
+ if (!mesh)
+ continue; //mesh not assigned
+
+ int ssize = mesh->surfaces.size();
+
+ for (int k = 0; k < ssize; k++) {
+
+ RasterizerStorageGLES3::Surface *s = mesh->surfaces[k];
+ _add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass);
+ }
+ }
+
+ } break;
+#endif
+ default: {
+ }
+ }
+ }
+}
+
+void RasterizerSceneHighEndRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) {
+
+ for (int i = 0; i < p_reflection_probe_cull_count; i++) {
+
+ RID rpi = p_reflection_probe_cull_result[i];
+
+ if (i >= (int)scene_state.max_reflections) {
+ reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set
+ continue;
+ }
+
+ reflection_probe_instance_set_render_index(rpi, i);
+
+ RID base_probe = reflection_probe_instance_get_probe(rpi);
+
+ ReflectionData &reflection_ubo = scene_state.reflections[i];
+
+ Vector3 extents = storage->reflection_probe_get_extents(base_probe);
+
+ reflection_ubo.box_extents[0] = extents.x;
+ reflection_ubo.box_extents[1] = extents.y;
+ reflection_ubo.box_extents[2] = extents.z;
+ reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi);
+
+ Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe);
+
+ reflection_ubo.box_offset[0] = origin_offset.x;
+ reflection_ubo.box_offset[1] = origin_offset.y;
+ reflection_ubo.box_offset[2] = origin_offset.z;
+ reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe);
+
+ float intensity = storage->reflection_probe_get_intensity(base_probe);
+ bool interior = storage->reflection_probe_is_interior(base_probe);
+ bool box_projection = storage->reflection_probe_is_box_projection(base_probe);
+
+ reflection_ubo.params[0] = intensity;
+ reflection_ubo.params[1] = 0;
+ reflection_ubo.params[2] = interior ? 1.0 : 0.0;
+ reflection_ubo.params[3] = box_projection ? 1.0 : 0.0;
+
+ if (interior) {
+ Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear();
+ float interior_ambient_energy = storage->reflection_probe_get_interior_ambient_energy(base_probe);
+ float interior_ambient_probe_contrib = storage->reflection_probe_get_interior_ambient_probe_contribution(base_probe);
+ reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy;
+ reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
+ reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
+ reflection_ubo.ambient[3] = interior_ambient_probe_contrib;
+ } else {
+ Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear();
+ if (is_environment(p_environment)) {
+ Color env_ambient_color = environment_get_ambient_light_color(p_environment).to_linear();
+ float env_ambient_energy = environment_get_ambient_light_ambient_energy(p_environment);
+ ambient_linear = env_ambient_color;
+ ambient_linear.r *= env_ambient_energy;
+ ambient_linear.g *= env_ambient_energy;
+ ambient_linear.b *= env_ambient_energy;
+ }
+
+ reflection_ubo.ambient[0] = ambient_linear.r;
+ reflection_ubo.ambient[1] = ambient_linear.g;
+ reflection_ubo.ambient[2] = ambient_linear.b;
+ reflection_ubo.ambient[3] = 0; //not used in exterior mode, since it just blends with regular ambient light
+ }
+
+ Transform transform = reflection_probe_instance_get_transform(rpi);
+ Transform proj = (p_camera_inverse_transform * transform).inverse();
+ store_transform(proj, reflection_ubo.local_matrix);
+
+ cluster_builder.add_reflection_probe(transform, extents);
+
+ reflection_probe_instance_set_render_pass(rpi, render_pass);
+ }
+
+ if (p_reflection_probe_cull_count) {
+ RD::get_singleton()->buffer_update(scene_state.reflection_buffer, 0, MIN(scene_state.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), scene_state.reflections, true);
+ }
+}
+
+void RasterizerSceneHighEndRD::_setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform) {
+
+ int index = 0;
+
+ for (int i = 0; i < p_gi_probe_probe_cull_count; i++) {
+
+ RID rpi = p_gi_probe_probe_cull_result[i];
+
+ if (index >= (int)scene_state.max_gi_probes) {
+ continue;
+ }
+
+ int slot = gi_probe_instance_get_slot(rpi);
+ if (slot < 0) {
+ continue; //not usable
+ }
+
+ RID base_probe = gi_probe_instance_get_base_probe(rpi);
+
+ GIProbeData &gi_probe_ubo = scene_state.gi_probes[index];
+
+ Transform to_cell = gi_probe_instance_get_transform_to_cell(rpi) * p_camera_transform;
+
+ store_transform(to_cell, gi_probe_ubo.xform);
+
+ Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
+
+ gi_probe_ubo.bounds[0] = bounds.x;
+ gi_probe_ubo.bounds[1] = bounds.y;
+ gi_probe_ubo.bounds[2] = bounds.z;
+
+ gi_probe_ubo.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
+ gi_probe_ubo.bias = storage->gi_probe_get_bias(base_probe);
+ gi_probe_ubo.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
+ gi_probe_ubo.blend_ambient = !storage->gi_probe_is_interior(base_probe);
+ gi_probe_ubo.texture_slot = gi_probe_instance_get_slot(rpi);
+ gi_probe_ubo.anisotropy_strength = storage->gi_probe_get_anisotropy_strength(base_probe);
+ gi_probe_ubo.ao = storage->gi_probe_get_ao(base_probe);
+ gi_probe_ubo.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
+
+ if (gi_probe_is_anisotropic()) {
+ gi_probe_ubo.texture_slot *= 3;
+ }
+
+ gi_probe_instance_set_render_index(rpi, index);
+ gi_probe_instance_set_render_pass(rpi, render_pass);
+
+ index++;
+ }
+
+ if (index) {
+ RD::get_singleton()->buffer_update(scene_state.gi_probe_buffer, 0, index * sizeof(GIProbeData), scene_state.gi_probes, true);
+ }
+}
+
+void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows) {
+
+ uint32_t light_count = 0;
+ scene_state.ubo.directional_light_count = 0;
+ sky_scene_state.directional_light_count = 0;
+
+ for (int i = 0; i < p_light_cull_count; i++) {
+
+ RID li = p_light_cull_result[i];
+ RID base = light_instance_get_base_light(li);
+
+ ERR_CONTINUE(base.is_null());
+
+ RS::LightType type = storage->light_get_type(base);
+ switch (type) {
+
+ case RS::LIGHT_DIRECTIONAL: {
+
+ if (scene_state.ubo.directional_light_count >= scene_state.max_directional_lights) {
+ continue;
+ }
+
+ DirectionalLightData &light_data = scene_state.directional_lights[scene_state.ubo.directional_light_count];
+
+ Transform light_transform = light_instance_get_base_transform(li);
+
+ Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+
+ light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+
+ Color linear_col = storage->light_get_color(base).to_linear();
+ light_data.color[0] = linear_col.r;
+ light_data.color[1] = linear_col.g;
+ light_data.color[2] = linear_col.b;
+
+ light_data.specular = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
+ light_data.mask = storage->light_get_cull_mask(base);
+
+ float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+
+ Color shadow_col = storage->light_get_shadow_color(base).to_linear();
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
+ light_data.shadow_color1[0] = 1.0;
+ light_data.shadow_color1[1] = 0.0;
+ light_data.shadow_color1[2] = 0.0;
+ light_data.shadow_color1[3] = 1.0;
+ light_data.shadow_color2[0] = 0.0;
+ light_data.shadow_color2[1] = 1.0;
+ light_data.shadow_color2[2] = 0.0;
+ light_data.shadow_color2[3] = 1.0;
+ light_data.shadow_color3[0] = 0.0;
+ light_data.shadow_color3[1] = 0.0;
+ light_data.shadow_color3[2] = 1.0;
+ light_data.shadow_color3[3] = 1.0;
+ light_data.shadow_color4[0] = 1.0;
+ light_data.shadow_color4[1] = 1.0;
+ light_data.shadow_color4[2] = 0.0;
+ light_data.shadow_color4[3] = 1.0;
+
+ } else {
+
+ light_data.shadow_color1[0] = shadow_col.r;
+ light_data.shadow_color1[1] = shadow_col.g;
+ light_data.shadow_color1[2] = shadow_col.b;
+ light_data.shadow_color1[3] = 1.0;
+ light_data.shadow_color2[0] = shadow_col.r;
+ light_data.shadow_color2[1] = shadow_col.g;
+ light_data.shadow_color2[2] = shadow_col.b;
+ light_data.shadow_color2[3] = 1.0;
+ light_data.shadow_color3[0] = shadow_col.r;
+ light_data.shadow_color3[1] = shadow_col.g;
+ light_data.shadow_color3[2] = shadow_col.b;
+ light_data.shadow_color3[3] = 1.0;
+ light_data.shadow_color4[0] = shadow_col.r;
+ light_data.shadow_color4[1] = shadow_col.g;
+ light_data.shadow_color4[2] = shadow_col.b;
+ light_data.shadow_color4[3] = 1.0;
+ }
+
+ light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base);
+
+ if (light_data.shadow_enabled) {
+
+ RS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base);
+
+ int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
+ light_data.blend_splits = storage->light_directional_get_blend_splits(base);
+ for (int j = 0; j < 4; j++) {
+ Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j);
+ CameraMatrix matrix = light_instance_get_shadow_camera(li, j);
+ float split = light_instance_get_directional_shadow_split(li, MIN(limit, j));
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+ CameraMatrix rectm;
+ rectm.set_light_atlas_rect(atlas_rect);
+
+ Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse();
+
+ CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
+ light_data.shadow_split_offsets[j] = split;
+ float bias_scale = light_instance_get_shadow_bias_scale(li, j);
+ light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;
+ light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * light_instance_get_directional_shadow_texel_size(li, j);
+ light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
+ light_data.shadow_transmittance_z_scale[j] = light_instance_get_shadow_range(li, j);
+ light_data.shadow_range_begin[j] = light_instance_get_shadow_range_begin(li, j);
+ store_camera(shadow_mtx, light_data.shadow_matrices[j]);
+
+ Vector2 uv_scale = light_instance_get_shadow_uv_scale(li, j);
+ uv_scale *= atlas_rect.size; //adapt to atlas size
+ switch (j) {
+ case 0: {
+ light_data.uv_scale1[0] = uv_scale.x;
+ light_data.uv_scale1[1] = uv_scale.y;
+ } break;
+ case 1: {
+ light_data.uv_scale2[0] = uv_scale.x;
+ light_data.uv_scale2[1] = uv_scale.y;
+ } break;
+ case 2: {
+ light_data.uv_scale3[0] = uv_scale.x;
+ light_data.uv_scale3[1] = uv_scale.y;
+ } break;
+ case 3: {
+ light_data.uv_scale4[0] = uv_scale.x;
+ light_data.uv_scale4[1] = uv_scale.y;
+ } break;
+ }
+ }
+
+ float fade_start = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
+ light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
+ light_data.fade_to = -light_data.shadow_split_offsets[3];
+
+ light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
+
+ float softshadow_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (softshadow_angle > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // technically this will keep expanding until reaching the sun, but all we care
+ // is expand until we reach the radius of the near plane (there can't be more occluders than that)
+ light_data.softshadow_angle = Math::tan(Math::deg2rad(softshadow_angle));
+ } else {
+ light_data.softshadow_angle = 0;
+ light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
+ }
+ }
+
+ // Copy to SkyDirectionalLightData
+ if (sky_scene_state.directional_light_count < sky_scene_state.max_directional_lights) {
+
+ SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.directional_light_count];
+
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = -world_direction.z;
+
+ sky_light_data.energy = light_data.energy / Math_PI;
+
+ sky_light_data.color[0] = light_data.color[0];
+ sky_light_data.color[1] = light_data.color[1];
+ sky_light_data.color[2] = light_data.color[2];
+
+ sky_light_data.enabled = true;
+ sky_scene_state.directional_light_count++;
+ }
+
+ scene_state.ubo.directional_light_count++;
+ } break;
+ case RS::LIGHT_SPOT:
+ case RS::LIGHT_OMNI: {
+
+ if (light_count >= scene_state.max_lights) {
+ continue;
+ }
+
+ Transform light_transform = light_instance_get_base_transform(li);
+
+ LightData &light_data = scene_state.lights[light_count];
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+ Color linear_col = storage->light_get_color(base).to_linear();
+
+ light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION));
+ light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI);
+
+ light_data.color_specular[0] = MIN(uint32_t(linear_col.r * 255), 255);
+ light_data.color_specular[1] = MIN(uint32_t(linear_col.g * 255), 255);
+ light_data.color_specular[2] = MIN(uint32_t(linear_col.b * 255), 255);
+ light_data.color_specular[3] = MIN(uint32_t(storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 255), 255);
+
+ float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
+ light_data.inv_radius = 1.0 / radius;
+
+ Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin);
+
+ light_data.position[0] = pos.x;
+ light_data.position[1] = pos.y;
+ light_data.position[2] = pos.z;
+
+ Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float size = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+
+ light_data.size = size;
+
+ light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION));
+ float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
+ light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle)));
+
+ light_data.mask = storage->light_get_cull_mask(base);
+
+ light_data.atlas_rect[0] = 0;
+ light_data.atlas_rect[1] = 0;
+ light_data.atlas_rect[2] = 0;
+ light_data.atlas_rect[3] = 0;
+
+ RID projector = storage->light_get_projector(base);
+
+ if (projector.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(projector);
+
+ if (type == RS::LIGHT_SPOT) {
+
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = -rect.size.height;
+ } else {
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y;
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
+ }
+ } else {
+ light_data.projector_rect[0] = 0;
+ light_data.projector_rect[1] = 0;
+ light_data.projector_rect[2] = 0;
+ light_data.projector_rect[3] = 0;
+ }
+
+ if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
+ // fill in the shadow information
+
+ Color shadow_color = storage->light_get_shadow_color(base);
+
+ light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255);
+ light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255);
+ light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255);
+ light_data.shadow_color_enabled[3] = 255;
+
+ if (type == RS::LIGHT_SPOT) {
+ light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0);
+ float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0;
+ shadow_texel_size *= light_instance_get_shadow_texel_size(li, p_shadow_atlas);
+
+ light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size;
+
+ } else { //omni
+ light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0;
+ float shadow_texel_size = light_instance_get_shadow_texel_size(li, p_shadow_atlas);
+ light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space
+ }
+
+ light_data.transmittance_bias = storage->light_get_transmittance_bias(base);
+
+ Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas);
+
+ light_data.atlas_rect[0] = rect.position.x;
+ light_data.atlas_rect[1] = rect.position.y;
+ light_data.atlas_rect[2] = rect.size.width;
+ light_data.atlas_rect[3] = rect.size.height;
+
+ light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
+
+ if (type == RS::LIGHT_OMNI) {
+
+ light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another
+ Transform proj = (p_camera_inverse_transform * light_transform).inverse();
+
+ store_transform(proj, light_data.shadow_matrix);
+
+ if (size > 0.0) {
+
+ light_data.soft_shadow_size = size;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
+ }
+
+ } else if (type == RS::LIGHT_SPOT) {
+
+ Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
+ CameraMatrix bias;
+ bias.set_light_bias();
+
+ CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview;
+ store_camera(shadow_mtx, light_data.shadow_matrix);
+
+ if (size > 0.0) {
+ CameraMatrix cm = light_instance_get_shadow_camera(li, 0);
+ float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle));
+ light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
+ }
+ }
+ } else {
+ light_data.shadow_color_enabled[3] = 0;
+ }
+
+ light_instance_set_index(li, light_count);
+
+ cluster_builder.add_light(type == RS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
+
+ light_count++;
+ } break;
+ }
+
+ light_instance_set_render_pass(li, render_pass);
+
+ //update UBO for forward rendering, blit to texture for clustered
+ }
+
+ if (light_count) {
+ RD::get_singleton()->buffer_update(scene_state.light_buffer, 0, sizeof(LightData) * light_count, scene_state.lights, true);
+ }
+
+ if (scene_state.ubo.directional_light_count) {
+ RD::get_singleton()->buffer_update(scene_state.directional_light_buffer, 0, sizeof(DirectionalLightData) * scene_state.ubo.directional_light_count, scene_state.directional_lights, true);
+ }
+}
+
+void RasterizerSceneHighEndRD::_setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform) {
+
+ Transform uv_xform;
+ uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
+ uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
+
+ p_decal_count = MIN((uint32_t)p_decal_count, scene_state.max_decals);
+ int idx = 0;
+ for (int i = 0; i < p_decal_count; i++) {
+
+ RID di = p_decal_instances[i];
+ RID decal = decal_instance_get_base(di);
+
+ Transform xform = decal_instance_get_transform(di);
+
+ float fade = 1.0;
+
+ if (storage->decal_is_distance_fade_enabled(decal)) {
+ real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+ float fade_begin = storage->decal_get_distance_fade_begin(decal);
+ float fade_length = storage->decal_get_distance_fade_length(decal);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ continue; // do not use this decal, its invisible
+ }
+
+ fade = 1.0 - (distance - fade_begin) / fade_length;
+ }
+ }
+
+ DecalData &dd = scene_state.decals[idx];
+
+ Vector3 decal_extents = storage->decal_get_extents(decal);
+
+ Transform scale_xform;
+ scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z));
+ Transform to_decal_xform = (p_camera_inverse_xform * decal_instance_get_transform(di) * scale_xform * uv_xform).affine_inverse();
+ store_transform(to_decal_xform, dd.xform);
+
+ Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized();
+ normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
+
+ dd.normal[0] = normal.x;
+ dd.normal[1] = normal.y;
+ dd.normal[2] = normal.z;
+ dd.normal_fade = storage->decal_get_normal_fade(decal);
+
+ RID albedo_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO);
+ RID emission_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION);
+ if (albedo_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(albedo_tex);
+ dd.albedo_rect[0] = rect.position.x;
+ dd.albedo_rect[1] = rect.position.y;
+ dd.albedo_rect[2] = rect.size.x;
+ dd.albedo_rect[3] = rect.size.y;
+ } else {
+
+ if (!emission_tex.is_valid()) {
+ continue; //no albedo, no emission, no decal.
+ }
+ dd.albedo_rect[0] = 0;
+ dd.albedo_rect[1] = 0;
+ dd.albedo_rect[2] = 0;
+ dd.albedo_rect[3] = 0;
+ }
+
+ RID normal_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL);
+
+ if (normal_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(normal_tex);
+ dd.normal_rect[0] = rect.position.x;
+ dd.normal_rect[1] = rect.position.y;
+ dd.normal_rect[2] = rect.size.x;
+ dd.normal_rect[3] = rect.size.y;
+
+ Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
+ store_basis_3x4(normal_xform, dd.normal_xform);
+ } else {
+ dd.normal_rect[0] = 0;
+ dd.normal_rect[1] = 0;
+ dd.normal_rect[2] = 0;
+ dd.normal_rect[3] = 0;
+ }
+
+ RID orm_tex = storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM);
+ if (orm_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(orm_tex);
+ dd.orm_rect[0] = rect.position.x;
+ dd.orm_rect[1] = rect.position.y;
+ dd.orm_rect[2] = rect.size.x;
+ dd.orm_rect[3] = rect.size.y;
+ } else {
+ dd.orm_rect[0] = 0;
+ dd.orm_rect[1] = 0;
+ dd.orm_rect[2] = 0;
+ dd.orm_rect[3] = 0;
+ }
+
+ if (emission_tex.is_valid()) {
+ Rect2 rect = storage->decal_atlas_get_texture_rect(emission_tex);
+ dd.emission_rect[0] = rect.position.x;
+ dd.emission_rect[1] = rect.position.y;
+ dd.emission_rect[2] = rect.size.x;
+ dd.emission_rect[3] = rect.size.y;
+ } else {
+ dd.emission_rect[0] = 0;
+ dd.emission_rect[1] = 0;
+ dd.emission_rect[2] = 0;
+ dd.emission_rect[3] = 0;
+ }
+
+ Color modulate = storage->decal_get_modulate(decal);
+ dd.modulate[0] = modulate.r;
+ dd.modulate[1] = modulate.g;
+ dd.modulate[2] = modulate.b;
+ dd.modulate[3] = modulate.a * fade;
+ dd.emission_energy = storage->decal_get_emission_energy(decal) * fade;
+ dd.albedo_mix = storage->decal_get_albedo_mix(decal);
+ dd.mask = storage->decal_get_cull_mask(decal);
+ dd.upper_fade = storage->decal_get_upper_fade(decal);
+ dd.lower_fade = storage->decal_get_lower_fade(decal);
+
+ cluster_builder.add_decal(xform, decal_extents);
+
+ idx++;
+ }
+
+ if (idx > 0) {
+ RD::get_singleton()->buffer_update(scene_state.decal_buffer, 0, sizeof(DecalData) * idx, scene_state.decals, true);
+ }
+}
+
+void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, 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) {
+
+ RenderBufferDataHighEnd *render_buffer = nullptr;
+ if (p_render_buffer.is_valid()) {
+ render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffer);
+ }
+
+ //first of all, make a new render pass
+ render_pass++;
+
+ //fill up ubo
+
+ RENDER_TIMESTAMP("Setup 3D Scene");
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ p_light_cull_count = 0;
+ p_reflection_probe_cull_count = 0;
+ p_gi_probe_cull_count = 0;
+ }
+
+ bool using_shadows = true;
+
+ if (p_reflection_probe.is_valid()) {
+ scene_state.ubo.reflection_multiplier = 0.0;
+ if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) {
+ using_shadows = false;
+ }
+ } else {
+ scene_state.ubo.reflection_multiplier = 1.0;
+ }
+
+ //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size;
+
+ 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;
+
+ Size2 screen_pixel_size;
+ Size2i screen_size;
+ RID opaque_framebuffer;
+ RID opaque_specular_framebuffer;
+ RID depth_framebuffer;
+ RID alpha_framebuffer;
+
+ PassMode depth_pass_mode = PASS_MODE_DEPTH;
+ Vector<Color> depth_pass_clear;
+ bool using_separate_specular = false;
+ bool using_ssr = false;
+
+ if (render_buffer) {
+
+ screen_pixel_size.width = 1.0 / render_buffer->width;
+ screen_pixel_size.height = 1.0 / render_buffer->height;
+ screen_size.x = render_buffer->width;
+ screen_size.y = render_buffer->height;
+
+ opaque_framebuffer = render_buffer->color_fb;
+
+ if (p_environment.is_valid() && environment_is_ssr_enabled(p_environment)) {
+ depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
+ render_buffer->ensure_specular();
+ using_separate_specular = true;
+ using_ssr = true;
+ opaque_specular_framebuffer = render_buffer->color_specular_fb;
+ } else if (screen_space_roughness_limiter_is_active()) {
+ depth_pass_mode = PASS_MODE_DEPTH_NORMAL;
+ //we need to allocate both these, if not allocated
+ _allocate_normal_texture(render_buffer);
+ _allocate_roughness_texture(render_buffer);
+ } else if (p_environment.is_valid() && (environment_is_ssao_enabled(p_environment) || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) {
+ depth_pass_mode = PASS_MODE_DEPTH_NORMAL;
+ }
+
+ switch (depth_pass_mode) {
+ case PASS_MODE_DEPTH: {
+ depth_framebuffer = render_buffer->depth_fb;
+ } break;
+ case PASS_MODE_DEPTH_NORMAL: {
+ _allocate_normal_texture(render_buffer);
+ depth_framebuffer = render_buffer->depth_normal_fb;
+ depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
+ } break;
+ case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
+ _allocate_normal_texture(render_buffer);
+ _allocate_roughness_texture(render_buffer);
+ depth_framebuffer = render_buffer->depth_normal_roughness_fb;
+ depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
+ depth_pass_clear.push_back(Color());
+ } break;
+ default: {
+ };
+ }
+
+ alpha_framebuffer = opaque_framebuffer;
+
+ } else if (p_reflection_probe.is_valid()) {
+ uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe);
+ screen_pixel_size.width = 1.0 / resolution;
+ screen_pixel_size.height = 1.0 / resolution;
+ screen_size.x = resolution;
+ screen_size.y = resolution;
+
+ opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass);
+ depth_framebuffer = reflection_probe_instance_get_depth_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
+ }
+
+ } else {
+ ERR_FAIL(); //bug?
+ }
+
+ cluster_builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster
+
+ _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
+ _setup_decals(p_decal_cull_result, p_decal_cull_count, p_cam_transform.affine_inverse());
+ _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
+ _setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
+ _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_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);
+
+ cluster_builder.bake_cluster(); //bake to cluster
+
+ _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
+
+ render_list.clear();
+ _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
+
+ 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;
+ render_buffer->ensure_specular();
+ using_separate_specular = true;
+ opaque_specular_framebuffer = render_buffer->color_specular_fb;
+ }
+ RID radiance_uniform_set;
+ bool draw_sky = false;
+
+ Color clear_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;
+ } 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;
+ } break;
+ case RS::ENV_BG_SKY: {
+ RID sky = environment_get_sky(p_environment);
+ if (sky.is_valid()) {
+
+ RENDER_TIMESTAMP("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;
+ }
+
+ _setup_sky(p_environment, p_cam_transform.origin, screen_size);
+ _update_sky(p_environment, projection, p_cam_transform);
+ radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
+
+ 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: {
+ }
+ }
+ } else {
+
+ clear_color = p_default_bg_color;
+ }
+
+ _setup_view_dependant_uniform_set(p_shadow_atlas, p_reflection_atlas);
+
+ render_list.sort_by_key(false);
+
+ _fill_instances(render_list.elements, render_list.element_count, false);
+
+ 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 depth_pre_pass = depth_framebuffer.is_valid();
+ RID render_buffers_uniform_set;
+
+ bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment);
+
+ if (depth_pre_pass) { //depth pre pass
+ RENDER_TIMESTAMP("Render Depth Pre-Pass");
+
+ bool finish_depth = using_ssao;
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, depth_pass_clear);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID());
+ RD::get_singleton()->draw_list_end();
+
+ if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ if (finish_depth) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth, true);
+ }
+
+ if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->normal_buffer_msaa, render_buffer->normal_buffer, true);
+ if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->roughness_buffer_msaa, render_buffer->roughness_buffer, true);
+ }
+ }
+ }
+ }
+
+ if (using_ssao) {
+ _process_ssao(p_render_buffer, p_environment, render_buffer->normal_buffer, p_cam_projection);
+ }
+
+ if (p_render_buffer.is_valid() && screen_space_roughness_limiter_is_active()) {
+ storage->get_effects()->roughness_limit(render_buffer->normal_buffer, render_buffer->roughness_buffer, Size2(render_buffer->width, render_buffer->height), screen_space_roughness_limiter_get_curve());
+ }
+
+ if (p_render_buffer.is_valid()) {
+ //update the render buffers uniform set in case it changed
+ _update_render_buffers_uniform_set(p_render_buffer);
+ render_buffers_uniform_set = render_buffer->uniform_set;
+ }
+
+ _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_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");
+
+ 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 || debug_giprobes);
+ bool will_continue_depth = (can_continue_depth || draw_sky || debug_giprobes);
+
+ //regular forward for now
+ Vector<Color> c;
+ if (using_separate_specular) {
+ Color cc = clear_color.to_linear();
+ cc.a = 0; //subsurf scatter must be 0
+ c.push_back(cc);
+ c.push_back(Color(0, 0, 0, 0));
+ } else {
+ c.push_back(clear_color.to_linear());
+ }
+
+ RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(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 ? (using_ssao ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set);
+ RD::get_singleton()->draw_list_end();
+
+ if (will_continue_color && using_separate_specular) {
+ // close the specular framebuffer, as it's no longer used
+ draw_list = RD::get_singleton()->draw_list_begin(render_buffer->specular_only_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ if (debug_giprobes) {
+ //debug giprobes
+ bool will_continue_color = (can_continue_color || draw_sky);
+ bool will_continue_depth = (can_continue_depth || draw_sky);
+
+ CameraMatrix dc;
+ dc.set_depth_correction(true);
+ CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());
+ 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);
+ for (int i = 0; i < p_gi_probe_cull_count; i++) {
+ _debug_giprobe(p_gi_probe_cull_result[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_list_end();
+ }
+
+ if (draw_sky) {
+ 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;
+ }
+
+ _draw_sky(can_continue_color, can_continue_depth, opaque_framebuffer, p_environment, projection, p_cam_transform);
+ }
+
+ 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, true);
+ if (using_separate_specular) {
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular, true);
+ }
+ }
+
+ 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, true);
+ }
+
+ if (using_separate_specular) {
+
+ if (using_sss) {
+ RENDER_TIMESTAMP("Sub Surface Scattering");
+ _process_sss(p_render_buffer, p_cam_projection);
+ }
+
+ if (using_ssr) {
+ RENDER_TIMESTAMP("Screen Space Reflection");
+ _process_ssr(p_render_buffer, render_buffer->color_fb, render_buffer->normal_buffer, render_buffer->roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_environment, p_cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED);
+ } else {
+ //just mix specular back
+ RENDER_TIMESTAMP("Merge Specular");
+ storage->get_effects()->merge_specular(render_buffer->color_fb, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID());
+ }
+ }
+
+ RENDER_TIMESTAMP("Render Transparent Pass");
+
+ _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_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);
+
+ render_list.sort_by_reverse_depth_and_priority(true);
+
+ _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false);
+
+ {
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(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);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+
+ RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color, true);
+ }
+}
+
+void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, 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) {
+
+ RENDER_TIMESTAMP("Setup Rendering Shadow");
+
+ _update_render_base_uniform_set();
+
+ render_pass++;
+
+ scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+
+ _setup_environment(RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar, false, p_use_pancake);
+
+ render_list.clear();
+
+ PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
+
+ _fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
+
+ _setup_view_dependant_uniform_set(RID(), RID());
+
+ RENDER_TIMESTAMP("Render Shadow");
+
+ render_list.sort_by_key(false);
+
+ _fill_instances(render_list.elements, render_list.element_count, true);
+
+ {
+ //regular forward for now
+ 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);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, RID(), RID());
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
+void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
+ RENDER_TIMESTAMP("Setup Rendering Shadow");
+
+ _update_render_base_uniform_set();
+
+ render_pass++;
+
+ scene_state.ubo.dual_paraboloid_side = 0;
+
+ _setup_environment(RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0);
+
+ render_list.clear();
+
+ PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
+ _fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
+
+ _setup_view_dependant_uniform_set(RID(), RID());
+
+ RENDER_TIMESTAMP("Render Material");
+
+ render_list.sort_by_key(false);
+
+ _fill_instances(render_list.elements, render_list.element_count, 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);
+ _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID());
+ RD::get_singleton()->draw_list_end();
+ }
+}
+
+void RasterizerSceneHighEndRD::_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 RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
+
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
+
+ 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);
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.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.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.ids.push_back(shadow_sampler);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.uniform_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 5;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.light_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 6;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.reflection_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 7;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 8;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(scene_state.gi_probe_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 9;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ int slot_count = gi_probe_get_slots().size();
+ if (gi_probe_is_anisotropic()) {
+ u.ids.resize(slot_count * 3);
+ } else {
+ u.ids.resize(slot_count);
+ }
+
+ for (int i = 0; i < slot_count; i++) {
+
+ RID probe = gi_probe_get_slots()[i];
+
+ if (gi_probe_is_anisotropic()) {
+ if (probe.is_null()) {
+ RID empty_tex = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ u.ids.write[i * 3 + 0] = empty_tex;
+ u.ids.write[i * 3 + 1] = empty_tex;
+ u.ids.write[i * 3 + 2] = empty_tex;
+ } else {
+ u.ids.write[i * 3 + 0] = gi_probe_instance_get_texture(probe);
+ u.ids.write[i * 3 + 1] = gi_probe_instance_get_aniso_texture(probe, 0);
+ u.ids.write[i * 3 + 2] = gi_probe_instance_get_aniso_texture(probe, 1);
+ }
+ } else {
+ if (probe.is_null()) {
+ u.ids.write[i] = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ } else {
+ u.ids.write[i] = gi_probe_instance_get_texture(probe);
+ }
+ }
+ }
+
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 10;
+ u.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 = 11;
+ u.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 = 12;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(scene_state.decal_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 13;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.ids.push_back(cluster_builder.get_cluster_texture());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 14;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(cluster_builder.get_cluster_indices_buffer());
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 15;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ if (directional_shadow_get_texture().is_valid()) {
+ u.ids.push_back(directional_shadow_get_texture());
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ }
+ uniforms.push_back(u);
+ }
+
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET);
+ }
+}
+
+void RasterizerSceneHighEndRD::_setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas) {
+
+ if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) {
+ RD::get_singleton()->free(view_dependant_uniform_set);
+ }
+
+ //default render buffer and scene state uniform set
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+
+ RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
+ RD::Uniform u;
+ u.binding = 0;
+ u.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
+ }
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ }
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ view_dependant_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, VIEW_DEPENDANT_UNIFORM_SET);
+}
+
+void RasterizerSceneHighEndRD::_render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb) {
+
+ if (!rb->uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) {
+ RD::get_singleton()->free(rb->uniform_set);
+ }
+ rb->uniform_set = RID();
+}
+
+void RasterizerSceneHighEndRD::_render_buffers_uniform_set_changed(RID p_render_buffers) {
+
+ RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
+
+ _render_buffers_clear_uniform_set(rb);
+}
+
+RID RasterizerSceneHighEndRD::_render_buffers_get_roughness_texture(RID p_render_buffers) {
+ RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
+
+ return rb->roughness_buffer;
+}
+
+RID RasterizerSceneHighEndRD::_render_buffers_get_normal_texture(RID p_render_buffers) {
+ RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
+
+ return rb->normal_buffer;
+}
+
+void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_buffers) {
+
+ RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
+
+ if (rb->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) {
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = false && rb->depth.is_valid() ? rb->depth : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 1;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID bbt = render_buffers_get_back_buffer_texture(p_render_buffers);
+ RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb->normal_buffer.is_valid() ? rb->normal_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 3;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb->roughness_buffer.is_valid() ? rb->roughness_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.binding = 4;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID aot = render_buffers_get_ao_texture(p_render_buffers);
+ RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
+ }
+}
+
+RasterizerSceneHighEndRD *RasterizerSceneHighEndRD::singleton = nullptr;
+
+void RasterizerSceneHighEndRD::set_time(double p_time, double p_step) {
+ time = p_time;
+ RasterizerSceneRD::set_time(p_time, p_step);
+}
+
+RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage) :
+ RasterizerSceneRD(p_storage) {
+ singleton = this;
+ storage = p_storage;
+
+ /* SCENE SHADER */
+
+ {
+ 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";
+ }
+
+ uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
+
+ { //reflections
+ uint32_t reflection_buffer_size;
+ if (uniform_max_size < 65536) {
+ //Yes, you guessed right, ARM again
+ reflection_buffer_size = uniform_max_size;
+ } else {
+ reflection_buffer_size = 65536;
+ }
+
+ scene_state.max_reflections = reflection_buffer_size / sizeof(ReflectionData);
+ scene_state.reflections = memnew_arr(ReflectionData, scene_state.max_reflections);
+ scene_state.reflection_buffer = RD::get_singleton()->uniform_buffer_create(reflection_buffer_size);
+ defines += "\n#define MAX_REFLECTION_DATA_STRUCTS " + itos(scene_state.max_reflections) + "\n";
+ }
+
+ { //lights
+ scene_state.max_lights = MIN(1024 * 1024, uniform_max_size) / sizeof(LightData); //1mb of lights
+ uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData);
+ scene_state.lights = memnew_arr(LightData, scene_state.max_lights);
+ scene_state.light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
+ //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n";
+
+ scene_state.max_directional_lights = 8;
+ uint32_t directional_light_buffer_size = scene_state.max_directional_lights * sizeof(DirectionalLightData);
+ scene_state.directional_lights = memnew_arr(DirectionalLightData, scene_state.max_directional_lights);
+ scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
+ defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(scene_state.max_directional_lights) + "\n";
+ }
+
+ { //giprobes
+ int slot_count = gi_probe_get_slots().size();
+ if (gi_probe_is_anisotropic()) {
+ slot_count *= 3;
+ defines += "\n#define GI_PROBE_USE_ANISOTROPY\n";
+ }
+
+ if (gi_probe_get_quality() == GIPROBE_QUALITY_ULTRA_LOW) {
+ defines += "\n#define GI_PROBE_LOW_QUALITY\n";
+ } else if (gi_probe_get_quality() == GIPROBE_QUALITY_HIGH) {
+ defines += "\n#define GI_PROBE_HIGH_QUALITY\n";
+ }
+
+ defines += "\n#define MAX_GI_PROBE_TEXTURES " + itos(slot_count) + "\n";
+
+ uint32_t giprobe_buffer_size;
+ if (uniform_max_size < 65536) {
+ //Yes, you guessed right, ARM again
+ giprobe_buffer_size = uniform_max_size;
+ } else {
+ giprobe_buffer_size = 65536;
+ }
+
+ giprobe_buffer_size = MIN(sizeof(GIProbeData) * gi_probe_get_slots().size(), giprobe_buffer_size);
+ scene_state.max_gi_probes = giprobe_buffer_size / sizeof(GIProbeData);
+ scene_state.gi_probes = memnew_arr(GIProbeData, scene_state.max_gi_probes);
+ scene_state.gi_probe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * scene_state.max_gi_probes);
+ defines += "\n#define MAX_GI_PROBES " + itos(scene_state.max_gi_probes) + "\n";
+ }
+
+ { //decals
+ scene_state.max_decals = MIN(1024 * 1024, uniform_max_size) / sizeof(DecalData); //1mb of decals
+ uint32_t decal_buffer_size = scene_state.max_decals * sizeof(DecalData);
+ scene_state.decals = memnew_arr(DecalData, scene_state.max_decals);
+ scene_state.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
+ }
+
+ 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\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL\n#define MODE_RENDER_ROUGHNESS\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
+ shader_versions.push_back("");
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
+ shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n");
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_VOXEL_CONE_TRACING\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);
+ }
+
+ storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
+ storage->material_set_data_request_function(RasterizerStorageRD::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";
+
+ //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["NORMALMAP"] = "normalmap";
+ actions.renames["NORMALMAP_DEPTH"] = "normaldepth";
+ 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_TEXTURE"] = "normal_buffer";
+ actions.renames["DEPTH"] = "gl_FragDepth";
+ actions.renames["OUTPUT_IS_SRGB"] = "true";
+
+ //for light
+ actions.renames["VIEW"] = "view";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["ATTENUATION"] = "attenuation";
+ actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+ 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["NORMALMAP"] = "#define NORMALMAP_USED\n";
+ actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
+ 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["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.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;
+
+ shader.compiler.initialize(actions);
+ }
+
+ //render list
+ render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)128000);
+ render_list.init();
+ render_pass = 0;
+
+ {
+
+ scene_state.max_instances = render_list.max_elements;
+ scene_state.instances = memnew_arr(InstanceData, scene_state.max_instances);
+ scene_state.instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(InstanceData) * scene_state.max_instances);
+ }
+
+ scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
+
+ {
+ //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, RasterizerStorageRD::SHADER_TYPE_3D);
+ default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+ }
+
+ {
+
+ 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);
+ }
+
+ {
+ default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.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);
+ }
+
+ {
+ Vector<RD::Uniform> uniforms;
+
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+
+ default_radiance_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RADIANCE_UNIFORM_SET);
+ }
+
+ { //render buffers
+ Vector<RD::Uniform> uniforms;
+ for (int i = 0; i < 5; i++) {
+ RD::Uniform u;
+ u.binding = i;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = storage->texture_rd_get_default(i == 0 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE : (i == 2 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL : RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
+ u.ids.push_back(texture);
+ uniforms.push_back(u);
+ }
+
+ default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
+ }
+
+ cluster_builder.setup(16, 8, 24);
+}
+
+RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() {
+ directional_shadow_atlas_set_size(0);
+
+ //clear base uniform set if still valid
+ if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) {
+ RD::get_singleton()->free(view_dependant_uniform_set);
+ }
+
+ RD::get_singleton()->free(default_render_buffers_uniform_set);
+ RD::get_singleton()->free(default_radiance_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);
+
+ {
+ RD::get_singleton()->free(scene_state.uniform_buffer);
+ RD::get_singleton()->free(scene_state.instance_buffer);
+ RD::get_singleton()->free(scene_state.gi_probe_buffer);
+ RD::get_singleton()->free(scene_state.directional_light_buffer);
+ RD::get_singleton()->free(scene_state.light_buffer);
+ RD::get_singleton()->free(scene_state.reflection_buffer);
+ RD::get_singleton()->free(scene_state.decal_buffer);
+ memdelete_arr(scene_state.instances);
+ memdelete_arr(scene_state.gi_probes);
+ memdelete_arr(scene_state.directional_lights);
+ memdelete_arr(scene_state.lights);
+ memdelete_arr(scene_state.reflections);
+ memdelete_arr(scene_state.decals);
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
new file mode 100644
index 0000000000..83ff46ca7e
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h
@@ -0,0 +1,654 @@
+/*************************************************************************/
+/* rasterizer_scene_high_end_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_SCENE_HIGHEND_RD_H
+#define RASTERIZER_SCENE_HIGHEND_RD_H
+
+#include "servers/rendering/rasterizer_rd/light_cluster_builder.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_scene_rd.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
+#include "servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h"
+#include "servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl.gen.h"
+
+class RasterizerSceneHighEndRD : public RasterizerSceneRD {
+
+ enum {
+ SCENE_UNIFORM_SET = 0,
+ RADIANCE_UNIFORM_SET = 1,
+ VIEW_DEPENDANT_UNIFORM_SET = 2,
+ RENDER_BUFFERS_UNIFORM_SET = 3,
+ TRANSFORMS_UNIFORM_SET = 4,
+ MATERIAL_UNIFORM_SET = 5
+ };
+
+ /* Scene Shader */
+
+ enum ShaderVersion {
+ SHADER_VERSION_DEPTH_PASS,
+ SHADER_VERSION_DEPTH_PASS_DP,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_VCT_COLOR_PASS,
+ SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_MAX
+ };
+
+ struct {
+ SceneHighEndShaderRD scene_shader;
+ ShaderCompilerRD compiler;
+ } shader;
+
+ RasterizerStorageRD *storage;
+
+ /* Material */
+
+ struct ShaderData : public RasterizerStorageRD::ShaderData {
+
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ };
+
+ 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
+
+ };
+
+ bool valid;
+ RID version;
+ uint32_t vertex_input_mask;
+ RenderPipelineVertexFormatCacheRD 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_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;
+ 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;
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RasterizerStorageRD::ShaderData *_create_shader_func();
+ static RasterizerStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RasterizerStorageRD::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();
+ };
+
+ RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
+ return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
+ /* Push Constant */
+
+ struct PushConstant {
+ uint32_t index;
+ uint32_t pad[3];
+ };
+
+ /* Framebuffer */
+
+ struct RenderBufferDataHighEnd : public RenderBufferData {
+ //for rendering, may be MSAAd
+
+ RID color;
+ RID depth;
+ RID specular;
+ RID normal_buffer;
+ RID roughness_buffer;
+
+ RS::ViewportMSAA msaa;
+ RD::TextureSamples texture_samples;
+
+ RID color_msaa;
+ RID depth_msaa;
+ RID specular_msaa;
+ RID normal_buffer_msaa;
+ RID roughness_buffer_msaa;
+
+ RID depth_fb;
+ RID depth_normal_fb;
+ RID depth_normal_roughness_fb;
+ RID color_fb;
+ RID color_specular_fb;
+ RID specular_only_fb;
+ int width, height;
+
+ void ensure_specular();
+ void clear();
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
+
+ RID uniform_set;
+
+ ~RenderBufferDataHighEnd();
+ };
+
+ virtual RenderBufferData *_create_render_buffer_data();
+ void _allocate_normal_texture(RenderBufferDataHighEnd *rb);
+ void _allocate_roughness_texture(RenderBufferDataHighEnd *rb);
+
+ RID shadow_sampler;
+ RID render_base_uniform_set;
+ RID view_dependant_uniform_set;
+
+ virtual void _base_uniforms_changed();
+ void _render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb);
+ virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
+ virtual RID _render_buffers_get_roughness_texture(RID p_render_buffers);
+ virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
+
+ void _update_render_base_uniform_set();
+ void _setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas);
+ void _update_render_buffers_uniform_set(RID p_render_buffers);
+
+ /* Scene State UBO */
+
+ struct ReflectionData { //should always be 128 bytes
+ float box_extents[3];
+ float index;
+ float box_offset[3];
+ uint32_t mask;
+ float params[4]; // intensity, 0, interior , boxproject
+ float ambient[4]; // ambient color, energy
+ float local_matrix[16]; // up to here for spot and omni, rest is for directional
+ };
+
+ struct LightData {
+ float position[3];
+ float inv_radius;
+ float direction[3];
+ float size;
+ uint16_t attenuation_energy[2]; //16 bits attenuation, then energy
+ uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm)
+ uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float)
+ uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm)
+ float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
+ float shadow_matrix[16];
+ float shadow_bias;
+ float shadow_normal_bias;
+ float transmittance_bias;
+ float soft_shadow_size;
+ float soft_shadow_scale;
+ uint32_t mask;
+ uint32_t pad[2];
+ float projector_rect[4];
+ };
+
+ struct DirectionalLightData {
+
+ float direction[3];
+ float energy;
+ float color[3];
+ float size;
+ float specular;
+ uint32_t mask;
+ float softshadow_angle;
+ float soft_shadow_scale;
+ uint32_t blend_splits;
+ uint32_t shadow_enabled;
+ float fade_from;
+ float fade_to;
+ float shadow_bias[4];
+ float shadow_normal_bias[4];
+ float shadow_transmittance_bias[4];
+ float shadow_transmittance_z_scale[4];
+ float shadow_range_begin[4];
+ float shadow_split_offsets[4];
+ float shadow_matrices[4][16];
+ float shadow_color1[4];
+ float shadow_color2[4];
+ float shadow_color3[4];
+ float shadow_color4[4];
+ float uv_scale1[2];
+ float uv_scale2[2];
+ float uv_scale3[2];
+ float uv_scale4[2];
+ };
+
+ 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 pad[1];
+ };
+
+ struct DecalData {
+ float xform[16];
+ float inv_extents[3];
+ float albedo_mix;
+ float albedo_rect[4];
+ float normal_rect[4];
+ float orm_rect[4];
+ float emission_rect[4];
+ float modulate[4];
+ float emission_energy;
+ uint32_t mask;
+ float upper_fade;
+ float lower_fade;
+ float normal_xform[12];
+ float normal[3];
+ float normal_fade;
+ };
+
+ enum {
+ 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_MULTIMESH_STRIDE_SHIFT = 16,
+ INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7,
+ INSTANCE_DATA_FLAG_SKELETON = 1 << 19,
+ };
+
+ struct InstanceData {
+ float transform[16];
+ float normal_transform[16];
+ uint32_t flags;
+ uint32_t instance_ofs; //instance_offset in instancing/skeleton buffer
+ uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap)
+ uint32_t mask;
+ };
+
+ struct SceneState {
+ 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 time;
+ float reflection_multiplier;
+
+ uint32_t pancake_shadows;
+ uint32_t pad;
+
+ 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 ao_color[4];
+ };
+
+ UBO ubo;
+
+ RID uniform_buffer;
+
+ ReflectionData *reflections;
+ uint32_t max_reflections;
+ RID reflection_buffer;
+ uint32_t max_reflection_probes_per_instance;
+
+ GIProbeData *gi_probes;
+ uint32_t max_gi_probes;
+ RID gi_probe_buffer;
+ uint32_t max_gi_probe_probes_per_instance;
+
+ DecalData *decals;
+ uint32_t max_decals;
+ RID decal_buffer;
+
+ LightData *lights;
+ uint32_t max_lights;
+ RID light_buffer;
+
+ DirectionalLightData *directional_lights;
+ uint32_t max_directional_lights;
+ RID directional_light_buffer;
+
+ RID instance_buffer;
+ InstanceData *instances;
+ uint32_t max_instances;
+
+ bool used_screen_texture = false;
+ bool used_normal_texture = false;
+ bool used_depth_texture = false;
+ bool used_sss = false;
+ uint32_t current_shader_index = 0;
+ uint32_t current_material_index = 0;
+ } scene_state;
+
+ /* Render List */
+
+ struct RenderList {
+
+ int max_elements;
+
+ struct Element {
+ RasterizerScene::InstanceBase *instance;
+ MaterialData *material;
+ union {
+ struct {
+ //from least significant to most significant in sort, TODO: should be endian swapped on big endian
+ uint64_t geometry_index : 20;
+ uint64_t material_index : 15;
+ uint64_t shader_index : 12;
+ uint64_t uses_instancing : 1;
+ uint64_t uses_vct : 1;
+ uint64_t uses_lightmap : 1;
+ uint64_t depth_layer : 4;
+ uint64_t priority : 8;
+ };
+
+ uint64_t sort_key;
+ };
+ uint32_t surface_index;
+ };
+
+ Element *base_elements;
+ Element **elements;
+
+ int element_count;
+ int alpha_element_count;
+
+ void clear() {
+
+ element_count = 0;
+ alpha_element_count = 0;
+ }
+
+ //should eventually be replaced by radix
+
+ struct SortByKey {
+
+ _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
+ return A->sort_key < B->sort_key;
+ }
+ };
+
+ void sort_by_key(bool p_alpha) {
+
+ SortArray<Element *, SortByKey> sorter;
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
+ } else {
+ sorter.sort(elements, element_count);
+ }
+ }
+
+ struct SortByDepth {
+
+ _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
+ return A->instance->depth < B->instance->depth;
+ }
+ };
+
+ void sort_by_depth(bool p_alpha) { //used for shadows
+
+ SortArray<Element *, SortByDepth> sorter;
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
+ } else {
+ sorter.sort(elements, element_count);
+ }
+ }
+
+ struct SortByReverseDepthAndPriority {
+
+ _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
+ uint32_t layer_A = uint32_t(A->priority);
+ uint32_t layer_B = uint32_t(B->priority);
+ if (layer_A == layer_B) {
+ return A->instance->depth > B->instance->depth;
+ } else {
+ return layer_A < layer_B;
+ }
+ }
+ };
+
+ void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
+
+ SortArray<Element *, SortByReverseDepthAndPriority> sorter;
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
+ } else {
+ sorter.sort(elements, element_count);
+ }
+ }
+
+ _FORCE_INLINE_ Element *add_element() {
+
+ if (element_count + alpha_element_count >= max_elements)
+ return nullptr;
+ elements[element_count] = &base_elements[element_count];
+ return elements[element_count++];
+ }
+
+ _FORCE_INLINE_ Element *add_alpha_element() {
+
+ if (element_count + alpha_element_count >= max_elements)
+ return nullptr;
+ int idx = max_elements - alpha_element_count - 1;
+ elements[idx] = &base_elements[idx];
+ alpha_element_count++;
+ return elements[idx];
+ }
+
+ void init() {
+
+ element_count = 0;
+ alpha_element_count = 0;
+ elements = memnew_arr(Element *, max_elements);
+ base_elements = memnew_arr(Element, max_elements);
+ for (int i = 0; i < max_elements; i++)
+ elements[i] = &base_elements[i]; // assign elements
+ }
+
+ RenderList() {
+
+ max_elements = 0;
+ }
+
+ ~RenderList() {
+ memdelete_arr(elements);
+ memdelete_arr(base_elements);
+ }
+ };
+
+ RenderList render_list;
+
+ static RasterizerSceneHighEndRD *singleton;
+ uint64_t render_pass;
+ 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_radiance_uniform_set;
+ RID default_render_buffers_uniform_set;
+
+ RID default_vec4_xform_buffer;
+ RID default_vec4_xform_uniform_set;
+
+ LightClusterBuilder cluster_builder;
+
+ 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,
+ PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
+ PASS_MODE_DEPTH_MATERIAL,
+ };
+
+ void _setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_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);
+ void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
+ void _setup_decals(const RID *p_decal_instances, int p_decal_count, const Transform &p_camera_inverse_xform);
+ void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
+ void _setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform);
+
+ void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth);
+ void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set);
+ _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index);
+ _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index);
+
+ void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi);
+
+protected:
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, 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);
+ virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, 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);
+ virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
+
+public:
+ virtual void set_time(double p_time, double p_step);
+
+ virtual bool free(RID p_rid);
+
+ RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage);
+ ~RasterizerSceneHighEndRD();
+};
+#endif // RASTERIZER_SCENE_HIGHEND_RD_H
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
new file mode 100644
index 0000000000..37e2aaad0e
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -0,0 +1,4308 @@
+/*************************************************************************/
+/* rasterizer_scene_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer_scene_rd.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+#include "servers/rendering/rendering_server_raster.h"
+
+uint64_t RasterizerSceneRD::auto_exposure_counter = 2;
+
+void get_vogel_disk(float *r_kernel, int p_sample_count) {
+ const float golden_angle = 2.4;
+
+ for (int i = 0; i < p_sample_count; i++) {
+ float r = Math::sqrt(float(i) + 0.5) / Math::sqrt(float(p_sample_count));
+ float theta = float(i) * golden_angle;
+
+ r_kernel[i * 4] = Math::cos(theta) * r;
+ r_kernel[i * 4 + 1] = Math::sin(theta) * r;
+ }
+}
+
+void RasterizerSceneRD::_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 RasterizerSceneRD::_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.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 RasterizerSceneRD::_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 RasterizerSceneRD::_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 RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd) {
+
+ if (sky_use_cubemap_array) {
+
+ for (int i = 0; i < rd.layers.size(); i++) {
+ for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) {
+ for (int k = 0; k < 6; k++) {
+ RID view = rd.layers[i].mipmaps[j].views[k];
+ RID texture = rd.layers[i].mipmaps[j + 1].views[k];
+ Size2i size = rd.layers[i].mipmaps[j + 1].size;
+ storage->get_effects()->make_mipmap(view, texture, size);
+ }
+ }
+ }
+ }
+}
+
+RID RasterizerSceneRD::sky_create() {
+ return sky_owner.make_rid(Sky());
+}
+
+void RasterizerSceneRD::_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 RasterizerSceneRD::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);
+}
+
+void RasterizerSceneRD::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);
+}
+
+void RasterizerSceneRD::sky_set_material(RID p_sky, RID p_material) {
+ Sky *sky = sky_owner.getornull(p_sky);
+ ERR_FAIL_COND(!sky);
+ sky->material = p_material;
+}
+void RasterizerSceneRD::_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.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.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 havent 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.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.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 *next = sky->dirty_list;
+ sky->dirty_list = nullptr;
+ sky->dirty = false;
+ sky = next;
+ }
+
+ dirty_sky_list = nullptr;
+}
+
+RID RasterizerSceneRD::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 RasterizerSceneRD::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.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 RasterizerSceneRD::_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.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ }
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+ } else {
+ u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::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];
+}
+
+RID RasterizerSceneRD::sky_get_material(RID p_sky) const {
+ Sky *sky = sky_owner.getornull(p_sky);
+ ERR_FAIL_COND_V(!sky, RID());
+
+ return sky->material;
+}
+
+void RasterizerSceneRD::_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));
+
+ 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, RasterizerStorageRD::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, RasterizerStorageRD::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) {
+ RenderPipelineVertexFormatCacheRD *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.sampler_uniform_set, sky_scene_state.light_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) {
+ RenderPipelineVertexFormatCacheRD *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.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+ }
+
+ RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
+
+ RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+
+ 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.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+ RD::get_singleton()->draw_list_end();
+}
+
+void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size) {
+
+ 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, RasterizerStorageRD::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, RasterizerStorageRD::SHADER_TYPE_SKY);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ SkyShaderData *shader_data = material->shader_data;
+
+ ERR_FAIL_COND(!shader_data);
+
+ // 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;
+ RenderingServerRaster::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_position.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+
+ sky->prev_position = p_position;
+ sky->reflection.dirty = true;
+ }
+
+ if (shader_data->uses_light || sky_scene_state.light_uniform_set.is_null()) {
+ // Check whether the directional_light_buffer changes
+ bool light_data_dirty = false;
+
+ if (sky_scene_state.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
+ light_data_dirty = true;
+ for (uint32_t i = sky_scene_state.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.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) {
+ light_data_dirty = true;
+ break;
+ }
+ }
+ }
+
+ if (light_data_dirty || sky_scene_state.light_uniform_set.is_null()) {
+
+ 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, true);
+
+ if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.ids.push_back(sky_scene_state.directional_light_buffer);
+ uniforms.push_back(u);
+ }
+
+ sky_scene_state.light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_LIGHTS);
+
+ RasterizerSceneRD::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.directional_light_count;
+ sky->reflection.dirty = true;
+ }
+ }
+}
+
+void RasterizerSceneRD::_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, RasterizerStorageRD::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, RasterizerStorageRD::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);
+
+ // Update radiance cubemap
+ if (sky->reflection.dirty) {
+
+ 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) {
+ RenderPipelineVertexFormatCacheRD *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.sampler_uniform_set, sky_scene_state.light_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) {
+ RenderPipelineVertexFormatCacheRD *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.sampler_uniform_set, sky_scene_state.light_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;
+ RenderPipelineVertexFormatCacheRD *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.sampler_uniform_set, sky_scene_state.light_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_use_cubemap_array) {
+ if (sky->mode == RS::SKY_MODE_QUALITY) {
+ for (int i = 1; i < sky->reflection.layers.size(); i++) {
+ _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i);
+ }
+ } else {
+ _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
+ }
+
+ _update_reflection_mipmaps(sky->reflection);
+ } else {
+ if (sky->mode == RS::SKY_MODE_QUALITY) {
+ for (int i = 1; i < sky->reflection.layers[0].mipmaps.size(); i++) {
+ _create_reflection_importance_sample(sky->reflection, sky_use_cubemap_array, 10, i);
+ }
+ } else {
+ _create_reflection_fast_filter(sky->reflection, sky_use_cubemap_array);
+ }
+ }
+
+ sky->reflection.dirty = false;
+ }
+}
+
+/* SKY SHADER */
+
+void RasterizerSceneRD::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["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["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["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.uniforms = &uniforms;
+
+ RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::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 RasterizerSceneRD::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 RasterizerSceneRD::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().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);
+ }
+}
+
+bool RasterizerSceneRD::SkyShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RasterizerSceneRD::SkyShaderData::is_animated() const {
+ return false;
+}
+
+bool RasterizerSceneRD::SkyShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant RasterizerSceneRD::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();
+}
+
+RasterizerSceneRD::SkyShaderData::SkyShaderData() {
+ valid = false;
+}
+
+RasterizerSceneRD::SkyShaderData::~SkyShaderData() {
+ RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::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);
+ }
+}
+
+RasterizerStorageRD::ShaderData *RasterizerSceneRD::_create_sky_shader_func() {
+ SkyShaderData *shader_data = memnew(SkyShaderData);
+ return shader_data;
+}
+
+void RasterizerSceneRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+
+ RasterizerSceneRD *scene_singleton = (RasterizerSceneRD *)RasterizerSceneRD::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.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.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);
+}
+
+RasterizerSceneRD::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);
+ }
+}
+
+RasterizerStorageRD::MaterialData *RasterizerSceneRD::_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 RasterizerSceneRD::environment_create() {
+
+ return environment_owner.make_rid(Environent());
+}
+
+void RasterizerSceneRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->background = p_bg;
+}
+void RasterizerSceneRD::environment_set_sky(RID p_env, RID p_sky) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->sky = p_sky;
+}
+void RasterizerSceneRD::environment_set_sky_custom_fov(RID p_env, float p_scale) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->sky_custom_fov = p_scale;
+}
+void RasterizerSceneRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->sky_orientation = p_orientation;
+}
+void RasterizerSceneRD::environment_set_bg_color(RID p_env, const Color &p_color) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->bg_color = p_color;
+}
+void RasterizerSceneRD::environment_set_bg_energy(RID p_env, float p_energy) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->bg_energy = p_energy;
+}
+void RasterizerSceneRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->canvas_max_layer = p_max_layer;
+}
+void RasterizerSceneRD::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) {
+ Environent *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;
+}
+
+RS::EnvironmentBG RasterizerSceneRD::environment_get_background(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX);
+ return env->background;
+}
+RID RasterizerSceneRD::environment_get_sky(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, RID());
+ return env->sky;
+}
+float RasterizerSceneRD::environment_get_sky_custom_fov(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->sky_custom_fov;
+}
+Basis RasterizerSceneRD::environment_get_sky_orientation(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, Basis());
+ return env->sky_orientation;
+}
+Color RasterizerSceneRD::environment_get_bg_color(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, Color());
+ return env->bg_color;
+}
+float RasterizerSceneRD::environment_get_bg_energy(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->bg_energy;
+}
+int RasterizerSceneRD::environment_get_canvas_max_layer(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->canvas_max_layer;
+}
+Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, Color());
+ return env->ambient_light;
+}
+RS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_light_ambient_source(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG);
+ return env->ambient_source;
+}
+float RasterizerSceneRD::environment_get_ambient_light_ambient_energy(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->ambient_light_energy;
+}
+float RasterizerSceneRD::environment_get_ambient_sky_contribution(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, 0);
+ return env->ambient_sky_contribution;
+}
+RS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_source(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED);
+ return env->reflection_source;
+}
+
+Color RasterizerSceneRD::environment_get_ao_color(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, Color());
+ return env->ao_color;
+}
+
+void RasterizerSceneRD::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) {
+ Environent *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;
+}
+
+void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, 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) {
+
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->glow_enabled = p_enable;
+ env->glow_levels = p_level_flags;
+ 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;
+}
+
+void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable) {
+ glow_bicubic_upscale = p_enable;
+}
+
+void RasterizerSceneRD::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) {
+
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ 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;
+}
+
+void RasterizerSceneRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
+ ssr_roughness_quality = p_quality;
+}
+
+RS::EnvironmentSSRRoughnessQuality RasterizerSceneRD::environment_get_ssr_roughness_quality() const {
+ return ssr_roughness_quality;
+}
+
+void RasterizerSceneRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
+
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->ssao_enabled = p_enable;
+ env->ssao_radius = p_radius;
+ env->ssao_intensity = p_intensity;
+ env->ssao_bias = p_bias;
+ env->ssao_direct_light_affect = p_light_affect;
+ env->ssao_ao_channel_affect = p_ao_channel_affect;
+ env->ssao_blur = p_blur;
+}
+
+void RasterizerSceneRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size) {
+ ssao_quality = p_quality;
+ ssao_half_size = p_half_size;
+}
+
+bool RasterizerSceneRD::environment_is_ssao_enabled(RID p_env) const {
+
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, false);
+ return env->ssao_enabled;
+}
+
+float RasterizerSceneRD::environment_get_ssao_ao_affect(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, false);
+ return env->ssao_ao_channel_affect;
+}
+float RasterizerSceneRD::environment_get_ssao_light_affect(RID p_env) const {
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, false);
+ return env->ssao_direct_light_affect;
+}
+
+bool RasterizerSceneRD::environment_is_ssr_enabled(RID p_env) const {
+
+ Environent *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, false);
+ return env->ssr_enabled;
+}
+
+bool RasterizerSceneRD::is_environment(RID p_env) const {
+ return environment_owner.owns(p_env);
+}
+
+////////////////////////////////////////////////////////////
+
+RID RasterizerSceneRD::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");
+
+ return reflection_atlas_owner.make_rid(ra);
+}
+
+void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
+
+ ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas);
+ ERR_FAIL_COND(!ra);
+
+ if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
+ return; //no changes
+ }
+
+ ra->size = p_reflection_size;
+ ra->count = p_reflection_count;
+
+ if (ra->reflection.is_valid()) {
+ //clear and invalidate everything
+ RD::get_singleton()->free(ra->reflection);
+ ra->reflection = RID();
+ 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);
+ if (ra->reflections[i].owner.is_null()) {
+ continue;
+ }
+ reflection_probe_release_atlas_index(ra->reflections[i].owner);
+ //rp->atlasindex clear
+ }
+
+ ra->reflections.clear();
+ }
+}
+
+////////////////////////
+RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) {
+ ReflectionProbeInstance rpi;
+ rpi.probe = p_probe;
+ return reflection_probe_instance_owner.make_rid(rpi);
+}
+
+void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!rpi);
+
+ rpi->transform = p_transform;
+ rpi->dirty = true;
+}
+
+void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) {
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!rpi);
+
+ if (rpi->atlas.is_null()) {
+ return; //nothing to release
+ }
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ERR_FAIL_COND(!atlas);
+ ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
+ atlas->reflections.write[rpi->atlas_index].owner = RID();
+ rpi->atlas_index = -1;
+ rpi->atlas = RID();
+}
+
+bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) {
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+
+ if (rpi->rendering) {
+ return false;
+ }
+
+ if (rpi->dirty) {
+ return true;
+ }
+
+ if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
+ return true;
+ }
+
+ return rpi->atlas_index == -1;
+}
+
+bool RasterizerSceneRD::reflection_probe_instance_has_reflection(RID p_instance) {
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+
+ return rpi->atlas.is_valid();
+}
+
+bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas);
+
+ ERR_FAIL_COND_V(!atlas, false);
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+
+ if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
+ WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
+ reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
+ }
+
+ if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 8) {
+ // Invalidate reflection atlas, need to regenerate
+ RD::get_singleton()->free(atlas->reflection);
+ atlas->reflection = RID();
+
+ for (int i = 0; i < atlas->reflections.size(); i++) {
+ if (atlas->reflections[i].owner.is_null()) {
+ continue;
+ }
+ reflection_probe_release_atlas_index(atlas->reflections[i].owner);
+ }
+
+ atlas->reflections.clear();
+ }
+
+ if (atlas->reflection.is_null()) {
+ int mipmaps = MIN(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:
+ RD::TextureFormat tf;
+ tf.array_layers = 6 * atlas->count;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+ tf.mipmaps = mipmaps;
+ tf.width = atlas->size;
+ tf.height = atlas->size;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+ {
+
+ RD::TextureFormat tf;
+ tf.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;
+ tf.width = atlas->size;
+ tf.height = atlas->size;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+ 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);
+ for (int j = 0; j < 6; j++) {
+ Vector<RID> fb;
+ fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
+ fb.push_back(atlas->depth_buffer);
+ atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
+ }
+ }
+
+ Vector<RID> fb;
+ fb.push_back(atlas->depth_buffer);
+ atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ if (rpi->atlas_index == -1) {
+ for (int i = 0; i < atlas->reflections.size(); i++) {
+ if (atlas->reflections[i].owner.is_null()) {
+ rpi->atlas_index = i;
+ break;
+ }
+ }
+ //find the one used last
+ if (rpi->atlas_index == -1) {
+ //everything is in use, find the one least used via LRU
+ uint64_t pass_min = 0;
+
+ for (int i = 0; i < atlas->reflections.size(); i++) {
+ ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.getornull(atlas->reflections[i].owner);
+ if (rpi2->last_pass < pass_min) {
+ pass_min = rpi2->last_pass;
+ rpi->atlas_index = i;
+ }
+ }
+ }
+ }
+
+ rpi->atlas = p_reflection_atlas;
+ rpi->rendering = true;
+ rpi->dirty = false;
+ rpi->processing_layer = 1;
+ rpi->processing_side = 0;
+
+ return true;
+}
+
+bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) {
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+ ERR_FAIL_COND_V(!rpi->rendering, false);
+ ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ if (!atlas || rpi->atlas_index == -1) {
+ //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
+ rpi->rendering = false;
+ return false;
+ }
+
+ 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);
+ rpi->rendering = false;
+ rpi->processing_side = 0;
+ rpi->processing_layer = 1;
+ return true;
+ }
+
+ if (rpi->processing_layer > 1) {
+ _create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, 10, rpi->processing_layer);
+ rpi->processing_layer++;
+ if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
+ rpi->rendering = false;
+ rpi->processing_side = 0;
+ rpi->processing_layer = 1;
+ return true;
+ }
+ return false;
+
+ } else {
+ _create_reflection_importance_sample(atlas->reflections.write[rpi->atlas_index].data, false, rpi->processing_side, rpi->processing_layer);
+ }
+
+ rpi->processing_side++;
+ if (rpi->processing_side == 6) {
+ rpi->processing_side = 0;
+ rpi->processing_layer++;
+ }
+
+ return false;
+}
+
+uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, 0);
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, 0);
+ return atlas->size;
+}
+
+RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_INDEX_V(p_index, 6, RID());
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->reflections[rpi->atlas_index].fbs[p_index];
+}
+
+RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_INDEX_V(p_index, 6, RID());
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->depth_fb;
+}
+
+///////////////////////////////////////////////////////////
+
+RID RasterizerSceneRD::shadow_atlas_create() {
+
+ return shadow_atlas_owner.make_rid(ShadowAtlas());
+}
+
+void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_COND(p_size < 0);
+ p_size = next_power_of_2(p_size);
+
+ if (p_size == shadow_atlas->size)
+ return;
+
+ // erasing atlas
+ if (shadow_atlas->depth.is_valid()) {
+ RD::get_singleton()->free(shadow_atlas->depth);
+ shadow_atlas->depth = RID();
+ }
+ for (int i = 0; i < 4; i++) {
+ //clear subdivisions
+ shadow_atlas->quadrants[i].shadows.resize(0);
+ shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision);
+ }
+
+ //erase shadow atlas reference from lights
+ for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) {
+ LightInstance *li = light_instance_owner.getornull(E->key());
+ ERR_CONTINUE(!li);
+ li->shadow_atlases.erase(p_atlas);
+ }
+
+ //clear owners
+ shadow_atlas->shadow_owners.clear();
+
+ shadow_atlas->size = p_size;
+
+ if (shadow_atlas->size) {
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ tf.width = shadow_atlas->size;
+ tf.height = shadow_atlas->size;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+}
+
+void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_INDEX(p_quadrant, 4);
+ ERR_FAIL_INDEX(p_subdivision, 16384);
+
+ uint32_t subdiv = next_power_of_2(p_subdivision);
+ if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer
+ subdiv <<= 1;
+ }
+
+ subdiv = int(Math::sqrt((float)subdiv));
+
+ //obtain the number that will be x*x
+
+ if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv)
+ return;
+
+ //erase all data from quadrant
+ for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
+
+ if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
+ shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+ LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+ ERR_CONTINUE(!li);
+ li->shadow_atlases.erase(p_atlas);
+ }
+ }
+
+ shadow_atlas->quadrants[p_quadrant].shadows.resize(0);
+ shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv);
+ shadow_atlas->quadrants[p_quadrant].subdivision = subdiv;
+
+ //cache the smallest subdiv (for faster allocation in light update)
+
+ shadow_atlas->smallest_subdiv = 1 << 30;
+
+ for (int i = 0; i < 4; i++) {
+ if (shadow_atlas->quadrants[i].subdivision) {
+ shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision);
+ }
+ }
+
+ if (shadow_atlas->smallest_subdiv == 1 << 30) {
+ shadow_atlas->smallest_subdiv = 0;
+ }
+
+ //resort the size orders, simple bublesort for 4 elements..
+
+ int swaps = 0;
+ do {
+ swaps = 0;
+
+ for (int i = 0; i < 3; i++) {
+ if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) {
+ SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]);
+ swaps++;
+ }
+ }
+ } while (swaps > 0);
+}
+
+bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
+
+ for (int i = p_quadrant_count - 1; i >= 0; i--) {
+
+ int qidx = p_in_quadrants[i];
+
+ if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+ return false;
+ }
+
+ //look for an empty space
+ int sc = shadow_atlas->quadrants[qidx].shadows.size();
+ ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw();
+
+ int found_free_idx = -1; //found a free one
+ int found_used_idx = -1; //found existing one, must steal it
+ uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion)
+
+ for (int j = 0; j < sc; j++) {
+ if (!sarr[j].owner.is_valid()) {
+ found_free_idx = j;
+ break;
+ }
+
+ LightInstance *sli = light_instance_owner.getornull(sarr[j].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass != scene_pass) {
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec)
+ continue;
+
+ if (found_used_idx == -1 || sli->last_scene_pass < min_pass) {
+ found_used_idx = j;
+ min_pass = sli->last_scene_pass;
+ }
+ }
+ }
+
+ if (found_free_idx == -1 && found_used_idx == -1)
+ continue; //nothing found
+
+ if (found_free_idx == -1 && found_used_idx != -1) {
+ found_free_idx = found_used_idx;
+ }
+
+ r_quadrant = qidx;
+ r_shadow = found_free_idx;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND_V(!shadow_atlas, false);
+
+ LightInstance *li = light_instance_owner.getornull(p_light_intance);
+ ERR_FAIL_COND_V(!li, false);
+
+ if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
+ return false;
+ }
+
+ uint32_t quad_size = shadow_atlas->size >> 1;
+ int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
+
+ int valid_quadrants[4];
+ int valid_quadrant_count = 0;
+ int best_size = -1; //best size found
+ int best_subdiv = -1; //subdiv for the best size
+
+ //find the quadrants this fits into, and the best possible size it can fit into
+ for (int i = 0; i < 4; i++) {
+ int q = shadow_atlas->size_order[i];
+ int sd = shadow_atlas->quadrants[q].subdivision;
+ if (sd == 0)
+ continue; //unused
+
+ int max_fit = quad_size / sd;
+
+ if (best_size != -1 && max_fit > best_size)
+ break; //too large
+
+ valid_quadrants[valid_quadrant_count++] = q;
+ best_subdiv = sd;
+
+ if (max_fit >= desired_fit) {
+ best_size = max_fit;
+ }
+ }
+
+ ERR_FAIL_COND_V(valid_quadrant_count == 0, false);
+
+ uint64_t tick = OS::get_singleton()->get_ticks_msec();
+
+ //see if it already exists
+
+ if (shadow_atlas->shadow_owners.has(p_light_intance)) {
+ //it does!
+ uint32_t key = shadow_atlas->shadow_owners[p_light_intance];
+ uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
+ bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version;
+
+ if (!should_realloc) {
+ shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+ //already existing, see if it should redraw or it's just OK
+ return should_redraw;
+ }
+
+ int new_quadrant, new_shadow;
+
+ //find a better place
+ if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) {
+ //found a better place!
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ if (sh->owner.is_valid()) {
+ //is taken, but is invalid, erasing it
+ shadow_atlas->shadow_owners.erase(sh->owner);
+ LightInstance *sli = light_instance_owner.getornull(sh->owner);
+ sli->shadow_atlases.erase(p_atlas);
+ }
+
+ //erase previous
+ shadow_atlas->quadrants[q].shadows.write[s].version = 0;
+ shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+
+ sh->owner = p_light_intance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
+ li->shadow_atlases.insert(p_atlas);
+
+ //make new key
+ key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
+ key |= new_shadow;
+ //update it in map
+ shadow_atlas->shadow_owners[p_light_intance] = key;
+ //make it dirty, as it should redraw anyway
+ return true;
+ }
+
+ //no better place for this shadow found, keep current
+
+ //already existing, see if it should redraw or it's just OK
+
+ shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+
+ return should_redraw;
+ }
+
+ int new_quadrant, new_shadow;
+
+ //find a better place
+ if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) {
+ //found a better place!
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ if (sh->owner.is_valid()) {
+ //is taken, but is invalid, erasing it
+ shadow_atlas->shadow_owners.erase(sh->owner);
+ LightInstance *sli = light_instance_owner.getornull(sh->owner);
+ sli->shadow_atlases.erase(p_atlas);
+ }
+
+ sh->owner = p_light_intance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
+ li->shadow_atlases.insert(p_atlas);
+
+ //make new key
+ uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
+ key |= new_shadow;
+ //update it in map
+ shadow_atlas->shadow_owners[p_light_intance] = key;
+ //make it dirty, as it should redraw anyway
+
+ return true;
+ }
+
+ //no place to allocate this light, apologies
+
+ return false;
+}
+
+void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) {
+
+ p_size = nearest_power_of_2_templated(p_size);
+
+ if (directional_shadow.size == p_size) {
+ return;
+ }
+
+ directional_shadow.size = p_size;
+
+ if (directional_shadow.depth.is_valid()) {
+ RD::get_singleton()->free(directional_shadow.depth);
+ directional_shadow.depth = RID();
+ }
+
+ if (p_size > 0) {
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ tf.width = p_size;
+ tf.height = p_size;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ _base_uniforms_changed();
+}
+
+void RasterizerSceneRD::set_directional_shadow_count(int p_count) {
+
+ directional_shadow.light_count = p_count;
+ directional_shadow.current_light = 0;
+}
+
+static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) {
+
+ int split_h = 1;
+ int split_v = 1;
+
+ while (split_h * split_v < p_shadow_count) {
+ if (split_h == split_v) {
+ split_h <<= 1;
+ } else {
+ split_v <<= 1;
+ }
+ }
+
+ Rect2i rect(0, 0, p_size, p_size);
+ rect.size.width /= split_h;
+ rect.size.height /= split_v;
+
+ rect.position.x = rect.size.width * (p_shadow_index % split_h);
+ rect.position.y = rect.size.height * (p_shadow_index / split_h);
+
+ return rect;
+}
+
+int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) {
+
+ ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
+
+ Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_intance);
+ ERR_FAIL_COND_V(!light_instance, 0);
+
+ switch (storage->light_directional_get_shadow_mode(light_instance->light)) {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
+ break; //none
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: r.size.height /= 2; break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: r.size /= 2; break;
+ }
+
+ return MAX(r.size.width, r.size.height);
+}
+
+//////////////////////////////////////////////////
+
+RID RasterizerSceneRD::camera_effects_create() {
+
+ return camera_effects_owner.make_rid(CameraEffects());
+}
+
+void RasterizerSceneRD::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) {
+
+ dof_blur_quality = p_quality;
+ dof_blur_use_jitter = p_use_jitter;
+}
+
+void RasterizerSceneRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) {
+
+ dof_blur_bokeh_shape = p_shape;
+}
+
+void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) {
+ CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+ ERR_FAIL_COND(!camfx);
+
+ camfx->dof_blur_far_enabled = p_far_enable;
+ camfx->dof_blur_far_distance = p_far_distance;
+ camfx->dof_blur_far_transition = p_far_transition;
+
+ camfx->dof_blur_near_enabled = p_near_enable;
+ camfx->dof_blur_near_distance = p_near_distance;
+ camfx->dof_blur_near_transition = p_near_transition;
+
+ camfx->dof_blur_amount = p_amount;
+}
+
+void RasterizerSceneRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {
+
+ CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+ ERR_FAIL_COND(!camfx);
+
+ camfx->override_exposure_enabled = p_enable;
+ camfx->override_exposure = p_exposure;
+}
+
+RID RasterizerSceneRD::light_instance_create(RID p_light) {
+
+ RID li = light_instance_owner.make_rid(LightInstance());
+
+ LightInstance *light_instance = light_instance_owner.getornull(li);
+
+ light_instance->self = li;
+ light_instance->light = p_light;
+ light_instance->light_type = storage->light_get_type(p_light);
+
+ return li;
+}
+
+void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->transform = p_transform;
+}
+
+void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ if (storage->light_get_type(light_instance->light) != RS::LIGHT_DIRECTIONAL) {
+ p_pass = 0;
+ }
+
+ ERR_FAIL_INDEX(p_pass, 4);
+
+ light_instance->shadow_transform[p_pass].camera = p_projection;
+ light_instance->shadow_transform[p_pass].transform = p_transform;
+ light_instance->shadow_transform[p_pass].farplane = p_far;
+ light_instance->shadow_transform[p_pass].split = p_split;
+ light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
+ light_instance->shadow_transform[p_pass].range_begin = p_range_begin;
+ light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size;
+ light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale;
+}
+
+void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->last_scene_pass = scene_pass;
+}
+
+RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_size) {
+
+ if (!shadow_cubemaps.has(p_size)) {
+
+ ShadowCubemap sc;
+ {
+ RD::TextureFormat tf;
+ tf.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;
+ tf.width = p_size;
+ tf.height = p_size;
+ tf.type = RD::TEXTURE_TYPE_CUBE;
+ tf.array_layers = 6;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ for (int i = 0; i < 6; i++) {
+ RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0);
+ Vector<RID> fbtex;
+ fbtex.push_back(side_texture);
+ sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+
+ shadow_cubemaps[p_size] = sc;
+ }
+
+ return &shadow_cubemaps[p_size];
+}
+
+RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p_size) {
+
+ if (!shadow_maps.has(p_size)) {
+
+ ShadowMap sm;
+ {
+ RD::TextureFormat tf;
+ tf.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;
+ tf.width = p_size.width;
+ tf.height = p_size.height;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ sm.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ Vector<RID> fbtex;
+ fbtex.push_back(sm.depth);
+ sm.fb = RD::get_singleton()->framebuffer_create(fbtex);
+
+ shadow_maps[p_size] = sm;
+ }
+
+ return &shadow_maps[p_size];
+}
+
+//////////////////////////
+
+RID RasterizerSceneRD::decal_instance_create(RID p_decal) {
+ DecalInstance di;
+ di.decal = p_decal;
+ return decal_instance_owner.make_rid(di);
+}
+
+void RasterizerSceneRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) {
+ DecalInstance *di = decal_instance_owner.getornull(p_decal);
+ ERR_FAIL_COND(!di);
+ di->transform = p_transform;
+}
+
+/////////////////////////////////
+
+RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) {
+ //find a free slot
+ int index = -1;
+ for (int i = 0; i < gi_probe_slots.size(); i++) {
+ if (gi_probe_slots[i] == RID()) {
+ index = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND_V(index == -1, RID());
+
+ GIProbeInstance gi_probe;
+ gi_probe.slot = index;
+ gi_probe.probe = p_base;
+ RID rid = gi_probe_instance_owner.make_rid(gi_probe);
+ gi_probe_slots.write[index] = rid;
+
+ return rid;
+}
+
+void RasterizerSceneRD::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;
+}
+
+bool RasterizerSceneRD::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);
+
+ //return true;
+ return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
+}
+
+void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) {
+
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ 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);
+ if (gi_probe_use_anisotropy) {
+ RD::get_singleton()->free(gi_probe->anisotropy_r16[0]);
+ RD::get_singleton()->free(gi_probe->anisotropy_r16[1]);
+ }
+ 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.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, false);
+
+ if (gi_probe_use_anisotropy) {
+ tf.format = RD::DATA_FORMAT_R16_UINT;
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R5G6B5_UNORM_PACK16);
+
+ //need to create R16 first, else driver does not like the storage bit for compute..
+ gi_probe->anisotropy_r16[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ gi_probe->anisotropy_r16[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R5G6B5_UNORM_PACK16;
+ gi_probe->anisotropy[0] = RD::get_singleton()->texture_create_shared(tv, gi_probe->anisotropy_r16[0]);
+ gi_probe->anisotropy[1] = RD::get_singleton()->texture_create_shared(tv, gi_probe->anisotropy_r16[1]);
+
+ RD::get_singleton()->texture_clear(gi_probe->anisotropy[0], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+ RD::get_singleton()->texture_clear(gi_probe->anisotropy[1], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
+ }
+
+ {
+ int total_elements = 0;
+ for (int i = 0; i < levels.size(); i++) {
+ total_elements += levels[i];
+ }
+
+ if (gi_probe_use_anisotropy) {
+ total_elements *= 6;
+ }
+
+ 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);
+ if (gi_probe_use_anisotropy) {
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R16_UINT;
+ mipmap.anisotropy[0] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[0], 0, i, RD::TEXTURE_SLICE_3D);
+ mipmap.anisotropy[1] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[1], 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.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.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.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.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.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.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.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ u.ids.push_back(gi_probe->texture);
+ copy_uniforms.push_back(u);
+ }
+
+ if (gi_probe_use_anisotropy) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 7;
+ u.ids.push_back(gi_probe->anisotropy[0]);
+ copy_uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 8;
+ u.ids.push_back(gi_probe->anisotropy[1]);
+ 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.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(mipmap.texture);
+ uniforms.push_back(u);
+ }
+
+ if (gi_probe_use_anisotropy) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(mipmap.anisotropy[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(mipmap.anisotropy[1]);
+ 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.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.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 5;
+ u.ids.push_back(dmap.albedo);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 6;
+ u.ids.push_back(dmap.normal);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.orm);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 8;
+ u.ids.push_back(dmap.fb_depth);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.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.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.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.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.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.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.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 7;
+ u.ids.push_back(dmap.texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 8;
+ u.ids.push_back(dmap.depth);
+ uniforms.push_back(u);
+ }
+ }
+
+ {
+ RD::Uniform u;
+ u.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.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.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 11;
+ u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
+ uniforms.push_back(u);
+ }
+ if (gi_probe_is_anisotropic()) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 12;
+ u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 13;
+ u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[1]);
+ 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, true);
+ if (gi_probe_is_anisotropic()) {
+ RD::get_singleton()->texture_clear(gi_probe->anisotropy[0], Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
+ RD::get_singleton()->texture_clear(gi_probe->anisotropy[1], Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
+ }
+ }
+
+ uint32_t light_count = 0;
+
+ if (p_update_light_instances || p_dynamic_object_count > 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);
+ 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.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE));
+ l.spot_attenuation = 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, true);
+ }
+ }
+
+ if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) {
+ // 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 = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
+
+ /* 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_object_count && 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 < p_dynamic_object_count; i++) {
+
+ InstanceBase *instance = p_dynamic_objects[i];
+ //not used, so clear
+ instance->depth_layer = 0;
+ instance->depth = 0;
+
+ //transform aabb to giprobe
+ AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb);
+
+ //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]);
+
+ _render_material(to_world_xform * xform, cm, true, &instance, 1, 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 RasterizerSceneRD::_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.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.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 2;
+ u.ids.push_back(gi_probe->texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.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);
+ }
+
+ if (gi_probe_use_anisotropy) {
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 4;
+ u.ids.push_back(gi_probe->anisotropy[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 5;
+ u.ids.push_back(gi_probe->anisotropy[1]);
+ 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);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].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);
+}
+
+const Vector<RID> &RasterizerSceneRD::gi_probe_get_slots() const {
+
+ return gi_probe_slots;
+}
+
+RasterizerSceneRD::GIProbeQuality RasterizerSceneRD::gi_probe_get_quality() const {
+ return gi_probe_quality;
+}
+
+////////////////////////////////
+RID RasterizerSceneRD::render_buffers_create() {
+ RenderBuffers rb;
+ rb.data = _create_render_buffer_data();
+ return render_buffers_owner.make_rid(rb);
+}
+
+void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) {
+ ERR_FAIL_COND(!rb->blur[0].texture.is_null());
+
+ uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH);
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.type = RD::TEXTURE_TYPE_2D;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tf.mipmaps = mipmaps_required;
+
+ rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ //the second one is smaller (only used for separatable part of blur)
+ tf.width >>= 1;
+ tf.height >>= 1;
+ tf.mipmaps--;
+ rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ int base_width = rb->width;
+ int base_height = rb->height;
+
+ for (uint32_t i = 0; i < mipmaps_required; i++) {
+
+ RenderBuffers::Blur::Mipmap mm;
+ mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[0].texture, 0, i);
+
+ mm.width = base_width;
+ mm.height = base_height;
+
+ rb->blur[0].mipmaps.push_back(mm);
+
+ if (i > 0) {
+
+ mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1);
+
+ rb->blur[1].mipmaps.push_back(mm);
+ }
+
+ base_width = MAX(1, base_width >> 1);
+ base_height = MAX(1, base_height >> 1);
+ }
+}
+
+void RasterizerSceneRD::_allocate_luminance_textures(RenderBuffers *rb) {
+ ERR_FAIL_COND(!rb->luminance.current.is_null());
+
+ int w = rb->width;
+ int h = rb->height;
+
+ while (true) {
+ w = MAX(w / 8, 1);
+ h = MAX(h / 8, 1);
+
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ tf.width = w;
+ tf.height = h;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ bool final = w == 1 && h == 1;
+
+ if (final) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
+ }
+
+ RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ rb->luminance.reduce.push_back(texture);
+
+ if (final) {
+ rb->luminance.current = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ break;
+ }
+ }
+}
+
+void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) {
+
+ if (rb->texture.is_valid()) {
+ RD::get_singleton()->free(rb->texture);
+ rb->texture = RID();
+ }
+
+ if (rb->depth_texture.is_valid()) {
+ RD::get_singleton()->free(rb->depth_texture);
+ rb->depth_texture = RID();
+ }
+
+ for (int i = 0; i < 2; i++) {
+ if (rb->blur[i].texture.is_valid()) {
+ RD::get_singleton()->free(rb->blur[i].texture);
+ rb->blur[i].texture = RID();
+ rb->blur[i].mipmaps.clear();
+ }
+ }
+
+ for (int i = 0; i < rb->luminance.reduce.size(); i++) {
+ RD::get_singleton()->free(rb->luminance.reduce[i]);
+ }
+
+ for (int i = 0; i < rb->luminance.reduce.size(); i++) {
+ RD::get_singleton()->free(rb->luminance.reduce[i]);
+ }
+ rb->luminance.reduce.clear();
+
+ if (rb->luminance.current.is_valid()) {
+ RD::get_singleton()->free(rb->luminance.current);
+ rb->luminance.current = RID();
+ }
+
+ if (rb->ssao.ao[0].is_valid()) {
+ RD::get_singleton()->free(rb->ssao.depth);
+ RD::get_singleton()->free(rb->ssao.ao[0]);
+ if (rb->ssao.ao[1].is_valid()) {
+ RD::get_singleton()->free(rb->ssao.ao[1]);
+ }
+ if (rb->ssao.ao_full.is_valid()) {
+ RD::get_singleton()->free(rb->ssao.ao_full);
+ }
+
+ rb->ssao.depth = RID();
+ rb->ssao.ao[0] = RID();
+ rb->ssao.ao[1] = RID();
+ rb->ssao.ao_full = RID();
+ rb->ssao.depth_slices.clear();
+ }
+
+ if (rb->ssr.blur_radius[0].is_valid()) {
+ RD::get_singleton()->free(rb->ssr.blur_radius[0]);
+ RD::get_singleton()->free(rb->ssr.blur_radius[1]);
+ rb->ssr.blur_radius[0] = RID();
+ rb->ssr.blur_radius[1] = RID();
+ }
+
+ if (rb->ssr.depth_scaled.is_valid()) {
+ RD::get_singleton()->free(rb->ssr.depth_scaled);
+ rb->ssr.depth_scaled = RID();
+ RD::get_singleton()->free(rb->ssr.normal_scaled);
+ rb->ssr.normal_scaled = RID();
+ }
+}
+
+void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) {
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+
+ if (!can_use_effects) {
+ //just copy
+ return;
+ }
+
+ 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);
+}
+
+void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) {
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+
+ if (!can_use_effects) {
+ //just copy
+ storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, RID());
+ return;
+ }
+
+ Environent *env = environment_owner.getornull(p_environment);
+ ERR_FAIL_COND(!env);
+
+ ERR_FAIL_COND(!env->ssr_enabled);
+
+ if (rb->ssr.depth_scaled.is_null()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ tf.width = rb->width / 2;
+ tf.height = rb->height / 2;
+ tf.type = RD::TEXTURE_TYPE_2D;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+ rb->ssr.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+
+ rb->ssr.normal_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = rb->width / 2;
+ tf.height = rb->height / 2;
+ tf.type = RD::TEXTURE_TYPE_2D;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+ rb->ssr.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->ssr.blur_radius[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ 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, p_roughness_buffer, 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);
+ storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture);
+}
+
+void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) {
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ Environent *env = environment_owner.getornull(p_environment);
+ ERR_FAIL_COND(!env);
+
+ if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) {
+ RD::get_singleton()->free(rb->ssao.depth);
+ RD::get_singleton()->free(rb->ssao.ao[0]);
+ if (rb->ssao.ao[1].is_valid()) {
+ RD::get_singleton()->free(rb->ssao.ao[1]);
+ }
+ if (rb->ssao.ao_full.is_valid()) {
+ RD::get_singleton()->free(rb->ssao.ao_full);
+ }
+
+ rb->ssao.depth = RID();
+ rb->ssao.ao[0] = RID();
+ rb->ssao.ao[1] = RID();
+ rb->ssao.ao_full = RID();
+ rb->ssao.depth_slices.clear();
+ }
+
+ if (!rb->ssao.ao[0].is_valid()) {
+ //allocate depth slices
+
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+ tf.width = rb->width / 2;
+ tf.height = rb->height / 2;
+ tf.mipmaps = Image::get_image_required_mipmaps(tf.width, tf.height, Image::FORMAT_RF) + 1;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ rb->ssao.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ for (uint32_t i = 0; i < tf.mipmaps; i++) {
+ RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i);
+ rb->ssao.depth_slices.push_back(slice);
+ }
+ }
+
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = ssao_half_size ? rb->width / 2 : rb->width;
+ tf.height = ssao_half_size ? rb->height / 2 : rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ rb->ssao.ao[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->ssao.ao[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ if (ssao_half_size) {
+ //upsample texture
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ rb->ssao.ao_full = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ _render_buffers_uniform_set_changed(p_render_buffers);
+ }
+
+ storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, Size2i(rb->width, rb->height), rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao[0], rb->ssao.ao_full.is_valid(), rb->ssao.ao[1], rb->ssao.ao_full, env->ssao_intensity, env->ssao_radius, env->ssao_bias, p_projection, ssao_quality, env->ssao_blur, env->ssao_blur_edge_sharpness);
+}
+
+void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) {
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ Environent *env = environment_owner.getornull(p_environment);
+ //glow (if enabled)
+ CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
+
+ bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+
+ 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;
+ storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_projection.get_z_near(), p_projection.get_z_far(), p_projection.is_orthogonal());
+ }
+
+ 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;
+ rb->auto_exposure_version = env->auto_exposure_version;
+
+ double step = env->auto_exp_speed * time_step;
+ storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+
+ //swap final reduce with prev luminance
+ SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]);
+ RenderingServerRaster::redraw_request(); //redraw all the time if auto exposure rendering is on
+ }
+
+ int max_glow_level = -1;
+ int glow_mask = 0;
+
+ if (can_use_effects && env && env->glow_enabled) {
+
+ /* see that blur textures are allocated */
+
+ if (rb->blur[0].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++) {
+ if (env->glow_levels & (1 << i)) {
+
+ if (i >= rb->blur[1].mipmaps.size()) {
+ max_glow_level = rb->blur[1].mipmaps.size() - 1;
+ glow_mask |= 1 << max_glow_level;
+
+ } else {
+ max_glow_level = i;
+ glow_mask |= (1 << i);
+ }
+ }
+ }
+
+ for (int i = 0; i < (max_glow_level + 1); i++) {
+
+ int vp_w = rb->blur[1].mipmaps[i].width;
+ int vp_h = rb->blur[1].mipmaps[i].height;
+
+ if (i == 0) {
+ RID luminance_texture;
+ if (env->auto_exposure && rb->luminance.current.is_valid()) {
+ luminance_texture = rb->luminance.current;
+ }
+ storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ } else {
+ storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength);
+ }
+ }
+ }
+
+ {
+ //tonemap
+ RasterizerEffectsRD::TonemapSettings tonemap;
+
+ tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+
+ if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) {
+ tonemap.use_auto_exposure = true;
+ tonemap.exposure_texture = rb->luminance.current;
+ tonemap.auto_exposure_grey = env->auto_exp_scale;
+ } else {
+
+ tonemap.exposure_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
+ }
+
+ if (can_use_effects && env && env->glow_enabled) {
+ tonemap.use_glow = true;
+ tonemap.glow_mode = RasterizerEffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode);
+ tonemap.glow_intensity = env->glow_blend_mode == RS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity;
+ tonemap.glow_level_flags = glow_mask;
+ tonemap.glow_texture_size.x = rb->blur[1].mipmaps[0].width;
+ tonemap.glow_texture_size.y = rb->blur[1].mipmaps[0].height;
+ tonemap.glow_use_bicubic_upscale = glow_bicubic_upscale;
+ tonemap.glow_texture = rb->blur[1].texture;
+ } else {
+ tonemap.glow_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
+ }
+
+ if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
+ tonemap.use_fxaa = true;
+ }
+
+ tonemap.texture_size = Vector2i(rb->width, rb->height);
+
+ if (env) {
+ tonemap.tonemap_mode = env->tone_mapper;
+ tonemap.white = env->white;
+ tonemap.exposure = env->exposure;
+ }
+
+ storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+ }
+
+ storage->render_target_disable_clear_request(rb->render_target);
+}
+
+void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) {
+ RasterizerEffectsRD *effects = storage->get_effects();
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
+ if (p_shadow_atlas.is_valid()) {
+ RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+
+ effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true);
+ }
+ }
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) {
+ if (directional_shadow_get_texture().is_valid()) {
+ RID shadow_atlas_texture = directional_shadow_get_texture();
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+
+ effects->copy_to_fb_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, true);
+ }
+ }
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DECAL_ATLAS) {
+ RID decal_atlas = storage->decal_atlas_get_texture();
+
+ if (decal_atlas.is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+
+ effects->copy_to_fb_rect(decal_atlas, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2i(Vector2(), rtsize / 2), false, false, true);
+ }
+ }
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) {
+ if (rb->luminance.current.is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+
+ effects->copy_to_fb_rect(rb->luminance.current, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true);
+ }
+ }
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao[0].is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+ RID ao_buf = rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0];
+ effects->copy_to_fb_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true);
+ }
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER && _render_buffers_get_roughness_texture(p_render_buffers).is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+ effects->copy_to_fb_rect(_render_buffers_get_roughness_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true);
+ }
+
+ if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) {
+ Size2 rtsize = storage->render_target_get_size(rb->render_target);
+ effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, false);
+ }
+}
+
+RID RasterizerSceneRD::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());
+ if (!rb->blur[0].texture.is_valid()) {
+ return RID(); //not valid at the moment
+ }
+ return rb->blur[0].texture;
+}
+
+RID RasterizerSceneRD::render_buffers_get_ao_texture(RID p_render_buffers) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, RID());
+
+ return rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0];
+}
+
+void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa) {
+
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ rb->width = p_width;
+ rb->height = p_height;
+ rb->render_target = p_render_target;
+ rb->msaa = p_msaa;
+ rb->screen_space_aa = p_screen_space_aa;
+ _free_render_buffer_data(rb);
+
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ tf.width = rb->width;
+ tf.height = rb->height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ } else {
+ tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ {
+ RD::TextureFormat tf;
+ 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.width = p_width;
+ tf.height = p_height;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ }
+
+ rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
+ _render_buffers_uniform_set_changed(p_render_buffers);
+}
+
+void RasterizerSceneRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
+ sss_quality = p_quality;
+}
+
+RS::SubSurfaceScatteringQuality RasterizerSceneRD::sub_surface_scattering_get_quality() const {
+ return sss_quality;
+}
+
+void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) {
+ sss_scale = p_scale;
+ sss_depth_scale = p_depth_scale;
+}
+
+void RasterizerSceneRD::shadows_quality_set(RS::ShadowQuality p_quality) {
+
+ ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum");
+
+ if (shadows_quality != p_quality) {
+ shadows_quality = p_quality;
+
+ switch (shadows_quality) {
+ case RS::SHADOW_QUALITY_HARD: {
+ penumbra_shadow_samples = 4;
+ soft_shadow_samples = 1;
+ shadows_quality_radius = 1.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_LOW: {
+ penumbra_shadow_samples = 8;
+ soft_shadow_samples = 4;
+ shadows_quality_radius = 2.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_MEDIUM: {
+ penumbra_shadow_samples = 12;
+ soft_shadow_samples = 8;
+ shadows_quality_radius = 2.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_HIGH: {
+ penumbra_shadow_samples = 24;
+ soft_shadow_samples = 16;
+ shadows_quality_radius = 3.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_ULTRA: {
+ penumbra_shadow_samples = 32;
+ soft_shadow_samples = 32;
+ shadows_quality_radius = 4.0;
+ } break;
+ case RS::SHADOW_QUALITY_MAX:
+ break;
+ }
+ get_vogel_disk(penumbra_shadow_kernel, penumbra_shadow_samples);
+ get_vogel_disk(soft_shadow_kernel, soft_shadow_samples);
+ }
+}
+
+void RasterizerSceneRD::directional_shadow_quality_set(RS::ShadowQuality p_quality) {
+
+ ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum");
+
+ if (directional_shadow_quality != p_quality) {
+ directional_shadow_quality = p_quality;
+
+ switch (directional_shadow_quality) {
+ case RS::SHADOW_QUALITY_HARD: {
+ directional_penumbra_shadow_samples = 4;
+ directional_soft_shadow_samples = 1;
+ directional_shadow_quality_radius = 1.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_LOW: {
+ directional_penumbra_shadow_samples = 8;
+ directional_soft_shadow_samples = 4;
+ directional_shadow_quality_radius = 2.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_MEDIUM: {
+ directional_penumbra_shadow_samples = 12;
+ directional_soft_shadow_samples = 8;
+ directional_shadow_quality_radius = 2.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_HIGH: {
+ directional_penumbra_shadow_samples = 24;
+ directional_soft_shadow_samples = 16;
+ directional_shadow_quality_radius = 3.0;
+ } break;
+ case RS::SHADOW_QUALITY_SOFT_ULTRA: {
+ directional_penumbra_shadow_samples = 32;
+ directional_soft_shadow_samples = 32;
+ directional_shadow_quality_radius = 4.0;
+ } break;
+ case RS::SHADOW_QUALITY_MAX:
+ break;
+ }
+ get_vogel_disk(directional_penumbra_shadow_kernel, directional_penumbra_shadow_samples);
+ get_vogel_disk(directional_soft_shadow_kernel, directional_soft_shadow_samples);
+ }
+}
+
+int RasterizerSceneRD::get_roughness_layers() const {
+ return roughness_layers;
+}
+
+bool RasterizerSceneRD::is_using_radiance_cubemap_array() const {
+ return sky_use_cubemap_array;
+}
+
+RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data(RID p_render_buffers) {
+ RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+ ERR_FAIL_COND_V(!rb, nullptr);
+ return rb->data;
+}
+
+void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+
+ 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();
+ }
+
+ _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_decal_cull_result, p_decal_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
+
+ if (p_render_buffers.is_valid()) {
+ 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);
+ }
+}
+
+void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light);
+ ERR_FAIL_COND(!light_instance);
+
+ Rect2i atlas_rect;
+ RID atlas_texture;
+
+ bool using_dual_paraboloid = false;
+ bool using_dual_paraboloid_flip = false;
+ float znear = 0;
+ float zfar = 0;
+ RID render_fb;
+ RID render_texture;
+ float bias = 0;
+ float normal_bias = 0;
+
+ bool use_pancake = false;
+ bool use_linear_depth = false;
+ bool render_cubemap = false;
+ bool finalize_cubemap = false;
+
+ CameraMatrix light_projection;
+ Transform light_transform;
+
+ if (storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) {
+ //set pssm stuff
+ if (light_instance->last_scene_shadow_pass != scene_pass) {
+ light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
+ directional_shadow.current_light++;
+ light_instance->last_scene_shadow_pass = scene_pass;
+ }
+
+ use_pancake = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0;
+ light_projection = light_instance->shadow_transform[p_pass].camera;
+ light_transform = light_instance->shadow_transform[p_pass].transform;
+
+ atlas_rect.position.x = light_instance->directional_rect.position.x;
+ atlas_rect.position.y = light_instance->directional_rect.position.y;
+ atlas_rect.size.width = light_instance->directional_rect.size.x;
+ atlas_rect.size.height = light_instance->directional_rect.size.y;
+
+ if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+
+ atlas_rect.size.width /= 2;
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 1) {
+ atlas_rect.position.x += atlas_rect.size.width;
+ } else if (p_pass == 2) {
+ atlas_rect.position.y += atlas_rect.size.height;
+ } else if (p_pass == 3) {
+ atlas_rect.position.x += atlas_rect.size.width;
+ atlas_rect.position.y += atlas_rect.size.height;
+ }
+
+ } else if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 0) {
+
+ } else {
+ atlas_rect.position.y += atlas_rect.size.height;
+ }
+ }
+
+ light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect;
+
+ light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size;
+ light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size;
+
+ float bias_mult = light_instance->shadow_transform[p_pass].bias_scale;
+ zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
+ bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult;
+ normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult;
+
+ ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
+ render_fb = shadow_map->fb;
+ render_texture = shadow_map->depth;
+ atlas_texture = directional_shadow.depth;
+
+ } else {
+ //set from shadow atlas
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light));
+
+ uint32_t key = shadow_atlas->shadow_owners[p_light];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+ atlas_rect.position.x = (quadrant & 1) * quadrant_size;
+ atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ atlas_rect.size.width = shadow_size;
+ atlas_rect.size.height = shadow_size;
+ atlas_texture = shadow_atlas->depth;
+
+ zfar = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
+ bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_BIAS);
+ normal_bias = storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS);
+
+ if (storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) {
+
+ if (storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+
+ ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2);
+
+ render_fb = cubemap->side_fb[p_pass];
+ render_texture = cubemap->cubemap;
+
+ light_projection = light_instance->shadow_transform[0].camera;
+ light_transform = light_instance->shadow_transform[0].transform;
+ render_cubemap = true;
+ finalize_cubemap = p_pass == 5;
+
+ } else {
+
+ light_projection = light_instance->shadow_transform[0].camera;
+ light_transform = light_instance->shadow_transform[0].transform;
+
+ atlas_rect.size.height /= 2;
+ atlas_rect.position.y += p_pass * atlas_rect.size.height;
+
+ using_dual_paraboloid = true;
+ using_dual_paraboloid_flip = p_pass == 1;
+
+ ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
+ render_fb = shadow_map->fb;
+ render_texture = shadow_map->depth;
+ }
+
+ } else if (storage->light_get_type(light_instance->light) == RS::LIGHT_SPOT) {
+
+ light_projection = light_instance->shadow_transform[0].camera;
+ light_transform = light_instance->shadow_transform[0].transform;
+
+ ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
+ render_fb = shadow_map->fb;
+ render_texture = shadow_map->depth;
+
+ znear = light_instance->shadow_transform[0].camera.get_z_near();
+ use_linear_depth = true;
+ }
+ }
+
+ if (render_cubemap) {
+ //rendering to cubemap
+ _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake);
+ if (finalize_cubemap) {
+ //reblit
+ atlas_rect.size.height /= 2;
+ storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, false);
+ atlas_rect.position.y += atlas_rect.size.height;
+ storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_texture, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), 0.0, true);
+ }
+ } else {
+ //render shadow
+
+ _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake);
+
+ //copy to atlas
+ if (use_linear_depth) {
+ storage->get_effects()->copy_depth_to_rect_and_linearize(render_texture, atlas_texture, atlas_rect, true, znear, zfar);
+ } else {
+ storage->get_effects()->copy_depth_to_rect(render_texture, atlas_texture, atlas_rect, true);
+ }
+
+ //does not work from depth to color
+ //RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true);
+ }
+}
+
+void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
+
+ _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region);
+}
+
+bool RasterizerSceneRD::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);
+ render_buffers_owner.free(p_rid);
+ } else if (environment_owner.owns(p_rid)) {
+ //not much to delete, just free it
+ environment_owner.free(p_rid);
+ } else if (camera_effects_owner.owns(p_rid)) {
+ //not much to delete, just free it
+ camera_effects_owner.free(p_rid);
+ } else if (reflection_atlas_owner.owns(p_rid)) {
+ reflection_atlas_set_size(p_rid, 0, 0);
+ reflection_atlas_owner.free(p_rid);
+ } else if (reflection_probe_instance_owner.owns(p_rid)) {
+ //not much to delete, just free it
+ //ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
+ reflection_probe_release_atlas_index(p_rid);
+ reflection_probe_instance_owner.free(p_rid);
+ } else if (decal_instance_owner.owns(p_rid)) {
+ decal_instance_owner.free(p_rid);
+ } else if (gi_probe_instance_owner.owns(p_rid)) {
+ GIProbeInstance *gi_probe = 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);
+ }
+ if (gi_probe->anisotropy[0].is_valid()) {
+ RD::get_singleton()->free(gi_probe->anisotropy[0]);
+ RD::get_singleton()->free(gi_probe->anisotropy[1]);
+ }
+
+ 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_slots.write[gi_probe->slot] = RID();
+
+ 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);
+ } else if (light_instance_owner.owns(p_rid)) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_rid);
+
+ //remove from shadow atlases..
+ for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get());
+ ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid));
+ uint32_t key = shadow_atlas->shadow_owners[p_rid];
+ uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+ shadow_atlas->shadow_owners.erase(p_rid);
+ }
+
+ light_instance_owner.free(p_rid);
+
+ } else if (shadow_atlas_owner.owns(p_rid)) {
+
+ shadow_atlas_set_size(p_rid, 0);
+ shadow_atlas_owner.free(p_rid);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void RasterizerSceneRD::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) {
+ debug_draw = p_debug_draw;
+}
+
+void RasterizerSceneRD::update() {
+ _update_dirty_skys();
+}
+
+void RasterizerSceneRD::set_time(double p_time, double p_step) {
+ time = p_time;
+ time_step = p_step;
+}
+
+void RasterizerSceneRD::screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) {
+ screen_space_roughness_limiter = p_enable;
+ screen_space_roughness_limiter_curve = p_curve;
+}
+
+bool RasterizerSceneRD::screen_space_roughness_limiter_is_active() const {
+ return screen_space_roughness_limiter;
+}
+
+float RasterizerSceneRD::screen_space_roughness_limiter_get_curve() const {
+ return screen_space_roughness_limiter_curve;
+}
+
+RasterizerSceneRD *RasterizerSceneRD::singleton = nullptr;
+
+RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
+ 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");
+ // sky_use_cubemap_array = false;
+
+ uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
+
+ {
+
+ //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_use_anisotropy = GLOBAL_GET("rendering/quality/gi_probes/anisotropic");
+ gi_probe_quality = GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/quality/gi_probes/quality")), 0, 2));
+
+ if (textures_per_stage <= 16) {
+ gi_probe_slots.resize(2); //thats all you can get
+ gi_probe_use_anisotropy = false;
+ } else if (textures_per_stage <= 31) {
+ gi_probe_slots.resize(4); //thats all you can get, iOS
+ gi_probe_use_anisotropy = false;
+ } else if (textures_per_stage <= 128) {
+ gi_probe_slots.resize(32); //old intel
+ gi_probe_use_anisotropy = false;
+ } else if (textures_per_stage <= 256) {
+ gi_probe_slots.resize(64); //old intel too
+ gi_probe_use_anisotropy = false;
+ } else {
+ if (gi_probe_use_anisotropy) {
+ gi_probe_slots.resize(1024 / 3); //needs 3 textures
+ } else {
+ gi_probe_slots.resize(1024); //modern intel, nvidia, 8192 or greater
+ }
+ }
+
+ String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
+ if (gi_probe_use_anisotropy) {
+ defines += "\n#define MODE_ANISOTROPIC\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;
+ if (gi_probe_use_anisotropy) {
+ defines += "\n#define USE_ANISOTROPY\n";
+ }
+ 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);
+ }
+ }
+
+ /* 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(RasterizerStorageRD::SHADER_TYPE_SKY, _create_sky_shader_funcs);
+ storage->material_set_data_request_function(RasterizerStorageRD::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["LIGHT0_ENABLED"] = "directional_lights.data[0].enabled";
+ actions.renames["LIGHT0_DIRECTION"] = "directional_lights.data[0].direction";
+ actions.renames["LIGHT0_ENERGY"] = "directional_lights.data[0].energy";
+ actions.renames["LIGHT0_COLOR"] = "directional_lights.data[0].color";
+ actions.renames["LIGHT1_ENABLED"] = "directional_lights.data[1].enabled";
+ actions.renames["LIGHT1_DIRECTION"] = "directional_lights.data[1].direction";
+ actions.renames["LIGHT1_ENERGY"] = "directional_lights.data[1].energy";
+ actions.renames["LIGHT1_COLOR"] = "directional_lights.data[1].color";
+ actions.renames["LIGHT2_ENABLED"] = "directional_lights.data[2].enabled";
+ actions.renames["LIGHT2_DIRECTION"] = "directional_lights.data[2].direction";
+ actions.renames["LIGHT2_ENERGY"] = "directional_lights.data[2].energy";
+ actions.renames["LIGHT2_COLOR"] = "directional_lights.data[2].color";
+ actions.renames["LIGHT3_ENABLED"] = "directional_lights.data[3].enabled";
+ actions.renames["LIGHT3_DIRECTION"] = "directional_lights.data[3].direction";
+ actions.renames["LIGHT3_ENERGY"] = "directional_lights.data[3].energy";
+ actions.renames["LIGHT3_COLOR"] = "directional_lights.data[3].color";
+ 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.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;
+
+ 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 = mix(vec3(0.3), vec3(0.2, 0.4, 0.9), smoothstep(0.0, 0.05, EYEDIR.y)); } \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, RasterizerStorageRD::SHADER_TYPE_SKY);
+ sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.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);
+ }
+
+ sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS);
+ }
+
+ 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"));
+ screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter");
+ screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_curve");
+ glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
+ 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");
+ 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"))));
+}
+
+RasterizerSceneRD::~RasterizerSceneRD() {
+ for (Map<Vector2i, ShadowMap>::Element *E = shadow_maps.front(); E; E = E->next()) {
+ RD::get_singleton()->free(E->get().depth);
+ }
+ for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) {
+ RD::get_singleton()->free(E->get().cubemap);
+ }
+
+ if (sky_scene_state.sampler_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.sampler_uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.sampler_uniform_set);
+ }
+ if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
+ RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+ }
+
+ RD::get_singleton()->free(gi_probe_lights_uniform);
+ giprobe_debug_shader.version_free(giprobe_debug_shader_version);
+ giprobe_shader.version_free(giprobe_lighting_shader_version);
+ memdelete_arr(gi_probe_lights);
+ SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+ sky_shader.shader.version_free(md->shader_data->version);
+ RD::get_singleton()->free(sky_scene_state.directional_light_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);
+ memdelete_arr(directional_penumbra_shadow_kernel);
+ memdelete_arr(directional_soft_shadow_kernel);
+ memdelete_arr(penumbra_shadow_kernel);
+ memdelete_arr(soft_shadow_kernel);
+}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
new file mode 100644
index 0000000000..bb42ce7182
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -0,0 +1,1250 @@
+/*************************************************************************/
+/* rasterizer_scene_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_SCENE_RD_H
+#define RASTERIZER_SCENE_RD_H
+
+#include "core/rid_owner.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_storage_rd.h"
+#include "servers/rendering/rasterizer_rd/shaders/giprobe.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/sky.glsl.gen.h"
+#include "servers/rendering/rendering_device.h"
+
+class RasterizerSceneRD : public RasterizerScene {
+public:
+ enum GIProbeQuality {
+ GIPROBE_QUALITY_ULTRA_LOW,
+ GIPROBE_QUALITY_MEDIUM,
+ GIPROBE_QUALITY_HIGH,
+ };
+
+protected:
+ double time;
+
+ // Skys need less info from Directional Lights than the normal shaders
+ struct SkyDirectionalLightData {
+
+ float direction[3];
+ float energy;
+ float color[3];
+ uint32_t enabled;
+ };
+
+ struct SkySceneState {
+
+ SkyDirectionalLightData *directional_lights;
+ SkyDirectionalLightData *last_frame_directional_lights;
+ uint32_t max_directional_lights;
+ uint32_t directional_light_count;
+ uint32_t last_frame_directional_light_count;
+ RID directional_light_buffer;
+ RID sampler_uniform_set;
+ RID light_uniform_set;
+ } sky_scene_state;
+
+ struct RenderBufferData {
+
+ virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0;
+ virtual ~RenderBufferData() {}
+ };
+ virtual RenderBufferData *_create_render_buffer_data() = 0;
+
+ virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, 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) = 0;
+ virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip, bool p_use_pancake) = 0;
+ virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 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);
+
+ 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_roughness_texture(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_roughness_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, const Vector3 &p_position, 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);
+
+private:
+ RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
+ double time_step = 0;
+ static RasterizerSceneRD *singleton;
+
+ int roughness_layers;
+
+ RasterizerStorageRD *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);
+
+ /* 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 RasterizerStorageRD::ShaderData {
+ bool valid;
+ RID version;
+
+ RenderPipelineVertexFormatCacheRD 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 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;
+ SkyShaderData();
+ virtual ~SkyShaderData();
+ };
+
+ RasterizerStorageRD::ShaderData *_create_sky_shader_func();
+ static RasterizerStorageRD::ShaderData *_create_sky_shader_funcs() {
+ return static_cast<RasterizerSceneRD *>(singleton)->_create_sky_shader_func();
+ };
+
+ struct SkyMaterialData : public RasterizerStorageRD::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();
+ };
+
+ RasterizerStorageRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
+ static RasterizerStorageRD::MaterialData *_create_sky_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
+ return static_cast<RasterizerSceneRD *>(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_SAMPLERS,
+ SKY_SET_MATERIAL,
+ SKY_SET_TEXTURES,
+ SKY_SET_LIGHTS,
+ 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_QUALITY;
+
+ ReflectionData reflection;
+ bool dirty = false;
+ Sky *dirty_list = nullptr;
+
+ //State to track when radiance cubemap needs updating
+ SkyMaterialData *prev_material;
+ Vector3 prev_position;
+ float prev_time;
+ };
+
+ 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);
+
+ uint32_t sky_ggx_samples_quality;
+ bool sky_use_cubemap_array;
+
+ mutable RID_Owner<Sky> sky_owner;
+
+ /* REFLECTION ATLAS */
+
+ struct ReflectionAtlas {
+
+ int count = 0;
+ int size = 0;
+
+ RID reflection;
+ RID depth_buffer;
+ RID depth_fb;
+
+ struct Reflection {
+ RID owner;
+ ReflectionData data;
+ RID fbs[6];
+ };
+
+ Vector<Reflection> reflections;
+ };
+
+ RID_Owner<ReflectionAtlas> reflection_atlas_owner;
+
+ /* REFLECTION PROBE INSTANCE */
+
+ struct ReflectionProbeInstance {
+
+ RID probe;
+ int atlas_index = -1;
+ RID atlas;
+
+ bool dirty = true;
+ bool rendering = false;
+ int processing_layer = 1;
+ int processing_side = 0;
+
+ uint32_t render_step = 0;
+ uint64_t last_pass = 0;
+ uint32_t render_index = 0;
+
+ Transform transform;
+ };
+
+ mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
+
+ /* REFLECTION PROBE INSTANCE */
+
+ struct DecalInstance {
+
+ RID decal;
+ Transform transform;
+ };
+
+ mutable RID_Owner<DecalInstance> decal_instance_owner;
+
+ /* GIPROBE INSTANCE */
+
+ struct GIProbeLight {
+
+ uint32_t type;
+ float energy;
+ float radius;
+ float attenuation;
+
+ float color[3];
+ float spot_angle_radians;
+
+ float position[3];
+ float 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 anisotropy[2]; //only if anisotropy is used
+ RID anisotropy_r16[2]; //only if anisotropy is used
+ RID write_buffer;
+
+ struct Mipmap {
+ RID texture;
+ RID anisotropy[2]; //only if anisotropy is used
+ 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;
+
+ bool gi_probe_use_anisotropy = false;
+ GIProbeQuality gi_probe_quality = GIPROBE_QUALITY_MEDIUM;
+
+ Vector<RID> gi_probe_slots;
+
+ 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;
+
+ 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];
+ RenderPipelineVertexFormatCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
+ RID giprobe_debug_uniform_set;
+
+ /* SHADOW ATLAS */
+
+ struct ShadowAtlas {
+
+ enum {
+ QUADRANT_SHIFT = 27,
+ SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1,
+ SHADOW_INVALID = 0xFFFFFFFF
+ };
+
+ struct Quadrant {
+
+ uint32_t subdivision;
+
+ struct Shadow {
+ RID owner;
+ uint64_t version;
+ uint64_t alloc_tick;
+
+ Shadow() {
+ version = 0;
+ alloc_tick = 0;
+ }
+ };
+
+ Vector<Shadow> shadows;
+
+ Quadrant() {
+ subdivision = 0; //not in use
+ }
+
+ } quadrants[4];
+
+ int size_order[4] = { 0, 1, 2, 3 };
+ uint32_t smallest_subdiv = 0;
+
+ int size = 0;
+
+ RID depth;
+ RID fb; //for copying
+
+ Map<RID, uint32_t> shadow_owners;
+ };
+
+ RID_Owner<ShadowAtlas> shadow_atlas_owner;
+
+ bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
+
+ RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
+ RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
+ float shadows_quality_radius = 1.0;
+ float directional_shadow_quality_radius = 1.0;
+
+ float *directional_penumbra_shadow_kernel;
+ float *directional_soft_shadow_kernel;
+ float *penumbra_shadow_kernel;
+ float *soft_shadow_kernel;
+ int directional_penumbra_shadow_samples = 0;
+ int directional_soft_shadow_samples = 0;
+ int penumbra_shadow_samples = 0;
+ int soft_shadow_samples = 0;
+
+ /* DIRECTIONAL SHADOW */
+
+ struct DirectionalShadow {
+ RID depth;
+
+ int light_count = 0;
+ int size = 0;
+ int current_light = 0;
+ } directional_shadow;
+
+ /* SHADOW CUBEMAPS */
+
+ struct ShadowCubemap {
+
+ RID cubemap;
+ RID side_fb[6];
+ };
+
+ Map<int, ShadowCubemap> shadow_cubemaps;
+ ShadowCubemap *_get_shadow_cubemap(int p_size);
+
+ struct ShadowMap {
+ RID depth;
+ RID fb;
+ };
+
+ Map<Vector2i, ShadowMap> shadow_maps;
+ ShadowMap *_get_shadow_map(const Size2i &p_size);
+
+ void _create_shadow_cubemaps();
+
+ /* LIGHT INSTANCE */
+
+ struct LightInstance {
+
+ struct ShadowTransform {
+
+ CameraMatrix camera;
+ Transform transform;
+ float farplane;
+ float split;
+ float bias_scale;
+ float shadow_texel_size;
+ float range_begin;
+ Rect2 atlas_rect;
+ Vector2 uv_scale;
+ };
+
+ RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
+
+ ShadowTransform shadow_transform[4];
+
+ RID self;
+ RID light;
+ Transform transform;
+
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att = 0.0;
+
+ uint64_t shadow_pass = 0;
+ uint64_t last_scene_pass = 0;
+ uint64_t last_scene_shadow_pass = 0;
+ uint64_t last_pass = 0;
+ uint32_t light_index = 0;
+ uint32_t light_directional_index = 0;
+
+ uint32_t current_shadow_atlas_key = 0;
+
+ Vector2 dp;
+
+ Rect2 directional_rect;
+
+ Set<RID> shadow_atlases; //shadow atlases where this light is registered
+
+ LightInstance() {}
+ };
+
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
+ /* ENVIRONMENT */
+
+ struct Environent {
+
+ // 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;
+
+ /// Glow
+
+ bool glow_enabled = false;
+ int glow_levels = (1 << 2) | (1 << 4);
+ 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;
+ float ssao_intensity = 1;
+ float ssao_bias = 0.01;
+ float ssao_direct_light_affect = 0.0;
+ float ssao_ao_channel_affect = 0.0;
+ float ssao_blur_edge_sharpness = 4.0;
+ RS::EnvironmentSSAOBlur ssao_blur = RS::ENV_SSAO_BLUR_3x3;
+
+ /// 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;
+ };
+
+ RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
+ bool ssao_half_size = false;
+ bool glow_bicubic_upscale = false;
+ RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW;
+
+ static uint64_t auto_exposure_counter;
+
+ mutable RID_Owner<Environent> environment_owner;
+
+ /* CAMERA EFFECTS */
+
+ struct CameraEffects {
+
+ bool dof_blur_far_enabled = false;
+ float dof_blur_far_distance = 10;
+ float dof_blur_far_transition = 5;
+
+ bool dof_blur_near_enabled = false;
+ float dof_blur_near_distance = 2;
+ float dof_blur_near_transition = 1;
+
+ float dof_blur_amount = 0.1;
+
+ bool override_exposure_enabled = false;
+ float override_exposure = 1;
+ };
+
+ RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM;
+ RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON;
+ bool dof_blur_use_jitter = false;
+ RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
+ float sss_scale = 0.05;
+ float sss_depth_scale = 0.01;
+
+ mutable RID_Owner<CameraEffects> camera_effects_owner;
+
+ /* RENDER BUFFERS */
+
+ struct RenderBuffers {
+
+ RenderBufferData *data = nullptr;
+ int width = 0, height = 0;
+ RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
+ RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+
+ RID render_target;
+
+ uint64_t auto_exposure_version = 1;
+
+ RID texture; //main texture for rendering to, must be filled after done rendering
+ RID depth_texture; //main depth texture
+
+ //built-in textures used for ping pong image processing and blurring
+ struct Blur {
+ RID texture;
+
+ struct Mipmap {
+ RID texture;
+ int width;
+ int height;
+ };
+
+ Vector<Mipmap> mipmaps;
+ };
+
+ Blur blur[2]; //the second one starts from the first mipmap
+
+ struct Luminance {
+
+ Vector<RID> reduce;
+ RID current;
+ } luminance;
+
+ struct SSAO {
+ RID depth;
+ Vector<RID> depth_slices;
+ RID ao[2];
+ RID ao_full; //when using half-size
+ } ssao;
+
+ struct SSR {
+ RID normal_scaled;
+ RID depth_scaled;
+ RID blur_radius[2];
+ } ssr;
+ };
+
+ bool screen_space_roughness_limiter = false;
+ float screen_space_roughness_limiter_curve = 1.0;
+
+ mutable RID_Owner<RenderBuffers> render_buffers_owner;
+
+ void _free_render_buffer_data(RenderBuffers *rb);
+ 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_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection);
+
+ uint64_t scene_pass = 0;
+ uint64_t shadow_atlas_realloc_tolerance_msec = 500;
+
+public:
+ /* SHADOW ATLAS API */
+
+ RID shadow_atlas_create();
+ void shadow_atlas_set_size(RID p_atlas, int p_size);
+ void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision);
+ bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version);
+ _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
+ ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND_V(!atlas, false);
+ return atlas->shadow_owners.has(p_light_intance);
+ }
+
+ _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
+ ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->depth;
+ }
+
+ _FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) {
+ ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND_V(!atlas, Size2i());
+ return Size2(atlas->size, atlas->size);
+ }
+
+ void directional_shadow_atlas_set_size(int p_size);
+ int get_directional_light_shadow_size(RID p_light_intance);
+ void set_directional_shadow_count(int p_count);
+
+ _FORCE_INLINE_ RID directional_shadow_get_texture() {
+ return directional_shadow.depth;
+ }
+
+ _FORCE_INLINE_ Size2i directional_shadow_get_size() {
+ return Size2i(directional_shadow.size, directional_shadow.size);
+ }
+
+ /* SKY API */
+
+ RID sky_create();
+ 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);
+
+ 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();
+
+ void environment_set_background(RID p_env, RS::EnvironmentBG p_bg);
+ void environment_set_sky(RID p_env, RID p_sky);
+ void environment_set_sky_custom_fov(RID p_env, float p_scale);
+ void environment_set_sky_orientation(RID p_env, const Basis &p_orientation);
+ void environment_set_bg_color(RID p_env, const Color &p_color);
+ void environment_set_bg_energy(RID p_env, float p_energy);
+ void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
+ void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color());
+
+ RS::EnvironmentBG environment_get_background(RID p_env) const;
+ RID environment_get_sky(RID p_env) const;
+ float environment_get_sky_custom_fov(RID p_env) const;
+ Basis environment_get_sky_orientation(RID p_env) const;
+ Color environment_get_bg_color(RID p_env) const;
+ float environment_get_bg_energy(RID p_env) const;
+ int environment_get_canvas_max_layer(RID p_env) const;
+ Color environment_get_ambient_light_color(RID p_env) const;
+ RS::EnvironmentAmbientSource environment_get_ambient_light_ambient_source(RID p_env) const;
+ float environment_get_ambient_light_ambient_energy(RID p_env) const;
+ float environment_get_ambient_sky_contribution(RID p_env) const;
+ RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
+ Color environment_get_ao_color(RID p_env) const;
+
+ bool is_environment(RID p_env) const;
+
+ void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, 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 environment_glow_set_use_bicubic_upscale(bool p_enable);
+
+ void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
+
+ void 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);
+ void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, RS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
+ void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size);
+ bool environment_is_ssao_enabled(RID p_env) const;
+ float environment_get_ssao_ao_affect(RID p_env) const;
+ float environment_get_ssao_light_affect(RID p_env) const;
+ bool environment_is_ssr_enabled(RID p_env) const;
+
+ void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
+ RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const;
+
+ void 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);
+ void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {}
+
+ void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {}
+ void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {}
+ void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {}
+
+ virtual RID camera_effects_create();
+
+ 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);
+
+ virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount);
+ virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure);
+
+ RID light_instance_create(RID p_light);
+ void light_instance_set_transform(RID p_light_instance, const Transform &p_transform);
+ void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2());
+ void light_instance_mark_visible(RID p_light_instance);
+
+ _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->light;
+ }
+
+ _FORCE_INLINE_ Transform light_instance_get_base_transform(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->transform;
+ }
+
+ _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas) {
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ uint32_t key = shadow_atlas->shadow_owners[li->self];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2());
+
+ uint32_t atlas_size = shadow_atlas->size;
+ uint32_t quadrant_size = atlas_size >> 1;
+
+ uint32_t x = (quadrant & 1) * quadrant_size;
+ uint32_t y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ uint32_t width = shadow_size;
+ uint32_t height = shadow_size;
+
+ return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size));
+ }
+
+ _FORCE_INLINE_ CameraMatrix light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].camera;
+ }
+
+ _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
+
+#ifdef DEBUG_ENABLED
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
+#endif
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ ERR_FAIL_COND_V(!shadow_atlas, 0);
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
+#endif
+ uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+
+ uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+
+ return float(1.0) / shadow_size;
+ }
+
+ _FORCE_INLINE_ Transform
+ light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].transform;
+ }
+ _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].bias_scale;
+ }
+ _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].farplane;
+ }
+ _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].range_begin;
+ }
+
+ _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].uv_scale;
+ }
+
+ _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].atlas_rect;
+ }
+
+ _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].split;
+ }
+
+ _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].shadow_texel_size;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ li->last_pass = p_pass;
+ }
+
+ _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->last_pass;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_index(RID p_light_instance, uint32_t p_index) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ li->light_index = p_index;
+ }
+
+ _FORCE_INLINE_ uint32_t light_instance_get_index(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->light_index;
+ }
+
+ _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->light_type;
+ }
+
+ virtual RID reflection_atlas_create();
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count);
+ _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
+ ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->reflection;
+ }
+
+ virtual RID reflection_probe_instance_create(RID p_probe);
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform);
+ virtual void reflection_probe_release_atlas_index(RID p_instance);
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance);
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance);
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas);
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance);
+
+ uint32_t reflection_probe_instance_get_resolution(RID p_instance);
+ RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
+ RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
+
+ _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+
+ return rpi->probe;
+ }
+
+ _FORCE_INLINE_ void reflection_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!rpi);
+ rpi->render_index = p_render_index;
+ }
+
+ _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_index(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, 0);
+
+ return rpi->render_index;
+ }
+
+ _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!rpi);
+ rpi->last_pass = p_render_pass;
+ }
+
+ _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, 0);
+
+ return rpi->last_pass;
+ }
+
+ _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, Transform());
+
+ return rpi->transform;
+ }
+
+ _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
+ ERR_FAIL_COND_V(!rpi, -1);
+
+ return rpi->atlas_index;
+ }
+
+ virtual RID decal_instance_create(RID p_decal);
+ virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform);
+
+ _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ return decal->decal;
+ }
+
+ _FORCE_INLINE_ Transform decal_instance_get_transform(RID p_decal) const {
+ DecalInstance *decal = decal_instance_owner.getornull(p_decal);
+ return decal->transform;
+ }
+
+ 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, int p_dynamic_object_count, InstanceBase **p_dynamic_objects);
+
+ _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_ RID gi_probe_instance_get_aniso_texture(RID p_probe, int p_index) {
+ GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
+ return gi_probe->anisotropy[p_index];
+ }
+
+ _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;
+ }
+
+ _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;
+ }
+
+ const Vector<RID> &gi_probe_get_slots() const;
+ _FORCE_INLINE_ bool gi_probe_is_anisotropic() const {
+ return gi_probe_use_anisotropy;
+ }
+ GIProbeQuality gi_probe_get_quality() const;
+
+ 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);
+
+ RID render_buffers_get_ao_texture(RID p_render_buffers);
+ RID render_buffers_get_back_buffer_texture(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, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID *p_decal_cull_result, int p_decal_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+
+ void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
+
+ void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
+
+ virtual void set_scene_pass(uint64_t p_pass) {
+ scene_pass = p_pass;
+ }
+ _FORCE_INLINE_ uint64_t get_scene_pass() {
+ return scene_pass;
+ }
+
+ virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve);
+ virtual bool screen_space_roughness_limiter_is_active() const;
+ virtual float screen_space_roughness_limiter_get_curve() const;
+
+ virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality);
+ RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const;
+ virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale);
+
+ virtual void shadows_quality_set(RS::ShadowQuality p_quality);
+ virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality);
+ _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; }
+ _FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const { return directional_shadow_quality; }
+ _FORCE_INLINE_ float shadows_quality_radius_get() const { return shadows_quality_radius; }
+ _FORCE_INLINE_ float directional_shadow_quality_radius_get() const { return directional_shadow_quality_radius; }
+
+ _FORCE_INLINE_ float *directional_penumbra_shadow_kernel_get() { return directional_penumbra_shadow_kernel; }
+ _FORCE_INLINE_ float *directional_soft_shadow_kernel_get() { return directional_soft_shadow_kernel; }
+ _FORCE_INLINE_ float *penumbra_shadow_kernel_get() { return penumbra_shadow_kernel; }
+ _FORCE_INLINE_ float *soft_shadow_kernel_get() { return soft_shadow_kernel; }
+
+ _FORCE_INLINE_ int directional_penumbra_shadow_samples_get() const { return directional_penumbra_shadow_samples; }
+ _FORCE_INLINE_ int directional_soft_shadow_samples_get() const { return directional_soft_shadow_samples; }
+ _FORCE_INLINE_ int penumbra_shadow_samples_get() const { return penumbra_shadow_samples; }
+ _FORCE_INLINE_ int soft_shadow_samples_get() const { return soft_shadow_samples; }
+
+ int get_roughness_layers() const;
+ bool is_using_radiance_cubemap_array() const;
+
+ virtual bool free(RID p_rid);
+
+ virtual void update();
+
+ virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw);
+ _FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const {
+ return debug_draw;
+ }
+
+ virtual void set_time(double p_time, double p_step);
+
+ RasterizerSceneRD(RasterizerStorageRD *p_storage);
+ ~RasterizerSceneRD();
+};
+
+#endif // RASTERIZER_SCENE_RD_H
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
new file mode 100644
index 0000000000..148494692c
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -0,0 +1,5193 @@
+/*************************************************************************/
+/* rasterizer_storage_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "rasterizer_storage_rd.h"
+
+#include "core/engine.h"
+#include "core/project_settings.h"
+#include "servers/rendering/shader_language.h"
+
+Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
+
+ Ref<Image> image = p_image->duplicate();
+
+ switch (p_image->get_format()) {
+ case Image::FORMAT_L8: {
+ r_format.format = RD::DATA_FORMAT_R8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //luminance
+ case Image::FORMAT_LA8: {
+ r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_G;
+ } break; //luminance-alpha
+ case Image::FORMAT_R8: {
+ r_format.format = RD::DATA_FORMAT_R8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_RG8: {
+ r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_RGB8: {
+ //this format is not mandatory for specification, check if supported first
+ if (false && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT) && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_SRGB, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_R8G8B8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8_SRGB;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case Image::FORMAT_RGBA8: {
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_RGBA4444: {
+ r_format.format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B; //needs swizzle
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_RGB565: {
+ r_format.format = RD::DATA_FORMAT_B5G6R5_UNORM_PACK16;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_RF: {
+ r_format.format = RD::DATA_FORMAT_R32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //float
+ case Image::FORMAT_RGF: {
+ r_format.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_RGBF: {
+ //this format is not mandatory for specification, check if supported first
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ image->convert(Image::FORMAT_RGBAF);
+ }
+
+ r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_RGBAF: {
+ r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break;
+ case Image::FORMAT_RH: {
+ r_format.format = RD::DATA_FORMAT_R16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //half float
+ case Image::FORMAT_RGH: {
+ r_format.format = RD::DATA_FORMAT_R16G16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case Image::FORMAT_RGBH: {
+ //this format is not mandatory for specification, check if supported first
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_R16G16B16_SFLOAT;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ image->convert(Image::FORMAT_RGBAH);
+ }
+
+ r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_RGBAH: {
+ r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break;
+ case Image::FORMAT_RGBE9995: {
+ r_format.format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
+#ifndef _MSC_VER
+#warning TODO need to make a function in Image to swap bits for this
+#endif
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_IDENTITY;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_IDENTITY;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_IDENTITY;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_IDENTITY;
+ } break;
+ case Image::FORMAT_DXT1: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_BC1_RGB_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //s3tc bc1
+ case Image::FORMAT_DXT3: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC2_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC2_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_BC2_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; //bc2
+ case Image::FORMAT_DXT5: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC3_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break; //bc3
+ case Image::FORMAT_RGTC_R: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC4_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC4_UNORM_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8_UNORM;
+ image->decompress();
+ image->convert(Image::FORMAT_R8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case Image::FORMAT_RGTC_RG: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC5_UNORM_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
+ image->decompress();
+ image->convert(Image::FORMAT_RG8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case Image::FORMAT_BPTC_RGBA: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC7_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_BC7_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+
+ } break; //btpc bc7
+ case Image::FORMAT_BPTC_RGBF: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBAH);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //float bc6h
+ case Image::FORMAT_BPTC_RGBFU: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBAH);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //unsigned float bc6hu
+ case Image::FORMAT_PVRTC2: {
+ //this is not properly supported by MoltekVK it seems, so best to use ETC2
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
+ r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //pvrtc
+ case Image::FORMAT_PVRTC2A: {
+ //this is not properly supported by MoltekVK it seems, so best to use ETC2
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
+ r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_PVRTC4: {
+ //this is not properly supported by MoltekVK it seems, so best to use ETC2
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
+ r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_PVRTC4A: {
+ //this is not properly supported by MoltekVK it seems, so best to use ETC2
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
+ r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_ETC2_R11: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8_UNORM;
+ image->decompress();
+ image->convert(Image::FORMAT_R8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break; //etc2
+ case Image::FORMAT_ETC2_R11S: {
+
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8_SNORM;
+ image->decompress();
+ image->convert(Image::FORMAT_R8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break; //signed: {} break; NOT srgb.
+ case Image::FORMAT_ETC2_RG11: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
+ image->decompress();
+ image->convert(Image::FORMAT_RG8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_ETC2_RG11S: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8_SNORM;
+ image->decompress();
+ image->convert(Image::FORMAT_RG8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_ETC:
+ case Image::FORMAT_ETC2_RGB8: {
+ //ETC2 is backwards compatible with ETC1, and all modern platforms support it
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+
+ } break;
+ case Image::FORMAT_ETC2_RGBA8: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_ETC2_RGB8A1: {
+
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ } break;
+ case Image::FORMAT_ETC2_RA_AS_RG: {
+
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+ case Image::FORMAT_DXT5_RA_AS_RG: {
+ if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC3_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
+ r_format.format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
+ r_format.format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK;
+ } else {
+ //not supported, reconvert
+ r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ image->decompress();
+ image->convert(Image::FORMAT_RGBA8);
+ }
+ r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
+ r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
+ r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ } break;
+
+ default: {
+ }
+ }
+
+ return image;
+}
+
+RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_V(p_image.is_null(), RID());
+ ERR_FAIL_COND_V(p_image->empty(), RID());
+
+ TextureToRDFormat ret_format;
+ Ref<Image> image = _validate_texture_format(p_image, ret_format);
+
+ Texture texture;
+
+ texture.type = Texture::TYPE_2D;
+
+ texture.width = p_image->get_width();
+ texture.height = p_image->get_height();
+ texture.layers = 1;
+ texture.mipmaps = p_image->get_mipmap_count() + 1;
+ texture.depth = 1;
+ texture.format = p_image->get_format();
+ texture.validated_format = image->get_format();
+
+ texture.rd_type = RD::TEXTURE_TYPE_2D;
+ texture.rd_format = ret_format.format;
+ texture.rd_format_srgb = ret_format.format_srgb;
+
+ RD::TextureFormat rd_format;
+ RD::TextureView rd_view;
+ { //attempt register
+ rd_format.format = texture.rd_format;
+ rd_format.width = texture.width;
+ rd_format.height = texture.height;
+ rd_format.depth = 1;
+ rd_format.array_layers = 1;
+ rd_format.mipmaps = texture.mipmaps;
+ rd_format.type = texture.rd_type;
+ rd_format.samples = RD::TEXTURE_SAMPLES_1;
+ rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
+ rd_format.shareable_formats.push_back(texture.rd_format);
+ rd_format.shareable_formats.push_back(texture.rd_format_srgb);
+ }
+ }
+ {
+ rd_view.swizzle_r = ret_format.swizzle_r;
+ rd_view.swizzle_g = ret_format.swizzle_g;
+ rd_view.swizzle_b = ret_format.swizzle_b;
+ rd_view.swizzle_a = ret_format.swizzle_a;
+ }
+ Vector<uint8_t> data = image->get_data(); //use image data
+ 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());
+ 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());
+ }
+ }
+
+ //used for 2D, overridable
+ texture.width_2d = texture.width;
+ texture.height_2d = texture.height;
+ texture.is_render_target = false;
+ texture.rd_view = rd_view;
+ texture.is_proxy = false;
+
+ return texture_owner.make_rid(texture);
+}
+
+RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) {
+
+ return RID();
+}
+RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image>> &p_slices) {
+
+ return RID();
+}
+
+RID RasterizerStorageRD::texture_proxy_create(RID p_base) {
+ Texture *tex = texture_owner.getornull(p_base);
+ ERR_FAIL_COND_V(!tex, RID());
+ Texture proxy_tex = *tex;
+
+ proxy_tex.rd_view.format_override = tex->rd_format;
+ proxy_tex.rd_texture = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture);
+ if (proxy_tex.rd_texture_srgb.is_valid()) {
+ proxy_tex.rd_view.format_override = tex->rd_format_srgb;
+ proxy_tex.rd_texture_srgb = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture);
+ }
+ proxy_tex.proxy_to = p_base;
+ proxy_tex.is_render_target = false;
+ proxy_tex.is_proxy = true;
+ proxy_tex.proxies.clear();
+
+ RID rid = texture_owner.make_rid(proxy_tex);
+
+ tex->proxies.push_back(rid);
+
+ return rid;
+}
+
+void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) {
+
+ ERR_FAIL_COND(p_image.is_null() || p_image->empty());
+
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ ERR_FAIL_COND(tex->is_render_target);
+ ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height);
+ ERR_FAIL_COND(p_image->get_format() != tex->format);
+
+ if (tex->type == Texture::TYPE_LAYERED) {
+ ERR_FAIL_INDEX(p_layer, tex->layers);
+ }
+
+#ifdef TOOLS_ENABLED
+ tex->image_cache_2d.unref();
+#endif
+ TextureToRDFormat f;
+ Ref<Image> validated = _validate_texture_format(p_image, f);
+
+ RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data(), !p_immediate);
+}
+
+void RasterizerStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) {
+ _texture_2d_update(p_texture, p_image, p_layer, true);
+}
+void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
+ _texture_2d_update(p_texture, p_image, p_layer, false);
+}
+void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) {
+}
+
+void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) {
+
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ ERR_FAIL_COND(!tex->is_proxy);
+ Texture *proxy_to = texture_owner.getornull(p_proxy_to);
+ ERR_FAIL_COND(!proxy_to);
+ ERR_FAIL_COND(proxy_to->is_proxy);
+
+ if (tex->proxy_to.is_valid()) {
+ //unlink proxy
+ if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
+ RD::get_singleton()->free(tex->rd_texture);
+ tex->rd_texture = RID();
+ }
+ if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
+ RD::get_singleton()->free(tex->rd_texture_srgb);
+ tex->rd_texture_srgb = RID();
+ }
+ Texture *prev_tex = texture_owner.getornull(tex->proxy_to);
+ ERR_FAIL_COND(!prev_tex);
+ prev_tex->proxies.erase(p_texture);
+ }
+
+ *tex = *proxy_to;
+
+ tex->proxy_to = p_proxy_to;
+ tex->is_render_target = false;
+ tex->is_proxy = true;
+ tex->proxies.clear();
+ proxy_to->proxies.push_back(p_texture);
+
+ tex->rd_view.format_override = tex->rd_format;
+ tex->rd_texture = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture);
+ if (tex->rd_texture_srgb.is_valid()) {
+ tex->rd_view.format_override = tex->rd_format_srgb;
+ tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture);
+ }
+}
+
+//these two APIs can be used together or in combination with the others.
+RID RasterizerStorageRD::texture_2d_placeholder_create() {
+
+ //this could be better optimized to reuse an existing image , done this way
+ //for now to get it working
+ Ref<Image> image;
+ image.instance();
+ image->create(4, 4, false, Image::FORMAT_RGBA8);
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ image->set_pixel(i, j, Color(1, 0, 1, 1));
+ }
+ }
+
+ return texture_2d_create(image);
+}
+RID RasterizerStorageRD::texture_2d_layered_placeholder_create() {
+
+ return RID();
+}
+RID RasterizerStorageRD::texture_3d_placeholder_create() {
+
+ return RID();
+}
+
+Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const {
+
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND_V(!tex, Ref<Image>());
+
+#ifdef TOOLS_ENABLED
+ if (tex->image_cache_2d.is_valid()) {
+ return tex->image_cache_2d;
+ }
+#endif
+ Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
+ ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
+ Ref<Image> image;
+ image.instance();
+ image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
+ ERR_FAIL_COND_V(image->empty(), Ref<Image>());
+ if (tex->format != tex->validated_format) {
+ image->convert(tex->format);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ tex->image_cache_2d = image;
+ }
+#endif
+
+ return image;
+}
+Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const {
+
+ return Ref<Image>();
+}
+Ref<Image> RasterizerStorageRD::texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const {
+
+ return Ref<Image>();
+}
+
+void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
+
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy
+ Texture *by_tex = texture_owner.getornull(p_by_texture);
+ ERR_FAIL_COND(!by_tex);
+ ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy
+
+ if (tex == by_tex) {
+ return;
+ }
+
+ if (tex->rd_texture_srgb.is_valid()) {
+ RD::get_singleton()->free(tex->rd_texture_srgb);
+ }
+ RD::get_singleton()->free(tex->rd_texture);
+
+ Vector<RID> proxies_to_update = tex->proxies;
+ Vector<RID> proxies_to_redirect = by_tex->proxies;
+
+ *tex = *by_tex;
+
+ tex->proxies = proxies_to_update; //restore proxies, so they can be updated
+
+ for (int i = 0; i < proxies_to_update.size(); i++) {
+ texture_proxy_update(proxies_to_update[i], p_texture);
+ }
+ for (int i = 0; i < proxies_to_redirect.size(); i++) {
+ texture_proxy_update(proxies_to_redirect[i], p_texture);
+ }
+ //delete last, so proxies can be updated
+ texture_owner.free(p_by_texture);
+
+ if (decal_atlas.textures.has(p_texture)) {
+ //belongs to decal atlas..
+
+ decal_atlas.dirty = true; //mark it dirty since it was most likely modified
+ }
+}
+void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) {
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ ERR_FAIL_COND(tex->type != Texture::TYPE_2D);
+ tex->width_2d = p_width;
+ tex->height_2d = p_height;
+}
+
+void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) {
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ tex->path = p_path;
+}
+String RasterizerStorageRD::texture_get_path(RID p_texture) const {
+ return String();
+}
+
+void RasterizerStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ tex->detect_3d_callback_ud = p_userdata;
+ tex->detect_3d_callback = p_callback;
+}
+void RasterizerStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ tex->detect_normal_callback_ud = p_userdata;
+ tex->detect_normal_callback = p_callback;
+}
+void RasterizerStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {
+ Texture *tex = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!tex);
+ tex->detect_roughness_callback_ud = p_userdata;
+ tex->detect_roughness_callback = p_callback;
+}
+void RasterizerStorageRD::texture_debug_usage(List<RS::TextureInfo> *r_info) {
+}
+
+void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) {
+}
+void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
+}
+
+Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {
+ return texture_2d_get_size(p_proxy);
+}
+
+/* SHADER API */
+
+RID RasterizerStorageRD::shader_create() {
+
+ Shader shader;
+ shader.data = nullptr;
+ shader.type = SHADER_TYPE_MAX;
+
+ return shader_owner.make_rid(shader);
+}
+
+void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ shader->code = p_code;
+ String mode_string = ShaderLanguage::get_shader_type(p_code);
+
+ ShaderType new_type;
+ if (mode_string == "canvas_item")
+ new_type = SHADER_TYPE_2D;
+ else if (mode_string == "particles")
+ new_type = SHADER_TYPE_PARTICLES;
+ else if (mode_string == "spatial")
+ new_type = SHADER_TYPE_3D;
+ else if (mode_string == "sky")
+ new_type = SHADER_TYPE_SKY;
+ else
+ new_type = SHADER_TYPE_MAX;
+
+ if (new_type != shader->type) {
+ if (shader->data) {
+ memdelete(shader->data);
+ shader->data = nullptr;
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+
+ Material *material = E->get();
+ material->shader_type = new_type;
+ if (material->data) {
+ memdelete(material->data);
+ material->data = nullptr;
+ }
+ }
+
+ shader->type = new_type;
+
+ if (new_type < SHADER_TYPE_MAX && shader_data_request_func[new_type]) {
+ shader->data = shader_data_request_func[new_type]();
+ } else {
+ shader->type = SHADER_TYPE_MAX; //invalid
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+ Material *material = E->get();
+ if (shader->data) {
+ material->data = material_data_request_func[new_type](shader->data);
+ material->data->set_next_pass(material->next_pass);
+ material->data->set_render_priority(material->priority);
+ }
+ material->shader_type = new_type;
+ }
+ }
+
+ if (shader->data) {
+ shader->data->set_code(p_code);
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+ Material *material = E->get();
+ material->instance_dependency.instance_notify_changed(false, true);
+ _material_queue_update(material, true, true);
+ }
+}
+
+String RasterizerStorageRD::shader_get_code(RID p_shader) const {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND_V(!shader, String());
+ return shader->code;
+}
+void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+ if (shader->data) {
+ return shader->data->get_param_list(p_param_list);
+ }
+}
+
+void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {
+
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+
+ if (p_texture.is_valid() && texture_owner.owns(p_texture)) {
+ shader->default_texture_parameter[p_name] = p_texture;
+ } else {
+ shader->default_texture_parameter.erase(p_name);
+ }
+
+ for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
+ Material *material = E->get();
+ _material_queue_update(material, false, true);
+ }
+}
+
+RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND_V(!shader, RID());
+ if (shader->default_texture_parameter.has(p_name)) {
+ return shader->default_texture_parameter[p_name];
+ }
+
+ return RID();
+}
+Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const {
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND_V(!shader, Variant());
+ if (shader->data) {
+ return shader->data->get_default_parameter(p_param);
+ }
+ return Variant();
+}
+void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) {
+ ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
+ shader_data_request_func[p_shader_type] = p_function;
+}
+
+/* COMMON MATERIAL API */
+
+RID RasterizerStorageRD::material_create() {
+
+ Material material;
+ material.data = nullptr;
+ material.shader = nullptr;
+ material.shader_type = SHADER_TYPE_MAX;
+ material.update_next = nullptr;
+ material.update_requested = false;
+ 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;
+}
+
+void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
+ if (material->update_requested) {
+ return;
+ }
+
+ material->update_next = material_update_list;
+ material_update_list = material;
+ material->update_requested = true;
+ material->uniform_dirty = p_uniform;
+ material->texture_dirty = p_texture;
+}
+
+void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (material->data) {
+ memdelete(material->data);
+ material->data = nullptr;
+ }
+
+ if (material->shader) {
+ material->shader->owners.erase(material);
+ material->shader = nullptr;
+ material->shader_type = SHADER_TYPE_MAX;
+ }
+
+ if (p_shader.is_null()) {
+ material->instance_dependency.instance_notify_changed(false, true);
+ return;
+ }
+
+ Shader *shader = shader_owner.getornull(p_shader);
+ ERR_FAIL_COND(!shader);
+ material->shader = shader;
+ material->shader_type = shader->type;
+ shader->owners.insert(material);
+
+ if (shader->type == SHADER_TYPE_MAX) {
+ return;
+ }
+
+ ERR_FAIL_COND(shader->data == nullptr);
+
+ material->data = material_data_request_func[shader->type](shader->data);
+ material->data->set_next_pass(material->next_pass);
+ material->data->set_render_priority(material->priority);
+ //updating happens later
+ material->instance_dependency.instance_notify_changed(false, true);
+ _material_queue_update(material, true, true);
+}
+
+void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (p_value.get_type() == Variant::NIL) {
+ material->params.erase(p_param);
+ } else {
+ material->params[p_param] = p_value;
+ }
+
+ if (material->shader && material->shader->data) { //shader is valid
+ bool is_texture = material->shader->data->is_param_texture(p_param);
+ _material_queue_update(material, !is_texture, is_texture);
+ } else {
+ _material_queue_update(material, true, true);
+ }
+}
+
+Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND_V(!material, Variant());
+ if (material->params.has(p_param)) {
+ return material->params[p_param];
+ } else {
+ return Variant();
+ }
+}
+
+void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ if (material->next_pass == p_next_material) {
+ return;
+ }
+
+ material->next_pass = p_next_material;
+ if (material->data) {
+ material->data->set_next_pass(p_next_material);
+ }
+
+ material->instance_dependency.instance_notify_changed(false, true);
+}
+void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+ material->priority = priority;
+ if (material->data) {
+ material->data->set_render_priority(priority);
+ }
+}
+
+bool RasterizerStorageRD::material_is_animated(RID p_material) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND_V(!material, false);
+ if (material->shader && material->shader->data) {
+ if (material->shader->data->is_animated()) {
+ return true;
+ } else if (material->next_pass.is_valid()) {
+ return material_is_animated(material->next_pass);
+ }
+ }
+ return false; //by default nothing is animated
+}
+bool RasterizerStorageRD::material_casts_shadows(RID p_material) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND_V(!material, true);
+ if (material->shader && material->shader->data) {
+ if (material->shader->data->casts_shadows()) {
+ return true;
+ } else if (material->next_pass.is_valid()) {
+ return material_casts_shadows(material->next_pass);
+ }
+ }
+ return true; //by default everything casts shadows
+}
+
+void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+ p_instance->update_dependency(&material->instance_dependency);
+ if (material->next_pass.is_valid()) {
+ material_update_dependency(material->next_pass, p_instance);
+ }
+}
+
+void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) {
+ ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
+ material_data_request_func[p_shader_type] = p_function;
+}
+
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) {
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL: {
+
+ bool v = value;
+
+ uint32_t *gui = (uint32_t *)data;
+ *gui = v ? 1 : 0;
+ } break;
+ case ShaderLanguage::TYPE_BVEC2: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = v & 1 ? 1 : 0;
+ gui[1] = v & 2 ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC3: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC4: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ gui[3] = (v & 8) ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_INT: {
+
+ int v = value;
+ int32_t *gui = (int32_t *)data;
+ gui[0] = v;
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2: {
+
+ Vector<int> iv = value;
+ int s = iv.size();
+ int32_t *gui = (int32_t *)data;
+
+ const int *r = iv.ptr();
+
+ for (int i = 0; i < 2; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC3: {
+
+ Vector<int> iv = value;
+ int s = iv.size();
+ int32_t *gui = (int32_t *)data;
+
+ const int *r = iv.ptr();
+
+ for (int i = 0; i < 3; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_IVEC4: {
+
+ Vector<int> iv = value;
+ int s = iv.size();
+ int32_t *gui = (int32_t *)data;
+
+ const int *r = iv.ptr();
+
+ for (int i = 0; i < 4; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UINT: {
+
+ int v = value;
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = v;
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC2: {
+
+ Vector<int> iv = value;
+ int s = iv.size();
+ uint32_t *gui = (uint32_t *)data;
+
+ const int *r = iv.ptr();
+
+ for (int i = 0; i < 2; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC3: {
+ Vector<int> iv = value;
+ int s = iv.size();
+ uint32_t *gui = (uint32_t *)data;
+
+ const int *r = iv.ptr();
+
+ for (int i = 0; i < 3; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC4: {
+ Vector<int> iv = value;
+ int s = iv.size();
+ uint32_t *gui = (uint32_t *)data;
+
+ const int *r = iv.ptr();
+
+ for (int i = 0; i < 4; i++) {
+ if (i < s)
+ gui[i] = r[i];
+ else
+ gui[i] = 0;
+ }
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ float v = value;
+ float *gui = (float *)data;
+ gui[0] = v;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: {
+ Vector2 v = value;
+ float *gui = (float *)data;
+ gui[0] = v.x;
+ gui[1] = v.y;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC3: {
+ Vector3 v = value;
+ float *gui = (float *)data;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC4: {
+
+ float *gui = (float *)data;
+
+ if (value.get_type() == Variant::COLOR) {
+ Color v = value;
+
+ if (p_linear_color) {
+ v = v.to_linear();
+ }
+
+ gui[0] = v.r;
+ gui[1] = v.g;
+ gui[2] = v.b;
+ gui[3] = v.a;
+ } else if (value.get_type() == Variant::RECT2) {
+ Rect2 v = value;
+
+ gui[0] = v.position.x;
+ gui[1] = v.position.y;
+ gui[2] = v.size.x;
+ gui[3] = v.size.y;
+ } else if (value.get_type() == Variant::QUAT) {
+ Quat v = value;
+
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ } else {
+ Plane v = value;
+
+ gui[0] = v.normal.x;
+ gui[1] = v.normal.y;
+ gui[2] = v.normal.z;
+ gui[3] = v.d;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ Transform2D v = value;
+ float *gui = (float *)data;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[0][1];
+ gui[2] = 0;
+ gui[3] = 0;
+ gui[4] = v.elements[1][0];
+ gui[5] = v.elements[1][1];
+ gui[6] = 0;
+ gui[7] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+
+ Basis v = value;
+ float *gui = (float *)data;
+
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[1][0];
+ gui[2] = v.elements[2][0];
+ gui[3] = 0;
+ gui[4] = v.elements[0][1];
+ gui[5] = v.elements[1][1];
+ gui[6] = v.elements[2][1];
+ gui[7] = 0;
+ gui[8] = v.elements[0][2];
+ gui[9] = v.elements[1][2];
+ gui[10] = v.elements[2][2];
+ gui[11] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+
+ Transform v = value;
+ float *gui = (float *)data;
+
+ gui[0] = v.basis.elements[0][0];
+ gui[1] = v.basis.elements[1][0];
+ gui[2] = v.basis.elements[2][0];
+ gui[3] = 0;
+ gui[4] = v.basis.elements[0][1];
+ gui[5] = v.basis.elements[1][1];
+ gui[6] = v.basis.elements[2][1];
+ gui[7] = 0;
+ gui[8] = v.basis.elements[0][2];
+ gui[9] = v.basis.elements[1][2];
+ gui[10] = v.basis.elements[2][2];
+ gui[11] = 0;
+ gui[12] = v.origin.x;
+ gui[13] = v.origin.y;
+ gui[14] = v.origin.z;
+ gui[15] = 1;
+ } break;
+ default: {
+ }
+ }
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
+
+ switch (type) {
+ case ShaderLanguage::TYPE_BOOL: {
+
+ uint32_t *gui = (uint32_t *)data;
+ *gui = value[0].boolean ? 1 : 0;
+ } break;
+ case ShaderLanguage::TYPE_BVEC2: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC3: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+ gui[2] = value[2].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_BVEC4: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].boolean ? 1 : 0;
+ gui[1] = value[1].boolean ? 1 : 0;
+ gui[2] = value[2].boolean ? 1 : 0;
+ gui[3] = value[3].boolean ? 1 : 0;
+
+ } break;
+ case ShaderLanguage::TYPE_INT: {
+
+ int32_t *gui = (int32_t *)data;
+ gui[0] = value[0].sint;
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC3: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC4: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].sint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UINT: {
+
+ uint32_t *gui = (uint32_t *)data;
+ gui[0] = value[0].uint;
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC2: {
+
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].uint;
+ }
+ } break;
+ case ShaderLanguage::TYPE_UVEC3: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].uint;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_UVEC4: {
+ int32_t *gui = (int32_t *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].uint;
+ }
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+
+ float *gui = (float *)data;
+ gui[0] = value[0].real;
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 2; i++) {
+ gui[i] = value[i].real;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC3: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 3; i++) {
+ gui[i] = value[i].real;
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC4: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 4; i++) {
+ gui[i] = value[i].real;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+ float *gui = (float *)data;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = value[0].real;
+ gui[1] = value[1].real;
+ gui[2] = 0;
+ gui[3] = 0;
+ gui[4] = value[2].real;
+ gui[5] = value[3].real;
+ gui[6] = 0;
+ gui[7] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+
+ float *gui = (float *)data;
+
+ gui[0] = value[0].real;
+ gui[1] = value[1].real;
+ gui[2] = value[2].real;
+ gui[3] = 0;
+ gui[4] = value[3].real;
+ gui[5] = value[4].real;
+ gui[6] = value[5].real;
+ gui[7] = 0;
+ gui[8] = value[6].real;
+ gui[9] = value[7].real;
+ gui[10] = value[8].real;
+ gui[11] = 0;
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+
+ float *gui = (float *)data;
+
+ for (int i = 0; i < 16; i++) {
+ gui[i] = value[i].real;
+ }
+ } break;
+ default: {
+ }
+ }
+}
+
+_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
+
+ switch (type) {
+
+ case ShaderLanguage::TYPE_BOOL:
+ case ShaderLanguage::TYPE_INT:
+ case ShaderLanguage::TYPE_UINT:
+ case ShaderLanguage::TYPE_FLOAT: {
+ zeromem(data, 4);
+ } break;
+ case ShaderLanguage::TYPE_BVEC2:
+ case ShaderLanguage::TYPE_IVEC2:
+ case ShaderLanguage::TYPE_UVEC2:
+ case ShaderLanguage::TYPE_VEC2: {
+ zeromem(data, 8);
+ } break;
+ case ShaderLanguage::TYPE_BVEC3:
+ case ShaderLanguage::TYPE_IVEC3:
+ case ShaderLanguage::TYPE_UVEC3:
+ case ShaderLanguage::TYPE_VEC3:
+ case ShaderLanguage::TYPE_BVEC4:
+ case ShaderLanguage::TYPE_IVEC4:
+ case ShaderLanguage::TYPE_UVEC4:
+ case ShaderLanguage::TYPE_VEC4: {
+
+ zeromem(data, 16);
+ } break;
+ case ShaderLanguage::TYPE_MAT2: {
+
+ zeromem(data, 32);
+ } break;
+ case ShaderLanguage::TYPE_MAT3: {
+
+ zeromem(data, 48);
+ } break;
+ case ShaderLanguage::TYPE_MAT4: {
+ zeromem(data, 64);
+ } break;
+
+ default: {
+ }
+ }
+}
+
+void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) {
+
+ if (E->get().order < 0)
+ continue; // texture, does not go here
+
+ //regular uniform
+ uint32_t offset = p_uniform_offsets[E->get().order];
+#ifdef DEBUG_ENABLED
+ uint32_t size = ShaderLanguage::get_type_size(E->get().type);
+ ERR_CONTINUE(offset + size > p_buffer_size);
+#endif
+ uint8_t *data = &p_buffer[offset];
+ const Map<StringName, Variant>::Element *V = p_parameters.find(E->key());
+
+ if (V) {
+ //user provided
+ _fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color);
+
+ } else if (E->get().default_value.size()) {
+ //default value
+ _fill_std140_ubo_value(E->get().type, E->get().default_value, data);
+ //value=E->get().default_value;
+ } else {
+ //zero because it was not provided
+ if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ //colors must be set as black, with alpha as 1.0
+ _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color);
+ } else {
+ //else just zero it out
+ _fill_std140_ubo_empty(E->get().type, data);
+ }
+ }
+ }
+}
+
+void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
+
+ RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton;
+#ifdef TOOLS_ENABLED
+ Texture *roughness_detect_texture = nullptr;
+ RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGNHESS_R;
+ Texture *normal_detect_texture = nullptr;
+#endif
+
+ for (int i = 0; i < p_texture_uniforms.size(); i++) {
+
+ const StringName &uniform_name = p_texture_uniforms[i].name;
+
+ RID texture;
+
+ const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
+ if (V) {
+ texture = V->get();
+ }
+
+ if (!texture.is_valid()) {
+ const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
+ if (W) {
+
+ texture = W->get();
+ }
+ }
+
+ RID rd_texture;
+
+ if (texture.is_null()) {
+ //check default usage
+ switch (p_texture_uniforms[i].hint) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
+ } break;
+ default: {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ } break;
+ }
+ } else {
+ bool srgb = p_use_linear_color && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO);
+
+ Texture *tex = singleton->texture_owner.getornull(texture);
+
+ if (tex) {
+
+ rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
+#ifdef TOOLS_ENABLED
+ if (tex->detect_3d_callback && p_use_linear_color) {
+ tex->detect_3d_callback(tex->detect_3d_callback_ud);
+ }
+ if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
+ if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
+ normal_detect_texture = tex;
+ }
+ tex->detect_normal_callback(tex->detect_normal_callback_ud);
+ }
+ if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
+ //find the normal texture
+ roughness_detect_texture = tex;
+ roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
+ }
+
+#endif
+ }
+
+ if (rd_texture.is_null()) {
+ //wtf
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ }
+ }
+
+ p_textures[i] = rd_texture;
+ }
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
+ }
+#endif
+}
+
+void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) {
+ Material *material = material_owner.getornull(p_material);
+ if (material->shader_type != p_shader_type) {
+ return;
+ }
+ if (material->data) {
+ material->data->update_parameters(material->params, false, true);
+ }
+}
+
+void RasterizerStorageRD::_update_queued_materials() {
+ Material *material = material_update_list;
+ while (material) {
+ Material *next = material->update_next;
+
+ if (material->data) {
+ material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
+ }
+ material->update_requested = false;
+ material->texture_dirty = false;
+ material->uniform_dirty = false;
+ material->update_next = nullptr;
+ material = next;
+ }
+ material_update_list = nullptr;
+}
+/* MESH API */
+
+RID RasterizerStorageRD::mesh_create() {
+
+ return mesh_owner.make_rid(Mesh());
+}
+
+/// Returns stride
+void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ //ensure blend shape consistency
+ ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count);
+ ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size());
+
+#ifdef DEBUG_ENABLED
+ //do a validation, to catch errors first
+ {
+
+ uint32_t stride = 0;
+
+ for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
+
+ if ((p_surface.format & (1 << i))) {
+
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ stride += sizeof(float) * 2;
+ } else {
+ stride += sizeof(float) * 3;
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+
+ if (p_surface.format & RS::ARRAY_COMPRESS_NORMAL) {
+ stride += sizeof(int8_t) * 4;
+ } else {
+ stride += sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_TANGENT: {
+
+ if (p_surface.format & RS::ARRAY_COMPRESS_TANGENT) {
+ stride += sizeof(int8_t) * 4;
+ } else {
+ stride += sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ if (p_surface.format & RS::ARRAY_COMPRESS_COLOR) {
+ stride += sizeof(int8_t) * 4;
+ } else {
+ stride += sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_TEX_UV: {
+
+ if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV) {
+ stride += sizeof(int16_t) * 2;
+ } else {
+ stride += sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_TEX_UV2: {
+
+ if (p_surface.format & RS::ARRAY_COMPRESS_TEX_UV2) {
+ stride += sizeof(int16_t) * 2;
+ } else {
+ stride += sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_BONES: {
+ //assumed weights too
+
+ //unique format, internally 16 bits, exposed as single array for 32
+
+ stride += sizeof(int32_t) * 4;
+
+ } break;
+ }
+ }
+ }
+
+ int expected_size = stride * p_surface.vertex_count;
+ ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
+ }
+
+#endif
+
+ Mesh::Surface *s = memnew(Mesh::Surface);
+
+ s->format = p_surface.format;
+ s->primitive = p_surface.primitive;
+
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data);
+ s->vertex_count = p_surface.vertex_count;
+
+ if (p_surface.index_count) {
+ bool is_index_16 = p_surface.vertex_count <= 65536;
+
+ s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false);
+ s->index_count = p_surface.index_count;
+ s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count);
+ if (p_surface.lods.size()) {
+ s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
+ s->lod_count = p_surface.lods.size();
+
+ for (int i = 0; i < p_surface.lods.size(); i++) {
+
+ uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
+ s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data);
+ s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
+ s->lods[i].edge_length = p_surface.lods[i].edge_length;
+ }
+ }
+ }
+
+ s->aabb = p_surface.aabb;
+ s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
+
+ for (int i = 0; i < p_surface.blend_shapes.size(); i++) {
+
+ if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) {
+ memdelete(s);
+ ERR_FAIL_COND(p_surface.blend_shapes[i].size() != p_surface.vertex_data.size());
+ }
+ RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]);
+ s->blend_shapes.push_back(vertex_buffer);
+ }
+
+ mesh->blend_shape_count = p_surface.blend_shapes.size();
+
+ if (mesh->surface_count == 0) {
+ mesh->bone_aabbs = p_surface.bone_aabbs;
+ mesh->aabb = p_surface.aabb;
+ } else {
+ for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
+ mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]);
+ }
+ mesh->aabb.merge_with(p_surface.aabb);
+ }
+
+ s->material = p_surface.material;
+
+ mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
+ mesh->surfaces[mesh->surface_count] = s;
+ mesh->surface_count++;
+
+ mesh->instance_dependency.instance_notify_changed(true, true);
+
+ mesh->material_cache.clear();
+}
+
+int RasterizerStorageRD::mesh_get_blend_shape_count(RID p_mesh) const {
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, -1);
+ return mesh->blend_shape_count;
+}
+
+void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX((int)p_mode, 2);
+
+ mesh->blend_shape_mode = p_mode;
+}
+RS::BlendShapeMode RasterizerStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
+ return mesh->blend_shape_mode;
+}
+
+void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+ uint64_t data_size = p_data.size();
+ const uint8_t *r = p_data.ptr();
+
+ RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r);
+}
+
+void RasterizerStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ mesh->surfaces[p_surface]->material = p_material;
+
+ mesh->instance_dependency.instance_notify_changed(false, true);
+ mesh->material_cache.clear();
+}
+RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
+
+ return mesh->surfaces[p_surface]->material;
+}
+
+RS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const {
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
+ ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
+
+ Mesh::Surface &s = *mesh->surfaces[p_surface];
+
+ RS::SurfaceData sd;
+ sd.format = s.format;
+ sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+ sd.vertex_count = s.vertex_count;
+ sd.index_count = s.index_count;
+ sd.primitive = s.primitive;
+
+ if (sd.index_count) {
+ sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
+ }
+ sd.aabb = s.aabb;
+ for (uint32_t i = 0; i < s.lod_count; i++) {
+ RS::SurfaceData::LOD lod;
+ lod.edge_length = s.lods[i].edge_length;
+ lod.index_data = RD::get_singleton()->buffer_get_data(s.lods[i].index_buffer);
+ sd.lods.push_back(lod);
+ }
+
+ sd.bone_aabbs = s.bone_aabbs;
+
+ for (int i = 0; i < s.blend_shapes.size(); i++) {
+ Vector<uint8_t> bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]);
+ sd.blend_shapes.push_back(bs);
+ }
+
+ return sd;
+}
+
+int RasterizerStorageRD::mesh_get_surface_count(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, 0);
+ return mesh->surface_count;
+}
+
+void RasterizerStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ mesh->custom_aabb = p_aabb;
+}
+AABB RasterizerStorageRD::mesh_get_custom_aabb(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+ return mesh->custom_aabb;
+}
+
+AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+
+ if (mesh->custom_aabb != AABB()) {
+ return mesh->custom_aabb;
+ }
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+
+ if (!skeleton || skeleton->size == 0) {
+ return mesh->aabb;
+ }
+
+ AABB aabb;
+
+ for (uint32_t i = 0; i < mesh->surface_count; i++) {
+
+ AABB laabb;
+ if ((mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) {
+
+ int bs = mesh->surfaces[i]->bone_aabbs.size();
+ const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr();
+
+ int sbs = skeleton->size;
+ ERR_CONTINUE(bs > sbs);
+ const float *baseptr = skeleton->data.ptr();
+
+ bool first = true;
+
+ if (skeleton->use_2d) {
+ for (int j = 0; j < bs; j++) {
+
+ if (skbones[0].size == Vector3())
+ continue; //bone is unused
+
+ const float *dataptr = baseptr + j * 8;
+
+ Transform mtx;
+
+ mtx.basis.elements[0].x = dataptr[0];
+ mtx.basis.elements[1].x = dataptr[1];
+ mtx.origin.x = dataptr[3];
+
+ mtx.basis.elements[0].y = dataptr[4];
+ mtx.basis.elements[1].y = dataptr[5];
+ mtx.origin.y = dataptr[7];
+
+ AABB baabb = mtx.xform(skbones[j]);
+
+ if (first) {
+ laabb = baabb;
+ first = false;
+ } else {
+ laabb.merge_with(baabb);
+ }
+ }
+ } else {
+ for (int j = 0; j < bs; j++) {
+
+ if (skbones[0].size == Vector3())
+ continue; //bone is unused
+
+ const float *dataptr = baseptr + j * 12;
+
+ Transform mtx;
+
+ mtx.basis.elements[0][0] = dataptr[0];
+ mtx.basis.elements[0][1] = dataptr[1];
+ mtx.basis.elements[0][2] = dataptr[2];
+ mtx.origin.x = dataptr[3];
+ mtx.basis.elements[1][0] = dataptr[4];
+ mtx.basis.elements[1][1] = dataptr[5];
+ mtx.basis.elements[1][2] = dataptr[6];
+ mtx.origin.y = dataptr[7];
+ mtx.basis.elements[2][0] = dataptr[8];
+ mtx.basis.elements[2][1] = dataptr[9];
+ mtx.basis.elements[2][2] = dataptr[10];
+ mtx.origin.z = dataptr[11];
+
+ AABB baabb = mtx.xform(skbones[j]);
+ if (first) {
+ laabb = baabb;
+ first = false;
+ } else {
+ laabb.merge_with(baabb);
+ }
+ }
+ }
+
+ if (laabb.size == Vector3()) {
+ laabb = mesh->surfaces[i]->aabb;
+ }
+ } else {
+
+ laabb = mesh->surfaces[i]->aabb;
+ }
+
+ if (i == 0) {
+ aabb = laabb;
+ } else {
+ aabb.merge_with(laabb);
+ }
+ }
+
+ return aabb;
+}
+
+void RasterizerStorageRD::mesh_clear(RID p_mesh) {
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ for (uint32_t i = 0; i < mesh->surface_count; i++) {
+ Mesh::Surface &s = *mesh->surfaces[i];
+ RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
+ if (s.versions) {
+ memfree(s.versions); //reallocs, so free with memfree.
+ }
+
+ if (s.index_buffer.is_valid()) {
+ RD::get_singleton()->free(s.index_buffer);
+ }
+
+ if (s.lod_count) {
+ for (uint32_t j = 0; j < s.lod_count; j++) {
+ RD::get_singleton()->free(s.lods[j].index_buffer);
+ }
+ memdelete_arr(s.lods);
+ }
+
+ for (int32_t j = 0; j < s.blend_shapes.size(); j++) {
+ RD::get_singleton()->free(s.blend_shapes[j]);
+ }
+
+ if (s.blend_shape_base_buffer.is_valid()) {
+ RD::get_singleton()->free(s.blend_shape_base_buffer);
+ }
+
+ memdelete(mesh->surfaces[i]);
+ }
+ if (mesh->surfaces) {
+ memfree(mesh->surfaces);
+ }
+
+ mesh->surfaces = nullptr;
+ mesh->surface_count = 0;
+ mesh->material_cache.clear();
+ mesh->instance_dependency.instance_notify_changed(true, true);
+}
+
+void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask) {
+ uint32_t version = s->version_count;
+ s->version_count++;
+ s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
+
+ Mesh::Surface::Version &v = s->versions[version];
+
+ Vector<RD::VertexDescription> attributes;
+ Vector<RID> buffers;
+
+ uint32_t stride = 0;
+
+ for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
+
+ RD::VertexDescription vd;
+ RID buffer;
+ vd.location = i;
+
+ if (!(s->format & (1 << i))) {
+ // Not supplied by surface, use default value
+ buffer = mesh_default_rd_buffers[i];
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ } break;
+ case RS::ARRAY_TANGENT: {
+
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+
+ } break;
+ case RS::ARRAY_TEX_UV: {
+
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+
+ } break;
+ case RS::ARRAY_TEX_UV2: {
+
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ } break;
+ case RS::ARRAY_BONES: {
+
+ //assumed weights too
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ } break;
+ }
+ } else {
+ //Supplied, use it
+
+ vd.offset = stride;
+ vd.stride = 1; //mark that it needs a stride set
+ buffer = s->vertex_buffer;
+
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ stride += sizeof(float) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
+ stride += sizeof(float) * 3;
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+
+ if (s->format & RS::ARRAY_COMPRESS_NORMAL) {
+ vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
+ stride += sizeof(int8_t) * 4;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ stride += sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_TANGENT: {
+
+ if (s->format & RS::ARRAY_COMPRESS_TANGENT) {
+ vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
+ stride += sizeof(int8_t) * 4;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ stride += sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ if (s->format & RS::ARRAY_COMPRESS_COLOR) {
+ vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ stride += sizeof(int8_t) * 4;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
+ stride += sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_TEX_UV: {
+
+ if (s->format & RS::ARRAY_COMPRESS_TEX_UV) {
+ vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
+ stride += sizeof(int16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ stride += sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_TEX_UV2: {
+
+ if (s->format & RS::ARRAY_COMPRESS_TEX_UV2) {
+ vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
+ stride += sizeof(int16_t) * 2;
+ } else {
+ vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
+ stride += sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_BONES: {
+ //assumed weights too
+
+ //unique format, internally 16 bits, exposed as single array for 32
+
+ vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
+ stride += sizeof(int32_t) * 4;
+
+ } break;
+ }
+ }
+
+ if (!(p_input_mask & (1 << i))) {
+ continue; // Shader does not need this, skip it
+ }
+
+ attributes.push_back(vd);
+ buffers.push_back(buffer);
+ }
+
+ //update final stride
+ for (int i = 0; i < attributes.size(); i++) {
+ if (attributes[i].stride == 1) {
+ attributes.write[i].stride = stride;
+ }
+ }
+
+ v.input_mask = p_input_mask;
+ v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
+ v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers);
+}
+
+////////////////// MULTIMESH
+
+RID RasterizerStorageRD::multimesh_create() {
+
+ return multimesh_owner.make_rid(MultiMesh());
+}
+
+void RasterizerStorageRD::multimesh_allocate(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);
+
+ if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
+ return;
+ }
+
+ if (multimesh->buffer.is_valid()) {
+ RD::get_singleton()->free(multimesh->buffer);
+ multimesh->buffer = RID();
+ multimesh->uniform_set_3d = RID(); //cleared by dependency
+ }
+
+ if (multimesh->data_cache_dirty_regions) {
+ memdelete_arr(multimesh->data_cache_dirty_regions);
+ multimesh->data_cache_dirty_regions = nullptr;
+ multimesh->data_cache_used_dirty_regions = 0;
+ }
+
+ multimesh->instances = p_instances;
+ multimesh->xform_format = p_transform_format;
+ multimesh->uses_colors = p_use_colors;
+ multimesh->color_offset_cache = p_transform_format == RS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
+ multimesh->uses_custom_data = p_use_custom_data;
+ multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 4 : 0);
+ multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
+ multimesh->buffer_set = false;
+
+ //print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == RS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances));
+ multimesh->data_cache = Vector<float>();
+ multimesh->aabb = AABB();
+ multimesh->aabb_dirty = false;
+ multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
+
+ if (multimesh->instances) {
+
+ multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4);
+ }
+}
+
+int RasterizerStorageRD::multimesh_get_instance_count(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, 0);
+ return multimesh->instances;
+}
+
+void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ if (multimesh->mesh == p_mesh) {
+ return;
+ }
+ multimesh->mesh = p_mesh;
+
+ if (multimesh->instances == 0) {
+ return;
+ }
+
+ if (multimesh->data_cache.size()) {
+ //we have a data cache, just mark it dirt
+ _multimesh_mark_all_dirty(multimesh, false, true);
+ } else if (multimesh->instances) {
+ //need to re-create AABB unfortunately, calling this has a penalty
+ if (multimesh->buffer_set) {
+ Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ const uint8_t *r = buffer.ptr();
+ const float *data = (const float *)r;
+ _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
+ }
+ }
+
+ multimesh->instance_dependency.instance_notify_changed(true, true);
+}
+
+#define MULTIMESH_DIRTY_REGION_SIZE 512
+
+void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const {
+ if (multimesh->data_cache.size() > 0) {
+ return; //already local
+ }
+ ERR_FAIL_COND(multimesh->data_cache.size() > 0);
+ // this means that the user wants to load/save individual elements,
+ // for this, the data must reside on CPU, so just copy it there.
+ multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache);
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ if (multimesh->buffer_set) {
+ Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ {
+
+ const uint8_t *r = buffer.ptr();
+ copymem(w, r, buffer.size());
+ }
+ } else {
+ zeromem(w, multimesh->instances * multimesh->stride_cache * sizeof(float));
+ }
+ }
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ multimesh->data_cache_dirty_regions[i] = 0;
+ }
+ multimesh->data_cache_used_dirty_regions = 0;
+}
+
+void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
+
+ uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE;
+#ifdef DEBUG_ENABLED
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ ERR_FAIL_UNSIGNED_INDEX(region_index, data_cache_dirty_region_count); //bug
+#endif
+ if (!multimesh->data_cache_dirty_regions[region_index]) {
+ multimesh->data_cache_dirty_regions[region_index] = true;
+ multimesh->data_cache_used_dirty_regions++;
+ }
+
+ if (p_aabb) {
+ multimesh->aabb_dirty = true;
+ }
+
+ if (!multimesh->dirty) {
+ multimesh->dirty_list = multimesh_dirty_list;
+ multimesh_dirty_list = multimesh;
+ multimesh->dirty = true;
+ }
+}
+
+void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) {
+ if (p_data) {
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ if (!multimesh->data_cache_dirty_regions[i]) {
+ multimesh->data_cache_dirty_regions[i] = true;
+ multimesh->data_cache_used_dirty_regions++;
+ }
+ }
+ }
+
+ if (p_aabb) {
+ multimesh->aabb_dirty = true;
+ }
+
+ if (!multimesh->dirty) {
+ multimesh->dirty_list = multimesh_dirty_list;
+ multimesh_dirty_list = multimesh;
+ multimesh->dirty = true;
+ }
+}
+
+void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) {
+
+ ERR_FAIL_COND(multimesh->mesh.is_null());
+ AABB aabb;
+ AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
+ for (int i = 0; i < p_instances; i++) {
+ const float *data = p_data + multimesh->stride_cache * i;
+ Transform t;
+
+ if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) {
+
+ t.basis.elements[0][0] = data[0];
+ t.basis.elements[0][1] = data[1];
+ t.basis.elements[0][2] = data[2];
+ t.origin.x = data[3];
+ t.basis.elements[1][0] = data[4];
+ t.basis.elements[1][1] = data[5];
+ t.basis.elements[1][2] = data[6];
+ t.origin.y = data[7];
+ t.basis.elements[2][0] = data[8];
+ t.basis.elements[2][1] = data[9];
+ t.basis.elements[2][2] = data[10];
+ t.origin.z = data[11];
+
+ } else {
+
+ t.basis.elements[0].x = data[0];
+ t.basis.elements[1].x = data[1];
+ t.origin.x = data[3];
+
+ t.basis.elements[0].y = data[4];
+ t.basis.elements[1].y = data[5];
+ t.origin.y = data[7];
+ }
+
+ if (i == 0) {
+ aabb = t.xform(mesh_aabb);
+ } else {
+ aabb.merge_with(t.xform(mesh_aabb));
+ }
+ }
+
+ multimesh->aabb = aabb;
+}
+
+void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache;
+
+ dataptr[0] = p_transform.basis.elements[0][0];
+ dataptr[1] = p_transform.basis.elements[0][1];
+ dataptr[2] = p_transform.basis.elements[0][2];
+ dataptr[3] = p_transform.origin.x;
+ dataptr[4] = p_transform.basis.elements[1][0];
+ dataptr[5] = p_transform.basis.elements[1][1];
+ dataptr[6] = p_transform.basis.elements[1][2];
+ dataptr[7] = p_transform.origin.y;
+ dataptr[8] = p_transform.basis.elements[2][0];
+ dataptr[9] = p_transform.basis.elements[2][1];
+ dataptr[10] = p_transform.basis.elements[2][2];
+ dataptr[11] = p_transform.origin.z;
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, true);
+}
+
+void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache;
+
+ dataptr[0] = p_transform.elements[0][0];
+ dataptr[1] = p_transform.elements[1][0];
+ dataptr[2] = 0;
+ dataptr[3] = p_transform.elements[2][0];
+ dataptr[4] = p_transform.elements[0][1];
+ dataptr[5] = p_transform.elements[1][1];
+ dataptr[6] = 0;
+ dataptr[7] = p_transform.elements[2][1];
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, true);
+}
+void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(!multimesh->uses_colors);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+
+ dataptr[0] = p_color.r;
+ dataptr[1] = p_color.g;
+ dataptr[2] = p_color.b;
+ dataptr[3] = p_color.a;
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, false);
+}
+void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->instances);
+ ERR_FAIL_COND(!multimesh->uses_custom_data);
+
+ _multimesh_make_local(multimesh);
+
+ {
+ float *w = multimesh->data_cache.ptrw();
+
+ float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+
+ dataptr[0] = p_color.r;
+ dataptr[1] = p_color.g;
+ dataptr[2] = p_color.b;
+ dataptr[3] = p_color.a;
+ }
+
+ _multimesh_mark_dirty(multimesh, p_index, false);
+}
+
+RID RasterizerStorageRD::multimesh_get_mesh(RID p_multimesh) const {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, RID());
+
+ return multimesh->mesh;
+}
+
+Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform());
+ ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform());
+
+ _multimesh_make_local(multimesh);
+
+ Transform t;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache;
+
+ t.basis.elements[0][0] = dataptr[0];
+ t.basis.elements[0][1] = dataptr[1];
+ t.basis.elements[0][2] = dataptr[2];
+ t.origin.x = dataptr[3];
+ t.basis.elements[1][0] = dataptr[4];
+ t.basis.elements[1][1] = dataptr[5];
+ t.basis.elements[1][2] = dataptr[6];
+ t.origin.y = dataptr[7];
+ t.basis.elements[2][0] = dataptr[8];
+ t.basis.elements[2][1] = dataptr[9];
+ t.basis.elements[2][2] = dataptr[10];
+ t.origin.z = dataptr[11];
+ }
+
+ return t;
+}
+Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform2D());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
+ ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D());
+
+ _multimesh_make_local(multimesh);
+
+ Transform2D t;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache;
+
+ t.elements[0][0] = dataptr[0];
+ t.elements[1][0] = dataptr[1];
+ t.elements[2][0] = dataptr[3];
+ t.elements[0][1] = dataptr[4];
+ t.elements[1][1] = dataptr[5];
+ t.elements[2][1] = dataptr[7];
+ }
+
+ return t;
+}
+Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
+ ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
+
+ _multimesh_make_local(multimesh);
+
+ Color c;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+
+ c.r = dataptr[0];
+ c.g = dataptr[1];
+ c.b = dataptr[2];
+ c.a = dataptr[3];
+ }
+
+ return c;
+}
+Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
+ ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
+
+ _multimesh_make_local(multimesh);
+
+ Color c;
+ {
+ const float *r = multimesh->data_cache.ptr();
+
+ const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+
+ c.r = dataptr[0];
+ c.g = dataptr[1];
+ c.b = dataptr[2];
+ c.a = dataptr[3];
+ }
+
+ return c;
+}
+
+void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+
+ {
+ const float *r = p_buffer.ptr();
+ RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r, false);
+ multimesh->buffer_set = true;
+ }
+
+ if (multimesh->data_cache.size()) {
+ //if we have a data cache, just update it
+ multimesh->data_cache = p_buffer;
+ {
+ //clear dirty since nothing will be dirty anymore
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ multimesh->data_cache_dirty_regions[i] = false;
+ }
+ multimesh->data_cache_used_dirty_regions = 0;
+ }
+
+ _multimesh_mark_all_dirty(multimesh, false, true); //update AABB
+ } else if (multimesh->mesh.is_valid()) {
+ //if we have a mesh set, we need to re-generate the AABB from the new data
+ const float *data = p_buffer.ptr();
+
+ _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
+ multimesh->instance_dependency.instance_notify_changed(true, false);
+ }
+}
+
+Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Vector<float>());
+ if (multimesh->buffer.is_null()) {
+ return Vector<float>();
+ } else if (multimesh->data_cache.size()) {
+ return multimesh->data_cache;
+ } else {
+ //get from memory
+
+ Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ Vector<float> ret;
+ ret.resize(multimesh->instances);
+ {
+ float *w = multimesh->data_cache.ptrw();
+ const uint8_t *r = buffer.ptr();
+ copymem(w, r, buffer.size());
+ }
+
+ return ret;
+ }
+}
+
+void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
+ if (multimesh->visible_instances == p_visible) {
+ return;
+ }
+
+ if (multimesh->data_cache.size()) {
+ //there is a data cache..
+ _multimesh_mark_all_dirty(multimesh, false, true);
+ }
+
+ multimesh->visible_instances = p_visible;
+}
+int RasterizerStorageRD::multimesh_get_visible_instances(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, 0);
+ return multimesh->visible_instances;
+}
+
+AABB RasterizerStorageRD::multimesh_get_aabb(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, AABB());
+ if (multimesh->aabb_dirty) {
+ const_cast<RasterizerStorageRD *>(this)->_update_dirty_multimeshes();
+ }
+ return multimesh->aabb;
+}
+
+void RasterizerStorageRD::_update_dirty_multimeshes() {
+
+ while (multimesh_dirty_list) {
+
+ MultiMesh *multimesh = multimesh_dirty_list;
+
+ if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
+ const float *data = multimesh->data_cache.ptr();
+
+ uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+
+ if (multimesh->data_cache_used_dirty_regions) {
+
+ uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ uint32_t visible_region_count = (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+
+ uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
+
+ if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
+ //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
+ RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data, false);
+ } else {
+ //not that many regions? update them all
+ for (uint32_t i = 0; i < visible_region_count; i++) {
+ if (multimesh->data_cache_dirty_regions[i]) {
+ uint64_t offset = i * region_size;
+ uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float);
+ RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size], false);
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
+ multimesh->data_cache_dirty_regions[i] = false;
+ }
+
+ multimesh->data_cache_used_dirty_regions = 0;
+ }
+
+ if (multimesh->aabb_dirty) {
+ //aabb is dirty..
+ _multimesh_re_create_aabb(multimesh, data, visible_instances);
+ multimesh->aabb_dirty = false;
+ multimesh->instance_dependency.instance_notify_changed(true, false);
+ }
+ }
+
+ multimesh_dirty_list = multimesh->dirty_list;
+
+ multimesh->dirty_list = nullptr;
+ multimesh->dirty = false;
+ }
+
+ multimesh_dirty_list = nullptr;
+}
+
+/* SKELETON */
+
+/* SKELETON API */
+
+RID RasterizerStorageRD::skeleton_create() {
+
+ return skeleton_owner.make_rid(Skeleton());
+}
+
+void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) {
+
+ if (!skeleton->dirty) {
+ skeleton->dirty = true;
+ skeleton->dirty_list = skeleton_dirty_list;
+ skeleton_dirty_list = skeleton;
+ }
+}
+
+void RasterizerStorageRD::skeleton_allocate(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);
+
+ if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton)
+ return;
+
+ skeleton->size = p_bones;
+ skeleton->use_2d = p_2d_skeleton;
+ skeleton->uniform_set_3d = RID();
+
+ if (skeleton->buffer.is_valid()) {
+ RD::get_singleton()->free(skeleton->buffer);
+ skeleton->buffer = RID();
+ skeleton->data.resize(0);
+ }
+
+ 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));
+
+ _skeleton_make_dirty(skeleton);
+ }
+}
+int RasterizerStorageRD::skeleton_get_bone_count(RID p_skeleton) const {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, 0);
+
+ return skeleton->size;
+}
+
+void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_INDEX(p_bone, skeleton->size);
+ ERR_FAIL_COND(skeleton->use_2d);
+
+ float *dataptr = skeleton->data.ptrw() + p_bone * 12;
+
+ dataptr[0] = p_transform.basis.elements[0][0];
+ dataptr[1] = p_transform.basis.elements[0][1];
+ dataptr[2] = p_transform.basis.elements[0][2];
+ dataptr[3] = p_transform.origin.x;
+ dataptr[4] = p_transform.basis.elements[1][0];
+ dataptr[5] = p_transform.basis.elements[1][1];
+ dataptr[6] = p_transform.basis.elements[1][2];
+ dataptr[7] = p_transform.origin.y;
+ dataptr[8] = p_transform.basis.elements[2][0];
+ dataptr[9] = p_transform.basis.elements[2][1];
+ dataptr[10] = p_transform.basis.elements[2][2];
+ dataptr[11] = p_transform.origin.z;
+
+ _skeleton_make_dirty(skeleton);
+}
+
+Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+
+ ERR_FAIL_COND_V(!skeleton, Transform());
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform());
+ ERR_FAIL_COND_V(skeleton->use_2d, Transform());
+
+ const float *dataptr = skeleton->data.ptr() + p_bone * 12;
+
+ Transform t;
+
+ t.basis.elements[0][0] = dataptr[0];
+ t.basis.elements[0][1] = dataptr[1];
+ t.basis.elements[0][2] = dataptr[2];
+ t.origin.x = dataptr[3];
+ t.basis.elements[1][0] = dataptr[4];
+ t.basis.elements[1][1] = dataptr[5];
+ t.basis.elements[1][2] = dataptr[6];
+ t.origin.y = dataptr[7];
+ t.basis.elements[2][0] = dataptr[8];
+ t.basis.elements[2][1] = dataptr[9];
+ t.basis.elements[2][2] = dataptr[10];
+ t.origin.z = dataptr[11];
+
+ return t;
+}
+void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_INDEX(p_bone, skeleton->size);
+ ERR_FAIL_COND(!skeleton->use_2d);
+
+ float *dataptr = skeleton->data.ptrw() + p_bone * 8;
+
+ dataptr[0] = p_transform.elements[0][0];
+ dataptr[1] = p_transform.elements[1][0];
+ dataptr[2] = 0;
+ dataptr[3] = p_transform.elements[2][0];
+ dataptr[4] = p_transform.elements[0][1];
+ dataptr[5] = p_transform.elements[1][1];
+ dataptr[6] = 0;
+ dataptr[7] = p_transform.elements[2][1];
+
+ _skeleton_make_dirty(skeleton);
+}
+Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+
+ ERR_FAIL_COND_V(!skeleton, Transform2D());
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
+ ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
+
+ const float *dataptr = skeleton->data.ptr() + p_bone * 8;
+
+ Transform2D t;
+ t.elements[0][0] = dataptr[0];
+ t.elements[1][0] = dataptr[1];
+ t.elements[2][0] = dataptr[3];
+ t.elements[0][1] = dataptr[4];
+ t.elements[1][1] = dataptr[5];
+ t.elements[2][1] = dataptr[7];
+
+ return t;
+}
+
+void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+
+ ERR_FAIL_COND(!skeleton->use_2d);
+
+ skeleton->base_transform_2d = p_base_transform;
+}
+
+void RasterizerStorageRD::_update_dirty_skeletons() {
+
+ while (skeleton_dirty_list) {
+
+ Skeleton *skeleton = skeleton_dirty_list;
+
+ if (skeleton->size) {
+
+ RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr(), false);
+ }
+
+ skeleton_dirty_list = skeleton->dirty_list;
+
+ skeleton->instance_dependency.instance_notify_changed(true, false);
+
+ skeleton->dirty = false;
+ skeleton->dirty_list = nullptr;
+ }
+
+ skeleton_dirty_list = nullptr;
+}
+
+/* LIGHT */
+
+RID RasterizerStorageRD::light_create(RS::LightType p_type) {
+
+ Light light;
+ light.type = p_type;
+
+ light.param[RS::LIGHT_PARAM_ENERGY] = 1.0;
+ light.param[RS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+ light.param[RS::LIGHT_PARAM_SPECULAR] = 0.5;
+ light.param[RS::LIGHT_PARAM_RANGE] = 1.0;
+ light.param[RS::LIGHT_PARAM_SIZE] = 0.0;
+ light.param[RS::LIGHT_PARAM_SPOT_ANGLE] = 45;
+ light.param[RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
+ light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
+ light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
+ light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
+ light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;
+ light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02;
+ light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;
+ light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
+ light.param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] = 0.05;
+
+ return light_owner.make_rid(light);
+}
+
+void RasterizerStorageRD::light_set_color(RID p_light, const Color &p_color) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->color = p_color;
+}
+void RasterizerStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+ ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
+
+ switch (p_param) {
+ case RS::LIGHT_PARAM_RANGE:
+ case RS::LIGHT_PARAM_SPOT_ANGLE:
+ case RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
+ case RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
+ case RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
+ case RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
+ case RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
+ case RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE:
+ case RS::LIGHT_PARAM_SHADOW_BIAS: {
+
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+ } break;
+ default: {
+ }
+ }
+
+ light->param[p_param] = p_value;
+}
+void RasterizerStorageRD::light_set_shadow(RID p_light, bool p_enabled) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+ light->shadow = p_enabled;
+
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+ light->shadow_color = p_color;
+}
+
+void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ if (light->projector == p_texture) {
+ return;
+ }
+
+ if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
+ texture_remove_from_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+
+ light->projector = p_texture;
+
+ if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
+ texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
+ }
+}
+
+void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->negative = p_enable;
+}
+void RasterizerStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->cull_mask = p_mask;
+
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->reverse_cull = p_enabled;
+
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::light_set_use_gi(RID p_light, bool p_enabled) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->use_gi = p_enabled;
+
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->omni_shadow_mode = p_mode;
+
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+
+RS::LightOmniShadowMode RasterizerStorageRD::light_omni_get_shadow_mode(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE);
+
+ return light->omni_shadow_mode;
+}
+
+void RasterizerStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_shadow_mode = p_mode;
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_blend_splits = p_enable;
+ light->version++;
+ light->instance_dependency.instance_notify_changed(true, false);
+}
+
+bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, false);
+
+ return light->directional_blend_splits;
+}
+
+RS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+
+ return light->directional_shadow_mode;
+}
+
+void RasterizerStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) {
+
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_range_mode = p_range_mode;
+}
+
+RS::LightDirectionalShadowDepthRangeMode RasterizerStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
+
+ return light->directional_range_mode;
+}
+
+bool RasterizerStorageRD::light_get_use_gi(RID p_light) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, false);
+
+ return light->use_gi;
+}
+
+uint64_t RasterizerStorageRD::light_get_version(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->version;
+}
+
+AABB RasterizerStorageRD::light_get_aabb(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, AABB());
+
+ switch (light->type) {
+
+ case RS::LIGHT_SPOT: {
+
+ float len = light->param[RS::LIGHT_PARAM_RANGE];
+ float size = Math::tan(Math::deg2rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len;
+ return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
+ };
+ case RS::LIGHT_OMNI: {
+
+ float r = light->param[RS::LIGHT_PARAM_RANGE];
+ return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2);
+ };
+ case RS::LIGHT_DIRECTIONAL: {
+
+ return AABB();
+ };
+ }
+
+ ERR_FAIL_V(AABB());
+}
+
+/* REFLECTION PROBE */
+
+RID RasterizerStorageRD::reflection_probe_create() {
+
+ return reflection_probe_owner.make_rid(ReflectionProbe());
+}
+
+void RasterizerStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->update_mode = p_mode;
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->intensity = p_intensity;
+}
+
+void RasterizerStorageRD::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->interior_ambient = p_ambient;
+}
+
+void RasterizerStorageRD::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->interior_ambient_energy = p_energy;
+}
+
+void RasterizerStorageRD::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->interior_ambient_probe_contrib = p_contrib;
+}
+
+void RasterizerStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->max_distance = p_distance;
+
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->extents = p_extents;
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->origin_offset = p_offset;
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->interior = p_enable;
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->box_projection = p_enable;
+}
+
+void RasterizerStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->enable_shadows = p_enable;
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+
+ reflection_probe->cull_mask = p_layers;
+ reflection_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
+
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!reflection_probe);
+ ERR_FAIL_COND(p_resolution < 32);
+
+ reflection_probe->resolution = p_resolution;
+}
+
+AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const {
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, AABB());
+
+ AABB aabb;
+ aabb.position = -reflection_probe->extents;
+ aabb.size = reflection_probe->extents * 2.0;
+
+ return aabb;
+}
+RS::ReflectionProbeUpdateMode RasterizerStorageRD::reflection_probe_get_update_mode(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS);
+
+ return reflection_probe->update_mode;
+}
+
+uint32_t RasterizerStorageRD::reflection_probe_get_cull_mask(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->cull_mask;
+}
+
+Vector3 RasterizerStorageRD::reflection_probe_get_extents(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, Vector3());
+
+ return reflection_probe->extents;
+}
+Vector3 RasterizerStorageRD::reflection_probe_get_origin_offset(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, Vector3());
+
+ return reflection_probe->origin_offset;
+}
+
+bool RasterizerStorageRD::reflection_probe_renders_shadows(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, false);
+
+ return reflection_probe->enable_shadows;
+}
+
+float RasterizerStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->max_distance;
+}
+
+int RasterizerStorageRD::reflection_probe_get_resolution(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->resolution;
+}
+
+float RasterizerStorageRD::reflection_probe_get_intensity(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->intensity;
+}
+bool RasterizerStorageRD::reflection_probe_is_interior(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, false);
+
+ return reflection_probe->interior;
+}
+bool RasterizerStorageRD::reflection_probe_is_box_projection(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, false);
+
+ return reflection_probe->box_projection;
+}
+
+Color RasterizerStorageRD::reflection_probe_get_interior_ambient(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, Color());
+
+ return reflection_probe->interior_ambient;
+}
+float RasterizerStorageRD::reflection_probe_get_interior_ambient_energy(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->interior_ambient_energy;
+}
+float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const {
+
+ const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!reflection_probe, 0);
+
+ return reflection_probe->interior_ambient_probe_contrib;
+}
+
+RID RasterizerStorageRD::decal_create() {
+ return decal_owner.make_rid(Decal());
+}
+
+void RasterizerStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->extents = p_extents;
+ decal->instance_dependency.instance_notify_changed(true, false);
+}
+void RasterizerStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX);
+
+ if (decal->textures[p_type] == p_texture) {
+ return;
+ }
+
+ ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture));
+
+ if (decal->textures[p_type].is_valid() && texture_owner.owns(decal->textures[p_type])) {
+ texture_remove_from_decal_atlas(decal->textures[p_type]);
+ }
+
+ decal->textures[p_type] = p_texture;
+
+ if (decal->textures[p_type].is_valid()) {
+ texture_add_to_decal_atlas(decal->textures[p_type]);
+ }
+
+ decal->instance_dependency.instance_notify_changed(false, true);
+}
+void RasterizerStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->emission_energy = p_energy;
+}
+
+void RasterizerStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->albedo_mix = p_mix;
+}
+
+void RasterizerStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->modulate = p_modulate;
+}
+void RasterizerStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->cull_mask = p_layers;
+ decal->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) {
+
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->distance_fade = p_enabled;
+ decal->distance_fade_begin = p_begin;
+ decal->distance_fade_length = p_length;
+}
+
+void RasterizerStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) {
+
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->upper_fade = p_above;
+ decal->lower_fade = p_below;
+}
+
+void RasterizerStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) {
+
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND(!decal);
+ decal->normal_fade = p_fade;
+}
+
+AABB RasterizerStorageRD::decal_get_aabb(RID p_decal) const {
+ Decal *decal = decal_owner.getornull(p_decal);
+ ERR_FAIL_COND_V(!decal, AABB());
+
+ return AABB(-decal->extents, decal->extents * 2.0);
+}
+
+RID RasterizerStorageRD::gi_probe_create() {
+
+ return gi_probe_owner.make_rid(GIProbe());
+}
+
+void RasterizerStorageRD::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) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ if (gi_probe->octree_buffer.is_valid()) {
+ RD::get_singleton()->free(gi_probe->octree_buffer);
+ RD::get_singleton()->free(gi_probe->data_buffer);
+ if (gi_probe->sdf_texture.is_valid()) {
+ RD::get_singleton()->free(gi_probe->sdf_texture);
+ }
+
+ gi_probe->sdf_texture = RID();
+ gi_probe->octree_buffer = RID();
+ gi_probe->data_buffer = RID();
+ gi_probe->octree_buffer_size = 0;
+ gi_probe->data_buffer_size = 0;
+ gi_probe->cell_count = 0;
+ }
+
+ gi_probe->to_cell_xform = p_to_cell_xform;
+ gi_probe->bounds = p_aabb;
+ gi_probe->octree_size = p_octree_size;
+ gi_probe->level_counts = p_level_counts;
+
+ if (p_octree_cells.size()) {
+ ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32
+
+ uint32_t cell_count = p_octree_cells.size() / 32;
+
+ ERR_FAIL_COND(p_data_cells.size() != (int)cell_count * 16); //see that data size matches
+
+ gi_probe->cell_count = cell_count;
+ gi_probe->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
+ gi_probe->octree_buffer_size = p_octree_cells.size();
+ gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
+ gi_probe->data_buffer_size = p_data_cells.size();
+
+ if (p_distance_field.size()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = gi_probe->octree_size.x;
+ tf.height = gi_probe->octree_size.y;
+ tf.depth = gi_probe->octree_size.z;
+ tf.type = RD::TEXTURE_TYPE_3D;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ Vector<Vector<uint8_t>> s;
+ s.push_back(p_distance_field);
+ gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s);
+ }
+#if 0
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R8_UNORM;
+ tf.width = gi_probe->octree_size.x;
+ tf.height = gi_probe->octree_size.y;
+ tf.depth = gi_probe->octree_size.z;
+ tf.type = RD::TEXTURE_TYPE_3D;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
+ tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
+ gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+ RID shared_tex;
+ {
+
+ RD::TextureView tv;
+ tv.format_override = RD::DATA_FORMAT_R8_UINT;
+ shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture);
+ }
+ //update SDF texture
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(gi_probe->octree_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(gi_probe->data_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 3;
+ u.ids.push_back(shared_tex);
+ uniforms.push_back(u);
+ }
+
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
+
+ {
+ uint32_t push_constant[4] = { 0, 0, 0, 0 };
+
+ for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) {
+ push_constant[0] += gi_probe->level_counts[i];
+ }
+ push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
+
+ print_line("offset: " + itos(push_constant[0]));
+ print_line("size: " + itos(push_constant[1]));
+ //create SDF
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4);
+ RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4);
+ RD::get_singleton()->compute_list_end();
+ }
+
+ RD::get_singleton()->free(uniform_set);
+ RD::get_singleton()->free(shared_tex);
+ }
+#endif
+ }
+
+ gi_probe->version++;
+ gi_probe->data_version++;
+
+ gi_probe->instance_dependency.instance_notify_changed(true, false);
+}
+
+AABB RasterizerStorageRD::gi_probe_get_bounds(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, AABB());
+
+ return gi_probe->bounds;
+}
+
+Vector3i RasterizerStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Vector3i());
+ return gi_probe->octree_size;
+}
+Vector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
+
+ if (gi_probe->octree_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer);
+ }
+ return Vector<uint8_t>();
+}
+Vector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
+
+ if (gi_probe->data_buffer.is_valid()) {
+ return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer);
+ }
+ return Vector<uint8_t>();
+}
+Vector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
+
+ if (gi_probe->data_buffer.is_valid()) {
+ return RD::get_singleton()->texture_get_data(gi_probe->sdf_texture, 0);
+ }
+ return Vector<uint8_t>();
+}
+Vector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Vector<int>());
+
+ return gi_probe->level_counts;
+}
+Transform RasterizerStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, Transform());
+
+ return gi_probe->to_cell_xform;
+}
+
+void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->dynamic_range = p_range;
+ gi_probe->version++;
+}
+float RasterizerStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+
+ return gi_probe->dynamic_range;
+}
+
+void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->propagation = p_range;
+ gi_probe->version++;
+}
+float RasterizerStorageRD::gi_probe_get_propagation(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->propagation;
+}
+
+void RasterizerStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->energy = p_energy;
+}
+float RasterizerStorageRD::gi_probe_get_energy(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->energy;
+}
+
+void RasterizerStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->ao = p_ao;
+}
+float RasterizerStorageRD::gi_probe_get_ao(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->ao;
+}
+
+void RasterizerStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->ao_size = p_strength;
+}
+
+float RasterizerStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->ao_size;
+}
+
+void RasterizerStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->bias = p_bias;
+}
+float RasterizerStorageRD::gi_probe_get_bias(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->bias;
+}
+
+void RasterizerStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->normal_bias = p_normal_bias;
+}
+float RasterizerStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->normal_bias;
+}
+
+void RasterizerStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->anisotropy_strength = p_strength;
+}
+
+float RasterizerStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->anisotropy_strength;
+}
+
+void RasterizerStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->interior = p_enable;
+}
+
+void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gi_probe);
+
+ gi_probe->use_two_bounces = p_enable;
+ gi_probe->version++;
+}
+
+bool RasterizerStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, false);
+ return gi_probe->use_two_bounces;
+}
+
+bool RasterizerStorageRD::gi_probe_is_interior(RID p_gi_probe) const {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->interior;
+}
+
+uint32_t RasterizerStorageRD::gi_probe_get_version(RID p_gi_probe) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->version;
+}
+
+uint32_t RasterizerStorageRD::gi_probe_get_data_version(RID p_gi_probe) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, 0);
+ return gi_probe->data_version;
+}
+
+RID RasterizerStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+ return gi_probe->octree_buffer;
+}
+RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
+
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+ return gi_probe->data_buffer;
+}
+
+RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gi_probe, RID());
+
+ return gi_probe->sdf_texture;
+}
+
+/* RENDER TARGET API */
+
+void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
+
+ //free in reverse dependency order
+ if (rt->framebuffer.is_valid()) {
+ RD::get_singleton()->free(rt->framebuffer);
+ }
+
+ if (rt->color.is_valid()) {
+ RD::get_singleton()->free(rt->color);
+ }
+
+ if (rt->backbuffer.is_valid()) {
+ RD::get_singleton()->free(rt->backbuffer);
+ rt->backbuffer = RID();
+ for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) {
+ //just erase copies, since the rest are erased by dependency
+ RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy);
+ }
+ rt->backbuffer_mipmaps.clear();
+ if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) {
+ RD::get_singleton()->free(rt->backbuffer_uniform_set);
+ }
+ rt->backbuffer_uniform_set = RID();
+ }
+
+ rt->framebuffer = RID();
+ rt->color = RID();
+}
+
+void RasterizerStorageRD::_update_render_target(RenderTarget *rt) {
+
+ if (rt->texture.is_null()) {
+ //create a placeholder until updated
+ rt->texture = texture_2d_placeholder_create();
+ Texture *tex = texture_owner.getornull(rt->texture);
+ tex->is_render_target = true;
+ }
+
+ _clear_render_target(rt);
+
+ if (rt->size.width == 0 || rt->size.height == 0) {
+ return;
+ }
+ //until we implement support for HDR monitors (and render target is attached to screen), this is enough.
+ rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
+
+ RD::TextureFormat rd_format;
+ RD::TextureView rd_view;
+ { //attempt register
+ rd_format.format = rt->color_format;
+ rd_format.width = rt->size.width;
+ rd_format.height = rt->size.height;
+ rd_format.depth = 1;
+ rd_format.array_layers = 1;
+ rd_format.mipmaps = 1;
+ rd_format.type = RD::TEXTURE_TYPE_2D;
+ rd_format.samples = RD::TEXTURE_SAMPLES_1;
+ rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
+ rd_format.shareable_formats.push_back(rt->color_format);
+ rd_format.shareable_formats.push_back(rt->color_format_srgb);
+ }
+
+ rt->color = RD::get_singleton()->texture_create(rd_format, rd_view);
+ ERR_FAIL_COND(rt->color.is_null());
+
+ Vector<RID> fb_textures;
+ fb_textures.push_back(rt->color);
+ rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures);
+ if (rt->framebuffer.is_null()) {
+ _clear_render_target(rt);
+ ERR_FAIL_COND(rt->framebuffer.is_null());
+ }
+
+ { //update texture
+
+ Texture *tex = texture_owner.getornull(rt->texture);
+
+ //free existing textures
+ if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
+ RD::get_singleton()->free(tex->rd_texture);
+ }
+ if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
+ RD::get_singleton()->free(tex->rd_texture_srgb);
+ }
+
+ tex->rd_texture = RID();
+ tex->rd_texture_srgb = RID();
+
+ //create shared textures to the color buffer,
+ //so transparent can be supported
+ RD::TextureView view;
+ view.format_override = rt->color_format;
+ if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
+ view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
+ }
+ tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color);
+ if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
+ view.format_override = rt->color_format_srgb;
+ tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color);
+ }
+ tex->rd_view = view;
+ tex->width = rt->size.width;
+ tex->height = rt->size.height;
+ tex->width_2d = rt->size.width;
+ tex->height_2d = rt->size.height;
+ tex->rd_format = rt->color_format;
+ tex->rd_format_srgb = rt->color_format_srgb;
+ tex->format = rt->image_format;
+
+ Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
+ for (int i = 0; i < proxies.size(); i++) {
+ texture_proxy_update(proxies[i], rt->texture);
+ }
+ }
+}
+
+void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) {
+ ERR_FAIL_COND(rt->backbuffer.is_valid());
+
+ uint32_t mipmaps_required = Image::get_image_required_mipmaps(rt->size.width, rt->size.height, Image::FORMAT_RGBA8);
+ RD::TextureFormat tf;
+ tf.format = rt->color_format;
+ tf.width = rt->size.width;
+ tf.height = rt->size.height;
+ tf.type = RD::TEXTURE_TYPE_2D;
+ tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tf.mipmaps = mipmaps_required;
+
+ rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rt->backbuffer_mipmap0 = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0);
+
+ //create mipmaps
+ for (uint32_t i = 1; i < mipmaps_required; i++) {
+
+ RenderTarget::BackbufferMipmap mm;
+ {
+ mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i);
+ }
+
+ {
+ Size2 mm_size = Image::get_image_mipmap_size(tf.width, tf.height, Image::FORMAT_RGBA8, i);
+
+ RD::TextureFormat mmtf = tf;
+ mmtf.width = mm_size.width;
+ mmtf.height = mm_size.height;
+ mmtf.mipmaps = 1;
+
+ mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView());
+ }
+
+ rt->backbuffer_mipmaps.push_back(mm);
+ }
+}
+
+RID RasterizerStorageRD::render_target_create() {
+ RenderTarget render_target;
+
+ render_target.was_used = false;
+ render_target.clear_requested = false;
+
+ for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
+ render_target.flags[i] = false;
+ }
+ _update_render_target(&render_target);
+ return render_target_owner.make_rid(render_target);
+}
+
+void RasterizerStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) {
+ //unused for this render target
+}
+
+void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->size.x = p_width;
+ rt->size.y = p_height;
+ _update_render_target(rt);
+}
+
+RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->texture;
+}
+
+void RasterizerStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
+}
+
+void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->flags[p_flag] = p_value;
+ _update_render_target(rt);
+}
+
+bool RasterizerStorageRD::render_target_was_used(RID p_render_target) {
+
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+ return rt->was_used;
+}
+
+void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) {
+
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->was_used = false;
+}
+
+Size2 RasterizerStorageRD::render_target_get_size(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, Size2());
+
+ return rt->size;
+}
+
+RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->framebuffer;
+}
+RID RasterizerStorageRD::render_target_get_rd_texture(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->color;
+}
+void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->clear_requested = true;
+ rt->clear_color = p_clear_color;
+}
+
+bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+ return rt->clear_requested;
+}
+
+Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) {
+
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, Color());
+ return rt->clear_color;
+}
+
+void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) {
+
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ rt->clear_requested = false;
+}
+
+void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
+
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (!rt->clear_requested) {
+ return;
+ }
+ Vector<Color> clear_colors;
+ clear_colors.push_back(rt->clear_color);
+ RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::get_singleton()->draw_list_end();
+ rt->clear_requested = false;
+}
+
+void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (!rt->backbuffer.is_valid()) {
+ _create_render_target_backbuffer(rt);
+ }
+
+ Rect2i region = p_region;
+ if (region == Rect2i()) {
+ region.size = rt->size;
+ }
+
+ //single texture copy for backbuffer
+ RD::get_singleton()->texture_copy(rt->color, rt->backbuffer_mipmap0, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true);
+ //effects.copy(rt->color, rt->backbuffer_fb, blur_region);
+
+ //then mipmap blur
+ RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps.
+
+ for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) {
+ region.position.x >>= 1;
+ region.position.y >>= 1;
+ region.size.x = MAX(1, region.size.x >> 1);
+ region.size.y = MAX(1, region.size.y >> 1);
+
+ const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i];
+ effects.gaussian_blur(prev_texture, mm.mipmap, mm.mipmap_copy, region, true);
+ prev_texture = mm.mipmap;
+ }
+}
+
+RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader) {
+ RenderTarget *rt = render_target_owner.getornull(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ if (!rt->backbuffer.is_valid()) {
+ _create_render_target_backbuffer(rt);
+ }
+
+ if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) {
+ return rt->backbuffer_uniform_set; //if still valid, return/reuse it.
+ }
+
+ //create otherwise
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 0;
+ u.ids.push_back(rt->backbuffer);
+ uniforms.push_back(u);
+
+ rt->backbuffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, 3);
+ ERR_FAIL_COND_V(!rt->backbuffer_uniform_set.is_valid(), RID());
+
+ return rt->backbuffer_uniform_set;
+}
+
+void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
+ if (mesh_owner.owns(p_base)) {
+ Mesh *mesh = mesh_owner.getornull(p_base);
+ p_instance->update_dependency(&mesh->instance_dependency);
+ } else if (multimesh_owner.owns(p_base)) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_base);
+ p_instance->update_dependency(&multimesh->instance_dependency);
+ if (multimesh->mesh.is_valid()) {
+ base_update_dependency(multimesh->mesh, p_instance);
+ }
+ } else if (reflection_probe_owner.owns(p_base)) {
+ ReflectionProbe *rp = reflection_probe_owner.getornull(p_base);
+ p_instance->update_dependency(&rp->instance_dependency);
+ } else if (decal_owner.owns(p_base)) {
+ Decal *decal = decal_owner.getornull(p_base);
+ p_instance->update_dependency(&decal->instance_dependency);
+ } else if (gi_probe_owner.owns(p_base)) {
+ GIProbe *gip = gi_probe_owner.getornull(p_base);
+ p_instance->update_dependency(&gip->instance_dependency);
+ } else if (light_owner.owns(p_base)) {
+ Light *l = light_owner.getornull(p_base);
+ p_instance->update_dependency(&l->instance_dependency);
+ }
+}
+
+void RasterizerStorageRD::skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND(!skeleton);
+
+ p_instance->update_dependency(&skeleton->instance_dependency);
+}
+
+RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
+
+ if (mesh_owner.owns(p_rid)) {
+ return RS::INSTANCE_MESH;
+ }
+ if (multimesh_owner.owns(p_rid)) {
+ return RS::INSTANCE_MULTIMESH;
+ }
+ if (reflection_probe_owner.owns(p_rid)) {
+ return RS::INSTANCE_REFLECTION_PROBE;
+ }
+ if (decal_owner.owns(p_rid)) {
+ return RS::INSTANCE_DECAL;
+ }
+ if (gi_probe_owner.owns(p_rid)) {
+ return RS::INSTANCE_GI_PROBE;
+ }
+ if (light_owner.owns(p_rid)) {
+ return RS::INSTANCE_LIGHT;
+ }
+
+ return RS::INSTANCE_NONE;
+}
+
+void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
+ if (!decal_atlas.textures.has(p_texture)) {
+ DecalAtlas::Texture t;
+ t.users = 1;
+ t.panorama_to_dp_users = p_panorama_to_dp ? 1 : 0;
+ decal_atlas.textures[p_texture] = t;
+ decal_atlas.dirty = true;
+ } else {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
+ t->users++;
+ if (p_panorama_to_dp) {
+ t->panorama_to_dp_users++;
+ }
+ }
+}
+
+void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
+ ERR_FAIL_COND(!t);
+ t->users--;
+ if (p_panorama_to_dp) {
+ ERR_FAIL_COND(t->panorama_to_dp_users == 0);
+ t->panorama_to_dp_users--;
+ }
+ if (t->users == 0) {
+ decal_atlas.textures.erase(p_texture);
+ //do not mark it dirty, there is no need to since it remains working
+ }
+}
+
+RID RasterizerStorageRD::decal_atlas_get_texture() const {
+ return decal_atlas.texture;
+}
+
+RID RasterizerStorageRD::decal_atlas_get_texture_srgb() const {
+ return decal_atlas.texture;
+}
+
+void RasterizerStorageRD::_update_decal_atlas() {
+ if (!decal_atlas.dirty) {
+ return; //nothing to do
+ }
+
+ decal_atlas.dirty = false;
+
+ if (decal_atlas.texture.is_valid()) {
+ RD::get_singleton()->free(decal_atlas.texture);
+ decal_atlas.texture = RID();
+ decal_atlas.texture_srgb = RID();
+ decal_atlas.texture_mipmaps.clear();
+ }
+
+ int border = 1 << decal_atlas.mipmaps;
+
+ if (decal_atlas.textures.size()) {
+ //generate atlas
+ Vector<DecalAtlas::SortItem> itemsv;
+ itemsv.resize(decal_atlas.textures.size());
+ int base_size = 8;
+ const RID *K = NULL;
+
+ int idx = 0;
+ while ((K = decal_atlas.textures.next(K))) {
+ DecalAtlas::SortItem &si = itemsv.write[idx];
+
+ Texture *src_tex = texture_owner.getornull(*K);
+
+ si.size.width = (src_tex->width / border) + 1;
+ si.size.height = (src_tex->height / border) + 1;
+ si.pixel_size = Size2i(src_tex->width, src_tex->height);
+
+ if (base_size < si.size.width) {
+ base_size = nearest_power_of_2_templated(si.size.width);
+ }
+
+ si.texture = *K;
+ idx++;
+ }
+
+ //sort items by size
+ itemsv.sort();
+
+ //attempt to create atlas
+ int item_count = itemsv.size();
+ DecalAtlas::SortItem *items = itemsv.ptrw();
+
+ int atlas_height = 0;
+
+ while (true) {
+
+ Vector<int> v_offsetsv;
+ v_offsetsv.resize(base_size);
+
+ int *v_offsets = v_offsetsv.ptrw();
+ zeromem(v_offsets, sizeof(int) * base_size);
+
+ int max_height = 0;
+
+ for (int i = 0; i < item_count; i++) {
+ //best fit
+ DecalAtlas::SortItem &si = items[i];
+ int best_idx = -1;
+ int best_height = 0x7FFFFFFF;
+ for (int j = 0; j <= base_size - si.size.width; j++) {
+ int height = 0;
+ for (int k = 0; k < si.size.width; k++) {
+ int h = v_offsets[k + j];
+ if (h > height) {
+ height = h;
+ if (height > best_height) {
+ break; //already bad
+ }
+ }
+ }
+
+ if (height < best_height) {
+ best_height = height;
+ best_idx = j;
+ }
+ }
+
+ //update
+ for (int k = 0; k < si.size.width; k++) {
+ v_offsets[k + best_idx] = best_height + si.size.height;
+ }
+
+ si.pos.x = best_idx;
+ si.pos.y = best_height;
+
+ if (si.pos.y + si.size.height > max_height) {
+ max_height = si.pos.y + si.size.height;
+ }
+ }
+
+ if (max_height <= base_size * 2) {
+ atlas_height = max_height;
+ break; //good ratio, break;
+ }
+
+ base_size *= 2;
+ }
+
+ decal_atlas.size.width = base_size * border;
+ decal_atlas.size.height = nearest_power_of_2_templated(atlas_height * border);
+
+ for (int i = 0; i < item_count; i++) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(items[i].texture);
+ t->uv_rect.position = items[i].pos * border + Vector2i(border / 2, border / 2);
+ t->uv_rect.size = items[i].pixel_size;
+ //print_line("blitrect: " + t->uv_rect);
+ t->uv_rect.position /= Size2(decal_atlas.size);
+ t->uv_rect.size /= Size2(decal_atlas.size);
+ }
+ } else {
+
+ //use border as size, so it at least has enough mipmaps
+ decal_atlas.size.width = border;
+ decal_atlas.size.height = border;
+ }
+
+ //blit textures
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = decal_atlas.size.width;
+ tformat.height = decal_atlas.size.height;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+ tformat.type = RD::TEXTURE_TYPE_2D;
+ tformat.mipmaps = decal_atlas.mipmaps;
+ tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
+ tformat.shareable_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
+
+ decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+
+ {
+ //create the framebuffer
+
+ Size2i s = decal_atlas.size;
+
+ for (int i = 0; i < decal_atlas.mipmaps; i++) {
+ DecalAtlas::MipMap mm;
+ mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), decal_atlas.texture, 0, i);
+ Vector<RID> fb;
+ fb.push_back(mm.texture);
+ mm.fb = RD::get_singleton()->framebuffer_create(fb);
+ mm.size = s;
+ decal_atlas.texture_mipmaps.push_back(mm);
+
+ s.width = MAX(1, s.width >> 1);
+ s.height = MAX(1, s.height >> 1);
+ }
+ {
+ //create the SRGB variant
+ RD::TextureView rd_view;
+ rd_view.format_override = RD::DATA_FORMAT_R8G8B8A8_SRGB;
+ decal_atlas.texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, decal_atlas.texture);
+ }
+ }
+
+ RID prev_texture;
+ for (int i = 0; i < decal_atlas.texture_mipmaps.size(); i++) {
+ const DecalAtlas::MipMap &mm = decal_atlas.texture_mipmaps[i];
+
+ Color clear_color(0, 0, 0, 0);
+
+ if (decal_atlas.textures.size()) {
+
+ if (i == 0) {
+ Vector<Color> cc;
+ cc.push_back(clear_color);
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(mm.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, cc);
+
+ const RID *K = NULL;
+ while ((K = decal_atlas.textures.next(K))) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
+ Texture *src_tex = texture_owner.getornull(*K);
+ effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
+ }
+
+ RD::get_singleton()->draw_list_end();
+
+ prev_texture = mm.texture;
+ } else {
+
+ effects.copy_to_fb_rect(prev_texture, mm.fb, Rect2i(Point2i(), mm.size));
+ prev_texture = mm.texture;
+ }
+ } else {
+ RD::get_singleton()->texture_clear(mm.texture, clear_color, 0, 1, 0, 1, false);
+ }
+ }
+}
+
+void RasterizerStorageRD::update_dirty_resources() {
+ _update_queued_materials();
+ _update_dirty_multimeshes();
+ _update_dirty_skeletons();
+ _update_decal_atlas();
+}
+
+bool RasterizerStorageRD::has_os_feature(const String &p_feature) const {
+
+ if (p_feature == "rgtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
+ return true;
+ }
+
+ if (p_feature == "s3tc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
+ return true;
+ }
+
+ if (p_feature == "bptc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
+ return true;
+ }
+
+ if ((p_feature == "etc" || p_feature == "etc2") && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
+ return true;
+ }
+
+ if (p_feature == "pvrtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
+ return true;
+ }
+
+ return false;
+}
+bool RasterizerStorageRD::free(RID p_rid) {
+
+ if (texture_owner.owns(p_rid)) {
+ Texture *t = texture_owner.getornull(p_rid);
+
+ ERR_FAIL_COND_V(t->is_render_target, false);
+
+ if (RD::get_singleton()->texture_is_valid(t->rd_texture_srgb)) {
+ //erase this first, as it's a dependency of the one below
+ RD::get_singleton()->free(t->rd_texture_srgb);
+ }
+ if (RD::get_singleton()->texture_is_valid(t->rd_texture)) {
+ RD::get_singleton()->free(t->rd_texture);
+ }
+
+ if (t->is_proxy && t->proxy_to.is_valid()) {
+ Texture *proxy_to = texture_owner.getornull(t->proxy_to);
+ if (proxy_to) {
+ proxy_to->proxies.erase(p_rid);
+ }
+ }
+
+ if (decal_atlas.textures.has(p_rid)) {
+ decal_atlas.textures.erase(p_rid);
+ //there is not much a point of making it dirty, just let it be.
+ }
+
+ for (int i = 0; i < t->proxies.size(); i++) {
+ Texture *p = texture_owner.getornull(t->proxies[i]);
+ ERR_CONTINUE(!p);
+ p->proxy_to = RID();
+ p->rd_texture = RID();
+ p->rd_texture_srgb = RID();
+ }
+ texture_owner.free(p_rid);
+
+ } else if (shader_owner.owns(p_rid)) {
+ Shader *shader = shader_owner.getornull(p_rid);
+ //make material unreference this
+ while (shader->owners.size()) {
+ material_set_shader(shader->owners.front()->get()->self, RID());
+ }
+ //clear data if exists
+ if (shader->data) {
+ memdelete(shader->data);
+ }
+ shader_owner.free(p_rid);
+
+ } else if (material_owner.owns(p_rid)) {
+ Material *material = material_owner.getornull(p_rid);
+ if (material->update_requested) {
+ _update_queued_materials();
+ }
+ material_set_shader(p_rid, RID()); //clean up shader
+ material->instance_dependency.instance_notify_deleted(p_rid);
+ material_owner.free(p_rid);
+ } else if (mesh_owner.owns(p_rid)) {
+ mesh_clear(p_rid);
+ Mesh *mesh = mesh_owner.getornull(p_rid);
+ mesh->instance_dependency.instance_notify_deleted(p_rid);
+ mesh_owner.free(p_rid);
+ } else if (multimesh_owner.owns(p_rid)) {
+ _update_dirty_multimeshes();
+ multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D);
+ MultiMesh *multimesh = multimesh_owner.getornull(p_rid);
+ multimesh->instance_dependency.instance_notify_deleted(p_rid);
+ multimesh_owner.free(p_rid);
+ } else if (skeleton_owner.owns(p_rid)) {
+ _update_dirty_skeletons();
+ skeleton_allocate(p_rid, 0);
+ Skeleton *skeleton = skeleton_owner.getornull(p_rid);
+ skeleton->instance_dependency.instance_notify_deleted(p_rid);
+ skeleton_owner.free(p_rid);
+ } else if (reflection_probe_owner.owns(p_rid)) {
+ ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid);
+ reflection_probe->instance_dependency.instance_notify_deleted(p_rid);
+ reflection_probe_owner.free(p_rid);
+ } else if (decal_owner.owns(p_rid)) {
+ Decal *decal = decal_owner.getornull(p_rid);
+ for (int i = 0; i < RS::DECAL_TEXTURE_MAX; i++) {
+ if (decal->textures[i].is_valid() && texture_owner.owns(decal->textures[i])) {
+ texture_remove_from_decal_atlas(decal->textures[i]);
+ }
+ }
+ decal->instance_dependency.instance_notify_deleted(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
+ GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
+ gi_probe->instance_dependency.instance_notify_deleted(p_rid);
+ gi_probe_owner.free(p_rid);
+
+ } else if (light_owner.owns(p_rid)) {
+
+ light_set_projector(p_rid, RID()); //clear projector
+ // delete the texture
+ Light *light = light_owner.getornull(p_rid);
+ light->instance_dependency.instance_notify_deleted(p_rid);
+ light_owner.free(p_rid);
+
+ } else if (render_target_owner.owns(p_rid)) {
+ RenderTarget *rt = render_target_owner.getornull(p_rid);
+
+ _clear_render_target(rt);
+
+ if (rt->texture.is_valid()) {
+ Texture *tex = texture_owner.getornull(rt->texture);
+ tex->is_render_target = false;
+ free(rt->texture);
+ }
+
+ render_target_owner.free(p_rid);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+RasterizerEffectsRD *RasterizerStorageRD::get_effects() {
+ return &effects;
+}
+
+void RasterizerStorageRD::capture_timestamps_begin() {
+ RD::get_singleton()->capture_timestamp("Frame Begin", false);
+}
+
+void RasterizerStorageRD::capture_timestamp(const String &p_name) {
+ RD::get_singleton()->capture_timestamp(p_name, true);
+}
+
+uint32_t RasterizerStorageRD::get_captured_timestamps_count() const {
+ return RD::get_singleton()->get_captured_timestamps_count();
+}
+uint64_t RasterizerStorageRD::get_captured_timestamps_frame() const {
+ return RD::get_singleton()->get_captured_timestamps_frame();
+}
+
+uint64_t RasterizerStorageRD::get_captured_timestamp_gpu_time(uint32_t p_index) const {
+ return RD::get_singleton()->get_captured_timestamp_gpu_time(p_index);
+}
+uint64_t RasterizerStorageRD::get_captured_timestamp_cpu_time(uint32_t p_index) const {
+ return RD::get_singleton()->get_captured_timestamp_cpu_time(p_index);
+}
+String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const {
+ return RD::get_singleton()->get_captured_timestamp_name(p_index);
+}
+
+RasterizerStorageRD::RasterizerStorageRD() {
+
+ for (int i = 0; i < SHADER_TYPE_MAX; i++) {
+ shader_data_request_func[i] = nullptr;
+ }
+
+ material_update_list = nullptr;
+ { //create default textures
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.type = RD::TEXTURE_TYPE_2D;
+
+ Vector<uint8_t> pv;
+ pv.resize(16 * 4);
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 255);
+ pv.set(i * 4 + 1, 255);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+
+ //take the chance and initialize decal atlas to something
+ decal_atlas.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ decal_atlas.texture_srgb = decal_atlas.texture;
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 128);
+ pv.set(i * 4 + 1, 128);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_NORMAL] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 255);
+ pv.set(i * 4 + 1, 128);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_ANISO] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ default_rd_textures[DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER] = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
+ }
+
+ { //create default cubemap
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.array_layers = 6;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+
+ Vector<uint8_t> pv;
+ pv.resize(16 * 4);
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ for (int i = 0; i < 6; i++) {
+ vpv.push_back(pv);
+ }
+ default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+ }
+
+ { //create default cubemap array
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.array_layers = 6;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.type = RD::TEXTURE_TYPE_CUBE;
+
+ Vector<uint8_t> pv;
+ pv.resize(16 * 4);
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ for (int i = 0; i < 6; i++) {
+ vpv.push_back(pv);
+ }
+ default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+ }
+
+ { //create default 3D
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.depth = 4;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.type = RD::TEXTURE_TYPE_3D;
+
+ Vector<uint8_t> pv;
+ pv.resize(64 * 4);
+ for (int i = 0; i < 64; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_3D_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+ }
+
+ //default samplers
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::SamplerState sampler_state;
+ switch (i) {
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ 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 = GLOBAL_GET("rendering/quality/texture_filters/max_anisotropy");
+ } 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 = GLOBAL_GET("rendering/quality/texture_filters/max_anisotropy");
+
+ } break;
+ default: {
+ }
+ }
+ switch (j) {
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ } break;
+ default: {
+ }
+ }
+
+ default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
+ }
+ }
+
+ //default rd buffers
+ {
+
+ //vertex
+ {
+
+ Vector<uint8_t> buffer;
+
+ buffer.resize(sizeof(float) * 3);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //normal
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 3);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 1.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //tangent
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 4);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 1.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ fptr[3] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //color
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 4);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 1.0;
+ fptr[1] = 1.0;
+ fptr[2] = 1.0;
+ fptr[3] = 1.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //tex uv 1
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 2);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+{ //tex uv 2
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 2);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //bones
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(uint32_t) * 4);
+ {
+ uint8_t *w = buffer.ptrw();
+ uint32_t *fptr = (uint32_t *)w;
+ fptr[0] = 0;
+ fptr[1] = 0;
+ fptr[2] = 0;
+ fptr[3] = 0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+
+{ //weights
+ Vector<uint8_t> buffer;
+ buffer.resize(sizeof(float) * 4);
+ {
+ uint8_t *w = buffer.ptrw();
+ float *fptr = (float *)w;
+ fptr[0] = 0.0;
+ fptr[1] = 0.0;
+ fptr[2] = 0.0;
+ fptr[3] = 0.0;
+ }
+ mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
+}
+}
+
+{
+ Vector<String> sdf_versions;
+ 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);
+}
+}
+
+RasterizerStorageRD::~RasterizerStorageRD() {
+
+ //def textures
+ for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) {
+ RD::get_singleton()->free(default_rd_textures[i]);
+ }
+
+ //def samplers
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::get_singleton()->free(default_rd_samplers[i][j]);
+ }
+ }
+
+ //def buffers
+ for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) {
+ RD::get_singleton()->free(mesh_default_rd_buffers[i]);
+ }
+ giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
+
+ if (decal_atlas.textures.size()) {
+ ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas.");
+ }
+
+ if (decal_atlas.texture.is_valid()) {
+ RD::get_singleton()->free(decal_atlas.texture);
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
new file mode 100644
index 0000000000..1980f043a0
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -0,0 +1,1306 @@
+/*************************************************************************/
+/* rasterizer_storage_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RASTERIZER_STORAGE_RD_H
+#define RASTERIZER_STORAGE_RD_H
+
+#include "core/rid_owner.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h"
+#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h"
+#include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
+#include "servers/rendering/rendering_device.h"
+
+class RasterizerStorageRD : public RasterizerStorage {
+public:
+ enum ShaderType {
+ SHADER_TYPE_2D,
+ SHADER_TYPE_3D,
+ SHADER_TYPE_PARTICLES,
+ SHADER_TYPE_SKY,
+ SHADER_TYPE_MAX
+ };
+
+ struct ShaderData {
+ virtual void set_code(const String &p_Code) = 0;
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
+ virtual bool is_param_texture(const StringName &p_param) const = 0;
+ virtual bool is_animated() const = 0;
+ virtual bool casts_shadows() const = 0;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
+ virtual ~ShaderData() {}
+ };
+
+ typedef ShaderData *(*ShaderDataRequestFunction)();
+
+ struct MaterialData {
+
+ void update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
+ void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
+
+ virtual void set_render_priority(int p_priority) = 0;
+ virtual void set_next_pass(RID p_pass) = 0;
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
+ virtual ~MaterialData() {}
+ };
+ typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+
+ enum DefaultRDTexture {
+ DEFAULT_RD_TEXTURE_WHITE,
+ DEFAULT_RD_TEXTURE_BLACK,
+ DEFAULT_RD_TEXTURE_NORMAL,
+ DEFAULT_RD_TEXTURE_ANISO,
+ DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER,
+ DEFAULT_RD_TEXTURE_CUBEMAP_BLACK,
+ DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK,
+ DEFAULT_RD_TEXTURE_3D_WHITE,
+ DEFAULT_RD_TEXTURE_MAX
+ };
+
+ enum DefaultRDBuffer {
+ DEFAULT_RD_BUFFER_VERTEX,
+ DEFAULT_RD_BUFFER_NORMAL,
+ DEFAULT_RD_BUFFER_TANGENT,
+ DEFAULT_RD_BUFFER_COLOR,
+ DEFAULT_RD_BUFFER_TEX_UV,
+ DEFAULT_RD_BUFFER_TEX_UV2,
+ DEFAULT_RD_BUFFER_BONES,
+ DEFAULT_RD_BUFFER_WEIGHTS,
+ DEFAULT_RD_BUFFER_MAX,
+ };
+
+private:
+ /* TEXTURE API */
+ struct Texture {
+
+ enum Type {
+ TYPE_2D,
+ TYPE_LAYERED,
+ TYPE_3D
+ };
+
+ Type type;
+
+ RenderingDevice::TextureType rd_type;
+ RID rd_texture;
+ RID rd_texture_srgb;
+ RenderingDevice::DataFormat rd_format;
+ RenderingDevice::DataFormat rd_format_srgb;
+
+ RD::TextureView rd_view;
+
+ Image::Format format;
+ Image::Format validated_format;
+
+ int width;
+ int height;
+ int depth;
+ int layers;
+ int mipmaps;
+
+ int height_2d;
+ int width_2d;
+
+ bool is_render_target;
+ bool is_proxy;
+
+ Ref<Image> image_cache_2d;
+ String path;
+
+ RID proxy_to;
+ Vector<RID> proxies;
+
+ RS::TextureDetectCallback detect_3d_callback = nullptr;
+ void *detect_3d_callback_ud = nullptr;
+
+ RS::TextureDetectCallback detect_normal_callback = nullptr;
+ void *detect_normal_callback_ud = nullptr;
+
+ RS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;
+ void *detect_roughness_callback_ud = nullptr;
+ };
+
+ struct TextureToRDFormat {
+ RD::DataFormat format;
+ RD::DataFormat format_srgb;
+ RD::TextureSwizzle swizzle_r;
+ RD::TextureSwizzle swizzle_g;
+ RD::TextureSwizzle swizzle_b;
+ RD::TextureSwizzle swizzle_a;
+ TextureToRDFormat() {
+ format = RD::DATA_FORMAT_MAX;
+ format_srgb = RD::DATA_FORMAT_MAX;
+ swizzle_r = RD::TEXTURE_SWIZZLE_R;
+ swizzle_g = RD::TEXTURE_SWIZZLE_G;
+ swizzle_b = RD::TEXTURE_SWIZZLE_B;
+ swizzle_a = RD::TEXTURE_SWIZZLE_A;
+ }
+ };
+
+ //textures can be created from threads, so this RID_Owner is thread safe
+ mutable RID_Owner<Texture, true> texture_owner;
+
+ Ref<Image> _validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format);
+
+ RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
+ RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+
+ /* DECAL ATLAS */
+
+ struct DecalAtlas {
+ struct Texture {
+
+ int panorama_to_dp_users;
+ int users;
+ Rect2 uv_rect;
+ };
+
+ struct SortItem {
+ RID texture;
+ Size2i pixel_size;
+ Size2i size;
+ Point2i pos;
+
+ bool operator<(const SortItem &p_item) const {
+ //sort larger to smaller
+ if (size.height == p_item.size.height) {
+ return size.width > p_item.size.width;
+ } else {
+ return size.height > p_item.size.height;
+ }
+ }
+ };
+
+ HashMap<RID, Texture> textures;
+ bool dirty = true;
+ int mipmaps = 5;
+
+ RID texture;
+ RID texture_srgb;
+ struct MipMap {
+ RID fb;
+ RID texture;
+ Size2i size;
+ };
+ Vector<MipMap> texture_mipmaps;
+
+ Size2i size;
+
+ } decal_atlas;
+
+ void _update_decal_atlas();
+
+ /* SHADER */
+
+ struct Material;
+
+ struct Shader {
+ ShaderData *data;
+ String code;
+ ShaderType type;
+ Map<StringName, RID> default_texture_parameter;
+ Set<Material *> owners;
+ };
+
+ ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX];
+ mutable RID_Owner<Shader> shader_owner;
+
+ /* Material */
+
+ struct Material {
+ RID self;
+ MaterialData *data;
+ Shader *shader;
+ //shortcut to shader data and type
+ ShaderType shader_type;
+ bool update_requested;
+ bool uniform_dirty;
+ bool texture_dirty;
+ Material *update_next;
+ Map<StringName, Variant> params;
+ int32_t priority;
+ RID next_pass;
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
+ mutable RID_Owner<Material> material_owner;
+
+ Material *material_update_list;
+ void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
+ void _update_queued_materials();
+
+ /* Mesh */
+
+ struct Mesh {
+
+ struct Surface {
+ RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
+ uint32_t format = 0;
+
+ RID vertex_buffer;
+ uint32_t vertex_count = 0;
+
+ // A different pipeline needs to be allocated
+ // depending on the inputs available in the
+ // material.
+ // There are never that many geometry/material
+ // combinations, so a simple array is the most
+ // cache-efficient structure.
+
+ struct Version {
+ uint32_t input_mask = 0;
+ RD::VertexFormatID vertex_format = 0;
+ RID vertex_array;
+ };
+
+ SpinLock version_lock; //needed to access versions
+ Version *versions = nullptr; //allocated on demand
+ uint32_t version_count = 0;
+
+ RID index_buffer;
+ RID index_array;
+ uint32_t index_count = 0;
+
+ struct LOD {
+ float edge_length = 0.0;
+ RID index_buffer;
+ RID index_array;
+ };
+
+ LOD *lods = nullptr;
+ uint32_t lod_count = 0;
+
+ AABB aabb;
+
+ Vector<AABB> bone_aabbs;
+
+ Vector<RID> blend_shapes;
+ RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed
+
+ RID material;
+
+ uint32_t render_index = 0;
+ uint64_t render_pass = 0;
+
+ uint32_t multimesh_render_index = 0;
+ uint64_t multimesh_render_pass = 0;
+ };
+
+ uint32_t blend_shape_count = 0;
+ RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
+
+ Surface **surfaces = nullptr;
+ uint32_t surface_count = 0;
+
+ Vector<AABB> bone_aabbs;
+
+ AABB aabb;
+ AABB custom_aabb;
+
+ Vector<RID> material_cache;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<Mesh> mesh_owner;
+
+ void _mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask);
+
+ RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
+
+ /* MultiMesh */
+ struct MultiMesh {
+ RID mesh;
+ int instances = 0;
+ RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
+ bool uses_colors = false;
+ bool uses_custom_data = false;
+ int visible_instances = -1;
+ AABB aabb;
+ bool aabb_dirty = false;
+ bool buffer_set = false;
+ uint32_t stride_cache = 0;
+ uint32_t color_offset_cache = 0;
+ uint32_t custom_data_offset_cache = 0;
+
+ Vector<float> data_cache; //used if individual setting is used
+ bool *data_cache_dirty_regions = nullptr;
+ uint32_t data_cache_used_dirty_regions = 0;
+
+ RID buffer; //storage buffer
+ RID uniform_set_3d;
+
+ bool dirty = false;
+ MultiMesh *dirty_list = nullptr;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<MultiMesh> multimesh_owner;
+
+ MultiMesh *multimesh_dirty_list = nullptr;
+
+ _FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+ _FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
+ _FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
+ _FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
+ void _update_dirty_multimeshes();
+
+ /* Skeleton */
+
+ struct Skeleton {
+ bool use_2d = false;
+ int size = 0;
+ Vector<float> data;
+ RID buffer;
+
+ bool dirty = false;
+ Skeleton *dirty_list = nullptr;
+ Transform2D base_transform_2d;
+
+ RID uniform_set_3d;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<Skeleton> skeleton_owner;
+
+ _FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
+
+ Skeleton *skeleton_dirty_list = nullptr;
+
+ void _update_dirty_skeletons();
+
+ /* LIGHT */
+
+ struct Light {
+
+ RS::LightType type;
+ float param[RS::LIGHT_PARAM_MAX];
+ Color color = Color(1, 1, 1, 1);
+ Color shadow_color;
+ RID projector;
+ bool shadow = false;
+ bool negative = false;
+ bool reverse_cull = false;
+ bool use_gi = true;
+ uint32_t cull_mask = 0xFFFFFFFF;
+ RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
+ bool directional_blend_splits = false;
+ uint64_t version = 0;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<Light> light_owner;
+
+ /* REFLECTION PROBE */
+
+ struct ReflectionProbe {
+
+ RS::ReflectionProbeUpdateMode update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE;
+ int resolution = 256;
+ float intensity = 1.0;
+ Color interior_ambient;
+ float interior_ambient_energy = 1.0;
+ float interior_ambient_probe_contrib = 0.0;
+ float max_distance = 0;
+ Vector3 extents = Vector3(1, 1, 1);
+ Vector3 origin_offset;
+ bool interior = false;
+ bool box_projection = false;
+ bool enable_shadows = false;
+ uint32_t cull_mask = (1 << 20) - 1;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
+
+ /* DECAL */
+
+ struct Decal {
+
+ Vector3 extents = Vector3(1, 1, 1);
+ RID textures[RS::DECAL_TEXTURE_MAX];
+ float emission_energy = 1.0;
+ float albedo_mix = 1.0;
+ Color modulate = Color(1, 1, 1, 1);
+ uint32_t cull_mask = (1 << 20) - 1;
+ float upper_fade = 0.3;
+ float lower_fade = 0.3;
+ bool distance_fade = false;
+ float distance_fade_begin = 10;
+ float distance_fade_length = 1;
+ float normal_fade = 0.0;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ mutable RID_Owner<Decal> decal_owner;
+
+ /* GI PROBE */
+
+ struct GIProbe {
+
+ RID octree_buffer;
+ RID data_buffer;
+ RID sdf_texture;
+
+ uint32_t octree_buffer_size = 0;
+ uint32_t data_buffer_size = 0;
+
+ Vector<int> level_counts;
+
+ int cell_count = 0;
+
+ Transform to_cell_xform;
+ AABB bounds;
+ Vector3i octree_size;
+
+ float dynamic_range = 4.0;
+ float energy = 1.0;
+ float ao = 0.0;
+ float ao_size = 0.5;
+ float bias = 1.4;
+ float normal_bias = 0.0;
+ float propagation = 0.7;
+ bool interior = false;
+ bool use_two_bounces = false;
+
+ float anisotropy_strength = 0.5;
+
+ uint32_t version = 1;
+ uint32_t data_version = 1;
+
+ RasterizerScene::InstanceDependency instance_dependency;
+ };
+
+ GiprobeSdfShaderRD giprobe_sdf_shader;
+ RID giprobe_sdf_shader_version;
+ RID giprobe_sdf_shader_version_shader;
+ RID giprobe_sdf_shader_pipeline;
+
+ mutable RID_Owner<GIProbe> gi_probe_owner;
+
+ /* RENDER TARGET */
+
+ struct RenderTarget {
+
+ Size2i size;
+ RID framebuffer;
+ RID color;
+
+ //used for retrieving from CPU
+ RD::DataFormat color_format = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
+ RD::DataFormat color_format_srgb = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
+ Image::Format image_format = Image::FORMAT_L8;
+
+ bool flags[RENDER_TARGET_FLAG_MAX];
+
+ RID backbuffer; //used for effects
+ RID backbuffer_mipmap0;
+
+ struct BackbufferMipmap {
+ RID mipmap;
+ RID mipmap_copy;
+ };
+
+ Vector<BackbufferMipmap> backbuffer_mipmaps;
+ RID backbuffer_uniform_set;
+
+ //texture generated for this owner (nor RD).
+ RID texture;
+ bool was_used;
+
+ //clear request
+ bool clear_requested;
+ Color clear_color;
+ };
+
+ RID_Owner<RenderTarget> render_target_owner;
+
+ void _clear_render_target(RenderTarget *rt);
+ void _update_render_target(RenderTarget *rt);
+ void _create_render_target_backbuffer(RenderTarget *rt);
+
+ /* EFFECTS */
+
+ RasterizerEffectsRD effects;
+
+public:
+ /* 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(const Vector<Ref<Image>> &p_slices); //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_proxy_create(RID p_base);
+
+ virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate);
+
+ virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming
+ virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
+ virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap);
+ 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();
+ virtual RID texture_3d_placeholder_create();
+
+ virtual Ref<Image> texture_2d_get(RID p_texture) const;
+ virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const;
+ virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const;
+
+ virtual void texture_replace(RID p_texture, RID p_by_texture);
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
+
+ virtual void texture_set_path(RID p_texture, const String &p_path);
+ virtual String texture_get_path(RID p_texture) const;
+
+ virtual void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata);
+ virtual void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata);
+ virtual void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata);
+
+ virtual void texture_debug_usage(List<RS::TextureInfo> *r_info);
+
+ virtual void texture_set_proxy(RID p_proxy, RID p_base);
+ virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable);
+
+ virtual Size2 texture_size_with_proxy(RID p_proxy);
+
+ virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false);
+ virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false);
+
+ RID decal_atlas_get_texture() const;
+ RID decal_atlas_get_texture_srgb() const;
+ _FORCE_INLINE_ Rect2 decal_atlas_get_texture_rect(RID p_texture) {
+ DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
+ if (!t) {
+ return Rect2();
+ }
+
+ return t->uv_rect;
+ }
+
+ //internal usage
+
+ _FORCE_INLINE_ RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) {
+ if (p_texture.is_null()) {
+ return RID();
+ }
+ Texture *tex = texture_owner.getornull(p_texture);
+
+ if (!tex) {
+ return RID();
+ }
+ return (p_srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
+ }
+
+ _FORCE_INLINE_ Size2i texture_2d_get_size(RID p_texture) {
+ if (p_texture.is_null()) {
+ return Size2i();
+ }
+ Texture *tex = texture_owner.getornull(p_texture);
+
+ if (!tex) {
+ return Size2i();
+ }
+ return Size2i(tex->width_2d, tex->height_2d);
+ }
+
+ _FORCE_INLINE_ RID texture_rd_get_default(DefaultRDTexture p_texture) {
+ return default_rd_textures[p_texture];
+ }
+ _FORCE_INLINE_ RID sampler_rd_get_default(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
+ return default_rd_samplers[p_filter][p_repeat];
+ }
+
+ /* SHADER API */
+
+ RID shader_create();
+
+ void shader_set_code(RID p_shader, const String &p_code);
+ String shader_get_code(RID p_shader) const;
+ void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
+
+ void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
+ RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
+ Variant shader_get_param_default(RID p_shader, const StringName &p_param) const;
+ void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function);
+
+ /* COMMON MATERIAL API */
+
+ RID material_create();
+
+ void material_set_shader(RID p_material, RID p_shader);
+
+ void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value);
+ Variant material_get_param(RID p_material, const StringName &p_param) const;
+
+ void material_set_next_pass(RID p_material, RID p_next_material);
+ void material_set_render_priority(RID p_material, int priority);
+
+ bool material_is_animated(RID p_material);
+ bool material_casts_shadows(RID p_material);
+
+ void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance);
+ void material_force_update_textures(RID p_material, ShaderType p_shader_type);
+
+ void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function);
+
+ _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) {
+ Material *material = material_owner.getornull(p_material);
+ if (!material || material->shader_type != p_shader_type) {
+ return nullptr;
+ } else {
+ return material->data;
+ }
+ }
+
+ /* MESH API */
+
+ virtual RID mesh_create();
+
+ /// Return stride
+ virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface);
+
+ virtual int mesh_get_blend_shape_count(RID p_mesh) const;
+
+ virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode);
+ virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
+
+ virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
+
+ virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material);
+ virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
+
+ virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const;
+
+ virtual int mesh_get_surface_count(RID p_mesh) const;
+
+ virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb);
+ virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
+
+ virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID());
+
+ virtual void mesh_clear(RID p_mesh);
+
+ _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, nullptr);
+ r_surface_count = mesh->surface_count;
+ if (r_surface_count == 0) {
+ return nullptr;
+ }
+ if (mesh->material_cache.empty()) {
+ mesh->material_cache.resize(mesh->surface_count);
+ for (uint32_t i = 0; i < r_surface_count; i++) {
+ mesh->material_cache.write[i] = mesh->surfaces[i]->material;
+ }
+ }
+
+ return mesh->material_cache.ptr();
+ }
+
+ _FORCE_INLINE_ RS::PrimitiveType mesh_surface_get_primitive(RID p_mesh, uint32_t p_surface_index) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RS::PRIMITIVE_MAX);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, RS::PRIMITIVE_MAX);
+
+ return mesh->surfaces[p_surface_index]->primitive;
+ }
+
+ _FORCE_INLINE_ void mesh_surface_get_arrays_and_format(RID p_mesh, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RID &r_index_array_rd, RD::VertexFormatID &r_vertex_format) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
+
+ Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+ r_index_array_rd = s->index_array;
+
+ s->version_lock.lock();
+
+ //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
+
+ for (uint32_t i = 0; i < s->version_count; i++) {
+ if (s->versions[i].input_mask != p_input_mask) {
+ continue;
+ }
+ //we have this version, hooray
+ r_vertex_format = s->versions[i].vertex_format;
+ r_vertex_array_rd = s->versions[i].vertex_array;
+ s->version_lock.unlock();
+ return;
+ }
+
+ uint32_t version = s->version_count; //gets added at the end
+
+ _mesh_surface_generate_version_for_input_mask(s, p_input_mask);
+
+ r_vertex_format = s->versions[version].vertex_format;
+ r_vertex_array_rd = s->versions[version].vertex_array;
+
+ s->version_lock.unlock();
+ }
+
+ _FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) {
+ ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID());
+ return mesh_default_rd_buffers[p_buffer];
+ }
+
+ _FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+ if (s->render_pass != p_render_pass) {
+ (*r_index)++;
+ s->render_pass = p_render_pass;
+ s->render_index = *r_index;
+ }
+
+ return s->render_index;
+ }
+
+ _FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+ if (s->multimesh_render_pass != p_render_pass) {
+ (*r_index)++;
+ s->multimesh_render_pass = p_render_pass;
+ s->multimesh_render_index = *r_index;
+ }
+
+ return s->multimesh_render_index;
+ }
+
+ /* MULTIMESH API */
+
+ RID multimesh_create();
+
+ 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);
+ int multimesh_get_instance_count(RID p_multimesh) const;
+
+ void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
+ void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
+ void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
+ void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
+ void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
+
+ RID multimesh_get_mesh(RID p_multimesh) const;
+
+ Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
+ Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
+ Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
+ Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
+
+ void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
+ Vector<float> multimesh_get_buffer(RID p_multimesh) const;
+
+ void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
+ int multimesh_get_visible_instances(RID p_multimesh) const;
+
+ AABB multimesh_get_aabb(RID p_multimesh) const;
+
+ _FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ return multimesh->xform_format;
+ }
+
+ _FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ return multimesh->uses_colors;
+ }
+
+ _FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ return multimesh->uses_custom_data;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ if (multimesh->visible_instances >= 0) {
+ return multimesh->visible_instances;
+ }
+ return multimesh->instances;
+ }
+
+ _FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ if (!multimesh->uniform_set_3d.is_valid()) {
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(multimesh->buffer);
+ uniforms.push_back(u);
+ multimesh->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+ }
+
+ return multimesh->uniform_set_3d;
+ }
+
+ /* 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(); }
+
+ /* SKELETON API */
+
+ RID skeleton_create();
+ void skeleton_allocate(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;
+ void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform);
+ Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const;
+ void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
+ Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
+
+ _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, RID());
+ ERR_FAIL_COND_V(skeleton->size == 0, RID());
+ if (skeleton->use_2d) {
+ return RID();
+ }
+ if (!skeleton->uniform_set_3d.is_valid()) {
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(skeleton->buffer);
+ uniforms.push_back(u);
+ skeleton->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+ }
+
+ return skeleton->uniform_set_3d;
+ }
+ /* Light API */
+
+ RID light_create(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); }
+
+ 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);
+ void light_set_shadow(RID p_light, bool p_enabled);
+ void light_set_shadow_color(RID p_light, const Color &p_color);
+ void light_set_projector(RID p_light, RID p_texture);
+ void light_set_negative(RID p_light, bool p_enable);
+ void light_set_cull_mask(RID p_light, uint32_t p_mask);
+ void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled);
+ void light_set_use_gi(RID p_light, bool p_enabled);
+
+ void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode);
+
+ void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode);
+ void light_directional_set_blend_splits(RID p_light, bool p_enable);
+ bool light_directional_get_blend_splits(RID p_light) const;
+ void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode);
+ RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
+
+ RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
+ RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
+
+ _FORCE_INLINE_ RS::LightType light_get_type(RID p_light) const {
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light->type;
+ }
+ AABB light_get_aabb(RID p_light) const;
+
+ _FORCE_INLINE_ float light_get_param(RID p_light, RS::LightParam p_param) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->param[p_param];
+ }
+
+ _FORCE_INLINE_ RID light_get_projector(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RID());
+
+ return light->projector;
+ }
+
+ _FORCE_INLINE_ Color light_get_color(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, Color());
+
+ return light->color;
+ }
+
+ _FORCE_INLINE_ Color light_get_shadow_color(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, Color());
+
+ return light->shadow_color;
+ }
+
+ _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->cull_mask;
+ }
+
+ _FORCE_INLINE_ bool light_has_shadow(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light->shadow;
+ }
+
+ _FORCE_INLINE_ bool light_is_negative(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+
+ return light->negative;
+ }
+
+ _FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const {
+
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0.0);
+
+ return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
+ }
+
+ bool light_get_use_gi(RID p_light);
+ uint64_t light_get_version(RID p_light) const;
+
+ /* PROBE API */
+
+ RID reflection_probe_create();
+
+ void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode);
+ void reflection_probe_set_intensity(RID p_probe, float p_intensity);
+ void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient);
+ void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy);
+ void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib);
+ void reflection_probe_set_max_distance(RID p_probe, float p_distance);
+ void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents);
+ void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset);
+ void reflection_probe_set_as_interior(RID p_probe, bool p_enable);
+ void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable);
+ void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable);
+ void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
+ void reflection_probe_set_resolution(RID p_probe, int p_resolution);
+
+ AABB reflection_probe_get_aabb(RID p_probe) const;
+ RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
+ uint32_t reflection_probe_get_cull_mask(RID p_probe) const;
+ Vector3 reflection_probe_get_extents(RID p_probe) const;
+ Vector3 reflection_probe_get_origin_offset(RID p_probe) const;
+ float reflection_probe_get_origin_max_distance(RID p_probe) const;
+ int reflection_probe_get_resolution(RID p_probe) const;
+ bool reflection_probe_renders_shadows(RID p_probe) const;
+
+ float reflection_probe_get_intensity(RID p_probe) const;
+ bool reflection_probe_is_interior(RID p_probe) const;
+ bool reflection_probe_is_box_projection(RID p_probe) const;
+ Color reflection_probe_get_interior_ambient(RID p_probe) const;
+ float reflection_probe_get_interior_ambient_energy(RID p_probe) const;
+ float reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const;
+
+ void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance);
+ void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance);
+
+ /* DECAL API */
+
+ virtual RID decal_create();
+ 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);
+ virtual void decal_set_albedo_mix(RID p_decal, float p_mix);
+ virtual void decal_set_modulate(RID p_decal, const Color &p_modulate);
+ virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers);
+ virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length);
+ virtual void decal_set_fade(RID p_decal, float p_above, float p_below);
+ virtual void decal_set_normal_fade(RID p_decal, float p_fade);
+
+ _FORCE_INLINE_ Vector3 decal_get_extents(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->extents;
+ }
+
+ _FORCE_INLINE_ RID decal_get_texture(RID p_decal, RS::DecalTexture p_texture) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->textures[p_texture];
+ }
+
+ _FORCE_INLINE_ Color decal_get_modulate(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->modulate;
+ }
+
+ _FORCE_INLINE_ float decal_get_emission_energy(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->emission_energy;
+ }
+
+ _FORCE_INLINE_ float decal_get_albedo_mix(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->albedo_mix;
+ }
+
+ _FORCE_INLINE_ uint32_t decal_get_cull_mask(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->cull_mask;
+ }
+
+ _FORCE_INLINE_ float decal_get_upper_fade(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->upper_fade;
+ }
+
+ _FORCE_INLINE_ float decal_get_lower_fade(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->lower_fade;
+ }
+
+ _FORCE_INLINE_ float decal_get_normal_fade(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->normal_fade;
+ }
+
+ _FORCE_INLINE_ bool decal_is_distance_fade_enabled(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->distance_fade;
+ }
+
+ _FORCE_INLINE_ float decal_get_distance_fade_begin(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->distance_fade_begin;
+ }
+
+ _FORCE_INLINE_ float decal_get_distance_fade_length(RID p_decal) {
+ const Decal *decal = decal_owner.getornull(p_decal);
+ return decal->distance_fade_length;
+ }
+
+ virtual AABB decal_get_aabb(RID p_decal) const;
+
+ /* GI PROBE API */
+
+ RID gi_probe_create();
+
+ 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);
+
+ AABB gi_probe_get_bounds(RID p_gi_probe) const;
+ Vector3i gi_probe_get_octree_size(RID p_gi_probe) const;
+ Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const;
+ Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const;
+ Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const;
+
+ Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const;
+ Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const;
+
+ void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range);
+ float gi_probe_get_dynamic_range(RID p_gi_probe) const;
+
+ void gi_probe_set_propagation(RID p_gi_probe, float p_range);
+ float gi_probe_get_propagation(RID p_gi_probe) const;
+
+ void gi_probe_set_energy(RID p_gi_probe, float p_energy);
+ float gi_probe_get_energy(RID p_gi_probe) const;
+
+ void gi_probe_set_ao(RID p_gi_probe, float p_ao);
+ float gi_probe_get_ao(RID p_gi_probe) const;
+
+ void gi_probe_set_ao_size(RID p_gi_probe, float p_strength);
+ float gi_probe_get_ao_size(RID p_gi_probe) const;
+
+ void gi_probe_set_bias(RID p_gi_probe, float p_bias);
+ float gi_probe_get_bias(RID p_gi_probe) const;
+
+ void gi_probe_set_normal_bias(RID p_gi_probe, float p_range);
+ float gi_probe_get_normal_bias(RID p_gi_probe) const;
+
+ void gi_probe_set_interior(RID p_gi_probe, bool p_enable);
+ bool gi_probe_is_interior(RID p_gi_probe) const;
+
+ void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable);
+ bool gi_probe_is_using_two_bounces(RID p_gi_probe) const;
+
+ void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength);
+ float gi_probe_get_anisotropy_strength(RID p_gi_probe) const;
+
+ uint32_t gi_probe_get_version(RID p_probe);
+ uint32_t gi_probe_get_data_version(RID p_probe);
+
+ RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
+ RID gi_probe_get_data_buffer(RID p_gi_probe) const;
+
+ RID gi_probe_get_sdf_texture(RID p_gi_probe);
+
+ /* LIGHTMAP CAPTURE */
+
+ void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
+ AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); }
+ void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) {}
+ RID lightmap_capture_create() {
+ return RID();
+ }
+ Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const {
+ return Vector<uint8_t>();
+ }
+ void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {}
+ Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const { return Transform(); }
+ void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) {}
+ int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { return 0; }
+ void lightmap_capture_set_energy(RID p_capture, float p_energy) {}
+ float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
+ const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const {
+ return nullptr;
+ }
+
+ /* PARTICLES */
+
+ RID particles_create() { return RID(); }
+
+ void particles_set_emitting(RID p_particles, bool p_emitting) {}
+ void particles_set_amount(RID p_particles, int p_amount) {}
+ void particles_set_lifetime(RID p_particles, float p_lifetime) {}
+ void particles_set_one_shot(RID p_particles, bool p_one_shot) {}
+ void particles_set_pre_process_time(RID p_particles, float p_time) {}
+ void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {}
+ void particles_set_randomness_ratio(RID p_particles, float p_ratio) {}
+ void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {}
+ void particles_set_speed_scale(RID p_particles, float p_scale) {}
+ 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_fractional_delta(RID p_particles, bool p_enable) {}
+ void particles_restart(RID p_particles) {}
+
+ void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {}
+
+ void particles_set_draw_passes(RID p_particles, int p_count) {}
+ void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {}
+
+ void particles_request_process(RID p_particles) {}
+ AABB particles_get_current_aabb(RID p_particles) { return AABB(); }
+ AABB particles_get_aabb(RID p_particles) const { return AABB(); }
+
+ void particles_set_emission_transform(RID p_particles, const Transform &p_transform) {}
+
+ bool particles_get_emitting(RID p_particles) { return false; }
+ int particles_get_draw_passes(RID p_particles) const { return 0; }
+ RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); }
+
+ virtual bool particles_is_inactive(RID p_particles) const { return false; }
+
+ /* RENDER TARGET API */
+
+ RID render_target_create();
+ void render_target_set_position(RID p_render_target, int p_x, int p_y);
+ void render_target_set_size(RID p_render_target, int p_width, int p_height);
+ RID render_target_get_texture(RID p_render_target);
+ void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
+ void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
+ bool render_target_was_used(RID p_render_target);
+ void render_target_set_as_unused(RID p_render_target);
+ void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region);
+ RID render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader);
+
+ virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color);
+ virtual bool render_target_is_clear_requested(RID p_render_target);
+ virtual Color render_target_get_clear_request_color(RID p_render_target);
+ virtual void render_target_disable_clear_request(RID p_render_target);
+ virtual void render_target_do_clear_request(RID p_render_target);
+
+ Size2 render_target_get_size(RID p_render_target);
+ RID render_target_get_rd_framebuffer(RID p_render_target);
+ RID render_target_get_rd_texture(RID p_render_target);
+
+ RS::InstanceType get_base_type(RID p_rid) const;
+
+ bool free(RID p_rid);
+
+ bool has_os_feature(const String &p_feature) const;
+
+ void update_dirty_resources();
+
+ void set_debug_generate_wireframes(bool p_generate) {}
+
+ void render_info_begin_capture() {}
+ 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; }
+ String get_video_adapter_name() const { return String(); }
+ String get_video_adapter_vendor() const { return String(); }
+
+ virtual void capture_timestamps_begin();
+ virtual void capture_timestamp(const String &p_name);
+ virtual uint32_t get_captured_timestamps_count() const;
+ virtual uint64_t get_captured_timestamps_frame() const;
+ virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const;
+ virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
+ virtual String get_captured_timestamp_name(uint32_t p_index) const;
+
+ static RasterizerStorage *base_singleton;
+
+ RasterizerEffectsRD *get_effects();
+
+ RasterizerStorageRD();
+ ~RasterizerStorageRD();
+};
+
+#endif // RASTERIZER_STORAGE_RD_H
diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp
new file mode 100644
index 0000000000..2bfdb7fffe
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp
@@ -0,0 +1,97 @@
+/*************************************************************************/
+/* render_pipeline_vertex_format_cache_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_pipeline_vertex_format_cache_rd.h"
+#include "core/os/memory.h"
+
+RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id) {
+
+ RD::PipelineMultisampleState multisample_state_version = multisample_state;
+ multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id);
+
+ RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, rasterization_state, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags);
+ ERR_FAIL_COND_V(pipeline.is_null(), RID());
+ versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1));
+ versions[version_count].framebuffer_id = p_framebuffer_format_id;
+ versions[version_count].vertex_id = p_vertex_format_id;
+ versions[version_count].pipeline = pipeline;
+ version_count++;
+ return pipeline;
+}
+
+void RenderPipelineVertexFormatCacheRD::_clear() {
+
+ if (versions) {
+ for (uint32_t i = 0; i < version_count; i++) {
+ //shader may be gone, so this may not be valid
+ if (RD::get_singleton()->render_pipeline_is_valid(versions[i].pipeline)) {
+ RD::get_singleton()->free(versions[i].pipeline);
+ }
+ }
+ version_count = 0;
+ memfree(versions);
+ versions = nullptr;
+ }
+}
+
+void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) {
+ ERR_FAIL_COND(p_shader.is_null());
+ _clear();
+ shader = p_shader;
+ input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(p_shader);
+ render_primitive = p_primitive;
+ rasterization_state = p_rasterization_state;
+ multisample_state = p_multisample;
+ depth_stencil_state = p_depth_stencil_state;
+ blend_state = p_blend_state;
+ dynamic_state_flags = p_dynamic_state_flags;
+}
+
+void RenderPipelineVertexFormatCacheRD::update_shader(RID p_shader) {
+ ERR_FAIL_COND(p_shader.is_null());
+ _clear();
+ setup(p_shader, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags);
+}
+
+void RenderPipelineVertexFormatCacheRD::clear() {
+ _clear();
+ shader = RID(); //clear shader
+ input_mask = 0;
+}
+
+RenderPipelineVertexFormatCacheRD::RenderPipelineVertexFormatCacheRD() {
+ version_count = 0;
+ versions = nullptr;
+ input_mask = 0;
+}
+
+RenderPipelineVertexFormatCacheRD::~RenderPipelineVertexFormatCacheRD() {
+ _clear();
+}
diff --git a/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h
new file mode 100644
index 0000000000..ecb1b42b06
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* render_pipeline_vertex_format_cache_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 RENDER_PIPELINE_CACHE_RD_H
+#define RENDER_PIPELINE_CACHE_RD_H
+
+#include "core/spin_lock.h"
+#include "servers/rendering/rendering_device.h"
+
+class RenderPipelineVertexFormatCacheRD {
+
+ SpinLock spin_lock;
+
+ RID shader;
+ uint32_t input_mask;
+
+ RD::RenderPrimitive render_primitive;
+ RD::PipelineRasterizationState rasterization_state;
+ RD::PipelineMultisampleState multisample_state;
+ RD::PipelineDepthStencilState depth_stencil_state;
+ RD::PipelineColorBlendState blend_state;
+ int dynamic_state_flags;
+
+ struct Version {
+ RD::VertexFormatID vertex_id;
+ RD::FramebufferFormatID framebuffer_id;
+ RID pipeline;
+ };
+
+ Version *versions;
+ uint32_t version_count;
+
+ RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id);
+
+ void _clear();
+
+public:
+ void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0);
+ void update_shader(RID p_shader);
+
+ _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V_MSG(shader.is_null(), RID(),
+ "Attempted to use an unused shader variant (shader is null),");
+#endif
+
+ spin_lock.lock();
+ RID result;
+ for (uint32_t i = 0; i < version_count; i++) {
+ if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id) {
+ result = versions[i].pipeline;
+ spin_lock.unlock();
+ return result;
+ }
+ }
+ result = _generate_version(p_vertex_format_id, p_framebuffer_format_id);
+ spin_lock.unlock();
+ return result;
+ }
+
+ _FORCE_INLINE_ uint32_t get_vertex_input_mask() const {
+ return input_mask;
+ }
+ void clear();
+ RenderPipelineVertexFormatCacheRD();
+ ~RenderPipelineVertexFormatCacheRD();
+};
+
+#endif // RENDER_PIPELINE_CACHE_RD_H
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
new file mode 100644
index 0000000000..4a0b4f02b1
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
@@ -0,0 +1,1243 @@
+/*************************************************************************/
+/* shader_compiler_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "shader_compiler_rd.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+
+#define SL ShaderLanguage
+
+static String _mktab(int p_level) {
+
+ String tb;
+ for (int i = 0; i < p_level; i++) {
+ tb += "\t";
+ }
+
+ return tb;
+}
+
+static String _typestr(SL::DataType p_type) {
+
+ String type = ShaderLanguage::get_datatype_name(p_type);
+ if (ShaderLanguage::is_sampler_type(p_type)) {
+ type = type.replace("sampler", "texture"); //we use textures instead of samplers
+ }
+ return type;
+}
+
+static int _get_datatype_size(SL::DataType p_type) {
+
+ switch (p_type) {
+
+ case SL::TYPE_VOID: return 0;
+ case SL::TYPE_BOOL: return 4;
+ case SL::TYPE_BVEC2: return 8;
+ case SL::TYPE_BVEC3: return 12;
+ case SL::TYPE_BVEC4: return 16;
+ case SL::TYPE_INT: return 4;
+ case SL::TYPE_IVEC2: return 8;
+ case SL::TYPE_IVEC3: return 12;
+ case SL::TYPE_IVEC4: return 16;
+ case SL::TYPE_UINT: return 4;
+ case SL::TYPE_UVEC2: return 8;
+ case SL::TYPE_UVEC3: return 12;
+ case SL::TYPE_UVEC4: return 16;
+ case SL::TYPE_FLOAT: return 4;
+ case SL::TYPE_VEC2: return 8;
+ case SL::TYPE_VEC3: return 12;
+ case SL::TYPE_VEC4: return 16;
+ case SL::TYPE_MAT2:
+ return 32; //4 * 4 + 4 * 4
+ case SL::TYPE_MAT3:
+ return 48; // 4 * 4 + 4 * 4 + 4 * 4
+ case SL::TYPE_MAT4: return 64;
+ case SL::TYPE_SAMPLER2D: return 16;
+ case SL::TYPE_ISAMPLER2D: return 16;
+ case SL::TYPE_USAMPLER2D: return 16;
+ case SL::TYPE_SAMPLER2DARRAY: return 16;
+ case SL::TYPE_ISAMPLER2DARRAY: return 16;
+ case SL::TYPE_USAMPLER2DARRAY: return 16;
+ case SL::TYPE_SAMPLER3D: return 16;
+ case SL::TYPE_ISAMPLER3D: return 16;
+ case SL::TYPE_USAMPLER3D: return 16;
+ case SL::TYPE_SAMPLERCUBE: return 16;
+ case SL::TYPE_STRUCT: return 0;
+ }
+
+ ERR_FAIL_V(0);
+}
+
+static int _get_datatype_alignment(SL::DataType p_type) {
+
+ switch (p_type) {
+
+ case SL::TYPE_VOID: return 0;
+ case SL::TYPE_BOOL: return 4;
+ case SL::TYPE_BVEC2: return 8;
+ case SL::TYPE_BVEC3: return 16;
+ case SL::TYPE_BVEC4: return 16;
+ case SL::TYPE_INT: return 4;
+ case SL::TYPE_IVEC2: return 8;
+ case SL::TYPE_IVEC3: return 16;
+ case SL::TYPE_IVEC4: return 16;
+ case SL::TYPE_UINT: return 4;
+ case SL::TYPE_UVEC2: return 8;
+ case SL::TYPE_UVEC3: return 16;
+ case SL::TYPE_UVEC4: return 16;
+ case SL::TYPE_FLOAT: return 4;
+ case SL::TYPE_VEC2: return 8;
+ case SL::TYPE_VEC3: return 16;
+ case SL::TYPE_VEC4: return 16;
+ case SL::TYPE_MAT2: return 16;
+ case SL::TYPE_MAT3: return 16;
+ case SL::TYPE_MAT4: return 16;
+ case SL::TYPE_SAMPLER2D: return 16;
+ case SL::TYPE_ISAMPLER2D: return 16;
+ case SL::TYPE_USAMPLER2D: return 16;
+ case SL::TYPE_SAMPLER2DARRAY: return 16;
+ case SL::TYPE_ISAMPLER2DARRAY: return 16;
+ case SL::TYPE_USAMPLER2DARRAY: return 16;
+ case SL::TYPE_SAMPLER3D: return 16;
+ case SL::TYPE_ISAMPLER3D: return 16;
+ case SL::TYPE_USAMPLER3D: return 16;
+ case SL::TYPE_SAMPLERCUBE: return 16;
+ case SL::TYPE_STRUCT: return 0;
+ }
+
+ ERR_FAIL_V(0);
+}
+static String _interpstr(SL::DataInterpolation p_interp) {
+
+ switch (p_interp) {
+ case SL::INTERPOLATION_FLAT: return "flat ";
+ case SL::INTERPOLATION_SMOOTH: return "";
+ }
+ return "";
+}
+
+static String _prestr(SL::DataPrecision p_pres) {
+
+ switch (p_pres) {
+ case SL::PRECISION_LOWP: return "lowp ";
+ case SL::PRECISION_MEDIUMP: return "mediump ";
+ case SL::PRECISION_HIGHP: return "highp ";
+ case SL::PRECISION_DEFAULT: return "";
+ }
+ return "";
+}
+
+static String _qualstr(SL::ArgumentQualifier p_qual) {
+
+ switch (p_qual) {
+ case SL::ARGUMENT_QUALIFIER_IN: return "";
+ case SL::ARGUMENT_QUALIFIER_OUT: return "out ";
+ case SL::ARGUMENT_QUALIFIER_INOUT: return "inout ";
+ }
+ return "";
+}
+
+static String _opstr(SL::Operator p_op) {
+
+ return SL::get_operator_text(p_op);
+}
+
+static String _mkid(const String &p_id) {
+
+ String id = "m_" + p_id.replace("__", "_dus_");
+ return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
+}
+
+static String f2sp0(float p_float) {
+
+ String num = rtoss(p_float);
+ if (num.find(".") == -1 && num.find("e") == -1) {
+ num += ".0";
+ }
+ return num;
+}
+
+static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
+
+ switch (p_type) {
+ case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false";
+ case SL::TYPE_BVEC2:
+ case SL::TYPE_BVEC3:
+ case SL::TYPE_BVEC4: {
+
+ String text = "bvec" + itos(p_type - SL::TYPE_BOOL + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += p_values[i].boolean ? "true" : "false";
+ }
+ text += ")";
+ return text;
+ }
+
+ case SL::TYPE_INT: return itos(p_values[0].sint);
+ case SL::TYPE_IVEC2:
+ case SL::TYPE_IVEC3:
+ case SL::TYPE_IVEC4: {
+
+ String text = "ivec" + itos(p_type - SL::TYPE_INT + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += itos(p_values[i].sint);
+ }
+ text += ")";
+ return text;
+
+ } break;
+ case SL::TYPE_UINT: return itos(p_values[0].uint) + "u";
+ case SL::TYPE_UVEC2:
+ case SL::TYPE_UVEC3:
+ case SL::TYPE_UVEC4: {
+
+ String text = "uvec" + itos(p_type - SL::TYPE_UINT + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += itos(p_values[i].uint) + "u";
+ }
+ text += ")";
+ return text;
+ } break;
+ case SL::TYPE_FLOAT: return f2sp0(p_values[0].real);
+ case SL::TYPE_VEC2:
+ case SL::TYPE_VEC3:
+ case SL::TYPE_VEC4: {
+
+ String text = "vec" + itos(p_type - SL::TYPE_FLOAT + 1) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += f2sp0(p_values[i].real);
+ }
+ text += ")";
+ return text;
+
+ } break;
+ case SL::TYPE_MAT2:
+ case SL::TYPE_MAT3:
+ case SL::TYPE_MAT4: {
+
+ String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "(";
+ for (int i = 0; i < p_values.size(); i++) {
+ if (i > 0)
+ text += ",";
+
+ text += f2sp0(p_values[i].real);
+ }
+ text += ")";
+ return text;
+
+ } break;
+ default: ERR_FAIL_V(String());
+ }
+}
+
+String ShaderCompilerRD::_get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat) {
+ if (p_filter == ShaderLanguage::FILTER_DEFAULT) {
+ ERR_FAIL_COND_V(actions.default_filter == ShaderLanguage::FILTER_DEFAULT, String());
+ p_filter = actions.default_filter;
+ }
+ if (p_repeat == ShaderLanguage::REPEAT_DEFAULT) {
+ ERR_FAIL_COND_V(actions.default_repeat == ShaderLanguage::REPEAT_DEFAULT, String());
+ p_repeat = actions.default_repeat;
+ }
+ return actions.sampler_array_name + "[" + itos(p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)) + "]";
+}
+
+void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) {
+
+ int fidx = -1;
+
+ for (int i = 0; i < p_node->functions.size(); i++) {
+ if (p_node->functions[i].name == p_for_func) {
+ fidx = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(fidx == -1);
+
+ for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
+
+ if (added.has(E->get())) {
+ continue; //was added already
+ }
+
+ _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
+
+ SL::FunctionNode *fnode = nullptr;
+
+ for (int i = 0; i < p_node->functions.size(); i++) {
+ if (p_node->functions[i].name == E->get()) {
+ fnode = p_node->functions[i].function;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(!fnode);
+
+ r_to_add += "\n";
+
+ String header;
+ if (fnode->return_type == SL::TYPE_STRUCT) {
+ header = _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "(";
+ } else {
+ header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
+ }
+ for (int i = 0; i < fnode->arguments.size(); i++) {
+
+ if (i > 0)
+ header += ", ";
+ if (fnode->arguments[i].type == SL::TYPE_STRUCT) {
+ header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name);
+ } else {
+ header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
+ }
+ }
+
+ header += ")\n";
+ r_to_add += header;
+ r_to_add += p_func_code[E->get()];
+
+ added.insert(E->get());
+ }
+}
+
+String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) {
+
+ String code;
+
+ switch (p_node->type) {
+
+ case SL::Node::TYPE_SHADER: {
+
+ SL::ShaderNode *pnode = (SL::ShaderNode *)p_node;
+
+ for (int i = 0; i < pnode->render_modes.size(); i++) {
+
+ if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) {
+
+ r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]]);
+ used_rmode_defines.insert(pnode->render_modes[i]);
+ }
+
+ if (p_actions.render_mode_flags.has(pnode->render_modes[i])) {
+ *p_actions.render_mode_flags[pnode->render_modes[i]] = true;
+ }
+
+ if (p_actions.render_mode_values.has(pnode->render_modes[i])) {
+ Pair<int *, int> &p = p_actions.render_mode_values[pnode->render_modes[i]];
+ *p.first = p.second;
+ }
+ }
+
+ // structs
+
+ for (int i = 0; i < pnode->vstructs.size(); i++) {
+
+ SL::StructNode *st = pnode->vstructs[i].shader_struct;
+ String struct_code;
+
+ struct_code += "struct ";
+ struct_code += _mkid(pnode->vstructs[i].name);
+ struct_code += " ";
+ struct_code += "{\n";
+ for (int j = 0; j < st->members.size(); j++) {
+ SL::MemberNode *m = st->members[j];
+ if (m->datatype == SL::TYPE_STRUCT) {
+ struct_code += _mkid(m->struct_name);
+ } else {
+ struct_code += _prestr(m->precision);
+ struct_code += _typestr(m->datatype);
+ }
+ struct_code += " ";
+ struct_code += m->name;
+ if (m->array_size > 0) {
+ struct_code += "[";
+ struct_code += itos(m->array_size);
+ struct_code += "]";
+ }
+ struct_code += ";\n";
+ }
+ struct_code += "}";
+ struct_code += ";\n";
+
+ r_gen_code.vertex_global += struct_code;
+ r_gen_code.fragment_global += struct_code;
+ }
+
+ int max_texture_uniforms = 0;
+ int max_uniforms = 0;
+
+ for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+ if (SL::is_sampler_type(E->get().type))
+ max_texture_uniforms++;
+ else
+ max_uniforms++;
+ }
+
+ r_gen_code.texture_uniforms.resize(max_texture_uniforms);
+
+ Vector<int> uniform_sizes;
+ Vector<int> uniform_alignments;
+ Vector<StringName> uniform_defines;
+ uniform_sizes.resize(max_uniforms);
+ uniform_alignments.resize(max_uniforms);
+ uniform_defines.resize(max_uniforms);
+ bool uses_uniforms = false;
+
+ for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
+
+ String ucode;
+
+ if (SL::is_sampler_type(E->get().type)) {
+ ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
+ }
+
+ ucode += _prestr(E->get().precision);
+ ucode += _typestr(E->get().type);
+ 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;
+
+ GeneratedCode::Texture texture;
+ texture.name = E->key();
+ texture.hint = E->get().hint;
+ texture.type = E->get().type;
+ texture.filter = E->get().filter;
+ texture.repeat = E->get().repeat;
+
+ 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;
+ uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
+ uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
+ }
+
+ p_actions.uniforms->insert(E->key(), E->get());
+ }
+
+ for (int i = 0; i < max_uniforms; i++) {
+ r_gen_code.uniforms += uniform_defines[i];
+ }
+
+#if 1
+ // add up
+ int offset = 0;
+ for (int i = 0; i < uniform_sizes.size(); i++) {
+
+ int align = offset % uniform_alignments[i];
+
+ if (align != 0) {
+ offset += uniform_alignments[i] - align;
+ }
+
+ r_gen_code.uniform_offsets.push_back(offset);
+
+ offset += uniform_sizes[i];
+ }
+
+ r_gen_code.uniform_total_size = offset;
+
+ if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16
+ r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
+ }
+#else
+ // add up
+ for (int i = 0; i < uniform_sizes.size(); i++) {
+
+ if (i > 0) {
+
+ int align = uniform_sizes[i - 1] % uniform_alignments[i];
+ if (align != 0) {
+ uniform_sizes[i - 1] += uniform_alignments[i] - align;
+ }
+
+ uniform_sizes[i] = uniform_sizes[i] + uniform_sizes[i - 1];
+ }
+ }
+ //offset
+ r_gen_code.uniform_offsets.resize(uniform_sizes.size());
+ for (int i = 0; i < uniform_sizes.size(); i++) {
+
+ if (i > 0)
+ r_gen_code.uniform_offsets[i] = uniform_sizes[i - 1];
+ else
+ r_gen_code.uniform_offsets[i] = 0;
+ }
+ /*
+ for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
+
+ if (SL::is_sampler_type(E->get().type)) {
+ continue;
+ }
+
+ }
+
+*/
+ if (uniform_sizes.size()) {
+ r_gen_code.uniform_total_size = uniform_sizes[uniform_sizes.size() - 1];
+ } else {
+ r_gen_code.uniform_total_size = 0;
+ }
+#endif
+
+ uint32_t index = p_default_actions.base_varying_index;
+
+ for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
+
+ String vcode;
+ String interp_mode = _interpstr(E->get().interpolation);
+ vcode += _prestr(E->get().precision);
+ vcode += _typestr(E->get().type);
+ vcode += " " + _mkid(E->key());
+ if (E->get().array_size > 0) {
+ vcode += "[";
+ vcode += itos(E->get().array_size);
+ 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;
+ index++;
+ }
+
+ for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) {
+ String gcode;
+ gcode += "const ";
+ gcode += _prestr(E->get().precision);
+ if (E->get().type == SL::TYPE_STRUCT) {
+ gcode += _mkid(E->get().type_str);
+ } else {
+ gcode += _typestr(E->get().type);
+ }
+ gcode += " " + _mkid(E->key());
+ gcode += "=";
+ gcode += _dump_node_code(E->get().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;
+ }
+
+ Map<StringName, String> function_code;
+
+ //code for functions
+ for (int i = 0; i < pnode->functions.size(); i++) {
+ SL::FunctionNode *fnode = pnode->functions[i].function;
+ function = fnode;
+ current_func_name = fnode->name;
+ function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ function = nullptr;
+ }
+
+ //place functions in actual code
+
+ Set<StringName> added_vtx;
+ Set<StringName> added_fragment; //share for light
+
+ for (int i = 0; i < pnode->functions.size(); i++) {
+
+ SL::FunctionNode *fnode = pnode->functions[i].function;
+
+ function = fnode;
+
+ 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];
+ }
+ function = nullptr;
+ }
+
+ //code+=dump_node_code(pnode->body,p_level);
+ } break;
+ case SL::Node::TYPE_STRUCT: {
+
+ } break;
+ case SL::Node::TYPE_FUNCTION: {
+
+ } break;
+ case SL::Node::TYPE_BLOCK: {
+ SL::BlockNode *bnode = (SL::BlockNode *)p_node;
+
+ //variables
+ if (!bnode->single_statement) {
+ code += _mktab(p_level - 1) + "{\n";
+ }
+
+ for (int i = 0; i < bnode->statements.size(); i++) {
+
+ String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+ if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) {
+ code += scode; //use directly
+ } else {
+ code += _mktab(p_level) + scode + ";\n";
+ }
+ }
+ if (!bnode->single_statement) {
+ code += _mktab(p_level - 1) + "}\n";
+ }
+
+ } break;
+ case SL::Node::TYPE_VARIABLE_DECLARATION: {
+ SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node;
+
+ String declaration;
+ if (vdnode->is_const) {
+ declaration += "const ";
+ }
+ if (vdnode->datatype == SL::TYPE_STRUCT) {
+ declaration += _mkid(vdnode->struct_name);
+ } else {
+ declaration += _prestr(vdnode->precision) + _typestr(vdnode->datatype);
+ }
+ for (int i = 0; i < vdnode->declarations.size(); i++) {
+ if (i > 0) {
+ declaration += ",";
+ } else {
+ declaration += " ";
+ }
+ declaration += _mkid(vdnode->declarations[i].name);
+ if (vdnode->declarations[i].initializer) {
+ declaration += "=";
+ declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ }
+ }
+
+ code += declaration;
+ } break;
+ case SL::Node::TYPE_VARIABLE: {
+ SL::VariableNode *vnode = (SL::VariableNode *)p_node;
+
+ if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) {
+ *p_actions.write_flag_pointers[vnode->name] = true;
+ }
+
+ if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) {
+ String define = p_default_actions.usage_defines[vnode->name];
+ if (define.begins_with("@")) {
+ define = p_default_actions.usage_defines[define.substr(1, define.length())];
+ }
+ r_gen_code.defines.push_back(define);
+ used_name_defines.insert(vnode->name);
+ }
+
+ if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) {
+ *p_actions.usage_flag_pointers[vnode->name] = true;
+ used_flag_pointers.insert(vnode->name);
+ }
+
+ if (p_default_actions.renames.has(vnode->name))
+ code = p_default_actions.renames[vnode->name];
+ else {
+ code = _mkid(vnode->name);
+ if (actions.base_uniform_string != String() && shader->uniforms.has(vnode->name) && shader->uniforms[vnode->name].texture_order < 0) {
+ code = actions.base_uniform_string + code;
+ }
+ }
+
+ if (vnode->name == time_name) {
+ if (current_func_name == vertex_name) {
+ r_gen_code.uses_vertex_time = true;
+ }
+ if (current_func_name == fragment_name || current_func_name == light_name) {
+ r_gen_code.uses_fragment_time = true;
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_ARRAY_CONSTRUCT: {
+ SL::ArrayConstructNode *acnode = (SL::ArrayConstructNode *)p_node;
+ int sz = acnode->initializer.size();
+ if (acnode->datatype == SL::TYPE_STRUCT) {
+ code += _mkid(acnode->struct_name);
+ } else {
+ code += _typestr(acnode->datatype);
+ }
+ code += "[";
+ code += itos(acnode->initializer.size());
+ code += "]";
+ code += "(";
+ for (int i = 0; i < sz; i++) {
+ code += _dump_node_code(acnode->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (i != sz - 1) {
+ code += ", ";
+ }
+ }
+ code += ")";
+ } break;
+ case SL::Node::TYPE_ARRAY_DECLARATION: {
+
+ SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node;
+ String declaration;
+ if (adnode->is_const) {
+ declaration += "const ";
+ }
+ if (adnode->datatype == SL::TYPE_STRUCT) {
+ declaration += _mkid(adnode->struct_name);
+ } else {
+ declaration = _prestr(adnode->precision) + _typestr(adnode->datatype);
+ }
+ for (int i = 0; i < adnode->declarations.size(); i++) {
+ if (i > 0) {
+ declaration += ",";
+ } else {
+ declaration += " ";
+ }
+ declaration += _mkid(adnode->declarations[i].name);
+ declaration += "[";
+ declaration += itos(adnode->declarations[i].size);
+ declaration += "]";
+ int sz = adnode->declarations[i].initializer.size();
+ if (sz > 0) {
+ declaration += "=";
+ if (adnode->datatype == SL::TYPE_STRUCT) {
+ declaration += _mkid(adnode->struct_name);
+ } else {
+ declaration += _typestr(adnode->datatype);
+ }
+ declaration += "[";
+ declaration += itos(sz);
+ declaration += "]";
+ declaration += "(";
+ for (int j = 0; j < sz; j++) {
+ declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (j != sz - 1) {
+ declaration += ", ";
+ }
+ }
+ declaration += ")";
+ }
+ }
+
+ code += declaration;
+ } break;
+ case SL::Node::TYPE_ARRAY: {
+ SL::ArrayNode *anode = (SL::ArrayNode *)p_node;
+
+ if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) {
+ *p_actions.write_flag_pointers[anode->name] = true;
+ }
+
+ if (p_default_actions.usage_defines.has(anode->name) && !used_name_defines.has(anode->name)) {
+ String define = p_default_actions.usage_defines[anode->name];
+ if (define.begins_with("@")) {
+ define = p_default_actions.usage_defines[define.substr(1, define.length())];
+ }
+ r_gen_code.defines.push_back(define);
+ used_name_defines.insert(anode->name);
+ }
+
+ if (p_actions.usage_flag_pointers.has(anode->name) && !used_flag_pointers.has(anode->name)) {
+ *p_actions.usage_flag_pointers[anode->name] = true;
+ used_flag_pointers.insert(anode->name);
+ }
+
+ if (p_default_actions.renames.has(anode->name))
+ code = p_default_actions.renames[anode->name];
+ else
+ code = _mkid(anode->name);
+
+ if (anode->call_expression != nullptr) {
+ code += ".";
+ code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ }
+
+ if (anode->index_expression != nullptr) {
+ code += "[";
+ code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "]";
+ }
+
+ if (anode->name == time_name) {
+ if (current_func_name == vertex_name) {
+ r_gen_code.uses_vertex_time = true;
+ }
+ if (current_func_name == fragment_name || current_func_name == light_name) {
+ r_gen_code.uses_fragment_time = true;
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_CONSTANT: {
+ SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
+ return get_constant_text(cnode->datatype, cnode->values);
+
+ } break;
+ case SL::Node::TYPE_OPERATOR: {
+ SL::OperatorNode *onode = (SL::OperatorNode *)p_node;
+
+ switch (onode->op) {
+
+ case SL::OP_ASSIGN:
+ case SL::OP_ASSIGN_ADD:
+ case SL::OP_ASSIGN_SUB:
+ case SL::OP_ASSIGN_MUL:
+ case SL::OP_ASSIGN_DIV:
+ case SL::OP_ASSIGN_SHIFT_LEFT:
+ case SL::OP_ASSIGN_SHIFT_RIGHT:
+ case SL::OP_ASSIGN_MOD:
+ case SL::OP_ASSIGN_BIT_AND:
+ case SL::OP_ASSIGN_BIT_OR:
+ case SL::OP_ASSIGN_BIT_XOR:
+ code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ break;
+ case SL::OP_BIT_INVERT:
+ case SL::OP_NEGATE:
+ case SL::OP_NOT:
+ case SL::OP_DECREMENT:
+ case SL::OP_INCREMENT:
+ code = _opstr(onode->op) + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ break;
+ case SL::OP_POST_DECREMENT:
+ case SL::OP_POST_INCREMENT:
+ code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op);
+ break;
+ case SL::OP_CALL:
+ case SL::OP_STRUCT:
+ case SL::OP_CONSTRUCT: {
+
+ ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
+
+ SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
+
+ bool is_texture_func = false;
+ if (onode->op == SL::OP_STRUCT) {
+ code += _mkid(vnode->name);
+ } else if (onode->op == SL::OP_CONSTRUCT) {
+ code += String(vnode->name);
+ } else {
+
+ if (internal_functions.has(vnode->name)) {
+ code += vnode->name;
+ is_texture_func = texture_functions.has(vnode->name);
+ } else if (p_default_actions.renames.has(vnode->name)) {
+ code += p_default_actions.renames[vnode->name];
+ } else {
+ code += _mkid(vnode->name);
+ }
+ }
+
+ code += "(";
+
+ for (int i = 1; i < onode->arguments.size(); i++) {
+ if (i > 1)
+ code += ", ";
+ String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
+
+ //need to map from texture to sampler in order to sample
+ const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+
+ StringName texture_uniform = varnode->name;
+
+ String sampler_name;
+
+ if (actions.custom_samplers.has(texture_uniform)) {
+ sampler_name = actions.custom_samplers[texture_uniform];
+ } else {
+ if (shader->uniforms.has(texture_uniform)) {
+ sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ } else {
+ bool found = false;
+
+ for (int j = 0; j < function->arguments.size(); j++) {
+ if (function->arguments[j].name == texture_uniform) {
+ if (function->arguments[j].tex_builtin_check) {
+ ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
+ sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
+ found = true;
+ break;
+ }
+ if (function->arguments[j].tex_argument_check) {
+ sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ //function was most likely unused, so use anything (compiler will remove it anyway)
+ sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+ }
+ }
+ }
+
+ code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+ } else {
+ code += node_code;
+ }
+ }
+ code += ")";
+ } break;
+ case SL::OP_INDEX: {
+
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "[";
+ code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "]";
+
+ } break;
+ case SL::OP_SELECT_IF: {
+
+ code += "(";
+ code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "?";
+ code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += ":";
+ code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += ")";
+
+ } break;
+
+ default: {
+
+ code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")";
+ break;
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_CONTROL_FLOW: {
+ SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node;
+ if (cfnode->flow_op == SL::FLOW_OP_IF) {
+
+ code += _mktab(p_level) + "if (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ if (cfnode->blocks.size() == 2) {
+
+ code += _mktab(p_level) + "else\n";
+ code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ }
+ } else if (cfnode->flow_op == SL::FLOW_OP_SWITCH) {
+
+ code += _mktab(p_level) + "switch (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else if (cfnode->flow_op == SL::FLOW_OP_CASE) {
+
+ code += _mktab(p_level) + "case " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else if (cfnode->flow_op == SL::FLOW_OP_DEFAULT) {
+
+ code += _mktab(p_level) + "default:\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else if (cfnode->flow_op == SL::FLOW_OP_DO) {
+
+ code += _mktab(p_level) + "do";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ");";
+ } else if (cfnode->flow_op == SL::FLOW_OP_WHILE) {
+
+ code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
+ code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+ } else if (cfnode->flow_op == SL::FLOW_OP_FOR) {
+
+ String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n";
+ code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
+
+ } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) {
+
+ if (cfnode->expressions.size()) {
+ code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ";";
+ } else {
+ code = "return;";
+ }
+ } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
+
+ if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+ *p_actions.usage_flag_pointers["DISCARD"] = true;
+ used_flag_pointers.insert("DISCARD");
+ }
+
+ code = "discard;";
+ } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) {
+
+ code = "continue;";
+ } else if (cfnode->flow_op == SL::FLOW_OP_BREAK) {
+
+ code = "break;";
+ }
+
+ } break;
+ case SL::Node::TYPE_MEMBER: {
+ SL::MemberNode *mnode = (SL::MemberNode *)p_node;
+ code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
+ if (mnode->index_expression != nullptr) {
+ code += "[";
+ code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += "]";
+ }
+
+ } break;
+ }
+
+ return code;
+}
+
+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());
+
+ if (err != OK) {
+
+ Vector<String> shader = p_code.split("\n");
+ for (int i = 0; i < shader.size(); i++) {
+ print_line(itos(i + 1) + " " + shader[i]);
+ }
+
+ _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
+ return err;
+ }
+
+ 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.light = String();
+ r_gen_code.uses_fragment_time = false;
+ r_gen_code.uses_vertex_time = false;
+
+ used_name_defines.clear();
+ used_rmode_defines.clear();
+ used_flag_pointers.clear();
+
+ shader = parser.get_shader();
+ function = nullptr;
+ _dump_node_code(shader, 1, r_gen_code, *p_actions, actions, false);
+
+ return OK;
+}
+
+void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
+ actions = p_actions;
+
+ vertex_name = "vertex";
+ fragment_name = "fragment";
+ light_name = "light";
+ time_name = "TIME";
+
+ List<String> func_list;
+
+ ShaderLanguage::get_builtin_funcs(&func_list);
+
+ for (List<String>::Element *E = func_list.front(); E; E = E->next()) {
+ internal_functions.insert(E->get());
+ }
+ texture_functions.insert("texture");
+ texture_functions.insert("textureProj");
+ texture_functions.insert("textureLod");
+ texture_functions.insert("textureProjLod");
+ texture_functions.insert("textureGrad");
+}
+
+ShaderCompilerRD::ShaderCompilerRD() {
+#if 0
+
+ /** SPATIAL SHADER **/
+
+ actions[RS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
+ actions[RS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
+ actions[RS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
+ actions[RS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions[RS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
+ actions[RS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
+
+ actions[RS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
+ actions[RS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
+ actions[RS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
+ actions[RS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
+ actions[RS::SHADER_SPATIAL].renames["POSITION"] = "position";
+ actions[RS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
+ actions[RS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
+ actions[RS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
+ actions[RS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
+ actions[RS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID";
+
+ //builtins
+
+ actions[RS::SHADER_SPATIAL].renames["TIME"] = "time";
+ actions[RS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
+
+ actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
+ actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions[RS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
+ actions[RS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
+ actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
+ actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
+ actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
+ actions[RS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
+ actions[RS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
+ actions[RS::SHADER_SPATIAL].renames["RIM"] = "rim";
+ actions[RS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
+ actions[RS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
+ actions[RS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions[RS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
+ actions[RS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions[RS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
+ actions[RS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
+ actions[RS::SHADER_SPATIAL].renames["AO"] = "ao";
+ actions[RS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions[RS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
+ actions[RS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
+ actions[RS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions[RS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
+ actions[RS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
+ actions[RS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions[RS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth";
+ actions[RS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
+ actions[RS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+
+ //for light
+ actions[RS::SHADER_SPATIAL].renames["VIEW"] = "view";
+ actions[RS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
+ actions[RS::SHADER_SPATIAL].renames["LIGHT"] = "light";
+ actions[RS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
+ actions[RS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions[RS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions[RS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
+ actions[RS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
+ actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions[RS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
+ actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions[RS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions[RS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions[RS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions[RS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ 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");
+
+ if (!force_lambert) {
+ actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+ 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");
+
+ if (!force_blinn) {
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ } else {
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ }
+
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions[RS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+
+ /* PARTICLES SHADER */
+
+ actions[RS::SHADER_PARTICLES].renames["COLOR"] = "out_color";
+ actions[RS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz";
+ actions[RS::SHADER_PARTICLES].renames["MASS"] = "mass";
+ actions[RS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active";
+ actions[RS::SHADER_PARTICLES].renames["RESTART"] = "restart";
+ actions[RS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom";
+ actions[RS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform";
+ actions[RS::SHADER_PARTICLES].renames["TIME"] = "time";
+ actions[RS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime";
+ actions[RS::SHADER_PARTICLES].renames["DELTA"] = "local_delta";
+ actions[RS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number";
+ actions[RS::SHADER_PARTICLES].renames["INDEX"] = "index";
+ actions[RS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity";
+ actions[RS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform";
+ actions[RS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed";
+
+ actions[RS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
+ actions[RS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
+ actions[RS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/rasterizer_rd/shader_compiler_rd.h
new file mode 100644
index 0000000000..7d78469e9c
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.h
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* shader_compiler_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SHADER_COMPILER_RD_H
+#define SHADER_COMPILER_RD_H
+
+#include "core/pair.h"
+#include "servers/rendering/shader_language.h"
+#include "servers/rendering/shader_types.h"
+#include "servers/rendering_server.h"
+
+class ShaderCompilerRD {
+public:
+ struct IdentifierActions {
+
+ Map<StringName, Pair<int *, int>> render_mode_values;
+ Map<StringName, bool *> render_mode_flags;
+ Map<StringName, bool *> usage_flag_pointers;
+ Map<StringName, bool *> write_flag_pointers;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms;
+ };
+
+ struct GeneratedCode {
+
+ Vector<String> defines;
+ struct Texture {
+ StringName name;
+ ShaderLanguage::DataType type;
+ ShaderLanguage::ShaderNode::Uniform::Hint hint;
+ ShaderLanguage::TextureFilter filter;
+ ShaderLanguage::TextureRepeat repeat;
+ };
+
+ Vector<Texture> texture_uniforms;
+
+ Vector<uint32_t> uniform_offsets;
+ uint32_t uniform_total_size;
+ String uniforms;
+ String vertex_global;
+ String vertex;
+ String fragment_global;
+ String fragment;
+ String light;
+
+ bool uses_fragment_time;
+ bool uses_vertex_time;
+ };
+
+ struct DefaultIdentifierActions {
+
+ Map<StringName, String> renames;
+ Map<StringName, String> render_mode_defines;
+ Map<StringName, String> usage_defines;
+ Map<StringName, String> custom_samplers;
+ ShaderLanguage::TextureFilter default_filter;
+ ShaderLanguage::TextureRepeat default_repeat;
+ String sampler_array_name;
+ int base_texture_binding_index = 0;
+ int texture_layout_set = 0;
+ String base_uniform_string;
+ uint32_t base_varying_index = 0;
+ };
+
+private:
+ ShaderLanguage parser;
+
+ String _get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat);
+
+ void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added);
+ String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning);
+
+ const ShaderLanguage::ShaderNode *shader;
+ const ShaderLanguage::FunctionNode *function;
+ StringName current_func_name;
+ StringName vertex_name;
+ StringName fragment_name;
+ StringName light_name;
+ StringName time_name;
+ Set<StringName> texture_functions;
+
+ Set<StringName> used_name_defines;
+ Set<StringName> used_flag_pointers;
+ Set<StringName> used_rmode_defines;
+ Set<StringName> internal_functions;
+
+ DefaultIdentifierActions actions;
+
+public:
+ Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
+
+ void initialize(DefaultIdentifierActions p_actions);
+ ShaderCompilerRD();
+};
+
+#endif // SHADERCOMPILERRD_H
diff --git a/servers/rendering/rasterizer_rd/shader_rd.cpp b/servers/rendering/rasterizer_rd/shader_rd.cpp
new file mode 100644
index 0000000000..d60a58813e
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shader_rd.cpp
@@ -0,0 +1,495 @@
+/*************************************************************************/
+/* shader_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "shader_rd.h"
+
+#include "core/string_builder.h"
+#include "rasterizer_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();
+ }
+ }
+ }
+ }
+
+ 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());
+ }
+
+ 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 (p_compute_code) {
+ 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());
+ }
+
+ 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();
+ }
+ }
+ }
+ }
+}
+
+RID ShaderRD::version_create() {
+
+ //initialize() was never called
+ ERR_FAIL_COND_V(variant_defines.size() == 0, RID());
+
+ Version version;
+ version.dirty = true;
+ version.valid = false;
+ version.initialize_needed = true;
+ version.variants = nullptr;
+ return version_owner.make_rid(version);
+}
+
+void ShaderRD::_clear_version(Version *p_version) {
+ //clear versions if they exist
+ if (p_version->variants) {
+ for (int i = 0; i < variant_defines.size(); i++) {
+ RD::get_singleton()->free(p_version->variants[i]);
+ }
+
+ memdelete_arr(p_version->variants);
+ p_version->variants = nullptr;
+ }
+}
+
+void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
+
+ Vector<RD::ShaderStageData> stages;
+
+ String error;
+ String current_source;
+ RD::ShaderStage current_stage = RD::SHADER_STAGE_VERTEX;
+ bool build_ok = true;
+
+ if (!is_compute) {
+ //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
+
+ current_source = builder.as_string();
+ RD::ShaderStageData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ if (stage.spir_v.size() == 0) {
+ build_ok = false;
+ } else {
+
+ stage.shader_stage = RD::SHADER_STAGE_VERTEX;
+ stages.push_back(stage);
+ }
+ }
+
+ if (!is_compute && build_ok) {
+ //fragment stage
+ 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
+
+ current_source = builder.as_string();
+ RD::ShaderStageData stage;
+ stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
+ if (stage.spir_v.size() == 0) {
+ build_ok = false;
+ } else {
+
+ stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
+ stages.push_back(stage);
+ }
+ }
+
+ if (is_compute) {
+ //compute stage
+ 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(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
+
+ 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) {
+ build_ok = false;
+ } else {
+
+ stage.shader_stage = RD::SHADER_STAGE_COMPUTE;
+ stages.push_back(stage);
+ }
+ }
+
+ if (!build_ok) {
+ MutexLock lock(variant_set_mutex); //properly print the errors
+ ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_COMPUTE ? "Compute " : (current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment")) + " shader, variant #" + itos(p_variant) + " (" + variant_defines[p_variant].get_data() + ").");
+ ERR_PRINT(error);
+
+#ifdef DEBUG_ENABLED
+ ERR_PRINT("code:\n" + current_source.get_with_code_lines());
+#endif
+ return;
+ }
+
+ RID shader = RD::get_singleton()->shader_create(stages);
+ {
+ MutexLock lock(variant_set_mutex);
+ p_version->variants[p_variant] = shader;
+ }
+}
+
+void ShaderRD::_compile_version(Version *p_version) {
+
+ _clear_version(p_version);
+
+ p_version->valid = false;
+ p_version->dirty = false;
+
+ p_version->variants = memnew_arr(RID, variant_defines.size());
+#if 1
+
+ RasterizerRD::thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version);
+#else
+ for (int i = 0; i < variant_defines.size(); i++) {
+
+ _compile_variant(i, p_version);
+ }
+#endif
+
+ bool all_valid = true;
+ for (int i = 0; i < variant_defines.size(); i++) {
+ if (p_version->variants[i].is_null()) {
+ all_valid = false;
+ break;
+ }
+ }
+
+ if (!all_valid) {
+ //clear versions if they exist
+ for (int i = 0; i < variant_defines.size(); i++) {
+ if (!p_version->variants[i].is_null()) {
+ RD::get_singleton()->free(p_version->variants[i]);
+ }
+ }
+ memdelete_arr(p_version->variants);
+ p_version->variants = nullptr;
+ return;
+ }
+
+ 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) {
+
+ 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->custom_defines.clear();
+ for (int i = 0; i < p_custom_defines.size(); i++) {
+ version->custom_defines.push_back(p_custom_defines[i].utf8());
+ }
+
+ version->dirty = true;
+ if (version->initialize_needed) {
+ _compile_version(version);
+ version->initialize_needed = false;
+ }
+}
+
+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) {
+
+ 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->custom_defines.clear();
+ for (int i = 0; i < p_custom_defines.size(); i++) {
+ version->custom_defines.push_back(p_custom_defines[i].utf8());
+ }
+
+ version->dirty = true;
+ if (version->initialize_needed) {
+ _compile_version(version);
+ version->initialize_needed = false;
+ }
+}
+
+bool ShaderRD::version_is_valid(RID p_version) {
+ Version *version = version_owner.getornull(p_version);
+ ERR_FAIL_COND_V(!version, false);
+
+ if (version->dirty) {
+ _compile_version(version);
+ }
+
+ return version->valid;
+}
+
+bool ShaderRD::version_free(RID p_version) {
+
+ if (version_owner.owns(p_version)) {
+ Version *version = version_owner.getornull(p_version);
+ _clear_version(version);
+ version_owner.free(p_version);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines) {
+ ERR_FAIL_COND(variant_defines.size());
+ ERR_FAIL_COND(p_variant_defines.size() == 0);
+ general_defines = p_general_defines.utf8();
+ for (int i = 0; i < p_variant_defines.size(); i++) {
+
+ variant_defines.push_back(p_variant_defines[i].utf8());
+ }
+}
+
+ShaderRD::~ShaderRD() {
+ List<RID> remaining;
+ version_owner.get_owned_list(&remaining);
+ if (remaining.size()) {
+ ERR_PRINT(itos(remaining.size()) + " shaders of type " + name + " were never freed");
+ while (remaining.size()) {
+ version_free(remaining.front()->get());
+ remaining.pop_front();
+ }
+ }
+}
diff --git a/servers/visual/rasterizer_rd/shader_rd.h b/servers/rendering/rasterizer_rd/shader_rd.h
index 6635b08cc8..6635b08cc8 100644
--- a/servers/visual/rasterizer_rd/shader_rd.h
+++ b/servers/rendering/rasterizer_rd/shader_rd.h
diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub
new file mode 100644
index 0000000000..a454d144aa
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/SCsub
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "RD_GLSL" in env["BUILDERS"]:
+ env.RD_GLSL("canvas.glsl")
+ env.RD_GLSL("canvas_occlusion.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_high_end.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_minify.glsl")
+ env.RD_GLSL("ssao_blur.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")
diff --git a/servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl b/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl
index 7153fe6b17..7153fe6b17 100644
--- a/servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/bokeh_dof.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/canvas.glsl b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
index 28135fce31..28135fce31 100644
--- a/servers/visual/rasterizer_rd/shaders/canvas.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
index 7b30cc8fe9..7b30cc8fe9 100644
--- a/servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_occlusion.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
index 1ac43480cd..1ac43480cd 100644
--- a/servers/visual/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/canvas_uniforms_inc.glsl
diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl
new file mode 100644
index 0000000000..2d7661f65f
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl
@@ -0,0 +1,220 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+/* clang-format on */
+
+#define FLAG_HORIZONTAL (1 << 0)
+#define FLAG_USE_BLUR_SECTION (1 << 1)
+#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2)
+#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3)
+#define FLAG_GLOW_FIRST_PASS (1 << 4)
+#define FLAG_FLIP_Y (1 << 5)
+#define FLAG_FORCE_LUMINANCE (1 << 6)
+#define FLAG_COPY_ALL_SOURCE (1 << 7)
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ ivec4 section;
+ ivec2 target;
+ uint flags;
+ uint pad;
+ // Glow.
+ float glow_strength;
+ float glow_bloom;
+ float glow_hdr_threshold;
+ float glow_hdr_scale;
+
+ float glow_exposure;
+ float glow_white;
+ float glow_luminance_cap;
+ float glow_auto_exposure_grey;
+ // DOF.
+ float camera_z_far;
+ float camera_z_near;
+ uint pad2[2];
+}
+params;
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+
+#ifdef GLOW_USE_AUTO_EXPOSURE
+layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
+#endif
+
+#if defined(MODE_LINEARIZE_DEPTH_COPY) || defined(MODE_SIMPLE_COPY_DEPTH)
+layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
+#elif defined(DST_IMAGE_8BIT)
+layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
+#else
+layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
+#endif
+
+void main() {
+
+ // Pixel being shaded
+ ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThan(pos, params.section.zw))) { //too large, do nothing
+ return;
+ }
+
+#ifdef MODE_MIPMAP
+
+ ivec2 base_pos = (pos + params.section.xy) << 1;
+ vec4 color = texelFetch(source_color, base_pos, 0);
+ color += texelFetch(source_color, base_pos + ivec2(0, 1), 0);
+ color += texelFetch(source_color, base_pos + ivec2(1, 0), 0);
+ color += texelFetch(source_color, base_pos + ivec2(1, 1), 0);
+ color /= 4.0;
+
+ imageStore(dest_buffer, pos + params.target, color);
+#endif
+
+#ifdef MODE_GAUSSIAN_BLUR
+
+ //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect
+
+ if (bool(params.flags & FLAG_HORIZONTAL)) {
+
+ ivec2 base_pos = (pos + params.section.xy) << 1;
+ vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.214607;
+ color += texelFetch(source_color, base_pos + ivec2(1, 0), 0) * 0.189879;
+ color += texelFetch(source_color, base_pos + ivec2(2, 0), 0) * 0.131514;
+ color += texelFetch(source_color, base_pos + ivec2(3, 0), 0) * 0.071303;
+ color += texelFetch(source_color, base_pos + ivec2(-1, 0), 0) * 0.189879;
+ color += texelFetch(source_color, base_pos + ivec2(-2, 0), 0) * 0.131514;
+ color += texelFetch(source_color, base_pos + ivec2(-3, 0), 0) * 0.071303;
+ imageStore(dest_buffer, pos + params.target, color);
+ } else {
+
+ ivec2 base_pos = (pos + params.section.xy);
+ vec4 color = texelFetch(source_color, base_pos + ivec2(0, 0), 0) * 0.38774;
+ color += texelFetch(source_color, base_pos + ivec2(0, 1), 0) * 0.24477;
+ color += texelFetch(source_color, base_pos + ivec2(0, 2), 0) * 0.06136;
+ color += texelFetch(source_color, base_pos + ivec2(0, -1), 0) * 0.24477;
+ color += texelFetch(source_color, base_pos + ivec2(0, -2), 0) * 0.06136;
+ imageStore(dest_buffer, pos + params.target, color);
+ }
+#endif
+
+#ifdef MODE_GAUSSIAN_GLOW
+
+ //Glow uses larger sigma 1 for a more rounded blur effect
+
+#define GLOW_ADD(m_ofs, m_mult) \
+ { \
+ ivec2 ofs = base_pos + m_ofs; \
+ if (all(greaterThanEqual(ofs, section_begin)) && all(lessThan(ofs, section_end))) { \
+ color += texelFetch(source_color, ofs, 0) * m_mult; \
+ } \
+ }
+
+ vec4 color = vec4(0.0);
+
+ if (bool(params.flags & FLAG_HORIZONTAL)) {
+
+ ivec2 base_pos = (pos + params.section.xy) << 1;
+ ivec2 section_begin = params.section.xy << 1;
+ ivec2 section_end = section_begin + (params.section.zw << 1);
+
+ GLOW_ADD(ivec2(0, 0), 0.174938);
+ GLOW_ADD(ivec2(1, 0), 0.165569);
+ GLOW_ADD(ivec2(2, 0), 0.140367);
+ GLOW_ADD(ivec2(3, 0), 0.106595);
+ GLOW_ADD(ivec2(-1, 0), 0.165569);
+ GLOW_ADD(ivec2(-2, 0), 0.140367);
+ GLOW_ADD(ivec2(-3, 0), 0.106595);
+ color *= params.glow_strength;
+ } else {
+
+ ivec2 base_pos = pos + params.section.xy;
+ ivec2 section_begin = params.section.xy;
+ ivec2 section_end = section_begin + params.section.zw;
+
+ GLOW_ADD(ivec2(0, 0), 0.288713);
+ GLOW_ADD(ivec2(0, 1), 0.233062);
+ GLOW_ADD(ivec2(0, 2), 0.122581);
+ GLOW_ADD(ivec2(0, -1), 0.233062);
+ GLOW_ADD(ivec2(0, -2), 0.122581);
+ color *= params.glow_strength;
+ }
+
+#undef GLOW_ADD
+
+ if (bool(params.flags & FLAG_GLOW_FIRST_PASS)) {
+#ifdef GLOW_USE_AUTO_EXPOSURE
+
+ color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.glow_auto_exposure_grey;
+#endif
+ color *= params.glow_exposure;
+
+ float luminance = max(color.r, max(color.g, color.b));
+ float feedback = max(smoothstep(params.glow_hdr_threshold, params.glow_hdr_threshold + params.glow_hdr_scale, luminance), params.glow_bloom);
+
+ color = min(color * feedback, vec4(params.glow_luminance_cap));
+ }
+
+ imageStore(dest_buffer, pos + params.target, color);
+
+#endif
+
+#ifdef MODE_SIMPLE_COPY
+
+ vec4 color;
+ if (bool(params.flags & FLAG_COPY_ALL_SOURCE)) {
+ vec2 uv = vec2(pos) / vec2(params.section.zw);
+ if (bool(params.flags & FLAG_FLIP_Y)) {
+ uv.y = 1.0 - uv.y;
+ }
+ color = textureLod(source_color, uv, 0.0);
+
+ if (bool(params.flags & FLAG_FORCE_LUMINANCE)) {
+ color.rgb = vec3(max(max(color.r, color.g), color.b));
+ }
+ imageStore(dest_buffer, pos + params.target, color);
+
+ } else {
+ color = texelFetch(source_color, pos + params.section.xy, 0);
+
+ if (bool(params.flags & FLAG_FORCE_LUMINANCE)) {
+ color.rgb = vec3(max(max(color.r, color.g), color.b));
+ }
+
+ if (bool(params.flags & FLAG_FLIP_Y)) {
+ pos.y = params.section.w - pos.y - 1;
+ }
+
+ imageStore(dest_buffer, pos + params.target, color);
+ }
+
+#endif
+
+#ifdef MODE_SIMPLE_COPY_DEPTH
+
+ vec4 color = texelFetch(source_color, pos + params.section.xy, 0);
+
+ if (bool(params.flags & FLAG_FLIP_Y)) {
+ pos.y = params.section.w - pos.y - 1;
+ }
+
+ imageStore(dest_buffer, pos + params.target, vec4(color.r));
+
+#endif
+
+#ifdef MODE_LINEARIZE_DEPTH_COPY
+
+ float depth = texelFetch(source_color, pos + params.section.xy, 0).r;
+ depth = depth * 2.0 - 1.0;
+ depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+ vec4 color = vec4(depth / params.camera_z_far);
+
+ if (bool(params.flags & FLAG_FLIP_Y)) {
+ pos.y = params.section.w - pos.y - 1;
+ }
+
+ imageStore(dest_buffer, pos + params.target, color);
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl
new file mode 100644
index 0000000000..07f8d09743
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/copy_to_fb.glsl
@@ -0,0 +1,104 @@
+/* clang-format off */
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ vec4 section;
+ vec2 pixel_size;
+ bool flip_y;
+ bool use_section;
+
+ bool force_luminance;
+ uint pad[3];
+}
+params;
+
+void main() {
+
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ vec2 vpos = uv_interp;
+ if (params.use_section) {
+ vpos = params.section.xy + vpos * params.section.zw;
+ }
+
+ gl_Position = vec4(vpos * 2.0 - 1.0, 0.0, 1.0);
+
+ if (params.flip_y) {
+ uv_interp.y = 1.0 - uv_interp.y;
+ }
+}
+
+/* clang-format off */
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ vec4 section;
+ vec2 pixel_size;
+ bool flip_y;
+ bool use_section;
+
+ bool force_luminance;
+ bool alpha_to_zero;
+ uint pad[2];
+} params;
+
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+ vec2 uv = uv_interp;
+
+#ifdef MODE_PANORAMA_TO_DP
+
+ //obtain normal from dual paraboloid uv
+#define M_PI 3.14159265359
+
+ float side;
+ uv.y = modf(uv.y * 2.0, side);
+ side = side * 2.0 - 1.0;
+ vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ normal *= -side;
+ normal = normalize(normal);
+
+ //now convert normal to panorama uv
+
+ vec2 st = vec2(atan(normal.x, normal.z), acos(normal.y));
+
+ if (st.x < 0.0)
+ st.x += M_PI * 2.0;
+
+ uv = st / vec2(M_PI * 2.0, M_PI);
+
+ if (side < 0.0) {
+ //uv.y = 1.0 - uv.y;
+ uv = 1.0 - uv;
+ }
+#endif
+ vec4 color = textureLod(source_color, uv, 0.0);
+ if (params.force_luminance) {
+ color.rgb = vec3(max(max(color.r, color.g), color.b));
+ }
+ if (params.alpha_to_zero) {
+ color.rgb *= color.a;
+ }
+ frag_color = color;
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl
new file mode 100644
index 0000000000..02ebe1a53b
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/cube_to_dp.glsl
@@ -0,0 +1,72 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform samplerCube source_cube;
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ ivec2 screen_size;
+ ivec2 offset;
+ float bias;
+ float z_far;
+ float z_near;
+ bool z_flip;
+}
+params;
+
+layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D depth_buffer;
+
+void main() {
+
+ ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
+ if (any(greaterThan(pos, params.screen_size))) { //too large, do nothing
+ return;
+ }
+
+ vec2 pixel_size = 1.0 / vec2(params.screen_size);
+ vec2 uv = (vec2(pos) + 0.5) * pixel_size;
+
+ vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
+
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ normal = normalize(normal);
+
+ normal.y = -normal.y; //needs to be flipped to match projection matrix
+ if (!params.z_flip) {
+ normal.z = -normal.z;
+ }
+
+ float depth = texture(source_cube, normal).r;
+
+ // absolute values for direction cosines, bigger value equals closer to basis axis
+ vec3 unorm = abs(normal);
+
+ if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+ } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+ } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
+ } else {
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3(1.0, 0.0, 0.0);
+ }
+
+ float depth_fix = 1.0 / dot(normal, unorm);
+
+ depth = 2.0 * depth - 1.0;
+ float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
+ depth = (linear_depth * depth_fix) / params.z_far;
+
+ imageStore(depth_buffer, pos + params.offset, vec4(depth));
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl
new file mode 100644
index 0000000000..9f3ecf6053
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/cubemap_downsampler.glsl
@@ -0,0 +1,188 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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.
+
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+#define BLOCK_SIZE 8
+
+layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_size;
+}
+params;
+
+#define M_PI 3.14159265359
+
+void get_dir_0(out vec3 dir, in float u, in float v) {
+ dir[0] = 1.0;
+ dir[1] = v;
+ dir[2] = -u;
+}
+void get_dir_1(out vec3 dir, in float u, in float v) {
+ dir[0] = -1.0;
+ dir[1] = v;
+ dir[2] = u;
+}
+void get_dir_2(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = 1.0;
+ dir[2] = -v;
+}
+void get_dir_3(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = -1.0;
+ dir[2] = v;
+}
+void get_dir_4(out vec3 dir, in float u, in float v) {
+ dir[0] = u;
+ dir[1] = v;
+ dir[2] = 1.0;
+}
+void get_dir_5(out vec3 dir, in float u, in float v) {
+ dir[0] = -u;
+ dir[1] = v;
+ dir[2] = -1.0;
+}
+
+float calcWeight(float u, float v) {
+ float val = u * u + v * v + 1.0;
+ return val * sqrt(val);
+}
+
+void main() {
+ uvec3 id = gl_GlobalInvocationID;
+ uint face_size = params.face_size;
+
+ if (id.x < face_size && id.y < face_size) {
+ float inv_face_size = 1.0 / float(face_size);
+
+ float u0 = (float(id.x) * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
+ float u1 = (float(id.x) * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
+
+ float v0 = (float(id.y) * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
+ float v1 = (float(id.y) * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
+
+ float weights[4];
+ weights[0] = calcWeight(u0, v0);
+ weights[1] = calcWeight(u1, v0);
+ weights[2] = calcWeight(u0, v1);
+ weights[3] = calcWeight(u1, v1);
+
+ const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
+ for (int i = 0; i < 4; i++) {
+ weights[i] = weights[i] * wsum + .125;
+ }
+
+ vec3 dir;
+ vec4 color;
+ switch (id.z) {
+ case 0:
+ get_dir_0(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_0(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_0(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_0(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 1:
+ get_dir_1(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_1(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_1(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_1(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 2:
+ get_dir_2(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_2(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_2(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_2(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 3:
+ get_dir_3(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_3(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_3(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_3(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ case 4:
+ get_dir_4(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_4(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_4(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_4(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ default:
+ get_dir_5(dir, u0, v0);
+ color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+ get_dir_5(dir, u1, v0);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+ get_dir_5(dir, u0, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+ get_dir_5(dir, u1, v1);
+ color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+ break;
+ }
+ imageStore(dest_cubemap, ivec3(id), color);
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl b/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl
new file mode 100644
index 0000000000..193d0a8a3c
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/cubemap_filter.glsl
@@ -0,0 +1,328 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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.
+
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+#define GROUP_SIZE 64
+
+layout(local_size_x = GROUP_SIZE, local_size_y = 1, local_size_z = 1) in;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly imageCube dest_cubemap0;
+layout(rgba16f, set = 2, binding = 1) uniform restrict writeonly imageCube dest_cubemap1;
+layout(rgba16f, set = 2, binding = 2) uniform restrict writeonly imageCube dest_cubemap2;
+layout(rgba16f, set = 2, binding = 3) uniform restrict writeonly imageCube dest_cubemap3;
+layout(rgba16f, set = 2, binding = 4) uniform restrict writeonly imageCube dest_cubemap4;
+layout(rgba16f, set = 2, binding = 5) uniform restrict writeonly imageCube dest_cubemap5;
+layout(rgba16f, set = 2, binding = 6) uniform restrict writeonly imageCube dest_cubemap6;
+
+#ifdef USE_HIGH_QUALITY
+#define NUM_TAPS 32
+#else
+#define NUM_TAPS 8
+#endif
+
+#define BASE_RESOLUTION 128
+
+#ifdef USE_HIGH_QUALITY
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][3][24] coeffs;
+}
+data;
+#else
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+ vec4[7][5][6] coeffs;
+}
+data;
+#endif
+
+void get_dir(out vec3 dir, in vec2 uv, in uint face) {
+ switch (face) {
+ case 0:
+ dir = vec3(1.0, uv[1], -uv[0]);
+ break;
+ case 1:
+ dir = vec3(-1.0, uv[1], uv[0]);
+ break;
+ case 2:
+ dir = vec3(uv[0], 1.0, -uv[1]);
+ break;
+ case 3:
+ dir = vec3(uv[0], -1.0, uv[1]);
+ break;
+ case 4:
+ dir = vec3(uv[0], uv[1], 1.0);
+ break;
+ default:
+ dir = vec3(-uv[0], uv[1], -1.0);
+ break;
+ }
+}
+
+void main() {
+ // INPUT:
+ // id.x = the linear address of the texel (ignoring face)
+ // id.y = the face
+ // -> use to index output texture
+ // id.x = texel x
+ // id.y = texel y
+ // id.z = face
+ uvec3 id = gl_GlobalInvocationID;
+
+ // determine which texel this is
+#ifndef USE_TEXTURE_ARRAY
+ // NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
+ int mip_level = 0;
+ if (id.x < (128 * 128)) {
+ mip_level = 0;
+ } else if (id.x < (128 * 128 + 64 * 64)) {
+ mip_level = 1;
+ id.x -= (128 * 128);
+ } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32)) {
+ mip_level = 2;
+ id.x -= (128 * 128 + 64 * 64);
+ } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16)) {
+ mip_level = 3;
+ id.x -= (128 * 128 + 64 * 64 + 32 * 32);
+ } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8)) {
+ mip_level = 4;
+ id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16);
+ } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4)) {
+ mip_level = 5;
+ id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8);
+ } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2)) {
+ mip_level = 6;
+ id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4);
+ } else {
+ return;
+ }
+ int res = BASE_RESOLUTION >> mip_level;
+#else // Using Texture Arrays so all levels are the same resolution
+ int res = BASE_RESOLUTION;
+ int mip_level = int(id.x / (BASE_RESOLUTION * BASE_RESOLUTION));
+ id.x -= mip_level * BASE_RESOLUTION * BASE_RESOLUTION;
+#endif
+
+ // determine dir / pos for the texel
+ vec3 dir, adir, frameZ;
+ {
+ id.z = id.y;
+ id.y = id.x / res;
+ id.x -= id.y * res;
+
+ vec2 uv;
+ uv.x = (float(id.x) * 2.0 + 1.0) / float(res) - 1.0;
+ uv.y = -(float(id.y) * 2.0 + 1.0) / float(res) + 1.0;
+
+ get_dir(dir, uv, id.z);
+ frameZ = normalize(dir);
+
+ adir = abs(dir);
+ }
+
+ // GGX gather colors
+ vec4 color = vec4(0.0);
+ for (int axis = 0; axis < 3; axis++) {
+ const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
+ const int otherAxis1 = 2 - (axis >> 1);
+
+ float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
+ if (frameweight > 0.0) {
+ // determine frame
+ vec3 UpVector;
+ switch (axis) {
+ case 0:
+ UpVector = vec3(1, 0, 0);
+ break;
+ case 1:
+ UpVector = vec3(0, 1, 0);
+ break;
+ default:
+ UpVector = vec3(0, 0, 1);
+ break;
+ }
+
+ vec3 frameX = normalize(cross(UpVector, frameZ));
+ vec3 frameY = cross(frameZ, frameX);
+
+ // calculate parametrization for polynomial
+ float Nx = dir[otherAxis0];
+ float Ny = dir[otherAxis1];
+ float Nz = adir[axis];
+
+ float NmaxXY = max(abs(Ny), abs(Nx));
+ Nx /= NmaxXY;
+ Ny /= NmaxXY;
+
+ float theta;
+ if (Ny < Nx) {
+ if (Ny <= -0.999)
+ theta = Nx;
+ else
+ theta = Ny;
+ } else {
+ if (Ny >= 0.999)
+ theta = -Nx;
+ else
+ theta = -Ny;
+ }
+
+ float phi;
+ if (Nz <= -0.999)
+ phi = -NmaxXY;
+ else if (Nz >= 0.999)
+ phi = NmaxXY;
+ else
+ phi = Nz;
+
+ float theta2 = theta * theta;
+ float phi2 = phi * phi;
+
+ // sample
+ for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
+ const int index = (NUM_TAPS / 4) * axis + iSuperTap;
+
+#ifdef USE_HIGH_QUALITY
+ vec4 coeffsDir0[3];
+ vec4 coeffsDir1[3];
+ vec4 coeffsDir2[3];
+ vec4 coeffsLevel[3];
+ vec4 coeffsWeight[3];
+
+ for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
+ coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index];
+ coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index];
+ coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index];
+ coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index];
+ coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index];
+ }
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
+
+ float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
+
+ float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
+#else
+ vec4 coeffsDir0 = data.coeffs[mip_level][0][index];
+ vec4 coeffsDir1 = data.coeffs[mip_level][1][index];
+ vec4 coeffsDir2 = data.coeffs[mip_level][2][index];
+ vec4 coeffsLevel = data.coeffs[mip_level][3][index];
+ vec4 coeffsWeight = data.coeffs[mip_level][4][index];
+
+ for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+ // determine sample attributes (dir, weight, mip_level)
+ vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
+
+ float sample_level = coeffsLevel[iSubTap];
+
+ float sample_weight = coeffsWeight[iSubTap];
+#endif
+
+ sample_weight *= frameweight;
+
+ // adjust for jacobian
+ sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
+ sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
+#ifndef USE_TEXTURE_ARRAY
+ sample_level += float(mip_level) / 6.0; // Hack to increase the perceived roughness and reduce upscaling artifacts
+#endif
+ // sample cubemap
+ color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
+ color.w += sample_weight;
+ }
+ }
+ }
+ }
+ color /= color.w;
+
+ // write color
+ color.xyz = max(vec3(0.0), color.xyz);
+ color.w = 1.0;
+#ifdef USE_TEXTURE_ARRAY
+ id.xy *= uvec2(2, 2);
+#endif
+
+ switch (mip_level) {
+ case 0:
+ imageStore(dest_cubemap0, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap0, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap0, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap0, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ case 1:
+ imageStore(dest_cubemap1, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap1, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap1, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap1, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ case 2:
+ imageStore(dest_cubemap2, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap2, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap2, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap2, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ case 3:
+ imageStore(dest_cubemap3, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap3, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap3, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap3, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ case 4:
+ imageStore(dest_cubemap4, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap4, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap4, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap4, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ case 5:
+ imageStore(dest_cubemap5, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap5, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap5, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap5, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ default:
+ imageStore(dest_cubemap6, ivec3(id), color);
+#ifdef USE_TEXTURE_ARRAY
+ imageStore(dest_cubemap6, ivec3(id) + ivec3(1.0, 0.0, 0.0), color);
+ imageStore(dest_cubemap6, ivec3(id) + ivec3(0.0, 1.0, 0.0), color);
+ imageStore(dest_cubemap6, ivec3(id) + ivec3(1.0, 1.0, 0.0), color);
+#endif
+ break;
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl
new file mode 100644
index 0000000000..e85996fa1a
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/cubemap_roughness.glsl
@@ -0,0 +1,147 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+#define GROUP_SIZE 8
+
+layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform samplerCube source_cube;
+
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ uint face_id;
+ uint sample_count;
+ float roughness;
+ bool use_direct_write;
+ float face_size;
+}
+params;
+
+#define M_PI 3.14159265359
+
+vec3 texelCoordToVec(vec2 uv, uint faceID) {
+ mat3 faceUvVectors[6];
+
+ // -x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
+ float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
+
+ // Compute distribution direction
+ float Phi = 2.0 * M_PI * Xi.x;
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
+ float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
+
+ // Convert to spherical direction
+ vec3 H;
+ H.x = SinTheta * cos(Phi);
+ H.y = SinTheta * sin(Phi);
+ H.z = CosTheta;
+
+ vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ vec3 TangentX = normalize(cross(UpVector, N));
+ vec3 TangentY = cross(N, TangentX);
+
+ // Tangent to world space
+ return TangentX * H.x + TangentY * H.y + N * H.z;
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a) {
+ float k = a / 2.0;
+ return NdotV / (NdotV * (1.0 - k) + k);
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL) {
+ return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+}
+
+float radicalInverse_VdC(uint bits) {
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+}
+
+vec2 Hammersley(uint i, uint N) {
+ return vec2(float(i) / float(N), radicalInverse_VdC(i));
+}
+
+void main() {
+ uvec3 id = gl_GlobalInvocationID;
+ id.z += params.face_id;
+
+ vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0);
+ vec3 N = texelCoordToVec(uv, id.z);
+
+ //vec4 color = color_interp;
+
+ if (params.use_direct_write) {
+
+ imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0));
+ } else {
+
+ vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+
+ for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
+ vec2 xi = Hammersley(sampleNum, params.sample_count);
+
+ vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
+ vec3 V = N;
+ vec3 L = (2.0 * dot(V, H) * H - V);
+
+ float ndotl = clamp(dot(N, L), 0.0, 1.0);
+
+ if (ndotl > 0.0) {
+
+ sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
+ sum.a += ndotl;
+ }
+ }
+ sum /= sum.a;
+
+ imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0));
+ }
+}
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe.glsl b/servers/rendering/rasterizer_rd/shaders/giprobe.glsl
index fd09f96a57..fd09f96a57 100644
--- a/servers/visual/rasterizer_rd/shaders/giprobe.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/giprobe.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl b/servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl
index b1784e7eee..b1784e7eee 100644
--- a/servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/giprobe_debug.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl
index d089236723..d089236723 100644
--- a/servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl b/servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl
index c832223b1e..c832223b1e 100644
--- a/servers/visual/rasterizer_rd/shaders/giprobe_write.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/giprobe_write.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/luminance_reduce.glsl b/servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl
index 4bf5b7e7f1..4bf5b7e7f1 100644
--- a/servers/visual/rasterizer_rd/shaders/luminance_reduce.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/luminance_reduce.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/roughness_limiter.glsl b/servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl
index 3637b1abb2..3637b1abb2 100644
--- a/servers/visual/rasterizer_rd/shaders/roughness_limiter.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/roughness_limiter.glsl
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
new file mode 100644
index 0000000000..ec47887036
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -0,0 +1,2474 @@
+/* clang-format off */
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+#include "scene_high_end_inc.glsl"
+
+/* INPUT ATTRIBS */
+
+layout(location = 0) in vec3 vertex_attrib;
+/* clang-format on */
+layout(location = 1) in vec3 normal_attrib;
+#if defined(TANGENT_USED) || defined(NORMALMAP_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
+
+layout(location = 4) in vec2 uv_attrib;
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 5) in vec2 uv2_attrib;
+#endif
+
+layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused
+
+/* Varyings */
+
+layout(location = 0) out vec3 vertex_interp;
+layout(location = 1) out vec3 normal_interp;
+
+#if defined(COLOR_USED)
+layout(location = 2) out vec4 color_interp;
+#endif
+
+layout(location = 3) out vec2 uv_interp;
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 4) out vec2 uv2_interp;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 5) out vec3 tangent_interp;
+layout(location = 6) out vec3 binormal_interp;
+#endif
+
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 5, binding = 0, std140) uniform MaterialUniforms{
+ /* clang-format off */
+MATERIAL_UNIFORMS
+ /* clang-format on */
+} material;
+#endif
+
+/* clang-format off */
+
+VERTEX_SHADER_GLOBALS
+
+/* clang-format on */
+
+// FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now.
+// See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316
+invariant gl_Position;
+
+layout(location = 7) flat out uint instance_index;
+
+#ifdef MODE_DUAL_PARABOLOID
+
+layout(location = 8) out float dp_clip;
+
+#endif
+
+void main() {
+
+ instance_index = draw_call.instance_index;
+ vec4 instance_custom = vec4(0.0);
+#if defined(COLOR_USED)
+ color_interp = color_attrib;
+#endif
+
+ mat4 world_matrix = instances.data[instance_index].transform;
+ mat3 world_normal_matrix = mat3(instances.data[instance_index].normal_transform);
+
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_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;
+ 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;
+ } 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(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
+#ifdef COLOR_USED
+ color_interp *= transforms.data[offset];
+#endif
+ offset += 1;
+ }
+
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
+ instance_custom = transforms.data[offset];
+ }
+
+ //transpose
+ matrix = transpose(matrix);
+ world_matrix = world_matrix * matrix;
+ world_normal_matrix = world_normal_matrix * mat3(matrix);
+
+ } else {
+ //not a multimesh, instances are for multiple draw calls
+ instance_index += gl_InstanceIndex;
+ }
+
+ vec3 vertex = vertex_attrib;
+ vec3 normal = normal_attrib;
+
+#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 tangent = tangent_attrib.xyz;
+ float binormalf = tangent_attrib.a;
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
+#endif
+
+ 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(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+
+ tangent = (vec4(tangent, 0.0) * m).xyz;
+ binormal = (vec4(binormal, 0.0) * m).xyz;
+#endif
+ }
+
+ uv_interp = uv_attrib;
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ uv2_interp = uv2_attrib;
+#endif
+
+#ifdef USE_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(NORMALMAP_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;
+
+ {
+ /* clang-format off */
+
+VERTEX_SHADER_CODE
+
+ /* clang-format on */
+ }
+
+// using local coordinates (default)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
+
+ vertex = (modelview * vec4(vertex, 1.0)).xyz;
+ normal = modelview_normal * normal;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMALMAP_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(NORMALMAP_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;
+ normal_interp = normal;
+
+#if defined(TANGENT_USED) || defined(NORMALMAP_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;
+ normal_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 USE_OVERRIDE_POSITION
+ gl_Position = position;
+#else
+ gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
+#endif
+
+#ifdef MODE_RENDER_DEPTH
+ if (scene_data.pancake_shadows) {
+ if (gl_Position.z <= 0.00001) {
+ gl_Position.z = 0.00001;
+ }
+ }
+#endif
+}
+
+/* clang-format off */
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+#include "scene_high_end_inc.glsl"
+
+/* Varyings */
+
+layout(location = 0) in vec3 vertex_interp;
+/* clang-format on */
+layout(location = 1) in vec3 normal_interp;
+
+#if defined(COLOR_USED)
+layout(location = 2) in vec4 color_interp;
+#endif
+
+layout(location = 3) in vec2 uv_interp;
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 4) in vec2 uv2_interp;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 5) in vec3 tangent_interp;
+layout(location = 6) in vec3 binormal_interp;
+#endif
+
+layout(location = 7) flat in uint instance_index;
+
+#ifdef MODE_DUAL_PARABOLOID
+
+layout(location = 8) in float dp_clip;
+
+#endif
+
+//defines to keep compatibility with vertex
+
+#define world_matrix instances.data[instance_index].transform
+#define world_normal_matrix instances.data[instance_index].normal_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 USE_MATERIAL_UNIFORMS
+layout(set = 5, binding = 0, std140) uniform MaterialUniforms{
+ /* clang-format off */
+MATERIAL_UNIFORMS
+ /* clang-format on */
+} material;
+#endif
+
+/* clang-format off */
+
+FRAGMENT_SHADER_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
+
+#ifdef MODE_RENDER_NORMAL
+layout(location = 0) out vec4 normal_output_buffer;
+#ifdef MODE_RENDER_ROUGHNESS
+layout(location = 1) out float roughness_output_buffer;
+#endif //MODE_RENDER_ROUGHNESS
+#endif //MODE_RENDER_NORMAL
+#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
+
+#endif // RENDER DEPTH
+
+// 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).
+
+#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, float A, vec3 light_color, float attenuation, vec3 shadow_attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity,
+#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,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 B, vec3 T, float anisotropy,
+#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 albedo = diffuse_color;
+ vec3 light = L;
+ vec3 view = V;
+
+ /* clang-format off */
+
+LIGHT_SHADER_CODE
+
+ /* clang-format on */
+
+#else
+ float NdotL = min(A + dot(N, L), 1.0);
+ 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)
+ float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
+#endif
+
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+ float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
+#endif
+
+ if (metallic < 1.0) {
+#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_OREN_NAYAR)
+
+ {
+ // see http://mimosa-pudica.net/improved-oren-nayar.html
+ float LdotV = dot(L, V);
+
+ float s = LdotV - NdotL * NdotV;
+ float t = mix(1.0, max(NdotL, NdotV), step(0.0, s));
+
+ float sigma2 = roughness * roughness; // TODO: this needs checking
+ vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13));
+ float B = 0.45 * sigma2 / (sigma2 + 0.09);
+
+ diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI);
+ }
+
+#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_color * shadow_attenuation * diffuse_brdf_NL * attenuation;
+
+#if defined(LIGHT_BACKLIGHT_USED)
+ diffuse_light += light_color * diffuse_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), diffuse_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 * diffuse_color * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI) * attenuation;
+ }
+#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 += diffuse_color * transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade * attenuation;
+ }
+
+#endif //SSS_MODE_SKIN
+
+#endif //LIGHT_TRANSMITTANCE_USED
+ }
+
+ 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 * shadow_attenuation * intensity * specular_blob_intensity * attenuation;
+
+#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 * shadow_attenuation * intensity * specular_blob_intensity * attenuation;
+
+#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 * shadow_attenuation * intensity * specular_blob_intensity * attenuation; // 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
+ vec3 f0 = F0(metallic, specular, diffuse_color);
+ 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 * shadow_attenuation * specular_blob_intensity * attenuation;
+#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 * shadow_attenuation * specular_blob_intensity * attenuation;
+#endif
+ }
+
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha = min(alpha, clamp(1.0 - length(shadow_attenuation * attenuation), 0.0, 1.0));
+#endif
+
+#endif //defined(USE_LIGHT_SHADER_CODE)
+}
+
+#ifndef USE_NO_SHADOWS
+
+// Produces cheap but low-quality white noise, nothing special
+float quick_hash(vec2 pos) {
+ return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237);
+}
+
+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
+
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
+#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,
+#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 = lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float normalized_distance = light_length * lights.data[idx].inv_radius;
+ vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy);
+ float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x);
+ float light_attenuation = omni_attenuation;
+ vec3 shadow_attenuation = vec3(1.0);
+ vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
+ color_specular.rgb *= attenuation_energy.y;
+ float size_A = 0.0;
+
+ if (lights.data[idx].size > 0.0) {
+
+ float t = lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth; //no transmittance by default
+#endif
+
+#ifndef USE_NO_SHADOWS
+ vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled);
+ if (shadow_color_enabled.w > 0.5) {
+ // there is a shadowmap
+
+ vec4 v = vec4(vertex, 1.0);
+
+ vec4 splane = (lights.data[idx].shadow_matrix * v);
+ float shadow_len = length(splane.xyz); //need to remember shadow len from here
+
+ {
+ vec3 nofs = normal_interp * lights.data[idx].shadow_normal_bias / lights.data[idx].inv_radius;
+ nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
+ v.xyz += nofs;
+ splane = (lights.data[idx].shadow_matrix * v);
+ }
+
+ float shadow;
+
+ if (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 * lights.data[idx].inv_radius;
+
+ tangent *= lights.data[idx].soft_shadow_size * lights.data[idx].soft_shadow_scale;
+ bitangent *= lights.data[idx].soft_shadow_size * 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 = 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 -= lights.data[idx].inv_radius * 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 = 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 {
+
+ splane.xyz = normalize(splane.xyz);
+ vec4 clamp_rect = 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 - lights.data[idx].shadow_bias) * 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, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
+ }
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ {
+
+ vec4 clamp_rect = lights.data[idx].atlas_rect;
+
+ //redo shadowmapping, but shrink the model a bit to avoid arctifacts
+ splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * 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 * 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) / lights.data[idx].inv_radius;
+ }
+#endif
+
+ vec3 no_shadow = vec3(1.0);
+
+ if (lights.data[idx].projector_rect != vec4(0.0)) {
+
+ vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
+ local_v = normalize(local_v);
+
+ vec4 atlas_rect = 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 = (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 = (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);
+ }
+
+ shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow);
+ }
+#endif //USE_NO_SHADOWS
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
+#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,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light,
+ specular_light);
+}
+
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
+#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,
+#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 = lights.data[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float normalized_distance = light_length * lights.data[idx].inv_radius;
+ vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy);
+ float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x);
+ vec3 spot_dir = lights.data[idx].direction;
+ vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle);
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y));
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x);
+ float light_attenuation = spot_attenuation;
+ vec3 shadow_attenuation = vec3(1.0);
+ vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
+ color_specular.rgb *= attenuation_energy.y;
+
+ float size_A = 0.0;
+
+ if (lights.data[idx].size > 0.0) {
+
+ float t = lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
+/*
+ if (lights.data[idx].atlas_rect!=vec4(0.0)) {
+ //use projector texture
+ }
+ */
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth;
+#endif
+
+#ifndef USE_NO_SHADOWS
+ vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled);
+ if (shadow_color_enabled.w > 0.5) {
+ //there is a shadowmap
+ vec4 v = vec4(vertex, 1.0);
+
+ v.xyz -= spot_dir * lights.data[idx].shadow_bias;
+
+ float z_norm = dot(spot_dir, -light_rel_vec) * 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)))) * 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 - lights.data[idx].position) * lights.data[idx].inv_radius;
+
+ float shadow;
+
+ vec4 splane = (lights.data[idx].shadow_matrix * v);
+ splane /= splane.w;
+
+ if (lights.data[idx].soft_shadow_size > 0.0) {
+ //soft shadow
+
+ //find blocker
+
+ vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + 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 = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale;
+ vec2 clamp_max = lights.data[idx].atlas_rect.xy + 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, 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, 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 {
+ //hard shadow
+ vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0);
+
+ shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
+ }
+
+ vec3 no_shadow = vec3(1.0);
+
+ if (lights.data[idx].projector_rect != vec4(0.0)) {
+
+ splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
+ splane /= splane.w;
+
+ vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw;
+
+ //ensure we have proper mipmaps
+ vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
+ splane_ddx /= splane_ddx.w;
+ vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0));
+ splane_ddy /= splane_ddy.w;
+ vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv;
+
+ vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy);
+ no_shadow = mix(no_shadow, proj.rgb, proj.a);
+ }
+
+ shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow);
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ {
+
+ splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
+ splane /= splane.w;
+ splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + 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 / 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
+ }
+
+#endif //USE_NO_SHADOWS
+
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color_specular.rgb, light_attenuation, shadow_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
+#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,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#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].params.x > 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].params.w > 0.5) { //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].params.z < 0.5) {
+ reflection.rgb = mix(specular_light, reflection.rgb, blend);
+ }
+
+ reflection.rgb *= reflections.data[ref_index].params.x;
+ reflection.a = blend;
+ reflection.rgb *= reflection.a;
+
+ reflection_accum += reflection;
+ }
+
+#if !defined(USE_LIGHTMAP) && !defined(USE_VOXEL_CONE_TRACING)
+ if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox
+
+ 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;
+ ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a);
+ if (reflections.data[ref_index].params.z < 0.5) {
+ ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+ }
+
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum += ambient_out;
+ } else {
+
+ vec4 ambient_out;
+ ambient_out.a = blend;
+ ambient_out.rgb = reflections.data[ref_index].ambient.rgb;
+ if (reflections.data[ref_index].params.z < 0.5) {
+ ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
+ }
+ ambient_out.rgb *= ambient_out.a;
+ ambient_accum += ambient_out;
+ }
+#endif //USE_LIGHTMAP or VCT
+}
+
+#ifdef USE_VOXEL_CONE_TRACING
+
+//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;
+}
+
+#ifndef GI_PROBE_HIGH_QUALITY
+//faster version for 45 degrees
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+
+vec4 voxel_cone_trace_anisotropic_45_degrees(texture3D probe, texture3D aniso_pos, texture3D aniso_neg, vec3 normal, 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);
+ vec3 aniso_neg = textureLod(sampler3D(aniso_neg, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
+ vec3 aniso_pos = textureLod(sampler3D(aniso_pos, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
+
+ scolor.rgb *= dot(max(vec3(0.0), (normal * aniso_pos)), vec3(1.0)) + dot(max(vec3(0.0), (-normal * aniso_neg)), vec3(1.0));
+ 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;
+}
+#else
+
+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;
+}
+
+#endif
+
+#elif defined(GI_PROBE_USE_ANISOTROPY)
+
+//standard voxel cone trace
+vec4 voxel_cone_trace_anisotropic(texture3D probe, texture3D aniso_pos, texture3D aniso_neg, vec3 normal, 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;
+ }
+ float log2_diameter = log2(diameter);
+ vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter);
+ vec3 aniso_neg = textureLod(sampler3D(aniso_neg, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
+ vec3 aniso_pos = textureLod(sampler3D(aniso_pos, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
+
+ scolor.rgb *= dot(max(vec3(0.0), (normal * aniso_pos)), vec3(1.0)) + dot(max(vec3(0.0), (-normal * aniso_neg)), vec3(1.0));
+
+ float a = (1.0 - color.a);
+ scolor *= a;
+ color += scolor;
+ dist += half_diameter;
+ }
+
+ return color;
+}
+
+#endif
+
+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
+
+#ifdef GI_PROBE_HIGH_QUALITY
+
+#define MAX_CONE_DIRS 6
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.0, 0.0, 1.0),
+ vec3(0.866025, 0.0, 0.5),
+ vec3(0.267617, 0.823639, 0.5),
+ vec3(-0.700629, 0.509037, 0.5),
+ vec3(-0.700629, -0.509037, 0.5),
+ vec3(0.267617, -0.823639, 0.5));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+ float cone_angle_tan = 0.577;
+
+#elif defined(GI_PROBE_LOW_QUALITY)
+
+#define MAX_CONE_DIRS 1
+
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
+ vec3(0.0, 0.0, 1.0));
+
+ float cone_weights[MAX_CONE_DIRS] = float[](1.0);
+ float cone_angle_tan = 4; //~76 degrees
+#else // MEDIUM QUALITY
+
+#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;
+
+#endif
+ 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);
+
+#if defined(GI_PROBE_HIGH_QUALITY) || defined(GI_PROBE_LOW_QUALITY)
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+ vec4 cone_light = voxel_cone_trace_anisotropic(gi_probe_textures[gi_probes.data[index].texture_slot], gi_probe_textures[gi_probes.data[index].texture_slot + 1], gi_probe_textures[gi_probes.data[index].texture_slot + 2], normalize(mix(dir, normal, gi_probes.data[index].anisotropy_strength)), cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#else
+
+ vec4 cone_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+
+#endif // GI_PROBE_USE_ANISOTROPY
+
+#else
+
+#ifdef GI_PROBE_USE_ANISOTROPY
+ vec4 cone_light = voxel_cone_trace_anisotropic_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot], gi_probe_textures[gi_probes.data[index].texture_slot + 1], gi_probe_textures[gi_probes.data[index].texture_slot + 2], normalize(mix(dir, normal, gi_probes.data[index].anisotropy_strength)), cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#else
+ vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
+#endif // GI_PROBE_USE_ANISOTROPY
+
+#endif
+ 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;
+
+ if (gi_probes.data[index].ambient_occlusion > 0.001) {
+
+ float size = 1.0 + gi_probes.data[index].ambient_occlusion_size * 7.0;
+
+ float taps, blend;
+ blend = modf(size, taps);
+ float ao = 0.0;
+ for (float i = 1.0; i <= taps; i++) {
+ vec3 ofs = (position + normal * (i * 0.5 + 1.0)) * cell_size;
+ ao += textureLod(sampler3D(gi_probe_textures[gi_probes.data[index].texture_slot], material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ofs, i - 1.0).a * i;
+ }
+
+ if (blend > 0.001) {
+ vec3 ofs = (position + normal * ((taps + 1.0) * 0.5 + 1.0)) * cell_size;
+ ao += textureLod(sampler3D(gi_probe_textures[gi_probes.data[index].texture_slot], material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ofs, taps).a * (taps + 1.0) * blend;
+ }
+
+ ao = 1.0 - min(1.0, ao);
+
+ light = mix(scene_data.ao_color.rgb, light, mix(1.0, ao, gi_probes.data[index].ambient_occlusion));
+ }
+
+ out_diff += vec4(light * blend, blend);
+
+ //irradiance
+#ifndef GI_PROBE_LOW_QUALITY
+ vec4 irr_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], 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);
+#endif
+}
+
+#endif //USE_VOXEL_CONE_TRACING
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+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);
+
+#if defined(AO_USED)
+ float ao = 1.0;
+ float ao_light_affect = 0.0;
+#endif
+
+ float alpha = 1.0;
+
+#if defined(ALPHA_SCISSOR_USED)
+ float alpha_scissor = 0.5;
+#endif
+
+#if defined(TANGENT_USED) || defined(NORMALMAP_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
+ vec3 normal = normalize(normal_interp);
+
+#if defined(DO_SIDE_CHECK)
+ if (!gl_FrontFacing) {
+ normal = -normal;
+ }
+#endif
+
+ vec2 uv = uv_interp;
+
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ vec2 uv2 = uv2_interp;
+#endif
+
+#if defined(COLOR_USED)
+ vec4 color = color_interp;
+#endif
+
+#if defined(NORMALMAP_USED)
+
+ vec3 normalmap = vec3(0.5);
+#endif
+
+ float normaldepth = 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;
+
+ {
+ /* clang-format off */
+
+FRAGMENT_SHADER_CODE
+
+ /* clang-format on */
+ }
+
+#if defined(LIGHT_TRANSMITTANCE_USED)
+#ifdef SSS_MODE_SKIN
+ transmittance_color.a = sss_strength;
+#else
+ transmittance_color.a *= sss_strength;
+#endif
+#endif
+
+#if !defined(USE_SHADOW_TO_OPACITY)
+
+#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
+
+#if defined(NORMALMAP_USED)
+
+ normalmap.xy = normalmap.xy * 2.0 - 1.0;
+ normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
+
+ normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth));
+
+#endif
+
+#if defined(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
+ /////////////////////// DECALS ////////////////////////////////
+
+#ifndef MODE_RENDER_DEPTH
+
+ uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)));
+ //used for interpolating anything cluster related
+ vec3 vertex_ddx = dFdx(vertex);
+ vec3 vertex_ddy = dFdy(vertex);
+
+ { // process decals
+
+ uint decal_count = cluster_cell.w >> CLUSTER_COUNTER_SHIFT;
+ uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK;
+
+ //do outside for performance and avoiding arctifacts
+
+ for (uint i = 0; i < decal_count; i++) {
+
+ uint decal_index = cluster_data.indices[decal_pointer + i];
+ if (!bool(decals.data[decal_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ 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;
+#if defined(AO_USED)
+ ao = mix(ao, decal_orm.r, decal_albedo.a);
+#endif
+ 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;
+ }
+ }
+ }
+
+#endif //not render depth
+ /////////////////////// LIGHTING //////////////////////////////
+
+ //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.roughness_limiter_enabled) {
+ float limit = texelFetch(sampler2D(roughness_buffer, material_samplers[SAMPLER_NEAREST_CLAMP]), ivec2(gl_FragCoord.xy), 0).r;
+ roughness = max(roughness, limit);
+ }
+
+ 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
+ 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;
+ }
+
+#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
+
+#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+
+ //radiance
+
+ float specular_blob_intensity = 1.0;
+
+#if defined(SPECULAR_TOON)
+ specular_blob_intensity *= specular * 2.0;
+#endif
+
+#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
+ //gi probes
+
+ //lightmap
+
+ //lightmap capture
+
+#ifdef USE_VOXEL_CONE_TRACING
+ { // process giprobes
+ uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
+ if (index1 != 0xFFFF) {
+ vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
+ //find arbitrary tangent and bitangent, then build a matrix
+ 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));
+ mat3 normal_mat = mat3(tangent, bitangent, normal);
+
+ vec4 amb_accum = vec4(0.0);
+ vec4 spec_accum = vec4(0.0);
+ gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
+
+ uint index2 = instances.data[instance_index].gi_offset >> 16;
+
+ if (index2 != 0xFFFF) {
+ gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
+ }
+
+ if (amb_accum.a > 0.0) {
+ amb_accum.rgb /= amb_accum.a;
+ }
+
+ if (spec_accum.a > 0.0) {
+ spec_accum.rgb /= spec_accum.a;
+ }
+
+ specular_light = spec_accum.rgb;
+ ambient_light = amb_accum.rgb;
+ }
+ }
+#endif
+
+ { // process reflections
+
+ 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_probe_count = cluster_cell.z >> CLUSTER_COUNTER_SHIFT;
+ uint reflection_probe_pointer = cluster_cell.z & CLUSTER_POINTER_MASK;
+
+ for (uint i = 0; i < reflection_probe_count; i++) {
+
+ uint ref_index = cluster_data.indices[reflection_probe_pointer + i];
+ reflection_process(ref_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;
+ }
+
+#if !defined(USE_LIGHTMAP)
+ if (ambient_accum.a > 0.0) {
+ ambient_light = ambient_accum.rgb / ambient_accum.a;
+ }
+#endif
+ }
+
+ {
+
+#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;
+
+ vec3 f0 = F0(metallic, specular, albedo);
+ specular_light *= env.x * f0 + env.y;
+#endif
+ }
+
+ { //directional light
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+
+ if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ vec3 shadow_attenuation = vec3(1.0);
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ float transmittance_z = transmittance_depth;
+#endif
+
+ 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;
+
+ float shadow = 0.0;
+
+ 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;
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ {
+ vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0);
+ vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex;
+ trans_coord /= trans_coord.w;
+
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x;
+ float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x;
+
+ transmittance_z = z - shadow_z;
+ }
+#endif
+ } 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;
+#ifdef LIGHT_TRANSMITTANCE_USED
+ {
+ vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0);
+ vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex;
+ trans_coord /= trans_coord.w;
+
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y;
+ float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y;
+
+ transmittance_z = z - shadow_z;
+ }
+#endif
+ } 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;
+#ifdef LIGHT_TRANSMITTANCE_USED
+ {
+ vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0);
+ vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex;
+ trans_coord /= trans_coord.w;
+
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z;
+ float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z;
+
+ transmittance_z = z - shadow_z;
+ }
+#endif
+
+ } 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;
+
+#ifdef LIGHT_TRANSMITTANCE_USED
+ {
+ vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0);
+ vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex;
+ trans_coord /= trans_coord.w;
+
+ float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r;
+ shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w;
+ float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w;
+
+ transmittance_z = z - shadow_z;
+ }
+#endif
+ }
+
+ 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
+
+ shadow_attenuation = mix(shadow_color, vec3(1.0), shadow);
+
+#undef BIAS_FUNC
+ }
+
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].size, directional_lights.data[i].color * directional_lights.data[i].energy, 1.0, shadow_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity,
+#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, rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha,
+#endif
+ diffuse_light,
+ specular_light);
+ }
+ }
+
+ { //omni lights
+
+ uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT;
+ uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK;
+
+ for (uint i = 0; i < omni_light_count; i++) {
+
+ uint light_index = cluster_data.indices[omni_light_pointer + i];
+
+ if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity,
+#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,
+#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
+ uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT;
+ uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK;
+
+ for (uint i = 0; i < spot_light_count; i++) {
+
+ uint light_index = cluster_data.indices[spot_light_pointer + i];
+
+ if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity,
+#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,
+#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);
+ }
+ }
+
+#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;
+
+#if defined(AO_USED)
+ orm_output_buffer.r = ao;
+#else
+ orm_output_buffer.r = 0.0;
+#endif
+ 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
+
+#ifdef MODE_RENDER_NORMAL
+ normal_output_buffer = vec4(normal * 0.5 + 0.5, 0.0);
+#ifdef MODE_RENDER_ROUGHNESS
+ roughness_output_buffer = roughness;
+#endif //MODE_RENDER_ROUGHNESS
+#endif //MODE_RENDER_NORMAL
+
+//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else
+
+ specular_light *= scene_data.reflection_multiplier;
+ ambient_light *= albedo; //ambient must be multiplied by albedo at the end
+
+//ambient occlusion
+#if defined(AO_USED)
+
+ if (scene_data.ssao_enabled && scene_data.ssao_ao_affect > 0.0) {
+ float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
+ ao = mix(ao, min(ao, ssao), scene_data.ssao_ao_affect);
+ ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect);
+ }
+
+ ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao);
+ ao_light_affect = mix(1.0, ao, ao_light_affect);
+ specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect);
+ diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect);
+
+#else
+
+ if (scene_data.ssao_enabled) {
+ float ao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
+ ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao);
+ float ao_light_affect = mix(1.0, ao, scene_data.ssao_light_affect);
+ specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect);
+ diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect);
+ }
+
+#endif // AO_USED
+
+ // base color remapping
+ diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point
+ ambient_light *= 1.0 - metallic;
+
+ //fog
+
+#ifdef MODE_MULTIPLE_RENDER_TARGETS
+
+#ifdef MODE_UNSHADED
+ diffuse_buffer = vec4(albedo.rgb, 0.0);
+ specular_buffer = vec4(0.0);
+
+#else
+
+#ifdef SSS_MODE_SKIN
+ sss_strength = -sss_strength;
+#endif
+ diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength);
+ specular_buffer = vec4(specular_light, metallic);
+
+#endif
+
+#else //MODE_MULTIPLE_RENDER_TARGETS
+
+#ifdef MODE_UNSHADED
+ frag_color = vec4(albedo, alpha);
+#else
+ frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
+ //frag_color = vec4(1.0);
+
+#endif //USE_NO_SHADING
+
+#endif //MODE_MULTIPLE_RENDER_TARGETS
+
+#endif //MODE_RENDER_DEPTH
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
new file mode 100644
index 0000000000..b5e3de5e82
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl
@@ -0,0 +1,325 @@
+#define M_PI 3.14159265359
+#define ROUGHNESS_MAX_LOD 5
+
+layout(push_constant, binding = 0, std430) uniform DrawCall {
+ uint instance_index;
+ uint pad[3]; //16 bits minimum size
+}
+draw_call;
+
+/* Set 0 Scene data that never changes, ever */
+
+#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;
+
+layout(set = 0, binding = 3, std140) uniform SceneData {
+
+ mat4 projection_matrix;
+ mat4 inv_projection_matrix;
+
+ mat4 camera_matrix;
+ mat4 inv_camera_matrix;
+
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
+
+ float time;
+ float reflection_multiplier; // one normally, zero when rendering reflections
+
+ bool pancake_shadows;
+ uint pad;
+
+ //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;
+
+ vec4 ao_color;
+
+#if 0
+ vec4 ambient_light_color;
+ vec4 bg_color;
+
+ vec4 fog_color_enabled;
+ vec4 fog_sun_color_amount;
+
+ float ambient_energy;
+ float bg_energy;
+#endif
+
+#if 0
+ vec2 shadow_atlas_pixel_size;
+ vec2 directional_shadow_pixel_size;
+
+ float z_far;
+
+ float subsurface_scatter_width;
+ float ambient_occlusion_affect_light;
+ float ambient_occlusion_affect_ao_channel;
+ float opaque_prepass_threshold;
+
+ bool fog_depth_enabled;
+ float fog_depth_begin;
+ float fog_depth_end;
+ float fog_density;
+ float fog_depth_curve;
+ bool fog_transmit_enabled;
+ float fog_transmit_curve;
+ bool fog_height_enabled;
+ float fog_height_min;
+ float fog_height_max;
+ float fog_height_curve;
+#endif
+}
+scene_data;
+
+#define INSTANCE_FLAGS_FORWARD_MASK 0x7
+#define INSTANCE_FLAGS_FORWARD_OMNI_LIGHT_SHIFT 3
+#define INSTANCE_FLAGS_FORWARD_SPOT_LIGHT_SHIFT 6
+#define INSTANCE_FLAGS_FORWARD_DECAL_SHIFT 9
+
+#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_MULTIMESH_STRIDE_SHIFT 16
+//3 bits of stride
+#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7
+
+#define INSTANCE_FLAGS_SKELETON (1 << 19)
+
+struct InstanceData {
+ mat4 transform;
+ mat4 normal_transform;
+ uint flags;
+ uint instance_ofs; //instance_offset in instancing/skeleton buffer
+ uint gi_offset; //GI information when using lightmapping (VCT or lightmap)
+ uint layer_mask;
+};
+
+layout(set = 0, binding = 4, std430) restrict readonly buffer Instances {
+ InstanceData data[];
+}
+instances;
+
+struct LightData { //this structure needs to be as packed as possible
+ vec3 position;
+ float inv_radius;
+ vec3 direction;
+ float size;
+ uint attenuation_energy; //attenuation
+ uint color_specular; //rgb color, a specular (8 bit unorm)
+ uint cone_attenuation_angle; // attenuation and angle, (16bit float)
+ uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
+ 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;
+ uint pad[2];
+ vec4 projector_rect; //projector rect in srgb decal atlas
+};
+
+layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
+ LightData data[];
+}
+lights;
+
+struct ReflectionData {
+
+ vec3 box_extents;
+ float index;
+ vec3 box_offset;
+ uint mask;
+ vec4 params; // intensity, 0, interior , boxproject
+ vec4 ambient; // ambient color, energy
+ 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
+};
+
+layout(set = 0, binding = 6, std140) uniform ReflectionProbeData {
+ ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
+}
+reflections;
+
+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;
+ vec4 shadow_bias;
+ vec4 shadow_normal_bias;
+ vec4 shadow_transmittance_bias;
+ vec4 shadow_transmittance_z_scale;
+ 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;
+};
+
+layout(set = 0, binding = 7, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+struct GIProbeData {
+ mat4 xform;
+ vec3 bounds;
+ float dynamic_range;
+
+ float bias;
+ float normal_bias;
+ bool blend_ambient;
+ uint texture_slot;
+
+ float anisotropy_strength;
+ float ambient_occlusion;
+ float ambient_occlusion_size;
+ uint pad2;
+};
+
+layout(set = 0, binding = 8, std140) uniform GIProbes {
+ GIProbeData data[MAX_GI_PROBES];
+}
+gi_probes;
+
+layout(set = 0, binding = 9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TEXTURES];
+
+#define CLUSTER_COUNTER_SHIFT 20
+#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
+#define CLUSTER_COUNTER_MASK 0xfff
+
+layout(set = 0, binding = 10) uniform texture2D decal_atlas;
+layout(set = 0, binding = 11) uniform texture2D decal_atlas_srgb;
+
+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;
+};
+
+layout(set = 0, binding = 12, std430) restrict readonly buffer Decals {
+ DecalData data[];
+}
+decals;
+
+layout(set = 0, binding = 13) uniform utexture3D cluster_texture;
+
+layout(set = 0, binding = 14, std430) restrict readonly buffer ClusterData {
+ uint indices[];
+}
+cluster_data;
+
+layout(set = 0, binding = 15) uniform texture2D directional_shadow_atlas;
+
+// decal atlas
+
+/* Set 1, Radiance */
+
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+
+layout(set = 1, binding = 0) uniform textureCubeArray radiance_cubemap;
+
+#else
+
+layout(set = 1, binding = 0) uniform textureCube radiance_cubemap;
+
+#endif
+
+/* Set 2, Reflection and Shadow Atlases (view dependant) */
+
+layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas;
+
+layout(set = 2, binding = 1) uniform texture2D shadow_atlas;
+
+/* Set 1, Render Buffers */
+
+layout(set = 3, binding = 0) uniform texture2D depth_buffer;
+layout(set = 3, binding = 1) uniform texture2D color_buffer;
+layout(set = 3, binding = 2) uniform texture2D normal_buffer;
+layout(set = 3, binding = 3) uniform texture2D roughness_buffer;
+layout(set = 3, binding = 4) uniform texture2D ao_buffer;
+
+/* Set 4 Skeleton & Instancing (Multimesh) */
+
+layout(set = 4, binding = 0, std430) restrict readonly buffer Transforms {
+ vec4 data[];
+}
+transforms;
+
+/* Set 5 User Material */
diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl
new file mode 100644
index 0000000000..e3c26c9b72
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection.glsl
@@ -0,0 +1,262 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+/* clang-format on */
+
+layout(rgba16f, set = 0, binding = 0) uniform restrict readonly image2D source_diffuse;
+layout(r32f, set = 0, binding = 1) uniform restrict readonly image2D source_depth;
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D ssr_image;
+#ifdef MODE_ROUGH
+layout(r8, set = 1, binding = 1) uniform restrict writeonly image2D blur_radius_image;
+#endif
+layout(rgba8, set = 2, binding = 0) uniform restrict readonly image2D source_normal;
+layout(set = 3, binding = 0) uniform sampler2D source_metallic;
+#ifdef MODE_ROUGH
+layout(set = 3, binding = 1) uniform sampler2D source_roughness;
+#endif
+
+layout(push_constant, binding = 2, std430) uniform Params {
+
+ vec4 proj_info;
+
+ ivec2 screen_size;
+ float camera_z_near;
+ float camera_z_far;
+
+ int num_steps;
+ float depth_tolerance;
+ float distance_fade;
+ float curve_fade_in;
+
+ bool orthogonal;
+ float filter_mipmap_levels;
+ bool use_half_res;
+ uint metallic_mask;
+
+ mat4 projection;
+}
+params;
+
+vec2 view_to_screen(vec3 view_pos, out float w) {
+ vec4 projected = params.projection * vec4(view_pos, 1.0);
+ projected.xyz /= projected.w;
+ projected.xy = projected.xy * 0.5 + 0.5;
+ w = projected.w;
+ return projected.xy;
+}
+
+#define M_PI 3.14159265359
+
+vec3 reconstructCSPosition(vec2 S, float z) {
+ if (params.orthogonal) {
+ return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z);
+ } else {
+ return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
+ }
+}
+
+void main() {
+
+ // Pixel being shaded
+ ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
+
+ if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing
+ return;
+ }
+
+ vec2 pixel_size = 1.0 / vec2(params.screen_size);
+ vec2 uv = vec2(ssC) * pixel_size;
+
+ uv += pixel_size * 0.5;
+
+ float base_depth = imageLoad(source_depth, ssC).r;
+
+ // World space point being shaded
+ vec3 vertex = reconstructCSPosition(uv * vec2(params.screen_size), base_depth);
+
+ vec3 normal = imageLoad(source_normal, ssC).xyz * 2.0 - 1.0;
+ normal = normalize(normal);
+ normal.y = -normal.y; //because this code reads flipped
+
+ vec3 view_dir = normalize(vertex);
+ vec3 ray_dir = normalize(reflect(view_dir, normal));
+
+ if (dot(ray_dir, normal) < 0.001) {
+ imageStore(ssr_image, ssC, vec4(0.0));
+ return;
+ }
+ //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0);
+ //ray_dir = normalize(vec3(1.0, 1.0, -1.0));
+
+ ////////////////
+
+ // make ray length and clip it against the near plane (don't want to trace beyond visible)
+ float ray_len = (vertex.z + ray_dir.z * params.camera_z_far) > -params.camera_z_near ? (-params.camera_z_near - vertex.z) / ray_dir.z : params.camera_z_far;
+ vec3 ray_end = vertex + ray_dir * ray_len;
+
+ float w_begin;
+ vec2 vp_line_begin = view_to_screen(vertex, w_begin);
+ float w_end;
+ vec2 vp_line_end = view_to_screen(ray_end, w_end);
+ vec2 vp_line_dir = vp_line_end - vp_line_begin;
+
+ // we need to interpolate w along the ray, to generate perspective correct reflections
+ w_begin = 1.0 / w_begin;
+ w_end = 1.0 / w_end;
+
+ float z_begin = vertex.z * w_begin;
+ float z_end = ray_end.z * w_end;
+
+ vec2 line_begin = vp_line_begin / pixel_size;
+ vec2 line_dir = vp_line_dir / pixel_size;
+ float z_dir = z_end - z_begin;
+ float w_dir = w_end - w_begin;
+
+ // clip the line to the viewport edges
+
+ float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x));
+ float scale_max_y = min(1.0, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y));
+ float scale_min_x = min(1.0, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x));
+ float scale_min_y = min(1.0, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y));
+ float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y);
+ line_dir *= line_clip;
+ z_dir *= line_clip;
+ w_dir *= line_clip;
+
+ // clip z and w advance to line advance
+ vec2 line_advance = normalize(line_dir); // down to pixel
+ float step_size = length(line_advance) / length(line_dir);
+ float z_advance = z_dir * step_size; // adapt z advance to line advance
+ float w_advance = w_dir * step_size; // adapt w advance to line advance
+
+ // make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice)
+ float advance_angle_adj = 1.0 / max(abs(line_advance.x), abs(line_advance.y));
+ line_advance *= advance_angle_adj; // adapt z advance to line advance
+ z_advance *= advance_angle_adj;
+ w_advance *= advance_angle_adj;
+
+ vec2 pos = line_begin;
+ float z = z_begin;
+ float w = w_begin;
+ float z_from = z / w;
+ float z_to = z_from;
+ float depth;
+ vec2 prev_pos = pos;
+
+ bool found = false;
+
+ float steps_taken = 0.0;
+
+ for (int i = 0; i < params.num_steps; i++) {
+
+ pos += line_advance;
+ z += z_advance;
+ w += w_advance;
+
+ // convert to linear depth
+
+ depth = imageLoad(source_depth, ivec2(pos - 0.5)).r;
+
+ if (-depth >= params.camera_z_far) { //went beyond camera
+ break;
+ }
+
+ z_from = z_to;
+ z_to = z / w;
+
+ if (depth > z_to) {
+ // if depth was surpassed
+ if (depth <= max(z_to, z_from) + params.depth_tolerance) {
+ // check the depth tolerance
+ //check that normal is valid
+ found = true;
+ }
+ break;
+ }
+
+ steps_taken += 1.0;
+ prev_pos = pos;
+ }
+
+ if (found) {
+
+ float margin_blend = 1.0;
+
+ vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.5 * 0.05); // make a uniform margin
+ if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, params.screen_size + margin)))) {
+ // clip outside screen + margin
+ imageStore(ssr_image, ssC, vec4(0.0));
+ return;
+ }
+
+ {
+ //blend fading out towards external margin
+ vec2 margin_grad = mix(pos - params.screen_size, -pos, lessThan(pos, vec2(0.0)));
+ margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y));
+ //margin_blend = 1.0;
+ }
+
+ vec2 final_pos;
+ float grad;
+ grad = steps_taken / float(params.num_steps);
+ float initial_fade = params.curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), params.curve_fade_in);
+ float fade = pow(clamp(1.0 - grad, 0.0, 1.0), params.distance_fade) * initial_fade;
+ final_pos = pos;
+
+ vec4 final_color;
+
+#ifdef MODE_ROUGH
+
+ // if roughness is enabled, do screen space cone tracing
+ float blur_radius = 0.0;
+ float roughness = texelFetch(source_roughness, ssC << 1, 0).r;
+
+ if (roughness > 0.001) {
+
+ float cone_angle = min(roughness, 0.999) * M_PI * 0.5;
+ float cone_len = length(final_pos - line_begin);
+ float op_len = 2.0 * tan(cone_angle) * cone_len; // opposite side of iso triangle
+ {
+ // fit to sphere inside cone (sphere ends at end of cone), something like this:
+ // ___
+ // \O/
+ // V
+ //
+ // as it avoids bleeding from beyond the reflection as much as possible. As a plus
+ // it also makes the rough reflection more elongated.
+ float a = op_len;
+ float h = cone_len;
+ float a2 = a * a;
+ float fh2 = 4.0f * h * h;
+ blur_radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h);
+ }
+ }
+
+ final_color = imageLoad(source_diffuse, ivec2((final_pos - 0.5) * pixel_size));
+
+ imageStore(blur_radius_image, ssC, vec4(blur_radius / 255.0)); //stored in r8
+
+#endif
+
+ final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend);
+ //change blend by metallic
+ vec4 metallic_mask = unpackUnorm4x8(params.metallic_mask);
+ final_color.a *= dot(metallic_mask, texelFetch(source_metallic, ssC << 1, 0));
+
+ imageStore(ssr_image, ssC, final_color);
+
+ } else {
+#ifdef MODE_ROUGH
+ imageStore(blur_radius_image, ssC, vec4(0.0));
+#endif
+ imageStore(ssr_image, ssC, vec4(0.0));
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl
new file mode 100644
index 0000000000..1a5dd5ab55
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl
@@ -0,0 +1,164 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+/* clang-format on */
+
+layout(rgba16f, set = 0, binding = 0) uniform restrict readonly image2D source_ssr;
+layout(r8, set = 0, binding = 1) uniform restrict readonly image2D source_radius;
+layout(rgba8, set = 1, binding = 0) uniform restrict readonly image2D source_normal;
+
+layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_ssr;
+#ifndef VERTICAL_PASS
+layout(r8, set = 2, binding = 1) uniform restrict writeonly image2D dest_radius;
+#endif
+layout(r32f, set = 3, binding = 0) uniform restrict readonly image2D source_depth;
+
+layout(push_constant, binding = 2, std430) uniform Params {
+
+ vec4 proj_info;
+
+ bool orthogonal;
+ float edge_tolerance;
+ int increment;
+ uint pad;
+
+ ivec2 screen_size;
+ bool vertical;
+ uint steps;
+}
+params;
+
+#define GAUSS_TABLE_SIZE 15
+
+const float gauss_table[GAUSS_TABLE_SIZE + 1] = float[](
+ 0.1847392078702266,
+ 0.16595854345772326,
+ 0.12031364177766891,
+ 0.07038755277896766,
+ 0.03322925565155569,
+ 0.012657819729901945,
+ 0.0038903040680094217,
+ 0.0009646503390864025,
+ 0.00019297087402915717,
+ 0.000031139936308099136,
+ 0.000004053309048174758,
+ 4.255228059965837e-7,
+ 3.602517634249573e-8,
+ 2.4592560765896795e-9,
+ 1.3534945386863618e-10,
+ 0.0 //one more for interpolation
+);
+
+float gauss_weight(float p_val) {
+
+ float idxf;
+ float c = modf(max(0.0, p_val * float(GAUSS_TABLE_SIZE)), idxf);
+ int idx = int(idxf);
+ if (idx >= GAUSS_TABLE_SIZE + 1) {
+ return 0.0;
+ }
+
+ return mix(gauss_table[idx], gauss_table[idx + 1], c);
+}
+
+#define M_PI 3.14159265359
+
+vec3 reconstructCSPosition(vec2 S, float z) {
+ if (params.orthogonal) {
+ return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z);
+ } else {
+ return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
+ }
+}
+
+void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor, ivec2 texcoord, ivec2 increment, vec3 p_pos, vec3 normal, float p_limit_radius) {
+
+ for (int i = 1; i < params.steps; i++) {
+ float d = float(i * params.increment);
+ ivec2 tc = texcoord + increment * i;
+ float depth = imageLoad(source_depth, tc).r;
+ vec3 view_pos = reconstructCSPosition(vec2(tc) + 0.5, depth);
+ vec3 view_normal = normalize(imageLoad(source_normal, tc).rgb * 2.0 - 1.0);
+ view_normal.y = -view_normal.y;
+
+ float r = imageLoad(source_radius, tc).r;
+ float radius = round(r * 255.0);
+
+ float angle_n = 1.0 - abs(dot(normal, view_normal));
+ if (angle_n > params.edge_tolerance) {
+ break;
+ }
+
+ float angle = abs(dot(normal, normalize(view_pos - p_pos)));
+
+ if (angle > params.edge_tolerance) {
+ break;
+ }
+
+ if (d < radius) {
+
+ float w = gauss_weight(d / radius);
+ accum += imageLoad(source_ssr, tc) * w;
+#ifndef VERTICAL_PASS
+ accum_radius += r * w;
+#endif
+ divisor += w;
+ }
+ }
+}
+
+void main() {
+
+ // Pixel being shaded
+ ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
+
+ if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing
+ return;
+ }
+
+ float base_contrib = gauss_table[0];
+
+ vec4 accum = imageLoad(source_ssr, ssC);
+
+ float accum_radius = imageLoad(source_radius, ssC).r;
+ float radius = accum_radius * 255.0;
+
+ float divisor = gauss_table[0];
+ accum *= divisor;
+ accum_radius *= divisor;
+#ifdef VERTICAL_PASS
+ ivec2 direction = ivec2(0, params.increment);
+#else
+ ivec2 direction = ivec2(params.increment, 0);
+#endif
+ float depth = imageLoad(source_depth, ssC).r;
+ vec3 pos = reconstructCSPosition(vec2(ssC) + 0.5, depth);
+ vec3 normal = imageLoad(source_normal, ssC).xyz * 2.0 - 1.0;
+ normal = normalize(normal);
+ normal.y = -normal.y;
+
+ do_filter(accum, accum_radius, divisor, ssC, direction, pos, normal, radius);
+ do_filter(accum, accum_radius, divisor, ssC, -direction, pos, normal, radius);
+
+ if (divisor > 0.0) {
+ accum /= divisor;
+ accum_radius /= divisor;
+ } else {
+ accum = vec4(0.0);
+ accum_radius = 0.0;
+ }
+
+ imageStore(dest_ssr, ssC, accum);
+
+#ifndef VERTICAL_PASS
+ imageStore(dest_radius, ssC, vec4(accum_radius));
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl
new file mode 100644
index 0000000000..cec6c14c76
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl
@@ -0,0 +1,96 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_ssr;
+layout(set = 1, binding = 0) uniform sampler2D source_depth;
+layout(set = 1, binding = 1) uniform sampler2D source_normal;
+layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_ssr;
+layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_depth;
+layout(rgba8, set = 3, binding = 1) uniform restrict writeonly image2D dest_normal;
+
+layout(push_constant, binding = 1, std430) uniform Params {
+
+ ivec2 screen_size;
+ float camera_z_near;
+ float camera_z_far;
+
+ bool orthogonal;
+ bool filtered;
+ uint pad[2];
+}
+params;
+
+void main() {
+
+ // Pixel being shaded
+ ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
+
+ if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing
+ return;
+ }
+ //do not filter, SSR will generate arctifacts if this is done
+
+ float divisor = 0.0;
+ vec4 color;
+ float depth;
+ vec3 normal;
+
+ if (params.filtered) {
+
+ color = vec4(0.0);
+ depth = 0.0;
+ normal = vec3(0.0);
+
+ for (int i = 0; i < 4; i++) {
+
+ ivec2 ofs = ssC << 1;
+ if (bool(i & 1)) {
+ ofs.x += 1;
+ }
+ if (bool(i & 2)) {
+ ofs.y += 1;
+ }
+ color += texelFetch(source_ssr, ofs, 0);
+ float d = texelFetch(source_depth, ofs, 0).r;
+ normal += texelFetch(source_normal, ofs, 0).xyz * 2.0 - 1.0;
+
+ d = d * 2.0 - 1.0;
+ if (params.orthogonal) {
+ d = ((d + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+ } else {
+ d = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - d * (params.camera_z_far - params.camera_z_near));
+ }
+ depth += -d;
+ }
+
+ color /= 4.0;
+ depth /= 4.0;
+ normal = normalize(normal / 4.0) * 0.5 + 0.5;
+
+ } else {
+ color = texelFetch(source_ssr, ssC << 1, 0);
+ depth = texelFetch(source_depth, ssC << 1, 0).r;
+ normal = texelFetch(source_normal, ssC << 1, 0).xyz;
+
+ depth = depth * 2.0 - 1.0;
+ if (params.orthogonal) {
+ depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+ } else {
+ depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+ }
+ depth = -depth;
+ }
+
+ imageStore(dest_ssr, ssC, color);
+ imageStore(dest_depth, ssC, vec4(depth));
+ imageStore(dest_normal, ssC, vec4(normal, 0.0));
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/sky.glsl b/servers/rendering/rasterizer_rd/shaders/sky.glsl
new file mode 100644
index 0000000000..c6c863ec60
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/sky.glsl
@@ -0,0 +1,187 @@
+/* clang-format off */
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ mat3 orientation;
+ vec4 proj;
+ vec4 position_multiplier;
+ float time;
+}
+params;
+
+void main() {
+
+ vec2 base_arr[4] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(1.0, -1.0));
+ uv_interp = base_arr[gl_VertexIndex];
+ gl_Position = vec4(uv_interp, 1.0, 1.0);
+}
+
+/* clang-format off */
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+#define M_PI 3.14159265359
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ mat3 orientation;
+ vec4 proj;
+ vec4 position_multiplier;
+ float time; //TODO consider adding vec2 screen res, and float radiance size
+}
+params;
+
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
+layout(set = 0, binding = 0) uniform sampler material_samplers[12];
+
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
+ /* clang-format off */
+
+MATERIAL_UNIFORMS
+
+ /* clang-format on */
+} material;
+#endif
+
+layout(set = 2, binding = 0) uniform textureCube radiance;
+#ifdef USE_CUBEMAP_PASS
+layout(set = 2, binding = 1) uniform textureCube half_res;
+layout(set = 2, binding = 2) uniform textureCube quarter_res;
+#else
+layout(set = 2, binding = 1) uniform texture2D half_res;
+layout(set = 2, binding = 2) uniform texture2D quarter_res;
+#endif
+
+#ifdef USE_CUBEMAP_PASS
+#define AT_CUBEMAP_PASS true
+#else
+#define AT_CUBEMAP_PASS false
+#endif
+
+#ifdef USE_HALF_RES_PASS
+#define AT_HALF_RES_PASS true
+#else
+#define AT_HALF_RES_PASS false
+#endif
+
+#ifdef USE_QUARTER_RES_PASS
+#define AT_QUARTER_RES_PASS true
+#else
+#define AT_QUARTER_RES_PASS false
+#endif
+
+struct DirectionalLightData {
+ vec3 direction;
+ float energy;
+ vec3 color;
+ bool enabled;
+};
+
+layout(set = 3, binding = 0, std140) uniform DirectionalLights {
+ DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+directional_lights;
+
+/* clang-format off */
+
+FRAGMENT_SHADER_GLOBALS
+
+/* clang-format on */
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+ vec3 cube_normal;
+ cube_normal.z = -1.0;
+ cube_normal.x = (cube_normal.z * (-uv_interp.x - params.proj.x)) / params.proj.y;
+ cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.proj.z)) / params.proj.w;
+ cube_normal = mat3(params.orientation) * cube_normal;
+ cube_normal.z = -cube_normal.z;
+ cube_normal = normalize(cube_normal);
+
+ vec2 uv = uv_interp * 0.5 + 0.5;
+
+ vec2 panorama_coords = vec2(atan(cube_normal.x, cube_normal.z), acos(cube_normal.y));
+
+ if (panorama_coords.x < 0.0) {
+ panorama_coords.x += M_PI * 2.0;
+ }
+
+ panorama_coords /= vec2(M_PI * 2.0, M_PI);
+
+ vec3 color = vec3(0.0, 0.0, 0.0);
+ float alpha = 1.0; // Only available to subpasses
+ vec4 half_res_color = vec4(1.0);
+ vec4 quarter_res_color = vec4(1.0);
+
+#ifdef USE_CUBEMAP_PASS
+ vec3 inverted_cube_normal = cube_normal;
+ inverted_cube_normal.z *= -1.0;
+#ifdef USES_HALF_RES_COLOR
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+#endif
+#ifdef USES_QUARTER_RES_COLOR
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
+#endif
+#else
+#ifdef USES_HALF_RES_COLOR
+ half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+#endif
+#ifdef USES_QUARTER_RES_COLOR
+ quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
+#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
+
+ /* clang-format on */
+ }
+
+ frag_color.rgb = color * params.position_multiplier.w;
+ frag_color.a = alpha;
+
+ // Blending is disabled for Sky, so alpha doesn't blend
+ // alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
+ if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
+ frag_color.a = 0.0;
+ }
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl b/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl
new file mode 100644
index 0000000000..b28250318e
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/specular_merge.glsl
@@ -0,0 +1,59 @@
+/* clang-format off */
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D specular;
+
+#ifdef MODE_SSR
+
+layout(set = 1, binding = 0) uniform sampler2D ssr;
+
+#endif
+
+#ifdef MODE_MERGE
+
+layout(set = 2, binding = 0) uniform sampler2D diffuse;
+
+#endif
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+
+ frag_color.rgb = texture(specular, uv_interp).rgb;
+ frag_color.a = 0.0;
+#ifdef MODE_SSR
+
+ vec4 ssr = texture(ssr, uv_interp);
+ frag_color.rgb = mix(frag_color.rgb, ssr.rgb, ssr.a);
+#endif
+
+#ifdef MODE_MERGE
+ frag_color += texture(diffuse, uv_interp);
+#endif
+ //added using additive blend
+}
diff --git a/servers/visual/rasterizer_rd/shaders/ssao.glsl b/servers/rendering/rasterizer_rd/shaders/ssao.glsl
index c9d7134610..c9d7134610 100644
--- a/servers/visual/rasterizer_rd/shaders/ssao.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/ssao.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/ssao_blur.glsl b/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl
index e90c788e08..e90c788e08 100644
--- a/servers/visual/rasterizer_rd/shaders/ssao_blur.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl
diff --git a/servers/visual/rasterizer_rd/shaders/ssao_minify.glsl b/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl
index 8728154347..8728154347 100644
--- a/servers/visual/rasterizer_rd/shaders/ssao_minify.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl
diff --git a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl
new file mode 100644
index 0000000000..41f8fde3ca
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl
@@ -0,0 +1,198 @@
+/* clang-format off */
+[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+/* clang-format on */
+
+#ifdef USE_25_SAMPLES
+const int kernel_size = 13;
+
+const vec2 kernel[kernel_size] = vec2[](
+ vec2(0.530605, 0.0),
+ vec2(0.0211412, 0.0208333),
+ vec2(0.0402784, 0.0833333),
+ vec2(0.0493588, 0.1875),
+ vec2(0.0410172, 0.333333),
+ vec2(0.0263642, 0.520833),
+ vec2(0.017924, 0.75),
+ vec2(0.0128496, 1.02083),
+ vec2(0.0094389, 1.33333),
+ vec2(0.00700976, 1.6875),
+ vec2(0.00500364, 2.08333),
+ vec2(0.00333804, 2.52083),
+ vec2(0.000973794, 3.0));
+
+const vec4 skin_kernel[kernel_size] = vec4[](
+ vec4(0.530605, 0.613514, 0.739601, 0),
+ vec4(0.0211412, 0.0459286, 0.0378196, 0.0208333),
+ vec4(0.0402784, 0.0657244, 0.04631, 0.0833333),
+ vec4(0.0493588, 0.0367726, 0.0219485, 0.1875),
+ vec4(0.0410172, 0.0199899, 0.0118481, 0.333333),
+ vec4(0.0263642, 0.0119715, 0.00684598, 0.520833),
+ vec4(0.017924, 0.00711691, 0.00347194, 0.75),
+ vec4(0.0128496, 0.00356329, 0.00132016, 1.02083),
+ vec4(0.0094389, 0.00139119, 0.000416598, 1.33333),
+ vec4(0.00700976, 0.00049366, 0.000151938, 1.6875),
+ vec4(0.00500364, 0.00020094, 5.28848e-005, 2.08333),
+ vec4(0.00333804, 7.85443e-005, 1.2945e-005, 2.52083),
+ vec4(0.000973794, 1.11862e-005, 9.43437e-007, 3));
+
+#endif //USE_25_SAMPLES
+
+#ifdef USE_17_SAMPLES
+const int kernel_size = 9;
+const vec2 kernel[kernel_size] = vec2[](
+ vec2(0.536343, 0.0),
+ vec2(0.0324462, 0.03125),
+ vec2(0.0582416, 0.125),
+ vec2(0.0571056, 0.28125),
+ vec2(0.0347317, 0.5),
+ vec2(0.0216301, 0.78125),
+ vec2(0.0144609, 1.125),
+ vec2(0.0100386, 1.53125),
+ vec2(0.00317394, 2.0));
+
+const vec4 skin_kernel[kernel_size] = vec4[](
+ vec4(0.536343, 0.624624, 0.748867, 0),
+ vec4(0.0324462, 0.0656718, 0.0532821, 0.03125),
+ vec4(0.0582416, 0.0659959, 0.0411329, 0.125),
+ vec4(0.0571056, 0.0287432, 0.0172844, 0.28125),
+ vec4(0.0347317, 0.0151085, 0.00871983, 0.5),
+ vec4(0.0216301, 0.00794618, 0.00376991, 0.78125),
+ vec4(0.0144609, 0.00317269, 0.00106399, 1.125),
+ vec4(0.0100386, 0.000914679, 0.000275702, 1.53125),
+ vec4(0.00317394, 0.000134823, 3.77269e-005, 2));
+#endif //USE_17_SAMPLES
+
+#ifdef USE_11_SAMPLES
+const int kernel_size = 6;
+const vec2 kernel[kernel_size] = vec2[](
+ vec2(0.560479, 0.0),
+ vec2(0.0771802, 0.08),
+ vec2(0.0821904, 0.32),
+ vec2(0.03639, 0.72),
+ vec2(0.0192831, 1.28),
+ vec2(0.00471691, 2.0));
+
+const vec4 skin_kernel[kernel_size] = vec4[](
+
+ vec4(0.560479, 0.669086, 0.784728, 0),
+ vec4(0.0771802, 0.113491, 0.0793803, 0.08),
+ vec4(0.0821904, 0.0358608, 0.0209261, 0.32),
+ vec4(0.03639, 0.0130999, 0.00643685, 0.72),
+ vec4(0.0192831, 0.00282018, 0.00084214, 1.28),
+ vec4(0.00471691, 0.000184771, 5.07565e-005, 2));
+
+#endif //USE_11_SAMPLES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+
+ ivec2 screen_size;
+ float camera_z_far;
+ float camera_z_near;
+
+ bool vertical;
+ bool orthogonal;
+ float unit_size;
+ float scale;
+
+ float depth_scale;
+ uint pad[3];
+}
+params;
+
+layout(set = 0, binding = 0) uniform sampler2D source_image;
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_image;
+layout(set = 2, binding = 0) uniform sampler2D source_depth;
+
+void do_filter(inout vec3 color_accum, inout vec3 divisor, vec2 uv, vec2 step, bool p_skin) {
+
+ // Accumulate the other samples:
+ for (int i = 1; i < kernel_size; i++) {
+ // Fetch color and depth for current sample:
+ vec2 offset = uv + kernel[i].y * step;
+ vec4 color = texture(source_image, offset);
+
+ if (abs(color.a) < 0.001) {
+ break; //mix no more
+ }
+
+ vec3 w;
+ if (p_skin) {
+ //skin
+ w = skin_kernel[i].rgb;
+ } else {
+ w = vec3(kernel[i].x);
+ }
+
+ color_accum += color.rgb * w;
+ divisor += w;
+ }
+}
+
+void main() {
+
+ // Pixel being shaded
+ ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
+
+ if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing
+ return;
+ }
+
+ vec2 uv = (vec2(ssC) + 0.5) / vec2(params.screen_size);
+
+ // Fetch color of current pixel:
+ vec4 base_color = texture(source_image, uv);
+ float strength = abs(base_color.a);
+
+ if (strength > 0.0) {
+
+ vec2 dir = params.vertical ? vec2(0.0, 1.0) : vec2(1.0, 0.0);
+
+ // Fetch linear depth of current pixel:
+ float depth = texture(source_depth, uv).r * 2.0 - 1.0;
+ float depth_scale;
+
+ if (params.orthogonal) {
+ depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+ depth_scale = params.unit_size; //remember depth is negative by default in OpenGL
+ } else {
+ depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+ depth_scale = params.unit_size / depth; //remember depth is negative by default in OpenGL
+ }
+
+ float scale = mix(params.scale, depth_scale, params.depth_scale);
+
+ // Calculate the final step to fetch the surrounding pixels:
+ vec2 step = scale * dir;
+ step *= strength;
+ step /= 3.0;
+ // Accumulate the center sample:
+
+ vec3 divisor;
+ bool skin = bool(base_color.a < 0.0);
+
+ if (skin) {
+ //skin
+ divisor = skin_kernel[0].rgb;
+ } else {
+ divisor = vec3(kernel[0].x);
+ }
+
+ vec3 color = base_color.rgb * divisor;
+
+ do_filter(color, divisor, uv, step, skin);
+ do_filter(color, divisor, uv, -step, skin);
+
+ base_color.rgb = color / divisor;
+ }
+
+ imageStore(dest_image, ssC, base_color);
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/tonemap.glsl b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
new file mode 100644
index 0000000000..a142d263e2
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/tonemap.glsl
@@ -0,0 +1,359 @@
+/* clang-format off */
+[vertex]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+
+ vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+ uv_interp = base_arr[gl_VertexIndex];
+ gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+[fragment]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(location = 0) in vec2 uv_interp;
+/* clang-format on */
+
+layout(set = 0, binding = 0) uniform sampler2D source_color;
+layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
+layout(set = 2, binding = 0) uniform sampler2D source_glow;
+layout(set = 3, binding = 0) uniform sampler3D color_correction;
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ vec3 bcs;
+ bool use_bcs;
+
+ bool use_glow;
+ bool use_auto_exposure;
+ bool use_color_correction;
+ uint tonemapper;
+
+ uvec2 glow_texture_size;
+
+ float glow_intensity;
+ uint glow_level_flags;
+ uint glow_mode;
+
+ float exposure;
+ float white;
+ float auto_exposure_grey;
+
+ vec2 pixel_size;
+ bool use_fxaa;
+ uint pad;
+}
+params;
+
+layout(location = 0) out vec4 frag_color;
+
+#ifdef USE_GLOW_FILTER_BICUBIC
+// w0, w1, w2, and w3 are the four cubic B-spline basis functions
+float w0(float a) {
+ return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f);
+}
+
+float w1(float a) {
+ return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f);
+}
+
+float w2(float a) {
+ return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f);
+}
+
+float w3(float a) {
+ return (1.0f / 6.0f) * (a * a * a);
+}
+
+// g0 and g1 are the two amplitude functions
+float g0(float a) {
+ return w0(a) + w1(a);
+}
+
+float g1(float a) {
+ return w2(a) + w3(a);
+}
+
+// h0 and h1 are the two offset functions
+float h0(float a) {
+ return -1.0f + w1(a) / (w0(a) + w1(a));
+}
+
+float h1(float a) {
+ return 1.0f + w3(a) / (w2(a) + w3(a));
+}
+
+vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) {
+ float lod = float(p_lod);
+ vec2 tex_size = vec2(params.glow_texture_size >> p_lod);
+ vec2 pixel_size = vec2(1.0f) / tex_size;
+
+ uv = uv * tex_size + vec2(0.5f);
+
+ vec2 iuv = floor(uv);
+ vec2 fuv = fract(uv);
+
+ float g0x = g0(fuv.x);
+ float g1x = g1(fuv.x);
+ float h0x = h0(fuv.x);
+ float h1x = h1(fuv.x);
+ float h0y = h0(fuv.y);
+ float h1y = h1(fuv.y);
+
+ vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size;
+ vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size;
+ vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
+ vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
+
+ return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) +
+ (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
+}
+
+#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod)
+
+#else
+
+#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod))
+
+#endif
+
+vec3 tonemap_filmic(vec3 color, float white) {
+ // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers
+ // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values)
+ // has no effect on the curve's general shape or visual properties
+ const float exposure_bias = 2.0f;
+ const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance
+ const float B = 0.30f * exposure_bias;
+ const float C = 0.10f;
+ const float D = 0.20f;
+ const float E = 0.01f;
+ const float F = 0.30f;
+
+ vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
+ float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F;
+
+ return color_tonemapped / white_tonemapped;
+}
+
+vec3 tonemap_aces(vec3 color, float white) {
+ const float exposure_bias = 0.85f;
+ const float A = 2.51f * exposure_bias * exposure_bias;
+ const float B = 0.03f * exposure_bias;
+ const float C = 2.43f * exposure_bias * exposure_bias;
+ const float D = 0.59f * exposure_bias;
+ const float E = 0.14f;
+
+ vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E);
+ float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E);
+
+ return color_tonemapped / white_tonemapped;
+}
+
+vec3 tonemap_reinhard(vec3 color, float white) {
+ return (white * color + color) / (color * white + white);
+}
+
+vec3 linear_to_srgb(vec3 color) {
+ //if going to srgb, clamp from 0 to 1.
+ color = clamp(color, vec3(0.0), vec3(1.0));
+ const vec3 a = vec3(0.055f);
+ return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
+}
+
+#define TONEMAPPER_LINEAR 0
+#define TONEMAPPER_REINHARD 1
+#define TONEMAPPER_FILMIC 2
+#define TONEMAPPER_ACES 3
+
+vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color
+
+ if (params.tonemapper == TONEMAPPER_LINEAR) {
+ return color;
+ } else if (params.tonemapper == TONEMAPPER_REINHARD) {
+ return tonemap_reinhard(color, white);
+ } else if (params.tonemapper == TONEMAPPER_FILMIC) {
+ return tonemap_filmic(color, white);
+ } else { //aces
+ return tonemap_aces(color, white);
+ }
+}
+
+vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels
+ vec3 glow = vec3(0.0f);
+
+ if (bool(params.glow_level_flags & (1 << 0))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb;
+ }
+
+ if (bool(params.glow_level_flags & (1 << 1))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb;
+ }
+
+ if (bool(params.glow_level_flags & (1 << 2))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb;
+ }
+
+ if (bool(params.glow_level_flags & (1 << 3))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb;
+ }
+
+ if (bool(params.glow_level_flags & (1 << 4))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb;
+ }
+
+ if (bool(params.glow_level_flags & (1 << 5))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb;
+ }
+
+ if (bool(params.glow_level_flags & (1 << 6))) {
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb;
+ }
+
+ return glow;
+}
+
+#define GLOW_MODE_ADD 0
+#define GLOW_MODE_SCREEN 1
+#define GLOW_MODE_SOFTLIGHT 2
+#define GLOW_MODE_REPLACE 3
+#define GLOW_MODE_MIX 4
+
+vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode
+ if (params.glow_mode == GLOW_MODE_ADD) {
+ return color + glow;
+ } else if (params.glow_mode == GLOW_MODE_SCREEN) {
+ //need color clamping
+ return max((color + glow) - (color * glow), vec3(0.0));
+ } else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) {
+ //need color clamping
+ glow = glow * vec3(0.5f) + vec3(0.5f);
+
+ color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r)));
+ color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g)));
+ color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b)));
+ return color;
+ } else { //replace
+ return glow;
+ }
+}
+
+vec3 apply_bcs(vec3 color, vec3 bcs) {
+ color = mix(vec3(0.0f), color, bcs.x);
+ color = mix(vec3(0.5f), color, bcs.y);
+ color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z);
+
+ return color;
+}
+
+vec3 apply_color_correction(vec3 color, sampler3D correction_tex) {
+ return texture(correction_tex, color).rgb;
+}
+
+vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
+
+ const float FXAA_REDUCE_MIN = (1.0 / 128.0);
+ const float FXAA_REDUCE_MUL = (1.0 / 8.0);
+ const float FXAA_SPAN_MAX = 8.0;
+
+ vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure;
+ vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure;
+ vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure;
+ vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure;
+ vec3 rgbM = color;
+ vec3 luma = vec3(0.299, 0.587, 0.114);
+ float lumaNW = dot(rgbNW, luma);
+ float lumaNE = dot(rgbNE, luma);
+ float lumaSW = dot(rgbSW, luma);
+ float lumaSE = dot(rgbSE, luma);
+ float lumaM = dot(rgbM, luma);
+ float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
+ float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
+
+ vec2 dir;
+ dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
+ dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
+
+ float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
+ (0.25 * FXAA_REDUCE_MUL),
+ FXAA_REDUCE_MIN);
+
+ float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
+ dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
+ max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
+ dir * rcpDirMin)) *
+ params.pixel_size;
+
+ vec3 rgbA = 0.5 * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz * exposure + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * exposure;
+ vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz * exposure +
+ textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz * exposure);
+
+ float lumaB = dot(rgbB, luma);
+ if ((lumaB < lumaMin) || (lumaB > lumaMax))
+ return rgbA;
+ else
+ return rgbB;
+}
+
+void main() {
+ vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
+
+ // Exposure
+
+ float exposure = params.exposure;
+
+ if (params.use_auto_exposure) {
+ exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey);
+ }
+
+ color *= exposure;
+
+ // Early Tonemap & SRGB Conversion
+
+ if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
+
+ vec3 glow = gather_glow(source_glow, uv_interp);
+ color.rgb = mix(color.rgb, glow, params.glow_intensity);
+ }
+
+ if (params.use_fxaa) {
+ color = do_fxaa(color, exposure, uv_interp);
+ }
+ color = apply_tonemapping(color, params.white);
+
+ color = linear_to_srgb(color); // regular linear -> SRGB conversion
+
+ // Glow
+
+ if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
+
+ vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity;
+
+ // high dynamic range -> SRGB
+ glow = apply_tonemapping(glow, params.white);
+ glow = linear_to_srgb(glow);
+
+ color = apply_glow(color, glow);
+ }
+
+ // Additional effects
+
+ if (params.use_bcs) {
+ color = apply_bcs(color, params.bcs);
+ }
+
+ if (params.use_color_correction) {
+ color = apply_color_correction(color, color_correction);
+ }
+
+ frag_color = vec4(color, 1.0f);
+}
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
new file mode 100644
index 0000000000..a3799b0e4d
--- /dev/null
+++ b/servers/rendering/rendering_device.cpp
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* rendering_device.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_device.h"
+
+RenderingDevice *RenderingDevice::singleton = nullptr;
+
+RenderingDevice *RenderingDevice::get_singleton() {
+ return singleton;
+}
+
+RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = nullptr;
+RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = nullptr;
+
+void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
+ compile_function = p_function;
+}
+void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function) {
+ cache_function = p_function;
+}
+
+Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
+ if (p_allow_cache && cache_function) {
+ Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
+ if (cache.size()) {
+ return cache;
+ }
+ }
+
+ ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>());
+
+ return compile_function(p_stage, p_source_code, p_language, r_error);
+}
+
+RenderingDevice::RenderingDevice() {
+ singleton = this;
+}
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
new file mode 100644
index 0000000000..63aa8dde1c
--- /dev/null
+++ b/servers/rendering/rendering_device.h
@@ -0,0 +1,1034 @@
+/*************************************************************************/
+/* rendering_device.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_DEVICE_H
+#define RENDERING_DEVICE_H
+
+#include "core/object.h"
+#include "servers/display_server.h"
+
+class RenderingDevice : public Object {
+ GDCLASS(RenderingDevice, Object)
+public:
+ enum ShaderStage {
+ SHADER_STAGE_VERTEX,
+ SHADER_STAGE_FRAGMENT,
+ SHADER_STAGE_TESSELATION_CONTROL,
+ SHADER_STAGE_TESSELATION_EVALUATION,
+ SHADER_STAGE_COMPUTE,
+ SHADER_STAGE_MAX,
+ SHADER_STAGE_VERTEX_BIT = (1 << SHADER_STAGE_VERTEX),
+ SHADER_STAGE_FRAGMENT_BIT = (1 << SHADER_STAGE_FRAGMENT),
+ SHADER_STAGE_TESSELATION_CONTROL_BIT = (1 << SHADER_STAGE_TESSELATION_CONTROL),
+ SHADER_STAGE_TESSELATION_EVALUATION_BIT = (1 << SHADER_STAGE_TESSELATION_EVALUATION),
+ SHADER_STAGE_COMPUTE_BIT = (1 << SHADER_STAGE_COMPUTE),
+ };
+
+ enum ShaderLanguage {
+ SHADER_LANGUAGE_GLSL,
+ SHADER_LANGUAGE_HLSL
+ };
+
+ typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error);
+ typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
+
+private:
+ static ShaderCompileFunction compile_function;
+ static ShaderCacheFunction cache_function;
+
+ static RenderingDevice *singleton;
+
+public:
+ //base numeric ID for all types
+ enum {
+ INVALID_ID = -1
+ };
+
+ /*****************/
+ /**** GENERIC ****/
+ /*****************/
+
+ enum CompareOperator {
+ COMPARE_OP_NEVER,
+ COMPARE_OP_LESS,
+ COMPARE_OP_EQUAL,
+ COMPARE_OP_LESS_OR_EQUAL,
+ COMPARE_OP_GREATER,
+ COMPARE_OP_NOT_EQUAL,
+ COMPARE_OP_GREATER_OR_EQUAL,
+ COMPARE_OP_ALWAYS,
+ COMPARE_OP_MAX //not an actual operator, just the amount of operators :D
+ };
+
+ enum DataFormat {
+ DATA_FORMAT_R4G4_UNORM_PACK8,
+ DATA_FORMAT_R4G4B4A4_UNORM_PACK16,
+ DATA_FORMAT_B4G4R4A4_UNORM_PACK16,
+ DATA_FORMAT_R5G6B5_UNORM_PACK16,
+ DATA_FORMAT_B5G6R5_UNORM_PACK16,
+ DATA_FORMAT_R5G5B5A1_UNORM_PACK16,
+ DATA_FORMAT_B5G5R5A1_UNORM_PACK16,
+ DATA_FORMAT_A1R5G5B5_UNORM_PACK16,
+ DATA_FORMAT_R8_UNORM,
+ DATA_FORMAT_R8_SNORM,
+ DATA_FORMAT_R8_USCALED,
+ DATA_FORMAT_R8_SSCALED,
+ DATA_FORMAT_R8_UINT,
+ DATA_FORMAT_R8_SINT,
+ DATA_FORMAT_R8_SRGB,
+ DATA_FORMAT_R8G8_UNORM,
+ DATA_FORMAT_R8G8_SNORM,
+ DATA_FORMAT_R8G8_USCALED,
+ DATA_FORMAT_R8G8_SSCALED,
+ DATA_FORMAT_R8G8_UINT,
+ DATA_FORMAT_R8G8_SINT,
+ DATA_FORMAT_R8G8_SRGB,
+ DATA_FORMAT_R8G8B8_UNORM,
+ DATA_FORMAT_R8G8B8_SNORM,
+ DATA_FORMAT_R8G8B8_USCALED,
+ DATA_FORMAT_R8G8B8_SSCALED,
+ DATA_FORMAT_R8G8B8_UINT,
+ DATA_FORMAT_R8G8B8_SINT,
+ DATA_FORMAT_R8G8B8_SRGB,
+ DATA_FORMAT_B8G8R8_UNORM,
+ DATA_FORMAT_B8G8R8_SNORM,
+ DATA_FORMAT_B8G8R8_USCALED,
+ DATA_FORMAT_B8G8R8_SSCALED,
+ DATA_FORMAT_B8G8R8_UINT,
+ DATA_FORMAT_B8G8R8_SINT,
+ DATA_FORMAT_B8G8R8_SRGB,
+ DATA_FORMAT_R8G8B8A8_UNORM,
+ DATA_FORMAT_R8G8B8A8_SNORM,
+ DATA_FORMAT_R8G8B8A8_USCALED,
+ DATA_FORMAT_R8G8B8A8_SSCALED,
+ DATA_FORMAT_R8G8B8A8_UINT,
+ DATA_FORMAT_R8G8B8A8_SINT,
+ DATA_FORMAT_R8G8B8A8_SRGB,
+ DATA_FORMAT_B8G8R8A8_UNORM,
+ DATA_FORMAT_B8G8R8A8_SNORM,
+ DATA_FORMAT_B8G8R8A8_USCALED,
+ DATA_FORMAT_B8G8R8A8_SSCALED,
+ DATA_FORMAT_B8G8R8A8_UINT,
+ DATA_FORMAT_B8G8R8A8_SINT,
+ DATA_FORMAT_B8G8R8A8_SRGB,
+ DATA_FORMAT_A8B8G8R8_UNORM_PACK32,
+ DATA_FORMAT_A8B8G8R8_SNORM_PACK32,
+ DATA_FORMAT_A8B8G8R8_USCALED_PACK32,
+ DATA_FORMAT_A8B8G8R8_SSCALED_PACK32,
+ DATA_FORMAT_A8B8G8R8_UINT_PACK32,
+ DATA_FORMAT_A8B8G8R8_SINT_PACK32,
+ DATA_FORMAT_A8B8G8R8_SRGB_PACK32,
+ DATA_FORMAT_A2R10G10B10_UNORM_PACK32,
+ DATA_FORMAT_A2R10G10B10_SNORM_PACK32,
+ DATA_FORMAT_A2R10G10B10_USCALED_PACK32,
+ DATA_FORMAT_A2R10G10B10_SSCALED_PACK32,
+ DATA_FORMAT_A2R10G10B10_UINT_PACK32,
+ DATA_FORMAT_A2R10G10B10_SINT_PACK32,
+ DATA_FORMAT_A2B10G10R10_UNORM_PACK32,
+ DATA_FORMAT_A2B10G10R10_SNORM_PACK32,
+ DATA_FORMAT_A2B10G10R10_USCALED_PACK32,
+ DATA_FORMAT_A2B10G10R10_SSCALED_PACK32,
+ DATA_FORMAT_A2B10G10R10_UINT_PACK32,
+ DATA_FORMAT_A2B10G10R10_SINT_PACK32,
+ DATA_FORMAT_R16_UNORM,
+ DATA_FORMAT_R16_SNORM,
+ DATA_FORMAT_R16_USCALED,
+ DATA_FORMAT_R16_SSCALED,
+ DATA_FORMAT_R16_UINT,
+ DATA_FORMAT_R16_SINT,
+ DATA_FORMAT_R16_SFLOAT,
+ DATA_FORMAT_R16G16_UNORM,
+ DATA_FORMAT_R16G16_SNORM,
+ DATA_FORMAT_R16G16_USCALED,
+ DATA_FORMAT_R16G16_SSCALED,
+ DATA_FORMAT_R16G16_UINT,
+ DATA_FORMAT_R16G16_SINT,
+ DATA_FORMAT_R16G16_SFLOAT,
+ DATA_FORMAT_R16G16B16_UNORM,
+ DATA_FORMAT_R16G16B16_SNORM,
+ DATA_FORMAT_R16G16B16_USCALED,
+ DATA_FORMAT_R16G16B16_SSCALED,
+ DATA_FORMAT_R16G16B16_UINT,
+ DATA_FORMAT_R16G16B16_SINT,
+ DATA_FORMAT_R16G16B16_SFLOAT,
+ DATA_FORMAT_R16G16B16A16_UNORM,
+ DATA_FORMAT_R16G16B16A16_SNORM,
+ DATA_FORMAT_R16G16B16A16_USCALED,
+ DATA_FORMAT_R16G16B16A16_SSCALED,
+ DATA_FORMAT_R16G16B16A16_UINT,
+ DATA_FORMAT_R16G16B16A16_SINT,
+ DATA_FORMAT_R16G16B16A16_SFLOAT,
+ DATA_FORMAT_R32_UINT,
+ DATA_FORMAT_R32_SINT,
+ DATA_FORMAT_R32_SFLOAT,
+ DATA_FORMAT_R32G32_UINT,
+ DATA_FORMAT_R32G32_SINT,
+ DATA_FORMAT_R32G32_SFLOAT,
+ DATA_FORMAT_R32G32B32_UINT,
+ DATA_FORMAT_R32G32B32_SINT,
+ DATA_FORMAT_R32G32B32_SFLOAT,
+ DATA_FORMAT_R32G32B32A32_UINT,
+ DATA_FORMAT_R32G32B32A32_SINT,
+ DATA_FORMAT_R32G32B32A32_SFLOAT,
+ DATA_FORMAT_R64_UINT,
+ DATA_FORMAT_R64_SINT,
+ DATA_FORMAT_R64_SFLOAT,
+ DATA_FORMAT_R64G64_UINT,
+ DATA_FORMAT_R64G64_SINT,
+ DATA_FORMAT_R64G64_SFLOAT,
+ DATA_FORMAT_R64G64B64_UINT,
+ DATA_FORMAT_R64G64B64_SINT,
+ DATA_FORMAT_R64G64B64_SFLOAT,
+ DATA_FORMAT_R64G64B64A64_UINT,
+ DATA_FORMAT_R64G64B64A64_SINT,
+ DATA_FORMAT_R64G64B64A64_SFLOAT,
+ DATA_FORMAT_B10G11R11_UFLOAT_PACK32,
+ DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32,
+ DATA_FORMAT_D16_UNORM,
+ DATA_FORMAT_X8_D24_UNORM_PACK32,
+ DATA_FORMAT_D32_SFLOAT,
+ DATA_FORMAT_S8_UINT,
+ DATA_FORMAT_D16_UNORM_S8_UINT,
+ DATA_FORMAT_D24_UNORM_S8_UINT,
+ DATA_FORMAT_D32_SFLOAT_S8_UINT,
+ DATA_FORMAT_BC1_RGB_UNORM_BLOCK,
+ DATA_FORMAT_BC1_RGB_SRGB_BLOCK,
+ DATA_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ DATA_FORMAT_BC1_RGBA_SRGB_BLOCK,
+ DATA_FORMAT_BC2_UNORM_BLOCK,
+ DATA_FORMAT_BC2_SRGB_BLOCK,
+ DATA_FORMAT_BC3_UNORM_BLOCK,
+ DATA_FORMAT_BC3_SRGB_BLOCK,
+ DATA_FORMAT_BC4_UNORM_BLOCK,
+ DATA_FORMAT_BC4_SNORM_BLOCK,
+ DATA_FORMAT_BC5_UNORM_BLOCK,
+ DATA_FORMAT_BC5_SNORM_BLOCK,
+ DATA_FORMAT_BC6H_UFLOAT_BLOCK,
+ DATA_FORMAT_BC6H_SFLOAT_BLOCK,
+ DATA_FORMAT_BC7_UNORM_BLOCK,
+ DATA_FORMAT_BC7_SRGB_BLOCK,
+ DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
+ DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
+ DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
+ DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
+ DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
+ DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
+ DATA_FORMAT_EAC_R11_UNORM_BLOCK,
+ DATA_FORMAT_EAC_R11_SNORM_BLOCK,
+ DATA_FORMAT_EAC_R11G11_UNORM_BLOCK,
+ DATA_FORMAT_EAC_R11G11_SNORM_BLOCK,
+ DATA_FORMAT_ASTC_4x4_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_4x4_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_5x4_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_5x4_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_5x5_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_5x5_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_6x5_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_6x5_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_6x6_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_6x6_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_8x5_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_8x5_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_8x6_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_8x6_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_8x8_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_8x8_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_10x5_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_10x5_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_10x6_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_10x6_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_10x8_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_10x8_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_10x10_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_10x10_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_12x10_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_12x10_SRGB_BLOCK,
+ DATA_FORMAT_ASTC_12x12_UNORM_BLOCK,
+ DATA_FORMAT_ASTC_12x12_SRGB_BLOCK,
+ DATA_FORMAT_G8B8G8R8_422_UNORM,
+ DATA_FORMAT_B8G8R8G8_422_UNORM,
+ DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
+ DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+ DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
+ DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM,
+ DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
+ DATA_FORMAT_R10X6_UNORM_PACK16,
+ DATA_FORMAT_R10X6G10X6_UNORM_2PACK16,
+ DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
+ DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
+ DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
+ DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
+ DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
+ DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
+ DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
+ DATA_FORMAT_R12X4_UNORM_PACK16,
+ DATA_FORMAT_R12X4G12X4_UNORM_2PACK16,
+ DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
+ DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
+ DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
+ DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
+ DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
+ DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
+ DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
+ DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
+ DATA_FORMAT_G16B16G16R16_422_UNORM,
+ DATA_FORMAT_B16G16R16G16_422_UNORM,
+ DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
+ DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM,
+ DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
+ DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM,
+ DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
+ DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,
+ DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,
+ DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,
+ DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,
+ DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,
+ DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,
+ DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,
+ DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,
+ DATA_FORMAT_MAX
+ };
+
+ /*****************/
+ /**** TEXTURE ****/
+ /*****************/
+
+ enum TextureType {
+ TEXTURE_TYPE_1D,
+ TEXTURE_TYPE_2D,
+ TEXTURE_TYPE_3D,
+ TEXTURE_TYPE_CUBE,
+ TEXTURE_TYPE_1D_ARRAY,
+ TEXTURE_TYPE_2D_ARRAY,
+ TEXTURE_TYPE_CUBE_ARRAY,
+ TEXTURE_TYPE_MAX
+ };
+
+ enum TextureSamples {
+ TEXTURE_SAMPLES_1,
+ TEXTURE_SAMPLES_2,
+ TEXTURE_SAMPLES_4,
+ TEXTURE_SAMPLES_8,
+ TEXTURE_SAMPLES_16,
+ TEXTURE_SAMPLES_32,
+ TEXTURE_SAMPLES_64,
+ TEXTURE_SAMPLES_MAX
+ };
+
+ enum TextureUsageBits {
+ TEXTURE_USAGE_SAMPLING_BIT = (1 << 0),
+ TEXTURE_USAGE_COLOR_ATTACHMENT_BIT = (1 << 1),
+ TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = (1 << 2),
+ TEXTURE_USAGE_STORAGE_BIT = (1 << 3),
+ TEXTURE_USAGE_STORAGE_ATOMIC_BIT = (1 << 4),
+ TEXTURE_USAGE_CPU_READ_BIT = (1 << 5),
+ TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6),
+ TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7),
+ TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8),
+ TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 9),
+ };
+
+ enum TextureSwizzle {
+ TEXTURE_SWIZZLE_IDENTITY,
+ TEXTURE_SWIZZLE_ZERO,
+ TEXTURE_SWIZZLE_ONE,
+ TEXTURE_SWIZZLE_R,
+ TEXTURE_SWIZZLE_G,
+ TEXTURE_SWIZZLE_B,
+ TEXTURE_SWIZZLE_A,
+ TEXTURE_SWIZZLE_MAX
+ };
+
+ struct TextureFormat {
+ DataFormat format;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
+ uint32_t array_layers;
+ uint32_t mipmaps;
+ TextureType type;
+ TextureSamples samples;
+ uint32_t usage_bits;
+ Vector<DataFormat> shareable_formats;
+
+ TextureFormat() {
+ format = DATA_FORMAT_R8_UNORM;
+ width = 1;
+ height = 1;
+ depth = 1;
+ array_layers = 1;
+ mipmaps = 1;
+ type = TEXTURE_TYPE_2D;
+ samples = TEXTURE_SAMPLES_1;
+ usage_bits = 0;
+ }
+ };
+
+ struct TextureView {
+ DataFormat format_override;
+ TextureSwizzle swizzle_r;
+ TextureSwizzle swizzle_g;
+ TextureSwizzle swizzle_b;
+ TextureSwizzle swizzle_a;
+
+ TextureView() {
+ format_override = DATA_FORMAT_MAX; //means, use same as format
+ swizzle_r = TEXTURE_SWIZZLE_R;
+ swizzle_g = TEXTURE_SWIZZLE_G;
+ swizzle_b = TEXTURE_SWIZZLE_B;
+ swizzle_a = TEXTURE_SWIZZLE_A;
+ }
+ };
+
+ virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>()) = 0;
+ virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0;
+
+ enum TextureSliceType {
+ TEXTURE_SLICE_2D,
+ TEXTURE_SLICE_CUBEMAP,
+ TEXTURE_SLICE_3D,
+ };
+
+ virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0;
+
+ virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls
+ virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush
+
+ virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0;
+ virtual bool texture_is_shared(RID p_texture) = 0;
+ virtual bool texture_is_valid(RID p_texture) = 0;
+
+ virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0;
+ virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0;
+ virtual Error texture_resolve_multisample(RID p_from_texture, RID p_to_texture, bool p_sync_with_draw = false) = 0;
+
+ /*********************/
+ /**** FRAMEBUFFER ****/
+ /*********************/
+
+ struct AttachmentFormat {
+ DataFormat format;
+ TextureSamples samples;
+ uint32_t usage_flags;
+ AttachmentFormat() {
+ format = DATA_FORMAT_R8G8B8A8_UNORM;
+ samples = TEXTURE_SAMPLES_1;
+ usage_flags = 0;
+ }
+ };
+
+ typedef int64_t FramebufferFormatID;
+
+ // This ID is warranted to be unique for the same formats, does not need to be freed
+ virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format) = 0;
+ virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0;
+
+ virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0;
+
+ virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0;
+
+ /*****************/
+ /**** SAMPLER ****/
+ /*****************/
+
+ enum SamplerFilter {
+ SAMPLER_FILTER_NEAREST,
+ SAMPLER_FILTER_LINEAR,
+ };
+
+ enum SamplerRepeatMode {
+ SAMPLER_REPEAT_MODE_REPEAT,
+ SAMPLER_REPEAT_MODE_MIRRORED_REPEAT,
+ SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE,
+ SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER,
+ SAMPLER_REPEAT_MODE_MIRROR_CLAMP_TO_EDGE,
+ SAMPLER_REPEAT_MODE_MAX
+ };
+
+ enum SamplerBorderColor {
+ SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+ SAMPLER_BORDER_COLOR_INT_TRANSPARENT_BLACK,
+ SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
+ SAMPLER_BORDER_COLOR_INT_OPAQUE_BLACK,
+ SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
+ SAMPLER_BORDER_COLOR_INT_OPAQUE_WHITE,
+ SAMPLER_BORDER_COLOR_MAX
+ };
+
+ struct SamplerState {
+ SamplerFilter mag_filter;
+ SamplerFilter min_filter;
+ SamplerFilter mip_filter;
+ SamplerRepeatMode repeat_u;
+ SamplerRepeatMode repeat_v;
+ SamplerRepeatMode repeat_w;
+ float lod_bias;
+ bool use_anisotropy;
+ float anisotropy_max;
+ bool enable_compare;
+ CompareOperator compare_op;
+ float min_lod;
+ float max_lod;
+ SamplerBorderColor border_color;
+ bool unnormalized_uvw;
+
+ SamplerState() {
+ mag_filter = SAMPLER_FILTER_NEAREST;
+ min_filter = SAMPLER_FILTER_NEAREST;
+ mip_filter = SAMPLER_FILTER_NEAREST;
+ repeat_u = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ repeat_v = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ repeat_w = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ lod_bias = 0;
+ use_anisotropy = false;
+ anisotropy_max = 1.0;
+ enable_compare = false;
+ compare_op = COMPARE_OP_ALWAYS;
+ min_lod = 0;
+ max_lod = 1e20; //something very large should do
+ border_color = SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+ unnormalized_uvw = false;
+ }
+ };
+
+ virtual RID sampler_create(const SamplerState &p_state) = 0;
+
+ /**********************/
+ /**** VERTEX ARRAY ****/
+ /**********************/
+
+ enum VertexFrequency {
+ VERTEX_FREQUENCY_VERTEX,
+ VERTEX_FREQUENCY_INSTANCE,
+ };
+
+ struct VertexDescription {
+ uint32_t location; //shader location
+ uint32_t offset;
+ DataFormat format;
+ uint32_t stride;
+ VertexFrequency frequency;
+ VertexDescription() {
+ location = 0;
+ offset = 0;
+ stride = 0;
+ format = DATA_FORMAT_MAX;
+ frequency = VERTEX_FREQUENCY_VERTEX;
+ }
+ };
+ virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
+
+ typedef int64_t VertexFormatID;
+
+ // This ID is warranted to be unique for the same formats, does not need to be freed
+ virtual VertexFormatID vertex_format_create(const Vector<VertexDescription> &p_vertex_formats) = 0;
+ virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) = 0;
+
+ enum IndexBufferFormat {
+ INDEX_BUFFER_FORMAT_UINT16,
+ INDEX_BUFFER_FORMAT_UINT32,
+ };
+
+ virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_restart_indices = false) = 0;
+ virtual RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) = 0;
+
+ /****************/
+ /**** SHADER ****/
+ /****************/
+
+ 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);
+ static void shader_set_cache_function(ShaderCacheFunction p_function);
+
+ struct ShaderStageData {
+ ShaderStage shader_stage;
+ Vector<uint8_t> spir_v;
+
+ ShaderStageData() {
+ shader_stage = SHADER_STAGE_VERTEX;
+ }
+ };
+
+ virtual RID shader_create(const Vector<ShaderStageData> &p_stages) = 0;
+ virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
+
+ /******************/
+ /**** UNIFORMS ****/
+ /******************/
+
+ enum UniformType {
+ UNIFORM_TYPE_SAMPLER, //for sampling only (sampler GLSL type)
+ UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, // for sampling only, but includes a texture, (samplerXX GLSL type), first a sampler then a texture
+ UNIFORM_TYPE_TEXTURE, //only texture, (textureXX GLSL type)
+ UNIFORM_TYPE_IMAGE, // storage image (imageXX GLSL type), for compute mostly
+ UNIFORM_TYPE_TEXTURE_BUFFER, // buffer texture (or TBO, textureBuffer type)
+ UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER, // buffer texture with a sampler(or TBO, samplerBuffer type)
+ UNIFORM_TYPE_IMAGE_BUFFER, //texel buffer, (imageBuffer type), for compute mostly
+ UNIFORM_TYPE_UNIFORM_BUFFER, //regular uniform buffer (or UBO).
+ UNIFORM_TYPE_STORAGE_BUFFER, //storage buffer ("buffer" qualifier) like UBO, but supports storage, for compute mostly
+ UNIFORM_TYPE_INPUT_ATTACHMENT, //used for sub-pass read/write, for compute mostly
+ UNIFORM_TYPE_MAX
+ };
+
+ virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
+ virtual RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
+ virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
+
+ struct Uniform {
+ UniformType type;
+ int binding; //binding index as specified in shader
+
+ //for single items, provide one ID, for
+ //multiple items (declared as arrays in shader),
+ //provide more
+ //for sampler with texture, supply two IDs for each.
+ //accepted IDs are: Sampler, Texture, Uniform Buffer and Texture Buffer
+ Vector<RID> ids;
+
+ Uniform() {
+ type = UNIFORM_TYPE_IMAGE;
+ binding = 0;
+ }
+ };
+
+ virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
+ virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
+
+ virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls
+ virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving
+
+ /*************************/
+ /**** RENDER PIPELINE ****/
+ /*************************/
+
+ enum RenderPrimitive {
+ RENDER_PRIMITIVE_POINTS,
+ RENDER_PRIMITIVE_LINES,
+ RENDER_PRIMITIVE_LINES_WITH_ADJACENCY,
+ RENDER_PRIMITIVE_LINESTRIPS,
+ RENDER_PRIMITIVE_LINESTRIPS_WITH_ADJACENCY,
+ RENDER_PRIMITIVE_TRIANGLES,
+ RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY,
+ RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_AJACENCY,
+ RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX,
+ RENDER_PRIMITIVE_TESSELATION_PATCH,
+ RENDER_PRIMITIVE_MAX
+ };
+
+ //disable optimization, tessellate control points
+
+ enum PolygonCullMode {
+ POLYGON_CULL_DISABLED,
+ POLYGON_CULL_FRONT,
+ POLYGON_CULL_BACK,
+ };
+
+ enum PolygonFrontFace {
+ POLYGON_FRONT_FACE_CLOCKWISE,
+ POLYGON_FRONT_FACE_COUNTER_CLOCKWISE,
+ };
+
+ enum StencilOperation {
+ STENCIL_OP_KEEP,
+ STENCIL_OP_ZERO,
+ STENCIL_OP_REPLACE,
+ STENCIL_OP_INCREMENT_AND_CLAMP,
+ STENCIL_OP_DECREMENT_AND_CLAMP,
+ STENCIL_OP_INVERT,
+ STENCIL_OP_INCREMENT_AND_WRAP,
+ STENCIL_OP_DECREMENT_AND_WRAP,
+ STENCIL_OP_MAX //not an actual operator, just the amount of operators :D
+ };
+
+ enum LogicOperation {
+ LOGIC_OP_CLEAR,
+ LOGIC_OP_AND,
+ LOGIC_OP_AND_REVERSE,
+ LOGIC_OP_COPY,
+ LOGIC_OP_AND_INVERTED,
+ LOGIC_OP_NO_OP,
+ LOGIC_OP_XOR,
+ LOGIC_OP_OR,
+ LOGIC_OP_NOR,
+ LOGIC_OP_EQUIVALENT,
+ LOGIC_OP_INVERT,
+ LOGIC_OP_OR_REVERSE,
+ LOGIC_OP_COPY_INVERTED,
+ LOGIC_OP_OR_INVERTED,
+ LOGIC_OP_NAND,
+ LOGIC_OP_SET,
+ LOGIC_OP_MAX //not an actual operator, just the amount of operators :D
+ };
+
+ enum BlendFactor {
+ BLEND_FACTOR_ZERO,
+ BLEND_FACTOR_ONE,
+ BLEND_FACTOR_SRC_COLOR,
+ BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
+ BLEND_FACTOR_DST_COLOR,
+ BLEND_FACTOR_ONE_MINUS_DST_COLOR,
+ BLEND_FACTOR_SRC_ALPHA,
+ BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+ BLEND_FACTOR_DST_ALPHA,
+ BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
+ BLEND_FACTOR_CONSTANT_COLOR,
+ BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
+ BLEND_FACTOR_CONSTANT_ALPHA,
+ BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
+ BLEND_FACTOR_SRC_ALPHA_SATURATE,
+ BLEND_FACTOR_SRC1_COLOR,
+ BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
+ BLEND_FACTOR_SRC1_ALPHA,
+ BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
+ BLEND_FACTOR_MAX
+ };
+
+ enum BlendOperation {
+ BLEND_OP_ADD,
+ BLEND_OP_SUBTRACT,
+ BLEND_OP_REVERSE_SUBTRACT,
+ BLEND_OP_MINIMUM,
+ BLEND_OP_MAXIMUM, //yes this one is an actual operator
+ BLEND_OP_MAX //not an actual operator, just the amount of operators :D
+ };
+
+ struct PipelineRasterizationState {
+ bool enable_depth_clamp;
+ bool discard_primitives;
+ bool wireframe;
+ PolygonCullMode cull_mode;
+ PolygonFrontFace front_face;
+ bool depth_bias_enable;
+ float depth_bias_constant_factor;
+ float depth_bias_clamp;
+ float depth_bias_slope_factor;
+ float line_width;
+ uint32_t patch_control_points;
+ PipelineRasterizationState() {
+ enable_depth_clamp = false;
+ discard_primitives = false;
+ wireframe = false;
+ cull_mode = POLYGON_CULL_DISABLED;
+ front_face = POLYGON_FRONT_FACE_CLOCKWISE;
+ depth_bias_enable = false;
+ depth_bias_constant_factor = 0;
+ depth_bias_clamp = 0;
+ depth_bias_slope_factor = 0;
+ line_width = 1.0;
+ patch_control_points = 1;
+ }
+ };
+
+ struct PipelineMultisampleState {
+ TextureSamples sample_count;
+ bool enable_sample_shading;
+ float min_sample_shading;
+ Vector<uint32_t> sample_mask;
+ bool enable_alpha_to_coverage;
+ bool enable_alpha_to_one;
+
+ PipelineMultisampleState() {
+ sample_count = TEXTURE_SAMPLES_1;
+ enable_sample_shading = false;
+ min_sample_shading = 0;
+ enable_alpha_to_coverage = false;
+ enable_alpha_to_one = false;
+ }
+ };
+
+ struct PipelineDepthStencilState {
+
+ bool enable_depth_test;
+ bool enable_depth_write;
+ CompareOperator depth_compare_operator;
+ bool enable_depth_range;
+ float depth_range_min;
+ float depth_range_max;
+ bool enable_stencil;
+
+ struct StencilOperationState {
+ StencilOperation fail;
+ StencilOperation pass;
+ StencilOperation depth_fail;
+ CompareOperator compare;
+ uint32_t compare_mask;
+ uint32_t write_mask;
+ uint32_t reference;
+
+ StencilOperationState() {
+ fail = STENCIL_OP_ZERO;
+ pass = STENCIL_OP_ZERO;
+ depth_fail = STENCIL_OP_ZERO;
+ compare = COMPARE_OP_ALWAYS;
+ compare_mask = 0;
+ write_mask = 0;
+ reference = 0;
+ }
+ };
+
+ StencilOperationState stencil_operation_front;
+ StencilOperationState stencil_operation_back;
+
+ PipelineDepthStencilState() {
+ enable_depth_test = false;
+ enable_depth_write = false;
+ depth_compare_operator = COMPARE_OP_ALWAYS;
+ enable_depth_range = false;
+ depth_range_min = 0;
+ depth_range_max = 0;
+ enable_stencil = false;
+ }
+ };
+
+ struct PipelineColorBlendState {
+
+ bool enable_logic_op;
+ LogicOperation logic_op;
+ struct Attachment {
+ bool enable_blend;
+ BlendFactor src_color_blend_factor;
+ BlendFactor dst_color_blend_factor;
+ BlendOperation color_blend_op;
+ BlendFactor src_alpha_blend_factor;
+ BlendFactor dst_alpha_blend_factor;
+ BlendOperation alpha_blend_op;
+ bool write_r;
+ bool write_g;
+ bool write_b;
+ bool write_a;
+ Attachment() {
+ enable_blend = false;
+ src_color_blend_factor = BLEND_FACTOR_ZERO;
+ dst_color_blend_factor = BLEND_FACTOR_ZERO;
+ color_blend_op = BLEND_OP_ADD;
+ src_alpha_blend_factor = BLEND_FACTOR_ZERO;
+ dst_alpha_blend_factor = BLEND_FACTOR_ZERO;
+ alpha_blend_op = BLEND_OP_ADD;
+ write_r = true;
+ write_g = true;
+ write_b = true;
+ write_a = true;
+ }
+ };
+
+ static PipelineColorBlendState create_disabled(int p_attachments = 1) {
+ PipelineColorBlendState bs;
+ for (int i = 0; i < p_attachments; i++) {
+ bs.attachments.push_back(Attachment());
+ }
+ return bs;
+ }
+
+ static PipelineColorBlendState create_blend(int p_attachments = 1) {
+ PipelineColorBlendState bs;
+ for (int i = 0; i < p_attachments; i++) {
+
+ Attachment ba;
+ ba.enable_blend = true;
+ ba.src_color_blend_factor = BLEND_FACTOR_SRC_ALPHA;
+ ba.dst_color_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ ba.src_alpha_blend_factor = BLEND_FACTOR_SRC_ALPHA;
+ ba.dst_alpha_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ bs.attachments.push_back(ba);
+ }
+ return bs;
+ }
+
+ Vector<Attachment> attachments; //one per render target texture
+ Color blend_constant;
+
+ PipelineColorBlendState() {
+ enable_logic_op = false;
+ logic_op = LOGIC_OP_CLEAR;
+ }
+ };
+
+ enum PipelineDynamicStateFlags {
+ DYNAMIC_STATE_LINE_WIDTH = (1 << 0),
+ DYNAMIC_STATE_DEPTH_BIAS = (1 << 1),
+ DYNAMIC_STATE_BLEND_CONSTANTS = (1 << 2),
+ DYNAMIC_STATE_DEPTH_BOUNDS = (1 << 3),
+ DYNAMIC_STATE_STENCIL_COMPARE_MASK = (1 << 4),
+ DYNAMIC_STATE_STENCIL_WRITE_MASK = (1 << 5),
+ DYNAMIC_STATE_STENCIL_REFERENCE = (1 << 6),
+ };
+
+ virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0;
+ virtual bool render_pipeline_is_valid(RID p_pipeline) = 0;
+
+ /**************************/
+ /**** COMPUTE PIPELINE ****/
+ /**************************/
+
+ virtual RID compute_pipeline_create(RID p_shader) = 0;
+ virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0;
+
+ /****************/
+ /**** SCREEN ****/
+ /****************/
+
+ virtual int screen_get_width(DisplayServer::WindowID p_screen = 0) const = 0;
+ virtual int screen_get_height(DisplayServer::WindowID p_screen = 0) const = 0;
+ virtual FramebufferFormatID screen_get_framebuffer_format() const = 0;
+
+ /********************/
+ /**** DRAW LISTS ****/
+ /********************/
+
+ enum InitialAction {
+ INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params)
+ INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared)
+ INITIAL_ACTION_DROP, //start rendering, ignore what is there, just write above it
+ INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action previously)
+ INITIAL_ACTION_MAX
+ };
+
+ enum FinalAction {
+ FINAL_ACTION_READ, //will no longer render to it, allows attached textures to be read again, but depth buffer contents will be dropped (Can't be read from)
+ FINAL_ACTION_DISCARD, // discard contents after rendering
+ FINAL_ACTION_CONTINUE, //will continue rendering later, attached textures can't be read until re-bound with "finish"
+ FINAL_ACTION_MAX
+ };
+
+ typedef int64_t DrawListID;
+
+ virtual DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color()) = 0;
+ virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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()) = 0;
+ virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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()) = 0;
+
+ virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0;
+ virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
+ virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0;
+ virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array) = 0;
+ virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0;
+ virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0;
+
+ virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0) = 0;
+
+ virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
+ virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
+
+ virtual void draw_list_end() = 0;
+
+ /***********************/
+ /**** COMPUTE LISTS ****/
+ /***********************/
+
+ typedef int64_t ComputeListID;
+
+ virtual ComputeListID compute_list_begin() = 0;
+ virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) = 0;
+ virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
+ virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) = 0;
+ virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
+ virtual void compute_list_add_barrier(ComputeListID p_list) = 0;
+
+ virtual void compute_list_end() = 0;
+
+ /***************/
+ /**** FREE! ****/
+ /***************/
+
+ virtual void free(RID p_id) = 0;
+
+ /****************/
+ /**** Timing ****/
+ /****************/
+
+ virtual void capture_timestamp(const String &p_name, bool p_sync_to_draw) = 0;
+ virtual uint32_t get_captured_timestamps_count() const = 0;
+ virtual uint64_t get_captured_timestamps_frame() const = 0;
+ virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0;
+ virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0;
+ virtual String get_captured_timestamp_name(uint32_t p_index) const = 0;
+
+ /****************/
+ /**** LIMITS ****/
+ /****************/
+
+ enum Limit {
+ LIMIT_MAX_BOUND_UNIFORM_SETS,
+ LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS,
+ LIMIT_MAX_TEXTURES_PER_UNIFORM_SET,
+ LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET,
+ LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET,
+ LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET,
+ LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET,
+ LIMIT_MAX_DRAW_INDEXED_INDEX,
+ LIMIT_MAX_FRAMEBUFFER_HEIGHT,
+ LIMIT_MAX_FRAMEBUFFER_WIDTH,
+ LIMIT_MAX_TEXTURE_ARRAY_LAYERS,
+ LIMIT_MAX_TEXTURE_SIZE_1D,
+ LIMIT_MAX_TEXTURE_SIZE_2D,
+ LIMIT_MAX_TEXTURE_SIZE_3D,
+ LIMIT_MAX_TEXTURE_SIZE_CUBE,
+ LIMIT_MAX_TEXTURES_PER_SHADER_STAGE,
+ LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE,
+ LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE,
+ LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE,
+ LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE,
+ LIMIT_MAX_PUSH_CONSTANT_SIZE,
+ LIMIT_MAX_UNIFORM_BUFFER_SIZE,
+ LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET,
+ LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES,
+ LIMIT_MAX_VERTEX_INPUT_BINDINGS,
+ LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE,
+ LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
+ LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE,
+ LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X,
+ LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y,
+ LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z,
+ LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS,
+ LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X,
+ LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y,
+ LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z,
+ };
+
+ virtual int limit_get(Limit p_limit) = 0;
+
+ //methods below not exposed, used by RenderingDeviceRD
+ virtual void prepare_screen_for_drawing() = 0;
+
+ virtual void swap_buffers() = 0;
+
+ virtual uint32_t get_frame_delay() const = 0;
+
+ static RenderingDevice *get_singleton();
+
+ RenderingDevice();
+};
+
+typedef RenderingDevice RD;
+
+#endif // RENDERING_DEVICE_H
diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp
new file mode 100644
index 0000000000..5d6dcfd2c1
--- /dev/null
+++ b/servers/rendering/rendering_server_canvas.cpp
@@ -0,0 +1,1479 @@
+/*************************************************************************/
+/* rendering_server_canvas.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_canvas.h"
+#include "rendering_server_globals.h"
+#include "rendering_server_raster.h"
+#include "rendering_server_viewport.h"
+
+static const int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1;
+
+void RenderingServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) {
+
+ RENDER_TIMESTAMP("Cull CanvasItem Tree");
+
+ memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
+ memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
+
+ for (int i = 0; i < p_child_item_count; i++) {
+ _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr);
+ }
+ if (p_canvas_item) {
+ _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr);
+ }
+
+ RasterizerCanvas::Item *list = nullptr;
+ RasterizerCanvas::Item *list_end = nullptr;
+
+ for (int i = 0; i < z_range; i++) {
+ if (!z_list[i])
+ continue;
+ if (!list) {
+ list = z_list[i];
+ list_end = z_last_list[i];
+ } else {
+ list_end->next = z_list[i];
+ list_end = z_last_list[i];
+ }
+ }
+
+ RENDER_TIMESTAMP("Render Canvas Items");
+
+ RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform);
+}
+
+void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transform2D p_transform, RenderingServerCanvas::Item *p_material_owner, RenderingServerCanvas::Item **r_items, int &r_index) {
+ int child_item_count = p_canvas_item->child_items.size();
+ RenderingServerCanvas::Item **child_items = p_canvas_item->child_items.ptrw();
+ for (int i = 0; i < child_item_count; i++) {
+ if (child_items[i]->visible) {
+ if (r_items) {
+ r_items[r_index] = child_items[i];
+ child_items[i]->ysort_xform = p_transform;
+ child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.elements[2]);
+ child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
+ }
+
+ r_index++;
+
+ if (child_items[i]->sort_y)
+ _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], r_items, r_index);
+ }
+ }
+}
+
+void _mark_ysort_dirty(RenderingServerCanvas::Item *ysort_owner, RID_PtrOwner<RenderingServerCanvas::Item> &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;
+ } while (ysort_owner && ysort_owner->sort_y);
+}
+
+void RenderingServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) {
+
+ Item *ci = p_canvas_item;
+
+ if (!ci->visible)
+ return;
+
+ if (ci->children_order_dirty) {
+
+ ci->child_items.sort_custom<ItemIndexSort>();
+ ci->children_order_dirty = false;
+ }
+
+ Rect2 rect = ci->get_rect();
+ Transform2D xform = p_transform * ci->xform;
+ Rect2 global_rect = xform.xform(rect);
+ global_rect.position += p_clip_rect.position;
+
+ if (ci->use_parent_material && p_material_owner)
+ ci->material_owner = p_material_owner;
+ else {
+ p_material_owner = ci;
+ ci->material_owner = nullptr;
+ }
+
+ Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a);
+
+ if (modulate.a < 0.007)
+ return;
+
+ int child_item_count = ci->child_items.size();
+ Item **child_items = ci->child_items.ptrw();
+
+ if (ci->clip) {
+ if (p_canvas_clip != nullptr) {
+ ci->final_clip_rect = p_canvas_clip->final_clip_rect.clip(global_rect);
+ } else {
+ ci->final_clip_rect = global_rect;
+ }
+ ci->final_clip_owner = ci;
+
+ } else {
+ ci->final_clip_owner = p_canvas_clip;
+ }
+
+ if (ci->sort_y) {
+
+ if (ci->ysort_children_count == -1) {
+ ci->ysort_children_count = 0;
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count);
+ }
+
+ child_item_count = ci->ysort_children_count;
+ child_items = (Item **)alloca(child_item_count * sizeof(Item *));
+
+ int i = 0;
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i);
+
+ SortArray<Item *, ItemPtrSort> sorter;
+ sorter.sort(child_items, child_item_count);
+ }
+
+ if (ci->z_relative)
+ p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
+ else
+ p_z = ci->z_index;
+
+ for (int i = 0; i < child_item_count; i++) {
+
+ if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y))
+ continue;
+ if (ci->sort_y) {
+ _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
+ } else {
+ _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
+ }
+ }
+
+ if (ci->copy_back_buffer) {
+
+ ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);
+ }
+
+ if (ci->update_when_visible) {
+ RenderingServerRaster::redraw_request();
+ }
+
+ if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
+ //something to draw?
+ ci->final_transform = xform;
+ ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
+ ci->global_rect_cache = global_rect;
+ ci->global_rect_cache.position -= p_clip_rect.position;
+ ci->light_masked = false;
+
+ int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
+
+ if (z_last_list[zidx]) {
+ z_last_list[zidx]->next = ci;
+ z_last_list[zidx] = ci;
+
+ } else {
+ z_list[zidx] = ci;
+ z_last_list[zidx] = ci;
+ }
+
+ ci->z_final = p_z;
+
+ ci->next = nullptr;
+ }
+
+ for (int i = 0; i < child_item_count; i++) {
+
+ if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y))
+ continue;
+ if (ci->sort_y) {
+ _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
+ } else {
+ _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
+ }
+ }
+}
+
+void RenderingServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights) {
+
+ if (!p_masked_lights)
+ return;
+
+ RasterizerCanvas::Item *ci = p_canvas_item;
+
+ while (ci) {
+
+ RasterizerCanvas::Light *light = p_masked_lights;
+ while (light) {
+
+ if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
+ ci->light_masked = true;
+ }
+
+ light = light->mask_next_ptr;
+ }
+
+ ci = ci->next;
+ }
+}
+
+void RenderingServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) {
+
+ RENDER_TIMESTAMP(">Render Canvas");
+
+ if (p_canvas->children_order_dirty) {
+
+ p_canvas->child_items.sort();
+ p_canvas->children_order_dirty = false;
+ }
+
+ int l = p_canvas->child_items.size();
+ Canvas::ChildItem *ci = p_canvas->child_items.ptrw();
+
+ bool has_mirror = false;
+ for (int i = 0; i < l; i++) {
+ if (ci[i].mirror.x || ci[i].mirror.y) {
+ has_mirror = true;
+ break;
+ }
+ }
+
+ if (!has_mirror) {
+
+ _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
+
+ } else {
+ //used for parallaxlayer mirroring
+ for (int i = 0; i < l; i++) {
+
+ const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
+
+ //mirroring (useful for scrolling backgrounds)
+ if (ci2.mirror.x != 0) {
+
+ Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
+ }
+ if (ci2.mirror.y != 0) {
+
+ Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
+ }
+ if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
+
+ Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
+ }
+ }
+ }
+
+ RENDER_TIMESTAMP("<End Render Canvas");
+}
+
+RID RenderingServerCanvas::canvas_create() {
+
+ Canvas *canvas = memnew(Canvas);
+ ERR_FAIL_COND_V(!canvas, RID());
+ RID rid = canvas_owner.make_rid(canvas);
+
+ return rid;
+}
+
+void RenderingServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) {
+
+ Canvas *canvas = canvas_owner.getornull(p_canvas);
+ ERR_FAIL_COND(!canvas);
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ int idx = canvas->find_item(canvas_item);
+ ERR_FAIL_COND(idx == -1);
+ canvas->child_items.write[idx].mirror = p_mirroring;
+}
+void RenderingServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) {
+
+ Canvas *canvas = canvas_owner.getornull(p_canvas);
+ ERR_FAIL_COND(!canvas);
+ canvas->modulate = p_color;
+}
+
+void RenderingServerCanvas::canvas_set_disable_scale(bool p_disable) {
+ disable_scale = p_disable;
+}
+
+void RenderingServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) {
+
+ Canvas *canvas = canvas_owner.getornull(p_canvas);
+ ERR_FAIL_COND(!canvas);
+
+ canvas->parent = p_parent;
+ canvas->parent_scale = p_scale;
+}
+
+RID RenderingServerCanvas::canvas_item_create() {
+
+ Item *canvas_item = memnew(Item);
+ ERR_FAIL_COND_V(!canvas_item, RID());
+
+ return canvas_item_owner.make_rid(canvas_item);
+}
+
+void RenderingServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ if (canvas_item->parent.is_valid()) {
+
+ if (canvas_owner.owns(canvas_item->parent)) {
+
+ Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
+ canvas->erase_item(canvas_item);
+ } else if (canvas_item_owner.owns(canvas_item->parent)) {
+
+ Item *item_owner = canvas_item_owner.getornull(canvas_item->parent);
+ item_owner->child_items.erase(canvas_item);
+
+ if (item_owner->sort_y) {
+ _mark_ysort_dirty(item_owner, canvas_item_owner);
+ }
+ }
+
+ canvas_item->parent = RID();
+ }
+
+ if (p_parent.is_valid()) {
+ if (canvas_owner.owns(p_parent)) {
+
+ Canvas *canvas = canvas_owner.getornull(p_parent);
+ Canvas::ChildItem ci;
+ ci.item = canvas_item;
+ canvas->child_items.push_back(ci);
+ canvas->children_order_dirty = true;
+ } else if (canvas_item_owner.owns(p_parent)) {
+
+ Item *item_owner = canvas_item_owner.getornull(p_parent);
+ item_owner->child_items.push_back(canvas_item);
+ item_owner->children_order_dirty = true;
+
+ if (item_owner->sort_y) {
+ _mark_ysort_dirty(item_owner, canvas_item_owner);
+ }
+
+ } else {
+
+ ERR_FAIL_MSG("Invalid parent.");
+ }
+ }
+
+ canvas_item->parent = p_parent;
+}
+void RenderingServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->visible = p_visible;
+
+ _mark_ysort_dirty(canvas_item, canvas_item_owner);
+}
+void RenderingServerCanvas::canvas_item_set_light_mask(RID p_item, int p_mask) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->light_mask = p_mask;
+}
+
+void RenderingServerCanvas::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->xform = p_transform;
+}
+void RenderingServerCanvas::canvas_item_set_clip(RID p_item, bool p_clip) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->clip = p_clip;
+}
+void RenderingServerCanvas::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->distance_field = p_enable;
+}
+void RenderingServerCanvas::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->custom_rect = p_custom_rect;
+ canvas_item->rect = p_rect;
+}
+void RenderingServerCanvas::canvas_item_set_modulate(RID p_item, const Color &p_color) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->modulate = p_color;
+}
+void RenderingServerCanvas::canvas_item_set_self_modulate(RID p_item, const Color &p_color) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->self_modulate = p_color;
+}
+
+void RenderingServerCanvas::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->behind = p_enable;
+}
+
+void RenderingServerCanvas::canvas_item_set_update_when_visible(RID p_item, bool p_update) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->update_when_visible = p_update;
+}
+
+void RenderingServerCanvas::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+ canvas_item->texture_filter = p_filter;
+}
+
+void RenderingServerCanvas::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+ canvas_item->texture_repeat = p_repeat;
+}
+
+void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!line);
+ if (p_width > 1.001) {
+
+ Vector2 t = (p_from - p_to).tangent().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;
+ line->point_count = 4;
+ } else {
+ line->point_count = 2;
+ line->points[0] = p_from;
+ line->points[1] = p_to;
+ }
+ for (uint32_t i = 0; i < line->point_count; i++) {
+ line->colors[i] = p_color;
+ }
+ line->specular_shininess = Color(1, 1, 1, 1);
+}
+
+void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+
+ ERR_FAIL_COND(p_points.size() < 2);
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!pline);
+
+ pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
+
+ if (true || p_width <= 1) {
+#define TODO make thick lines possible
+ Vector<int> indices;
+ int pc = p_points.size();
+ indices.resize((pc - 1) * 2);
+ {
+ int *iptr = indices.ptrw();
+ for (int i = 0; i < (pc - 1); i++) {
+ iptr[i * 2 + 0] = i;
+ iptr[i * 2 + 1] = i + 1;
+ }
+ }
+
+ pline->primitive = RS::PRIMITIVE_LINES;
+ pline->specular_shininess = Color(1, 1, 1, 1);
+ pline->polygon.create(indices, p_points, p_colors);
+ } else {
+#if 0
+ //make a trianglestrip for drawing the line...
+ Vector2 prev_t;
+ pline->triangles.resize(p_points.size() * 2);
+ if (p_antialiased) {
+ pline->lines.resize(p_points.size() * 2);
+ }
+
+ if (p_colors.size() == 0) {
+ pline->triangle_colors.push_back(Color(1, 1, 1, 1));
+ if (p_antialiased) {
+ pline->line_colors.push_back(Color(1, 1, 1, 1));
+ }
+ } else if (p_colors.size() == 1) {
+ pline->triangle_colors = p_colors;
+ pline->line_colors = p_colors;
+ } else {
+ if (p_colors.size() != p_points.size()) {
+ pline->triangle_colors.push_back(p_colors[0]);
+ pline->line_colors.push_back(p_colors[0]);
+ } else {
+ pline->triangle_colors.resize(pline->triangles.size());
+ pline->line_colors.resize(pline->lines.size());
+ }
+ }
+
+ for (int i = 0; i < p_points.size(); i++) {
+
+ Vector2 t;
+ if (i == p_points.size() - 1) {
+ t = prev_t;
+ } else {
+ t = (p_points[i + 1] - p_points[i]).normalized().tangent();
+ if (i == 0) {
+ prev_t = t;
+ }
+ }
+
+ Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+
+ if (p_antialiased) {
+ pline->lines.write[i] = p_points[i] + tangent;
+ pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent;
+ if (pline->line_colors.size() > 1) {
+ pline->line_colors.write[i] = p_colors[i];
+ pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i];
+ }
+ }
+
+ pline->triangles.write[i * 2 + 0] = p_points[i] + tangent;
+ pline->triangles.write[i * 2 + 1] = p_points[i] - tangent;
+
+ if (pline->triangle_colors.size() > 1) {
+
+ pline->triangle_colors.write[i * 2 + 0] = p_colors[i];
+ pline->triangle_colors.write[i * 2 + 1] = p_colors[i];
+ }
+
+ prev_t = t;
+ }
+#endif
+ }
+}
+
+void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+
+ ERR_FAIL_COND(p_points.size() < 2);
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!pline);
+
+ pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
+
+ if (true || p_width <= 1) {
+#define TODO make thick lines possible
+
+ pline->primitive = RS::PRIMITIVE_LINES;
+ pline->specular_shininess = Color(1, 1, 1, 1);
+ pline->polygon.create(Vector<int>(), p_points, p_colors);
+ } else {
+ }
+}
+
+void RenderingServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
+ ERR_FAIL_COND(!rect);
+ rect->modulate = p_color;
+ rect->rect = p_rect;
+}
+
+void RenderingServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!circle);
+
+ circle->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
+
+ circle->primitive = RS::PRIMITIVE_TRIANGLES;
+ circle->specular_shininess = Color(1, 1, 1, 1);
+
+ Vector<int> indices;
+ Vector<Vector2> points;
+
+ static const int circle_points = 64;
+
+ points.resize(circle_points);
+ for (int i = 0; i < circle_points; i++) {
+ float angle = (i / float(circle_points)) * 2 * Math_PI;
+ points.write[i].x = Math::cos(angle) * p_radius;
+ points.write[i].y = Math::sin(angle) * p_radius;
+ points.write[i] += p_pos;
+ }
+ indices.resize((circle_points - 2) * 3);
+
+ for (int i = 0; i < circle_points - 2; i++) {
+ indices.write[i * 3 + 0] = 0;
+ indices.write[i * 3 + 1] = i + 1;
+ indices.write[i * 3 + 2] = i + 2;
+ }
+
+ Vector<Color> color;
+ color.push_back(p_color);
+ circle->polygon.create(indices, points, color);
+}
+
+void RenderingServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
+ ERR_FAIL_COND(!rect);
+ rect->modulate = p_modulate;
+ rect->rect = p_rect;
+ rect->flags = 0;
+ if (p_tile) {
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_TILE;
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_REGION;
+ rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height));
+ }
+
+ if (p_rect.size.x < 0) {
+
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H;
+ rect->rect.size.x = -rect->rect.size.x;
+ }
+ if (p_rect.size.y < 0) {
+
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V;
+ rect->rect.size.y = -rect->rect.size.y;
+ }
+ if (p_transpose) {
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE;
+ SWAP(rect->rect.size.x, rect->rect.size.y);
+ }
+ rect->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ rect->specular_shininess = p_specular_color_shininess;
+}
+
+void RenderingServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
+ ERR_FAIL_COND(!rect);
+ rect->modulate = p_modulate;
+ rect->rect = p_rect;
+ rect->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ rect->specular_shininess = p_specular_color_shininess;
+ rect->source = p_src_rect;
+ rect->flags = RasterizerCanvas::CANVAS_RECT_REGION;
+
+ if (p_rect.size.x < 0) {
+
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H;
+ rect->rect.size.x = -rect->rect.size.x;
+ }
+ if (p_src_rect.size.x < 0) {
+
+ rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_H;
+ rect->source.size.x = -rect->source.size.x;
+ }
+ if (p_rect.size.y < 0) {
+
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V;
+ rect->rect.size.y = -rect->rect.size.y;
+ }
+ if (p_src_rect.size.y < 0) {
+
+ rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_V;
+ rect->source.size.y = -rect->source.size.y;
+ }
+
+ if (p_transpose) {
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE;
+ SWAP(rect->rect.size.x, rect->rect.size.y);
+ }
+
+ if (p_clip_uv) {
+ rect->flags |= RasterizerCanvas::CANVAS_RECT_CLIP_UV;
+ }
+}
+
+void RenderingServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandNinePatch *style = canvas_item->alloc_command<Item::CommandNinePatch>();
+ ERR_FAIL_COND(!style);
+ style->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ style->specular_shininess = p_specular_color_shininess;
+ style->rect = p_rect;
+ style->source = p_source;
+ style->draw_center = p_draw_center;
+ style->color = p_modulate;
+ style->margin[MARGIN_LEFT] = p_topleft.x;
+ style->margin[MARGIN_TOP] = p_topleft.y;
+ style->margin[MARGIN_RIGHT] = p_bottomright.x;
+ style->margin[MARGIN_BOTTOM] = p_bottomright.y;
+ style->axis_x = p_x_axis_mode;
+ style->axis_y = p_y_axis_mode;
+}
+void RenderingServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ uint32_t pc = p_points.size();
+ ERR_FAIL_COND(pc == 0 || pc > 4);
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandPrimitive *prim = canvas_item->alloc_command<Item::CommandPrimitive>();
+ ERR_FAIL_COND(!prim);
+
+ for (int i = 0; i < p_points.size(); i++) {
+ prim->points[i] = p_points[i];
+ if (i < p_uvs.size()) {
+ prim->uvs[i] = p_uvs[i];
+ }
+ if (i < p_colors.size()) {
+ prim->colors[i] = p_colors[i];
+ } else if (p_colors.size()) {
+ prim->colors[i] = p_colors[0];
+ } else {
+ prim->colors[i] = Color(1, 1, 1, 1);
+ }
+ }
+
+ prim->point_count = p_points.size();
+
+ prim->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ prim->specular_shininess = p_specular_color_shininess;
+}
+
+void RenderingServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+#ifdef DEBUG_ENABLED
+ int pointcount = p_points.size();
+ ERR_FAIL_COND(pointcount < 3);
+ int color_size = p_colors.size();
+ int uv_size = p_uvs.size();
+ ERR_FAIL_COND(color_size != 0 && color_size != 1 && color_size != pointcount);
+ ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount));
+#endif
+ Vector<int> indices = Geometry::triangulate_polygon(p_points);
+ ERR_FAIL_COND_MSG(indices.empty(), "Invalid polygon data, triangulation failed.");
+
+ Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!polygon);
+ polygon->primitive = RS::PRIMITIVE_TRIANGLES;
+ polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ polygon->specular_shininess = p_specular_color_shininess;
+ polygon->polygon.create(indices, p_points, p_colors, p_uvs);
+}
+
+void RenderingServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ int vertex_count = p_points.size();
+ ERR_FAIL_COND(vertex_count == 0);
+ ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != vertex_count && p_colors.size() != 1);
+ ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != vertex_count);
+ ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != vertex_count * 4);
+ ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != vertex_count * 4);
+
+ Vector<int> indices = p_indices;
+
+ Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
+ ERR_FAIL_COND(!polygon);
+ polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ polygon->specular_shininess = p_specular_color_shininess;
+ polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights);
+
+ polygon->primitive = RS::PRIMITIVE_TRIANGLES;
+}
+
+void RenderingServerCanvas::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandTransform *tr = canvas_item->alloc_command<Item::CommandTransform>();
+ ERR_FAIL_COND(!tr);
+ tr->xform = p_transform;
+}
+
+void RenderingServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>();
+ ERR_FAIL_COND(!m);
+ m->mesh = p_mesh;
+ m->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ m->specular_shininess = p_specular_color_shininess;
+ m->transform = p_transform;
+ m->modulate = p_modulate;
+}
+void RenderingServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandParticles *part = canvas_item->alloc_command<Item::CommandParticles>();
+ ERR_FAIL_COND(!part);
+ part->particles = p_particles;
+ part->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
+ part->specular_shininess = p_specular_color_shininess;
+
+ //take the chance and request processing for them, at least once until they become visible again
+ RSG::storage->particles_request_process(p_particles);
+}
+
+void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, RenderingServer::CanvasItemTextureFilter p_filter, RenderingServer::CanvasItemTextureRepeat p_repeat) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandMultiMesh *mm = canvas_item->alloc_command<Item::CommandMultiMesh>();
+ ERR_FAIL_COND(!mm);
+ mm->multimesh = p_mesh;
+ mm->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, mm->multimesh);
+ mm->specular_shininess = p_specular_color_shininess;
+}
+
+void RenderingServerCanvas::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandClipIgnore *ci = canvas_item->alloc_command<Item::CommandClipIgnore>();
+ ERR_FAIL_COND(!ci);
+ ci->ignore = p_ignore;
+}
+void RenderingServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->sort_y = p_enable;
+
+ _mark_ysort_dirty(canvas_item, canvas_item_owner);
+}
+void RenderingServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) {
+
+ ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX);
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->z_index = p_z;
+}
+void RenderingServerCanvas::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->z_relative = p_enable;
+}
+
+void RenderingServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->skeleton = p_skeleton;
+}
+
+void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+ if (bool(canvas_item->copy_back_buffer != nullptr) != p_enable) {
+ if (p_enable) {
+ canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer);
+ } else {
+ memdelete(canvas_item->copy_back_buffer);
+ canvas_item->copy_back_buffer = nullptr;
+ }
+ }
+
+ if (p_enable) {
+ canvas_item->copy_back_buffer->rect = p_rect;
+ canvas_item->copy_back_buffer->full = p_rect == Rect2();
+ }
+}
+
+void RenderingServerCanvas::canvas_item_clear(RID p_item) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->clear();
+}
+void RenderingServerCanvas::canvas_item_set_draw_index(RID p_item, int p_index) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->index = p_index;
+
+ if (canvas_item_owner.owns(canvas_item->parent)) {
+ Item *canvas_item_parent = canvas_item_owner.getornull(canvas_item->parent);
+ canvas_item_parent->children_order_dirty = true;
+ return;
+ }
+
+ Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
+ if (canvas) {
+ canvas->children_order_dirty = true;
+ return;
+ }
+}
+
+void RenderingServerCanvas::canvas_item_set_material(RID p_item, RID p_material) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->material = p_material;
+}
+
+void RenderingServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->use_parent_material = p_enable;
+}
+
+RID RenderingServerCanvas::canvas_light_create() {
+
+ RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light);
+ clight->light_internal = RSG::canvas_render->light_create();
+ return canvas_light_owner.make_rid(clight);
+}
+void RenderingServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ if (clight->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.getornull(clight->canvas);
+ canvas->lights.erase(clight);
+ }
+
+ if (!canvas_owner.owns(p_canvas))
+ p_canvas = RID();
+
+ clight->canvas = p_canvas;
+
+ if (clight->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.getornull(clight->canvas);
+ canvas->lights.insert(clight);
+ }
+}
+
+void RenderingServerCanvas::canvas_light_set_enabled(RID p_light, bool p_enabled) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->enabled = p_enabled;
+}
+void RenderingServerCanvas::canvas_light_set_scale(RID p_light, float p_scale) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->scale = p_scale;
+}
+void RenderingServerCanvas::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->xform = p_transform;
+}
+void RenderingServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->texture = p_texture;
+ clight->version++;
+ RSG::canvas_render->light_set_texture(clight->light_internal, p_texture);
+}
+void RenderingServerCanvas::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->texture_offset = p_offset;
+}
+void RenderingServerCanvas::canvas_light_set_color(RID p_light, const Color &p_color) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->color = p_color;
+}
+void RenderingServerCanvas::canvas_light_set_height(RID p_light, float p_height) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->height = p_height;
+}
+void RenderingServerCanvas::canvas_light_set_energy(RID p_light, float p_energy) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->energy = p_energy;
+}
+void RenderingServerCanvas::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->z_min = p_min_z;
+ clight->z_max = p_max_z;
+}
+void RenderingServerCanvas::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->layer_max = p_max_layer;
+ clight->layer_min = p_min_layer;
+}
+void RenderingServerCanvas::canvas_light_set_item_cull_mask(RID p_light, int p_mask) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->item_mask = p_mask;
+}
+void RenderingServerCanvas::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->item_shadow_mask = p_mask;
+}
+void RenderingServerCanvas::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->mode = p_mode;
+}
+
+void RenderingServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ if (clight->use_shadow == p_enabled) {
+ return;
+ }
+ clight->use_shadow = p_enabled;
+ clight->version++;
+ RSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow, clight->shadow_buffer_size);
+}
+
+void RenderingServerCanvas::canvas_light_set_shadow_buffer_size(RID p_light, int p_size) {
+
+ ERR_FAIL_COND(p_size < 32 || p_size > 16384);
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ int new_size = next_power_of_2(p_size);
+ if (new_size == clight->shadow_buffer_size)
+ return;
+
+ clight->shadow_buffer_size = next_power_of_2(p_size);
+ clight->version++;
+
+ RSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow, clight->shadow_buffer_size);
+}
+
+void RenderingServerCanvas::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->shadow_filter = p_filter;
+}
+void RenderingServerCanvas::canvas_light_set_shadow_color(RID p_light, const Color &p_color) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+
+ clight->shadow_color = p_color;
+}
+
+void RenderingServerCanvas::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) {
+
+ RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->shadow_smooth = p_smooth;
+}
+
+RID RenderingServerCanvas::canvas_light_occluder_create() {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = memnew(RasterizerCanvas::LightOccluderInstance);
+
+ return canvas_light_occluder_owner.make_rid(occluder);
+}
+void RenderingServerCanvas::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ if (occluder->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.getornull(occluder->canvas);
+ canvas->occluders.erase(occluder);
+ }
+
+ if (!canvas_owner.owns(p_canvas))
+ p_canvas = RID();
+
+ occluder->canvas = p_canvas;
+
+ if (occluder->canvas.is_valid()) {
+
+ Canvas *canvas = canvas_owner.getornull(occluder->canvas);
+ canvas->occluders.insert(occluder);
+ }
+}
+void RenderingServerCanvas::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->enabled = p_enabled;
+}
+void RenderingServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ if (occluder->polygon.is_valid()) {
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
+ if (occluder_poly) {
+ occluder_poly->owners.erase(occluder);
+ }
+ }
+
+ occluder->polygon = p_polygon;
+ occluder->occluder = RID();
+
+ if (occluder->polygon.is_valid()) {
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
+ if (!occluder_poly) {
+ occluder->polygon = RID();
+ ERR_FAIL_COND(!occluder_poly);
+ } else {
+ occluder_poly->owners.insert(occluder);
+ occluder->occluder = occluder_poly->occluder;
+ occluder->aabb_cache = occluder_poly->aabb;
+ occluder->cull_cache = occluder_poly->cull_mode;
+ }
+ }
+}
+void RenderingServerCanvas::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->xform = p_xform;
+}
+void RenderingServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
+ ERR_FAIL_COND(!occluder);
+
+ occluder->light_mask = p_mask;
+}
+
+RID RenderingServerCanvas::canvas_occluder_polygon_create() {
+
+ LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon);
+ occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create();
+ return canvas_light_occluder_polygon_owner.make_rid(occluder_poly);
+}
+void RenderingServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
+
+ if (p_shape.size() < 3) {
+ canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, p_shape);
+ return;
+ }
+
+ Vector<Vector2> lines;
+ int lc = p_shape.size() * 2;
+
+ lines.resize(lc - (p_closed ? 0 : 2));
+ {
+ Vector2 *w = lines.ptrw();
+ const Vector2 *r = p_shape.ptr();
+
+ int max = lc / 2;
+ if (!p_closed) {
+ max--;
+ }
+ for (int i = 0; i < max; i++) {
+
+ Vector2 a = r[i];
+ Vector2 b = r[(i + 1) % (lc / 2)];
+ w[i * 2 + 0] = a;
+ w[i * 2 + 1] = b;
+ }
+ }
+
+ canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, lines);
+}
+void RenderingServerCanvas::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) {
+
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
+ ERR_FAIL_COND(!occluder_poly);
+ ERR_FAIL_COND(p_shape.size() & 1);
+
+ int lc = p_shape.size();
+ occluder_poly->aabb = Rect2();
+ {
+ const Vector2 *r = p_shape.ptr();
+ for (int i = 0; i < lc; i++) {
+ if (i == 0)
+ occluder_poly->aabb.position = r[i];
+ else
+ occluder_poly->aabb.expand_to(r[i]);
+ }
+ }
+
+ RSG::canvas_render->occluder_polygon_set_shape_as_lines(occluder_poly->occluder, p_shape);
+ for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
+ E->get()->aabb_cache = occluder_poly->aabb;
+ }
+}
+
+void RenderingServerCanvas::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) {
+
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
+ ERR_FAIL_COND(!occluder_poly);
+ occluder_poly->cull_mode = p_mode;
+ RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode);
+ for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
+ E->get()->cull_cache = p_mode;
+ }
+}
+
+bool RenderingServerCanvas::free(RID p_rid) {
+
+ if (canvas_owner.owns(p_rid)) {
+
+ Canvas *canvas = canvas_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!canvas, false);
+
+ while (canvas->viewports.size()) {
+
+ RenderingServerViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get());
+ ERR_FAIL_COND_V(!vp, true);
+
+ Map<RID, RenderingServerViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid);
+ ERR_FAIL_COND_V(!E, true);
+ vp->canvas_map.erase(p_rid);
+
+ canvas->viewports.erase(canvas->viewports.front());
+ }
+
+ for (int i = 0; i < canvas->child_items.size(); i++) {
+
+ canvas->child_items[i].item->parent = RID();
+ }
+
+ for (Set<RasterizerCanvas::Light *>::Element *E = canvas->lights.front(); E; E = E->next()) {
+
+ E->get()->canvas = RID();
+ }
+
+ for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = canvas->occluders.front(); E; E = E->next()) {
+
+ E->get()->canvas = RID();
+ }
+
+ canvas_owner.free(p_rid);
+
+ memdelete(canvas);
+
+ } else if (canvas_item_owner.owns(p_rid)) {
+
+ Item *canvas_item = canvas_item_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!canvas_item, true);
+
+ if (canvas_item->parent.is_valid()) {
+
+ if (canvas_owner.owns(canvas_item->parent)) {
+
+ Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
+ canvas->erase_item(canvas_item);
+ } else if (canvas_item_owner.owns(canvas_item->parent)) {
+
+ Item *item_owner = canvas_item_owner.getornull(canvas_item->parent);
+ item_owner->child_items.erase(canvas_item);
+
+ if (item_owner->sort_y) {
+ _mark_ysort_dirty(item_owner, canvas_item_owner);
+ }
+ }
+ }
+
+ for (int i = 0; i < canvas_item->child_items.size(); i++) {
+
+ canvas_item->child_items[i]->parent = RID();
+ }
+
+ /*
+ if (canvas_item->material) {
+ canvas_item->material->owners.erase(canvas_item);
+ }
+ */
+
+ canvas_item_owner.free(p_rid);
+
+ memdelete(canvas_item);
+
+ } else if (canvas_light_owner.owns(p_rid)) {
+
+ RasterizerCanvas::Light *canvas_light = canvas_light_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!canvas_light, true);
+
+ if (canvas_light->canvas.is_valid()) {
+ Canvas *canvas = canvas_owner.getornull(canvas_light->canvas);
+ if (canvas)
+ canvas->lights.erase(canvas_light);
+ }
+
+ RSG::canvas_render->free(canvas_light->light_internal);
+
+ canvas_light_owner.free(p_rid);
+ memdelete(canvas_light);
+
+ } else if (canvas_light_occluder_owner.owns(p_rid)) {
+
+ RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!occluder, true);
+
+ if (occluder->polygon.is_valid()) {
+
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(occluder->polygon);
+ if (occluder_poly) {
+ occluder_poly->owners.erase(occluder);
+ }
+ }
+
+ if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) {
+
+ Canvas *canvas = canvas_owner.getornull(occluder->canvas);
+ canvas->occluders.erase(occluder);
+ }
+
+ canvas_light_occluder_owner.free(p_rid);
+ memdelete(occluder);
+
+ } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
+
+ LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid);
+ ERR_FAIL_COND_V(!occluder_poly, true);
+ RSG::canvas_render->free(occluder_poly->occluder);
+
+ while (occluder_poly->owners.size()) {
+
+ occluder_poly->owners.front()->get()->polygon = RID();
+ occluder_poly->owners.erase(occluder_poly->owners.front());
+ }
+
+ canvas_light_occluder_polygon_owner.free(p_rid);
+ memdelete(occluder_poly);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+RenderingServerCanvas::RenderingServerCanvas() {
+
+ z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
+ z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
+
+ disable_scale = false;
+}
+
+RenderingServerCanvas::~RenderingServerCanvas() {
+
+ memfree(z_list);
+ memfree(z_last_list);
+}
diff --git a/servers/rendering/rendering_server_canvas.h b/servers/rendering/rendering_server_canvas.h
new file mode 100644
index 0000000000..9da11462db
--- /dev/null
+++ b/servers/rendering/rendering_server_canvas.h
@@ -0,0 +1,270 @@
+/*************************************************************************/
+/* rendering_server_canvas.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VISUALSERVERCANVAS_H
+#define VISUALSERVERCANVAS_H
+
+#include "rasterizer.h"
+#include "rendering_server_viewport.h"
+
+class RenderingServerCanvas {
+public:
+ struct Item : public RasterizerCanvas::Item {
+
+ RID parent; // canvas it belongs to
+ List<Item *>::Element *E;
+ int z_index;
+ bool z_relative;
+ bool sort_y;
+ Color modulate;
+ Color self_modulate;
+ bool use_parent_material;
+ int index;
+ bool children_order_dirty;
+ int ysort_children_count;
+ Color ysort_modulate;
+ Transform2D ysort_xform;
+ Vector2 ysort_pos;
+ RS::CanvasItemTextureFilter texture_filter;
+ RS::CanvasItemTextureRepeat texture_repeat;
+
+ Vector<Item *> child_items;
+
+ Item() {
+ children_order_dirty = true;
+ E = nullptr;
+ z_index = 0;
+ modulate = Color(1, 1, 1, 1);
+ self_modulate = Color(1, 1, 1, 1);
+ sort_y = false;
+ use_parent_material = false;
+ z_relative = true;
+ index = 0;
+ ysort_children_count = -1;
+ ysort_xform = Transform2D();
+ ysort_pos = Vector2();
+ texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
+ texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
+ }
+ };
+
+ struct ItemIndexSort {
+
+ _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
+
+ return p_left->index < p_right->index;
+ }
+ };
+
+ struct ItemPtrSort {
+
+ _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
+
+ if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y))
+ return p_left->ysort_pos.x < p_right->ysort_pos.x;
+
+ return p_left->ysort_pos.y < p_right->ysort_pos.y;
+ }
+ };
+
+ struct LightOccluderPolygon {
+
+ bool active;
+ Rect2 aabb;
+ RS::CanvasOccluderPolygonCullMode cull_mode;
+ RID occluder;
+ Set<RasterizerCanvas::LightOccluderInstance *> owners;
+
+ LightOccluderPolygon() {
+ active = false;
+ cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+ }
+ };
+
+ RID_PtrOwner<LightOccluderPolygon> canvas_light_occluder_polygon_owner;
+
+ RID_PtrOwner<RasterizerCanvas::LightOccluderInstance> canvas_light_occluder_owner;
+
+ struct Canvas : public RenderingServerViewport::CanvasBase {
+
+ Set<RID> viewports;
+ struct ChildItem {
+
+ Point2 mirror;
+ Item *item;
+ bool operator<(const ChildItem &p_item) const {
+ return item->index < p_item.item->index;
+ }
+ };
+
+ Set<RasterizerCanvas::Light *> lights;
+
+ Set<RasterizerCanvas::LightOccluderInstance *> occluders;
+
+ bool children_order_dirty;
+ Vector<ChildItem> child_items;
+ Color modulate;
+ RID parent;
+ float parent_scale;
+
+ int find_item(Item *p_item) {
+ for (int i = 0; i < child_items.size(); i++) {
+ if (child_items[i].item == p_item)
+ return i;
+ }
+ return -1;
+ }
+ void erase_item(Item *p_item) {
+ int idx = find_item(p_item);
+ if (idx >= 0)
+ child_items.remove(idx);
+ }
+
+ Canvas() {
+ modulate = Color(1, 1, 1, 1);
+ children_order_dirty = true;
+ parent_scale = 1.0;
+ }
+ };
+
+ mutable RID_PtrOwner<Canvas> canvas_owner;
+ RID_PtrOwner<Item> canvas_item_owner;
+ RID_PtrOwner<RasterizerCanvas::Light> canvas_light_owner;
+
+ bool disable_scale;
+
+private:
+ void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights);
+ void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
+ void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights);
+
+ RasterizerCanvas::Item **z_list;
+ RasterizerCanvas::Item **z_last_list;
+
+public:
+ void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect);
+
+ RID canvas_create();
+ 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();
+ void canvas_item_set_parent(RID p_item, RID p_parent);
+
+ void canvas_item_set_visible(RID p_item, bool p_visible);
+ void canvas_item_set_light_mask(RID p_item, int p_mask);
+
+ void canvas_item_set_transform(RID p_item, const Transform2D &p_transform);
+ void canvas_item_set_clip(RID p_item, bool p_clip);
+ void canvas_item_set_distance_field_mode(RID p_item, bool p_enable);
+ void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2());
+ void canvas_item_set_modulate(RID p_item, const Color &p_color);
+ void canvas_item_set_self_modulate(RID p_item, const Color &p_color);
+
+ void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable);
+
+ void canvas_item_set_update_when_visible(RID p_item, bool p_update);
+
+ void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter);
+ void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat);
+
+ void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
+ void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
+ void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
+ void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_clip_uv = false, RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, RS::CanvasItemTextureRepeat p_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
+ void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
+ void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);
+ void canvas_item_set_z_index(RID p_item, int p_z);
+ void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable);
+ void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect);
+ void canvas_item_attach_skeleton(RID p_item, RID p_skeleton);
+
+ void canvas_item_clear(RID p_item);
+ void canvas_item_set_draw_index(RID p_item, int p_index);
+
+ void canvas_item_set_material(RID p_item, RID p_material);
+
+ void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
+
+ RID canvas_light_create();
+ void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
+ void canvas_light_set_enabled(RID p_light, bool p_enabled);
+ void canvas_light_set_scale(RID p_light, float p_scale);
+ void canvas_light_set_transform(RID p_light, const Transform2D &p_transform);
+ void canvas_light_set_texture(RID p_light, RID p_texture);
+ void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset);
+ void canvas_light_set_color(RID p_light, const Color &p_color);
+ void canvas_light_set_height(RID p_light, float p_height);
+ void canvas_light_set_energy(RID p_light, float p_energy);
+ void canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z);
+ void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer);
+ void canvas_light_set_item_cull_mask(RID p_light, int p_mask);
+ void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask);
+
+ void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
+
+ void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
+ void canvas_light_set_shadow_buffer_size(RID p_light, int p_size);
+ void canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter);
+ 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();
+ 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);
+ 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();
+ void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed);
+ void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape);
+
+ void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode);
+
+ bool free(RID p_rid);
+ RenderingServerCanvas();
+ ~RenderingServerCanvas();
+};
+
+#endif // VISUALSERVERCANVAS_H
diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp
new file mode 100644
index 0000000000..5a270520a9
--- /dev/null
+++ b/servers/rendering/rendering_server_globals.cpp
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* rendering_server_globals.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_globals.h"
+
+RasterizerStorage *RenderingServerGlobals::storage = nullptr;
+RasterizerCanvas *RenderingServerGlobals::canvas_render = nullptr;
+RasterizerScene *RenderingServerGlobals::scene_render = nullptr;
+Rasterizer *RenderingServerGlobals::rasterizer = nullptr;
+
+RenderingServerCanvas *RenderingServerGlobals::canvas = nullptr;
+RenderingServerViewport *RenderingServerGlobals::viewport = nullptr;
+RenderingServerScene *RenderingServerGlobals::scene = nullptr;
diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h
new file mode 100644
index 0000000000..b33f328b69
--- /dev/null
+++ b/servers/rendering/rendering_server_globals.h
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* rendering_server_globals.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_GLOBALS_H
+#define RENDERING_SERVER_GLOBALS_H
+
+#include "rasterizer.h"
+
+class RenderingServerCanvas;
+class RenderingServerViewport;
+class RenderingServerScene;
+
+class RenderingServerGlobals {
+public:
+ static RasterizerStorage *storage;
+ static RasterizerCanvas *canvas_render;
+ static RasterizerScene *scene_render;
+ static Rasterizer *rasterizer;
+
+ static RenderingServerCanvas *canvas;
+ static RenderingServerViewport *viewport;
+ static RenderingServerScene *scene;
+};
+
+#define RSG RenderingServerGlobals
+
+#endif // RENDERING_SERVER_GLOBALS_H
diff --git a/servers/rendering/rendering_server_raster.cpp b/servers/rendering/rendering_server_raster.cpp
new file mode 100644
index 0000000000..c6f3273339
--- /dev/null
+++ b/servers/rendering/rendering_server_raster.cpp
@@ -0,0 +1,282 @@
+/*************************************************************************/
+/* rendering_server_raster.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_raster.h"
+
+#include "core/io/marshalls.h"
+#include "core/os/os.h"
+#include "core/project_settings.h"
+#include "core/sort_array.h"
+#include "rendering_server_canvas.h"
+#include "rendering_server_globals.h"
+#include "rendering_server_scene.h"
+
+// careful, these may run in different threads than the visual server
+
+int RenderingServerRaster::changes = 0;
+
+/* BLACK BARS */
+
+void RenderingServerRaster::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) {
+
+ black_margin[MARGIN_LEFT] = p_left;
+ black_margin[MARGIN_TOP] = p_top;
+ black_margin[MARGIN_RIGHT] = p_right;
+ black_margin[MARGIN_BOTTOM] = p_bottom;
+}
+
+void RenderingServerRaster::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) {
+
+ black_image[MARGIN_LEFT] = p_left;
+ black_image[MARGIN_TOP] = p_top;
+ black_image[MARGIN_RIGHT] = p_right;
+ black_image[MARGIN_BOTTOM] = p_bottom;
+}
+
+void RenderingServerRaster::_draw_margins() {
+
+ RSG::canvas_render->draw_window_margins(black_margin, black_image);
+};
+
+/* FREE */
+
+void RenderingServerRaster::free(RID p_rid) {
+
+ if (RSG::storage->free(p_rid))
+ return;
+ if (RSG::canvas->free(p_rid))
+ return;
+ if (RSG::viewport->free(p_rid))
+ return;
+ if (RSG::scene->free(p_rid))
+ return;
+ if (RSG::scene_render->free(p_rid))
+ return;
+}
+
+/* EVENT QUEUING */
+
+void RenderingServerRaster::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) {
+
+ ERR_FAIL_NULL(p_where);
+ FrameDrawnCallbacks fdc;
+ fdc.object = p_where->get_instance_id();
+ fdc.method = p_method;
+ fdc.param = p_userdata;
+
+ frame_drawn_callbacks.push_back(fdc);
+}
+
+void RenderingServerRaster::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");
+
+ changes = 0;
+
+ RSG::rasterizer->begin_frame(frame_step);
+
+ TIMESTAMP_BEGIN()
+
+ RSG::scene_render->update(); //update scenes stuff before updating instances
+
+ RSG::scene->update_dirty_instances(); //update scene stuff
+
+ RSG::scene->render_probes();
+ RSG::viewport->draw_viewports();
+ RSG::canvas_render->update();
+
+ _draw_margins();
+ RSG::rasterizer->end_frame(p_swap_buffers);
+
+ while (frame_drawn_callbacks.front()) {
+
+ Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
+ if (obj) {
+ Callable::CallError ce;
+ const Variant *v = &frame_drawn_callbacks.front()->get().param;
+ obj->call(frame_drawn_callbacks.front()->get().method, &v, 1, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ String err = Variant::get_call_error_text(obj, frame_drawn_callbacks.front()->get().method, &v, 1, ce);
+ ERR_PRINT("Error calling frame drawn function: " + err);
+ }
+ }
+
+ frame_drawn_callbacks.pop_front();
+ }
+ RS::get_singleton()->emit_signal("frame_post_draw");
+
+ if (RSG::storage->get_captured_timestamps_count()) {
+ Vector<FrameProfileArea> new_profile;
+ if (RSG::storage->capturing_timestamps) {
+ new_profile.resize(RSG::storage->get_captured_timestamps_count());
+ }
+
+ uint64_t base_cpu = RSG::storage->get_captured_timestamp_cpu_time(0);
+ uint64_t base_gpu = RSG::storage->get_captured_timestamp_gpu_time(0);
+ for (uint32_t i = 0; i < RSG::storage->get_captured_timestamps_count(); i++) {
+ uint64_t time_cpu = RSG::storage->get_captured_timestamp_cpu_time(i);
+ uint64_t time_gpu = RSG::storage->get_captured_timestamp_gpu_time(i);
+
+ String name = RSG::storage->get_captured_timestamp_name(i);
+
+ if (name.begins_with("vp_")) {
+ RSG::viewport->handle_timestamp(name, time_cpu, time_gpu);
+ }
+
+ if (RSG::storage->capturing_timestamps) {
+ new_profile.write[i].gpu_msec = float((time_gpu - base_gpu) / 1000) / 1000.0;
+ new_profile.write[i].cpu_msec = float(time_cpu - base_cpu) / 1000.0;
+ new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i);
+ }
+ }
+
+ frame_profile = new_profile;
+ }
+
+ frame_profile_frame = RSG::storage->get_captured_timestamps_frame();
+}
+void RenderingServerRaster::sync() {
+}
+bool RenderingServerRaster::has_changed() const {
+
+ return changes > 0;
+}
+void RenderingServerRaster::init() {
+
+ RSG::rasterizer->initialize();
+}
+void RenderingServerRaster::finish() {
+
+ if (test_cube.is_valid()) {
+ free(test_cube);
+ }
+
+ RSG::rasterizer->finalize();
+}
+
+/* STATUS INFORMATION */
+
+int RenderingServerRaster::get_render_info(RenderInfo p_info) {
+
+ return RSG::storage->get_render_info(p_info);
+}
+
+String RenderingServerRaster::get_video_adapter_name() const {
+
+ return RSG::storage->get_video_adapter_name();
+}
+
+String RenderingServerRaster::get_video_adapter_vendor() const {
+
+ return RSG::storage->get_video_adapter_vendor();
+}
+
+void RenderingServerRaster::set_frame_profiling_enabled(bool p_enable) {
+ RSG::storage->capturing_timestamps = p_enable;
+}
+
+uint64_t RenderingServerRaster::get_frame_profile_frame() {
+ return frame_profile_frame;
+}
+
+Vector<RenderingServer::FrameProfileArea> RenderingServerRaster::get_frame_profile() {
+ return frame_profile;
+}
+
+/* TESTING */
+
+void RenderingServerRaster::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
+
+ redraw_request();
+ RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter);
+}
+void RenderingServerRaster::set_default_clear_color(const Color &p_color) {
+ RSG::viewport->set_default_clear_color(p_color);
+}
+
+bool RenderingServerRaster::has_feature(Features p_feature) const {
+
+ return false;
+}
+
+RID RenderingServerRaster::get_test_cube() {
+ if (!test_cube.is_valid()) {
+ test_cube = _make_test_cube();
+ }
+ return test_cube;
+}
+
+bool RenderingServerRaster::has_os_feature(const String &p_feature) const {
+
+ return RSG::storage->has_os_feature(p_feature);
+}
+
+void RenderingServerRaster::set_debug_generate_wireframes(bool p_generate) {
+
+ RSG::storage->set_debug_generate_wireframes(p_generate);
+}
+
+void RenderingServerRaster::call_set_use_vsync(bool p_enable) {
+ DisplayServer::get_singleton()->_set_use_vsync(p_enable);
+}
+
+bool RenderingServerRaster::is_low_end() const {
+ // FIXME: Commented out when rebasing vulkan branch on master,
+ // causes a crash, it seems rasterizer is not initialized yet the
+ // first time it's called.
+ //return RSG::rasterizer->is_low_end();
+ return false;
+}
+RenderingServerRaster::RenderingServerRaster() {
+
+ RSG::canvas = memnew(RenderingServerCanvas);
+ RSG::viewport = memnew(RenderingServerViewport);
+ RSG::scene = memnew(RenderingServerScene);
+ RSG::rasterizer = Rasterizer::create();
+ RSG::storage = RSG::rasterizer->get_storage();
+ RSG::canvas_render = RSG::rasterizer->get_canvas();
+ RSG::scene_render = RSG::rasterizer->get_scene();
+
+ frame_profile_frame = 0;
+
+ for (int i = 0; i < 4; i++) {
+ black_margin[i] = 0;
+ black_image[i] = RID();
+ }
+}
+
+RenderingServerRaster::~RenderingServerRaster() {
+
+ memdelete(RSG::canvas);
+ memdelete(RSG::viewport);
+ memdelete(RSG::rasterizer);
+ memdelete(RSG::scene);
+}
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
new file mode 100644
index 0000000000..6f7ce7728d
--- /dev/null
+++ b/servers/rendering/rendering_server_raster.h
@@ -0,0 +1,788 @@
+/*************************************************************************/
+/* rendering_server_raster.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_RASTER_H
+#define RENDERING_SERVER_RASTER_H
+
+#include "core/math/octree.h"
+#include "rendering_server_canvas.h"
+#include "rendering_server_globals.h"
+#include "rendering_server_scene.h"
+#include "rendering_server_viewport.h"
+#include "servers/rendering/rasterizer.h"
+#include "servers/rendering_server.h"
+
+class RenderingServerRaster : public RenderingServer {
+
+ enum {
+
+ MAX_INSTANCE_CULL = 8192,
+ MAX_INSTANCE_LIGHTS = 4,
+ LIGHT_CACHE_DIRTY = -1,
+ MAX_LIGHTS_CULLED = 256,
+ MAX_ROOM_CULL = 32,
+ MAX_EXTERIOR_PORTALS = 128,
+ MAX_LIGHT_SAMPLERS = 256,
+ INSTANCE_ROOMLESS_MASK = (1 << 20)
+
+ };
+
+ static int changes;
+ RID test_cube;
+
+ int black_margin[4];
+ RID black_image[4];
+
+ struct FrameDrawnCallbacks {
+
+ ObjectID object;
+ StringName method;
+ Variant param;
+ };
+
+ List<FrameDrawnCallbacks> frame_drawn_callbacks;
+
+ void _draw_margins();
+ static void _changes_changed() {}
+
+ uint64_t frame_profile_frame;
+ Vector<FrameProfileArea> frame_profile;
+
+public:
+ //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed()
+ //#define DEBUG_CHANGES
+
+#ifdef DEBUG_CHANGES
+ _FORCE_INLINE_ static void redraw_request() {
+ changes++;
+ _changes_changed();
+ }
+
+#define DISPLAY_CHANGED \
+ changes++; \
+ _changes_changed();
+
+#else
+ _FORCE_INLINE_ static void redraw_request() { changes++; }
+
+#define DISPLAY_CHANGED \
+ changes++;
+#endif
+
+#define BIND0R(m_r, m_name) \
+ m_r m_name() { 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 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 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 BIND1(m_name, m_type1) \
+ void m_name(m_type1 arg1) { 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); }
+
+//from now on, calls forwarded to this singleton
+#define BINDBASE RSG::storage
+
+ /* TEXTURE API */
+
+ //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)
+ BIND1R(RID, texture_3d_create, const Vector<Ref<Image>> &)
+ BIND1R(RID, texture_proxy_create, RID)
+
+ //goes pass-through
+ BIND3(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)
+ BIND4(texture_3d_update, RID, const Ref<Image> &, int, int)
+ BIND2(texture_proxy_update, RID, RID)
+
+ //these also go pass-through
+ BIND0R(RID, texture_2d_placeholder_create)
+ BIND0R(RID, texture_2d_layered_placeholder_create)
+ BIND0R(RID, texture_3d_placeholder_create)
+
+ BIND1RC(Ref<Image>, texture_2d_get, RID)
+ BIND2RC(Ref<Image>, texture_2d_layer_get, RID, int)
+ BIND3RC(Ref<Image>, texture_3d_slice_get, RID, int, int)
+
+ BIND2(texture_replace, RID, RID)
+
+ BIND3(texture_set_size_override, RID, int, int)
+// FIXME: Disabled during Vulkan refactoring, should be ported.
+#if 0
+ BIND2(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 *)
+
+ BIND2(texture_set_path, RID, const String &)
+ BIND1RC(String, texture_get_path, RID)
+ BIND1(texture_debug_usage, List<TextureInfo> *)
+
+ BIND2(texture_set_force_redraw_if_visible, RID, bool)
+
+ /* SHADER API */
+
+ BIND0R(RID, shader_create)
+
+ BIND2(shader_set_code, RID, const String &)
+ BIND1RC(String, shader_get_code, RID)
+
+ BIND2C(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 &)
+
+ /* COMMON MATERIAL API */
+
+ BIND0R(RID, material_create)
+
+ BIND2(material_set_shader, RID, RID)
+
+ BIND3(material_set_param, RID, const StringName &, const Variant &)
+ BIND2RC(Variant, material_get_param, RID, const StringName &)
+
+ BIND2(material_set_render_priority, RID, int)
+ BIND2(material_set_next_pass, RID, RID)
+
+ /* MESH API */
+
+ virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) {
+ RID mesh = mesh_create();
+ for (int i = 0; i < p_surfaces.size(); i++) {
+ mesh_add_surface(mesh, p_surfaces[i]);
+ }
+ return mesh;
+ }
+
+ BIND0R(RID, mesh_create)
+
+ BIND2(mesh_add_surface, RID, const SurfaceData &)
+
+ BIND1RC(int, mesh_get_blend_shape_count, RID)
+
+ BIND2(mesh_set_blend_shape_mode, RID, BlendShapeMode)
+ BIND1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID)
+
+ BIND4(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)
+
+ BIND2RC(SurfaceData, mesh_get_surface, RID, int)
+
+ BIND1RC(int, mesh_get_surface_count, RID)
+
+ BIND2(mesh_set_custom_aabb, RID, const AABB &)
+ BIND1RC(AABB, mesh_get_custom_aabb, RID)
+
+ BIND1(mesh_clear, RID)
+
+ /* MULTIMESH API */
+
+ BIND0R(RID, multimesh_create)
+
+ BIND5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool)
+ BIND1RC(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 &)
+
+ BIND1RC(RID, multimesh_get_mesh, RID)
+ BIND1RC(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)
+
+ BIND2(multimesh_set_buffer, RID, const Vector<float> &)
+ BIND1RC(Vector<float>, multimesh_get_buffer, RID)
+
+ BIND2(multimesh_set_visible_instances, RID, int)
+ BIND1RC(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)
+
+ /* 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 &)
+
+ /* Light API */
+
+ BIND0R(RID, directional_light_create)
+ BIND0R(RID, omni_light_create)
+ BIND0R(RID, spot_light_create)
+
+ 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_use_gi, RID, bool)
+
+ BIND2(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_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_interior_ambient, RID, const Color &)
+ BIND2(reflection_probe_set_interior_ambient_energy, RID, float)
+ BIND2(reflection_probe_set_interior_ambient_probe_contribution, RID, float)
+ 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)
+
+ /* DECAL API */
+
+ BIND0R(RID, decal_create)
+
+ 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)
+
+ /* BAKED LIGHT API */
+
+ BIND0R(RID, gi_probe_create)
+
+ 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> &)
+
+ 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)
+
+ BIND2(gi_probe_set_dynamic_range, RID, float)
+ BIND1RC(float, gi_probe_get_dynamic_range, RID)
+
+ BIND2(gi_probe_set_propagation, RID, float)
+ BIND1RC(float, gi_probe_get_propagation, RID)
+
+ BIND2(gi_probe_set_energy, RID, float)
+ BIND1RC(float, gi_probe_get_energy, RID)
+
+ BIND2(gi_probe_set_ao, RID, float)
+ BIND1RC(float, gi_probe_get_ao, RID)
+
+ BIND2(gi_probe_set_ao_size, RID, float)
+ BIND1RC(float, gi_probe_get_ao_size, RID)
+
+ BIND2(gi_probe_set_bias, RID, float)
+ BIND1RC(float, gi_probe_get_bias, RID)
+
+ BIND2(gi_probe_set_normal_bias, RID, float)
+ BIND1RC(float, gi_probe_get_normal_bias, RID)
+
+ BIND2(gi_probe_set_interior, RID, bool)
+ BIND1RC(bool, gi_probe_is_interior, RID)
+
+ BIND2(gi_probe_set_use_two_bounces, RID, bool)
+ BIND1RC(bool, gi_probe_is_using_two_bounces, RID)
+
+ BIND2(gi_probe_set_anisotropy_strength, RID, float)
+ BIND1RC(float, gi_probe_get_anisotropy_strength, RID)
+
+ /* LIGHTMAP CAPTURE */
+
+ BIND0R(RID, lightmap_capture_create)
+
+ BIND2(lightmap_capture_set_bounds, RID, const AABB &)
+ BIND1RC(AABB, lightmap_capture_get_bounds, RID)
+
+ BIND2(lightmap_capture_set_octree, RID, const Vector<uint8_t> &)
+ BIND1RC(Vector<uint8_t>, lightmap_capture_get_octree, RID)
+
+ BIND2(lightmap_capture_set_octree_cell_transform, RID, const Transform &)
+ BIND1RC(Transform, lightmap_capture_get_octree_cell_transform, RID)
+ BIND2(lightmap_capture_set_octree_cell_subdiv, RID, int)
+ BIND1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
+
+ BIND2(lightmap_capture_set_energy, RID, float)
+ BIND1RC(float, lightmap_capture_get_energy, RID)
+
+ /* 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)
+
+ 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 &)
+
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE 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
+//from now on, calls forwarded to this singleton
+#define BINDBASE RSG::viewport
+
+ /* VIEWPORT TARGET API */
+
+ BIND0R(RID, viewport_create)
+
+ BIND2(viewport_set_use_xr, RID, bool)
+ BIND3(viewport_set_size, RID, int, int)
+
+ BIND2(viewport_set_active, RID, bool)
+ BIND2(viewport_set_parent_viewport, RID, RID)
+
+ BIND2(viewport_set_clear_mode, RID, ViewportClearMode)
+
+ BIND3(viewport_attach_to_screen, RID, const Rect2 &, int)
+ BIND2(viewport_set_render_direct_to_screen, RID, bool)
+
+ BIND2(viewport_set_update_mode, RID, ViewportUpdateMode)
+ BIND2(viewport_set_vflip, RID, bool)
+
+ BIND1RC(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)
+
+ BIND2(viewport_attach_camera, RID, RID)
+ BIND2(viewport_set_scenario, RID, RID)
+ BIND2(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_global_canvas_transform, RID, const Transform2D &)
+ BIND4(viewport_set_canvas_stacking, RID, RID, int, int)
+ BIND2(viewport_set_shadow_atlas_size, RID, int)
+ BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
+ BIND2(viewport_set_msaa, RID, ViewportMSAA)
+ BIND2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
+
+ BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
+ BIND2(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)
+
+ /* ENVIRONMENT API */
+
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE RSG::scene_render
+
+ BIND1(directional_shadow_atlas_set_size, int)
+
+ /* 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)
+
+ BIND0R(RID, environment_create)
+
+ 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 &)
+
+// FIXME: Disabled during Vulkan refactoring, should be ported.
+#if 0
+ BIND2(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)
+
+ BIND9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float)
+ BIND2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool)
+
+ BIND11(environment_set_glow, RID, bool, int, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
+ BIND1(environment_glow_set_use_bicubic_upscale, bool)
+
+ BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
+
+ BIND6(environment_set_adjustment, RID, bool, float, float, float, RID)
+
+ BIND5(environment_set_fog, RID, bool, const Color &, const Color &, float)
+ BIND7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
+ BIND5(environment_set_fog_height, RID, bool, float, float, float)
+
+ BIND2(screen_space_roughness_limiter_set_active, bool, float)
+ BIND1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality)
+ BIND2(sub_surface_scattering_set_scale, float, float)
+
+ /* CAMERA EFFECTS */
+
+ BIND0R(RID, camera_effects_create)
+
+ BIND2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool)
+ BIND1(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)
+
+ BIND1(shadows_quality_set, ShadowQuality);
+ BIND1(directional_shadow_quality_set, ShadowQuality);
+
+ /* SCENARIO API */
+
+#undef BINDBASE
+#define BINDBASE RSG::scene
+
+ BIND0R(RID, scenario_create)
+
+ 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)
+
+ /* INSTANCING API */
+ BIND0R(RID, instance_create)
+
+ 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)
+ BIND3(instance_set_use_lightmap, RID, RID, RID)
+
+ BIND2(instance_set_custom_aabb, RID, AABB)
+
+ BIND2(instance_attach_skeleton, RID, RID)
+ BIND2(instance_set_exterior, RID, bool)
+
+ BIND2(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)
+
+ 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)
+
+ BIND5(instance_geometry_set_draw_range, RID, float, float, float, float)
+ BIND2(instance_geometry_set_as_instance_lod, RID, RID)
+
+#undef BINDBASE
+//from now on, calls forwarded to this singleton
+#define BINDBASE 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_item_create)
+ BIND2(canvas_item_set_parent, RID, RID)
+
+ 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)
+
+ BIND2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
+ BIND2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
+
+ BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
+ BIND4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+ 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 &)
+ BIND11(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND12(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND15(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND11(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND10(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND14(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, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND10(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND8(canvas_item_add_multimesh, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ BIND8(canvas_item_add_particles, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ 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)
+
+ BIND0R(RID, canvas_light_create)
+ BIND2(canvas_light_attach_to_canvas, RID, RID)
+ BIND2(canvas_light_set_enabled, RID, bool)
+ BIND2(canvas_light_set_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_mode, RID, CanvasLightMode)
+
+ BIND2(canvas_light_set_shadow_enabled, RID, bool)
+ BIND2(canvas_light_set_shadow_buffer_size, RID, int)
+ 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_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_shape_as_lines, RID, const Vector<Vector2> &)
+
+ BIND2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
+
+ /* 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);
+
+ /* FREE */
+
+ virtual void free(RID p_rid); ///< free RIDs associated with the visual server
+
+ /* EVENT QUEUING */
+
+ virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata);
+
+ virtual void draw(bool p_swap_buffers, double frame_step);
+ virtual void sync();
+ virtual bool has_changed() const;
+ virtual void init();
+ virtual void finish();
+
+ /* 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 void set_frame_profiling_enabled(bool p_enable);
+ virtual Vector<FrameProfileArea> get_frame_profile();
+ virtual uint64_t get_frame_profile_frame();
+
+ virtual RID get_test_cube();
+
+ /* TESTING */
+
+ 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 bool has_feature(Features p_feature) const;
+
+ virtual bool has_os_feature(const String &p_feature) const;
+ virtual void set_debug_generate_wireframes(bool p_generate);
+
+ virtual void call_set_use_vsync(bool p_enable);
+
+ virtual bool is_low_end() const;
+
+ RenderingServerRaster();
+ ~RenderingServerRaster();
+
+#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_scene.cpp b/servers/rendering/rendering_server_scene.cpp
new file mode 100644
index 0000000000..fc7c160c0b
--- /dev/null
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -0,0 +1,3021 @@
+/*************************************************************************/
+/* rendering_server_scene.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_scene.h"
+
+#include "core/os/os.h"
+#include "rendering_server_globals.h"
+#include "rendering_server_raster.h"
+
+#include <new>
+
+/* CAMERA API */
+
+RID RenderingServerScene::camera_create() {
+
+ Camera *camera = memnew(Camera);
+ return camera_owner.make_rid(camera);
+}
+
+void RenderingServerScene::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->type = Camera::PERSPECTIVE;
+ camera->fov = p_fovy_degrees;
+ camera->znear = p_z_near;
+ camera->zfar = p_z_far;
+}
+
+void RenderingServerScene::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->type = Camera::ORTHOGONAL;
+ camera->size = p_size;
+ camera->znear = p_z_near;
+ camera->zfar = p_z_far;
+}
+
+void RenderingServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->type = Camera::FRUSTUM;
+ camera->size = p_size;
+ camera->offset = p_offset;
+ camera->znear = p_z_near;
+ camera->zfar = p_z_far;
+}
+
+void RenderingServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->transform = p_transform.orthonormalized();
+}
+
+void RenderingServerScene::camera_set_cull_mask(RID p_camera, uint32_t p_layers) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+
+ camera->visible_layers = p_layers;
+}
+
+void RenderingServerScene::camera_set_environment(RID p_camera, RID p_env) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->env = p_env;
+}
+
+void RenderingServerScene::camera_set_camera_effects(RID p_camera, RID p_fx) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->effects = p_fx;
+}
+
+void RenderingServerScene::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) {
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->vaspect = p_enable;
+}
+
+/* SCENARIO API */
+
+void *RenderingServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int) {
+
+ //RenderingServerScene *self = (RenderingServerScene*)p_self;
+ Instance *A = p_A;
+ Instance *B = p_B;
+
+ //instance indices are designed so greater always contains lesser
+ if (A->base_type > B->base_type) {
+ SWAP(A, B); //lesser always first
+ }
+
+ if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ InstanceLightData::PairInfo pinfo;
+ pinfo.geometry = A;
+ pinfo.L = geom->lighting.push_back(B);
+
+ List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo);
+
+ if (geom->can_cast_shadows) {
+
+ light->shadow_dirty = true;
+ }
+ geom->lighting_dirty = true;
+
+ return E; //this element should make freeing faster
+ } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ InstanceReflectionProbeData::PairInfo pinfo;
+ pinfo.geometry = A;
+ pinfo.L = geom->reflection_probes.push_back(B);
+
+ List<InstanceReflectionProbeData::PairInfo>::Element *E = reflection_probe->geometries.push_back(pinfo);
+
+ geom->reflection_dirty = true;
+
+ return E; //this element should make freeing faster
+ } else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ InstanceDecalData::PairInfo pinfo;
+ pinfo.geometry = A;
+ pinfo.L = geom->decals.push_back(B);
+
+ List<InstanceDecalData::PairInfo>::Element *E = decal->geometries.push_back(pinfo);
+
+ geom->decal_dirty = true;
+
+ return E; //this element should make freeing faster
+ } else if (B->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ InstanceLightmapCaptureData::PairInfo pinfo;
+ pinfo.geometry = A;
+ pinfo.L = geom->lightmap_captures.push_back(B);
+
+ List<InstanceLightmapCaptureData::PairInfo>::Element *E = lightmap_capture->geometries.push_back(pinfo);
+ ((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
+
+ return E; //this element should make freeing faster
+ } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ InstanceGIProbeData::PairInfo pinfo;
+ pinfo.geometry = A;
+ pinfo.L = geom->gi_probes.push_back(B);
+
+ List<InstanceGIProbeData::PairInfo>::Element *E;
+ if (A->dynamic_gi) {
+ E = gi_probe->dynamic_geometries.push_back(pinfo);
+ } else {
+ E = gi_probe->geometries.push_back(pinfo);
+ }
+
+ geom->gi_probes_dirty = true;
+
+ return E; //this element should make freeing faster
+
+ } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ return gi_probe->lights.insert(A);
+ }
+
+ return nullptr;
+}
+void RenderingServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *udata) {
+
+ //RenderingServerScene *self = (RenderingServerScene*)p_self;
+ Instance *A = p_A;
+ Instance *B = p_B;
+
+ //instance indices are designed so greater always contains lesser
+ if (A->base_type > B->base_type) {
+ SWAP(A, B); //lesser always first
+ }
+
+ if (B->base_type == RS::INSTANCE_LIGHT && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element *>(udata);
+
+ geom->lighting.erase(E->get().L);
+ light->geometries.erase(E);
+
+ if (geom->can_cast_shadows) {
+ light->shadow_dirty = true;
+ }
+ geom->lighting_dirty = true;
+
+ } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ List<InstanceReflectionProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceReflectionProbeData::PairInfo>::Element *>(udata);
+
+ geom->reflection_probes.erase(E->get().L);
+ reflection_probe->geometries.erase(E);
+
+ geom->reflection_dirty = true;
+ } else if (B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ List<InstanceDecalData::PairInfo>::Element *E = reinterpret_cast<List<InstanceDecalData::PairInfo>::Element *>(udata);
+
+ geom->decals.erase(E->get().L);
+ decal->geometries.erase(E);
+
+ geom->decal_dirty = true;
+ } else if (B->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ List<InstanceLightmapCaptureData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapCaptureData::PairInfo>::Element *>(udata);
+
+ geom->lightmap_captures.erase(E->get().L);
+ lightmap_capture->geometries.erase(E);
+ ((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
+
+ } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
+
+ List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata);
+
+ geom->gi_probes.erase(E->get().L);
+ if (A->dynamic_gi) {
+ gi_probe->dynamic_geometries.erase(E);
+ } else {
+ gi_probe->geometries.erase(E);
+ }
+
+ geom->gi_probes_dirty = true;
+
+ } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
+ Set<Instance *>::Element *E = reinterpret_cast<Set<Instance *>::Element *>(udata);
+
+ gi_probe->lights.erase(E);
+ }
+}
+
+RID RenderingServerScene::scenario_create() {
+
+ Scenario *scenario = memnew(Scenario);
+ ERR_FAIL_COND_V(!scenario, RID());
+ RID scenario_rid = scenario_owner.make_rid(scenario);
+ scenario->self = scenario_rid;
+
+ scenario->octree.set_pair_callback(_instance_pair, this);
+ scenario->octree.set_unpair_callback(_instance_unpair, this);
+ scenario->reflection_probe_shadow_atlas = RSG::scene_render->shadow_atlas_create();
+ RSG::scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
+ RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4);
+ RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
+ RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
+ RSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
+ scenario->reflection_atlas = RSG::scene_render->reflection_atlas_create();
+ return scenario_rid;
+}
+
+void RenderingServerScene::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->debug = p_debug_mode;
+}
+
+void RenderingServerScene::scenario_set_environment(RID p_scenario, RID p_environment) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->environment = p_environment;
+}
+
+void RenderingServerScene::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->camera_effects = p_camera_effects;
+}
+
+void RenderingServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ scenario->fallback_environment = p_environment;
+}
+
+void RenderingServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+ RSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
+}
+
+/* INSTANCING API */
+
+void RenderingServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
+
+ if (p_update_aabb)
+ p_instance->update_aabb = true;
+ if (p_update_dependencies)
+ p_instance->update_dependencies = true;
+
+ if (p_instance->update_item.in_list())
+ return;
+
+ _instance_update_list.add(&p_instance->update_item);
+}
+
+RID RenderingServerScene::instance_create() {
+
+ Instance *instance = memnew(Instance);
+ ERR_FAIL_COND_V(!instance, RID());
+
+ RID instance_rid = instance_owner.make_rid(instance);
+ instance->self = instance_rid;
+
+ return instance_rid;
+}
+
+void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ Scenario *scenario = instance->scenario;
+
+ if (instance->base_type != RS::INSTANCE_NONE) {
+ //free anything related to that base
+
+ if (scenario && instance->octree_id) {
+ scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
+ instance->octree_id = 0;
+ }
+
+ switch (instance->base_type) {
+ case RS::INSTANCE_LIGHT: {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
+#ifdef DEBUG_ENABLED
+ if (light->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from light.");
+ }
+#endif
+ if (instance->scenario && light->D) {
+ instance->scenario->directional_lights.erase(light->D);
+ light->D = nullptr;
+ }
+ RSG::scene_render->free(light->instance);
+ } break;
+ case RS::INSTANCE_REFLECTION_PROBE: {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
+ RSG::scene_render->free(reflection_probe->instance);
+ if (reflection_probe->update_list.in_list()) {
+ reflection_probe_render_list.remove(&reflection_probe->update_list);
+ }
+ } break;
+ case RS::INSTANCE_DECAL: {
+
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data);
+ RSG::scene_render->free(decal->instance);
+
+ } break;
+ case RS::INSTANCE_LIGHTMAP_CAPTURE: {
+
+ InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(instance->base_data);
+ //erase dependencies, since no longer a lightmap
+ while (lightmap_capture->users.front()) {
+ instance_set_use_lightmap(lightmap_capture->users.front()->get()->self, RID(), RID());
+ }
+ } break;
+ case RS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+#ifdef DEBUG_ENABLED
+ if (gi_probe->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
+ }
+#endif
+#ifdef DEBUG_ENABLED
+ if (gi_probe->lights.size()) {
+ ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
+ }
+#endif
+ if (gi_probe->update_element.in_list()) {
+ gi_probe_update_list.remove(&gi_probe->update_element);
+ }
+
+ if (instance->lightmap_capture) {
+ Instance *capture = (Instance *)instance->lightmap_capture;
+ InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(capture->base_data);
+ lightmap_capture->users.erase(instance);
+ instance->lightmap_capture = nullptr;
+ instance->lightmap = RID();
+ }
+
+ RSG::scene_render->free(gi_probe->probe_instance);
+
+ } break;
+ default: {
+ }
+ }
+
+ if (instance->base_data) {
+ memdelete(instance->base_data);
+ instance->base_data = nullptr;
+ }
+
+ instance->blend_values.clear();
+ instance->materials.clear();
+ }
+
+ instance->base_type = RS::INSTANCE_NONE;
+ instance->base = RID();
+
+ if (p_base.is_valid()) {
+
+ instance->base_type = RSG::storage->get_base_type(p_base);
+ ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE);
+
+ switch (instance->base_type) {
+ case RS::INSTANCE_LIGHT: {
+
+ InstanceLightData *light = memnew(InstanceLightData);
+
+ if (scenario && RSG::storage->light_get_type(p_base) == RS::LIGHT_DIRECTIONAL) {
+ light->D = scenario->directional_lights.push_back(instance);
+ }
+
+ light->instance = RSG::scene_render->light_instance_create(p_base);
+
+ instance->base_data = light;
+ } break;
+ case RS::INSTANCE_MESH:
+ case RS::INSTANCE_MULTIMESH:
+ case RS::INSTANCE_IMMEDIATE:
+ case RS::INSTANCE_PARTICLES: {
+
+ InstanceGeometryData *geom = memnew(InstanceGeometryData);
+ instance->base_data = geom;
+ if (instance->base_type == RS::INSTANCE_MESH) {
+ instance->blend_values.resize(RSG::storage->mesh_get_blend_shape_count(p_base));
+ }
+ } break;
+ case RS::INSTANCE_REFLECTION_PROBE: {
+
+ InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData);
+ reflection_probe->owner = instance;
+ instance->base_data = reflection_probe;
+
+ reflection_probe->instance = RSG::scene_render->reflection_probe_instance_create(p_base);
+ } break;
+ case RS::INSTANCE_DECAL: {
+
+ InstanceDecalData *decal = memnew(InstanceDecalData);
+ decal->owner = instance;
+ instance->base_data = decal;
+
+ decal->instance = RSG::scene_render->decal_instance_create(p_base);
+ } break;
+ case RS::INSTANCE_LIGHTMAP_CAPTURE: {
+
+ InstanceLightmapCaptureData *lightmap_capture = memnew(InstanceLightmapCaptureData);
+ instance->base_data = lightmap_capture;
+ //lightmap_capture->instance = RSG::scene_render->lightmap_capture_instance_create(p_base);
+ } break;
+ case RS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData);
+ instance->base_data = gi_probe;
+ gi_probe->owner = instance;
+
+ if (scenario && !gi_probe->update_element.in_list()) {
+ gi_probe_update_list.add(&gi_probe->update_element);
+ }
+
+ gi_probe->probe_instance = RSG::scene_render->gi_probe_instance_create(p_base);
+
+ } break;
+ default: {
+ }
+ }
+
+ instance->base = p_base;
+
+ //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it
+ RSG::storage->base_update_dependency(p_base, instance);
+ }
+
+ _instance_queue_update(instance, true, true);
+}
+void RenderingServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->scenario) {
+
+ instance->scenario->instances.remove(&instance->scenario_item);
+
+ if (instance->octree_id) {
+ instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
+ instance->octree_id = 0;
+ }
+
+ switch (instance->base_type) {
+
+ case RS::INSTANCE_LIGHT: {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
+#ifdef DEBUG_ENABLED
+ if (light->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from light.");
+ }
+#endif
+ if (light->D) {
+ instance->scenario->directional_lights.erase(light->D);
+ light->D = nullptr;
+ }
+ } break;
+ case RS::INSTANCE_REFLECTION_PROBE: {
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
+ RSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance);
+
+ } break;
+ case RS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+
+#ifdef DEBUG_ENABLED
+ if (gi_probe->geometries.size()) {
+ ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
+ }
+#endif
+#ifdef DEBUG_ENABLED
+ if (gi_probe->lights.size()) {
+ ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
+ }
+#endif
+
+ if (gi_probe->update_element.in_list()) {
+ gi_probe_update_list.remove(&gi_probe->update_element);
+ }
+ } break;
+ default: {
+ }
+ }
+
+ instance->scenario = nullptr;
+ }
+
+ if (p_scenario.is_valid()) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND(!scenario);
+
+ instance->scenario = scenario;
+
+ scenario->instances.add(&instance->scenario_item);
+
+ switch (instance->base_type) {
+
+ case RS::INSTANCE_LIGHT: {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
+
+ if (RSG::storage->light_get_type(instance->base) == RS::LIGHT_DIRECTIONAL) {
+ light->D = scenario->directional_lights.push_back(instance);
+ }
+ } break;
+ case RS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
+ if (!gi_probe->update_element.in_list()) {
+ gi_probe_update_list.add(&gi_probe->update_element);
+ }
+ } break;
+ default: {
+ }
+ }
+
+ _instance_queue_update(instance, true, true);
+ }
+}
+void RenderingServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->layer_mask = p_mask;
+}
+void RenderingServerScene::instance_set_transform(RID p_instance, const Transform &p_transform) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->transform == p_transform)
+ return; //must be checked to avoid worst evil
+
+#ifdef DEBUG_ENABLED
+
+ for (int i = 0; i < 4; i++) {
+ const Vector3 &v = i < 3 ? p_transform.basis.elements[i] : p_transform.origin;
+ ERR_FAIL_COND(Math::is_inf(v.x));
+ ERR_FAIL_COND(Math::is_nan(v.x));
+ ERR_FAIL_COND(Math::is_inf(v.y));
+ ERR_FAIL_COND(Math::is_nan(v.y));
+ ERR_FAIL_COND(Math::is_inf(v.z));
+ ERR_FAIL_COND(Math::is_nan(v.z));
+ }
+
+#endif
+ instance->transform = p_transform;
+ _instance_queue_update(instance, true);
+}
+void RenderingServerScene::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->object_id = p_id;
+}
+void RenderingServerScene::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->update_item.in_list()) {
+ _update_dirty_instance(instance);
+ }
+
+ ERR_FAIL_INDEX(p_shape, instance->blend_values.size());
+ instance->blend_values.write[p_shape] = p_weight;
+}
+
+void RenderingServerScene::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->base_type == RS::INSTANCE_MESH) {
+ //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
+ instance->materials.resize(MAX(p_surface + 1, RSG::storage->mesh_get_surface_count(instance->base)));
+ }
+
+ ERR_FAIL_INDEX(p_surface, instance->materials.size());
+
+ instance->materials.write[p_surface] = p_material;
+
+ _instance_queue_update(instance, false, true);
+}
+
+void RenderingServerScene::instance_set_visible(RID p_instance, bool p_visible) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->visible == p_visible)
+ return;
+
+ instance->visible = p_visible;
+
+ switch (instance->base_type) {
+ case RS::INSTANCE_LIGHT: {
+ if (RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario) {
+ instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHT, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0);
+ }
+
+ } break;
+ case RS::INSTANCE_REFLECTION_PROBE: {
+ if (instance->octree_id && instance->scenario) {
+ instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_REFLECTION_PROBE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0);
+ }
+
+ } break;
+ case RS::INSTANCE_DECAL: {
+ if (instance->octree_id && instance->scenario) {
+ instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_DECAL, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0);
+ }
+
+ } break;
+ case RS::INSTANCE_LIGHTMAP_CAPTURE: {
+ if (instance->octree_id && instance->scenario) {
+ instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_LIGHTMAP_CAPTURE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0);
+ }
+
+ } break;
+ case RS::INSTANCE_GI_PROBE: {
+ if (instance->octree_id && instance->scenario) {
+ instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << RS::INSTANCE_GI_PROBE, p_visible ? (RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT)) : 0);
+ }
+
+ } break;
+ default: {
+ }
+ }
+}
+inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
+ return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE;
+}
+
+void RenderingServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->lightmap_capture) {
+ InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
+ lightmap_capture->users.erase(instance);
+ instance->lightmap = RID();
+ instance->lightmap_capture = nullptr;
+ }
+
+ if (p_lightmap_instance.is_valid()) {
+ Instance *lightmap_instance = instance_owner.getornull(p_lightmap_instance);
+ ERR_FAIL_COND(!lightmap_instance);
+ ERR_FAIL_COND(lightmap_instance->base_type != RS::INSTANCE_LIGHTMAP_CAPTURE);
+ instance->lightmap_capture = lightmap_instance;
+
+ InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
+ lightmap_capture->users.insert(instance);
+ instance->lightmap = p_lightmap;
+ }
+}
+
+void RenderingServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+ ERR_FAIL_COND(!is_geometry_instance(instance->base_type));
+
+ if (p_aabb != AABB()) {
+
+ // Set custom AABB
+ if (instance->custom_aabb == nullptr)
+ instance->custom_aabb = memnew(AABB);
+ *instance->custom_aabb = p_aabb;
+
+ } else {
+
+ // Clear custom AABB
+ if (instance->custom_aabb != nullptr) {
+ memdelete(instance->custom_aabb);
+ instance->custom_aabb = nullptr;
+ }
+ }
+
+ if (instance->scenario)
+ _instance_queue_update(instance, true, false);
+}
+
+void RenderingServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ if (instance->skeleton == p_skeleton)
+ return;
+
+ instance->skeleton = p_skeleton;
+
+ if (p_skeleton.is_valid()) {
+ //update the dependency now, so if cleared, we remove it
+ RSG::storage->skeleton_update_dependency(p_skeleton, instance);
+ }
+ _instance_queue_update(instance, true, true);
+}
+
+void RenderingServerScene::instance_set_exterior(RID p_instance, bool p_enabled) {
+}
+
+void RenderingServerScene::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) {
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->extra_margin = p_margin;
+ _instance_queue_update(instance, true, false);
+}
+
+Vector<ObjectID> RenderingServerScene::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const {
+
+ Vector<ObjectID> instances;
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND_V(!scenario, instances);
+
+ const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling
+
+ int culled = 0;
+ Instance *cull[1024];
+ culled = scenario->octree.cull_aabb(p_aabb, cull, 1024);
+
+ for (int i = 0; i < culled; i++) {
+
+ Instance *instance = cull[i];
+ ERR_CONTINUE(!instance);
+ if (instance->object_id.is_null())
+ continue;
+
+ instances.push_back(instance->object_id);
+ }
+
+ return instances;
+}
+Vector<ObjectID> RenderingServerScene::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
+
+ Vector<ObjectID> instances;
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND_V(!scenario, instances);
+ const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling
+
+ int culled = 0;
+ Instance *cull[1024];
+ culled = scenario->octree.cull_segment(p_from, p_from + p_to * 10000, cull, 1024);
+
+ for (int i = 0; i < culled; i++) {
+ Instance *instance = cull[i];
+ ERR_CONTINUE(!instance);
+ if (instance->object_id.is_null())
+ continue;
+
+ instances.push_back(instance->object_id);
+ }
+
+ return instances;
+}
+Vector<ObjectID> RenderingServerScene::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const {
+
+ Vector<ObjectID> instances;
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+ ERR_FAIL_COND_V(!scenario, instances);
+ const_cast<RenderingServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling
+
+ int culled = 0;
+ Instance *cull[1024];
+
+ culled = scenario->octree.cull_convex(p_convex, cull, 1024);
+
+ for (int i = 0; i < culled; i++) {
+
+ Instance *instance = cull[i];
+ ERR_CONTINUE(!instance);
+ if (instance->object_id.is_null())
+ continue;
+
+ instances.push_back(instance->object_id);
+ }
+
+ return instances;
+}
+
+void RenderingServerScene::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK));
+
+ switch (p_flags) {
+
+ case RS::INSTANCE_FLAG_USE_BAKED_LIGHT: {
+
+ instance->baked_light = p_enabled;
+
+ } break;
+ case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: {
+
+ if (p_enabled == instance->dynamic_gi) {
+ //bye, redundant
+ return;
+ }
+
+ if (instance->octree_id != 0) {
+ //remove from octree, it needs to be re-paired
+ instance->scenario->octree.erase(instance->octree_id);
+ instance->octree_id = 0;
+ _instance_queue_update(instance, true, true);
+ }
+
+ //once out of octree, can be changed
+ instance->dynamic_gi = p_enabled;
+
+ } break;
+ case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: {
+
+ instance->redraw_if_visible = p_enabled;
+
+ } break;
+ default: {
+ }
+ }
+}
+void RenderingServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->cast_shadows = p_shadow_casting_setting;
+ _instance_queue_update(instance, false, true);
+}
+void RenderingServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) {
+
+ Instance *instance = instance_owner.getornull(p_instance);
+ ERR_FAIL_COND(!instance);
+
+ instance->material_override = p_material;
+ _instance_queue_update(instance, false, true);
+}
+
+void RenderingServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
+}
+void RenderingServerScene::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
+}
+
+void RenderingServerScene::_update_instance(Instance *p_instance) {
+
+ p_instance->version++;
+
+ if (p_instance->base_type == RS::INSTANCE_LIGHT) {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
+
+ RSG::scene_render->light_instance_set_transform(light->instance, p_instance->transform);
+ light->shadow_dirty = true;
+ }
+
+ if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
+
+ RSG::scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
+ reflection_probe->reflection_dirty = true;
+ }
+
+ if (p_instance->base_type == RS::INSTANCE_DECAL) {
+
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data);
+
+ RSG::scene_render->decal_instance_set_transform(decal->instance, p_instance->transform);
+ }
+
+ if (p_instance->base_type == RS::INSTANCE_GI_PROBE) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
+
+ RSG::scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform);
+ }
+
+ if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
+
+ RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
+ }
+
+ if (p_instance->aabb.has_no_surface()) {
+ return;
+ }
+
+ if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+ //make sure lights are updated if it casts shadow
+
+ if (geom->can_cast_shadows) {
+ for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) {
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+ light->shadow_dirty = true;
+ }
+ }
+
+ if (!p_instance->lightmap_capture && geom->lightmap_captures.size()) {
+ //affected by lightmap captures, must update capture info!
+ _update_instance_lightmap_captures(p_instance);
+ } else {
+ if (!p_instance->lightmap_capture_data.empty()) {
+ p_instance->lightmap_capture_data.resize(0); //not in use, clear capture data
+ }
+ }
+ }
+
+ p_instance->mirror = p_instance->transform.basis.determinant() < 0.0;
+
+ AABB new_aabb;
+
+ new_aabb = p_instance->transform.xform(p_instance->aabb);
+
+ p_instance->transformed_aabb = new_aabb;
+
+ if (!p_instance->scenario) {
+
+ return;
+ }
+
+ if (p_instance->octree_id == 0) {
+
+ uint32_t base_type = 1 << p_instance->base_type;
+ uint32_t pairable_mask = 0;
+ bool pairable = false;
+
+ if (p_instance->base_type == RS::INSTANCE_LIGHT || p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_DECAL || p_instance->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE) {
+
+ pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK : 0;
+ pairable = true;
+ }
+
+ if (p_instance->base_type == RS::INSTANCE_GI_PROBE) {
+ //lights and geometries
+ pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT) : 0;
+ pairable = true;
+ }
+
+ // not inside octree
+ p_instance->octree_id = p_instance->scenario->octree.create(p_instance, new_aabb, 0, pairable, base_type, pairable_mask);
+
+ } else {
+
+ /*
+ if (new_aabb==p_instance->data.transformed_aabb)
+ return;
+ */
+
+ p_instance->scenario->octree.move(p_instance->octree_id, new_aabb);
+ }
+}
+
+void RenderingServerScene::_update_instance_aabb(Instance *p_instance) {
+
+ AABB new_aabb;
+
+ ERR_FAIL_COND(p_instance->base_type != RS::INSTANCE_NONE && !p_instance->base.is_valid());
+
+ switch (p_instance->base_type) {
+ case RenderingServer::INSTANCE_NONE: {
+
+ // do nothing
+ } break;
+ case RenderingServer::INSTANCE_MESH: {
+
+ if (p_instance->custom_aabb)
+ new_aabb = *p_instance->custom_aabb;
+ else
+ new_aabb = RSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton);
+
+ } break;
+
+ case RenderingServer::INSTANCE_MULTIMESH: {
+
+ if (p_instance->custom_aabb)
+ new_aabb = *p_instance->custom_aabb;
+ else
+ new_aabb = RSG::storage->multimesh_get_aabb(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_IMMEDIATE: {
+
+ if (p_instance->custom_aabb)
+ new_aabb = *p_instance->custom_aabb;
+ else
+ new_aabb = RSG::storage->immediate_get_aabb(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_PARTICLES: {
+
+ if (p_instance->custom_aabb)
+ new_aabb = *p_instance->custom_aabb;
+ else
+ new_aabb = RSG::storage->particles_get_aabb(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_LIGHT: {
+
+ new_aabb = RSG::storage->light_get_aabb(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_REFLECTION_PROBE: {
+
+ new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_DECAL: {
+
+ new_aabb = RSG::storage->decal_get_aabb(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_GI_PROBE: {
+
+ new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base);
+
+ } break;
+ case RenderingServer::INSTANCE_LIGHTMAP_CAPTURE: {
+
+ new_aabb = RSG::storage->lightmap_capture_get_bounds(p_instance->base);
+
+ } break;
+ default: {
+ }
+ }
+
+ // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs
+ if (p_instance->extra_margin)
+ new_aabb.grow_by(p_instance->extra_margin);
+
+ p_instance->aabb = new_aabb;
+}
+
+_FORCE_INLINE_ static void _light_capture_sample_octree(const RasterizerStorage::LightmapCaptureOctree *p_octree, int p_cell_subdiv, const Vector3 &p_pos, const Vector3 &p_dir, float p_level, Vector3 &r_color, float &r_alpha) {
+
+ static const Vector3 aniso_normal[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)
+ };
+
+ int size = 1 << (p_cell_subdiv - 1);
+
+ int clamp_v = size - 1;
+ //first of all, clamp
+ Vector3 pos;
+ pos.x = CLAMP(p_pos.x, 0, clamp_v);
+ pos.y = CLAMP(p_pos.y, 0, clamp_v);
+ pos.z = CLAMP(p_pos.z, 0, clamp_v);
+
+ float level = (p_cell_subdiv - 1) - p_level;
+
+ int target_level;
+ float level_filter;
+ if (level <= 0.0) {
+ level_filter = 0;
+ target_level = 0;
+ } else {
+ target_level = Math::ceil(level);
+ level_filter = target_level - level;
+ }
+
+ Vector3 color[2][8];
+ float alpha[2][8];
+ zeromem(alpha, sizeof(float) * 2 * 8);
+
+ //find cell at given level first
+
+ for (int c = 0; c < 2; c++) {
+
+ int current_level = MAX(0, target_level - c);
+ int level_cell_size = (1 << (p_cell_subdiv - 1)) >> current_level;
+
+ for (int n = 0; n < 8; n++) {
+
+ int x = int(pos.x);
+ int y = int(pos.y);
+ int z = int(pos.z);
+
+ if (n & 1)
+ x += level_cell_size;
+ if (n & 2)
+ y += level_cell_size;
+ if (n & 4)
+ z += level_cell_size;
+
+ int ofs_x = 0;
+ int ofs_y = 0;
+ int ofs_z = 0;
+
+ x = CLAMP(x, 0, clamp_v);
+ y = CLAMP(y, 0, clamp_v);
+ z = CLAMP(z, 0, clamp_v);
+
+ int half = size / 2;
+ uint32_t cell = 0;
+ for (int i = 0; i < current_level; i++) {
+
+ const RasterizerStorage::LightmapCaptureOctree *bc = &p_octree[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child |= 1;
+ ofs_x += half;
+ }
+ if (y >= ofs_y + half) {
+ child |= 2;
+ ofs_y += half;
+ }
+ if (z >= ofs_z + half) {
+ child |= 4;
+ ofs_z += half;
+ }
+
+ cell = bc->children[child];
+ if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY)
+ break;
+
+ half >>= 1;
+ }
+
+ if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY) {
+ alpha[c][n] = 0;
+ } else {
+ alpha[c][n] = p_octree[cell].alpha;
+
+ for (int i = 0; i < 6; i++) {
+ //anisotropic read light
+ float amount = p_dir.dot(aniso_normal[i]);
+ if (amount < 0)
+ amount = 0;
+ color[c][n].x += p_octree[cell].light[i][0] / 1024.0 * amount;
+ color[c][n].y += p_octree[cell].light[i][1] / 1024.0 * amount;
+ color[c][n].z += p_octree[cell].light[i][2] / 1024.0 * amount;
+ }
+ }
+
+ //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]);
+ }
+ }
+
+ float target_level_size = size >> target_level;
+ Vector3 pos_fract[2];
+
+ pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size;
+ pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size;
+ pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size;
+
+ target_level_size = size >> MAX(0, target_level - 1);
+
+ pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size;
+ pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size;
+ pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size;
+
+ float alpha_interp[2];
+ Vector3 color_interp[2];
+
+ for (int i = 0; i < 2; i++) {
+
+ Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x);
+ Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x);
+ Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y);
+
+ Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x);
+ Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x);
+ Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y);
+
+ color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z);
+
+ float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x);
+ float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x);
+ float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y);
+
+ float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x);
+ float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x);
+ float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y);
+
+ alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z);
+ }
+
+ r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter);
+ r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter);
+
+ //print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha));
+}
+
+_FORCE_INLINE_ static Color _light_capture_voxel_cone_trace(const RasterizerStorage::LightmapCaptureOctree *p_octree, const Vector3 &p_pos, const Vector3 &p_dir, float p_aperture, int p_cell_subdiv) {
+
+ float bias = 0.0; //no need for bias here
+ float max_distance = (Vector3(1, 1, 1) * (1 << (p_cell_subdiv - 1))).length();
+
+ float dist = bias;
+ float alpha = 0.0;
+ Vector3 color;
+
+ Vector3 scolor;
+ float salpha;
+
+ while (dist < max_distance && alpha < 0.95) {
+ float diameter = MAX(1.0, 2.0 * p_aperture * dist);
+ _light_capture_sample_octree(p_octree, p_cell_subdiv, p_pos + dist * p_dir, p_dir, log2(diameter), scolor, salpha);
+ float a = (1.0 - alpha);
+ color += scolor * a;
+ alpha += a * salpha;
+ dist += diameter * 0.5;
+ }
+
+ return Color(color.x, color.y, color.z, alpha);
+}
+
+void RenderingServerScene::_update_instance_lightmap_captures(Instance *p_instance) {
+
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+
+ static const Vector3 cone_traces[12] = {
+ Vector3(0, 0, 1),
+ Vector3(0.866025, 0, 0.5),
+ Vector3(0.267617, 0.823639, 0.5),
+ Vector3(-0.700629, 0.509037, 0.5),
+ Vector3(-0.700629, -0.509037, 0.5),
+ Vector3(0.267617, -0.823639, 0.5),
+ Vector3(0, 0, -1),
+ Vector3(0.866025, 0, -0.5),
+ Vector3(0.267617, 0.823639, -0.5),
+ Vector3(-0.700629, 0.509037, -0.5),
+ Vector3(-0.700629, -0.509037, -0.5),
+ Vector3(0.267617, -0.823639, -0.5)
+ };
+
+ float cone_aperture = 0.577; // tan(angle) 60 degrees
+
+ if (p_instance->lightmap_capture_data.empty()) {
+ p_instance->lightmap_capture_data.resize(12);
+ }
+
+ //print_line("update captures for pos: " + p_instance->transform.origin);
+
+ for (int i = 0; i < 12; i++)
+ new (&p_instance->lightmap_capture_data.ptrw()[i]) Color;
+
+ //this could use some sort of blending..
+ for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) {
+ const Vector<RasterizerStorage::LightmapCaptureOctree> *octree = RSG::storage->lightmap_capture_get_octree_ptr(E->get()->base);
+ //print_line("octree size: " + itos(octree->size()));
+ if (octree->size() == 0)
+ continue;
+ Transform to_cell_xform = RSG::storage->lightmap_capture_get_octree_cell_transform(E->get()->base);
+ int cell_subdiv = RSG::storage->lightmap_capture_get_octree_cell_subdiv(E->get()->base);
+ to_cell_xform = to_cell_xform * E->get()->transform.affine_inverse();
+
+ const RasterizerStorage::LightmapCaptureOctree *octree_r = octree->ptr();
+
+ Vector3 pos = to_cell_xform.xform(p_instance->transform.origin);
+
+ for (int i = 0; i < 12; i++) {
+
+ Vector3 dir = to_cell_xform.basis.xform(cone_traces[i]).normalized();
+ Color capture = _light_capture_voxel_cone_trace(octree_r, pos, dir, cone_aperture, cell_subdiv);
+ p_instance->lightmap_capture_data.write[i] += capture;
+ }
+ }
+}
+
+bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario) {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
+
+ Transform light_transform = p_instance->transform;
+ light_transform.orthonormalize(); //scale does not count on lights
+
+ bool animated_material_found = false;
+
+ switch (RSG::storage->light_get_type(p_instance->base)) {
+
+ case RS::LIGHT_DIRECTIONAL: {
+
+ real_t max_distance = p_cam_projection.get_z_far();
+ real_t shadow_max = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
+ if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera
+ max_distance = MIN(shadow_max, max_distance);
+ }
+ max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001);
+ real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance);
+
+ RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base);
+
+ real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE);
+
+ if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) {
+ //optimize min/max
+ Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform);
+ int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK);
+ Plane base(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2));
+ //check distance max and min
+
+ bool found_items = false;
+ real_t z_max = -1e20;
+ real_t z_min = 1e20;
+
+ for (int i = 0; i < cull_count; i++) {
+
+ Instance *instance = instance_shadow_cull_result[i];
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
+ continue;
+ }
+
+ if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
+ animated_material_found = true;
+ }
+
+ real_t max, min;
+ instance->transformed_aabb.project_range_in_plane(base, min, max);
+
+ if (max > z_max) {
+ z_max = max;
+ }
+
+ if (min < z_min) {
+ z_min = min;
+ }
+
+ found_items = true;
+ }
+
+ if (found_items) {
+ min_distance = MAX(min_distance, z_min);
+ max_distance = MIN(max_distance, z_max);
+ }
+ }
+
+ real_t range = max_distance - min_distance;
+
+ int splits = 0;
+ switch (RSG::storage->light_directional_get_shadow_mode(p_instance->base)) {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: splits = 1; break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: splits = 2; break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: splits = 4; break;
+ }
+
+ real_t distances[5];
+
+ distances[0] = min_distance;
+ for (int i = 0; i < splits; i++) {
+ distances[i + 1] = min_distance + RSG::storage->light_get_param(p_instance->base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range;
+ };
+
+ distances[splits] = max_distance;
+
+ real_t texture_size = RSG::scene_render->get_directional_light_shadow_size(light->instance);
+
+ bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base);
+
+ real_t first_radius = 0.0;
+
+ real_t min_distance_bias_scale = pancake_size > 0 ? distances[1] / 10.0 : 0;
+
+ for (int i = 0; i < splits; i++) {
+
+ RENDER_TIMESTAMP("Culling Directional Light split" + itos(i));
+
+ // setup a camera matrix for that range!
+ CameraMatrix camera_matrix;
+
+ real_t aspect = p_cam_projection.get_aspect();
+
+ if (p_cam_orthogonal) {
+
+ Vector2 vp_he = p_cam_projection.get_viewport_half_extents();
+
+ camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
+ } else {
+
+ real_t fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
+ camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
+ }
+
+ //obtain the frustum endpoints
+
+ Vector3 endpoints[8]; // frustum plane endpoints
+ bool res = camera_matrix.get_endpoints(p_cam_transform, endpoints);
+ ERR_CONTINUE(!res);
+
+ // obtain the light frustm ranges (given endpoints)
+
+ Transform transform = light_transform; //discard scale and stabilize light
+
+ Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized();
+ Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized();
+ Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized();
+ //z_vec points agsint the camera, like in default opengl
+
+ real_t x_min = 0.f, x_max = 0.f;
+ real_t y_min = 0.f, y_max = 0.f;
+ real_t z_min = 0.f, z_max = 0.f;
+
+ // FIXME: z_max_cam is defined, computed, but not used below when setting up
+ // ortho_camera. Commented out for now to fix warnings but should be investigated.
+ real_t x_min_cam = 0.f, x_max_cam = 0.f;
+ real_t y_min_cam = 0.f, y_max_cam = 0.f;
+ real_t z_min_cam = 0.f;
+ //real_t z_max_cam = 0.f;
+
+ real_t bias_scale = 1.0;
+ real_t aspect_bias_scale = 1.0;
+
+ //used for culling
+
+ for (int j = 0; j < 8; j++) {
+
+ real_t d_x = x_vec.dot(endpoints[j]);
+ real_t d_y = y_vec.dot(endpoints[j]);
+ real_t d_z = z_vec.dot(endpoints[j]);
+
+ if (j == 0 || d_x < x_min)
+ x_min = d_x;
+ if (j == 0 || d_x > x_max)
+ x_max = d_x;
+
+ if (j == 0 || d_y < y_min)
+ y_min = d_y;
+ if (j == 0 || d_y > y_max)
+ y_max = d_y;
+
+ if (j == 0 || d_z < z_min)
+ z_min = d_z;
+ if (j == 0 || d_z > z_max)
+ z_max = d_z;
+ }
+
+ real_t radius = 0;
+ real_t soft_shadow_expand = 0;
+ Vector3 center;
+
+ {
+ //camera viewport stuff
+
+ for (int j = 0; j < 8; j++) {
+
+ center += endpoints[j];
+ }
+ center /= 8.0;
+
+ //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5;
+
+ for (int j = 0; j < 8; j++) {
+
+ real_t d = center.distance_to(endpoints[j]);
+ if (d > radius)
+ radius = d;
+ }
+
+ radius *= texture_size / (texture_size - 2.0); //add a texel by each side
+
+ if (i == 0) {
+ first_radius = radius;
+ } else {
+ bias_scale = radius / first_radius;
+ }
+
+ z_min_cam = z_vec.dot(center) - radius;
+
+ {
+
+ float soft_shadow_angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE);
+
+ if (soft_shadow_angle > 0.0 && pancake_size > 0.0) {
+
+ float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam;
+ soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range;
+
+ x_max += soft_shadow_expand;
+ y_max += soft_shadow_expand;
+
+ x_min -= soft_shadow_expand;
+ y_min -= soft_shadow_expand;
+ }
+ }
+
+ x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand;
+ x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand;
+ y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand;
+ y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand;
+
+ if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) {
+ //this trick here is what stabilizes the shadow (make potential jaggies to not move)
+ //at the cost of some wasted resolution. Still the quality increase is very well worth it
+
+ real_t unit = radius * 2.0 / texture_size;
+
+ x_max_cam = Math::stepify(x_max_cam, unit);
+ x_min_cam = Math::stepify(x_min_cam, unit);
+ y_max_cam = Math::stepify(y_max_cam, unit);
+ y_min_cam = Math::stepify(y_min_cam, unit);
+ }
+ }
+
+ //now that we now all ranges, we can proceed to make the light frustum planes, for culling octree
+
+ Vector<Plane> light_frustum_planes;
+ light_frustum_planes.resize(6);
+
+ //right/left
+ light_frustum_planes.write[0] = Plane(x_vec, x_max);
+ light_frustum_planes.write[1] = Plane(-x_vec, -x_min);
+ //top/bottom
+ light_frustum_planes.write[2] = Plane(y_vec, y_max);
+ light_frustum_planes.write[3] = Plane(-y_vec, -y_min);
+ //near/far
+ light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6);
+ light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed
+
+ int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK);
+
+ // a pre pass will need to be needed to determine the actual z-near to be used
+
+ Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2));
+
+ real_t cull_max = 0;
+ for (int j = 0; j < cull_count; j++) {
+
+ real_t min, max;
+ Instance *instance = instance_shadow_cull_result[j];
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
+ cull_count--;
+ SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
+ j--;
+ continue;
+ }
+
+ instance->transformed_aabb.project_range_in_plane(Plane(z_vec, 0), min, max);
+ instance->depth = near_plane.distance_to(instance->transform.origin);
+ instance->depth_layer = 0;
+ if (j == 0 || max > cull_max) {
+ cull_max = max;
+ }
+ }
+
+ if (cull_max > z_max) {
+ z_max = cull_max;
+ }
+
+ if (pancake_size > 0) {
+ z_max = z_vec.dot(center) + radius + pancake_size;
+ }
+
+ if (aspect != 1.0) {
+
+ // if the aspect is different, then the radius will become larger.
+ // if this happens, then bias needs to be adjusted too, as depth will increase
+ // to do this, compare the depth of one that would have resulted from a square frustum
+
+ CameraMatrix camera_matrix_square;
+ if (p_cam_orthogonal) {
+
+ Vector2 vp_he = camera_matrix.get_viewport_half_extents();
+ if (p_cam_vaspect) {
+ camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
+ } else {
+ camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
+ }
+ } else {
+ Vector2 vp_he = camera_matrix.get_viewport_half_extents();
+ if (p_cam_vaspect) {
+ camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
+ } else {
+ camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
+ }
+
+ if (i == 0) {
+ //print_line("prev he: " + vp_he + " new he: " + camera_matrix_square.get_viewport_half_extents());
+ }
+ }
+
+ Vector3 endpoints_square[8]; // frustum plane endpoints
+ res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square);
+ ERR_CONTINUE(!res);
+ Vector3 center_square;
+ real_t z_max_square = 0;
+
+ for (int j = 0; j < 8; j++) {
+
+ center_square += endpoints_square[j];
+
+ real_t d_z = z_vec.dot(endpoints_square[j]);
+
+ if (j == 0 || d_z > z_max_square)
+ z_max_square = d_z;
+ }
+
+ if (cull_max > z_max_square) {
+ z_max_square = cull_max;
+ }
+
+ center_square /= 8.0;
+
+ real_t radius_square = 0;
+
+ for (int j = 0; j < 8; j++) {
+
+ real_t d = center_square.distance_to(endpoints_square[j]);
+ if (d > radius_square)
+ radius_square = d;
+ }
+
+ radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side
+
+ if (pancake_size > 0) {
+ z_max_square = z_vec.dot(center_square) + radius_square + pancake_size;
+ }
+
+ real_t z_min_cam_square = z_vec.dot(center_square) - radius_square;
+
+ aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square);
+
+ // this is not entirely perfect, because the cull-adjusted z-max may be different
+ // but at least it's warranted that it results in a greater bias, so no acne should be present either way.
+ // pancaking also helps with this.
+ }
+
+ {
+
+ CameraMatrix ortho_camera;
+ real_t half_x = (x_max_cam - x_min_cam) * 0.5;
+ real_t half_y = (y_max_cam - y_min_cam) * 0.5;
+
+ ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam));
+
+ Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam));
+
+ Transform ortho_transform;
+ ortho_transform.basis = transform.basis;
+ ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max;
+
+ {
+ Vector3 max_in_view = p_cam_transform.affine_inverse().xform(z_vec * cull_max);
+ Vector3 dir_in_view = p_cam_transform.xform_inv(z_vec).normalized();
+ cull_max = dir_in_view.dot(max_in_view);
+ }
+
+ RSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, z_max - z_min_cam, distances[i + 1], i, radius * 2.0 / texture_size, bias_scale * aspect_bias_scale * min_distance_bias_scale, z_max, uv_scale);
+ }
+
+ RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
+ }
+
+ } break;
+ case RS::LIGHT_OMNI: {
+
+ RS::LightOmniShadowMode shadow_mode = RSG::storage->light_omni_get_shadow_mode(p_instance->base);
+
+ if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !RSG::scene_render->light_instances_can_render_shadow_cube()) {
+
+ for (int i = 0; i < 2; i++) {
+
+ //using this one ensures that raster deferred will have it
+ RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i));
+
+ real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
+
+ real_t z = i == 0 ? -1 : 1;
+ Vector<Plane> planes;
+ planes.resize(5);
+ planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius));
+ planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius));
+ planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius));
+ planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius));
+ planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius));
+
+ int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK);
+ Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z);
+
+ for (int j = 0; j < cull_count; j++) {
+
+ Instance *instance = instance_shadow_cull_result[j];
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
+ cull_count--;
+ SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
+ j--;
+ } else {
+ if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
+ animated_material_found = true;
+ }
+
+ instance->depth = near_plane.distance_to(instance->transform.origin);
+ instance->depth_layer = 0;
+ }
+ }
+
+ RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0);
+ RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
+ }
+ } else { //shadow cube
+
+ real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
+ CameraMatrix cm;
+ cm.set_perspective(90, 1, 0.01, radius);
+
+ for (int i = 0; i < 6; i++) {
+
+ RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i));
+ //using this one ensures that raster deferred will have it
+
+ 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)
+ };
+
+ Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]);
+
+ Vector<Plane> planes = cm.get_projection_planes(xform);
+
+ int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK);
+
+ Plane near_plane(xform.origin, -xform.basis.get_axis(2));
+ for (int j = 0; j < cull_count; j++) {
+
+ Instance *instance = instance_shadow_cull_result[j];
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
+ cull_count--;
+ SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
+ j--;
+ } else {
+ if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
+ animated_material_found = true;
+ }
+ instance->depth = near_plane.distance_to(instance->transform.origin);
+ instance->depth_layer = 0;
+ }
+ }
+
+ RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
+ RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
+ }
+
+ //restore the regular DP matrix
+ RSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0);
+ }
+
+ } break;
+ case RS::LIGHT_SPOT: {
+
+ RENDER_TIMESTAMP("Culling Spot Light");
+
+ real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE);
+ real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
+
+ CameraMatrix cm;
+ cm.set_perspective(angle * 2.0, 1.0, 0.01, radius);
+
+ Vector<Plane> planes = cm.get_projection_planes(light_transform);
+ int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, RS::INSTANCE_GEOMETRY_MASK);
+
+ Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2));
+ for (int j = 0; j < cull_count; j++) {
+
+ Instance *instance = instance_shadow_cull_result[j];
+ if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
+ cull_count--;
+ SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
+ j--;
+ } else {
+ if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
+ animated_material_found = true;
+ }
+ instance->depth = near_plane.distance_to(instance->transform.origin);
+ instance->depth_layer = 0;
+ }
+ }
+
+ RSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
+ RSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
+
+ } break;
+ }
+
+ return animated_material_found;
+}
+
+void RenderingServerScene::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) {
+// render to mono camera
+#ifndef _3D_DISABLED
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+
+ /* STEP 1 - SETUP CAMERA */
+ CameraMatrix camera_matrix;
+ bool ortho = false;
+
+ switch (camera->type) {
+ case Camera::ORTHOGONAL: {
+
+ camera_matrix.set_orthogonal(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ ortho = true;
+ } break;
+ case Camera::PERSPECTIVE: {
+
+ camera_matrix.set_perspective(
+ camera->fov,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ ortho = false;
+
+ } break;
+ case Camera::FRUSTUM: {
+
+ camera_matrix.set_frustum(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->offset,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ ortho = false;
+ } break;
+ }
+
+ _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
+ _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1);
+#endif
+}
+
+void RenderingServerScene::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) {
+ // render for AR/VR interface
+
+ Camera *camera = camera_owner.getornull(p_camera);
+ ERR_FAIL_COND(!camera);
+
+ /* SETUP CAMERA, we are ignoring type and FOV here */
+ float aspect = p_viewport_size.width / (float)p_viewport_size.height;
+ CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar);
+
+ // We also ignore our camera position, it will have been positioned with a slightly old tracking position.
+ // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo!
+ Transform world_origin = XRServer::get_singleton()->get_world_origin();
+ Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin);
+
+ // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye
+ if (p_eye == XRInterface::EYE_LEFT) {
+ // Center our transform, we assume basis is equal.
+ Transform mono_transform = cam_transform;
+ Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin);
+ mono_transform.origin += right_transform.origin;
+ mono_transform.origin *= 0.5;
+
+ // We need to combine our projection frustums for culling.
+ // Ideally we should use our clipping planes for this and combine them,
+ // however our shadow map logic uses our projection matrix.
+ // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix.
+
+ // - get some base values we need
+ float eye_dist = (mono_transform.origin - cam_transform.origin).length();
+ float z_near = camera_matrix.get_z_near(); // get our near plane
+ float z_far = camera_matrix.get_z_far(); // get our far plane
+ float width = (2.0 * z_near) / camera_matrix.matrix[0][0];
+ float x_shift = width * camera_matrix.matrix[2][0];
+ float height = (2.0 * z_near) / camera_matrix.matrix[1][1];
+ float y_shift = height * camera_matrix.matrix[2][1];
+
+ // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift);
+
+ // - calculate our near plane size (horizontal only, right_near is mirrored)
+ float left_near = -eye_dist - ((width - x_shift) * 0.5);
+
+ // - calculate our far plane size (horizontal only, right_far is mirrored)
+ float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near);
+ float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near);
+ if (left_far > left_far_right_eye) {
+ // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes.
+ left_far = left_far_right_eye;
+ }
+
+ // - figure out required z-shift
+ float slope = (left_far - left_near) / (z_far - z_near);
+ float z_shift = (left_near / slope) - z_near;
+
+ // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift)
+ float top_near = (height - y_shift) * 0.5;
+ top_near += (top_near / z_near) * z_shift;
+ float bottom_near = -(height + y_shift) * 0.5;
+ bottom_near += (bottom_near / z_near) * z_shift;
+
+ // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift);
+
+ // - generate our frustum
+ CameraMatrix combined_matrix;
+ combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift);
+
+ // and finally move our camera back
+ Transform apply_z_shift;
+ apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards
+ mono_transform *= apply_z_shift;
+
+ // now prepare our scene with our adjusted transform projection matrix
+ _prepare_scene(mono_transform, combined_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
+ } else if (p_eye == XRInterface::EYE_MONO) {
+ // For mono render, prepare as per usual
+ _prepare_scene(cam_transform, camera_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
+ }
+
+ // And render our scene...
+ _render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1);
+};
+
+void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, 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
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+
+ render_pass++;
+ uint32_t camera_layer_mask = p_visible_layers;
+
+ RSG::scene_render->set_scene_pass(render_pass);
+
+ RENDER_TIMESTAMP("Frustum Culling");
+
+ //rasterizer->set_camera(camera->transform, camera_matrix,ortho);
+
+ Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform);
+
+ Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized());
+ float z_far = p_cam_projection.get_z_far();
+
+ /* STEP 2 - CULL */
+ instance_cull_count = scenario->octree.cull_convex(planes, instance_cull_result, MAX_INSTANCE_CULL);
+ light_cull_count = 0;
+
+ reflection_probe_cull_count = 0;
+ decal_cull_count = 0;
+ gi_probe_cull_count = 0;
+
+ //light_samplers_culled=0;
+
+ /*
+ print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0));
+ print_line("OTO: "+itos(p_scenario->octree.get_octant_count()));
+ print_line("OTE: "+itos(p_scenario->octree.get_elem_count()));
+ print_line("OTP: "+itos(p_scenario->octree.get_pair_count()));
+ */
+
+ /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */
+ //removed, will replace with culling
+
+ /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */
+
+ for (int i = 0; i < instance_cull_count; i++) {
+
+ Instance *ins = instance_cull_result[i];
+
+ bool keep = false;
+
+ if ((camera_layer_mask & ins->layer_mask) == 0) {
+ //failure
+ } else if (ins->base_type == RS::INSTANCE_LIGHT && ins->visible) {
+
+ if (light_cull_count < MAX_LIGHTS_CULLED) {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
+
+ if (!light->geometries.empty()) {
+ //do not add this light if no geometry is affected by it..
+ light_cull_result[light_cull_count] = ins;
+ light_instance_cull_result[light_cull_count] = light->instance;
+ if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(ins->base)) {
+ RSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later
+ }
+
+ light_cull_count++;
+ }
+ }
+ } else if (ins->base_type == RS::INSTANCE_REFLECTION_PROBE && ins->visible) {
+
+ if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data);
+
+ if (p_reflection_probe != reflection_probe->instance) {
+ //avoid entering The Matrix
+
+ if (!reflection_probe->geometries.empty()) {
+ //do not add this light if no geometry is affected by it..
+
+ if (reflection_probe->reflection_dirty || RSG::scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) {
+ if (!reflection_probe->update_list.in_list()) {
+ reflection_probe->render_step = 0;
+ reflection_probe_render_list.add_last(&reflection_probe->update_list);
+ }
+
+ reflection_probe->reflection_dirty = false;
+ }
+
+ if (RSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) {
+ reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance;
+ reflection_probe_cull_count++;
+ }
+ }
+ }
+ }
+ } else if (ins->base_type == RS::INSTANCE_DECAL && ins->visible) {
+
+ if (decal_cull_count < MAX_DECALS_CULLED) {
+
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(ins->base_data);
+
+ if (!decal->geometries.empty()) {
+ //do not add this decal if no geometry is affected by it..
+ decal_instance_cull_result[decal_cull_count] = decal->instance;
+ decal_cull_count++;
+ }
+ }
+
+ } else if (ins->base_type == RS::INSTANCE_GI_PROBE && ins->visible) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(ins->base_data);
+ if (!gi_probe->update_element.in_list()) {
+ gi_probe_update_list.add(&gi_probe->update_element);
+ }
+
+ if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) {
+ gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance;
+ gi_probe_cull_count++;
+ }
+
+ } else if (((1 << ins->base_type) & RS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
+
+ keep = true;
+
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data);
+
+ if (ins->redraw_if_visible) {
+ RenderingServerRaster::redraw_request();
+ }
+
+ if (ins->base_type == RS::INSTANCE_PARTICLES) {
+ //particles visible? process them
+ if (RSG::storage->particles_is_inactive(ins->base)) {
+ //but if nothing is going on, don't do it.
+ keep = false;
+ } else {
+ RSG::storage->particles_request_process(ins->base);
+ //particles visible? request redraw
+ RenderingServerRaster::redraw_request();
+ }
+ }
+
+ if (geom->lighting_dirty) {
+ int l = 0;
+ //only called when lights AABB enter/exit this geometry
+ ins->light_instances.resize(geom->lighting.size());
+
+ for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) {
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+
+ ins->light_instances.write[l++] = light->instance;
+ }
+
+ geom->lighting_dirty = false;
+ }
+
+ if (geom->reflection_dirty) {
+ int l = 0;
+ //only called when reflection probe AABB enter/exit this geometry
+ ins->reflection_probe_instances.resize(geom->reflection_probes.size());
+
+ for (List<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
+
+ ins->reflection_probe_instances.write[l++] = reflection_probe->instance;
+ }
+
+ geom->reflection_dirty = false;
+ }
+
+ if (geom->gi_probes_dirty) {
+ int l = 0;
+ //only called when reflection probe AABB enter/exit this geometry
+ ins->gi_probe_instances.resize(geom->gi_probes.size());
+
+ for (List<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data);
+
+ ins->gi_probe_instances.write[l++] = gi_probe->probe_instance;
+ }
+
+ geom->gi_probes_dirty = false;
+ }
+
+ ins->depth = near_plane.distance_to(ins->transform.origin);
+ ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15);
+ }
+
+ if (!keep) {
+ // remove, no reason to keep
+ instance_cull_count--;
+ SWAP(instance_cull_result[i], instance_cull_result[instance_cull_count]);
+ i--;
+ ins->last_render_pass = 0; // make invalid
+ } else {
+
+ ins->last_render_pass = render_pass;
+ }
+ }
+
+ /* STEP 5 - PROCESS LIGHTS */
+
+ RID *directional_light_ptr = &light_instance_cull_result[light_cull_count];
+ directional_light_count = 0;
+
+ // directional lights
+ {
+
+ Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size());
+ int directional_shadow_count = 0;
+
+ for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) {
+
+ if (light_cull_count + directional_light_count >= MAX_LIGHTS_CULLED) {
+ break;
+ }
+
+ if (!E->get()->visible)
+ continue;
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+
+ //check shadow..
+
+ if (light) {
+ if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base)) {
+ lights_with_shadow[directional_shadow_count++] = E->get();
+ }
+ //add to list
+ directional_light_ptr[directional_light_count++] = light->instance;
+ }
+ }
+
+ RSG::scene_render->set_directional_shadow_count(directional_shadow_count);
+
+ for (int i = 0; i < directional_shadow_count; i++) {
+
+ RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i));
+
+ _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario);
+
+ RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i));
+ }
+ }
+
+ if (p_using_shadows) { //setup shadow maps
+
+ //SortArray<Instance*,_InstanceLightsort> sorter;
+ //sorter.sort(light_cull_result,light_cull_count);
+ for (int i = 0; i < light_cull_count; i++) {
+
+ Instance *ins = light_cull_result[i];
+
+ if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base))
+ continue;
+
+ InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
+
+ float coverage = 0.f;
+
+ { //compute coverage
+
+ Transform cam_xf = p_cam_transform;
+ float zn = p_cam_projection.get_z_near();
+ Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane
+
+ // near plane half width and height
+ Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents();
+
+ switch (RSG::storage->light_get_type(ins->base)) {
+
+ case RS::LIGHT_OMNI: {
+
+ float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE);
+
+ //get two points parallel to near plane
+ Vector3 points[2] = {
+ ins->transform.origin,
+ ins->transform.origin + cam_xf.basis.get_axis(0) * radius
+ };
+
+ if (!p_cam_orthogonal) {
+ //if using perspetive, map them to near plane
+ for (int j = 0; j < 2; j++) {
+ if (p.distance_to(points[j]) < 0) {
+ points[j].z = -zn; //small hack to keep size constant when hitting the screen
+ }
+
+ p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane
+ }
+ }
+
+ float screen_diameter = points[0].distance_to(points[1]) * 2;
+ coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y);
+ } break;
+ case RS::LIGHT_SPOT: {
+
+ float radius = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE);
+ float angle = RSG::storage->light_get_param(ins->base, RS::LIGHT_PARAM_SPOT_ANGLE);
+
+ float w = radius * Math::sin(Math::deg2rad(angle));
+ float d = radius * Math::cos(Math::deg2rad(angle));
+
+ Vector3 base = ins->transform.origin - ins->transform.basis.get_axis(2).normalized() * d;
+
+ Vector3 points[2] = {
+ base,
+ base + cam_xf.basis.get_axis(0) * w
+ };
+
+ if (!p_cam_orthogonal) {
+ //if using perspetive, map them to near plane
+ for (int j = 0; j < 2; j++) {
+ if (p.distance_to(points[j]) < 0) {
+ points[j].z = -zn; //small hack to keep size constant when hitting the screen
+ }
+
+ p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane
+ }
+ }
+
+ float screen_diameter = points[0].distance_to(points[1]) * 2;
+ coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y);
+
+ } break;
+ default: {
+ ERR_PRINT("Invalid Light Type");
+ }
+ }
+ }
+
+ if (light->shadow_dirty) {
+ light->last_version++;
+ light->shadow_dirty = false;
+ }
+
+ bool redraw = RSG::scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
+
+ if (redraw) {
+ //must redraw!
+ RENDER_TIMESTAMP(">Rendering Light " + itos(i));
+ light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario);
+ RENDER_TIMESTAMP("<Rendering Light " + itos(i));
+ }
+ }
+ }
+}
+
+void RenderingServerScene::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+
+ /* ENVIRONMENT */
+
+ RID environment;
+ if (p_force_environment.is_valid()) //camera has more environment priority
+ environment = p_force_environment;
+ else if (scenario->environment.is_valid())
+ environment = scenario->environment;
+ else
+ environment = scenario->fallback_environment;
+
+ RID camera_effects;
+ if (p_force_camera_effects.is_valid()) {
+ camera_effects = p_force_camera_effects;
+ } else {
+ camera_effects = scenario->camera_effects;
+ }
+ /* PROCESS GEOMETRY AND DRAW SCENE */
+
+ RENDER_TIMESTAMP("Render Scene ");
+ RSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, decal_instance_cull_result, decal_cull_count, environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
+}
+
+void RenderingServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
+
+#ifndef _3D_DISABLED
+
+ Scenario *scenario = scenario_owner.getornull(p_scenario);
+
+ RID environment;
+ if (scenario->environment.is_valid())
+ environment = scenario->environment;
+ else
+ environment = scenario->fallback_environment;
+ RENDER_TIMESTAMP("Render Empty Scene ");
+ RSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
+#endif
+}
+
+bool RenderingServerScene::_render_reflection_probe_step(Instance *p_instance, int p_step) {
+
+ InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
+ Scenario *scenario = p_instance->scenario;
+ ERR_FAIL_COND_V(!scenario, true);
+
+ RenderingServerRaster::redraw_request(); //update, so it updates in editor
+
+ if (p_step == 0) {
+
+ if (!RSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
+ return true; //all full
+ }
+ }
+
+ if (p_step >= 0 && p_step < 6) {
+
+ 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)
+ };
+
+ Vector3 extents = RSG::storage->reflection_probe_get_extents(p_instance->base);
+ Vector3 origin_offset = RSG::storage->reflection_probe_get_origin_offset(p_instance->base);
+ float max_distance = RSG::storage->reflection_probe_get_origin_max_distance(p_instance->base);
+
+ Vector3 edge = view_normals[p_step] * extents;
+ float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit
+
+ max_distance = MAX(max_distance, distance);
+
+ //render cubemap side
+ CameraMatrix cm;
+ cm.set_perspective(90, 1, 0.01, max_distance);
+
+ Transform local_view;
+ local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]);
+
+ Transform xform = p_instance->transform * local_view;
+
+ RID shadow_atlas;
+
+ bool use_shadows = RSG::storage->reflection_probe_renders_shadows(p_instance->base);
+ if (use_shadows) {
+
+ shadow_atlas = scenario->reflection_probe_shadow_atlas;
+ }
+
+ RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
+ _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows);
+ _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step);
+
+ } else {
+ //do roughness postprocess step until it believes it's done
+ RENDER_TIMESTAMP("Post-Process Reflection Probe, Step " + itos(p_step));
+ return RSG::scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance);
+ }
+
+ return false;
+}
+
+void RenderingServerScene::render_probes() {
+
+ /* REFLECTION PROBES */
+
+ SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first();
+
+ bool busy = false;
+
+ while (ref_probe) {
+
+ SelfList<InstanceReflectionProbeData> *next = ref_probe->next();
+ RID base = ref_probe->self()->owner->base;
+
+ switch (RSG::storage->reflection_probe_get_update_mode(base)) {
+
+ case RS::REFLECTION_PROBE_UPDATE_ONCE: {
+ if (busy) //already rendering something
+ break;
+
+ bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step);
+ if (done) {
+ reflection_probe_render_list.remove(ref_probe);
+ } else {
+ ref_probe->self()->render_step++;
+ }
+
+ busy = true; //do not render another one of this kind
+ } break;
+ case RS::REFLECTION_PROBE_UPDATE_ALWAYS: {
+
+ int step = 0;
+ bool done = false;
+ while (!done) {
+ done = _render_reflection_probe_step(ref_probe->self()->owner, step);
+ step++;
+ }
+
+ reflection_probe_render_list.remove(ref_probe);
+ } break;
+ }
+
+ ref_probe = next;
+ }
+
+ /* GI PROBES */
+
+ SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
+
+ if (gi_probe) {
+ RENDER_TIMESTAMP("Render GI Probes");
+ }
+
+ while (gi_probe) {
+
+ SelfList<InstanceGIProbeData> *next = gi_probe->next();
+
+ InstanceGIProbeData *probe = gi_probe->self();
+ //Instance *instance_probe = probe->owner;
+
+ //check if probe must be setup, but don't do if on the lighting thread
+
+ bool cache_dirty = false;
+ int cache_count = 0;
+ {
+
+ int light_cache_size = probe->light_cache.size();
+ const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr();
+ const RID *instance_caches = probe->light_instances.ptr();
+
+ int idx = 0; //must count visible lights
+ for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+ if (cache_dirty) {
+ //do nothing, since idx must count all visible lights anyway
+ } else if (idx >= light_cache_size) {
+ cache_dirty = true;
+ } else {
+
+ const InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ if (
+ instance_caches[idx] != instance_light->instance ||
+ cache->has_shadow != RSG::storage->light_has_shadow(instance->base) ||
+ cache->type != RSG::storage->light_get_type(instance->base) ||
+ cache->transform != instance->transform ||
+ cache->color != RSG::storage->light_get_color(instance->base) ||
+ cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) ||
+ cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) ||
+ cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) ||
+ cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) ||
+ cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) ||
+ cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache_dirty = true;
+ }
+ }
+
+ idx++;
+ }
+
+ for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
+
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+ if (cache_dirty) {
+ //do nothing, since idx must count all visible lights anyway
+ } else if (idx >= light_cache_size) {
+ cache_dirty = true;
+ } else {
+
+ const InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ if (
+ instance_caches[idx] != instance_light->instance ||
+ cache->has_shadow != RSG::storage->light_has_shadow(instance->base) ||
+ cache->type != RSG::storage->light_get_type(instance->base) ||
+ cache->transform != instance->transform ||
+ cache->color != RSG::storage->light_get_color(instance->base) ||
+ cache->energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY) ||
+ cache->bake_energy != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY) ||
+ cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) ||
+ cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) ||
+ cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) ||
+ cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache_dirty = true;
+ }
+ }
+
+ idx++;
+ }
+
+ if (idx != light_cache_size) {
+ cache_dirty = true;
+ }
+
+ cache_count = idx;
+ }
+
+ bool update_lights = RSG::scene_render->gi_probe_needs_update(probe->probe_instance);
+
+ if (cache_dirty) {
+ probe->light_cache.resize(cache_count);
+ probe->light_instances.resize(cache_count);
+
+ if (cache_count) {
+ InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw();
+ RID *instance_caches = probe->light_instances.ptrw();
+
+ int idx = 0; //must count visible lights
+ for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+
+ InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ instance_caches[idx] = instance_light->instance;
+ cache->has_shadow = RSG::storage->light_has_shadow(instance->base);
+ cache->type = RSG::storage->light_get_type(instance->base);
+ cache->transform = instance->transform;
+ cache->color = RSG::storage->light_get_color(instance->base);
+ cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY);
+ cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE);
+ cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION);
+ cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
+ cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+ for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
+ Instance *instance = E->get();
+ InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
+ if (!instance->visible) {
+ continue;
+ }
+
+ InstanceGIProbeData::LightCache *cache = &caches[idx];
+
+ instance_caches[idx] = instance_light->instance;
+ cache->has_shadow = RSG::storage->light_has_shadow(instance->base);
+ cache->type = RSG::storage->light_get_type(instance->base);
+ cache->transform = instance->transform;
+ cache->color = RSG::storage->light_get_color(instance->base);
+ cache->energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ENERGY);
+ cache->bake_energy = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ cache->radius = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE);
+ cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION);
+ cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
+ cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+
+ idx++;
+ }
+ }
+
+ update_lights = true;
+ }
+
+ instance_cull_count = 0;
+ for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) {
+ if (instance_cull_count < MAX_INSTANCE_CULL) {
+ Instance *ins = E->get().geometry;
+ if (!ins->visible) {
+ continue;
+ }
+ InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
+
+ if (geom->gi_probes_dirty) {
+ //giprobes may be dirty, so update
+ int l = 0;
+ //only called when reflection probe AABB enter/exit this geometry
+ ins->gi_probe_instances.resize(geom->gi_probes.size());
+
+ for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) {
+
+ InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data);
+
+ ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance;
+ }
+
+ geom->gi_probes_dirty = false;
+ }
+
+ instance_cull_result[instance_cull_count++] = E->get().geometry;
+ }
+ }
+
+ RSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result);
+
+ gi_probe_update_list.remove(gi_probe);
+
+ gi_probe = next;
+ }
+}
+
+void RenderingServerScene::_update_dirty_instance(Instance *p_instance) {
+
+ if (p_instance->update_aabb) {
+ _update_instance_aabb(p_instance);
+ }
+
+ if (p_instance->update_dependencies) {
+
+ p_instance->instance_increase_version();
+
+ if (p_instance->base.is_valid()) {
+ RSG::storage->base_update_dependency(p_instance->base, p_instance);
+ }
+
+ if (p_instance->material_override.is_valid()) {
+ RSG::storage->material_update_dependency(p_instance->material_override, p_instance);
+ }
+
+ if (p_instance->base_type == RS::INSTANCE_MESH) {
+ //remove materials no longer used and un-own them
+
+ int new_mat_count = RSG::storage->mesh_get_surface_count(p_instance->base);
+ p_instance->materials.resize(new_mat_count);
+
+ int new_blend_shape_count = RSG::storage->mesh_get_blend_shape_count(p_instance->base);
+ if (new_blend_shape_count != p_instance->blend_values.size()) {
+ p_instance->blend_values.resize(new_blend_shape_count);
+ for (int i = 0; i < new_blend_shape_count; i++) {
+ p_instance->blend_values.write[i] = 0;
+ }
+ }
+ }
+
+ if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
+
+ bool can_cast_shadows = true;
+ bool is_animated = false;
+
+ if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) {
+ can_cast_shadows = false;
+ } else if (p_instance->material_override.is_valid()) {
+ can_cast_shadows = RSG::storage->material_casts_shadows(p_instance->material_override);
+ is_animated = RSG::storage->material_is_animated(p_instance->material_override);
+ } else {
+
+ if (p_instance->base_type == RS::INSTANCE_MESH) {
+ RID mesh = p_instance->base;
+
+ if (mesh.is_valid()) {
+ bool cast_shadows = false;
+
+ for (int i = 0; i < p_instance->materials.size(); i++) {
+
+ RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : RSG::storage->mesh_surface_get_material(mesh, i);
+
+ if (!mat.is_valid()) {
+ cast_shadows = true;
+ } else {
+
+ if (RSG::storage->material_casts_shadows(mat)) {
+ cast_shadows = true;
+ }
+
+ if (RSG::storage->material_is_animated(mat)) {
+ is_animated = true;
+ }
+
+ RSG::storage->material_update_dependency(mat, p_instance);
+ }
+ }
+
+ if (!cast_shadows) {
+ can_cast_shadows = false;
+ }
+ }
+
+ } else if (p_instance->base_type == RS::INSTANCE_MULTIMESH) {
+ RID mesh = RSG::storage->multimesh_get_mesh(p_instance->base);
+ if (mesh.is_valid()) {
+
+ bool cast_shadows = false;
+
+ int sc = RSG::storage->mesh_get_surface_count(mesh);
+ for (int i = 0; i < sc; i++) {
+
+ RID mat = RSG::storage->mesh_surface_get_material(mesh, i);
+
+ if (!mat.is_valid()) {
+ cast_shadows = true;
+
+ } else {
+
+ if (RSG::storage->material_casts_shadows(mat)) {
+ cast_shadows = true;
+ }
+ if (RSG::storage->material_is_animated(mat)) {
+ is_animated = true;
+ }
+
+ RSG::storage->material_update_dependency(mat, p_instance);
+ }
+ }
+
+ if (!cast_shadows) {
+ can_cast_shadows = false;
+ }
+
+ RSG::storage->base_update_dependency(mesh, p_instance);
+ }
+ } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) {
+
+ RID mat = RSG::storage->immediate_get_material(p_instance->base);
+
+ can_cast_shadows = !mat.is_valid() || RSG::storage->material_casts_shadows(mat);
+
+ if (mat.is_valid() && RSG::storage->material_is_animated(mat)) {
+ is_animated = true;
+ }
+
+ if (mat.is_valid()) {
+ RSG::storage->material_update_dependency(mat, p_instance);
+ }
+
+ } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
+
+ bool cast_shadows = false;
+
+ int dp = RSG::storage->particles_get_draw_passes(p_instance->base);
+
+ for (int i = 0; i < dp; i++) {
+
+ RID mesh = RSG::storage->particles_get_draw_pass_mesh(p_instance->base, i);
+ if (!mesh.is_valid())
+ continue;
+
+ int sc = RSG::storage->mesh_get_surface_count(mesh);
+ for (int j = 0; j < sc; j++) {
+
+ RID mat = RSG::storage->mesh_surface_get_material(mesh, j);
+
+ if (!mat.is_valid()) {
+ cast_shadows = true;
+ } else {
+
+ if (RSG::storage->material_casts_shadows(mat)) {
+ cast_shadows = true;
+ }
+
+ if (RSG::storage->material_is_animated(mat)) {
+ is_animated = true;
+ }
+
+ RSG::storage->material_update_dependency(mat, p_instance);
+ }
+ }
+ }
+
+ if (!cast_shadows) {
+ can_cast_shadows = false;
+ }
+ }
+ }
+
+ if (can_cast_shadows != geom->can_cast_shadows) {
+ //ability to cast shadows change, let lights now
+ for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) {
+ InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
+ light->shadow_dirty = true;
+ }
+
+ geom->can_cast_shadows = can_cast_shadows;
+ }
+
+ geom->material_is_animated = is_animated;
+ }
+
+ if (p_instance->skeleton.is_valid()) {
+ RSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance);
+ }
+
+ p_instance->clean_up_dependencies();
+ }
+
+ _instance_update_list.remove(&p_instance->update_item);
+
+ _update_instance(p_instance);
+
+ p_instance->update_aabb = false;
+ p_instance->update_dependencies = false;
+}
+
+void RenderingServerScene::update_dirty_instances() {
+
+ RSG::storage->update_dirty_resources();
+
+ while (_instance_update_list.first()) {
+
+ _update_dirty_instance(_instance_update_list.first()->self());
+ }
+}
+
+bool RenderingServerScene::free(RID p_rid) {
+
+ if (camera_owner.owns(p_rid)) {
+
+ Camera *camera = camera_owner.getornull(p_rid);
+
+ camera_owner.free(p_rid);
+ memdelete(camera);
+
+ } else if (scenario_owner.owns(p_rid)) {
+
+ Scenario *scenario = scenario_owner.getornull(p_rid);
+
+ while (scenario->instances.first()) {
+ instance_set_scenario(scenario->instances.first()->self()->self, RID());
+ }
+ RSG::scene_render->free(scenario->reflection_probe_shadow_atlas);
+ RSG::scene_render->free(scenario->reflection_atlas);
+ scenario_owner.free(p_rid);
+ memdelete(scenario);
+
+ } else if (instance_owner.owns(p_rid)) {
+ // delete the instance
+
+ update_dirty_instances();
+
+ Instance *instance = instance_owner.getornull(p_rid);
+
+ instance_set_use_lightmap(p_rid, RID(), RID());
+ instance_set_scenario(p_rid, RID());
+ instance_set_base(p_rid, RID());
+ instance_geometry_set_material_override(p_rid, RID());
+ instance_attach_skeleton(p_rid, RID());
+
+ update_dirty_instances(); //in case something changed this
+
+ instance_owner.free(p_rid);
+ memdelete(instance);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+RenderingServerScene *RenderingServerScene::singleton = nullptr;
+
+RenderingServerScene::RenderingServerScene() {
+
+ render_pass = 1;
+ singleton = this;
+}
+
+RenderingServerScene::~RenderingServerScene() {
+}
diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h
new file mode 100644
index 0000000000..f5f7c50ea0
--- /dev/null
+++ b/servers/rendering/rendering_server_scene.h
@@ -0,0 +1,462 @@
+/*************************************************************************/
+/* rendering_server_scene.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VISUALSERVERSCENE_H
+#define VISUALSERVERSCENE_H
+
+#include "servers/rendering/rasterizer.h"
+
+#include "core/math/geometry.h"
+#include "core/math/octree.h"
+#include "core/os/semaphore.h"
+#include "core/os/thread.h"
+#include "core/rid_owner.h"
+#include "core/self_list.h"
+#include "servers/xr/xr_interface.h"
+
+class RenderingServerScene {
+public:
+ enum {
+
+ MAX_INSTANCE_CULL = 65536,
+ MAX_LIGHTS_CULLED = 4096,
+ MAX_REFLECTION_PROBES_CULLED = 4096,
+ MAX_DECALS_CULLED = 4096,
+ MAX_GI_PROBES_CULLED = 4096,
+ MAX_ROOM_CULL = 32,
+ MAX_EXTERIOR_PORTALS = 128,
+ };
+
+ uint64_t render_pass;
+
+ static RenderingServerScene *singleton;
+
+ /* CAMERA API */
+
+ struct Camera {
+
+ enum Type {
+ PERSPECTIVE,
+ ORTHOGONAL,
+ FRUSTUM
+ };
+ Type type;
+ float fov;
+ float znear, zfar;
+ float size;
+ Vector2 offset;
+ uint32_t visible_layers;
+ bool vaspect;
+ RID env;
+ RID effects;
+
+ Transform transform;
+
+ Camera() {
+
+ visible_layers = 0xFFFFFFFF;
+ fov = 70;
+ type = PERSPECTIVE;
+ znear = 0.05;
+ zfar = 100;
+ size = 1.0;
+ offset = Vector2();
+ vaspect = false;
+ }
+ };
+
+ mutable RID_PtrOwner<Camera> camera_owner;
+
+ 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);
+ virtual void camera_set_transform(RID p_camera, const Transform &p_transform);
+ virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
+ virtual void camera_set_environment(RID p_camera, RID p_env);
+ virtual void camera_set_camera_effects(RID p_camera, RID p_fx);
+ virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
+
+ /* SCENARIO API */
+
+ struct Instance;
+
+ struct Scenario {
+
+ RS::ScenarioDebugMode debug;
+ RID self;
+
+ Octree<Instance, true> octree;
+
+ List<Instance *> directional_lights;
+ RID environment;
+ RID fallback_environment;
+ RID camera_effects;
+ RID reflection_probe_shadow_atlas;
+ RID reflection_atlas;
+
+ SelfList<Instance>::List instances;
+
+ Scenario() { debug = RS::SCENARIO_DEBUG_DISABLED; }
+ };
+
+ mutable RID_PtrOwner<Scenario> scenario_owner;
+
+ static void *_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int);
+ static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *);
+
+ virtual RID scenario_create();
+
+ virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode);
+ virtual void scenario_set_environment(RID p_scenario, RID p_environment);
+ virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx);
+ virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
+ virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
+
+ /* INSTANCING API */
+
+ struct InstanceBaseData {
+
+ virtual ~InstanceBaseData() {}
+ };
+
+ struct Instance : RasterizerScene::InstanceBase {
+
+ RID self;
+ //scenario stuff
+ OctreeElementID octree_id;
+ Scenario *scenario;
+ SelfList<Instance> scenario_item;
+
+ //aabb stuff
+ bool update_aabb;
+ bool update_dependencies;
+
+ SelfList<Instance> update_item;
+
+ AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better?
+ float extra_margin;
+ ObjectID object_id;
+
+ float lod_begin;
+ float lod_end;
+ float lod_begin_hysteresis;
+ float lod_end_hysteresis;
+ RID lod_instance;
+
+ uint64_t last_render_pass;
+ uint64_t last_frame_pass;
+
+ uint64_t version; // changes to this, and changes to base increase version
+
+ InstanceBaseData *base_data;
+
+ virtual void dependency_deleted(RID p_dependency) {
+ if (p_dependency == base) {
+ singleton->instance_set_base(self, RID());
+ } else if (p_dependency == skeleton) {
+ singleton->instance_attach_skeleton(self, RID());
+ } else {
+ singleton->_instance_queue_update(this, false, true);
+ }
+ }
+
+ virtual void dependency_changed(bool p_aabb, bool p_dependencies) {
+ singleton->_instance_queue_update(this, p_aabb, p_dependencies);
+ }
+
+ Instance() :
+ scenario_item(this),
+ update_item(this) {
+
+ octree_id = 0;
+ scenario = nullptr;
+
+ update_aabb = false;
+ update_dependencies = false;
+
+ extra_margin = 0;
+
+ visible = true;
+
+ lod_begin = 0;
+ lod_end = 0;
+ lod_begin_hysteresis = 0;
+ lod_end_hysteresis = 0;
+
+ last_render_pass = 0;
+ last_frame_pass = 0;
+ version = 1;
+ base_data = nullptr;
+
+ custom_aabb = nullptr;
+ }
+
+ ~Instance() {
+
+ if (base_data)
+ memdelete(base_data);
+ if (custom_aabb)
+ memdelete(custom_aabb);
+ }
+ };
+
+ SelfList<Instance>::List _instance_update_list;
+ void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false);
+
+ struct InstanceGeometryData : public InstanceBaseData {
+
+ List<Instance *> lighting;
+ bool lighting_dirty;
+ bool can_cast_shadows;
+ bool material_is_animated;
+
+ List<Instance *> decals;
+ bool decal_dirty;
+
+ List<Instance *> reflection_probes;
+ bool reflection_dirty;
+
+ List<Instance *> gi_probes;
+ bool gi_probes_dirty;
+
+ List<Instance *> lightmap_captures;
+
+ InstanceGeometryData() {
+
+ lighting_dirty = false;
+ reflection_dirty = true;
+ can_cast_shadows = true;
+ material_is_animated = true;
+ gi_probes_dirty = true;
+ decal_dirty = true;
+ }
+ };
+
+ struct InstanceReflectionProbeData : public InstanceBaseData {
+
+ Instance *owner;
+
+ struct PairInfo {
+ List<Instance *>::Element *L; //reflection iterator in geometry
+ Instance *geometry;
+ };
+ List<PairInfo> geometries;
+
+ RID instance;
+ bool reflection_dirty;
+ SelfList<InstanceReflectionProbeData> update_list;
+
+ int render_step;
+
+ InstanceReflectionProbeData() :
+ update_list(this) {
+
+ reflection_dirty = true;
+ render_step = -1;
+ }
+ };
+
+ struct InstanceDecalData : public InstanceBaseData {
+
+ Instance *owner;
+ RID instance;
+
+ struct PairInfo {
+ List<Instance *>::Element *L; //reflection iterator in geometry
+ Instance *geometry;
+ };
+ List<PairInfo> geometries;
+
+ InstanceDecalData() {
+ }
+ };
+
+ SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list;
+
+ struct InstanceLightData : public InstanceBaseData {
+
+ struct PairInfo {
+ List<Instance *>::Element *L; //light iterator in geometry
+ Instance *geometry;
+ };
+
+ RID instance;
+ uint64_t last_version;
+ List<Instance *>::Element *D; // directional light in scenario
+
+ bool shadow_dirty;
+
+ List<PairInfo> geometries;
+
+ Instance *baked_light;
+
+ InstanceLightData() {
+
+ shadow_dirty = true;
+ D = nullptr;
+ last_version = 0;
+ baked_light = nullptr;
+ }
+ };
+
+ struct InstanceGIProbeData : public InstanceBaseData {
+
+ Instance *owner;
+
+ struct PairInfo {
+ List<Instance *>::Element *L; //gi probe iterator in geometry
+ Instance *geometry;
+ };
+
+ List<PairInfo> geometries;
+ List<PairInfo> dynamic_geometries;
+
+ Set<Instance *> lights;
+
+ struct LightCache {
+
+ RS::LightType type;
+ Transform transform;
+ Color color;
+ float energy;
+ float bake_energy;
+ float radius;
+ float attenuation;
+ float spot_angle;
+ float spot_attenuation;
+ bool has_shadow;
+ };
+
+ Vector<LightCache> light_cache;
+ Vector<RID> light_instances;
+
+ RID probe_instance;
+
+ bool invalid;
+ uint32_t base_version;
+
+ SelfList<InstanceGIProbeData> update_element;
+
+ InstanceGIProbeData() :
+ update_element(this) {
+ invalid = true;
+ base_version = 0;
+ }
+ };
+
+ SelfList<InstanceGIProbeData>::List gi_probe_update_list;
+
+ struct InstanceLightmapCaptureData : public InstanceBaseData {
+
+ struct PairInfo {
+ List<Instance *>::Element *L; //iterator in geometry
+ Instance *geometry;
+ };
+ List<PairInfo> geometries;
+
+ Set<Instance *> users;
+
+ InstanceLightmapCaptureData() {
+ }
+ };
+
+ int instance_cull_count;
+ Instance *instance_cull_result[MAX_INSTANCE_CULL];
+ Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
+ Instance *light_cull_result[MAX_LIGHTS_CULLED];
+ RID light_instance_cull_result[MAX_LIGHTS_CULLED];
+ int light_cull_count;
+ int directional_light_count;
+ RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
+ RID decal_instance_cull_result[MAX_DECALS_CULLED];
+ int reflection_probe_cull_count;
+ int decal_cull_count;
+ RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED];
+ int gi_probe_cull_count;
+
+ RID_PtrOwner<Instance> instance_owner;
+
+ virtual RID instance_create();
+
+ virtual void instance_set_base(RID p_instance, RID p_base);
+ virtual void instance_set_scenario(RID p_instance, RID p_scenario);
+ virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
+ 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_visible(RID p_instance, bool p_visible);
+ virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap);
+
+ virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb);
+
+ virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton);
+ virtual void instance_set_exterior(RID p_instance, bool p_enabled);
+
+ virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin);
+
+ // don't use these in a game!
+ virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const;
+ virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
+ virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const;
+
+ virtual void instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled);
+ virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting);
+ virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
+
+ virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin);
+ virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance);
+
+ _FORCE_INLINE_ void _update_instance(Instance *p_instance);
+ _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
+ _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
+ _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);
+
+ _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario);
+
+ bool _render_reflection_probe_step(Instance *p_instance, int p_step);
+ void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true);
+ void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
+ 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, 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, RID p_shadow_atlas);
+ void update_dirty_instances();
+
+ void render_probes();
+
+ bool free(RID p_rid);
+
+ RenderingServerScene();
+ virtual ~RenderingServerScene();
+};
+
+#endif // VISUALSERVERSCENE_H
diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/rendering_server_viewport.cpp
new file mode 100644
index 0000000000..6fb8f6ca63
--- /dev/null
+++ b/servers/rendering/rendering_server_viewport.cpp
@@ -0,0 +1,855 @@
+/*************************************************************************/
+/* rendering_server_viewport.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_viewport.h"
+
+#include "core/project_settings.h"
+#include "rendering_server_canvas.h"
+#include "rendering_server_globals.h"
+#include "rendering_server_scene.h"
+
+static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_viewport, RenderingServerCanvas::Canvas *p_canvas, RenderingServerViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) {
+
+ Transform2D xf = p_viewport->global_transform;
+
+ float scale = 1.0;
+ if (p_viewport->canvas_map.has(p_canvas->parent)) {
+ xf = xf * p_viewport->canvas_map[p_canvas->parent].transform;
+ scale = p_canvas->parent_scale;
+ }
+
+ xf = xf * p_canvas_data->transform;
+
+ if (scale != 1.0 && !RSG::canvas->disable_scale) {
+ Vector2 pivot = p_vp_size * 0.5;
+ Transform2D xfpivot;
+ xfpivot.set_origin(pivot);
+ Transform2D xfscale;
+ xfscale.scale(Vector2(scale, scale));
+
+ xf = xfpivot.affine_inverse() * xf;
+ xf = xfscale * xf;
+ xf = xfpivot * xf;
+ }
+
+ return xf;
+}
+
+void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+
+ RENDER_TIMESTAMP(">Begin Rendering 3D Scene");
+
+ Ref<XRInterface> xr_interface;
+ if (XRServer::get_singleton() != nullptr) {
+ xr_interface = XRServer::get_singleton()->get_primary_interface();
+ }
+
+ 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, p_viewport->shadow_atlas);
+ } else {
+ RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ }
+ RENDER_TIMESTAMP("<End Rendering 3D Scene");
+}
+
+void RenderingServerViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) {
+
+ if (p_viewport->measure_render_time) {
+ String rt_id = "vp_begin_" + itos(p_viewport->self.get_id());
+ RSG::storage->capture_timestamp(rt_id);
+ timestamp_vp_map[rt_id] = p_viewport->self;
+ }
+
+ /* Camera should always be BEFORE any other 3D */
+
+ bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
+ int scenario_canvas_max_layer = 0;
+
+ Color bgcolor = RSG::storage->get_default_clear_color();
+
+ if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->scenario_owner.owns(p_viewport->scenario)) {
+
+ RenderingServerScene::Scenario *scenario = RSG::scene->scenario_owner.getornull(p_viewport->scenario);
+ ERR_FAIL_COND(!scenario);
+ if (RSG::scene_render->is_environment(scenario->environment)) {
+ scenario_draw_canvas_bg = RSG::scene_render->environment_get_background(scenario->environment) == RS::ENV_BG_CANVAS;
+
+ scenario_canvas_max_layer = RSG::scene_render->environment_get_canvas_max_layer(scenario->environment);
+ }
+ }
+
+ bool can_draw_3d = RSG::scene->camera_owner.owns(p_viewport->camera);
+
+ if (p_viewport->clear_mode != RS::VIEWPORT_CLEAR_NEVER) {
+ if (p_viewport->transparent_bg) {
+ bgcolor = Color(0, 0, 0, 0);
+ }
+ if (p_viewport->clear_mode == RS::VIEWPORT_CLEAR_ONLY_NEXT_FRAME) {
+ p_viewport->clear_mode = RS::VIEWPORT_CLEAR_NEVER;
+ }
+ }
+
+ if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) {
+ //wants to draw 3D but there is no render buffer, create
+ p_viewport->render_buffers = RSG::scene_render->render_buffers_create();
+ RSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa);
+ }
+
+ RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor);
+
+ if (!scenario_draw_canvas_bg && can_draw_3d) {
+ _draw_3d(p_viewport, p_eye);
+ }
+
+ if (!p_viewport->hide_canvas) {
+ int i = 0;
+
+ Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map;
+
+ Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y);
+ RasterizerCanvas::Light *lights = nullptr;
+ RasterizerCanvas::Light *lights_with_shadow = nullptr;
+ RasterizerCanvas::Light *lights_with_mask = nullptr;
+ Rect2 shadow_rect;
+
+ int light_count = 0;
+
+ RENDER_TIMESTAMP("Cull Canvas Lights");
+ for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
+
+ RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas);
+
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+
+ //find lights in canvas
+
+ for (Set<RasterizerCanvas::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) {
+
+ RasterizerCanvas::Light *cl = F->get();
+ if (cl->enabled && cl->texture.is_valid()) {
+ //not super efficient..
+ Size2 tsize = RSG::storage->texture_size_with_proxy(cl->texture);
+ tsize *= cl->scale;
+
+ Vector2 offset = tsize / 2.0;
+ cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize);
+ cl->xform_cache = xf * cl->xform;
+
+ if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) {
+
+ cl->filter_next_ptr = lights;
+ lights = cl;
+ // cl->texture_cache = nullptr;
+ Transform2D scale;
+ scale.scale(cl->rect_cache.size);
+ scale.elements[2] = cl->rect_cache.position;
+ cl->light_shader_xform = cl->xform * scale;
+ //cl->light_shader_pos = cl->xform_cache[2];
+ if (cl->use_shadow) {
+
+ cl->shadows_next_ptr = lights_with_shadow;
+ if (lights_with_shadow == nullptr) {
+ shadow_rect = cl->xform_cache.xform(cl->rect_cache);
+ } else {
+ shadow_rect = shadow_rect.merge(cl->xform_cache.xform(cl->rect_cache));
+ }
+ lights_with_shadow = cl;
+ cl->radius_cache = cl->rect_cache.size.length();
+ }
+ if (cl->mode == RS::CANVAS_LIGHT_MODE_MASK) {
+ cl->mask_next_ptr = lights_with_mask;
+ lights_with_mask = cl;
+ }
+
+ light_count++;
+ }
+
+ //guess this is not needed, but keeping because it may be
+ //RSG::canvas_render->light_internal_update(cl->light_internal, cl);
+ }
+ }
+
+ canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get();
+ }
+
+ if (lights_with_shadow) {
+ //update shadows if any
+
+ RasterizerCanvas::LightOccluderInstance *occluders = nullptr;
+
+ RENDER_TIMESTAMP(">Render 2D Shadows");
+ RENDER_TIMESTAMP("Cull Occluders");
+
+ //make list of occluders
+ for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
+
+ RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get().canvas);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+
+ for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
+
+ if (!F->get()->enabled)
+ continue;
+ F->get()->xform_cache = xf * F->get()->xform;
+ if (shadow_rect.intersects_transformed(F->get()->xform_cache, F->get()->aabb_cache)) {
+
+ F->get()->next = occluders;
+ occluders = F->get();
+ }
+ }
+ }
+ //update the light shadowmaps with them
+
+ RasterizerCanvas::Light *light = lights_with_shadow;
+ while (light) {
+
+ RENDER_TIMESTAMP("Render Shadow");
+
+ RSG::canvas_render->light_update_shadow(light->light_internal, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders);
+ light = light->shadows_next_ptr;
+ }
+
+ //RSG::canvas_render->reset_canvas();
+ RENDER_TIMESTAMP("<End rendering 2D Shadows");
+ }
+
+ if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) {
+ if (!can_draw_3d) {
+ RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
+ } else {
+ _draw_3d(p_viewport, p_eye);
+ }
+ scenario_draw_canvas_bg = false;
+ }
+
+ for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) {
+
+ RenderingServerCanvas::Canvas *canvas = static_cast<RenderingServerCanvas::Canvas *>(E->get()->canvas);
+
+ Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size);
+
+ RasterizerCanvas::Light *canvas_lights = nullptr;
+
+ RasterizerCanvas::Light *ptr = lights;
+ while (ptr) {
+ if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) {
+ ptr->next_ptr = canvas_lights;
+ canvas_lights = ptr;
+ }
+ ptr = ptr->filter_next_ptr;
+ }
+
+ RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect);
+ i++;
+
+ if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
+ if (!can_draw_3d) {
+ RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
+ } else {
+ _draw_3d(p_viewport, p_eye);
+ }
+
+ scenario_draw_canvas_bg = false;
+ }
+ }
+
+ if (scenario_draw_canvas_bg) {
+ if (!can_draw_3d) {
+ RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
+ } else {
+ _draw_3d(p_viewport, p_eye);
+ }
+ }
+
+ //RSG::canvas_render->canvas_debug_viewport_shadows(lights_with_shadow);
+ }
+
+ if (RSG::storage->render_target_is_clear_requested(p_viewport->render_target)) {
+ //was never cleared in the end, force clear it
+ RSG::storage->render_target_do_clear_request(p_viewport->render_target);
+ }
+
+ if (p_viewport->measure_render_time) {
+ String rt_id = "vp_end_" + itos(p_viewport->self.get_id());
+ RSG::storage->capture_timestamp(rt_id);
+ timestamp_vp_map[rt_id] = p_viewport->self;
+ }
+}
+
+void RenderingServerViewport::draw_viewports() {
+
+ timestamp_vp_map.clear();
+
+ // get our xr interface in case we need it
+ Ref<XRInterface> xr_interface;
+
+ if (XRServer::get_singleton() != nullptr) {
+ xr_interface = XRServer::get_singleton()->get_primary_interface();
+
+ // process all our active interfaces
+ XRServer::get_singleton()->_process();
+ }
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color"));
+ }
+
+ //sort viewports
+ active_viewports.sort_custom<ViewportSort>();
+
+ Map<DisplayServer::WindowID, Vector<Rasterizer::BlitToScreen>> blit_to_screen_list;
+ //draw viewports
+ RENDER_TIMESTAMP(">Render Viewports");
+
+ //determine what is visible
+ draw_viewports_pass++;
+
+ for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
+
+ Viewport *vp = active_viewports[i];
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED)
+ continue;
+
+ if (!vp->render_target.is_valid()) {
+ continue;
+ }
+ //ERR_CONTINUE(!vp->render_target.is_valid());
+
+ bool visible = vp->viewport_to_screen_rect != Rect2();
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
+ visible = true;
+ }
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_VISIBLE && RSG::storage->render_target_was_used(vp->render_target)) {
+ visible = true;
+ }
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
+ Viewport *parent = viewport_owner.getornull(vp->parent);
+ if (parent && parent->last_pass == draw_viewports_pass) {
+ visible = true;
+ }
+ }
+
+ visible = visible && vp->size.x > 1 && vp->size.y > 1;
+
+ if (visible) {
+ vp->last_pass = draw_viewports_pass;
+ }
+ }
+
+ for (int i = 0; i < active_viewports.size(); i++) {
+
+ Viewport *vp = active_viewports[i];
+
+ if (vp->last_pass != draw_viewports_pass) {
+ continue; //should not draw
+ }
+
+ RENDER_TIMESTAMP(">Rendering Viewport " + itos(i));
+
+ RSG::storage->render_target_set_as_unused(vp->render_target);
+#if 0
+ // TODO fix up this code after we change our commit_for_eye to accept our new render targets
+
+ if (vp->use_xr && xr_interface.is_valid()) {
+ // override our size, make sure it matches our required size
+ vp->size = xr_interface->get_render_targetsize();
+ RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y);
+
+ // render mono or left eye first
+ XRInterface::Eyes leftOrMono = xr_interface->is_stereo() ? XRInterface::EYE_LEFT : XRInterface::EYE_MONO;
+
+ // check for an external texture destination for our left eye/mono
+ // TODO investigate how we're going to make external textures work
+ RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
+
+ // set our render target as current
+ RSG::rasterizer->set_current_render_target(vp->render_target);
+
+ // and draw left eye/mono
+ _draw_viewport(vp, leftOrMono);
+ xr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect);
+
+ // render right eye
+ if (leftOrMono == XRInterface::EYE_LEFT) {
+ // check for an external texture destination for our right eye
+ RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(XRInterface::EYE_RIGHT));
+
+ // commit for eye may have changed the render target
+ RSG::rasterizer->set_current_render_target(vp->render_target);
+
+ _draw_viewport(vp, XRInterface::EYE_RIGHT);
+ xr_interface->commit_for_eye(XRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect);
+ }
+
+ // and for our frame timing, mark when we've finished committing our eyes
+ XRServer::get_singleton()->_mark_commit();
+ } else {
+#endif
+ {
+ RSG::storage->render_target_set_external_texture(vp->render_target, 0);
+
+ RSG::scene_render->set_debug_draw_mode(vp->debug_draw);
+ RSG::storage->render_info_begin_capture();
+
+ // render standard mono camera
+ _draw_viewport(vp);
+
+ RSG::storage->render_info_end_capture();
+ vp->render_info[RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_OBJECTS_IN_FRAME);
+ vp->render_info[RS::VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_VERTICES_IN_FRAME);
+ vp->render_info[RS::VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME);
+ vp->render_info[RS::VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME);
+ vp->render_info[RS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME);
+ vp->render_info[RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_DRAW_CALLS_IN_FRAME);
+
+ if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && (!vp->viewport_render_direct_to_screen || !RSG::rasterizer->is_low_end())) {
+ //copy to screen if set as such
+ Rasterizer::BlitToScreen blit;
+ blit.render_target = vp->render_target;
+ if (vp->viewport_to_screen_rect != Rect2()) {
+ blit.rect = vp->viewport_to_screen_rect;
+ } else {
+ blit.rect.position = Vector2();
+ blit.rect.size = vp->size;
+ }
+
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<Rasterizer::BlitToScreen>();
+ }
+
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
+ }
+ }
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
+ vp->update_mode = RS::VIEWPORT_UPDATE_DISABLED;
+ }
+
+ RENDER_TIMESTAMP("<Rendering Viewport " + itos(i));
+ }
+ RSG::scene_render->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED);
+
+ RENDER_TIMESTAMP("<Render Viewports");
+ //this needs to be called to make screen swapping more efficient
+ RSG::rasterizer->prepare_for_blitting_render_targets();
+
+ for (Map<int, Vector<Rasterizer::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) {
+ RSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size());
+ }
+}
+
+RID RenderingServerViewport::viewport_create() {
+
+ Viewport *viewport = memnew(Viewport);
+
+ RID rid = viewport_owner.make_rid(viewport);
+
+ viewport->self = rid;
+ viewport->hide_scenario = false;
+ viewport->hide_canvas = false;
+ viewport->render_target = RSG::storage->render_target_create();
+ viewport->shadow_atlas = RSG::scene_render->shadow_atlas_create();
+ viewport->viewport_render_direct_to_screen = false;
+
+ return rid;
+}
+
+void RenderingServerViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->use_xr = p_use_xr;
+}
+
+void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
+
+ ERR_FAIL_COND(p_width < 0 && p_height < 0);
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->size = Size2(p_width, p_height);
+ RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height);
+ if (viewport->render_buffers.is_valid()) {
+ if (p_width == 0 || p_height == 0) {
+ RSG::scene_render->free(viewport->render_buffers);
+ viewport->render_buffers = RID();
+ } else {
+ RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa);
+ }
+ }
+}
+
+void RenderingServerViewport::viewport_set_active(RID p_viewport, bool p_active) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (p_active) {
+ ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active
+ active_viewports.push_back(viewport);
+ } else {
+ active_viewports.erase(viewport);
+ }
+}
+
+void RenderingServerViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->parent = p_parent_viewport;
+}
+
+void RenderingServerViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->clear_mode = p_clear_mode;
+}
+
+void RenderingServerViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (p_screen != DisplayServer::INVALID_WINDOW_ID) {
+ // If using GLES2 we can optimize this operation by rendering directly to system_fbo
+ // instead of rendering to fbo and copying to system_fbo after
+ if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
+
+ RSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y);
+ RSG::storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
+ }
+
+ viewport->viewport_to_screen_rect = p_rect;
+ viewport->viewport_to_screen = p_screen;
+ } else {
+
+ // if render_direct_to_screen was used, reset size and position
+ if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
+
+ RSG::storage->render_target_set_position(viewport->render_target, 0, 0);
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y);
+ }
+
+ viewport->viewport_to_screen_rect = Rect2();
+ viewport->viewport_to_screen = DisplayServer::INVALID_WINDOW_ID;
+ }
+}
+
+void RenderingServerViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (p_enable == viewport->viewport_render_direct_to_screen)
+ return;
+
+ // if disabled, reset render_target size and position
+ if (!p_enable) {
+
+ RSG::storage->render_target_set_position(viewport->render_target, 0, 0);
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y);
+ }
+
+ RSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable);
+ viewport->viewport_render_direct_to_screen = p_enable;
+
+ // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
+ if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
+
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y);
+ RSG::storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
+ }
+}
+
+void RenderingServerViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->update_mode = p_mode;
+}
+
+RID RenderingServerViewport::viewport_get_texture(RID p_viewport) const {
+
+ const Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, RID());
+
+ return RSG::storage->render_target_get_texture(viewport->render_target);
+}
+
+void RenderingServerViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->hide_scenario = p_hide;
+}
+void RenderingServerViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->hide_canvas = p_hide;
+}
+void RenderingServerViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->disable_environment = p_disable;
+}
+
+void RenderingServerViewport::viewport_attach_camera(RID p_viewport, RID p_camera) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->camera = p_camera;
+}
+void RenderingServerViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->scenario = p_scenario;
+}
+void RenderingServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ ERR_FAIL_COND(viewport->canvas_map.has(p_canvas));
+ RenderingServerCanvas::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas);
+ ERR_FAIL_COND(!canvas);
+
+ canvas->viewports.insert(p_viewport);
+ viewport->canvas_map[p_canvas] = Viewport::CanvasData();
+ viewport->canvas_map[p_canvas].layer = 0;
+ viewport->canvas_map[p_canvas].sublayer = 0;
+ viewport->canvas_map[p_canvas].canvas = canvas;
+}
+
+void RenderingServerViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ RenderingServerCanvas::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas);
+ ERR_FAIL_COND(!canvas);
+
+ viewport->canvas_map.erase(p_canvas);
+ canvas->viewports.erase(p_viewport);
+}
+void RenderingServerViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
+ viewport->canvas_map[p_canvas].transform = p_offset;
+}
+void RenderingServerViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ RSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_TRANSPARENT, p_enabled);
+ viewport->transparent_bg = p_enabled;
+}
+
+void RenderingServerViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->global_transform = p_transform;
+}
+void RenderingServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
+ viewport->canvas_map[p_canvas].layer = p_layer;
+ viewport->canvas_map[p_canvas].sublayer = p_sublayer;
+}
+
+void RenderingServerViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->shadow_atlas_size = p_size;
+
+ RSG::scene_render->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size);
+}
+
+void RenderingServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ RSG::scene_render->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
+}
+
+void RenderingServerViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (viewport->msaa == p_msaa) {
+ return;
+ }
+ viewport->msaa = p_msaa;
+ if (viewport->render_buffers.is_valid()) {
+ RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa);
+ }
+}
+
+void RenderingServerViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) {
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ if (viewport->screen_space_aa == p_mode) {
+ return;
+ }
+ viewport->screen_space_aa = p_mode;
+ if (viewport->render_buffers.is_valid()) {
+ RSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode);
+ }
+}
+
+int RenderingServerViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) {
+
+ ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1);
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ if (!viewport)
+ return 0; //there should be a lock here..
+
+ return viewport->render_info[p_info];
+}
+
+void RenderingServerViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->debug_draw = p_draw;
+}
+
+void RenderingServerViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->measure_render_time = p_enable;
+}
+
+float RenderingServerViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, 0);
+
+ return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0;
+}
+
+float RenderingServerViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const {
+
+ Viewport *viewport = viewport_owner.getornull(p_viewport);
+ ERR_FAIL_COND_V(!viewport, 0);
+
+ return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0;
+}
+
+bool RenderingServerViewport::free(RID p_rid) {
+
+ if (viewport_owner.owns(p_rid)) {
+
+ Viewport *viewport = viewport_owner.getornull(p_rid);
+
+ RSG::storage->free(viewport->render_target);
+ RSG::scene_render->free(viewport->shadow_atlas);
+ if (viewport->render_buffers.is_valid()) {
+ RSG::scene_render->free(viewport->render_buffers);
+ }
+
+ while (viewport->canvas_map.front()) {
+ viewport_remove_canvas(p_rid, viewport->canvas_map.front()->key());
+ }
+
+ viewport_set_scenario(p_rid, RID());
+ active_viewports.erase(viewport);
+
+ viewport_owner.free(p_rid);
+ memdelete(viewport);
+
+ return true;
+ }
+
+ return false;
+}
+
+void RenderingServerViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time) {
+
+ RID *vp = timestamp_vp_map.getptr(p_timestamp);
+ if (!vp) {
+ return;
+ }
+
+ Viewport *viewport = viewport_owner.getornull(*vp);
+ if (!viewport) {
+ return;
+ }
+
+ if (p_timestamp.begins_with("vp_begin")) {
+ viewport->time_cpu_begin = p_cpu_time;
+ viewport->time_gpu_begin = p_gpu_time;
+ }
+
+ if (p_timestamp.begins_with("vp_end")) {
+ viewport->time_cpu_end = p_cpu_time;
+ viewport->time_gpu_end = p_gpu_time;
+ }
+}
+
+void RenderingServerViewport::set_default_clear_color(const Color &p_color) {
+ RSG::storage->set_default_clear_color(p_color);
+}
+
+RenderingServerViewport::RenderingServerViewport() {
+}
diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/rendering_server_viewport.h
new file mode 100644
index 0000000000..fcba7886c5
--- /dev/null
+++ b/servers/rendering/rendering_server_viewport.h
@@ -0,0 +1,232 @@
+/*************************************************************************/
+/* rendering_server_viewport.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VISUALSERVERVIEWPORT_H
+#define VISUALSERVERVIEWPORT_H
+
+#include "core/rid_owner.h"
+#include "core/self_list.h"
+#include "rasterizer.h"
+#include "servers/rendering_server.h"
+#include "servers/xr/xr_interface.h"
+
+class RenderingServerViewport {
+public:
+ struct CanvasBase {
+ };
+
+ struct Viewport {
+
+ RID self;
+ RID parent;
+
+ bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */
+
+ Size2i size;
+ RID camera;
+ RID scenario;
+
+ RS::ViewportUpdateMode update_mode;
+ RID render_target;
+ RID render_target_texture;
+ RID render_buffers;
+
+ RS::ViewportMSAA msaa;
+ RS::ViewportScreenSpaceAA screen_space_aa;
+
+ DisplayServer::WindowID viewport_to_screen;
+ Rect2 viewport_to_screen_rect;
+ bool viewport_render_direct_to_screen;
+
+ bool hide_scenario;
+ bool hide_canvas;
+ bool disable_environment;
+ bool measure_render_time;
+
+ uint64_t time_cpu_begin;
+ uint64_t time_cpu_end;
+
+ uint64_t time_gpu_begin;
+ uint64_t time_gpu_end;
+
+ RID shadow_atlas;
+ int shadow_atlas_size;
+
+ uint64_t last_pass = 0;
+
+ int render_info[RS::VIEWPORT_RENDER_INFO_MAX];
+ RS::ViewportDebugDraw debug_draw;
+
+ RS::ViewportClearMode clear_mode;
+
+ bool transparent_bg;
+
+ struct CanvasKey {
+
+ int64_t stacking;
+ RID canvas;
+ bool operator<(const CanvasKey &p_canvas) const {
+ if (stacking == p_canvas.stacking)
+ return canvas < p_canvas.canvas;
+ return stacking < p_canvas.stacking;
+ }
+ CanvasKey() {
+ stacking = 0;
+ }
+ CanvasKey(const RID &p_canvas, int p_layer, int p_sublayer) {
+ canvas = p_canvas;
+ int64_t sign = p_layer < 0 ? -1 : 1;
+ stacking = sign * (((int64_t)ABS(p_layer)) << 32) + p_sublayer;
+ }
+ int get_layer() const { return stacking >> 32; }
+ };
+
+ struct CanvasData {
+
+ CanvasBase *canvas;
+ Transform2D transform;
+ int layer;
+ int sublayer;
+ };
+
+ Transform2D global_transform;
+
+ Map<RID, CanvasData> canvas_map;
+
+ Viewport() {
+ update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE;
+ clear_mode = RS::VIEWPORT_CLEAR_ALWAYS;
+ transparent_bg = false;
+ disable_environment = false;
+ viewport_to_screen = DisplayServer::INVALID_WINDOW_ID;
+ shadow_atlas_size = 0;
+ measure_render_time = false;
+
+ debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
+ msaa = RS::VIEWPORT_MSAA_DISABLED;
+ screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+
+ for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) {
+ render_info[i] = 0;
+ }
+ use_xr = false;
+
+ time_cpu_begin = 0;
+ time_cpu_end = 0;
+
+ time_gpu_begin = 0;
+ time_gpu_end = 0;
+ }
+ };
+
+ HashMap<String, RID> timestamp_vp_map;
+
+ uint64_t draw_viewports_pass = 0;
+
+ mutable RID_PtrOwner<Viewport> viewport_owner;
+
+ struct ViewportSort {
+ _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const {
+
+ bool left_to_screen = p_left->viewport_to_screen_rect.size != Size2();
+ bool right_to_screen = p_right->viewport_to_screen_rect.size != Size2();
+
+ if (left_to_screen == right_to_screen) {
+
+ return p_right->parent == p_left->self;
+ }
+ return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1);
+ }
+ };
+
+ Vector<Viewport *> active_viewports;
+
+private:
+ void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye);
+ void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO);
+
+public:
+ RID viewport_create();
+
+ void viewport_set_use_xr(RID p_viewport, bool p_use_xr);
+
+ void viewport_set_size(RID p_viewport, int p_width, int p_height);
+
+ void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
+ void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable);
+
+ void viewport_set_active(RID p_viewport, bool p_active);
+ void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport);
+ void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode);
+ void viewport_set_vflip(RID p_viewport, bool p_enable);
+
+ void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode);
+
+ RID viewport_get_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);
+ void viewport_set_disable_environment(RID p_viewport, bool p_disable);
+
+ void viewport_attach_camera(RID p_viewport, RID p_camera);
+ void viewport_set_scenario(RID p_viewport, RID p_scenario);
+ void viewport_attach_canvas(RID p_viewport, RID p_canvas);
+ void viewport_remove_canvas(RID p_viewport, RID p_canvas);
+ void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset);
+ void viewport_set_transparent_background(RID p_viewport, bool p_enabled);
+
+ void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform);
+ void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer);
+
+ void viewport_set_shadow_atlas_size(RID p_viewport, int p_size);
+ void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv);
+
+ void viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa);
+ void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode);
+
+ virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info);
+ virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw);
+
+ void viewport_set_measure_render_time(RID p_viewport, bool p_enable);
+ float viewport_get_measured_render_time_cpu(RID p_viewport) const;
+ float viewport_get_measured_render_time_gpu(RID p_viewport) const;
+
+ void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time);
+
+ void set_default_clear_color(const Color &p_color);
+ void draw_viewports();
+
+ bool free(RID p_rid);
+
+ RenderingServerViewport();
+ virtual ~RenderingServerViewport() {}
+};
+
+#endif // VISUALSERVERVIEWPORT_H
diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp
new file mode 100644
index 0000000000..4ca13dbef9
--- /dev/null
+++ b/servers/rendering/rendering_server_wrap_mt.cpp
@@ -0,0 +1,197 @@
+/*************************************************************************/
+/* rendering_server_wrap_mt.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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/os/os.h"
+#include "core/project_settings.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 = Thread::create(_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_capture_free_cached_ids();
+ particles_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 (thread) {
+
+ command_queue.push(this, &RenderingServerWrapMT::thread_exit);
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+
+ thread = nullptr;
+ } 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;
+ thread = nullptr;
+ 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
new file mode 100644
index 0000000000..79f328cb3b
--- /dev/null
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -0,0 +1,709 @@
+/*************************************************************************/
+/* rendering_server_wrap_mt.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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/command_queue_mt.h"
+#include "core/os/thread.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(const Vector<Ref<Image>> &p_slices) { return rendering_server->texture_3d_create(p_slices); }
+ 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)
+ FUNC4(texture_3d_update, RID, const Ref<Image> &, int, int)
+ 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() { return rendering_server->texture_2d_layered_placeholder_create(); }
+ 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)
+ FUNC3RC(Ref<Image>, texture_3d_slice_get, RID, int, int)
+
+ 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 &)
+
+ /* 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) {
+ return rendering_server->mesh_create_from_surfaces(p_surfaces);
+ }
+
+ 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)
+
+ 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_use_gi, RID, bool)
+
+ 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_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_interior_ambient, RID, const Color &)
+ FUNC2(reflection_probe_set_interior_ambient_energy, RID, float)
+ FUNC2(reflection_probe_set_interior_ambient_probe_contribution, RID, float)
+ 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)
+
+ /* 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)
+
+ /* LIGHTMAP CAPTURE */
+
+ FUNCRID(lightmap_capture)
+
+ FUNC2(lightmap_capture_set_bounds, RID, const AABB &)
+ FUNC1RC(AABB, lightmap_capture_get_bounds, RID)
+
+ FUNC2(lightmap_capture_set_octree, RID, const Vector<uint8_t> &)
+ FUNC1RC(Vector<uint8_t>, lightmap_capture_get_octree, RID)
+ FUNC2(lightmap_capture_set_octree_cell_transform, RID, const Transform &)
+ FUNC1RC(Transform, lightmap_capture_get_octree_cell_transform, RID)
+ FUNC2(lightmap_capture_set_octree_cell_subdiv, RID, int)
+ FUNC1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
+ FUNC2(lightmap_capture_set_energy, RID, float)
+ FUNC1RC(float, lightmap_capture_get_energy, RID)
+
+ /* 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)
+ FUNC1R(bool, particles_is_inactive, RID)
+ FUNC1(particles_request_process, RID)
+ FUNC1(particles_restart, RID)
+
+ 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 &)
+
+ FUNC1R(AABB, particles_get_current_aabb, RID)
+
+ /* 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_global_canvas_transform, RID, const Transform2D &)
+ FUNC4(viewport_set_canvas_stacking, RID, RID, int, int)
+ FUNC2(viewport_set_shadow_atlas_size, RID, int)
+ FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
+ FUNC2(viewport_set_msaa, RID, ViewportMSAA)
+ FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA)
+
+ //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);
+ }
+
+ FUNC1(directional_shadow_atlas_set_size, int)
+
+ /* SKY API */
+
+ FUNCRID(sky)
+ FUNC2(sky_set_radiance_size, RID, int)
+ FUNC2(sky_set_mode, RID, SkyMode)
+ FUNC2(sky_set_material, RID, RID)
+
+ /* 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)
+
+ FUNC9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float)
+
+ FUNC2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool)
+
+ FUNC11(environment_set_glow, RID, bool, int, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
+ FUNC1(environment_glow_set_use_bicubic_upscale, bool)
+
+ FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
+
+ FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID)
+
+ FUNC5(environment_set_fog, RID, bool, const Color &, const Color &, float)
+ FUNC7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
+ FUNC5(environment_set_fog_height, RID, bool, float, float, float)
+
+ FUNC2(screen_space_roughness_limiter_set_active, bool, 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)
+ FUNC3(instance_set_use_lightmap, RID, RID, RID)
+
+ 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)
+
+ /* 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_item)
+ FUNC2(canvas_item_set_parent, RID, RID)
+
+ 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)
+
+ FUNC2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
+ FUNC2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
+
+ FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
+ FUNC4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+ 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 &)
+ FUNC11(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC12(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC15(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC11(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC10(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC14(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, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC10(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC8(canvas_item_add_multimesh, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ FUNC8(canvas_item_add_particles, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
+ 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)
+
+ FUNC0R(RID, canvas_light_create)
+ FUNC2(canvas_light_attach_to_canvas, RID, RID)
+ FUNC2(canvas_light_set_enabled, RID, bool)
+ FUNC2(canvas_light_set_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_mode, RID, CanvasLightMode)
+
+ FUNC2(canvas_light_set_shadow_enabled, RID, bool)
+ FUNC2(canvas_light_set_shadow_buffer_size, RID, int)
+ 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_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_shape_as_lines, RID, const Vector<Vector2> &)
+
+ FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
+
+ /* 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();
+ }
+
+ 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();
+ }
+
+ 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
new file mode 100644
index 0000000000..76a81a4a1c
--- /dev/null
+++ b/servers/rendering/shader_language.cpp
@@ -0,0 +1,7011 @@
+/*************************************************************************/
+/* shader_language.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "shader_language.h"
+#include "core/os/os.h"
+#include "core/print_string.h"
+#include "servers/rendering_server.h"
+
+static bool _is_text_char(CharType c) {
+
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+}
+
+static bool _is_number(CharType c) {
+
+ return (c >= '0' && c <= '9');
+}
+
+static bool _is_hex(CharType c) {
+
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+
+String ShaderLanguage::get_operator_text(Operator p_op) {
+
+ static const char *op_names[OP_MAX] = { "==",
+ "!=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "&&",
+ "||",
+ "!",
+ "-",
+ "+",
+ "-",
+ "*",
+ "/",
+ "%",
+ "<<",
+ ">>",
+ "=",
+ "+=",
+ "-=",
+ "*=",
+ "/=",
+ "%=",
+ "<<=",
+ ">>=",
+ "&=",
+ "|=",
+ "^=",
+ "&",
+ "|",
+ "^",
+ "~",
+ "++",
+ "--",
+ "?",
+ ":",
+ "++",
+ "--",
+ "()",
+ "construct",
+ "index" };
+
+ return op_names[p_op];
+}
+
+const char *ShaderLanguage::token_names[TK_MAX] = {
+ "EMPTY",
+ "IDENTIFIER",
+ "TRUE",
+ "FALSE",
+ "REAL_CONSTANT",
+ "INT_CONSTANT",
+ "TYPE_VOID",
+ "TYPE_BOOL",
+ "TYPE_BVEC2",
+ "TYPE_BVEC3",
+ "TYPE_BVEC4",
+ "TYPE_INT",
+ "TYPE_IVEC2",
+ "TYPE_IVEC3",
+ "TYPE_IVEC4",
+ "TYPE_UINT",
+ "TYPE_UVEC2",
+ "TYPE_UVEC3",
+ "TYPE_UVEC4",
+ "TYPE_FLOAT",
+ "TYPE_VEC2",
+ "TYPE_VEC3",
+ "TYPE_VEC4",
+ "TYPE_MAT2",
+ "TYPE_MAT3",
+ "TYPE_MAT4",
+ "TYPE_SAMPLER2D",
+ "TYPE_ISAMPLER2D",
+ "TYPE_USAMPLER2D",
+ "TYPE_SAMPLER2DARRAY",
+ "TYPE_ISAMPLER2DARRAY",
+ "TYPE_USAMPLER2DARRAY",
+ "TYPE_SAMPLER3D",
+ "TYPE_ISAMPLER3D",
+ "TYPE_USAMPLER3D",
+ "TYPE_SAMPLERCUBE",
+ "INTERPOLATION_FLAT",
+ "INTERPOLATION_SMOOTH",
+ "CONST",
+ "PRECISION_LOW",
+ "PRECISION_MID",
+ "PRECISION_HIGH",
+ "OP_EQUAL",
+ "OP_NOT_EQUAL",
+ "OP_LESS",
+ "OP_LESS_EQUAL",
+ "OP_GREATER",
+ "OP_GREATER_EQUAL",
+ "OP_AND",
+ "OP_OR",
+ "OP_NOT",
+ "OP_ADD",
+ "OP_SUB",
+ "OP_MUL",
+ "OP_DIV",
+ "OP_MOD",
+ "OP_SHIFT_LEFT",
+ "OP_SHIFT_RIGHT",
+ "OP_ASSIGN",
+ "OP_ASSIGN_ADD",
+ "OP_ASSIGN_SUB",
+ "OP_ASSIGN_MUL",
+ "OP_ASSIGN_DIV",
+ "OP_ASSIGN_MOD",
+ "OP_ASSIGN_SHIFT_LEFT",
+ "OP_ASSIGN_SHIFT_RIGHT",
+ "OP_ASSIGN_BIT_AND",
+ "OP_ASSIGN_BIT_OR",
+ "OP_ASSIGN_BIT_XOR",
+ "OP_BIT_AND",
+ "OP_BIT_OR",
+ "OP_BIT_XOR",
+ "OP_BIT_INVERT",
+ "OP_INCREMENT",
+ "OP_DECREMENT",
+ "CF_IF",
+ "CF_ELSE",
+ "CF_FOR",
+ "CF_WHILE",
+ "CF_DO",
+ "CF_SWITCH",
+ "CF_CASE",
+ "CF_BREAK",
+ "CF_CONTINUE",
+ "CF_RETURN",
+ "CF_DISCARD",
+ "BRACKET_OPEN",
+ "BRACKET_CLOSE",
+ "CURLY_BRACKET_OPEN",
+ "CURLY_BRACKET_CLOSE",
+ "PARENTHESIS_OPEN",
+ "PARENTHESIS_CLOSE",
+ "QUESTION",
+ "COMMA",
+ "COLON",
+ "SEMICOLON",
+ "PERIOD",
+ "UNIFORM",
+ "VARYING",
+ "IN",
+ "OUT",
+ "INOUT",
+ "RENDER_MODE",
+ "HINT_WHITE_TEXTURE",
+ "HINT_BLACK_TEXTURE",
+ "HINT_NORMAL_TEXTURE",
+ "HINT_ANISO_TEXTURE",
+ "HINT_ALBEDO_TEXTURE",
+ "HINT_BLACK_ALBEDO_TEXTURE",
+ "HINT_COLOR",
+ "HINT_RANGE",
+ "FILTER_NEAREST",
+ "FILTER_LINEAR",
+ "FILTER_NEAREST_MIPMAP",
+ "FILTER_LINEAR_MIPMAP",
+ "FILTER_NEAREST_MIPMAP_ANISO",
+ "FILTER_LINEAR_MIPMAP_ANISO",
+ "REPEAT_ENABLE",
+ "REPEAT_DISABLE",
+ "SHADER_TYPE",
+ "CURSOR",
+ "ERROR",
+ "EOF",
+};
+
+String ShaderLanguage::get_token_text(Token p_token) {
+
+ String name = token_names[p_token.type];
+ if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) {
+ name += "(" + rtos(p_token.constant) + ")";
+ } else if (p_token.type == TK_IDENTIFIER) {
+ name += "(" + String(p_token.text) + ")";
+ } else if (p_token.type == TK_ERROR) {
+ name += "(" + String(p_token.text) + ")";
+ }
+
+ return name;
+}
+
+ShaderLanguage::Token ShaderLanguage::_make_token(TokenType p_type, const StringName &p_text) {
+
+ Token tk;
+ tk.type = p_type;
+ tk.text = p_text;
+ tk.line = tk_line;
+ if (tk.type == TK_ERROR) {
+ _set_error(p_text);
+ }
+ return tk;
+}
+
+const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
+ { TK_TRUE, "true" },
+ { TK_FALSE, "false" },
+ { TK_TYPE_VOID, "void" },
+ { TK_TYPE_BOOL, "bool" },
+ { TK_TYPE_BVEC2, "bvec2" },
+ { TK_TYPE_BVEC3, "bvec3" },
+ { TK_TYPE_BVEC4, "bvec4" },
+ { TK_TYPE_INT, "int" },
+ { TK_TYPE_IVEC2, "ivec2" },
+ { TK_TYPE_IVEC3, "ivec3" },
+ { TK_TYPE_IVEC4, "ivec4" },
+ { TK_TYPE_UINT, "uint" },
+ { TK_TYPE_UVEC2, "uvec2" },
+ { TK_TYPE_UVEC3, "uvec3" },
+ { TK_TYPE_UVEC4, "uvec4" },
+ { TK_TYPE_FLOAT, "float" },
+ { TK_TYPE_VEC2, "vec2" },
+ { TK_TYPE_VEC3, "vec3" },
+ { TK_TYPE_VEC4, "vec4" },
+ { TK_TYPE_MAT2, "mat2" },
+ { TK_TYPE_MAT3, "mat3" },
+ { TK_TYPE_MAT4, "mat4" },
+ { TK_TYPE_SAMPLER2D, "sampler2D" },
+ { TK_TYPE_ISAMPLER2D, "isampler2D" },
+ { TK_TYPE_USAMPLER2D, "usampler2D" },
+ { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray" },
+ { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray" },
+ { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray" },
+ { TK_TYPE_SAMPLER3D, "sampler3D" },
+ { TK_TYPE_ISAMPLER3D, "isampler3D" },
+ { TK_TYPE_USAMPLER3D, "usampler3D" },
+ { TK_TYPE_SAMPLERCUBE, "samplerCube" },
+ { TK_INTERPOLATION_FLAT, "flat" },
+ { TK_INTERPOLATION_SMOOTH, "smooth" },
+ { TK_CONST, "const" },
+ { TK_STRUCT, "struct" },
+ { TK_PRECISION_LOW, "lowp" },
+ { TK_PRECISION_MID, "mediump" },
+ { TK_PRECISION_HIGH, "highp" },
+ { TK_CF_IF, "if" },
+ { TK_CF_ELSE, "else" },
+ { TK_CF_FOR, "for" },
+ { TK_CF_WHILE, "while" },
+ { TK_CF_DO, "do" },
+ { TK_CF_SWITCH, "switch" },
+ { TK_CF_CASE, "case" },
+ { TK_CF_DEFAULT, "default" },
+ { TK_CF_BREAK, "break" },
+ { TK_CF_CONTINUE, "continue" },
+ { TK_CF_RETURN, "return" },
+ { TK_CF_DISCARD, "discard" },
+ { TK_UNIFORM, "uniform" },
+ { TK_VARYING, "varying" },
+ { TK_ARG_IN, "in" },
+ { TK_ARG_OUT, "out" },
+ { TK_ARG_INOUT, "inout" },
+ { TK_RENDER_MODE, "render_mode" },
+ { TK_HINT_WHITE_TEXTURE, "hint_white" },
+ { TK_HINT_BLACK_TEXTURE, "hint_black" },
+ { TK_HINT_NORMAL_TEXTURE, "hint_normal" },
+ { TK_HINT_ROUGHNESS_NORMAL_TEXTURE, "hint_roughness_normal" },
+ { TK_HINT_ROUGHNESS_R, "hint_roughness_r" },
+ { TK_HINT_ROUGHNESS_G, "hint_roughness_g" },
+ { TK_HINT_ROUGHNESS_B, "hint_roughness_b" },
+ { TK_HINT_ROUGHNESS_A, "hint_roughness_a" },
+ { TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray" },
+ { TK_HINT_ANISO_TEXTURE, "hint_aniso" },
+ { TK_HINT_ALBEDO_TEXTURE, "hint_albedo" },
+ { TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" },
+ { TK_HINT_COLOR, "hint_color" },
+ { TK_HINT_RANGE, "hint_range" },
+ { TK_FILTER_NEAREST, "filter_nearest" },
+ { TK_FILTER_LINEAR, "filter_linear" },
+ { TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" },
+ { TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" },
+ { TK_FILTER_NEAREST_MIPMAP_ANISO, "filter_nearest_mipmap_aniso" },
+ { TK_FILTER_LINEAR_MIPMAP_ANISO, "filter_linear_mipmap_aniso" },
+ { TK_REPEAT_ENABLE, "repeat_enable" },
+ { TK_REPEAT_DISABLE, "repeat_disable" },
+ { TK_SHADER_TYPE, "shader_type" },
+ { TK_ERROR, nullptr }
+};
+
+ShaderLanguage::Token ShaderLanguage::_get_token() {
+
+#define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : CharType(0))
+
+ while (true) {
+ char_idx++;
+ switch (GETCHAR(-1)) {
+
+ case 0:
+ return _make_token(TK_EOF);
+ case 0xFFFF:
+ return _make_token(TK_CURSOR); //for completion
+ case '\t':
+ case '\r':
+ case ' ':
+ continue;
+ case '\n':
+ tk_line++;
+ continue;
+ case '/': {
+
+ switch (GETCHAR(0)) {
+ case '*': { // block comment
+
+ char_idx++;
+ while (true) {
+ if (GETCHAR(0) == 0) {
+ return _make_token(TK_EOF);
+ }
+ if (GETCHAR(0) == '*' && GETCHAR(1) == '/') {
+ char_idx += 2;
+ break;
+ } else if (GETCHAR(0) == '\n') {
+ tk_line++;
+ }
+
+ char_idx++;
+ }
+
+ } break;
+ case '/': { // line comment skip
+
+ while (true) {
+ if (GETCHAR(0) == '\n') {
+ tk_line++;
+ char_idx++;
+ break;
+ }
+ if (GETCHAR(0) == 0) {
+ return _make_token(TK_EOF);
+ }
+ char_idx++;
+ }
+
+ } break;
+ case '=': { // diveq
+
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_DIV);
+
+ } break;
+ default:
+ return _make_token(TK_OP_DIV);
+ }
+
+ continue; //a comment, continue to next token
+ } break;
+ case '=': {
+
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_EQUAL);
+ }
+
+ return _make_token(TK_OP_ASSIGN);
+
+ } break;
+ case '<': {
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_LESS_EQUAL);
+ } else if (GETCHAR(0) == '<') {
+ char_idx++;
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_SHIFT_LEFT);
+ }
+
+ return _make_token(TK_OP_SHIFT_LEFT);
+ }
+
+ return _make_token(TK_OP_LESS);
+
+ } break;
+ case '>': {
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_GREATER_EQUAL);
+ } else if (GETCHAR(0) == '>') {
+ char_idx++;
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_SHIFT_RIGHT);
+ }
+
+ return _make_token(TK_OP_SHIFT_RIGHT);
+ }
+
+ return _make_token(TK_OP_GREATER);
+
+ } break;
+ case '!': {
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_NOT_EQUAL);
+ }
+
+ return _make_token(TK_OP_NOT);
+
+ } break;
+ //case '"' //string - no strings in shader
+ //case '\'' //string - no strings in shader
+ case '{':
+ return _make_token(TK_CURLY_BRACKET_OPEN);
+ case '}':
+ return _make_token(TK_CURLY_BRACKET_CLOSE);
+ case '[':
+ return _make_token(TK_BRACKET_OPEN);
+ case ']':
+ return _make_token(TK_BRACKET_CLOSE);
+ case '(':
+ return _make_token(TK_PARENTHESIS_OPEN);
+ case ')':
+ return _make_token(TK_PARENTHESIS_CLOSE);
+ case ',':
+ return _make_token(TK_COMMA);
+ case ';':
+ return _make_token(TK_SEMICOLON);
+ case '?':
+ return _make_token(TK_QUESTION);
+ case ':':
+ return _make_token(TK_COLON);
+ case '^':
+ return _make_token(TK_OP_BIT_XOR);
+ case '~':
+ return _make_token(TK_OP_BIT_INVERT);
+ case '&': {
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_BIT_AND);
+ } else if (GETCHAR(0) == '&') {
+ char_idx++;
+ return _make_token(TK_OP_AND);
+ }
+ return _make_token(TK_OP_BIT_AND);
+ } break;
+ case '|': {
+
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_BIT_OR);
+ } else if (GETCHAR(0) == '|') {
+ char_idx++;
+ return _make_token(TK_OP_OR);
+ }
+ return _make_token(TK_OP_BIT_OR);
+
+ } break;
+ case '*': {
+
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_MUL);
+ }
+ return _make_token(TK_OP_MUL);
+ } break;
+ case '+': {
+
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_ADD);
+ } else if (GETCHAR(0) == '+') {
+
+ char_idx++;
+ return _make_token(TK_OP_INCREMENT);
+ }
+
+ return _make_token(TK_OP_ADD);
+ } break;
+ case '-': {
+
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_SUB);
+ } else if (GETCHAR(0) == '-') {
+
+ char_idx++;
+ return _make_token(TK_OP_DECREMENT);
+ }
+
+ return _make_token(TK_OP_SUB);
+ } break;
+ case '%': {
+
+ if (GETCHAR(0) == '=') {
+ char_idx++;
+ return _make_token(TK_OP_ASSIGN_MOD);
+ }
+
+ return _make_token(TK_OP_MOD);
+ } break;
+ default: {
+
+ char_idx--; //go back one, since we have no idea what this is
+
+ if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
+ // parse number
+ bool period_found = false;
+ bool exponent_found = false;
+ bool hexa_found = false;
+ bool sign_found = false;
+ bool float_suffix_found = false;
+
+ String str;
+ int i = 0;
+
+ while (true) {
+ if (GETCHAR(i) == '.') {
+ if (period_found || exponent_found || hexa_found || float_suffix_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ period_found = true;
+ } else if (GETCHAR(i) == 'x') {
+ if (hexa_found || str.length() != 1 || str[0] != '0')
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ hexa_found = true;
+ } else if (GETCHAR(i) == 'e') {
+ if (hexa_found || 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)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ float_suffix_found = true;
+ } else if (_is_number(GETCHAR(i))) {
+ if (float_suffix_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ } else if (hexa_found && _is_hex(GETCHAR(i))) {
+
+ } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
+ if (sign_found)
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ sign_found = true;
+ } else
+ break;
+
+ str += CharType(GETCHAR(i));
+ i++;
+ }
+
+ CharType last_char = str[str.length() - 1];
+
+ if (hexa_found) {
+ //integer(hex)
+ if (str.size() > 11 || !str.is_valid_hex_number(true)) { // > 0xFFFFFFFF
+ return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
+ }
+ } else if (period_found || exponent_found || float_suffix_found) {
+ //floats
+ if (period_found) {
+ if (float_suffix_found) {
+ //checks for eg "1.f" or "1.99f" notations
+ if (last_char != 'f') {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ } else {
+ //checks for eg. "1." or "1.99" notations
+ if (last_char != '.' && !_is_number(last_char)) {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ }
+ } else if (float_suffix_found) {
+ // if no period found the float suffix must be the last character, like in "2f" for "2.0"
+ if (last_char != 'f') {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ }
+
+ if (float_suffix_found) {
+ //strip the suffix
+ str = str.left(str.length() - 1);
+ //compensate reading cursor position
+ char_idx += 1;
+ }
+
+ if (!str.is_valid_float()) {
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
+ }
+ } else {
+ //integers
+ if (!_is_number(last_char)) {
+ return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
+ }
+ if (!str.is_valid_integer()) {
+ return _make_token(TK_ERROR, "Invalid numeric constant");
+ }
+ }
+
+ char_idx += str.length();
+ Token tk;
+ if (period_found || exponent_found || float_suffix_found)
+ tk.type = TK_REAL_CONSTANT;
+ else
+ tk.type = TK_INT_CONSTANT;
+
+ if (hexa_found) {
+ tk.constant = (double)str.hex_to_int64(true);
+ } else {
+ tk.constant = str.to_double();
+ }
+ tk.line = tk_line;
+
+ return tk;
+ }
+
+ if (GETCHAR(0) == '.') {
+ //parse period
+ char_idx++;
+ return _make_token(TK_PERIOD);
+ }
+
+ if (_is_text_char(GETCHAR(0))) {
+ // parse identifier
+ String str;
+
+ while (_is_text_char(GETCHAR(0))) {
+
+ str += CharType(GETCHAR(0));
+ char_idx++;
+ }
+
+ //see if keyword
+ //should be converted to a static map
+ int idx = 0;
+
+ while (keyword_list[idx].text) {
+
+ if (str == keyword_list[idx].text) {
+
+ return _make_token(keyword_list[idx].token);
+ }
+ idx++;
+ }
+
+ str = str.replace("dus_", "_");
+
+ return _make_token(TK_IDENTIFIER, str);
+ }
+
+ if (GETCHAR(0) > 32)
+ return _make_token(TK_ERROR, "Tokenizer: Unknown character #" + itos(GETCHAR(0)) + ": '" + String::chr(GETCHAR(0)) + "'");
+ else
+ return _make_token(TK_ERROR, "Tokenizer: Unknown character #" + itos(GETCHAR(0)));
+
+ } break;
+ }
+ }
+ ERR_PRINT("BUG");
+ return Token();
+
+#undef GETCHAR
+}
+
+String ShaderLanguage::token_debug(const String &p_code) {
+
+ clear();
+
+ code = p_code;
+
+ String output;
+
+ Token tk = _get_token();
+ while (tk.type != TK_EOF && tk.type != TK_ERROR) {
+
+ output += itos(tk_line) + ": " + get_token_text(tk) + "\n";
+ tk = _get_token();
+ }
+
+ return output;
+}
+
+bool ShaderLanguage::is_token_variable_datatype(TokenType p_type) {
+ return (
+ p_type == TK_TYPE_VOID ||
+ p_type == TK_TYPE_BOOL ||
+ p_type == TK_TYPE_BVEC2 ||
+ p_type == TK_TYPE_BVEC3 ||
+ p_type == TK_TYPE_BVEC4 ||
+ p_type == TK_TYPE_INT ||
+ p_type == TK_TYPE_IVEC2 ||
+ p_type == TK_TYPE_IVEC3 ||
+ p_type == TK_TYPE_IVEC4 ||
+ p_type == TK_TYPE_UINT ||
+ p_type == TK_TYPE_UVEC2 ||
+ p_type == TK_TYPE_UVEC3 ||
+ p_type == TK_TYPE_UVEC4 ||
+ p_type == TK_TYPE_FLOAT ||
+ p_type == TK_TYPE_VEC2 ||
+ p_type == TK_TYPE_VEC3 ||
+ p_type == TK_TYPE_VEC4 ||
+ p_type == TK_TYPE_MAT2 ||
+ p_type == TK_TYPE_MAT3 ||
+ p_type == TK_TYPE_MAT4);
+}
+
+bool ShaderLanguage::is_token_datatype(TokenType p_type) {
+
+ return (
+ p_type == TK_TYPE_VOID ||
+ p_type == TK_TYPE_BOOL ||
+ p_type == TK_TYPE_BVEC2 ||
+ p_type == TK_TYPE_BVEC3 ||
+ p_type == TK_TYPE_BVEC4 ||
+ p_type == TK_TYPE_INT ||
+ p_type == TK_TYPE_IVEC2 ||
+ p_type == TK_TYPE_IVEC3 ||
+ p_type == TK_TYPE_IVEC4 ||
+ p_type == TK_TYPE_UINT ||
+ p_type == TK_TYPE_UVEC2 ||
+ p_type == TK_TYPE_UVEC3 ||
+ p_type == TK_TYPE_UVEC4 ||
+ p_type == TK_TYPE_FLOAT ||
+ p_type == TK_TYPE_VEC2 ||
+ p_type == TK_TYPE_VEC3 ||
+ p_type == TK_TYPE_VEC4 ||
+ p_type == TK_TYPE_MAT2 ||
+ p_type == TK_TYPE_MAT3 ||
+ p_type == TK_TYPE_MAT4 ||
+ p_type == TK_TYPE_SAMPLER2D ||
+ p_type == TK_TYPE_ISAMPLER2D ||
+ p_type == TK_TYPE_USAMPLER2D ||
+ p_type == TK_TYPE_SAMPLER2DARRAY ||
+ p_type == TK_TYPE_ISAMPLER2DARRAY ||
+ p_type == TK_TYPE_USAMPLER2DARRAY ||
+ p_type == TK_TYPE_SAMPLER3D ||
+ p_type == TK_TYPE_ISAMPLER3D ||
+ p_type == TK_TYPE_USAMPLER3D ||
+ p_type == TK_TYPE_SAMPLERCUBE);
+}
+
+ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) {
+
+ return DataType(p_type - TK_TYPE_VOID);
+}
+
+bool ShaderLanguage::is_token_interpolation(TokenType p_type) {
+
+ return (
+ p_type == TK_INTERPOLATION_FLAT ||
+ p_type == TK_INTERPOLATION_SMOOTH);
+}
+
+ShaderLanguage::DataInterpolation ShaderLanguage::get_token_interpolation(TokenType p_type) {
+
+ if (p_type == TK_INTERPOLATION_FLAT)
+ return INTERPOLATION_FLAT;
+ else
+ return INTERPOLATION_SMOOTH;
+}
+
+bool ShaderLanguage::is_token_precision(TokenType p_type) {
+
+ return (
+ p_type == TK_PRECISION_LOW ||
+ p_type == TK_PRECISION_MID ||
+ p_type == TK_PRECISION_HIGH);
+}
+
+ShaderLanguage::DataPrecision ShaderLanguage::get_token_precision(TokenType p_type) {
+
+ if (p_type == TK_PRECISION_LOW)
+ return PRECISION_LOWP;
+ else if (p_type == TK_PRECISION_HIGH)
+ return PRECISION_HIGHP;
+ else
+ return PRECISION_MEDIUMP;
+}
+
+String ShaderLanguage::get_precision_name(DataPrecision p_type) {
+ switch (p_type) {
+ case PRECISION_LOWP: return "lowp";
+ case PRECISION_MEDIUMP: return "mediump";
+ case PRECISION_HIGHP: return "highp";
+ default:
+ break;
+ }
+ return "";
+}
+
+String ShaderLanguage::get_datatype_name(DataType p_type) {
+
+ switch (p_type) {
+
+ case TYPE_VOID: return "void";
+ case TYPE_BOOL: return "bool";
+ case TYPE_BVEC2: return "bvec2";
+ case TYPE_BVEC3: return "bvec3";
+ case TYPE_BVEC4: return "bvec4";
+ case TYPE_INT: return "int";
+ case TYPE_IVEC2: return "ivec2";
+ case TYPE_IVEC3: return "ivec3";
+ case TYPE_IVEC4: return "ivec4";
+ case TYPE_UINT: return "uint";
+ case TYPE_UVEC2: return "uvec2";
+ case TYPE_UVEC3: return "uvec3";
+ case TYPE_UVEC4: return "uvec4";
+ case TYPE_FLOAT: return "float";
+ case TYPE_VEC2: return "vec2";
+ case TYPE_VEC3: return "vec3";
+ case TYPE_VEC4: return "vec4";
+ case TYPE_MAT2: return "mat2";
+ case TYPE_MAT3: return "mat3";
+ case TYPE_MAT4: return "mat4";
+ case TYPE_SAMPLER2D: return "sampler2D";
+ case TYPE_ISAMPLER2D: return "isampler2D";
+ case TYPE_USAMPLER2D: return "usampler2D";
+ case TYPE_SAMPLER2DARRAY: return "sampler2DArray";
+ case TYPE_ISAMPLER2DARRAY: return "isampler2DArray";
+ case TYPE_USAMPLER2DARRAY: return "usampler2DArray";
+ case TYPE_SAMPLER3D: return "sampler3D";
+ case TYPE_ISAMPLER3D: return "isampler3D";
+ case TYPE_USAMPLER3D: return "usampler3D";
+ case TYPE_SAMPLERCUBE: return "samplerCube";
+ case TYPE_STRUCT: return "struct";
+ }
+
+ return "";
+}
+
+bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
+
+ return is_token_datatype(p_type) && p_type != TK_TYPE_VOID;
+}
+
+void ShaderLanguage::clear() {
+
+ current_function = StringName();
+
+ completion_type = COMPLETION_NONE;
+ completion_block = nullptr;
+ completion_function = StringName();
+ completion_class = SubClassTag::TAG_GLOBAL;
+ completion_struct = StringName();
+
+ error_line = 0;
+ tk_line = 1;
+ char_idx = 0;
+ error_set = false;
+ error_str = "";
+ while (nodes) {
+ Node *n = nodes;
+ nodes = nodes->next;
+ memdelete(n);
+ }
+}
+
+bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
+
+ if (p_builtin_types.has(p_identifier)) {
+
+ if (r_data_type) {
+ *r_data_type = p_builtin_types[p_identifier].type;
+ }
+ if (r_is_const) {
+ *r_is_const = p_builtin_types[p_identifier].constant;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_BUILTIN_VAR;
+ }
+
+ return true;
+ }
+
+ FunctionNode *function = nullptr;
+
+ while (p_block) {
+
+ if (p_block->variables.has(p_identifier)) {
+ if (r_data_type) {
+ *r_data_type = p_block->variables[p_identifier].type;
+ }
+ if (r_is_const) {
+ *r_is_const = p_block->variables[p_identifier].is_const;
+ }
+ if (r_array_size) {
+ *r_array_size = p_block->variables[p_identifier].array_size;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_LOCAL_VAR;
+ }
+ if (r_struct_name) {
+ *r_struct_name = p_block->variables[p_identifier].struct_name;
+ }
+
+ return true;
+ }
+
+ if (p_block->parent_function) {
+ function = p_block->parent_function;
+ break;
+ } else {
+ if (p_allow_reassign) {
+ break;
+ }
+ ERR_FAIL_COND_V(!p_block->parent_block, false);
+ p_block = p_block->parent_block;
+ }
+ }
+
+ if (function) {
+ for (int i = 0; i < function->arguments.size(); i++) {
+ if (function->arguments[i].name == p_identifier) {
+ if (r_data_type) {
+ *r_data_type = function->arguments[i].type;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_FUNCTION_ARGUMENT;
+ }
+ if (r_struct_name) {
+ *r_struct_name = function->arguments[i].type_str;
+ }
+ return true;
+ }
+ }
+ }
+
+ if (shader->varyings.has(p_identifier)) {
+ if (r_data_type) {
+ *r_data_type = shader->varyings[p_identifier].type;
+ }
+ if (r_array_size) {
+ *r_array_size = shader->varyings[p_identifier].array_size;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_VARYING;
+ }
+ return true;
+ }
+
+ if (shader->uniforms.has(p_identifier)) {
+ if (r_data_type) {
+ *r_data_type = shader->uniforms[p_identifier].type;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_UNIFORM;
+ }
+ return true;
+ }
+
+ if (shader->constants.has(p_identifier)) {
+ if (r_data_type) {
+ *r_data_type = shader->constants[p_identifier].type;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_CONSTANT;
+ }
+ if (r_struct_name) {
+ *r_struct_name = shader->constants[p_identifier].type_str;
+ }
+ return true;
+ }
+
+ for (int i = 0; i < shader->functions.size(); i++) {
+
+ if (!shader->functions[i].callable)
+ continue;
+
+ if (shader->functions[i].name == p_identifier) {
+ if (r_data_type) {
+ *r_data_type = shader->functions[i].function->return_type;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_FUNCTION;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type) {
+
+ bool valid = false;
+ DataType ret_type = TYPE_VOID;
+
+ switch (p_op->op) {
+ case OP_EQUAL:
+ case OP_NOT_EQUAL: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+ valid = na == nb;
+ ret_type = TYPE_BOOL;
+ } break;
+ case OP_LESS:
+ case OP_LESS_EQUAL:
+ case OP_GREATER:
+ case OP_GREATER_EQUAL: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ valid = na == nb && (na == TYPE_UINT || na == TYPE_INT || na == TYPE_FLOAT);
+ ret_type = TYPE_BOOL;
+
+ } break;
+ case OP_AND:
+ case OP_OR: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ valid = na == nb && na == TYPE_BOOL;
+ ret_type = TYPE_BOOL;
+
+ } break;
+ case OP_NOT: {
+
+ DataType na = p_op->arguments[0]->get_datatype();
+ valid = na == TYPE_BOOL;
+ ret_type = TYPE_BOOL;
+
+ } break;
+ case OP_INCREMENT:
+ case OP_DECREMENT:
+ case OP_POST_INCREMENT:
+ case OP_POST_DECREMENT:
+ case OP_NEGATE: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ valid = na > TYPE_BOOL && na < TYPE_MAT2;
+ ret_type = na;
+ } break;
+ case OP_ADD:
+ case OP_SUB:
+ case OP_MUL:
+ case OP_DIV: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ if (na > nb) {
+ //make things easier;
+ SWAP(na, nb);
+ }
+
+ if (na == nb) {
+ valid = (na > TYPE_BOOL && na <= TYPE_MAT4);
+ ret_type = na;
+ } else if (na == TYPE_INT && nb == TYPE_IVEC2) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_INT && nb == TYPE_IVEC3) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_INT && nb == TYPE_IVEC4) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ } else if (na == TYPE_UINT && nb == TYPE_UVEC2) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UINT && nb == TYPE_UVEC3) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UINT && nb == TYPE_UVEC4) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ } else if (na == TYPE_FLOAT && nb == TYPE_VEC2) {
+ valid = true;
+ ret_type = TYPE_VEC2;
+ } else if (na == TYPE_FLOAT && nb == TYPE_VEC3) {
+ valid = true;
+ ret_type = TYPE_VEC3;
+ } else if (na == TYPE_FLOAT && nb == TYPE_VEC4) {
+ valid = true;
+ ret_type = TYPE_VEC4;
+ } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT2) {
+ valid = true;
+ ret_type = TYPE_MAT2;
+ } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT3) {
+ valid = true;
+ ret_type = TYPE_MAT3;
+ } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT4) {
+ valid = true;
+ ret_type = TYPE_MAT4;
+ } else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
+ valid = true;
+ ret_type = TYPE_VEC2;
+ } else if (p_op->op == OP_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) {
+ valid = true;
+ ret_type = TYPE_VEC3;
+ } else if (p_op->op == OP_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) {
+ valid = true;
+ ret_type = TYPE_VEC4;
+ }
+ } break;
+ case OP_ASSIGN_MOD:
+ case OP_MOD: {
+ /*
+ * The operator modulus (%) operates on signed or unsigned integers or integer vectors. The operand
+ * types must both be signed or both be unsigned. The operands cannot be vectors of differing size. If
+ * one operand is a scalar and the other vector, then the scalar is applied component-wise to the vector,
+ * resulting in the same type as the vector. If both are vectors of the same size, the result is computed
+ * component-wise.
+ */
+
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ if (na == TYPE_INT && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_INT;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_IVEC2) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_IVEC3) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ /////
+ } else if (na == TYPE_UINT && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UINT;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ }
+ } break;
+ case OP_ASSIGN_SHIFT_LEFT:
+ case OP_ASSIGN_SHIFT_RIGHT:
+ case OP_SHIFT_LEFT:
+ case OP_SHIFT_RIGHT: {
+
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ if (na == TYPE_INT && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_INT;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_IVEC2) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_IVEC3) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ } else if (na == TYPE_UINT && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UINT;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ }
+ } break;
+ case OP_ASSIGN: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+ if (na == TYPE_STRUCT || nb == TYPE_STRUCT) {
+ valid = p_op->arguments[0]->get_datatype_name() == p_op->arguments[1]->get_datatype_name();
+ } else {
+ valid = na == nb;
+ }
+ ret_type = na;
+ } break;
+ case OP_ASSIGN_ADD:
+ case OP_ASSIGN_SUB:
+ case OP_ASSIGN_MUL:
+ case OP_ASSIGN_DIV: {
+
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ if (na == nb) {
+ valid = (na > TYPE_BOOL && na < TYPE_MAT2) || (p_op->op == OP_ASSIGN_MUL && na >= TYPE_MAT2 && na <= TYPE_MAT4);
+ ret_type = na;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ } else if (na == TYPE_VEC2 && nb == TYPE_FLOAT) {
+ valid = true;
+ ret_type = TYPE_VEC2;
+ } else if (na == TYPE_VEC3 && nb == TYPE_FLOAT) {
+ valid = true;
+ ret_type = TYPE_VEC3;
+ } else if (na == TYPE_VEC4 && nb == TYPE_FLOAT) {
+ valid = true;
+ ret_type = TYPE_VEC4;
+ } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT2 && nb == TYPE_VEC2) {
+ valid = true;
+ ret_type = TYPE_MAT2;
+ } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT3 && nb == TYPE_VEC3) {
+ valid = true;
+ ret_type = TYPE_MAT3;
+ } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT4 && nb == TYPE_VEC4) {
+ valid = true;
+ ret_type = TYPE_MAT4;
+ } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
+ valid = true;
+ ret_type = TYPE_VEC2;
+ } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) {
+ valid = true;
+ ret_type = TYPE_VEC3;
+ } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) {
+ valid = true;
+ ret_type = TYPE_VEC4;
+ }
+ } break;
+ case OP_ASSIGN_BIT_AND:
+ case OP_ASSIGN_BIT_OR:
+ case OP_ASSIGN_BIT_XOR:
+ case OP_BIT_AND:
+ case OP_BIT_OR:
+ case OP_BIT_XOR: {
+
+ /*
+ * The bitwise operators and (&), exclusive-or (^), and inclusive-or (|). The operands must be of type
+ * signed or unsigned integers or integer vectors. The operands cannot be vectors of differing size. If
+ * one operand is a scalar and the other a vector, the scalar is applied component-wise to the vector,
+ * resulting in the same type as the vector. The fundamental types of the operands (signed or unsigned)
+ * must match.
+ */
+
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+
+ if (na > nb && p_op->op >= OP_BIT_AND) {
+ //can swap for non assign
+ SWAP(na, nb);
+ }
+
+ if (na == TYPE_INT && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_INT;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ } else if (na == TYPE_IVEC2 && nb == TYPE_IVEC2) {
+ valid = true;
+ ret_type = TYPE_IVEC2;
+ } else if (na == TYPE_IVEC3 && nb == TYPE_IVEC3) {
+ valid = true;
+ ret_type = TYPE_IVEC3;
+ } else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
+ valid = true;
+ ret_type = TYPE_IVEC4;
+ /////
+ } else if (na == TYPE_UINT && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UINT;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ } else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
+ valid = true;
+ ret_type = TYPE_UVEC2;
+ } else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
+ valid = true;
+ ret_type = TYPE_UVEC3;
+ } else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
+ valid = true;
+ ret_type = TYPE_UVEC4;
+ }
+ } break;
+ case OP_BIT_INVERT: { //unaries
+ DataType na = p_op->arguments[0]->get_datatype();
+ valid = na >= TYPE_INT && na < TYPE_FLOAT;
+ ret_type = na;
+ } break;
+ case OP_SELECT_IF: {
+ DataType na = p_op->arguments[0]->get_datatype();
+ DataType nb = p_op->arguments[1]->get_datatype();
+ DataType nc = p_op->arguments[2]->get_datatype();
+
+ valid = na == TYPE_BOOL && (nb == nc);
+ ret_type = nb;
+ } break;
+ default: {
+ ERR_FAIL_V(false);
+ }
+ }
+
+ if (r_ret_type)
+ *r_ret_type = ret_type;
+ return valid;
+}
+
+const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
+ //constructors
+ { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC3, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "mat2", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "mat2", TYPE_MAT2, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ //conversion scalars
+
+ { "int", TYPE_INT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "int", TYPE_INT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "int", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "float", TYPE_FLOAT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "float", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "float", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "uint", TYPE_UINT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uint", TYPE_UINT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bool", TYPE_BOOL, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bool", TYPE_BOOL, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "bool", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ //conversion vectors
+
+ { "ivec2", TYPE_IVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec2", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "vec2", TYPE_VEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec2", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "vec2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "uvec2", TYPE_UVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec2", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "bvec2", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec2", TYPE_BVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "bvec2", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "ivec3", TYPE_IVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec3", TYPE_IVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "ivec3", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "vec3", TYPE_VEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec3", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "vec3", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "uvec3", TYPE_UVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec3", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "bvec3", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec3", TYPE_BVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "bvec3", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "ivec4", TYPE_IVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ivec4", TYPE_IVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "ivec4", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "vec4", TYPE_VEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "vec4", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "vec4", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "uvec4", TYPE_UVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uvec4", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "bvec4", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ //conversion between matrixes
+
+ { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
+
+ //builtins - trigonometry
+
+ { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "radians", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "radians", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "radians", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "degrees", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "degrees", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "degrees", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "degrees", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "sin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "cos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "tan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "tan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "tan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "tan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "asin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "asin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "asin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "asin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "acos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "acos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "acos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "acos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "sinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "cosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "tanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "tanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "tanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "tanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "asinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "asinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "asinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "asinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "acosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "acosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "acosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "acosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "atanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "atanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ //builtins - exponential
+ { "pow", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "pow", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "pow", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "pow", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "exp2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "log2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "inversesqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ //builtins - common
+ { "abs", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "abs", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "abs", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "abs", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "abs", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "abs", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "abs", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "abs", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "sign", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sign", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sign", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sign", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "sign", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sign", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sign", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "sign", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "floor", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "floor", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "floor", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "floor", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "trunc", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "trunc", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "trunc", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "trunc", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "round", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "round", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "round", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "round", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "roundEven", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ceil", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ceil", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ceil", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "ceil", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "fract", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "fract", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "fract", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "fract", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "mod", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "modf", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "modf", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "modf", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "modf", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "min", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "min", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "min", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "max", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "max", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "max", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "clamp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "clamp", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "clamp", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "mix", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC2, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "step", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "smoothstep", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "isnan", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "isnan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "isnan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "isnan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "isinf", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "isinf", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "isinf", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "isinf", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "floatBitsToInt", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "floatBitsToInt", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "floatBitsToInt", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "floatBitsToInt", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "floatBitsToUint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "floatBitsToUint", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "floatBitsToUint", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "floatBitsToUint", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "intBitsToFloat", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "intBitsToFloat", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "intBitsToFloat", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "intBitsToFloat", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "uintBitsToFloat", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uintBitsToFloat", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uintBitsToFloat", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "uintBitsToFloat", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ //builtins - geometric
+ { "length", TYPE_FLOAT, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "length", TYPE_FLOAT, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "length", TYPE_FLOAT, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "distance", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "distance", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "distance", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "dot", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "dot", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "dot", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "cross", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "normalize", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "normalize", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "normalize", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+ { "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "faceforward", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "faceforward", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "faceforward", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "matrixCompMult", TYPE_MAT2, { TYPE_MAT2, TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "matrixCompMult", TYPE_MAT3, { TYPE_MAT3, TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "matrixCompMult", TYPE_MAT4, { TYPE_MAT4, TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "outerProduct", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "outerProduct", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "outerProduct", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "transpose", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "transpose", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "transpose", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "determinant", TYPE_FLOAT, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "determinant", TYPE_FLOAT, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "determinant", TYPE_FLOAT, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "inverse", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "inverse", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "inverse", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "lessThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "lessThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "lessThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "lessThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "lessThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "greaterThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "greaterThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "greaterThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "greaterThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "greaterThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "lessThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "lessThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "lessThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "lessThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "lessThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "lessThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "greaterThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "greaterThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "greaterThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "greaterThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "greaterThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "greaterThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "equal", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "equal", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "equal", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "equal", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "equal", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "equal", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "equal", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "notEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "notEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "notEqual", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "notEqual", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "any", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "any", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "any", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "all", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "all", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "all", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "not", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "not", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "not", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
+
+ //builtins - texture
+ { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
+ { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+ { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
+
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "dFdy", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
+ { "fwidth", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
+ { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
+ { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
+
+ //sub-functions
+
+ //array
+ { "length", TYPE_INT, { TYPE_VOID }, TAG_ARRAY, true },
+
+ { nullptr, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false }
+
+};
+
+const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = {
+ //constructors
+ { "modf", 1 },
+ { nullptr, 0 }
+};
+
+bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
+
+ ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
+
+ Vector<DataType> args;
+ Vector<StringName> args2;
+
+ ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::TYPE_VARIABLE, false);
+
+ StringName name = static_cast<VariableNode *>(p_func->arguments[0])->name.operator String();
+
+ for (int i = 1; i < p_func->arguments.size(); i++) {
+ args.push_back(p_func->arguments[i]->get_datatype());
+ args2.push_back(p_func->arguments[i]->get_datatype_name());
+ }
+
+ int argcount = args.size();
+
+ bool failed_builtin = false;
+ bool unsupported_builtin = false;
+ int builtin_idx = 0;
+
+ if (argcount <= 4) {
+ // test builtins
+ int idx = 0;
+
+ while (builtin_func_defs[idx].name) {
+
+ if (completion_class != builtin_func_defs[idx].tag) {
+ idx++;
+ continue;
+ }
+
+ if (name == builtin_func_defs[idx].name) {
+
+ failed_builtin = true;
+ bool fail = false;
+ for (int i = 0; i < argcount; i++) {
+
+ if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) {
+ //all good, but needs implicit conversion later
+ } else if (args[i] != builtin_func_defs[idx].args[i]) {
+ fail = true;
+ break;
+ }
+ }
+
+ if (!fail) {
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ if (builtin_func_defs[idx].high_end) {
+ fail = true;
+ unsupported_builtin = true;
+ builtin_idx = idx;
+ }
+ }
+ }
+
+ if (!fail && argcount < 4 && builtin_func_defs[idx].args[argcount] != TYPE_VOID)
+ fail = true; //make sure the number of arguments matches
+
+ if (!fail) {
+
+ //make sure its not an out argument used in the wrong way
+ int outarg_idx = 0;
+ while (builtin_func_out_args[outarg_idx].name) {
+
+ if (String(name) == builtin_func_out_args[outarg_idx].name) {
+ int arg_idx = builtin_func_out_args[outarg_idx].argument;
+
+ if (arg_idx < argcount) {
+
+ if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) {
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member.");
+ return false;
+ }
+
+ if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) {
+ ArrayNode *mn = static_cast<ArrayNode *>(p_func->arguments[arg_idx + 1]);
+ if (mn->is_const) {
+ fail = true;
+ }
+ } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) {
+ MemberNode *mn = static_cast<MemberNode *>(p_func->arguments[arg_idx + 1]);
+ if (mn->basetype_const) {
+ fail = true;
+ }
+ } else { // TYPE_VARIABLE
+ VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg_idx + 1]);
+ if (vn->is_const) {
+ fail = true;
+ } else {
+ StringName varname = vn->name;
+ if (shader->uniforms.has(varname)) {
+ fail = true;
+ } else {
+ if (p_builtin_types.has(varname)) {
+ BuiltInInfo info = p_builtin_types[varname];
+ if (info.constant) {
+ fail = true;
+ }
+ }
+ }
+ }
+ }
+ if (fail) {
+ _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out"));
+ return false;
+ }
+
+ StringName var_name;
+ if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) {
+ var_name = static_cast<const ArrayNode *>(p_func->arguments[arg_idx + 1])->name;
+ } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) {
+ Node *n = static_cast<const MemberNode *>(p_func->arguments[arg_idx + 1])->owner;
+ while (n->type == Node::TYPE_MEMBER) {
+ n = static_cast<const MemberNode *>(n)->owner;
+ }
+ if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) {
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member.");
+ return false;
+ }
+ if (n->type == Node::TYPE_VARIABLE) {
+ var_name = static_cast<const VariableNode *>(n)->name;
+ } else { // TYPE_ARRAY
+ var_name = static_cast<const ArrayNode *>(n)->name;
+ }
+ } else { // TYPE_VARIABLE
+ var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name;
+ }
+ const BlockNode *b = p_block;
+ bool valid = false;
+ while (b) {
+ if (b->variables.has(var_name) || p_builtin_types.has(var_name)) {
+ valid = true;
+ break;
+ }
+ if (b->parent_function) {
+ for (int i = 0; i < b->parent_function->arguments.size(); i++) {
+ if (b->parent_function->arguments[i].name == var_name) {
+ valid = true;
+ break;
+ }
+ }
+ }
+ b = b->parent_block;
+ }
+
+ if (!valid) {
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member.");
+ return false;
+ }
+ }
+ }
+
+ outarg_idx++;
+ }
+ //implicitly convert values if possible
+ for (int i = 0; i < argcount; i++) {
+
+ if (get_scalar_type(args[i]) != args[i] || args[i] == builtin_func_defs[idx].args[i] || p_func->arguments[i + 1]->type != Node::TYPE_CONSTANT) {
+ //can't do implicit conversion here
+ continue;
+ }
+
+ //this is an implicit conversion
+ ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[i + 1]);
+ ConstantNode *conversion = alloc_node<ConstantNode>();
+
+ conversion->datatype = builtin_func_defs[idx].args[i];
+ conversion->values.resize(1);
+
+ convert_constant(constant, builtin_func_defs[idx].args[i], conversion->values.ptrw());
+ p_func->arguments.write[i + 1] = conversion;
+ }
+
+ if (r_ret_type)
+ *r_ret_type = builtin_func_defs[idx].rettype;
+
+ return true;
+ }
+ }
+
+ idx++;
+ }
+ }
+
+ if (unsupported_builtin) {
+
+ String arglist = "";
+ for (int i = 0; i < argcount; i++) {
+ if (i > 0) {
+ arglist += ", ";
+ }
+ arglist += get_datatype_name(builtin_func_defs[builtin_idx].args[i]);
+ }
+
+ String err = "Built-in function \"" + String(name) + "(" + arglist + ")\" is supported only on high-end platform!";
+ _set_error(err);
+ return false;
+ }
+
+ if (failed_builtin) {
+ String err = "Invalid arguments for built-in function: " + String(name) + "(";
+ for (int i = 0; i < argcount; i++) {
+ if (i > 0)
+ err += ",";
+
+ if (p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && p_func->arguments[i + 1]->get_datatype() == TYPE_INT && static_cast<ConstantNode *>(p_func->arguments[i + 1])->values[0].sint < 0) {
+ err += "-";
+ }
+ err += get_datatype_name(args[i]);
+ }
+ err += ")";
+ _set_error(err);
+ return false;
+ }
+
+ // try existing functions..
+
+ StringName exclude_function;
+ BlockNode *block = p_block;
+
+ while (block) {
+
+ if (block->parent_function) {
+ exclude_function = block->parent_function->name;
+ }
+ block = block->parent_block;
+ }
+
+ if (name == exclude_function) {
+ _set_error("Recursion is not allowed");
+ return false;
+ }
+
+ for (int i = 0; i < shader->functions.size(); i++) {
+
+ if (name != shader->functions[i].name)
+ continue;
+
+ if (!shader->functions[i].callable) {
+ _set_error("Function '" + String(name) + " can't be called from source code.");
+ return false;
+ }
+
+ FunctionNode *pfunc = shader->functions[i].function;
+
+ if (pfunc->arguments.size() != args.size())
+ continue;
+
+ bool fail = false;
+
+ for (int j = 0; j < args.size(); j++) {
+ if (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) {
+ fail = true;
+ break;
+ }
+ if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
+ //all good, but it needs implicit conversion later
+ } else if (args[j] != pfunc->arguments[j].type) {
+ fail = true;
+ break;
+ }
+ }
+
+ if (!fail) {
+
+ //implicitly convert values if possible
+ for (int k = 0; k < args.size(); k++) {
+
+ if (get_scalar_type(args[k]) != args[k] || args[k] == pfunc->arguments[k].type || p_func->arguments[k + 1]->type != Node::TYPE_CONSTANT) {
+ //can't do implicit conversion here
+ continue;
+ }
+
+ //this is an implicit conversion
+ ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[k + 1]);
+ ConstantNode *conversion = alloc_node<ConstantNode>();
+
+ conversion->datatype = pfunc->arguments[k].type;
+ conversion->values.resize(1);
+
+ convert_constant(constant, pfunc->arguments[k].type, conversion->values.ptrw());
+ p_func->arguments.write[k + 1] = conversion;
+ }
+
+ if (r_ret_type) {
+ *r_ret_type = pfunc->return_type;
+ if (pfunc->return_type == TYPE_STRUCT) {
+ *r_ret_type_str = pfunc->return_struct_name;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
+ if (a->get_datatype() != b->get_datatype()) {
+ return false;
+ }
+ if (a->get_datatype() == TYPE_STRUCT || b->get_datatype() == TYPE_STRUCT) {
+ if (a->get_datatype_name() != b->get_datatype_name()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) {
+
+ TkPos pos = _get_tkpos();
+ Token tk = _get_token();
+
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ return true;
+ }
+
+ _set_tkpos(pos);
+
+ while (true) {
+
+ if (r_complete_arg) {
+ pos = _get_tkpos();
+ tk = _get_token();
+
+ if (tk.type == TK_CURSOR) {
+
+ *r_complete_arg = p_func->arguments.size() - 1;
+ } else {
+
+ _set_tkpos(pos);
+ }
+ }
+
+ Node *arg = _parse_and_reduce_expression(p_block, p_builtin_types);
+
+ if (!arg) {
+
+ return false;
+ }
+
+ p_func->arguments.push_back(arg);
+
+ tk = _get_token();
+
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+
+ return true;
+ } else if (tk.type != TK_COMMA) {
+ // something is broken
+ _set_error("Expected ',' or ')' after argument");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ShaderLanguage::is_token_operator(TokenType p_type) {
+
+ return (p_type == TK_OP_EQUAL ||
+ p_type == TK_OP_NOT_EQUAL ||
+ p_type == TK_OP_LESS ||
+ p_type == TK_OP_LESS_EQUAL ||
+ p_type == TK_OP_GREATER ||
+ p_type == TK_OP_GREATER_EQUAL ||
+ p_type == TK_OP_AND ||
+ p_type == TK_OP_OR ||
+ p_type == TK_OP_NOT ||
+ p_type == TK_OP_ADD ||
+ p_type == TK_OP_SUB ||
+ p_type == TK_OP_MUL ||
+ p_type == TK_OP_DIV ||
+ p_type == TK_OP_MOD ||
+ p_type == TK_OP_SHIFT_LEFT ||
+ p_type == TK_OP_SHIFT_RIGHT ||
+ p_type == TK_OP_ASSIGN ||
+ p_type == TK_OP_ASSIGN_ADD ||
+ p_type == TK_OP_ASSIGN_SUB ||
+ p_type == TK_OP_ASSIGN_MUL ||
+ p_type == TK_OP_ASSIGN_DIV ||
+ p_type == TK_OP_ASSIGN_MOD ||
+ p_type == TK_OP_ASSIGN_SHIFT_LEFT ||
+ p_type == TK_OP_ASSIGN_SHIFT_RIGHT ||
+ p_type == TK_OP_ASSIGN_BIT_AND ||
+ p_type == TK_OP_ASSIGN_BIT_OR ||
+ p_type == TK_OP_ASSIGN_BIT_XOR ||
+ p_type == TK_OP_BIT_AND ||
+ p_type == TK_OP_BIT_OR ||
+ p_type == TK_OP_BIT_XOR ||
+ p_type == TK_OP_BIT_INVERT ||
+ p_type == TK_OP_INCREMENT ||
+ p_type == TK_OP_DECREMENT ||
+ p_type == TK_QUESTION ||
+ p_type == TK_COLON);
+}
+
+bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
+
+ if (p_constant->datatype == p_to_type) {
+ if (p_value) {
+ for (int i = 0; i < p_constant->values.size(); i++) {
+ p_value[i] = p_constant->values[i];
+ }
+ }
+ return true;
+ } else if (p_constant->datatype == TYPE_INT && p_to_type == TYPE_FLOAT) {
+
+ if (p_value) {
+ p_value->real = p_constant->values[0].sint;
+ }
+ return true;
+ } else if (p_constant->datatype == TYPE_UINT && p_to_type == TYPE_FLOAT) {
+
+ if (p_value) {
+ p_value->real = p_constant->values[0].uint;
+ }
+ return true;
+ } else if (p_constant->datatype == TYPE_INT && p_to_type == TYPE_UINT) {
+ if (p_constant->values[0].sint < 0) {
+ return false;
+ }
+ if (p_value) {
+ p_value->uint = p_constant->values[0].sint;
+ }
+ return true;
+ } else if (p_constant->datatype == TYPE_UINT && p_to_type == TYPE_INT) {
+
+ if (p_constant->values[0].uint > 0x7FFFFFFF) {
+ return false;
+ }
+ if (p_value) {
+ p_value->sint = p_constant->values[0].uint;
+ }
+ return true;
+ } else
+ return false;
+}
+
+bool ShaderLanguage::is_scalar_type(DataType p_type) {
+
+ return p_type == TYPE_BOOL || p_type == TYPE_INT || p_type == TYPE_UINT || p_type == TYPE_FLOAT;
+}
+
+bool ShaderLanguage::is_sampler_type(DataType p_type) {
+
+ return p_type == TYPE_SAMPLER2D ||
+ p_type == TYPE_ISAMPLER2D ||
+ p_type == TYPE_USAMPLER2D ||
+ p_type == TYPE_SAMPLER2DARRAY ||
+ p_type == TYPE_ISAMPLER2DARRAY ||
+ p_type == TYPE_USAMPLER2DARRAY ||
+ p_type == TYPE_SAMPLER3D ||
+ p_type == TYPE_ISAMPLER3D ||
+ p_type == TYPE_USAMPLER3D ||
+ p_type == TYPE_SAMPLERCUBE;
+}
+
+Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
+ if (p_value.size() > 0) {
+ Variant value;
+ switch (p_type) {
+ case ShaderLanguage::TYPE_BOOL:
+ value = Variant(p_value[0].boolean);
+ break;
+ case ShaderLanguage::TYPE_BVEC2:
+ case ShaderLanguage::TYPE_BVEC3:
+ case ShaderLanguage::TYPE_BVEC4:
+ case ShaderLanguage::TYPE_INT:
+ value = Variant(p_value[0].sint);
+ break;
+ case ShaderLanguage::TYPE_IVEC2:
+ value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
+ break;
+ case ShaderLanguage::TYPE_IVEC3:
+ value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
+ break;
+ case ShaderLanguage::TYPE_IVEC4:
+ value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
+ break;
+ case ShaderLanguage::TYPE_UINT:
+ value = Variant(p_value[0].uint);
+ break;
+ case ShaderLanguage::TYPE_UVEC2:
+ value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
+ break;
+ case ShaderLanguage::TYPE_UVEC3:
+ value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
+ break;
+ case ShaderLanguage::TYPE_UVEC4:
+ value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
+ break;
+ case ShaderLanguage::TYPE_FLOAT:
+ value = Variant(p_value[0].real);
+ break;
+ case ShaderLanguage::TYPE_VEC2:
+ value = Variant(Vector2(p_value[0].real, p_value[1].real));
+ break;
+ case ShaderLanguage::TYPE_VEC3:
+ value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ break;
+ case ShaderLanguage::TYPE_VEC4:
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ } else {
+ value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ }
+ break;
+ case ShaderLanguage::TYPE_MAT2:
+ value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0));
+ break;
+ case ShaderLanguage::TYPE_MAT3: {
+ Basis p;
+ p[0][0] = p_value[0].real;
+ p[0][1] = p_value[1].real;
+ p[0][2] = p_value[2].real;
+ p[1][0] = p_value[3].real;
+ p[1][1] = p_value[4].real;
+ p[1][2] = p_value[5].real;
+ p[2][0] = p_value[6].real;
+ p[2][1] = p_value[7].real;
+ p[2][2] = p_value[8].real;
+ value = Variant(p);
+ break;
+ }
+ case ShaderLanguage::TYPE_MAT4: {
+ Basis p;
+ p[0][0] = p_value[0].real;
+ p[0][1] = p_value[1].real;
+ p[0][2] = p_value[2].real;
+ p[1][0] = p_value[4].real;
+ p[1][1] = p_value[5].real;
+ p[1][2] = p_value[6].real;
+ p[2][0] = p_value[8].real;
+ p[2][1] = p_value[9].real;
+ p[2][2] = p_value[10].real;
+ Transform t = Transform(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
+ value = Variant(t);
+ break;
+ }
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_SAMPLER2D:
+ case ShaderLanguage::TYPE_SAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+ // Texture types, likely not relevant here.
+ break;
+ }
+ case ShaderLanguage::TYPE_STRUCT:
+ break;
+ case ShaderLanguage::TYPE_VOID:
+ break;
+ }
+ return value;
+ }
+ return Variant();
+}
+
+PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform &p_uniform) {
+ PropertyInfo pi;
+ switch (p_uniform.type) {
+ case ShaderLanguage::TYPE_VOID: pi.type = Variant::NIL; break;
+ case ShaderLanguage::TYPE_BOOL: pi.type = Variant::BOOL; break;
+ case ShaderLanguage::TYPE_BVEC2:
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y";
+ break;
+ case ShaderLanguage::TYPE_BVEC3:
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z";
+ break;
+ case ShaderLanguage::TYPE_BVEC4:
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z,w";
+ break;
+ case ShaderLanguage::TYPE_UINT:
+ case ShaderLanguage::TYPE_INT: {
+ pi.type = Variant::INT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_IVEC2:
+ case ShaderLanguage::TYPE_IVEC3:
+ case ShaderLanguage::TYPE_IVEC4:
+ case ShaderLanguage::TYPE_UVEC2:
+ case ShaderLanguage::TYPE_UVEC3:
+ case ShaderLanguage::TYPE_UVEC4: {
+
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ pi.type = Variant::FLOAT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
+
+ } break;
+ case ShaderLanguage::TYPE_VEC2: pi.type = Variant::VECTOR2; break;
+ case ShaderLanguage::TYPE_VEC3: pi.type = Variant::VECTOR3; break;
+ case ShaderLanguage::TYPE_VEC4: {
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.type = Variant::COLOR;
+ } else {
+ pi.type = Variant::PLANE;
+ }
+ } break;
+ case ShaderLanguage::TYPE_MAT2: pi.type = Variant::TRANSFORM2D; break;
+ case ShaderLanguage::TYPE_MAT3: pi.type = Variant::BASIS; break;
+ case ShaderLanguage::TYPE_MAT4: pi.type = Variant::TRANSFORM; break;
+ case ShaderLanguage::TYPE_SAMPLER2D:
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER2D: {
+
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Texture2D";
+ } break;
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY: {
+
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "TextureArray";
+ } break;
+ case ShaderLanguage::TYPE_SAMPLER3D:
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D: {
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Texture3D";
+ } break;
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "CubeMap";
+ } break;
+ case ShaderLanguage::TYPE_STRUCT: {
+ // FIXME: Implement this.
+ } break;
+ }
+ return pi;
+}
+
+uint32_t ShaderLanguage::get_type_size(DataType p_type) {
+ switch (p_type) {
+ case TYPE_VOID:
+ return 0;
+ case TYPE_BOOL:
+ case TYPE_INT:
+ case TYPE_UINT:
+ case TYPE_FLOAT:
+ return 4;
+ case TYPE_BVEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_VEC2:
+ return 8;
+ case TYPE_BVEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_VEC3:
+ return 12;
+ case TYPE_BVEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_VEC4:
+ return 16;
+ case TYPE_MAT2:
+ return 8;
+ case TYPE_MAT3:
+ return 12;
+ case TYPE_MAT4:
+ return 16;
+ case TYPE_SAMPLER2D:
+ case TYPE_ISAMPLER2D:
+ case TYPE_USAMPLER2D:
+ case TYPE_SAMPLER2DARRAY:
+ case TYPE_ISAMPLER2DARRAY:
+ case TYPE_USAMPLER2DARRAY:
+ case TYPE_SAMPLER3D:
+ case TYPE_ISAMPLER3D:
+ case TYPE_USAMPLER3D:
+ case TYPE_SAMPLERCUBE:
+ return 4; //not really, but useful for indices
+ case TYPE_STRUCT:
+ // FIXME: Implement.
+ return 0;
+ }
+ return 0;
+}
+
+void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
+
+ Set<String> kws;
+
+ int idx = 0;
+
+ while (keyword_list[idx].text) {
+
+ kws.insert(keyword_list[idx].text);
+ idx++;
+ }
+
+ idx = 0;
+
+ while (builtin_func_defs[idx].name) {
+
+ kws.insert(builtin_func_defs[idx].name);
+
+ idx++;
+ }
+
+ for (Set<String>::Element *E = kws.front(); E; E = E->next()) {
+ r_keywords->push_back(E->get());
+ }
+}
+
+void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) {
+
+ Set<String> kws;
+
+ int idx = 0;
+
+ while (builtin_func_defs[idx].name) {
+
+ kws.insert(builtin_func_defs[idx].name);
+
+ idx++;
+ }
+
+ for (Set<String>::Element *E = kws.front(); E; E = E->next()) {
+ r_keywords->push_back(E->get());
+ }
+}
+
+ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) {
+
+ static const DataType scalar_types[] = {
+ TYPE_VOID,
+ TYPE_BOOL,
+ TYPE_BOOL,
+ TYPE_BOOL,
+ TYPE_BOOL,
+ TYPE_INT,
+ TYPE_INT,
+ TYPE_INT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_UINT,
+ TYPE_UINT,
+ TYPE_UINT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_FLOAT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_FLOAT,
+ };
+
+ return scalar_types[p_type];
+}
+
+int ShaderLanguage::get_cardinality(DataType p_type) {
+ static const int cardinality_table[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 1,
+ 2,
+ 3,
+ 4,
+ 1,
+ 2,
+ 3,
+ 4,
+ 1,
+ 2,
+ 3,
+ 4,
+ 4,
+ 9,
+ 16,
+ 1,
+ 1,
+ 1,
+ 1,
+ };
+
+ return cardinality_table[p_type];
+}
+
+bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier) {
+
+ identifier = StringName();
+
+ TkPos pos = { 0, 0 };
+
+ Token tk = _get_token();
+
+ if (tk.type == TK_IDENTIFIER) {
+ identifier = tk.text;
+ pos = _get_tkpos();
+ tk = _get_token();
+ }
+
+ if (tk.type == TK_CURSOR) {
+
+ completion_type = p_type;
+ completion_line = tk_line;
+ completion_block = p_block;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+
+ if (tk.type == TK_IDENTIFIER) {
+ identifier = identifier.operator String() + tk.text.operator String();
+ } else {
+ _set_tkpos(pos);
+ }
+ return true;
+ } else if (identifier != StringName()) {
+ _set_tkpos(pos);
+ }
+
+ return false;
+}
+
+bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
+ switch (p_op) {
+ case OP_ASSIGN:
+ case OP_ASSIGN_ADD:
+ case OP_ASSIGN_SUB:
+ case OP_ASSIGN_MUL:
+ case OP_ASSIGN_DIV:
+ case OP_ASSIGN_MOD:
+ case OP_ASSIGN_SHIFT_LEFT:
+ case OP_ASSIGN_SHIFT_RIGHT:
+ case OP_ASSIGN_BIT_AND:
+ case OP_ASSIGN_BIT_OR:
+ case OP_ASSIGN_BIT_XOR:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
+
+ if (p_node->type == Node::TYPE_OPERATOR) {
+
+ OperatorNode *op = static_cast<OperatorNode *>(p_node);
+
+ if (op->op == OP_INDEX) {
+ return _validate_assign(op->arguments[0], p_builtin_types, r_message);
+
+ } else if (_is_operator_assign(op->op)) {
+ //chained assignment
+ return _validate_assign(op->arguments[1], p_builtin_types, r_message);
+
+ } else if (op->op == OP_CALL) {
+ if (r_message)
+ *r_message = RTR("Assignment to function.");
+ return false;
+ }
+
+ } else if (p_node->type == Node::TYPE_MEMBER) {
+
+ MemberNode *member = static_cast<MemberNode *>(p_node);
+
+ if (member->has_swizzling_duplicates) {
+ if (r_message)
+ *r_message = RTR("Swizzling assignment contains duplicates.");
+ return false;
+ }
+
+ return _validate_assign(member->owner, p_builtin_types, r_message);
+
+ } else if (p_node->type == Node::TYPE_VARIABLE) {
+
+ VariableNode *var = static_cast<VariableNode *>(p_node);
+
+ if (shader->uniforms.has(var->name)) {
+ if (r_message)
+ *r_message = RTR("Assignment to uniform.");
+ 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.");
+ return false;
+ }
+
+ if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) {
+ return true;
+ }
+ } else if (p_node->type == Node::TYPE_ARRAY) {
+
+ ArrayNode *arr = static_cast<ArrayNode *>(p_node);
+
+ if (arr->is_const) {
+ if (r_message)
+ *r_message = RTR("Constants cannot be modified.");
+ 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;
+ }
+
+ if (r_message)
+ *r_message = "Assignment to constant expression.";
+ return false;
+}
+
+bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
+ for (int i = 0; shader->functions.size(); i++) {
+ if (shader->functions[i].name == p_name) {
+
+ ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
+ FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+ if (arg->tex_builtin_check) {
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+ return false;
+ } else if (arg->tex_argument_check) {
+ //was checked, verify that filter and repeat are the same
+ if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) {
+ return true;
+ } else {
+
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using textures that differ in either filter or repeat setting.");
+ return false;
+ }
+ } else {
+
+ arg->tex_argument_check = true;
+ arg->tex_argument_filter = p_filter;
+ arg->tex_argument_repeat = p_repeat;
+ for (Map<StringName, Set<int>>::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
+ for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
+ if (!_propagate_function_call_sampler_uniform_settings(E->key(), F->get(), p_filter, p_repeat)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ ERR_FAIL_V(false); //bug? function not found
+}
+bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) {
+ for (int i = 0; shader->functions.size(); i++) {
+ if (shader->functions[i].name == p_name) {
+
+ ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
+ FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
+ if (arg->tex_argument_check) {
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
+ return false;
+ } else if (arg->tex_builtin_check) {
+ //was checked, verify that the built-in is the same
+ if (arg->tex_builtin == p_builtin) {
+ return true;
+ } else {
+ _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using different built-ins. Only calling with the same built-in is supported.");
+ return false;
+ }
+ } else {
+
+ arg->tex_builtin_check = true;
+ arg->tex_builtin = p_builtin;
+
+ for (Map<StringName, Set<int>>::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
+ for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
+ if (!_propagate_function_call_sampler_builtin_reference(E->key(), F->get(), p_builtin)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ ERR_FAIL_V(false); //bug? function not found
+}
+
+ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
+
+ Vector<Expression> expression;
+
+ //Vector<TokenType> operators;
+
+ while (true) {
+
+ Node *expr = nullptr;
+ TkPos prepos = _get_tkpos();
+ Token tk = _get_token();
+ TkPos pos = _get_tkpos();
+
+ bool is_const = false;
+
+ if (tk.type == TK_PARENTHESIS_OPEN) {
+ //handle subexpression
+
+ expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!expr)
+ return nullptr;
+
+ tk = _get_token();
+
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+
+ _set_error("Expected ')' in expression");
+ return nullptr;
+ }
+
+ } else if (tk.type == TK_REAL_CONSTANT) {
+
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ ConstantNode::Value v;
+ v.real = tk.constant;
+ constant->values.push_back(v);
+ constant->datatype = TYPE_FLOAT;
+ expr = constant;
+
+ } else if (tk.type == TK_INT_CONSTANT) {
+
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ ConstantNode::Value v;
+ v.sint = tk.constant;
+ constant->values.push_back(v);
+ constant->datatype = TYPE_INT;
+ expr = constant;
+
+ } else if (tk.type == TK_TRUE) {
+
+ //handle true constant
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ ConstantNode::Value v;
+ v.boolean = true;
+ constant->values.push_back(v);
+ constant->datatype = TYPE_BOOL;
+ expr = constant;
+
+ } else if (tk.type == TK_FALSE) {
+
+ //handle false constant
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ ConstantNode::Value v;
+ v.boolean = false;
+ constant->values.push_back(v);
+ constant->datatype = TYPE_BOOL;
+ expr = constant;
+
+ } else if (tk.type == TK_TYPE_VOID) {
+
+ //make sure void is not used in expression
+ _set_error("Void value not allowed in Expression");
+ return nullptr;
+ } else if (is_token_nonvoid_datatype(tk.type)) {
+ //basic type constructor
+
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_CONSTRUCT;
+
+ if (is_token_precision(tk.type)) {
+
+ func->return_precision_cache = get_token_precision(tk.type);
+ tk = _get_token();
+ }
+
+ VariableNode *funcname = alloc_node<VariableNode>();
+ funcname->name = get_datatype_name(get_token_datatype(tk.type));
+ func->arguments.push_back(funcname);
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after type name");
+ return nullptr;
+ }
+
+ int carg = -1;
+
+ bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+
+ if (carg >= 0) {
+ completion_type = COMPLETION_CALL_ARGUMENTS;
+ completion_line = tk_line;
+ completion_block = p_block;
+ completion_function = funcname->name;
+ completion_argument = carg;
+ }
+
+ if (!ok)
+ return nullptr;
+
+ if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) {
+ _set_error("No matching constructor found for: '" + String(funcname->name) + "'");
+ return nullptr;
+ }
+
+ expr = _reduce_expression(p_block, func);
+
+ } else if (tk.type == TK_IDENTIFIER) {
+
+ _set_tkpos(prepos);
+
+ StringName identifier;
+
+ StructNode *pstruct = nullptr;
+ bool struct_init = false;
+
+ _get_completable_identifier(p_block, COMPLETION_IDENTIFIER, identifier);
+
+ if (shader->structs.has(identifier)) {
+ pstruct = shader->structs[identifier].shader_struct;
+ struct_init = true;
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_PARENTHESIS_OPEN) {
+
+ if (struct_init) { //a struct constructor
+
+ const StringName &name = identifier;
+
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_STRUCT;
+ func->struct_name = name;
+ func->return_cache = TYPE_STRUCT;
+ VariableNode *funcname = alloc_node<VariableNode>();
+ funcname->name = name;
+ func->arguments.push_back(funcname);
+
+ for (int i = 0; i < pstruct->members.size(); i++) {
+ Node *nexpr;
+
+ if (pstruct->members[i]->array_size != 0) {
+
+ DataType type = pstruct->members[i]->get_datatype();
+ String struct_name = pstruct->members[i]->struct_name;
+ int array_size = pstruct->members[i]->array_size;
+
+ DataType type2;
+ String struct_name2 = "";
+ int array_size2 = 0;
+
+ bool auto_size = false;
+
+ tk = _get_token();
+
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ auto_size = true;
+ } else {
+
+ if (shader->structs.has(tk.text)) {
+ type2 = TYPE_STRUCT;
+ struct_name2 = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for array");
+ return nullptr;
+ }
+ type2 = get_token_datatype(tk.type);
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos2 = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ array_size2 = array_size;
+ tk = _get_token();
+ } else {
+ _set_tkpos(pos2);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+
+ ConstantNode *cnode = (ConstantNode *)n;
+ if (cnode->values.size() == 1) {
+ array_size2 = cnode->values[0].sint;
+ if (array_size2 <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return nullptr;
+ } else {
+ tk = _get_token();
+ }
+ }
+ } else {
+ _set_error("Expected '['");
+ return nullptr;
+ }
+
+ if (type != type2 || struct_name != struct_name2 || array_size != array_size2) {
+ String error_str = "Cannot convert from '";
+ if (type2 == TYPE_STRUCT) {
+ error_str += struct_name2;
+ } else {
+ error_str += get_datatype_name(type2);
+ }
+ error_str += "[";
+ error_str += itos(array_size2);
+ error_str += "]'";
+ error_str += " to '";
+ if (type == TYPE_STRUCT) {
+ error_str += struct_name;
+ } else {
+ error_str += get_datatype_name(type);
+ }
+ error_str += "[";
+ error_str += itos(array_size);
+ error_str += "]'";
+ _set_error(error_str);
+ return nullptr;
+ }
+ }
+
+ ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
+ an->datatype = type;
+ an->struct_name = struct_name;
+
+ if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
+ while (true) {
+
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n) {
+ return nullptr;
+ }
+
+ if (type != n->get_datatype() || struct_name != n->get_datatype_name()) {
+ _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'");
+ return nullptr;
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ an->initializer.push_back(n);
+ continue;
+ } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) {
+ an->initializer.push_back(n);
+ break;
+ } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) {
+ an->initializer.push_back(n);
+ break;
+ } else {
+ if (auto_size)
+ _set_error("Expected '}' or ','");
+ else
+ _set_error("Expected ')' or ','");
+ return nullptr;
+ }
+ }
+ if (an->initializer.size() != array_size) {
+ _set_error("Array size mismatch");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected array initialization!");
+ return nullptr;
+ }
+
+ nexpr = an;
+ } else {
+ nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!nexpr) {
+ return nullptr;
+ }
+ Node *node = pstruct->members[i];
+ if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
+ String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
+ String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
+ _set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
+ return nullptr;
+ }
+ }
+
+ if (i + 1 < pstruct->members.size()) {
+ tk = _get_token();
+ if (tk.type != TK_COMMA) {
+ _set_error("Expected ','");
+ return nullptr;
+ }
+ }
+ func->arguments.push_back(nexpr);
+ }
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')'");
+ return nullptr;
+ }
+
+ expr = func;
+
+ } else { //a function
+
+ const StringName &name = identifier;
+
+ OperatorNode *func = alloc_node<OperatorNode>();
+ func->op = OP_CALL;
+ VariableNode *funcname = alloc_node<VariableNode>();
+ funcname->name = name;
+ func->arguments.push_back(funcname);
+
+ int carg = -1;
+
+ bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+
+ // Check if block has a variable with the same name as function to prevent shader crash.
+ ShaderLanguage::BlockNode *bnode = p_block;
+ while (bnode) {
+ if (bnode->variables.has(name)) {
+ _set_error("Expected function name");
+ return nullptr;
+ }
+ bnode = bnode->parent_block;
+ }
+
+ //test if function was parsed first
+ int function_index = -1;
+ for (int i = 0; i < shader->functions.size(); i++) {
+ if (shader->functions[i].name == name) {
+ //add to current function as dependency
+ for (int j = 0; j < shader->functions.size(); j++) {
+ if (shader->functions[j].name == current_function) {
+ shader->functions.write[j].uses_function.insert(name);
+ break;
+ }
+ }
+
+ //see if texture arguments must connect
+ function_index = i;
+ break;
+ }
+ }
+
+ if (carg >= 0) {
+ completion_type = COMPLETION_CALL_ARGUMENTS;
+ completion_line = tk_line;
+ completion_block = p_block;
+ completion_function = funcname->name;
+ completion_argument = carg;
+ }
+
+ if (!ok)
+ return nullptr;
+
+ if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) {
+ _set_error("No matching function found for: '" + String(funcname->name) + "'");
+ return nullptr;
+ }
+ completion_class = TAG_GLOBAL; // reset sub-class
+ if (function_index >= 0) {
+ //connect texture arguments, so we can cache in the
+ //argument what type of filter and repeat to use
+
+ FunctionNode *call_function = shader->functions[function_index].function;
+ if (call_function) {
+
+ //get current base function
+ FunctionNode *base_function = nullptr;
+ {
+ BlockNode *b = p_block;
+
+ while (b) {
+
+ if (b->parent_function) {
+ base_function = b->parent_function;
+ break;
+ } else {
+ b = b->parent_block;
+ }
+ }
+ }
+
+ ERR_FAIL_COND_V(!base_function, nullptr); //bug, wtf
+
+ for (int i = 0; i < call_function->arguments.size(); i++) {
+ int argidx = i + 1;
+ if (argidx < func->arguments.size()) {
+ if (call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) {
+ bool error = false;
+ Node *n = func->arguments[argidx];
+ if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) {
+ error = true;
+ } else if (n->type == Node::TYPE_ARRAY) {
+ ArrayNode *an = static_cast<ArrayNode *>(n);
+ if (an->call_expression != nullptr) {
+ error = true;
+ }
+ } else if (n->type == Node::TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ if (vn->is_const) {
+ error = true;
+ } else {
+ StringName varname = vn->name;
+ if (shader->uniforms.has(varname)) {
+ error = true;
+ } else {
+ if (p_builtin_types.has(varname)) {
+ BuiltInInfo info = p_builtin_types[varname];
+ if (info.constant) {
+ error = true;
+ }
+ }
+ }
+ }
+ } else if (n->type == Node::TYPE_MEMBER) {
+ MemberNode *mn = static_cast<MemberNode *>(n);
+ if (mn->basetype_const) {
+ error = true;
+ }
+ }
+ if (error) {
+ _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier)));
+ return nullptr;
+ }
+ }
+ if (is_sampler_type(call_function->arguments[i].type)) {
+ //let's see where our argument comes from
+ Node *n = func->arguments[argidx];
+ ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ StringName varname = vn->name;
+ if (shader->uniforms.has(varname)) {
+ //being sampler, this either comes from a uniform
+ ShaderNode::Uniform *u = &shader->uniforms[varname];
+ ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously
+ //propagate
+ if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
+ return nullptr;
+ }
+ } else if (p_builtin_types.has(varname)) {
+ //a built-in
+ if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) {
+ return nullptr;
+ }
+ } else {
+ //or this comes from an argument, but nothing else can be a sampler
+ bool found = false;
+ for (int j = 0; j < base_function->arguments.size(); j++) {
+ if (base_function->arguments[j].name == varname) {
+ if (!base_function->arguments[j].tex_argument_connect.has(call_function->name)) {
+ base_function->arguments.write[j].tex_argument_connect[call_function->name] = Set<int>();
+ }
+ base_function->arguments.write[j].tex_argument_connect[call_function->name].insert(i);
+ found = true;
+ break;
+ }
+ }
+ ERR_CONTINUE(!found);
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ expr = func;
+ }
+ } else {
+ //an identifier
+
+ _set_tkpos(pos);
+
+ DataType data_type;
+ IdentifierType ident_type;
+ int array_size = 0;
+ StringName struct_name;
+
+ if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) {
+ int idx = 0;
+ bool found = false;
+
+ while (builtin_func_defs[idx].name) {
+ if (builtin_func_defs[idx].tag == p_block->block_tag && builtin_func_defs[idx].name == identifier) {
+ found = true;
+ break;
+ }
+ idx++;
+ }
+ if (!found) {
+ _set_error("Unknown identifier in expression: " + String(identifier));
+ return nullptr;
+ }
+ } else {
+
+ if (!_find_identifier(p_block, false, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
+ _set_error("Unknown identifier in expression: " + String(identifier));
+ return nullptr;
+ }
+
+ if (ident_type == IDENTIFIER_FUNCTION) {
+ _set_error("Can't use function as identifier: " + String(identifier));
+ return nullptr;
+ }
+ }
+
+ Node *index_expression = nullptr;
+ Node *call_expression = nullptr;
+
+ if (array_size > 0) {
+ tk = _get_token();
+
+ if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD) {
+ _set_error("Expected '[' or '.'");
+ return nullptr;
+ }
+
+ if (tk.type == TK_PERIOD) {
+ completion_class = TAG_ARRAY;
+ p_block->block_tag = SubClassTag::TAG_ARRAY;
+ call_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ p_block->block_tag = SubClassTag::TAG_GLOBAL;
+ if (!call_expression)
+ return nullptr;
+ data_type = call_expression->get_datatype();
+ } else { // indexing
+
+ index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!index_expression)
+ return nullptr;
+
+ if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
+ _set_error("Only integer expressions are allowed for indexing");
+ return nullptr;
+ }
+
+ if (index_expression->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cnode = (ConstantNode *)index_expression;
+ if (cnode) {
+ if (!cnode->values.empty()) {
+ int value = cnode->values[0].sint;
+ if (value < 0 || value >= array_size) {
+ _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1));
+ return nullptr;
+ }
+ }
+ }
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return nullptr;
+ }
+ }
+
+ ArrayNode *arrname = alloc_node<ArrayNode>();
+ arrname->name = identifier;
+ arrname->datatype_cache = data_type;
+ arrname->struct_name = struct_name;
+ arrname->index_expression = index_expression;
+ arrname->call_expression = call_expression;
+ arrname->is_const = is_const;
+ expr = arrname;
+
+ } else {
+
+ VariableNode *varname = alloc_node<VariableNode>();
+ varname->name = identifier;
+ varname->datatype_cache = data_type;
+ varname->is_const = is_const;
+ varname->struct_name = struct_name;
+ expr = varname;
+ }
+ }
+ } else if (tk.type == TK_OP_ADD) {
+ continue; //this one does nothing
+ } else if (tk.type == TK_OP_SUB || tk.type == TK_OP_NOT || tk.type == TK_OP_BIT_INVERT || tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
+
+ Expression e;
+ e.is_op = true;
+
+ switch (tk.type) {
+ case TK_OP_SUB: e.op = OP_NEGATE; break;
+ case TK_OP_NOT: e.op = OP_NOT; break;
+ case TK_OP_BIT_INVERT: e.op = OP_BIT_INVERT; break;
+ case TK_OP_INCREMENT: e.op = OP_INCREMENT; break;
+ case TK_OP_DECREMENT: e.op = OP_DECREMENT; break;
+ default: ERR_FAIL_V(nullptr);
+ }
+
+ expression.push_back(e);
+ continue;
+ } else {
+ _set_error("Expected expression, found: " + get_token_text(tk));
+ return nullptr;
+ //nothing
+ }
+
+ 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();
+ tk = _get_token();
+
+ if (tk.type == TK_CURSOR) {
+ //do nothing
+ } else if (tk.type == TK_IDENTIFIER) {
+
+ } else if (tk.type == TK_PERIOD) {
+
+ DataType dt = expr->get_datatype();
+ String st = expr->get_datatype_name();
+
+ StringName identifier;
+ if (_get_completable_identifier(p_block, dt == TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX, identifier)) {
+ if (dt == TYPE_STRUCT) {
+ completion_struct = st;
+ } else {
+ completion_base = dt;
+ }
+ }
+
+ if (identifier == StringName()) {
+ _set_error("Expected identifier as member");
+ return nullptr;
+ }
+ String ident = identifier;
+
+ bool ok = true;
+ bool repeated = false;
+ DataType member_type = TYPE_VOID;
+ StringName member_struct_name = "";
+ int array_size = 0;
+
+ Set<char> position_symbols;
+ Set<char> color_symbols;
+ Set<char> texture_symbols;
+
+ bool mix_error = false;
+
+ switch (dt) {
+ case TYPE_STRUCT: {
+ ok = false;
+ String member_name = String(ident.ptr());
+ if (shader->structs.has(st)) {
+ StructNode *n = shader->structs[st].shader_struct;
+ for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) {
+ if (String(E->get()->name) == member_name) {
+ member_type = E->get()->datatype;
+ array_size = E->get()->array_size;
+ if (member_type == TYPE_STRUCT) {
+ member_struct_name = E->get()->struct_name;
+ }
+ ok = true;
+ break;
+ }
+ }
+ }
+
+ } break;
+ case TYPE_BVEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_VEC2: {
+
+ int l = ident.length();
+ if (l == 1) {
+ member_type = DataType(dt - 1);
+ } else if (l == 2) {
+ member_type = dt;
+ } else if (l == 3) {
+ member_type = DataType(dt + 1);
+ } else if (l == 4) {
+ member_type = DataType(dt + 2);
+ } else {
+ ok = false;
+ break;
+ }
+
+ const CharType *c = ident.ptr();
+ for (int i = 0; i < l; i++) {
+
+ switch (c[i]) {
+ case 'r':
+ case 'g':
+ if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!color_symbols.has(c[i])) {
+ color_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ case 'x':
+ case 'y':
+ if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!position_symbols.has(c[i])) {
+ position_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ case 's':
+ case 't':
+ if (color_symbols.size() > 0 || position_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!texture_symbols.has(c[i])) {
+ texture_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+
+ } break;
+ case TYPE_BVEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_VEC3: {
+
+ int l = ident.length();
+ if (l == 1) {
+ member_type = DataType(dt - 2);
+ } else if (l == 2) {
+ member_type = DataType(dt - 1);
+ } else if (l == 3) {
+ member_type = dt;
+ } else if (l == 4) {
+ member_type = DataType(dt + 1);
+ } else {
+ ok = false;
+ break;
+ }
+
+ const CharType *c = ident.ptr();
+ for (int i = 0; i < l; i++) {
+
+ switch (c[i]) {
+ case 'r':
+ case 'g':
+ case 'b':
+ if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!color_symbols.has(c[i])) {
+ color_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ case 'x':
+ case 'y':
+ case 'z':
+ if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!position_symbols.has(c[i])) {
+ position_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ case 's':
+ case 't':
+ case 'p':
+ if (color_symbols.size() > 0 || position_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!texture_symbols.has(c[i])) {
+ texture_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+
+ } break;
+ case TYPE_BVEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_VEC4: {
+
+ int l = ident.length();
+ if (l == 1) {
+ member_type = DataType(dt - 3);
+ } else if (l == 2) {
+ member_type = DataType(dt - 2);
+ } else if (l == 3) {
+ member_type = DataType(dt - 1);
+ } else if (l == 4) {
+ member_type = dt;
+ } else {
+ ok = false;
+ break;
+ }
+
+ const CharType *c = ident.ptr();
+ for (int i = 0; i < l; i++) {
+
+ switch (c[i]) {
+ case 'r':
+ case 'g':
+ case 'b':
+ case 'a':
+ if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!color_symbols.has(c[i])) {
+ color_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ case 'x':
+ case 'y':
+ case 'z':
+ case 'w':
+ if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!position_symbols.has(c[i])) {
+ position_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ case 's':
+ case 't':
+ case 'p':
+ case 'q':
+ if (color_symbols.size() > 0 || position_symbols.size() > 0) {
+ mix_error = true;
+ break;
+ }
+ if (!texture_symbols.has(c[i])) {
+ texture_symbols.insert(c[i]);
+ } else {
+ repeated = true;
+ }
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+
+ } break;
+
+ default: {
+ ok = false;
+ }
+ }
+
+ if (mix_error) {
+ _set_error("Cannot combine symbols from different sets in expression ." + ident);
+ return nullptr;
+ }
+
+ if (!ok) {
+ _set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident);
+ return nullptr;
+ }
+
+ MemberNode *mn = alloc_node<MemberNode>();
+ mn->basetype = dt;
+ mn->basetype_const = is_const;
+ mn->datatype = member_type;
+ mn->base_struct_name = st;
+ mn->struct_name = member_struct_name;
+ mn->array_size = array_size;
+ mn->name = ident;
+ mn->owner = expr;
+ mn->has_swizzling_duplicates = repeated;
+
+ if (array_size > 0) {
+
+ tk = _get_token();
+ if (tk.type == TK_PERIOD) {
+ _set_error("Nested array length() is not yet implemented");
+ return nullptr;
+ } else if (tk.type == TK_BRACKET_OPEN) {
+
+ Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!index_expression)
+ return nullptr;
+
+ if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
+ _set_error("Only integer expressions are allowed for indexing");
+ return nullptr;
+ }
+
+ if (index_expression->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cnode = (ConstantNode *)index_expression;
+ if (cnode) {
+ if (!cnode->values.empty()) {
+ int value = cnode->values[0].sint;
+ if (value < 0 || value >= array_size) {
+ _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1));
+ return nullptr;
+ }
+ }
+ }
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return nullptr;
+ }
+ mn->index_expression = index_expression;
+
+ } else {
+ _set_error("Expected '[' or '.'");
+ return nullptr;
+ }
+ }
+
+ expr = mn;
+
+ //todo
+ //member (period) has priority over any operator
+ //creates a subindexing expression in place
+
+ /*} else if (tk.type==TK_BRACKET_OPEN) {
+ //todo
+ //subindexing has priority over any operator
+ //creates a subindexing expression in place
+
+ */
+ } else if (tk.type == TK_BRACKET_OPEN) {
+
+ Node *index = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!index)
+ return nullptr;
+
+ if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) {
+ _set_error("Only integer datatypes are allowed for indexing");
+ return nullptr;
+ }
+
+ DataType member_type = TYPE_VOID;
+
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC2:
+ case TYPE_VEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_MAT2:
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= 2) {
+ _set_error("Index out of range (0-1)");
+ return nullptr;
+ }
+ }
+
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC2: member_type = TYPE_BOOL; break;
+ case TYPE_VEC2: member_type = TYPE_FLOAT; break;
+ case TYPE_IVEC2: member_type = TYPE_INT; break;
+ case TYPE_UVEC2: member_type = TYPE_UINT; break;
+ case TYPE_MAT2: member_type = TYPE_VEC2; break;
+ default: break;
+ }
+
+ break;
+ case TYPE_BVEC3:
+ case TYPE_VEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_MAT3:
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= 3) {
+ _set_error("Index out of range (0-2)");
+ return nullptr;
+ }
+ }
+
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC3: member_type = TYPE_BOOL; break;
+ case TYPE_VEC3: member_type = TYPE_FLOAT; break;
+ case TYPE_IVEC3: member_type = TYPE_INT; break;
+ case TYPE_UVEC3: member_type = TYPE_UINT; break;
+ case TYPE_MAT3: member_type = TYPE_VEC3; break;
+ default: break;
+ }
+ break;
+ case TYPE_BVEC4:
+ case TYPE_VEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_MAT4:
+ if (index->type == Node::TYPE_CONSTANT) {
+ uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
+ if (index_constant >= 4) {
+ _set_error("Index out of range (0-3)");
+ return nullptr;
+ }
+ }
+
+ switch (expr->get_datatype()) {
+ case TYPE_BVEC4: member_type = TYPE_BOOL; break;
+ case TYPE_VEC4: member_type = TYPE_FLOAT; break;
+ case TYPE_IVEC4: member_type = TYPE_INT; break;
+ case TYPE_UVEC4: member_type = TYPE_UINT; break;
+ case TYPE_MAT4: member_type = TYPE_VEC4; break;
+ default: break;
+ }
+ break;
+ default: {
+ _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
+ return nullptr;
+ }
+ }
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = OP_INDEX;
+ op->return_cache = member_type;
+ op->arguments.push_back(expr);
+ op->arguments.push_back(index);
+ expr = op;
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']' after indexing expression");
+ return nullptr;
+ }
+
+ } else if (tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = tk.type == TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT;
+ op->arguments.push_back(expr);
+
+ if (!_validate_operator(op, &op->return_cache)) {
+ _set_error("Invalid base type for increment/decrement operator");
+ return nullptr;
+ }
+
+ if (!_validate_assign(expr, p_builtin_types)) {
+ _set_error("Invalid use of increment/decrement operator in constant expression.");
+ return nullptr;
+ }
+ expr = op;
+ } else {
+
+ _set_tkpos(pos2);
+ break;
+ }
+ }
+
+ Expression e;
+ e.is_op = false;
+ e.node = expr;
+ expression.push_back(e);
+
+ pos = _get_tkpos();
+ tk = _get_token();
+
+ if (is_token_operator(tk.type)) {
+
+ Expression o;
+ o.is_op = true;
+
+ switch (tk.type) {
+
+ case TK_OP_EQUAL: o.op = OP_EQUAL; break;
+ case TK_OP_NOT_EQUAL: o.op = OP_NOT_EQUAL; break;
+ case TK_OP_LESS: o.op = OP_LESS; break;
+ case TK_OP_LESS_EQUAL: o.op = OP_LESS_EQUAL; break;
+ case TK_OP_GREATER: o.op = OP_GREATER; break;
+ case TK_OP_GREATER_EQUAL: o.op = OP_GREATER_EQUAL; break;
+ case TK_OP_AND: o.op = OP_AND; break;
+ case TK_OP_OR: o.op = OP_OR; break;
+ case TK_OP_ADD: o.op = OP_ADD; break;
+ case TK_OP_SUB: o.op = OP_SUB; break;
+ case TK_OP_MUL: o.op = OP_MUL; break;
+ case TK_OP_DIV: o.op = OP_DIV; break;
+ case TK_OP_MOD: o.op = OP_MOD; break;
+ case TK_OP_SHIFT_LEFT: o.op = OP_SHIFT_LEFT; break;
+ case TK_OP_SHIFT_RIGHT: o.op = OP_SHIFT_RIGHT; break;
+ case TK_OP_ASSIGN: o.op = OP_ASSIGN; break;
+ case TK_OP_ASSIGN_ADD: o.op = OP_ASSIGN_ADD; break;
+ case TK_OP_ASSIGN_SUB: o.op = OP_ASSIGN_SUB; break;
+ case TK_OP_ASSIGN_MUL: o.op = OP_ASSIGN_MUL; break;
+ case TK_OP_ASSIGN_DIV: o.op = OP_ASSIGN_DIV; break;
+ case TK_OP_ASSIGN_MOD: o.op = OP_ASSIGN_MOD; break;
+ case TK_OP_ASSIGN_SHIFT_LEFT: o.op = OP_ASSIGN_SHIFT_LEFT; break;
+ case TK_OP_ASSIGN_SHIFT_RIGHT: o.op = OP_ASSIGN_SHIFT_RIGHT; break;
+ case TK_OP_ASSIGN_BIT_AND: o.op = OP_ASSIGN_BIT_AND; break;
+ case TK_OP_ASSIGN_BIT_OR: o.op = OP_ASSIGN_BIT_OR; break;
+ case TK_OP_ASSIGN_BIT_XOR: o.op = OP_ASSIGN_BIT_XOR; break;
+ case TK_OP_BIT_AND: o.op = OP_BIT_AND; break;
+ case TK_OP_BIT_OR: o.op = OP_BIT_OR; break;
+ case TK_OP_BIT_XOR: o.op = OP_BIT_XOR; break;
+ case TK_QUESTION: o.op = OP_SELECT_IF; break;
+ case TK_COLON: o.op = OP_SELECT_ELSE; break;
+ default: {
+ _set_error("Invalid token for operator: " + get_token_text(tk));
+ return nullptr;
+ }
+ }
+
+ expression.push_back(o);
+
+ } else {
+ _set_tkpos(pos); //something else, so rollback and end
+ break;
+ }
+ }
+
+ /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
+
+ while (expression.size() > 1) {
+
+ int next_op = -1;
+ int min_priority = 0xFFFFF;
+ bool is_unary = false;
+ bool is_ternary = false;
+
+ for (int i = 0; i < expression.size(); i++) {
+
+ if (!expression[i].is_op) {
+
+ continue;
+ }
+
+ bool unary = false;
+ bool ternary = false;
+
+ int priority;
+ switch (expression[i].op) {
+ case OP_EQUAL: priority = 8; break;
+ case OP_NOT_EQUAL: priority = 8; break;
+ case OP_LESS: priority = 7; break;
+ case OP_LESS_EQUAL: priority = 7; break;
+ case OP_GREATER: priority = 7; break;
+ case OP_GREATER_EQUAL: priority = 7; break;
+ case OP_AND: priority = 12; break;
+ case OP_OR: priority = 14; break;
+ case OP_NOT:
+ priority = 3;
+ unary = true;
+ break;
+ case OP_NEGATE:
+ priority = 3;
+ unary = true;
+ break;
+ case OP_ADD: priority = 5; break;
+ case OP_SUB: priority = 5; break;
+ case OP_MUL: priority = 4; break;
+ case OP_DIV: priority = 4; break;
+ case OP_MOD: priority = 4; break;
+ case OP_SHIFT_LEFT: priority = 6; break;
+ case OP_SHIFT_RIGHT: priority = 6; break;
+ case OP_ASSIGN: priority = 16; break;
+ case OP_ASSIGN_ADD: priority = 16; break;
+ case OP_ASSIGN_SUB: priority = 16; break;
+ case OP_ASSIGN_MUL: priority = 16; break;
+ case OP_ASSIGN_DIV: priority = 16; break;
+ case OP_ASSIGN_MOD: priority = 16; break;
+ case OP_ASSIGN_SHIFT_LEFT: priority = 16; break;
+ case OP_ASSIGN_SHIFT_RIGHT: priority = 16; break;
+ case OP_ASSIGN_BIT_AND: priority = 16; break;
+ case OP_ASSIGN_BIT_OR: priority = 16; break;
+ case OP_ASSIGN_BIT_XOR: priority = 16; break;
+ case OP_BIT_AND: priority = 9; break;
+ case OP_BIT_OR: priority = 11; break;
+ case OP_BIT_XOR: priority = 10; break;
+ case OP_BIT_INVERT:
+ priority = 3;
+ unary = true;
+ break;
+ case OP_INCREMENT:
+ priority = 3;
+ unary = true;
+ break;
+ case OP_DECREMENT:
+ priority = 3;
+ unary = true;
+ break;
+ case OP_SELECT_IF:
+ priority = 15;
+ ternary = true;
+ break;
+ case OP_SELECT_ELSE:
+ priority = 15;
+ ternary = true;
+ break;
+
+ default:
+ ERR_FAIL_V(nullptr); //unexpected operator
+ }
+
+ if (priority < min_priority) {
+ // < is used for left to right (default)
+ // <= is used for right to left
+ next_op = i;
+ min_priority = priority;
+ is_unary = unary;
+ is_ternary = ternary;
+ }
+ }
+
+ 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) {
+
+ expr_pos++;
+ if (expr_pos == expression.size()) {
+ //can happen..
+ _set_error("Unexpected end of expression...");
+ return nullptr;
+ }
+ }
+
+ //consecutively do unary operators
+ for (int i = expr_pos - 1; i >= next_op; i--) {
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = expression[i].op;
+ if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_builtin_types)) {
+
+ _set_error("Can't use increment/decrement operator in constant expression.");
+ return nullptr;
+ }
+ op->arguments.push_back(expression[i + 1].node);
+
+ expression.write[i].is_op = false;
+ expression.write[i].node = op;
+
+ if (!_validate_operator(op, &op->return_cache)) {
+
+ String at;
+ for (int j = 0; j < op->arguments.size(); j++) {
+ if (j > 0)
+ at += " and ";
+ at += get_datatype_name(op->arguments[j]->get_datatype());
+ }
+ _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at);
+ return nullptr;
+ }
+ expression.remove(i + 1);
+ }
+
+ } else if (is_ternary) {
+
+ if (next_op < 1 || next_op >= (expression.size() - 1)) {
+ _set_error("Parser bug...");
+ ERR_FAIL_V(nullptr);
+ }
+
+ if (next_op + 2 >= expression.size() || !expression[next_op + 2].is_op || expression[next_op + 2].op != OP_SELECT_ELSE) {
+ _set_error("Missing matching ':' for select operator");
+ return nullptr;
+ }
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = expression[next_op].op;
+ op->arguments.push_back(expression[next_op - 1].node);
+ op->arguments.push_back(expression[next_op + 1].node);
+ op->arguments.push_back(expression[next_op + 3].node);
+
+ expression.write[next_op - 1].is_op = false;
+ expression.write[next_op - 1].node = op;
+ if (!_validate_operator(op, &op->return_cache)) {
+
+ String at;
+ for (int i = 0; i < op->arguments.size(); i++) {
+ if (i > 0)
+ at += " and ";
+ at += get_datatype_name(op->arguments[i]->get_datatype());
+ }
+ _set_error("Invalid argument to ternary ?: operator: " + at);
+ return nullptr;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ expression.remove(next_op);
+ }
+
+ } else {
+
+ if (next_op < 1 || next_op >= (expression.size() - 1)) {
+ _set_error("Parser bug...");
+ ERR_FAIL_V(nullptr);
+ }
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = expression[next_op].op;
+
+ if (expression[next_op - 1].is_op) {
+
+ _set_error("Parser bug...");
+ ERR_FAIL_V(nullptr);
+ }
+
+ if (_is_operator_assign(op->op)) {
+
+ String assign_message;
+ if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) {
+
+ _set_error(assign_message);
+ return nullptr;
+ }
+ }
+
+ if (expression[next_op + 1].is_op) {
+ // this is not invalid and can really appear
+ // but it becomes invalid anyway because no binary op
+ // can be followed by a unary op in a valid combination,
+ // due to how precedence works, unaries will always disappear first
+
+ _set_error("Parser bug...");
+ }
+
+ op->arguments.push_back(expression[next_op - 1].node); //expression goes as left
+ op->arguments.push_back(expression[next_op + 1].node); //next expression goes as right
+ expression.write[next_op - 1].node = op;
+
+ //replace all 3 nodes by this operator and make it an expression
+
+ if (!_validate_operator(op, &op->return_cache)) {
+
+ String at;
+ for (int i = 0; i < op->arguments.size(); i++) {
+ if (i > 0)
+ at += " and ";
+ if (op->arguments[i]->get_datatype() == TYPE_STRUCT) {
+ at += op->arguments[i]->get_datatype_name();
+ } else {
+ at += get_datatype_name(op->arguments[i]->get_datatype());
+ }
+ }
+ _set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
+ return nullptr;
+ }
+
+ expression.remove(next_op);
+ expression.remove(next_op);
+ }
+ }
+
+ return expression[0].node;
+}
+
+ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node) {
+
+ if (p_node->type != Node::TYPE_OPERATOR)
+ return p_node;
+
+ //for now only reduce simple constructors
+ OperatorNode *op = static_cast<OperatorNode *>(p_node);
+
+ if (op->op == OP_CONSTRUCT) {
+
+ ERR_FAIL_COND_V(op->arguments[0]->type != Node::TYPE_VARIABLE, p_node);
+
+ DataType type = op->get_datatype();
+ DataType base = get_scalar_type(type);
+ int cardinality = get_cardinality(type);
+
+ Vector<ConstantNode::Value> values;
+
+ for (int i = 1; i < op->arguments.size(); i++) {
+
+ op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]);
+ if (op->arguments[i]->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i]);
+
+ if (get_scalar_type(cn->datatype) == base) {
+ for (int j = 0; j < cn->values.size(); j++) {
+ values.push_back(cn->values[j]);
+ }
+ } else if (get_scalar_type(cn->datatype) == cn->datatype) {
+
+ ConstantNode::Value v;
+ if (!convert_constant(cn, base, &v)) {
+ return p_node;
+ }
+ values.push_back(v);
+ } else {
+ return p_node;
+ }
+
+ } else {
+ return p_node;
+ }
+ }
+
+ if (values.size() == 1) {
+ if (type >= TYPE_MAT2 && type <= TYPE_MAT4) {
+ ConstantNode::Value value = values[0];
+ ConstantNode::Value zero;
+ zero.real = 0.0f;
+ int size = 2 + (type - TYPE_MAT2);
+
+ values.clear();
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
+ values.push_back(i == j ? value : zero);
+ }
+ }
+ } else {
+ ConstantNode::Value value = values[0];
+ for (int i = 1; i < cardinality; i++) {
+ values.push_back(value);
+ }
+ }
+ } else if (values.size() != cardinality) {
+ ERR_PRINT("Failed to reduce expression, values and cardinality mismatch.");
+ return p_node;
+ }
+
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ cn->datatype = op->get_datatype();
+ cn->values = values;
+ return cn;
+ } else if (op->op == OP_NEGATE) {
+
+ op->arguments.write[0] = _reduce_expression(p_block, op->arguments[0]);
+ if (op->arguments[0]->type == Node::TYPE_CONSTANT) {
+
+ ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[0]);
+
+ DataType base = get_scalar_type(cn->datatype);
+
+ Vector<ConstantNode::Value> values;
+
+ for (int i = 0; i < cn->values.size(); i++) {
+
+ ConstantNode::Value nv;
+ switch (base) {
+ case TYPE_BOOL: {
+ nv.boolean = !cn->values[i].boolean;
+ } break;
+ case TYPE_INT: {
+ nv.sint = -cn->values[i].sint;
+ } break;
+ case TYPE_UINT: {
+ // Intentionally wrap the unsigned int value, because GLSL does.
+ nv.uint = 0 - cn->values[i].uint;
+ } break;
+ case TYPE_FLOAT: {
+ nv.real = -cn->values[i].real;
+ } break;
+ default: {
+ }
+ }
+
+ values.push_back(nv);
+ }
+
+ cn->values = values;
+ return cn;
+ }
+ }
+
+ return p_node;
+}
+
+ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
+
+ ShaderLanguage::Node *expr = _parse_expression(p_block, p_builtin_types);
+ if (!expr) //errored
+ return nullptr;
+
+ expr = _reduce_expression(p_block, expr);
+
+ return expr;
+}
+
+Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) {
+
+ while (true) {
+
+ TkPos pos = _get_tkpos();
+
+ Token tk = _get_token();
+
+ if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_SWITCH) {
+ if (tk.type != TK_CF_CASE && tk.type != TK_CF_DEFAULT && tk.type != TK_CURLY_BRACKET_CLOSE) {
+ _set_error("Switch may contains only case and default blocks");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ bool is_struct = shader->structs.has(tk.text);
+
+ if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block
+ if (p_just_one) {
+ _set_error("Unexpected '}'");
+ return ERR_PARSE_ERROR;
+ }
+
+ return OK;
+
+ } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) {
+ String struct_name = "";
+ if (is_struct) {
+ struct_name = tk.text;
+ }
+
+ bool is_const = false;
+
+ if (tk.type == TK_CONST) {
+ is_const = true;
+ tk = _get_token();
+
+ if (!is_struct) {
+ is_struct = shader->structs.has(tk.text); // check again.
+ struct_name = tk.text;
+ }
+ }
+
+ DataPrecision precision = PRECISION_DEFAULT;
+ if (is_token_precision(tk.type)) {
+ precision = get_token_precision(tk.type);
+ tk = _get_token();
+
+ if (!is_struct) {
+ is_struct = shader->structs.has(tk.text); // check again.
+ }
+ if (is_struct && precision != PRECISION_DEFAULT) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ if (!is_token_nonvoid_datatype(tk.type)) {
+ _set_error("Expected datatype after precision");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (!is_struct) {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for variable (samplers not allowed)");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ DataType type = is_struct ? TYPE_STRUCT : get_token_datatype(tk.type);
+
+ if (_validate_datatype(type) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ Node *vardecl = nullptr;
+
+ while (true) {
+
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier after type");
+ return ERR_PARSE_ERROR;
+ }
+
+ StringName name = tk.text;
+ ShaderLanguage::IdentifierType itype;
+ if (_find_identifier(p_block, true, p_builtin_types, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (itype != IDENTIFIER_FUNCTION) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ BlockNode::Variable var;
+ var.type = type;
+ var.precision = precision;
+ var.line = tk_line;
+ var.array_size = 0;
+ var.is_const = is_const;
+ var.struct_name = struct_name;
+
+ tk = _get_token();
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ bool unknown_size = false;
+
+ if (RenderingServer::get_singleton()->is_low_end() && is_const) {
+ _set_error("Local const arrays are supported only on high-end platform!");
+ return ERR_PARSE_ERROR;
+ }
+
+ ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>();
+ if (is_struct) {
+ node->struct_name = struct_name;
+ node->datatype = TYPE_STRUCT;
+ } else {
+ node->datatype = type;
+ }
+ node->precision = precision;
+ node->is_const = is_const;
+ vardecl = (Node *)node;
+
+ ArrayDeclarationNode::Declaration decl;
+ decl.name = name;
+ decl.size = 0U;
+
+ tk = _get_token();
+
+ if (tk.type == TK_BRACKET_CLOSE) {
+ unknown_size = true;
+ } else {
+
+ if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
+ _set_error("Expected integer constant > 0 or ']'");
+ return ERR_PARSE_ERROR;
+ }
+
+ decl.size = ((uint32_t)tk.constant);
+ tk = _get_token();
+
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ var.array_size = decl.size;
+ }
+
+ bool full_def = false;
+
+ tk = _get_token();
+ if (tk.type == TK_OP_ASSIGN) {
+
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ _set_error("Array initialization is supported only on high-end platform!");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ if (tk.type != TK_CURLY_BRACKET_OPEN) {
+
+ if (unknown_size) {
+ _set_error("Expected '{'");
+ return ERR_PARSE_ERROR;
+ }
+
+ full_def = true;
+
+ DataPrecision precision2 = PRECISION_DEFAULT;
+ if (is_token_precision(tk.type)) {
+ precision2 = get_token_precision(tk.type);
+ tk = _get_token();
+ if (shader->structs.has(tk.text)) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ if (!is_token_nonvoid_datatype(tk.type)) {
+ _set_error("Expected datatype after precision");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ DataType type2;
+ String struct_name2 = "";
+
+ if (shader->structs.has(tk.text)) {
+ type2 = TYPE_STRUCT;
+ struct_name2 = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for array");
+ return ERR_PARSE_ERROR;
+ }
+ type2 = get_token_datatype(tk.type);
+ }
+
+ int array_size2 = 0;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos2 = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ array_size2 = var.array_size;
+ tk = _get_token();
+ } else {
+ _set_tkpos(pos2);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ ConstantNode *cnode = (ConstantNode *)n;
+ if (cnode->values.size() == 1) {
+ array_size2 = cnode->values[0].sint;
+ if (array_size2 <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ } else {
+ tk = _get_token();
+ }
+ }
+ } else {
+ _set_error("Expected '['");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) {
+ String error_str = "Cannot convert from '";
+ if (precision2 != PRECISION_DEFAULT) {
+ error_str += get_precision_name(precision2);
+ error_str += " ";
+ }
+ if (type2 == TYPE_STRUCT) {
+ error_str += struct_name2;
+ } else {
+ error_str += get_datatype_name(type2);
+ }
+ error_str += "[";
+ error_str += itos(array_size2);
+ error_str += "]'";
+ error_str += " to '";
+ if (precision != PRECISION_DEFAULT) {
+ error_str += get_precision_name(precision);
+ error_str += " ";
+ }
+ if (type == TYPE_STRUCT) {
+ error_str += struct_name;
+ } else {
+ error_str += get_datatype_name(type);
+ }
+ error_str += "[";
+ error_str += itos(var.array_size);
+ error_str += "]'";
+ _set_error(error_str);
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ bool curly = tk.type == TK_CURLY_BRACKET_OPEN;
+
+ if (unknown_size) {
+ if (!curly) {
+ _set_error("Expected '{'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ if (full_def) {
+ if (curly) {
+ _set_error("Expected '('");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ }
+
+ if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
+ while (true) {
+
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n) {
+ return ERR_PARSE_ERROR;
+ }
+
+ if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
+ _set_error("Expected constant expression");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (var.type != n->get_datatype() || struct_name != n->get_datatype_name()) {
+ _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? struct_name : get_datatype_name(var.type)) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ decl.initializer.push_back(n);
+ continue;
+ } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
+ decl.initializer.push_back(n);
+ break;
+ } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
+ decl.initializer.push_back(n);
+ break;
+ } else {
+ if (curly)
+ _set_error("Expected '}' or ','");
+ else
+ _set_error("Expected ')' or ','");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ if (unknown_size) {
+ decl.size = decl.initializer.size();
+ var.array_size = decl.initializer.size();
+ } else if (decl.initializer.size() != var.array_size) {
+ _set_error("Array size mismatch");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ }
+ } else {
+ if (unknown_size) {
+ _set_error("Expected array initialization");
+ return ERR_PARSE_ERROR;
+ }
+ if (is_const) {
+ _set_error("Expected initialization of constant");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ node->declarations.push_back(decl);
+ } else if (tk.type == TK_OP_ASSIGN) {
+
+ VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
+ if (is_struct) {
+ node->struct_name = struct_name;
+ node->datatype = TYPE_STRUCT;
+ } else {
+ node->datatype = type;
+ }
+ node->precision = precision;
+ node->is_const = is_const;
+ vardecl = (Node *)node;
+
+ VariableDeclarationNode::Declaration decl;
+ decl.name = name;
+ decl.initializer = nullptr;
+
+ //variable created with assignment! must parse an expression
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n)
+ 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;
+ }
+ decl.initializer = n;
+
+ if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) {
+ _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ node->declarations.push_back(decl);
+ } else {
+ if (is_const) {
+ _set_error("Expected initialization of constant");
+ return ERR_PARSE_ERROR;
+ }
+
+ VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
+ if (is_struct) {
+ node->struct_name = struct_name;
+ node->datatype = TYPE_STRUCT;
+ } else {
+ node->datatype = type;
+ }
+ node->precision = precision;
+ vardecl = (Node *)node;
+
+ VariableDeclarationNode::Declaration decl;
+ decl.name = name;
+ decl.initializer = nullptr;
+ node->declarations.push_back(decl);
+ }
+
+ p_block->statements.push_back(vardecl);
+
+ p_block->variables[name] = var;
+
+ if (tk.type == TK_COMMA) {
+ if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) {
+ _set_error("Multiple declarations in 'for' loop are not implemented yet.");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ //another variable
+ } else if (tk.type == TK_SEMICOLON) {
+ break;
+ } else {
+ _set_error("Expected ',' or ';' after variable");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ } else if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ //a sub block, just because..
+ BlockNode *block = alloc_node<BlockNode>();
+ block->parent_block = p_block;
+ if (_parse_block(block, p_builtin_types, false, p_can_break, p_can_continue) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+ p_block->statements.push_back(block);
+ } else if (tk.type == TK_CF_IF) {
+ //if () {}
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after if");
+ return ERR_PARSE_ERROR;
+ }
+
+ ControlFlowNode *cf = alloc_node<ControlFlowNode>();
+ cf->flow_op = FLOW_OP_IF;
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n)
+ return ERR_PARSE_ERROR;
+
+ if (n->get_datatype() != TYPE_BOOL) {
+ _set_error("Expected boolean expression");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' after expression");
+ return ERR_PARSE_ERROR;
+ }
+
+ BlockNode *block = alloc_node<BlockNode>();
+ block->parent_block = p_block;
+ cf->expressions.push_back(n);
+ cf->blocks.push_back(block);
+ p_block->statements.push_back(cf);
+
+ Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
+ if (err)
+ return err;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_CF_ELSE) {
+
+ block = alloc_node<BlockNode>();
+ block->parent_block = p_block;
+ cf->blocks.push_back(block);
+ err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
+
+ } else {
+ _set_tkpos(pos); //rollback
+ }
+ } else if (tk.type == TK_CF_SWITCH) {
+
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ _set_error("\"switch\" operator is supported only on high-end platform!");
+ return ERR_PARSE_ERROR;
+ }
+
+ // switch() {}
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after switch");
+ return ERR_PARSE_ERROR;
+ }
+ ControlFlowNode *cf = alloc_node<ControlFlowNode>();
+ cf->flow_op = FLOW_OP_SWITCH;
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n)
+ return ERR_PARSE_ERROR;
+ if (n->get_datatype() != TYPE_INT) {
+ _set_error("Expected integer expression");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' after expression");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ if (tk.type != TK_CURLY_BRACKET_OPEN) {
+ _set_error("Expected '{' after switch statement");
+ return ERR_PARSE_ERROR;
+ }
+ BlockNode *switch_block = alloc_node<BlockNode>();
+ switch_block->block_type = BlockNode::BLOCK_TYPE_SWITCH;
+ switch_block->parent_block = p_block;
+ cf->expressions.push_back(n);
+ cf->blocks.push_back(switch_block);
+ p_block->statements.push_back(cf);
+
+ int prev_type = TK_CF_CASE;
+ while (true) { // Go-through multiple cases.
+
+ if (_parse_block(switch_block, p_builtin_types, true, true, false) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+ pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) {
+ if (prev_type == TK_CF_DEFAULT) {
+ if (tk.type == TK_CF_CASE) {
+ _set_error("Cases must be defined before default case.");
+ return ERR_PARSE_ERROR;
+ } else if (prev_type == TK_CF_DEFAULT) {
+ _set_error("Default case must be defined only once.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ prev_type = tk.type;
+ _set_tkpos(pos);
+ continue;
+ } else {
+ Set<int> constants;
+ for (int i = 0; i < switch_block->statements.size(); i++) { // Checks for duplicates.
+ ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i];
+ if (flow) {
+ if (flow->flow_op == FLOW_OP_CASE) {
+ ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]);
+ if (!n2) {
+ return ERR_PARSE_ERROR;
+ }
+ if (n2->values.empty()) {
+ return ERR_PARSE_ERROR;
+ }
+ if (constants.has(n2->values[0].sint)) {
+ _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ constants.insert(n2->values[0].sint);
+ } else if (flow->flow_op == FLOW_OP_DEFAULT) {
+ continue;
+ } else {
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ return ERR_PARSE_ERROR;
+ }
+ }
+ break;
+ }
+ }
+
+ } else if (tk.type == TK_CF_CASE) {
+ // case x : break; | return;
+
+ if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) {
+ _set_tkpos(pos);
+ return OK;
+ }
+
+ if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) {
+ _set_error("case must be placed within switch block");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ int sign = 1;
+
+ if (tk.type == TK_OP_SUB) {
+ sign = -1;
+ tk = _get_token();
+ }
+
+ if (tk.type != TK_INT_CONSTANT) {
+ _set_error("Expected integer constant");
+ return ERR_PARSE_ERROR;
+ }
+
+ int constant = (int)tk.constant * sign;
+
+ tk = _get_token();
+
+ if (tk.type != TK_COLON) {
+ _set_error("Expected ':'");
+ return ERR_PARSE_ERROR;
+ }
+
+ ControlFlowNode *cf = alloc_node<ControlFlowNode>();
+ cf->flow_op = FLOW_OP_CASE;
+
+ ConstantNode *n = alloc_node<ConstantNode>();
+ ConstantNode::Value v;
+ v.sint = constant;
+ n->values.push_back(v);
+ n->datatype = TYPE_INT;
+
+ BlockNode *case_block = alloc_node<BlockNode>();
+ case_block->block_type = BlockNode::BLOCK_TYPE_CASE;
+ case_block->parent_block = p_block;
+ cf->expressions.push_back(n);
+ cf->blocks.push_back(case_block);
+ p_block->statements.push_back(cf);
+
+ Error err = _parse_block(case_block, p_builtin_types, false, true, false);
+ if (err)
+ return err;
+
+ return OK;
+
+ } else if (tk.type == TK_CF_DEFAULT) {
+
+ if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) {
+ _set_tkpos(pos);
+ return OK;
+ }
+
+ if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) {
+ _set_error("default must be placed within switch block");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ if (tk.type != TK_COLON) {
+ _set_error("Expected ':'");
+ return ERR_PARSE_ERROR;
+ }
+
+ ControlFlowNode *cf = alloc_node<ControlFlowNode>();
+ cf->flow_op = FLOW_OP_DEFAULT;
+
+ BlockNode *default_block = alloc_node<BlockNode>();
+ default_block->block_type = BlockNode::BLOCK_TYPE_DEFAULT;
+ default_block->parent_block = p_block;
+ cf->blocks.push_back(default_block);
+ p_block->statements.push_back(cf);
+
+ Error err = _parse_block(default_block, p_builtin_types, false, true, false);
+ if (err)
+ return err;
+
+ return OK;
+
+ } else if (tk.type == TK_CF_DO || tk.type == TK_CF_WHILE) {
+ // do {} while()
+ // while() {}
+ bool is_do = tk.type == TK_CF_DO;
+
+ BlockNode *do_block = nullptr;
+ if (is_do) {
+
+ do_block = alloc_node<BlockNode>();
+ do_block->parent_block = p_block;
+
+ Error err = _parse_block(do_block, p_builtin_types, true, true, true);
+ if (err)
+ return err;
+
+ tk = _get_token();
+ if (tk.type != TK_CF_WHILE) {
+ _set_error("Expected while after do");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ tk = _get_token();
+
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after while");
+ return ERR_PARSE_ERROR;
+ }
+
+ ControlFlowNode *cf = alloc_node<ControlFlowNode>();
+ if (is_do) {
+ cf->flow_op = FLOW_OP_DO;
+ } else {
+ cf->flow_op = FLOW_OP_WHILE;
+ }
+ Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!n)
+ return ERR_PARSE_ERROR;
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' after expression");
+ return ERR_PARSE_ERROR;
+ }
+ if (!is_do) {
+ BlockNode *block = alloc_node<BlockNode>();
+ block->parent_block = p_block;
+ cf->expressions.push_back(n);
+ cf->blocks.push_back(block);
+ p_block->statements.push_back(cf);
+
+ Error err = _parse_block(block, p_builtin_types, true, true, true);
+ if (err)
+ return err;
+ } else {
+
+ cf->expressions.push_back(n);
+ cf->blocks.push_back(do_block);
+ p_block->statements.push_back(cf);
+
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';'");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ } else if (tk.type == TK_CF_FOR) {
+ // for() {}
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after for");
+ return ERR_PARSE_ERROR;
+ }
+
+ ControlFlowNode *cf = alloc_node<ControlFlowNode>();
+ cf->flow_op = FLOW_OP_FOR;
+
+ BlockNode *init_block = alloc_node<BlockNode>();
+ init_block->block_type = BlockNode::BLOCK_TYPE_FOR;
+ init_block->parent_block = p_block;
+ init_block->single_statement = true;
+ cf->blocks.push_back(init_block);
+ if (_parse_block(init_block, p_builtin_types, true, false, false) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+
+ Node *n = _parse_and_reduce_expression(init_block, p_builtin_types);
+ if (!n)
+ return ERR_PARSE_ERROR;
+
+ if (n->get_datatype() != TYPE_BOOL) {
+ _set_error("Middle expression is expected to be boolean.");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';' after middle expression");
+ return ERR_PARSE_ERROR;
+ }
+
+ cf->expressions.push_back(n);
+
+ n = _parse_and_reduce_expression(init_block, p_builtin_types);
+ if (!n)
+ return ERR_PARSE_ERROR;
+
+ cf->expressions.push_back(n);
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' after third expression");
+ return ERR_PARSE_ERROR;
+ }
+
+ BlockNode *block = alloc_node<BlockNode>();
+ block->parent_block = init_block;
+ cf->blocks.push_back(block);
+ p_block->statements.push_back(cf);
+
+ Error err = _parse_block(block, p_builtin_types, true, true, true);
+ if (err)
+ return err;
+
+ } else if (tk.type == TK_CF_RETURN) {
+
+ //check return type
+ BlockNode *b = p_block;
+ while (b && !b->parent_function) {
+ b = b->parent_block;
+ }
+
+ if (!b) {
+ _set_error("Bug");
+ return ERR_BUG;
+ }
+
+ ControlFlowNode *flow = alloc_node<ControlFlowNode>();
+ flow->flow_op = FLOW_OP_RETURN;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+ 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) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_tkpos(pos); //rollback, wants expression
+ Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!expr)
+ 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) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';' after return expression");
+ return ERR_PARSE_ERROR;
+ }
+
+ flow->expressions.push_back(expr);
+ }
+
+ p_block->statements.push_back(flow);
+
+ BlockNode *block = p_block;
+ while (block) {
+ if (block->block_type == BlockNode::BLOCK_TYPE_CASE || block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) {
+ return OK;
+ }
+ block = block->parent_block;
+ }
+ } else if (tk.type == TK_CF_DISCARD) {
+
+ //check return type
+ BlockNode *b = p_block;
+ while (b && !b->parent_function) {
+ b = b->parent_block;
+ }
+ if (!b) {
+ _set_error("Bug");
+ return ERR_BUG;
+ }
+
+ if (!b->parent_function->can_discard) {
+ _set_error("Use of 'discard' is not allowed here.");
+ return ERR_PARSE_ERROR;
+ }
+
+ ControlFlowNode *flow = alloc_node<ControlFlowNode>();
+ flow->flow_op = FLOW_OP_DISCARD;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ //all is good
+ _set_error("Expected ';' after discard");
+ }
+
+ 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");
+ }
+
+ ControlFlowNode *flow = alloc_node<ControlFlowNode>();
+ flow->flow_op = FLOW_OP_BREAK;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ //all is good
+ _set_error("Expected ';' after break");
+ }
+
+ p_block->statements.push_back(flow);
+
+ BlockNode *block = p_block;
+ while (block) {
+ if (block->block_type == BlockNode::BLOCK_TYPE_CASE || block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) {
+ return OK;
+ }
+ block = block->parent_block;
+ }
+
+ } else if (tk.type == TK_CF_CONTINUE) {
+
+ if (!p_can_continue) {
+ //all is good
+ _set_error("Continuing is not allowed here");
+ }
+
+ ControlFlowNode *flow = alloc_node<ControlFlowNode>();
+ flow->flow_op = FLOW_OP_CONTINUE;
+
+ pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ //all is good
+ _set_error("Expected ';' after continue");
+ }
+
+ p_block->statements.push_back(flow);
+
+ } else {
+
+ //nothing else, so expression
+ _set_tkpos(pos); //rollback
+ Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ if (!expr)
+ return ERR_PARSE_ERROR;
+ p_block->statements.push_back(expr);
+ tk = _get_token();
+
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';' after statement");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (p_just_one)
+ break;
+ }
+
+ return OK;
+}
+
+String ShaderLanguage::_get_shader_type_list(const Set<String> &p_shader_types) const {
+
+ // Return a list of shader types as an human-readable string
+ String valid_types;
+ for (const Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) {
+ if (valid_types != String()) {
+ valid_types += ", ";
+ }
+
+ valid_types += "'" + E->get() + "'";
+ }
+
+ return valid_types;
+}
+
+String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const {
+ switch (p_qualifier) {
+ case ArgumentQualifier::ARGUMENT_QUALIFIER_IN:
+ return "in";
+ case ArgumentQualifier::ARGUMENT_QUALIFIER_OUT:
+ return "out";
+ case ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT:
+ return "inout";
+ }
+ return "";
+}
+
+Error ShaderLanguage::_validate_datatype(DataType p_type) {
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ bool invalid_type = false;
+
+ switch (p_type) {
+ case TYPE_UINT:
+ case TYPE_UVEC2:
+ case TYPE_UVEC3:
+ case TYPE_UVEC4:
+ case TYPE_ISAMPLER2D:
+ case TYPE_USAMPLER2D:
+ case TYPE_ISAMPLER3D:
+ case TYPE_USAMPLER3D:
+ case TYPE_USAMPLER2DARRAY:
+ case TYPE_ISAMPLER2DARRAY:
+ invalid_type = true;
+ break;
+ default:
+ break;
+ }
+
+ if (invalid_type) {
+ _set_error(vformat("\"%s\" type is supported only on high-end platform!", get_datatype_name(p_type)));
+ return ERR_UNAVAILABLE;
+ }
+ }
+ return OK;
+}
+
+Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types) {
+
+ Token tk = _get_token();
+
+ if (tk.type != TK_SHADER_TYPE) {
+ _set_error("Expected 'shader_type' at the beginning of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
+ return ERR_PARSE_ERROR;
+ }
+
+ String shader_type_identifier;
+
+ shader_type_identifier = tk.text;
+
+ if (!p_shader_types.has(shader_type_identifier)) {
+ _set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';' after 'shader_type <type>'.");
+ }
+
+ tk = _get_token();
+
+ int texture_uniforms = 0;
+ int uniforms = 0;
+
+ while (tk.type != TK_EOF) {
+
+ switch (tk.type) {
+ case TK_RENDER_MODE: {
+
+ while (true) {
+
+ StringName mode;
+ _get_completable_identifier(nullptr, COMPLETION_RENDER_MODE, mode);
+
+ if (mode == StringName()) {
+ _set_error("Expected identifier for render mode");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (p_render_modes.find(mode) == -1) {
+ _set_error("Invalid render mode: '" + String(mode) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (shader->render_modes.find(mode) != -1) {
+ _set_error("Duplicate render mode: '" + String(mode) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ shader->render_modes.push_back(mode);
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ //all good, do nothing
+ } else if (tk.type == TK_SEMICOLON) {
+ break; //done
+ } else {
+ _set_error("Unexpected token: " + get_token_text(tk));
+ return ERR_PARSE_ERROR;
+ }
+ }
+ } break;
+ case TK_STRUCT: {
+ ShaderNode::Struct st;
+ DataType type;
+
+ tk = _get_token();
+ if (tk.type == TK_IDENTIFIER) {
+ st.name = tk.text;
+ tk = _get_token();
+ if (tk.type != TK_CURLY_BRACKET_OPEN) {
+ _set_error("Expected '{'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected struct identifier!");
+ return ERR_PARSE_ERROR;
+ }
+
+ StructNode *st_node = alloc_node<StructNode>();
+ st.shader_struct = st_node;
+
+ int member_count = 0;
+ Set<String> member_names;
+ while (true) { // variables list
+ tk = _get_token();
+ if (tk.type == TK_CURLY_BRACKET_CLOSE) {
+ break;
+ }
+ StringName struct_name = "";
+ bool struct_dt = false;
+ bool use_precision = false;
+ DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
+
+ if (tk.type == TK_STRUCT) {
+ _set_error("nested structs are not allowed!");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (is_token_precision(tk.type)) {
+ precision = get_token_precision(tk.type);
+ use_precision = true;
+ tk = _get_token();
+ }
+
+ if (shader->structs.has(tk.text)) {
+ struct_name = tk.text;
+ struct_dt = true;
+ if (use_precision) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (!is_token_datatype(tk.type) && !struct_dt) {
+ _set_error("Expected datatype.");
+ return ERR_PARSE_ERROR;
+ } else {
+ type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
+
+ if (is_sampler_type(type)) {
+ _set_error("sampler datatype not allowed here");
+ return ERR_PARSE_ERROR;
+ } else if (type == TYPE_VOID) {
+ _set_error("void datatype not allowed here");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier!");
+ return ERR_PARSE_ERROR;
+ }
+
+ MemberNode *member = alloc_node<MemberNode>();
+ member->precision = precision;
+ member->datatype = type;
+ member->struct_name = struct_name;
+ member->name = tk.text;
+
+ if (member_names.has(member->name)) {
+ _set_error("Redefinition of '" + String(member->name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ member_names.insert(member->name);
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ tk = _get_token();
+ if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
+ member->array_size = (int)tk.constant;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ st_node->members.push_back(member);
+
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ']' or ';'");
+ return ERR_PARSE_ERROR;
+ }
+ member_count++;
+ }
+ }
+ if (member_count == 0) {
+ _set_error("Empty structs are not allowed!");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';'");
+ return ERR_PARSE_ERROR;
+ }
+ shader->structs[st.name] = st;
+ shader->vstructs.push_back(st); // struct's order is important!
+
+ } break;
+ case TK_UNIFORM:
+ case TK_VARYING: {
+
+ bool uniform = tk.type == TK_UNIFORM;
+ DataPrecision precision = PRECISION_DEFAULT;
+ DataInterpolation interpolation = INTERPOLATION_SMOOTH;
+ DataType type;
+ StringName name;
+
+ tk = _get_token();
+ if (is_token_interpolation(tk.type)) {
+ interpolation = get_token_interpolation(tk.type);
+ tk = _get_token();
+ }
+
+ if (is_token_precision(tk.type)) {
+ precision = get_token_precision(tk.type);
+ tk = _get_token();
+ }
+
+ if (!is_token_datatype(tk.type)) {
+ _set_error("Expected datatype. ");
+ return ERR_PARSE_ERROR;
+ }
+
+ type = get_token_datatype(tk.type);
+
+ if (type == TYPE_VOID) {
+ _set_error("void datatype not allowed here");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (!uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
+ _set_error("Invalid type for varying, only float,vec2,vec3,vec4,mat2,mat3,mat4 or array of these types allowed.");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier!");
+ return ERR_PARSE_ERROR;
+ }
+
+ name = tk.text;
+
+ if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (has_builtin(p_functions, name)) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (uniform) {
+
+ ShaderNode::Uniform uniform2;
+
+ if (is_sampler_type(type)) {
+ uniform2.texture_order = texture_uniforms++;
+ uniform2.order = -1;
+ if (_validate_datatype(type) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ uniform2.texture_order = -1;
+ uniform2.order = uniforms++;
+ }
+ uniform2.type = type;
+ uniform2.precision = precision;
+
+ //todo parse default value
+
+ tk = _get_token();
+
+ if (tk.type == TK_COLON) {
+ //hint
+ do {
+ tk = _get_token();
+ if (tk.type == TK_HINT_WHITE_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
+ } else if (tk.type == TK_HINT_BLACK_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_BLACK;
+ } else if (tk.type == TK_HINT_NORMAL_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_NORMAL;
+ } else if (tk.type == TK_HINT_ROUGHNESS_NORMAL_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL;
+ } else if (tk.type == TK_HINT_ROUGHNESS_R) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_R;
+ } else if (tk.type == TK_HINT_ROUGHNESS_G) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_G;
+ } else if (tk.type == TK_HINT_ROUGHNESS_B) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_B;
+ } else if (tk.type == TK_HINT_ROUGHNESS_A) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_A;
+ } else if (tk.type == TK_HINT_ROUGHNESS_GRAY) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_GRAY;
+ } else if (tk.type == TK_HINT_ANISO_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ANISO;
+ } else if (tk.type == TK_HINT_ALBEDO_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_ALBEDO;
+ } else if (tk.type == TK_HINT_BLACK_ALBEDO_TEXTURE) {
+ uniform2.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO;
+ } else if (tk.type == TK_HINT_COLOR) {
+ if (type != TYPE_VEC4) {
+ _set_error("Color hint is for vec4 only");
+ return ERR_PARSE_ERROR;
+ }
+ uniform2.hint = ShaderNode::Uniform::HINT_COLOR;
+ } else if (tk.type == TK_HINT_RANGE) {
+
+ uniform2.hint = ShaderNode::Uniform::HINT_RANGE;
+ if (type != TYPE_FLOAT && type != TYPE_INT) {
+ _set_error("Range hint is for float and int only");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after hint_range");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ float sign = 1.0;
+
+ if (tk.type == TK_OP_SUB) {
+ sign = -1.0;
+ tk = _get_token();
+ }
+
+ if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
+ _set_error("Expected integer constant");
+ return ERR_PARSE_ERROR;
+ }
+
+ uniform2.hint_range[0] = tk.constant;
+ uniform2.hint_range[0] *= sign;
+
+ tk = _get_token();
+
+ if (tk.type != TK_COMMA) {
+ _set_error("Expected ',' after integer constant");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ sign = 1.0;
+
+ if (tk.type == TK_OP_SUB) {
+ sign = -1.0;
+ tk = _get_token();
+ }
+
+ if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
+ _set_error("Expected integer constant after ','");
+ return ERR_PARSE_ERROR;
+ }
+
+ uniform2.hint_range[1] = tk.constant;
+ uniform2.hint_range[1] *= sign;
+
+ tk = _get_token();
+
+ if (tk.type == TK_COMMA) {
+ tk = _get_token();
+
+ if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
+ _set_error("Expected integer constant after ','");
+ return ERR_PARSE_ERROR;
+ }
+
+ uniform2.hint_range[2] = tk.constant;
+ tk = _get_token();
+ } else {
+ if (type == TYPE_INT) {
+ uniform2.hint_range[2] = 1;
+ } else {
+ uniform2.hint_range[2] = 0.001;
+ }
+ }
+
+ if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ','");
+ return ERR_PARSE_ERROR;
+ }
+ } else if (tk.type == TK_FILTER_LINEAR) {
+ uniform2.filter = FILTER_LINEAR;
+ } else if (tk.type == TK_FILTER_NEAREST) {
+ uniform2.filter = FILTER_NEAREST;
+ } else if (tk.type == TK_FILTER_NEAREST_MIPMAP) {
+ uniform2.filter = FILTER_NEAREST_MIPMAP;
+ } else if (tk.type == TK_FILTER_LINEAR_MIPMAP) {
+ uniform2.filter = FILTER_LINEAR_MIPMAP;
+ } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISO) {
+ uniform2.filter = FILTER_NEAREST_MIPMAP_ANISO;
+ } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISO) {
+ uniform2.filter = FILTER_LINEAR_MIPMAP_ANISO;
+ } else if (tk.type == TK_REPEAT_DISABLE) {
+ uniform2.repeat = REPEAT_DISABLE;
+ } else if (tk.type == TK_REPEAT_ENABLE) {
+ uniform2.repeat = REPEAT_ENABLE;
+ } else {
+ _set_error("Expected valid type hint after ':'.");
+ }
+
+ if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
+ _set_error("This hint is only for sampler types");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ } while (tk.type == TK_COMMA);
+ }
+
+ if (tk.type == TK_OP_ASSIGN) {
+
+ Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>());
+ if (!expr)
+ return ERR_PARSE_ERROR;
+ if (expr->type != Node::TYPE_CONSTANT) {
+ _set_error("Expected constant expression after '='");
+ return ERR_PARSE_ERROR;
+ }
+
+ ConstantNode *cn = static_cast<ConstantNode *>(expr);
+
+ uniform2.default_value.resize(cn->values.size());
+
+ if (!convert_constant(cn, uniform2.type, uniform2.default_value.ptrw())) {
+ _set_error("Can't convert constant to " + get_datatype_name(uniform2.type));
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ }
+
+ shader->uniforms[name] = uniform2;
+
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+
+ ShaderNode::Varying varying;
+ varying.type = type;
+ varying.precision = precision;
+ varying.interpolation = interpolation;
+
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected ';' or '['");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ tk = _get_token();
+ if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
+ varying.array_size = (int)tk.constant;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ tk = _get_token();
+ if (tk.type != TK_SEMICOLON) {
+ _set_error("Expected ';'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ shader->varyings[name] = varying;
+ }
+
+ } break;
+ default: {
+ //function or constant variable
+
+ bool is_constant = false;
+ bool is_struct = false;
+ StringName struct_name;
+ DataPrecision precision = PRECISION_DEFAULT;
+ DataType type;
+ StringName name;
+
+ if (tk.type == TK_CONST) {
+ is_constant = true;
+ tk = _get_token();
+ }
+
+ if (is_token_precision(tk.type)) {
+ precision = get_token_precision(tk.type);
+ tk = _get_token();
+ }
+
+ if (shader->structs.has(tk.text)) {
+ if (precision != PRECISION_DEFAULT) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ is_struct = true;
+ struct_name = tk.text;
+ } else {
+
+ if (!is_token_datatype(tk.type)) {
+ _set_error("Expected constant, function, uniform or varying");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for constants or function return (samplers not allowed)");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (is_struct) {
+ type = TYPE_STRUCT;
+ } else {
+ type = get_token_datatype(tk.type);
+ }
+ TkPos prev_pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ _set_error("Cannot use arrays as return types");
+ return ERR_PARSE_ERROR;
+ }
+ _set_tkpos(prev_pos);
+
+ _get_completable_identifier(nullptr, COMPLETION_MAIN_FUNCTION, name);
+
+ if (name == StringName()) {
+ _set_error("Expected function name after datatype");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (has_builtin(p_functions, name)) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_PARENTHESIS_OPEN) {
+ if (type == TYPE_VOID) {
+ _set_error("Expected '(' after function identifier");
+ return ERR_PARSE_ERROR;
+ }
+
+ //variable
+
+ while (true) {
+ ShaderNode::Constant constant;
+ constant.type = is_struct ? TYPE_STRUCT : type;
+ constant.type_str = struct_name;
+ constant.precision = precision;
+ constant.initializer = nullptr;
+
+ if (tk.type == TK_OP_ASSIGN) {
+
+ if (!is_constant) {
+ _set_error("Expected 'const' keyword before constant definition");
+ return ERR_PARSE_ERROR;
+ }
+
+ //variable created with assignment! must parse an expression
+ Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>());
+ 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;
+ }
+
+ constant.initializer = static_cast<ConstantNode *>(expr);
+
+ if (is_struct) {
+ if (expr->get_datatype_name() != struct_name) {
+ _set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + struct_name + "'");
+ return ERR_PARSE_ERROR;
+ }
+ } else if (type != expr->get_datatype()) {
+ _set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+ } else {
+ _set_error("Expected initialization of constant");
+ return ERR_PARSE_ERROR;
+ }
+
+ shader->constants[name] = constant;
+ if (tk.type == TK_COMMA) {
+ tk = _get_token();
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier after type");
+ return ERR_PARSE_ERROR;
+ }
+
+ name = tk.text;
+ if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (has_builtin(p_functions, name)) {
+ _set_error("Redefinition of '" + String(name) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+
+ } else if (tk.type == TK_SEMICOLON) {
+ break;
+ } else {
+ _set_error("Expected ',' or ';' after constant");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ break;
+ }
+
+ Map<StringName, BuiltInInfo> builtin_types;
+ if (p_functions.has(name)) {
+ builtin_types = p_functions[name].built_ins;
+ }
+
+ if (p_functions.has("global")) { // Adds global variables: 'TIME'
+ for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) {
+ builtin_types.insert(E->key(), E->value());
+ }
+ }
+
+ ShaderNode::Function function;
+
+ function.callable = !p_functions.has(name);
+ function.name = name;
+
+ FunctionNode *func_node = alloc_node<FunctionNode>();
+
+ function.function = func_node;
+
+ shader->functions.push_back(function);
+
+ func_node->name = name;
+ func_node->return_type = type;
+ func_node->return_struct_name = struct_name;
+ func_node->return_precision = precision;
+
+ if (p_functions.has(name)) {
+ func_node->can_discard = p_functions[name].can_discard;
+ }
+
+ func_node->body = alloc_node<BlockNode>();
+ func_node->body->parent_function = func_node;
+
+ tk = _get_token();
+
+ while (true) {
+ if (tk.type == TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+
+ ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
+
+ if (tk.type == TK_ARG_IN) {
+ qualifier = ARGUMENT_QUALIFIER_IN;
+ tk = _get_token();
+ } else if (tk.type == TK_ARG_OUT) {
+ qualifier = ARGUMENT_QUALIFIER_OUT;
+ tk = _get_token();
+ } else if (tk.type == TK_ARG_INOUT) {
+ qualifier = ARGUMENT_QUALIFIER_INOUT;
+ tk = _get_token();
+ }
+
+ DataType ptype;
+ StringName pname;
+ StringName param_struct_name;
+ DataPrecision pprecision = PRECISION_DEFAULT;
+ bool use_precision = false;
+
+ if (is_token_precision(tk.type)) {
+ pprecision = get_token_precision(tk.type);
+ tk = _get_token();
+ use_precision = true;
+ }
+
+ is_struct = false;
+
+ if (shader->structs.has(tk.text)) {
+ is_struct = true;
+ param_struct_name = tk.text;
+ if (use_precision) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (!is_struct && !is_token_datatype(tk.type)) {
+ _set_error("Expected a valid datatype for argument");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) {
+ if (is_sampler_type(get_token_datatype(tk.type))) {
+ _set_error("Opaque types cannot be output parameters.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (is_struct) {
+ ptype = TYPE_STRUCT;
+ } else {
+ ptype = get_token_datatype(tk.type);
+ if (_validate_datatype(ptype) != OK) {
+ return ERR_PARSE_ERROR;
+ }
+ if (ptype == TYPE_VOID) {
+ _set_error("void not allowed in argument");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ tk = _get_token();
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ _set_error("Arrays as parameters are not implemented yet");
+ return ERR_PARSE_ERROR;
+ }
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier for argument name");
+ return ERR_PARSE_ERROR;
+ }
+
+ pname = tk.text;
+
+ ShaderLanguage::IdentifierType itype;
+ if (_find_identifier(func_node->body, false, builtin_types, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (itype != IDENTIFIER_FUNCTION) {
+ _set_error("Redefinition of '" + String(pname) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (has_builtin(p_functions, pname)) {
+ _set_error("Redefinition of '" + String(pname) + "'");
+ return ERR_PARSE_ERROR;
+ }
+
+ FunctionNode::Argument arg;
+ arg.type = ptype;
+ arg.name = pname;
+ arg.type_str = param_struct_name;
+ arg.precision = pprecision;
+ arg.qualifier = qualifier;
+ arg.tex_argument_check = false;
+ arg.tex_builtin_check = false;
+ arg.tex_argument_filter = FILTER_DEFAULT;
+ arg.tex_argument_repeat = REPEAT_DEFAULT;
+
+ func_node->arguments.push_back(arg);
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ _set_error("Arrays as parameters are not implemented yet");
+ return ERR_PARSE_ERROR;
+ }
+
+ if (tk.type == TK_COMMA) {
+ tk = _get_token();
+ //do none and go on
+ } else if (tk.type != TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ',' or ')' after identifier");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ if (p_functions.has(name)) {
+ //if one of the core functions, make sure they are of the correct form
+ if (func_node->arguments.size() > 0) {
+ _set_error("Function '" + String(name) + "' expects no arguments.");
+ return ERR_PARSE_ERROR;
+ }
+ if (func_node->return_type != TYPE_VOID) {
+ _set_error("Function '" + String(name) + "' must be of void return type.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ //all good let's parse inside the function!
+ tk = _get_token();
+ if (tk.type != TK_CURLY_BRACKET_OPEN) {
+ _set_error("Expected '{' to begin function");
+ return ERR_PARSE_ERROR;
+ }
+
+ current_function = name;
+
+ Error err = _parse_block(func_node->body, builtin_types);
+ if (err)
+ return err;
+
+ if (func_node->return_type != DataType::TYPE_VOID) {
+
+ BlockNode *block = func_node->body;
+ if (_find_last_flow_op_in_block(block, FlowOperation::FLOW_OP_RETURN) != OK) {
+ _set_error("Expected at least one return statement in a non-void function.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ current_function = StringName();
+ }
+ }
+
+ tk = _get_token();
+ }
+
+ 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;
+ }
+ }
+ return false;
+}
+
+Error ShaderLanguage::_find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op) {
+
+ bool found = false;
+
+ for (int i = p_flow->blocks.size() - 1; i >= 0; i--) {
+ if (p_flow->blocks[i]->type == Node::TYPE_BLOCK) {
+ BlockNode *last_block = (BlockNode *)p_flow->blocks[i];
+ if (_find_last_flow_op_in_block(last_block, p_op) == OK) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (found) {
+ return OK;
+ }
+ return FAILED;
+}
+
+Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op) {
+
+ bool found = false;
+
+ for (int i = p_block->statements.size() - 1; i >= 0; i--) {
+
+ if (p_block->statements[i]->type == Node::TYPE_CONTROL_FLOW) {
+ ControlFlowNode *flow = (ControlFlowNode *)p_block->statements[i];
+ if (flow->flow_op == p_op) {
+ found = true;
+ break;
+ } else {
+ if (_find_last_flow_op_in_op(flow, p_op) == OK) {
+ found = true;
+ break;
+ }
+ }
+ } else if (p_block->statements[i]->type == Node::TYPE_BLOCK) {
+ BlockNode *block = (BlockNode *)p_block->statements[i];
+ if (_find_last_flow_op_in_block(block, p_op) == OK) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ return OK;
+ }
+ return FAILED;
+}
+
+// skips over whitespace and /* */ and // comments
+static int _get_first_ident_pos(const String &p_code) {
+
+ int idx = 0;
+
+#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0))
+
+ while (true) {
+ if (GETCHAR(0) == '/' && GETCHAR(1) == '/') {
+ idx += 2;
+ while (true) {
+ if (GETCHAR(0) == 0) return 0;
+ if (GETCHAR(0) == '\n') {
+ idx++;
+ break; // loop
+ }
+ idx++;
+ }
+ } else if (GETCHAR(0) == '/' && GETCHAR(1) == '*') {
+ idx += 2;
+ while (true) {
+ if (GETCHAR(0) == 0) return 0;
+ if (GETCHAR(0) == '*' && GETCHAR(1) == '/') {
+ idx += 2;
+ break; // loop
+ }
+ idx++;
+ }
+ } else {
+ switch (GETCHAR(0)) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n': {
+ idx++;
+ } break; // switch
+ default:
+ return idx;
+ }
+ }
+ }
+
+#undef GETCHAR
+}
+
+String ShaderLanguage::get_shader_type(const String &p_code) {
+
+ bool reading_type = false;
+
+ String cur_identifier;
+
+ for (int i = _get_first_ident_pos(p_code); i < p_code.length(); i++) {
+
+ if (p_code[i] == ';') {
+ break;
+
+ } else if (p_code[i] <= 32) {
+ if (cur_identifier != String()) {
+ if (!reading_type) {
+ if (cur_identifier != "shader_type") {
+ return String();
+ }
+
+ reading_type = true;
+ cur_identifier = String();
+ } else {
+ return cur_identifier;
+ }
+ }
+ } else {
+ cur_identifier += String::chr(p_code[i]);
+ }
+ }
+
+ if (reading_type)
+ return cur_identifier;
+
+ 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) {
+
+ clear();
+
+ code = p_code;
+
+ nodes = nullptr;
+
+ shader = alloc_node<ShaderNode>();
+ Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
+
+ if (err != OK) {
+ return err;
+ }
+ 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, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
+
+ clear();
+
+ code = p_code;
+
+ nodes = nullptr;
+
+ shader = alloc_node<ShaderNode>();
+ _parse_shader(p_functions, p_render_modes, p_shader_types);
+
+ switch (completion_type) {
+
+ case COMPLETION_NONE: {
+ //do nothing
+ return OK;
+ } break;
+ case COMPLETION_RENDER_MODE: {
+ for (int i = 0; i < p_render_modes.size(); i++) {
+ ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_ENUM);
+ r_options->push_back(option);
+ }
+
+ return OK;
+ } break;
+ case COMPLETION_STRUCT: {
+
+ if (shader->structs.has(completion_struct)) {
+ StructNode *node = shader->structs[completion_struct].shader_struct;
+ for (int i = 0; i < node->members.size(); i++) {
+ ScriptCodeCompletionOption option(node->members[i]->name, ScriptCodeCompletionOption::KIND_MEMBER);
+ r_options->push_back(option);
+ }
+ }
+
+ return OK;
+ } break;
+ case COMPLETION_MAIN_FUNCTION: {
+
+ for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
+ r_options->push_back(option);
+ }
+
+ return OK;
+ } break;
+ case COMPLETION_IDENTIFIER:
+ case COMPLETION_FUNCTION_CALL: {
+
+ bool comp_ident = completion_type == COMPLETION_IDENTIFIER;
+ Map<String, ScriptCodeCompletionOption::Kind> matches;
+ StringName skip_function;
+ BlockNode *block = completion_block;
+
+ if (completion_class == TAG_GLOBAL) {
+ while (block) {
+ if (comp_ident) {
+ for (const Map<StringName, BlockNode::Variable>::Element *E = block->variables.front(); E; E = E->next()) {
+
+ if (E->get().line < completion_line) {
+ matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE);
+ }
+ }
+ }
+
+ if (block->parent_function) {
+ if (comp_ident) {
+ for (int i = 0; i < block->parent_function->arguments.size(); i++) {
+ matches.insert(block->parent_function->arguments[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ }
+ }
+ skip_function = block->parent_function->name;
+ }
+ block = block->parent_block;
+ }
+
+ if (comp_ident) {
+ if (p_functions.has("global")) {
+ for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
+ if (E->get().constant) {
+ kind = ScriptCodeCompletionOption::KIND_CONSTANT;
+ }
+ matches.insert(E->key(), kind);
+ }
+ }
+
+ if (skip_function != StringName() && p_functions.has(skip_function)) {
+ for (Map<StringName, BuiltInInfo>::Element *E = p_functions[skip_function].built_ins.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
+ if (E->get().constant) {
+ kind = ScriptCodeCompletionOption::KIND_CONSTANT;
+ }
+ matches.insert(E->key(), kind);
+ }
+ }
+
+ for (const Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) {
+ matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE);
+ }
+ for (const Map<StringName, ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) {
+ matches.insert(E->key(), ScriptCodeCompletionOption::KIND_MEMBER);
+ }
+ }
+
+ for (int i = 0; i < shader->functions.size(); i++) {
+ if (!shader->functions[i].callable || shader->functions[i].name == skip_function)
+ continue;
+ matches.insert(String(shader->functions[i].name), ScriptCodeCompletionOption::KIND_FUNCTION);
+ }
+
+ int idx = 0;
+ bool low_end = RenderingServer::get_singleton()->is_low_end();
+
+ while (builtin_func_defs[idx].name) {
+ if (low_end && builtin_func_defs[idx].high_end) {
+ idx++;
+ continue;
+ }
+ matches.insert(String(builtin_func_defs[idx].name), ScriptCodeCompletionOption::KIND_FUNCTION);
+ idx++;
+ }
+
+ } else { // sub-class
+ int idx = 0;
+ bool low_end = RenderingServer::get_singleton()->is_low_end();
+
+ while (builtin_func_defs[idx].name) {
+ if (low_end && builtin_func_defs[idx].high_end) {
+ idx++;
+ continue;
+ }
+ if (builtin_func_defs[idx].tag == completion_class) {
+ matches.insert(String(builtin_func_defs[idx].name), ScriptCodeCompletionOption::KIND_FUNCTION);
+ }
+ idx++;
+ }
+ }
+
+ for (Map<String, ScriptCodeCompletionOption::Kind>::Element *E = matches.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->key(), E->value());
+ if (E->value() == ScriptCodeCompletionOption::KIND_FUNCTION) {
+ option.insert_text += "(";
+ }
+ r_options->push_back(option);
+ }
+
+ return OK;
+ } break;
+ case COMPLETION_CALL_ARGUMENTS: {
+
+ for (int i = 0; i < shader->functions.size(); i++) {
+ if (!shader->functions[i].callable)
+ continue;
+ if (shader->functions[i].name == completion_function) {
+
+ String calltip;
+
+ calltip += get_datatype_name(shader->functions[i].function->return_type);
+ calltip += " ";
+ calltip += shader->functions[i].name;
+ calltip += "(";
+
+ for (int j = 0; j < shader->functions[i].function->arguments.size(); j++) {
+
+ if (j > 0)
+ calltip += ", ";
+ else
+ calltip += " ";
+
+ if (j == completion_argument) {
+ calltip += CharType(0xFFFF);
+ }
+
+ if (shader->functions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) {
+ if (shader->functions[i].function->arguments[j].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT) {
+ calltip += "out ";
+ } else { // ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT
+ calltip += "inout ";
+ }
+ }
+
+ calltip += get_datatype_name(shader->functions[i].function->arguments[j].type);
+ calltip += " ";
+ calltip += shader->functions[i].function->arguments[j].name;
+
+ if (j == completion_argument) {
+ calltip += CharType(0xFFFF);
+ }
+ }
+
+ if (shader->functions[i].function->arguments.size())
+ calltip += " ";
+ calltip += ")";
+
+ r_call_hint = calltip;
+ return OK;
+ }
+ }
+
+ int idx = 0;
+
+ String calltip;
+ bool low_end = RenderingServer::get_singleton()->is_low_end();
+
+ while (builtin_func_defs[idx].name) {
+
+ if (low_end && builtin_func_defs[idx].high_end) {
+ idx++;
+ continue;
+ }
+
+ int idx2 = 0;
+ int out_arg = -1;
+ while (builtin_func_out_args[idx2].name != nullptr) {
+ if (builtin_func_out_args[idx2].name == builtin_func_defs[idx].name) {
+ out_arg = builtin_func_out_args[idx2].argument;
+ break;
+ }
+ idx2++;
+ }
+
+ if (completion_function == builtin_func_defs[idx].name) {
+
+ if (builtin_func_defs[idx].tag != completion_class) {
+ idx++;
+ continue;
+ }
+
+ if (calltip.length())
+ calltip += "\n";
+
+ calltip += get_datatype_name(builtin_func_defs[idx].rettype);
+ calltip += " ";
+ calltip += builtin_func_defs[idx].name;
+ calltip += "(";
+
+ bool found_arg = false;
+ for (int i = 0; i < 4; i++) {
+
+ if (builtin_func_defs[idx].args[i] == TYPE_VOID)
+ break;
+
+ if (i > 0)
+ calltip += ", ";
+ else
+ calltip += " ";
+
+ if (i == completion_argument) {
+ calltip += CharType(0xFFFF);
+ }
+
+ if (out_arg >= 0 && i == out_arg) {
+ calltip += "out ";
+ }
+
+ calltip += get_datatype_name(builtin_func_defs[idx].args[i]);
+
+ if (i == completion_argument) {
+ calltip += CharType(0xFFFF);
+ }
+
+ found_arg = true;
+ }
+
+ if (found_arg)
+ calltip += " ";
+ calltip += ")";
+ }
+ idx++;
+ }
+
+ r_call_hint = calltip;
+
+ return OK;
+
+ } break;
+ case COMPLETION_INDEX: {
+
+ const char colv[4] = { 'r', 'g', 'b', 'a' };
+ const char coordv[4] = { 'x', 'y', 'z', 'w' };
+ const char coordt[4] = { 's', 't', 'p', 'q' };
+
+ int limit = 0;
+
+ switch (completion_base) {
+ case TYPE_BVEC2:
+ case TYPE_IVEC2:
+ case TYPE_UVEC2:
+ case TYPE_VEC2: {
+ limit = 2;
+
+ } break;
+ case TYPE_BVEC3:
+ case TYPE_IVEC3:
+ case TYPE_UVEC3:
+ case TYPE_VEC3: {
+
+ limit = 3;
+
+ } break;
+ case TYPE_BVEC4:
+ case TYPE_IVEC4:
+ case TYPE_UVEC4:
+ case TYPE_VEC4: {
+
+ limit = 4;
+
+ } break;
+ case TYPE_MAT2: limit = 2; break;
+ case TYPE_MAT3: limit = 3; break;
+ case TYPE_MAT4: limit = 4; break;
+ default: {
+ }
+ }
+
+ for (int i = 0; i < limit; i++) {
+ r_options->push_back(ScriptCodeCompletionOption(String::chr(colv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
+ r_options->push_back(ScriptCodeCompletionOption(String::chr(coordv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
+ r_options->push_back(ScriptCodeCompletionOption(String::chr(coordt[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
+ }
+
+ } break;
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
+String ShaderLanguage::get_error_text() {
+
+ return error_str;
+}
+
+int ShaderLanguage::get_error_line() {
+
+ return error_line;
+}
+
+ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() {
+
+ return shader;
+}
+
+ShaderLanguage::ShaderLanguage() {
+
+ nodes = nullptr;
+ completion_class = TAG_GLOBAL;
+}
+
+ShaderLanguage::~ShaderLanguage() {
+
+ clear();
+}
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
new file mode 100644
index 0000000000..beabae0dda
--- /dev/null
+++ b/servers/rendering/shader_language.h
@@ -0,0 +1,901 @@
+/*************************************************************************/
+/* shader_language.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SHADER_LANGUAGE_H
+#define SHADER_LANGUAGE_H
+
+#include "core/list.h"
+#include "core/map.h"
+#include "core/script_language.h"
+#include "core/string_name.h"
+#include "core/typedefs.h"
+#include "core/ustring.h"
+#include "core/variant.h"
+
+class ShaderLanguage {
+
+public:
+ enum TokenType {
+ TK_EMPTY,
+ TK_IDENTIFIER,
+ TK_TRUE,
+ TK_FALSE,
+ TK_REAL_CONSTANT,
+ TK_INT_CONSTANT,
+ TK_TYPE_VOID,
+ TK_TYPE_BOOL,
+ TK_TYPE_BVEC2,
+ TK_TYPE_BVEC3,
+ TK_TYPE_BVEC4,
+ TK_TYPE_INT,
+ TK_TYPE_IVEC2,
+ TK_TYPE_IVEC3,
+ TK_TYPE_IVEC4,
+ TK_TYPE_UINT,
+ TK_TYPE_UVEC2,
+ TK_TYPE_UVEC3,
+ TK_TYPE_UVEC4,
+ TK_TYPE_FLOAT,
+ TK_TYPE_VEC2,
+ TK_TYPE_VEC3,
+ TK_TYPE_VEC4,
+ TK_TYPE_MAT2,
+ TK_TYPE_MAT3,
+ TK_TYPE_MAT4,
+ TK_TYPE_SAMPLER2D,
+ TK_TYPE_ISAMPLER2D,
+ TK_TYPE_USAMPLER2D,
+ TK_TYPE_SAMPLER2DARRAY,
+ TK_TYPE_ISAMPLER2DARRAY,
+ TK_TYPE_USAMPLER2DARRAY,
+ TK_TYPE_SAMPLER3D,
+ TK_TYPE_ISAMPLER3D,
+ TK_TYPE_USAMPLER3D,
+ TK_TYPE_SAMPLERCUBE,
+ TK_INTERPOLATION_FLAT,
+ TK_INTERPOLATION_SMOOTH,
+ TK_CONST,
+ TK_STRUCT,
+ TK_PRECISION_LOW,
+ TK_PRECISION_MID,
+ TK_PRECISION_HIGH,
+ TK_OP_EQUAL,
+ TK_OP_NOT_EQUAL,
+ TK_OP_LESS,
+ TK_OP_LESS_EQUAL,
+ TK_OP_GREATER,
+ TK_OP_GREATER_EQUAL,
+ TK_OP_AND,
+ TK_OP_OR,
+ TK_OP_NOT,
+ TK_OP_ADD,
+ TK_OP_SUB,
+ TK_OP_MUL,
+ TK_OP_DIV,
+ TK_OP_MOD,
+ TK_OP_SHIFT_LEFT,
+ TK_OP_SHIFT_RIGHT,
+ TK_OP_ASSIGN,
+ TK_OP_ASSIGN_ADD,
+ TK_OP_ASSIGN_SUB,
+ TK_OP_ASSIGN_MUL,
+ TK_OP_ASSIGN_DIV,
+ TK_OP_ASSIGN_MOD,
+ TK_OP_ASSIGN_SHIFT_LEFT,
+ TK_OP_ASSIGN_SHIFT_RIGHT,
+ TK_OP_ASSIGN_BIT_AND,
+ TK_OP_ASSIGN_BIT_OR,
+ TK_OP_ASSIGN_BIT_XOR,
+ TK_OP_BIT_AND,
+ TK_OP_BIT_OR,
+ TK_OP_BIT_XOR,
+ TK_OP_BIT_INVERT,
+ TK_OP_INCREMENT,
+ TK_OP_DECREMENT,
+ TK_CF_IF,
+ TK_CF_ELSE,
+ TK_CF_FOR,
+ TK_CF_WHILE,
+ TK_CF_DO,
+ TK_CF_SWITCH,
+ TK_CF_CASE,
+ TK_CF_DEFAULT,
+ TK_CF_BREAK,
+ TK_CF_CONTINUE,
+ TK_CF_RETURN,
+ TK_CF_DISCARD,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_PARENTHESIS_OPEN,
+ TK_PARENTHESIS_CLOSE,
+ TK_QUESTION,
+ TK_COMMA,
+ TK_COLON,
+ TK_SEMICOLON,
+ TK_PERIOD,
+ TK_UNIFORM,
+ TK_VARYING,
+ TK_ARG_IN,
+ TK_ARG_OUT,
+ TK_ARG_INOUT,
+ TK_RENDER_MODE,
+ TK_HINT_WHITE_TEXTURE,
+ TK_HINT_BLACK_TEXTURE,
+ TK_HINT_NORMAL_TEXTURE,
+ TK_HINT_ROUGHNESS_NORMAL_TEXTURE,
+ TK_HINT_ROUGHNESS_R,
+ TK_HINT_ROUGHNESS_G,
+ TK_HINT_ROUGHNESS_B,
+ TK_HINT_ROUGHNESS_A,
+ TK_HINT_ROUGHNESS_GRAY,
+ TK_HINT_ANISO_TEXTURE,
+ TK_HINT_ALBEDO_TEXTURE,
+ TK_HINT_BLACK_ALBEDO_TEXTURE,
+ TK_HINT_COLOR,
+ TK_HINT_RANGE,
+ TK_FILTER_NEAREST,
+ TK_FILTER_LINEAR,
+ TK_FILTER_NEAREST_MIPMAP,
+ TK_FILTER_LINEAR_MIPMAP,
+ TK_FILTER_NEAREST_MIPMAP_ANISO,
+ TK_FILTER_LINEAR_MIPMAP_ANISO,
+ TK_REPEAT_ENABLE,
+ TK_REPEAT_DISABLE,
+ TK_SHADER_TYPE,
+ TK_CURSOR,
+ TK_ERROR,
+ TK_EOF,
+ TK_MAX
+ };
+
+/* COMPILER */
+
+// lame work around to Apple defining this as a macro in 10.12 SDK
+#ifdef TYPE_BOOL
+#undef TYPE_BOOL
+#endif
+
+ enum DataType {
+ TYPE_VOID,
+ TYPE_BOOL,
+ TYPE_BVEC2,
+ TYPE_BVEC3,
+ TYPE_BVEC4,
+ TYPE_INT,
+ TYPE_IVEC2,
+ TYPE_IVEC3,
+ TYPE_IVEC4,
+ TYPE_UINT,
+ TYPE_UVEC2,
+ TYPE_UVEC3,
+ TYPE_UVEC4,
+ TYPE_FLOAT,
+ TYPE_VEC2,
+ TYPE_VEC3,
+ TYPE_VEC4,
+ TYPE_MAT2,
+ TYPE_MAT3,
+ TYPE_MAT4,
+ TYPE_SAMPLER2D,
+ TYPE_ISAMPLER2D,
+ TYPE_USAMPLER2D,
+ TYPE_SAMPLER2DARRAY,
+ TYPE_ISAMPLER2DARRAY,
+ TYPE_USAMPLER2DARRAY,
+ TYPE_SAMPLER3D,
+ TYPE_ISAMPLER3D,
+ TYPE_USAMPLER3D,
+ TYPE_SAMPLERCUBE,
+ TYPE_STRUCT,
+ };
+
+ enum DataPrecision {
+ PRECISION_LOWP,
+ PRECISION_MEDIUMP,
+ PRECISION_HIGHP,
+ PRECISION_DEFAULT,
+ };
+
+ enum DataInterpolation {
+ INTERPOLATION_FLAT,
+ INTERPOLATION_SMOOTH,
+ };
+
+ enum Operator {
+ OP_EQUAL,
+ OP_NOT_EQUAL,
+ OP_LESS,
+ OP_LESS_EQUAL,
+ OP_GREATER,
+ OP_GREATER_EQUAL,
+ OP_AND,
+ OP_OR,
+ OP_NOT,
+ OP_NEGATE,
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_SHIFT_LEFT,
+ OP_SHIFT_RIGHT,
+ OP_ASSIGN,
+ OP_ASSIGN_ADD,
+ OP_ASSIGN_SUB,
+ OP_ASSIGN_MUL,
+ OP_ASSIGN_DIV,
+ OP_ASSIGN_MOD,
+ OP_ASSIGN_SHIFT_LEFT,
+ OP_ASSIGN_SHIFT_RIGHT,
+ OP_ASSIGN_BIT_AND,
+ OP_ASSIGN_BIT_OR,
+ OP_ASSIGN_BIT_XOR,
+ OP_BIT_AND,
+ OP_BIT_OR,
+ OP_BIT_XOR,
+ OP_BIT_INVERT,
+ OP_INCREMENT,
+ OP_DECREMENT,
+ OP_SELECT_IF,
+ OP_SELECT_ELSE, //used only internally, then only IF appears with 3 arguments
+ OP_POST_INCREMENT,
+ OP_POST_DECREMENT,
+ OP_CALL,
+ OP_CONSTRUCT,
+ OP_STRUCT,
+ OP_INDEX,
+ OP_MAX
+ };
+
+ enum FlowOperation {
+ FLOW_OP_IF,
+ FLOW_OP_RETURN,
+ FLOW_OP_FOR,
+ FLOW_OP_WHILE,
+ FLOW_OP_DO,
+ FLOW_OP_BREAK,
+ FLOW_OP_SWITCH,
+ FLOW_OP_CASE,
+ FLOW_OP_DEFAULT,
+ FLOW_OP_CONTINUE,
+ FLOW_OP_DISCARD
+ };
+
+ enum ArgumentQualifier {
+ ARGUMENT_QUALIFIER_IN,
+ ARGUMENT_QUALIFIER_OUT,
+ ARGUMENT_QUALIFIER_INOUT,
+ };
+
+ enum SubClassTag {
+ TAG_GLOBAL,
+ TAG_ARRAY,
+ };
+
+ enum TextureFilter {
+ FILTER_NEAREST,
+ FILTER_LINEAR,
+ FILTER_NEAREST_MIPMAP,
+ FILTER_LINEAR_MIPMAP,
+ FILTER_NEAREST_MIPMAP_ANISO,
+ FILTER_LINEAR_MIPMAP_ANISO,
+ FILTER_DEFAULT,
+ };
+
+ enum TextureRepeat {
+ REPEAT_DISABLE,
+ REPEAT_ENABLE,
+ REPEAT_DEFAULT,
+ };
+
+ struct Node {
+ Node *next;
+
+ enum Type {
+ TYPE_SHADER,
+ TYPE_FUNCTION,
+ TYPE_BLOCK,
+ TYPE_VARIABLE,
+ TYPE_VARIABLE_DECLARATION,
+ TYPE_CONSTANT,
+ TYPE_OPERATOR,
+ TYPE_CONTROL_FLOW,
+ TYPE_MEMBER,
+ TYPE_ARRAY,
+ TYPE_ARRAY_DECLARATION,
+ TYPE_ARRAY_CONSTRUCT,
+ TYPE_STRUCT,
+ };
+
+ Type type;
+
+ virtual DataType get_datatype() const { return TYPE_VOID; }
+ virtual String get_datatype_name() const { return ""; }
+
+ Node(Type t) :
+ next(nullptr),
+ type(t) {}
+ virtual ~Node() {}
+ };
+
+ template <class T>
+ T *alloc_node() {
+ T *node = memnew(T);
+ node->next = nodes;
+ nodes = node;
+ return node;
+ }
+
+ Node *nodes;
+
+ struct OperatorNode : public Node {
+ DataType return_cache;
+ DataPrecision return_precision_cache;
+ Operator op;
+ StringName struct_name;
+ Vector<Node *> arguments;
+ virtual DataType get_datatype() const { return return_cache; }
+ virtual String get_datatype_name() const { return String(struct_name); }
+
+ OperatorNode() :
+ Node(TYPE_OPERATOR),
+ return_cache(TYPE_VOID),
+ return_precision_cache(PRECISION_DEFAULT),
+ op(OP_EQUAL),
+ struct_name("") {}
+ };
+
+ struct VariableNode : public Node {
+ DataType datatype_cache;
+ StringName name;
+ StringName struct_name;
+ virtual DataType get_datatype() const { return datatype_cache; }
+ virtual String get_datatype_name() const { return String(struct_name); }
+ bool is_const;
+
+ VariableNode() :
+ Node(TYPE_VARIABLE),
+ datatype_cache(TYPE_VOID),
+ is_const(false) {}
+ };
+
+ struct VariableDeclarationNode : public Node {
+ DataPrecision precision;
+ DataType datatype;
+ String struct_name;
+ bool is_const;
+
+ struct Declaration {
+ StringName name;
+ Node *initializer;
+ };
+
+ Vector<Declaration> declarations;
+ virtual DataType get_datatype() const { return datatype; }
+
+ VariableDeclarationNode() :
+ Node(TYPE_VARIABLE_DECLARATION),
+ precision(PRECISION_DEFAULT),
+ datatype(TYPE_VOID),
+ is_const(false) {}
+ };
+
+ struct ArrayNode : public Node {
+ DataType datatype_cache;
+ StringName struct_name;
+ StringName name;
+ Node *index_expression;
+ Node *call_expression;
+ bool is_const;
+
+ virtual DataType get_datatype() const { return datatype_cache; }
+ virtual String get_datatype_name() const { return String(struct_name); }
+
+ ArrayNode() :
+ Node(TYPE_ARRAY),
+ datatype_cache(TYPE_VOID),
+ index_expression(nullptr),
+ call_expression(nullptr),
+ is_const(false) {}
+ };
+
+ struct ArrayConstructNode : public Node {
+ DataType datatype;
+ String struct_name;
+ Vector<Node *> initializer;
+
+ ArrayConstructNode() :
+ Node(TYPE_ARRAY_CONSTRUCT),
+ datatype(TYPE_VOID) {
+ }
+ };
+
+ struct ArrayDeclarationNode : public Node {
+ DataPrecision precision;
+ DataType datatype;
+ String struct_name;
+ bool is_const;
+
+ struct Declaration {
+ StringName name;
+ uint32_t size;
+ Vector<Node *> initializer;
+ };
+
+ Vector<Declaration> declarations;
+ virtual DataType get_datatype() const { return datatype; }
+
+ ArrayDeclarationNode() :
+ Node(TYPE_ARRAY_DECLARATION),
+ precision(PRECISION_DEFAULT),
+ datatype(TYPE_VOID),
+ is_const(false) {}
+ };
+
+ struct ConstantNode : public Node {
+ DataType datatype;
+
+ union Value {
+ bool boolean;
+ float real;
+ int32_t sint;
+ uint32_t uint;
+ };
+
+ Vector<Value> values;
+ virtual DataType get_datatype() const { return datatype; }
+
+ ConstantNode() :
+ Node(TYPE_CONSTANT),
+ datatype(TYPE_VOID) {}
+ };
+
+ struct FunctionNode;
+
+ struct BlockNode : public Node {
+ FunctionNode *parent_function;
+ BlockNode *parent_block;
+
+ enum BlockType {
+ BLOCK_TYPE_STANDART,
+ BLOCK_TYPE_FOR,
+ BLOCK_TYPE_SWITCH,
+ BLOCK_TYPE_CASE,
+ BLOCK_TYPE_DEFAULT,
+ };
+
+ int block_type;
+ SubClassTag block_tag;
+
+ struct Variable {
+ DataType type;
+ StringName struct_name;
+ DataPrecision precision;
+ int line; //for completion
+ int array_size;
+ bool is_const;
+ };
+
+ Map<StringName, Variable> variables;
+ List<Node *> statements;
+ bool single_statement;
+
+ BlockNode() :
+ Node(TYPE_BLOCK),
+ parent_function(nullptr),
+ parent_block(nullptr),
+ block_type(BLOCK_TYPE_STANDART),
+ block_tag(SubClassTag::TAG_GLOBAL),
+ single_statement(false) {}
+ };
+
+ struct ControlFlowNode : public Node {
+ FlowOperation flow_op;
+ Vector<Node *> expressions;
+ Vector<BlockNode *> blocks;
+
+ ControlFlowNode() :
+ Node(TYPE_CONTROL_FLOW),
+ flow_op(FLOW_OP_IF) {}
+ };
+
+ struct MemberNode : public Node {
+ DataType basetype;
+ bool basetype_const;
+ StringName base_struct_name;
+ DataPrecision precision;
+ DataType datatype;
+ int array_size;
+ StringName struct_name;
+ StringName name;
+ Node *owner;
+ Node *index_expression;
+ bool has_swizzling_duplicates;
+
+ virtual DataType get_datatype() const { return datatype; }
+ virtual String get_datatype_name() const { return String(struct_name); }
+
+ MemberNode() :
+ Node(TYPE_MEMBER),
+ basetype(TYPE_VOID),
+ basetype_const(false),
+ datatype(TYPE_VOID),
+ array_size(0),
+ owner(nullptr),
+ index_expression(nullptr),
+ has_swizzling_duplicates(false) {}
+ };
+
+ struct StructNode : public Node {
+
+ List<MemberNode *> members;
+ StructNode() :
+ Node(TYPE_STRUCT) {}
+ };
+
+ struct FunctionNode : public Node {
+
+ struct Argument {
+ ArgumentQualifier qualifier;
+ StringName name;
+ DataType type;
+ StringName type_str;
+ DataPrecision precision;
+ //for passing textures as arguments
+ bool tex_argument_check;
+ TextureFilter tex_argument_filter;
+ TextureRepeat tex_argument_repeat;
+ bool tex_builtin_check;
+ StringName tex_builtin;
+
+ Map<StringName, Set<int>> tex_argument_connect;
+ };
+
+ StringName name;
+ DataType return_type;
+ StringName return_struct_name;
+ DataPrecision return_precision;
+ Vector<Argument> arguments;
+ BlockNode *body;
+ bool can_discard;
+
+ FunctionNode() :
+ Node(TYPE_FUNCTION),
+ return_type(TYPE_VOID),
+ return_precision(PRECISION_DEFAULT),
+ body(nullptr),
+ can_discard(false) {}
+ };
+
+ struct ShaderNode : public Node {
+
+ struct Constant {
+ DataType type;
+ StringName type_str;
+ DataPrecision precision;
+ ConstantNode *initializer;
+ };
+
+ struct Function {
+ StringName name;
+ FunctionNode *function;
+ Set<StringName> uses_function;
+ bool callable;
+ };
+
+ struct Struct {
+ StringName name;
+ StructNode *shader_struct;
+ };
+
+ struct Varying {
+ DataType type;
+ DataInterpolation interpolation;
+ DataPrecision precision;
+ int array_size;
+
+ Varying() :
+ type(TYPE_VOID),
+ interpolation(INTERPOLATION_FLAT),
+ precision(PRECISION_DEFAULT),
+ array_size(0) {}
+ };
+
+ struct Uniform {
+ enum Hint {
+ HINT_NONE,
+ HINT_COLOR,
+ HINT_RANGE,
+ HINT_ALBEDO,
+ HINT_BLACK_ALBEDO,
+ HINT_NORMAL,
+ HINT_ROUGHNESS_NORMAL,
+ HINT_ROUGHNESS_R,
+ HINT_ROUGHNESS_G,
+ HINT_ROUGHNESS_B,
+ HINT_ROUGHNESS_A,
+ HINT_ROUGHNESS_GRAY,
+ HINT_BLACK,
+ HINT_WHITE,
+ HINT_ANISO,
+ HINT_MAX
+ };
+
+ int order;
+ int texture_order;
+ DataType type;
+ DataPrecision precision;
+ Vector<ConstantNode::Value> default_value;
+ Hint hint;
+ TextureFilter filter;
+ TextureRepeat repeat;
+ float hint_range[3];
+
+ Uniform() :
+ order(0),
+ texture_order(0),
+ type(TYPE_VOID),
+ precision(PRECISION_DEFAULT),
+ hint(HINT_NONE),
+ filter(FILTER_DEFAULT),
+ repeat(REPEAT_DEFAULT) {
+ hint_range[0] = 0.0f;
+ hint_range[1] = 1.0f;
+ hint_range[2] = 0.001f;
+ }
+ };
+
+ Map<StringName, Constant> constants;
+ Map<StringName, Varying> varyings;
+ Map<StringName, Uniform> uniforms;
+ Map<StringName, Struct> structs;
+ Vector<StringName> render_modes;
+
+ Vector<Function> functions;
+ Vector<Struct> vstructs;
+
+ ShaderNode() :
+ Node(TYPE_SHADER) {}
+ };
+
+ struct Expression {
+ bool is_op;
+ union {
+ Operator op;
+ Node *node;
+ };
+ };
+
+ struct VarInfo {
+ StringName name;
+ DataType type;
+ };
+
+ enum CompletionType {
+ COMPLETION_NONE,
+ COMPLETION_RENDER_MODE,
+ COMPLETION_MAIN_FUNCTION,
+ COMPLETION_IDENTIFIER,
+ COMPLETION_FUNCTION_CALL,
+ COMPLETION_CALL_ARGUMENTS,
+ COMPLETION_INDEX,
+ COMPLETION_STRUCT,
+ };
+
+ struct Token {
+ TokenType type;
+ StringName text;
+ double constant;
+ uint16_t line;
+ };
+
+ static String get_operator_text(Operator p_op);
+ static String get_token_text(Token p_token);
+
+ static bool is_token_datatype(TokenType p_type);
+ static bool is_token_variable_datatype(TokenType p_type);
+ static DataType get_token_datatype(TokenType p_type);
+ static bool is_token_interpolation(TokenType p_type);
+ static DataInterpolation get_token_interpolation(TokenType p_type);
+ static bool is_token_precision(TokenType p_type);
+ static DataPrecision get_token_precision(TokenType p_type);
+ static String get_precision_name(DataPrecision p_type);
+ static String get_datatype_name(DataType p_type);
+ static bool is_token_nonvoid_datatype(TokenType p_type);
+ static bool is_token_operator(TokenType p_type);
+
+ static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr);
+ static DataType get_scalar_type(DataType p_type);
+ static int get_cardinality(DataType p_type);
+ static bool is_scalar_type(DataType p_type);
+ static bool is_sampler_type(DataType p_type);
+ static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
+ static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
+ static uint32_t get_type_size(DataType p_type);
+
+ static void get_keyword_list(List<String> *r_keywords);
+ static void get_builtin_funcs(List<String> *r_keywords);
+
+ struct BuiltInInfo {
+ DataType type;
+ bool constant;
+
+ BuiltInInfo() :
+ type(TYPE_VOID),
+ constant(false) {}
+
+ BuiltInInfo(DataType p_type, bool p_constant = false) :
+ type(p_type),
+ constant(p_constant) {}
+ };
+
+ struct FunctionInfo {
+ Map<StringName, BuiltInInfo> built_ins;
+ bool can_discard;
+ };
+ static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
+
+private:
+ struct KeyWord {
+ TokenType token;
+ const char *text;
+ };
+
+ static const KeyWord keyword_list[];
+
+ bool error_set;
+ String error_str;
+ int error_line;
+
+ String code;
+ int char_idx;
+ int tk_line;
+
+ StringName current_function;
+
+ struct TkPos {
+ int char_idx;
+ int tk_line;
+ };
+
+ TkPos _get_tkpos() {
+ TkPos tkp;
+ tkp.char_idx = char_idx;
+ tkp.tk_line = tk_line;
+ return tkp;
+ }
+
+ void _set_tkpos(TkPos p_pos) {
+ char_idx = p_pos.char_idx;
+ tk_line = p_pos.tk_line;
+ }
+
+ void _set_error(const String &p_str) {
+ if (error_set)
+ return;
+
+ error_line = tk_line;
+ error_set = true;
+ error_str = p_str;
+ }
+
+ static const char *token_names[TK_MAX];
+
+ Token _make_token(TokenType p_type, const StringName &p_text = StringName());
+ Token _get_token();
+
+ ShaderNode *shader;
+
+ enum IdentifierType {
+ IDENTIFIER_FUNCTION,
+ IDENTIFIER_UNIFORM,
+ IDENTIFIER_VARYING,
+ IDENTIFIER_FUNCTION_ARGUMENT,
+ IDENTIFIER_LOCAL_VAR,
+ IDENTIFIER_BUILTIN_VAR,
+ IDENTIFIER_CONSTANT,
+ };
+
+ bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr);
+ bool _is_operator_assign(Operator p_op) const;
+ bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = nullptr);
+ bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr);
+
+ struct BuiltinFuncDef {
+ enum { MAX_ARGS = 5 };
+ const char *name;
+ DataType rettype;
+ const DataType args[MAX_ARGS];
+ SubClassTag tag;
+ bool high_end;
+ };
+
+ struct BuiltinFuncOutArgs { //arguments used as out in built in functions
+ const char *name;
+ int argument;
+ };
+
+ CompletionType completion_type;
+ int completion_line;
+ BlockNode *completion_block;
+ DataType completion_base;
+ SubClassTag completion_class;
+ StringName completion_function;
+ StringName completion_struct;
+ int completion_argument;
+
+ bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
+ static const BuiltinFuncDef builtin_func_defs[];
+ static const BuiltinFuncOutArgs builtin_func_out_args[];
+
+ Error _validate_datatype(DataType p_type);
+ bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
+
+ bool _validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
+ bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, 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);
+
+ Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
+ ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
+
+ Node *_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
+ Error _parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
+ String _get_shader_type_list(const Set<String> &p_shader_types) const;
+ String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
+
+ Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types);
+
+ Error _find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op);
+ Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op);
+
+public:
+ //static void get_keyword_list(ShaderType p_type,List<String> *p_keywords);
+
+ 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);
+ Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint);
+
+ String get_error_text();
+ int get_error_line();
+
+ ShaderNode *get_shader();
+
+ String token_debug(const String &p_code);
+
+ ShaderLanguage();
+ ~ShaderLanguage();
+};
+
+#endif // SHADER_LANGUAGE_H
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
new file mode 100644
index 0000000000..de69fea16f
--- /dev/null
+++ b/servers/rendering/shader_types.cpp
@@ -0,0 +1,334 @@
+/*************************************************************************/
+/* shader_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "shader_types.h"
+
+const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(RS::ShaderMode p_mode) {
+
+ return shader_modes[p_mode].functions;
+}
+
+const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) {
+
+ return shader_modes[p_mode].modes;
+}
+
+const Set<String> &ShaderTypes::get_types() {
+ return shader_types;
+}
+
+ShaderTypes *ShaderTypes::singleton = nullptr;
+
+static ShaderLanguage::BuiltInInfo constt(ShaderLanguage::DataType p_type) {
+
+ return ShaderLanguage::BuiltInInfo(p_type, true);
+}
+
+ShaderTypes::ShaderTypes() {
+ singleton = this;
+
+ /*************** SPATIAL ***********************/
+
+ shader_modes[RS::SHADER_SPATIAL].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["POSITION"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["UV2"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
+
+ //builtins
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["FRONT_FACING"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["METALLIC"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SPECULAR"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RIM"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RIM_TINT"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT_GLOSS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY_FLOW"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_DEPTH"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_CURVE"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_BOOST"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BACKLIGHT"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
+
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_NORMAL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT3);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].can_discard = true;
+
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
+
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ATTENUATION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALBEDO"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["BACKLIGHT"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
+
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
+
+ //order used puts first enum mode (default) first
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mix");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_add");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_sub");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mul");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_opaque");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_always");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_never");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_prepass_alpha");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_test_disabled");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("sss_mode_skin");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_back");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_front");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("unshaded");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("wireframe");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_oren_nayar");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_burley");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_toon");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_schlick_ggx");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_blinn");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_phong");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_toon");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_disabled");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("skip_vertex_transform");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("world_vertex_coords");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("ensure_correct_normals");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadows_disabled");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("ambient_light_disabled");
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity");
+
+ shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting");
+
+ /************ CANVAS ITEM **************************/
+
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
+
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["CANVAS_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["SCREEN_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
+ 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["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["LIGHT_VERTEX"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
+
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_MODULATE"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
+ 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].modes.push_back("skip_vertex_transform");
+
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_mix");
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_add");
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_sub");
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_mul");
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_premul_alpha");
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_disabled");
+
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("unshaded");
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("light_only");
+
+ /************ PARTICLES **************************/
+
+ shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["vertex"].can_discard = false;
+
+ shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_force");
+ shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_velocity");
+ shader_modes[RS::SHADER_PARTICLES].modes.push_back("keep_data");
+
+ /************ SKY **************************/
+
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["RADIANCE"] = constt(ShaderLanguage::TYPE_SAMPLERCUBE);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["AT_HALF_RES_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["AT_QUARTER_RES_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["AT_CUBEMAP_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT0_ENABLED"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT0_DIRECTION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT0_ENERGY"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT0_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT1_ENABLED"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT1_DIRECTION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT1_ENERGY"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT1_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT2_ENABLED"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT2_DIRECTION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT2_ENERGY"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT2_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_ENABLED"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_DIRECTION"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_ENERGY"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
+
+ 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].modes.push_back("use_half_res_pass");
+ shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
+
+ shader_types.insert("spatial");
+ shader_types.insert("canvas_item");
+ shader_types.insert("particles");
+ shader_types.insert("sky");
+}
diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h
new file mode 100644
index 0000000000..499a761265
--- /dev/null
+++ b/servers/rendering/shader_types.h
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* shader_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 SHADERTYPES_H
+#define SHADERTYPES_H
+
+#include "core/ordered_hash_map.h"
+#include "servers/rendering_server.h"
+#include "shader_language.h"
+
+class ShaderTypes {
+
+ struct Type {
+
+ Map<StringName, ShaderLanguage::FunctionInfo> functions;
+ Vector<StringName> modes;
+ };
+
+ Map<RS::ShaderMode, Type> shader_modes;
+
+ static ShaderTypes *singleton;
+
+ Set<String> shader_types;
+
+public:
+ static ShaderTypes *get_singleton() { return singleton; }
+
+ const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode);
+ const Vector<StringName> &get_modes(RS::ShaderMode p_mode);
+ const Set<String> &get_types();
+
+ ShaderTypes();
+};
+
+#endif // SHADERTYPES_H
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
new file mode 100644
index 0000000000..c288c2986e
--- /dev/null
+++ b/servers/rendering_server.cpp
@@ -0,0 +1,2378 @@
+/*************************************************************************/
+/* rendering_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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.h"
+
+#include "core/method_bind_ext.gen.inc"
+#include "core/project_settings.h"
+
+RenderingServer *RenderingServer::singleton = nullptr;
+RenderingServer *(*RenderingServer::create_func)() = nullptr;
+
+RenderingServer *RenderingServer::get_singleton() {
+
+ return singleton;
+}
+
+RenderingServer *RenderingServer::create() {
+
+ ERR_FAIL_COND_V(singleton, nullptr);
+
+ if (create_func)
+ return create_func();
+
+ return nullptr;
+}
+
+Array RenderingServer::_texture_debug_usage_bind() {
+
+ List<TextureInfo> list;
+ texture_debug_usage(&list);
+ Array arr;
+ for (const List<TextureInfo>::Element *E = list.front(); E; E = E->next()) {
+
+ Dictionary dict;
+ dict["texture"] = E->get().texture;
+ dict["width"] = E->get().width;
+ dict["height"] = E->get().height;
+ dict["depth"] = E->get().depth;
+ dict["format"] = E->get().format;
+ dict["bytes"] = E->get().bytes;
+ dict["path"] = E->get().path;
+ arr.push_back(dict);
+ }
+ return arr;
+}
+
+Array RenderingServer::_shader_get_param_list_bind(RID p_shader) const {
+
+ List<PropertyInfo> l;
+ shader_get_param_list(p_shader, &l);
+ return convert_property_list(&l);
+}
+
+static Array to_array(const Vector<ObjectID> &ids) {
+ Array a;
+ a.resize(ids.size());
+ for (int i = 0; i < ids.size(); ++i) {
+ a[i] = ids[i];
+ }
+ return a;
+}
+
+Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const {
+
+ Vector<ObjectID> ids = instances_cull_aabb(p_aabb, p_scenario);
+ return to_array(ids);
+}
+
+Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
+
+ Vector<ObjectID> ids = instances_cull_ray(p_from, p_to, p_scenario);
+ return to_array(ids);
+}
+
+Array RenderingServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const {
+
+ Vector<Plane> planes;
+ for (int i = 0; i < p_convex.size(); ++i) {
+ Variant v = p_convex[i];
+ ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, Array());
+ planes.push_back(v);
+ }
+
+ Vector<ObjectID> ids = instances_cull_convex(planes, p_scenario);
+ return to_array(ids);
+}
+
+RID RenderingServer::get_test_texture() {
+
+ if (test_texture.is_valid()) {
+ return test_texture;
+ };
+
+#define TEST_TEXTURE_SIZE 256
+
+ Vector<uint8_t> test_data;
+ test_data.resize(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 3);
+
+ {
+ uint8_t *w = test_data.ptrw();
+
+ for (int x = 0; x < TEST_TEXTURE_SIZE; x++) {
+
+ for (int y = 0; y < TEST_TEXTURE_SIZE; y++) {
+
+ Color c;
+ int r = 255 - (x + y) / 2;
+
+ if ((x % (TEST_TEXTURE_SIZE / 8)) < 2 || (y % (TEST_TEXTURE_SIZE / 8)) < 2) {
+
+ c.r = y;
+ c.g = r;
+ c.b = x;
+
+ } else {
+
+ c.r = r;
+ c.g = x;
+ c.b = y;
+ }
+
+ w[(y * TEST_TEXTURE_SIZE + x) * 3 + 0] = uint8_t(CLAMP(c.r * 255, 0, 255));
+ w[(y * TEST_TEXTURE_SIZE + x) * 3 + 1] = uint8_t(CLAMP(c.g * 255, 0, 255));
+ w[(y * TEST_TEXTURE_SIZE + x) * 3 + 2] = uint8_t(CLAMP(c.b * 255, 0, 255));
+ }
+ }
+ }
+
+ Ref<Image> data = memnew(Image(TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, false, Image::FORMAT_RGB8, test_data));
+
+ test_texture = texture_2d_create(data);
+
+ return test_texture;
+}
+
+void RenderingServer::_free_internal_rids() {
+
+ if (test_texture.is_valid())
+ free(test_texture);
+ if (white_texture.is_valid())
+ free(white_texture);
+ if (test_material.is_valid())
+ free(test_material);
+}
+
+RID RenderingServer::_make_test_cube() {
+
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+ Vector<float> tangents;
+ Vector<Vector3> uvs;
+
+#define ADD_VTX(m_idx) \
+ vertices.push_back(face_points[m_idx]); \
+ normals.push_back(normal_points[m_idx]); \
+ tangents.push_back(normal_points[m_idx][1]); \
+ tangents.push_back(normal_points[m_idx][2]); \
+ tangents.push_back(normal_points[m_idx][0]); \
+ tangents.push_back(1.0); \
+ uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0));
+
+ for (int i = 0; i < 6; i++) {
+
+ Vector3 face_points[4];
+ Vector3 normal_points[4];
+ float uv_points[8] = { 0, 0, 0, 1, 1, 1, 1, 0 };
+
+ for (int j = 0; j < 4; j++) {
+
+ float v[3];
+ v[0] = 1.0;
+ v[1] = 1 - 2 * ((j >> 1) & 1);
+ v[2] = v[1] * (1 - 2 * (j & 1));
+
+ for (int k = 0; k < 3; k++) {
+
+ if (i < 3)
+ face_points[j][(i + k) % 3] = v[k];
+ else
+ face_points[3 - j][(i + k) % 3] = -v[k];
+ }
+ normal_points[j] = Vector3();
+ normal_points[j][i % 3] = (i >= 3 ? -1 : 1);
+ }
+
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+ }
+
+ RID test_cube = mesh_create();
+
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+ d[RenderingServer::ARRAY_NORMAL] = normals;
+ d[RenderingServer::ARRAY_TANGENT] = tangents;
+ d[RenderingServer::ARRAY_TEX_UV] = uvs;
+ d[RenderingServer::ARRAY_VERTEX] = vertices;
+
+ Vector<int> indices;
+ indices.resize(vertices.size());
+ for (int i = 0; i < vertices.size(); i++)
+ indices.set(i, i);
+ d[RenderingServer::ARRAY_INDEX] = indices;
+
+ mesh_add_surface_from_arrays(test_cube, PRIMITIVE_TRIANGLES, d);
+
+ /*
+ test_material = fixed_material_create();
+ //material_set_flag(material, MATERIAL_FLAG_BILLBOARD_TOGGLE,true);
+ fixed_material_set_texture( test_material, FIXED_MATERIAL_PARAM_DIFFUSE, get_test_texture() );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_SPECULAR_EXP, 70 );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_EMISSION, Color(0.2,0.2,0.2) );
+
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_DIFFUSE, Color(1, 1, 1) );
+ fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_SPECULAR, Color(1,1,1) );
+*/
+ mesh_surface_set_material(test_cube, 0, test_material);
+
+ return test_cube;
+}
+
+RID RenderingServer::make_sphere_mesh(int p_lats, int p_lons, float p_radius) {
+
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+
+ for (int i = 1; i <= p_lats; i++) {
+ double lat0 = Math_PI * (-0.5 + (double)(i - 1) / p_lats);
+ double z0 = Math::sin(lat0);
+ double zr0 = Math::cos(lat0);
+
+ double lat1 = Math_PI * (-0.5 + (double)i / p_lats);
+ double z1 = Math::sin(lat1);
+ double zr1 = Math::cos(lat1);
+
+ for (int j = p_lons; j >= 1; j--) {
+
+ double lng0 = 2 * Math_PI * (double)(j - 1) / p_lons;
+ double x0 = Math::cos(lng0);
+ double y0 = Math::sin(lng0);
+
+ double lng1 = 2 * Math_PI * (double)(j) / p_lons;
+ double x1 = Math::cos(lng1);
+ double y1 = Math::sin(lng1);
+
+ Vector3 v[4] = {
+ Vector3(x1 * zr0, z0, y1 * zr0),
+ Vector3(x1 * zr1, z1, y1 * zr1),
+ Vector3(x0 * zr1, z1, y0 * zr1),
+ Vector3(x0 * zr0, z0, y0 * zr0)
+ };
+
+#define ADD_POINT(m_idx) \
+ normals.push_back(v[m_idx]); \
+ vertices.push_back(v[m_idx] * p_radius);
+
+ ADD_POINT(0);
+ ADD_POINT(1);
+ ADD_POINT(2);
+
+ ADD_POINT(2);
+ ADD_POINT(3);
+ ADD_POINT(0);
+ }
+ }
+
+ RID mesh = mesh_create();
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+
+ d[ARRAY_VERTEX] = vertices;
+ d[ARRAY_NORMAL] = normals;
+
+ mesh_add_surface_from_arrays(mesh, PRIMITIVE_TRIANGLES, d);
+
+ return mesh;
+}
+
+RID RenderingServer::get_white_texture() {
+
+ if (white_texture.is_valid())
+ return white_texture;
+
+ Vector<uint8_t> wt;
+ wt.resize(16 * 3);
+ {
+ uint8_t *w = wt.ptrw();
+ for (int i = 0; i < 16 * 3; i++)
+ w[i] = 255;
+ }
+ Ref<Image> white = memnew(Image(4, 4, 0, Image::FORMAT_RGB8, wt));
+ white_texture = texture_2d_create(white);
+ return white_texture;
+}
+
+#define SMALL_VEC2 Vector2(0.00001, 0.00001)
+#define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001)
+
+Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) {
+
+ uint8_t *vw = r_vertex_array.ptrw();
+
+ uint8_t *iw = nullptr;
+ if (r_index_array.size()) {
+ iw = r_index_array.ptrw();
+ }
+
+ int max_bone = 0;
+
+ for (int ai = 0; ai < RS::ARRAY_MAX; ai++) {
+
+ if (!(p_format & (1 << ai))) // no array
+ continue;
+
+ switch (ai) {
+
+ case RS::ARRAY_VERTEX: {
+
+ if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+
+ Vector<Vector2> array = p_arrays[ai];
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
+
+ const Vector2 *src = array.ptr();
+
+ // setting vertices means regenerating the AABB
+ Rect2 aabb;
+
+ {
+ 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_stride], vector, sizeof(float) * 2);
+
+ if (i == 0) {
+
+ aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size
+ } else {
+
+ aabb.expand_to(src[i]);
+ }
+ }
+ }
+
+ r_aabb = AABB(Vector3(aabb.position.x, aabb.position.y, 0), Vector3(aabb.size.x, aabb.size.y, 0));
+
+ } else {
+ Vector<Vector3> array = p_arrays[ai];
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
+
+ const Vector3 *src = array.ptr();
+
+ // setting vertices means regenerating the AABB
+ AABB aabb;
+
+ {
+ 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_stride], vector, sizeof(float) * 3);
+
+ if (i == 0) {
+
+ aabb = AABB(src[i], SMALL_VEC3);
+ } else {
+
+ aabb.expand_to(src[i]);
+ }
+ }
+ }
+
+ r_aabb = aabb;
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<Vector3> array = p_arrays[ai];
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
+
+ const Vector3 *src = array.ptr();
+
+ // setting vertices means regenerating the AABB
+
+ if (p_format & ARRAY_COMPRESS_NORMAL) {
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ int8_t vector[4] = {
+ (int8_t)CLAMP(src[i].x * 127, -128, 127),
+ (int8_t)CLAMP(src[i].y * 127, -128, 127),
+ (int8_t)CLAMP(src[i].z * 127, -128, 127),
+ 0,
+ };
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], vector, 4);
+ }
+
+ } else {
+ 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_stride], vector, 3 * 4);
+ }
+ }
+
+ } break;
+
+ case RS::ARRAY_TANGENT: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<real_t> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
+
+ const real_t *src = array.ptr();
+
+ if (p_format & ARRAY_COMPRESS_TANGENT) {
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+ int8_t xyzw[4] = {
+ (int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
+ (int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
+ (int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
+ (int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
+ };
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4);
+ }
+
+ } else {
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ float xyzw[4] = {
+ src[i * 4 + 0],
+ src[i * 4 + 1],
+ src[i * 4 + 2],
+ src[i * 4 + 3]
+ };
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4 * 4);
+ }
+ }
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_COLOR_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<Color> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
+
+ const Color *src = array.ptr();
+
+ if (p_format & ARRAY_COMPRESS_COLOR) {
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ uint8_t colors[4];
+
+ for (int j = 0; j < 4; j++) {
+
+ colors[j] = CLAMP(int((src[i][j]) * 255.0), 0, 255);
+ }
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], colors, 4);
+ }
+ } else {
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], &src[i], 4 * 4);
+ }
+ }
+
+ } break;
+ case RS::ARRAY_TEX_UV: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<Vector2> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
+
+ const Vector2 *src = array.ptr();
+
+ if (p_format & ARRAY_COMPRESS_TEX_UV) {
+
+ 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(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2);
+ }
+
+ } else {
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ float uv[2] = { src[i].x, src[i].y };
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4);
+ }
+ }
+
+ } break;
+
+ case RS::ARRAY_TEX_UV2: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<Vector2> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
+
+ const Vector2 *src = array.ptr();
+
+ if (p_format & ARRAY_COMPRESS_TEX_UV2) {
+
+ 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(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2);
+ }
+
+ } else {
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ float uv[2] = { src[i].x, src[i].y };
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4);
+ }
+ }
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<real_t> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER);
+
+ const real_t *src = array.ptr();
+
+ {
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ uint16_t data[RS::ARRAY_WEIGHTS_SIZE];
+ for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) {
+ data[j] = CLAMP(src[i * RS::ARRAY_WEIGHTS_SIZE + j] * 65535, 0, 65535);
+ }
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4);
+ }
+ }
+
+ } break;
+ case RS::ARRAY_BONES: {
+
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_INT32_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<int> array = p_arrays[ai];
+
+ ERR_FAIL_COND_V(array.size() != p_vertex_array_len * RS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER);
+
+ const int *src = array.ptr();
+
+ for (int i = 0; i < p_vertex_array_len; i++) {
+
+ uint16_t data[RS::ARRAY_WEIGHTS_SIZE];
+ for (int j = 0; j < RS::ARRAY_WEIGHTS_SIZE; j++) {
+ data[j] = src[i * RS::ARRAY_WEIGHTS_SIZE + j];
+ max_bone = MAX(data[j], max_bone);
+ }
+
+ copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4);
+ }
+
+ } break;
+ case RS::ARRAY_INDEX: {
+
+ ERR_FAIL_NULL_V(iw, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V(p_index_array_len <= 0, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_INT32_ARRAY, ERR_INVALID_PARAMETER);
+
+ Vector<int> indices = p_arrays[ai];
+ ERR_FAIL_COND_V(indices.size() == 0, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(indices.size() != p_index_array_len, ERR_INVALID_PARAMETER);
+
+ /* determine whether using 16 or 32 bits indices */
+
+ const int *src = indices.ptr();
+
+ for (int i = 0; i < p_index_array_len; i++) {
+
+ if (p_vertex_array_len < (1 << 16)) {
+ uint16_t v = src[i];
+
+ copymem(&iw[i * 2], &v, 2);
+ } else {
+ uint32_t v = src[i];
+
+ copymem(&iw[i * 4], &v, 4);
+ }
+ }
+ } break;
+ default: {
+ ERR_FAIL_V(ERR_INVALID_DATA);
+ }
+ }
+ }
+
+ if (p_format & RS::ARRAY_FORMAT_BONES) {
+ //create AABBs for each detected bone
+ int total_bones = max_bone + 1;
+
+ bool first = r_bone_aabb.size() == 0;
+
+ r_bone_aabb.resize(total_bones);
+
+ if (first) {
+ for (int i = 0; i < total_bones; i++) {
+ r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused
+ }
+ }
+
+ Vector<Vector3> vertices = p_arrays[RS::ARRAY_VERTEX];
+ Vector<int> bones = p_arrays[RS::ARRAY_BONES];
+ Vector<float> weights = p_arrays[RS::ARRAY_WEIGHTS];
+
+ bool any_valid = false;
+
+ if (vertices.size() && bones.size() == vertices.size() * 4 && weights.size() == bones.size()) {
+
+ int vs = vertices.size();
+ const Vector3 *rv = vertices.ptr();
+ const int *rb = bones.ptr();
+ const float *rw = weights.ptr();
+
+ AABB *bptr = r_bone_aabb.ptrw();
+
+ for (int i = 0; i < vs; i++) {
+
+ Vector3 v = rv[i];
+ for (int j = 0; j < 4; j++) {
+
+ int idx = rb[i * 4 + j];
+ float w = rw[i * 4 + j];
+ if (w == 0)
+ continue; //break;
+ ERR_FAIL_INDEX_V(idx, total_bones, ERR_INVALID_DATA);
+
+ if (bptr[idx].size.x < 0) {
+ //first
+ bptr[idx] = AABB(v, SMALL_VEC3);
+ any_valid = true;
+ } else {
+ bptr[idx].expand_to(v);
+ }
+ }
+ }
+ }
+
+ if (!any_valid && first) {
+
+ r_bone_aabb.clear();
+ }
+ }
+ return OK;
+}
+
+uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const {
+ uint32_t offsets[ARRAY_MAX];
+ mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets);
+ return offsets[p_array_index];
+}
+
+uint32_t RenderingServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const {
+ uint32_t offsets[ARRAY_MAX];
+ return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets);
+}
+
+uint32_t RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const {
+
+ int total_elem_size = 0;
+
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
+
+ r_offsets[i] = 0; //reset
+
+ if (!(p_format & (1 << i))) // no array
+ continue;
+
+ int elem_size = 0;
+
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
+ elem_size = 2;
+ } else {
+ elem_size = 3;
+ }
+
+ {
+ elem_size *= sizeof(float);
+ }
+
+ if (elem_size == 6) {
+ elem_size = 8;
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+
+ if (p_format & ARRAY_COMPRESS_NORMAL) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 3;
+ }
+
+ } break;
+
+ case RS::ARRAY_TANGENT: {
+ if (p_format & ARRAY_COMPRESS_TANGENT) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ if (p_format & ARRAY_COMPRESS_COLOR) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 4;
+ }
+ } break;
+ case RS::ARRAY_TEX_UV: {
+ if (p_format & ARRAY_COMPRESS_TEX_UV) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 2;
+ }
+
+ } break;
+
+ case RS::ARRAY_TEX_UV2: {
+ if (p_format & ARRAY_COMPRESS_TEX_UV2) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+
+ elem_size = sizeof(uint16_t) * 4;
+
+ } break;
+ case RS::ARRAY_BONES: {
+
+ elem_size = sizeof(uint16_t) * 4;
+
+ } break;
+ case RS::ARRAY_INDEX: {
+
+ if (p_index_len <= 0) {
+ ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
+ break;
+ }
+ /* determine whether using 16 or 32 bits indices */
+ if (p_vertex_len >= (1 << 16)) {
+
+ elem_size = 4;
+
+ } else {
+ elem_size = 2;
+ }
+ r_offsets[i] = elem_size;
+ continue;
+ }
+ default: {
+ ERR_FAIL_V(0);
+ }
+ }
+
+ r_offsets[i] = total_elem_size;
+ total_elem_size += elem_size;
+ }
+ return total_elem_size;
+}
+
+Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) {
+
+ ERR_FAIL_INDEX_V(p_primitive, RS::PRIMITIVE_MAX, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_arrays.size() != RS::ARRAY_MAX, ERR_INVALID_PARAMETER);
+
+ uint32_t format = 0;
+
+ // validation
+ int index_array_len = 0;
+ int array_len = 0;
+
+ for (int i = 0; i < p_arrays.size(); i++) {
+
+ if (p_arrays[i].get_type() == Variant::NIL)
+ continue;
+
+ format |= (1 << i);
+
+ if (i == RS::ARRAY_VERTEX) {
+
+ Variant var = p_arrays[i];
+ switch (var.get_type()) {
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ Vector<Vector2> v2 = var;
+ } break;
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ Vector<Vector3> v3 = var;
+ } break;
+ default: {
+ Array v = var;
+ } break;
+ }
+
+ array_len = PackedVector3Array(p_arrays[i]).size();
+ ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA);
+ } else if (i == RS::ARRAY_INDEX) {
+
+ index_array_len = PackedInt32Array(p_arrays[i]).size();
+ }
+ }
+
+ ERR_FAIL_COND_V((format & RS::ARRAY_FORMAT_VERTEX) == 0, ERR_INVALID_PARAMETER); // mandatory
+
+ if (p_blend_shapes.size()) {
+ //validate format for morphs
+ for (int i = 0; i < p_blend_shapes.size(); i++) {
+
+ uint32_t bsformat = 0;
+ Array arr = p_blend_shapes[i];
+ for (int j = 0; j < arr.size(); j++) {
+
+ if (arr[j].get_type() != Variant::NIL)
+ bsformat |= (1 << j);
+ }
+
+ ERR_FAIL_COND_V((bsformat) != (format & (RS::ARRAY_FORMAT_INDEX - 1)), ERR_INVALID_PARAMETER);
+ }
+ }
+
+ uint32_t offsets[RS::ARRAY_MAX];
+
+ int total_elem_size = 0;
+
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
+
+ offsets[i] = 0; //reset
+
+ if (!(format & (1 << i))) // no array
+ continue;
+
+ int elem_size = 0;
+
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ Variant arr = p_arrays[0];
+ if (arr.get_type() == Variant::PACKED_VECTOR2_ARRAY) {
+ elem_size = 2;
+ p_compress_format |= ARRAY_FLAG_USE_2D_VERTICES;
+ } else if (arr.get_type() == Variant::PACKED_VECTOR3_ARRAY) {
+ p_compress_format &= ~ARRAY_FLAG_USE_2D_VERTICES;
+ elem_size = 3;
+ } else {
+ elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3;
+ }
+
+ {
+ elem_size *= sizeof(float);
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+
+ if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 3;
+ }
+
+ } break;
+
+ case RS::ARRAY_TANGENT: {
+ if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ if (p_compress_format & ARRAY_COMPRESS_COLOR) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 4;
+ }
+ } break;
+ case RS::ARRAY_TEX_UV: {
+ if (p_compress_format & ARRAY_COMPRESS_TEX_UV) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 2;
+ }
+
+ } break;
+
+ case RS::ARRAY_TEX_UV2: {
+ if (p_compress_format & ARRAY_COMPRESS_TEX_UV2) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+
+ elem_size = sizeof(uint16_t) * 4;
+
+ } break;
+ case RS::ARRAY_BONES: {
+
+ elem_size = sizeof(uint16_t) * 4;
+
+ } break;
+ case RS::ARRAY_INDEX: {
+
+ if (index_array_len <= 0) {
+ ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
+ break;
+ }
+ /* determine whether using 16 or 32 bits indices */
+ if (array_len >= (1 << 16)) {
+
+ elem_size = 4;
+
+ } else {
+ elem_size = 2;
+ }
+ offsets[i] = elem_size;
+ continue;
+ }
+ default: {
+ ERR_FAIL_V(ERR_BUG);
+ }
+ }
+
+ offsets[i] = total_elem_size;
+ total_elem_size += elem_size;
+ }
+
+ uint32_t mask = (1 << ARRAY_MAX) - 1;
+ format |= (~mask) & p_compress_format; //make the full format
+
+ int array_size = total_elem_size * array_len;
+
+ Vector<uint8_t> vertex_array;
+ vertex_array.resize(array_size);
+
+ int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len;
+
+ Vector<uint8_t> index_array;
+ index_array.resize(index_array_size);
+
+ AABB aabb;
+ Vector<AABB> bone_aabb;
+
+ Error err = _surface_set_data(p_arrays, format, offsets, total_elem_size, vertex_array, array_len, index_array, index_array_len, aabb, bone_aabb);
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface.");
+
+ Vector<Vector<uint8_t>> blend_shape_data;
+
+ for (int i = 0; i < p_blend_shapes.size(); i++) {
+
+ Vector<uint8_t> vertex_array_shape;
+ vertex_array_shape.resize(array_size);
+ Vector<uint8_t> noindex;
+
+ AABB laabb;
+ Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb);
+ aabb.merge_with(laabb);
+ ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface.");
+
+ blend_shape_data.push_back(vertex_array_shape);
+ }
+ Vector<SurfaceData::LOD> lods;
+ if (index_array_len) {
+
+ List<Variant> keys;
+ p_lods.get_key_list(&keys);
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
+ float distance = E->get();
+ ERR_CONTINUE(distance <= 0.0);
+ Vector<int> indices = p_lods[E->get()];
+ ERR_CONTINUE(indices.size() == 0);
+ uint32_t index_count = indices.size();
+ ERR_CONTINUE(index_count >= (uint32_t)index_array_len); //should be smaller..
+
+ const int *r = indices.ptr();
+
+ Vector<uint8_t> data;
+ if (array_len <= 65536) {
+ //16 bits indices
+ data.resize(indices.size() * 2);
+ uint8_t *w = data.ptrw();
+ uint16_t *index_ptr = (uint16_t *)w;
+ for (uint32_t i = 0; i < index_count; i++) {
+ index_ptr[i] = r[i];
+ }
+ } else {
+ //32 bits indices
+ data.resize(indices.size() * 4);
+ uint8_t *w = data.ptrw();
+ uint32_t *index_ptr = (uint32_t *)w;
+ for (uint32_t i = 0; i < index_count; i++) {
+ index_ptr[i] = r[i];
+ }
+ }
+
+ SurfaceData::LOD lod;
+ lod.edge_length = distance;
+ lod.index_data = data;
+ lods.push_back(lod);
+ }
+ }
+
+ SurfaceData &surface_data = *r_surface_data;
+ surface_data.format = format;
+ surface_data.primitive = p_primitive;
+ surface_data.aabb = aabb;
+ surface_data.vertex_data = vertex_array;
+ surface_data.vertex_count = array_len;
+ surface_data.index_data = index_array;
+ surface_data.index_count = index_array_len;
+ surface_data.blend_shapes = blend_shape_data;
+ surface_data.bone_aabbs = bone_aabb;
+ surface_data.lods = lods;
+
+ return OK;
+}
+
+void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) {
+
+ SurfaceData sd;
+ Error err = mesh_create_surface_data_from_arrays(&sd, p_primitive, p_arrays, p_blend_shapes, p_lods, p_compress_format);
+ if (err != OK) {
+ return;
+ }
+ mesh_add_surface(p_mesh, sd);
+}
+
+Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const {
+
+ uint32_t offsets[ARRAY_MAX];
+
+ int total_elem_size = 0;
+
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
+
+ offsets[i] = 0; //reset
+
+ if (!(p_format & (1 << i))) // no array
+ continue;
+
+ int elem_size = 0;
+
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
+ elem_size = 2;
+ } else {
+ elem_size = 3;
+ }
+
+ {
+ elem_size *= sizeof(float);
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+
+ if (p_format & ARRAY_COMPRESS_NORMAL) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 3;
+ }
+
+ } break;
+
+ case RS::ARRAY_TANGENT: {
+ if (p_format & ARRAY_COMPRESS_TANGENT) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 4;
+ }
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ if (p_format & ARRAY_COMPRESS_COLOR) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 4;
+ }
+ } break;
+ case RS::ARRAY_TEX_UV: {
+ if (p_format & ARRAY_COMPRESS_TEX_UV) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 2;
+ }
+
+ } break;
+
+ case RS::ARRAY_TEX_UV2: {
+ if (p_format & ARRAY_COMPRESS_TEX_UV2) {
+ elem_size = sizeof(uint32_t);
+ } else {
+ elem_size = sizeof(float) * 2;
+ }
+
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+
+ elem_size = sizeof(uint16_t) * 4;
+
+ } break;
+ case RS::ARRAY_BONES: {
+
+ elem_size = sizeof(uint16_t) * 4;
+
+ } break;
+ case RS::ARRAY_INDEX: {
+
+ if (p_index_len <= 0) {
+ ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
+ break;
+ }
+ /* determine whether using 16 or 32 bits indices */
+ if (p_vertex_len >= (1 << 16)) {
+
+ elem_size = 4;
+
+ } else {
+ elem_size = 2;
+ }
+ offsets[i] = elem_size;
+ continue;
+ }
+ default: {
+ ERR_FAIL_V(Array());
+ }
+ }
+
+ offsets[i] = total_elem_size;
+ total_elem_size += elem_size;
+ }
+
+ Array ret;
+ ret.resize(RS::ARRAY_MAX);
+
+ const uint8_t *r = p_vertex_data.ptr();
+
+ for (int i = 0; i < RS::ARRAY_MAX; i++) {
+
+ if (!(p_format & (1 << i)))
+ continue;
+
+ switch (i) {
+
+ case RS::ARRAY_VERTEX: {
+
+ if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
+
+ Vector<Vector2> arr_2d;
+ arr_2d.resize(p_vertex_len);
+
+ {
+
+ Vector2 *w = arr_2d.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector2(v[0], v[1]);
+ }
+ }
+
+ ret[i] = arr_2d;
+ } else {
+
+ Vector<Vector3> arr_3d;
+ arr_3d.resize(p_vertex_len);
+
+ {
+
+ Vector3 *w = arr_3d.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector3(v[0], v[1], v[2]);
+ }
+ }
+
+ ret[i] = arr_3d;
+ }
+
+ } break;
+ case RS::ARRAY_NORMAL: {
+ Vector<Vector3> arr;
+ arr.resize(p_vertex_len);
+
+ if (p_format & ARRAY_COMPRESS_NORMAL) {
+
+ Vector3 *w = arr.ptrw();
+ const float multiplier = 1.f / 127.f;
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
+ }
+ } else {
+ Vector3 *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector3(v[0], v[1], v[2]);
+ }
+ }
+
+ ret[i] = arr;
+
+ } break;
+
+ case RS::ARRAY_TANGENT: {
+ Vector<float> arr;
+ arr.resize(p_vertex_len * 4);
+ if (p_format & ARRAY_COMPRESS_TANGENT) {
+ float *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
+ for (int k = 0; k < 4; k++) {
+ w[j * 4 + k] = float(v[k] / 127.0);
+ }
+ }
+ } else {
+
+ float *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ for (int k = 0; k < 4; k++) {
+ w[j * 4 + k] = v[k];
+ }
+ }
+ }
+
+ ret[i] = arr;
+
+ } break;
+ case RS::ARRAY_COLOR: {
+
+ Vector<Color> arr;
+ arr.resize(p_vertex_len);
+
+ if (p_format & ARRAY_COMPRESS_COLOR) {
+
+ Color *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Color(float(v[0] / 255.0), float(v[1] / 255.0), float(v[2] / 255.0), float(v[3] / 255.0));
+ }
+ } else {
+ Color *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Color(v[0], v[1], v[2], v[3]);
+ }
+ }
+
+ ret[i] = arr;
+ } break;
+ case RS::ARRAY_TEX_UV: {
+
+ Vector<Vector2> arr;
+ arr.resize(p_vertex_len);
+
+ if (p_format & ARRAY_COMPRESS_TEX_UV) {
+
+ Vector2 *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]));
+ }
+ } else {
+
+ Vector2 *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector2(v[0], v[1]);
+ }
+ }
+
+ ret[i] = arr;
+ } break;
+
+ case RS::ARRAY_TEX_UV2: {
+ Vector<Vector2> arr;
+ arr.resize(p_vertex_len);
+
+ if (p_format & ARRAY_COMPRESS_TEX_UV2) {
+
+ Vector2 *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]));
+ }
+ } else {
+
+ Vector2 *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
+ w[j] = Vector2(v[0], v[1]);
+ }
+ }
+
+ ret[i] = arr;
+
+ } break;
+ case RS::ARRAY_WEIGHTS: {
+
+ Vector<float> arr;
+ arr.resize(p_vertex_len * 4);
+ {
+ float *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
+ for (int k = 0; k < 4; k++) {
+ w[j * 4 + k] = float(v[k] / 65535.0);
+ }
+ }
+ }
+
+ ret[i] = arr;
+
+ } break;
+ case RS::ARRAY_BONES: {
+
+ Vector<int> arr;
+ arr.resize(p_vertex_len * 4);
+
+ int *w = arr.ptrw();
+
+ for (int j = 0; j < p_vertex_len; j++) {
+
+ const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
+ for (int k = 0; k < 4; k++) {
+ w[j * 4 + k] = v[k];
+ }
+ }
+
+ ret[i] = arr;
+
+ } break;
+ case RS::ARRAY_INDEX: {
+ /* determine whether using 16 or 32 bits indices */
+
+ const uint8_t *ir = p_index_data.ptr();
+
+ Vector<int> arr;
+ arr.resize(p_index_len);
+ if (p_vertex_len < (1 << 16)) {
+
+ int *w = arr.ptrw();
+
+ for (int j = 0; j < p_index_len; j++) {
+
+ const uint16_t *v = (const uint16_t *)&ir[j * 2];
+ w[j] = *v;
+ }
+ } else {
+
+ int *w = arr.ptrw();
+
+ for (int j = 0; j < p_index_len; j++) {
+ const int *v = (const int *)&ir[j * 4];
+ w[j] = *v;
+ }
+ }
+ ret[i] = arr;
+ } break;
+ default: {
+ ERR_FAIL_V(ret);
+ }
+ }
+ }
+
+ return ret;
+}
+
+Array RenderingServer::mesh_surface_get_arrays(RID p_mesh, int p_surface) const {
+
+ SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
+ return mesh_create_arrays_from_surface_data(sd);
+}
+
+Dictionary RenderingServer::mesh_surface_get_lods(RID p_mesh, int p_surface) const {
+
+ SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
+ ERR_FAIL_COND_V(sd.vertex_count == 0, Dictionary());
+
+ Dictionary ret;
+
+ for (int i = 0; i < sd.lods.size(); i++) {
+ Vector<int> lods;
+ if (sd.vertex_count <= 65536) {
+ uint32_t lc = sd.lods[i].index_data.size() / 2;
+ lods.resize(lc);
+ const uint8_t *r = sd.lods[i].index_data.ptr();
+ const uint16_t *rptr = (const uint16_t *)r;
+ int *w = lods.ptrw();
+ for (uint32_t j = 0; j < lc; j++) {
+ w[j] = rptr[i];
+ }
+ } else {
+ uint32_t lc = sd.lods[i].index_data.size() / 4;
+ lods.resize(lc);
+ const uint8_t *r = sd.lods[i].index_data.ptr();
+ const uint32_t *rptr = (const uint32_t *)r;
+ int *w = lods.ptrw();
+ for (uint32_t j = 0; j < lc; j++) {
+ w[j] = rptr[i];
+ }
+ }
+
+ ret[sd.lods[i].edge_length] = lods;
+ }
+
+ return ret;
+}
+
+Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const {
+
+ SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
+ ERR_FAIL_COND_V(sd.vertex_count == 0, Array());
+
+ Vector<Vector<uint8_t>> blend_shape_data = sd.blend_shapes;
+
+ if (blend_shape_data.size() > 0) {
+ int vertex_len = sd.vertex_count;
+
+ Vector<uint8_t> index_data = sd.index_data;
+ int index_len = sd.index_count;
+
+ uint32_t format = sd.format;
+
+ Array blend_shape_array;
+ blend_shape_array.resize(blend_shape_data.size());
+ for (int i = 0; i < blend_shape_data.size(); i++) {
+ blend_shape_array.set(i, _get_array_from_surface(format, blend_shape_data[i], vertex_len, index_data, index_len));
+ }
+
+ return blend_shape_array;
+ } else {
+ return Array();
+ }
+}
+
+Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const {
+
+ Vector<uint8_t> vertex_data = p_data.vertex_data;
+
+ ERR_FAIL_COND_V(vertex_data.size() == 0, Array());
+ int vertex_len = p_data.vertex_count;
+
+ Vector<uint8_t> index_data = p_data.index_data;
+ int index_len = p_data.index_count;
+
+ uint32_t format = p_data.format;
+
+ return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len);
+}
+#if 0
+Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const {
+
+ Vector<AABB> vec = RS::get_singleton()->mesh_surface_get_skeleton_aabb(p_mesh, p_surface);
+ Array arr;
+ for (int i = 0; i < vec.size(); i++) {
+ arr[i] = vec[i];
+ }
+ return arr;
+}
+#endif
+void RenderingServer::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("force_sync"), &RenderingServer::sync);
+ ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &RenderingServer::draw, DEFVAL(true), DEFVAL(0.0));
+
+#ifndef _MSC_VER
+#warning TODO all texture methods need re-binding
+#endif
+
+ ClassDB::bind_method(D_METHOD("texture_2d_create", "image"), &RenderingServer::texture_2d_create);
+ ClassDB::bind_method(D_METHOD("texture_2d_get", "texture"), &RenderingServer::texture_2d_get);
+
+#ifndef _3D_DISABLED
+ ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create);
+ ClassDB::bind_method(D_METHOD("sky_set_material", "sky", "material"), &RenderingServer::sky_set_material);
+#endif
+ ClassDB::bind_method(D_METHOD("shader_create"), &RenderingServer::shader_create);
+ ClassDB::bind_method(D_METHOD("shader_set_code", "shader", "code"), &RenderingServer::shader_set_code);
+ ClassDB::bind_method(D_METHOD("shader_get_code", "shader"), &RenderingServer::shader_get_code);
+ ClassDB::bind_method(D_METHOD("shader_get_param_list", "shader"), &RenderingServer::_shader_get_param_list_bind);
+ ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "name", "texture"), &RenderingServer::shader_set_default_texture_param);
+ ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "name"), &RenderingServer::shader_get_default_texture_param);
+ ClassDB::bind_method(D_METHOD("shader_get_param_default", "material", "parameter"), &RenderingServer::shader_get_param_default);
+
+ ClassDB::bind_method(D_METHOD("material_create"), &RenderingServer::material_create);
+ ClassDB::bind_method(D_METHOD("material_set_shader", "shader_material", "shader"), &RenderingServer::material_set_shader);
+ ClassDB::bind_method(D_METHOD("material_set_param", "material", "parameter", "value"), &RenderingServer::material_set_param);
+ ClassDB::bind_method(D_METHOD("material_get_param", "material", "parameter"), &RenderingServer::material_get_param);
+ ClassDB::bind_method(D_METHOD("material_set_render_priority", "material", "priority"), &RenderingServer::material_set_render_priority);
+
+ ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &RenderingServer::material_set_next_pass);
+
+ ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &RenderingServer::mesh_surface_get_format_offset);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &RenderingServer::mesh_surface_get_format_stride);
+ ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &RenderingServer::mesh_get_blend_shape_count);
+ ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &RenderingServer::mesh_set_blend_shape_mode);
+ ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &RenderingServer::mesh_get_blend_shape_mode);
+ ClassDB::bind_method(D_METHOD("mesh_surface_update_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_region);
+ ClassDB::bind_method(D_METHOD("mesh_surface_set_material", "mesh", "surface", "material"), &RenderingServer::mesh_surface_set_material);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_material", "mesh", "surface"), &RenderingServer::mesh_surface_get_material);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_arrays", "mesh", "surface"), &RenderingServer::mesh_surface_get_arrays);
+ ClassDB::bind_method(D_METHOD("mesh_surface_get_blend_shape_arrays", "mesh", "surface"), &RenderingServer::mesh_surface_get_blend_shape_arrays);
+ ClassDB::bind_method(D_METHOD("mesh_get_surface_count", "mesh"), &RenderingServer::mesh_get_surface_count);
+ ClassDB::bind_method(D_METHOD("mesh_set_custom_aabb", "mesh", "aabb"), &RenderingServer::mesh_set_custom_aabb);
+ ClassDB::bind_method(D_METHOD("mesh_get_custom_aabb", "mesh"), &RenderingServer::mesh_get_custom_aabb);
+ 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_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);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform_2d", "multimesh", "index", "transform"), &RenderingServer::multimesh_instance_set_transform_2d);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_set_color", "multimesh", "index", "color"), &RenderingServer::multimesh_instance_set_color);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_set_custom_data", "multimesh", "index", "custom_data"), &RenderingServer::multimesh_instance_set_custom_data);
+ ClassDB::bind_method(D_METHOD("multimesh_get_mesh", "multimesh"), &RenderingServer::multimesh_get_mesh);
+ ClassDB::bind_method(D_METHOD("multimesh_get_aabb", "multimesh"), &RenderingServer::multimesh_get_aabb);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform_2d", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform_2d);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_get_color", "multimesh", "index"), &RenderingServer::multimesh_instance_get_color);
+ ClassDB::bind_method(D_METHOD("multimesh_instance_get_custom_data", "multimesh", "index"), &RenderingServer::multimesh_instance_get_custom_data);
+ ClassDB::bind_method(D_METHOD("multimesh_set_visible_instances", "multimesh", "visible"), &RenderingServer::multimesh_set_visible_instances);
+ ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &RenderingServer::multimesh_get_visible_instances);
+ ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &RenderingServer::multimesh_set_buffer);
+ ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &RenderingServer::multimesh_get_buffer);
+#ifndef _3D_DISABLED
+ ClassDB::bind_method(D_METHOD("immediate_create"), &RenderingServer::immediate_create);
+ ClassDB::bind_method(D_METHOD("immediate_begin", "immediate", "primitive", "texture"), &RenderingServer::immediate_begin, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("immediate_vertex", "immediate", "vertex"), &RenderingServer::immediate_vertex);
+ ClassDB::bind_method(D_METHOD("immediate_vertex_2d", "immediate", "vertex"), &RenderingServer::immediate_vertex_2d);
+ ClassDB::bind_method(D_METHOD("immediate_normal", "immediate", "normal"), &RenderingServer::immediate_normal);
+ ClassDB::bind_method(D_METHOD("immediate_tangent", "immediate", "tangent"), &RenderingServer::immediate_tangent);
+ ClassDB::bind_method(D_METHOD("immediate_color", "immediate", "color"), &RenderingServer::immediate_color);
+ ClassDB::bind_method(D_METHOD("immediate_uv", "immediate", "tex_uv"), &RenderingServer::immediate_uv);
+ ClassDB::bind_method(D_METHOD("immediate_uv2", "immediate", "tex_uv"), &RenderingServer::immediate_uv2);
+ ClassDB::bind_method(D_METHOD("immediate_end", "immediate"), &RenderingServer::immediate_end);
+ ClassDB::bind_method(D_METHOD("immediate_clear", "immediate"), &RenderingServer::immediate_clear);
+ ClassDB::bind_method(D_METHOD("immediate_set_material", "immediate", "material"), &RenderingServer::immediate_set_material);
+ ClassDB::bind_method(D_METHOD("immediate_get_material", "immediate"), &RenderingServer::immediate_get_material);
+#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_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);
+ ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform_2d", "skeleton", "bone", "transform"), &RenderingServer::skeleton_bone_set_transform_2d);
+ ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform_2d", "skeleton", "bone"), &RenderingServer::skeleton_bone_get_transform_2d);
+
+#ifndef _3D_DISABLED
+ ClassDB::bind_method(D_METHOD("directional_light_create"), &RenderingServer::directional_light_create);
+ ClassDB::bind_method(D_METHOD("omni_light_create"), &RenderingServer::omni_light_create);
+ ClassDB::bind_method(D_METHOD("spot_light_create"), &RenderingServer::spot_light_create);
+
+ ClassDB::bind_method(D_METHOD("light_set_color", "light", "color"), &RenderingServer::light_set_color);
+ ClassDB::bind_method(D_METHOD("light_set_param", "light", "param", "value"), &RenderingServer::light_set_param);
+ ClassDB::bind_method(D_METHOD("light_set_shadow", "light", "enabled"), &RenderingServer::light_set_shadow);
+ ClassDB::bind_method(D_METHOD("light_set_shadow_color", "light", "color"), &RenderingServer::light_set_shadow_color);
+ ClassDB::bind_method(D_METHOD("light_set_projector", "light", "texture"), &RenderingServer::light_set_projector);
+ ClassDB::bind_method(D_METHOD("light_set_negative", "light", "enable"), &RenderingServer::light_set_negative);
+ ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &RenderingServer::light_set_cull_mask);
+ ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &RenderingServer::light_set_reverse_cull_face_mode);
+ ClassDB::bind_method(D_METHOD("light_set_use_gi", "light", "enabled"), &RenderingServer::light_set_use_gi);
+
+ ClassDB::bind_method(D_METHOD("light_omni_set_shadow_mode", "light", "mode"), &RenderingServer::light_omni_set_shadow_mode);
+
+ ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &RenderingServer::light_directional_set_shadow_mode);
+ ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &RenderingServer::light_directional_set_blend_splits);
+ ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &RenderingServer::light_directional_set_shadow_depth_range_mode);
+
+ ClassDB::bind_method(D_METHOD("reflection_probe_create"), &RenderingServer::reflection_probe_create);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_update_mode", "probe", "mode"), &RenderingServer::reflection_probe_set_update_mode);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_intensity", "probe", "intensity"), &RenderingServer::reflection_probe_set_intensity);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_interior_ambient", "probe", "color"), &RenderingServer::reflection_probe_set_interior_ambient);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_interior_ambient_energy", "probe", "energy"), &RenderingServer::reflection_probe_set_interior_ambient_energy);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_interior_ambient_probe_contribution", "probe", "contrib"), &RenderingServer::reflection_probe_set_interior_ambient_probe_contribution);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_max_distance", "probe", "distance"), &RenderingServer::reflection_probe_set_max_distance);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_extents", "probe", "extents"), &RenderingServer::reflection_probe_set_extents);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_origin_offset", "probe", "offset"), &RenderingServer::reflection_probe_set_origin_offset);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_as_interior", "probe", "enable"), &RenderingServer::reflection_probe_set_as_interior);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_box_projection", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_box_projection);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_shadows);
+ ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_cull_mask);
+
+#ifndef _MSC_VER
+#warning TODO all giprobe methods need re-binding
+#endif
+#if 0
+ ClassDB::bind_method(D_METHOD("gi_probe_create"), &RenderingServer::gi_probe_create);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_bounds", "probe", "bounds"), &RenderingServer::gi_probe_set_bounds);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_bounds", "probe"), &RenderingServer::gi_probe_get_bounds);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_cell_size", "probe", "range"), &RenderingServer::gi_probe_set_cell_size);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_cell_size", "probe"), &RenderingServer::gi_probe_get_cell_size);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_to_cell_xform", "probe", "xform"), &RenderingServer::gi_probe_set_to_cell_xform);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_to_cell_xform", "probe"), &RenderingServer::gi_probe_get_to_cell_xform);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_dynamic_data", "probe", "data"), &RenderingServer::gi_probe_set_dynamic_data);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_dynamic_data", "probe"), &RenderingServer::gi_probe_get_dynamic_data);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_dynamic_range", "probe", "range"), &RenderingServer::gi_probe_set_dynamic_range);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_dynamic_range", "probe"), &RenderingServer::gi_probe_get_dynamic_range);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_energy", "probe", "energy"), &RenderingServer::gi_probe_set_energy);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_energy", "probe"), &RenderingServer::gi_probe_get_energy);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_bias", "probe", "bias"), &RenderingServer::gi_probe_set_bias);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_bias", "probe"), &RenderingServer::gi_probe_get_bias);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_normal_bias", "probe", "bias"), &RenderingServer::gi_probe_set_normal_bias);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_normal_bias", "probe"), &RenderingServer::gi_probe_get_normal_bias);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_propagation", "probe", "propagation"), &RenderingServer::gi_probe_set_propagation);
+ ClassDB::bind_method(D_METHOD("gi_probe_get_propagation", "probe"), &RenderingServer::gi_probe_get_propagation);
+ ClassDB::bind_method(D_METHOD("gi_probe_set_interior", "probe", "enable"), &RenderingServer::gi_probe_set_interior);
+ ClassDB::bind_method(D_METHOD("gi_probe_is_interior", "probe"), &RenderingServer::gi_probe_is_interior);
+ 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_capture_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);
+ ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree", "capture", "octree"), &RenderingServer::lightmap_capture_set_octree);
+ ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_transform", "capture", "xform"), &RenderingServer::lightmap_capture_set_octree_cell_transform);
+ ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_transform", "capture"), &RenderingServer::lightmap_capture_get_octree_cell_transform);
+ ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_subdiv", "capture", "subdiv"), &RenderingServer::lightmap_capture_set_octree_cell_subdiv);
+ ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_subdiv", "capture"), &RenderingServer::lightmap_capture_get_octree_cell_subdiv);
+ ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &RenderingServer::lightmap_capture_get_octree);
+ 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);
+#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);
+ ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &RenderingServer::particles_get_emitting);
+ ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &RenderingServer::particles_set_amount);
+ ClassDB::bind_method(D_METHOD("particles_set_lifetime", "particles", "lifetime"), &RenderingServer::particles_set_lifetime);
+ ClassDB::bind_method(D_METHOD("particles_set_one_shot", "particles", "one_shot"), &RenderingServer::particles_set_one_shot);
+ ClassDB::bind_method(D_METHOD("particles_set_pre_process_time", "particles", "time"), &RenderingServer::particles_set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("particles_set_explosiveness_ratio", "particles", "ratio"), &RenderingServer::particles_set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("particles_set_randomness_ratio", "particles", "ratio"), &RenderingServer::particles_set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("particles_set_custom_aabb", "particles", "aabb"), &RenderingServer::particles_set_custom_aabb);
+ ClassDB::bind_method(D_METHOD("particles_set_speed_scale", "particles", "scale"), &RenderingServer::particles_set_speed_scale);
+ ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &RenderingServer::particles_set_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("particles_set_process_material", "particles", "material"), &RenderingServer::particles_set_process_material);
+ ClassDB::bind_method(D_METHOD("particles_set_fixed_fps", "particles", "fps"), &RenderingServer::particles_set_fixed_fps);
+ ClassDB::bind_method(D_METHOD("particles_set_fractional_delta", "particles", "enable"), &RenderingServer::particles_set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("particles_is_inactive", "particles"), &RenderingServer::particles_is_inactive);
+ ClassDB::bind_method(D_METHOD("particles_request_process", "particles"), &RenderingServer::particles_request_process);
+ ClassDB::bind_method(D_METHOD("particles_restart", "particles"), &RenderingServer::particles_restart);
+ ClassDB::bind_method(D_METHOD("particles_set_draw_order", "particles", "order"), &RenderingServer::particles_set_draw_order);
+ ClassDB::bind_method(D_METHOD("particles_set_draw_passes", "particles", "count"), &RenderingServer::particles_set_draw_passes);
+ ClassDB::bind_method(D_METHOD("particles_set_draw_pass_mesh", "particles", "pass", "mesh"), &RenderingServer::particles_set_draw_pass_mesh);
+ ClassDB::bind_method(D_METHOD("particles_get_current_aabb", "particles"), &RenderingServer::particles_get_current_aabb);
+ ClassDB::bind_method(D_METHOD("particles_set_emission_transform", "particles", "transform"), &RenderingServer::particles_set_emission_transform);
+
+ ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create);
+ ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &RenderingServer::camera_set_perspective);
+ ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &RenderingServer::camera_set_orthogonal);
+ ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &RenderingServer::camera_set_frustum);
+ ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &RenderingServer::camera_set_transform);
+ ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &RenderingServer::camera_set_cull_mask);
+ ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &RenderingServer::camera_set_environment);
+ ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &RenderingServer::camera_set_use_vertical_aspect);
+
+ ClassDB::bind_method(D_METHOD("viewport_create"), &RenderingServer::viewport_create);
+ ClassDB::bind_method(D_METHOD("viewport_set_use_xr", "viewport", "use_xr"), &RenderingServer::viewport_set_use_xr);
+ ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &RenderingServer::viewport_set_size);
+ ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &RenderingServer::viewport_set_active);
+ ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &RenderingServer::viewport_set_parent_viewport);
+ ClassDB::bind_method(D_METHOD("viewport_attach_to_screen", "viewport", "rect", "screen"), &RenderingServer::viewport_attach_to_screen, DEFVAL(Rect2()), DEFVAL(DisplayServer::MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &RenderingServer::viewport_set_render_direct_to_screen);
+
+ ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &RenderingServer::viewport_set_update_mode);
+ ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &RenderingServer::viewport_set_clear_mode);
+ ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture);
+ ClassDB::bind_method(D_METHOD("viewport_set_hide_scenario", "viewport", "hidden"), &RenderingServer::viewport_set_hide_scenario);
+ ClassDB::bind_method(D_METHOD("viewport_set_hide_canvas", "viewport", "hidden"), &RenderingServer::viewport_set_hide_canvas);
+ ClassDB::bind_method(D_METHOD("viewport_set_disable_environment", "viewport", "disabled"), &RenderingServer::viewport_set_disable_environment);
+ ClassDB::bind_method(D_METHOD("viewport_attach_camera", "viewport", "camera"), &RenderingServer::viewport_attach_camera);
+ ClassDB::bind_method(D_METHOD("viewport_set_scenario", "viewport", "scenario"), &RenderingServer::viewport_set_scenario);
+ ClassDB::bind_method(D_METHOD("viewport_attach_canvas", "viewport", "canvas"), &RenderingServer::viewport_attach_canvas);
+ ClassDB::bind_method(D_METHOD("viewport_remove_canvas", "viewport", "canvas"), &RenderingServer::viewport_remove_canvas);
+ ClassDB::bind_method(D_METHOD("viewport_set_canvas_transform", "viewport", "canvas", "offset"), &RenderingServer::viewport_set_canvas_transform);
+ ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &RenderingServer::viewport_set_transparent_background);
+ ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &RenderingServer::viewport_set_global_canvas_transform);
+ ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &RenderingServer::viewport_set_canvas_stacking);
+ ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &RenderingServer::viewport_set_shadow_atlas_size);
+ 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_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);
+
+ ClassDB::bind_method(D_METHOD("environment_create"), &RenderingServer::environment_create);
+ ClassDB::bind_method(D_METHOD("environment_set_background", "env", "bg"), &RenderingServer::environment_set_background);
+ ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &RenderingServer::environment_set_sky);
+ ClassDB::bind_method(D_METHOD("environment_set_sky_custom_fov", "env", "scale"), &RenderingServer::environment_set_sky_custom_fov);
+ ClassDB::bind_method(D_METHOD("environment_set_sky_orientation", "env", "orientation"), &RenderingServer::environment_set_sky_orientation);
+ ClassDB::bind_method(D_METHOD("environment_set_bg_color", "env", "color"), &RenderingServer::environment_set_bg_color);
+ ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy);
+ ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer);
+ ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color()));
+ ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "level_flags", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow);
+ ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap);
+ ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &RenderingServer::environment_set_adjustment);
+ ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr);
+ ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "bias", "light_affect", "ao_channel_affect", "blur", "bilateral_sharpness"), &RenderingServer::environment_set_ssao);
+ ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "color", "sun_color", "sun_amount"), &RenderingServer::environment_set_fog);
+
+ ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "enable", "depth_begin", "depth_end", "depth_curve", "transmit", "transmit_curve"), &RenderingServer::environment_set_fog_depth);
+
+ ClassDB::bind_method(D_METHOD("environment_set_fog_height", "env", "enable", "min_height", "max_height", "height_curve"), &RenderingServer::environment_set_fog_height);
+
+ 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_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment);
+
+#ifndef _3D_DISABLED
+
+ ClassDB::bind_method(D_METHOD("instance_create2", "base", "scenario"), &RenderingServer::instance_create2);
+ ClassDB::bind_method(D_METHOD("instance_create"), &RenderingServer::instance_create);
+ ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &RenderingServer::instance_set_base);
+ ClassDB::bind_method(D_METHOD("instance_set_scenario", "instance", "scenario"), &RenderingServer::instance_set_scenario);
+ ClassDB::bind_method(D_METHOD("instance_set_layer_mask", "instance", "mask"), &RenderingServer::instance_set_layer_mask);
+ 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_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);
+ ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton);
+ ClassDB::bind_method(D_METHOD("instance_set_exterior", "instance", "enabled"), &RenderingServer::instance_set_exterior);
+ ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &RenderingServer::instance_set_extra_visibility_margin);
+ ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag);
+ ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting);
+ ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &RenderingServer::instance_geometry_set_material_override);
+ ClassDB::bind_method(D_METHOD("instance_geometry_set_draw_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_draw_range);
+ ClassDB::bind_method(D_METHOD("instance_geometry_set_as_instance_lod", "instance", "as_lod_of_instance"), &RenderingServer::instance_geometry_set_as_instance_lod);
+
+ ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &RenderingServer::_instances_cull_aabb_bind, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &RenderingServer::_instances_cull_ray_bind, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("instances_cull_convex", "convex", "scenario"), &RenderingServer::_instances_cull_convex_bind, DEFVAL(RID()));
+#endif
+ ClassDB::bind_method(D_METHOD("canvas_create"), &RenderingServer::canvas_create);
+ ClassDB::bind_method(D_METHOD("canvas_set_item_mirroring", "canvas", "item", "mirroring"), &RenderingServer::canvas_set_item_mirroring);
+ ClassDB::bind_method(D_METHOD("canvas_set_modulate", "canvas", "color"), &RenderingServer::canvas_set_modulate);
+#ifndef _MSC_VER
+#warning TODO method bindings need to be fixed
+#endif
+#if 0
+
+ ClassDB::bind_method(D_METHOD("canvas_item_create"), &RenderingServer::canvas_item_create);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_parent", "item", "parent"), &RenderingServer::canvas_item_set_parent);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_visible", "item", "visible"), &RenderingServer::canvas_item_set_visible);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_light_mask", "item", "mask"), &RenderingServer::canvas_item_set_light_mask);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_transform", "item", "transform"), &RenderingServer::canvas_item_set_transform);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_clip", "item", "clip"), &RenderingServer::canvas_item_set_clip);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_distance_field_mode", "item", "enabled"), &RenderingServer::canvas_item_set_distance_field_mode);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_custom_rect", "item", "use_custom_rect", "rect"), &RenderingServer::canvas_item_set_custom_rect, DEFVAL(Rect2()));
+ ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &RenderingServer::canvas_item_set_modulate);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &RenderingServer::canvas_item_set_self_modulate);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &RenderingServer::canvas_item_set_draw_behind_parent);
+ ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect);
+ ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
+ ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose", "normal_map"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(RID()), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate", "normal_map"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width", "normal_map"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0), DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture", "normal_map", "antialiased"), &RenderingServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID()), DEFVAL(RID()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture", "normal_map"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()), DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &RenderingServer::canvas_item_add_multimesh, DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &RenderingServer::canvas_item_add_particles);
+ ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &RenderingServer::canvas_item_add_set_transform);
+ ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &RenderingServer::canvas_item_add_clip_ignore);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &RenderingServer::canvas_item_set_sort_children_by_y);
+#endif
+ ClassDB::bind_method(D_METHOD("canvas_item_set_z_index", "item", "z_index"), &RenderingServer::canvas_item_set_z_index);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_z_as_relative_to_parent", "item", "enabled"), &RenderingServer::canvas_item_set_z_as_relative_to_parent);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_copy_to_backbuffer", "item", "enabled", "rect"), &RenderingServer::canvas_item_set_copy_to_backbuffer);
+ ClassDB::bind_method(D_METHOD("canvas_item_clear", "item"), &RenderingServer::canvas_item_clear);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_draw_index", "item", "index"), &RenderingServer::canvas_item_set_draw_index);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &RenderingServer::canvas_item_set_material);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_use_parent_material", "item", "enabled"), &RenderingServer::canvas_item_set_use_parent_material);
+ ClassDB::bind_method(D_METHOD("canvas_light_create"), &RenderingServer::canvas_light_create);
+ ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &RenderingServer::canvas_light_attach_to_canvas);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_enabled);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_scale", "light", "scale"), &RenderingServer::canvas_light_set_scale);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_transform", "light", "transform"), &RenderingServer::canvas_light_set_transform);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_texture", "light", "texture"), &RenderingServer::canvas_light_set_texture);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_texture_offset", "light", "offset"), &RenderingServer::canvas_light_set_texture_offset);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_color", "light", "color"), &RenderingServer::canvas_light_set_color);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_height", "light", "height"), &RenderingServer::canvas_light_set_height);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_energy", "light", "energy"), &RenderingServer::canvas_light_set_energy);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_z_range", "light", "min_z", "max_z"), &RenderingServer::canvas_light_set_z_range);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_layer_range", "light", "min_layer", "max_layer"), &RenderingServer::canvas_light_set_layer_range);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_item_cull_mask", "light", "mask"), &RenderingServer::canvas_light_set_item_cull_mask);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_item_shadow_cull_mask", "light", "mask"), &RenderingServer::canvas_light_set_item_shadow_cull_mask);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_mode", "light", "mode"), &RenderingServer::canvas_light_set_mode);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_shadow_enabled);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_buffer_size", "light", "size"), &RenderingServer::canvas_light_set_shadow_buffer_size);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_filter", "light", "filter"), &RenderingServer::canvas_light_set_shadow_filter);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth);
+
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_create"), &RenderingServer::canvas_light_occluder_create);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_attach_to_canvas", "occluder", "canvas"), &RenderingServer::canvas_light_occluder_attach_to_canvas);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_enabled", "occluder", "enabled"), &RenderingServer::canvas_light_occluder_set_enabled);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_polygon", "occluder", "polygon"), &RenderingServer::canvas_light_occluder_set_polygon);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask);
+
+ ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &RenderingServer::canvas_occluder_polygon_create);
+ ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &RenderingServer::canvas_occluder_polygon_set_shape);
+ ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape_as_lines", "occluder_polygon", "shape"), &RenderingServer::canvas_occluder_polygon_set_shape_as_lines);
+ ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_cull_mode", "occluder_polygon", "mode"), &RenderingServer::canvas_occluder_polygon_set_cull_mode);
+
+ ClassDB::bind_method(D_METHOD("black_bars_set_margins", "left", "top", "right", "bottom"), &RenderingServer::black_bars_set_margins);
+ ClassDB::bind_method(D_METHOD("black_bars_set_images", "left", "top", "right", "bottom"), &RenderingServer::black_bars_set_images);
+
+ ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingServer::free); // shouldn't conflict with Object::free()
+
+ ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &RenderingServer::request_frame_drawn_callback);
+ ClassDB::bind_method(D_METHOD("has_changed"), &RenderingServer::has_changed);
+ ClassDB::bind_method(D_METHOD("init"), &RenderingServer::init);
+ ClassDB::bind_method(D_METHOD("finish"), &RenderingServer::finish);
+ ClassDB::bind_method(D_METHOD("get_render_info", "info"), &RenderingServer::get_render_info);
+ ClassDB::bind_method(D_METHOD("get_video_adapter_name"), &RenderingServer::get_video_adapter_name);
+ ClassDB::bind_method(D_METHOD("get_video_adapter_vendor"), &RenderingServer::get_video_adapter_vendor);
+#ifndef _3D_DISABLED
+
+ ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &RenderingServer::make_sphere_mesh);
+ ClassDB::bind_method(D_METHOD("get_test_cube"), &RenderingServer::get_test_cube);
+#endif
+ ClassDB::bind_method(D_METHOD("get_test_texture"), &RenderingServer::get_test_texture);
+ ClassDB::bind_method(D_METHOD("get_white_texture"), &RenderingServer::get_white_texture);
+
+ ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "use_filter"), &RenderingServer::set_boot_image, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color);
+
+ ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature);
+ ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &RenderingServer::has_os_feature);
+ ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &RenderingServer::set_debug_generate_wireframes);
+
+ BIND_CONSTANT(NO_INDEX_ARRAY);
+ BIND_CONSTANT(ARRAY_WEIGHTS_SIZE);
+ BIND_CONSTANT(CANVAS_ITEM_Z_MIN);
+ BIND_CONSTANT(CANVAS_ITEM_Z_MAX);
+ BIND_CONSTANT(MAX_GLOW_LEVELS);
+ BIND_CONSTANT(MAX_CURSORS);
+
+ BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MIN);
+ BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MAX);
+
+ BIND_ENUM_CONSTANT(TEXTURE_LAYERED_2D_ARRAY);
+ BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP);
+ BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP_ARRAY);
+
+ BIND_ENUM_CONSTANT(CUBEMAP_LAYER_LEFT);
+ BIND_ENUM_CONSTANT(CUBEMAP_LAYER_RIGHT);
+ BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BOTTOM);
+ BIND_ENUM_CONSTANT(CUBEMAP_LAYER_TOP);
+ BIND_ENUM_CONSTANT(CUBEMAP_LAYER_FRONT);
+ BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BACK);
+
+ BIND_ENUM_CONSTANT(SHADER_SPATIAL);
+ BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM);
+ BIND_ENUM_CONSTANT(SHADER_PARTICLES);
+ BIND_ENUM_CONSTANT(SHADER_SKY);
+ BIND_ENUM_CONSTANT(SHADER_MAX);
+
+ BIND_ENUM_CONSTANT(ARRAY_VERTEX);
+ BIND_ENUM_CONSTANT(ARRAY_NORMAL);
+ BIND_ENUM_CONSTANT(ARRAY_TANGENT);
+ BIND_ENUM_CONSTANT(ARRAY_COLOR);
+ BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
+ BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
+ BIND_ENUM_CONSTANT(ARRAY_BONES);
+ BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
+ BIND_ENUM_CONSTANT(ARRAY_INDEX);
+ BIND_ENUM_CONSTANT(ARRAY_MAX);
+
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
+ BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
+
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
+ BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
+ BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
+ BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
+
+ BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
+ BIND_ENUM_CONSTANT(PRIMITIVE_LINES);
+ BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP);
+ BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES);
+ BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP);
+ BIND_ENUM_CONSTANT(PRIMITIVE_MAX);
+
+ BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
+ BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
+
+ BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_2D);
+ BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_3D);
+
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL);
+ BIND_ENUM_CONSTANT(LIGHT_OMNI);
+ BIND_ENUM_CONSTANT(LIGHT_SPOT);
+
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_INDIRECT_ENERGY);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SPECULAR);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ANGLE);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ATTENUATION);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_MAX_DISTANCE);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_FADE_START);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID);
+ BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE);
+
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS);
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS);
+
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED);
+
+ BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE);
+ BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS);
+
+ BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_INDEX);
+ BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_VIEW_DEPTH);
+
+ BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED);
+ BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE);
+ BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE);
+ BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
+ BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ALWAYS);
+
+ BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ALWAYS);
+ BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_NEVER);
+ BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ONLY_NEXT_FRAME);
+
+ BIND_ENUM_CONSTANT(VIEWPORT_MSAA_DISABLED);
+ BIND_ENUM_CONSTANT(VIEWPORT_MSAA_2X);
+ BIND_ENUM_CONSTANT(VIEWPORT_MSAA_4X);
+ BIND_ENUM_CONSTANT(VIEWPORT_MSAA_8X);
+ BIND_ENUM_CONSTANT(VIEWPORT_MSAA_16X);
+
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MAX);
+
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DISABLED);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_UNSHADED);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_LIGHTING);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OVERDRAW);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_WIREFRAME);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SSAO);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER);
+ BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_PSSM_SPLITS);
+
+ BIND_ENUM_CONSTANT(SKY_MODE_QUALITY);
+ BIND_ENUM_CONSTANT(SKY_MODE_REALTIME);
+
+ BIND_ENUM_CONSTANT(ENV_BG_CLEAR_COLOR);
+ BIND_ENUM_CONSTANT(ENV_BG_COLOR);
+ BIND_ENUM_CONSTANT(ENV_BG_SKY);
+ BIND_ENUM_CONSTANT(ENV_BG_CANVAS);
+ BIND_ENUM_CONSTANT(ENV_BG_KEEP);
+ BIND_ENUM_CONSTANT(ENV_BG_CAMERA_FEED);
+ BIND_ENUM_CONSTANT(ENV_BG_MAX);
+
+ BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_BG);
+ BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_DISABLED);
+ BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_COLOR);
+ BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_SKY);
+
+ BIND_ENUM_CONSTANT(ENV_REFLECTION_SOURCE_BG);
+ BIND_ENUM_CONSTANT(ENV_REFLECTION_SOURCE_DISABLED);
+ BIND_ENUM_CONSTANT(ENV_REFLECTION_SOURCE_SKY);
+
+ BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_ADDITIVE);
+ BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_SCREEN);
+ BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_SOFTLIGHT);
+ BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_REPLACE);
+ BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_MIX);
+
+ BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_LINEAR);
+ BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_REINHARD);
+ BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_FILMIC);
+ BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_ACES);
+
+ BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_DISABLED);
+ BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_1x1);
+ BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_2x2);
+ BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_3x3);
+
+ BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_LOW);
+ BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_MEDIUM);
+ BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_HIGH);
+ BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_ULTRA);
+
+ BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_VERY_LOW);
+ BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_LOW);
+ BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_MEDIUM);
+ BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_HIGH);
+
+ BIND_ENUM_CONSTANT(DOF_BOKEH_BOX);
+ BIND_ENUM_CONSTANT(DOF_BOKEH_HEXAGON);
+ BIND_ENUM_CONSTANT(DOF_BOKEH_CIRCLE);
+
+ BIND_ENUM_CONSTANT(SCENARIO_DEBUG_DISABLED);
+ BIND_ENUM_CONSTANT(SCENARIO_DEBUG_WIREFRAME);
+ BIND_ENUM_CONSTANT(SCENARIO_DEBUG_OVERDRAW);
+ BIND_ENUM_CONSTANT(SCENARIO_DEBUG_SHADELESS);
+
+ BIND_ENUM_CONSTANT(INSTANCE_NONE);
+ BIND_ENUM_CONSTANT(INSTANCE_MESH);
+ BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH);
+ BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE);
+ BIND_ENUM_CONSTANT(INSTANCE_PARTICLES);
+ BIND_ENUM_CONSTANT(INSTANCE_LIGHT);
+ BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE);
+ BIND_ENUM_CONSTANT(INSTANCE_GI_PROBE);
+ BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP_CAPTURE);
+ 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_MAX);
+
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON);
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED);
+ BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
+
+ BIND_ENUM_CONSTANT(NINE_PATCH_STRETCH);
+ BIND_ENUM_CONSTANT(NINE_PATCH_TILE);
+ BIND_ENUM_CONSTANT(NINE_PATCH_TILE_FIT);
+
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_DEFAULT);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_MAX);
+
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_ADD);
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_SUB);
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MIX);
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MASK);
+
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_NONE);
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF5);
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF13);
+ BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_MAX);
+
+ BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_DISABLED);
+ BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE);
+ BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE);
+
+ BIND_ENUM_CONSTANT(INFO_OBJECTS_IN_FRAME);
+ BIND_ENUM_CONSTANT(INFO_VERTICES_IN_FRAME);
+ BIND_ENUM_CONSTANT(INFO_MATERIAL_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(INFO_SHADER_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(INFO_SURFACE_CHANGES_IN_FRAME);
+ BIND_ENUM_CONSTANT(INFO_DRAW_CALLS_IN_FRAME);
+ BIND_ENUM_CONSTANT(INFO_USAGE_VIDEO_MEM_TOTAL);
+ BIND_ENUM_CONSTANT(INFO_VIDEO_MEM_USED);
+ BIND_ENUM_CONSTANT(INFO_TEXTURE_MEM_USED);
+ BIND_ENUM_CONSTANT(INFO_VERTEX_MEM_USED);
+
+ BIND_ENUM_CONSTANT(FEATURE_SHADERS);
+ BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED);
+
+ ADD_SIGNAL(MethodInfo("frame_pre_draw"));
+ ADD_SIGNAL(MethodInfo("frame_post_draw"));
+}
+
+void RenderingServer::_canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate) {
+
+ ERR_FAIL_COND(p_margins.size() != 4);
+ //canvas_item_add_style_box(p_item,p_rect,p_source,p_texture,Vector2(p_margins[0],p_margins[1]),Vector2(p_margins[2],p_margins[3]),true,p_modulate);
+}
+
+void RenderingServer::_camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) {
+
+ camera_set_orthogonal(p_camera, p_size, p_z_near, p_z_far);
+}
+
+void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry::MeshData &p_mesh_data) {
+
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+
+ for (int i = 0; i < p_mesh_data.faces.size(); i++) {
+
+ const Geometry::MeshData::Face &f = p_mesh_data.faces[i];
+
+ for (int j = 2; j < f.indices.size(); j++) {
+
+#define _ADD_VERTEX(m_idx) \
+ vertices.push_back(p_mesh_data.vertices[f.indices[m_idx]]); \
+ normals.push_back(f.plane.normal);
+
+ _ADD_VERTEX(0);
+ _ADD_VERTEX(j - 1);
+ _ADD_VERTEX(j);
+ }
+ }
+
+ Array d;
+ d.resize(RS::ARRAY_MAX);
+ d[ARRAY_VERTEX] = vertices;
+ d[ARRAY_NORMAL] = normals;
+ mesh_add_surface_from_arrays(p_mesh, PRIMITIVE_TRIANGLES, d);
+}
+
+void RenderingServer::mesh_add_surface_from_planes(RID p_mesh, const Vector<Plane> &p_planes) {
+
+ Geometry::MeshData mdata = Geometry::build_convex_mesh(p_planes);
+ mesh_add_surface_from_mesh_data(p_mesh, mdata);
+}
+
+void RenderingServer::immediate_vertex_2d(RID p_immediate, const Vector2 &p_vertex) {
+ immediate_vertex(p_immediate, Vector3(p_vertex.x, p_vertex.y, 0));
+}
+
+RID RenderingServer::instance_create2(RID p_base, RID p_scenario) {
+
+ RID instance = instance_create();
+ instance_set_base(instance, p_base);
+ instance_set_scenario(instance, p_scenario);
+ return instance;
+}
+
+RenderingServer::RenderingServer() {
+
+ //ERR_FAIL_COND(singleton);
+ 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("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/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/shadow_atlas/size", 4096);
+ GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048);
+ 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/quadrant_0_subdiv", 1);
+ GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2);
+ GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3);
+ 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"));
+
+ 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_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, "Lowest (1 Cone - Fast),Medium (4 Cones - Average),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/max_anisotropy", 4);
+
+ 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", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Low (Fast),Medium (Average),High (Slow),Ultra (Slower)"));
+ GLOBAL_DEF("rendering/quality/ssao/half_size", false);
+
+ GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter", PropertyInfo(Variant::INT, "rendering/quality/screen_filters/screen_space_roughness_limiter", PROPERTY_HINT_ENUM, "Disabled (Fast),Enabled (Average)"));
+ GLOBAL_DEF("rendering/quality/screen_filters/screen_space_roughness_limiter_curve", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_filters/screen_space_roughness_limiter_curve", PropertyInfo(Variant::FLOAT, "rendering/quality/screen_filters/screen_space_roughness_limiter_curve", PROPERTY_HINT_EXP_EASING, "0.01,8,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/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"));
+}
+
+RenderingServer::~RenderingServer() {
+
+ singleton = nullptr;
+}
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
new file mode 100644
index 0000000000..43c65d8007
--- /dev/null
+++ b/servers/rendering_server.h
@@ -0,0 +1,1226 @@
+/*************************************************************************/
+/* rendering_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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_H
+#define RENDERING_SERVER_H
+
+#include "core/image.h"
+#include "core/math/geometry.h"
+#include "core/math/transform_2d.h"
+#include "core/object.h"
+#include "core/rid.h"
+#include "core/variant.h"
+#include "servers/display_server.h"
+
+class RenderingServer : public Object {
+
+ GDCLASS(RenderingServer, Object);
+
+ static RenderingServer *singleton;
+
+ int mm_policy;
+
+ void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
+ void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1));
+ Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const;
+
+protected:
+ RID _make_test_cube();
+ void _free_internal_rids();
+ RID test_texture;
+ RID white_texture;
+ RID test_material;
+
+ Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb);
+
+ static RenderingServer *(*create_func)();
+ static void _bind_methods();
+
+public:
+ static RenderingServer *get_singleton();
+ static RenderingServer *create();
+
+ enum {
+ NO_INDEX_ARRAY = -1,
+ ARRAY_WEIGHTS_SIZE = 4,
+ CANVAS_ITEM_Z_MIN = -4096,
+ CANVAS_ITEM_Z_MAX = 4096,
+ MAX_GLOW_LEVELS = 7,
+ MAX_CURSORS = 8,
+ };
+
+ /* TEXTURE API */
+
+ enum TextureLayeredType {
+ TEXTURE_LAYERED_2D_ARRAY,
+ TEXTURE_LAYERED_CUBEMAP,
+ TEXTURE_LAYERED_CUBEMAP_ARRAY,
+ };
+
+ enum CubeMapLayer {
+
+ CUBEMAP_LAYER_LEFT,
+ CUBEMAP_LAYER_RIGHT,
+ CUBEMAP_LAYER_BOTTOM,
+ CUBEMAP_LAYER_TOP,
+ CUBEMAP_LAYER_FRONT,
+ CUBEMAP_LAYER_BACK
+ };
+
+ virtual RID texture_2d_create(const Ref<Image> &p_image) = 0;
+ virtual RID texture_2d_layered_create(const Vector<Ref<Image>> &p_layers, TextureLayeredType p_layered_type) = 0;
+ virtual RID texture_3d_create(const Vector<Ref<Image>> &p_slices) = 0; //all slices, then all the mipmaps, must be coherent
+ virtual RID texture_proxy_create(RID p_base) = 0;
+
+ 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;
+ virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0;
+ virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 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() = 0;
+ virtual RID texture_3d_placeholder_create() = 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;
+ virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const = 0;
+
+ virtual void texture_replace(RID p_texture, RID p_by_texture) = 0;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;
+// FIXME: Disabled during Vulkan refactoring, should be ported.
+#if 0
+ virtual void texture_bind(RID p_texture, uint32_t p_texture_no) = 0;
+#endif
+
+ virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
+ virtual String texture_get_path(RID p_texture) const = 0;
+
+ typedef void (*TextureDetectCallback)(void *);
+
+ virtual void texture_set_detect_3d_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0;
+ virtual void texture_set_detect_normal_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0;
+
+ enum TextureDetectRoughnessChannel {
+ TEXTURE_DETECT_ROUGNHESS_R,
+ TEXTURE_DETECT_ROUGNHESS_G,
+ TEXTURE_DETECT_ROUGNHESS_B,
+ TEXTURE_DETECT_ROUGNHESS_A,
+ TEXTURE_DETECT_ROUGNHESS_GRAY,
+ };
+
+ typedef void (*TextureDetectRoughnessCallback)(void *, const String &, TextureDetectRoughnessChannel);
+ virtual void texture_set_detect_roughness_callback(RID p_texture, TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0;
+
+ struct TextureInfo {
+ RID texture;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
+ Image::Format format;
+ int bytes;
+ String path;
+ };
+
+ virtual void texture_debug_usage(List<TextureInfo> *r_info) = 0;
+ Array _texture_debug_usage_bind();
+
+ virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
+
+ /* SHADER API */
+
+ enum ShaderMode {
+
+ SHADER_SPATIAL,
+ SHADER_CANVAS_ITEM,
+ SHADER_PARTICLES,
+ SHADER_SKY,
+ SHADER_MAX
+ };
+
+ virtual RID shader_create() = 0;
+
+ virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
+ virtual String shader_get_code(RID p_shader) const = 0;
+ virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
+ Array _shader_get_param_list_bind(RID p_shader) const;
+ virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const = 0;
+
+ virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
+ virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
+
+ /* COMMON MATERIAL API */
+
+ enum {
+ MATERIAL_RENDER_PRIORITY_MIN = -128,
+ MATERIAL_RENDER_PRIORITY_MAX = 127,
+
+ };
+ virtual RID material_create() = 0;
+
+ virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
+
+ virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
+ virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
+
+ virtual void material_set_render_priority(RID p_material, int priority) = 0;
+
+ virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0;
+
+ /* MESH API */
+
+ enum ArrayType {
+
+ ARRAY_VERTEX = 0,
+ ARRAY_NORMAL = 1,
+ ARRAY_TANGENT = 2,
+ ARRAY_COLOR = 3,
+ ARRAY_TEX_UV = 4,
+ ARRAY_TEX_UV2 = 5,
+ ARRAY_BONES = 6,
+ ARRAY_WEIGHTS = 7,
+ ARRAY_INDEX = 8,
+ ARRAY_MAX = 9
+ };
+
+ enum ArrayFormat {
+ /* ARRAY FORMAT FLAGS */
+ ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, // mandatory
+ ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL,
+ ARRAY_FORMAT_TANGENT = 1 << ARRAY_TANGENT,
+ ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
+ ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV,
+ ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2,
+ ARRAY_FORMAT_BONES = 1 << ARRAY_BONES,
+ ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS,
+ ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX,
+
+ ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1),
+ ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE),
+ ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE),
+ ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE),
+ ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE),
+ ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE),
+ ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE),
+
+ ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
+ ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
+
+ ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2
+
+ };
+
+ enum PrimitiveType {
+ PRIMITIVE_POINTS,
+ PRIMITIVE_LINES,
+ PRIMITIVE_LINE_STRIP,
+ PRIMITIVE_TRIANGLES,
+ PRIMITIVE_TRIANGLE_STRIP,
+ PRIMITIVE_MAX,
+ };
+
+ struct SurfaceData {
+
+ PrimitiveType primitive = PRIMITIVE_MAX;
+
+ uint32_t format = 0;
+ Vector<uint8_t> vertex_data;
+ uint32_t vertex_count = 0;
+ Vector<uint8_t> index_data;
+ uint32_t index_count = 0;
+
+ AABB aabb;
+ struct LOD {
+ float edge_length;
+ Vector<uint8_t> index_data;
+ };
+ Vector<LOD> lods;
+ Vector<AABB> bone_aabbs;
+
+ Vector<Vector<uint8_t>> blend_shapes;
+
+ RID material;
+ };
+
+ virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0;
+ virtual RID mesh_create() = 0;
+
+ virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const;
+ virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const;
+ /// Returns stride
+ virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const;
+ virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
+ Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const;
+ Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const;
+ Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const;
+ Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const;
+
+ virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
+ virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0;
+
+ virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
+
+ enum BlendShapeMode {
+ BLEND_SHAPE_MODE_NORMALIZED,
+ BLEND_SHAPE_MODE_RELATIVE,
+ };
+
+ virtual void mesh_set_blend_shape_mode(RID p_mesh, BlendShapeMode p_mode) = 0;
+ virtual BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
+
+ virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
+
+ virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
+ virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
+
+ virtual SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0;
+
+ virtual int mesh_get_surface_count(RID p_mesh) const = 0;
+
+ virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
+ virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
+
+ virtual void mesh_clear(RID p_mesh) = 0;
+
+ /* MULTIMESH API */
+
+ virtual RID multimesh_create() = 0;
+
+ enum MultimeshTransformFormat {
+ MULTIMESH_TRANSFORM_2D,
+ 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 int multimesh_get_instance_count(RID p_multimesh) const = 0;
+
+ virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
+ virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0;
+ virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
+ virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
+
+ virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
+ virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
+
+ virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
+ virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
+ virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
+ virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
+
+ virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
+ virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
+
+ virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
+ virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
+
+ /* IMMEDIATE API */
+
+ virtual RID immediate_create() = 0;
+ virtual void immediate_begin(RID p_immediate, PrimitiveType p_rimitive, RID p_texture = RID()) = 0;
+ virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0;
+ virtual void immediate_vertex_2d(RID p_immediate, const Vector2 &p_vertex);
+ virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0;
+ virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0;
+ virtual void immediate_color(RID p_immediate, const Color &p_color) = 0;
+ virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0;
+ virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0;
+ virtual void immediate_end(RID p_immediate) = 0;
+ virtual void immediate_clear(RID p_immediate) = 0;
+ virtual void immediate_set_material(RID p_immediate, RID p_material) = 0;
+ virtual RID immediate_get_material(RID p_immediate) const = 0;
+
+ /* SKELETON API */
+
+ virtual RID skeleton_create() = 0;
+ virtual void skeleton_allocate(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;
+ virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
+ virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
+ virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
+
+ /* Light API */
+
+ enum LightType {
+ LIGHT_DIRECTIONAL,
+ LIGHT_OMNI,
+ LIGHT_SPOT
+ };
+
+ enum LightParam {
+
+ LIGHT_PARAM_ENERGY,
+ LIGHT_PARAM_INDIRECT_ENERGY,
+ LIGHT_PARAM_SPECULAR,
+ LIGHT_PARAM_RANGE,
+ LIGHT_PARAM_SIZE,
+ LIGHT_PARAM_ATTENUATION,
+ LIGHT_PARAM_SPOT_ANGLE,
+ LIGHT_PARAM_SPOT_ATTENUATION,
+ LIGHT_PARAM_SHADOW_MAX_DISTANCE,
+ LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
+ LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
+ LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
+ LIGHT_PARAM_SHADOW_FADE_START,
+ LIGHT_PARAM_SHADOW_NORMAL_BIAS,
+ LIGHT_PARAM_SHADOW_BIAS,
+ LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
+ LIGHT_PARAM_SHADOW_BLUR,
+ LIGHT_PARAM_TRANSMITTANCE_BIAS,
+ LIGHT_PARAM_MAX
+ };
+
+ virtual RID directional_light_create() = 0;
+ virtual RID omni_light_create() = 0;
+ virtual RID spot_light_create() = 0;
+
+ virtual void light_set_color(RID p_light, const Color &p_color) = 0;
+ virtual void light_set_param(RID p_light, LightParam p_param, float p_value) = 0;
+ virtual void light_set_shadow(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0;
+ virtual void light_set_projector(RID p_light, RID p_texture) = 0;
+ virtual void light_set_negative(RID p_light, bool p_enable) = 0;
+ virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
+ virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_use_gi(RID p_light, bool p_enable) = 0;
+
+ // omni light
+ enum LightOmniShadowMode {
+ LIGHT_OMNI_SHADOW_DUAL_PARABOLOID,
+ LIGHT_OMNI_SHADOW_CUBE,
+ };
+
+ virtual void light_omni_set_shadow_mode(RID p_light, LightOmniShadowMode p_mode) = 0;
+
+ // directional light
+ enum LightDirectionalShadowMode {
+ LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL,
+ LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS,
+ LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS
+ };
+
+ virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0;
+ virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
+
+ enum LightDirectionalShadowDepthRangeMode {
+ LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
+ LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED,
+
+ };
+
+ virtual void light_directional_set_shadow_depth_range_mode(RID p_light, LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
+
+ /* PROBE API */
+
+ virtual RID reflection_probe_create() = 0;
+
+ enum ReflectionProbeUpdateMode {
+ REFLECTION_PROBE_UPDATE_ONCE,
+ REFLECTION_PROBE_UPDATE_ALWAYS,
+ };
+
+ virtual void reflection_probe_set_update_mode(RID p_probe, ReflectionProbeUpdateMode p_mode) = 0;
+ virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0;
+ virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_color) = 0;
+ virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) = 0;
+ virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) = 0;
+ virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0;
+ virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0;
+ virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0;
+ virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0;
+ virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
+ virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
+ virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
+ virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
+
+ /* DECAL API */
+
+ enum DecalTexture {
+ DECAL_TEXTURE_ALBEDO,
+ DECAL_TEXTURE_NORMAL,
+ DECAL_TEXTURE_ORM,
+ DECAL_TEXTURE_EMISSION,
+ DECAL_TEXTURE_MAX
+ };
+
+ virtual RID decal_create() = 0;
+ virtual void decal_set_extents(RID p_decal, const Vector3 &p_extents) = 0;
+ virtual void decal_set_texture(RID p_decal, DecalTexture p_type, RID p_texture) = 0;
+ virtual void decal_set_emission_energy(RID p_decal, float p_energy) = 0;
+ virtual void decal_set_albedo_mix(RID p_decal, float p_mix) = 0;
+ virtual void decal_set_modulate(RID p_decal, const Color &p_modulate) = 0;
+ virtual void decal_set_cull_mask(RID p_decal, uint32_t p_layers) = 0;
+ virtual void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) = 0;
+ virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0;
+ virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0;
+
+ /* GI PROBE API */
+
+ 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 AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
+ virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
+ virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
+ virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
+ virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0;
+ virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
+ virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
+ virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0;
+ virtual float gi_probe_get_ao(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0;
+ virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
+ virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
+ virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
+ virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
+ virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
+
+ virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
+ virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
+
+ /* LIGHTMAP CAPTURE */
+
+ virtual RID lightmap_capture_create() = 0;
+ virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0;
+ virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) = 0;
+ virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0;
+ virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0;
+ virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
+ virtual Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
+ virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
+ virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
+
+ /* PARTICLES API */
+
+ virtual RID particles_create() = 0;
+
+ virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
+ virtual bool particles_get_emitting(RID p_particles) = 0;
+ virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
+ virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
+ virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
+ virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
+ virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
+ virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
+ virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
+ virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
+ 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_fractional_delta(RID p_particles, bool p_enable) = 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;
+
+ enum ParticlesDrawOrder {
+ PARTICLES_DRAW_ORDER_INDEX,
+ PARTICLES_DRAW_ORDER_LIFETIME,
+ PARTICLES_DRAW_ORDER_VIEW_DEPTH,
+ };
+
+ virtual void particles_set_draw_order(RID p_particles, ParticlesDrawOrder p_order) = 0;
+
+ virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
+ virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
+
+ virtual AABB particles_get_current_aabb(RID p_particles) = 0;
+
+ virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; //this is only used for 2D, in 3D it's automatic
+
+ /* CAMERA API */
+
+ virtual RID camera_create() = 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;
+ virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0;
+ virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0;
+ virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
+ virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
+ 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;
+
+ /*
+ enum ParticlesCollisionMode {
+ PARTICLES_COLLISION_NONE,
+ PARTICLES_COLLISION_TEXTURE,
+ PARTICLES_COLLISION_CUBEMAP,
+ };
+
+ virtual void particles_set_collision(RID p_particles,ParticlesCollisionMode p_mode,const Transform&, p_xform,const RID p_depth_tex,const RID p_normal_tex)=0;
+*/
+ /* VIEWPORT TARGET API */
+
+ virtual RID viewport_create() = 0;
+
+ virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0;
+ virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0;
+ virtual void viewport_set_active(RID p_viewport, bool p_active) = 0;
+ virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0;
+
+ virtual void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) = 0;
+ virtual void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) = 0;
+
+ enum ViewportUpdateMode {
+ VIEWPORT_UPDATE_DISABLED,
+ VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated
+ VIEWPORT_UPDATE_WHEN_VISIBLE, // default
+ VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE,
+ VIEWPORT_UPDATE_ALWAYS
+ };
+
+ virtual void viewport_set_update_mode(RID p_viewport, ViewportUpdateMode p_mode) = 0;
+
+ enum ViewportClearMode {
+
+ VIEWPORT_CLEAR_ALWAYS,
+ VIEWPORT_CLEAR_NEVER,
+ VIEWPORT_CLEAR_ONLY_NEXT_FRAME
+ };
+
+ virtual void viewport_set_clear_mode(RID p_viewport, ViewportClearMode p_clear_mode) = 0;
+
+ virtual RID viewport_get_texture(RID p_viewport) const = 0;
+
+ virtual void viewport_set_hide_scenario(RID p_viewport, bool p_hide) = 0;
+ virtual void viewport_set_hide_canvas(RID p_viewport, bool p_hide) = 0;
+ virtual void viewport_set_disable_environment(RID p_viewport, bool p_disable) = 0;
+
+ virtual void viewport_attach_camera(RID p_viewport, RID p_camera) = 0;
+ virtual void viewport_set_scenario(RID p_viewport, RID p_scenario) = 0;
+ virtual void viewport_attach_canvas(RID p_viewport, RID p_canvas) = 0;
+ virtual void viewport_remove_canvas(RID p_viewport, RID p_canvas) = 0;
+ virtual void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) = 0;
+ virtual void viewport_set_transparent_background(RID p_viewport, bool p_enabled) = 0;
+
+ virtual void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) = 0;
+ virtual void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) = 0;
+
+ virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0;
+ virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0;
+
+ enum ViewportMSAA {
+ VIEWPORT_MSAA_DISABLED,
+ VIEWPORT_MSAA_2X,
+ VIEWPORT_MSAA_4X,
+ VIEWPORT_MSAA_8X,
+ VIEWPORT_MSAA_16X,
+ VIEWPORT_MSAA_MAX,
+ };
+
+ virtual void viewport_set_msaa(RID p_viewport, ViewportMSAA p_msaa) = 0;
+
+ enum ViewportScreenSpaceAA {
+ VIEWPORT_SCREEN_SPACE_AA_DISABLED,
+ VIEWPORT_SCREEN_SPACE_AA_FXAA,
+ };
+ virtual void viewport_set_screen_space_aa(RID p_viewport, ViewportScreenSpaceAA p_mode) = 0;
+
+ enum ViewportRenderInfo {
+
+ VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME,
+ VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME,
+ VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME,
+ VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME,
+ VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME,
+ VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME,
+ VIEWPORT_RENDER_INFO_MAX
+ };
+
+ virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) = 0;
+
+ enum ViewportDebugDraw {
+ VIEWPORT_DEBUG_DRAW_DISABLED,
+ VIEWPORT_DEBUG_DRAW_UNSHADED,
+ VIEWPORT_DEBUG_DRAW_LIGHTING,
+ VIEWPORT_DEBUG_DRAW_OVERDRAW,
+ VIEWPORT_DEBUG_DRAW_WIREFRAME,
+ VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER,
+ VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO,
+ VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING,
+ VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION,
+ VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS,
+ VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
+ VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE,
+ VIEWPORT_DEBUG_DRAW_SSAO,
+ VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER,
+ VIEWPORT_DEBUG_DRAW_PSSM_SPLITS,
+ VIEWPORT_DEBUG_DRAW_DECAL_ATLAS,
+
+ };
+
+ virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0;
+
+ virtual void viewport_set_measure_render_time(RID p_viewport, bool p_enable) = 0;
+ virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0;
+ virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0;
+
+ virtual void directional_shadow_atlas_set_size(int p_size) = 0;
+
+ /* SKY API */
+
+ enum SkyMode {
+ SKY_MODE_QUALITY,
+ SKY_MODE_REALTIME
+ };
+
+ virtual RID sky_create() = 0;
+ virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0;
+ virtual void sky_set_mode(RID p_sky, SkyMode p_mode) = 0;
+ virtual void sky_set_material(RID p_sky, RID p_material) = 0;
+
+ /* ENVIRONMENT API */
+
+ virtual RID environment_create() = 0;
+
+ enum EnvironmentBG {
+
+ ENV_BG_CLEAR_COLOR,
+ ENV_BG_COLOR,
+ ENV_BG_SKY,
+ ENV_BG_CANVAS,
+ ENV_BG_KEEP,
+ ENV_BG_CAMERA_FEED,
+ ENV_BG_MAX
+ };
+
+ enum EnvironmentAmbientSource {
+ ENV_AMBIENT_SOURCE_BG,
+ ENV_AMBIENT_SOURCE_DISABLED,
+ ENV_AMBIENT_SOURCE_COLOR,
+ ENV_AMBIENT_SOURCE_SKY,
+ };
+
+ enum EnvironmentReflectionSource {
+ ENV_REFLECTION_SOURCE_BG,
+ ENV_REFLECTION_SOURCE_DISABLED,
+ ENV_REFLECTION_SOURCE_SKY,
+ };
+
+ virtual void environment_set_background(RID p_env, EnvironmentBG p_bg) = 0;
+ virtual void environment_set_sky(RID p_env, RID p_sky) = 0;
+ virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0;
+ virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0;
+ virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
+ virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
+ virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
+ virtual void environment_set_ambient_light(RID p_env, const Color &p_color, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0;
+// FIXME: Disabled during Vulkan refactoring, should be ported.
+#if 0
+ virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
+#endif
+
+ enum EnvironmentGlowBlendMode {
+ ENV_GLOW_BLEND_MODE_ADDITIVE,
+ ENV_GLOW_BLEND_MODE_SCREEN,
+ ENV_GLOW_BLEND_MODE_SOFTLIGHT,
+ ENV_GLOW_BLEND_MODE_REPLACE,
+ ENV_GLOW_BLEND_MODE_MIX,
+ };
+ virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0;
+
+ virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
+
+ enum EnvironmentToneMapper {
+ ENV_TONE_MAPPER_LINEAR,
+ ENV_TONE_MAPPER_REINHARD,
+ ENV_TONE_MAPPER_FILMIC,
+ ENV_TONE_MAPPER_ACES
+ };
+
+ virtual void environment_set_tonemap(RID p_env, 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_grey) = 0;
+ virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
+
+ virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0;
+
+ enum EnvironmentSSRRoughnessQuality {
+ ENV_SSR_ROUGNESS_QUALITY_DISABLED,
+ ENV_SSR_ROUGNESS_QUALITY_LOW,
+ ENV_SSR_ROUGNESS_QUALITY_MEDIUM,
+ ENV_SSR_ROUGNESS_QUALITY_HIGH,
+ };
+
+ virtual void environment_set_ssr_roughness_quality(EnvironmentSSRRoughnessQuality p_quality) = 0;
+
+ enum EnvironmentSSAOBlur {
+ ENV_SSAO_BLUR_DISABLED,
+ ENV_SSAO_BLUR_1x1,
+ ENV_SSAO_BLUR_2x2,
+ ENV_SSAO_BLUR_3x3,
+ };
+
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0;
+
+ enum EnvironmentSSAOQuality {
+ ENV_SSAO_QUALITY_LOW,
+ ENV_SSAO_QUALITY_MEDIUM,
+ ENV_SSAO_QUALITY_HIGH,
+ ENV_SSAO_QUALITY_ULTRA,
+ };
+
+ virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size) = 0;
+
+ virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0;
+ virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;
+ virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0;
+
+ virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0;
+
+ enum SubSurfaceScatteringQuality {
+ SUB_SURFACE_SCATTERING_QUALITY_DISABLED,
+ SUB_SURFACE_SCATTERING_QUALITY_LOW,
+ SUB_SURFACE_SCATTERING_QUALITY_MEDIUM,
+ SUB_SURFACE_SCATTERING_QUALITY_HIGH,
+ };
+
+ virtual void sub_surface_scattering_set_quality(SubSurfaceScatteringQuality p_quality) = 0;
+ virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0;
+
+ /* CAMERA EFFECTS */
+
+ virtual RID camera_effects_create() = 0;
+
+ enum DOFBlurQuality {
+ DOF_BLUR_QUALITY_VERY_LOW,
+ DOF_BLUR_QUALITY_LOW,
+ DOF_BLUR_QUALITY_MEDIUM,
+ DOF_BLUR_QUALITY_HIGH,
+ };
+
+ virtual void camera_effects_set_dof_blur_quality(DOFBlurQuality p_quality, bool p_use_jitter) = 0;
+
+ enum DOFBokehShape {
+ DOF_BOKEH_BOX,
+ DOF_BOKEH_HEXAGON,
+ DOF_BOKEH_CIRCLE
+ };
+
+ virtual void camera_effects_set_dof_blur_bokeh_shape(DOFBokehShape p_shape) = 0;
+
+ virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
+ virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
+
+ enum ShadowQuality {
+ SHADOW_QUALITY_HARD,
+ SHADOW_QUALITY_SOFT_LOW,
+ SHADOW_QUALITY_SOFT_MEDIUM,
+ SHADOW_QUALITY_SOFT_HIGH,
+ SHADOW_QUALITY_SOFT_ULTRA,
+ SHADOW_QUALITY_MAX
+ };
+
+ virtual void shadows_quality_set(ShadowQuality p_quality) = 0;
+ virtual void directional_shadow_quality_set(ShadowQuality p_quality) = 0;
+
+ /* SCENARIO API */
+
+ virtual RID scenario_create() = 0;
+
+ enum ScenarioDebugMode {
+ SCENARIO_DEBUG_DISABLED,
+ SCENARIO_DEBUG_WIREFRAME,
+ SCENARIO_DEBUG_OVERDRAW,
+ SCENARIO_DEBUG_SHADELESS,
+
+ };
+
+ virtual void scenario_set_debug(RID p_scenario, ScenarioDebugMode p_debug_mode) = 0;
+ virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0;
+ virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0;
+ virtual void scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) = 0;
+
+ /* INSTANCING API */
+
+ enum InstanceType {
+
+ INSTANCE_NONE,
+ INSTANCE_MESH,
+ INSTANCE_MULTIMESH,
+ INSTANCE_IMMEDIATE,
+ INSTANCE_PARTICLES,
+ INSTANCE_LIGHT,
+ INSTANCE_REFLECTION_PROBE,
+ INSTANCE_DECAL,
+ INSTANCE_GI_PROBE,
+ INSTANCE_LIGHTMAP_CAPTURE,
+ INSTANCE_MAX,
+
+ INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)
+ };
+
+ virtual RID instance_create2(RID p_base, RID p_scenario);
+
+ virtual RID instance_create() = 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;
+ virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0;
+ 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_visible(RID p_instance, bool p_visible) = 0;
+
+ virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) = 0;
+
+ virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0;
+
+ virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0;
+ virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0;
+
+ virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
+
+ // don't use these in a game!
+ virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
+ virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0;
+ virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0;
+
+ Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const;
+ Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
+ Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const;
+
+ enum InstanceFlags {
+ INSTANCE_FLAG_USE_BAKED_LIGHT,
+ INSTANCE_FLAG_USE_DYNAMIC_GI,
+ INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
+ INSTANCE_FLAG_MAX
+ };
+
+ enum ShadowCastingSetting {
+ SHADOW_CASTING_SETTING_OFF,
+ SHADOW_CASTING_SETTING_ON,
+ SHADOW_CASTING_SETTING_DOUBLE_SIDED,
+ SHADOW_CASTING_SETTING_SHADOWS_ONLY,
+ };
+
+ virtual void instance_geometry_set_flag(RID p_instance, InstanceFlags p_flags, bool p_enabled) = 0;
+ virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) = 0;
+ virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0;
+
+ virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
+ virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0;
+
+ /* CANVAS (2D) */
+
+ virtual RID canvas_create() = 0;
+ virtual void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) = 0;
+ virtual void canvas_set_modulate(RID p_canvas, const Color &p_color) = 0;
+ virtual void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) = 0;
+
+ virtual void canvas_set_disable_scale(bool p_disable) = 0;
+
+ virtual RID canvas_item_create() = 0;
+ virtual void canvas_item_set_parent(RID p_item, RID p_parent) = 0;
+
+ virtual void canvas_item_set_visible(RID p_item, bool p_visible) = 0;
+ virtual void canvas_item_set_light_mask(RID p_item, int p_mask) = 0;
+
+ virtual void canvas_item_set_update_when_visible(RID p_item, bool p_update) = 0;
+
+ virtual void canvas_item_set_transform(RID p_item, const Transform2D &p_transform) = 0;
+ virtual void canvas_item_set_clip(RID p_item, bool p_clip) = 0;
+ virtual void canvas_item_set_distance_field_mode(RID p_item, bool p_enable) = 0;
+ virtual void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2()) = 0;
+ virtual void canvas_item_set_modulate(RID p_item, const Color &p_color) = 0;
+ virtual void canvas_item_set_self_modulate(RID p_item, const Color &p_color) = 0;
+
+ virtual void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) = 0;
+
+ enum NinePatchAxisMode {
+ NINE_PATCH_STRETCH,
+ NINE_PATCH_TILE,
+ NINE_PATCH_TILE_FIT,
+ };
+
+ enum CanvasItemTextureFilter {
+ CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item
+ CANVAS_ITEM_TEXTURE_FILTER_NEAREST,
+ CANVAS_ITEM_TEXTURE_FILTER_LINEAR,
+ CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS,
+ CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
+ CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC,
+ CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
+ CANVAS_ITEM_TEXTURE_FILTER_MAX
+ };
+
+ enum CanvasItemTextureRepeat {
+ CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item
+ CANVAS_ITEM_TEXTURE_REPEAT_DISABLED,
+ CANVAS_ITEM_TEXTURE_REPEAT_ENABLED,
+ CANVAS_ITEM_TEXTURE_REPEAT_MIRROR,
+ CANVAS_ITEM_TEXTURE_REPEAT_MAX,
+ };
+
+ //takes effect only for new draw commands
+ virtual void canvas_item_set_default_texture_filter(RID p_item, CanvasItemTextureFilter p_filter) = 0;
+ virtual void canvas_item_set_default_texture_repeat(RID p_item, CanvasItemTextureRepeat p_repeat) = 0;
+
+ virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
+ virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
+ virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_clip_uv = false, CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
+ virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
+ virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0;
+ virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0;
+ virtual void canvas_item_set_z_index(RID p_item, int p_z) = 0;
+ virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) = 0;
+ virtual void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) = 0;
+
+ virtual void canvas_item_attach_skeleton(RID p_item, RID p_skeleton) = 0;
+
+ virtual void canvas_item_clear(RID p_item) = 0;
+ virtual void canvas_item_set_draw_index(RID p_item, int p_index) = 0;
+
+ virtual void canvas_item_set_material(RID p_item, RID p_material) = 0;
+
+ virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
+
+ virtual RID canvas_light_create() = 0;
+ virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0;
+ virtual void canvas_light_set_enabled(RID p_light, bool p_enabled) = 0;
+ virtual void canvas_light_set_scale(RID p_light, float p_scale) = 0;
+ virtual void canvas_light_set_transform(RID p_light, const Transform2D &p_transform) = 0;
+ virtual void canvas_light_set_texture(RID p_light, RID p_texture) = 0;
+ virtual void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) = 0;
+ virtual void canvas_light_set_color(RID p_light, const Color &p_color) = 0;
+ virtual void canvas_light_set_height(RID p_light, float p_height) = 0;
+ virtual void canvas_light_set_energy(RID p_light, float p_energy) = 0;
+ virtual void canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) = 0;
+ virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) = 0;
+ virtual void canvas_light_set_item_cull_mask(RID p_light, int p_mask) = 0;
+ virtual void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) = 0;
+
+ enum CanvasLightMode {
+ CANVAS_LIGHT_MODE_ADD,
+ CANVAS_LIGHT_MODE_SUB,
+ CANVAS_LIGHT_MODE_MIX,
+ CANVAS_LIGHT_MODE_MASK,
+ };
+
+ virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) = 0;
+
+ enum CanvasLightShadowFilter {
+ CANVAS_LIGHT_FILTER_NONE,
+ CANVAS_LIGHT_FILTER_PCF5,
+ CANVAS_LIGHT_FILTER_PCF13,
+ CANVAS_LIGHT_FILTER_MAX
+ };
+
+ virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) = 0;
+ virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size) = 0;
+ virtual void canvas_light_set_shadow_filter(RID p_light, CanvasLightShadowFilter p_filter) = 0;
+ virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0;
+ virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0;
+
+ virtual RID canvas_light_occluder_create() = 0;
+ virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) = 0;
+ virtual void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) = 0;
+ virtual void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) = 0;
+ virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0;
+ virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0;
+
+ virtual RID canvas_occluder_polygon_create() = 0;
+ virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) = 0;
+ virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) = 0;
+
+ enum CanvasOccluderPolygonCullMode {
+ CANVAS_OCCLUDER_POLYGON_CULL_DISABLED,
+ CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE,
+ CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE,
+ };
+ virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, CanvasOccluderPolygonCullMode p_mode) = 0;
+
+ /* BLACK BARS */
+
+ virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) = 0;
+ virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) = 0;
+
+ /* FREE */
+
+ virtual void free(RID p_rid) = 0; ///< free RIDs associated with the visual server
+
+ virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) = 0;
+
+ /* EVENT QUEUING */
+
+ virtual void draw(bool p_swap_buffers = true, double frame_step = 0.0) = 0;
+ virtual void sync() = 0;
+ virtual bool has_changed() const = 0;
+ virtual void init() = 0;
+ virtual void finish() = 0;
+
+ /* STATUS INFORMATION */
+
+ enum RenderInfo {
+
+ INFO_OBJECTS_IN_FRAME,
+ INFO_VERTICES_IN_FRAME,
+ INFO_MATERIAL_CHANGES_IN_FRAME,
+ INFO_SHADER_CHANGES_IN_FRAME,
+ INFO_SURFACE_CHANGES_IN_FRAME,
+ INFO_DRAW_CALLS_IN_FRAME,
+ INFO_USAGE_VIDEO_MEM_TOTAL,
+ INFO_VIDEO_MEM_USED,
+ INFO_TEXTURE_MEM_USED,
+ INFO_VERTEX_MEM_USED,
+ };
+
+ virtual int get_render_info(RenderInfo p_info) = 0;
+ virtual String get_video_adapter_name() const = 0;
+ virtual String get_video_adapter_vendor() const = 0;
+
+ struct FrameProfileArea {
+ String name;
+ float gpu_msec;
+ float cpu_msec;
+ };
+
+ virtual void set_frame_profiling_enabled(bool p_enable) = 0;
+ virtual Vector<FrameProfileArea> get_frame_profile() = 0;
+ virtual uint64_t get_frame_profile_frame() = 0;
+
+ /* Materials for 2D on 3D */
+
+ /* TESTING */
+
+ virtual RID get_test_cube() = 0;
+
+ virtual RID get_test_texture();
+ virtual RID get_white_texture();
+
+ virtual RID make_sphere_mesh(int p_lats, int p_lons, float p_radius);
+
+ virtual void mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry::MeshData &p_mesh_data);
+ virtual void mesh_add_surface_from_planes(RID p_mesh, const Vector<Plane> &p_planes);
+
+ virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0;
+ virtual void set_default_clear_color(const Color &p_color) = 0;
+
+ enum Features {
+ FEATURE_SHADERS,
+ FEATURE_MULTITHREADED,
+ };
+
+ virtual bool has_feature(Features p_feature) const = 0;
+
+ virtual bool has_os_feature(const String &p_feature) const = 0;
+
+ virtual void set_debug_generate_wireframes(bool p_generate) = 0;
+
+ virtual void call_set_use_vsync(bool p_enable) = 0;
+
+ virtual bool is_low_end() const = 0;
+
+ RenderingServer();
+ virtual ~RenderingServer();
+};
+
+// make variant understand the enums
+VARIANT_ENUM_CAST(RenderingServer::TextureLayeredType);
+VARIANT_ENUM_CAST(RenderingServer::CubeMapLayer);
+VARIANT_ENUM_CAST(RenderingServer::ShaderMode);
+VARIANT_ENUM_CAST(RenderingServer::ArrayType);
+VARIANT_ENUM_CAST(RenderingServer::ArrayFormat);
+VARIANT_ENUM_CAST(RenderingServer::PrimitiveType);
+VARIANT_ENUM_CAST(RenderingServer::BlendShapeMode);
+VARIANT_ENUM_CAST(RenderingServer::MultimeshTransformFormat);
+VARIANT_ENUM_CAST(RenderingServer::LightType);
+VARIANT_ENUM_CAST(RenderingServer::LightParam);
+VARIANT_ENUM_CAST(RenderingServer::LightOmniShadowMode);
+VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowMode);
+VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowDepthRangeMode);
+VARIANT_ENUM_CAST(RenderingServer::ReflectionProbeUpdateMode);
+VARIANT_ENUM_CAST(RenderingServer::DecalTexture);
+VARIANT_ENUM_CAST(RenderingServer::ParticlesDrawOrder);
+VARIANT_ENUM_CAST(RenderingServer::ViewportUpdateMode);
+VARIANT_ENUM_CAST(RenderingServer::ViewportClearMode);
+VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA);
+VARIANT_ENUM_CAST(RenderingServer::ViewportRenderInfo);
+VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw);
+VARIANT_ENUM_CAST(RenderingServer::SkyMode);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentReflectionSource);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentGlowBlendMode);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality);
+VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOBlur);
+VARIANT_ENUM_CAST(RenderingServer::DOFBlurQuality);
+VARIANT_ENUM_CAST(RenderingServer::DOFBokehShape);
+VARIANT_ENUM_CAST(RenderingServer::ScenarioDebugMode);
+VARIANT_ENUM_CAST(RenderingServer::InstanceType);
+VARIANT_ENUM_CAST(RenderingServer::InstanceFlags);
+VARIANT_ENUM_CAST(RenderingServer::ShadowCastingSetting);
+VARIANT_ENUM_CAST(RenderingServer::NinePatchAxisMode);
+VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureFilter);
+VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureRepeat);
+VARIANT_ENUM_CAST(RenderingServer::CanvasLightMode);
+VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter);
+VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode);
+VARIANT_ENUM_CAST(RenderingServer::RenderInfo);
+VARIANT_ENUM_CAST(RenderingServer::Features);
+
+//typedef RenderingServer VS; // makes it easier to use
+#define RS RenderingServer
+
+#endif
diff --git a/servers/visual/SCsub b/servers/visual/SCsub
deleted file mode 100644
index fca18bfea0..0000000000
--- a/servers/visual/SCsub
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.servers_sources, "*.cpp")
-
-SConscript("rasterizer_rd/SCsub")
diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp
deleted file mode 100644
index a3f93a3f8c..0000000000
--- a/servers/visual/rasterizer.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*************************************************************************/
-/* rasterizer.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer.h"
-
-#include "core/os/os.h"
-#include "core/print_string.h"
-
-Rasterizer *(*Rasterizer::_create_func)() = NULL;
-
-void RasterizerScene::InstanceDependency::instance_notify_changed(bool p_aabb, bool p_dependencies) {
- for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- E->key()->dependency_changed(p_aabb, p_dependencies);
- }
-}
-void RasterizerScene::InstanceDependency::instance_notify_deleted(RID p_deleted) {
- for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- E->key()->dependency_deleted(p_deleted);
- }
- for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- E->key()->dependencies.erase(this);
- }
-
- instances.clear();
-}
-
-RasterizerScene::InstanceDependency::~InstanceDependency() {
-#ifdef DEBUG_ENABLED
- if (instances.size()) {
- WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing.");
- for (Map<InstanceBase *, uint32_t>::Element *E = instances.front(); E; E = E->next()) {
- E->key()->dependencies.erase(this);
- }
- }
-#endif
-}
-
-Rasterizer *Rasterizer::create() {
-
- return _create_func();
-}
-
-RasterizerCanvas *RasterizerCanvas::singleton = NULL;
-
-RasterizerStorage *RasterizerStorage::base_singleton = NULL;
-
-RasterizerStorage::RasterizerStorage() {
-
- base_singleton = this;
-}
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
deleted file mode 100644
index 0a55c78133..0000000000
--- a/servers/visual/rasterizer.h
+++ /dev/null
@@ -1,1307 +0,0 @@
-/*************************************************************************/
-/* rasterizer.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_H
-#define RASTERIZER_H
-
-#include "core/math/camera_matrix.h"
-#include "servers/visual_server.h"
-
-#include "core/pair.h"
-#include "core/self_list.h"
-
-class RasterizerScene {
-
-public:
- /* SHADOW ATLAS API */
-
- virtual RID shadow_atlas_create() = 0;
- virtual void shadow_atlas_set_size(RID p_atlas, int p_size) = 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;
-
- virtual void directional_shadow_atlas_set_size(int p_size) = 0;
- virtual int get_directional_light_shadow_size(RID p_light_intance) = 0;
- virtual void set_directional_shadow_count(int p_count) = 0;
-
- /* SKY API */
-
- virtual RID sky_create() = 0;
- virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0;
- virtual void sky_set_mode(RID p_sky, VS::SkyMode p_samples) = 0;
- virtual void sky_set_texture(RID p_sky, RID p_panorama) = 0;
-
- /* ENVIRONMENT API */
-
- virtual RID environment_create() = 0;
-
- virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg) = 0;
- virtual void environment_set_sky(RID p_env, RID p_sky) = 0;
- virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0;
- virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0;
- virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
- virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
- virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
- virtual void environment_set_ambient_light(RID p_env, const Color &p_color, VS::EnvironmentAmbientSource p_ambient = VS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, VS::EnvironmentReflectionSource p_reflection_source = VS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0;
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
-#endif
-
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) = 0;
- virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) = 0;
-
- virtual void 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, bool p_roughness) = 0;
- virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0;
-
- virtual void environment_set_ssao_quality(VS::EnvironmentSSAOQuality p_quality, bool p_half_size) = 0;
-
- virtual void environment_set_tonemap(RID p_env, VS::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) = 0;
-
- virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
-
- virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0;
- virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;
- virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0;
-
- virtual bool is_environment(RID p_env) const = 0;
- virtual VS::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 void camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter) = 0;
- virtual void camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape) = 0;
-
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
-
- struct InstanceBase;
-
- struct InstanceDependency {
-
- void instance_notify_changed(bool p_aabb, bool p_dependencies);
- void instance_notify_deleted(RID p_deleted);
-
- ~InstanceDependency();
-
- private:
- friend struct InstanceBase;
- Map<InstanceBase *, uint32_t> instances;
- };
-
- struct InstanceBase {
-
- VS::InstanceType base_type;
- RID base;
-
- RID skeleton;
- RID material_override;
-
- RID instance_data;
-
- Transform transform;
-
- int depth_layer;
- uint32_t layer_mask;
- uint32_t instance_version;
-
- //RID sampled_light;
-
- Vector<RID> materials;
- Vector<RID> light_instances;
- Vector<RID> reflection_probe_instances;
- Vector<RID> gi_probe_instances;
-
- Vector<float> blend_values;
-
- VS::ShadowCastingSetting cast_shadows;
-
- //fit in 32 bits
- bool mirror : 8;
- bool receive_shadows : 8;
- bool visible : 8;
- bool baked_light : 2; //this flag is only to know if it actually did use baked light
- bool dynamic_gi : 2; //this flag is only to know if it actually did use baked light
- bool redraw_if_visible : 4;
-
- float depth; //used for sorting
-
- SelfList<InstanceBase> dependency_item;
-
- InstanceBase *lightmap_capture;
- RID lightmap;
- Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
-
- AABB aabb;
- AABB transformed_aabb;
-
- virtual void dependency_deleted(RID p_dependency) = 0;
- virtual void dependency_changed(bool p_aabb, bool p_dependencies) = 0;
-
- Set<InstanceDependency *> dependencies;
-
- void instance_increase_version() {
- instance_version++;
- }
-
- void update_dependency(InstanceDependency *p_dependency) {
- dependencies.insert(p_dependency);
- p_dependency->instances[this] = instance_version;
- }
-
- void clean_up_dependencies() {
- List<Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> > to_clean_up;
- for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
- InstanceDependency *dep = E->get();
- Map<InstanceBase *, uint32_t>::Element *F = dep->instances.find(this);
- ERR_CONTINUE(!F);
- if (F->get() != instance_version) {
- Pair<InstanceDependency *, Map<InstanceBase *, uint32_t>::Element *> p;
- p.first = dep;
- p.second = F;
- to_clean_up.push_back(p);
- }
- }
-
- while (to_clean_up.size()) {
- to_clean_up.front()->get().first->instances.erase(to_clean_up.front()->get().second);
- to_clean_up.pop_front();
- }
- }
-
- void clear_dependencies() {
- for (Set<InstanceDependency *>::Element *E = dependencies.front(); E; E = E->next()) {
- InstanceDependency *dep = E->get();
- dep->instances.erase(this);
- }
- dependencies.clear();
- }
-
- InstanceBase() :
- dependency_item(this) {
-
- base_type = VS::INSTANCE_NONE;
- cast_shadows = VS::SHADOW_CASTING_SETTING_ON;
- receive_shadows = true;
- visible = true;
- depth_layer = 0;
- layer_mask = 1;
- instance_version = 0;
- baked_light = false;
- dynamic_gi = false;
- redraw_if_visible = false;
- lightmap_capture = NULL;
- }
-
- virtual ~InstanceBase() {
- clear_dependencies();
- }
- };
-
- virtual RID light_instance_create(RID p_light) = 0;
- virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0;
- virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0) = 0;
- virtual void light_instance_mark_visible(RID p_light_instance) = 0;
- virtual bool light_instances_can_render_shadow_cube() const { return true; }
-
- virtual RID reflection_atlas_create() = 0;
- virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
-
- virtual RID reflection_probe_instance_create(RID p_probe) = 0;
- virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
- virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
- virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
- virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
- virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
- virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
-
- virtual RID gi_probe_instance_create(RID p_gi_probe) = 0;
- virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0;
- virtual bool gi_probe_needs_update(RID p_probe) const = 0;
- virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) = 0;
-
- virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) = 0;
-
- virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) = 0;
- virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 0;
-
- virtual void set_scene_pass(uint64_t p_pass) = 0;
- virtual void set_time(double p_time, double p_step) = 0;
- virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) = 0;
-
- 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, VS::ViewportMSAA p_msaa) = 0;
-
- virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0;
- virtual bool screen_space_roughness_limiter_is_active() const = 0;
-
- virtual bool free(RID p_rid) = 0;
-
- virtual void update() = 0;
- virtual ~RasterizerScene() {}
-};
-
-class RasterizerStorage {
-
- Color default_clear_color;
-
-public:
- /* 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, VS::TextureLayeredType p_layered_type) = 0;
- virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent
- virtual RID texture_proxy_create(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;
- virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0;
- 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() = 0;
- virtual RID texture_3d_placeholder_create() = 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;
- virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const = 0;
-
- virtual void texture_replace(RID p_texture, RID p_by_texture) = 0;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- virtual void texture_bind(RID p_texture, uint32_t p_texture_no) = 0;
-#endif
-
- virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
- virtual String texture_get_path(RID p_texture) const = 0;
-
- virtual void texture_set_detect_3d_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) = 0;
- virtual void texture_set_detect_normal_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) = 0;
- virtual void texture_set_detect_roughness_callback(RID p_texture, VS::TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0;
-
- virtual void texture_debug_usage(List<VS::TextureInfo> *r_info) = 0;
-
- virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
-
- virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
-
- /* SHADER API */
-
- virtual RID shader_create() = 0;
-
- virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
- virtual String shader_get_code(RID p_shader) const = 0;
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
-
- virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
- virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
- virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0;
-
- /* COMMON MATERIAL API */
-
- virtual RID material_create() = 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;
-
- virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
- virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
-
- virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0;
-
- virtual bool material_is_animated(RID p_material) = 0;
- virtual bool material_casts_shadows(RID p_material) = 0;
-
- virtual void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) = 0;
-
- /* MESH API */
-
- virtual RID mesh_create() = 0;
-
- /// Returns stride
- virtual void mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface) = 0;
-
- virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
-
- virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) = 0;
- virtual VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
-
- virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
-
- virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
- virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
-
- virtual VS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0;
-
- virtual int mesh_get_surface_count(RID p_mesh) const = 0;
-
- virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
- virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
-
- virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) = 0;
-
- virtual void mesh_clear(RID p_mesh) = 0;
-
- /* MULTIMESH API */
-
- virtual RID multimesh_create() = 0;
-
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::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;
- virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0;
- virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
- virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
- virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
-
- virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
-
- virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
- virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
- virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
- virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
-
- virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
- virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
-
- virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
- virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
-
- virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
-
- /* IMMEDIATE API */
-
- virtual RID immediate_create() = 0;
- virtual void immediate_begin(RID p_immediate, VS::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;
- virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0;
- virtual void immediate_color(RID p_immediate, const Color &p_color) = 0;
- virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0;
- virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0;
- virtual void immediate_end(RID p_immediate) = 0;
- virtual void immediate_clear(RID p_immediate) = 0;
- virtual void immediate_set_material(RID p_immediate, RID p_material) = 0;
- virtual RID immediate_get_material(RID p_immediate) const = 0;
- virtual AABB immediate_get_aabb(RID p_immediate) const = 0;
-
- /* SKELETON API */
-
- virtual RID skeleton_create() = 0;
- virtual void skeleton_allocate(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;
- virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
- virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
- virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
-
- /* Light API */
-
- virtual RID light_create(VS::LightType p_type) = 0;
-
- RID directional_light_create() { return light_create(VS::LIGHT_DIRECTIONAL); }
- RID omni_light_create() { return light_create(VS::LIGHT_OMNI); }
- RID spot_light_create() { return light_create(VS::LIGHT_SPOT); }
-
- virtual void light_set_color(RID p_light, const Color &p_color) = 0;
- virtual void light_set_param(RID p_light, VS::LightParam p_param, float p_value) = 0;
- virtual void light_set_shadow(RID p_light, bool p_enabled) = 0;
- virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0;
- virtual void light_set_projector(RID p_light, RID p_texture) = 0;
- virtual void light_set_negative(RID p_light, bool p_enable) = 0;
- virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
- virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
- virtual void light_set_use_gi(RID p_light, bool p_enable) = 0;
-
- virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) = 0;
-
- virtual void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) = 0;
- virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
- virtual bool light_directional_get_blend_splits(RID p_light) const = 0;
- virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
- virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0;
-
- virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0;
- virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0;
-
- virtual bool light_has_shadow(RID p_light) const = 0;
-
- virtual VS::LightType light_get_type(RID p_light) const = 0;
- virtual AABB light_get_aabb(RID p_light) const = 0;
- virtual float light_get_param(RID p_light, VS::LightParam p_param) = 0;
- virtual Color light_get_color(RID p_light) = 0;
- virtual bool light_get_use_gi(RID p_light) = 0;
- virtual uint64_t light_get_version(RID p_light) const = 0;
-
- /* PROBE API */
-
- virtual RID reflection_probe_create() = 0;
-
- virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) = 0;
- virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
- virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0;
- virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) = 0;
- virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) = 0;
- virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) = 0;
- virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0;
- virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0;
- virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0;
- virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0;
- virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
- virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
- virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
-
- virtual AABB reflection_probe_get_aabb(RID p_probe) const = 0;
- virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const = 0;
- virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const = 0;
- virtual Vector3 reflection_probe_get_extents(RID p_probe) const = 0;
- virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const = 0;
- virtual float reflection_probe_get_origin_max_distance(RID p_probe) const = 0;
- virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
-
- virtual void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
- virtual void skeleton_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
-
- /* GI PROBE API */
-
- 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 AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
- virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0;
-
- virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
- virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
- virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0;
- virtual float gi_probe_get_ao(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0;
- virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
- virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
- virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
-
- virtual uint32_t gi_probe_get_version(RID p_probe) = 0;
-
- /* LIGHTMAP CAPTURE */
-
- struct LightmapCaptureOctree {
-
- enum {
- CHILD_EMPTY = 0xFFFFFFFF
- };
-
- uint16_t light[6][3]; //anisotropic light
- float alpha;
- uint32_t children[8];
- };
-
- virtual RID lightmap_capture_create() = 0;
- virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0;
- virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0;
- virtual void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) = 0;
- virtual Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
- virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0;
- virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0;
- virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0;
- virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
- virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
- virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
- virtual const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const = 0;
-
- /* PARTICLES */
-
- virtual RID particles_create() = 0;
-
- virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
- virtual bool particles_get_emitting(RID p_particles) = 0;
-
- virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
- virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
- virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
- virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
- virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
- virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
- virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
- virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
- 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_fractional_delta(RID p_particles, bool p_enable) = 0;
- virtual void particles_restart(RID p_particles) = 0;
-
- virtual bool particles_is_inactive(RID p_particles) const = 0;
-
- virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) = 0;
-
- virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
- virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
-
- virtual void particles_request_process(RID p_particles) = 0;
- virtual AABB particles_get_current_aabb(RID p_particles) = 0;
- virtual AABB particles_get_aabb(RID p_particles) const = 0;
-
- virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0;
-
- 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;
-
- /* RENDER TARGET */
-
- enum RenderTargetFlags {
- RENDER_TARGET_TRANSPARENT,
- RENDER_TARGET_DIRECT_TO_SCREEN,
- RENDER_TARGET_FLAG_MAX
- };
-
- virtual RID render_target_create() = 0;
- virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0;
- virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0;
- virtual RID render_target_get_texture(RID p_render_target) = 0;
- virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
- virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
- virtual bool render_target_was_used(RID p_render_target) = 0;
- virtual void render_target_set_as_unused(RID p_render_target) = 0;
-
- virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0;
- virtual bool render_target_is_clear_requested(RID p_render_target) = 0;
- virtual Color render_target_get_clear_request_color(RID p_render_target) = 0;
- virtual void render_target_disable_clear_request(RID p_render_target) = 0;
- virtual void render_target_do_clear_request(RID p_render_target) = 0;
-
- virtual VS::InstanceType get_base_type(RID p_rid) const = 0;
- virtual bool free(RID p_rid) = 0;
-
- virtual bool has_os_feature(const String &p_feature) const = 0;
-
- virtual void update_dirty_resources() = 0;
-
- virtual void set_debug_generate_wireframes(bool p_generate) = 0;
-
- virtual void render_info_begin_capture() = 0;
- virtual void render_info_end_capture() = 0;
- virtual int get_captured_render_info(VS::RenderInfo p_info) = 0;
-
- virtual int get_render_info(VS::RenderInfo p_info) = 0;
- virtual String get_video_adapter_name() const = 0;
- virtual String get_video_adapter_vendor() const = 0;
-
- static RasterizerStorage *base_singleton;
-
- void set_default_clear_color(const Color &p_color) {
- default_clear_color = p_color;
- }
-
- Color get_default_clear_color() const {
- return default_clear_color;
- }
-#define TIMESTAMP_BEGIN() \
- { \
- if (VSG::storage->capturing_timestamps) VSG::storage->capture_timestamps_begin(); \
- }
-
-#define RENDER_TIMESTAMP(m_text) \
- { \
- if (VSG::storage->capturing_timestamps) VSG::storage->capture_timestamp(m_text); \
- }
-
- bool capturing_timestamps = false;
-
- virtual void capture_timestamps_begin() = 0;
- virtual void capture_timestamp(const String &p_name) = 0;
- virtual uint32_t get_captured_timestamps_count() const = 0;
- virtual uint64_t get_captured_timestamps_frame() const = 0;
- virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0;
- virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0;
- virtual String get_captured_timestamp_name(uint32_t p_index) const = 0;
-
- RasterizerStorage();
- virtual ~RasterizerStorage() {}
-};
-
-class RasterizerCanvas {
-public:
- static RasterizerCanvas *singleton;
-
- enum CanvasRectFlags {
-
- CANVAS_RECT_REGION = 1,
- CANVAS_RECT_TILE = 2,
- CANVAS_RECT_FLIP_H = 4,
- CANVAS_RECT_FLIP_V = 8,
- CANVAS_RECT_TRANSPOSE = 16,
- CANVAS_RECT_CLIP_UV = 32
- };
-
- struct Light {
-
- bool enabled;
- Color color;
- Transform2D xform;
- float height;
- float energy;
- float scale;
- int z_min;
- int z_max;
- int layer_min;
- int layer_max;
- int item_mask;
- int item_shadow_mask;
- VS::CanvasLightMode mode;
- RID texture;
- Vector2 texture_offset;
- RID canvas;
- bool use_shadow;
- int shadow_buffer_size;
- VS::CanvasLightShadowFilter shadow_filter;
- Color shadow_color;
- float shadow_smooth;
-
- //void *texture_cache; // implementation dependent
- Rect2 rect_cache;
- Transform2D xform_cache;
- float radius_cache; //used for shadow far plane
- //CameraMatrix shadow_matrix_cache;
-
- Transform2D light_shader_xform;
- //Vector2 light_shader_pos;
-
- Light *shadows_next_ptr;
- Light *filter_next_ptr;
- Light *next_ptr;
- Light *mask_next_ptr;
-
- RID light_internal;
- uint64_t version;
-
- int32_t render_index_cache;
-
- Light() {
- version = 0;
- enabled = true;
- color = Color(1, 1, 1);
- shadow_color = Color(0, 0, 0, 0);
- height = 0;
- z_min = -1024;
- z_max = 1024;
- layer_min = 0;
- layer_max = 0;
- item_mask = 1;
- scale = 1.0;
- energy = 1.0;
- item_shadow_mask = -1;
- mode = VS::CANVAS_LIGHT_MODE_ADD;
- // texture_cache = NULL;
- next_ptr = NULL;
- mask_next_ptr = NULL;
- filter_next_ptr = NULL;
- use_shadow = false;
- shadow_buffer_size = 2048;
- shadow_filter = VS::CANVAS_LIGHT_FILTER_NONE;
- shadow_smooth = 0.0;
- render_index_cache = -1;
- }
- };
-
- typedef uint64_t TextureBindingID;
-
- virtual TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) = 0;
- virtual void free_texture_binding(TextureBindingID p_binding) = 0;
-
- //easier wrap to avoid mistakes
-
- struct Item;
-
- struct TextureBinding {
-
- TextureBindingID binding_id;
-
- _FORCE_INLINE_ void create(VS::CanvasItemTextureFilter p_item_filter, VS::CanvasItemTextureRepeat p_item_repeat, RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
- if (p_filter == VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
- p_filter = p_item_filter;
- }
- if (p_repeat == VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
- p_repeat = p_item_repeat;
- }
- if (p_texture != RID() || p_normalmap != RID() || p_specular != RID() || p_filter != VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT || p_repeat != VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT || p_multimesh.is_valid()) {
- ERR_FAIL_COND(binding_id != 0);
- binding_id = singleton->request_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh);
- }
- }
-
- _FORCE_INLINE_ TextureBinding() { binding_id = 0; }
- _FORCE_INLINE_ ~TextureBinding() {
- if (binding_id) singleton->free_texture_binding(binding_id);
- }
- };
-
- typedef uint64_t PolygonID;
- virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0;
- virtual void free_polygon(PolygonID p_polygon) = 0;
-
- //also easier to wrap to avoid mistakes
- struct Polygon {
-
- PolygonID polygon_id;
- Rect2 rect_cache;
-
- _FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) {
- ERR_FAIL_COND(polygon_id != 0);
- {
- uint32_t pc = p_points.size();
- const Vector2 *v2 = p_points.ptr();
- rect_cache.position = *v2;
- for (uint32_t i = 1; i < pc; i++) {
- rect_cache.expand_to(v2[i]);
- }
- }
- polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights);
- }
-
- _FORCE_INLINE_ Polygon() { polygon_id = 0; }
- _FORCE_INLINE_ ~Polygon() {
- if (polygon_id) singleton->free_polygon(polygon_id);
- }
- };
-
- //item
-
- struct Item {
-
- //commands are allocated in blocks of 4k to improve performance
- //and cache coherence.
- //blocks always grow but never shrink.
-
- struct CommandBlock {
- enum {
- MAX_SIZE = 4096
- };
- uint32_t usage;
- uint8_t *memory;
- };
-
- struct Command {
-
- enum Type {
-
- TYPE_RECT,
- TYPE_NINEPATCH,
- TYPE_POLYGON,
- TYPE_PRIMITIVE,
- TYPE_MESH,
- TYPE_MULTIMESH,
- TYPE_PARTICLES,
- TYPE_TRANSFORM,
- TYPE_CLIP_IGNORE,
- };
-
- Command *next;
- Type type;
- virtual ~Command() {}
- };
-
- struct CommandRect : public Command {
-
- Rect2 rect;
- Color modulate;
- Rect2 source;
- uint8_t flags;
- Color specular_shininess;
-
- TextureBinding texture_binding;
-
- CommandRect() {
- flags = 0;
- type = TYPE_RECT;
- }
- };
-
- struct CommandNinePatch : public Command {
-
- Rect2 rect;
- Rect2 source;
- float margin[4];
- bool draw_center;
- Color color;
- VS::NinePatchAxisMode axis_x;
- VS::NinePatchAxisMode axis_y;
- Color specular_shininess;
- TextureBinding texture_binding;
- CommandNinePatch() {
- draw_center = true;
- type = TYPE_NINEPATCH;
- }
- };
-
- struct CommandPolygon : public Command {
-
- VS::PrimitiveType primitive;
- Polygon polygon;
- Color specular_shininess;
- TextureBinding texture_binding;
- CommandPolygon() {
- type = TYPE_POLYGON;
- }
- };
-
- struct CommandPrimitive : public Command {
-
- uint32_t point_count;
- Vector2 points[4];
- Vector2 uvs[4];
- Color colors[4];
- Color specular_shininess;
- TextureBinding texture_binding;
- CommandPrimitive() {
- type = TYPE_PRIMITIVE;
- }
- };
-
- struct CommandMesh : public Command {
-
- RID mesh;
- Transform2D transform;
- Color modulate;
- Color specular_shininess;
- TextureBinding texture_binding;
- CommandMesh() { type = TYPE_MESH; }
- };
-
- struct CommandMultiMesh : public Command {
-
- RID multimesh;
- Color specular_shininess;
- TextureBinding texture_binding;
- CommandMultiMesh() { type = TYPE_MULTIMESH; }
- };
-
- struct CommandParticles : public Command {
-
- RID particles;
- Color specular_shininess;
- TextureBinding texture_binding;
- CommandParticles() { type = TYPE_PARTICLES; }
- };
-
- struct CommandTransform : public Command {
-
- Transform2D xform;
- CommandTransform() { type = TYPE_TRANSFORM; }
- };
-
- struct CommandClipIgnore : public Command {
-
- bool ignore;
- CommandClipIgnore() {
- type = TYPE_CLIP_IGNORE;
- ignore = false;
- }
- };
-
- struct ViewportRender {
- VisualServer *owner;
- void *udata;
- Rect2 rect;
- };
-
- Transform2D xform;
- bool clip;
- bool visible;
- bool behind;
- bool update_when_visible;
- //VS::MaterialBlendMode blend_mode;
- int light_mask;
- int z_final;
-
- mutable bool custom_rect;
- mutable bool rect_dirty;
- mutable Rect2 rect;
- RID material;
- RID skeleton;
-
- Item *next;
-
- struct CopyBackBuffer {
- Rect2 rect;
- Rect2 screen_rect;
- bool full;
- };
- CopyBackBuffer *copy_back_buffer;
-
- Color final_modulate;
- Transform2D final_transform;
- Rect2 final_clip_rect;
- Item *final_clip_owner;
- Item *material_owner;
- ViewportRender *vp_render;
- bool distance_field;
- bool light_masked;
-
- Rect2 global_rect_cache;
-
- const Rect2 &get_rect() const {
- if (custom_rect || (!rect_dirty && !update_when_visible))
- return rect;
-
- //must update rect
-
- if (commands == NULL) {
-
- rect = Rect2();
- rect_dirty = false;
- return rect;
- }
-
- Transform2D xf;
- bool found_xform = false;
- bool first = true;
-
- const Item::Command *c = commands;
-
- while (c) {
-
- Rect2 r;
-
- switch (c->type) {
- case Item::Command::TYPE_RECT: {
-
- const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c);
- r = crect->rect;
-
- } break;
- case Item::Command::TYPE_NINEPATCH: {
-
- const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c);
- r = style->rect;
- } break;
-
- case Item::Command::TYPE_POLYGON: {
-
- const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
- r = polygon->polygon.rect_cache;
- } break;
- case Item::Command::TYPE_PRIMITIVE: {
-
- const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
- for (uint32_t j = 0; j < primitive->point_count; j++) {
- if (j == 0) {
- r.position = primitive->points[0];
- } else {
- r.expand_to(primitive->points[j]);
- }
- }
- } break;
- case Item::Command::TYPE_MESH: {
-
- const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
- AABB aabb = RasterizerStorage::base_singleton->mesh_get_aabb(mesh->mesh, RID());
-
- r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
-
- } break;
- case Item::Command::TYPE_MULTIMESH: {
-
- const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
- AABB aabb = RasterizerStorage::base_singleton->multimesh_get_aabb(multimesh->multimesh);
-
- r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
-
- } break;
- case Item::Command::TYPE_PARTICLES: {
-
- const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
- if (particles_cmd->particles.is_valid()) {
- AABB aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles);
- r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
- }
-
- } break;
- case Item::Command::TYPE_TRANSFORM: {
-
- const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
- xf = transform->xform;
- found_xform = true;
- [[fallthrough]];
- }
- default: {
- c = c->next;
- continue;
- }
- }
-
- if (found_xform) {
- r = xf.xform(r);
- found_xform = false;
- }
-
- if (first) {
- rect = r;
- first = false;
- } else {
- rect = rect.merge(r);
- }
- c = c->next;
- }
-
- rect_dirty = false;
- return rect;
- }
-
- Command *commands;
- Command *last_command;
- Vector<CommandBlock> blocks;
- uint32_t current_block;
-
- template <class T>
- T *alloc_command() {
- T *command;
- if (commands == NULL) {
- // As the most common use case of canvas items is to
- // use only one command, the first is done with it's
- // own allocation. The rest of them use blocks.
- command = memnew(T);
- command->next = NULL;
- commands = command;
- last_command = command;
- } else {
- //Subsequent commands go into a block.
-
- while (true) {
- if (unlikely(current_block == (uint32_t)blocks.size())) {
- // If we need more blocks, we allocate them
- // (they won't be freed until this CanvasItem is
- // deleted, though).
- CommandBlock cb;
- cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE);
- cb.usage = 0;
- blocks.push_back(cb);
- }
-
- CommandBlock *c = &blocks.write[current_block];
- size_t space_left = CommandBlock::MAX_SIZE - c->usage;
- if (space_left < sizeof(T)) {
- current_block++;
- continue;
- }
-
- //allocate block and add to the linked list
- void *memory = c->memory + c->usage;
- command = memnew_placement(memory, T);
- command->next = NULL;
- last_command->next = command;
- last_command = command;
- c->usage += sizeof(T);
- break;
- }
- }
-
- rect_dirty = true;
- return command;
- }
-
- struct CustomData {
-
- virtual ~CustomData() {}
- };
-
- mutable CustomData *custom_data; //implementation dependent
-
- void clear() {
- Command *c = commands;
- while (c) {
- Command *n = c->next;
- if (c == commands) {
- memdelete(commands);
- commands = NULL;
- } else {
- c->~Command();
- }
- c = n;
- }
- {
- uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size());
- CommandBlock *blockptr = blocks.ptrw();
- for (uint32_t i = 0; i < cbc; i++) {
- blockptr[i].usage = 0;
- }
- }
-
- last_command = NULL;
- commands = NULL;
- current_block = 0;
- clip = false;
- rect_dirty = true;
- final_clip_owner = NULL;
- material_owner = NULL;
- light_masked = false;
- }
- Item() {
- commands = NULL;
- last_command = NULL;
- current_block = 0;
- light_mask = 1;
- vp_render = NULL;
- next = NULL;
- final_clip_owner = NULL;
- clip = false;
- final_modulate = Color(1, 1, 1, 1);
- visible = true;
- rect_dirty = true;
- custom_rect = false;
- behind = false;
- material_owner = NULL;
- copy_back_buffer = NULL;
- distance_field = false;
- light_masked = false;
- update_when_visible = false;
- z_final = 0;
- custom_data = NULL;
- }
- virtual ~Item() {
- clear();
- for (int i = 0; i < blocks.size(); i++) {
- memfree(blocks[i].memory);
- }
- if (copy_back_buffer) memdelete(copy_back_buffer);
- if (custom_data) {
- memdelete(custom_data);
- }
- }
- };
-
- virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0;
- virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
-
- struct LightOccluderInstance {
-
- bool enabled;
- RID canvas;
- RID polygon;
- RID occluder;
- Rect2 aabb_cache;
- Transform2D xform;
- Transform2D xform_cache;
- int light_mask;
- VS::CanvasOccluderPolygonCullMode cull_cache;
-
- LightOccluderInstance *next;
-
- LightOccluderInstance() {
- enabled = true;
- next = NULL;
- light_mask = 1;
- cull_cache = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
- }
- };
-
- virtual RID light_create() = 0;
- virtual void light_set_texture(RID p_rid, RID p_texture) = 0;
- virtual void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) = 0;
- virtual void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0;
-
- virtual RID occluder_polygon_create() = 0;
- virtual void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) = 0;
- virtual void occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) = 0;
-
- virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0;
-
- virtual bool free(RID p_rid) = 0;
- virtual void update() = 0;
-
- RasterizerCanvas() { singleton = this; }
- virtual ~RasterizerCanvas() {}
-};
-
-class Rasterizer {
-protected:
- static Rasterizer *(*_create_func)();
-
-public:
- static Rasterizer *create();
-
- virtual RasterizerStorage *get_storage() = 0;
- virtual RasterizerCanvas *get_canvas() = 0;
- virtual RasterizerScene *get_scene() = 0;
-
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0;
-
- virtual void initialize() = 0;
- virtual void begin_frame(double frame_step) = 0;
-
- struct BlitToScreen {
- RID render_target;
- Rect2i rect;
- //lens distorted parameters for VR should go here
- };
-
- virtual void prepare_for_blitting_render_targets() = 0;
- virtual void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
-
- virtual void end_frame(bool p_swap_buffers) = 0;
- virtual void finalize() = 0;
-
- virtual bool is_low_end() const = 0;
-
- virtual ~Rasterizer() {}
-};
-
-#endif // RASTERIZER_H
diff --git a/servers/visual/rasterizer_rd/SCsub b/servers/visual/rasterizer_rd/SCsub
deleted file mode 100644
index cc17feeb05..0000000000
--- a/servers/visual/rasterizer_rd/SCsub
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-env.add_source_files(env.servers_sources, "*.cpp")
-
-SConscript("shaders/SCsub")
diff --git a/servers/visual/rasterizer_rd/cubemap_coeffs.h b/servers/visual/rasterizer_rd/cubemap_coeffs.h
deleted file mode 100644
index 9d4117191b..0000000000
--- a/servers/visual/rasterizer_rd/cubemap_coeffs.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 Activision Publishing, Inc.
-//
-// 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 CUBEMAP_COEFFS_H
-#define CUBEMAP_COEFFS_H
-
-const float low_quality_coeffs[7][5][6][4] = { { { { 0.0002037563, 0.0045063655, -0.0016408688, 0.00012037493 }, { -9.1834951e-05, -0.008947532, -8.1524405e-05, -3.9080094e-05 }, { -2.6038267e-05, -6.8409667e-05, 7.2175702e-05, 0.25492775 }, { -9.9426044e-05, 0.0025427756, -0.00074437925, 1.1773191e-05 }, { -3.2668211e-05, 0.0026930659, -4.824934e-05, -0.0006835048 }, { -0.0002864144, -0.0032220854, 0.0021558286, -0.00014573736 } }, { { 0.00030683201, 0.0026819548, -0.00060011756, -0.0067169226 }, { -0.0030993251, 0.0098575575, 0.0022416671, -8.9075401e-05 }, { 0.00052405626, 0.00057860515, 0.00011654518, -0.048018609 }, { 0.00010850967, -0.0088443512, -0.0018168095, 8.6633128e-05 }, { 0.003333989, -0.0050956447, -8.0414612e-05, 0.0049721239 }, { -4.0961436e-05, -8.5486984e-05, 0.0058683066, 2.2978359e-05 } }, { { 0.99999993, 0.99998625, 0.99999847, 0.99997743 }, { 0.99999519, 0.99991138, 0.99999748, 1 }, { 0.99999986, 0.99999983, 0.99999999, 0.96576708 }, { 0.99999999, 0.99995765, 0.99999807, 1 }, { 0.99999444, 0.99998339, 1, 0.99998741 }, { 0.99999996, 0.99999481, 0.99998046, 0.99999999 } }, { { -0.32267524, -0.65409377, -1.4666488, 0.87153305 }, { -1.264365, 0.89880861, -1.2245906, -0.88501403 }, { -0.31118682, -0.086150323, -0.58811532, 1.1317711 }, { -1.2193493, 1.250379, -1.0871569, -0.12694096 }, { -0.4012249, -0.47436307, -0.59661001, 2.7313005 }, { -1.3109856, 0.60929855, 0.55672643, -0.39880018 } }, { { 0.93273157, 0.59530745, 1.1994788, 0.19102276 }, { 1.2272239, 0.23245736, 1.2577607, 2.5491008 }, { 1.1210098, 0.83074953, 1.3049282, -0.001940633 }, { 1.5839111, 0.10520816, 1.150458, 2.3251789 }, { 0.688692, 0.59807498, 1.3374877, 0.095746692 }, { 1.3054173, 0.36604721, 0.065870226, 1.6496907 } } }, { { { 0.10348445, -4.6771514e-07, -0.011513131, 8.8921052e-05 }, { -0.042152043, 0.013143535, 0.00029120107, 0.036661611 }, { -0.04516036, 0.011438473, -0.0099289792, -0.011707897 }, { -0.034779497, 0.0090981166, -5.4202726e-05, 0.038592793 }, { -0.0071967376, -0.0056614418, -0.012278945, 0.0056867462 }, { -0.037678514, 0.011570177, 0.00029044557, 0.038583909 } }, { { 0.048320869, 1.4603673e-05, 0.0092672368, 0.00033289199 }, { 0.0071001761, -0.0090106091, -0.0027305905, -0.00221479 }, { -0.0027204116, 0.00017921587, 0.015296357, -0.00010306185 }, { 0.0079350203, -0.014772431, -1.2410913e-05, -0.0062296897 }, { 0.025087691, 0.00086046427, 0.015034685, -0.00078224706 }, { 0.00074587265, -0.014602074, 0.00027338224, -0.012848552 } }, { { 0.99345662, 1, 0.99989078, 0.99999994 }, { 0.99908598, 0.99987302, 0.99999623, 0.99932528 }, { 0.99897605, 0.99993456, 0.9998337, 0.99993145 }, { 0.99936351, 0.99984949, 1, 0.9992356 }, { 0.99965935, 0.9999836, 0.99981158, 0.99998352 }, { 0.99928963, 0.99982644, 0.99999992, 0.99917276 } }, { { 3.6882765, 0.15963861, 0.55983965, 0.4075649 }, { 2.1169304, 0.56463157, 0.52957047, 2.0117964 }, { 3.1080461, 0.09682931, 0.42125986, 0.089254784 }, { 1.4247315, 0.48411378, -0.17039102, 1.7431674 }, { 4.0339531, 0.14046159, 0.89848909, 0.011661811 }, { 1.9787852, 0.61750145, 0.63514194, 1.9359003 } }, { { 0.030848793, 1.4472743, 1.4356825, 1.4078009 }, { 0.37639678, 1.0793106, 1.1945413, 0.43983395 }, { 0.27451605, 1.5256415, 1.016769, 1.4850575 }, { 0.54580883, 1.1332879, 3.1331784, 0.60772955 }, { 0.11785158, 1.3928946, 0.94998805, 1.0377182 }, { 0.2842108, 1.0026911, 1.9064553, 0.27147854 } } }, { { { -0.096789259, 0.10326967, 0.0011799959, -0.03077328 }, { 0.08342021, 0.033260738, -0.00045864451, -0.021450568 }, { -0.093369441, -0.05807574, -0.033745214, 0.023817208 }, { 0.056747754, 0.031140512, 0.00019362509, -0.023727797 }, { -0.084538386, -0.040545412, -0.0076838784, 0.03424599 }, { 0.074312056, 0.027619787, 0.0015509082, -0.031043528 } }, { { -0.0085160473, -0.012179292, 0.0049910118, 0.020224799 }, { 0.022559343, -0.016273333, -0.0069382139, 0.00058083224 }, { -0.001115062, 0.035002846, -0.0038974773, -0.039378629 }, { 0.0014921617, -0.00058523872, -0.0011606685, 0.02807528 }, { -0.021454809, 0.052957852, -0.0022083677, -0.027956663 }, { -0.016486487, -0.0040233682, 0.00029949558, 0.021924605 } }, { { 0.99526846, 0.99457883, 0.99998685, 0.99932175 }, { 0.99625908, 0.99931422, 0.99997583, 0.99976974 }, { 0.99563091, 0.99769836, 0.99942287, 0.99894047 }, { 0.99838743, 0.99951485, 0.99999931, 0.99932416 }, { 0.99618922, 0.99777329, 0.99996804, 0.99902234 }, { 0.99709875, 0.9996104, 0.99999875, 0.99927754 } }, { { 3.0342011, 4.8022834, 1.3814123, 1.5280754 }, { 2.9043837, 1.7325954, 1.422223, 2.0569263 }, { 3.0358722, 5.3331504, 1.5680146, 1.6079289 }, { 3.2062833, 1.5368069, 1.0484709, 1.5399477 }, { 2.4471653, 4.0916696, 1.5060688, 1.5807009 }, { 2.6932695, 1.5161537, 1.3991175, 1.6301918 } }, { { 0.50787578, 0.17735471, 1.4006765, 1.0878482 }, { 0.69514518, 1.6765187, 1.2224869, 1.3461327 }, { 0.71381288, 0.17509216, 1.2712934, 0.94575821 }, { 1.1817337, 1.796984, 1.8671538, 1.5708691 }, { 0.55621228, 0.38291359, 1.4128781, 0.82625349 }, { 0.72441647, 1.005794, 1.5522327, 1.6032524 } } }, { { { -0.00041301094, -0.095882618, 0.26932618, -0.25137214 }, { 0.13737415, -0.12694293, -0.0090389663, 0.07227623 }, { -0.005236407, -0.0072961249, 0.27776083, -0.19536433 }, { 0.12781899, -0.042881667, -0.095979169, 0.088937396 }, { 0.037496084, -0.090547583, 0.22112334, -0.21930294 }, { 0.13353408, -0.084346121, -0.011365728, 0.043459312 } }, { { -0.05799135, -0.048612281, 0.02422989, 0.015536268 }, { -0.083144241, 0.039381032, 0.018705957, 0.029297922 }, { 0.026364989, -0.041927591, 0.036718516, 0.0050376168 }, { -0.11562256, 0.043521976, -0.014481644, 0.01529188 }, { -0.047859898, -0.057779647, -0.053171395, -0.0063193506 }, { -0.028781196, 0.041145059, -0.00018523142, 0.053524246 } }, { { 0.998317, 0.99420489, 0.96274416, 0.96776581 }, { 0.98702349, 0.99112796, 0.99978417, 0.99695425 }, { 0.99963867, 0.99909401, 0.95994827, 0.9807178 }, { 0.98503489, 0.99813175, 0.99527799, 0.99591983 }, { 0.99815003, 0.99421459, 0.97379529, 0.97563635 }, { 0.99062621, 0.99558667, 0.99993539, 0.99762039 } }, { { 2.3221943, 2.5383575, 4.3177232, 4.2016467 }, { 3.1936529, 3.0443024, 2.548962, 2.7636456 }, { 2.5923827, 2.3497949, 4.2471014, 4.1975975 }, { 3.3748785, 3.2836577, 2.9220414, 2.7175317 }, { 2.3290083, 2.5560991, 4.3572168, 4.4372585 }, { 3.1512055, 3.2863613, 2.4475378, 2.3620003 } }, { { 0.62833231, 0.52378061, 0.55845033, 0.64883444 }, { 0.76905594, 1.1017801, 1.8714048, 1.5664383 }, { 1.5283278, 1.2423369, 0.62247385, 1.0341956 }, { 0.77484548, 1.6866409, 1.0307399, 1.4224643 }, { 0.85627405, 0.72516079, 0.70094339, 0.7547877 }, { 1.202842, 1.7650605, 1.5938526, 0.97031337 } } }, { { { -0.078108035, -0.049518839, 0.26950139, -0.51522828 }, { 0.43015518, -0.045354216, 0.094550359, -0.2395012 }, { -0.079900522, -0.082582235, 0.24464909, -0.5234896 }, { 0.38422945, -0.023833644, 0.07334288, -0.22827313 }, { -0.075370379, -0.05156594, 0.19883182, -0.45064193 }, { 0.46285395, 0.021899343, 0.10155287, -0.25974773 } }, { { 0.068681419, -0.32175988, 0.15143274, -0.0066205388 }, { -0.17060226, 0.31051319, -0.080511981, -0.1593209 }, { 0.08167251, -0.32517768, 0.10937023, -0.06941926 }, { -0.14580685, 0.32474959, -0.081718057, -0.11068378 }, { 0.053961394, -0.29322836, 0.10408839, -0.02243046 }, { -0.030598471, 0.34332821, -0.091528353, -0.16299796 } }, { { 0.99457629, 0.9455255, 0.95101899, 0.85702741 }, { 0.88648824, 0.94948647, 0.99225906, 0.95773484 }, { 0.99345131, 0.94204015, 0.96342357, 0.84919939 }, { 0.9116513, 0.94549969, 0.99395321, 0.96728511 }, { 0.99569447, 0.95465076, 0.97449039, 0.89242295 }, { 0.88590629, 0.93896015, 0.99061071, 0.95182077 } }, { { 3.6380949, 4.1749529, 4.1351439, 4.8389883 }, { 5.256362, 4.2027959, 3.6096892, 3.9848645 }, { 3.5689427, 3.8620869, 4.0023981, 4.8268584 }, { 5.1128497, 4.468934, 3.5851596, 4.047485 }, { 3.7014988, 4.1310058, 4.2446872, 5.3049323 }, { 4.8659881, 4.3133002, 3.4582876, 3.8863853 } }, { { 1.6276316, 0.7747672, 1.0485958, 0.73900224 }, { 0.72010795, 0.65403093, 1.3179681, 0.65610074 }, { 1.5881174, 0.55108527, 1.0509725, 0.72153362 }, { 1.1389053, 1.0905142, 1.6661598, 0.9987548 }, { 1.977914, 0.83001686, 1.0571479, 0.80249183 }, { 0.94107069, 0.80840873, 0.95379751, 0.50386367 } } }, { { { 0.015525428, -0.48038019, -0.021799698, 0.43629156 }, { 0.045681247, -0.55039024, -0.54573329, 0.57817853 }, { -0.045869129, -0.42209953, -0.14040829, 0.37787106 }, { 0.66327604, -0.70070311, -0.55261635, 0.63446196 }, { 0.015397585, -0.43515767, -0.021927897, 0.4203714 }, { 0.85681772, -0.65394729, -0.67557236, 0.60104142 } }, { { -0.31503888, -0.26745648, 0.26817896, 0.26548747 }, { -0.93282124, -0.033621213, 0.68374802, -0.10858524 }, { -0.21723689, -0.17935495, 0.38521982, 0.2578335 }, { -0.39913153, 0.23555359, 0.59589456, -0.19075103 }, { -0.28851798, -0.24142459, 0.28279261, 0.24766617 }, { -0.29435977, -0.25850549, 0.57790878, -0.200546 } }, { { 0.94895177, 0.83528552, 0.96312243, 0.85974768 }, { 0.35743218, 0.8342303, 0.48442112, 0.80865248 }, { 0.97504059, 0.88863029, 0.9120807, 0.88923301 }, { 0.63305523, 0.67344611, 0.58268761, 0.74904744 }, { 0.95735066, 0.86738225, 0.9589304, 0.87289711 }, { 0.42333878, 0.71100482, 0.45784651, 0.77364753 } }, { { 5.3641275, 5.2550422, 5.3103777, 5.2851215 }, { 5.2657045, 6.2095784, 6.9549598, 4.9205516 }, { 5.163385, 5.3141038, 4.9907618, 5.3583852 }, { 6.1257061, 6.1102338, 6.9549598, 5.3129951 }, { 5.3138838, 5.3257842, 5.3133783, 5.2687156 }, { 5.8915091, 6.153324, 6.9549598, 4.9568971 } }, { { 3.1221918, 1.1882615, 2.6991784, 1.1185048 }, { -0.2322432, -0.16590163, 0.088416958, 0.057399579 }, { 3.4395383, 1.5836276, 2.6242352, 1.2873336 }, { -0.23767634, -0.79425452, 0.20477899, 0.40461516 }, { 2.2521751, 1.1933374, 2.3309484, 1.0185309 }, { -0.099258385, -0.2173726, 0.0736866, 0.15470436 } } }, { { { 0.066050217, -0.33053278, -0.13771479, 0.33278465 }, { 0.00084467977, -0.50077778, -0.30083482, 0.6494273 }, { 0.24880159, -0.30354993, -0.15417892, 0.38203296 }, { -0.073325098, -0.4778777, 0.10779844, 0.66683723 }, { 0.15703809, -0.36335455, -0.15657631, 0.35926503 }, { 0.26127617, -0.29524368, -0.14490804, 0.65461301 } }, { { -0.57970022, -0.33939622, 0.72169742, 0.320959 }, { -0.38698206, -0.12730306, 0.65810895, 0.026509232 }, { -0.6199708, -0.34745658, 0.68683659, 0.34547285 }, { -0.3613378, -0.14006845, 0.65917895, 0.038446867 }, { -0.57778101, -0.35057776, 0.57837882, 0.36488991 }, { -0.50051482, -0.019174387, 0.50816239, 0.02682636 } }, { { 0.8121484, 0.88065787, 0.67837119, 0.88670158 }, { 0.92208686, 0.85616327, 0.69021085, -0.75996148 }, { 0.74413303, 0.88720424, 0.71027063, 0.85714604 }, { 0.92954743, 0.86718726, 0.74421946, -0.74421095 }, { 0.80094204, 0.86317363, 0.8006009, 0.85894353 }, { 0.82536033, 0.95522956, 0.8489833, -0.75548802 } }, { { 5.7725061, 5.1565901, 5.6224483, 5.0847054 }, { 5.7717118, 6.4180057, 6.9797014, -0.03290957 }, { 5.7847117, 5.2015529, 5.614561, 5.2019388 }, { 6.2613999, 6.5807982, 6.9797014, -0.032764603 }, { 5.823775, 5.2332343, 5.826694, 5.197143 }, { 6.3463188, 5.8174311, 6.9797014, -0.032766769 } }, { { 2.96787, 1.3557735, 2.0749129, 1.3066609 }, { -0.92782801, 0.0079162579, -0.33479446, 2.699659e-05 }, { 2.1997063, 3.1083252, 2.6810949, 1.8276262 }, { -0.48654719, -0.10954189, -0.32175132, 5.490092e-05 }, { 3.1970446, 1.787085, 3.062849, 1.6274811 }, { -0.78882801, -0.34050184, -0.59962127, 3.6554198e-05 } } } };
-
-const float high_quality_coeffs[7][5][3][24][4] = { { { { { -4.8355339e-06, -4.4902569e-05, -9.2632249e-05, -0.00053773136 }, { 0.0040143823, -0.00060900339, -0.0095301923, -0.0053956011 }, { -0.0005923892, -3.6901978e-05, -5.6694857e-06, -0.00017018564 }, { 0.0012441402, 0.02236187, 0.022751769, 0.0062788948 }, { 0.00013810055, -2.2709815e-05, 0.0054849671, -1.6599195e-05 }, { -0.020320408, -0.017066319, -0.017457746, 0.022910628 }, { 0.00024171724, 9.7419073e-05, -0.00047804272, -0.00010093683 }, { 7.6988167e-05, 1.8551597e-05, -5.7692813e-05, -3.332362e-05 }, { -0.00062766208, 2.713742e-05, 0.00026511682, 2.3841873e-05 }, { -0.00043656844, 0.0028645469, 0.0049817085, 0.0080221478 }, { -3.3210444e-05, -8.0852386e-05, -2.2111492e-06, -8.4430827e-05 }, { 0.010967284, 0.018811225, 0.017569463, -0.0046944996 }, { -0.00018391248, -0.00010462174, -0.00017726, -0.00018490133 }, { 0.00012591989, 0.015965386, 0.015964059, -0.0078018431 }, { -0.006125333, -8.2224165e-05, -0.00020500151, -0.00025207244 }, { -0.00016320041, -0.0001279242, 0.00014038799, 8.1359421e-05 }, { -0.00064341098, -0.0011265496, -0.0011634792, -0.00081607159 }, { 0.00089294825, 0.0061923653, 0.0052662392, -0.00058227469 }, { -2.4001308e-05, -1.3534224e-05, -1.4720478e-05, -2.5120827e-05 }, { 0.00029964918, -0.0045658543, -0.0045581938, 0.0017106208 }, { 7.5790173e-05, -1.8265415e-05, 1.5918205e-05, 5.8524021e-05 }, { 0.0011669872, -0.00017571882, -0.00017190275, -0.0023833977 }, { 0.0033487264, -0.0066535821, -0.0066413786, -0.0032332601 }, { -3.6468807e-05, -0.00068145131, -9.8190714e-05, -8.7169435e-05 } }, { { -0.0010440653, -8.9750644e-05, 4.971182e-05, 0.0044618878 }, { 0.0078333883, -0.00090884312, -0.00046920549, -0.002465051 }, { -0.0058778609, 0.0026554895, -0.00031880506, -0.00010649091 }, { -0.0015095448, 0.0094026506, 0.009492703, 0.0024572848 }, { 0.0047331786, 0.00070722401, 0.0028798817, -0.00039779892 }, { -0.0089878107, -0.0095474878, -0.0097187652, 0.008765907 }, { -4.0435321e-05, -0.00061813281, -0.0060490143, 0.0016259965 }, { -0.00014720558, -1.0601876e-05, 0.00014757138, 0.00016227641 }, { -0.010428289, -0.00031812813, -0.0016172213, -0.00012022134 }, { 0.0040517131, 0.0072972763, 0.0060433905, 0.0025041645 }, { 0.00014090924, 0.00027612853, 0.00015961665, 0.0002605418 }, { -0.00020653783, -0.00048482867, -0.00058472338, 0.00026413759 }, { 0.00056712638, 0.00026385353, 0.00035484947, 0.00033212447 }, { -0.00094663094, 0.0029891757, 0.0029887838, -0.0026583585 }, { -0.0017400246, 0.00042350567, 0.00086128207, 0.00039863587 }, { 0.00059604848, 0.00027495434, -0.00059956434, -4.4981673e-05 }, { -0.010211343, -0.0080580409, -0.0085333216, 0.0023258717 }, { 0.00042832593, 0.0056750222, 0.0048059635, -0.0092168281 }, { 3.0214612e-05, 4.540924e-06, 1.7239937e-05, 2.783598e-05 }, { 0.00029393335, -4.5128636e-05, -4.3089017e-05, 0.00030682556 }, { -4.7077735e-05, -1.3596835e-05, -0.0015338149, -7.4957991e-05 }, { -0.00097136844, 0.00018564298, 0.00021815754, 0.0015095577 }, { 0.00043929849, -0.0014691094, -0.0014671742, -0.00029365954 }, { 8.8554045e-05, 0.0062500772, 0.0001495049, 0.00021007601 } }, { { 0.0020307077, 0.0020947445, 0.0017438295, 0.0084822342 }, { -0.0069727503, -0.0010131005, 0.0055261321, -0.0020442588 }, { 0.00031035611, 0.00010839441, 3.7359209e-06, 4.3112837e-05 }, { 9.1207794e-05, 0.0050148169, 0.0051071455, 0.0033679057 }, { -0.00090101737, -0.00053793176, -0.0025829621, 0.0003241927 }, { -0.0019244714, -0.0033690472, -0.0035193497, 0.0027653636 }, { -0.00065476293, -0.00017787403, 0.00040383136, -0.00018123957 }, { -0.00030640434, -0.00018961553, -0.00011036218, -0.00015793049 }, { 0.001110592, -0.00021252645, 0.00015849587, -3.7758317e-05 }, { 0.00077967828, -0.0051765235, -0.0078505592, -0.010796339 }, { -1.2024951e-05, 6.48806e-05, -3.9409005e-05, 7.4639306e-05 }, { -0.00017352424, -0.00037802595, -0.00045639468, 0.00016843169 }, { -4.2866244e-05, -4.3730932e-06, 7.3574276e-05, 5.6076779e-05 }, { 0.00024802387, 0.0018053101, 0.0018042994, -0.0016700716 }, { 0.0082698262, -0.00014605077, 0.0004377682, 8.1585074e-05 }, { -4.494343e-06, 0.00019781519, -0.00058910268, -0.00027360572 }, { 0.0013016934, 0.0021020456, 0.0022718598, -0.0059377824 }, { 0.002185371, -0.0080788056, -0.0071952836, 0.0039688918 }, { 0.00013048617, 0.0001738124, 0.00012978924, 0.00013813358 }, { 0.00032386518, 0.00023046021, 0.00023064714, 0.00033762343 }, { 0.00023643771, 0.00019652953, 0.0013083597, 0.00024739959 }, { -0.0063957036, -0.0055319023, -0.0054742301, -0.0037204932 }, { -0.0005510683, -0.0007715413, -0.00077385934, -0.001009415 }, { 0.00017904616, -0.00096137522, 0.00030252599, -2.2478138e-05 } } }, { { { -0.00038948583, -0.00040817153, -0.00041280315, -0.0010985631 }, { 0.0025695337, 0.00042904308, 0.0054649973, -0.0055079106 }, { 0.00052050672, 2.2618679e-05, 0.00024058975, -0.00012632201 }, { -0.013468886, 0.0079396715, 0.0079402246, 0.026283756 }, { -7.922122e-05, -3.4761763e-06, -0.0041716347, 0.0001478739 }, { 0.023716381, -0.016415262, -0.015296927, -0.021050827 }, { 3.7654391e-05, 0.00012765816, -0.0001337099, 0.00051483398 }, { 0.00015671907, 0.00010686796, 2.1421097e-05, -2.2281569e-05 }, { 3.1779413e-06, 0.00010449913, -0.00018303614, 7.5382489e-05 }, { -0.00020526765, -0.0011333575, -0.0050720108, 0.0051482782 }, { 4.0450357e-05, 1.0808158e-05, -2.3316095e-05, 9.7767333e-06 }, { -0.019107229, 0.010907324, 0.0048969594, 0.017851514 }, { 7.4048796e-05, -7.041835e-06, 8.0226174e-05, 5.1714105e-05 }, { -0.016564627, 0.0023486944, 0.0023601429, 0.016005248 }, { -0.004528284, 3.6291049e-05, 2.4229636e-05, 0.0024853948 }, { 5.6882054e-05, 6.8805135e-05, 0.00013119897, 0.00010339801 }, { 0.00021183341, 0.0008203137, -7.204401e-05, 0.00062599728 }, { -0.00099314707, 0.0030198762, -0.0038989955, 0.00055571214 }, { -7.4247984e-05, -8.3993373e-05, -5.9133252e-05, -7.7411989e-05 }, { 0.0054296732, -0.00057858871, -0.00058417754, -0.005072911 }, { -0.00019259782, -0.00018772532, -4.2959783e-05, -0.0001827295 }, { -0.00029351865, 0.00013736372, 0.00016666048, 0.00020873447 }, { 0.0069341659, 0.0027612928, 0.0027538377, -0.0061770317 }, { 4.2584714e-05, -0.00037063589, -9.0693123e-06, 0.00011845784 } }, { { 0.0028834168, 0.0031807308, 0.0031352582, 0.01064051 }, { 0.0049297987, -4.2149356e-05, -0.0014926841, -0.0002300371 }, { 0.0020396303, -0.00066042794, -6.4359283e-05, 0.00017835163 }, { -0.0025767816, 0.0025148152, 0.0025224779, 0.0043006543 }, { -0.00042084416, -0.00013534305, 0.002453623, -4.0707749e-05 }, { -0.0001803055, -0.0010450606, -0.00084380806, 0.00014843677 }, { -0.0064067107, 0.00011012652, -0.0022552747, -0.00080508294 }, { -0.00017778763, -4.296789e-05, 0.00015343883, 0.00025036711 }, { 0.002825978, -0.00031945362, -0.00031987612, -0.00021117763 }, { 0.00032791249, -0.00049524542, 0.0049368722, -0.0017186408 }, { -0.0001685943, -0.00016766033, -0.0001755097, -0.00017067307 }, { 0.00023939157, -0.00011793706, -6.0620575e-05, -0.0002706595 }, { -2.9718673e-05, 3.5950879e-05, 1.839844e-05, -2.8718148e-05 }, { -0.0017260981, 0.00012145435, 0.0001236679, 0.0018292155 }, { 0.0036086706, 0.0001026898, -2.5518889e-05, -0.00019830236 }, { -0.00031546808, -0.00042107458, -0.00059963868, -0.00061472497 }, { -0.0074719522, 0.0015719596, -0.0033624165, -0.0092664101 }, { -0.0011285776, 0.0018601435, 0.00052060704, -1.5554679e-05 }, { 4.9853171e-05, 7.3650922e-05, 3.4080107e-05, 5.4255445e-05 }, { 0.00015102779, -2.58105e-05, -2.5851018e-05, -4.5185316e-05 }, { 0.0002057452, 0.00019037765, 0.0040052198, 0.00020046579 }, { 0.0027727314, 0.0040749211, 0.0036050794, 0.0034635222 }, { 0.00042503689, 0.00056027382, 0.00056052971, -8.2485044e-05 }, { -5.6309634e-05, 0.0019722025, 6.4267434e-05, -0.00020376412 } }, { { 0.0051607661, 0.0047835358, 0.0047658352, 0.0054281814 }, { -0.0040939561, 0.0012119183, -0.0023408179, -0.00055891234 }, { -0.0031939804, -0.0015954053, -0.00018570689, 0.00028849431 }, { -0.0075625096, 0.0033878734, 0.0033797415, 0.010242674 }, { -0.002293562, 0.00024245282, 0.0019455622, 0.0039550747 }, { 0.0090386754, -0.0086947671, -0.0082684939, -0.0075613346 }, { -0.00085735117, 3.4822634e-05, -0.0024653972, -0.00090964985 }, { -0.00013750587, -0.00010089501, 6.3555498e-05, 0.0002758494 }, { 0.0060496328, -0.00032664426, 0.0005979723, -0.00018819024 }, { 0.00072724184, 0.00082242885, 0.0045668772, -0.0054557456 }, { -9.6167811e-05, 7.9856612e-05, 0.00015672473, 8.0901183e-05 }, { 0.00038859448, -0.00025360755, -0.00017624981, -0.00049125519 }, { -8.8277361e-05, 2.4159527e-05, -0.00016014627, -2.7854246e-05 }, { -0.0037308647, 0.00041434141, 0.0004167221, 0.0037190244 }, { 0.00050696744, -4.6752715e-05, 0.00033183668, -0.0025882828 }, { -0.00015915702, -0.0002325901, -0.00036157415, -0.00016391937 }, { 0.00012320153, 0.0026711886, 0.0018414591, -0.0058215223 }, { -0.0029409983, -0.00015460743, 0.0031951665, 0.0074654329 }, { 9.9084813e-05, 9.1785865e-05, 5.9300007e-05, 0.00010463304 }, { 0.00024773341, -2.5723276e-05, -2.5709769e-05, -0.00015357475 }, { 0.000416633, 0.00028749584, -0.0038632071, 0.00039869488 }, { 0.00018344152, 3.0811778e-05, -0.00010240082, 0.00059301197 }, { 0.0019217461, 0.00034404024, 0.00034318823, -0.0015867375 }, { -0.00011928879, 0.001178769, -5.8655983e-05, -0.00028461439 } } }, { { { 0.99999992, 0.99999992, 0.99999991, 0.99999925 }, { 0.99998864, 0.99999972, 0.99993965, 0.99997027 }, { 0.99999969, 1, 0.99999997, 0.99999998 }, { 0.99990852, 0.99971841, 0.99970961, 0.9996348 }, { 0.99999999, 1, 0.99997626, 0.99999999 }, { 0.99951219, 0.9997196, 0.99973058, 0.99951587 }, { 0.99999997, 0.99999999, 0.99999988, 0.99999986 }, { 0.99999998, 0.99999999, 1, 1 }, { 0.9999998, 0.99999999, 0.99999995, 1 }, { 0.99999988, 0.99999525, 0.99997473, 0.99995457 }, { 1, 1, 1, 1 }, { 0.99975729, 0.99976356, 0.99983365, 0.99982963 }, { 0.99999998, 0.99999999, 0.99999998, 0.99999998 }, { 0.99986279, 0.99986979, 0.99986978, 0.99984147 }, { 0.99997099, 1, 0.99999998, 0.99999688 }, { 0.99999999, 0.99999999, 0.99999998, 0.99999999 }, { 0.99999977, 0.99999903, 0.99999932, 0.99999947 }, { 0.99999911, 0.99997627, 0.99997853, 0.99999968 }, { 1, 1, 1, 1 }, { 0.99998521, 0.99998941, 0.99998944, 0.99998567 }, { 0.99999998, 0.99999998, 1, 0.99999998 }, { 0.99999928, 0.99999998, 0.99999997, 0.99999714 }, { 0.99997035, 0.99997405, 0.99997415, 0.99997569 }, { 1, 0.9999997, 1, 0.99999999 } }, { { 0.00015966941, 0.00014262676, 0.00020165066, 0.00021618914 }, { 2.8140907e-06, -0.00020325872, 0.00017736728, 6.0386679e-05 }, { -0.0003187876, 5.8862288e-05, 6.2281085e-05, 1.7339908e-05 }, { -2.6587911e-05, -0.00011609007, -0.00011725093, -7.6114852e-05 }, { 0.00013665042, 5.2703844e-06, -0.00031293536, 3.8693931e-05 }, { -9.8143069e-05, -0.00012816332, -0.00012926252, -0.00010623032 }, { 0.00032342312, -1.9200091e-06, -0.00010691485, 6.3541059e-05 }, { -8.0643542e-06, 9.7622933e-06, 2.9924822e-05, -1.988333e-05 }, { 0.00025318464, 1.2588649e-05, 1.4665927e-05, 9.3294806e-06 }, { 2.6875391e-06, -2.4928123e-05, 2.251878e-05, 0.00011026808 }, { 1.767638e-05, 1.0309044e-05, 2.4765648e-05, 1.4397941e-05 }, { 6.9000935e-06, 1.0637078e-05, 1.087637e-05, 6.3065784e-06 }, { 5.532953e-05, 1.6231463e-05, 4.9564371e-05, 3.6623041e-05 }, { -1.6958729e-05, -3.1627491e-05, -3.1524511e-05, -2.9954116e-05 }, { 8.9045086e-05, 2.1005026e-05, 1.3016463e-05, 8.7863053e-05 }, { -2.75035e-05, -3.0440427e-05, -3.5356286e-05, 5.9609261e-06 }, { 0.0001586274, 4.0711165e-05, 3.1563135e-05, 0.0001385483 }, { 8.5548316e-06, 7.4531928e-05, -3.7017413e-05, 2.6874037e-05 }, { -1.3750655e-05, -8.2756032e-06, -2.7214983e-07, -1.4830115e-05 }, { -7.0798362e-07, -3.3187173e-07, -3.3266762e-07, -5.7113855e-07 }, { 4.3615512e-05, -4.4076433e-06, 8.9239586e-06, 3.7278531e-05 }, { -7.7366773e-06, 4.610399e-06, 4.3762687e-06, -5.64067e-06 }, { -3.2666125e-06, -1.0773146e-05, -1.0861965e-05, -1.3327232e-06 }, { -9.1178305e-06, 0.00030171207, -1.5395234e-05, -2.0695425e-07 } }, { { 0.00017159464, 0.00014699558, 0.00018752678, 0.0002227926 }, { -4.6524822e-05, -0.00010460271, 0.00034735325, 0.00010082238 }, { -6.8269006e-05, 1.4343751e-05, 7.7283393e-06, 2.5347136e-05 }, { -6.6149546e-05, -7.1168993e-05, -7.0621016e-05, -0.00015246746 }, { 7.12022e-05, 3.8790461e-05, -0.00023994449, 6.6792921e-05 }, { -0.00014735813, -0.00012658353, -0.00012162488, -0.00012106777 }, { 0.00015161388, -1.4439153e-05, -3.7629923e-06, 8.3140788e-06 }, { 4.0175416e-05, 2.5380268e-05, -2.2894421e-06, 4.6374378e-06 }, { 0.00028906023, 1.7695243e-05, 5.3790587e-06, 1.631859e-05 }, { 1.8890685e-05, -1.6898275e-05, 2.1007663e-05, 6.5179363e-05 }, { -3.9142595e-06, 2.5745488e-05, 1.0803197e-05, 2.7099749e-05 }, { 9.4245546e-06, 1.0010075e-05, 9.058324e-06, 9.8703427e-06 }, { -2.3441863e-06, 2.5490323e-05, -1.0097654e-05, 4.0554798e-05 }, { -4.1443921e-05, -1.996316e-05, -2.0000841e-05, -4.7495655e-05 }, { 0.00012591695, 5.6179903e-05, -1.8415869e-05, -3.8697972e-05 }, { 2.6719505e-05, 2.4195362e-06, 2.4287424e-05, 3.4703059e-05 }, { 7.3804931e-05, 4.9784871e-05, 3.1159931e-06, 0.00015857197 }, { -0.00010634331, -1.6427658e-05, -7.4874306e-05, -6.2620255e-05 }, { -4.2561214e-06, -1.6123179e-05, -1.5507273e-05, -1.2909924e-05 }, { -1.2210463e-06, 1.1546399e-06, 1.1413892e-06, -1.3465856e-06 }, { 3.4909884e-05, -1.2677793e-05, 0.00011543701, 2.413091e-05 }, { -2.1953323e-05, -4.6244252e-06, -3.5624435e-06, 4.2293671e-06 }, { -1.1392936e-05, -4.3970369e-06, -4.4264864e-06, -1.208518e-05 }, { -4.4002617e-05, 0.00020912348, -3.9617824e-05, -4.1725112e-05 } } }, { { { -0.32504349, -0.32502096, -0.32501094, -0.32423576 }, { -0.65602876, -0.65622598, -0.65567173, -0.65525128 }, { -1.4666488, -1.4666488, -1.4666488, -1.4666488 }, { 0.87168363, 0.87181364, 0.87181792, 0.8718169 }, { -1.264365, -1.264365, -1.264365, -1.264365 }, { 0.89917968, 0.89916889, 0.89916525, 0.89927374 }, { -1.2245906, -1.2245906, -1.2245906, -1.2245906 }, { -0.8885678, -0.88856217, -0.88856327, -0.88855044 }, { -0.31799095, -0.31916566, -0.31907669, -0.31918911 }, { -0.08987958, -0.090342401, -0.090004674, -0.090222398 }, { -0.59425693, -0.59433999, -0.59429118, -0.59433553 }, { 1.1317575, 1.1317475, 1.1317412, 1.1317494 }, { -1.2193493, -1.2193493, -1.2193493, -1.2193493 }, { 1.2506981, 1.250675, 1.250675, 1.2506569 }, { -1.08782, -1.0877793, -1.0878022, -1.0878025 }, { -0.13925598, -0.13932948, -0.13919658, -0.13913403 }, { -0.40394684, -0.4042314, -0.40436178, -0.40402218 }, { -0.47762966, -0.47745572, -0.47767784, -0.47713093 }, { -0.60177181, -0.60176862, -0.60177347, -0.60177079 }, { 2.7311956, 2.7311911, 2.7311911, 2.731191 }, { -1.3109856, -1.3109856, -1.3109856, -1.3109856 }, { 0.60942644, 0.60941369, 0.6094123, 0.60944198 }, { 0.55675448, 0.55672275, 0.55672303, 0.5567542 }, { -0.40637059, -0.4057945, -0.40635768, -0.40636681 } }, { { -0.0016154222, -0.0015930079, -0.0015828998, -0.00087447165 }, { -0.0011262472, -0.001324462, -0.00094895016, -0.00062188189 }, { 0, 0, 0, 0 }, { 9.7616744e-05, 0.00010718899, 0.00010718606, 0.00012665246 }, { 0, 0, 0, 0 }, { 0.00013476236, 6.982272e-05, 6.8208505e-05, 0.00014604742 }, { 0, 0, 0, 0 }, { -0.0031089951, -0.0031071196, -0.0031207245, -0.0031097054 }, { -0.0027808116, -0.0035049857, -0.0034100135, -0.0035192661 }, { -0.0018291474, -0.0019603285, -0.0018919656, -0.0019656229 }, { -0.0034301741, -0.0034912573, -0.0034474395, -0.0034893985 }, { -6.156701e-06, -9.8568527e-06, -1.2383692e-05, -9.9984205e-06 }, { 0, 0, 0, 0 }, { 0.00011838153, 0.00011008679, 0.00011008878, 0.00010536608 }, { -0.0006246638, -0.00058479459, -0.00061327452, -0.00061085433 }, { -0.0059197749, -0.0059778169, -0.0059586015, -0.0058798299 }, { -0.0013246996, -0.0016061786, -0.0016081246, -0.0014374546 }, { -0.001593227, -0.0014706843, -0.0015974008, -0.001341579 }, { -0.0027930604, -0.0027920013, -0.0027939865, -0.0027928528 }, { -1.8908723e-06, -4.266382e-06, -4.2210172e-06, -5.0155215e-06 }, { 0, 0, 0, 0 }, { 0.00018508026, 0.00019774537, 0.00019744661, 0.00019538593 }, { 2.3243747e-05, 1.7291398e-05, 1.7309712e-05, 2.9261396e-05 }, { -0.0041402471, -0.0037085946, -0.0041294876, -0.0041316136 } }, { { -0.0018899732, -0.0018719182, -0.0018661076, -0.0012234594 }, { -0.0012968123, -0.0012971446, -0.00093522854, -0.00066475268 }, { 0, 0, 0, 0 }, { 9.1054464e-05, 0.00014124217, 0.00014156806, 0.00012014953 }, { 0, 0, 0, 0 }, { 0.00017026995, 0.00010528413, 0.00010537941, 0.00015698848 }, { 0, 0, 0, 0 }, { -0.0025812972, -0.0025835894, -0.0025789321, -0.002554949 }, { -0.0035568863, -0.0042988014, -0.0042155548, -0.004312546 }, { -0.0024184575, -0.0025111277, -0.0024654994, -0.0023980076 }, { -0.0036993386, -0.0037113013, -0.0036987284, -0.0037094875 }, { -5.074861e-06, -1.1367399e-05, -1.4819989e-05, -9.2705899e-06 }, { 0, 0, 0, 0 }, { 0.00012570403, 0.00012150272, 0.00012149179, 0.00010579599 }, { -0.00062162762, -0.00058131015, -0.00060837583, -0.00060795256 }, { -0.00775735, -0.0077198081, -0.0078365948, -0.0077749317 }, { -0.0015325554, -0.0017125784, -0.001703195, -0.0015662859 }, { -0.0018130784, -0.00177106, -0.001858095, -0.0015845058 }, { -0.003668417, -0.0036659688, -0.0036693421, -0.0036680526 }, { -9.5804016e-06, -9.6276607e-06, -9.630607e-06, -1.2159056e-05 }, { 0, 0, 0, 0 }, { 0.00017930618, 0.00020084683, 0.00020150104, 0.00020810787 }, { 2.3869269e-05, 1.1024793e-05, 1.1041937e-05, 1.6467357e-05 }, { -0.004690782, -0.0044656761, -0.0046782065, -0.0046921455 } } }, { { { 0.23047932, 0.23043226, 0.23041471, 0.22922185 }, { 0.14990977, 0.15703656, 0.15110771, 0.15149153 }, { 0.30629171, 0.30426701, 0.30400037, 0.30403889 }, { 0.03476576, 0.036188528, 0.036216719, 0.037322097 }, { 0.31066251, 0.31090363, 0.31041565, 0.31057779 }, { 0.04875259, 0.046468595, 0.046486323, 0.046584523 }, { 0.31745458, 0.31874472, 0.32086369, 0.31880207 }, { 0.64054942, 0.64062862, 0.64051973, 0.64059059 }, { 0.27309038, 0.27480819, 0.27477284, 0.27486762 }, { 0.196647, 0.19687982, 0.19607604, 0.1957915 }, { 0.32867362, 0.32858008, 0.32856702, 0.328555 }, { -0.0026873031, -0.0042393446, -0.0057894907, -0.0041858859 }, { 0.40254624, 0.4024247, 0.4025598, 0.40243731 }, { 0.019362807, 0.018146218, 0.018146051, 0.019656613 }, { 0.29328089, 0.29403937, 0.29435036, 0.29403094 }, { 0.57111506, 0.57118505, 0.57099608, 0.57099266 }, { 0.16966612, 0.16993739, 0.17069399, 0.16991136 }, { 0.14989055, 0.1489484, 0.14995985, 0.15015916 }, { 0.33606014, 0.33606294, 0.33606393, 0.33605429 }, { 0.015421206, 0.015180692, 0.01518037, 0.015431139 }, { 0.33165237, 0.33185282, 0.33162592, 0.33166981 }, { 0.078137018, 0.078153855, 0.078165152, 0.078332343 }, { 0.002896946, 0.0026038621, 0.0026029604, 0.0022081151 }, { 0.41064398, 0.40987685, 0.41065341, 0.41059166 } }, { { -0.0024316111, -0.0024732789, -0.0024922144, -0.0035874346 }, { 0.0013306961, 0.004171802, 0.0027660627, 0.0023671465 }, { 0.0034411091, 0.0020878413, 0.0020874456, 0.0022028237 }, { -0.0032873976, -0.0021351911, -0.0021071363, -0.0028424534 }, { 0.0017995208, 0.0022319618, 0.0039270256, 0.0021249365 }, { -0.0019590835, -0.0012526895, -0.0012347747, -0.0021069943 }, { 0.0012319531, 0.002255621, 0.0030193583, 0.0020970822 }, { 0.0015144077, 0.0015110104, 0.0014803089, 0.0015340007 }, { -0.0036679996, -0.0028160114, -0.0028586497, -0.0027953731 }, { -0.005445786, -0.0052624873, -0.0054843188, -0.0053271749 }, { 0.00067154572, 0.0007530775, 0.00067974516, 0.00074462315 }, { -0.0035626119, -0.0034186877, -0.0038720517, -0.0040088745 }, { 0.003455851, 0.0035040061, 0.0034671486, 0.0035069881 }, { -0.0047789747, -0.0047994804, -0.0047996451, -0.0044008337 }, { 0.0032403482, 0.0033627856, 0.003429619, 0.0031153117 }, { -0.005027022, -0.0049812, -0.0049604573, -0.0050556194 }, { -0.0020728991, -0.0014784158, -0.001216894, -0.0019213729 }, { -0.00013808007, -0.00067270623, -0.00024001574, -0.00030691077 }, { 0.0004367104, 0.00043390709, 0.00043548166, 0.00043425516 }, { -0.00082746467, -0.00088151411, -0.00088152334, -0.0008043643 }, { 0.0030277712, 0.003133577, 0.0028529862, 0.0030362271 }, { -0.0058721937, -0.0059816331, -0.0059799345, -0.0058882832 }, { -0.0057032562, -0.0057401855, -0.0057416619, -0.0062417688 }, { -0.0014357888, -0.0020782049, -0.0014346823, -0.0014513767 } }, { { -0.0027051235, -0.0027087245, -0.0027052303, -0.0033594951 }, { 0.0028036195, 0.0030416572, 0.0014306948, 0.0017897371 }, { 0.0031113166, 0.0026432303, 0.0025937824, 0.0025394463 }, { -0.0036032904, -0.003447065, -0.0034344406, -0.0024163572 }, { 0.0023912799, 0.0025281229, 0.0038665087, 0.0024214034 }, { -0.0023543827, -0.0024294943, -0.0024539784, -0.0027742617 }, { 0.0020903896, 0.0026617586, 0.003395249, 0.0026261065 }, { 0.0019031008, 0.0019405475, 0.0019426085, 0.0019404325 }, { -0.0040413326, -0.0030964835, -0.0031020735, -0.0030826754 }, { -0.0064568993, -0.0062342438, -0.0064704698, -0.0065636744 }, { 0.0010788406, 0.0010092051, 0.0010264121, 0.00099891228 }, { -0.0040759201, -0.0059224283, -0.0066809927, -0.0049099348 }, { 0.0042962009, 0.0041909175, 0.0043195236, 0.0041900138 }, { -0.0062728983, -0.0070256154, -0.007025641, -0.0061758746 }, { 0.0036210401, 0.0039723998, 0.0042232048, 0.0042757707 }, { -0.0058693852, -0.0058583303, -0.0058544016, -0.005887725 }, { -0.0023099876, -0.0021136245, -0.0017298078, -0.0022483337 }, { -0.00017851962, -0.00014956209, 8.5676316e-05, -0.00024971669 }, { 0.0003734781, 0.00037078986, 0.00037364181, 0.00037070594 }, { -0.00030648905, -0.00038230535, -0.00038223043, -0.00028623253 }, { 0.0032871423, 0.0034163052, 0.0028276655, 0.0032991918 }, { -0.0061331695, -0.0063319797, -0.0063340119, -0.0064390374 }, { -0.0062172888, -0.0059787106, -0.0059793294, -0.0060406701 }, { -0.0018276142, -0.0022170788, -0.0018293949, -0.0018222824 } } } }, { { { { 0.13218089, -0.11654637, -0.11622196, -0.044208736 }, { 0.0074579257, 0.0038503609, 0.0013201096, 4.0415784e-05 }, { -0.025474487, -0.01209255, -0.016535858, 0.012704547 }, { -0.0016894103, -0.0081312144, -0.0033264609, 0.0011923269 }, { -0.068044876, 0.018276873, -0.074833897, 0.01308348 }, { 0.02665691, 0.013515118, 0.026440814, -0.0077037816 }, { 0.0023286096, -0.0025782652, 0.0021644694, -0.0042955294 }, { 0.051356261, -0.031058382, -0.085382962, -0.033103269 }, { -0.081609229, 0.0035270199, -0.015722417, 0.048773789 }, { 0.0023928418, -0.001243811, 0.011910492, -0.011621478 }, { -0.028953904, -0.029335777, -0.0057891432, 0.013874136 }, { -0.012473582, 0.001772629, -0.013983442, 0.014846792 }, { -0.016111661, 0.0018902323, 0.025910586, 0.042848276 }, { 0.026200626, 0.024007879, 0.0017667146, -0.016394032 }, { -0.0067006429, -0.0017968936, 0.009028659, 0.0044060413 }, { 0.019280611, 0.0449581, -0.042852227, -0.066012332 }, { -0.014451123, -0.047772741, -0.047475406, 0.098434178 }, { -0.0028954635, 0.010521833, -0.015741597, -0.00091666191 }, { 0.0020291956, -0.057966746, -0.04525094, 0.032711614 }, { 0.020563445, -0.0078684621, -0.015282237, -0.0019830466 }, { -0.019504171, 0.071338511, 0.0033729474, -0.0095772339 }, { 0.013056103, 0.018719519, 0.0096002937, -0.028774366 }, { -0.00038728577, -0.0010662982, -0.0014333502, 0.00059135695 }, { 0.073844752, -0.05666013, -0.1007151, -0.030440738 } }, { { 0.00017766639, -9.2398532e-05, -3.9442682e-05, -3.9559848e-05 }, { -0.0043956477, 0.00044042277, -0.00047491077, 9.4171117e-05 }, { -0.0042095545, -0.00910753, -0.0014295282, 0.0042595844 }, { 0.00070989004, -0.0009623012, 0.00084162653, -0.00015925965 }, { -0.0017587638, 0.0033199811, -0.00025544613, 0.00083644978 }, { 0.0051797987, 0.0015691893, -0.002324397, 0.0050776381 }, { 0.003911779, 0.00072639703, 2.102924e-05, -0.0029529332 }, { 0.0050240476, -0.00041452319, 3.1730448e-06, -0.0072697591 }, { -1.5023048e-05, 0.00032491246, -9.2151952e-05, 0.0035851726 }, { 0.0030984373, 0.0016428856, 0.0032974124, -0.0036034289 }, { -0.00044578206, -0.0035916409, 0.0028146658, 0.0068013321 }, { 0.00025716711, -0.0024772152, 0.0029660992, -0.0008783244 }, { -0.005543602, -0.00046453249, 0.006815884, 0.0069207512 }, { -0.0033541738, -0.0015140333, -0.004071746, -0.0020908789 }, { 0.0027932918, -0.0012517158, -0.0033509184, -0.001271572 }, { 0.0043481525, -0.00088858735, -0.0081538059, 0.00027985077 }, { 7.4017523e-05, -7.0080388e-05, -7.1766386e-05, 0.00020468758 }, { 0.00044507396, 0.010179106, -0.0048087449, 0.0013487105 }, { 0.00082148695, -0.00042640153, -0.0024255173, 0.0044486011 }, { -0.00026383509, -0.0031871528, -0.008203704, -0.00053957093 }, { -0.0002996462, 0.00070789605, 7.9300612e-05, -0.00024002209 }, { 0.0013722116, 0.0049176054, 0.0029283062, -0.000849108 }, { 0.00026545039, 0.0011783443, 0.00072103548, -0.0007355776 }, { 0.002192273, -0.00294318, 1.5452606e-05, -0.0020953993 } }, { { 2.4074136e-05, -2.4931598e-05, -1.0893587e-05, 1.080951e-05 }, { -0.0061635883, -0.0042963493, -0.00177783, -0.00080292808 }, { 0.0047868795, -0.0050472436, 0.0082439123, -0.0090979713 }, { 0.0017221077, 0.0067285193, 0.0031011872, -0.0019932567 }, { 0.0010926271, -0.0012170693, 0.00012875612, 0.00016441623 }, { -0.0048786273, -0.0041225634, -0.005591426, 0.0043469593 }, { -0.0070664098, -0.0012625813, -0.00022220241, -0.0026120468 }, { -0.0026689917, 0.00030860545, 1.9297947e-05, 0.001274799 }, { 0.0026769559, 0.00016106032, 0.00013829246, -0.0017239107 }, { -0.0042495789, 0.0010270326, -0.00078224804, -0.0019210019 }, { 0.0072385804, 0.0086418476, 0.0061428272, -0.0027142827 }, { 0.0019768127, -0.00057957046, 0.0047464783, -0.004599565 }, { 0.0093618867, -0.0010476542, -0.0038681572, -0.0065219521 }, { -0.0076406673, -0.0036729355, -0.0068804827, 0.0077571478 }, { 0.0012706397, -0.00042567505, -0.002521821, 6.0288127e-05 }, { -0.002041411, 0.000430125, 0.0073620925, 0.0021579456 }, { 0.00012145466, 4.1276616e-05, 4.2449608e-05, 9.8351262e-05 }, { 0.0014376278, -0.007439719, 0.0039006971, 0.00051135138 }, { -7.1665367e-05, 0.00023856335, 0.00015274881, -0.0096946274 }, { -0.00076804256, 0.0040182915, 0.012603411, -0.00059669891 }, { -0.00010641981, -0.00052355992, 0.00057481361, 0.00016456343 }, { -0.0027623375, -0.0036761364, -0.010480297, 0.0066006902 }, { 0.00049081404, 0.00077264749, 0.0021355718, -0.00029188425 }, { 0.00028566818, 0.00097678458, 0.00089022281, -0.00013760767 } } }, { { { -0.0098123577, 0.11017117, 0.11245143, -0.01173447 }, { 0.0036188505, -0.0025878518, -0.00043343726, -0.0038813197 }, { 0.013109746, -0.016775181, -0.0011093308, 0.00083465721 }, { -0.0042515898, -0.0028159364, 0.00027829209, -0.002907578 }, { -0.0081027554, -0.0019330574, 0.061872524, -0.037539524 }, { -0.012923735, 0.021011524, 0.002680406, 0.0034369108 }, { 0.0027819214, 0.0028657905, -0.0034177203, -0.0037322329 }, { -0.0036178174, 0.065792163, 0.13263475, 0.0055427994 }, { 0.027832309, -0.083372016, -0.058757582, 0.016164879 }, { -0.0082343898, 0.011782416, 0.011496052, -0.0027847616 }, { 0.0012516658, -0.014686832, -0.025073035, -0.020700577 }, { 0.0055718234, -0.011543219, -0.012867689, -0.0049474286 }, { 0.028869265, -0.035431559, 0.024976635, -0.01063055 }, { -0.0010657662, 0.014977146, 0.027109, 0.01612865 }, { -0.0021697493, 0.0044220507, 0.0055654161, -0.0032373397 }, { -0.018500666, -0.01979267, -0.0068480612, 0.03908391 }, { 0.063306878, 0.01934691, 0.019254616, -0.099824471 }, { 7.0580666e-05, -0.0015082457, -0.0056893693, 0.00022726294 }, { 0.0077067654, -0.014018834, -0.021406454, -0.0076589993 }, { -0.0013072394, 2.6765854e-05, 0.0028400803, 0.0037431063 }, { -0.025369581, -0.064039908, -0.020594137, -0.086807367 }, { -0.033639351, 0.010434758, 0.00082983507, 0.013145885 }, { 0.00029373395, 7.8193614e-05, 0.00048496415, 0.00062972215 }, { -0.0041597628, 0.024283117, -0.030148407, 0.011456515 } }, { { -1.3484857e-05, -3.7204145e-05, -1.5660577e-05, -2.4497955e-05 }, { -0.0068070249, 0.0041035892, 0.0034647689, 0.0035918321 }, { -0.0053613309, 0.0080593503, 0.0028507084, -0.0023104987 }, { 0.0048581064, 0.0039720065, -0.0019058129, 0.0047295789 }, { -0.00030675956, -0.0007787587, -0.00025201217, 0.00020777843 }, { -0.00026433336, -0.0093672701, -0.0053201627, -0.0059632173 }, { -0.0063062815, 0.0011995204, 0.0001870407, 0.0028197877 }, { -0.00053247524, -0.00066138217, -1.4959372e-05, -0.00036023628 }, { 0.00027591427, 0.00011309835, 2.2453632e-05, -0.00075736359 }, { 0.0015654886, 0.0018114616, -0.0004503446, -8.5866048e-05 }, { 0.003501393, 0.0037179893, 0.008328543, 0.013411108 }, { -0.0035136609, -0.0015054003, 0.0011903964, 0.0022551358 }, { -0.0083723767, 0.0061303554, -0.008056962, 0.0035035183 }, { -0.0023715655, -0.0070468331, -0.010219655, -0.0057856465 }, { -0.0011406634, -0.00021204595, -0.001693195, 0.0011051597 }, { 0.0011643412, 0.00037557194, 0.0048567739, -0.00063996433 }, { -3.1728174e-05, -2.9073903e-06, -3.0243209e-06, 2.579239e-05 }, { 0.00053152589, 0.0029635352, 0.0040743289, -0.00051381046 }, { -0.0017253584, 0.00012081524, 0.00012243664, -0.00063598215 }, { 0.0026711847, -0.0020733972, -0.0027860744, 0.0017065643 }, { 5.7762902e-05, 0.00092043577, -0.0035278882, 0.0007846087 }, { 0.0056127705, -0.0051893669, -0.0027072408, -0.0025630045 }, { -0.00059289151, -0.0004168408, -8.8118696e-05, -0.00073538101 }, { 0.0003388606, -0.00094234652, 3.013109e-05, -0.0010532484 } }, { { -2.9013996e-05, 6.1983083e-05, 2.8401438e-05, -3.4901557e-05 }, { 0.0045230474, -0.0021369843, -0.00422706, -0.0018918027 }, { 0.00017586142, 0.005389053, 0.0071352982, -0.0018278685 }, { -0.0012135723, -0.0035970727, 0.00078957165, -0.0017065397 }, { -0.00067051937, -1.9501585e-05, 4.1968766e-05, -0.0010958091 }, { -0.0015277626, -0.0039952533, -0.00049631478, 0.0018042745 }, { 0.0039376754, -0.00097834328, 6.5894634e-06, -0.0044189106 }, { -0.00067623039, 0.0004690807, 1.4532105e-07, 0.0032984829 }, { 0.0020787449, -0.0016586579, -0.00062367064, 0.0021545362 }, { 0.0016427801, 2.6710288e-05, 0.0016011535, -0.00077649869 }, { 0.0039999622, -0.0014968097, -0.0025647576, 0.0022783424 }, { 0.001558454, -0.00083803058, 0.0018955692, 0.0010432376 }, { 0.010555722, -0.010395022, 0.0050354965, -0.0016177699 }, { 0.00011370745, -0.009328355, -0.0063009522, 0.0024377458 }, { -0.00024433189, 0.00052920244, -0.0013213352, -0.0013503982 }, { -0.0057620093, 0.00095391746, -0.0034768563, 0.00093990705 }, { 0.00012108024, 4.1007202e-05, 4.2193381e-05, -0.00011043617 }, { 0.0038593696, -0.00074282979, -0.0093457897, 0.00027311164 }, { 0.0021514797, -7.8742315e-05, -0.0018813077, -0.0017625098 }, { 0.0038491118, 0.00022570776, -0.0061331041, 0.00014956617 }, { -0.00014676603, -0.00025053931, 0.003376287, -0.00014730695 }, { 0.0016439646, 0.0060569792, 0.00063058918, -0.0034810156 }, { 0.00011722835, 0.00032237223, -0.0012556553, -0.0006887808 }, { 0.00060814722, 0.0003708376, -0.00056515636, -0.00016801817 } } }, { { { 0.99117704, 0.98705585, 0.98683693, 0.9989534 }, { 0.99996564, 0.99998924, 0.99999903, 0.99999247 }, { 0.99958951, 0.99978616, 0.99986266, 0.99991895 }, { 0.99998953, 0.99996298, 0.99999443, 0.99999506 }, { 0.99764936, 0.9998311, 0.99527468, 0.99920949 }, { 0.9995611, 0.99968788, 0.99964679, 0.99996442 }, { 0.99999342, 0.99999257, 0.99999182, 0.99998381 }, { 0.99867384, 0.99734987, 0.98748052, 0.99943657 }, { 0.99627571, 0.99651225, 0.99814846, 0.99867903 }, { 0.99996323, 0.99992981, 0.99986298, 0.99992859 }, { 0.99957996, 0.99946171, 0.99966886, 0.99968945 }, { 0.99990668, 0.9999318, 0.99981943, 0.99987754 }, { 0.99945334, 0.99937032, 0.99935219, 0.99902503 }, { 0.99965614, 0.99959957, 0.99963092, 0.99973552 }, { 0.9999752, 0.99998861, 0.99994375, 0.99998505 }, { 0.99964293, 0.99879278, 0.99905795, 0.99705307 }, { 0.99788947, 0.99867085, 0.99868681, 0.99012413 }, { 0.99999581, 0.99994351, 0.99985991, 0.99999955 }, { 0.99996824, 0.99822008, 0.99874627, 0.99943549 }, { 0.9997877, 0.99996904, 0.99987919, 0.99999103 }, { 0.99948785, 0.99539425, 0.99978223, 0.99617908 }, { 0.99934875, 0.99977032, 0.99995357, 0.99949949 }, { 0.99999988, 0.99999943, 0.99999886, 0.99999963 }, { 0.99726107, 0.99809817, 0.99445842, 0.99947091 } }, { { -2.3481737e-05, -6.7307406e-06, -2.8605869e-06, -2.0372001e-06 }, { 6.6885689e-05, 4.5630281e-06, 3.5788218e-05, 1.0842484e-05 }, { -4.9278613e-05, -2.4660601e-05, 3.1625301e-06, 0.00019708279 }, { 1.2439158e-05, 3.0347865e-05, 8.6153947e-06, 1.0887256e-05 }, { -0.00012454598, -6.513709e-05, -3.5853483e-06, -3.4708286e-06 }, { -0.00013746339, 0.00013516333, 8.4535039e-05, 5.693766e-05 }, { -2.3674091e-05, -3.4690053e-06, 5.3812265e-07, -1.7613197e-05 }, { -0.00025790043, 3.0475251e-05, 2.1174795e-06, -0.00023630753 }, { -8.8624748e-06, 7.9175589e-06, -2.4258477e-07, -0.00017288313 }, { 4.0061469e-05, 0.00069846663, -0.00060299476, -0.00015396968 }, { 5.0667108e-06, 2.306363e-05, 0.00028636884, 3.6246633e-05 }, { 0.00032740524, -0.00037985037, -0.00014841039, -0.00012676016 }, { 8.7000758e-05, 0.00018530207, 1.7669124e-05, -0.00023199594 }, { 9.2332094e-05, 0.00013487652, 0.00034587506, -3.8853378e-05 }, { 6.9809868e-05, -0.00015411544, 0.0013505166, 1.4531796e-06 }, { -6.3782301e-05, 4.8545135e-05, -0.00027083794, 4.5129465e-05 }, { 3.0912438e-06, -3.2982361e-06, -3.3551612e-06, -1.7781589e-05 }, { 9.872609e-06, -2.9944213e-05, -4.5592652e-05, 1.5950681e-05 }, { 1.4767773e-05, -2.2486726e-05, -0.00010613341, -0.00015794394 }, { 2.4386215e-05, -1.1610334e-05, -4.4456294e-05, -5.0215596e-06 }, { -4.2741558e-06, 8.7714242e-06, -6.6343322e-05, 6.7010735e-05 }, { 0.00016489767, -3.3636771e-05, 5.1610504e-05, 5.2803593e-06 }, { 1.1649256e-05, 2.1169993e-05, 1.9755999e-05, 1.3389438e-05 }, { -0.00015815197, -0.00014316145, 2.6536218e-06, -4.6846396e-05 } }, { { -3.5109783e-06, -9.8530632e-06, -4.5020804e-06, 6.9233235e-08 }, { 9.9938991e-06, -2.0914089e-06, 3.5717699e-05, 3.2813664e-06 }, { 0.00012938219, 1.111062e-05, 8.0858608e-05, 0.00018147439 }, { 4.8657525e-06, 8.6580257e-06, 3.6742927e-06, 3.5828406e-06 }, { 6.9905696e-05, 2.0985073e-05, 6.8866215e-06, -4.2552499e-05 }, { 0.00012100208, 9.7821801e-05, 0.00013576456, 6.3686234e-05 }, { 1.954525e-06, -1.0727343e-06, 5.2332444e-07, -5.4034988e-06 }, { 0.00013699813, -2.226833e-05, 1.4994043e-06, 1.7110377e-05 }, { 0.0001678261, -0.00013844113, -3.4281745e-05, 5.3854072e-05 }, { -1.3018868e-05, 0.00022176303, 0.00016983401, 0.00038109805 }, { 0.00019016068, 0.00023448876, 2.643329e-05, 4.6842203e-05 }, { -1.2492528e-05, -0.00059486605, 0.00012427061, 8.1876965e-05 }, { 8.400564e-05, -0.00029859163, -4.884214e-05, 0.0002631806 }, { 0.00019907281, 0.00014046808, 0.00015482448, 4.0461099e-05 }, { -0.00024349239, 0.00081298441, 0.00084294728, 7.9617963e-05 }, { -6.0040835e-05, 3.2352918e-07, 0.00024295599, 0.00011067283 }, { -6.0027092e-06, 1.1975092e-06, 1.2248893e-06, -2.1293392e-05 }, { 1.4478736e-05, 6.8326918e-05, -7.8693614e-06, 9.2888155e-06 }, { -1.6982828e-05, 1.2094341e-05, -3.1693808e-05, 0.00028574477 }, { 3.4480942e-05, 2.6556008e-05, 0.00016193956, -1.8966503e-06 }, { -5.7726961e-06, 2.1091148e-05, 5.8963955e-05, -1.0834372e-05 }, { 0.0001214393, 1.4174882e-05, 0.0001371836, 0.00021757165 }, { 1.0140226e-05, 6.1641031e-06, 1.0590727e-05, 1.0893212e-05 }, { -1.7442656e-05, 4.2353331e-05, 7.4324714e-05, -1.9484775e-06 } } }, { { { 3.7217719, 3.6900797, 3.6899881, 3.6670816 }, { 0.067826319, 0.16468028, 0.083129199, 0.1336756 }, { 0.66338737, 0.23883566, 0.093361469, 0.10095622 }, { 0.27185537, 0.20781392, 0.32216624, 0.29876595 }, { 2.0776462, 2.0006156, 2.0243138, 2.080345 }, { 0.57695783, 0.18015147, -0.11440889, 0.14229144 }, { 0.63833683, 0.41431062, 0.44752994, 0.47594414 }, { 1.7890608, 1.962584, 1.9322155, 1.6588331 }, { 3.0538128, 3.108267, 3.1001573, 2.9593433 }, { -0.28383051, -0.27708376, -0.042513902, -0.085181891 }, { 0.3873435, 0.41697884, 0.39625427, 0.33250735 }, { -0.33498881, -0.40206929, -0.028905862, -0.48179632 }, { 1.1875033, 1.3535177, 1.2526197, 1.3337495 }, { 0.42579488, 0.24951727, 0.18976118, 0.20605317 }, { -0.53212666, -0.3861028, -0.75685995, -0.23411882 }, { 1.6910165, 1.686815, 1.5906473, 1.6528217 }, { 4.0570657, 4.0349492, 4.0350332, 4.0498099 }, { -0.017225465, -0.032503897, 0.46003211, 0.21602109 }, { 1.1196901, 1.00885, 0.91675568, 0.99635794 }, { -0.093891275, 0.0809352, -0.13783332, 0.27130678 }, { 1.9925136, 1.9829394, 1.8820721, 1.9542026 }, { 0.84563763, 0.48476746, 0.37907152, 0.70267878 }, { 0.37054708, 0.4228574, 0.6329822, 0.26197064 }, { 1.9618393, 1.8405969, 1.9440918, 1.901629 } }, { { -5.6047186e-06, 6.0454847e-06, 2.8365975e-06, 6.0894367e-06 }, { -0.00069876506, -0.00029642785, -0.00059516082, -0.00025400441 }, { -0.00020850504, -0.00012959593, -0.00032902532, -0.00058117893 }, { -0.00037901964, -0.00038062016, -0.00023777964, -0.00033714679 }, { -5.9894351e-05, -9.820791e-05, -5.9867157e-06, -6.258549e-06 }, { -0.00035424038, -8.7146215e-05, 3.0398362e-05, -0.00061406521 }, { 0.00014971442, 4.5936211e-05, -5.6259869e-06, 0.00013567035 }, { -0.00016180211, 3.1840487e-06, 3.8979157e-07, -0.00017131994 }, { -1.9877193e-05, 2.5768261e-05, 9.0577543e-06, -0.00013927462 }, { -0.0012323564, -0.00042892846, 7.2082106e-05, 0.00010999853 }, { -0.00034618449, -0.00017058897, -0.00016535057, -0.00096982024 }, { -0.00028039653, -7.155747e-05, -0.00075796707, 0.00062756458 }, { 6.6596276e-05, -7.9730809e-05, -8.0686754e-05, -2.9532397e-05 }, { -0.00084106867, -0.00036762453, 0.00012523548, -0.00052789663 }, { 7.6718268e-05, -0.0010042005, -0.00042802983, -0.0011951304 }, { -3.6972258e-05, 2.1447505e-06, -0.00035448623, -1.0620008e-05 }, { 2.8326169e-05, 2.2049468e-05, 2.2640575e-05, 1.7574827e-05 }, { -0.00014318496, -0.0004811524, -0.00049293303, -0.00067646484 }, { -2.7469144e-05, -5.9653763e-06, -1.3998899e-05, -0.00018475323 }, { -0.00017314302, -0.00010954727, -0.00040004932, 3.31106e-05 }, { -3.6093435e-06, -1.6125243e-05, -4.9195648e-05, 1.5586886e-05 }, { 0.0002059631, -0.0004024722, -0.00047984678, -9.8485329e-05 }, { -0.00094100913, -0.00073046048, -0.00052500163, -0.00068196784 }, { -2.2820197e-05, -5.9454557e-05, -6.2505468e-06, -2.6569804e-05 } }, { { 2.6015883e-05, 8.5398335e-06, 3.8473185e-06, 9.1409625e-06 }, { -0.00041459247, -0.0001855224, -0.00030529542, -0.00016322166 }, { -8.8427847e-05, -0.0002302048, -0.00038072959, -0.00076801295 }, { -0.00027717792, -0.00028594346, -0.00017910208, -0.00027291164 }, { 2.8409311e-05, -3.8005817e-05, -4.2266878e-06, -1.4520383e-05 }, { -0.0001088827, -0.00021924377, 3.9307406e-05, -0.00032488556 }, { 0.00027997916, 3.5103699e-05, -5.7448764e-06, 0.00010259251 }, { -4.7807894e-06, -2.9470863e-05, 2.6656233e-07, -0.00014346393 }, { 0.00015527098, -6.8528726e-05, -1.1206714e-05, 2.3422595e-05 }, { -0.0012763247, -0.00051503472, 0.00058055106, -0.00068688488 }, { -6.1232076e-06, -1.7073841e-05, -0.00033533389, -0.00078769935 }, { -0.00044113485, -0.00027577451, -0.0012008622, 0.00013071136 }, { 1.834948e-05, -0.00015615102, -0.00016449385, 3.6685217e-05 }, { -0.00063618257, -0.00032641968, -5.0281118e-05, -0.00041378992 }, { -0.0010181884, -0.0003871932, -0.00050061147, -0.0018967455 }, { -5.7650067e-05, -5.1145774e-06, -0.00017409773, 1.9512036e-05 }, { 1.5838743e-05, 2.503655e-05, 2.5679098e-05, 2.0053218e-05 }, { -0.00018055811, -0.00044345237, -7.9049557e-05, -0.00095669161 }, { -4.98611e-05, -1.1320605e-06, 3.7756645e-06, -8.7299215e-05 }, { -0.00011794063, -0.00015778552, -0.00036514881, 4.7288704e-05 }, { -5.1753817e-06, -1.5040527e-06, -2.836739e-05, -9.4945229e-06 }, { 0.00016873335, -0.00031983601, -0.00052281245, 0.00019034815 }, { -0.0011988594, -0.0010684975, -0.00057577023, -0.0009143845 }, { 5.0336006e-05, -1.356148e-05, 1.5582694e-05, -2.0666272e-05 } } }, { { { 0.012207721, 0.0044164612, 0.0022704542, 0.0042008503 }, { 0.29516302, 0.139976, 0.35038027, 0.13748343 }, { 0.1462123, 0.12114907, 0.28473665, 0.45762717 }, { 0.17976664, 0.19141553, 0.1209483, 0.16393769 }, { 0.044254492, 0.11383095, 0.0062726904, 0.023550537 }, { 0.14785458, 0.10151341, 0.045717467, 0.42243971 }, { -0.24205201, -0.033590842, 0.0032064617, -0.093924041 }, { 0.10866955, 0.016299431, 0.00081631108, 0.15856447 }, { 0.10108337, 0.057931152, 0.024463589, 0.21514346 }, { 0.47967783, 0.75472932, 0.5653649, 0.64752457 }, { 0.30082544, 0.15124922, 0.23567284, 0.47161499 }, { 0.54286166, 0.61049777, 0.61641378, 0.51181399 }, { 0.39328762, 0.25557559, 0.25875912, 0.22436901 }, { 0.45699569, 0.16989563, 0.2429263, 0.3924359 }, { 0.92996797, 1.1024806, 0.78045387, 1.2298879 }, { 0.19029829, -0.022675055, 0.28113642, 0.034941166 }, { 0.013203939, 0.013034069, 0.013414649, 0.011688038 }, { 0.076026927, 0.13838472, 0.29961655, 0.31531564 }, { 0.089182386, 0.010401684, 0.029374547, 0.22995838 }, { 0.052198894, 0.039866726, 0.11570972, -0.013818992 }, { 0.0062380932, 0.01788119, -0.20765047, 0.013339281 }, { 0.12436441, 0.17318651, 0.21554136, 0.18600144 }, { 0.38005287, 0.32135548, 0.28632777, 0.29211902 }, { 0.03798742, 0.0450845, 0.010912505, 0.039060104 } }, { { 0.00077914246, 0.00011130803, 8.1110229e-05, -0.00035312557 }, { 0.00051711901, 0.00029701387, 0.00040733345, 0.00034149723 }, { 0.00063893978, -0.00013702086, 0.00030866699, -0.00020070677 }, { 7.5899443e-05, 9.7456273e-05, -4.5352178e-05, 7.6172703e-06 }, { 0.00066250814, -0.00073033349, 0.00015225542, -0.0010197351 }, { 0.00040931533, -0.00043022747, 0.00093333285, 0.0002579685 }, { -0.00067488578, -0.0003706974, -0.00044487256, -0.00056555959 }, { 0.00075838366, -0.0021903789, -0.0026744174, -0.00047135202 }, { -0.00081050821, -0.0010297809, -0.00099480849, -0.00074914246 }, { 0.00063637392, 5.248783e-05, 0.00044645091, 0.00018028446 }, { 0.00067430392, 0.0004762628, -0.00032736685, 0.00041933609 }, { 6.2324555e-05, -1.6709531e-06, 0.00057418116, -0.0010360999 }, { -0.00038256183, -0.0010104012, -0.00045533693, -1.3888404e-05 }, { 0.00068274628, 0.00068411875, -0.00091273333, 0.00016211145 }, { -0.00039440715, 0.00027665323, -0.00035895503, 0.00013423207 }, { -0.00061939017, 0.00012140102, 0.00024178233, 0.00064755788 }, { -0.00052441128, -0.00050994483, -0.00051126044, 0.00066320373 }, { 0.00085915332, 0.0013567332, -0.00014328466, 0.00056098523 }, { -0.0012682676, 0.0029139719, 0.0019812291, -0.00053863027 }, { 0.0021895869, 0.00062956835, 0.0018161156, 0.00011699452 }, { -0.0010337306, 0.00016880497, -0.0014942346, -0.0034402453 }, { -0.0025336946, -0.00019468865, -0.00018045349, -5.4312149e-05 }, { 0.00021491979, 4.7651714e-05, -0.00044921151, 0.00046742044 }, { 0.0019408125, 0.00044842687, 0.0026003265, -0.00090116109 } }, { { -0.0006591255, 0.00022873584, 0.00026313866, -0.00060151354 }, { 0.00027198127, 0.00034252944, 0.00033246896, 0.00035232159 }, { -0.00034460639, -5.9085725e-05, 7.836454e-05, -0.00018946388 }, { 0.00018790551, 0.0001918358, 9.7031467e-05, 0.00015259869 }, { -0.0023033429, -0.0012945186, -0.00080964072, -0.00030432514 }, { -0.001359781, 0.00055828912, -0.00041912301, 0.00019263336 }, { -0.00042789448, -0.00018313775, -0.00030217124, -0.00028437496 }, { -0.0018340159, 0.00030654336, -0.00010781402, -0.0011985455 }, { -0.002103478, 0.00029492518, -0.00042283946, -0.001472689 }, { 0.00064558079, 0.00049703204, -0.00018932594, -0.00038268301 }, { -0.00097813334, -0.00057838807, 0.00079268109, 0.00039650774 }, { -0.00017335252, 0.00074363734, 0.0008194423, -0.00065923207 }, { -0.00075344545, -0.00026114262, -0.00054658657, -0.0013814943 }, { -0.00028279346, 0.00055730283, 0.00048990213, -0.00022186466 }, { 0.00013438509, -0.0001962818, -0.00036195953, 0.00042669461 }, { -0.00089003585, -0.0011600794, -0.0012554286, -0.0012892408 }, { -0.00067007058, -0.0010597247, -0.0010590421, 0.00044132516 }, { 0.0011626727, 0.001261033, -0.00072912018, 0.00076332442 }, { -0.001204702, -0.00011230019, 0.00036178615, -0.0017559004 }, { 0.00096282849, 0.001025959, 0.0011696947, 0.00046633555 }, { -0.00082328571, -0.00075771669, -0.0011629302, 0.00073458863 }, { -0.0016869269, -0.00035239862, -0.0004024204, -0.0016276971 }, { 0.00029053123, 0.00013409355, -0.00049087974, 0.00061969429 }, { -0.0013198997, -0.0018615784, -0.0025724061, -0.0015563017 } } } }, { { { { -0.072246889, -0.043157285, 0.043289306, 0.095998047 }, { 0.12597079, 0.24289541, -0.10930005, -0.24150539 }, { 0.031889347, -0.036238337, -0.014521983, -0.018963885 }, { -0.044155351, -0.0077170425, -0.043781059, 0.047982339 }, { 0.093995001, -0.0079510758, -0.04688882, -0.11125523 }, { 0.01700754, -0.0034361033, 0.055252382, -0.053119426 }, { -0.0014957087, -0.00063057103, 0.037930463, 0.017656646 }, { -0.017388477, -0.084085888, -0.067726647, 0.061397079 }, { -0.070625168, -0.061293011, -0.077366932, 0.11518646 }, { -0.14771316, -0.12543895, 0.052150789, 0.10530462 }, { -0.03609139, 0.001131616, -0.039549928, 0.03805765 }, { 0.064364205, 0.066758929, 0.045537002, -0.05510954 }, { 0.049051369, 0.098312455, -0.01079726, -0.11202623 }, { 0.033012208, -0.0013996988, -0.0049458824, -0.028981527 }, { 0.008617177, -0.00017670863, -0.0052380282, -0.0023438457 }, { -0.05901498, -0.050754807, -0.00011829844, 0.037297411 }, { -0.056264446, -0.03645315, -0.066412698, 0.019549244 }, { -0.11401603, -0.11856524, 0.12275022, 0.11635143 }, { -0.0011999881, -0.0016334327, -0.0056868938, 0.013393766 }, { 0.054526972, 0.033632235, 0.062591094, -0.0025531074 }, { 0.073041316, 0.073735243, -0.06935254, -0.11214186 }, { 0.034872822, -0.015473423, 0.037359975, -0.026829465 }, { -0.015137592, -0.0064462553, 0.011771178, 0.0025042048 }, { -0.038708904, -0.033968131, -0.044070885, 0.024422773 } }, { { -0.047895007, -0.016535938, 0.04855533, 0.018341613 }, { 0.004310087, 0.01519838, -0.0033290683, -0.013597406 }, { 0.0015859181, 0.016869623, -0.019279963, -0.01426933 }, { -0.0061048976, 0.031131561, 0.018085381, -0.017927117 }, { 0.052590378, 0.0066156852, -0.0025756141, -0.037241705 }, { 0.0083512619, 0.0046235666, 0.024122126, -0.013443654 }, { 0.0010672274, 0.00053123301, -0.0016276029, -0.04221993 }, { -0.0048754166, -0.021474788, -0.0039993317, 0.011831691 }, { -0.054685347, -0.050242732, -0.007606251, 0.043061893 }, { -7.5644942e-05, 0.00086632318, 0.0001960729, 0.0013264286 }, { 0.0042413724, -0.0057181522, 0.0065940983, -0.0078263328 }, { 0.0031260881, -0.0013520907, 0.025073658, -0.010841673 }, { 0.038353769, 0.06620308, -0.0072105562, -0.079188681 }, { 0.003099559, -0.0022927921, 0.021982683, -0.018991144 }, { 0.012285675, 0.0091834074, -0.0041874571, -0.032253924 }, { -0.014563556, 0.009843969, -0.010490279, 0.012979866 }, { -0.005492286, 0.064109426, -0.034795617, -0.020395732 }, { -0.023364141, -0.059336321, 0.080710391, 0.038948527 }, { 0.0028384819, 0.001822471, 0.0012903958, 0.012781079 }, { -0.004510518, -0.0020008272, 0.0017752876, 0.0077607089 }, { 0.032279653, 0.0041906079, -0.034682371, 0.0061335907 }, { -0.0082992317, -0.025250117, -0.017026845, -0.028345042 }, { -0.013132125, -0.026688493, -0.0014827793, -0.003236826 }, { 0.01650781, 0.002313574, -0.012897922, 0.026077933 } }, { { 0.062668058, 0.0081578851, 0.018952049, -0.012267283 }, { 0.0008567722, 0.0033246009, -0.0037620102, -0.0096317368 }, { -0.0083012273, 0.01184624, -0.01209373, 0.020208536 }, { 0.013862003, 0.019166381, 0.013235471, -0.026788736 }, { -0.021904217, -0.051018749, 0.0020330268, 0.006626371 }, { -0.015856131, 0.0028024655, -0.032825412, -0.018920906 }, { 0.0020870233, 0.0011616727, -0.0032704368, -0.027327141 }, { 0.01934969, 0.002427195, 0.049925128, -0.0061414889 }, { 0.013158375, 0.022248445, 0.040266734, -0.017583455 }, { 1.9024812e-05, 0.00071602053, 0.0012622199, 0.0018791611 }, { -0.0011857767, 0.0023417924, 0.026237548, -0.014687892 }, { -0.041419782, 0.024942194, -0.029143101, 0.036590943 }, { -0.015470651, -0.035208671, -0.038530514, 0.037434376 }, { -0.0029356279, 0.0023358079, 0.017641055, 0.0038203652 }, { -0.0030449623, -0.010187444, 0.0066142145, 0.0037433206 }, { 0.0080034603, 0.011463159, -0.0058129532, 0.011831147 }, { -0.0091743137, 0.045949289, 0.022412137, -0.0067531419 }, { 0.00069946656, -0.0068974782, 0.0091806954, 0.0022160793 }, { -0.0027530077, 0.00089797627, 0.0066153093, -0.010355635 }, { -0.019399018, -0.0085762573, 0.0208003, -0.027739023 }, { -0.014354809, -0.011971089, -0.0031124986, 0.044710091 }, { -0.011411144, 0.0073253411, -0.0087561348, -0.014838738 }, { 0.018837992, 0.00231775, -0.013982978, -0.0020044658 }, { 0.0012069362, 0.0012202952, 0.029106153, 0.00062793994 } } }, { { { 0.054154158, -0.11603661, -0.025631275, 0.054671866 }, { -0.2359715, 0.093194255, 0.21874866, -0.08378526 }, { 0.0089903397, 0.0087113885, -0.015445726, 0.011142042 }, { -0.0055372249, -0.0041494086, -0.033355186, -0.010136823 }, { -0.015010227, -0.0077144008, 0.13058394, -0.016779666 }, { -0.015855009, 0.014090685, 0.026549575, 0.025677527 }, { -0.00065423811, -0.0011506403, 0.028628751, 0.0086359197 }, { -0.010571292, 0.035861454, -0.025871285, -0.024827688 }, { 0.00010603924, 0.011433504, -0.052819957, -0.020208661 }, { 0.12243361, -0.14574398, -0.10091072, 0.054524772 }, { -0.014659734, -0.02291001, 0.010102434, -0.0099333349 }, { -0.0079939087, 0.023468399, 0.044548395, 0.04568814 }, { -0.048188816, 0.016469102, 0.084818672, -0.040634065 }, { 0.015089138, 0.025396216, 0.017000121, 0.010820807 }, { -0.0098155552, -0.00080001495, 0.0020122754, -0.00046896909 }, { -0.0018906417, -0.03909342, -0.020339049, -0.024007559 }, { -0.0012744487, -0.027829333, -0.05202457, -0.024366779 }, { 0.10406956, -0.092281421, -0.050420166, 0.10716663 }, { -0.0049603976, -0.0055370076, -0.0016910106, 0.012172389 }, { -0.0026486448, 0.038673757, -0.0016176887, 0.052692494 }, { -0.03722357, 0.055455783, 0.067738953, -0.0087990582 }, { -0.0026491637, 0.017275247, 0.010687117, 0.020312052 }, { -0.0016032469, 0.0090272843, -0.0079027514, -0.0050039898 }, { -0.0073653412, -0.033150577, 0.0082912493, -0.021457881 } }, { { -0.0059001999, 0.033600833, 0.066374213, -0.018058548 }, { -0.0037864945, -0.0064946131, 0.0018627774, 0.0044899139 }, { 0.0048961861, -0.0034770968, -0.0002311598, -0.0053935761 }, { 0.0090090757, 0.012149811, 0.0029969663, 0.0049403543 }, { -0.042874682, -0.0083455851, -0.0064437344, 0.0010579362 }, { 0.011866873, -0.017157526, -0.014724976, 0.0054373752 }, { -0.0006329516, -0.00024834697, 0.0015416168, -0.014246989 }, { 0.031530357, -0.052715858, -0.0063186617, -0.0070200141 }, { -0.0082273844, 0.053856605, 0.0096812384, 0.01684635 }, { -0.00017150577, 0.00097354737, 0.0013944706, 0.00085166684 }, { -0.013604545, 0.0089329355, -0.013809086, 0.0025044469 }, { -0.020284731, 0.0004724419, -0.045697697, -0.01844702 }, { 0.017874081, -0.0040537465, -0.023316716, -0.026344708 }, { 0.0092557469, -0.014456327, -0.0092919835, 0.0091758924 }, { 0.016058873, 0.0019220807, 0.0031692823, 0.0024577167 }, { -0.021184352, 0.021287579, -0.0048442696, 0.0095799112 }, { 0.035229915, -0.054291919, -0.013871324, 0.035585241 }, { 0.001275203, 0.011513119, 0.020184769, -0.0061701639 }, { 0.011353237, 0.0052697685, 0.0047637419, -0.020278005 }, { 0.0068266296, -0.01173749, 0.037482577, -0.0083236299 }, { 0.025699221, -0.03651135, -0.032342446, -0.0059784486 }, { 0.0029540635, -0.0021598269, 0.0028168477, 0.0044577193 }, { 0.0038274002, -0.0050806333, 0.007628551, 0.0027461742 }, { 0.0056567464, 0.006846664, -0.031161558, -0.0040832656 } }, { { 0.025668431, 0.0093723617, 7.4324163e-05, -0.023051436 }, { -0.010148124, 0.0018159908, 0.0072269566, 0.00082671261 }, { 0.0069741056, 0.023493533, 0.028507618, -0.026874125 }, { 0.0083316277, -0.024891629, 0.013623217, 0.0038373532 }, { -0.020992516, 0.070912136, -0.0014634877, -0.015680371 }, { 0.02178962, -0.003772636, -0.024578501, -0.047467019 }, { 0.0028586275, 0.0033445767, 0.0049576063, -0.017365739 }, { 0.0075721122, 0.010652219, -0.024031886, -0.0001146548 }, { 0.016381176, -0.044765924, -0.038036229, -0.014041395 }, { -0.00082564842, 0.00033107944, 0.00073792054, 0.0005712734 }, { 0.0080934887, 0.014534447, -0.0071347609, 0.0085413493 }, { -0.018211778, 0.0064443848, 0.017393403, 0.011490985 }, { -0.071531366, 0.030059694, 0.049103287, 0.0074609412 }, { 0.00770209, -0.017999995, -0.040048679, -0.0029073853 }, { 0.020442166, 0.0019454488, -0.019644905, 0.021793285 }, { 0.035171271, 0.0080192155, -0.023151504, 0.014168348 }, { -0.048901887, -0.0039613606, 0.0021703807, 0.030275152 }, { 0.044666116, -0.029756153, -0.015570779, 0.034470632 }, { -0.0078700362, 0.0037551741, 0.0003070052, -0.0031237403 }, { 0.015288427, -0.01284757, -0.0075319169, 0.026981487 }, { -0.0093872483, 0.013517073, -0.030221944, 0.058356065 }, { 0.0042326205, -0.016381154, 0.021475001, 0.01008732 }, { 0.0034929117, 0.020531314, -0.0085114063, 0.004821913 }, { 0.014314413, 0.01127037, -0.017197896, 0.0046932185 } } }, { { { 0.99591552, 0.99230689, 0.99873374, 0.99387895 }, { 0.96356049, 0.96556546, 0.96964041, 0.96677566 }, { 0.99945097, 0.99930521, 0.99977525, 0.99975808 }, { 0.99900933, 0.99996161, 0.99848418, 0.99879675 }, { 0.99545951, 0.99993863, 0.99032786, 0.9936502 }, { 0.99972964, 0.99989482, 0.99811938, 0.99825798 }, { 0.99999867, 0.99999914, 0.9988702, 0.99980681 }, { 0.99979292, 0.99581299, 0.99736843, 0.99780458 }, { 0.99750292, 0.99805433, 0.99560254, 0.9931383 }, { 0.98142286, 0.98133774, 0.99352772, 0.9929441 }, { 0.99924096, 0.99973689, 0.99916652, 0.99922617 }, { 0.99789446, 0.9974931, 0.99796885, 0.99743448 }, { 0.9976331, 0.99501931, 0.9963379, 0.99287411 }, { 0.99934104, 0.99967648, 0.99984325, 0.99952138 }, { 0.9999147, 0.99999966, 0.99998426, 0.99999714 }, { 0.99825531, 0.99794572, 0.99979313, 0.99901579 }, { 0.99841509, 0.99894779, 0.99643504, 0.99951192 }, { 0.98801309, 0.98864879, 0.99115599, 0.98740957 }, { 0.99998698, 0.99998334, 0.9999824, 0.99983621 }, { 0.99850879, 0.99868574, 0.99803794, 0.99860752 }, { 0.99663402, 0.99573479, 0.99528974, 0.99365325 }, { 0.99938825, 0.99973103, 0.99924472, 0.99943364 }, { 0.99988413, 0.99993848, 0.99989949, 0.99998434 }, { 0.99922338, 0.99887297, 0.998994, 0.9994714 } }, { { -0.0050599833, 0.003362263, 0.0035202243, -0.00056864904 }, { -0.0014675187, -0.0029154981, -0.00077796172, -0.0027392627 }, { -0.0010916411, 0.00078232803, 0.0014339533, -0.0020166729 }, { 0.011183745, 0.008298699, 0.011631254, 0.00030693508 }, { -0.0012964861, -0.00028098882, 0.00098513135, -0.0052243577 }, { 0.0091119501, 0.002780703, 0.011045274, 0.00334383 }, { 4.1103001e-05, 5.5767744e-05, 0.0030605577, 0.0022152241 }, { 0.00085375099, 0.0026952672, 0.0071937971, 0.0056504112 }, { -0.003773118, 0.0047936307, -4.5743022e-05, -0.0038357994 }, { 2.3815581e-05, 0.0002468657, 0.00013492048, -0.00018410816 }, { 0.0070959632, -0.00205589, 0.0056417297, 0.0030702073 }, { 0.010671769, 0.0074346008, 0.0012867659, 0.0075437523 }, { -0.0013037272, -0.0058374269, 0.0025899757, -0.0071565118 }, { 0.0030041304, 0.0018011397, 0.0093160386, 0.0082062863 }, { 0.0053156934, 0.0036543193, 0.0048724246, 0.0035118324 }, { -0.0053866158, 0.0024053442, 0.00052459148, 0.0090970513 }, { 0.011239324, -0.0010327051, -0.00097551594, 0.0044180668 }, { -0.0024379533, -0.0088232426, -0.012355568, -0.0031875953 }, { 0.0026244123, 0.0011858999, 0.0028110843, -0.001005442 }, { 0.0059514328, 0.0018892606, 0.0050231625, 0.0046700575 }, { 0.00050741664, 0.0096547476, -0.00079618251, 0.0024532112 }, { 0.0058717468, -0.0017457656, 0.0080261577, -0.00048009588 }, { 0.0025457914, 0.0016788968, 0.0013982313, 0.00073909928 }, { 0.0075035778, 0.011234409, 0.0079271096, 0.006672353 } }, { { 0.0095152396, 0.0011785006, -0.00081996856, 0.0018904938 }, { -0.0025430397, -0.0010236291, -0.0020168276, -0.0021827861 }, { 0.0036295778, 0.005406882, 0.0040788276, -0.0057729163 }, { -0.00029952998, 0.0024548208, 0.0088548836, 0.0019084209 }, { 0.0034184324, -0.0088925589, 0.00023040452, 0.00017437939 }, { 0.0037804595, 0.012156355, 0.0041276361, 0.012721488 }, { 7.4846461e-05, 0.00010580108, 0.013483417, 0.0024239851 }, { 0.00026411032, -0.00059353627, 0.0093564271, 0.0061507538 }, { 0.0016065383, -0.0027764641, 0.0013620195, 0.0010062065 }, { 9.7127925e-05, 0.00017275393, 1.0814607e-05, -0.00022627793 }, { 0.0048710612, -0.00014794569, 0.0082832436, -0.00072595412 }, { -0.0027392579, 0.0066783951, 0.00087397132, 0.001567366 }, { -0.003378151, 0.0025916338, -0.0025553201, 0.0030152022 }, { 0.0096818399, 0.0012695523, 0.0072489949, 0.016881099 }, { 0.0022796191, 0.0051693266, 0.0023373397, -0.0041448561 }, { -0.0002074582, 0.0035962454, -0.0007460719, 0.0025086317 }, { 0.0035784996, 0.003162753, 0.0022592918, 0.00024595998 }, { -0.0051294944, -0.0041428868, -0.0027597, -0.0039539398 }, { 0.0022410392, 0.00031263884, 0.0016376751, -0.0022787113 }, { 0.0025647038, 0.0074733037, 0.0051722028, 0.0024463612 }, { 0.0011787227, 0.0071159753, 0.0017217143, 0.0062717989 }, { 0.0046836737, 0.0038976423, 0.00062832002, 0.0027638154 }, { 0.0014142926, 0.0024903802, 0.0015757227, 0.0011628587 }, { 0.0016928585, 0.0043828548, 0.001653268, 0.011450696 } } }, { { { 2.8886078, 2.8900127, 2.7925705, 2.7895874 }, { 4.5455217, 4.5284714, 4.7042338, 4.6915273 }, { 0.96672505, 0.99303664, 0.98927606, 1.0351588 }, { 1.2743756, 1.2525364, 0.99649566, 0.94572778 }, { 2.6910679, 2.6922168, 2.8503404, 2.8246076 }, { 1.256075, 1.2325025, 1.5911826, 1.6091223 }, { 1.3601759, 1.3606869, 1.2793533, 1.240925 }, { 2.0291828, 2.0506809, 1.7341658, 1.6555689 }, { 2.6663531, 2.6921882, 3.1290975, 3.11849 }, { 5.3676887, 5.3663279, 5.3848664, 5.3852162 }, { 1.0586431, 1.0865889, 0.8196623, 0.8076665 }, { 1.6967251, 1.7305944, 1.5450413, 1.6347879 }, { 3.0908857, 3.0706775, 3.2974343, 3.3053965 }, { 1.2172073, 1.3839086, 1.5086796, 1.4295506 }, { 0.97676668, 1.0856738, 0.98747912, 1.0385491 }, { 1.5662275, 1.4603538, 1.784278, 1.6575438 }, { 2.1085757, 2.2092885, 2.1410448, 2.1518347 }, { 4.0214776, 4.006424, 3.7686967, 3.7771354 }, { 1.2089239, 1.2116036, 1.1244311, 1.0901017 }, { 1.1827246, 1.1472796, 1.7516784, 1.7833976 }, { 2.2113439, 2.197512, 2.2692963, 2.2787751 }, { 0.98819531, 1.057833, 1.3587301, 1.3890421 }, { 1.208957, 1.2247867, 1.2301205, 1.2325178 }, { 1.0499613, 1.1319197, 1.4067885, 1.3209087 } }, { { -0.002860931, -0.0033581281, -0.0047612075, -0.0030481839 }, { -0.0017370907, -0.0065700936, -0.0011051926, -0.0046915938 }, { -0.0006126207, 0.0010791181, -0.022876686, -0.015937275 }, { -0.010040922, -0.016433531, -0.0044976975, -0.029838315 }, { 0.00056888968, -0.0093450028, -0.00041549218, -0.0069079656 }, { -0.029781683, -0.019722587, 0.019472312, 0.0016798037 }, { -0.0015128736, -0.0012250172, -0.0091568262, -0.0091368119 }, { 0.0010846814, 0.0017189068, 0.012975603, -0.0051530971 }, { -0.026042808, -0.0090684857, -0.0021498742, -0.0032938309 }, { -0.0012792901, -0.0010431731, -0.0021366737, -0.0025526365 }, { -0.03218779, -0.013848893, -0.021872476, -0.029443623 }, { 0.008300061, 0.011951182, -0.011139414, 0.0098292843 }, { -0.0065854884, -0.020955083, -9.3843515e-05, -0.0078425688 }, { -0.054726229, -0.0073673428, -0.019267231, -0.03383648 }, { -0.049769726, 0.0065482059, -0.010189395, -0.0050480393 }, { 0.022565943, -0.020311569, 0.0091512717, -0.015600752 }, { -0.014418429, 0.0060070592, -0.0055296743, -0.003361885 }, { 8.8146509e-05, -0.0082609252, 0.0036746024, 0.0040108321 }, { 0.0010230427, 4.8153189e-06, 0.0052893378, -0.0096303521 }, { 0.0032909351, -0.010982824, 0.003880027, 0.0097699095 }, { -0.006528317, -0.012608887, -0.0057088008, -0.003867806 }, { -0.046599771, -0.024701737, -0.001078321, -0.0041018649 }, { -0.021680777, -0.021120711, 0.0055144734, -0.0031337995 }, { -0.030559213, 0.0089872726, -0.011166202, -0.0077587071 } }, { { -0.0059548858, -0.0040070313, -0.0062572119, -0.0047711065 }, { -0.0031938803, -0.005431389, -0.0026376521, -0.0046119366 }, { 0.0064917253, 0.013030824, -0.027850471, -0.011824849 }, { -0.032644485, -0.025045016, -0.0034396539, -0.039827623 }, { -0.007691681, -0.014095643, -0.0008171964, -0.0051336386 }, { -0.035626586, -0.021424668, 0.00035790929, 0.0099705685 }, { -0.0019006762, -0.0014887089, -0.0050782898, -0.0096835564 }, { -0.00087496879, 0.0052586834, 0.017041675, -0.00046753956 }, { -0.022489507, -0.0084834888, 0.0017184219, -0.0023910992 }, { -0.0010618265, -0.00085888729, -0.0020035777, -0.0024245283 }, { -0.029245834, -0.038977066, -0.013385246, -0.030312138 }, { -0.0028497869, 0.014205986, -0.0125692, 0.0037959624 }, { -0.0086377959, -0.019175965, -0.007684309, -0.005037677 }, { -0.063945685, -0.0060751259, -0.0057457302, -0.019079575 }, { -0.043745147, 0.013651906, -0.034067394, 0.0012111497 }, { 0.0086647574, -0.019171418, 0.020745219, -0.0055629951 }, { -0.024541273, 0.0072112135, -0.0078821942, -0.0085072621 }, { -0.0018227939, -0.0021153099, 0.008577002, 0.0043865151 }, { -0.013984752, -0.012209334, 0.00023638151, -0.0085025952 }, { -0.0099800075, -0.0095390578, 0.0081328135, 0.012673433 }, { -0.0099975551, -0.0028467616, -0.010712056, -0.0045012212 }, { -0.011329139, -0.0084709831, -0.0070232966, 0.0015504012 }, { -0.015334801, -0.0075637633, -0.01107439, -0.0094188163 }, { -0.017505269, -0.00013701888, -0.033955823, -0.034192649 } } }, { { { 0.16413327, 0.084074422, 0.10646123, 0.18806073 }, { 0.039511019, 0.058967072, 0.035166958, 0.052296507 }, { 0.26970995, 0.21576211, 0.2954278, 0.29870678 }, { 0.40442043, 0.38744132, 0.14502571, 0.24076804 }, { 0.22655046, 0.20912486, 0.015295019, 0.16442957 }, { 0.69235319, 0.6080183, 0.36756076, 0.23314717 }, { 0.085565328, 0.075535626, 0.22162979, 0.33140596 }, { 0.16109547, 0.11961895, 0.26619212, 0.25941009 }, { 0.27077686, 0.23481238, 0.063446408, 0.11614487 }, { 0.026116057, 0.027491327, 0.030421883, 0.039965345 }, { 0.33922592, 0.38039792, 0.27167385, 0.31510976 }, { 0.32744968, 0.22567102, 0.23116584, 0.18867836 }, { 0.29783431, 0.28054079, 0.26752139, 0.23889932 }, { 0.61721263, 0.60602797, 0.51283622, 0.47601102 }, { 0.51383952, 0.53111455, 0.44519064, 0.42875877 }, { 0.3485879, 0.35374178, 0.53292055, 0.53995494 }, { 0.4366997, 0.35554257, 0.14878367, 0.22083288 }, { 0.12855375, 0.16718264, 0.17583661, 0.11125895 }, { 0.35898096, 0.37222307, 0.35439108, 0.35956111 }, { 0.16773044, 0.25668894, 0.23246756, 0.1506316 }, { 0.36172813, 0.26938211, 0.20069185, 0.1714591 }, { 0.3998571, 0.23607244, 0.34121623, 0.29126696 }, { 0.31471307, 0.29500525, 0.39451396, 0.40013999 }, { 0.29554399, 0.28083636, 0.47190649, 0.47892938 } }, { { 0.01419653, -0.061214452, -0.032506906, 0.0078227125 }, { -0.015799432, 0.0136148, -0.0090824684, 0.013638505 }, { 0.023848919, 0.022034707, 0.022812846, 0.022790329 }, { -0.0026324255, -0.0053566952, 0.00027470228, 0.050203583 }, { 0.0035659857, -0.02015272, -0.039043616, 0.054511651 }, { 0.0052075445, 0.0051043119, -0.011801097, -0.0074336577 }, { 0.020735195, 0.01811747, 0.00808952, 0.01140964 }, { -0.0073139049, 0.011075347, 0.0057685988, 0.010251582 }, { 0.024813488, -0.01629986, -0.012536791, -0.01110061 }, { -0.014508648, -0.021444084, -0.023836972, -0.014258253 }, { 0.0079687141, -0.00092011446, 0.060249601, 0.033199468 }, { -0.020822483, -0.013924875, -0.005068391, -0.016928794 }, { -0.030059, -0.013887475, -0.045329289, -0.04449219 }, { 0.007264541, 0.0015213919, -0.0066322618, -0.0036449174 }, { 0.0057175046, 0.0012159867, -0.00054271896, 0.0020625484 }, { 0.0027083179, -0.0012554897, -0.0044854592, -0.0045242423 }, { -0.017906563, -0.028301884, -0.010139427, 0.0035851304 }, { -0.020245794, 0.01149232, 0.011320484, -0.013561794 }, { 0.0068048997, 0.011957759, 0.0046962412, -0.0015476541 }, { -0.0022514613, 0.019996868, 0.0051520398, -0.023405604 }, { 0.0055213198, 0.0070384134, 0.024405643, -0.02050399 }, { 0.039987541, 0.021127504, -0.012323503, -0.0041538161 }, { 0.0072321478, 0.0053097351, 0.0039966161, 0.013617175 }, { 0.030470642, 0.0044694115, -0.0024591651, -0.0027274707 } }, { { -0.040500402, -0.039657034, -0.017497359, -0.017857145 }, { -0.0015646885, -0.020957371, -0.0057356498, -0.0060587007 }, { 0.0070388709, -0.013205178, -0.00033412934, 0.02192306 }, { -0.0042317723, 0.020620857, -0.012309167, 0.065948811 }, { -0.016686589, 0.013616667, 0.030139062, -0.019023551 }, { 0.015181564, 0.008673659, -0.0014559576, -0.025916054 }, { 0.031630671, 0.027030197, -0.026982415, 0.025214731 }, { -0.003845127, -0.00062884599, -0.029488655, -0.0051457939 }, { -0.0032476351, 0.0021153707, -0.033110808, -0.033629213 }, { -0.0064637077, -0.010805748, -0.014982403, -0.0084641529 }, { 0.0087766042, 0.017780238, 0.026838871, 0.032580257 }, { 0.0010700985, -0.037414784, -0.0053773565, 0.0040969752 }, { -0.02637392, -0.050236074, -0.048422986, -0.069357813 }, { -0.0089483588, 0.0026259727, 0.0040142797, -0.010752754 }, { -0.0025658872, 0.0071106029, 0.015467367, 0.0012536589 }, { -0.0037247444, -0.0036991733, -0.015429566, -0.016148852 }, { -0.024788221, -0.045938054, -0.028679471, 0.011593494 }, { -0.032699114, -0.036800967, -0.033870575, -0.031842203 }, { 0.018156047, 0.02457546, 0.0209432, 0.015057433 }, { 0.0043152638, 0.025831372, -0.019608349, -0.026614397 }, { -0.0057047815, -0.013831909, 0.027613211, -0.043616864 }, { 0.014124478, -0.010786326, 0.010775415, -0.023241344 }, { 0.018337827, 0.0048735321, 0.018371717, 0.022106807 }, { 0.013619207, 0.022051384, 0.0082720974, -0.0030262071 } } } }, { { { { 0.083322661, 0.079807165, 0.03660117, -0.051657142 }, { -0.099216074, -0.0080141573, 0.10637241, 0.0367403 }, { 0.20813681, -0.0001361621, -0.20762563, -0.085913357 }, { -0.22091149, 0.10003156, -0.16122219, 0.31542901 }, { 0.16226908, 0.02665194, -0.012123307, -0.16559939 }, { -0.14025496, 0.025804505, 0.076174345, 0.20548591 }, { 0.0035713609, -0.0092551928, -0.099937652, 0.0038879391 }, { 0.12405732, -0.0053373497, -0.030865175, -0.060934551 }, { -0.0060175826, -0.026583926, -0.075326797, -0.0063155886 }, { 0.036389362, 0.054175433, 0.06490927, -0.038784258 }, { 0.30604876, -0.030813476, 0.011402956, -0.21074796 }, { -0.31769497, 0.046793931, -0.038212559, 0.21137297 }, { 0.12952945, 0.20720126, 0.08525845, -0.14568109 }, { -0.09735197, -0.17799099, -0.12256082, 0.038889119 }, { 0.002114572, 0.026037779, -0.0036772795, 0.13478173 }, { 0.094577863, 0.0057382415, -0.087017736, -0.059444148 }, { 0.054953104, 0.071323301, 0.097417831, 8.3254475e-05 }, { -0.11005534, 0.027214076, 0.0059378205, 0.02443999 }, { 0.27096654, 0.1864966, 0.034810947, -0.25886676 }, { -0.35626794, 0.037256657, -0.17795321, 0.52988269 }, { 0.14913899, -0.0086988732, -0.028760192, -0.21779266 }, { -0.16010301, -0.17699785, 0.017269826, 0.17878541 }, { -0.0049504093, -0.02387924, -0.04034852, -0.060461173 }, { 0.10405347, 0.0072745723, -0.10244372, -0.072981984 } }, { { 0.019363393, 5.327311e-05, 0.0075925373, 0.0019542034 }, { -0.051707557, 0.06554253, 0.0050626046, -0.0061857803 }, { 0.022891698, 0.014872273, -0.020436928, 0.0069081531 }, { -0.044566611, 0.019854557, 0.023600607, -0.0055387351 }, { 0.02283957, -0.067086756, 0.088865856, -0.033915007 }, { 0.0020254431, -0.16422426, 0.032495902, 0.012460808 }, { -0.017316175, 0.023440087, 0.011459595, 0.0043887872 }, { 0.027714908, -0.06907548, 0.013578806, -0.009848884 }, { 0.0044782488, 0.0079432606, 0.010143137, 0.023589488 }, { 0.014325082, 0.0075465848, -0.0079373813, -0.0056032635 }, { 0.025123579, 0.01904807, -0.0092328848, -0.019002052 }, { -0.02633985, -0.019560519, -0.065544737, 0.0073352606 }, { 0.044308433, -0.0032233834, 0.01324206, -0.00047128106 }, { -0.076577611, -0.021853603, -0.020190543, 0.0026420865 }, { -0.0029799448, -0.0083566545, 0.14896601, 0.0078617095 }, { 0.021033237, -0.08234711, -0.020642328, -0.0089829962 }, { 0.043793881, 0.0096494147, 0.035831274, -0.01294602 }, { -0.014064874, 0.066144489, 0.0143429, 0.015113964 }, { 0.043111732, 0.0029232804, -0.016912145, 0.012142059 }, { 0.0014186333, -0.0078590166, 0.065781153, -0.038375123 }, { 0.02255714, -0.030191796, -0.078373164, -0.0017593196 }, { -0.033878798, 0.016266579, 0.013539653, 0.043519216 }, { 0.019046482, 0.0080403173, -0.0010755939, 0.03305222 }, { 0.023206448, -0.054323067, -0.035173093, -0.010873592 } }, { { 0.014068291, -0.026418786, 0.016375695, 0.0048801469 }, { 0.024404214, 0.0073572002, -0.027247654, 0.00093849398 }, { 0.012741523, -0.012913063, 0.0054881373, -0.021780769 }, { -0.020497215, 0.057437717, 0.0031122704, 0.014713732 }, { 0.012765254, -0.052846334, 0.048042201, 0.0016578534 }, { 0.031245254, -0.0469321, -0.057199738, 0.012436479 }, { -0.0022837759, 0.0068501747, 0.010541107, -0.0005227683 }, { -0.0187059, 0.0025631581, -0.0082184266, 0.0026294483 }, { 0.0053899388, -0.0199458, 0.0023448066, 0.016215236 }, { 0.021117204, 0.010868775, -0.016412681, -0.016399297 }, { -0.0026199223, -0.011436548, 0.0031355049, 0.011933919 }, { 0.017940023, 0.090292392, -0.061029038, 0.016388845 }, { 0.0074493061, -0.045849358, -0.082612855, 0.025851315 }, { 0.061276666, -0.024654813, 0.035447334, -0.025952766 }, { -0.0068267167, -0.02207426, 0.003724368, 0.0070458116 }, { 0.021714649, -0.017552721, -0.037105408, 0.024398534 }, { 0.0092901891, -0.021559075, 0.009034776, -0.016574279 }, { -0.017218595, -0.041930302, 0.003369899, 0.017959363 }, { -0.0022510875, 0.028106616, -0.042936548, -0.041948028 }, { -0.017145551, -0.032331654, 0.021486923, -0.020295391 }, { -0.023196465, -0.088353584, 0.010086154, 0.018689553 }, { -0.024508386, -0.00058959302, -0.02867958, 0.019018994 }, { 0.0088748911, 0.012528454, -0.016636351, 0.0078166115 }, { 0.00066772723, 0.001693912, 0.032066885, 0.016951148 } } }, { { { 0.015200105, 0.071414961, -0.020616434, 0.0063982643 }, { -0.084578144, -0.12318522, -0.035470756, 0.057833574 }, { 0.19487946, 0.44043059, 0.10981527, -0.31907303 }, { -0.17774238, -0.30460726, -0.53133003, 0.31186606 }, { -0.1172677, 0.3183613, 0.10375266, -0.066515168 }, { 0.054176263, -0.12382077, -0.033807438, 0.039809238 }, { -5.3634009e-05, 0.004084452, 0.005103199, -0.060697866 }, { 0.06093199, 0.060355274, 0.049176467, -0.060579228 }, { 0.054611799, 9.0520863e-05, -0.048891261, -0.047609349 }, { -0.036428706, 0.06336736, 0.0020843807, 0.033254378 }, { 0.26975732, 0.51328693, 0.29976157, 0.049031141 }, { -0.28383516, -0.48219276, -0.27898799, -0.033028759 }, { -0.078976834, 0.14077934, 0.098587186, 0.051336328 }, { 0.076281206, -0.074223398, -0.053178835, -0.099578331 }, { -0.056377095, -0.00066113896, -0.11597726, 0.058805777 }, { -0.0027130032, 0.12007881, 0.0081935835, -0.10415807 }, { -0.019349408, 0.06206561, -0.0079099126, 0.079363093 }, { -0.059959607, -0.0591041, -0.047505451, -0.0031496967 }, { -0.11419194, 0.20904287, 0.53960104, 0.10467592 }, { -0.21312862, -0.34770872, -0.54593093, 0.23230512 }, { -0.073229448, 0.12913, 0.27728133, -0.050627706 }, { 0.082312471, -0.24529296, -0.12381516, 0.05577292 }, { 0.03015389, -0.0015805638, 0.024306632, -0.080697961 }, { 0.061367564, 0.056058289, 0.041197211, -0.015551356 } }, { { -0.029269776, -0.030251548, 0.01352869, 0.0084860712 }, { 0.053983187, 0.047657625, -0.026379004, 0.022474039 }, { 0.011898439, 0.045120742, -0.024430477, -0.081318878 }, { -0.0012641508, -0.018495044, -0.030127865, -0.0088483264 }, { 0.040728292, 0.010691761, -0.023566342, 0.028045232 }, { 0.014593998, 0.0047006468, -0.049032498, -0.011446808 }, { 0.00045433705, -0.0030610749, -0.010359449, -0.0026455857 }, { -0.0026794352, -0.032142744, 0.010153936, -0.0034586152 }, { 0.0097198782, 0.0051005644, 0.03482872, -0.0043676475 }, { -0.0012381415, -0.025746274, -0.0081178021, 0.0041481596 }, { -0.01598781, 0.0048815642, 0.06313106, -0.0062291669 }, { 0.072970618, -0.041153529, -0.007457013, 0.059776924 }, { 0.0024768493, 0.0093018711, 0.024827984, 0.043842172 }, { -0.012927661, -0.023256709, -0.0035951539, -0.069710027 }, { 0.0064149713, 0.0019783425, 0.010135188, 0.019449636 }, { -0.0071551675, 0.015761815, 0.0086309278, 0.038854386 }, { 0.020978109, -0.0056696814, 0.0025526797, -0.017352926 }, { -0.010711116, -0.0097050903, 0.0022304504, -0.0039308489 }, { 0.036904234, 0.025927127, 0.028330671, 0.051193417 }, { -0.00076391153, -0.077528792, -0.029763477, 0.0033945843 }, { -0.01775202, 0.034507636, 0.065392848, -0.017840909 }, { -0.019567742, -0.019880035, 0.055214211, -0.02206159 }, { 0.01110111, 0.0022938832, -0.011417507, 0.017692635 }, { 0.050208493, -0.028178909, 0.0065276591, -0.0056267473 } }, { { 0.0065622702, -0.0012303136, -0.0081183663, 0.00079383048 }, { 0.030775912, 0.052260356, -0.019758331, -0.020044147 }, { 0.019016537, -0.043070451, 0.035298744, -0.040592775 }, { 0.010468089, 0.00057085185, 0.0081761984, 0.0033382478 }, { 0.047189462, -0.052695409, 0.021849623, 0.033585939 }, { 0.0012065616, -0.050287476, -0.065085924, -0.039012886 }, { -0.012294892, 0.006839242, 0.0051165438, -2.0711078e-05 }, { -0.03292822, 0.015299577, 0.0029119931, 0.0073040242 }, { -0.0086784873, 0.0085910164, -0.0059378411, -0.010259049 }, { -0.014191355, -0.011172486, -0.01299927, 0.015386671 }, { 0.040453224, -0.041489173, 0.015047889, 0.064340197 }, { -0.020000046, 0.058477092, -0.0018150465, 0.048536972 }, { -0.006105982, 0.03437044, 0.0087640339, 0.032868283 }, { -0.027120362, 0.016579996, -0.01708524, 0.011178424 }, { 0.030535528, 0.0058718219, -0.031240404, 0.024241052 }, { 0.003729958, -0.055735848, -0.0055392842, 0.03447519 }, { -0.04084502, -0.01227488, 0.0062970198, -0.021996031 }, { 0.053671675, -0.067787009, 0.0053426012, -0.0080796738 }, { -0.021911856, 0.038395527, -0.07713235, 0.024805484 }, { -0.0034319194, 0.0052741327, 0.026402991, 0.0012916612 }, { -0.033119652, -0.0046506889, 0.045613946, -0.050230593 }, { -0.0054612035, -0.033482221, 0.084267507, -0.0224334 }, { -0.0063348693, -0.0074524817, -0.0029629355, 0.035493958 }, { -0.0073519185, 0.045139911, 0.0022901735, -0.041385515 } } }, { { { 0.99640669, 0.99424882, 0.99911727, 0.99864438 }, { 0.99146493, 0.99235134, 0.99369348, 0.99764995 }, { 0.95848895, 0.89778665, 0.9720248, 0.943828 }, { 0.95896077, 0.9472107, 0.83168251, 0.89623886 }, { 0.97975356, 0.94759472, 0.99452924, 0.98394744 }, { 0.98863213, 0.99196902, 0.99652121, 0.97785007 }, { 0.99999362, 0.99994883, 0.99498061, 0.99814861 }, { 0.99040248, 0.99816269, 0.99831309, 0.99630173 }, { 0.99848953, 0.99964658, 0.9959596, 0.99884607 }, { 0.9986735, 0.99651874, 0.99788899, 0.99869411 }, { 0.91299789, 0.85766372, 0.953946, 0.97631002 }, { 0.90471405, 0.87481454, 0.959534, 0.97684726 }, { 0.9884254, 0.96811612, 0.9914694, 0.98799879 }, { 0.99232241, 0.98122887, 0.99103524, 0.99426948 }, { 0.99840731, 0.99966074, 0.99324506, 0.98912879 }, { 0.99551377, 0.99274778, 0.99617307, 0.9927827 }, { 0.99830144, 0.99552039, 0.99521214, 0.99684577 }, { 0.99211525, 0.9978808, 0.99885333, 0.99969634 }, { 0.95579147, 0.95995838, 0.84120087, 0.96022443 }, { 0.90975235, 0.9368621, 0.81871367, 0.8156339 }, { 0.98610091, 0.99158952, 0.96035822, 0.97468107 }, { 0.98366238, 0.9531543, 0.99215501, 0.98230604 }, { 0.99953301, 0.9997136, 0.99888998, 0.99490315 }, { 0.99267663, 0.998401, 0.99388534, 0.99721201 } }, { { -0.0021537732, 0.010607958, -0.0066166595, -0.0027390442 }, { -0.0069401807, 0.0053215201, 0.0062121114, 0.013403291 }, { -0.0035740125, -0.021839368, 0.00042431197, -0.029478899 }, { -0.007886159, -0.0087705321, -0.010570968, 0.0040635318 }, { -0.0021772698, 0.00025306776, -0.0092725896, -0.0075657706 }, { -0.010438319, -0.0072866821, 0.009272756, 0.0043932916 }, { -0.00058203184, 0.0081284104, 0.027749999, 0.0035426599 }, { -0.003604276, -0.012244348, 0.0072177908, 0.0026686264 }, { 0.011192179, 0.0069527119, 0.017278396, -0.0053058312 }, { -0.020276487, -0.0063228657, 0.013968347, -0.0021534789 }, { -0.0037534313, 0.00061399133, -0.02126817, 0.0085256452 }, { 0.015620795, -0.022637876, 0.00069280338, 0.0054369037 }, { 0.0095244184, -0.0026896982, -0.0057963534, 0.0067237437 }, { -0.0085689961, -0.004816024, -0.00088793436, -0.0034021999 }, { 0.015428153, 0.019777562, -0.011217833, 0.0095744159 }, { -0.003802304, 0.0022643577, 0.0054254827, 0.025560756 }, { -0.0053298651, 0.021621993, -0.01864184, 0.019120967 }, { 0.015380344, -0.0027384467, 0.0010235928, 0.0062792725 }, { -0.001166873, -0.0049586656, -0.014850883, 0.00057841904 }, { 0.0032865456, -0.033386196, 0.0032068954, 0.02854738 }, { 0.010308266, -0.000233004, -0.020287643, 0.0044441043 }, { -0.0040523345, 0.0050367711, 0.01627907, -0.010032412 }, { 0.0073463987, 0.00073274858, 0.002814661, 0.030221018 }, { 0.0057509063, -0.011441338, 0.01894259, 0.0077856453 } }, { { -0.0053054924, 0.0037677068, 0.0066263851, 0.0011220287 }, { -0.02212139, 0.013769097, -0.0013834097, 0.014152363 }, { -0.0008493126, 0.021473024, -0.0039313241, -0.017764981 }, { -0.00081897848, -0.0074161164, 0.0038179092, -0.0035760615 }, { 0.014045643, 0.015317904, 0.0045966739, 0.0075917156 }, { 0.0035574126, -0.00017773424, -0.0010937491, -0.0017762282 }, { 0.0072018344, 0.012586227, 0.0138702, -0.0085424173 }, { -0.0055783456, -0.019909385, 0.01190919, -0.0065821489 }, { 1.7402026e-05, 0.0094513341, 0.015333305, -0.0072158969 }, { -0.0063049905, 0.0021776758, 0.014376378, 0.0072426401 }, { -0.0078049673, 0.028764242, -0.0024169449, 0.0077604105 }, { 0.00047536469, 0.029806623, 0.0017798261, 0.00087410198 }, { -0.0030498401, 0.0044874501, 0.0020382571, -0.0011101062 }, { -0.0057084397, -0.0013428994, -0.001024136, 0.0066188614 }, { 0.039201052, 0.015120258, -0.0082642793, 0.0051985023 }, { -0.0091203243, 0.020790215, 0.0025270937, 0.020092044 }, { -0.0029830063, 0.006602841, -0.00833601, 0.044852353 }, { 0.025206353, -0.0038915173, 0.00045914851, 0.0037840538 }, { 0.0014814254, -0.011573911, 0.046232337, -0.015228958 }, { -0.0071984443, 0.0090004063, 0.022942838, 0.016019787 }, { 0.0050929336, 0.0060892107, -0.0061771339, 0.0047850766 }, { -0.011634853, 0.0010276548, 0.022396644, -0.0021248711 }, { -0.012943002, 0.0016430074, 0.02034928, 0.024289705 }, { 0.0051047037, 0.010052556, 0.0020923265, -0.019043181 } } }, { { { 2.1627647, 2.1788232, 1.9290264, 1.8457806 }, { 2.526488, 2.3020441, 2.538915, 2.03484 }, { 3.9987521, 4.3952121, 3.906821, 4.1693278 }, { 4.0400466, 4.1069844, 5.2512999, 5.4283264 }, { 3.0141968, 3.3306035, 3.2224806, 3.2473051 }, { 2.9840674, 3.1294685, 3.2964833, 3.2929246 }, { 1.8346741, 1.8637353, 2.3037966, 2.0860888 }, { 2.691236, 2.6068079, 1.9349032, 2.1632935 }, { 1.9231956, 1.7251627, 2.1609654, 2.1155629 }, { 2.165771, 2.1908952, 1.777038, 2.0223741 }, { 4.5166991, 4.8674508, 3.918546, 3.378087 }, { 4.4502295, 4.5429338, 3.9552598, 3.3580272 }, { 3.0973598, 3.3953852, 2.2704362, 2.6488177 }, { 3.2110537, 3.3104376, 2.515002, 2.3267785 }, { 1.8303675, 1.7094345, 3.1787979, 2.5960104 }, { 2.4391795, 2.8730077, 2.3730261, 2.1545299 }, { 2.2130903, 2.1899209, 2.4997355, 1.9058674 }, { 2.6472893, 2.5455636, 2.1164596, 1.8341163 }, { 3.9428283, 4.0433678, 4.5430063, 4.2482776 }, { 4.1941673, 4.28852, 4.64044, 4.6644567 }, { 3.0873642, 2.649364, 3.6026133, 3.2426354 }, { 3.2415154, 3.5406745, 3.2976852, 3.3100246 }, { 1.8400289, 1.8404692, 1.889289, 2.0125184 }, { 2.7063995, 2.7229173, 2.6289878, 2.4313709 } }, { { -0.015335928, -0.043382119, -0.0054163805, -0.028249934 }, { -0.017200109, 0.0027582413, -0.079612821, -0.0013966663 }, { -0.027233584, -0.018783395, -0.01183278, -0.020918937 }, { -0.0036358348, -0.015712206, -0.0089146421, -0.0057117233 }, { 0.020392865, 0.017743746, -0.068597326, -0.030425581 }, { -0.041123673, -0.020767538, -0.0087941887, -0.0065248183 }, { -0.0055478408, -0.00082196865, 0.0088521402, -0.045916836 }, { -0.010506485, 0.0078523247, -0.030002306, -0.0015085765 }, { 0.01894068, -0.012424968, -0.034837214, -0.045009941 }, { -0.045299587, 0.02630478, -0.017175711, -0.043601235 }, { -0.046003661, -0.020588165, 0.034398873, -0.054653787 }, { -0.0042534368, 0.01325834, -0.0036369576, -0.079162988 }, { -0.028728556, 0.0051289128, 0.012104313, 0.010686997 }, { -0.066337767, 0.00059928728, -0.080303668, 0.011318772 }, { -0.031879871, 0.0011317962, -0.050259029, 0.0031596552 }, { -0.090121238, -0.011196084, -0.072456123, -0.00079731072 }, { -0.024243475, 0.021401076, -0.018209385, -0.0083196072 }, { -0.079888701, 0.0032806631, -0.12762259, -0.04652308 }, { 0.031806075, -0.034165157, -0.015255921, -0.049164663 }, { -0.0012051123, 0.030788487, 0.022291919, 0.0025694519 }, { 0.035836509, 0.0055365388, 0.026704836, 0.0001547235 }, { -0.012129747, -0.0094322145, -0.040637935, -0.12125388 }, { -0.027044986, 0.04531553, -0.033484589, -0.0059927923 }, { 0.0067188802, -0.051166351, -0.048822794, -0.025926988 } }, { { 0.022049053, 0.021265778, -0.040370641, -0.036232952 }, { -0.0058098424, -0.0042264198, -0.077428509, -0.04241654 }, { -0.0026825379, -0.029453318, -0.016181275, -0.028320229 }, { -0.012541692, -0.01345735, 0.00037814888, -0.0046052489 }, { -0.026527394, 0.020033638, -0.025683861, -0.084207169 }, { -0.0010459945, -0.036745215, -0.039772051, 0.024810839 }, { 0.012134618, 0.0068515798, -0.035286972, 0.043129595 }, { -0.077093357, -0.026872688, 0.032800133, -0.090326706 }, { 0.13930909, 0.0081274014, -0.08349188, -0.012200005 }, { -0.091693797, -0.012567011, -0.069736822, -0.0061444184 }, { -0.053061301, 0.003642159, 0.0052515175, -0.036957472 }, { 0.0043493933, -0.013069332, -0.014708126, -0.032765039 }, { -0.016116105, -0.022907609, -0.043503106, -0.013266465 }, { -0.072759977, -0.077354585, 0.0043827591, -0.013821612 }, { -0.032399073, -0.045305037, -0.021840791, 0.073996542 }, { -0.057239255, -0.056581235, -0.038880927, 0.044102943 }, { -0.026951489, -0.088667645, -0.013659704, 0.033527579 }, { 0.034815442, -0.028634059, -0.036666529, 0.011546036 }, { 0.026688447, -0.0081892129, -0.031138092, -0.041739155 }, { 0.0015665701, -0.012701682, 0.0013533943, -0.002849785 }, { 0.032994636, 0.008802974, 0.019032649, 0.0039042621 }, { -0.044544917, 0.0093201326, -0.017968915, 0.01936344 }, { -0.034794535, 0.043032983, -0.051072531, -0.040148303 }, { -0.0030398597, -0.027112065, -0.064007483, -0.01798277 } } }, { { { 0.22040906, 0.24911942, 0.41660708, 0.23632869 }, { 0.25894466, 0.1416669, 0.41902981, 0.35717608 }, { 0.26918091, 0.14566759, 0.2147652, 0.15769391 }, { 0.22500921, 0.12113361, 0.11151768, 0.12348609 }, { 0.25699055, 0.056819107, 0.3859882, 0.4585378 }, { 0.7304995, 0.20719358, 0.44455636, 0.42226989 }, { 0.43602897, 0.51049581, 0.41978824, 0.62521039 }, { 0.42004119, 0.52912054, 0.33314238, 0.38257921 }, { 0.55092562, 0.43085653, 0.31149977, 0.34391138 }, { 0.40391149, 0.48820255, 0.13569806, 0.36060266 }, { 0.13647907, 0.12061002, 0.20668806, 0.30221394 }, { 0.15583476, 0.13133696, 0.22775202, 0.35653823 }, { 0.56336195, 0.25684627, 0.11118383, 0.23109245 }, { 0.45430401, 0.42843367, 0.25496534, 0.097473509 }, { 0.3420223, 0.39418925, 0.26458947, 0.30588082 }, { 0.51345558, 0.3612731, 0.41151773, 0.25269512 }, { 0.29195176, 0.42659964, 0.47971993, 0.32714756 }, { 0.49222777, 0.28477645, 0.74993827, 0.43781271 }, { 0.098434481, 0.31164923, 0.14486345, 0.11466693 }, { 0.070833248, 0.20569754, 0.10233576, 0.047352701 }, { 0.51050902, 0.15597643, 0.1417112, 0.35581415 }, { 0.48261165, 0.14592221, 0.62554576, 0.5209765 }, { 0.33562628, 0.39920067, 0.28183433, 0.297464 }, { 0.366851, 0.59278666, 0.59095922, 0.48385165 } }, { { 0.13792051, 0.072076744, 0.094800532, 0.026318377 }, { 0.13607414, -0.061382542, 0.061800151, -0.020060553 }, { 0.028096406, 0.069282616, 0.010195109, -0.010461141 }, { 0.018651237, 0.02642439, 0.0077552848, -0.051151646 }, { 0.098299803, -0.0085081153, -0.011764584, 0.087405711 }, { 0.064082346, -0.04626424, -0.071480607, 0.064447268 }, { 0.022766233, 0.0167542, -0.021285286, -0.071637286 }, { -0.0202445, 0.011692601, 0.048325551, 0.0097755172 }, { -0.027775183, 0.016463115, 0.060050391, -0.034226107 }, { 0.019412547, 0.059977501, -0.0041737169, 0.031539317 }, { 0.013192979, 0.036015595, -0.049943198, 0.014112312 }, { -0.013272349, 0.035821037, -0.060503687, 0.095316821 }, { 0.038338785, -0.059038809, -0.044954172, -0.00051347307 }, { -0.039594082, 0.018205882, 0.13413799, 0.012292954 }, { 0.015177594, -0.0082493854, 0.00029420179, 0.010356248 }, { 0.100271, -0.13623174, 0.1121235, 0.068902399 }, { 0.025189636, 0.0014918434, 0.0088847718, -0.053714493 }, { 0.06487698, -0.097217547, -0.069537353, 0.032490984 }, { -0.030729608, 0.048956315, 0.016036034, 0.022485239 }, { 0.049839618, 0.01148525, -0.021032427, -0.019665817 }, { -0.0037762817, -0.030422275, -0.062343207, 0.057994884 }, { 0.014035184, -0.021387762, -0.080846143, -0.020681511 }, { -0.03594567, 0.026862531, 0.078975557, -0.034056659 }, { -0.014490672, 0.026128902, 0.045617611, 0.090192953 } }, { { 0.011904288, -0.014624471, 0.042023114, 0.019592867 }, { 0.032705848, 0.00038558691, 0.031901745, 0.027208951 }, { -0.044369719, -0.039761364, -0.013366816, -0.019308126 }, { -0.019051023, -0.00015767269, -0.082968285, -0.035266053 }, { -0.004775162, 0.010889271, 0.0089521094, 0.027037104 }, { 0.005616143, -0.00099668486, 0.0068716426, -0.12649184 }, { 0.018531199, 0.023881776, -0.053798787, -0.041912909 }, { -0.0036187094, 0.11590788, 0.025140733, 0.022280209 }, { -0.02994342, -0.026293799, -0.017204658, 0.044901944 }, { 0.079892089, 0.10816526, 0.14667807, 0.027301352 }, { -0.045296738, -0.066748968, -0.0099354431, -0.070369692 }, { -0.08357374, -0.043311901, 0.013163375, -0.0881777 }, { -0.065923811, -0.10382274, 0.090440302, -0.013617198 }, { -0.092578587, -0.010178017, -0.01416593, 0.0432333 }, { 0.055172515, 0.10021805, -0.0062782668, -0.11791805 }, { -0.039684132, -0.08934283, 0.020686084, -0.0013788117 }, { 0.064624676, 0.051773746, 0.0045383964, -0.037696971 }, { -0.066296373, 0.020570689, -0.017742721, -0.022651449 }, { -0.0061572447, -0.094510525, -0.094775804, -0.038022514 }, { 0.0055683313, 0.039513342, -0.096815654, -0.0065483011 }, { -0.03311602, -0.018395457, 0.0028464434, -0.088048272 }, { -0.073106109, -0.055187863, -0.093209932, -0.10155137 }, { 0.042841842, -0.005778703, 0.074069607, -0.025841052 }, { -0.018569637, 0.063144303, 0.02291584, 0.005525742 } } } }, { { { { -0.20809663, -0.18346453, -0.072140694, -0.0078104407 }, { -0.19490097, 0.25712922, 0.37640771, 0.11563399 }, { 0.26894915, -0.33477877, -0.093739129, -0.55078405 }, { -0.65794103, 0.09211629, -0.19166986, 0.5574327 }, { 0.45579532, 0.23202083, 0.19626303, -0.64130523 }, { -0.018763975, -0.24981569, -0.32514026, -0.11121342 }, { 0.22376238, 0.09515938, 0.071728264, -0.02790747 }, { -0.3053338, 0.34023365, 0.099862481, 0.26163964 }, { -0.21722968, -0.094881958, -0.086364431, -0.0081863581 }, { -0.16090709, 0.23527698, 0.28947119, 0.11309742 }, { 0.26447184, -0.33536416, -0.096418234, -0.26201294 }, { -0.56343769, -0.041662822, -0.24873841, 0.67122901 }, { 0.35362642, 0.2577592, 0.2009013, -0.74233681 }, { -0.047956299, -0.54973418, -0.4958485, -0.12453303 }, { 0.06917425, 0.080509853, 0.0090863722, -0.023518805 }, { -0.27000602, 0.083167162, 0.12715558, 0.12397839 }, { -0.11376964, -0.079199259, 0.019676685, -0.0094352472 }, { -0.19185851, 0.22193112, 0.28110877, -0.06422845 }, { 0.084091992, -0.16151548, 0.091400556, -0.28257376 }, { -0.53821376, 0.21718328, -0.2234907, 0.52302804 }, { 0.71322306, 0.042728493, 0.13229522, -0.61892094 }, { 0.15270046, -0.26304886, -0.33110633, -0.052728951 }, { 0.072398971, 0.25829764, 0.25881687, -0.020942042 }, { -0.26788161, 0.055822039, 0.33817103, 0.42061402 } }, { { 0.088248648, 0.091306255, 0.020476927, 0.0030144802 }, { 0.0087376707, 0.043816157, 0.0022807168, 0.016745414 }, { -0.13412414, 0.12686539, 0.060531476, 0.044582027 }, { 0.019204757, -0.0070891897, 0.091194602, 0.065258927 }, { -0.10429513, -0.027665602, -0.064350626, 0.0053147478 }, { 0.069218141, -0.035018324, -0.088257571, 0.019279642 }, { -0.073137338, 0.040764456, -0.022352804, 0.031743288 }, { 0.040325697, -0.12840825, -0.009582113, 0.034509657 }, { 0.081971224, -0.0035223125, -0.051728499, 0.0038899717 }, { 0.050968435, 0.022254651, 0.18781134, -0.032392139 }, { 0.024342518, 0.13929014, -0.019175435, -0.0011608234 }, { -0.0021942487, -0.01251222, 0.024263454, -0.063179344 }, { -0.13071776, -0.059221747, -0.034153238, 0.036561209 }, { 0.054124093, 0.070495803, 0.081441614, 0.051900357 }, { 0.027480327, 0.028940343, -0.01469313, 0.032388411 }, { -0.039696828, -0.0069393798, -0.011361641, 0.035031025 }, { -0.039730763, 0.0085971581, -0.0077461932, -0.040735188 }, { 0.10893368, 0.00014757217, 0.025489178, -0.11388774 }, { -0.0013816669, 0.0031148929, 0.10281666, -0.019860642 }, { -0.065093128, -0.11495815, 0.041783056, -0.091373461 }, { -0.044985581, 0.0012713031, -0.16078032, 0.17303747 }, { -0.038132358, -0.02995975, -0.037612782, 0.012575173 }, { 0.0042976619, 0.027014275, 0.017518808, 0.030405184 }, { -0.0015298607, 0.029297664, -0.1034349, 0.023450502 } }, { { 0.028785558, -0.028708377, -0.010459636, 2.8360915e-05 }, { 0.091634877, 0.021214811, 0.12282079, 0.080617943 }, { -0.29287977, 0.045481846, 0.014712563, 0.057317576 }, { -0.10728772, 0.03268482, 0.015167285, -0.011256231 }, { 0.09337321, 0.037150859, 0.052549202, -0.042671474 }, { -0.0041288689, -0.024299997, -0.11357403, -0.022045772 }, { -0.041469935, -0.0071353646, -0.0086607538, 0.008536762 }, { 0.033629272, -0.0070042955, -0.037864853, -0.0055907778 }, { 0.016404597, -0.0055321059, -0.020989839, -0.013771265 }, { 0.042552435, 0.04428518, 0.0030587466, 0.044894182 }, { -0.027600219, 0.026831779, 0.051120849, -0.032184808 }, { 0.13870554, 0.15273282, 0.049260112, 0.043371121 }, { -0.018453269, -0.18061413, 0.24805649, -0.031741165 }, { -0.085137374, 0.025935867, 0.015978067, 0.067726486 }, { 0.072393868, 0.0050430488, 0.0016664585, 0.0072097064 }, { 0.033840162, 0.082225764, -0.079387016, 0.033165625 }, { 0.033170766, 0.0012231618, -0.066984982, 0.051671704 }, { 0.017894231, -0.012267532, 0.045536123, -0.07327109 }, { 0.0073109731, -0.063797898, -0.13446413, 0.1408986 }, { -0.045702456, -0.1647051, -0.14336468, 0.054543693 }, { 0.0042448876, -0.13234456, 0.092181719, -0.10440841 }, { -0.060020212, -0.011098469, -0.030257182, -0.030922037 }, { -0.018118661, 0.00067983745, -0.0061776598, -0.031721273 }, { -0.019885189, 0.094157888, 0.014017961, -0.051373389 } } }, { { { 0.12415319, -0.13611564, -0.029441661, -0.14143497 }, { -0.26074418, 0.011913326, -0.033328425, 0.43248793 }, { 0.19336432, 0.37269586, 0.36803538, -0.51720719 }, { -0.15185913, -0.47431781, -0.6593667, 0.23163184 }, { 0.18276216, 0.19248743, 0.65453332, 0.54748087 }, { 0.17751443, -0.0020337696, 0.08506463, -0.40147769 }, { -0.11370932, 0.11523476, -0.010573025, 0.082295392 }, { -0.13666335, -0.32747478, -0.16897386, 0.15359006 }, { 0.11716326, -0.12259922, 0.0033396256, -0.13240653 }, { -0.27776876, -0.10222241, -0.039920479, 0.35499708 }, { 0.090003723, 0.3313923, 0.1871549, 0.003163675 }, { -0.51626118, -0.76341562, -0.56326874, 0.20153559 }, { -0.34172723, 0.26975563, 0.67520079, -0.1252004 }, { 0.45758078, -0.19142179, 0.064180031, -0.48748431 }, { -0.12800789, 0.1399912, 0.0077954775, 0.14379741 }, { -0.13042104, -0.45670817, -0.18831095, 0.0032738639 }, { 0.12446807, -0.11504524, -0.027331682, 0.03861758 }, { -0.31337986, -0.11842668, 0.033415325, 0.45344231 }, { 0.11463107, 0.077427841, 0.060880794, -0.069619455 }, { -0.37772106, -0.59628905, -0.65426572, 0.065297039 }, { 0.29532991, 0.75920243, 0.53294265, -0.15002562 }, { 0.3618333, 0.10488387, 0.36007528, -0.30963565 }, { -0.13738196, 0.20795596, 0.029274703, 0.18017599 }, { -0.10290023, -0.48517535, -0.33278584, 0.56477854 } }, { { -0.0047891472, 0.024629901, 0.015256654, -0.0084462001 }, { 0.056227746, -0.048057782, -0.15671312, 0.06418471 }, { -0.070093217, -0.018057199, 0.062026545, -0.051053726 }, { -0.0091221476, 0.0020547295, -0.087729813, -0.10164738 }, { 0.098917091, -0.066835916, 0.083151519, 0.006342544 }, { 0.0013540606, 0.038719082, 0.036333261, -0.053178668 }, { 0.0083787438, 0.0028359378, 0.0089872852, 0.031308249 }, { 0.014379686, -0.079563474, -0.079160006, -0.016352226 }, { 0.0091376645, -0.016678006, -0.044636785, -0.0011035265 }, { 0.0099146109, 0.027589302, -0.09494437, 0.07451767 }, { 0.017453983, 0.080674871, 0.06341808, 0.048820473 }, { 0.02794057, 0.058230195, -0.010793601, 0.091813872 }, { -0.049633232, -0.1142016, 0.036984283, 0.0034294865 }, { 0.047712957, 0.10161366, 0.13774722, 0.039503136 }, { 0.014194782, -0.014555183, -0.00053182909, 0.0019143477 }, { 0.0014900262, 0.0056176356, -0.034517871, -0.0010707988 }, { 0.013287784, -0.0073967933, -0.019271341, 0.016354896 }, { -0.10345626, 0.023536634, 0.027943639, -0.015686972 }, { -0.025193395, -0.10224801, 0.078686884, -0.048574399 }, { 0.15797878, -0.0012322757, -0.036096649, -0.23983963 }, { -0.10455507, -0.056368102, -0.06570944, 0.29104616 }, { 0.05155239, -0.040940824, -0.038367594, 0.058174485 }, { 0.010471732, -0.066952904, -0.047763843, -0.021124742 }, { -0.033555686, 0.0049111983, -0.026592789, 0.014438586 } }, { { -0.0048440946, 0.025915095, -0.018325403, 0.022133613 }, { 0.059240081, -0.031272176, -0.12967647, -0.17957913 }, { 0.0574837, 0.067005152, 0.024644254, 0.10786296 }, { 0.067084865, 0.008513386, 0.04077659, 0.10587924 }, { 0.026332643, 0.1072618, -0.098375042, -0.001724609 }, { -0.021386362, -0.0020174921, 0.16800158, 0.081359882 }, { -0.018204146, -0.026432136, -0.0068153455, -0.029997667 }, { -0.043221501, -0.016869967, -0.067406967, -0.024965804 }, { -0.0033879999, 0.031310818, -0.010853802, 0.00088944004 }, { -0.068991006, 0.087874253, -0.15737392, -0.088870044 }, { 0.061763806, -0.00072874343, -0.009915009, -0.0178225 }, { -0.07340717, 0.080339271, -0.0027124572, -0.13078641 }, { -0.023682834, 0.16512313, -0.15784472, 0.047978827 }, { 0.0063250439, -0.09953777, 0.094180888, 0.010565041 }, { 0.010047311, -0.042999009, -0.012483998, -0.016966759 }, { -0.048612679, 0.051708319, 0.015059148, 0.0036776472 }, { -0.011737015, -0.0027276603, 0.026535075, -0.065453876 }, { 0.056388137, 0.061461073, -0.12726984, -0.025578248 }, { 0.0016833003, 0.10878558, 0.13254828, -0.017098914 }, { -0.031606282, -0.072245098, 0.12724789, -0.21852899 }, { -0.062502612, -0.073402771, -0.049624729, 0.069066032 }, { -0.075837195, -0.10297347, -0.07249237, -0.11538062 }, { -0.015644005, 0.039474396, 0.074415075, -0.038881161 }, { -0.040175911, 0.034030267, 0.03947059, 0.014167463 } } }, { { { 0.97019677, 0.97355703, 0.99695983, 0.98991674 }, { 0.94552952, 0.96630359, 0.92585444, 0.89419404 }, { 0.9435447, 0.86545998, 0.92507456, 0.65508294 }, { 0.73759908, 0.87552111, 0.72697883, 0.79725496 }, { 0.87111918, 0.95347518, 0.73011435, 0.53758004 }, { 0.9839393, 0.96829127, 0.94183216, 0.90909143 }, { 0.96798791, 0.98876976, 0.99736817, 0.99621717 }, { 0.9423876, 0.88147679, 0.98054848, 0.95286662 }, { 0.96906348, 0.98791034, 0.99625801, 0.99116169 }, { 0.94707625, 0.9665378, 0.9563539, 0.9280011 }, { 0.96018435, 0.88187869, 0.97758711, 0.96505917 }, { 0.64499021, 0.64456248, 0.78794513, 0.71332673 }, { 0.87073007, 0.92778882, 0.70974824, 0.65822558 }, { 0.88787388, 0.81311133, 0.86603417, 0.86420517 }, { 0.98935782, 0.98687417, 0.99992833, 0.98932764 }, { 0.95398485, 0.88572054, 0.97384313, 0.99227952 }, { 0.98567955, 0.99019799, 0.99943274, 0.99920952 }, { 0.93004482, 0.96784384, 0.95909399, 0.88896838 }, { 0.98984254, 0.98382807, 0.99395144, 0.95671584 }, { 0.75342733, 0.77283296, 0.72248756, 0.84981055 }, { 0.63568318, 0.6494505, 0.83574524, 0.77099234 }, { 0.91965169, 0.95906448, 0.87218942, 0.94939213 }, { 0.98786871, 0.94341754, 0.96548269, 0.98341143 }, { 0.95794101, 0.87263324, 0.8802806, 0.71000638 } }, { { -0.0064390277, 0.051629953, -0.011423447, 0.032337826 }, { 0.055030538, 0.061305324, -0.016012659, 0.083766345 }, { 0.052467122, 0.018425134, -0.00054737782, 0.048038459 }, { 0.076436505, 0.016815709, -0.024174832, -0.00829119 }, { 0.057903371, 0.068822104, -0.0064003131, 0.00010695928 }, { 0.067104151, 0.067284611, 0.0074295447, 0.024215238 }, { 0.073380541, 0.01486405, 0.01523157, 0.012966612 }, { -0.0002536971, 0.010628632, 0.00045031869, 0.041891438 }, { 0.055922922, 0.0090823157, 0.011101162, 0.033807592 }, { -0.040264953, 0.022318628, -0.013682045, -0.016112502 }, { -0.034286564, 4.7089727e-05, -0.013030079, -0.012231424 }, { 0.027756308, 0.084041595, 0.018308393, 0.11564334 }, { 0.0026690817, 0.058149333, -0.013682964, 0.052975934 }, { -0.03852481, 0.063493354, 0.059460027, 0.047740976 }, { 0.026410264, -0.0073902435, 0.022353771, 0.012987341 }, { 0.035217135, -0.0023455309, -0.0055505614, 0.010102857 }, { 0.00075590283, 0.038624793, -0.0040614962, 0.070039437 }, { -0.02318411, 0.04527054, 0.013119286, 0.025335215 }, { 0.021268391, 0.044855911, 0.012622905, 0.04827088 }, { -0.0046678346, -0.01934799, 0.018393432, 0.09750434 }, { 0.12480373, 0.059151139, 0.055196092, 0.26701338 }, { -0.0096669036, 0.065624767, 0.016918517, 0.028425135 }, { 0.026488514, -0.0037618693, 0.0077028717, 0.041713399 }, { 0.018628451, 0.033145064, 0.029067918, -0.000924258 } }, { { -0.043525781, 0.028119778, -0.011653105, -0.020930158 }, { -0.028099186, 0.017594088, -0.099226445, 0.10408808 }, { 0.11750066, -0.0010629746, 0.018381448, 0.096538552 }, { 0.0010069446, 0.013799541, 0.1325137, 0.020820734 }, { -0.053571928, -0.0066793785, 0.14596488, -0.03272949 }, { 0.028507895, 0.015474376, -0.025411653, 0.037264272 }, { 0.033698911, 0.018088387, 0.0038898537, 0.03163178 }, { 0.0057766828, 0.015879322, 0.012557033, 0.071771631 }, { -0.0044521866, 0.0083963511, -0.0020426175, 0.023784146 }, { -0.011508765, 0.0075020051, 0.0018808294, 0.040843424 }, { 0.0085150894, 0.0056891711, 0.010134672, 0.046224768 }, { 0.040825446, 0.10099754, 0.021853299, 0.024507528 }, { -0.0055958303, -0.0060958, 0.1115321, -0.021701014 }, { 0.010487817, -0.010033143, -0.031203025, 0.054265436 }, { 0.0040500672, 0.0053935875, 0.018233022, 0.018797311 }, { 0.064057639, 0.014318185, 0.0199119, 0.014366235 }, { 0.02411682, 0.045454692, 0.0030084434, 0.019464939 }, { 0.012500289, 0.027734846, 0.0025097372, 0.047343669 }, { 0.037625829, -0.00064472688, 0.0557556, 0.04785655 }, { 0.0020433437, 0.019929208, 0.087936103, -0.036738471 }, { 0.020811556, 0.0915387, 0.055445303, -0.065132763 }, { 0.03911814, 0.043721622, 0.0074336204, -0.031370424 }, { 0.014072509, -0.014795458, 0.010517063, 0.022409628 }, { -0.0054107234, 0.055313602, 0.053556404, 0.048574319 } } }, { { { 3.4224197, 3.3162336, 3.1136621, 3.3189801 }, { 4.0715355, 3.5614196, 4.1797877, 4.0959601 }, { 4.3979407, 4.1858272, 4.3116447, 4.5467451 }, { 4.4920032, 4.0716439, 4.6107962, 4.5268016 }, { 5.6570832, 4.9036495, 4.7373547, 4.7259419 }, { 3.3277827, 3.6015237, 4.226646, 3.7939772 }, { 3.4893058, 3.3260638, 3.0626103, 3.1798705 }, { 3.6423735, 4.1092281, 3.3264203, 3.7325301 }, { 3.4756581, 3.2550256, 3.224671, 3.4093307 }, { 3.8511362, 3.4821381, 4.3232597, 3.7357164 }, { 3.6688024, 4.0797971, 3.4140927, 3.6881261 }, { 4.5298469, 4.7472506, 4.4046473, 4.7279944 }, { 4.1614448, 4.1242955, 4.6741969, 5.0037875 }, { 4.3148703, 4.3815566, 4.1976536, 3.9032858 }, { 3.2640506, 3.3214728, 2.9463564, 3.3562068 }, { 3.6729325, 3.9218642, 3.4550701, 3.4833871 }, { 3.435975, 3.3079446, 3.3432341, 3.3632985 }, { 3.8404619, 3.4716915, 3.858149, 3.8677391 }, { 3.3181827, 3.8403872, 4.0363918, 3.9604287 }, { 5.0916792, 5.2773748, 4.5404255, 4.377031 }, { 4.6514614, 4.7569957, 4.1233238, 4.4022582 }, { 3.6884833, 3.6283543, 4.1874612, 4.2963913 }, { 3.456705, 3.6250566, 3.5292789, 3.1420033 }, { 3.5986317, 4.0596074, 4.0696874, 4.5327067 } }, { { -0.12592901, -0.14780788, -0.11051274, -0.18767653 }, { -0.020435093, 0.0055221209, -0.021183195, -0.15159792 }, { 0.022498629, -0.025100789, -0.30939177, 0.016420202 }, { 0.21296442, -0.042976575, 0.082118132, 0.14574735 }, { -0.13608022, 0.16141834, -0.015091164, 0.044951541 }, { -0.08235774, -0.10333151, 0.089785432, -0.036620639 }, { -0.17664465, -0.015842477, -0.083075331, -0.15660828 }, { -0.11292423, -0.072894494, -0.068901923, -0.2283674 }, { -0.19063437, -0.071954393, 0.091375283, -0.26993547 }, { 0.042798331, -0.06495575, 0.050221766, 0.024602586 }, { -0.026228614, 0.0049810367, 0.046584088, -0.13067577 }, { 0.072779737, -0.023369437, -0.030275791, 0.19591126 }, { -0.018649072, 0.029208952, 0.012033439, 0.00094798196 }, { -0.094599446, 0.0070746366, -0.0007115864, -0.040175552 }, { -0.027599009, -0.068747365, 0.19480498, -0.19423733 }, { -0.076671551, 0.0075475135, 0.019853903, -0.012984601 }, { 0.064371855, -0.24044027, -0.043765356, 0.0016424127 }, { -0.076744435, 0.035881398, 0.12967612, 0.081825243 }, { -0.15224256, 0.032665115, -0.027927205, 0.076091133 }, { -0.0057973613, -0.14914213, -0.047678749, -0.037214457 }, { 0.10060085, -0.099197666, -0.22704457, -0.0020812401 }, { -0.070664558, -0.13179176, -0.014217065, -0.030410253 }, { -0.12286487, -0.046623366, -0.10695394, -0.0081383175 }, { -0.14561788, 0.02765909, 0.10439783, 0.033139041 } }, { { 0.0063171031, -0.0047223477, -0.056312039, -0.065065766 }, { -0.0059575982, -0.062348475, 0.069540315, -0.090331962 }, { 0.10218203, 0.050383376, -0.0089914697, -0.037837343 }, { -0.0037657879, 0.18278082, 0.079014627, -0.052587294 }, { -0.33929282, 0.018522098, 0.0078923893, 0.042545349 }, { 0.027294929, -0.086490439, -0.0057363347, -0.035932082 }, { -0.061716003, -0.14470599, 0.033117786, -0.08112808 }, { 0.16414856, 0.082471596, -0.058497326, 0.050552718 }, { -0.07627083, -0.0064181717, -0.031179581, -0.075705068 }, { -0.057808009, -0.00074561624, -0.23990956, 0.018671772 }, { 0.1677602, 0.10757253, 0.028015134, -0.23923178 }, { 0.078827365, 0.068682485, 0.056277532, -0.069749241 }, { 0.079502977, 0.05526585, 0.0089767144, -0.15319341 }, { -0.038594242, -0.055488998, -0.043132461, 0.054313031 }, { 0.12890592, -0.082639555, 0.22520491, -0.026781096 }, { -0.071292391, 0.064592881, -0.050368563, -0.072488866 }, { 0.092998671, 0.12152394, 0.033318795, -0.039691417 }, { -0.0049706273, -0.0014175115, -0.11634604, 0.15219284 }, { -0.012414906, 0.035583927, -0.072463074, -0.058394705 }, { -0.071558898, -0.00093653835, 0.013149622, 0.01495775 }, { -0.057103279, 0.013702583, -0.020242751, 0.04649072 }, { -0.083398977, -0.20123674, 0.062758815, -0.043671819 }, { 0.084479675, 0.17868517, -0.021185269, 0.15711776 }, { 0.11862504, 0.079985297, 0.063556911, 0.14639069 } } }, { { { 0.48018566, 0.17712962, 0.45065949, 0.76214707 }, { 0.37788335, 0.385421, 0.24766167, 0.3647243 }, { 0.45095873, 0.2634498, 0.37824131, 0.10713483 }, { 0.18808611, 0.27852978, 0.23671202, 0.23174978 }, { 0.39404781, -0.7399413, 0.28511918, 0.026007027 }, { 0.46587668, 0.46802177, 0.36697974, 0.23706778 }, { 0.48925391, 0.42086488, 0.49570155, 0.45137287 }, { 0.30655255, 0.35196398, 0.23019387, 0.50586011 }, { 0.45798975, 0.34137244, 0.33289763, 0.54218519 }, { 0.42271216, 0.38700914, 0.48791862, 0.15025833 }, { 0.7282781, 0.37956244, 0.25156645, 0.51632504 }, { 0.084933462, 0.15576738, 0.16469359, 0.29684651 }, { 0.34570877, 0.34912791, 0.26663435, 0.11188061 }, { 0.48552914, 0.19012867, 0.12677402, 0.1234341 }, { 0.2190939, 0.41431469, 0.64823269, 0.51846746 }, { 0.49289149, 0.29829354, 0.29090992, 0.36465152 }, { 0.50568056, 0.64150077, 0.40217634, 0.53523743 }, { 0.24945735, 0.47058801, 0.29099852, 0.25452114 }, { 0.49039753, 0.26327736, 0.39431507, 0.50632023 }, { 0.19678915, 0.031547614, 0.22295107, 0.26300048 }, { 0.12409997, 0.11506147, 0.19327618, 0.2174585 }, { 0.15319333, 0.39177705, 0.38498586, 0.25972804 }, { 0.69027161, 0.37279682, 0.31143504, 0.23440833 }, { 0.39682066, 0.3156927, 0.36369313, 0.14308402 } }, { { 0.15030994, 0.15410005, 0.0072554408, -0.22242826 }, { -0.032421729, 0.22531436, 0.22185899, -0.022703209 }, { 0.070341052, 0.30237173, 0.047916387, 0.03629681 }, { -0.024283222, 0.075614195, 0.013940033, -0.016841468 }, { 0.077729482, 0.19455394, -0.02162282, -0.018761003 }, { -0.22986895, 0.18914992, 0.14483608, 0.11173921 }, { 0.14132894, -0.0081864768, -0.11405791, 0.031777789 }, { 0.38775389, 0.0085565642, -0.057167843, 0.09784167 }, { 0.079102739, 0.030530894, 0.041954967, 0.02957611 }, { 0.076915126, 0.18656729, 0.044218872, 0.22478833 }, { 0.017173879, 0.11961351, -0.085099523, 0.22720323 }, { 0.030466202, 0.095221887, -0.042982583, -0.069264747 }, { 0.041170442, -0.090598444, -0.021082598, -0.028016784 }, { -0.082581617, -0.023712106, 0.32427665, 0.1010696 }, { 0.19197752, 0.10900527, -0.0053794951, 0.068553764 }, { 0.18674269, 0.028895321, -0.053421028, 0.063918058 }, { 0.044090722, -0.054247791, 0.05585954, -0.13406746 }, { 0.08358642, -0.032301886, 0.010371619, 0.099505528 }, { 0.16467816, 0.044994571, -0.0045949279, 0.0626774 }, { 0.12942209, 0.092097891, 0.019866495, 0.10340014 }, { 0.037094903, 0.13829877, 0.15116473, -0.048632499 }, { 0.10749044, 0.14329542, -0.061272024, -0.1536028 }, { 0.097716907, 0.044246181, 0.056664419, 0.15804873 }, { 0.031819999, 0.10132976, 0.079198524, 0.017871462 } }, { { 0.056219172, 0.08683492, -0.061488015, 0.065746152 }, { 0.088983664, 0.19773741, -0.096766599, 0.16352101 }, { -0.0097043787, -0.040925999, 0.097458334, 0.032319634 }, { -0.024873518, 0.057873123, -0.0059256291, -0.057498398 }, { -0.13355098, 0.39190863, 0.017449142, -0.0076009344 }, { 0.10319658, 0.22069551, -0.098795717, 0.10603434 }, { 0.090765308, 0.13803326, -0.070647945, 0.14557561 }, { -0.068457348, 0.058955208, -0.050501105, 0.02914144 }, { 0.10363866, 0.060231993, 0.027681685, 0.079659088 }, { 0.01269983, 0.11977996, -0.049648315, 0.089882363 }, { -0.072877286, 0.019348792, 0.13977764, 0.055396044 }, { 0.028834456, -0.1084196, -0.0043985215, -0.072640844 }, { -0.040232522, 0.051835989, -0.02198193, 0.016421295 }, { -0.087848469, -0.04621504, 0.099259188, -0.0025909067 }, { 0.3000131, 0.10526775, 0.016890366, 0.12892588 }, { -0.021028821, -0.024429075, 0.088067677, -0.084594075 }, { 0.086861805, -0.045902006, 0.0058222123, -0.0075466204 }, { 0.14411905, 0.036488937, 0.05091815, 0.16385101 }, { 0.1576814, 0.043890956, -0.064244298, -0.087234754 }, { -0.071100004, 0.16782304, -0.10860149, -0.1601076 }, { 0.032634641, -0.0025068263, -0.093802703, -0.076176546 }, { 0.1121451, 0.15584236, 0.070074778, 0.083736091 }, { 0.16981897, -0.078106227, 0.12480295, -0.0056807652 }, { -0.20300117, -0.017467249, 0.035504155, 0.056546123 } } } }, { { { { 0.014994926, 0.3118252, 0.12179235, -0.2013765 }, { -0.2622824, 0.28086607, 0.018805882, 0.72058929 }, { -0.0081002049, -0.28176506, -0.592214, -0.15032918 }, { 0.18913426, -0.24000825, 0.0020279072, -0.54749128 }, { 0.010237954, 0.76905205, 0.80173664, -0.016024595 }, { -0.53448318, 0.31204229, -0.16183732, 0.76857439 }, { -0.57639279, -0.63719194, -0.71354849, 0.56346054 }, { 0.49443258, 0.15067585, 0.31864726, -0.30570933 }, { -0.20756322, 0.2544828, -0.005298245, 0.0073796841 }, { -0.61822672, 0.21508574, 0.6362534, 0.30433278 }, { -0.0050327191, -0.278054, -0.3460806, 0.29967778 }, { 0.33983098, -0.11715664, -0.21761592, -0.068273894 }, { 0.5550354, 0.44369709, 0.64019993, -0.026032291 }, { -0.72587268, -0.33528197, -0.33592445, 0.53027141 }, { -0.47623191, -0.61767624, -0.61525655, 0.37823554 }, { 0.82869964, 0.219401, -0.018181789, -0.56937955 }, { -0.051792934, 0.3461701, 0.20915925, 0.078166496 }, { -0.26705611, 0.14439061, 0.0055054648, 0.463243 }, { -0.0019649711, -0.34119962, -0.29306531, -0.040223173 }, { 0.29285811, -0.32824753, -0.24768208, -0.29676955 }, { 0.87604898, 0.25374435, 0.2341931, -0.77851996 }, { -0.80404697, 0.011122158, 0.18899178, 0.55592668 }, { -0.78397618, -0.53690406, -0.59931185, 0.62348293 }, { 0.54613799, 0.080819658, 0.12590931, -0.60614071 } }, { { -0.12307869, -0.20242175, 0.21530167, -0.15608553 }, { 0.00052208688, 0.09998365, -0.067550225, -0.14009319 }, { 0.12621699, -0.089024022, 0.022656689, 0.18947331 }, { 0.34838897, -0.04936051, 0.25527451, -0.18942819 }, { 0.013210249, -0.043957685, -0.19088103, -0.034189573 }, { -0.0027790938, -0.026595097, 0.087083287, -0.12513839 }, { -0.038231564, 0.013328425, -0.0091503894, -0.005743873 }, { 0.17205702, -0.14956835, -0.0088915291, 0.18720588 }, { -0.049670195, 0.39532325, 0.080260299, 0.01811245 }, { 0.043555003, -0.30289197, -0.50878196, 0.27306166 }, { 0.02555972, -0.0068359476, 0.061097702, -0.43822038 }, { -0.10926471, 0.1870906, 0.12419548, 0.1245213 }, { -0.012443149, 0.040036941, 0.18601483, 0.02310445 }, { -0.10442982, 0.057455632, 0.13475314, -0.0019859122 }, { -0.068181593, -0.0033655904, 0.01922998, -0.020393828 }, { -0.10660626, 0.0020812455, 0.081209707, 0.077131932 }, { 0.088733212, -0.10430986, 0.45554817, -0.17113078 }, { 0.0046831409, 0.13247549, -0.1077727, 0.15382275 }, { 0.022346595, 0.022924261, -0.35016323, 0.2437608 }, { 0.029795657, 0.23046877, -0.020493651, -0.33214749 }, { -0.016101582, 0.042296203, 0.046779444, 0.037412394 }, { -0.02214903, -0.025218605, 0.14797485, -0.051723623 }, { 0.021321783, 0.010405115, 0.0075476201, 0.0082410917 }, { 0.040559796, 0.027927916, -0.012812736, -0.0096642379 } }, { { -0.055647079, 0.017595207, 0.34495838, -0.03055759 }, { -0.058415094, 0.027416036, 0.18568916, 0.13044498 }, { 0.01482217, -0.17300703, 0.027540135, -0.2744944 }, { 0.25558424, -0.15324455, -0.29751197, -0.11422984 }, { -0.068936732, -0.11425403, 0.094767025, -0.0020892558 }, { 0.040887892, 0.031622148, -0.095292456, -0.02460001 }, { -0.0026237665, 0.017734103, 0.01213911, 0.0056586962 }, { -0.052138375, 0.052245567, 0.04608449, -0.043004468 }, { -0.17693366, 0.0021023738, 0.13167397, -0.14062006 }, { -0.20900333, 0.0057695127, 0.13057243, 0.046715668 }, { -0.020569928, -0.08439655, -0.09683347, 0.038139385 }, { 0.18196242, 0.44461908, -0.11388512, -0.12413082 }, { 0.072801844, -0.0017236427, -0.0026756083, 0.049805114 }, { -0.092195952, -0.0076195172, -0.22763849, -0.11320887 }, { 0.016234922, 0.007258942, 0.078535592, -0.084829275 }, { -0.15320003, 0.057490618, -0.16065455, -0.17063675 }, { -0.012856124, 0.024818957, 0.097529739, 0.11569844 }, { -0.11141243, 0.26677735, 0.1319403, -0.15699502 }, { -0.021128161, -0.12370585, 0.056198856, -0.1836225 }, { -0.01871806, 0.025525037, 0.063822152, 0.066517944 }, { -0.013759301, 0.11401068, -0.04701374, -0.021321516 }, { 0.032714649, -3.161284e-06, 0.026930697, 0.00019593482 }, { 0.10575127, 0.016956425, 0.016873291, 0.0049304377 }, { -0.11938883, 0.31242334, 0.29347156, -0.19514533 } } }, { { { -0.17374661, -0.028781395, -0.25993234, 0.27242277 }, { -0.13675759, -0.62291002, -0.80742781, 0.54260546 }, { 0.16876581, -0.052588487, 0.22415557, -0.59669887 }, { 0.1769234, 0.64210979, 0.81157479, -0.2718564 }, { -0.99873125, -0.013258174, 0.58939675, 0.99930085 }, { -0.30883355, -0.71116337, -0.76218623, 0.096388818 }, { 0.65749012, -0.54533843, -0.57508599, -0.70359398 }, { -0.27406769, 0.61006308, 0.1873512, 0.2563151 }, { -0.78453523, -0.13585943, -0.048534939, 0.02085237 }, { 0.40938527, -0.76981396, -0.42506866, 0.22362984 }, { 0.29003079, -0.20624421, 0.1151133, -0.50558933 }, { 0.0070051806, 0.20763719, 0.59485798, -0.61562639 }, { -0.4371111, 0.48314196, 0.72981069, 0.99889301 }, { 0.58257878, -0.8603979, -0.94188892, -0.83140889 }, { 0.71858167, -0.49534538, -0.63421799, -0.84488463 }, { 0.016158248, 0.65330502, 0.82883727, -0.127372 }, { -0.50292264, -0.14848746, -0.20836533, 0.2471481 }, { -0.15815031, -0.63472031, -0.79826416, 0.15325573 }, { -0.010424343, -0.022843894, 0.099730136, -0.26040744 }, { 0.15069433, 0.31188588, 0.63836617, -0.25234477 }, { -0.36946506, 0.92093529, 0.96548808, 0.62354203 }, { -0.57070465, -0.99847512, -0.47855156, -0.079970605 }, { 0.077467525, -0.71134336, -0.67172579, -0.66364974 }, { -0.27299386, 0.89512951, 0.61598356, 0.49577277 } }, { { 0.070458859, -0.28774455, 0.21287043, -0.094689772 }, { 0.0029548085, -0.31404605, -0.039280892, -0.3652277 }, { -0.033729607, 0.041215792, 0.065844258, -0.21509418 }, { 0.39270582, 0.067526811, 0.15655351, 0.053346856 }, { 0.052704394, -0.087801294, 0.18655104, 0.056114808 }, { -0.074582751, -0.055177669, -0.22165519, 0.13272162 }, { -0.027850171, 0.0029849066, -0.0062314784, -0.010484316 }, { 0.20753796, -0.0087111988, -0.13875075, -0.06137521 }, { 0.089744421, 0.07271039, 0.099417029, -0.22157272 }, { -0.013209094, 0.048633419, -0.26528065, -0.15253703 }, { 0.052922007, 0.24859103, 0.14406684, 0.13857649 }, { 0.00096142813, 0.32643367, 0.17939549, -0.39761314 }, { 0.013505803, -0.036986517, -0.12729111, 0.15459921 }, { -0.00049722057, -0.047063275, -0.0018666598, 0.1067114 }, { -0.074221027, -0.00927958, -0.029535811, -0.024240068 }, { -0.12387933, 0.06626829, 0.16422781, 0.077740779 }, { 0.14560404, -0.082132455, 0.027268021, 0.18857832 }, { 0.10470732, -0.29519533, -0.23666419, 0.10917064 }, { 0.042550279, 0.02436036, -0.31865644, -0.024987356 }, { -0.030434576, 0.082115299, 0.17770796, 0.020944092 }, { -0.17365377, 0.13807361, 0.12476029, 0.072738061 }, { -0.11503962, -0.04022554, 0.028018434, -0.070211356 }, { -0.043677907, 0.0053361863, 0.0039019898, 0.0027489647 }, { 0.27060899, -0.0016552279, 0.14166067, -0.25461265 } }, { { 0.014703402, 0.094752279, -0.32162049, 0.082335322 }, { -0.31539882, 0.44394592, 0.44316202, -0.031456167 }, { -0.024148679, 0.082370612, -0.0031744796, 0.098610537 }, { 0.46130367, -0.19989896, -0.56118891, 0.11979937 }, { 0.11784636, 0.079971516, -0.16977121, 0.014922099 }, { 0.018367216, -0.076519762, 0.13801492, 0.039682415 }, { -0.0027614728, 0.0010389006, -0.023126227, 0.0027068473 }, { 0.22249856, -0.071302328, 0.23721977, 0.10734273 }, { 0.41478408, -0.36611101, 0.18031261, -0.11176768 }, { 0.15800457, 0.23829725, -0.0016193556, 0.2112867 }, { -0.14793833, -0.15378785, 0.0082778301, 0.27105519 }, { -0.064743588, 0.44794816, -0.12599819, 0.4310022 }, { 0.092725214, 0.033947737, 0.19969884, 0.0072363359 }, { -0.074190657, 0.005985921, 0.300818, -0.090919095 }, { 0.024238118, -0.010955859, -0.068086841, -0.021137349 }, { 0.12196721, -0.19977338, -0.64428422, -0.30808722 }, { 0.46567096, -0.042072501, -0.1778338, 0.34294059 }, { -0.32528695, 0.25699981, 0.49346557, -0.20743316 }, { 0.10422458, 0.049488574, 0.49098274, -0.34871439 }, { 0.16431875, -0.050748897, -0.18464312, -0.61695364 }, { -0.1753479, 0.033238479, -0.046267845, -0.012339883 }, { -0.16098841, 0.080519992, -0.11793031, 0.036790025 }, { 0.017193144, -0.0029212372, -0.0044153187, -0.0057094316 }, { 0.23481771, -0.1556448, -0.18775429, -0.013697353 } } }, { { { 0.98467622, 0.94970347, 0.95791534, 0.9408684 }, { 0.95525144, 0.73013516, 0.58966657, 0.43166004 }, { 0.98562289, 0.95804118, 0.77397471, 0.78825859 }, { 0.96588112, 0.72807352, 0.58424502, 0.79142113 }, { -0.049305848, 0.63904864, 0.099145551, -0.03377918 }, { 0.78673348, 0.62998117, 0.62680207, 0.63245759 }, { 0.48526085, 0.544603, 0.40015579, 0.43297544 }, { 0.82487776, 0.77789448, 0.92917353, 0.91697567 }, { 0.58431326, 0.95748667, 0.99880743, 0.99975533 }, { 0.67096902, 0.60093643, 0.64381538, 0.92594344 }, { 0.95700408, 0.93816272, 0.93111608, 0.80905665 }, { 0.94046044, 0.97116483, 0.77381347, 0.78507504 }, { 0.7077214, 0.7547892, 0.23983411, -0.039180128 }, { 0.3656649, 0.38379871, -0.00015338393, 0.16604667 }, { 0.50679735, 0.6108265, 0.46821675, 0.37829596 }, { 0.55946029, 0.72460731, 0.55919425, 0.81214734 }, { 0.86277825, 0.92634645, 0.95542467, 0.96581976 }, { 0.95061533, 0.75913205, 0.60228234, 0.87287949 }, { 0.99994373, 0.93971324, 0.95087677, 0.96466059 }, { 0.9442062, 0.89161694, 0.72879505, 0.92100486 }, { 0.30989313, 0.29579046, 0.11395771, 0.071428407 }, { 0.16674735, -0.054071458, 0.85747916, 0.82737551 }, { 0.61593841, 0.45356879, 0.43544204, 0.41332561 }, { 0.79196443, 0.43841915, 0.77763172, 0.62193473 } }, { { 0.028699614, 0.071974788, -0.028868668, 0.030119772 }, { -0.16988515, -0.35713152, 0.36877151, 0.37172103 }, { 0.024472009, 0.10373643, 0.052160621, -0.12998364 }, { 0.051999909, -0.1688679, 0.05813266, -0.11063347 }, { 0.026373007, 0.067310776, 0.34433164, 0.0017481699 }, { -0.017659611, -0.10215276, -0.23736187, 0.12678732 }, { -0.0019097928, 0.02067204, -0.030447136, -0.0093192388 }, { 0.10615435, 0.11124023, 0.04473958, 0.14369936 }, { 0.14791062, -0.034502091, 0.041456555, 0.06737059 }, { 0.22389399, 0.2668048, 0.25742349, 0.03724758 }, { 0.0046009946, 0.066632032, 0.097957775, 0.22969631 }, { 0.043253167, -0.013638494, 0.071328387, -0.19249903 }, { -0.023561087, 0.011490741, 0.19824644, -0.04133258 }, { -0.057507532, -0.039265903, 0.060469313, 0.37300659 }, { 0.027051207, -0.0086784396, -0.0055877341, -0.0315352 }, { 0.15724931, 0.0099485187, 0.22462997, 0.14112999 }, { 0.13909905, 0.026199511, -0.12430815, -0.076900423 }, { -0.022327596, -0.1975812, 0.49862652, -0.096026553 }, { 0.076782007, 0.041598482, 0.0033451155, 0.039947963 }, { 0.005353589, 0.070993946, 0.0068174778, -0.17805261 }, { -0.059912765, -0.17027417, -0.060069718, 0.1561139 }, { 0.017122435, 0.048532637, -0.05315926, 0.066962855 }, { 0.058014377, 0.021874362, 0.017248667, -0.0069413843 }, { 0.099274028, 0.040622241, 0.040435904, 0.14191123 } }, { { -0.13453832, 0.071519908, -0.1597656, -0.030758273 }, { -0.13511715, 0.32373425, 0.35851035, -0.18685481 }, { 0.021440457, 0.034442875, 0.14324368, 0.15754565 }, { -0.061440371, 0.16837735, 0.47887644, -0.036265812 }, { 0.55060811, 0.14095672, 0.13077418, 0.25515565 }, { -0.084599968, -0.084002143, 0.1542308, 0.044223437 }, { 0.0017727822, 0.025149715, -0.025479364, -0.0023658361 }, { 0.1619123, 0.069159159, -0.016343512, 0.026108175 }, { 0.3296525, 0.029456656, 0.039715069, 0.015958704 }, { -0.093419591, 0.37051381, -0.063182977, -0.017764112 }, { 0.11962535, 0.062511772, -0.070445145, 0.27768911 }, { 0.07458833, -0.16218828, 0.064111239, 0.43889373 }, { -0.0326486, -0.03666828, -0.17597139, 0.34213144 }, { 0.061334301, -0.0099525239, 0.21497301, 0.0074569296 }, { -0.016749445, 0.00054557189, 0.040331287, 0.066200794 }, { 0.20620866, 0.25268529, 0.46594276, 0.059651923 }, { 0.15170896, 0.041438057, 0.021708506, -0.15049245 }, { -0.14317538, 0.13548996, 0.37297491, 0.13718874 }, { 0.053339004, 0.015014013, -0.10418356, -0.13598877 }, { -0.02227412, 0.045548464, 0.21534467, -0.23828118 }, { -0.055326885, 0.11851609, 0.28938409, 0.041373996 }, { -0.1219532, 0.57338554, -0.094571555, 0.025008596 }, { 0.070380772, 0.016993506, 0.018073937, -0.015404818 }, { 0.17033841, 0.12449473, 0.10847869, -0.11141982 } } }, { { { 4.409738, 4.5071479, 5.4761817, 5.3214091 }, { 5.3741435, 4.6270256, 5.4786338, 5.323679 }, { 4.305776, 4.4890731, 4.6894257, 4.6068436 }, { 5.4930574, 4.9116386, 5.4097636, 4.9225404 }, { 5.1861828, 5.5144226, 5.1307797, 5.0804212 }, { 6.1194597, 6.0655136, 5.7369562, 6.1076578 }, { 6.9549598, 6.9281578, 6.9549598, 6.9549598 }, { 4.5030565, 4.5849566, 4.4830953, 4.4904323 }, { 5.3629211, 5.5524848, 4.5719135, 4.9103175 }, { 4.8906163, 5.3972226, 4.8806206, 5.1834202 }, { 4.5047396, 4.5984947, 4.7039612, 4.3422371 }, { 4.5956963, 5.6294962, 4.46025, 4.4827131 }, { 5.8454206, 6.000743, 5.4594428, 4.9952614 }, { 6.09642, 6.3979283, 4.9784963, 5.6878449 }, { 6.9549598, 6.9752898, 6.9549598, 6.9549598 }, { 6.2053562, 4.9984547, 5.3887395, 4.6221036 }, { 4.5265196, 4.3684629, 5.5819288, 5.4957366 }, { 5.2220057, 4.6118907, 5.5046208, 4.9190037 }, { 4.3408178, 4.4980303, 5.4937404, 5.6154153 }, { 4.4802186, 4.4666194, 4.8546878, 5.1764252 }, { 5.7384024, 5.9048089, 5.4636107, 5.0807017 }, { 5.1013817, 5.2237041, 6.0338955, 5.8869417 }, { 6.9414339, 6.9549598, 6.9549598, 6.9549598 }, { 4.3368412, 4.9692663, 4.7090567, 4.9023075 } }, { { 0.0093525884, -0.33796029, -0.4366682, -0.18161326 }, { -0.34446047, 0.10854359, -0.61563912, -0.16514117 }, { 0.055849315, 0.093045585, 0.36722184, 0.085665647 }, { -0.21881508, -0.036846235, -0.25226403, -0.012790033 }, { -0.14697546, -0.026656628, 0.2559775, 0.026279081 }, { 0.073189287, -0.074472165, -0.15439557, 0.020907645 }, { 0, -0.015078298, 0, 0 }, { 0.027540893, -0.30876053, -0.15680794, -0.18470107 }, { -0.072547269, -0.019227086, -0.26735769, -0.1362069 }, { 0.36907279, -0.28005156, 0.01966203, -0.10277819 }, { -0.26755862, 0.066747173, 0.60834173, -0.23356165 }, { -0.12357338, -0.41742338, 0.081840746, -0.14596222 }, { -0.068599762, -0.004402392, -0.17192993, -0.15797464 }, { -0.072923207, -0.02555551, -0.21075071, 0.047272919 }, { 0, 0.0115085, 0, 0 }, { 0.32527558, 0.066048741, -0.28639187, 0.45171914 }, { -0.158086, -0.049098981, -0.17226122, -0.50289857 }, { -0.39456648, 0.031970902, -0.74883626, 0.20536003 }, { 0.22864705, -0.0095988927, -0.1155595, -0.06240073 }, { 0.12336497, -0.34128076, 0.34341316, 0.083678547 }, { -0.032718317, 0.076359349, -0.30099369, -0.016865529 }, { -0.23491753, -0.17228011, -0.044893186, -0.057411459 }, { -0.0077848677, 0, 0, 0 }, { -0.18713605, -0.11612415, 0.30907006, 0.064707406 } }, { { -0.20768494, -0.15642062, -0.079474216, -0.020948121 }, { -0.18767308, -0.013722599, 0.15827086, -0.27421942 }, { -0.11484158, -0.29325715, 0.24426149, 0.34598577 }, { -0.095599056, 0.16784413, 0.23369965, 0.15036114 }, { 0.058496274, -0.064565923, -0.076598803, -0.11988702 }, { -0.03406356, -0.010863931, -0.036116475, 0.0077051595 }, { 0, -0.015078298, 0, 0 }, { -0.21271534, 0.31678528, 0.084310434, -0.039787477 }, { 0.057420352, -0.60894321, -0.14275706, -0.29178151 }, { -0.21477227, 0.091254596, -0.053659362, -0.13299553 }, { -0.24972574, 0.22261101, -0.59415755, -0.13299464 }, { -0.406027, 0.15018847, 0.33281927, 0.28006105 }, { -0.033198856, 0.013081228, 0.0098634494, -0.18858267 }, { -0.16914457, -0.014917022, -0.15618156, 0.038961385 }, { 0, 0.0115085, 0, 0 }, { 0.047340338, -0.052961301, 0.30193278, 0.38564757 }, { -0.2009302, -0.15247105, -0.32333852, 0.22878398 }, { -0.22934017, 0.022888443, 0.30911154, -0.12420416 }, { 0.21191356, -0.33281926, -0.13523708, -0.038546557 }, { 0.28507859, -0.012777666, 0.16285544, -0.12612215 }, { -0.057034227, 0.01719448, -0.037892291, -0.13064036 }, { -0.075888865, 0.041589292, 0.0089100653, -0.10775402 }, { 0.0075560462, 0, 0, 0 }, { -0.18120766, 0.16485298, 0.58949587, 0.072313493 } } }, { { { 0.60381773, 0.64633179, 0.92301353, 0.23720177 }, { 1.1128727, 0.42172315, 1.6605811, 0.22066721 }, { 0.55829912, 0.7107351, 0.47437673, 0.53646626 }, { 0.75684406, 0.65607146, 1.5264507, 0.12817954 }, { -0.25070514, 0.30263175, -0.21070678, -0.2264813 }, { -0.24745858, -0.26801252, 0.2750925, 0.055035565 }, { -0.018769156, -0.066023008, 0.10111114, 0.0089232736 }, { 0.41152465, 0.52508091, 0.4161358, 0.39058287 }, { 0.90919582, 1.2448772, 0.61547497, 0.51303689 }, { 0.2973136, 1.2348603, 0.24154398, 0.76087607 }, { 0.23369317, 0.68368068, 0.81024353, 0.35451079 }, { 0.69272073, 0.47014545, 0.61401877, 0.43768641 }, { -0.44449894, -0.10123077, -0.19173956, -0.15811184 }, { -0.089717, -0.068601549, -0.16704813, -0.29761406 }, { 0.0055968308, -0.089855929, -0.087150641, 0.2244144 }, { 0.38902787, 0.62620686, 1.3314901, 0.26038797 }, { 0.16776511, 0.32722251, 0.71914611, 0.53556119 }, { 0.63106992, 0.46256454, 1.785895, 0.17339911 }, { 0.72516261, 0.44941094, 0.81174974, 0.61247129 }, { 0.56877815, 0.20989179, 0.7607991, 0.017998645 }, { 0.016372087, 0.26062407, -0.32771461, -0.075930098 }, { -0.11957223, -0.22579003, -0.42587945, -0.0015549589 }, { 0.0049992009, 0.053511694, 0.00053268274, 0.022778575 }, { 0.19356675, 0.5564623, 0.74981777, 0.28733119 } }, { { 0.017029304, 0.22690356, 0.25927682, -0.048136042 }, { 0.52936856, -0.26082526, 0.12568074, -0.046727529 }, { 0.08949554, -0.019090555, 0.31477592, -0.067513409 }, { 0.056302335, -0.011819435, -0.063621104, 0.27092306 }, { 0.053971592, -0.17913246, -0.14991651, -0.044263405 }, { 0.29037749, -0.040498369, -0.33600753, 0.16250066 }, { -0.067102844, -0.17843768, 0.033172168, 0.13638573 }, { 0.057127881, -0.044468822, 0.33005778, 0.34775491 }, { -0.14300931, 0.022121077, -0.045281831, -0.065216583 }, { 0.084931489, 0.06688461, 0.15758114, -0.091330485 }, { -0.014274888, 0.29139103, 0.089163749, -0.18005467 }, { -0.2191522, -0.1333803, -0.31948964, -0.28536602 }, { 0.20298891, -0.0031882515, -0.15749696, -0.014977715 }, { -0.14016857, -0.17278064, 0.01369474, 0.10971499 }, { 0.018219806, 0.080447764, 0.0056022696, -0.043028475 }, { -0.076556403, -0.13038184, -0.23788273, 0.5849635 }, { 0.1038427, 0.18199702, 0.35294355, -0.0023601311 }, { 0.22294845, -0.37427713, 0.2907529, 0.26234219 }, { 0.40809306, 0.12982813, 0.42857338, 0.14064303 }, { 0.4265028, 0.18710053, 0.15310514, 0.067551813 }, { -0.18986488, -0.029676062, -0.087045959, -0.14788626 }, { -0.07865478, 0.011558295, -0.018262356, 0.38992629 }, { 0.22297641, 0.072192947, 0.064119712, 0.12862555 }, { -0.069262467, -0.14990585, 0.31342655, -0.15002022 } }, { { 0.25288162, -0.096551539, 0.051695506, 0.20925392 }, { 0.23093904, 0.096712594, 0.19826434, 0.32530694 }, { 0.14114785, 0.071010138, -0.17642029, 0.092260082 }, { 0.39001648, -0.17666595, 0.088397252, 0.1462816 }, { 0.12484597, 0.066920676, -0.16116194, 0.21758387 }, { 0.15625272, -0.00043631439, -0.07868976, -0.19261141 }, { -0.0142415, 0.06356153, 0.026276923, -0.024546668 }, { 0.097089221, 0.085426402, 0.11936115, 0.012042542 }, { 0.52509109, -0.22465399, -0.11490612, 0.023562122 }, { -0.12418278, 0.11985465, 0.087804943, 0.25283464 }, { 0.10716753, -0.036426901, 0.2469409, -0.095816257 }, { -0.095364501, 0.14001518, -0.068636804, -0.082487255 }, { 0.074490355, 0.25323233, 0.17863748, 0.12482145 }, { -0.019616587, -0.0053326518, 0.047558858, 0.066104462 }, { 0.12647102, 0.25712368, 0.12306783, -0.050252261 }, { -0.13375041, 0.17825067, 0.026649645, -0.33338076 }, { 0.16384463, -0.022241979, 0.17817325, 0.6808721 }, { 0.42075944, -0.024292721, -0.11323318, 0.45027063 }, { -0.023953485, 0.25719992, 0.28680108, 0.33600529 }, { 0.013445546, 0.22504275, 0.17408162, 0.52860686 }, { -0.098839039, -0.27017244, 0.10293505, -0.012472685 }, { 0.074267375, -0.0056418849, 0.17632358, 0.21754089 }, { 0.1491061, 0.017927571, -0.0217757, -0.0039381966 }, { 0.067239102, -0.74624136, 0.12992555, -0.058866581 } } } }, { { { { 0.1270204, 0.7650174, 0.55252173, 0.05956498 }, { -0.36870832, 0.31227245, 0.52167466, 0.4282174 }, { -0.036761861, -0.5477415, -0.76091563, -0.37583127 }, { 0.17129434, -0.14281209, -0.40463148, -0.56367877 }, { 0.07429238, 0.45420144, 0.41919765, 0.019225986 }, { -0.44125436, -0.05567539, 0.080551064, 0.54444995 }, { -0.36600455, -0.55359309, -0.3290331, 0.33946169 }, { 0.65253747, 0.015186649, 0.0665303, -0.64649501 }, { 0.05392469, 0.54355001, 0.7539307, -0.41089455 }, { -0.29264863, 0.49684721, 0.39184208, 0.47737193 }, { 0.10885354, -0.80803227, -0.7443769, -0.3736688 }, { 0.1939378, -0.079590275, -0.42241709, -0.75536039 }, { 0.44776697, 0.44884546, 0.427965, 0.3297221 }, { -0.34595785, 0.27723463, 0.12245317, 0.43884357 }, { 0.18467758, -0.55582608, -0.99421464, -0.0096027817 }, { 0.6672057, -0.038103784, -0.048616141, -0.68508055 }, { -0.016615937, 0.62001729, 0.50530563, -0.22211425 }, { -0.16823123, 0.31934529, 0.47092187, 0.4884373 }, { 0.03194189, -0.5624624, -0.44688229, 0.223814 }, { 0.17828041, -0.080017082, -0.44239439, -0.46726625 }, { 0.19895649, 0.82568772, 0.47859751, 0.064443297 }, { -0.47464217, 0.011895223, 0.01123465, -0.010697203 }, { -0.17670677, -0.66931423, -0.5814681, -0.01325001 }, { 0.65193874, -0.010713062, -0.007915928, -0.65520853 } }, { { -0.01027431, -0.0019056004, 0.0020213958, 0.0064495753 }, { 0.0058416688, 0.0051314639, 0.021497114, 0.005870592 }, { -0.00035518612, -0.00087553938, -0.0029318969, 0.0087577986 }, { -0.0048770476, -0.015949665, -0.034816051, -0.006104917 }, { 0.0015371362, -0.0012591621, 0.01241148, 0.00096621463 }, { 0.0032416133, 0.021025709, 0.0036344622, 0.0015436078 }, { -0.0093946276, 0.0046564763, 0.028177476, -0.01022744 }, { 0.00014675555, 0.030031482, -0.0092302407, -0.001999398 }, { -0.049980321, 0.024752279, 0.016684689, -0.0045230976 }, { 0.0067493834, 0.014071508, 0.0079316435, 0.034593704 }, { 0.01971715, -0.0037227013, -0.013430278, -0.024257585 }, { -0.004342319, 0.024001878, -0.013356442, -0.022792018 }, { -0.0051709665, -0.017029547, 0.040567567, 0.0052520812 }, { 0.0090399102, 0.0079604733, 0.00018765016, -0.0092868977 }, { -0.020304032, 0.0056590257, -0.0045373063, -0.018653318 }, { -9.9636934e-05, 0.002001886, 0.0046843544, 0.0055608043 }, { 0.0018025744, -0.0025962216, 0.0068285574, -0.014851062 }, { 0.00041645221, 0.0054738242, 0.0076769026, -0.013419208 }, { 0.0038347099, -0.0042555066, -0.0066470075, 0.0039146778 }, { -0.009084153, 0.024461537, 0.0034578066, -0.0054827001 }, { 0.0033463477, 0.0045594748, 0.00037604935, -0.01571513 }, { -0.012589588, 0.029678359, -0.019924871, -0.004708459 }, { -0.0002642682, -0.0051057336, -0.0042867302, -0.00041141781 }, { -0.00086487068, -0.0025170841, 0.0030062196, -0.0030385417 } }, { { -0.01027431, -0.0019056004, 0.0020213958, 0.0064495753 }, { 0.0058416688, 0.0051314639, 0.021497114, 0.005870592 }, { -0.00035518612, -0.00087553938, -0.0029318969, 0.0087577986 }, { -0.0048770476, -0.015949665, -0.034816051, -0.006104917 }, { 0.0015371362, -0.0012591621, 0.01241148, 0.00096621463 }, { 0.0032416133, 0.021025709, 0.0036344622, 0.0015436078 }, { -0.0093946276, 0.0046564763, 0.028177476, -0.01022744 }, { 0.00014675555, 0.030031482, -0.0092302407, -0.001999398 }, { -0.049980321, 0.024752279, 0.016684689, -0.0045230976 }, { 0.0067493834, 0.014071508, 0.0079316435, 0.034593704 }, { 0.01971715, -0.0037227013, -0.013430278, -0.024257585 }, { -0.004342319, 0.024001878, -0.013356442, -0.022792018 }, { -0.0051709665, -0.017029547, 0.040567567, 0.0052520812 }, { 0.0090399102, 0.0079604733, 0.00018765016, -0.0092868977 }, { -0.020304032, 0.0056590257, -0.0045373063, -0.018653318 }, { -9.9636934e-05, 0.002001886, 0.0046843544, 0.0055608043 }, { 0.0018025744, -0.0025962216, 0.0068285574, -0.014851062 }, { 0.00041645221, 0.0054738242, 0.0076769026, -0.013419208 }, { 0.0038347099, -0.0042555066, -0.0066470075, 0.0039146778 }, { -0.009084153, 0.024461537, 0.0034578066, -0.0054827001 }, { 0.0033463477, 0.0045594748, 0.00037604935, -0.01571513 }, { -0.012589588, 0.029678359, -0.019924871, -0.004708459 }, { -0.0002642682, -0.0051057336, -0.0042867302, -0.00041141781 }, { -0.00086487068, -0.0025170841, 0.0030062196, -0.0030385417 } } }, { { { -0.68772793, 0.19029367, -0.17427646, 0.60300616 }, { -0.29980532, -0.22397537, -0.4071009, 0.36277983 }, { 0.75628069, -0.13426242, 0.13645381, -0.74653491 }, { 0.14891408, -0.13497977, 0.36807879, -0.39814386 }, { -0.20608987, -0.076497863, -0.19510375, 0.34604256 }, { -0.02421123, -0.4588774, -0.64965351, 0.083039161 }, { 0.51918764, -0.30614677, -0.25791921, -0.40837612 }, { 0.028860181, 0.63152733, 0.5876224, -0.033139773 }, { -0.63418144, 0.046874151, 0.24431924, 0.71662556 }, { -0.29088451, -0.21455586, -0.73980807, 0.65038559 }, { 0.78663226, 0.00020858525, 0.40361403, -0.75720144 }, { 0.1998276, 0.54590973, 0.1773378, -0.35464319 }, { -0.40236144, 0.31362578, -0.34406026, 0.38120073 }, { -0.27845549, -0.46862161, -0.47141499, 0.095899189 }, { 0.6004921, 0.28051621, -0.011378178, -0.98141078 }, { 0.032724674, 0.66798127, 0.66430425, -0.05209965 }, { -0.59603974, -0.083198329, 0.34616224, 0.42082916 }, { -0.14262632, -0.21418442, -0.37504914, 0.32676687 }, { 0.58204273, 0.0067537174, -0.35923481, -0.40792038 }, { 0.15607366, 0.17215007, 0.34414936, -0.33566945 }, { -0.44862333, 0.004919013, 0.0076768115, 0.41897935 }, { -0.022062848, -0.39695079, -0.0062786656, 0.042925103 }, { 0.65953535, -0.15521993, 0.011867978, -0.57721165 }, { 0.031305912, 0.65627006, 0.66779002, -0.029815636 } }, { { 0.011457792, -0.011774949, -0.012205337, 0.0048139052 }, { -0.024024566, 0.018313023, -0.023210623, -0.0046351547 }, { 0.0039133571, 0.0046801024, -0.020590099, -0.0018568631 }, { -0.015369931, -0.0092621276, -0.026149742, 0.0010335971 }, { 0.032555144, -0.01336897, -0.022733265, -0.027997469 }, { -0.028161537, -0.00073877629, -0.023989631, 0.0055660453 }, { -0.012966193, 0.003944376, 0.025685982, -0.0017458044 }, { 0.00015626641, -0.009524206, 0.0083025026, -0.00049753811 }, { -0.02358661, 0.006370149, 0.00087066462, -0.00054248544 }, { -0.0024571244, -0.023218369, -0.010895303, -0.0095647684 }, { 0.0069970393, -0.00093403301, -0.0081922371, -0.00026359768 }, { 0.0065921354, 0.028846533, -0.045676337, 0.006070217 }, { 0.0045248423, -0.0084676847, 0.028756195, 0.020612871 }, { 0.0037691244, -0.0069385161, -0.00029501448, -0.0017839033 }, { -0.0048675353, -0.011930456, 0.0044251285, -0.00016323616 }, { -0.0012291164, -0.0019575288, 0.0078250029, -0.0011151155 }, { 0.00503333, -0.0094538968, 0.0092375183, 0.018207648 }, { 0.0080615812, -0.0073583459, -0.0166794, 0.016416158 }, { 0.002192959, -0.01153759, -0.0048668362, -0.0071123281 }, { -0.010116143, -0.010224552, 0.010897731, 0.00093792816 }, { 0.017199359, -0.0087516179, 0.0021169251, -0.020946959 }, { -0.01570063, 0.020087246, 0.014492818, -0.016014018 }, { 0.0023484072, 0.0015070243, -0.00045616273, -0.001211882 }, { 0.0018090492, -0.0012261901, 0.0012809284, 0.00096488905 } }, { { 0.011457792, -0.011774949, -0.012205337, 0.0048139052 }, { -0.024024566, 0.018313023, -0.023210623, -0.0046351547 }, { 0.0039133571, 0.0046801024, -0.020590099, -0.0018568631 }, { -0.015369931, -0.0092621276, -0.026149742, 0.0010335971 }, { 0.032555144, -0.01336897, -0.022733265, -0.027997469 }, { -0.028161537, -0.00073877629, -0.023989631, 0.0055660453 }, { -0.012966193, 0.003944376, 0.025685982, -0.0017458044 }, { 0.00015626641, -0.009524206, 0.0083025026, -0.00049753811 }, { -0.02358661, 0.006370149, 0.00087066462, -0.00054248544 }, { -0.0024571244, -0.023218369, -0.010895303, -0.0095647684 }, { 0.0069970393, -0.00093403301, -0.0081922371, -0.00026359768 }, { 0.0065921354, 0.028846533, -0.045676337, 0.006070217 }, { 0.0045248423, -0.0084676847, 0.028756195, 0.020612871 }, { 0.0037691244, -0.0069385161, -0.00029501448, -0.0017839033 }, { -0.0048675353, -0.011930456, 0.0044251285, -0.00016323616 }, { -0.0012291164, -0.0019575288, 0.0078250029, -0.0011151155 }, { 0.00503333, -0.0094538968, 0.0092375183, 0.018207648 }, { 0.0080615812, -0.0073583459, -0.0166794, 0.016416158 }, { 0.002192959, -0.01153759, -0.0048668362, -0.0071123281 }, { -0.010116143, -0.010224552, 0.010897731, 0.00093792816 }, { 0.017199359, -0.0087516179, 0.0021169251, -0.020946959 }, { -0.01570063, 0.020087246, 0.014492818, -0.016014018 }, { 0.0023484072, 0.0015070243, -0.00045616273, -0.001211882 }, { 0.0018090492, -0.0012261901, 0.0012809284, 0.00096488905 } } }, { { { 0.71476997, 0.61525336, 0.81507512, 0.79550964 }, { 0.87986984, 0.9232123, 0.74974956, 0.82765975 }, { 0.65321366, 0.82580437, 0.63434042, 0.54903231 }, { 0.97390084, 0.98050251, 0.83713283, 0.72370416 }, { 0.97570877, 0.88760866, 0.88668363, 0.9380218 }, { 0.89705541, 0.88675351, 0.75595095, 0.83467284 }, { 0.77232433, 0.77447327, 0.9084134, 0.84734569 }, { -0.75720667, -0.77520488, -0.80639546, -0.76219811 }, { 0.77130152, 0.83806694, 0.60983327, 0.56357207 }, { 0.91090229, 0.84089752, 0.54694041, 0.59085922 }, { 0.60775044, 0.58913818, 0.53197627, 0.53574024 }, { 0.96044628, 0.83405513, 0.88888419, 0.55105253 }, { 0.79850486, 0.83676557, 0.83574428, 0.86369517 }, { 0.89597751, 0.83876978, 0.87336884, 0.8934314 }, { 0.77801249, 0.78253947, 0.10680725, 0.19167855 }, { -0.74415432, -0.74320194, -0.74587957, -0.72660186 }, { 0.802783, 0.78016447, 0.79046691, 0.87952719 }, { 0.97537479, 0.92311625, 0.79848027, 0.80910594 }, { 0.8125306, 0.82679528, 0.81929639, 0.88516002 }, { 0.97152309, 0.98181547, 0.82815966, 0.81791703 }, { 0.87129411, 0.56410602, 0.87800085, 0.905706 }, { 0.87990229, 0.91776281, 0.99991718, 0.99902102 }, { 0.73060786, 0.72658464, 0.81348263, 0.81648708 }, { -0.75762512, -0.75445002, -0.74430762, -0.75485946 } }, { { 0.018332644, 0.0084005452, -0.0018937689, -0.0035491975 }, { 0.0016556654, 0.0049261013, -0.021796869, 0.0025973591 }, { -0.0019671758, 0.00051947074, 0.0071261223, 0.0056689139 }, { 0.00041901024, -0.0023903288, -0.0035639711, -0.0036673013 }, { 0.009963464, 0.00099195429, -0.0042516892, 0.0092605531 }, { 0.0034813664, 0.0028575465, -0.016343415, -0.0014475905 }, { 0.0053571039, 0.0051116063, 0.016171091, -0.00052744238 }, { 0.00013272575, -0.0095491849, 0.0070156475, 0.0017057538 }, { 0.028067438, -0.0086835729, -0.0087852674, 0.0035321054 }, { 0.0025007808, -0.0075654884, -0.012551417, -0.0068823899 }, { -0.00017607308, 0.002636122, -0.011272055, -0.010314896 }, { 0.010646599, 0.00042804331, 0.013900837, -0.01279076 }, { 0.0059898286, 0.012331371, -0.0073125296, 0.016248603 }, { 0.031579315, -0.0057840222, -0.00018304192, 0.005171422 }, { 0.010928513, 0.0092660887, 0.030404621, 0.0053167707 }, { -0.00014899672, -0.0035246494, 0.0075862845, -0.005861723 }, { 0.0067791918, 0.0021224495, -0.0071755505, -0.010370936 }, { 0.0015352958, -0.0025785166, -0.0092688001, 0.003966373 }, { 0.0036915074, -0.002306452, -0.005736452, -0.0033594125 }, { 0.0065128512, 0.006188005, 0.00088322638, -0.0016227066 }, { 0.0092720771, -0.0046684631, -7.3769604e-05, 0.013807013 }, { -0.0031421984, 0.010622679, 0.00041591214, 0.0032786075 }, { -0.0021421613, -0.0041675589, -0.0029529994, -0.00085350449 }, { -0.00069204344, -0.0010785124, 0.00097549628, 0.0025280456 } }, { { 0.018332644, 0.0084005452, -0.0018937689, -0.0035491975 }, { 0.0016556654, 0.0049261013, -0.021796869, 0.0025973591 }, { -0.0019671758, 0.00051947074, 0.0071261223, 0.0056689139 }, { 0.00041901024, -0.0023903288, -0.0035639711, -0.0036673013 }, { 0.009963464, 0.00099195429, -0.0042516892, 0.0092605531 }, { 0.0034813664, 0.0028575465, -0.016343415, -0.0014475905 }, { 0.0053571039, 0.0051116063, 0.016171091, -0.00052744238 }, { 0.00013272575, -0.0095491849, 0.0070156475, 0.0017057538 }, { 0.028067438, -0.0086835729, -0.0087852674, 0.0035321054 }, { 0.0025007808, -0.0075654884, -0.012551417, -0.0068823899 }, { -0.00017607308, 0.002636122, -0.011272055, -0.010314896 }, { 0.010646599, 0.00042804331, 0.013900837, -0.01279076 }, { 0.0059898286, 0.012331371, -0.0073125296, 0.016248603 }, { 0.031579315, -0.0057840222, -0.00018304192, 0.005171422 }, { 0.010928513, 0.0092660887, 0.030404621, 0.0053167707 }, { -0.00014899672, -0.0035246494, 0.0075862845, -0.005861723 }, { 0.0067791918, 0.0021224495, -0.0071755505, -0.010370936 }, { 0.0015352958, -0.0025785166, -0.0092688001, 0.003966373 }, { 0.0036915074, -0.002306452, -0.005736452, -0.0033594125 }, { 0.0065128512, 0.006188005, 0.00088322638, -0.0016227066 }, { 0.0092720771, -0.0046684631, -7.3769604e-05, 0.013807013 }, { -0.0031421984, 0.010622679, 0.00041591214, 0.0032786075 }, { -0.0021421613, -0.0041675589, -0.0029529994, -0.00085350449 }, { -0.00069204344, -0.0010785124, 0.00097549628, 0.0025280456 } } }, { { { 5.3792285, 5.1960477, 5.5112916, 5.6615254 }, { 5.0489877, 5.2428834, 5.1752035, 5.1109826 }, { 5.5205204, 5.7511938, 5.0202917, 4.9168865 }, { 4.9522523, 4.8880256, 5.1015936, 5.2858816 }, { 5.7256502, 5.7919759, 5.645241, 5.6035708 }, { 6.4076931, 6.4822111, 6.2642633, 6.3925959 }, { 6.9797014, 6.981436, 7.0028674, 6.9976464 }, { -0.03290957, -0.03290957, -0.03290957, -0.03290957 }, { 5.4977854, 5.7684965, 5.3463095, 4.8810492 }, { 4.9869047, 5.4896416, 4.9647805, 4.884877 }, { 5.3141219, 5.3357788, 4.7695434, 4.8709631 }, { 5.2056063, 5.407802, 5.2123857, 4.9428208 }, { 6.2188218, 6.17756, 6.2751008, 6.3672109 }, { 6.9105856, 6.7986798, 6.5712335, 6.5907061 }, { 6.9797014, 6.9797014, 5.6859993, 5.5642483 }, { -0.032764603, -0.032764603, -0.032764603, -0.032764603 }, { 5.7724142, 6.0929556, 5.99581, 5.9265164 }, { 4.9363192, 4.9823732, 5.1732995, 5.2475265 }, { 5.8365191, 5.9972902, 5.9778441, 5.9270668 }, { 4.8706768, 5.0194503, 5.155585, 5.2188041 }, { 6.1569904, 6.0563989, 6.0989699, 6.2139837 }, { 5.8727399, 5.8948086, 5.5734095, 5.5536103 }, { 6.9797014, 6.9797014, 6.9797014, 6.9797014 }, { -0.032766769, -0.032766769, -0.032766769, -0.032766769 } }, { { 0.0011802354, -0.006546101, -0.02103972, 0.0008654047 }, { -0.015460534, 0.017874544, 0.0029121134, 0.023511773 }, { -0.040909245, 0.011927691, 0.011991588, 0.01677931 }, { -0.015633544, -0.0042321141, 0.026623034, 0.0080414514 }, { 0.012614382, 0.0065080145, 0.035716738, -0.0080665814 }, { -0.0057849744, -0.017478461, -0.031219642, 0.00016446523 }, { 0, 0.00032235028, 0, 0 }, { 0, 0, 0, 0 }, { -0.068586697, -0.024228236, -0.012857221, -0.039493706 }, { -0.018078201, -0.015140979, 0.00072119173, -0.051249859 }, { -0.054228277, 0.0097895101, 0.0019832646, -0.011715411 }, { -0.042326208, -0.010160072, 0.037088052, -0.031848667 }, { 0.00067130897, -0.013966717, -0.017268559, -0.0074614576 }, { 0.070515961, 0.012848107, -0.0008396517, 0.0049006506 }, { 0, 0, -0.063014256, -0.0085124986 }, { 0, 0, 0, 0 }, { -0.040302299, 0.0048936307, 0.0064406394, 0.0034044871 }, { -0.010453589, 0.0035820836, -0.017384391, -0.038199947 }, { -0.044968611, -0.0088322127, 0.020303819, 0.0058131005 }, { -0.0056838535, 0.010211409, -0.010999927, -0.027621859 }, { 0.0064753811, -0.0059341242, -0.014902755, 0.0082868118 }, { -0.0013222735, 0.0028492181, -0.023523273, -0.02576271 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, { { 0.0011802354, -0.006546101, -0.02103972, 0.00086540469 }, { -0.015460534, 0.017874544, 0.0029121134, 0.023511773 }, { -0.040909245, 0.011927691, 0.011991588, 0.01677931 }, { -0.015633544, -0.0042321141, 0.026623034, 0.0080414514 }, { 0.012614382, 0.0065080145, 0.035716738, -0.0080665814 }, { -0.0057849744, -0.017478461, -0.031219642, 0.00016446523 }, { 0, 0.00032235028, 0, 0 }, { 0, 0, 0, 0 }, { -0.068586697, -0.024228236, -0.012857221, -0.039493706 }, { -0.018078201, -0.015140979, 0.00072119173, -0.051249859 }, { -0.054228277, 0.0097895101, 0.0019832646, -0.011715411 }, { -0.042326208, -0.010160072, 0.037088052, -0.031848667 }, { 0.00067130897, -0.013966717, -0.017268559, -0.0074614576 }, { 0.070515961, 0.012848107, -0.0008396517, 0.0049006506 }, { 0, 0, -0.063014256, -0.0085124986 }, { 0, 0, 0, 0 }, { -0.040302299, 0.0048936307, 0.0064406394, 0.0034044871 }, { -0.010453589, 0.0035820836, -0.017384391, -0.038199947 }, { -0.044968611, -0.0088322127, 0.020303819, 0.0058131005 }, { -0.0056838535, 0.010211409, -0.010999927, -0.027621859 }, { 0.0064753811, -0.0059341242, -0.014902755, 0.0082868118 }, { -0.0013222735, 0.0028492181, -0.023523273, -0.02576271 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } } }, { { { 0.72189984, 0.22069996, 0.71952927, 0.77725949 }, { 0.4054405, 0.20582059, 0.2747016, 0.37612563 }, { 0.58887422, 0.27441131, 0.19468101, 0.21480554 }, { 0.46814145, 0.34317, 0.46068212, 0.13962064 }, { -0.18134132, -0.26668789, -0.60984999, -0.67879259 }, { -0.47870351, -0.34453227, 0.32494779, 0.10292971 }, { 0.087252967, 0.066950358, 0.31813819, 0.071094818 }, { -0.0031436256, 0.038245091, -0.0076651913, -0.015389479 }, { 1.2668531, 1.2894974, 0.40584018, 0.51755806 }, { 1.3207257, 1.3403747, 0.54924634, 0.40282713 }, { 0.78581828, 0.56379328, 0.27901993, 0.56429306 }, { 0.8748226, 1.0271253, 1.0085726, 0.3888545 }, { -0.22577636, -0.32895071, -0.2846317, -0.11679531 }, { 0.26477285, 0.3179447, -0.063393238, 0.024059773 }, { -0.15463395, -0.22721468, -0.20680404, -0.15700788 }, { 0.012107106, -0.0061245949, -0.024224367, 0.005040693 }, { 0.97943693, 0.64840429, 0.45106998, 0.40771935 }, { 0.49907853, 0.1562184, 0.34338458, 0.39710628 }, { 0.95047709, 0.53336107, 0.38318275, 0.44919148 }, { 0.41892697, 0.069965886, 0.45831656, 0.38821529 }, { -0.20216736, -0.43209441, -0.57684857, -0.40189427 }, { -0.63992377, -0.40683032, -0.59207903, -0.57251716 }, { -0.047117438, -0.1880015, -0.12265155, 0.00059988607 }, { -0.011836442, -0.010049497, -0.0026152072, 0.016137736 } }, { { 0.092068993, 0.0045466749, 0.0054574031, 0.02582156 }, { 0.022115456, -0.015664041, -0.022004653, 0.041431654 }, { 0.029951298, -0.0004408542, 0.0087496069, 0.017850027 }, { 0.029086373, 0.022116039, 0.044010315, 0.001644876 }, { 0.016256387, 0.0083249367, 0.019570849, -0.0021276222 }, { 0.0079070076, -0.024696939, 0.044311101, 0.023671132 }, { -0.0081796119, -0.0024995551, 0.033501743, -0.031958988 }, { 0.0065005403, -0.076642001, 0.015736477, 0.030966939 }, { 0.029110717, 0.039154477, -0.074376619, 0.025532063 }, { -0.10980761, 0.0038346834, 0.014449171, -0.030702653 }, { -0.00068350423, -0.037251569, -0.008409224, -0.026322878 }, { 0.035406012, 0.064176275, 0.031437854, -0.0344642 }, { 0.037145809, -0.024909212, 0.041030386, 0.035216105 }, { -0.093276646, -0.013904083, -0.019536023, -0.023834405 }, { 0.042751846, -0.03620164, 0.081115921, 0.018379967 }, { -0.023909625, 0.012833691, 0.048086442, -0.0097340268 }, { 0.039552712, -0.00026806514, 0.011646753, 0.0065939486 }, { 0.058985248, 0.020165701, 0.0076721521, 0.033274221 }, { 0.052889871, 0.0042520093, 0.016490396, 0.009287973 }, { 0.044305975, -0.0016263469, 0.041390177, 0.033541355 }, { 0.014595133, -0.004801042, -0.0049517302, 0.015714264 }, { 0.00075086205, 0.0080838736, -0.037611057, -0.030488441 }, { 0.0019178075, -0.0082517768, -0.002525773, 0.0043993022 }, { 0.023774971, 0.020335611, 0.0056643868, -0.032100338 } }, { { 0.092068993, 0.0045466749, 0.0054574031, 0.02582156 }, { 0.022115456, -0.015664041, -0.022004653, 0.041431654 }, { 0.029951298, -0.0004408542, 0.0087496069, 0.017850027 }, { 0.029086373, 0.022116039, 0.044010315, 0.001644876 }, { 0.016256387, 0.0083249367, 0.019570849, -0.0021276222 }, { 0.0079070076, -0.024696939, 0.044311101, 0.023671132 }, { -0.0081796119, -0.0024995551, 0.033501743, -0.031958988 }, { 0.0065005403, -0.076642001, 0.015736477, 0.030966939 }, { 0.029110717, 0.039154477, -0.074376619, 0.025532063 }, { -0.10980761, 0.0038346834, 0.014449171, -0.030702653 }, { -0.00068350423, -0.037251569, -0.008409224, -0.026322878 }, { 0.035406012, 0.064176275, 0.031437854, -0.0344642 }, { 0.037145809, -0.024909212, 0.041030386, 0.035216105 }, { -0.093276646, -0.013904083, -0.019536023, -0.023834405 }, { 0.042751846, -0.03620164, 0.081115921, 0.018379967 }, { -0.023909625, 0.012833691, 0.048086442, -0.0097340268 }, { 0.039552712, -0.00026806514, 0.011646753, 0.0065939486 }, { 0.058985248, 0.020165701, 0.0076721521, 0.033274221 }, { 0.052889871, 0.0042520093, 0.016490396, 0.009287973 }, { 0.044305975, -0.0016263469, 0.041390177, 0.033541355 }, { 0.014595133, -0.004801042, -0.0049517303, 0.015714264 }, { 0.00075086205, 0.0080838736, -0.037611057, -0.030488441 }, { 0.0019178075, -0.0082517768, -0.002525773, 0.0043993022 }, { 0.023774971, 0.020335611, 0.0056643868, -0.032100338 } } } } };
-
-#endif \ No newline at end of file
diff --git a/servers/visual/rasterizer_rd/light_cluster_builder.cpp b/servers/visual/rasterizer_rd/light_cluster_builder.cpp
deleted file mode 100644
index 943ef1c7fa..0000000000
--- a/servers/visual/rasterizer_rd/light_cluster_builder.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/*************************************************************************/
-/* light_cluster_builder.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "light_cluster_builder.h"
-
-void LightClusterBuilder::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection) {
- view_xform = p_view_transform;
- projection = p_cam_projection;
- z_near = -projection.get_z_near();
- z_far = -projection.get_z_far();
-
- //reset counts
- light_count = 0;
- refprobe_count = 0;
- item_count = 0;
- sort_id_count = 0;
-}
-
-void LightClusterBuilder::bake_cluster() {
-
- float slice_depth = (z_near - z_far) / depth;
-
- uint8_t *cluster_dataw = cluster_data.ptrw();
- Cell *cluster_data_ptr = (Cell *)cluster_dataw;
- //clear the cluster
- zeromem(cluster_data_ptr, (width * height * depth * sizeof(Cell)));
-
- /* Step 1, create cell positions and count them */
-
- for (uint32_t i = 0; i < item_count; i++) {
-
- const Item &item = items[i];
-
- int from_slice = Math::floor((z_near - (item.aabb.position.z + item.aabb.size.z)) / slice_depth);
- int to_slice = Math::floor((z_near - item.aabb.position.z) / slice_depth);
-
- if (from_slice >= (int)depth || to_slice < 0) {
- continue; //sorry no go
- }
-
- from_slice = MAX(0, from_slice);
- to_slice = MIN((int)depth - 1, to_slice);
-
- for (int j = from_slice; j <= to_slice; j++) {
-
- Vector3 min = item.aabb.position;
- Vector3 max = item.aabb.position + item.aabb.size;
-
- float limit_near = MIN((z_near - slice_depth * j), max.z);
- float limit_far = MAX((z_near - slice_depth * (j + 1)), min.z);
-
- max.z = limit_near;
- min.z = limit_near;
-
- Vector3 proj_min = projection.xform(min);
- Vector3 proj_max = projection.xform(max);
-
- int near_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width));
- int near_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height));
- int near_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width));
- int near_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height));
-
- max.z = limit_far;
- min.z = limit_far;
-
- proj_min = projection.xform(min);
- proj_max = projection.xform(max);
-
- int far_from_x = int(Math::floor((proj_min.x * 0.5 + 0.5) * width));
- int far_from_y = int(Math::floor((-proj_max.y * 0.5 + 0.5) * height));
- int far_to_x = int(Math::floor((proj_max.x * 0.5 + 0.5) * width));
- int far_to_y = int(Math::floor((-proj_min.y * 0.5 + 0.5) * height));
-
- //print_line(itos(j) + " near - " + Vector2i(near_from_x, near_from_y) + " -> " + Vector2i(near_to_x, near_to_y));
- //print_line(itos(j) + " far - " + Vector2i(far_from_x, far_from_y) + " -> " + Vector2i(far_to_x, far_to_y));
-
- int from_x = MIN(near_from_x, far_from_x);
- int from_y = MIN(near_from_y, far_from_y);
- int to_x = MAX(near_to_x, far_to_x);
- int to_y = MAX(near_to_y, far_to_y);
-
- if (from_x >= (int)width || to_x < 0 || from_y >= (int)height || to_y < 0) {
- continue;
- }
-
- int sx = MAX(0, from_x);
- int sy = MAX(0, from_y);
- int dx = MIN((int)width - 1, to_x);
- int dy = MIN((int)height - 1, to_y);
-
- //print_line(itos(j) + " - " + Vector2i(sx, sy) + " -> " + Vector2i(dx, dy));
-
- for (int x = sx; x <= dx; x++) {
- for (int y = sy; y <= dy; y++) {
- uint32_t offset = j * (width * height) + y * width + x;
-
- if (unlikely(sort_id_count == sort_id_max)) {
- sort_id_max = nearest_power_of_2_templated(sort_id_max + 1);
- sort_ids = (SortID *)memrealloc(sort_ids, sizeof(SortID) * sort_id_max);
- if (ids.size()) {
-
- ids.resize(sort_id_max);
- RD::get_singleton()->free(items_buffer);
- items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * sort_id_max);
- }
- }
-
- sort_ids[sort_id_count].cell_index = offset;
- sort_ids[sort_id_count].item_index = item.index;
- sort_ids[sort_id_count].item_type = item.type;
-
- sort_id_count++;
-
- //for now, only count
- cluster_data_ptr[offset].item_pointers[item.type]++;
- //print_line("at offset " + itos(offset) + " value: " + itos(cluster_data_ptr[offset].item_pointers[item.type]));
- }
- }
- }
- }
-
- /* Step 2, Assign pointers (and reset counters) */
-
- uint32_t offset = 0;
- for (uint32_t i = 0; i < (width * height * depth); i++) {
- for (int j = 0; j < ITEM_TYPE_MAX; j++) {
- uint32_t count = cluster_data_ptr[i].item_pointers[j]; //save count
- cluster_data_ptr[i].item_pointers[j] = offset; //replace count by pointer
- offset += count; //increase offset by count;
- }
- }
-
- //print_line("offset: " + itos(offset));
- /* Step 3, Place item lists */
-
- uint32_t *ids_ptr = ids.ptrw();
-
- for (uint32_t i = 0; i < sort_id_count; i++) {
- const SortID &id = sort_ids[i];
- Cell &cell = cluster_data_ptr[id.cell_index];
- uint32_t pointer = cell.item_pointers[id.item_type] & POINTER_MASK;
- uint32_t counter = cell.item_pointers[id.item_type] >> COUNTER_SHIFT;
- ids_ptr[pointer + counter] = id.item_index;
-
- cell.item_pointers[id.item_type] = pointer | ((counter + 1) << COUNTER_SHIFT);
- }
-
- RD::get_singleton()->texture_update(cluster_texture, 0, cluster_data, true);
- RD::get_singleton()->buffer_update(items_buffer, 0, offset * sizeof(uint32_t), ids_ptr, true);
-}
-
-void LightClusterBuilder::setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth) {
-
- if (width == p_width && height == p_height && depth == p_depth) {
- return;
- }
- if (cluster_texture.is_valid()) {
- RD::get_singleton()->free(cluster_texture);
- }
-
- width = p_width;
- height = p_height;
- depth = p_depth;
-
- cluster_data.resize(width * height * depth * sizeof(Cell));
-
- {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
- tf.type = RD::TEXTURE_TYPE_3D;
- tf.width = width;
- tf.height = height;
- tf.depth = depth;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
-
- cluster_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-}
-
-RID LightClusterBuilder::get_cluster_texture() const {
- return cluster_texture;
-}
-RID LightClusterBuilder::get_cluster_indices_buffer() const {
- return items_buffer;
-}
-
-LightClusterBuilder::LightClusterBuilder() {
- //initialize accumulators to something
- lights = (LightData *)memalloc(sizeof(LightData) * 1024);
- light_max = 1024;
-
- refprobes = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024);
- refprobe_max = 1024;
-
- decals = (OrientedBoxData *)memalloc(sizeof(OrientedBoxData) * 1024);
- decal_max = 1024;
-
- items = (Item *)memalloc(sizeof(Item) * 1024);
- item_max = 1024;
-
- sort_ids = (SortID *)memalloc(sizeof(SortID) * 1024);
- ids.resize(2014);
- items_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 1024);
- item_max = 1024;
-}
-LightClusterBuilder::~LightClusterBuilder() {
-
- if (cluster_data.size()) {
- RD::get_singleton()->free(cluster_texture);
- }
-
- if (lights) {
- memfree(lights);
- }
- if (refprobes) {
- memfree(refprobes);
- }
- if (decals) {
- memfree(decals);
- }
- if (items) {
- memfree(items);
- }
- if (sort_ids) {
- memfree(sort_ids);
- RD::get_singleton()->free(items_buffer);
- }
-}
diff --git a/servers/visual/rasterizer_rd/light_cluster_builder.h b/servers/visual/rasterizer_rd/light_cluster_builder.h
deleted file mode 100644
index 83014a7dd0..0000000000
--- a/servers/visual/rasterizer_rd/light_cluster_builder.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/*************************************************************************/
-/* light_cluster_builder.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 LIGHT_CLUSTER_BUILDER_H
-#define LIGHT_CLUSTER_BUILDER_H
-
-#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-
-class LightClusterBuilder {
-public:
- enum LightType {
- LIGHT_TYPE_OMNI,
- LIGHT_TYPE_SPOT
- };
-
- enum ItemType {
- ITEM_TYPE_OMNI_LIGHT,
- ITEM_TYPE_SPOT_LIGHT,
- ITEM_TYPE_REFLECTION_PROBE,
- ITEM_TYPE_DECAL,
- ITEM_TYPE_MAX //should always be 4
- };
-
- enum {
- COUNTER_SHIFT = 20, //one million total ids
- POINTER_MASK = (1 << COUNTER_SHIFT) - 1,
- COUNTER_MASK = 0xfff // 4096 items per cell
- };
-
-private:
- struct LightData {
- float position[3];
- uint32_t type;
- float radius;
- float spot_aperture;
- uint32_t pad[2];
- };
-
- uint32_t light_count = 0;
- uint32_t light_max = 0;
- LightData *lights = nullptr;
-
- struct OrientedBoxData {
- float position[3];
- uint32_t pad;
- float x_axis[3];
- uint32_t pad2;
- float y_axis[3];
- uint32_t pad3;
- float z_axis[3];
- uint32_t pad4;
- };
-
- uint32_t refprobe_count = 0;
- uint32_t refprobe_max = 0;
- OrientedBoxData *refprobes = nullptr;
-
- uint32_t decal_count = 0;
- uint32_t decal_max = 0;
- OrientedBoxData *decals = nullptr;
-
- struct Item {
- AABB aabb;
- ItemType type;
- uint32_t index;
- };
-
- Item *items = nullptr;
- uint32_t item_count = 0;
- uint32_t item_max = 0;
-
- uint32_t width = 0;
- uint32_t height = 0;
- uint32_t depth = 0;
-
- struct Cell {
- uint32_t item_pointers[ITEM_TYPE_MAX];
- };
-
- Vector<uint8_t> cluster_data;
- RID cluster_texture;
-
- struct SortID {
- uint32_t cell_index;
- uint32_t item_index;
- ItemType item_type;
- };
-
- SortID *sort_ids = nullptr;
- Vector<uint32_t> ids;
- uint32_t sort_id_count = 0;
- uint32_t sort_id_max = 0;
- RID items_buffer;
-
- Transform view_xform;
- CameraMatrix projection;
- float z_far = 0;
- float z_near = 0;
-
- _FORCE_INLINE_ void _add_item(const AABB &p_aabb, ItemType p_type, uint32_t p_index) {
- if (unlikely(item_count == item_max)) {
- item_max = nearest_power_of_2_templated(item_max + 1);
- items = (Item *)memrealloc(items, sizeof(Item) * item_max);
- }
-
- Item &item = items[item_count];
- item.aabb = p_aabb;
- item.index = p_index;
- item.type = p_type;
- item_count++;
- }
-
-public:
- void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection);
-
- _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) {
- if (unlikely(light_count == light_max)) {
- light_max = nearest_power_of_2_templated(light_max + 1);
- lights = (LightData *)memrealloc(lights, sizeof(LightData) * light_max);
- }
-
- LightData &ld = lights[light_count];
- ld.type = p_type;
- ld.position[0] = p_transform.origin.x;
- ld.position[1] = p_transform.origin.y;
- ld.position[2] = p_transform.origin.z;
- ld.radius = p_radius;
- ld.spot_aperture = p_spot_aperture;
-
- Transform xform = view_xform * p_transform;
-
- ld.radius *= xform.basis.get_uniform_scale();
-
- AABB aabb;
-
- switch (p_type) {
- case LIGHT_TYPE_OMNI: {
- aabb.position = xform.origin;
- aabb.size = Vector3(ld.radius, ld.radius, ld.radius);
- aabb.position -= aabb.size;
- aabb.size *= 2.0;
-
- _add_item(aabb, ITEM_TYPE_OMNI_LIGHT, light_count);
- } break;
- case LIGHT_TYPE_SPOT: {
- Vector3 v(0, 0, -1);
- v.rotated(Vector3(0, 1, 0), Math::deg2rad(ld.spot_aperture)); //rotate in x-z
- v.normalize();
- v *= ld.radius;
- v.y = v.x;
-
- aabb.position = xform.origin;
- aabb.expand_to(xform.xform(v));
- aabb.expand_to(xform.xform(Vector3(-v.x, v.y, v.z)));
- aabb.expand_to(xform.xform(Vector3(-v.x, -v.y, v.z)));
- aabb.expand_to(xform.xform(Vector3(v.x, -v.y, v.z)));
- _add_item(aabb, ITEM_TYPE_SPOT_LIGHT, light_count);
- } break;
- }
-
- light_count++;
- }
-
- _FORCE_INLINE_ void add_reflection_probe(const Transform &p_transform, const Vector3 &p_half_extents) {
-
- if (unlikely(refprobe_count == refprobe_max)) {
- refprobe_max = nearest_power_of_2_templated(refprobe_max + 1);
- refprobes = (OrientedBoxData *)memrealloc(refprobes, sizeof(OrientedBoxData) * refprobe_max);
- }
-
- OrientedBoxData &rp = refprobes[refprobe_count];
- Vector3 origin = p_transform.origin;
- rp.position[0] = origin.x;
- rp.position[1] = origin.y;
- rp.position[2] = origin.z;
-
- Vector3 x_axis = p_transform.basis.get_axis(0) * p_half_extents.x;
- rp.x_axis[0] = x_axis.x;
- rp.x_axis[1] = x_axis.y;
- rp.x_axis[2] = x_axis.z;
-
- Vector3 y_axis = p_transform.basis.get_axis(1) * p_half_extents.y;
- rp.y_axis[0] = y_axis.x;
- rp.y_axis[1] = y_axis.y;
- rp.y_axis[2] = y_axis.z;
-
- Vector3 z_axis = p_transform.basis.get_axis(2) * p_half_extents.z;
- rp.z_axis[0] = z_axis.x;
- rp.z_axis[1] = z_axis.y;
- rp.z_axis[2] = z_axis.z;
-
- AABB aabb;
-
- aabb.position = origin + x_axis + y_axis + z_axis;
- aabb.expand_to(origin + x_axis + y_axis - z_axis);
- aabb.expand_to(origin + x_axis - y_axis + z_axis);
- aabb.expand_to(origin + x_axis - y_axis - z_axis);
- aabb.expand_to(origin - x_axis + y_axis + z_axis);
- aabb.expand_to(origin - x_axis + y_axis - z_axis);
- aabb.expand_to(origin - x_axis - y_axis + z_axis);
- aabb.expand_to(origin - x_axis - y_axis - z_axis);
-
- _add_item(aabb, ITEM_TYPE_REFLECTION_PROBE, refprobe_count);
-
- refprobe_count++;
- }
-
- _FORCE_INLINE_ void add_decal(const Transform &p_transform, const Vector2 &p_half_extents, float p_depth) {
-
- if (unlikely(decal_count == decal_max)) {
- decal_max = nearest_power_of_2_templated(decal_max + 1);
- decals = (OrientedBoxData *)memrealloc(decals, sizeof(OrientedBoxData) * decal_max);
- }
-
- OrientedBoxData &dc = decals[decal_count];
-
- Vector3 z_axis = -p_transform.basis.get_axis(2) * p_depth * 0.5;
- dc.z_axis[0] = z_axis.x;
- dc.z_axis[1] = z_axis.y;
- dc.z_axis[2] = z_axis.z;
-
- Vector3 origin = p_transform.origin - z_axis;
- dc.position[0] = origin.x;
- dc.position[1] = origin.y;
- dc.position[2] = origin.z;
-
- Vector3 x_axis = p_transform.basis.get_axis(0) * p_half_extents.x;
- dc.x_axis[0] = x_axis.x;
- dc.x_axis[1] = x_axis.y;
- dc.x_axis[2] = x_axis.z;
-
- Vector3 y_axis = p_transform.basis.get_axis(1) * p_half_extents.y;
- dc.y_axis[0] = y_axis.x;
- dc.y_axis[1] = y_axis.y;
- dc.y_axis[2] = y_axis.z;
-
- AABB aabb;
-
- aabb.position = origin + x_axis + y_axis + z_axis;
- aabb.expand_to(origin + x_axis + y_axis - z_axis);
- aabb.expand_to(origin + x_axis - y_axis + z_axis);
- aabb.expand_to(origin + x_axis - y_axis - z_axis);
- aabb.expand_to(origin - x_axis + y_axis + z_axis);
- aabb.expand_to(origin - x_axis + y_axis - z_axis);
- aabb.expand_to(origin - x_axis - y_axis + z_axis);
- aabb.expand_to(origin - x_axis - y_axis - z_axis);
-
- _add_item(aabb, ITEM_TYPE_DECAL, decal_count);
-
- decal_count++;
- }
-
- void bake_cluster();
-
- void setup(uint32_t p_width, uint32_t p_height, uint32_t p_depth);
-
- RID get_cluster_texture() const;
- RID get_cluster_indices_buffer() const;
-
- LightClusterBuilder();
- ~LightClusterBuilder();
-};
-
-#endif // LIGHT_CLUSTER_BUILDER_H
diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
deleted file mode 100644
index 38b1e3b3a6..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp
+++ /dev/null
@@ -1,2558 +0,0 @@
-/*************************************************************************/
-/* rasterizer_canvas_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer_canvas_rd.h"
-#include "core/math/math_funcs.h"
-#include "core/project_settings.h"
-#include "rasterizer_rd.h"
-
-void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
-
- p_mat4[0] = p_transform.elements[0][0];
- p_mat4[1] = p_transform.elements[0][1];
- p_mat4[2] = 0;
- p_mat4[3] = 0;
- p_mat4[4] = p_transform.elements[1][0];
- p_mat4[5] = p_transform.elements[1][1];
- p_mat4[6] = 0;
- p_mat4[7] = 0;
- p_mat4[8] = 0;
- p_mat4[9] = 0;
- p_mat4[10] = 1;
- p_mat4[11] = 0;
- p_mat4[12] = p_transform.elements[2][0];
- p_mat4[13] = p_transform.elements[2][1];
- p_mat4[14] = 0;
- p_mat4[15] = 1;
-}
-
-void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) {
-
- p_mat2x4[0] = p_transform.elements[0][0];
- p_mat2x4[1] = p_transform.elements[1][0];
- p_mat2x4[2] = 0;
- p_mat2x4[3] = p_transform.elements[2][0];
-
- p_mat2x4[4] = p_transform.elements[0][1];
- p_mat2x4[5] = p_transform.elements[1][1];
- p_mat2x4[6] = 0;
- p_mat2x4[7] = p_transform.elements[2][1];
-}
-
-void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) {
-
- p_mat2x3[0] = p_transform.elements[0][0];
- p_mat2x3[1] = p_transform.elements[0][1];
- p_mat2x3[2] = p_transform.elements[1][0];
- p_mat2x3[3] = p_transform.elements[1][1];
- p_mat2x3[4] = p_transform.elements[2][0];
- p_mat2x3[5] = p_transform.elements[2][1];
-}
-
-void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) {
-
- p_mat4[0] = p_transform.basis.elements[0][0];
- p_mat4[1] = p_transform.basis.elements[1][0];
- p_mat4[2] = p_transform.basis.elements[2][0];
- p_mat4[3] = 0;
- p_mat4[4] = p_transform.basis.elements[0][1];
- p_mat4[5] = p_transform.basis.elements[1][1];
- p_mat4[6] = p_transform.basis.elements[2][1];
- p_mat4[7] = 0;
- p_mat4[8] = p_transform.basis.elements[0][2];
- p_mat4[9] = p_transform.basis.elements[1][2];
- p_mat4[10] = p_transform.basis.elements[2][2];
- p_mat4[11] = 0;
- p_mat4[12] = p_transform.origin.x;
- p_mat4[13] = p_transform.origin.y;
- p_mat4[14] = p_transform.origin.z;
- p_mat4[15] = 1;
-}
-
-void RasterizerCanvasRD::_update_specular_shininess(const Color &p_transform, uint32_t *r_ss) {
-
- *r_ss = uint32_t(CLAMP(p_transform.a * 255.0, 0, 255)) << 24;
- *r_ss |= uint32_t(CLAMP(p_transform.b * 255.0, 0, 255)) << 16;
- *r_ss |= uint32_t(CLAMP(p_transform.g * 255.0, 0, 255)) << 8;
- *r_ss |= uint32_t(CLAMP(p_transform.r * 255.0, 0, 255));
-}
-
-RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
-
- Vector<RD::Uniform> uniform_set;
-
- { // COLOR TEXTURE
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1;
- RID texture = storage->texture_get_rd_texture(p_texture);
- if (!texture.is_valid()) {
- //use default white texture
- texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
- }
- u.ids.push_back(texture);
- uniform_set.push_back(u);
- }
-
- { // NORMAL TEXTURE
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
- RID texture = storage->texture_get_rd_texture(p_normalmap);
- if (!texture.is_valid()) {
- //use default normal texture
- texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
- }
- u.ids.push_back(texture);
- uniform_set.push_back(u);
- }
-
- { // SPECULAR TEXTURE
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 3;
- RID texture = storage->texture_get_rd_texture(p_specular);
- if (!texture.is_valid()) {
- //use default white texture
- texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
- }
- u.ids.push_back(texture);
- uniform_set.push_back(u);
- }
-
- { // SAMPLER
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 4;
- RID sampler = storage->sampler_rd_get_default(p_filter, p_repeat);
- ERR_FAIL_COND_V(sampler.is_null(), RID());
- u.ids.push_back(sampler);
- uniform_set.push_back(u);
- }
-
- { // MULTIMESH TEXTURE BUFFER
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
- u.binding = 5;
- u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER));
- uniform_set.push_back(u);
- }
-
- return RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0);
-}
-
-RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
-
- if (p_filter == VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
- p_filter = default_samplers.default_filter;
- }
-
- if (p_repeat == VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
- p_repeat = default_samplers.default_repeat;
- }
-
- TextureBindingKey key;
- key.texture = p_texture;
- key.normalmap = p_normalmap;
- key.specular = p_specular;
- key.multimesh = p_multimesh;
- key.texture_filter = p_filter;
- key.texture_repeat = p_repeat;
-
- TextureBinding *binding;
- TextureBindingID id;
- {
- TextureBindingID *idptr = bindings.texture_key_bindings.getptr(key);
-
- if (!idptr) {
- id = bindings.id_generator++;
- bindings.texture_key_bindings[key] = id;
- binding = memnew(TextureBinding);
- binding->key = key;
- binding->id = id;
-
- bindings.texture_bindings[id] = binding;
-
- } else {
- id = *idptr;
- binding = bindings.texture_bindings[id];
- }
- }
-
- binding->reference_count++;
-
- if (binding->to_dispose.in_list()) {
- //was queued for disposal previously, but ended up reused.
- bindings.to_dispose_list.remove(&binding->to_dispose);
- }
-
- if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) {
- binding->uniform_set = _create_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh);
- }
-
- return id;
-}
-
-void RasterizerCanvasRD::free_texture_binding(TextureBindingID p_binding) {
-
- TextureBinding **binding_ptr = bindings.texture_bindings.getptr(p_binding);
- ERR_FAIL_COND(!binding_ptr);
- TextureBinding *binding = *binding_ptr;
- ERR_FAIL_COND(binding->reference_count == 0);
- binding->reference_count--;
- if (binding->reference_count == 0) {
- bindings.to_dispose_list.add(&binding->to_dispose);
- }
-}
-
-void RasterizerCanvasRD::_dispose_bindings() {
-
- while (bindings.to_dispose_list.first()) {
- TextureBinding *binding = bindings.to_dispose_list.first()->self();
- if (binding->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) {
- RD::get_singleton()->free(binding->uniform_set);
- }
-
- bindings.texture_key_bindings.erase(binding->key);
- bindings.texture_bindings.erase(binding->id);
- bindings.to_dispose_list.remove(&binding->to_dispose);
- memdelete(binding);
- }
-}
-
-RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights) {
-
- // Care must be taken to generate array formats
- // in ways where they could be reused, so we will
- // put single-occuring elements first, and repeated
- // elements later. This way the generated formats are
- // the same no matter the length of the arrays.
- // This dramatically reduces the amount of pipeline objects
- // that need to be created for these formats.
-
- uint32_t vertex_count = p_points.size();
- uint32_t stride = 2; //vertices always repeat
- if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
- stride += 4;
- }
- if ((uint32_t)p_uvs.size() == vertex_count) {
- stride += 2;
- }
- if ((uint32_t)p_bones.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
- stride += 4;
- }
-
- uint32_t buffer_size = stride * p_points.size();
-
- Vector<uint8_t> polygon_buffer;
- polygon_buffer.resize(buffer_size * sizeof(float));
- Vector<RD::VertexDescription> descriptions;
- descriptions.resize(4);
- Vector<RID> buffers;
- buffers.resize(4);
-
- {
- const uint8_t *r = polygon_buffer.ptr();
- float *fptr = (float *)r;
- uint32_t *uptr = (uint32_t *)r;
- uint32_t base_offset = 0;
- { //vertices
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- vd.offset = base_offset * sizeof(float);
- vd.location = VS::ARRAY_VERTEX;
- vd.stride = stride * sizeof(float);
-
- descriptions.write[0] = vd;
-
- const Vector2 *points_ptr = p_points.ptr();
-
- for (uint32_t i = 0; i < vertex_count; i++) {
- fptr[base_offset + i * stride + 0] = points_ptr[i].x;
- fptr[base_offset + i * stride + 1] = points_ptr[i].y;
- }
-
- base_offset += 2;
- }
-
- //colors
- if ((uint32_t)p_colors.size() == vertex_count || p_colors.size() == 1) {
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- vd.offset = base_offset * sizeof(float);
- vd.location = VS::ARRAY_COLOR;
- vd.stride = stride * sizeof(float);
-
- descriptions.write[1] = vd;
-
- if (p_colors.size() == 1) {
- Color color = p_colors[0];
- for (uint32_t i = 0; i < vertex_count; i++) {
- fptr[base_offset + i * stride + 0] = color.r;
- fptr[base_offset + i * stride + 1] = color.g;
- fptr[base_offset + i * stride + 2] = color.b;
- fptr[base_offset + i * stride + 3] = color.a;
- }
- } else {
- const Color *color_ptr = p_colors.ptr();
-
- for (uint32_t i = 0; i < vertex_count; i++) {
- fptr[base_offset + i * stride + 0] = color_ptr[i].r;
- fptr[base_offset + i * stride + 1] = color_ptr[i].g;
- fptr[base_offset + i * stride + 2] = color_ptr[i].b;
- fptr[base_offset + i * stride + 3] = color_ptr[i].a;
- }
- }
- base_offset += 4;
- } else {
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- vd.offset = 0;
- vd.location = VS::ARRAY_COLOR;
- vd.stride = 0;
-
- descriptions.write[1] = vd;
- buffers.write[1] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_COLOR);
- }
-
- //uvs
- if ((uint32_t)p_uvs.size() == vertex_count) {
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- vd.offset = base_offset * sizeof(float);
- vd.location = VS::ARRAY_TEX_UV;
- vd.stride = stride * sizeof(float);
-
- descriptions.write[2] = vd;
-
- const Vector2 *uv_ptr = p_uvs.ptr();
-
- for (uint32_t i = 0; i < vertex_count; i++) {
- fptr[base_offset + i * stride + 0] = uv_ptr[i].x;
- fptr[base_offset + i * stride + 1] = uv_ptr[i].y;
- }
- base_offset += 2;
- } else {
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- vd.offset = 0;
- vd.location = VS::ARRAY_TEX_UV;
- vd.stride = 0;
-
- descriptions.write[2] = vd;
- buffers.write[2] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_TEX_UV);
- }
-
- //bones
- if ((uint32_t)p_indices.size() == vertex_count * 4 && (uint32_t)p_weights.size() == vertex_count * 4) {
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
- vd.offset = base_offset * sizeof(float);
- vd.location = VS::ARRAY_BONES;
- vd.stride = stride * sizeof(float);
-
- descriptions.write[3] = vd;
-
- const int *bone_ptr = p_bones.ptr();
- const float *weight_ptr = p_weights.ptr();
-
- for (uint32_t i = 0; i < vertex_count; i++) {
-
- uint16_t *bone16w = (uint16_t *)&uptr[base_offset + i * stride];
- uint16_t *weight16w = (uint16_t *)&uptr[base_offset + i * stride + 2];
-
- bone16w[0] = bone_ptr[i * 4 + 0];
- bone16w[1] = bone_ptr[i * 4 + 1];
- bone16w[2] = bone_ptr[i * 4 + 2];
- bone16w[3] = bone_ptr[i * 4 + 3];
-
- weight16w[0] = CLAMP(weight_ptr[i * 4 + 0] * 65535, 0, 65535);
- weight16w[1] = CLAMP(weight_ptr[i * 4 + 1] * 65535, 0, 65535);
- weight16w[2] = CLAMP(weight_ptr[i * 4 + 2] * 65535, 0, 65535);
- weight16w[3] = CLAMP(weight_ptr[i * 4 + 3] * 65535, 0, 65535);
- }
-
- base_offset += 4;
- } else {
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
- vd.offset = 0;
- vd.location = VS::ARRAY_BONES;
- vd.stride = 0;
-
- descriptions.write[3] = vd;
- buffers.write[3] = storage->mesh_get_default_rd_buffer(RasterizerStorageRD::DEFAULT_RD_BUFFER_BONES);
- }
-
- //check that everything is as it should be
- ERR_FAIL_COND_V(base_offset != stride, 0); //bug
- }
-
- RD::VertexFormatID vertex_id = RD::get_singleton()->vertex_format_create(descriptions);
- ERR_FAIL_COND_V(vertex_id == RD::INVALID_ID, 0);
-
- PolygonBuffers pb;
- pb.vertex_buffer = RD::get_singleton()->vertex_buffer_create(polygon_buffer.size(), polygon_buffer);
- for (int i = 0; i < descriptions.size(); i++) {
- if (buffers[i] == RID()) { //if put in vertex, use as vertex
- buffers.write[i] = pb.vertex_buffer;
- }
- }
-
- pb.vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), vertex_id, buffers);
-
- if (p_indices.size()) {
- //create indices, as indices were requested
- Vector<uint8_t> index_buffer;
- 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());
- }
- 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());
- }
-
- pb.vertex_format_id = vertex_id;
-
- PolygonID id = polygon_buffers.last_id++;
-
- polygon_buffers.polygons[id] = pb;
-
- return id;
-}
-
-void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) {
-
- PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon);
- ERR_FAIL_COND(!pb_ptr);
-
- PolygonBuffers &pb = *pb_ptr;
-
- if (pb.indices.is_valid()) {
- RD::get_singleton()->free(pb.indices);
- }
- if (pb.index_buffer.is_valid()) {
- RD::get_singleton()->free(pb.index_buffer);
- }
-
- RD::get_singleton()->free(pb.vertex_array);
- RD::get_singleton()->free(pb.vertex_buffer);
-
- polygon_buffers.polygons.erase(p_polygon);
-}
-
-Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list, uint32_t &flags) {
-
- TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding);
- ERR_FAIL_COND_V(!texture_binding_ptr, Size2i());
- TextureBinding *texture_binding = *texture_binding_ptr;
-
- if (texture_binding->key.normalmap.is_valid()) {
- flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
- }
- if (texture_binding->key.specular.is_valid()) {
- flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
- }
-
- if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) {
- //texture may have changed (erased or replaced, see if we can fix)
- texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh);
- ERR_FAIL_COND_V(!texture_binding->uniform_set.is_valid(), Size2i(1, 1));
- }
-
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0);
- if (texture_binding->key.texture.is_valid()) {
- return storage->texture_2d_get_size(texture_binding->key.texture);
- } else {
- return Size2i(1, 1);
- }
-}
-
-////////////////////
-void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants) {
-
- //create an empty push constant
-
- PushConstant push_constant;
- Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
- _update_transform_2d_to_mat2x3(base_transform, push_constant.world);
-
- Color base_color = p_item->final_modulate;
-
- for (int i = 0; i < 4; i++) {
- push_constant.modulation[i] = 0;
- push_constant.ninepatch_margins[i] = 0;
- push_constant.src_rect[i] = 0;
- push_constant.dst_rect[i] = 0;
- }
- push_constant.flags = 0;
- push_constant.color_texture_pixel_size[0] = 0;
- push_constant.color_texture_pixel_size[1] = 0;
-
- push_constant.pad[0] = 0;
- push_constant.pad[1] = 0;
-
- push_constant.lights[0] = 0;
- push_constant.lights[1] = 0;
- push_constant.lights[2] = 0;
- push_constant.lights[3] = 0;
-
- uint32_t base_flags = 0;
-
- bool light_uniform_set_dirty = false;
-
- if (!p_item->custom_data) {
- p_item->custom_data = memnew(ItemStateData);
- light_uniform_set_dirty = true;
- }
-
- ItemStateData *state_data = (ItemStateData *)p_item->custom_data;
-
- Light *light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];
- uint16_t light_count = 0;
- PipelineLightMode light_mode;
-
- {
-
- Light *light = p_lights;
-
- while (light) {
-
- if (light->render_index_cache >= 0 && p_item->light_mask & light->item_mask && p_item->z_final >= light->z_min && p_item->z_final <= light->z_max && p_item->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
-
- uint32_t light_index = light->render_index_cache;
- push_constant.lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
-
- if (!light_uniform_set_dirty && (state_data->light_cache[light_count].light != light || state_data->light_cache[light_count].light_version != light->version)) {
- light_uniform_set_dirty = true;
- }
-
- light_cache[light_count] = light;
-
- light_count++;
- if (light->mode == VS::CANVAS_LIGHT_MODE_MASK) {
- base_flags |= FLAGS_USING_LIGHT_MASK;
- }
- if (light_count == state.max_lights_per_item) {
- break;
- }
- }
- light = light->next_ptr;
- }
-
- if (light_count != state_data->light_cache_count) {
- light_uniform_set_dirty = true;
- }
- base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
- }
-
- {
-
- RID &canvas_item_state = light_count ? state_data->state_uniform_set_with_light : state_data->state_uniform_set;
-
- bool invalid_uniform = canvas_item_state.is_valid() && !RD::get_singleton()->uniform_set_is_valid(canvas_item_state);
-
- if (canvas_item_state.is_null() || invalid_uniform || (light_count > 0 && light_uniform_set_dirty)) {
- //re create canvas state
- Vector<RD::Uniform> uniforms;
-
- if (state_data->state_uniform_set_with_light.is_valid() && !invalid_uniform) {
- RD::get_singleton()->free(canvas_item_state);
- }
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(state.canvas_state_buffer);
- uniforms.push_back(u);
- }
-
- if (false && p_item->skeleton.is_valid()) {
- //bind skeleton stuff
- } else {
- //bind default
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
- u.binding = 1;
- u.ids.push_back(shader.default_skeleton_texture_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 2;
- u.ids.push_back(shader.default_skeleton_uniform_buffer);
- uniforms.push_back(u);
- }
- }
-
- //validate and update lighs if they are being used
-
- if (light_count > 0) {
- //recreate uniform set
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 3;
- u.ids.push_back(state.lights_uniform_buffer);
- uniforms.push_back(u);
- }
-
- {
-
- RD::Uniform u_lights;
- u_lights.type = RD::UNIFORM_TYPE_TEXTURE;
- u_lights.binding = 4;
-
- RD::Uniform u_shadows;
- u_shadows.type = RD::UNIFORM_TYPE_TEXTURE;
- u_shadows.binding = 5;
-
- //lights
- for (uint32_t i = 0; i < state.max_lights_per_item; i++) {
- if (i < light_count) {
-
- CanvasLight *cl = canvas_light_owner.getornull(light_cache[i]->light_internal);
- ERR_CONTINUE(!cl);
-
- RID rd_texture;
-
- if (cl->texture.is_valid()) {
- rd_texture = storage->texture_get_rd_texture(cl->texture);
- }
- if (rd_texture.is_valid()) {
- u_lights.ids.push_back(rd_texture);
- } else {
- u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- }
- if (cl->shadow.texture.is_valid()) {
- u_shadows.ids.push_back(cl->shadow.texture);
- } else {
- u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
- }
- } else {
- u_lights.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- u_shadows.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
- }
- }
-
- uniforms.push_back(u_lights);
- uniforms.push_back(u_shadows);
- }
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 6;
- u.ids.push_back(state.shadow_sampler);
- uniforms.push_back(u);
- }
-
- canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader_light, 2);
- } else {
- canvas_item_state = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 2);
- }
- }
-
- RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, canvas_item_state, 2);
- }
-
- light_mode = light_count > 0 ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
-
- PipelineVariants *pipeline_variants = p_pipeline_variants;
-
- bool reclip = false;
-
- const Item::Command *c = p_item->commands;
- while (c) {
- push_constant.flags = base_flags; //reset on each command for sanity
- push_constant.specular_shininess = 0xFFFFFFFF;
-
- switch (c->type) {
- case Item::Command::TYPE_RECT: {
-
- const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
-
- //bind pipeline
- {
- RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- }
-
- //bind textures
-
- Size2 texpixel_size;
- {
- texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list, push_constant.flags);
- texpixel_size.x = 1.0 / texpixel_size.x;
- texpixel_size.y = 1.0 / texpixel_size.y;
- }
-
- if (rect->specular_shininess.a < 0.999) {
- push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
- }
-
- _update_specular_shininess(rect->specular_shininess, &push_constant.specular_shininess);
-
- Rect2 src_rect;
- Rect2 dst_rect;
-
- if (texpixel_size != Vector2()) {
- push_constant.color_texture_pixel_size[0] = texpixel_size.x;
- push_constant.color_texture_pixel_size[1] = texpixel_size.y;
-
- src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
- dst_rect = Rect2(rect->rect.position, rect->rect.size);
-
- if (dst_rect.size.width < 0) {
- dst_rect.position.x += dst_rect.size.width;
- dst_rect.size.width *= -1;
- }
- if (dst_rect.size.height < 0) {
- dst_rect.position.y += dst_rect.size.height;
- dst_rect.size.height *= -1;
- }
-
- if (rect->flags & CANVAS_RECT_FLIP_H) {
- src_rect.size.x *= -1;
- }
-
- if (rect->flags & CANVAS_RECT_FLIP_V) {
- src_rect.size.y *= -1;
- }
-
- if (rect->flags & CANVAS_RECT_TRANSPOSE) {
- dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
- }
-
- if (rect->flags & CANVAS_RECT_CLIP_UV) {
- push_constant.flags |= FLAGS_CLIP_RECT_UV;
- }
-
- } else {
- dst_rect = Rect2(rect->rect.position, rect->rect.size);
-
- if (dst_rect.size.width < 0) {
- dst_rect.position.x += dst_rect.size.width;
- dst_rect.size.width *= -1;
- }
- if (dst_rect.size.height < 0) {
- dst_rect.position.y += dst_rect.size.height;
- dst_rect.size.height *= -1;
- }
-
- src_rect = Rect2(0, 0, 1, 1);
- texpixel_size = Vector2(1, 1);
- }
-
- push_constant.modulation[0] = rect->modulate.r * base_color.r;
- push_constant.modulation[1] = rect->modulate.g * base_color.g;
- push_constant.modulation[2] = rect->modulate.b * base_color.b;
- push_constant.modulation[3] = rect->modulate.a * base_color.a;
-
- push_constant.src_rect[0] = src_rect.position.x;
- push_constant.src_rect[1] = src_rect.position.y;
- push_constant.src_rect[2] = src_rect.size.width;
- push_constant.src_rect[3] = src_rect.size.height;
-
- push_constant.dst_rect[0] = dst_rect.position.x;
- push_constant.dst_rect[1] = dst_rect.position.y;
- push_constant.dst_rect[2] = dst_rect.size.width;
- push_constant.dst_rect[3] = dst_rect.size.height;
-
- push_constant.color_texture_pixel_size[0] = texpixel_size.x;
- push_constant.color_texture_pixel_size[1] = texpixel_size.y;
-
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
- RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
- RD::get_singleton()->draw_list_draw(p_draw_list, true);
-
- } break;
-
- case Item::Command::TYPE_NINEPATCH: {
-
- const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
-
- //bind pipeline
- {
- RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_NINEPATCH].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- }
-
- //bind textures
-
- Size2 texpixel_size;
- {
- texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list, push_constant.flags);
- texpixel_size.x = 1.0 / texpixel_size.x;
- texpixel_size.y = 1.0 / texpixel_size.y;
- }
-
- if (np->specular_shininess.a < 0.999) {
- push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
- }
-
- _update_specular_shininess(np->specular_shininess, &push_constant.specular_shininess);
-
- Rect2 src_rect;
- Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
-
- if (texpixel_size == Size2()) {
-
- texpixel_size = Size2(1, 1);
- src_rect = Rect2(0, 0, 1, 1);
-
- } else {
-
- if (np->source != Rect2()) {
- src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height);
- texpixel_size = Size2(1.0 / np->source.size.width, 1.0 / np->source.size.height);
- } else {
- src_rect = Rect2(0, 0, 1, 1);
- }
- }
-
- push_constant.modulation[0] = np->color.r * base_color.r;
- push_constant.modulation[1] = np->color.g * base_color.g;
- push_constant.modulation[2] = np->color.b * base_color.b;
- push_constant.modulation[3] = np->color.a * base_color.a;
-
- push_constant.src_rect[0] = src_rect.position.x;
- push_constant.src_rect[1] = src_rect.position.y;
- push_constant.src_rect[2] = src_rect.size.width;
- push_constant.src_rect[3] = src_rect.size.height;
-
- push_constant.dst_rect[0] = dst_rect.position.x;
- push_constant.dst_rect[1] = dst_rect.position.y;
- push_constant.dst_rect[2] = dst_rect.size.width;
- push_constant.dst_rect[3] = dst_rect.size.height;
-
- push_constant.color_texture_pixel_size[0] = texpixel_size.x;
- push_constant.color_texture_pixel_size[1] = texpixel_size.y;
-
- push_constant.flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
- push_constant.flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
-
- if (np->draw_center) {
- push_constant.flags |= FLAGS_NINEPACH_DRAW_CENTER;
- }
-
- push_constant.ninepatch_margins[0] = np->margin[MARGIN_LEFT];
- push_constant.ninepatch_margins[1] = np->margin[MARGIN_TOP];
- push_constant.ninepatch_margins[2] = np->margin[MARGIN_RIGHT];
- push_constant.ninepatch_margins[3] = np->margin[MARGIN_BOTTOM];
-
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
- RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
- RD::get_singleton()->draw_list_draw(p_draw_list, true);
-
- } break;
- case Item::Command::TYPE_POLYGON: {
-
- const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
-
- PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
- ERR_CONTINUE(!pb);
- //bind pipeline
- {
- static const PipelineVariant variant[VS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
- ERR_CONTINUE(polygon->primitive < 0 || polygon->primitive >= VS::PRIMITIVE_MAX);
- RID pipeline = pipeline_variants->variants[light_mode][variant[polygon->primitive]].get_render_pipeline(pb->vertex_format_id, p_framebuffer_format);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- }
-
- if (polygon->primitive == VS::PRIMITIVE_LINES) {
- //not supported in most hardware, so pointless
- //RD::get_singleton()->draw_list_set_line_width(p_draw_list, polygon->line_width);
- }
-
- //bind textures
-
- Size2 texpixel_size;
- {
- texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list, push_constant.flags);
- texpixel_size.x = 1.0 / texpixel_size.x;
- texpixel_size.y = 1.0 / texpixel_size.y;
- }
-
- if (polygon->specular_shininess.a < 0.999) {
- push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
- }
-
- _update_specular_shininess(polygon->specular_shininess, &push_constant.specular_shininess);
-
- push_constant.modulation[0] = base_color.r;
- push_constant.modulation[1] = base_color.g;
- push_constant.modulation[2] = base_color.b;
- push_constant.modulation[3] = base_color.a;
-
- for (int j = 0; j < 4; j++) {
- push_constant.src_rect[j] = 0;
- push_constant.dst_rect[j] = 0;
- push_constant.ninepatch_margins[j] = 0;
- }
-
- push_constant.color_texture_pixel_size[0] = texpixel_size.x;
- push_constant.color_texture_pixel_size[1] = texpixel_size.y;
-
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
- RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
- if (pb->indices.is_valid()) {
- RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices);
- }
- RD::get_singleton()->draw_list_draw(p_draw_list, pb->indices.is_valid());
-
- } break;
- case Item::Command::TYPE_PRIMITIVE: {
-
- const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
-
- //bind pipeline
- {
- static const PipelineVariant variant[4] = { PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES };
- ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4);
- RID pipeline = pipeline_variants->variants[light_mode][variant[primitive->point_count - 1]].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
- }
-
- //bind textures
-
- {
- _bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list, push_constant.flags);
- }
-
- if (primitive->specular_shininess.a < 0.999) {
- push_constant.flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
- }
-
- _update_specular_shininess(primitive->specular_shininess, &push_constant.specular_shininess);
-
- RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3, primitive->point_count) - 1]);
-
- for (uint32_t j = 0; j < MIN(3, primitive->point_count); j++) {
- push_constant.points[j * 2 + 0] = primitive->points[j].x;
- push_constant.points[j * 2 + 1] = primitive->points[j].y;
- push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x;
- push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y;
- Color col = primitive->colors[j] * base_color;
- push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
- push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
- }
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, true);
-
- if (primitive->point_count == 4) {
- for (uint32_t j = 1; j < 3; j++) {
- //second half of triangle
- push_constant.points[j * 2 + 0] = primitive->points[j + 1].x;
- push_constant.points[j * 2 + 1] = primitive->points[j + 1].y;
- push_constant.uvs[j * 2 + 0] = primitive->uvs[j + 1].x;
- push_constant.uvs[j * 2 + 1] = primitive->uvs[j + 1].y;
- Color col = primitive->colors[j + 1] * base_color;
- push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
- push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
- }
-
- RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
- RD::get_singleton()->draw_list_draw(p_draw_list, true);
- }
-
- } break;
- case Item::Command::TYPE_MESH:
- case Item::Command::TYPE_MULTIMESH:
- case Item::Command::TYPE_PARTICLES: {
- ERR_PRINT("FIXME: Mesh, MultiMesh and Particles render commands are unimplemented currently, they need to be ported to the 4.0 rendering architecture.");
-#ifndef _MSC_VER
-#warning Item::Command types for Mesh, MultiMesh and Particles need to be implemented.
-#endif
- // See #if 0'ed code below to port from GLES3.
- } break;
-
-#if 0
- case Item::Command::TYPE_MESH: {
-
- Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c);
- _set_texture_rect_mode(false);
-
- RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map);
-
- if (texture) {
- Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
- }
-
- state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform);
-
- RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh);
- if (mesh_data) {
-
- for (int j = 0; j < mesh_data->surfaces.size(); j++) {
- RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
- // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
- glBindVertexArray(s->array_id);
-
- glVertexAttrib4f(VS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a);
-
- if (s->index_array_len) {
- glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
- } else {
- glDrawArrays(gl_primitive[s->primitive], 0, s->array_len);
- }
-
- glBindVertexArray(0);
- }
- }
- state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform);
-
- } break;
- case Item::Command::TYPE_MULTIMESH: {
-
- Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c);
-
- RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh);
-
- if (!multi_mesh)
- break;
-
- RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh);
-
- if (!mesh_data)
- break;
-
- RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map);
-
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != VS::MULTIMESH_CUSTOM_DATA_NONE);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
- //reset shader and force rebind
- state.using_texture_rect = true;
- _set_texture_rect_mode(false);
-
- if (texture) {
- Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
- }
-
- int amount = MIN(multi_mesh->size, multi_mesh->visible_instances);
-
- if (amount == -1) {
- amount = multi_mesh->size;
- }
-
- for (int j = 0; j < mesh_data->surfaces.size(); j++) {
- RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
- // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
- glBindVertexArray(s->instancing_array_id);
-
- glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
-
- int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4;
- glEnableVertexAttribArray(8);
- glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
- glVertexAttribDivisor(8, 1);
- glEnableVertexAttribArray(9);
- glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4));
- glVertexAttribDivisor(9, 1);
-
- int color_ofs;
-
- if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) {
- glEnableVertexAttribArray(10);
- glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4));
- glVertexAttribDivisor(10, 1);
- color_ofs = 12 * 4;
- } else {
- glDisableVertexAttribArray(10);
- glVertexAttrib4f(10, 0, 0, 1, 0);
- color_ofs = 8 * 4;
- }
-
- int custom_data_ofs = color_ofs;
-
- switch (multi_mesh->color_format) {
-
- case VS::MULTIMESH_COLOR_NONE: {
- glDisableVertexAttribArray(11);
- glVertexAttrib4f(11, 1, 1, 1, 1);
- } break;
- case VS::MULTIMESH_COLOR_8BIT: {
- glEnableVertexAttribArray(11);
- glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
- glVertexAttribDivisor(11, 1);
- custom_data_ofs += 4;
-
- } break;
- case VS::MULTIMESH_COLOR_FLOAT: {
- glEnableVertexAttribArray(11);
- glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
- glVertexAttribDivisor(11, 1);
- custom_data_ofs += 4 * 4;
- } break;
- }
-
- switch (multi_mesh->custom_data_format) {
-
- case VS::MULTIMESH_CUSTOM_DATA_NONE: {
- glDisableVertexAttribArray(12);
- glVertexAttrib4f(12, 1, 1, 1, 1);
- } break;
- case VS::MULTIMESH_CUSTOM_DATA_8BIT: {
- glEnableVertexAttribArray(12);
- glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
- glVertexAttribDivisor(12, 1);
-
- } break;
- case VS::MULTIMESH_CUSTOM_DATA_FLOAT: {
- glEnableVertexAttribArray(12);
- glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
- glVertexAttribDivisor(12, 1);
- } break;
- }
-
- if (s->index_array_len) {
- glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
- } else {
- glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
- }
-
- glBindVertexArray(0);
- }
-
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
- state.using_texture_rect = true;
- _set_texture_rect_mode(false);
-
- } break;
- case Item::Command::TYPE_PARTICLES: {
-
- Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c);
-
- RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles);
- if (!particles)
- break;
-
- if (particles->inactive && !particles->emitting)
- break;
-
- glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
-
- VisualServerRaster::redraw_request();
-
- storage->particles_request_process(particles_cmd->particles);
- //enable instancing
-
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
- //reset shader and force rebind
- state.using_texture_rect = true;
- _set_texture_rect_mode(false);
-
- RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
-
- if (texture) {
- Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
- state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
- } else {
- state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0));
- }
-
- if (!particles->use_local_coords) {
-
- Transform2D inv_xf;
- inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y));
- inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y));
- inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y));
- inv_xf.affine_invert();
-
- state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
- }
-
- glBindVertexArray(data.particle_quad_array); //use particle quad array
- glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
-
- int stride = sizeof(float) * 4 * 6;
-
- int amount = particles->amount;
-
- if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) {
-
- glEnableVertexAttribArray(8); //xform x
- glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
- glVertexAttribDivisor(8, 1);
- glEnableVertexAttribArray(9); //xform y
- glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
- glVertexAttribDivisor(9, 1);
- glEnableVertexAttribArray(10); //xform z
- glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
- glVertexAttribDivisor(10, 1);
- glEnableVertexAttribArray(11); //color
- glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL);
- glVertexAttribDivisor(11, 1);
- glEnableVertexAttribArray(12); //custom
- glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
- glVertexAttribDivisor(12, 1);
-
- glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount);
- } else {
- //split
- int split = int(Math::ceil(particles->phase * particles->amount));
-
- if (amount - split > 0) {
- glEnableVertexAttribArray(8); //xform x
- glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3));
- glVertexAttribDivisor(8, 1);
- glEnableVertexAttribArray(9); //xform y
- glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4));
- glVertexAttribDivisor(9, 1);
- glEnableVertexAttribArray(10); //xform z
- glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5));
- glVertexAttribDivisor(10, 1);
- glEnableVertexAttribArray(11); //color
- glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0));
- glVertexAttribDivisor(11, 1);
- glEnableVertexAttribArray(12); //custom
- glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2));
- glVertexAttribDivisor(12, 1);
-
- glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split);
- }
-
- if (split > 0) {
- glEnableVertexAttribArray(8); //xform x
- glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
- glVertexAttribDivisor(8, 1);
- glEnableVertexAttribArray(9); //xform y
- glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
- glVertexAttribDivisor(9, 1);
- glEnableVertexAttribArray(10); //xform z
- glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
- glVertexAttribDivisor(10, 1);
- glEnableVertexAttribArray(11); //color
- glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL);
- glVertexAttribDivisor(11, 1);
- glEnableVertexAttribArray(12); //custom
- glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
- glVertexAttribDivisor(12, 1);
-
- glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split);
- }
- }
-
- glBindVertexArray(0);
-
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
- state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
- state.using_texture_rect = true;
- _set_texture_rect_mode(false);
-
- } break;
-#endif
- case Item::Command::TYPE_TRANSFORM: {
-
- const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
- _update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world);
-
- } break;
- case Item::Command::TYPE_CLIP_IGNORE: {
-
- const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
- if (current_clip) {
-
- if (ci->ignore != reclip) {
-
- if (ci->ignore) {
- RD::get_singleton()->draw_list_disable_scissor(p_draw_list);
- reclip = true;
- } else {
-
- RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect);
- reclip = false;
- }
- }
- }
-
- } break;
- }
-
- c = c->next;
- }
-
- if (current_clip && reclip) {
- //will make it re-enable clipping if needed afterwards
- current_clip = NULL;
- }
-}
-
-void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set) {
-
- Item *current_clip = NULL;
-
- Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
-
- RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target);
-
- Vector<Color> clear_colors;
- bool clear = false;
- if (storage->render_target_is_clear_requested(p_to_render_target)) {
- clear = true;
- clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target));
- storage->render_target_disable_clear_request(p_to_render_target);
- }
-#ifndef _MSC_VER
-#warning TODO obtain from framebuffer format eventually when this is implemented
-#endif
-
- RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
-
- if (p_screen_uniform_set.is_valid()) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_screen_uniform_set, 3);
- }
- RID prev_material;
-
- PipelineVariants *pipeline_variants = &shader.pipeline_variants;
-
- for (int i = 0; i < p_item_count; i++) {
-
- Item *ci = items[i];
-
- if (current_clip != ci->final_clip_owner) {
-
- current_clip = ci->final_clip_owner;
-
- //setup clip
- if (current_clip) {
-
- RD::get_singleton()->draw_list_enable_scissor(draw_list, current_clip->final_clip_rect);
-
- } else {
-
- RD::get_singleton()->draw_list_disable_scissor(draw_list);
- }
- }
-
- if (ci->material != prev_material) {
-
- MaterialData *material_data = NULL;
- if (ci->material.is_valid()) {
- material_data = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
- }
-
- if (material_data) {
-
- if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
- pipeline_variants = &material_data->shader_data->pipeline_variants;
- if (material_data->uniform_set.is_valid()) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, 1);
- }
- } else {
- pipeline_variants = &shader.pipeline_variants;
- }
- } else {
- pipeline_variants = &shader.pipeline_variants;
- }
- }
-
- _render_item(draw_list, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants);
-
- prev_material = ci->material;
- }
-
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) {
-
- int item_count = 0;
-
- //setup canvas state uniforms if needed
-
- Transform2D canvas_transform_inverse = p_canvas_transform.affine_inverse();
-
- {
- //update canvas state uniform buffer
- State::Buffer state_buffer;
-
- Size2i ssize = storage->render_target_get_size(p_to_render_target);
-
- Transform screen_transform;
- screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
- screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
- _update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
- _update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform);
-
- Transform2D normal_transform = p_canvas_transform;
- normal_transform.elements[0].normalize();
- normal_transform.elements[1].normalize();
- normal_transform.elements[2] = Vector2();
- _update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
-
- state_buffer.canvas_modulate[0] = p_modulate.r;
- state_buffer.canvas_modulate[1] = p_modulate.g;
- state_buffer.canvas_modulate[2] = p_modulate.b;
- state_buffer.canvas_modulate[3] = p_modulate.a;
-
- Size2 render_target_size = storage->render_target_get_size(p_to_render_target);
- state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
- state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
-
- state_buffer.time = state.time;
- RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
- }
-
- //setup lights if exist
-
- {
-
- Light *l = p_light_list;
- uint32_t index = 0;
-
- while (l) {
-
- if (index == state.max_lights_per_render) {
- l->render_index_cache = -1;
- l = l->next_ptr;
- continue;
- }
-
- CanvasLight *clight = canvas_light_owner.getornull(l->light_internal);
- if (!clight) { //unused or invalid texture
- l->render_index_cache = -1;
- l = l->next_ptr;
- ERR_CONTINUE(!clight);
- }
- Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
-
- Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
- state.light_uniforms[index].position[0] = canvas_light_pos.x;
- state.light_uniforms[index].position[1] = canvas_light_pos.y;
-
- _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
- _update_transform_2d_to_mat2x4(l->xform_cache.affine_inverse(), state.light_uniforms[index].shadow_matrix);
-
- state.light_uniforms[index].height = l->height * (p_canvas_transform.elements[0].length() + p_canvas_transform.elements[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
- for (int i = 0; i < 4; i++) {
- state.light_uniforms[index].shadow_color[i] = l->shadow_color[i];
- state.light_uniforms[index].color[i] = l->color[i];
- }
-
- state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
-
- if (clight->shadow.texture.is_valid()) {
- state.light_uniforms[index].shadow_pixel_size = (1.0 / clight->shadow.size) * (1.0 + l->shadow_smooth);
- } else {
- state.light_uniforms[index].shadow_pixel_size = 1.0;
- }
-
- state.light_uniforms[index].flags |= l->mode << LIGHT_FLAGS_BLEND_SHIFT;
- state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
- if (clight->shadow.texture.is_valid()) {
- state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
- }
-
- l->render_index_cache = index;
-
- index++;
- l = l->next_ptr;
- }
-
- if (index > 0) {
- RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * index, &state.light_uniforms[0], true);
- }
- }
-
- //fill the list until rendering is possible.
- bool material_screen_texture_found = false;
- Item *ci = p_item_list;
- Rect2 back_buffer_rect;
- bool backbuffer_copy = false;
- RID screen_uniform_set;
-
- while (ci) {
-
- if (ci->copy_back_buffer) {
- backbuffer_copy = true;
-
- if (ci->copy_back_buffer->full) {
- back_buffer_rect = Rect2();
- } else {
- back_buffer_rect = ci->copy_back_buffer->rect;
- }
- }
-
- if (ci->material.is_valid()) {
- MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
- if (md && md->shader_data->valid) {
-
- if (md->shader_data->uses_screen_texture) {
- if (!material_screen_texture_found) {
- backbuffer_copy = true;
- back_buffer_rect = Rect2();
- }
- if (screen_uniform_set.is_null()) {
- RID backbuffer_shader = shader.canvas_shader.version_get_shader(md->shader_data->version, 0); //any version is fine
- screen_uniform_set = storage->render_target_get_back_buffer_uniform_set(p_to_render_target, backbuffer_shader);
- }
- }
-
- if (md->last_frame != RasterizerRD::get_frame_number()) {
- md->last_frame = RasterizerRD::get_frame_number();
- if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) {
- // uniform set may be gone because a dependency was erased. In this case, it will happen
- // if a texture is deleted, so just re-create it.
- storage->material_force_update_textures(ci->material, RasterizerStorageRD::SHADER_TYPE_2D);
- }
- }
- }
- }
-
- if (backbuffer_copy) {
- //render anything pending, including clearing if no items
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set);
- item_count = 0;
-
- storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect);
-
- backbuffer_copy = false;
- material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
- }
-
- items[item_count++] = ci;
-
- if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, screen_uniform_set);
- //then reset
- item_count = 0;
- }
-
- ci = ci->next;
- }
-}
-
-RID RasterizerCanvasRD::light_create() {
-
- CanvasLight canvas_light;
- canvas_light.shadow.size = 0;
- return canvas_light_owner.make_rid(canvas_light);
-}
-
-void RasterizerCanvasRD::light_set_texture(RID p_rid, RID p_texture) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
- ERR_FAIL_COND(!cl);
- if (cl->texture == p_texture) {
- return;
- }
-
- cl->texture = p_texture;
-}
-void RasterizerCanvasRD::light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
- ERR_FAIL_COND(!cl);
- ERR_FAIL_COND(p_resolution < 64);
- if (cl->shadow.texture.is_valid() == p_enable && p_resolution == cl->shadow.size) {
- return;
- }
-
- if (cl->shadow.texture.is_valid()) {
-
- RD::get_singleton()->free(cl->shadow.fb);
- RD::get_singleton()->free(cl->shadow.depth);
- RD::get_singleton()->free(cl->shadow.texture);
- cl->shadow.fb = RID();
- cl->shadow.texture = RID();
- cl->shadow.depth = RID();
- }
-
- if (p_enable) {
-
- Vector<RID> fb_textures;
-
- { //texture
- RD::TextureFormat tf;
- tf.type = RD::TEXTURE_TYPE_2D;
- tf.width = p_resolution;
- tf.height = 1;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
-
- cl->shadow.texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- fb_textures.push_back(cl->shadow.texture);
- }
- {
- RD::TextureFormat tf;
- tf.type = RD::TEXTURE_TYPE_2D;
- tf.width = p_resolution;
- tf.height = 1;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
- tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_X8_D24_UNORM_PACK32, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_X8_D24_UNORM_PACK32 : RD::DATA_FORMAT_D32_SFLOAT;
- //chunks to write
- cl->shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- fb_textures.push_back(cl->shadow.depth);
- }
-
- cl->shadow.fb = RD::get_singleton()->framebuffer_create(fb_textures);
- }
-
- cl->shadow.size = p_resolution;
-}
-
-void RasterizerCanvasRD::light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
-
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
- ERR_FAIL_COND(cl->shadow.texture.is_null());
-
- for (int i = 0; i < 4; i++) {
-
- //make sure it remains orthogonal, makes easy to read angle later
-
- //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1));
-
- Vector<Color> cc;
- cc.push_back(Color(p_far, p_far, p_far, 1.0));
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(cl->shadow.fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, cc, 1.0, 0, Rect2i((cl->shadow.size / 4) * i, 0, (cl->shadow.size / 4), 1));
-
- CameraMatrix projection;
- {
- real_t fov = 90;
- real_t nearp = p_near;
- real_t farp = p_far;
- real_t aspect = 1.0;
-
- real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5));
- real_t ymin = -ymax;
- real_t xmin = ymin * aspect;
- real_t xmax = ymax * aspect;
-
- projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
- }
-
- Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
- projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
-
- ShadowRenderPushConstant push_constant;
- for (int y = 0; y < 4; y++) {
- for (int x = 0; x < 4; x++) {
- push_constant.projection[y * 4 + x] = projection.matrix[y][x];
- }
- }
- static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
- push_constant.direction[0] = directions[i].x;
- push_constant.direction[1] = directions[i].y;
- push_constant.pad[0] = 0;
- push_constant.pad[1] = 0;
-
- /*if (i == 0)
- *p_xform_cache = projection;*/
-
- LightOccluderInstance *instance = p_occluders;
-
- while (instance) {
-
- OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder);
-
- if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) {
-
- instance = instance->next;
- continue;
- }
-
- _update_transform_2d_to_mat2x4(p_light_xform * instance->xform_cache, push_constant.modelview);
-
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, shadow_render.render_pipelines[co->cull_mode]);
- RD::get_singleton()->draw_list_bind_vertex_array(draw_list, co->vertex_array);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, co->index_array);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowRenderPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
-
- instance = instance->next;
- }
-
- RD::get_singleton()->draw_list_end();
- }
-}
-
-RID RasterizerCanvasRD::occluder_polygon_create() {
-
- OccluderPolygon occluder;
- occluder.point_count = 0;
- occluder.cull_mode = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
- return occluder_polygon_owner.make_rid(occluder);
-}
-
-void RasterizerCanvasRD::occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines) {
-
- OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
- ERR_FAIL_COND(!oc);
-
- if (oc->point_count != p_lines.size() && oc->vertex_array.is_valid()) {
-
- RD::get_singleton()->free(oc->vertex_array);
- RD::get_singleton()->free(oc->vertex_buffer);
- RD::get_singleton()->free(oc->index_array);
- RD::get_singleton()->free(oc->index_buffer);
-
- oc->vertex_array = RID();
- oc->vertex_buffer = RID();
- oc->index_array = RID();
- oc->index_buffer = RID();
- }
-
- if (p_lines.size()) {
-
- Vector<uint8_t> geometry;
- Vector<uint8_t> indices;
- int lc = p_lines.size();
-
- geometry.resize(lc * 6 * sizeof(float));
- indices.resize(lc * 3 * sizeof(uint16_t));
-
- {
- uint8_t *vw = geometry.ptrw();
- float *vwptr = (float *)vw;
- uint8_t *iw = indices.ptrw();
- uint16_t *iwptr = (uint16_t *)iw;
-
- const Vector2 *lr = p_lines.ptr();
-
- const int POLY_HEIGHT = 16384;
-
- for (int i = 0; i < lc / 2; i++) {
-
- vwptr[i * 12 + 0] = lr[i * 2 + 0].x;
- vwptr[i * 12 + 1] = lr[i * 2 + 0].y;
- vwptr[i * 12 + 2] = POLY_HEIGHT;
-
- vwptr[i * 12 + 3] = lr[i * 2 + 1].x;
- vwptr[i * 12 + 4] = lr[i * 2 + 1].y;
- vwptr[i * 12 + 5] = POLY_HEIGHT;
-
- vwptr[i * 12 + 6] = lr[i * 2 + 1].x;
- vwptr[i * 12 + 7] = lr[i * 2 + 1].y;
- vwptr[i * 12 + 8] = -POLY_HEIGHT;
-
- vwptr[i * 12 + 9] = lr[i * 2 + 0].x;
- vwptr[i * 12 + 10] = lr[i * 2 + 0].y;
- vwptr[i * 12 + 11] = -POLY_HEIGHT;
-
- iwptr[i * 6 + 0] = i * 4 + 0;
- iwptr[i * 6 + 1] = i * 4 + 1;
- iwptr[i * 6 + 2] = i * 4 + 2;
-
- iwptr[i * 6 + 3] = i * 4 + 2;
- iwptr[i * 6 + 4] = i * 4 + 3;
- iwptr[i * 6 + 5] = i * 4 + 0;
- }
- }
-
- //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
-
- if (oc->vertex_array.is_null()) {
- //create from scratch
- //vertices
- oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry);
-
- Vector<RID> buffer;
- buffer.push_back(oc->vertex_buffer);
- oc->vertex_array = RD::get_singleton()->vertex_array_create(4 * lc / 2, shadow_render.vertex_format, buffer);
- //indices
-
- oc->index_buffer = RD::get_singleton()->index_buffer_create(3 * lc, RD::INDEX_BUFFER_FORMAT_UINT16, indices);
- oc->index_array = RD::get_singleton()->index_array_create(oc->index_buffer, 0, 3 * lc);
-
- } else {
- //update existing
- const uint8_t *vr = geometry.ptr();
- RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, geometry.size(), vr);
- const uint8_t *ir = indices.ptr();
- RD::get_singleton()->buffer_update(oc->index_buffer, 0, indices.size(), ir);
- }
- }
-}
-void RasterizerCanvasRD::occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode) {
- OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder);
- ERR_FAIL_COND(!oc);
- oc->cull_mode = p_mode;
-}
-
-void RasterizerCanvasRD::ShaderData::set_code(const String &p_code) {
- //compile
-
- code = p_code;
- valid = false;
- ubo_size = 0;
- uniforms.clear();
- uses_screen_texture = false;
- uses_material_samplers = false;
-
- if (code == String()) {
- return; //just invalid, but no error
- }
-
- ShaderCompilerRD::GeneratedCode gen_code;
-
- int light_mode = LIGHT_MODE_NORMAL;
- int blend_mode = BLEND_MODE_MIX;
- uses_screen_texture = false;
-
- 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["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
- actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
-
- actions.render_mode_values["unshaded"] = Pair<int *, int>(&light_mode, LIGHT_MODE_UNSHADED);
- actions.render_mode_values["light_only"] = Pair<int *, int>(&light_mode, LIGHT_MODE_LIGHT_ONLY);
-
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
-
- actions.uniforms = &uniforms;
-
- RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
-
- Error err = canvas_singleton->shader.compiler.compile(VS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
-
- if (version.is_null()) {
- version = canvas_singleton->shader.canvas_shader.version_create();
- }
-
- if (gen_code.texture_uniforms.size() || uses_screen_texture) { //requires the samplers
- gen_code.defines.push_back("\n#define USE_MATERIAL_SAMPLERS\n");
- uses_material_samplers = true;
- }
-#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
- 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);
- ERR_FAIL_COND(!canvas_singleton->shader.canvas_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 them pipelines
-
- RD::PipelineColorBlendState::Attachment attachment;
-
- switch (blend_mode) {
- case BLEND_MODE_DISABLED: {
-
- // nothing to do here, disabled by default
-
- } break;
- case BLEND_MODE_MIX: {
-
- attachment.enable_blend = true;
- attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- attachment.color_blend_op = RD::BLEND_OP_ADD;
- attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
-
- } break;
- case BLEND_MODE_ADD: {
-
- attachment.enable_blend = true;
- attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- attachment.color_blend_op = RD::BLEND_OP_ADD;
- attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
-
- } break;
- case BLEND_MODE_SUB: {
-
- attachment.enable_blend = true;
- attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
- attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
- attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
-
- } break;
- case BLEND_MODE_MUL: {
- attachment.enable_blend = true;
- attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- attachment.color_blend_op = RD::BLEND_OP_ADD;
- attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
- attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
- attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
- attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
-
- } break;
- case BLEND_MODE_PMALPHA: {
- attachment.enable_blend = true;
- attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- attachment.color_blend_op = RD::BLEND_OP_ADD;
- attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
- attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
-
- } break;
- }
-
- RD::PipelineColorBlendState blend_state;
- blend_state.attachments.push_back(attachment);
-
- //update pipelines
-
- for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
- for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
- RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_LINES,
- RD::RENDER_PRIMITIVE_POINTS,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
- RD::RENDER_PRIMITIVE_LINES,
- RD::RENDER_PRIMITIVE_LINESTRIPS,
- RD::RENDER_PRIMITIVE_POINTS,
- };
-
- ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
- { //non lit
- SHADER_VARIANT_QUAD,
- SHADER_VARIANT_NINEPATCH,
- SHADER_VARIANT_PRIMITIVE,
- SHADER_VARIANT_PRIMITIVE,
- SHADER_VARIANT_PRIMITIVE_POINTS,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES_POINTS },
- { //lit
- SHADER_VARIANT_QUAD_LIGHT,
- SHADER_VARIANT_NINEPATCH_LIGHT,
- SHADER_VARIANT_PRIMITIVE_LIGHT,
- SHADER_VARIANT_PRIMITIVE_LIGHT,
- SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
- };
-
- RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]);
- pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
- }
- }
-
- valid = true;
-}
-
-void RasterizerCanvasRD::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 RasterizerCanvasRD::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().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);
- }
-}
-
-bool RasterizerCanvasRD::ShaderData::is_param_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
-bool RasterizerCanvasRD::ShaderData::is_animated() const {
- return false;
-}
-bool RasterizerCanvasRD::ShaderData::casts_shadows() const {
- return false;
-}
-Variant RasterizerCanvasRD::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();
-}
-
-RasterizerCanvasRD::ShaderData::ShaderData() {
- valid = false;
- uses_screen_texture = false;
- uses_material_samplers = false;
-}
-
-RasterizerCanvasRD::ShaderData::~ShaderData() {
- RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::singleton;
- ERR_FAIL_COND(!canvas_singleton);
- //pipeline variants will clear themselves if shader is gone
- if (version.is_valid()) {
- canvas_singleton->shader.canvas_shader.version_free(version);
- }
-}
-
-RasterizerStorageRD::ShaderData *RasterizerCanvasRD::_create_shader_func() {
- ShaderData *shader_data = memnew(ShaderData);
- return shader_data;
-}
-void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
-
- RasterizerCanvasRD *canvas_singleton = (RasterizerCanvasRD *)RasterizerCanvas::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());
- }
-
- 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(), false);
- }
-
- if (shader_data->ubo_size == 0 && !shader_data->uses_material_samplers) {
- // 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->uses_material_samplers) {
- //needs samplers for the material (uses custom textures) create them
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 0;
- u.ids.resize(12);
- RID *ids_ptr = u.ids.ptrw();
- ids_ptr[0] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = canvas_singleton->storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- uniforms.push_back(u);
- }
-
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 1;
- 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.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), 1);
-}
-RasterizerCanvasRD::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);
- }
-}
-
-RasterizerStorageRD::MaterialData *RasterizerCanvasRD::_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;
-}
-
-void RasterizerCanvasRD::set_time(double p_time) {
- state.time = p_time;
-}
-
-void RasterizerCanvasRD::update() {
- _dispose_bindings();
-}
-
-RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
- storage = p_storage;
-
- { //create default samplers
-
- default_samplers.default_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
- default_samplers.default_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
- }
-
- { //shader variants
-
- uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
-
- String global_defines;
- if (textures_per_stage <= 16) {
- //ARM pretty much, and very old Intel GPUs under Linux
- state.max_lights_per_item = 4; //sad
- global_defines += "#define MAX_LIGHT_TEXTURES 4\n";
- } else if (textures_per_stage <= 32) {
- //Apple (Metal)
- state.max_lights_per_item = 8; //sad
- global_defines += "#define MAX_LIGHT_TEXTURES 8\n";
- } else {
- //Anything else (16 lights per item)
- state.max_lights_per_item = DEFAULT_MAX_LIGHTS_PER_ITEM;
- global_defines += "#define MAX_LIGHT_TEXTURES " + itos(DEFAULT_MAX_LIGHTS_PER_ITEM) + "\n";
- }
-
- uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
- if (uniform_max_size < 65536) {
- //Yes, you guessed right, ARM again
- state.max_lights_per_render = 64;
- global_defines += "#define MAX_LIGHTS 64\n";
- } else {
- state.max_lights_per_render = DEFAULT_MAX_LIGHTS_PER_RENDER;
- global_defines += "#define MAX_LIGHTS " + itos(DEFAULT_MAX_LIGHTS_PER_RENDER) + "\n";
- }
-
- state.light_uniforms = memnew_arr(LightUniform, state.max_lights_per_render);
- Vector<String> variants;
- //non light variants
- variants.push_back(""); //none by default is first variant
- variants.push_back("#define USE_NINEPATCH\n"); //ninepatch is the second variant
- variants.push_back("#define USE_PRIMITIVE\n"); //primitive is the third
- variants.push_back("#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size
- variants.push_back("#define USE_ATTRIBUTES\n"); // attributes for vertex arrays
- variants.push_back("#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size
- //light variants
- variants.push_back("#define USE_LIGHTING\n"); //none by default is first variant
- variants.push_back("#define USE_LIGHTING\n#define USE_NINEPATCH\n"); //ninepatch is the second variant
- variants.push_back("#define USE_LIGHTING\n#define USE_PRIMITIVE\n"); //primitive is the third
- variants.push_back("#define USE_LIGHTING\n#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size
- variants.push_back("#define USE_LIGHTING\n#define USE_ATTRIBUTES\n"); // attributes for vertex arrays
- variants.push_back("#define USE_LIGHTING\n#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size
-
- shader.canvas_shader.initialize(variants, global_defines);
-
- shader.default_version = shader.canvas_shader.version_create();
- shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD);
- shader.default_version_rd_shader_light = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD_LIGHT);
-
- for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
- for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
- RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_LINES,
- RD::RENDER_PRIMITIVE_POINTS,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
- RD::RENDER_PRIMITIVE_LINES,
- RD::RENDER_PRIMITIVE_LINESTRIPS,
- RD::RENDER_PRIMITIVE_POINTS,
- };
-
- ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
- { //non lit
- SHADER_VARIANT_QUAD,
- SHADER_VARIANT_NINEPATCH,
- SHADER_VARIANT_PRIMITIVE,
- SHADER_VARIANT_PRIMITIVE,
- SHADER_VARIANT_PRIMITIVE_POINTS,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES_POINTS },
- { //lit
- SHADER_VARIANT_QUAD_LIGHT,
- SHADER_VARIANT_NINEPATCH_LIGHT,
- SHADER_VARIANT_PRIMITIVE_LIGHT,
- SHADER_VARIANT_PRIMITIVE_LIGHT,
- SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
- };
-
- RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]);
- shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
- }
- }
- }
-
- {
- //shader compiler
- ShaderCompilerRD::DefaultIdentifierActions actions;
-
- actions.renames["VERTEX"] = "vertex";
- actions.renames["LIGHT_VERTEX"] = "light_vertex";
- actions.renames["SHADOW_VERTEX"] = "shadow_vertex";
- actions.renames["UV"] = "uv";
- actions.renames["POINT_SIZE"] = "gl_PointSize";
-
- actions.renames["WORLD_MATRIX"] = "world_matrix";
- actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
- actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
- actions.renames["TIME"] = "canvas_data.time";
- actions.renames["AT_LIGHT_PASS"] = "false";
- actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
-
- actions.renames["COLOR"] = "color";
- actions.renames["NORMAL"] = "normal";
- actions.renames["NORMALMAP"] = "normal_map";
- actions.renames["NORMALMAP_DEPTH"] = "normal_depth";
- actions.renames["TEXTURE"] = "color_texture";
- actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size";
- actions.renames["NORMAL_TEXTURE"] = "normal_texture";
- actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
- actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
- actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "screen_texture";
- actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
- actions.renames["FRAGCOORD"] = "gl_FragCoord";
- actions.renames["POINT_COORD"] = "gl_PointCoord";
-
- actions.renames["LIGHT_POSITION"] = "light_pos";
- actions.renames["LIGHT_COLOR"] = "light_color";
- actions.renames["LIGHT_ENERGY"] = "light_energy";
- actions.renames["LIGHT"] = "light";
- actions.renames["SHADOW_MODULATE"] = "shadow_modulate";
-
- actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
- actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
- actions.usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
- actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
- actions.usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n";
- actions.usage_defines["LIGHT"] = "#define LIGHT_SHADER_CODE_USED\n";
-
- actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
-
- actions.custom_samplers["TEXTURE"] = "texture_sampler";
- actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
- actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
- actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture
- actions.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 2;
- actions.texture_layout_set = 1;
- actions.base_uniform_string = "material.";
- actions.default_filter = ShaderLanguage::FILTER_LINEAR;
- actions.default_repeat = ShaderLanguage::REPEAT_DISABLE;
- actions.base_varying_index = 4;
-
- shader.compiler.initialize(actions);
- }
-
- { //shadow rendering
- Vector<String> versions;
- versions.push_back(String()); //no versions
- shadow_render.shader.initialize(versions);
-
- {
- Vector<RD::AttachmentFormat> attachments;
-
- RD::AttachmentFormat af_color;
- af_color.format = RD::DATA_FORMAT_R32_SFLOAT;
- af_color.usage_flags = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- attachments.push_back(af_color);
-
- RD::AttachmentFormat af_depth;
- af_depth.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;
- af_depth.usage_flags = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-
- attachments.push_back(af_depth);
-
- shadow_render.framebuffer_format = RD::get_singleton()->framebuffer_format_create(attachments);
- }
-
- //pipelines
- Vector<RD::VertexDescription> vf;
- RD::VertexDescription vd;
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- vd.location = 0;
- vd.offset = 0;
- vd.stride = sizeof(float) * 3;
- vf.push_back(vd);
- shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf);
-
- shadow_render.shader_version = shadow_render.shader.version_create();
-
- for (int i = 0; i < 3; i++) {
- RD::PipelineRasterizationState rs;
- rs.cull_mode = i == 0 ? RD::POLYGON_CULL_DISABLED : (i == 1 ? RD::POLYGON_CULL_FRONT : RD::POLYGON_CULL_BACK);
- RD::PipelineDepthStencilState ds;
- ds.enable_depth_write = true;
- ds.enable_depth_test = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS;
- shadow_render.render_pipelines[i] = RD::get_singleton()->render_pipeline_create(shadow_render.shader.version_get_shader(shadow_render.shader_version, 0), shadow_render.framebuffer_format, shadow_render.vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
-
- { //bindings
- bindings.id_generator = 0;
- //generate for 0
- bindings.default_empty = request_texture_binding(RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, RID());
-
- { //state allocate
- state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer));
- state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * state.max_lights_per_render);
-
- RD::SamplerState shadow_sampler_state;
- shadow_sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- shadow_sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- shadow_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; //shadow wrap around
- shadow_sampler_state.compare_op = RD::COMPARE_OP_GREATER;
- state.shadow_sampler = RD::get_singleton()->sampler_create(shadow_sampler_state);
- }
- }
-
- {
- //polygon buffers
- polygon_buffers.last_id = 1;
- }
-
- { // default index buffer
-
- Vector<uint8_t> pv;
- pv.resize(6 * 4);
- {
- uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
- }
- shader.quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
- shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6);
- }
-
- { //primitive
- primitive_arrays.index_array[0] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 1);
- primitive_arrays.index_array[1] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 2);
- primitive_arrays.index_array[2] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 3);
- primitive_arrays.index_array[3] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6);
- }
-
- { //default skeleton buffer
-
- shader.default_skeleton_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform));
- SkeletonUniform su;
- _update_transform_2d_to_mat4(Transform2D(), su.skeleton_inverse);
- _update_transform_2d_to_mat4(Transform2D(), su.skeleton_transform);
- RD::get_singleton()->buffer_update(shader.default_skeleton_uniform_buffer, 0, sizeof(SkeletonUniform), &su);
-
- shader.default_skeleton_texture_buffer = RD::get_singleton()->texture_buffer_create(32, RD::DATA_FORMAT_R32G32B32A32_SFLOAT);
- }
-
- //create functions for shader and material
- storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_shader_funcs);
- storage->material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_2D, _create_material_funcs);
-
- state.time = 0;
-
- static_assert(sizeof(PushConstant) == 128);
-}
-
-bool RasterizerCanvasRD::free(RID p_rid) {
-
- if (canvas_light_owner.owns(p_rid)) {
- CanvasLight *cl = canvas_light_owner.getornull(p_rid);
- ERR_FAIL_COND_V(!cl, false);
- light_set_use_shadow(p_rid, false, 64);
- canvas_light_owner.free(p_rid);
- } else if (occluder_polygon_owner.owns(p_rid)) {
- occluder_polygon_set_shape_as_lines(p_rid, Vector<Vector2>());
- occluder_polygon_owner.free(p_rid);
- } else {
- return false;
- }
-
- return true;
-}
-
-RasterizerCanvasRD::~RasterizerCanvasRD() {
-
- //canvas state
-
- {
- if (state.canvas_state_buffer.is_valid()) {
- RD::get_singleton()->free(state.canvas_state_buffer);
- }
-
- memdelete_arr(state.light_uniforms);
- RD::get_singleton()->free(state.lights_uniform_buffer);
- RD::get_singleton()->free(shader.default_skeleton_uniform_buffer);
- RD::get_singleton()->free(shader.default_skeleton_texture_buffer);
- }
-
- //shadow rendering
- {
-
- shadow_render.shader.version_free(shadow_render.shader_version);
- //this will also automatically clear all pipelines
- RD::get_singleton()->free(state.shadow_sampler);
- }
- //bindings
- {
-
- free_texture_binding(bindings.default_empty);
-
- //dispose pending
- _dispose_bindings();
- //anything remains?
- if (bindings.texture_bindings.size()) {
- ERR_PRINT("Some texture bindings were not properly freed (leaked canvasitems?");
- const TextureBindingID *key = NULL;
- while ((key = bindings.texture_bindings.next(key))) {
- TextureBinding *tb = bindings.texture_bindings[*key];
- tb->reference_count = 1;
- free_texture_binding(*key);
- }
- //dispose pending
- _dispose_bindings();
- }
- }
-
- //shaders
-
- shader.canvas_shader.version_free(shader.default_version);
-
- //buffers
- {
- RD::get_singleton()->free(shader.quad_index_array);
- RD::get_singleton()->free(shader.quad_index_buffer);
- //primitives are erase by dependency
- }
-
- //pipelines don't need freeing, they are all gone after shaders are gone
-}
diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h
deleted file mode 100644
index 894a00a436..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.h
+++ /dev/null
@@ -1,501 +0,0 @@
-/*************************************************************************/
-/* rasterizer_canvas_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_CANVAS_RD_H
-#define RASTERIZER_CANVAS_RD_H
-
-#include "servers/visual/rasterizer.h"
-#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-#include "servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h"
-#include "servers/visual/rasterizer_rd/shader_compiler_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/canvas.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/canvas_occlusion.glsl.gen.h"
-#include "servers/visual/rendering_device.h"
-
-class RasterizerCanvasRD : public RasterizerCanvas {
-
- RasterizerStorageRD *storage;
-
- enum ShaderVariant {
- SHADER_VARIANT_QUAD,
- SHADER_VARIANT_NINEPATCH,
- SHADER_VARIANT_PRIMITIVE,
- SHADER_VARIANT_PRIMITIVE_POINTS,
- SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES_POINTS,
- SHADER_VARIANT_QUAD_LIGHT,
- SHADER_VARIANT_NINEPATCH_LIGHT,
- SHADER_VARIANT_PRIMITIVE_LIGHT,
- SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
- SHADER_VARIANT_MAX
- };
-
- enum {
- FLAGS_INSTANCING_STRIDE_MASK = 0xF,
- FLAGS_INSTANCING_ENABLED = (1 << 4),
- FLAGS_INSTANCING_HAS_COLORS = (1 << 5),
- FLAGS_INSTANCING_COLOR_8BIT = (1 << 6),
- FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 7),
- FLAGS_INSTANCING_CUSTOM_DATA_8_BIT = (1 << 8),
-
- FLAGS_CLIP_RECT_UV = (1 << 9),
- FLAGS_TRANSPOSE_RECT = (1 << 10),
- FLAGS_USING_LIGHT_MASK = (1 << 11),
-
- FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
- FLAGS_USING_PARTICLES = (1 << 13),
- FLAGS_USE_PIXEL_SNAP = (1 << 14),
-
- FLAGS_USE_SKELETON = (1 << 15),
- FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
- FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
- FLAGS_LIGHT_COUNT_SHIFT = 20,
-
- FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
- FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27)
-
- };
-
- enum {
- LIGHT_FLAGS_TEXTURE_MASK = 0xFFFF,
- LIGHT_FLAGS_BLEND_SHIFT = 16,
- LIGHT_FLAGS_BLEND_MASK = (3 << 16),
- LIGHT_FLAGS_BLEND_MODE_ADD = (0 << 16),
- LIGHT_FLAGS_BLEND_MODE_SUB = (1 << 16),
- LIGHT_FLAGS_BLEND_MODE_MIX = (2 << 16),
- LIGHT_FLAGS_BLEND_MODE_MASK = (3 << 16),
- LIGHT_FLAGS_HAS_SHADOW = (1 << 20),
- LIGHT_FLAGS_FILTER_SHIFT = 22
-
- };
-
- enum {
- MAX_RENDER_ITEMS = 256 * 1024,
- MAX_LIGHT_TEXTURES = 1024,
- DEFAULT_MAX_LIGHTS_PER_ITEM = 16,
- DEFAULT_MAX_LIGHTS_PER_RENDER = 256
- };
-
- /****************/
- /**** SHADER ****/
- /****************/
-
- enum PipelineVariant {
- PIPELINE_VARIANT_QUAD,
- PIPELINE_VARIANT_NINEPATCH,
- PIPELINE_VARIANT_PRIMITIVE_TRIANGLES,
- PIPELINE_VARIANT_PRIMITIVE_LINES,
- PIPELINE_VARIANT_PRIMITIVE_POINTS,
- PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES,
- PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP,
- PIPELINE_VARIANT_ATTRIBUTE_LINES,
- PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP,
- PIPELINE_VARIANT_ATTRIBUTE_POINTS,
- PIPELINE_VARIANT_MAX
- };
- enum PipelineLightMode {
- PIPELINE_LIGHT_MODE_DISABLED,
- PIPELINE_LIGHT_MODE_ENABLED,
- PIPELINE_LIGHT_MODE_MAX
- };
-
- struct PipelineVariants {
- RenderPipelineVertexFormatCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX];
- };
-
- struct {
- CanvasShaderRD canvas_shader;
- RID default_version;
- RID default_version_rd_shader;
- RID default_version_rd_shader_light;
- RID quad_index_buffer;
- RID quad_index_array;
- PipelineVariants pipeline_variants;
-
- // default_skeleton uniform set
- RID default_skeleton_uniform_buffer;
- RID default_skeleton_texture_buffer;
-
- ShaderCompilerRD compiler;
- } shader;
-
- struct ShaderData : public RasterizerStorageRD::ShaderData {
-
- enum BlendMode { //used internally
- BLEND_MODE_MIX,
- BLEND_MODE_ADD,
- BLEND_MODE_SUB,
- BLEND_MODE_MUL,
- BLEND_MODE_PMALPHA,
- BLEND_MODE_DISABLED,
- };
-
- enum LightMode {
- LIGHT_MODE_NORMAL,
- LIGHT_MODE_UNSHADED,
- LIGHT_MODE_LIGHT_ONLY
- };
-
- bool valid;
- RID version;
- PipelineVariants pipeline_variants;
- 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;
-
- bool uses_screen_texture;
- bool uses_material_samplers;
-
- 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 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;
- ShaderData();
- virtual ~ShaderData();
- };
-
- RasterizerStorageRD::ShaderData *_create_shader_func();
- static RasterizerStorageRD::ShaderData *_create_shader_funcs() {
- return static_cast<RasterizerCanvasRD *>(singleton)->_create_shader_func();
- }
-
- struct MaterialData : public RasterizerStorageRD::MaterialData {
- uint64_t last_frame;
- ShaderData *shader_data;
- RID uniform_buffer;
- RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
-
- 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();
- };
-
- RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
- static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
- return static_cast<RasterizerCanvasRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
- }
-
- /**************************/
- /**** TEXTURE BINDINGS ****/
- /**************************/
-
- // bindings used to render commands,
- // cached for performance.
-
- struct TextureBindingKey {
- RID texture;
- RID normalmap;
- RID specular;
- RID multimesh;
- VS::CanvasItemTextureFilter texture_filter;
- VS::CanvasItemTextureRepeat texture_repeat;
- bool operator==(const TextureBindingKey &p_key) const {
- return texture == p_key.texture && normalmap == p_key.normalmap && specular == p_key.specular && multimesh == p_key.specular && texture_filter == p_key.texture_filter && texture_repeat == p_key.texture_repeat;
- }
- };
-
- struct TextureBindingKeyHasher {
- static _FORCE_INLINE_ uint32_t hash(const TextureBindingKey &p_key) {
- uint32_t hash = hash_djb2_one_64(p_key.texture.get_id());
- hash = hash_djb2_one_64(p_key.normalmap.get_id(), hash);
- hash = hash_djb2_one_64(p_key.specular.get_id(), hash);
- hash = hash_djb2_one_64(p_key.multimesh.get_id(), hash);
- hash = hash_djb2_one_32(uint32_t(p_key.texture_filter) << 16 | uint32_t(p_key.texture_repeat), hash);
- return hash;
- }
- };
-
- struct TextureBinding {
- TextureBindingID id;
- TextureBindingKey key;
- SelfList<TextureBinding> to_dispose;
- uint32_t reference_count;
- RID uniform_set;
- TextureBinding() :
- to_dispose(this) {
- reference_count = 0;
- }
- };
-
- struct {
- SelfList<TextureBinding>::List to_dispose_list;
-
- TextureBindingID id_generator;
- HashMap<TextureBindingKey, TextureBindingID, TextureBindingKeyHasher> texture_key_bindings;
- HashMap<TextureBindingID, TextureBinding *> texture_bindings;
-
- TextureBindingID default_empty;
- } bindings;
-
- RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
- void _dispose_bindings();
-
- struct {
- VS::CanvasItemTextureFilter default_filter;
- VS::CanvasItemTextureRepeat default_repeat;
- } default_samplers;
-
- /******************/
- /**** POLYGONS ****/
- /******************/
-
- struct PolygonBuffers {
- RD::VertexFormatID vertex_format_id;
- RID vertex_buffer;
- RID vertex_array;
- RID index_buffer;
- RID indices;
- };
-
- struct {
- HashMap<PolygonID, PolygonBuffers> polygons;
- PolygonID last_id;
- } polygon_buffers;
-
- /********************/
- /**** PRIMITIVES ****/
- /********************/
-
- struct {
- RID index_array[4];
- } primitive_arrays;
-
- /*******************/
- /**** MATERIALS ****/
- /*******************/
-
- /******************/
- /**** LIGHTING ****/
- /******************/
-
- struct CanvasLight {
-
- RID texture;
- struct {
- int size;
- RID texture;
- RID depth;
- RID fb;
- } shadow;
- };
-
- RID_Owner<CanvasLight> canvas_light_owner;
-
- struct ShadowRenderPushConstant {
- float projection[16];
- float modelview[8];
- float direction[2];
- float pad[2];
- };
-
- struct OccluderPolygon {
-
- VS::CanvasOccluderPolygonCullMode cull_mode;
- int point_count;
- RID vertex_buffer;
- RID vertex_array;
- RID index_buffer;
- RID index_array;
- };
-
- struct LightUniform {
- float matrix[8]; //light to texture coordinate matrix
- float shadow_matrix[8]; //light to shadow coordinate matrix
- float color[4];
- float shadow_color[4];
- float position[2];
- uint32_t flags; //index to light texture
- float height;
- float shadow_pixel_size;
- float pad[3];
- };
-
- RID_Owner<OccluderPolygon> occluder_polygon_owner;
-
- struct {
- CanvasOcclusionShaderRD shader;
- RID shader_version;
- RID render_pipelines[3];
- RD::VertexFormatID vertex_format;
- RD::FramebufferFormatID framebuffer_format;
- } shadow_render;
-
- /***************/
- /**** STATE ****/
- /***************/
-
- //state that does not vary across rendering all items
-
- struct ItemStateData : public Item::CustomData {
-
- struct LightCache {
- uint64_t light_version;
- Light *light;
- };
-
- LightCache light_cache[DEFAULT_MAX_LIGHTS_PER_ITEM];
- uint32_t light_cache_count;
- RID state_uniform_set_with_light;
- RID state_uniform_set;
- ItemStateData() {
-
- for (int i = 0; i < DEFAULT_MAX_LIGHTS_PER_ITEM; i++) {
- light_cache[i].light_version = 0;
- light_cache[i].light = NULL;
- }
- light_cache_count = 0xFFFFFFFF;
- }
-
- ~ItemStateData() {
- if (state_uniform_set_with_light.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set_with_light)) {
- RD::get_singleton()->free(state_uniform_set_with_light);
- }
- if (state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state_uniform_set)) {
- RD::get_singleton()->free(state_uniform_set);
- }
- }
- };
-
- struct State {
-
- //state buffer
- struct Buffer {
- float canvas_transform[16];
- float screen_transform[16];
- float canvas_normal_transform[16];
- float canvas_modulate[4];
- float screen_pixel_size[2];
- float time;
- float pad;
-
- //uint32_t light_count;
- //uint32_t pad[3];
- };
-
- LightUniform *light_uniforms;
-
- RID lights_uniform_buffer;
- RID canvas_state_buffer;
- RID shadow_sampler;
-
- uint32_t max_lights_per_render;
- uint32_t max_lights_per_item;
-
- double time;
- } state;
-
- struct PushConstant {
- float world[6];
- uint32_t flags;
- uint32_t specular_shininess;
- union {
- //rect
- struct {
- float modulation[4];
- float ninepatch_margins[4];
- float dst_rect[4];
- float src_rect[4];
- float pad[2];
- };
- //primitive
- struct {
- float points[6]; // vec2 points[3]
- float uvs[6]; // vec2 points[3]
- uint32_t colors[6]; // colors encoded as half
- };
- };
- float color_texture_pixel_size[2];
- uint32_t lights[4];
- };
-
- struct SkeletonUniform {
- float skeleton_transform[16];
- float skeleton_inverse[16];
- };
-
- Item *items[MAX_RENDER_ITEMS];
-
- Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list, uint32_t &flags);
- void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants);
- void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, RID p_screen_uniform_set);
-
- _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
- _FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
-
- _FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);
- _FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4);
-
- _FORCE_INLINE_ void _update_specular_shininess(const Color &p_transform, uint32_t *r_ss);
-
-public:
- TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
- void free_texture_binding(TextureBindingID p_binding);
-
- PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>());
- void free_polygon(PolygonID p_polygon);
-
- RID light_create();
- void light_set_texture(RID p_rid, RID p_texture);
- void light_set_use_shadow(RID p_rid, bool p_enable, int p_resolution);
- void light_update_shadow(RID p_rid, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders);
-
- RID occluder_polygon_create();
- void occluder_polygon_set_shape_as_lines(RID p_occluder, const Vector<Vector2> &p_lines);
- void occluder_polygon_set_cull_mode(RID p_occluder, VS::CanvasOccluderPolygonCullMode p_mode);
-
- void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform);
-
- void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){};
-
- void draw_window_margins(int *p_margins, RID *p_margin_textures) {}
-
- void set_time(double p_time);
- void update();
- bool free(RID p_rid);
- RasterizerCanvasRD(RasterizerStorageRD *p_storage);
- ~RasterizerCanvasRD();
-};
-
-#endif // RASTERIZER_CANVAS_RD_H
diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
deleted file mode 100644
index 6b6c750fd3..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp
+++ /dev/null
@@ -1,1105 +0,0 @@
-/*************************************************************************/
-/* rasterizer_effects_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer_effects_rd.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-#include "cubemap_coeffs.h"
-
-static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) {
- p_array[0] = p_basis.elements[0][0];
- p_array[1] = p_basis.elements[1][0];
- p_array[2] = p_basis.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_basis.elements[0][1];
- p_array[5] = p_basis.elements[1][1];
- p_array[6] = p_basis.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_basis.elements[0][2];
- p_array[9] = p_basis.elements[1][2];
- p_array[10] = p_basis.elements[2][2];
- p_array[11] = 0;
-}
-
-RID RasterizerEffectsRD::_get_uniform_set_from_image(RID p_image) {
-
- if (image_to_uniform_set_cache.has(p_image)) {
- RID uniform_set = image_to_uniform_set_cache[p_image];
- if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- return uniform_set;
- }
- }
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 0;
- u.ids.push_back(p_image);
- uniforms.push_back(u);
- //any thing with the same configuration (one texture in binding 0 for set 0), is good
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, 0), 1);
-
- image_to_uniform_set_cache[p_image] = uniform_set;
-
- return uniform_set;
-}
-
-RID RasterizerEffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
-
- if (texture_to_uniform_set_cache.has(p_texture)) {
- RID uniform_set = texture_to_uniform_set_cache[p_texture];
- if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- return uniform_set;
- }
- }
-
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- u.binding = 0;
- u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
- u.ids.push_back(p_texture);
- uniforms.push_back(u);
- //any thing with the same configuration (one texture in binding 0 for set 0), is good
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, blur.shader.version_get_shader(blur.shader_version, 0), 0);
-
- texture_to_uniform_set_cache[p_texture] = uniform_set;
-
- return uniform_set;
-}
-
-RID RasterizerEffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {
-
- if (texture_to_compute_uniform_set_cache.has(p_texture)) {
- RID uniform_set = texture_to_compute_uniform_set_cache[p_texture];
- if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- return uniform_set;
- }
- }
-
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- u.binding = 0;
- u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler);
- u.ids.push_back(p_texture);
- uniforms.push_back(u);
- //any thing with the same configuration (one texture in binding 0 for set 0), is good
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, 0), 0);
-
- texture_to_compute_uniform_set_cache[p_texture] = uniform_set;
-
- return uniform_set;
-}
-
-void RasterizerEffectsRD::copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y, bool p_force_luminance) {
-
- zeromem(&blur.push_constant, sizeof(BlurPushConstant));
- if (p_flip_y) {
- blur.push_constant.flags |= BLUR_FLAG_FLIP_Y;
- }
- if (p_force_luminance) {
- blur.push_constant.flags |= BLUR_COPY_FORCE_LUMINANCE;
- }
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region) {
-
- zeromem(&blur.push_constant, sizeof(BlurPushConstant));
-
- if (p_region != Rect2()) {
- blur.push_constant.flags = BLUR_FLAG_USE_BLUR_SECTION;
- blur.push_constant.section[0] = p_region.position.x;
- blur.push_constant.section[1] = p_region.position.y;
- blur.push_constant.section[2] = p_region.size.width;
- blur.push_constant.section[3] = p_region.size.height;
- }
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_SIMPLY_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region) {
-
- zeromem(&blur.push_constant, sizeof(BlurPushConstant));
-
- uint32_t base_flags = 0;
- if (p_region != Rect2()) {
- base_flags = BLUR_FLAG_USE_BLUR_SECTION;
- blur.push_constant.section[0] = p_region.position.x;
- blur.push_constant.section[1] = p_region.position.y;
- blur.push_constant.section[2] = p_region.size.width;
- blur.push_constant.section[3] = p_region.size.height;
- }
-
- blur.push_constant.pixel_size[0] = p_pixel_size.x;
- blur.push_constant.pixel_size[1] = p_pixel_size.y;
-
- //HORIZONTAL
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL;
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-
- //VERTICAL
- draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_GAUSSIAN_BLUR].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- blur.push_constant.flags = base_flags;
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, 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(&blur.push_constant, sizeof(BlurPushConstant));
-
- BlurMode blur_mode = p_first_pass && p_auto_exposure.is_valid() ? BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : BLUR_MODE_GAUSSIAN_GLOW;
- uint32_t base_flags = 0;
-
- blur.push_constant.pixel_size[0] = p_pixel_size.x;
- blur.push_constant.pixel_size[1] = p_pixel_size.y;
-
- blur.push_constant.glow_strength = p_strength;
- blur.push_constant.glow_bloom = p_bloom;
- blur.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold;
- blur.push_constant.glow_hdr_scale = p_hdr_bleed_scale;
- blur.push_constant.glow_exposure = p_exposure;
- blur.push_constant.glow_white = 0; //actually unused
- blur.push_constant.glow_luminance_cap = p_luminance_cap;
- blur.push_constant.glow_auto_exposure_grey = p_auto_exposure_grey; //unused also
-
- //HORIZONTAL
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer_half, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer_half)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- if (p_auto_exposure.is_valid() && p_first_pass) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_auto_exposure), 1);
- }
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- blur.push_constant.flags = base_flags | BLUR_FLAG_HORIZONTAL | (p_first_pass ? BLUR_FLAG_GLOW_FIRST_PASS : 0);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-
- blur_mode = BLUR_MODE_GAUSSIAN_GLOW;
-
- //VERTICAL
- draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[blur_mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_rd_texture_half), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- blur.push_constant.flags = base_flags;
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, 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));
-
- roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
- roughness.push_constant.roughness = p_roughness;
- roughness.push_constant.sample_count = p_sample_count;
- roughness.push_constant.use_direct_write = p_roughness == 0.0;
- roughness.push_constant.face_size = p_size;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP]);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_framebuffer), 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
-
- int x_groups = (p_size - 1) / 8 + 1;
- int y_groups = (p_size - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1);
-
- RD::get_singleton()->compute_list_end();
-}
-
-void RasterizerEffectsRD::render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler) {
-
- zeromem(&sky.push_constant, sizeof(SkyPushConstant));
-
- sky.push_constant.proj[0] = p_camera.matrix[2][0];
- sky.push_constant.proj[1] = p_camera.matrix[0][0];
- sky.push_constant.proj[2] = p_camera.matrix[2][1];
- sky.push_constant.proj[3] = p_camera.matrix[1][1];
- sky.push_constant.alpha = p_alpha;
- sky.push_constant.depth = 1.0;
- sky.push_constant.multiplier = p_multipler;
- store_transform_3x3(p_orientation, sky.push_constant.orientation);
-
- RD::DrawListID draw_list = p_list;
-
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, sky.pipeline.get_render_pipeline(RD::INVALID_ID, p_fb_format));
-
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_panorama), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky.push_constant, sizeof(SkyPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
-}
-
-void RasterizerEffectsRD::make_mipmap(RID p_source_rd_texture, RID p_dest_framebuffer, const Vector2 &p_pixel_size) {
-
- zeromem(&blur.push_constant, sizeof(BlurPushConstant));
-
- blur.push_constant.pixel_size[0] = p_pixel_size.x;
- blur.push_constant.pixel_size[1] = p_pixel_size.y;
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blur.pipelines[BLUR_MODE_MIPMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &blur.push_constant, sizeof(BlurPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip) {
-
- CopyToDPPushConstant push_constant;
- push_constant.bias = p_bias;
- push_constant.z_far = p_z_far;
- push_constant.z_near = p_z_near;
- push_constant.z_flip = p_dp_flip;
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy.pipelines[COPY_MODE_CUBE_TO_DP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) {
-
- zeromem(&tonemap.push_constant, sizeof(TonemapPushConstant));
-
- tonemap.push_constant.use_bcs = p_settings.use_bcs;
- tonemap.push_constant.bcs[0] = p_settings.brightness;
- tonemap.push_constant.bcs[1] = p_settings.contrast;
- tonemap.push_constant.bcs[2] = p_settings.saturation;
-
- tonemap.push_constant.use_glow = p_settings.use_glow;
- tonemap.push_constant.glow_intensity = p_settings.glow_intensity;
- tonemap.push_constant.glow_level_flags = p_settings.glow_level_flags;
- tonemap.push_constant.glow_texture_size[0] = p_settings.glow_texture_size.x;
- tonemap.push_constant.glow_texture_size[1] = p_settings.glow_texture_size.y;
- tonemap.push_constant.glow_mode = p_settings.glow_mode;
-
- TonemapMode mode = p_settings.glow_use_bicubic_upscale ? TONEMAP_MODE_BICUBIC_GLOW_FILTER : TONEMAP_MODE_NORMAL;
-
- tonemap.push_constant.tonemapper = p_settings.tonemap_mode;
- tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure;
- tonemap.push_constant.exposure = p_settings.exposure;
- tonemap.push_constant.white = p_settings.white;
- tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey;
-
- tonemap.push_constant.use_color_correction = p_settings.use_color_correction;
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerEffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
-
- luminance_reduce.push_constant.source_size[0] = p_source_size.x;
- luminance_reduce.push_constant.source_size[1] = p_source_size.y;
- luminance_reduce.push_constant.max_luminance = p_max_luminance;
- luminance_reduce.push_constant.min_luminance = p_min_luminance;
- luminance_reduce.push_constant.exposure_adjust = p_adjust;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- for (int i = 0; i < p_reduce.size(); i++) {
-
- if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_READ]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_texture), 0);
- } else {
-
- RD::get_singleton()->compute_list_add_barrier(compute_list); //needs barrier, wait until previous is done
-
- if (i == p_reduce.size() - 1 && !p_set) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_WRITE]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_prev_luminance), 2);
- } else {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE]);
- }
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_reduce[i - 1]), 0);
- }
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_reduce[i]), 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &luminance_reduce.push_constant, sizeof(LuminanceReducePushConstant));
-
- int32_t x_groups = (luminance_reduce.push_constant.source_size[0] - 1) / 8 + 1;
- int32_t y_groups = (luminance_reduce.push_constant.source_size[1] - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
-
- luminance_reduce.push_constant.source_size[0] = MAX(luminance_reduce.push_constant.source_size[0] / 8, 1);
- luminance_reduce.push_constant.source_size[1] = MAX(luminance_reduce.push_constant.source_size[1] / 8, 1);
- }
-
- RD::get_singleton()->compute_list_end();
-}
-
-void RasterizerEffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_halfsize_texture1, RID p_halfsize_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, VisualServer::DOFBokehShape p_bokeh_shape, VS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal) {
-
- bokeh.push_constant.blur_far_active = p_dof_far;
- bokeh.push_constant.blur_far_begin = p_dof_far_begin;
- bokeh.push_constant.blur_far_end = p_dof_far_begin + p_dof_far_size;
-
- bokeh.push_constant.blur_near_active = p_dof_near;
- bokeh.push_constant.blur_near_begin = p_dof_near_begin;
- bokeh.push_constant.blur_near_end = MAX(0, p_dof_near_begin - p_dof_near_size);
- bokeh.push_constant.use_jitter = p_use_jitter;
- bokeh.push_constant.jitter_seed = Math::randf() * 1000.0;
-
- bokeh.push_constant.z_near = p_cam_znear;
- bokeh.push_constant.z_far = p_cam_zfar;
- bokeh.push_constant.orthogonal = p_cam_orthogonal;
- bokeh.push_constant.blur_size = p_bokeh_size;
-
- bokeh.push_constant.second_pass = false;
- bokeh.push_constant.half_size = false;
-
- bokeh.push_constant.blur_scale = 0.5;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- /* FIRST PASS */
- // The alpha channel of the source color texture is filled with the expected circle size
- // If used for DOF far, the size is positive, if used for near, its negative.
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BLUR_SIZE]);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_texture), 1);
-
- int32_t x_groups = (p_base_texture_size.x - 1) / 8 + 1;
- int32_t y_groups = (p_base_texture_size.y - 1) / 8 + 1;
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- if (p_bokeh_shape == VS::DOF_BOKEH_BOX || p_bokeh_shape == VS::DOF_BOKEH_HEXAGON) {
-
- //second pass
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[p_bokeh_shape == VS::DOF_BOKEH_BOX ? BOKEH_GEN_BOKEH_BOX : BOKEH_GEN_BOKEH_HEXAGONAL]);
-
- static const int quality_samples[4] = { 6, 12, 12, 24 };
-
- bokeh.push_constant.steps = quality_samples[p_quality];
-
- if (p_quality == VS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == VS::DOF_BLUR_QUALITY_LOW) {
- //box and hexagon are more or less the same, and they can work in either half (very low and low quality) or full (medium and high quality_ sizes)
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
-
- x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1;
- y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1;
- bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
- bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
- bokeh.push_constant.half_size = true;
- bokeh.push_constant.blur_size *= 0.5;
-
- } else {
- //medium and high quality use full size
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
- }
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //third pass
- bokeh.push_constant.second_pass = true;
-
- if (p_quality == VS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == VS::DOF_BLUR_QUALITY_LOW) {
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture2), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
- } else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 1);
- }
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- if (p_quality == VS::DOF_BLUR_QUALITY_VERY_LOW || p_quality == VS::DOF_BLUR_QUALITY_LOW) {
- //forth pass, upscale for low quality
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture2), 1);
-
- x_groups = (p_base_texture_size.x - 1) / 8 + 1;
- y_groups = (p_base_texture_size.y - 1) / 8 + 1;
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
- bokeh.push_constant.half_size = false;
- bokeh.push_constant.second_pass = false;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- }
- } else {
- //circle
-
- //second pass
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
-
- static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
-
- bokeh.push_constant.steps = 0;
- bokeh.push_constant.blur_scale = quality_scale[p_quality];
-
- //circle always runs in half size, otherwise too expensive
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_halfsize_texture1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_base_texture), 1);
-
- x_groups = ((p_base_texture_size.x >> 1) - 1) / 8 + 1;
- y_groups = ((p_base_texture_size.y >> 1) - 1) / 8 + 1;
- bokeh.push_constant.size[0] = p_base_texture_size.x >> 1;
- bokeh.push_constant.size[1] = p_base_texture_size.y >> 1;
- bokeh.push_constant.half_size = true;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- //circle is just one pass, then upscale
-
- // upscale
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.pipelines[BOKEH_COMPOSITE]);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_base_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_halfsize_texture1), 1);
-
- x_groups = (p_base_texture_size.x - 1) / 8 + 1;
- y_groups = (p_base_texture_size.y - 1) / 8 + 1;
- bokeh.push_constant.size[0] = p_base_texture_size.x;
- bokeh.push_constant.size[1] = p_base_texture_size.y;
- bokeh.push_constant.half_size = false;
- bokeh.push_constant.second_pass = false;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &bokeh.push_constant, sizeof(BokehPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- }
-
- RD::get_singleton()->compute_list_end();
-}
-
-void RasterizerEffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness) {
-
- //minify first
- ssao.minify_push_constant.orthogonal = p_projection.is_orthogonal();
- ssao.minify_push_constant.z_near = p_projection.get_z_near();
- ssao.minify_push_constant.z_far = p_projection.get_z_far();
- ssao.minify_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x;
- ssao.minify_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y;
- ssao.minify_push_constant.source_size[0] = p_depth_buffer_size.x;
- ssao.minify_push_constant.source_size[1] = p_depth_buffer_size.y;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-
- /* FIRST PASS */
- // Minify the depth buffer.
-
- for (int i = 0; i < depth_mipmaps.size(); i++) {
-
- if (i == 0) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_FIRST]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0);
- } else {
- if (i == 1) {
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_MINIFY_MIPMAP]);
- }
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i - 1]), 0);
- }
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(depth_mipmaps[i]), 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.minify_push_constant, sizeof(SSAOMinifyPushConstant));
- // shrink after set
- ssao.minify_push_constant.source_size[0] = MAX(1, ssao.minify_push_constant.source_size[0] >> 1);
- ssao.minify_push_constant.source_size[1] = MAX(1, ssao.minify_push_constant.source_size[1] >> 1);
-
- int x_groups = (ssao.minify_push_constant.source_size[0] - 1) / 8 + 1;
- int y_groups = (ssao.minify_push_constant.source_size[1] - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- }
-
- /* SECOND PASS */
- // Gather samples
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[(SSAO_GATHER_LOW + p_quality) + (p_half_size ? 4 : 0)]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 1);
- if (!p_half_size) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 2);
- }
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_normal_buffer), 3);
-
- ssao.gather_push_constant.screen_size[0] = p_depth_buffer_size.x;
- ssao.gather_push_constant.screen_size[1] = p_depth_buffer_size.y;
- if (p_half_size) {
- ssao.gather_push_constant.screen_size[0] >>= 1;
- ssao.gather_push_constant.screen_size[1] >>= 1;
- }
- ssao.gather_push_constant.z_far = p_projection.get_z_far();
- ssao.gather_push_constant.z_near = p_projection.get_z_near();
- ssao.gather_push_constant.orthogonal = p_projection.is_orthogonal();
-
- ssao.gather_push_constant.proj_info[0] = -2.0f / (ssao.gather_push_constant.screen_size[0] * p_projection.matrix[0][0]);
- ssao.gather_push_constant.proj_info[1] = -2.0f / (ssao.gather_push_constant.screen_size[1] * p_projection.matrix[1][1]);
- ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
- ssao.gather_push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
- //ssao.gather_push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
- //ssao.gather_push_constant.proj_info[3] = -(1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
-
- ssao.gather_push_constant.radius = p_radius;
-
- ssao.gather_push_constant.proj_scale = float(p_projection.get_pixels_per_meter(ssao.gather_push_constant.screen_size[0]));
- ssao.gather_push_constant.bias = p_bias;
- ssao.gather_push_constant.intensity_div_r6 = p_intensity / pow(p_radius, 6.0f);
-
- ssao.gather_push_constant.pixel_size[0] = 1.0 / p_depth_buffer_size.x;
- ssao.gather_push_constant.pixel_size[1] = 1.0 / p_depth_buffer_size.y;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant));
-
- int x_groups = (ssao.gather_push_constant.screen_size[0] - 1) / 8 + 1;
- int y_groups = (ssao.gather_push_constant.screen_size[1] - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- /* THIRD PASS */
- // Blur horizontal
-
- ssao.blur_push_constant.edge_sharpness = p_edge_sharpness;
- ssao.blur_push_constant.filter_scale = p_blur;
- ssao.blur_push_constant.screen_size[0] = ssao.gather_push_constant.screen_size[0];
- ssao.blur_push_constant.screen_size[1] = ssao.gather_push_constant.screen_size[1];
- ssao.blur_push_constant.z_far = p_projection.get_z_far();
- ssao.blur_push_constant.z_near = p_projection.get_z_near();
- ssao.blur_push_constant.orthogonal = p_projection.is_orthogonal();
- ssao.blur_push_constant.axis[0] = 1;
- ssao.blur_push_constant.axis[1] = 0;
-
- if (p_blur != VS::ENV_SSAO_BLUR_DISABLED) {
-
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[p_half_size ? SSAO_BLUR_PASS_HALF : SSAO_BLUR_PASS]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0);
- if (p_half_size) {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 1);
- } else {
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1);
- }
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao2), 3);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- RD::get_singleton()->compute_list_add_barrier(compute_list);
-
- /* THIRD PASS */
- // Blur vertical
-
- ssao.blur_push_constant.axis[0] = 0;
- ssao.blur_push_constant.axis[1] = 1;
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao2), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_ao1), 3);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- }
- if (p_half_size) { //must upscale
-
- /* FOURTH PASS */
- // upscale if half size
- //back to full size
- ssao.blur_push_constant.screen_size[0] = p_depth_buffer_size.x;
- ssao.blur_push_constant.screen_size[1] = p_depth_buffer_size.y;
-
- RD::get_singleton()->compute_list_add_barrier(compute_list);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_BLUR_UPSCALE]);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_ao1), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_upscale_buffer), 3);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_mipmaps_texture), 2);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant)); //not used but set anyway
-
- x_groups = (p_depth_buffer_size.x - 1) / 8 + 1;
- y_groups = (p_depth_buffer_size.y - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
- }
-
- RD::get_singleton()->compute_list_end();
-}
-
-void RasterizerEffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) {
-
- roughness_limiter.push_constant.screen_size[0] = p_size.x;
- roughness_limiter.push_constant.screen_size[1] = p_size.y;
- roughness_limiter.push_constant.curve = p_curve;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness_limiter.pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_normal), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_roughness), 1);
-
- int x_groups = (p_size.x - 1) / 8 + 1;
- int y_groups = (p_size.y - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness_limiter.push_constant, sizeof(RoughnessLimiterPushConstant)); //not used but set anyway
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
-
- RD::get_singleton()->compute_list_end();
-}
-
-void RasterizerEffectsRD::cubemap_downsample(RID p_source_cubemap, bool p_source_is_panorama, RID p_dest_cubemap, const Size2i &p_size) {
-
- cubemap_downsampler.push_constant.face_size = p_size.x;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipelines[p_source_is_panorama ? CUBEMAP_DOWNSAMPLER_SOURCE_PANORAMA : CUBEMAP_DOWNSAMPLER_SOURCE_CUBEMAP]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
-
- int x_groups = (p_size.x - 1) / 8 + 1;
- int y_groups = (p_size.y - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face
-
- RD::get_singleton()->compute_list_end();
-}
-
-void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
-
- Vector<RD::Uniform> uniforms;
- for (int i = 0; i < p_dest_cubemap.size(); i++) {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = i;
- u.ids.push_back(p_dest_cubemap[i]);
- uniforms.push_back(u);
- }
- if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
- RD::get_singleton()->free(filter.image_uniform_set);
- }
- filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, 0), 2);
-
- int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
- pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.pipelines[pipeline]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
-
- int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face
-
- RD::get_singleton()->compute_list_end();
-}
-
-RasterizerEffectsRD::RasterizerEffectsRD() {
-
- {
- // Initialize blur
- Vector<String> blur_modes;
- blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n");
- blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n");
- blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n#define GLOW_USE_AUTO_EXPOSURE\n");
- blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n");
- blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n");
- blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n");
- blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_LOW\n#define DOF_NEAR_BLUR_MERGE\n");
- blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_MEDIUM\n#define DOF_NEAR_BLUR_MERGE\n");
- blur_modes.push_back("\n#define MODE_DOF_NEAR_BLUR\n#define DOF_QUALITY_HIGH\n#define DOF_NEAR_BLUR_MERGE\n");
- blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_LOW\n");
- blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_MEDIUM\n");
- blur_modes.push_back("\n#define MODE_DOF_FAR_BLUR\n#define DOF_QUALITY_HIGH\n");
- blur_modes.push_back("\n#define MODE_SSAO_MERGE\n");
- blur_modes.push_back("\n#define MODE_SIMPLE_COPY\n");
- blur_modes.push_back("\n#define MODE_MIPMAP\n");
-
- blur.shader.initialize(blur_modes);
- zeromem(&blur.push_constant, sizeof(BlurPushConstant));
- blur.shader_version = blur.shader.version_create();
-
- for (int i = 0; i < BLUR_MODE_MAX; i++) {
- blur.pipelines[i].setup(blur.shader.version_get_shader(blur.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
-
- {
- // Initialize roughness
- Vector<String> cubemap_roughness_modes;
- cubemap_roughness_modes.push_back("\n#define MODE_SOURCE_PANORAMA\n");
- cubemap_roughness_modes.push_back("\n#define MODE_SOURCE_CUBEMAP\n");
- roughness.shader.initialize(cubemap_roughness_modes);
-
- roughness.shader_version = roughness.shader.version_create();
-
- for (int i = 0; i < CUBEMAP_ROUGHNESS_SOURCE_MAX; i++) {
- roughness.pipelines[i] = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, i));
- }
- }
-
- {
- // Initialize sky
- Vector<String> sky_modes;
- sky_modes.push_back("");
- sky.shader.initialize(sky_modes);
-
- sky.shader_version = sky.shader.version_create();
-
- RD::PipelineDepthStencilState depth_stencil_state;
-
- depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
-
- sky.pipeline.setup(sky.shader.version_get_shader(sky.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0);
- }
-
- {
- // Initialize tonemapper
- Vector<String> tonemap_modes;
- tonemap_modes.push_back("\n");
- tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n");
-
- tonemap.shader.initialize(tonemap_modes);
-
- tonemap.shader_version = tonemap.shader.version_create();
-
- for (int i = 0; i < TONEMAP_MODE_MAX; i++) {
- tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
-
- {
- // Initialize luminance_reduce
- Vector<String> luminance_reduce_modes;
- luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n");
- luminance_reduce_modes.push_back("\n");
- luminance_reduce_modes.push_back("\n#define WRITE_LUMINANCE\n");
-
- luminance_reduce.shader.initialize(luminance_reduce_modes);
-
- luminance_reduce.shader_version = luminance_reduce.shader.version_create();
-
- for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) {
- luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i));
- }
- }
-
- {
- // Initialize copier
- Vector<String> copy_modes;
- copy_modes.push_back("\n#define MODE_CUBE_TO_DP\n");
-
- copy.shader.initialize(copy_modes);
-
- copy.shader_version = copy.shader.version_create();
-
- for (int i = 0; i < COPY_MODE_MAX; i++) {
- copy.pipelines[i].setup(copy.shader.version_get_shader(copy.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
- }
- }
-
- {
- // Initialize bokeh
- Vector<String> bokeh_modes;
- bokeh_modes.push_back("\n#define MODE_GEN_BLUR_SIZE\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_BOX\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_HEXAGONAL\n");
- bokeh_modes.push_back("\n#define MODE_BOKEH_CIRCULAR\n");
- bokeh_modes.push_back("\n#define MODE_COMPOSITE_BOKEH\n");
-
- bokeh.shader.initialize(bokeh_modes);
-
- bokeh.shader_version = bokeh.shader.version_create();
-
- for (int i = 0; i < BOKEH_MAX; i++) {
- bokeh.pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.shader.version_get_shader(bokeh.shader_version, i));
- }
- }
-
- {
- // Initialize ssao
- uint32_t pipeline = 0;
- {
- Vector<String> ssao_modes;
- ssao_modes.push_back("\n#define MINIFY_START\n");
- ssao_modes.push_back("\n");
-
- ssao.minify_shader.initialize(ssao_modes);
-
- ssao.minify_shader_version = ssao.minify_shader.version_create();
-
- for (int i = 0; i <= SSAO_MINIFY_MIPMAP; i++) {
- ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.minify_shader.version_get_shader(ssao.minify_shader_version, i));
- pipeline++;
- }
- }
- {
- Vector<String> ssao_modes;
- ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n");
- ssao_modes.push_back("\n");
- ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n");
- ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n");
- ssao_modes.push_back("\n#define SSAO_QUALITY_LOW\n#define USE_HALF_SIZE\n");
- ssao_modes.push_back("\n#define USE_HALF_SIZE\n");
- ssao_modes.push_back("\n#define SSAO_QUALITY_HIGH\n#define USE_HALF_SIZE\n");
- ssao_modes.push_back("\n#define SSAO_QUALITY_ULTRA\n#define USE_HALF_SIZE\n");
-
- ssao.gather_shader.initialize(ssao_modes);
-
- ssao.gather_shader_version = ssao.gather_shader.version_create();
-
- for (int i = SSAO_GATHER_LOW; i <= SSAO_GATHER_ULTRA_HALF; i++) {
- ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i - SSAO_GATHER_LOW));
- pipeline++;
- }
- }
- {
- Vector<String> ssao_modes;
- ssao_modes.push_back("\n#define MODE_FULL_SIZE\n");
- ssao_modes.push_back("\n");
- ssao_modes.push_back("\n#define MODE_UPSCALE\n");
-
- ssao.blur_shader.initialize(ssao_modes);
-
- ssao.blur_shader_version = ssao.blur_shader.version_create();
-
- for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_UPSCALE; i++) {
- ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS));
- pipeline++;
- }
- }
-
- ERR_FAIL_COND(pipeline != SSAO_MAX);
- }
-
- {
- // Initialize roughness limiter
- Vector<String> shader_modes;
- shader_modes.push_back("");
-
- roughness_limiter.shader.initialize(shader_modes);
-
- roughness_limiter.shader_version = roughness_limiter.shader.version_create();
-
- roughness_limiter.pipeline = RD::get_singleton()->compute_pipeline_create(roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0));
- }
-
- {
- //Initialize cubemap downsampler
- Vector<String> cubemap_downsampler_modes;
- cubemap_downsampler_modes.push_back("\n#define MODE_SOURCE_PANORAMA\n");
- cubemap_downsampler_modes.push_back("\n#define MODE_SOURCE_CUBEMAP\n");
- cubemap_downsampler.shader.initialize(cubemap_downsampler_modes);
-
- cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create();
-
- for (int i = 0; i < CUBEMAP_DOWNSAMPLER_SOURCE_MAX; i++) {
- cubemap_downsampler.pipelines[i] = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, i));
- }
- }
-
- {
- // Initialize cubemap filter
- filter.use_high_quality = GLOBAL_GET("rendering/quality/reflections/fast_filter_high_quality");
-
- Vector<String> cubemap_filter_modes;
- cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n");
- cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
- cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
- cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
- filter.shader.initialize(cubemap_filter_modes);
- filter.shader_version = filter.shader.version_create();
-
- for (int i = 0; i < FILTER_MODE_MAX; i++) {
- filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.shader.version_get_shader(filter.shader_version, i));
- }
-
- if (filter.use_high_quality) {
- filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
- RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0], false);
- } else {
- filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs));
- RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0], false);
- }
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.ids.push_back(filter.coefficient_buffer);
- uniforms.push_back(u);
- }
- filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
- }
-
- RD::SamplerState sampler;
- sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.max_lod = 0;
-
- default_sampler = RD::get_singleton()->sampler_create(sampler);
-
- sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.max_lod = 1e20;
-
- default_mipmap_sampler = RD::get_singleton()->sampler_create(sampler);
-
- { //create index array for copy shaders
- Vector<uint8_t> pv;
- pv.resize(6 * 4);
- {
- uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
- }
- index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
- index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6);
- }
-}
-
-RasterizerEffectsRD::~RasterizerEffectsRD() {
- if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
- RD::get_singleton()->free(filter.image_uniform_set);
- }
-
- if (RD::get_singleton()->uniform_set_is_valid(filter.uniform_set)) {
- RD::get_singleton()->free(filter.uniform_set);
- }
-
- RD::get_singleton()->free(default_sampler);
- RD::get_singleton()->free(default_mipmap_sampler);
- RD::get_singleton()->free(index_buffer); //array gets freed as dependency
- RD::get_singleton()->free(filter.coefficient_buffer);
- blur.shader.version_free(blur.shader_version);
- roughness.shader.version_free(roughness.shader_version);
- sky.shader.version_free(sky.shader_version);
- tonemap.shader.version_free(tonemap.shader_version);
- luminance_reduce.shader.version_free(luminance_reduce.shader_version);
- copy.shader.version_free(copy.shader_version);
- bokeh.shader.version_free(bokeh.shader_version);
- ssao.minify_shader.version_free(ssao.minify_shader_version);
- ssao.gather_shader.version_free(ssao.gather_shader_version);
- ssao.blur_shader.version_free(ssao.blur_shader_version);
- roughness_limiter.shader.version_free(roughness_limiter.shader_version);
- cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
- filter.shader.version_free(filter.shader_version);
-}
diff --git a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h b/servers/visual/rasterizer_rd/rasterizer_effects_rd.h
deleted file mode 100644
index fbf6b39ecb..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_effects_rd.h
+++ /dev/null
@@ -1,478 +0,0 @@
-/*************************************************************************/
-/* rasterizer_effects_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_EFFECTS_RD_H
-#define RASTERIZER_EFFECTS_RD_H
-
-#include "core/math/camera_matrix.h"
-#include "render_pipeline_vertex_format_cache_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/blur.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/bokeh_dof.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/copy.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/cubemap_downsampler.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/cubemap_filter.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/luminance_reduce.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/roughness_limiter.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/sky.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/ssao.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/ssao_blur.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/ssao_minify.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/tonemap.glsl.gen.h"
-
-#include "servers/visual_server.h"
-
-class RasterizerEffectsRD {
-
- enum BlurMode {
- BLUR_MODE_GAUSSIAN_BLUR,
- BLUR_MODE_GAUSSIAN_GLOW,
- BLUR_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE,
- BLUR_MODE_DOF_NEAR_LOW,
- BLUR_MODE_DOF_NEAR_MEDIUM,
- BLUR_MODE_DOF_NEAR_HIGH,
- BLUR_MODE_DOF_NEAR_MERGE_LOW,
- BLUR_MODE_DOF_NEAR_MERGE_MEDIUM,
- BLUR_MODE_DOF_NEAR_MERGE_HIGH,
- BLUR_MODE_DOF_FAR_LOW,
- BLUR_MODE_DOF_FAR_MEDIUM,
- BLUR_MODE_DOF_FAR_HIGH,
- BLUR_MODE_SSAO_MERGE,
- BLUR_MODE_SIMPLY_COPY,
- BLUR_MODE_MIPMAP,
- BLUR_MODE_MAX,
-
- };
-
- enum {
- BLUR_FLAG_HORIZONTAL = (1 << 0),
- BLUR_FLAG_USE_BLUR_SECTION = (1 << 1),
- BLUR_FLAG_USE_ORTHOGONAL_PROJECTION = (1 << 2),
- BLUR_FLAG_DOF_NEAR_FIRST_TAP = (1 << 3),
- BLUR_FLAG_GLOW_FIRST_PASS = (1 << 4),
- BLUR_FLAG_FLIP_Y = (1 << 5),
- BLUR_COPY_FORCE_LUMINANCE = (1 << 6)
- };
-
- struct BlurPushConstant {
- float section[4];
- float pixel_size[2];
- uint32_t flags;
- uint32_t pad;
- //glow
- float glow_strength;
- float glow_bloom;
- float glow_hdr_threshold;
- float glow_hdr_scale;
- float glow_exposure;
- float glow_white;
- float glow_luminance_cap;
- float glow_auto_exposure_grey;
- //dof
- float dof_begin;
- float dof_end;
- float dof_radius;
- float dof_pad;
-
- float dof_dir[2];
- float camera_z_far;
- float camera_z_near;
-
- float ssao_color[4];
- };
-
- struct Blur {
- BlurPushConstant push_constant;
- BlurShaderRD shader;
- RID shader_version;
- RenderPipelineVertexFormatCacheRD pipelines[BLUR_MODE_MAX];
-
- } blur;
-
- enum CubemapRoughnessSource {
- CUBEMAP_ROUGHNESS_SOURCE_PANORAMA,
- CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP,
- CUBEMAP_ROUGHNESS_SOURCE_MAX
- };
-
- struct CubemapRoughnessPushConstant {
- uint32_t face_id;
- uint32_t sample_count;
- float roughness;
- uint32_t use_direct_write;
- float face_size;
- float pad[3];
- };
-
- struct CubemapRoughness {
-
- CubemapRoughnessPushConstant push_constant;
- CubemapRoughnessShaderRD shader;
- RID shader_version;
- RID pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX];
- } roughness;
-
- struct SkyPushConstant {
- float orientation[12];
- float proj[4];
- float multiplier;
- float alpha;
- float depth;
- float pad;
- };
-
- struct Sky {
-
- SkyPushConstant push_constant;
- SkyShaderRD shader;
- RID shader_version;
- RenderPipelineVertexFormatCacheRD pipeline;
- } sky;
-
- enum TonemapMode {
- TONEMAP_MODE_NORMAL,
- TONEMAP_MODE_BICUBIC_GLOW_FILTER,
- TONEMAP_MODE_MAX
- };
-
- struct TonemapPushConstant {
- float bcs[3];
- uint32_t use_bcs;
-
- uint32_t use_glow;
- uint32_t use_auto_exposure;
- uint32_t use_color_correction;
- uint32_t tonemapper;
-
- uint32_t glow_texture_size[2];
-
- float glow_intensity;
- uint32_t glow_level_flags;
- uint32_t glow_mode;
-
- float exposure;
- float white;
- float auto_exposure_grey;
- };
-
- struct Tonemap {
-
- TonemapPushConstant push_constant;
- TonemapShaderRD shader;
- RID shader_version;
- RenderPipelineVertexFormatCacheRD pipelines[TONEMAP_MODE_MAX];
- } tonemap;
-
- enum LuminanceReduceMode {
- LUMINANCE_REDUCE_READ,
- LUMINANCE_REDUCE,
- LUMINANCE_REDUCE_WRITE,
- LUMINANCE_REDUCE_MAX
- };
-
- struct LuminanceReducePushConstant {
- int32_t source_size[2];
- float max_luminance;
- float min_luminance;
- float exposure_adjust;
- float pad[3];
- };
-
- struct LuminanceReduce {
-
- LuminanceReducePushConstant push_constant;
- LuminanceReduceShaderRD shader;
- RID shader_version;
- RID pipelines[LUMINANCE_REDUCE_MAX];
- } luminance_reduce;
-
- struct CopyToDPPushConstant {
- float bias;
- float z_far;
- float z_near;
- uint32_t z_flip;
- };
-
- enum CopyMode {
- COPY_MODE_CUBE_TO_DP,
- COPY_MODE_MAX
- };
-
- struct Copy {
-
- CopyShaderRD shader;
- RID shader_version;
- RenderPipelineVertexFormatCacheRD pipelines[COPY_MODE_MAX];
- } copy;
-
- struct BokehPushConstant {
- uint32_t size[2];
- float z_far;
- float z_near;
-
- uint32_t orthogonal;
- float blur_size;
- float blur_scale;
- uint32_t steps;
-
- uint32_t blur_near_active;
- float blur_near_begin;
- float blur_near_end;
- uint32_t blur_far_active;
-
- float blur_far_begin;
- float blur_far_end;
- uint32_t second_pass;
- uint32_t half_size;
-
- uint32_t use_jitter;
- float jitter_seed;
- uint32_t pad[2];
- };
-
- enum BokehMode {
- BOKEH_GEN_BLUR_SIZE,
- BOKEH_GEN_BOKEH_BOX,
- BOKEH_GEN_BOKEH_HEXAGONAL,
- BOKEH_GEN_BOKEH_CIRCULAR,
- BOKEH_COMPOSITE,
- BOKEH_MAX
- };
-
- struct Bokeh {
-
- BokehPushConstant push_constant;
- BokehDofShaderRD shader;
- RID shader_version;
- RID pipelines[BOKEH_MAX];
- } bokeh;
-
- enum SSAOMode {
- SSAO_MINIFY_FIRST,
- SSAO_MINIFY_MIPMAP,
- SSAO_GATHER_LOW,
- SSAO_GATHER_MEDIUM,
- SSAO_GATHER_HIGH,
- SSAO_GATHER_ULTRA,
- SSAO_GATHER_LOW_HALF,
- SSAO_GATHER_MEDIUM_HALF,
- SSAO_GATHER_HIGH_HALF,
- SSAO_GATHER_ULTRA_HALF,
- SSAO_BLUR_PASS,
- SSAO_BLUR_PASS_HALF,
- SSAO_BLUR_UPSCALE,
- SSAO_MAX
- };
-
- struct SSAOMinifyPushConstant {
- float pixel_size[2];
- float z_far;
- float z_near;
- int32_t source_size[2];
- uint32_t orthogonal;
- uint32_t pad;
- };
-
- struct SSAOGatherPushConstant {
- int32_t screen_size[2];
- float z_far;
- float z_near;
-
- uint32_t orthogonal;
- float intensity_div_r6;
- float radius;
- float bias;
-
- float proj_info[4];
- float pixel_size[2];
- float proj_scale;
- uint32_t pad;
- };
-
- struct SSAOBlurPushConstant {
- float edge_sharpness;
- int32_t filter_scale;
- float z_far;
- float z_near;
- uint32_t orthogonal;
- uint32_t pad[3];
- int32_t axis[2];
- int32_t screen_size[2];
- };
-
- struct SSAO {
-
- SSAOMinifyPushConstant minify_push_constant;
- SsaoMinifyShaderRD minify_shader;
- RID minify_shader_version;
-
- SSAOGatherPushConstant gather_push_constant;
- SsaoShaderRD gather_shader;
- RID gather_shader_version;
-
- SSAOBlurPushConstant blur_push_constant;
- SsaoBlurShaderRD blur_shader;
- RID blur_shader_version;
-
- RID pipelines[SSAO_MAX];
- } ssao;
-
- struct RoughnessLimiterPushConstant {
- int32_t screen_size[2];
- float curve;
- uint32_t pad;
- };
-
- struct RoughnessLimiter {
-
- RoughnessLimiterPushConstant push_constant;
- RoughnessLimiterShaderRD shader;
- RID shader_version;
- RID pipeline;
-
- } roughness_limiter;
-
- enum CubemapDownsamplerSource {
- CUBEMAP_DOWNSAMPLER_SOURCE_PANORAMA,
- CUBEMAP_DOWNSAMPLER_SOURCE_CUBEMAP,
- CUBEMAP_DOWNSAMPLER_SOURCE_MAX
- };
-
- struct CubemapDownsamplerPushConstant {
- uint32_t face_size;
- float pad[3];
- };
-
- struct CubemapDownsampler {
-
- CubemapDownsamplerPushConstant push_constant;
- CubemapDownsamplerShaderRD shader;
- RID shader_version;
- RID pipelines[CUBEMAP_DOWNSAMPLER_SOURCE_MAX];
-
- } cubemap_downsampler;
-
- enum CubemapFilterMode {
- FILTER_MODE_HIGH_QUALITY,
- FILTER_MODE_LOW_QUALITY,
- FILTER_MODE_HIGH_QUALITY_ARRAY,
- FILTER_MODE_LOW_QUALITY_ARRAY,
- FILTER_MODE_MAX,
- };
-
- struct CubemapFilter {
-
- CubemapFilterShaderRD shader;
- RID shader_version;
- RID pipelines[FILTER_MODE_MAX];
- RID uniform_set;
- RID image_uniform_set;
- RID coefficient_buffer;
- bool use_high_quality;
-
- } filter;
-
- RID default_sampler;
- RID default_mipmap_sampler;
- RID index_buffer;
- RID index_array;
-
- Map<RID, RID> texture_to_uniform_set_cache;
-
- Map<RID, RID> image_to_uniform_set_cache;
- Map<RID, RID> texture_to_compute_uniform_set_cache;
-
- RID _get_uniform_set_from_image(RID p_texture);
- RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
- RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
-
-public:
- //TODO must re-do most of the shaders in compute
-
- void region_copy(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_region);
- void copy_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, bool p_flip_y = false, bool p_force_luminance = false);
- void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region);
- void gaussian_glow(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
-
- void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
- void render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler);
- void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size);
- void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip);
- void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
- void bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i &p_base_texture_size, RID p_secondary_texture, RID p_bokeh_texture1, RID p_bokeh_texture2, bool p_dof_far, float p_dof_far_begin, float p_dof_far_size, bool p_dof_near, float p_dof_near_begin, float p_dof_near_size, float p_bokeh_size, VS::DOFBokehShape p_bokeh_shape, VS::DOFBlurQuality p_quality, bool p_use_jitter, float p_cam_znear, float p_cam_zfar, bool p_cam_orthogonal);
-
- struct TonemapSettings {
-
- bool use_glow = false;
- enum GlowMode {
- GLOW_MODE_ADD,
- GLOW_MODE_SCREEN,
- GLOW_MODE_SOFTLIGHT,
- GLOW_MODE_REPLACE,
- GLOW_MODE_MIX
- };
-
- GlowMode glow_mode = GLOW_MODE_ADD;
- float glow_intensity = 1.0;
- uint32_t glow_level_flags = 0;
- Vector2i glow_texture_size;
- bool glow_use_bicubic_upscale = false;
- RID glow_texture;
-
- VS::EnvironmentToneMapper tonemap_mode = VS::ENV_TONE_MAPPER_LINEAR;
- float exposure = 1.0;
- float white = 1.0;
-
- bool use_auto_exposure = false;
- float auto_exposure_grey = 0.5;
- RID exposure_texture;
-
- bool use_bcs = false;
- float brightness = 1.0;
- float contrast = 1.0;
- float saturation = 1.0;
-
- bool use_color_correction = false;
- RID color_correction_texture;
- };
-
- void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings);
-
- void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, const Size2i &p_depth_buffer_size, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao1, bool p_half_size, RID p_ao2, RID p_upscale_buffer, float p_intensity, float p_radius, float p_bias, const CameraMatrix &p_projection, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_edge_sharpness);
-
- void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
- void cubemap_downsample(RID p_source_cubemap, bool p_source_is_panorama, RID p_dest_cubemap, const Size2i &p_size);
- void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
-
- RasterizerEffectsRD();
- ~RasterizerEffectsRD();
-};
-
-#endif // EFFECTS_RD_H
diff --git a/servers/visual/rasterizer_rd/rasterizer_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_rd.cpp
deleted file mode 100644
index 206320376b..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_rd.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*************************************************************************/
-/* rasterizer_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer_rd.h"
-
-void RasterizerRD::prepare_for_blitting_render_targets() {
- RD::get_singleton()->prepare_screen_for_drawing();
-}
-
-void RasterizerRD::blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) {
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen);
-
- for (int i = 0; i < p_amount; i++) {
- RID texture = storage->render_target_get_texture(p_render_targets[i].render_target);
- ERR_CONTINUE(texture.is_null());
- RID rd_texture = storage->texture_get_rd_texture(texture);
- ERR_CONTINUE(rd_texture.is_null());
- if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) {
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
- u.binding = 0;
- u.ids.push_back(copy_viewports_sampler);
- u.ids.push_back(rd_texture);
- uniforms.push_back(u);
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, copy_viewports_rd_shader, 0);
-
- render_target_descriptors[rd_texture] = uniform_set;
- }
-
- Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen));
-
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_viewports_rd_pipeline);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, copy_viewports_rd_array);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0);
-
- float push_constant[4] = {
- p_render_targets[i].rect.position.x / screen_size.width,
- p_render_targets[i].rect.position.y / screen_size.height,
- p_render_targets[i].rect.size.width / screen_size.width,
- p_render_targets[i].rect.size.height / screen_size.height,
- };
- RD::get_singleton()->draw_list_set_push_constant(draw_list, push_constant, 4 * sizeof(float));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- }
-
- RD::get_singleton()->draw_list_end();
-}
-
-void RasterizerRD::begin_frame(double frame_step) {
- frame++;
- time += frame_step;
- canvas->set_time(time);
- scene->set_time(time, frame_step);
-}
-
-void RasterizerRD::end_frame(bool p_swap_buffers) {
-
-#ifndef _MSC_VER
-#warning TODO: likely passa bool to swap buffers to avoid display?
-#endif
- RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?
-}
-
-void RasterizerRD::initialize() {
-
- { //create framebuffer copy shader
- RenderingDevice::ShaderStageData vert;
- vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX;
- vert.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_VERTEX,
- "#version 450\n"
- "layout(push_constant, binding = 0, std140) uniform Pos { vec4 dst_rect; } pos;\n"
- "layout(location =0) out vec2 uv;\n"
- "void main() { \n"
- " vec2 base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0));\n"
- " uv = base_arr[gl_VertexIndex];\n"
- " vec2 vtx = pos.dst_rect.xy+uv*pos.dst_rect.zw;\n"
- " gl_Position = vec4(vtx * 2.0 - 1.0,0.0,1.0);\n"
- "}\n");
-
- RenderingDevice::ShaderStageData frag;
- frag.shader_stage = RenderingDevice::SHADER_STAGE_FRAGMENT;
- frag.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_FRAGMENT,
- "#version 450\n"
- "layout (location = 0) in vec2 uv;\n"
- "layout (location = 0) out vec4 color;\n"
- "layout (binding = 0) uniform sampler2D src_rt;\n"
- "void main() { color=texture(src_rt,uv); }\n");
-
- Vector<RenderingDevice::ShaderStageData> source;
- source.push_back(vert);
- source.push_back(frag);
- String error;
- copy_viewports_rd_shader = RD::get_singleton()->shader_create(source);
- if (!copy_viewports_rd_shader.is_valid()) {
- print_line("Failed compilation: " + error);
- }
- }
-
- { //create index array for copy shader
- Vector<uint8_t> pv;
- pv.resize(6 * 4);
- {
- uint8_t *w = pv.ptrw();
- int *p32 = (int *)w;
- p32[0] = 0;
- p32[1] = 1;
- p32[2] = 2;
- p32[3] = 0;
- p32[4] = 2;
- p32[5] = 3;
- }
- copy_viewports_rd_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
- copy_viewports_rd_array = RD::get_singleton()->index_array_create(copy_viewports_rd_index_buffer, 0, 6);
- }
-
- { //pipeline
- copy_viewports_rd_pipeline = RD::get_singleton()->render_pipeline_create(copy_viewports_rd_shader, RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
- }
- { // sampler
- copy_viewports_sampler = RD::get_singleton()->sampler_create(RD::SamplerState());
- }
-}
-
-ThreadWorkPool RasterizerRD::thread_work_pool;
-uint32_t RasterizerRD::frame = 1;
-
-void RasterizerRD::finalize() {
-
- thread_work_pool.finish();
-
- memdelete(scene);
- memdelete(canvas);
- memdelete(storage);
-
- //only need to erase these, the rest are erased by cascade
- RD::get_singleton()->free(copy_viewports_rd_index_buffer);
- RD::get_singleton()->free(copy_viewports_rd_shader);
- RD::get_singleton()->free(copy_viewports_sampler);
-}
-
-RasterizerRD::RasterizerRD() {
- thread_work_pool.init();
- time = 0;
-
- storage = memnew(RasterizerStorageRD);
- canvas = memnew(RasterizerCanvasRD(storage));
- scene = memnew(RasterizerSceneHighEndRD(storage));
-}
diff --git a/servers/visual/rasterizer_rd/rasterizer_rd.h b/servers/visual/rasterizer_rd/rasterizer_rd.h
deleted file mode 100644
index d14e9fb36e..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_rd.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*************************************************************************/
-/* rasterizer_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_RD_H
-#define RASTERIZER_RD_H
-
-#include "core/os/os.h"
-#include "core/thread_work_pool.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual/rasterizer_rd/rasterizer_canvas_rd.h"
-#include "servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.h"
-#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-
-class RasterizerRD : public Rasterizer {
-protected:
- RasterizerCanvasRD *canvas;
- RasterizerStorageRD *storage;
- RasterizerSceneHighEndRD *scene;
-
- RID copy_viewports_rd_shader;
- RID copy_viewports_rd_pipeline;
- RID copy_viewports_rd_index_buffer;
- RID copy_viewports_rd_array;
- RID copy_viewports_sampler;
-
- Map<RID, RID> render_target_descriptors;
-
- double time;
-
- static uint32_t frame;
-
-public:
- RasterizerStorage *get_storage() { return storage; }
- RasterizerCanvas *get_canvas() { return canvas; }
- RasterizerScene *get_scene() { return scene; }
-
- void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {}
-
- void initialize();
- void begin_frame(double frame_step);
- void prepare_for_blitting_render_targets();
- void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount);
-
- void end_frame(bool p_swap_buffers);
- void finalize();
-
- static _ALWAYS_INLINE_ uint64_t get_frame_number() { return frame; }
-
- static Error is_viable() {
- return OK;
- }
-
- static Rasterizer *_create_current() {
- return memnew(RasterizerRD);
- }
-
- static void make_current() {
- _create_func = _create_current;
- }
-
- virtual bool is_low_end() const { return false; }
-
- static ThreadWorkPool thread_work_pool;
-
- RasterizerRD();
- ~RasterizerRD() {}
-};
-#endif // RASTERIZER_RD_H
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
deleted file mode 100644
index 0a3105b143..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ /dev/null
@@ -1,2722 +0,0 @@
-/*************************************************************************/
-/* rasterizer_scene_high_end_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer_scene_high_end_rd.h"
-#include "core/project_settings.h"
-#include "servers/visual/rendering_device.h"
-#include "servers/visual/visual_server_raster.h"
-
-static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) {
- p_array[0] = p_mtx.basis.elements[0][0];
- p_array[1] = p_mtx.basis.elements[1][0];
- p_array[2] = p_mtx.basis.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_mtx.basis.elements[0][1];
- p_array[5] = p_mtx.basis.elements[1][1];
- p_array[6] = p_mtx.basis.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_mtx.basis.elements[0][2];
- p_array[9] = p_mtx.basis.elements[1][2];
- p_array[10] = p_mtx.basis.elements[2][2];
- p_array[11] = 0;
- p_array[12] = p_mtx.origin.x;
- p_array[13] = p_mtx.origin.y;
- p_array[14] = p_mtx.origin.z;
- p_array[15] = 1;
-}
-
-static _FORCE_INLINE_ void store_transform_3x3(const Transform &p_mtx, float *p_array) {
- p_array[0] = p_mtx.basis.elements[0][0];
- p_array[1] = p_mtx.basis.elements[1][0];
- p_array[2] = p_mtx.basis.elements[2][0];
- p_array[3] = 0;
- p_array[4] = p_mtx.basis.elements[0][1];
- p_array[5] = p_mtx.basis.elements[1][1];
- p_array[6] = p_mtx.basis.elements[2][1];
- p_array[7] = 0;
- p_array[8] = p_mtx.basis.elements[0][2];
- p_array[9] = p_mtx.basis.elements[1][2];
- p_array[10] = p_mtx.basis.elements[2][2];
- p_array[11] = 0;
-}
-
-static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
-
- p_array[i * 4 + j] = p_mtx.matrix[i][j];
- }
- }
-}
-void RasterizerSceneHighEndRD::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 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_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["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["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["NORMALMAP"] = &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;
-
- RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::singleton;
-
- Error err = scene_singleton->shader.compiler.compile(VS::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
-
- 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;
- }
-
- 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 = RD::PipelineColorBlendState::create_disabled(1);
- RD::PipelineColorBlendState blend_state_depth_normal_roughness = 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 < VS::PRIMITIVE_MAX; j++) {
-
- RD::RenderPrimitive primitive_rd_table[VS::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++) {
-
- 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;
-
- if (uses_alpha || uses_blend_alpha) {
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_VCT_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 (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL || 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_VCT_COLOR_PASS || 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) {
- blend_state = blend_state_depth_normal;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
- blend_state = blend_state_depth_normal;
- } 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 {
- //specular write
- blend_state = blend_state_opaque_specular;
- }
- }
-
- RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, RD::PipelineMultisampleState(), depth_stencil, blend_state, 0);
- }
- }
- }
-
- valid = true;
-}
-
-void RasterizerSceneHighEndRD::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 RasterizerSceneHighEndRD::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().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);
- }
-}
-
-bool RasterizerSceneHighEndRD::ShaderData::is_param_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
-bool RasterizerSceneHighEndRD::ShaderData::is_animated() const {
- return false;
-}
-bool RasterizerSceneHighEndRD::ShaderData::casts_shadows() const {
- return false;
-}
-Variant RasterizerSceneHighEndRD::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();
-}
-
-RasterizerSceneHighEndRD::ShaderData::ShaderData() {
- valid = false;
- uses_screen_texture = false;
-}
-
-RasterizerSceneHighEndRD::ShaderData::~ShaderData() {
- RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::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);
- }
-}
-
-RasterizerStorageRD::ShaderData *RasterizerSceneHighEndRD::_create_shader_func() {
- ShaderData *shader_data = memnew(ShaderData);
- return shader_data;
-}
-
-void RasterizerSceneHighEndRD::MaterialData::set_render_priority(int p_priority) {
- priority = p_priority - VS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
-}
-
-void RasterizerSceneHighEndRD::MaterialData::set_next_pass(RID p_pass) {
- next_pass = p_pass;
-}
-
-void RasterizerSceneHighEndRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
-
- RasterizerSceneHighEndRD *scene_singleton = (RasterizerSceneHighEndRD *)RasterizerSceneHighEndRD::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());
- }
-
- 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.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.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);
-}
-RasterizerSceneHighEndRD::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);
- }
-}
-
-RasterizerStorageRD::MaterialData *RasterizerSceneHighEndRD::_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;
-}
-
-RasterizerSceneHighEndRD::RenderBufferDataHighEnd::~RenderBufferDataHighEnd() {
- clear();
-}
-
-void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::ensure_specular() {
-
- if (!specular.is_valid()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = width;
- tf.height = height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- specular = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- Vector<RID> fb;
- fb.push_back(color);
- fb.push_back(specular);
- fb.push_back(depth);
-
- color_specular_fb = RD::get_singleton()->framebuffer_create(fb);
- }
-}
-
-void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::clear() {
-
- if (specular.is_valid()) {
- RD::get_singleton()->free(specular);
- specular = RID();
- }
-
- color_specular_fb = RID();
- color_fb = RID();
-
- if (normal_buffer.is_valid()) {
- RD::get_singleton()->free(normal_buffer);
- normal_buffer = RID();
- depth_normal_fb = RID();
- }
-
- if (roughness_buffer.is_valid()) {
- RD::get_singleton()->free(roughness_buffer);
- roughness_buffer = RID();
- depth_normal_roughness_fb = RID();
- }
-}
-
-void RasterizerSceneHighEndRD::RenderBufferDataHighEnd::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, VS::ViewportMSAA p_msaa) {
- clear();
-
- width = p_width;
- height = p_height;
-
- color = p_color_buffer;
- depth = p_depth_buffer;
-
- {
- Vector<RID> fb;
- fb.push_back(p_color_buffer);
- fb.push_back(depth);
-
- color_fb = RD::get_singleton()->framebuffer_create(fb);
- }
- {
- Vector<RID> fb;
- fb.push_back(depth);
-
- depth_fb = RD::get_singleton()->framebuffer_create(fb);
- }
-}
-
-void RasterizerSceneHighEndRD::_allocate_normal_texture(RenderBufferDataHighEnd *rb) {
- if (rb->normal_buffer.is_valid()) {
- return;
- }
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
- tf.width = rb->width;
- tf.height = rb->height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- rb->normal_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- Vector<RID> fb;
- fb.push_back(rb->depth);
- fb.push_back(rb->normal_buffer);
- rb->depth_normal_fb = RD::get_singleton()->framebuffer_create(fb);
-
- _render_buffers_clear_uniform_set(rb);
-}
-
-void RasterizerSceneHighEndRD::_allocate_roughness_texture(RenderBufferDataHighEnd *rb) {
-
- if (rb->roughness_buffer.is_valid()) {
- return;
- }
-
- ERR_FAIL_COND(rb->normal_buffer.is_null());
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = rb->width;
- tf.height = rb->height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- rb->roughness_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- Vector<RID> fb;
- fb.push_back(rb->depth);
- fb.push_back(rb->normal_buffer);
- fb.push_back(rb->roughness_buffer);
- rb->depth_normal_roughness_fb = RD::get_singleton()->framebuffer_create(fb);
-
- _render_buffers_clear_uniform_set(rb);
-}
-
-RasterizerSceneRD::RenderBufferData *RasterizerSceneHighEndRD::_create_render_buffer_data() {
- return memnew(RenderBufferDataHighEnd);
-}
-
-bool RasterizerSceneHighEndRD::free(RID p_rid) {
- if (RasterizerSceneRD::free(p_rid)) {
- return true;
- }
- return false;
-}
-
-void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth) {
-
- for (int i = 0; i < p_element_count; i++) {
-
- const RenderList::Element *e = p_elements[i];
- InstanceData &id = scene_state.instances[i];
- store_transform(e->instance->transform, id.transform);
- store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
- id.flags = 0;
- id.mask = e->instance->layer_mask;
-
- if (e->instance->base_type == VS::INSTANCE_MULTIMESH) {
- id.flags |= INSTANCE_DATA_FLAG_MULTIMESH;
- uint32_t stride;
- if (storage->multimesh_get_transform_format(e->instance->base) == VS::MULTIMESH_TRANSFORM_2D) {
- id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
- stride = 2;
- } else {
- stride = 3;
- }
- if (storage->multimesh_uses_colors(e->instance->base)) {
- id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
- stride += 1;
- }
- if (storage->multimesh_uses_custom_data(e->instance->base)) {
- id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
- stride += 1;
- }
-
- id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
- } else if (e->instance->base_type == VS::INSTANCE_MESH) {
- if (e->instance->skeleton.is_valid()) {
- id.flags |= INSTANCE_DATA_FLAG_SKELETON;
- }
- }
-
- if (p_for_depth) {
- id.gi_offset = 0xFFFFFFFF;
- continue;
- }
-
- if (!e->instance->gi_probe_instances.empty()) {
- uint32_t written = 0;
- for (int j = 0; j < e->instance->gi_probe_instances.size(); j++) {
- RID probe = e->instance->gi_probe_instances[j];
- int slot = gi_probe_instance_get_slot(probe);
- if (slot < 0) {
- continue; //unallocated, dont render
- }
-
- if (render_pass != gi_probe_instance_get_render_pass(probe)) {
- continue; //not rendered in this frame
- }
-
- uint32_t index = gi_probe_instance_get_render_index(probe);
-
- if (written == 0) {
- id.gi_offset = index;
- written = 1;
- } else {
- id.gi_offset = index << 16;
- written = 2;
- break;
- }
- }
- if (written == 0) {
- id.gi_offset = 0xFFFFFFFF;
- } else if (written == 1) {
- id.gi_offset |= 0xFFFF0000;
- }
- } else {
- id.gi_offset = 0xFFFFFFFF;
- }
- }
-
- RD::get_singleton()->buffer_update(scene_state.instance_buffer, 0, sizeof(InstanceData) * p_element_count, scene_state.instances, true);
-}
-
-/// RENDERING ///
-
-void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set) {
-
- 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);
- if (p_radiance_uniform_set.is_valid()) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_radiance_uniform_set, RADIANCE_UNIFORM_SET);
- } else {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_radiance_uniform_set, RADIANCE_UNIFORM_SET);
- }
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, view_dependant_uniform_set, VIEW_DEPENDANT_UNIFORM_SET);
- if (p_render_buffers_uniform_set.is_valid()) {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET);
- } else {
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_render_buffers_uniform_set, RENDER_BUFFERS_UNIFORM_SET);
- }
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
-
- MaterialData *prev_material = nullptr;
- // ShaderData *prev_shader = nullptr;
-
- RID prev_vertex_array_rd;
- RID prev_index_array_rd;
- RID prev_pipeline_rd;
- RID prev_xforms_uniform_set;
-
- PushConstant push_constant;
- zeromem(&push_constant, sizeof(PushConstant));
-
- for (int i = 0; i < p_element_count; i++) {
-
- const RenderList::Element *e = p_elements[i];
-
- MaterialData *material = e->material;
- ShaderData *shader = material->shader_data;
- RID xforms_uniform_set;
-
- //find cull variant
- ShaderData::CullVariant cull_variant;
-
- if ((p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) && e->instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) {
- cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED;
- } else {
- bool mirror = e->instance->mirror;
- if (p_reverse_cull) {
- mirror = !mirror;
- }
- cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL;
- }
-
- //find primitive and vertex format
- VS::PrimitiveType primitive;
-
- switch (e->instance->base_type) {
- case VS::INSTANCE_MESH: {
- primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index);
- if (e->instance->skeleton.is_valid()) {
- xforms_uniform_set = storage->skeleton_get_3d_uniform_set(e->instance->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET);
- }
- } break;
- case VS::INSTANCE_MULTIMESH: {
- RID mesh = storage->multimesh_get_mesh(e->instance->base);
- ERR_CONTINUE(!mesh.is_valid()); //should be a bug
- primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index);
-
- xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
-
- } break;
- case VS::INSTANCE_IMMEDIATE: {
- ERR_CONTINUE(true); //should be a bug
- } break;
- case VS::INSTANCE_PARTICLES: {
- ERR_CONTINUE(true); //should be a bug
- } break;
- default: {
- ERR_CONTINUE(true); //should be a bug
- }
- }
-
- ShaderVersion shader_version;
-
- switch (p_pass_mode) {
- case PASS_MODE_COLOR:
- case PASS_MODE_COLOR_TRANSPARENT: {
-
- if (e->uses_lightmap) {
- shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS;
- } else if (e->uses_vct) {
- shader_version = SHADER_VERSION_VCT_COLOR_PASS;
- } else {
- shader_version = SHADER_VERSION_COLOR_PASS;
- }
-
- } break;
- case PASS_MODE_COLOR_SPECULAR: {
- if (e->uses_lightmap) {
- shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
- } else if (e->uses_vct) {
- shader_version = SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR;
- } else {
- shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
- }
- } break;
- case PASS_MODE_SHADOW:
- case PASS_MODE_DEPTH: {
- shader_version = SHADER_VERSION_DEPTH_PASS;
- } break;
- case PASS_MODE_SHADOW_DP: {
- shader_version = SHADER_VERSION_DEPTH_PASS_DP;
- } break;
- case PASS_MODE_DEPTH_NORMAL: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL;
- } break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
- } break;
- case PASS_MODE_DEPTH_MATERIAL: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
- } break;
- }
-
- RenderPipelineVertexFormatCacheRD *pipeline = nullptr;
-
- pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
-
- RD::VertexFormatID vertex_format;
- RID vertex_array_rd;
- RID index_array_rd;
-
- switch (e->instance->base_type) {
- case VS::INSTANCE_MESH: {
- storage->mesh_surface_get_arrays_and_format(e->instance->base, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
- } break;
- case VS::INSTANCE_MULTIMESH: {
- RID mesh = storage->multimesh_get_mesh(e->instance->base);
- ERR_CONTINUE(!mesh.is_valid()); //should be a bug
- storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
- } break;
- case VS::INSTANCE_IMMEDIATE: {
- ERR_CONTINUE(true); //should be a bug
- } break;
- case VS::INSTANCE_PARTICLES: {
- ERR_CONTINUE(true); //should be a bug
- } break;
- default: {
- ERR_CONTINUE(true); //should be a bug
- }
- }
-
- 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);
-
- 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 != prev_material) {
- //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 = material;
- }
-
- push_constant.index = i;
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(PushConstant));
-
- switch (e->instance->base_type) {
- case VS::INSTANCE_MESH: {
- RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid());
- } break;
- case VS::INSTANCE_MULTIMESH: {
- uint32_t instances = storage->multimesh_get_instances_to_draw(e->instance->base);
- RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances);
- } break;
- case VS::INSTANCE_IMMEDIATE: {
-
- } break;
- case VS::INSTANCE_PARTICLES: {
-
- } break;
- default: {
- ERR_CONTINUE(true); //should be a bug
- }
- }
- }
-}
-
-void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_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) {
-
- //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
- store_camera(projection, scene_state.ubo.projection_matrix);
- store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- store_transform(p_cam_transform, scene_state.ubo.camera_matrix);
- 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.screen_pixel_size[0] = p_screen_pixel_size.x;
- scene_state.ubo.screen_pixel_size[1] = p_screen_pixel_size.y;
-
- 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;
-
- if (get_debug_draw_mode() == VS::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)) {
-
- VS::EnvironmentBG env_bg = environment_get_background(p_environment);
- VS::EnvironmentAmbientSource ambient_src = environment_get_ambient_light_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 == VS::ENV_AMBIENT_SOURCE_BG && (env_bg == VS::ENV_BG_CLEAR_COLOR || env_bg == VS::ENV_BG_COLOR)) {
-
- Color color = env_bg == VS::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_ambient_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;
- store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
-
- scene_state.ubo.use_ambient_cubemap = (ambient_src == VS::ENV_AMBIENT_SOURCE_BG && env_bg == VS::ENV_BG_SKY) || ambient_src == VS::ENV_AMBIENT_SOURCE_SKY;
- scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == VS::ENV_AMBIENT_SOURCE_COLOR;
- }
-
- //specular
- VS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_environment);
- if ((ref_src == VS::ENV_REFLECTION_SOURCE_BG && env_bg == VS::ENV_BG_SKY) || ref_src == VS::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);
- 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;
-
- } 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.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
-
- RD::get_singleton()->buffer_update(scene_state.uniform_buffer, 0, sizeof(SceneState::UBO), &scene_state.ubo, true);
-}
-
-void RasterizerSceneHighEndRD::_add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index) {
-
- RID m_src;
-
- m_src = p_instance->material_override.is_valid() ? p_instance->material_override : p_material;
-
- if (unlikely(get_debug_draw_mode() != VS::VIEWPORT_DEBUG_DRAW_DISABLED)) {
- if (get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
- m_src = overdraw_material;
- } else if (get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME) {
- m_src = wireframe_material;
- } else if (get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_LIGHTING) {
- m_src = default_material;
- }
- }
-
- MaterialData *material = NULL;
-
- if (m_src.is_valid()) {
- material = (MaterialData *)storage->material_get_data(m_src, RasterizerStorageRD::SHADER_TYPE_3D);
- if (!material || !material->shader_data->valid) {
- material = NULL;
- }
- }
-
- if (!material) {
- material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
- m_src = default_material;
- }
-
- ERR_FAIL_COND(!material);
-
- _add_geometry_with_material(p_instance, p_surface, material, m_src, p_pass_mode, p_geometry_index);
-
- while (material->next_pass.is_valid()) {
-
- material = (MaterialData *)storage->material_get_data(material->next_pass, RasterizerStorageRD::SHADER_TYPE_3D);
- if (!material || !material->shader_data->valid)
- break;
- _add_geometry_with_material(p_instance, p_surface, material, material->next_pass, p_pass_mode, p_geometry_index);
- }
-}
-
-void RasterizerSceneHighEndRD::_add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index) {
-
- 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;
-
- if (p_material->shader_data->uses_sss) {
- scene_state.used_sss = true;
- }
-
- if (p_material->shader_data->uses_screen_texture) {
- scene_state.used_screen_texture = true;
- }
-
- if (p_material->shader_data->uses_depth_texture) {
- scene_state.used_depth_texture = true;
- }
-
- if (p_material->shader_data->uses_normal_texture) {
- scene_state.used_normal_texture = true;
- }
-
- if (p_pass_mode != PASS_MODE_COLOR && p_pass_mode != PASS_MODE_COLOR_SPECULAR) {
-
- if (has_blend_alpha || has_read_screen_alpha || (has_base_alpha && !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 || p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) {
- //conditions in which no depth pass should be processed
- return;
- }
-
- if (p_pass_mode != PASS_MODE_DEPTH_MATERIAL && !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) {
- //shader does not use discard and does not write a vertex position, use generic material
- if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_DEPTH) {
- p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
- } else if (p_pass_mode == PASS_MODE_DEPTH_NORMAL && !p_material->shader_data->uses_normal) {
- p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
- } else if (p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS && !p_material->shader_data->uses_normal && !p_material->shader_data->uses_roughness) {
- p_material = (MaterialData *)storage->material_get_data(default_material, RasterizerStorageRD::SHADER_TYPE_3D);
- }
- }
-
- has_alpha = false;
- }
-
- RenderList::Element *e = (has_alpha || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) ? render_list.add_alpha_element() : render_list.add_element();
-
- if (!e)
- return;
-
- e->instance = p_instance;
- e->material = p_material;
- e->surface_index = p_surface;
- e->sort_key = 0;
-
- if (e->material->last_pass != render_pass) {
- if (!RD::get_singleton()->uniform_set_is_valid(e->material->uniform_set)) {
- //uniform set no longer valid, probably a texture changed
- storage->material_force_update_textures(p_material_rid, RasterizerStorageRD::SHADER_TYPE_3D);
- }
- e->material->last_pass = render_pass;
- e->material->index = scene_state.current_material_index++;
- if (e->material->shader_data->last_pass != render_pass) {
- e->material->shader_data->last_pass = scene_state.current_material_index++;
- e->material->shader_data->index = scene_state.current_shader_index++;
- }
- }
- e->geometry_index = p_geometry_index;
- e->material_index = e->material->index;
- e->uses_instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH;
- e->uses_lightmap = e->instance->lightmap.is_valid();
- e->uses_vct = e->instance->gi_probe_instances.size();
- e->shader_index = e->shader_index;
- e->depth_layer = e->instance->depth_layer;
- e->priority = p_material->priority;
-
- if (p_material->shader_data->uses_time) {
- VisualServerRaster::redraw_request();
- }
-}
-
-void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi) {
-
- scene_state.current_shader_index = 0;
- scene_state.current_material_index = 0;
- 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 geometry_index = 0;
-
- //fill list
-
- for (int i = 0; i < p_cull_count; i++) {
-
- InstanceBase *inst = p_cull_result[i];
-
- //add geometry for drawing
- switch (inst->base_type) {
-
- case VS::INSTANCE_MESH: {
-
- const RID *materials = NULL;
- uint32_t surface_count;
-
- materials = storage->mesh_get_surface_count_and_materials(inst->base, surface_count);
- if (!materials) {
- continue; //nothing to do
- }
-
- const RID *inst_materials = inst->materials.ptr();
-
- for (uint32_t j = 0; j < surface_count; j++) {
-
- RID material = inst_materials[j].is_valid() ? inst_materials[j] : materials[j];
-
- uint32_t surface_index = storage->mesh_surface_get_render_pass_index(inst->base, j, render_pass, &geometry_index);
- _add_geometry(inst, j, material, p_pass_mode, surface_index);
- }
-
- //mesh->last_pass=frame;
-
- } break;
-
- case VS::INSTANCE_MULTIMESH: {
-
- if (storage->multimesh_get_instances_to_draw(inst->base) == 0) {
- //not visible, 0 instances
- continue;
- }
-
- RID mesh = storage->multimesh_get_mesh(inst->base);
- if (!mesh.is_valid()) {
- continue;
- }
-
- const RID *materials = NULL;
- uint32_t surface_count;
-
- materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
- if (!materials) {
- continue; //nothing to do
- }
-
- for (uint32_t j = 0; j < surface_count; j++) {
-
- uint32_t surface_index = storage->mesh_surface_get_multimesh_render_pass_index(mesh, j, render_pass, &geometry_index);
- _add_geometry(inst, j, materials[j], p_pass_mode, surface_index);
- }
-
- } break;
-#if 0
- case VS::INSTANCE_IMMEDIATE: {
-
- RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base);
- ERR_CONTINUE(!immediate);
-
- _add_geometry(immediate, inst, NULL, -1, p_depth_pass, p_shadow_pass);
-
- } break;
- case VS::INSTANCE_PARTICLES: {
-
- RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(inst->base);
- ERR_CONTINUE(!particles);
-
- for (int j = 0; j < particles->draw_passes.size(); j++) {
-
- RID pmesh = particles->draw_passes[j];
- if (!pmesh.is_valid())
- continue;
- RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(pmesh);
- if (!mesh)
- continue; //mesh not assigned
-
- int ssize = mesh->surfaces.size();
-
- for (int k = 0; k < ssize; k++) {
-
- RasterizerStorageGLES3::Surface *s = mesh->surfaces[k];
- _add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass);
- }
- }
-
- } break;
-#endif
- default: {
- }
- }
- }
-}
-
-void RasterizerSceneHighEndRD::_draw_sky(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha) {
-
- ERR_FAIL_COND(!is_environment(p_environment));
-
- RID sky = environment_get_sky(p_environment);
- ERR_FAIL_COND(!sky.is_valid());
- RID panorama = sky_get_panorama_texture_rd(sky);
- ERR_FAIL_COND(!panorama.is_valid());
- 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;
- storage->get_effects()->render_panorama(p_draw_list, p_fb_format, panorama, camera, sky_transform, 1.0, multiplier);
-}
-
-void RasterizerSceneHighEndRD::_setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment) {
-
- for (int i = 0; i < p_reflection_probe_cull_count; i++) {
-
- RID rpi = p_reflection_probe_cull_result[i];
-
- if (i >= (int)scene_state.max_reflections) {
- reflection_probe_instance_set_render_index(rpi, 0); //invalid, but something needs to be set
- continue;
- }
-
- reflection_probe_instance_set_render_index(rpi, i);
-
- RID base_probe = reflection_probe_instance_get_probe(rpi);
-
- ReflectionData &reflection_ubo = scene_state.reflections[i];
-
- Vector3 extents = storage->reflection_probe_get_extents(base_probe);
-
- reflection_ubo.box_extents[0] = extents.x;
- reflection_ubo.box_extents[1] = extents.y;
- reflection_ubo.box_extents[2] = extents.z;
- reflection_ubo.index = reflection_probe_instance_get_atlas_index(rpi);
-
- Vector3 origin_offset = storage->reflection_probe_get_origin_offset(base_probe);
-
- reflection_ubo.box_offset[0] = origin_offset.x;
- reflection_ubo.box_offset[1] = origin_offset.y;
- reflection_ubo.box_offset[2] = origin_offset.z;
- reflection_ubo.mask = storage->reflection_probe_get_cull_mask(base_probe);
-
- float intensity = storage->reflection_probe_get_intensity(base_probe);
- bool interior = storage->reflection_probe_is_interior(base_probe);
- bool box_projection = storage->reflection_probe_is_box_projection(base_probe);
-
- reflection_ubo.params[0] = intensity;
- reflection_ubo.params[1] = 0;
- reflection_ubo.params[2] = interior ? 1.0 : 0.0;
- reflection_ubo.params[3] = box_projection ? 1.0 : 0.0;
-
- if (interior) {
- Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear();
- float interior_ambient_energy = storage->reflection_probe_get_interior_ambient_energy(base_probe);
- float interior_ambient_probe_contrib = storage->reflection_probe_get_interior_ambient_probe_contribution(base_probe);
- reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy;
- reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
- reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
- reflection_ubo.ambient[3] = interior_ambient_probe_contrib;
- } else {
- Color ambient_linear = storage->reflection_probe_get_interior_ambient(base_probe).to_linear();
- if (is_environment(p_environment)) {
- Color env_ambient_color = environment_get_ambient_light_color(p_environment).to_linear();
- float env_ambient_energy = environment_get_ambient_light_ambient_energy(p_environment);
- ambient_linear = env_ambient_color;
- ambient_linear.r *= env_ambient_energy;
- ambient_linear.g *= env_ambient_energy;
- ambient_linear.b *= env_ambient_energy;
- }
-
- reflection_ubo.ambient[0] = ambient_linear.r;
- reflection_ubo.ambient[1] = ambient_linear.g;
- reflection_ubo.ambient[2] = ambient_linear.b;
- reflection_ubo.ambient[3] = 0; //not used in exterior mode, since it just blends with regular ambient light
- }
-
- Transform transform = reflection_probe_instance_get_transform(rpi);
- Transform proj = (p_camera_inverse_transform * transform).inverse();
- store_transform(proj, reflection_ubo.local_matrix);
-
- cluster_builder.add_reflection_probe(transform, extents);
-
- reflection_probe_instance_set_render_pass(rpi, render_pass);
- }
-
- if (p_reflection_probe_cull_count) {
- RD::get_singleton()->buffer_update(scene_state.reflection_buffer, 0, MIN(scene_state.max_reflections, (unsigned int)p_reflection_probe_cull_count) * sizeof(ReflectionData), scene_state.reflections, true);
- }
-}
-
-void RasterizerSceneHighEndRD::_setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform) {
-
- int index = 0;
-
- for (int i = 0; i < p_gi_probe_probe_cull_count; i++) {
-
- RID rpi = p_gi_probe_probe_cull_result[i];
-
- if (index >= (int)scene_state.max_gi_probes) {
- continue;
- }
-
- int slot = gi_probe_instance_get_slot(rpi);
- if (slot < 0) {
- continue; //not usable
- }
-
- RID base_probe = gi_probe_instance_get_base_probe(rpi);
-
- GIProbeData &gi_probe_ubo = scene_state.gi_probes[index];
-
- Transform to_cell = gi_probe_instance_get_transform_to_cell(rpi) * p_camera_transform;
-
- store_transform(to_cell, gi_probe_ubo.xform);
-
- Vector3 bounds = storage->gi_probe_get_octree_size(base_probe);
-
- gi_probe_ubo.bounds[0] = bounds.x;
- gi_probe_ubo.bounds[1] = bounds.y;
- gi_probe_ubo.bounds[2] = bounds.z;
-
- gi_probe_ubo.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe);
- gi_probe_ubo.bias = storage->gi_probe_get_bias(base_probe);
- gi_probe_ubo.normal_bias = storage->gi_probe_get_normal_bias(base_probe);
- gi_probe_ubo.blend_ambient = !storage->gi_probe_is_interior(base_probe);
- gi_probe_ubo.texture_slot = gi_probe_instance_get_slot(rpi);
- gi_probe_ubo.anisotropy_strength = storage->gi_probe_get_anisotropy_strength(base_probe);
- gi_probe_ubo.ao = storage->gi_probe_get_ao(base_probe);
- gi_probe_ubo.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f);
-
- if (gi_probe_is_anisotropic()) {
- gi_probe_ubo.texture_slot *= 3;
- }
-
- gi_probe_instance_set_render_index(rpi, index);
- gi_probe_instance_set_render_pass(rpi, render_pass);
-
- index++;
- }
-
- if (index) {
- RD::get_singleton()->buffer_update(scene_state.gi_probe_buffer, 0, index * sizeof(GIProbeData), scene_state.gi_probes, true);
- }
-}
-
-void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows) {
-
- uint32_t light_count = 0;
- scene_state.ubo.directional_light_count = 0;
-
- for (int i = 0; i < p_light_cull_count; i++) {
-
- RID li = p_light_cull_result[i];
- RID base = light_instance_get_base_light(li);
-
- ERR_CONTINUE(base.is_null());
-
- VS::LightType type = storage->light_get_type(base);
- switch (type) {
-
- case VS::LIGHT_DIRECTIONAL: {
-
- if (scene_state.ubo.directional_light_count >= scene_state.max_directional_lights) {
- continue;
- }
-
- DirectionalLightData &light_data = scene_state.directional_lights[scene_state.ubo.directional_light_count];
-
- Transform light_transform = light_instance_get_base_transform(li);
-
- Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
-
- light_data.direction[0] = direction.x;
- light_data.direction[1] = direction.y;
- light_data.direction[2] = direction.z;
-
- float sign = storage->light_is_negative(base) ? -1 : 1;
-
- light_data.energy = sign * storage->light_get_param(base, VS::LIGHT_PARAM_ENERGY) * Math_PI;
-
- Color linear_col = storage->light_get_color(base).to_linear();
- light_data.color[0] = linear_col.r;
- light_data.color[1] = linear_col.g;
- light_data.color[2] = linear_col.b;
-
- light_data.specular = storage->light_get_param(base, VS::LIGHT_PARAM_SPECULAR);
- light_data.mask = storage->light_get_cull_mask(base);
-
- Color shadow_col = storage->light_get_shadow_color(base).to_linear();
-
- light_data.shadow_color[0] = shadow_col.r;
- light_data.shadow_color[1] = shadow_col.g;
- light_data.shadow_color[2] = shadow_col.b;
-
- light_data.shadow_enabled = p_using_shadows && storage->light_has_shadow(base);
-
- if (light_data.shadow_enabled) {
-
- VS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base);
-
- int limit = smode == VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
- light_data.blend_splits = storage->light_directional_get_blend_splits(base);
- for (int j = 0; j < 4; j++) {
- Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j);
- CameraMatrix matrix = light_instance_get_shadow_camera(li, j);
- float split = light_instance_get_directional_shadow_split(li, MIN(limit, j));
-
- CameraMatrix bias;
- bias.set_light_bias();
- CameraMatrix rectm;
- rectm.set_light_atlas_rect(atlas_rect);
-
- Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse();
-
- CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
- light_data.shadow_split_offsets[j] = split;
- store_camera(shadow_mtx, light_data.shadow_matrices[j]);
- }
-
- float fade_start = storage->light_get_param(base, VS::LIGHT_PARAM_SHADOW_FADE_START);
- light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
- light_data.fade_to = -light_data.shadow_split_offsets[3];
- }
-
- scene_state.ubo.directional_light_count++;
- } break;
- case VS::LIGHT_SPOT:
- case VS::LIGHT_OMNI: {
-
- if (light_count >= scene_state.max_lights) {
- continue;
- }
-
- Transform light_transform = light_instance_get_base_transform(li);
-
- LightData &light_data = scene_state.lights[light_count];
-
- float sign = storage->light_is_negative(base) ? -1 : 1;
- Color linear_col = storage->light_get_color(base).to_linear();
-
- light_data.attenuation_energy[0] = Math::make_half_float(storage->light_get_param(base, VS::LIGHT_PARAM_ATTENUATION));
- light_data.attenuation_energy[1] = Math::make_half_float(sign * storage->light_get_param(base, VS::LIGHT_PARAM_ENERGY) * Math_PI);
-
- light_data.color_specular[0] = MIN(uint32_t(linear_col.r * 255), 255);
- light_data.color_specular[1] = MIN(uint32_t(linear_col.g * 255), 255);
- light_data.color_specular[2] = MIN(uint32_t(linear_col.b * 255), 255);
- light_data.color_specular[3] = MIN(uint32_t(storage->light_get_param(base, VS::LIGHT_PARAM_SPECULAR) * 255), 255);
-
- float radius = MAX(0.001, storage->light_get_param(base, VS::LIGHT_PARAM_RANGE));
- light_data.inv_radius = 1.0 / radius;
-
- Vector3 pos = p_camera_inverse_transform.xform(light_transform.origin);
-
- light_data.position[0] = pos.x;
- light_data.position[1] = pos.y;
- light_data.position[2] = pos.z;
-
- Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
-
- light_data.direction[0] = direction.x;
- light_data.direction[1] = direction.y;
- light_data.direction[2] = direction.z;
-
- light_data.cone_attenuation_angle[0] = Math::make_half_float(storage->light_get_param(base, VS::LIGHT_PARAM_SPOT_ATTENUATION));
- float spot_angle = storage->light_get_param(base, VS::LIGHT_PARAM_SPOT_ANGLE);
- light_data.cone_attenuation_angle[1] = Math::make_half_float(Math::cos(Math::deg2rad(spot_angle)));
-
- light_data.mask = storage->light_get_cull_mask(base);
-
- Color shadow_color = storage->light_get_shadow_color(base);
-
- bool has_shadow = p_using_shadows && storage->light_has_shadow(base);
- light_data.shadow_color_enabled[0] = MIN(uint32_t(shadow_color.r * 255), 255);
- light_data.shadow_color_enabled[1] = MIN(uint32_t(shadow_color.g * 255), 255);
- light_data.shadow_color_enabled[2] = MIN(uint32_t(shadow_color.b * 255), 255);
- light_data.shadow_color_enabled[3] = has_shadow ? 255 : 0;
-
- light_data.atlas_rect[0] = 0;
- light_data.atlas_rect[1] = 0;
- light_data.atlas_rect[2] = 0;
- light_data.atlas_rect[3] = 0;
-
- if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
- // fill in the shadow information
-
- Rect2 rect = light_instance_get_shadow_atlas_rect(li, p_shadow_atlas);
-
- if (type == VS::LIGHT_OMNI) {
-
- light_data.atlas_rect[0] = rect.position.x;
- light_data.atlas_rect[1] = rect.position.y;
- light_data.atlas_rect[2] = rect.size.width;
- light_data.atlas_rect[3] = rect.size.height * 0.5;
-
- Transform proj = (p_camera_inverse_transform * light_transform).inverse();
-
- store_transform(proj, light_data.shadow_matrix);
- } else if (type == VS::LIGHT_SPOT) {
-
- Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
- CameraMatrix bias;
- bias.set_light_bias();
- CameraMatrix rectm;
- rectm.set_light_atlas_rect(rect);
-
- CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview;
- store_camera(shadow_mtx, light_data.shadow_matrix);
- }
- }
-
- light_instance_set_index(li, light_count);
-
- cluster_builder.add_light(type == VS::LIGHT_SPOT ? LightClusterBuilder::LIGHT_TYPE_SPOT : LightClusterBuilder::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
-
- light_count++;
- } break;
- }
-
- light_instance_set_render_pass(li, render_pass);
-
- //update UBO for forward rendering, blit to texture for clustered
- }
-
- if (light_count) {
- RD::get_singleton()->buffer_update(scene_state.light_buffer, 0, sizeof(LightData) * light_count, scene_state.lights, true);
- }
-
- if (scene_state.ubo.directional_light_count) {
- RD::get_singleton()->buffer_update(scene_state.directional_light_buffer, 0, sizeof(DirectionalLightData) * scene_state.ubo.directional_light_count, scene_state.directional_lights, true);
- }
-}
-
-void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, 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) {
-
- RenderBufferDataHighEnd *render_buffer = NULL;
- if (p_render_buffer.is_valid()) {
- render_buffer = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffer);
- }
-
- //first of all, make a new render pass
- render_pass++;
-
- //fill up ubo
-#if 0
- storage->info.render.object_count += p_cull_count;
-
- Environment *env = environment_owner.getornull(p_environment);
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
- ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas);
-
- if (shadow_atlas && shadow_atlas->size) {
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5);
- glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
- scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / shadow_atlas->size;
- scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / shadow_atlas->size;
- }
-
- if (reflection_atlas && reflection_atlas->size) {
- glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
- glBindTexture(GL_TEXTURE_2D, reflection_atlas->color);
- }
-#endif
-
- RENDER_TIMESTAMP("Setup 3D Scene");
-
- if (get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- p_light_cull_count = 0;
- p_reflection_probe_cull_count = 0;
- p_gi_probe_cull_count = 0;
- }
-
- bool using_shadows = true;
-
- if (p_reflection_probe.is_valid()) {
- scene_state.ubo.reflection_multiplier = 0.0;
- if (!storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_reflection_probe))) {
- using_shadows = false;
- }
- } else {
- scene_state.ubo.reflection_multiplier = 1.0;
- }
-
- //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size;
-
- scene_state.ubo.shadow_z_offset = 0;
- scene_state.ubo.shadow_z_slope_scale = 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;
-
- Size2 screen_pixel_size;
- RID opaque_framebuffer;
- RID depth_framebuffer;
- RID alpha_framebuffer;
-
- PassMode depth_pass_mode = PASS_MODE_DEPTH;
- Vector<Color> depth_pass_clear;
-
- if (render_buffer) {
- screen_pixel_size.width = 1.0 / render_buffer->width;
- screen_pixel_size.height = 1.0 / render_buffer->height;
-
- opaque_framebuffer = render_buffer->color_fb;
-
- if (p_environment.is_valid() && environment_is_ssr_enabled(p_environment)) {
- depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS;
- } else if (screen_space_roughness_limiter_is_active()) {
- depth_pass_mode = PASS_MODE_DEPTH_NORMAL;
- //we need to allocate both these, if not allocated
- _allocate_normal_texture(render_buffer);
- _allocate_roughness_texture(render_buffer);
- } else if (p_environment.is_valid() && (environment_is_ssao_enabled(p_environment) || get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER)) {
- depth_pass_mode = PASS_MODE_DEPTH_NORMAL;
- }
-
- switch (depth_pass_mode) {
- case PASS_MODE_DEPTH: {
- depth_framebuffer = render_buffer->depth_fb;
- } break;
- case PASS_MODE_DEPTH_NORMAL: {
- _allocate_normal_texture(render_buffer);
- depth_framebuffer = render_buffer->depth_normal_fb;
- depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
- } break;
- case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
- _allocate_normal_texture(render_buffer);
- _allocate_roughness_texture(render_buffer);
- depth_framebuffer = render_buffer->depth_normal_roughness_fb;
- depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
- depth_pass_clear.push_back(Color());
- } break;
- default: {
- };
- }
-
- alpha_framebuffer = opaque_framebuffer;
-
- } else if (p_reflection_probe.is_valid()) {
- uint32_t resolution = reflection_probe_instance_get_resolution(p_reflection_probe);
- screen_pixel_size.width = 1.0 / resolution;
- screen_pixel_size.height = 1.0 / resolution;
-
- opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_reflection_probe, p_reflection_probe_pass);
- depth_framebuffer = reflection_probe_instance_get_depth_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
- }
-
- } else {
- ERR_FAIL(); //bug?
- }
-
- cluster_builder.begin(p_cam_transform.affine_inverse(), p_cam_projection); //prepare cluster
-
- _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_shadow_atlas, using_shadows);
- _setup_reflections(p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_cam_transform.affine_inverse(), p_environment);
- _setup_gi_probes(p_gi_probe_cull_result, p_gi_probe_cull_count, p_cam_transform);
- _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_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);
-
- cluster_builder.bake_cluster(); //bake to cluster
-
- _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
-
- render_list.clear();
- _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr);
-
- RID radiance_uniform_set;
- bool draw_sky = false;
-
- Color clear_color;
- bool keep_color = false;
-
- if (get_debug_draw_mode() == VS::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)) {
- VS::EnvironmentBG bg_mode = environment_get_background(p_environment);
- float bg_energy = environment_get_bg_energy(p_environment);
- switch (bg_mode) {
- case VS::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;
- } break;
- case VS::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;
- } break;
- case VS::ENV_BG_SKY: {
- RID sky = environment_get_sky(p_environment);
- if (sky.is_valid()) {
- radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
- draw_sky = true;
- }
- } break;
- case VS::ENV_BG_CANVAS: {
- keep_color = true;
- } break;
- case VS::ENV_BG_KEEP: {
- keep_color = true;
- } break;
- case VS::ENV_BG_CAMERA_FEED: {
-
- } break;
- default: {
- }
- }
- } else {
-
- clear_color = p_default_bg_color;
- }
-
- _setup_view_dependant_uniform_set(p_shadow_atlas, p_reflection_atlas);
-
- render_list.sort_by_key(false);
-
- _fill_instances(render_list.elements, render_list.element_count, false);
-
- bool can_continue = true; //unless the middle buffers are needed
- bool debug_giprobes = get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
- bool using_separate_specular = false;
-
- bool depth_pre_pass = depth_framebuffer.is_valid();
- RID render_buffers_uniform_set;
-
- if (depth_pre_pass) { //depth pre pass
- RENDER_TIMESTAMP("Render Depth Pre-Pass");
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(depth_framebuffer), render_list.elements, render_list.element_count, false, depth_pass_mode, render_buffer == nullptr, radiance_uniform_set, RID());
- RD::get_singleton()->draw_list_end();
- }
-
- if (p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment)) {
- _process_ssao(p_render_buffer, p_environment, render_buffer->normal_buffer, p_cam_projection);
- }
-
- if (p_render_buffer.is_valid() && screen_space_roughness_limiter_is_active()) {
- storage->get_effects()->roughness_limit(render_buffer->normal_buffer, render_buffer->roughness_buffer, Size2(render_buffer->width, render_buffer->height), screen_space_roughness_limiter_get_curve());
- }
-
- if (p_render_buffer.is_valid()) {
- //update the render buffers uniform set in case it changed
- _update_render_buffers_uniform_set(p_render_buffer);
- render_buffers_uniform_set = render_buffer->uniform_set;
- }
-
- _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_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");
-
- {
- bool will_continue = (can_continue || draw_sky || debug_giprobes);
- //regular forward for now
- Vector<Color> c;
- c.push_back(clear_color.to_linear());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), render_list.elements, render_list.element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set);
- RD::get_singleton()->draw_list_end();
- }
-
- if (debug_giprobes) {
- //debug giprobes
- bool will_continue = (can_continue || draw_sky);
- CameraMatrix dc;
- dc.set_depth_correction(true);
- CameraMatrix cm = (dc * p_cam_projection) * CameraMatrix(p_cam_transform.affine_inverse());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- for (int i = 0; i < p_gi_probe_cull_count; i++) {
- _debug_giprobe(p_gi_probe_cull_result[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == VS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0);
- }
- RD::get_singleton()->draw_list_end();
- }
-
- if (draw_sky) {
- 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::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, can_continue ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
- _draw_sky(draw_list, RD::get_singleton()->framebuffer_get_format(opaque_framebuffer), p_environment, projection, p_cam_transform, 1.0);
- RD::get_singleton()->draw_list_end();
-
- if (using_separate_specular && !can_continue) {
- //can't continue, so close the buffers
- //RD::get_singleton()->draw_list_begin(render_buffer->color_specular_fb, RD::INITIAL_ACTION_CONTINUE, RD::FINAL_ACTION_READ_COLOR_AND_DEPTH, c);
- //RD::get_singleton()->draw_list_end();
- }
- }
-
- RENDER_TIMESTAMP("Render Transparent Pass");
-
- _setup_environment(p_environment, p_cam_projection, p_cam_transform, p_reflection_probe, p_reflection_probe.is_valid(), screen_pixel_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);
-
- render_list.sort_by_reverse_depth_and_priority(true);
-
- _fill_instances(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false);
-
- {
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(alpha_framebuffer, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(alpha_framebuffer), &render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, false, PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set);
- RD::get_singleton()->draw_list_end();
- }
-
- //_render_list
-#if 0
- if (state.directional_light_count == 0) {
- directional_light = NULL;
- _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, false, shadow_atlas != NULL);
- } else {
- for (int i = 0; i < state.directional_light_count; i++) {
- directional_light = directional_lights[i];
- _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
- _render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, i > 0, shadow_atlas != NULL);
- }
- }
-#endif
-
-#if 0
- _post_process(env, p_cam_projection);
- // Needed only for debugging
- /* if (shadow_atlas && storage->frame.current_rt) {
-
- //_copy_texture_to_front_buffer(shadow_atlas->depth);
- storage->canvas->canvas_begin();
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
- }
-
- if (storage->frame.current_rt) {
-
- //_copy_texture_to_front_buffer(shadow_atlas->depth);
- storage->canvas->canvas_begin();
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, exposure_shrink[4].color);
- //glBindTexture(GL_TEXTURE_2D,storage->frame.current_rt->exposure.color);
- storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1));
- }
-
- if (reflection_atlas && storage->frame.current_rt) {
-
- //_copy_texture_to_front_buffer(shadow_atlas->depth);
- storage->canvas->canvas_begin();
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, reflection_atlas->color);
- storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
- }
-
- if (directional_shadow.fbo) {
-
- //_copy_texture_to_front_buffer(shadow_atlas->depth);
- storage->canvas->canvas_begin();
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
- }
-
- if ( env_radiance_tex) {
-
- //_copy_texture_to_front_buffer(shadow_atlas->depth);
- storage->canvas->canvas_begin();
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, env_radiance_tex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }*/
- //disable all stuff
-#endif
-}
-void RasterizerSceneHighEndRD::_render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, 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) {
-
- RENDER_TIMESTAMP("Setup Rendering Shadow");
-
- _update_render_base_uniform_set();
-
- render_pass++;
-
- scene_state.ubo.shadow_z_offset = p_bias;
- scene_state.ubo.shadow_z_slope_scale = p_normal_bias;
- scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
-
- _setup_environment(RID(), p_projection, p_transform, RID(), true, Vector2(1, 1), RID(), true, Color(), 0, p_zfar);
-
- render_list.clear();
-
- PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
-
- _fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
-
- _setup_view_dependant_uniform_set(RID(), RID());
-
- RENDER_TIMESTAMP("Render Shadow");
-
- render_list.sort_by_key(false);
-
- _fill_instances(render_list.elements, render_list.element_count, true);
-
- {
- //regular forward for now
- 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);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, p_use_dp_flip, pass_mode, true, RID(), RID());
- RD::get_singleton()->draw_list_end();
- }
-}
-
-void RasterizerSceneHighEndRD::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
- RENDER_TIMESTAMP("Setup Rendering Shadow");
-
- _update_render_base_uniform_set();
-
- render_pass++;
-
- scene_state.ubo.shadow_z_offset = 0;
- scene_state.ubo.shadow_z_slope_scale = 0;
- scene_state.ubo.dual_paraboloid_side = 0;
-
- _setup_environment(RID(), p_cam_projection, p_cam_transform, RID(), true, Vector2(1, 1), RID(), false, Color(), 0, 0);
-
- render_list.clear();
-
- PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
- _fill_render_list(p_cull_result, p_cull_count, pass_mode, true);
-
- _setup_view_dependant_uniform_set(RID(), RID());
-
- RENDER_TIMESTAMP("Render Material");
-
- render_list.sort_by_key(false);
-
- _fill_instances(render_list.elements, render_list.element_count, 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);
- _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), render_list.elements, render_list.element_count, true, pass_mode, true, RID(), RID());
- RD::get_singleton()->draw_list_end();
- }
-}
-
-void RasterizerSceneHighEndRD::_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 RasterizerSceneHighEndRD::_update_render_base_uniform_set() {
-
- if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
-
- 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);
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- RD::Uniform u;
- u.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(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 2;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(shadow_sampler);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 3;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.uniform_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 4;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(scene_state.instance_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 5;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.light_buffer);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 6;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.reflection_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 7;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.directional_light_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 8;
- u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.ids.push_back(scene_state.gi_probe_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 9;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- int slot_count = gi_probe_get_slots().size();
- if (gi_probe_is_anisotropic()) {
- u.ids.resize(slot_count * 3);
- } else {
- u.ids.resize(slot_count);
- }
-
- for (int i = 0; i < slot_count; i++) {
-
- RID probe = gi_probe_get_slots()[i];
-
- if (gi_probe_is_anisotropic()) {
- if (probe.is_null()) {
- RID empty_tex = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- u.ids.write[i * 3 + 0] = empty_tex;
- u.ids.write[i * 3 + 1] = empty_tex;
- u.ids.write[i * 3 + 2] = empty_tex;
- } else {
- u.ids.write[i * 3 + 0] = gi_probe_instance_get_texture(probe);
- u.ids.write[i * 3 + 1] = gi_probe_instance_get_aniso_texture(probe, 0);
- u.ids.write[i * 3 + 2] = gi_probe_instance_get_aniso_texture(probe, 1);
- }
- } else {
- if (probe.is_null()) {
- u.ids.write[i] = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
- } else {
- u.ids.write[i] = gi_probe_instance_get_texture(probe);
- }
- }
- }
-
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 10;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.ids.push_back(cluster_builder.get_cluster_texture());
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 11;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(cluster_builder.get_cluster_indices_buffer());
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 12;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- if (directional_shadow_get_texture().is_valid()) {
- u.ids.push_back(directional_shadow_get_texture());
- } else {
- u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
- }
- uniforms.push_back(u);
- }
-
- render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET);
- }
-}
-
-void RasterizerSceneHighEndRD::_setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas) {
-
- if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) {
- RD::get_singleton()->free(view_dependant_uniform_set);
- }
-
- //default render buffer and scene state uniform set
-
- Vector<RD::Uniform> uniforms;
-
- {
-
- RID ref_texture = p_reflection_atlas.is_valid() ? reflection_atlas_get_texture(p_reflection_atlas) : RID();
- RD::Uniform u;
- u.binding = 0;
- u.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
- }
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 1;
- u.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(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
- }
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
-
- view_dependant_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, VIEW_DEPENDANT_UNIFORM_SET);
-}
-
-void RasterizerSceneHighEndRD::_render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb) {
-
- if (!rb->uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) {
- RD::get_singleton()->free(rb->uniform_set);
- }
- rb->uniform_set = RID();
-}
-
-void RasterizerSceneHighEndRD::_render_buffers_uniform_set_changed(RID p_render_buffers) {
-
- RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
-
- _render_buffers_clear_uniform_set(rb);
-}
-
-RID RasterizerSceneHighEndRD::_render_buffers_get_roughness_texture(RID p_render_buffers) {
- RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
-
- return rb->roughness_buffer;
-}
-
-RID RasterizerSceneHighEndRD::_render_buffers_get_normal_texture(RID p_render_buffers) {
- RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
-
- return rb->normal_buffer;
-}
-
-void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_buffers) {
-
- RenderBufferDataHighEnd *rb = (RenderBufferDataHighEnd *)render_buffers_get_data(p_render_buffers);
-
- if (rb->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->uniform_set)) {
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.binding = 0;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = false && rb->depth.is_valid() ? rb->depth : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 1;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID bbt = render_buffers_get_back_buffer_texture(p_render_buffers);
- RID texture = bbt.is_valid() ? bbt : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 2;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb->normal_buffer.is_valid() ? rb->normal_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL);
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 3;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb->roughness_buffer.is_valid() ? rb->roughness_buffer : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
-
- {
- RD::Uniform u;
- u.binding = 4;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID aot = render_buffers_get_ao_texture(p_render_buffers);
- RID texture = aot.is_valid() ? aot : storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
-
- rb->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
- }
-}
-
-RasterizerSceneHighEndRD *RasterizerSceneHighEndRD::singleton = NULL;
-
-void RasterizerSceneHighEndRD::set_time(double p_time, double p_step) {
- time = p_time;
- RasterizerSceneRD::set_time(p_time, p_step);
-}
-
-RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage) :
- RasterizerSceneRD(p_storage) {
- singleton = this;
- storage = p_storage;
-
- /* SHADER */
-
- {
- 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";
- }
-
- uint32_t uniform_max_size = RD::get_singleton()->limit_get(RD::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
-
- { //reflections
- uint32_t reflection_buffer_size;
- if (uniform_max_size < 65536) {
- //Yes, you guessed right, ARM again
- reflection_buffer_size = uniform_max_size;
- } else {
- reflection_buffer_size = 65536;
- }
-
- scene_state.max_reflections = reflection_buffer_size / sizeof(ReflectionData);
- scene_state.reflections = memnew_arr(ReflectionData, scene_state.max_reflections);
- scene_state.reflection_buffer = RD::get_singleton()->uniform_buffer_create(reflection_buffer_size);
- defines += "\n#define MAX_REFLECTION_DATA_STRUCTS " + itos(scene_state.max_reflections) + "\n";
- }
-
- { //lights
- scene_state.max_lights = MIN(65536, uniform_max_size) / sizeof(LightData);
- uint32_t light_buffer_size = scene_state.max_lights * sizeof(LightData);
- scene_state.lights = memnew_arr(LightData, scene_state.max_lights);
- scene_state.light_buffer = RD::get_singleton()->uniform_buffer_create(light_buffer_size);
- defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(scene_state.max_lights) + "\n";
-
- scene_state.max_directional_lights = 8;
- uint32_t directional_light_buffer_size = scene_state.max_directional_lights * sizeof(DirectionalLightData);
- scene_state.directional_lights = memnew_arr(DirectionalLightData, scene_state.max_directional_lights);
- scene_state.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
- defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(scene_state.max_directional_lights) + "\n";
- }
-
- { //giprobes
- int slot_count = gi_probe_get_slots().size();
- if (gi_probe_is_anisotropic()) {
- slot_count *= 3;
- defines += "\n#define GI_PROBE_USE_ANISOTROPY\n";
- }
-
- if (gi_probe_get_quality() == GIPROBE_QUALITY_ULTRA_LOW) {
- defines += "\n#define GI_PROBE_LOW_QUALITY\n";
- } else if (gi_probe_get_quality() == GIPROBE_QUALITY_HIGH) {
- defines += "\n#define GI_PROBE_HIGH_QUALITY\n";
- }
-
- defines += "\n#define MAX_GI_PROBE_TEXTURES " + itos(slot_count) + "\n";
-
- uint32_t giprobe_buffer_size;
- if (uniform_max_size < 65536) {
- //Yes, you guessed right, ARM again
- giprobe_buffer_size = uniform_max_size;
- } else {
- giprobe_buffer_size = 65536;
- }
-
- giprobe_buffer_size = MIN(sizeof(GIProbeData) * gi_probe_get_slots().size(), giprobe_buffer_size);
- scene_state.max_gi_probes = giprobe_buffer_size / sizeof(GIProbeData);
- scene_state.gi_probes = memnew_arr(GIProbeData, scene_state.max_gi_probes);
- scene_state.gi_probe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * scene_state.max_gi_probes);
- defines += "\n#define MAX_GI_PROBES " + itos(scene_state.max_gi_probes) + "\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\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL\n#define MODE_RENDER_ROUGHNESS\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
- shader_versions.push_back("");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
- shader_versions.push_back("\n#define USE_VOXEL_CONE_TRACING\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_VOXEL_CONE_TRACING\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);
- }
-
- storage->shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
- storage->material_set_data_request_function(RasterizerStorageRD::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";
-
- //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["NORMALMAP"] = "normalmap";
- actions.renames["NORMALMAP_DEPTH"] = "normaldepth";
- 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["TRANSMISSION"] = "transmission";
- 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_TEXTURE"] = "normal_buffer";
- actions.renames["DEPTH"] = "gl_FragDepth";
- actions.renames["OUTPUT_IS_SRGB"] = "true";
-
- //for light
- actions.renames["VIEW"] = "view";
- actions.renames["LIGHT_COLOR"] = "light_color";
- actions.renames["LIGHT"] = "light";
- actions.renames["ATTENUATION"] = "attenuation";
- actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
- actions.renames["SPECULAR_LIGHT"] = "specular_light";
-
- 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["NORMALMAP"] = "#define NORMALMAP_USED\n";
- actions.usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
- 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["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
- actions.usage_defines["TRANSMISSION"] = "#define LIGHT_TRANSMISSION_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.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";
-
- 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;
-
- shader.compiler.initialize(actions);
- }
-
- //render list
- render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)128000);
- render_list.init();
- render_pass = 0;
-
- {
-
- scene_state.max_instances = render_list.max_elements;
- scene_state.instances = memnew_arr(InstanceData, scene_state.max_instances);
- scene_state.instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(InstanceData) * scene_state.max_instances);
- }
-
- scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
-
- {
- //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, RasterizerStorageRD::SHADER_TYPE_3D);
- default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
- }
-
- {
-
- 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);
- }
-
- {
- default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.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);
- }
-
- {
- Vector<RD::Uniform> uniforms;
-
- RD::Uniform u;
- u.binding = 0;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
- u.ids.push_back(texture);
- uniforms.push_back(u);
-
- default_radiance_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RADIANCE_UNIFORM_SET);
- }
-
- { //render buffers
- Vector<RD::Uniform> uniforms;
- for (int i = 0; i < 5; i++) {
- RD::Uniform u;
- u.binding = i;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = storage->texture_rd_get_default(i == 0 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE : (i == 2 ? RasterizerStorageRD::DEFAULT_RD_TEXTURE_NORMAL : RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK));
- u.ids.push_back(texture);
- uniforms.push_back(u);
- }
-
- default_render_buffers_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_BUFFERS_UNIFORM_SET);
- }
-
- cluster_builder.setup(16, 8, 24);
-}
-
-RasterizerSceneHighEndRD::~RasterizerSceneHighEndRD() {
- directional_shadow_atlas_set_size(0);
-
- //clear base uniform set if still valid
- if (view_dependant_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(view_dependant_uniform_set)) {
- RD::get_singleton()->free(view_dependant_uniform_set);
- }
-
- RD::get_singleton()->free(default_render_buffers_uniform_set);
- RD::get_singleton()->free(default_radiance_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);
-
- {
- RD::get_singleton()->free(scene_state.uniform_buffer);
- RD::get_singleton()->free(scene_state.instance_buffer);
- RD::get_singleton()->free(scene_state.gi_probe_buffer);
- RD::get_singleton()->free(scene_state.directional_light_buffer);
- RD::get_singleton()->free(scene_state.light_buffer);
- RD::get_singleton()->free(scene_state.reflection_buffer);
- memdelete_arr(scene_state.instances);
- memdelete_arr(scene_state.gi_probes);
- memdelete_arr(scene_state.directional_lights);
- memdelete_arr(scene_state.lights);
- memdelete_arr(scene_state.reflections);
- }
-}
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.h
deleted file mode 100644
index 647b8f225e..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_scene_high_end_rd.h
+++ /dev/null
@@ -1,587 +0,0 @@
-/*************************************************************************/
-/* rasterizer_scene_high_end_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_SCENE_HIGHEND_RD_H
-#define RASTERIZER_SCENE_HIGHEND_RD_H
-
-#include "servers/visual/rasterizer_rd/light_cluster_builder.h"
-#include "servers/visual/rasterizer_rd/rasterizer_scene_rd.h"
-#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-#include "servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/scene_high_end.glsl.gen.h"
-
-class RasterizerSceneHighEndRD : public RasterizerSceneRD {
-
- enum {
- SCENE_UNIFORM_SET = 0,
- RADIANCE_UNIFORM_SET = 1,
- VIEW_DEPENDANT_UNIFORM_SET = 2,
- RENDER_BUFFERS_UNIFORM_SET = 3,
- TRANSFORMS_UNIFORM_SET = 4,
- MATERIAL_UNIFORM_SET = 5
- };
-
- /* Shader */
-
- enum ShaderVersion {
- SHADER_VERSION_DEPTH_PASS,
- SHADER_VERSION_DEPTH_PASS_DP,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
- SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
- SHADER_VERSION_COLOR_PASS,
- SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_VCT_COLOR_PASS,
- SHADER_VERSION_VCT_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_LIGHTMAP_COLOR_PASS,
- SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_MAX
- };
-
- struct {
- SceneHighEndShaderRD scene_shader;
- ShaderCompilerRD compiler;
- } shader;
-
- RasterizerStorageRD *storage;
-
- /* Material */
-
- struct ShaderData : public RasterizerStorageRD::ShaderData {
-
- enum BlendMode { //used internally
- BLEND_MODE_MIX,
- BLEND_MODE_ADD,
- BLEND_MODE_SUB,
- BLEND_MODE_MUL,
- };
-
- 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
-
- };
-
- bool valid;
- RID version;
- uint32_t vertex_input_mask;
- RenderPipelineVertexFormatCacheRD pipelines[CULL_VARIANT_MAX][VS::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_depth_pre_pass;
- bool uses_discard;
- bool uses_roughness;
- bool uses_normal;
-
- bool unshaded;
- bool uses_vertex;
- bool uses_sss;
- 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;
- 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;
- ShaderData();
- virtual ~ShaderData();
- };
-
- RasterizerStorageRD::ShaderData *_create_shader_func();
- static RasterizerStorageRD::ShaderData *_create_shader_funcs() {
- return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_shader_func();
- }
-
- struct MaterialData : public RasterizerStorageRD::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();
- };
-
- RasterizerStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
- static RasterizerStorageRD::MaterialData *_create_material_funcs(RasterizerStorageRD::ShaderData *p_shader) {
- return static_cast<RasterizerSceneHighEndRD *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
- }
-
- /* Push Constant */
-
- struct PushConstant {
- uint32_t index;
- uint32_t pad[3];
- };
-
- /* Framebuffer */
-
- struct RenderBufferDataHighEnd : public RenderBufferData {
- //for rendering, may be MSAAd
- RID color;
- RID depth;
- RID specular;
- RID normal_buffer;
- RID roughness_buffer;
- RID depth_fb;
- RID depth_normal_fb;
- RID depth_normal_roughness_fb;
- RID color_fb;
- RID color_specular_fb;
- int width, height;
-
- void ensure_specular();
- void clear();
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, VS::ViewportMSAA p_msaa);
-
- RID uniform_set;
-
- ~RenderBufferDataHighEnd();
- };
-
- virtual RenderBufferData *_create_render_buffer_data();
- void _allocate_normal_texture(RenderBufferDataHighEnd *rb);
- void _allocate_roughness_texture(RenderBufferDataHighEnd *rb);
-
- RID shadow_sampler;
- RID render_base_uniform_set;
- RID view_dependant_uniform_set;
-
- virtual void _base_uniforms_changed();
- void _render_buffers_clear_uniform_set(RenderBufferDataHighEnd *rb);
- virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
- virtual RID _render_buffers_get_roughness_texture(RID p_render_buffers);
- virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
-
- void _update_render_base_uniform_set();
- void _setup_view_dependant_uniform_set(RID p_shadow_atlas, RID p_reflection_atlas);
- void _update_render_buffers_uniform_set(RID p_render_buffers);
-
- /* Scene State UBO */
-
- struct ReflectionData { //should always be 128 bytes
- float box_extents[3];
- float index;
- float box_offset[3];
- uint32_t mask;
- float params[4]; // intensity, 0, interior , boxproject
- float ambient[4]; // ambient color, energy
- float local_matrix[16]; // up to here for spot and omni, rest is for directional
- };
-
- struct LightData {
- float position[3];
- float inv_radius;
- float direction[3];
- uint16_t attenuation_energy[2]; //16 bits attenuation, then energy
- uint8_t color_specular[4]; //rgb color, a specular (8 bit unorm)
- uint16_t cone_attenuation_angle[2]; // attenuation and angle, (16bit float)
- uint32_t mask;
- uint8_t shadow_color_enabled[4]; //shadow rgb color, a>0.5 enabled (8bit unorm)
- float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
- float shadow_matrix[16];
- };
-
- struct DirectionalLightData {
-
- float direction[3];
- float energy;
- float color[3];
- float specular;
- float shadow_color[3];
- uint32_t mask;
- uint32_t blend_splits;
- uint32_t shadow_enabled;
- float fade_from;
- float fade_to;
- float shadow_split_offsets[4];
- float shadow_matrices[4][16];
- };
-
- 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 pad[1];
- };
-
- enum {
- 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_MULTIMESH_STRIDE_SHIFT = 16,
- INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7,
- INSTANCE_DATA_FLAG_SKELETON = 1 << 19,
- };
-
- struct InstanceData {
- float transform[16];
- float normal_transform[16];
- uint32_t flags;
- uint32_t instance_ofs; //instance_offset in instancing/skeleton buffer
- uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap)
- uint32_t mask;
- };
-
- struct SceneState {
- 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 shadow_z_offset;
- float shadow_z_slope_scale;
-
- float time;
- float reflection_multiplier;
-
- 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 ao_color[4];
- };
-
- UBO ubo;
-
- RID uniform_buffer;
-
- ReflectionData *reflections;
- uint32_t max_reflections;
- RID reflection_buffer;
- uint32_t max_reflection_probes_per_instance;
-
- GIProbeData *gi_probes;
- uint32_t max_gi_probes;
- RID gi_probe_buffer;
- uint32_t max_gi_probe_probes_per_instance;
-
- LightData *lights;
- uint32_t max_lights;
- RID light_buffer;
-
- DirectionalLightData *directional_lights;
- uint32_t max_directional_lights;
- RID directional_light_buffer;
-
- RID instance_buffer;
- InstanceData *instances;
- uint32_t max_instances;
-
- bool used_screen_texture = false;
- bool used_normal_texture = false;
- bool used_depth_texture = false;
- bool used_sss = false;
- uint32_t current_shader_index = 0;
- uint32_t current_material_index = 0;
- } scene_state;
-
- /* Render List */
-
- struct RenderList {
-
- int max_elements;
-
- struct Element {
- RasterizerScene::InstanceBase *instance;
- MaterialData *material;
- union {
- struct {
- //from least significant to most significant in sort, TODO: should be endian swapped on big endian
- uint64_t geometry_index : 20;
- uint64_t material_index : 15;
- uint64_t shader_index : 12;
- uint64_t uses_instancing : 1;
- uint64_t uses_vct : 1;
- uint64_t uses_lightmap : 1;
- uint64_t depth_layer : 4;
- uint64_t priority : 8;
- };
-
- uint64_t sort_key;
- };
- uint32_t surface_index;
- };
-
- Element *base_elements;
- Element **elements;
-
- int element_count;
- int alpha_element_count;
-
- void clear() {
-
- element_count = 0;
- alpha_element_count = 0;
- }
-
- //should eventually be replaced by radix
-
- struct SortByKey {
-
- _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
- return A->sort_key < B->sort_key;
- }
- };
-
- void sort_by_key(bool p_alpha) {
-
- SortArray<Element *, SortByKey> sorter;
- if (p_alpha) {
- sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
- } else {
- sorter.sort(elements, element_count);
- }
- }
-
- struct SortByDepth {
-
- _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
- return A->instance->depth < B->instance->depth;
- }
- };
-
- void sort_by_depth(bool p_alpha) { //used for shadows
-
- SortArray<Element *, SortByDepth> sorter;
- if (p_alpha) {
- sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
- } else {
- sorter.sort(elements, element_count);
- }
- }
-
- struct SortByReverseDepthAndPriority {
-
- _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
- uint32_t layer_A = uint32_t(A->priority);
- uint32_t layer_B = uint32_t(B->priority);
- if (layer_A == layer_B) {
- return A->instance->depth > B->instance->depth;
- } else {
- return layer_A < layer_B;
- }
- }
- };
-
- void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
-
- SortArray<Element *, SortByReverseDepthAndPriority> sorter;
- if (p_alpha) {
- sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
- } else {
- sorter.sort(elements, element_count);
- }
- }
-
- _FORCE_INLINE_ Element *add_element() {
-
- if (element_count + alpha_element_count >= max_elements)
- return NULL;
- elements[element_count] = &base_elements[element_count];
- return elements[element_count++];
- }
-
- _FORCE_INLINE_ Element *add_alpha_element() {
-
- if (element_count + alpha_element_count >= max_elements)
- return NULL;
- int idx = max_elements - alpha_element_count - 1;
- elements[idx] = &base_elements[idx];
- alpha_element_count++;
- return elements[idx];
- }
-
- void init() {
-
- element_count = 0;
- alpha_element_count = 0;
- elements = memnew_arr(Element *, max_elements);
- base_elements = memnew_arr(Element, max_elements);
- for (int i = 0; i < max_elements; i++)
- elements[i] = &base_elements[i]; // assign elements
- }
-
- RenderList() {
-
- max_elements = 0;
- }
-
- ~RenderList() {
- memdelete_arr(elements);
- memdelete_arr(base_elements);
- }
- };
-
- RenderList render_list;
-
- static RasterizerSceneHighEndRD *singleton;
- uint64_t render_pass;
- 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_radiance_uniform_set;
- RID default_render_buffers_uniform_set;
-
- RID default_vec4_xform_buffer;
- RID default_vec4_xform_uniform_set;
-
- LightClusterBuilder cluster_builder;
-
- 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,
- PASS_MODE_DEPTH_NORMAL_ROUGHNESS,
- PASS_MODE_DEPTH_MATERIAL,
- };
-
- void _setup_environment(RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2 &p_screen_pixel_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);
- void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, RID p_shadow_atlas, bool p_using_shadows);
- void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, RID p_environment);
- void _setup_gi_probes(RID *p_gi_probe_probe_cull_result, int p_gi_probe_probe_cull_count, const Transform &p_camera_transform);
-
- void _fill_instances(RenderList::Element **p_elements, int p_element_count, bool p_for_depth);
- void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderList::Element **p_elements, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, bool p_no_gi, RID p_radiance_uniform_set, RID p_render_buffers_uniform_set);
- _FORCE_INLINE_ void _add_geometry(InstanceBase *p_instance, uint32_t p_surface, RID p_material, PassMode p_pass_mode, uint32_t p_geometry_index);
- _FORCE_INLINE_ void _add_geometry_with_material(InstanceBase *p_instance, uint32_t p_surface, MaterialData *p_material, RID p_material_rid, PassMode p_pass_mode, uint32_t p_geometry_index);
-
- void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, PassMode p_pass_mode, bool p_no_gi);
-
- void _draw_sky(RD::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, float p_alpha);
-
-protected:
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, 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);
- virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, 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);
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
-
-public:
- virtual void set_time(double p_time, double p_step);
-
- virtual bool free(RID p_rid);
-
- RasterizerSceneHighEndRD(RasterizerStorageRD *p_storage);
- ~RasterizerSceneHighEndRD();
-};
-#endif // RASTERIZER_SCENE_HIGHEND_RD_H
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
deleted file mode 100644
index 457f6970c8..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
+++ /dev/null
@@ -1,3229 +0,0 @@
-/*************************************************************************/
-/* rasterizer_scene_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer_scene_rd.h"
-
-#include "core/os/os.h"
-#include "core/project_settings.h"
-#include "servers/visual/visual_server_raster.h"
-
-uint64_t RasterizerSceneRD::auto_exposure_counter = 2;
-
-void RasterizerSceneRD::_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 RasterizerSceneRD::_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 ? 7 : 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 ? 7 : 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.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 RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality) {
-
- if (sky_use_cubemap_array) {
-
- if (p_quality) {
- //render directly to the layers
- for (int i = 0; i < rd.layers.size(); i++) {
- storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].views[0], 10, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0), rd.layers[i].mipmaps[0].size.x);
- }
- } else {
- // Use fast filtering. Render directly to base mip levels
- storage->get_effects()->cubemap_downsample(p_panorama, true, 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, false, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size);
- }
- Vector<RID> views;
- for (int i = 0; i < rd.layers.size(); i++) {
- views.push_back(rd.layers[i].views[0]);
- }
-
- storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, true);
- }
- } else {
-
- if (p_quality) {
- //render directly to the layers
- for (int i = 0; i < rd.layers[0].mipmaps.size(); i++) {
- storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].views[i], 10, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[i].size.x);
- }
- } else {
- // Use fast filtering. Render directly to each mip level
- storage->get_effects()->cubemap_downsample(p_panorama, true, 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, false, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size);
- }
- storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, rd.layers[0].views, false);
- }
- }
-}
-
-void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer) {
-
- if (p_use_arrays) {
-
- if (p_quality) {
- //render directly to the layers
- storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, 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_downsample(rd.radiance_base_cubemap, false, 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, false, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size);
- }
- Vector<RID> views;
- for (int i = 0; i < rd.layers.size(); i++) {
- views.push_back(rd.layers[i].views[0]);
- }
-
- storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, views, true);
- }
- } else {
-
- if (p_quality) {
-
- storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], false, 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);
- } else {
-
- storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, 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, false, rd.downsampled_layer.mipmaps[i].view, rd.downsampled_layer.mipmaps[i].size);
- }
- storage->get_effects()->cubemap_filter(rd.downsampled_radiance_cubemap, rd.layers[0].views, false);
- }
- }
-}
-
-void RasterizerSceneRD::_update_reflection_mipmaps(ReflectionData &rd, bool p_quality) {
-
- if (sky_use_cubemap_array) {
-
- for (int i = 0; i < rd.layers.size(); i++) {
- for (int j = 0; j < rd.layers[i].mipmaps.size() - 1; j++) {
- for (int k = 0; k < 6; k++) {
- RID view = rd.layers[i].mipmaps[j].views[k];
- RID fb = rd.layers[i].mipmaps[j + 1].framebuffers[k];
- Vector2 size = rd.layers[i].mipmaps[j].size;
- size = Vector2(1.0 / size.x, 1.0 / size.y);
- storage->get_effects()->make_mipmap(view, fb, size);
- }
- }
- }
- }
-}
-
-RID RasterizerSceneRD::sky_create() {
- return sky_owner.make_rid(Sky());
-}
-
-void RasterizerSceneRD::_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 RasterizerSceneRD::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 == VS::SKY_MODE_REALTIME && sky->radiance_size != 128) {
- WARN_PRINT("Realtime Skies can only use a radiance size of 128. Radiance size will be set to 128 internally.");
- sky->radiance_size = 128;
- }
-
- _sky_invalidate(sky);
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
-}
-
-void RasterizerSceneRD::sky_set_mode(RID p_sky, VS::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 == VS::SKY_MODE_REALTIME && sky->radiance_size != 128) {
- WARN_PRINT("Realtime Skies can only use a radiance size of 128. Radiance size will be set to 128 internally.");
- sky_set_radiance_size(p_sky, 128);
- }
-
- _sky_invalidate(sky);
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
-}
-
-void RasterizerSceneRD::sky_set_texture(RID p_sky, RID p_panorama) {
-
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND(!sky);
-
- if (sky->panorama.is_valid()) {
- sky->panorama = RID();
- if (sky->radiance.is_valid()) {
- RD::get_singleton()->free(sky->radiance);
- sky->radiance = RID();
- }
- _clear_reflection_data(sky->reflection);
- }
-
- sky->panorama = p_panorama;
-
- if (!sky->panorama.is_valid())
- return; //cleared
-
- _sky_invalidate(sky);
-}
-void RasterizerSceneRD::_update_dirty_skys() {
-
- Sky *sky = dirty_sky_list;
-
- while (sky) {
-
- //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 = sky->mode == VS::SKY_MODE_REALTIME ? 7 : roughness_layers;
-
- 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.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 == VS::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.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 == VS::SKY_MODE_REALTIME);
- }
- }
-
- RID panorama_texture = storage->texture_get_rd_texture(sky->panorama);
-
- if (panorama_texture.is_valid()) {
- //is there a panorama texture?
- _create_reflection_from_panorama(sky->reflection, panorama_texture, sky->mode == VS::SKY_MODE_QUALITY);
- _update_reflection_mipmaps(sky->reflection, sky->mode == VS::SKY_MODE_QUALITY);
- }
-
- Sky *next = sky->dirty_list;
- sky->dirty_list = nullptr;
- sky->dirty = false;
- sky = next;
- }
-
- dirty_sky_list = nullptr;
-}
-
-RID RasterizerSceneRD::sky_get_panorama_texture_rd(RID p_sky) const {
-
- Sky *sky = sky_owner.getornull(p_sky);
- ERR_FAIL_COND_V(!sky, RID());
- if (sky->panorama.is_null()) {
- return RID();
- }
-
- return storage->texture_get_rd_texture(sky->panorama, true);
-}
-RID RasterizerSceneRD::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 RasterizerSceneRD::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.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 RasterizerSceneRD::environment_create() {
-
- return environment_owner.make_rid(Environent());
-}
-
-void RasterizerSceneRD::environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->background = p_bg;
-}
-void RasterizerSceneRD::environment_set_sky(RID p_env, RID p_sky) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->sky = p_sky;
-}
-void RasterizerSceneRD::environment_set_sky_custom_fov(RID p_env, float p_scale) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->sky_custom_fov = p_scale;
-}
-void RasterizerSceneRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->sky_orientation = p_orientation;
-}
-void RasterizerSceneRD::environment_set_bg_color(RID p_env, const Color &p_color) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->bg_color = p_color;
-}
-void RasterizerSceneRD::environment_set_bg_energy(RID p_env, float p_energy) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->bg_energy = p_energy;
-}
-void RasterizerSceneRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->canvas_max_layer = p_max_layer;
-}
-void RasterizerSceneRD::environment_set_ambient_light(RID p_env, const Color &p_color, VS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, VS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) {
- Environent *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;
-}
-
-VS::EnvironmentBG RasterizerSceneRD::environment_get_background(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, VS::ENV_BG_MAX);
- return env->background;
-}
-RID RasterizerSceneRD::environment_get_sky(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, RID());
- return env->sky;
-}
-float RasterizerSceneRD::environment_get_sky_custom_fov(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, 0);
- return env->sky_custom_fov;
-}
-Basis RasterizerSceneRD::environment_get_sky_orientation(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, Basis());
- return env->sky_orientation;
-}
-Color RasterizerSceneRD::environment_get_bg_color(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, Color());
- return env->bg_color;
-}
-float RasterizerSceneRD::environment_get_bg_energy(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, 0);
- return env->bg_energy;
-}
-int RasterizerSceneRD::environment_get_canvas_max_layer(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, 0);
- return env->canvas_max_layer;
-}
-Color RasterizerSceneRD::environment_get_ambient_light_color(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, Color());
- return env->ambient_light;
-}
-VS::EnvironmentAmbientSource RasterizerSceneRD::environment_get_ambient_light_ambient_source(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, VS::ENV_AMBIENT_SOURCE_BG);
- return env->ambient_source;
-}
-float RasterizerSceneRD::environment_get_ambient_light_ambient_energy(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, 0);
- return env->ambient_light_energy;
-}
-float RasterizerSceneRD::environment_get_ambient_sky_contribution(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, 0);
- return env->ambient_sky_contribution;
-}
-VS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_source(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, VS::ENV_REFLECTION_SOURCE_DISABLED);
- return env->reflection_source;
-}
-
-Color RasterizerSceneRD::environment_get_ao_color(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, Color());
- return env->ao_color;
-}
-
-void RasterizerSceneRD::environment_set_tonemap(RID p_env, VS::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) {
- Environent *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;
-}
-
-void RasterizerSceneRD::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {
-
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
- env->glow_enabled = p_enable;
- env->glow_levels = p_level_flags;
- 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->glow_bicubic_upscale = p_bicubic_upscale;
-}
-
-void RasterizerSceneRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
-
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND(!env);
-
- env->ssao_enabled = p_enable;
- env->ssao_radius = p_radius;
- env->ssao_intensity = p_intensity;
- env->ssao_bias = p_bias;
- env->ssao_direct_light_affect = p_light_affect;
- env->ssao_ao_channel_affect = p_ao_channel_affect;
- env->ssao_blur = p_blur;
-}
-
-void RasterizerSceneRD::environment_set_ssao_quality(VS::EnvironmentSSAOQuality p_quality, bool p_half_size) {
- ssao_quality = p_quality;
- ssao_half_size = p_half_size;
-}
-
-bool RasterizerSceneRD::environment_is_ssao_enabled(RID p_env) const {
-
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, false);
- return env->ssao_enabled;
-}
-
-float RasterizerSceneRD::environment_get_ssao_ao_affect(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, false);
- return env->ssao_ao_channel_affect;
-}
-float RasterizerSceneRD::environment_get_ssao_light_affect(RID p_env) const {
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, false);
- return env->ssao_direct_light_affect;
-}
-
-bool RasterizerSceneRD::environment_is_ssr_enabled(RID p_env) const {
-
- Environent *env = environment_owner.getornull(p_env);
- ERR_FAIL_COND_V(!env, false);
- return false;
-}
-
-bool RasterizerSceneRD::is_environment(RID p_env) const {
- return environment_owner.owns(p_env);
-}
-
-////////////////////////////////////////////////////////////
-
-RID RasterizerSceneRD::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");
-
- return reflection_atlas_owner.make_rid(ra);
-}
-
-void RasterizerSceneRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
-
- ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas);
- ERR_FAIL_COND(!ra);
-
- if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
- return; //no changes
- }
-
- ra->size = p_reflection_size;
- ra->count = p_reflection_count;
-
- if (ra->reflection.is_valid()) {
- //clear and invalidate everything
- RD::get_singleton()->free(ra->reflection);
- ra->reflection = RID();
- 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);
- if (ra->reflections[i].owner.is_null()) {
- continue;
- }
- reflection_probe_release_atlas_index(ra->reflections[i].owner);
- //rp->atlasindex clear
- }
-
- ra->reflections.clear();
- }
-}
-
-////////////////////////
-RID RasterizerSceneRD::reflection_probe_instance_create(RID p_probe) {
- ReflectionProbeInstance rpi;
- rpi.probe = p_probe;
- return reflection_probe_instance_owner.make_rid(rpi);
-}
-
-void RasterizerSceneRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!rpi);
-
- rpi->transform = p_transform;
- rpi->dirty = true;
-}
-
-void RasterizerSceneRD::reflection_probe_release_atlas_index(RID p_instance) {
-
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!rpi);
-
- if (rpi->atlas.is_null()) {
- return; //nothing to release
- }
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
- ERR_FAIL_COND(!atlas);
- ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
- atlas->reflections.write[rpi->atlas_index].owner = RID();
- rpi->atlas_index = -1;
- rpi->atlas = RID();
-}
-
-bool RasterizerSceneRD::reflection_probe_instance_needs_redraw(RID p_instance) {
-
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
-
- if (rpi->rendering) {
- return false;
- }
-
- if (rpi->dirty) {
- return true;
- }
-
- if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) {
- return true;
- }
-
- return rpi->atlas_index == -1;
-}
-
-bool RasterizerSceneRD::reflection_probe_instance_has_reflection(RID p_instance) {
-
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
-
- return rpi->atlas.is_valid();
-}
-
-bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
-
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas);
-
- ERR_FAIL_COND_V(!atlas, false);
-
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
-
- if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 128) {
- WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 128. Please update the atlas size in the ProjectSettings.");
- reflection_atlas_set_size(p_reflection_atlas, 128, atlas->count);
- }
-
- if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 7) {
- // Invalidate reflection atlas, need to regenerate
- RD::get_singleton()->free(atlas->reflection);
- atlas->reflection = RID();
-
- for (int i = 0; i < atlas->reflections.size(); i++) {
- if (atlas->reflections[i].owner.is_null()) {
- continue;
- }
- reflection_probe_release_atlas_index(atlas->reflections[i].owner);
- }
-
- atlas->reflections.clear();
- }
-
- if (atlas->reflection.is_null()) {
- int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
- mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS ? 7 : mipmaps; // always use 7 mipmaps with real time filtering
- {
- //reflection atlas was unused, create:
- RD::TextureFormat tf;
- tf.array_layers = 6 * atlas->count;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
- tf.mipmaps = mipmaps;
- tf.width = atlas->size;
- tf.height = atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-
- atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
- {
-
- RD::TextureFormat tf;
- tf.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;
- tf.width = atlas->size;
- tf.height = atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
- 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) == VS::REFLECTION_PROBE_UPDATE_ALWAYS);
- for (int j = 0; j < 6; j++) {
- Vector<RID> fb;
- fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
- fb.push_back(atlas->depth_buffer);
- atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb);
- }
- }
-
- Vector<RID> fb;
- fb.push_back(atlas->depth_buffer);
- atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
- }
-
- if (rpi->atlas_index == -1) {
- for (int i = 0; i < atlas->reflections.size(); i++) {
- if (atlas->reflections[i].owner.is_null()) {
- rpi->atlas_index = i;
- break;
- }
- }
- //find the one used last
- if (rpi->atlas_index == -1) {
- //everything is in use, find the one least used via LRU
- uint64_t pass_min = 0;
-
- for (int i = 0; i < atlas->reflections.size(); i++) {
- ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.getornull(atlas->reflections[i].owner);
- if (rpi2->last_pass < pass_min) {
- pass_min = rpi2->last_pass;
- rpi->atlas_index = i;
- }
- }
- }
- }
-
- rpi->atlas = p_reflection_atlas;
- rpi->rendering = true;
- rpi->dirty = false;
- rpi->processing_layer = 1;
- rpi->processing_side = 0;
-
- return true;
-}
-
-bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instance) {
-
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
- ERR_FAIL_COND_V(!rpi->rendering, false);
- ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
-
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
- if (!atlas || rpi->atlas_index == -1) {
- //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
- rpi->rendering = false;
- return false;
- }
-
- if (rpi->processing_layer > 1) {
- _create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, 10, rpi->processing_layer);
- rpi->processing_layer++;
- if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
- rpi->rendering = false;
- rpi->processing_side = 0;
- rpi->processing_layer = 1;
- return true;
- }
- return false;
-
- } else {
- _create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side, rpi->processing_layer);
- }
-
- if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) {
- // Using real time reflections, all roughness is done in one step
- rpi->rendering = false;
- rpi->processing_side = 0;
- rpi->processing_layer = 1;
- return true;
- }
-
- rpi->processing_side++;
- if (rpi->processing_side == 6) {
- rpi->processing_side = 0;
- rpi->processing_layer++;
- }
-
- return false;
-}
-
-uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
-
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, 0);
- return atlas->size;
-}
-
-RID RasterizerSceneRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
- ERR_FAIL_INDEX_V(p_index, 6, RID());
-
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->reflections[rpi->atlas_index].fbs[p_index];
-}
-
-RID RasterizerSceneRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
- ERR_FAIL_INDEX_V(p_index, 6, RID());
-
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->depth_fb;
-}
-
-///////////////////////////////////////////////////////////
-
-RID RasterizerSceneRD::shadow_atlas_create() {
-
- return shadow_atlas_owner.make_rid(ShadowAtlas());
-}
-
-void RasterizerSceneRD::shadow_atlas_set_size(RID p_atlas, int p_size) {
-
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
- ERR_FAIL_COND(p_size < 0);
- p_size = next_power_of_2(p_size);
-
- if (p_size == shadow_atlas->size)
- return;
-
- // erasing atlas
- if (shadow_atlas->depth.is_valid()) {
- RD::get_singleton()->free(shadow_atlas->depth);
- shadow_atlas->depth = RID();
- shadow_atlas->fb = RID();
- }
- for (int i = 0; i < 4; i++) {
- //clear subdivisions
- shadow_atlas->quadrants[i].shadows.resize(0);
- shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision);
- }
-
- //erase shadow atlas reference from lights
- for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) {
- LightInstance *li = light_instance_owner.getornull(E->key());
- ERR_CONTINUE(!li);
- li->shadow_atlases.erase(p_atlas);
- }
-
- //clear owners
- shadow_atlas->shadow_owners.clear();
-
- shadow_atlas->size = p_size;
-
- if (shadow_atlas->size) {
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- tf.width = shadow_atlas->size;
- tf.height = shadow_atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- Vector<RID> fb;
- fb.push_back(shadow_atlas->depth);
- shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb);
- }
-}
-
-void RasterizerSceneRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
-
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
- ERR_FAIL_INDEX(p_quadrant, 4);
- ERR_FAIL_INDEX(p_subdivision, 16384);
-
- uint32_t subdiv = next_power_of_2(p_subdivision);
- if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer
- subdiv <<= 1;
- }
-
- subdiv = int(Math::sqrt((float)subdiv));
-
- //obtain the number that will be x*x
-
- if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv)
- return;
-
- //erase all data from quadrant
- for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
-
- if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
- shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
- LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
- ERR_CONTINUE(!li);
- li->shadow_atlases.erase(p_atlas);
- }
- }
-
- shadow_atlas->quadrants[p_quadrant].shadows.resize(0);
- shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv);
- shadow_atlas->quadrants[p_quadrant].subdivision = subdiv;
-
- //cache the smallest subdiv (for faster allocation in light update)
-
- shadow_atlas->smallest_subdiv = 1 << 30;
-
- for (int i = 0; i < 4; i++) {
- if (shadow_atlas->quadrants[i].subdivision) {
- shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision);
- }
- }
-
- if (shadow_atlas->smallest_subdiv == 1 << 30) {
- shadow_atlas->smallest_subdiv = 0;
- }
-
- //resort the size orders, simple bublesort for 4 elements..
-
- int swaps = 0;
- do {
- swaps = 0;
-
- for (int i = 0; i < 3; i++) {
- if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) {
- SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]);
- swaps++;
- }
- }
- } while (swaps > 0);
-}
-
-bool RasterizerSceneRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
-
- for (int i = p_quadrant_count - 1; i >= 0; i--) {
-
- int qidx = p_in_quadrants[i];
-
- if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
- return false;
- }
-
- //look for an empty space
- int sc = shadow_atlas->quadrants[qidx].shadows.size();
- ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw();
-
- int found_free_idx = -1; //found a free one
- int found_used_idx = -1; //found existing one, must steal it
- uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion)
-
- for (int j = 0; j < sc; j++) {
- if (!sarr[j].owner.is_valid()) {
- found_free_idx = j;
- break;
- }
-
- LightInstance *sli = light_instance_owner.getornull(sarr[j].owner);
- ERR_CONTINUE(!sli);
-
- if (sli->last_scene_pass != scene_pass) {
-
- //was just allocated, don't kill it so soon, wait a bit..
- if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec)
- continue;
-
- if (found_used_idx == -1 || sli->last_scene_pass < min_pass) {
- found_used_idx = j;
- min_pass = sli->last_scene_pass;
- }
- }
- }
-
- if (found_free_idx == -1 && found_used_idx == -1)
- continue; //nothing found
-
- if (found_free_idx == -1 && found_used_idx != -1) {
- found_free_idx = found_used_idx;
- }
-
- r_quadrant = qidx;
- r_shadow = found_free_idx;
-
- return true;
- }
-
- return false;
-}
-
-bool RasterizerSceneRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
-
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND_V(!shadow_atlas, false);
-
- LightInstance *li = light_instance_owner.getornull(p_light_intance);
- ERR_FAIL_COND_V(!li, false);
-
- if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
- return false;
- }
-
- uint32_t quad_size = shadow_atlas->size >> 1;
- int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
-
- int valid_quadrants[4];
- int valid_quadrant_count = 0;
- int best_size = -1; //best size found
- int best_subdiv = -1; //subdiv for the best size
-
- //find the quadrants this fits into, and the best possible size it can fit into
- for (int i = 0; i < 4; i++) {
- int q = shadow_atlas->size_order[i];
- int sd = shadow_atlas->quadrants[q].subdivision;
- if (sd == 0)
- continue; //unused
-
- int max_fit = quad_size / sd;
-
- if (best_size != -1 && max_fit > best_size)
- break; //too large
-
- valid_quadrants[valid_quadrant_count++] = q;
- best_subdiv = sd;
-
- if (max_fit >= desired_fit) {
- best_size = max_fit;
- }
- }
-
- ERR_FAIL_COND_V(valid_quadrant_count == 0, false);
-
- uint64_t tick = OS::get_singleton()->get_ticks_msec();
-
- //see if it already exists
-
- if (shadow_atlas->shadow_owners.has(p_light_intance)) {
- //it does!
- uint32_t key = shadow_atlas->shadow_owners[p_light_intance];
- uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
- bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version;
-
- if (!should_realloc) {
- shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
- //already existing, see if it should redraw or it's just OK
- return should_redraw;
- }
-
- int new_quadrant, new_shadow;
-
- //find a better place
- if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) {
- //found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- if (sh->owner.is_valid()) {
- //is taken, but is invalid, erasing it
- shadow_atlas->shadow_owners.erase(sh->owner);
- LightInstance *sli = light_instance_owner.getornull(sh->owner);
- sli->shadow_atlases.erase(p_atlas);
- }
-
- //erase previous
- shadow_atlas->quadrants[q].shadows.write[s].version = 0;
- shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
-
- sh->owner = p_light_intance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
- li->shadow_atlases.insert(p_atlas);
-
- //make new key
- key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- key |= new_shadow;
- //update it in map
- shadow_atlas->shadow_owners[p_light_intance] = key;
- //make it dirty, as it should redraw anyway
- return true;
- }
-
- //no better place for this shadow found, keep current
-
- //already existing, see if it should redraw or it's just OK
-
- shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
-
- return should_redraw;
- }
-
- int new_quadrant, new_shadow;
-
- //find a better place
- if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) {
- //found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- if (sh->owner.is_valid()) {
- //is taken, but is invalid, erasing it
- shadow_atlas->shadow_owners.erase(sh->owner);
- LightInstance *sli = light_instance_owner.getornull(sh->owner);
- sli->shadow_atlases.erase(p_atlas);
- }
-
- sh->owner = p_light_intance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
- li->shadow_atlases.insert(p_atlas);
-
- //make new key
- uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- key |= new_shadow;
- //update it in map
- shadow_atlas->shadow_owners[p_light_intance] = key;
- //make it dirty, as it should redraw anyway
-
- return true;
- }
-
- //no place to allocate this light, apologies
-
- return false;
-}
-
-void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) {
-
- p_size = nearest_power_of_2_templated(p_size);
-
- if (directional_shadow.size == p_size) {
- return;
- }
-
- directional_shadow.size = p_size;
-
- if (directional_shadow.depth.is_valid()) {
- RD::get_singleton()->free(directional_shadow.depth);
- directional_shadow.depth = RID();
- directional_shadow.fb = RID();
- }
-
- if (p_size > 0) {
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- tf.width = p_size;
- tf.height = p_size;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- Vector<RID> fb;
- fb.push_back(directional_shadow.depth);
- directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb);
- }
-
- _base_uniforms_changed();
-}
-
-void RasterizerSceneRD::set_directional_shadow_count(int p_count) {
-
- directional_shadow.light_count = p_count;
- directional_shadow.current_light = 0;
-}
-
-static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) {
-
- int split_h = 1;
- int split_v = 1;
-
- while (split_h * split_v < p_shadow_count) {
- if (split_h == split_v) {
- split_h <<= 1;
- } else {
- split_v <<= 1;
- }
- }
-
- Rect2i rect(0, 0, p_size, p_size);
- rect.size.width /= split_h;
- rect.size.height /= split_v;
-
- rect.position.x = rect.size.width * (p_shadow_index % split_h);
- rect.position.y = rect.size.height * (p_shadow_index / split_h);
-
- return rect;
-}
-
-int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) {
-
- ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
-
- Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
-
- LightInstance *light_instance = light_instance_owner.getornull(p_light_intance);
- ERR_FAIL_COND_V(!light_instance, 0);
-
- switch (storage->light_directional_get_shadow_mode(light_instance->light)) {
- case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
- break; //none
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: r.size.height /= 2; break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: r.size /= 2; break;
- }
-
- return MAX(r.size.width, r.size.height);
-}
-
-//////////////////////////////////////////////////
-
-RID RasterizerSceneRD::camera_effects_create() {
-
- return camera_effects_owner.make_rid(CameraEffects());
-}
-
-void RasterizerSceneRD::camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter) {
-
- dof_blur_quality = p_quality;
- dof_blur_use_jitter = p_use_jitter;
-}
-
-void RasterizerSceneRD::camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape) {
-
- dof_blur_bokeh_shape = p_shape;
-}
-
-void RasterizerSceneRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) {
- CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
- ERR_FAIL_COND(!camfx);
-
- camfx->dof_blur_far_enabled = p_far_enable;
- camfx->dof_blur_far_distance = p_far_distance;
- camfx->dof_blur_far_transition = p_far_transition;
-
- camfx->dof_blur_near_enabled = p_near_enable;
- camfx->dof_blur_near_distance = p_near_distance;
- camfx->dof_blur_near_transition = p_near_transition;
-
- camfx->dof_blur_amount = p_amount;
-}
-
-void RasterizerSceneRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) {
-
- CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
- ERR_FAIL_COND(!camfx);
-
- camfx->override_exposure_enabled = p_enable;
- camfx->override_exposure = p_exposure;
-}
-
-RID RasterizerSceneRD::light_instance_create(RID p_light) {
-
- RID li = light_instance_owner.make_rid(LightInstance());
-
- LightInstance *light_instance = light_instance_owner.getornull(li);
-
- light_instance->self = li;
- light_instance->light = p_light;
- light_instance->light_type = storage->light_get_type(p_light);
-
- return li;
-}
-
-void RasterizerSceneRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {
-
- LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->transform = p_transform;
-}
-
-void RasterizerSceneRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) {
-
- LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- if (storage->light_get_type(light_instance->light) != VS::LIGHT_DIRECTIONAL) {
- p_pass = 0;
- }
-
- ERR_FAIL_INDEX(p_pass, 4);
-
- light_instance->shadow_transform[p_pass].camera = p_projection;
- light_instance->shadow_transform[p_pass].transform = p_transform;
- light_instance->shadow_transform[p_pass].farplane = p_far;
- light_instance->shadow_transform[p_pass].split = p_split;
- light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
-}
-
-void RasterizerSceneRD::light_instance_mark_visible(RID p_light_instance) {
-
- LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->last_scene_pass = scene_pass;
-}
-
-RasterizerSceneRD::ShadowCubemap *RasterizerSceneRD::_get_shadow_cubemap(int p_size) {
-
- if (!shadow_cubemaps.has(p_size)) {
-
- ShadowCubemap sc;
- {
- RD::TextureFormat tf;
- tf.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;
- tf.width = p_size;
- tf.height = p_size;
- tf.type = RD::TEXTURE_TYPE_CUBE;
- tf.array_layers = 6;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- for (int i = 0; i < 6; i++) {
- RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0);
- Vector<RID> fbtex;
- fbtex.push_back(side_texture);
- sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex);
- }
-
- shadow_cubemaps[p_size] = sc;
- }
-
- return &shadow_cubemaps[p_size];
-}
-
-RasterizerSceneRD::ShadowMap *RasterizerSceneRD::_get_shadow_map(const Size2i &p_size) {
-
- if (!shadow_maps.has(p_size)) {
-
- ShadowMap sm;
- {
- RD::TextureFormat tf;
- tf.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;
- tf.width = p_size.width;
- tf.height = p_size.height;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
- sm.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- Vector<RID> fbtex;
- fbtex.push_back(sm.depth);
- sm.fb = RD::get_singleton()->framebuffer_create(fbtex);
-
- shadow_maps[p_size] = sm;
- }
-
- return &shadow_maps[p_size];
-}
-/////////////////////////////////
-
-RID RasterizerSceneRD::gi_probe_instance_create(RID p_base) {
- //find a free slot
- int index = -1;
- for (int i = 0; i < gi_probe_slots.size(); i++) {
- if (gi_probe_slots[i] == RID()) {
- index = i;
- break;
- }
- }
-
- ERR_FAIL_COND_V(index == -1, RID());
-
- GIProbeInstance gi_probe;
- gi_probe.slot = index;
- gi_probe.probe = p_base;
- RID rid = gi_probe_instance_owner.make_rid(gi_probe);
- gi_probe_slots.write[index] = rid;
-
- return rid;
-}
-
-void RasterizerSceneRD::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;
-}
-
-bool RasterizerSceneRD::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);
-
- //return true;
- return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe);
-}
-
-void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, int p_dynamic_object_count, InstanceBase **p_dynamic_objects) {
-
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- ERR_FAIL_COND(!gi_probe);
-
- 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);
- if (gi_probe_use_anisotropy) {
- RD::get_singleton()->free(gi_probe->anisotropy_r16[0]);
- RD::get_singleton()->free(gi_probe->anisotropy_r16[1]);
- }
- 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.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, false);
-
- if (gi_probe_use_anisotropy) {
- tf.format = RD::DATA_FORMAT_R16_UINT;
- tf.shareable_formats.push_back(RD::DATA_FORMAT_R16_UINT);
- tf.shareable_formats.push_back(RD::DATA_FORMAT_R5G6B5_UNORM_PACK16);
-
- //need to create R16 first, else driver does not like the storage bit for compute..
- gi_probe->anisotropy_r16[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
- gi_probe->anisotropy_r16[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_R5G6B5_UNORM_PACK16;
- gi_probe->anisotropy[0] = RD::get_singleton()->texture_create_shared(tv, gi_probe->anisotropy_r16[0]);
- gi_probe->anisotropy[1] = RD::get_singleton()->texture_create_shared(tv, gi_probe->anisotropy_r16[1]);
-
- RD::get_singleton()->texture_clear(gi_probe->anisotropy[0], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
- RD::get_singleton()->texture_clear(gi_probe->anisotropy[1], Color(0, 0, 0, 0), 0, levels.size(), 0, 1, false);
- }
-
- {
- int total_elements = 0;
- for (int i = 0; i < levels.size(); i++) {
- total_elements += levels[i];
- }
-
- if (gi_probe_use_anisotropy) {
- total_elements *= 6;
- }
-
- 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);
- if (gi_probe_use_anisotropy) {
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_R16_UINT;
- mipmap.anisotropy[0] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[0], 0, i, RD::TEXTURE_SLICE_3D);
- mipmap.anisotropy[1] = RD::get_singleton()->texture_create_shared_from_slice(tv, gi_probe->anisotropy[1], 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.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.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.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.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.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- {
- Vector<RD::Uniform> copy_uniforms = uniforms;
- if (i == 0) {
- {
- RD::Uniform u;
- u.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.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 5;
- u.ids.push_back(gi_probe->texture);
- copy_uniforms.push_back(u);
- }
-
- if (gi_probe_use_anisotropy) {
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 7;
- u.ids.push_back(gi_probe->anisotropy[0]);
- copy_uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 8;
- u.ids.push_back(gi_probe->anisotropy[1]);
- 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.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(mipmap.texture);
- uniforms.push_back(u);
- }
-
- if (gi_probe_use_anisotropy) {
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(mipmap.anisotropy[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(mipmap.anisotropy[1]);
- 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.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.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 5;
- u.ids.push_back(dmap.albedo);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 6;
- u.ids.push_back(dmap.normal);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(dmap.orm);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 8;
- u.ids.push_back(dmap.fb_depth);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.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.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(dmap.texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.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.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.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.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 7;
- u.ids.push_back(dmap.texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 8;
- u.ids.push_back(dmap.depth);
- uniforms.push_back(u);
- }
- }
-
- {
- RD::Uniform u;
- u.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.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 10;
- u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- if (plot) {
-
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
- u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].texture);
- uniforms.push_back(u);
- }
- if (gi_probe_is_anisotropic()) {
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
- u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 13;
- u.ids.push_back(gi_probe->mipmaps[dmap.mipmap].anisotropy[1]);
- 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, true);
- if (gi_probe_is_anisotropic()) {
- RD::get_singleton()->texture_clear(gi_probe->anisotropy[0], Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
- RD::get_singleton()->texture_clear(gi_probe->anisotropy[1], Color(0, 0, 0, 0), 0, gi_probe->mipmaps.size(), 0, 1, true);
- }
- }
-
- uint32_t light_count = 0;
-
- if (p_update_light_instances || p_dynamic_object_count > 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);
- l.attenuation = storage->light_get_param(light, VS::LIGHT_PARAM_ATTENUATION);
- l.energy = storage->light_get_param(light, VS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, VS::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.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, VS::LIGHT_PARAM_SPOT_ANGLE));
- l.spot_attenuation = storage->light_get_param(light, VS::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, true);
- }
- }
-
- if (gi_probe->has_dynamic_object_data || p_update_light_instances || p_dynamic_object_count) {
- // 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 = storage->gi_probe_get_anisotropy_strength(gi_probe->probe);
-
- /* 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_object_count && 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 < p_dynamic_object_count; i++) {
-
- InstanceBase *instance = p_dynamic_objects[i];
- //not used, so clear
- instance->depth_layer = 0;
- instance->depth = 0;
-
- //transform aabb to giprobe
- AABB aabb = (to_probe_xform * instance->transform).xform(instance->aabb);
-
- //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]);
-
- _render_material(to_world_xform * xform, cm, true, &instance, 1, 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 RasterizerSceneRD::_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.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.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 2;
- u.ids.push_back(gi_probe->texture);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 3;
- u.ids.push_back(storage->sampler_rd_get_default(VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
- uniforms.push_back(u);
- }
-
- if (gi_probe_use_anisotropy) {
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 4;
- u.ids.push_back(gi_probe->anisotropy[0]);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 5;
- u.ids.push_back(gi_probe->anisotropy[1]);
- 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);
- RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, giprobe_debug_shader_version_pipelines[p_emission ? GI_PROBE_DEBUG_EMISSION : p_lighting ? (gi_probe->has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT) : GI_PROBE_DEBUG_COLOR].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);
-}
-
-const Vector<RID> &RasterizerSceneRD::gi_probe_get_slots() const {
-
- return gi_probe_slots;
-}
-
-RasterizerSceneRD::GIProbeQuality RasterizerSceneRD::gi_probe_get_quality() const {
- return gi_probe_quality;
-}
-
-////////////////////////////////
-RID RasterizerSceneRD::render_buffers_create() {
- RenderBuffers rb;
- rb.data = _create_render_buffer_data();
- return render_buffers_owner.make_rid(rb);
-}
-
-void RasterizerSceneRD::_allocate_blur_textures(RenderBuffers *rb) {
- ERR_FAIL_COND(!rb->blur[0].texture.is_null());
-
- uint32_t mipmaps_required = Image::get_image_required_mipmaps(rb->width, rb->height, Image::FORMAT_RGBAH);
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
- tf.type = RD::TEXTURE_TYPE_2D;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- tf.mipmaps = mipmaps_required;
-
- rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- //the second one is smaller (only used for separatable part of blur)
- tf.width >>= 1;
- tf.height >>= 1;
- tf.mipmaps--;
- rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- int base_width = rb->width;
- int base_height = rb->height;
-
- for (uint32_t i = 0; i < mipmaps_required; i++) {
-
- RenderBuffers::Blur::Mipmap mm;
- mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[0].texture, 0, i);
- {
- Vector<RID> fbs;
- fbs.push_back(mm.texture);
- mm.framebuffer = RD::get_singleton()->framebuffer_create(fbs);
- }
-
- mm.width = base_width;
- mm.height = base_height;
-
- rb->blur[0].mipmaps.push_back(mm);
-
- if (i > 0) {
-
- mm.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->blur[1].texture, 0, i - 1);
- {
- Vector<RID> fbs;
- fbs.push_back(mm.texture);
- mm.framebuffer = RD::get_singleton()->framebuffer_create(fbs);
- }
-
- rb->blur[1].mipmaps.push_back(mm);
- }
-
- base_width = MAX(1, base_width >> 1);
- base_height = MAX(1, base_height >> 1);
- }
-}
-
-void RasterizerSceneRD::_allocate_luminance_textures(RenderBuffers *rb) {
- ERR_FAIL_COND(!rb->luminance.current.is_null());
-
- int w = rb->width;
- int h = rb->height;
-
- while (true) {
- w = MAX(w / 8, 1);
- h = MAX(h / 8, 1);
-
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- tf.width = w;
- tf.height = h;
- tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
-
- bool final = w == 1 && h == 1;
-
- if (final) {
- tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT;
- }
-
- RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- rb->luminance.reduce.push_back(texture);
-
- if (final) {
- rb->luminance.current = RD::get_singleton()->texture_create(tf, RD::TextureView());
- break;
- }
- }
-}
-
-void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) {
-
- if (rb->texture.is_valid()) {
- RD::get_singleton()->free(rb->texture);
- rb->texture = RID();
- }
-
- if (rb->depth_texture.is_valid()) {
- RD::get_singleton()->free(rb->depth_texture);
- rb->depth_texture = RID();
- }
-
- for (int i = 0; i < 2; i++) {
- if (rb->blur[i].texture.is_valid()) {
- RD::get_singleton()->free(rb->blur[i].texture);
- rb->blur[i].texture = RID();
- rb->blur[i].mipmaps.clear();
- }
- }
-
- for (int i = 0; i < rb->luminance.reduce.size(); i++) {
- RD::get_singleton()->free(rb->luminance.reduce[i]);
- }
-
- for (int i = 0; i < rb->luminance.reduce.size(); i++) {
- RD::get_singleton()->free(rb->luminance.reduce[i]);
- }
- rb->luminance.reduce.clear();
-
- if (rb->luminance.current.is_valid()) {
- RD::get_singleton()->free(rb->luminance.current);
- rb->luminance.current = RID();
- }
-
- if (rb->ssao.ao[0].is_valid()) {
- RD::get_singleton()->free(rb->ssao.depth);
- RD::get_singleton()->free(rb->ssao.ao[0]);
- if (rb->ssao.ao[1].is_valid()) {
- RD::get_singleton()->free(rb->ssao.ao[1]);
- }
- if (rb->ssao.ao_full.is_valid()) {
- RD::get_singleton()->free(rb->ssao.ao_full);
- }
-
- rb->ssao.depth = RID();
- rb->ssao.ao[0] = RID();
- rb->ssao.ao[1] = RID();
- rb->ssao.ao_full = RID();
- rb->ssao.depth_slices.clear();
- }
-}
-
-void RasterizerSceneRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) {
-
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- Environent *env = environment_owner.getornull(p_environment);
- ERR_FAIL_COND(!env);
-
- if (rb->ssao.ao[0].is_valid() && rb->ssao.ao_full.is_valid() != ssao_half_size) {
- RD::get_singleton()->free(rb->ssao.depth);
- RD::get_singleton()->free(rb->ssao.ao[0]);
- if (rb->ssao.ao[1].is_valid()) {
- RD::get_singleton()->free(rb->ssao.ao[1]);
- }
- if (rb->ssao.ao_full.is_valid()) {
- RD::get_singleton()->free(rb->ssao.ao_full);
- }
-
- rb->ssao.depth = RID();
- rb->ssao.ao[0] = RID();
- rb->ssao.ao[1] = RID();
- rb->ssao.ao_full = RID();
- rb->ssao.depth_slices.clear();
- }
-
- if (!rb->ssao.ao[0].is_valid()) {
- //allocate depth slices
-
- {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- tf.width = rb->width / 2;
- tf.height = rb->height / 2;
- tf.mipmaps = Image::get_image_required_mipmaps(tf.width, tf.height, Image::FORMAT_RF) + 1;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- rb->ssao.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- for (uint32_t i = 0; i < tf.mipmaps; i++) {
- RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ssao.depth, 0, i);
- rb->ssao.depth_slices.push_back(slice);
- }
- }
-
- {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = ssao_half_size ? rb->width / 2 : rb->width;
- tf.height = ssao_half_size ? rb->height / 2 : rb->height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- rb->ssao.ao[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->ssao.ao[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- if (ssao_half_size) {
- //upsample texture
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = rb->width;
- tf.height = rb->height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- rb->ssao.ao_full = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- _render_buffers_uniform_set_changed(p_render_buffers);
- }
-
- storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, Size2i(rb->width, rb->height), rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao[0], rb->ssao.ao_full.is_valid(), rb->ssao.ao[1], rb->ssao.ao_full, env->ssao_intensity, env->ssao_radius, env->ssao_bias, p_projection, ssao_quality, env->ssao_blur, env->ssao_blur_edge_sharpness);
-}
-
-void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection) {
-
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- Environent *env = environment_owner.getornull(p_environment);
- //glow (if enabled)
- CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects);
-
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
-
- 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;
- storage->get_effects()->bokeh_dof(rb->texture, rb->depth_texture, Size2i(rb->width, rb->height), rb->blur[0].mipmaps[0].texture, rb->blur[1].mipmaps[0].texture, rb->blur[0].mipmaps[1].texture, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_projection.get_z_near(), p_projection.get_z_far(), p_projection.is_orthogonal());
- }
-
- 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;
- rb->auto_exposure_version = env->auto_exposure_version;
-
- double step = env->auto_exp_speed * time_step;
- storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
-
- //swap final reduce with prev luminance
- SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]);
- VisualServerRaster::redraw_request(); //redraw all the time if auto exposure rendering is on
- }
-
- int max_glow_level = -1;
- int glow_mask = 0;
-
- if (can_use_effects && env && env->glow_enabled) {
-
- /* see that blur textures are allocated */
-
- if (rb->blur[0].texture.is_null()) {
- _allocate_blur_textures(rb);
- _render_buffers_uniform_set_changed(p_render_buffers);
- }
-
- for (int i = 0; i < VS::MAX_GLOW_LEVELS; i++) {
- if (env->glow_levels & (1 << i)) {
-
- if (i >= rb->blur[1].mipmaps.size()) {
- max_glow_level = rb->blur[1].mipmaps.size() - 1;
- glow_mask |= 1 << max_glow_level;
-
- } else {
- max_glow_level = i;
- glow_mask |= (1 << i);
- }
- }
- }
-
- for (int i = 0; i < (max_glow_level + 1); i++) {
-
- int vp_w = rb->blur[1].mipmaps[i].width;
- int vp_h = rb->blur[1].mipmaps[i].height;
-
- if (i == 0) {
- RID luminance_texture;
- if (env->auto_exposure && rb->luminance.current.is_valid()) {
- luminance_texture = rb->luminance.current;
- }
- storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].framebuffer, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].framebuffer, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
- } else {
- storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].framebuffer, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].framebuffer, Vector2(1.0 / vp_w, 1.0 / vp_h), env->glow_strength);
- }
- }
- }
-
- {
- //tonemap
- RasterizerEffectsRD::TonemapSettings tonemap;
-
- tonemap.color_correction_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
-
- if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) {
- tonemap.use_auto_exposure = true;
- tonemap.exposure_texture = rb->luminance.current;
- tonemap.auto_exposure_grey = env->auto_exp_scale;
- } else {
-
- tonemap.exposure_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
- }
-
- if (can_use_effects && env && env->glow_enabled) {
- tonemap.use_glow = true;
- tonemap.glow_mode = RasterizerEffectsRD::TonemapSettings::GlowMode(env->glow_blend_mode);
- tonemap.glow_intensity = env->glow_blend_mode == VS::ENV_GLOW_BLEND_MODE_MIX ? env->glow_mix : env->glow_intensity;
- tonemap.glow_level_flags = glow_mask;
- tonemap.glow_texture_size.x = rb->blur[1].mipmaps[0].width;
- tonemap.glow_texture_size.y = rb->blur[1].mipmaps[0].height;
- tonemap.glow_use_bicubic_upscale = env->glow_bicubic_upscale;
- tonemap.glow_texture = rb->blur[1].texture;
- } else {
- tonemap.glow_texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_BLACK);
- }
-
- if (env) {
- tonemap.tonemap_mode = env->tone_mapper;
- tonemap.white = env->white;
- tonemap.exposure = env->exposure;
- }
-
- storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
- }
-
- storage->render_target_disable_clear_request(rb->render_target);
-}
-
-void RasterizerSceneRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas) {
- RasterizerEffectsRD *effects = storage->get_effects();
-
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND(!rb);
-
- if (debug_draw == VS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
- if (p_shadow_atlas.is_valid()) {
- RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
-
- effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 2), false, true);
- }
- }
-
- if (debug_draw == VS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) {
- if (directional_shadow_get_texture().is_valid()) {
- RID shadow_atlas_texture = directional_shadow_get_texture();
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
-
- effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 2), false, true);
- }
- }
-
- if (debug_draw == VS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) {
- if (rb->luminance.current.is_valid()) {
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
-
- effects->copy_to_rect(rb->luminance.current, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize / 8), false, true);
- }
- }
-
- if (debug_draw == VS::VIEWPORT_DEBUG_DRAW_SSAO && rb->ssao.ao[0].is_valid()) {
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
- RID ao_buf = rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0];
- effects->copy_to_rect(ao_buf, storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true);
- }
-
- if (debug_draw == VS::VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER && _render_buffers_get_roughness_texture(p_render_buffers).is_valid()) {
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
- effects->copy_to_rect(_render_buffers_get_roughness_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize), false, true);
- }
-
- if (debug_draw == VS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) {
- Size2 rtsize = storage->render_target_get_size(rb->render_target);
- effects->copy_to_rect(_render_buffers_get_normal_texture(p_render_buffers), storage->render_target_get_rd_framebuffer(rb->render_target), Rect2(Vector2(), rtsize));
- }
-}
-
-RID RasterizerSceneRD::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());
- if (!rb->blur[0].texture.is_valid()) {
- return RID(); //not valid at the moment
- }
- return rb->blur[0].texture;
-}
-
-RID RasterizerSceneRD::render_buffers_get_ao_texture(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND_V(!rb, RID());
-
- return rb->ssao.ao_full.is_valid() ? rb->ssao.ao_full : rb->ssao.ao[0];
-}
-
-void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa) {
-
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- rb->width = p_width;
- rb->height = p_height;
- rb->render_target = p_render_target;
- rb->msaa = p_msaa;
- _free_render_buffer_data(rb);
-
- {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-
- rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- {
- RD::TextureFormat tf;
- 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.width = p_width;
- tf.height = p_height;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-
- rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
- _render_buffers_uniform_set_changed(p_render_buffers);
-}
-
-int RasterizerSceneRD::get_roughness_layers() const {
- return roughness_layers;
-}
-
-bool RasterizerSceneRD::is_using_radiance_cubemap_array() const {
- return sky_use_cubemap_array;
-}
-
-RasterizerSceneRD::RenderBufferData *RasterizerSceneRD::render_buffers_get_data(RID p_render_buffers) {
- RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
- ERR_FAIL_COND_V(!rb, NULL);
- return rb->data;
-}
-
-void RasterizerSceneRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
-
- 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();
- }
-
- _render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_light_cull_result, p_light_cull_count, p_reflection_probe_cull_result, p_reflection_probe_cull_count, p_gi_probe_cull_result, p_gi_probe_cull_count, p_environment, p_camera_effects, p_shadow_atlas, p_reflection_atlas, p_reflection_probe, p_reflection_probe_pass, clear_color);
-
- if (p_render_buffers.is_valid()) {
- 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);
- }
-}
-
-void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
-
- LightInstance *light_instance = light_instance_owner.getornull(p_light);
- ERR_FAIL_COND(!light_instance);
-
- Rect2i atlas_rect;
- RID atlas_fb;
-
- bool using_dual_paraboloid = false;
- bool using_dual_paraboloid_flip = false;
- float zfar = 0;
- RID render_fb;
- RID render_texture;
- float bias = 0;
- float normal_bias = 0;
-
- bool render_cubemap = false;
- bool finalize_cubemap = false;
-
- CameraMatrix light_projection;
- Transform light_transform;
-
- if (storage->light_get_type(light_instance->light) == VS::LIGHT_DIRECTIONAL) {
- //set pssm stuff
- if (light_instance->last_scene_shadow_pass != scene_pass) {
- light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
- directional_shadow.current_light++;
- light_instance->last_scene_shadow_pass = scene_pass;
- }
-
- light_projection = light_instance->shadow_transform[p_pass].camera;
- light_transform = light_instance->shadow_transform[p_pass].transform;
-
- atlas_rect.position.x = light_instance->directional_rect.position.x;
- atlas_rect.position.y = light_instance->directional_rect.position.y;
- atlas_rect.size.width = light_instance->directional_rect.size.x;
- atlas_rect.size.height = light_instance->directional_rect.size.y;
-
- if (storage->light_directional_get_shadow_mode(light_instance->light) == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
-
- atlas_rect.size.width /= 2;
- atlas_rect.size.height /= 2;
-
- if (p_pass == 1) {
- atlas_rect.position.x += atlas_rect.size.width;
- } else if (p_pass == 2) {
- atlas_rect.position.y += atlas_rect.size.height;
- } else if (p_pass == 3) {
- atlas_rect.position.x += atlas_rect.size.width;
- atlas_rect.position.y += atlas_rect.size.height;
- }
-
- } else if (storage->light_directional_get_shadow_mode(light_instance->light) == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
-
- atlas_rect.size.height /= 2;
-
- if (p_pass == 0) {
-
- } else {
- atlas_rect.position.y += atlas_rect.size.height;
- }
- }
-
- light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect;
-
- light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size;
- light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size;
-
- float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE));
- zfar = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_RANGE);
- bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult;
- normal_bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * bias_mult;
-
- ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
- render_fb = shadow_map->fb;
- render_texture = shadow_map->depth;
- atlas_fb = directional_shadow.fb;
-
- } else {
- //set from shadow atlas
-
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
- ERR_FAIL_COND(!shadow_atlas);
- ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light));
-
- uint32_t key = shadow_atlas->shadow_owners[p_light];
-
- uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size());
-
- uint32_t quadrant_size = shadow_atlas->size >> 1;
-
- atlas_rect.position.x = (quadrant & 1) * quadrant_size;
- atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
-
- uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
- atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
- atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
-
- atlas_rect.size.width = shadow_size;
- atlas_rect.size.height = shadow_size;
- atlas_fb = shadow_atlas->fb;
-
- zfar = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_RANGE);
- bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS);
- normal_bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS);
-
- if (storage->light_get_type(light_instance->light) == VS::LIGHT_OMNI) {
-
- if (storage->light_omni_get_shadow_mode(light_instance->light) == VS::LIGHT_OMNI_SHADOW_CUBE) {
-
- ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2);
-
- render_fb = cubemap->side_fb[p_pass];
- render_texture = cubemap->cubemap;
-
- light_projection = light_instance->shadow_transform[0].camera;
- light_transform = light_instance->shadow_transform[0].transform;
- render_cubemap = true;
- finalize_cubemap = p_pass == 5;
-
- } else {
-
- light_projection = light_instance->shadow_transform[0].camera;
- light_transform = light_instance->shadow_transform[0].transform;
-
- atlas_rect.size.height /= 2;
- atlas_rect.position.y += p_pass * atlas_rect.size.height;
-
- using_dual_paraboloid = true;
- using_dual_paraboloid_flip = p_pass == 1;
-
- ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
- render_fb = shadow_map->fb;
- render_texture = shadow_map->depth;
- }
-
- } else if (storage->light_get_type(light_instance->light) == VS::LIGHT_SPOT) {
-
- light_projection = light_instance->shadow_transform[0].camera;
- light_transform = light_instance->shadow_transform[0].transform;
-
- ShadowMap *shadow_map = _get_shadow_map(atlas_rect.size);
- render_fb = shadow_map->fb;
- render_texture = shadow_map->depth;
- }
- }
-
- if (render_cubemap) {
- //rendering to cubemap
- _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, 0, 0, false, false);
- if (finalize_cubemap) {
- //reblit
- atlas_rect.size.height /= 2;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), bias, false);
- atlas_rect.position.y += atlas_rect.size.height;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect, light_projection.get_z_near(), light_projection.get_z_far(), bias, true);
- }
- } else {
- //render shadow
-
- _render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip);
-
- //copy to atlas
- storage->get_effects()->copy_to_rect(render_texture, atlas_fb, atlas_rect, true);
-
- //does not work from depth to color
- //RD::get_singleton()->texture_copy(render_texture, atlas_texture, Vector3(0, 0, 0), Vector3(atlas_rect.position.x, atlas_rect.position.y, 0), Vector3(atlas_rect.size.x, atlas_rect.size.y, 1), 0, 0, 0, 0, true);
- }
-}
-
-void RasterizerSceneRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) {
-
- _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_cull_result, p_cull_count, p_framebuffer, p_region);
-}
-
-bool RasterizerSceneRD::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);
- render_buffers_owner.free(p_rid);
- } else if (environment_owner.owns(p_rid)) {
- //not much to delete, just free it
- environment_owner.free(p_rid);
- } else if (camera_effects_owner.owns(p_rid)) {
- //not much to delete, just free it
- camera_effects_owner.free(p_rid);
- } else if (reflection_atlas_owner.owns(p_rid)) {
- reflection_atlas_set_size(p_rid, 0, 0);
- reflection_atlas_owner.free(p_rid);
- } else if (reflection_probe_instance_owner.owns(p_rid)) {
- //not much to delete, just free it
- //ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid);
- reflection_probe_release_atlas_index(p_rid);
- reflection_probe_instance_owner.free(p_rid);
- } else if (gi_probe_instance_owner.owns(p_rid)) {
- GIProbeInstance *gi_probe = 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);
- }
- if (gi_probe->anisotropy[0].is_valid()) {
- RD::get_singleton()->free(gi_probe->anisotropy[0]);
- RD::get_singleton()->free(gi_probe->anisotropy[1]);
- }
-
- 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_slots.write[gi_probe->slot] = RID();
-
- 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);
- sky_owner.free(p_rid);
- } else if (light_instance_owner.owns(p_rid)) {
-
- LightInstance *light_instance = light_instance_owner.getornull(p_rid);
-
- //remove from shadow atlases..
- for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get());
- ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid));
- uint32_t key = shadow_atlas->shadow_owners[p_rid];
- uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
- shadow_atlas->shadow_owners.erase(p_rid);
- }
-
- light_instance_owner.free(p_rid);
-
- } else if (shadow_atlas_owner.owns(p_rid)) {
-
- shadow_atlas_set_size(p_rid, 0);
- shadow_atlas_owner.free(p_rid);
-
- } else {
- return false;
- }
-
- return true;
-}
-
-void RasterizerSceneRD::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {
- debug_draw = p_debug_draw;
-}
-
-void RasterizerSceneRD::update() {
- _update_dirty_skys();
-}
-
-void RasterizerSceneRD::set_time(double p_time, double p_step) {
- time_step = p_step;
-}
-
-void RasterizerSceneRD::screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) {
- screen_space_roughness_limiter = p_enable;
- screen_space_roughness_limiter_curve = p_curve;
-}
-
-bool RasterizerSceneRD::screen_space_roughness_limiter_is_active() const {
- return screen_space_roughness_limiter;
-}
-
-float RasterizerSceneRD::screen_space_roughness_limiter_get_curve() const {
- return screen_space_roughness_limiter_curve;
-}
-
-RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
- storage = p_storage;
-
- 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");
- // sky_use_cubemap_array = false;
-
- uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
-
- {
-
- //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_use_anisotropy = GLOBAL_GET("rendering/quality/gi_probes/anisotropic");
- gi_probe_quality = GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/quality/gi_probes/quality")), 0, 2));
-
- if (textures_per_stage <= 16) {
- gi_probe_slots.resize(2); //thats all you can get
- gi_probe_use_anisotropy = false;
- } else if (textures_per_stage <= 31) {
- gi_probe_slots.resize(4); //thats all you can get, iOS
- gi_probe_use_anisotropy = false;
- } else if (textures_per_stage <= 128) {
- gi_probe_slots.resize(32); //old intel
- gi_probe_use_anisotropy = false;
- } else if (textures_per_stage <= 256) {
- gi_probe_slots.resize(64); //old intel too
- gi_probe_use_anisotropy = false;
- } else {
- if (gi_probe_use_anisotropy) {
- gi_probe_slots.resize(1024 / 3); //needs 3 textures
- } else {
- gi_probe_slots.resize(1024); //modern intel, nvidia, 8192 or greater
- }
- }
-
- String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n";
- if (gi_probe_use_anisotropy) {
- defines += "\n#define MODE_ANISOTROPIC\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;
- if (gi_probe_use_anisotropy) {
- defines += "\n#define USE_ANISOTROPY\n";
- }
- 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);
- }
- }
-
- camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_shape"))));
- camera_effects_set_dof_blur_quality(VS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/filters/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/quality/filters/depth_of_field_use_jitter"));
- environment_set_ssao_quality(VS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"));
- screen_space_roughness_limiter = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter");
- screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve");
-}
-
-RasterizerSceneRD::~RasterizerSceneRD() {
- for (Map<Vector2i, ShadowMap>::Element *E = shadow_maps.front(); E; E = E->next()) {
- RD::get_singleton()->free(E->get().depth);
- }
- for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) {
- RD::get_singleton()->free(E->get().cubemap);
- }
-
- RD::get_singleton()->free(gi_probe_lights_uniform);
- giprobe_debug_shader.version_free(giprobe_debug_shader_version);
- giprobe_shader.version_free(giprobe_lighting_shader_version);
- memdelete_arr(gi_probe_lights);
-}
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
deleted file mode 100644
index 0fa853f2df..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
+++ /dev/null
@@ -1,964 +0,0 @@
-/*************************************************************************/
-/* rasterizer_scene_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_SCENE_RD_H
-#define RASTERIZER_SCENE_RD_H
-
-#include "core/rid_owner.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual/rasterizer_rd/rasterizer_storage_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/giprobe.glsl.gen.h"
-#include "servers/visual/rasterizer_rd/shaders/giprobe_debug.glsl.gen.h"
-#include "servers/visual/rendering_device.h"
-
-class RasterizerSceneRD : public RasterizerScene {
-public:
- enum GIProbeQuality {
- GIPROBE_QUALITY_ULTRA_LOW,
- GIPROBE_QUALITY_MEDIUM,
- GIPROBE_QUALITY_HIGH,
- };
-
-protected:
- struct RenderBufferData {
-
- virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, VS::ViewportMSAA p_msaa) = 0;
- virtual ~RenderBufferData() {}
- };
- virtual RenderBufferData *_create_render_buffer_data() = 0;
-
- virtual void _render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, 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) = 0;
- virtual void _render_shadow(RID p_framebuffer, InstanceBase **p_cull_result, int p_cull_count, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool use_dp_flip) = 0;
- virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region) = 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);
-
- 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_roughness_texture(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);
-
-private:
- VS::ViewportDebugDraw debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED;
- double time_step = 0;
-
- int roughness_layers;
-
- RasterizerStorageRD *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;
-
- 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_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality);
- void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer);
- void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality);
-
- /* SKY */
- struct Sky {
- RID radiance;
- RID uniform_set;
- int radiance_size = 128;
- VS::SkyMode mode = VS::SKY_MODE_QUALITY;
- RID panorama;
- ReflectionData reflection;
- bool dirty = false;
- Sky *dirty_list = nullptr;
- };
-
- Sky *dirty_sky_list = nullptr;
-
- void _sky_invalidate(Sky *p_sky);
- void _update_dirty_skys();
-
- uint32_t sky_ggx_samples_quality;
- bool sky_use_cubemap_array;
-
- mutable RID_Owner<Sky> sky_owner;
-
- /* REFLECTION ATLAS */
-
- struct ReflectionAtlas {
-
- int count = 0;
- int size = 0;
-
- RID reflection;
- RID depth_buffer;
- RID depth_fb;
-
- struct Reflection {
- RID owner;
- ReflectionData data;
- RID fbs[6];
- };
-
- Vector<Reflection> reflections;
- };
-
- RID_Owner<ReflectionAtlas> reflection_atlas_owner;
-
- /* REFLECTION PROBE INSTANCE */
-
- struct ReflectionProbeInstance {
-
- RID probe;
- int atlas_index = -1;
- RID atlas;
-
- bool dirty = true;
- bool rendering = false;
- int processing_layer = 1;
- int processing_side = 0;
-
- uint32_t render_step = 0;
- uint64_t last_pass = 0;
- uint32_t render_index = 0;
-
- Transform transform;
- };
-
- mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
-
- /* GIPROBE INSTANCE */
-
- struct GIProbeLight {
-
- uint32_t type;
- float energy;
- float radius;
- float attenuation;
-
- float color[3];
- float spot_angle_radians;
-
- float position[3];
- float 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 anisotropy[2]; //only if anisotropy is used
- RID anisotropy_r16[2]; //only if anisotropy is used
- RID write_buffer;
-
- struct Mipmap {
- RID texture;
- RID anisotropy[2]; //only if anisotropy is used
- 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;
-
- bool gi_probe_use_anisotropy = false;
- GIProbeQuality gi_probe_quality = GIPROBE_QUALITY_MEDIUM;
-
- Vector<RID> gi_probe_slots;
-
- 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;
-
- 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];
- RenderPipelineVertexFormatCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX];
- RID giprobe_debug_uniform_set;
-
- /* SHADOW ATLAS */
-
- struct ShadowAtlas {
-
- enum {
- QUADRANT_SHIFT = 27,
- SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1,
- SHADOW_INVALID = 0xFFFFFFFF
- };
-
- struct Quadrant {
-
- uint32_t subdivision;
-
- struct Shadow {
- RID owner;
- uint64_t version;
- uint64_t alloc_tick;
-
- Shadow() {
- version = 0;
- alloc_tick = 0;
- }
- };
-
- Vector<Shadow> shadows;
-
- Quadrant() {
- subdivision = 0; //not in use
- }
-
- } quadrants[4];
-
- int size_order[4] = { 0, 1, 2, 3 };
- uint32_t smallest_subdiv = 0;
-
- int size = 0;
-
- RID depth;
- RID fb; //for copying
-
- Map<RID, uint32_t> shadow_owners;
- };
-
- RID_Owner<ShadowAtlas> shadow_atlas_owner;
-
- bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
-
- /* DIRECTIONAL SHADOW */
-
- struct DirectionalShadow {
- RID depth;
- RID fb; //for copying
-
- int light_count = 0;
- int size = 0;
- int current_light = 0;
- } directional_shadow;
-
- /* SHADOW CUBEMAPS */
-
- struct ShadowCubemap {
-
- RID cubemap;
- RID side_fb[6];
- };
-
- Map<int, ShadowCubemap> shadow_cubemaps;
- ShadowCubemap *_get_shadow_cubemap(int p_size);
-
- struct ShadowMap {
- RID depth;
- RID fb;
- };
-
- Map<Vector2i, ShadowMap> shadow_maps;
- ShadowMap *_get_shadow_map(const Size2i &p_size);
-
- void _create_shadow_cubemaps();
-
- /* LIGHT INSTANCE */
-
- struct LightInstance {
-
- struct ShadowTransform {
-
- CameraMatrix camera;
- Transform transform;
- float farplane;
- float split;
- float bias_scale;
- Rect2 atlas_rect;
- };
-
- VS::LightType light_type;
-
- ShadowTransform shadow_transform[4];
-
- RID self;
- RID light;
- Transform transform;
-
- Vector3 light_vector;
- Vector3 spot_vector;
- float linear_att;
-
- uint64_t shadow_pass = 0;
- uint64_t last_scene_pass = 0;
- uint64_t last_scene_shadow_pass = 0;
- uint64_t last_pass = 0;
- uint32_t light_index = 0;
- uint32_t light_directional_index = 0;
-
- uint32_t current_shadow_atlas_key;
-
- Vector2 dp;
-
- Rect2 directional_rect;
-
- Set<RID> shadow_atlases; //shadow atlases where this light is registered
-
- LightInstance() {}
- };
-
- mutable RID_Owner<LightInstance> light_instance_owner;
-
- /* ENVIRONMENT */
-
- struct Environent {
-
- // BG
- VS::EnvironmentBG background = VS::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;
- VS::EnvironmentAmbientSource ambient_source = VS::ENV_AMBIENT_SOURCE_BG;
- Color ambient_light;
- float ambient_light_energy = 1.0;
- float ambient_sky_contribution = 1.0;
- VS::EnvironmentReflectionSource reflection_source = VS::ENV_REFLECTION_SOURCE_BG;
- Color ao_color;
-
- /// Tonemap
-
- VS::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;
-
- /// Glow
-
- bool glow_enabled = false;
- int glow_levels = (1 << 2) | (1 << 4);
- float glow_intensity = 0.8;
- float glow_strength = 1.0;
- float glow_bloom = 0.0;
- float glow_mix = 0.01;
- VS::EnvironmentGlowBlendMode glow_blend_mode = VS::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;
- bool glow_bicubic_upscale = false;
-
- /// SSAO
-
- bool ssao_enabled = false;
- float ssao_radius = 1;
- float ssao_intensity = 1;
- float ssao_bias = 0.01;
- float ssao_direct_light_affect = 0.0;
- float ssao_ao_channel_affect = 0.0;
- float ssao_blur_edge_sharpness = 4.0;
- VS::EnvironmentSSAOBlur ssao_blur = VS::ENV_SSAO_BLUR_3x3;
- };
-
- VS::EnvironmentSSAOQuality ssao_quality = VS::ENV_SSAO_QUALITY_MEDIUM;
- bool ssao_half_size = false;
-
- static uint64_t auto_exposure_counter;
-
- mutable RID_Owner<Environent> environment_owner;
-
- /* CAMERA EFFECTS */
-
- struct CameraEffects {
-
- bool dof_blur_far_enabled = false;
- float dof_blur_far_distance = 10;
- float dof_blur_far_transition = 5;
-
- bool dof_blur_near_enabled = false;
- float dof_blur_near_distance = 2;
- float dof_blur_near_transition = 1;
-
- float dof_blur_amount = 0.1;
-
- bool override_exposure_enabled = false;
- float override_exposure = 1;
- };
-
- VS::DOFBlurQuality dof_blur_quality = VS::DOF_BLUR_QUALITY_MEDIUM;
- VS::DOFBokehShape dof_blur_bokeh_shape = VS::DOF_BOKEH_HEXAGON;
- bool dof_blur_use_jitter = false;
-
- mutable RID_Owner<CameraEffects> camera_effects_owner;
-
- /* RENDER BUFFERS */
-
- struct RenderBuffers {
-
- RenderBufferData *data = nullptr;
- int width = 0, height = 0;
- VS::ViewportMSAA msaa = VS::VIEWPORT_MSAA_DISABLED;
- RID render_target;
-
- uint64_t auto_exposure_version = 1;
-
- RID texture; //main texture for rendering to, must be filled after done rendering
- RID depth_texture; //main depth texture
-
- //built-in textures used for ping pong image processing and blurring
- struct Blur {
- RID texture;
-
- struct Mipmap {
- RID texture;
- RID framebuffer;
- int width;
- int height;
- };
-
- Vector<Mipmap> mipmaps;
- };
-
- Blur blur[2]; //the second one starts from the first mipmap
-
- struct Luminance {
-
- Vector<RID> reduce;
- RID current;
- } luminance;
-
- struct SSAO {
- RID depth;
- Vector<RID> depth_slices;
- RID ao[2];
- RID ao_full; //when using half-size
- } ssao;
- };
-
- bool screen_space_roughness_limiter = false;
- float screen_space_roughness_limiter_curve = 1.0;
-
- mutable RID_Owner<RenderBuffers> render_buffers_owner;
-
- void _free_render_buffer_data(RenderBuffers *rb);
- 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_post_process_and_tonemap(RID p_render_buffers, RID p_environment, RID p_camera_effects, const CameraMatrix &p_projection);
-
- uint64_t scene_pass = 0;
- uint64_t shadow_atlas_realloc_tolerance_msec = 500;
-
-public:
- /* SHADOW ATLAS API */
-
- RID shadow_atlas_create();
- void shadow_atlas_set_size(RID p_atlas, int p_size);
- void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision);
- bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version);
- _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
- ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND_V(!atlas, false);
- return atlas->shadow_owners.has(p_light_intance);
- }
-
- _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
- ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->depth;
- }
-
- _FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) {
- ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas);
- ERR_FAIL_COND_V(!atlas, Size2i());
- return Size2(atlas->size, atlas->size);
- }
-
- void directional_shadow_atlas_set_size(int p_size);
- int get_directional_light_shadow_size(RID p_light_intance);
- void set_directional_shadow_count(int p_count);
-
- _FORCE_INLINE_ RID directional_shadow_get_texture() {
- return directional_shadow.depth;
- }
-
- _FORCE_INLINE_ Size2i directional_shadow_get_size() {
- return Size2i(directional_shadow.size, directional_shadow.size);
- }
-
- /* SKY API */
-
- RID sky_create();
- void sky_set_radiance_size(RID p_sky, int p_radiance_size);
- void sky_set_mode(RID p_sky, VS::SkyMode p_mode);
- void sky_set_texture(RID p_sky, RID p_panorama);
-
- RID sky_get_panorama_texture_rd(RID p_sky) const;
- 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;
-
- /* ENVIRONMENT API */
-
- RID environment_create();
-
- void environment_set_background(RID p_env, VS::EnvironmentBG p_bg);
- void environment_set_sky(RID p_env, RID p_sky);
- void environment_set_sky_custom_fov(RID p_env, float p_scale);
- void environment_set_sky_orientation(RID p_env, const Basis &p_orientation);
- void environment_set_bg_color(RID p_env, const Color &p_color);
- void environment_set_bg_energy(RID p_env, float p_energy);
- void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
- void environment_set_ambient_light(RID p_env, const Color &p_color, VS::EnvironmentAmbientSource p_ambient = VS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, VS::EnvironmentReflectionSource p_reflection_source = VS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color());
-
- VS::EnvironmentBG environment_get_background(RID p_env) const;
- RID environment_get_sky(RID p_env) const;
- float environment_get_sky_custom_fov(RID p_env) const;
- Basis environment_get_sky_orientation(RID p_env) const;
- Color environment_get_bg_color(RID p_env) const;
- float environment_get_bg_energy(RID p_env) const;
- int environment_get_canvas_max_layer(RID p_env) const;
- Color environment_get_ambient_light_color(RID p_env) const;
- VS::EnvironmentAmbientSource environment_get_ambient_light_ambient_source(RID p_env) const;
- float environment_get_ambient_light_ambient_energy(RID p_env) const;
- float environment_get_ambient_sky_contribution(RID p_env) const;
- VS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const;
- Color environment_get_ao_color(RID p_env) const;
-
- bool is_environment(RID p_env) const;
-
- void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale);
-
- void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
-
- void 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, bool p_roughness) {}
- void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
- void environment_set_ssao_quality(VS::EnvironmentSSAOQuality p_quality, bool p_half_size);
- bool environment_is_ssao_enabled(RID p_env) const;
- float environment_get_ssao_ao_affect(RID p_env) const;
- float environment_get_ssao_light_affect(RID p_env) const;
- bool environment_is_ssr_enabled(RID p_env) const;
-
- void environment_set_tonemap(RID p_env, VS::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 environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {}
-
- void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {}
- void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {}
- void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {}
-
- virtual RID camera_effects_create();
-
- virtual void camera_effects_set_dof_blur_quality(VS::DOFBlurQuality p_quality, bool p_use_jitter);
- virtual void camera_effects_set_dof_blur_bokeh_shape(VS::DOFBokehShape p_shape);
-
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount);
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure);
-
- RID light_instance_create(RID p_light);
- void light_instance_set_transform(RID p_light_instance, const Transform &p_transform);
- void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0);
- void light_instance_mark_visible(RID p_light_instance);
-
- _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->light;
- }
-
- _FORCE_INLINE_ Transform light_instance_get_base_transform(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->transform;
- }
-
- _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas) {
-
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- uint32_t key = shadow_atlas->shadow_owners[li->self];
-
- uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2());
-
- uint32_t atlas_size = shadow_atlas->size;
- uint32_t quadrant_size = atlas_size >> 1;
-
- uint32_t x = (quadrant & 1) * quadrant_size;
- uint32_t y = (quadrant >> 1) * quadrant_size;
-
- uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
- x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
- y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
-
- uint32_t width = shadow_size;
- uint32_t height = shadow_size;
-
- return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size));
- }
-
- _FORCE_INLINE_ CameraMatrix light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
-
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->shadow_transform[p_index].camera;
- }
-
- _FORCE_INLINE_ Transform light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
-
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->shadow_transform[p_index].transform;
- }
-
- _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
-
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->shadow_transform[p_index].atlas_rect;
- }
-
- _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
-
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->shadow_transform[p_index].split;
- }
-
- _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- li->last_pass = p_pass;
- }
-
- _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->last_pass;
- }
-
- _FORCE_INLINE_ void light_instance_set_index(RID p_light_instance, uint32_t p_index) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- li->light_index = p_index;
- }
-
- _FORCE_INLINE_ uint32_t light_instance_get_index(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->light_index;
- }
-
- _FORCE_INLINE_ VS::LightType light_instance_get_type(RID p_light_instance) {
- LightInstance *li = light_instance_owner.getornull(p_light_instance);
- return li->light_type;
- }
-
- virtual RID reflection_atlas_create();
- virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count);
- _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
- ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->reflection;
- }
-
- virtual RID reflection_probe_instance_create(RID p_probe);
- virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform);
- virtual void reflection_probe_release_atlas_index(RID p_instance);
- virtual bool reflection_probe_instance_needs_redraw(RID p_instance);
- virtual bool reflection_probe_instance_has_reflection(RID p_instance);
- virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas);
- virtual bool reflection_probe_instance_postprocess_step(RID p_instance);
-
- uint32_t reflection_probe_instance_get_resolution(RID p_instance);
- RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
- RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
-
- _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
-
- return rpi->probe;
- }
-
- _FORCE_INLINE_ void reflection_probe_instance_set_render_index(RID p_instance, uint32_t p_render_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!rpi);
- rpi->render_index = p_render_index;
- }
-
- _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
-
- return rpi->render_index;
- }
-
- _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!rpi);
- rpi->last_pass = p_render_pass;
- }
-
- _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
-
- return rpi->last_pass;
- }
-
- _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, Transform());
-
- return rpi->transform;
- }
-
- _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
- ERR_FAIL_COND_V(!rpi, -1);
-
- return rpi->atlas_index;
- }
-
- 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, int p_dynamic_object_count, InstanceBase **p_dynamic_objects);
-
- _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_ RID gi_probe_instance_get_aniso_texture(RID p_probe, int p_index) {
- GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_probe);
- return gi_probe->anisotropy[p_index];
- }
-
- _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;
- }
-
- _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;
- }
-
- const Vector<RID> &gi_probe_get_slots() const;
- _FORCE_INLINE_ bool gi_probe_is_anisotropic() const {
- return gi_probe_use_anisotropy;
- }
- GIProbeQuality gi_probe_get_quality() const;
-
- RID render_buffers_create();
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, VS::ViewportMSAA p_msaa);
-
- RID render_buffers_get_ao_texture(RID p_render_buffers);
- RID render_buffers_get_back_buffer_texture(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, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_camera_effects, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
-
- void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
-
- void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID p_framebuffer, const Rect2i &p_region);
-
- virtual void set_scene_pass(uint64_t p_pass) { scene_pass = p_pass; }
- _FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; }
-
- virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve);
- virtual bool screen_space_roughness_limiter_is_active() const;
- virtual float screen_space_roughness_limiter_get_curve() const;
-
- int get_roughness_layers() const;
- bool is_using_radiance_cubemap_array() const;
-
- virtual bool free(RID p_rid);
-
- virtual void update();
-
- virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw);
- _FORCE_INLINE_ VS::ViewportDebugDraw get_debug_draw_mode() const { return debug_draw; }
-
- virtual void set_time(double p_time, double p_step);
-
- RasterizerSceneRD(RasterizerStorageRD *p_storage);
- ~RasterizerSceneRD();
-};
-
-#endif // RASTERIZER_SCENE_RD_H
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
deleted file mode 100644
index 850acbf554..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
+++ /dev/null
@@ -1,4820 +0,0 @@
-/*************************************************************************/
-/* rasterizer_storage_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rasterizer_storage_rd.h"
-#include "core/engine.h"
-#include "core/project_settings.h"
-#include "servers/visual/shader_language.h"
-
-Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
-
- Ref<Image> image = p_image->duplicate();
-
- switch (p_image->get_format()) {
- case Image::FORMAT_L8: {
- r_format.format = RD::DATA_FORMAT_R8_UNORM;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break; //luminance
- case Image::FORMAT_LA8: {
- r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_G;
- } break; //luminance-alpha
- case Image::FORMAT_R8: {
- r_format.format = RD::DATA_FORMAT_R8_UNORM;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_RG8: {
- r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_RGB8: {
- //this format is not mandatory for specification, check if supported first
- if (false && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT) && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_SRGB, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_R8G8B8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8_SRGB;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break;
- case Image::FORMAT_RGBA8: {
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_RGBA4444: {
- r_format.format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B; //needs swizzle
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_RGB565: {
- r_format.format = RD::DATA_FORMAT_B5G6R5_UNORM_PACK16;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_RF: {
- r_format.format = RD::DATA_FORMAT_R32_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break; //float
- case Image::FORMAT_RGF: {
- r_format.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_RGBF: {
- //this format is not mandatory for specification, check if supported first
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- image->convert(Image::FORMAT_RGBAF);
- }
-
- r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_RGBAF: {
- r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
-
- } break;
- case Image::FORMAT_RH: {
- r_format.format = RD::DATA_FORMAT_R16_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break; //half float
- case Image::FORMAT_RGH: {
- r_format.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break;
- case Image::FORMAT_RGBH: {
- //this format is not mandatory for specification, check if supported first
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_R16G16B16_SFLOAT;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- image->convert(Image::FORMAT_RGBAH);
- }
-
- r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_RGBAH: {
- r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
-
- } break;
- case Image::FORMAT_RGBE9995: {
- r_format.format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
-#ifndef _MSC_VER
-#warning TODO need to make a function in Image to swap bits for this
-#endif
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_IDENTITY;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_IDENTITY;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_IDENTITY;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_IDENTITY;
- } break;
- case Image::FORMAT_DXT1: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_BC1_RGB_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break; //s3tc bc1
- case Image::FORMAT_DXT3: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC2_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC2_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_BC2_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
-
- } break; //bc2
- case Image::FORMAT_DXT5: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC3_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break; //bc3
- case Image::FORMAT_RGTC_R: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC4_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC4_UNORM_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8_UNORM;
- image->decompress();
- image->convert(Image::FORMAT_R8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break;
- case Image::FORMAT_RGTC_RG: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC5_UNORM_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
- image->decompress();
- image->convert(Image::FORMAT_RG8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break;
- case Image::FORMAT_BPTC_RGBA: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC7_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_BC7_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
-
- } break; //btpc bc7
- case Image::FORMAT_BPTC_RGBF: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- image->decompress();
- image->convert(Image::FORMAT_RGBAH);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break; //float bc6h
- case Image::FORMAT_BPTC_RGBFU: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- image->decompress();
- image->convert(Image::FORMAT_RGBAH);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break; //unsigned float bc6hu
- case Image::FORMAT_PVRTC2: {
- //this is not properly supported by MoltekVK it seems, so best to use ETC2
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
- r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break; //pvrtc
- case Image::FORMAT_PVRTC2A: {
- //this is not properly supported by MoltekVK it seems, so best to use ETC2
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
- r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_PVRTC4: {
- //this is not properly supported by MoltekVK it seems, so best to use ETC2
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
- r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_PVRTC4A: {
- //this is not properly supported by MoltekVK it seems, so best to use ETC2
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
- r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_ETC2_R11: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8_UNORM;
- image->decompress();
- image->convert(Image::FORMAT_R8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break; //etc2
- case Image::FORMAT_ETC2_R11S: {
-
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8_SNORM;
- image->decompress();
- image->convert(Image::FORMAT_R8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break; //signed: {} break; NOT srgb.
- case Image::FORMAT_ETC2_RG11: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8_UNORM;
- image->decompress();
- image->convert(Image::FORMAT_RG8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_ETC2_RG11S: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8_SNORM;
- image->decompress();
- image->convert(Image::FORMAT_RG8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_ETC:
- case Image::FORMAT_ETC2_RGB8: {
- //ETC2 is backwards compatible with ETC1, and all modern platforms support it
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-
- } break;
- case Image::FORMAT_ETC2_RGBA8: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_ETC2_RGB8A1: {
-
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
- } break;
- case Image::FORMAT_ETC2_RA_AS_RG: {
-
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
- case Image::FORMAT_DXT5_RA_AS_RG: {
- if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC3_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) {
- r_format.format = RD::DATA_FORMAT_BC3_UNORM_BLOCK;
- r_format.format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK;
- } else {
- //not supported, reconvert
- r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- image->decompress();
- image->convert(Image::FORMAT_RGBA8);
- }
- r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
- r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
- r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
- r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- } break;
-
- default: {
- }
- }
-
- return image;
-}
-
-RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
- ERR_FAIL_COND_V(p_image.is_null(), RID());
- ERR_FAIL_COND_V(p_image->empty(), RID());
-
- TextureToRDFormat ret_format;
- Ref<Image> image = _validate_texture_format(p_image, ret_format);
-
- Texture texture;
-
- texture.type = Texture::TYPE_2D;
-
- texture.width = p_image->get_width();
- texture.height = p_image->get_height();
- texture.layers = 1;
- texture.mipmaps = p_image->get_mipmap_count() + 1;
- texture.depth = 1;
- texture.format = p_image->get_format();
- texture.validated_format = image->get_format();
-
- texture.rd_type = RD::TEXTURE_TYPE_2D;
- texture.rd_format = ret_format.format;
- texture.rd_format_srgb = ret_format.format_srgb;
-
- RD::TextureFormat rd_format;
- RD::TextureView rd_view;
- { //attempt register
- rd_format.format = texture.rd_format;
- rd_format.width = texture.width;
- rd_format.height = texture.height;
- rd_format.depth = 1;
- rd_format.array_layers = 1;
- rd_format.mipmaps = texture.mipmaps;
- rd_format.type = texture.rd_type;
- rd_format.samples = RD::TEXTURE_SAMPLES_1;
- rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) {
- rd_format.shareable_formats.push_back(texture.rd_format);
- rd_format.shareable_formats.push_back(texture.rd_format_srgb);
- }
- }
- {
- rd_view.swizzle_r = ret_format.swizzle_r;
- rd_view.swizzle_g = ret_format.swizzle_g;
- rd_view.swizzle_b = ret_format.swizzle_b;
- rd_view.swizzle_a = ret_format.swizzle_a;
- }
- Vector<uint8_t> data = image->get_data(); //use image data
- 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());
- 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());
- }
- }
-
- //used for 2D, overridable
- texture.width_2d = texture.width;
- texture.height_2d = texture.height;
- texture.is_render_target = false;
- texture.rd_view = rd_view;
- texture.is_proxy = false;
-
- return texture_owner.make_rid(texture);
-}
-
-RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type) {
-
- return RID();
-}
-RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image> > &p_slices) {
-
- return RID();
-}
-
-RID RasterizerStorageRD::texture_proxy_create(RID p_base) {
- Texture *tex = texture_owner.getornull(p_base);
- ERR_FAIL_COND_V(!tex, RID());
- Texture proxy_tex = *tex;
-
- proxy_tex.rd_view.format_override = tex->rd_format;
- proxy_tex.rd_texture = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture);
- if (proxy_tex.rd_texture_srgb.is_valid()) {
- proxy_tex.rd_view.format_override = tex->rd_format_srgb;
- proxy_tex.rd_texture_srgb = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture);
- }
- proxy_tex.proxy_to = p_base;
- proxy_tex.is_render_target = false;
- proxy_tex.is_proxy = true;
- proxy_tex.proxies.clear();
-
- RID rid = texture_owner.make_rid(proxy_tex);
-
- tex->proxies.push_back(rid);
-
- return rid;
-}
-
-void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) {
-
- ERR_FAIL_COND(p_image.is_null() || p_image->empty());
-
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(tex->is_render_target);
- ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height);
- ERR_FAIL_COND(p_image->get_format() != tex->format);
-
- if (tex->type == Texture::TYPE_LAYERED) {
- ERR_FAIL_INDEX(p_layer, tex->layers);
- }
-
-#ifdef TOOLS_ENABLED
- tex->image_cache_2d.unref();
-#endif
- TextureToRDFormat f;
- Ref<Image> validated = _validate_texture_format(p_image, f);
-
- RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data(), !p_immediate);
-}
-
-void RasterizerStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- _texture_2d_update(p_texture, p_image, p_layer, true);
-}
-void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- _texture_2d_update(p_texture, p_image, p_layer, false);
-}
-void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) {
-}
-
-void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) {
-
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(!tex->is_proxy);
- Texture *proxy_to = texture_owner.getornull(p_proxy_to);
- ERR_FAIL_COND(!proxy_to);
- ERR_FAIL_COND(proxy_to->is_proxy);
-
- if (tex->proxy_to.is_valid()) {
- //unlink proxy
- if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
- RD::get_singleton()->free(tex->rd_texture);
- tex->rd_texture = RID();
- }
- if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
- RD::get_singleton()->free(tex->rd_texture_srgb);
- tex->rd_texture_srgb = RID();
- }
- Texture *prev_tex = texture_owner.getornull(tex->proxy_to);
- ERR_FAIL_COND(!prev_tex);
- prev_tex->proxies.erase(p_texture);
- }
-
- *tex = *proxy_to;
-
- tex->proxy_to = p_proxy_to;
- tex->is_render_target = false;
- tex->is_proxy = true;
- tex->proxies.clear();
- proxy_to->proxies.push_back(p_texture);
-
- tex->rd_view.format_override = tex->rd_format;
- tex->rd_texture = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture);
- if (tex->rd_texture_srgb.is_valid()) {
- tex->rd_view.format_override = tex->rd_format_srgb;
- tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture);
- }
-}
-
-//these two APIs can be used together or in combination with the others.
-RID RasterizerStorageRD::texture_2d_placeholder_create() {
-
- //this could be better optimized to reuse an existing image , done this way
- //for now to get it working
- Ref<Image> image;
- image.instance();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- image->set_pixel(i, j, Color(1, 0, 1, 1));
- }
- }
-
- return texture_2d_create(image);
-}
-RID RasterizerStorageRD::texture_2d_layered_placeholder_create() {
-
- return RID();
-}
-RID RasterizerStorageRD::texture_3d_placeholder_create() {
-
- return RID();
-}
-
-Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const {
-
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND_V(!tex, Ref<Image>());
-
-#ifdef TOOLS_ENABLED
- if (tex->image_cache_2d.is_valid()) {
- return tex->image_cache_2d;
- }
-#endif
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
- ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image;
- image.instance();
- image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
- ERR_FAIL_COND_V(image->empty(), Ref<Image>());
- if (tex->format != tex->validated_format) {
- image->convert(tex->format);
- }
-
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- tex->image_cache_2d = image;
- }
-#endif
-
- return image;
-}
-Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const {
-
- return Ref<Image>();
-}
-Ref<Image> RasterizerStorageRD::texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const {
-
- return Ref<Image>();
-}
-
-void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
-
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy
- Texture *by_tex = texture_owner.getornull(p_by_texture);
- ERR_FAIL_COND(!by_tex);
- ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy
-
- if (tex == by_tex) {
- return;
- }
-
- if (tex->rd_texture_srgb.is_valid()) {
- RD::get_singleton()->free(tex->rd_texture_srgb);
- }
- RD::get_singleton()->free(tex->rd_texture);
-
- Vector<RID> proxies_to_update = tex->proxies;
- Vector<RID> proxies_to_redirect = by_tex->proxies;
-
- *tex = *by_tex;
-
- tex->proxies = proxies_to_update; //restore proxies, so they can be updated
-
- for (int i = 0; i < proxies_to_update.size(); i++) {
- texture_proxy_update(proxies_to_update[i], p_texture);
- }
- for (int i = 0; i < proxies_to_redirect.size(); i++) {
- texture_proxy_update(proxies_to_redirect[i], p_texture);
- }
- //delete last, so proxies can be updated
- texture_owner.free(p_by_texture);
-}
-void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) {
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(tex->type != Texture::TYPE_2D);
- tex->width_2d = p_width;
- tex->height_2d = p_height;
-}
-
-void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) {
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- tex->path = p_path;
-}
-String RasterizerStorageRD::texture_get_path(RID p_texture) const {
- return String();
-}
-
-void RasterizerStorageRD::texture_set_detect_3d_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- tex->detect_3d_callback_ud = p_userdata;
- tex->detect_3d_callback = p_callback;
-}
-void RasterizerStorageRD::texture_set_detect_normal_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) {
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- tex->detect_normal_callback_ud = p_userdata;
- tex->detect_normal_callback = p_callback;
-}
-void RasterizerStorageRD::texture_set_detect_roughness_callback(RID p_texture, VS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {
- Texture *tex = texture_owner.getornull(p_texture);
- ERR_FAIL_COND(!tex);
- tex->detect_roughness_callback_ud = p_userdata;
- tex->detect_roughness_callback = p_callback;
-}
-void RasterizerStorageRD::texture_debug_usage(List<VS::TextureInfo> *r_info) {
-}
-
-void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) {
-}
-void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
-}
-
-Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {
- return texture_2d_get_size(p_proxy);
-}
-
-/* SHADER API */
-
-RID RasterizerStorageRD::shader_create() {
-
- Shader shader;
- shader.data = NULL;
- shader.type = SHADER_TYPE_MAX;
-
- return shader_owner.make_rid(shader);
-}
-
-void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) {
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND(!shader);
-
- shader->code = p_code;
- String mode_string = ShaderLanguage::get_shader_type(p_code);
-
- ShaderType new_type;
- if (mode_string == "canvas_item")
- new_type = SHADER_TYPE_2D;
- else if (mode_string == "particles")
- new_type = SHADER_TYPE_PARTICLES;
- else if (mode_string == "spatial")
- new_type = SHADER_TYPE_3D;
- else
- new_type = SHADER_TYPE_MAX;
-
- if (new_type != shader->type) {
- if (shader->data) {
- memdelete(shader->data);
- shader->data = NULL;
- }
-
- for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
-
- Material *material = E->get();
- material->shader_type = new_type;
- if (material->data) {
- memdelete(material->data);
- material->data = NULL;
- }
- }
-
- shader->type = new_type;
-
- if (new_type < SHADER_TYPE_MAX && shader_data_request_func[new_type]) {
- shader->data = shader_data_request_func[new_type]();
- } else {
- shader->type = SHADER_TYPE_MAX; //invalid
- }
-
- for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
- Material *material = E->get();
- if (shader->data) {
- material->data = material_data_request_func[new_type](shader->data);
- material->data->set_next_pass(material->next_pass);
- material->data->set_render_priority(material->priority);
- }
- material->shader_type = new_type;
- }
- }
-
- if (shader->data) {
- shader->data->set_code(p_code);
- }
-
- for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
- Material *material = E->get();
- material->instance_dependency.instance_notify_changed(false, true);
- _material_queue_update(material, true, true);
- }
-}
-
-String RasterizerStorageRD::shader_get_code(RID p_shader) const {
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND_V(!shader, String());
- return shader->code;
-}
-void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
-
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND(!shader);
- if (shader->data) {
- return shader->data->get_param_list(p_param_list);
- }
-}
-
-void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) {
-
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND(!shader);
-
- if (p_texture.is_valid() && texture_owner.owns(p_texture)) {
- shader->default_texture_parameter[p_name] = p_texture;
- } else {
- shader->default_texture_parameter.erase(p_name);
- }
-
- for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) {
- Material *material = E->get();
- _material_queue_update(material, false, true);
- }
-}
-
-RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const {
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
- if (shader->default_texture_parameter.has(p_name)) {
- return shader->default_texture_parameter[p_name];
- }
-
- return RID();
-}
-Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const {
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND_V(!shader, Variant());
- if (shader->data) {
- return shader->data->get_default_parameter(p_param);
- }
- return Variant();
-}
-void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) {
- ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
- shader_data_request_func[p_shader_type] = p_function;
-}
-
-/* COMMON MATERIAL API */
-
-RID RasterizerStorageRD::material_create() {
-
- Material material;
- material.data = NULL;
- material.shader = NULL;
- material.shader_type = SHADER_TYPE_MAX;
- material.update_next = NULL;
- material.update_requested = false;
- 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;
-}
-
-void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
- if (material->update_requested) {
- return;
- }
-
- material->update_next = material_update_list;
- material_update_list = material;
- material->update_requested = true;
- material->uniform_dirty = p_uniform;
- material->texture_dirty = p_texture;
-}
-
-void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) {
-
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND(!material);
-
- if (material->data) {
- memdelete(material->data);
- material->data = NULL;
- }
-
- if (material->shader) {
- material->shader->owners.erase(material);
- material->shader = NULL;
- material->shader_type = SHADER_TYPE_MAX;
- }
-
- if (p_shader.is_null()) {
- material->instance_dependency.instance_notify_changed(false, true);
- return;
- }
-
- Shader *shader = shader_owner.getornull(p_shader);
- ERR_FAIL_COND(!shader);
- material->shader = shader;
- material->shader_type = shader->type;
- shader->owners.insert(material);
-
- if (shader->type == SHADER_TYPE_MAX) {
- return;
- }
-
- ERR_FAIL_COND(shader->data == NULL);
-
- material->data = material_data_request_func[shader->type](shader->data);
- material->data->set_next_pass(material->next_pass);
- material->data->set_render_priority(material->priority);
- //updating happens later
- material->instance_dependency.instance_notify_changed(false, true);
- _material_queue_update(material, true, true);
-}
-
-void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
-
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND(!material);
-
- if (p_value.get_type() == Variant::NIL) {
- material->params.erase(p_param);
- } else {
- material->params[p_param] = p_value;
- }
-
- if (material->shader && material->shader->data) { //shader is valid
- bool is_texture = material->shader->data->is_param_texture(p_param);
- _material_queue_update(material, !is_texture, is_texture);
- } else {
- _material_queue_update(material, true, true);
- }
-}
-
-Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const {
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND_V(!material, Variant());
- if (material->params.has(p_param)) {
- return material->params[p_param];
- } else {
- return Variant();
- }
-}
-
-void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) {
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND(!material);
-
- if (material->next_pass == p_next_material) {
- return;
- }
-
- material->next_pass = p_next_material;
- if (material->data) {
- material->data->set_next_pass(p_next_material);
- }
-
- material->instance_dependency.instance_notify_changed(false, true);
-}
-void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) {
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND(!material);
- material->priority = priority;
- if (material->data) {
- material->data->set_render_priority(priority);
- }
-}
-
-bool RasterizerStorageRD::material_is_animated(RID p_material) {
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND_V(!material, false);
- if (material->shader && material->shader->data) {
- if (material->shader->data->is_animated()) {
- return true;
- } else if (material->next_pass.is_valid()) {
- return material_is_animated(material->next_pass);
- }
- }
- return false; //by default nothing is animated
-}
-bool RasterizerStorageRD::material_casts_shadows(RID p_material) {
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND_V(!material, true);
- if (material->shader && material->shader->data) {
- if (material->shader->data->casts_shadows()) {
- return true;
- } else if (material->next_pass.is_valid()) {
- return material_casts_shadows(material->next_pass);
- }
- }
- return true; //by default everything casts shadows
-}
-
-void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) {
- Material *material = material_owner.getornull(p_material);
- ERR_FAIL_COND(!material);
- p_instance->update_dependency(&material->instance_dependency);
- if (material->next_pass.is_valid()) {
- material_update_dependency(material->next_pass, p_instance);
- }
-}
-
-void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) {
- ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
- material_data_request_func[p_shader_type] = p_function;
-}
-
-_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) {
- switch (type) {
- case ShaderLanguage::TYPE_BOOL: {
-
- bool v = value;
-
- uint32_t *gui = (uint32_t *)data;
- *gui = v ? 1 : 0;
- } break;
- case ShaderLanguage::TYPE_BVEC2: {
-
- int v = value;
- uint32_t *gui = (uint32_t *)data;
- gui[0] = v & 1 ? 1 : 0;
- gui[1] = v & 2 ? 1 : 0;
-
- } break;
- case ShaderLanguage::TYPE_BVEC3: {
-
- int v = value;
- uint32_t *gui = (uint32_t *)data;
- gui[0] = (v & 1) ? 1 : 0;
- gui[1] = (v & 2) ? 1 : 0;
- gui[2] = (v & 4) ? 1 : 0;
-
- } break;
- case ShaderLanguage::TYPE_BVEC4: {
-
- int v = value;
- uint32_t *gui = (uint32_t *)data;
- gui[0] = (v & 1) ? 1 : 0;
- gui[1] = (v & 2) ? 1 : 0;
- gui[2] = (v & 4) ? 1 : 0;
- gui[3] = (v & 8) ? 1 : 0;
-
- } break;
- case ShaderLanguage::TYPE_INT: {
-
- int v = value;
- int32_t *gui = (int32_t *)data;
- gui[0] = v;
-
- } break;
- case ShaderLanguage::TYPE_IVEC2: {
-
- Vector<int> iv = value;
- int s = iv.size();
- int32_t *gui = (int32_t *)data;
-
- const int *r = iv.ptr();
-
- for (int i = 0; i < 2; i++) {
- if (i < s)
- gui[i] = r[i];
- else
- gui[i] = 0;
- }
-
- } break;
- case ShaderLanguage::TYPE_IVEC3: {
-
- Vector<int> iv = value;
- int s = iv.size();
- int32_t *gui = (int32_t *)data;
-
- const int *r = iv.ptr();
-
- for (int i = 0; i < 3; i++) {
- if (i < s)
- gui[i] = r[i];
- else
- gui[i] = 0;
- }
- } break;
- case ShaderLanguage::TYPE_IVEC4: {
-
- Vector<int> iv = value;
- int s = iv.size();
- int32_t *gui = (int32_t *)data;
-
- const int *r = iv.ptr();
-
- for (int i = 0; i < 4; i++) {
- if (i < s)
- gui[i] = r[i];
- else
- gui[i] = 0;
- }
- } break;
- case ShaderLanguage::TYPE_UINT: {
-
- int v = value;
- uint32_t *gui = (uint32_t *)data;
- gui[0] = v;
-
- } break;
- case ShaderLanguage::TYPE_UVEC2: {
-
- Vector<int> iv = value;
- int s = iv.size();
- uint32_t *gui = (uint32_t *)data;
-
- const int *r = iv.ptr();
-
- for (int i = 0; i < 2; i++) {
- if (i < s)
- gui[i] = r[i];
- else
- gui[i] = 0;
- }
- } break;
- case ShaderLanguage::TYPE_UVEC3: {
- Vector<int> iv = value;
- int s = iv.size();
- uint32_t *gui = (uint32_t *)data;
-
- const int *r = iv.ptr();
-
- for (int i = 0; i < 3; i++) {
- if (i < s)
- gui[i] = r[i];
- else
- gui[i] = 0;
- }
-
- } break;
- case ShaderLanguage::TYPE_UVEC4: {
- Vector<int> iv = value;
- int s = iv.size();
- uint32_t *gui = (uint32_t *)data;
-
- const int *r = iv.ptr();
-
- for (int i = 0; i < 4; i++) {
- if (i < s)
- gui[i] = r[i];
- else
- gui[i] = 0;
- }
- } break;
- case ShaderLanguage::TYPE_FLOAT: {
- float v = value;
- float *gui = (float *)data;
- gui[0] = v;
-
- } break;
- case ShaderLanguage::TYPE_VEC2: {
- Vector2 v = value;
- float *gui = (float *)data;
- gui[0] = v.x;
- gui[1] = v.y;
-
- } break;
- case ShaderLanguage::TYPE_VEC3: {
- Vector3 v = value;
- float *gui = (float *)data;
- gui[0] = v.x;
- gui[1] = v.y;
- gui[2] = v.z;
-
- } break;
- case ShaderLanguage::TYPE_VEC4: {
-
- float *gui = (float *)data;
-
- if (value.get_type() == Variant::COLOR) {
- Color v = value;
-
- if (p_linear_color) {
- v = v.to_linear();
- }
-
- gui[0] = v.r;
- gui[1] = v.g;
- gui[2] = v.b;
- gui[3] = v.a;
- } else if (value.get_type() == Variant::RECT2) {
- Rect2 v = value;
-
- gui[0] = v.position.x;
- gui[1] = v.position.y;
- gui[2] = v.size.x;
- gui[3] = v.size.y;
- } else if (value.get_type() == Variant::QUAT) {
- Quat v = value;
-
- gui[0] = v.x;
- gui[1] = v.y;
- gui[2] = v.z;
- gui[3] = v.w;
- } else {
- Plane v = value;
-
- gui[0] = v.normal.x;
- gui[1] = v.normal.y;
- gui[2] = v.normal.z;
- gui[3] = v.d;
- }
- } break;
- case ShaderLanguage::TYPE_MAT2: {
- Transform2D v = value;
- float *gui = (float *)data;
-
- //in std140 members of mat2 are treated as vec4s
- gui[0] = v.elements[0][0];
- gui[1] = v.elements[0][1];
- gui[2] = 0;
- gui[3] = 0;
- gui[4] = v.elements[1][0];
- gui[5] = v.elements[1][1];
- gui[6] = 0;
- gui[7] = 0;
- } break;
- case ShaderLanguage::TYPE_MAT3: {
-
- Basis v = value;
- float *gui = (float *)data;
-
- gui[0] = v.elements[0][0];
- gui[1] = v.elements[1][0];
- gui[2] = v.elements[2][0];
- gui[3] = 0;
- gui[4] = v.elements[0][1];
- gui[5] = v.elements[1][1];
- gui[6] = v.elements[2][1];
- gui[7] = 0;
- gui[8] = v.elements[0][2];
- gui[9] = v.elements[1][2];
- gui[10] = v.elements[2][2];
- gui[11] = 0;
- } break;
- case ShaderLanguage::TYPE_MAT4: {
-
- Transform v = value;
- float *gui = (float *)data;
-
- gui[0] = v.basis.elements[0][0];
- gui[1] = v.basis.elements[1][0];
- gui[2] = v.basis.elements[2][0];
- gui[3] = 0;
- gui[4] = v.basis.elements[0][1];
- gui[5] = v.basis.elements[1][1];
- gui[6] = v.basis.elements[2][1];
- gui[7] = 0;
- gui[8] = v.basis.elements[0][2];
- gui[9] = v.basis.elements[1][2];
- gui[10] = v.basis.elements[2][2];
- gui[11] = 0;
- gui[12] = v.origin.x;
- gui[13] = v.origin.y;
- gui[14] = v.origin.z;
- gui[15] = 1;
- } break;
- default: {
- }
- }
-}
-
-_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
-
- switch (type) {
- case ShaderLanguage::TYPE_BOOL: {
-
- uint32_t *gui = (uint32_t *)data;
- *gui = value[0].boolean ? 1 : 0;
- } break;
- case ShaderLanguage::TYPE_BVEC2: {
-
- uint32_t *gui = (uint32_t *)data;
- gui[0] = value[0].boolean ? 1 : 0;
- gui[1] = value[1].boolean ? 1 : 0;
-
- } break;
- case ShaderLanguage::TYPE_BVEC3: {
-
- uint32_t *gui = (uint32_t *)data;
- gui[0] = value[0].boolean ? 1 : 0;
- gui[1] = value[1].boolean ? 1 : 0;
- gui[2] = value[2].boolean ? 1 : 0;
-
- } break;
- case ShaderLanguage::TYPE_BVEC4: {
-
- uint32_t *gui = (uint32_t *)data;
- gui[0] = value[0].boolean ? 1 : 0;
- gui[1] = value[1].boolean ? 1 : 0;
- gui[2] = value[2].boolean ? 1 : 0;
- gui[3] = value[3].boolean ? 1 : 0;
-
- } break;
- case ShaderLanguage::TYPE_INT: {
-
- int32_t *gui = (int32_t *)data;
- gui[0] = value[0].sint;
-
- } break;
- case ShaderLanguage::TYPE_IVEC2: {
-
- int32_t *gui = (int32_t *)data;
-
- for (int i = 0; i < 2; i++) {
- gui[i] = value[i].sint;
- }
-
- } break;
- case ShaderLanguage::TYPE_IVEC3: {
-
- int32_t *gui = (int32_t *)data;
-
- for (int i = 0; i < 3; i++) {
- gui[i] = value[i].sint;
- }
-
- } break;
- case ShaderLanguage::TYPE_IVEC4: {
-
- int32_t *gui = (int32_t *)data;
-
- for (int i = 0; i < 4; i++) {
- gui[i] = value[i].sint;
- }
-
- } break;
- case ShaderLanguage::TYPE_UINT: {
-
- uint32_t *gui = (uint32_t *)data;
- gui[0] = value[0].uint;
-
- } break;
- case ShaderLanguage::TYPE_UVEC2: {
-
- int32_t *gui = (int32_t *)data;
-
- for (int i = 0; i < 2; i++) {
- gui[i] = value[i].uint;
- }
- } break;
- case ShaderLanguage::TYPE_UVEC3: {
- int32_t *gui = (int32_t *)data;
-
- for (int i = 0; i < 3; i++) {
- gui[i] = value[i].uint;
- }
-
- } break;
- case ShaderLanguage::TYPE_UVEC4: {
- int32_t *gui = (int32_t *)data;
-
- for (int i = 0; i < 4; i++) {
- gui[i] = value[i].uint;
- }
- } break;
- case ShaderLanguage::TYPE_FLOAT: {
-
- float *gui = (float *)data;
- gui[0] = value[0].real;
-
- } break;
- case ShaderLanguage::TYPE_VEC2: {
-
- float *gui = (float *)data;
-
- for (int i = 0; i < 2; i++) {
- gui[i] = value[i].real;
- }
-
- } break;
- case ShaderLanguage::TYPE_VEC3: {
-
- float *gui = (float *)data;
-
- for (int i = 0; i < 3; i++) {
- gui[i] = value[i].real;
- }
-
- } break;
- case ShaderLanguage::TYPE_VEC4: {
-
- float *gui = (float *)data;
-
- for (int i = 0; i < 4; i++) {
- gui[i] = value[i].real;
- }
- } break;
- case ShaderLanguage::TYPE_MAT2: {
- float *gui = (float *)data;
-
- //in std140 members of mat2 are treated as vec4s
- gui[0] = value[0].real;
- gui[1] = value[1].real;
- gui[2] = 0;
- gui[3] = 0;
- gui[4] = value[2].real;
- gui[5] = value[3].real;
- gui[6] = 0;
- gui[7] = 0;
- } break;
- case ShaderLanguage::TYPE_MAT3: {
-
- float *gui = (float *)data;
-
- gui[0] = value[0].real;
- gui[1] = value[1].real;
- gui[2] = value[2].real;
- gui[3] = 0;
- gui[4] = value[3].real;
- gui[5] = value[4].real;
- gui[6] = value[5].real;
- gui[7] = 0;
- gui[8] = value[6].real;
- gui[9] = value[7].real;
- gui[10] = value[8].real;
- gui[11] = 0;
- } break;
- case ShaderLanguage::TYPE_MAT4: {
-
- float *gui = (float *)data;
-
- for (int i = 0; i < 16; i++) {
- gui[i] = value[i].real;
- }
- } break;
- default: {
- }
- }
-}
-
-_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
-
- switch (type) {
-
- case ShaderLanguage::TYPE_BOOL:
- case ShaderLanguage::TYPE_INT:
- case ShaderLanguage::TYPE_UINT:
- case ShaderLanguage::TYPE_FLOAT: {
- zeromem(data, 4);
- } break;
- case ShaderLanguage::TYPE_BVEC2:
- case ShaderLanguage::TYPE_IVEC2:
- case ShaderLanguage::TYPE_UVEC2:
- case ShaderLanguage::TYPE_VEC2: {
- zeromem(data, 8);
- } break;
- case ShaderLanguage::TYPE_BVEC3:
- case ShaderLanguage::TYPE_IVEC3:
- case ShaderLanguage::TYPE_UVEC3:
- case ShaderLanguage::TYPE_VEC3:
- case ShaderLanguage::TYPE_BVEC4:
- case ShaderLanguage::TYPE_IVEC4:
- case ShaderLanguage::TYPE_UVEC4:
- case ShaderLanguage::TYPE_VEC4: {
-
- zeromem(data, 16);
- } break;
- case ShaderLanguage::TYPE_MAT2: {
-
- zeromem(data, 32);
- } break;
- case ShaderLanguage::TYPE_MAT3: {
-
- zeromem(data, 48);
- } break;
- case ShaderLanguage::TYPE_MAT4: {
- zeromem(data, 64);
- } break;
-
- default: {
- }
- }
-}
-
-void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
-
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) {
-
- if (E->get().order < 0)
- continue; // texture, does not go here
-
- //regular uniform
- uint32_t offset = p_uniform_offsets[E->get().order];
-#ifdef DEBUG_ENABLED
- uint32_t size = ShaderLanguage::get_type_size(E->get().type);
- ERR_CONTINUE(offset + size > p_buffer_size);
-#endif
- uint8_t *data = &p_buffer[offset];
- const Map<StringName, Variant>::Element *V = p_parameters.find(E->key());
-
- if (V) {
- //user provided
- _fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color);
-
- } else if (E->get().default_value.size()) {
- //default value
- _fill_std140_ubo_value(E->get().type, E->get().default_value, data);
- //value=E->get().default_value;
- } else {
- //zero because it was not provided
- if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- //colors must be set as black, with alpha as 1.0
- _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color);
- } else {
- //else just zero it out
- _fill_std140_ubo_empty(E->get().type, data);
- }
- }
- }
-}
-
-void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
-
- RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton;
-#ifdef TOOLS_ENABLED
- Texture *roughness_detect_texture = nullptr;
- VS::TextureDetectRoughnessChannel roughness_channel;
- Texture *normal_detect_texture = nullptr;
-#endif
-
- for (int i = 0; i < p_texture_uniforms.size(); i++) {
-
- const StringName &uniform_name = p_texture_uniforms[i].name;
-
- RID texture;
-
- const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
- if (V) {
- texture = V->get();
- }
-
- if (!texture.is_valid()) {
- const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
- if (W) {
-
- texture = W->get();
- }
- }
-
- RID rd_texture;
-
- if (texture.is_null()) {
- //check default usage
- switch (p_texture_uniforms[i].hint) {
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
- } break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
- } break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
- } break;
- default: {
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
- } break;
- }
- } else {
- bool srgb = p_use_linear_color && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO);
-
- Texture *tex = singleton->texture_owner.getornull(texture);
-
- if (tex) {
-
- rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
-#ifdef TOOLS_ENABLED
- if (tex->detect_3d_callback && p_use_linear_color) {
- tex->detect_3d_callback(tex->detect_3d_callback_ud);
- }
- if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
- if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
- normal_detect_texture = tex;
- }
- tex->detect_normal_callback(tex->detect_normal_callback_ud);
- }
- if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
- //find the normal texture
- roughness_detect_texture = tex;
- roughness_channel = VS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
- }
-
-#endif
- }
-
- if (rd_texture.is_null()) {
- //wtf
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
- }
- }
-
- p_textures[i] = rd_texture;
- }
-#ifdef TOOLS_ENABLED
- if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
- roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
- }
-#endif
-}
-
-void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) {
- Material *material = material_owner.getornull(p_material);
- if (material->shader_type != p_shader_type) {
- return;
- }
- if (material->data) {
- material->data->update_parameters(material->params, false, true);
- }
-}
-
-void RasterizerStorageRD::_update_queued_materials() {
- Material *material = material_update_list;
- while (material) {
- Material *next = material->update_next;
-
- if (material->data) {
- material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty);
- }
- material->update_requested = false;
- material->texture_dirty = false;
- material->uniform_dirty = false;
- material->update_next = NULL;
- material = next;
- }
- material_update_list = NULL;
-}
-/* MESH API */
-
-RID RasterizerStorageRD::mesh_create() {
-
- return mesh_owner.make_rid(Mesh());
-}
-
-/// Returns stride
-void RasterizerStorageRD::mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface) {
-
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
-
- //ensure blend shape consistency
- ERR_FAIL_COND(mesh->blend_shape_count && p_surface.blend_shapes.size() != (int)mesh->blend_shape_count);
- ERR_FAIL_COND(mesh->blend_shape_count && p_surface.bone_aabbs.size() != mesh->bone_aabbs.size());
-
-#ifdef DEBUG_ENABLED
- //do a validation, to catch errors first
- {
-
- uint32_t stride = 0;
-
- for (int i = 0; i < VS::ARRAY_WEIGHTS; i++) {
-
- if ((p_surface.format & (1 << i))) {
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- if (p_surface.format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
- stride += sizeof(float) * 2;
- } else {
- stride += sizeof(float) * 3;
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- if (p_surface.format & VS::ARRAY_COMPRESS_NORMAL) {
- stride += sizeof(int8_t) * 4;
- } else {
- stride += sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_TANGENT: {
-
- if (p_surface.format & VS::ARRAY_COMPRESS_TANGENT) {
- stride += sizeof(int8_t) * 4;
- } else {
- stride += sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- if (p_surface.format & VS::ARRAY_COMPRESS_COLOR) {
- stride += sizeof(int8_t) * 4;
- } else {
- stride += sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_TEX_UV: {
-
- if (p_surface.format & VS::ARRAY_COMPRESS_TEX_UV) {
- stride += sizeof(int16_t) * 2;
- } else {
- stride += sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_TEX_UV2: {
-
- if (p_surface.format & VS::ARRAY_COMPRESS_TEX_UV2) {
- stride += sizeof(int16_t) * 2;
- } else {
- stride += sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_BONES: {
- //assumed weights too
-
- //unique format, internally 16 bits, exposed as single array for 32
-
- stride += sizeof(int32_t) * 4;
-
- } break;
- }
- }
- }
-
- int expected_size = stride * p_surface.vertex_count;
- ERR_FAIL_COND_MSG(expected_size != p_surface.vertex_data.size(), "Size of data provided (" + itos(p_surface.vertex_data.size()) + ") does not match expected (" + itos(expected_size) + ")");
- }
-
-#endif
-
- Mesh::Surface *s = memnew(Mesh::Surface);
-
- s->format = p_surface.format;
- s->primitive = p_surface.primitive;
-
- s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data);
- s->vertex_count = p_surface.vertex_count;
-
- if (p_surface.index_count) {
- bool is_index_16 = p_surface.vertex_count <= 65536;
-
- s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false);
- s->index_count = p_surface.index_count;
- s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count);
- if (p_surface.lods.size()) {
- s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
- s->lod_count = p_surface.lods.size();
-
- for (int i = 0; i < p_surface.lods.size(); i++) {
-
- uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
- s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data);
- s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices);
- s->lods[i].edge_length = p_surface.lods[i].edge_length;
- }
- }
- }
-
- s->aabb = p_surface.aabb;
- s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
-
- for (int i = 0; i < p_surface.blend_shapes.size(); i++) {
-
- if (p_surface.blend_shapes[i].size() != p_surface.vertex_data.size()) {
- memdelete(s);
- ERR_FAIL_COND(p_surface.blend_shapes[i].size() != p_surface.vertex_data.size());
- }
- RID vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.blend_shapes[i].size(), p_surface.blend_shapes[i]);
- s->blend_shapes.push_back(vertex_buffer);
- }
-
- mesh->blend_shape_count = p_surface.blend_shapes.size();
-
- if (mesh->surface_count == 0) {
- mesh->bone_aabbs = p_surface.bone_aabbs;
- mesh->aabb = p_surface.aabb;
- } else {
- for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
- mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]);
- }
- mesh->aabb.merge_with(p_surface.aabb);
- }
-
- s->material = p_surface.material;
-
- mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
- mesh->surfaces[mesh->surface_count] = s;
- mesh->surface_count++;
-
- mesh->instance_dependency.instance_notify_changed(true, true);
-
- mesh->material_cache.clear();
-}
-
-int RasterizerStorageRD::mesh_get_blend_shape_count(RID p_mesh) const {
- const Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, -1);
- return mesh->blend_shape_count;
-}
-
-void RasterizerStorageRD::mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_INDEX((int)p_mode, 2);
-
- mesh->blend_shape_mode = p_mode;
-}
-VS::BlendShapeMode RasterizerStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, VS::BLEND_SHAPE_MODE_NORMALIZED);
- return mesh->blend_shape_mode;
-}
-
-void RasterizerStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
- ERR_FAIL_COND(p_data.size() == 0);
- uint64_t data_size = p_data.size();
- const uint8_t *r = p_data.ptr();
-
- RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r);
-}
-
-void RasterizerStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
- mesh->surfaces[p_surface]->material = p_material;
-
- mesh->instance_dependency.instance_notify_changed(false, true);
- mesh->material_cache.clear();
-}
-RID RasterizerStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, RID());
- ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
-
- return mesh->surfaces[p_surface]->material;
-}
-
-VS::SurfaceData RasterizerStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const {
-
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, VS::SurfaceData());
- ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, VS::SurfaceData());
-
- Mesh::Surface &s = *mesh->surfaces[p_surface];
-
- VS::SurfaceData sd;
- sd.format = s.format;
- sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
- sd.vertex_count = s.vertex_count;
- sd.index_count = s.index_count;
- sd.primitive = s.primitive;
-
- if (sd.index_count) {
- sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer);
- }
- sd.aabb = s.aabb;
- for (uint32_t i = 0; i < s.lod_count; i++) {
- VS::SurfaceData::LOD lod;
- lod.edge_length = s.lods[i].edge_length;
- lod.index_data = RD::get_singleton()->buffer_get_data(s.lods[i].index_buffer);
- sd.lods.push_back(lod);
- }
-
- sd.bone_aabbs = s.bone_aabbs;
-
- for (int i = 0; i < s.blend_shapes.size(); i++) {
- Vector<uint8_t> bs = RD::get_singleton()->buffer_get_data(s.blend_shapes[i]);
- sd.blend_shapes.push_back(bs);
- }
-
- return sd;
-}
-
-int RasterizerStorageRD::mesh_get_surface_count(RID p_mesh) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, 0);
- return mesh->surface_count;
-}
-
-void RasterizerStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- mesh->custom_aabb = p_aabb;
-}
-AABB RasterizerStorageRD::mesh_get_custom_aabb(RID p_mesh) const {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, AABB());
- return mesh->custom_aabb;
-}
-
-AABB RasterizerStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, AABB());
-
- if (mesh->custom_aabb != AABB()) {
- return mesh->custom_aabb;
- }
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
-
- if (!skeleton || skeleton->size == 0) {
- return mesh->aabb;
- }
-
- AABB aabb;
-
- for (uint32_t i = 0; i < mesh->surface_count; i++) {
-
- AABB laabb;
- if ((mesh->surfaces[i]->format & VS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->bone_aabbs.size()) {
-
- int bs = mesh->surfaces[i]->bone_aabbs.size();
- const AABB *skbones = mesh->surfaces[i]->bone_aabbs.ptr();
-
- int sbs = skeleton->size;
- ERR_CONTINUE(bs > sbs);
- const float *baseptr = skeleton->data.ptr();
-
- bool first = true;
-
- if (skeleton->use_2d) {
- for (int j = 0; j < bs; j++) {
-
- if (skbones[0].size == Vector3())
- continue; //bone is unused
-
- const float *dataptr = baseptr + j * 8;
-
- Transform mtx;
-
- mtx.basis.elements[0].x = dataptr[0];
- mtx.basis.elements[1].x = dataptr[1];
- mtx.origin.x = dataptr[3];
-
- mtx.basis.elements[0].y = dataptr[4];
- mtx.basis.elements[1].y = dataptr[5];
- mtx.origin.y = dataptr[7];
-
- AABB baabb = mtx.xform(skbones[j]);
-
- if (first) {
- laabb = baabb;
- first = false;
- } else {
- laabb.merge_with(baabb);
- }
- }
- } else {
- for (int j = 0; j < bs; j++) {
-
- if (skbones[0].size == Vector3())
- continue; //bone is unused
-
- const float *dataptr = baseptr + j * 12;
-
- Transform mtx;
-
- mtx.basis.elements[0][0] = dataptr[0];
- mtx.basis.elements[0][1] = dataptr[1];
- mtx.basis.elements[0][2] = dataptr[2];
- mtx.origin.x = dataptr[3];
- mtx.basis.elements[1][0] = dataptr[4];
- mtx.basis.elements[1][1] = dataptr[5];
- mtx.basis.elements[1][2] = dataptr[6];
- mtx.origin.y = dataptr[7];
- mtx.basis.elements[2][0] = dataptr[8];
- mtx.basis.elements[2][1] = dataptr[9];
- mtx.basis.elements[2][2] = dataptr[10];
- mtx.origin.z = dataptr[11];
-
- AABB baabb = mtx.xform(skbones[j]);
- if (first) {
- laabb = baabb;
- first = false;
- } else {
- laabb.merge_with(baabb);
- }
- }
- }
-
- if (laabb.size == Vector3()) {
- laabb = mesh->surfaces[i]->aabb;
- }
- } else {
-
- laabb = mesh->surfaces[i]->aabb;
- }
-
- if (i == 0) {
- aabb = laabb;
- } else {
- aabb.merge_with(laabb);
- }
- }
-
- return aabb;
-}
-
-void RasterizerStorageRD::mesh_clear(RID p_mesh) {
-
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- for (uint32_t i = 0; i < mesh->surface_count; i++) {
- Mesh::Surface &s = *mesh->surfaces[i];
- RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
- if (s.versions) {
- memfree(s.versions); //reallocs, so free with memfree.
- }
-
- if (s.index_buffer.is_valid()) {
- RD::get_singleton()->free(s.index_buffer);
- }
-
- if (s.lod_count) {
- for (uint32_t j = 0; j < s.lod_count; j++) {
- RD::get_singleton()->free(s.lods[j].index_buffer);
- }
- memdelete_arr(s.lods);
- }
-
- for (int32_t j = 0; j < s.blend_shapes.size(); j++) {
- RD::get_singleton()->free(s.blend_shapes[j]);
- }
-
- if (s.blend_shape_base_buffer.is_valid()) {
- RD::get_singleton()->free(s.blend_shape_base_buffer);
- }
-
- memdelete(mesh->surfaces[i]);
- }
- if (mesh->surfaces) {
- memfree(mesh->surfaces);
- }
-
- mesh->surfaces = nullptr;
- mesh->surface_count = 0;
- mesh->material_cache.clear();
- mesh->instance_dependency.instance_notify_changed(true, true);
-}
-
-void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask) {
- uint32_t version = s->version_count;
- s->version_count++;
- s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
-
- Mesh::Surface::Version &v = s->versions[version];
-
- Vector<RD::VertexDescription> attributes;
- Vector<RID> buffers;
-
- uint32_t stride = 0;
-
- for (int i = 0; i < VS::ARRAY_WEIGHTS; i++) {
-
- RD::VertexDescription vd;
- RID buffer;
- vd.location = i;
-
- if (!(s->format & (1 << i))) {
- // Not supplied by surface, use default value
- buffer = mesh_default_rd_buffers[i];
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
-
- } break;
- case VS::ARRAY_NORMAL: {
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- } break;
- case VS::ARRAY_TANGENT: {
-
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- } break;
- case VS::ARRAY_COLOR: {
-
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
-
- } break;
- case VS::ARRAY_TEX_UV: {
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
-
- } break;
- case VS::ARRAY_TEX_UV2: {
-
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- } break;
- case VS::ARRAY_BONES: {
-
- //assumed weights too
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
- } break;
- }
- } else {
- //Supplied, use it
-
- vd.offset = stride;
- vd.stride = 1; //mark that it needs a stride set
- buffer = s->vertex_buffer;
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
- stride += sizeof(float) * 3;
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- if (s->format & VS::ARRAY_COMPRESS_NORMAL) {
- vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
- stride += sizeof(int8_t) * 4;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- stride += sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_TANGENT: {
-
- if (s->format & VS::ARRAY_COMPRESS_TANGENT) {
- vd.format = RD::DATA_FORMAT_R8G8B8A8_SNORM;
- stride += sizeof(int8_t) * 4;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- stride += sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- if (s->format & VS::ARRAY_COMPRESS_COLOR) {
- vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- stride += sizeof(int8_t) * 4;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
- stride += sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_TEX_UV: {
-
- if (s->format & VS::ARRAY_COMPRESS_TEX_UV) {
- vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- stride += sizeof(int16_t) * 2;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_TEX_UV2: {
-
- if (s->format & VS::ARRAY_COMPRESS_TEX_UV2) {
- vd.format = RD::DATA_FORMAT_R16G16_SFLOAT;
- stride += sizeof(int16_t) * 2;
- } else {
- vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
- stride += sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_BONES: {
- //assumed weights too
-
- //unique format, internally 16 bits, exposed as single array for 32
-
- vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
- stride += sizeof(int32_t) * 4;
-
- } break;
- }
- }
-
- if (!(p_input_mask & (1 << i))) {
- continue; // Shader does not need this, skip it
- }
-
- attributes.push_back(vd);
- buffers.push_back(buffer);
- }
-
- //update final stride
- for (int i = 0; i < attributes.size(); i++) {
- if (attributes[i].stride == 1) {
- attributes.write[i].stride = stride;
- }
- }
-
- v.input_mask = p_input_mask;
- v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
- v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers);
-}
-
-////////////////// MULTIMESH
-
-RID RasterizerStorageRD::multimesh_create() {
-
- return multimesh_owner.make_rid(MultiMesh());
-}
-
-void RasterizerStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
-
- if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
- return;
- }
-
- if (multimesh->buffer.is_valid()) {
- RD::get_singleton()->free(multimesh->buffer);
- multimesh->buffer = RID();
- multimesh->uniform_set_3d = RID(); //cleared by dependency
- }
-
- if (multimesh->data_cache_dirty_regions) {
- memdelete_arr(multimesh->data_cache_dirty_regions);
- multimesh->data_cache_dirty_regions = nullptr;
- multimesh->data_cache_used_dirty_regions = 0;
- }
-
- multimesh->instances = p_instances;
- multimesh->xform_format = p_transform_format;
- multimesh->uses_colors = p_use_colors;
- multimesh->color_offset_cache = p_transform_format == VS::MULTIMESH_TRANSFORM_2D ? 8 : 12;
- multimesh->uses_custom_data = p_use_custom_data;
- multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 4 : 0);
- multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
- multimesh->buffer_set = false;
-
- //print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == VS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances));
- multimesh->data_cache = Vector<float>();
- multimesh->aabb = AABB();
- multimesh->aabb_dirty = false;
- multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
-
- if (multimesh->instances) {
-
- multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4);
- }
-}
-
-int RasterizerStorageRD::multimesh_get_instance_count(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, 0);
- return multimesh->instances;
-}
-
-void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- if (multimesh->mesh == p_mesh) {
- return;
- }
- multimesh->mesh = p_mesh;
-
- if (multimesh->instances == 0) {
- return;
- }
-
- if (multimesh->data_cache.size()) {
- //we have a data cache, just mark it dirt
- _multimesh_mark_all_dirty(multimesh, false, true);
- } else if (multimesh->instances) {
- //need to re-create AABB unfortunately, calling this has a penalty
- if (multimesh->buffer_set) {
- Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- const uint8_t *r = buffer.ptr();
- const float *data = (const float *)r;
- _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
- }
- }
-
- multimesh->instance_dependency.instance_notify_changed(true, true);
-}
-
-#define MULTIMESH_DIRTY_REGION_SIZE 512
-
-void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const {
- if (multimesh->data_cache.size() > 0) {
- return; //already local
- }
- ERR_FAIL_COND(multimesh->data_cache.size() > 0);
- // this means that the user wants to load/save individual elements,
- // for this, the data must reside on CPU, so just copy it there.
- multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache);
- {
- float *w = multimesh->data_cache.ptrw();
-
- if (multimesh->buffer_set) {
- Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- {
-
- const uint8_t *r = buffer.ptr();
- copymem(w, r, buffer.size());
- }
- } else {
- zeromem(w, multimesh->instances * multimesh->stride_cache * sizeof(float));
- }
- }
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = 0;
- }
- multimesh->data_cache_used_dirty_regions = 0;
-}
-
-void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
-
- uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE;
-#ifdef DEBUG_ENABLED
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- ERR_FAIL_UNSIGNED_INDEX(region_index, data_cache_dirty_region_count); //bug
-#endif
- if (!multimesh->data_cache_dirty_regions[region_index]) {
- multimesh->data_cache_dirty_regions[region_index] = true;
- multimesh->data_cache_used_dirty_regions++;
- }
-
- if (p_aabb) {
- multimesh->aabb_dirty = true;
- }
-
- if (!multimesh->dirty) {
- multimesh->dirty_list = multimesh_dirty_list;
- multimesh_dirty_list = multimesh;
- multimesh->dirty = true;
- }
-}
-
-void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) {
- if (p_data) {
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
-
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- if (!multimesh->data_cache_dirty_regions[i]) {
- multimesh->data_cache_dirty_regions[i] = true;
- multimesh->data_cache_used_dirty_regions++;
- }
- }
- }
-
- if (p_aabb) {
- multimesh->aabb_dirty = true;
- }
-
- if (!multimesh->dirty) {
- multimesh->dirty_list = multimesh_dirty_list;
- multimesh_dirty_list = multimesh;
- multimesh->dirty = true;
- }
-}
-
-void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) {
-
- ERR_FAIL_COND(multimesh->mesh.is_null());
- AABB aabb;
- AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
- for (int i = 0; i < p_instances; i++) {
- const float *data = p_data + multimesh->stride_cache * i;
- Transform t;
-
- if (multimesh->xform_format == VS::MULTIMESH_TRANSFORM_3D) {
-
- t.basis.elements[0][0] = data[0];
- t.basis.elements[0][1] = data[1];
- t.basis.elements[0][2] = data[2];
- t.origin.x = data[3];
- t.basis.elements[1][0] = data[4];
- t.basis.elements[1][1] = data[5];
- t.basis.elements[1][2] = data[6];
- t.origin.y = data[7];
- t.basis.elements[2][0] = data[8];
- t.basis.elements[2][1] = data[9];
- t.basis.elements[2][2] = data[10];
- t.origin.z = data[11];
-
- } else {
-
- t.basis.elements[0].x = data[0];
- t.basis.elements[1].x = data[1];
- t.origin.x = data[3];
-
- t.basis.elements[0].y = data[4];
- t.basis.elements[1].y = data[5];
- t.origin.y = data[7];
- }
-
- if (i == 0) {
- aabb = t.xform(mesh_aabb);
- } else {
- aabb.merge_with(t.xform(mesh_aabb));
- }
- }
-
- multimesh->aabb = aabb;
-}
-
-void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_INDEX(p_index, multimesh->instances);
- ERR_FAIL_COND(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_3D);
-
- _multimesh_make_local(multimesh);
-
- {
- float *w = multimesh->data_cache.ptrw();
-
- float *dataptr = w + p_index * multimesh->stride_cache;
-
- dataptr[0] = p_transform.basis.elements[0][0];
- dataptr[1] = p_transform.basis.elements[0][1];
- dataptr[2] = p_transform.basis.elements[0][2];
- dataptr[3] = p_transform.origin.x;
- dataptr[4] = p_transform.basis.elements[1][0];
- dataptr[5] = p_transform.basis.elements[1][1];
- dataptr[6] = p_transform.basis.elements[1][2];
- dataptr[7] = p_transform.origin.y;
- dataptr[8] = p_transform.basis.elements[2][0];
- dataptr[9] = p_transform.basis.elements[2][1];
- dataptr[10] = p_transform.basis.elements[2][2];
- dataptr[11] = p_transform.origin.z;
- }
-
- _multimesh_mark_dirty(multimesh, p_index, true);
-}
-
-void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_INDEX(p_index, multimesh->instances);
- ERR_FAIL_COND(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_2D);
-
- _multimesh_make_local(multimesh);
-
- {
- float *w = multimesh->data_cache.ptrw();
-
- float *dataptr = w + p_index * multimesh->stride_cache;
-
- dataptr[0] = p_transform.elements[0][0];
- dataptr[1] = p_transform.elements[1][0];
- dataptr[2] = 0;
- dataptr[3] = p_transform.elements[2][0];
- dataptr[4] = p_transform.elements[0][1];
- dataptr[5] = p_transform.elements[1][1];
- dataptr[6] = 0;
- dataptr[7] = p_transform.elements[2][1];
- }
-
- _multimesh_mark_dirty(multimesh, p_index, true);
-}
-void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_INDEX(p_index, multimesh->instances);
- ERR_FAIL_COND(!multimesh->uses_colors);
-
- _multimesh_make_local(multimesh);
-
- {
- float *w = multimesh->data_cache.ptrw();
-
- float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
-
- dataptr[0] = p_color.r;
- dataptr[1] = p_color.g;
- dataptr[2] = p_color.b;
- dataptr[3] = p_color.a;
- }
-
- _multimesh_mark_dirty(multimesh, p_index, false);
-}
-void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_INDEX(p_index, multimesh->instances);
- ERR_FAIL_COND(!multimesh->uses_custom_data);
-
- _multimesh_make_local(multimesh);
-
- {
- float *w = multimesh->data_cache.ptrw();
-
- float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
-
- dataptr[0] = p_color.r;
- dataptr[1] = p_color.g;
- dataptr[2] = p_color.b;
- dataptr[3] = p_color.a;
- }
-
- _multimesh_mark_dirty(multimesh, p_index, false);
-}
-
-RID RasterizerStorageRD::multimesh_get_mesh(RID p_multimesh) const {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, RID());
-
- return multimesh->mesh;
-}
-
-Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform());
- ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform());
- ERR_FAIL_COND_V(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_3D, Transform());
-
- _multimesh_make_local(multimesh);
-
- Transform t;
- {
- const float *r = multimesh->data_cache.ptr();
-
- const float *dataptr = r + p_index * multimesh->stride_cache;
-
- t.basis.elements[0][0] = dataptr[0];
- t.basis.elements[0][1] = dataptr[1];
- t.basis.elements[0][2] = dataptr[2];
- t.origin.x = dataptr[3];
- t.basis.elements[1][0] = dataptr[4];
- t.basis.elements[1][1] = dataptr[5];
- t.basis.elements[1][2] = dataptr[6];
- t.origin.y = dataptr[7];
- t.basis.elements[2][0] = dataptr[8];
- t.basis.elements[2][1] = dataptr[9];
- t.basis.elements[2][2] = dataptr[10];
- t.origin.z = dataptr[11];
- }
-
- return t;
-}
-Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform2D());
- ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
- ERR_FAIL_COND_V(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_2D, Transform2D());
-
- _multimesh_make_local(multimesh);
-
- Transform2D t;
- {
- const float *r = multimesh->data_cache.ptr();
-
- const float *dataptr = r + p_index * multimesh->stride_cache;
-
- t.elements[0][0] = dataptr[0];
- t.elements[1][0] = dataptr[1];
- t.elements[2][0] = dataptr[3];
- t.elements[0][1] = dataptr[4];
- t.elements[1][1] = dataptr[5];
- t.elements[2][1] = dataptr[7];
- }
-
- return t;
-}
-Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Color());
- ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
- ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
-
- _multimesh_make_local(multimesh);
-
- Color c;
- {
- const float *r = multimesh->data_cache.ptr();
-
- const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
-
- c.r = dataptr[0];
- c.g = dataptr[1];
- c.b = dataptr[2];
- c.a = dataptr[3];
- }
-
- return c;
-}
-Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Color());
- ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
- ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
-
- _multimesh_make_local(multimesh);
-
- Color c;
- {
- const float *r = multimesh->data_cache.ptr();
-
- const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
-
- c.r = dataptr[0];
- c.g = dataptr[1];
- c.b = dataptr[2];
- c.a = dataptr[3];
- }
-
- return c;
-}
-
-void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
-
- {
- const float *r = p_buffer.ptr();
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r, false);
- multimesh->buffer_set = true;
- }
-
- if (multimesh->data_cache.size()) {
- //if we have a data cache, just update it
- multimesh->data_cache = p_buffer;
- {
- //clear dirty since nothing will be dirty anymore
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
- }
- multimesh->data_cache_used_dirty_regions = 0;
- }
-
- _multimesh_mark_all_dirty(multimesh, false, true); //update AABB
- } else if (multimesh->mesh.is_valid()) {
- //if we have a mesh set, we need to re-generate the AABB from the new data
- const float *data = p_buffer.ptr();
-
- _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
- multimesh->instance_dependency.instance_notify_changed(true, false);
- }
-}
-
-Vector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Vector<float>());
- if (multimesh->buffer.is_null()) {
- return Vector<float>();
- } else if (multimesh->data_cache.size()) {
- return multimesh->data_cache;
- } else {
- //get from memory
-
- Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- Vector<float> ret;
- ret.resize(multimesh->instances);
- {
- float *w = multimesh->data_cache.ptrw();
- const uint8_t *r = buffer.ptr();
- copymem(w, r, buffer.size());
- }
-
- return ret;
- }
-}
-
-void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND(!multimesh);
- ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
- if (multimesh->visible_instances == p_visible) {
- return;
- }
-
- if (multimesh->data_cache.size()) {
- //there is a data cache..
- _multimesh_mark_all_dirty(multimesh, false, true);
- }
-
- multimesh->visible_instances = p_visible;
-}
-int RasterizerStorageRD::multimesh_get_visible_instances(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, 0);
- return multimesh->visible_instances;
-}
-
-AABB RasterizerStorageRD::multimesh_get_aabb(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, AABB());
- if (multimesh->aabb_dirty) {
- const_cast<RasterizerStorageRD *>(this)->_update_dirty_multimeshes();
- }
- return multimesh->aabb;
-}
-
-void RasterizerStorageRD::_update_dirty_multimeshes() {
-
- while (multimesh_dirty_list) {
-
- MultiMesh *multimesh = multimesh_dirty_list;
-
- if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
- const float *data = multimesh->data_cache.ptr();
-
- uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
-
- if (multimesh->data_cache_used_dirty_regions) {
-
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- uint32_t visible_region_count = (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
-
- uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
-
- if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
- //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data, false);
- } else {
- //not that many regions? update them all
- for (uint32_t i = 0; i < visible_region_count; i++) {
- if (multimesh->data_cache_dirty_regions[i]) {
- uint64_t offset = i * region_size;
- uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float);
- RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size], false);
- }
- }
- }
-
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
- }
-
- multimesh->data_cache_used_dirty_regions = 0;
- }
-
- if (multimesh->aabb_dirty) {
- //aabb is dirty..
- _multimesh_re_create_aabb(multimesh, data, visible_instances);
- multimesh->aabb_dirty = false;
- multimesh->instance_dependency.instance_notify_changed(true, false);
- }
- }
-
- multimesh_dirty_list = multimesh->dirty_list;
-
- multimesh->dirty_list = nullptr;
- multimesh->dirty = false;
- }
-
- multimesh_dirty_list = nullptr;
-}
-
-/* SKELETON */
-
-/* SKELETON API */
-
-RID RasterizerStorageRD::skeleton_create() {
-
- return skeleton_owner.make_rid(Skeleton());
-}
-
-void RasterizerStorageRD::_skeleton_make_dirty(Skeleton *skeleton) {
-
- if (!skeleton->dirty) {
- skeleton->dirty = true;
- skeleton->dirty_list = skeleton_dirty_list;
- skeleton_dirty_list = skeleton;
- }
-}
-
-void RasterizerStorageRD::skeleton_allocate(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);
-
- if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton)
- return;
-
- skeleton->size = p_bones;
- skeleton->use_2d = p_2d_skeleton;
- skeleton->uniform_set_3d = RID();
-
- if (skeleton->buffer.is_valid()) {
- RD::get_singleton()->free(skeleton->buffer);
- skeleton->buffer = RID();
- skeleton->data.resize(0);
- }
-
- 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));
-
- _skeleton_make_dirty(skeleton);
- }
-}
-int RasterizerStorageRD::skeleton_get_bone_count(RID p_skeleton) const {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, 0);
-
- return skeleton->size;
-}
-
-void RasterizerStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
-
- ERR_FAIL_COND(!skeleton);
- ERR_FAIL_INDEX(p_bone, skeleton->size);
- ERR_FAIL_COND(skeleton->use_2d);
-
- float *dataptr = skeleton->data.ptrw() + p_bone * 12;
-
- dataptr[0] = p_transform.basis.elements[0][0];
- dataptr[1] = p_transform.basis.elements[0][1];
- dataptr[2] = p_transform.basis.elements[0][2];
- dataptr[3] = p_transform.origin.x;
- dataptr[4] = p_transform.basis.elements[1][0];
- dataptr[5] = p_transform.basis.elements[1][1];
- dataptr[6] = p_transform.basis.elements[1][2];
- dataptr[7] = p_transform.origin.y;
- dataptr[8] = p_transform.basis.elements[2][0];
- dataptr[9] = p_transform.basis.elements[2][1];
- dataptr[10] = p_transform.basis.elements[2][2];
- dataptr[11] = p_transform.origin.z;
-
- _skeleton_make_dirty(skeleton);
-}
-
-Transform RasterizerStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
-
- ERR_FAIL_COND_V(!skeleton, Transform());
- ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform());
- ERR_FAIL_COND_V(skeleton->use_2d, Transform());
-
- const float *dataptr = skeleton->data.ptr() + p_bone * 12;
-
- Transform t;
-
- t.basis.elements[0][0] = dataptr[0];
- t.basis.elements[0][1] = dataptr[1];
- t.basis.elements[0][2] = dataptr[2];
- t.origin.x = dataptr[3];
- t.basis.elements[1][0] = dataptr[4];
- t.basis.elements[1][1] = dataptr[5];
- t.basis.elements[1][2] = dataptr[6];
- t.origin.y = dataptr[7];
- t.basis.elements[2][0] = dataptr[8];
- t.basis.elements[2][1] = dataptr[9];
- t.basis.elements[2][2] = dataptr[10];
- t.origin.z = dataptr[11];
-
- return t;
-}
-void RasterizerStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
-
- ERR_FAIL_COND(!skeleton);
- ERR_FAIL_INDEX(p_bone, skeleton->size);
- ERR_FAIL_COND(!skeleton->use_2d);
-
- float *dataptr = skeleton->data.ptrw() + p_bone * 8;
-
- dataptr[0] = p_transform.elements[0][0];
- dataptr[1] = p_transform.elements[1][0];
- dataptr[2] = 0;
- dataptr[3] = p_transform.elements[2][0];
- dataptr[4] = p_transform.elements[0][1];
- dataptr[5] = p_transform.elements[1][1];
- dataptr[6] = 0;
- dataptr[7] = p_transform.elements[2][1];
-
- _skeleton_make_dirty(skeleton);
-}
-Transform2D RasterizerStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
-
- ERR_FAIL_COND_V(!skeleton, Transform2D());
- ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
- ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
-
- const float *dataptr = skeleton->data.ptr() + p_bone * 8;
-
- Transform2D t;
- t.elements[0][0] = dataptr[0];
- t.elements[1][0] = dataptr[1];
- t.elements[2][0] = dataptr[3];
- t.elements[0][1] = dataptr[4];
- t.elements[1][1] = dataptr[5];
- t.elements[2][1] = dataptr[7];
-
- return t;
-}
-
-void RasterizerStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
-
- ERR_FAIL_COND(!skeleton->use_2d);
-
- skeleton->base_transform_2d = p_base_transform;
-}
-
-void RasterizerStorageRD::_update_dirty_skeletons() {
-
- while (skeleton_dirty_list) {
-
- Skeleton *skeleton = skeleton_dirty_list;
-
- if (skeleton->size) {
-
- RD::get_singleton()->buffer_update(skeleton->buffer, 0, skeleton->data.size() * sizeof(float), skeleton->data.ptr(), false);
- }
-
- skeleton_dirty_list = skeleton->dirty_list;
-
- skeleton->instance_dependency.instance_notify_changed(true, false);
-
- skeleton->dirty = false;
- skeleton->dirty_list = nullptr;
- }
-
- skeleton_dirty_list = nullptr;
-}
-
-/* LIGHT */
-
-RID RasterizerStorageRD::light_create(VS::LightType p_type) {
-
- Light light;
- light.type = p_type;
-
- light.param[VS::LIGHT_PARAM_ENERGY] = 1.0;
- light.param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
- light.param[VS::LIGHT_PARAM_SPECULAR] = 0.5;
- light.param[VS::LIGHT_PARAM_RANGE] = 1.0;
- light.param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;
- light.param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45;
- light.param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
- light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
- light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
- light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
- light.param[VS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;
- light.param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1;
- light.param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1;
-
- return light_owner.make_rid(light);
-}
-
-void RasterizerStorageRD::light_set_color(RID p_light, const Color &p_color) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->color = p_color;
-}
-void RasterizerStorageRD::light_set_param(RID p_light, VS::LightParam p_param, float p_value) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
- ERR_FAIL_INDEX(p_param, VS::LIGHT_PARAM_MAX);
-
- switch (p_param) {
- case VS::LIGHT_PARAM_RANGE:
- case VS::LIGHT_PARAM_SPOT_ANGLE:
- case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
- case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
- case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
- case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
- case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
- case VS::LIGHT_PARAM_SHADOW_BIAS: {
-
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
- } break;
- default: {
- }
- }
-
- light->param[p_param] = p_value;
-}
-void RasterizerStorageRD::light_set_shadow(RID p_light, bool p_enabled) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
- light->shadow = p_enabled;
-
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
- light->shadow_color = p_color;
-}
-
-void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->projector = p_texture;
-}
-
-void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->negative = p_enable;
-}
-void RasterizerStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->cull_mask = p_mask;
-
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->reverse_cull = p_enabled;
-
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::light_set_use_gi(RID p_light, bool p_enabled) {
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->use_gi = p_enabled;
-
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-void RasterizerStorageRD::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->omni_shadow_mode = p_mode;
-
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-
-VS::LightOmniShadowMode RasterizerStorageRD::light_omni_get_shadow_mode(RID p_light) {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_OMNI_SHADOW_CUBE);
-
- return light->omni_shadow_mode;
-}
-
-void RasterizerStorageRD::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->directional_shadow_mode = p_mode;
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->directional_blend_splits = p_enable;
- light->version++;
- light->instance_dependency.instance_notify_changed(true, false);
-}
-
-bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, false);
-
- return light->directional_blend_splits;
-}
-
-VS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
-
- return light->directional_shadow_mode;
-}
-
-void RasterizerStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) {
-
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND(!light);
-
- light->directional_range_mode = p_range_mode;
-}
-
-VS::LightDirectionalShadowDepthRangeMode RasterizerStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
-
- return light->directional_range_mode;
-}
-
-bool RasterizerStorageRD::light_get_use_gi(RID p_light) {
- Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, false);
-
- return light->use_gi;
-}
-
-uint64_t RasterizerStorageRD::light_get_version(RID p_light) const {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, 0);
-
- return light->version;
-}
-
-AABB RasterizerStorageRD::light_get_aabb(RID p_light) const {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, AABB());
-
- switch (light->type) {
-
- case VS::LIGHT_SPOT: {
-
- float len = light->param[VS::LIGHT_PARAM_RANGE];
- float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len;
- return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
- };
- case VS::LIGHT_OMNI: {
-
- float r = light->param[VS::LIGHT_PARAM_RANGE];
- return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2);
- };
- case VS::LIGHT_DIRECTIONAL: {
-
- return AABB();
- };
- }
-
- ERR_FAIL_V(AABB());
-}
-
-/* REFLECTION PROBE */
-
-RID RasterizerStorageRD::reflection_probe_create() {
-
- return reflection_probe_owner.make_rid(ReflectionProbe());
-}
-
-void RasterizerStorageRD::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->update_mode = p_mode;
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->intensity = p_intensity;
-}
-
-void RasterizerStorageRD::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->interior_ambient = p_ambient;
-}
-
-void RasterizerStorageRD::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->interior_ambient_energy = p_energy;
-}
-
-void RasterizerStorageRD::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->interior_ambient_probe_contrib = p_contrib;
-}
-
-void RasterizerStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->max_distance = p_distance;
-
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-void RasterizerStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->extents = p_extents;
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-void RasterizerStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->origin_offset = p_offset;
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->interior = p_enable;
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-void RasterizerStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->box_projection = p_enable;
-}
-
-void RasterizerStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->enable_shadows = p_enable;
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-void RasterizerStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
-
- reflection_probe->cull_mask = p_layers;
- reflection_probe->instance_dependency.instance_notify_changed(true, false);
-}
-
-void RasterizerStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
-
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND(!reflection_probe);
- ERR_FAIL_COND(p_resolution < 32);
-
- reflection_probe->resolution = p_resolution;
-}
-
-AABB RasterizerStorageRD::reflection_probe_get_aabb(RID p_probe) const {
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, AABB());
-
- AABB aabb;
- aabb.position = -reflection_probe->extents;
- aabb.size = reflection_probe->extents * 2.0;
-
- return aabb;
-}
-VS::ReflectionProbeUpdateMode RasterizerStorageRD::reflection_probe_get_update_mode(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS);
-
- return reflection_probe->update_mode;
-}
-
-uint32_t RasterizerStorageRD::reflection_probe_get_cull_mask(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
-
- return reflection_probe->cull_mask;
-}
-
-Vector3 RasterizerStorageRD::reflection_probe_get_extents(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, Vector3());
-
- return reflection_probe->extents;
-}
-Vector3 RasterizerStorageRD::reflection_probe_get_origin_offset(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, Vector3());
-
- return reflection_probe->origin_offset;
-}
-
-bool RasterizerStorageRD::reflection_probe_renders_shadows(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, false);
-
- return reflection_probe->enable_shadows;
-}
-
-float RasterizerStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
-
- return reflection_probe->max_distance;
-}
-
-int RasterizerStorageRD::reflection_probe_get_resolution(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
-
- return reflection_probe->resolution;
-}
-
-float RasterizerStorageRD::reflection_probe_get_intensity(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
-
- return reflection_probe->intensity;
-}
-bool RasterizerStorageRD::reflection_probe_is_interior(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, false);
-
- return reflection_probe->interior;
-}
-bool RasterizerStorageRD::reflection_probe_is_box_projection(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, false);
-
- return reflection_probe->box_projection;
-}
-
-Color RasterizerStorageRD::reflection_probe_get_interior_ambient(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, Color());
-
- return reflection_probe->interior_ambient;
-}
-float RasterizerStorageRD::reflection_probe_get_interior_ambient_energy(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
-
- return reflection_probe->interior_ambient_energy;
-}
-float RasterizerStorageRD::reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const {
-
- const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
- ERR_FAIL_COND_V(!reflection_probe, 0);
-
- return reflection_probe->interior_ambient_probe_contrib;
-}
-
-RID RasterizerStorageRD::gi_probe_create() {
-
- return gi_probe_owner.make_rid(GIProbe());
-}
-
-void RasterizerStorageRD::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) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- if (gi_probe->octree_buffer.is_valid()) {
- RD::get_singleton()->free(gi_probe->octree_buffer);
- RD::get_singleton()->free(gi_probe->data_buffer);
- if (gi_probe->sdf_texture.is_valid()) {
- RD::get_singleton()->free(gi_probe->sdf_texture);
- }
-
- gi_probe->sdf_texture = RID();
- gi_probe->octree_buffer = RID();
- gi_probe->data_buffer = RID();
- gi_probe->octree_buffer_size = 0;
- gi_probe->data_buffer_size = 0;
- gi_probe->cell_count = 0;
- }
-
- gi_probe->to_cell_xform = p_to_cell_xform;
- gi_probe->bounds = p_aabb;
- gi_probe->octree_size = p_octree_size;
- gi_probe->level_counts = p_level_counts;
-
- if (p_octree_cells.size()) {
- ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32
-
- uint32_t cell_count = p_octree_cells.size() / 32;
-
- ERR_FAIL_COND(p_data_cells.size() != (int)cell_count * 16); //see that data size matches
-
- gi_probe->cell_count = cell_count;
- gi_probe->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells);
- gi_probe->octree_buffer_size = p_octree_cells.size();
- gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells);
- gi_probe->data_buffer_size = p_data_cells.size();
-
- if (p_distance_field.size()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = gi_probe->octree_size.x;
- tf.height = gi_probe->octree_size.y;
- tf.depth = gi_probe->octree_size.z;
- tf.type = RD::TEXTURE_TYPE_3D;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- Vector<Vector<uint8_t> > s;
- s.push_back(p_distance_field);
- gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s);
- }
-#if 0
- {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = gi_probe->octree_size.x;
- tf.height = gi_probe->octree_size.y;
- tf.depth = gi_probe->octree_size.z;
- tf.type = RD::TEXTURE_TYPE_3D;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM);
- tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT);
- gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
- RID shared_tex;
- {
-
- RD::TextureView tv;
- tv.format_override = RD::DATA_FORMAT_R8_UINT;
- shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture);
- }
- //update SDF texture
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 1;
- u.ids.push_back(gi_probe->octree_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 2;
- u.ids.push_back(gi_probe->data_buffer);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 3;
- u.ids.push_back(shared_tex);
- uniforms.push_back(u);
- }
-
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0);
-
- {
- uint32_t push_constant[4] = { 0, 0, 0, 0 };
-
- for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) {
- push_constant[0] += gi_probe->level_counts[i];
- }
- push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1];
-
- print_line("offset: " + itos(push_constant[0]));
- print_line("size: " + itos(push_constant[1]));
- //create SDF
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
- RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4);
- RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4);
- RD::get_singleton()->compute_list_end();
- }
-
- RD::get_singleton()->free(uniform_set);
- RD::get_singleton()->free(shared_tex);
- }
-#endif
- }
-
- gi_probe->version++;
- gi_probe->data_version++;
-
- gi_probe->instance_dependency.instance_notify_changed(true, false);
-}
-
-AABB RasterizerStorageRD::gi_probe_get_bounds(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, AABB());
-
- return gi_probe->bounds;
-}
-
-Vector3i RasterizerStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector3i());
- return gi_probe->octree_size;
-}
-Vector<uint8_t> RasterizerStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
-
- if (gi_probe->octree_buffer.is_valid()) {
- return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer);
- }
- return Vector<uint8_t>();
-}
-Vector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
-
- if (gi_probe->data_buffer.is_valid()) {
- return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer);
- }
- return Vector<uint8_t>();
-}
-Vector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>());
-
- if (gi_probe->data_buffer.is_valid()) {
- return RD::get_singleton()->texture_get_data(gi_probe->sdf_texture, 0);
- }
- return Vector<uint8_t>();
-}
-Vector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Vector<int>());
-
- return gi_probe->level_counts;
-}
-Transform RasterizerStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, Transform());
-
- return gi_probe->to_cell_xform;
-}
-
-void RasterizerStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->dynamic_range = p_range;
- gi_probe->version++;
-}
-float RasterizerStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
-
- return gi_probe->dynamic_range;
-}
-
-void RasterizerStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->propagation = p_range;
- gi_probe->version++;
-}
-float RasterizerStorageRD::gi_probe_get_propagation(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->propagation;
-}
-
-void RasterizerStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->energy = p_energy;
-}
-float RasterizerStorageRD::gi_probe_get_energy(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->energy;
-}
-
-void RasterizerStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->ao = p_ao;
-}
-float RasterizerStorageRD::gi_probe_get_ao(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->ao;
-}
-
-void RasterizerStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) {
-
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->ao_size = p_strength;
-}
-
-float RasterizerStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->ao_size;
-}
-
-void RasterizerStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->bias = p_bias;
-}
-float RasterizerStorageRD::gi_probe_get_bias(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->bias;
-}
-
-void RasterizerStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->normal_bias = p_normal_bias;
-}
-float RasterizerStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->normal_bias;
-}
-
-void RasterizerStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) {
-
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->anisotropy_strength = p_strength;
-}
-
-float RasterizerStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->anisotropy_strength;
-}
-
-void RasterizerStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->interior = p_enable;
-}
-
-void RasterizerStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND(!gi_probe);
-
- gi_probe->use_two_bounces = p_enable;
- gi_probe->version++;
-}
-
-bool RasterizerStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, false);
- return gi_probe->use_two_bounces;
-}
-
-bool RasterizerStorageRD::gi_probe_is_interior(RID p_gi_probe) const {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->interior;
-}
-
-uint32_t RasterizerStorageRD::gi_probe_get_version(RID p_gi_probe) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->version;
-}
-
-uint32_t RasterizerStorageRD::gi_probe_get_data_version(RID p_gi_probe) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, 0);
- return gi_probe->data_version;
-}
-
-RID RasterizerStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const {
-
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
- return gi_probe->octree_buffer;
-}
-RID RasterizerStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const {
-
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
- return gi_probe->data_buffer;
-}
-
-RID RasterizerStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) {
- GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe);
- ERR_FAIL_COND_V(!gi_probe, RID());
-
- return gi_probe->sdf_texture;
-}
-
-/* RENDER TARGET API */
-
-void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
-
- //free in reverse dependency order
- if (rt->framebuffer.is_valid()) {
- RD::get_singleton()->free(rt->framebuffer);
- }
-
- if (rt->color.is_valid()) {
- RD::get_singleton()->free(rt->color);
- }
-
- if (rt->backbuffer.is_valid()) {
- RD::get_singleton()->free(rt->backbuffer);
- rt->backbuffer = RID();
- rt->backbuffer_fb = RID();
- for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) {
- //just erase copies, since the rest are erased by dependency
- RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy);
- }
- rt->backbuffer_mipmaps.clear();
- if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) {
- RD::get_singleton()->free(rt->backbuffer_uniform_set);
- }
- rt->backbuffer_uniform_set = RID();
- }
-
- rt->framebuffer = RID();
- rt->color = RID();
-}
-
-void RasterizerStorageRD::_update_render_target(RenderTarget *rt) {
-
- if (rt->texture.is_null()) {
- //create a placeholder until updated
- rt->texture = texture_2d_placeholder_create();
- Texture *tex = texture_owner.getornull(rt->texture);
- tex->is_render_target = true;
- }
-
- _clear_render_target(rt);
-
- if (rt->size.width == 0 || rt->size.height == 0) {
- return;
- }
- //until we implement support for HDR monitors (and render target is attached to screen), this is enough.
- rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
- rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
-
- RD::TextureFormat rd_format;
- RD::TextureView rd_view;
- { //attempt register
- rd_format.format = rt->color_format;
- rd_format.width = rt->size.width;
- rd_format.height = rt->size.height;
- rd_format.depth = 1;
- rd_format.array_layers = 1;
- rd_format.mipmaps = 1;
- rd_format.type = RD::TEXTURE_TYPE_2D;
- rd_format.samples = RD::TEXTURE_SAMPLES_1;
- rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
- rd_format.shareable_formats.push_back(rt->color_format);
- rd_format.shareable_formats.push_back(rt->color_format_srgb);
- }
-
- rt->color = RD::get_singleton()->texture_create(rd_format, rd_view);
- ERR_FAIL_COND(rt->color.is_null());
-
- Vector<RID> fb_textures;
- fb_textures.push_back(rt->color);
- rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures);
- if (rt->framebuffer.is_null()) {
- _clear_render_target(rt);
- ERR_FAIL_COND(rt->framebuffer.is_null());
- }
-
- { //update texture
-
- Texture *tex = texture_owner.getornull(rt->texture);
-
- //free existing textures
- if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
- RD::get_singleton()->free(tex->rd_texture);
- }
- if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
- RD::get_singleton()->free(tex->rd_texture_srgb);
- }
-
- tex->rd_texture = RID();
- tex->rd_texture_srgb = RID();
-
- //create shared textures to the color buffer,
- //so transparent can be supported
- RD::TextureView view;
- view.format_override = rt->color_format;
- if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
- view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
- }
- tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color);
- if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
- view.format_override = rt->color_format_srgb;
- tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color);
- }
- tex->rd_view = view;
- tex->width = rt->size.width;
- tex->height = rt->size.height;
- tex->width_2d = rt->size.width;
- tex->height_2d = rt->size.height;
- tex->rd_format = rt->color_format;
- tex->rd_format_srgb = rt->color_format_srgb;
- tex->format = rt->image_format;
-
- Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
- for (int i = 0; i < proxies.size(); i++) {
- texture_proxy_update(proxies[i], rt->texture);
- }
- }
-}
-
-void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) {
- ERR_FAIL_COND(rt->backbuffer.is_valid());
-
- uint32_t mipmaps_required = Image::get_image_required_mipmaps(rt->size.width, rt->size.height, Image::FORMAT_RGBA8);
- RD::TextureFormat tf;
- tf.format = rt->color_format;
- tf.width = rt->size.width;
- tf.height = rt->size.height;
- tf.type = RD::TEXTURE_TYPE_2D;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
- tf.mipmaps = mipmaps_required;
-
- rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
- {
- Vector<RID> backbuffer_att;
- RID backbuffer_fb_tex = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0);
- backbuffer_att.push_back(backbuffer_fb_tex);
- rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(backbuffer_att);
- }
-
- //create mipmaps
- for (uint32_t i = 1; i < mipmaps_required; i++) {
-
- RenderTarget::BackbufferMipmap mm;
- {
- mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i);
- Vector<RID> mm_fb_at;
- mm_fb_at.push_back(mm.mipmap);
- mm.mipmap_fb = RD::get_singleton()->framebuffer_create(mm_fb_at);
- }
-
- {
- Size2 mm_size = Image::get_image_mipmap_size(tf.width, tf.height, Image::FORMAT_RGBA8, i);
-
- RD::TextureFormat mmtf = tf;
- mmtf.width = mm_size.width;
- mmtf.height = mm_size.height;
- mmtf.mipmaps = 1;
-
- mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView());
- Vector<RID> mm_fb_at;
- mm_fb_at.push_back(mm.mipmap_copy);
- mm.mipmap_copy_fb = RD::get_singleton()->framebuffer_create(mm_fb_at);
- }
-
- rt->backbuffer_mipmaps.push_back(mm);
- }
-}
-
-RID RasterizerStorageRD::render_target_create() {
- RenderTarget render_target;
-
- render_target.was_used = false;
- render_target.clear_requested = false;
-
- for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
- render_target.flags[i] = false;
- }
- _update_render_target(&render_target);
- return render_target_owner.make_rid(render_target);
-}
-
-void RasterizerStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) {
- //unused for this render target
-}
-
-void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->size.x = p_width;
- rt->size.y = p_height;
- _update_render_target(rt);
-}
-
-RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
-
- return rt->texture;
-}
-
-void RasterizerStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
-}
-
-void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->flags[p_flag] = p_value;
- _update_render_target(rt);
-}
-
-bool RasterizerStorageRD::render_target_was_used(RID p_render_target) {
-
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
- return rt->was_used;
-}
-
-void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) {
-
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->was_used = false;
-}
-
-Size2 RasterizerStorageRD::render_target_get_size(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2());
-
- return rt->size;
-}
-
-RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
-
- return rt->framebuffer;
-}
-
-void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->clear_requested = true;
- rt->clear_color = p_clear_color;
-}
-
-bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
- return rt->clear_requested;
-}
-
-Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) {
-
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, Color());
- return rt->clear_color;
-}
-
-void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) {
-
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- rt->clear_requested = false;
-}
-
-void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) {
-
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- if (!rt->clear_requested) {
- return;
- }
- Vector<Color> clear_colors;
- clear_colors.push_back(rt->clear_color);
- RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
- RD::get_singleton()->draw_list_end();
- rt->clear_requested = false;
-}
-
-void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND(!rt);
- if (!rt->backbuffer.is_valid()) {
- _create_render_target_backbuffer(rt);
- }
-
- Rect2i region = p_region;
- Rect2 blur_region;
- if (region == Rect2i()) {
- region.size = rt->size;
- } else {
- blur_region = region;
- blur_region.position /= rt->size;
- blur_region.size /= rt->size;
- }
-
- //single texture copy for backbuffer
- RD::get_singleton()->texture_copy(rt->color, rt->backbuffer, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true);
- //effects.copy(rt->color, rt->backbuffer_fb, blur_region);
-
- //then mipmap blur
- RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps.
- Vector2 pixel_size = Vector2(1.0 / rt->size.width, 1.0 / rt->size.height);
-
- for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) {
- pixel_size *= 2.0; //go halfway
- const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i];
- effects.gaussian_blur(prev_texture, mm.mipmap_copy_fb, mm.mipmap_copy, mm.mipmap_fb, pixel_size, blur_region);
- prev_texture = mm.mipmap;
- }
-}
-
-RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader) {
- RenderTarget *rt = render_target_owner.getornull(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
-
- if (!rt->backbuffer.is_valid()) {
- _create_render_target_backbuffer(rt);
- }
-
- if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) {
- return rt->backbuffer_uniform_set; //if still valid, return/reuse it.
- }
-
- //create otherwise
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 0;
- u.ids.push_back(rt->backbuffer);
- uniforms.push_back(u);
-
- rt->backbuffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, 3);
- ERR_FAIL_COND_V(!rt->backbuffer_uniform_set.is_valid(), RID());
-
- return rt->backbuffer_uniform_set;
-}
-
-void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
- if (mesh_owner.owns(p_base)) {
- Mesh *mesh = mesh_owner.getornull(p_base);
- p_instance->update_dependency(&mesh->instance_dependency);
- } else if (multimesh_owner.owns(p_base)) {
-
- MultiMesh *multimesh = multimesh_owner.getornull(p_base);
- p_instance->update_dependency(&multimesh->instance_dependency);
- if (multimesh->mesh.is_valid()) {
- base_update_dependency(multimesh->mesh, p_instance);
- }
- } else if (reflection_probe_owner.owns(p_base)) {
- ReflectionProbe *rp = reflection_probe_owner.getornull(p_base);
- p_instance->update_dependency(&rp->instance_dependency);
- } else if (gi_probe_owner.owns(p_base)) {
- GIProbe *gip = gi_probe_owner.getornull(p_base);
- p_instance->update_dependency(&gip->instance_dependency);
- } else if (light_owner.owns(p_base)) {
- Light *l = light_owner.getornull(p_base);
- p_instance->update_dependency(&l->instance_dependency);
- }
-}
-
-void RasterizerStorageRD::skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
-
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
- ERR_FAIL_COND(!skeleton);
-
- p_instance->update_dependency(&skeleton->instance_dependency);
-}
-
-VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
-
- if (mesh_owner.owns(p_rid)) {
- return VS::INSTANCE_MESH;
- }
- if (multimesh_owner.owns(p_rid)) {
- return VS::INSTANCE_MULTIMESH;
- }
- if (reflection_probe_owner.owns(p_rid)) {
- return VS::INSTANCE_REFLECTION_PROBE;
- }
- if (gi_probe_owner.owns(p_rid)) {
- return VS::INSTANCE_GI_PROBE;
- }
- if (light_owner.owns(p_rid)) {
- return VS::INSTANCE_LIGHT;
- }
-
- return VS::INSTANCE_NONE;
-}
-void RasterizerStorageRD::update_dirty_resources() {
- _update_queued_materials();
- _update_dirty_multimeshes();
- _update_dirty_skeletons();
-}
-
-bool RasterizerStorageRD::has_os_feature(const String &p_feature) const {
-
- if (p_feature == "rgtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
- return true;
- }
-
- if (p_feature == "s3tc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
- return true;
- }
-
- if (p_feature == "bptc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
- return true;
- }
-
- if ((p_feature == "etc" || p_feature == "etc2") && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
- return true;
- }
-
- if (p_feature == "pvrtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
- return true;
- }
-
- return false;
-}
-bool RasterizerStorageRD::free(RID p_rid) {
-
- if (texture_owner.owns(p_rid)) {
- Texture *t = texture_owner.getornull(p_rid);
-
- ERR_FAIL_COND_V(t->is_render_target, false);
-
- if (RD::get_singleton()->texture_is_valid(t->rd_texture_srgb)) {
- //erase this first, as it's a dependency of the one below
- RD::get_singleton()->free(t->rd_texture_srgb);
- }
- if (RD::get_singleton()->texture_is_valid(t->rd_texture)) {
- RD::get_singleton()->free(t->rd_texture);
- }
-
- if (t->is_proxy && t->proxy_to.is_valid()) {
- Texture *proxy_to = texture_owner.getornull(t->proxy_to);
- if (proxy_to) {
- proxy_to->proxies.erase(p_rid);
- }
- }
-
- for (int i = 0; i < t->proxies.size(); i++) {
- Texture *p = texture_owner.getornull(t->proxies[i]);
- ERR_CONTINUE(!p);
- p->proxy_to = RID();
- p->rd_texture = RID();
- p->rd_texture_srgb = RID();
- }
- texture_owner.free(p_rid);
-
- } else if (shader_owner.owns(p_rid)) {
- Shader *shader = shader_owner.getornull(p_rid);
- //make material unreference this
- while (shader->owners.size()) {
- material_set_shader(shader->owners.front()->get()->self, RID());
- }
- //clear data if exists
- if (shader->data) {
- memdelete(shader->data);
- }
- shader_owner.free(p_rid);
-
- } else if (material_owner.owns(p_rid)) {
- Material *material = material_owner.getornull(p_rid);
- if (material->update_requested) {
- _update_queued_materials();
- }
- material_set_shader(p_rid, RID()); //clean up shader
- material->instance_dependency.instance_notify_deleted(p_rid);
- material_owner.free(p_rid);
- } else if (mesh_owner.owns(p_rid)) {
- mesh_clear(p_rid);
- Mesh *mesh = mesh_owner.getornull(p_rid);
- mesh->instance_dependency.instance_notify_deleted(p_rid);
- mesh_owner.free(p_rid);
- } else if (multimesh_owner.owns(p_rid)) {
- _update_dirty_multimeshes();
- multimesh_allocate(p_rid, 0, VS::MULTIMESH_TRANSFORM_2D);
- MultiMesh *multimesh = multimesh_owner.getornull(p_rid);
- multimesh->instance_dependency.instance_notify_deleted(p_rid);
- multimesh_owner.free(p_rid);
- } else if (skeleton_owner.owns(p_rid)) {
- _update_dirty_skeletons();
- skeleton_allocate(p_rid, 0);
- Skeleton *skeleton = skeleton_owner.getornull(p_rid);
- skeleton->instance_dependency.instance_notify_deleted(p_rid);
- skeleton_owner.free(p_rid);
- } else if (reflection_probe_owner.owns(p_rid)) {
- ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid);
- reflection_probe->instance_dependency.instance_notify_deleted(p_rid);
- reflection_probe_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
- GIProbe *gi_probe = gi_probe_owner.getornull(p_rid);
- gi_probe->instance_dependency.instance_notify_deleted(p_rid);
- gi_probe_owner.free(p_rid);
-
- } else if (light_owner.owns(p_rid)) {
-
- // delete the texture
- Light *light = light_owner.getornull(p_rid);
- light->instance_dependency.instance_notify_deleted(p_rid);
- light_owner.free(p_rid);
-
- } else if (render_target_owner.owns(p_rid)) {
- RenderTarget *rt = render_target_owner.getornull(p_rid);
-
- _clear_render_target(rt);
-
- if (rt->texture.is_valid()) {
- Texture *tex = texture_owner.getornull(rt->texture);
- tex->is_render_target = false;
- free(rt->texture);
- }
-
- render_target_owner.free(p_rid);
- } else {
- return false;
- }
-
- return true;
-}
-
-RasterizerEffectsRD *RasterizerStorageRD::get_effects() {
- return &effects;
-}
-
-void RasterizerStorageRD::capture_timestamps_begin() {
- RD::get_singleton()->capture_timestamp("Frame Begin", false);
-}
-
-void RasterizerStorageRD::capture_timestamp(const String &p_name) {
- RD::get_singleton()->capture_timestamp(p_name, true);
-}
-
-uint32_t RasterizerStorageRD::get_captured_timestamps_count() const {
- return RD::get_singleton()->get_captured_timestamps_count();
-}
-uint64_t RasterizerStorageRD::get_captured_timestamps_frame() const {
- return RD::get_singleton()->get_captured_timestamps_frame();
-}
-
-uint64_t RasterizerStorageRD::get_captured_timestamp_gpu_time(uint32_t p_index) const {
- return RD::get_singleton()->get_captured_timestamp_gpu_time(p_index);
-}
-uint64_t RasterizerStorageRD::get_captured_timestamp_cpu_time(uint32_t p_index) const {
- return RD::get_singleton()->get_captured_timestamp_cpu_time(p_index);
-}
-String RasterizerStorageRD::get_captured_timestamp_name(uint32_t p_index) const {
- return RD::get_singleton()->get_captured_timestamp_name(p_index);
-}
-
-RasterizerStorageRD::RasterizerStorageRD() {
-
- for (int i = 0; i < SHADER_TYPE_MAX; i++) {
- shader_data_request_func[i] = NULL;
- }
-
- material_update_list = NULL;
- { //create default textures
-
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tformat.width = 4;
- tformat.height = 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- tformat.type = RD::TEXTURE_TYPE_2D;
-
- Vector<uint8_t> pv;
- pv.resize(16 * 4);
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 255);
- pv.set(i * 4 + 1, 255);
- pv.set(i * 4 + 2, 255);
- pv.set(i * 4 + 3, 255);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_rd_textures[DEFAULT_RD_TEXTURE_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
-
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 255);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
-
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 128);
- pv.set(i * 4 + 1, 128);
- pv.set(i * 4 + 2, 255);
- pv.set(i * 4 + 3, 255);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_rd_textures[DEFAULT_RD_TEXTURE_NORMAL] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
-
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 255);
- pv.set(i * 4 + 1, 128);
- pv.set(i * 4 + 2, 255);
- pv.set(i * 4 + 3, 255);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_rd_textures[DEFAULT_RD_TEXTURE_ANISO] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
-
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 0);
- }
-
- default_rd_textures[DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER] = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
- }
-
- { //create default cubemap
-
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tformat.width = 4;
- tformat.height = 4;
- tformat.array_layers = 6;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- tformat.type = RD::TEXTURE_TYPE_CUBE_ARRAY;
-
- Vector<uint8_t> pv;
- pv.resize(16 * 4);
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 0);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- for (int i = 0; i < 6; i++) {
- vpv.push_back(pv);
- }
- default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
- }
-
- { //create default cubemap array
-
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tformat.width = 4;
- tformat.height = 4;
- tformat.array_layers = 6;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- tformat.type = RD::TEXTURE_TYPE_CUBE;
-
- Vector<uint8_t> pv;
- pv.resize(16 * 4);
- for (int i = 0; i < 16; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 0);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- for (int i = 0; i < 6; i++) {
- vpv.push_back(pv);
- }
- default_rd_textures[DEFAULT_RD_TEXTURE_CUBEMAP_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
- }
-
- { //create default 3D
-
- RD::TextureFormat tformat;
- tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
- tformat.width = 4;
- tformat.height = 4;
- tformat.depth = 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
- tformat.type = RD::TEXTURE_TYPE_3D;
-
- Vector<uint8_t> pv;
- pv.resize(64 * 4);
- for (int i = 0; i < 64; i++) {
- pv.set(i * 4 + 0, 0);
- pv.set(i * 4 + 1, 0);
- pv.set(i * 4 + 2, 0);
- pv.set(i * 4 + 3, 0);
- }
-
- {
- Vector<Vector<uint8_t> > vpv;
- vpv.push_back(pv);
- default_rd_textures[DEFAULT_RD_TEXTURE_3D_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
- }
- }
-
- //default samplers
- for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::SamplerState sampler_state;
- switch (i) {
- case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.max_lod = 0;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
-
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.max_lod = 0;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
-
- } break;
- case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
- sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- 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 = GLOBAL_GET("rendering/quality/filters/max_anisotropy");
- } break;
- case VS::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 = GLOBAL_GET("rendering/quality/filters/max_anisotropy");
-
- } break;
- default: {
- }
- }
- switch (j) {
- case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
-
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
-
- } break;
- case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
- } break;
- case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
- sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
- } break;
- default: {
- }
- }
-
- default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
- }
- }
-
- //default rd buffers
- {
-
- { //vertex
-
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 3);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_VERTEX] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-
-{ //normal
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 3);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 1.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_NORMAL] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-
-{ //tangent
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 4);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 1.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- fptr[3] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TANGENT] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-
-{ //color
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 4);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 1.0;
- fptr[1] = 1.0;
- fptr[2] = 1.0;
- fptr[3] = 1.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_COLOR] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-
-{ //tex uv 1
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 2);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-{ //tex uv 2
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 2);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_TEX_UV2] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-
-{ //bones
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(uint32_t) * 4);
- {
- uint8_t *w = buffer.ptrw();
- uint32_t *fptr = (uint32_t *)w;
- fptr[0] = 0;
- fptr[1] = 0;
- fptr[2] = 0;
- fptr[3] = 0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_BONES] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-
-{ //weights
- Vector<uint8_t> buffer;
- buffer.resize(sizeof(float) * 4);
- {
- uint8_t *w = buffer.ptrw();
- float *fptr = (float *)w;
- fptr[0] = 0.0;
- fptr[1] = 0.0;
- fptr[2] = 0.0;
- fptr[3] = 0.0;
- }
- mesh_default_rd_buffers[DEFAULT_RD_BUFFER_WEIGHTS] = RD::get_singleton()->vertex_buffer_create(buffer.size(), buffer);
-}
-}
-
-{
- Vector<String> sdf_versions;
- 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);
-}
-}
-
-RasterizerStorageRD::~RasterizerStorageRD() {
-
- //def textures
- for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) {
- RD::get_singleton()->free(default_rd_textures[i]);
- }
-
- //def samplers
- for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
- for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
- RD::get_singleton()->free(default_rd_samplers[i][j]);
- }
- }
-
- //def buffers
- for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) {
- RD::get_singleton()->free(mesh_default_rd_buffers[i]);
- }
- giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
-}
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
deleted file mode 100644
index 48097ffaac..0000000000
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h
+++ /dev/null
@@ -1,1134 +0,0 @@
-/*************************************************************************/
-/* rasterizer_storage_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RASTERIZER_STORAGE_RD_H
-#define RASTERIZER_STORAGE_RD_H
-
-#include "core/rid_owner.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual/rasterizer_rd/rasterizer_effects_rd.h"
-#include "servers/visual/rasterizer_rd/shader_compiler_rd.h"
-#include "servers/visual/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
-#include "servers/visual/rendering_device.h"
-
-class RasterizerStorageRD : public RasterizerStorage {
-public:
- enum ShaderType {
- SHADER_TYPE_2D,
- SHADER_TYPE_3D,
- SHADER_TYPE_PARTICLES,
- SHADER_TYPE_MAX
- };
-
- struct ShaderData {
- virtual void set_code(const String &p_Code) = 0;
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0;
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
- virtual bool is_param_texture(const StringName &p_param) const = 0;
- virtual bool is_animated() const = 0;
- virtual bool casts_shadows() const = 0;
- virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
- virtual ~ShaderData() {}
- };
-
- typedef ShaderData *(*ShaderDataRequestFunction)();
-
- struct MaterialData {
-
- void update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
- void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
-
- virtual void set_render_priority(int p_priority) = 0;
- virtual void set_next_pass(RID p_pass) = 0;
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
- virtual ~MaterialData() {}
- };
- typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
-
- enum DefaultRDTexture {
- DEFAULT_RD_TEXTURE_WHITE,
- DEFAULT_RD_TEXTURE_BLACK,
- DEFAULT_RD_TEXTURE_NORMAL,
- DEFAULT_RD_TEXTURE_ANISO,
- DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER,
- DEFAULT_RD_TEXTURE_CUBEMAP_BLACK,
- DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK,
- DEFAULT_RD_TEXTURE_3D_WHITE,
- DEFAULT_RD_TEXTURE_MAX
- };
-
- enum DefaultRDBuffer {
- DEFAULT_RD_BUFFER_VERTEX,
- DEFAULT_RD_BUFFER_NORMAL,
- DEFAULT_RD_BUFFER_TANGENT,
- DEFAULT_RD_BUFFER_COLOR,
- DEFAULT_RD_BUFFER_TEX_UV,
- DEFAULT_RD_BUFFER_TEX_UV2,
- DEFAULT_RD_BUFFER_BONES,
- DEFAULT_RD_BUFFER_WEIGHTS,
- DEFAULT_RD_BUFFER_MAX,
- };
-
-private:
- /* TEXTURE API */
- struct Texture {
-
- enum Type {
- TYPE_2D,
- TYPE_LAYERED,
- TYPE_3D
- };
-
- Type type;
-
- RenderingDevice::TextureType rd_type;
- RID rd_texture;
- RID rd_texture_srgb;
- RenderingDevice::DataFormat rd_format;
- RenderingDevice::DataFormat rd_format_srgb;
-
- RD::TextureView rd_view;
-
- Image::Format format;
- Image::Format validated_format;
-
- int width;
- int height;
- int depth;
- int layers;
- int mipmaps;
-
- int height_2d;
- int width_2d;
-
- bool is_render_target;
- bool is_proxy;
-
- Ref<Image> image_cache_2d;
- String path;
-
- RID proxy_to;
- Vector<RID> proxies;
-
- VS::TextureDetectCallback detect_3d_callback = nullptr;
- void *detect_3d_callback_ud = nullptr;
-
- VS::TextureDetectCallback detect_normal_callback = nullptr;
- void *detect_normal_callback_ud = nullptr;
-
- VS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;
- void *detect_roughness_callback_ud = nullptr;
- };
-
- struct TextureToRDFormat {
- RD::DataFormat format;
- RD::DataFormat format_srgb;
- RD::TextureSwizzle swizzle_r;
- RD::TextureSwizzle swizzle_g;
- RD::TextureSwizzle swizzle_b;
- RD::TextureSwizzle swizzle_a;
- TextureToRDFormat() {
- format = RD::DATA_FORMAT_MAX;
- format_srgb = RD::DATA_FORMAT_MAX;
- swizzle_r = RD::TEXTURE_SWIZZLE_R;
- swizzle_g = RD::TEXTURE_SWIZZLE_G;
- swizzle_b = RD::TEXTURE_SWIZZLE_B;
- swizzle_a = RD::TEXTURE_SWIZZLE_A;
- }
- };
-
- //textures can be created from threads, so this RID_Owner is thread safe
- mutable RID_Owner<Texture, true> texture_owner;
-
- Ref<Image> _validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format);
-
- RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
- RID default_rd_samplers[VS::CANVAS_ITEM_TEXTURE_FILTER_MAX][VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
-
- /* SHADER */
-
- struct Material;
-
- struct Shader {
- ShaderData *data;
- String code;
- ShaderType type;
- Map<StringName, RID> default_texture_parameter;
- Set<Material *> owners;
- };
-
- ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX];
- mutable RID_Owner<Shader> shader_owner;
-
- /* Material */
-
- struct Material {
- RID self;
- MaterialData *data;
- Shader *shader;
- //shortcut to shader data and type
- ShaderType shader_type;
- bool update_requested;
- bool uniform_dirty;
- bool texture_dirty;
- Material *update_next;
- Map<StringName, Variant> params;
- int32_t priority;
- RID next_pass;
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
- mutable RID_Owner<Material> material_owner;
-
- Material *material_update_list;
- void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
- void _update_queued_materials();
-
- /* Mesh */
-
- struct Mesh {
-
- struct Surface {
- VS::PrimitiveType primitive;
- uint32_t format = 0;
-
- RID vertex_buffer;
- uint32_t vertex_count = 0;
-
- // A different pipeline needs to be allocated
- // depending on the inputs available in the
- // material.
- // There are never that many geometry/material
- // combinations, so a simple array is the most
- // cache-efficient structure.
-
- struct Version {
- uint32_t input_mask;
- RD::VertexFormatID vertex_format;
- RID vertex_array;
- };
-
- SpinLock version_lock; //needed to access versions
- Version *versions = nullptr; //allocated on demand
- uint32_t version_count = 0;
-
- RID index_buffer;
- RID index_array;
- uint32_t index_count = 0;
-
- struct LOD {
- float edge_length;
- RID index_buffer;
- RID index_array;
- };
-
- LOD *lods = nullptr;
- uint32_t lod_count = 0;
-
- AABB aabb;
-
- Vector<AABB> bone_aabbs;
-
- Vector<RID> blend_shapes;
- RID blend_shape_base_buffer; //source buffer goes here when using blend shapes, and main one is uncompressed
-
- RID material;
-
- uint32_t render_index = 0;
- uint64_t render_pass = 0;
-
- uint32_t multimesh_render_index = 0;
- uint64_t multimesh_render_pass = 0;
- };
-
- uint32_t blend_shape_count = 0;
- VS::BlendShapeMode blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED;
-
- Surface **surfaces = nullptr;
- uint32_t surface_count = 0;
-
- Vector<AABB> bone_aabbs;
-
- AABB aabb;
- AABB custom_aabb;
-
- Vector<RID> material_cache;
-
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- mutable RID_Owner<Mesh> mesh_owner;
-
- void _mesh_surface_generate_version_for_input_mask(Mesh::Surface *s, uint32_t p_input_mask);
-
- RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
-
- /* MultiMesh */
- struct MultiMesh {
- RID mesh;
- int instances = 0;
- VS::MultimeshTransformFormat xform_format = VS::MULTIMESH_TRANSFORM_3D;
- bool uses_colors = false;
- bool uses_custom_data = false;
- int visible_instances = -1;
- AABB aabb;
- bool aabb_dirty = false;
- bool buffer_set = false;
- uint32_t stride_cache = 0;
- uint32_t color_offset_cache = 0;
- uint32_t custom_data_offset_cache = 0;
-
- Vector<float> data_cache; //used if individual setting is used
- bool *data_cache_dirty_regions = nullptr;
- uint32_t data_cache_used_dirty_regions = 0;
-
- RID buffer; //storage buffer
- RID uniform_set_3d;
-
- bool dirty = false;
- MultiMesh *dirty_list = nullptr;
-
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- mutable RID_Owner<MultiMesh> multimesh_owner;
-
- MultiMesh *multimesh_dirty_list = nullptr;
-
- _FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
- _FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
- _FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
- _FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
- void _update_dirty_multimeshes();
-
- /* Skeleton */
-
- struct Skeleton {
- bool use_2d = false;
- int size = 0;
- Vector<float> data;
- RID buffer;
-
- bool dirty = false;
- Skeleton *dirty_list = nullptr;
- Transform2D base_transform_2d;
-
- RID uniform_set_3d;
-
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- mutable RID_Owner<Skeleton> skeleton_owner;
-
- _FORCE_INLINE_ void _skeleton_make_dirty(Skeleton *skeleton);
-
- Skeleton *skeleton_dirty_list = nullptr;
-
- void _update_dirty_skeletons();
-
- /* LIGHT */
-
- struct Light {
-
- VS::LightType type;
- float param[VS::LIGHT_PARAM_MAX];
- Color color = Color(1, 1, 1, 1);
- Color shadow_color;
- RID projector;
- bool shadow = false;
- bool negative = false;
- bool reverse_cull = false;
- bool use_gi = true;
- uint32_t cull_mask = 0xFFFFFFFF;
- VS::LightOmniShadowMode omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
- VS::LightDirectionalShadowMode directional_shadow_mode = VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
- VS::LightDirectionalShadowDepthRangeMode directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
- bool directional_blend_splits = false;
- uint64_t version = 0;
-
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- mutable RID_Owner<Light> light_owner;
-
- /* REFLECTION PROBE */
-
- struct ReflectionProbe {
-
- VS::ReflectionProbeUpdateMode update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE;
- int resolution = 256;
- float intensity = 1.0;
- Color interior_ambient;
- float interior_ambient_energy = 1.0;
- float interior_ambient_probe_contrib = 0.0;
- float max_distance = 0;
- Vector3 extents = Vector3(1, 1, 1);
- Vector3 origin_offset;
- bool interior = false;
- bool box_projection = false;
- bool enable_shadows = false;
- uint32_t cull_mask = (1 << 20) - 1;
-
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
-
- /* GI PROBE */
-
- struct GIProbe {
-
- RID octree_buffer;
- RID data_buffer;
- RID sdf_texture;
-
- uint32_t octree_buffer_size = 0;
- uint32_t data_buffer_size = 0;
-
- Vector<int> level_counts;
-
- int cell_count = 0;
-
- Transform to_cell_xform;
- AABB bounds;
- Vector3i octree_size;
-
- float dynamic_range = 4.0;
- float energy = 1.0;
- float ao = 0.0;
- float ao_size = 0.5;
- float bias = 1.4;
- float normal_bias = 0.0;
- float propagation = 0.7;
- bool interior = false;
- bool use_two_bounces = false;
-
- float anisotropy_strength = 0.5;
-
- uint32_t version = 1;
- uint32_t data_version = 1;
-
- RasterizerScene::InstanceDependency instance_dependency;
- };
-
- GiprobeSdfShaderRD giprobe_sdf_shader;
- RID giprobe_sdf_shader_version;
- RID giprobe_sdf_shader_version_shader;
- RID giprobe_sdf_shader_pipeline;
-
- mutable RID_Owner<GIProbe> gi_probe_owner;
-
- /* RENDER TARGET */
-
- struct RenderTarget {
-
- Size2i size;
- RID framebuffer;
- RID color;
-
- //used for retrieving from CPU
- RD::DataFormat color_format;
- RD::DataFormat color_format_srgb;
- Image::Format image_format;
-
- bool flags[RENDER_TARGET_FLAG_MAX];
-
- RID backbuffer; //used for effects
- RID backbuffer_fb;
-
- struct BackbufferMipmap {
- RID mipmap;
- RID mipmap_fb;
- RID mipmap_copy;
- RID mipmap_copy_fb;
- };
-
- Vector<BackbufferMipmap> backbuffer_mipmaps;
- RID backbuffer_uniform_set;
-
- //texture generated for this owner (nor RD).
- RID texture;
- bool was_used;
-
- //clear request
- bool clear_requested;
- Color clear_color;
- };
-
- RID_Owner<RenderTarget> render_target_owner;
-
- void _clear_render_target(RenderTarget *rt);
- void _update_render_target(RenderTarget *rt);
- void _create_render_target_backbuffer(RenderTarget *rt);
-
- /* EFFECTS */
-
- RasterizerEffectsRD effects;
-
-public:
- /* TEXTURE API */
-
- virtual RID texture_2d_create(const Ref<Image> &p_image);
- virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type);
- virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices); //all slices, then all the mipmaps, must be coherent
- virtual RID texture_proxy_create(RID p_base);
-
- virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate);
-
- virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming
- virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
- virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap);
- 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();
- virtual RID texture_3d_placeholder_create();
-
- virtual Ref<Image> texture_2d_get(RID p_texture) const;
- virtual Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const;
- virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const;
-
- virtual void texture_replace(RID p_texture, RID p_by_texture);
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
-
- virtual void texture_set_path(RID p_texture, const String &p_path);
- virtual String texture_get_path(RID p_texture) const;
-
- virtual void texture_set_detect_3d_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata);
- virtual void texture_set_detect_normal_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata);
- virtual void texture_set_detect_roughness_callback(RID p_texture, VS::TextureDetectRoughnessCallback p_callback, void *p_userdata);
-
- virtual void texture_debug_usage(List<VS::TextureInfo> *r_info);
-
- virtual void texture_set_proxy(RID p_proxy, RID p_base);
- virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable);
-
- virtual Size2 texture_size_with_proxy(RID p_proxy);
-
- //internal usage
-
- _FORCE_INLINE_ RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) {
- if (p_texture.is_null()) {
- return RID();
- }
- Texture *tex = texture_owner.getornull(p_texture);
-
- if (!tex) {
- return RID();
- }
- return (p_srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
- }
-
- _FORCE_INLINE_ Size2i texture_2d_get_size(RID p_texture) {
- if (p_texture.is_null()) {
- return Size2i();
- }
- Texture *tex = texture_owner.getornull(p_texture);
-
- if (!tex) {
- return Size2i();
- }
- return Size2i(tex->width_2d, tex->height_2d);
- }
-
- _FORCE_INLINE_ RID texture_rd_get_default(DefaultRDTexture p_texture) {
- return default_rd_textures[p_texture];
- }
- _FORCE_INLINE_ RID sampler_rd_get_default(VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat) {
- return default_rd_samplers[p_filter][p_repeat];
- }
-
- /* SHADER API */
-
- RID shader_create();
-
- void shader_set_code(RID p_shader, const String &p_code);
- String shader_get_code(RID p_shader) const;
- void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
-
- void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture);
- RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const;
- Variant shader_get_param_default(RID p_shader, const StringName &p_param) const;
- void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function);
-
- /* COMMON MATERIAL API */
-
- RID material_create();
-
- void material_set_shader(RID p_material, RID p_shader);
-
- void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value);
- Variant material_get_param(RID p_material, const StringName &p_param) const;
-
- void material_set_next_pass(RID p_material, RID p_next_material);
- void material_set_render_priority(RID p_material, int priority);
-
- bool material_is_animated(RID p_material);
- bool material_casts_shadows(RID p_material);
-
- void material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance);
- void material_force_update_textures(RID p_material, ShaderType p_shader_type);
-
- void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function);
-
- _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) {
- Material *material = material_owner.getornull(p_material);
- if (!material || material->shader_type != p_shader_type) {
- return NULL;
- } else {
- return material->data;
- }
- }
-
- /* MESH API */
-
- virtual RID mesh_create();
-
- /// Return stride
- virtual void mesh_add_surface(RID p_mesh, const VS::SurfaceData &p_surface);
-
- virtual int mesh_get_blend_shape_count(RID p_mesh) const;
-
- virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode);
- virtual VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
-
- virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data);
-
- virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material);
- virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
-
- virtual VS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const;
-
- virtual int mesh_get_surface_count(RID p_mesh) const;
-
- virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb);
- virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
-
- virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID());
-
- virtual void mesh_clear(RID p_mesh);
-
- _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, NULL);
- r_surface_count = mesh->surface_count;
- if (r_surface_count == 0) {
- return NULL;
- }
- if (mesh->material_cache.empty()) {
- mesh->material_cache.resize(mesh->surface_count);
- for (uint32_t i = 0; i < r_surface_count; i++) {
- mesh->material_cache.write[i] = mesh->surfaces[i]->material;
- }
- }
-
- return mesh->material_cache.ptr();
- }
-
- _FORCE_INLINE_ VS::PrimitiveType mesh_surface_get_primitive(RID p_mesh, uint32_t p_surface_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND_V(!mesh, VS::PRIMITIVE_MAX);
- ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, VS::PRIMITIVE_MAX);
-
- return mesh->surfaces[p_surface_index]->primitive;
- }
-
- _FORCE_INLINE_ void mesh_surface_get_arrays_and_format(RID p_mesh, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RID &r_index_array_rd, RD::VertexFormatID &r_vertex_format) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- ERR_FAIL_COND(!mesh);
- ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
-
- Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
- r_index_array_rd = s->index_array;
-
- s->version_lock.lock();
-
- //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
-
- for (uint32_t i = 0; i < s->version_count; i++) {
- if (s->versions[i].input_mask != p_input_mask) {
- continue;
- }
- //we have this version, hooray
- r_vertex_format = s->versions[i].vertex_format;
- r_vertex_array_rd = s->versions[i].vertex_array;
- s->version_lock.unlock();
- return;
- }
-
- uint32_t version = s->version_count; //gets added at the end
-
- _mesh_surface_generate_version_for_input_mask(s, p_input_mask);
-
- r_vertex_format = s->versions[version].vertex_format;
- r_vertex_array_rd = s->versions[version].vertex_array;
-
- s->version_lock.unlock();
- }
-
- _FORCE_INLINE_ RID mesh_get_default_rd_buffer(DefaultRDBuffer p_buffer) {
- ERR_FAIL_INDEX_V(p_buffer, DEFAULT_RD_BUFFER_MAX, RID());
- return mesh_default_rd_buffers[p_buffer];
- }
-
- _FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
- if (s->render_pass != p_render_pass) {
- (*r_index)++;
- s->render_pass = p_render_pass;
- s->render_index = *r_index;
- }
-
- return s->render_index;
- }
-
- _FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
- Mesh *mesh = mesh_owner.getornull(p_mesh);
- Mesh::Surface *s = mesh->surfaces[p_surface_index];
-
- if (s->multimesh_render_pass != p_render_pass) {
- (*r_index)++;
- s->multimesh_render_pass = p_render_pass;
- s->multimesh_render_index = *r_index;
- }
-
- return s->multimesh_render_index;
- }
-
- /* MULTIMESH API */
-
- RID multimesh_create();
-
- void multimesh_allocate(RID p_multimesh, int p_instances, VS::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);
- void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
- void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
- void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
- void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
-
- RID multimesh_get_mesh(RID p_multimesh) const;
-
- Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
- Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
- Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
- Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
-
- void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
- Vector<float> multimesh_get_buffer(RID p_multimesh) const;
-
- void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
- int multimesh_get_visible_instances(RID p_multimesh) const;
-
- AABB multimesh_get_aabb(RID p_multimesh) const;
-
- _FORCE_INLINE_ VS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- return multimesh->xform_format;
- }
-
- _FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- return multimesh->uses_colors;
- }
-
- _FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- return multimesh->uses_custom_data;
- }
-
- _FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- if (multimesh->visible_instances >= 0) {
- return multimesh->visible_instances;
- }
- return multimesh->instances;
- }
-
- _FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const {
- MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
- if (!multimesh->uniform_set_3d.is_valid()) {
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.ids.push_back(multimesh->buffer);
- uniforms.push_back(u);
- multimesh->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
- }
-
- return multimesh->uniform_set_3d;
- }
-
- /* IMMEDIATE API */
-
- RID immediate_create() { return RID(); }
- void immediate_begin(RID p_immediate, VS::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(); }
-
- /* SKELETON API */
-
- RID skeleton_create();
- void skeleton_allocate(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;
- void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform);
- Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const;
- void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
- Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
-
- _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const {
- Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, RID());
- ERR_FAIL_COND_V(skeleton->size == 0, RID());
- if (skeleton->use_2d) {
- return RID();
- }
- if (!skeleton->uniform_set_3d.is_valid()) {
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.ids.push_back(skeleton->buffer);
- uniforms.push_back(u);
- skeleton->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
- }
-
- return skeleton->uniform_set_3d;
- }
- /* Light API */
-
- RID light_create(VS::LightType p_type);
-
- RID directional_light_create() { return light_create(VS::LIGHT_DIRECTIONAL); }
- RID omni_light_create() { return light_create(VS::LIGHT_OMNI); }
- RID spot_light_create() { return light_create(VS::LIGHT_SPOT); }
-
- void light_set_color(RID p_light, const Color &p_color);
- void light_set_param(RID p_light, VS::LightParam p_param, float p_value);
- void light_set_shadow(RID p_light, bool p_enabled);
- void light_set_shadow_color(RID p_light, const Color &p_color);
- void light_set_projector(RID p_light, RID p_texture);
- void light_set_negative(RID p_light, bool p_enable);
- void light_set_cull_mask(RID p_light, uint32_t p_mask);
- void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled);
- void light_set_use_gi(RID p_light, bool p_enabled);
-
- void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode);
-
- void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode);
- void light_directional_set_blend_splits(RID p_light, bool p_enable);
- bool light_directional_get_blend_splits(RID p_light) const;
- void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode);
- VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
-
- VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
- VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
-
- _FORCE_INLINE_ VS::LightType light_get_type(RID p_light) const {
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL);
-
- return light->type;
- }
- AABB light_get_aabb(RID p_light) const;
-
- _FORCE_INLINE_ float light_get_param(RID p_light, VS::LightParam p_param) {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, 0);
-
- return light->param[p_param];
- }
-
- _FORCE_INLINE_ Color light_get_color(RID p_light) {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, Color());
-
- return light->color;
- }
-
- _FORCE_INLINE_ Color light_get_shadow_color(RID p_light) {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, Color());
-
- return light->shadow_color;
- }
-
- _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, 0);
-
- return light->cull_mask;
- }
-
- _FORCE_INLINE_ bool light_has_shadow(RID p_light) const {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL);
-
- return light->shadow;
- }
-
- _FORCE_INLINE_ bool light_is_negative(RID p_light) const {
-
- const Light *light = light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL);
-
- return light->negative;
- }
-
- bool light_get_use_gi(RID p_light);
- uint64_t light_get_version(RID p_light) const;
-
- /* PROBE API */
-
- RID reflection_probe_create();
-
- void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode);
- void reflection_probe_set_intensity(RID p_probe, float p_intensity);
- void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient);
- void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy);
- void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib);
- void reflection_probe_set_max_distance(RID p_probe, float p_distance);
- void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents);
- void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset);
- void reflection_probe_set_as_interior(RID p_probe, bool p_enable);
- void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable);
- void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable);
- void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
- void reflection_probe_set_resolution(RID p_probe, int p_resolution);
-
- AABB reflection_probe_get_aabb(RID p_probe) const;
- VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
- uint32_t reflection_probe_get_cull_mask(RID p_probe) const;
- Vector3 reflection_probe_get_extents(RID p_probe) const;
- Vector3 reflection_probe_get_origin_offset(RID p_probe) const;
- float reflection_probe_get_origin_max_distance(RID p_probe) const;
- int reflection_probe_get_resolution(RID p_probe) const;
- bool reflection_probe_renders_shadows(RID p_probe) const;
-
- float reflection_probe_get_intensity(RID p_probe) const;
- bool reflection_probe_is_interior(RID p_probe) const;
- bool reflection_probe_is_box_projection(RID p_probe) const;
- Color reflection_probe_get_interior_ambient(RID p_probe) const;
- float reflection_probe_get_interior_ambient_energy(RID p_probe) const;
- float reflection_probe_get_interior_ambient_probe_contribution(RID p_probe) const;
-
- void base_update_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance);
- void skeleton_update_dependency(RID p_skeleton, RasterizerScene::InstanceBase *p_instance);
-
- /* GI PROBE API */
-
- RID gi_probe_create();
-
- 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);
-
- AABB gi_probe_get_bounds(RID p_gi_probe) const;
- Vector3i gi_probe_get_octree_size(RID p_gi_probe) const;
- Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const;
- Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const;
- Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const;
-
- Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const;
- Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const;
-
- void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range);
- float gi_probe_get_dynamic_range(RID p_gi_probe) const;
-
- void gi_probe_set_propagation(RID p_gi_probe, float p_range);
- float gi_probe_get_propagation(RID p_gi_probe) const;
-
- void gi_probe_set_energy(RID p_gi_probe, float p_energy);
- float gi_probe_get_energy(RID p_gi_probe) const;
-
- void gi_probe_set_ao(RID p_gi_probe, float p_ao);
- float gi_probe_get_ao(RID p_gi_probe) const;
-
- void gi_probe_set_ao_size(RID p_gi_probe, float p_strength);
- float gi_probe_get_ao_size(RID p_gi_probe) const;
-
- void gi_probe_set_bias(RID p_gi_probe, float p_bias);
- float gi_probe_get_bias(RID p_gi_probe) const;
-
- void gi_probe_set_normal_bias(RID p_gi_probe, float p_range);
- float gi_probe_get_normal_bias(RID p_gi_probe) const;
-
- void gi_probe_set_interior(RID p_gi_probe, bool p_enable);
- bool gi_probe_is_interior(RID p_gi_probe) const;
-
- void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable);
- bool gi_probe_is_using_two_bounces(RID p_gi_probe) const;
-
- void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength);
- float gi_probe_get_anisotropy_strength(RID p_gi_probe) const;
-
- uint32_t gi_probe_get_version(RID p_probe);
- uint32_t gi_probe_get_data_version(RID p_probe);
-
- RID gi_probe_get_octree_buffer(RID p_gi_probe) const;
- RID gi_probe_get_data_buffer(RID p_gi_probe) const;
-
- RID gi_probe_get_sdf_texture(RID p_gi_probe);
-
- /* LIGHTMAP CAPTURE */
-
- void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
- AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); }
- void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) {}
- RID lightmap_capture_create() {
- return RID();
- }
- Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const {
- return Vector<uint8_t>();
- }
- void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {}
- Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const { return Transform(); }
- void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) {}
- int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { return 0; }
- void lightmap_capture_set_energy(RID p_capture, float p_energy) {}
- float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
- const Vector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const {
- return NULL;
- }
-
- /* PARTICLES */
-
- RID particles_create() { return RID(); }
-
- void particles_set_emitting(RID p_particles, bool p_emitting) {}
- void particles_set_amount(RID p_particles, int p_amount) {}
- void particles_set_lifetime(RID p_particles, float p_lifetime) {}
- void particles_set_one_shot(RID p_particles, bool p_one_shot) {}
- void particles_set_pre_process_time(RID p_particles, float p_time) {}
- void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {}
- void particles_set_randomness_ratio(RID p_particles, float p_ratio) {}
- void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {}
- void particles_set_speed_scale(RID p_particles, float p_scale) {}
- 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_fractional_delta(RID p_particles, bool p_enable) {}
- void particles_restart(RID p_particles) {}
-
- void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) {}
-
- void particles_set_draw_passes(RID p_particles, int p_count) {}
- void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {}
-
- void particles_request_process(RID p_particles) {}
- AABB particles_get_current_aabb(RID p_particles) { return AABB(); }
- AABB particles_get_aabb(RID p_particles) const { return AABB(); }
-
- void particles_set_emission_transform(RID p_particles, const Transform &p_transform) {}
-
- bool particles_get_emitting(RID p_particles) { return false; }
- int particles_get_draw_passes(RID p_particles) const { return 0; }
- RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); }
-
- virtual bool particles_is_inactive(RID p_particles) const { return false; }
-
- /* RENDER TARGET API */
-
- RID render_target_create();
- void render_target_set_position(RID p_render_target, int p_x, int p_y);
- void render_target_set_size(RID p_render_target, int p_width, int p_height);
- RID render_target_get_texture(RID p_render_target);
- void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
- void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
- bool render_target_was_used(RID p_render_target);
- void render_target_set_as_unused(RID p_render_target);
- void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region);
- RID render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader);
-
- virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color);
- virtual bool render_target_is_clear_requested(RID p_render_target);
- virtual Color render_target_get_clear_request_color(RID p_render_target);
- virtual void render_target_disable_clear_request(RID p_render_target);
- virtual void render_target_do_clear_request(RID p_render_target);
-
- Size2 render_target_get_size(RID p_render_target);
- RID render_target_get_rd_framebuffer(RID p_render_target);
-
- VS::InstanceType get_base_type(RID p_rid) const;
-
- bool free(RID p_rid);
-
- bool has_os_feature(const String &p_feature) const;
-
- void update_dirty_resources();
-
- void set_debug_generate_wireframes(bool p_generate) {}
-
- void render_info_begin_capture() {}
- void render_info_end_capture() {}
- int get_captured_render_info(VS::RenderInfo p_info) { return 0; }
-
- int get_render_info(VS::RenderInfo p_info) { return 0; }
- String get_video_adapter_name() const { return String(); }
- String get_video_adapter_vendor() const { return String(); }
-
- virtual void capture_timestamps_begin();
- virtual void capture_timestamp(const String &p_name);
- virtual uint32_t get_captured_timestamps_count() const;
- virtual uint64_t get_captured_timestamps_frame() const;
- virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const;
- virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const;
- virtual String get_captured_timestamp_name(uint32_t p_index) const;
-
- static RasterizerStorage *base_singleton;
-
- RasterizerEffectsRD *get_effects();
-
- RasterizerStorageRD();
- ~RasterizerStorageRD();
-};
-
-#endif // RASTERIZER_STORAGE_RD_H
diff --git a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp
deleted file mode 100644
index 4ee020aa69..0000000000
--- a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*************************************************************************/
-/* render_pipeline_vertex_format_cache_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_pipeline_vertex_format_cache_rd.h"
-#include "core/os/memory.h"
-
-RID RenderPipelineVertexFormatCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id) {
-
- RD::PipelineMultisampleState multisample_state_version = multisample_state;
- multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id);
-
- RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, rasterization_state, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags);
- ERR_FAIL_COND_V(pipeline.is_null(), RID());
- versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1));
- versions[version_count].framebuffer_id = p_framebuffer_format_id;
- versions[version_count].vertex_id = p_vertex_format_id;
- versions[version_count].pipeline = pipeline;
- version_count++;
- return pipeline;
-}
-
-void RenderPipelineVertexFormatCacheRD::_clear() {
-
- if (versions) {
- for (uint32_t i = 0; i < version_count; i++) {
- //shader may be gone, so this may not be valid
- if (RD::get_singleton()->render_pipeline_is_valid(versions[i].pipeline)) {
- RD::get_singleton()->free(versions[i].pipeline);
- }
- }
- version_count = 0;
- memfree(versions);
- versions = NULL;
- }
-}
-
-void RenderPipelineVertexFormatCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) {
- ERR_FAIL_COND(p_shader.is_null());
- _clear();
- shader = p_shader;
- input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(p_shader);
- render_primitive = p_primitive;
- rasterization_state = p_rasterization_state;
- multisample_state = p_multisample;
- depth_stencil_state = p_depth_stencil_state;
- blend_state = p_blend_state;
- dynamic_state_flags = p_dynamic_state_flags;
-}
-
-void RenderPipelineVertexFormatCacheRD::update_shader(RID p_shader) {
- ERR_FAIL_COND(p_shader.is_null());
- _clear();
- setup(p_shader, render_primitive, rasterization_state, multisample_state, depth_stencil_state, blend_state, dynamic_state_flags);
-}
-
-void RenderPipelineVertexFormatCacheRD::clear() {
- _clear();
- shader = RID(); //clear shader
- input_mask = 0;
-}
-
-RenderPipelineVertexFormatCacheRD::RenderPipelineVertexFormatCacheRD() {
- version_count = 0;
- versions = NULL;
- input_mask = 0;
-}
-
-RenderPipelineVertexFormatCacheRD::~RenderPipelineVertexFormatCacheRD() {
- _clear();
-}
diff --git a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h b/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h
deleted file mode 100644
index 05c5968360..0000000000
--- a/servers/visual/rasterizer_rd/render_pipeline_vertex_format_cache_rd.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************************************/
-/* render_pipeline_vertex_format_cache_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 RENDER_PIPELINE_CACHE_RD_H
-#define RENDER_PIPELINE_CACHE_RD_H
-
-#include "core/spin_lock.h"
-#include "servers/visual/rendering_device.h"
-
-class RenderPipelineVertexFormatCacheRD {
-
- SpinLock spin_lock;
-
- RID shader;
- uint32_t input_mask;
-
- RD::RenderPrimitive render_primitive;
- RD::PipelineRasterizationState rasterization_state;
- RD::PipelineMultisampleState multisample_state;
- RD::PipelineDepthStencilState depth_stencil_state;
- RD::PipelineColorBlendState blend_state;
- int dynamic_state_flags;
-
- struct Version {
- RD::VertexFormatID vertex_id;
- RD::FramebufferFormatID framebuffer_id;
- RID pipeline;
- };
-
- Version *versions;
- uint32_t version_count;
-
- RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id);
-
- void _clear();
-
-public:
- void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0);
- void update_shader(RID p_shader);
-
- _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V_MSG(shader.is_null(), RID(),
- "Attempted to use an unused shader variant (shader is null),");
-#endif
-
- spin_lock.lock();
- RID result;
- for (uint32_t i = 0; i < version_count; i++) {
- if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id) {
- result = versions[i].pipeline;
- spin_lock.unlock();
- return result;
- }
- }
- result = _generate_version(p_vertex_format_id, p_framebuffer_format_id);
- spin_lock.unlock();
- return result;
- }
-
- _FORCE_INLINE_ uint32_t get_vertex_input_mask() const {
- return input_mask;
- }
- void clear();
- RenderPipelineVertexFormatCacheRD();
- ~RenderPipelineVertexFormatCacheRD();
-};
-
-#endif // RENDER_PIPELINE_CACHE_RD_H
diff --git a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
deleted file mode 100644
index ecff8d81f6..0000000000
--- a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp
+++ /dev/null
@@ -1,1243 +0,0 @@
-/*************************************************************************/
-/* shader_compiler_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "shader_compiler_rd.h"
-
-#include "core/os/os.h"
-#include "core/project_settings.h"
-
-#define SL ShaderLanguage
-
-static String _mktab(int p_level) {
-
- String tb;
- for (int i = 0; i < p_level; i++) {
- tb += "\t";
- }
-
- return tb;
-}
-
-static String _typestr(SL::DataType p_type) {
-
- String type = ShaderLanguage::get_datatype_name(p_type);
- if (ShaderLanguage::is_sampler_type(p_type)) {
- type = type.replace("sampler", "texture"); //we use textures instead of samplers
- }
- return type;
-}
-
-static int _get_datatype_size(SL::DataType p_type) {
-
- switch (p_type) {
-
- case SL::TYPE_VOID: return 0;
- case SL::TYPE_BOOL: return 4;
- case SL::TYPE_BVEC2: return 8;
- case SL::TYPE_BVEC3: return 12;
- case SL::TYPE_BVEC4: return 16;
- case SL::TYPE_INT: return 4;
- case SL::TYPE_IVEC2: return 8;
- case SL::TYPE_IVEC3: return 12;
- case SL::TYPE_IVEC4: return 16;
- case SL::TYPE_UINT: return 4;
- case SL::TYPE_UVEC2: return 8;
- case SL::TYPE_UVEC3: return 12;
- case SL::TYPE_UVEC4: return 16;
- case SL::TYPE_FLOAT: return 4;
- case SL::TYPE_VEC2: return 8;
- case SL::TYPE_VEC3: return 12;
- case SL::TYPE_VEC4: return 16;
- case SL::TYPE_MAT2:
- return 32; //4 * 4 + 4 * 4
- case SL::TYPE_MAT3:
- return 48; // 4 * 4 + 4 * 4 + 4 * 4
- case SL::TYPE_MAT4: return 64;
- case SL::TYPE_SAMPLER2D: return 16;
- case SL::TYPE_ISAMPLER2D: return 16;
- case SL::TYPE_USAMPLER2D: return 16;
- case SL::TYPE_SAMPLER2DARRAY: return 16;
- case SL::TYPE_ISAMPLER2DARRAY: return 16;
- case SL::TYPE_USAMPLER2DARRAY: return 16;
- case SL::TYPE_SAMPLER3D: return 16;
- case SL::TYPE_ISAMPLER3D: return 16;
- case SL::TYPE_USAMPLER3D: return 16;
- case SL::TYPE_SAMPLERCUBE: return 16;
- case SL::TYPE_STRUCT: return 0;
- }
-
- ERR_FAIL_V(0);
-}
-
-static int _get_datatype_alignment(SL::DataType p_type) {
-
- switch (p_type) {
-
- case SL::TYPE_VOID: return 0;
- case SL::TYPE_BOOL: return 4;
- case SL::TYPE_BVEC2: return 8;
- case SL::TYPE_BVEC3: return 16;
- case SL::TYPE_BVEC4: return 16;
- case SL::TYPE_INT: return 4;
- case SL::TYPE_IVEC2: return 8;
- case SL::TYPE_IVEC3: return 16;
- case SL::TYPE_IVEC4: return 16;
- case SL::TYPE_UINT: return 4;
- case SL::TYPE_UVEC2: return 8;
- case SL::TYPE_UVEC3: return 16;
- case SL::TYPE_UVEC4: return 16;
- case SL::TYPE_FLOAT: return 4;
- case SL::TYPE_VEC2: return 8;
- case SL::TYPE_VEC3: return 16;
- case SL::TYPE_VEC4: return 16;
- case SL::TYPE_MAT2: return 16;
- case SL::TYPE_MAT3: return 16;
- case SL::TYPE_MAT4: return 16;
- case SL::TYPE_SAMPLER2D: return 16;
- case SL::TYPE_ISAMPLER2D: return 16;
- case SL::TYPE_USAMPLER2D: return 16;
- case SL::TYPE_SAMPLER2DARRAY: return 16;
- case SL::TYPE_ISAMPLER2DARRAY: return 16;
- case SL::TYPE_USAMPLER2DARRAY: return 16;
- case SL::TYPE_SAMPLER3D: return 16;
- case SL::TYPE_ISAMPLER3D: return 16;
- case SL::TYPE_USAMPLER3D: return 16;
- case SL::TYPE_SAMPLERCUBE: return 16;
- case SL::TYPE_STRUCT: return 0;
- }
-
- ERR_FAIL_V(0);
-}
-static String _interpstr(SL::DataInterpolation p_interp) {
-
- switch (p_interp) {
- case SL::INTERPOLATION_FLAT: return "flat ";
- case SL::INTERPOLATION_SMOOTH: return "";
- }
- return "";
-}
-
-static String _prestr(SL::DataPrecision p_pres) {
-
- switch (p_pres) {
- case SL::PRECISION_LOWP: return "lowp ";
- case SL::PRECISION_MEDIUMP: return "mediump ";
- case SL::PRECISION_HIGHP: return "highp ";
- case SL::PRECISION_DEFAULT: return "";
- }
- return "";
-}
-
-static String _qualstr(SL::ArgumentQualifier p_qual) {
-
- switch (p_qual) {
- case SL::ARGUMENT_QUALIFIER_IN: return "";
- case SL::ARGUMENT_QUALIFIER_OUT: return "out ";
- case SL::ARGUMENT_QUALIFIER_INOUT: return "inout ";
- }
- return "";
-}
-
-static String _opstr(SL::Operator p_op) {
-
- return SL::get_operator_text(p_op);
-}
-
-static String _mkid(const String &p_id) {
-
- String id = "m_" + p_id.replace("__", "_dus_");
- return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
-}
-
-static String f2sp0(float p_float) {
-
- String num = rtoss(p_float);
- if (num.find(".") == -1 && num.find("e") == -1) {
- num += ".0";
- }
- return num;
-}
-
-static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
-
- switch (p_type) {
- case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false";
- case SL::TYPE_BVEC2:
- case SL::TYPE_BVEC3:
- case SL::TYPE_BVEC4: {
-
- String text = "bvec" + itos(p_type - SL::TYPE_BOOL + 1) + "(";
- for (int i = 0; i < p_values.size(); i++) {
- if (i > 0)
- text += ",";
-
- text += p_values[i].boolean ? "true" : "false";
- }
- text += ")";
- return text;
- }
-
- case SL::TYPE_INT: return itos(p_values[0].sint);
- case SL::TYPE_IVEC2:
- case SL::TYPE_IVEC3:
- case SL::TYPE_IVEC4: {
-
- String text = "ivec" + itos(p_type - SL::TYPE_INT + 1) + "(";
- for (int i = 0; i < p_values.size(); i++) {
- if (i > 0)
- text += ",";
-
- text += itos(p_values[i].sint);
- }
- text += ")";
- return text;
-
- } break;
- case SL::TYPE_UINT: return itos(p_values[0].uint) + "u";
- case SL::TYPE_UVEC2:
- case SL::TYPE_UVEC3:
- case SL::TYPE_UVEC4: {
-
- String text = "uvec" + itos(p_type - SL::TYPE_UINT + 1) + "(";
- for (int i = 0; i < p_values.size(); i++) {
- if (i > 0)
- text += ",";
-
- text += itos(p_values[i].uint) + "u";
- }
- text += ")";
- return text;
- } break;
- case SL::TYPE_FLOAT: return f2sp0(p_values[0].real);
- case SL::TYPE_VEC2:
- case SL::TYPE_VEC3:
- case SL::TYPE_VEC4: {
-
- String text = "vec" + itos(p_type - SL::TYPE_FLOAT + 1) + "(";
- for (int i = 0; i < p_values.size(); i++) {
- if (i > 0)
- text += ",";
-
- text += f2sp0(p_values[i].real);
- }
- text += ")";
- return text;
-
- } break;
- case SL::TYPE_MAT2:
- case SL::TYPE_MAT3:
- case SL::TYPE_MAT4: {
-
- String text = "mat" + itos(p_type - SL::TYPE_MAT2 + 2) + "(";
- for (int i = 0; i < p_values.size(); i++) {
- if (i > 0)
- text += ",";
-
- text += f2sp0(p_values[i].real);
- }
- text += ")";
- return text;
-
- } break;
- default: ERR_FAIL_V(String());
- }
-}
-
-String ShaderCompilerRD::_get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat) {
- if (p_filter == ShaderLanguage::FILTER_DEFAULT) {
- ERR_FAIL_COND_V(actions.default_filter == ShaderLanguage::FILTER_DEFAULT, String());
- p_filter = actions.default_filter;
- }
- if (p_repeat == ShaderLanguage::REPEAT_DEFAULT) {
- ERR_FAIL_COND_V(actions.default_repeat == ShaderLanguage::REPEAT_DEFAULT, String());
- p_repeat = actions.default_repeat;
- }
- return actions.sampler_array_name + "[" + itos(p_filter + (p_repeat == ShaderLanguage::REPEAT_ENABLE ? ShaderLanguage::FILTER_DEFAULT : 0)) + "]";
-}
-
-void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) {
-
- int fidx = -1;
-
- for (int i = 0; i < p_node->functions.size(); i++) {
- if (p_node->functions[i].name == p_for_func) {
- fidx = i;
- break;
- }
- }
-
- ERR_FAIL_COND(fidx == -1);
-
- for (Set<StringName>::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) {
-
- if (added.has(E->get())) {
- continue; //was added already
- }
-
- _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, added);
-
- SL::FunctionNode *fnode = NULL;
-
- for (int i = 0; i < p_node->functions.size(); i++) {
- if (p_node->functions[i].name == E->get()) {
- fnode = p_node->functions[i].function;
- break;
- }
- }
-
- ERR_FAIL_COND(!fnode);
-
- r_to_add += "\n";
-
- String header;
- if (fnode->return_type == SL::TYPE_STRUCT) {
- header = _mkid(fnode->return_struct_name) + " " + _mkid(fnode->name) + "(";
- } else {
- header = _typestr(fnode->return_type) + " " + _mkid(fnode->name) + "(";
- }
- for (int i = 0; i < fnode->arguments.size(); i++) {
-
- if (i > 0)
- header += ", ";
- if (fnode->arguments[i].type == SL::TYPE_STRUCT) {
- header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name);
- } else {
- header += _qualstr(fnode->arguments[i].qualifier) + _prestr(fnode->arguments[i].precision) + _typestr(fnode->arguments[i].type) + " " + _mkid(fnode->arguments[i].name);
- }
- }
-
- header += ")\n";
- r_to_add += header;
- r_to_add += p_func_code[E->get()];
-
- added.insert(E->get());
- }
-}
-
-String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) {
-
- String code;
-
- switch (p_node->type) {
-
- case SL::Node::TYPE_SHADER: {
-
- SL::ShaderNode *pnode = (SL::ShaderNode *)p_node;
-
- for (int i = 0; i < pnode->render_modes.size(); i++) {
-
- if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) {
-
- r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]]);
- used_rmode_defines.insert(pnode->render_modes[i]);
- }
-
- if (p_actions.render_mode_flags.has(pnode->render_modes[i])) {
- *p_actions.render_mode_flags[pnode->render_modes[i]] = true;
- }
-
- if (p_actions.render_mode_values.has(pnode->render_modes[i])) {
- Pair<int *, int> &p = p_actions.render_mode_values[pnode->render_modes[i]];
- *p.first = p.second;
- }
- }
-
- // structs
-
- for (int i = 0; i < pnode->vstructs.size(); i++) {
-
- SL::StructNode *st = pnode->vstructs[i].shader_struct;
- String struct_code;
-
- struct_code += "struct ";
- struct_code += _mkid(pnode->vstructs[i].name);
- struct_code += " ";
- struct_code += "{\n";
- for (int j = 0; j < st->members.size(); j++) {
- SL::MemberNode *m = st->members[j];
- if (m->datatype == SL::TYPE_STRUCT) {
- struct_code += _mkid(m->struct_name);
- } else {
- struct_code += _prestr(m->precision);
- struct_code += _typestr(m->datatype);
- }
- struct_code += " ";
- struct_code += m->name;
- if (m->array_size > 0) {
- struct_code += "[";
- struct_code += itos(m->array_size);
- struct_code += "]";
- }
- struct_code += ";\n";
- }
- struct_code += "}";
- struct_code += ";\n";
-
- r_gen_code.vertex_global += struct_code;
- r_gen_code.fragment_global += struct_code;
- }
-
- int max_texture_uniforms = 0;
- int max_uniforms = 0;
-
- for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
- if (SL::is_sampler_type(E->get().type))
- max_texture_uniforms++;
- else
- max_uniforms++;
- }
-
- r_gen_code.texture_uniforms.resize(max_texture_uniforms);
-
- Vector<int> uniform_sizes;
- Vector<int> uniform_alignments;
- Vector<StringName> uniform_defines;
- uniform_sizes.resize(max_uniforms);
- uniform_alignments.resize(max_uniforms);
- uniform_defines.resize(max_uniforms);
- bool uses_uniforms = false;
-
- for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) {
-
- String ucode;
-
- if (SL::is_sampler_type(E->get().type)) {
- ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + E->get().texture_order) + ") uniform ";
- }
-
- ucode += _prestr(E->get().precision);
- ucode += _typestr(E->get().type);
- 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;
-
- GeneratedCode::Texture texture;
- texture.name = E->key();
- texture.hint = E->get().hint;
- texture.type = E->get().type;
- texture.filter = E->get().filter;
- texture.repeat = E->get().repeat;
-
- 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;
- uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
- uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
- }
-
- p_actions.uniforms->insert(E->key(), E->get());
- }
-
- for (int i = 0; i < max_uniforms; i++) {
- r_gen_code.uniforms += uniform_defines[i];
- }
-
-#if 1
- // add up
- int offset = 0;
- for (int i = 0; i < uniform_sizes.size(); i++) {
-
- int align = offset % uniform_alignments[i];
-
- if (align != 0) {
- offset += uniform_alignments[i] - align;
- }
-
- r_gen_code.uniform_offsets.push_back(offset);
-
- offset += uniform_sizes[i];
- }
-
- r_gen_code.uniform_total_size = offset;
-
- if (r_gen_code.uniform_total_size % 16 != 0) { //UBO sizes must be multiples of 16
- r_gen_code.uniform_total_size += 16 - (r_gen_code.uniform_total_size % 16);
- }
-#else
- // add up
- for (int i = 0; i < uniform_sizes.size(); i++) {
-
- if (i > 0) {
-
- int align = uniform_sizes[i - 1] % uniform_alignments[i];
- if (align != 0) {
- uniform_sizes[i - 1] += uniform_alignments[i] - align;
- }
-
- uniform_sizes[i] = uniform_sizes[i] + uniform_sizes[i - 1];
- }
- }
- //offset
- r_gen_code.uniform_offsets.resize(uniform_sizes.size());
- for (int i = 0; i < uniform_sizes.size(); i++) {
-
- if (i > 0)
- r_gen_code.uniform_offsets[i] = uniform_sizes[i - 1];
- else
- r_gen_code.uniform_offsets[i] = 0;
- }
- /*
- for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
-
- if (SL::is_sampler_type(E->get().type)) {
- continue;
- }
-
- }
-
-*/
- if (uniform_sizes.size()) {
- r_gen_code.uniform_total_size = uniform_sizes[uniform_sizes.size() - 1];
- } else {
- r_gen_code.uniform_total_size = 0;
- }
-#endif
-
- uint32_t index = p_default_actions.base_varying_index;
-
- for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) {
-
- String vcode;
- String interp_mode = _interpstr(E->get().interpolation);
- vcode += _prestr(E->get().precision);
- vcode += _typestr(E->get().type);
- vcode += " " + _mkid(E->key());
- if (E->get().array_size > 0) {
- vcode += "[";
- vcode += itos(E->get().array_size);
- 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;
- index++;
- }
-
- for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) {
- String gcode;
- gcode += "const ";
- gcode += _prestr(E->get().precision);
- if (E->get().type == SL::TYPE_STRUCT) {
- gcode += _mkid(E->get().type_str);
- } else {
- gcode += _typestr(E->get().type);
- }
- gcode += " " + _mkid(E->key());
- gcode += "=";
- gcode += _dump_node_code(E->get().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;
- }
-
- Map<StringName, String> function_code;
-
- //code for functions
- for (int i = 0; i < pnode->functions.size(); i++) {
- SL::FunctionNode *fnode = pnode->functions[i].function;
- function = fnode;
- current_func_name = fnode->name;
- function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- function = NULL;
- }
-
- //place functions in actual code
-
- Set<StringName> added_vtx;
- Set<StringName> added_fragment; //share for light
-
- for (int i = 0; i < pnode->functions.size(); i++) {
-
- SL::FunctionNode *fnode = pnode->functions[i].function;
-
- function = fnode;
-
- 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];
- }
- function = NULL;
- }
-
- //code+=dump_node_code(pnode->body,p_level);
- } break;
- case SL::Node::TYPE_STRUCT: {
-
- } break;
- case SL::Node::TYPE_FUNCTION: {
-
- } break;
- case SL::Node::TYPE_BLOCK: {
- SL::BlockNode *bnode = (SL::BlockNode *)p_node;
-
- //variables
- if (!bnode->single_statement) {
- code += _mktab(p_level - 1) + "{\n";
- }
-
- for (int i = 0; i < bnode->statements.size(); i++) {
-
- String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
-
- if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) {
- code += scode; //use directly
- } else {
- code += _mktab(p_level) + scode + ";\n";
- }
- }
- if (!bnode->single_statement) {
- code += _mktab(p_level - 1) + "}\n";
- }
-
- } break;
- case SL::Node::TYPE_VARIABLE_DECLARATION: {
- SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node;
-
- String declaration;
- if (vdnode->is_const) {
- declaration += "const ";
- }
- if (vdnode->datatype == SL::TYPE_STRUCT) {
- declaration += _mkid(vdnode->struct_name);
- } else {
- declaration += _prestr(vdnode->precision) + _typestr(vdnode->datatype);
- }
- for (int i = 0; i < vdnode->declarations.size(); i++) {
- if (i > 0) {
- declaration += ",";
- } else {
- declaration += " ";
- }
- declaration += _mkid(vdnode->declarations[i].name);
- if (vdnode->declarations[i].initializer) {
- declaration += "=";
- declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- }
- }
-
- code += declaration;
- } break;
- case SL::Node::TYPE_VARIABLE: {
- SL::VariableNode *vnode = (SL::VariableNode *)p_node;
-
- if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) {
- *p_actions.write_flag_pointers[vnode->name] = true;
- }
-
- if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) {
- String define = p_default_actions.usage_defines[vnode->name];
- if (define.begins_with("@")) {
- define = p_default_actions.usage_defines[define.substr(1, define.length())];
- }
- r_gen_code.defines.push_back(define);
- used_name_defines.insert(vnode->name);
- }
-
- if (p_actions.usage_flag_pointers.has(vnode->name) && !used_flag_pointers.has(vnode->name)) {
- *p_actions.usage_flag_pointers[vnode->name] = true;
- used_flag_pointers.insert(vnode->name);
- }
-
- if (p_default_actions.renames.has(vnode->name))
- code = p_default_actions.renames[vnode->name];
- else {
- code = _mkid(vnode->name);
- if (actions.base_uniform_string != String() && shader->uniforms.has(vnode->name) && shader->uniforms[vnode->name].texture_order < 0) {
- code = actions.base_uniform_string + code;
- }
- }
-
- if (vnode->name == time_name) {
- if (current_func_name == vertex_name) {
- r_gen_code.uses_vertex_time = true;
- }
- if (current_func_name == fragment_name || current_func_name == light_name) {
- r_gen_code.uses_fragment_time = true;
- }
- }
-
- } break;
- case SL::Node::TYPE_ARRAY_CONSTRUCT: {
- SL::ArrayConstructNode *acnode = (SL::ArrayConstructNode *)p_node;
- int sz = acnode->initializer.size();
- if (acnode->datatype == SL::TYPE_STRUCT) {
- code += _mkid(acnode->struct_name);
- } else {
- code += _typestr(acnode->datatype);
- }
- code += "[";
- code += itos(acnode->initializer.size());
- code += "]";
- code += "(";
- for (int i = 0; i < sz; i++) {
- code += _dump_node_code(acnode->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (i != sz - 1) {
- code += ", ";
- }
- }
- code += ")";
- } break;
- case SL::Node::TYPE_ARRAY_DECLARATION: {
-
- SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node;
- String declaration;
- if (adnode->is_const) {
- declaration += "const ";
- }
- if (adnode->datatype == SL::TYPE_STRUCT) {
- declaration += _mkid(adnode->struct_name);
- } else {
- declaration = _prestr(adnode->precision) + _typestr(adnode->datatype);
- }
- for (int i = 0; i < adnode->declarations.size(); i++) {
- if (i > 0) {
- declaration += ",";
- } else {
- declaration += " ";
- }
- declaration += _mkid(adnode->declarations[i].name);
- declaration += "[";
- declaration += itos(adnode->declarations[i].size);
- declaration += "]";
- int sz = adnode->declarations[i].initializer.size();
- if (sz > 0) {
- declaration += "=";
- if (adnode->datatype == SL::TYPE_STRUCT) {
- declaration += _mkid(adnode->struct_name);
- } else {
- declaration += _typestr(adnode->datatype);
- }
- declaration += "[";
- declaration += itos(sz);
- declaration += "]";
- declaration += "(";
- for (int j = 0; j < sz; j++) {
- declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (j != sz - 1) {
- declaration += ", ";
- }
- }
- declaration += ")";
- }
- }
-
- code += declaration;
- } break;
- case SL::Node::TYPE_ARRAY: {
- SL::ArrayNode *anode = (SL::ArrayNode *)p_node;
-
- if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) {
- *p_actions.write_flag_pointers[anode->name] = true;
- }
-
- if (p_default_actions.usage_defines.has(anode->name) && !used_name_defines.has(anode->name)) {
- String define = p_default_actions.usage_defines[anode->name];
- if (define.begins_with("@")) {
- define = p_default_actions.usage_defines[define.substr(1, define.length())];
- }
- r_gen_code.defines.push_back(define);
- used_name_defines.insert(anode->name);
- }
-
- if (p_actions.usage_flag_pointers.has(anode->name) && !used_flag_pointers.has(anode->name)) {
- *p_actions.usage_flag_pointers[anode->name] = true;
- used_flag_pointers.insert(anode->name);
- }
-
- if (p_default_actions.renames.has(anode->name))
- code = p_default_actions.renames[anode->name];
- else
- code = _mkid(anode->name);
-
- if (anode->call_expression != NULL) {
- code += ".";
- code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- }
-
- if (anode->index_expression != NULL) {
- code += "[";
- code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += "]";
- }
-
- if (anode->name == time_name) {
- if (current_func_name == vertex_name) {
- r_gen_code.uses_vertex_time = true;
- }
- if (current_func_name == fragment_name || current_func_name == light_name) {
- r_gen_code.uses_fragment_time = true;
- }
- }
-
- } break;
- case SL::Node::TYPE_CONSTANT: {
- SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
- return get_constant_text(cnode->datatype, cnode->values);
-
- } break;
- case SL::Node::TYPE_OPERATOR: {
- SL::OperatorNode *onode = (SL::OperatorNode *)p_node;
-
- switch (onode->op) {
-
- case SL::OP_ASSIGN:
- case SL::OP_ASSIGN_ADD:
- case SL::OP_ASSIGN_SUB:
- case SL::OP_ASSIGN_MUL:
- case SL::OP_ASSIGN_DIV:
- case SL::OP_ASSIGN_SHIFT_LEFT:
- case SL::OP_ASSIGN_SHIFT_RIGHT:
- case SL::OP_ASSIGN_MOD:
- case SL::OP_ASSIGN_BIT_AND:
- case SL::OP_ASSIGN_BIT_OR:
- case SL::OP_ASSIGN_BIT_XOR:
- code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- break;
- case SL::OP_BIT_INVERT:
- case SL::OP_NEGATE:
- case SL::OP_NOT:
- case SL::OP_DECREMENT:
- case SL::OP_INCREMENT:
- code = _opstr(onode->op) + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- break;
- case SL::OP_POST_DECREMENT:
- case SL::OP_POST_INCREMENT:
- code = _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op);
- break;
- case SL::OP_CALL:
- case SL::OP_STRUCT:
- case SL::OP_CONSTRUCT: {
-
- ERR_FAIL_COND_V(onode->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
-
- SL::VariableNode *vnode = (SL::VariableNode *)onode->arguments[0];
-
- bool is_texture_func = false;
- if (onode->op == SL::OP_STRUCT) {
- code += _mkid(vnode->name);
- } else if (onode->op == SL::OP_CONSTRUCT) {
- code += String(vnode->name);
- } else {
-
- if (internal_functions.has(vnode->name)) {
- code += vnode->name;
- is_texture_func = texture_functions.has(vnode->name);
- } else if (p_default_actions.renames.has(vnode->name)) {
- code += p_default_actions.renames[vnode->name];
- } else {
- code += _mkid(vnode->name);
- }
- }
-
- code += "(";
-
- for (int i = 1; i < onode->arguments.size(); i++) {
- if (i > 1)
- code += ", ";
- String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
-
- //need to map from texture to sampler in order to sample
- const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
-
- StringName texture_uniform = varnode->name;
-
- String sampler_name;
-
- if (actions.custom_samplers.has(texture_uniform)) {
- sampler_name = actions.custom_samplers[texture_uniform];
- } else {
- if (shader->uniforms.has(texture_uniform)) {
- sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
- } else {
- bool found = false;
-
- for (int j = 0; j < function->arguments.size(); j++) {
- if (function->arguments[j].name == texture_uniform) {
- if (function->arguments[j].tex_builtin_check) {
- ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
- sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
- found = true;
- break;
- }
- if (function->arguments[j].tex_argument_check) {
- sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
- found = true;
- break;
- }
- }
- }
- if (!found) {
- //function was most likely unused, so use anything (compiler will remove it anyway)
- sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
- }
- }
- }
-
- code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
- } else {
- code += node_code;
- }
- }
- code += ")";
- } break;
- case SL::OP_INDEX: {
-
- code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += "[";
- code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += "]";
-
- } break;
- case SL::OP_SELECT_IF: {
-
- code += "(";
- code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += "?";
- code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += ":";
- code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += ")";
-
- } break;
-
- default: {
-
- code = "(" + _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + _opstr(onode->op) + _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")";
- break;
- }
- }
-
- } break;
- case SL::Node::TYPE_CONTROL_FLOW: {
- SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node;
- if (cfnode->flow_op == SL::FLOW_OP_IF) {
-
- code += _mktab(p_level) + "if (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
- code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (cfnode->blocks.size() == 2) {
-
- code += _mktab(p_level) + "else\n";
- code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- }
- } else if (cfnode->flow_op == SL::FLOW_OP_SWITCH) {
-
- code += _mktab(p_level) + "switch (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
- code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- } else if (cfnode->flow_op == SL::FLOW_OP_CASE) {
-
- code += _mktab(p_level) + "case " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n";
- code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- } else if (cfnode->flow_op == SL::FLOW_OP_DEFAULT) {
-
- code += _mktab(p_level) + "default:\n";
- code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- } else if (cfnode->flow_op == SL::FLOW_OP_DO) {
-
- code += _mktab(p_level) + "do";
- code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ");";
- } else if (cfnode->flow_op == SL::FLOW_OP_WHILE) {
-
- code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n";
- code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
- } else if (cfnode->flow_op == SL::FLOW_OP_FOR) {
-
- String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n";
- code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
-
- } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) {
-
- if (cfnode->expressions.size()) {
- code = "return " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ";";
- } else {
- code = "return;";
- }
- } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
-
- if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
- *p_actions.usage_flag_pointers["DISCARD"] = true;
- used_flag_pointers.insert("DISCARD");
- }
-
- code = "discard;";
- } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) {
-
- code = "continue;";
- } else if (cfnode->flow_op == SL::FLOW_OP_BREAK) {
-
- code = "break;";
- }
-
- } break;
- case SL::Node::TYPE_MEMBER: {
- SL::MemberNode *mnode = (SL::MemberNode *)p_node;
- code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
- if (mnode->index_expression != NULL) {
- code += "[";
- code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- code += "]";
- }
-
- } break;
- }
-
- return code;
-}
-
-Error ShaderCompilerRD::compile(VS::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());
-
- if (err != OK) {
-
- Vector<String> shader = p_code.split("\n");
- for (int i = 0; i < shader.size(); i++) {
- print_line(itos(i + 1) + " " + shader[i]);
- }
-
- _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER);
- return err;
- }
-
- 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.light = String();
- r_gen_code.uses_fragment_time = false;
- r_gen_code.uses_vertex_time = false;
-
- used_name_defines.clear();
- used_rmode_defines.clear();
- used_flag_pointers.clear();
-
- shader = parser.get_shader();
- function = NULL;
- _dump_node_code(shader, 1, r_gen_code, *p_actions, actions, false);
-
- return OK;
-}
-
-void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
- actions = p_actions;
-
- vertex_name = "vertex";
- fragment_name = "fragment";
- light_name = "light";
- time_name = "TIME";
-
- List<String> func_list;
-
- ShaderLanguage::get_builtin_funcs(&func_list);
-
- for (List<String>::Element *E = func_list.front(); E; E = E->next()) {
- internal_functions.insert(E->get());
- }
- texture_functions.insert("texture");
- texture_functions.insert("textureProj");
- texture_functions.insert("textureLod");
- texture_functions.insert("textureProjLod");
- texture_functions.insert("textureGrad");
-}
-
-ShaderCompilerRD::ShaderCompilerRD() {
-#if 0
-
- /** SPATIAL SHADER **/
-
- actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
- actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
- actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
- actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
- actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
-
- actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
- actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
- actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
- actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
- actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position";
- actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
- actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
- actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
- actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
- actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID";
-
- //builtins
-
- actions[VS::SHADER_SPATIAL].renames["TIME"] = "time";
- actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
-
- actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
- actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
- actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
- actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
- actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
- actions[VS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
- actions[VS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
- actions[VS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
- actions[VS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
- actions[VS::SHADER_SPATIAL].renames["RIM"] = "rim";
- actions[VS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
- actions[VS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
- actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
- actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
- actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
- actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
- actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
- actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
- actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
- actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
- actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
- actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
- actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
- actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
- actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth";
- actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
- actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
-
- //for light
- actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view";
- actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
- actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light";
- actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
- actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
- actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
-
- actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
- actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
- actions[VS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
- actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
- actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
- actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
- actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
- actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
- actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
- actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
- actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
- actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
- actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
-
- actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
- actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
- actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
-
- actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
-
- actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
- actions[VS::SHADER_SPATIAL].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[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
- }
-
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
-
- bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx");
-
- if (!force_blinn) {
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
- } else {
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
- }
-
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
- actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
-
- /* PARTICLES SHADER */
-
- actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color";
- actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz";
- actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass";
- actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active";
- actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart";
- actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom";
- actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform";
- actions[VS::SHADER_PARTICLES].renames["TIME"] = "time";
- actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime";
- actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta";
- actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number";
- actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index";
- actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity";
- actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform";
- actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed";
-
- actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
- actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
- actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
-#endif
-}
diff --git a/servers/visual/rasterizer_rd/shader_compiler_rd.h b/servers/visual/rasterizer_rd/shader_compiler_rd.h
deleted file mode 100644
index c267c2b6d8..0000000000
--- a/servers/visual/rasterizer_rd/shader_compiler_rd.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*************************************************************************/
-/* shader_compiler_rd.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SHADER_COMPILER_RD_H
-#define SHADER_COMPILER_RD_H
-
-#include "core/pair.h"
-#include "servers/visual/shader_language.h"
-#include "servers/visual/shader_types.h"
-#include "servers/visual_server.h"
-
-class ShaderCompilerRD {
-public:
- struct IdentifierActions {
-
- Map<StringName, Pair<int *, int> > render_mode_values;
- Map<StringName, bool *> render_mode_flags;
- Map<StringName, bool *> usage_flag_pointers;
- Map<StringName, bool *> write_flag_pointers;
-
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms;
- };
-
- struct GeneratedCode {
-
- Vector<String> defines;
- struct Texture {
- StringName name;
- ShaderLanguage::DataType type;
- ShaderLanguage::ShaderNode::Uniform::Hint hint;
- ShaderLanguage::TextureFilter filter;
- ShaderLanguage::TextureRepeat repeat;
- };
-
- Vector<Texture> texture_uniforms;
-
- Vector<uint32_t> uniform_offsets;
- uint32_t uniform_total_size;
- String uniforms;
- String vertex_global;
- String vertex;
- String fragment_global;
- String fragment;
- String light;
-
- bool uses_fragment_time;
- bool uses_vertex_time;
- };
-
- struct DefaultIdentifierActions {
-
- Map<StringName, String> renames;
- Map<StringName, String> render_mode_defines;
- Map<StringName, String> usage_defines;
- Map<StringName, String> custom_samplers;
- ShaderLanguage::TextureFilter default_filter;
- ShaderLanguage::TextureRepeat default_repeat;
- String sampler_array_name;
- int base_texture_binding_index = 0;
- int texture_layout_set = 0;
- String base_uniform_string;
- uint32_t base_varying_index = 0;
- };
-
-private:
- ShaderLanguage parser;
-
- String _get_sampler_name(ShaderLanguage::TextureFilter p_filter, ShaderLanguage::TextureRepeat p_repeat);
-
- void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added);
- String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning);
-
- const ShaderLanguage::ShaderNode *shader;
- const ShaderLanguage::FunctionNode *function;
- StringName current_func_name;
- StringName vertex_name;
- StringName fragment_name;
- StringName light_name;
- StringName time_name;
- Set<StringName> texture_functions;
-
- Set<StringName> used_name_defines;
- Set<StringName> used_flag_pointers;
- Set<StringName> used_rmode_defines;
- Set<StringName> internal_functions;
-
- DefaultIdentifierActions actions;
-
-public:
- Error compile(VS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code);
-
- void initialize(DefaultIdentifierActions p_actions);
- ShaderCompilerRD();
-};
-
-#endif // SHADERCOMPILERRD_H
diff --git a/servers/visual/rasterizer_rd/shader_rd.cpp b/servers/visual/rasterizer_rd/shader_rd.cpp
deleted file mode 100644
index 857a29f7f4..0000000000
--- a/servers/visual/rasterizer_rd/shader_rd.cpp
+++ /dev/null
@@ -1,494 +0,0 @@
-/*************************************************************************/
-/* shader_rd.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "shader_rd.h"
-#include "core/string_builder.h"
-#include "rasterizer_rd.h"
-#include "servers/visual/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();
- }
- }
- }
- }
-
- 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());
- }
-
- 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 (p_compute_code) {
- 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());
- }
-
- 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();
- }
- }
- }
- }
-}
-
-RID ShaderRD::version_create() {
-
- //initialize() was never called
- ERR_FAIL_COND_V(variant_defines.size() == 0, RID());
-
- Version version;
- version.dirty = true;
- version.valid = false;
- version.initialize_needed = true;
- version.variants = NULL;
- return version_owner.make_rid(version);
-}
-
-void ShaderRD::_clear_version(Version *p_version) {
- //clear versions if they exist
- if (p_version->variants) {
- for (int i = 0; i < variant_defines.size(); i++) {
- RD::get_singleton()->free(p_version->variants[i]);
- }
-
- memdelete_arr(p_version->variants);
- p_version->variants = NULL;
- }
-}
-
-void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
-
- Vector<RD::ShaderStageData> stages;
-
- String error;
- String current_source;
- RD::ShaderStage current_stage = RD::SHADER_STAGE_VERTEX;
- bool build_ok = true;
-
- if (!is_compute) {
- //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
-
- current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_VERTEX, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
- if (stage.spir_v.size() == 0) {
- build_ok = false;
- } else {
-
- stage.shader_stage = RD::SHADER_STAGE_VERTEX;
- stages.push_back(stage);
- }
- }
-
- if (!is_compute && build_ok) {
- //fragment stage
- 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
-
- current_source = builder.as_string();
- RD::ShaderStageData stage;
- stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_FRAGMENT, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
- if (stage.spir_v.size() == 0) {
- build_ok = false;
- } else {
-
- stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
- stages.push_back(stage);
- }
- }
-
- if (is_compute) {
- //compute stage
- 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(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
-
- 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) {
- build_ok = false;
- } else {
-
- stage.shader_stage = RD::SHADER_STAGE_COMPUTE;
- stages.push_back(stage);
- }
- }
-
- if (!build_ok) {
- MutexLock lock(variant_set_mutex); //properly print the errors
- ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_COMPUTE ? "Compute " : (current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment")) + " shader, variant #" + itos(p_variant) + " (" + variant_defines[p_variant].get_data() + ").");
- ERR_PRINT(error);
-
-#ifdef DEBUG_ENABLED
- ERR_PRINT("code:\n" + current_source.get_with_code_lines());
-#endif
- return;
- }
-
- RID shader = RD::get_singleton()->shader_create(stages);
- {
- MutexLock lock(variant_set_mutex);
- p_version->variants[p_variant] = shader;
- }
-}
-
-void ShaderRD::_compile_version(Version *p_version) {
-
- _clear_version(p_version);
-
- p_version->valid = false;
- p_version->dirty = false;
-
- p_version->variants = memnew_arr(RID, variant_defines.size());
-#if 1
-
- RasterizerRD::thread_work_pool.do_work(variant_defines.size(), this, &ShaderRD::_compile_variant, p_version);
-#else
- for (int i = 0; i < variant_defines.size(); i++) {
-
- _compile_variant(i, p_version);
- }
-#endif
-
- bool all_valid = true;
- for (int i = 0; i < variant_defines.size(); i++) {
- if (p_version->variants[i].is_null()) {
- all_valid = false;
- break;
- }
- }
-
- if (!all_valid) {
- //clear versions if they exist
- for (int i = 0; i < variant_defines.size(); i++) {
- if (!p_version->variants[i].is_null()) {
- RD::get_singleton()->free(p_version->variants[i]);
- }
- }
- memdelete_arr(p_version->variants);
- p_version->variants = NULL;
- return;
- }
-
- 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) {
-
- 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->custom_defines.clear();
- for (int i = 0; i < p_custom_defines.size(); i++) {
- version->custom_defines.push_back(p_custom_defines[i].utf8());
- }
-
- version->dirty = true;
- if (version->initialize_needed) {
- _compile_version(version);
- version->initialize_needed = false;
- }
-}
-
-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) {
-
- 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->custom_defines.clear();
- for (int i = 0; i < p_custom_defines.size(); i++) {
- version->custom_defines.push_back(p_custom_defines[i].utf8());
- }
-
- version->dirty = true;
- if (version->initialize_needed) {
- _compile_version(version);
- version->initialize_needed = false;
- }
-}
-
-bool ShaderRD::version_is_valid(RID p_version) {
- Version *version = version_owner.getornull(p_version);
- ERR_FAIL_COND_V(!version, false);
-
- if (version->dirty) {
- _compile_version(version);
- }
-
- return version->valid;
-}
-
-bool ShaderRD::version_free(RID p_version) {
-
- if (version_owner.owns(p_version)) {
- Version *version = version_owner.getornull(p_version);
- _clear_version(version);
- version_owner.free(p_version);
- } else {
- return false;
- }
-
- return true;
-}
-
-void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines) {
- ERR_FAIL_COND(variant_defines.size());
- ERR_FAIL_COND(p_variant_defines.size() == 0);
- general_defines = p_general_defines.utf8();
- for (int i = 0; i < p_variant_defines.size(); i++) {
-
- variant_defines.push_back(p_variant_defines[i].utf8());
- }
-}
-
-ShaderRD::~ShaderRD() {
- List<RID> remaining;
- version_owner.get_owned_list(&remaining);
- if (remaining.size()) {
- ERR_PRINT(itos(remaining.size()) + " shaders of type " + name + " were never freed");
- while (remaining.size()) {
- version_free(remaining.front()->get());
- remaining.pop_front();
- }
- }
-}
diff --git a/servers/visual/rasterizer_rd/shaders/SCsub b/servers/visual/rasterizer_rd/shaders/SCsub
deleted file mode 100644
index 2dcb2a703f..0000000000
--- a/servers/visual/rasterizer_rd/shaders/SCsub
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-
-Import('env')
-
-if 'RD_GLSL' in env['BUILDERS']:
- env.RD_GLSL('canvas.glsl');
- env.RD_GLSL('canvas_occlusion.glsl');
- env.RD_GLSL('blur.glsl');
- env.RD_GLSL('cubemap_roughness.glsl');
- env.RD_GLSL('cubemap_downsampler.glsl');
- env.RD_GLSL('cubemap_filter.glsl');
- env.RD_GLSL('scene_high_end.glsl');
- env.RD_GLSL('sky.glsl');
- env.RD_GLSL('tonemap.glsl');
- env.RD_GLSL('copy.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_minify.glsl');
- env.RD_GLSL('ssao_blur.glsl');
- env.RD_GLSL('roughness_limiter.glsl');
diff --git a/servers/visual/rasterizer_rd/shaders/blur.glsl b/servers/visual/rasterizer_rd/shaders/blur.glsl
deleted file mode 100644
index 87c20ebaef..0000000000
--- a/servers/visual/rasterizer_rd/shaders/blur.glsl
+++ /dev/null
@@ -1,294 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#version 450
-
-VERSION_DEFINES
-
-#include "blur_inc.glsl"
-
-layout(location = 0) out vec2 uv_interp;
-/* clang-format on */
-
-void main() {
-
- vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
- uv_interp = base_arr[gl_VertexIndex];
-
- if (bool(blur.flags & FLAG_USE_BLUR_SECTION)) {
- uv_interp = blur.section.xy + uv_interp * blur.section.zw;
- }
-
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
-
- if (bool(blur.flags & FLAG_FLIP_Y)) {
- uv_interp.y = 1.0 - uv_interp.y;
- }
-}
-
-/* clang-format off */
-[fragment]
-
-#version 450
-
-VERSION_DEFINES
-
-#include "blur_inc.glsl"
-
-layout(location = 0) in vec2 uv_interp;
-/* clang-format on */
-
-layout(set = 0, binding = 0) uniform sampler2D source_color;
-
-#ifdef MODE_SSAO_MERGE
-layout(set = 1, binding = 0) uniform sampler2D source_ssao;
-#endif
-
-#ifdef GLOW_USE_AUTO_EXPOSURE
-layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
-#endif
-
-layout(location = 0) out vec4 frag_color;
-
-//DOF
-#if defined(MODE_DOF_FAR_BLUR) || defined(MODE_DOF_NEAR_BLUR)
-
-layout(set = 1, binding = 0) uniform sampler2D dof_source_depth;
-
-#ifdef DOF_NEAR_BLUR_MERGE
-layout(set = 2, binding = 0) uniform sampler2D source_dof_original;
-#endif
-
-#ifdef DOF_QUALITY_LOW
-const int dof_kernel_size = 5;
-const int dof_kernel_from = 2;
-const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388);
-#endif
-
-#ifdef DOF_QUALITY_MEDIUM
-const int dof_kernel_size = 11;
-const int dof_kernel_from = 5;
-const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037);
-
-#endif
-
-#ifdef DOF_QUALITY_HIGH
-const int dof_kernel_size = 21;
-const int dof_kernel_from = 10;
-const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174);
-#endif
-
-#endif
-
-void main() {
-
-#ifdef MODE_MIPMAP
-
- vec2 pix_size = blur.pixel_size;
- vec4 color = texture(source_color, uv_interp + vec2(-0.5, -0.5) * pix_size);
- color += texture(source_color, uv_interp + vec2(0.5, -0.5) * pix_size);
- color += texture(source_color, uv_interp + vec2(0.5, 0.5) * pix_size);
- color += texture(source_color, uv_interp + vec2(-0.5, 0.5) * pix_size);
- frag_color = color / 4.0;
-
-#endif
-
-#ifdef MODE_GAUSSIAN_BLUR
-
- //Simpler blur uses SIGMA2 for the gaussian kernel for a stronger effect
-
- if (bool(blur.flags & FLAG_HORIZONTAL)) {
-
- vec2 pix_size = blur.pixel_size;
- pix_size *= 0.5; //reading from larger buffer, so use more samples
- vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.214607;
- color += texture(source_color, uv_interp + vec2(1.0, 0.0) * pix_size) * 0.189879;
- color += texture(source_color, uv_interp + vec2(2.0, 0.0) * pix_size) * 0.131514;
- color += texture(source_color, uv_interp + vec2(3.0, 0.0) * pix_size) * 0.071303;
- color += texture(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size) * 0.189879;
- color += texture(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size) * 0.131514;
- color += texture(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size) * 0.071303;
- frag_color = color;
- } else {
-
- vec2 pix_size = blur.pixel_size;
- vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.38774;
- color += texture(source_color, uv_interp + vec2(0.0, 1.0) * pix_size) * 0.24477;
- color += texture(source_color, uv_interp + vec2(0.0, 2.0) * pix_size) * 0.06136;
- color += texture(source_color, uv_interp + vec2(0.0, -1.0) * pix_size) * 0.24477;
- color += texture(source_color, uv_interp + vec2(0.0, -2.0) * pix_size) * 0.06136;
- frag_color = color;
- }
-#endif
-
-#ifdef MODE_GAUSSIAN_GLOW
-
- //Glow uses larger sigma 1 for a more rounded blur effect
-
-#define GLOW_ADD(m_ofs, m_mult) \
- { \
- vec2 ofs = uv_interp + m_ofs * pix_size; \
- vec4 c = texture(source_color, ofs) * m_mult; \
- if (any(lessThan(ofs, vec2(0.0))) || any(greaterThan(ofs, vec2(1.0)))) { \
- c *= 0.0; \
- } \
- color += c; \
- }
-
- if (bool(blur.flags & FLAG_HORIZONTAL)) {
-
- vec2 pix_size = blur.pixel_size;
- pix_size *= 0.5; //reading from larger buffer, so use more samples
- vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.174938;
- GLOW_ADD(vec2(1.0, 0.0), 0.165569);
- GLOW_ADD(vec2(2.0, 0.0), 0.140367);
- GLOW_ADD(vec2(3.0, 0.0), 0.106595);
- GLOW_ADD(vec2(-1.0, 0.0), 0.165569);
- GLOW_ADD(vec2(-2.0, 0.0), 0.140367);
- GLOW_ADD(vec2(-3.0, 0.0), 0.106595);
- color *= blur.glow_strength;
- frag_color = color;
- } else {
-
- vec2 pix_size = blur.pixel_size;
- vec4 color = texture(source_color, uv_interp + vec2(0.0, 0.0) * pix_size) * 0.288713;
- GLOW_ADD(vec2(0.0, 1.0), 0.233062);
- GLOW_ADD(vec2(0.0, 2.0), 0.122581);
- GLOW_ADD(vec2(0.0, -1.0), 0.233062);
- GLOW_ADD(vec2(0.0, -2.0), 0.122581);
- color *= blur.glow_strength;
- frag_color = color;
- }
-
-#undef GLOW_ADD
-
- if (bool(blur.flags & FLAG_GLOW_FIRST_PASS)) {
-#ifdef GLOW_USE_AUTO_EXPOSURE
-
- frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / blur.glow_auto_exposure_grey;
-#endif
- frag_color *= blur.glow_exposure;
-
- float luminance = max(frag_color.r, max(frag_color.g, frag_color.b));
- float feedback = max(smoothstep(blur.glow_hdr_threshold, blur.glow_hdr_threshold + blur.glow_hdr_scale, luminance), blur.glow_bloom);
-
- frag_color = min(frag_color * feedback, vec4(blur.glow_luminance_cap));
- }
-
-#endif
-
-#ifdef MODE_DOF_FAR_BLUR
-
- vec4 color_accum = vec4(0.0);
-
- float depth = texture(dof_source_depth, uv_interp, 0.0).r;
- depth = depth * 2.0 - 1.0;
-
- if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
- depth = ((depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
- } else {
- depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - depth * (blur.camera_z_far - blur.camera_z_near));
- }
-
- float amount = smoothstep(blur.dof_begin, blur.dof_end, depth);
- float k_accum = 0.0;
-
- for (int i = 0; i < dof_kernel_size; i++) {
-
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * amount * blur.dof_radius;
-
- float tap_k = dof_kernel[i];
-
- float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
-
- if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
-
- tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
- } else {
- tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near));
- }
-
- float tap_amount = mix(smoothstep(blur.dof_begin, blur.dof_end, tap_depth), 1.0, int_ofs == 0);
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
- vec4 tap_color = texture(source_color, tap_uv, 0.0) * tap_k;
-
- k_accum += tap_k * tap_amount;
- color_accum += tap_color * tap_amount;
- }
-
- if (k_accum > 0.0) {
- color_accum /= k_accum;
- }
-
- frag_color = color_accum; ///k_accum;
-
-#endif
-
-#ifdef MODE_DOF_NEAR_BLUR
-
- vec4 color_accum = vec4(0.0);
-
- float max_accum = 0.0;
-
- for (int i = 0; i < dof_kernel_size; i++) {
-
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + blur.dof_dir * float(int_ofs) * blur.dof_radius;
- float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from));
-
- float tap_k = dof_kernel[i];
-
- vec4 tap_color = texture(source_color, tap_uv, 0.0);
-
- float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
- if (bool(blur.flags & FLAG_USE_ORTHOGONAL_PROJECTION)) {
-
- tap_depth = ((tap_depth + (blur.camera_z_far + blur.camera_z_near) / (blur.camera_z_far - blur.camera_z_near)) * (blur.camera_z_far - blur.camera_z_near)) / 2.0;
- } else {
- tap_depth = 2.0 * blur.camera_z_near * blur.camera_z_far / (blur.camera_z_far + blur.camera_z_near - tap_depth * (blur.camera_z_far - blur.camera_z_near));
- }
- float tap_amount = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth);
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
- if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) {
- tap_color.a = 1.0 - smoothstep(blur.dof_end, blur.dof_begin, tap_depth);
- }
-
- max_accum = max(max_accum, tap_amount * ofs_influence);
-
- color_accum += tap_color * tap_k;
- }
-
- color_accum.a = max(color_accum.a, sqrt(max_accum));
-
-#ifdef DOF_NEAR_BLUR_MERGE
- {
- vec4 original = texture(source_dof_original, uv_interp, 0.0);
- color_accum = mix(original, color_accum, color_accum.a);
- }
-#endif
-
- if (bool(blur.flags & FLAG_DOF_NEAR_FIRST_TAP)) {
- frag_color = color_accum;
- }
-#endif
-
-#ifdef MODE_SIMPLE_COPY
- vec4 color = texture(source_color, uv_interp, 0.0);
- if (bool(blur.flags & FLAG_COPY_FORCE_LUMINANCE)) {
- color.rgb = vec3(max(max(color.r, color.g), color.b));
- }
- frag_color = color;
-#endif
-
-#ifdef MODE_SSAO_MERGE
- vec4 color = texture(source_color, uv_interp, 0.0);
- float ssao = texture(source_ssao, uv_interp, 0.0).r;
- frag_color = vec4(mix(color.rgb, color.rgb * mix(blur.ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0);
-
-#endif
-}
diff --git a/servers/visual/rasterizer_rd/shaders/blur_inc.glsl b/servers/visual/rasterizer_rd/shaders/blur_inc.glsl
deleted file mode 100644
index 33ba9de7bb..0000000000
--- a/servers/visual/rasterizer_rd/shaders/blur_inc.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-#define FLAG_HORIZONTAL (1 << 0)
-#define FLAG_USE_BLUR_SECTION (1 << 1)
-#define FLAG_USE_ORTHOGONAL_PROJECTION (1 << 2)
-#define FLAG_DOF_NEAR_FIRST_TAP (1 << 3)
-#define FLAG_GLOW_FIRST_PASS (1 << 4)
-#define FLAG_FLIP_Y (1 << 5)
-#define FLAG_COPY_FORCE_LUMINANCE (1 << 6)
-
-layout(push_constant, binding = 1, std430) uniform Blur {
- vec4 section;
- vec2 pixel_size;
- uint flags;
- uint pad;
- // Glow.
- float glow_strength;
- float glow_bloom;
- float glow_hdr_threshold;
- float glow_hdr_scale;
- float glow_exposure;
- float glow_white;
- float glow_luminance_cap;
- float glow_auto_exposure_grey;
- // DOF.
- float dof_begin;
- float dof_end;
- float dof_radius;
- float dof_pad;
-
- vec2 dof_dir;
- float camera_z_far;
- float camera_z_near;
-
- vec4 ssao_color;
-}
-blur;
diff --git a/servers/visual/rasterizer_rd/shaders/copy.glsl b/servers/visual/rasterizer_rd/shaders/copy.glsl
deleted file mode 100644
index cbb9b546a3..0000000000
--- a/servers/visual/rasterizer_rd/shaders/copy.glsl
+++ /dev/null
@@ -1,86 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(location = 0) out vec2 uv_interp;
-/* clang-format on */
-
-void main() {
-
- vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
- uv_interp = base_arr[gl_VertexIndex];
-
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
-}
-
-/* clang-format off */
-[fragment]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(location = 0) in vec2 uv_interp;
-/* clang-format on */
-
-#ifdef MODE_CUBE_TO_DP
-
-layout(set = 0, binding = 0) uniform samplerCube source_cube;
-
-layout(push_constant, binding = 0, std430) uniform Params {
- float bias;
- float z_far;
- float z_near;
- bool z_flip;
-}
-params;
-
-layout(location = 0) out float depth_buffer;
-
-#endif
-
-void main() {
-
-#ifdef MODE_CUBE_TO_DP
-
- vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0);
-
- normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
- normal = normalize(normal);
-
- normal.y = -normal.y; //needs to be flipped to match projection matrix
- if (!params.z_flip) {
- normal.z = -normal.z;
- }
-
- float depth = texture(source_cube, normal).r;
-
- // absolute values for direction cosines, bigger value equals closer to basis axis
- vec3 unorm = abs(normal);
-
- if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
- // x code
- unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
- } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
- // y code
- unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
- } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
- // z code
- unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
- } else {
- // oh-no we messed up code
- // has to be
- unorm = vec3(1.0, 0.0, 0.0);
- }
-
- float depth_fix = 1.0 / dot(normal, unorm);
-
- depth = 2.0 * depth - 1.0;
- float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
- depth_buffer = (linear_depth * depth_fix + params.bias) / params.z_far;
-
-#endif
-}
diff --git a/servers/visual/rasterizer_rd/shaders/cubemap_downsampler.glsl b/servers/visual/rasterizer_rd/shaders/cubemap_downsampler.glsl
deleted file mode 100644
index b042dc8868..0000000000
--- a/servers/visual/rasterizer_rd/shaders/cubemap_downsampler.glsl
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2016 Activision Publishing, Inc.
-//
-// 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.
-
-/* clang-format off */
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-#define BLOCK_SIZE 8
-
-layout(local_size_x = BLOCK_SIZE, local_size_y = BLOCK_SIZE, local_size_z = 1) in;
-/* clang-format on */
-
-#ifdef MODE_SOURCE_PANORAMA
-layout(set = 0, binding = 0) uniform sampler2D source_panorama;
-#endif
-
-#ifdef MODE_SOURCE_CUBEMAP
-layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
-#endif
-
-layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-void get_dir_0(out vec3 dir, in float u, in float v) {
- dir[0] = 1.0;
- dir[1] = v;
- dir[2] = -u;
-}
-void get_dir_1(out vec3 dir, in float u, in float v) {
- dir[0] = -1.0;
- dir[1] = v;
- dir[2] = u;
-}
-void get_dir_2(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = 1.0;
- dir[2] = -v;
-}
-void get_dir_3(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = -1.0;
- dir[2] = v;
-}
-void get_dir_4(out vec3 dir, in float u, in float v) {
- dir[0] = u;
- dir[1] = v;
- dir[2] = 1.0;
-}
-void get_dir_5(out vec3 dir, in float u, in float v) {
- dir[0] = -u;
- dir[1] = v;
- dir[2] = -1.0;
-}
-
-float calcWeight(float u, float v) {
- float val = u * u + v * v + 1.0;
- return val * sqrt(val);
-}
-
-#ifdef MODE_SOURCE_PANORAMA
-
-vec4 texturePanorama(vec3 normal, sampler2D pano) {
-
- vec2 st = vec2(
- atan(normal.x, -normal.z),
- acos(normal.y));
-
- if (st.x < 0.0)
- st.x += M_PI * 2.0;
-
- st /= vec2(M_PI * 2.0, M_PI);
-
- return textureLod(pano, st, 0.0);
-}
-
-#endif
-
-vec4 get_texture(vec3 p_dir) {
-#ifdef MODE_SOURCE_PANORAMA
- return texturePanorama(normalize(p_dir), source_panorama);
-#else
- return textureLod(source_cubemap, normalize(p_dir), 0.0);
-#endif
-}
-
-void main() {
- uvec3 id = gl_GlobalInvocationID;
- uint face_size = params.face_size;
-
- if (id.x < face_size && id.y < face_size) {
- float inv_face_size = 1.0 / float(face_size);
-
- float u0 = (float(id.x) * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
- float u1 = (float(id.x) * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
-
- float v0 = (float(id.y) * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
- float v1 = (float(id.y) * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
-
- float weights[4];
- weights[0] = calcWeight(u0, v0);
- weights[1] = calcWeight(u1, v0);
- weights[2] = calcWeight(u0, v1);
- weights[3] = calcWeight(u1, v1);
-
- const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
- for (int i = 0; i < 4; i++) {
- weights[i] = weights[i] * wsum + .125;
- }
-
- vec3 dir;
- vec4 color;
- switch (id.z) {
- case 0:
- get_dir_0(dir, u0, v0);
- color = get_texture(dir) * weights[0];
-
- get_dir_0(dir, u1, v0);
- color += get_texture(dir) * weights[1];
-
- get_dir_0(dir, u0, v1);
- color += get_texture(dir) * weights[2];
-
- get_dir_0(dir, u1, v1);
- color += get_texture(dir) * weights[3];
- break;
- case 1:
- get_dir_1(dir, u0, v0);
- color = get_texture(dir) * weights[0];
-
- get_dir_1(dir, u1, v0);
- color += get_texture(dir) * weights[1];
-
- get_dir_1(dir, u0, v1);
- color += get_texture(dir) * weights[2];
-
- get_dir_1(dir, u1, v1);
- color += get_texture(dir) * weights[3];
- break;
- case 2:
- get_dir_2(dir, u0, v0);
- color = get_texture(dir) * weights[0];
-
- get_dir_2(dir, u1, v0);
- color += get_texture(dir) * weights[1];
-
- get_dir_2(dir, u0, v1);
- color += get_texture(dir) * weights[2];
-
- get_dir_2(dir, u1, v1);
- color += get_texture(dir) * weights[3];
- break;
- case 3:
- get_dir_3(dir, u0, v0);
- color = get_texture(dir) * weights[0];
-
- get_dir_3(dir, u1, v0);
- color += get_texture(dir) * weights[1];
-
- get_dir_3(dir, u0, v1);
- color += get_texture(dir) * weights[2];
-
- get_dir_3(dir, u1, v1);
- color += get_texture(dir) * weights[3];
- break;
- case 4:
- get_dir_4(dir, u0, v0);
- color = get_texture(dir) * weights[0];
-
- get_dir_4(dir, u1, v0);
- color += get_texture(dir) * weights[1];
-
- get_dir_4(dir, u0, v1);
- color += get_texture(dir) * weights[2];
-
- get_dir_4(dir, u1, v1);
- color += get_texture(dir) * weights[3];
- break;
- default:
- get_dir_5(dir, u0, v0);
- color = get_texture(dir) * weights[0];
-
- get_dir_5(dir, u1, v0);
- color += get_texture(dir) * weights[1];
-
- get_dir_5(dir, u0, v1);
- color += get_texture(dir) * weights[2];
-
- get_dir_5(dir, u1, v1);
- color += get_texture(dir) * weights[3];
- break;
- }
- imageStore(dest_cubemap, ivec3(id), color);
- }
-} \ No newline at end of file
diff --git a/servers/visual/rasterizer_rd/shaders/cubemap_filter.glsl b/servers/visual/rasterizer_rd/shaders/cubemap_filter.glsl
deleted file mode 100644
index a7e51c1489..0000000000
--- a/servers/visual/rasterizer_rd/shaders/cubemap_filter.glsl
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2016 Activision Publishing, Inc.
-//
-// 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.
-
-/* clang-format off */
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-#define GROUP_SIZE 64
-
-layout(local_size_x = GROUP_SIZE, local_size_y = 1, local_size_z = 1) in;
-/* clang-format on */
-
-layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
-layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly imageCube dest_cubemap0;
-layout(rgba16f, set = 2, binding = 1) uniform restrict writeonly imageCube dest_cubemap1;
-layout(rgba16f, set = 2, binding = 2) uniform restrict writeonly imageCube dest_cubemap2;
-layout(rgba16f, set = 2, binding = 3) uniform restrict writeonly imageCube dest_cubemap3;
-layout(rgba16f, set = 2, binding = 4) uniform restrict writeonly imageCube dest_cubemap4;
-layout(rgba16f, set = 2, binding = 5) uniform restrict writeonly imageCube dest_cubemap5;
-layout(rgba16f, set = 2, binding = 6) uniform restrict writeonly imageCube dest_cubemap6;
-
-#ifdef USE_HIGH_QUALITY
-#define NUM_TAPS 32
-#else
-#define NUM_TAPS 8
-#endif
-
-#define BASE_RESOLUTION 128
-
-#ifdef USE_HIGH_QUALITY
-layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
- vec4[7][5][3][24] coeffs;
-}
-data;
-#else
-layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
- vec4[7][5][6] coeffs;
-}
-data;
-#endif
-
-void get_dir(out vec3 dir, in vec2 uv, in uint face) {
- switch (face) {
- case 0:
- dir = vec3(1.0, uv[1], -uv[0]);
- break;
- case 1:
- dir = vec3(-1.0, uv[1], uv[0]);
- break;
- case 2:
- dir = vec3(uv[0], 1.0, -uv[1]);
- break;
- case 3:
- dir = vec3(uv[0], -1.0, uv[1]);
- break;
- case 4:
- dir = vec3(uv[0], uv[1], 1.0);
- break;
- default:
- dir = vec3(-uv[0], uv[1], -1.0);
- break;
- }
-}
-
-void main() {
- // INPUT:
- // id.x = the linear address of the texel (ignoring face)
- // id.y = the face
- // -> use to index output texture
- // id.x = texel x
- // id.y = texel y
- // id.z = face
- uvec3 id = gl_GlobalInvocationID;
-
- // determine which texel this is
-#ifndef USE_TEXTURE_ARRAY
- int level = 0;
- if (id.x < (128 * 128)) {
- level = 0;
- } else if (id.x < (128 * 128 + 64 * 64)) {
- level = 1;
- id.x -= (128 * 128);
- } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32)) {
- level = 2;
- id.x -= (128 * 128 + 64 * 64);
- } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16)) {
- level = 3;
- id.x -= (128 * 128 + 64 * 64 + 32 * 32);
- } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8)) {
- level = 4;
- id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16);
- } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4)) {
- level = 5;
- id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8);
- } else if (id.x < (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2)) {
- level = 6;
- id.x -= (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8 + 4 * 4);
- } else {
- return;
- }
- int res = BASE_RESOLUTION >> level;
-#else // Using Texture Arrays so all levels are the same resolution
- int res = BASE_RESOLUTION;
- int level = int(id.x / (BASE_RESOLUTION * BASE_RESOLUTION));
- id.x -= level * BASE_RESOLUTION * BASE_RESOLUTION;
-#endif
-
- // determine dir / pos for the texel
- vec3 dir, adir, frameZ;
- {
- id.z = id.y;
- id.y = id.x / res;
- id.x -= id.y * res;
-
- vec2 uv;
- uv.x = (float(id.x) * 2.0 + 1.0) / float(res) - 1.0;
- uv.y = -(float(id.y) * 2.0 + 1.0) / float(res) + 1.0;
-
- get_dir(dir, uv, id.z);
- frameZ = normalize(dir);
-
- adir = abs(dir);
- }
-
- // GGX gather colors
- vec4 color = vec4(0.0);
- for (int axis = 0; axis < 3; axis++) {
- const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
- const int otherAxis1 = 2 - (axis >> 1);
-
- float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
- if (frameweight > 0.0) {
- // determine frame
- vec3 UpVector;
- switch (axis) {
- case 0:
- UpVector = vec3(1, 0, 0);
- break;
- case 1:
- UpVector = vec3(0, 1, 0);
- break;
- default:
- UpVector = vec3(0, 0, 1);
- break;
- }
-
- vec3 frameX = normalize(cross(UpVector, frameZ));
- vec3 frameY = cross(frameZ, frameX);
-
- // calculate parametrization for polynomial
- float Nx = dir[otherAxis0];
- float Ny = dir[otherAxis1];
- float Nz = adir[axis];
-
- float NmaxXY = max(abs(Ny), abs(Nx));
- Nx /= NmaxXY;
- Ny /= NmaxXY;
-
- float theta;
- if (Ny < Nx) {
- if (Ny <= -0.999)
- theta = Nx;
- else
- theta = Ny;
- } else {
- if (Ny >= 0.999)
- theta = -Nx;
- else
- theta = -Ny;
- }
-
- float phi;
- if (Nz <= -0.999)
- phi = -NmaxXY;
- else if (Nz >= 0.999)
- phi = NmaxXY;
- else
- phi = Nz;
-
- float theta2 = theta * theta;
- float phi2 = phi * phi;
-
- // sample
- for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
- const int index = (NUM_TAPS / 4) * axis + iSuperTap;
-
-#ifdef USE_HIGH_QUALITY
- vec4 coeffsDir0[3];
- vec4 coeffsDir1[3];
- vec4 coeffsDir2[3];
- vec4 coeffsLevel[3];
- vec4 coeffsWeight[3];
-
- for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
- coeffsDir0[iCoeff] = data.coeffs[level][0][iCoeff][index];
- coeffsDir1[iCoeff] = data.coeffs[level][1][iCoeff][index];
- coeffsDir2[iCoeff] = data.coeffs[level][2][iCoeff][index];
- coeffsLevel[iCoeff] = data.coeffs[level][3][iCoeff][index];
- coeffsWeight[iCoeff] = data.coeffs[level][4][iCoeff][index];
- }
-
- for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
- // determine sample attributes (dir, weight, level)
- vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
-
- float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
-
- float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
-#else
- vec4 coeffsDir0 = data.coeffs[level][0][index];
- vec4 coeffsDir1 = data.coeffs[level][1][index];
- vec4 coeffsDir2 = data.coeffs[level][2][index];
- vec4 coeffsLevel = data.coeffs[level][3][index];
- vec4 coeffsWeight = data.coeffs[level][4][index];
-
- for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
- // determine sample attributes (dir, weight, level)
- vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
-
- float sample_level = coeffsLevel[iSubTap];
-
- float sample_weight = coeffsWeight[iSubTap];
-#endif
-
- sample_weight *= frameweight;
-
- // adjust for jacobian
- sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
- sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
-#ifndef USE_TEXTURE_ARRAY
- sample_level += float(level) / 6.0; // Hack to increase the perceived roughness and reduce upscaling artifacts
-#endif
- // sample cubemap
- color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
- color.w += sample_weight;
- }
- }
- }
- }
- color /= color.w;
-
- // write color
- color.xyz = max(vec3(0.0), color.xyz);
- color.w = 1.0;
-
- switch (level) {
- case 0:
- imageStore(dest_cubemap0, ivec3(id), color);
- break;
- case 1:
- imageStore(dest_cubemap1, ivec3(id), color);
- break;
- case 2:
- imageStore(dest_cubemap2, ivec3(id), color);
- break;
- case 3:
- imageStore(dest_cubemap3, ivec3(id), color);
- break;
- case 4:
- imageStore(dest_cubemap4, ivec3(id), color);
- break;
- case 5:
- imageStore(dest_cubemap5, ivec3(id), color);
- break;
- default:
- imageStore(dest_cubemap6, ivec3(id), color);
- break;
- }
-} \ No newline at end of file
diff --git a/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl b/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl
deleted file mode 100644
index 3dba143e56..0000000000
--- a/servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl
+++ /dev/null
@@ -1,184 +0,0 @@
-/* clang-format off */
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-#define GROUP_SIZE 8
-
-layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in;
-/* clang-format on */
-
-#ifdef MODE_SOURCE_PANORAMA
-layout(set = 0, binding = 0) uniform sampler2D source_panorama;
-#endif
-
-#ifdef MODE_SOURCE_CUBEMAP
-layout(set = 0, binding = 0) uniform samplerCube source_cube;
-#endif
-
-layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
-
-layout(push_constant, binding = 1, std430) uniform Params {
- uint face_id;
- uint sample_count;
- float roughness;
- bool use_direct_write;
- float face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-vec3 texelCoordToVec(vec2 uv, uint faceID) {
- mat3 faceUvVectors[6];
-
- // -x
- faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-
- // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
- return normalize(result);
-}
-
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
- float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
-
- // Compute distribution direction
- float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
- float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
-
- // Convert to spherical direction
- vec3 H;
- H.x = SinTheta * cos(Phi);
- H.y = SinTheta * sin(Phi);
- H.z = CosTheta;
-
- vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
- vec3 TangentX = normalize(cross(UpVector, N));
- vec3 TangentY = cross(N, TangentX);
-
- // Tangent to world space
- return TangentX * H.x + TangentY * H.y + N * H.z;
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a) {
- float k = a / 2.0;
- return NdotV / (NdotV * (1.0 - k) + k);
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL) {
- return GGX(nDotL, a * a) * GGX(nDotV, a * a);
-}
-
-float radicalInverse_VdC(uint bits) {
- bits = (bits << 16u) | (bits >> 16u);
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
-}
-
-vec2 Hammersley(uint i, uint N) {
- return vec2(float(i) / float(N), radicalInverse_VdC(i));
-}
-
-#ifdef MODE_SOURCE_PANORAMA
-
-vec4 texturePanorama(vec3 normal, sampler2D pano) {
-
- vec2 st = vec2(
- atan(normal.x, -normal.z),
- acos(normal.y));
-
- if (st.x < 0.0)
- st.x += M_PI * 2.0;
-
- st /= vec2(M_PI * 2.0, M_PI);
-
- return textureLod(pano, st, 0.0);
-}
-
-#endif
-
-void main() {
- uvec3 id = gl_GlobalInvocationID;
- id.z += params.face_id;
-
- vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0);
- vec3 N = texelCoordToVec(uv, id.z);
-
- //vec4 color = color_interp;
-
- if (params.use_direct_write) {
-
-#ifdef MODE_SOURCE_PANORAMA
- imageStore(dest_cubemap, ivec3(id), vec4(texturePanorama(N, source_panorama).rgb, 1.0));
-#endif
-
-#ifdef MODE_SOURCE_CUBEMAP
- imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0));
-
-#endif
-
- } else {
-
- vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
-
- for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
- vec2 xi = Hammersley(sampleNum, params.sample_count);
-
- vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
- vec3 V = N;
- vec3 L = (2.0 * dot(V, H) * H - V);
-
- float ndotl = clamp(dot(N, L), 0.0, 1.0);
-
- if (ndotl > 0.0) {
-#ifdef MODE_SOURCE_PANORAMA
- sum.rgb += texturePanorama(L, source_panorama).rgb * ndotl;
-#endif
-
-#ifdef MODE_SOURCE_CUBEMAP
- sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
-#endif
- sum.a += ndotl;
- }
- }
- sum /= sum.a;
-
- imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0));
- }
-}
diff --git a/servers/visual/rasterizer_rd/shaders/scene_high_end.glsl b/servers/visual/rasterizer_rd/shaders/scene_high_end.glsl
deleted file mode 100644
index 07f4770b14..0000000000
--- a/servers/visual/rasterizer_rd/shaders/scene_high_end.glsl
+++ /dev/null
@@ -1,1718 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#version 450
-
-VERSION_DEFINES
-
-#include "scene_high_end_inc.glsl"
-
-/* INPUT ATTRIBS */
-
-layout(location = 0) in vec3 vertex_attrib;
-/* clang-format on */
-layout(location = 1) in vec3 normal_attrib;
-#if defined(TANGENT_USED) || defined(NORMALMAP_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
-
-#if defined(UV_USED)
-layout(location = 4) in vec2 uv_attrib;
-#endif
-
-#if defined(UV2_USED) || defined(USE_LIGHTMAP)
-layout(location = 5) in vec2 uv2_attrib;
-#endif
-
-layout(location = 6) in uvec4 bone_attrib; // always bound, even if unused
-
-/* Varyings */
-
-layout(location = 0) out vec3 vertex_interp;
-layout(location = 1) out vec3 normal_interp;
-
-#if defined(COLOR_USED)
-layout(location = 2) out vec4 color_interp;
-#endif
-
-#if defined(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(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) out vec3 tangent_interp;
-layout(location = 6) out vec3 binormal_interp;
-#endif
-
-#ifdef USE_MATERIAL_UNIFORMS
-layout(set = 5, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
-} material;
-#endif
-
-/* clang-format off */
-
-VERTEX_SHADER_GLOBALS
-
-/* clang-format on */
-
-// FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now.
-// See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316
-invariant gl_Position;
-
-layout(location = 7) flat out uint instance_index;
-
-#ifdef MODE_DUAL_PARABOLOID
-
-layout(location = 8) out float dp_clip;
-
-#endif
-
-void main() {
-
- instance_index = draw_call.instance_index;
- vec4 instance_custom = vec4(0.0);
-#if defined(COLOR_USED)
- color_interp = color_attrib;
-#endif
-
- mat4 world_matrix = instances.data[instance_index].transform;
- mat3 world_normal_matrix = mat3(instances.data[instance_index].normal_transform);
-
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_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;
- 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;
- } 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(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) {
-#ifdef COLOR_USED
- color_interp *= transforms.data[offset];
-#endif
- offset += 1;
- }
-
- if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) {
- instance_custom = transforms.data[offset];
- }
-
- //transpose
- matrix = transpose(matrix);
- world_matrix = world_matrix * matrix;
- world_normal_matrix = world_normal_matrix * mat3(matrix);
-
- } else {
- //not a multimesh, instances are for multiple draw calls
- instance_index += gl_InstanceIndex;
- }
-
- vec3 vertex = vertex_attrib;
- vec3 normal = normal_attrib;
-
-#if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec3 tangent = tangent_attrib.xyz;
- float binormalf = tangent_attrib.a;
- vec3 binormal = normalize(cross(normal, tangent) * binormalf);
-#endif
-
- 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(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-
- tangent = (vec4(tangent, 0.0) * m).xyz;
- binormal = (vec4(binormal, 0.0) * m).xyz;
-#endif
- }
-
-#if defined(UV_USED)
- uv_interp = uv_attrib;
-#endif
-
-#if defined(UV2_USED) || defined(USE_LIGHTMAP)
- uv2_interp = uv2_attrib;
-#endif
-
-#ifdef USE_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(NORMALMAP_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;
-
- {
- /* clang-format off */
-
-VERTEX_SHADER_CODE
-
- /* clang-format on */
- }
-
-// using local coordinates (default)
-#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
-
- vertex = (modelview * vec4(vertex, 1.0)).xyz;
- normal = modelview_normal * normal;
-#endif
-
-#if defined(TANGENT_USED) || defined(NORMALMAP_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(NORMALMAP_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;
- normal_interp = normal;
-
-#if defined(TANGENT_USED) || defined(NORMALMAP_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;
- normal_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 + normalize(vertex_interp) * scene_data.z_offset;
- 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;
-#else
-
- float z_ofs = scene_data.z_offset;
- z_ofs += max(0.0, 1.0 - abs(normalize(normal_interp).z)) * scene_data.z_slope_scale;
- vertex_interp.z -= z_ofs;
-
-#endif
-
-#endif //MODE_RENDER_DEPTH
-
-#ifdef USE_OVERRIDE_POSITION
- gl_Position = position;
-#else
- gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
-#endif
-}
-
-/* clang-format off */
-[fragment]
-
-#version 450
-
-VERSION_DEFINES
-
-#include "scene_high_end_inc.glsl"
-
-/* Varyings */
-
-layout(location = 0) in vec3 vertex_interp;
-/* clang-format on */
-layout(location = 1) in vec3 normal_interp;
-
-#if defined(COLOR_USED)
-layout(location = 2) in vec4 color_interp;
-#endif
-
-#if defined(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(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 5) in vec3 tangent_interp;
-layout(location = 6) in vec3 binormal_interp;
-#endif
-
-layout(location = 7) flat in uint instance_index;
-
-#ifdef MODE_DUAL_PARABOLOID
-
-layout(location = 8) in float dp_clip;
-
-#endif
-
-//defines to keep compatibility with vertex
-
-#define world_matrix instances.data[instance_index].transform
-#define world_normal_matrix instances.data[instance_index].normal_transform
-#define projection_matrix scene_data.projection_matrix
-
-#ifdef USE_MATERIAL_UNIFORMS
-layout(set = 5, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
-} material;
-#endif
-
-/* clang-format off */
-
-FRAGMENT_SHADER_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
-
-#ifdef MODE_RENDER_NORMAL
-layout(location = 0) out vec4 normal_output_buffer;
-#ifdef MODE_RENDER_ROUGHNESS
-layout(location = 1) out float roughness_output_buffer;
-#endif //MODE_RENDER_ROUGHNESS
-#endif //MODE_RENDER_NORMAL
-#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
-
-#endif // RENDER DEPTH
-
-// 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).
-
-#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, vec3 attenuation, vec3 diffuse_color, float roughness, float metallic, float specular, float specular_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- vec3 transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- float clearcoat, float clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- vec3 B, vec3 T, float anisotropy,
-#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 albedo = diffuse_color;
- vec3 light = L;
- vec3 view = V;
-
- /* clang-format off */
-
-LIGHT_SHADER_CODE
-
- /* clang-format on */
-
-#else
- float NdotL = dot(N, L);
- 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)
- float cNdotH = max(dot(N, H), 0.0);
-#endif
-
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
- float cLdotH = max(dot(L, H), 0.0);
-#endif
-
- if (metallic < 1.0) {
-#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_OREN_NAYAR)
-
- {
- // see http://mimosa-pudica.net/improved-oren-nayar.html
- float LdotV = dot(L, V);
-
- float s = LdotV - NdotL * NdotV;
- float t = mix(1.0, max(NdotL, NdotV), step(0.0, s));
-
- float sigma2 = roughness * roughness; // TODO: this needs checking
- vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13));
- float B = 0.45 * sigma2 / (sigma2 + 0.09);
-
- diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI);
- }
-
-#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_color * diffuse_brdf_NL * attenuation;
-
-#if defined(LIGHT_TRANSMISSION_USED)
- diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * 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), diffuse_color, rim_tint) * light_color;
-#endif
- }
-
- 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 * specular_blob_intensity * attenuation;
-
-#elif defined(SPECULAR_PHONG)
-
- vec3 R = normalize(-reflect(L, N));
- float cRdotV = max(0.0, dot(R, V));
- 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 * specular_blob_intensity * attenuation;
-
-#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 * specular_blob_intensity * attenuation; // 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
- vec3 f0 = F0(metallic, specular, diffuse_color);
- 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 * specular_blob_intensity * attenuation;
-#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 * specular_blob_intensity * attenuation;
-#endif
- }
-
-#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0));
-#endif
-
-#endif //defined(USE_LIGHT_SHADER_CODE)
-}
-
-#ifndef USE_NO_SHADOWS
-
-float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
-
- //todo optimize
- vec2 pos = coord.xy;
- float depth = coord.z;
-
-#ifdef SHADOW_MODE_PCF_13
-
- float avg = textureProj(shadow, vec4(pos, depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0));
- return avg * (1.0 / 13.0);
-#endif
-
-#ifdef SHADOW_MODE_PCF_5
-
- float avg = textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0));
- avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0));
- return avg * (1.0 / 5.0);
-
-#endif
-
-#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13)
-
- return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
-
-#endif
-}
-
-#endif //USE_NO_SHADOWS
-
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- vec3 transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint,
-#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 = lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- float normalized_distance = light_length * lights.data[idx].inv_radius;
- vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy);
- float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x);
- vec3 light_attenuation = vec3(omni_attenuation);
- vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
- color_specular.rgb *= attenuation_energy.y;
-
-#ifndef USE_NO_SHADOWS
- vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled);
- if (shadow_color_enabled.w > 0.5) {
- // there is a shadowmap
-
- vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
- float shadow_len = length(splane);
- splane = normalize(splane);
- vec4 clamp_rect = 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 * 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 = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
-
- light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
- }
-#endif //USE_NO_SHADOWS
-
- light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- rim * omni_attenuation, rim_tint,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light,
- specular_light);
-}
-
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- vec3 transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- float rim, float rim_tint,
-#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 = lights.data[idx].position - vertex;
- float light_length = length(light_rel_vec);
- float normalized_distance = light_length * lights.data[idx].inv_radius;
- vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy);
- float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x);
- vec3 spot_dir = lights.data[idx].direction;
- vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle);
- float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y);
- float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_att_angle.y));
- spot_attenuation *= 1.0 - pow(spot_rim, spot_att_angle.x);
- vec3 light_attenuation = vec3(spot_attenuation);
- vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
- color_specular.rgb *= attenuation_energy.y;
-
-/*
- if (lights.data[idx].atlas_rect!=vec4(0.0)) {
- //use projector texture
- }
- */
-#ifndef USE_NO_SHADOWS
- vec4 shadow_color_enabled = unpackUnorm4x8(lights.data[idx].shadow_color_enabled);
- if (shadow_color_enabled.w > 0.5) {
- //there is a shadowmap
- vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
- splane /= splane.w;
- float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
-
- light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
- }
-
-#endif //USE_NO_SHADOWS
-
- light_compute(normal, normalize(light_rel_vec), eye_vec, color_specular.rgb, light_attenuation, albedo, roughness, metallic, specular, color_specular.a * p_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- rim * spot_attenuation, rim_tint,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#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].params.x > 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].params.w > 0.5) { //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].params.z < 0.5) {
- reflection.rgb = mix(specular_light, reflection.rgb, blend);
- }
-
- reflection.rgb *= reflections.data[ref_index].params.x;
- reflection.a = blend;
- reflection.rgb *= reflection.a;
-
- reflection_accum += reflection;
- }
-
-#if !defined(USE_LIGHTMAP) && !defined(USE_VOXEL_CONE_TRACING)
- if (reflections.data[ref_index].ambient.a > 0.0) { //compute ambient using skybox
-
- 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;
- ambient_out.rgb = mix(reflections.data[ref_index].ambient.rgb, ambient_out.rgb, reflections.data[ref_index].ambient.a);
- if (reflections.data[ref_index].params.z < 0.5) {
- ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
- }
-
- ambient_out.rgb *= ambient_out.a;
- ambient_accum += ambient_out;
- } else {
-
- vec4 ambient_out;
- ambient_out.a = blend;
- ambient_out.rgb = reflections.data[ref_index].ambient.rgb;
- if (reflections.data[ref_index].params.z < 0.5) {
- ambient_out.rgb = mix(ambient_light, ambient_out.rgb, blend);
- }
- ambient_out.rgb *= ambient_out.a;
- ambient_accum += ambient_out;
- }
-#endif //USE_LIGHTMAP or VCT
-}
-
-#ifdef USE_VOXEL_CONE_TRACING
-
-//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;
-}
-
-#ifndef GI_PROBE_HIGH_QUALITY
-//faster version for 45 degrees
-
-#ifdef GI_PROBE_USE_ANISOTROPY
-
-vec4 voxel_cone_trace_anisotropic_45_degrees(texture3D probe, texture3D aniso_pos, texture3D aniso_neg, vec3 normal, 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);
- vec3 aniso_neg = textureLod(sampler3D(aniso_neg, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
- vec3 aniso_pos = textureLod(sampler3D(aniso_pos, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, lod_level).rgb;
-
- scolor.rgb *= dot(max(vec3(0.0), (normal * aniso_pos)), vec3(1.0)) + dot(max(vec3(0.0), (-normal * aniso_neg)), vec3(1.0));
- 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;
-}
-#else
-
-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;
-}
-
-#endif
-
-#elif defined(GI_PROBE_USE_ANISOTROPY)
-
-//standard voxel cone trace
-vec4 voxel_cone_trace_anisotropic(texture3D probe, texture3D aniso_pos, texture3D aniso_neg, vec3 normal, 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;
- }
- float log2_diameter = log2(diameter);
- vec4 scolor = textureLod(sampler3D(probe, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter);
- vec3 aniso_neg = textureLod(sampler3D(aniso_neg, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
- vec3 aniso_pos = textureLod(sampler3D(aniso_pos, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), uvw_pos, log2_diameter).rgb;
-
- scolor.rgb *= dot(max(vec3(0.0), (normal * aniso_pos)), vec3(1.0)) + dot(max(vec3(0.0), (-normal * aniso_neg)), vec3(1.0));
-
- float a = (1.0 - color.a);
- scolor *= a;
- color += scolor;
- dist += half_diameter;
- }
-
- return color;
-}
-
-#endif
-
-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
-
-#ifdef GI_PROBE_HIGH_QUALITY
-
-#define MAX_CONE_DIRS 6
- vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
- vec3(0.0, 0.0, 1.0),
- vec3(0.866025, 0.0, 0.5),
- vec3(0.267617, 0.823639, 0.5),
- vec3(-0.700629, 0.509037, 0.5),
- vec3(-0.700629, -0.509037, 0.5),
- vec3(0.267617, -0.823639, 0.5));
-
- float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
- float cone_angle_tan = 0.577;
-
-#elif defined(GI_PROBE_LOW_QUALITY)
-
-#define MAX_CONE_DIRS 1
-
- vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
- vec3(0.0, 0.0, 1.0));
-
- float cone_weights[MAX_CONE_DIRS] = float[](1.0);
- float cone_angle_tan = 4; //~76 degrees
-#else // MEDIUM QUALITY
-
-#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;
-
-#endif
- 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);
-
-#if defined(GI_PROBE_HIGH_QUALITY) || defined(GI_PROBE_LOW_QUALITY)
-
-#ifdef GI_PROBE_USE_ANISOTROPY
- vec4 cone_light = voxel_cone_trace_anisotropic(gi_probe_textures[gi_probes.data[index].texture_slot], gi_probe_textures[gi_probes.data[index].texture_slot + 1], gi_probe_textures[gi_probes.data[index].texture_slot + 2], normalize(mix(dir, normal, gi_probes.data[index].anisotropy_strength)), cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
-#else
-
- vec4 cone_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
-
-#endif // GI_PROBE_USE_ANISOTROPY
-
-#else
-
-#ifdef GI_PROBE_USE_ANISOTROPY
- vec4 cone_light = voxel_cone_trace_anisotropic_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot], gi_probe_textures[gi_probes.data[index].texture_slot + 1], gi_probe_textures[gi_probes.data[index].texture_slot + 2], normalize(mix(dir, normal, gi_probes.data[index].anisotropy_strength)), cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
-#else
- vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[gi_probes.data[index].texture_slot], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias);
-#endif // GI_PROBE_USE_ANISOTROPY
-
-#endif
- 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;
-
- if (gi_probes.data[index].ambient_occlusion > 0.001) {
-
- float size = 1.0 + gi_probes.data[index].ambient_occlusion_size * 7.0;
-
- float taps, blend;
- blend = modf(size, taps);
- float ao = 0.0;
- for (float i = 1.0; i <= taps; i++) {
- vec3 ofs = (position + normal * (i * 0.5 + 1.0)) * cell_size;
- ao += textureLod(sampler3D(gi_probe_textures[gi_probes.data[index].texture_slot], material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ofs, i - 1.0).a * i;
- }
-
- if (blend > 0.001) {
- vec3 ofs = (position + normal * ((taps + 1.0) * 0.5 + 1.0)) * cell_size;
- ao += textureLod(sampler3D(gi_probe_textures[gi_probes.data[index].texture_slot], material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ofs, taps).a * (taps + 1.0) * blend;
- }
-
- ao = 1.0 - min(1.0, ao);
-
- light = mix(scene_data.ao_color.rgb, light, mix(1.0, ao, gi_probes.data[index].ambient_occlusion));
- }
-
- out_diff += vec4(light * blend, blend);
-
- //irradiance
-#ifndef GI_PROBE_LOW_QUALITY
- vec4 irr_light = voxel_cone_trace(gi_probe_textures[gi_probes.data[index].texture_slot], 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);
-#endif
-}
-
-#endif //USE_VOXEL_CONE_TRACING
-
-#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-
-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 transmission = vec3(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);
-
-#if defined(AO_USED)
- float ao = 1.0;
- float ao_light_affect = 0.0;
-#endif
-
- float alpha = 1.0;
-
-#if defined(ALPHA_SCISSOR_USED)
- float alpha_scissor = 0.5;
-#endif
-
-#if defined(TANGENT_USED) || defined(NORMALMAP_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
- vec3 normal = normalize(normal_interp);
-
-#if defined(DO_SIDE_CHECK)
- if (!gl_FrontFacing) {
- normal = -normal;
- }
-#endif
-
-#if defined(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(NORMALMAP_USED)
-
- vec3 normalmap = vec3(0.5);
-#endif
-
- float normaldepth = 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;
-
- {
- /* clang-format off */
-
-FRAGMENT_SHADER_CODE
-
- /* clang-format on */
- }
-
-#if !defined(USE_SHADOW_TO_OPACITY)
-
-#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
-
-#if defined(NORMALMAP_USED)
-
- normalmap.xy = normalmap.xy * 2.0 - 1.0;
- normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
-
- normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth));
-
-#endif
-
-#if defined(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
-
- /////////////////////// LIGHTING //////////////////////////////
-
- //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.roughness_limiter_enabled) {
- float limit = texelFetch(sampler2D(roughness_buffer, material_samplers[SAMPLER_NEAREST_CLAMP]), ivec2(gl_FragCoord.xy), 0).r;
- roughness = max(roughness, limit);
- }
-
- 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
- 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;
- }
-
-#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
-
-#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
-
- //radiance
-
- float specular_blob_intensity = 1.0;
-
-#if defined(SPECULAR_TOON)
- specular_blob_intensity *= specular * 2.0;
-#endif
-
-#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
- //gi probes
-
- //lightmap
-
- //lightmap capture
-
-#ifdef USE_VOXEL_CONE_TRACING
- { // process giprobes
- uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
- if (index1 != 0xFFFF) {
- vec3 ref_vec = normalize(reflect(normalize(vertex), normal));
- //find arbitrary tangent and bitangent, then build a matrix
- 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));
- mat3 normal_mat = mat3(tangent, bitangent, normal);
-
- vec4 amb_accum = vec4(0.0);
- vec4 spec_accum = vec4(0.0);
- gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
-
- uint index2 = instances.data[instance_index].gi_offset >> 16;
-
- if (index2 != 0xFFFF) {
- gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum);
- }
-
- if (amb_accum.a > 0.0) {
- amb_accum.rgb /= amb_accum.a;
- }
-
- if (spec_accum.a > 0.0) {
- spec_accum.rgb /= spec_accum.a;
- }
-
- specular_light = spec_accum.rgb;
- ambient_light = amb_accum.rgb;
- }
- }
-#endif
-
- uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)));
-
- { // process reflections
-
- 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_probe_count = cluster_cell.z >> CLUSTER_COUNTER_SHIFT;
- uint reflection_probe_pointer = cluster_cell.z & CLUSTER_POINTER_MASK;
-
- for (uint i = 0; i < reflection_probe_count; i++) {
-
- uint ref_index = cluster_data.indices[reflection_probe_pointer + i];
- reflection_process(ref_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;
- }
-
-#if !defined(USE_LIGHTMAP)
- if (ambient_accum.a > 0.0) {
- ambient_light = ambient_accum.rgb / ambient_accum.a;
- }
-#endif
- }
-
- {
-
-#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;
-
- vec3 f0 = F0(metallic, specular, albedo);
- specular_light *= env.x * f0 + env.y;
-#endif
- }
-
- { //directional light
-
- for (uint i = 0; i < scene_data.directional_light_count; i++) {
-
- if (!bool(directional_lights.data[i].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
-
- vec3 light_attenuation = vec3(1.0);
-
- if (directional_lights.data[i].shadow_enabled) {
- float depth_z = -vertex.z;
-
- vec4 pssm_coord;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- pssm_coord = (directional_lights.data[i].shadow_matrix1 * vec4(vertex, 1.0));
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * vec4(vertex, 1.0));
- } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * vec4(vertex, 1.0));
- } else {
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * vec4(vertex, 1.0));
- }
-
- pssm_coord /= pssm_coord.w;
-
- float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
-
- if (directional_lights.data[i].blend_splits) {
-
- float pssm_blend;
-
- if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
- pssm_coord = (directional_lights.data[i].shadow_matrix2 * vec4(vertex, 1.0));
- 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) {
- pssm_coord = (directional_lights.data[i].shadow_matrix3 * vec4(vertex, 1.0));
- 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) {
- pssm_coord = (directional_lights.data[i].shadow_matrix4 * vec4(vertex, 1.0));
- 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_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, 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
-
- light_attenuation = mix(directional_lights.data[i].shadow_color, vec3(1.0), shadow);
- }
-
- light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, light_attenuation, albedo, roughness, metallic, specular, directional_lights.data[i].specular * specular_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- rim, rim_tint,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
- clearcoat, clearcoat_gloss,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
- binormal, tangent, anisotropy,
-#endif
-#ifdef USE_SHADOW_TO_OPACITY
- alpha,
-#endif
- diffuse_light,
- specular_light);
- }
- }
-
- { //omni lights
-
- uint omni_light_count = cluster_cell.x >> CLUSTER_COUNTER_SHIFT;
- uint omni_light_pointer = cluster_cell.x & CLUSTER_POINTER_MASK;
-
- for (uint i = 0; i < omni_light_count; i++) {
-
- uint light_index = cluster_data.indices[omni_light_pointer + i];
-
- if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
-
- light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
-#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
- uint spot_light_count = cluster_cell.y >> CLUSTER_COUNTER_SHIFT;
- uint spot_light_pointer = cluster_cell.y & CLUSTER_POINTER_MASK;
-
- for (uint i = 0; i < spot_light_count; i++) {
-
- uint light_index = cluster_data.indices[spot_light_pointer + i];
-
- if (!bool(lights.data[light_index].mask & instances.data[instance_index].layer_mask)) {
- continue; //not masked
- }
-
- light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity,
-#ifdef LIGHT_TRANSMISSION_USED
- transmission,
-#endif
-#ifdef LIGHT_RIM_USED
- rim,
- rim_tint,
-#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);
- }
- }
-
-#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;
-
-#if defined(AO_USED)
- orm_output_buffer.r = ao;
-#else
- orm_output_buffer.r = 0.0;
-#endif
- 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
-
-#ifdef MODE_RENDER_NORMAL
- normal_output_buffer = vec4(normal * 0.5 + 0.5, 0.0);
-#ifdef MODE_RENDER_ROUGHNESS
- roughness_output_buffer = roughness;
-#endif //MODE_RENDER_ROUGHNESS
-#endif //MODE_RENDER_NORMAL
-
-//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
-#else
-
- specular_light *= scene_data.reflection_multiplier;
- ambient_light *= albedo; //ambient must be multiplied by albedo at the end
-
-//ambient occlusion
-#if defined(AO_USED)
-
- if (scene_data.ssao_enabled && scene_data.ssao_ao_affect > 0.0) {
- float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
- ao = mix(ao, min(ao, ssao), scene_data.ssao_ao_affect);
- ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect);
- }
-
- ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao);
- ao_light_affect = mix(1.0, ao, ao_light_affect);
- specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect);
- diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect);
-
-#else
-
- if (scene_data.ssao_enabled) {
- float ao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
- ambient_light = mix(scene_data.ao_color.rgb, ambient_light, ao);
- float ao_light_affect = mix(1.0, ao, scene_data.ssao_light_affect);
- specular_light = mix(scene_data.ao_color.rgb, specular_light, ao_light_affect);
- diffuse_light = mix(scene_data.ao_color.rgb, diffuse_light, ao_light_affect);
- }
-
-#endif // AO_USED
-
- // base color remapping
- diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point
- ambient_light *= 1.0 - metallic;
-
- //fog
-
-#ifdef MODE_MULTIPLE_RENDER_TARGETS
-
-#ifdef MODE_UNSHADED
- diffuse_buffer = vec4(albedo.rgb, 0.0);
- specular_buffer = vec4(0.0);
-
-#else
-
- diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength);
- specular_buffer = vec4(specular_light, metallic);
-
-#endif
-
-#else //MODE_MULTIPLE_RENDER_TARGETS
-
-#ifdef MODE_UNSHADED
- frag_color = vec4(albedo, alpha);
-#else
- frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
- //frag_color = vec4(1.0);
-
-#endif //USE_NO_SHADING
-
-#endif //MODE_MULTIPLE_RENDER_TARGETS
-
-#endif //MODE_RENDER_DEPTH
-}
diff --git a/servers/visual/rasterizer_rd/shaders/scene_high_end_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_high_end_inc.glsl
deleted file mode 100644
index baef1e060f..0000000000
--- a/servers/visual/rasterizer_rd/shaders/scene_high_end_inc.glsl
+++ /dev/null
@@ -1,266 +0,0 @@
-#define M_PI 3.14159265359
-#define ROUGHNESS_MAX_LOD 5
-
-layout(push_constant, binding = 0, std430) uniform DrawCall {
- uint instance_index;
- uint pad[3]; //16 bits minimum size
-}
-draw_call;
-
-/* Set 0 Scene data that never changes, ever */
-
-#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;
-
-layout(set = 0, binding = 3, std140) uniform SceneData {
-
- mat4 projection_matrix;
- mat4 inv_projection_matrix;
-
- mat4 camera_matrix;
- mat4 inv_camera_matrix;
-
- vec2 viewport_size;
- vec2 screen_pixel_size;
-
- //used for shadow mapping only
- float z_offset;
- float z_slope_scale;
-
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
-
- 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;
-
- vec4 ao_color;
-
-#if 0
- vec4 ambient_light_color;
- vec4 bg_color;
-
- vec4 fog_color_enabled;
- vec4 fog_sun_color_amount;
-
- float ambient_energy;
- float bg_energy;
-#endif
-
-#if 0
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
-
- float z_far;
-
- float subsurface_scatter_width;
- float ambient_occlusion_affect_light;
- float ambient_occlusion_affect_ao_channel;
- float opaque_prepass_threshold;
-
- bool fog_depth_enabled;
- float fog_depth_begin;
- float fog_depth_end;
- float fog_density;
- float fog_depth_curve;
- bool fog_transmit_enabled;
- float fog_transmit_curve;
- bool fog_height_enabled;
- float fog_height_min;
- float fog_height_max;
- float fog_height_curve;
-#endif
-}
-scene_data;
-
-#define INSTANCE_FLAGS_FORWARD_MASK 0x7
-#define INSTANCE_FLAGS_FORWARD_OMNI_LIGHT_SHIFT 3
-#define INSTANCE_FLAGS_FORWARD_SPOT_LIGHT_SHIFT 6
-#define INSTANCE_FLAGS_FORWARD_DECAL_SHIFT 9
-
-#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_MULTIMESH_STRIDE_SHIFT 16
-//3 bits of stride
-#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7
-
-#define INSTANCE_FLAGS_SKELETON (1 << 19)
-
-struct InstanceData {
- mat4 transform;
- mat4 normal_transform;
- uint flags;
- uint instance_ofs; //instance_offset in instancing/skeleton buffer
- uint gi_offset; //GI information when using lightmapping (VCT or lightmap)
- uint layer_mask;
-};
-
-layout(set = 0, binding = 4, std430) buffer Instances {
- InstanceData data[];
-}
-instances;
-
-struct LightData { //this structure needs to be 128 bits
- vec3 position;
- float inv_radius;
- vec3 direction;
- uint attenuation_energy; //attenuation
- uint color_specular; //rgb color, a specular (8 bit unorm)
- uint cone_attenuation_angle; // attenuation and angle, (16bit float)
- uint mask;
- uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
- vec4 atlas_rect; //used for shadow atlas uv on omni, and for projection atlas on spot
- mat4 shadow_matrix;
-};
-
-layout(set = 0, binding = 5, std140) uniform Lights {
- LightData data[MAX_LIGHT_DATA_STRUCTS];
-}
-lights;
-
-struct ReflectionData {
-
- vec3 box_extents;
- float index;
- vec3 box_offset;
- uint mask;
- vec4 params; // intensity, 0, interior , boxproject
- vec4 ambient; // ambient color, energy
- 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
-};
-
-layout(set = 0, binding = 6, std140) uniform ReflectionProbeData {
- ReflectionData data[MAX_REFLECTION_DATA_STRUCTS];
-}
-reflections;
-
-struct DirectionalLightData {
- vec3 direction;
- float energy;
- vec3 color;
- float specular;
- vec3 shadow_color;
- uint mask;
- bool blend_splits;
- bool shadow_enabled;
- float fade_from;
- float fade_to;
- vec4 shadow_split_offsets;
- mat4 shadow_matrix1;
- mat4 shadow_matrix2;
- mat4 shadow_matrix3;
- mat4 shadow_matrix4;
-};
-
-layout(set = 0, binding = 7, std140) uniform DirectionalLights {
- DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
-}
-directional_lights;
-
-struct GIProbeData {
- mat4 xform;
- vec3 bounds;
- float dynamic_range;
-
- float bias;
- float normal_bias;
- bool blend_ambient;
- uint texture_slot;
-
- float anisotropy_strength;
- float ambient_occlusion;
- float ambient_occlusion_size;
- uint pad2;
-};
-
-layout(set = 0, binding = 8, std140) uniform GIProbes {
- GIProbeData data[MAX_GI_PROBES];
-}
-gi_probes;
-
-layout(set = 0, binding = 9) uniform texture3D gi_probe_textures[MAX_GI_PROBE_TEXTURES];
-
-#define CLUSTER_COUNTER_SHIFT 20
-#define CLUSTER_POINTER_MASK ((1 << CLUSTER_COUNTER_SHIFT) - 1)
-#define CLUSTER_COUNTER_MASK 0xfff
-
-layout(set = 0, binding = 10) uniform utexture3D cluster_texture;
-
-layout(set = 0, binding = 11, std430) buffer ClusterData {
- uint indices[];
-}
-cluster_data;
-
-layout(set = 0, binding = 12) uniform texture2D directional_shadow_atlas;
-
-// decal atlas
-
-/* Set 1, Radiance */
-
-#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-
-layout(set = 1, binding = 0) uniform textureCubeArray radiance_cubemap;
-
-#else
-
-layout(set = 1, binding = 0) uniform textureCube radiance_cubemap;
-
-#endif
-
-/* Set 2, Reflection and Shadow Atlases (view dependant) */
-
-layout(set = 2, binding = 0) uniform textureCubeArray reflection_atlas;
-
-layout(set = 2, binding = 1) uniform texture2D shadow_atlas;
-
-/* Set 1, Render Buffers */
-
-layout(set = 3, binding = 0) uniform texture2D depth_buffer;
-layout(set = 3, binding = 1) uniform texture2D color_buffer;
-layout(set = 3, binding = 2) uniform texture2D normal_buffer;
-layout(set = 3, binding = 3) uniform texture2D roughness_buffer;
-layout(set = 3, binding = 4) uniform texture2D ao_buffer;
-
-/* Set 4 Skeleton & Instancing (Multimesh) */
-
-layout(set = 4, binding = 0, std430) buffer Transforms {
- vec4 data[];
-}
-transforms;
-
-/* Set 5 User Material */
diff --git a/servers/visual/rasterizer_rd/shaders/sky.glsl b/servers/visual/rasterizer_rd/shaders/sky.glsl
deleted file mode 100644
index 28fd2883c3..0000000000
--- a/servers/visual/rasterizer_rd/shaders/sky.glsl
+++ /dev/null
@@ -1,79 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(location = 0) out vec2 uv_interp;
-/* clang-format on */
-
-layout(push_constant, binding = 1, std430) uniform Params {
- mat3 orientation;
- vec4 proj;
- float multiplier;
- float alpha;
- float depth;
- float pad;
-}
-params;
-
-void main() {
-
- vec2 base_arr[4] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0), vec2(1.0, -1.0));
- uv_interp = base_arr[gl_VertexIndex];
- gl_Position = vec4(uv_interp, params.depth, 1.0);
-}
-
-/* clang-format off */
-[fragment]
-
-#version 450
-
-VERSION_DEFINES
-
-#define M_PI 3.14159265359
-
-layout(location = 0) in vec2 uv_interp;
-/* clang-format on */
-
-layout(set = 0, binding = 0) uniform sampler2D source_panorama;
-
-layout(push_constant, binding = 1, std430) uniform Params {
- mat3 orientation;
- vec4 proj;
- float multiplier;
- float alpha;
- float depth;
- float pad;
-}
-params;
-
-vec4 texturePanorama(sampler2D pano, vec3 normal) {
-
- vec2 st = vec2(
- atan(normal.x, normal.z),
- acos(normal.y));
-
- if (st.x < 0.0)
- st.x += M_PI * 2.0;
-
- st /= vec2(M_PI * 2.0, M_PI);
-
- return texture(pano, st);
-}
-
-layout(location = 0) out vec4 frag_color;
-
-void main() {
-
- vec3 cube_normal;
- cube_normal.z = -1000000.0;
- cube_normal.x = (cube_normal.z * (-uv_interp.x - params.proj.x)) / params.proj.y;
- cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.proj.z)) / params.proj.w;
- cube_normal = mat3(params.orientation) * cube_normal;
- cube_normal.z = -cube_normal.z;
-
- frag_color.rgb = texturePanorama(source_panorama, normalize(cube_normal.xyz)).rgb;
- frag_color.a = params.alpha;
-}
diff --git a/servers/visual/rasterizer_rd/shaders/tonemap.glsl b/servers/visual/rasterizer_rd/shaders/tonemap.glsl
deleted file mode 100644
index 524ca5e2ea..0000000000
--- a/servers/visual/rasterizer_rd/shaders/tonemap.glsl
+++ /dev/null
@@ -1,305 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(location = 0) out vec2 uv_interp;
-/* clang-format on */
-
-void main() {
-
- vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
- uv_interp = base_arr[gl_VertexIndex];
- gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
-}
-
-/* clang-format off */
-[fragment]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(location = 0) in vec2 uv_interp;
-/* clang-format on */
-
-layout(set = 0, binding = 0) uniform sampler2D source_color;
-layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure;
-layout(set = 2, binding = 0) uniform sampler2D source_glow;
-layout(set = 3, binding = 0) uniform sampler3D color_correction;
-
-layout(push_constant, binding = 1, std430) uniform Params {
- vec3 bcs;
- bool use_bcs;
-
- bool use_glow;
- bool use_auto_exposure;
- bool use_color_correction;
- uint tonemapper;
-
- uvec2 glow_texture_size;
-
- float glow_intensity;
- uint glow_level_flags;
- uint glow_mode;
-
- float exposure;
- float white;
- float auto_exposure_grey;
-}
-params;
-
-layout(location = 0) out vec4 frag_color;
-
-#ifdef USE_GLOW_FILTER_BICUBIC
-// w0, w1, w2, and w3 are the four cubic B-spline basis functions
-float w0(float a) {
- return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f);
-}
-
-float w1(float a) {
- return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f);
-}
-
-float w2(float a) {
- return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f);
-}
-
-float w3(float a) {
- return (1.0f / 6.0f) * (a * a * a);
-}
-
-// g0 and g1 are the two amplitude functions
-float g0(float a) {
- return w0(a) + w1(a);
-}
-
-float g1(float a) {
- return w2(a) + w3(a);
-}
-
-// h0 and h1 are the two offset functions
-float h0(float a) {
- return -1.0f + w1(a) / (w0(a) + w1(a));
-}
-
-float h1(float a) {
- return 1.0f + w3(a) / (w2(a) + w3(a));
-}
-
-vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) {
- float lod = float(p_lod);
- vec2 tex_size = vec2(params.glow_texture_size >> p_lod);
- vec2 pixel_size = vec2(1.0f) / tex_size;
-
- uv = uv * tex_size + vec2(0.5f);
-
- vec2 iuv = floor(uv);
- vec2 fuv = fract(uv);
-
- float g0x = g0(fuv.x);
- float g1x = g1(fuv.x);
- float h0x = h0(fuv.x);
- float h1x = h1(fuv.x);
- float h0y = h0(fuv.y);
- float h1y = h1(fuv.y);
-
- vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size;
- vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size;
- vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
- vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
-
- return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) +
- (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
-}
-
-#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod)
-
-#else
-
-#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod))
-
-#endif
-
-vec3 tonemap_filmic(vec3 color, float white) {
- // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers
- // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values)
- // has no effect on the curve's general shape or visual properties
- const float exposure_bias = 2.0f;
- const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance
- const float B = 0.30f * exposure_bias;
- const float C = 0.10f;
- const float D = 0.20f;
- const float E = 0.01f;
- const float F = 0.30f;
-
- vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
- float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F;
-
- return color_tonemapped / white_tonemapped;
-}
-
-vec3 tonemap_aces(vec3 color, float white) {
- const float exposure_bias = 0.85f;
- const float A = 2.51f * exposure_bias * exposure_bias;
- const float B = 0.03f * exposure_bias;
- const float C = 2.43f * exposure_bias * exposure_bias;
- const float D = 0.59f * exposure_bias;
- const float E = 0.14f;
-
- vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E);
- float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E);
-
- return color_tonemapped / white_tonemapped;
-}
-
-vec3 tonemap_reinhard(vec3 color, float white) {
- return (white * color + color) / (color * white + white);
-}
-
-vec3 linear_to_srgb(vec3 color) {
- //if going to srgb, clamp from 0 to 1.
- color = clamp(color, vec3(0.0), vec3(1.0));
- const vec3 a = vec3(0.055f);
- return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
-}
-
-#define TONEMAPPER_LINEAR 0
-#define TONEMAPPER_REINHARD 1
-#define TONEMAPPER_FILMIC 2
-#define TONEMAPPER_ACES 3
-
-vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color
-
- if (params.tonemapper == TONEMAPPER_LINEAR) {
- return color;
- } else if (params.tonemapper == TONEMAPPER_REINHARD) {
- return tonemap_reinhard(color, white);
- } else if (params.tonemapper == TONEMAPPER_FILMIC) {
- return tonemap_filmic(color, white);
- } else { //aces
- return tonemap_aces(color, white);
- }
-}
-
-vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels
- vec3 glow = vec3(0.0f);
-
- if (bool(params.glow_level_flags & (1 << 0))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 0).rgb;
- }
-
- if (bool(params.glow_level_flags & (1 << 1))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb;
- }
-
- if (bool(params.glow_level_flags & (1 << 2))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb;
- }
-
- if (bool(params.glow_level_flags & (1 << 3))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb;
- }
-
- if (bool(params.glow_level_flags & (1 << 4))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb;
- }
-
- if (bool(params.glow_level_flags & (1 << 5))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb;
- }
-
- if (bool(params.glow_level_flags & (1 << 6))) {
- glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb;
- }
-
- return glow;
-}
-
-#define GLOW_MODE_ADD 0
-#define GLOW_MODE_SCREEN 1
-#define GLOW_MODE_SOFTLIGHT 2
-#define GLOW_MODE_REPLACE 3
-#define GLOW_MODE_MIX 4
-
-vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode
- if (params.glow_mode == GLOW_MODE_ADD) {
- return color + glow;
- } else if (params.glow_mode == GLOW_MODE_SCREEN) {
- //need color clamping
- return max((color + glow) - (color * glow), vec3(0.0));
- } else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) {
- //need color clamping
- glow = glow * vec3(0.5f) + vec3(0.5f);
-
- color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r)));
- color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g)));
- color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b)));
- return color;
- } else { //replace
- return glow;
- }
-}
-
-vec3 apply_bcs(vec3 color, vec3 bcs) {
- color = mix(vec3(0.0f), color, bcs.x);
- color = mix(vec3(0.5f), color, bcs.y);
- color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z);
-
- return color;
-}
-
-vec3 apply_color_correction(vec3 color, sampler3D correction_tex) {
- return texture(correction_tex, color).rgb;
-}
-
-void main() {
- vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb;
-
- // Exposure
-
- if (params.use_auto_exposure) {
- color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey;
- }
-
- color *= params.exposure;
-
- // Early Tonemap & SRGB Conversion
-
- if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
-
- vec3 glow = gather_glow(source_glow, uv_interp);
- color.rgb = mix(color.rgb, glow, params.glow_intensity);
- }
-
- color = apply_tonemapping(color, params.white);
-
- color = linear_to_srgb(color); // regular linear -> SRGB conversion
-
- // Glow
-
- if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
-
- vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity;
-
- // high dynamic range -> SRGB
- glow = apply_tonemapping(glow, params.white);
- glow = linear_to_srgb(glow);
-
- color = apply_glow(color, glow);
- }
-
- // Additional effects
-
- if (params.use_bcs) {
- color = apply_bcs(color, params.bcs);
- }
-
- if (params.use_color_correction) {
- color = apply_color_correction(color, color_correction);
- }
-
- frag_color = vec4(color, 1.0f);
-}
diff --git a/servers/visual/rendering_device.cpp b/servers/visual/rendering_device.cpp
deleted file mode 100644
index 3c1795161d..0000000000
--- a/servers/visual/rendering_device.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*************************************************************************/
-/* rendering_device.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_device.h"
-
-RenderingDevice *RenderingDevice::singleton = NULL;
-
-RenderingDevice *RenderingDevice::get_singleton() {
- return singleton;
-}
-
-RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = NULL;
-RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = NULL;
-
-void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
- compile_function = p_function;
-}
-void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function) {
- cache_function = p_function;
-}
-
-Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
- if (p_allow_cache && cache_function) {
- Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
- if (cache.size()) {
- return cache;
- }
- }
-
- ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>());
-
- return compile_function(p_stage, p_source_code, p_language, r_error);
-}
-
-RenderingDevice::RenderingDevice() {
- singleton = this;
-}
diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h
deleted file mode 100644
index 1ff169f102..0000000000
--- a/servers/visual/rendering_device.h
+++ /dev/null
@@ -1,1031 +0,0 @@
-/*************************************************************************/
-/* rendering_device.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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_DEVICE_H
-#define RENDERING_DEVICE_H
-
-#include "core/object.h"
-
-class RenderingDevice : public Object {
- GDCLASS(RenderingDevice, Object)
-public:
- enum ShaderStage {
- SHADER_STAGE_VERTEX,
- SHADER_STAGE_FRAGMENT,
- SHADER_STAGE_TESSELATION_CONTROL,
- SHADER_STAGE_TESSELATION_EVALUATION,
- SHADER_STAGE_COMPUTE,
- SHADER_STAGE_MAX,
- SHADER_STAGE_VERTEX_BIT = (1 << SHADER_STAGE_VERTEX),
- SHADER_STAGE_FRAGMENT_BIT = (1 << SHADER_STAGE_FRAGMENT),
- SHADER_STAGE_TESSELATION_CONTROL_BIT = (1 << SHADER_STAGE_TESSELATION_CONTROL),
- SHADER_STAGE_TESSELATION_EVALUATION_BIT = (1 << SHADER_STAGE_TESSELATION_EVALUATION),
- SHADER_STAGE_COMPUTE_BIT = (1 << SHADER_STAGE_COMPUTE),
- };
-
- enum ShaderLanguage {
- SHADER_LANGUAGE_GLSL,
- SHADER_LANGUAGE_HLSL
- };
-
- typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error);
- typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
-
-private:
- static ShaderCompileFunction compile_function;
- static ShaderCacheFunction cache_function;
-
- static RenderingDevice *singleton;
-
-public:
- //base numeric ID for all types
- enum {
- INVALID_ID = -1
- };
-
- /*****************/
- /**** GENERIC ****/
- /*****************/
-
- enum CompareOperator {
- COMPARE_OP_NEVER,
- COMPARE_OP_LESS,
- COMPARE_OP_EQUAL,
- COMPARE_OP_LESS_OR_EQUAL,
- COMPARE_OP_GREATER,
- COMPARE_OP_NOT_EQUAL,
- COMPARE_OP_GREATER_OR_EQUAL,
- COMPARE_OP_ALWAYS,
- COMPARE_OP_MAX //not an actual operator, just the amount of operators :D
- };
-
- enum DataFormat {
- DATA_FORMAT_R4G4_UNORM_PACK8,
- DATA_FORMAT_R4G4B4A4_UNORM_PACK16,
- DATA_FORMAT_B4G4R4A4_UNORM_PACK16,
- DATA_FORMAT_R5G6B5_UNORM_PACK16,
- DATA_FORMAT_B5G6R5_UNORM_PACK16,
- DATA_FORMAT_R5G5B5A1_UNORM_PACK16,
- DATA_FORMAT_B5G5R5A1_UNORM_PACK16,
- DATA_FORMAT_A1R5G5B5_UNORM_PACK16,
- DATA_FORMAT_R8_UNORM,
- DATA_FORMAT_R8_SNORM,
- DATA_FORMAT_R8_USCALED,
- DATA_FORMAT_R8_SSCALED,
- DATA_FORMAT_R8_UINT,
- DATA_FORMAT_R8_SINT,
- DATA_FORMAT_R8_SRGB,
- DATA_FORMAT_R8G8_UNORM,
- DATA_FORMAT_R8G8_SNORM,
- DATA_FORMAT_R8G8_USCALED,
- DATA_FORMAT_R8G8_SSCALED,
- DATA_FORMAT_R8G8_UINT,
- DATA_FORMAT_R8G8_SINT,
- DATA_FORMAT_R8G8_SRGB,
- DATA_FORMAT_R8G8B8_UNORM,
- DATA_FORMAT_R8G8B8_SNORM,
- DATA_FORMAT_R8G8B8_USCALED,
- DATA_FORMAT_R8G8B8_SSCALED,
- DATA_FORMAT_R8G8B8_UINT,
- DATA_FORMAT_R8G8B8_SINT,
- DATA_FORMAT_R8G8B8_SRGB,
- DATA_FORMAT_B8G8R8_UNORM,
- DATA_FORMAT_B8G8R8_SNORM,
- DATA_FORMAT_B8G8R8_USCALED,
- DATA_FORMAT_B8G8R8_SSCALED,
- DATA_FORMAT_B8G8R8_UINT,
- DATA_FORMAT_B8G8R8_SINT,
- DATA_FORMAT_B8G8R8_SRGB,
- DATA_FORMAT_R8G8B8A8_UNORM,
- DATA_FORMAT_R8G8B8A8_SNORM,
- DATA_FORMAT_R8G8B8A8_USCALED,
- DATA_FORMAT_R8G8B8A8_SSCALED,
- DATA_FORMAT_R8G8B8A8_UINT,
- DATA_FORMAT_R8G8B8A8_SINT,
- DATA_FORMAT_R8G8B8A8_SRGB,
- DATA_FORMAT_B8G8R8A8_UNORM,
- DATA_FORMAT_B8G8R8A8_SNORM,
- DATA_FORMAT_B8G8R8A8_USCALED,
- DATA_FORMAT_B8G8R8A8_SSCALED,
- DATA_FORMAT_B8G8R8A8_UINT,
- DATA_FORMAT_B8G8R8A8_SINT,
- DATA_FORMAT_B8G8R8A8_SRGB,
- DATA_FORMAT_A8B8G8R8_UNORM_PACK32,
- DATA_FORMAT_A8B8G8R8_SNORM_PACK32,
- DATA_FORMAT_A8B8G8R8_USCALED_PACK32,
- DATA_FORMAT_A8B8G8R8_SSCALED_PACK32,
- DATA_FORMAT_A8B8G8R8_UINT_PACK32,
- DATA_FORMAT_A8B8G8R8_SINT_PACK32,
- DATA_FORMAT_A8B8G8R8_SRGB_PACK32,
- DATA_FORMAT_A2R10G10B10_UNORM_PACK32,
- DATA_FORMAT_A2R10G10B10_SNORM_PACK32,
- DATA_FORMAT_A2R10G10B10_USCALED_PACK32,
- DATA_FORMAT_A2R10G10B10_SSCALED_PACK32,
- DATA_FORMAT_A2R10G10B10_UINT_PACK32,
- DATA_FORMAT_A2R10G10B10_SINT_PACK32,
- DATA_FORMAT_A2B10G10R10_UNORM_PACK32,
- DATA_FORMAT_A2B10G10R10_SNORM_PACK32,
- DATA_FORMAT_A2B10G10R10_USCALED_PACK32,
- DATA_FORMAT_A2B10G10R10_SSCALED_PACK32,
- DATA_FORMAT_A2B10G10R10_UINT_PACK32,
- DATA_FORMAT_A2B10G10R10_SINT_PACK32,
- DATA_FORMAT_R16_UNORM,
- DATA_FORMAT_R16_SNORM,
- DATA_FORMAT_R16_USCALED,
- DATA_FORMAT_R16_SSCALED,
- DATA_FORMAT_R16_UINT,
- DATA_FORMAT_R16_SINT,
- DATA_FORMAT_R16_SFLOAT,
- DATA_FORMAT_R16G16_UNORM,
- DATA_FORMAT_R16G16_SNORM,
- DATA_FORMAT_R16G16_USCALED,
- DATA_FORMAT_R16G16_SSCALED,
- DATA_FORMAT_R16G16_UINT,
- DATA_FORMAT_R16G16_SINT,
- DATA_FORMAT_R16G16_SFLOAT,
- DATA_FORMAT_R16G16B16_UNORM,
- DATA_FORMAT_R16G16B16_SNORM,
- DATA_FORMAT_R16G16B16_USCALED,
- DATA_FORMAT_R16G16B16_SSCALED,
- DATA_FORMAT_R16G16B16_UINT,
- DATA_FORMAT_R16G16B16_SINT,
- DATA_FORMAT_R16G16B16_SFLOAT,
- DATA_FORMAT_R16G16B16A16_UNORM,
- DATA_FORMAT_R16G16B16A16_SNORM,
- DATA_FORMAT_R16G16B16A16_USCALED,
- DATA_FORMAT_R16G16B16A16_SSCALED,
- DATA_FORMAT_R16G16B16A16_UINT,
- DATA_FORMAT_R16G16B16A16_SINT,
- DATA_FORMAT_R16G16B16A16_SFLOAT,
- DATA_FORMAT_R32_UINT,
- DATA_FORMAT_R32_SINT,
- DATA_FORMAT_R32_SFLOAT,
- DATA_FORMAT_R32G32_UINT,
- DATA_FORMAT_R32G32_SINT,
- DATA_FORMAT_R32G32_SFLOAT,
- DATA_FORMAT_R32G32B32_UINT,
- DATA_FORMAT_R32G32B32_SINT,
- DATA_FORMAT_R32G32B32_SFLOAT,
- DATA_FORMAT_R32G32B32A32_UINT,
- DATA_FORMAT_R32G32B32A32_SINT,
- DATA_FORMAT_R32G32B32A32_SFLOAT,
- DATA_FORMAT_R64_UINT,
- DATA_FORMAT_R64_SINT,
- DATA_FORMAT_R64_SFLOAT,
- DATA_FORMAT_R64G64_UINT,
- DATA_FORMAT_R64G64_SINT,
- DATA_FORMAT_R64G64_SFLOAT,
- DATA_FORMAT_R64G64B64_UINT,
- DATA_FORMAT_R64G64B64_SINT,
- DATA_FORMAT_R64G64B64_SFLOAT,
- DATA_FORMAT_R64G64B64A64_UINT,
- DATA_FORMAT_R64G64B64A64_SINT,
- DATA_FORMAT_R64G64B64A64_SFLOAT,
- DATA_FORMAT_B10G11R11_UFLOAT_PACK32,
- DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32,
- DATA_FORMAT_D16_UNORM,
- DATA_FORMAT_X8_D24_UNORM_PACK32,
- DATA_FORMAT_D32_SFLOAT,
- DATA_FORMAT_S8_UINT,
- DATA_FORMAT_D16_UNORM_S8_UINT,
- DATA_FORMAT_D24_UNORM_S8_UINT,
- DATA_FORMAT_D32_SFLOAT_S8_UINT,
- DATA_FORMAT_BC1_RGB_UNORM_BLOCK,
- DATA_FORMAT_BC1_RGB_SRGB_BLOCK,
- DATA_FORMAT_BC1_RGBA_UNORM_BLOCK,
- DATA_FORMAT_BC1_RGBA_SRGB_BLOCK,
- DATA_FORMAT_BC2_UNORM_BLOCK,
- DATA_FORMAT_BC2_SRGB_BLOCK,
- DATA_FORMAT_BC3_UNORM_BLOCK,
- DATA_FORMAT_BC3_SRGB_BLOCK,
- DATA_FORMAT_BC4_UNORM_BLOCK,
- DATA_FORMAT_BC4_SNORM_BLOCK,
- DATA_FORMAT_BC5_UNORM_BLOCK,
- DATA_FORMAT_BC5_SNORM_BLOCK,
- DATA_FORMAT_BC6H_UFLOAT_BLOCK,
- DATA_FORMAT_BC6H_SFLOAT_BLOCK,
- DATA_FORMAT_BC7_UNORM_BLOCK,
- DATA_FORMAT_BC7_SRGB_BLOCK,
- DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
- DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
- DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
- DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
- DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
- DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
- DATA_FORMAT_EAC_R11_UNORM_BLOCK,
- DATA_FORMAT_EAC_R11_SNORM_BLOCK,
- DATA_FORMAT_EAC_R11G11_UNORM_BLOCK,
- DATA_FORMAT_EAC_R11G11_SNORM_BLOCK,
- DATA_FORMAT_ASTC_4x4_UNORM_BLOCK,
- DATA_FORMAT_ASTC_4x4_SRGB_BLOCK,
- DATA_FORMAT_ASTC_5x4_UNORM_BLOCK,
- DATA_FORMAT_ASTC_5x4_SRGB_BLOCK,
- DATA_FORMAT_ASTC_5x5_UNORM_BLOCK,
- DATA_FORMAT_ASTC_5x5_SRGB_BLOCK,
- DATA_FORMAT_ASTC_6x5_UNORM_BLOCK,
- DATA_FORMAT_ASTC_6x5_SRGB_BLOCK,
- DATA_FORMAT_ASTC_6x6_UNORM_BLOCK,
- DATA_FORMAT_ASTC_6x6_SRGB_BLOCK,
- DATA_FORMAT_ASTC_8x5_UNORM_BLOCK,
- DATA_FORMAT_ASTC_8x5_SRGB_BLOCK,
- DATA_FORMAT_ASTC_8x6_UNORM_BLOCK,
- DATA_FORMAT_ASTC_8x6_SRGB_BLOCK,
- DATA_FORMAT_ASTC_8x8_UNORM_BLOCK,
- DATA_FORMAT_ASTC_8x8_SRGB_BLOCK,
- DATA_FORMAT_ASTC_10x5_UNORM_BLOCK,
- DATA_FORMAT_ASTC_10x5_SRGB_BLOCK,
- DATA_FORMAT_ASTC_10x6_UNORM_BLOCK,
- DATA_FORMAT_ASTC_10x6_SRGB_BLOCK,
- DATA_FORMAT_ASTC_10x8_UNORM_BLOCK,
- DATA_FORMAT_ASTC_10x8_SRGB_BLOCK,
- DATA_FORMAT_ASTC_10x10_UNORM_BLOCK,
- DATA_FORMAT_ASTC_10x10_SRGB_BLOCK,
- DATA_FORMAT_ASTC_12x10_UNORM_BLOCK,
- DATA_FORMAT_ASTC_12x10_SRGB_BLOCK,
- DATA_FORMAT_ASTC_12x12_UNORM_BLOCK,
- DATA_FORMAT_ASTC_12x12_SRGB_BLOCK,
- DATA_FORMAT_G8B8G8R8_422_UNORM,
- DATA_FORMAT_B8G8R8G8_422_UNORM,
- DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
- DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM,
- DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
- DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM,
- DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
- DATA_FORMAT_R10X6_UNORM_PACK16,
- DATA_FORMAT_R10X6G10X6_UNORM_2PACK16,
- DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
- DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
- DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
- DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
- DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
- DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
- DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
- DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
- DATA_FORMAT_R12X4_UNORM_PACK16,
- DATA_FORMAT_R12X4G12X4_UNORM_2PACK16,
- DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
- DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
- DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
- DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
- DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
- DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
- DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
- DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
- DATA_FORMAT_G16B16G16R16_422_UNORM,
- DATA_FORMAT_B16G16R16G16_422_UNORM,
- DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
- DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM,
- DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
- DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM,
- DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
- DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,
- DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG,
- DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG,
- DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG,
- DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG,
- DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG,
- DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG,
- DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,
- DATA_FORMAT_MAX
- };
-
- /*****************/
- /**** TEXTURE ****/
- /*****************/
-
- enum TextureType {
- TEXTURE_TYPE_1D,
- TEXTURE_TYPE_2D,
- TEXTURE_TYPE_3D,
- TEXTURE_TYPE_CUBE,
- TEXTURE_TYPE_1D_ARRAY,
- TEXTURE_TYPE_2D_ARRAY,
- TEXTURE_TYPE_CUBE_ARRAY,
- TEXTURE_TYPE_MAX
- };
-
- enum TextureSamples {
- TEXTURE_SAMPLES_1,
- TEXTURE_SAMPLES_2,
- TEXTURE_SAMPLES_4,
- TEXTURE_SAMPLES_8,
- TEXTURE_SAMPLES_16,
- TEXTURE_SAMPLES_32,
- TEXTURE_SAMPLES_64,
- TEXTURE_SAMPLES_MAX
- };
-
- enum TextureUsageBits {
- TEXTURE_USAGE_SAMPLING_BIT = (1 << 0),
- TEXTURE_USAGE_COLOR_ATTACHMENT_BIT = (1 << 1),
- TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = (1 << 2),
- TEXTURE_USAGE_STORAGE_BIT = (1 << 3),
- TEXTURE_USAGE_STORAGE_ATOMIC_BIT = (1 << 4),
- TEXTURE_USAGE_CPU_READ_BIT = (1 << 5),
- TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6),
- TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7),
- TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8),
- TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 9),
- };
-
- enum TextureSwizzle {
- TEXTURE_SWIZZLE_IDENTITY,
- TEXTURE_SWIZZLE_ZERO,
- TEXTURE_SWIZZLE_ONE,
- TEXTURE_SWIZZLE_R,
- TEXTURE_SWIZZLE_G,
- TEXTURE_SWIZZLE_B,
- TEXTURE_SWIZZLE_A,
- TEXTURE_SWIZZLE_MAX
- };
-
- struct TextureFormat {
- DataFormat format;
- uint32_t width;
- uint32_t height;
- uint32_t depth;
- uint32_t array_layers;
- uint32_t mipmaps;
- TextureType type;
- TextureSamples samples;
- uint32_t usage_bits;
- Vector<DataFormat> shareable_formats;
-
- TextureFormat() {
- format = DATA_FORMAT_R8_UNORM;
- width = 1;
- height = 1;
- depth = 1;
- array_layers = 1;
- mipmaps = 1;
- type = TEXTURE_TYPE_2D;
- samples = TEXTURE_SAMPLES_1;
- usage_bits = 0;
- }
- };
-
- struct TextureView {
- DataFormat format_override;
- TextureSwizzle swizzle_r;
- TextureSwizzle swizzle_g;
- TextureSwizzle swizzle_b;
- TextureSwizzle swizzle_a;
-
- TextureView() {
- format_override = DATA_FORMAT_MAX; //means, use same as format
- swizzle_r = TEXTURE_SWIZZLE_R;
- swizzle_g = TEXTURE_SWIZZLE_G;
- swizzle_b = TEXTURE_SWIZZLE_B;
- swizzle_a = TEXTURE_SWIZZLE_A;
- }
- };
-
- virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t> > &p_data = Vector<Vector<uint8_t> >()) = 0;
- virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0;
-
- enum TextureSliceType {
- TEXTURE_SLICE_2D,
- TEXTURE_SLICE_CUBEMAP,
- TEXTURE_SLICE_3D,
- };
-
- virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D) = 0;
-
- virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls
- virtual Vector<uint8_t> texture_get_data(RID p_texture, uint32_t p_layer) = 0; // CPU textures will return immediately, while GPU textures will most likely force a flush
-
- virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0;
- virtual bool texture_is_shared(RID p_texture) = 0;
- virtual bool texture_is_valid(RID p_texture) = 0;
-
- virtual Error texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw = false) = 0;
- virtual Error texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw = false) = 0;
-
- /*********************/
- /**** FRAMEBUFFER ****/
- /*********************/
-
- struct AttachmentFormat {
- DataFormat format;
- TextureSamples samples;
- uint32_t usage_flags;
- AttachmentFormat() {
- format = DATA_FORMAT_R8G8B8A8_UNORM;
- samples = TEXTURE_SAMPLES_1;
- usage_flags = 0;
- }
- };
-
- typedef int64_t FramebufferFormatID;
-
- // This ID is warranted to be unique for the same formats, does not need to be freed
- virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format) = 0;
- virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0;
-
- virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0;
-
- virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0;
-
- /*****************/
- /**** SAMPLER ****/
- /*****************/
-
- enum SamplerFilter {
- SAMPLER_FILTER_NEAREST,
- SAMPLER_FILTER_LINEAR,
- };
-
- enum SamplerRepeatMode {
- SAMPLER_REPEAT_MODE_REPEAT,
- SAMPLER_REPEAT_MODE_MIRRORED_REPEAT,
- SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE,
- SAMPLER_REPEAT_MODE_CLAMP_TO_BORDER,
- SAMPLER_REPEAT_MODE_MIRROR_CLAMP_TO_EDGE,
- SAMPLER_REPEAT_MODE_MAX
- };
-
- enum SamplerBorderColor {
- SAMPLER_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
- SAMPLER_BORDER_COLOR_INT_TRANSPARENT_BLACK,
- SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK,
- SAMPLER_BORDER_COLOR_INT_OPAQUE_BLACK,
- SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
- SAMPLER_BORDER_COLOR_INT_OPAQUE_WHITE,
- SAMPLER_BORDER_COLOR_MAX
- };
-
- struct SamplerState {
- SamplerFilter mag_filter;
- SamplerFilter min_filter;
- SamplerFilter mip_filter;
- SamplerRepeatMode repeat_u;
- SamplerRepeatMode repeat_v;
- SamplerRepeatMode repeat_w;
- float lod_bias;
- bool use_anisotropy;
- float anisotropy_max;
- bool enable_compare;
- CompareOperator compare_op;
- float min_lod;
- float max_lod;
- SamplerBorderColor border_color;
- bool unnormalized_uvw;
-
- SamplerState() {
- mag_filter = SAMPLER_FILTER_NEAREST;
- min_filter = SAMPLER_FILTER_NEAREST;
- mip_filter = SAMPLER_FILTER_NEAREST;
- repeat_u = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- repeat_v = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- repeat_w = SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
- lod_bias = 0;
- use_anisotropy = false;
- anisotropy_max = 1.0;
- enable_compare = false;
- compare_op = COMPARE_OP_ALWAYS;
- min_lod = 0;
- max_lod = 1e20; //something very large should do
- border_color = SAMPLER_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
- unnormalized_uvw = false;
- }
- };
-
- virtual RID sampler_create(const SamplerState &p_state) = 0;
-
- /**********************/
- /**** VERTEX ARRAY ****/
- /**********************/
-
- enum VertexFrequency {
- VERTEX_FREQUENCY_VERTEX,
- VERTEX_FREQUENCY_INSTANCE,
- };
-
- struct VertexDescription {
- uint32_t location; //shader location
- uint32_t offset;
- DataFormat format;
- uint32_t stride;
- VertexFrequency frequency;
- VertexDescription() {
- location = 0;
- offset = 0;
- stride = 0;
- format = DATA_FORMAT_MAX;
- frequency = VERTEX_FREQUENCY_VERTEX;
- }
- };
- virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
-
- typedef int64_t VertexFormatID;
-
- // This ID is warranted to be unique for the same formats, does not need to be freed
- virtual VertexFormatID vertex_format_create(const Vector<VertexDescription> &p_vertex_formats) = 0;
- virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers) = 0;
-
- enum IndexBufferFormat {
- INDEX_BUFFER_FORMAT_UINT16,
- INDEX_BUFFER_FORMAT_UINT32,
- };
-
- virtual RID index_buffer_create(uint32_t p_size_indices, IndexBufferFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_restart_indices = false) = 0;
- virtual RID index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) = 0;
-
- /****************/
- /**** SHADER ****/
- /****************/
-
- 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 = NULL, bool p_allow_cache = true);
-
- static void shader_set_compile_function(ShaderCompileFunction p_function);
- static void shader_set_cache_function(ShaderCacheFunction p_function);
-
- struct ShaderStageData {
- ShaderStage shader_stage;
- Vector<uint8_t> spir_v;
-
- ShaderStageData() {
- shader_stage = SHADER_STAGE_VERTEX;
- }
- };
-
- virtual RID shader_create(const Vector<ShaderStageData> &p_stages) = 0;
- virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0;
-
- /******************/
- /**** UNIFORMS ****/
- /******************/
-
- enum UniformType {
- UNIFORM_TYPE_SAMPLER, //for sampling only (sampler GLSL type)
- UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, // for sampling only, but includes a texture, (samplerXX GLSL type), first a sampler then a texture
- UNIFORM_TYPE_TEXTURE, //only texture, (textureXX GLSL type)
- UNIFORM_TYPE_IMAGE, // storage image (imageXX GLSL type), for compute mostly
- UNIFORM_TYPE_TEXTURE_BUFFER, // buffer texture (or TBO, textureBuffer type)
- UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER, // buffer texture with a sampler(or TBO, samplerBuffer type)
- UNIFORM_TYPE_IMAGE_BUFFER, //texel buffer, (imageBuffer type), for compute mostly
- UNIFORM_TYPE_UNIFORM_BUFFER, //regular uniform buffer (or UBO).
- UNIFORM_TYPE_STORAGE_BUFFER, //storage buffer ("buffer" qualifier) like UBO, but supports storage, for compute mostly
- UNIFORM_TYPE_INPUT_ATTACHMENT, //used for sub-pass read/write, for compute mostly
- UNIFORM_TYPE_MAX
- };
-
- virtual RID uniform_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
- virtual RID storage_buffer_create(uint32_t p_size, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
- virtual RID texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const Vector<uint8_t> &p_data = Vector<uint8_t>()) = 0;
-
- struct Uniform {
- UniformType type;
- int binding; //binding index as specified in shader
-
- //for single items, provide one ID, for
- //multiple items (declared as arrays in shader),
- //provide more
- //for sampler with texture, supply two IDs for each.
- //accepted IDs are: Sampler, Texture, Uniform Buffer and Texture Buffer
- Vector<RID> ids;
-
- Uniform() {
- type = UNIFORM_TYPE_IMAGE;
- binding = 0;
- }
- };
-
- virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
- virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
-
- virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the beginning of the frame, unless sync with draw is used, which is used to mix updates with draw calls
- virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving
-
- /*************************/
- /**** RENDER PIPELINE ****/
- /*************************/
-
- enum RenderPrimitive {
- RENDER_PRIMITIVE_POINTS,
- RENDER_PRIMITIVE_LINES,
- RENDER_PRIMITIVE_LINES_WITH_ADJACENCY,
- RENDER_PRIMITIVE_LINESTRIPS,
- RENDER_PRIMITIVE_LINESTRIPS_WITH_ADJACENCY,
- RENDER_PRIMITIVE_TRIANGLES,
- RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY,
- RENDER_PRIMITIVE_TRIANGLE_STRIPS,
- RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_AJACENCY,
- RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX,
- RENDER_PRIMITIVE_TESSELATION_PATCH,
- RENDER_PRIMITIVE_MAX
- };
-
- //disable optimization, tessellate control points
-
- enum PolygonCullMode {
- POLYGON_CULL_DISABLED,
- POLYGON_CULL_FRONT,
- POLYGON_CULL_BACK,
- };
-
- enum PolygonFrontFace {
- POLYGON_FRONT_FACE_CLOCKWISE,
- POLYGON_FRONT_FACE_COUNTER_CLOCKWISE,
- };
-
- enum StencilOperation {
- STENCIL_OP_KEEP,
- STENCIL_OP_ZERO,
- STENCIL_OP_REPLACE,
- STENCIL_OP_INCREMENT_AND_CLAMP,
- STENCIL_OP_DECREMENT_AND_CLAMP,
- STENCIL_OP_INVERT,
- STENCIL_OP_INCREMENT_AND_WRAP,
- STENCIL_OP_DECREMENT_AND_WRAP,
- STENCIL_OP_MAX //not an actual operator, just the amount of operators :D
- };
-
- enum LogicOperation {
- LOGIC_OP_CLEAR,
- LOGIC_OP_AND,
- LOGIC_OP_AND_REVERSE,
- LOGIC_OP_COPY,
- LOGIC_OP_AND_INVERTED,
- LOGIC_OP_NO_OP,
- LOGIC_OP_XOR,
- LOGIC_OP_OR,
- LOGIC_OP_NOR,
- LOGIC_OP_EQUIVALENT,
- LOGIC_OP_INVERT,
- LOGIC_OP_OR_REVERSE,
- LOGIC_OP_COPY_INVERTED,
- LOGIC_OP_OR_INVERTED,
- LOGIC_OP_NAND,
- LOGIC_OP_SET,
- LOGIC_OP_MAX //not an actual operator, just the amount of operators :D
- };
-
- enum BlendFactor {
- BLEND_FACTOR_ZERO,
- BLEND_FACTOR_ONE,
- BLEND_FACTOR_SRC_COLOR,
- BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
- BLEND_FACTOR_DST_COLOR,
- BLEND_FACTOR_ONE_MINUS_DST_COLOR,
- BLEND_FACTOR_SRC_ALPHA,
- BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
- BLEND_FACTOR_DST_ALPHA,
- BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
- BLEND_FACTOR_CONSTANT_COLOR,
- BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
- BLEND_FACTOR_CONSTANT_ALPHA,
- BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
- BLEND_FACTOR_SRC_ALPHA_SATURATE,
- BLEND_FACTOR_SRC1_COLOR,
- BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
- BLEND_FACTOR_SRC1_ALPHA,
- BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
- BLEND_FACTOR_MAX
- };
-
- enum BlendOperation {
- BLEND_OP_ADD,
- BLEND_OP_SUBTRACT,
- BLEND_OP_REVERSE_SUBTRACT,
- BLEND_OP_MINIMUM,
- BLEND_OP_MAXIMUM, //yes this one is an actual operator
- BLEND_OP_MAX //not an actual operator, just the amount of operators :D
- };
-
- struct PipelineRasterizationState {
- bool enable_depth_clamp;
- bool discard_primitives;
- bool wireframe;
- PolygonCullMode cull_mode;
- PolygonFrontFace front_face;
- bool depth_bias_enable;
- float depth_bias_constant_factor;
- float depth_bias_clamp;
- float depth_bias_slope_factor;
- float line_width;
- uint32_t patch_control_points;
- PipelineRasterizationState() {
- enable_depth_clamp = false;
- discard_primitives = false;
- wireframe = false;
- cull_mode = POLYGON_CULL_DISABLED;
- front_face = POLYGON_FRONT_FACE_CLOCKWISE;
- depth_bias_enable = false;
- depth_bias_constant_factor = 0;
- depth_bias_clamp = 0;
- depth_bias_slope_factor = 0;
- line_width = 1.0;
- patch_control_points = 1;
- }
- };
-
- struct PipelineMultisampleState {
- TextureSamples sample_count;
- bool enable_sample_shading;
- float min_sample_shading;
- Vector<uint32_t> sample_mask;
- bool enable_alpha_to_coverage;
- bool enable_alpha_to_one;
-
- PipelineMultisampleState() {
- sample_count = TEXTURE_SAMPLES_1;
- enable_sample_shading = false;
- min_sample_shading = 0;
- enable_alpha_to_coverage = false;
- enable_alpha_to_one = false;
- }
- };
-
- struct PipelineDepthStencilState {
-
- bool enable_depth_test;
- bool enable_depth_write;
- CompareOperator depth_compare_operator;
- bool enable_depth_range;
- float depth_range_min;
- float depth_range_max;
- bool enable_stencil;
-
- struct StencilOperationState {
- StencilOperation fail;
- StencilOperation pass;
- StencilOperation depth_fail;
- CompareOperator compare;
- uint32_t compare_mask;
- uint32_t write_mask;
- uint32_t reference;
-
- StencilOperationState() {
- fail = STENCIL_OP_ZERO;
- pass = STENCIL_OP_ZERO;
- depth_fail = STENCIL_OP_ZERO;
- compare = COMPARE_OP_ALWAYS;
- compare_mask = 0;
- write_mask = 0;
- reference = 0;
- }
- };
-
- StencilOperationState stencil_operation_front;
- StencilOperationState stencil_operation_back;
-
- PipelineDepthStencilState() {
- enable_depth_test = false;
- enable_depth_write = false;
- depth_compare_operator = COMPARE_OP_ALWAYS;
- enable_depth_range = false;
- depth_range_min = 0;
- depth_range_max = 0;
- enable_stencil = false;
- }
- };
-
- struct PipelineColorBlendState {
-
- bool enable_logic_op;
- LogicOperation logic_op;
- struct Attachment {
- bool enable_blend;
- BlendFactor src_color_blend_factor;
- BlendFactor dst_color_blend_factor;
- BlendOperation color_blend_op;
- BlendFactor src_alpha_blend_factor;
- BlendFactor dst_alpha_blend_factor;
- BlendOperation alpha_blend_op;
- bool write_r;
- bool write_g;
- bool write_b;
- bool write_a;
- Attachment() {
- enable_blend = false;
- src_color_blend_factor = BLEND_FACTOR_ZERO;
- dst_color_blend_factor = BLEND_FACTOR_ZERO;
- color_blend_op = BLEND_OP_ADD;
- src_alpha_blend_factor = BLEND_FACTOR_ZERO;
- dst_alpha_blend_factor = BLEND_FACTOR_ZERO;
- alpha_blend_op = BLEND_OP_ADD;
- write_r = true;
- write_g = true;
- write_b = true;
- write_a = true;
- }
- };
-
- static PipelineColorBlendState create_disabled(int p_attachments = 1) {
- PipelineColorBlendState bs;
- for (int i = 0; i < p_attachments; i++) {
- bs.attachments.push_back(Attachment());
- }
- return bs;
- }
-
- static PipelineColorBlendState create_blend(int p_attachments = 1) {
- PipelineColorBlendState bs;
- for (int i = 0; i < p_attachments; i++) {
-
- Attachment ba;
- ba.enable_blend = true;
- ba.src_color_blend_factor = BLEND_FACTOR_SRC_ALPHA;
- ba.dst_color_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- ba.src_alpha_blend_factor = BLEND_FACTOR_SRC_ALPHA;
- ba.dst_alpha_blend_factor = BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
-
- bs.attachments.push_back(ba);
- }
- return bs;
- }
-
- Vector<Attachment> attachments; //one per render target texture
- Color blend_constant;
-
- PipelineColorBlendState() {
- enable_logic_op = false;
- logic_op = LOGIC_OP_CLEAR;
- }
- };
-
- enum PipelineDynamicStateFlags {
- DYNAMIC_STATE_LINE_WIDTH = (1 << 0),
- DYNAMIC_STATE_DEPTH_BIAS = (1 << 1),
- DYNAMIC_STATE_BLEND_CONSTANTS = (1 << 2),
- DYNAMIC_STATE_DEPTH_BOUNDS = (1 << 3),
- DYNAMIC_STATE_STENCIL_COMPARE_MASK = (1 << 4),
- DYNAMIC_STATE_STENCIL_WRITE_MASK = (1 << 5),
- DYNAMIC_STATE_STENCIL_REFERENCE = (1 << 6),
- };
-
- virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0;
- virtual bool render_pipeline_is_valid(RID p_pipeline) = 0;
-
- /**************************/
- /**** COMPUTE PIPELINE ****/
- /**************************/
-
- virtual RID compute_pipeline_create(RID p_shader) = 0;
- virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0;
-
- /****************/
- /**** SCREEN ****/
- /****************/
-
- virtual int screen_get_width(int p_screen = 0) const = 0;
- virtual int screen_get_height(int p_screen = 0) const = 0;
- virtual FramebufferFormatID screen_get_framebuffer_format() const = 0;
-
- /********************/
- /**** DRAW LISTS ****/
- /********************/
-
- enum InitialAction {
- INITIAL_ACTION_CLEAR, //start rendering and clear the framebuffer (supply params)
- INITIAL_ACTION_KEEP, //start rendering, but keep attached color texture contents (depth will be cleared)
- INITIAL_ACTION_CONTINUE, //continue rendering (framebuffer must have been left in "continue" state as final action previously)
- INITIAL_ACTION_MAX
- };
-
- enum FinalAction {
- FINAL_ACTION_READ, //will no longer render to it, allows attached textures to be read again, but depth buffer contents will be dropped (Can't be read from)
- FINAL_ACTION_DISCARD, // discard contents after rendering
- FINAL_ACTION_CONTINUE, //will continue rendering later, attached textures can't be read until re-bound with "finish"
- FINAL_ACTION_MAX
- };
-
- typedef int64_t DrawListID;
-
- virtual DrawListID draw_list_begin_for_screen(int p_screen = 0, const Color &p_clear_color = Color()) = 0;
- virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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()) = 0;
- virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, 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()) = 0;
-
- virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0;
- virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
- virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0;
- virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array) = 0;
- virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0;
- virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0;
-
- virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0) = 0;
-
- virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0;
- virtual void draw_list_disable_scissor(DrawListID p_list) = 0;
-
- virtual void draw_list_end() = 0;
-
- /***********************/
- /**** COMPUTE LISTS ****/
- /***********************/
-
- typedef int64_t ComputeListID;
-
- virtual ComputeListID compute_list_begin() = 0;
- virtual void compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) = 0;
- virtual void compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
- virtual void compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) = 0;
- virtual void compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) = 0;
- virtual void compute_list_add_barrier(ComputeListID p_list) = 0;
-
- virtual void compute_list_end() = 0;
-
- /***************/
- /**** FREE! ****/
- /***************/
-
- virtual void free(RID p_id) = 0;
-
- /****************/
- /**** Timing ****/
- /****************/
-
- virtual void capture_timestamp(const String &p_name, bool p_sync_to_draw) = 0;
- virtual uint32_t get_captured_timestamps_count() const = 0;
- virtual uint64_t get_captured_timestamps_frame() const = 0;
- virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const = 0;
- virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const = 0;
- virtual String get_captured_timestamp_name(uint32_t p_index) const = 0;
-
- /****************/
- /**** LIMITS ****/
- /****************/
-
- enum Limit {
- LIMIT_MAX_BOUND_UNIFORM_SETS,
- LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS,
- LIMIT_MAX_TEXTURES_PER_UNIFORM_SET,
- LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET,
- LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET,
- LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET,
- LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET,
- LIMIT_MAX_DRAW_INDEXED_INDEX,
- LIMIT_MAX_FRAMEBUFFER_HEIGHT,
- LIMIT_MAX_FRAMEBUFFER_WIDTH,
- LIMIT_MAX_TEXTURE_ARRAY_LAYERS,
- LIMIT_MAX_TEXTURE_SIZE_1D,
- LIMIT_MAX_TEXTURE_SIZE_2D,
- LIMIT_MAX_TEXTURE_SIZE_3D,
- LIMIT_MAX_TEXTURE_SIZE_CUBE,
- LIMIT_MAX_TEXTURES_PER_SHADER_STAGE,
- LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE,
- LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE,
- LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE,
- LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE,
- LIMIT_MAX_PUSH_CONSTANT_SIZE,
- LIMIT_MAX_UNIFORM_BUFFER_SIZE,
- LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET,
- LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES,
- LIMIT_MAX_VERTEX_INPUT_BINDINGS,
- LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE,
- LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
- LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE,
- LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X,
- LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y,
- LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z,
- LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS,
- LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X,
- LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y,
- LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z,
- };
-
- virtual int limit_get(Limit p_limit) = 0;
-
- //methods below not exposed, used by RenderingDeviceRD
- virtual void prepare_screen_for_drawing() = 0;
-
- virtual void swap_buffers() = 0;
-
- virtual uint32_t get_frame_delay() const = 0;
-
- static RenderingDevice *get_singleton();
-
- RenderingDevice();
-};
-
-typedef RenderingDevice RD;
-
-#endif // RENDERING_DEVICE_H
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
deleted file mode 100644
index 8cd0dc7937..0000000000
--- a/servers/visual/shader_language.cpp
+++ /dev/null
@@ -1,6904 +0,0 @@
-/*************************************************************************/
-/* shader_language.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "shader_language.h"
-#include "core/os/os.h"
-#include "core/print_string.h"
-#include "servers/visual_server.h"
-
-static bool _is_text_char(CharType c) {
-
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
-}
-
-static bool _is_number(CharType c) {
-
- return (c >= '0' && c <= '9');
-}
-
-static bool _is_hex(CharType c) {
-
- return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
-}
-
-String ShaderLanguage::get_operator_text(Operator p_op) {
-
- static const char *op_names[OP_MAX] = { "==",
- "!=",
- "<",
- "<=",
- ">",
- ">=",
- "&&",
- "||",
- "!",
- "-",
- "+",
- "-",
- "*",
- "/",
- "%",
- "<<",
- ">>",
- "=",
- "+=",
- "-=",
- "*=",
- "/=",
- "%=",
- "<<=",
- ">>=",
- "&=",
- "|=",
- "^=",
- "&",
- "|",
- "^",
- "~",
- "++",
- "--",
- "?",
- ":",
- "++",
- "--",
- "()",
- "construct",
- "index" };
-
- return op_names[p_op];
-}
-
-const char *ShaderLanguage::token_names[TK_MAX] = {
- "EMPTY",
- "IDENTIFIER",
- "TRUE",
- "FALSE",
- "REAL_CONSTANT",
- "INT_CONSTANT",
- "TYPE_VOID",
- "TYPE_BOOL",
- "TYPE_BVEC2",
- "TYPE_BVEC3",
- "TYPE_BVEC4",
- "TYPE_INT",
- "TYPE_IVEC2",
- "TYPE_IVEC3",
- "TYPE_IVEC4",
- "TYPE_UINT",
- "TYPE_UVEC2",
- "TYPE_UVEC3",
- "TYPE_UVEC4",
- "TYPE_FLOAT",
- "TYPE_VEC2",
- "TYPE_VEC3",
- "TYPE_VEC4",
- "TYPE_MAT2",
- "TYPE_MAT3",
- "TYPE_MAT4",
- "TYPE_SAMPLER2D",
- "TYPE_ISAMPLER2D",
- "TYPE_USAMPLER2D",
- "TYPE_SAMPLER2DARRAY",
- "TYPE_ISAMPLER2DARRAY",
- "TYPE_USAMPLER2DARRAY",
- "TYPE_SAMPLER3D",
- "TYPE_ISAMPLER3D",
- "TYPE_USAMPLER3D",
- "TYPE_SAMPLERCUBE",
- "INTERPOLATION_FLAT",
- "INTERPOLATION_SMOOTH",
- "CONST",
- "PRECISION_LOW",
- "PRECISION_MID",
- "PRECISION_HIGH",
- "OP_EQUAL",
- "OP_NOT_EQUAL",
- "OP_LESS",
- "OP_LESS_EQUAL",
- "OP_GREATER",
- "OP_GREATER_EQUAL",
- "OP_AND",
- "OP_OR",
- "OP_NOT",
- "OP_ADD",
- "OP_SUB",
- "OP_MUL",
- "OP_DIV",
- "OP_MOD",
- "OP_SHIFT_LEFT",
- "OP_SHIFT_RIGHT",
- "OP_ASSIGN",
- "OP_ASSIGN_ADD",
- "OP_ASSIGN_SUB",
- "OP_ASSIGN_MUL",
- "OP_ASSIGN_DIV",
- "OP_ASSIGN_MOD",
- "OP_ASSIGN_SHIFT_LEFT",
- "OP_ASSIGN_SHIFT_RIGHT",
- "OP_ASSIGN_BIT_AND",
- "OP_ASSIGN_BIT_OR",
- "OP_ASSIGN_BIT_XOR",
- "OP_BIT_AND",
- "OP_BIT_OR",
- "OP_BIT_XOR",
- "OP_BIT_INVERT",
- "OP_INCREMENT",
- "OP_DECREMENT",
- "CF_IF",
- "CF_ELSE",
- "CF_FOR",
- "CF_WHILE",
- "CF_DO",
- "CF_SWITCH",
- "CF_CASE",
- "CF_BREAK",
- "CF_CONTINUE",
- "CF_RETURN",
- "CF_DISCARD",
- "BRACKET_OPEN",
- "BRACKET_CLOSE",
- "CURLY_BRACKET_OPEN",
- "CURLY_BRACKET_CLOSE",
- "PARENTHESIS_OPEN",
- "PARENTHESIS_CLOSE",
- "QUESTION",
- "COMMA",
- "COLON",
- "SEMICOLON",
- "PERIOD",
- "UNIFORM",
- "VARYING",
- "IN",
- "OUT",
- "INOUT",
- "RENDER_MODE",
- "HINT_WHITE_TEXTURE",
- "HINT_BLACK_TEXTURE",
- "HINT_NORMAL_TEXTURE",
- "HINT_ANISO_TEXTURE",
- "HINT_ALBEDO_TEXTURE",
- "HINT_BLACK_ALBEDO_TEXTURE",
- "HINT_COLOR",
- "HINT_RANGE",
- "FILTER_NEAREST",
- "FILTER_LINEAR",
- "FILTER_NEAREST_MIPMAP",
- "FILTER_LINEAR_MIPMAP",
- "FILTER_NEAREST_MIPMAP_ANISO",
- "FILTER_LINEAR_MIPMAP_ANISO",
- "REPEAT_ENABLE",
- "REPEAT_DISABLE",
- "SHADER_TYPE",
- "CURSOR",
- "ERROR",
- "EOF",
-};
-
-String ShaderLanguage::get_token_text(Token p_token) {
-
- String name = token_names[p_token.type];
- if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) {
- name += "(" + rtos(p_token.constant) + ")";
- } else if (p_token.type == TK_IDENTIFIER) {
- name += "(" + String(p_token.text) + ")";
- } else if (p_token.type == TK_ERROR) {
- name += "(" + String(p_token.text) + ")";
- }
-
- return name;
-}
-
-ShaderLanguage::Token ShaderLanguage::_make_token(TokenType p_type, const StringName &p_text) {
-
- Token tk;
- tk.type = p_type;
- tk.text = p_text;
- tk.line = tk_line;
- if (tk.type == TK_ERROR) {
- _set_error(p_text);
- }
- return tk;
-}
-
-const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
- { TK_TRUE, "true" },
- { TK_FALSE, "false" },
- { TK_TYPE_VOID, "void" },
- { TK_TYPE_BOOL, "bool" },
- { TK_TYPE_BVEC2, "bvec2" },
- { TK_TYPE_BVEC3, "bvec3" },
- { TK_TYPE_BVEC4, "bvec4" },
- { TK_TYPE_INT, "int" },
- { TK_TYPE_IVEC2, "ivec2" },
- { TK_TYPE_IVEC3, "ivec3" },
- { TK_TYPE_IVEC4, "ivec4" },
- { TK_TYPE_UINT, "uint" },
- { TK_TYPE_UVEC2, "uvec2" },
- { TK_TYPE_UVEC3, "uvec3" },
- { TK_TYPE_UVEC4, "uvec4" },
- { TK_TYPE_FLOAT, "float" },
- { TK_TYPE_VEC2, "vec2" },
- { TK_TYPE_VEC3, "vec3" },
- { TK_TYPE_VEC4, "vec4" },
- { TK_TYPE_MAT2, "mat2" },
- { TK_TYPE_MAT3, "mat3" },
- { TK_TYPE_MAT4, "mat4" },
- { TK_TYPE_SAMPLER2D, "sampler2D" },
- { TK_TYPE_ISAMPLER2D, "isampler2D" },
- { TK_TYPE_USAMPLER2D, "usampler2D" },
- { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray" },
- { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray" },
- { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray" },
- { TK_TYPE_SAMPLER3D, "sampler3D" },
- { TK_TYPE_ISAMPLER3D, "isampler3D" },
- { TK_TYPE_USAMPLER3D, "usampler3D" },
- { TK_TYPE_SAMPLERCUBE, "samplerCube" },
- { TK_INTERPOLATION_FLAT, "flat" },
- { TK_INTERPOLATION_SMOOTH, "smooth" },
- { TK_CONST, "const" },
- { TK_STRUCT, "struct" },
- { TK_PRECISION_LOW, "lowp" },
- { TK_PRECISION_MID, "mediump" },
- { TK_PRECISION_HIGH, "highp" },
- { TK_CF_IF, "if" },
- { TK_CF_ELSE, "else" },
- { TK_CF_FOR, "for" },
- { TK_CF_WHILE, "while" },
- { TK_CF_DO, "do" },
- { TK_CF_SWITCH, "switch" },
- { TK_CF_CASE, "case" },
- { TK_CF_DEFAULT, "default" },
- { TK_CF_BREAK, "break" },
- { TK_CF_CONTINUE, "continue" },
- { TK_CF_RETURN, "return" },
- { TK_CF_DISCARD, "discard" },
- { TK_UNIFORM, "uniform" },
- { TK_VARYING, "varying" },
- { TK_ARG_IN, "in" },
- { TK_ARG_OUT, "out" },
- { TK_ARG_INOUT, "inout" },
- { TK_RENDER_MODE, "render_mode" },
- { TK_HINT_WHITE_TEXTURE, "hint_white" },
- { TK_HINT_BLACK_TEXTURE, "hint_black" },
- { TK_HINT_NORMAL_TEXTURE, "hint_normal" },
- { TK_HINT_ROUGHNESS_NORMAL_TEXTURE, "hint_roughness_normal" },
- { TK_HINT_ROUGHNESS_R, "hint_roughness_r" },
- { TK_HINT_ROUGHNESS_G, "hint_roughness_g" },
- { TK_HINT_ROUGHNESS_B, "hint_roughness_b" },
- { TK_HINT_ROUGHNESS_A, "hint_roughness_a" },
- { TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray" },
- { TK_HINT_ANISO_TEXTURE, "hint_aniso" },
- { TK_HINT_ALBEDO_TEXTURE, "hint_albedo" },
- { TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" },
- { TK_HINT_COLOR, "hint_color" },
- { TK_HINT_RANGE, "hint_range" },
- { TK_FILTER_NEAREST, "filter_nearest" },
- { TK_FILTER_LINEAR, "filter_linear" },
- { TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap" },
- { TK_FILTER_LINEAR_MIPMAP, "filter_linear_mipmap" },
- { TK_FILTER_NEAREST_MIPMAP_ANISO, "filter_nearest_mipmap_aniso" },
- { TK_FILTER_LINEAR_MIPMAP_ANISO, "filter_linear_mipmap_aniso" },
- { TK_REPEAT_ENABLE, "repeat_enable" },
- { TK_REPEAT_DISABLE, "repeat_disable" },
- { TK_SHADER_TYPE, "shader_type" },
- { TK_ERROR, NULL }
-};
-
-ShaderLanguage::Token ShaderLanguage::_get_token() {
-
-#define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : CharType(0))
-
- while (true) {
- char_idx++;
- switch (GETCHAR(-1)) {
-
- case 0:
- return _make_token(TK_EOF);
- case 0xFFFF:
- return _make_token(TK_CURSOR); //for completion
- case '\t':
- case '\r':
- case ' ':
- continue;
- case '\n':
- tk_line++;
- continue;
- case '/': {
-
- switch (GETCHAR(0)) {
- case '*': { // block comment
-
- char_idx++;
- while (true) {
- if (GETCHAR(0) == 0) {
- return _make_token(TK_EOF);
- }
- if (GETCHAR(0) == '*' && GETCHAR(1) == '/') {
- char_idx += 2;
- break;
- } else if (GETCHAR(0) == '\n') {
- tk_line++;
- }
-
- char_idx++;
- }
-
- } break;
- case '/': { // line comment skip
-
- while (true) {
- if (GETCHAR(0) == '\n') {
- tk_line++;
- char_idx++;
- break;
- }
- if (GETCHAR(0) == 0) {
- return _make_token(TK_EOF);
- }
- char_idx++;
- }
-
- } break;
- case '=': { // diveq
-
- char_idx++;
- return _make_token(TK_OP_ASSIGN_DIV);
-
- } break;
- default:
- return _make_token(TK_OP_DIV);
- }
-
- continue; //a comment, continue to next token
- } break;
- case '=': {
-
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_EQUAL);
- }
-
- return _make_token(TK_OP_ASSIGN);
-
- } break;
- case '<': {
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_LESS_EQUAL);
- } else if (GETCHAR(0) == '<') {
- char_idx++;
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_SHIFT_LEFT);
- }
-
- return _make_token(TK_OP_SHIFT_LEFT);
- }
-
- return _make_token(TK_OP_LESS);
-
- } break;
- case '>': {
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_GREATER_EQUAL);
- } else if (GETCHAR(0) == '>') {
- char_idx++;
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_SHIFT_RIGHT);
- }
-
- return _make_token(TK_OP_SHIFT_RIGHT);
- }
-
- return _make_token(TK_OP_GREATER);
-
- } break;
- case '!': {
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_NOT_EQUAL);
- }
-
- return _make_token(TK_OP_NOT);
-
- } break;
- //case '"' //string - no strings in shader
- //case '\'' //string - no strings in shader
- case '{':
- return _make_token(TK_CURLY_BRACKET_OPEN);
- case '}':
- return _make_token(TK_CURLY_BRACKET_CLOSE);
- case '[':
- return _make_token(TK_BRACKET_OPEN);
- case ']':
- return _make_token(TK_BRACKET_CLOSE);
- case '(':
- return _make_token(TK_PARENTHESIS_OPEN);
- case ')':
- return _make_token(TK_PARENTHESIS_CLOSE);
- case ',':
- return _make_token(TK_COMMA);
- case ';':
- return _make_token(TK_SEMICOLON);
- case '?':
- return _make_token(TK_QUESTION);
- case ':':
- return _make_token(TK_COLON);
- case '^':
- return _make_token(TK_OP_BIT_XOR);
- case '~':
- return _make_token(TK_OP_BIT_INVERT);
- case '&': {
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_BIT_AND);
- } else if (GETCHAR(0) == '&') {
- char_idx++;
- return _make_token(TK_OP_AND);
- }
- return _make_token(TK_OP_BIT_AND);
- } break;
- case '|': {
-
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_BIT_OR);
- } else if (GETCHAR(0) == '|') {
- char_idx++;
- return _make_token(TK_OP_OR);
- }
- return _make_token(TK_OP_BIT_OR);
-
- } break;
- case '*': {
-
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_MUL);
- }
- return _make_token(TK_OP_MUL);
- } break;
- case '+': {
-
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_ADD);
- } else if (GETCHAR(0) == '+') {
-
- char_idx++;
- return _make_token(TK_OP_INCREMENT);
- }
-
- return _make_token(TK_OP_ADD);
- } break;
- case '-': {
-
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_SUB);
- } else if (GETCHAR(0) == '-') {
-
- char_idx++;
- return _make_token(TK_OP_DECREMENT);
- }
-
- return _make_token(TK_OP_SUB);
- } break;
- case '%': {
-
- if (GETCHAR(0) == '=') {
- char_idx++;
- return _make_token(TK_OP_ASSIGN_MOD);
- }
-
- return _make_token(TK_OP_MOD);
- } break;
- default: {
-
- char_idx--; //go back one, since we have no idea what this is
-
- if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
- // parse number
- bool period_found = false;
- bool exponent_found = false;
- bool hexa_found = false;
- bool sign_found = false;
- bool float_suffix_found = false;
-
- String str;
- int i = 0;
-
- while (true) {
- if (GETCHAR(i) == '.') {
- if (period_found || exponent_found || hexa_found || float_suffix_found)
- return _make_token(TK_ERROR, "Invalid numeric constant");
- period_found = true;
- } else if (GETCHAR(i) == 'x') {
- if (hexa_found || str.length() != 1 || str[0] != '0')
- return _make_token(TK_ERROR, "Invalid numeric constant");
- hexa_found = true;
- } else if (GETCHAR(i) == 'e') {
- if (hexa_found || 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)
- return _make_token(TK_ERROR, "Invalid numeric constant");
- float_suffix_found = true;
- } else if (_is_number(GETCHAR(i))) {
- if (float_suffix_found)
- return _make_token(TK_ERROR, "Invalid numeric constant");
- } else if (hexa_found && _is_hex(GETCHAR(i))) {
-
- } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
- if (sign_found)
- return _make_token(TK_ERROR, "Invalid numeric constant");
- sign_found = true;
- } else
- break;
-
- str += CharType(GETCHAR(i));
- i++;
- }
-
- CharType last_char = str[str.length() - 1];
-
- if (hexa_found) {
- //integer(hex)
- if (str.size() > 11 || !str.is_valid_hex_number(true)) { // > 0xFFFFFFFF
- return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
- }
- } else if (period_found || exponent_found || float_suffix_found) {
- //floats
- if (period_found) {
- if (float_suffix_found) {
- //checks for eg "1.f" or "1.99f" notations
- if (last_char != 'f') {
- return _make_token(TK_ERROR, "Invalid (float) numeric constant");
- }
- } else {
- //checks for eg. "1." or "1.99" notations
- if (last_char != '.' && !_is_number(last_char)) {
- return _make_token(TK_ERROR, "Invalid (float) numeric constant");
- }
- }
- } else if (float_suffix_found) {
- // if no period found the float suffix must be the last character, like in "2f" for "2.0"
- if (last_char != 'f') {
- return _make_token(TK_ERROR, "Invalid (float) numeric constant");
- }
- }
-
- if (float_suffix_found) {
- //strip the suffix
- str = str.left(str.length() - 1);
- //compensate reading cursor position
- char_idx += 1;
- }
-
- if (!str.is_valid_float()) {
- return _make_token(TK_ERROR, "Invalid (float) numeric constant");
- }
- } else {
- //integers
- if (!_is_number(last_char)) {
- return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
- }
- if (!str.is_valid_integer()) {
- return _make_token(TK_ERROR, "Invalid numeric constant");
- }
- }
-
- char_idx += str.length();
- Token tk;
- if (period_found || exponent_found || float_suffix_found)
- tk.type = TK_REAL_CONSTANT;
- else
- tk.type = TK_INT_CONSTANT;
-
- if (hexa_found) {
- tk.constant = (double)str.hex_to_int64(true);
- } else {
- tk.constant = str.to_double();
- }
- tk.line = tk_line;
-
- return tk;
- }
-
- if (GETCHAR(0) == '.') {
- //parse period
- char_idx++;
- return _make_token(TK_PERIOD);
- }
-
- if (_is_text_char(GETCHAR(0))) {
- // parse identifier
- String str;
-
- while (_is_text_char(GETCHAR(0))) {
-
- str += CharType(GETCHAR(0));
- char_idx++;
- }
-
- //see if keyword
- //should be converted to a static map
- int idx = 0;
-
- while (keyword_list[idx].text) {
-
- if (str == keyword_list[idx].text) {
-
- return _make_token(keyword_list[idx].token);
- }
- idx++;
- }
-
- str = str.replace("dus_", "_");
-
- return _make_token(TK_IDENTIFIER, str);
- }
-
- if (GETCHAR(0) > 32)
- return _make_token(TK_ERROR, "Tokenizer: Unknown character #" + itos(GETCHAR(0)) + ": '" + String::chr(GETCHAR(0)) + "'");
- else
- return _make_token(TK_ERROR, "Tokenizer: Unknown character #" + itos(GETCHAR(0)));
-
- } break;
- }
- }
- ERR_PRINT("BUG");
- return Token();
-
-#undef GETCHAR
-}
-
-String ShaderLanguage::token_debug(const String &p_code) {
-
- clear();
-
- code = p_code;
-
- String output;
-
- Token tk = _get_token();
- while (tk.type != TK_EOF && tk.type != TK_ERROR) {
-
- output += itos(tk_line) + ": " + get_token_text(tk) + "\n";
- tk = _get_token();
- }
-
- return output;
-}
-
-bool ShaderLanguage::is_token_variable_datatype(TokenType p_type) {
- return (
- p_type == TK_TYPE_VOID ||
- p_type == TK_TYPE_BOOL ||
- p_type == TK_TYPE_BVEC2 ||
- p_type == TK_TYPE_BVEC3 ||
- p_type == TK_TYPE_BVEC4 ||
- p_type == TK_TYPE_INT ||
- p_type == TK_TYPE_IVEC2 ||
- p_type == TK_TYPE_IVEC3 ||
- p_type == TK_TYPE_IVEC4 ||
- p_type == TK_TYPE_UINT ||
- p_type == TK_TYPE_UVEC2 ||
- p_type == TK_TYPE_UVEC3 ||
- p_type == TK_TYPE_UVEC4 ||
- p_type == TK_TYPE_FLOAT ||
- p_type == TK_TYPE_VEC2 ||
- p_type == TK_TYPE_VEC3 ||
- p_type == TK_TYPE_VEC4 ||
- p_type == TK_TYPE_MAT2 ||
- p_type == TK_TYPE_MAT3 ||
- p_type == TK_TYPE_MAT4);
-}
-
-bool ShaderLanguage::is_token_datatype(TokenType p_type) {
-
- return (
- p_type == TK_TYPE_VOID ||
- p_type == TK_TYPE_BOOL ||
- p_type == TK_TYPE_BVEC2 ||
- p_type == TK_TYPE_BVEC3 ||
- p_type == TK_TYPE_BVEC4 ||
- p_type == TK_TYPE_INT ||
- p_type == TK_TYPE_IVEC2 ||
- p_type == TK_TYPE_IVEC3 ||
- p_type == TK_TYPE_IVEC4 ||
- p_type == TK_TYPE_UINT ||
- p_type == TK_TYPE_UVEC2 ||
- p_type == TK_TYPE_UVEC3 ||
- p_type == TK_TYPE_UVEC4 ||
- p_type == TK_TYPE_FLOAT ||
- p_type == TK_TYPE_VEC2 ||
- p_type == TK_TYPE_VEC3 ||
- p_type == TK_TYPE_VEC4 ||
- p_type == TK_TYPE_MAT2 ||
- p_type == TK_TYPE_MAT3 ||
- p_type == TK_TYPE_MAT4 ||
- p_type == TK_TYPE_SAMPLER2D ||
- p_type == TK_TYPE_ISAMPLER2D ||
- p_type == TK_TYPE_USAMPLER2D ||
- p_type == TK_TYPE_SAMPLER2DARRAY ||
- p_type == TK_TYPE_ISAMPLER2DARRAY ||
- p_type == TK_TYPE_USAMPLER2DARRAY ||
- p_type == TK_TYPE_SAMPLER3D ||
- p_type == TK_TYPE_ISAMPLER3D ||
- p_type == TK_TYPE_USAMPLER3D ||
- p_type == TK_TYPE_SAMPLERCUBE);
-}
-
-ShaderLanguage::DataType ShaderLanguage::get_token_datatype(TokenType p_type) {
-
- return DataType(p_type - TK_TYPE_VOID);
-}
-
-bool ShaderLanguage::is_token_interpolation(TokenType p_type) {
-
- return (
- p_type == TK_INTERPOLATION_FLAT ||
- p_type == TK_INTERPOLATION_SMOOTH);
-}
-
-ShaderLanguage::DataInterpolation ShaderLanguage::get_token_interpolation(TokenType p_type) {
-
- if (p_type == TK_INTERPOLATION_FLAT)
- return INTERPOLATION_FLAT;
- else
- return INTERPOLATION_SMOOTH;
-}
-
-bool ShaderLanguage::is_token_precision(TokenType p_type) {
-
- return (
- p_type == TK_PRECISION_LOW ||
- p_type == TK_PRECISION_MID ||
- p_type == TK_PRECISION_HIGH);
-}
-
-ShaderLanguage::DataPrecision ShaderLanguage::get_token_precision(TokenType p_type) {
-
- if (p_type == TK_PRECISION_LOW)
- return PRECISION_LOWP;
- else if (p_type == TK_PRECISION_HIGH)
- return PRECISION_HIGHP;
- else
- return PRECISION_MEDIUMP;
-}
-
-String ShaderLanguage::get_precision_name(DataPrecision p_type) {
- switch (p_type) {
- case PRECISION_LOWP: return "lowp";
- case PRECISION_MEDIUMP: return "mediump";
- case PRECISION_HIGHP: return "highp";
- default:
- break;
- }
- return "";
-}
-
-String ShaderLanguage::get_datatype_name(DataType p_type) {
-
- switch (p_type) {
-
- case TYPE_VOID: return "void";
- case TYPE_BOOL: return "bool";
- case TYPE_BVEC2: return "bvec2";
- case TYPE_BVEC3: return "bvec3";
- case TYPE_BVEC4: return "bvec4";
- case TYPE_INT: return "int";
- case TYPE_IVEC2: return "ivec2";
- case TYPE_IVEC3: return "ivec3";
- case TYPE_IVEC4: return "ivec4";
- case TYPE_UINT: return "uint";
- case TYPE_UVEC2: return "uvec2";
- case TYPE_UVEC3: return "uvec3";
- case TYPE_UVEC4: return "uvec4";
- case TYPE_FLOAT: return "float";
- case TYPE_VEC2: return "vec2";
- case TYPE_VEC3: return "vec3";
- case TYPE_VEC4: return "vec4";
- case TYPE_MAT2: return "mat2";
- case TYPE_MAT3: return "mat3";
- case TYPE_MAT4: return "mat4";
- case TYPE_SAMPLER2D: return "sampler2D";
- case TYPE_ISAMPLER2D: return "isampler2D";
- case TYPE_USAMPLER2D: return "usampler2D";
- case TYPE_SAMPLER2DARRAY: return "sampler2DArray";
- case TYPE_ISAMPLER2DARRAY: return "isampler2DArray";
- case TYPE_USAMPLER2DARRAY: return "usampler2DArray";
- case TYPE_SAMPLER3D: return "sampler3D";
- case TYPE_ISAMPLER3D: return "isampler3D";
- case TYPE_USAMPLER3D: return "usampler3D";
- case TYPE_SAMPLERCUBE: return "samplerCube";
- case TYPE_STRUCT: return "struct";
- }
-
- return "";
-}
-
-bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
-
- return is_token_datatype(p_type) && p_type != TK_TYPE_VOID;
-}
-
-void ShaderLanguage::clear() {
-
- current_function = StringName();
-
- completion_type = COMPLETION_NONE;
- completion_block = NULL;
- completion_function = StringName();
- completion_class = SubClassTag::TAG_GLOBAL;
- completion_struct = StringName();
-
- error_line = 0;
- tk_line = 1;
- char_idx = 0;
- error_set = false;
- error_str = "";
- while (nodes) {
- Node *n = nodes;
- nodes = nodes->next;
- memdelete(n);
- }
-}
-
-bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
-
- if (p_builtin_types.has(p_identifier)) {
-
- if (r_data_type) {
- *r_data_type = p_builtin_types[p_identifier].type;
- }
- if (r_is_const) {
- *r_is_const = p_builtin_types[p_identifier].constant;
- }
- if (r_type) {
- *r_type = IDENTIFIER_BUILTIN_VAR;
- }
-
- return true;
- }
-
- FunctionNode *function = NULL;
-
- while (p_block) {
-
- if (p_block->variables.has(p_identifier)) {
- if (r_data_type) {
- *r_data_type = p_block->variables[p_identifier].type;
- }
- if (r_is_const) {
- *r_is_const = p_block->variables[p_identifier].is_const;
- }
- if (r_array_size) {
- *r_array_size = p_block->variables[p_identifier].array_size;
- }
- if (r_type) {
- *r_type = IDENTIFIER_LOCAL_VAR;
- }
- if (r_struct_name) {
- *r_struct_name = p_block->variables[p_identifier].struct_name;
- }
-
- return true;
- }
-
- if (p_block->parent_function) {
- function = p_block->parent_function;
- break;
- } else {
- ERR_FAIL_COND_V(!p_block->parent_block, false);
- p_block = p_block->parent_block;
- }
- }
-
- if (function) {
- for (int i = 0; i < function->arguments.size(); i++) {
- if (function->arguments[i].name == p_identifier) {
- if (r_data_type) {
- *r_data_type = function->arguments[i].type;
- }
- if (r_type) {
- *r_type = IDENTIFIER_FUNCTION_ARGUMENT;
- }
- if (r_struct_name) {
- *r_struct_name = function->arguments[i].type_str;
- }
- return true;
- }
- }
- }
-
- if (shader->varyings.has(p_identifier)) {
- if (r_data_type) {
- *r_data_type = shader->varyings[p_identifier].type;
- }
- if (r_array_size) {
- *r_array_size = shader->varyings[p_identifier].array_size;
- }
- if (r_type) {
- *r_type = IDENTIFIER_VARYING;
- }
- return true;
- }
-
- if (shader->uniforms.has(p_identifier)) {
- if (r_data_type) {
- *r_data_type = shader->uniforms[p_identifier].type;
- }
- if (r_type) {
- *r_type = IDENTIFIER_UNIFORM;
- }
- return true;
- }
-
- if (shader->constants.has(p_identifier)) {
- if (r_data_type) {
- *r_data_type = shader->constants[p_identifier].type;
- }
- if (r_type) {
- *r_type = IDENTIFIER_CONSTANT;
- }
- if (r_struct_name) {
- *r_struct_name = shader->constants[p_identifier].type_str;
- }
- return true;
- }
-
- for (int i = 0; i < shader->functions.size(); i++) {
-
- if (!shader->functions[i].callable)
- continue;
-
- if (shader->functions[i].name == p_identifier) {
- if (r_data_type) {
- *r_data_type = shader->functions[i].function->return_type;
- }
- if (r_type) {
- *r_type = IDENTIFIER_FUNCTION;
- }
- return true;
- }
- }
-
- return false;
-}
-
-bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type) {
-
- bool valid = false;
- DataType ret_type = TYPE_VOID;
-
- switch (p_op->op) {
- case OP_EQUAL:
- case OP_NOT_EQUAL: {
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
- valid = na == nb;
- ret_type = TYPE_BOOL;
- } break;
- case OP_LESS:
- case OP_LESS_EQUAL:
- case OP_GREATER:
- case OP_GREATER_EQUAL: {
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- valid = na == nb && (na == TYPE_UINT || na == TYPE_INT || na == TYPE_FLOAT);
- ret_type = TYPE_BOOL;
-
- } break;
- case OP_AND:
- case OP_OR: {
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- valid = na == nb && na == TYPE_BOOL;
- ret_type = TYPE_BOOL;
-
- } break;
- case OP_NOT: {
-
- DataType na = p_op->arguments[0]->get_datatype();
- valid = na == TYPE_BOOL;
- ret_type = TYPE_BOOL;
-
- } break;
- case OP_INCREMENT:
- case OP_DECREMENT:
- case OP_POST_INCREMENT:
- case OP_POST_DECREMENT:
- case OP_NEGATE: {
- DataType na = p_op->arguments[0]->get_datatype();
- valid = na > TYPE_BOOL && na < TYPE_MAT2;
- ret_type = na;
- } break;
- case OP_ADD:
- case OP_SUB:
- case OP_MUL:
- case OP_DIV: {
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- if (na > nb) {
- //make things easier;
- SWAP(na, nb);
- }
-
- if (na == nb) {
- valid = (na > TYPE_BOOL && na <= TYPE_MAT4);
- ret_type = na;
- } else if (na == TYPE_INT && nb == TYPE_IVEC2) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_INT && nb == TYPE_IVEC3) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_INT && nb == TYPE_IVEC4) {
- valid = true;
- ret_type = TYPE_IVEC4;
- } else if (na == TYPE_UINT && nb == TYPE_UVEC2) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UINT && nb == TYPE_UVEC3) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UINT && nb == TYPE_UVEC4) {
- valid = true;
- ret_type = TYPE_UVEC4;
- } else if (na == TYPE_FLOAT && nb == TYPE_VEC2) {
- valid = true;
- ret_type = TYPE_VEC2;
- } else if (na == TYPE_FLOAT && nb == TYPE_VEC3) {
- valid = true;
- ret_type = TYPE_VEC3;
- } else if (na == TYPE_FLOAT && nb == TYPE_VEC4) {
- valid = true;
- ret_type = TYPE_VEC4;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT2) {
- valid = true;
- ret_type = TYPE_MAT2;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT3) {
- valid = true;
- ret_type = TYPE_MAT3;
- } else if (p_op->op == OP_MUL && na == TYPE_FLOAT && nb == TYPE_MAT4) {
- valid = true;
- ret_type = TYPE_MAT4;
- } else if (p_op->op == OP_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
- valid = true;
- ret_type = TYPE_VEC2;
- } else if (p_op->op == OP_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) {
- valid = true;
- ret_type = TYPE_VEC3;
- } else if (p_op->op == OP_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) {
- valid = true;
- ret_type = TYPE_VEC4;
- }
- } break;
- case OP_ASSIGN_MOD:
- case OP_MOD: {
- /*
- * The operator modulus (%) operates on signed or unsigned integers or integer vectors. The operand
- * types must both be signed or both be unsigned. The operands cannot be vectors of differing size. If
- * one operand is a scalar and the other vector, then the scalar is applied component-wise to the vector,
- * resulting in the same type as the vector. If both are vectors of the same size, the result is computed
- * component-wise.
- */
-
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- if (na == TYPE_INT && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_INT;
- } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC4;
- } else if (na == TYPE_IVEC2 && nb == TYPE_IVEC2) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_IVEC3) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
- valid = true;
- ret_type = TYPE_IVEC4;
- /////
- } else if (na == TYPE_UINT && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UINT;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC4;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
- valid = true;
- ret_type = TYPE_UVEC4;
- }
- } break;
- case OP_ASSIGN_SHIFT_LEFT:
- case OP_ASSIGN_SHIFT_RIGHT:
- case OP_SHIFT_LEFT:
- case OP_SHIFT_RIGHT: {
-
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- if (na == TYPE_INT && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_INT;
- } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC4;
- } else if (na == TYPE_IVEC2 && nb == TYPE_IVEC2) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_IVEC3) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
- valid = true;
- ret_type = TYPE_IVEC4;
- } else if (na == TYPE_UINT && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UINT;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC4;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
- valid = true;
- ret_type = TYPE_UVEC4;
- }
- } break;
- case OP_ASSIGN: {
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
- if (na == TYPE_STRUCT || nb == TYPE_STRUCT) {
- valid = p_op->arguments[0]->get_datatype_name() == p_op->arguments[1]->get_datatype_name();
- } else {
- valid = na == nb;
- }
- ret_type = na;
- } break;
- case OP_ASSIGN_ADD:
- case OP_ASSIGN_SUB:
- case OP_ASSIGN_MUL:
- case OP_ASSIGN_DIV: {
-
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- if (na == nb) {
- valid = (na > TYPE_BOOL && na < TYPE_MAT2) || (p_op->op == OP_ASSIGN_MUL && na >= TYPE_MAT2 && na <= TYPE_MAT4);
- ret_type = na;
- } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC4;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC4;
- } else if (na == TYPE_VEC2 && nb == TYPE_FLOAT) {
- valid = true;
- ret_type = TYPE_VEC2;
- } else if (na == TYPE_VEC3 && nb == TYPE_FLOAT) {
- valid = true;
- ret_type = TYPE_VEC3;
- } else if (na == TYPE_VEC4 && nb == TYPE_FLOAT) {
- valid = true;
- ret_type = TYPE_VEC4;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT2 && nb == TYPE_VEC2) {
- valid = true;
- ret_type = TYPE_MAT2;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT3 && nb == TYPE_VEC3) {
- valid = true;
- ret_type = TYPE_MAT3;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT4 && nb == TYPE_VEC4) {
- valid = true;
- ret_type = TYPE_MAT4;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) {
- valid = true;
- ret_type = TYPE_VEC2;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) {
- valid = true;
- ret_type = TYPE_VEC3;
- } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) {
- valid = true;
- ret_type = TYPE_VEC4;
- }
- } break;
- case OP_ASSIGN_BIT_AND:
- case OP_ASSIGN_BIT_OR:
- case OP_ASSIGN_BIT_XOR:
- case OP_BIT_AND:
- case OP_BIT_OR:
- case OP_BIT_XOR: {
-
- /*
- * The bitwise operators and (&), exclusive-or (^), and inclusive-or (|). The operands must be of type
- * signed or unsigned integers or integer vectors. The operands cannot be vectors of differing size. If
- * one operand is a scalar and the other a vector, the scalar is applied component-wise to the vector,
- * resulting in the same type as the vector. The fundamental types of the operands (signed or unsigned)
- * must match.
- */
-
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
-
- if (na > nb && p_op->op >= OP_BIT_AND) {
- //can swap for non assign
- SWAP(na, nb);
- }
-
- if (na == TYPE_INT && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_INT;
- } else if (na == TYPE_IVEC2 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_INT) {
- valid = true;
- ret_type = TYPE_IVEC4;
- } else if (na == TYPE_IVEC2 && nb == TYPE_IVEC2) {
- valid = true;
- ret_type = TYPE_IVEC2;
- } else if (na == TYPE_IVEC3 && nb == TYPE_IVEC3) {
- valid = true;
- ret_type = TYPE_IVEC3;
- } else if (na == TYPE_IVEC4 && nb == TYPE_IVEC4) {
- valid = true;
- ret_type = TYPE_IVEC4;
- /////
- } else if (na == TYPE_UINT && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UINT;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UINT) {
- valid = true;
- ret_type = TYPE_UVEC4;
- } else if (na == TYPE_UVEC2 && nb == TYPE_UVEC2) {
- valid = true;
- ret_type = TYPE_UVEC2;
- } else if (na == TYPE_UVEC3 && nb == TYPE_UVEC3) {
- valid = true;
- ret_type = TYPE_UVEC3;
- } else if (na == TYPE_UVEC4 && nb == TYPE_UVEC4) {
- valid = true;
- ret_type = TYPE_UVEC4;
- }
- } break;
- case OP_BIT_INVERT: { //unaries
- DataType na = p_op->arguments[0]->get_datatype();
- valid = na >= TYPE_INT && na < TYPE_FLOAT;
- ret_type = na;
- } break;
- case OP_SELECT_IF: {
- DataType na = p_op->arguments[0]->get_datatype();
- DataType nb = p_op->arguments[1]->get_datatype();
- DataType nc = p_op->arguments[2]->get_datatype();
-
- valid = na == TYPE_BOOL && (nb == nc);
- ret_type = nb;
- } break;
- default: {
- ERR_FAIL_V(false);
- }
- }
-
- if (r_ret_type)
- *r_ret_type = ret_type;
- return valid;
-}
-
-const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
- //constructors
- { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC2, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BOOL, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BOOL, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC3, TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_INT, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_INT, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_INT, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UINT, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UINT, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "mat2", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "mat2", TYPE_MAT2, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- //conversion scalars
-
- { "int", TYPE_INT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "int", TYPE_INT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "int", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "float", TYPE_FLOAT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "float", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "float", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "float", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uint", TYPE_UINT, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, true },
- { "uint", TYPE_UINT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uint", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, TAG_GLOBAL, false },
- { "bool", TYPE_BOOL, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "bool", TYPE_BOOL, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "bool", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- //conversion vectors
-
- { "ivec2", TYPE_IVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec2", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "vec2", TYPE_VEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec2", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "vec2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uvec2", TYPE_UVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec2", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bvec2", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec2", TYPE_BVEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "bvec2", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "ivec3", TYPE_IVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec3", TYPE_IVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "ivec3", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "vec3", TYPE_VEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec3", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "vec3", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uvec3", TYPE_UVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec3", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bvec3", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec3", TYPE_BVEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "bvec3", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "ivec4", TYPE_IVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "ivec4", TYPE_IVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "ivec4", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "vec4", TYPE_VEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "vec4", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "vec4", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "uvec4", TYPE_UVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "uvec4", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "bvec4", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- //conversion between matrixes
-
- { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
-
- //builtins - trigonometry
-
- { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "radians", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "radians", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "radians", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "degrees", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "degrees", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "degrees", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "degrees", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "cos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "cos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "cos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "cos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "tan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "tan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "tan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "tan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "asin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "asin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "asin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "asin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "acos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "acos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "acos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "acos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "cosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "cosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "cosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "cosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "tanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "tanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "tanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "tanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "asinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "asinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "asinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "asinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "acosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "acosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "acosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "acosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "atanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "atanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "atanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "atanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- //builtins - exponential
- { "pow", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "pow", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "pow", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "pow", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "log", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "exp2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "log2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "inversesqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- //builtins - common
- { "abs", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "abs", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "abs", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sign", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "sign", TYPE_INT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "sign", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "floor", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "floor", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "floor", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "floor", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "trunc", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "round", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "roundEven", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "ceil", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "fract", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "mod", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "modf", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "modf", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "modf", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "modf", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "min", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "min", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "min", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "min", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "max", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "max", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "max", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "max", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "clamp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "clamp", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
- { "clamp", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "clamp", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "mix", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC2, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "step", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC2, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "smoothstep", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "isnan", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "isnan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "isnan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "isnan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "isinf", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "isinf", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "isinf", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "isinf", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "floatBitsToInt", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToInt", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToInt", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToInt", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "floatBitsToUint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToUint", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToUint", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "floatBitsToUint", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "intBitsToFloat", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "intBitsToFloat", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "intBitsToFloat", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "intBitsToFloat", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "uintBitsToFloat", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, TAG_GLOBAL, true },
- { "uintBitsToFloat", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "uintBitsToFloat", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "uintBitsToFloat", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- //builtins - geometric
- { "length", TYPE_FLOAT, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "length", TYPE_FLOAT, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "length", TYPE_FLOAT, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "distance", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "distance", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "distance", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "dot", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "dot", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "dot", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "cross", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "normalize", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "normalize", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "normalize", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
- { "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "faceforward", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "faceforward", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "faceforward", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "matrixCompMult", TYPE_MAT2, { TYPE_MAT2, TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "matrixCompMult", TYPE_MAT3, { TYPE_MAT3, TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "matrixCompMult", TYPE_MAT4, { TYPE_MAT4, TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "outerProduct", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "outerProduct", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "outerProduct", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "transpose", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "transpose", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "transpose", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "determinant", TYPE_FLOAT, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "determinant", TYPE_FLOAT, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "determinant", TYPE_FLOAT, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "inverse", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, TAG_GLOBAL, false },
- { "inverse", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, TAG_GLOBAL, false },
- { "inverse", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "greaterThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThan", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThan", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThan", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "lessThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "lessThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "lessThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "lessThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "greaterThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThanEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "greaterThanEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "greaterThanEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "greaterThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "equal", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "equal", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "equal", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "equal", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "equal", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "equal", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "equal", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "notEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "notEqual", TYPE_BVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "notEqual", TYPE_BVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "notEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "notEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "notEqual", TYPE_BVEC2, { TYPE_BVEC2, TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "notEqual", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "any", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "any", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "any", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "all", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "all", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "all", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "not", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "not", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "not", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, TAG_GLOBAL, false },
-
- //builtins - texture
- { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, false },
- { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
- { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, false },
-
- { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
- { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdy", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, TAG_GLOBAL, true },
- { "fwidth", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, TAG_GLOBAL, true },
- { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, TAG_GLOBAL, true },
- { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, TAG_GLOBAL, true },
-
- //sub-functions
-
- //array
- { "length", TYPE_INT, { TYPE_VOID }, TAG_ARRAY, true },
-
- { NULL, TYPE_VOID, { TYPE_VOID }, TAG_GLOBAL, false }
-
-};
-
-const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = {
- //constructors
- { "modf", 1 },
- { NULL, 0 }
-};
-
-bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
-
- ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
-
- Vector<DataType> args;
- Vector<StringName> args2;
-
- ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::TYPE_VARIABLE, false);
-
- StringName name = static_cast<VariableNode *>(p_func->arguments[0])->name.operator String();
-
- for (int i = 1; i < p_func->arguments.size(); i++) {
- args.push_back(p_func->arguments[i]->get_datatype());
- args2.push_back(p_func->arguments[i]->get_datatype_name());
- }
-
- int argcount = args.size();
-
- bool failed_builtin = false;
- bool unsupported_builtin = false;
- int builtin_idx = 0;
-
- if (argcount <= 4) {
- // test builtins
- int idx = 0;
-
- while (builtin_func_defs[idx].name) {
-
- if (completion_class != builtin_func_defs[idx].tag) {
- idx++;
- continue;
- }
-
- if (name == builtin_func_defs[idx].name) {
-
- failed_builtin = true;
- bool fail = false;
- for (int i = 0; i < argcount; i++) {
-
- if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) {
- //all good, but needs implicit conversion later
- } else if (args[i] != builtin_func_defs[idx].args[i]) {
- fail = true;
- break;
- }
- }
-
- if (!fail) {
- if (VisualServer::get_singleton()->is_low_end()) {
- if (builtin_func_defs[idx].high_end) {
- fail = true;
- unsupported_builtin = true;
- builtin_idx = idx;
- }
- }
- }
-
- if (!fail && argcount < 4 && builtin_func_defs[idx].args[argcount] != TYPE_VOID)
- fail = true; //make sure the number of arguments matches
-
- if (!fail) {
-
- //make sure its not an out argument used in the wrong way
- int outarg_idx = 0;
- while (builtin_func_out_args[outarg_idx].name) {
-
- if (String(name) == builtin_func_out_args[outarg_idx].name) {
- int arg_idx = builtin_func_out_args[outarg_idx].argument;
-
- if (arg_idx < argcount) {
-
- if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE) {
- _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable");
- return false;
- }
- StringName var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name;
-
- const BlockNode *b = p_block;
- bool valid = false;
- while (b) {
- if (b->variables.has(var_name)) {
- valid = true;
- break;
- }
- b = b->parent_block;
- }
-
- if (!valid) {
- _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable");
- return false;
- }
- }
- }
-
- outarg_idx++;
- }
- //implicitly convert values if possible
- for (int i = 0; i < argcount; i++) {
-
- if (get_scalar_type(args[i]) != args[i] || args[i] == builtin_func_defs[idx].args[i] || p_func->arguments[i + 1]->type != Node::TYPE_CONSTANT) {
- //can't do implicit conversion here
- continue;
- }
-
- //this is an implicit conversion
- ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[i + 1]);
- ConstantNode *conversion = alloc_node<ConstantNode>();
-
- conversion->datatype = builtin_func_defs[idx].args[i];
- conversion->values.resize(1);
-
- convert_constant(constant, builtin_func_defs[idx].args[i], conversion->values.ptrw());
- p_func->arguments.write[i + 1] = conversion;
- }
-
- if (r_ret_type)
- *r_ret_type = builtin_func_defs[idx].rettype;
-
- return true;
- }
- }
-
- idx++;
- }
- }
-
- if (unsupported_builtin) {
-
- String arglist = "";
- for (int i = 0; i < argcount; i++) {
- if (i > 0) {
- arglist += ", ";
- }
- arglist += get_datatype_name(builtin_func_defs[builtin_idx].args[i]);
- }
-
- String err = "Built-in function \"" + String(name) + "(" + arglist + ")\" is supported only on high-end platform!";
- _set_error(err);
- return false;
- }
-
- if (failed_builtin) {
- String err = "Invalid arguments for built-in function: " + String(name) + "(";
- for (int i = 0; i < argcount; i++) {
- if (i > 0)
- err += ",";
-
- if (p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && p_func->arguments[i + 1]->get_datatype() == TYPE_INT && static_cast<ConstantNode *>(p_func->arguments[i + 1])->values[0].sint < 0) {
- err += "-";
- }
- err += get_datatype_name(args[i]);
- }
- err += ")";
- _set_error(err);
- return false;
- }
-
- // try existing functions..
-
- StringName exclude_function;
- BlockNode *block = p_block;
-
- while (block) {
-
- if (block->parent_function) {
- exclude_function = block->parent_function->name;
- }
- block = block->parent_block;
- }
-
- if (name == exclude_function) {
- _set_error("Recursion is not allowed");
- return false;
- }
-
- for (int i = 0; i < shader->functions.size(); i++) {
-
- if (name != shader->functions[i].name)
- continue;
-
- if (!shader->functions[i].callable) {
- _set_error("Function '" + String(name) + " can't be called from source code.");
- return false;
- }
-
- FunctionNode *pfunc = shader->functions[i].function;
-
- if (pfunc->arguments.size() != args.size())
- continue;
-
- bool fail = false;
-
- for (int j = 0; j < args.size(); j++) {
- if (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) {
- fail = true;
- break;
- }
- if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
- //all good, but it needs implicit conversion later
- } else if (args[j] != pfunc->arguments[j].type) {
- fail = true;
- break;
- }
- }
-
- if (!fail) {
-
- //implicitly convert values if possible
- for (int k = 0; k < args.size(); k++) {
-
- if (get_scalar_type(args[k]) != args[k] || args[k] == pfunc->arguments[k].type || p_func->arguments[k + 1]->type != Node::TYPE_CONSTANT) {
- //can't do implicit conversion here
- continue;
- }
-
- //this is an implicit conversion
- ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[k + 1]);
- ConstantNode *conversion = alloc_node<ConstantNode>();
-
- conversion->datatype = pfunc->arguments[k].type;
- conversion->values.resize(1);
-
- convert_constant(constant, pfunc->arguments[k].type, conversion->values.ptrw());
- p_func->arguments.write[k + 1] = conversion;
- }
-
- if (r_ret_type) {
- *r_ret_type = pfunc->return_type;
- if (pfunc->return_type == TYPE_STRUCT) {
- *r_ret_type_str = pfunc->return_struct_name;
- }
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
- if (a->get_datatype() != b->get_datatype()) {
- return false;
- }
- if (a->get_datatype() == TYPE_STRUCT || b->get_datatype() == TYPE_STRUCT) {
- if (a->get_datatype_name() != b->get_datatype_name()) {
- return false;
- }
- }
- return true;
-}
-
-bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) {
-
- TkPos pos = _get_tkpos();
- Token tk = _get_token();
-
- if (tk.type == TK_PARENTHESIS_CLOSE) {
- return true;
- }
-
- _set_tkpos(pos);
-
- while (true) {
-
- if (r_complete_arg) {
- pos = _get_tkpos();
- tk = _get_token();
-
- if (tk.type == TK_CURSOR) {
-
- *r_complete_arg = p_func->arguments.size() - 1;
- } else {
-
- _set_tkpos(pos);
- }
- }
-
- Node *arg = _parse_and_reduce_expression(p_block, p_builtin_types);
-
- if (!arg) {
-
- return false;
- }
-
- p_func->arguments.push_back(arg);
-
- tk = _get_token();
-
- if (tk.type == TK_PARENTHESIS_CLOSE) {
-
- return true;
- } else if (tk.type != TK_COMMA) {
- // something is broken
- _set_error("Expected ',' or ')' after argument");
- return false;
- }
- }
-
- return true;
-}
-
-bool ShaderLanguage::is_token_operator(TokenType p_type) {
-
- return (p_type == TK_OP_EQUAL ||
- p_type == TK_OP_NOT_EQUAL ||
- p_type == TK_OP_LESS ||
- p_type == TK_OP_LESS_EQUAL ||
- p_type == TK_OP_GREATER ||
- p_type == TK_OP_GREATER_EQUAL ||
- p_type == TK_OP_AND ||
- p_type == TK_OP_OR ||
- p_type == TK_OP_NOT ||
- p_type == TK_OP_ADD ||
- p_type == TK_OP_SUB ||
- p_type == TK_OP_MUL ||
- p_type == TK_OP_DIV ||
- p_type == TK_OP_MOD ||
- p_type == TK_OP_SHIFT_LEFT ||
- p_type == TK_OP_SHIFT_RIGHT ||
- p_type == TK_OP_ASSIGN ||
- p_type == TK_OP_ASSIGN_ADD ||
- p_type == TK_OP_ASSIGN_SUB ||
- p_type == TK_OP_ASSIGN_MUL ||
- p_type == TK_OP_ASSIGN_DIV ||
- p_type == TK_OP_ASSIGN_MOD ||
- p_type == TK_OP_ASSIGN_SHIFT_LEFT ||
- p_type == TK_OP_ASSIGN_SHIFT_RIGHT ||
- p_type == TK_OP_ASSIGN_BIT_AND ||
- p_type == TK_OP_ASSIGN_BIT_OR ||
- p_type == TK_OP_ASSIGN_BIT_XOR ||
- p_type == TK_OP_BIT_AND ||
- p_type == TK_OP_BIT_OR ||
- p_type == TK_OP_BIT_XOR ||
- p_type == TK_OP_BIT_INVERT ||
- p_type == TK_OP_INCREMENT ||
- p_type == TK_OP_DECREMENT ||
- p_type == TK_QUESTION ||
- p_type == TK_COLON);
-}
-
-bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
-
- if (p_constant->datatype == p_to_type) {
- if (p_value) {
- for (int i = 0; i < p_constant->values.size(); i++) {
- p_value[i] = p_constant->values[i];
- }
- }
- return true;
- } else if (p_constant->datatype == TYPE_INT && p_to_type == TYPE_FLOAT) {
-
- if (p_value) {
- p_value->real = p_constant->values[0].sint;
- }
- return true;
- } else if (p_constant->datatype == TYPE_UINT && p_to_type == TYPE_FLOAT) {
-
- if (p_value) {
- p_value->real = p_constant->values[0].uint;
- }
- return true;
- } else if (p_constant->datatype == TYPE_INT && p_to_type == TYPE_UINT) {
- if (p_constant->values[0].sint < 0) {
- return false;
- }
- if (p_value) {
- p_value->uint = p_constant->values[0].sint;
- }
- return true;
- } else if (p_constant->datatype == TYPE_UINT && p_to_type == TYPE_INT) {
-
- if (p_constant->values[0].uint > 0x7FFFFFFF) {
- return false;
- }
- if (p_value) {
- p_value->sint = p_constant->values[0].uint;
- }
- return true;
- } else
- return false;
-}
-
-bool ShaderLanguage::is_scalar_type(DataType p_type) {
-
- return p_type == TYPE_BOOL || p_type == TYPE_INT || p_type == TYPE_UINT || p_type == TYPE_FLOAT;
-}
-
-bool ShaderLanguage::is_sampler_type(DataType p_type) {
-
- return p_type == TYPE_SAMPLER2D ||
- p_type == TYPE_ISAMPLER2D ||
- p_type == TYPE_USAMPLER2D ||
- p_type == TYPE_SAMPLER2DARRAY ||
- p_type == TYPE_ISAMPLER2DARRAY ||
- p_type == TYPE_USAMPLER2DARRAY ||
- p_type == TYPE_SAMPLER3D ||
- p_type == TYPE_ISAMPLER3D ||
- p_type == TYPE_USAMPLER3D ||
- p_type == TYPE_SAMPLERCUBE;
-}
-
-Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
- if (p_value.size() > 0) {
- Variant value;
- switch (p_type) {
- case ShaderLanguage::TYPE_BOOL:
- value = Variant(p_value[0].boolean);
- break;
- case ShaderLanguage::TYPE_BVEC2:
- case ShaderLanguage::TYPE_BVEC3:
- case ShaderLanguage::TYPE_BVEC4:
- case ShaderLanguage::TYPE_INT:
- value = Variant(p_value[0].sint);
- break;
- case ShaderLanguage::TYPE_IVEC2:
- value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
- break;
- case ShaderLanguage::TYPE_IVEC3:
- value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
- break;
- case ShaderLanguage::TYPE_IVEC4:
- value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
- break;
- case ShaderLanguage::TYPE_UINT:
- value = Variant(p_value[0].uint);
- break;
- case ShaderLanguage::TYPE_UVEC2:
- value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
- break;
- case ShaderLanguage::TYPE_UVEC3:
- value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
- break;
- case ShaderLanguage::TYPE_UVEC4:
- value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
- break;
- case ShaderLanguage::TYPE_FLOAT:
- value = Variant(p_value[0].real);
- break;
- case ShaderLanguage::TYPE_VEC2:
- value = Variant(Vector2(p_value[0].real, p_value[1].real));
- break;
- case ShaderLanguage::TYPE_VEC3:
- value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
- break;
- case ShaderLanguage::TYPE_VEC4:
- if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
- } else {
- value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
- }
- break;
- case ShaderLanguage::TYPE_MAT2:
- value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0));
- break;
- case ShaderLanguage::TYPE_MAT3: {
- Basis p;
- p[0][0] = p_value[0].real;
- p[0][1] = p_value[1].real;
- p[0][2] = p_value[2].real;
- p[1][0] = p_value[3].real;
- p[1][1] = p_value[4].real;
- p[1][2] = p_value[5].real;
- p[2][0] = p_value[6].real;
- p[2][1] = p_value[7].real;
- p[2][2] = p_value[8].real;
- value = Variant(p);
- break;
- }
- case ShaderLanguage::TYPE_MAT4: {
- Basis p;
- p[0][0] = p_value[0].real;
- p[0][1] = p_value[1].real;
- p[0][2] = p_value[2].real;
- p[1][0] = p_value[4].real;
- p[1][1] = p_value[5].real;
- p[1][2] = p_value[6].real;
- p[2][0] = p_value[8].real;
- p[2][1] = p_value[9].real;
- p[2][2] = p_value[10].real;
- Transform t = Transform(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
- value = Variant(t);
- break;
- }
- case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
- case ShaderLanguage::TYPE_ISAMPLER2D:
- case ShaderLanguage::TYPE_ISAMPLER3D:
- case ShaderLanguage::TYPE_SAMPLER2DARRAY:
- case ShaderLanguage::TYPE_SAMPLER2D:
- case ShaderLanguage::TYPE_SAMPLER3D:
- case ShaderLanguage::TYPE_USAMPLER2DARRAY:
- case ShaderLanguage::TYPE_USAMPLER2D:
- case ShaderLanguage::TYPE_USAMPLER3D:
- case ShaderLanguage::TYPE_SAMPLERCUBE: {
- // Texture types, likely not relevant here.
- break;
- }
- case ShaderLanguage::TYPE_STRUCT:
- break;
- case ShaderLanguage::TYPE_VOID:
- break;
- }
- return value;
- }
- return Variant();
-}
-
-PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform &p_uniform) {
- PropertyInfo pi;
- switch (p_uniform.type) {
- case ShaderLanguage::TYPE_VOID: pi.type = Variant::NIL; break;
- case ShaderLanguage::TYPE_BOOL: pi.type = Variant::BOOL; break;
- case ShaderLanguage::TYPE_BVEC2:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y";
- break;
- case ShaderLanguage::TYPE_BVEC3:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y,z";
- break;
- case ShaderLanguage::TYPE_BVEC4:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y,z,w";
- break;
- case ShaderLanguage::TYPE_UINT:
- case ShaderLanguage::TYPE_INT: {
- pi.type = Variant::INT;
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
- pi.hint = PROPERTY_HINT_RANGE;
- pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
- }
-
- } break;
- case ShaderLanguage::TYPE_IVEC2:
- case ShaderLanguage::TYPE_IVEC3:
- case ShaderLanguage::TYPE_IVEC4:
- case ShaderLanguage::TYPE_UVEC2:
- case ShaderLanguage::TYPE_UVEC3:
- case ShaderLanguage::TYPE_UVEC4: {
-
- pi.type = Variant::PACKED_INT32_ARRAY;
- } break;
- case ShaderLanguage::TYPE_FLOAT: {
- pi.type = Variant::FLOAT;
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
- pi.hint = PROPERTY_HINT_RANGE;
- pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
- }
-
- } break;
- case ShaderLanguage::TYPE_VEC2: pi.type = Variant::VECTOR2; break;
- case ShaderLanguage::TYPE_VEC3: pi.type = Variant::VECTOR3; break;
- case ShaderLanguage::TYPE_VEC4: {
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- pi.type = Variant::COLOR;
- } else {
- pi.type = Variant::PLANE;
- }
- } break;
- case ShaderLanguage::TYPE_MAT2: pi.type = Variant::TRANSFORM2D; break;
- case ShaderLanguage::TYPE_MAT3: pi.type = Variant::BASIS; break;
- case ShaderLanguage::TYPE_MAT4: pi.type = Variant::TRANSFORM; break;
- case ShaderLanguage::TYPE_SAMPLER2D:
- case ShaderLanguage::TYPE_ISAMPLER2D:
- case ShaderLanguage::TYPE_USAMPLER2D: {
-
- pi.type = Variant::OBJECT;
- pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string = "Texture2D";
- } break;
- case ShaderLanguage::TYPE_SAMPLER2DARRAY:
- case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
- case ShaderLanguage::TYPE_USAMPLER2DARRAY: {
-
- pi.type = Variant::OBJECT;
- pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string = "TextureArray";
- } break;
- case ShaderLanguage::TYPE_SAMPLER3D:
- case ShaderLanguage::TYPE_ISAMPLER3D:
- case ShaderLanguage::TYPE_USAMPLER3D: {
- pi.type = Variant::OBJECT;
- pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string = "Texture3D";
- } break;
- case ShaderLanguage::TYPE_SAMPLERCUBE: {
-
- pi.type = Variant::OBJECT;
- pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string = "CubeMap";
- } break;
- case ShaderLanguage::TYPE_STRUCT: {
- // FIXME: Implement this.
- } break;
- }
- return pi;
-}
-
-uint32_t ShaderLanguage::get_type_size(DataType p_type) {
- switch (p_type) {
- case TYPE_VOID:
- return 0;
- case TYPE_BOOL:
- case TYPE_INT:
- case TYPE_UINT:
- case TYPE_FLOAT:
- return 4;
- case TYPE_BVEC2:
- case TYPE_IVEC2:
- case TYPE_UVEC2:
- case TYPE_VEC2:
- return 8;
- case TYPE_BVEC3:
- case TYPE_IVEC3:
- case TYPE_UVEC3:
- case TYPE_VEC3:
- return 12;
- case TYPE_BVEC4:
- case TYPE_IVEC4:
- case TYPE_UVEC4:
- case TYPE_VEC4:
- return 16;
- case TYPE_MAT2:
- return 8;
- case TYPE_MAT3:
- return 12;
- case TYPE_MAT4:
- return 16;
- case TYPE_SAMPLER2D:
- case TYPE_ISAMPLER2D:
- case TYPE_USAMPLER2D:
- case TYPE_SAMPLER2DARRAY:
- case TYPE_ISAMPLER2DARRAY:
- case TYPE_USAMPLER2DARRAY:
- case TYPE_SAMPLER3D:
- case TYPE_ISAMPLER3D:
- case TYPE_USAMPLER3D:
- case TYPE_SAMPLERCUBE:
- return 4; //not really, but useful for indices
- case TYPE_STRUCT:
- // FIXME: Implement.
- return 0;
- }
- return 0;
-}
-
-void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
-
- Set<String> kws;
-
- int idx = 0;
-
- while (keyword_list[idx].text) {
-
- kws.insert(keyword_list[idx].text);
- idx++;
- }
-
- idx = 0;
-
- while (builtin_func_defs[idx].name) {
-
- kws.insert(builtin_func_defs[idx].name);
-
- idx++;
- }
-
- for (Set<String>::Element *E = kws.front(); E; E = E->next()) {
- r_keywords->push_back(E->get());
- }
-}
-
-void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) {
-
- Set<String> kws;
-
- int idx = 0;
-
- while (builtin_func_defs[idx].name) {
-
- kws.insert(builtin_func_defs[idx].name);
-
- idx++;
- }
-
- for (Set<String>::Element *E = kws.front(); E; E = E->next()) {
- r_keywords->push_back(E->get());
- }
-}
-
-ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) {
-
- static const DataType scalar_types[] = {
- TYPE_VOID,
- TYPE_BOOL,
- TYPE_BOOL,
- TYPE_BOOL,
- TYPE_BOOL,
- TYPE_INT,
- TYPE_INT,
- TYPE_INT,
- TYPE_INT,
- TYPE_UINT,
- TYPE_UINT,
- TYPE_UINT,
- TYPE_UINT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_FLOAT,
- TYPE_INT,
- TYPE_UINT,
- TYPE_FLOAT,
- };
-
- return scalar_types[p_type];
-}
-
-int ShaderLanguage::get_cardinality(DataType p_type) {
- static const int cardinality_table[] = {
- 0,
- 1,
- 2,
- 3,
- 4,
- 1,
- 2,
- 3,
- 4,
- 1,
- 2,
- 3,
- 4,
- 1,
- 2,
- 3,
- 4,
- 4,
- 9,
- 16,
- 1,
- 1,
- 1,
- 1,
- };
-
- return cardinality_table[p_type];
-}
-
-bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier) {
-
- identifier = StringName();
-
- TkPos pos = { 0, 0 };
-
- Token tk = _get_token();
-
- if (tk.type == TK_IDENTIFIER) {
- identifier = tk.text;
- pos = _get_tkpos();
- tk = _get_token();
- }
-
- if (tk.type == TK_CURSOR) {
-
- completion_type = p_type;
- completion_line = tk_line;
- completion_block = p_block;
-
- pos = _get_tkpos();
- tk = _get_token();
-
- if (tk.type == TK_IDENTIFIER) {
- identifier = identifier.operator String() + tk.text.operator String();
- } else {
- _set_tkpos(pos);
- }
- return true;
- } else if (identifier != StringName()) {
- _set_tkpos(pos);
- }
-
- return false;
-}
-
-bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
- switch (p_op) {
- case OP_ASSIGN:
- case OP_ASSIGN_ADD:
- case OP_ASSIGN_SUB:
- case OP_ASSIGN_MUL:
- case OP_ASSIGN_DIV:
- case OP_ASSIGN_MOD:
- case OP_ASSIGN_SHIFT_LEFT:
- case OP_ASSIGN_SHIFT_RIGHT:
- case OP_ASSIGN_BIT_AND:
- case OP_ASSIGN_BIT_OR:
- case OP_ASSIGN_BIT_XOR:
- return true;
- default:
- return false;
- }
-
- return false;
-}
-
-bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
-
- if (p_node->type == Node::TYPE_OPERATOR) {
-
- OperatorNode *op = static_cast<OperatorNode *>(p_node);
-
- if (op->op == OP_INDEX) {
- return _validate_assign(op->arguments[0], p_builtin_types, r_message);
-
- } else if (_is_operator_assign(op->op)) {
- //chained assignment
- return _validate_assign(op->arguments[1], p_builtin_types, r_message);
-
- } else if (op->op == OP_CALL) {
- if (r_message)
- *r_message = RTR("Assignment to function.");
- return false;
- }
-
- } else if (p_node->type == Node::TYPE_MEMBER) {
-
- MemberNode *member = static_cast<MemberNode *>(p_node);
-
- if (member->has_swizzling_duplicates) {
- if (r_message)
- *r_message = RTR("Swizzling assignment contains duplicates.");
- return false;
- }
-
- return _validate_assign(member->owner, p_builtin_types, r_message);
-
- } else if (p_node->type == Node::TYPE_VARIABLE) {
-
- VariableNode *var = static_cast<VariableNode *>(p_node);
-
- if (shader->uniforms.has(var->name)) {
- if (r_message)
- *r_message = RTR("Assignment to uniform.");
- 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.");
- return false;
- }
-
- if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) {
- return true;
- }
- } else if (p_node->type == Node::TYPE_ARRAY) {
-
- ArrayNode *arr = static_cast<ArrayNode *>(p_node);
-
- if (arr->is_const) {
- if (r_message)
- *r_message = RTR("Constants cannot be modified.");
- 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;
- }
-
- if (r_message)
- *r_message = "Assignment to constant expression.";
- return false;
-}
-
-bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat) {
- for (int i = 0; shader->functions.size(); i++) {
- if (shader->functions[i].name == p_name) {
-
- ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
- FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
- if (arg->tex_builtin_check) {
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
- return false;
- } else if (arg->tex_argument_check) {
- //was checked, verify that filter and repeat are the same
- if (arg->tex_argument_filter == p_filter && arg->tex_argument_repeat == p_repeat) {
- return true;
- } else {
-
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using textures that differ in either filter or repeat setting.");
- return false;
- }
- } else {
-
- arg->tex_argument_check = true;
- arg->tex_argument_filter = p_filter;
- arg->tex_argument_repeat = p_repeat;
- for (Map<StringName, Set<int> >::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
- for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
- if (!_propagate_function_call_sampler_uniform_settings(E->key(), F->get(), p_filter, p_repeat)) {
- return false;
- }
- }
- }
- return true;
- }
- }
- }
- ERR_FAIL_V(false); //bug? function not found
-}
-bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin) {
- for (int i = 0; shader->functions.size(); i++) {
- if (shader->functions[i].name == p_name) {
-
- ERR_FAIL_INDEX_V(p_argument, shader->functions[i].function->arguments.size(), false);
- FunctionNode::Argument *arg = &shader->functions[i].function->arguments.write[p_argument];
- if (arg->tex_argument_check) {
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using both built-ins and uniform textures, this is not supported (use either one or the other).");
- return false;
- } else if (arg->tex_builtin_check) {
- //was checked, verify that the built-in is the same
- if (arg->tex_builtin == p_builtin) {
- return true;
- } else {
- _set_error("Sampler argument #" + itos(p_argument) + " of function '" + String(p_name) + "' called more than once using different built-ins. Only calling with the same built-in is supported.");
- return false;
- }
- } else {
-
- arg->tex_builtin_check = true;
- arg->tex_builtin = p_builtin;
-
- for (Map<StringName, Set<int> >::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) {
- for (Set<int>::Element *F = E->get().front(); F; F = F->next()) {
- if (!_propagate_function_call_sampler_builtin_reference(E->key(), F->get(), p_builtin)) {
- return false;
- }
- }
- }
- return true;
- }
- }
- }
- ERR_FAIL_V(false); //bug? function not found
-}
-
-ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
-
- Vector<Expression> expression;
-
- //Vector<TokenType> operators;
-
- while (true) {
-
- Node *expr = NULL;
- TkPos prepos = _get_tkpos();
- Token tk = _get_token();
- TkPos pos = _get_tkpos();
-
- bool is_const = false;
-
- if (tk.type == TK_PARENTHESIS_OPEN) {
- //handle subexpression
-
- expr = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!expr)
- return NULL;
-
- tk = _get_token();
-
- if (tk.type != TK_PARENTHESIS_CLOSE) {
-
- _set_error("Expected ')' in expression");
- return NULL;
- }
-
- } else if (tk.type == TK_REAL_CONSTANT) {
-
- ConstantNode *constant = alloc_node<ConstantNode>();
- ConstantNode::Value v;
- v.real = tk.constant;
- constant->values.push_back(v);
- constant->datatype = TYPE_FLOAT;
- expr = constant;
-
- } else if (tk.type == TK_INT_CONSTANT) {
-
- ConstantNode *constant = alloc_node<ConstantNode>();
- ConstantNode::Value v;
- v.sint = tk.constant;
- constant->values.push_back(v);
- constant->datatype = TYPE_INT;
- expr = constant;
-
- } else if (tk.type == TK_TRUE) {
-
- //handle true constant
- ConstantNode *constant = alloc_node<ConstantNode>();
- ConstantNode::Value v;
- v.boolean = true;
- constant->values.push_back(v);
- constant->datatype = TYPE_BOOL;
- expr = constant;
-
- } else if (tk.type == TK_FALSE) {
-
- //handle false constant
- ConstantNode *constant = alloc_node<ConstantNode>();
- ConstantNode::Value v;
- v.boolean = false;
- constant->values.push_back(v);
- constant->datatype = TYPE_BOOL;
- expr = constant;
-
- } else if (tk.type == TK_TYPE_VOID) {
-
- //make sure void is not used in expression
- _set_error("Void value not allowed in Expression");
- return NULL;
- } else if (is_token_nonvoid_datatype(tk.type)) {
- //basic type constructor
-
- OperatorNode *func = alloc_node<OperatorNode>();
- func->op = OP_CONSTRUCT;
-
- if (is_token_precision(tk.type)) {
-
- func->return_precision_cache = get_token_precision(tk.type);
- tk = _get_token();
- }
-
- VariableNode *funcname = alloc_node<VariableNode>();
- funcname->name = get_datatype_name(get_token_datatype(tk.type));
- func->arguments.push_back(funcname);
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after type name");
- return NULL;
- }
-
- int carg = -1;
-
- bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
-
- if (carg >= 0) {
- completion_type = COMPLETION_CALL_ARGUMENTS;
- completion_line = tk_line;
- completion_block = p_block;
- completion_function = funcname->name;
- completion_argument = carg;
- }
-
- if (!ok)
- return NULL;
-
- if (!_validate_function_call(p_block, func, &func->return_cache, &func->struct_name)) {
- _set_error("No matching constructor found for: '" + String(funcname->name) + "'");
- return NULL;
- }
-
- expr = _reduce_expression(p_block, func);
-
- } else if (tk.type == TK_IDENTIFIER) {
-
- _set_tkpos(prepos);
-
- StringName identifier;
-
- StructNode *pstruct = NULL;
- bool struct_init = false;
-
- _get_completable_identifier(p_block, COMPLETION_IDENTIFIER, identifier);
-
- if (shader->structs.has(identifier)) {
- pstruct = shader->structs[identifier].shader_struct;
- struct_init = true;
- }
-
- tk = _get_token();
- if (tk.type == TK_PARENTHESIS_OPEN) {
-
- if (struct_init) { //a struct constructor
-
- const StringName &name = identifier;
-
- OperatorNode *func = alloc_node<OperatorNode>();
- func->op = OP_STRUCT;
- func->struct_name = name;
- func->return_cache = TYPE_STRUCT;
- VariableNode *funcname = alloc_node<VariableNode>();
- funcname->name = name;
- func->arguments.push_back(funcname);
-
- for (int i = 0; i < pstruct->members.size(); i++) {
- Node *nexpr;
-
- if (pstruct->members[i]->array_size != 0) {
-
- DataType type = pstruct->members[i]->get_datatype();
- String struct_name = pstruct->members[i]->struct_name;
- int array_size = pstruct->members[i]->array_size;
-
- DataType type2;
- String struct_name2 = "";
- int array_size2 = 0;
-
- bool auto_size = false;
-
- tk = _get_token();
-
- if (tk.type == TK_CURLY_BRACKET_OPEN) {
- auto_size = true;
- } else {
-
- if (shader->structs.has(tk.text)) {
- type2 = TYPE_STRUCT;
- struct_name2 = tk.text;
- } else {
- if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for array");
- return NULL;
- }
- type2 = get_token_datatype(tk.type);
- }
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- TkPos pos2 = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- array_size2 = array_size;
- tk = _get_token();
- } else {
- _set_tkpos(pos2);
-
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
- _set_error("Expected single integer constant > 0");
- return NULL;
- }
-
- ConstantNode *cnode = (ConstantNode *)n;
- if (cnode->values.size() == 1) {
- array_size2 = cnode->values[0].sint;
- if (array_size2 <= 0) {
- _set_error("Expected single integer constant > 0");
- return NULL;
- }
- } else {
- _set_error("Expected single integer constant > 0");
- return NULL;
- }
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return NULL;
- } else {
- tk = _get_token();
- }
- }
- } else {
- _set_error("Expected '['");
- return NULL;
- }
-
- if (type != type2 || struct_name != struct_name2 || array_size != array_size2) {
- String error_str = "Cannot convert from '";
- if (type2 == TYPE_STRUCT) {
- error_str += struct_name2;
- } else {
- error_str += get_datatype_name(type2);
- }
- error_str += "[";
- error_str += itos(array_size2);
- error_str += "]'";
- error_str += " to '";
- if (type == TYPE_STRUCT) {
- error_str += struct_name;
- } else {
- error_str += get_datatype_name(type);
- }
- error_str += "[";
- error_str += itos(array_size);
- error_str += "]'";
- _set_error(error_str);
- return NULL;
- }
- }
-
- ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
- an->datatype = type;
- an->struct_name = struct_name;
-
- if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
- while (true) {
-
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n) {
- return NULL;
- }
-
- if (type != n->get_datatype() || struct_name != n->get_datatype_name()) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'");
- return NULL;
- }
-
- tk = _get_token();
- if (tk.type == TK_COMMA) {
- an->initializer.push_back(n);
- continue;
- } else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) {
- an->initializer.push_back(n);
- break;
- } else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) {
- an->initializer.push_back(n);
- break;
- } else {
- if (auto_size)
- _set_error("Expected '}' or ','");
- else
- _set_error("Expected ')' or ','");
- return NULL;
- }
- }
- if (an->initializer.size() != array_size) {
- _set_error("Array size mismatch");
- return NULL;
- }
- } else {
- _set_error("Expected array initialization!");
- return NULL;
- }
-
- nexpr = an;
- } else {
- nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!nexpr) {
- return NULL;
- }
- Node *node = pstruct->members[i];
- if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
- String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
- String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
- _set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
- return NULL;
- }
- }
-
- if (i + 1 < pstruct->members.size()) {
- tk = _get_token();
- if (tk.type != TK_COMMA) {
- _set_error("Expected ','");
- return NULL;
- }
- }
- func->arguments.push_back(nexpr);
- }
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')'");
- return NULL;
- }
-
- expr = func;
-
- } else { //a function
-
- const StringName &name = identifier;
-
- OperatorNode *func = alloc_node<OperatorNode>();
- func->op = OP_CALL;
- VariableNode *funcname = alloc_node<VariableNode>();
- funcname->name = name;
- func->arguments.push_back(funcname);
-
- int carg = -1;
-
- bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
-
- // Check if block has a variable with the same name as function to prevent shader crash.
- ShaderLanguage::BlockNode *bnode = p_block;
- while (bnode) {
- if (bnode->variables.has(name)) {
- _set_error("Expected function name");
- return NULL;
- }
- bnode = bnode->parent_block;
- }
-
- //test if function was parsed first
- int function_index = -1;
- for (int i = 0; i < shader->functions.size(); i++) {
- if (shader->functions[i].name == name) {
- //add to current function as dependency
- for (int j = 0; j < shader->functions.size(); j++) {
- if (shader->functions[j].name == current_function) {
- shader->functions.write[j].uses_function.insert(name);
- break;
- }
- }
-
- //see if texture arguments must connect
- function_index = i;
- break;
- }
- }
-
- if (carg >= 0) {
- completion_type = COMPLETION_CALL_ARGUMENTS;
- completion_line = tk_line;
- completion_block = p_block;
- completion_function = funcname->name;
- completion_argument = carg;
- }
-
- if (!ok)
- return NULL;
-
- if (!_validate_function_call(p_block, func, &func->return_cache, &func->struct_name)) {
- _set_error("No matching function found for: '" + String(funcname->name) + "'");
- return NULL;
- }
- completion_class = TAG_GLOBAL; // reset sub-class
- if (function_index >= 0) {
- //connect texture arguments, so we can cache in the
- //argument what type of filter and repeat to use
-
- FunctionNode *call_function = shader->functions[function_index].function;
- if (call_function) {
-
- //get current base function
- FunctionNode *base_function = NULL;
- {
- BlockNode *b = p_block;
-
- while (b) {
-
- if (b->parent_function) {
- base_function = b->parent_function;
- break;
- } else {
- b = b->parent_block;
- }
- }
- }
-
- ERR_FAIL_COND_V(!base_function, NULL); //bug, wtf
-
- for (int i = 0; i < call_function->arguments.size(); i++) {
- int argidx = i + 1;
- if (argidx < func->arguments.size()) {
- if (call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) {
- bool error = false;
- Node *n = func->arguments[argidx];
- if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) {
- error = true;
- } else if (n->type == Node::TYPE_ARRAY) {
- ArrayNode *an = static_cast<ArrayNode *>(n);
- if (an->call_expression != NULL) {
- error = true;
- }
- } else if (n->type == Node::TYPE_VARIABLE) {
- VariableNode *vn = static_cast<VariableNode *>(n);
- if (vn->is_const) {
- error = true;
- } else {
- StringName varname = vn->name;
- if (shader->uniforms.has(varname)) {
- error = true;
- } else {
- if (p_builtin_types.has(varname)) {
- BuiltInInfo info = p_builtin_types[varname];
- if (info.constant) {
- error = true;
- }
- }
- }
- }
- } else if (n->type == Node::TYPE_MEMBER) {
- MemberNode *mn = static_cast<MemberNode *>(n);
- if (mn->basetype_const) {
- error = true;
- }
- }
- if (error) {
- _set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier)));
- return NULL;
- }
- }
- if (is_sampler_type(call_function->arguments[i].type)) {
- //let's see where our argument comes from
- Node *n = func->arguments[argidx];
- ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable
- VariableNode *vn = static_cast<VariableNode *>(n);
- StringName varname = vn->name;
- if (shader->uniforms.has(varname)) {
- //being sampler, this either comes from a uniform
- ShaderNode::Uniform *u = &shader->uniforms[varname];
- ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously
- //propagate
- if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
- return NULL;
- }
- } else if (p_builtin_types.has(varname)) {
- //a built-in
- if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) {
- return NULL;
- }
- } else {
- //or this comes from an argument, but nothing else can be a sampler
- bool found = false;
- for (int j = 0; j < base_function->arguments.size(); j++) {
- if (base_function->arguments[j].name == varname) {
- if (!base_function->arguments[j].tex_argument_connect.has(call_function->name)) {
- base_function->arguments.write[j].tex_argument_connect[call_function->name] = Set<int>();
- }
- base_function->arguments.write[j].tex_argument_connect[call_function->name].insert(i);
- found = true;
- break;
- }
- }
- ERR_CONTINUE(!found);
- }
- }
- } else {
- break;
- }
- }
- }
- }
- expr = func;
- }
- } else {
- //an identifier
-
- _set_tkpos(pos);
-
- DataType data_type;
- IdentifierType ident_type;
- int array_size = 0;
- StringName struct_name;
-
- if (p_block && p_block->block_tag != SubClassTag::TAG_GLOBAL) {
- int idx = 0;
- bool found = false;
-
- while (builtin_func_defs[idx].name) {
- if (builtin_func_defs[idx].tag == p_block->block_tag && builtin_func_defs[idx].name == identifier) {
- found = true;
- break;
- }
- idx++;
- }
- if (!found) {
- _set_error("Unknown identifier in expression: " + String(identifier));
- return NULL;
- }
- } else {
-
- if (!_find_identifier(p_block, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
- _set_error("Unknown identifier in expression: " + String(identifier));
- return NULL;
- }
-
- if (ident_type == IDENTIFIER_FUNCTION) {
- _set_error("Can't use function as identifier: " + String(identifier));
- return NULL;
- }
- }
-
- Node *index_expression = NULL;
- Node *call_expression = NULL;
-
- if (array_size > 0) {
- tk = _get_token();
-
- if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD) {
- _set_error("Expected '[' or '.'");
- return NULL;
- }
-
- if (tk.type == TK_PERIOD) {
- completion_class = TAG_ARRAY;
- p_block->block_tag = SubClassTag::TAG_ARRAY;
- call_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
- p_block->block_tag = SubClassTag::TAG_GLOBAL;
- if (!call_expression)
- return NULL;
- data_type = call_expression->get_datatype();
- } else { // indexing
-
- index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!index_expression)
- return NULL;
-
- if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
- _set_error("Only integer expressions are allowed for indexing");
- return NULL;
- }
-
- if (index_expression->type == Node::TYPE_CONSTANT) {
- ConstantNode *cnode = (ConstantNode *)index_expression;
- if (cnode) {
- if (!cnode->values.empty()) {
- int value = cnode->values[0].sint;
- if (value < 0 || value >= array_size) {
- _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1));
- return NULL;
- }
- }
- }
- }
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return NULL;
- }
- }
-
- ArrayNode *arrname = alloc_node<ArrayNode>();
- arrname->name = identifier;
- arrname->datatype_cache = data_type;
- arrname->struct_name = struct_name;
- arrname->index_expression = index_expression;
- arrname->call_expression = call_expression;
- arrname->is_const = is_const;
- expr = arrname;
-
- } else {
-
- VariableNode *varname = alloc_node<VariableNode>();
- varname->name = identifier;
- varname->datatype_cache = data_type;
- varname->is_const = is_const;
- varname->struct_name = struct_name;
- expr = varname;
- }
- }
- } else if (tk.type == TK_OP_ADD) {
- continue; //this one does nothing
- } else if (tk.type == TK_OP_SUB || tk.type == TK_OP_NOT || tk.type == TK_OP_BIT_INVERT || tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
-
- Expression e;
- e.is_op = true;
-
- switch (tk.type) {
- case TK_OP_SUB: e.op = OP_NEGATE; break;
- case TK_OP_NOT: e.op = OP_NOT; break;
- case TK_OP_BIT_INVERT: e.op = OP_BIT_INVERT; break;
- case TK_OP_INCREMENT: e.op = OP_INCREMENT; break;
- case TK_OP_DECREMENT: e.op = OP_DECREMENT; break;
- default: ERR_FAIL_V(NULL);
- }
-
- expression.push_back(e);
- continue;
- } else {
- _set_error("Expected expression, found: " + get_token_text(tk));
- return NULL;
- //nothing
- }
-
- ERR_FAIL_COND_V(!expr, NULL);
-
- /* 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();
- tk = _get_token();
-
- if (tk.type == TK_CURSOR) {
- //do nothing
- } else if (tk.type == TK_IDENTIFIER) {
-
- } else if (tk.type == TK_PERIOD) {
-
- DataType dt = expr->get_datatype();
- String st = expr->get_datatype_name();
-
- StringName identifier;
- if (_get_completable_identifier(p_block, dt == TYPE_STRUCT ? COMPLETION_STRUCT : COMPLETION_INDEX, identifier)) {
- if (dt == TYPE_STRUCT) {
- completion_struct = st;
- } else {
- completion_base = dt;
- }
- }
-
- if (identifier == StringName()) {
- _set_error("Expected identifier as member");
- return NULL;
- }
- String ident = identifier;
-
- bool ok = true;
- bool repeated = false;
- DataType member_type = TYPE_VOID;
- StringName member_struct_name = "";
- int array_size = 0;
-
- Set<char> position_symbols;
- Set<char> color_symbols;
- Set<char> texture_symbols;
-
- bool mix_error = false;
-
- switch (dt) {
- case TYPE_STRUCT: {
- ok = false;
- String member_name = String(ident.ptr());
- if (shader->structs.has(st)) {
- StructNode *n = shader->structs[st].shader_struct;
- for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) {
- if (String(E->get()->name) == member_name) {
- member_type = E->get()->datatype;
- array_size = E->get()->array_size;
- if (member_type == TYPE_STRUCT) {
- member_struct_name = E->get()->struct_name;
- }
- ok = true;
- break;
- }
- }
- }
-
- } break;
- case TYPE_BVEC2:
- case TYPE_IVEC2:
- case TYPE_UVEC2:
- case TYPE_VEC2: {
-
- int l = ident.length();
- if (l == 1) {
- member_type = DataType(dt - 1);
- } else if (l == 2) {
- member_type = dt;
- } else if (l == 3) {
- member_type = DataType(dt + 1);
- } else if (l == 4) {
- member_type = DataType(dt + 2);
- } else {
- ok = false;
- break;
- }
-
- const CharType *c = ident.ptr();
- for (int i = 0; i < l; i++) {
-
- switch (c[i]) {
- case 'r':
- case 'g':
- if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!color_symbols.has(c[i])) {
- color_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- case 'x':
- case 'y':
- if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!position_symbols.has(c[i])) {
- position_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- case 's':
- case 't':
- if (color_symbols.size() > 0 || position_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!texture_symbols.has(c[i])) {
- texture_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- default:
- ok = false;
- break;
- }
- }
-
- } break;
- case TYPE_BVEC3:
- case TYPE_IVEC3:
- case TYPE_UVEC3:
- case TYPE_VEC3: {
-
- int l = ident.length();
- if (l == 1) {
- member_type = DataType(dt - 2);
- } else if (l == 2) {
- member_type = DataType(dt - 1);
- } else if (l == 3) {
- member_type = dt;
- } else if (l == 4) {
- member_type = DataType(dt + 1);
- } else {
- ok = false;
- break;
- }
-
- const CharType *c = ident.ptr();
- for (int i = 0; i < l; i++) {
-
- switch (c[i]) {
- case 'r':
- case 'g':
- case 'b':
- if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!color_symbols.has(c[i])) {
- color_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- case 'x':
- case 'y':
- case 'z':
- if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!position_symbols.has(c[i])) {
- position_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- case 's':
- case 't':
- case 'p':
- if (color_symbols.size() > 0 || position_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!texture_symbols.has(c[i])) {
- texture_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- default:
- ok = false;
- break;
- }
- }
-
- } break;
- case TYPE_BVEC4:
- case TYPE_IVEC4:
- case TYPE_UVEC4:
- case TYPE_VEC4: {
-
- int l = ident.length();
- if (l == 1) {
- member_type = DataType(dt - 3);
- } else if (l == 2) {
- member_type = DataType(dt - 2);
- } else if (l == 3) {
- member_type = DataType(dt - 1);
- } else if (l == 4) {
- member_type = dt;
- } else {
- ok = false;
- break;
- }
-
- const CharType *c = ident.ptr();
- for (int i = 0; i < l; i++) {
-
- switch (c[i]) {
- case 'r':
- case 'g':
- case 'b':
- case 'a':
- if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!color_symbols.has(c[i])) {
- color_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- case 'x':
- case 'y':
- case 'z':
- case 'w':
- if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!position_symbols.has(c[i])) {
- position_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- case 's':
- case 't':
- case 'p':
- case 'q':
- if (color_symbols.size() > 0 || position_symbols.size() > 0) {
- mix_error = true;
- break;
- }
- if (!texture_symbols.has(c[i])) {
- texture_symbols.insert(c[i]);
- } else {
- repeated = true;
- }
- break;
- default:
- ok = false;
- break;
- }
- }
-
- } break;
-
- default: {
- ok = false;
- }
- }
-
- if (mix_error) {
- _set_error("Cannot combine symbols from different sets in expression ." + ident);
- return NULL;
- }
-
- if (!ok) {
- _set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident);
- return NULL;
- }
-
- MemberNode *mn = alloc_node<MemberNode>();
- mn->basetype = dt;
- mn->basetype_const = is_const;
- mn->datatype = member_type;
- mn->base_struct_name = st;
- mn->struct_name = member_struct_name;
- mn->array_size = array_size;
- mn->name = ident;
- mn->owner = expr;
- mn->has_swizzling_duplicates = repeated;
-
- if (array_size > 0) {
-
- tk = _get_token();
- if (tk.type == TK_PERIOD) {
- _set_error("Nested array length() is not yet implemented");
- return NULL;
- } else if (tk.type == TK_BRACKET_OPEN) {
-
- Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!index_expression)
- return NULL;
-
- if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
- _set_error("Only integer expressions are allowed for indexing");
- return NULL;
- }
-
- if (index_expression->type == Node::TYPE_CONSTANT) {
- ConstantNode *cnode = (ConstantNode *)index_expression;
- if (cnode) {
- if (!cnode->values.empty()) {
- int value = cnode->values[0].sint;
- if (value < 0 || value >= array_size) {
- _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1));
- return NULL;
- }
- }
- }
- }
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return NULL;
- }
- mn->index_expression = index_expression;
-
- } else {
- _set_error("Expected '[' or '.'");
- return NULL;
- }
- }
-
- expr = mn;
-
- //todo
- //member (period) has priority over any operator
- //creates a subindexing expression in place
-
- /*} else if (tk.type==TK_BRACKET_OPEN) {
- //todo
- //subindexing has priority over any operator
- //creates a subindexing expression in place
-
- */
- } else if (tk.type == TK_BRACKET_OPEN) {
-
- Node *index = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!index)
- return NULL;
-
- if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) {
- _set_error("Only integer datatypes are allowed for indexing");
- return NULL;
- }
-
- DataType member_type = TYPE_VOID;
-
- switch (expr->get_datatype()) {
- case TYPE_BVEC2:
- case TYPE_VEC2:
- case TYPE_IVEC2:
- case TYPE_UVEC2:
- case TYPE_MAT2:
- if (index->type == Node::TYPE_CONSTANT) {
- uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
- if (index_constant >= 2) {
- _set_error("Index out of range (0-1)");
- return NULL;
- }
- }
-
- switch (expr->get_datatype()) {
- case TYPE_BVEC2: member_type = TYPE_BOOL; break;
- case TYPE_VEC2: member_type = TYPE_FLOAT; break;
- case TYPE_IVEC2: member_type = TYPE_INT; break;
- case TYPE_UVEC2: member_type = TYPE_UINT; break;
- case TYPE_MAT2: member_type = TYPE_VEC2; break;
- default: break;
- }
-
- break;
- case TYPE_BVEC3:
- case TYPE_VEC3:
- case TYPE_IVEC3:
- case TYPE_UVEC3:
- case TYPE_MAT3:
- if (index->type == Node::TYPE_CONSTANT) {
- uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
- if (index_constant >= 3) {
- _set_error("Index out of range (0-2)");
- return NULL;
- }
- }
-
- switch (expr->get_datatype()) {
- case TYPE_BVEC3: member_type = TYPE_BOOL; break;
- case TYPE_VEC3: member_type = TYPE_FLOAT; break;
- case TYPE_IVEC3: member_type = TYPE_INT; break;
- case TYPE_UVEC3: member_type = TYPE_UINT; break;
- case TYPE_MAT3: member_type = TYPE_VEC3; break;
- default: break;
- }
- break;
- case TYPE_BVEC4:
- case TYPE_VEC4:
- case TYPE_IVEC4:
- case TYPE_UVEC4:
- case TYPE_MAT4:
- if (index->type == Node::TYPE_CONSTANT) {
- uint32_t index_constant = static_cast<ConstantNode *>(index)->values[0].uint;
- if (index_constant >= 4) {
- _set_error("Index out of range (0-3)");
- return NULL;
- }
- }
-
- switch (expr->get_datatype()) {
- case TYPE_BVEC4: member_type = TYPE_BOOL; break;
- case TYPE_VEC4: member_type = TYPE_FLOAT; break;
- case TYPE_IVEC4: member_type = TYPE_INT; break;
- case TYPE_UVEC4: member_type = TYPE_UINT; break;
- case TYPE_MAT4: member_type = TYPE_VEC4; break;
- default: break;
- }
- break;
- default: {
- _set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
- return NULL;
- }
- }
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = OP_INDEX;
- op->return_cache = member_type;
- op->arguments.push_back(expr);
- op->arguments.push_back(index);
- expr = op;
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']' after indexing expression");
- return NULL;
- }
-
- } else if (tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = tk.type == TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT;
- op->arguments.push_back(expr);
-
- if (!_validate_operator(op, &op->return_cache)) {
- _set_error("Invalid base type for increment/decrement operator");
- return NULL;
- }
-
- if (!_validate_assign(expr, p_builtin_types)) {
- _set_error("Invalid use of increment/decrement operator in constant expression.");
- return NULL;
- }
- expr = op;
- } else {
-
- _set_tkpos(pos2);
- break;
- }
- }
-
- Expression e;
- e.is_op = false;
- e.node = expr;
- expression.push_back(e);
-
- pos = _get_tkpos();
- tk = _get_token();
-
- if (is_token_operator(tk.type)) {
-
- Expression o;
- o.is_op = true;
-
- switch (tk.type) {
-
- case TK_OP_EQUAL: o.op = OP_EQUAL; break;
- case TK_OP_NOT_EQUAL: o.op = OP_NOT_EQUAL; break;
- case TK_OP_LESS: o.op = OP_LESS; break;
- case TK_OP_LESS_EQUAL: o.op = OP_LESS_EQUAL; break;
- case TK_OP_GREATER: o.op = OP_GREATER; break;
- case TK_OP_GREATER_EQUAL: o.op = OP_GREATER_EQUAL; break;
- case TK_OP_AND: o.op = OP_AND; break;
- case TK_OP_OR: o.op = OP_OR; break;
- case TK_OP_ADD: o.op = OP_ADD; break;
- case TK_OP_SUB: o.op = OP_SUB; break;
- case TK_OP_MUL: o.op = OP_MUL; break;
- case TK_OP_DIV: o.op = OP_DIV; break;
- case TK_OP_MOD: o.op = OP_MOD; break;
- case TK_OP_SHIFT_LEFT: o.op = OP_SHIFT_LEFT; break;
- case TK_OP_SHIFT_RIGHT: o.op = OP_SHIFT_RIGHT; break;
- case TK_OP_ASSIGN: o.op = OP_ASSIGN; break;
- case TK_OP_ASSIGN_ADD: o.op = OP_ASSIGN_ADD; break;
- case TK_OP_ASSIGN_SUB: o.op = OP_ASSIGN_SUB; break;
- case TK_OP_ASSIGN_MUL: o.op = OP_ASSIGN_MUL; break;
- case TK_OP_ASSIGN_DIV: o.op = OP_ASSIGN_DIV; break;
- case TK_OP_ASSIGN_MOD: o.op = OP_ASSIGN_MOD; break;
- case TK_OP_ASSIGN_SHIFT_LEFT: o.op = OP_ASSIGN_SHIFT_LEFT; break;
- case TK_OP_ASSIGN_SHIFT_RIGHT: o.op = OP_ASSIGN_SHIFT_RIGHT; break;
- case TK_OP_ASSIGN_BIT_AND: o.op = OP_ASSIGN_BIT_AND; break;
- case TK_OP_ASSIGN_BIT_OR: o.op = OP_ASSIGN_BIT_OR; break;
- case TK_OP_ASSIGN_BIT_XOR: o.op = OP_ASSIGN_BIT_XOR; break;
- case TK_OP_BIT_AND: o.op = OP_BIT_AND; break;
- case TK_OP_BIT_OR: o.op = OP_BIT_OR; break;
- case TK_OP_BIT_XOR: o.op = OP_BIT_XOR; break;
- case TK_QUESTION: o.op = OP_SELECT_IF; break;
- case TK_COLON: o.op = OP_SELECT_ELSE; break;
- default: {
- _set_error("Invalid token for operator: " + get_token_text(tk));
- return NULL;
- }
- }
-
- expression.push_back(o);
-
- } else {
- _set_tkpos(pos); //something else, so rollback and end
- break;
- }
- }
-
- /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */
-
- while (expression.size() > 1) {
-
- int next_op = -1;
- int min_priority = 0xFFFFF;
- bool is_unary = false;
- bool is_ternary = false;
-
- for (int i = 0; i < expression.size(); i++) {
-
- if (!expression[i].is_op) {
-
- continue;
- }
-
- bool unary = false;
- bool ternary = false;
-
- int priority;
- switch (expression[i].op) {
- case OP_EQUAL: priority = 8; break;
- case OP_NOT_EQUAL: priority = 8; break;
- case OP_LESS: priority = 7; break;
- case OP_LESS_EQUAL: priority = 7; break;
- case OP_GREATER: priority = 7; break;
- case OP_GREATER_EQUAL: priority = 7; break;
- case OP_AND: priority = 12; break;
- case OP_OR: priority = 14; break;
- case OP_NOT:
- priority = 3;
- unary = true;
- break;
- case OP_NEGATE:
- priority = 3;
- unary = true;
- break;
- case OP_ADD: priority = 5; break;
- case OP_SUB: priority = 5; break;
- case OP_MUL: priority = 4; break;
- case OP_DIV: priority = 4; break;
- case OP_MOD: priority = 4; break;
- case OP_SHIFT_LEFT: priority = 6; break;
- case OP_SHIFT_RIGHT: priority = 6; break;
- case OP_ASSIGN: priority = 16; break;
- case OP_ASSIGN_ADD: priority = 16; break;
- case OP_ASSIGN_SUB: priority = 16; break;
- case OP_ASSIGN_MUL: priority = 16; break;
- case OP_ASSIGN_DIV: priority = 16; break;
- case OP_ASSIGN_MOD: priority = 16; break;
- case OP_ASSIGN_SHIFT_LEFT: priority = 16; break;
- case OP_ASSIGN_SHIFT_RIGHT: priority = 16; break;
- case OP_ASSIGN_BIT_AND: priority = 16; break;
- case OP_ASSIGN_BIT_OR: priority = 16; break;
- case OP_ASSIGN_BIT_XOR: priority = 16; break;
- case OP_BIT_AND: priority = 9; break;
- case OP_BIT_OR: priority = 11; break;
- case OP_BIT_XOR: priority = 10; break;
- case OP_BIT_INVERT:
- priority = 3;
- unary = true;
- break;
- case OP_INCREMENT:
- priority = 3;
- unary = true;
- break;
- case OP_DECREMENT:
- priority = 3;
- unary = true;
- break;
- case OP_SELECT_IF:
- priority = 15;
- ternary = true;
- break;
- case OP_SELECT_ELSE:
- priority = 15;
- ternary = true;
- break;
-
- default:
- ERR_FAIL_V(NULL); //unexpected operator
- }
-
- if (priority < min_priority) {
- // < is used for left to right (default)
- // <= is used for right to left
- next_op = i;
- min_priority = priority;
- is_unary = unary;
- is_ternary = ternary;
- }
- }
-
- ERR_FAIL_COND_V(next_op == -1, NULL);
-
- // OK! create operator..
- // OK! create operator..
- if (is_unary) {
-
- int expr_pos = next_op;
- while (expression[expr_pos].is_op) {
-
- expr_pos++;
- if (expr_pos == expression.size()) {
- //can happen..
- _set_error("Unexpected end of expression...");
- return NULL;
- }
- }
-
- //consecutively do unary operators
- for (int i = expr_pos - 1; i >= next_op; i--) {
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[i].op;
- if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_builtin_types)) {
-
- _set_error("Can't use increment/decrement operator in constant expression.");
- return NULL;
- }
- op->arguments.push_back(expression[i + 1].node);
-
- expression.write[i].is_op = false;
- expression.write[i].node = op;
-
- if (!_validate_operator(op, &op->return_cache)) {
-
- String at;
- for (int j = 0; j < op->arguments.size(); j++) {
- if (j > 0)
- at += " and ";
- at += get_datatype_name(op->arguments[j]->get_datatype());
- }
- _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at);
- return NULL;
- }
- expression.remove(i + 1);
- }
-
- } else if (is_ternary) {
-
- if (next_op < 1 || next_op >= (expression.size() - 1)) {
- _set_error("Parser bug...");
- ERR_FAIL_V(NULL);
- }
-
- if (next_op + 2 >= expression.size() || !expression[next_op + 2].is_op || expression[next_op + 2].op != OP_SELECT_ELSE) {
- _set_error("Missing matching ':' for select operator");
- return NULL;
- }
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[next_op].op;
- op->arguments.push_back(expression[next_op - 1].node);
- op->arguments.push_back(expression[next_op + 1].node);
- op->arguments.push_back(expression[next_op + 3].node);
-
- expression.write[next_op - 1].is_op = false;
- expression.write[next_op - 1].node = op;
- if (!_validate_operator(op, &op->return_cache)) {
-
- String at;
- for (int i = 0; i < op->arguments.size(); i++) {
- if (i > 0)
- at += " and ";
- at += get_datatype_name(op->arguments[i]->get_datatype());
- }
- _set_error("Invalid argument to ternary ?: operator: " + at);
- return NULL;
- }
-
- for (int i = 0; i < 4; i++) {
- expression.remove(next_op);
- }
-
- } else {
-
- if (next_op < 1 || next_op >= (expression.size() - 1)) {
- _set_error("Parser bug...");
- ERR_FAIL_V(NULL);
- }
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[next_op].op;
-
- if (expression[next_op - 1].is_op) {
-
- _set_error("Parser bug...");
- ERR_FAIL_V(NULL);
- }
-
- if (_is_operator_assign(op->op)) {
-
- String assign_message;
- if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) {
-
- _set_error(assign_message);
- return NULL;
- }
- }
-
- if (expression[next_op + 1].is_op) {
- // this is not invalid and can really appear
- // but it becomes invalid anyway because no binary op
- // can be followed by a unary op in a valid combination,
- // due to how precedence works, unaries will always disappear first
-
- _set_error("Parser bug...");
- }
-
- op->arguments.push_back(expression[next_op - 1].node); //expression goes as left
- op->arguments.push_back(expression[next_op + 1].node); //next expression goes as right
- expression.write[next_op - 1].node = op;
-
- //replace all 3 nodes by this operator and make it an expression
-
- if (!_validate_operator(op, &op->return_cache)) {
-
- String at;
- for (int i = 0; i < op->arguments.size(); i++) {
- if (i > 0)
- at += " and ";
- if (op->arguments[i]->get_datatype() == TYPE_STRUCT) {
- at += op->arguments[i]->get_datatype_name();
- } else {
- at += get_datatype_name(op->arguments[i]->get_datatype());
- }
- }
- _set_error("Invalid arguments to operator '" + get_operator_text(op->op) + "' :" + at);
- return NULL;
- }
-
- expression.remove(next_op);
- expression.remove(next_op);
- }
- }
-
- return expression[0].node;
-}
-
-ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node) {
-
- if (p_node->type != Node::TYPE_OPERATOR)
- return p_node;
-
- //for now only reduce simple constructors
- OperatorNode *op = static_cast<OperatorNode *>(p_node);
-
- if (op->op == OP_CONSTRUCT) {
-
- ERR_FAIL_COND_V(op->arguments[0]->type != Node::TYPE_VARIABLE, p_node);
-
- DataType type = op->get_datatype();
- DataType base = get_scalar_type(type);
- int cardinality = get_cardinality(type);
-
- Vector<ConstantNode::Value> values;
-
- for (int i = 1; i < op->arguments.size(); i++) {
-
- op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]);
- if (op->arguments[i]->type == Node::TYPE_CONSTANT) {
- ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i]);
-
- if (get_scalar_type(cn->datatype) == base) {
- for (int j = 0; j < cn->values.size(); j++) {
- values.push_back(cn->values[j]);
- }
- } else if (get_scalar_type(cn->datatype) == cn->datatype) {
-
- ConstantNode::Value v;
- if (!convert_constant(cn, base, &v)) {
- return p_node;
- }
- values.push_back(v);
- } else {
- return p_node;
- }
-
- } else {
- return p_node;
- }
- }
-
- if (values.size() == 1) {
- if (type >= TYPE_MAT2 && type <= TYPE_MAT4) {
- ConstantNode::Value value = values[0];
- ConstantNode::Value zero;
- zero.real = 0.0f;
- int size = 2 + (type - TYPE_MAT2);
-
- values.clear();
- for (int i = 0; i < size; i++) {
- for (int j = 0; j < size; j++) {
- values.push_back(i == j ? value : zero);
- }
- }
- } else {
- ConstantNode::Value value = values[0];
- for (int i = 1; i < cardinality; i++) {
- values.push_back(value);
- }
- }
- } else if (values.size() != cardinality) {
- ERR_PRINT("Failed to reduce expression, values and cardinality mismatch.");
- return p_node;
- }
-
- ConstantNode *cn = alloc_node<ConstantNode>();
- cn->datatype = op->get_datatype();
- cn->values = values;
- return cn;
- } else if (op->op == OP_NEGATE) {
-
- op->arguments.write[0] = _reduce_expression(p_block, op->arguments[0]);
- if (op->arguments[0]->type == Node::TYPE_CONSTANT) {
-
- ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[0]);
-
- DataType base = get_scalar_type(cn->datatype);
-
- Vector<ConstantNode::Value> values;
-
- for (int i = 0; i < cn->values.size(); i++) {
-
- ConstantNode::Value nv;
- switch (base) {
- case TYPE_BOOL: {
- nv.boolean = !cn->values[i].boolean;
- } break;
- case TYPE_INT: {
- nv.sint = -cn->values[i].sint;
- } break;
- case TYPE_UINT: {
- // Intentionally wrap the unsigned int value, because GLSL does.
- nv.uint = 0 - cn->values[i].uint;
- } break;
- case TYPE_FLOAT: {
- nv.real = -cn->values[i].real;
- } break;
- default: {
- }
- }
-
- values.push_back(nv);
- }
-
- cn->values = values;
- return cn;
- }
- }
-
- return p_node;
-}
-
-ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
-
- ShaderLanguage::Node *expr = _parse_expression(p_block, p_builtin_types);
- if (!expr) //errored
- return NULL;
-
- expr = _reduce_expression(p_block, expr);
-
- return expr;
-}
-
-Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) {
-
- while (true) {
-
- TkPos pos = _get_tkpos();
-
- Token tk = _get_token();
-
- if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_SWITCH) {
- if (tk.type != TK_CF_CASE && tk.type != TK_CF_DEFAULT && tk.type != TK_CURLY_BRACKET_CLOSE) {
- _set_error("Switch may contains only case and default blocks");
- return ERR_PARSE_ERROR;
- }
- }
-
- bool is_struct = shader->structs.has(tk.text);
-
- if (tk.type == TK_CURLY_BRACKET_CLOSE) { //end of block
- if (p_just_one) {
- _set_error("Unexpected '}'");
- return ERR_PARSE_ERROR;
- }
-
- return OK;
-
- } else if (tk.type == TK_CONST || is_token_precision(tk.type) || is_token_nonvoid_datatype(tk.type) || is_struct) {
- String struct_name = "";
- if (is_struct) {
- struct_name = tk.text;
- }
-
- bool is_const = false;
-
- if (tk.type == TK_CONST) {
- is_const = true;
- tk = _get_token();
-
- if (!is_struct) {
- is_struct = shader->structs.has(tk.text); // check again.
- struct_name = tk.text;
- }
- }
-
- DataPrecision precision = PRECISION_DEFAULT;
- if (is_token_precision(tk.type)) {
- precision = get_token_precision(tk.type);
- tk = _get_token();
-
- if (!is_struct) {
- is_struct = shader->structs.has(tk.text); // check again.
- }
- if (is_struct && precision != PRECISION_DEFAULT) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
- if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (!is_struct) {
- if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for variable (samplers not allowed)");
- return ERR_PARSE_ERROR;
- }
- }
-
- DataType type = is_struct ? TYPE_STRUCT : get_token_datatype(tk.type);
-
- if (_validate_datatype(type) != OK) {
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- Node *vardecl = NULL;
-
- while (true) {
-
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after type");
- return ERR_PARSE_ERROR;
- }
-
- StringName name = tk.text;
- ShaderLanguage::IdentifierType itype;
- if (_find_identifier(p_block, p_builtin_types, name, (ShaderLanguage::DataType *)0, &itype)) {
- if (itype != IDENTIFIER_FUNCTION) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
- }
-
- BlockNode::Variable var;
- var.type = type;
- var.precision = precision;
- var.line = tk_line;
- var.array_size = 0;
- var.is_const = is_const;
- var.struct_name = struct_name;
-
- tk = _get_token();
-
- if (tk.type == TK_BRACKET_OPEN) {
- bool unknown_size = false;
-
- if (VisualServer::get_singleton()->is_low_end() && is_const) {
- _set_error("Local const arrays are supported only on high-end platform!");
- return ERR_PARSE_ERROR;
- }
-
- ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>();
- if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
- } else {
- node->datatype = type;
- }
- node->precision = precision;
- node->is_const = is_const;
- vardecl = (Node *)node;
-
- ArrayDeclarationNode::Declaration decl;
- decl.name = name;
- decl.size = 0U;
-
- tk = _get_token();
-
- if (tk.type == TK_BRACKET_CLOSE) {
- unknown_size = true;
- } else {
-
- if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
- _set_error("Expected integer constant > 0 or ']'");
- return ERR_PARSE_ERROR;
- }
-
- decl.size = ((uint32_t)tk.constant);
- tk = _get_token();
-
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- var.array_size = decl.size;
- }
-
- bool full_def = false;
-
- tk = _get_token();
- if (tk.type == TK_OP_ASSIGN) {
-
- if (VisualServer::get_singleton()->is_low_end()) {
- _set_error("Array initialization is supported only on high-end platform!");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- if (tk.type != TK_CURLY_BRACKET_OPEN) {
-
- if (unknown_size) {
- _set_error("Expected '{'");
- return ERR_PARSE_ERROR;
- }
-
- full_def = true;
-
- DataPrecision precision2 = PRECISION_DEFAULT;
- if (is_token_precision(tk.type)) {
- precision2 = get_token_precision(tk.type);
- tk = _get_token();
- if (shader->structs.has(tk.text)) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
- if (!is_token_nonvoid_datatype(tk.type)) {
- _set_error("Expected datatype after precision");
- return ERR_PARSE_ERROR;
- }
- }
-
- DataType type2;
- String struct_name2 = "";
-
- if (shader->structs.has(tk.text)) {
- type2 = TYPE_STRUCT;
- struct_name2 = tk.text;
- } else {
- if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for array");
- return ERR_PARSE_ERROR;
- }
- type2 = get_token_datatype(tk.type);
- }
-
- int array_size2 = 0;
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- TkPos pos2 = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- array_size2 = var.array_size;
- tk = _get_token();
- } else {
- _set_tkpos(pos2);
-
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
- }
-
- ConstantNode *cnode = (ConstantNode *)n;
- if (cnode->values.size() == 1) {
- array_size2 = cnode->values[0].sint;
- if (array_size2 <= 0) {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- } else {
- tk = _get_token();
- }
- }
- } else {
- _set_error("Expected '['");
- return ERR_PARSE_ERROR;
- }
-
- if (precision != precision2 || type != type2 || struct_name != struct_name2 || var.array_size != array_size2) {
- String error_str = "Cannot convert from '";
- if (precision2 != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision2);
- error_str += " ";
- }
- if (type2 == TYPE_STRUCT) {
- error_str += struct_name2;
- } else {
- error_str += get_datatype_name(type2);
- }
- error_str += "[";
- error_str += itos(array_size2);
- error_str += "]'";
- error_str += " to '";
- if (precision != PRECISION_DEFAULT) {
- error_str += get_precision_name(precision);
- error_str += " ";
- }
- if (type == TYPE_STRUCT) {
- error_str += struct_name;
- } else {
- error_str += get_datatype_name(type);
- }
- error_str += "[";
- error_str += itos(var.array_size);
- error_str += "]'";
- _set_error(error_str);
- return ERR_PARSE_ERROR;
- }
- }
-
- bool curly = tk.type == TK_CURLY_BRACKET_OPEN;
-
- if (unknown_size) {
- if (!curly) {
- _set_error("Expected '{'");
- return ERR_PARSE_ERROR;
- }
- } else {
- if (full_def) {
- if (curly) {
- _set_error("Expected '('");
- return ERR_PARSE_ERROR;
- }
- }
- }
-
- if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
- while (true) {
-
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n) {
- return ERR_PARSE_ERROR;
- }
-
- if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
- _set_error("Expected constant expression");
- return ERR_PARSE_ERROR;
- }
-
- if (var.type != n->get_datatype() || struct_name != n->get_datatype_name()) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? struct_name : get_datatype_name(var.type)) + "'");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type == TK_COMMA) {
- decl.initializer.push_back(n);
- continue;
- } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
- decl.initializer.push_back(n);
- break;
- } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
- decl.initializer.push_back(n);
- break;
- } else {
- if (curly)
- _set_error("Expected '}' or ','");
- else
- _set_error("Expected ')' or ','");
- return ERR_PARSE_ERROR;
- }
- }
- if (unknown_size) {
- decl.size = decl.initializer.size();
- var.array_size = decl.initializer.size();
- } else if (decl.initializer.size() != var.array_size) {
- _set_error("Array size mismatch");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
- }
- } else {
- if (unknown_size) {
- _set_error("Expected array initialization");
- return ERR_PARSE_ERROR;
- }
- if (is_const) {
- _set_error("Expected initialization of constant");
- return ERR_PARSE_ERROR;
- }
- }
-
- node->declarations.push_back(decl);
- } else if (tk.type == TK_OP_ASSIGN) {
-
- VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
- if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
- } else {
- node->datatype = type;
- }
- node->precision = precision;
- node->is_const = is_const;
- vardecl = (Node *)node;
-
- VariableDeclarationNode::Declaration decl;
- decl.name = name;
- decl.initializer = NULL;
-
- //variable created with assignment! must parse an expression
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n)
- 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;
- }
- decl.initializer = n;
-
- if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) {
- _set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
- node->declarations.push_back(decl);
- } else {
- if (is_const) {
- _set_error("Expected initialization of constant");
- return ERR_PARSE_ERROR;
- }
-
- VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
- if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
- } else {
- node->datatype = type;
- }
- node->precision = precision;
- vardecl = (Node *)node;
-
- VariableDeclarationNode::Declaration decl;
- decl.name = name;
- decl.initializer = NULL;
- node->declarations.push_back(decl);
- }
-
- p_block->statements.push_back(vardecl);
-
- p_block->variables[name] = var;
-
- if (tk.type == TK_COMMA) {
- tk = _get_token();
- //another variable
- } else if (tk.type == TK_SEMICOLON) {
- break;
- } else {
- _set_error("Expected ',' or ';' after variable");
- return ERR_PARSE_ERROR;
- }
- }
- } else if (tk.type == TK_CURLY_BRACKET_OPEN) {
- //a sub block, just because..
- BlockNode *block = alloc_node<BlockNode>();
- block->parent_block = p_block;
- _parse_block(block, p_builtin_types, false, p_can_break, p_can_continue);
- p_block->statements.push_back(block);
- } else if (tk.type == TK_CF_IF) {
- //if () {}
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after if");
- return ERR_PARSE_ERROR;
- }
-
- ControlFlowNode *cf = alloc_node<ControlFlowNode>();
- cf->flow_op = FLOW_OP_IF;
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n)
- return ERR_PARSE_ERROR;
-
- if (n->get_datatype() != TYPE_BOOL) {
- _set_error("Expected boolean expression");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after expression");
- return ERR_PARSE_ERROR;
- }
-
- BlockNode *block = alloc_node<BlockNode>();
- block->parent_block = p_block;
- cf->expressions.push_back(n);
- cf->blocks.push_back(block);
- p_block->statements.push_back(cf);
-
- Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
- if (err)
- return err;
-
- pos = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_CF_ELSE) {
-
- block = alloc_node<BlockNode>();
- block->parent_block = p_block;
- cf->blocks.push_back(block);
- err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
-
- } else {
- _set_tkpos(pos); //rollback
- }
- } else if (tk.type == TK_CF_SWITCH) {
-
- if (VisualServer::get_singleton()->is_low_end()) {
- _set_error("\"switch\" operator is supported only on high-end platform!");
- return ERR_PARSE_ERROR;
- }
-
- // switch() {}
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after switch");
- return ERR_PARSE_ERROR;
- }
- ControlFlowNode *cf = alloc_node<ControlFlowNode>();
- cf->flow_op = FLOW_OP_SWITCH;
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n)
- return ERR_PARSE_ERROR;
- if (n->get_datatype() != TYPE_INT) {
- _set_error("Expected integer expression");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after expression");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
- if (tk.type != TK_CURLY_BRACKET_OPEN) {
- _set_error("Expected '{' after switch statement");
- return ERR_PARSE_ERROR;
- }
- BlockNode *switch_block = alloc_node<BlockNode>();
- switch_block->block_type = BlockNode::BLOCK_TYPE_SWITCH;
- switch_block->parent_block = p_block;
- cf->expressions.push_back(n);
- cf->blocks.push_back(switch_block);
- p_block->statements.push_back(cf);
-
- int prev_type = TK_CF_CASE;
- while (true) { // Go-through multiple cases.
-
- if (_parse_block(switch_block, p_builtin_types, true, true, false) != OK) {
- return ERR_PARSE_ERROR;
- }
- pos = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_CF_CASE || tk.type == TK_CF_DEFAULT) {
- if (prev_type == TK_CF_DEFAULT) {
- if (tk.type == TK_CF_CASE) {
- _set_error("Cases must be defined before default case.");
- return ERR_PARSE_ERROR;
- } else if (prev_type == TK_CF_DEFAULT) {
- _set_error("Default case must be defined only once.");
- return ERR_PARSE_ERROR;
- }
- }
- prev_type = tk.type;
- _set_tkpos(pos);
- continue;
- } else {
- Set<int> constants;
- for (int i = 0; i < switch_block->statements.size(); i++) { // Checks for duplicates.
- ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i];
- if (flow) {
- if (flow->flow_op == FLOW_OP_CASE) {
- ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]);
- if (!n2) {
- return ERR_PARSE_ERROR;
- }
- if (n2->values.empty()) {
- return ERR_PARSE_ERROR;
- }
- if (constants.has(n2->values[0].sint)) {
- _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'");
- return ERR_PARSE_ERROR;
- }
- constants.insert(n2->values[0].sint);
- } else if (flow->flow_op == FLOW_OP_DEFAULT) {
- continue;
- } else {
- return ERR_PARSE_ERROR;
- }
- } else {
- return ERR_PARSE_ERROR;
- }
- }
- break;
- }
- }
-
- } else if (tk.type == TK_CF_CASE) {
- // case x : break; | return;
-
- if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) {
- _set_tkpos(pos);
- return OK;
- }
-
- if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) {
- _set_error("case must be placed within switch block");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- int sign = 1;
-
- if (tk.type == TK_OP_SUB) {
- sign = -1;
- tk = _get_token();
- }
-
- if (tk.type != TK_INT_CONSTANT) {
- _set_error("Expected integer constant");
- return ERR_PARSE_ERROR;
- }
-
- int constant = (int)tk.constant * sign;
-
- tk = _get_token();
-
- if (tk.type != TK_COLON) {
- _set_error("Expected ':'");
- return ERR_PARSE_ERROR;
- }
-
- ControlFlowNode *cf = alloc_node<ControlFlowNode>();
- cf->flow_op = FLOW_OP_CASE;
-
- ConstantNode *n = alloc_node<ConstantNode>();
- ConstantNode::Value v;
- v.sint = constant;
- n->values.push_back(v);
- n->datatype = TYPE_INT;
-
- BlockNode *case_block = alloc_node<BlockNode>();
- case_block->block_type = BlockNode::BLOCK_TYPE_CASE;
- case_block->parent_block = p_block;
- cf->expressions.push_back(n);
- cf->blocks.push_back(case_block);
- p_block->statements.push_back(cf);
-
- Error err = _parse_block(case_block, p_builtin_types, false, true, false);
- if (err)
- return err;
-
- return OK;
-
- } else if (tk.type == TK_CF_DEFAULT) {
-
- if (p_block && p_block->block_type == BlockNode::BLOCK_TYPE_CASE) {
- _set_tkpos(pos);
- return OK;
- }
-
- if (!p_block || (p_block->block_type != BlockNode::BLOCK_TYPE_SWITCH)) {
- _set_error("default must be placed within switch block");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- if (tk.type != TK_COLON) {
- _set_error("Expected ':'");
- return ERR_PARSE_ERROR;
- }
-
- ControlFlowNode *cf = alloc_node<ControlFlowNode>();
- cf->flow_op = FLOW_OP_DEFAULT;
-
- BlockNode *default_block = alloc_node<BlockNode>();
- default_block->block_type = BlockNode::BLOCK_TYPE_DEFAULT;
- default_block->parent_block = p_block;
- cf->blocks.push_back(default_block);
- p_block->statements.push_back(cf);
-
- Error err = _parse_block(default_block, p_builtin_types, false, true, false);
- if (err)
- return err;
-
- return OK;
-
- } else if (tk.type == TK_CF_DO || tk.type == TK_CF_WHILE) {
- // do {} while()
- // while() {}
- bool is_do = tk.type == TK_CF_DO;
-
- BlockNode *do_block = NULL;
- if (is_do) {
-
- do_block = alloc_node<BlockNode>();
- do_block->parent_block = p_block;
-
- Error err = _parse_block(do_block, p_builtin_types, true, true, true);
- if (err)
- return err;
-
- tk = _get_token();
- if (tk.type != TK_CF_WHILE) {
- _set_error("Expected while after do");
- return ERR_PARSE_ERROR;
- }
- }
- tk = _get_token();
-
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after while");
- return ERR_PARSE_ERROR;
- }
-
- ControlFlowNode *cf = alloc_node<ControlFlowNode>();
- if (is_do) {
- cf->flow_op = FLOW_OP_DO;
- } else {
- cf->flow_op = FLOW_OP_WHILE;
- }
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!n)
- return ERR_PARSE_ERROR;
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after expression");
- return ERR_PARSE_ERROR;
- }
- if (!is_do) {
- BlockNode *block = alloc_node<BlockNode>();
- block->parent_block = p_block;
- cf->expressions.push_back(n);
- cf->blocks.push_back(block);
- p_block->statements.push_back(cf);
-
- Error err = _parse_block(block, p_builtin_types, true, true, true);
- if (err)
- return err;
- } else {
-
- cf->expressions.push_back(n);
- cf->blocks.push_back(do_block);
- p_block->statements.push_back(cf);
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- }
- } else if (tk.type == TK_CF_FOR) {
- // for() {}
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after for");
- return ERR_PARSE_ERROR;
- }
-
- ControlFlowNode *cf = alloc_node<ControlFlowNode>();
- cf->flow_op = FLOW_OP_FOR;
-
- BlockNode *init_block = alloc_node<BlockNode>();
- init_block->parent_block = p_block;
- init_block->single_statement = true;
- cf->blocks.push_back(init_block);
- if (_parse_block(init_block, p_builtin_types, true, false, false) != OK) {
- return ERR_PARSE_ERROR;
- }
-
- Node *n = _parse_and_reduce_expression(init_block, p_builtin_types);
- if (!n)
- return ERR_PARSE_ERROR;
-
- if (n->get_datatype() != TYPE_BOOL) {
- _set_error("Middle expression is expected to be boolean.");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after middle expression");
- return ERR_PARSE_ERROR;
- }
-
- cf->expressions.push_back(n);
-
- n = _parse_and_reduce_expression(init_block, p_builtin_types);
- if (!n)
- return ERR_PARSE_ERROR;
-
- cf->expressions.push_back(n);
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' after third expression");
- return ERR_PARSE_ERROR;
- }
-
- BlockNode *block = alloc_node<BlockNode>();
- block->parent_block = init_block;
- cf->blocks.push_back(block);
- p_block->statements.push_back(cf);
-
- Error err = _parse_block(block, p_builtin_types, true, true, true);
- if (err)
- return err;
-
- } else if (tk.type == TK_CF_RETURN) {
-
- //check return type
- BlockNode *b = p_block;
- while (b && !b->parent_function) {
- b = b->parent_block;
- }
-
- if (!b) {
- _set_error("Bug");
- return ERR_BUG;
- }
-
- ControlFlowNode *flow = alloc_node<ControlFlowNode>();
- flow->flow_op = FLOW_OP_RETURN;
-
- pos = _get_tkpos();
- tk = _get_token();
- 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) + "'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_tkpos(pos); //rollback, wants expression
- Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!expr)
- 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) + "'");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after return expression");
- return ERR_PARSE_ERROR;
- }
-
- flow->expressions.push_back(expr);
- }
-
- p_block->statements.push_back(flow);
-
- BlockNode *block = p_block;
- while (block) {
- if (block->block_type == BlockNode::BLOCK_TYPE_CASE || block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) {
- return OK;
- }
- block = block->parent_block;
- }
- } else if (tk.type == TK_CF_DISCARD) {
-
- //check return type
- BlockNode *b = p_block;
- while (b && !b->parent_function) {
- b = b->parent_block;
- }
- if (!b) {
- _set_error("Bug");
- return ERR_BUG;
- }
-
- if (!b->parent_function->can_discard) {
- _set_error("Use of 'discard' is not allowed here.");
- return ERR_PARSE_ERROR;
- }
-
- ControlFlowNode *flow = alloc_node<ControlFlowNode>();
- flow->flow_op = FLOW_OP_DISCARD;
-
- pos = _get_tkpos();
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- //all is good
- _set_error("Expected ';' after discard");
- }
-
- 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");
- }
-
- ControlFlowNode *flow = alloc_node<ControlFlowNode>();
- flow->flow_op = FLOW_OP_BREAK;
-
- pos = _get_tkpos();
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- //all is good
- _set_error("Expected ';' after break");
- }
-
- p_block->statements.push_back(flow);
-
- BlockNode *block = p_block;
- while (block) {
- if (block->block_type == BlockNode::BLOCK_TYPE_CASE || block->block_type == BlockNode::BLOCK_TYPE_DEFAULT) {
- return OK;
- }
- block = block->parent_block;
- }
-
- } else if (tk.type == TK_CF_CONTINUE) {
-
- if (!p_can_continue) {
- //all is good
- _set_error("Continuing is not allowed here");
- }
-
- ControlFlowNode *flow = alloc_node<ControlFlowNode>();
- flow->flow_op = FLOW_OP_CONTINUE;
-
- pos = _get_tkpos();
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- //all is good
- _set_error("Expected ';' after continue");
- }
-
- p_block->statements.push_back(flow);
-
- } else {
-
- //nothing else, so expression
- _set_tkpos(pos); //rollback
- Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
- if (!expr)
- return ERR_PARSE_ERROR;
- p_block->statements.push_back(expr);
- tk = _get_token();
-
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after statement");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (p_just_one)
- break;
- }
-
- return OK;
-}
-
-String ShaderLanguage::_get_shader_type_list(const Set<String> &p_shader_types) const {
-
- // Return a list of shader types as an human-readable string
- String valid_types;
- for (const Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) {
- if (valid_types != String()) {
- valid_types += ", ";
- }
-
- valid_types += "'" + E->get() + "'";
- }
-
- return valid_types;
-}
-
-String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const {
- switch (p_qualifier) {
- case ArgumentQualifier::ARGUMENT_QUALIFIER_IN:
- return "in";
- case ArgumentQualifier::ARGUMENT_QUALIFIER_OUT:
- return "out";
- case ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT:
- return "inout";
- }
- return "";
-}
-
-Error ShaderLanguage::_validate_datatype(DataType p_type) {
- if (VisualServer::get_singleton()->is_low_end()) {
- bool invalid_type = false;
-
- switch (p_type) {
- case TYPE_UINT:
- case TYPE_UVEC2:
- case TYPE_UVEC3:
- case TYPE_UVEC4:
- case TYPE_ISAMPLER2D:
- case TYPE_USAMPLER2D:
- case TYPE_ISAMPLER3D:
- case TYPE_USAMPLER3D:
- case TYPE_USAMPLER2DARRAY:
- case TYPE_ISAMPLER2DARRAY:
- invalid_type = true;
- break;
- default:
- break;
- }
-
- if (invalid_type) {
- _set_error(vformat("\"%s\" type is supported only on high-end platform!", get_datatype_name(p_type)));
- return ERR_UNAVAILABLE;
- }
- }
- return OK;
-}
-
-Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types) {
-
- Token tk = _get_token();
-
- if (tk.type != TK_SHADER_TYPE) {
- _set_error("Expected 'shader_type' at the beginning of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
- return ERR_PARSE_ERROR;
- }
-
- String shader_type_identifier;
-
- shader_type_identifier = tk.text;
-
- if (!p_shader_types.has(shader_type_identifier)) {
- _set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';' after 'shader_type <type>'.");
- }
-
- tk = _get_token();
-
- int texture_uniforms = 0;
- int uniforms = 0;
-
- while (tk.type != TK_EOF) {
-
- switch (tk.type) {
- case TK_RENDER_MODE: {
-
- while (true) {
-
- StringName mode;
- _get_completable_identifier(NULL, COMPLETION_RENDER_MODE, mode);
-
- if (mode == StringName()) {
- _set_error("Expected identifier for render mode");
- return ERR_PARSE_ERROR;
- }
-
- if (p_render_modes.find(mode) == -1) {
- _set_error("Invalid render mode: '" + String(mode) + "'");
- return ERR_PARSE_ERROR;
- }
-
- if (shader->render_modes.find(mode) != -1) {
- _set_error("Duplicate render mode: '" + String(mode) + "'");
- return ERR_PARSE_ERROR;
- }
-
- shader->render_modes.push_back(mode);
-
- tk = _get_token();
- if (tk.type == TK_COMMA) {
- //all good, do nothing
- } else if (tk.type == TK_SEMICOLON) {
- break; //done
- } else {
- _set_error("Unexpected token: " + get_token_text(tk));
- return ERR_PARSE_ERROR;
- }
- }
- } break;
- case TK_STRUCT: {
- ShaderNode::Struct st;
- DataType type;
-
- tk = _get_token();
- if (tk.type == TK_IDENTIFIER) {
- st.name = tk.text;
- tk = _get_token();
- if (tk.type != TK_CURLY_BRACKET_OPEN) {
- _set_error("Expected '{'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected struct identifier!");
- return ERR_PARSE_ERROR;
- }
-
- StructNode *st_node = alloc_node<StructNode>();
- st.shader_struct = st_node;
-
- int member_count = 0;
- Set<String> member_names;
- while (true) { // variables list
- tk = _get_token();
- if (tk.type == TK_CURLY_BRACKET_CLOSE) {
- break;
- }
- StringName struct_name = "";
- bool struct_dt = false;
- bool use_precision = false;
- DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
-
- if (tk.type == TK_STRUCT) {
- _set_error("nested structs are not allowed!");
- return ERR_PARSE_ERROR;
- }
-
- if (is_token_precision(tk.type)) {
- precision = get_token_precision(tk.type);
- use_precision = true;
- tk = _get_token();
- }
-
- if (shader->structs.has(tk.text)) {
- struct_name = tk.text;
- struct_dt = true;
- if (use_precision) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (!is_token_datatype(tk.type) && !struct_dt) {
- _set_error("Expected datatype.");
- return ERR_PARSE_ERROR;
- } else {
- type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
-
- if (is_sampler_type(type)) {
- _set_error("sampler datatype not allowed here");
- return ERR_PARSE_ERROR;
- } else if (type == TYPE_VOID) {
- _set_error("void datatype not allowed here");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier!");
- return ERR_PARSE_ERROR;
- }
-
- MemberNode *member = alloc_node<MemberNode>();
- member->precision = precision;
- member->datatype = type;
- member->struct_name = struct_name;
- member->name = tk.text;
-
- if (member_names.has(member->name)) {
- _set_error("Redefinition of '" + String(member->name) + "'");
- return ERR_PARSE_ERROR;
- }
- member_names.insert(member->name);
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- tk = _get_token();
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
- member->array_size = (int)tk.constant;
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
- }
- }
- st_node->members.push_back(member);
-
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ']' or ';'");
- return ERR_PARSE_ERROR;
- }
- member_count++;
- }
- }
- if (member_count == 0) {
- _set_error("Empty structs are not allowed!");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- shader->structs[st.name] = st;
- shader->vstructs.push_back(st); // struct's order is important!
-
- } break;
- case TK_UNIFORM:
- case TK_VARYING: {
-
- bool uniform = tk.type == TK_UNIFORM;
- DataPrecision precision = PRECISION_DEFAULT;
- DataInterpolation interpolation = INTERPOLATION_SMOOTH;
- DataType type;
- StringName name;
-
- tk = _get_token();
- if (is_token_interpolation(tk.type)) {
- interpolation = get_token_interpolation(tk.type);
- tk = _get_token();
- }
-
- if (is_token_precision(tk.type)) {
- precision = get_token_precision(tk.type);
- tk = _get_token();
- }
-
- if (!is_token_datatype(tk.type)) {
- _set_error("Expected datatype. ");
- return ERR_PARSE_ERROR;
- }
-
- type = get_token_datatype(tk.type);
-
- if (type == TYPE_VOID) {
- _set_error("void datatype not allowed here");
- return ERR_PARSE_ERROR;
- }
-
- if (!uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
- _set_error("Invalid type for varying, only float,vec2,vec3,vec4,mat2,mat3,mat4 or array of these types allowed.");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier!");
- return ERR_PARSE_ERROR;
- }
-
- name = tk.text;
-
- if (_find_identifier(NULL, Map<StringName, BuiltInInfo>(), name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
-
- if (has_builtin(p_functions, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
-
- if (uniform) {
-
- ShaderNode::Uniform uniform2;
-
- if (is_sampler_type(type)) {
- uniform2.texture_order = texture_uniforms++;
- uniform2.order = -1;
- if (_validate_datatype(type) != OK) {
- return ERR_PARSE_ERROR;
- }
- } else {
- uniform2.texture_order = -1;
- uniform2.order = uniforms++;
- }
- uniform2.type = type;
- uniform2.precision = precision;
-
- //todo parse default value
-
- tk = _get_token();
-
- if (tk.type == TK_COLON) {
- //hint
- do {
- tk = _get_token();
- if (tk.type == TK_HINT_WHITE_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
- } else if (tk.type == TK_HINT_BLACK_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_BLACK;
- } else if (tk.type == TK_HINT_NORMAL_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_NORMAL;
- } else if (tk.type == TK_HINT_ROUGHNESS_NORMAL_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL;
- } else if (tk.type == TK_HINT_ROUGHNESS_R) {
- uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_R;
- } else if (tk.type == TK_HINT_ROUGHNESS_G) {
- uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_G;
- } else if (tk.type == TK_HINT_ROUGHNESS_B) {
- uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_B;
- } else if (tk.type == TK_HINT_ROUGHNESS_A) {
- uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_A;
- } else if (tk.type == TK_HINT_ROUGHNESS_GRAY) {
- uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_GRAY;
- } else if (tk.type == TK_HINT_ANISO_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_ANISO;
- } else if (tk.type == TK_HINT_ALBEDO_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_ALBEDO;
- } else if (tk.type == TK_HINT_BLACK_ALBEDO_TEXTURE) {
- uniform2.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO;
- } else if (tk.type == TK_HINT_COLOR) {
- if (type != TYPE_VEC4) {
- _set_error("Color hint is for vec4 only");
- return ERR_PARSE_ERROR;
- }
- uniform2.hint = ShaderNode::Uniform::HINT_COLOR;
- } else if (tk.type == TK_HINT_RANGE) {
-
- uniform2.hint = ShaderNode::Uniform::HINT_RANGE;
- if (type != TYPE_FLOAT && type != TYPE_INT) {
- _set_error("Range hint is for float and int only");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '(' after hint_range");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- float sign = 1.0;
-
- if (tk.type == TK_OP_SUB) {
- sign = -1.0;
- tk = _get_token();
- }
-
- if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
- _set_error("Expected integer constant");
- return ERR_PARSE_ERROR;
- }
-
- uniform2.hint_range[0] = tk.constant;
- uniform2.hint_range[0] *= sign;
-
- tk = _get_token();
-
- if (tk.type != TK_COMMA) {
- _set_error("Expected ',' after integer constant");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- sign = 1.0;
-
- if (tk.type == TK_OP_SUB) {
- sign = -1.0;
- tk = _get_token();
- }
-
- if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
- _set_error("Expected integer constant after ','");
- return ERR_PARSE_ERROR;
- }
-
- uniform2.hint_range[1] = tk.constant;
- uniform2.hint_range[1] *= sign;
-
- tk = _get_token();
-
- if (tk.type == TK_COMMA) {
- tk = _get_token();
-
- if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
- _set_error("Expected integer constant after ','");
- return ERR_PARSE_ERROR;
- }
-
- uniform2.hint_range[2] = tk.constant;
- tk = _get_token();
- } else {
- if (type == TYPE_INT) {
- uniform2.hint_range[2] = 1;
- } else {
- uniform2.hint_range[2] = 0.001;
- }
- }
-
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ','");
- return ERR_PARSE_ERROR;
- }
- } else if (tk.type == TK_FILTER_LINEAR) {
- uniform2.filter = FILTER_LINEAR;
- } else if (tk.type == TK_FILTER_NEAREST) {
- uniform2.filter = FILTER_NEAREST;
- } else if (tk.type == TK_FILTER_NEAREST_MIPMAP) {
- uniform2.filter = FILTER_NEAREST_MIPMAP;
- } else if (tk.type == TK_FILTER_LINEAR_MIPMAP) {
- uniform2.filter = FILTER_LINEAR_MIPMAP;
- } else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISO) {
- uniform2.filter = FILTER_NEAREST_MIPMAP_ANISO;
- } else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISO) {
- uniform2.filter = FILTER_LINEAR_MIPMAP_ANISO;
- } else if (tk.type == TK_REPEAT_DISABLE) {
- uniform2.repeat = REPEAT_DISABLE;
- } else if (tk.type == TK_REPEAT_ENABLE) {
- uniform2.repeat = REPEAT_ENABLE;
- } else {
- _set_error("Expected valid type hint after ':'.");
- }
-
- if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
- _set_error("This hint is only for sampler types");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- } while (tk.type == TK_COMMA);
- }
-
- if (tk.type == TK_OP_ASSIGN) {
-
- Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
- if (!expr)
- return ERR_PARSE_ERROR;
- if (expr->type != Node::TYPE_CONSTANT) {
- _set_error("Expected constant expression after '='");
- return ERR_PARSE_ERROR;
- }
-
- ConstantNode *cn = static_cast<ConstantNode *>(expr);
-
- uniform2.default_value.resize(cn->values.size());
-
- if (!convert_constant(cn, uniform2.type, uniform2.default_value.ptrw())) {
- _set_error("Can't convert constant to " + get_datatype_name(uniform2.type));
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
- }
-
- shader->uniforms[name] = uniform2;
-
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- } else {
-
- ShaderNode::Varying varying;
- varying.type = type;
- varying.precision = precision;
- varying.interpolation = interpolation;
-
- tk = _get_token();
- if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
- _set_error("Expected ';' or '['");
- return ERR_PARSE_ERROR;
- }
-
- if (tk.type == TK_BRACKET_OPEN) {
- tk = _get_token();
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
- varying.array_size = (int)tk.constant;
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- tk = _get_token();
- if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ';'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected single integer constant > 0");
- return ERR_PARSE_ERROR;
- }
- }
-
- shader->varyings[name] = varying;
- }
-
- } break;
- default: {
- //function or constant variable
-
- bool is_constant = false;
- bool is_struct = false;
- StringName struct_name;
- DataPrecision precision = PRECISION_DEFAULT;
- DataType type;
- StringName name;
-
- if (tk.type == TK_CONST) {
- is_constant = true;
- tk = _get_token();
- }
-
- if (is_token_precision(tk.type)) {
- precision = get_token_precision(tk.type);
- tk = _get_token();
- }
-
- if (shader->structs.has(tk.text)) {
- if (precision != PRECISION_DEFAULT) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
- is_struct = true;
- struct_name = tk.text;
- } else {
-
- if (!is_token_datatype(tk.type)) {
- _set_error("Expected constant, function, uniform or varying");
- return ERR_PARSE_ERROR;
- }
-
- if (!is_token_variable_datatype(tk.type)) {
- _set_error("Invalid data type for constants or function return (samplers not allowed)");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (is_struct) {
- type = TYPE_STRUCT;
- } else {
- type = get_token_datatype(tk.type);
- }
- TkPos prev_pos = _get_tkpos();
- tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Cannot use arrays as return types");
- return ERR_PARSE_ERROR;
- }
- _set_tkpos(prev_pos);
-
- _get_completable_identifier(NULL, COMPLETION_MAIN_FUNCTION, name);
-
- if (name == StringName()) {
- _set_error("Expected function name after datatype");
- return ERR_PARSE_ERROR;
- }
-
- if (_find_identifier(NULL, Map<StringName, BuiltInInfo>(), name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
-
- if (has_builtin(p_functions, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
- if (tk.type != TK_PARENTHESIS_OPEN) {
- if (type == TYPE_VOID) {
- _set_error("Expected '(' after function identifier");
- return ERR_PARSE_ERROR;
- }
-
- //variable
-
- while (true) {
- ShaderNode::Constant constant;
- constant.type = is_struct ? TYPE_STRUCT : type;
- constant.type_str = struct_name;
- constant.precision = precision;
- constant.initializer = NULL;
-
- if (tk.type == TK_OP_ASSIGN) {
-
- if (!is_constant) {
- _set_error("Expected 'const' keyword before constant definition");
- return ERR_PARSE_ERROR;
- }
-
- //variable created with assignment! must parse an expression
- Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
- 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;
- }
-
- constant.initializer = static_cast<ConstantNode *>(expr);
-
- if (is_struct) {
- if (expr->get_datatype_name() != struct_name) {
- _set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + struct_name + "'");
- return ERR_PARSE_ERROR;
- }
- } else if (type != expr->get_datatype()) {
- _set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'");
- return ERR_PARSE_ERROR;
- }
- tk = _get_token();
- } else {
- _set_error("Expected initialization of constant");
- return ERR_PARSE_ERROR;
- }
-
- shader->constants[name] = constant;
- if (tk.type == TK_COMMA) {
- tk = _get_token();
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after type");
- return ERR_PARSE_ERROR;
- }
-
- name = tk.text;
- if (_find_identifier(NULL, Map<StringName, BuiltInInfo>(), name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
-
- if (has_builtin(p_functions, name)) {
- _set_error("Redefinition of '" + String(name) + "'");
- return ERR_PARSE_ERROR;
- }
-
- tk = _get_token();
-
- } else if (tk.type == TK_SEMICOLON) {
- break;
- } else {
- _set_error("Expected ',' or ';' after constant");
- return ERR_PARSE_ERROR;
- }
- }
-
- break;
- }
-
- Map<StringName, BuiltInInfo> builtin_types;
- if (p_functions.has(name)) {
- builtin_types = p_functions[name].built_ins;
- }
-
- ShaderNode::Function function;
-
- function.callable = !p_functions.has(name);
- function.name = name;
-
- FunctionNode *func_node = alloc_node<FunctionNode>();
-
- function.function = func_node;
-
- shader->functions.push_back(function);
-
- func_node->name = name;
- func_node->return_type = type;
- func_node->return_struct_name = struct_name;
- func_node->return_precision = precision;
-
- if (p_functions.has(name)) {
- func_node->can_discard = p_functions[name].can_discard;
- }
-
- func_node->body = alloc_node<BlockNode>();
- func_node->body->parent_function = func_node;
-
- tk = _get_token();
-
- while (true) {
- if (tk.type == TK_PARENTHESIS_CLOSE) {
- break;
- }
-
- ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
-
- if (tk.type == TK_ARG_IN) {
- qualifier = ARGUMENT_QUALIFIER_IN;
- tk = _get_token();
- } else if (tk.type == TK_ARG_OUT) {
- qualifier = ARGUMENT_QUALIFIER_OUT;
- tk = _get_token();
- } else if (tk.type == TK_ARG_INOUT) {
- qualifier = ARGUMENT_QUALIFIER_INOUT;
- tk = _get_token();
- }
-
- DataType ptype;
- StringName pname;
- StringName param_struct_name;
- DataPrecision pprecision = PRECISION_DEFAULT;
- bool use_precision = false;
-
- if (is_token_precision(tk.type)) {
- pprecision = get_token_precision(tk.type);
- tk = _get_token();
- use_precision = true;
- }
-
- is_struct = false;
-
- if (shader->structs.has(tk.text)) {
- is_struct = true;
- param_struct_name = tk.text;
- if (use_precision) {
- _set_error("Precision modifier cannot be used on structs.");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (!is_struct && !is_token_datatype(tk.type)) {
- _set_error("Expected a valid datatype for argument");
- return ERR_PARSE_ERROR;
- }
-
- if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) {
- if (is_sampler_type(get_token_datatype(tk.type))) {
- _set_error("Opaque types cannot be output parameters.");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (is_struct) {
- ptype = TYPE_STRUCT;
- } else {
- ptype = get_token_datatype(tk.type);
- if (_validate_datatype(ptype) != OK) {
- return ERR_PARSE_ERROR;
- }
- if (ptype == TYPE_VOID) {
- _set_error("void not allowed in argument");
- return ERR_PARSE_ERROR;
- }
- }
-
- tk = _get_token();
-
- if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Arrays as parameters are not implemented yet");
- return ERR_PARSE_ERROR;
- }
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier for argument name");
- return ERR_PARSE_ERROR;
- }
-
- pname = tk.text;
-
- ShaderLanguage::IdentifierType itype;
- if (_find_identifier(func_node->body, builtin_types, pname, (ShaderLanguage::DataType *)0, &itype)) {
- if (itype != IDENTIFIER_FUNCTION) {
- _set_error("Redefinition of '" + String(pname) + "'");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (has_builtin(p_functions, pname)) {
- _set_error("Redefinition of '" + String(pname) + "'");
- return ERR_PARSE_ERROR;
- }
-
- FunctionNode::Argument arg;
- arg.type = ptype;
- arg.name = pname;
- arg.type_str = param_struct_name;
- arg.precision = pprecision;
- arg.qualifier = qualifier;
- arg.tex_argument_check = false;
- arg.tex_builtin_check = false;
- arg.tex_argument_filter = FILTER_DEFAULT;
- arg.tex_argument_repeat = REPEAT_DEFAULT;
-
- func_node->arguments.push_back(arg);
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- _set_error("Arrays as parameters are not implemented yet");
- return ERR_PARSE_ERROR;
- }
-
- if (tk.type == TK_COMMA) {
- tk = _get_token();
- //do none and go on
- } else if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ',' or ')' after identifier");
- return ERR_PARSE_ERROR;
- }
- }
-
- if (p_functions.has(name)) {
- //if one of the core functions, make sure they are of the correct form
- if (func_node->arguments.size() > 0) {
- _set_error("Function '" + String(name) + "' expects no arguments.");
- return ERR_PARSE_ERROR;
- }
- if (func_node->return_type != TYPE_VOID) {
- _set_error("Function '" + String(name) + "' must be of void return type.");
- return ERR_PARSE_ERROR;
- }
- }
-
- //all good let's parse inside the function!
- tk = _get_token();
- if (tk.type != TK_CURLY_BRACKET_OPEN) {
- _set_error("Expected '{' to begin function");
- return ERR_PARSE_ERROR;
- }
-
- current_function = name;
-
- Error err = _parse_block(func_node->body, builtin_types);
- if (err)
- return err;
-
- if (func_node->return_type != DataType::TYPE_VOID) {
-
- BlockNode *block = func_node->body;
- if (_find_last_flow_op_in_block(block, FlowOperation::FLOW_OP_RETURN) != OK) {
- _set_error("Expected at least one return statement in a non-void function.");
- return ERR_PARSE_ERROR;
- }
- }
- current_function = StringName();
- }
- }
-
- tk = _get_token();
- }
-
- 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;
- }
- }
- return false;
-}
-
-Error ShaderLanguage::_find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op) {
-
- bool found = false;
-
- for (int i = p_flow->blocks.size() - 1; i >= 0; i--) {
- if (p_flow->blocks[i]->type == Node::TYPE_BLOCK) {
- BlockNode *last_block = (BlockNode *)p_flow->blocks[i];
- if (_find_last_flow_op_in_block(last_block, p_op) == OK) {
- found = true;
- break;
- }
- }
- }
- if (found) {
- return OK;
- }
- return FAILED;
-}
-
-Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op) {
-
- bool found = false;
-
- for (int i = p_block->statements.size() - 1; i >= 0; i--) {
-
- if (p_block->statements[i]->type == Node::TYPE_CONTROL_FLOW) {
- ControlFlowNode *flow = (ControlFlowNode *)p_block->statements[i];
- if (flow->flow_op == p_op) {
- found = true;
- break;
- } else {
- if (_find_last_flow_op_in_op(flow, p_op) == OK) {
- found = true;
- break;
- }
- }
- } else if (p_block->statements[i]->type == Node::TYPE_BLOCK) {
- BlockNode *block = (BlockNode *)p_block->statements[i];
- if (_find_last_flow_op_in_block(block, p_op) == OK) {
- found = true;
- break;
- }
- }
- }
-
- if (found) {
- return OK;
- }
- return FAILED;
-}
-
-// skips over whitespace and /* */ and // comments
-static int _get_first_ident_pos(const String &p_code) {
-
- int idx = 0;
-
-#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0))
-
- while (true) {
- if (GETCHAR(0) == '/' && GETCHAR(1) == '/') {
- idx += 2;
- while (true) {
- if (GETCHAR(0) == 0) return 0;
- if (GETCHAR(0) == '\n') {
- idx++;
- break; // loop
- }
- idx++;
- }
- } else if (GETCHAR(0) == '/' && GETCHAR(1) == '*') {
- idx += 2;
- while (true) {
- if (GETCHAR(0) == 0) return 0;
- if (GETCHAR(0) == '*' && GETCHAR(1) == '/') {
- idx += 2;
- break; // loop
- }
- idx++;
- }
- } else {
- switch (GETCHAR(0)) {
- case ' ':
- case '\t':
- case '\r':
- case '\n': {
- idx++;
- } break; // switch
- default:
- return idx;
- }
- }
- }
-
-#undef GETCHAR
-}
-
-String ShaderLanguage::get_shader_type(const String &p_code) {
-
- bool reading_type = false;
-
- String cur_identifier;
-
- for (int i = _get_first_ident_pos(p_code); i < p_code.length(); i++) {
-
- if (p_code[i] == ';') {
- break;
-
- } else if (p_code[i] <= 32) {
- if (cur_identifier != String()) {
- if (!reading_type) {
- if (cur_identifier != "shader_type") {
- return String();
- }
-
- reading_type = true;
- cur_identifier = String();
- } else {
- return cur_identifier;
- }
- }
- } else {
- cur_identifier += String::chr(p_code[i]);
- }
- }
-
- if (reading_type)
- return cur_identifier;
-
- 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) {
-
- clear();
-
- code = p_code;
-
- nodes = NULL;
-
- shader = alloc_node<ShaderNode>();
- Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
-
- if (err != OK) {
- return err;
- }
- 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, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
-
- clear();
-
- code = p_code;
-
- nodes = NULL;
-
- shader = alloc_node<ShaderNode>();
- _parse_shader(p_functions, p_render_modes, p_shader_types);
-
- switch (completion_type) {
-
- case COMPLETION_NONE: {
- //do nothing
- return OK;
- } break;
- case COMPLETION_RENDER_MODE: {
- for (int i = 0; i < p_render_modes.size(); i++) {
- ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_ENUM);
- r_options->push_back(option);
- }
-
- return OK;
- } break;
- case COMPLETION_STRUCT: {
-
- if (shader->structs.has(completion_struct)) {
- StructNode *node = shader->structs[completion_struct].shader_struct;
- for (int i = 0; i < node->members.size(); i++) {
- ScriptCodeCompletionOption option(node->members[i]->name, ScriptCodeCompletionOption::KIND_MEMBER);
- r_options->push_back(option);
- }
- }
-
- return OK;
- } break;
- case COMPLETION_MAIN_FUNCTION: {
-
- for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
- r_options->push_back(option);
- }
-
- return OK;
- } break;
- case COMPLETION_IDENTIFIER:
- case COMPLETION_FUNCTION_CALL: {
-
- bool comp_ident = completion_type == COMPLETION_IDENTIFIER;
- Map<String, ScriptCodeCompletionOption::Kind> matches;
- StringName skip_function;
- BlockNode *block = completion_block;
-
- if (completion_class == TAG_GLOBAL) {
- while (block) {
- if (comp_ident) {
- for (const Map<StringName, BlockNode::Variable>::Element *E = block->variables.front(); E; E = E->next()) {
-
- if (E->get().line < completion_line) {
- matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE);
- }
- }
- }
-
- if (block->parent_function) {
- if (comp_ident) {
- for (int i = 0; i < block->parent_function->arguments.size(); i++) {
- matches.insert(block->parent_function->arguments[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
- }
- }
- skip_function = block->parent_function->name;
- }
- block = block->parent_block;
- }
-
- if (comp_ident && skip_function != StringName() && p_functions.has(skip_function)) {
-
- for (Map<StringName, BuiltInInfo>::Element *E = p_functions[skip_function].built_ins.front(); E; E = E->next()) {
- ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER;
- if (E->get().constant) {
- kind = ScriptCodeCompletionOption::KIND_CONSTANT;
- }
- matches.insert(E->key(), kind);
- }
- }
-
- if (comp_ident) {
- for (const Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) {
- matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE);
- }
- for (const Map<StringName, ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) {
- matches.insert(E->key(), ScriptCodeCompletionOption::KIND_MEMBER);
- }
- }
-
- for (int i = 0; i < shader->functions.size(); i++) {
- if (!shader->functions[i].callable || shader->functions[i].name == skip_function)
- continue;
- matches.insert(String(shader->functions[i].name), ScriptCodeCompletionOption::KIND_FUNCTION);
- }
-
- int idx = 0;
- bool low_end = VisualServer::get_singleton()->is_low_end();
-
- while (builtin_func_defs[idx].name) {
- if (low_end && builtin_func_defs[idx].high_end) {
- idx++;
- continue;
- }
- matches.insert(String(builtin_func_defs[idx].name), ScriptCodeCompletionOption::KIND_FUNCTION);
- idx++;
- }
-
- } else { // sub-class
- int idx = 0;
- bool low_end = VisualServer::get_singleton()->is_low_end();
-
- while (builtin_func_defs[idx].name) {
- if (low_end && builtin_func_defs[idx].high_end) {
- idx++;
- continue;
- }
- if (builtin_func_defs[idx].tag == completion_class) {
- matches.insert(String(builtin_func_defs[idx].name), ScriptCodeCompletionOption::KIND_FUNCTION);
- }
- idx++;
- }
- }
-
- for (Map<String, ScriptCodeCompletionOption::Kind>::Element *E = matches.front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->key(), E->value());
- if (E->value() == ScriptCodeCompletionOption::KIND_FUNCTION) {
- option.insert_text += "(";
- }
- r_options->push_back(option);
- }
-
- return OK;
- } break;
- case COMPLETION_CALL_ARGUMENTS: {
-
- for (int i = 0; i < shader->functions.size(); i++) {
- if (!shader->functions[i].callable)
- continue;
- if (shader->functions[i].name == completion_function) {
-
- String calltip;
-
- calltip += get_datatype_name(shader->functions[i].function->return_type);
- calltip += " ";
- calltip += shader->functions[i].name;
- calltip += "(";
-
- for (int j = 0; j < shader->functions[i].function->arguments.size(); j++) {
-
- if (j > 0)
- calltip += ", ";
- else
- calltip += " ";
-
- if (j == completion_argument) {
- calltip += CharType(0xFFFF);
- }
-
- calltip += get_datatype_name(shader->functions[i].function->arguments[j].type);
- calltip += " ";
- calltip += shader->functions[i].function->arguments[j].name;
-
- if (j == completion_argument) {
- calltip += CharType(0xFFFF);
- }
- }
-
- if (shader->functions[i].function->arguments.size())
- calltip += " ";
- calltip += ")";
-
- r_call_hint = calltip;
- return OK;
- }
- }
-
- int idx = 0;
-
- String calltip;
- bool low_end = VisualServer::get_singleton()->is_low_end();
-
- while (builtin_func_defs[idx].name) {
-
- if (low_end && builtin_func_defs[idx].high_end) {
- idx++;
- continue;
- }
-
- if (completion_function == builtin_func_defs[idx].name) {
-
- if (builtin_func_defs[idx].tag != completion_class) {
- idx++;
- continue;
- }
-
- if (calltip.length())
- calltip += "\n";
-
- calltip += get_datatype_name(builtin_func_defs[idx].rettype);
- calltip += " ";
- calltip += builtin_func_defs[idx].name;
- calltip += "(";
-
- bool found_arg = false;
- for (int i = 0; i < 4; i++) {
-
- if (builtin_func_defs[idx].args[i] == TYPE_VOID)
- break;
-
- if (i > 0)
- calltip += ", ";
- else
- calltip += " ";
-
- if (i == completion_argument) {
- calltip += CharType(0xFFFF);
- }
-
- calltip += get_datatype_name(builtin_func_defs[idx].args[i]);
-
- if (i == completion_argument) {
- calltip += CharType(0xFFFF);
- }
-
- found_arg = true;
- }
-
- if (found_arg)
- calltip += " ";
- calltip += ")";
- }
- idx++;
- }
-
- r_call_hint = calltip;
-
- return OK;
-
- } break;
- case COMPLETION_INDEX: {
-
- const char colv[4] = { 'r', 'g', 'b', 'a' };
- const char coordv[4] = { 'x', 'y', 'z', 'w' };
- const char coordt[4] = { 's', 't', 'p', 'q' };
-
- int limit = 0;
-
- switch (completion_base) {
- case TYPE_BVEC2:
- case TYPE_IVEC2:
- case TYPE_UVEC2:
- case TYPE_VEC2: {
- limit = 2;
-
- } break;
- case TYPE_BVEC3:
- case TYPE_IVEC3:
- case TYPE_UVEC3:
- case TYPE_VEC3: {
-
- limit = 3;
-
- } break;
- case TYPE_BVEC4:
- case TYPE_IVEC4:
- case TYPE_UVEC4:
- case TYPE_VEC4: {
-
- limit = 4;
-
- } break;
- case TYPE_MAT2: limit = 2; break;
- case TYPE_MAT3: limit = 3; break;
- case TYPE_MAT4: limit = 4; break;
- default: {
- }
- }
-
- for (int i = 0; i < limit; i++) {
- r_options->push_back(ScriptCodeCompletionOption(String::chr(colv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
- r_options->push_back(ScriptCodeCompletionOption(String::chr(coordv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
- r_options->push_back(ScriptCodeCompletionOption(String::chr(coordt[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
- }
-
- } break;
- }
-
- return ERR_PARSE_ERROR;
-}
-
-String ShaderLanguage::get_error_text() {
-
- return error_str;
-}
-
-int ShaderLanguage::get_error_line() {
-
- return error_line;
-}
-
-ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() {
-
- return shader;
-}
-
-ShaderLanguage::ShaderLanguage() {
-
- nodes = NULL;
- completion_class = TAG_GLOBAL;
-}
-
-ShaderLanguage::~ShaderLanguage() {
-
- clear();
-}
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
deleted file mode 100644
index 5a69a84650..0000000000
--- a/servers/visual/shader_language.h
+++ /dev/null
@@ -1,900 +0,0 @@
-/*************************************************************************/
-/* shader_language.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SHADER_LANGUAGE_H
-#define SHADER_LANGUAGE_H
-
-#include "core/list.h"
-#include "core/map.h"
-#include "core/script_language.h"
-#include "core/string_name.h"
-#include "core/typedefs.h"
-#include "core/ustring.h"
-#include "core/variant.h"
-
-class ShaderLanguage {
-
-public:
- enum TokenType {
- TK_EMPTY,
- TK_IDENTIFIER,
- TK_TRUE,
- TK_FALSE,
- TK_REAL_CONSTANT,
- TK_INT_CONSTANT,
- TK_TYPE_VOID,
- TK_TYPE_BOOL,
- TK_TYPE_BVEC2,
- TK_TYPE_BVEC3,
- TK_TYPE_BVEC4,
- TK_TYPE_INT,
- TK_TYPE_IVEC2,
- TK_TYPE_IVEC3,
- TK_TYPE_IVEC4,
- TK_TYPE_UINT,
- TK_TYPE_UVEC2,
- TK_TYPE_UVEC3,
- TK_TYPE_UVEC4,
- TK_TYPE_FLOAT,
- TK_TYPE_VEC2,
- TK_TYPE_VEC3,
- TK_TYPE_VEC4,
- TK_TYPE_MAT2,
- TK_TYPE_MAT3,
- TK_TYPE_MAT4,
- TK_TYPE_SAMPLER2D,
- TK_TYPE_ISAMPLER2D,
- TK_TYPE_USAMPLER2D,
- TK_TYPE_SAMPLER2DARRAY,
- TK_TYPE_ISAMPLER2DARRAY,
- TK_TYPE_USAMPLER2DARRAY,
- TK_TYPE_SAMPLER3D,
- TK_TYPE_ISAMPLER3D,
- TK_TYPE_USAMPLER3D,
- TK_TYPE_SAMPLERCUBE,
- TK_INTERPOLATION_FLAT,
- TK_INTERPOLATION_SMOOTH,
- TK_CONST,
- TK_STRUCT,
- TK_PRECISION_LOW,
- TK_PRECISION_MID,
- TK_PRECISION_HIGH,
- TK_OP_EQUAL,
- TK_OP_NOT_EQUAL,
- TK_OP_LESS,
- TK_OP_LESS_EQUAL,
- TK_OP_GREATER,
- TK_OP_GREATER_EQUAL,
- TK_OP_AND,
- TK_OP_OR,
- TK_OP_NOT,
- TK_OP_ADD,
- TK_OP_SUB,
- TK_OP_MUL,
- TK_OP_DIV,
- TK_OP_MOD,
- TK_OP_SHIFT_LEFT,
- TK_OP_SHIFT_RIGHT,
- TK_OP_ASSIGN,
- TK_OP_ASSIGN_ADD,
- TK_OP_ASSIGN_SUB,
- TK_OP_ASSIGN_MUL,
- TK_OP_ASSIGN_DIV,
- TK_OP_ASSIGN_MOD,
- TK_OP_ASSIGN_SHIFT_LEFT,
- TK_OP_ASSIGN_SHIFT_RIGHT,
- TK_OP_ASSIGN_BIT_AND,
- TK_OP_ASSIGN_BIT_OR,
- TK_OP_ASSIGN_BIT_XOR,
- TK_OP_BIT_AND,
- TK_OP_BIT_OR,
- TK_OP_BIT_XOR,
- TK_OP_BIT_INVERT,
- TK_OP_INCREMENT,
- TK_OP_DECREMENT,
- TK_CF_IF,
- TK_CF_ELSE,
- TK_CF_FOR,
- TK_CF_WHILE,
- TK_CF_DO,
- TK_CF_SWITCH,
- TK_CF_CASE,
- TK_CF_DEFAULT,
- TK_CF_BREAK,
- TK_CF_CONTINUE,
- TK_CF_RETURN,
- TK_CF_DISCARD,
- TK_BRACKET_OPEN,
- TK_BRACKET_CLOSE,
- TK_CURLY_BRACKET_OPEN,
- TK_CURLY_BRACKET_CLOSE,
- TK_PARENTHESIS_OPEN,
- TK_PARENTHESIS_CLOSE,
- TK_QUESTION,
- TK_COMMA,
- TK_COLON,
- TK_SEMICOLON,
- TK_PERIOD,
- TK_UNIFORM,
- TK_VARYING,
- TK_ARG_IN,
- TK_ARG_OUT,
- TK_ARG_INOUT,
- TK_RENDER_MODE,
- TK_HINT_WHITE_TEXTURE,
- TK_HINT_BLACK_TEXTURE,
- TK_HINT_NORMAL_TEXTURE,
- TK_HINT_ROUGHNESS_NORMAL_TEXTURE,
- TK_HINT_ROUGHNESS_R,
- TK_HINT_ROUGHNESS_G,
- TK_HINT_ROUGHNESS_B,
- TK_HINT_ROUGHNESS_A,
- TK_HINT_ROUGHNESS_GRAY,
- TK_HINT_ANISO_TEXTURE,
- TK_HINT_ALBEDO_TEXTURE,
- TK_HINT_BLACK_ALBEDO_TEXTURE,
- TK_HINT_COLOR,
- TK_HINT_RANGE,
- TK_FILTER_NEAREST,
- TK_FILTER_LINEAR,
- TK_FILTER_NEAREST_MIPMAP,
- TK_FILTER_LINEAR_MIPMAP,
- TK_FILTER_NEAREST_MIPMAP_ANISO,
- TK_FILTER_LINEAR_MIPMAP_ANISO,
- TK_REPEAT_ENABLE,
- TK_REPEAT_DISABLE,
- TK_SHADER_TYPE,
- TK_CURSOR,
- TK_ERROR,
- TK_EOF,
- TK_MAX
- };
-
-/* COMPILER */
-
-// lame work around to Apple defining this as a macro in 10.12 SDK
-#ifdef TYPE_BOOL
-#undef TYPE_BOOL
-#endif
-
- enum DataType {
- TYPE_VOID,
- TYPE_BOOL,
- TYPE_BVEC2,
- TYPE_BVEC3,
- TYPE_BVEC4,
- TYPE_INT,
- TYPE_IVEC2,
- TYPE_IVEC3,
- TYPE_IVEC4,
- TYPE_UINT,
- TYPE_UVEC2,
- TYPE_UVEC3,
- TYPE_UVEC4,
- TYPE_FLOAT,
- TYPE_VEC2,
- TYPE_VEC3,
- TYPE_VEC4,
- TYPE_MAT2,
- TYPE_MAT3,
- TYPE_MAT4,
- TYPE_SAMPLER2D,
- TYPE_ISAMPLER2D,
- TYPE_USAMPLER2D,
- TYPE_SAMPLER2DARRAY,
- TYPE_ISAMPLER2DARRAY,
- TYPE_USAMPLER2DARRAY,
- TYPE_SAMPLER3D,
- TYPE_ISAMPLER3D,
- TYPE_USAMPLER3D,
- TYPE_SAMPLERCUBE,
- TYPE_STRUCT,
- };
-
- enum DataPrecision {
- PRECISION_LOWP,
- PRECISION_MEDIUMP,
- PRECISION_HIGHP,
- PRECISION_DEFAULT,
- };
-
- enum DataInterpolation {
- INTERPOLATION_FLAT,
- INTERPOLATION_SMOOTH,
- };
-
- enum Operator {
- OP_EQUAL,
- OP_NOT_EQUAL,
- OP_LESS,
- OP_LESS_EQUAL,
- OP_GREATER,
- OP_GREATER_EQUAL,
- OP_AND,
- OP_OR,
- OP_NOT,
- OP_NEGATE,
- OP_ADD,
- OP_SUB,
- OP_MUL,
- OP_DIV,
- OP_MOD,
- OP_SHIFT_LEFT,
- OP_SHIFT_RIGHT,
- OP_ASSIGN,
- OP_ASSIGN_ADD,
- OP_ASSIGN_SUB,
- OP_ASSIGN_MUL,
- OP_ASSIGN_DIV,
- OP_ASSIGN_MOD,
- OP_ASSIGN_SHIFT_LEFT,
- OP_ASSIGN_SHIFT_RIGHT,
- OP_ASSIGN_BIT_AND,
- OP_ASSIGN_BIT_OR,
- OP_ASSIGN_BIT_XOR,
- OP_BIT_AND,
- OP_BIT_OR,
- OP_BIT_XOR,
- OP_BIT_INVERT,
- OP_INCREMENT,
- OP_DECREMENT,
- OP_SELECT_IF,
- OP_SELECT_ELSE, //used only internally, then only IF appears with 3 arguments
- OP_POST_INCREMENT,
- OP_POST_DECREMENT,
- OP_CALL,
- OP_CONSTRUCT,
- OP_STRUCT,
- OP_INDEX,
- OP_MAX
- };
-
- enum FlowOperation {
- FLOW_OP_IF,
- FLOW_OP_RETURN,
- FLOW_OP_FOR,
- FLOW_OP_WHILE,
- FLOW_OP_DO,
- FLOW_OP_BREAK,
- FLOW_OP_SWITCH,
- FLOW_OP_CASE,
- FLOW_OP_DEFAULT,
- FLOW_OP_CONTINUE,
- FLOW_OP_DISCARD
- };
-
- enum ArgumentQualifier {
- ARGUMENT_QUALIFIER_IN,
- ARGUMENT_QUALIFIER_OUT,
- ARGUMENT_QUALIFIER_INOUT,
- };
-
- enum SubClassTag {
- TAG_GLOBAL,
- TAG_ARRAY,
- };
-
- enum TextureFilter {
- FILTER_NEAREST,
- FILTER_LINEAR,
- FILTER_NEAREST_MIPMAP,
- FILTER_LINEAR_MIPMAP,
- FILTER_NEAREST_MIPMAP_ANISO,
- FILTER_LINEAR_MIPMAP_ANISO,
- FILTER_DEFAULT,
- };
-
- enum TextureRepeat {
- REPEAT_DISABLE,
- REPEAT_ENABLE,
- REPEAT_DEFAULT,
- };
-
- struct Node {
- Node *next;
-
- enum Type {
- TYPE_SHADER,
- TYPE_FUNCTION,
- TYPE_BLOCK,
- TYPE_VARIABLE,
- TYPE_VARIABLE_DECLARATION,
- TYPE_CONSTANT,
- TYPE_OPERATOR,
- TYPE_CONTROL_FLOW,
- TYPE_MEMBER,
- TYPE_ARRAY,
- TYPE_ARRAY_DECLARATION,
- TYPE_ARRAY_CONSTRUCT,
- TYPE_STRUCT,
- };
-
- Type type;
-
- virtual DataType get_datatype() const { return TYPE_VOID; }
- virtual String get_datatype_name() const { return ""; }
-
- Node(Type t) :
- next(NULL),
- type(t) {}
- virtual ~Node() {}
- };
-
- template <class T>
- T *alloc_node() {
- T *node = memnew(T);
- node->next = nodes;
- nodes = node;
- return node;
- }
-
- Node *nodes;
-
- struct OperatorNode : public Node {
- DataType return_cache;
- DataPrecision return_precision_cache;
- Operator op;
- StringName struct_name;
- Vector<Node *> arguments;
- virtual DataType get_datatype() const { return return_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
-
- OperatorNode() :
- Node(TYPE_OPERATOR),
- return_cache(TYPE_VOID),
- return_precision_cache(PRECISION_DEFAULT),
- op(OP_EQUAL),
- struct_name("") {}
- };
-
- struct VariableNode : public Node {
- DataType datatype_cache;
- StringName name;
- StringName struct_name;
- virtual DataType get_datatype() const { return datatype_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
- bool is_const;
-
- VariableNode() :
- Node(TYPE_VARIABLE),
- datatype_cache(TYPE_VOID),
- is_const(false) {}
- };
-
- struct VariableDeclarationNode : public Node {
- DataPrecision precision;
- DataType datatype;
- String struct_name;
- bool is_const;
-
- struct Declaration {
- StringName name;
- Node *initializer;
- };
-
- Vector<Declaration> declarations;
- virtual DataType get_datatype() const { return datatype; }
-
- VariableDeclarationNode() :
- Node(TYPE_VARIABLE_DECLARATION),
- precision(PRECISION_DEFAULT),
- datatype(TYPE_VOID),
- is_const(false) {}
- };
-
- struct ArrayNode : public Node {
- DataType datatype_cache;
- StringName struct_name;
- StringName name;
- Node *index_expression;
- Node *call_expression;
- bool is_const;
-
- virtual DataType get_datatype() const { return datatype_cache; }
- virtual String get_datatype_name() const { return String(struct_name); }
-
- ArrayNode() :
- Node(TYPE_ARRAY),
- datatype_cache(TYPE_VOID),
- index_expression(NULL),
- call_expression(NULL),
- is_const(false) {}
- };
-
- struct ArrayConstructNode : public Node {
- DataType datatype;
- String struct_name;
- Vector<Node *> initializer;
-
- ArrayConstructNode() :
- Node(TYPE_ARRAY_CONSTRUCT),
- datatype(TYPE_VOID) {
- }
- };
-
- struct ArrayDeclarationNode : public Node {
- DataPrecision precision;
- DataType datatype;
- String struct_name;
- bool is_const;
-
- struct Declaration {
- StringName name;
- uint32_t size;
- Vector<Node *> initializer;
- };
-
- Vector<Declaration> declarations;
- virtual DataType get_datatype() const { return datatype; }
-
- ArrayDeclarationNode() :
- Node(TYPE_ARRAY_DECLARATION),
- precision(PRECISION_DEFAULT),
- datatype(TYPE_VOID),
- is_const(false) {}
- };
-
- struct ConstantNode : public Node {
- DataType datatype;
-
- union Value {
- bool boolean;
- float real;
- int32_t sint;
- uint32_t uint;
- };
-
- Vector<Value> values;
- virtual DataType get_datatype() const { return datatype; }
-
- ConstantNode() :
- Node(TYPE_CONSTANT),
- datatype(TYPE_VOID) {}
- };
-
- struct FunctionNode;
-
- struct BlockNode : public Node {
- FunctionNode *parent_function;
- BlockNode *parent_block;
-
- enum BlockType {
- BLOCK_TYPE_STANDART,
- BLOCK_TYPE_SWITCH,
- BLOCK_TYPE_CASE,
- BLOCK_TYPE_DEFAULT,
- };
-
- int block_type;
- SubClassTag block_tag;
-
- struct Variable {
- DataType type;
- StringName struct_name;
- DataPrecision precision;
- int line; //for completion
- int array_size;
- bool is_const;
- };
-
- Map<StringName, Variable> variables;
- List<Node *> statements;
- bool single_statement;
-
- BlockNode() :
- Node(TYPE_BLOCK),
- parent_function(NULL),
- parent_block(NULL),
- block_type(BLOCK_TYPE_STANDART),
- block_tag(SubClassTag::TAG_GLOBAL),
- single_statement(false) {}
- };
-
- struct ControlFlowNode : public Node {
- FlowOperation flow_op;
- Vector<Node *> expressions;
- Vector<BlockNode *> blocks;
-
- ControlFlowNode() :
- Node(TYPE_CONTROL_FLOW),
- flow_op(FLOW_OP_IF) {}
- };
-
- struct MemberNode : public Node {
- DataType basetype;
- bool basetype_const;
- StringName base_struct_name;
- DataPrecision precision;
- DataType datatype;
- int array_size;
- StringName struct_name;
- StringName name;
- Node *owner;
- Node *index_expression;
- bool has_swizzling_duplicates;
-
- virtual DataType get_datatype() const { return datatype; }
- virtual String get_datatype_name() const { return String(struct_name); }
-
- MemberNode() :
- Node(TYPE_MEMBER),
- basetype(TYPE_VOID),
- basetype_const(false),
- datatype(TYPE_VOID),
- array_size(0),
- owner(NULL),
- index_expression(NULL),
- has_swizzling_duplicates(false) {}
- };
-
- struct StructNode : public Node {
-
- List<MemberNode *> members;
- StructNode() :
- Node(TYPE_STRUCT) {}
- };
-
- struct FunctionNode : public Node {
-
- struct Argument {
- ArgumentQualifier qualifier;
- StringName name;
- DataType type;
- StringName type_str;
- DataPrecision precision;
- //for passing textures as arguments
- bool tex_argument_check;
- TextureFilter tex_argument_filter;
- TextureRepeat tex_argument_repeat;
- bool tex_builtin_check;
- StringName tex_builtin;
-
- Map<StringName, Set<int> > tex_argument_connect;
- };
-
- StringName name;
- DataType return_type;
- StringName return_struct_name;
- DataPrecision return_precision;
- Vector<Argument> arguments;
- BlockNode *body;
- bool can_discard;
-
- FunctionNode() :
- Node(TYPE_FUNCTION),
- return_type(TYPE_VOID),
- return_precision(PRECISION_DEFAULT),
- body(NULL),
- can_discard(false) {}
- };
-
- struct ShaderNode : public Node {
-
- struct Constant {
- DataType type;
- StringName type_str;
- DataPrecision precision;
- ConstantNode *initializer;
- };
-
- struct Function {
- StringName name;
- FunctionNode *function;
- Set<StringName> uses_function;
- bool callable;
- };
-
- struct Struct {
- StringName name;
- StructNode *shader_struct;
- };
-
- struct Varying {
- DataType type;
- DataInterpolation interpolation;
- DataPrecision precision;
- int array_size;
-
- Varying() :
- type(TYPE_VOID),
- interpolation(INTERPOLATION_FLAT),
- precision(PRECISION_DEFAULT),
- array_size(0) {}
- };
-
- struct Uniform {
- enum Hint {
- HINT_NONE,
- HINT_COLOR,
- HINT_RANGE,
- HINT_ALBEDO,
- HINT_BLACK_ALBEDO,
- HINT_NORMAL,
- HINT_ROUGHNESS_NORMAL,
- HINT_ROUGHNESS_R,
- HINT_ROUGHNESS_G,
- HINT_ROUGHNESS_B,
- HINT_ROUGHNESS_A,
- HINT_ROUGHNESS_GRAY,
- HINT_BLACK,
- HINT_WHITE,
- HINT_ANISO,
- HINT_MAX
- };
-
- int order;
- int texture_order;
- DataType type;
- DataPrecision precision;
- Vector<ConstantNode::Value> default_value;
- Hint hint;
- TextureFilter filter;
- TextureRepeat repeat;
- float hint_range[3];
-
- Uniform() :
- order(0),
- texture_order(0),
- type(TYPE_VOID),
- precision(PRECISION_DEFAULT),
- hint(HINT_NONE),
- filter(FILTER_DEFAULT),
- repeat(REPEAT_DEFAULT) {
- hint_range[0] = 0.0f;
- hint_range[1] = 1.0f;
- hint_range[2] = 0.001f;
- }
- };
-
- Map<StringName, Constant> constants;
- Map<StringName, Varying> varyings;
- Map<StringName, Uniform> uniforms;
- Map<StringName, Struct> structs;
- Vector<StringName> render_modes;
-
- Vector<Function> functions;
- Vector<Struct> vstructs;
-
- ShaderNode() :
- Node(TYPE_SHADER) {}
- };
-
- struct Expression {
- bool is_op;
- union {
- Operator op;
- Node *node;
- };
- };
-
- struct VarInfo {
- StringName name;
- DataType type;
- };
-
- enum CompletionType {
- COMPLETION_NONE,
- COMPLETION_RENDER_MODE,
- COMPLETION_MAIN_FUNCTION,
- COMPLETION_IDENTIFIER,
- COMPLETION_FUNCTION_CALL,
- COMPLETION_CALL_ARGUMENTS,
- COMPLETION_INDEX,
- COMPLETION_STRUCT,
- };
-
- struct Token {
- TokenType type;
- StringName text;
- double constant;
- uint16_t line;
- };
-
- static String get_operator_text(Operator p_op);
- static String get_token_text(Token p_token);
-
- static bool is_token_datatype(TokenType p_type);
- static bool is_token_variable_datatype(TokenType p_type);
- static DataType get_token_datatype(TokenType p_type);
- static bool is_token_interpolation(TokenType p_type);
- static DataInterpolation get_token_interpolation(TokenType p_type);
- static bool is_token_precision(TokenType p_type);
- static DataPrecision get_token_precision(TokenType p_type);
- static String get_precision_name(DataPrecision p_type);
- static String get_datatype_name(DataType p_type);
- static bool is_token_nonvoid_datatype(TokenType p_type);
- static bool is_token_operator(TokenType p_type);
-
- static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = NULL);
- static DataType get_scalar_type(DataType p_type);
- static int get_cardinality(DataType p_type);
- static bool is_scalar_type(DataType p_type);
- static bool is_sampler_type(DataType p_type);
- static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
- static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
- static uint32_t get_type_size(DataType p_type);
-
- static void get_keyword_list(List<String> *r_keywords);
- static void get_builtin_funcs(List<String> *r_keywords);
-
- struct BuiltInInfo {
- DataType type;
- bool constant;
-
- BuiltInInfo() :
- type(TYPE_VOID),
- constant(false) {}
-
- BuiltInInfo(DataType p_type, bool p_constant = false) :
- type(p_type),
- constant(p_constant) {}
- };
-
- struct FunctionInfo {
- Map<StringName, BuiltInInfo> built_ins;
- bool can_discard;
- };
- static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
-
-private:
- struct KeyWord {
- TokenType token;
- const char *text;
- };
-
- static const KeyWord keyword_list[];
-
- bool error_set;
- String error_str;
- int error_line;
-
- String code;
- int char_idx;
- int tk_line;
-
- StringName current_function;
-
- struct TkPos {
- int char_idx;
- int tk_line;
- };
-
- TkPos _get_tkpos() {
- TkPos tkp;
- tkp.char_idx = char_idx;
- tkp.tk_line = tk_line;
- return tkp;
- }
-
- void _set_tkpos(TkPos p_pos) {
- char_idx = p_pos.char_idx;
- tk_line = p_pos.tk_line;
- }
-
- void _set_error(const String &p_str) {
- if (error_set)
- return;
-
- error_line = tk_line;
- error_set = true;
- error_str = p_str;
- }
-
- static const char *token_names[TK_MAX];
-
- Token _make_token(TokenType p_type, const StringName &p_text = StringName());
- Token _get_token();
-
- ShaderNode *shader;
-
- enum IdentifierType {
- IDENTIFIER_FUNCTION,
- IDENTIFIER_UNIFORM,
- IDENTIFIER_VARYING,
- IDENTIFIER_FUNCTION_ARGUMENT,
- IDENTIFIER_LOCAL_VAR,
- IDENTIFIER_BUILTIN_VAR,
- IDENTIFIER_CONSTANT,
- };
-
- bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = NULL, IdentifierType *r_type = NULL, bool *r_is_const = NULL, int *r_array_size = NULL, StringName *r_struct_name = NULL);
- bool _is_operator_assign(Operator p_op) const;
- bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = NULL);
- bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = NULL);
-
- struct BuiltinFuncDef {
- enum { MAX_ARGS = 5 };
- const char *name;
- DataType rettype;
- const DataType args[MAX_ARGS];
- SubClassTag tag;
- bool high_end;
- };
-
- struct BuiltinFuncOutArgs { //arguments used as out in built in functions
- const char *name;
- int argument;
- };
-
- CompletionType completion_type;
- int completion_line;
- BlockNode *completion_block;
- DataType completion_base;
- SubClassTag completion_class;
- StringName completion_function;
- StringName completion_struct;
- int completion_argument;
-
- bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier);
- static const BuiltinFuncDef builtin_func_defs[];
- static const BuiltinFuncOutArgs builtin_func_out_args[];
-
- Error _validate_datatype(DataType p_type);
- bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
-
- bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
- bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL);
- 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);
-
- Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
- ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
-
- Node *_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
- Error _parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
- String _get_shader_type_list(const Set<String> &p_shader_types) const;
- String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
-
- Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types);
-
- Error _find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op);
- Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op);
-
-public:
- //static void get_keyword_list(ShaderType p_type,List<String> *p_keywords);
-
- 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);
- Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint);
-
- String get_error_text();
- int get_error_line();
-
- ShaderNode *get_shader();
-
- String token_debug(const String &p_code);
-
- ShaderLanguage();
- ~ShaderLanguage();
-};
-
-#endif // SHADER_LANGUAGE_H
diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp
deleted file mode 100644
index 5cd5f0b7bb..0000000000
--- a/servers/visual/shader_types.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*************************************************************************/
-/* shader_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "shader_types.h"
-
-const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(VS::ShaderMode p_mode) {
-
- return shader_modes[p_mode].functions;
-}
-
-const Vector<StringName> &ShaderTypes::get_modes(VS::ShaderMode p_mode) {
-
- return shader_modes[p_mode].modes;
-}
-
-const Set<String> &ShaderTypes::get_types() {
- return shader_types;
-}
-
-ShaderTypes *ShaderTypes::singleton = NULL;
-
-static ShaderLanguage::BuiltInInfo constt(ShaderLanguage::DataType p_type) {
-
- return ShaderLanguage::BuiltInInfo(p_type, true);
-}
-
-ShaderTypes::ShaderTypes() {
- singleton = this;
-
- /*************** SPATIAL ***********************/
-
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["POSITION"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["UV2"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_ID"] = constt(ShaderLanguage::TYPE_INT);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
-
- //builtins
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["PROJECTION_MATRIX"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_MATRIX"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["MODELVIEW_NORMAL_MATRIX"] = ShaderLanguage::TYPE_MAT3;
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
-
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["FRONT_FACING"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["TANGENT"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["BINORMAL"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["METALLIC"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SPECULAR"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ROUGHNESS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["RIM"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["RIM_TINT"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["CLEARCOAT_GLOSS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["ANISOTROPY_FLOW"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["TRANSMISSION"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
-
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
-
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_NORMAL_MATRIX"] = constt(ShaderLanguage::TYPE_MAT3);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["fragment"].can_discard = true;
-
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["CAMERA_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["INV_PROJECTION_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
-
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["UV2"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["VIEW"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ATTENUATION"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALBEDO"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TRANSMISSION"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
-
- shader_modes[VS::SHADER_SPATIAL].functions["light"].can_discard = true;
-
- //order used puts first enum mode (default) first
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_mix");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_add");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_sub");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("blend_mul");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_opaque");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_always");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_draw_never");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_prepass_alpha");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("depth_test_disabled");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("cull_back");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("cull_front");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("cull_disabled");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("unshaded");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("wireframe");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_lambert");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_oren_nayar");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_burley");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("diffuse_toon");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("specular_schlick_ggx");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("specular_blinn");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("specular_phong");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("specular_toon");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("specular_disabled");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("skip_vertex_transform");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("world_vertex_coords");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("ensure_correct_normals");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("shadows_disabled");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("ambient_light_disabled");
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity");
-
- shader_modes[VS::SHADER_SPATIAL].modes.push_back("vertex_lighting");
-
- /************ CANVAS ITEM **************************/
-
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["UV"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["POINT_SIZE"] = ShaderLanguage::TYPE_FLOAT;
-
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["CANVAS_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["SCREEN_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
-
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["LIGHT_VERTEX"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["NORMAL_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
-
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SPECULAR_SHININESS"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT_VERTEX"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["LIGHT"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SHADOW_MODULATE"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
-
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform");
-
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("blend_mix");
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("blend_add");
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("blend_sub");
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("blend_mul");
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("blend_premul_alpha");
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("blend_disabled");
-
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("unshaded");
- shader_modes[VS::SHADER_CANVAS_ITEM].modes.push_back("light_only");
-
- /************ PARTICLES **************************/
-
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[VS::SHADER_PARTICLES].functions["vertex"].can_discard = false;
-
- shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_force");
- shader_modes[VS::SHADER_PARTICLES].modes.push_back("disable_velocity");
- shader_modes[VS::SHADER_PARTICLES].modes.push_back("keep_data");
-
- shader_types.insert("spatial");
- shader_types.insert("canvas_item");
- shader_types.insert("particles");
-}
diff --git a/servers/visual/shader_types.h b/servers/visual/shader_types.h
deleted file mode 100644
index 7d674bfb5c..0000000000
--- a/servers/visual/shader_types.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* shader_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 SHADERTYPES_H
-#define SHADERTYPES_H
-
-#include "core/ordered_hash_map.h"
-#include "servers/visual_server.h"
-#include "shader_language.h"
-
-class ShaderTypes {
-
- struct Type {
-
- Map<StringName, ShaderLanguage::FunctionInfo> functions;
- Vector<StringName> modes;
- };
-
- Map<VS::ShaderMode, Type> shader_modes;
-
- static ShaderTypes *singleton;
-
- Set<String> shader_types;
-
-public:
- static ShaderTypes *get_singleton() { return singleton; }
-
- const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(VS::ShaderMode p_mode);
- const Vector<StringName> &get_modes(VS::ShaderMode p_mode);
- const Set<String> &get_types();
-
- ShaderTypes();
-};
-
-#endif // SHADERTYPES_H
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
deleted file mode 100644
index c192b77988..0000000000
--- a/servers/visual/visual_server_canvas.cpp
+++ /dev/null
@@ -1,1479 +0,0 @@
-/*************************************************************************/
-/* visual_server_canvas.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_canvas.h"
-#include "visual_server_globals.h"
-#include "visual_server_raster.h"
-#include "visual_server_viewport.h"
-
-static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1;
-
-void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) {
-
- RENDER_TIMESTAMP("Cull CanvasItem Tree");
-
- memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
- memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
-
- for (int i = 0; i < p_child_item_count; i++) {
- _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL);
- }
- if (p_canvas_item) {
- _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL);
- }
-
- RasterizerCanvas::Item *list = NULL;
- RasterizerCanvas::Item *list_end = NULL;
-
- for (int i = 0; i < z_range; i++) {
- if (!z_list[i])
- continue;
- if (!list) {
- list = z_list[i];
- list_end = z_last_list[i];
- } else {
- list_end->next = z_list[i];
- list_end = z_last_list[i];
- }
- }
-
- RENDER_TIMESTAMP("Render Canvas Items");
-
- VSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform);
-}
-
-void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item *p_material_owner, VisualServerCanvas::Item **r_items, int &r_index) {
- int child_item_count = p_canvas_item->child_items.size();
- VisualServerCanvas::Item **child_items = p_canvas_item->child_items.ptrw();
- for (int i = 0; i < child_item_count; i++) {
- if (child_items[i]->visible) {
- if (r_items) {
- r_items[r_index] = child_items[i];
- child_items[i]->ysort_xform = p_transform;
- child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.elements[2]);
- child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : NULL;
- }
-
- r_index++;
-
- if (child_items[i]->sort_y)
- _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], r_items, r_index);
- }
- }
-}
-
-void _mark_ysort_dirty(VisualServerCanvas::Item *ysort_owner, RID_PtrOwner<VisualServerCanvas::Item> &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) : NULL;
- } while (ysort_owner && ysort_owner->sort_y);
-}
-
-void VisualServerCanvas::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) {
-
- Item *ci = p_canvas_item;
-
- if (!ci->visible)
- return;
-
- if (ci->children_order_dirty) {
-
- ci->child_items.sort_custom<ItemIndexSort>();
- ci->children_order_dirty = false;
- }
-
- Rect2 rect = ci->get_rect();
- Transform2D xform = p_transform * ci->xform;
- Rect2 global_rect = xform.xform(rect);
- global_rect.position += p_clip_rect.position;
-
- if (ci->use_parent_material && p_material_owner)
- ci->material_owner = p_material_owner;
- else {
- p_material_owner = ci;
- ci->material_owner = NULL;
- }
-
- Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a);
-
- if (modulate.a < 0.007)
- return;
-
- int child_item_count = ci->child_items.size();
- Item **child_items = ci->child_items.ptrw();
-
- if (ci->clip) {
- if (p_canvas_clip != NULL) {
- ci->final_clip_rect = p_canvas_clip->final_clip_rect.clip(global_rect);
- } else {
- ci->final_clip_rect = global_rect;
- }
- ci->final_clip_owner = ci;
-
- } else {
- ci->final_clip_owner = p_canvas_clip;
- }
-
- if (ci->sort_y) {
-
- if (ci->ysort_children_count == -1) {
- ci->ysort_children_count = 0;
- _collect_ysort_children(ci, Transform2D(), p_material_owner, NULL, ci->ysort_children_count);
- }
-
- child_item_count = ci->ysort_children_count;
- child_items = (Item **)alloca(child_item_count * sizeof(Item *));
-
- int i = 0;
- _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i);
-
- SortArray<Item *, ItemPtrSort> sorter;
- sorter.sort(child_items, child_item_count);
- }
-
- if (ci->z_relative)
- p_z = CLAMP(p_z + ci->z_index, VS::CANVAS_ITEM_Z_MIN, VS::CANVAS_ITEM_Z_MAX);
- else
- p_z = ci->z_index;
-
- for (int i = 0; i < child_item_count; i++) {
-
- if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y))
- continue;
- if (ci->sort_y) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
- } else {
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
- }
- }
-
- if (ci->copy_back_buffer) {
-
- ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);
- }
-
- if (ci->update_when_visible) {
- VisualServerRaster::redraw_request();
- }
-
- if ((ci->commands != NULL && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
- //something to draw?
- ci->final_transform = xform;
- ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
- ci->global_rect_cache = global_rect;
- ci->global_rect_cache.position -= p_clip_rect.position;
- ci->light_masked = false;
-
- int zidx = p_z - VS::CANVAS_ITEM_Z_MIN;
-
- if (z_last_list[zidx]) {
- z_last_list[zidx]->next = ci;
- z_last_list[zidx] = ci;
-
- } else {
- z_list[zidx] = ci;
- z_last_list[zidx] = ci;
- }
-
- ci->z_final = p_z;
-
- ci->next = NULL;
- }
-
- for (int i = 0; i < child_item_count; i++) {
-
- if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y))
- continue;
- if (ci->sort_y) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
- } else {
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
- }
- }
-}
-
-void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights) {
-
- if (!p_masked_lights)
- return;
-
- RasterizerCanvas::Item *ci = p_canvas_item;
-
- while (ci) {
-
- RasterizerCanvas::Light *light = p_masked_lights;
- while (light) {
-
- if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
- ci->light_masked = true;
- }
-
- light = light->mask_next_ptr;
- }
-
- ci = ci->next;
- }
-}
-
-void VisualServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) {
-
- RENDER_TIMESTAMP(">Render Canvas");
-
- if (p_canvas->children_order_dirty) {
-
- p_canvas->child_items.sort();
- p_canvas->children_order_dirty = false;
- }
-
- int l = p_canvas->child_items.size();
- Canvas::ChildItem *ci = p_canvas->child_items.ptrw();
-
- bool has_mirror = false;
- for (int i = 0; i < l; i++) {
- if (ci[i].mirror.x || ci[i].mirror.y) {
- has_mirror = true;
- break;
- }
- }
-
- if (!has_mirror) {
-
- _render_canvas_item_tree(p_render_target, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
-
- } else {
- //used for parallaxlayer mirroring
- for (int i = 0; i < l; i++) {
-
- const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
- _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
-
- //mirroring (useful for scrolling backgrounds)
- if (ci2.mirror.x != 0) {
-
- Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
- _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
- }
- if (ci2.mirror.y != 0) {
-
- Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
- _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
- }
- if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
-
- Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
- _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
- }
- }
- }
-
- RENDER_TIMESTAMP("<End Render Canvas");
-}
-
-RID VisualServerCanvas::canvas_create() {
-
- Canvas *canvas = memnew(Canvas);
- ERR_FAIL_COND_V(!canvas, RID());
- RID rid = canvas_owner.make_rid(canvas);
-
- return rid;
-}
-
-void VisualServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) {
-
- Canvas *canvas = canvas_owner.getornull(p_canvas);
- ERR_FAIL_COND(!canvas);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- int idx = canvas->find_item(canvas_item);
- ERR_FAIL_COND(idx == -1);
- canvas->child_items.write[idx].mirror = p_mirroring;
-}
-void VisualServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) {
-
- Canvas *canvas = canvas_owner.getornull(p_canvas);
- ERR_FAIL_COND(!canvas);
- canvas->modulate = p_color;
-}
-
-void VisualServerCanvas::canvas_set_disable_scale(bool p_disable) {
- disable_scale = p_disable;
-}
-
-void VisualServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) {
-
- Canvas *canvas = canvas_owner.getornull(p_canvas);
- ERR_FAIL_COND(!canvas);
-
- canvas->parent = p_parent;
- canvas->parent_scale = p_scale;
-}
-
-RID VisualServerCanvas::canvas_item_create() {
-
- Item *canvas_item = memnew(Item);
- ERR_FAIL_COND_V(!canvas_item, RID());
-
- return canvas_item_owner.make_rid(canvas_item);
-}
-
-void VisualServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- if (canvas_item->parent.is_valid()) {
-
- if (canvas_owner.owns(canvas_item->parent)) {
-
- Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
- canvas->erase_item(canvas_item);
- } else if (canvas_item_owner.owns(canvas_item->parent)) {
-
- Item *item_owner = canvas_item_owner.getornull(canvas_item->parent);
- item_owner->child_items.erase(canvas_item);
-
- if (item_owner->sort_y) {
- _mark_ysort_dirty(item_owner, canvas_item_owner);
- }
- }
-
- canvas_item->parent = RID();
- }
-
- if (p_parent.is_valid()) {
- if (canvas_owner.owns(p_parent)) {
-
- Canvas *canvas = canvas_owner.getornull(p_parent);
- Canvas::ChildItem ci;
- ci.item = canvas_item;
- canvas->child_items.push_back(ci);
- canvas->children_order_dirty = true;
- } else if (canvas_item_owner.owns(p_parent)) {
-
- Item *item_owner = canvas_item_owner.getornull(p_parent);
- item_owner->child_items.push_back(canvas_item);
- item_owner->children_order_dirty = true;
-
- if (item_owner->sort_y) {
- _mark_ysort_dirty(item_owner, canvas_item_owner);
- }
-
- } else {
-
- ERR_FAIL_MSG("Invalid parent.");
- }
- }
-
- canvas_item->parent = p_parent;
-}
-void VisualServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->visible = p_visible;
-
- _mark_ysort_dirty(canvas_item, canvas_item_owner);
-}
-void VisualServerCanvas::canvas_item_set_light_mask(RID p_item, int p_mask) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->light_mask = p_mask;
-}
-
-void VisualServerCanvas::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->xform = p_transform;
-}
-void VisualServerCanvas::canvas_item_set_clip(RID p_item, bool p_clip) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->clip = p_clip;
-}
-void VisualServerCanvas::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->distance_field = p_enable;
-}
-void VisualServerCanvas::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->custom_rect = p_custom_rect;
- canvas_item->rect = p_rect;
-}
-void VisualServerCanvas::canvas_item_set_modulate(RID p_item, const Color &p_color) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->modulate = p_color;
-}
-void VisualServerCanvas::canvas_item_set_self_modulate(RID p_item, const Color &p_color) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->self_modulate = p_color;
-}
-
-void VisualServerCanvas::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->behind = p_enable;
-}
-
-void VisualServerCanvas::canvas_item_set_update_when_visible(RID p_item, bool p_update) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->update_when_visible = p_update;
-}
-
-void VisualServerCanvas::canvas_item_set_default_texture_filter(RID p_item, VS::CanvasItemTextureFilter p_filter) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
- canvas_item->texture_filter = p_filter;
-}
-
-void VisualServerCanvas::canvas_item_set_default_texture_repeat(RID p_item, VS::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
- canvas_item->texture_repeat = p_repeat;
-}
-
-void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
- ERR_FAIL_COND(!line);
- if (p_width > 1.001) {
-
- Vector2 t = (p_from - p_to).tangent().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;
- line->point_count = 4;
- } else {
- line->point_count = 2;
- line->points[0] = p_from;
- line->points[1] = p_to;
- }
- for (uint32_t i = 0; i < line->point_count; i++) {
- line->colors[i] = p_color;
- }
- line->specular_shininess = Color(1, 1, 1, 1);
-}
-
-void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
-
- ERR_FAIL_COND(p_points.size() < 2);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
- ERR_FAIL_COND(!pline);
-
- pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
-
- if (true || p_width <= 1) {
-#define TODO make thick lines possible
- Vector<int> indices;
- int pc = p_points.size();
- indices.resize((pc - 1) * 2);
- {
- int *iptr = indices.ptrw();
- for (int i = 0; i < (pc - 1); i++) {
- iptr[i * 2 + 0] = i;
- iptr[i * 2 + 1] = i + 1;
- }
- }
-
- pline->primitive = VS::PRIMITIVE_LINES;
- pline->specular_shininess = Color(1, 1, 1, 1);
- pline->polygon.create(indices, p_points, p_colors);
- } else {
-#if 0
- //make a trianglestrip for drawing the line...
- Vector2 prev_t;
- pline->triangles.resize(p_points.size() * 2);
- if (p_antialiased) {
- pline->lines.resize(p_points.size() * 2);
- }
-
- if (p_colors.size() == 0) {
- pline->triangle_colors.push_back(Color(1, 1, 1, 1));
- if (p_antialiased) {
- pline->line_colors.push_back(Color(1, 1, 1, 1));
- }
- } else if (p_colors.size() == 1) {
- pline->triangle_colors = p_colors;
- pline->line_colors = p_colors;
- } else {
- if (p_colors.size() != p_points.size()) {
- pline->triangle_colors.push_back(p_colors[0]);
- pline->line_colors.push_back(p_colors[0]);
- } else {
- pline->triangle_colors.resize(pline->triangles.size());
- pline->line_colors.resize(pline->lines.size());
- }
- }
-
- for (int i = 0; i < p_points.size(); i++) {
-
- Vector2 t;
- if (i == p_points.size() - 1) {
- t = prev_t;
- } else {
- t = (p_points[i + 1] - p_points[i]).normalized().tangent();
- if (i == 0) {
- prev_t = t;
- }
- }
-
- Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
-
- if (p_antialiased) {
- pline->lines.write[i] = p_points[i] + tangent;
- pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent;
- if (pline->line_colors.size() > 1) {
- pline->line_colors.write[i] = p_colors[i];
- pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i];
- }
- }
-
- pline->triangles.write[i * 2 + 0] = p_points[i] + tangent;
- pline->triangles.write[i * 2 + 1] = p_points[i] - tangent;
-
- if (pline->triangle_colors.size() > 1) {
-
- pline->triangle_colors.write[i * 2 + 0] = p_colors[i];
- pline->triangle_colors.write[i * 2 + 1] = p_colors[i];
- }
-
- prev_t = t;
- }
-#endif
- }
-}
-
-void VisualServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
-
- ERR_FAIL_COND(p_points.size() < 2);
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
- ERR_FAIL_COND(!pline);
-
- pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
-
- if (true || p_width <= 1) {
-#define TODO make thick lines possible
-
- pline->primitive = VS::PRIMITIVE_LINES;
- pline->specular_shininess = Color(1, 1, 1, 1);
- pline->polygon.create(Vector<int>(), p_points, p_colors);
- } else {
- }
-}
-
-void VisualServerCanvas::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
- ERR_FAIL_COND(!rect);
- rect->modulate = p_color;
- rect->rect = p_rect;
-}
-
-void VisualServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>();
- ERR_FAIL_COND(!circle);
-
- circle->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
-
- circle->primitive = VS::PRIMITIVE_TRIANGLES;
- circle->specular_shininess = Color(1, 1, 1, 1);
-
- Vector<int> indices;
- Vector<Vector2> points;
-
- static const int circle_points = 64;
-
- points.resize(circle_points);
- for (int i = 0; i < circle_points; i++) {
- float angle = (i / float(circle_points)) * 2 * Math_PI;
- points.write[i].x = Math::cos(angle) * p_radius;
- points.write[i].y = Math::sin(angle) * p_radius;
- points.write[i] += p_pos;
- }
- indices.resize((circle_points - 2) * 3);
-
- for (int i = 0; i < circle_points - 2; i++) {
- indices.write[i * 3 + 0] = 0;
- indices.write[i * 3 + 1] = i + 1;
- indices.write[i * 3 + 2] = i + 2;
- }
-
- Vector<Color> color;
- color.push_back(p_color);
- circle->polygon.create(indices, points, color);
-}
-
-void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
- ERR_FAIL_COND(!rect);
- rect->modulate = p_modulate;
- rect->rect = p_rect;
- rect->flags = 0;
- if (p_tile) {
- rect->flags |= RasterizerCanvas::CANVAS_RECT_TILE;
- rect->flags |= RasterizerCanvas::CANVAS_RECT_REGION;
- rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height));
- }
-
- if (p_rect.size.x < 0) {
-
- rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H;
- rect->rect.size.x = -rect->rect.size.x;
- }
- if (p_rect.size.y < 0) {
-
- rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V;
- rect->rect.size.y = -rect->rect.size.y;
- }
- if (p_transpose) {
- rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE;
- SWAP(rect->rect.size.x, rect->rect.size.y);
- }
- rect->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- rect->specular_shininess = p_specular_color_shininess;
-}
-
-void VisualServerCanvas::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
- ERR_FAIL_COND(!rect);
- rect->modulate = p_modulate;
- rect->rect = p_rect;
- rect->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- rect->specular_shininess = p_specular_color_shininess;
- rect->source = p_src_rect;
- rect->flags = RasterizerCanvas::CANVAS_RECT_REGION;
-
- if (p_rect.size.x < 0) {
-
- rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_H;
- rect->rect.size.x = -rect->rect.size.x;
- }
- if (p_src_rect.size.x < 0) {
-
- rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_H;
- rect->source.size.x = -rect->source.size.x;
- }
- if (p_rect.size.y < 0) {
-
- rect->flags |= RasterizerCanvas::CANVAS_RECT_FLIP_V;
- rect->rect.size.y = -rect->rect.size.y;
- }
- if (p_src_rect.size.y < 0) {
-
- rect->flags ^= RasterizerCanvas::CANVAS_RECT_FLIP_V;
- rect->source.size.y = -rect->source.size.y;
- }
-
- if (p_transpose) {
- rect->flags |= RasterizerCanvas::CANVAS_RECT_TRANSPOSE;
- SWAP(rect->rect.size.x, rect->rect.size.y);
- }
-
- if (p_clip_uv) {
- rect->flags |= RasterizerCanvas::CANVAS_RECT_CLIP_UV;
- }
-}
-
-void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode, VS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandNinePatch *style = canvas_item->alloc_command<Item::CommandNinePatch>();
- ERR_FAIL_COND(!style);
- style->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- style->specular_shininess = p_specular_color_shininess;
- style->rect = p_rect;
- style->source = p_source;
- style->draw_center = p_draw_center;
- style->color = p_modulate;
- style->margin[MARGIN_LEFT] = p_topleft.x;
- style->margin[MARGIN_TOP] = p_topleft.y;
- style->margin[MARGIN_RIGHT] = p_bottomright.x;
- style->margin[MARGIN_BOTTOM] = p_bottomright.y;
- style->axis_x = p_x_axis_mode;
- style->axis_y = p_y_axis_mode;
-}
-void VisualServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- uint32_t pc = p_points.size();
- ERR_FAIL_COND(pc == 0 || pc > 4);
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandPrimitive *prim = canvas_item->alloc_command<Item::CommandPrimitive>();
- ERR_FAIL_COND(!prim);
-
- for (int i = 0; i < p_points.size(); i++) {
- prim->points[i] = p_points[i];
- if (i < p_uvs.size()) {
- prim->uvs[i] = p_uvs[i];
- }
- if (i < p_colors.size()) {
- prim->colors[i] = p_colors[i];
- } else if (p_colors.size()) {
- prim->colors[i] = p_colors[0];
- } else {
- prim->colors[i] = Color(1, 1, 1, 1);
- }
- }
-
- prim->point_count = p_points.size();
-
- prim->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- prim->specular_shininess = p_specular_color_shininess;
-}
-
-void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-#ifdef DEBUG_ENABLED
- int pointcount = p_points.size();
- ERR_FAIL_COND(pointcount < 3);
- int color_size = p_colors.size();
- int uv_size = p_uvs.size();
- ERR_FAIL_COND(color_size != 0 && color_size != 1 && color_size != pointcount);
- ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount));
-#endif
- Vector<int> indices = Geometry::triangulate_polygon(p_points);
- ERR_FAIL_COND_MSG(indices.empty(), "Invalid polygon data, triangulation failed.");
-
- Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
- ERR_FAIL_COND(!polygon);
- polygon->primitive = VS::PRIMITIVE_TRIANGLES;
- polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- polygon->specular_shininess = p_specular_color_shininess;
- polygon->polygon.create(indices, p_points, p_colors, p_uvs);
-}
-
-void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- int vertex_count = p_points.size();
- ERR_FAIL_COND(vertex_count == 0);
- ERR_FAIL_COND(!p_colors.empty() && p_colors.size() != vertex_count && p_colors.size() != 1);
- ERR_FAIL_COND(!p_uvs.empty() && p_uvs.size() != vertex_count);
- ERR_FAIL_COND(!p_bones.empty() && p_bones.size() != vertex_count * 4);
- ERR_FAIL_COND(!p_weights.empty() && p_weights.size() != vertex_count * 4);
-
- Vector<int> indices = p_indices;
-
- Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
- ERR_FAIL_COND(!polygon);
- polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- polygon->specular_shininess = p_specular_color_shininess;
- polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights);
-
- polygon->primitive = VS::PRIMITIVE_TRIANGLES;
-}
-
-void VisualServerCanvas::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandTransform *tr = canvas_item->alloc_command<Item::CommandTransform>();
- ERR_FAIL_COND(!tr);
- tr->xform = p_transform;
-}
-
-void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>();
- ERR_FAIL_COND(!m);
- m->mesh = p_mesh;
- m->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- m->specular_shininess = p_specular_color_shininess;
- m->transform = p_transform;
- m->modulate = p_modulate;
-}
-void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandParticles *part = canvas_item->alloc_command<Item::CommandParticles>();
- ERR_FAIL_COND(!part);
- part->particles = p_particles;
- part->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
- part->specular_shininess = p_specular_color_shininess;
-
- //take the chance and request processing for them, at least once until they become visible again
- VSG::storage->particles_request_process(p_particles);
-}
-
-void VisualServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandMultiMesh *mm = canvas_item->alloc_command<Item::CommandMultiMesh>();
- ERR_FAIL_COND(!mm);
- mm->multimesh = p_mesh;
- mm->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, mm->multimesh);
- mm->specular_shininess = p_specular_color_shininess;
-}
-
-void VisualServerCanvas::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- Item::CommandClipIgnore *ci = canvas_item->alloc_command<Item::CommandClipIgnore>();
- ERR_FAIL_COND(!ci);
- ci->ignore = p_ignore;
-}
-void VisualServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->sort_y = p_enable;
-
- _mark_ysort_dirty(canvas_item, canvas_item_owner);
-}
-void VisualServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) {
-
- ERR_FAIL_COND(p_z < VS::CANVAS_ITEM_Z_MIN || p_z > VS::CANVAS_ITEM_Z_MAX);
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->z_index = p_z;
-}
-void VisualServerCanvas::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->z_relative = p_enable;
-}
-
-void VisualServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->skeleton = p_skeleton;
-}
-
-void VisualServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
- if (bool(canvas_item->copy_back_buffer != NULL) != p_enable) {
- if (p_enable) {
- canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer);
- } else {
- memdelete(canvas_item->copy_back_buffer);
- canvas_item->copy_back_buffer = NULL;
- }
- }
-
- if (p_enable) {
- canvas_item->copy_back_buffer->rect = p_rect;
- canvas_item->copy_back_buffer->full = p_rect == Rect2();
- }
-}
-
-void VisualServerCanvas::canvas_item_clear(RID p_item) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->clear();
-}
-void VisualServerCanvas::canvas_item_set_draw_index(RID p_item, int p_index) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->index = p_index;
-
- if (canvas_item_owner.owns(canvas_item->parent)) {
- Item *canvas_item_parent = canvas_item_owner.getornull(canvas_item->parent);
- canvas_item_parent->children_order_dirty = true;
- return;
- }
-
- Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
- if (canvas) {
- canvas->children_order_dirty = true;
- return;
- }
-}
-
-void VisualServerCanvas::canvas_item_set_material(RID p_item, RID p_material) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->material = p_material;
-}
-
-void VisualServerCanvas::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_item);
- ERR_FAIL_COND(!canvas_item);
-
- canvas_item->use_parent_material = p_enable;
-}
-
-RID VisualServerCanvas::canvas_light_create() {
-
- RasterizerCanvas::Light *clight = memnew(RasterizerCanvas::Light);
- clight->light_internal = VSG::canvas_render->light_create();
- return canvas_light_owner.make_rid(clight);
-}
-void VisualServerCanvas::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- if (clight->canvas.is_valid()) {
-
- Canvas *canvas = canvas_owner.getornull(clight->canvas);
- canvas->lights.erase(clight);
- }
-
- if (!canvas_owner.owns(p_canvas))
- p_canvas = RID();
-
- clight->canvas = p_canvas;
-
- if (clight->canvas.is_valid()) {
-
- Canvas *canvas = canvas_owner.getornull(clight->canvas);
- canvas->lights.insert(clight);
- }
-}
-
-void VisualServerCanvas::canvas_light_set_enabled(RID p_light, bool p_enabled) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->enabled = p_enabled;
-}
-void VisualServerCanvas::canvas_light_set_scale(RID p_light, float p_scale) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->scale = p_scale;
-}
-void VisualServerCanvas::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->xform = p_transform;
-}
-void VisualServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->texture = p_texture;
- clight->version++;
- VSG::canvas_render->light_set_texture(clight->light_internal, p_texture);
-}
-void VisualServerCanvas::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->texture_offset = p_offset;
-}
-void VisualServerCanvas::canvas_light_set_color(RID p_light, const Color &p_color) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->color = p_color;
-}
-void VisualServerCanvas::canvas_light_set_height(RID p_light, float p_height) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->height = p_height;
-}
-void VisualServerCanvas::canvas_light_set_energy(RID p_light, float p_energy) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->energy = p_energy;
-}
-void VisualServerCanvas::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->z_min = p_min_z;
- clight->z_max = p_max_z;
-}
-void VisualServerCanvas::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->layer_max = p_max_layer;
- clight->layer_min = p_min_layer;
-}
-void VisualServerCanvas::canvas_light_set_item_cull_mask(RID p_light, int p_mask) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->item_mask = p_mask;
-}
-void VisualServerCanvas::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->item_shadow_mask = p_mask;
-}
-void VisualServerCanvas::canvas_light_set_mode(RID p_light, VS::CanvasLightMode p_mode) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->mode = p_mode;
-}
-
-void VisualServerCanvas::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- if (clight->use_shadow == p_enabled) {
- return;
- }
- clight->use_shadow = p_enabled;
- clight->version++;
- VSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow, clight->shadow_buffer_size);
-}
-
-void VisualServerCanvas::canvas_light_set_shadow_buffer_size(RID p_light, int p_size) {
-
- ERR_FAIL_COND(p_size < 32 || p_size > 16384);
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- int new_size = next_power_of_2(p_size);
- if (new_size == clight->shadow_buffer_size)
- return;
-
- clight->shadow_buffer_size = next_power_of_2(p_size);
- clight->version++;
-
- VSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow, clight->shadow_buffer_size);
-}
-
-void VisualServerCanvas::canvas_light_set_shadow_filter(RID p_light, VS::CanvasLightShadowFilter p_filter) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->shadow_filter = p_filter;
-}
-void VisualServerCanvas::canvas_light_set_shadow_color(RID p_light, const Color &p_color) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
-
- clight->shadow_color = p_color;
-}
-
-void VisualServerCanvas::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) {
-
- RasterizerCanvas::Light *clight = canvas_light_owner.getornull(p_light);
- ERR_FAIL_COND(!clight);
- clight->shadow_smooth = p_smooth;
-}
-
-RID VisualServerCanvas::canvas_light_occluder_create() {
-
- RasterizerCanvas::LightOccluderInstance *occluder = memnew(RasterizerCanvas::LightOccluderInstance);
-
- return canvas_light_occluder_owner.make_rid(occluder);
-}
-void VisualServerCanvas::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) {
-
- RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
- ERR_FAIL_COND(!occluder);
-
- if (occluder->canvas.is_valid()) {
-
- Canvas *canvas = canvas_owner.getornull(occluder->canvas);
- canvas->occluders.erase(occluder);
- }
-
- if (!canvas_owner.owns(p_canvas))
- p_canvas = RID();
-
- occluder->canvas = p_canvas;
-
- if (occluder->canvas.is_valid()) {
-
- Canvas *canvas = canvas_owner.getornull(occluder->canvas);
- canvas->occluders.insert(occluder);
- }
-}
-void VisualServerCanvas::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) {
-
- RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
- ERR_FAIL_COND(!occluder);
-
- occluder->enabled = p_enabled;
-}
-void VisualServerCanvas::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) {
-
- RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
- ERR_FAIL_COND(!occluder);
-
- if (occluder->polygon.is_valid()) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
- if (occluder_poly) {
- occluder_poly->owners.erase(occluder);
- }
- }
-
- occluder->polygon = p_polygon;
- occluder->occluder = RID();
-
- if (occluder->polygon.is_valid()) {
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon);
- if (!occluder_poly) {
- occluder->polygon = RID();
- ERR_FAIL_COND(!occluder_poly);
- } else {
- occluder_poly->owners.insert(occluder);
- occluder->occluder = occluder_poly->occluder;
- occluder->aabb_cache = occluder_poly->aabb;
- occluder->cull_cache = occluder_poly->cull_mode;
- }
- }
-}
-void VisualServerCanvas::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
-
- RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
- ERR_FAIL_COND(!occluder);
-
- occluder->xform = p_xform;
-}
-void VisualServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
-
- RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder);
- ERR_FAIL_COND(!occluder);
-
- occluder->light_mask = p_mask;
-}
-
-RID VisualServerCanvas::canvas_occluder_polygon_create() {
-
- LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon);
- occluder_poly->occluder = VSG::canvas_render->occluder_polygon_create();
- return canvas_light_occluder_polygon_owner.make_rid(occluder_poly);
-}
-void VisualServerCanvas::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
-
- if (p_shape.size() < 3) {
- canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, p_shape);
- return;
- }
-
- Vector<Vector2> lines;
- int lc = p_shape.size() * 2;
-
- lines.resize(lc - (p_closed ? 0 : 2));
- {
- Vector2 *w = lines.ptrw();
- const Vector2 *r = p_shape.ptr();
-
- int max = lc / 2;
- if (!p_closed) {
- max--;
- }
- for (int i = 0; i < max; i++) {
-
- Vector2 a = r[i];
- Vector2 b = r[(i + 1) % (lc / 2)];
- w[i * 2 + 0] = a;
- w[i * 2 + 1] = b;
- }
- }
-
- canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon, lines);
-}
-void VisualServerCanvas::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) {
-
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
- ERR_FAIL_COND(!occluder_poly);
- ERR_FAIL_COND(p_shape.size() & 1);
-
- int lc = p_shape.size();
- occluder_poly->aabb = Rect2();
- {
- const Vector2 *r = p_shape.ptr();
- for (int i = 0; i < lc; i++) {
- if (i == 0)
- occluder_poly->aabb.position = r[i];
- else
- occluder_poly->aabb.expand_to(r[i]);
- }
- }
-
- VSG::canvas_render->occluder_polygon_set_shape_as_lines(occluder_poly->occluder, p_shape);
- for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
- E->get()->aabb_cache = occluder_poly->aabb;
- }
-}
-
-void VisualServerCanvas::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, VS::CanvasOccluderPolygonCullMode p_mode) {
-
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon);
- ERR_FAIL_COND(!occluder_poly);
- occluder_poly->cull_mode = p_mode;
- VSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode);
- for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = occluder_poly->owners.front(); E; E = E->next()) {
- E->get()->cull_cache = p_mode;
- }
-}
-
-bool VisualServerCanvas::free(RID p_rid) {
-
- if (canvas_owner.owns(p_rid)) {
-
- Canvas *canvas = canvas_owner.getornull(p_rid);
- ERR_FAIL_COND_V(!canvas, false);
-
- while (canvas->viewports.size()) {
-
- VisualServerViewport::Viewport *vp = VSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get());
- ERR_FAIL_COND_V(!vp, true);
-
- Map<RID, VisualServerViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid);
- ERR_FAIL_COND_V(!E, true);
- vp->canvas_map.erase(p_rid);
-
- canvas->viewports.erase(canvas->viewports.front());
- }
-
- for (int i = 0; i < canvas->child_items.size(); i++) {
-
- canvas->child_items[i].item->parent = RID();
- }
-
- for (Set<RasterizerCanvas::Light *>::Element *E = canvas->lights.front(); E; E = E->next()) {
-
- E->get()->canvas = RID();
- }
-
- for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *E = canvas->occluders.front(); E; E = E->next()) {
-
- E->get()->canvas = RID();
- }
-
- canvas_owner.free(p_rid);
-
- memdelete(canvas);
-
- } else if (canvas_item_owner.owns(p_rid)) {
-
- Item *canvas_item = canvas_item_owner.getornull(p_rid);
- ERR_FAIL_COND_V(!canvas_item, true);
-
- if (canvas_item->parent.is_valid()) {
-
- if (canvas_owner.owns(canvas_item->parent)) {
-
- Canvas *canvas = canvas_owner.getornull(canvas_item->parent);
- canvas->erase_item(canvas_item);
- } else if (canvas_item_owner.owns(canvas_item->parent)) {
-
- Item *item_owner = canvas_item_owner.getornull(canvas_item->parent);
- item_owner->child_items.erase(canvas_item);
-
- if (item_owner->sort_y) {
- _mark_ysort_dirty(item_owner, canvas_item_owner);
- }
- }
- }
-
- for (int i = 0; i < canvas_item->child_items.size(); i++) {
-
- canvas_item->child_items[i]->parent = RID();
- }
-
- /*
- if (canvas_item->material) {
- canvas_item->material->owners.erase(canvas_item);
- }
- */
-
- canvas_item_owner.free(p_rid);
-
- memdelete(canvas_item);
-
- } else if (canvas_light_owner.owns(p_rid)) {
-
- RasterizerCanvas::Light *canvas_light = canvas_light_owner.getornull(p_rid);
- ERR_FAIL_COND_V(!canvas_light, true);
-
- if (canvas_light->canvas.is_valid()) {
- Canvas *canvas = canvas_owner.getornull(canvas_light->canvas);
- if (canvas)
- canvas->lights.erase(canvas_light);
- }
-
- VSG::canvas_render->free(canvas_light->light_internal);
-
- canvas_light_owner.free(p_rid);
- memdelete(canvas_light);
-
- } else if (canvas_light_occluder_owner.owns(p_rid)) {
-
- RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid);
- ERR_FAIL_COND_V(!occluder, true);
-
- if (occluder->polygon.is_valid()) {
-
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(occluder->polygon);
- if (occluder_poly) {
- occluder_poly->owners.erase(occluder);
- }
- }
-
- if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) {
-
- Canvas *canvas = canvas_owner.getornull(occluder->canvas);
- canvas->occluders.erase(occluder);
- }
-
- canvas_light_occluder_owner.free(p_rid);
- memdelete(occluder);
-
- } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
-
- LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid);
- ERR_FAIL_COND_V(!occluder_poly, true);
- VSG::canvas_render->free(occluder_poly->occluder);
-
- while (occluder_poly->owners.size()) {
-
- occluder_poly->owners.front()->get()->polygon = RID();
- occluder_poly->owners.erase(occluder_poly->owners.front());
- }
-
- canvas_light_occluder_polygon_owner.free(p_rid);
- memdelete(occluder_poly);
- } else {
- return false;
- }
-
- return true;
-}
-
-VisualServerCanvas::VisualServerCanvas() {
-
- z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
- z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
-
- disable_scale = false;
-}
-
-VisualServerCanvas::~VisualServerCanvas() {
-
- memfree(z_list);
- memfree(z_last_list);
-}
diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h
deleted file mode 100644
index dea4183752..0000000000
--- a/servers/visual/visual_server_canvas.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*************************************************************************/
-/* visual_server_canvas.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUALSERVERCANVAS_H
-#define VISUALSERVERCANVAS_H
-
-#include "rasterizer.h"
-#include "visual_server_viewport.h"
-
-class VisualServerCanvas {
-public:
- struct Item : public RasterizerCanvas::Item {
-
- RID parent; // canvas it belongs to
- List<Item *>::Element *E;
- int z_index;
- bool z_relative;
- bool sort_y;
- Color modulate;
- Color self_modulate;
- bool use_parent_material;
- int index;
- bool children_order_dirty;
- int ysort_children_count;
- Color ysort_modulate;
- Transform2D ysort_xform;
- Vector2 ysort_pos;
- VS::CanvasItemTextureFilter texture_filter;
- VS::CanvasItemTextureRepeat texture_repeat;
-
- Vector<Item *> child_items;
-
- Item() {
- children_order_dirty = true;
- E = NULL;
- z_index = 0;
- modulate = Color(1, 1, 1, 1);
- self_modulate = Color(1, 1, 1, 1);
- sort_y = false;
- use_parent_material = false;
- z_relative = true;
- index = 0;
- ysort_children_count = -1;
- ysort_xform = Transform2D();
- ysort_pos = Vector2();
- texture_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
- texture_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
- }
- };
-
- struct ItemIndexSort {
-
- _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
-
- return p_left->index < p_right->index;
- }
- };
-
- struct ItemPtrSort {
-
- _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
-
- if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y))
- return p_left->ysort_pos.x < p_right->ysort_pos.x;
-
- return p_left->ysort_pos.y < p_right->ysort_pos.y;
- }
- };
-
- struct LightOccluderPolygon {
-
- bool active;
- Rect2 aabb;
- VS::CanvasOccluderPolygonCullMode cull_mode;
- RID occluder;
- Set<RasterizerCanvas::LightOccluderInstance *> owners;
-
- LightOccluderPolygon() {
- active = false;
- cull_mode = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
- }
- };
-
- RID_PtrOwner<LightOccluderPolygon> canvas_light_occluder_polygon_owner;
-
- RID_PtrOwner<RasterizerCanvas::LightOccluderInstance> canvas_light_occluder_owner;
-
- struct Canvas : public VisualServerViewport::CanvasBase {
-
- Set<RID> viewports;
- struct ChildItem {
-
- Point2 mirror;
- Item *item;
- bool operator<(const ChildItem &p_item) const {
- return item->index < p_item.item->index;
- }
- };
-
- Set<RasterizerCanvas::Light *> lights;
-
- Set<RasterizerCanvas::LightOccluderInstance *> occluders;
-
- bool children_order_dirty;
- Vector<ChildItem> child_items;
- Color modulate;
- RID parent;
- float parent_scale;
-
- int find_item(Item *p_item) {
- for (int i = 0; i < child_items.size(); i++) {
- if (child_items[i].item == p_item)
- return i;
- }
- return -1;
- }
- void erase_item(Item *p_item) {
- int idx = find_item(p_item);
- if (idx >= 0)
- child_items.remove(idx);
- }
-
- Canvas() {
- modulate = Color(1, 1, 1, 1);
- children_order_dirty = true;
- parent_scale = 1.0;
- }
- };
-
- mutable RID_PtrOwner<Canvas> canvas_owner;
- RID_PtrOwner<Item> canvas_item_owner;
- RID_PtrOwner<RasterizerCanvas::Light> canvas_light_owner;
-
- bool disable_scale;
-
-private:
- void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights);
- void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
- void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights);
-
- RasterizerCanvas::Item **z_list;
- RasterizerCanvas::Item **z_last_list;
-
-public:
- void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect);
-
- RID canvas_create();
- 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();
- void canvas_item_set_parent(RID p_item, RID p_parent);
-
- void canvas_item_set_visible(RID p_item, bool p_visible);
- void canvas_item_set_light_mask(RID p_item, int p_mask);
-
- void canvas_item_set_transform(RID p_item, const Transform2D &p_transform);
- void canvas_item_set_clip(RID p_item, bool p_clip);
- void canvas_item_set_distance_field_mode(RID p_item, bool p_enable);
- void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2());
- void canvas_item_set_modulate(RID p_item, const Color &p_color);
- void canvas_item_set_self_modulate(RID p_item, const Color &p_color);
-
- void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable);
-
- void canvas_item_set_update_when_visible(RID p_item, bool p_update);
-
- void canvas_item_set_default_texture_filter(RID p_item, VS::CanvasItemTextureFilter p_filter);
- void canvas_item_set_default_texture_repeat(RID p_item, VS::CanvasItemTextureRepeat p_repeat);
-
- void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
- void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
- void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
- void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_clip_uv = false, VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, VS::NinePatchAxisMode p_x_axis_mode = VS::NINE_PATCH_STRETCH, VS::NinePatchAxisMode p_y_axis_mode = VS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), VS::CanvasItemTextureFilter p_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CanvasItemTextureRepeat p_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
- void canvas_item_add_clip_ignore(RID p_item, bool p_ignore);
- void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable);
- void canvas_item_set_z_index(RID p_item, int p_z);
- void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable);
- void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect);
- void canvas_item_attach_skeleton(RID p_item, RID p_skeleton);
-
- void canvas_item_clear(RID p_item);
- void canvas_item_set_draw_index(RID p_item, int p_index);
-
- void canvas_item_set_material(RID p_item, RID p_material);
-
- void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
-
- RID canvas_light_create();
- void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
- void canvas_light_set_enabled(RID p_light, bool p_enabled);
- void canvas_light_set_scale(RID p_light, float p_scale);
- void canvas_light_set_transform(RID p_light, const Transform2D &p_transform);
- void canvas_light_set_texture(RID p_light, RID p_texture);
- void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset);
- void canvas_light_set_color(RID p_light, const Color &p_color);
- void canvas_light_set_height(RID p_light, float p_height);
- void canvas_light_set_energy(RID p_light, float p_energy);
- void canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z);
- void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer);
- void canvas_light_set_item_cull_mask(RID p_light, int p_mask);
- void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask);
-
- void canvas_light_set_mode(RID p_light, VS::CanvasLightMode p_mode);
-
- void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
- void canvas_light_set_shadow_buffer_size(RID p_light, int p_size);
- void canvas_light_set_shadow_filter(RID p_light, VS::CanvasLightShadowFilter p_filter);
- 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();
- 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);
- 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();
- void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed);
- void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape);
-
- void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, VS::CanvasOccluderPolygonCullMode p_mode);
-
- bool free(RID p_rid);
- VisualServerCanvas();
- ~VisualServerCanvas();
-};
-
-#endif // VISUALSERVERCANVAS_H
diff --git a/servers/visual/visual_server_globals.cpp b/servers/visual/visual_server_globals.cpp
deleted file mode 100644
index 248d27e08a..0000000000
--- a/servers/visual/visual_server_globals.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*************************************************************************/
-/* visual_server_globals.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_globals.h"
-
-RasterizerStorage *VisualServerGlobals::storage = NULL;
-RasterizerCanvas *VisualServerGlobals::canvas_render = NULL;
-RasterizerScene *VisualServerGlobals::scene_render = NULL;
-Rasterizer *VisualServerGlobals::rasterizer = NULL;
-
-VisualServerCanvas *VisualServerGlobals::canvas = NULL;
-VisualServerViewport *VisualServerGlobals::viewport = NULL;
-VisualServerScene *VisualServerGlobals::scene = NULL;
diff --git a/servers/visual/visual_server_globals.h b/servers/visual/visual_server_globals.h
deleted file mode 100644
index 5a9d365eca..0000000000
--- a/servers/visual/visual_server_globals.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*************************************************************************/
-/* visual_server_globals.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUAL_SERVER_GLOBALS_H
-#define VISUAL_SERVER_GLOBALS_H
-
-#include "rasterizer.h"
-
-class VisualServerCanvas;
-class VisualServerViewport;
-class VisualServerScene;
-
-class VisualServerGlobals {
-public:
- static RasterizerStorage *storage;
- static RasterizerCanvas *canvas_render;
- static RasterizerScene *scene_render;
- static Rasterizer *rasterizer;
-
- static VisualServerCanvas *canvas;
- static VisualServerViewport *viewport;
- static VisualServerScene *scene;
-};
-
-#define VSG VisualServerGlobals
-
-#endif // VISUAL_SERVER_GLOBALS_H
diff --git a/servers/visual/visual_server_light_baker.cpp b/servers/visual/visual_server_light_baker.cpp
deleted file mode 100644
index 4f9ade5017..0000000000
--- a/servers/visual/visual_server_light_baker.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*************************************************************************/
-/* visual_server_light_baker.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_light_baker.h"
-
-VisualServerLightBaker::VisualServerLightBaker() {
-}
diff --git a/servers/visual/visual_server_light_baker.h b/servers/visual/visual_server_light_baker.h
deleted file mode 100644
index d88090c473..0000000000
--- a/servers/visual/visual_server_light_baker.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* visual_server_light_baker.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUALSERVERLIGHTBAKER_H
-#define VISUALSERVERLIGHTBAKER_H
-
-#include "servers/visual_server.h"
-
-class VisualServerLightBaker {
-public:
- struct BakeCell {
-
- uint32_t cells[8];
- uint32_t neighbours[7]; //one unused
- uint32_t albedo; //albedo in RGBE
- uint32_t emission; //emissive light in RGBE
- uint32_t light[4]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
- float alpha; //used for upsampling
- uint32_t directional_pass; //used for baking directional
- };
-
- VisualServerLightBaker();
-};
-
-#endif // VISUALSERVERLIGHTBAKER_H
diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp
deleted file mode 100644
index 35ec52a5c0..0000000000
--- a/servers/visual/visual_server_raster.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/*************************************************************************/
-/* visual_server_raster.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_raster.h"
-
-#include "core/io/marshalls.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-#include "core/sort_array.h"
-#include "visual_server_canvas.h"
-#include "visual_server_globals.h"
-#include "visual_server_scene.h"
-
-// careful, these may run in different threads than the visual server
-
-int VisualServerRaster::changes = 0;
-
-/* BLACK BARS */
-
-void VisualServerRaster::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) {
-
- black_margin[MARGIN_LEFT] = p_left;
- black_margin[MARGIN_TOP] = p_top;
- black_margin[MARGIN_RIGHT] = p_right;
- black_margin[MARGIN_BOTTOM] = p_bottom;
-}
-
-void VisualServerRaster::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) {
-
- black_image[MARGIN_LEFT] = p_left;
- black_image[MARGIN_TOP] = p_top;
- black_image[MARGIN_RIGHT] = p_right;
- black_image[MARGIN_BOTTOM] = p_bottom;
-}
-
-void VisualServerRaster::_draw_margins() {
-
- VSG::canvas_render->draw_window_margins(black_margin, black_image);
-};
-
-/* FREE */
-
-void VisualServerRaster::free(RID p_rid) {
-
- if (VSG::storage->free(p_rid))
- return;
- if (VSG::canvas->free(p_rid))
- return;
- if (VSG::viewport->free(p_rid))
- return;
- if (VSG::scene->free(p_rid))
- return;
- if (VSG::scene_render->free(p_rid))
- return;
-}
-
-/* EVENT QUEUING */
-
-void VisualServerRaster::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) {
-
- ERR_FAIL_NULL(p_where);
- FrameDrawnCallbacks fdc;
- fdc.object = p_where->get_instance_id();
- fdc.method = p_method;
- fdc.param = p_userdata;
-
- frame_drawn_callbacks.push_back(fdc);
-}
-
-void VisualServerRaster::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
- VS::get_singleton()->emit_signal("frame_pre_draw");
-
- changes = 0;
-
- VSG::rasterizer->begin_frame(frame_step);
-
- TIMESTAMP_BEGIN()
-
- VSG::scene_render->update(); //update scenes stuff before updating instances
-
- VSG::scene->update_dirty_instances(); //update scene stuff
-
- VSG::scene->render_probes();
- VSG::viewport->draw_viewports();
- VSG::canvas_render->update();
-
- _draw_margins();
- VSG::rasterizer->end_frame(p_swap_buffers);
-
- while (frame_drawn_callbacks.front()) {
-
- Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object);
- if (obj) {
- Callable::CallError ce;
- const Variant *v = &frame_drawn_callbacks.front()->get().param;
- obj->call(frame_drawn_callbacks.front()->get().method, &v, 1, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- String err = Variant::get_call_error_text(obj, frame_drawn_callbacks.front()->get().method, &v, 1, ce);
- ERR_PRINT("Error calling frame drawn function: " + err);
- }
- }
-
- frame_drawn_callbacks.pop_front();
- }
- VS::get_singleton()->emit_signal("frame_post_draw");
-
- if (VSG::storage->get_captured_timestamps_count()) {
- Vector<FrameProfileArea> new_profile;
- new_profile.resize(VSG::storage->get_captured_timestamps_count());
-
- uint64_t base_cpu = VSG::storage->get_captured_timestamp_cpu_time(0);
- uint64_t base_gpu = VSG::storage->get_captured_timestamp_gpu_time(0);
- for (uint32_t i = 0; i < VSG::storage->get_captured_timestamps_count(); i++) {
- uint64_t time_cpu = VSG::storage->get_captured_timestamp_cpu_time(i) - base_cpu;
- uint64_t time_gpu = VSG::storage->get_captured_timestamp_gpu_time(i) - base_gpu;
- new_profile.write[i].gpu_msec = float(time_gpu / 1000) / 1000.0;
- new_profile.write[i].cpu_msec = float(time_cpu) / 1000.0;
- new_profile.write[i].name = VSG::storage->get_captured_timestamp_name(i);
- }
-
- frame_profile = new_profile;
- }
-
- frame_profile_frame = VSG::storage->get_captured_timestamps_frame();
-}
-void VisualServerRaster::sync() {
-}
-bool VisualServerRaster::has_changed() const {
-
- return changes > 0;
-}
-void VisualServerRaster::init() {
-
- VSG::rasterizer->initialize();
-}
-void VisualServerRaster::finish() {
-
- if (test_cube.is_valid()) {
- free(test_cube);
- }
-
- VSG::rasterizer->finalize();
-}
-
-/* STATUS INFORMATION */
-
-int VisualServerRaster::get_render_info(RenderInfo p_info) {
-
- return VSG::storage->get_render_info(p_info);
-}
-
-String VisualServerRaster::get_video_adapter_name() const {
-
- return VSG::storage->get_video_adapter_name();
-}
-
-String VisualServerRaster::get_video_adapter_vendor() const {
-
- return VSG::storage->get_video_adapter_vendor();
-}
-
-void VisualServerRaster::set_frame_profiling_enabled(bool p_enable) {
- VSG::storage->capturing_timestamps = p_enable;
-}
-
-uint64_t VisualServerRaster::get_frame_profile_frame() {
- return frame_profile_frame;
-}
-
-Vector<VisualServer::FrameProfileArea> VisualServerRaster::get_frame_profile() {
- return frame_profile;
-}
-
-/* TESTING */
-
-void VisualServerRaster::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
-
- redraw_request();
- VSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter);
-}
-void VisualServerRaster::set_default_clear_color(const Color &p_color) {
- VSG::viewport->set_default_clear_color(p_color);
-}
-
-bool VisualServerRaster::has_feature(Features p_feature) const {
-
- return false;
-}
-
-RID VisualServerRaster::get_test_cube() {
- if (!test_cube.is_valid()) {
- test_cube = _make_test_cube();
- }
- return test_cube;
-}
-
-bool VisualServerRaster::has_os_feature(const String &p_feature) const {
-
- return VSG::storage->has_os_feature(p_feature);
-}
-
-void VisualServerRaster::set_debug_generate_wireframes(bool p_generate) {
-
- VSG::storage->set_debug_generate_wireframes(p_generate);
-}
-
-void VisualServerRaster::call_set_use_vsync(bool p_enable) {
- OS::get_singleton()->_set_use_vsync(p_enable);
-}
-
-bool VisualServerRaster::is_low_end() const {
- // FIXME: Commented out when rebasing vulkan branch on master,
- // causes a crash, it seems rasterizer is not initialized yet the
- // first time it's called.
- //return VSG::rasterizer->is_low_end();
- return false;
-}
-VisualServerRaster::VisualServerRaster() {
-
- VSG::canvas = memnew(VisualServerCanvas);
- VSG::viewport = memnew(VisualServerViewport);
- VSG::scene = memnew(VisualServerScene);
- VSG::rasterizer = Rasterizer::create();
- VSG::storage = VSG::rasterizer->get_storage();
- VSG::canvas_render = VSG::rasterizer->get_canvas();
- VSG::scene_render = VSG::rasterizer->get_scene();
-
- frame_profile_frame = 0;
-
- for (int i = 0; i < 4; i++) {
- black_margin[i] = 0;
- black_image[i] = RID();
- }
-}
-
-VisualServerRaster::~VisualServerRaster() {
-
- memdelete(VSG::canvas);
- memdelete(VSG::viewport);
- memdelete(VSG::rasterizer);
- memdelete(VSG::scene);
-}
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
deleted file mode 100644
index 4fea6082f4..0000000000
--- a/servers/visual/visual_server_raster.h
+++ /dev/null
@@ -1,762 +0,0 @@
-/*************************************************************************/
-/* visual_server_raster.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUAL_SERVER_RASTER_H
-#define VISUAL_SERVER_RASTER_H
-
-#include "core/math/octree.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/visual_server.h"
-#include "visual_server_canvas.h"
-#include "visual_server_globals.h"
-#include "visual_server_scene.h"
-#include "visual_server_viewport.h"
-
-class VisualServerRaster : public VisualServer {
-
- enum {
-
- MAX_INSTANCE_CULL = 8192,
- MAX_INSTANCE_LIGHTS = 4,
- LIGHT_CACHE_DIRTY = -1,
- MAX_LIGHTS_CULLED = 256,
- MAX_ROOM_CULL = 32,
- MAX_EXTERIOR_PORTALS = 128,
- MAX_LIGHT_SAMPLERS = 256,
- INSTANCE_ROOMLESS_MASK = (1 << 20)
-
- };
-
- static int changes;
- RID test_cube;
-
- int black_margin[4];
- RID black_image[4];
-
- struct FrameDrawnCallbacks {
-
- ObjectID object;
- StringName method;
- Variant param;
- };
-
- List<FrameDrawnCallbacks> frame_drawn_callbacks;
-
- void _draw_margins();
- static void _changes_changed() {}
-
- uint64_t frame_profile_frame;
- Vector<FrameProfileArea> frame_profile;
-
-public:
- //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed()
- //#define DEBUG_CHANGES
-
-#ifdef DEBUG_CHANGES
- _FORCE_INLINE_ static void redraw_request() {
- changes++;
- _changes_changed();
- }
-
-#define DISPLAY_CHANGED \
- changes++; \
- _changes_changed();
-
-#else
- _FORCE_INLINE_ static void redraw_request() { changes++; }
-
-#define DISPLAY_CHANGED \
- changes++;
-#endif
-
-#define BIND0R(m_r, m_name) \
- m_r m_name() { 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 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 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 BIND1(m_name, m_type1) \
- void m_name(m_type1 arg1) { 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); }
-
-//from now on, calls forwarded to this singleton
-#define BINDBASE VSG::storage
-
- /* TEXTURE API */
-
- //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)
- BIND1R(RID, texture_3d_create, const Vector<Ref<Image> > &)
- BIND1R(RID, texture_proxy_create, RID)
-
- //goes pass-through
- BIND3(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)
- BIND4(texture_3d_update, RID, const Ref<Image> &, int, int)
- BIND2(texture_proxy_update, RID, RID)
-
- //these also go pass-through
- BIND0R(RID, texture_2d_placeholder_create)
- BIND0R(RID, texture_2d_layered_placeholder_create)
- BIND0R(RID, texture_3d_placeholder_create)
-
- BIND1RC(Ref<Image>, texture_2d_get, RID)
- BIND2RC(Ref<Image>, texture_2d_layer_get, RID, int)
- BIND3RC(Ref<Image>, texture_3d_slice_get, RID, int, int)
-
- BIND2(texture_replace, RID, RID)
-
- BIND3(texture_set_size_override, RID, int, int)
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- BIND2(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 *)
-
- BIND2(texture_set_path, RID, const String &)
- BIND1RC(String, texture_get_path, RID)
- BIND1(texture_debug_usage, List<TextureInfo> *)
-
- BIND2(texture_set_force_redraw_if_visible, RID, bool)
-
- /* SHADER API */
-
- BIND0R(RID, shader_create)
-
- BIND2(shader_set_code, RID, const String &)
- BIND1RC(String, shader_get_code, RID)
-
- BIND2C(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 &)
-
- /* COMMON MATERIAL API */
-
- BIND0R(RID, material_create)
-
- BIND2(material_set_shader, RID, RID)
-
- BIND3(material_set_param, RID, const StringName &, const Variant &)
- BIND2RC(Variant, material_get_param, RID, const StringName &)
-
- BIND2(material_set_render_priority, RID, int)
- BIND2(material_set_next_pass, RID, RID)
-
- /* MESH API */
-
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) {
- RID mesh = mesh_create();
- for (int i = 0; i < p_surfaces.size(); i++) {
- mesh_add_surface(mesh, p_surfaces[i]);
- }
- return mesh;
- }
-
- BIND0R(RID, mesh_create)
-
- BIND2(mesh_add_surface, RID, const SurfaceData &)
-
- BIND1RC(int, mesh_get_blend_shape_count, RID)
-
- BIND2(mesh_set_blend_shape_mode, RID, BlendShapeMode)
- BIND1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID)
-
- BIND4(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)
-
- BIND2RC(SurfaceData, mesh_get_surface, RID, int)
-
- BIND1RC(int, mesh_get_surface_count, RID)
-
- BIND2(mesh_set_custom_aabb, RID, const AABB &)
- BIND1RC(AABB, mesh_get_custom_aabb, RID)
-
- BIND1(mesh_clear, RID)
-
- /* MULTIMESH API */
-
- BIND0R(RID, multimesh_create)
-
- BIND5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool)
- BIND1RC(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 &)
-
- BIND1RC(RID, multimesh_get_mesh, RID)
- BIND1RC(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)
-
- BIND2(multimesh_set_buffer, RID, const Vector<float> &)
- BIND1RC(Vector<float>, multimesh_get_buffer, RID)
-
- BIND2(multimesh_set_visible_instances, RID, int)
- BIND1RC(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)
-
- /* 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 &)
-
- /* Light API */
-
- BIND0R(RID, directional_light_create)
- BIND0R(RID, omni_light_create)
- BIND0R(RID, spot_light_create)
-
- 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_use_gi, RID, bool)
-
- BIND2(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_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_interior_ambient, RID, const Color &)
- BIND2(reflection_probe_set_interior_ambient_energy, RID, float)
- BIND2(reflection_probe_set_interior_ambient_probe_contribution, RID, float)
- 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)
-
- /* BAKED LIGHT API */
-
- BIND0R(RID, gi_probe_create)
-
- 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> &)
-
- 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)
-
- BIND2(gi_probe_set_dynamic_range, RID, float)
- BIND1RC(float, gi_probe_get_dynamic_range, RID)
-
- BIND2(gi_probe_set_propagation, RID, float)
- BIND1RC(float, gi_probe_get_propagation, RID)
-
- BIND2(gi_probe_set_energy, RID, float)
- BIND1RC(float, gi_probe_get_energy, RID)
-
- BIND2(gi_probe_set_ao, RID, float)
- BIND1RC(float, gi_probe_get_ao, RID)
-
- BIND2(gi_probe_set_ao_size, RID, float)
- BIND1RC(float, gi_probe_get_ao_size, RID)
-
- BIND2(gi_probe_set_bias, RID, float)
- BIND1RC(float, gi_probe_get_bias, RID)
-
- BIND2(gi_probe_set_normal_bias, RID, float)
- BIND1RC(float, gi_probe_get_normal_bias, RID)
-
- BIND2(gi_probe_set_interior, RID, bool)
- BIND1RC(bool, gi_probe_is_interior, RID)
-
- BIND2(gi_probe_set_use_two_bounces, RID, bool)
- BIND1RC(bool, gi_probe_is_using_two_bounces, RID)
-
- BIND2(gi_probe_set_anisotropy_strength, RID, float)
- BIND1RC(float, gi_probe_get_anisotropy_strength, RID)
-
- /* LIGHTMAP CAPTURE */
-
- BIND0R(RID, lightmap_capture_create)
-
- BIND2(lightmap_capture_set_bounds, RID, const AABB &)
- BIND1RC(AABB, lightmap_capture_get_bounds, RID)
-
- BIND2(lightmap_capture_set_octree, RID, const Vector<uint8_t> &)
- BIND1RC(Vector<uint8_t>, lightmap_capture_get_octree, RID)
-
- BIND2(lightmap_capture_set_octree_cell_transform, RID, const Transform &)
- BIND1RC(Transform, lightmap_capture_get_octree_cell_transform, RID)
- BIND2(lightmap_capture_set_octree_cell_subdiv, RID, int)
- BIND1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
-
- BIND2(lightmap_capture_set_energy, RID, float)
- BIND1RC(float, lightmap_capture_get_energy, RID)
-
- /* 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)
-
- BIND2(particles_set_draw_order, RID, VS::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 &)
-
-#undef BINDBASE
-//from now on, calls forwarded to this singleton
-#define BINDBASE VSG::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
-//from now on, calls forwarded to this singleton
-#define BINDBASE VSG::viewport
-
- /* VIEWPORT TARGET API */
-
- BIND0R(RID, viewport_create)
-
- BIND2(viewport_set_use_arvr, RID, bool)
- BIND3(viewport_set_size, RID, int, int)
-
- BIND2(viewport_set_active, RID, bool)
- BIND2(viewport_set_parent_viewport, RID, RID)
-
- BIND2(viewport_set_clear_mode, RID, ViewportClearMode)
-
- BIND3(viewport_attach_to_screen, RID, const Rect2 &, int)
- BIND2(viewport_set_render_direct_to_screen, RID, bool)
- BIND1(viewport_detach, RID)
-
- BIND2(viewport_set_update_mode, RID, ViewportUpdateMode)
- BIND2(viewport_set_vflip, RID, bool)
-
- BIND1RC(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)
-
- BIND2(viewport_attach_camera, RID, RID)
- BIND2(viewport_set_scenario, RID, RID)
- BIND2(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_global_canvas_transform, RID, const Transform2D &)
- BIND4(viewport_set_canvas_stacking, RID, RID, int, int)
- BIND2(viewport_set_shadow_atlas_size, RID, int)
- BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
- BIND2(viewport_set_msaa, RID, ViewportMSAA)
-
- BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo)
- BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw)
-
- /* ENVIRONMENT API */
-
-#undef BINDBASE
-//from now on, calls forwarded to this singleton
-#define BINDBASE VSG::scene_render
-
- BIND1(directional_shadow_atlas_set_size, int)
-
- /* SKY API */
-
- BIND0R(RID, sky_create)
- BIND2(sky_set_radiance_size, RID, int)
- BIND2(sky_set_mode, RID, SkyMode)
- BIND2(sky_set_texture, RID, RID)
-
- BIND0R(RID, environment_create)
-
- 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 &)
-
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- BIND2(environment_set_camera_feed_id, RID, int)
-#endif
- BIND7(environment_set_ssr, RID, bool, int, float, float, float, bool)
- BIND9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float)
- BIND2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool)
-
- BIND12(environment_set_glow, RID, bool, int, float, float, float, float, EnvironmentGlowBlendMode, float, float, float, bool)
-
- BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
-
- BIND6(environment_set_adjustment, RID, bool, float, float, float, RID)
-
- BIND5(environment_set_fog, RID, bool, const Color &, const Color &, float)
- BIND7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
- BIND5(environment_set_fog_height, RID, bool, float, float, float)
-
- BIND2(screen_space_roughness_limiter_set_active, bool, float)
-
- /* CAMERA EFFECTS */
-
- BIND0R(RID, camera_effects_create)
-
- BIND2(camera_effects_set_dof_blur_quality, DOFBlurQuality, bool)
- BIND1(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)
-
- /* SCENARIO API */
-
-#undef BINDBASE
-#define BINDBASE VSG::scene
-
- BIND0R(RID, scenario_create)
-
- 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)
-
- /* INSTANCING API */
- BIND0R(RID, instance_create)
-
- 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)
- BIND3(instance_set_use_lightmap, RID, RID, RID)
-
- BIND2(instance_set_custom_aabb, RID, AABB)
-
- BIND2(instance_attach_skeleton, RID, RID)
- BIND2(instance_set_exterior, RID, bool)
-
- BIND2(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)
-
- 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)
-
- BIND5(instance_geometry_set_draw_range, RID, float, float, float, float)
- BIND2(instance_geometry_set_as_instance_lod, RID, RID)
-
-#undef BINDBASE
-//from now on, calls forwarded to this singleton
-#define BINDBASE VSG::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_item_create)
- BIND2(canvas_item_set_parent, RID, RID)
-
- 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)
-
- BIND2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
- BIND2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
-
- BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
- BIND4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
- 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 &)
- BIND11(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND12(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND15(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND11(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND10(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND14(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, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND10(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND8(canvas_item_add_multimesh, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- BIND8(canvas_item_add_particles, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- 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)
-
- BIND0R(RID, canvas_light_create)
- BIND2(canvas_light_attach_to_canvas, RID, RID)
- BIND2(canvas_light_set_enabled, RID, bool)
- BIND2(canvas_light_set_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_mode, RID, CanvasLightMode)
-
- BIND2(canvas_light_set_shadow_enabled, RID, bool)
- BIND2(canvas_light_set_shadow_buffer_size, RID, int)
- 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_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_shape_as_lines, RID, const Vector<Vector2> &)
-
- BIND2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
-
- /* 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);
-
- /* FREE */
-
- virtual void free(RID p_rid); ///< free RIDs associated with the visual server
-
- /* EVENT QUEUING */
-
- virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata);
-
- virtual void draw(bool p_swap_buffers, double frame_step);
- virtual void sync();
- virtual bool has_changed() const;
- virtual void init();
- virtual void finish();
-
- /* 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 void set_frame_profiling_enabled(bool p_enable);
- virtual Vector<FrameProfileArea> get_frame_profile();
- virtual uint64_t get_frame_profile_frame();
-
- virtual RID get_test_cube();
-
- /* TESTING */
-
- 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 bool has_feature(Features p_feature) const;
-
- virtual bool has_os_feature(const String &p_feature) const;
- virtual void set_debug_generate_wireframes(bool p_generate);
-
- virtual void call_set_use_vsync(bool p_enable);
-
- virtual bool is_low_end() const;
-
- VisualServerRaster();
- ~VisualServerRaster();
-
-#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/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
deleted file mode 100644
index 1a9ecae23a..0000000000
--- a/servers/visual/visual_server_scene.cpp
+++ /dev/null
@@ -1,2839 +0,0 @@
-/*************************************************************************/
-/* visual_server_scene.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_scene.h"
-
-#include "core/os/os.h"
-#include "visual_server_globals.h"
-#include "visual_server_raster.h"
-
-#include <new>
-
-/* CAMERA API */
-
-RID VisualServerScene::camera_create() {
-
- Camera *camera = memnew(Camera);
- return camera_owner.make_rid(camera);
-}
-
-void VisualServerScene::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->type = Camera::PERSPECTIVE;
- camera->fov = p_fovy_degrees;
- camera->znear = p_z_near;
- camera->zfar = p_z_far;
-}
-
-void VisualServerScene::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->type = Camera::ORTHOGONAL;
- camera->size = p_size;
- camera->znear = p_z_near;
- camera->zfar = p_z_far;
-}
-
-void VisualServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->type = Camera::FRUSTUM;
- camera->size = p_size;
- camera->offset = p_offset;
- camera->znear = p_z_near;
- camera->zfar = p_z_far;
-}
-
-void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->transform = p_transform.orthonormalized();
-}
-
-void VisualServerScene::camera_set_cull_mask(RID p_camera, uint32_t p_layers) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
-
- camera->visible_layers = p_layers;
-}
-
-void VisualServerScene::camera_set_environment(RID p_camera, RID p_env) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->env = p_env;
-}
-
-void VisualServerScene::camera_set_camera_effects(RID p_camera, RID p_fx) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->effects = p_fx;
-}
-
-void VisualServerScene::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) {
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
- camera->vaspect = p_enable;
-}
-
-/* SCENARIO API */
-
-void *VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int) {
-
- //VisualServerScene *self = (VisualServerScene*)p_self;
- Instance *A = p_A;
- Instance *B = p_B;
-
- //instance indices are designed so greater always contains lesser
- if (A->base_type > B->base_type) {
- SWAP(A, B); //lesser always first
- }
-
- if (B->base_type == VS::INSTANCE_LIGHT && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- InstanceLightData::PairInfo pinfo;
- pinfo.geometry = A;
- pinfo.L = geom->lighting.push_back(B);
-
- List<InstanceLightData::PairInfo>::Element *E = light->geometries.push_back(pinfo);
-
- if (geom->can_cast_shadows) {
-
- light->shadow_dirty = true;
- }
- geom->lighting_dirty = true;
-
- return E; //this element should make freeing faster
- } else if (B->base_type == VS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- InstanceReflectionProbeData::PairInfo pinfo;
- pinfo.geometry = A;
- pinfo.L = geom->reflection_probes.push_back(B);
-
- List<InstanceReflectionProbeData::PairInfo>::Element *E = reflection_probe->geometries.push_back(pinfo);
-
- geom->reflection_dirty = true;
-
- return E; //this element should make freeing faster
- } else if (B->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- InstanceLightmapCaptureData::PairInfo pinfo;
- pinfo.geometry = A;
- pinfo.L = geom->lightmap_captures.push_back(B);
-
- List<InstanceLightmapCaptureData::PairInfo>::Element *E = lightmap_capture->geometries.push_back(pinfo);
- ((VisualServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
-
- return E; //this element should make freeing faster
- } else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- InstanceGIProbeData::PairInfo pinfo;
- pinfo.geometry = A;
- pinfo.L = geom->gi_probes.push_back(B);
-
- List<InstanceGIProbeData::PairInfo>::Element *E;
- if (A->dynamic_gi) {
- E = gi_probe->dynamic_geometries.push_back(pinfo);
- } else {
- E = gi_probe->geometries.push_back(pinfo);
- }
-
- geom->gi_probes_dirty = true;
-
- return E; //this element should make freeing faster
-
- } else if (B->base_type == VS::INSTANCE_GI_PROBE && A->base_type == VS::INSTANCE_LIGHT) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- return gi_probe->lights.insert(A);
- }
-
- return NULL;
-}
-void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *udata) {
-
- //VisualServerScene *self = (VisualServerScene*)p_self;
- Instance *A = p_A;
- Instance *B = p_B;
-
- //instance indices are designed so greater always contains lesser
- if (A->base_type > B->base_type) {
- SWAP(A, B); //lesser always first
- }
-
- if (B->base_type == VS::INSTANCE_LIGHT && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- List<InstanceLightData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightData::PairInfo>::Element *>(udata);
-
- geom->lighting.erase(E->get().L);
- light->geometries.erase(E);
-
- if (geom->can_cast_shadows) {
- light->shadow_dirty = true;
- }
- geom->lighting_dirty = true;
-
- } else if (B->base_type == VS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- List<InstanceReflectionProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceReflectionProbeData::PairInfo>::Element *>(udata);
-
- geom->reflection_probes.erase(E->get().L);
- reflection_probe->geometries.erase(E);
-
- geom->reflection_dirty = true;
- } else if (B->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- List<InstanceLightmapCaptureData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapCaptureData::PairInfo>::Element *>(udata);
-
- geom->lightmap_captures.erase(E->get().L);
- lightmap_capture->geometries.erase(E);
- ((VisualServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
-
- } else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
-
- List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element *>(udata);
-
- geom->gi_probes.erase(E->get().L);
- if (A->dynamic_gi) {
- gi_probe->dynamic_geometries.erase(E);
- } else {
- gi_probe->geometries.erase(E);
- }
-
- geom->gi_probes_dirty = true;
-
- } else if (B->base_type == VS::INSTANCE_GI_PROBE && A->base_type == VS::INSTANCE_LIGHT) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data);
- Set<Instance *>::Element *E = reinterpret_cast<Set<Instance *>::Element *>(udata);
-
- gi_probe->lights.erase(E);
- }
-}
-
-RID VisualServerScene::scenario_create() {
-
- Scenario *scenario = memnew(Scenario);
- ERR_FAIL_COND_V(!scenario, RID());
- RID scenario_rid = scenario_owner.make_rid(scenario);
- scenario->self = scenario_rid;
-
- scenario->octree.set_pair_callback(_instance_pair, this);
- scenario->octree.set_unpair_callback(_instance_unpair, this);
- scenario->reflection_probe_shadow_atlas = VSG::scene_render->shadow_atlas_create();
- VSG::scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
- VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4);
- VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
- VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
- VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
- scenario->reflection_atlas = VSG::scene_render->reflection_atlas_create();
- return scenario_rid;
-}
-
-void VisualServerScene::scenario_set_debug(RID p_scenario, VS::ScenarioDebugMode p_debug_mode) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
- scenario->debug = p_debug_mode;
-}
-
-void VisualServerScene::scenario_set_environment(RID p_scenario, RID p_environment) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
- scenario->environment = p_environment;
-}
-
-void VisualServerScene::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
- scenario->camera_effects = p_camera_effects;
-}
-
-void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
- scenario->fallback_environment = p_environment;
-}
-
-void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
- VSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
-}
-
-/* INSTANCING API */
-
-void VisualServerScene::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
-
- if (p_update_aabb)
- p_instance->update_aabb = true;
- if (p_update_dependencies)
- p_instance->update_dependencies = true;
-
- if (p_instance->update_item.in_list())
- return;
-
- _instance_update_list.add(&p_instance->update_item);
-}
-
-RID VisualServerScene::instance_create() {
-
- Instance *instance = memnew(Instance);
- ERR_FAIL_COND_V(!instance, RID());
-
- RID instance_rid = instance_owner.make_rid(instance);
- instance->self = instance_rid;
-
- return instance_rid;
-}
-
-void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- Scenario *scenario = instance->scenario;
-
- if (instance->base_type != VS::INSTANCE_NONE) {
- //free anything related to that base
-
- if (scenario && instance->octree_id) {
- scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
- instance->octree_id = 0;
- }
-
- switch (instance->base_type) {
- case VS::INSTANCE_LIGHT: {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
-#ifdef DEBUG_ENABLED
- if (light->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from light.");
- }
-#endif
- if (instance->scenario && light->D) {
- instance->scenario->directional_lights.erase(light->D);
- light->D = NULL;
- }
- VSG::scene_render->free(light->instance);
- } break;
- case VS::INSTANCE_REFLECTION_PROBE: {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
- VSG::scene_render->free(reflection_probe->instance);
- if (reflection_probe->update_list.in_list()) {
- reflection_probe_render_list.remove(&reflection_probe->update_list);
- }
- } break;
- case VS::INSTANCE_LIGHTMAP_CAPTURE: {
-
- InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(instance->base_data);
- //erase dependencies, since no longer a lightmap
- while (lightmap_capture->users.front()) {
- instance_set_use_lightmap(lightmap_capture->users.front()->get()->self, RID(), RID());
- }
- } break;
- case VS::INSTANCE_GI_PROBE: {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
-#ifdef DEBUG_ENABLED
- if (gi_probe->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
- }
-#endif
-#ifdef DEBUG_ENABLED
- if (gi_probe->lights.size()) {
- ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
- }
-#endif
- if (gi_probe->update_element.in_list()) {
- gi_probe_update_list.remove(&gi_probe->update_element);
- }
-
- if (instance->lightmap_capture) {
- Instance *capture = (Instance *)instance->lightmap_capture;
- InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(capture->base_data);
- lightmap_capture->users.erase(instance);
- instance->lightmap_capture = NULL;
- instance->lightmap = RID();
- }
-
- VSG::scene_render->free(gi_probe->probe_instance);
-
- } break;
- default: {
- }
- }
-
- if (instance->base_data) {
- memdelete(instance->base_data);
- instance->base_data = NULL;
- }
-
- instance->blend_values.clear();
- instance->materials.clear();
- }
-
- instance->base_type = VS::INSTANCE_NONE;
- instance->base = RID();
-
- if (p_base.is_valid()) {
-
- instance->base_type = VSG::storage->get_base_type(p_base);
- ERR_FAIL_COND(instance->base_type == VS::INSTANCE_NONE);
-
- switch (instance->base_type) {
- case VS::INSTANCE_LIGHT: {
-
- InstanceLightData *light = memnew(InstanceLightData);
-
- if (scenario && VSG::storage->light_get_type(p_base) == VS::LIGHT_DIRECTIONAL) {
- light->D = scenario->directional_lights.push_back(instance);
- }
-
- light->instance = VSG::scene_render->light_instance_create(p_base);
-
- instance->base_data = light;
- } break;
- case VS::INSTANCE_MESH:
- case VS::INSTANCE_MULTIMESH:
- case VS::INSTANCE_IMMEDIATE:
- case VS::INSTANCE_PARTICLES: {
-
- InstanceGeometryData *geom = memnew(InstanceGeometryData);
- instance->base_data = geom;
- if (instance->base_type == VS::INSTANCE_MESH) {
- instance->blend_values.resize(VSG::storage->mesh_get_blend_shape_count(p_base));
- }
- } break;
- case VS::INSTANCE_REFLECTION_PROBE: {
-
- InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData);
- reflection_probe->owner = instance;
- instance->base_data = reflection_probe;
-
- reflection_probe->instance = VSG::scene_render->reflection_probe_instance_create(p_base);
- } break;
- case VS::INSTANCE_LIGHTMAP_CAPTURE: {
-
- InstanceLightmapCaptureData *lightmap_capture = memnew(InstanceLightmapCaptureData);
- instance->base_data = lightmap_capture;
- //lightmap_capture->instance = VSG::scene_render->lightmap_capture_instance_create(p_base);
- } break;
- case VS::INSTANCE_GI_PROBE: {
-
- InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData);
- instance->base_data = gi_probe;
- gi_probe->owner = instance;
-
- if (scenario && !gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
- }
-
- gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create(p_base);
-
- } break;
- default: {
- }
- }
-
- instance->base = p_base;
-
- //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it
- VSG::storage->base_update_dependency(p_base, instance);
- }
-
- _instance_queue_update(instance, true, true);
-}
-void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->scenario) {
-
- instance->scenario->instances.remove(&instance->scenario_item);
-
- if (instance->octree_id) {
- instance->scenario->octree.erase(instance->octree_id); //make dependencies generated by the octree go away
- instance->octree_id = 0;
- }
-
- switch (instance->base_type) {
-
- case VS::INSTANCE_LIGHT: {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
-#ifdef DEBUG_ENABLED
- if (light->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from light.");
- }
-#endif
- if (light->D) {
- instance->scenario->directional_lights.erase(light->D);
- light->D = NULL;
- }
- } break;
- case VS::INSTANCE_REFLECTION_PROBE: {
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
- VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance);
-
- } break;
- case VS::INSTANCE_GI_PROBE: {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
-
-#ifdef DEBUG_ENABLED
- if (gi_probe->geometries.size()) {
- ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe.");
- }
-#endif
-#ifdef DEBUG_ENABLED
- if (gi_probe->lights.size()) {
- ERR_PRINT("BUG, indexing did not unpair lights from GIProbe.");
- }
-#endif
-
- if (gi_probe->update_element.in_list()) {
- gi_probe_update_list.remove(&gi_probe->update_element);
- }
- } break;
- default: {
- }
- }
-
- instance->scenario = NULL;
- }
-
- if (p_scenario.is_valid()) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND(!scenario);
-
- instance->scenario = scenario;
-
- scenario->instances.add(&instance->scenario_item);
-
- switch (instance->base_type) {
-
- case VS::INSTANCE_LIGHT: {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
-
- if (VSG::storage->light_get_type(instance->base) == VS::LIGHT_DIRECTIONAL) {
- light->D = scenario->directional_lights.push_back(instance);
- }
- } break;
- case VS::INSTANCE_GI_PROBE: {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
- if (!gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
- }
- } break;
- default: {
- }
- }
-
- _instance_queue_update(instance, true, true);
- }
-}
-void VisualServerScene::instance_set_layer_mask(RID p_instance, uint32_t p_mask) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- instance->layer_mask = p_mask;
-}
-void VisualServerScene::instance_set_transform(RID p_instance, const Transform &p_transform) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->transform == p_transform)
- return; //must be checked to avoid worst evil
-
-#ifdef DEBUG_ENABLED
-
- for (int i = 0; i < 4; i++) {
- const Vector3 &v = i < 3 ? p_transform.basis.elements[i] : p_transform.origin;
- ERR_FAIL_COND(Math::is_inf(v.x));
- ERR_FAIL_COND(Math::is_nan(v.x));
- ERR_FAIL_COND(Math::is_inf(v.y));
- ERR_FAIL_COND(Math::is_nan(v.y));
- ERR_FAIL_COND(Math::is_inf(v.z));
- ERR_FAIL_COND(Math::is_nan(v.z));
- }
-
-#endif
- instance->transform = p_transform;
- _instance_queue_update(instance, true);
-}
-void VisualServerScene::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- instance->object_id = p_id;
-}
-void VisualServerScene::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->update_item.in_list()) {
- _update_dirty_instance(instance);
- }
-
- ERR_FAIL_INDEX(p_shape, instance->blend_values.size());
- instance->blend_values.write[p_shape] = p_weight;
-}
-
-void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->base_type == VS::INSTANCE_MESH) {
- //may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
- instance->materials.resize(MAX(p_surface + 1, VSG::storage->mesh_get_surface_count(instance->base)));
- }
-
- ERR_FAIL_INDEX(p_surface, instance->materials.size());
-
- instance->materials.write[p_surface] = p_material;
-
- _instance_queue_update(instance, false, true);
-}
-
-void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->visible == p_visible)
- return;
-
- instance->visible = p_visible;
-
- switch (instance->base_type) {
- case VS::INSTANCE_LIGHT: {
- if (VSG::storage->light_get_type(instance->base) != VS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario) {
- instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_LIGHT, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0);
- }
-
- } break;
- case VS::INSTANCE_REFLECTION_PROBE: {
- if (instance->octree_id && instance->scenario) {
- instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_REFLECTION_PROBE, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0);
- }
-
- } break;
- case VS::INSTANCE_LIGHTMAP_CAPTURE: {
- if (instance->octree_id && instance->scenario) {
- instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_LIGHTMAP_CAPTURE, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0);
- }
-
- } break;
- case VS::INSTANCE_GI_PROBE: {
- if (instance->octree_id && instance->scenario) {
- instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_GI_PROBE, p_visible ? (VS::INSTANCE_GEOMETRY_MASK | (1 << VS::INSTANCE_LIGHT)) : 0);
- }
-
- } break;
- default: {
- }
- }
-}
-inline bool is_geometry_instance(VisualServer::InstanceType p_type) {
- return p_type == VS::INSTANCE_MESH || p_type == VS::INSTANCE_MULTIMESH || p_type == VS::INSTANCE_PARTICLES || p_type == VS::INSTANCE_IMMEDIATE;
-}
-
-void VisualServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->lightmap_capture) {
- InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
- lightmap_capture->users.erase(instance);
- instance->lightmap = RID();
- instance->lightmap_capture = NULL;
- }
-
- if (p_lightmap_instance.is_valid()) {
- Instance *lightmap_instance = instance_owner.getornull(p_lightmap_instance);
- ERR_FAIL_COND(!lightmap_instance);
- ERR_FAIL_COND(lightmap_instance->base_type != VS::INSTANCE_LIGHTMAP_CAPTURE);
- instance->lightmap_capture = lightmap_instance;
-
- InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
- lightmap_capture->users.insert(instance);
- instance->lightmap = p_lightmap;
- }
-}
-
-void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
- ERR_FAIL_COND(!is_geometry_instance(instance->base_type));
-
- if (p_aabb != AABB()) {
-
- // Set custom AABB
- if (instance->custom_aabb == NULL)
- instance->custom_aabb = memnew(AABB);
- *instance->custom_aabb = p_aabb;
-
- } else {
-
- // Clear custom AABB
- if (instance->custom_aabb != NULL) {
- memdelete(instance->custom_aabb);
- instance->custom_aabb = NULL;
- }
- }
-
- if (instance->scenario)
- _instance_queue_update(instance, true, false);
-}
-
-void VisualServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- if (instance->skeleton == p_skeleton)
- return;
-
- instance->skeleton = p_skeleton;
-
- if (p_skeleton.is_valid()) {
- //update the dependency now, so if cleared, we remove it
- VSG::storage->skeleton_update_dependency(p_skeleton, instance);
- }
- _instance_queue_update(instance, true, true);
-}
-
-void VisualServerScene::instance_set_exterior(RID p_instance, bool p_enabled) {
-}
-
-void VisualServerScene::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) {
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- instance->extra_margin = p_margin;
- _instance_queue_update(instance, true, false);
-}
-
-Vector<ObjectID> VisualServerScene::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const {
-
- Vector<ObjectID> instances;
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND_V(!scenario, instances);
-
- const_cast<VisualServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling
-
- int culled = 0;
- Instance *cull[1024];
- culled = scenario->octree.cull_aabb(p_aabb, cull, 1024);
-
- for (int i = 0; i < culled; i++) {
-
- Instance *instance = cull[i];
- ERR_CONTINUE(!instance);
- if (instance->object_id.is_null())
- continue;
-
- instances.push_back(instance->object_id);
- }
-
- return instances;
-}
-Vector<ObjectID> VisualServerScene::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
-
- Vector<ObjectID> instances;
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND_V(!scenario, instances);
- const_cast<VisualServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling
-
- int culled = 0;
- Instance *cull[1024];
- culled = scenario->octree.cull_segment(p_from, p_from + p_to * 10000, cull, 1024);
-
- for (int i = 0; i < culled; i++) {
- Instance *instance = cull[i];
- ERR_CONTINUE(!instance);
- if (instance->object_id.is_null())
- continue;
-
- instances.push_back(instance->object_id);
- }
-
- return instances;
-}
-Vector<ObjectID> VisualServerScene::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const {
-
- Vector<ObjectID> instances;
- Scenario *scenario = scenario_owner.getornull(p_scenario);
- ERR_FAIL_COND_V(!scenario, instances);
- const_cast<VisualServerScene *>(this)->update_dirty_instances(); // check dirty instances before culling
-
- int culled = 0;
- Instance *cull[1024];
-
- culled = scenario->octree.cull_convex(p_convex, cull, 1024);
-
- for (int i = 0; i < culled; i++) {
-
- Instance *instance = cull[i];
- ERR_CONTINUE(!instance);
- if (instance->object_id.is_null())
- continue;
-
- instances.push_back(instance->object_id);
- }
-
- return instances;
-}
-
-void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceFlags p_flags, bool p_enabled) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- //ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK));
-
- switch (p_flags) {
-
- case VS::INSTANCE_FLAG_USE_BAKED_LIGHT: {
-
- instance->baked_light = p_enabled;
-
- } break;
- case VS::INSTANCE_FLAG_USE_DYNAMIC_GI: {
-
- if (p_enabled == instance->dynamic_gi) {
- //bye, redundant
- return;
- }
-
- if (instance->octree_id != 0) {
- //remove from octree, it needs to be re-paired
- instance->scenario->octree.erase(instance->octree_id);
- instance->octree_id = 0;
- _instance_queue_update(instance, true, true);
- }
-
- //once out of octree, can be changed
- instance->dynamic_gi = p_enabled;
-
- } break;
- case VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: {
-
- instance->redraw_if_visible = p_enabled;
-
- } break;
- default: {
- }
- }
-}
-void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- instance->cast_shadows = p_shadow_casting_setting;
- _instance_queue_update(instance, false, true);
-}
-void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) {
-
- Instance *instance = instance_owner.getornull(p_instance);
- ERR_FAIL_COND(!instance);
-
- instance->material_override = p_material;
- _instance_queue_update(instance, false, true);
-}
-
-void VisualServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
-}
-void VisualServerScene::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
-}
-
-void VisualServerScene::_update_instance(Instance *p_instance) {
-
- p_instance->version++;
-
- if (p_instance->base_type == VS::INSTANCE_LIGHT) {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
-
- VSG::scene_render->light_instance_set_transform(light->instance, p_instance->transform);
- light->shadow_dirty = true;
- }
-
- if (p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE) {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
-
- VSG::scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
- reflection_probe->reflection_dirty = true;
- }
-
- if (p_instance->base_type == VS::INSTANCE_GI_PROBE) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data);
-
- VSG::scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform);
- }
-
- if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
-
- VSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform);
- }
-
- if (p_instance->aabb.has_no_surface()) {
- return;
- }
-
- if ((1 << p_instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) {
-
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
- //make sure lights are updated if it casts shadow
-
- if (geom->can_cast_shadows) {
- for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) {
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
- light->shadow_dirty = true;
- }
- }
-
- if (!p_instance->lightmap_capture && geom->lightmap_captures.size()) {
- //affected by lightmap captures, must update capture info!
- _update_instance_lightmap_captures(p_instance);
- } else {
- if (!p_instance->lightmap_capture_data.empty()) {
- p_instance->lightmap_capture_data.resize(0); //not in use, clear capture data
- }
- }
- }
-
- p_instance->mirror = p_instance->transform.basis.determinant() < 0.0;
-
- AABB new_aabb;
-
- new_aabb = p_instance->transform.xform(p_instance->aabb);
-
- p_instance->transformed_aabb = new_aabb;
-
- if (!p_instance->scenario) {
-
- return;
- }
-
- if (p_instance->octree_id == 0) {
-
- uint32_t base_type = 1 << p_instance->base_type;
- uint32_t pairable_mask = 0;
- bool pairable = false;
-
- if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE) {
-
- pairable_mask = p_instance->visible ? VS::INSTANCE_GEOMETRY_MASK : 0;
- pairable = true;
- }
-
- if (p_instance->base_type == VS::INSTANCE_GI_PROBE) {
- //lights and geometries
- pairable_mask = p_instance->visible ? VS::INSTANCE_GEOMETRY_MASK | (1 << VS::INSTANCE_LIGHT) : 0;
- pairable = true;
- }
-
- // not inside octree
- p_instance->octree_id = p_instance->scenario->octree.create(p_instance, new_aabb, 0, pairable, base_type, pairable_mask);
-
- } else {
-
- /*
- if (new_aabb==p_instance->data.transformed_aabb)
- return;
- */
-
- p_instance->scenario->octree.move(p_instance->octree_id, new_aabb);
- }
-}
-
-void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
-
- AABB new_aabb;
-
- ERR_FAIL_COND(p_instance->base_type != VS::INSTANCE_NONE && !p_instance->base.is_valid());
-
- switch (p_instance->base_type) {
- case VisualServer::INSTANCE_NONE: {
-
- // do nothing
- } break;
- case VisualServer::INSTANCE_MESH: {
-
- if (p_instance->custom_aabb)
- new_aabb = *p_instance->custom_aabb;
- else
- new_aabb = VSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton);
-
- } break;
-
- case VisualServer::INSTANCE_MULTIMESH: {
-
- if (p_instance->custom_aabb)
- new_aabb = *p_instance->custom_aabb;
- else
- new_aabb = VSG::storage->multimesh_get_aabb(p_instance->base);
-
- } break;
- case VisualServer::INSTANCE_IMMEDIATE: {
-
- if (p_instance->custom_aabb)
- new_aabb = *p_instance->custom_aabb;
- else
- new_aabb = VSG::storage->immediate_get_aabb(p_instance->base);
-
- } break;
- case VisualServer::INSTANCE_PARTICLES: {
-
- if (p_instance->custom_aabb)
- new_aabb = *p_instance->custom_aabb;
- else
- new_aabb = VSG::storage->particles_get_aabb(p_instance->base);
-
- } break;
- case VisualServer::INSTANCE_LIGHT: {
-
- new_aabb = VSG::storage->light_get_aabb(p_instance->base);
-
- } break;
- case VisualServer::INSTANCE_REFLECTION_PROBE: {
-
- new_aabb = VSG::storage->reflection_probe_get_aabb(p_instance->base);
-
- } break;
- case VisualServer::INSTANCE_GI_PROBE: {
-
- new_aabb = VSG::storage->gi_probe_get_bounds(p_instance->base);
-
- } break;
- case VisualServer::INSTANCE_LIGHTMAP_CAPTURE: {
-
- new_aabb = VSG::storage->lightmap_capture_get_bounds(p_instance->base);
-
- } break;
- default: {
- }
- }
-
- // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs
- if (p_instance->extra_margin)
- new_aabb.grow_by(p_instance->extra_margin);
-
- p_instance->aabb = new_aabb;
-}
-
-_FORCE_INLINE_ static void _light_capture_sample_octree(const RasterizerStorage::LightmapCaptureOctree *p_octree, int p_cell_subdiv, const Vector3 &p_pos, const Vector3 &p_dir, float p_level, Vector3 &r_color, float &r_alpha) {
-
- static const Vector3 aniso_normal[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)
- };
-
- int size = 1 << (p_cell_subdiv - 1);
-
- int clamp_v = size - 1;
- //first of all, clamp
- Vector3 pos;
- pos.x = CLAMP(p_pos.x, 0, clamp_v);
- pos.y = CLAMP(p_pos.y, 0, clamp_v);
- pos.z = CLAMP(p_pos.z, 0, clamp_v);
-
- float level = (p_cell_subdiv - 1) - p_level;
-
- int target_level;
- float level_filter;
- if (level <= 0.0) {
- level_filter = 0;
- target_level = 0;
- } else {
- target_level = Math::ceil(level);
- level_filter = target_level - level;
- }
-
- Vector3 color[2][8];
- float alpha[2][8];
- zeromem(alpha, sizeof(float) * 2 * 8);
-
- //find cell at given level first
-
- for (int c = 0; c < 2; c++) {
-
- int current_level = MAX(0, target_level - c);
- int level_cell_size = (1 << (p_cell_subdiv - 1)) >> current_level;
-
- for (int n = 0; n < 8; n++) {
-
- int x = int(pos.x);
- int y = int(pos.y);
- int z = int(pos.z);
-
- if (n & 1)
- x += level_cell_size;
- if (n & 2)
- y += level_cell_size;
- if (n & 4)
- z += level_cell_size;
-
- int ofs_x = 0;
- int ofs_y = 0;
- int ofs_z = 0;
-
- x = CLAMP(x, 0, clamp_v);
- y = CLAMP(y, 0, clamp_v);
- z = CLAMP(z, 0, clamp_v);
-
- int half = size / 2;
- uint32_t cell = 0;
- for (int i = 0; i < current_level; i++) {
-
- const RasterizerStorage::LightmapCaptureOctree *bc = &p_octree[cell];
-
- int child = 0;
- if (x >= ofs_x + half) {
- child |= 1;
- ofs_x += half;
- }
- if (y >= ofs_y + half) {
- child |= 2;
- ofs_y += half;
- }
- if (z >= ofs_z + half) {
- child |= 4;
- ofs_z += half;
- }
-
- cell = bc->children[child];
- if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY)
- break;
-
- half >>= 1;
- }
-
- if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY) {
- alpha[c][n] = 0;
- } else {
- alpha[c][n] = p_octree[cell].alpha;
-
- for (int i = 0; i < 6; i++) {
- //anisotropic read light
- float amount = p_dir.dot(aniso_normal[i]);
- if (amount < 0)
- amount = 0;
- color[c][n].x += p_octree[cell].light[i][0] / 1024.0 * amount;
- color[c][n].y += p_octree[cell].light[i][1] / 1024.0 * amount;
- color[c][n].z += p_octree[cell].light[i][2] / 1024.0 * amount;
- }
- }
-
- //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]);
- }
- }
-
- float target_level_size = size >> target_level;
- Vector3 pos_fract[2];
-
- pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size;
- pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size;
- pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size;
-
- target_level_size = size >> MAX(0, target_level - 1);
-
- pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size;
- pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size;
- pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size;
-
- float alpha_interp[2];
- Vector3 color_interp[2];
-
- for (int i = 0; i < 2; i++) {
-
- Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x);
- Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x);
- Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y);
-
- Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x);
- Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x);
- Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y);
-
- color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z);
-
- float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x);
- float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x);
- float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y);
-
- float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x);
- float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x);
- float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y);
-
- alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z);
- }
-
- r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter);
- r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter);
-
- //print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha));
-}
-
-_FORCE_INLINE_ static Color _light_capture_voxel_cone_trace(const RasterizerStorage::LightmapCaptureOctree *p_octree, const Vector3 &p_pos, const Vector3 &p_dir, float p_aperture, int p_cell_subdiv) {
-
- float bias = 0.0; //no need for bias here
- float max_distance = (Vector3(1, 1, 1) * (1 << (p_cell_subdiv - 1))).length();
-
- float dist = bias;
- float alpha = 0.0;
- Vector3 color;
-
- Vector3 scolor;
- float salpha;
-
- while (dist < max_distance && alpha < 0.95) {
- float diameter = MAX(1.0, 2.0 * p_aperture * dist);
- _light_capture_sample_octree(p_octree, p_cell_subdiv, p_pos + dist * p_dir, p_dir, log2(diameter), scolor, salpha);
- float a = (1.0 - alpha);
- color += scolor * a;
- alpha += a * salpha;
- dist += diameter * 0.5;
- }
-
- return Color(color.x, color.y, color.z, alpha);
-}
-
-void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) {
-
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
-
- static const Vector3 cone_traces[12] = {
- Vector3(0, 0, 1),
- Vector3(0.866025, 0, 0.5),
- Vector3(0.267617, 0.823639, 0.5),
- Vector3(-0.700629, 0.509037, 0.5),
- Vector3(-0.700629, -0.509037, 0.5),
- Vector3(0.267617, -0.823639, 0.5),
- Vector3(0, 0, -1),
- Vector3(0.866025, 0, -0.5),
- Vector3(0.267617, 0.823639, -0.5),
- Vector3(-0.700629, 0.509037, -0.5),
- Vector3(-0.700629, -0.509037, -0.5),
- Vector3(0.267617, -0.823639, -0.5)
- };
-
- float cone_aperture = 0.577; // tan(angle) 60 degrees
-
- if (p_instance->lightmap_capture_data.empty()) {
- p_instance->lightmap_capture_data.resize(12);
- }
-
- //print_line("update captures for pos: " + p_instance->transform.origin);
-
- for (int i = 0; i < 12; i++)
- new (&p_instance->lightmap_capture_data.ptrw()[i]) Color;
-
- //this could use some sort of blending..
- for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) {
- const Vector<RasterizerStorage::LightmapCaptureOctree> *octree = VSG::storage->lightmap_capture_get_octree_ptr(E->get()->base);
- //print_line("octree size: " + itos(octree->size()));
- if (octree->size() == 0)
- continue;
- Transform to_cell_xform = VSG::storage->lightmap_capture_get_octree_cell_transform(E->get()->base);
- int cell_subdiv = VSG::storage->lightmap_capture_get_octree_cell_subdiv(E->get()->base);
- to_cell_xform = to_cell_xform * E->get()->transform.affine_inverse();
-
- const RasterizerStorage::LightmapCaptureOctree *octree_r = octree->ptr();
-
- Vector3 pos = to_cell_xform.xform(p_instance->transform.origin);
-
- for (int i = 0; i < 12; i++) {
-
- Vector3 dir = to_cell_xform.basis.xform(cone_traces[i]).normalized();
- Color capture = _light_capture_voxel_cone_trace(octree_r, pos, dir, cone_aperture, cell_subdiv);
- p_instance->lightmap_capture_data.write[i] += capture;
- }
- }
-}
-
-bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
-
- Transform light_transform = p_instance->transform;
- light_transform.orthonormalize(); //scale does not count on lights
-
- bool animated_material_found = false;
-
- switch (VSG::storage->light_get_type(p_instance->base)) {
-
- case VS::LIGHT_DIRECTIONAL: {
-
- float max_distance = p_cam_projection.get_z_far();
- float shadow_max = VSG::storage->light_get_param(p_instance->base, VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
- if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera
- max_distance = MIN(shadow_max, max_distance);
- }
- max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001);
- float min_distance = MIN(p_cam_projection.get_z_near(), max_distance);
-
- VS::LightDirectionalShadowDepthRangeMode depth_range_mode = VSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base);
-
- if (depth_range_mode == VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) {
- //optimize min/max
- Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform);
- int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
- Plane base(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2));
- //check distance max and min
-
- bool found_items = false;
- float z_max = -1e20;
- float z_min = 1e20;
-
- for (int i = 0; i < cull_count; i++) {
-
- Instance *instance = instance_shadow_cull_result[i];
- if (!instance->visible || !((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
- continue;
- }
-
- if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
- animated_material_found = true;
- }
-
- float max, min;
- instance->transformed_aabb.project_range_in_plane(base, min, max);
-
- if (max > z_max) {
- z_max = max;
- }
-
- if (min < z_min) {
- z_min = min;
- }
-
- found_items = true;
- }
-
- if (found_items) {
- min_distance = MAX(min_distance, z_min);
- max_distance = MIN(max_distance, z_max);
- }
- }
-
- float range = max_distance - min_distance;
-
- int splits = 0;
- switch (VSG::storage->light_directional_get_shadow_mode(p_instance->base)) {
- case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: splits = 1; break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: splits = 2; break;
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: splits = 4; break;
- }
-
- float distances[5];
-
- distances[0] = min_distance;
- for (int i = 0; i < splits; i++) {
- distances[i + 1] = min_distance + VSG::storage->light_get_param(p_instance->base, VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range;
- };
-
- distances[splits] = max_distance;
-
- float texture_size = VSG::scene_render->get_directional_light_shadow_size(light->instance);
-
- bool overlap = VSG::storage->light_directional_get_blend_splits(p_instance->base);
-
- float first_radius = 0.0;
-
- for (int i = 0; i < splits; i++) {
-
- RENDER_TIMESTAMP("Culling Directional Light split" + itos(i));
-
- // setup a camera matrix for that range!
- CameraMatrix camera_matrix;
-
- float aspect = p_cam_projection.get_aspect();
-
- if (p_cam_orthogonal) {
-
- Vector2 vp_he = p_cam_projection.get_viewport_half_extents();
-
- camera_matrix.set_orthogonal(vp_he.y * 2.0, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
- } else {
-
- float fov = p_cam_projection.get_fov();
- camera_matrix.set_perspective(fov, aspect, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
- }
-
- //obtain the frustum endpoints
-
- Vector3 endpoints[8]; // frustum plane endpoints
- bool res = camera_matrix.get_endpoints(p_cam_transform, endpoints);
- ERR_CONTINUE(!res);
-
- // obtain the light frustm ranges (given endpoints)
-
- Transform transform = light_transform; //discard scale and stabilize light
-
- Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized();
- Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized();
- Vector3 z_vec = transform.basis.get_axis(Vector3::AXIS_Z).normalized();
- //z_vec points agsint the camera, like in default opengl
-
- float x_min = 0.f, x_max = 0.f;
- float y_min = 0.f, y_max = 0.f;
- float z_min = 0.f, z_max = 0.f;
-
- // FIXME: z_max_cam is defined, computed, but not used below when setting up
- // ortho_camera. Commented out for now to fix warnings but should be investigated.
- float x_min_cam = 0.f, x_max_cam = 0.f;
- float y_min_cam = 0.f, y_max_cam = 0.f;
- float z_min_cam = 0.f;
- //float z_max_cam = 0.f;
-
- float bias_scale = 1.0;
-
- //used for culling
-
- for (int j = 0; j < 8; j++) {
-
- float d_x = x_vec.dot(endpoints[j]);
- float d_y = y_vec.dot(endpoints[j]);
- float d_z = z_vec.dot(endpoints[j]);
-
- if (j == 0 || d_x < x_min)
- x_min = d_x;
- if (j == 0 || d_x > x_max)
- x_max = d_x;
-
- if (j == 0 || d_y < y_min)
- y_min = d_y;
- if (j == 0 || d_y > y_max)
- y_max = d_y;
-
- if (j == 0 || d_z < z_min)
- z_min = d_z;
- if (j == 0 || d_z > z_max)
- z_max = d_z;
- }
-
- {
- //camera viewport stuff
-
- Vector3 center;
-
- for (int j = 0; j < 8; j++) {
-
- center += endpoints[j];
- }
- center /= 8.0;
-
- //center=x_vec*(x_max-x_min)*0.5 + y_vec*(y_max-y_min)*0.5 + z_vec*(z_max-z_min)*0.5;
-
- float radius = 0;
-
- for (int j = 0; j < 8; j++) {
-
- float d = center.distance_to(endpoints[j]);
- if (d > radius)
- radius = d;
- }
-
- radius *= texture_size / (texture_size - 2.0); //add a texel by each side
-
- if (i == 0) {
- first_radius = radius;
- } else {
- bias_scale = radius / first_radius;
- }
-
- x_max_cam = x_vec.dot(center) + radius;
- x_min_cam = x_vec.dot(center) - radius;
- y_max_cam = y_vec.dot(center) + radius;
- y_min_cam = y_vec.dot(center) - radius;
- //z_max_cam = z_vec.dot(center) + radius;
- z_min_cam = z_vec.dot(center) - radius;
-
- if (depth_range_mode == VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) {
- //this trick here is what stabilizes the shadow (make potential jaggies to not move)
- //at the cost of some wasted resolution. Still the quality increase is very well worth it
-
- float unit = radius * 2.0 / texture_size;
-
- x_max_cam = Math::stepify(x_max_cam, unit);
- x_min_cam = Math::stepify(x_min_cam, unit);
- y_max_cam = Math::stepify(y_max_cam, unit);
- y_min_cam = Math::stepify(y_min_cam, unit);
- }
- }
-
- //now that we now all ranges, we can proceed to make the light frustum planes, for culling octree
-
- Vector<Plane> light_frustum_planes;
- light_frustum_planes.resize(6);
-
- //right/left
- light_frustum_planes.write[0] = Plane(x_vec, x_max);
- light_frustum_planes.write[1] = Plane(-x_vec, -x_min);
- //top/bottom
- light_frustum_planes.write[2] = Plane(y_vec, y_max);
- light_frustum_planes.write[3] = Plane(-y_vec, -y_min);
- //near/far
- light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6);
- light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed
-
- int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
-
- // a pre pass will need to be needed to determine the actual z-near to be used
-
- Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2));
-
- for (int j = 0; j < cull_count; j++) {
-
- float min, max;
- Instance *instance = instance_shadow_cull_result[j];
- if (!instance->visible || !((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
- cull_count--;
- SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
- j--;
- continue;
- }
-
- instance->transformed_aabb.project_range_in_plane(Plane(z_vec, 0), min, max);
- instance->depth = near_plane.distance_to(instance->transform.origin);
- instance->depth_layer = 0;
- if (max > z_max)
- z_max = max;
- }
-
- {
-
- CameraMatrix ortho_camera;
- real_t half_x = (x_max_cam - x_min_cam) * 0.5;
- real_t half_y = (y_max_cam - y_min_cam) * 0.5;
-
- ortho_camera.set_orthogonal(-half_x, half_x, -half_y, half_y, 0, (z_max - z_min_cam));
-
- Transform ortho_transform;
- ortho_transform.basis = transform.basis;
- ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max;
-
- VSG::scene_render->light_instance_set_shadow_transform(light->instance, ortho_camera, ortho_transform, 0, distances[i + 1], i, bias_scale);
- }
-
- VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
- }
-
- } break;
- case VS::LIGHT_OMNI: {
-
- VS::LightOmniShadowMode shadow_mode = VSG::storage->light_omni_get_shadow_mode(p_instance->base);
-
- if (shadow_mode == VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !VSG::scene_render->light_instances_can_render_shadow_cube()) {
-
- for (int i = 0; i < 2; i++) {
-
- //using this one ensures that raster deferred will have it
- RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i));
-
- float radius = VSG::storage->light_get_param(p_instance->base, VS::LIGHT_PARAM_RANGE);
-
- float z = i == 0 ? -1 : 1;
- Vector<Plane> planes;
- planes.resize(5);
- planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius));
- planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius));
- planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius));
- planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius));
- planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius));
-
- int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
- Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z);
-
- for (int j = 0; j < cull_count; j++) {
-
- Instance *instance = instance_shadow_cull_result[j];
- if (!instance->visible || !((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
- cull_count--;
- SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
- j--;
- } else {
- if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
- animated_material_found = true;
- }
-
- instance->depth = near_plane.distance_to(instance->transform.origin);
- instance->depth_layer = 0;
- }
- }
-
- VSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i);
- VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
- }
- } else { //shadow cube
-
- float radius = VSG::storage->light_get_param(p_instance->base, VS::LIGHT_PARAM_RANGE);
- CameraMatrix cm;
- cm.set_perspective(90, 1, 0.01, radius);
-
- for (int i = 0; i < 6; i++) {
-
- RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i));
- //using this one ensures that raster deferred will have it
-
- 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)
- };
-
- Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]);
-
- Vector<Plane> planes = cm.get_projection_planes(xform);
-
- int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
-
- Plane near_plane(xform.origin, -xform.basis.get_axis(2));
- for (int j = 0; j < cull_count; j++) {
-
- Instance *instance = instance_shadow_cull_result[j];
- if (!instance->visible || !((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
- cull_count--;
- SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
- j--;
- } else {
- if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
- animated_material_found = true;
- }
- instance->depth = near_plane.distance_to(instance->transform.origin);
- instance->depth_layer = 0;
- }
- }
-
- VSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i);
- VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, i, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
- }
-
- //restore the regular DP matrix
- VSG::scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0);
- }
-
- } break;
- case VS::LIGHT_SPOT: {
-
- RENDER_TIMESTAMP("Culling Spot Light");
-
- float radius = VSG::storage->light_get_param(p_instance->base, VS::LIGHT_PARAM_RANGE);
- float angle = VSG::storage->light_get_param(p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
-
- CameraMatrix cm;
- cm.set_perspective(angle * 2.0, 1.0, 0.01, radius);
-
- Vector<Plane> planes = cm.get_projection_planes(light_transform);
- int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
-
- Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2));
- for (int j = 0; j < cull_count; j++) {
-
- Instance *instance = instance_shadow_cull_result[j];
- if (!instance->visible || !((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) {
- cull_count--;
- SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]);
- j--;
- } else {
- if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) {
- animated_material_found = true;
- }
- instance->depth = near_plane.distance_to(instance->transform.origin);
- instance->depth_layer = 0;
- }
- }
-
- VSG::scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0);
- VSG::scene_render->render_shadow(light->instance, p_shadow_atlas, 0, (RasterizerScene::InstanceBase **)instance_shadow_cull_result, cull_count);
-
- } break;
- }
-
- return animated_material_found;
-}
-
-void VisualServerScene::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) {
-// render to mono camera
-#ifndef _3D_DISABLED
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
-
- /* STEP 1 - SETUP CAMERA */
- CameraMatrix camera_matrix;
- bool ortho = false;
-
- switch (camera->type) {
- case Camera::ORTHOGONAL: {
-
- camera_matrix.set_orthogonal(
- camera->size,
- p_viewport_size.width / (float)p_viewport_size.height,
- camera->znear,
- camera->zfar,
- camera->vaspect);
- ortho = true;
- } break;
- case Camera::PERSPECTIVE: {
-
- camera_matrix.set_perspective(
- camera->fov,
- p_viewport_size.width / (float)p_viewport_size.height,
- camera->znear,
- camera->zfar,
- camera->vaspect);
- ortho = false;
-
- } break;
- case Camera::FRUSTUM: {
-
- camera_matrix.set_frustum(
- camera->size,
- p_viewport_size.width / (float)p_viewport_size.height,
- camera->offset,
- camera->znear,
- camera->zfar,
- camera->vaspect);
- ortho = false;
- } break;
- }
-
- _prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
- _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1);
-#endif
-}
-
-void VisualServerScene::render_camera(RID p_render_buffers, Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) {
- // render for AR/VR interface
-
- Camera *camera = camera_owner.getornull(p_camera);
- ERR_FAIL_COND(!camera);
-
- /* SETUP CAMERA, we are ignoring type and FOV here */
- float aspect = p_viewport_size.width / (float)p_viewport_size.height;
- CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar);
-
- // We also ignore our camera position, it will have been positioned with a slightly old tracking position.
- // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo!
- Transform world_origin = ARVRServer::get_singleton()->get_world_origin();
- Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin);
-
- // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye
- if (p_eye == ARVRInterface::EYE_LEFT) {
- ///@TODO possibly move responsibility for this into our ARVRServer or ARVRInterface?
-
- // Center our transform, we assume basis is equal.
- Transform mono_transform = cam_transform;
- Transform right_transform = p_interface->get_transform_for_eye(ARVRInterface::EYE_RIGHT, world_origin);
- mono_transform.origin += right_transform.origin;
- mono_transform.origin *= 0.5;
-
- // We need to combine our projection frustums for culling.
- // Ideally we should use our clipping planes for this and combine them,
- // however our shadow map logic uses our projection matrix.
- // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix.
-
- // - get some base values we need
- float eye_dist = (mono_transform.origin - cam_transform.origin).length();
- float z_near = camera_matrix.get_z_near(); // get our near plane
- float z_far = camera_matrix.get_z_far(); // get our far plane
- float width = (2.0 * z_near) / camera_matrix.matrix[0][0];
- float x_shift = width * camera_matrix.matrix[2][0];
- float height = (2.0 * z_near) / camera_matrix.matrix[1][1];
- float y_shift = height * camera_matrix.matrix[2][1];
-
- // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift);
-
- // - calculate our near plane size (horizontal only, right_near is mirrored)
- float left_near = -eye_dist - ((width - x_shift) * 0.5);
-
- // - calculate our far plane size (horizontal only, right_far is mirrored)
- float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near);
- float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near);
- if (left_far > left_far_right_eye) {
- // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes.
- left_far = left_far_right_eye;
- }
-
- // - figure out required z-shift
- float slope = (left_far - left_near) / (z_far - z_near);
- float z_shift = (left_near / slope) - z_near;
-
- // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift)
- float top_near = (height - y_shift) * 0.5;
- top_near += (top_near / z_near) * z_shift;
- float bottom_near = -(height + y_shift) * 0.5;
- bottom_near += (bottom_near / z_near) * z_shift;
-
- // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift);
-
- // - generate our frustum
- CameraMatrix combined_matrix;
- combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift);
-
- // and finally move our camera back
- Transform apply_z_shift;
- apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards
- mono_transform *= apply_z_shift;
-
- // now prepare our scene with our adjusted transform projection matrix
- _prepare_scene(mono_transform, combined_matrix, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
- } else if (p_eye == ARVRInterface::EYE_MONO) {
- // For mono render, prepare as per usual
- _prepare_scene(cam_transform, camera_matrix, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
- }
-
- // And render our scene...
- _render_scene(p_render_buffers, cam_transform, camera_matrix, false, camera->env, camera->effects, p_scenario, p_shadow_atlas, RID(), -1);
-};
-
-void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, 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
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
-
- render_pass++;
- uint32_t camera_layer_mask = p_visible_layers;
-
- VSG::scene_render->set_scene_pass(render_pass);
-
- RENDER_TIMESTAMP("Frustum Culling");
-
- //rasterizer->set_camera(camera->transform, camera_matrix,ortho);
-
- Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform);
-
- Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized());
- float z_far = p_cam_projection.get_z_far();
-
- /* STEP 2 - CULL */
- instance_cull_count = scenario->octree.cull_convex(planes, instance_cull_result, MAX_INSTANCE_CULL);
- light_cull_count = 0;
-
- reflection_probe_cull_count = 0;
- gi_probe_cull_count = 0;
-
- //light_samplers_culled=0;
-
- /*
- print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0));
- print_line("OTO: "+itos(p_scenario->octree.get_octant_count()));
- print_line("OTE: "+itos(p_scenario->octree.get_elem_count()));
- print_line("OTP: "+itos(p_scenario->octree.get_pair_count()));
- */
-
- /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */
- //removed, will replace with culling
-
- /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */
-
- for (int i = 0; i < instance_cull_count; i++) {
-
- Instance *ins = instance_cull_result[i];
-
- bool keep = false;
-
- if ((camera_layer_mask & ins->layer_mask) == 0) {
- //failure
- } else if (ins->base_type == VS::INSTANCE_LIGHT && ins->visible) {
-
- if (light_cull_count < MAX_LIGHTS_CULLED) {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
-
- if (!light->geometries.empty()) {
- //do not add this light if no geometry is affected by it..
- light_cull_result[light_cull_count] = ins;
- light_instance_cull_result[light_cull_count] = light->instance;
- if (p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(ins->base)) {
- VSG::scene_render->light_instance_mark_visible(light->instance); //mark it visible for shadow allocation later
- }
-
- light_cull_count++;
- }
- }
- } else if (ins->base_type == VS::INSTANCE_REFLECTION_PROBE && ins->visible) {
-
- if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data);
-
- if (p_reflection_probe != reflection_probe->instance) {
- //avoid entering The Matrix
-
- if (!reflection_probe->geometries.empty()) {
- //do not add this light if no geometry is affected by it..
-
- if (reflection_probe->reflection_dirty || VSG::scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) {
- if (!reflection_probe->update_list.in_list()) {
- reflection_probe->render_step = 0;
- reflection_probe_render_list.add_last(&reflection_probe->update_list);
- }
-
- reflection_probe->reflection_dirty = false;
- }
-
- if (VSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) {
- reflection_probe_instance_cull_result[reflection_probe_cull_count] = reflection_probe->instance;
- reflection_probe_cull_count++;
- }
- }
- }
- }
-
- } else if (ins->base_type == VS::INSTANCE_GI_PROBE && ins->visible) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(ins->base_data);
- if (!gi_probe->update_element.in_list()) {
- gi_probe_update_list.add(&gi_probe->update_element);
- }
-
- if (gi_probe_cull_count < MAX_GI_PROBES_CULLED) {
- gi_probe_instance_cull_result[gi_probe_cull_count] = gi_probe->probe_instance;
- gi_probe_cull_count++;
- }
-
- } else if (((1 << ins->base_type) & VS::INSTANCE_GEOMETRY_MASK) && ins->visible && ins->cast_shadows != VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
-
- keep = true;
-
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data);
-
- if (ins->redraw_if_visible) {
- VisualServerRaster::redraw_request();
- }
-
- if (ins->base_type == VS::INSTANCE_PARTICLES) {
- //particles visible? process them
- if (VSG::storage->particles_is_inactive(ins->base)) {
- //but if nothing is going on, don't do it.
- keep = false;
- } else {
- VSG::storage->particles_request_process(ins->base);
- //particles visible? request redraw
- VisualServerRaster::redraw_request();
- }
- }
-
- if (geom->lighting_dirty) {
- int l = 0;
- //only called when lights AABB enter/exit this geometry
- ins->light_instances.resize(geom->lighting.size());
-
- for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) {
-
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
-
- ins->light_instances.write[l++] = light->instance;
- }
-
- geom->lighting_dirty = false;
- }
-
- if (geom->reflection_dirty) {
- int l = 0;
- //only called when reflection probe AABB enter/exit this geometry
- ins->reflection_probe_instances.resize(geom->reflection_probes.size());
-
- for (List<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
-
- ins->reflection_probe_instances.write[l++] = reflection_probe->instance;
- }
-
- geom->reflection_dirty = false;
- }
-
- if (geom->gi_probes_dirty) {
- int l = 0;
- //only called when reflection probe AABB enter/exit this geometry
- ins->gi_probe_instances.resize(geom->gi_probes.size());
-
- for (List<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) {
-
- InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data);
-
- ins->gi_probe_instances.write[l++] = gi_probe->probe_instance;
- }
-
- geom->gi_probes_dirty = false;
- }
-
- ins->depth = near_plane.distance_to(ins->transform.origin);
- ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15);
- }
-
- if (!keep) {
- // remove, no reason to keep
- instance_cull_count--;
- SWAP(instance_cull_result[i], instance_cull_result[instance_cull_count]);
- i--;
- ins->last_render_pass = 0; // make invalid
- } else {
-
- ins->last_render_pass = render_pass;
- }
- }
-
- /* STEP 5 - PROCESS LIGHTS */
-
- RID *directional_light_ptr = &light_instance_cull_result[light_cull_count];
- directional_light_count = 0;
-
- // directional lights
- {
-
- Instance **lights_with_shadow = (Instance **)alloca(sizeof(Instance *) * scenario->directional_lights.size());
- int directional_shadow_count = 0;
-
- for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) {
-
- if (light_cull_count + directional_light_count >= MAX_LIGHTS_CULLED) {
- break;
- }
-
- if (!E->get()->visible)
- continue;
-
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
-
- //check shadow..
-
- if (light) {
- if (p_using_shadows && p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) {
- lights_with_shadow[directional_shadow_count++] = E->get();
- }
- //add to list
- directional_light_ptr[directional_light_count++] = light->instance;
- }
- }
-
- VSG::scene_render->set_directional_shadow_count(directional_shadow_count);
-
- for (int i = 0; i < directional_shadow_count; i++) {
-
- RENDER_TIMESTAMP(">Rendering Directional Light " + itos(i));
-
- _light_instance_update_shadow(lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario);
-
- RENDER_TIMESTAMP("<Rendering Directional Light " + itos(i));
- }
- }
-
- if (p_using_shadows) { //setup shadow maps
-
- //SortArray<Instance*,_InstanceLightsort> sorter;
- //sorter.sort(light_cull_result,light_cull_count);
- for (int i = 0; i < light_cull_count; i++) {
-
- Instance *ins = light_cull_result[i];
-
- if (!p_shadow_atlas.is_valid() || !VSG::storage->light_has_shadow(ins->base))
- continue;
-
- InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
-
- float coverage = 0.f;
-
- { //compute coverage
-
- Transform cam_xf = p_cam_transform;
- float zn = p_cam_projection.get_z_near();
- Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane
-
- // near plane half width and height
- Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents();
-
- switch (VSG::storage->light_get_type(ins->base)) {
-
- case VS::LIGHT_OMNI: {
-
- float radius = VSG::storage->light_get_param(ins->base, VS::LIGHT_PARAM_RANGE);
-
- //get two points parallel to near plane
- Vector3 points[2] = {
- ins->transform.origin,
- ins->transform.origin + cam_xf.basis.get_axis(0) * radius
- };
-
- if (!p_cam_orthogonal) {
- //if using perspetive, map them to near plane
- for (int j = 0; j < 2; j++) {
- if (p.distance_to(points[j]) < 0) {
- points[j].z = -zn; //small hack to keep size constant when hitting the screen
- }
-
- p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane
- }
- }
-
- float screen_diameter = points[0].distance_to(points[1]) * 2;
- coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y);
- } break;
- case VS::LIGHT_SPOT: {
-
- float radius = VSG::storage->light_get_param(ins->base, VS::LIGHT_PARAM_RANGE);
- float angle = VSG::storage->light_get_param(ins->base, VS::LIGHT_PARAM_SPOT_ANGLE);
-
- float w = radius * Math::sin(Math::deg2rad(angle));
- float d = radius * Math::cos(Math::deg2rad(angle));
-
- Vector3 base = ins->transform.origin - ins->transform.basis.get_axis(2).normalized() * d;
-
- Vector3 points[2] = {
- base,
- base + cam_xf.basis.get_axis(0) * w
- };
-
- if (!p_cam_orthogonal) {
- //if using perspetive, map them to near plane
- for (int j = 0; j < 2; j++) {
- if (p.distance_to(points[j]) < 0) {
- points[j].z = -zn; //small hack to keep size constant when hitting the screen
- }
-
- p.intersects_segment(cam_xf.origin, points[j], &points[j]); //map to plane
- }
- }
-
- float screen_diameter = points[0].distance_to(points[1]) * 2;
- coverage = screen_diameter / (vp_half_extents.x + vp_half_extents.y);
-
- } break;
- default: {
- ERR_PRINT("Invalid Light Type");
- }
- }
- }
-
- if (light->shadow_dirty) {
- light->last_version++;
- light->shadow_dirty = false;
- }
-
- bool redraw = VSG::scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
-
- if (redraw) {
- //must redraw!
- RENDER_TIMESTAMP(">Rendering Light " + itos(i));
- light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario);
- RENDER_TIMESTAMP("<Rendering Light " + itos(i));
- }
- }
- }
-}
-
-void VisualServerScene::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
-
- /* ENVIRONMENT */
-
- RID environment;
- if (p_force_environment.is_valid()) //camera has more environment priority
- environment = p_force_environment;
- else if (scenario->environment.is_valid())
- environment = scenario->environment;
- else
- environment = scenario->fallback_environment;
-
- RID camera_effects;
- if (p_force_camera_effects.is_valid()) {
- camera_effects = p_force_camera_effects;
- } else {
- camera_effects = scenario->camera_effects;
- }
- /* PROCESS GEOMETRY AND DRAW SCENE */
-
- RENDER_TIMESTAMP("Render Scene ");
- VSG::scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, instance_cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, gi_probe_instance_cull_result, gi_probe_cull_count, environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass);
-}
-
-void VisualServerScene::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) {
-
-#ifndef _3D_DISABLED
-
- Scenario *scenario = scenario_owner.getornull(p_scenario);
-
- RID environment;
- if (scenario->environment.is_valid())
- environment = scenario->environment;
- else
- environment = scenario->fallback_environment;
- RENDER_TIMESTAMP("Render Empty Scene ");
- VSG::scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, NULL, 0, environment, RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0);
-#endif
-}
-
-bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int p_step) {
-
- InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
- Scenario *scenario = p_instance->scenario;
- ERR_FAIL_COND_V(!scenario, true);
-
- VisualServerRaster::redraw_request(); //update, so it updates in editor
-
- if (p_step == 0) {
-
- if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
- return true; //all full
- }
- }
-
- if (p_step >= 0 && p_step < 6) {
-
- 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)
- };
-
- Vector3 extents = VSG::storage->reflection_probe_get_extents(p_instance->base);
- Vector3 origin_offset = VSG::storage->reflection_probe_get_origin_offset(p_instance->base);
- float max_distance = VSG::storage->reflection_probe_get_origin_max_distance(p_instance->base);
-
- Vector3 edge = view_normals[p_step] * extents;
- float distance = ABS(view_normals[p_step].dot(edge) - view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit
-
- max_distance = MAX(max_distance, distance);
-
- //render cubemap side
- CameraMatrix cm;
- cm.set_perspective(90, 1, 0.01, max_distance);
-
- Transform local_view;
- local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]);
-
- Transform xform = p_instance->transform * local_view;
-
- RID shadow_atlas;
-
- bool use_shadows = VSG::storage->reflection_probe_renders_shadows(p_instance->base);
- if (use_shadows) {
-
- shadow_atlas = scenario->reflection_probe_shadow_atlas;
- }
-
- RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
- _prepare_scene(xform, cm, false, RID(), RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, use_shadows);
- _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step);
-
- } else {
- //do roughness postprocess step until it believes it's done
- RENDER_TIMESTAMP("Post-Process Reflection Probe, Step " + itos(p_step));
- return VSG::scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance);
- }
-
- return false;
-}
-
-void VisualServerScene::render_probes() {
-
- /* REFLECTION PROBES */
-
- SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first();
-
- bool busy = false;
-
- while (ref_probe) {
-
- SelfList<InstanceReflectionProbeData> *next = ref_probe->next();
- RID base = ref_probe->self()->owner->base;
-
- switch (VSG::storage->reflection_probe_get_update_mode(base)) {
-
- case VS::REFLECTION_PROBE_UPDATE_ONCE: {
- if (busy) //already rendering something
- break;
-
- bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step);
- if (done) {
- reflection_probe_render_list.remove(ref_probe);
- } else {
- ref_probe->self()->render_step++;
- }
-
- busy = true; //do not render another one of this kind
- } break;
- case VS::REFLECTION_PROBE_UPDATE_ALWAYS: {
-
- int step = 0;
- bool done = false;
- while (!done) {
- done = _render_reflection_probe_step(ref_probe->self()->owner, step);
- step++;
- }
-
- reflection_probe_render_list.remove(ref_probe);
- } break;
- }
-
- ref_probe = next;
- }
-
- /* GI PROBES */
-
- SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
-
- if (gi_probe) {
- RENDER_TIMESTAMP("Render GI Probes");
- }
-
- while (gi_probe) {
-
- SelfList<InstanceGIProbeData> *next = gi_probe->next();
-
- InstanceGIProbeData *probe = gi_probe->self();
- //Instance *instance_probe = probe->owner;
-
- //check if probe must be setup, but don't do if on the lighting thread
-
- bool cache_dirty = false;
- int cache_count = 0;
- {
-
- int light_cache_size = probe->light_cache.size();
- const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr();
- const RID *instance_caches = probe->light_instances.ptr();
-
- int idx = 0; //must count visible lights
- for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
- Instance *instance = E->get();
- InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
- if (!instance->visible) {
- continue;
- }
- if (cache_dirty) {
- //do nothing, since idx must count all visible lights anyway
- } else if (idx >= light_cache_size) {
- cache_dirty = true;
- } else {
-
- const InstanceGIProbeData::LightCache *cache = &caches[idx];
-
- if (
- instance_caches[idx] != instance_light->instance ||
- cache->has_shadow != VSG::storage->light_has_shadow(instance->base) ||
- cache->type != VSG::storage->light_get_type(instance->base) ||
- cache->transform != instance->transform ||
- cache->color != VSG::storage->light_get_color(instance->base) ||
- cache->energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY) ||
- cache->bake_energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY) ||
- cache->radius != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE) ||
- cache->attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION) ||
- cache->spot_angle != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE) ||
- cache->spot_attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION)) {
- cache_dirty = true;
- }
- }
-
- idx++;
- }
-
- for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
-
- Instance *instance = E->get();
- InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
- if (!instance->visible) {
- continue;
- }
- if (cache_dirty) {
- //do nothing, since idx must count all visible lights anyway
- } else if (idx >= light_cache_size) {
- cache_dirty = true;
- } else {
-
- const InstanceGIProbeData::LightCache *cache = &caches[idx];
-
- if (
- instance_caches[idx] != instance_light->instance ||
- cache->has_shadow != VSG::storage->light_has_shadow(instance->base) ||
- cache->type != VSG::storage->light_get_type(instance->base) ||
- cache->transform != instance->transform ||
- cache->color != VSG::storage->light_get_color(instance->base) ||
- cache->energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY) ||
- cache->bake_energy != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY) ||
- cache->radius != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE) ||
- cache->attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION) ||
- cache->spot_angle != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE) ||
- cache->spot_attenuation != VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION)) {
- cache_dirty = true;
- }
- }
-
- idx++;
- }
-
- if (idx != light_cache_size) {
- cache_dirty = true;
- }
-
- cache_count = idx;
- }
-
- bool update_lights = VSG::scene_render->gi_probe_needs_update(probe->probe_instance);
-
- if (cache_dirty) {
- probe->light_cache.resize(cache_count);
- probe->light_instances.resize(cache_count);
-
- if (cache_count) {
- InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw();
- RID *instance_caches = probe->light_instances.ptrw();
-
- int idx = 0; //must count visible lights
- for (Set<Instance *>::Element *E = probe->lights.front(); E; E = E->next()) {
- Instance *instance = E->get();
- InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
- if (!instance->visible) {
- continue;
- }
-
- InstanceGIProbeData::LightCache *cache = &caches[idx];
-
- instance_caches[idx] = instance_light->instance;
- cache->has_shadow = VSG::storage->light_has_shadow(instance->base);
- cache->type = VSG::storage->light_get_type(instance->base);
- cache->transform = instance->transform;
- cache->color = VSG::storage->light_get_color(instance->base);
- cache->energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY);
- cache->bake_energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- cache->radius = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE);
- cache->attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION);
- cache->spot_angle = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
- cache->spot_attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- idx++;
- }
- for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) {
- Instance *instance = E->get();
- InstanceLightData *instance_light = (InstanceLightData *)instance->base_data;
- if (!instance->visible) {
- continue;
- }
-
- InstanceGIProbeData::LightCache *cache = &caches[idx];
-
- instance_caches[idx] = instance_light->instance;
- cache->has_shadow = VSG::storage->light_has_shadow(instance->base);
- cache->type = VSG::storage->light_get_type(instance->base);
- cache->transform = instance->transform;
- cache->color = VSG::storage->light_get_color(instance->base);
- cache->energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ENERGY);
- cache->bake_energy = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_INDIRECT_ENERGY);
- cache->radius = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_RANGE);
- cache->attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_ATTENUATION);
- cache->spot_angle = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ANGLE);
- cache->spot_attenuation = VSG::storage->light_get_param(instance->base, VS::LIGHT_PARAM_SPOT_ATTENUATION);
-
- idx++;
- }
- }
-
- update_lights = true;
- }
-
- instance_cull_count = 0;
- for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) {
- if (instance_cull_count < MAX_INSTANCE_CULL) {
- Instance *ins = E->get().geometry;
- if (!ins->visible) {
- continue;
- }
- InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
-
- if (geom->gi_probes_dirty) {
- //giprobes may be dirty, so update
- int l = 0;
- //only called when reflection probe AABB enter/exit this geometry
- ins->gi_probe_instances.resize(geom->gi_probes.size());
-
- for (List<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) {
-
- InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data);
-
- ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance;
- }
-
- geom->gi_probes_dirty = false;
- }
-
- instance_cull_result[instance_cull_count++] = E->get().geometry;
- }
- }
-
- VSG::scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, instance_cull_count, (RasterizerScene::InstanceBase **)instance_cull_result);
-
- gi_probe_update_list.remove(gi_probe);
-
- gi_probe = next;
- }
-}
-
-void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
-
- if (p_instance->update_aabb) {
- _update_instance_aabb(p_instance);
- }
-
- if (p_instance->update_dependencies) {
-
- p_instance->instance_increase_version();
-
- if (p_instance->base.is_valid()) {
- VSG::storage->base_update_dependency(p_instance->base, p_instance);
- }
-
- if (p_instance->material_override.is_valid()) {
- VSG::storage->material_update_dependency(p_instance->material_override, p_instance);
- }
-
- if (p_instance->base_type == VS::INSTANCE_MESH) {
- //remove materials no longer used and un-own them
-
- int new_mat_count = VSG::storage->mesh_get_surface_count(p_instance->base);
- p_instance->materials.resize(new_mat_count);
-
- int new_blend_shape_count = VSG::storage->mesh_get_blend_shape_count(p_instance->base);
- if (new_blend_shape_count != p_instance->blend_values.size()) {
- p_instance->blend_values.resize(new_blend_shape_count);
- for (int i = 0; i < new_blend_shape_count; i++) {
- p_instance->blend_values.write[i] = 0;
- }
- }
- }
-
- if ((1 << p_instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) {
-
- InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
-
- bool can_cast_shadows = true;
- bool is_animated = false;
-
- if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) {
- can_cast_shadows = false;
- } else if (p_instance->material_override.is_valid()) {
- can_cast_shadows = VSG::storage->material_casts_shadows(p_instance->material_override);
- is_animated = VSG::storage->material_is_animated(p_instance->material_override);
- } else {
-
- if (p_instance->base_type == VS::INSTANCE_MESH) {
- RID mesh = p_instance->base;
-
- if (mesh.is_valid()) {
- bool cast_shadows = false;
-
- for (int i = 0; i < p_instance->materials.size(); i++) {
-
- RID mat = p_instance->materials[i].is_valid() ? p_instance->materials[i] : VSG::storage->mesh_surface_get_material(mesh, i);
-
- if (!mat.is_valid()) {
- cast_shadows = true;
- } else {
-
- if (VSG::storage->material_casts_shadows(mat)) {
- cast_shadows = true;
- }
-
- if (VSG::storage->material_is_animated(mat)) {
- is_animated = true;
- }
-
- VSG::storage->material_update_dependency(mat, p_instance);
- }
- }
-
- if (!cast_shadows) {
- can_cast_shadows = false;
- }
- }
-
- } else if (p_instance->base_type == VS::INSTANCE_MULTIMESH) {
- RID mesh = VSG::storage->multimesh_get_mesh(p_instance->base);
- if (mesh.is_valid()) {
-
- bool cast_shadows = false;
-
- int sc = VSG::storage->mesh_get_surface_count(mesh);
- for (int i = 0; i < sc; i++) {
-
- RID mat = VSG::storage->mesh_surface_get_material(mesh, i);
-
- if (!mat.is_valid()) {
- cast_shadows = true;
-
- } else {
-
- if (VSG::storage->material_casts_shadows(mat)) {
- cast_shadows = true;
- }
- if (VSG::storage->material_is_animated(mat)) {
- is_animated = true;
- }
-
- VSG::storage->material_update_dependency(mat, p_instance);
- }
- }
-
- if (!cast_shadows) {
- can_cast_shadows = false;
- }
-
- VSG::storage->base_update_dependency(mesh, p_instance);
- }
- } else if (p_instance->base_type == VS::INSTANCE_IMMEDIATE) {
-
- RID mat = VSG::storage->immediate_get_material(p_instance->base);
-
- can_cast_shadows = !mat.is_valid() || VSG::storage->material_casts_shadows(mat);
-
- if (mat.is_valid() && VSG::storage->material_is_animated(mat)) {
- is_animated = true;
- }
-
- if (mat.is_valid()) {
- VSG::storage->material_update_dependency(mat, p_instance);
- }
-
- } else if (p_instance->base_type == VS::INSTANCE_PARTICLES) {
-
- bool cast_shadows = false;
-
- int dp = VSG::storage->particles_get_draw_passes(p_instance->base);
-
- for (int i = 0; i < dp; i++) {
-
- RID mesh = VSG::storage->particles_get_draw_pass_mesh(p_instance->base, i);
- if (!mesh.is_valid())
- continue;
-
- int sc = VSG::storage->mesh_get_surface_count(mesh);
- for (int j = 0; j < sc; j++) {
-
- RID mat = VSG::storage->mesh_surface_get_material(mesh, j);
-
- if (!mat.is_valid()) {
- cast_shadows = true;
- } else {
-
- if (VSG::storage->material_casts_shadows(mat)) {
- cast_shadows = true;
- }
-
- if (VSG::storage->material_is_animated(mat)) {
- is_animated = true;
- }
-
- VSG::storage->material_update_dependency(mat, p_instance);
- }
- }
- }
-
- if (!cast_shadows) {
- can_cast_shadows = false;
- }
- }
- }
-
- if (can_cast_shadows != geom->can_cast_shadows) {
- //ability to cast shadows change, let lights now
- for (List<Instance *>::Element *E = geom->lighting.front(); E; E = E->next()) {
- InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
- light->shadow_dirty = true;
- }
-
- geom->can_cast_shadows = can_cast_shadows;
- }
-
- geom->material_is_animated = is_animated;
- }
-
- if (p_instance->skeleton.is_valid()) {
- VSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance);
- }
-
- p_instance->clean_up_dependencies();
- }
-
- _instance_update_list.remove(&p_instance->update_item);
-
- _update_instance(p_instance);
-
- p_instance->update_aabb = false;
- p_instance->update_dependencies = false;
-}
-
-void VisualServerScene::update_dirty_instances() {
-
- VSG::storage->update_dirty_resources();
-
- while (_instance_update_list.first()) {
-
- _update_dirty_instance(_instance_update_list.first()->self());
- }
-}
-
-bool VisualServerScene::free(RID p_rid) {
-
- if (camera_owner.owns(p_rid)) {
-
- Camera *camera = camera_owner.getornull(p_rid);
-
- camera_owner.free(p_rid);
- memdelete(camera);
-
- } else if (scenario_owner.owns(p_rid)) {
-
- Scenario *scenario = scenario_owner.getornull(p_rid);
-
- while (scenario->instances.first()) {
- instance_set_scenario(scenario->instances.first()->self()->self, RID());
- }
- VSG::scene_render->free(scenario->reflection_probe_shadow_atlas);
- VSG::scene_render->free(scenario->reflection_atlas);
- scenario_owner.free(p_rid);
- memdelete(scenario);
-
- } else if (instance_owner.owns(p_rid)) {
- // delete the instance
-
- update_dirty_instances();
-
- Instance *instance = instance_owner.getornull(p_rid);
-
- instance_set_use_lightmap(p_rid, RID(), RID());
- instance_set_scenario(p_rid, RID());
- instance_set_base(p_rid, RID());
- instance_geometry_set_material_override(p_rid, RID());
- instance_attach_skeleton(p_rid, RID());
-
- update_dirty_instances(); //in case something changed this
-
- instance_owner.free(p_rid);
- memdelete(instance);
- } else {
- return false;
- }
-
- return true;
-}
-
-VisualServerScene *VisualServerScene::singleton = NULL;
-
-VisualServerScene::VisualServerScene() {
-
- render_pass = 1;
- singleton = this;
-}
-
-VisualServerScene::~VisualServerScene() {
-}
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
deleted file mode 100644
index 8dbd60d3ff..0000000000
--- a/servers/visual/visual_server_scene.h
+++ /dev/null
@@ -1,440 +0,0 @@
-/*************************************************************************/
-/* visual_server_scene.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUALSERVERSCENE_H
-#define VISUALSERVERSCENE_H
-
-#include "servers/visual/rasterizer.h"
-
-#include "core/math/geometry.h"
-#include "core/math/octree.h"
-#include "core/os/semaphore.h"
-#include "core/os/thread.h"
-#include "core/rid_owner.h"
-#include "core/self_list.h"
-#include "servers/arvr/arvr_interface.h"
-
-class VisualServerScene {
-public:
- enum {
-
- MAX_INSTANCE_CULL = 65536,
- MAX_LIGHTS_CULLED = 4096,
- MAX_REFLECTION_PROBES_CULLED = 4096,
- MAX_GI_PROBES_CULLED = 4096,
- MAX_ROOM_CULL = 32,
- MAX_EXTERIOR_PORTALS = 128,
- };
-
- uint64_t render_pass;
-
- static VisualServerScene *singleton;
-
- /* CAMERA API */
-
- struct Camera {
-
- enum Type {
- PERSPECTIVE,
- ORTHOGONAL,
- FRUSTUM
- };
- Type type;
- float fov;
- float znear, zfar;
- float size;
- Vector2 offset;
- uint32_t visible_layers;
- bool vaspect;
- RID env;
- RID effects;
-
- Transform transform;
-
- Camera() {
-
- visible_layers = 0xFFFFFFFF;
- fov = 70;
- type = PERSPECTIVE;
- znear = 0.05;
- zfar = 100;
- size = 1.0;
- offset = Vector2();
- vaspect = false;
- }
- };
-
- mutable RID_PtrOwner<Camera> camera_owner;
-
- 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);
- virtual void camera_set_transform(RID p_camera, const Transform &p_transform);
- virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
- virtual void camera_set_environment(RID p_camera, RID p_env);
- virtual void camera_set_camera_effects(RID p_camera, RID p_fx);
- virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
-
- /* SCENARIO API */
-
- struct Instance;
-
- struct Scenario {
-
- VS::ScenarioDebugMode debug;
- RID self;
-
- Octree<Instance, true> octree;
-
- List<Instance *> directional_lights;
- RID environment;
- RID fallback_environment;
- RID camera_effects;
- RID reflection_probe_shadow_atlas;
- RID reflection_atlas;
-
- SelfList<Instance>::List instances;
-
- Scenario() { debug = VS::SCENARIO_DEBUG_DISABLED; }
- };
-
- mutable RID_PtrOwner<Scenario> scenario_owner;
-
- static void *_instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int);
- static void _instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *);
-
- virtual RID scenario_create();
-
- virtual void scenario_set_debug(RID p_scenario, VS::ScenarioDebugMode p_debug_mode);
- virtual void scenario_set_environment(RID p_scenario, RID p_environment);
- virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx);
- virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment);
- virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
-
- /* INSTANCING API */
-
- struct InstanceBaseData {
-
- virtual ~InstanceBaseData() {}
- };
-
- struct Instance : RasterizerScene::InstanceBase {
-
- RID self;
- //scenario stuff
- OctreeElementID octree_id;
- Scenario *scenario;
- SelfList<Instance> scenario_item;
-
- //aabb stuff
- bool update_aabb;
- bool update_dependencies;
-
- SelfList<Instance> update_item;
-
- AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better?
- float extra_margin;
- ObjectID object_id;
-
- float lod_begin;
- float lod_end;
- float lod_begin_hysteresis;
- float lod_end_hysteresis;
- RID lod_instance;
-
- uint64_t last_render_pass;
- uint64_t last_frame_pass;
-
- uint64_t version; // changes to this, and changes to base increase version
-
- InstanceBaseData *base_data;
-
- virtual void dependency_deleted(RID p_dependency) {
- if (p_dependency == base) {
- singleton->instance_set_base(self, RID());
- } else if (p_dependency == skeleton) {
- singleton->instance_attach_skeleton(self, RID());
- } else {
- singleton->_instance_queue_update(this, false, true);
- }
- }
-
- virtual void dependency_changed(bool p_aabb, bool p_dependencies) {
- singleton->_instance_queue_update(this, p_aabb, p_dependencies);
- }
-
- Instance() :
- scenario_item(this),
- update_item(this) {
-
- octree_id = 0;
- scenario = NULL;
-
- update_aabb = false;
- update_dependencies = false;
-
- extra_margin = 0;
-
- visible = true;
-
- lod_begin = 0;
- lod_end = 0;
- lod_begin_hysteresis = 0;
- lod_end_hysteresis = 0;
-
- last_render_pass = 0;
- last_frame_pass = 0;
- version = 1;
- base_data = NULL;
-
- custom_aabb = NULL;
- }
-
- ~Instance() {
-
- if (base_data)
- memdelete(base_data);
- if (custom_aabb)
- memdelete(custom_aabb);
- }
- };
-
- SelfList<Instance>::List _instance_update_list;
- void _instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies = false);
-
- struct InstanceGeometryData : public InstanceBaseData {
-
- List<Instance *> lighting;
- bool lighting_dirty;
- bool can_cast_shadows;
- bool material_is_animated;
-
- List<Instance *> reflection_probes;
- bool reflection_dirty;
-
- List<Instance *> gi_probes;
- bool gi_probes_dirty;
-
- List<Instance *> lightmap_captures;
-
- InstanceGeometryData() {
-
- lighting_dirty = false;
- reflection_dirty = true;
- can_cast_shadows = true;
- material_is_animated = true;
- gi_probes_dirty = true;
- }
- };
-
- struct InstanceReflectionProbeData : public InstanceBaseData {
-
- Instance *owner;
-
- struct PairInfo {
- List<Instance *>::Element *L; //reflection iterator in geometry
- Instance *geometry;
- };
- List<PairInfo> geometries;
-
- RID instance;
- bool reflection_dirty;
- SelfList<InstanceReflectionProbeData> update_list;
-
- int render_step;
-
- InstanceReflectionProbeData() :
- update_list(this) {
-
- reflection_dirty = true;
- render_step = -1;
- }
- };
-
- SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list;
-
- struct InstanceLightData : public InstanceBaseData {
-
- struct PairInfo {
- List<Instance *>::Element *L; //light iterator in geometry
- Instance *geometry;
- };
-
- RID instance;
- uint64_t last_version;
- List<Instance *>::Element *D; // directional light in scenario
-
- bool shadow_dirty;
-
- List<PairInfo> geometries;
-
- Instance *baked_light;
-
- InstanceLightData() {
-
- shadow_dirty = true;
- D = NULL;
- last_version = 0;
- baked_light = NULL;
- }
- };
-
- struct InstanceGIProbeData : public InstanceBaseData {
-
- Instance *owner;
-
- struct PairInfo {
- List<Instance *>::Element *L; //gi probe iterator in geometry
- Instance *geometry;
- };
-
- List<PairInfo> geometries;
- List<PairInfo> dynamic_geometries;
-
- Set<Instance *> lights;
-
- struct LightCache {
-
- VS::LightType type;
- Transform transform;
- Color color;
- float energy;
- float bake_energy;
- float radius;
- float attenuation;
- float spot_angle;
- float spot_attenuation;
- bool has_shadow;
- };
-
- Vector<LightCache> light_cache;
- Vector<RID> light_instances;
-
- RID probe_instance;
-
- bool invalid;
- uint32_t base_version;
-
- SelfList<InstanceGIProbeData> update_element;
-
- InstanceGIProbeData() :
- update_element(this) {
- invalid = true;
- base_version = 0;
- }
- };
-
- SelfList<InstanceGIProbeData>::List gi_probe_update_list;
-
- struct InstanceLightmapCaptureData : public InstanceBaseData {
-
- struct PairInfo {
- List<Instance *>::Element *L; //iterator in geometry
- Instance *geometry;
- };
- List<PairInfo> geometries;
-
- Set<Instance *> users;
-
- InstanceLightmapCaptureData() {
- }
- };
-
- int instance_cull_count;
- Instance *instance_cull_result[MAX_INSTANCE_CULL];
- Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
- Instance *light_cull_result[MAX_LIGHTS_CULLED];
- RID light_instance_cull_result[MAX_LIGHTS_CULLED];
- int light_cull_count;
- int directional_light_count;
- RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED];
- int reflection_probe_cull_count;
- RID gi_probe_instance_cull_result[MAX_GI_PROBES_CULLED];
- int gi_probe_cull_count;
-
- RID_PtrOwner<Instance> instance_owner;
-
- virtual RID instance_create();
-
- virtual void instance_set_base(RID p_instance, RID p_base);
- virtual void instance_set_scenario(RID p_instance, RID p_scenario);
- virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask);
- 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_visible(RID p_instance, bool p_visible);
- virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap);
-
- virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb);
-
- virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton);
- virtual void instance_set_exterior(RID p_instance, bool p_enabled);
-
- virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin);
-
- // don't use these in a game!
- virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const;
- virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
- virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const;
-
- virtual void instance_geometry_set_flag(RID p_instance, VS::InstanceFlags p_flags, bool p_enabled);
- virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting);
- virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
-
- virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin);
- virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance);
-
- _FORCE_INLINE_ void _update_instance(Instance *p_instance);
- _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
- _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
- _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);
-
- _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario);
-
- bool _render_reflection_probe_step(Instance *p_instance, int p_step);
- void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, bool p_using_shadows = true);
- void _render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
- 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, RID p_shadow_atlas);
- void render_camera(RID p_render_buffers, Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);
- void update_dirty_instances();
-
- void render_probes();
-
- bool free(RID p_rid);
-
- VisualServerScene();
- virtual ~VisualServerScene();
-};
-
-#endif // VISUALSERVERSCENE_H
diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp
deleted file mode 100644
index 30fdef9325..0000000000
--- a/servers/visual/visual_server_viewport.cpp
+++ /dev/null
@@ -1,747 +0,0 @@
-/*************************************************************************/
-/* visual_server_viewport.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_viewport.h"
-
-#include "core/project_settings.h"
-#include "visual_server_canvas.h"
-#include "visual_server_globals.h"
-#include "visual_server_scene.h"
-
-static Transform2D _canvas_get_transform(VisualServerViewport::Viewport *p_viewport, VisualServerCanvas::Canvas *p_canvas, VisualServerViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) {
-
- Transform2D xf = p_viewport->global_transform;
-
- float scale = 1.0;
- if (p_viewport->canvas_map.has(p_canvas->parent)) {
- xf = xf * p_viewport->canvas_map[p_canvas->parent].transform;
- scale = p_canvas->parent_scale;
- }
-
- xf = xf * p_canvas_data->transform;
-
- if (scale != 1.0 && !VSG::canvas->disable_scale) {
- Vector2 pivot = p_vp_size * 0.5;
- Transform2D xfpivot;
- xfpivot.set_origin(pivot);
- Transform2D xfscale;
- xfscale.scale(Vector2(scale, scale));
-
- xf = xfpivot.affine_inverse() * xf;
- xf = xfscale * xf;
- xf = xfpivot * xf;
- }
-
- return xf;
-}
-
-void VisualServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye) {
-
- RENDER_TIMESTAMP(">Begin Rendering 3D Scene");
-
- Ref<ARVRInterface> arvr_interface;
- if (ARVRServer::get_singleton() != NULL) {
- arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
- }
-
- if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(p_viewport->render_buffers, arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
- } else {
- VSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
- }
- RENDER_TIMESTAMP("<End Rendering 3D Scene");
-}
-
-void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) {
-
- /* Camera should always be BEFORE any other 3D */
-
- bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
- int scenario_canvas_max_layer = 0;
-
- Color bgcolor = VSG::storage->get_default_clear_color();
-
- if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) {
-
- VisualServerScene::Scenario *scenario = VSG::scene->scenario_owner.getornull(p_viewport->scenario);
- ERR_FAIL_COND(!scenario);
- if (VSG::scene_render->is_environment(scenario->environment)) {
- scenario_draw_canvas_bg = VSG::scene_render->environment_get_background(scenario->environment) == VS::ENV_BG_CANVAS;
-
- scenario_canvas_max_layer = VSG::scene_render->environment_get_canvas_max_layer(scenario->environment);
- }
- }
-
- bool can_draw_3d = VSG::scene->camera_owner.owns(p_viewport->camera);
-
- if (p_viewport->clear_mode != VS::VIEWPORT_CLEAR_NEVER) {
- if (p_viewport->transparent_bg) {
- bgcolor = Color(0, 0, 0, 0);
- }
- if (p_viewport->clear_mode == VS::VIEWPORT_CLEAR_ONLY_NEXT_FRAME) {
- p_viewport->clear_mode = VS::VIEWPORT_CLEAR_NEVER;
- }
- }
-
- if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) {
- //wants to draw 3D but there is no render buffer, create
- p_viewport->render_buffers = VSG::scene_render->render_buffers_create();
- VSG::scene_render->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa);
- }
-
- VSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor);
-
- if (!scenario_draw_canvas_bg && can_draw_3d) {
- _draw_3d(p_viewport, p_eye);
- }
-
- if (!p_viewport->hide_canvas) {
- int i = 0;
-
- Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map;
-
- Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y);
- RasterizerCanvas::Light *lights = NULL;
- RasterizerCanvas::Light *lights_with_shadow = NULL;
- RasterizerCanvas::Light *lights_with_mask = NULL;
- Rect2 shadow_rect;
-
- int light_count = 0;
-
- RENDER_TIMESTAMP("Cull Canvas Lights");
- for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
-
- VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get().canvas);
-
- Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
-
- //find lights in canvas
-
- for (Set<RasterizerCanvas::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) {
-
- RasterizerCanvas::Light *cl = F->get();
- if (cl->enabled && cl->texture.is_valid()) {
- //not super efficient..
- Size2 tsize = VSG::storage->texture_size_with_proxy(cl->texture);
- tsize *= cl->scale;
-
- Vector2 offset = tsize / 2.0;
- cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize);
- cl->xform_cache = xf * cl->xform;
-
- if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) {
-
- cl->filter_next_ptr = lights;
- lights = cl;
- // cl->texture_cache = NULL;
- Transform2D scale;
- scale.scale(cl->rect_cache.size);
- scale.elements[2] = cl->rect_cache.position;
- cl->light_shader_xform = cl->xform * scale;
- //cl->light_shader_pos = cl->xform_cache[2];
- if (cl->use_shadow) {
-
- cl->shadows_next_ptr = lights_with_shadow;
- if (lights_with_shadow == NULL) {
- shadow_rect = cl->xform_cache.xform(cl->rect_cache);
- } else {
- shadow_rect = shadow_rect.merge(cl->xform_cache.xform(cl->rect_cache));
- }
- lights_with_shadow = cl;
- cl->radius_cache = cl->rect_cache.size.length();
- }
- if (cl->mode == VS::CANVAS_LIGHT_MODE_MASK) {
- cl->mask_next_ptr = lights_with_mask;
- lights_with_mask = cl;
- }
-
- light_count++;
- }
-
- //guess this is not needed, but keeping because it may be
- //VSG::canvas_render->light_internal_update(cl->light_internal, cl);
- }
- }
-
- canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get();
- }
-
- if (lights_with_shadow) {
- //update shadows if any
-
- RasterizerCanvas::LightOccluderInstance *occluders = NULL;
-
- RENDER_TIMESTAMP(">Render 2D Shadows");
- RENDER_TIMESTAMP("Cull Occluders");
-
- //make list of occluders
- for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
-
- VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get().canvas);
- Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
-
- for (Set<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
-
- if (!F->get()->enabled)
- continue;
- F->get()->xform_cache = xf * F->get()->xform;
- if (shadow_rect.intersects_transformed(F->get()->xform_cache, F->get()->aabb_cache)) {
-
- F->get()->next = occluders;
- occluders = F->get();
- }
- }
- }
- //update the light shadowmaps with them
-
- RasterizerCanvas::Light *light = lights_with_shadow;
- while (light) {
-
- RENDER_TIMESTAMP("Render Shadow");
-
- VSG::canvas_render->light_update_shadow(light->light_internal, light->xform_cache.affine_inverse(), light->item_shadow_mask, light->radius_cache / 1000.0, light->radius_cache * 1.1, occluders);
- light = light->shadows_next_ptr;
- }
-
- //VSG::canvas_render->reset_canvas();
- RENDER_TIMESTAMP("<End rendering 2D Shadows");
- }
-
- if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) {
- if (!can_draw_3d) {
- VSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
- } else {
- _draw_3d(p_viewport, p_eye);
- }
- scenario_draw_canvas_bg = false;
- }
-
- for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) {
-
- VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get()->canvas);
-
- Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size);
-
- RasterizerCanvas::Light *canvas_lights = NULL;
-
- RasterizerCanvas::Light *ptr = lights;
- while (ptr) {
- if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) {
- ptr->next_ptr = canvas_lights;
- canvas_lights = ptr;
- }
- ptr = ptr->filter_next_ptr;
- }
-
- VSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect);
- i++;
-
- if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
- if (!can_draw_3d) {
- VSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
- } else {
- _draw_3d(p_viewport, p_eye);
- }
-
- scenario_draw_canvas_bg = false;
- }
- }
-
- if (scenario_draw_canvas_bg) {
- if (!can_draw_3d) {
- VSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas);
- } else {
- _draw_3d(p_viewport, p_eye);
- }
- }
-
- //VSG::canvas_render->canvas_debug_viewport_shadows(lights_with_shadow);
- }
-
- if (VSG::storage->render_target_is_clear_requested(p_viewport->render_target)) {
- //was never cleared in the end, force clear it
- VSG::storage->render_target_do_clear_request(p_viewport->render_target);
- }
-}
-
-void VisualServerViewport::draw_viewports() {
-
-#if 0
- // get our arvr interface in case we need it
- Ref<ARVRInterface> arvr_interface;
-
- if (ARVRServer::get_singleton() != NULL) {
- arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
- // process all our active interfaces
- ARVRServer::get_singleton()->_process();
- }
-#endif
-
- if (Engine::get_singleton()->is_editor_hint()) {
- set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color"));
- }
-
- //sort viewports
- active_viewports.sort_custom<ViewportSort>();
-
- Map<int, Vector<Rasterizer::BlitToScreen> > blit_to_screen_list;
- //draw viewports
- RENDER_TIMESTAMP(">Render Viewports");
-
- for (int i = 0; i < active_viewports.size(); i++) {
-
- Viewport *vp = active_viewports[i];
-
- if (vp->update_mode == VS::VIEWPORT_UPDATE_DISABLED)
- continue;
-
- if (!vp->render_target.is_valid()) {
- continue;
- }
- //ERR_CONTINUE(!vp->render_target.is_valid());
-
- bool visible = vp->viewport_to_screen_rect != Rect2() || vp->update_mode == VS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == VS::VIEWPORT_UPDATE_ONCE || (vp->update_mode == VS::VIEWPORT_UPDATE_WHEN_VISIBLE && VSG::storage->render_target_was_used(vp->render_target));
- visible = visible && vp->size.x > 1 && vp->size.y > 1;
-
- if (!visible)
- continue;
-
- RENDER_TIMESTAMP(">Rendering Viewport " + itos(i));
-
- VSG::storage->render_target_set_as_unused(vp->render_target);
-#if 0
- if (vp->use_arvr && arvr_interface.is_valid()) {
- // override our size, make sure it matches our required size
- vp->size = arvr_interface->get_render_targetsize();
- VSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y);
-
- // render mono or left eye first
- ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO;
-
- // check for an external texture destination for our left eye/mono
- VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono));
-
- // set our render target as current
- VSG::rasterizer->set_current_render_target(vp->render_target);
-
- // and draw left eye/mono
- _draw_viewport(vp, leftOrMono);
- arvr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect);
-
- // render right eye
- if (leftOrMono == ARVRInterface::EYE_LEFT) {
- // check for an external texture destination for our right eye
- VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT));
-
- // commit for eye may have changed the render target
- VSG::rasterizer->set_current_render_target(vp->render_target);
-
- _draw_viewport(vp, ARVRInterface::EYE_RIGHT);
- arvr_interface->commit_for_eye(ARVRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect);
- }
-
- // and for our frame timing, mark when we've finished committing our eyes
- ARVRServer::get_singleton()->_mark_commit();
- } else {
-#endif
- {
- VSG::storage->render_target_set_external_texture(vp->render_target, 0);
-
- VSG::scene_render->set_debug_draw_mode(vp->debug_draw);
- VSG::storage->render_info_begin_capture();
-
- // render standard mono camera
- _draw_viewport(vp);
-
- VSG::storage->render_info_end_capture();
- vp->render_info[VS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_OBJECTS_IN_FRAME);
- vp->render_info[VS::VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_VERTICES_IN_FRAME);
- vp->render_info[VS::VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_MATERIAL_CHANGES_IN_FRAME);
- vp->render_info[VS::VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SHADER_CHANGES_IN_FRAME);
- vp->render_info[VS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SURFACE_CHANGES_IN_FRAME);
- vp->render_info[VS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_DRAW_CALLS_IN_FRAME);
-
- if (vp->viewport_to_screen_rect != Rect2() && (!vp->viewport_render_direct_to_screen || !VSG::rasterizer->is_low_end())) {
- //copy to screen if set as such
- Rasterizer::BlitToScreen blit;
- blit.render_target = vp->render_target;
- blit.rect = vp->viewport_to_screen_rect;
-
- if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
- blit_to_screen_list[vp->viewport_to_screen] = Vector<Rasterizer::BlitToScreen>();
- }
-
- blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
- }
- }
-
- if (vp->update_mode == VS::VIEWPORT_UPDATE_ONCE) {
- vp->update_mode = VS::VIEWPORT_UPDATE_DISABLED;
- }
-
- RENDER_TIMESTAMP("<Rendering Viewport " + itos(i));
- }
- VSG::scene_render->set_debug_draw_mode(VS::VIEWPORT_DEBUG_DRAW_DISABLED);
-
- RENDER_TIMESTAMP("<Render Viewports");
- //this needs to be called to make screen swapping more efficient
- VSG::rasterizer->prepare_for_blitting_render_targets();
-
- for (Map<int, Vector<Rasterizer::BlitToScreen> >::Element *E = blit_to_screen_list.front(); E; E = E->next()) {
- VSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size());
- }
-}
-
-RID VisualServerViewport::viewport_create() {
-
- Viewport *viewport = memnew(Viewport);
-
- RID rid = viewport_owner.make_rid(viewport);
-
- viewport->self = rid;
- viewport->hide_scenario = false;
- viewport->hide_canvas = false;
- viewport->render_target = VSG::storage->render_target_create();
- viewport->shadow_atlas = VSG::scene_render->shadow_atlas_create();
- viewport->viewport_render_direct_to_screen = false;
-
- return rid;
-}
-
-void VisualServerViewport::viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->use_arvr = p_use_arvr;
-}
-
-void VisualServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
-
- ERR_FAIL_COND(p_width < 0 && p_height < 0);
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- // if (viewport->size.width == p_width && viewport->size.height == p_height) {
- // return; //nothing to do
- // }
- viewport->size = Size2(p_width, p_height);
- VSG::storage->render_target_set_size(viewport->render_target, p_width, p_height);
- if (viewport->render_buffers.is_valid()) {
- VSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa);
- }
-}
-
-void VisualServerViewport::viewport_set_active(RID p_viewport, bool p_active) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- if (p_active) {
- ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active
- active_viewports.push_back(viewport);
- } else {
- active_viewports.erase(viewport);
- }
-}
-
-void VisualServerViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->parent = p_parent_viewport;
-}
-
-void VisualServerViewport::viewport_set_clear_mode(RID p_viewport, VS::ViewportClearMode p_clear_mode) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->clear_mode = p_clear_mode;
-}
-
-void VisualServerViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, int p_screen) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- // If using GLES2 we can optimize this operation by rendering directly to system_fbo
- // instead of rendering to fbo and copying to system_fbo after
- if (VSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
-
- VSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y);
- VSG::storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
- }
-
- viewport->viewport_to_screen_rect = p_rect;
- viewport->viewport_to_screen = p_screen;
-}
-
-void VisualServerViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) {
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- if (p_enable == viewport->viewport_render_direct_to_screen)
- return;
-
- // if disabled, reset render_target size and position
- if (!p_enable) {
-
- VSG::storage->render_target_set_position(viewport->render_target, 0, 0);
- VSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y);
- }
-
- VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable);
- viewport->viewport_render_direct_to_screen = p_enable;
-
- // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
- if (VSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
-
- VSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y);
- VSG::storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
- }
-}
-
-void VisualServerViewport::viewport_detach(RID p_viewport) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- // if render_direct_to_screen was used, reset size and position
- if (VSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
-
- VSG::storage->render_target_set_position(viewport->render_target, 0, 0);
- VSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y);
- }
-
- viewport->viewport_to_screen_rect = Rect2();
- viewport->viewport_to_screen = 0;
-}
-
-void VisualServerViewport::viewport_set_update_mode(RID p_viewport, VS::ViewportUpdateMode p_mode) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->update_mode = p_mode;
-}
-
-RID VisualServerViewport::viewport_get_texture(RID p_viewport) const {
-
- const Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND_V(!viewport, RID());
-
- return VSG::storage->render_target_get_texture(viewport->render_target);
-}
-
-void VisualServerViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->hide_scenario = p_hide;
-}
-void VisualServerViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->hide_canvas = p_hide;
-}
-void VisualServerViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->disable_environment = p_disable;
-}
-
-void VisualServerViewport::viewport_attach_camera(RID p_viewport, RID p_camera) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->camera = p_camera;
-}
-void VisualServerViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->scenario = p_scenario;
-}
-void VisualServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- ERR_FAIL_COND(viewport->canvas_map.has(p_canvas));
- VisualServerCanvas::Canvas *canvas = VSG::canvas->canvas_owner.getornull(p_canvas);
- ERR_FAIL_COND(!canvas);
-
- canvas->viewports.insert(p_viewport);
- viewport->canvas_map[p_canvas] = Viewport::CanvasData();
- viewport->canvas_map[p_canvas].layer = 0;
- viewport->canvas_map[p_canvas].sublayer = 0;
- viewport->canvas_map[p_canvas].canvas = canvas;
-}
-
-void VisualServerViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- VisualServerCanvas::Canvas *canvas = VSG::canvas->canvas_owner.getornull(p_canvas);
- ERR_FAIL_COND(!canvas);
-
- viewport->canvas_map.erase(p_canvas);
- canvas->viewports.erase(p_viewport);
-}
-void VisualServerViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
- viewport->canvas_map[p_canvas].transform = p_offset;
-}
-void VisualServerViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- VSG::storage->render_target_set_flag(viewport->render_target, RasterizerStorage::RENDER_TARGET_TRANSPARENT, p_enabled);
- viewport->transparent_bg = p_enabled;
-}
-
-void VisualServerViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->global_transform = p_transform;
-}
-void VisualServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas));
- viewport->canvas_map[p_canvas].layer = p_layer;
- viewport->canvas_map[p_canvas].sublayer = p_sublayer;
-}
-
-void VisualServerViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->shadow_atlas_size = p_size;
-
- VSG::scene_render->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size);
-}
-
-void VisualServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- VSG::scene_render->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
-}
-
-void VisualServerViewport::viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_msaa) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- if (viewport->msaa == p_msaa) {
- return;
- }
- viewport->msaa = p_msaa;
- if (viewport->render_buffers.is_valid()) {
- VSG::scene_render->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa);
- }
-}
-
-int VisualServerViewport::viewport_get_render_info(RID p_viewport, VS::ViewportRenderInfo p_info) {
-
- ERR_FAIL_INDEX_V(p_info, VS::VIEWPORT_RENDER_INFO_MAX, -1);
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- if (!viewport)
- return 0; //there should be a lock here..
-
- return viewport->render_info[p_info];
-}
-
-void VisualServerViewport::viewport_set_debug_draw(RID p_viewport, VS::ViewportDebugDraw p_draw) {
-
- Viewport *viewport = viewport_owner.getornull(p_viewport);
- ERR_FAIL_COND(!viewport);
-
- viewport->debug_draw = p_draw;
-}
-
-bool VisualServerViewport::free(RID p_rid) {
-
- if (viewport_owner.owns(p_rid)) {
-
- Viewport *viewport = viewport_owner.getornull(p_rid);
-
- VSG::storage->free(viewport->render_target);
- VSG::scene_render->free(viewport->shadow_atlas);
- if (viewport->render_buffers.is_valid()) {
- VSG::scene_render->free(viewport->render_buffers);
- }
-
- while (viewport->canvas_map.front()) {
- viewport_remove_canvas(p_rid, viewport->canvas_map.front()->key());
- }
-
- viewport_set_scenario(p_rid, RID());
- active_viewports.erase(viewport);
-
- viewport_owner.free(p_rid);
- memdelete(viewport);
-
- return true;
- }
-
- return false;
-}
-
-void VisualServerViewport::set_default_clear_color(const Color &p_color) {
- VSG::storage->set_default_clear_color(p_color);
-}
-
-VisualServerViewport::VisualServerViewport() {
-}
diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h
deleted file mode 100644
index 30b53f3935..0000000000
--- a/servers/visual/visual_server_viewport.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*************************************************************************/
-/* visual_server_viewport.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUALSERVERVIEWPORT_H
-#define VISUALSERVERVIEWPORT_H
-
-#include "core/rid_owner.h"
-#include "core/self_list.h"
-#include "rasterizer.h"
-#include "servers/arvr/arvr_interface.h"
-#include "servers/visual_server.h"
-
-class VisualServerViewport {
-public:
- struct CanvasBase {
- };
-
- struct Viewport {
-
- RID self;
- RID parent;
-
- bool use_arvr; /* use arvr interface to override camera positioning and projection matrices and control output */
-
- Size2i size;
- RID camera;
- RID scenario;
-
- VS::ViewportUpdateMode update_mode;
- RID render_target;
- RID render_target_texture;
- RID render_buffers;
-
- VS::ViewportMSAA msaa;
-
- int viewport_to_screen;
- Rect2 viewport_to_screen_rect;
- bool viewport_render_direct_to_screen;
-
- bool hide_scenario;
- bool hide_canvas;
- bool disable_environment;
- bool disable_3d_by_usage;
- bool keep_3d_linear;
-
- RID shadow_atlas;
- int shadow_atlas_size;
-
- int render_info[VS::VIEWPORT_RENDER_INFO_MAX];
- VS::ViewportDebugDraw debug_draw;
-
- VS::ViewportClearMode clear_mode;
-
- bool transparent_bg;
-
- struct CanvasKey {
-
- int64_t stacking;
- RID canvas;
- bool operator<(const CanvasKey &p_canvas) const {
- if (stacking == p_canvas.stacking)
- return canvas < p_canvas.canvas;
- return stacking < p_canvas.stacking;
- }
- CanvasKey() {
- stacking = 0;
- }
- CanvasKey(const RID &p_canvas, int p_layer, int p_sublayer) {
- canvas = p_canvas;
- int64_t sign = p_layer < 0 ? -1 : 1;
- stacking = sign * (((int64_t)ABS(p_layer)) << 32) + p_sublayer;
- }
- int get_layer() const { return stacking >> 32; }
- };
-
- struct CanvasData {
-
- CanvasBase *canvas;
- Transform2D transform;
- int layer;
- int sublayer;
- };
-
- Transform2D global_transform;
-
- Map<RID, CanvasData> canvas_map;
-
- Viewport() {
- update_mode = VS::VIEWPORT_UPDATE_WHEN_VISIBLE;
- clear_mode = VS::VIEWPORT_CLEAR_ALWAYS;
- transparent_bg = false;
- disable_environment = false;
- viewport_to_screen = 0;
- shadow_atlas_size = 0;
- keep_3d_linear = false;
- debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED;
- msaa = VS::VIEWPORT_MSAA_DISABLED;
- for (int i = 0; i < VS::VIEWPORT_RENDER_INFO_MAX; i++) {
- render_info[i] = 0;
- }
- use_arvr = false;
- }
- };
-
- mutable RID_PtrOwner<Viewport> viewport_owner;
-
- struct ViewportSort {
- _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const {
-
- bool left_to_screen = p_left->viewport_to_screen_rect.size != Size2();
- bool right_to_screen = p_right->viewport_to_screen_rect.size != Size2();
-
- if (left_to_screen == right_to_screen) {
-
- return p_left->parent == p_right->self;
- }
- return right_to_screen;
- }
- };
-
- Vector<Viewport *> active_viewports;
-
-private:
- void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye);
- void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO);
-
-public:
- RID viewport_create();
-
- void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr);
-
- void viewport_set_size(RID p_viewport, int p_width, int p_height);
-
- void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), int p_screen = 0);
- void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable);
- void viewport_detach(RID p_viewport);
-
- void viewport_set_active(RID p_viewport, bool p_active);
- void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport);
- void viewport_set_update_mode(RID p_viewport, VS::ViewportUpdateMode p_mode);
- void viewport_set_vflip(RID p_viewport, bool p_enable);
-
- void viewport_set_clear_mode(RID p_viewport, VS::ViewportClearMode p_clear_mode);
-
- RID viewport_get_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);
- void viewport_set_disable_environment(RID p_viewport, bool p_disable);
-
- void viewport_attach_camera(RID p_viewport, RID p_camera);
- void viewport_set_scenario(RID p_viewport, RID p_scenario);
- void viewport_attach_canvas(RID p_viewport, RID p_canvas);
- void viewport_remove_canvas(RID p_viewport, RID p_canvas);
- void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset);
- void viewport_set_transparent_background(RID p_viewport, bool p_enabled);
-
- void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform);
- void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer);
-
- void viewport_set_shadow_atlas_size(RID p_viewport, int p_size);
- void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv);
-
- void viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_msaa);
-
- virtual int viewport_get_render_info(RID p_viewport, VS::ViewportRenderInfo p_info);
- virtual void viewport_set_debug_draw(RID p_viewport, VS::ViewportDebugDraw p_draw);
-
- void set_default_clear_color(const Color &p_color);
- void draw_viewports();
-
- bool free(RID p_rid);
-
- VisualServerViewport();
- virtual ~VisualServerViewport() {}
-};
-
-#endif // VISUALSERVERVIEWPORT_H
diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp
deleted file mode 100644
index 90d301c0cd..0000000000
--- a/servers/visual/visual_server_wrap_mt.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*************************************************************************/
-/* visual_server_wrap_mt.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server_wrap_mt.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-
-void VisualServerWrapMT::thread_exit() {
-
- exit = true;
-}
-
-void VisualServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) {
-
- if (!atomic_decrement(&draw_pending)) {
-
- visual_server->draw(p_swap_buffers, frame_step);
- }
-}
-
-void VisualServerWrapMT::thread_flush() {
-
- atomic_decrement(&draw_pending);
-}
-
-void VisualServerWrapMT::_thread_callback(void *_instance) {
-
- VisualServerWrapMT *vsmt = reinterpret_cast<VisualServerWrapMT *>(_instance);
-
- vsmt->thread_loop();
-}
-
-void VisualServerWrapMT::thread_loop() {
-
- server_thread = Thread::get_caller_id();
-
- OS::get_singleton()->make_rendering_thread();
-
- visual_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
-
- visual_server->finish();
-}
-
-/* EVENT QUEUING */
-
-void VisualServerWrapMT::sync() {
-
- if (create_thread) {
-
- atomic_increment(&draw_pending);
- command_queue.push_and_sync(this, &VisualServerWrapMT::thread_flush);
- } else {
-
- command_queue.flush_all(); //flush all pending from other threads
- }
-}
-
-void VisualServerWrapMT::draw(bool p_swap_buffers, double frame_step) {
-
- if (create_thread) {
-
- atomic_increment(&draw_pending);
- command_queue.push(this, &VisualServerWrapMT::thread_draw, p_swap_buffers, frame_step);
- } else {
-
- visual_server->draw(p_swap_buffers, frame_step);
- }
-}
-
-void VisualServerWrapMT::init() {
-
- if (create_thread) {
-
- print_verbose("VisualServerWrapMT: Creating render thread");
- OS::get_singleton()->release_rendering_thread();
- if (create_thread) {
- thread = Thread::create(_thread_callback, this);
- print_verbose("VisualServerWrapMT: Starting render thread");
- }
- while (!draw_thread_up) {
- OS::get_singleton()->delay_usec(1000);
- }
- print_verbose("VisualServerWrapMT: Finished render thread");
- } else {
-
- visual_server->init();
- }
-}
-
-void VisualServerWrapMT::finish() {
-
- if (thread) {
-
- command_queue.push(this, &VisualServerWrapMT::thread_exit);
- Thread::wait_to_finish(thread);
- memdelete(thread);
-
- thread = NULL;
- } else {
- visual_server->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_capture_free_cached_ids();
- particles_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();
-}
-
-void VisualServerWrapMT::set_use_vsync_callback(bool p_enable) {
-
- singleton_mt->call_set_use_vsync(p_enable);
-}
-
-VisualServerWrapMT *VisualServerWrapMT::singleton_mt = NULL;
-
-VisualServerWrapMT::VisualServerWrapMT(VisualServer *p_contained, bool p_create_thread) :
- command_queue(p_create_thread) {
-
- singleton_mt = this;
- OS::switch_vsync_function = set_use_vsync_callback; //as this goes to another thread, make sure it goes properly
-
- visual_server = p_contained;
- create_thread = p_create_thread;
- thread = NULL;
- 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;
- }
-}
-
-VisualServerWrapMT::~VisualServerWrapMT() {
-
- memdelete(visual_server);
- //finish();
-}
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
deleted file mode 100644
index 2eaafe220b..0000000000
--- a/servers/visual/visual_server_wrap_mt.h
+++ /dev/null
@@ -1,679 +0,0 @@
-/*************************************************************************/
-/* visual_server_wrap_mt.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUAL_SERVER_WRAP_MT_H
-#define VISUAL_SERVER_WRAP_MT_H
-
-#include "core/command_queue_mt.h"
-#include "core/os/thread.h"
-#include "servers/visual_server.h"
-
-class VisualServerWrapMT : public VisualServer {
-
- // the real visual server
- mutable VisualServer *visual_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 VisualServerWrapMT *singleton_mt;
-
-#ifdef DEBUG_SYNC
-#define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__));
-#else
-#define SYNC_DEBUG
-#endif
-
-public:
-#define ServerName VisualServer
-#define ServerNameWrapMT VisualServerWrapMT
-#define server_name visual_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 visual_server->texture_2d_create(p_image); }
- virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, TextureLayeredType p_layered_type) { return visual_server->texture_2d_layered_create(p_layers, p_layered_type); }
- virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) { return visual_server->texture_3d_create(p_slices); }
- virtual RID texture_proxy_create(RID p_base) { return visual_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) { visual_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)
- FUNC4(texture_3d_update, RID, const Ref<Image> &, int, int)
- FUNC2(texture_proxy_update, RID, RID)
-
- //these also go pass-through
- virtual RID texture_2d_placeholder_create() { return visual_server->texture_2d_placeholder_create(); }
- virtual RID texture_2d_layered_placeholder_create() { return visual_server->texture_2d_layered_placeholder_create(); }
- virtual RID texture_3d_placeholder_create() { return visual_server->texture_3d_placeholder_create(); }
-
- FUNC1RC(Ref<Image>, texture_2d_get, RID)
- FUNC2RC(Ref<Image>, texture_2d_layer_get, RID, int)
- FUNC3RC(Ref<Image>, texture_3d_slice_get, RID, int, int)
-
- 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 &)
-
- /* 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) {
- return visual_server->mesh_create_from_surfaces(p_surfaces);
- }
-
- 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)
-
- 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_use_gi, RID, bool)
-
- 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_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_interior_ambient, RID, const Color &)
- FUNC2(reflection_probe_set_interior_ambient_energy, RID, float)
- FUNC2(reflection_probe_set_interior_ambient_probe_contribution, RID, float)
- 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)
-
- /* 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)
-
- /* LIGHTMAP CAPTURE */
-
- FUNCRID(lightmap_capture)
-
- FUNC2(lightmap_capture_set_bounds, RID, const AABB &)
- FUNC1RC(AABB, lightmap_capture_get_bounds, RID)
-
- FUNC2(lightmap_capture_set_octree, RID, const Vector<uint8_t> &)
- FUNC1RC(Vector<uint8_t>, lightmap_capture_get_octree, RID)
- FUNC2(lightmap_capture_set_octree_cell_transform, RID, const Transform &)
- FUNC1RC(Transform, lightmap_capture_get_octree_cell_transform, RID)
- FUNC2(lightmap_capture_set_octree_cell_subdiv, RID, int)
- FUNC1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
- FUNC2(lightmap_capture_set_energy, RID, float)
- FUNC1RC(float, lightmap_capture_get_energy, RID)
-
- /* 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)
- FUNC1R(bool, particles_is_inactive, RID)
- FUNC1(particles_request_process, RID)
- FUNC1(particles_restart, RID)
-
- FUNC2(particles_set_draw_order, RID, VS::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 &)
-
- FUNC1R(AABB, particles_get_current_aabb, RID)
-
- /* 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_arvr, 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 &, int)
- FUNC2(viewport_set_render_direct_to_screen, RID, bool)
- FUNC1(viewport_detach, RID)
-
- 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_global_canvas_transform, RID, const Transform2D &)
- FUNC4(viewport_set_canvas_stacking, RID, RID, int, int)
- FUNC2(viewport_set_shadow_atlas_size, RID, int)
- FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int)
- FUNC2(viewport_set_msaa, RID, ViewportMSAA)
-
- //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 visual_server->viewport_get_render_info(p_viewport, p_info);
- }
-
- FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw)
-
- FUNC1(directional_shadow_atlas_set_size, int)
-
- /* SKY API */
-
- FUNCRID(sky)
- FUNC2(sky_set_radiance_size, RID, int)
- FUNC2(sky_set_mode, RID, SkyMode)
- FUNC2(sky_set_texture, RID, RID)
-
- /* 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
- FUNC7(environment_set_ssr, RID, bool, int, float, float, float, bool)
- FUNC9(environment_set_ssao, RID, bool, float, float, float, float, float, EnvironmentSSAOBlur, float)
-
- FUNC2(environment_set_ssao_quality, EnvironmentSSAOQuality, bool)
-
- FUNC12(environment_set_glow, RID, bool, int, float, float, float, float, EnvironmentGlowBlendMode, float, float, float, bool)
-
- FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
-
- FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID)
-
- FUNC5(environment_set_fog, RID, bool, const Color &, const Color &, float)
- FUNC7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
- FUNC5(environment_set_fog_height, RID, bool, float, float, float)
-
- FUNC2(screen_space_roughness_limiter_set_active, bool, 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)
-
- 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)
- FUNC3(instance_set_use_lightmap, RID, RID, RID)
-
- 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)
-
- /* 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_item)
- FUNC2(canvas_item_set_parent, RID, RID)
-
- 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)
-
- FUNC2(canvas_item_set_default_texture_filter, RID, CanvasItemTextureFilter)
- FUNC2(canvas_item_set_default_texture_repeat, RID, CanvasItemTextureRepeat)
-
- FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
- FUNC4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
- 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 &)
- FUNC11(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC12(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, RID, RID, const Color &, bool, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC15(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC11(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC10(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC14(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, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC10(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC8(canvas_item_add_multimesh, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- FUNC8(canvas_item_add_particles, RID, RID, RID, RID, RID, const Color &, CanvasItemTextureFilter, CanvasItemTextureRepeat)
- 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)
-
- FUNC0R(RID, canvas_light_create)
- FUNC2(canvas_light_attach_to_canvas, RID, RID)
- FUNC2(canvas_light_set_enabled, RID, bool)
- FUNC2(canvas_light_set_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_mode, RID, CanvasLightMode)
-
- FUNC2(canvas_light_set_shadow_enabled, RID, bool)
- FUNC2(canvas_light_set_shadow_buffer_size, RID, int)
- 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_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_shape_as_lines, RID, const Vector<Vector2> &)
-
- FUNC2(canvas_occluder_polygon_set_cull_mode, RID, CanvasOccluderPolygonCullMode)
-
- /* 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 visual_server->get_render_info(p_info);
- }
-
- virtual String get_video_adapter_name() const {
- return visual_server->get_video_adapter_name();
- }
-
- virtual String get_video_adapter_vendor() const {
- return visual_server->get_video_adapter_vendor();
- }
-
- 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 visual_server->has_feature(p_feature);
- }
- virtual bool has_os_feature(const String &p_feature) const {
- return visual_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 visual_server->is_low_end();
- }
-
- virtual uint64_t get_frame_profile_frame() {
- return visual_server->get_frame_profile_frame();
- }
-
- virtual void set_frame_profiling_enabled(bool p_enabled) {
- visual_server->set_frame_profiling_enabled(p_enabled);
- }
-
- virtual Vector<FrameProfileArea> get_frame_profile() {
- return visual_server->get_frame_profile();
- }
-
- VisualServerWrapMT(VisualServer *p_contained, bool p_create_thread);
- ~VisualServerWrapMT();
-
-#undef ServerName
-#undef ServerNameWrapMT
-#undef server_name
-};
-
-#ifdef DEBUG_SYNC
-#undef DEBUG_SYNC
-#endif
-#undef SYNC_DEBUG
-
-#endif
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
deleted file mode 100644
index b30d5e1dd1..0000000000
--- a/servers/visual_server.cpp
+++ /dev/null
@@ -1,2360 +0,0 @@
-/*************************************************************************/
-/* visual_server.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "visual_server.h"
-
-#include "core/method_bind_ext.gen.inc"
-#include "core/project_settings.h"
-
-VisualServer *VisualServer::singleton = NULL;
-VisualServer *(*VisualServer::create_func)() = NULL;
-
-VisualServer *VisualServer::get_singleton() {
-
- return singleton;
-}
-
-VisualServer *VisualServer::create() {
-
- ERR_FAIL_COND_V(singleton, NULL);
-
- if (create_func)
- return create_func();
-
- return NULL;
-}
-
-Array VisualServer::_texture_debug_usage_bind() {
-
- List<TextureInfo> list;
- texture_debug_usage(&list);
- Array arr;
- for (const List<TextureInfo>::Element *E = list.front(); E; E = E->next()) {
-
- Dictionary dict;
- dict["texture"] = E->get().texture;
- dict["width"] = E->get().width;
- dict["height"] = E->get().height;
- dict["depth"] = E->get().depth;
- dict["format"] = E->get().format;
- dict["bytes"] = E->get().bytes;
- dict["path"] = E->get().path;
- arr.push_back(dict);
- }
- return arr;
-}
-
-Array VisualServer::_shader_get_param_list_bind(RID p_shader) const {
-
- List<PropertyInfo> l;
- shader_get_param_list(p_shader, &l);
- return convert_property_list(&l);
-}
-
-static Array to_array(const Vector<ObjectID> &ids) {
- Array a;
- a.resize(ids.size());
- for (int i = 0; i < ids.size(); ++i) {
- a[i] = ids[i];
- }
- return a;
-}
-
-Array VisualServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const {
-
- Vector<ObjectID> ids = instances_cull_aabb(p_aabb, p_scenario);
- return to_array(ids);
-}
-
-Array VisualServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
-
- Vector<ObjectID> ids = instances_cull_ray(p_from, p_to, p_scenario);
- return to_array(ids);
-}
-
-Array VisualServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const {
-
- Vector<Plane> planes;
- for (int i = 0; i < p_convex.size(); ++i) {
- Variant v = p_convex[i];
- ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, Array());
- planes.push_back(v);
- }
-
- Vector<ObjectID> ids = instances_cull_convex(planes, p_scenario);
- return to_array(ids);
-}
-
-RID VisualServer::get_test_texture() {
-
- if (test_texture.is_valid()) {
- return test_texture;
- };
-
-#define TEST_TEXTURE_SIZE 256
-
- Vector<uint8_t> test_data;
- test_data.resize(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 3);
-
- {
- uint8_t *w = test_data.ptrw();
-
- for (int x = 0; x < TEST_TEXTURE_SIZE; x++) {
-
- for (int y = 0; y < TEST_TEXTURE_SIZE; y++) {
-
- Color c;
- int r = 255 - (x + y) / 2;
-
- if ((x % (TEST_TEXTURE_SIZE / 8)) < 2 || (y % (TEST_TEXTURE_SIZE / 8)) < 2) {
-
- c.r = y;
- c.g = r;
- c.b = x;
-
- } else {
-
- c.r = r;
- c.g = x;
- c.b = y;
- }
-
- w[(y * TEST_TEXTURE_SIZE + x) * 3 + 0] = uint8_t(CLAMP(c.r * 255, 0, 255));
- w[(y * TEST_TEXTURE_SIZE + x) * 3 + 1] = uint8_t(CLAMP(c.g * 255, 0, 255));
- w[(y * TEST_TEXTURE_SIZE + x) * 3 + 2] = uint8_t(CLAMP(c.b * 255, 0, 255));
- }
- }
- }
-
- Ref<Image> data = memnew(Image(TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, false, Image::FORMAT_RGB8, test_data));
-
- test_texture = texture_2d_create(data);
-
- return test_texture;
-}
-
-void VisualServer::_free_internal_rids() {
-
- if (test_texture.is_valid())
- free(test_texture);
- if (white_texture.is_valid())
- free(white_texture);
- if (test_material.is_valid())
- free(test_material);
-}
-
-RID VisualServer::_make_test_cube() {
-
- Vector<Vector3> vertices;
- Vector<Vector3> normals;
- Vector<float> tangents;
- Vector<Vector3> uvs;
-
-#define ADD_VTX(m_idx) \
- vertices.push_back(face_points[m_idx]); \
- normals.push_back(normal_points[m_idx]); \
- tangents.push_back(normal_points[m_idx][1]); \
- tangents.push_back(normal_points[m_idx][2]); \
- tangents.push_back(normal_points[m_idx][0]); \
- tangents.push_back(1.0); \
- uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0));
-
- for (int i = 0; i < 6; i++) {
-
- Vector3 face_points[4];
- Vector3 normal_points[4];
- float uv_points[8] = { 0, 0, 0, 1, 1, 1, 1, 0 };
-
- for (int j = 0; j < 4; j++) {
-
- float v[3];
- v[0] = 1.0;
- v[1] = 1 - 2 * ((j >> 1) & 1);
- v[2] = v[1] * (1 - 2 * (j & 1));
-
- for (int k = 0; k < 3; k++) {
-
- if (i < 3)
- face_points[j][(i + k) % 3] = v[k];
- else
- face_points[3 - j][(i + k) % 3] = -v[k];
- }
- normal_points[j] = Vector3();
- normal_points[j][i % 3] = (i >= 3 ? -1 : 1);
- }
-
- //tri 1
- ADD_VTX(0);
- ADD_VTX(1);
- ADD_VTX(2);
- //tri 2
- ADD_VTX(2);
- ADD_VTX(3);
- ADD_VTX(0);
- }
-
- RID test_cube = mesh_create();
-
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[VisualServer::ARRAY_NORMAL] = normals;
- d[VisualServer::ARRAY_TANGENT] = tangents;
- d[VisualServer::ARRAY_TEX_UV] = uvs;
- d[VisualServer::ARRAY_VERTEX] = vertices;
-
- Vector<int> indices;
- indices.resize(vertices.size());
- for (int i = 0; i < vertices.size(); i++)
- indices.set(i, i);
- d[VisualServer::ARRAY_INDEX] = indices;
-
- mesh_add_surface_from_arrays(test_cube, PRIMITIVE_TRIANGLES, d);
-
- /*
- test_material = fixed_material_create();
- //material_set_flag(material, MATERIAL_FLAG_BILLBOARD_TOGGLE,true);
- fixed_material_set_texture( test_material, FIXED_MATERIAL_PARAM_DIFFUSE, get_test_texture() );
- fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_SPECULAR_EXP, 70 );
- fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_EMISSION, Color(0.2,0.2,0.2) );
-
- fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_DIFFUSE, Color(1, 1, 1) );
- fixed_material_set_param( test_material, FIXED_MATERIAL_PARAM_SPECULAR, Color(1,1,1) );
-*/
- mesh_surface_set_material(test_cube, 0, test_material);
-
- return test_cube;
-}
-
-RID VisualServer::make_sphere_mesh(int p_lats, int p_lons, float p_radius) {
-
- Vector<Vector3> vertices;
- Vector<Vector3> normals;
-
- for (int i = 1; i <= p_lats; i++) {
- double lat0 = Math_PI * (-0.5 + (double)(i - 1) / p_lats);
- double z0 = Math::sin(lat0);
- double zr0 = Math::cos(lat0);
-
- double lat1 = Math_PI * (-0.5 + (double)i / p_lats);
- double z1 = Math::sin(lat1);
- double zr1 = Math::cos(lat1);
-
- for (int j = p_lons; j >= 1; j--) {
-
- double lng0 = 2 * Math_PI * (double)(j - 1) / p_lons;
- double x0 = Math::cos(lng0);
- double y0 = Math::sin(lng0);
-
- double lng1 = 2 * Math_PI * (double)(j) / p_lons;
- double x1 = Math::cos(lng1);
- double y1 = Math::sin(lng1);
-
- Vector3 v[4] = {
- Vector3(x1 * zr0, z0, y1 * zr0),
- Vector3(x1 * zr1, z1, y1 * zr1),
- Vector3(x0 * zr1, z1, y0 * zr1),
- Vector3(x0 * zr0, z0, y0 * zr0)
- };
-
-#define ADD_POINT(m_idx) \
- normals.push_back(v[m_idx]); \
- vertices.push_back(v[m_idx] * p_radius);
-
- ADD_POINT(0);
- ADD_POINT(1);
- ADD_POINT(2);
-
- ADD_POINT(2);
- ADD_POINT(3);
- ADD_POINT(0);
- }
- }
-
- RID mesh = mesh_create();
- Array d;
- d.resize(VS::ARRAY_MAX);
-
- d[ARRAY_VERTEX] = vertices;
- d[ARRAY_NORMAL] = normals;
-
- mesh_add_surface_from_arrays(mesh, PRIMITIVE_TRIANGLES, d);
-
- return mesh;
-}
-
-RID VisualServer::get_white_texture() {
-
- if (white_texture.is_valid())
- return white_texture;
-
- Vector<uint8_t> wt;
- wt.resize(16 * 3);
- {
- uint8_t *w = wt.ptrw();
- for (int i = 0; i < 16 * 3; i++)
- w[i] = 255;
- }
- Ref<Image> white = memnew(Image(4, 4, 0, Image::FORMAT_RGB8, wt));
- white_texture = texture_2d_create(white);
- return white_texture;
-}
-
-#define SMALL_VEC2 Vector2(0.00001, 0.00001)
-#define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001)
-
-Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) {
-
- uint8_t *vw = r_vertex_array.ptrw();
-
- uint8_t *iw;
- if (r_index_array.size()) {
- iw = r_index_array.ptrw();
- }
-
- int max_bone = 0;
-
- for (int ai = 0; ai < VS::ARRAY_MAX; ai++) {
-
- if (!(p_format & (1 << ai))) // no array
- continue;
-
- switch (ai) {
-
- case VS::ARRAY_VERTEX: {
-
- if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
-
- Vector<Vector2> array = p_arrays[ai];
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
-
- const Vector2 *src = array.ptr();
-
- // setting vertices means regenerating the AABB
- Rect2 aabb;
-
- {
- 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_stride], vector, sizeof(float) * 2);
-
- if (i == 0) {
-
- aabb = Rect2(src[i], SMALL_VEC2); //must have a bit of size
- } else {
-
- aabb.expand_to(src[i]);
- }
- }
- }
-
- r_aabb = AABB(Vector3(aabb.position.x, aabb.position.y, 0), Vector3(aabb.size.x, aabb.size.y, 0));
-
- } else {
- Vector<Vector3> array = p_arrays[ai];
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
-
- const Vector3 *src = array.ptr();
-
- // setting vertices means regenerating the AABB
- AABB aabb;
-
- {
- 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_stride], vector, sizeof(float) * 3);
-
- if (i == 0) {
-
- aabb = AABB(src[i], SMALL_VEC3);
- } else {
-
- aabb.expand_to(src[i]);
- }
- }
- }
-
- r_aabb = aabb;
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<Vector3> array = p_arrays[ai];
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
-
- const Vector3 *src = array.ptr();
-
- // setting vertices means regenerating the AABB
-
- if (p_format & ARRAY_COMPRESS_NORMAL) {
-
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- int8_t vector[4] = {
- (int8_t)CLAMP(src[i].x * 127, -128, 127),
- (int8_t)CLAMP(src[i].y * 127, -128, 127),
- (int8_t)CLAMP(src[i].z * 127, -128, 127),
- 0,
- };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], vector, 4);
- }
-
- } else {
- 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_stride], vector, 3 * 4);
- }
- }
-
- } break;
-
- case VS::ARRAY_TANGENT: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<real_t> array = p_arrays[ai];
-
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
-
- const real_t *src = array.ptr();
-
- if (p_format & ARRAY_COMPRESS_TANGENT) {
-
- for (int i = 0; i < p_vertex_array_len; i++) {
- int8_t xyzw[4] = {
- (int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
- (int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
- (int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
- (int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
- };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4);
- }
-
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- float xyzw[4] = {
- src[i * 4 + 0],
- src[i * 4 + 1],
- src[i * 4 + 2],
- src[i * 4 + 3]
- };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], xyzw, 4 * 4);
- }
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_COLOR_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<Color> array = p_arrays[ai];
-
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
-
- const Color *src = array.ptr();
-
- if (p_format & ARRAY_COMPRESS_COLOR) {
-
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- uint8_t colors[4];
-
- for (int j = 0; j < 4; j++) {
-
- colors[j] = CLAMP(int((src[i][j]) * 255.0), 0, 255);
- }
-
- copymem(&vw[p_offsets[ai] + i * p_stride], colors, 4);
- }
- } else {
-
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- copymem(&vw[p_offsets[ai] + i * p_stride], &src[i], 4 * 4);
- }
- }
-
- } break;
- case VS::ARRAY_TEX_UV: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<Vector2> array = p_arrays[ai];
-
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
-
- const Vector2 *src = array.ptr();
-
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
-
- 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(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2);
- }
-
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- float uv[2] = { src[i].x, src[i].y };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4);
- }
- }
-
- } break;
-
- case VS::ARRAY_TEX_UV2: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_VECTOR2_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<Vector2> array = p_arrays[ai];
-
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER);
-
- const Vector2 *src = array.ptr();
-
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
-
- 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(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 2);
- }
-
- } else {
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- float uv[2] = { src[i].x, src[i].y };
-
- copymem(&vw[p_offsets[ai] + i * p_stride], uv, 2 * 4);
- }
- }
- } break;
- case VS::ARRAY_WEIGHTS: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<real_t> array = p_arrays[ai];
-
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len * VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER);
-
- const real_t *src = array.ptr();
-
- {
-
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- uint16_t data[VS::ARRAY_WEIGHTS_SIZE];
- for (int j = 0; j < VS::ARRAY_WEIGHTS_SIZE; j++) {
- data[j] = CLAMP(src[i * VS::ARRAY_WEIGHTS_SIZE + j] * 65535, 0, 65535);
- }
-
- copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4);
- }
- }
-
- } break;
- case VS::ARRAY_BONES: {
-
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_INT32_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<int> array = p_arrays[ai];
-
- ERR_FAIL_COND_V(array.size() != p_vertex_array_len * VS::ARRAY_WEIGHTS_SIZE, ERR_INVALID_PARAMETER);
-
- const int *src = array.ptr();
-
- for (int i = 0; i < p_vertex_array_len; i++) {
-
- uint16_t data[VS::ARRAY_WEIGHTS_SIZE];
- for (int j = 0; j < VS::ARRAY_WEIGHTS_SIZE; j++) {
- data[j] = src[i * VS::ARRAY_WEIGHTS_SIZE + j];
- max_bone = MAX(data[j], max_bone);
- }
-
- copymem(&vw[p_offsets[ai] + i * p_stride], data, 2 * 4);
- }
-
- } break;
- case VS::ARRAY_INDEX: {
-
- ERR_FAIL_COND_V(p_index_array_len <= 0, ERR_INVALID_DATA);
- ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_INT32_ARRAY, ERR_INVALID_PARAMETER);
-
- Vector<int> indices = p_arrays[ai];
- ERR_FAIL_COND_V(indices.size() == 0, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(indices.size() != p_index_array_len, ERR_INVALID_PARAMETER);
-
- /* determine whether using 16 or 32 bits indices */
-
- const int *src = indices.ptr();
-
- for (int i = 0; i < p_index_array_len; i++) {
-
- if (p_vertex_array_len < (1 << 16)) {
- uint16_t v = src[i];
-
- copymem(&iw[i * 2], &v, 2);
- } else {
- uint32_t v = src[i];
-
- copymem(&iw[i * 4], &v, 4);
- }
- }
- } break;
- default: {
- ERR_FAIL_V(ERR_INVALID_DATA);
- }
- }
- }
-
- if (p_format & VS::ARRAY_FORMAT_BONES) {
- //create AABBs for each detected bone
- int total_bones = max_bone + 1;
-
- bool first = r_bone_aabb.size() == 0;
-
- r_bone_aabb.resize(total_bones);
-
- if (first) {
- for (int i = 0; i < total_bones; i++) {
- r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused
- }
- }
-
- Vector<Vector3> vertices = p_arrays[VS::ARRAY_VERTEX];
- Vector<int> bones = p_arrays[VS::ARRAY_BONES];
- Vector<float> weights = p_arrays[VS::ARRAY_WEIGHTS];
-
- bool any_valid = false;
-
- if (vertices.size() && bones.size() == vertices.size() * 4 && weights.size() == bones.size()) {
-
- int vs = vertices.size();
- const Vector3 *rv = vertices.ptr();
- const int *rb = bones.ptr();
- const float *rw = weights.ptr();
-
- AABB *bptr = r_bone_aabb.ptrw();
-
- for (int i = 0; i < vs; i++) {
-
- Vector3 v = rv[i];
- for (int j = 0; j < 4; j++) {
-
- int idx = rb[i * 4 + j];
- float w = rw[i * 4 + j];
- if (w == 0)
- continue; //break;
- ERR_FAIL_INDEX_V(idx, total_bones, ERR_INVALID_DATA);
-
- if (bptr[idx].size.x < 0) {
- //first
- bptr[idx] = AABB(v, SMALL_VEC3);
- any_valid = true;
- } else {
- bptr[idx].expand_to(v);
- }
- }
- }
- }
-
- if (!any_valid && first) {
-
- r_bone_aabb.clear();
- }
- }
- return OK;
-}
-
-uint32_t VisualServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const {
- uint32_t offsets[ARRAY_MAX];
- mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets);
- return offsets[p_array_index];
-}
-
-uint32_t VisualServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const {
- uint32_t offsets[ARRAY_MAX];
- return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets);
-}
-
-uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const {
-
- int total_elem_size = 0;
-
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
-
- r_offsets[i] = 0; //reset
-
- if (!(p_format & (1 << i))) // no array
- continue;
-
- int elem_size = 0;
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
- elem_size = 2;
- } else {
- elem_size = 3;
- }
-
- {
- elem_size *= sizeof(float);
- }
-
- if (elem_size == 6) {
- elem_size = 8;
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- if (p_format & ARRAY_COMPRESS_NORMAL) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 3;
- }
-
- } break;
-
- case VS::ARRAY_TANGENT: {
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- if (p_format & ARRAY_COMPRESS_COLOR) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
- } break;
- case VS::ARRAY_TEX_UV: {
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
-
- case VS::ARRAY_TEX_UV2: {
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_WEIGHTS: {
-
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case VS::ARRAY_BONES: {
-
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case VS::ARRAY_INDEX: {
-
- if (p_index_len <= 0) {
- ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
- break;
- }
- /* determine whether using 16 or 32 bits indices */
- if (p_vertex_len >= (1 << 16)) {
-
- elem_size = 4;
-
- } else {
- elem_size = 2;
- }
- r_offsets[i] = elem_size;
- continue;
- }
- default: {
- ERR_FAIL_V(0);
- }
- }
-
- r_offsets[i] = total_elem_size;
- total_elem_size += elem_size;
- }
- return total_elem_size;
-}
-
-Error VisualServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) {
-
- ERR_FAIL_INDEX_V(p_primitive, VS::PRIMITIVE_MAX, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(p_arrays.size() != VS::ARRAY_MAX, ERR_INVALID_PARAMETER);
-
- uint32_t format = 0;
-
- // validation
- int index_array_len = 0;
- int array_len = 0;
-
- for (int i = 0; i < p_arrays.size(); i++) {
-
- if (p_arrays[i].get_type() == Variant::NIL)
- continue;
-
- format |= (1 << i);
-
- if (i == VS::ARRAY_VERTEX) {
-
- Variant var = p_arrays[i];
- switch (var.get_type()) {
- case Variant::PACKED_VECTOR2_ARRAY: {
- Vector<Vector2> v2 = var;
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- Vector<Vector3> v3 = var;
- } break;
- default: {
- Array v = var;
- } break;
- }
-
- array_len = PackedVector3Array(p_arrays[i]).size();
- ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA);
- } else if (i == VS::ARRAY_INDEX) {
-
- index_array_len = PackedInt32Array(p_arrays[i]).size();
- }
- }
-
- ERR_FAIL_COND_V((format & VS::ARRAY_FORMAT_VERTEX) == 0, ERR_INVALID_PARAMETER); // mandatory
-
- if (p_blend_shapes.size()) {
- //validate format for morphs
- for (int i = 0; i < p_blend_shapes.size(); i++) {
-
- uint32_t bsformat = 0;
- Array arr = p_blend_shapes[i];
- for (int j = 0; j < arr.size(); j++) {
-
- if (arr[j].get_type() != Variant::NIL)
- bsformat |= (1 << j);
- }
-
- ERR_FAIL_COND_V((bsformat) != (format & (VS::ARRAY_FORMAT_INDEX - 1)), ERR_INVALID_PARAMETER);
- }
- }
-
- uint32_t offsets[VS::ARRAY_MAX];
-
- int total_elem_size = 0;
-
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
-
- offsets[i] = 0; //reset
-
- if (!(format & (1 << i))) // no array
- continue;
-
- int elem_size = 0;
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- Variant arr = p_arrays[0];
- if (arr.get_type() == Variant::PACKED_VECTOR2_ARRAY) {
- elem_size = 2;
- p_compress_format |= ARRAY_FLAG_USE_2D_VERTICES;
- } else if (arr.get_type() == Variant::PACKED_VECTOR3_ARRAY) {
- p_compress_format &= ~ARRAY_FLAG_USE_2D_VERTICES;
- elem_size = 3;
- } else {
- elem_size = (p_compress_format & ARRAY_FLAG_USE_2D_VERTICES) ? 2 : 3;
- }
-
- {
- elem_size *= sizeof(float);
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 3;
- }
-
- } break;
-
- case VS::ARRAY_TANGENT: {
- if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- if (p_compress_format & ARRAY_COMPRESS_COLOR) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
- } break;
- case VS::ARRAY_TEX_UV: {
- if (p_compress_format & ARRAY_COMPRESS_TEX_UV) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
-
- case VS::ARRAY_TEX_UV2: {
- if (p_compress_format & ARRAY_COMPRESS_TEX_UV2) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_WEIGHTS: {
-
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case VS::ARRAY_BONES: {
-
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case VS::ARRAY_INDEX: {
-
- if (index_array_len <= 0) {
- ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
- break;
- }
- /* determine whether using 16 or 32 bits indices */
- if (array_len >= (1 << 16)) {
-
- elem_size = 4;
-
- } else {
- elem_size = 2;
- }
- offsets[i] = elem_size;
- continue;
- }
- default: {
- ERR_FAIL_V(ERR_BUG);
- }
- }
-
- offsets[i] = total_elem_size;
- total_elem_size += elem_size;
- }
-
- uint32_t mask = (1 << ARRAY_MAX) - 1;
- format |= (~mask) & p_compress_format; //make the full format
-
- int array_size = total_elem_size * array_len;
-
- Vector<uint8_t> vertex_array;
- vertex_array.resize(array_size);
-
- int index_array_size = offsets[VS::ARRAY_INDEX] * index_array_len;
-
- Vector<uint8_t> index_array;
- index_array.resize(index_array_size);
-
- AABB aabb;
- Vector<AABB> bone_aabb;
-
- Error err = _surface_set_data(p_arrays, format, offsets, total_elem_size, vertex_array, array_len, index_array, index_array_len, aabb, bone_aabb);
- ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface.");
-
- Vector<Vector<uint8_t> > blend_shape_data;
-
- for (int i = 0; i < p_blend_shapes.size(); i++) {
-
- Vector<uint8_t> vertex_array_shape;
- vertex_array_shape.resize(array_size);
- Vector<uint8_t> noindex;
-
- AABB laabb;
- Error err2 = _surface_set_data(p_blend_shapes[i], format & ~ARRAY_FORMAT_INDEX, offsets, total_elem_size, vertex_array_shape, array_len, noindex, 0, laabb, bone_aabb);
- aabb.merge_with(laabb);
- ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface.");
-
- blend_shape_data.push_back(vertex_array_shape);
- }
- Vector<SurfaceData::LOD> lods;
- if (index_array_len) {
-
- List<Variant> keys;
- p_lods.get_key_list(&keys);
- for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- float distance = E->get();
- ERR_CONTINUE(distance <= 0.0);
- Vector<int> indices = p_lods[E->get()];
- ERR_CONTINUE(indices.size() == 0);
- uint32_t index_count = indices.size();
- ERR_CONTINUE(index_count >= (uint32_t)index_array_len); //should be smaller..
-
- const int *r = indices.ptr();
-
- Vector<uint8_t> data;
- if (array_len <= 65536) {
- //16 bits indices
- data.resize(indices.size() * 2);
- uint8_t *w = data.ptrw();
- uint16_t *index_ptr = (uint16_t *)w;
- for (uint32_t i = 0; i < index_count; i++) {
- index_ptr[i] = r[i];
- }
- } else {
- //32 bits indices
- data.resize(indices.size() * 4);
- uint8_t *w = data.ptrw();
- uint32_t *index_ptr = (uint32_t *)w;
- for (uint32_t i = 0; i < index_count; i++) {
- index_ptr[i] = r[i];
- }
- }
-
- SurfaceData::LOD lod;
- lod.edge_length = distance;
- lod.index_data = data;
- lods.push_back(lod);
- }
- }
-
- SurfaceData &surface_data = *r_surface_data;
- surface_data.format = format;
- surface_data.primitive = p_primitive;
- surface_data.aabb = aabb;
- surface_data.vertex_data = vertex_array;
- surface_data.vertex_count = array_len;
- surface_data.index_data = index_array;
- surface_data.index_count = index_array_len;
- surface_data.blend_shapes = blend_shape_data;
- surface_data.bone_aabbs = bone_aabb;
- surface_data.lods = lods;
-
- return OK;
-}
-
-void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) {
-
- SurfaceData sd;
- Error err = mesh_create_surface_data_from_arrays(&sd, p_primitive, p_arrays, p_blend_shapes, p_lods, p_compress_format);
- if (err != OK) {
- return;
- }
- mesh_add_surface(p_mesh, sd);
-}
-
-Array VisualServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const {
-
- uint32_t offsets[ARRAY_MAX];
-
- int total_elem_size = 0;
-
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
-
- offsets[i] = 0; //reset
-
- if (!(p_format & (1 << i))) // no array
- continue;
-
- int elem_size = 0;
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
- elem_size = 2;
- } else {
- elem_size = 3;
- }
-
- {
- elem_size *= sizeof(float);
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
-
- if (p_format & ARRAY_COMPRESS_NORMAL) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 3;
- }
-
- } break;
-
- case VS::ARRAY_TANGENT: {
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
-
- } break;
- case VS::ARRAY_COLOR: {
-
- if (p_format & ARRAY_COMPRESS_COLOR) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 4;
- }
- } break;
- case VS::ARRAY_TEX_UV: {
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
-
- case VS::ARRAY_TEX_UV2: {
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
- elem_size = sizeof(uint32_t);
- } else {
- elem_size = sizeof(float) * 2;
- }
-
- } break;
- case VS::ARRAY_WEIGHTS: {
-
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case VS::ARRAY_BONES: {
-
- elem_size = sizeof(uint16_t) * 4;
-
- } break;
- case VS::ARRAY_INDEX: {
-
- if (p_index_len <= 0) {
- ERR_PRINT("index_array_len==NO_INDEX_ARRAY");
- break;
- }
- /* determine whether using 16 or 32 bits indices */
- if (p_vertex_len >= (1 << 16)) {
-
- elem_size = 4;
-
- } else {
- elem_size = 2;
- }
- offsets[i] = elem_size;
- continue;
- }
- default: {
- ERR_FAIL_V(Array());
- }
- }
-
- offsets[i] = total_elem_size;
- total_elem_size += elem_size;
- }
-
- Array ret;
- ret.resize(VS::ARRAY_MAX);
-
- const uint8_t *r = p_vertex_data.ptr();
-
- for (int i = 0; i < VS::ARRAY_MAX; i++) {
-
- if (!(p_format & (1 << i)))
- continue;
-
- switch (i) {
-
- case VS::ARRAY_VERTEX: {
-
- if (p_format & ARRAY_FLAG_USE_2D_VERTICES) {
-
- Vector<Vector2> arr_2d;
- arr_2d.resize(p_vertex_len);
-
- {
-
- Vector2 *w = arr_2d.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(v[0], v[1]);
- }
- }
-
- ret[i] = arr_2d;
- } else {
-
- Vector<Vector3> arr_3d;
- arr_3d.resize(p_vertex_len);
-
- {
-
- Vector3 *w = arr_3d.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector3(v[0], v[1], v[2]);
- }
- }
-
- ret[i] = arr_3d;
- }
-
- } break;
- case VS::ARRAY_NORMAL: {
- Vector<Vector3> arr;
- arr.resize(p_vertex_len);
-
- if (p_format & ARRAY_COMPRESS_NORMAL) {
-
- Vector3 *w = arr.ptrw();
- const float multiplier = 1.f / 127.f;
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
- }
- } else {
- Vector3 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector3(v[0], v[1], v[2]);
- }
- }
-
- ret[i] = arr;
-
- } break;
-
- case VS::ARRAY_TANGENT: {
- Vector<float> arr;
- arr.resize(p_vertex_len * 4);
- if (p_format & ARRAY_COMPRESS_TANGENT) {
- float *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = float(v[k] / 127.0);
- }
- }
- } else {
-
- float *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = v[k];
- }
- }
- }
-
- ret[i] = arr;
-
- } break;
- case VS::ARRAY_COLOR: {
-
- Vector<Color> arr;
- arr.resize(p_vertex_len);
-
- if (p_format & ARRAY_COMPRESS_COLOR) {
-
- Color *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const uint8_t *v = (const uint8_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Color(float(v[0] / 255.0), float(v[1] / 255.0), float(v[2] / 255.0), float(v[3] / 255.0));
- }
- } else {
- Color *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Color(v[0], v[1], v[2], v[3]);
- }
- }
-
- ret[i] = arr;
- } break;
- case VS::ARRAY_TEX_UV: {
-
- Vector<Vector2> arr;
- arr.resize(p_vertex_len);
-
- if (p_format & ARRAY_COMPRESS_TEX_UV) {
-
- Vector2 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]));
- }
- } else {
-
- Vector2 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(v[0], v[1]);
- }
- }
-
- ret[i] = arr;
- } break;
-
- case VS::ARRAY_TEX_UV2: {
- Vector<Vector2> arr;
- arr.resize(p_vertex_len);
-
- if (p_format & ARRAY_COMPRESS_TEX_UV2) {
-
- Vector2 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(Math::halfptr_to_float(&v[0]), Math::halfptr_to_float(&v[1]));
- }
- } else {
-
- Vector2 *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
- w[j] = Vector2(v[0], v[1]);
- }
- }
-
- ret[i] = arr;
-
- } break;
- case VS::ARRAY_WEIGHTS: {
-
- Vector<float> arr;
- arr.resize(p_vertex_len * 4);
- {
- float *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = float(v[k] / 65535.0);
- }
- }
- }
-
- ret[i] = arr;
-
- } break;
- case VS::ARRAY_BONES: {
-
- Vector<int> arr;
- arr.resize(p_vertex_len * 4);
-
- int *w = arr.ptrw();
-
- for (int j = 0; j < p_vertex_len; j++) {
-
- const uint16_t *v = (const uint16_t *)&r[j * total_elem_size + offsets[i]];
- for (int k = 0; k < 4; k++) {
- w[j * 4 + k] = v[k];
- }
- }
-
- ret[i] = arr;
-
- } break;
- case VS::ARRAY_INDEX: {
- /* determine whether using 16 or 32 bits indices */
-
- const uint8_t *ir = p_index_data.ptr();
-
- Vector<int> arr;
- arr.resize(p_index_len);
- if (p_vertex_len < (1 << 16)) {
-
- int *w = arr.ptrw();
-
- for (int j = 0; j < p_index_len; j++) {
-
- const uint16_t *v = (const uint16_t *)&ir[j * 2];
- w[j] = *v;
- }
- } else {
-
- int *w = arr.ptrw();
-
- for (int j = 0; j < p_index_len; j++) {
- const int *v = (const int *)&ir[j * 4];
- w[j] = *v;
- }
- }
- ret[i] = arr;
- } break;
- default: {
- ERR_FAIL_V(ret);
- }
- }
- }
-
- return ret;
-}
-
-Array VisualServer::mesh_surface_get_arrays(RID p_mesh, int p_surface) const {
-
- SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
- return mesh_create_arrays_from_surface_data(sd);
-}
-
-Dictionary VisualServer::mesh_surface_get_lods(RID p_mesh, int p_surface) const {
-
- SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
- ERR_FAIL_COND_V(sd.vertex_count == 0, Dictionary());
-
- Dictionary ret;
-
- for (int i = 0; i < sd.lods.size(); i++) {
- Vector<int> lods;
- if (sd.vertex_count <= 65536) {
- uint32_t lc = sd.lods[i].index_data.size() / 2;
- lods.resize(lc);
- const uint8_t *r = sd.lods[i].index_data.ptr();
- const uint16_t *rptr = (const uint16_t *)r;
- int *w = lods.ptrw();
- for (uint32_t j = 0; j < lc; j++) {
- w[j] = rptr[i];
- }
- } else {
- uint32_t lc = sd.lods[i].index_data.size() / 4;
- lods.resize(lc);
- const uint8_t *r = sd.lods[i].index_data.ptr();
- const uint32_t *rptr = (const uint32_t *)r;
- int *w = lods.ptrw();
- for (uint32_t j = 0; j < lc; j++) {
- w[j] = rptr[i];
- }
- }
-
- ret[sd.lods[i].edge_length] = lods;
- }
-
- return ret;
-}
-
-Array VisualServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const {
-
- SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
- ERR_FAIL_COND_V(sd.vertex_count == 0, Array());
-
- Vector<Vector<uint8_t> > blend_shape_data = sd.blend_shapes;
-
- if (blend_shape_data.size() > 0) {
- int vertex_len = sd.vertex_count;
-
- Vector<uint8_t> index_data = sd.index_data;
- int index_len = sd.index_count;
-
- uint32_t format = sd.format;
-
- Array blend_shape_array;
- blend_shape_array.resize(blend_shape_data.size());
- for (int i = 0; i < blend_shape_data.size(); i++) {
- blend_shape_array.set(i, _get_array_from_surface(format, blend_shape_data[i], vertex_len, index_data, index_len));
- }
-
- return blend_shape_array;
- } else {
- return Array();
- }
-}
-
-Array VisualServer::mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const {
-
- Vector<uint8_t> vertex_data = p_data.vertex_data;
-
- ERR_FAIL_COND_V(vertex_data.size() == 0, Array());
- int vertex_len = p_data.vertex_count;
-
- Vector<uint8_t> index_data = p_data.index_data;
- int index_len = p_data.index_count;
-
- uint32_t format = p_data.format;
-
- return _get_array_from_surface(format, vertex_data, vertex_len, index_data, index_len);
-}
-#if 0
-Array VisualServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const {
-
- Vector<AABB> vec = VS::get_singleton()->mesh_surface_get_skeleton_aabb(p_mesh, p_surface);
- Array arr;
- for (int i = 0; i < vec.size(); i++) {
- arr[i] = vec[i];
- }
- return arr;
-}
-#endif
-void VisualServer::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("force_sync"), &VisualServer::sync);
- ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &VisualServer::draw, DEFVAL(true), DEFVAL(0.0));
-
-#ifndef _MSC_VER
-#warning TODO all texture methods need re-binding
-#endif
-
- ClassDB::bind_method(D_METHOD("texture_2d_create", "image"), &VisualServer::texture_2d_create);
- ClassDB::bind_method(D_METHOD("texture_2d_get", "texture"), &VisualServer::texture_2d_get);
-
-#ifndef _3D_DISABLED
- ClassDB::bind_method(D_METHOD("sky_create"), &VisualServer::sky_create);
- ClassDB::bind_method(D_METHOD("sky_set_texture", "sky", "panorama"), &VisualServer::sky_set_texture);
-#endif
- ClassDB::bind_method(D_METHOD("shader_create"), &VisualServer::shader_create);
- ClassDB::bind_method(D_METHOD("shader_set_code", "shader", "code"), &VisualServer::shader_set_code);
- ClassDB::bind_method(D_METHOD("shader_get_code", "shader"), &VisualServer::shader_get_code);
- ClassDB::bind_method(D_METHOD("shader_get_param_list", "shader"), &VisualServer::_shader_get_param_list_bind);
- ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "name", "texture"), &VisualServer::shader_set_default_texture_param);
- ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "name"), &VisualServer::shader_get_default_texture_param);
- ClassDB::bind_method(D_METHOD("shader_get_param_default", "material", "parameter"), &VisualServer::shader_get_param_default);
-
- ClassDB::bind_method(D_METHOD("material_create"), &VisualServer::material_create);
- ClassDB::bind_method(D_METHOD("material_set_shader", "shader_material", "shader"), &VisualServer::material_set_shader);
- ClassDB::bind_method(D_METHOD("material_set_param", "material", "parameter", "value"), &VisualServer::material_set_param);
- ClassDB::bind_method(D_METHOD("material_get_param", "material", "parameter"), &VisualServer::material_get_param);
- ClassDB::bind_method(D_METHOD("material_set_render_priority", "material", "priority"), &VisualServer::material_set_render_priority);
-
- ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &VisualServer::material_set_next_pass);
-
- ClassDB::bind_method(D_METHOD("mesh_create"), &VisualServer::mesh_create);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &VisualServer::mesh_surface_get_format_offset);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &VisualServer::mesh_surface_get_format_stride);
- ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &VisualServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
- ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &VisualServer::mesh_get_blend_shape_count);
- ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &VisualServer::mesh_set_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &VisualServer::mesh_get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("mesh_surface_update_region", "mesh", "surface", "offset", "data"), &VisualServer::mesh_surface_update_region);
- ClassDB::bind_method(D_METHOD("mesh_surface_set_material", "mesh", "surface", "material"), &VisualServer::mesh_surface_set_material);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_material", "mesh", "surface"), &VisualServer::mesh_surface_get_material);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_arrays", "mesh", "surface"), &VisualServer::mesh_surface_get_arrays);
- ClassDB::bind_method(D_METHOD("mesh_surface_get_blend_shape_arrays", "mesh", "surface"), &VisualServer::mesh_surface_get_blend_shape_arrays);
- ClassDB::bind_method(D_METHOD("mesh_get_surface_count", "mesh"), &VisualServer::mesh_get_surface_count);
- ClassDB::bind_method(D_METHOD("mesh_set_custom_aabb", "mesh", "aabb"), &VisualServer::mesh_set_custom_aabb);
- ClassDB::bind_method(D_METHOD("mesh_get_custom_aabb", "mesh"), &VisualServer::mesh_get_custom_aabb);
- ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &VisualServer::mesh_clear);
-
- ClassDB::bind_method(D_METHOD("multimesh_create"), &VisualServer::multimesh_create);
- ClassDB::bind_method(D_METHOD("multimesh_allocate", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &VisualServer::multimesh_allocate, DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("multimesh_get_instance_count", "multimesh"), &VisualServer::multimesh_get_instance_count);
- ClassDB::bind_method(D_METHOD("multimesh_set_mesh", "multimesh", "mesh"), &VisualServer::multimesh_set_mesh);
- ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform", "multimesh", "index", "transform"), &VisualServer::multimesh_instance_set_transform);
- ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform_2d", "multimesh", "index", "transform"), &VisualServer::multimesh_instance_set_transform_2d);
- ClassDB::bind_method(D_METHOD("multimesh_instance_set_color", "multimesh", "index", "color"), &VisualServer::multimesh_instance_set_color);
- ClassDB::bind_method(D_METHOD("multimesh_instance_set_custom_data", "multimesh", "index", "custom_data"), &VisualServer::multimesh_instance_set_custom_data);
- ClassDB::bind_method(D_METHOD("multimesh_get_mesh", "multimesh"), &VisualServer::multimesh_get_mesh);
- ClassDB::bind_method(D_METHOD("multimesh_get_aabb", "multimesh"), &VisualServer::multimesh_get_aabb);
- ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform", "multimesh", "index"), &VisualServer::multimesh_instance_get_transform);
- ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform_2d", "multimesh", "index"), &VisualServer::multimesh_instance_get_transform_2d);
- ClassDB::bind_method(D_METHOD("multimesh_instance_get_color", "multimesh", "index"), &VisualServer::multimesh_instance_get_color);
- ClassDB::bind_method(D_METHOD("multimesh_instance_get_custom_data", "multimesh", "index"), &VisualServer::multimesh_instance_get_custom_data);
- ClassDB::bind_method(D_METHOD("multimesh_set_visible_instances", "multimesh", "visible"), &VisualServer::multimesh_set_visible_instances);
- ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &VisualServer::multimesh_get_visible_instances);
- ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &VisualServer::multimesh_set_buffer);
- ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &VisualServer::multimesh_get_buffer);
-#ifndef _3D_DISABLED
- ClassDB::bind_method(D_METHOD("immediate_create"), &VisualServer::immediate_create);
- ClassDB::bind_method(D_METHOD("immediate_begin", "immediate", "primitive", "texture"), &VisualServer::immediate_begin, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("immediate_vertex", "immediate", "vertex"), &VisualServer::immediate_vertex);
- ClassDB::bind_method(D_METHOD("immediate_vertex_2d", "immediate", "vertex"), &VisualServer::immediate_vertex_2d);
- ClassDB::bind_method(D_METHOD("immediate_normal", "immediate", "normal"), &VisualServer::immediate_normal);
- ClassDB::bind_method(D_METHOD("immediate_tangent", "immediate", "tangent"), &VisualServer::immediate_tangent);
- ClassDB::bind_method(D_METHOD("immediate_color", "immediate", "color"), &VisualServer::immediate_color);
- ClassDB::bind_method(D_METHOD("immediate_uv", "immediate", "tex_uv"), &VisualServer::immediate_uv);
- ClassDB::bind_method(D_METHOD("immediate_uv2", "immediate", "tex_uv"), &VisualServer::immediate_uv2);
- ClassDB::bind_method(D_METHOD("immediate_end", "immediate"), &VisualServer::immediate_end);
- ClassDB::bind_method(D_METHOD("immediate_clear", "immediate"), &VisualServer::immediate_clear);
- ClassDB::bind_method(D_METHOD("immediate_set_material", "immediate", "material"), &VisualServer::immediate_set_material);
- ClassDB::bind_method(D_METHOD("immediate_get_material", "immediate"), &VisualServer::immediate_get_material);
-#endif
-
- ClassDB::bind_method(D_METHOD("skeleton_create"), &VisualServer::skeleton_create);
- ClassDB::bind_method(D_METHOD("skeleton_allocate", "skeleton", "bones", "is_2d_skeleton"), &VisualServer::skeleton_allocate, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("skeleton_get_bone_count", "skeleton"), &VisualServer::skeleton_get_bone_count);
- ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform", "skeleton", "bone", "transform"), &VisualServer::skeleton_bone_set_transform);
- ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform", "skeleton", "bone"), &VisualServer::skeleton_bone_get_transform);
- ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform_2d", "skeleton", "bone", "transform"), &VisualServer::skeleton_bone_set_transform_2d);
- ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform_2d", "skeleton", "bone"), &VisualServer::skeleton_bone_get_transform_2d);
-
-#ifndef _3D_DISABLED
- ClassDB::bind_method(D_METHOD("directional_light_create"), &VisualServer::directional_light_create);
- ClassDB::bind_method(D_METHOD("omni_light_create"), &VisualServer::omni_light_create);
- ClassDB::bind_method(D_METHOD("spot_light_create"), &VisualServer::spot_light_create);
-
- ClassDB::bind_method(D_METHOD("light_set_color", "light", "color"), &VisualServer::light_set_color);
- ClassDB::bind_method(D_METHOD("light_set_param", "light", "param", "value"), &VisualServer::light_set_param);
- ClassDB::bind_method(D_METHOD("light_set_shadow", "light", "enabled"), &VisualServer::light_set_shadow);
- ClassDB::bind_method(D_METHOD("light_set_shadow_color", "light", "color"), &VisualServer::light_set_shadow_color);
- ClassDB::bind_method(D_METHOD("light_set_projector", "light", "texture"), &VisualServer::light_set_projector);
- ClassDB::bind_method(D_METHOD("light_set_negative", "light", "enable"), &VisualServer::light_set_negative);
- ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &VisualServer::light_set_cull_mask);
- ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &VisualServer::light_set_reverse_cull_face_mode);
- ClassDB::bind_method(D_METHOD("light_set_use_gi", "light", "enabled"), &VisualServer::light_set_use_gi);
-
- ClassDB::bind_method(D_METHOD("light_omni_set_shadow_mode", "light", "mode"), &VisualServer::light_omni_set_shadow_mode);
-
- ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &VisualServer::light_directional_set_shadow_mode);
- ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &VisualServer::light_directional_set_blend_splits);
- ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &VisualServer::light_directional_set_shadow_depth_range_mode);
-
- ClassDB::bind_method(D_METHOD("reflection_probe_create"), &VisualServer::reflection_probe_create);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_update_mode", "probe", "mode"), &VisualServer::reflection_probe_set_update_mode);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_intensity", "probe", "intensity"), &VisualServer::reflection_probe_set_intensity);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_interior_ambient", "probe", "color"), &VisualServer::reflection_probe_set_interior_ambient);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_interior_ambient_energy", "probe", "energy"), &VisualServer::reflection_probe_set_interior_ambient_energy);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_interior_ambient_probe_contribution", "probe", "contrib"), &VisualServer::reflection_probe_set_interior_ambient_probe_contribution);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_max_distance", "probe", "distance"), &VisualServer::reflection_probe_set_max_distance);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_extents", "probe", "extents"), &VisualServer::reflection_probe_set_extents);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_origin_offset", "probe", "offset"), &VisualServer::reflection_probe_set_origin_offset);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_as_interior", "probe", "enable"), &VisualServer::reflection_probe_set_as_interior);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_box_projection", "probe", "enable"), &VisualServer::reflection_probe_set_enable_box_projection);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &VisualServer::reflection_probe_set_enable_shadows);
- ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &VisualServer::reflection_probe_set_cull_mask);
-
-#ifndef _MSC_VER
-#warning TODO all giprobe methods need re-binding
-#endif
-#if 0
- ClassDB::bind_method(D_METHOD("gi_probe_create"), &VisualServer::gi_probe_create);
- ClassDB::bind_method(D_METHOD("gi_probe_set_bounds", "probe", "bounds"), &VisualServer::gi_probe_set_bounds);
- ClassDB::bind_method(D_METHOD("gi_probe_get_bounds", "probe"), &VisualServer::gi_probe_get_bounds);
- ClassDB::bind_method(D_METHOD("gi_probe_set_cell_size", "probe", "range"), &VisualServer::gi_probe_set_cell_size);
- ClassDB::bind_method(D_METHOD("gi_probe_get_cell_size", "probe"), &VisualServer::gi_probe_get_cell_size);
- ClassDB::bind_method(D_METHOD("gi_probe_set_to_cell_xform", "probe", "xform"), &VisualServer::gi_probe_set_to_cell_xform);
- ClassDB::bind_method(D_METHOD("gi_probe_get_to_cell_xform", "probe"), &VisualServer::gi_probe_get_to_cell_xform);
- ClassDB::bind_method(D_METHOD("gi_probe_set_dynamic_data", "probe", "data"), &VisualServer::gi_probe_set_dynamic_data);
- ClassDB::bind_method(D_METHOD("gi_probe_get_dynamic_data", "probe"), &VisualServer::gi_probe_get_dynamic_data);
- ClassDB::bind_method(D_METHOD("gi_probe_set_dynamic_range", "probe", "range"), &VisualServer::gi_probe_set_dynamic_range);
- ClassDB::bind_method(D_METHOD("gi_probe_get_dynamic_range", "probe"), &VisualServer::gi_probe_get_dynamic_range);
- ClassDB::bind_method(D_METHOD("gi_probe_set_energy", "probe", "energy"), &VisualServer::gi_probe_set_energy);
- ClassDB::bind_method(D_METHOD("gi_probe_get_energy", "probe"), &VisualServer::gi_probe_get_energy);
- ClassDB::bind_method(D_METHOD("gi_probe_set_bias", "probe", "bias"), &VisualServer::gi_probe_set_bias);
- ClassDB::bind_method(D_METHOD("gi_probe_get_bias", "probe"), &VisualServer::gi_probe_get_bias);
- ClassDB::bind_method(D_METHOD("gi_probe_set_normal_bias", "probe", "bias"), &VisualServer::gi_probe_set_normal_bias);
- ClassDB::bind_method(D_METHOD("gi_probe_get_normal_bias", "probe"), &VisualServer::gi_probe_get_normal_bias);
- ClassDB::bind_method(D_METHOD("gi_probe_set_propagation", "probe", "propagation"), &VisualServer::gi_probe_set_propagation);
- ClassDB::bind_method(D_METHOD("gi_probe_get_propagation", "probe"), &VisualServer::gi_probe_get_propagation);
- ClassDB::bind_method(D_METHOD("gi_probe_set_interior", "probe", "enable"), &VisualServer::gi_probe_set_interior);
- ClassDB::bind_method(D_METHOD("gi_probe_is_interior", "probe"), &VisualServer::gi_probe_is_interior);
- ClassDB::bind_method(D_METHOD("gi_probe_set_compress", "probe", "enable"), &VisualServer::gi_probe_set_compress);
- ClassDB::bind_method(D_METHOD("gi_probe_is_compressed", "probe"), &VisualServer::gi_probe_is_compressed);
-#endif
-
- ClassDB::bind_method(D_METHOD("lightmap_capture_create"), &VisualServer::lightmap_capture_create);
- ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &VisualServer::lightmap_capture_set_bounds);
- ClassDB::bind_method(D_METHOD("lightmap_capture_get_bounds", "capture"), &VisualServer::lightmap_capture_get_bounds);
- ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree", "capture", "octree"), &VisualServer::lightmap_capture_set_octree);
- ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_transform", "capture", "xform"), &VisualServer::lightmap_capture_set_octree_cell_transform);
- ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_transform", "capture"), &VisualServer::lightmap_capture_get_octree_cell_transform);
- ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_subdiv", "capture", "subdiv"), &VisualServer::lightmap_capture_set_octree_cell_subdiv);
- ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_subdiv", "capture"), &VisualServer::lightmap_capture_get_octree_cell_subdiv);
- ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &VisualServer::lightmap_capture_get_octree);
- ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &VisualServer::lightmap_capture_set_energy);
- ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &VisualServer::lightmap_capture_get_energy);
-#endif
- ClassDB::bind_method(D_METHOD("particles_create"), &VisualServer::particles_create);
- ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &VisualServer::particles_set_emitting);
- ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &VisualServer::particles_get_emitting);
- ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &VisualServer::particles_set_amount);
- ClassDB::bind_method(D_METHOD("particles_set_lifetime", "particles", "lifetime"), &VisualServer::particles_set_lifetime);
- ClassDB::bind_method(D_METHOD("particles_set_one_shot", "particles", "one_shot"), &VisualServer::particles_set_one_shot);
- ClassDB::bind_method(D_METHOD("particles_set_pre_process_time", "particles", "time"), &VisualServer::particles_set_pre_process_time);
- ClassDB::bind_method(D_METHOD("particles_set_explosiveness_ratio", "particles", "ratio"), &VisualServer::particles_set_explosiveness_ratio);
- ClassDB::bind_method(D_METHOD("particles_set_randomness_ratio", "particles", "ratio"), &VisualServer::particles_set_randomness_ratio);
- ClassDB::bind_method(D_METHOD("particles_set_custom_aabb", "particles", "aabb"), &VisualServer::particles_set_custom_aabb);
- ClassDB::bind_method(D_METHOD("particles_set_speed_scale", "particles", "scale"), &VisualServer::particles_set_speed_scale);
- ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &VisualServer::particles_set_use_local_coordinates);
- ClassDB::bind_method(D_METHOD("particles_set_process_material", "particles", "material"), &VisualServer::particles_set_process_material);
- ClassDB::bind_method(D_METHOD("particles_set_fixed_fps", "particles", "fps"), &VisualServer::particles_set_fixed_fps);
- ClassDB::bind_method(D_METHOD("particles_set_fractional_delta", "particles", "enable"), &VisualServer::particles_set_fractional_delta);
- ClassDB::bind_method(D_METHOD("particles_is_inactive", "particles"), &VisualServer::particles_is_inactive);
- ClassDB::bind_method(D_METHOD("particles_request_process", "particles"), &VisualServer::particles_request_process);
- ClassDB::bind_method(D_METHOD("particles_restart", "particles"), &VisualServer::particles_restart);
- ClassDB::bind_method(D_METHOD("particles_set_draw_order", "particles", "order"), &VisualServer::particles_set_draw_order);
- ClassDB::bind_method(D_METHOD("particles_set_draw_passes", "particles", "count"), &VisualServer::particles_set_draw_passes);
- ClassDB::bind_method(D_METHOD("particles_set_draw_pass_mesh", "particles", "pass", "mesh"), &VisualServer::particles_set_draw_pass_mesh);
- ClassDB::bind_method(D_METHOD("particles_get_current_aabb", "particles"), &VisualServer::particles_get_current_aabb);
- ClassDB::bind_method(D_METHOD("particles_set_emission_transform", "particles", "transform"), &VisualServer::particles_set_emission_transform);
-
- ClassDB::bind_method(D_METHOD("camera_create"), &VisualServer::camera_create);
- ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &VisualServer::camera_set_perspective);
- ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &VisualServer::camera_set_orthogonal);
- ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &VisualServer::camera_set_frustum);
- ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &VisualServer::camera_set_transform);
- ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &VisualServer::camera_set_cull_mask);
- ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &VisualServer::camera_set_environment);
- ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &VisualServer::camera_set_use_vertical_aspect);
-
- ClassDB::bind_method(D_METHOD("viewport_create"), &VisualServer::viewport_create);
- ClassDB::bind_method(D_METHOD("viewport_set_use_arvr", "viewport", "use_arvr"), &VisualServer::viewport_set_use_arvr);
- ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &VisualServer::viewport_set_size);
- ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &VisualServer::viewport_set_active);
- ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &VisualServer::viewport_set_parent_viewport);
- ClassDB::bind_method(D_METHOD("viewport_attach_to_screen", "viewport", "rect", "screen"), &VisualServer::viewport_attach_to_screen, DEFVAL(Rect2()), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &VisualServer::viewport_set_render_direct_to_screen);
- ClassDB::bind_method(D_METHOD("viewport_detach", "viewport"), &VisualServer::viewport_detach);
- ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &VisualServer::viewport_set_update_mode);
- ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &VisualServer::viewport_set_clear_mode);
- ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &VisualServer::viewport_get_texture);
- ClassDB::bind_method(D_METHOD("viewport_set_hide_scenario", "viewport", "hidden"), &VisualServer::viewport_set_hide_scenario);
- ClassDB::bind_method(D_METHOD("viewport_set_hide_canvas", "viewport", "hidden"), &VisualServer::viewport_set_hide_canvas);
- ClassDB::bind_method(D_METHOD("viewport_set_disable_environment", "viewport", "disabled"), &VisualServer::viewport_set_disable_environment);
- ClassDB::bind_method(D_METHOD("viewport_attach_camera", "viewport", "camera"), &VisualServer::viewport_attach_camera);
- ClassDB::bind_method(D_METHOD("viewport_set_scenario", "viewport", "scenario"), &VisualServer::viewport_set_scenario);
- ClassDB::bind_method(D_METHOD("viewport_attach_canvas", "viewport", "canvas"), &VisualServer::viewport_attach_canvas);
- ClassDB::bind_method(D_METHOD("viewport_remove_canvas", "viewport", "canvas"), &VisualServer::viewport_remove_canvas);
- ClassDB::bind_method(D_METHOD("viewport_set_canvas_transform", "viewport", "canvas", "offset"), &VisualServer::viewport_set_canvas_transform);
- ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &VisualServer::viewport_set_transparent_background);
- ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &VisualServer::viewport_set_global_canvas_transform);
- ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &VisualServer::viewport_set_canvas_stacking);
- ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &VisualServer::viewport_set_shadow_atlas_size);
- ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &VisualServer::viewport_set_shadow_atlas_quadrant_subdivision);
- ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &VisualServer::viewport_set_msaa);
- ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &VisualServer::viewport_get_render_info);
- ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &VisualServer::viewport_set_debug_draw);
-
- ClassDB::bind_method(D_METHOD("environment_create"), &VisualServer::environment_create);
- ClassDB::bind_method(D_METHOD("environment_set_background", "env", "bg"), &VisualServer::environment_set_background);
- ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &VisualServer::environment_set_sky);
- ClassDB::bind_method(D_METHOD("environment_set_sky_custom_fov", "env", "scale"), &VisualServer::environment_set_sky_custom_fov);
- ClassDB::bind_method(D_METHOD("environment_set_sky_orientation", "env", "orientation"), &VisualServer::environment_set_sky_orientation);
- ClassDB::bind_method(D_METHOD("environment_set_bg_color", "env", "color"), &VisualServer::environment_set_bg_color);
- ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &VisualServer::environment_set_bg_energy);
- ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &VisualServer::environment_set_canvas_max_layer);
- ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &VisualServer::environment_set_ambient_light, DEFVAL(VS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(VS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color()));
- ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "level_flags", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap", "bicubic_upscale"), &VisualServer::environment_set_glow);
- ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &VisualServer::environment_set_tonemap);
- ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &VisualServer::environment_set_adjustment);
- ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance", "roughness"), &VisualServer::environment_set_ssr);
- ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "bias", "light_affect", "ao_channel_affect", "blur", "bilateral_sharpness"), &VisualServer::environment_set_ssao);
- ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "color", "sun_color", "sun_amount"), &VisualServer::environment_set_fog);
-
- ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "enable", "depth_begin", "depth_end", "depth_curve", "transmit", "transmit_curve"), &VisualServer::environment_set_fog_depth);
-
- ClassDB::bind_method(D_METHOD("environment_set_fog_height", "env", "enable", "min_height", "max_height", "height_curve"), &VisualServer::environment_set_fog_height);
-
- ClassDB::bind_method(D_METHOD("scenario_create"), &VisualServer::scenario_create);
- ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &VisualServer::scenario_set_debug);
- ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &VisualServer::scenario_set_environment);
- ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &VisualServer::scenario_set_fallback_environment);
-
-#ifndef _3D_DISABLED
-
- ClassDB::bind_method(D_METHOD("instance_create2", "base", "scenario"), &VisualServer::instance_create2);
- ClassDB::bind_method(D_METHOD("instance_create"), &VisualServer::instance_create);
- ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &VisualServer::instance_set_base);
- ClassDB::bind_method(D_METHOD("instance_set_scenario", "instance", "scenario"), &VisualServer::instance_set_scenario);
- ClassDB::bind_method(D_METHOD("instance_set_layer_mask", "instance", "mask"), &VisualServer::instance_set_layer_mask);
- ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &VisualServer::instance_set_transform);
- ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &VisualServer::instance_attach_object_instance_id);
- ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &VisualServer::instance_set_blend_shape_weight);
- ClassDB::bind_method(D_METHOD("instance_set_surface_material", "instance", "surface", "material"), &VisualServer::instance_set_surface_material);
- ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &VisualServer::instance_set_visible);
- ClassDB::bind_method(D_METHOD("instance_set_use_lightmap", "instance", "lightmap_instance", "lightmap"), &VisualServer::instance_set_use_lightmap);
- ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &VisualServer::instance_set_custom_aabb);
- ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &VisualServer::instance_attach_skeleton);
- ClassDB::bind_method(D_METHOD("instance_set_exterior", "instance", "enabled"), &VisualServer::instance_set_exterior);
- ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &VisualServer::instance_set_extra_visibility_margin);
- ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &VisualServer::instance_geometry_set_flag);
- ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &VisualServer::instance_geometry_set_cast_shadows_setting);
- ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &VisualServer::instance_geometry_set_material_override);
- ClassDB::bind_method(D_METHOD("instance_geometry_set_draw_range", "instance", "min", "max", "min_margin", "max_margin"), &VisualServer::instance_geometry_set_draw_range);
- ClassDB::bind_method(D_METHOD("instance_geometry_set_as_instance_lod", "instance", "as_lod_of_instance"), &VisualServer::instance_geometry_set_as_instance_lod);
-
- ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &VisualServer::_instances_cull_aabb_bind, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &VisualServer::_instances_cull_ray_bind, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("instances_cull_convex", "convex", "scenario"), &VisualServer::_instances_cull_convex_bind, DEFVAL(RID()));
-#endif
- ClassDB::bind_method(D_METHOD("canvas_create"), &VisualServer::canvas_create);
- ClassDB::bind_method(D_METHOD("canvas_set_item_mirroring", "canvas", "item", "mirroring"), &VisualServer::canvas_set_item_mirroring);
- ClassDB::bind_method(D_METHOD("canvas_set_modulate", "canvas", "color"), &VisualServer::canvas_set_modulate);
-#ifndef _MSC_VER
-#warning TODO method bindings need to be fixed
-#endif
-#if 0
-
- ClassDB::bind_method(D_METHOD("canvas_item_create"), &VisualServer::canvas_item_create);
- ClassDB::bind_method(D_METHOD("canvas_item_set_parent", "item", "parent"), &VisualServer::canvas_item_set_parent);
- ClassDB::bind_method(D_METHOD("canvas_item_set_visible", "item", "visible"), &VisualServer::canvas_item_set_visible);
- ClassDB::bind_method(D_METHOD("canvas_item_set_light_mask", "item", "mask"), &VisualServer::canvas_item_set_light_mask);
- ClassDB::bind_method(D_METHOD("canvas_item_set_transform", "item", "transform"), &VisualServer::canvas_item_set_transform);
- ClassDB::bind_method(D_METHOD("canvas_item_set_clip", "item", "clip"), &VisualServer::canvas_item_set_clip);
- ClassDB::bind_method(D_METHOD("canvas_item_set_distance_field_mode", "item", "enabled"), &VisualServer::canvas_item_set_distance_field_mode);
- ClassDB::bind_method(D_METHOD("canvas_item_set_custom_rect", "item", "use_custom_rect", "rect"), &VisualServer::canvas_item_set_custom_rect, DEFVAL(Rect2()));
- ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &VisualServer::canvas_item_set_modulate);
- ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &VisualServer::canvas_item_set_self_modulate);
- ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &VisualServer::canvas_item_set_draw_behind_parent);
- ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &VisualServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &VisualServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &VisualServer::canvas_item_add_rect);
- ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &VisualServer::canvas_item_add_circle);
- ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose", "normal_map"), &VisualServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(RID()), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate", "normal_map"), &VisualServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width", "normal_map"), &VisualServer::canvas_item_add_primitive, DEFVAL(1.0), DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture", "normal_map", "antialiased"), &VisualServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID()), DEFVAL(RID()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased"), &VisualServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture", "normal_map"), &VisualServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()), DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_multimesh, DEFVAL(RID()));
- ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &VisualServer::canvas_item_add_particles);
- ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &VisualServer::canvas_item_add_set_transform);
- ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &VisualServer::canvas_item_add_clip_ignore);
- ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &VisualServer::canvas_item_set_sort_children_by_y);
-#endif
- ClassDB::bind_method(D_METHOD("canvas_item_set_z_index", "item", "z_index"), &VisualServer::canvas_item_set_z_index);
- ClassDB::bind_method(D_METHOD("canvas_item_set_z_as_relative_to_parent", "item", "enabled"), &VisualServer::canvas_item_set_z_as_relative_to_parent);
- ClassDB::bind_method(D_METHOD("canvas_item_set_copy_to_backbuffer", "item", "enabled", "rect"), &VisualServer::canvas_item_set_copy_to_backbuffer);
- ClassDB::bind_method(D_METHOD("canvas_item_clear", "item"), &VisualServer::canvas_item_clear);
- ClassDB::bind_method(D_METHOD("canvas_item_set_draw_index", "item", "index"), &VisualServer::canvas_item_set_draw_index);
- ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &VisualServer::canvas_item_set_material);
- ClassDB::bind_method(D_METHOD("canvas_item_set_use_parent_material", "item", "enabled"), &VisualServer::canvas_item_set_use_parent_material);
- ClassDB::bind_method(D_METHOD("canvas_light_create"), &VisualServer::canvas_light_create);
- ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &VisualServer::canvas_light_attach_to_canvas);
- ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &VisualServer::canvas_light_set_enabled);
- ClassDB::bind_method(D_METHOD("canvas_light_set_scale", "light", "scale"), &VisualServer::canvas_light_set_scale);
- ClassDB::bind_method(D_METHOD("canvas_light_set_transform", "light", "transform"), &VisualServer::canvas_light_set_transform);
- ClassDB::bind_method(D_METHOD("canvas_light_set_texture", "light", "texture"), &VisualServer::canvas_light_set_texture);
- ClassDB::bind_method(D_METHOD("canvas_light_set_texture_offset", "light", "offset"), &VisualServer::canvas_light_set_texture_offset);
- ClassDB::bind_method(D_METHOD("canvas_light_set_color", "light", "color"), &VisualServer::canvas_light_set_color);
- ClassDB::bind_method(D_METHOD("canvas_light_set_height", "light", "height"), &VisualServer::canvas_light_set_height);
- ClassDB::bind_method(D_METHOD("canvas_light_set_energy", "light", "energy"), &VisualServer::canvas_light_set_energy);
- ClassDB::bind_method(D_METHOD("canvas_light_set_z_range", "light", "min_z", "max_z"), &VisualServer::canvas_light_set_z_range);
- ClassDB::bind_method(D_METHOD("canvas_light_set_layer_range", "light", "min_layer", "max_layer"), &VisualServer::canvas_light_set_layer_range);
- ClassDB::bind_method(D_METHOD("canvas_light_set_item_cull_mask", "light", "mask"), &VisualServer::canvas_light_set_item_cull_mask);
- ClassDB::bind_method(D_METHOD("canvas_light_set_item_shadow_cull_mask", "light", "mask"), &VisualServer::canvas_light_set_item_shadow_cull_mask);
- ClassDB::bind_method(D_METHOD("canvas_light_set_mode", "light", "mode"), &VisualServer::canvas_light_set_mode);
- ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_enabled", "light", "enabled"), &VisualServer::canvas_light_set_shadow_enabled);
- ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_buffer_size", "light", "size"), &VisualServer::canvas_light_set_shadow_buffer_size);
- ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_filter", "light", "filter"), &VisualServer::canvas_light_set_shadow_filter);
- ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &VisualServer::canvas_light_set_shadow_color);
- ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &VisualServer::canvas_light_set_shadow_smooth);
-
- ClassDB::bind_method(D_METHOD("canvas_light_occluder_create"), &VisualServer::canvas_light_occluder_create);
- ClassDB::bind_method(D_METHOD("canvas_light_occluder_attach_to_canvas", "occluder", "canvas"), &VisualServer::canvas_light_occluder_attach_to_canvas);
- ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_enabled", "occluder", "enabled"), &VisualServer::canvas_light_occluder_set_enabled);
- ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_polygon", "occluder", "polygon"), &VisualServer::canvas_light_occluder_set_polygon);
- ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &VisualServer::canvas_light_occluder_set_transform);
- ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &VisualServer::canvas_light_occluder_set_light_mask);
-
- ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &VisualServer::canvas_occluder_polygon_create);
- ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &VisualServer::canvas_occluder_polygon_set_shape);
- ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape_as_lines", "occluder_polygon", "shape"), &VisualServer::canvas_occluder_polygon_set_shape_as_lines);
- ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_cull_mode", "occluder_polygon", "mode"), &VisualServer::canvas_occluder_polygon_set_cull_mode);
-
- ClassDB::bind_method(D_METHOD("black_bars_set_margins", "left", "top", "right", "bottom"), &VisualServer::black_bars_set_margins);
- ClassDB::bind_method(D_METHOD("black_bars_set_images", "left", "top", "right", "bottom"), &VisualServer::black_bars_set_images);
-
- ClassDB::bind_method(D_METHOD("free_rid", "rid"), &VisualServer::free); // shouldn't conflict with Object::free()
-
- ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &VisualServer::request_frame_drawn_callback);
- ClassDB::bind_method(D_METHOD("has_changed"), &VisualServer::has_changed);
- ClassDB::bind_method(D_METHOD("init"), &VisualServer::init);
- ClassDB::bind_method(D_METHOD("finish"), &VisualServer::finish);
- ClassDB::bind_method(D_METHOD("get_render_info", "info"), &VisualServer::get_render_info);
- ClassDB::bind_method(D_METHOD("get_video_adapter_name"), &VisualServer::get_video_adapter_name);
- ClassDB::bind_method(D_METHOD("get_video_adapter_vendor"), &VisualServer::get_video_adapter_vendor);
-#ifndef _3D_DISABLED
-
- ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &VisualServer::make_sphere_mesh);
- ClassDB::bind_method(D_METHOD("get_test_cube"), &VisualServer::get_test_cube);
-#endif
- ClassDB::bind_method(D_METHOD("get_test_texture"), &VisualServer::get_test_texture);
- ClassDB::bind_method(D_METHOD("get_white_texture"), &VisualServer::get_white_texture);
-
- ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "use_filter"), &VisualServer::set_boot_image, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &VisualServer::set_default_clear_color);
-
- ClassDB::bind_method(D_METHOD("has_feature", "feature"), &VisualServer::has_feature);
- ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &VisualServer::has_os_feature);
- ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &VisualServer::set_debug_generate_wireframes);
-
- BIND_CONSTANT(NO_INDEX_ARRAY);
- BIND_CONSTANT(ARRAY_WEIGHTS_SIZE);
- BIND_CONSTANT(CANVAS_ITEM_Z_MIN);
- BIND_CONSTANT(CANVAS_ITEM_Z_MAX);
- BIND_CONSTANT(MAX_GLOW_LEVELS);
- BIND_CONSTANT(MAX_CURSORS);
-
- BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MIN);
- BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MAX);
-
- BIND_ENUM_CONSTANT(TEXTURE_LAYERED_2D_ARRAY);
- BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP);
- BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP_ARRAY);
-
- BIND_ENUM_CONSTANT(CUBEMAP_LAYER_LEFT);
- BIND_ENUM_CONSTANT(CUBEMAP_LAYER_RIGHT);
- BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BOTTOM);
- BIND_ENUM_CONSTANT(CUBEMAP_LAYER_TOP);
- BIND_ENUM_CONSTANT(CUBEMAP_LAYER_FRONT);
- BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BACK);
-
- BIND_ENUM_CONSTANT(SHADER_SPATIAL);
- BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM);
- BIND_ENUM_CONSTANT(SHADER_PARTICLES);
- BIND_ENUM_CONSTANT(SHADER_MAX);
-
- BIND_ENUM_CONSTANT(ARRAY_VERTEX);
- BIND_ENUM_CONSTANT(ARRAY_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_BONES);
- BIND_ENUM_CONSTANT(ARRAY_WEIGHTS);
- BIND_ENUM_CONSTANT(ARRAY_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_MAX);
-
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS);
- BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
-
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_COLOR);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TEX_UV2);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
- BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
- BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
- BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
-
- BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
- BIND_ENUM_CONSTANT(PRIMITIVE_LINES);
- BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP);
- BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES);
- BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP);
- BIND_ENUM_CONSTANT(PRIMITIVE_MAX);
-
- BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
- BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
-
- BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_2D);
- BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_3D);
-
- BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL);
- BIND_ENUM_CONSTANT(LIGHT_OMNI);
- BIND_ENUM_CONSTANT(LIGHT_SPOT);
-
- BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_INDIRECT_ENERGY);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SPECULAR);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ANGLE);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ATTENUATION);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_CONTACT_SHADOW_SIZE);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_MAX_DISTANCE);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_FADE_START);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE);
- BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX);
-
- BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID);
- BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE);
-
- BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
- BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS);
- BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS);
-
- BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
- BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED);
-
- BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE);
- BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS);
-
- BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_INDEX);
- BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_LIFETIME);
- BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_VIEW_DEPTH);
-
- BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED);
- BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE);
- BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE);
- BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ALWAYS);
-
- BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ALWAYS);
- BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_NEVER);
- BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ONLY_NEXT_FRAME);
-
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_DISABLED);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_2X);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_4X);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_8X);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_16X);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_EXT_2X);
- BIND_ENUM_CONSTANT(VIEWPORT_MSAA_EXT_4X);
-
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MAX);
-
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DISABLED);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_UNSHADED);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_LIGHTING);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OVERDRAW);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_WIREFRAME);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SSAO);
- BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER);
-
- BIND_ENUM_CONSTANT(SKY_MODE_QUALITY);
- BIND_ENUM_CONSTANT(SKY_MODE_REALTIME);
-
- BIND_ENUM_CONSTANT(ENV_BG_CLEAR_COLOR);
- BIND_ENUM_CONSTANT(ENV_BG_COLOR);
- BIND_ENUM_CONSTANT(ENV_BG_SKY);
- BIND_ENUM_CONSTANT(ENV_BG_CANVAS);
- BIND_ENUM_CONSTANT(ENV_BG_KEEP);
- BIND_ENUM_CONSTANT(ENV_BG_CAMERA_FEED);
- BIND_ENUM_CONSTANT(ENV_BG_MAX);
-
- BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_BG);
- BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_DISABLED);
- BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_COLOR);
- BIND_ENUM_CONSTANT(ENV_AMBIENT_SOURCE_SKY);
-
- BIND_ENUM_CONSTANT(ENV_REFLECTION_SOURCE_BG);
- BIND_ENUM_CONSTANT(ENV_REFLECTION_SOURCE_DISABLED);
- BIND_ENUM_CONSTANT(ENV_REFLECTION_SOURCE_SKY);
-
- BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_ADDITIVE);
- BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_SCREEN);
- BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_SOFTLIGHT);
- BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_REPLACE);
- BIND_ENUM_CONSTANT(ENV_GLOW_BLEND_MODE_MIX);
-
- BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_LINEAR);
- BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_REINHARD);
- BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_FILMIC);
- BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_ACES);
-
- BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_DISABLED);
- BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_1x1);
- BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_2x2);
- BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_3x3);
-
- BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_LOW);
- BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_MEDIUM);
- BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_HIGH);
- BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_ULTRA);
-
- BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_VERY_LOW);
- BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_LOW);
- BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_MEDIUM);
- BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_HIGH);
-
- BIND_ENUM_CONSTANT(DOF_BOKEH_BOX);
- BIND_ENUM_CONSTANT(DOF_BOKEH_HEXAGON);
- BIND_ENUM_CONSTANT(DOF_BOKEH_CIRCLE);
-
- BIND_ENUM_CONSTANT(SCENARIO_DEBUG_DISABLED);
- BIND_ENUM_CONSTANT(SCENARIO_DEBUG_WIREFRAME);
- BIND_ENUM_CONSTANT(SCENARIO_DEBUG_OVERDRAW);
- BIND_ENUM_CONSTANT(SCENARIO_DEBUG_SHADELESS);
-
- BIND_ENUM_CONSTANT(INSTANCE_NONE);
- BIND_ENUM_CONSTANT(INSTANCE_MESH);
- BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH);
- BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE);
- BIND_ENUM_CONSTANT(INSTANCE_PARTICLES);
- BIND_ENUM_CONSTANT(INSTANCE_LIGHT);
- BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE);
- BIND_ENUM_CONSTANT(INSTANCE_GI_PROBE);
- BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP_CAPTURE);
- 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_MAX);
-
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON);
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED);
- BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
-
- BIND_ENUM_CONSTANT(NINE_PATCH_STRETCH);
- BIND_ENUM_CONSTANT(NINE_PATCH_TILE);
- BIND_ENUM_CONSTANT(NINE_PATCH_TILE_FIT);
-
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_DEFAULT);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_FILTER_MAX);
-
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
- BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MAX);
-
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_ADD);
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_SUB);
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MIX);
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_MASK);
-
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_NONE);
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF5);
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF13);
- BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_MAX);
-
- BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_DISABLED);
- BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE);
- BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE);
-
- BIND_ENUM_CONSTANT(INFO_OBJECTS_IN_FRAME);
- BIND_ENUM_CONSTANT(INFO_VERTICES_IN_FRAME);
- BIND_ENUM_CONSTANT(INFO_MATERIAL_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(INFO_SHADER_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(INFO_SURFACE_CHANGES_IN_FRAME);
- BIND_ENUM_CONSTANT(INFO_DRAW_CALLS_IN_FRAME);
- BIND_ENUM_CONSTANT(INFO_USAGE_VIDEO_MEM_TOTAL);
- BIND_ENUM_CONSTANT(INFO_VIDEO_MEM_USED);
- BIND_ENUM_CONSTANT(INFO_TEXTURE_MEM_USED);
- BIND_ENUM_CONSTANT(INFO_VERTEX_MEM_USED);
-
- BIND_ENUM_CONSTANT(FEATURE_SHADERS);
- BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED);
-
- ADD_SIGNAL(MethodInfo("frame_pre_draw"));
- ADD_SIGNAL(MethodInfo("frame_post_draw"));
-}
-
-void VisualServer::_canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate) {
-
- ERR_FAIL_COND(p_margins.size() != 4);
- //canvas_item_add_style_box(p_item,p_rect,p_source,p_texture,Vector2(p_margins[0],p_margins[1]),Vector2(p_margins[2],p_margins[3]),true,p_modulate);
-}
-
-void VisualServer::_camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) {
-
- camera_set_orthogonal(p_camera, p_size, p_z_near, p_z_far);
-}
-
-void VisualServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry::MeshData &p_mesh_data) {
-
- Vector<Vector3> vertices;
- Vector<Vector3> normals;
-
- for (int i = 0; i < p_mesh_data.faces.size(); i++) {
-
- const Geometry::MeshData::Face &f = p_mesh_data.faces[i];
-
- for (int j = 2; j < f.indices.size(); j++) {
-
-#define _ADD_VERTEX(m_idx) \
- vertices.push_back(p_mesh_data.vertices[f.indices[m_idx]]); \
- normals.push_back(f.plane.normal);
-
- _ADD_VERTEX(0);
- _ADD_VERTEX(j - 1);
- _ADD_VERTEX(j);
- }
- }
-
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[ARRAY_VERTEX] = vertices;
- d[ARRAY_NORMAL] = normals;
- mesh_add_surface_from_arrays(p_mesh, PRIMITIVE_TRIANGLES, d);
-}
-
-void VisualServer::mesh_add_surface_from_planes(RID p_mesh, const Vector<Plane> &p_planes) {
-
- Geometry::MeshData mdata = Geometry::build_convex_mesh(p_planes);
- mesh_add_surface_from_mesh_data(p_mesh, mdata);
-}
-
-void VisualServer::immediate_vertex_2d(RID p_immediate, const Vector2 &p_vertex) {
- immediate_vertex(p_immediate, Vector3(p_vertex.x, p_vertex.y, 0));
-}
-
-RID VisualServer::instance_create2(RID p_base, RID p_scenario) {
-
- RID instance = instance_create();
- instance_set_base(instance, p_base);
- instance_set_scenario(instance, p_scenario);
- return instance;
-}
-
-VisualServer::VisualServer() {
-
- //ERR_FAIL_COND(singleton);
- 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("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/shadow_atlas/size", 4096);
- GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048);
- 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/quadrant_0_subdiv", 1);
- GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2);
- GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3);
- 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"));
-
- GLOBAL_DEF("rendering/quality/shadows/filter_mode", 1);
- GLOBAL_DEF("rendering/quality/shadows/filter_mode.mobile", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadows/filter_mode", PropertyInfo(Variant::INT, "rendering/quality/shadows/filter_mode", PROPERTY_HINT_ENUM, "Disabled (Fastest),PCF5,PCF13 (Slowest)"));
-
- GLOBAL_DEF("rendering/quality/reflections/roughness_layers", 6);
- 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", 128);
- GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_size.mobile", 128);
- GLOBAL_DEF("rendering/quality/reflection_atlas/reflection_count", 64);
-
- 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, "Ultra-Low (1 cone - fastest),Medium (4 cones), High (6 cones - slowest)"));
-
- 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/filters/use_nearest_mipmap_filter", false);
- GLOBAL_DEF("rendering/quality/filters/max_anisotropy", 4);
-
- GLOBAL_DEF("rendering/quality/filters/depth_of_field_bokeh_shape", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/depth_of_field_bokeh_shape", PropertyInfo(Variant::INT, "rendering/quality/filters/depth_of_field_bokeh_shape", PROPERTY_HINT_ENUM, "Box (Fastest),Hexagon,Circle (Slowest)"));
- GLOBAL_DEF("rendering/quality/filters/depth_of_field_bokeh_quality", 2);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/depth_of_field_bokeh_quality", PropertyInfo(Variant::INT, "rendering/quality/filters/depth_of_field_bokeh_quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low,Medium,High (Slow)"));
- GLOBAL_DEF("rendering/quality/filters/depth_of_field_use_jitter", false);
-
- GLOBAL_DEF("rendering/quality/ssao/quality", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/ssao/quality", PropertyInfo(Variant::INT, "rendering/quality/ssao/quality", PROPERTY_HINT_ENUM, "Low (Fast),Medium,High (Slow),Ultra (Very Slow)"));
- GLOBAL_DEF("rendering/quality/ssao/half_size", false);
-
- GLOBAL_DEF("rendering/quality/filters/screen_space_roughness_limiter", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/screen_space_roughness_limiter", PropertyInfo(Variant::INT, "rendering/quality/filters/screen_space_roughness_limiter", PROPERTY_HINT_ENUM, "Disabled,Enabled (Small Cost)"));
- GLOBAL_DEF("rendering/quality/filters/screen_space_roughness_limiter_curve", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/screen_space_roughness_limiter_curve", PropertyInfo(Variant::FLOAT, "rendering/quality/filters/screen_space_roughness_limiter_curve", PROPERTY_HINT_EXP_EASING, "0.01,8,0.01"));
-}
-
-VisualServer::~VisualServer() {
-
- singleton = NULL;
-}
diff --git a/servers/visual_server.h b/servers/visual_server.h
deleted file mode 100644
index 9129f940ee..0000000000
--- a/servers/visual_server.h
+++ /dev/null
@@ -1,1155 +0,0 @@
-/*************************************************************************/
-/* visual_server.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 VISUAL_SERVER_H
-#define VISUAL_SERVER_H
-
-#include "core/image.h"
-#include "core/math/geometry.h"
-#include "core/math/transform_2d.h"
-#include "core/object.h"
-#include "core/rid.h"
-#include "core/variant.h"
-
-class VisualServer : public Object {
-
- GDCLASS(VisualServer, Object);
-
- static VisualServer *singleton;
-
- int mm_policy;
-
- void _camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
- void _canvas_item_add_style_box(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector<float> &p_margins, const Color &p_modulate = Color(1, 1, 1));
- Array _get_array_from_surface(uint32_t p_format, Vector<uint8_t> p_vertex_data, int p_vertex_len, Vector<uint8_t> p_index_data, int p_index_len) const;
-
-protected:
- RID _make_test_cube();
- void _free_internal_rids();
- RID test_texture;
- RID white_texture;
- RID test_material;
-
- Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, Vector<uint8_t> &r_vertex_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb);
-
- static VisualServer *(*create_func)();
- static void _bind_methods();
-
-public:
- static VisualServer *get_singleton();
- static VisualServer *create();
-
- enum {
- NO_INDEX_ARRAY = -1,
- ARRAY_WEIGHTS_SIZE = 4,
- CANVAS_ITEM_Z_MIN = -4096,
- CANVAS_ITEM_Z_MAX = 4096,
- MAX_GLOW_LEVELS = 7,
- MAX_CURSORS = 8,
- };
-
- /* TEXTURE API */
-
- enum TextureLayeredType {
- TEXTURE_LAYERED_2D_ARRAY,
- TEXTURE_LAYERED_CUBEMAP,
- TEXTURE_LAYERED_CUBEMAP_ARRAY,
- };
-
- enum CubeMapLayer {
-
- CUBEMAP_LAYER_LEFT,
- CUBEMAP_LAYER_RIGHT,
- CUBEMAP_LAYER_BOTTOM,
- CUBEMAP_LAYER_TOP,
- CUBEMAP_LAYER_FRONT,
- CUBEMAP_LAYER_BACK
- };
-
- virtual RID texture_2d_create(const Ref<Image> &p_image) = 0;
- virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, TextureLayeredType p_layered_type) = 0;
- virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent
- virtual RID texture_proxy_create(RID p_base) = 0;
-
- 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;
- virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0;
- virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 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() = 0;
- virtual RID texture_3d_placeholder_create() = 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;
- virtual Ref<Image> texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const = 0;
-
- virtual void texture_replace(RID p_texture, RID p_by_texture) = 0;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0;
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- virtual void texture_bind(RID p_texture, uint32_t p_texture_no) = 0;
-#endif
-
- virtual void texture_set_path(RID p_texture, const String &p_path) = 0;
- virtual String texture_get_path(RID p_texture) const = 0;
-
- typedef void (*TextureDetectCallback)(void *);
-
- virtual void texture_set_detect_3d_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0;
- virtual void texture_set_detect_normal_callback(RID p_texture, TextureDetectCallback p_callback, void *p_userdata) = 0;
-
- enum TextureDetectRoughnessChannel {
- TEXTURE_DETECT_ROUGNHESS_R,
- TEXTURE_DETECT_ROUGNHESS_G,
- TEXTURE_DETECT_ROUGNHESS_B,
- TEXTURE_DETECT_ROUGNHESS_A,
- TEXTURE_DETECT_ROUGNHESS_GRAY,
- };
-
- typedef void (*TextureDetectRoughnessCallback)(void *, const String &, TextureDetectRoughnessChannel);
- virtual void texture_set_detect_roughness_callback(RID p_texture, TextureDetectRoughnessCallback p_callback, void *p_userdata) = 0;
-
- struct TextureInfo {
- RID texture;
- uint32_t width;
- uint32_t height;
- uint32_t depth;
- Image::Format format;
- int bytes;
- String path;
- };
-
- virtual void texture_debug_usage(List<TextureInfo> *r_info) = 0;
- Array _texture_debug_usage_bind();
-
- virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
-
- /* SHADER API */
-
- enum ShaderMode {
-
- SHADER_SPATIAL,
- SHADER_CANVAS_ITEM,
- SHADER_PARTICLES,
- SHADER_MAX
- };
-
- virtual RID shader_create() = 0;
-
- virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
- virtual String shader_get_code(RID p_shader) const = 0;
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
- Array _shader_get_param_list_bind(RID p_shader) const;
- virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const = 0;
-
- virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0;
- virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0;
-
- /* COMMON MATERIAL API */
-
- enum {
- MATERIAL_RENDER_PRIORITY_MIN = -128,
- MATERIAL_RENDER_PRIORITY_MAX = 127,
-
- };
- virtual RID material_create() = 0;
-
- virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
-
- virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) = 0;
- virtual Variant material_get_param(RID p_material, const StringName &p_param) const = 0;
-
- virtual void material_set_render_priority(RID p_material, int priority) = 0;
-
- virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0;
-
- /* MESH API */
-
- enum ArrayType {
-
- ARRAY_VERTEX = 0,
- ARRAY_NORMAL = 1,
- ARRAY_TANGENT = 2,
- ARRAY_COLOR = 3,
- ARRAY_TEX_UV = 4,
- ARRAY_TEX_UV2 = 5,
- ARRAY_BONES = 6,
- ARRAY_WEIGHTS = 7,
- ARRAY_INDEX = 8,
- ARRAY_MAX = 9
- };
-
- enum ArrayFormat {
- /* ARRAY FORMAT FLAGS */
- ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, // mandatory
- ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL,
- ARRAY_FORMAT_TANGENT = 1 << ARRAY_TANGENT,
- ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
- ARRAY_FORMAT_TEX_UV = 1 << ARRAY_TEX_UV,
- ARRAY_FORMAT_TEX_UV2 = 1 << ARRAY_TEX_UV2,
- ARRAY_FORMAT_BONES = 1 << ARRAY_BONES,
- ARRAY_FORMAT_WEIGHTS = 1 << ARRAY_WEIGHTS,
- ARRAY_FORMAT_INDEX = 1 << ARRAY_INDEX,
-
- ARRAY_COMPRESS_BASE = (ARRAY_INDEX + 1),
- ARRAY_COMPRESS_NORMAL = 1 << (ARRAY_NORMAL + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TANGENT = 1 << (ARRAY_TANGENT + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_COLOR = 1 << (ARRAY_COLOR + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TEX_UV = 1 << (ARRAY_TEX_UV + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_TEX_UV2 = 1 << (ARRAY_TEX_UV2 + ARRAY_COMPRESS_BASE),
- ARRAY_COMPRESS_INDEX = 1 << (ARRAY_INDEX + ARRAY_COMPRESS_BASE),
-
- ARRAY_FLAG_USE_2D_VERTICES = ARRAY_COMPRESS_INDEX << 1,
- ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
-
- ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2
-
- };
-
- enum PrimitiveType {
- PRIMITIVE_POINTS,
- PRIMITIVE_LINES,
- PRIMITIVE_LINE_STRIP,
- PRIMITIVE_TRIANGLES,
- PRIMITIVE_TRIANGLE_STRIP,
- PRIMITIVE_MAX,
- };
-
- struct SurfaceData {
-
- PrimitiveType primitive = PRIMITIVE_MAX;
-
- uint32_t format = 0;
- Vector<uint8_t> vertex_data;
- uint32_t vertex_count = 0;
- Vector<uint8_t> index_data;
- uint32_t index_count = 0;
-
- AABB aabb;
- struct LOD {
- float edge_length;
- Vector<uint8_t> index_data;
- };
- Vector<LOD> lods;
- Vector<AABB> bone_aabbs;
-
- Vector<Vector<uint8_t> > blend_shapes;
-
- RID material;
- };
-
- virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces) = 0;
- virtual RID mesh_create() = 0;
-
- virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const;
- virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const;
- /// Returns stride
- virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const;
- virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
- Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const;
- Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const;
- Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const;
- Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const;
-
- virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT);
- virtual void mesh_add_surface(RID p_mesh, const SurfaceData &p_surface) = 0;
-
- virtual int mesh_get_blend_shape_count(RID p_mesh) const = 0;
-
- enum BlendShapeMode {
- BLEND_SHAPE_MODE_NORMALIZED,
- BLEND_SHAPE_MODE_RELATIVE,
- };
-
- virtual void mesh_set_blend_shape_mode(RID p_mesh, BlendShapeMode p_mode) = 0;
- virtual BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0;
-
- virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0;
-
- virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0;
- virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0;
-
- virtual SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const = 0;
-
- virtual int mesh_get_surface_count(RID p_mesh) const = 0;
-
- virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
- virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0;
-
- virtual void mesh_clear(RID p_mesh) = 0;
-
- /* MULTIMESH API */
-
- virtual RID multimesh_create() = 0;
-
- enum MultimeshTransformFormat {
- MULTIMESH_TRANSFORM_2D,
- 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 int multimesh_get_instance_count(RID p_multimesh) const = 0;
-
- virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0;
- virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0;
- virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0;
- virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
- virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
-
- virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
- virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
-
- virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
- virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
- virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;
- virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
-
- virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
- virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
-
- virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
- virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0;
-
- /* IMMEDIATE API */
-
- virtual RID immediate_create() = 0;
- virtual void immediate_begin(RID p_immediate, PrimitiveType p_rimitive, RID p_texture = RID()) = 0;
- virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0;
- virtual void immediate_vertex_2d(RID p_immediate, const Vector2 &p_vertex);
- virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0;
- virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0;
- virtual void immediate_color(RID p_immediate, const Color &p_color) = 0;
- virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0;
- virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0;
- virtual void immediate_end(RID p_immediate) = 0;
- virtual void immediate_clear(RID p_immediate) = 0;
- virtual void immediate_set_material(RID p_immediate, RID p_material) = 0;
- virtual RID immediate_get_material(RID p_immediate) const = 0;
-
- /* SKELETON API */
-
- virtual RID skeleton_create() = 0;
- virtual void skeleton_allocate(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;
- virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
- virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
- virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
-
- /* Light API */
-
- enum LightType {
- LIGHT_DIRECTIONAL,
- LIGHT_OMNI,
- LIGHT_SPOT
- };
-
- enum LightParam {
-
- LIGHT_PARAM_ENERGY,
- LIGHT_PARAM_INDIRECT_ENERGY,
- LIGHT_PARAM_SPECULAR,
- LIGHT_PARAM_RANGE,
- LIGHT_PARAM_ATTENUATION,
- LIGHT_PARAM_SPOT_ANGLE,
- LIGHT_PARAM_SPOT_ATTENUATION,
- LIGHT_PARAM_CONTACT_SHADOW_SIZE,
- LIGHT_PARAM_SHADOW_MAX_DISTANCE,
- LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
- LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
- LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
- LIGHT_PARAM_SHADOW_FADE_START,
- LIGHT_PARAM_SHADOW_NORMAL_BIAS,
- LIGHT_PARAM_SHADOW_BIAS,
- LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
- LIGHT_PARAM_MAX
- };
-
- virtual RID directional_light_create() = 0;
- virtual RID omni_light_create() = 0;
- virtual RID spot_light_create() = 0;
-
- virtual void light_set_color(RID p_light, const Color &p_color) = 0;
- virtual void light_set_param(RID p_light, LightParam p_param, float p_value) = 0;
- virtual void light_set_shadow(RID p_light, bool p_enabled) = 0;
- virtual void light_set_shadow_color(RID p_light, const Color &p_color) = 0;
- virtual void light_set_projector(RID p_light, RID p_texture) = 0;
- virtual void light_set_negative(RID p_light, bool p_enable) = 0;
- virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
- virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
- virtual void light_set_use_gi(RID p_light, bool p_enable) = 0;
-
- // omni light
- enum LightOmniShadowMode {
- LIGHT_OMNI_SHADOW_DUAL_PARABOLOID,
- LIGHT_OMNI_SHADOW_CUBE,
- };
-
- virtual void light_omni_set_shadow_mode(RID p_light, LightOmniShadowMode p_mode) = 0;
-
- // directional light
- enum LightDirectionalShadowMode {
- LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL,
- LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS,
- LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS
- };
-
- virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0;
- virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
-
- enum LightDirectionalShadowDepthRangeMode {
- LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
- LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED,
-
- };
-
- virtual void light_directional_set_shadow_depth_range_mode(RID p_light, LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
-
- /* PROBE API */
-
- virtual RID reflection_probe_create() = 0;
-
- enum ReflectionProbeUpdateMode {
- REFLECTION_PROBE_UPDATE_ONCE,
- REFLECTION_PROBE_UPDATE_ALWAYS,
- };
-
- virtual void reflection_probe_set_update_mode(RID p_probe, ReflectionProbeUpdateMode p_mode) = 0;
- virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0;
- virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_color) = 0;
- virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) = 0;
- virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) = 0;
- virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance) = 0;
- virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) = 0;
- virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) = 0;
- virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0;
- virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
- virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
- virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
- virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
-
- /* GI PROBE API */
-
- 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 AABB gi_probe_get_bounds(RID p_gi_probe) const = 0;
- virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0;
- virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0;
- virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0;
- virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0;
- virtual float gi_probe_get_energy(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0;
- virtual float gi_probe_get_ao(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0;
- virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0;
- virtual float gi_probe_get_bias(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0;
- virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0;
- virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0;
-
- virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0;
- virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0;
-
- /* LIGHTMAP CAPTURE */
-
- virtual RID lightmap_capture_create() = 0;
- virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0;
- virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0;
- virtual void lightmap_capture_set_octree(RID p_capture, const Vector<uint8_t> &p_octree) = 0;
- virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0;
- virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0;
- virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0;
- virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
- virtual Vector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
- virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
- virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
-
- /* PARTICLES API */
-
- virtual RID particles_create() = 0;
-
- virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
- virtual bool particles_get_emitting(RID p_particles) = 0;
- virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
- virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
- virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
- virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
- virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
- virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
- virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
- virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
- 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_fractional_delta(RID p_particles, bool p_enable) = 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;
-
- enum ParticlesDrawOrder {
- PARTICLES_DRAW_ORDER_INDEX,
- PARTICLES_DRAW_ORDER_LIFETIME,
- PARTICLES_DRAW_ORDER_VIEW_DEPTH,
- };
-
- virtual void particles_set_draw_order(RID p_particles, ParticlesDrawOrder p_order) = 0;
-
- virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
- virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
-
- virtual AABB particles_get_current_aabb(RID p_particles) = 0;
-
- virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; //this is only used for 2D, in 3D it's automatic
-
- /* CAMERA API */
-
- virtual RID camera_create() = 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;
- virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0;
- virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0;
- virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
- virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
- 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;
-
- /*
- enum ParticlesCollisionMode {
- PARTICLES_COLLISION_NONE,
- PARTICLES_COLLISION_TEXTURE,
- PARTICLES_COLLISION_CUBEMAP,
- };
-
- virtual void particles_set_collision(RID p_particles,ParticlesCollisionMode p_mode,const Transform&, p_xform,const RID p_depth_tex,const RID p_normal_tex)=0;
-*/
- /* VIEWPORT TARGET API */
-
- virtual RID viewport_create() = 0;
-
- virtual void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) = 0;
- virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0;
- virtual void viewport_set_active(RID p_viewport, bool p_active) = 0;
- virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0;
-
- virtual void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), int p_screen = 0) = 0;
- virtual void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) = 0;
- virtual void viewport_detach(RID p_viewport) = 0;
-
- enum ViewportUpdateMode {
- VIEWPORT_UPDATE_DISABLED,
- VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated
- VIEWPORT_UPDATE_WHEN_VISIBLE, // default
- VIEWPORT_UPDATE_ALWAYS
- };
-
- virtual void viewport_set_update_mode(RID p_viewport, ViewportUpdateMode p_mode) = 0;
-
- enum ViewportClearMode {
-
- VIEWPORT_CLEAR_ALWAYS,
- VIEWPORT_CLEAR_NEVER,
- VIEWPORT_CLEAR_ONLY_NEXT_FRAME
- };
-
- virtual void viewport_set_clear_mode(RID p_viewport, ViewportClearMode p_clear_mode) = 0;
-
- virtual RID viewport_get_texture(RID p_viewport) const = 0;
-
- virtual void viewport_set_hide_scenario(RID p_viewport, bool p_hide) = 0;
- virtual void viewport_set_hide_canvas(RID p_viewport, bool p_hide) = 0;
- virtual void viewport_set_disable_environment(RID p_viewport, bool p_disable) = 0;
-
- virtual void viewport_attach_camera(RID p_viewport, RID p_camera) = 0;
- virtual void viewport_set_scenario(RID p_viewport, RID p_scenario) = 0;
- virtual void viewport_attach_canvas(RID p_viewport, RID p_canvas) = 0;
- virtual void viewport_remove_canvas(RID p_viewport, RID p_canvas) = 0;
- virtual void viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) = 0;
- virtual void viewport_set_transparent_background(RID p_viewport, bool p_enabled) = 0;
-
- virtual void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) = 0;
- virtual void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) = 0;
-
- virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0;
- virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0;
-
- enum ViewportMSAA {
- VIEWPORT_MSAA_DISABLED,
- VIEWPORT_MSAA_2X,
- VIEWPORT_MSAA_4X,
- VIEWPORT_MSAA_8X,
- VIEWPORT_MSAA_16X,
- VIEWPORT_MSAA_EXT_2X,
- VIEWPORT_MSAA_EXT_4X,
- };
-
- virtual void viewport_set_msaa(RID p_viewport, ViewportMSAA p_msaa) = 0;
-
- enum ViewportRenderInfo {
-
- VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME,
- VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME,
- VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME,
- VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME,
- VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME,
- VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME,
- VIEWPORT_RENDER_INFO_MAX
- };
-
- virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) = 0;
-
- enum ViewportDebugDraw {
- VIEWPORT_DEBUG_DRAW_DISABLED,
- VIEWPORT_DEBUG_DRAW_UNSHADED,
- VIEWPORT_DEBUG_DRAW_LIGHTING,
- VIEWPORT_DEBUG_DRAW_OVERDRAW,
- VIEWPORT_DEBUG_DRAW_WIREFRAME,
- VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER,
- VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO,
- VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING,
- VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION,
- VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS,
- VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
- VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE,
- VIEWPORT_DEBUG_DRAW_SSAO,
- VIEWPORT_DEBUG_DRAW_ROUGHNESS_LIMITER,
-
- };
-
- virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0;
-
- virtual void directional_shadow_atlas_set_size(int p_size) = 0;
-
- /* SKY API */
-
- enum SkyMode {
- SKY_MODE_QUALITY,
- SKY_MODE_REALTIME
- };
-
- virtual RID sky_create() = 0;
- virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) = 0;
- virtual void sky_set_mode(RID p_sky, SkyMode p_mode) = 0;
- virtual void sky_set_texture(RID p_sky, RID p_panorama) = 0;
-
- /* ENVIRONMENT API */
-
- virtual RID environment_create() = 0;
-
- enum EnvironmentBG {
-
- ENV_BG_CLEAR_COLOR,
- ENV_BG_COLOR,
- ENV_BG_SKY,
- ENV_BG_CANVAS,
- ENV_BG_KEEP,
- ENV_BG_CAMERA_FEED,
- ENV_BG_MAX
- };
-
- enum EnvironmentAmbientSource {
- ENV_AMBIENT_SOURCE_BG,
- ENV_AMBIENT_SOURCE_DISABLED,
- ENV_AMBIENT_SOURCE_COLOR,
- ENV_AMBIENT_SOURCE_SKY,
- };
-
- enum EnvironmentReflectionSource {
- ENV_REFLECTION_SOURCE_BG,
- ENV_REFLECTION_SOURCE_DISABLED,
- ENV_REFLECTION_SOURCE_SKY,
- };
-
- virtual void environment_set_background(RID p_env, EnvironmentBG p_bg) = 0;
- virtual void environment_set_sky(RID p_env, RID p_sky) = 0;
- virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) = 0;
- virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) = 0;
- virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0;
- virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0;
- virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0;
- virtual void environment_set_ambient_light(RID p_env, const Color &p_color, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0;
-// FIXME: Disabled during Vulkan refactoring, should be ported.
-#if 0
- virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0;
-#endif
-
- enum EnvironmentGlowBlendMode {
- ENV_GLOW_BLEND_MODE_ADDITIVE,
- ENV_GLOW_BLEND_MODE_SCREEN,
- ENV_GLOW_BLEND_MODE_SOFTLIGHT,
- ENV_GLOW_BLEND_MODE_REPLACE,
- ENV_GLOW_BLEND_MODE_MIX,
- };
- virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) = 0;
-
- enum EnvironmentToneMapper {
- ENV_TONE_MAPPER_LINEAR,
- ENV_TONE_MAPPER_REINHARD,
- ENV_TONE_MAPPER_FILMIC,
- ENV_TONE_MAPPER_ACES
- };
-
- virtual void environment_set_tonemap(RID p_env, 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_grey) = 0;
- virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
-
- virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness) = 0;
-
- enum EnvironmentSSAOBlur {
- ENV_SSAO_BLUR_DISABLED,
- ENV_SSAO_BLUR_1x1,
- ENV_SSAO_BLUR_2x2,
- ENV_SSAO_BLUR_3x3,
- };
-
- virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_bias, float p_light_affect, float p_ao_channel_affect, EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0;
-
- enum EnvironmentSSAOQuality {
- ENV_SSAO_QUALITY_LOW,
- ENV_SSAO_QUALITY_MEDIUM,
- ENV_SSAO_QUALITY_HIGH,
- ENV_SSAO_QUALITY_ULTRA,
- };
-
- virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size) = 0;
-
- virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0;
- virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0;
- virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0;
-
- virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0;
-
- /* CAMERA EFFECTS */
-
- virtual RID camera_effects_create() = 0;
-
- enum DOFBlurQuality {
- DOF_BLUR_QUALITY_VERY_LOW,
- DOF_BLUR_QUALITY_LOW,
- DOF_BLUR_QUALITY_MEDIUM,
- DOF_BLUR_QUALITY_HIGH,
- };
-
- virtual void camera_effects_set_dof_blur_quality(DOFBlurQuality p_quality, bool p_use_jitter) = 0;
-
- enum DOFBokehShape {
- DOF_BOKEH_BOX,
- DOF_BOKEH_HEXAGON,
- DOF_BOKEH_CIRCLE
- };
-
- virtual void camera_effects_set_dof_blur_bokeh_shape(DOFBokehShape p_shape) = 0;
-
- virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0;
- virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0;
-
- /* SCENARIO API */
-
- virtual RID scenario_create() = 0;
-
- enum ScenarioDebugMode {
- SCENARIO_DEBUG_DISABLED,
- SCENARIO_DEBUG_WIREFRAME,
- SCENARIO_DEBUG_OVERDRAW,
- SCENARIO_DEBUG_SHADELESS,
-
- };
-
- virtual void scenario_set_debug(RID p_scenario, ScenarioDebugMode p_debug_mode) = 0;
- virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0;
- virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0;
- virtual void scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) = 0;
-
- /* INSTANCING API */
-
- enum InstanceType {
-
- INSTANCE_NONE,
- INSTANCE_MESH,
- INSTANCE_MULTIMESH,
- INSTANCE_IMMEDIATE,
- INSTANCE_PARTICLES,
- INSTANCE_LIGHT,
- INSTANCE_REFLECTION_PROBE,
- INSTANCE_GI_PROBE,
- INSTANCE_LIGHTMAP_CAPTURE,
- INSTANCE_MAX,
-
- INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)
- };
-
- virtual RID instance_create2(RID p_base, RID p_scenario);
-
- virtual RID instance_create() = 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;
- virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0;
- 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_visible(RID p_instance, bool p_visible) = 0;
-
- virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) = 0;
-
- virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0;
-
- virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0;
- virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0;
-
- virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
-
- // don't use these in a game!
- virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
- virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0;
- virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0;
-
- Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const;
- Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
- Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const;
-
- enum InstanceFlags {
- INSTANCE_FLAG_USE_BAKED_LIGHT,
- INSTANCE_FLAG_USE_DYNAMIC_GI,
- INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
- INSTANCE_FLAG_MAX
- };
-
- enum ShadowCastingSetting {
- SHADOW_CASTING_SETTING_OFF,
- SHADOW_CASTING_SETTING_ON,
- SHADOW_CASTING_SETTING_DOUBLE_SIDED,
- SHADOW_CASTING_SETTING_SHADOWS_ONLY,
- };
-
- virtual void instance_geometry_set_flag(RID p_instance, InstanceFlags p_flags, bool p_enabled) = 0;
- virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) = 0;
- virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0;
-
- virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
- virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0;
-
- /* CANVAS (2D) */
-
- virtual RID canvas_create() = 0;
- virtual void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) = 0;
- virtual void canvas_set_modulate(RID p_canvas, const Color &p_color) = 0;
- virtual void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) = 0;
-
- virtual void canvas_set_disable_scale(bool p_disable) = 0;
-
- virtual RID canvas_item_create() = 0;
- virtual void canvas_item_set_parent(RID p_item, RID p_parent) = 0;
-
- virtual void canvas_item_set_visible(RID p_item, bool p_visible) = 0;
- virtual void canvas_item_set_light_mask(RID p_item, int p_mask) = 0;
-
- virtual void canvas_item_set_update_when_visible(RID p_item, bool p_update) = 0;
-
- virtual void canvas_item_set_transform(RID p_item, const Transform2D &p_transform) = 0;
- virtual void canvas_item_set_clip(RID p_item, bool p_clip) = 0;
- virtual void canvas_item_set_distance_field_mode(RID p_item, bool p_enable) = 0;
- virtual void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2()) = 0;
- virtual void canvas_item_set_modulate(RID p_item, const Color &p_color) = 0;
- virtual void canvas_item_set_self_modulate(RID p_item, const Color &p_color) = 0;
-
- virtual void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) = 0;
-
- enum NinePatchAxisMode {
- NINE_PATCH_STRETCH,
- NINE_PATCH_TILE,
- NINE_PATCH_TILE_FIT,
- };
-
- enum CanvasItemTextureFilter {
- CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item
- CANVAS_ITEM_TEXTURE_FILTER_NEAREST,
- CANVAS_ITEM_TEXTURE_FILTER_LINEAR,
- CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS,
- CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
- CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC,
- CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
- CANVAS_ITEM_TEXTURE_FILTER_MAX
- };
-
- enum CanvasItemTextureRepeat {
- CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item
- CANVAS_ITEM_TEXTURE_REPEAT_DISABLED,
- CANVAS_ITEM_TEXTURE_REPEAT_ENABLED,
- CANVAS_ITEM_TEXTURE_REPEAT_MIRROR,
- CANVAS_ITEM_TEXTURE_REPEAT_MAX,
- };
-
- //takes effect only for new draw commands
- virtual void canvas_item_set_default_texture_filter(RID p_item, CanvasItemTextureFilter p_filter) = 0;
- virtual void canvas_item_set_default_texture_repeat(RID p_item, CanvasItemTextureRepeat p_repeat) = 0;
-
- virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0;
- virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
- virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
- virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
- virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
- virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), bool p_clip_uv = false, CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID(), RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, RID p_specular_map = RID(), const Color &p_specular_color_shininess = Color(), CanvasItemTextureFilter p_texture_filter = CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, CanvasItemTextureRepeat = CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) = 0;
- virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
- virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0;
- virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0;
- virtual void canvas_item_set_z_index(RID p_item, int p_z) = 0;
- virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) = 0;
- virtual void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) = 0;
-
- virtual void canvas_item_attach_skeleton(RID p_item, RID p_skeleton) = 0;
-
- virtual void canvas_item_clear(RID p_item) = 0;
- virtual void canvas_item_set_draw_index(RID p_item, int p_index) = 0;
-
- virtual void canvas_item_set_material(RID p_item, RID p_material) = 0;
-
- virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
-
- virtual RID canvas_light_create() = 0;
- virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0;
- virtual void canvas_light_set_enabled(RID p_light, bool p_enabled) = 0;
- virtual void canvas_light_set_scale(RID p_light, float p_scale) = 0;
- virtual void canvas_light_set_transform(RID p_light, const Transform2D &p_transform) = 0;
- virtual void canvas_light_set_texture(RID p_light, RID p_texture) = 0;
- virtual void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) = 0;
- virtual void canvas_light_set_color(RID p_light, const Color &p_color) = 0;
- virtual void canvas_light_set_height(RID p_light, float p_height) = 0;
- virtual void canvas_light_set_energy(RID p_light, float p_energy) = 0;
- virtual void canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) = 0;
- virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) = 0;
- virtual void canvas_light_set_item_cull_mask(RID p_light, int p_mask) = 0;
- virtual void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) = 0;
-
- enum CanvasLightMode {
- CANVAS_LIGHT_MODE_ADD,
- CANVAS_LIGHT_MODE_SUB,
- CANVAS_LIGHT_MODE_MIX,
- CANVAS_LIGHT_MODE_MASK,
- };
-
- virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode) = 0;
-
- enum CanvasLightShadowFilter {
- CANVAS_LIGHT_FILTER_NONE,
- CANVAS_LIGHT_FILTER_PCF5,
- CANVAS_LIGHT_FILTER_PCF13,
- CANVAS_LIGHT_FILTER_MAX
- };
-
- virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) = 0;
- virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size) = 0;
- virtual void canvas_light_set_shadow_filter(RID p_light, CanvasLightShadowFilter p_filter) = 0;
- virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0;
- virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0;
-
- virtual RID canvas_light_occluder_create() = 0;
- virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) = 0;
- virtual void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) = 0;
- virtual void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) = 0;
- virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0;
- virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0;
-
- virtual RID canvas_occluder_polygon_create() = 0;
- virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) = 0;
- virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const Vector<Vector2> &p_shape) = 0;
-
- enum CanvasOccluderPolygonCullMode {
- CANVAS_OCCLUDER_POLYGON_CULL_DISABLED,
- CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE,
- CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE,
- };
- virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, CanvasOccluderPolygonCullMode p_mode) = 0;
-
- /* BLACK BARS */
-
- virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) = 0;
- virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) = 0;
-
- /* FREE */
-
- virtual void free(RID p_rid) = 0; ///< free RIDs associated with the visual server
-
- virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) = 0;
-
- /* EVENT QUEUING */
-
- virtual void draw(bool p_swap_buffers = true, double frame_step = 0.0) = 0;
- virtual void sync() = 0;
- virtual bool has_changed() const = 0;
- virtual void init() = 0;
- virtual void finish() = 0;
-
- /* STATUS INFORMATION */
-
- enum RenderInfo {
-
- INFO_OBJECTS_IN_FRAME,
- INFO_VERTICES_IN_FRAME,
- INFO_MATERIAL_CHANGES_IN_FRAME,
- INFO_SHADER_CHANGES_IN_FRAME,
- INFO_SURFACE_CHANGES_IN_FRAME,
- INFO_DRAW_CALLS_IN_FRAME,
- INFO_USAGE_VIDEO_MEM_TOTAL,
- INFO_VIDEO_MEM_USED,
- INFO_TEXTURE_MEM_USED,
- INFO_VERTEX_MEM_USED,
- };
-
- virtual int get_render_info(RenderInfo p_info) = 0;
- virtual String get_video_adapter_name() const = 0;
- virtual String get_video_adapter_vendor() const = 0;
-
- struct FrameProfileArea {
- String name;
- float gpu_msec;
- float cpu_msec;
- };
-
- virtual void set_frame_profiling_enabled(bool p_enable) = 0;
- virtual Vector<FrameProfileArea> get_frame_profile() = 0;
- virtual uint64_t get_frame_profile_frame() = 0;
-
- /* Materials for 2D on 3D */
-
- /* TESTING */
-
- virtual RID get_test_cube() = 0;
-
- virtual RID get_test_texture();
- virtual RID get_white_texture();
-
- virtual RID make_sphere_mesh(int p_lats, int p_lons, float p_radius);
-
- virtual void mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry::MeshData &p_mesh_data);
- virtual void mesh_add_surface_from_planes(RID p_mesh, const Vector<Plane> &p_planes);
-
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) = 0;
- virtual void set_default_clear_color(const Color &p_color) = 0;
-
- enum Features {
- FEATURE_SHADERS,
- FEATURE_MULTITHREADED,
- };
-
- virtual bool has_feature(Features p_feature) const = 0;
-
- virtual bool has_os_feature(const String &p_feature) const = 0;
-
- virtual void set_debug_generate_wireframes(bool p_generate) = 0;
-
- virtual void call_set_use_vsync(bool p_enable) = 0;
-
- virtual bool is_low_end() const = 0;
-
- VisualServer();
- virtual ~VisualServer();
-};
-
-// make variant understand the enums
-VARIANT_ENUM_CAST(VisualServer::TextureLayeredType);
-VARIANT_ENUM_CAST(VisualServer::CubeMapLayer);
-VARIANT_ENUM_CAST(VisualServer::ShaderMode);
-VARIANT_ENUM_CAST(VisualServer::ArrayType);
-VARIANT_ENUM_CAST(VisualServer::ArrayFormat);
-VARIANT_ENUM_CAST(VisualServer::PrimitiveType);
-VARIANT_ENUM_CAST(VisualServer::BlendShapeMode);
-VARIANT_ENUM_CAST(VisualServer::MultimeshTransformFormat);
-VARIANT_ENUM_CAST(VisualServer::LightType);
-VARIANT_ENUM_CAST(VisualServer::LightParam);
-VARIANT_ENUM_CAST(VisualServer::LightOmniShadowMode);
-VARIANT_ENUM_CAST(VisualServer::LightDirectionalShadowMode);
-VARIANT_ENUM_CAST(VisualServer::LightDirectionalShadowDepthRangeMode);
-VARIANT_ENUM_CAST(VisualServer::ReflectionProbeUpdateMode);
-VARIANT_ENUM_CAST(VisualServer::ParticlesDrawOrder);
-VARIANT_ENUM_CAST(VisualServer::ViewportUpdateMode);
-VARIANT_ENUM_CAST(VisualServer::ViewportClearMode);
-VARIANT_ENUM_CAST(VisualServer::ViewportMSAA);
-VARIANT_ENUM_CAST(VisualServer::ViewportRenderInfo);
-VARIANT_ENUM_CAST(VisualServer::ViewportDebugDraw);
-VARIANT_ENUM_CAST(VisualServer::SkyMode);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentBG);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentAmbientSource);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentReflectionSource);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentGlowBlendMode);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentToneMapper);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOQuality);
-VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOBlur);
-VARIANT_ENUM_CAST(VisualServer::DOFBlurQuality);
-VARIANT_ENUM_CAST(VisualServer::DOFBokehShape);
-VARIANT_ENUM_CAST(VisualServer::ScenarioDebugMode);
-VARIANT_ENUM_CAST(VisualServer::InstanceType);
-VARIANT_ENUM_CAST(VisualServer::InstanceFlags);
-VARIANT_ENUM_CAST(VisualServer::ShadowCastingSetting);
-VARIANT_ENUM_CAST(VisualServer::NinePatchAxisMode);
-VARIANT_ENUM_CAST(VisualServer::CanvasItemTextureFilter);
-VARIANT_ENUM_CAST(VisualServer::CanvasItemTextureRepeat);
-VARIANT_ENUM_CAST(VisualServer::CanvasLightMode);
-VARIANT_ENUM_CAST(VisualServer::CanvasLightShadowFilter);
-VARIANT_ENUM_CAST(VisualServer::CanvasOccluderPolygonCullMode);
-VARIANT_ENUM_CAST(VisualServer::RenderInfo);
-VARIANT_ENUM_CAST(VisualServer::Features);
-
-//typedef VisualServer VS; // makes it easier to use
-#define VS VisualServer
-
-#endif
diff --git a/servers/xr/SCsub b/servers/xr/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/xr/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
new file mode 100644
index 0000000000..c1233ae810
--- /dev/null
+++ b/servers/xr/xr_interface.cpp
@@ -0,0 +1,145 @@
+/*************************************************************************/
+/* xr_interface.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "xr_interface.h"
+
+void XRInterface::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name);
+ ClassDB::bind_method(D_METHOD("get_capabilities"), &XRInterface::get_capabilities);
+
+ ClassDB::bind_method(D_METHOD("is_primary"), &XRInterface::is_primary);
+ ClassDB::bind_method(D_METHOD("set_is_primary", "enable"), &XRInterface::set_is_primary);
+
+ ClassDB::bind_method(D_METHOD("is_initialized"), &XRInterface::is_initialized);
+ ClassDB::bind_method(D_METHOD("set_is_initialized", "initialized"), &XRInterface::set_is_initialized);
+ ClassDB::bind_method(D_METHOD("initialize"), &XRInterface::initialize);
+ ClassDB::bind_method(D_METHOD("uninitialize"), &XRInterface::uninitialize);
+
+ ClassDB::bind_method(D_METHOD("get_tracking_status"), &XRInterface::get_tracking_status);
+
+ ClassDB::bind_method(D_METHOD("get_render_targetsize"), &XRInterface::get_render_targetsize);
+ ClassDB::bind_method(D_METHOD("is_stereo"), &XRInterface::is_stereo);
+
+ ADD_GROUP("Interface", "interface_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_is_primary", "is_primary");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_initialized"), "set_is_initialized", "is_initialized");
+
+ // we don't have any properties specific to VR yet....
+
+ // but we do have properties specific to AR....
+ ClassDB::bind_method(D_METHOD("get_anchor_detection_is_enabled"), &XRInterface::get_anchor_detection_is_enabled);
+ ClassDB::bind_method(D_METHOD("set_anchor_detection_is_enabled", "enable"), &XRInterface::set_anchor_detection_is_enabled);
+ ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &XRInterface::get_camera_feed_id);
+
+ ADD_GROUP("AR", "ar_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled");
+
+ BIND_ENUM_CONSTANT(XR_NONE);
+ BIND_ENUM_CONSTANT(XR_MONO);
+ BIND_ENUM_CONSTANT(XR_STEREO);
+ BIND_ENUM_CONSTANT(XR_AR);
+ BIND_ENUM_CONSTANT(XR_EXTERNAL);
+
+ BIND_ENUM_CONSTANT(EYE_MONO);
+ BIND_ENUM_CONSTANT(EYE_LEFT);
+ BIND_ENUM_CONSTANT(EYE_RIGHT);
+
+ BIND_ENUM_CONSTANT(XR_NORMAL_TRACKING);
+ BIND_ENUM_CONSTANT(XR_EXCESSIVE_MOTION);
+ BIND_ENUM_CONSTANT(XR_INSUFFICIENT_FEATURES);
+ BIND_ENUM_CONSTANT(XR_UNKNOWN_TRACKING);
+ BIND_ENUM_CONSTANT(XR_NOT_TRACKING);
+};
+
+StringName XRInterface::get_name() const {
+ return "Unknown";
+};
+
+bool XRInterface::is_primary() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, false);
+
+ return xr_server->get_primary_interface() == this;
+};
+
+void XRInterface::set_is_primary(bool p_is_primary) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ if (p_is_primary) {
+ ERR_FAIL_COND(!is_initialized());
+
+ xr_server->set_primary_interface(this);
+ } else {
+ xr_server->clear_primary_interface_if(this);
+ };
+};
+
+void XRInterface::set_is_initialized(bool p_initialized) {
+ if (p_initialized) {
+ if (!is_initialized()) {
+ initialize();
+ };
+ } else {
+ if (is_initialized()) {
+ uninitialize();
+ };
+ };
+};
+
+XRInterface::Tracking_status XRInterface::get_tracking_status() const {
+ return tracking_state;
+};
+
+XRInterface::XRInterface() {
+ tracking_state = XR_UNKNOWN_TRACKING;
+};
+
+XRInterface::~XRInterface(){};
+
+// optional render to external texture which enhances performance on those platforms that require us to submit our end result into special textures.
+unsigned int XRInterface::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
+ return 0;
+};
+
+/** these will only be implemented on AR interfaces, so we want dummies for VR **/
+bool XRInterface::get_anchor_detection_is_enabled() const {
+ return false;
+};
+
+void XRInterface::set_anchor_detection_is_enabled(bool p_enable){
+ // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
+};
+
+int XRInterface::get_camera_feed_id() {
+ // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
+
+ return 0;
+};
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
new file mode 100644
index 0000000000..99fcef7925
--- /dev/null
+++ b/servers/xr/xr_interface.h
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* xr_interface.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 XR_INTERFACE_H
+#define XR_INTERFACE_H
+
+#include "core/math/camera_matrix.h"
+#include "core/os/thread_safe.h"
+#include "scene/main/window.h"
+#include "servers/xr_server.h"
+
+/**
+ @author Bastiaan Olij <mux213@gmail.com>
+
+ The XR interface is a template class ontop of which we build interface to different AR, VR and tracking SDKs.
+ The idea is that we subclass this class, implement the logic, and then instantiate a singleton of each interface
+ when Godot starts. These instances do not initialize themselves but register themselves with the AR/VR server.
+
+ If the user wants to enable AR/VR the choose the interface they want to use and initialize it.
+
+ Note that we may make this into a fully instantiable class for GDNative support.
+*/
+
+class XRInterface : public Reference {
+ GDCLASS(XRInterface, Reference);
+
+public:
+ enum Capabilities { /* purely meta data, provides some info about what this interface supports */
+ XR_NONE = 0, /* no capabilities */
+ XR_MONO = 1, /* can be used with mono output */
+ XR_STEREO = 2, /* can be used with stereo output */
+ XR_AR = 4, /* offers a camera feed for AR */
+ XR_EXTERNAL = 8 /* renders to external device */
+ };
+
+ enum Eyes {
+ EYE_MONO, /* my son says we should call this EYE_CYCLOPS */
+ EYE_LEFT,
+ EYE_RIGHT
+ };
+
+ enum Tracking_status { /* tracking status currently based on AR but we can start doing more with this for VR as well */
+ XR_NORMAL_TRACKING,
+ XR_EXCESSIVE_MOTION,
+ XR_INSUFFICIENT_FEATURES,
+ XR_UNKNOWN_TRACKING,
+ XR_NOT_TRACKING
+ };
+
+protected:
+ _THREAD_SAFE_CLASS_
+
+ Tracking_status tracking_state;
+ static void _bind_methods();
+
+public:
+ /** general interface information **/
+ virtual StringName get_name() const;
+ virtual int get_capabilities() const = 0;
+
+ bool is_primary();
+ void set_is_primary(bool p_is_primary);
+
+ virtual bool is_initialized() const = 0; /* returns true if we've initialized this interface */
+ void set_is_initialized(bool p_initialized); /* helper function, will call initialize or uninitialize */
+ virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */
+ virtual void uninitialize() = 0; /* deinitialize this interface */
+
+ Tracking_status get_tracking_status() const; /* get the status of our current tracking */
+
+ /** specific to VR **/
+ // nothing yet
+
+ /** specific to AR **/
+ virtual bool get_anchor_detection_is_enabled() const;
+ virtual void set_anchor_detection_is_enabled(bool p_enable);
+ virtual int get_camera_feed_id();
+
+ /** rendering and internal **/
+
+ virtual Size2 get_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */
+ virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */
+ virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */
+ virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */
+ virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye); /* if applicable return external texture to render to */
+ virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */
+
+ virtual void process() = 0;
+ virtual void notification(int p_what) = 0;
+
+ XRInterface();
+ ~XRInterface();
+};
+
+VARIANT_ENUM_CAST(XRInterface::Capabilities);
+VARIANT_ENUM_CAST(XRInterface::Eyes);
+VARIANT_ENUM_CAST(XRInterface::Tracking_status);
+
+#endif
diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp
new file mode 100644
index 0000000000..808b0a608f
--- /dev/null
+++ b/servers/xr/xr_positional_tracker.cpp
@@ -0,0 +1,237 @@
+/*************************************************************************/
+/* xr_positional_tracker.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "xr_positional_tracker.h"
+#include "core/input/input_filter.h"
+
+void XRPositionalTracker::_bind_methods() {
+ BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN);
+ BIND_ENUM_CONSTANT(TRACKER_LEFT_HAND);
+ BIND_ENUM_CONSTANT(TRACKER_RIGHT_HAND);
+
+ // this class is read only from GDScript, so we only have access to getters..
+ ClassDB::bind_method(D_METHOD("get_type"), &XRPositionalTracker::get_type);
+ ClassDB::bind_method(D_METHOD("get_tracker_id"), &XRPositionalTracker::get_tracker_id);
+ ClassDB::bind_method(D_METHOD("get_name"), &XRPositionalTracker::get_name);
+ ClassDB::bind_method(D_METHOD("get_joy_id"), &XRPositionalTracker::get_joy_id);
+ ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &XRPositionalTracker::get_tracks_orientation);
+ ClassDB::bind_method(D_METHOD("get_orientation"), &XRPositionalTracker::get_orientation);
+ ClassDB::bind_method(D_METHOD("get_tracks_position"), &XRPositionalTracker::get_tracks_position);
+ ClassDB::bind_method(D_METHOD("get_position"), &XRPositionalTracker::get_position);
+ ClassDB::bind_method(D_METHOD("get_hand"), &XRPositionalTracker::get_hand);
+ ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &XRPositionalTracker::get_transform);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &XRPositionalTracker::get_mesh);
+
+ // these functions we don't want to expose to normal users but do need to be callable from GDNative
+ ClassDB::bind_method(D_METHOD("_set_type", "type"), &XRPositionalTracker::set_type);
+ ClassDB::bind_method(D_METHOD("_set_name", "name"), &XRPositionalTracker::set_name);
+ ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &XRPositionalTracker::set_joy_id);
+ ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &XRPositionalTracker::set_orientation);
+ ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &XRPositionalTracker::set_rw_position);
+ ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &XRPositionalTracker::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_rumble"), &XRPositionalTracker::get_rumble);
+ ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRPositionalTracker::set_rumble);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble");
+};
+
+void XRPositionalTracker::set_type(XRServer::TrackerType p_type) {
+ if (type != p_type) {
+ type = p_type;
+ hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ // get a tracker id for our type
+ // note if this is a controller this will be 3 or higher but we may change it later.
+ tracker_id = xr_server->get_free_tracker_id_for_type(p_type);
+ };
+};
+
+XRServer::TrackerType XRPositionalTracker::get_type() const {
+ return type;
+};
+
+void XRPositionalTracker::set_name(const String &p_name) {
+ name = p_name;
+};
+
+StringName XRPositionalTracker::get_name() const {
+ return name;
+};
+
+int XRPositionalTracker::get_tracker_id() const {
+ return tracker_id;
+};
+
+void XRPositionalTracker::set_joy_id(int p_joy_id) {
+ joy_id = p_joy_id;
+};
+
+int XRPositionalTracker::get_joy_id() const {
+ return joy_id;
+};
+
+bool XRPositionalTracker::get_tracks_orientation() const {
+ return tracks_orientation;
+};
+
+void XRPositionalTracker::set_orientation(const Basis &p_orientation) {
+ _THREAD_SAFE_METHOD_
+
+ tracks_orientation = true; // obviously we have this
+ orientation = p_orientation;
+};
+
+Basis XRPositionalTracker::get_orientation() const {
+ _THREAD_SAFE_METHOD_
+
+ return orientation;
+};
+
+bool XRPositionalTracker::get_tracks_position() const {
+ return tracks_position;
+};
+
+void XRPositionalTracker::set_position(const Vector3 &p_position) {
+ _THREAD_SAFE_METHOD_
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+ real_t world_scale = xr_server->get_world_scale();
+ ERR_FAIL_COND(world_scale == 0);
+
+ tracks_position = true; // obviously we have this
+ rw_position = p_position / world_scale;
+};
+
+Vector3 XRPositionalTracker::get_position() const {
+ _THREAD_SAFE_METHOD_
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, rw_position);
+ real_t world_scale = xr_server->get_world_scale();
+
+ return rw_position * world_scale;
+};
+
+void XRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) {
+ _THREAD_SAFE_METHOD_
+
+ tracks_position = true; // obviously we have this
+ rw_position = p_rw_position;
+};
+
+Vector3 XRPositionalTracker::get_rw_position() const {
+ _THREAD_SAFE_METHOD_
+
+ return rw_position;
+};
+
+void XRPositionalTracker::set_mesh(const Ref<Mesh> &p_mesh) {
+ _THREAD_SAFE_METHOD_
+
+ mesh = p_mesh;
+};
+
+Ref<Mesh> XRPositionalTracker::get_mesh() const {
+ _THREAD_SAFE_METHOD_
+
+ return mesh;
+};
+
+XRPositionalTracker::TrackerHand XRPositionalTracker::get_hand() const {
+ return hand;
+};
+
+void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ if (hand != p_hand) {
+ // we can only set this if we've previously set this to be a controller!!
+ ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN));
+
+ hand = p_hand;
+ if (hand == XRPositionalTracker::TRACKER_LEFT_HAND) {
+ if (!xr_server->is_tracker_id_in_use_for_type(type, 1)) {
+ tracker_id = 1;
+ };
+ } else if (hand == XRPositionalTracker::TRACKER_RIGHT_HAND) {
+ if (!xr_server->is_tracker_id_in_use_for_type(type, 2)) {
+ tracker_id = 2;
+ };
+ };
+ };
+};
+
+Transform XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
+ Transform new_transform;
+
+ new_transform.basis = get_orientation();
+ new_transform.origin = get_position();
+
+ if (p_adjust_by_reference_frame) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, new_transform);
+
+ new_transform = xr_server->get_reference_frame() * new_transform;
+ };
+
+ return new_transform;
+};
+
+real_t XRPositionalTracker::get_rumble() const {
+ return rumble;
+};
+
+void XRPositionalTracker::set_rumble(real_t p_rumble) {
+ if (p_rumble > 0.0) {
+ rumble = p_rumble;
+ } else {
+ rumble = 0.0;
+ };
+};
+
+XRPositionalTracker::XRPositionalTracker() {
+ type = XRServer::TRACKER_UNKNOWN;
+ name = "Unknown";
+ joy_id = -1;
+ tracker_id = 0;
+ tracks_orientation = false;
+ tracks_position = false;
+ hand = TRACKER_HAND_UNKNOWN;
+ rumble = 0.0;
+};
+
+XRPositionalTracker::~XRPositionalTracker(){
+
+};
diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h
new file mode 100644
index 0000000000..d9d1f909e9
--- /dev/null
+++ b/servers/xr/xr_positional_tracker.h
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* xr_positional_tracker.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 XR_POSITIONAL_TRACKER_H
+#define XR_POSITIONAL_TRACKER_H
+
+#include "core/os/thread_safe.h"
+#include "scene/resources/mesh.h"
+#include "servers/xr_server.h"
+
+/**
+ @author Bastiaan Olij <mux213@gmail.com>
+
+ The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset.
+ An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation.
+ 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);
+ _THREAD_SAFE_CLASS_
+
+public:
+ enum TrackerHand {
+ TRACKER_HAND_UNKNOWN, /* unknown or not applicable */
+ TRACKER_LEFT_HAND, /* controller is the left hand controller */
+ TRACKER_RIGHT_HAND /* controller is the right hand controller */
+ };
+
+private:
+ XRServer::TrackerType type; // type of tracker
+ StringName name; // (unique) name of the tracker
+ int tracker_id; // tracker index id that is unique per type
+ int joy_id; // if we also have a related joystick entity, the id of the joystick
+ bool tracks_orientation; // do we track orientation?
+ Basis orientation; // our orientation
+ bool tracks_position; // do we track position?
+ Vector3 rw_position; // our position "in the real world, so without world_scale applied"
+ Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker
+ TrackerHand hand; // if known, the hand this tracker is held in
+ real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, xr_interface is responsible for execution
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_type(XRServer::TrackerType p_type);
+ XRServer::TrackerType get_type() const;
+ void set_name(const String &p_name);
+ StringName get_name() const;
+ int get_tracker_id() const;
+ void set_joy_id(int p_joy_id);
+ int get_joy_id() const;
+ bool get_tracks_orientation() const;
+ void set_orientation(const Basis &p_orientation);
+ Basis get_orientation() const;
+ bool get_tracks_position() const;
+ void set_position(const Vector3 &p_position); // set position with world_scale applied
+ Vector3 get_position() const; // get position with world_scale applied
+ void set_rw_position(const Vector3 &p_rw_position);
+ Vector3 get_rw_position() const;
+ XRPositionalTracker::TrackerHand get_hand() const;
+ void set_hand(const XRPositionalTracker::TrackerHand p_hand);
+ real_t get_rumble() const;
+ void set_rumble(real_t p_rumble);
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ Transform get_transform(bool p_adjust_by_reference_frame) const;
+
+ XRPositionalTracker();
+ ~XRPositionalTracker();
+};
+
+VARIANT_ENUM_CAST(XRPositionalTracker::TrackerHand);
+
+#endif
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
new file mode 100644
index 0000000000..a93b99025f
--- /dev/null
+++ b/servers/xr_server.cpp
@@ -0,0 +1,386 @@
+/*************************************************************************/
+/* xr_server.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "xr_server.h"
+#include "core/project_settings.h"
+#include "xr/xr_interface.h"
+#include "xr/xr_positional_tracker.h"
+
+XRServer *XRServer::singleton = nullptr;
+
+XRServer *XRServer::get_singleton() {
+ return singleton;
+};
+
+void XRServer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_world_scale"), &XRServer::get_world_scale);
+ ClassDB::bind_method(D_METHOD("set_world_scale"), &XRServer::set_world_scale);
+ ClassDB::bind_method(D_METHOD("get_reference_frame"), &XRServer::get_reference_frame);
+ ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &XRServer::center_on_hmd);
+ ClassDB::bind_method(D_METHOD("get_hmd_transform"), &XRServer::get_hmd_transform);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
+
+ ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count);
+ 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("get_primary_interface"), &XRServer::get_primary_interface);
+ ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "primary_interface"), "set_primary_interface", "get_primary_interface");
+
+ ClassDB::bind_method(D_METHOD("get_last_process_usec"), &XRServer::get_last_process_usec);
+ ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &XRServer::get_last_commit_usec);
+ ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &XRServer::get_last_frame_usec);
+
+ BIND_ENUM_CONSTANT(TRACKER_CONTROLLER);
+ BIND_ENUM_CONSTANT(TRACKER_BASESTATION);
+ BIND_ENUM_CONSTANT(TRACKER_ANCHOR);
+ BIND_ENUM_CONSTANT(TRACKER_ANY_KNOWN);
+ BIND_ENUM_CONSTANT(TRACKER_UNKNOWN);
+ BIND_ENUM_CONSTANT(TRACKER_ANY);
+
+ BIND_ENUM_CONSTANT(RESET_FULL_ROTATION);
+ BIND_ENUM_CONSTANT(RESET_BUT_KEEP_TILT);
+ BIND_ENUM_CONSTANT(DONT_RESET_ROTATION);
+
+ ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name")));
+ ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name")));
+
+ ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id")));
+};
+
+real_t XRServer::get_world_scale() const {
+ return world_scale;
+};
+
+void XRServer::set_world_scale(real_t p_world_scale) {
+ if (p_world_scale < 0.01) {
+ p_world_scale = 0.01;
+ } else if (p_world_scale > 1000.0) {
+ p_world_scale = 1000.0;
+ }
+
+ world_scale = p_world_scale;
+};
+
+Transform XRServer::get_world_origin() const {
+ return world_origin;
+};
+
+void XRServer::set_world_origin(const Transform &p_world_origin) {
+ world_origin = p_world_origin;
+};
+
+Transform XRServer::get_reference_frame() const {
+ return reference_frame;
+};
+
+void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
+ if (primary_interface != nullptr) {
+ // clear our current reference frame or we'll end up double adjusting it
+ reference_frame = Transform();
+
+ // requesting our EYE_MONO transform should return our current HMD position
+ Transform new_reference_frame = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform());
+
+ // remove our tilt
+ if (p_rotation_mode == 1) {
+ // take the Y out of our Z
+ new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized());
+
+ // Y is straight up
+ new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0));
+
+ // and X is our cross reference
+ new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized());
+ } else if (p_rotation_mode == 2) {
+ // remove our rotation, we're only interesting in centering on position
+ new_reference_frame.basis = Basis();
+ };
+
+ // don't negate our height
+ if (p_keep_height) {
+ new_reference_frame.origin.y = 0.0;
+ };
+
+ reference_frame = new_reference_frame.inverse();
+ };
+};
+
+Transform XRServer::get_hmd_transform() {
+ Transform hmd_transform;
+ if (primary_interface != nullptr) {
+ hmd_transform = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, hmd_transform);
+ };
+ return hmd_transform;
+};
+
+void XRServer::add_interface(const Ref<XRInterface> &p_interface) {
+ ERR_FAIL_COND(p_interface.is_null());
+
+ for (int i = 0; i < interfaces.size(); i++) {
+
+ if (interfaces[i] == p_interface) {
+ ERR_PRINT("Interface was already added");
+ return;
+ };
+ };
+
+ interfaces.push_back(p_interface);
+ emit_signal("interface_added", p_interface->get_name());
+};
+
+void XRServer::remove_interface(const Ref<XRInterface> &p_interface) {
+ ERR_FAIL_COND(p_interface.is_null());
+
+ int idx = -1;
+ for (int i = 0; i < interfaces.size(); i++) {
+
+ if (interfaces[i] == p_interface) {
+
+ idx = i;
+ break;
+ };
+ };
+
+ ERR_FAIL_COND(idx == -1);
+
+ print_verbose("XR: Removed interface" + p_interface->get_name());
+
+ emit_signal("interface_removed", p_interface->get_name());
+ interfaces.remove(idx);
+};
+
+int XRServer::get_interface_count() const {
+ return interfaces.size();
+};
+
+Ref<XRInterface> XRServer::get_interface(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr);
+
+ return interfaces[p_index];
+};
+
+Ref<XRInterface> XRServer::find_interface(const String &p_name) const {
+ int idx = -1;
+ for (int i = 0; i < interfaces.size(); i++) {
+
+ if (interfaces[i]->get_name() == p_name) {
+
+ idx = i;
+ break;
+ };
+ };
+
+ ERR_FAIL_COND_V(idx == -1, nullptr);
+
+ return interfaces[idx];
+};
+
+Array XRServer::get_interfaces() const {
+ Array ret;
+
+ for (int i = 0; i < interfaces.size(); i++) {
+ Dictionary iface_info;
+
+ iface_info["id"] = i;
+ iface_info["name"] = interfaces[i]->get_name();
+
+ ret.push_back(iface_info);
+ };
+
+ return ret;
+};
+
+/*
+ A little extra info on the tracker ids, these are unique per tracker type so we get some consistency in recognising our trackers, specifically controllers.
+
+ The first controller that is turned of will get ID 1, the second will get ID 2, etc.
+ The magic happens when one of the controllers is turned off, say controller 1 turns off, controller 2 will remain controller 2, controller 3 will remain controller 3.
+ If controller number 1 is turned on again it again gets ID 1 unless another new controller was turned on since.
+
+ The most likely scenario however is a controller that runs out of battery and another controller being used to replace it.
+ Because the controllers are often linked to physical objects, say you're holding a shield in controller 1, your left hand, and a gun in controller 2, your right hand, and controller 1 dies:
+ - using our tracker index would suddenly make the gun disappear and the shield jump into your right hand because controller 2 becomes controller 1.
+ - using this approach the shield disappears or is no longer tracked, but the gun stays firmly in your right hand because that is still controller 2, further more, if controller 1 is replaced the shield will return.
+*/
+
+bool XRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const {
+ for (int i = 0; i < trackers.size(); i++) {
+ if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) {
+ return true;
+ };
+ };
+
+ // all good
+ return false;
+};
+
+int XRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) {
+ // We start checking at 1, 0 means that it's not a controller..
+ // Note that for controller we reserve:
+ // - 1 for the left hand controller and
+ // - 2 for the right hand controller
+ // so we start at 3 :)
+ int tracker_id = p_tracker_type == XRServer::TRACKER_CONTROLLER ? 3 : 1;
+
+ while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) {
+ // try the next one
+ tracker_id++;
+ };
+
+ return tracker_id;
+};
+
+void XRServer::add_tracker(XRPositionalTracker *p_tracker) {
+ ERR_FAIL_NULL(p_tracker);
+
+ trackers.push_back(p_tracker);
+ emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id());
+};
+
+void XRServer::remove_tracker(XRPositionalTracker *p_tracker) {
+ ERR_FAIL_NULL(p_tracker);
+
+ int idx = -1;
+ for (int i = 0; i < trackers.size(); i++) {
+
+ if (trackers[i] == p_tracker) {
+
+ idx = i;
+ break;
+ };
+ };
+
+ ERR_FAIL_COND(idx == -1);
+
+ emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id());
+ trackers.remove(idx);
+};
+
+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);
+
+ 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);
+
+ for (int i = 0; i < trackers.size(); i++) {
+ if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) {
+ return trackers[i];
+ };
+ };
+
+ return nullptr;
+};
+
+Ref<XRInterface> XRServer::get_primary_interface() const {
+ return primary_interface;
+};
+
+void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) {
+ primary_interface = p_primary_interface;
+
+ print_verbose("XR: Primary interface set to: " + primary_interface->get_name());
+};
+
+void XRServer::clear_primary_interface_if(const Ref<XRInterface> &p_primary_interface) {
+ if (primary_interface == p_primary_interface) {
+ print_verbose("XR: Clearing primary interface");
+ primary_interface.unref();
+ };
+};
+
+uint64_t XRServer::get_last_process_usec() {
+ return last_process_usec;
+};
+
+uint64_t XRServer::get_last_commit_usec() {
+ return last_commit_usec;
+};
+
+uint64_t XRServer::get_last_frame_usec() {
+ return last_frame_usec;
+};
+
+void XRServer::_process() {
+ /* called from rendering_server_viewport.draw_viewports right before we start drawing our viewports */
+
+ /* mark for our frame timing */
+ last_process_usec = OS::get_singleton()->get_ticks_usec();
+
+ /* process all active interfaces */
+ for (int i = 0; i < interfaces.size(); i++) {
+ if (!interfaces[i].is_valid()) {
+ // ignore, not a valid reference
+ } else if (interfaces[i]->is_initialized()) {
+ interfaces.write[i]->process();
+ };
+ };
+};
+
+void XRServer::_mark_commit() {
+ /* time this */
+ last_commit_usec = OS::get_singleton()->get_ticks_usec();
+
+ /* now store our difference as we may overwrite last_process_usec before this is accessed */
+ last_frame_usec = last_commit_usec - last_process_usec;
+};
+
+XRServer::XRServer() {
+ singleton = this;
+ world_scale = 1.0;
+};
+
+XRServer::~XRServer() {
+ primary_interface.unref();
+
+ while (interfaces.size() > 0) {
+ interfaces.remove(0);
+ }
+
+ while (trackers.size() > 0) {
+ trackers.remove(0);
+ }
+
+ singleton = nullptr;
+};
diff --git a/servers/xr_server.h b/servers/xr_server.h
new file mode 100644
index 0000000000..e04c7b3592
--- /dev/null
+++ b/servers/xr_server.h
@@ -0,0 +1,192 @@
+/*************************************************************************/
+/* xr_server.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 XR_SERVER_H
+#define XR_SERVER_H
+
+#include "core/os/os.h"
+#include "core/os/thread_safe.h"
+#include "core/reference.h"
+#include "core/rid.h"
+#include "core/variant.h"
+
+class XRInterface;
+class XRPositionalTracker;
+
+/**
+ @author Bastiaan Olij <mux213@gmail.com>
+
+ The XR server is a singleton object that gives access to the various
+ objects and SDKs that are available on the system.
+ Because there can be multiple SDKs active this is exposed as an array
+ and our XR server object acts as a pass through
+ Also each positioning tracker is accessible from here.
+
+ I've added some additional info into this header file that should move
+ into the documentation, I will do so when we're close to accepting this PR
+ or as a separate PR once this has been merged into the master branch.
+**/
+
+class XRServer : public Object {
+ GDCLASS(XRServer, Object);
+ _THREAD_SAFE_CLASS_
+
+public:
+ enum TrackerType {
+ TRACKER_CONTROLLER = 0x01, /* tracks a controller */
+ TRACKER_BASESTATION = 0x02, /* tracks location of a base station */
+ TRACKER_ANCHOR = 0x04, /* tracks an anchor point, used in AR to track a real live location */
+ TRACKER_UNKNOWN = 0x80, /* unknown tracker */
+
+ TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */
+ TRACKER_ANY = 0xff /* used by get_connected_trackers to return all types */
+ };
+
+ enum RotationMode {
+ RESET_FULL_ROTATION = 0, /* we reset the full rotation, regardless of how the HMD is oriented, we're looking dead ahead */
+ RESET_BUT_KEEP_TILT = 1, /* reset rotation but keep tilt. */
+ DONT_RESET_ROTATION = 2, /* don't reset the rotation, we will only center on position */
+ };
+
+private:
+ Vector<Ref<XRInterface>> interfaces;
+ Vector<XRPositionalTracker *> trackers;
+
+ Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */
+
+ real_t world_scale; /* scale by which we multiply our tracker positions */
+ Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */
+ Transform reference_frame; /* our reference frame */
+
+ uint64_t last_process_usec; /* for frame timing, usec when we did our processing */
+ uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */
+ uint64_t last_frame_usec; /* time it took between process and committing, we should probably average this over the last x frames */
+
+protected:
+ static XRServer *singleton;
+
+ static void _bind_methods();
+
+public:
+ static XRServer *get_singleton();
+
+ /*
+ World scale allows you to specify a scale factor that is applied to all positioning vectors in our VR world in essence scaling up, or scaling down the world.
+ For stereoscopic rendering specifically this is very important to give an accurate sense of scale.
+ Add controllers into the mix and an accurate mapping of real world movement to perceived virtual movement becomes very important.
+
+ Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode.
+ This scale basically effects the unit size relationship to real world size.
+
+ I may remove access to this property in GDScript in favour of exposing it on the XROrigin3D node
+ */
+ real_t get_world_scale() const;
+ void set_world_scale(real_t p_world_scale);
+
+ /*
+ The world maps the 0,0,0 coordinate of our real world coordinate system for our tracking volume to a location in our
+ virtual world. It is this origin point that should be moved when the player is moved through the world by controller
+ actions be it straffing, teleporting, etc. Movement of the player by moving through the physical space is always tracked
+ in relation to this point.
+
+ Note that the XROrigin3D spatial node in your scene automatically updates this property and it should be used instead of
+ direct access to this property and it therefore is not available in GDScript
+
+ Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world
+ and in the virtual world out of sync
+ */
+ Transform get_world_origin() const;
+ void set_world_origin(const Transform &p_world_origin);
+
+ /*
+ center_on_hmd calculates a new reference frame. This ensures the HMD is positioned to 0,0,0 facing 0,0,-1 (need to verify this direction)
+ in the virtual world.
+
+ You can ignore the tilt of the device ensuring you're looking straight forward even if the player is looking down or sideways.
+ You can chose to keep the height the tracking provides which is important for room scale capable tracking.
+
+ Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world
+ and in the virtual world out of sync
+ */
+ Transform get_reference_frame() const;
+ void center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height);
+
+ /*
+ get_hmd_transform gets our hmd transform (centered between eyes) with most up to date tracking, relative to the origin
+ */
+ Transform get_hmd_transform();
+
+ /*
+ Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc.
+ */
+ void add_interface(const Ref<XRInterface> &p_interface);
+ void remove_interface(const Ref<XRInterface> &p_interface);
+ int get_interface_count() const;
+ Ref<XRInterface> get_interface(int p_index) const;
+ Ref<XRInterface> find_interface(const String &p_name) const;
+ Array get_interfaces() const;
+
+ /*
+ note, more then one interface can technically be active, especially on mobile, but only one interface is used for
+ rendering. This interface identifies itself by calling set_primary_interface when it is initialized
+ */
+ Ref<XRInterface> get_primary_interface() const;
+ void set_primary_interface(const Ref<XRInterface> &p_primary_interface);
+ void clear_primary_interface_if(const Ref<XRInterface> &p_primary_interface); /* this is automatically called if an interface destructs */
+
+ /*
+ Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc.
+ They are created and managed by our active AR/VR interfaces.
+ */
+ 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);
+ 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;
+
+ uint64_t get_last_process_usec();
+ uint64_t get_last_commit_usec();
+ uint64_t get_last_frame_usec();
+
+ void _process();
+ void _mark_commit();
+
+ XRServer();
+ ~XRServer();
+};
+
+#define XR XRServer
+
+VARIANT_ENUM_CAST(XRServer::TrackerType);
+VARIANT_ENUM_CAST(XRServer::RotationMode);
+
+#endif
diff --git a/thirdparty/README.md b/thirdparty/README.md
index b52b68fe47..95a6902089 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -360,6 +360,10 @@ Collection of single-file libraries used in Godot components.
* Upstream: https://sourceforge.net/projects/polyclipping
* Version: 6.4.2 + Godot changes (added optional exceptions handling)
* License: BSL-1.0
+- `cubemap_coeffs.h`
+ * Upstream: https://research.activision.com/publications/archives/fast-filtering-of-reflection-probes
+ File coeffs_const_8.txt
+ * License: MIT
- `fastlz.{c,h}`
* Upstream: https://github.com/ariya/FastLZ
* Version: git (f121734, 2007)
@@ -570,6 +574,8 @@ Files extracted from upstream source:
`vk_enum_string_helper.h` is taken from the matching `Vulkan-ValidationLayers`
SDK release: https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/master/layers/generated/vk_enum_string_helper.h
+Includes custom change to disable MSVC pragma, might be upstreamed via:
+https://github.com/KhronosGroup/Vulkan-ValidationLayers/pull/1666
`vk_mem_alloc.h` is taken from https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
Version: 2.3.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/etc2comp/patches/fix-rgba8-max-channels.patch b/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
new file mode 100644
index 0000000000..ea9b5640b6
--- /dev/null
+++ b/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
@@ -0,0 +1,224 @@
+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/misc/cubemap_coeffs.h b/thirdparty/misc/cubemap_coeffs.h
new file mode 100644
index 0000000000..1db03ce7c4
--- /dev/null
+++ b/thirdparty/misc/cubemap_coeffs.h
@@ -0,0 +1,28 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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 CUBEMAP_COEFFS_H
+#define CUBEMAP_COEFFS_H
+
+const float low_quality_coeffs[7][5][6][4] = { { { { 0.0002037563, 0.0045063655, -0.0016408688, 0.00012037493 }, { -9.1834951e-05, -0.008947532, -8.1524405e-05, -3.9080094e-05 }, { -2.6038267e-05, -6.8409667e-05, 7.2175702e-05, 0.25492775 }, { -9.9426044e-05, 0.0025427756, -0.00074437925, 1.1773191e-05 }, { -3.2668211e-05, 0.0026930659, -4.824934e-05, -0.0006835048 }, { -0.0002864144, -0.0032220854, 0.0021558286, -0.00014573736 } }, { { 0.00030683201, 0.0026819548, -0.00060011756, -0.0067169226 }, { -0.0030993251, 0.0098575575, 0.0022416671, -8.9075401e-05 }, { 0.00052405626, 0.00057860515, 0.00011654518, -0.048018609 }, { 0.00010850967, -0.0088443512, -0.0018168095, 8.6633128e-05 }, { 0.003333989, -0.0050956447, -8.0414612e-05, 0.0049721239 }, { -4.0961436e-05, -8.5486984e-05, 0.0058683066, 2.2978359e-05 } }, { { 0.99999993, 0.99998625, 0.99999847, 0.99997743 }, { 0.99999519, 0.99991138, 0.99999748, 1 }, { 0.99999986, 0.99999983, 0.99999999, 0.96576708 }, { 0.99999999, 0.99995765, 0.99999807, 1 }, { 0.99999444, 0.99998339, 1, 0.99998741 }, { 0.99999996, 0.99999481, 0.99998046, 0.99999999 } }, { { -0.32267524, -0.65409377, -1.4666488, 0.87153305 }, { -1.264365, 0.89880861, -1.2245906, -0.88501403 }, { -0.31118682, -0.086150323, -0.58811532, 1.1317711 }, { -1.2193493, 1.250379, -1.0871569, -0.12694096 }, { -0.4012249, -0.47436307, -0.59661001, 2.7313005 }, { -1.3109856, 0.60929855, 0.55672643, -0.39880018 } }, { { 0.93273157, 0.59530745, 1.1994788, 0.19102276 }, { 1.2272239, 0.23245736, 1.2577607, 2.5491008 }, { 1.1210098, 0.83074953, 1.3049282, -0.001940633 }, { 1.5839111, 0.10520816, 1.150458, 2.3251789 }, { 0.688692, 0.59807498, 1.3374877, 0.095746692 }, { 1.3054173, 0.36604721, 0.065870226, 1.6496907 } } }, { { { 0.10348445, -4.6771514e-07, -0.011513131, 8.8921052e-05 }, { -0.042152043, 0.013143535, 0.00029120107, 0.036661611 }, { -0.04516036, 0.011438473, -0.0099289792, -0.011707897 }, { -0.034779497, 0.0090981166, -5.4202726e-05, 0.038592793 }, { -0.0071967376, -0.0056614418, -0.012278945, 0.0056867462 }, { -0.037678514, 0.011570177, 0.00029044557, 0.038583909 } }, { { 0.048320869, 1.4603673e-05, 0.0092672368, 0.00033289199 }, { 0.0071001761, -0.0090106091, -0.0027305905, -0.00221479 }, { -0.0027204116, 0.00017921587, 0.015296357, -0.00010306185 }, { 0.0079350203, -0.014772431, -1.2410913e-05, -0.0062296897 }, { 0.025087691, 0.00086046427, 0.015034685, -0.00078224706 }, { 0.00074587265, -0.014602074, 0.00027338224, -0.012848552 } }, { { 0.99345662, 1, 0.99989078, 0.99999994 }, { 0.99908598, 0.99987302, 0.99999623, 0.99932528 }, { 0.99897605, 0.99993456, 0.9998337, 0.99993145 }, { 0.99936351, 0.99984949, 1, 0.9992356 }, { 0.99965935, 0.9999836, 0.99981158, 0.99998352 }, { 0.99928963, 0.99982644, 0.99999992, 0.99917276 } }, { { 3.6882765, 0.15963861, 0.55983965, 0.4075649 }, { 2.1169304, 0.56463157, 0.52957047, 2.0117964 }, { 3.1080461, 0.09682931, 0.42125986, 0.089254784 }, { 1.4247315, 0.48411378, -0.17039102, 1.7431674 }, { 4.0339531, 0.14046159, 0.89848909, 0.011661811 }, { 1.9787852, 0.61750145, 0.63514194, 1.9359003 } }, { { 0.030848793, 1.4472743, 1.4356825, 1.4078009 }, { 0.37639678, 1.0793106, 1.1945413, 0.43983395 }, { 0.27451605, 1.5256415, 1.016769, 1.4850575 }, { 0.54580883, 1.1332879, 3.1331784, 0.60772955 }, { 0.11785158, 1.3928946, 0.94998805, 1.0377182 }, { 0.2842108, 1.0026911, 1.9064553, 0.27147854 } } }, { { { -0.096789259, 0.10326967, 0.0011799959, -0.03077328 }, { 0.08342021, 0.033260738, -0.00045864451, -0.021450568 }, { -0.093369441, -0.05807574, -0.033745214, 0.023817208 }, { 0.056747754, 0.031140512, 0.00019362509, -0.023727797 }, { -0.084538386, -0.040545412, -0.0076838784, 0.03424599 }, { 0.074312056, 0.027619787, 0.0015509082, -0.031043528 } }, { { -0.0085160473, -0.012179292, 0.0049910118, 0.020224799 }, { 0.022559343, -0.016273333, -0.0069382139, 0.00058083224 }, { -0.001115062, 0.035002846, -0.0038974773, -0.039378629 }, { 0.0014921617, -0.00058523872, -0.0011606685, 0.02807528 }, { -0.021454809, 0.052957852, -0.0022083677, -0.027956663 }, { -0.016486487, -0.0040233682, 0.00029949558, 0.021924605 } }, { { 0.99526846, 0.99457883, 0.99998685, 0.99932175 }, { 0.99625908, 0.99931422, 0.99997583, 0.99976974 }, { 0.99563091, 0.99769836, 0.99942287, 0.99894047 }, { 0.99838743, 0.99951485, 0.99999931, 0.99932416 }, { 0.99618922, 0.99777329, 0.99996804, 0.99902234 }, { 0.99709875, 0.9996104, 0.99999875, 0.99927754 } }, { { 3.0342011, 4.8022834, 1.3814123, 1.5280754 }, { 2.9043837, 1.7325954, 1.422223, 2.0569263 }, { 3.0358722, 5.3331504, 1.5680146, 1.6079289 }, { 3.2062833, 1.5368069, 1.0484709, 1.5399477 }, { 2.4471653, 4.0916696, 1.5060688, 1.5807009 }, { 2.6932695, 1.5161537, 1.3991175, 1.6301918 } }, { { 0.50787578, 0.17735471, 1.4006765, 1.0878482 }, { 0.69514518, 1.6765187, 1.2224869, 1.3461327 }, { 0.71381288, 0.17509216, 1.2712934, 0.94575821 }, { 1.1817337, 1.796984, 1.8671538, 1.5708691 }, { 0.55621228, 0.38291359, 1.4128781, 0.82625349 }, { 0.72441647, 1.005794, 1.5522327, 1.6032524 } } }, { { { -0.00041301094, -0.095882618, 0.26932618, -0.25137214 }, { 0.13737415, -0.12694293, -0.0090389663, 0.07227623 }, { -0.005236407, -0.0072961249, 0.27776083, -0.19536433 }, { 0.12781899, -0.042881667, -0.095979169, 0.088937396 }, { 0.037496084, -0.090547583, 0.22112334, -0.21930294 }, { 0.13353408, -0.084346121, -0.011365728, 0.043459312 } }, { { -0.05799135, -0.048612281, 0.02422989, 0.015536268 }, { -0.083144241, 0.039381032, 0.018705957, 0.029297922 }, { 0.026364989, -0.041927591, 0.036718516, 0.0050376168 }, { -0.11562256, 0.043521976, -0.014481644, 0.01529188 }, { -0.047859898, -0.057779647, -0.053171395, -0.0063193506 }, { -0.028781196, 0.041145059, -0.00018523142, 0.053524246 } }, { { 0.998317, 0.99420489, 0.96274416, 0.96776581 }, { 0.98702349, 0.99112796, 0.99978417, 0.99695425 }, { 0.99963867, 0.99909401, 0.95994827, 0.9807178 }, { 0.98503489, 0.99813175, 0.99527799, 0.99591983 }, { 0.99815003, 0.99421459, 0.97379529, 0.97563635 }, { 0.99062621, 0.99558667, 0.99993539, 0.99762039 } }, { { 2.3221943, 2.5383575, 4.3177232, 4.2016467 }, { 3.1936529, 3.0443024, 2.548962, 2.7636456 }, { 2.5923827, 2.3497949, 4.2471014, 4.1975975 }, { 3.3748785, 3.2836577, 2.9220414, 2.7175317 }, { 2.3290083, 2.5560991, 4.3572168, 4.4372585 }, { 3.1512055, 3.2863613, 2.4475378, 2.3620003 } }, { { 0.62833231, 0.52378061, 0.55845033, 0.64883444 }, { 0.76905594, 1.1017801, 1.8714048, 1.5664383 }, { 1.5283278, 1.2423369, 0.62247385, 1.0341956 }, { 0.77484548, 1.6866409, 1.0307399, 1.4224643 }, { 0.85627405, 0.72516079, 0.70094339, 0.7547877 }, { 1.202842, 1.7650605, 1.5938526, 0.97031337 } } }, { { { -0.078108035, -0.049518839, 0.26950139, -0.51522828 }, { 0.43015518, -0.045354216, 0.094550359, -0.2395012 }, { -0.079900522, -0.082582235, 0.24464909, -0.5234896 }, { 0.38422945, -0.023833644, 0.07334288, -0.22827313 }, { -0.075370379, -0.05156594, 0.19883182, -0.45064193 }, { 0.46285395, 0.021899343, 0.10155287, -0.25974773 } }, { { 0.068681419, -0.32175988, 0.15143274, -0.0066205388 }, { -0.17060226, 0.31051319, -0.080511981, -0.1593209 }, { 0.08167251, -0.32517768, 0.10937023, -0.06941926 }, { -0.14580685, 0.32474959, -0.081718057, -0.11068378 }, { 0.053961394, -0.29322836, 0.10408839, -0.02243046 }, { -0.030598471, 0.34332821, -0.091528353, -0.16299796 } }, { { 0.99457629, 0.9455255, 0.95101899, 0.85702741 }, { 0.88648824, 0.94948647, 0.99225906, 0.95773484 }, { 0.99345131, 0.94204015, 0.96342357, 0.84919939 }, { 0.9116513, 0.94549969, 0.99395321, 0.96728511 }, { 0.99569447, 0.95465076, 0.97449039, 0.89242295 }, { 0.88590629, 0.93896015, 0.99061071, 0.95182077 } }, { { 3.6380949, 4.1749529, 4.1351439, 4.8389883 }, { 5.256362, 4.2027959, 3.6096892, 3.9848645 }, { 3.5689427, 3.8620869, 4.0023981, 4.8268584 }, { 5.1128497, 4.468934, 3.5851596, 4.047485 }, { 3.7014988, 4.1310058, 4.2446872, 5.3049323 }, { 4.8659881, 4.3133002, 3.4582876, 3.8863853 } }, { { 1.6276316, 0.7747672, 1.0485958, 0.73900224 }, { 0.72010795, 0.65403093, 1.3179681, 0.65610074 }, { 1.5881174, 0.55108527, 1.0509725, 0.72153362 }, { 1.1389053, 1.0905142, 1.6661598, 0.9987548 }, { 1.977914, 0.83001686, 1.0571479, 0.80249183 }, { 0.94107069, 0.80840873, 0.95379751, 0.50386367 } } }, { { { 0.015525428, -0.48038019, -0.021799698, 0.43629156 }, { 0.045681247, -0.55039024, -0.54573329, 0.57817853 }, { -0.045869129, -0.42209953, -0.14040829, 0.37787106 }, { 0.66327604, -0.70070311, -0.55261635, 0.63446196 }, { 0.015397585, -0.43515767, -0.021927897, 0.4203714 }, { 0.85681772, -0.65394729, -0.67557236, 0.60104142 } }, { { -0.31503888, -0.26745648, 0.26817896, 0.26548747 }, { -0.93282124, -0.033621213, 0.68374802, -0.10858524 }, { -0.21723689, -0.17935495, 0.38521982, 0.2578335 }, { -0.39913153, 0.23555359, 0.59589456, -0.19075103 }, { -0.28851798, -0.24142459, 0.28279261, 0.24766617 }, { -0.29435977, -0.25850549, 0.57790878, -0.200546 } }, { { 0.94895177, 0.83528552, 0.96312243, 0.85974768 }, { 0.35743218, 0.8342303, 0.48442112, 0.80865248 }, { 0.97504059, 0.88863029, 0.9120807, 0.88923301 }, { 0.63305523, 0.67344611, 0.58268761, 0.74904744 }, { 0.95735066, 0.86738225, 0.9589304, 0.87289711 }, { 0.42333878, 0.71100482, 0.45784651, 0.77364753 } }, { { 5.3641275, 5.2550422, 5.3103777, 5.2851215 }, { 5.2657045, 6.2095784, 6.9549598, 4.9205516 }, { 5.163385, 5.3141038, 4.9907618, 5.3583852 }, { 6.1257061, 6.1102338, 6.9549598, 5.3129951 }, { 5.3138838, 5.3257842, 5.3133783, 5.2687156 }, { 5.8915091, 6.153324, 6.9549598, 4.9568971 } }, { { 3.1221918, 1.1882615, 2.6991784, 1.1185048 }, { -0.2322432, -0.16590163, 0.088416958, 0.057399579 }, { 3.4395383, 1.5836276, 2.6242352, 1.2873336 }, { -0.23767634, -0.79425452, 0.20477899, 0.40461516 }, { 2.2521751, 1.1933374, 2.3309484, 1.0185309 }, { -0.099258385, -0.2173726, 0.0736866, 0.15470436 } } }, { { { 0.066050217, -0.33053278, -0.13771479, 0.33278465 }, { 0.00084467977, -0.50077778, -0.30083482, 0.6494273 }, { 0.24880159, -0.30354993, -0.15417892, 0.38203296 }, { -0.073325098, -0.4778777, 0.10779844, 0.66683723 }, { 0.15703809, -0.36335455, -0.15657631, 0.35926503 }, { 0.26127617, -0.29524368, -0.14490804, 0.65461301 } }, { { -0.57970022, -0.33939622, 0.72169742, 0.320959 }, { -0.38698206, -0.12730306, 0.65810895, 0.026509232 }, { -0.6199708, -0.34745658, 0.68683659, 0.34547285 }, { -0.3613378, -0.14006845, 0.65917895, 0.038446867 }, { -0.57778101, -0.35057776, 0.57837882, 0.36488991 }, { -0.50051482, -0.019174387, 0.50816239, 0.02682636 } }, { { 0.8121484, 0.88065787, 0.67837119, 0.88670158 }, { 0.92208686, 0.85616327, 0.69021085, -0.75996148 }, { 0.74413303, 0.88720424, 0.71027063, 0.85714604 }, { 0.92954743, 0.86718726, 0.74421946, -0.74421095 }, { 0.80094204, 0.86317363, 0.8006009, 0.85894353 }, { 0.82536033, 0.95522956, 0.8489833, -0.75548802 } }, { { 5.7725061, 5.1565901, 5.6224483, 5.0847054 }, { 5.7717118, 6.4180057, 6.9797014, -0.03290957 }, { 5.7847117, 5.2015529, 5.614561, 5.2019388 }, { 6.2613999, 6.5807982, 6.9797014, -0.032764603 }, { 5.823775, 5.2332343, 5.826694, 5.197143 }, { 6.3463188, 5.8174311, 6.9797014, -0.032766769 } }, { { 2.96787, 1.3557735, 2.0749129, 1.3066609 }, { -0.92782801, 0.0079162579, -0.33479446, 2.699659e-05 }, { 2.1997063, 3.1083252, 2.6810949, 1.8276262 }, { -0.48654719, -0.10954189, -0.32175132, 5.490092e-05 }, { 3.1970446, 1.787085, 3.062849, 1.6274811 }, { -0.78882801, -0.34050184, -0.59962127, 3.6554198e-05 } } } };
+
+const float high_quality_coeffs[7][5][3][24][4] = { { { { { -4.8355339e-06, -4.4902569e-05, -9.2632249e-05, -0.00053773136 }, { 0.0040143823, -0.00060900339, -0.0095301923, -0.0053956011 }, { -0.0005923892, -3.6901978e-05, -5.6694857e-06, -0.00017018564 }, { 0.0012441402, 0.02236187, 0.022751769, 0.0062788948 }, { 0.00013810055, -2.2709815e-05, 0.0054849671, -1.6599195e-05 }, { -0.020320408, -0.017066319, -0.017457746, 0.022910628 }, { 0.00024171724, 9.7419073e-05, -0.00047804272, -0.00010093683 }, { 7.6988167e-05, 1.8551597e-05, -5.7692813e-05, -3.332362e-05 }, { -0.00062766208, 2.713742e-05, 0.00026511682, 2.3841873e-05 }, { -0.00043656844, 0.0028645469, 0.0049817085, 0.0080221478 }, { -3.3210444e-05, -8.0852386e-05, -2.2111492e-06, -8.4430827e-05 }, { 0.010967284, 0.018811225, 0.017569463, -0.0046944996 }, { -0.00018391248, -0.00010462174, -0.00017726, -0.00018490133 }, { 0.00012591989, 0.015965386, 0.015964059, -0.0078018431 }, { -0.006125333, -8.2224165e-05, -0.00020500151, -0.00025207244 }, { -0.00016320041, -0.0001279242, 0.00014038799, 8.1359421e-05 }, { -0.00064341098, -0.0011265496, -0.0011634792, -0.00081607159 }, { 0.00089294825, 0.0061923653, 0.0052662392, -0.00058227469 }, { -2.4001308e-05, -1.3534224e-05, -1.4720478e-05, -2.5120827e-05 }, { 0.00029964918, -0.0045658543, -0.0045581938, 0.0017106208 }, { 7.5790173e-05, -1.8265415e-05, 1.5918205e-05, 5.8524021e-05 }, { 0.0011669872, -0.00017571882, -0.00017190275, -0.0023833977 }, { 0.0033487264, -0.0066535821, -0.0066413786, -0.0032332601 }, { -3.6468807e-05, -0.00068145131, -9.8190714e-05, -8.7169435e-05 } }, { { -0.0010440653, -8.9750644e-05, 4.971182e-05, 0.0044618878 }, { 0.0078333883, -0.00090884312, -0.00046920549, -0.002465051 }, { -0.0058778609, 0.0026554895, -0.00031880506, -0.00010649091 }, { -0.0015095448, 0.0094026506, 0.009492703, 0.0024572848 }, { 0.0047331786, 0.00070722401, 0.0028798817, -0.00039779892 }, { -0.0089878107, -0.0095474878, -0.0097187652, 0.008765907 }, { -4.0435321e-05, -0.00061813281, -0.0060490143, 0.0016259965 }, { -0.00014720558, -1.0601876e-05, 0.00014757138, 0.00016227641 }, { -0.010428289, -0.00031812813, -0.0016172213, -0.00012022134 }, { 0.0040517131, 0.0072972763, 0.0060433905, 0.0025041645 }, { 0.00014090924, 0.00027612853, 0.00015961665, 0.0002605418 }, { -0.00020653783, -0.00048482867, -0.00058472338, 0.00026413759 }, { 0.00056712638, 0.00026385353, 0.00035484947, 0.00033212447 }, { -0.00094663094, 0.0029891757, 0.0029887838, -0.0026583585 }, { -0.0017400246, 0.00042350567, 0.00086128207, 0.00039863587 }, { 0.00059604848, 0.00027495434, -0.00059956434, -4.4981673e-05 }, { -0.010211343, -0.0080580409, -0.0085333216, 0.0023258717 }, { 0.00042832593, 0.0056750222, 0.0048059635, -0.0092168281 }, { 3.0214612e-05, 4.540924e-06, 1.7239937e-05, 2.783598e-05 }, { 0.00029393335, -4.5128636e-05, -4.3089017e-05, 0.00030682556 }, { -4.7077735e-05, -1.3596835e-05, -0.0015338149, -7.4957991e-05 }, { -0.00097136844, 0.00018564298, 0.00021815754, 0.0015095577 }, { 0.00043929849, -0.0014691094, -0.0014671742, -0.00029365954 }, { 8.8554045e-05, 0.0062500772, 0.0001495049, 0.00021007601 } }, { { 0.0020307077, 0.0020947445, 0.0017438295, 0.0084822342 }, { -0.0069727503, -0.0010131005, 0.0055261321, -0.0020442588 }, { 0.00031035611, 0.00010839441, 3.7359209e-06, 4.3112837e-05 }, { 9.1207794e-05, 0.0050148169, 0.0051071455, 0.0033679057 }, { -0.00090101737, -0.00053793176, -0.0025829621, 0.0003241927 }, { -0.0019244714, -0.0033690472, -0.0035193497, 0.0027653636 }, { -0.00065476293, -0.00017787403, 0.00040383136, -0.00018123957 }, { -0.00030640434, -0.00018961553, -0.00011036218, -0.00015793049 }, { 0.001110592, -0.00021252645, 0.00015849587, -3.7758317e-05 }, { 0.00077967828, -0.0051765235, -0.0078505592, -0.010796339 }, { -1.2024951e-05, 6.48806e-05, -3.9409005e-05, 7.4639306e-05 }, { -0.00017352424, -0.00037802595, -0.00045639468, 0.00016843169 }, { -4.2866244e-05, -4.3730932e-06, 7.3574276e-05, 5.6076779e-05 }, { 0.00024802387, 0.0018053101, 0.0018042994, -0.0016700716 }, { 0.0082698262, -0.00014605077, 0.0004377682, 8.1585074e-05 }, { -4.494343e-06, 0.00019781519, -0.00058910268, -0.00027360572 }, { 0.0013016934, 0.0021020456, 0.0022718598, -0.0059377824 }, { 0.002185371, -0.0080788056, -0.0071952836, 0.0039688918 }, { 0.00013048617, 0.0001738124, 0.00012978924, 0.00013813358 }, { 0.00032386518, 0.00023046021, 0.00023064714, 0.00033762343 }, { 0.00023643771, 0.00019652953, 0.0013083597, 0.00024739959 }, { -0.0063957036, -0.0055319023, -0.0054742301, -0.0037204932 }, { -0.0005510683, -0.0007715413, -0.00077385934, -0.001009415 }, { 0.00017904616, -0.00096137522, 0.00030252599, -2.2478138e-05 } } }, { { { -0.00038948583, -0.00040817153, -0.00041280315, -0.0010985631 }, { 0.0025695337, 0.00042904308, 0.0054649973, -0.0055079106 }, { 0.00052050672, 2.2618679e-05, 0.00024058975, -0.00012632201 }, { -0.013468886, 0.0079396715, 0.0079402246, 0.026283756 }, { -7.922122e-05, -3.4761763e-06, -0.0041716347, 0.0001478739 }, { 0.023716381, -0.016415262, -0.015296927, -0.021050827 }, { 3.7654391e-05, 0.00012765816, -0.0001337099, 0.00051483398 }, { 0.00015671907, 0.00010686796, 2.1421097e-05, -2.2281569e-05 }, { 3.1779413e-06, 0.00010449913, -0.00018303614, 7.5382489e-05 }, { -0.00020526765, -0.0011333575, -0.0050720108, 0.0051482782 }, { 4.0450357e-05, 1.0808158e-05, -2.3316095e-05, 9.7767333e-06 }, { -0.019107229, 0.010907324, 0.0048969594, 0.017851514 }, { 7.4048796e-05, -7.041835e-06, 8.0226174e-05, 5.1714105e-05 }, { -0.016564627, 0.0023486944, 0.0023601429, 0.016005248 }, { -0.004528284, 3.6291049e-05, 2.4229636e-05, 0.0024853948 }, { 5.6882054e-05, 6.8805135e-05, 0.00013119897, 0.00010339801 }, { 0.00021183341, 0.0008203137, -7.204401e-05, 0.00062599728 }, { -0.00099314707, 0.0030198762, -0.0038989955, 0.00055571214 }, { -7.4247984e-05, -8.3993373e-05, -5.9133252e-05, -7.7411989e-05 }, { 0.0054296732, -0.00057858871, -0.00058417754, -0.005072911 }, { -0.00019259782, -0.00018772532, -4.2959783e-05, -0.0001827295 }, { -0.00029351865, 0.00013736372, 0.00016666048, 0.00020873447 }, { 0.0069341659, 0.0027612928, 0.0027538377, -0.0061770317 }, { 4.2584714e-05, -0.00037063589, -9.0693123e-06, 0.00011845784 } }, { { 0.0028834168, 0.0031807308, 0.0031352582, 0.01064051 }, { 0.0049297987, -4.2149356e-05, -0.0014926841, -0.0002300371 }, { 0.0020396303, -0.00066042794, -6.4359283e-05, 0.00017835163 }, { -0.0025767816, 0.0025148152, 0.0025224779, 0.0043006543 }, { -0.00042084416, -0.00013534305, 0.002453623, -4.0707749e-05 }, { -0.0001803055, -0.0010450606, -0.00084380806, 0.00014843677 }, { -0.0064067107, 0.00011012652, -0.0022552747, -0.00080508294 }, { -0.00017778763, -4.296789e-05, 0.00015343883, 0.00025036711 }, { 0.002825978, -0.00031945362, -0.00031987612, -0.00021117763 }, { 0.00032791249, -0.00049524542, 0.0049368722, -0.0017186408 }, { -0.0001685943, -0.00016766033, -0.0001755097, -0.00017067307 }, { 0.00023939157, -0.00011793706, -6.0620575e-05, -0.0002706595 }, { -2.9718673e-05, 3.5950879e-05, 1.839844e-05, -2.8718148e-05 }, { -0.0017260981, 0.00012145435, 0.0001236679, 0.0018292155 }, { 0.0036086706, 0.0001026898, -2.5518889e-05, -0.00019830236 }, { -0.00031546808, -0.00042107458, -0.00059963868, -0.00061472497 }, { -0.0074719522, 0.0015719596, -0.0033624165, -0.0092664101 }, { -0.0011285776, 0.0018601435, 0.00052060704, -1.5554679e-05 }, { 4.9853171e-05, 7.3650922e-05, 3.4080107e-05, 5.4255445e-05 }, { 0.00015102779, -2.58105e-05, -2.5851018e-05, -4.5185316e-05 }, { 0.0002057452, 0.00019037765, 0.0040052198, 0.00020046579 }, { 0.0027727314, 0.0040749211, 0.0036050794, 0.0034635222 }, { 0.00042503689, 0.00056027382, 0.00056052971, -8.2485044e-05 }, { -5.6309634e-05, 0.0019722025, 6.4267434e-05, -0.00020376412 } }, { { 0.0051607661, 0.0047835358, 0.0047658352, 0.0054281814 }, { -0.0040939561, 0.0012119183, -0.0023408179, -0.00055891234 }, { -0.0031939804, -0.0015954053, -0.00018570689, 0.00028849431 }, { -0.0075625096, 0.0033878734, 0.0033797415, 0.010242674 }, { -0.002293562, 0.00024245282, 0.0019455622, 0.0039550747 }, { 0.0090386754, -0.0086947671, -0.0082684939, -0.0075613346 }, { -0.00085735117, 3.4822634e-05, -0.0024653972, -0.00090964985 }, { -0.00013750587, -0.00010089501, 6.3555498e-05, 0.0002758494 }, { 0.0060496328, -0.00032664426, 0.0005979723, -0.00018819024 }, { 0.00072724184, 0.00082242885, 0.0045668772, -0.0054557456 }, { -9.6167811e-05, 7.9856612e-05, 0.00015672473, 8.0901183e-05 }, { 0.00038859448, -0.00025360755, -0.00017624981, -0.00049125519 }, { -8.8277361e-05, 2.4159527e-05, -0.00016014627, -2.7854246e-05 }, { -0.0037308647, 0.00041434141, 0.0004167221, 0.0037190244 }, { 0.00050696744, -4.6752715e-05, 0.00033183668, -0.0025882828 }, { -0.00015915702, -0.0002325901, -0.00036157415, -0.00016391937 }, { 0.00012320153, 0.0026711886, 0.0018414591, -0.0058215223 }, { -0.0029409983, -0.00015460743, 0.0031951665, 0.0074654329 }, { 9.9084813e-05, 9.1785865e-05, 5.9300007e-05, 0.00010463304 }, { 0.00024773341, -2.5723276e-05, -2.5709769e-05, -0.00015357475 }, { 0.000416633, 0.00028749584, -0.0038632071, 0.00039869488 }, { 0.00018344152, 3.0811778e-05, -0.00010240082, 0.00059301197 }, { 0.0019217461, 0.00034404024, 0.00034318823, -0.0015867375 }, { -0.00011928879, 0.001178769, -5.8655983e-05, -0.00028461439 } } }, { { { 0.99999992, 0.99999992, 0.99999991, 0.99999925 }, { 0.99998864, 0.99999972, 0.99993965, 0.99997027 }, { 0.99999969, 1, 0.99999997, 0.99999998 }, { 0.99990852, 0.99971841, 0.99970961, 0.9996348 }, { 0.99999999, 1, 0.99997626, 0.99999999 }, { 0.99951219, 0.9997196, 0.99973058, 0.99951587 }, { 0.99999997, 0.99999999, 0.99999988, 0.99999986 }, { 0.99999998, 0.99999999, 1, 1 }, { 0.9999998, 0.99999999, 0.99999995, 1 }, { 0.99999988, 0.99999525, 0.99997473, 0.99995457 }, { 1, 1, 1, 1 }, { 0.99975729, 0.99976356, 0.99983365, 0.99982963 }, { 0.99999998, 0.99999999, 0.99999998, 0.99999998 }, { 0.99986279, 0.99986979, 0.99986978, 0.99984147 }, { 0.99997099, 1, 0.99999998, 0.99999688 }, { 0.99999999, 0.99999999, 0.99999998, 0.99999999 }, { 0.99999977, 0.99999903, 0.99999932, 0.99999947 }, { 0.99999911, 0.99997627, 0.99997853, 0.99999968 }, { 1, 1, 1, 1 }, { 0.99998521, 0.99998941, 0.99998944, 0.99998567 }, { 0.99999998, 0.99999998, 1, 0.99999998 }, { 0.99999928, 0.99999998, 0.99999997, 0.99999714 }, { 0.99997035, 0.99997405, 0.99997415, 0.99997569 }, { 1, 0.9999997, 1, 0.99999999 } }, { { 0.00015966941, 0.00014262676, 0.00020165066, 0.00021618914 }, { 2.8140907e-06, -0.00020325872, 0.00017736728, 6.0386679e-05 }, { -0.0003187876, 5.8862288e-05, 6.2281085e-05, 1.7339908e-05 }, { -2.6587911e-05, -0.00011609007, -0.00011725093, -7.6114852e-05 }, { 0.00013665042, 5.2703844e-06, -0.00031293536, 3.8693931e-05 }, { -9.8143069e-05, -0.00012816332, -0.00012926252, -0.00010623032 }, { 0.00032342312, -1.9200091e-06, -0.00010691485, 6.3541059e-05 }, { -8.0643542e-06, 9.7622933e-06, 2.9924822e-05, -1.988333e-05 }, { 0.00025318464, 1.2588649e-05, 1.4665927e-05, 9.3294806e-06 }, { 2.6875391e-06, -2.4928123e-05, 2.251878e-05, 0.00011026808 }, { 1.767638e-05, 1.0309044e-05, 2.4765648e-05, 1.4397941e-05 }, { 6.9000935e-06, 1.0637078e-05, 1.087637e-05, 6.3065784e-06 }, { 5.532953e-05, 1.6231463e-05, 4.9564371e-05, 3.6623041e-05 }, { -1.6958729e-05, -3.1627491e-05, -3.1524511e-05, -2.9954116e-05 }, { 8.9045086e-05, 2.1005026e-05, 1.3016463e-05, 8.7863053e-05 }, { -2.75035e-05, -3.0440427e-05, -3.5356286e-05, 5.9609261e-06 }, { 0.0001586274, 4.0711165e-05, 3.1563135e-05, 0.0001385483 }, { 8.5548316e-06, 7.4531928e-05, -3.7017413e-05, 2.6874037e-05 }, { -1.3750655e-05, -8.2756032e-06, -2.7214983e-07, -1.4830115e-05 }, { -7.0798362e-07, -3.3187173e-07, -3.3266762e-07, -5.7113855e-07 }, { 4.3615512e-05, -4.4076433e-06, 8.9239586e-06, 3.7278531e-05 }, { -7.7366773e-06, 4.610399e-06, 4.3762687e-06, -5.64067e-06 }, { -3.2666125e-06, -1.0773146e-05, -1.0861965e-05, -1.3327232e-06 }, { -9.1178305e-06, 0.00030171207, -1.5395234e-05, -2.0695425e-07 } }, { { 0.00017159464, 0.00014699558, 0.00018752678, 0.0002227926 }, { -4.6524822e-05, -0.00010460271, 0.00034735325, 0.00010082238 }, { -6.8269006e-05, 1.4343751e-05, 7.7283393e-06, 2.5347136e-05 }, { -6.6149546e-05, -7.1168993e-05, -7.0621016e-05, -0.00015246746 }, { 7.12022e-05, 3.8790461e-05, -0.00023994449, 6.6792921e-05 }, { -0.00014735813, -0.00012658353, -0.00012162488, -0.00012106777 }, { 0.00015161388, -1.4439153e-05, -3.7629923e-06, 8.3140788e-06 }, { 4.0175416e-05, 2.5380268e-05, -2.2894421e-06, 4.6374378e-06 }, { 0.00028906023, 1.7695243e-05, 5.3790587e-06, 1.631859e-05 }, { 1.8890685e-05, -1.6898275e-05, 2.1007663e-05, 6.5179363e-05 }, { -3.9142595e-06, 2.5745488e-05, 1.0803197e-05, 2.7099749e-05 }, { 9.4245546e-06, 1.0010075e-05, 9.058324e-06, 9.8703427e-06 }, { -2.3441863e-06, 2.5490323e-05, -1.0097654e-05, 4.0554798e-05 }, { -4.1443921e-05, -1.996316e-05, -2.0000841e-05, -4.7495655e-05 }, { 0.00012591695, 5.6179903e-05, -1.8415869e-05, -3.8697972e-05 }, { 2.6719505e-05, 2.4195362e-06, 2.4287424e-05, 3.4703059e-05 }, { 7.3804931e-05, 4.9784871e-05, 3.1159931e-06, 0.00015857197 }, { -0.00010634331, -1.6427658e-05, -7.4874306e-05, -6.2620255e-05 }, { -4.2561214e-06, -1.6123179e-05, -1.5507273e-05, -1.2909924e-05 }, { -1.2210463e-06, 1.1546399e-06, 1.1413892e-06, -1.3465856e-06 }, { 3.4909884e-05, -1.2677793e-05, 0.00011543701, 2.413091e-05 }, { -2.1953323e-05, -4.6244252e-06, -3.5624435e-06, 4.2293671e-06 }, { -1.1392936e-05, -4.3970369e-06, -4.4264864e-06, -1.208518e-05 }, { -4.4002617e-05, 0.00020912348, -3.9617824e-05, -4.1725112e-05 } } }, { { { -0.32504349, -0.32502096, -0.32501094, -0.32423576 }, { -0.65602876, -0.65622598, -0.65567173, -0.65525128 }, { -1.4666488, -1.4666488, -1.4666488, -1.4666488 }, { 0.87168363, 0.87181364, 0.87181792, 0.8718169 }, { -1.264365, -1.264365, -1.264365, -1.264365 }, { 0.89917968, 0.89916889, 0.89916525, 0.89927374 }, { -1.2245906, -1.2245906, -1.2245906, -1.2245906 }, { -0.8885678, -0.88856217, -0.88856327, -0.88855044 }, { -0.31799095, -0.31916566, -0.31907669, -0.31918911 }, { -0.08987958, -0.090342401, -0.090004674, -0.090222398 }, { -0.59425693, -0.59433999, -0.59429118, -0.59433553 }, { 1.1317575, 1.1317475, 1.1317412, 1.1317494 }, { -1.2193493, -1.2193493, -1.2193493, -1.2193493 }, { 1.2506981, 1.250675, 1.250675, 1.2506569 }, { -1.08782, -1.0877793, -1.0878022, -1.0878025 }, { -0.13925598, -0.13932948, -0.13919658, -0.13913403 }, { -0.40394684, -0.4042314, -0.40436178, -0.40402218 }, { -0.47762966, -0.47745572, -0.47767784, -0.47713093 }, { -0.60177181, -0.60176862, -0.60177347, -0.60177079 }, { 2.7311956, 2.7311911, 2.7311911, 2.731191 }, { -1.3109856, -1.3109856, -1.3109856, -1.3109856 }, { 0.60942644, 0.60941369, 0.6094123, 0.60944198 }, { 0.55675448, 0.55672275, 0.55672303, 0.5567542 }, { -0.40637059, -0.4057945, -0.40635768, -0.40636681 } }, { { -0.0016154222, -0.0015930079, -0.0015828998, -0.00087447165 }, { -0.0011262472, -0.001324462, -0.00094895016, -0.00062188189 }, { 0, 0, 0, 0 }, { 9.7616744e-05, 0.00010718899, 0.00010718606, 0.00012665246 }, { 0, 0, 0, 0 }, { 0.00013476236, 6.982272e-05, 6.8208505e-05, 0.00014604742 }, { 0, 0, 0, 0 }, { -0.0031089951, -0.0031071196, -0.0031207245, -0.0031097054 }, { -0.0027808116, -0.0035049857, -0.0034100135, -0.0035192661 }, { -0.0018291474, -0.0019603285, -0.0018919656, -0.0019656229 }, { -0.0034301741, -0.0034912573, -0.0034474395, -0.0034893985 }, { -6.156701e-06, -9.8568527e-06, -1.2383692e-05, -9.9984205e-06 }, { 0, 0, 0, 0 }, { 0.00011838153, 0.00011008679, 0.00011008878, 0.00010536608 }, { -0.0006246638, -0.00058479459, -0.00061327452, -0.00061085433 }, { -0.0059197749, -0.0059778169, -0.0059586015, -0.0058798299 }, { -0.0013246996, -0.0016061786, -0.0016081246, -0.0014374546 }, { -0.001593227, -0.0014706843, -0.0015974008, -0.001341579 }, { -0.0027930604, -0.0027920013, -0.0027939865, -0.0027928528 }, { -1.8908723e-06, -4.266382e-06, -4.2210172e-06, -5.0155215e-06 }, { 0, 0, 0, 0 }, { 0.00018508026, 0.00019774537, 0.00019744661, 0.00019538593 }, { 2.3243747e-05, 1.7291398e-05, 1.7309712e-05, 2.9261396e-05 }, { -0.0041402471, -0.0037085946, -0.0041294876, -0.0041316136 } }, { { -0.0018899732, -0.0018719182, -0.0018661076, -0.0012234594 }, { -0.0012968123, -0.0012971446, -0.00093522854, -0.00066475268 }, { 0, 0, 0, 0 }, { 9.1054464e-05, 0.00014124217, 0.00014156806, 0.00012014953 }, { 0, 0, 0, 0 }, { 0.00017026995, 0.00010528413, 0.00010537941, 0.00015698848 }, { 0, 0, 0, 0 }, { -0.0025812972, -0.0025835894, -0.0025789321, -0.002554949 }, { -0.0035568863, -0.0042988014, -0.0042155548, -0.004312546 }, { -0.0024184575, -0.0025111277, -0.0024654994, -0.0023980076 }, { -0.0036993386, -0.0037113013, -0.0036987284, -0.0037094875 }, { -5.074861e-06, -1.1367399e-05, -1.4819989e-05, -9.2705899e-06 }, { 0, 0, 0, 0 }, { 0.00012570403, 0.00012150272, 0.00012149179, 0.00010579599 }, { -0.00062162762, -0.00058131015, -0.00060837583, -0.00060795256 }, { -0.00775735, -0.0077198081, -0.0078365948, -0.0077749317 }, { -0.0015325554, -0.0017125784, -0.001703195, -0.0015662859 }, { -0.0018130784, -0.00177106, -0.001858095, -0.0015845058 }, { -0.003668417, -0.0036659688, -0.0036693421, -0.0036680526 }, { -9.5804016e-06, -9.6276607e-06, -9.630607e-06, -1.2159056e-05 }, { 0, 0, 0, 0 }, { 0.00017930618, 0.00020084683, 0.00020150104, 0.00020810787 }, { 2.3869269e-05, 1.1024793e-05, 1.1041937e-05, 1.6467357e-05 }, { -0.004690782, -0.0044656761, -0.0046782065, -0.0046921455 } } }, { { { 0.23047932, 0.23043226, 0.23041471, 0.22922185 }, { 0.14990977, 0.15703656, 0.15110771, 0.15149153 }, { 0.30629171, 0.30426701, 0.30400037, 0.30403889 }, { 0.03476576, 0.036188528, 0.036216719, 0.037322097 }, { 0.31066251, 0.31090363, 0.31041565, 0.31057779 }, { 0.04875259, 0.046468595, 0.046486323, 0.046584523 }, { 0.31745458, 0.31874472, 0.32086369, 0.31880207 }, { 0.64054942, 0.64062862, 0.64051973, 0.64059059 }, { 0.27309038, 0.27480819, 0.27477284, 0.27486762 }, { 0.196647, 0.19687982, 0.19607604, 0.1957915 }, { 0.32867362, 0.32858008, 0.32856702, 0.328555 }, { -0.0026873031, -0.0042393446, -0.0057894907, -0.0041858859 }, { 0.40254624, 0.4024247, 0.4025598, 0.40243731 }, { 0.019362807, 0.018146218, 0.018146051, 0.019656613 }, { 0.29328089, 0.29403937, 0.29435036, 0.29403094 }, { 0.57111506, 0.57118505, 0.57099608, 0.57099266 }, { 0.16966612, 0.16993739, 0.17069399, 0.16991136 }, { 0.14989055, 0.1489484, 0.14995985, 0.15015916 }, { 0.33606014, 0.33606294, 0.33606393, 0.33605429 }, { 0.015421206, 0.015180692, 0.01518037, 0.015431139 }, { 0.33165237, 0.33185282, 0.33162592, 0.33166981 }, { 0.078137018, 0.078153855, 0.078165152, 0.078332343 }, { 0.002896946, 0.0026038621, 0.0026029604, 0.0022081151 }, { 0.41064398, 0.40987685, 0.41065341, 0.41059166 } }, { { -0.0024316111, -0.0024732789, -0.0024922144, -0.0035874346 }, { 0.0013306961, 0.004171802, 0.0027660627, 0.0023671465 }, { 0.0034411091, 0.0020878413, 0.0020874456, 0.0022028237 }, { -0.0032873976, -0.0021351911, -0.0021071363, -0.0028424534 }, { 0.0017995208, 0.0022319618, 0.0039270256, 0.0021249365 }, { -0.0019590835, -0.0012526895, -0.0012347747, -0.0021069943 }, { 0.0012319531, 0.002255621, 0.0030193583, 0.0020970822 }, { 0.0015144077, 0.0015110104, 0.0014803089, 0.0015340007 }, { -0.0036679996, -0.0028160114, -0.0028586497, -0.0027953731 }, { -0.005445786, -0.0052624873, -0.0054843188, -0.0053271749 }, { 0.00067154572, 0.0007530775, 0.00067974516, 0.00074462315 }, { -0.0035626119, -0.0034186877, -0.0038720517, -0.0040088745 }, { 0.003455851, 0.0035040061, 0.0034671486, 0.0035069881 }, { -0.0047789747, -0.0047994804, -0.0047996451, -0.0044008337 }, { 0.0032403482, 0.0033627856, 0.003429619, 0.0031153117 }, { -0.005027022, -0.0049812, -0.0049604573, -0.0050556194 }, { -0.0020728991, -0.0014784158, -0.001216894, -0.0019213729 }, { -0.00013808007, -0.00067270623, -0.00024001574, -0.00030691077 }, { 0.0004367104, 0.00043390709, 0.00043548166, 0.00043425516 }, { -0.00082746467, -0.00088151411, -0.00088152334, -0.0008043643 }, { 0.0030277712, 0.003133577, 0.0028529862, 0.0030362271 }, { -0.0058721937, -0.0059816331, -0.0059799345, -0.0058882832 }, { -0.0057032562, -0.0057401855, -0.0057416619, -0.0062417688 }, { -0.0014357888, -0.0020782049, -0.0014346823, -0.0014513767 } }, { { -0.0027051235, -0.0027087245, -0.0027052303, -0.0033594951 }, { 0.0028036195, 0.0030416572, 0.0014306948, 0.0017897371 }, { 0.0031113166, 0.0026432303, 0.0025937824, 0.0025394463 }, { -0.0036032904, -0.003447065, -0.0034344406, -0.0024163572 }, { 0.0023912799, 0.0025281229, 0.0038665087, 0.0024214034 }, { -0.0023543827, -0.0024294943, -0.0024539784, -0.0027742617 }, { 0.0020903896, 0.0026617586, 0.003395249, 0.0026261065 }, { 0.0019031008, 0.0019405475, 0.0019426085, 0.0019404325 }, { -0.0040413326, -0.0030964835, -0.0031020735, -0.0030826754 }, { -0.0064568993, -0.0062342438, -0.0064704698, -0.0065636744 }, { 0.0010788406, 0.0010092051, 0.0010264121, 0.00099891228 }, { -0.0040759201, -0.0059224283, -0.0066809927, -0.0049099348 }, { 0.0042962009, 0.0041909175, 0.0043195236, 0.0041900138 }, { -0.0062728983, -0.0070256154, -0.007025641, -0.0061758746 }, { 0.0036210401, 0.0039723998, 0.0042232048, 0.0042757707 }, { -0.0058693852, -0.0058583303, -0.0058544016, -0.005887725 }, { -0.0023099876, -0.0021136245, -0.0017298078, -0.0022483337 }, { -0.00017851962, -0.00014956209, 8.5676316e-05, -0.00024971669 }, { 0.0003734781, 0.00037078986, 0.00037364181, 0.00037070594 }, { -0.00030648905, -0.00038230535, -0.00038223043, -0.00028623253 }, { 0.0032871423, 0.0034163052, 0.0028276655, 0.0032991918 }, { -0.0061331695, -0.0063319797, -0.0063340119, -0.0064390374 }, { -0.0062172888, -0.0059787106, -0.0059793294, -0.0060406701 }, { -0.0018276142, -0.0022170788, -0.0018293949, -0.0018222824 } } } }, { { { { 0.13218089, -0.11654637, -0.11622196, -0.044208736 }, { 0.0074579257, 0.0038503609, 0.0013201096, 4.0415784e-05 }, { -0.025474487, -0.01209255, -0.016535858, 0.012704547 }, { -0.0016894103, -0.0081312144, -0.0033264609, 0.0011923269 }, { -0.068044876, 0.018276873, -0.074833897, 0.01308348 }, { 0.02665691, 0.013515118, 0.026440814, -0.0077037816 }, { 0.0023286096, -0.0025782652, 0.0021644694, -0.0042955294 }, { 0.051356261, -0.031058382, -0.085382962, -0.033103269 }, { -0.081609229, 0.0035270199, -0.015722417, 0.048773789 }, { 0.0023928418, -0.001243811, 0.011910492, -0.011621478 }, { -0.028953904, -0.029335777, -0.0057891432, 0.013874136 }, { -0.012473582, 0.001772629, -0.013983442, 0.014846792 }, { -0.016111661, 0.0018902323, 0.025910586, 0.042848276 }, { 0.026200626, 0.024007879, 0.0017667146, -0.016394032 }, { -0.0067006429, -0.0017968936, 0.009028659, 0.0044060413 }, { 0.019280611, 0.0449581, -0.042852227, -0.066012332 }, { -0.014451123, -0.047772741, -0.047475406, 0.098434178 }, { -0.0028954635, 0.010521833, -0.015741597, -0.00091666191 }, { 0.0020291956, -0.057966746, -0.04525094, 0.032711614 }, { 0.020563445, -0.0078684621, -0.015282237, -0.0019830466 }, { -0.019504171, 0.071338511, 0.0033729474, -0.0095772339 }, { 0.013056103, 0.018719519, 0.0096002937, -0.028774366 }, { -0.00038728577, -0.0010662982, -0.0014333502, 0.00059135695 }, { 0.073844752, -0.05666013, -0.1007151, -0.030440738 } }, { { 0.00017766639, -9.2398532e-05, -3.9442682e-05, -3.9559848e-05 }, { -0.0043956477, 0.00044042277, -0.00047491077, 9.4171117e-05 }, { -0.0042095545, -0.00910753, -0.0014295282, 0.0042595844 }, { 0.00070989004, -0.0009623012, 0.00084162653, -0.00015925965 }, { -0.0017587638, 0.0033199811, -0.00025544613, 0.00083644978 }, { 0.0051797987, 0.0015691893, -0.002324397, 0.0050776381 }, { 0.003911779, 0.00072639703, 2.102924e-05, -0.0029529332 }, { 0.0050240476, -0.00041452319, 3.1730448e-06, -0.0072697591 }, { -1.5023048e-05, 0.00032491246, -9.2151952e-05, 0.0035851726 }, { 0.0030984373, 0.0016428856, 0.0032974124, -0.0036034289 }, { -0.00044578206, -0.0035916409, 0.0028146658, 0.0068013321 }, { 0.00025716711, -0.0024772152, 0.0029660992, -0.0008783244 }, { -0.005543602, -0.00046453249, 0.006815884, 0.0069207512 }, { -0.0033541738, -0.0015140333, -0.004071746, -0.0020908789 }, { 0.0027932918, -0.0012517158, -0.0033509184, -0.001271572 }, { 0.0043481525, -0.00088858735, -0.0081538059, 0.00027985077 }, { 7.4017523e-05, -7.0080388e-05, -7.1766386e-05, 0.00020468758 }, { 0.00044507396, 0.010179106, -0.0048087449, 0.0013487105 }, { 0.00082148695, -0.00042640153, -0.0024255173, 0.0044486011 }, { -0.00026383509, -0.0031871528, -0.008203704, -0.00053957093 }, { -0.0002996462, 0.00070789605, 7.9300612e-05, -0.00024002209 }, { 0.0013722116, 0.0049176054, 0.0029283062, -0.000849108 }, { 0.00026545039, 0.0011783443, 0.00072103548, -0.0007355776 }, { 0.002192273, -0.00294318, 1.5452606e-05, -0.0020953993 } }, { { 2.4074136e-05, -2.4931598e-05, -1.0893587e-05, 1.080951e-05 }, { -0.0061635883, -0.0042963493, -0.00177783, -0.00080292808 }, { 0.0047868795, -0.0050472436, 0.0082439123, -0.0090979713 }, { 0.0017221077, 0.0067285193, 0.0031011872, -0.0019932567 }, { 0.0010926271, -0.0012170693, 0.00012875612, 0.00016441623 }, { -0.0048786273, -0.0041225634, -0.005591426, 0.0043469593 }, { -0.0070664098, -0.0012625813, -0.00022220241, -0.0026120468 }, { -0.0026689917, 0.00030860545, 1.9297947e-05, 0.001274799 }, { 0.0026769559, 0.00016106032, 0.00013829246, -0.0017239107 }, { -0.0042495789, 0.0010270326, -0.00078224804, -0.0019210019 }, { 0.0072385804, 0.0086418476, 0.0061428272, -0.0027142827 }, { 0.0019768127, -0.00057957046, 0.0047464783, -0.004599565 }, { 0.0093618867, -0.0010476542, -0.0038681572, -0.0065219521 }, { -0.0076406673, -0.0036729355, -0.0068804827, 0.0077571478 }, { 0.0012706397, -0.00042567505, -0.002521821, 6.0288127e-05 }, { -0.002041411, 0.000430125, 0.0073620925, 0.0021579456 }, { 0.00012145466, 4.1276616e-05, 4.2449608e-05, 9.8351262e-05 }, { 0.0014376278, -0.007439719, 0.0039006971, 0.00051135138 }, { -7.1665367e-05, 0.00023856335, 0.00015274881, -0.0096946274 }, { -0.00076804256, 0.0040182915, 0.012603411, -0.00059669891 }, { -0.00010641981, -0.00052355992, 0.00057481361, 0.00016456343 }, { -0.0027623375, -0.0036761364, -0.010480297, 0.0066006902 }, { 0.00049081404, 0.00077264749, 0.0021355718, -0.00029188425 }, { 0.00028566818, 0.00097678458, 0.00089022281, -0.00013760767 } } }, { { { -0.0098123577, 0.11017117, 0.11245143, -0.01173447 }, { 0.0036188505, -0.0025878518, -0.00043343726, -0.0038813197 }, { 0.013109746, -0.016775181, -0.0011093308, 0.00083465721 }, { -0.0042515898, -0.0028159364, 0.00027829209, -0.002907578 }, { -0.0081027554, -0.0019330574, 0.061872524, -0.037539524 }, { -0.012923735, 0.021011524, 0.002680406, 0.0034369108 }, { 0.0027819214, 0.0028657905, -0.0034177203, -0.0037322329 }, { -0.0036178174, 0.065792163, 0.13263475, 0.0055427994 }, { 0.027832309, -0.083372016, -0.058757582, 0.016164879 }, { -0.0082343898, 0.011782416, 0.011496052, -0.0027847616 }, { 0.0012516658, -0.014686832, -0.025073035, -0.020700577 }, { 0.0055718234, -0.011543219, -0.012867689, -0.0049474286 }, { 0.028869265, -0.035431559, 0.024976635, -0.01063055 }, { -0.0010657662, 0.014977146, 0.027109, 0.01612865 }, { -0.0021697493, 0.0044220507, 0.0055654161, -0.0032373397 }, { -0.018500666, -0.01979267, -0.0068480612, 0.03908391 }, { 0.063306878, 0.01934691, 0.019254616, -0.099824471 }, { 7.0580666e-05, -0.0015082457, -0.0056893693, 0.00022726294 }, { 0.0077067654, -0.014018834, -0.021406454, -0.0076589993 }, { -0.0013072394, 2.6765854e-05, 0.0028400803, 0.0037431063 }, { -0.025369581, -0.064039908, -0.020594137, -0.086807367 }, { -0.033639351, 0.010434758, 0.00082983507, 0.013145885 }, { 0.00029373395, 7.8193614e-05, 0.00048496415, 0.00062972215 }, { -0.0041597628, 0.024283117, -0.030148407, 0.011456515 } }, { { -1.3484857e-05, -3.7204145e-05, -1.5660577e-05, -2.4497955e-05 }, { -0.0068070249, 0.0041035892, 0.0034647689, 0.0035918321 }, { -0.0053613309, 0.0080593503, 0.0028507084, -0.0023104987 }, { 0.0048581064, 0.0039720065, -0.0019058129, 0.0047295789 }, { -0.00030675956, -0.0007787587, -0.00025201217, 0.00020777843 }, { -0.00026433336, -0.0093672701, -0.0053201627, -0.0059632173 }, { -0.0063062815, 0.0011995204, 0.0001870407, 0.0028197877 }, { -0.00053247524, -0.00066138217, -1.4959372e-05, -0.00036023628 }, { 0.00027591427, 0.00011309835, 2.2453632e-05, -0.00075736359 }, { 0.0015654886, 0.0018114616, -0.0004503446, -8.5866048e-05 }, { 0.003501393, 0.0037179893, 0.008328543, 0.013411108 }, { -0.0035136609, -0.0015054003, 0.0011903964, 0.0022551358 }, { -0.0083723767, 0.0061303554, -0.008056962, 0.0035035183 }, { -0.0023715655, -0.0070468331, -0.010219655, -0.0057856465 }, { -0.0011406634, -0.00021204595, -0.001693195, 0.0011051597 }, { 0.0011643412, 0.00037557194, 0.0048567739, -0.00063996433 }, { -3.1728174e-05, -2.9073903e-06, -3.0243209e-06, 2.579239e-05 }, { 0.00053152589, 0.0029635352, 0.0040743289, -0.00051381046 }, { -0.0017253584, 0.00012081524, 0.00012243664, -0.00063598215 }, { 0.0026711847, -0.0020733972, -0.0027860744, 0.0017065643 }, { 5.7762902e-05, 0.00092043577, -0.0035278882, 0.0007846087 }, { 0.0056127705, -0.0051893669, -0.0027072408, -0.0025630045 }, { -0.00059289151, -0.0004168408, -8.8118696e-05, -0.00073538101 }, { 0.0003388606, -0.00094234652, 3.013109e-05, -0.0010532484 } }, { { -2.9013996e-05, 6.1983083e-05, 2.8401438e-05, -3.4901557e-05 }, { 0.0045230474, -0.0021369843, -0.00422706, -0.0018918027 }, { 0.00017586142, 0.005389053, 0.0071352982, -0.0018278685 }, { -0.0012135723, -0.0035970727, 0.00078957165, -0.0017065397 }, { -0.00067051937, -1.9501585e-05, 4.1968766e-05, -0.0010958091 }, { -0.0015277626, -0.0039952533, -0.00049631478, 0.0018042745 }, { 0.0039376754, -0.00097834328, 6.5894634e-06, -0.0044189106 }, { -0.00067623039, 0.0004690807, 1.4532105e-07, 0.0032984829 }, { 0.0020787449, -0.0016586579, -0.00062367064, 0.0021545362 }, { 0.0016427801, 2.6710288e-05, 0.0016011535, -0.00077649869 }, { 0.0039999622, -0.0014968097, -0.0025647576, 0.0022783424 }, { 0.001558454, -0.00083803058, 0.0018955692, 0.0010432376 }, { 0.010555722, -0.010395022, 0.0050354965, -0.0016177699 }, { 0.00011370745, -0.009328355, -0.0063009522, 0.0024377458 }, { -0.00024433189, 0.00052920244, -0.0013213352, -0.0013503982 }, { -0.0057620093, 0.00095391746, -0.0034768563, 0.00093990705 }, { 0.00012108024, 4.1007202e-05, 4.2193381e-05, -0.00011043617 }, { 0.0038593696, -0.00074282979, -0.0093457897, 0.00027311164 }, { 0.0021514797, -7.8742315e-05, -0.0018813077, -0.0017625098 }, { 0.0038491118, 0.00022570776, -0.0061331041, 0.00014956617 }, { -0.00014676603, -0.00025053931, 0.003376287, -0.00014730695 }, { 0.0016439646, 0.0060569792, 0.00063058918, -0.0034810156 }, { 0.00011722835, 0.00032237223, -0.0012556553, -0.0006887808 }, { 0.00060814722, 0.0003708376, -0.00056515636, -0.00016801817 } } }, { { { 0.99117704, 0.98705585, 0.98683693, 0.9989534 }, { 0.99996564, 0.99998924, 0.99999903, 0.99999247 }, { 0.99958951, 0.99978616, 0.99986266, 0.99991895 }, { 0.99998953, 0.99996298, 0.99999443, 0.99999506 }, { 0.99764936, 0.9998311, 0.99527468, 0.99920949 }, { 0.9995611, 0.99968788, 0.99964679, 0.99996442 }, { 0.99999342, 0.99999257, 0.99999182, 0.99998381 }, { 0.99867384, 0.99734987, 0.98748052, 0.99943657 }, { 0.99627571, 0.99651225, 0.99814846, 0.99867903 }, { 0.99996323, 0.99992981, 0.99986298, 0.99992859 }, { 0.99957996, 0.99946171, 0.99966886, 0.99968945 }, { 0.99990668, 0.9999318, 0.99981943, 0.99987754 }, { 0.99945334, 0.99937032, 0.99935219, 0.99902503 }, { 0.99965614, 0.99959957, 0.99963092, 0.99973552 }, { 0.9999752, 0.99998861, 0.99994375, 0.99998505 }, { 0.99964293, 0.99879278, 0.99905795, 0.99705307 }, { 0.99788947, 0.99867085, 0.99868681, 0.99012413 }, { 0.99999581, 0.99994351, 0.99985991, 0.99999955 }, { 0.99996824, 0.99822008, 0.99874627, 0.99943549 }, { 0.9997877, 0.99996904, 0.99987919, 0.99999103 }, { 0.99948785, 0.99539425, 0.99978223, 0.99617908 }, { 0.99934875, 0.99977032, 0.99995357, 0.99949949 }, { 0.99999988, 0.99999943, 0.99999886, 0.99999963 }, { 0.99726107, 0.99809817, 0.99445842, 0.99947091 } }, { { -2.3481737e-05, -6.7307406e-06, -2.8605869e-06, -2.0372001e-06 }, { 6.6885689e-05, 4.5630281e-06, 3.5788218e-05, 1.0842484e-05 }, { -4.9278613e-05, -2.4660601e-05, 3.1625301e-06, 0.00019708279 }, { 1.2439158e-05, 3.0347865e-05, 8.6153947e-06, 1.0887256e-05 }, { -0.00012454598, -6.513709e-05, -3.5853483e-06, -3.4708286e-06 }, { -0.00013746339, 0.00013516333, 8.4535039e-05, 5.693766e-05 }, { -2.3674091e-05, -3.4690053e-06, 5.3812265e-07, -1.7613197e-05 }, { -0.00025790043, 3.0475251e-05, 2.1174795e-06, -0.00023630753 }, { -8.8624748e-06, 7.9175589e-06, -2.4258477e-07, -0.00017288313 }, { 4.0061469e-05, 0.00069846663, -0.00060299476, -0.00015396968 }, { 5.0667108e-06, 2.306363e-05, 0.00028636884, 3.6246633e-05 }, { 0.00032740524, -0.00037985037, -0.00014841039, -0.00012676016 }, { 8.7000758e-05, 0.00018530207, 1.7669124e-05, -0.00023199594 }, { 9.2332094e-05, 0.00013487652, 0.00034587506, -3.8853378e-05 }, { 6.9809868e-05, -0.00015411544, 0.0013505166, 1.4531796e-06 }, { -6.3782301e-05, 4.8545135e-05, -0.00027083794, 4.5129465e-05 }, { 3.0912438e-06, -3.2982361e-06, -3.3551612e-06, -1.7781589e-05 }, { 9.872609e-06, -2.9944213e-05, -4.5592652e-05, 1.5950681e-05 }, { 1.4767773e-05, -2.2486726e-05, -0.00010613341, -0.00015794394 }, { 2.4386215e-05, -1.1610334e-05, -4.4456294e-05, -5.0215596e-06 }, { -4.2741558e-06, 8.7714242e-06, -6.6343322e-05, 6.7010735e-05 }, { 0.00016489767, -3.3636771e-05, 5.1610504e-05, 5.2803593e-06 }, { 1.1649256e-05, 2.1169993e-05, 1.9755999e-05, 1.3389438e-05 }, { -0.00015815197, -0.00014316145, 2.6536218e-06, -4.6846396e-05 } }, { { -3.5109783e-06, -9.8530632e-06, -4.5020804e-06, 6.9233235e-08 }, { 9.9938991e-06, -2.0914089e-06, 3.5717699e-05, 3.2813664e-06 }, { 0.00012938219, 1.111062e-05, 8.0858608e-05, 0.00018147439 }, { 4.8657525e-06, 8.6580257e-06, 3.6742927e-06, 3.5828406e-06 }, { 6.9905696e-05, 2.0985073e-05, 6.8866215e-06, -4.2552499e-05 }, { 0.00012100208, 9.7821801e-05, 0.00013576456, 6.3686234e-05 }, { 1.954525e-06, -1.0727343e-06, 5.2332444e-07, -5.4034988e-06 }, { 0.00013699813, -2.226833e-05, 1.4994043e-06, 1.7110377e-05 }, { 0.0001678261, -0.00013844113, -3.4281745e-05, 5.3854072e-05 }, { -1.3018868e-05, 0.00022176303, 0.00016983401, 0.00038109805 }, { 0.00019016068, 0.00023448876, 2.643329e-05, 4.6842203e-05 }, { -1.2492528e-05, -0.00059486605, 0.00012427061, 8.1876965e-05 }, { 8.400564e-05, -0.00029859163, -4.884214e-05, 0.0002631806 }, { 0.00019907281, 0.00014046808, 0.00015482448, 4.0461099e-05 }, { -0.00024349239, 0.00081298441, 0.00084294728, 7.9617963e-05 }, { -6.0040835e-05, 3.2352918e-07, 0.00024295599, 0.00011067283 }, { -6.0027092e-06, 1.1975092e-06, 1.2248893e-06, -2.1293392e-05 }, { 1.4478736e-05, 6.8326918e-05, -7.8693614e-06, 9.2888155e-06 }, { -1.6982828e-05, 1.2094341e-05, -3.1693808e-05, 0.00028574477 }, { 3.4480942e-05, 2.6556008e-05, 0.00016193956, -1.8966503e-06 }, { -5.7726961e-06, 2.1091148e-05, 5.8963955e-05, -1.0834372e-05 }, { 0.0001214393, 1.4174882e-05, 0.0001371836, 0.00021757165 }, { 1.0140226e-05, 6.1641031e-06, 1.0590727e-05, 1.0893212e-05 }, { -1.7442656e-05, 4.2353331e-05, 7.4324714e-05, -1.9484775e-06 } } }, { { { 3.7217719, 3.6900797, 3.6899881, 3.6670816 }, { 0.067826319, 0.16468028, 0.083129199, 0.1336756 }, { 0.66338737, 0.23883566, 0.093361469, 0.10095622 }, { 0.27185537, 0.20781392, 0.32216624, 0.29876595 }, { 2.0776462, 2.0006156, 2.0243138, 2.080345 }, { 0.57695783, 0.18015147, -0.11440889, 0.14229144 }, { 0.63833683, 0.41431062, 0.44752994, 0.47594414 }, { 1.7890608, 1.962584, 1.9322155, 1.6588331 }, { 3.0538128, 3.108267, 3.1001573, 2.9593433 }, { -0.28383051, -0.27708376, -0.042513902, -0.085181891 }, { 0.3873435, 0.41697884, 0.39625427, 0.33250735 }, { -0.33498881, -0.40206929, -0.028905862, -0.48179632 }, { 1.1875033, 1.3535177, 1.2526197, 1.3337495 }, { 0.42579488, 0.24951727, 0.18976118, 0.20605317 }, { -0.53212666, -0.3861028, -0.75685995, -0.23411882 }, { 1.6910165, 1.686815, 1.5906473, 1.6528217 }, { 4.0570657, 4.0349492, 4.0350332, 4.0498099 }, { -0.017225465, -0.032503897, 0.46003211, 0.21602109 }, { 1.1196901, 1.00885, 0.91675568, 0.99635794 }, { -0.093891275, 0.0809352, -0.13783332, 0.27130678 }, { 1.9925136, 1.9829394, 1.8820721, 1.9542026 }, { 0.84563763, 0.48476746, 0.37907152, 0.70267878 }, { 0.37054708, 0.4228574, 0.6329822, 0.26197064 }, { 1.9618393, 1.8405969, 1.9440918, 1.901629 } }, { { -5.6047186e-06, 6.0454847e-06, 2.8365975e-06, 6.0894367e-06 }, { -0.00069876506, -0.00029642785, -0.00059516082, -0.00025400441 }, { -0.00020850504, -0.00012959593, -0.00032902532, -0.00058117893 }, { -0.00037901964, -0.00038062016, -0.00023777964, -0.00033714679 }, { -5.9894351e-05, -9.820791e-05, -5.9867157e-06, -6.258549e-06 }, { -0.00035424038, -8.7146215e-05, 3.0398362e-05, -0.00061406521 }, { 0.00014971442, 4.5936211e-05, -5.6259869e-06, 0.00013567035 }, { -0.00016180211, 3.1840487e-06, 3.8979157e-07, -0.00017131994 }, { -1.9877193e-05, 2.5768261e-05, 9.0577543e-06, -0.00013927462 }, { -0.0012323564, -0.00042892846, 7.2082106e-05, 0.00010999853 }, { -0.00034618449, -0.00017058897, -0.00016535057, -0.00096982024 }, { -0.00028039653, -7.155747e-05, -0.00075796707, 0.00062756458 }, { 6.6596276e-05, -7.9730809e-05, -8.0686754e-05, -2.9532397e-05 }, { -0.00084106867, -0.00036762453, 0.00012523548, -0.00052789663 }, { 7.6718268e-05, -0.0010042005, -0.00042802983, -0.0011951304 }, { -3.6972258e-05, 2.1447505e-06, -0.00035448623, -1.0620008e-05 }, { 2.8326169e-05, 2.2049468e-05, 2.2640575e-05, 1.7574827e-05 }, { -0.00014318496, -0.0004811524, -0.00049293303, -0.00067646484 }, { -2.7469144e-05, -5.9653763e-06, -1.3998899e-05, -0.00018475323 }, { -0.00017314302, -0.00010954727, -0.00040004932, 3.31106e-05 }, { -3.6093435e-06, -1.6125243e-05, -4.9195648e-05, 1.5586886e-05 }, { 0.0002059631, -0.0004024722, -0.00047984678, -9.8485329e-05 }, { -0.00094100913, -0.00073046048, -0.00052500163, -0.00068196784 }, { -2.2820197e-05, -5.9454557e-05, -6.2505468e-06, -2.6569804e-05 } }, { { 2.6015883e-05, 8.5398335e-06, 3.8473185e-06, 9.1409625e-06 }, { -0.00041459247, -0.0001855224, -0.00030529542, -0.00016322166 }, { -8.8427847e-05, -0.0002302048, -0.00038072959, -0.00076801295 }, { -0.00027717792, -0.00028594346, -0.00017910208, -0.00027291164 }, { 2.8409311e-05, -3.8005817e-05, -4.2266878e-06, -1.4520383e-05 }, { -0.0001088827, -0.00021924377, 3.9307406e-05, -0.00032488556 }, { 0.00027997916, 3.5103699e-05, -5.7448764e-06, 0.00010259251 }, { -4.7807894e-06, -2.9470863e-05, 2.6656233e-07, -0.00014346393 }, { 0.00015527098, -6.8528726e-05, -1.1206714e-05, 2.3422595e-05 }, { -0.0012763247, -0.00051503472, 0.00058055106, -0.00068688488 }, { -6.1232076e-06, -1.7073841e-05, -0.00033533389, -0.00078769935 }, { -0.00044113485, -0.00027577451, -0.0012008622, 0.00013071136 }, { 1.834948e-05, -0.00015615102, -0.00016449385, 3.6685217e-05 }, { -0.00063618257, -0.00032641968, -5.0281118e-05, -0.00041378992 }, { -0.0010181884, -0.0003871932, -0.00050061147, -0.0018967455 }, { -5.7650067e-05, -5.1145774e-06, -0.00017409773, 1.9512036e-05 }, { 1.5838743e-05, 2.503655e-05, 2.5679098e-05, 2.0053218e-05 }, { -0.00018055811, -0.00044345237, -7.9049557e-05, -0.00095669161 }, { -4.98611e-05, -1.1320605e-06, 3.7756645e-06, -8.7299215e-05 }, { -0.00011794063, -0.00015778552, -0.00036514881, 4.7288704e-05 }, { -5.1753817e-06, -1.5040527e-06, -2.836739e-05, -9.4945229e-06 }, { 0.00016873335, -0.00031983601, -0.00052281245, 0.00019034815 }, { -0.0011988594, -0.0010684975, -0.00057577023, -0.0009143845 }, { 5.0336006e-05, -1.356148e-05, 1.5582694e-05, -2.0666272e-05 } } }, { { { 0.012207721, 0.0044164612, 0.0022704542, 0.0042008503 }, { 0.29516302, 0.139976, 0.35038027, 0.13748343 }, { 0.1462123, 0.12114907, 0.28473665, 0.45762717 }, { 0.17976664, 0.19141553, 0.1209483, 0.16393769 }, { 0.044254492, 0.11383095, 0.0062726904, 0.023550537 }, { 0.14785458, 0.10151341, 0.045717467, 0.42243971 }, { -0.24205201, -0.033590842, 0.0032064617, -0.093924041 }, { 0.10866955, 0.016299431, 0.00081631108, 0.15856447 }, { 0.10108337, 0.057931152, 0.024463589, 0.21514346 }, { 0.47967783, 0.75472932, 0.5653649, 0.64752457 }, { 0.30082544, 0.15124922, 0.23567284, 0.47161499 }, { 0.54286166, 0.61049777, 0.61641378, 0.51181399 }, { 0.39328762, 0.25557559, 0.25875912, 0.22436901 }, { 0.45699569, 0.16989563, 0.2429263, 0.3924359 }, { 0.92996797, 1.1024806, 0.78045387, 1.2298879 }, { 0.19029829, -0.022675055, 0.28113642, 0.034941166 }, { 0.013203939, 0.013034069, 0.013414649, 0.011688038 }, { 0.076026927, 0.13838472, 0.29961655, 0.31531564 }, { 0.089182386, 0.010401684, 0.029374547, 0.22995838 }, { 0.052198894, 0.039866726, 0.11570972, -0.013818992 }, { 0.0062380932, 0.01788119, -0.20765047, 0.013339281 }, { 0.12436441, 0.17318651, 0.21554136, 0.18600144 }, { 0.38005287, 0.32135548, 0.28632777, 0.29211902 }, { 0.03798742, 0.0450845, 0.010912505, 0.039060104 } }, { { 0.00077914246, 0.00011130803, 8.1110229e-05, -0.00035312557 }, { 0.00051711901, 0.00029701387, 0.00040733345, 0.00034149723 }, { 0.00063893978, -0.00013702086, 0.00030866699, -0.00020070677 }, { 7.5899443e-05, 9.7456273e-05, -4.5352178e-05, 7.6172703e-06 }, { 0.00066250814, -0.00073033349, 0.00015225542, -0.0010197351 }, { 0.00040931533, -0.00043022747, 0.00093333285, 0.0002579685 }, { -0.00067488578, -0.0003706974, -0.00044487256, -0.00056555959 }, { 0.00075838366, -0.0021903789, -0.0026744174, -0.00047135202 }, { -0.00081050821, -0.0010297809, -0.00099480849, -0.00074914246 }, { 0.00063637392, 5.248783e-05, 0.00044645091, 0.00018028446 }, { 0.00067430392, 0.0004762628, -0.00032736685, 0.00041933609 }, { 6.2324555e-05, -1.6709531e-06, 0.00057418116, -0.0010360999 }, { -0.00038256183, -0.0010104012, -0.00045533693, -1.3888404e-05 }, { 0.00068274628, 0.00068411875, -0.00091273333, 0.00016211145 }, { -0.00039440715, 0.00027665323, -0.00035895503, 0.00013423207 }, { -0.00061939017, 0.00012140102, 0.00024178233, 0.00064755788 }, { -0.00052441128, -0.00050994483, -0.00051126044, 0.00066320373 }, { 0.00085915332, 0.0013567332, -0.00014328466, 0.00056098523 }, { -0.0012682676, 0.0029139719, 0.0019812291, -0.00053863027 }, { 0.0021895869, 0.00062956835, 0.0018161156, 0.00011699452 }, { -0.0010337306, 0.00016880497, -0.0014942346, -0.0034402453 }, { -0.0025336946, -0.00019468865, -0.00018045349, -5.4312149e-05 }, { 0.00021491979, 4.7651714e-05, -0.00044921151, 0.00046742044 }, { 0.0019408125, 0.00044842687, 0.0026003265, -0.00090116109 } }, { { -0.0006591255, 0.00022873584, 0.00026313866, -0.00060151354 }, { 0.00027198127, 0.00034252944, 0.00033246896, 0.00035232159 }, { -0.00034460639, -5.9085725e-05, 7.836454e-05, -0.00018946388 }, { 0.00018790551, 0.0001918358, 9.7031467e-05, 0.00015259869 }, { -0.0023033429, -0.0012945186, -0.00080964072, -0.00030432514 }, { -0.001359781, 0.00055828912, -0.00041912301, 0.00019263336 }, { -0.00042789448, -0.00018313775, -0.00030217124, -0.00028437496 }, { -0.0018340159, 0.00030654336, -0.00010781402, -0.0011985455 }, { -0.002103478, 0.00029492518, -0.00042283946, -0.001472689 }, { 0.00064558079, 0.00049703204, -0.00018932594, -0.00038268301 }, { -0.00097813334, -0.00057838807, 0.00079268109, 0.00039650774 }, { -0.00017335252, 0.00074363734, 0.0008194423, -0.00065923207 }, { -0.00075344545, -0.00026114262, -0.00054658657, -0.0013814943 }, { -0.00028279346, 0.00055730283, 0.00048990213, -0.00022186466 }, { 0.00013438509, -0.0001962818, -0.00036195953, 0.00042669461 }, { -0.00089003585, -0.0011600794, -0.0012554286, -0.0012892408 }, { -0.00067007058, -0.0010597247, -0.0010590421, 0.00044132516 }, { 0.0011626727, 0.001261033, -0.00072912018, 0.00076332442 }, { -0.001204702, -0.00011230019, 0.00036178615, -0.0017559004 }, { 0.00096282849, 0.001025959, 0.0011696947, 0.00046633555 }, { -0.00082328571, -0.00075771669, -0.0011629302, 0.00073458863 }, { -0.0016869269, -0.00035239862, -0.0004024204, -0.0016276971 }, { 0.00029053123, 0.00013409355, -0.00049087974, 0.00061969429 }, { -0.0013198997, -0.0018615784, -0.0025724061, -0.0015563017 } } } }, { { { { -0.072246889, -0.043157285, 0.043289306, 0.095998047 }, { 0.12597079, 0.24289541, -0.10930005, -0.24150539 }, { 0.031889347, -0.036238337, -0.014521983, -0.018963885 }, { -0.044155351, -0.0077170425, -0.043781059, 0.047982339 }, { 0.093995001, -0.0079510758, -0.04688882, -0.11125523 }, { 0.01700754, -0.0034361033, 0.055252382, -0.053119426 }, { -0.0014957087, -0.00063057103, 0.037930463, 0.017656646 }, { -0.017388477, -0.084085888, -0.067726647, 0.061397079 }, { -0.070625168, -0.061293011, -0.077366932, 0.11518646 }, { -0.14771316, -0.12543895, 0.052150789, 0.10530462 }, { -0.03609139, 0.001131616, -0.039549928, 0.03805765 }, { 0.064364205, 0.066758929, 0.045537002, -0.05510954 }, { 0.049051369, 0.098312455, -0.01079726, -0.11202623 }, { 0.033012208, -0.0013996988, -0.0049458824, -0.028981527 }, { 0.008617177, -0.00017670863, -0.0052380282, -0.0023438457 }, { -0.05901498, -0.050754807, -0.00011829844, 0.037297411 }, { -0.056264446, -0.03645315, -0.066412698, 0.019549244 }, { -0.11401603, -0.11856524, 0.12275022, 0.11635143 }, { -0.0011999881, -0.0016334327, -0.0056868938, 0.013393766 }, { 0.054526972, 0.033632235, 0.062591094, -0.0025531074 }, { 0.073041316, 0.073735243, -0.06935254, -0.11214186 }, { 0.034872822, -0.015473423, 0.037359975, -0.026829465 }, { -0.015137592, -0.0064462553, 0.011771178, 0.0025042048 }, { -0.038708904, -0.033968131, -0.044070885, 0.024422773 } }, { { -0.047895007, -0.016535938, 0.04855533, 0.018341613 }, { 0.004310087, 0.01519838, -0.0033290683, -0.013597406 }, { 0.0015859181, 0.016869623, -0.019279963, -0.01426933 }, { -0.0061048976, 0.031131561, 0.018085381, -0.017927117 }, { 0.052590378, 0.0066156852, -0.0025756141, -0.037241705 }, { 0.0083512619, 0.0046235666, 0.024122126, -0.013443654 }, { 0.0010672274, 0.00053123301, -0.0016276029, -0.04221993 }, { -0.0048754166, -0.021474788, -0.0039993317, 0.011831691 }, { -0.054685347, -0.050242732, -0.007606251, 0.043061893 }, { -7.5644942e-05, 0.00086632318, 0.0001960729, 0.0013264286 }, { 0.0042413724, -0.0057181522, 0.0065940983, -0.0078263328 }, { 0.0031260881, -0.0013520907, 0.025073658, -0.010841673 }, { 0.038353769, 0.06620308, -0.0072105562, -0.079188681 }, { 0.003099559, -0.0022927921, 0.021982683, -0.018991144 }, { 0.012285675, 0.0091834074, -0.0041874571, -0.032253924 }, { -0.014563556, 0.009843969, -0.010490279, 0.012979866 }, { -0.005492286, 0.064109426, -0.034795617, -0.020395732 }, { -0.023364141, -0.059336321, 0.080710391, 0.038948527 }, { 0.0028384819, 0.001822471, 0.0012903958, 0.012781079 }, { -0.004510518, -0.0020008272, 0.0017752876, 0.0077607089 }, { 0.032279653, 0.0041906079, -0.034682371, 0.0061335907 }, { -0.0082992317, -0.025250117, -0.017026845, -0.028345042 }, { -0.013132125, -0.026688493, -0.0014827793, -0.003236826 }, { 0.01650781, 0.002313574, -0.012897922, 0.026077933 } }, { { 0.062668058, 0.0081578851, 0.018952049, -0.012267283 }, { 0.0008567722, 0.0033246009, -0.0037620102, -0.0096317368 }, { -0.0083012273, 0.01184624, -0.01209373, 0.020208536 }, { 0.013862003, 0.019166381, 0.013235471, -0.026788736 }, { -0.021904217, -0.051018749, 0.0020330268, 0.006626371 }, { -0.015856131, 0.0028024655, -0.032825412, -0.018920906 }, { 0.0020870233, 0.0011616727, -0.0032704368, -0.027327141 }, { 0.01934969, 0.002427195, 0.049925128, -0.0061414889 }, { 0.013158375, 0.022248445, 0.040266734, -0.017583455 }, { 1.9024812e-05, 0.00071602053, 0.0012622199, 0.0018791611 }, { -0.0011857767, 0.0023417924, 0.026237548, -0.014687892 }, { -0.041419782, 0.024942194, -0.029143101, 0.036590943 }, { -0.015470651, -0.035208671, -0.038530514, 0.037434376 }, { -0.0029356279, 0.0023358079, 0.017641055, 0.0038203652 }, { -0.0030449623, -0.010187444, 0.0066142145, 0.0037433206 }, { 0.0080034603, 0.011463159, -0.0058129532, 0.011831147 }, { -0.0091743137, 0.045949289, 0.022412137, -0.0067531419 }, { 0.00069946656, -0.0068974782, 0.0091806954, 0.0022160793 }, { -0.0027530077, 0.00089797627, 0.0066153093, -0.010355635 }, { -0.019399018, -0.0085762573, 0.0208003, -0.027739023 }, { -0.014354809, -0.011971089, -0.0031124986, 0.044710091 }, { -0.011411144, 0.0073253411, -0.0087561348, -0.014838738 }, { 0.018837992, 0.00231775, -0.013982978, -0.0020044658 }, { 0.0012069362, 0.0012202952, 0.029106153, 0.00062793994 } } }, { { { 0.054154158, -0.11603661, -0.025631275, 0.054671866 }, { -0.2359715, 0.093194255, 0.21874866, -0.08378526 }, { 0.0089903397, 0.0087113885, -0.015445726, 0.011142042 }, { -0.0055372249, -0.0041494086, -0.033355186, -0.010136823 }, { -0.015010227, -0.0077144008, 0.13058394, -0.016779666 }, { -0.015855009, 0.014090685, 0.026549575, 0.025677527 }, { -0.00065423811, -0.0011506403, 0.028628751, 0.0086359197 }, { -0.010571292, 0.035861454, -0.025871285, -0.024827688 }, { 0.00010603924, 0.011433504, -0.052819957, -0.020208661 }, { 0.12243361, -0.14574398, -0.10091072, 0.054524772 }, { -0.014659734, -0.02291001, 0.010102434, -0.0099333349 }, { -0.0079939087, 0.023468399, 0.044548395, 0.04568814 }, { -0.048188816, 0.016469102, 0.084818672, -0.040634065 }, { 0.015089138, 0.025396216, 0.017000121, 0.010820807 }, { -0.0098155552, -0.00080001495, 0.0020122754, -0.00046896909 }, { -0.0018906417, -0.03909342, -0.020339049, -0.024007559 }, { -0.0012744487, -0.027829333, -0.05202457, -0.024366779 }, { 0.10406956, -0.092281421, -0.050420166, 0.10716663 }, { -0.0049603976, -0.0055370076, -0.0016910106, 0.012172389 }, { -0.0026486448, 0.038673757, -0.0016176887, 0.052692494 }, { -0.03722357, 0.055455783, 0.067738953, -0.0087990582 }, { -0.0026491637, 0.017275247, 0.010687117, 0.020312052 }, { -0.0016032469, 0.0090272843, -0.0079027514, -0.0050039898 }, { -0.0073653412, -0.033150577, 0.0082912493, -0.021457881 } }, { { -0.0059001999, 0.033600833, 0.066374213, -0.018058548 }, { -0.0037864945, -0.0064946131, 0.0018627774, 0.0044899139 }, { 0.0048961861, -0.0034770968, -0.0002311598, -0.0053935761 }, { 0.0090090757, 0.012149811, 0.0029969663, 0.0049403543 }, { -0.042874682, -0.0083455851, -0.0064437344, 0.0010579362 }, { 0.011866873, -0.017157526, -0.014724976, 0.0054373752 }, { -0.0006329516, -0.00024834697, 0.0015416168, -0.014246989 }, { 0.031530357, -0.052715858, -0.0063186617, -0.0070200141 }, { -0.0082273844, 0.053856605, 0.0096812384, 0.01684635 }, { -0.00017150577, 0.00097354737, 0.0013944706, 0.00085166684 }, { -0.013604545, 0.0089329355, -0.013809086, 0.0025044469 }, { -0.020284731, 0.0004724419, -0.045697697, -0.01844702 }, { 0.017874081, -0.0040537465, -0.023316716, -0.026344708 }, { 0.0092557469, -0.014456327, -0.0092919835, 0.0091758924 }, { 0.016058873, 0.0019220807, 0.0031692823, 0.0024577167 }, { -0.021184352, 0.021287579, -0.0048442696, 0.0095799112 }, { 0.035229915, -0.054291919, -0.013871324, 0.035585241 }, { 0.001275203, 0.011513119, 0.020184769, -0.0061701639 }, { 0.011353237, 0.0052697685, 0.0047637419, -0.020278005 }, { 0.0068266296, -0.01173749, 0.037482577, -0.0083236299 }, { 0.025699221, -0.03651135, -0.032342446, -0.0059784486 }, { 0.0029540635, -0.0021598269, 0.0028168477, 0.0044577193 }, { 0.0038274002, -0.0050806333, 0.007628551, 0.0027461742 }, { 0.0056567464, 0.006846664, -0.031161558, -0.0040832656 } }, { { 0.025668431, 0.0093723617, 7.4324163e-05, -0.023051436 }, { -0.010148124, 0.0018159908, 0.0072269566, 0.00082671261 }, { 0.0069741056, 0.023493533, 0.028507618, -0.026874125 }, { 0.0083316277, -0.024891629, 0.013623217, 0.0038373532 }, { -0.020992516, 0.070912136, -0.0014634877, -0.015680371 }, { 0.02178962, -0.003772636, -0.024578501, -0.047467019 }, { 0.0028586275, 0.0033445767, 0.0049576063, -0.017365739 }, { 0.0075721122, 0.010652219, -0.024031886, -0.0001146548 }, { 0.016381176, -0.044765924, -0.038036229, -0.014041395 }, { -0.00082564842, 0.00033107944, 0.00073792054, 0.0005712734 }, { 0.0080934887, 0.014534447, -0.0071347609, 0.0085413493 }, { -0.018211778, 0.0064443848, 0.017393403, 0.011490985 }, { -0.071531366, 0.030059694, 0.049103287, 0.0074609412 }, { 0.00770209, -0.017999995, -0.040048679, -0.0029073853 }, { 0.020442166, 0.0019454488, -0.019644905, 0.021793285 }, { 0.035171271, 0.0080192155, -0.023151504, 0.014168348 }, { -0.048901887, -0.0039613606, 0.0021703807, 0.030275152 }, { 0.044666116, -0.029756153, -0.015570779, 0.034470632 }, { -0.0078700362, 0.0037551741, 0.0003070052, -0.0031237403 }, { 0.015288427, -0.01284757, -0.0075319169, 0.026981487 }, { -0.0093872483, 0.013517073, -0.030221944, 0.058356065 }, { 0.0042326205, -0.016381154, 0.021475001, 0.01008732 }, { 0.0034929117, 0.020531314, -0.0085114063, 0.004821913 }, { 0.014314413, 0.01127037, -0.017197896, 0.0046932185 } } }, { { { 0.99591552, 0.99230689, 0.99873374, 0.99387895 }, { 0.96356049, 0.96556546, 0.96964041, 0.96677566 }, { 0.99945097, 0.99930521, 0.99977525, 0.99975808 }, { 0.99900933, 0.99996161, 0.99848418, 0.99879675 }, { 0.99545951, 0.99993863, 0.99032786, 0.9936502 }, { 0.99972964, 0.99989482, 0.99811938, 0.99825798 }, { 0.99999867, 0.99999914, 0.9988702, 0.99980681 }, { 0.99979292, 0.99581299, 0.99736843, 0.99780458 }, { 0.99750292, 0.99805433, 0.99560254, 0.9931383 }, { 0.98142286, 0.98133774, 0.99352772, 0.9929441 }, { 0.99924096, 0.99973689, 0.99916652, 0.99922617 }, { 0.99789446, 0.9974931, 0.99796885, 0.99743448 }, { 0.9976331, 0.99501931, 0.9963379, 0.99287411 }, { 0.99934104, 0.99967648, 0.99984325, 0.99952138 }, { 0.9999147, 0.99999966, 0.99998426, 0.99999714 }, { 0.99825531, 0.99794572, 0.99979313, 0.99901579 }, { 0.99841509, 0.99894779, 0.99643504, 0.99951192 }, { 0.98801309, 0.98864879, 0.99115599, 0.98740957 }, { 0.99998698, 0.99998334, 0.9999824, 0.99983621 }, { 0.99850879, 0.99868574, 0.99803794, 0.99860752 }, { 0.99663402, 0.99573479, 0.99528974, 0.99365325 }, { 0.99938825, 0.99973103, 0.99924472, 0.99943364 }, { 0.99988413, 0.99993848, 0.99989949, 0.99998434 }, { 0.99922338, 0.99887297, 0.998994, 0.9994714 } }, { { -0.0050599833, 0.003362263, 0.0035202243, -0.00056864904 }, { -0.0014675187, -0.0029154981, -0.00077796172, -0.0027392627 }, { -0.0010916411, 0.00078232803, 0.0014339533, -0.0020166729 }, { 0.011183745, 0.008298699, 0.011631254, 0.00030693508 }, { -0.0012964861, -0.00028098882, 0.00098513135, -0.0052243577 }, { 0.0091119501, 0.002780703, 0.011045274, 0.00334383 }, { 4.1103001e-05, 5.5767744e-05, 0.0030605577, 0.0022152241 }, { 0.00085375099, 0.0026952672, 0.0071937971, 0.0056504112 }, { -0.003773118, 0.0047936307, -4.5743022e-05, -0.0038357994 }, { 2.3815581e-05, 0.0002468657, 0.00013492048, -0.00018410816 }, { 0.0070959632, -0.00205589, 0.0056417297, 0.0030702073 }, { 0.010671769, 0.0074346008, 0.0012867659, 0.0075437523 }, { -0.0013037272, -0.0058374269, 0.0025899757, -0.0071565118 }, { 0.0030041304, 0.0018011397, 0.0093160386, 0.0082062863 }, { 0.0053156934, 0.0036543193, 0.0048724246, 0.0035118324 }, { -0.0053866158, 0.0024053442, 0.00052459148, 0.0090970513 }, { 0.011239324, -0.0010327051, -0.00097551594, 0.0044180668 }, { -0.0024379533, -0.0088232426, -0.012355568, -0.0031875953 }, { 0.0026244123, 0.0011858999, 0.0028110843, -0.001005442 }, { 0.0059514328, 0.0018892606, 0.0050231625, 0.0046700575 }, { 0.00050741664, 0.0096547476, -0.00079618251, 0.0024532112 }, { 0.0058717468, -0.0017457656, 0.0080261577, -0.00048009588 }, { 0.0025457914, 0.0016788968, 0.0013982313, 0.00073909928 }, { 0.0075035778, 0.011234409, 0.0079271096, 0.006672353 } }, { { 0.0095152396, 0.0011785006, -0.00081996856, 0.0018904938 }, { -0.0025430397, -0.0010236291, -0.0020168276, -0.0021827861 }, { 0.0036295778, 0.005406882, 0.0040788276, -0.0057729163 }, { -0.00029952998, 0.0024548208, 0.0088548836, 0.0019084209 }, { 0.0034184324, -0.0088925589, 0.00023040452, 0.00017437939 }, { 0.0037804595, 0.012156355, 0.0041276361, 0.012721488 }, { 7.4846461e-05, 0.00010580108, 0.013483417, 0.0024239851 }, { 0.00026411032, -0.00059353627, 0.0093564271, 0.0061507538 }, { 0.0016065383, -0.0027764641, 0.0013620195, 0.0010062065 }, { 9.7127925e-05, 0.00017275393, 1.0814607e-05, -0.00022627793 }, { 0.0048710612, -0.00014794569, 0.0082832436, -0.00072595412 }, { -0.0027392579, 0.0066783951, 0.00087397132, 0.001567366 }, { -0.003378151, 0.0025916338, -0.0025553201, 0.0030152022 }, { 0.0096818399, 0.0012695523, 0.0072489949, 0.016881099 }, { 0.0022796191, 0.0051693266, 0.0023373397, -0.0041448561 }, { -0.0002074582, 0.0035962454, -0.0007460719, 0.0025086317 }, { 0.0035784996, 0.003162753, 0.0022592918, 0.00024595998 }, { -0.0051294944, -0.0041428868, -0.0027597, -0.0039539398 }, { 0.0022410392, 0.00031263884, 0.0016376751, -0.0022787113 }, { 0.0025647038, 0.0074733037, 0.0051722028, 0.0024463612 }, { 0.0011787227, 0.0071159753, 0.0017217143, 0.0062717989 }, { 0.0046836737, 0.0038976423, 0.00062832002, 0.0027638154 }, { 0.0014142926, 0.0024903802, 0.0015757227, 0.0011628587 }, { 0.0016928585, 0.0043828548, 0.001653268, 0.011450696 } } }, { { { 2.8886078, 2.8900127, 2.7925705, 2.7895874 }, { 4.5455217, 4.5284714, 4.7042338, 4.6915273 }, { 0.96672505, 0.99303664, 0.98927606, 1.0351588 }, { 1.2743756, 1.2525364, 0.99649566, 0.94572778 }, { 2.6910679, 2.6922168, 2.8503404, 2.8246076 }, { 1.256075, 1.2325025, 1.5911826, 1.6091223 }, { 1.3601759, 1.3606869, 1.2793533, 1.240925 }, { 2.0291828, 2.0506809, 1.7341658, 1.6555689 }, { 2.6663531, 2.6921882, 3.1290975, 3.11849 }, { 5.3676887, 5.3663279, 5.3848664, 5.3852162 }, { 1.0586431, 1.0865889, 0.8196623, 0.8076665 }, { 1.6967251, 1.7305944, 1.5450413, 1.6347879 }, { 3.0908857, 3.0706775, 3.2974343, 3.3053965 }, { 1.2172073, 1.3839086, 1.5086796, 1.4295506 }, { 0.97676668, 1.0856738, 0.98747912, 1.0385491 }, { 1.5662275, 1.4603538, 1.784278, 1.6575438 }, { 2.1085757, 2.2092885, 2.1410448, 2.1518347 }, { 4.0214776, 4.006424, 3.7686967, 3.7771354 }, { 1.2089239, 1.2116036, 1.1244311, 1.0901017 }, { 1.1827246, 1.1472796, 1.7516784, 1.7833976 }, { 2.2113439, 2.197512, 2.2692963, 2.2787751 }, { 0.98819531, 1.057833, 1.3587301, 1.3890421 }, { 1.208957, 1.2247867, 1.2301205, 1.2325178 }, { 1.0499613, 1.1319197, 1.4067885, 1.3209087 } }, { { -0.002860931, -0.0033581281, -0.0047612075, -0.0030481839 }, { -0.0017370907, -0.0065700936, -0.0011051926, -0.0046915938 }, { -0.0006126207, 0.0010791181, -0.022876686, -0.015937275 }, { -0.010040922, -0.016433531, -0.0044976975, -0.029838315 }, { 0.00056888968, -0.0093450028, -0.00041549218, -0.0069079656 }, { -0.029781683, -0.019722587, 0.019472312, 0.0016798037 }, { -0.0015128736, -0.0012250172, -0.0091568262, -0.0091368119 }, { 0.0010846814, 0.0017189068, 0.012975603, -0.0051530971 }, { -0.026042808, -0.0090684857, -0.0021498742, -0.0032938309 }, { -0.0012792901, -0.0010431731, -0.0021366737, -0.0025526365 }, { -0.03218779, -0.013848893, -0.021872476, -0.029443623 }, { 0.008300061, 0.011951182, -0.011139414, 0.0098292843 }, { -0.0065854884, -0.020955083, -9.3843515e-05, -0.0078425688 }, { -0.054726229, -0.0073673428, -0.019267231, -0.03383648 }, { -0.049769726, 0.0065482059, -0.010189395, -0.0050480393 }, { 0.022565943, -0.020311569, 0.0091512717, -0.015600752 }, { -0.014418429, 0.0060070592, -0.0055296743, -0.003361885 }, { 8.8146509e-05, -0.0082609252, 0.0036746024, 0.0040108321 }, { 0.0010230427, 4.8153189e-06, 0.0052893378, -0.0096303521 }, { 0.0032909351, -0.010982824, 0.003880027, 0.0097699095 }, { -0.006528317, -0.012608887, -0.0057088008, -0.003867806 }, { -0.046599771, -0.024701737, -0.001078321, -0.0041018649 }, { -0.021680777, -0.021120711, 0.0055144734, -0.0031337995 }, { -0.030559213, 0.0089872726, -0.011166202, -0.0077587071 } }, { { -0.0059548858, -0.0040070313, -0.0062572119, -0.0047711065 }, { -0.0031938803, -0.005431389, -0.0026376521, -0.0046119366 }, { 0.0064917253, 0.013030824, -0.027850471, -0.011824849 }, { -0.032644485, -0.025045016, -0.0034396539, -0.039827623 }, { -0.007691681, -0.014095643, -0.0008171964, -0.0051336386 }, { -0.035626586, -0.021424668, 0.00035790929, 0.0099705685 }, { -0.0019006762, -0.0014887089, -0.0050782898, -0.0096835564 }, { -0.00087496879, 0.0052586834, 0.017041675, -0.00046753956 }, { -0.022489507, -0.0084834888, 0.0017184219, -0.0023910992 }, { -0.0010618265, -0.00085888729, -0.0020035777, -0.0024245283 }, { -0.029245834, -0.038977066, -0.013385246, -0.030312138 }, { -0.0028497869, 0.014205986, -0.0125692, 0.0037959624 }, { -0.0086377959, -0.019175965, -0.007684309, -0.005037677 }, { -0.063945685, -0.0060751259, -0.0057457302, -0.019079575 }, { -0.043745147, 0.013651906, -0.034067394, 0.0012111497 }, { 0.0086647574, -0.019171418, 0.020745219, -0.0055629951 }, { -0.024541273, 0.0072112135, -0.0078821942, -0.0085072621 }, { -0.0018227939, -0.0021153099, 0.008577002, 0.0043865151 }, { -0.013984752, -0.012209334, 0.00023638151, -0.0085025952 }, { -0.0099800075, -0.0095390578, 0.0081328135, 0.012673433 }, { -0.0099975551, -0.0028467616, -0.010712056, -0.0045012212 }, { -0.011329139, -0.0084709831, -0.0070232966, 0.0015504012 }, { -0.015334801, -0.0075637633, -0.01107439, -0.0094188163 }, { -0.017505269, -0.00013701888, -0.033955823, -0.034192649 } } }, { { { 0.16413327, 0.084074422, 0.10646123, 0.18806073 }, { 0.039511019, 0.058967072, 0.035166958, 0.052296507 }, { 0.26970995, 0.21576211, 0.2954278, 0.29870678 }, { 0.40442043, 0.38744132, 0.14502571, 0.24076804 }, { 0.22655046, 0.20912486, 0.015295019, 0.16442957 }, { 0.69235319, 0.6080183, 0.36756076, 0.23314717 }, { 0.085565328, 0.075535626, 0.22162979, 0.33140596 }, { 0.16109547, 0.11961895, 0.26619212, 0.25941009 }, { 0.27077686, 0.23481238, 0.063446408, 0.11614487 }, { 0.026116057, 0.027491327, 0.030421883, 0.039965345 }, { 0.33922592, 0.38039792, 0.27167385, 0.31510976 }, { 0.32744968, 0.22567102, 0.23116584, 0.18867836 }, { 0.29783431, 0.28054079, 0.26752139, 0.23889932 }, { 0.61721263, 0.60602797, 0.51283622, 0.47601102 }, { 0.51383952, 0.53111455, 0.44519064, 0.42875877 }, { 0.3485879, 0.35374178, 0.53292055, 0.53995494 }, { 0.4366997, 0.35554257, 0.14878367, 0.22083288 }, { 0.12855375, 0.16718264, 0.17583661, 0.11125895 }, { 0.35898096, 0.37222307, 0.35439108, 0.35956111 }, { 0.16773044, 0.25668894, 0.23246756, 0.1506316 }, { 0.36172813, 0.26938211, 0.20069185, 0.1714591 }, { 0.3998571, 0.23607244, 0.34121623, 0.29126696 }, { 0.31471307, 0.29500525, 0.39451396, 0.40013999 }, { 0.29554399, 0.28083636, 0.47190649, 0.47892938 } }, { { 0.01419653, -0.061214452, -0.032506906, 0.0078227125 }, { -0.015799432, 0.0136148, -0.0090824684, 0.013638505 }, { 0.023848919, 0.022034707, 0.022812846, 0.022790329 }, { -0.0026324255, -0.0053566952, 0.00027470228, 0.050203583 }, { 0.0035659857, -0.02015272, -0.039043616, 0.054511651 }, { 0.0052075445, 0.0051043119, -0.011801097, -0.0074336577 }, { 0.020735195, 0.01811747, 0.00808952, 0.01140964 }, { -0.0073139049, 0.011075347, 0.0057685988, 0.010251582 }, { 0.024813488, -0.01629986, -0.012536791, -0.01110061 }, { -0.014508648, -0.021444084, -0.023836972, -0.014258253 }, { 0.0079687141, -0.00092011446, 0.060249601, 0.033199468 }, { -0.020822483, -0.013924875, -0.005068391, -0.016928794 }, { -0.030059, -0.013887475, -0.045329289, -0.04449219 }, { 0.007264541, 0.0015213919, -0.0066322618, -0.0036449174 }, { 0.0057175046, 0.0012159867, -0.00054271896, 0.0020625484 }, { 0.0027083179, -0.0012554897, -0.0044854592, -0.0045242423 }, { -0.017906563, -0.028301884, -0.010139427, 0.0035851304 }, { -0.020245794, 0.01149232, 0.011320484, -0.013561794 }, { 0.0068048997, 0.011957759, 0.0046962412, -0.0015476541 }, { -0.0022514613, 0.019996868, 0.0051520398, -0.023405604 }, { 0.0055213198, 0.0070384134, 0.024405643, -0.02050399 }, { 0.039987541, 0.021127504, -0.012323503, -0.0041538161 }, { 0.0072321478, 0.0053097351, 0.0039966161, 0.013617175 }, { 0.030470642, 0.0044694115, -0.0024591651, -0.0027274707 } }, { { -0.040500402, -0.039657034, -0.017497359, -0.017857145 }, { -0.0015646885, -0.020957371, -0.0057356498, -0.0060587007 }, { 0.0070388709, -0.013205178, -0.00033412934, 0.02192306 }, { -0.0042317723, 0.020620857, -0.012309167, 0.065948811 }, { -0.016686589, 0.013616667, 0.030139062, -0.019023551 }, { 0.015181564, 0.008673659, -0.0014559576, -0.025916054 }, { 0.031630671, 0.027030197, -0.026982415, 0.025214731 }, { -0.003845127, -0.00062884599, -0.029488655, -0.0051457939 }, { -0.0032476351, 0.0021153707, -0.033110808, -0.033629213 }, { -0.0064637077, -0.010805748, -0.014982403, -0.0084641529 }, { 0.0087766042, 0.017780238, 0.026838871, 0.032580257 }, { 0.0010700985, -0.037414784, -0.0053773565, 0.0040969752 }, { -0.02637392, -0.050236074, -0.048422986, -0.069357813 }, { -0.0089483588, 0.0026259727, 0.0040142797, -0.010752754 }, { -0.0025658872, 0.0071106029, 0.015467367, 0.0012536589 }, { -0.0037247444, -0.0036991733, -0.015429566, -0.016148852 }, { -0.024788221, -0.045938054, -0.028679471, 0.011593494 }, { -0.032699114, -0.036800967, -0.033870575, -0.031842203 }, { 0.018156047, 0.02457546, 0.0209432, 0.015057433 }, { 0.0043152638, 0.025831372, -0.019608349, -0.026614397 }, { -0.0057047815, -0.013831909, 0.027613211, -0.043616864 }, { 0.014124478, -0.010786326, 0.010775415, -0.023241344 }, { 0.018337827, 0.0048735321, 0.018371717, 0.022106807 }, { 0.013619207, 0.022051384, 0.0082720974, -0.0030262071 } } } }, { { { { 0.083322661, 0.079807165, 0.03660117, -0.051657142 }, { -0.099216074, -0.0080141573, 0.10637241, 0.0367403 }, { 0.20813681, -0.0001361621, -0.20762563, -0.085913357 }, { -0.22091149, 0.10003156, -0.16122219, 0.31542901 }, { 0.16226908, 0.02665194, -0.012123307, -0.16559939 }, { -0.14025496, 0.025804505, 0.076174345, 0.20548591 }, { 0.0035713609, -0.0092551928, -0.099937652, 0.0038879391 }, { 0.12405732, -0.0053373497, -0.030865175, -0.060934551 }, { -0.0060175826, -0.026583926, -0.075326797, -0.0063155886 }, { 0.036389362, 0.054175433, 0.06490927, -0.038784258 }, { 0.30604876, -0.030813476, 0.011402956, -0.21074796 }, { -0.31769497, 0.046793931, -0.038212559, 0.21137297 }, { 0.12952945, 0.20720126, 0.08525845, -0.14568109 }, { -0.09735197, -0.17799099, -0.12256082, 0.038889119 }, { 0.002114572, 0.026037779, -0.0036772795, 0.13478173 }, { 0.094577863, 0.0057382415, -0.087017736, -0.059444148 }, { 0.054953104, 0.071323301, 0.097417831, 8.3254475e-05 }, { -0.11005534, 0.027214076, 0.0059378205, 0.02443999 }, { 0.27096654, 0.1864966, 0.034810947, -0.25886676 }, { -0.35626794, 0.037256657, -0.17795321, 0.52988269 }, { 0.14913899, -0.0086988732, -0.028760192, -0.21779266 }, { -0.16010301, -0.17699785, 0.017269826, 0.17878541 }, { -0.0049504093, -0.02387924, -0.04034852, -0.060461173 }, { 0.10405347, 0.0072745723, -0.10244372, -0.072981984 } }, { { 0.019363393, 5.327311e-05, 0.0075925373, 0.0019542034 }, { -0.051707557, 0.06554253, 0.0050626046, -0.0061857803 }, { 0.022891698, 0.014872273, -0.020436928, 0.0069081531 }, { -0.044566611, 0.019854557, 0.023600607, -0.0055387351 }, { 0.02283957, -0.067086756, 0.088865856, -0.033915007 }, { 0.0020254431, -0.16422426, 0.032495902, 0.012460808 }, { -0.017316175, 0.023440087, 0.011459595, 0.0043887872 }, { 0.027714908, -0.06907548, 0.013578806, -0.009848884 }, { 0.0044782488, 0.0079432606, 0.010143137, 0.023589488 }, { 0.014325082, 0.0075465848, -0.0079373813, -0.0056032635 }, { 0.025123579, 0.01904807, -0.0092328848, -0.019002052 }, { -0.02633985, -0.019560519, -0.065544737, 0.0073352606 }, { 0.044308433, -0.0032233834, 0.01324206, -0.00047128106 }, { -0.076577611, -0.021853603, -0.020190543, 0.0026420865 }, { -0.0029799448, -0.0083566545, 0.14896601, 0.0078617095 }, { 0.021033237, -0.08234711, -0.020642328, -0.0089829962 }, { 0.043793881, 0.0096494147, 0.035831274, -0.01294602 }, { -0.014064874, 0.066144489, 0.0143429, 0.015113964 }, { 0.043111732, 0.0029232804, -0.016912145, 0.012142059 }, { 0.0014186333, -0.0078590166, 0.065781153, -0.038375123 }, { 0.02255714, -0.030191796, -0.078373164, -0.0017593196 }, { -0.033878798, 0.016266579, 0.013539653, 0.043519216 }, { 0.019046482, 0.0080403173, -0.0010755939, 0.03305222 }, { 0.023206448, -0.054323067, -0.035173093, -0.010873592 } }, { { 0.014068291, -0.026418786, 0.016375695, 0.0048801469 }, { 0.024404214, 0.0073572002, -0.027247654, 0.00093849398 }, { 0.012741523, -0.012913063, 0.0054881373, -0.021780769 }, { -0.020497215, 0.057437717, 0.0031122704, 0.014713732 }, { 0.012765254, -0.052846334, 0.048042201, 0.0016578534 }, { 0.031245254, -0.0469321, -0.057199738, 0.012436479 }, { -0.0022837759, 0.0068501747, 0.010541107, -0.0005227683 }, { -0.0187059, 0.0025631581, -0.0082184266, 0.0026294483 }, { 0.0053899388, -0.0199458, 0.0023448066, 0.016215236 }, { 0.021117204, 0.010868775, -0.016412681, -0.016399297 }, { -0.0026199223, -0.011436548, 0.0031355049, 0.011933919 }, { 0.017940023, 0.090292392, -0.061029038, 0.016388845 }, { 0.0074493061, -0.045849358, -0.082612855, 0.025851315 }, { 0.061276666, -0.024654813, 0.035447334, -0.025952766 }, { -0.0068267167, -0.02207426, 0.003724368, 0.0070458116 }, { 0.021714649, -0.017552721, -0.037105408, 0.024398534 }, { 0.0092901891, -0.021559075, 0.009034776, -0.016574279 }, { -0.017218595, -0.041930302, 0.003369899, 0.017959363 }, { -0.0022510875, 0.028106616, -0.042936548, -0.041948028 }, { -0.017145551, -0.032331654, 0.021486923, -0.020295391 }, { -0.023196465, -0.088353584, 0.010086154, 0.018689553 }, { -0.024508386, -0.00058959302, -0.02867958, 0.019018994 }, { 0.0088748911, 0.012528454, -0.016636351, 0.0078166115 }, { 0.00066772723, 0.001693912, 0.032066885, 0.016951148 } } }, { { { 0.015200105, 0.071414961, -0.020616434, 0.0063982643 }, { -0.084578144, -0.12318522, -0.035470756, 0.057833574 }, { 0.19487946, 0.44043059, 0.10981527, -0.31907303 }, { -0.17774238, -0.30460726, -0.53133003, 0.31186606 }, { -0.1172677, 0.3183613, 0.10375266, -0.066515168 }, { 0.054176263, -0.12382077, -0.033807438, 0.039809238 }, { -5.3634009e-05, 0.004084452, 0.005103199, -0.060697866 }, { 0.06093199, 0.060355274, 0.049176467, -0.060579228 }, { 0.054611799, 9.0520863e-05, -0.048891261, -0.047609349 }, { -0.036428706, 0.06336736, 0.0020843807, 0.033254378 }, { 0.26975732, 0.51328693, 0.29976157, 0.049031141 }, { -0.28383516, -0.48219276, -0.27898799, -0.033028759 }, { -0.078976834, 0.14077934, 0.098587186, 0.051336328 }, { 0.076281206, -0.074223398, -0.053178835, -0.099578331 }, { -0.056377095, -0.00066113896, -0.11597726, 0.058805777 }, { -0.0027130032, 0.12007881, 0.0081935835, -0.10415807 }, { -0.019349408, 0.06206561, -0.0079099126, 0.079363093 }, { -0.059959607, -0.0591041, -0.047505451, -0.0031496967 }, { -0.11419194, 0.20904287, 0.53960104, 0.10467592 }, { -0.21312862, -0.34770872, -0.54593093, 0.23230512 }, { -0.073229448, 0.12913, 0.27728133, -0.050627706 }, { 0.082312471, -0.24529296, -0.12381516, 0.05577292 }, { 0.03015389, -0.0015805638, 0.024306632, -0.080697961 }, { 0.061367564, 0.056058289, 0.041197211, -0.015551356 } }, { { -0.029269776, -0.030251548, 0.01352869, 0.0084860712 }, { 0.053983187, 0.047657625, -0.026379004, 0.022474039 }, { 0.011898439, 0.045120742, -0.024430477, -0.081318878 }, { -0.0012641508, -0.018495044, -0.030127865, -0.0088483264 }, { 0.040728292, 0.010691761, -0.023566342, 0.028045232 }, { 0.014593998, 0.0047006468, -0.049032498, -0.011446808 }, { 0.00045433705, -0.0030610749, -0.010359449, -0.0026455857 }, { -0.0026794352, -0.032142744, 0.010153936, -0.0034586152 }, { 0.0097198782, 0.0051005644, 0.03482872, -0.0043676475 }, { -0.0012381415, -0.025746274, -0.0081178021, 0.0041481596 }, { -0.01598781, 0.0048815642, 0.06313106, -0.0062291669 }, { 0.072970618, -0.041153529, -0.007457013, 0.059776924 }, { 0.0024768493, 0.0093018711, 0.024827984, 0.043842172 }, { -0.012927661, -0.023256709, -0.0035951539, -0.069710027 }, { 0.0064149713, 0.0019783425, 0.010135188, 0.019449636 }, { -0.0071551675, 0.015761815, 0.0086309278, 0.038854386 }, { 0.020978109, -0.0056696814, 0.0025526797, -0.017352926 }, { -0.010711116, -0.0097050903, 0.0022304504, -0.0039308489 }, { 0.036904234, 0.025927127, 0.028330671, 0.051193417 }, { -0.00076391153, -0.077528792, -0.029763477, 0.0033945843 }, { -0.01775202, 0.034507636, 0.065392848, -0.017840909 }, { -0.019567742, -0.019880035, 0.055214211, -0.02206159 }, { 0.01110111, 0.0022938832, -0.011417507, 0.017692635 }, { 0.050208493, -0.028178909, 0.0065276591, -0.0056267473 } }, { { 0.0065622702, -0.0012303136, -0.0081183663, 0.00079383048 }, { 0.030775912, 0.052260356, -0.019758331, -0.020044147 }, { 0.019016537, -0.043070451, 0.035298744, -0.040592775 }, { 0.010468089, 0.00057085185, 0.0081761984, 0.0033382478 }, { 0.047189462, -0.052695409, 0.021849623, 0.033585939 }, { 0.0012065616, -0.050287476, -0.065085924, -0.039012886 }, { -0.012294892, 0.006839242, 0.0051165438, -2.0711078e-05 }, { -0.03292822, 0.015299577, 0.0029119931, 0.0073040242 }, { -0.0086784873, 0.0085910164, -0.0059378411, -0.010259049 }, { -0.014191355, -0.011172486, -0.01299927, 0.015386671 }, { 0.040453224, -0.041489173, 0.015047889, 0.064340197 }, { -0.020000046, 0.058477092, -0.0018150465, 0.048536972 }, { -0.006105982, 0.03437044, 0.0087640339, 0.032868283 }, { -0.027120362, 0.016579996, -0.01708524, 0.011178424 }, { 0.030535528, 0.0058718219, -0.031240404, 0.024241052 }, { 0.003729958, -0.055735848, -0.0055392842, 0.03447519 }, { -0.04084502, -0.01227488, 0.0062970198, -0.021996031 }, { 0.053671675, -0.067787009, 0.0053426012, -0.0080796738 }, { -0.021911856, 0.038395527, -0.07713235, 0.024805484 }, { -0.0034319194, 0.0052741327, 0.026402991, 0.0012916612 }, { -0.033119652, -0.0046506889, 0.045613946, -0.050230593 }, { -0.0054612035, -0.033482221, 0.084267507, -0.0224334 }, { -0.0063348693, -0.0074524817, -0.0029629355, 0.035493958 }, { -0.0073519185, 0.045139911, 0.0022901735, -0.041385515 } } }, { { { 0.99640669, 0.99424882, 0.99911727, 0.99864438 }, { 0.99146493, 0.99235134, 0.99369348, 0.99764995 }, { 0.95848895, 0.89778665, 0.9720248, 0.943828 }, { 0.95896077, 0.9472107, 0.83168251, 0.89623886 }, { 0.97975356, 0.94759472, 0.99452924, 0.98394744 }, { 0.98863213, 0.99196902, 0.99652121, 0.97785007 }, { 0.99999362, 0.99994883, 0.99498061, 0.99814861 }, { 0.99040248, 0.99816269, 0.99831309, 0.99630173 }, { 0.99848953, 0.99964658, 0.9959596, 0.99884607 }, { 0.9986735, 0.99651874, 0.99788899, 0.99869411 }, { 0.91299789, 0.85766372, 0.953946, 0.97631002 }, { 0.90471405, 0.87481454, 0.959534, 0.97684726 }, { 0.9884254, 0.96811612, 0.9914694, 0.98799879 }, { 0.99232241, 0.98122887, 0.99103524, 0.99426948 }, { 0.99840731, 0.99966074, 0.99324506, 0.98912879 }, { 0.99551377, 0.99274778, 0.99617307, 0.9927827 }, { 0.99830144, 0.99552039, 0.99521214, 0.99684577 }, { 0.99211525, 0.9978808, 0.99885333, 0.99969634 }, { 0.95579147, 0.95995838, 0.84120087, 0.96022443 }, { 0.90975235, 0.9368621, 0.81871367, 0.8156339 }, { 0.98610091, 0.99158952, 0.96035822, 0.97468107 }, { 0.98366238, 0.9531543, 0.99215501, 0.98230604 }, { 0.99953301, 0.9997136, 0.99888998, 0.99490315 }, { 0.99267663, 0.998401, 0.99388534, 0.99721201 } }, { { -0.0021537732, 0.010607958, -0.0066166595, -0.0027390442 }, { -0.0069401807, 0.0053215201, 0.0062121114, 0.013403291 }, { -0.0035740125, -0.021839368, 0.00042431197, -0.029478899 }, { -0.007886159, -0.0087705321, -0.010570968, 0.0040635318 }, { -0.0021772698, 0.00025306776, -0.0092725896, -0.0075657706 }, { -0.010438319, -0.0072866821, 0.009272756, 0.0043932916 }, { -0.00058203184, 0.0081284104, 0.027749999, 0.0035426599 }, { -0.003604276, -0.012244348, 0.0072177908, 0.0026686264 }, { 0.011192179, 0.0069527119, 0.017278396, -0.0053058312 }, { -0.020276487, -0.0063228657, 0.013968347, -0.0021534789 }, { -0.0037534313, 0.00061399133, -0.02126817, 0.0085256452 }, { 0.015620795, -0.022637876, 0.00069280338, 0.0054369037 }, { 0.0095244184, -0.0026896982, -0.0057963534, 0.0067237437 }, { -0.0085689961, -0.004816024, -0.00088793436, -0.0034021999 }, { 0.015428153, 0.019777562, -0.011217833, 0.0095744159 }, { -0.003802304, 0.0022643577, 0.0054254827, 0.025560756 }, { -0.0053298651, 0.021621993, -0.01864184, 0.019120967 }, { 0.015380344, -0.0027384467, 0.0010235928, 0.0062792725 }, { -0.001166873, -0.0049586656, -0.014850883, 0.00057841904 }, { 0.0032865456, -0.033386196, 0.0032068954, 0.02854738 }, { 0.010308266, -0.000233004, -0.020287643, 0.0044441043 }, { -0.0040523345, 0.0050367711, 0.01627907, -0.010032412 }, { 0.0073463987, 0.00073274858, 0.002814661, 0.030221018 }, { 0.0057509063, -0.011441338, 0.01894259, 0.0077856453 } }, { { -0.0053054924, 0.0037677068, 0.0066263851, 0.0011220287 }, { -0.02212139, 0.013769097, -0.0013834097, 0.014152363 }, { -0.0008493126, 0.021473024, -0.0039313241, -0.017764981 }, { -0.00081897848, -0.0074161164, 0.0038179092, -0.0035760615 }, { 0.014045643, 0.015317904, 0.0045966739, 0.0075917156 }, { 0.0035574126, -0.00017773424, -0.0010937491, -0.0017762282 }, { 0.0072018344, 0.012586227, 0.0138702, -0.0085424173 }, { -0.0055783456, -0.019909385, 0.01190919, -0.0065821489 }, { 1.7402026e-05, 0.0094513341, 0.015333305, -0.0072158969 }, { -0.0063049905, 0.0021776758, 0.014376378, 0.0072426401 }, { -0.0078049673, 0.028764242, -0.0024169449, 0.0077604105 }, { 0.00047536469, 0.029806623, 0.0017798261, 0.00087410198 }, { -0.0030498401, 0.0044874501, 0.0020382571, -0.0011101062 }, { -0.0057084397, -0.0013428994, -0.001024136, 0.0066188614 }, { 0.039201052, 0.015120258, -0.0082642793, 0.0051985023 }, { -0.0091203243, 0.020790215, 0.0025270937, 0.020092044 }, { -0.0029830063, 0.006602841, -0.00833601, 0.044852353 }, { 0.025206353, -0.0038915173, 0.00045914851, 0.0037840538 }, { 0.0014814254, -0.011573911, 0.046232337, -0.015228958 }, { -0.0071984443, 0.0090004063, 0.022942838, 0.016019787 }, { 0.0050929336, 0.0060892107, -0.0061771339, 0.0047850766 }, { -0.011634853, 0.0010276548, 0.022396644, -0.0021248711 }, { -0.012943002, 0.0016430074, 0.02034928, 0.024289705 }, { 0.0051047037, 0.010052556, 0.0020923265, -0.019043181 } } }, { { { 2.1627647, 2.1788232, 1.9290264, 1.8457806 }, { 2.526488, 2.3020441, 2.538915, 2.03484 }, { 3.9987521, 4.3952121, 3.906821, 4.1693278 }, { 4.0400466, 4.1069844, 5.2512999, 5.4283264 }, { 3.0141968, 3.3306035, 3.2224806, 3.2473051 }, { 2.9840674, 3.1294685, 3.2964833, 3.2929246 }, { 1.8346741, 1.8637353, 2.3037966, 2.0860888 }, { 2.691236, 2.6068079, 1.9349032, 2.1632935 }, { 1.9231956, 1.7251627, 2.1609654, 2.1155629 }, { 2.165771, 2.1908952, 1.777038, 2.0223741 }, { 4.5166991, 4.8674508, 3.918546, 3.378087 }, { 4.4502295, 4.5429338, 3.9552598, 3.3580272 }, { 3.0973598, 3.3953852, 2.2704362, 2.6488177 }, { 3.2110537, 3.3104376, 2.515002, 2.3267785 }, { 1.8303675, 1.7094345, 3.1787979, 2.5960104 }, { 2.4391795, 2.8730077, 2.3730261, 2.1545299 }, { 2.2130903, 2.1899209, 2.4997355, 1.9058674 }, { 2.6472893, 2.5455636, 2.1164596, 1.8341163 }, { 3.9428283, 4.0433678, 4.5430063, 4.2482776 }, { 4.1941673, 4.28852, 4.64044, 4.6644567 }, { 3.0873642, 2.649364, 3.6026133, 3.2426354 }, { 3.2415154, 3.5406745, 3.2976852, 3.3100246 }, { 1.8400289, 1.8404692, 1.889289, 2.0125184 }, { 2.7063995, 2.7229173, 2.6289878, 2.4313709 } }, { { -0.015335928, -0.043382119, -0.0054163805, -0.028249934 }, { -0.017200109, 0.0027582413, -0.079612821, -0.0013966663 }, { -0.027233584, -0.018783395, -0.01183278, -0.020918937 }, { -0.0036358348, -0.015712206, -0.0089146421, -0.0057117233 }, { 0.020392865, 0.017743746, -0.068597326, -0.030425581 }, { -0.041123673, -0.020767538, -0.0087941887, -0.0065248183 }, { -0.0055478408, -0.00082196865, 0.0088521402, -0.045916836 }, { -0.010506485, 0.0078523247, -0.030002306, -0.0015085765 }, { 0.01894068, -0.012424968, -0.034837214, -0.045009941 }, { -0.045299587, 0.02630478, -0.017175711, -0.043601235 }, { -0.046003661, -0.020588165, 0.034398873, -0.054653787 }, { -0.0042534368, 0.01325834, -0.0036369576, -0.079162988 }, { -0.028728556, 0.0051289128, 0.012104313, 0.010686997 }, { -0.066337767, 0.00059928728, -0.080303668, 0.011318772 }, { -0.031879871, 0.0011317962, -0.050259029, 0.0031596552 }, { -0.090121238, -0.011196084, -0.072456123, -0.00079731072 }, { -0.024243475, 0.021401076, -0.018209385, -0.0083196072 }, { -0.079888701, 0.0032806631, -0.12762259, -0.04652308 }, { 0.031806075, -0.034165157, -0.015255921, -0.049164663 }, { -0.0012051123, 0.030788487, 0.022291919, 0.0025694519 }, { 0.035836509, 0.0055365388, 0.026704836, 0.0001547235 }, { -0.012129747, -0.0094322145, -0.040637935, -0.12125388 }, { -0.027044986, 0.04531553, -0.033484589, -0.0059927923 }, { 0.0067188802, -0.051166351, -0.048822794, -0.025926988 } }, { { 0.022049053, 0.021265778, -0.040370641, -0.036232952 }, { -0.0058098424, -0.0042264198, -0.077428509, -0.04241654 }, { -0.0026825379, -0.029453318, -0.016181275, -0.028320229 }, { -0.012541692, -0.01345735, 0.00037814888, -0.0046052489 }, { -0.026527394, 0.020033638, -0.025683861, -0.084207169 }, { -0.0010459945, -0.036745215, -0.039772051, 0.024810839 }, { 0.012134618, 0.0068515798, -0.035286972, 0.043129595 }, { -0.077093357, -0.026872688, 0.032800133, -0.090326706 }, { 0.13930909, 0.0081274014, -0.08349188, -0.012200005 }, { -0.091693797, -0.012567011, -0.069736822, -0.0061444184 }, { -0.053061301, 0.003642159, 0.0052515175, -0.036957472 }, { 0.0043493933, -0.013069332, -0.014708126, -0.032765039 }, { -0.016116105, -0.022907609, -0.043503106, -0.013266465 }, { -0.072759977, -0.077354585, 0.0043827591, -0.013821612 }, { -0.032399073, -0.045305037, -0.021840791, 0.073996542 }, { -0.057239255, -0.056581235, -0.038880927, 0.044102943 }, { -0.026951489, -0.088667645, -0.013659704, 0.033527579 }, { 0.034815442, -0.028634059, -0.036666529, 0.011546036 }, { 0.026688447, -0.0081892129, -0.031138092, -0.041739155 }, { 0.0015665701, -0.012701682, 0.0013533943, -0.002849785 }, { 0.032994636, 0.008802974, 0.019032649, 0.0039042621 }, { -0.044544917, 0.0093201326, -0.017968915, 0.01936344 }, { -0.034794535, 0.043032983, -0.051072531, -0.040148303 }, { -0.0030398597, -0.027112065, -0.064007483, -0.01798277 } } }, { { { 0.22040906, 0.24911942, 0.41660708, 0.23632869 }, { 0.25894466, 0.1416669, 0.41902981, 0.35717608 }, { 0.26918091, 0.14566759, 0.2147652, 0.15769391 }, { 0.22500921, 0.12113361, 0.11151768, 0.12348609 }, { 0.25699055, 0.056819107, 0.3859882, 0.4585378 }, { 0.7304995, 0.20719358, 0.44455636, 0.42226989 }, { 0.43602897, 0.51049581, 0.41978824, 0.62521039 }, { 0.42004119, 0.52912054, 0.33314238, 0.38257921 }, { 0.55092562, 0.43085653, 0.31149977, 0.34391138 }, { 0.40391149, 0.48820255, 0.13569806, 0.36060266 }, { 0.13647907, 0.12061002, 0.20668806, 0.30221394 }, { 0.15583476, 0.13133696, 0.22775202, 0.35653823 }, { 0.56336195, 0.25684627, 0.11118383, 0.23109245 }, { 0.45430401, 0.42843367, 0.25496534, 0.097473509 }, { 0.3420223, 0.39418925, 0.26458947, 0.30588082 }, { 0.51345558, 0.3612731, 0.41151773, 0.25269512 }, { 0.29195176, 0.42659964, 0.47971993, 0.32714756 }, { 0.49222777, 0.28477645, 0.74993827, 0.43781271 }, { 0.098434481, 0.31164923, 0.14486345, 0.11466693 }, { 0.070833248, 0.20569754, 0.10233576, 0.047352701 }, { 0.51050902, 0.15597643, 0.1417112, 0.35581415 }, { 0.48261165, 0.14592221, 0.62554576, 0.5209765 }, { 0.33562628, 0.39920067, 0.28183433, 0.297464 }, { 0.366851, 0.59278666, 0.59095922, 0.48385165 } }, { { 0.13792051, 0.072076744, 0.094800532, 0.026318377 }, { 0.13607414, -0.061382542, 0.061800151, -0.020060553 }, { 0.028096406, 0.069282616, 0.010195109, -0.010461141 }, { 0.018651237, 0.02642439, 0.0077552848, -0.051151646 }, { 0.098299803, -0.0085081153, -0.011764584, 0.087405711 }, { 0.064082346, -0.04626424, -0.071480607, 0.064447268 }, { 0.022766233, 0.0167542, -0.021285286, -0.071637286 }, { -0.0202445, 0.011692601, 0.048325551, 0.0097755172 }, { -0.027775183, 0.016463115, 0.060050391, -0.034226107 }, { 0.019412547, 0.059977501, -0.0041737169, 0.031539317 }, { 0.013192979, 0.036015595, -0.049943198, 0.014112312 }, { -0.013272349, 0.035821037, -0.060503687, 0.095316821 }, { 0.038338785, -0.059038809, -0.044954172, -0.00051347307 }, { -0.039594082, 0.018205882, 0.13413799, 0.012292954 }, { 0.015177594, -0.0082493854, 0.00029420179, 0.010356248 }, { 0.100271, -0.13623174, 0.1121235, 0.068902399 }, { 0.025189636, 0.0014918434, 0.0088847718, -0.053714493 }, { 0.06487698, -0.097217547, -0.069537353, 0.032490984 }, { -0.030729608, 0.048956315, 0.016036034, 0.022485239 }, { 0.049839618, 0.01148525, -0.021032427, -0.019665817 }, { -0.0037762817, -0.030422275, -0.062343207, 0.057994884 }, { 0.014035184, -0.021387762, -0.080846143, -0.020681511 }, { -0.03594567, 0.026862531, 0.078975557, -0.034056659 }, { -0.014490672, 0.026128902, 0.045617611, 0.090192953 } }, { { 0.011904288, -0.014624471, 0.042023114, 0.019592867 }, { 0.032705848, 0.00038558691, 0.031901745, 0.027208951 }, { -0.044369719, -0.039761364, -0.013366816, -0.019308126 }, { -0.019051023, -0.00015767269, -0.082968285, -0.035266053 }, { -0.004775162, 0.010889271, 0.0089521094, 0.027037104 }, { 0.005616143, -0.00099668486, 0.0068716426, -0.12649184 }, { 0.018531199, 0.023881776, -0.053798787, -0.041912909 }, { -0.0036187094, 0.11590788, 0.025140733, 0.022280209 }, { -0.02994342, -0.026293799, -0.017204658, 0.044901944 }, { 0.079892089, 0.10816526, 0.14667807, 0.027301352 }, { -0.045296738, -0.066748968, -0.0099354431, -0.070369692 }, { -0.08357374, -0.043311901, 0.013163375, -0.0881777 }, { -0.065923811, -0.10382274, 0.090440302, -0.013617198 }, { -0.092578587, -0.010178017, -0.01416593, 0.0432333 }, { 0.055172515, 0.10021805, -0.0062782668, -0.11791805 }, { -0.039684132, -0.08934283, 0.020686084, -0.0013788117 }, { 0.064624676, 0.051773746, 0.0045383964, -0.037696971 }, { -0.066296373, 0.020570689, -0.017742721, -0.022651449 }, { -0.0061572447, -0.094510525, -0.094775804, -0.038022514 }, { 0.0055683313, 0.039513342, -0.096815654, -0.0065483011 }, { -0.03311602, -0.018395457, 0.0028464434, -0.088048272 }, { -0.073106109, -0.055187863, -0.093209932, -0.10155137 }, { 0.042841842, -0.005778703, 0.074069607, -0.025841052 }, { -0.018569637, 0.063144303, 0.02291584, 0.005525742 } } } }, { { { { -0.20809663, -0.18346453, -0.072140694, -0.0078104407 }, { -0.19490097, 0.25712922, 0.37640771, 0.11563399 }, { 0.26894915, -0.33477877, -0.093739129, -0.55078405 }, { -0.65794103, 0.09211629, -0.19166986, 0.5574327 }, { 0.45579532, 0.23202083, 0.19626303, -0.64130523 }, { -0.018763975, -0.24981569, -0.32514026, -0.11121342 }, { 0.22376238, 0.09515938, 0.071728264, -0.02790747 }, { -0.3053338, 0.34023365, 0.099862481, 0.26163964 }, { -0.21722968, -0.094881958, -0.086364431, -0.0081863581 }, { -0.16090709, 0.23527698, 0.28947119, 0.11309742 }, { 0.26447184, -0.33536416, -0.096418234, -0.26201294 }, { -0.56343769, -0.041662822, -0.24873841, 0.67122901 }, { 0.35362642, 0.2577592, 0.2009013, -0.74233681 }, { -0.047956299, -0.54973418, -0.4958485, -0.12453303 }, { 0.06917425, 0.080509853, 0.0090863722, -0.023518805 }, { -0.27000602, 0.083167162, 0.12715558, 0.12397839 }, { -0.11376964, -0.079199259, 0.019676685, -0.0094352472 }, { -0.19185851, 0.22193112, 0.28110877, -0.06422845 }, { 0.084091992, -0.16151548, 0.091400556, -0.28257376 }, { -0.53821376, 0.21718328, -0.2234907, 0.52302804 }, { 0.71322306, 0.042728493, 0.13229522, -0.61892094 }, { 0.15270046, -0.26304886, -0.33110633, -0.052728951 }, { 0.072398971, 0.25829764, 0.25881687, -0.020942042 }, { -0.26788161, 0.055822039, 0.33817103, 0.42061402 } }, { { 0.088248648, 0.091306255, 0.020476927, 0.0030144802 }, { 0.0087376707, 0.043816157, 0.0022807168, 0.016745414 }, { -0.13412414, 0.12686539, 0.060531476, 0.044582027 }, { 0.019204757, -0.0070891897, 0.091194602, 0.065258927 }, { -0.10429513, -0.027665602, -0.064350626, 0.0053147478 }, { 0.069218141, -0.035018324, -0.088257571, 0.019279642 }, { -0.073137338, 0.040764456, -0.022352804, 0.031743288 }, { 0.040325697, -0.12840825, -0.009582113, 0.034509657 }, { 0.081971224, -0.0035223125, -0.051728499, 0.0038899717 }, { 0.050968435, 0.022254651, 0.18781134, -0.032392139 }, { 0.024342518, 0.13929014, -0.019175435, -0.0011608234 }, { -0.0021942487, -0.01251222, 0.024263454, -0.063179344 }, { -0.13071776, -0.059221747, -0.034153238, 0.036561209 }, { 0.054124093, 0.070495803, 0.081441614, 0.051900357 }, { 0.027480327, 0.028940343, -0.01469313, 0.032388411 }, { -0.039696828, -0.0069393798, -0.011361641, 0.035031025 }, { -0.039730763, 0.0085971581, -0.0077461932, -0.040735188 }, { 0.10893368, 0.00014757217, 0.025489178, -0.11388774 }, { -0.0013816669, 0.0031148929, 0.10281666, -0.019860642 }, { -0.065093128, -0.11495815, 0.041783056, -0.091373461 }, { -0.044985581, 0.0012713031, -0.16078032, 0.17303747 }, { -0.038132358, -0.02995975, -0.037612782, 0.012575173 }, { 0.0042976619, 0.027014275, 0.017518808, 0.030405184 }, { -0.0015298607, 0.029297664, -0.1034349, 0.023450502 } }, { { 0.028785558, -0.028708377, -0.010459636, 2.8360915e-05 }, { 0.091634877, 0.021214811, 0.12282079, 0.080617943 }, { -0.29287977, 0.045481846, 0.014712563, 0.057317576 }, { -0.10728772, 0.03268482, 0.015167285, -0.011256231 }, { 0.09337321, 0.037150859, 0.052549202, -0.042671474 }, { -0.0041288689, -0.024299997, -0.11357403, -0.022045772 }, { -0.041469935, -0.0071353646, -0.0086607538, 0.008536762 }, { 0.033629272, -0.0070042955, -0.037864853, -0.0055907778 }, { 0.016404597, -0.0055321059, -0.020989839, -0.013771265 }, { 0.042552435, 0.04428518, 0.0030587466, 0.044894182 }, { -0.027600219, 0.026831779, 0.051120849, -0.032184808 }, { 0.13870554, 0.15273282, 0.049260112, 0.043371121 }, { -0.018453269, -0.18061413, 0.24805649, -0.031741165 }, { -0.085137374, 0.025935867, 0.015978067, 0.067726486 }, { 0.072393868, 0.0050430488, 0.0016664585, 0.0072097064 }, { 0.033840162, 0.082225764, -0.079387016, 0.033165625 }, { 0.033170766, 0.0012231618, -0.066984982, 0.051671704 }, { 0.017894231, -0.012267532, 0.045536123, -0.07327109 }, { 0.0073109731, -0.063797898, -0.13446413, 0.1408986 }, { -0.045702456, -0.1647051, -0.14336468, 0.054543693 }, { 0.0042448876, -0.13234456, 0.092181719, -0.10440841 }, { -0.060020212, -0.011098469, -0.030257182, -0.030922037 }, { -0.018118661, 0.00067983745, -0.0061776598, -0.031721273 }, { -0.019885189, 0.094157888, 0.014017961, -0.051373389 } } }, { { { 0.12415319, -0.13611564, -0.029441661, -0.14143497 }, { -0.26074418, 0.011913326, -0.033328425, 0.43248793 }, { 0.19336432, 0.37269586, 0.36803538, -0.51720719 }, { -0.15185913, -0.47431781, -0.6593667, 0.23163184 }, { 0.18276216, 0.19248743, 0.65453332, 0.54748087 }, { 0.17751443, -0.0020337696, 0.08506463, -0.40147769 }, { -0.11370932, 0.11523476, -0.010573025, 0.082295392 }, { -0.13666335, -0.32747478, -0.16897386, 0.15359006 }, { 0.11716326, -0.12259922, 0.0033396256, -0.13240653 }, { -0.27776876, -0.10222241, -0.039920479, 0.35499708 }, { 0.090003723, 0.3313923, 0.1871549, 0.003163675 }, { -0.51626118, -0.76341562, -0.56326874, 0.20153559 }, { -0.34172723, 0.26975563, 0.67520079, -0.1252004 }, { 0.45758078, -0.19142179, 0.064180031, -0.48748431 }, { -0.12800789, 0.1399912, 0.0077954775, 0.14379741 }, { -0.13042104, -0.45670817, -0.18831095, 0.0032738639 }, { 0.12446807, -0.11504524, -0.027331682, 0.03861758 }, { -0.31337986, -0.11842668, 0.033415325, 0.45344231 }, { 0.11463107, 0.077427841, 0.060880794, -0.069619455 }, { -0.37772106, -0.59628905, -0.65426572, 0.065297039 }, { 0.29532991, 0.75920243, 0.53294265, -0.15002562 }, { 0.3618333, 0.10488387, 0.36007528, -0.30963565 }, { -0.13738196, 0.20795596, 0.029274703, 0.18017599 }, { -0.10290023, -0.48517535, -0.33278584, 0.56477854 } }, { { -0.0047891472, 0.024629901, 0.015256654, -0.0084462001 }, { 0.056227746, -0.048057782, -0.15671312, 0.06418471 }, { -0.070093217, -0.018057199, 0.062026545, -0.051053726 }, { -0.0091221476, 0.0020547295, -0.087729813, -0.10164738 }, { 0.098917091, -0.066835916, 0.083151519, 0.006342544 }, { 0.0013540606, 0.038719082, 0.036333261, -0.053178668 }, { 0.0083787438, 0.0028359378, 0.0089872852, 0.031308249 }, { 0.014379686, -0.079563474, -0.079160006, -0.016352226 }, { 0.0091376645, -0.016678006, -0.044636785, -0.0011035265 }, { 0.0099146109, 0.027589302, -0.09494437, 0.07451767 }, { 0.017453983, 0.080674871, 0.06341808, 0.048820473 }, { 0.02794057, 0.058230195, -0.010793601, 0.091813872 }, { -0.049633232, -0.1142016, 0.036984283, 0.0034294865 }, { 0.047712957, 0.10161366, 0.13774722, 0.039503136 }, { 0.014194782, -0.014555183, -0.00053182909, 0.0019143477 }, { 0.0014900262, 0.0056176356, -0.034517871, -0.0010707988 }, { 0.013287784, -0.0073967933, -0.019271341, 0.016354896 }, { -0.10345626, 0.023536634, 0.027943639, -0.015686972 }, { -0.025193395, -0.10224801, 0.078686884, -0.048574399 }, { 0.15797878, -0.0012322757, -0.036096649, -0.23983963 }, { -0.10455507, -0.056368102, -0.06570944, 0.29104616 }, { 0.05155239, -0.040940824, -0.038367594, 0.058174485 }, { 0.010471732, -0.066952904, -0.047763843, -0.021124742 }, { -0.033555686, 0.0049111983, -0.026592789, 0.014438586 } }, { { -0.0048440946, 0.025915095, -0.018325403, 0.022133613 }, { 0.059240081, -0.031272176, -0.12967647, -0.17957913 }, { 0.0574837, 0.067005152, 0.024644254, 0.10786296 }, { 0.067084865, 0.008513386, 0.04077659, 0.10587924 }, { 0.026332643, 0.1072618, -0.098375042, -0.001724609 }, { -0.021386362, -0.0020174921, 0.16800158, 0.081359882 }, { -0.018204146, -0.026432136, -0.0068153455, -0.029997667 }, { -0.043221501, -0.016869967, -0.067406967, -0.024965804 }, { -0.0033879999, 0.031310818, -0.010853802, 0.00088944004 }, { -0.068991006, 0.087874253, -0.15737392, -0.088870044 }, { 0.061763806, -0.00072874343, -0.009915009, -0.0178225 }, { -0.07340717, 0.080339271, -0.0027124572, -0.13078641 }, { -0.023682834, 0.16512313, -0.15784472, 0.047978827 }, { 0.0063250439, -0.09953777, 0.094180888, 0.010565041 }, { 0.010047311, -0.042999009, -0.012483998, -0.016966759 }, { -0.048612679, 0.051708319, 0.015059148, 0.0036776472 }, { -0.011737015, -0.0027276603, 0.026535075, -0.065453876 }, { 0.056388137, 0.061461073, -0.12726984, -0.025578248 }, { 0.0016833003, 0.10878558, 0.13254828, -0.017098914 }, { -0.031606282, -0.072245098, 0.12724789, -0.21852899 }, { -0.062502612, -0.073402771, -0.049624729, 0.069066032 }, { -0.075837195, -0.10297347, -0.07249237, -0.11538062 }, { -0.015644005, 0.039474396, 0.074415075, -0.038881161 }, { -0.040175911, 0.034030267, 0.03947059, 0.014167463 } } }, { { { 0.97019677, 0.97355703, 0.99695983, 0.98991674 }, { 0.94552952, 0.96630359, 0.92585444, 0.89419404 }, { 0.9435447, 0.86545998, 0.92507456, 0.65508294 }, { 0.73759908, 0.87552111, 0.72697883, 0.79725496 }, { 0.87111918, 0.95347518, 0.73011435, 0.53758004 }, { 0.9839393, 0.96829127, 0.94183216, 0.90909143 }, { 0.96798791, 0.98876976, 0.99736817, 0.99621717 }, { 0.9423876, 0.88147679, 0.98054848, 0.95286662 }, { 0.96906348, 0.98791034, 0.99625801, 0.99116169 }, { 0.94707625, 0.9665378, 0.9563539, 0.9280011 }, { 0.96018435, 0.88187869, 0.97758711, 0.96505917 }, { 0.64499021, 0.64456248, 0.78794513, 0.71332673 }, { 0.87073007, 0.92778882, 0.70974824, 0.65822558 }, { 0.88787388, 0.81311133, 0.86603417, 0.86420517 }, { 0.98935782, 0.98687417, 0.99992833, 0.98932764 }, { 0.95398485, 0.88572054, 0.97384313, 0.99227952 }, { 0.98567955, 0.99019799, 0.99943274, 0.99920952 }, { 0.93004482, 0.96784384, 0.95909399, 0.88896838 }, { 0.98984254, 0.98382807, 0.99395144, 0.95671584 }, { 0.75342733, 0.77283296, 0.72248756, 0.84981055 }, { 0.63568318, 0.6494505, 0.83574524, 0.77099234 }, { 0.91965169, 0.95906448, 0.87218942, 0.94939213 }, { 0.98786871, 0.94341754, 0.96548269, 0.98341143 }, { 0.95794101, 0.87263324, 0.8802806, 0.71000638 } }, { { -0.0064390277, 0.051629953, -0.011423447, 0.032337826 }, { 0.055030538, 0.061305324, -0.016012659, 0.083766345 }, { 0.052467122, 0.018425134, -0.00054737782, 0.048038459 }, { 0.076436505, 0.016815709, -0.024174832, -0.00829119 }, { 0.057903371, 0.068822104, -0.0064003131, 0.00010695928 }, { 0.067104151, 0.067284611, 0.0074295447, 0.024215238 }, { 0.073380541, 0.01486405, 0.01523157, 0.012966612 }, { -0.0002536971, 0.010628632, 0.00045031869, 0.041891438 }, { 0.055922922, 0.0090823157, 0.011101162, 0.033807592 }, { -0.040264953, 0.022318628, -0.013682045, -0.016112502 }, { -0.034286564, 4.7089727e-05, -0.013030079, -0.012231424 }, { 0.027756308, 0.084041595, 0.018308393, 0.11564334 }, { 0.0026690817, 0.058149333, -0.013682964, 0.052975934 }, { -0.03852481, 0.063493354, 0.059460027, 0.047740976 }, { 0.026410264, -0.0073902435, 0.022353771, 0.012987341 }, { 0.035217135, -0.0023455309, -0.0055505614, 0.010102857 }, { 0.00075590283, 0.038624793, -0.0040614962, 0.070039437 }, { -0.02318411, 0.04527054, 0.013119286, 0.025335215 }, { 0.021268391, 0.044855911, 0.012622905, 0.04827088 }, { -0.0046678346, -0.01934799, 0.018393432, 0.09750434 }, { 0.12480373, 0.059151139, 0.055196092, 0.26701338 }, { -0.0096669036, 0.065624767, 0.016918517, 0.028425135 }, { 0.026488514, -0.0037618693, 0.0077028717, 0.041713399 }, { 0.018628451, 0.033145064, 0.029067918, -0.000924258 } }, { { -0.043525781, 0.028119778, -0.011653105, -0.020930158 }, { -0.028099186, 0.017594088, -0.099226445, 0.10408808 }, { 0.11750066, -0.0010629746, 0.018381448, 0.096538552 }, { 0.0010069446, 0.013799541, 0.1325137, 0.020820734 }, { -0.053571928, -0.0066793785, 0.14596488, -0.03272949 }, { 0.028507895, 0.015474376, -0.025411653, 0.037264272 }, { 0.033698911, 0.018088387, 0.0038898537, 0.03163178 }, { 0.0057766828, 0.015879322, 0.012557033, 0.071771631 }, { -0.0044521866, 0.0083963511, -0.0020426175, 0.023784146 }, { -0.011508765, 0.0075020051, 0.0018808294, 0.040843424 }, { 0.0085150894, 0.0056891711, 0.010134672, 0.046224768 }, { 0.040825446, 0.10099754, 0.021853299, 0.024507528 }, { -0.0055958303, -0.0060958, 0.1115321, -0.021701014 }, { 0.010487817, -0.010033143, -0.031203025, 0.054265436 }, { 0.0040500672, 0.0053935875, 0.018233022, 0.018797311 }, { 0.064057639, 0.014318185, 0.0199119, 0.014366235 }, { 0.02411682, 0.045454692, 0.0030084434, 0.019464939 }, { 0.012500289, 0.027734846, 0.0025097372, 0.047343669 }, { 0.037625829, -0.00064472688, 0.0557556, 0.04785655 }, { 0.0020433437, 0.019929208, 0.087936103, -0.036738471 }, { 0.020811556, 0.0915387, 0.055445303, -0.065132763 }, { 0.03911814, 0.043721622, 0.0074336204, -0.031370424 }, { 0.014072509, -0.014795458, 0.010517063, 0.022409628 }, { -0.0054107234, 0.055313602, 0.053556404, 0.048574319 } } }, { { { 3.4224197, 3.3162336, 3.1136621, 3.3189801 }, { 4.0715355, 3.5614196, 4.1797877, 4.0959601 }, { 4.3979407, 4.1858272, 4.3116447, 4.5467451 }, { 4.4920032, 4.0716439, 4.6107962, 4.5268016 }, { 5.6570832, 4.9036495, 4.7373547, 4.7259419 }, { 3.3277827, 3.6015237, 4.226646, 3.7939772 }, { 3.4893058, 3.3260638, 3.0626103, 3.1798705 }, { 3.6423735, 4.1092281, 3.3264203, 3.7325301 }, { 3.4756581, 3.2550256, 3.224671, 3.4093307 }, { 3.8511362, 3.4821381, 4.3232597, 3.7357164 }, { 3.6688024, 4.0797971, 3.4140927, 3.6881261 }, { 4.5298469, 4.7472506, 4.4046473, 4.7279944 }, { 4.1614448, 4.1242955, 4.6741969, 5.0037875 }, { 4.3148703, 4.3815566, 4.1976536, 3.9032858 }, { 3.2640506, 3.3214728, 2.9463564, 3.3562068 }, { 3.6729325, 3.9218642, 3.4550701, 3.4833871 }, { 3.435975, 3.3079446, 3.3432341, 3.3632985 }, { 3.8404619, 3.4716915, 3.858149, 3.8677391 }, { 3.3181827, 3.8403872, 4.0363918, 3.9604287 }, { 5.0916792, 5.2773748, 4.5404255, 4.377031 }, { 4.6514614, 4.7569957, 4.1233238, 4.4022582 }, { 3.6884833, 3.6283543, 4.1874612, 4.2963913 }, { 3.456705, 3.6250566, 3.5292789, 3.1420033 }, { 3.5986317, 4.0596074, 4.0696874, 4.5327067 } }, { { -0.12592901, -0.14780788, -0.11051274, -0.18767653 }, { -0.020435093, 0.0055221209, -0.021183195, -0.15159792 }, { 0.022498629, -0.025100789, -0.30939177, 0.016420202 }, { 0.21296442, -0.042976575, 0.082118132, 0.14574735 }, { -0.13608022, 0.16141834, -0.015091164, 0.044951541 }, { -0.08235774, -0.10333151, 0.089785432, -0.036620639 }, { -0.17664465, -0.015842477, -0.083075331, -0.15660828 }, { -0.11292423, -0.072894494, -0.068901923, -0.2283674 }, { -0.19063437, -0.071954393, 0.091375283, -0.26993547 }, { 0.042798331, -0.06495575, 0.050221766, 0.024602586 }, { -0.026228614, 0.0049810367, 0.046584088, -0.13067577 }, { 0.072779737, -0.023369437, -0.030275791, 0.19591126 }, { -0.018649072, 0.029208952, 0.012033439, 0.00094798196 }, { -0.094599446, 0.0070746366, -0.0007115864, -0.040175552 }, { -0.027599009, -0.068747365, 0.19480498, -0.19423733 }, { -0.076671551, 0.0075475135, 0.019853903, -0.012984601 }, { 0.064371855, -0.24044027, -0.043765356, 0.0016424127 }, { -0.076744435, 0.035881398, 0.12967612, 0.081825243 }, { -0.15224256, 0.032665115, -0.027927205, 0.076091133 }, { -0.0057973613, -0.14914213, -0.047678749, -0.037214457 }, { 0.10060085, -0.099197666, -0.22704457, -0.0020812401 }, { -0.070664558, -0.13179176, -0.014217065, -0.030410253 }, { -0.12286487, -0.046623366, -0.10695394, -0.0081383175 }, { -0.14561788, 0.02765909, 0.10439783, 0.033139041 } }, { { 0.0063171031, -0.0047223477, -0.056312039, -0.065065766 }, { -0.0059575982, -0.062348475, 0.069540315, -0.090331962 }, { 0.10218203, 0.050383376, -0.0089914697, -0.037837343 }, { -0.0037657879, 0.18278082, 0.079014627, -0.052587294 }, { -0.33929282, 0.018522098, 0.0078923893, 0.042545349 }, { 0.027294929, -0.086490439, -0.0057363347, -0.035932082 }, { -0.061716003, -0.14470599, 0.033117786, -0.08112808 }, { 0.16414856, 0.082471596, -0.058497326, 0.050552718 }, { -0.07627083, -0.0064181717, -0.031179581, -0.075705068 }, { -0.057808009, -0.00074561624, -0.23990956, 0.018671772 }, { 0.1677602, 0.10757253, 0.028015134, -0.23923178 }, { 0.078827365, 0.068682485, 0.056277532, -0.069749241 }, { 0.079502977, 0.05526585, 0.0089767144, -0.15319341 }, { -0.038594242, -0.055488998, -0.043132461, 0.054313031 }, { 0.12890592, -0.082639555, 0.22520491, -0.026781096 }, { -0.071292391, 0.064592881, -0.050368563, -0.072488866 }, { 0.092998671, 0.12152394, 0.033318795, -0.039691417 }, { -0.0049706273, -0.0014175115, -0.11634604, 0.15219284 }, { -0.012414906, 0.035583927, -0.072463074, -0.058394705 }, { -0.071558898, -0.00093653835, 0.013149622, 0.01495775 }, { -0.057103279, 0.013702583, -0.020242751, 0.04649072 }, { -0.083398977, -0.20123674, 0.062758815, -0.043671819 }, { 0.084479675, 0.17868517, -0.021185269, 0.15711776 }, { 0.11862504, 0.079985297, 0.063556911, 0.14639069 } } }, { { { 0.48018566, 0.17712962, 0.45065949, 0.76214707 }, { 0.37788335, 0.385421, 0.24766167, 0.3647243 }, { 0.45095873, 0.2634498, 0.37824131, 0.10713483 }, { 0.18808611, 0.27852978, 0.23671202, 0.23174978 }, { 0.39404781, -0.7399413, 0.28511918, 0.026007027 }, { 0.46587668, 0.46802177, 0.36697974, 0.23706778 }, { 0.48925391, 0.42086488, 0.49570155, 0.45137287 }, { 0.30655255, 0.35196398, 0.23019387, 0.50586011 }, { 0.45798975, 0.34137244, 0.33289763, 0.54218519 }, { 0.42271216, 0.38700914, 0.48791862, 0.15025833 }, { 0.7282781, 0.37956244, 0.25156645, 0.51632504 }, { 0.084933462, 0.15576738, 0.16469359, 0.29684651 }, { 0.34570877, 0.34912791, 0.26663435, 0.11188061 }, { 0.48552914, 0.19012867, 0.12677402, 0.1234341 }, { 0.2190939, 0.41431469, 0.64823269, 0.51846746 }, { 0.49289149, 0.29829354, 0.29090992, 0.36465152 }, { 0.50568056, 0.64150077, 0.40217634, 0.53523743 }, { 0.24945735, 0.47058801, 0.29099852, 0.25452114 }, { 0.49039753, 0.26327736, 0.39431507, 0.50632023 }, { 0.19678915, 0.031547614, 0.22295107, 0.26300048 }, { 0.12409997, 0.11506147, 0.19327618, 0.2174585 }, { 0.15319333, 0.39177705, 0.38498586, 0.25972804 }, { 0.69027161, 0.37279682, 0.31143504, 0.23440833 }, { 0.39682066, 0.3156927, 0.36369313, 0.14308402 } }, { { 0.15030994, 0.15410005, 0.0072554408, -0.22242826 }, { -0.032421729, 0.22531436, 0.22185899, -0.022703209 }, { 0.070341052, 0.30237173, 0.047916387, 0.03629681 }, { -0.024283222, 0.075614195, 0.013940033, -0.016841468 }, { 0.077729482, 0.19455394, -0.02162282, -0.018761003 }, { -0.22986895, 0.18914992, 0.14483608, 0.11173921 }, { 0.14132894, -0.0081864768, -0.11405791, 0.031777789 }, { 0.38775389, 0.0085565642, -0.057167843, 0.09784167 }, { 0.079102739, 0.030530894, 0.041954967, 0.02957611 }, { 0.076915126, 0.18656729, 0.044218872, 0.22478833 }, { 0.017173879, 0.11961351, -0.085099523, 0.22720323 }, { 0.030466202, 0.095221887, -0.042982583, -0.069264747 }, { 0.041170442, -0.090598444, -0.021082598, -0.028016784 }, { -0.082581617, -0.023712106, 0.32427665, 0.1010696 }, { 0.19197752, 0.10900527, -0.0053794951, 0.068553764 }, { 0.18674269, 0.028895321, -0.053421028, 0.063918058 }, { 0.044090722, -0.054247791, 0.05585954, -0.13406746 }, { 0.08358642, -0.032301886, 0.010371619, 0.099505528 }, { 0.16467816, 0.044994571, -0.0045949279, 0.0626774 }, { 0.12942209, 0.092097891, 0.019866495, 0.10340014 }, { 0.037094903, 0.13829877, 0.15116473, -0.048632499 }, { 0.10749044, 0.14329542, -0.061272024, -0.1536028 }, { 0.097716907, 0.044246181, 0.056664419, 0.15804873 }, { 0.031819999, 0.10132976, 0.079198524, 0.017871462 } }, { { 0.056219172, 0.08683492, -0.061488015, 0.065746152 }, { 0.088983664, 0.19773741, -0.096766599, 0.16352101 }, { -0.0097043787, -0.040925999, 0.097458334, 0.032319634 }, { -0.024873518, 0.057873123, -0.0059256291, -0.057498398 }, { -0.13355098, 0.39190863, 0.017449142, -0.0076009344 }, { 0.10319658, 0.22069551, -0.098795717, 0.10603434 }, { 0.090765308, 0.13803326, -0.070647945, 0.14557561 }, { -0.068457348, 0.058955208, -0.050501105, 0.02914144 }, { 0.10363866, 0.060231993, 0.027681685, 0.079659088 }, { 0.01269983, 0.11977996, -0.049648315, 0.089882363 }, { -0.072877286, 0.019348792, 0.13977764, 0.055396044 }, { 0.028834456, -0.1084196, -0.0043985215, -0.072640844 }, { -0.040232522, 0.051835989, -0.02198193, 0.016421295 }, { -0.087848469, -0.04621504, 0.099259188, -0.0025909067 }, { 0.3000131, 0.10526775, 0.016890366, 0.12892588 }, { -0.021028821, -0.024429075, 0.088067677, -0.084594075 }, { 0.086861805, -0.045902006, 0.0058222123, -0.0075466204 }, { 0.14411905, 0.036488937, 0.05091815, 0.16385101 }, { 0.1576814, 0.043890956, -0.064244298, -0.087234754 }, { -0.071100004, 0.16782304, -0.10860149, -0.1601076 }, { 0.032634641, -0.0025068263, -0.093802703, -0.076176546 }, { 0.1121451, 0.15584236, 0.070074778, 0.083736091 }, { 0.16981897, -0.078106227, 0.12480295, -0.0056807652 }, { -0.20300117, -0.017467249, 0.035504155, 0.056546123 } } } }, { { { { 0.014994926, 0.3118252, 0.12179235, -0.2013765 }, { -0.2622824, 0.28086607, 0.018805882, 0.72058929 }, { -0.0081002049, -0.28176506, -0.592214, -0.15032918 }, { 0.18913426, -0.24000825, 0.0020279072, -0.54749128 }, { 0.010237954, 0.76905205, 0.80173664, -0.016024595 }, { -0.53448318, 0.31204229, -0.16183732, 0.76857439 }, { -0.57639279, -0.63719194, -0.71354849, 0.56346054 }, { 0.49443258, 0.15067585, 0.31864726, -0.30570933 }, { -0.20756322, 0.2544828, -0.005298245, 0.0073796841 }, { -0.61822672, 0.21508574, 0.6362534, 0.30433278 }, { -0.0050327191, -0.278054, -0.3460806, 0.29967778 }, { 0.33983098, -0.11715664, -0.21761592, -0.068273894 }, { 0.5550354, 0.44369709, 0.64019993, -0.026032291 }, { -0.72587268, -0.33528197, -0.33592445, 0.53027141 }, { -0.47623191, -0.61767624, -0.61525655, 0.37823554 }, { 0.82869964, 0.219401, -0.018181789, -0.56937955 }, { -0.051792934, 0.3461701, 0.20915925, 0.078166496 }, { -0.26705611, 0.14439061, 0.0055054648, 0.463243 }, { -0.0019649711, -0.34119962, -0.29306531, -0.040223173 }, { 0.29285811, -0.32824753, -0.24768208, -0.29676955 }, { 0.87604898, 0.25374435, 0.2341931, -0.77851996 }, { -0.80404697, 0.011122158, 0.18899178, 0.55592668 }, { -0.78397618, -0.53690406, -0.59931185, 0.62348293 }, { 0.54613799, 0.080819658, 0.12590931, -0.60614071 } }, { { -0.12307869, -0.20242175, 0.21530167, -0.15608553 }, { 0.00052208688, 0.09998365, -0.067550225, -0.14009319 }, { 0.12621699, -0.089024022, 0.022656689, 0.18947331 }, { 0.34838897, -0.04936051, 0.25527451, -0.18942819 }, { 0.013210249, -0.043957685, -0.19088103, -0.034189573 }, { -0.0027790938, -0.026595097, 0.087083287, -0.12513839 }, { -0.038231564, 0.013328425, -0.0091503894, -0.005743873 }, { 0.17205702, -0.14956835, -0.0088915291, 0.18720588 }, { -0.049670195, 0.39532325, 0.080260299, 0.01811245 }, { 0.043555003, -0.30289197, -0.50878196, 0.27306166 }, { 0.02555972, -0.0068359476, 0.061097702, -0.43822038 }, { -0.10926471, 0.1870906, 0.12419548, 0.1245213 }, { -0.012443149, 0.040036941, 0.18601483, 0.02310445 }, { -0.10442982, 0.057455632, 0.13475314, -0.0019859122 }, { -0.068181593, -0.0033655904, 0.01922998, -0.020393828 }, { -0.10660626, 0.0020812455, 0.081209707, 0.077131932 }, { 0.088733212, -0.10430986, 0.45554817, -0.17113078 }, { 0.0046831409, 0.13247549, -0.1077727, 0.15382275 }, { 0.022346595, 0.022924261, -0.35016323, 0.2437608 }, { 0.029795657, 0.23046877, -0.020493651, -0.33214749 }, { -0.016101582, 0.042296203, 0.046779444, 0.037412394 }, { -0.02214903, -0.025218605, 0.14797485, -0.051723623 }, { 0.021321783, 0.010405115, 0.0075476201, 0.0082410917 }, { 0.040559796, 0.027927916, -0.012812736, -0.0096642379 } }, { { -0.055647079, 0.017595207, 0.34495838, -0.03055759 }, { -0.058415094, 0.027416036, 0.18568916, 0.13044498 }, { 0.01482217, -0.17300703, 0.027540135, -0.2744944 }, { 0.25558424, -0.15324455, -0.29751197, -0.11422984 }, { -0.068936732, -0.11425403, 0.094767025, -0.0020892558 }, { 0.040887892, 0.031622148, -0.095292456, -0.02460001 }, { -0.0026237665, 0.017734103, 0.01213911, 0.0056586962 }, { -0.052138375, 0.052245567, 0.04608449, -0.043004468 }, { -0.17693366, 0.0021023738, 0.13167397, -0.14062006 }, { -0.20900333, 0.0057695127, 0.13057243, 0.046715668 }, { -0.020569928, -0.08439655, -0.09683347, 0.038139385 }, { 0.18196242, 0.44461908, -0.11388512, -0.12413082 }, { 0.072801844, -0.0017236427, -0.0026756083, 0.049805114 }, { -0.092195952, -0.0076195172, -0.22763849, -0.11320887 }, { 0.016234922, 0.007258942, 0.078535592, -0.084829275 }, { -0.15320003, 0.057490618, -0.16065455, -0.17063675 }, { -0.012856124, 0.024818957, 0.097529739, 0.11569844 }, { -0.11141243, 0.26677735, 0.1319403, -0.15699502 }, { -0.021128161, -0.12370585, 0.056198856, -0.1836225 }, { -0.01871806, 0.025525037, 0.063822152, 0.066517944 }, { -0.013759301, 0.11401068, -0.04701374, -0.021321516 }, { 0.032714649, -3.161284e-06, 0.026930697, 0.00019593482 }, { 0.10575127, 0.016956425, 0.016873291, 0.0049304377 }, { -0.11938883, 0.31242334, 0.29347156, -0.19514533 } } }, { { { -0.17374661, -0.028781395, -0.25993234, 0.27242277 }, { -0.13675759, -0.62291002, -0.80742781, 0.54260546 }, { 0.16876581, -0.052588487, 0.22415557, -0.59669887 }, { 0.1769234, 0.64210979, 0.81157479, -0.2718564 }, { -0.99873125, -0.013258174, 0.58939675, 0.99930085 }, { -0.30883355, -0.71116337, -0.76218623, 0.096388818 }, { 0.65749012, -0.54533843, -0.57508599, -0.70359398 }, { -0.27406769, 0.61006308, 0.1873512, 0.2563151 }, { -0.78453523, -0.13585943, -0.048534939, 0.02085237 }, { 0.40938527, -0.76981396, -0.42506866, 0.22362984 }, { 0.29003079, -0.20624421, 0.1151133, -0.50558933 }, { 0.0070051806, 0.20763719, 0.59485798, -0.61562639 }, { -0.4371111, 0.48314196, 0.72981069, 0.99889301 }, { 0.58257878, -0.8603979, -0.94188892, -0.83140889 }, { 0.71858167, -0.49534538, -0.63421799, -0.84488463 }, { 0.016158248, 0.65330502, 0.82883727, -0.127372 }, { -0.50292264, -0.14848746, -0.20836533, 0.2471481 }, { -0.15815031, -0.63472031, -0.79826416, 0.15325573 }, { -0.010424343, -0.022843894, 0.099730136, -0.26040744 }, { 0.15069433, 0.31188588, 0.63836617, -0.25234477 }, { -0.36946506, 0.92093529, 0.96548808, 0.62354203 }, { -0.57070465, -0.99847512, -0.47855156, -0.079970605 }, { 0.077467525, -0.71134336, -0.67172579, -0.66364974 }, { -0.27299386, 0.89512951, 0.61598356, 0.49577277 } }, { { 0.070458859, -0.28774455, 0.21287043, -0.094689772 }, { 0.0029548085, -0.31404605, -0.039280892, -0.3652277 }, { -0.033729607, 0.041215792, 0.065844258, -0.21509418 }, { 0.39270582, 0.067526811, 0.15655351, 0.053346856 }, { 0.052704394, -0.087801294, 0.18655104, 0.056114808 }, { -0.074582751, -0.055177669, -0.22165519, 0.13272162 }, { -0.027850171, 0.0029849066, -0.0062314784, -0.010484316 }, { 0.20753796, -0.0087111988, -0.13875075, -0.06137521 }, { 0.089744421, 0.07271039, 0.099417029, -0.22157272 }, { -0.013209094, 0.048633419, -0.26528065, -0.15253703 }, { 0.052922007, 0.24859103, 0.14406684, 0.13857649 }, { 0.00096142813, 0.32643367, 0.17939549, -0.39761314 }, { 0.013505803, -0.036986517, -0.12729111, 0.15459921 }, { -0.00049722057, -0.047063275, -0.0018666598, 0.1067114 }, { -0.074221027, -0.00927958, -0.029535811, -0.024240068 }, { -0.12387933, 0.06626829, 0.16422781, 0.077740779 }, { 0.14560404, -0.082132455, 0.027268021, 0.18857832 }, { 0.10470732, -0.29519533, -0.23666419, 0.10917064 }, { 0.042550279, 0.02436036, -0.31865644, -0.024987356 }, { -0.030434576, 0.082115299, 0.17770796, 0.020944092 }, { -0.17365377, 0.13807361, 0.12476029, 0.072738061 }, { -0.11503962, -0.04022554, 0.028018434, -0.070211356 }, { -0.043677907, 0.0053361863, 0.0039019898, 0.0027489647 }, { 0.27060899, -0.0016552279, 0.14166067, -0.25461265 } }, { { 0.014703402, 0.094752279, -0.32162049, 0.082335322 }, { -0.31539882, 0.44394592, 0.44316202, -0.031456167 }, { -0.024148679, 0.082370612, -0.0031744796, 0.098610537 }, { 0.46130367, -0.19989896, -0.56118891, 0.11979937 }, { 0.11784636, 0.079971516, -0.16977121, 0.014922099 }, { 0.018367216, -0.076519762, 0.13801492, 0.039682415 }, { -0.0027614728, 0.0010389006, -0.023126227, 0.0027068473 }, { 0.22249856, -0.071302328, 0.23721977, 0.10734273 }, { 0.41478408, -0.36611101, 0.18031261, -0.11176768 }, { 0.15800457, 0.23829725, -0.0016193556, 0.2112867 }, { -0.14793833, -0.15378785, 0.0082778301, 0.27105519 }, { -0.064743588, 0.44794816, -0.12599819, 0.4310022 }, { 0.092725214, 0.033947737, 0.19969884, 0.0072363359 }, { -0.074190657, 0.005985921, 0.300818, -0.090919095 }, { 0.024238118, -0.010955859, -0.068086841, -0.021137349 }, { 0.12196721, -0.19977338, -0.64428422, -0.30808722 }, { 0.46567096, -0.042072501, -0.1778338, 0.34294059 }, { -0.32528695, 0.25699981, 0.49346557, -0.20743316 }, { 0.10422458, 0.049488574, 0.49098274, -0.34871439 }, { 0.16431875, -0.050748897, -0.18464312, -0.61695364 }, { -0.1753479, 0.033238479, -0.046267845, -0.012339883 }, { -0.16098841, 0.080519992, -0.11793031, 0.036790025 }, { 0.017193144, -0.0029212372, -0.0044153187, -0.0057094316 }, { 0.23481771, -0.1556448, -0.18775429, -0.013697353 } } }, { { { 0.98467622, 0.94970347, 0.95791534, 0.9408684 }, { 0.95525144, 0.73013516, 0.58966657, 0.43166004 }, { 0.98562289, 0.95804118, 0.77397471, 0.78825859 }, { 0.96588112, 0.72807352, 0.58424502, 0.79142113 }, { -0.049305848, 0.63904864, 0.099145551, -0.03377918 }, { 0.78673348, 0.62998117, 0.62680207, 0.63245759 }, { 0.48526085, 0.544603, 0.40015579, 0.43297544 }, { 0.82487776, 0.77789448, 0.92917353, 0.91697567 }, { 0.58431326, 0.95748667, 0.99880743, 0.99975533 }, { 0.67096902, 0.60093643, 0.64381538, 0.92594344 }, { 0.95700408, 0.93816272, 0.93111608, 0.80905665 }, { 0.94046044, 0.97116483, 0.77381347, 0.78507504 }, { 0.7077214, 0.7547892, 0.23983411, -0.039180128 }, { 0.3656649, 0.38379871, -0.00015338393, 0.16604667 }, { 0.50679735, 0.6108265, 0.46821675, 0.37829596 }, { 0.55946029, 0.72460731, 0.55919425, 0.81214734 }, { 0.86277825, 0.92634645, 0.95542467, 0.96581976 }, { 0.95061533, 0.75913205, 0.60228234, 0.87287949 }, { 0.99994373, 0.93971324, 0.95087677, 0.96466059 }, { 0.9442062, 0.89161694, 0.72879505, 0.92100486 }, { 0.30989313, 0.29579046, 0.11395771, 0.071428407 }, { 0.16674735, -0.054071458, 0.85747916, 0.82737551 }, { 0.61593841, 0.45356879, 0.43544204, 0.41332561 }, { 0.79196443, 0.43841915, 0.77763172, 0.62193473 } }, { { 0.028699614, 0.071974788, -0.028868668, 0.030119772 }, { -0.16988515, -0.35713152, 0.36877151, 0.37172103 }, { 0.024472009, 0.10373643, 0.052160621, -0.12998364 }, { 0.051999909, -0.1688679, 0.05813266, -0.11063347 }, { 0.026373007, 0.067310776, 0.34433164, 0.0017481699 }, { -0.017659611, -0.10215276, -0.23736187, 0.12678732 }, { -0.0019097928, 0.02067204, -0.030447136, -0.0093192388 }, { 0.10615435, 0.11124023, 0.04473958, 0.14369936 }, { 0.14791062, -0.034502091, 0.041456555, 0.06737059 }, { 0.22389399, 0.2668048, 0.25742349, 0.03724758 }, { 0.0046009946, 0.066632032, 0.097957775, 0.22969631 }, { 0.043253167, -0.013638494, 0.071328387, -0.19249903 }, { -0.023561087, 0.011490741, 0.19824644, -0.04133258 }, { -0.057507532, -0.039265903, 0.060469313, 0.37300659 }, { 0.027051207, -0.0086784396, -0.0055877341, -0.0315352 }, { 0.15724931, 0.0099485187, 0.22462997, 0.14112999 }, { 0.13909905, 0.026199511, -0.12430815, -0.076900423 }, { -0.022327596, -0.1975812, 0.49862652, -0.096026553 }, { 0.076782007, 0.041598482, 0.0033451155, 0.039947963 }, { 0.005353589, 0.070993946, 0.0068174778, -0.17805261 }, { -0.059912765, -0.17027417, -0.060069718, 0.1561139 }, { 0.017122435, 0.048532637, -0.05315926, 0.066962855 }, { 0.058014377, 0.021874362, 0.017248667, -0.0069413843 }, { 0.099274028, 0.040622241, 0.040435904, 0.14191123 } }, { { -0.13453832, 0.071519908, -0.1597656, -0.030758273 }, { -0.13511715, 0.32373425, 0.35851035, -0.18685481 }, { 0.021440457, 0.034442875, 0.14324368, 0.15754565 }, { -0.061440371, 0.16837735, 0.47887644, -0.036265812 }, { 0.55060811, 0.14095672, 0.13077418, 0.25515565 }, { -0.084599968, -0.084002143, 0.1542308, 0.044223437 }, { 0.0017727822, 0.025149715, -0.025479364, -0.0023658361 }, { 0.1619123, 0.069159159, -0.016343512, 0.026108175 }, { 0.3296525, 0.029456656, 0.039715069, 0.015958704 }, { -0.093419591, 0.37051381, -0.063182977, -0.017764112 }, { 0.11962535, 0.062511772, -0.070445145, 0.27768911 }, { 0.07458833, -0.16218828, 0.064111239, 0.43889373 }, { -0.0326486, -0.03666828, -0.17597139, 0.34213144 }, { 0.061334301, -0.0099525239, 0.21497301, 0.0074569296 }, { -0.016749445, 0.00054557189, 0.040331287, 0.066200794 }, { 0.20620866, 0.25268529, 0.46594276, 0.059651923 }, { 0.15170896, 0.041438057, 0.021708506, -0.15049245 }, { -0.14317538, 0.13548996, 0.37297491, 0.13718874 }, { 0.053339004, 0.015014013, -0.10418356, -0.13598877 }, { -0.02227412, 0.045548464, 0.21534467, -0.23828118 }, { -0.055326885, 0.11851609, 0.28938409, 0.041373996 }, { -0.1219532, 0.57338554, -0.094571555, 0.025008596 }, { 0.070380772, 0.016993506, 0.018073937, -0.015404818 }, { 0.17033841, 0.12449473, 0.10847869, -0.11141982 } } }, { { { 4.409738, 4.5071479, 5.4761817, 5.3214091 }, { 5.3741435, 4.6270256, 5.4786338, 5.323679 }, { 4.305776, 4.4890731, 4.6894257, 4.6068436 }, { 5.4930574, 4.9116386, 5.4097636, 4.9225404 }, { 5.1861828, 5.5144226, 5.1307797, 5.0804212 }, { 6.1194597, 6.0655136, 5.7369562, 6.1076578 }, { 6.9549598, 6.9281578, 6.9549598, 6.9549598 }, { 4.5030565, 4.5849566, 4.4830953, 4.4904323 }, { 5.3629211, 5.5524848, 4.5719135, 4.9103175 }, { 4.8906163, 5.3972226, 4.8806206, 5.1834202 }, { 4.5047396, 4.5984947, 4.7039612, 4.3422371 }, { 4.5956963, 5.6294962, 4.46025, 4.4827131 }, { 5.8454206, 6.000743, 5.4594428, 4.9952614 }, { 6.09642, 6.3979283, 4.9784963, 5.6878449 }, { 6.9549598, 6.9752898, 6.9549598, 6.9549598 }, { 6.2053562, 4.9984547, 5.3887395, 4.6221036 }, { 4.5265196, 4.3684629, 5.5819288, 5.4957366 }, { 5.2220057, 4.6118907, 5.5046208, 4.9190037 }, { 4.3408178, 4.4980303, 5.4937404, 5.6154153 }, { 4.4802186, 4.4666194, 4.8546878, 5.1764252 }, { 5.7384024, 5.9048089, 5.4636107, 5.0807017 }, { 5.1013817, 5.2237041, 6.0338955, 5.8869417 }, { 6.9414339, 6.9549598, 6.9549598, 6.9549598 }, { 4.3368412, 4.9692663, 4.7090567, 4.9023075 } }, { { 0.0093525884, -0.33796029, -0.4366682, -0.18161326 }, { -0.34446047, 0.10854359, -0.61563912, -0.16514117 }, { 0.055849315, 0.093045585, 0.36722184, 0.085665647 }, { -0.21881508, -0.036846235, -0.25226403, -0.012790033 }, { -0.14697546, -0.026656628, 0.2559775, 0.026279081 }, { 0.073189287, -0.074472165, -0.15439557, 0.020907645 }, { 0, -0.015078298, 0, 0 }, { 0.027540893, -0.30876053, -0.15680794, -0.18470107 }, { -0.072547269, -0.019227086, -0.26735769, -0.1362069 }, { 0.36907279, -0.28005156, 0.01966203, -0.10277819 }, { -0.26755862, 0.066747173, 0.60834173, -0.23356165 }, { -0.12357338, -0.41742338, 0.081840746, -0.14596222 }, { -0.068599762, -0.004402392, -0.17192993, -0.15797464 }, { -0.072923207, -0.02555551, -0.21075071, 0.047272919 }, { 0, 0.0115085, 0, 0 }, { 0.32527558, 0.066048741, -0.28639187, 0.45171914 }, { -0.158086, -0.049098981, -0.17226122, -0.50289857 }, { -0.39456648, 0.031970902, -0.74883626, 0.20536003 }, { 0.22864705, -0.0095988927, -0.1155595, -0.06240073 }, { 0.12336497, -0.34128076, 0.34341316, 0.083678547 }, { -0.032718317, 0.076359349, -0.30099369, -0.016865529 }, { -0.23491753, -0.17228011, -0.044893186, -0.057411459 }, { -0.0077848677, 0, 0, 0 }, { -0.18713605, -0.11612415, 0.30907006, 0.064707406 } }, { { -0.20768494, -0.15642062, -0.079474216, -0.020948121 }, { -0.18767308, -0.013722599, 0.15827086, -0.27421942 }, { -0.11484158, -0.29325715, 0.24426149, 0.34598577 }, { -0.095599056, 0.16784413, 0.23369965, 0.15036114 }, { 0.058496274, -0.064565923, -0.076598803, -0.11988702 }, { -0.03406356, -0.010863931, -0.036116475, 0.0077051595 }, { 0, -0.015078298, 0, 0 }, { -0.21271534, 0.31678528, 0.084310434, -0.039787477 }, { 0.057420352, -0.60894321, -0.14275706, -0.29178151 }, { -0.21477227, 0.091254596, -0.053659362, -0.13299553 }, { -0.24972574, 0.22261101, -0.59415755, -0.13299464 }, { -0.406027, 0.15018847, 0.33281927, 0.28006105 }, { -0.033198856, 0.013081228, 0.0098634494, -0.18858267 }, { -0.16914457, -0.014917022, -0.15618156, 0.038961385 }, { 0, 0.0115085, 0, 0 }, { 0.047340338, -0.052961301, 0.30193278, 0.38564757 }, { -0.2009302, -0.15247105, -0.32333852, 0.22878398 }, { -0.22934017, 0.022888443, 0.30911154, -0.12420416 }, { 0.21191356, -0.33281926, -0.13523708, -0.038546557 }, { 0.28507859, -0.012777666, 0.16285544, -0.12612215 }, { -0.057034227, 0.01719448, -0.037892291, -0.13064036 }, { -0.075888865, 0.041589292, 0.0089100653, -0.10775402 }, { 0.0075560462, 0, 0, 0 }, { -0.18120766, 0.16485298, 0.58949587, 0.072313493 } } }, { { { 0.60381773, 0.64633179, 0.92301353, 0.23720177 }, { 1.1128727, 0.42172315, 1.6605811, 0.22066721 }, { 0.55829912, 0.7107351, 0.47437673, 0.53646626 }, { 0.75684406, 0.65607146, 1.5264507, 0.12817954 }, { -0.25070514, 0.30263175, -0.21070678, -0.2264813 }, { -0.24745858, -0.26801252, 0.2750925, 0.055035565 }, { -0.018769156, -0.066023008, 0.10111114, 0.0089232736 }, { 0.41152465, 0.52508091, 0.4161358, 0.39058287 }, { 0.90919582, 1.2448772, 0.61547497, 0.51303689 }, { 0.2973136, 1.2348603, 0.24154398, 0.76087607 }, { 0.23369317, 0.68368068, 0.81024353, 0.35451079 }, { 0.69272073, 0.47014545, 0.61401877, 0.43768641 }, { -0.44449894, -0.10123077, -0.19173956, -0.15811184 }, { -0.089717, -0.068601549, -0.16704813, -0.29761406 }, { 0.0055968308, -0.089855929, -0.087150641, 0.2244144 }, { 0.38902787, 0.62620686, 1.3314901, 0.26038797 }, { 0.16776511, 0.32722251, 0.71914611, 0.53556119 }, { 0.63106992, 0.46256454, 1.785895, 0.17339911 }, { 0.72516261, 0.44941094, 0.81174974, 0.61247129 }, { 0.56877815, 0.20989179, 0.7607991, 0.017998645 }, { 0.016372087, 0.26062407, -0.32771461, -0.075930098 }, { -0.11957223, -0.22579003, -0.42587945, -0.0015549589 }, { 0.0049992009, 0.053511694, 0.00053268274, 0.022778575 }, { 0.19356675, 0.5564623, 0.74981777, 0.28733119 } }, { { 0.017029304, 0.22690356, 0.25927682, -0.048136042 }, { 0.52936856, -0.26082526, 0.12568074, -0.046727529 }, { 0.08949554, -0.019090555, 0.31477592, -0.067513409 }, { 0.056302335, -0.011819435, -0.063621104, 0.27092306 }, { 0.053971592, -0.17913246, -0.14991651, -0.044263405 }, { 0.29037749, -0.040498369, -0.33600753, 0.16250066 }, { -0.067102844, -0.17843768, 0.033172168, 0.13638573 }, { 0.057127881, -0.044468822, 0.33005778, 0.34775491 }, { -0.14300931, 0.022121077, -0.045281831, -0.065216583 }, { 0.084931489, 0.06688461, 0.15758114, -0.091330485 }, { -0.014274888, 0.29139103, 0.089163749, -0.18005467 }, { -0.2191522, -0.1333803, -0.31948964, -0.28536602 }, { 0.20298891, -0.0031882515, -0.15749696, -0.014977715 }, { -0.14016857, -0.17278064, 0.01369474, 0.10971499 }, { 0.018219806, 0.080447764, 0.0056022696, -0.043028475 }, { -0.076556403, -0.13038184, -0.23788273, 0.5849635 }, { 0.1038427, 0.18199702, 0.35294355, -0.0023601311 }, { 0.22294845, -0.37427713, 0.2907529, 0.26234219 }, { 0.40809306, 0.12982813, 0.42857338, 0.14064303 }, { 0.4265028, 0.18710053, 0.15310514, 0.067551813 }, { -0.18986488, -0.029676062, -0.087045959, -0.14788626 }, { -0.07865478, 0.011558295, -0.018262356, 0.38992629 }, { 0.22297641, 0.072192947, 0.064119712, 0.12862555 }, { -0.069262467, -0.14990585, 0.31342655, -0.15002022 } }, { { 0.25288162, -0.096551539, 0.051695506, 0.20925392 }, { 0.23093904, 0.096712594, 0.19826434, 0.32530694 }, { 0.14114785, 0.071010138, -0.17642029, 0.092260082 }, { 0.39001648, -0.17666595, 0.088397252, 0.1462816 }, { 0.12484597, 0.066920676, -0.16116194, 0.21758387 }, { 0.15625272, -0.00043631439, -0.07868976, -0.19261141 }, { -0.0142415, 0.06356153, 0.026276923, -0.024546668 }, { 0.097089221, 0.085426402, 0.11936115, 0.012042542 }, { 0.52509109, -0.22465399, -0.11490612, 0.023562122 }, { -0.12418278, 0.11985465, 0.087804943, 0.25283464 }, { 0.10716753, -0.036426901, 0.2469409, -0.095816257 }, { -0.095364501, 0.14001518, -0.068636804, -0.082487255 }, { 0.074490355, 0.25323233, 0.17863748, 0.12482145 }, { -0.019616587, -0.0053326518, 0.047558858, 0.066104462 }, { 0.12647102, 0.25712368, 0.12306783, -0.050252261 }, { -0.13375041, 0.17825067, 0.026649645, -0.33338076 }, { 0.16384463, -0.022241979, 0.17817325, 0.6808721 }, { 0.42075944, -0.024292721, -0.11323318, 0.45027063 }, { -0.023953485, 0.25719992, 0.28680108, 0.33600529 }, { 0.013445546, 0.22504275, 0.17408162, 0.52860686 }, { -0.098839039, -0.27017244, 0.10293505, -0.012472685 }, { 0.074267375, -0.0056418849, 0.17632358, 0.21754089 }, { 0.1491061, 0.017927571, -0.0217757, -0.0039381966 }, { 0.067239102, -0.74624136, 0.12992555, -0.058866581 } } } }, { { { { 0.1270204, 0.7650174, 0.55252173, 0.05956498 }, { -0.36870832, 0.31227245, 0.52167466, 0.4282174 }, { -0.036761861, -0.5477415, -0.76091563, -0.37583127 }, { 0.17129434, -0.14281209, -0.40463148, -0.56367877 }, { 0.07429238, 0.45420144, 0.41919765, 0.019225986 }, { -0.44125436, -0.05567539, 0.080551064, 0.54444995 }, { -0.36600455, -0.55359309, -0.3290331, 0.33946169 }, { 0.65253747, 0.015186649, 0.0665303, -0.64649501 }, { 0.05392469, 0.54355001, 0.7539307, -0.41089455 }, { -0.29264863, 0.49684721, 0.39184208, 0.47737193 }, { 0.10885354, -0.80803227, -0.7443769, -0.3736688 }, { 0.1939378, -0.079590275, -0.42241709, -0.75536039 }, { 0.44776697, 0.44884546, 0.427965, 0.3297221 }, { -0.34595785, 0.27723463, 0.12245317, 0.43884357 }, { 0.18467758, -0.55582608, -0.99421464, -0.0096027817 }, { 0.6672057, -0.038103784, -0.048616141, -0.68508055 }, { -0.016615937, 0.62001729, 0.50530563, -0.22211425 }, { -0.16823123, 0.31934529, 0.47092187, 0.4884373 }, { 0.03194189, -0.5624624, -0.44688229, 0.223814 }, { 0.17828041, -0.080017082, -0.44239439, -0.46726625 }, { 0.19895649, 0.82568772, 0.47859751, 0.064443297 }, { -0.47464217, 0.011895223, 0.01123465, -0.010697203 }, { -0.17670677, -0.66931423, -0.5814681, -0.01325001 }, { 0.65193874, -0.010713062, -0.007915928, -0.65520853 } }, { { -0.01027431, -0.0019056004, 0.0020213958, 0.0064495753 }, { 0.0058416688, 0.0051314639, 0.021497114, 0.005870592 }, { -0.00035518612, -0.00087553938, -0.0029318969, 0.0087577986 }, { -0.0048770476, -0.015949665, -0.034816051, -0.006104917 }, { 0.0015371362, -0.0012591621, 0.01241148, 0.00096621463 }, { 0.0032416133, 0.021025709, 0.0036344622, 0.0015436078 }, { -0.0093946276, 0.0046564763, 0.028177476, -0.01022744 }, { 0.00014675555, 0.030031482, -0.0092302407, -0.001999398 }, { -0.049980321, 0.024752279, 0.016684689, -0.0045230976 }, { 0.0067493834, 0.014071508, 0.0079316435, 0.034593704 }, { 0.01971715, -0.0037227013, -0.013430278, -0.024257585 }, { -0.004342319, 0.024001878, -0.013356442, -0.022792018 }, { -0.0051709665, -0.017029547, 0.040567567, 0.0052520812 }, { 0.0090399102, 0.0079604733, 0.00018765016, -0.0092868977 }, { -0.020304032, 0.0056590257, -0.0045373063, -0.018653318 }, { -9.9636934e-05, 0.002001886, 0.0046843544, 0.0055608043 }, { 0.0018025744, -0.0025962216, 0.0068285574, -0.014851062 }, { 0.00041645221, 0.0054738242, 0.0076769026, -0.013419208 }, { 0.0038347099, -0.0042555066, -0.0066470075, 0.0039146778 }, { -0.009084153, 0.024461537, 0.0034578066, -0.0054827001 }, { 0.0033463477, 0.0045594748, 0.00037604935, -0.01571513 }, { -0.012589588, 0.029678359, -0.019924871, -0.004708459 }, { -0.0002642682, -0.0051057336, -0.0042867302, -0.00041141781 }, { -0.00086487068, -0.0025170841, 0.0030062196, -0.0030385417 } }, { { -0.01027431, -0.0019056004, 0.0020213958, 0.0064495753 }, { 0.0058416688, 0.0051314639, 0.021497114, 0.005870592 }, { -0.00035518612, -0.00087553938, -0.0029318969, 0.0087577986 }, { -0.0048770476, -0.015949665, -0.034816051, -0.006104917 }, { 0.0015371362, -0.0012591621, 0.01241148, 0.00096621463 }, { 0.0032416133, 0.021025709, 0.0036344622, 0.0015436078 }, { -0.0093946276, 0.0046564763, 0.028177476, -0.01022744 }, { 0.00014675555, 0.030031482, -0.0092302407, -0.001999398 }, { -0.049980321, 0.024752279, 0.016684689, -0.0045230976 }, { 0.0067493834, 0.014071508, 0.0079316435, 0.034593704 }, { 0.01971715, -0.0037227013, -0.013430278, -0.024257585 }, { -0.004342319, 0.024001878, -0.013356442, -0.022792018 }, { -0.0051709665, -0.017029547, 0.040567567, 0.0052520812 }, { 0.0090399102, 0.0079604733, 0.00018765016, -0.0092868977 }, { -0.020304032, 0.0056590257, -0.0045373063, -0.018653318 }, { -9.9636934e-05, 0.002001886, 0.0046843544, 0.0055608043 }, { 0.0018025744, -0.0025962216, 0.0068285574, -0.014851062 }, { 0.00041645221, 0.0054738242, 0.0076769026, -0.013419208 }, { 0.0038347099, -0.0042555066, -0.0066470075, 0.0039146778 }, { -0.009084153, 0.024461537, 0.0034578066, -0.0054827001 }, { 0.0033463477, 0.0045594748, 0.00037604935, -0.01571513 }, { -0.012589588, 0.029678359, -0.019924871, -0.004708459 }, { -0.0002642682, -0.0051057336, -0.0042867302, -0.00041141781 }, { -0.00086487068, -0.0025170841, 0.0030062196, -0.0030385417 } } }, { { { -0.68772793, 0.19029367, -0.17427646, 0.60300616 }, { -0.29980532, -0.22397537, -0.4071009, 0.36277983 }, { 0.75628069, -0.13426242, 0.13645381, -0.74653491 }, { 0.14891408, -0.13497977, 0.36807879, -0.39814386 }, { -0.20608987, -0.076497863, -0.19510375, 0.34604256 }, { -0.02421123, -0.4588774, -0.64965351, 0.083039161 }, { 0.51918764, -0.30614677, -0.25791921, -0.40837612 }, { 0.028860181, 0.63152733, 0.5876224, -0.033139773 }, { -0.63418144, 0.046874151, 0.24431924, 0.71662556 }, { -0.29088451, -0.21455586, -0.73980807, 0.65038559 }, { 0.78663226, 0.00020858525, 0.40361403, -0.75720144 }, { 0.1998276, 0.54590973, 0.1773378, -0.35464319 }, { -0.40236144, 0.31362578, -0.34406026, 0.38120073 }, { -0.27845549, -0.46862161, -0.47141499, 0.095899189 }, { 0.6004921, 0.28051621, -0.011378178, -0.98141078 }, { 0.032724674, 0.66798127, 0.66430425, -0.05209965 }, { -0.59603974, -0.083198329, 0.34616224, 0.42082916 }, { -0.14262632, -0.21418442, -0.37504914, 0.32676687 }, { 0.58204273, 0.0067537174, -0.35923481, -0.40792038 }, { 0.15607366, 0.17215007, 0.34414936, -0.33566945 }, { -0.44862333, 0.004919013, 0.0076768115, 0.41897935 }, { -0.022062848, -0.39695079, -0.0062786656, 0.042925103 }, { 0.65953535, -0.15521993, 0.011867978, -0.57721165 }, { 0.031305912, 0.65627006, 0.66779002, -0.029815636 } }, { { 0.011457792, -0.011774949, -0.012205337, 0.0048139052 }, { -0.024024566, 0.018313023, -0.023210623, -0.0046351547 }, { 0.0039133571, 0.0046801024, -0.020590099, -0.0018568631 }, { -0.015369931, -0.0092621276, -0.026149742, 0.0010335971 }, { 0.032555144, -0.01336897, -0.022733265, -0.027997469 }, { -0.028161537, -0.00073877629, -0.023989631, 0.0055660453 }, { -0.012966193, 0.003944376, 0.025685982, -0.0017458044 }, { 0.00015626641, -0.009524206, 0.0083025026, -0.00049753811 }, { -0.02358661, 0.006370149, 0.00087066462, -0.00054248544 }, { -0.0024571244, -0.023218369, -0.010895303, -0.0095647684 }, { 0.0069970393, -0.00093403301, -0.0081922371, -0.00026359768 }, { 0.0065921354, 0.028846533, -0.045676337, 0.006070217 }, { 0.0045248423, -0.0084676847, 0.028756195, 0.020612871 }, { 0.0037691244, -0.0069385161, -0.00029501448, -0.0017839033 }, { -0.0048675353, -0.011930456, 0.0044251285, -0.00016323616 }, { -0.0012291164, -0.0019575288, 0.0078250029, -0.0011151155 }, { 0.00503333, -0.0094538968, 0.0092375183, 0.018207648 }, { 0.0080615812, -0.0073583459, -0.0166794, 0.016416158 }, { 0.002192959, -0.01153759, -0.0048668362, -0.0071123281 }, { -0.010116143, -0.010224552, 0.010897731, 0.00093792816 }, { 0.017199359, -0.0087516179, 0.0021169251, -0.020946959 }, { -0.01570063, 0.020087246, 0.014492818, -0.016014018 }, { 0.0023484072, 0.0015070243, -0.00045616273, -0.001211882 }, { 0.0018090492, -0.0012261901, 0.0012809284, 0.00096488905 } }, { { 0.011457792, -0.011774949, -0.012205337, 0.0048139052 }, { -0.024024566, 0.018313023, -0.023210623, -0.0046351547 }, { 0.0039133571, 0.0046801024, -0.020590099, -0.0018568631 }, { -0.015369931, -0.0092621276, -0.026149742, 0.0010335971 }, { 0.032555144, -0.01336897, -0.022733265, -0.027997469 }, { -0.028161537, -0.00073877629, -0.023989631, 0.0055660453 }, { -0.012966193, 0.003944376, 0.025685982, -0.0017458044 }, { 0.00015626641, -0.009524206, 0.0083025026, -0.00049753811 }, { -0.02358661, 0.006370149, 0.00087066462, -0.00054248544 }, { -0.0024571244, -0.023218369, -0.010895303, -0.0095647684 }, { 0.0069970393, -0.00093403301, -0.0081922371, -0.00026359768 }, { 0.0065921354, 0.028846533, -0.045676337, 0.006070217 }, { 0.0045248423, -0.0084676847, 0.028756195, 0.020612871 }, { 0.0037691244, -0.0069385161, -0.00029501448, -0.0017839033 }, { -0.0048675353, -0.011930456, 0.0044251285, -0.00016323616 }, { -0.0012291164, -0.0019575288, 0.0078250029, -0.0011151155 }, { 0.00503333, -0.0094538968, 0.0092375183, 0.018207648 }, { 0.0080615812, -0.0073583459, -0.0166794, 0.016416158 }, { 0.002192959, -0.01153759, -0.0048668362, -0.0071123281 }, { -0.010116143, -0.010224552, 0.010897731, 0.00093792816 }, { 0.017199359, -0.0087516179, 0.0021169251, -0.020946959 }, { -0.01570063, 0.020087246, 0.014492818, -0.016014018 }, { 0.0023484072, 0.0015070243, -0.00045616273, -0.001211882 }, { 0.0018090492, -0.0012261901, 0.0012809284, 0.00096488905 } } }, { { { 0.71476997, 0.61525336, 0.81507512, 0.79550964 }, { 0.87986984, 0.9232123, 0.74974956, 0.82765975 }, { 0.65321366, 0.82580437, 0.63434042, 0.54903231 }, { 0.97390084, 0.98050251, 0.83713283, 0.72370416 }, { 0.97570877, 0.88760866, 0.88668363, 0.9380218 }, { 0.89705541, 0.88675351, 0.75595095, 0.83467284 }, { 0.77232433, 0.77447327, 0.9084134, 0.84734569 }, { -0.75720667, -0.77520488, -0.80639546, -0.76219811 }, { 0.77130152, 0.83806694, 0.60983327, 0.56357207 }, { 0.91090229, 0.84089752, 0.54694041, 0.59085922 }, { 0.60775044, 0.58913818, 0.53197627, 0.53574024 }, { 0.96044628, 0.83405513, 0.88888419, 0.55105253 }, { 0.79850486, 0.83676557, 0.83574428, 0.86369517 }, { 0.89597751, 0.83876978, 0.87336884, 0.8934314 }, { 0.77801249, 0.78253947, 0.10680725, 0.19167855 }, { -0.74415432, -0.74320194, -0.74587957, -0.72660186 }, { 0.802783, 0.78016447, 0.79046691, 0.87952719 }, { 0.97537479, 0.92311625, 0.79848027, 0.80910594 }, { 0.8125306, 0.82679528, 0.81929639, 0.88516002 }, { 0.97152309, 0.98181547, 0.82815966, 0.81791703 }, { 0.87129411, 0.56410602, 0.87800085, 0.905706 }, { 0.87990229, 0.91776281, 0.99991718, 0.99902102 }, { 0.73060786, 0.72658464, 0.81348263, 0.81648708 }, { -0.75762512, -0.75445002, -0.74430762, -0.75485946 } }, { { 0.018332644, 0.0084005452, -0.0018937689, -0.0035491975 }, { 0.0016556654, 0.0049261013, -0.021796869, 0.0025973591 }, { -0.0019671758, 0.00051947074, 0.0071261223, 0.0056689139 }, { 0.00041901024, -0.0023903288, -0.0035639711, -0.0036673013 }, { 0.009963464, 0.00099195429, -0.0042516892, 0.0092605531 }, { 0.0034813664, 0.0028575465, -0.016343415, -0.0014475905 }, { 0.0053571039, 0.0051116063, 0.016171091, -0.00052744238 }, { 0.00013272575, -0.0095491849, 0.0070156475, 0.0017057538 }, { 0.028067438, -0.0086835729, -0.0087852674, 0.0035321054 }, { 0.0025007808, -0.0075654884, -0.012551417, -0.0068823899 }, { -0.00017607308, 0.002636122, -0.011272055, -0.010314896 }, { 0.010646599, 0.00042804331, 0.013900837, -0.01279076 }, { 0.0059898286, 0.012331371, -0.0073125296, 0.016248603 }, { 0.031579315, -0.0057840222, -0.00018304192, 0.005171422 }, { 0.010928513, 0.0092660887, 0.030404621, 0.0053167707 }, { -0.00014899672, -0.0035246494, 0.0075862845, -0.005861723 }, { 0.0067791918, 0.0021224495, -0.0071755505, -0.010370936 }, { 0.0015352958, -0.0025785166, -0.0092688001, 0.003966373 }, { 0.0036915074, -0.002306452, -0.005736452, -0.0033594125 }, { 0.0065128512, 0.006188005, 0.00088322638, -0.0016227066 }, { 0.0092720771, -0.0046684631, -7.3769604e-05, 0.013807013 }, { -0.0031421984, 0.010622679, 0.00041591214, 0.0032786075 }, { -0.0021421613, -0.0041675589, -0.0029529994, -0.00085350449 }, { -0.00069204344, -0.0010785124, 0.00097549628, 0.0025280456 } }, { { 0.018332644, 0.0084005452, -0.0018937689, -0.0035491975 }, { 0.0016556654, 0.0049261013, -0.021796869, 0.0025973591 }, { -0.0019671758, 0.00051947074, 0.0071261223, 0.0056689139 }, { 0.00041901024, -0.0023903288, -0.0035639711, -0.0036673013 }, { 0.009963464, 0.00099195429, -0.0042516892, 0.0092605531 }, { 0.0034813664, 0.0028575465, -0.016343415, -0.0014475905 }, { 0.0053571039, 0.0051116063, 0.016171091, -0.00052744238 }, { 0.00013272575, -0.0095491849, 0.0070156475, 0.0017057538 }, { 0.028067438, -0.0086835729, -0.0087852674, 0.0035321054 }, { 0.0025007808, -0.0075654884, -0.012551417, -0.0068823899 }, { -0.00017607308, 0.002636122, -0.011272055, -0.010314896 }, { 0.010646599, 0.00042804331, 0.013900837, -0.01279076 }, { 0.0059898286, 0.012331371, -0.0073125296, 0.016248603 }, { 0.031579315, -0.0057840222, -0.00018304192, 0.005171422 }, { 0.010928513, 0.0092660887, 0.030404621, 0.0053167707 }, { -0.00014899672, -0.0035246494, 0.0075862845, -0.005861723 }, { 0.0067791918, 0.0021224495, -0.0071755505, -0.010370936 }, { 0.0015352958, -0.0025785166, -0.0092688001, 0.003966373 }, { 0.0036915074, -0.002306452, -0.005736452, -0.0033594125 }, { 0.0065128512, 0.006188005, 0.00088322638, -0.0016227066 }, { 0.0092720771, -0.0046684631, -7.3769604e-05, 0.013807013 }, { -0.0031421984, 0.010622679, 0.00041591214, 0.0032786075 }, { -0.0021421613, -0.0041675589, -0.0029529994, -0.00085350449 }, { -0.00069204344, -0.0010785124, 0.00097549628, 0.0025280456 } } }, { { { 5.3792285, 5.1960477, 5.5112916, 5.6615254 }, { 5.0489877, 5.2428834, 5.1752035, 5.1109826 }, { 5.5205204, 5.7511938, 5.0202917, 4.9168865 }, { 4.9522523, 4.8880256, 5.1015936, 5.2858816 }, { 5.7256502, 5.7919759, 5.645241, 5.6035708 }, { 6.4076931, 6.4822111, 6.2642633, 6.3925959 }, { 6.9797014, 6.981436, 7.0028674, 6.9976464 }, { -0.03290957, -0.03290957, -0.03290957, -0.03290957 }, { 5.4977854, 5.7684965, 5.3463095, 4.8810492 }, { 4.9869047, 5.4896416, 4.9647805, 4.884877 }, { 5.3141219, 5.3357788, 4.7695434, 4.8709631 }, { 5.2056063, 5.407802, 5.2123857, 4.9428208 }, { 6.2188218, 6.17756, 6.2751008, 6.3672109 }, { 6.9105856, 6.7986798, 6.5712335, 6.5907061 }, { 6.9797014, 6.9797014, 5.6859993, 5.5642483 }, { -0.032764603, -0.032764603, -0.032764603, -0.032764603 }, { 5.7724142, 6.0929556, 5.99581, 5.9265164 }, { 4.9363192, 4.9823732, 5.1732995, 5.2475265 }, { 5.8365191, 5.9972902, 5.9778441, 5.9270668 }, { 4.8706768, 5.0194503, 5.155585, 5.2188041 }, { 6.1569904, 6.0563989, 6.0989699, 6.2139837 }, { 5.8727399, 5.8948086, 5.5734095, 5.5536103 }, { 6.9797014, 6.9797014, 6.9797014, 6.9797014 }, { -0.032766769, -0.032766769, -0.032766769, -0.032766769 } }, { { 0.0011802354, -0.006546101, -0.02103972, 0.0008654047 }, { -0.015460534, 0.017874544, 0.0029121134, 0.023511773 }, { -0.040909245, 0.011927691, 0.011991588, 0.01677931 }, { -0.015633544, -0.0042321141, 0.026623034, 0.0080414514 }, { 0.012614382, 0.0065080145, 0.035716738, -0.0080665814 }, { -0.0057849744, -0.017478461, -0.031219642, 0.00016446523 }, { 0, 0.00032235028, 0, 0 }, { 0, 0, 0, 0 }, { -0.068586697, -0.024228236, -0.012857221, -0.039493706 }, { -0.018078201, -0.015140979, 0.00072119173, -0.051249859 }, { -0.054228277, 0.0097895101, 0.0019832646, -0.011715411 }, { -0.042326208, -0.010160072, 0.037088052, -0.031848667 }, { 0.00067130897, -0.013966717, -0.017268559, -0.0074614576 }, { 0.070515961, 0.012848107, -0.0008396517, 0.0049006506 }, { 0, 0, -0.063014256, -0.0085124986 }, { 0, 0, 0, 0 }, { -0.040302299, 0.0048936307, 0.0064406394, 0.0034044871 }, { -0.010453589, 0.0035820836, -0.017384391, -0.038199947 }, { -0.044968611, -0.0088322127, 0.020303819, 0.0058131005 }, { -0.0056838535, 0.010211409, -0.010999927, -0.027621859 }, { 0.0064753811, -0.0059341242, -0.014902755, 0.0082868118 }, { -0.0013222735, 0.0028492181, -0.023523273, -0.02576271 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, { { 0.0011802354, -0.006546101, -0.02103972, 0.00086540469 }, { -0.015460534, 0.017874544, 0.0029121134, 0.023511773 }, { -0.040909245, 0.011927691, 0.011991588, 0.01677931 }, { -0.015633544, -0.0042321141, 0.026623034, 0.0080414514 }, { 0.012614382, 0.0065080145, 0.035716738, -0.0080665814 }, { -0.0057849744, -0.017478461, -0.031219642, 0.00016446523 }, { 0, 0.00032235028, 0, 0 }, { 0, 0, 0, 0 }, { -0.068586697, -0.024228236, -0.012857221, -0.039493706 }, { -0.018078201, -0.015140979, 0.00072119173, -0.051249859 }, { -0.054228277, 0.0097895101, 0.0019832646, -0.011715411 }, { -0.042326208, -0.010160072, 0.037088052, -0.031848667 }, { 0.00067130897, -0.013966717, -0.017268559, -0.0074614576 }, { 0.070515961, 0.012848107, -0.0008396517, 0.0049006506 }, { 0, 0, -0.063014256, -0.0085124986 }, { 0, 0, 0, 0 }, { -0.040302299, 0.0048936307, 0.0064406394, 0.0034044871 }, { -0.010453589, 0.0035820836, -0.017384391, -0.038199947 }, { -0.044968611, -0.0088322127, 0.020303819, 0.0058131005 }, { -0.0056838535, 0.010211409, -0.010999927, -0.027621859 }, { 0.0064753811, -0.0059341242, -0.014902755, 0.0082868118 }, { -0.0013222735, 0.0028492181, -0.023523273, -0.02576271 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } } }, { { { 0.72189984, 0.22069996, 0.71952927, 0.77725949 }, { 0.4054405, 0.20582059, 0.2747016, 0.37612563 }, { 0.58887422, 0.27441131, 0.19468101, 0.21480554 }, { 0.46814145, 0.34317, 0.46068212, 0.13962064 }, { -0.18134132, -0.26668789, -0.60984999, -0.67879259 }, { -0.47870351, -0.34453227, 0.32494779, 0.10292971 }, { 0.087252967, 0.066950358, 0.31813819, 0.071094818 }, { -0.0031436256, 0.038245091, -0.0076651913, -0.015389479 }, { 1.2668531, 1.2894974, 0.40584018, 0.51755806 }, { 1.3207257, 1.3403747, 0.54924634, 0.40282713 }, { 0.78581828, 0.56379328, 0.27901993, 0.56429306 }, { 0.8748226, 1.0271253, 1.0085726, 0.3888545 }, { -0.22577636, -0.32895071, -0.2846317, -0.11679531 }, { 0.26477285, 0.3179447, -0.063393238, 0.024059773 }, { -0.15463395, -0.22721468, -0.20680404, -0.15700788 }, { 0.012107106, -0.0061245949, -0.024224367, 0.005040693 }, { 0.97943693, 0.64840429, 0.45106998, 0.40771935 }, { 0.49907853, 0.1562184, 0.34338458, 0.39710628 }, { 0.95047709, 0.53336107, 0.38318275, 0.44919148 }, { 0.41892697, 0.069965886, 0.45831656, 0.38821529 }, { -0.20216736, -0.43209441, -0.57684857, -0.40189427 }, { -0.63992377, -0.40683032, -0.59207903, -0.57251716 }, { -0.047117438, -0.1880015, -0.12265155, 0.00059988607 }, { -0.011836442, -0.010049497, -0.0026152072, 0.016137736 } }, { { 0.092068993, 0.0045466749, 0.0054574031, 0.02582156 }, { 0.022115456, -0.015664041, -0.022004653, 0.041431654 }, { 0.029951298, -0.0004408542, 0.0087496069, 0.017850027 }, { 0.029086373, 0.022116039, 0.044010315, 0.001644876 }, { 0.016256387, 0.0083249367, 0.019570849, -0.0021276222 }, { 0.0079070076, -0.024696939, 0.044311101, 0.023671132 }, { -0.0081796119, -0.0024995551, 0.033501743, -0.031958988 }, { 0.0065005403, -0.076642001, 0.015736477, 0.030966939 }, { 0.029110717, 0.039154477, -0.074376619, 0.025532063 }, { -0.10980761, 0.0038346834, 0.014449171, -0.030702653 }, { -0.00068350423, -0.037251569, -0.008409224, -0.026322878 }, { 0.035406012, 0.064176275, 0.031437854, -0.0344642 }, { 0.037145809, -0.024909212, 0.041030386, 0.035216105 }, { -0.093276646, -0.013904083, -0.019536023, -0.023834405 }, { 0.042751846, -0.03620164, 0.081115921, 0.018379967 }, { -0.023909625, 0.012833691, 0.048086442, -0.0097340268 }, { 0.039552712, -0.00026806514, 0.011646753, 0.0065939486 }, { 0.058985248, 0.020165701, 0.0076721521, 0.033274221 }, { 0.052889871, 0.0042520093, 0.016490396, 0.009287973 }, { 0.044305975, -0.0016263469, 0.041390177, 0.033541355 }, { 0.014595133, -0.004801042, -0.0049517302, 0.015714264 }, { 0.00075086205, 0.0080838736, -0.037611057, -0.030488441 }, { 0.0019178075, -0.0082517768, -0.002525773, 0.0043993022 }, { 0.023774971, 0.020335611, 0.0056643868, -0.032100338 } }, { { 0.092068993, 0.0045466749, 0.0054574031, 0.02582156 }, { 0.022115456, -0.015664041, -0.022004653, 0.041431654 }, { 0.029951298, -0.0004408542, 0.0087496069, 0.017850027 }, { 0.029086373, 0.022116039, 0.044010315, 0.001644876 }, { 0.016256387, 0.0083249367, 0.019570849, -0.0021276222 }, { 0.0079070076, -0.024696939, 0.044311101, 0.023671132 }, { -0.0081796119, -0.0024995551, 0.033501743, -0.031958988 }, { 0.0065005403, -0.076642001, 0.015736477, 0.030966939 }, { 0.029110717, 0.039154477, -0.074376619, 0.025532063 }, { -0.10980761, 0.0038346834, 0.014449171, -0.030702653 }, { -0.00068350423, -0.037251569, -0.008409224, -0.026322878 }, { 0.035406012, 0.064176275, 0.031437854, -0.0344642 }, { 0.037145809, -0.024909212, 0.041030386, 0.035216105 }, { -0.093276646, -0.013904083, -0.019536023, -0.023834405 }, { 0.042751846, -0.03620164, 0.081115921, 0.018379967 }, { -0.023909625, 0.012833691, 0.048086442, -0.0097340268 }, { 0.039552712, -0.00026806514, 0.011646753, 0.0065939486 }, { 0.058985248, 0.020165701, 0.0076721521, 0.033274221 }, { 0.052889871, 0.0042520093, 0.016490396, 0.009287973 }, { 0.044305975, -0.0016263469, 0.041390177, 0.033541355 }, { 0.014595133, -0.004801042, -0.0049517303, 0.015714264 }, { 0.00075086205, 0.0080838736, -0.037611057, -0.030488441 }, { 0.0019178075, -0.0082517768, -0.002525773, 0.0043993022 }, { 0.023774971, 0.020335611, 0.0056643868, -0.032100338 } } } } };
+
+#endif
diff --git a/thirdparty/vulkan/android/vk_mem_alloc.cpp b/thirdparty/vulkan/android/vk_mem_alloc.cpp
new file mode 100644
index 0000000000..a28454cf6e
--- /dev/null
+++ b/thirdparty/vulkan/android/vk_mem_alloc.cpp
@@ -0,0 +1,8 @@
+#define VMA_IMPLEMENTATION
+#ifdef DEBUG_ENABLED
+#ifndef _DEBUG
+#define _DEBUG
+#endif
+#endif
+// Include memory allocator from Android NDK
+#include <vk_mem_alloc.h>
diff --git a/thirdparty/vulkan/vk_enum_string_helper.h b/thirdparty/vulkan/vk_enum_string_helper.h
index 00c2b9d1d5..1c99b31270 100644
--- a/thirdparty/vulkan/vk_enum_string_helper.h
+++ b/thirdparty/vulkan/vk_enum_string_helper.h
@@ -31,7 +31,7 @@
#pragma once
-#ifdef _WIN32
+#ifdef _MSC_VER
#pragma warning( disable : 4065 )
#endif